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

Commit55f4802

Browse files
committed
Prevent write operations on large objects in read-only transactions
Attempting such an operation would already fail, but in various andconfusing ways. For example, while in recovery, some elog() messageswould be reported, but these should never be user-facing. This commitrestricts any write operations done on large objects in a read-onlycontext, so as the errors generated are more user-friendly. This is perthe discussion done with Tom Lane and Robert Haas.Some regression tests are added to check the case of all the SQLfunctions working on large objects (including an update of the test'salternate output).Author: Yugo NagataDiscussion:https://postgr.es/m/20220527153028.61a4608f66abcd026fd3806f@sraoss.co.jp
1 parent8ba3cb2 commit55f4802

File tree

5 files changed

+166
-1
lines changed

5 files changed

+166
-1
lines changed

‎doc/src/sgml/lobj.sgml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,9 @@
114114
All large object manipulation using these functions
115115
<emphasis>must</emphasis> take place within an SQL transaction block,
116116
since large object file descriptors are only valid for the duration of
117-
a transaction.
117+
a transaction. Write operations, including <function>lo_open</function>
118+
with the <symbol>INV_WRITE</symbol> mode, are not allowed in a read-only
119+
transaction.
118120
</para>
119121

120122
<para>

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

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,9 @@ be_lo_open(PG_FUNCTION_ARGS)
9393
elog(DEBUG4,"lo_open(%u,%d)",lobjId,mode);
9494
#endif
9595

96+
if (mode&INV_WRITE)
97+
PreventCommandIfReadOnly("lo_open(INV_WRITE)");
98+
9699
/*
97100
* Allocate a large object descriptor first. This will also create
98101
* 'fscxt' if this is the first LO opened in this transaction.
@@ -245,6 +248,8 @@ be_lo_creat(PG_FUNCTION_ARGS)
245248
{
246249
OidlobjId;
247250

251+
PreventCommandIfReadOnly("lo_creat()");
252+
248253
lo_cleanup_needed= true;
249254
lobjId=inv_create(InvalidOid);
250255

@@ -256,6 +261,8 @@ be_lo_create(PG_FUNCTION_ARGS)
256261
{
257262
OidlobjId=PG_GETARG_OID(0);
258263

264+
PreventCommandIfReadOnly("lo_create()");
265+
259266
lo_cleanup_needed= true;
260267
lobjId=inv_create(lobjId);
261268

@@ -306,6 +313,8 @@ be_lo_unlink(PG_FUNCTION_ARGS)
306313
{
307314
OidlobjId=PG_GETARG_OID(0);
308315

316+
PreventCommandIfReadOnly("lo_unlink()");
317+
309318
/*
310319
* Must be owner of the large object. It would be cleaner to check this
311320
* in inv_drop(), but we want to throw the error before not after closing
@@ -368,6 +377,8 @@ be_lowrite(PG_FUNCTION_ARGS)
368377
intbytestowrite;
369378
inttotalwritten;
370379

380+
PreventCommandIfReadOnly("lowrite()");
381+
371382
bytestowrite=VARSIZE_ANY_EXHDR(wbuf);
372383
totalwritten=lo_write(fd,VARDATA_ANY(wbuf),bytestowrite);
373384
PG_RETURN_INT32(totalwritten);
@@ -413,6 +424,8 @@ lo_import_internal(text *filename, Oid lobjOid)
413424
LargeObjectDesc*lobj;
414425
Oidoid;
415426

427+
PreventCommandIfReadOnly("lo_import()");
428+
416429
/*
417430
* open the file to be read in
418431
*/
@@ -561,6 +574,8 @@ be_lo_truncate(PG_FUNCTION_ARGS)
561574
int32fd=PG_GETARG_INT32(0);
562575
int32len=PG_GETARG_INT32(1);
563576

577+
PreventCommandIfReadOnly("lo_truncate()");
578+
564579
lo_truncate_internal(fd,len);
565580
PG_RETURN_INT32(0);
566581
}
@@ -571,6 +586,8 @@ be_lo_truncate64(PG_FUNCTION_ARGS)
571586
int32fd=PG_GETARG_INT32(0);
572587
int64len=PG_GETARG_INT64(1);
573588

589+
PreventCommandIfReadOnly("lo_truncate64()");
590+
574591
lo_truncate_internal(fd,len);
575592
PG_RETURN_INT32(0);
576593
}
@@ -815,6 +832,8 @@ be_lo_from_bytea(PG_FUNCTION_ARGS)
815832
LargeObjectDesc*loDesc;
816833
intwrittenPG_USED_FOR_ASSERTS_ONLY;
817834

835+
PreventCommandIfReadOnly("lo_from_bytea()");
836+
818837
lo_cleanup_needed= true;
819838
loOid=inv_create(loOid);
820839
loDesc=inv_open(loOid,INV_WRITE,CurrentMemoryContext);
@@ -837,6 +856,8 @@ be_lo_put(PG_FUNCTION_ARGS)
837856
LargeObjectDesc*loDesc;
838857
intwrittenPG_USED_FOR_ASSERTS_ONLY;
839858

859+
PreventCommandIfReadOnly("lo_put()");
860+
840861
lo_cleanup_needed= true;
841862
loDesc=inv_open(loOid,INV_WRITE,CurrentMemoryContext);
842863

‎src/test/regress/expected/largeobject.out

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -506,6 +506,55 @@ SELECT lo_create(2121);
506506
(1 row)
507507

508508
COMMENT ON LARGE OBJECT 2121 IS 'testing comments';
509+
-- Test writes on large objects in read-only transactions
510+
START TRANSACTION READ ONLY;
511+
-- INV_READ ... ok
512+
SELECT lo_open(2121, x'40000'::int);
513+
lo_open
514+
---------
515+
0
516+
(1 row)
517+
518+
-- INV_WRITE ... error
519+
SELECT lo_open(2121, x'20000'::int);
520+
ERROR: cannot execute lo_open(INV_WRITE) in a read-only transaction
521+
ROLLBACK;
522+
START TRANSACTION READ ONLY;
523+
SELECT lo_create(42);
524+
ERROR: cannot execute lo_create() in a read-only transaction
525+
ROLLBACK;
526+
START TRANSACTION READ ONLY;
527+
SELECT lo_creat(42);
528+
ERROR: cannot execute lo_creat() in a read-only transaction
529+
ROLLBACK;
530+
START TRANSACTION READ ONLY;
531+
SELECT lo_unlink(42);
532+
ERROR: cannot execute lo_unlink() in a read-only transaction
533+
ROLLBACK;
534+
START TRANSACTION READ ONLY;
535+
SELECT lowrite(42, 'x');
536+
ERROR: cannot execute lowrite() in a read-only transaction
537+
ROLLBACK;
538+
START TRANSACTION READ ONLY;
539+
SELECT lo_import(:'filename');
540+
ERROR: cannot execute lo_import() in a read-only transaction
541+
ROLLBACK;
542+
START TRANSACTION READ ONLY;
543+
SELECT lo_truncate(42, 0);
544+
ERROR: cannot execute lo_truncate() in a read-only transaction
545+
ROLLBACK;
546+
START TRANSACTION READ ONLY;
547+
SELECT lo_truncate64(42, 0);
548+
ERROR: cannot execute lo_truncate64() in a read-only transaction
549+
ROLLBACK;
550+
START TRANSACTION READ ONLY;
551+
SELECT lo_from_bytea(0, 'x');
552+
ERROR: cannot execute lo_from_bytea() in a read-only transaction
553+
ROLLBACK;
554+
START TRANSACTION READ ONLY;
555+
SELECT lo_put(42, 0, 'x');
556+
ERROR: cannot execute lo_put() in a read-only transaction
557+
ROLLBACK;
509558
-- Clean up
510559
DROP TABLE lotest_stash_values;
511560
DROP ROLE regress_lo_user;

‎src/test/regress/expected/largeobject_1.out

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -506,6 +506,55 @@ SELECT lo_create(2121);
506506
(1 row)
507507

508508
COMMENT ON LARGE OBJECT 2121 IS 'testing comments';
509+
-- Test writes on large objects in read-only transactions
510+
START TRANSACTION READ ONLY;
511+
-- INV_READ ... ok
512+
SELECT lo_open(2121, x'40000'::int);
513+
lo_open
514+
---------
515+
0
516+
(1 row)
517+
518+
-- INV_WRITE ... error
519+
SELECT lo_open(2121, x'20000'::int);
520+
ERROR: cannot execute lo_open(INV_WRITE) in a read-only transaction
521+
ROLLBACK;
522+
START TRANSACTION READ ONLY;
523+
SELECT lo_create(42);
524+
ERROR: cannot execute lo_create() in a read-only transaction
525+
ROLLBACK;
526+
START TRANSACTION READ ONLY;
527+
SELECT lo_creat(42);
528+
ERROR: cannot execute lo_creat() in a read-only transaction
529+
ROLLBACK;
530+
START TRANSACTION READ ONLY;
531+
SELECT lo_unlink(42);
532+
ERROR: cannot execute lo_unlink() in a read-only transaction
533+
ROLLBACK;
534+
START TRANSACTION READ ONLY;
535+
SELECT lowrite(42, 'x');
536+
ERROR: cannot execute lowrite() in a read-only transaction
537+
ROLLBACK;
538+
START TRANSACTION READ ONLY;
539+
SELECT lo_import(:'filename');
540+
ERROR: cannot execute lo_import() in a read-only transaction
541+
ROLLBACK;
542+
START TRANSACTION READ ONLY;
543+
SELECT lo_truncate(42, 0);
544+
ERROR: cannot execute lo_truncate() in a read-only transaction
545+
ROLLBACK;
546+
START TRANSACTION READ ONLY;
547+
SELECT lo_truncate64(42, 0);
548+
ERROR: cannot execute lo_truncate64() in a read-only transaction
549+
ROLLBACK;
550+
START TRANSACTION READ ONLY;
551+
SELECT lo_from_bytea(0, 'x');
552+
ERROR: cannot execute lo_from_bytea() in a read-only transaction
553+
ROLLBACK;
554+
START TRANSACTION READ ONLY;
555+
SELECT lo_put(42, 0, 'x');
556+
ERROR: cannot execute lo_put() in a read-only transaction
557+
ROLLBACK;
509558
-- Clean up
510559
DROP TABLE lotest_stash_values;
511560
DROP ROLE regress_lo_user;

‎src/test/regress/sql/largeobject.sql

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,50 @@ SELECT lo_create(2121);
271271

272272
COMMENTON LARGE OBJECT2121 IS'testing comments';
273273

274+
-- Test writes on large objects in read-only transactions
275+
START TRANSACTION READ ONLY;
276+
-- INV_READ ... ok
277+
SELECT lo_open(2121, x'40000'::int);
278+
-- INV_WRITE ... error
279+
SELECT lo_open(2121, x'20000'::int);
280+
ROLLBACK;
281+
282+
START TRANSACTION READ ONLY;
283+
SELECT lo_create(42);
284+
ROLLBACK;
285+
286+
START TRANSACTION READ ONLY;
287+
SELECT lo_creat(42);
288+
ROLLBACK;
289+
290+
START TRANSACTION READ ONLY;
291+
SELECT lo_unlink(42);
292+
ROLLBACK;
293+
294+
START TRANSACTION READ ONLY;
295+
SELECT lowrite(42,'x');
296+
ROLLBACK;
297+
298+
START TRANSACTION READ ONLY;
299+
SELECT lo_import(:'filename');
300+
ROLLBACK;
301+
302+
START TRANSACTION READ ONLY;
303+
SELECT lo_truncate(42,0);
304+
ROLLBACK;
305+
306+
START TRANSACTION READ ONLY;
307+
SELECT lo_truncate64(42,0);
308+
ROLLBACK;
309+
310+
START TRANSACTION READ ONLY;
311+
SELECT lo_from_bytea(0,'x');
312+
ROLLBACK;
313+
314+
START TRANSACTION READ ONLY;
315+
SELECT lo_put(42,0,'x');
316+
ROLLBACK;
317+
274318
-- Clean up
275319
DROPTABLE lotest_stash_values;
276320

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp