openGauss-server/contrib/pg_xlogdump/compat.cpp

317 lines
11 KiB
C++

/*-------------------------------------------------------------------------
*
* compat.cpp
* Reimplementations of various backend functions.
*
* Portions Copyright (c) 2013-2016, PostgreSQL Global Development Group
*
* IDENTIFICATION
* contrib/pg_xlogdump/compat.cpp
*
* This file contains client-side implementations for various backend
* functions that the rm_desc functions in *desc.c files rely on.
*
*-------------------------------------------------------------------------
*/
/* ugly hack, same as in e.g pg_controldata */
#define FRONTEND 1
#include "postgres.h"
#include "knl/knl_variable.h"
#include <time.h>
#include "catalog/catalog.h"
#include "catalog/pg_tablespace.h"
#include "lib/stringinfo.h"
#include "storage/backendid.h"
#include "storage/custorage.h"
#include "utils/datetime.h"
/* We didn't know the exact pgxc nodename, use a const string instead. */
const char PGXCNodeName[] = "PGXC_NODENAME";
/*
* Lookup table of fork name by fork number.
*
* If you add a new entry, remember to update the errhint in
* forkname_to_number() below, and update the SGML documentation for
* pg_relation_size().
*/
const char* forkNames[] = {
"main", /* MAIN_FORKNUM */
"fsm", /* FSM_FORKNUM */
"vm", /* VISIBILITYMAP_FORKNUM */
"bcm", /* BCM_FORKNUM */
"init" /* INIT_FORKNUM */
};
/* copied from timestamp.c */
pg_time_t timestamptz_to_time_t(TimestampTz t)
{
pg_time_t result;
#ifdef HAVE_INT64_TIMESTAMP
result = (pg_time_t)(t / USECS_PER_SEC + ((POSTGRES_EPOCH_JDATE - UNIX_EPOCH_JDATE) * SECS_PER_DAY));
#else
result = (pg_time_t)(t + ((POSTGRES_EPOCH_JDATE - UNIX_EPOCH_JDATE) * SECS_PER_DAY));
#endif
return result;
}
/*
* Stopgap implementation of timestamptz_to_str that doesn't depend on backend
* infrastructure. This will work for timestamps that are within the range
* of the platform time_t type. (pg_time_t is compatible except for possibly
* being wider.)
*
* XXX the return value points to a static buffer, so beware of using more
* than one result value concurrently.
*
* XXX: The backend timestamp infrastructure should instead be split out and
* moved into src/common. That's a large project though.
*/
const char* timestamptz_to_str(TimestampTz dt)
{
static char buf[2 * MAXDATELEN + 14];
char ts[MAXDATELEN + 1];
char zone[MAXDATELEN + 1];
time_t result = (time_t)timestamptz_to_time_t(dt);
struct tm* ltime = localtime(&result);
strftime(ts, sizeof(ts), "%Y-%m-%d %H:%M:%S", ltime);
strftime(zone, sizeof(zone), "%Z", ltime);
#ifdef HAVE_INT64_TIMESTAMP
sprintf(buf, "%s.%06d %s", ts, (int)(dt % USECS_PER_SEC), zone);
#else
sprintf(buf, "%s.%.6f %s", ts, fabs(dt - floor(dt)), zone);
#endif
return buf;
}
/*
* Provide a hacked up compat layer for StringInfos so xlog desc functions can
* be linked/called.
*/
void appendStringInfo(StringInfo str, const char* fmt, ...)
{
va_list args;
va_start(args, fmt);
vprintf(fmt, args);
va_end(args);
}
void appendStringInfoString(StringInfo str, const char* string)
{
appendStringInfo(str, "%s", string);
}
void appendStringInfoChar(StringInfo str, char ch)
{
appendStringInfo(str, "%c", ch);
}
/*
* forkname_to_number - look up fork number by name
*
* In backend, we throw an error for no match; in frontend, we just
* return InvalidForkNumber.
*/
ForkNumber forkname_to_number(const char* forkName)
{
ForkNumber forkNum;
for (forkNum = 0; forkNum <= MAX_FORKNUM; forkNum++)
if (strcmp(forkNames[forkNum], forkName) == 0)
return forkNum;
#ifndef FRONTEND
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("invalid fork name"),
errhint("Valid fork names are \"main\", \"fsm\", "
"\"vm\", and \"init\".")));
#endif
return InvalidForkNumber;
}
/*
* relpathbackend - construct path to a relation's file
*/
char* relpathbackend(RelFileNode rnode, BackendId backend, ForkNumber forknum)
{
int pathlen;
char* path = NULL;
/* Column store file path, e.g: 16384_C1.0, 16384_C1_bcm */
if (forknum > MAX_FORKNUM) {
char attr_name[32];
int attid = forknum - MAX_FORKNUM;
path = (char*)calloc(MAXPGPATH, sizeof(char));
(void)snprintf(attr_name, sizeof(attr_name), "C%d", attid);
if (rnode.spcNode == GLOBALTABLESPACE_OID) {
/* Shared system relations live in {datadir}/global */
Assert(rnode.dbNode == 0);
pathlen = strlen("global") + 1 + OIDCHARS + 1 + strlen(attr_name) + 1;
(void)snprintf(path, pathlen, "global/%u_%s", rnode.relNode, attr_name);
} else if (rnode.spcNode == DEFAULTTABLESPACE_OID) {
/* The default tablespace is {datadir}/base */
pathlen = strlen("base") + 1 + OIDCHARS + 1 + OIDCHARS + 1 + strlen(attr_name) + 1;
(void)snprintf(path, pathlen, "base/%u/%u_%s", rnode.dbNode, rnode.relNode, attr_name);
} else {
/* All other tablespaces are accessed via symlinks */
pathlen = 9 + 1 + OIDCHARS + 1 + strlen(TABLESPACE_VERSION_DIRECTORY) + 1 + strlen(PGXCNodeName) + 1 +
OIDCHARS + 1 + OIDCHARS + 1 + strlen(attr_name) + 1;
(void)snprintf(path,
pathlen,
"pg_tblspc/%u/%s_%s/%u/%u_%s",
rnode.spcNode,
TABLESPACE_VERSION_DIRECTORY,
PGXCNodeName,
rnode.dbNode,
rnode.relNode,
attr_name);
}
} else {
if (rnode.spcNode == GLOBALTABLESPACE_OID) {
/* Shared system relations live in {datadir}/global */
Assert(rnode.dbNode == 0);
Assert(backend == InvalidBackendId);
pathlen = 7 + OIDCHARS + 1 + FORKNAMECHARS + 1;
path = (char*)malloc(pathlen);
if (forknum != MAIN_FORKNUM)
(void)snprintf(path, pathlen, "global/%u_%s", rnode.relNode, forkNames[forknum]);
else
(void)snprintf(path, pathlen, "global/%u", rnode.relNode);
} else if (rnode.spcNode == DEFAULTTABLESPACE_OID) {
/* The default tablespace is {datadir}/base */
if (backend == InvalidBackendId) {
pathlen = 5 + OIDCHARS + 1 + OIDCHARS + 1 + FORKNAMECHARS + 1;
path = (char*)malloc(pathlen);
if (forknum != MAIN_FORKNUM)
(void)snprintf(path, pathlen, "base/%u/%u_%s", rnode.dbNode, rnode.relNode, forkNames[forknum]);
else
(void)snprintf(path, pathlen, "base/%u/%u", rnode.dbNode, rnode.relNode);
} else {
/* OIDCHARS will suffice for an integer, too */
pathlen = 5 + OIDCHARS + 2 + OIDCHARS + 1 + OIDCHARS + 1 + FORKNAMECHARS + 1;
path = (char*)malloc(pathlen);
if (forknum != MAIN_FORKNUM)
(void)snprintf(
path, pathlen, "base/%u/t%d_%u_%s", rnode.dbNode, backend, rnode.relNode, forkNames[forknum]);
else
(void)snprintf(path, pathlen, "base/%u/t%d_%u", rnode.dbNode, backend, rnode.relNode);
}
} else {
/* All other tablespaces are accessed via symlinks */
if (backend == InvalidBackendId) {
pathlen = 9 + 1 + OIDCHARS + 1 + strlen(TABLESPACE_VERSION_DIRECTORY) + 1 + OIDCHARS +
1
#ifdef PGXC
/* Postgres-XC tablespaces include node name */
+ strlen(PGXCNodeName) + 1
#endif
+ OIDCHARS + 1 + FORKNAMECHARS + 1;
path = (char*)malloc(pathlen);
#ifdef PGXC
if (forknum != MAIN_FORKNUM)
(void)snprintf(path,
pathlen,
"pg_tblspc/%u/%s_%s/%u/%u_%s",
rnode.spcNode,
TABLESPACE_VERSION_DIRECTORY,
PGXCNodeName,
rnode.dbNode,
rnode.relNode,
forkNames[forknum]);
else
(void)snprintf(path,
pathlen,
"pg_tblspc/%u/%s_%s/%u/%u",
rnode.spcNode,
TABLESPACE_VERSION_DIRECTORY,
PGXCNodeName,
rnode.dbNode,
rnode.relNode);
#else
if (forknum != MAIN_FORKNUM)
(void)snprintf(path,
pathlen,
"pg_tblspc/%u/%s/%u/%u_%s",
rnode.spcNode,
TABLESPACE_VERSION_DIRECTORY,
rnode.dbNode,
rnode.relNode,
forkNames[forknum]);
else
(void)snprintf(path,
pathlen,
"pg_tblspc/%u/%s/%u/%u",
rnode.spcNode,
TABLESPACE_VERSION_DIRECTORY,
rnode.dbNode,
rnode.relNode);
#endif
} else {
/* OIDCHARS will suffice for an integer, too */
pathlen = 9 + 1 + OIDCHARS + 1 + strlen(TABLESPACE_VERSION_DIRECTORY) + 1 + OIDCHARS + 2
#ifdef PGXC
+ strlen(PGXCNodeName) + 1
#endif
+ OIDCHARS + 1 + OIDCHARS + 1 + FORKNAMECHARS + 1;
path = (char*)malloc(pathlen);
#ifdef PGXC
if (forknum != MAIN_FORKNUM)
(void)snprintf(path,
pathlen,
"pg_tblspc/%u/%s_%s/%u/t%d_%u_%s",
rnode.spcNode,
TABLESPACE_VERSION_DIRECTORY,
PGXCNodeName,
rnode.dbNode,
backend,
rnode.relNode,
forkNames[forknum]);
else
(void)snprintf(path,
pathlen,
"pg_tblspc/%u/%s_%s/%u/t%d_%u",
rnode.spcNode,
TABLESPACE_VERSION_DIRECTORY,
PGXCNodeName,
rnode.dbNode,
backend,
rnode.relNode);
#else
if (forknum != MAIN_FORKNUM)
(void)snprintf(path,
pathlen,
"pg_tblspc/%u/%s/%u/t%d_%u_%s",
rnode.spcNode,
TABLESPACE_VERSION_DIRECTORY,
rnode.dbNode,
backend,
rnode.relNode,
forkNames[forknum]);
else
(void)snprintf(path,
pathlen,
"pg_tblspc/%u/%s/%u/t%d_%u",
rnode.spcNode,
TABLESPACE_VERSION_DIRECTORY,
rnode.dbNode,
backend,
rnode.relNode);
#endif
}
}
}
return path;
}