Remove the adminpack contrib extension
The adminpack extension was only used to support pgAdmin III, which in turn was declared EOL many years ago. Removing the extension also allows us to remove functions from core as well which were only used to support old version of adminpack. Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us> Reviewed-by: Nathan Bossart <nathandbossart@gmail.com> Reviewed-by: Bharath Rupireddy <bharath.rupireddyforpostgres@gmail.com> Discussion: https://postgr.es/m/CALj2ACUmL5TraYBUBqDZBi1C+Re8_=SekqGYqYprj_W8wygQ8w@mail.gmail.com
This commit is contained in:
parent
dbbca2cf29
commit
cc09e6549f
20 changed files with 2 additions and 1280 deletions
|
@ -5,7 +5,6 @@ top_builddir = ..
|
|||
include $(top_builddir)/src/Makefile.global
|
||||
|
||||
SUBDIRS = \
|
||||
adminpack \
|
||||
amcheck \
|
||||
auth_delay \
|
||||
auto_explain \
|
||||
|
|
4
contrib/adminpack/.gitignore
vendored
4
contrib/adminpack/.gitignore
vendored
|
@ -1,4 +0,0 @@
|
|||
# Generated subdirectories
|
||||
/log/
|
||||
/results/
|
||||
/tmp_check/
|
|
@ -1,24 +0,0 @@
|
|||
# contrib/adminpack/Makefile
|
||||
|
||||
MODULE_big = adminpack
|
||||
OBJS = \
|
||||
$(WIN32RES) \
|
||||
adminpack.o
|
||||
|
||||
EXTENSION = adminpack
|
||||
DATA = adminpack--1.0.sql adminpack--1.0--1.1.sql adminpack--1.1--2.0.sql\
|
||||
adminpack--2.0--2.1.sql
|
||||
PGFILEDESC = "adminpack - support functions for pgAdmin"
|
||||
|
||||
REGRESS = adminpack
|
||||
|
||||
ifdef USE_PGXS
|
||||
PG_CONFIG = pg_config
|
||||
PGXS := $(shell $(PG_CONFIG) --pgxs)
|
||||
include $(PGXS)
|
||||
else
|
||||
subdir = contrib/adminpack
|
||||
top_builddir = ../..
|
||||
include $(top_builddir)/src/Makefile.global
|
||||
include $(top_srcdir)/contrib/contrib-global.mk
|
||||
endif
|
|
@ -1,6 +0,0 @@
|
|||
/* 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
|
||||
|
||||
REVOKE EXECUTE ON FUNCTION pg_catalog.pg_logfile_rotate() FROM PUBLIC;
|
|
@ -1,53 +0,0 @@
|
|||
/* contrib/adminpack/adminpack--1.0.sql */
|
||||
|
||||
-- complain if script is sourced in psql, rather than via CREATE EXTENSION
|
||||
\echo Use "CREATE EXTENSION adminpack" to load this file. \quit
|
||||
|
||||
/* ***********************************************
|
||||
* Administrative functions for PostgreSQL
|
||||
* *********************************************** */
|
||||
|
||||
/* generic file access functions */
|
||||
|
||||
CREATE FUNCTION pg_catalog.pg_file_write(text, text, bool)
|
||||
RETURNS bigint
|
||||
AS 'MODULE_PATHNAME', 'pg_file_write'
|
||||
LANGUAGE C VOLATILE STRICT;
|
||||
|
||||
CREATE FUNCTION pg_catalog.pg_file_rename(text, text, text)
|
||||
RETURNS bool
|
||||
AS 'MODULE_PATHNAME', 'pg_file_rename'
|
||||
LANGUAGE C VOLATILE;
|
||||
|
||||
CREATE 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 FUNCTION pg_catalog.pg_file_unlink(text)
|
||||
RETURNS bool
|
||||
AS 'MODULE_PATHNAME', 'pg_file_unlink'
|
||||
LANGUAGE C VOLATILE STRICT;
|
||||
|
||||
CREATE FUNCTION pg_catalog.pg_logdir_ls()
|
||||
RETURNS setof record
|
||||
AS 'MODULE_PATHNAME', 'pg_logdir_ls'
|
||||
LANGUAGE C VOLATILE STRICT;
|
||||
|
||||
|
||||
/* Renaming of existing backend functions for pgAdmin compatibility */
|
||||
|
||||
CREATE FUNCTION pg_catalog.pg_file_read(text, bigint, bigint)
|
||||
RETURNS text
|
||||
AS 'pg_read_file'
|
||||
LANGUAGE INTERNAL VOLATILE STRICT;
|
||||
|
||||
CREATE FUNCTION pg_catalog.pg_file_length(text)
|
||||
RETURNS bigint
|
||||
AS 'SELECT size FROM pg_catalog.pg_stat_file($1)'
|
||||
LANGUAGE SQL VOLATILE STRICT;
|
||||
|
||||
CREATE FUNCTION pg_catalog.pg_logfile_rotate()
|
||||
RETURNS int4
|
||||
AS 'pg_rotate_logfile'
|
||||
LANGUAGE INTERNAL VOLATILE STRICT;
|
|
@ -1,51 +0,0 @@
|
|||
/* contrib/adminpack/adminpack--1.1--2.0.sql */
|
||||
|
||||
-- complain if script is sourced in psql, rather than via ALTER EXTENSION
|
||||
\echo Use "ALTER EXTENSION adminpack UPDATE TO '2.0'" 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();
|
|
@ -1,17 +0,0 @@
|
|||
/* contrib/adminpack/adminpack--2.0--2.1.sql */
|
||||
|
||||
-- complain if script is sourced in psql, rather than via ALTER EXTENSION
|
||||
\echo Use "ALTER EXTENSION adminpack UPDATE TO '2.1'" to load this file. \quit
|
||||
|
||||
/* ***********************************************
|
||||
* Administrative functions for PostgreSQL
|
||||
* *********************************************** */
|
||||
|
||||
/* generic file access functions */
|
||||
|
||||
CREATE OR REPLACE FUNCTION pg_catalog.pg_file_sync(text)
|
||||
RETURNS void
|
||||
AS 'MODULE_PATHNAME', 'pg_file_sync'
|
||||
LANGUAGE C VOLATILE STRICT;
|
||||
|
||||
REVOKE EXECUTE ON FUNCTION pg_catalog.pg_file_sync(text) FROM PUBLIC;
|
|
@ -1,591 +0,0 @@
|
|||
/*-------------------------------------------------------------------------
|
||||
*
|
||||
* adminpack.c
|
||||
*
|
||||
*
|
||||
* Copyright (c) 2002-2024, PostgreSQL Global Development Group
|
||||
*
|
||||
* Author: Andreas Pflug <pgadmin@pse-consulting.de>
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* contrib/adminpack/adminpack.c
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
#include "postgres.h"
|
||||
|
||||
#include <sys/file.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "catalog/pg_authid.h"
|
||||
#include "catalog/pg_type.h"
|
||||
#include "funcapi.h"
|
||||
#include "miscadmin.h"
|
||||
#include "postmaster/syslogger.h"
|
||||
#include "storage/fd.h"
|
||||
#include "utils/acl.h"
|
||||
#include "utils/builtins.h"
|
||||
#include "utils/datetime.h"
|
||||
|
||||
|
||||
#ifdef WIN32
|
||||
|
||||
#ifdef rename
|
||||
#undef rename
|
||||
#endif
|
||||
|
||||
#ifdef unlink
|
||||
#undef unlink
|
||||
#endif
|
||||
#endif
|
||||
|
||||
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_sync);
|
||||
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);
|
||||
|
||||
|
||||
/*-----------------------
|
||||
* some helper functions
|
||||
*/
|
||||
|
||||
/*
|
||||
* Convert a "text" filename argument to C string, and check it's allowable.
|
||||
*
|
||||
* Filename may be absolute or relative to the DataDir, but we only allow
|
||||
* absolute paths that match DataDir.
|
||||
*/
|
||||
static char *
|
||||
convert_and_check_filename(text *arg)
|
||||
{
|
||||
char *filename = text_to_cstring(arg);
|
||||
|
||||
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 (has_privs_of_role(GetUserId(), ROLE_PG_WRITE_SERVER_FILES))
|
||||
return filename;
|
||||
|
||||
/*
|
||||
* User isn't a member of the pg_write_server_files role, so check if it's
|
||||
* allowable
|
||||
*/
|
||||
if (is_absolute_path(filename))
|
||||
{
|
||||
/* Allow absolute paths if within DataDir */
|
||||
if (!path_is_prefix_of_path(DataDir, filename))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
|
||||
errmsg("absolute path not allowed")));
|
||||
}
|
||||
else if (!path_is_relative_and_below_cwd(filename))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
|
||||
errmsg("path must be in or below the data directory")));
|
||||
|
||||
return filename;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* check for superuser, bark if not.
|
||||
*/
|
||||
static void
|
||||
requireSuperuser(void)
|
||||
{
|
||||
if (!superuser())
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
|
||||
errmsg("only superuser may access generic file 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)
|
||||
{
|
||||
text *file = PG_GETARG_TEXT_PP(0);
|
||||
text *data = PG_GETARG_TEXT_PP(1);
|
||||
bool replace = PG_GETARG_BOOL(2);
|
||||
int64 count = 0;
|
||||
|
||||
requireSuperuser();
|
||||
|
||||
count = pg_file_write_internal(file, data, replace);
|
||||
|
||||
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.
|
||||
*/
|
||||
static int64
|
||||
pg_file_write_internal(text *file, text *data, bool replace)
|
||||
{
|
||||
FILE *f;
|
||||
char *filename;
|
||||
int64 count = 0;
|
||||
|
||||
filename = convert_and_check_filename(file);
|
||||
|
||||
if (!replace)
|
||||
{
|
||||
struct stat fst;
|
||||
|
||||
if (stat(filename, &fst) >= 0)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_DUPLICATE_FILE),
|
||||
errmsg("file \"%s\" exists", filename)));
|
||||
|
||||
f = AllocateFile(filename, "wb");
|
||||
}
|
||||
else
|
||||
f = AllocateFile(filename, "ab");
|
||||
|
||||
if (!f)
|
||||
ereport(ERROR,
|
||||
(errcode_for_file_access(),
|
||||
errmsg("could not open file \"%s\" for writing: %m",
|
||||
filename)));
|
||||
|
||||
count = fwrite(VARDATA_ANY(data), 1, VARSIZE_ANY_EXHDR(data), f);
|
||||
if (count != VARSIZE_ANY_EXHDR(data) || FreeFile(f))
|
||||
ereport(ERROR,
|
||||
(errcode_for_file_access(),
|
||||
errmsg("could not write file \"%s\": %m", filename)));
|
||||
|
||||
return (count);
|
||||
}
|
||||
|
||||
/* ------------------------------------
|
||||
* pg_file_sync
|
||||
*
|
||||
* We REVOKE EXECUTE on the function from PUBLIC.
|
||||
* Users can then grant access to it based on their policies.
|
||||
*/
|
||||
Datum
|
||||
pg_file_sync(PG_FUNCTION_ARGS)
|
||||
{
|
||||
char *filename;
|
||||
struct stat fst;
|
||||
|
||||
filename = convert_and_check_filename(PG_GETARG_TEXT_PP(0));
|
||||
|
||||
if (stat(filename, &fst) < 0)
|
||||
ereport(ERROR,
|
||||
(errcode_for_file_access(),
|
||||
errmsg("could not stat file \"%s\": %m", filename)));
|
||||
|
||||
fsync_fname_ext(filename, S_ISDIR(fst.st_mode), false, ERROR);
|
||||
|
||||
PG_RETURN_VOID();
|
||||
}
|
||||
|
||||
/* ------------------------------------
|
||||
* 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)
|
||||
{
|
||||
text *file1;
|
||||
text *file2;
|
||||
text *file3;
|
||||
bool result;
|
||||
|
||||
requireSuperuser();
|
||||
|
||||
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_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.
|
||||
*/
|
||||
static bool
|
||||
pg_file_rename_internal(text *file1, text *file2, text *file3)
|
||||
{
|
||||
char *fn1,
|
||||
*fn2,
|
||||
*fn3;
|
||||
int rc;
|
||||
|
||||
fn1 = convert_and_check_filename(file1);
|
||||
fn2 = convert_and_check_filename(file2);
|
||||
|
||||
if (file3 == NULL)
|
||||
fn3 = NULL;
|
||||
else
|
||||
fn3 = convert_and_check_filename(file3);
|
||||
|
||||
if (access(fn1, W_OK) < 0)
|
||||
{
|
||||
ereport(WARNING,
|
||||
(errcode_for_file_access(),
|
||||
errmsg("file \"%s\" is not accessible: %m", fn1)));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (fn3 && access(fn2, W_OK) < 0)
|
||||
{
|
||||
ereport(WARNING,
|
||||
(errcode_for_file_access(),
|
||||
errmsg("file \"%s\" is not accessible: %m", fn2)));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
rc = access(fn3 ? fn3 : fn2, W_OK);
|
||||
if (rc >= 0 || errno != ENOENT)
|
||||
{
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_DUPLICATE_FILE),
|
||||
errmsg("cannot rename to target file \"%s\"",
|
||||
fn3 ? fn3 : fn2)));
|
||||
}
|
||||
|
||||
if (fn3)
|
||||
{
|
||||
if (rename(fn2, fn3) != 0)
|
||||
{
|
||||
ereport(ERROR,
|
||||
(errcode_for_file_access(),
|
||||
errmsg("could not rename \"%s\" to \"%s\": %m",
|
||||
fn2, fn3)));
|
||||
}
|
||||
if (rename(fn1, fn2) != 0)
|
||||
{
|
||||
ereport(WARNING,
|
||||
(errcode_for_file_access(),
|
||||
errmsg("could not rename \"%s\" to \"%s\": %m",
|
||||
fn1, fn2)));
|
||||
|
||||
if (rename(fn3, fn2) != 0)
|
||||
{
|
||||
ereport(ERROR,
|
||||
(errcode_for_file_access(),
|
||||
errmsg("could not rename \"%s\" back to \"%s\": %m",
|
||||
fn3, fn2)));
|
||||
}
|
||||
else
|
||||
{
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_UNDEFINED_FILE),
|
||||
errmsg("renaming \"%s\" to \"%s\" was reverted",
|
||||
fn2, fn3)));
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (rename(fn1, fn2) != 0)
|
||||
{
|
||||
ereport(ERROR,
|
||||
(errcode_for_file_access(),
|
||||
errmsg("could not rename \"%s\" to \"%s\": %m", fn1, fn2)));
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
char *filename;
|
||||
|
||||
requireSuperuser();
|
||||
|
||||
filename = convert_and_check_filename(PG_GETARG_TEXT_PP(0));
|
||||
|
||||
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_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));
|
||||
|
||||
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)
|
||||
{
|
||||
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));
|
||||
}
|
||||
|
||||
static Datum
|
||||
pg_logdir_ls_internal(FunctionCallInfo fcinfo)
|
||||
{
|
||||
ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
|
||||
bool randomAccess;
|
||||
TupleDesc tupdesc;
|
||||
Tuplestorestate *tupstore;
|
||||
AttInMetadata *attinmeta;
|
||||
DIR *dirdesc;
|
||||
struct dirent *de;
|
||||
MemoryContext oldcontext;
|
||||
|
||||
if (strcmp(Log_filename, "postgresql-%Y-%m-%d_%H%M%S.log") != 0)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||
errmsg("the log_filename parameter must equal 'postgresql-%%Y-%%m-%%d_%%H%%M%%S.log'")));
|
||||
|
||||
/* check to see if caller supports us returning a tuplestore */
|
||||
if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||
errmsg("set-valued function called in context that cannot accept a set")));
|
||||
if (!(rsinfo->allowedModes & SFRM_Materialize))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_SYNTAX_ERROR),
|
||||
errmsg("materialize mode required, but it is not allowed in this context")));
|
||||
|
||||
/* The tupdesc and tuplestore must be created in ecxt_per_query_memory */
|
||||
oldcontext = MemoryContextSwitchTo(rsinfo->econtext->ecxt_per_query_memory);
|
||||
|
||||
tupdesc = CreateTemplateTupleDesc(2);
|
||||
TupleDescInitEntry(tupdesc, (AttrNumber) 1, "starttime",
|
||||
TIMESTAMPOID, -1, 0);
|
||||
TupleDescInitEntry(tupdesc, (AttrNumber) 2, "filename",
|
||||
TEXTOID, -1, 0);
|
||||
|
||||
randomAccess = (rsinfo->allowedModes & SFRM_Materialize_Random) != 0;
|
||||
tupstore = tuplestore_begin_heap(randomAccess, false, work_mem);
|
||||
rsinfo->returnMode = SFRM_Materialize;
|
||||
rsinfo->setResult = tupstore;
|
||||
rsinfo->setDesc = tupdesc;
|
||||
|
||||
MemoryContextSwitchTo(oldcontext);
|
||||
|
||||
attinmeta = TupleDescGetAttInMetadata(tupdesc);
|
||||
|
||||
dirdesc = AllocateDir(Log_directory);
|
||||
while ((de = ReadDir(dirdesc, Log_directory)) != NULL)
|
||||
{
|
||||
char *values[2];
|
||||
HeapTuple tuple;
|
||||
char timestampbuf[32];
|
||||
char *field[MAXDATEFIELDS];
|
||||
char lowstr[MAXDATELEN + 1];
|
||||
int dtype;
|
||||
int nf,
|
||||
ftype[MAXDATEFIELDS];
|
||||
fsec_t fsec;
|
||||
int tz = 0;
|
||||
struct pg_tm date;
|
||||
DateTimeErrorExtra extra;
|
||||
|
||||
/*
|
||||
* Default format: postgresql-YYYY-MM-DD_HHMMSS.log
|
||||
*/
|
||||
if (strlen(de->d_name) != 32
|
||||
|| strncmp(de->d_name, "postgresql-", 11) != 0
|
||||
|| de->d_name[21] != '_'
|
||||
|| strcmp(de->d_name + 28, ".log") != 0)
|
||||
continue;
|
||||
|
||||
/* extract timestamp portion of filename */
|
||||
strcpy(timestampbuf, de->d_name + 11);
|
||||
timestampbuf[17] = '\0';
|
||||
|
||||
/* parse and decode expected timestamp to verify it's OK format */
|
||||
if (ParseDateTime(timestampbuf, lowstr, MAXDATELEN, field, ftype, MAXDATEFIELDS, &nf))
|
||||
continue;
|
||||
|
||||
if (DecodeDateTime(field, ftype, nf,
|
||||
&dtype, &date, &fsec, &tz, &extra))
|
||||
continue;
|
||||
|
||||
/* Seems the timestamp is OK; prepare and return tuple */
|
||||
|
||||
values[0] = timestampbuf;
|
||||
values[1] = psprintf("%s/%s", Log_directory, de->d_name);
|
||||
|
||||
tuple = BuildTupleFromCStrings(attinmeta, values);
|
||||
|
||||
tuplestore_puttuple(tupstore, tuple);
|
||||
}
|
||||
|
||||
FreeDir(dirdesc);
|
||||
return (Datum) 0;
|
||||
}
|
|
@ -1,6 +0,0 @@
|
|||
# adminpack extension
|
||||
comment = 'administrative functions for PostgreSQL'
|
||||
default_version = '2.1'
|
||||
module_pathname = '$libdir/adminpack'
|
||||
relocatable = false
|
||||
schema = pg_catalog
|
|
@ -1,172 +0,0 @@
|
|||
CREATE EXTENSION adminpack;
|
||||
-- create new file
|
||||
SELECT pg_file_write('test_file1', 'test1', false);
|
||||
pg_file_write
|
||||
---------------
|
||||
5
|
||||
(1 row)
|
||||
|
||||
SELECT pg_read_file('test_file1');
|
||||
pg_read_file
|
||||
--------------
|
||||
test1
|
||||
(1 row)
|
||||
|
||||
-- append
|
||||
SELECT pg_file_write('test_file1', 'test1', true);
|
||||
pg_file_write
|
||||
---------------
|
||||
5
|
||||
(1 row)
|
||||
|
||||
SELECT pg_read_file('test_file1');
|
||||
pg_read_file
|
||||
--------------
|
||||
test1test1
|
||||
(1 row)
|
||||
|
||||
-- error, already exists
|
||||
SELECT pg_file_write('test_file1', 'test1', false);
|
||||
ERROR: file "test_file1" exists
|
||||
SELECT pg_read_file('test_file1');
|
||||
pg_read_file
|
||||
--------------
|
||||
test1test1
|
||||
(1 row)
|
||||
|
||||
-- disallowed file paths for non-superusers and users who are
|
||||
-- not members of pg_write_server_files
|
||||
CREATE ROLE regress_adminpack_user1;
|
||||
GRANT pg_read_all_settings TO regress_adminpack_user1;
|
||||
GRANT EXECUTE ON FUNCTION pg_file_write(text,text,bool) TO regress_adminpack_user1;
|
||||
SET ROLE regress_adminpack_user1;
|
||||
SELECT pg_file_write('../test_file0', 'test0', false);
|
||||
ERROR: path must be in or below the data directory
|
||||
SELECT pg_file_write('/tmp/test_file0', 'test0', false);
|
||||
ERROR: absolute path not allowed
|
||||
SELECT pg_file_write(current_setting('data_directory') || '/test_file4', 'test4', false);
|
||||
pg_file_write
|
||||
---------------
|
||||
5
|
||||
(1 row)
|
||||
|
||||
SELECT pg_file_write(current_setting('data_directory') || '/../test_file4', 'test4', false);
|
||||
ERROR: absolute path not allowed
|
||||
RESET ROLE;
|
||||
REVOKE EXECUTE ON FUNCTION pg_file_write(text,text,bool) FROM regress_adminpack_user1;
|
||||
REVOKE pg_read_all_settings FROM regress_adminpack_user1;
|
||||
DROP ROLE regress_adminpack_user1;
|
||||
-- sync
|
||||
SELECT pg_file_sync('test_file1'); -- sync file
|
||||
pg_file_sync
|
||||
--------------
|
||||
|
||||
(1 row)
|
||||
|
||||
SELECT pg_file_sync('pg_stat'); -- sync directory
|
||||
pg_file_sync
|
||||
--------------
|
||||
|
||||
(1 row)
|
||||
|
||||
SELECT pg_file_sync('test_file2'); -- not there
|
||||
ERROR: could not stat file "test_file2": No such file or directory
|
||||
-- rename file
|
||||
SELECT pg_file_rename('test_file1', 'test_file2');
|
||||
pg_file_rename
|
||||
----------------
|
||||
t
|
||||
(1 row)
|
||||
|
||||
SELECT pg_read_file('test_file1'); -- not there
|
||||
ERROR: could not open file "test_file1" for reading: No such file or directory
|
||||
SELECT pg_read_file('test_file2');
|
||||
pg_read_file
|
||||
--------------
|
||||
test1test1
|
||||
(1 row)
|
||||
|
||||
-- error
|
||||
SELECT pg_file_rename('test_file1', 'test_file2');
|
||||
WARNING: file "test_file1" is not accessible: No such file or directory
|
||||
pg_file_rename
|
||||
----------------
|
||||
f
|
||||
(1 row)
|
||||
|
||||
-- rename file and archive
|
||||
SELECT pg_file_write('test_file3', 'test3', false);
|
||||
pg_file_write
|
||||
---------------
|
||||
5
|
||||
(1 row)
|
||||
|
||||
SELECT pg_file_rename('test_file2', 'test_file3', 'test_file3_archive');
|
||||
pg_file_rename
|
||||
----------------
|
||||
t
|
||||
(1 row)
|
||||
|
||||
SELECT pg_read_file('test_file2'); -- not there
|
||||
ERROR: could not open file "test_file2" for reading: No such file or directory
|
||||
SELECT pg_read_file('test_file3');
|
||||
pg_read_file
|
||||
--------------
|
||||
test1test1
|
||||
(1 row)
|
||||
|
||||
SELECT pg_read_file('test_file3_archive');
|
||||
pg_read_file
|
||||
--------------
|
||||
test3
|
||||
(1 row)
|
||||
|
||||
-- unlink
|
||||
SELECT pg_file_unlink('test_file1'); -- does not exist
|
||||
pg_file_unlink
|
||||
----------------
|
||||
f
|
||||
(1 row)
|
||||
|
||||
SELECT pg_file_unlink('test_file2'); -- does not exist
|
||||
pg_file_unlink
|
||||
----------------
|
||||
f
|
||||
(1 row)
|
||||
|
||||
SELECT pg_file_unlink('test_file3');
|
||||
pg_file_unlink
|
||||
----------------
|
||||
t
|
||||
(1 row)
|
||||
|
||||
SELECT pg_file_unlink('test_file3_archive');
|
||||
pg_file_unlink
|
||||
----------------
|
||||
t
|
||||
(1 row)
|
||||
|
||||
SELECT pg_file_unlink('test_file4');
|
||||
pg_file_unlink
|
||||
----------------
|
||||
t
|
||||
(1 row)
|
||||
|
||||
-- superuser checks
|
||||
CREATE USER regress_adminpack_user1;
|
||||
SET ROLE regress_adminpack_user1;
|
||||
SELECT pg_file_write('test_file0', 'test0', false);
|
||||
ERROR: permission denied for function pg_file_write
|
||||
SELECT pg_file_sync('test_file0');
|
||||
ERROR: permission denied for function pg_file_sync
|
||||
SELECT pg_file_rename('test_file0', 'test_file0');
|
||||
ERROR: permission denied for function pg_file_rename
|
||||
CONTEXT: SQL function "pg_file_rename" statement 1
|
||||
SELECT pg_file_unlink('test_file0');
|
||||
ERROR: permission denied for function pg_file_unlink
|
||||
SELECT pg_logdir_ls();
|
||||
ERROR: permission denied for function pg_logdir_ls
|
||||
RESET ROLE;
|
||||
DROP USER regress_adminpack_user1;
|
||||
-- no further tests for pg_logdir_ls() because it depends on the
|
||||
-- server's logging setup
|
|
@ -1,35 +0,0 @@
|
|||
# Copyright (c) 2022-2024, PostgreSQL Global Development Group
|
||||
|
||||
adminpack_sources = files(
|
||||
'adminpack.c',
|
||||
)
|
||||
|
||||
if host_system == 'windows'
|
||||
adminpack_sources += rc_lib_gen.process(win32ver_rc, extra_args: [
|
||||
'--NAME', 'adminpack',
|
||||
'--FILEDESC', 'adminpack - support functions for pgAdmin',])
|
||||
endif
|
||||
|
||||
adminpack = shared_module('adminpack',
|
||||
adminpack_sources,
|
||||
kwargs: contrib_mod_args,
|
||||
)
|
||||
contrib_targets += adminpack
|
||||
|
||||
install_data(
|
||||
'adminpack.control',
|
||||
'adminpack--1.0.sql',
|
||||
'adminpack--1.0--1.1.sql',
|
||||
'adminpack--1.1--2.0.sql',
|
||||
'adminpack--2.0--2.1.sql',
|
||||
kwargs: contrib_data_args,
|
||||
)
|
||||
|
||||
tests += {
|
||||
'name': 'adminpack',
|
||||
'sd': meson.current_source_dir(),
|
||||
'bd': meson.current_build_dir(),
|
||||
'regress': {
|
||||
'sql': ['adminpack'],
|
||||
},
|
||||
}
|
|
@ -1,76 +0,0 @@
|
|||
CREATE EXTENSION adminpack;
|
||||
|
||||
-- create new file
|
||||
SELECT pg_file_write('test_file1', 'test1', false);
|
||||
SELECT pg_read_file('test_file1');
|
||||
|
||||
-- append
|
||||
SELECT pg_file_write('test_file1', 'test1', true);
|
||||
SELECT pg_read_file('test_file1');
|
||||
|
||||
-- error, already exists
|
||||
SELECT pg_file_write('test_file1', 'test1', false);
|
||||
SELECT pg_read_file('test_file1');
|
||||
|
||||
-- disallowed file paths for non-superusers and users who are
|
||||
-- not members of pg_write_server_files
|
||||
CREATE ROLE regress_adminpack_user1;
|
||||
|
||||
GRANT pg_read_all_settings TO regress_adminpack_user1;
|
||||
GRANT EXECUTE ON FUNCTION pg_file_write(text,text,bool) TO regress_adminpack_user1;
|
||||
|
||||
SET ROLE regress_adminpack_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_adminpack_user1;
|
||||
REVOKE pg_read_all_settings FROM regress_adminpack_user1;
|
||||
DROP ROLE regress_adminpack_user1;
|
||||
|
||||
-- sync
|
||||
SELECT pg_file_sync('test_file1'); -- sync file
|
||||
SELECT pg_file_sync('pg_stat'); -- sync directory
|
||||
SELECT pg_file_sync('test_file2'); -- not there
|
||||
|
||||
-- rename file
|
||||
SELECT pg_file_rename('test_file1', 'test_file2');
|
||||
SELECT pg_read_file('test_file1'); -- not there
|
||||
SELECT pg_read_file('test_file2');
|
||||
|
||||
-- error
|
||||
SELECT pg_file_rename('test_file1', 'test_file2');
|
||||
|
||||
-- rename file and archive
|
||||
SELECT pg_file_write('test_file3', 'test3', false);
|
||||
SELECT pg_file_rename('test_file2', 'test_file3', 'test_file3_archive');
|
||||
SELECT pg_read_file('test_file2'); -- not there
|
||||
SELECT pg_read_file('test_file3');
|
||||
SELECT pg_read_file('test_file3_archive');
|
||||
|
||||
|
||||
-- unlink
|
||||
SELECT pg_file_unlink('test_file1'); -- does not exist
|
||||
SELECT pg_file_unlink('test_file2'); -- does not exist
|
||||
SELECT pg_file_unlink('test_file3');
|
||||
SELECT pg_file_unlink('test_file3_archive');
|
||||
SELECT pg_file_unlink('test_file4');
|
||||
|
||||
|
||||
-- superuser checks
|
||||
CREATE USER regress_adminpack_user1;
|
||||
SET ROLE regress_adminpack_user1;
|
||||
|
||||
SELECT pg_file_write('test_file0', 'test0', false);
|
||||
SELECT pg_file_sync('test_file0');
|
||||
SELECT pg_file_rename('test_file0', 'test_file0');
|
||||
SELECT pg_file_unlink('test_file0');
|
||||
SELECT pg_logdir_ls();
|
||||
|
||||
RESET ROLE;
|
||||
DROP USER regress_adminpack_user1;
|
||||
|
||||
|
||||
-- no further tests for pg_logdir_ls() because it depends on the
|
||||
-- server's logging setup
|
|
@ -12,7 +12,6 @@ contrib_doc_args = {
|
|||
'install_dir': contrib_doc_dir,
|
||||
}
|
||||
|
||||
subdir('adminpack')
|
||||
subdir('amcheck')
|
||||
subdir('auth_delay')
|
||||
subdir('auto_explain')
|
||||
|
|
|
@ -1,159 +0,0 @@
|
|||
<!-- doc/src/sgml/adminpack.sgml -->
|
||||
|
||||
<sect1 id="adminpack" xreflabel="adminpack">
|
||||
<title>adminpack — pgAdmin support toolpack</title>
|
||||
|
||||
<indexterm zone="adminpack">
|
||||
<primary>adminpack</primary>
|
||||
</indexterm>
|
||||
|
||||
<para>
|
||||
<filename>adminpack</filename> provides a number of support functions which
|
||||
<application>pgAdmin</application> 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 only allowed to database superusers by default, but may be
|
||||
allowed to other users by using the <command>GRANT</command> command.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The functions shown in <xref linkend="functions-adminpack-table"/> provide
|
||||
write access to files on the machine hosting the server. (See also the
|
||||
functions in <xref linkend="functions-admin-genfile-table"/>, which
|
||||
provide read-only access.)
|
||||
Only files within the database cluster directory can be accessed, unless the
|
||||
user is a superuser or given privileges of one of the
|
||||
<literal>pg_read_server_files</literal> or
|
||||
<literal>pg_write_server_files</literal> roles, as appropriate for the
|
||||
function, but either a relative or absolute path is allowable.
|
||||
</para>
|
||||
|
||||
<table id="functions-adminpack-table">
|
||||
<title><filename>adminpack</filename> Functions</title>
|
||||
<tgroup cols="1">
|
||||
<thead>
|
||||
<row>
|
||||
<entry role="func_table_entry"><para role="func_signature">
|
||||
Function
|
||||
</para>
|
||||
<para>
|
||||
Description
|
||||
</para></entry>
|
||||
</row>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
<row>
|
||||
<entry role="func_table_entry"><para role="func_signature">
|
||||
<function>pg_catalog.pg_file_write</function> ( <parameter>filename</parameter> <type>text</type>, <parameter>data</parameter> <type>text</type>, <parameter>append</parameter> <type>boolean</type> )
|
||||
<returnvalue>bigint</returnvalue>
|
||||
</para>
|
||||
<para>
|
||||
Writes, or appends to, a text file.
|
||||
</para></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry role="func_table_entry"><para role="func_signature">
|
||||
<function>pg_catalog.pg_file_sync</function> ( <parameter>filename</parameter> <type>text</type> )
|
||||
<returnvalue>void</returnvalue>
|
||||
</para>
|
||||
<para>
|
||||
Flushes a file or directory to disk.
|
||||
</para></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry role="func_table_entry"><para role="func_signature">
|
||||
<function>pg_catalog.pg_file_rename</function> ( <parameter>oldname</parameter> <type>text</type>, <parameter>newname</parameter> <type>text</type> <optional>, <parameter>archivename</parameter> <type>text</type> </optional> )
|
||||
<returnvalue>boolean</returnvalue>
|
||||
</para>
|
||||
<para>
|
||||
Renames a file.
|
||||
</para></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry role="func_table_entry"><para role="func_signature">
|
||||
<function>pg_catalog.pg_file_unlink</function> ( <parameter>filename</parameter> <type>text</type> )
|
||||
<returnvalue>boolean</returnvalue>
|
||||
</para>
|
||||
<para>
|
||||
Removes a file.
|
||||
</para></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry role="func_table_entry"><para role="func_signature">
|
||||
<function>pg_catalog.pg_logdir_ls</function> ()
|
||||
<returnvalue>setof record</returnvalue>
|
||||
</para>
|
||||
<para>
|
||||
Lists the log files in the <varname>log_directory</varname> directory.
|
||||
</para></entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
|
||||
<indexterm>
|
||||
<primary>pg_file_write</primary>
|
||||
</indexterm>
|
||||
<para>
|
||||
<function>pg_file_write</function> writes the specified <parameter>data</parameter> into
|
||||
the file named by <parameter>filename</parameter>. If <parameter>append</parameter> is
|
||||
false, the file must not already exist. If <parameter>append</parameter> is true,
|
||||
the file can already exist, and will be appended to if so.
|
||||
Returns the number of bytes written.
|
||||
</para>
|
||||
|
||||
<indexterm>
|
||||
<primary>pg_file_sync</primary>
|
||||
</indexterm>
|
||||
<para>
|
||||
<function>pg_file_sync</function> fsyncs the specified file or directory
|
||||
named by <parameter>filename</parameter>. An error is thrown
|
||||
on failure (e.g., the specified file is not present). Note that
|
||||
<xref linkend="guc-data-sync-retry"/> has no effect on this function,
|
||||
and therefore a PANIC-level error will not be raised even on failure to
|
||||
flush database files.
|
||||
</para>
|
||||
|
||||
<indexterm>
|
||||
<primary>pg_file_rename</primary>
|
||||
</indexterm>
|
||||
<para>
|
||||
<function>pg_file_rename</function> renames a file. If <parameter>archivename</parameter>
|
||||
is omitted or NULL, it simply renames <parameter>oldname</parameter>
|
||||
to <parameter>newname</parameter> (which must not already exist).
|
||||
If <parameter>archivename</parameter> is provided, it first
|
||||
renames <parameter>newname</parameter> to <parameter>archivename</parameter> (which must
|
||||
not already exist), and then renames <parameter>oldname</parameter>
|
||||
to <parameter>newname</parameter>. In event of failure of the second rename step,
|
||||
it will try to rename <parameter>archivename</parameter> back
|
||||
to <parameter>newname</parameter> before reporting the error.
|
||||
Returns true on success, false if the source file(s) are not present or
|
||||
not writable; other cases throw errors.
|
||||
</para>
|
||||
|
||||
<indexterm>
|
||||
<primary>pg_file_unlink</primary>
|
||||
</indexterm>
|
||||
<para>
|
||||
<function>pg_file_unlink</function> removes the specified file.
|
||||
Returns true on success, false if the specified file is not present
|
||||
or the <function>unlink()</function> call fails; other cases throw errors.
|
||||
</para>
|
||||
|
||||
<indexterm>
|
||||
<primary>pg_logdir_ls</primary>
|
||||
</indexterm>
|
||||
<para>
|
||||
<function>pg_logdir_ls</function> returns the start timestamps and path
|
||||
names of all the log files in the <xref linkend="guc-log-directory"/>
|
||||
directory. The <xref linkend="guc-log-filename"/> parameter must have its
|
||||
default setting (<literal>postgresql-%Y-%m-%d_%H%M%S.log</literal>) to use this
|
||||
function.
|
||||
</para>
|
||||
|
||||
</sect1>
|
|
@ -127,7 +127,6 @@ CREATE EXTENSION <replaceable>extension_name</replaceable>;
|
|||
component for details.
|
||||
</para>
|
||||
|
||||
&adminpack;
|
||||
&amcheck;
|
||||
&auth-delay;
|
||||
&auto-explain;
|
||||
|
|
|
@ -113,7 +113,6 @@
|
|||
|
||||
<!-- contrib information -->
|
||||
<!ENTITY contrib SYSTEM "contrib.sgml">
|
||||
<!ENTITY adminpack SYSTEM "adminpack.sgml">
|
||||
<!ENTITY amcheck SYSTEM "amcheck.sgml">
|
||||
<!ENTITY auth-delay SYSTEM "auth-delay.sgml">
|
||||
<!ENTITY auto-explain SYSTEM "auto-explain.sgml">
|
||||
|
|
|
@ -270,33 +270,6 @@ 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"),
|
||||
/* translator: %s is a SQL function name */
|
||||
errhint("Consider using %s, which is part of core, instead.",
|
||||
"pg_logfile_rotate()")));
|
||||
|
||||
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
|
||||
*
|
||||
|
@ -304,7 +277,7 @@ pg_rotate_logfile(PG_FUNCTION_ARGS)
|
|||
* GRANT system.
|
||||
*/
|
||||
Datum
|
||||
pg_rotate_logfile_v2(PG_FUNCTION_ARGS)
|
||||
pg_rotate_logfile(PG_FUNCTION_ARGS)
|
||||
{
|
||||
if (!Logging_collector)
|
||||
{
|
||||
|
|
|
@ -227,52 +227,6 @@ read_text_file(const char *filename, int64 seek_offset, int64 bytes_to_read,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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)
|
||||
{
|
||||
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;
|
||||
|
||||
if (!superuser())
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
|
||||
errmsg("must be superuser to read files with adminpack 1.0"),
|
||||
/* translator: %s is a SQL function name */
|
||||
errhint("Consider using %s, which is part of core, instead.",
|
||||
"pg_read_file()")));
|
||||
|
||||
/* 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
|
||||
*
|
||||
|
|
|
@ -57,6 +57,6 @@
|
|||
*/
|
||||
|
||||
/* yyyymmddN */
|
||||
#define CATALOG_VERSION_NO 202402291
|
||||
#define CATALOG_VERSION_NO 202403041
|
||||
|
||||
#endif
|
||||
|
|
|
@ -6545,9 +6545,6 @@
|
|||
proargtypes => '', prosrc => 'pg_reload_conf' },
|
||||
{ oid => '2622', descr => 'rotate log file',
|
||||
proname => 'pg_rotate_logfile', provolatile => 'v', prorettype => 'bool',
|
||||
proargtypes => '', prosrc => 'pg_rotate_logfile_v2' },
|
||||
{ oid => '4099', descr => 'rotate log file - old version for adminpack 1.0',
|
||||
proname => 'pg_rotate_logfile_old', provolatile => 'v', prorettype => 'bool',
|
||||
proargtypes => '', prosrc => 'pg_rotate_logfile' },
|
||||
{ oid => '3800', descr => 'current logging collector file location',
|
||||
proname => 'pg_current_logfile', proisstrict => 'f', provolatile => 'v',
|
||||
|
@ -6578,10 +6575,6 @@
|
|||
proname => 'pg_read_file', provolatile => 'v', prorettype => 'text',
|
||||
proargtypes => 'text int8 int8 bool',
|
||||
prosrc => 'pg_read_file_off_len_missing' },
|
||||
{ oid => '4100',
|
||||
descr => 'read text from a file - old version for adminpack 1.0',
|
||||
proname => 'pg_read_file_old', provolatile => 'v', prorettype => 'text',
|
||||
proargtypes => 'text int8 int8', prosrc => 'pg_read_file' },
|
||||
{ oid => '3826', descr => 'read text from a file',
|
||||
proname => 'pg_read_file', provolatile => 'v', prorettype => 'text',
|
||||
proargtypes => 'text', prosrc => 'pg_read_file_all' },
|
||||
|
|
Loading…
Reference in a new issue