|
17 | 17 | *
|
18 | 18 | *
|
19 | 19 | * IDENTIFICATION
|
20 |
| - * $PostgreSQL: pgsql/src/backend/storage/large_object/inv_api.c,v 1.122 2007/02/27 23:48:07 tgl Exp $ |
| 20 | + * $PostgreSQL: pgsql/src/backend/storage/large_object/inv_api.c,v 1.123 2007/03/03 19:52:46 momjian Exp $ |
21 | 21 | *
|
22 | 22 | *-------------------------------------------------------------------------
|
23 | 23 | */
|
@@ -681,3 +681,166 @@ inv_write(LargeObjectDesc *obj_desc, const char *buf, int nbytes)
|
681 | 681 |
|
682 | 682 | returnnwritten;
|
683 | 683 | }
|
| 684 | + |
| 685 | +void |
| 686 | +inv_truncate(LargeObjectDesc*obj_desc,intlen) |
| 687 | +{ |
| 688 | +int32pageno= (int32) (len /LOBLKSIZE); |
| 689 | +intoff; |
| 690 | +ScanKeyDataskey[2]; |
| 691 | +IndexScanDescsd; |
| 692 | +HeapTupleoldtuple; |
| 693 | +Form_pg_largeobjectolddata; |
| 694 | +struct |
| 695 | +{ |
| 696 | +byteahdr; |
| 697 | +chardata[LOBLKSIZE]; |
| 698 | +}workbuf; |
| 699 | +char*workb=VARDATA(&workbuf.hdr); |
| 700 | +HeapTuplenewtup; |
| 701 | +Datumvalues[Natts_pg_largeobject]; |
| 702 | +charnulls[Natts_pg_largeobject]; |
| 703 | +charreplace[Natts_pg_largeobject]; |
| 704 | +CatalogIndexStateindstate; |
| 705 | + |
| 706 | +Assert(PointerIsValid(obj_desc)); |
| 707 | + |
| 708 | +/* enforce writability because snapshot is probably wrong otherwise */ |
| 709 | +if ((obj_desc->flags&IFS_WRLOCK)==0) |
| 710 | +ereport(ERROR, |
| 711 | +(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), |
| 712 | +errmsg("large object %u was not opened for writing", |
| 713 | +obj_desc->id))); |
| 714 | + |
| 715 | +open_lo_relation(); |
| 716 | + |
| 717 | +indstate=CatalogOpenIndexes(lo_heap_r); |
| 718 | + |
| 719 | +ScanKeyInit(&skey[0], |
| 720 | +Anum_pg_largeobject_loid, |
| 721 | +BTEqualStrategyNumber,F_OIDEQ, |
| 722 | +ObjectIdGetDatum(obj_desc->id)); |
| 723 | + |
| 724 | +ScanKeyInit(&skey[1], |
| 725 | +Anum_pg_largeobject_pageno, |
| 726 | +BTGreaterEqualStrategyNumber,F_INT4GE, |
| 727 | +Int32GetDatum(pageno)); |
| 728 | + |
| 729 | +sd=index_beginscan(lo_heap_r,lo_index_r, |
| 730 | +obj_desc->snapshot,2,skey); |
| 731 | + |
| 732 | +/* |
| 733 | + * If possible, get the page the truncation point is in. |
| 734 | + * The truncation point may be beyond the end of the LO or |
| 735 | + * in a hole. |
| 736 | + */ |
| 737 | +olddata=NULL; |
| 738 | +if ((oldtuple=index_getnext(sd,ForwardScanDirection))!=NULL) |
| 739 | +{ |
| 740 | +olddata= (Form_pg_largeobject)GETSTRUCT(oldtuple); |
| 741 | +Assert(olddata->pageno >=pageno); |
| 742 | +} |
| 743 | + |
| 744 | +/* |
| 745 | + * If we found the page of the truncation point we need to |
| 746 | + * truncate the data in it. Otherwise if we're in a hole, |
| 747 | + * we need to create a page to mark the end of data. |
| 748 | + */ |
| 749 | +if (olddata!=NULL&&olddata->pageno==pageno) |
| 750 | +{ |
| 751 | +/* First, load old data into workbuf */ |
| 752 | +bytea*datafield=&(olddata->data); |
| 753 | +boolpfreeit= false; |
| 754 | +intpagelen; |
| 755 | + |
| 756 | +if (VARATT_IS_EXTENDED(datafield)) |
| 757 | +{ |
| 758 | +datafield= (bytea*) |
| 759 | +heap_tuple_untoast_attr((varattrib*)datafield); |
| 760 | +pfreeit= true; |
| 761 | +} |
| 762 | +pagelen=getbytealen(datafield); |
| 763 | +Assert(pagelen <=LOBLKSIZE); |
| 764 | +memcpy(workb,VARDATA(datafield),pagelen); |
| 765 | +if (pfreeit) |
| 766 | +pfree(datafield); |
| 767 | + |
| 768 | +/* |
| 769 | + * Fill any hole |
| 770 | + */ |
| 771 | +off=len %LOBLKSIZE; |
| 772 | +if (off>pagelen) |
| 773 | +MemSet(workb+pagelen,0,off-pagelen); |
| 774 | + |
| 775 | +/* compute length of new page */ |
| 776 | +SET_VARSIZE(&workbuf.hdr,off+VARHDRSZ); |
| 777 | + |
| 778 | +/* |
| 779 | + * Form and insert updated tuple |
| 780 | + */ |
| 781 | +memset(values,0,sizeof(values)); |
| 782 | +memset(nulls,' ',sizeof(nulls)); |
| 783 | +memset(replace,' ',sizeof(replace)); |
| 784 | +values[Anum_pg_largeobject_data-1]=PointerGetDatum(&workbuf); |
| 785 | +replace[Anum_pg_largeobject_data-1]='r'; |
| 786 | +newtup=heap_modifytuple(oldtuple,RelationGetDescr(lo_heap_r), |
| 787 | +values,nulls,replace); |
| 788 | +simple_heap_update(lo_heap_r,&newtup->t_self,newtup); |
| 789 | +CatalogIndexInsert(indstate,newtup); |
| 790 | +heap_freetuple(newtup); |
| 791 | +} |
| 792 | +else |
| 793 | +{ |
| 794 | +/* |
| 795 | + * If the first page we found was after the truncation |
| 796 | + * point, we're in a hole that we'll fill, but we need to |
| 797 | + * delete the later page. |
| 798 | + */ |
| 799 | +if (olddata!=NULL&&olddata->pageno>pageno) |
| 800 | +simple_heap_delete(lo_heap_r,&oldtuple->t_self); |
| 801 | + |
| 802 | +/* |
| 803 | + * Write a brand new page. |
| 804 | + * |
| 805 | + * Fill the hole up to the truncation point |
| 806 | + */ |
| 807 | +off=len %LOBLKSIZE; |
| 808 | +if (off>0) |
| 809 | +MemSet(workb,0,off); |
| 810 | + |
| 811 | +/* compute length of new page */ |
| 812 | +SET_VARSIZE(&workbuf.hdr,off+VARHDRSZ); |
| 813 | + |
| 814 | +/* |
| 815 | + * Form and insert new tuple |
| 816 | + */ |
| 817 | +memset(values,0,sizeof(values)); |
| 818 | +memset(nulls,' ',sizeof(nulls)); |
| 819 | +values[Anum_pg_largeobject_loid-1]=ObjectIdGetDatum(obj_desc->id); |
| 820 | +values[Anum_pg_largeobject_pageno-1]=Int32GetDatum(pageno); |
| 821 | +values[Anum_pg_largeobject_data-1]=PointerGetDatum(&workbuf); |
| 822 | +newtup=heap_formtuple(lo_heap_r->rd_att,values,nulls); |
| 823 | +simple_heap_insert(lo_heap_r,newtup); |
| 824 | +CatalogIndexInsert(indstate,newtup); |
| 825 | +heap_freetuple(newtup); |
| 826 | +} |
| 827 | + |
| 828 | +/* |
| 829 | + * Delete any pages after the truncation point |
| 830 | + */ |
| 831 | +while ((oldtuple=index_getnext(sd,ForwardScanDirection))!=NULL) |
| 832 | +{ |
| 833 | +simple_heap_delete(lo_heap_r,&oldtuple->t_self); |
| 834 | +} |
| 835 | + |
| 836 | +index_endscan(sd); |
| 837 | + |
| 838 | +CatalogCloseIndexes(indstate); |
| 839 | + |
| 840 | +/* |
| 841 | + * Advance command counter so that tuple updates will be seen by later |
| 842 | + * large-object operations in this transaction. |
| 843 | + */ |
| 844 | +CommandCounterIncrement(); |
| 845 | +} |
| 846 | + |