Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 283129e

Browse files
committed
Support pg_read_[binary_]file (filename, missing_ok).
There wasn't an especially nice way to read all of a file while passing missing_ok = true. Add an additional overloaded variant to support that use-case. While here, refactor the C code to avoid a rats-nest of PG_NARGS checks, instead handling the argument collection in the outer wrapper functions. It's a bit longer this way, but far more straightforward. (Upon looking at the code coverage report for genfile.c, I was impelled to also add a test case for pg_stat_file() -- tgl) Kyotaro Horiguchi Discussion: https://postgr.es/m/20220607.160520.1984541900138970018.horikyota.ntt@gmail.com
1 parent fd96d14 commit 283129e

File tree

7 files changed

+254
-72
lines changed

7 files changed

+254
-72
lines changed

doc/src/sgml/func.sgml

+14-4
Original file line numberDiff line numberDiff line change
@@ -28411,13 +28411,23 @@ SELECT pg_size_pretty(sum(pg_relation_size(relid))) AS total_size
2841128411
considered.
2841228412
</para>
2841328413

28414+
<para>
28415+
When granting privilege on these functions, note that the table entries
28416+
showing optional parameters are mostly implemented as several physical
28417+
functions with different parameter lists. Privilege must be granted
28418+
separately on each such function, if it is to be
28419+
used. <application>psql</application>'s <command>\df</command> command
28420+
can be useful to check what the actual function signatures are.
28421+
</para>
28422+
2841428423
<para>
2841528424
Some of these functions take an optional <parameter>missing_ok</parameter>
2841628425
parameter, which specifies the behavior when the file or directory does
2841728426
not exist. If <literal>true</literal>, the function
2841828427
returns <literal>NULL</literal> or an empty result set, as appropriate.
28419-
If <literal>false</literal>, an error is raised. The default
28420-
is <literal>false</literal>.
28428+
If <literal>false</literal>, an error is raised. (Failure conditions
28429+
other than <quote>file not found</quote> are reported as errors in any
28430+
case.) The default is <literal>false</literal>.
2842128431
</para>
2842228432

2842328433
<table id="functions-admin-genfile-table">
@@ -28636,7 +28646,7 @@ SELECT pg_size_pretty(sum(pg_relation_size(relid))) AS total_size
2863628646
<indexterm>
2863728647
<primary>pg_read_file</primary>
2863828648
</indexterm>
28639-
<function>pg_read_file</function> ( <parameter>filename</parameter> <type>text</type> <optional>, <parameter>offset</parameter> <type>bigint</type>, <parameter>length</parameter> <type>bigint</type> <optional>, <parameter>missing_ok</parameter> <type>boolean</type> </optional></optional> )
28649+
<function>pg_read_file</function> ( <parameter>filename</parameter> <type>text</type> <optional>, <parameter>offset</parameter> <type>bigint</type>, <parameter>length</parameter> <type>bigint</type> </optional> <optional>, <parameter>missing_ok</parameter> <type>boolean</type> </optional> )
2864028650
<returnvalue>text</returnvalue>
2864128651
</para>
2864228652
<para>
@@ -28661,7 +28671,7 @@ SELECT pg_size_pretty(sum(pg_relation_size(relid))) AS total_size
2866128671
<indexterm>
2866228672
<primary>pg_read_binary_file</primary>
2866328673
</indexterm>
28664-
<function>pg_read_binary_file</function> ( <parameter>filename</parameter> <type>text</type> <optional>, <parameter>offset</parameter> <type>bigint</type>, <parameter>length</parameter> <type>bigint</type> <optional>, <parameter>missing_ok</parameter> <type>boolean</type> </optional></optional> )
28674+
<function>pg_read_binary_file</function> ( <parameter>filename</parameter> <type>text</type> <optional>, <parameter>offset</parameter> <type>bigint</type>, <parameter>length</parameter> <type>bigint</type> </optional> <optional>, <parameter>missing_ok</parameter> <type>boolean</type> </optional> )
2866528675
<returnvalue>bytea</returnvalue>
2866628676
</para>
2866728677
<para>

src/backend/catalog/system_functions.sql

+4
Original file line numberDiff line numberDiff line change
@@ -659,12 +659,16 @@ REVOKE EXECUTE ON FUNCTION pg_ls_tmpdir(oid) FROM public;
659659

660660
REVOKE EXECUTE ON FUNCTION pg_read_file(text) FROM public;
661661

662+
REVOKE EXECUTE ON FUNCTION pg_read_file(text,boolean) FROM public;
663+
662664
REVOKE EXECUTE ON FUNCTION pg_read_file(text,bigint,bigint) FROM public;
663665

664666
REVOKE EXECUTE ON FUNCTION pg_read_file(text,bigint,bigint,boolean) FROM public;
665667

666668
REVOKE EXECUTE ON FUNCTION pg_read_binary_file(text) FROM public;
667669

670+
REVOKE EXECUTE ON FUNCTION pg_read_binary_file(text,boolean) FROM public;
671+
668672
REVOKE EXECUTE ON FUNCTION pg_read_binary_file(text,bigint,bigint) FROM public;
669673

670674
REVOKE EXECUTE ON FUNCTION pg_read_binary_file(text,bigint,bigint,boolean) FROM public;

src/backend/utils/adt/genfile.c

+135-65
Original file line numberDiff line numberDiff line change
@@ -278,81 +278,50 @@ pg_read_file(PG_FUNCTION_ARGS)
278278
*
279279
* No superuser check done here- instead privileges are handled by the
280280
* GRANT system.
281+
*
282+
* If read_to_eof is true, bytes_to_read must be -1, otherwise negative values
283+
* are not allowed for bytes_to_read.
281284
*/
282-
Datum
283-
pg_read_file_v2(PG_FUNCTION_ARGS)
285+
static text *
286+
pg_read_file_common(text *filename_t, int64 seek_offset, int64 bytes_to_read,
287+
bool read_to_eof, bool missing_ok)
284288
{
285-
text *filename_t = PG_GETARG_TEXT_PP(0);
286-
int64 seek_offset = 0;
287-
int64 bytes_to_read = -1;
288-
bool missing_ok = false;
289-
char *filename;
290-
text *result;
291-
292-
/* handle optional arguments */
293-
if (PG_NARGS() >= 3)
294-
{
295-
seek_offset = PG_GETARG_INT64(1);
296-
bytes_to_read = PG_GETARG_INT64(2);
297-
298-
if (bytes_to_read < 0)
299-
ereport(ERROR,
300-
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
301-
errmsg("requested length cannot be negative")));
302-
}
303-
if (PG_NARGS() >= 4)
304-
missing_ok = PG_GETARG_BOOL(3);
305-
306-
filename = convert_and_check_filename(filename_t);
289+
if (read_to_eof)
290+
Assert(bytes_to_read == -1);
291+
else if (bytes_to_read < 0)
292+
ereport(ERROR,
293+
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
294+
errmsg("requested length cannot be negative")));
307295

308-
result = read_text_file(filename, seek_offset, bytes_to_read, missing_ok);
309-
if (result)
310-
PG_RETURN_TEXT_P(result);
311-
else
312-
PG_RETURN_NULL();
296+
return read_text_file(convert_and_check_filename(filename_t),
297+
seek_offset, bytes_to_read, missing_ok);
313298
}
314299

315300
/*
316301
* Read a section of a file, returning it as bytea
302+
*
303+
* Parameters are interpreted the same as pg_read_file_common().
317304
*/
318-
Datum
319-
pg_read_binary_file(PG_FUNCTION_ARGS)
305+
static bytea *
306+
pg_read_binary_file_common(text *filename_t,
307+
int64 seek_offset, int64 bytes_to_read,
308+
bool read_to_eof, bool missing_ok)
320309
{
321-
text *filename_t = PG_GETARG_TEXT_PP(0);
322-
int64 seek_offset = 0;
323-
int64 bytes_to_read = -1;
324-
bool missing_ok = false;
325-
char *filename;
326-
bytea *result;
327-
328-
/* handle optional arguments */
329-
if (PG_NARGS() >= 3)
330-
{
331-
seek_offset = PG_GETARG_INT64(1);
332-
bytes_to_read = PG_GETARG_INT64(2);
333-
334-
if (bytes_to_read < 0)
335-
ereport(ERROR,
336-
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
337-
errmsg("requested length cannot be negative")));
338-
}
339-
if (PG_NARGS() >= 4)
340-
missing_ok = PG_GETARG_BOOL(3);
341-
342-
filename = convert_and_check_filename(filename_t);
310+
if (read_to_eof)
311+
Assert(bytes_to_read == -1);
312+
else if (bytes_to_read < 0)
313+
ereport(ERROR,
314+
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
315+
errmsg("requested length cannot be negative")));
343316

344-
result = read_binary_file(filename, seek_offset,
345-
bytes_to_read, missing_ok);
346-
if (result)
347-
PG_RETURN_BYTEA_P(result);
348-
else
349-
PG_RETURN_NULL();
317+
return read_binary_file(convert_and_check_filename(filename_t),
318+
seek_offset, bytes_to_read, missing_ok);
350319
}
351320

352321

353322
/*
354-
* Wrapper functions for the 1 and 3 argument variants of pg_read_file_v2()
355-
* and pg_read_binary_file().
323+
* Wrapper functions for the variants of SQL functions pg_read_file() and
324+
* pg_read_binary_file().
356325
*
357326
* These are necessary to pass the sanity check in opr_sanity, which checks
358327
* that all built-in functions that share the implementing C function take
@@ -361,25 +330,126 @@ pg_read_binary_file(PG_FUNCTION_ARGS)
361330
Datum
362331
pg_read_file_off_len(PG_FUNCTION_ARGS)
363332
{
364-
return pg_read_file_v2(fcinfo);
333+
text *filename_t = PG_GETARG_TEXT_PP(0);
334+
int64 seek_offset = PG_GETARG_INT64(1);
335+
int64 bytes_to_read = PG_GETARG_INT64(2);
336+
text *ret;
337+
338+
ret = pg_read_file_common(filename_t, seek_offset, bytes_to_read,
339+
false, false);
340+
if (!ret)
341+
PG_RETURN_NULL();
342+
343+
PG_RETURN_TEXT_P(ret);
344+
}
345+
346+
Datum
347+
pg_read_file_off_len_missing(PG_FUNCTION_ARGS)
348+
{
349+
text *filename_t = PG_GETARG_TEXT_PP(0);
350+
int64 seek_offset = PG_GETARG_INT64(1);
351+
int64 bytes_to_read = PG_GETARG_INT64(2);
352+
bool missing_ok = PG_GETARG_BOOL(3);
353+
text *ret;
354+
355+
ret = pg_read_file_common(filename_t, seek_offset, bytes_to_read,
356+
false, missing_ok);
357+
358+
if (!ret)
359+
PG_RETURN_NULL();
360+
361+
PG_RETURN_TEXT_P(ret);
365362
}
366363

367364
Datum
368365
pg_read_file_all(PG_FUNCTION_ARGS)
369366
{
370-
return pg_read_file_v2(fcinfo);
367+
text *filename_t = PG_GETARG_TEXT_PP(0);
368+
text *ret;
369+
370+
ret = pg_read_file_common(filename_t, 0, -1, true, false);
371+
372+
if (!ret)
373+
PG_RETURN_NULL();
374+
375+
PG_RETURN_TEXT_P(ret);
376+
}
377+
378+
Datum
379+
pg_read_file_all_missing(PG_FUNCTION_ARGS)
380+
{
381+
text *filename_t = PG_GETARG_TEXT_PP(0);
382+
bool missing_ok = PG_GETARG_BOOL(1);
383+
text *ret;
384+
385+
ret = pg_read_file_common(filename_t, 0, -1, true, missing_ok);
386+
387+
if (!ret)
388+
PG_RETURN_NULL();
389+
390+
PG_RETURN_TEXT_P(ret);
371391
}
372392

373393
Datum
374394
pg_read_binary_file_off_len(PG_FUNCTION_ARGS)
375395
{
376-
return pg_read_binary_file(fcinfo);
396+
text *filename_t = PG_GETARG_TEXT_PP(0);
397+
int64 seek_offset = PG_GETARG_INT64(1);
398+
int64 bytes_to_read = PG_GETARG_INT64(2);
399+
text *ret;
400+
401+
ret = pg_read_binary_file_common(filename_t, seek_offset, bytes_to_read,
402+
false, false);
403+
if (!ret)
404+
PG_RETURN_NULL();
405+
406+
PG_RETURN_BYTEA_P(ret);
407+
}
408+
409+
Datum
410+
pg_read_binary_file_off_len_missing(PG_FUNCTION_ARGS)
411+
{
412+
text *filename_t = PG_GETARG_TEXT_PP(0);
413+
int64 seek_offset = PG_GETARG_INT64(1);
414+
int64 bytes_to_read = PG_GETARG_INT64(2);
415+
bool missing_ok = PG_GETARG_BOOL(3);
416+
text *ret;
417+
418+
ret = pg_read_binary_file_common(filename_t, seek_offset, bytes_to_read,
419+
false, missing_ok);
420+
if (!ret)
421+
PG_RETURN_NULL();
422+
423+
PG_RETURN_BYTEA_P(ret);
377424
}
378425

379426
Datum
380427
pg_read_binary_file_all(PG_FUNCTION_ARGS)
381428
{
382-
return pg_read_binary_file(fcinfo);
429+
text *filename_t = PG_GETARG_TEXT_PP(0);
430+
text *ret;
431+
432+
ret = pg_read_binary_file_common(filename_t, 0, -1, true, false);
433+
434+
if (!ret)
435+
PG_RETURN_NULL();
436+
437+
PG_RETURN_BYTEA_P(ret);
438+
}
439+
440+
Datum
441+
pg_read_binary_file_all_missing(PG_FUNCTION_ARGS)
442+
{
443+
text *filename_t = PG_GETARG_TEXT_PP(0);
444+
bool missing_ok = PG_GETARG_BOOL(1);
445+
text *ret;
446+
447+
ret = pg_read_binary_file_common(filename_t, 0, -1, true, missing_ok);
448+
449+
if (!ret)
450+
PG_RETURN_NULL();
451+
452+
PG_RETURN_BYTEA_P(ret);
383453
}
384454

385455
/*

src/include/catalog/catversion.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,6 @@
5757
*/
5858

