From 2804fdc5fd974e688a930ab58559dbb7047cca8e Mon Sep 17 00:00:00 2001 From: Michael Paquier Date: Wed, 24 Jun 2015 10:34:17 +0900 Subject: [PATCH 2/8] Extend pg_stat_file with if_not_exists option This is useful for code paths that prefer receiving a NULL result instead of an ERROR if file specified does not exist. --- doc/src/sgml/func.sgml | 9 ++++-- src/backend/utils/adt/genfile.c | 65 +++++++++++++++++++++++++++++++---------- src/include/catalog/pg_proc.h | 2 ++ src/include/utils/builtins.h | 1 + 4 files changed, 59 insertions(+), 18 deletions(-) diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml index 7929e7e..0f70985 100644 --- a/doc/src/sgml/func.sgml +++ b/doc/src/sgml/func.sgml @@ -17830,10 +17830,15 @@ postgres=# SELECT * FROM pg_xlogfile_name_offset(pg_stop_backup()); - pg_stat_file(filename text) + pg_stat_file(filename text[, if_not_exists boolean]) record - Return information about a file + + Return information about a file. If + if_not_exists is true, NULL + is returned for all result fields if file does not exist instead of + an error. + diff --git a/src/backend/utils/adt/genfile.c b/src/backend/utils/adt/genfile.c index f3f3cca..dd97d83 100644 --- a/src/backend/utils/adt/genfile.c +++ b/src/backend/utils/adt/genfile.c @@ -254,10 +254,10 @@ pg_read_binary_file_all(PG_FUNCTION_ARGS) } /* - * stat a file + * Wrapper for pg_stat_file and pg_stat_file_extended. */ -Datum -pg_stat_file(PG_FUNCTION_ARGS) +static Datum +stat_file_wrapper(PG_FUNCTION_ARGS) { text *filename_t = PG_GETARG_TEXT_P(0); char *filename; @@ -266,18 +266,29 @@ pg_stat_file(PG_FUNCTION_ARGS) bool isnull[6]; HeapTuple tuple; TupleDesc tupdesc; + bool if_not_exists = false; + bool return_null = false; if (!superuser()) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), (errmsg("must be superuser to get file information")))); + /* Check for option if_not_exists */ + if (PG_NARGS() == 2 && !PG_ARGISNULL(1)) + if_not_exists = 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 (if_not_exists && errno == ENOENT) + return_null = true; + 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 @@ -298,20 +309,23 @@ pg_stat_file(PG_FUNCTION_ARGS) "isdir", BOOLOID, -1, 0); BlessTupleDesc(tupdesc); - memset(isnull, false, sizeof(isnull)); + memset(isnull, return_null, sizeof(isnull)); - values[0] = Int64GetDatum((int64) fst.st_size); - values[1] = TimestampTzGetDatum(time_t_to_timestamptz(fst.st_atime)); - values[2] = TimestampTzGetDatum(time_t_to_timestamptz(fst.st_mtime)); - /* Unix has file status change time, while Win32 has creation time */ + if (!return_null) + { + values[0] = Int64GetDatum((int64) fst.st_size); + values[1] = TimestampTzGetDatum(time_t_to_timestamptz(fst.st_atime)); + values[2] = TimestampTzGetDatum(time_t_to_timestamptz(fst.st_mtime)); + /* Unix has file status change time, while Win32 has creation time */ #if !defined(WIN32) && !defined(__CYGWIN__) - values[3] = TimestampTzGetDatum(time_t_to_timestamptz(fst.st_ctime)); - isnull[4] = true; + values[3] = TimestampTzGetDatum(time_t_to_timestamptz(fst.st_ctime)); + isnull[4] = true; #else - isnull[3] = true; - values[4] = TimestampTzGetDatum(time_t_to_timestamptz(fst.st_ctime)); + isnull[3] = true; + values[4] = TimestampTzGetDatum(time_t_to_timestamptz(fst.st_ctime)); #endif - values[5] = BoolGetDatum(S_ISDIR(fst.st_mode)); + values[5] = BoolGetDatum(S_ISDIR(fst.st_mode)); + } tuple = heap_form_tuple(tupdesc, values, isnull); @@ -320,6 +334,25 @@ pg_stat_file(PG_FUNCTION_ARGS) PG_RETURN_DATUM(HeapTupleGetDatum(tuple)); } +/* + * pg_stat_file_extended + * Stat a file, with possibility to bypass error in case of a missing file. + */ +Datum +pg_stat_file_extended(PG_FUNCTION_ARGS) +{ + return stat_file_wrapper(fcinfo); +} + +/* + * stat a file + */ +Datum +pg_stat_file(PG_FUNCTION_ARGS) +{ + return stat_file_wrapper(fcinfo); +} + /* * List a directory (returns the filenames only) diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h index 1f163f0..8da1781 100644 --- a/src/include/catalog/pg_proc.h +++ b/src/include/catalog/pg_proc.h @@ -3185,6 +3185,8 @@ 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_ )); DESCR("get information about file"); +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_extended _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_ )); 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_ )); diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h index ab78ec2..e46650a 100644 --- a/src/include/utils/builtins.h +++ b/src/include/utils/builtins.h @@ -472,6 +472,7 @@ extern Datum pg_relation_filepath(PG_FUNCTION_ARGS); 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_extended(PG_FUNCTION_ARGS); extern Datum pg_read_file(PG_FUNCTION_ARGS); extern Datum pg_read_file_all(PG_FUNCTION_ARGS); extern Datum pg_read_binary_file(PG_FUNCTION_ARGS); -- 2.4.4