]> granicus.if.org Git - postgresql/commitdiff
Add missing_ok option to the SQL functions for reading files.
authorHeikki Linnakangas <heikki.linnakangas@iki.fi>
Sun, 28 Jun 2015 18:35:46 +0000 (21:35 +0300)
committerHeikki Linnakangas <heikki.linnakangas@iki.fi>
Sun, 28 Jun 2015 18:35:46 +0000 (21:35 +0300)
This makes it possible to use the functions without getting errors, if there
is a chance that the file might be removed or renamed concurrently.
pg_rewind needs to do just that, although this could be useful for other
purposes too. (The changes to pg_rewind to use these functions will come in
a separate commit.)

The read_binary_file() function isn't very well-suited for extensions.c's
purposes anymore, if it ever was. So bite the bullet and make a copy of it
in extension.c, tailored for that use case. This seems better than the
accidental code reuse, even if it's a some more lines of code.

Michael Paquier, with plenty of kibitzing by me.

doc/src/sgml/func.sgml
src/backend/commands/extension.c
src/backend/utils/adt/genfile.c
src/include/catalog/catversion.h
src/include/catalog/pg_proc.h
src/include/utils/builtins.h

index 80b551e78c7c1f1d9260308879e52ad9bcb84270..69ac7c041692f0b18db4748eff2b573c04614cb2 100644 (file)
@@ -17811,43 +17811,63 @@ postgres=# SELECT * FROM pg_xlogfile_name_offset(pg_stop_backup());
      <tbody>
       <row>
        <entry>
-        <literal><function>pg_ls_dir(<parameter>dirname</> <type>text</>)</function></literal>
+        <literal><function>pg_ls_dir(<parameter>dirname</> <type>text</> [, <parameter>missing_ok</> <type>boolean</>, <parameter>include_dot_dirs</> <type>boolean</>])</function></literal>
        </entry>
        <entry><type>setof text</type></entry>
-       <entry>List the contents of a directory</entry>
+       <entry>
+        List the contents of a directory.
+       </entry>
       </row>
       <row>
        <entry>
-        <literal><function>pg_read_file(<parameter>filename</> <type>text</> [, <parameter>offset</> <type>bigint</>, <parameter>length</> <type>bigint</>])</function></literal>
+        <literal><function>pg_read_file(<parameter>filename</> <type>text</> [, <parameter>offset</> <type>bigint</>, <parameter>length</> <type>bigint</> [, <parameter>missing_ok</> <type>boolean</>] ])</function></literal>
        </entry>
        <entry><type>text</type></entry>
-       <entry>Return the contents of a text file</entry>
+       <entry>
+        Return the contents of a text file.
+       </entry>
       </row>
       <row>
        <entry>
-        <literal><function>pg_read_binary_file(<parameter>filename</> <type>text</> [, <parameter>offset</> <type>bigint</>, <parameter>length</> <type>bigint</>])</function></literal>
+        <literal><function>pg_read_binary_file(<parameter>filename</> <type>text</> [, <parameter>offset</> <type>bigint</>, <parameter>length</> <type>bigint</> [, <parameter>missing_ok</> <type>boolean</>] ])</function></literal>
        </entry>
        <entry><type>bytea</type></entry>
-       <entry>Return the contents of a file</entry>
+       <entry>
+        Return the contents of a file.
+       </entry>
       </row>
       <row>
        <entry>
-        <literal><function>pg_stat_file(<parameter>filename</> <type>text</>)</function></literal>
+        <literal><function>pg_stat_file(<parameter>filename</> <type>text</>[, <parameter>missing_ok</> <type>boolean</type>])</function></literal>
        </entry>
        <entry><type>record</type></entry>
-       <entry>Return information about a file</entry>
+       <entry>
+        Return information about a file.
+       </entry>
       </row>
      </tbody>
     </tgroup>
    </table>
 
+   <para>
+    All of these functions take an optional <parameter>missing_ok</> parameter,
+    which specifies the behaviour when the file or directory does not exist.
+    If <literal>true</literal>, the function returns NULL (except
+    <function>pg_ls_dir</>, which returns an empty result set). If
+    <literal>false</>, an error is raised. The default is <literal>false</>.
+   </para>
+
    <indexterm>
     <primary>pg_ls_dir</primary>
    </indexterm>
    <para>
