Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit0763a56

Browse files
committed
Add lo_truncate() to backend and libpq for large object truncation.
Kris Jurka
1 parent90d7652 commit0763a56

File tree

12 files changed

+372
-26
lines changed

12 files changed

+372
-26
lines changed

‎doc/src/sgml/lobj.sgml

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<!-- $PostgreSQL: pgsql/doc/src/sgml/lobj.sgml,v 1.44 2007/02/01 19:10:24 momjian Exp $ -->
1+
<!-- $PostgreSQL: pgsql/doc/src/sgml/lobj.sgml,v 1.45 2007/03/03 19:52:45 momjian Exp $ -->
22

33
<chapter id="largeObjects">
44
<title id="largeObjects-title">Large Objects</title>
@@ -301,6 +301,37 @@ int lo_tell(PGconn *conn, int fd);
301301
</para>
302302
</sect2>
303303

304+
<sect2>
305+
<title>Truncating a Large Object</title>
306+
307+
<para>
308+
To truncate a large object to a given length, call
309+
<synopsis>
310+
int lo_truncate(PGcon *conn, int fd, size_t len);
311+
</synopsis>
312+
<indexterm><primary>lo_truncate</></> truncates the large object
313+
descriptor <parameter>fd</> to length <parameter>len</>. The
314+
<parameter>fd</parameter> argument must have been returned by a
315+
previous <function>lo_open</function>. If <parameter>len</> is
316+
greater than the current large object length, the large object
317+
is extended with null bytes ('\0').
318+
</para>
319+
320+
<para>
321+
The file offset is not changed.
322+
</para>
323+
324+
<para>
325+
On success <function>lo_truncate</function> returns
326+
zero. On error, the return value is negative.
327+
</para>
328+
329+
<para>
330+
<function>lo_truncate</> is new as of <productname>PostgreSQL</productname>
331+
8.3; if this function is run against an older server version, it will
332+
fail and return a negative value.
333+
</para>
334+
304335
<sect2>
305336
<title>Closing a Large Object Descriptor</title>
306337

‎src/backend/libpq/be-fsstubs.c

Lines changed: 22 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/libpq/be-fsstubs.c,v 1.85 2007/02/27 23:48:07 tgl Exp $
11+
* $PostgreSQL: pgsql/src/backend/libpq/be-fsstubs.c,v 1.86 2007/03/03 19:52:46 momjian Exp $
1212
*
1313
* NOTES
1414
* This should be moved to a more appropriate place. It is here
@@ -120,12 +120,10 @@ lo_close(PG_FUNCTION_ARGS)
120120
int32fd=PG_GETARG_INT32(0);
121121

122122
if (fd<0||fd >=cookies_size||cookies[fd]==NULL)
123-
{
124123
ereport(ERROR,
125124
(errcode(ERRCODE_UNDEFINED_OBJECT),
126125
errmsg("invalid large-object descriptor: %d",fd)));
127-
PG_RETURN_INT32(-1);
128-
}
126+
129127
#ifFSDB
130128
elog(DEBUG4,"lo_close(%d)",fd);
131129
#endif
@@ -152,12 +150,9 @@ lo_read(int fd, char *buf, int len)
152150
intstatus;
153151

154152
if (fd<0||fd >=cookies_size||cookies[fd]==NULL)
155-
{
156153
ereport(ERROR,
157154
(errcode(ERRCODE_UNDEFINED_OBJECT),
158155
errmsg("invalid large-object descriptor: %d",fd)));
159-
return-1;
160-
}
161156

162157
status=inv_read(cookies[fd],buf,len);
163158

@@ -170,12 +165,9 @@ lo_write(int fd, const char *buf, int len)
170165
intstatus;
171166

172167
if (fd<0||fd >=cookies_size||cookies[fd]==NULL)
173-
{
174168
ereport(ERROR,
175169
(errcode(ERRCODE_UNDEFINED_OBJECT),
176170
errmsg("invalid large-object descriptor: %d",fd)));
177-
return-1;
178-
}
179171

180172
if ((cookies[fd]->flags&IFS_WRLOCK)==0)
181173
ereport(ERROR,
@@ -198,12 +190,9 @@ lo_lseek(PG_FUNCTION_ARGS)
198190
intstatus;
199191

200192
if (fd<0||fd >=cookies_size||cookies[fd]==NULL)
201-
{
202193
ereport(ERROR,
203194
(errcode(ERRCODE_UNDEFINED_OBJECT),
204195
errmsg("invalid large-object descriptor: %d",fd)));
205-
PG_RETURN_INT32(-1);
206-
}
207196

208197
status=inv_seek(cookies[fd],offset,whence);
209198

@@ -248,12 +237,9 @@ lo_tell(PG_FUNCTION_ARGS)
248237
int32fd=PG_GETARG_INT32(0);
249238

250239
if (fd<0||fd >=cookies_size||cookies[fd]==NULL)
251-
{
252240
ereport(ERROR,
253241
(errcode(ERRCODE_UNDEFINED_OBJECT),
254242
errmsg("invalid large-object descriptor: %d",fd)));
255-
PG_RETURN_INT32(-1);
256-
}
257243

258244
PG_RETURN_INT32(inv_tell(cookies[fd]));
259245
}
@@ -467,6 +453,26 @@ lo_export(PG_FUNCTION_ARGS)
467453
PG_RETURN_INT32(1);
468454
}
469455

456+
/*
457+
* lo_truncate -
458+
* truncate a large object to a specified length
459+
*/
460+
Datum
461+
lo_truncate(PG_FUNCTION_ARGS)
462+
{
463+
int32fd=PG_GETARG_INT32(0);
464+
int32len=PG_GETARG_INT32(1);
465+
466+
if (fd<0||fd >=cookies_size||cookies[fd]==NULL)
467+
ereport(ERROR,
468+
(errcode(ERRCODE_UNDEFINED_OBJECT),
469+
errmsg("invalid large-object descriptor: %d",fd)));
470+
471+
inv_truncate(cookies[fd],len);
472+
473+
PG_RETURN_INT32(0);
474+
}
475+
470476
/*
471477
* AtEOXact_LargeObject -
472478
* prepares large objects for transaction commit

‎src/backend/storage/large_object/inv_api.c

Lines changed: 164 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
*
1818
*
1919
* 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 $
2121
*
2222
*-------------------------------------------------------------------------
2323
*/
@@ -681,3 +681,166 @@ inv_write(LargeObjectDesc *obj_desc, const char *buf, int nbytes)
681681

682682
returnnwritten;
683683
}
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+

‎src/include/catalog/pg_proc.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
88
* Portions Copyright (c) 1994, Regents of the University of California
99
*
10-
* $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.446 2007/02/20 10:00:25 petere Exp $
10+
* $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.447 2007/03/03 19:52:46 momjian Exp $
1111
*
1212
* NOTES
1313
* The script catalog/genbki.sh reads this file and generates .bki
@@ -1233,6 +1233,8 @@ DATA(insert OID = 715 ( lo_create PGNSP PGUID 12 1 0 f f t f v 1 26 "26" _n
12331233
DESCR("large object create");
12341234
DATA(insertOID=958 (lo_tellPGNSPPGUID1210fftfv123"23"_null__null__null_lo_tell-_null_ ));
12351235
DESCR("large object position");
1236+
DATA(insertOID=1004 (lo_truncatePGNSPPGUID1210fftfv223"23 23"_null__null__null_lo_truncate-_null_ ));
1237+
DESCR("truncate large object");
12361238

12371239
DATA(insertOID=959 (on_plPGNSPPGUID1210fftfi216"600 628"_null__null__null_on_pl-_null_ ));
12381240
DESCR("point on line?");

‎src/include/libpq/be-fsstubs.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
88
* Portions Copyright (c) 1994, Regents of the University of California
99
*
10-
* $PostgreSQL: pgsql/src/include/libpq/be-fsstubs.h,v 1.28 2007/01/05 22:19:55 momjian Exp $
10+
* $PostgreSQL: pgsql/src/include/libpq/be-fsstubs.h,v 1.29 2007/03/0319:52:46 momjian Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -34,6 +34,7 @@ extern Datum lowrite(PG_FUNCTION_ARGS);
3434
externDatumlo_lseek(PG_FUNCTION_ARGS);
3535
externDatumlo_tell(PG_FUNCTION_ARGS);
3636
externDatumlo_unlink(PG_FUNCTION_ARGS);
37+
externDatumlo_truncate(PG_FUNCTION_ARGS);
3738

3839
/*
3940
* These are not fmgr-callable, but are available to C code.

‎src/include/storage/large_object.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
99
* Portions Copyright (c) 1994, Regents of the University of California
1010
*
11-
* $PostgreSQL: pgsql/src/include/storage/large_object.h,v 1.36 2007/01/05 22:19:58 momjian Exp $
11+
* $PostgreSQL: pgsql/src/include/storage/large_object.h,v 1.37 2007/03/0319:52:46 momjian Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -78,5 +78,6 @@ extern intinv_seek(LargeObjectDesc *obj_desc, int offset, int whence);
7878
externintinv_tell(LargeObjectDesc*obj_desc);
7979
externintinv_read(LargeObjectDesc*obj_desc,char*buf,intnbytes);
8080
externintinv_write(LargeObjectDesc*obj_desc,constchar*buf,intnbytes);
81+
externvoidinv_truncate(LargeObjectDesc*obj_desc,intlen);
8182

8283
#endif/* LARGE_OBJECT_H */

‎src/interfaces/libpq/exports.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# $PostgreSQL: pgsql/src/interfaces/libpq/exports.txt,v 1.14 2006/08/18 19:52:39 tgl Exp $
1+
# $PostgreSQL: pgsql/src/interfaces/libpq/exports.txt,v 1.15 2007/03/03 19:52:46 momjian Exp $
22
# Functions to be exported by libpq DLLs
33
PQconnectdb 1
44
PQsetdbLogin 2
@@ -136,3 +136,4 @@ PQdescribePrepared 133
136136
PQdescribePortal 134
137137
PQsendDescribePrepared 135
138138
PQsendDescribePortal 136
139+
lo_truncate 137

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp