Skip to content
Snippets Groups Projects
Commit a433c6b4 authored by Michael Paquier's avatar Michael Paquier
Browse files

wal_utils: Add function to fetch size of an archive element

This is useful if combined with the function to get a full data chunk
from the archives. At the same time regression tests are refactored
so as the extension wal_utils is created only once as initialization
for all the other tests.
parent a30b9bf8
No related branches found
No related tags found
No related merge requests found
Loading
Loading
@@ -3,7 +3,7 @@ MODULES = wal_utils
EXTENSION = wal_utils
DATA = wal_utils--1.0.sql
PGFILEDESC = "wal_utils - Set of tools for WAL data"
REGRESS = parse_wal_history wal_segment_list
REGRESS = init archive_data parse_wal_history wal_segment_list
 
PG_CONFIG = pg_config
PGXS := $(shell $(PG_CONFIG) --pgxs)
Loading
Loading
-- Sanity check for archive_get_size
SELECT archive_get_size('../no_parent'); -- error
ERROR: reference to parent directory ("..") not allowed
SELECT archive_get_size('/no_absolute'); -- error
ERROR: absolute path not allowed
-- Create extension for all the following tests
CREATE EXTENSION wal_utils;
-- Install extension for tests
CREATE EXTENSION wal_utils;
-- Tests for parsing of WAL history file
CREATE TABLE history_data (data text);
-- Note that COPY truncates newlines.
-- Load history file that succeeds
Loading
Loading
-- Install extension for tests
CREATE EXTENSION wal_utils;
ERROR: extension "wal_utils" already exists
-- Tests for build of WAL segment list for multiple timelines
-- NULL checks
SELECT build_wal_segment_list(NULL, '0/0'::pg_lsn, 1, '0/0'::pg_lsn, NULL);
ERROR: origin or target data cannot be NULL
Loading
Loading
-- Sanity check for archive_get_size
SELECT archive_get_size('../no_parent'); -- error
SELECT archive_get_size('/no_absolute'); -- error
-- Create extension for all the following tests
CREATE EXTENSION wal_utils;
-- Install extension for tests
CREATE EXTENSION wal_utils;
-- Tests for parsing of WAL history file
 
CREATE TABLE history_data (data text);
 
Loading
Loading
-- Install extension for tests
CREATE EXTENSION wal_utils;
-- Tests for build of WAL segment list for multiple timelines
 
-- NULL checks
SELECT build_wal_segment_list(NULL, '0/0'::pg_lsn, 1, '0/0'::pg_lsn, NULL);
Loading
Loading
Loading
Loading
@@ -28,3 +28,27 @@ CREATE FUNCTION build_wal_segment_list(
RETURNS SETOF text
AS 'MODULE_PATHNAME'
LANGUAGE C;
-- Set of routines for archive data fetching
-- Get data from the archive path. The base path where the lookup is
-- done uses as environment variable PGARCHIVE which points to a local
-- path where the archives are located. This should be a variable loaded
-- by Postgres. Note that there is no restriction on the file name that
-- caller can use here, a segment file could be compressed, and the
-- archive could be used as well to store some custom metadata. The path
-- defined cannot be absolute as well.
-- CREATE FUNCTION archive_get_data(
-- IN filename text,
-- IN begin bigint,
-- IN offset bigint,
-- OUT data bytea)
-- RETURNS bytea
-- AS 'MODULE_PATHNAME'
-- LANGUAGE C STRICT;
-- Get the size of a file in archives.
CREATE FUNCTION archive_get_size(
IN filename text,
OUT size bigint)
RETURNS bigint
AS 'MODULE_PATHNAME'
LANGUAGE C STRICT;
Loading
Loading
@@ -14,6 +14,8 @@
#include "postgres.h"
#include "fmgr.h"
 
#include <sys/stat.h>
#include "access/timeline.h"
#include "access/xlog_internal.h"
#include "catalog/pg_type.h"
Loading
Loading
@@ -31,6 +33,7 @@ static List *parseTimeLineHistory(char *buffer);
*/
PG_FUNCTION_INFO_V1(parse_wal_history);
PG_FUNCTION_INFO_V1(build_wal_segment_list);
PG_FUNCTION_INFO_V1(archive_get_size);
 
/*
* parseTimeLineHistory
Loading
Loading
@@ -433,3 +436,73 @@ build_wal_segment_list(PG_FUNCTION_ARGS)
 
return (Datum) 0;
}
/*
* Check the defined file name, looking at if it is an absolute path
* and if it contains references to a parent directory. Then build
* a full path name using the path defined for the archives which is
* enforced by the environment where Postgres is running.
*/
static char *
check_and_build_filepath(char *filename)
{
char *filepath;
char *archive_path;
if (is_absolute_path(filename))
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
(errmsg("absolute path not allowed"))));
if (path_contains_parent_reference(filename))
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
(errmsg("reference to parent directory (\"..\") not allowed"))));
archive_path = getenv("PGARCHIVE");
if (archive_path == NULL)
ereport(ERROR,
(errcode(ERRCODE_FDW_INVALID_OPTION_NAME),
errmsg("archive path is not defined"),
errhint("Check value of environment variable %s",
"PGARCHIVE")));
filepath = (char *) palloc(MAXPGPATH);
snprintf(filepath, MAXPGPATH, "%s/%s", archive_path, filename);
/* length can change here */
canonicalize_path(filepath);
return filepath;
}
/*
* archive_get_size
*
* Look at a file in the archives whose path is defined by the environment
* variable PGARCHIVE and get its size. This is useful when combined with
* archive_get_data to evaluate a set of chunks to be used during any
* data transfer from the archives.
*/
Datum
archive_get_size(PG_FUNCTION_ARGS)
{
char *filename = text_to_cstring(PG_GETARG_TEXT_PP(0));
char *filepath;
struct stat fst;
if (!superuser())
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
(errmsg("must be superuser to read files"))));
filepath = check_and_build_filepath(filename);
pfree(filename);
/* get needed information about the file */
if (stat(filepath, &fst) < 0)
ereport(ERROR,
(errcode_for_file_access(),
errmsg("could not stat file \"%s\": %m", filepath)));
PG_RETURN_INT64((int64) fst.st_size);
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment