215 lines
7.3 KiB
C++
215 lines
7.3 KiB
C++
/*
|
|
* tablespace.c
|
|
*
|
|
* tablespace functions
|
|
*
|
|
* Copyright (c) 2010-2012, PostgreSQL Global Development Group
|
|
* contrib/pg_upgrade/tablespace.c
|
|
*/
|
|
|
|
#include "postgres.h"
|
|
#include "knl/knl_variable.h"
|
|
|
|
#include "pg_upgrade.h"
|
|
#include "catalog/pg_tablespace.h"
|
|
|
|
static void get_tablespace_paths(void);
|
|
static void set_tablespace_directory_suffix(ClusterInfo* cluster);
|
|
bool is_column_exists(PGconn* conn, Oid relid, char* column_name);
|
|
|
|
void init_tablespaces(void)
|
|
{
|
|
int nRet = 0;
|
|
|
|
get_tablespace_paths();
|
|
|
|
set_tablespace_directory_suffix(&old_cluster);
|
|
set_tablespace_directory_suffix(&new_cluster);
|
|
|
|
if (user_opts.inplace_upgrade) {
|
|
char* new_tablespace_suffix = NULL;
|
|
|
|
new_tablespace_suffix =
|
|
(char*)pg_malloc(strlen(old_cluster.tablespace_suffix) + strlen("full_upgrade_bak") + 10);
|
|
|
|
nRet = snprintf_s(new_tablespace_suffix,
|
|
strlen(old_cluster.tablespace_suffix) + strlen("full_upgrade_bak") + 10,
|
|
strlen(old_cluster.tablespace_suffix) + strlen("full_upgrade_bak") + 9,
|
|
"/full_upgrade_bak%s",
|
|
old_cluster.tablespace_suffix);
|
|
securec_check_ss_c(nRet, "\0", "\0");
|
|
free(old_cluster.tablespace_suffix);
|
|
old_cluster.tablespace_suffix = new_tablespace_suffix;
|
|
}
|
|
|
|
if (os_info.num_tablespaces > 0 && strcmp(old_cluster.tablespace_suffix, new_cluster.tablespace_suffix) == 0)
|
|
pg_log(PG_FATAL,
|
|
"Cannot upgrade to/from the same system catalog version when\n"
|
|
"using tablespaces.\n");
|
|
}
|
|
|
|
/*
|
|
* get_tablespace_paths()
|
|
*
|
|
* Scans pg_tablespace and returns a malloc'ed array of all tablespace
|
|
* paths. Its the caller's responsibility to free the array.
|
|
*/
|
|
static void get_tablespace_paths(void)
|
|
{
|
|
PGconn* conn = connectToServer(&old_cluster, "template1");
|
|
PGresult* res = NULL;
|
|
int tblnum;
|
|
int i_spclocation;
|
|
int i_relative;
|
|
char* relative = NULL;
|
|
char* spclocation = NULL;
|
|
char query[QUERY_ALLOC];
|
|
bool is_exists = false;
|
|
char* tblpath = NULL;
|
|
int nRet = 0;
|
|
errno_t rc = 0;
|
|
int len = 0;
|
|
|
|
is_exists = is_column_exists(conn, TableSpaceRelationId, "relative");
|
|
|
|
nRet = snprintf_s(query,
|
|
sizeof(query),
|
|
sizeof(query) - 1,
|
|
"SELECT %s%s "
|
|
"FROM pg_catalog.pg_tablespace "
|
|
"WHERE spcname != 'pg_default' AND "
|
|
" spcname != 'pg_global'",
|
|
/* 9.2 removed the spclocation column */
|
|
(GET_MAJOR_VERSION(old_cluster.major_version) <= 901) ? "spclocation"
|
|
: "pg_catalog.pg_tablespace_location(oid) AS spclocation",
|
|
is_exists ? ", relative" : "");
|
|
securec_check_ss_c(nRet, "\0", "\0");
|
|
|
|
res = executeQueryOrDie(conn, "%s", query);
|
|
|
|
if ((os_info.num_tablespaces = PQntuples(res)) != 0) {
|
|
os_info.tablespaces = (char**)pg_malloc(os_info.num_tablespaces * sizeof(char*));
|
|
os_info.slavetablespaces = (char**)pg_malloc(os_info.num_tablespaces * sizeof(char*));
|
|
} else {
|
|
os_info.tablespaces = NULL;
|
|
os_info.slavetablespaces = NULL;
|
|
}
|
|
i_spclocation = PQfnumber(res, "spclocation");
|
|
if (is_exists)
|
|
i_relative = PQfnumber(res, "relative");
|
|
|
|
for (tblnum = 0; tblnum < os_info.num_tablespaces; tblnum++) {
|
|
spclocation = PQgetvalue(res, tblnum, i_spclocation);
|
|
if (is_exists) {
|
|
relative = PQgetvalue(res, tblnum, i_relative);
|
|
if (relative && *relative == 't') {
|
|
len = strlen(old_cluster.pgdata) + strlen("pg_location") + strlen(spclocation) + 3;
|
|
tblpath = (char*)pg_malloc(len);
|
|
rc = memset_s(tblpath, len, 0, len);
|
|
securec_check_c(rc, "\0", "\0");
|
|
nRet = snprintf_s(tblpath, len, len - 1, "%s/pg_location/%s", old_cluster.pgdata, spclocation);
|
|
securec_check_ss_c(nRet, "\0", "\0");
|
|
os_info.tablespaces[tblnum] = pg_strdup(tblpath);
|
|
free(tblpath);
|
|
|
|
len = MAXPGPATH + strlen("pg_location") + strlen(spclocation) + 3;
|
|
tblpath = (char*)pg_malloc(len);
|
|
rc = memset_s(tblpath, len, 0, len);
|
|
securec_check_c(rc, "\0", "\0");
|
|
nRet = snprintf_s(tblpath, len, len - 1, "%s/pg_location/%s", user_opts.pgHAdata, spclocation);
|
|
securec_check_ss_c(nRet, "\0", "\0");
|
|
os_info.slavetablespaces[tblnum] = pg_strdup(tblpath);
|
|
free(tblpath);
|
|
} else {
|
|
os_info.tablespaces[tblnum] = pg_strdup(spclocation);
|
|
os_info.slavetablespaces[tblnum] = pg_strdup(spclocation);
|
|
}
|
|
} else {
|
|
os_info.tablespaces[tblnum] = pg_strdup(spclocation);
|
|
os_info.slavetablespaces[tblnum] = pg_strdup(spclocation);
|
|
}
|
|
}
|
|
|
|
PQclear(res);
|
|
|
|
PQfinish(conn);
|
|
|
|
return;
|
|
}
|
|
|
|
void update_permissions_for_tablspace_dir(void)
|
|
{
|
|
int i;
|
|
for (i = 0; i < os_info.num_tablespaces; i++) {
|
|
exec_prog(UTILITY_LOG_FILE,
|
|
NULL,
|
|
true,
|
|
"chown -R --reference=\"%s/global/pg_control\" \"%supgrd/%s\"",
|
|
new_cluster.pgdata,
|
|
os_info.tablespaces[i],
|
|
new_cluster.tablespace_suffix);
|
|
}
|
|
}
|
|
|
|
void create_tablspace_directories(void)
|
|
{
|
|
int i;
|
|
char temp_path[MAXPGPATH];
|
|
struct passwd* pwd;
|
|
int nRet = 0;
|
|
|
|
set_tablespace_directory_suffix(&new_cluster);
|
|
|
|
if ((os_info.num_tablespaces <= 0) || !(os_info.is_root_user)) {
|
|
return;
|
|
}
|
|
|
|
pwd = getpwnam(new_cluster.user);
|
|
if (pwd == NULL) {
|
|
pg_log(PG_WARNING, "Not able to set permission for tablespaces: %s\n", getErrorText(errno));
|
|
return;
|
|
}
|
|
|
|
for (i = 0; i < os_info.num_tablespaces; i++) {
|
|
nRet = snprintf_s(temp_path, MAXPGPATH, MAXPGPATH - 1, "%supgrd", os_info.tablespaces[i]);
|
|
securec_check_ss_c(nRet, "\0", "\0");
|
|
if (mkdir(temp_path, S_IRWXU) < 0) {
|
|
if (errno != EEXIST) {
|
|
pg_log(PG_WARNING, "Not able to create tablespaces directory: %s\n", getErrorText(errno));
|
|
continue;
|
|
}
|
|
}
|
|
|
|
if (chown(temp_path, pwd->pw_uid, pwd->pw_gid) < 0) {
|
|
pg_log(PG_WARNING, "Not able to change permission to tablespaces directory: %s\n", getErrorText(errno));
|
|
}
|
|
}
|
|
}
|
|
|
|
static void set_tablespace_directory_suffix(ClusterInfo* cluster)
|
|
{
|
|
char instancename[NAMEDATALEN + 1] = {0};
|
|
int nRet = 0;
|
|
|
|
if (GET_MAJOR_VERSION(cluster->major_version) <= 804)
|
|
cluster->tablespace_suffix = pg_strdup("");
|
|
else {
|
|
/* This cluster has a version-specific subdirectory */
|
|
cluster->tablespace_suffix =
|
|
(char*)pg_malloc(4 + strlen(cluster->major_version_str) + NAMEDATALEN + 10 /* OIDCHARS */ + 1);
|
|
if (0 == get_local_instancename_by_dbpath(cluster->pgdata, ((char*)instancename) + 1)) {
|
|
instancename[0] = '_';
|
|
}
|
|
|
|
/* The leading slash is needed to start a new directory. */
|
|
nRet = snprintf_s(cluster->tablespace_suffix,
|
|
strlen(cluster->major_version_str) + NAMEDATALEN + 15,
|
|
strlen(cluster->major_version_str) + NAMEDATALEN + 14,
|
|
"/PG_%s_%d%s",
|
|
cluster->major_version_str,
|
|
cluster->controldata.cat_ver,
|
|
instancename);
|
|
securec_check_ss_c(nRet, "\0", "\0");
|
|
}
|
|
}
|