diff --git a/contrib/adminpack/Makefile b/contrib/adminpack/Makefile index 89c249bc0d..afcfac4103 100644 --- a/contrib/adminpack/Makefile +++ b/contrib/adminpack/Makefile @@ -5,7 +5,7 @@ OBJS = adminpack.o $(WIN32RES) PG_CPPFLAGS = -I$(libpq_srcdir) EXTENSION = adminpack -DATA = adminpack--1.0.sql +DATA = adminpack--1.0.sql adminpack--1.0--1.1.sql PGFILEDESC = "adminpack - support functions for pgAdmin" REGRESS = adminpack diff --git a/contrib/adminpack/adminpack--1.0--1.1.sql b/contrib/adminpack/adminpack--1.0--1.1.sql new file mode 100644 index 0000000000..22eeee2ffa --- /dev/null +++ b/contrib/adminpack/adminpack--1.0--1.1.sql @@ -0,0 +1,51 @@ +/* contrib/adminpack/adminpack--1.0--1.1.sql */ + +-- complain if script is sourced in psql, rather than via ALTER EXTENSION +\echo Use "ALTER EXTENSION adminpack UPDATE TO '1.1'" to load this file. \quit + +/* *********************************************** + * Administrative functions for PostgreSQL + * *********************************************** */ + +/* generic file access functions */ + +CREATE OR REPLACE FUNCTION pg_catalog.pg_file_write(text, text, bool) +RETURNS bigint +AS 'MODULE_PATHNAME', 'pg_file_write_v1_1' +LANGUAGE C VOLATILE STRICT; + +REVOKE EXECUTE ON FUNCTION pg_catalog.pg_file_write(text, text, bool) FROM PUBLIC; + +CREATE OR REPLACE FUNCTION pg_catalog.pg_file_rename(text, text, text) +RETURNS bool +AS 'MODULE_PATHNAME', 'pg_file_rename_v1_1' +LANGUAGE C VOLATILE; + +REVOKE EXECUTE ON FUNCTION pg_catalog.pg_file_rename(text, text, text) FROM PUBLIC; + +CREATE OR REPLACE FUNCTION pg_catalog.pg_file_rename(text, text) +RETURNS bool +AS 'SELECT pg_catalog.pg_file_rename($1, $2, NULL::pg_catalog.text);' +LANGUAGE SQL VOLATILE STRICT; + +CREATE OR REPLACE FUNCTION pg_catalog.pg_file_unlink(text) +RETURNS bool +AS 'MODULE_PATHNAME', 'pg_file_unlink_v1_1' +LANGUAGE C VOLATILE STRICT; + +REVOKE EXECUTE ON FUNCTION pg_catalog.pg_file_unlink(text) FROM PUBLIC; + +CREATE OR REPLACE FUNCTION pg_catalog.pg_logdir_ls() +RETURNS setof record +AS 'MODULE_PATHNAME', 'pg_logdir_ls_v1_1' +LANGUAGE C VOLATILE STRICT; + +REVOKE EXECUTE ON FUNCTION pg_catalog.pg_logdir_ls() FROM PUBLIC; + +/* These functions are now in the backend and callers should update to use those */ + +DROP FUNCTION pg_file_read(text, bigint, bigint); + +DROP FUNCTION pg_file_length(text); + +DROP FUNCTION pg_logfile_rotate(); diff --git a/contrib/adminpack/adminpack.c b/contrib/adminpack/adminpack.c index 1785dee3a1..fc513d628e 100644 --- a/contrib/adminpack/adminpack.c +++ b/contrib/adminpack/adminpack.c @@ -18,6 +18,7 @@ #include #include +#include "catalog/pg_authid.h" #include "catalog/pg_type.h" #include "funcapi.h" #include "miscadmin.h" @@ -41,9 +42,17 @@ PG_MODULE_MAGIC; PG_FUNCTION_INFO_V1(pg_file_write); +PG_FUNCTION_INFO_V1(pg_file_write_v1_1); PG_FUNCTION_INFO_V1(pg_file_rename); +PG_FUNCTION_INFO_V1(pg_file_rename_v1_1); PG_FUNCTION_INFO_V1(pg_file_unlink); +PG_FUNCTION_INFO_V1(pg_file_unlink_v1_1); PG_FUNCTION_INFO_V1(pg_logdir_ls); +PG_FUNCTION_INFO_V1(pg_logdir_ls_v1_1); + +static int64 pg_file_write_internal(text *file, text *data, bool replace); +static bool pg_file_rename_internal(text *file1, text *file2, text *file3); +static Datum pg_logdir_ls_internal(FunctionCallInfo fcinfo); typedef struct { @@ -68,6 +77,15 @@ convert_and_check_filename(text *arg, bool logAllowed) canonicalize_path(filename); /* filename can change length here */ + /* + * Members of the 'pg_write_server_files' role are allowed to access any + * files on the server as the PG user, so no need to do any further checks + * here. + */ + if (is_member_of_role(GetUserId(), DEFAULT_ROLE_WRITE_SERVER_FILES)) + return filename; + + /* User isn't a member of the default role, so check if it's allowable */ if (is_absolute_path(filename)) { /* Disallow '/a/b/data/..' */ @@ -111,23 +129,64 @@ requireSuperuser(void) /* ------------------------------------ - * generic file handling functions + * pg_file_write - old version + * + * The superuser() check here must be kept as the library might be upgraded + * without the extension being upgraded, meaning that in pre-1.1 installations + * these functions could be called by any user. */ - Datum pg_file_write(PG_FUNCTION_ARGS) { - FILE *f; - char *filename; - text *data; + text *file = PG_GETARG_TEXT_PP(0); + text *data = PG_GETARG_TEXT_PP(1); + bool replace = PG_GETARG_BOOL(2); int64 count = 0; requireSuperuser(); - filename = convert_and_check_filename(PG_GETARG_TEXT_PP(0), false); - data = PG_GETARG_TEXT_PP(1); + count = pg_file_write_internal(file, data, replace); - if (!PG_GETARG_BOOL(2)) + PG_RETURN_INT64(count); +} + +/* ------------------------------------ + * pg_file_write_v1_1 - Version 1.1 + * + * As of adminpack version 1.1, we no longer need to check if the user + * is a superuser because we REVOKE EXECUTE on the function from PUBLIC. + * Users can then grant access to it based on their policies. + * + * Otherwise identical to pg_file_write (above). + */ +Datum +pg_file_write_v1_1(PG_FUNCTION_ARGS) +{ + text *file = PG_GETARG_TEXT_PP(0); + text *data = PG_GETARG_TEXT_PP(1); + bool replace = PG_GETARG_BOOL(2); + int64 count = 0; + + count = pg_file_write_internal(file, data, replace); + + PG_RETURN_INT64(count); +} + +/* ------------------------------------ + * pg_file_write_internal - Workhorse for pg_file_write functions. + * + * This handles the actual work for pg_file_write. + */ +int64 +pg_file_write_internal(text *file, text *data, bool replace) +{ + FILE *f; + char *filename; + int64 count = 0; + + filename = convert_and_check_filename(file, false); + + if (!replace) { struct stat fst; @@ -153,29 +212,95 @@ pg_file_write(PG_FUNCTION_ARGS) (errcode_for_file_access(), errmsg("could not write file \"%s\": %m", filename))); - PG_RETURN_INT64(count); + return (count); } - +/* ------------------------------------ + * pg_file_rename - old version + * + * The superuser() check here must be kept as the library might be upgraded + * without the extension being upgraded, meaning that in pre-1.1 installations + * these functions could be called by any user. + */ Datum pg_file_rename(PG_FUNCTION_ARGS) { - char *fn1, - *fn2, - *fn3; - int rc; + text *file1; + text *file2; + text *file3; + bool result; requireSuperuser(); if (PG_ARGISNULL(0) || PG_ARGISNULL(1)) PG_RETURN_NULL(); - fn1 = convert_and_check_filename(PG_GETARG_TEXT_PP(0), false); - fn2 = convert_and_check_filename(PG_GETARG_TEXT_PP(1), false); + file1 = PG_GETARG_TEXT_PP(0); + file2 = PG_GETARG_TEXT_PP(1); + if (PG_ARGISNULL(2)) + file3 = NULL; + else + file3 = PG_GETARG_TEXT_PP(2); + + result = pg_file_rename_internal(file1, file2, file3); + + PG_RETURN_BOOL(result); +} + +/* ------------------------------------ + * pg_file_rename_v1_1 - Version 1.1 + * + * As of adminpack version 1.1, we no longer need to check if the user + * is a superuser because we REVOKE EXECUTE on the function from PUBLIC. + * Users can then grant access to it based on their policies. + * + * Otherwise identical to pg_file_write (above). + */ +Datum +pg_file_rename_v1_1(PG_FUNCTION_ARGS) +{ + text *file1; + text *file2; + text *file3; + bool result; + + if (PG_ARGISNULL(0) || PG_ARGISNULL(1)) + PG_RETURN_NULL(); + + file1 = PG_GETARG_TEXT_PP(0); + file2 = PG_GETARG_TEXT_PP(1); + + if (PG_ARGISNULL(2)) + file3 = NULL; + else + file3 = PG_GETARG_TEXT_PP(2); + + result = pg_file_rename_internal(file1, file2, file3); + + PG_RETURN_BOOL(result); +} + +/* ------------------------------------ + * pg_file_rename_internal - Workhorse for pg_file_rename functions. + * + * This handles the actual work for pg_file_rename. + */ +bool +pg_file_rename_internal(text *file1, text *file2, text *file3) +{ + char *fn1, + *fn2, + *fn3; + int rc; + + fn1 = convert_and_check_filename(file1, false); + fn2 = convert_and_check_filename(file2, false); + + if (file3 == NULL) fn3 = 0; else - fn3 = convert_and_check_filename(PG_GETARG_TEXT_PP(2), false); + fn3 = convert_and_check_filename(file3, false); if (access(fn1, W_OK) < 0) { @@ -183,7 +308,7 @@ pg_file_rename(PG_FUNCTION_ARGS) (errcode_for_file_access(), errmsg("file \"%s\" is not accessible: %m", fn1))); - PG_RETURN_BOOL(false); + return false; } if (fn3 && access(fn2, W_OK) < 0) @@ -192,7 +317,7 @@ pg_file_rename(PG_FUNCTION_ARGS) (errcode_for_file_access(), errmsg("file \"%s\" is not accessible: %m", fn2))); - PG_RETURN_BOOL(false); + return false; } rc = access(fn3 ? fn3 : fn2, 2); @@ -243,10 +368,17 @@ pg_file_rename(PG_FUNCTION_ARGS) errmsg("could not rename \"%s\" to \"%s\": %m", fn1, fn2))); } - PG_RETURN_BOOL(true); + return true; } +/* ------------------------------------ + * pg_file_unlink - old version + * + * The superuser() check here must be kept as the library might be upgraded + * without the extension being upgraded, meaning that in pre-1.1 installations + * these functions could be called by any user. + */ Datum pg_file_unlink(PG_FUNCTION_ARGS) { @@ -278,18 +410,83 @@ pg_file_unlink(PG_FUNCTION_ARGS) } +/* ------------------------------------ + * pg_file_unlink_v1_1 - Version 1.1 + * + * As of adminpack version 1.1, we no longer need to check if the user + * is a superuser because we REVOKE EXECUTE on the function from PUBLIC. + * Users can then grant access to it based on their policies. + * + * Otherwise identical to pg_file_unlink (above). + */ +Datum +pg_file_unlink_v1_1(PG_FUNCTION_ARGS) +{ + char *filename; + + filename = convert_and_check_filename(PG_GETARG_TEXT_PP(0), false); + + if (access(filename, W_OK) < 0) + { + if (errno == ENOENT) + PG_RETURN_BOOL(false); + else + ereport(ERROR, + (errcode_for_file_access(), + errmsg("file \"%s\" is not accessible: %m", filename))); + } + + if (unlink(filename) < 0) + { + ereport(WARNING, + (errcode_for_file_access(), + errmsg("could not unlink file \"%s\": %m", filename))); + + PG_RETURN_BOOL(false); + } + PG_RETURN_BOOL(true); +} + +/* ------------------------------------ + * pg_logdir_ls - Old version + * + * The superuser() check here must be kept as the library might be upgraded + * without the extension being upgraded, meaning that in pre-1.1 installations + * these functions could be called by any user. + */ Datum pg_logdir_ls(PG_FUNCTION_ARGS) { - FuncCallContext *funcctx; - struct dirent *de; - directory_fctx *fctx; - if (!superuser()) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), (errmsg("only superuser can list the log directory")))); + return (pg_logdir_ls_internal(fcinfo)); +} + +/* ------------------------------------ + * pg_logdir_ls_v1_1 - Version 1.1 + * + * As of adminpack version 1.1, we no longer need to check if the user + * is a superuser because we REVOKE EXECUTE on the function from PUBLIC. + * Users can then grant access to it based on their policies. + * + * Otherwise identical to pg_logdir_ls (above). + */ +Datum +pg_logdir_ls_v1_1(PG_FUNCTION_ARGS) +{ + return (pg_logdir_ls_internal(fcinfo)); +} + +Datum +pg_logdir_ls_internal(FunctionCallInfo fcinfo) +{ + FuncCallContext *funcctx; + struct dirent *de; + directory_fctx *fctx; + if (strcmp(Log_filename, "postgresql-%Y-%m-%d_%H%M%S.log") != 0) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), diff --git a/contrib/adminpack/adminpack.control b/contrib/adminpack/adminpack.control index c79413f378..71f6ad5ddf 100644 --- a/contrib/adminpack/adminpack.control +++ b/contrib/adminpack/adminpack.control @@ -1,6 +1,6 @@ # adminpack extension comment = 'administrative functions for PostgreSQL' -default_version = '1.0' +default_version = '1.1' module_pathname = '$libdir/adminpack' relocatable = false schema = pg_catalog diff --git a/contrib/adminpack/expected/adminpack.out b/contrib/adminpack/expected/adminpack.out index b0d72ddab2..8747ac69a2 100644 --- a/contrib/adminpack/expected/adminpack.out +++ b/contrib/adminpack/expected/adminpack.out @@ -34,7 +34,12 @@ SELECT pg_read_file('test_file1'); test1test1 (1 row) --- disallowed file paths +-- disallowed file paths for non-superusers and users who are +-- not members of pg_write_server_files +CREATE ROLE regress_user1; +GRANT pg_read_all_settings TO regress_user1; +GRANT EXECUTE ON FUNCTION pg_file_write(text,text,bool) TO regress_user1; +SET ROLE regress_user1; SELECT pg_file_write('../test_file0', 'test0', false); ERROR: path must be in or below the current directory SELECT pg_file_write('/tmp/test_file0', 'test0', false); @@ -47,6 +52,10 @@ SELECT pg_file_write(current_setting('data_directory') || '/test_file4', 'test4' SELECT pg_file_write(current_setting('data_directory') || '/../test_file4', 'test4', false); ERROR: reference to parent directory ("..") not allowed +RESET ROLE; +REVOKE EXECUTE ON FUNCTION pg_file_write(text,text,bool) FROM regress_user1; +REVOKE pg_read_all_settings FROM regress_user1; +DROP ROLE regress_user1; -- rename file SELECT pg_file_rename('test_file1', 'test_file2'); pg_file_rename @@ -132,14 +141,14 @@ SELECT pg_file_unlink('test_file4'); CREATE USER regress_user1; SET ROLE regress_user1; SELECT pg_file_write('test_file0', 'test0', false); -ERROR: only superuser may access generic file functions +ERROR: permission denied for function pg_file_write SELECT pg_file_rename('test_file0', 'test_file0'); -ERROR: only superuser may access generic file functions +ERROR: permission denied for function pg_file_rename CONTEXT: SQL function "pg_file_rename" statement 1 SELECT pg_file_unlink('test_file0'); -ERROR: only superuser may access generic file functions +ERROR: permission denied for function pg_file_unlink SELECT pg_logdir_ls(); -ERROR: only superuser can list the log directory +ERROR: permission denied for function pg_logdir_ls RESET ROLE; DROP USER regress_user1; -- no further tests for pg_logdir_ls() because it depends on the diff --git a/contrib/adminpack/sql/adminpack.sql b/contrib/adminpack/sql/adminpack.sql index 13621bd043..1525f0a82b 100644 --- a/contrib/adminpack/sql/adminpack.sql +++ b/contrib/adminpack/sql/adminpack.sql @@ -12,12 +12,22 @@ SELECT pg_read_file('test_file1'); SELECT pg_file_write('test_file1', 'test1', false); SELECT pg_read_file('test_file1'); --- disallowed file paths +-- disallowed file paths for non-superusers and users who are +-- not members of pg_write_server_files +CREATE ROLE regress_user1; + +GRANT pg_read_all_settings TO regress_user1; +GRANT EXECUTE ON FUNCTION pg_file_write(text,text,bool) TO regress_user1; + +SET ROLE regress_user1; SELECT pg_file_write('../test_file0', 'test0', false); SELECT pg_file_write('/tmp/test_file0', 'test0', false); SELECT pg_file_write(current_setting('data_directory') || '/test_file4', 'test4', false); SELECT pg_file_write(current_setting('data_directory') || '/../test_file4', 'test4', false); - +RESET ROLE; +REVOKE EXECUTE ON FUNCTION pg_file_write(text,text,bool) FROM regress_user1; +REVOKE pg_read_all_settings FROM regress_user1; +DROP ROLE regress_user1; -- rename file SELECT pg_file_rename('test_file1', 'test_file2'); diff --git a/doc/src/sgml/adminpack.sgml b/doc/src/sgml/adminpack.sgml index 1197eefbf3..2655417366 100644 --- a/doc/src/sgml/adminpack.sgml +++ b/doc/src/sgml/adminpack.sgml @@ -12,7 +12,8 @@ pgAdmin and other administration and management tools can use to provide additional functionality, such as remote management of server log files. - Use of all these functions is restricted to superusers. + Use of all these functions is only allowed to the superuser by default but may be + allowed to other users by using the GRANT command. @@ -20,8 +21,10 @@ write access to files on the machine hosting the server. (See also the functions in , which provide read-only access.) - Only files within the database cluster directory can be accessed, but - either a relative or absolute path is allowable. + Only files within the database cluster directory can be accessed, unless the + user is a superuser or given one of the pg_read_server_files, or pg_write_server_files + roles, as appropriate for the function, but either a relative or absolute path is + allowable. @@ -113,50 +116,4 @@ function. - - The functions shown - in are deprecated - and should not be used in new applications; instead use those shown - in - and . These functions are - provided in adminpack only for compatibility with old - versions of pgAdmin. - - -
- Deprecated <filename>adminpack</filename> Functions - - - Name Return Type Description - - - - - - pg_catalog.pg_file_read(filename text, offset bigint, nbytes bigint) - text - - Alternate name for pg_read_file() - - - - pg_catalog.pg_file_length(filename text) - bigint - - Same as size column returned - by pg_stat_file() - - - - pg_catalog.pg_logfile_rotate() - integer - - Alternate name for pg_rotate_logfile(), but note that it - returns integer 0 or 1 rather than boolean - - - - -
- diff --git a/src/backend/utils/adt/genfile.c b/src/backend/utils/adt/genfile.c index 9e85df18aa..a97cbea248 100644 --- a/src/backend/utils/adt/genfile.c +++ b/src/backend/utils/adt/genfile.c @@ -200,6 +200,8 @@ read_text_file(const char *filename, int64 seek_offset, int64 bytes_to_read, /* * Read a section of a file, returning it as text + * + * This function is kept to support adminpack 1.0. */ Datum pg_read_file(PG_FUNCTION_ARGS) @@ -211,6 +213,51 @@ pg_read_file(PG_FUNCTION_ARGS) char *filename; text *result; + if (!superuser()) + ereport(ERROR, + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + (errmsg("must be superuser to read files with adminpack 1.0"), + errhint("Consider using pg_file_read(), which is part of core, instead.")))); + + /* 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 (PG_NARGS() >= 4) + missing_ok = PG_GETARG_BOOL(3); + + filename = convert_and_check_filename(filename_t); + + result = read_text_file(filename, seek_offset, bytes_to_read, missing_ok); + if (result) + PG_RETURN_TEXT_P(result); + else + PG_RETURN_NULL(); +} + +/* + * Read a section of a file, returning it as text + * + * No superuser check done here- instead privileges are handled by the + * GRANT system. + */ +Datum +pg_read_file_v2(PG_FUNCTION_ARGS) +{ + text *filename_t = PG_GETARG_TEXT_PP(0); + int64 seek_offset = 0; + int64 bytes_to_read = -1; + bool missing_ok = false; + char *filename; + text *result; + /* handle optional arguments */ if (PG_NARGS() >= 3) { @@ -273,7 +320,7 @@ pg_read_binary_file(PG_FUNCTION_ARGS) /* - * Wrapper functions for the 1 and 3 argument variants of pg_read_file() + * Wrapper functions for the 1 and 3 argument variants of pg_read_file_v2() * and pg_binary_read_file(). * * These are necessary to pass the sanity check in opr_sanity, which checks @@ -283,13 +330,13 @@ pg_read_binary_file(PG_FUNCTION_ARGS) Datum pg_read_file_off_len(PG_FUNCTION_ARGS) { - return pg_read_file(fcinfo); + return pg_read_file_v2(fcinfo); } Datum pg_read_file_all(PG_FUNCTION_ARGS) { - return pg_read_file(fcinfo); + return pg_read_file_v2(fcinfo); } Datum diff --git a/src/backend/utils/adt/misc.c b/src/backend/utils/adt/misc.c index 2e1e020c4b..b24dece23f 100644 --- a/src/backend/utils/adt/misc.c +++ b/src/backend/utils/adt/misc.c @@ -341,6 +341,31 @@ pg_reload_conf(PG_FUNCTION_ARGS) } +/* + * Rotate log file + * + * This function is kept to support adminpack 1.0. + */ +Datum +pg_rotate_logfile(PG_FUNCTION_ARGS) +{ + if (!superuser()) + ereport(ERROR, + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + (errmsg("must be superuser to rotate log files with adminpack 1.0"), + errhint("Consider using pg_logfile_rotate(), which is part of core, instead.")))); + + if (!Logging_collector) + { + ereport(WARNING, + (errmsg("rotation not possible because log collection not active"))); + PG_RETURN_BOOL(false); + } + + SendPostmasterSignal(PMSIGNAL_ROTATE_LOGFILE); + PG_RETURN_BOOL(true); +} + /* * Rotate log file * @@ -348,7 +373,7 @@ pg_reload_conf(PG_FUNCTION_ARGS) * GRANT system. */ Datum -pg_rotate_logfile(PG_FUNCTION_ARGS) +pg_rotate_logfile_v2(PG_FUNCTION_ARGS) { if (!Logging_collector) { diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h index 02be8a5fbd..8dc30345b8 100644 --- a/src/include/catalog/pg_proc.h +++ b/src/include/catalog/pg_proc.h @@ -3359,8 +3359,10 @@ DESCR("true if wal replay is paused"); DATA(insert OID = 2621 ( pg_reload_conf PGNSP PGUID 12 1 0 0 0 f f f t f v s 0 0 16 "" _null_ _null_ _null_ _null_ _null_ pg_reload_conf _null_ _null_ _null_ )); DESCR("reload configuration files"); -DATA(insert OID = 2622 ( pg_rotate_logfile PGNSP PGUID 12 1 0 0 0 f f f t f v s 0 0 16 "" _null_ _null_ _null_ _null_ _null_ pg_rotate_logfile _null_ _null_ _null_ )); +DATA(insert OID = 2622 ( pg_rotate_logfile PGNSP PGUID 12 1 0 0 0 f f f t f v s 0 0 16 "" _null_ _null_ _null_ _null_ _null_ pg_rotate_logfile_v2 _null_ _null_ _null_ )); DESCR("rotate log file"); +DATA(insert OID = 4099 ( pg_rotate_logfile_old PGNSP PGUID 12 1 0 0 0 f f f t f v s 0 0 16 "" _null_ _null_ _null_ _null_ _null_ pg_rotate_logfile _null_ _null_ _null_ )); +DESCR("rotate log file - old version for adminpack 1.0"); DATA(insert OID = 3800 ( pg_current_logfile PGNSP PGUID 12 1 0 0 0 f f f f f v s 0 0 25 "" _null_ _null_ _null_ _null_ _null_ pg_current_logfile _null_ _null_ _null_ )); DESCR("current logging collector file location"); DATA(insert OID = 3801 ( pg_current_logfile PGNSP PGUID 12 1 0 0 0 f f f f f v s 1 0 25 "25" _null_ _null_ _null_ _null_ _null_ pg_current_logfile_1arg _null_ _null_ _null_ )); @@ -3372,8 +3374,10 @@ DATA(insert OID = 3307 ( pg_stat_file PGNSP PGUID 12 1 0 0 0 f f f t f v s 2 0 DESCR("get information about file"); DATA(insert OID = 2624 ( pg_read_file PGNSP PGUID 12 1 0 0 0 f f f t f v s 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 t f v s 4 0 25 "25 20 20 16" _null_ _null_ _null_ _null_ _null_ pg_read_file _null_ _null_ _null_ )); +DATA(insert OID = 3293 ( pg_read_file PGNSP PGUID 12 1 0 0 0 f f f t f v s 4 0 25 "25 20 20 16" _null_ _null_ _null_ _null_ _null_ pg_read_file_v2 _null_ _null_ _null_ )); DESCR("read text from a file"); +DATA(insert OID = 4100 ( pg_read_file_old PGNSP PGUID 12 1 0 0 0 f f f t f v s 3 0 25 "25 20 20" _null_ _null_ _null_ _null_ _null_ pg_read_file _null_ _null_ _null_ )); +DESCR("read text from a file - old version for adminpack 1.0"); DATA(insert OID = 3826 ( pg_read_file PGNSP PGUID 12 1 0 0 0 f f f t f v s 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 t f v s 3 0 17 "25 20 20" _null_ _null_ _null_ _null_ _null_ pg_read_binary_file_off_len _null_ _null_ _null_ ));