-    <function>pg_ls_dir</> returns all the names in the specified
-    directory, except the special entries <quote><literal>.</></> and
-    <quote><literal>..</></>.
+    <function>pg_ls_dir</> returns the names of all files (and directories
+    and other special files) in the specified directory. The <parameter>
+    include_dot_dirs</> indicates whether <quote>.</> and <quote>..</> are
+    included in the result set. The default is to exclude them
+    (<literal>false/>), but including them can be useful when
+    <parameter>missing_ok</> is <literal>true</literal>, to distinguish an
+    empty directory from an non-existent directory.
    </para>
 
    <indexterm>
index 5cc74d03c11a3aac696eb98393b0d7e0707133e5..2b1dcd0d19cad52b6428517c0caff1d7bafa09c7 100644 (file)
@@ -25,6 +25,8 @@
 
 #include <dirent.h>
 #include <limits.h>
+#include <sys/file.h>
+#include <sys/stat.h>
 #include <unistd.h>
 
 #include "access/htup_details.h"
@@ -51,6 +53,7 @@
 #include "utils/builtins.h"
 #include "utils/fmgroids.h"
 #include "utils/lsyscache.h"
+#include "utils/memutils.h"
 #include "utils/rel.h"
 #include "utils/snapmgr.h"
 #include "utils/tqual.h"
@@ -103,6 +106,7 @@ static void ApplyExtensionUpdates(Oid extensionOid,
                                          ExtensionControlFile *pcontrol,
                                          const char *initialVersion,
                                          List *updateVersions);
+static char *read_whole_file(const char *filename, int *length);
 
 
 /*
@@ -635,12 +639,11 @@ read_extension_script_file(const ExtensionControlFile *control,
                                                   const char *filename)
 {
        int                     src_encoding;
-       bytea      *content;
        char       *src_str;
        char       *dest_str;
        int                     len;
 
-       content = read_binary_file(filename, 0, -1);
+       src_str = read_whole_file(filename, &len);
 
        /* use database encoding if not given */
        if (control->encoding < 0)
@@ -649,21 +652,15 @@ read_extension_script_file(const ExtensionControlFile *control,
                src_encoding = control->encoding;
 
        /* make sure that source string is valid in the expected encoding */
-       len = VARSIZE_ANY_EXHDR(content);
-       src_str = VARDATA_ANY(content);
        pg_verify_mbstr_len(src_encoding, src_str, len, false);
 
-       /* convert the encoding to the database encoding */
+       /*
+        * Convert the encoding to the database encoding. read_whole_file
+        * null-terminated the string, so if no conversion happens the string is
+        * valid as is.
+        */
        dest_str = pg_any_to_server(src_str, len, src_encoding);
 
-       /* if no conversion happened, we have to arrange for null termination */
-       if (dest_str == src_str)
-       {
-               dest_str = (char *) palloc(len + 1);
-               memcpy(dest_str, src_str, len);
-               dest_str[len] = '\0';
-       }
-
        return dest_str;
 }
 
@@ -3008,3 +3005,49 @@ ExecAlterExtensionContentsStmt(AlterExtensionContentsStmt *stmt,
 
        return extension;
 }
+
+/*
+ * Read the whole of file into memory.
+ *
+ * The file contents are returned as a single palloc'd chunk. For convenience
+ * of the callers, an extra \0 byte is added to the end.
+ */
+static char *
+read_whole_file(const char *filename, int *length)
+{
+       char       *buf;
+       FILE       *file;
+       size_t          bytes_to_read;
+       struct stat fst;
+
+       if (stat(filename, &fst) < 0)
+               ereport(ERROR,
+                               (errcode_for_file_access(),
+                                errmsg("could not stat file \"%s\": %m", filename)));
+
+       if (fst.st_size > (MaxAllocSize - 1))
+               ereport(ERROR,
+                               (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
+                                errmsg("file too large")));
+       bytes_to_read = (size_t) fst.st_size;
+
+       if ((file = AllocateFile(filename, PG_BINARY_R)) == NULL)
+               ereport(ERROR,
+                               (errcode_for_file_access(),
+                                errmsg("could not open file \"%s\" for reading: %m",
+                                               filename)));
+
+       buf = (char *) palloc(bytes_to_read + 1);
+
+       *length = fread(buf, 1, bytes_to_read, file);
+
+       if (ferror(file))
+               ereport(ERROR,
+                               (errcode_for_file_access(),
+                                errmsg("could not read file \"%s\": %m", filename)));
+
+       FreeFile(file);
+
+       buf[*length] = '\0';
+       return buf;
+}
index f3f3cca5155736abaa0f643bf7799c9ef574b4c6..c4eb10d3cfd53ce0261194f655790f2de8c242aa 100644 (file)
@@ -35,6 +35,7 @@ typedef struct
 {
        char       *location;
        DIR                *dirdesc;
+       bool            include_dot_dirs;
 } directory_fctx;
 
 
@@ -87,8 +88,9 @@ convert_and_check_filename(text *arg)
  *
  * We read the whole of the file when bytes_to_read is negative.
  */
-bytea *
-read_binary_file(const char *filename, int64 seek_offset, int64 bytes_to_read)
+static bytea *
+read_binary_file(const char *filename, int64 seek_offset, int64 bytes_to_read,
+                                bool missing_ok)
 {
        bytea      *buf;
        size_t          nbytes;
@@ -103,9 +105,14 @@ read_binary_file(const char *filename, int64 seek_offset, int64 bytes_to_read)
                        struct stat fst;
 
                        if (stat(filename, &fst) < 0)
-                               ereport(ERROR,
-                                               (errcode_for_file_access(),
-                                                errmsg("could not stat file \"%s\": %m", filename)));
+                       {
+                               if (missing_ok && errno == ENOENT)
+                                       return NULL;
+                               else
+                                       ereport(ERROR,
+                                                       (errcode_for_file_access(),
+                                               errmsg("could not stat file \"%s\": %m", filename)));
+                       }
 
                        bytes_to_read = fst.st_size - seek_offset;
                }
@@ -118,10 +125,15 @@ read_binary_file(const char *filename, int64 seek_offset, int64 bytes_to_read)
                                 errmsg("requested length too large")));
 
        if ((file = AllocateFile(filename, PG_BINARY_R)) == NULL)
-               ereport(ERROR,
-                               (errcode_for_file_access(),
-                                errmsg("could not open file \"%s\" for reading: %m",
-                                               filename)));
+       {
+               if (missing_ok && errno == ENOENT)
+                       return NULL;
+               else
+                       ereport(ERROR,
+                                       (errcode_for_file_access(),
+                                        errmsg("could not open file \"%s\" for reading: %m",
+                                                       filename)));
+       }
 
        if (fseeko(file, (off_t) seek_offset,
                           (seek_offset >= 0) ? SEEK_SET : SEEK_END) != 0)
@@ -150,17 +162,23 @@ read_binary_file(const char *filename, int64 seek_offset, int64 bytes_to_read)
  * in the database encoding.
  */
 static text *
-read_text_file(const char *filename, int64 seek_offset, int64 bytes_to_read)
+read_text_file(const char *filename, int64 seek_offset, int64 bytes_to_read,
+                          bool missing_ok)
 {
        bytea      *buf;
 
-       buf = read_binary_file(filename, seek_offset, bytes_to_read);
+       buf = read_binary_file(filename, seek_offset, bytes_to_read, missing_ok);
 
-       /* Make sure the input is valid */
-       pg_verifymbstr(VARDATA(buf), VARSIZE(buf) - VARHDRSZ, false);
+       if (buf != NULL)
+       {
+               /* Make sure the input is valid */
+               pg_verifymbstr(VARDATA(buf), VARSIZE(buf) - VARHDRSZ, false);
 
-       /* OK, we can cast it to text safely */
-       return (text *) buf;
+               /* OK, we can cast it to text safely */
+               return (text *) buf;
+       }
+       else
+               return NULL;
 }
 
 /*
@@ -170,42 +188,38 @@ Datum
 pg_read_file(PG_FUNCTION_ARGS)
 {
        text       *filename_t = PG_GETARG_TEXT_P(0);
-       int64           seek_offset = PG_GETARG_INT64(1);
-       int64           bytes_to_read = PG_GETARG_INT64(2);
+       int64           seek_offset = 0;
+       int64           bytes_to_read = -1;
+       bool            missing_ok = false;
        char       *filename;
+       text       *result;
 
        if (!superuser())
                ereport(ERROR,
                                (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
                                 (errmsg("must be superuser to read files"))));
 
-       filename = convert_and_check_filename(filename_t);
-
-       if (bytes_to_read < 0)
-               ereport(ERROR,
-                               (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-                                errmsg("requested length cannot be negative")));
-
-       PG_RETURN_TEXT_P(read_text_file(filename, seek_offset, bytes_to_read));
-}
-
-/*
- * Read the whole of a file, returning it as text
- */
-Datum
-pg_read_file_all(PG_FUNCTION_ARGS)
-{
-       text       *filename_t = PG_GETARG_TEXT_P(0);
-       char       *filename;
+       /* handle optional arguments */
+       if (PG_NARGS() >= 3)
+       {
+               seek_offset = PG_GETARG_INT64(1);
+               bytes_to_read = PG_GETARG_INT64(2);
 
-       if (!superuser())
-               ereport(ERROR,
-                               (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
-                                (errmsg("must be superuser to read files"))));
+               if (bytes_to_read < 0)
+                       ereport(ERROR,
+                                       (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+                                        errmsg("requested length cannot be negative")));
+       }
+       if (PG_NARGS() >= 4)
+               missing_ok = PG_GETARG_BOOL(3);
 
        filename = convert_and_check_filename(filename_t);
 
-       PG_RETURN_TEXT_P(read_text_file(filename, 0, -1));
+       result = read_text_file(filename, seek_offset, bytes_to_read, missing_ok);
+       if (result)
+               PG_RETURN_TEXT_P(result);
+       else
+               PG_RETURN_NULL();
 }
 
 /*
@@ -215,42 +229,72 @@ Datum
 pg_read_binary_file(PG_FUNCTION_ARGS)
 {
        text       *filename_t = PG_GETARG_TEXT_P(0);
-       int64           seek_offset = PG_GETARG_INT64(1);
-       int64           bytes_to_read = PG_GETARG_INT64(2);
+       int64           seek_offset = 0;
+       int64           bytes_to_read = -1;
+       bool            missing_ok = false;
        char       *filename;
+       bytea      *result;
 
        if (!superuser())
                ereport(ERROR,
                                (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
                                 (errmsg("must be superuser to read files"))));
 
-       filename = convert_and_check_filename(filename_t);
+       /* handle optional arguments */
+       if (PG_NARGS() >= 3)
+       {
+               seek_offset = PG_GETARG_INT64(1);
+               bytes_to_read = PG_GETARG_INT64(2);
 
-       if (bytes_to_read < 0)
-               ereport(ERROR,
-                               (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-                                errmsg("requested length cannot be negative")));
+               if (bytes_to_read < 0)
+                       ereport(ERROR,
+                                       (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+                                        errmsg("requested length cannot be negative")));
+       }
+       if (PG_NARGS() >= 4)
+               missing_ok = PG_GETARG_BOOL(3);
+
+       filename = convert_and_check_filename(filename_t);
 
-       PG_RETURN_BYTEA_P(read_binary_file(filename, seek_offset, bytes_to_read));
+       result = read_binary_file(filename, seek_offset,
+                                                         bytes_to_read, missing_ok);
+       if (result)
+               PG_RETURN_BYTEA_P(result);
+       else
+               PG_RETURN_NULL();
 }
 
+
 /*
- * Read the whole of a file, returning it as bytea
+ * Wrapper functions for the 1 and 3 argument variants of pg_read_file()
+ * and pg_binary_read_file().
+ *
+ * These are necessary to pass the sanity check in opr_sanity, which checks
+ * that all built-in functions that share the implementing C function take
+ * the same number of arguments.
  */
 Datum
-pg_read_binary_file_all(PG_FUNCTION_ARGS)
+pg_read_file_off_len(PG_FUNCTION_ARGS)
 {
-       text       *filename_t = PG_GETARG_TEXT_P(0);
-       char       *filename;
+       return pg_read_file(fcinfo);
+}
 
-       if (!superuser())
-               ereport(ERROR,
-                               (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
-                                (errmsg("must be superuser to read files"))));
+Datum
+pg_read_file_all(PG_FUNCTION_ARGS)
+{
+       return pg_read_file(fcinfo);
+}
 
-       filename = convert_and_check_filename(filename_t);
+Datum
+pg_read_binary_file_off_len(PG_FUNCTION_ARGS)
+{
+       return pg_read_binary_file(fcinfo);
+}
 
-       PG_RETURN_BYTEA_P(read_binary_file(filename, 0, -1));
+Datum
+pg_read_binary_file_all(PG_FUNCTION_ARGS)
+{
+       return pg_read_binary_file(fcinfo);
 }
 
 /*
@@ -266,18 +310,28 @@ pg_stat_file(PG_FUNCTION_ARGS)
        bool            isnull[6];
        HeapTuple       tuple;
        TupleDesc       tupdesc;
+       bool            missing_ok = false;
 
        if (!superuser())
                ereport(ERROR,
                                (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
                                 (errmsg("must be superuser to get file information"))));
 
+       /* check the optional argument */
+       if (PG_NARGS() == 2)
+               missing_ok = PG_GETARG_BOOL(1);
+
        filename = convert_and_check_filename(filename_t);
 
        if (stat(filename, &fst) < 0)
-               ereport(ERROR,
-                               (errcode_for_file_access(),
-                                errmsg("could not stat file \"%s\": %m", filename)));
+       {
+               if (missing_ok && errno == ENOENT)
+                       PG_RETURN_NULL();
+               else
+                       ereport(ERROR,
+                                       (errcode_for_file_access(),
+                                        errmsg("could not stat file \"%s\": %m", filename)));
+       }
 
        /*
         * This record type had better match the output parameters declared for me
@@ -320,6 +374,18 @@ pg_stat_file(PG_FUNCTION_ARGS)
        PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
 }
 
+/*
+ * stat a file (1 argument version)
+ *
+ * note: this wrapper is necessary to pass the sanity check in opr_sanity,
+ * which checks that all built-in functions that share the implementing C
+ * function take the same number of arguments
+ */
+Datum
+pg_stat_file_1arg(PG_FUNCTION_ARGS)
+{
+       return pg_stat_file(fcinfo);
+}
 
 /*
  * List a directory (returns the filenames only)
@@ -330,6 +396,7 @@ pg_ls_dir(PG_FUNCTION_ARGS)
        FuncCallContext *funcctx;
        struct dirent *de;
        directory_fctx *fctx;
+       MemoryContext oldcontext;
 
        if (!superuser())
                ereport(ERROR,
@@ -338,7 +405,17 @@ pg_ls_dir(PG_FUNCTION_ARGS)
 
        if (SRF_IS_FIRSTCALL())
        {
-               MemoryContext oldcontext;
+               bool            missing_ok = false;
+               bool            include_dot_dirs = false;
+
+               /* check the optional arguments */
+               if (PG_NARGS() == 3)
+               {
+                       if (!PG_ARGISNULL(1))
+                               missing_ok = PG_GETARG_BOOL(1);
+                       if (!PG_ARGISNULL(2))
+                               include_dot_dirs = PG_GETARG_BOOL(2);
+               }
 
                funcctx = SRF_FIRSTCALL_INIT();
                oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
@@ -346,14 +423,22 @@ pg_ls_dir(PG_FUNCTION_ARGS)
                fctx = palloc(sizeof(directory_fctx));
                fctx->location = convert_and_check_filename(PG_GETARG_TEXT_P(0));
 
+               fctx->include_dot_dirs = include_dot_dirs;
                fctx->dirdesc = AllocateDir(fctx->location);
 
                if (!fctx->dirdesc)
-                       ereport(ERROR,
-                                       (errcode_for_file_access(),
-                                        errmsg("could not open directory \"%s\": %m",
-                                                       fctx->location)));
-
+               {
+                       if (missing_ok && errno == ENOENT)
+                       {
+                               MemoryContextSwitchTo(oldcontext);
+                               SRF_RETURN_DONE(funcctx);
+                       }
+                       else
+                               ereport(ERROR,
+                                               (errcode_for_file_access(),
+                                                errmsg("could not open directory \"%s\": %m",
+                                                               fctx->location)));
+               }
                funcctx->user_fctx = fctx;
                MemoryContextSwitchTo(oldcontext);
        }
@@ -363,8 +448,9 @@ pg_ls_dir(PG_FUNCTION_ARGS)
 
        while ((de = ReadDir(fctx->dirdesc, fctx->location)) != NULL)
        {
-               if (strcmp(de->d_name, ".") == 0 ||
-                       strcmp(de->d_name, "..") == 0)
+               if (!fctx->include_dot_dirs &&
+                       (strcmp(de->d_name, ".") == 0 ||
+                        strcmp(de->d_name, "..") == 0))
                        continue;
 
                SRF_RETURN_NEXT(funcctx, CStringGetTextDatum(de->d_name));
@@ -374,3 +460,16 @@ pg_ls_dir(PG_FUNCTION_ARGS)
 
        SRF_RETURN_DONE(funcctx);
 }
+
+/*
+ * List a directory (1 argument version)
+ *
+ * note: this wrapper is necessary to pass the sanity check in opr_sanity,
+ * which checks that all built-in functions that share the implementing C
+ * function take the same number of arguments.
+ */
+Datum
+pg_ls_dir_1arg(PG_FUNCTION_ARGS)
+{
+       return pg_ls_dir(fcinfo);
+}
index de9018b957f674cac11c1649323a987d9521fcb6..3515b6436aeae0fa0613dfbab3b5972e1a9276e7 100644 (file)
@@ -53,6 +53,6 @@
  */
 
 /*                                                     yyyymmddN */
-#define CATALOG_VERSION_NO     201506111
+#define CATALOG_VERSION_NO     201506281
 
 #endif
index 6b3d1949ef39e686ced9662dbfe08de7732c7293..d1cc8907d7c8d8206b4a15941b6329c906786d57 100644 (file)
@@ -3181,17 +3181,25 @@ DESCR("reload configuration files");
 DATA(insert OID = 2622 ( pg_rotate_logfile             PGNSP PGUID 12 1 0 0 0 f f f f t f v 0 0 16 "" _null_ _null_ _null_ _null_ _null_ pg_rotate_logfile _null_ _null_ _null_ ));
 DESCR("rotate log file");
 
-DATA(insert OID = 2623 ( pg_stat_file          PGNSP PGUID 12 1 0 0 0 f f f f t f v 1 0 2249 "25" "{25,20,1184,1184,1184,1184,16}" "{i,o,o,o,o,o,o}" "{filename,size,access,modification,change,creation,isdir}" _null_ _null_ pg_stat_file _null_ _null_ _null_ ));
+DATA(insert OID = 2623 ( pg_stat_file          PGNSP PGUID 12 1 0 0 0 f f f f t f v 1 0 2249 "25" "{25,20,1184,1184,1184,1184,16}" "{i,o,o,o,o,o,o}" "{filename,size,access,modification,change,creation,isdir}" _null_ _null_ pg_stat_file_1arg _null_ _null_ _null_ ));
 DESCR("get information about file");
-DATA(insert OID = 2624 ( pg_read_file          PGNSP PGUID 12 1 0 0 0 f f f f t f v 3 0 25 "25 20 20" _null_ _null_ _null_ _null_ _null_ pg_read_file _null_ _null_ _null_ ));
+DATA(insert OID = 3307 ( pg_stat_file          PGNSP PGUID 12 1 0 0 0 f f f f t f v 2 0 2249 "25 16" "{25,16,20,1184,1184,1184,1184,16}" "{i,i,o,o,o,o,o,o}" "{filename,if_not_exists,size,access,modification,change,creation,isdir}" _null_ _null_ pg_stat_file _null_ _null_ _null_ ));
+DESCR("get information about file");
+DATA(insert OID = 2624 ( pg_read_file          PGNSP PGUID 12 1 0 0 0 f f f f t f v 3 0 25 "25 20 20" _null_ _null_ _null_ _null_ _null_ pg_read_file_off_len _null_ _null_ _null_ ));
+DESCR("read text from a file");
+DATA(insert OID = 3293 ( pg_read_file          PGNSP PGUID 12 1 0 0 0 f f f f t f v 4 0 25 "25 20 20 16" _null_ _null_ _null_ _null_ _null_ pg_read_file _null_ _null_ _null_ ));
 DESCR("read text from a file");
 DATA(insert OID = 3826 ( pg_read_file          PGNSP PGUID 12 1 0 0 0 f f f f t f v 1 0 25 "25" _null_ _null_ _null_ _null_ _null_ pg_read_file_all _null_ _null_ _null_ ));
 DESCR("read text from a file");
-DATA(insert OID = 3827 ( pg_read_binary_file   PGNSP PGUID 12 1 0 0 0 f f f f t f v 3 0 17 "25 20 20" _null_ _null_ _null_ _null_ _null_ pg_read_binary_file _null_ _null_ _null_ ));
+DATA(insert OID = 3827 ( pg_read_binary_file   PGNSP PGUID 12 1 0 0 0 f f f f t f v 3 0 17 "25 20 20" _null_ _null_ _null_ _null_ _null_ pg_read_binary_file_off_len _null_ _null_ _null_ ));
+DESCR("read bytea from a file");
+DATA(insert OID = 3295 ( pg_read_binary_file   PGNSP PGUID 12 1 0 0 0 f f f f t f v 4 0 17 "25 20 20 16" _null_ _null_ _null_ _null_ _null_ pg_read_binary_file _null_ _null_ _null_ ));
 DESCR("read bytea from a file");
 DATA(insert OID = 3828 ( pg_read_binary_file   PGNSP PGUID 12 1 0 0 0 f f f f t f v 1 0 17 "25" _null_ _null_ _null_ _null_ _null_ pg_read_binary_file_all _null_ _null_ _null_ ));
 DESCR("read bytea from a file");
-DATA(insert OID = 2625 ( pg_ls_dir                     PGNSP PGUID 12 1 1000 0 0 f f f f t t v 1 0 25 "25" _null_ _null_ _null_ _null_ _null_ pg_ls_dir _null_ _null_ _null_ ));
+DATA(insert OID = 2625 ( pg_ls_dir                     PGNSP PGUID 12 1 1000 0 0 f f f f t t v 1 0 25 "25" _null_ _null_ _null_ _null_ _null_ pg_ls_dir_1arg _null_ _null_ _null_ ));
+DESCR("list all files in a directory");
+DATA(insert OID = 3297 ( pg_ls_dir                     PGNSP PGUID 12 1 1000 0 0 f f f f t t v 3 0 25 "25 16 16" _null_ _null_ _null_ _null_ _null_ pg_ls_dir _null_ _null_ _null_ ));
 DESCR("list all files in a directory");
 DATA(insert OID = 2626 ( pg_sleep                      PGNSP PGUID 12 1 0 0 0 f f f f t f v 1 0 2278 "701" _null_ _null_ _null_ _null_ _null_ pg_sleep _null_ _null_ _null_ ));
 DESCR("sleep for the specified time in seconds");
index 51f25a281486cb17278ba650c2f503db7188b4a8..98556725c8e02a01df2fc3f08772916cacbf5e61 100644 (file)
@@ -469,14 +469,16 @@ extern Datum pg_filenode_relation(PG_FUNCTION_ARGS);
 extern Datum pg_relation_filepath(PG_FUNCTION_ARGS);
 
 /* genfile.c */
-extern bytea *read_binary_file(const char *filename,
-                                int64 seek_offset, int64 bytes_to_read);
 extern Datum pg_stat_file(PG_FUNCTION_ARGS);
+extern Datum pg_stat_file_1arg(PG_FUNCTION_ARGS);
 extern Datum pg_read_file(PG_FUNCTION_ARGS);
+extern Datum pg_read_file_off_len(PG_FUNCTION_ARGS);
 extern Datum pg_read_file_all(PG_FUNCTION_ARGS);
 extern Datum pg_read_binary_file(PG_FUNCTION_ARGS);
+extern Datum pg_read_binary_file_off_len(PG_FUNCTION_ARGS);
 extern Datum pg_read_binary_file_all(PG_FUNCTION_ARGS);
 extern Datum pg_ls_dir(PG_FUNCTION_ARGS);
+extern Datum pg_ls_dir_1arg(PG_FUNCTION_ARGS);
 
 /* misc.c */
 extern Datum current_database(PG_FUNCTION_ARGS);