5959
/* yyyymmddN */
60-
#define CATALOG_VERSION_NO 202207271
60+
#define CATALOG_VERSION_NO 202207291
6161

6262
#endif

src/include/catalog/pg_proc.dat

+10-2
Original file line numberDiff line numberDiff line change
@@ -6415,23 +6415,31 @@
64156415
proargtypes => 'text int8 int8', prosrc => 'pg_read_file_off_len' },
64166416
{ oid => '3293', descr => 'read text from a file',
64176417
proname => 'pg_read_file', provolatile => 'v', prorettype => 'text',
6418-
proargtypes => 'text int8 int8 bool', prosrc => 'pg_read_file_v2' },
6418+
proargtypes => 'text int8 int8 bool',
6419+
prosrc => 'pg_read_file_off_len_missing' },
64196420
{ oid => '4100',
64206421
descr => 'read text from a file - old version for adminpack 1.0',
64216422
proname => 'pg_read_file_old', provolatile => 'v', prorettype => 'text',
64226423
proargtypes => 'text int8 int8', prosrc => 'pg_read_file' },
64236424
{ oid => '3826', descr => 'read text from a file',
64246425
proname => 'pg_read_file', provolatile => 'v', prorettype => 'text',
64256426
proargtypes => 'text', prosrc => 'pg_read_file_all' },
6427+
{ oid => '8025', descr => 'read text from a file',
6428+
proname => 'pg_read_file', provolatile => 'v', prorettype => 'text',
6429+
proargtypes => 'text bool', prosrc => 'pg_read_file_all_missing' },
64266430
{ oid => '3827', descr => 'read bytea from a file',
64276431
proname => 'pg_read_binary_file', provolatile => 'v', prorettype => 'bytea',
64286432
proargtypes => 'text int8 int8', prosrc => 'pg_read_binary_file_off_len' },
64296433
{ oid => '3295', descr => 'read bytea from a file',
64306434
proname => 'pg_read_binary_file', provolatile => 'v', prorettype => 'bytea',
6431-
proargtypes => 'text int8 int8 bool', prosrc => 'pg_read_binary_file' },
6435+
proargtypes => 'text int8 int8 bool',
6436+
prosrc => 'pg_read_binary_file_off_len_missing' },
64326437
{ oid => '3828', descr => 'read bytea from a file',
64336438
proname => 'pg_read_binary_file', provolatile => 'v', prorettype => 'bytea',
64346439
proargtypes => 'text', prosrc => 'pg_read_binary_file_all' },
6440+
{ oid => '8026', descr => 'read bytea from a file',
6441+
proname => 'pg_read_binary_file', provolatile => 'v', prorettype => 'bytea',
6442+
proargtypes => 'text bool', prosrc => 'pg_read_binary_file_all_missing' },
64356443
{ oid => '2625', descr => 'list all files in a directory',
64366444
proname => 'pg_ls_dir', prorows => '1000', proretset => 't',
64376445
provolatile => 'v', prorettype => 'text', proargtypes => 'text',

0 commit comments

Comments
 (0)