This commit is contained in:
luozihao 2020-08-27 17:32:22 +08:00
commit 32119f19b0
33 changed files with 3266 additions and 347 deletions

View File

@ -398,6 +398,7 @@ function target_file_copy()
sed -i '/gs_lcctl/d' binfile
sed -i '/gs_wsr/d' binfile
sed -i '/gs_gucZenith/d' binfile
sed -i '/gs_expansion/d' binfile
bin_script=$(cat binfile)
rm binfile script_file
cd $BUILD_DIR

View File

@ -19,7 +19,7 @@
/*
* We have to use postgres.h not postgres_fe.h here, because there's so much
* backend-only stuff in the XLOG include files we need. But we need a
* frontend-ish environment otherwise. Hence this ugly hack.
* frontend-ish environment otherwise. Hence this ugly hack.
*/
#include "postgres.h"
#include "knl/knl_variable.h"
@ -31,13 +31,10 @@
#include <sys/types.h>
#include <sys/wait.h>
#ifdef HAVE_LIBZ
#include "zlib.h"
#endif
#include "getopt_long.h"
#include "receivelog.h"
#include "streamutil.h"
#include "gs_tar_const.h"
#include "bin/elog.h"
#include "lib/string.h"
@ -55,7 +52,6 @@ typedef struct TablespaceList {
/* Global options */
char* basedir = NULL;
static TablespaceList tablespacee_dirs = {NULL, NULL};
static const int BLOCK_SIZE = 2560; /* gs_tar block size */
char* g_xlogOption = NULL;
char format = 'p'; /* p(lain)/t(ar) */
char* label = "gs_basebackup base backup";
@ -66,17 +62,6 @@ bool includewal = false;
bool streamwal = false;
bool fastcheckpoint = false;
/* fileStream result */
static const int READ_ERROR = -2;
/* gs_tar offset */
static const int LEN_LEFT = 1048;
static const int FILE_PADDING = 511; /* All files are padded up to 512 bytes */
static const int FILE_TYPE = 1080;
/* file type */
static const char TYPE_DICTORY = '5';
extern char** tblspaceDirectory;
extern int tblspaceCount;
extern int tblspaceIndex;
@ -122,21 +107,8 @@ static int GsTar(int argc, char** argv);
static int GsBaseBackup(int argc, char** argv);
static const char* get_tablespace_mapping(const char* dir);
extern void FetchMotCheckpoint(const char* basedir, PGconn* fetchConn, const char* progname, bool verbose);
#ifdef HAVE_LIBZ
static const char* get_gz_error(gzFile gzf)
{
int errnum;
const char* errmsg = NULL;
errmsg = gzerror(gzf, &errnum);
if (errnum == Z_ERRNO)
return strerror(errno);
else
return errmsg;
}
#endif
extern void FetchMotCheckpoint(const char* basedir, PGconn* fetchConn, const char* progname, bool verbose,
const char format = 'p', const int compresslevel = 0);
/*
* Split argument into old_dir and new_dir and append to tablespace mapping
@ -144,7 +116,7 @@ static const char* get_gz_error(gzFile gzf)
*/
static void tablespace_list_append(const char* arg)
{
TablespaceListCell* cell = (TablespaceListCell*)malloc(sizeof(TablespaceListCell));
TablespaceListCell* cell = (TablespaceListCell*)xmalloc0(sizeof(TablespaceListCell));
char* dst = NULL;
char* dst_ptr = NULL;
const char* arg_ptr = NULL;
@ -601,32 +573,6 @@ static void progress_report(int tablespacenum, const char* filename)
fprintf(stderr, "\r");
}
#ifdef HAVE_LIBZ
static gzFile openGzFile(const char* filename)
{
gzFile ztarfile = gzopen(filename, "wb");
if (gzsetparams(ztarfile, compresslevel, Z_DEFAULT_STRATEGY) != Z_OK) {
fprintf(
stderr, _("%s: could not set compression level %d: %s\n"), progname, compresslevel, get_gz_error(ztarfile));
disconnect_and_exit(1);
}
return ztarfile;
}
static void writeGzFile(gzFile ztarfile, char* copybuf, int buf_size, char* filename)
{
if (gzwrite(ztarfile, copybuf, buf_size) != buf_size) {
fprintf(stderr,
_("%s: could not write to compressed file \"%s\": %s\n"),
progname,
filename,
get_gz_error(ztarfile));
disconnect_and_exit(1);
}
}
#endif
/*
* Receive a tar format file from the connection to the server, and write
* the data from this file directly into a tar file. If compression is
@ -687,7 +633,15 @@ static void ReceiveTarFile(PGconn* conn, PGresult* res, int rownum)
if (compresslevel != 0) {
errorno = snprintf_s(filename, sizeof(filename), sizeof(filename) - 1, "%s/base.tar.gz", basedir);
securec_check_ss_c(errorno, "", "");
ztarfile = openGzFile(filename);
ztarfile = openGzFile(filename, compresslevel);
if (ztarfile == NULL) {
fprintf(stderr,
_("%s: could not set compression level %d: %s\n"),
progname,
compresslevel,
get_gz_error(ztarfile));
disconnect_and_exit(1);
}
} else
#endif
{
@ -706,7 +660,7 @@ static void ReceiveTarFile(PGconn* conn, PGresult* res, int rownum)
errorno = snprintf_s(
filename, sizeof(filename), sizeof(filename) - 1, "%s/%s.tar.gz", basedir, PQgetvalue(res, rownum, 0));
securec_check_ss_c(errorno, "", "");
ztarfile = openGzFile(filename);
ztarfile = openGzFile(filename, compresslevel);
} else
#endif
{
@ -760,30 +714,6 @@ static void ReceiveTarFile(PGconn* conn, PGresult* res, int rownum)
int r = PQgetCopyData(conn, &copybuf, 0);
if (r == -1) {
/*
* End of chunk. Close file (but not stdout).
*
* Also, write two completely empty blocks at the end of the tar
* file, as required by some tar programs.
*/
char zerobuf[1024];
errorno = memset_s(zerobuf, sizeof(zerobuf), 0, sizeof(zerobuf));
securec_check_c(errorno, "", "");
#ifdef HAVE_LIBZ
if (ztarfile != NULL) {
writeGzFile(ztarfile, zerobuf, sizeof(zerobuf), filename);
} else
#endif
{
if (fwrite(zerobuf, sizeof(zerobuf), 1, tarfile) != 1) {
fprintf(stderr, _("%s: could not write to file \"%s\": %s\n"), progname, filename, strerror(errno));
fclose(tarfile);
tarfile = NULL;
disconnect_and_exit(1);
}
}
#ifdef HAVE_LIBZ
if (ztarfile != NULL) {
if (gzclose(ztarfile) != 0) {
@ -807,7 +737,6 @@ static void ReceiveTarFile(PGconn* conn, PGresult* res, int rownum)
tarfile = NULL;
}
}
break;
} else if (r == -2) {
fprintf(stderr, _("%s: could not read COPY data: %s"), progname, PQerrorMessage(conn));
@ -816,7 +745,14 @@ static void ReceiveTarFile(PGconn* conn, PGresult* res, int rownum)
#ifdef HAVE_LIBZ
if (ztarfile != NULL) {
writeGzFile(ztarfile, copybuf, r, filename);
if (!writeGzFile(ztarfile, copybuf, r)) {
fprintf(stderr,
_("%s: could not write to compressed file \"%s\": %s\n"),
progname,
filename,
get_gz_error(ztarfile));
disconnect_and_exit(1);
}
} else
#endif
{
@ -960,7 +896,7 @@ static void ReceiveAndUnpackTarFile(PGconn* conn, PGresult* res, int rownum)
}
break;
} else if (r == READ_ERROR) {
} else if (r == TAR_READ_ERROR) {
fprintf(stderr, _("%s: could not read COPY data: %s"), progname, PQerrorMessage(conn));
disconnect_and_exit(1);
}
@ -972,13 +908,13 @@ static void ReceiveAndUnpackTarFile(PGconn* conn, PGresult* res, int rownum)
/*
* No current file, so this must be the header for a new file
*/
if (r != BLOCK_SIZE) {
if (r != TAR_BLOCK_SIZE) {
fprintf(stderr, _("%s: invalid tar block header size: %d\n"), progname, r);
disconnect_and_exit(1);
}
totaldone += BLOCK_SIZE;
totaldone += TAR_BLOCK_SIZE;
if (sscanf_s(copybuf + LEN_LEFT, "%201o", &current_len_left) != 1) {
if (sscanf_s(copybuf + TAR_LEN_LEFT, "%201o", &current_len_left) != 1) {
fprintf(stderr, _("%s: could not parse file size\n"), progname);
disconnect_and_exit(1);
}
@ -992,7 +928,7 @@ static void ReceiveAndUnpackTarFile(PGconn* conn, PGresult* res, int rownum)
/*
* All files are padded up to 512 bytes
*/
current_padding = ((current_len_left + FILE_PADDING) & ~FILE_PADDING) - current_len_left;
current_padding = ((current_len_left + TAR_FILE_PADDING) & ~TAR_FILE_PADDING) - current_len_left;
/*
* First part of header is zero terminated filename
@ -1010,7 +946,7 @@ static void ReceiveAndUnpackTarFile(PGconn* conn, PGresult* res, int rownum)
/*
* Ends in a slash means directory or symlink to directory
*/
if (copybuf[FILE_TYPE] == TYPE_DICTORY) {
if (copybuf[TAR_FILE_TYPE] == TAR_TYPE_DICTORY) {
/*
* Directory
*/
@ -1039,12 +975,12 @@ static void ReceiveAndUnpackTarFile(PGconn* conn, PGresult* res, int rownum)
filename,
strerror(errno));
#endif
} else if (copybuf[FILE_TYPE] == '2') {
} else if (copybuf[TAR_FILE_TYPE] == '2') {
/*
* Symbolic link
*/
filename[strlen(filename) - 1] = '\0'; /* Remove trailing slash */
mapped_tblspc_path = get_tablespace_mapping(&copybuf[FILE_TYPE + 1]);
mapped_tblspc_path = get_tablespace_mapping(&copybuf[TAR_FILE_TYPE + 1]);
if (symlink(mapped_tblspc_path, filename) != 0) {
if (IsXlogDir(filename)) {
fprintf(stderr,
@ -1072,7 +1008,7 @@ static void ReceiveAndUnpackTarFile(PGconn* conn, PGresult* res, int rownum)
sizeof(absolut_path) - 1,
"%s/%s",
basedir,
&copybuf[FILE_TYPE + 1]);
&copybuf[TAR_FILE_TYPE + 1]);
securec_check_ss_c(errorno, "\0", "\0");
if (symlink(absolut_path, filename) != 0) {
@ -1517,9 +1453,7 @@ static void BaseBackup(void)
exit(1);
}
ClearAndFreePasswd();
if (format == 'p') {
FetchMotCheckpoint(basedir, conn, progname, (bool)verbose);
}
FetchMotCheckpoint(basedir, conn, progname, (bool)verbose, format, compresslevel);
PQfinish(conn);
conn = NULL;
@ -1555,7 +1489,7 @@ static void remove_dw_file(const char* dw_file_name, const char* target_dir, cha
/* *
* * delete existing double write file if existed, recreate it and write one page of zero
* * @param target_dir data base root dir
* */
* */
static void backup_dw_file(const char* target_dir)
{
int rc;
@ -1708,12 +1642,12 @@ static int GsTar(int argc, char** argv)
copybuf = NULL;
}
current_len_left = current_len_left == 0 && current_padding == 0 ? BLOCK_SIZE : current_len_left;
current_len_left = current_len_left == 0 && current_padding == 0 ? TAR_BLOCK_SIZE : current_len_left;
if (current_len_left == 0 && current_padding != 0) {
copybuf = (char*)malloc(current_padding);
copybuf = (char*)xmalloc0(current_padding);
r = fread(copybuf, 1, current_padding, tarfile);
} else {
copybuf = (char*)malloc(current_len_left);
copybuf = (char*)xmalloc0(current_len_left);
r = fread(copybuf, 1, current_len_left, tarfile);
// end of file
if ((uint64)r < current_len_left) {
@ -1742,12 +1676,12 @@ static int GsTar(int argc, char** argv)
int filemode;
/* No current file, so this must be the header for a new file */
if (r != BLOCK_SIZE) {
if (r != TAR_BLOCK_SIZE) {
fprintf(stderr, "%s: invalid tar block header size: %d\n", progname, r);
fclose(tarfile);
return -1;
}
totaldone += BLOCK_SIZE;
totaldone += TAR_BLOCK_SIZE;
if (sscanf_s(copybuf + 1048, "%201o", &current_len_left) != 1) {
fprintf(stderr, "%s: could not parse file size\n", progname);
@ -1858,7 +1792,7 @@ static int GsTar(int argc, char** argv)
}
}
} else {
pg_log(PG_WARNING, "unrecognized link indicator \"%c\"\n", copybuf[FILE_TYPE]);
pg_log(PG_WARNING, "unrecognized link indicator \"%c\"\n", copybuf[TAR_FILE_TYPE]);
return -1;
}
continue; /* directory or link handled */
@ -1979,7 +1913,7 @@ static int GsBaseBackup(int argc, char** argv)
}
}
while ((c = getopt_long(argc, argv, "D:l:c:h:p:U:s:X:F:T:wWvPxz", long_options, &option_index)) != -1) {
while ((c = getopt_long(argc, argv, "D:l:c:h:p:U:s:X:F:T:Z:wWvPxz", long_options, &option_index)) != -1) {
switch (c) {
case 'D': {
GS_FREE(basedir);

View File

@ -127,7 +127,8 @@ static int replace_node_name(char* sSrc, const char* sMatchStr, const char* sRep
static void show_full_build_process(const char* errmg);
static void backup_dw_file(const char* target_dir);
static void get_xlog_location(char (&xlog_location)[MAXPGPATH]);
extern void FetchMotCheckpoint(const char* basedir, PGconn* fetchConn, const char* progname, bool verbose);
extern void FetchMotCheckpoint(const char* basedir, PGconn* fetchConn, const char* progname, bool verbose,
const char format = 'p', const int compresslevel = 0);
extern char* GetOptionValueFromFile(const char* fileName, const char* option);
/*

View File

@ -27,6 +27,8 @@
#include <stdlib.h>
#include <stdio.h>
#include "postgres_fe.h"
#include "gs_tar_const.h"
#include "streamutil.h"
#include "libpq/libpq-fe.h"
#include "utils/builtins.h"
#include "common/fe_memutils.h"
@ -40,6 +42,290 @@
static uint64 totaldone = 0;
static void CheckConnResult(PGconn* conn, const char* progname)
{
PGresult* res = PQgetResult(conn);
if (PQresultStatus(res) != PGRES_COPY_OUT) {
fprintf(stderr, "%s: could not get COPY data stream: %s", progname, PQerrorMessage(conn));
disconnect_and_exit(1);
}
PQclear(res);
}
static void MotReceiveAndAppendTarFile(
const char* basedir, const char* chkptName, PGconn* conn, const char* progname, int compresslevel)
{
CheckConnResult(conn, progname);
FILE* tarfile = NULL;
char filename[MAXPGPATH];
errno_t errorno = EOK;
char* copybuf = NULL;
FILE* file = NULL;
char current_path[MAXPGPATH];
int current_len_left = 0;
int current_padding = 0;
errorno = strncpy_s(current_path, sizeof(current_path), basedir, sizeof(current_path) - 1);
securec_check_c(errorno, "", "");
#ifdef HAVE_LIBZ
gzFile ztarfile = NULL;
int duplicatedfd = -1;
#endif
if (strcmp(basedir, "-") == 0) {
#ifdef HAVE_LIBZ
if (compresslevel != 0) {
duplicatedfd = dup(fileno(stdout));
if (duplicatedfd == -1) {
fprintf(stderr, _("%s: could not allocate dup fd by fileno(stdout): %s\n"), progname, strerror(errno));
disconnect_and_exit(1);
}
ztarfile = gzdopen(duplicatedfd, "ab");
if (gzsetparams(ztarfile, compresslevel, Z_DEFAULT_STRATEGY) != Z_OK) {
fprintf(stderr,
_("%s: could not set compression level %d: %s\n"),
progname,
compresslevel,
get_gz_error(ztarfile));
close(duplicatedfd);
duplicatedfd = -1;
disconnect_and_exit(1);
}
close(duplicatedfd);
duplicatedfd = -1;
} else
#endif
tarfile = stdout;
strcpy_s(filename, 1, "-");
} else {
#ifdef HAVE_LIBZ
if (compresslevel != 0) {
errorno = snprintf_s(filename, sizeof(filename), sizeof(filename) - 1, "%s/base.tar.gz", basedir);
securec_check_ss_c(errorno, "", "");
ztarfile = openGzFile(filename, compresslevel, "ab");
} else
#endif
{
errorno = snprintf_s(filename, sizeof(filename), sizeof(filename) - 1, "%s/base.tar", basedir);
// basdir has been realpath before
securec_check_ss_c(errorno, "", "");
tarfile = fopen(filename, "ab");
}
}
/* chkptName header */
copybuf = (char*)xmalloc0(TAR_BLOCK_SIZE);
int chkptDirLen = strlen(chkptName);
errorno = strcpy_s(copybuf + 2, chkptDirLen + 1, chkptName);
securec_check_ss_c(errorno, "", "");
copybuf[0] = '.';
copybuf[1] = '/';
copybuf[chkptDirLen + 2] = '/';
copybuf[TAR_FILE_TYPE] = TAR_TYPE_DICTORY;
for (int i = 0; i < 11; i++) {
copybuf[TAR_LEN_LEFT + i] = '0';
}
errorno = sprintf_s(&copybuf[TAR_FILE_MODE], TAR_BLOCK_SIZE - TAR_FILE_MODE, "%07o ", FILE_PERMISSION);
securec_check_ss_c(errorno, "", "");
#ifdef HAVE_LIBZ
if (ztarfile != NULL) {
if (!writeGzFile(ztarfile, copybuf, TAR_BLOCK_SIZE)) {
fprintf(stderr, _("%s: could not write to file \"%s\": %s\n"), progname, filename, strerror(errno));
disconnect_and_exit(1);
}
} else
#endif
{
if (fwrite(copybuf, TAR_BLOCK_SIZE, 1, tarfile) != 1) {
fprintf(stderr, _("%s: could not write to file \"%s\": %s\n"), progname, filename, strerror(errno));
disconnect_and_exit(1);
}
}
while (1) {
int r;
if (copybuf != NULL) {
PQfreemem(copybuf);
copybuf = NULL;
}
r = PQgetCopyData(conn, &copybuf, 0);
if (r == -1) {
#ifdef HAVE_LIBZ
if (ztarfile != NULL) {
if (gzclose(ztarfile) != 0) {
fprintf(stderr,
_("%s: could not close compressed file \"%s\": %s\n"),
progname,
filename,
get_gz_error(ztarfile));
disconnect_and_exit(1);
}
} else
#endif
{
if (strcmp(basedir, "-") != 0) {
if (fclose(tarfile) != 0) {
fprintf(
stderr, _("%s: could not close file \"%s\": %s\n"), progname, filename, strerror(errno));
tarfile = NULL;
disconnect_and_exit(1);
}
tarfile = NULL;
}
}
break;
} else if (r == TAR_READ_ERROR) {
fprintf(stderr, "%s: could not read COPY data: %s", progname, PQerrorMessage(conn));
disconnect_and_exit(1);
}
if (current_len_left == 0 && current_padding == 0) {
/* No current file, so this must be the header for a new file */
if (r != TAR_BLOCK_SIZE) {
fprintf(stderr, _("%s: invalid tar block header size: %d\n"), progname, r);
disconnect_and_exit(1);
}
/* new file */
int filemode;
totaldone += TAR_BLOCK_SIZE;
if (sscanf_s(copybuf + TAR_LEN_LEFT, "%201o", &current_len_left) != 1) {
fprintf(stderr, "%s: could not parse file size\n", progname);
disconnect_and_exit(1);
}
/* Set permissions on the file */
if (sscanf_s(&copybuf[TAR_FILE_MODE], "%07o ", (unsigned int*)&filemode) != 1) {
fprintf(stderr, "%s: could not parse file mode\n", progname);
disconnect_and_exit(1);
}
/*
* All files are padded up to 512 bytes
*/
current_padding = ((current_len_left + TAR_FILE_PADDING) & ~TAR_FILE_PADDING) - current_len_left;
/*
* First part of header is zero terminated filename.
* when getting a checkpoint, file name can be either
* the control file (written to base_dir), or a checkpoint
* file (written to base_dir/chkpt_)
*/
if (strstr(copybuf, "mot.ctrl")) {
errorno =
snprintf_s(filename, sizeof(filename), sizeof(filename) - 1, "%s/%s", current_path, "mot.ctrl");
securec_check_ss_c(errorno, "", "");
} else {
char* chkptOffset = strstr(copybuf, chkptName);
if (chkptOffset) {
errorno = snprintf_s(
filename, sizeof(filename), sizeof(filename) - 1, "%s/%s", current_path, chkptOffset);
securec_check_ss_c(errorno, "", "");
} else {
errorno =
snprintf_s(filename, sizeof(filename), sizeof(filename) - 1, "%s/%s", current_path, copybuf);
securec_check_ss_c(errorno, "", "");
}
}
if (filename[strlen(filename) - 1] == '/') {
filename[strlen(filename) - 1] = '\0'; /* Remove trailing slash */
strcpy_s(copybuf, strlen(filename), filename);
continue; /* directory or link handled */
}
#ifdef HAVE_LIBZ
if (ztarfile != NULL) {
if (!writeGzFile(ztarfile, copybuf, r)) {
fprintf(stderr, _("%s: could not write to file \"%s\": %s\n"), progname, filename, strerror(errno));
disconnect_and_exit(1);
}
} else
#endif
{
if (fwrite(copybuf, r, 1, tarfile) != 1) {
fprintf(stderr, _("%s: could not write to file \"%s\": %s\n"), progname, filename, strerror(errno));
disconnect_and_exit(1);
}
}
if (current_len_left == 0) {
continue;
}
} else {
/*
* Continuing blocks in existing file
*/
if (current_len_left == 0 && r == current_padding) {
#ifdef HAVE_LIBZ
if (ztarfile != NULL) {
if (!writeGzFile(ztarfile, copybuf, current_padding)) {
fprintf(
stderr, _("%s: could not write to file \"%s\": %s\n"), progname, filename, strerror(errno));
disconnect_and_exit(1);
}
} else
#endif
{
if (fwrite(copybuf, current_padding, 1, tarfile) != 1) {
fprintf(
stderr, _("%s: could not write to file \"%s\": %s\n"), progname, filename, strerror(errno));
disconnect_and_exit(1);
}
}
totaldone += r;
current_padding -= r;
continue;
}
totaldone += r;
#ifdef HAVE_LIBZ
if (ztarfile != NULL) {
if (!writeGzFile(ztarfile, copybuf, r)) {
fprintf(stderr, _("%s: could not write to file \"%s\": %s\n"), progname, filename, strerror(errno));
disconnect_and_exit(1);
}
} else
#endif
{
if (fwrite(copybuf, r, 1, tarfile) != 1) {
fprintf(stderr, _("%s: could not write to file \"%s\": %s\n"), progname, filename, strerror(errno));
disconnect_and_exit(1);
}
}
if (current_len_left == 0) {
continue;
}
current_len_left -= r;
if (current_len_left == 0 && current_padding == 0) {
/*
* Received the last block, and there is no padding to be
* expected. Close the file and move on to the next tar
* header.
*/
fclose(file);
file = NULL;
continue;
}
} /* continuing data in existing file */
} /* loop over all data blocks */
if (tarfile != NULL) {
fclose(tarfile);
tarfile = NULL;
}
if (copybuf != NULL) {
PQfreemem(copybuf);
copybuf = NULL;
}
return;
}
/*
* Receive a tar format stream from the connection to the server, and unpack
* the contents of it into a directory. Only files, directories and
@ -154,11 +440,8 @@ static void MotReceiveAndUnpackTarFile(const char* basedir, const char* chkptNam
*/
filename[strlen(filename) - 1] = '\0'; /* Remove trailing slash */
if (mkdir(filename, S_IRWXU) != 0) {
fprintf(stderr,
"%s: could not create directory \"%s\": %s\n",
progname,
filename,
strerror(errno));
fprintf(
stderr, "%s: could not create directory \"%s\": %s\n", progname, filename, strerror(errno));
disconnect_and_exit(1);
}
#ifndef WIN32
@ -272,7 +555,8 @@ static void MotReceiveAndUnpackTarFile(const char* basedir, const char* chkptNam
* @param controls verbose output
* @return Boolean value denoting success or failure.
*/
void FetchMotCheckpoint(const char* basedir, PGconn* fetchConn, const char* progname, bool verbose)
void FetchMotCheckpoint(
const char* basedir, PGconn* fetchConn, const char* progname, bool verbose, const char format, int compresslevel)
{
PGresult* res = NULL;
const char* fetchQuery = "FETCH_MOT_CHECKPOINT";
@ -333,17 +617,24 @@ void FetchMotCheckpoint(const char* basedir, PGconn* fetchConn, const char* prog
fprintf(stderr, "%s: mot checkpoint directory: %s\n", progname, dirName);
}
if (stat(dirName, &fileStat) < 0) {
if (pg_mkdir_p(dirName, S_IRWXU) == -1) {
fprintf(stderr, "%s: could not create directory \"%s\": %s\n", progname, dirName, strerror(errno));
if (format == 'p') {
if (stat(dirName, &fileStat) < 0) {
if (pg_mkdir_p(dirName, S_IRWXU) == -1) {
fprintf(stderr, "%s: could not create directory \"%s\": %s\n", progname, dirName, strerror(errno));
exit(1);
}
} else {
fprintf(stderr, "%s: directory \"%s\" already exists, please remove it and try again\n", progname,
dirName);
exit(1);
}
MotReceiveAndUnpackTarFile(basedir, chkptName, fetchConn, progname);
} else if (format == 't') {
MotReceiveAndAppendTarFile(basedir, chkptName, fetchConn, progname, compresslevel);
} else {
fprintf(stderr, "%s: directory \"%s\" already exists, please remove it and try again\n", progname, dirName);
fprintf(stderr, "%s: unsupport format type: \"%c\".\n", progname, format);
exit(1);
}
MotReceiveAndUnpackTarFile(basedir, chkptName, fetchConn, progname);
if (verbose) {
fprintf(stderr, "%s: finished fetching mot checkpoint\n", progname);
}

View File

@ -290,7 +290,8 @@ static char* get_string_by_sync_mode(bool syncmode);
static void free_ctl();
extern int GetLengthAndCheckReplConn(const char* ConnInfoList);
extern BuildErrorCode gs_increment_build(char* pgdata, const char* connstr, const uint32 term);
extern void FetchMotCheckpoint(const char* basedir, PGconn* fetchConn, const char* progname, bool verbose);
extern void FetchMotCheckpoint(const char* basedir, PGconn* fetchConn, const char* progname, bool verbose,
const char format = 'p', const int compresslevel = 0);
extern char* GetOptionValueFromFile(const char* fileName, const char* option);
void check_input_for_security(char* input_env_value)
@ -2268,7 +2269,7 @@ static void do_query(void)
}
static bool check_pid_exists(pgpid_t pid)
{
{
FILE* fp = NULL;
char buf[1024] = {0};
char command[128] = {0};

View File

@ -7272,6 +7272,10 @@
"pg_terminate_backend", 1,
AddBuiltinFunc(_0(2096), _1("pg_terminate_backend"), _2(1), _3(true), _4(false), _5(pg_terminate_backend), _6(16), _7(PG_CATALOG_NAMESPACE), _8(BOOTSTRAP_SUPERUSERID), _9(INTERNALlanguageId), _10(1), _11(0), _12(0), _13(0), _14('f'), _15(false), _16(false), _17('v'), _18(0), _19(1, 20), _20(NULL), _21(NULL), _22(NULL), _23(NULL), _24("pg_terminate_backend"), _25(NULL), _26(NULL), _27(NULL), _28(0), _29(false), _30(NULL), _31(false))
),
AddFuncGroup(
"pg_terminate_session", 1,
AddBuiltinFunc(_0(2099), _1("pg_terminate_session"), _2(2), _3(true), _4(false), _5(pg_terminate_session), _6(16), _7(PG_CATALOG_NAMESPACE), _8(BOOTSTRAP_SUPERUSERID), _9(INTERNALlanguageId), _10(1), _11(0), _12(0), _13(0), _14('f'), _15(false), _16(false), _17('v'), _18(0), _19(2, 20, 20), _20(NULL), _21(NULL), _22(NULL), _23(NULL), _24("pg_terminate_session"), _25(NULL), _26(NULL), _27(NULL), _28(0), _29(false), _30(NULL), _31(false))
),
AddFuncGroup(
"pg_test_err_contain_err", 1,
AddBuiltinFunc(_0(9999), _1("pg_test_err_contain_err"), _2(1), _3(true), _4(false), _5(pg_test_err_contain_err), _6(2278), _7(PG_CATALOG_NAMESPACE), _8(BOOTSTRAP_SUPERUSERID), _9(INTERNALlanguageId), _10(1), _11(0), _12(0), _13(0), _14('f'), _15(false), _16(false), _17('v'), _18(0), _19(1, 23), _20(NULL), _21(NULL), _22(NULL), _23(NULL), _24("pg_test_err_contain_err"), _25(NULL), _26(NULL), _27(NULL), _28(0), _29(false), _30(NULL), _31(false))

View File

@ -238,15 +238,9 @@ Datum signal_backend(PG_FUNCTION_ARGS)
PG_RETURN_BOOL(true);
}
/*
* Signal to terminate a backend process. This is allowed if you are superuser
* or have the same role as the process being terminated.
*/
Datum pg_terminate_backend(PG_FUNCTION_ARGS)
{
ThreadId tid = PG_GETARG_INT64(0);
int r = 0;
static int kill_backend(ThreadId tid)
{
/*
* It is forbidden to kill backend in the online expansion to protect
* the lock session from being interrupted by external applications.
@ -256,20 +250,49 @@ Datum pg_terminate_backend(PG_FUNCTION_ARGS)
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), (errmsg("kill backend is prohibited during online expansion."))));
}
r = pg_signal_backend(tid, SIGTERM);
int r = pg_signal_backend(tid, SIGTERM);
if (r == SIGNAL_BACKEND_NOPERMISSION) {
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
(errmsg("must be system admin or have the same role to terminate other backend"))));
}
if (t_thrd.proc && t_thrd.proc->workingVersionNum >= 92060) {
if (t_thrd.proc != NULL) {
uint64 query_id = get_query_id_beentry(tid);
(void)gs_close_all_stream_by_debug_id(query_id);
}
return r;
}
/*
* Signal to terminate a backend process. This is allowed if you are superuser
* or have the same role as the process being terminated.
*/
Datum pg_terminate_backend(PG_FUNCTION_ARGS)
{
ThreadId tid = PG_GETARG_INT64(0);
int r = kill_backend(tid);
PG_RETURN_BOOL(r == SIGNAL_BACKEND_SUCCESS);
}
Datum pg_terminate_session(PG_FUNCTION_ARGS)
{
ThreadId tid = PG_GETARG_INT64(0);
uint64 sid = PG_GETARG_INT64(1);
int r = 0;
if (tid == sid) {
r = kill_backend(tid);
} else {
ThreadPoolSessControl *sess_ctrl = g_threadPoolControler->GetSessionCtrl();
int ctrl_idx = sess_ctrl->FindCtrlIdxBySessId(sid);
r = sess_ctrl->SendSignal((int)ctrl_idx, SIGTERM);
}
PG_RETURN_BOOL(r == 0);
}
/*
* function name: pg_wlm_jump_queue
* description : wlm jump the queue with thread id.

View File

@ -215,6 +215,10 @@ static void gs_signal_send_mark(GsNode* local_node, GsSignalCheckType check_type
}
break;
}
case SIGNAL_CHECK_SESS_KEY: {
local_node->sig_data.check.session_id = t_thrd.sig_cxt.session_id;
break;
}
default: {
break;
}
@ -670,6 +674,14 @@ static bool gs_signal_handle_check(const GsSndSignal* local_node)
}
break;
}
case SIGNAL_CHECK_SESS_KEY: {
if (u_sess != NULL && local_node->check.session_id == u_sess->session_id) {
return true;
} else {
return false;
}
break;
}
default: {
break;
}

View File

@ -2090,7 +2090,8 @@ static void process_owned_by(const Relation seqrel, List* owned_by)
/* Must be a regular table */
if (tablerel->rd_rel->relkind != RELKIND_RELATION &&
!(tablerel->rd_rel->relkind == RELKIND_FOREIGN_TABLE && isMOTFromTblOid(RelationGetRelid(tablerel))))
!(tablerel->rd_rel->relkind == RELKIND_FOREIGN_TABLE && (isMOTFromTblOid(RelationGetRelid(tablerel)) ||
isPostgresFDWFromTblOid(RelationGetRelid(tablerel)))))
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("referenced relation \"%s\" is not a table", RelationGetRelationName(tablerel))));

View File

@ -9224,13 +9224,13 @@ static void ATAddForeignKeyConstraint(AlteredTableInfo* tab, Relation rel, Const
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("permission denied: \"%s\" is a system catalog", RelationGetRelationName(pkrel))));
#ifdef ENABLE_MULTIPLE_NODES
if (RELATION_IS_PARTITIONED(pkrel))
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("Invalid FOREIGN KEY constraints"),
errdetail("Partitioned table cannot be referenced table")));
#endif
/*
* References from permanent or unlogged tables to temp tables, and from
* permanent tables to unlogged tables, are disallowed because the

View File

@ -83,6 +83,8 @@ static void ConvertTriggerToFK(CreateTrigStmt* stmt, Oid funcoid);
static void SetTriggerFlags(TriggerDesc* trigdesc, const Trigger* trigger);
static HeapTuple GetTupleForTrigger(EState* estate, EPQState* epqstate, ResultRelInfo* relinfo, Oid targetPartitionOid,
int2 bucketid, ItemPointer tid, TupleTableSlot** newSlot);
static void ReleaseFakeRelation(Relation relation, Partition part, Relation* fakeRelation);
static bool TriggerEnabled(EState* estate, ResultRelInfo* relinfo, Trigger* trigger, TriggerEvent event,
const Bitmapset* modifiedCols, HeapTuple oldtup, HeapTuple newtup);
static HeapTuple ExecCallTriggerFunc(
@ -2624,12 +2626,7 @@ static HeapTuple GetTupleForTrigger(EState* estate, EPQState* epqstate, ResultRe
case HeapTupleSelfUpdated:
/* treat it as deleted; do not process */
ReleaseBuffer(buffer);
if (RELATION_IS_PARTITIONED(relation)) {
partitionClose(relation, part, NoLock);
}
if (RELATION_OWN_BUCKET(relation)) {
releaseDummyRelation(&fakeRelation);
}
ReleaseFakeRelation(relation, part, &fakeRelation);
return NULL;
case HeapTupleMayBeUpdated:
@ -2665,12 +2662,7 @@ static HeapTuple GetTupleForTrigger(EState* estate, EPQState* epqstate, ResultRe
* if tuple was deleted or PlanQual failed for updated tuple -
* we must not process this tuple!
*/
if (RELATION_IS_PARTITIONED(relation)) {
partitionClose(relation, part, NoLock);
}
if (RELATION_OWN_BUCKET(relation)) {
releaseDummyRelation(&fakeRelation);
}
ReleaseFakeRelation(relation, part, &fakeRelation);
return NULL;
default:
@ -2716,16 +2708,20 @@ static HeapTuple GetTupleForTrigger(EState* estate, EPQState* epqstate, ResultRe
result = heapCopyTuple(&tuple, RelationGetDescr(relation), BufferGetPage(buffer));
ReleaseBuffer(buffer);
if (RELATION_IS_PARTITIONED(relation)) {
partitionClose(relation, part, NoLock);
}
if (RELATION_OWN_BUCKET(relation)) {
releaseDummyRelation(&fakeRelation);
}
ReleaseFakeRelation(relation, part, &fakeRelation);
return result;
}
static void ReleaseFakeRelation(Relation relation, Partition part, Relation* fakeRelation){
if (RELATION_IS_PARTITIONED(relation)) {
partitionClose(relation, part, NoLock);
releaseDummyRelation(fakeRelation);
} else if (RELATION_OWN_BUCKET(relation)) {
releaseDummyRelation(fakeRelation);
}
}
/*
* Is trigger enabled to fire?
*/

View File

@ -216,6 +216,17 @@ int ThreadPoolSessControl::SendSignal(int ctrl_index, int signal)
}
knl_sess_control* ctrl = &m_base[ctrl_index - m_maxReserveSessionCount];
knl_session_context* sess = ctrl->sess;
/* check permission */
if (!superuser()) {
if (sess->proc_cxt.MyRoleId != GetUserId()) {
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
(errmsg("must be system admin or have the same role to terminate other backend"))));
}
}
volatile sig_atomic_t* plock = &ctrl->lock;
sig_atomic_t val;
do {
@ -223,13 +234,18 @@ int ThreadPoolSessControl::SendSignal(int ctrl_index, int signal)
/* perform an atomic compare and swap. */
val = __sync_val_compare_and_swap(plock, 0, 1);
if (val == 0) {
if (ctrl->sess != NULL) {
if (ctrl->sess->status == KNL_SESS_ATTACH) {
status = gs_signal_send(ctrl->sess->attachPid, signal);
} else if (ctrl->sess->status == KNL_SESS_DETACH) {
if (sess != NULL) {
if (sess->status == KNL_SESS_ATTACH) {
t_thrd.sig_cxt.gs_sigale_check_type = SIGNAL_CHECK_SESS_KEY;
t_thrd.sig_cxt.session_id = sess->session_id;
status = gs_signal_send(sess->attachPid, signal);
t_thrd.sig_cxt.gs_sigale_check_type = SIGNAL_CHECK_NONE;
t_thrd.sig_cxt.session_id = 0;
} else if (sess->status == KNL_SESS_DETACH) {
switch (signal) {
case SIGTERM:
ctrl->sess->status = KNL_SESS_CLOSE;
sess->status = KNL_SESS_CLOSE;
CloseClientSocket(sess, false);
status = 0;
break;
default:
@ -504,3 +520,15 @@ knl_session_context* ThreadPoolSessControl::GetSessionByIdx(int idx)
return NULL;
}
}
int ThreadPoolSessControl::FindCtrlIdxBySessId(uint64 id)
{
int cidx = 0;
for (cidx = 0; cidx < m_maxActiveSessionCount; cidx++) {
if (m_base[cidx].sess != NULL && m_base[cidx].sess->session_id == id) {
break;
}
}
return cidx + m_maxReserveSessionCount;
}

View File

@ -485,7 +485,7 @@ IndexOnlyScanFusion::IndexOnlyScanFusion(IndexOnlyScan* node, PlannedStmt* plans
m_keyInit = false;
m_keyNum = list_length(node->indexqual);
;
m_scanKeys = (ScanKey)palloc0(m_keyNum * sizeof(ScanKeyData));
/* init params */

View File

@ -94,7 +94,12 @@ typedef enum {
} RecoveryTargetType;
/* WAL levels */
typedef enum WalLevel { WAL_LEVEL_MINIMAL = 0, WAL_LEVEL_ARCHIVE, WAL_LEVEL_HOT_STANDBY, WAL_LEVEL_LOGICAL } WalLevel;
typedef enum WalLevel {
WAL_LEVEL_MINIMAL = 0,
WAL_LEVEL_ARCHIVE,
WAL_LEVEL_HOT_STANDBY,
WAL_LEVEL_LOGICAL
} WalLevel;
#define XLogArchivingActive() \
(u_sess->attr.attr_common.XLogArchiveMode && g_instance.attr.attr_storage.wal_level >= WAL_LEVEL_ARCHIVE)

View File

@ -0,0 +1,76 @@
/*
* Copyright (c) 2020 Huawei Technologies Co.,Ltd.
*
* openGauss is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
*
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
* ---------------------------------------------------------------------------------------
*
*
*
* IDENTIFICATION
* src/include/gs_tar_const.h
*
* ---------------------------------------------------------------------------------------
*/
#ifndef GS_TAR_CONST_H_
#define GS_TAR_CONST_H_
#ifdef HAVE_LIBZ
#include "zlib.h"
#endif
/* gs_tar offset */
static const int TAR_LEN_LEFT = 1048;
static const int TAR_FILE_PADDING = 511; /* All files are padded up to 512 bytes */
static const int TAR_FILE_TYPE = 1080; /* file type */
static const int TAR_BLOCK_SIZE = 2560; /* gs_tar block size */
static const int TAR_FILE_MODE = 1024;
/* fileStream result */
static const int TAR_READ_ERROR = -2;
/* file type */
static const char TAR_TYPE_DICTORY = '5';
static const int FILE_PERMISSION = 16832;
#ifdef HAVE_LIBZ
static const char* get_gz_error(gzFile gzf)
{
int errnum;
const char* errmsg = NULL;
errmsg = gzerror(gzf, &errnum);
if (errnum == Z_ERRNO)
return strerror(errno);
else
return errmsg;
}
static gzFile openGzFile(const char* filename, int compresslevel, const char* mode = "wb")
{
gzFile ztarfile = gzopen(filename, mode);
if (gzsetparams(ztarfile, compresslevel, Z_DEFAULT_STRATEGY) != Z_OK) {
return NULL;
}
return ztarfile;
}
static bool writeGzFile(gzFile ztarfile, char* copybuf, int buf_size)
{
if (gzwrite(ztarfile, copybuf, buf_size) != buf_size) {
return false;
}
return true;
}
#endif
#endif /* GS_TAR_CONST_H_ */

View File

@ -38,13 +38,15 @@ typedef void (*gs_sigfunc)(int);
typedef enum GsSignalCheckType {
SIGNAL_CHECK_NONE,
SIGNAL_CHECK_EXECUTOR_STOP,
SIGNAL_CHECK_STREAM_STOP
SIGNAL_CHECK_STREAM_STOP,
SIGNAL_CHECK_SESS_KEY
} GsSignalCheckType;
/* the struct of signal check */
typedef struct GsSignalCheck {
GsSignalCheckType check_type;
uint64 debug_query_id;
uint64 session_id;
} GsSignalCheck;
/* the struct of signal to be handled and the signal sender's thread id */

View File

@ -1929,6 +1929,7 @@ typedef struct knl_t_libwalreceiver_context {
typedef struct knl_t_sig_context {
unsigned long signal_handle_cnt;
GsSignalCheckType gs_sigale_check_type;
uint64 session_id;
} knl_t_sig_context;
typedef struct knl_t_slot_context {

View File

@ -76,6 +76,7 @@ public:
void HandlePoolerReload();
SessionMemoryDetail* getSessionMemoryDetail(uint32* num);
knl_session_context* GetSessionByIdx(int idx);
int FindCtrlIdxBySessId(uint64 id);
inline int GetActiveSessionCount()
{

View File

@ -580,6 +580,7 @@ extern Datum pg_cancel_invalid_query(PG_FUNCTION_ARGS);
extern Datum report_fatal(PG_FUNCTION_ARGS);
extern Datum signal_backend(PG_FUNCTION_ARGS);
extern Datum pg_terminate_backend(PG_FUNCTION_ARGS);
extern Datum pg_terminate_session(PG_FUNCTION_ARGS);
extern Datum pg_reload_conf(PG_FUNCTION_ARGS);
extern Datum pg_tablespace_databases(PG_FUNCTION_ARGS);
extern Datum pg_tablespace_location(PG_FUNCTION_ARGS);

View File

@ -0,0 +1,245 @@
#!/usr/bin/env python3
# -*- coding:utf-8 -*-
#############################################################################
# Copyright (c) 2020 Huawei Technologies Co.,Ltd.
#
# openGauss is licensed under Mulan PSL v2.
# You can use this software according to the terms
# and conditions of the Mulan PSL v2.
# You may obtain a copy of Mulan PSL v2 at:
#
# http://license.coscl.org.cn/MulanPSL2
#
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS,
# WITHOUT WARRANTIES OF ANY KIND,
# EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
# MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
# See the Mulan PSL v2 for more details.
# ----------------------------------------------------------------------------
# Description : gs_expansion is a utility to expansion standby node databases
#############################################################################
import os
import pwd
import sys
import threading
import uuid
import subprocess
import weakref
sys.path.append(sys.path[0])
from gspylib.common.DbClusterInfo import dbClusterInfo, \
readOneClusterConfigItem, initParserXMLFile, dbNodeInfo, checkPathVaild
from gspylib.common.GaussLog import GaussLog
from gspylib.common.Common import DefaultValue
from gspylib.common.ErrorCode import ErrorCode
from gspylib.common.ParallelBaseOM import ParallelBaseOM
from gspylib.common.ParameterParsecheck import Parameter
from impl.preinstall.OLAP.PreinstallImplOLAP import PreinstallImplOLAP
from gspylib.threads.SshTool import SshTool
from impl.expansion.ExpansionImpl import ExpansionImpl
ENV_LIST = ["MPPDB_ENV_SEPARATE_PATH", "GPHOME", "PATH",
"LD_LIBRARY_PATH", "PYTHONPATH", "GAUSS_WARNING_TYPE",
"GAUSSHOME", "PATH", "LD_LIBRARY_PATH",
"S3_CLIENT_CRT_FILE", "GAUSS_VERSION", "PGHOST",
"GS_CLUSTER_NAME", "GAUSSLOG", "GAUSS_ENV", "umask"]
class Expansion(ParallelBaseOM):
"""
"""
def __init__(self):
"""
"""
ParallelBaseOM.__init__(self)
# new added standby node backip list
self.newHostList = []
self.clusterInfoDict = {}
self.backIpNameMap = {}
self.packagepath = os.path.realpath(
os.path.join(os.path.realpath(__file__), "../../"))
self.standbyLocalMode = False
def usage(self):
"""
gs_expansion is a utility to expansion standby node for a cluster.
Usage:
gs_expansion -? | --help
gs_expansion -V | --version
gs_expansion -U USER -G GROUP -X XMLFILE -h nodeList [-L]
General options:
-U Cluster user.
-G Group of the cluster user.
-X Path of the XML configuration file.
-h New standby node node backip list.
Separate multiple nodes with commas (,).
such as '-h 192.168.0.1,192.168.0.2'
-L The standby database installed with
local mode.
-?, --help Show help information for this
utility, and exit the command line mode.
-V, --version Show version information.
"""
print(self.usage.__doc__)
def parseCommandLine(self):
"""
parse parameter from command line
"""
ParaObj = Parameter()
ParaDict = ParaObj.ParameterCommandLine("expansion")
# parameter -h or -?
if (ParaDict.__contains__("helpFlag")):
self.usage()
sys.exit(0)
# Resolves command line arguments
# parameter -U
if (ParaDict.__contains__("user")):
self.user = ParaDict.get("user")
DefaultValue.checkPathVaild(self.user)
# parameter -G
if (ParaDict.__contains__("group")):
self.group = ParaDict.get("group")
# parameter -X
if (ParaDict.__contains__("confFile")):
self.xmlFile = ParaDict.get("confFile")
# parameter -L
if (ParaDict.__contains__("localMode")):
self.localMode = ParaDict.get("localMode")
self.standbyLocalMode = ParaDict.get("localMode")
# parameter -l
if (ParaDict.__contains__("logFile")):
self.logFile = ParaDict.get("logFile")
#parameter -h
if (ParaDict.__contains__("nodename")):
self.newHostList = ParaDict.get("nodename")
def checkParameters(self):
"""
function: Check parameter from command line
input: NA
output: NA
"""
# check user | group | xmlfile | node
if len(self.user) == 0:
GaussLog.exitWithError(ErrorCode.GAUSS_357["GAUSS_35701"] % "-U")
if len(self.group) == 0:
GaussLog.exitWithError(ErrorCode.GAUSS_357["GAUSS_35701"] % "-G")
if len(self.xmlFile) == 0:
GaussLog.exitWithError(ErrorCode.GAUSS_357["GAUSS_35701"] % "-X")
if len(self.newHostList) == 0:
GaussLog.exitWithError(ErrorCode.GAUSS_357["GAUSS_35701"] % "-h")
clusterInfo = ExpansipnClusterInfo()
hostNameIpDict = clusterInfo.initFromXml(self.xmlFile)
clusterDict = clusterInfo.getClusterDirectorys()
backIpList = clusterInfo.getClusterBackIps()
nodeNameList = clusterInfo.getClusterNodeNames()
self.nodeNameList = nodeNameList
self.backIpNameMap = {}
for backip in backIpList:
self.backIpNameMap[backip] = clusterInfo.getNodeNameByBackIp(backip)
# check parameter node must in xml config file
for nodeid in self.newHostList:
if nodeid not in backIpList:
GaussLog.exitWithError(ErrorCode.GAUSS_357["GAUSS_35702"] % \
nodeid)
# get corepath and toolpath from xml file
corePath = clusterInfo.readClustercorePath(self.xmlFile)
toolPath = clusterInfo.getToolPath(self.xmlFile)
# parse xml file and cache node info
clusterInfoDict = {}
clusterInfoDict["appPath"] = clusterDict["appPath"][0]
clusterInfoDict["logPath"] = clusterDict["logPath"][0]
clusterInfoDict["corePath"] = corePath
clusterInfoDict["toolPath"] = toolPath
for nodeName in nodeNameList:
hostInfo = hostNameIpDict[nodeName]
ipList = hostInfo[0]
portList = hostInfo[1]
backIp = ""
sshIp = ""
if len(ipList) == 1:
backIp = sshIp = ipList[0]
elif len(ipList) == 2:
backIp = ipList[0]
sshIp = ipList[1]
port = portList[0]
cluster = clusterDict[nodeName]
dataNode = cluster[2]
clusterInfoDict[nodeName] = {
"backIp": backIp,
"sshIp": sshIp,
"port": port,
"localport": int(port) + 1,
"localservice": int(port) + 4,
"heartBeatPort": int(port) + 3,
"dataNode": dataNode,
"instanceType": -1
}
nodeIdList = clusterInfo.getClusterNodeIds()
for id in nodeIdList:
insType = clusterInfo.getdataNodeInstanceType(id)
hostName = clusterInfo.getHostNameByNodeId(id)
clusterInfoDict[hostName]["instanceType"] = insType
self.clusterInfoDict = clusterInfoDict
def initLogs(self):
"""
init log file
"""
# if no log file
if (self.logFile == ""):
self.logFile = DefaultValue.getOMLogPath(
DefaultValue.EXPANSION_LOG_FILE, self.user, "",
self.xmlFile)
# if not absolute path
if (not os.path.isabs(self.logFile)):
GaussLog.exitWithError(ErrorCode.GAUSS_502["GAUSS_50213"] % "log")
self.initLogger("gs_expansion")
self.logger.ignoreErr = True
class ExpansipnClusterInfo(dbClusterInfo):
def __init__(self):
dbClusterInfo.__init__(self)
def getToolPath(self, xmlFile):
"""
function : Read tool path from default xml file
input : String
output : String
"""
self.setDefaultXmlFile(xmlFile)
# read gaussdb tool path from xml file
(retStatus, retValue) = readOneClusterConfigItem(
initParserXMLFile(xmlFile), "gaussdbToolPath", "cluster")
if retStatus != 0:
raise Exception(ErrorCode.GAUSS_512["GAUSS_51200"]
% "gaussdbToolPath" + " Error: \n%s" % retValue)
toolPath = os.path.normpath(retValue)
checkPathVaild(toolPath)
return toolPath
if __name__ == "__main__":
"""
"""
expansion = Expansion()
expansion.parseCommandLine()
expansion.checkParameters()
expansion.initLogs()
expImpl = ExpansionImpl(expansion)
expImpl.run()

View File

@ -309,6 +309,7 @@ class DefaultValue():
LCCTL_LOG_FILE = "gs_lcctl.log"
RESIZE_LOG_FILE = "gs_resize.log"
HOTPATCH_LOG_FILE = "gs_hotpatch.log"
EXPANSION_LOG_FILE = "gs_expansion.log"
# hotpatch action
HOTPATCH_ACTION_LIST = ["load", "unload", "active", "deactive",
"info", "list"]

View File

@ -1092,6 +1092,24 @@ class ErrorCode():
'GAUSS_53612': "[GAUSS-53612]: Can not find any catalog in database %s"
}
##########################################################################
# gs_expansion
# [GAUSS-537] : gs_expansion failed
##########################################################################
GAUSS_357 = {
"GAUSS_35700": "[GAUSS-35700] Expansion standby node failed.",
"GAUSS_35701": "[GAUSS-35701] Empty parameter. The %s parameter is"
"missing in the command.",
"GAUSS_35702": "[GAUSS-35702] Unrecognized parameter, standby host "
"backip %s is not in the "
"XML configuration file",
"GAUSS_35703": "[GAUSS-35703] Check standby database Failed. The "
"database on node is abnormal. \n"
"node [%s], user [%s], dataNode [%s]. \n"
"You can use command \"gs_ctl query -D %s\" for more "
"detail."
}
class OmError(BaseException):
"""

View File

@ -93,6 +93,8 @@ gs_ssh = ["-?", "--help", "-V", "--version", "-c:"]
gs_checkos = ["-?", "--help", "-V", "--version", "-h:", "-f:", "-o:",
"-i:", "--detail",
"-l:", "-X:"]
gs_expansion = ["-?", "--help", "-V", "--version", "-U:", "-G:", "-L",
"-X:", "-h:", "--sep-env-file="]
# gs_om child branch
gs_om_start = ["-t:", "-?", "--help", "-V", "--version", "-h:", "-I:",
@ -153,7 +155,8 @@ ParameterDict = {"preinstall": gs_preinstall,
"postuninstall": gs_postuninstall,
"view": gs_om_view,
"query": gs_om_query,
"refreshconf": gs_om_refreshconf
"refreshconf": gs_om_refreshconf,
"expansion": gs_expansion
}
# List of scripts with the -t parameter

View File

@ -0,0 +1,829 @@
# -*- coding:utf-8 -*-
#############################################################################
# Copyright (c) 2020 Huawei Technologies Co.,Ltd.
#
# openGauss is licensed under Mulan PSL v2.
# You can use this software according to the terms
# and conditions of the Mulan PSL v2.
# You may obtain a copy of Mulan PSL v2 at:
#
# http://license.coscl.org.cn/MulanPSL2
#
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS,
# WITHOUT WARRANTIES OF ANY KIND,
# EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
# MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
# See the Mulan PSL v2 for more details.
# ----------------------------------------------------------------------------
# Description : ExpansionImpl.py
#############################################################################
import subprocess
import sys
import re
import os
import getpass
import pwd
import datetime
from random import sample
import time
from multiprocessing import Process, Value
sys.path.append(sys.path[0] + "/../../../../")
from gspylib.common.DbClusterInfo import dbClusterInfo, queryCmd
from gspylib.threads.SshTool import SshTool
from gspylib.common.DbClusterStatus import DbClusterStatus
from gspylib.common.ErrorCode import ErrorCode
from gspylib.common.Common import DefaultValue
from gspylib.common.GaussLog import GaussLog
sys.path.append(sys.path[0] + "/../../../lib/")
DefaultValue.doConfigForParamiko()
import paramiko
#mode
MODE_PRIMARY = "primary"
MODE_STANDBY = "standby"
MODE_NORMAL = "normal"
#db state
STAT_NORMAL = "normal"
# master
MASTER_INSTANCE = 0
# standby
STANDBY_INSTANCE = 1
# statu failed
STATUS_FAIL = "Failure"
class ExpansionImpl():
"""
class for expansion standby node.
step:
1. preinstall database on new standby node
2. install as single-node database
3. establish primary-standby relationship of all node
"""
def __init__(self, expansion):
"""
"""
self.context = expansion
self.user = self.context.user
self.group = self.context.group
self.logger = self.context.logger
self.envFile = DefaultValue.getEnv("MPPDB_ENV_SEPARATE_PATH")
currentTime = str(datetime.datetime.now()).replace(" ", "_").replace(
".", "_")
self.commonGsCtl = GsCtlCommon(expansion)
self.tempFileDir = "/tmp/gs_expansion_%s" % (currentTime)
self.logger.debug("tmp expansion dir is %s ." % self.tempFileDir)
def sendSoftToHosts(self):
"""
create software dir and send it on each nodes
"""
self.logger.debug("Start to send software to each standby nodes.\n")
hostNames = self.context.newHostList
hostList = hostNames
sshTool = SshTool(hostNames)
srcFile = self.context.packagepath
targetDir = os.path.realpath(
os.path.join(srcFile, "../"))
## mkdir package dir and send package to remote nodes.
sshTool.executeCommand("mkdir -p %s" % srcFile , "", DefaultValue.SUCCESS,
hostList)
sshTool.scpFiles(srcFile, targetDir, hostList)
## change mode of package dir to set privileges for users
tPathList = os.path.split(targetDir)
path2ChangeMode = targetDir
if len(tPathList) > 2:
path2ChangeMode = os.path.join(tPathList[0],tPathList[1])
changeModCmd = "chmod -R a+x {srcFile}".format(user=self.user,
group=self.group,srcFile=path2ChangeMode)
sshTool.executeCommand(changeModCmd, "", DefaultValue.SUCCESS,
hostList)
self.logger.debug("End to send software to each standby nodes.\n")
def generateAndSendXmlFile(self):
"""
"""
self.logger.debug("Start to generateAndSend XML file.\n")
tempXmlFile = "%s/clusterconfig.xml" % self.tempFileDir
cmd = "mkdir -p %s; touch %s; cat /dev/null > %s" % \
(self.tempFileDir, tempXmlFile, tempXmlFile)
(status, output) = subprocess.getstatusoutput(cmd)
cmd = "chown -R %s:%s %s" % (self.user, self.group, self.tempFileDir)
(status, output) = subprocess.getstatusoutput(cmd)
newHosts = self.context.newHostList
for host in newHosts:
# create single deploy xml file for each standby node
xmlContent = self.__generateXml(host)
fo = open("%s" % tempXmlFile, "w")
fo.write( xmlContent )
fo.close()
# send single deploy xml file to each standby node
sshTool = SshTool(host)
retmap, output = sshTool.getSshStatusOutput("mkdir -p %s" %
self.tempFileDir , [host], self.envFile)
retmap, output = sshTool.getSshStatusOutput("chown %s:%s %s" %
(self.user, self.group, self.tempFileDir), [host], self.envFile)
sshTool.scpFiles("%s" % tempXmlFile, "%s" %
tempXmlFile, [host], self.envFile)
self.logger.debug("End to generateAndSend XML file.\n")
def __generateXml(self, backIp):
"""
"""
nodeName = self.context.backIpNameMap[backIp]
nodeInfo = self.context.clusterInfoDict[nodeName]
backIp = nodeInfo["backIp"]
sshIp = nodeInfo["sshIp"]
port = nodeInfo["port"]
dataNode = nodeInfo["dataNode"]
appPath = self.context.clusterInfoDict["appPath"]
logPath = self.context.clusterInfoDict["logPath"]
corePath = self.context.clusterInfoDict["corePath"]
toolPath = self.context.clusterInfoDict["toolPath"]
xmlConfig = """\
<?xml version="1.0" encoding="UTF-8"?>
<ROOT>
<CLUSTER>
<PARAM name="clusterName" value="dbCluster" />
<PARAM name="nodeNames" value="{nodeName}" />
<PARAM name="backIp1s" value="{backIp}"/>
<PARAM name="gaussdbAppPath" value="{appPath}" />
<PARAM name="gaussdbLogPath" value="{logPath}" />
<PARAM name="gaussdbToolPath" value="{toolPath}" />
<PARAM name="corePath" value="{corePath}"/>
<PARAM name="clusterType" value="single-inst"/>
</CLUSTER>
<DEVICELIST>
<DEVICE sn="1000001">
<PARAM name="name" value="{nodeName}"/>
<PARAM name="azName" value="AZ1"/>
<PARAM name="azPriority" value="1"/>
<PARAM name="backIp1" value="{backIp}"/>
<PARAM name="sshIp1" value="{sshIp}"/>
<!--dbnode-->
<PARAM name="dataNum" value="1"/>
<PARAM name="dataPortBase" value="{port}"/>
<PARAM name="dataNode1" value="{dataNode}"/>
</DEVICE>
</DEVICELIST>
</ROOT>
""".format(nodeName=nodeName,backIp=backIp,appPath=appPath,
logPath=logPath,toolPath=toolPath,corePath=corePath,
sshIp=sshIp,port=port,dataNode=dataNode)
return xmlConfig
def changeUser(self):
user = self.user
try:
pw_record = pwd.getpwnam(user)
except Exception:
GaussLog.exitWithError(ErrorCode.GAUSS_503["GAUSS_50300"] % user)
user_name = pw_record.pw_name
user_uid = pw_record.pw_uid
user_gid = pw_record.pw_gid
env = os.environ.copy()
os.setgid(user_gid)
os.setuid(user_uid)
def initSshConnect(self, host, user='root'):
try:
getPwdStr = "Please enter the password of user [%s] on node [%s]: " \
% (user, host)
passwd = getpass.getpass(getPwdStr)
self.sshClient = paramiko.SSHClient()
self.sshClient.set_missing_host_key_policy(paramiko.AutoAddPolicy())
self.sshClient.connect(host, 22, user, passwd)
except paramiko.ssh_exception.AuthenticationException as e :
self.logger.log("Authentication failed.")
self.initSshConnect(host, user)
def installDatabaseOnHosts(self):
"""
install database on each standby node
"""
hostList = self.context.newHostList
envfile = DefaultValue.getEnv(DefaultValue.MPPRC_FILE_ENV)
tempXmlFile = "%s/clusterconfig.xml" % self.tempFileDir
installCmd = "source {envfile} ; gs_install -X {xmlfile} \
2>&1".format(envfile=envfile,xmlfile=tempXmlFile)
statusArr = []
for newHost in hostList:
self.logger.log("\ninstalling database on node %s:" % newHost)
self.logger.debug(installCmd)
hostName = self.context.backIpNameMap[newHost]
sshIp = self.context.clusterInfoDict[hostName]["sshIp"]
self.initSshConnect(sshIp, self.user)
stdin, stdout, stderr = self.sshClient.exec_command(installCmd,
get_pty=True)
channel = stdout.channel
echannel = stderr.channel
while not channel.exit_status_ready():
try:
recvOut = channel.recv(1024)
outDecode = recvOut.decode("utf-8");
outStr = outDecode.strip()
if(len(outStr) == 0):
continue
if(outDecode.endswith("\r\n")):
self.logger.log(outStr)
else:
value = ""
if re.match(r".*yes.*no.*", outStr):
value = input(outStr)
while True:
# check the input
if (
value.upper() != "YES"
and value.upper() != "NO"
and value.upper() != "Y"
and value.upper() != "N"):
value = input("Please type 'yes' or 'no': ")
continue
break
else:
value = getpass.getpass(outStr)
stdin.channel.send("%s\r\n" %value)
stdin.flush()
stdout.flush()
except Exception as e:
sys.exit(1)
pass
if channel.exit_status_ready() and \
not channel.recv_stderr_ready() and \
not channel.recv_ready():
channel.close()
break
stdout.close()
stderr.close()
status = channel.recv_exit_status()
statusArr.append(status)
isBothSuccess = True
for status in statusArr:
if status != 0:
isBothSuccess = False
break
if isBothSuccess:
self.logger.log("\nSuccessfully install database on node %s" %
hostList)
else:
sys.exit(1)
def preInstallOnHosts(self):
"""
execute preinstall step
"""
self.logger.debug("Start to preinstall database step.\n")
newBackIps = self.context.newHostList
newHostNames = []
for host in newBackIps:
newHostNames.append(self.context.backIpNameMap[host])
envfile = self.envFile
tempXmlFile = "%s/clusterconfig.xml" % self.tempFileDir
preinstallCmd = "{softpath}/script/gs_preinstall -U {user} -G {group} \
-X {xmlfile} --sep-env-file={envfile} \
--non-interactive 2>&1\
".format(softpath=self.context.packagepath,user=self.user,
group=self.group,xmlfile=tempXmlFile,envfile=envfile)
sshTool = SshTool(newHostNames)
status, output = sshTool.getSshStatusOutput(preinstallCmd , [], envfile)
statusValues = status.values()
if STATUS_FAIL in statusValues:
GaussLog.exitWithError(output)
self.logger.debug("End to preinstall database step.\n")
def buildStandbyRelation(self):
"""
func: after install single database on standby nodes.
build the relation with primary and standby nodes.
step:
1. restart primary node with Primary Mode
(only used to Single-Node instance)
2. set guc config to primary node
3. restart standby node with Standby Mode
4. set guc config to standby node
5. generate cluster static file and send to each node.
"""
self.queryPrimaryClusterDetail()
self.setPrimaryGUCConfig()
self.setStandbyGUCConfig()
self.buildStandbyHosts()
self.generateClusterStaticFile()
def queryPrimaryClusterDetail(self):
"""
get current cluster type.
single-node or primary-standby
"""
self.logger.debug("Query primary database instance mode.\n")
self.isSingleNodeInstance = True
primaryHost = self.getPrimaryHostName()
result = self.commonGsCtl.queryOmCluster(primaryHost, self.envFile)
instance = re.findall(r"node\s+node_ip\s+instance\s+state", result)
if len(instance) > 1:
self.isSingleNodeInstance = False
self.logger.debug("Original instance mode is %s" %
self.isSingleNodeInstance)
def setPrimaryGUCConfig(self):
"""
"""
self.logger.debug("Start to set primary node GUC config.\n")
primaryHost = self.getPrimaryHostName()
dataNode = self.context.clusterInfoDict[primaryHost]["dataNode"]
self.setGUCOnClusterHosts([primaryHost])
self.addStandbyIpInPrimaryConf()
insType, dbStat = self.commonGsCtl.queryInstanceStatus(primaryHost,
dataNode,self.envFile)
if insType != MODE_PRIMARY:
self.commonGsCtl.stopInstance(primaryHost, dataNode, self.envFile)
self.commonGsCtl.startInstanceWithMode(primaryHost, dataNode,
MODE_PRIMARY,self.envFile)
# start db to primary state for three times max
start_retry_num = 1
while start_retry_num <= 3:
insType, dbStat = self.commonGsCtl.queryInstanceStatus(primaryHost,
dataNode, self.envFile)
if insType == MODE_PRIMARY:
break
self.logger.debug("Start database as Primary mode failed, \
retry for %s times" % start_retry_num)
self.commonGsCtl.startInstanceWithMode(primaryHost, dataNode,
MODE_PRIMARY, self.envFile)
start_retry_num = start_retry_num + 1
def setStandbyGUCConfig(self):
"""
"""
self.logger.debug("Start to set standby node GUC config.\n")
standbyHosts = self.context.newHostList
standbyHostNames = []
for host in standbyHosts:
hostName = self.context.backIpNameMap[host]
standbyHostNames.append(hostName)
self.setGUCOnClusterHosts(standbyHostNames)
def addStandbyIpInPrimaryConf(self):
"""
add standby hosts ip in primary node pg_hba.conf
"""
standbyHosts = self.context.newHostList
primaryHost = self.getPrimaryHostName()
command = ''
for host in standbyHosts:
hostName = self.context.backIpNameMap[host]
dataNode = self.context.clusterInfoDict[hostName]["dataNode"]
command += "gs_guc set -D %s -h 'host all all %s/32 \
trust';" % (dataNode, host)
self.logger.debug(command)
sshTool = SshTool([primaryHost])
resultMap, outputCollect = sshTool.getSshStatusOutput(command,
[primaryHost], self.envFile)
self.logger.debug(outputCollect)
def reloadPrimaryConf(self):
"""
"""
primaryHost = self.getPrimaryHostName()
dataNode = self.context.clusterInfoDict[primaryHost]["dataNode"]
command = "gs_ctl reload -D %s " % dataNode
sshTool = SshTool([primaryHost])
self.logger.debug(command)
resultMap, outputCollect = sshTool.getSshStatusOutput(command,
[primaryHost], self.envFile)
self.logger.debug(outputCollect)
def getPrimaryHostName(self):
"""
"""
primaryHost = ""
for nodeName in self.context.nodeNameList:
if self.context.clusterInfoDict[nodeName]["instanceType"] \
== MASTER_INSTANCE:
primaryHost = nodeName
break
return primaryHost
def buildStandbyHosts(self):
"""
stop the new standby host`s database and build it as standby mode
"""
self.logger.debug("start to build standby node...\n")
standbyHosts = self.context.newHostList
for host in standbyHosts:
hostName = self.context.backIpNameMap[host]
dataNode = self.context.clusterInfoDict[hostName]["dataNode"]
self.commonGsCtl.stopInstance(hostName, dataNode, self.envFile)
self.commonGsCtl.startInstanceWithMode(hostName, dataNode,
MODE_STANDBY, self.envFile)
# start standby as standby mode for three times max.
start_retry_num = 1
while start_retry_num <= 3:
insType, dbStat = self.commonGsCtl.queryInstanceStatus(hostName,
dataNode, self.envFile)
if insType != MODE_STANDBY:
self.logger.debug("Start databasse as Standby mode failed, \
retry for %s times" % start_retry_num)
self.setGUCOnClusterHosts([])
self.addStandbyIpInPrimaryConf()
self.reloadPrimaryConf()
self.commonGsCtl.startInstanceWithMode(hostName, dataNode,
MODE_STANDBY, self.envFile)
start_retry_num = start_retry_num + 1
else:
break
# build standby node
self.addStandbyIpInPrimaryConf()
self.reloadPrimaryConf()
self.commonGsCtl.buildInstance(hostName, dataNode, MODE_STANDBY,
self.envFile)
# if build failed first time. retry for three times.
start_retry_num = 1
while start_retry_num <= 3:
insType, dbStat = self.commonGsCtl.queryInstanceStatus(hostName,
dataNode, self.envFile)
if dbStat != STAT_NORMAL:
self.logger.debug("Build standby instance failed, \
retry for %s times" % start_retry_num)
self.addStandbyIpInPrimaryConf()
self.reloadPrimaryConf()
self.commonGsCtl.buildInstance(hostName, dataNode,
MODE_STANDBY, self.envFile)
start_retry_num = start_retry_num + 1
else:
break
def generateClusterStaticFile(self):
"""
generate static_config_files and send to all hosts
"""
self.logger.debug("Start to generate and send cluster static file.\n")
primaryHosts = self.getPrimaryHostName()
command = "gs_om -t generateconf -X %s" % self.context.xmlFile
sshTool = SshTool([primaryHosts])
resultMap, outputCollect = sshTool.getSshStatusOutput(command,
[primaryHosts], self.envFile)
self.logger.debug(outputCollect)
nodeNameList = self.context.nodeNameList
for hostName in nodeNameList:
hostSsh = SshTool([hostName])
toolPath = self.context.clusterInfoDict["toolPath"]
appPath = self.context.clusterInfoDict["appPath"]
srcFile = "%s/script/static_config_files/cluster_static_config_%s" \
% (toolPath, hostName)
targetFile = "%s/bin/cluster_static_config" % appPath
hostSsh.scpFiles(srcFile, targetFile, [hostName], self.envFile)
self.logger.debug("End to generate and send cluster static file.\n")
time.sleep(10)
# Single-node database need start cluster after expansion
if self.isSingleNodeInstance:
self.logger.debug("Single-Node instance need restart.\n")
self.commonGsCtl.queryOmCluster(primaryHosts, self.envFile)
# if primary database not normal, restart it
primaryHost = self.getPrimaryHostName()
dataNode = self.context.clusterInfoDict[primaryHost]["dataNode"]
insType, dbStat = self.commonGsCtl.queryInstanceStatus(primaryHost,
dataNode, self.envFile)
if insType != MODE_PRIMARY:
self.commonGsCtl.startInstanceWithMode(primaryHost, dataNode,
MODE_PRIMARY, self.envFile)
# if stat if not normal,rebuild standby database
standbyHosts = self.context.newHostList
for host in standbyHosts:
hostName = self.context.backIpNameMap[host]
dataNode = self.context.clusterInfoDict[hostName]["dataNode"]
insType, dbStat = self.commonGsCtl.queryInstanceStatus(hostName,
dataNode, self.envFile)
if dbStat != STAT_NORMAL:
self.commonGsCtl.buildInstance(hostName, dataNode,
MODE_STANDBY, self.envFile)
self.commonGsCtl.startOmCluster(primaryHosts, self.envFile)
def setGUCOnClusterHosts(self, hostNames=[]):
"""
guc config on all hosts
"""
gucDict = self.getGUCConfig()
tempShFile = "%s/guc.sh" % self.tempFileDir
if len(hostNames) == 0:
hostNames = self.context.nodeNameList
for host in hostNames:
command = "source %s ; " % self.envFile + gucDict[host]
self.logger.debug(command)
sshTool = SshTool([host])
# create temporary dir to save guc command bashfile.
mkdirCmd = "mkdir -m a+x -p %s; chown %s:%s %s" % \
(self.tempFileDir,self.user,self.group,self.tempFileDir)
retmap, output = sshTool.getSshStatusOutput(mkdirCmd, [host], self.envFile)
subprocess.getstatusoutput("mkdir -m a+x -p %s; touch %s; \
cat /dev/null > %s" % \
(self.tempFileDir, tempShFile, tempShFile))
fo = open("%s" % tempShFile, "w")
fo.write("#bash\n")
fo.write( command )
fo.close()
# send guc command bashfile to each host and execute it.
sshTool.scpFiles("%s" % tempShFile, "%s" % tempShFile, [host],
self.envFile)
resultMap, outputCollect = sshTool.getSshStatusOutput("sh %s" % \
tempShFile, [host], self.envFile)
self.logger.debug(outputCollect)
def getGUCConfig(self):
"""
get guc config of each node:
replconninfo[index]
remote_read_mode
replication_type
"""
nodeDict = self.context.clusterInfoDict
hostNames = self.context.nodeNameList
gucDict = {}
for hostName in hostNames:
localeHostInfo = nodeDict[hostName]
index = 1
guc_tempate_str = ""
for remoteHost in hostNames:
if(remoteHost == hostName):
continue
remoteHostInfo = nodeDict[remoteHost]
guc_repl_template = """\
gs_guc set -D {dn} -c "replconninfo{index}=\
'localhost={localhost} localport={localport} \
localheartbeatport={localeHeartPort} \
localservice={localservice} \
remotehost={remoteNode} \
remoteport={remotePort} \
remoteheartbeatport={remoteHeartPort} \
remoteservice={remoteservice}'"
""".format(dn=localeHostInfo["dataNode"],
index=index,
localhost=localeHostInfo["sshIp"],
localport=localeHostInfo["localport"],
localeHeartPort=localeHostInfo["heartBeatPort"],
localservice=localeHostInfo["localservice"],
remoteNode=remoteHostInfo["sshIp"],
remotePort=remoteHostInfo["localport"],
remoteHeartPort=remoteHostInfo["heartBeatPort"],
remoteservice=remoteHostInfo["localservice"])
guc_tempate_str += guc_repl_template
index += 1
guc_mode_type = """
gs_guc set -D {dn} -c 'remote_read_mode=off';
gs_guc set -D {dn} -c 'replication_type=1';
""".format(dn=localeHostInfo["dataNode"])
guc_tempate_str += guc_mode_type
gucDict[hostName] = guc_tempate_str
return gucDict
def checkLocalModeOnStandbyHosts(self):
"""
"""
standbyHosts = self.context.newHostList
self.logger.log("Checking the database with locale mode.")
for host in standbyHosts:
hostName = self.context.backIpNameMap[host]
dataNode = self.context.clusterInfoDict[hostName]["dataNode"]
insType, dbStat = self.commonGsCtl.queryInstanceStatus(hostName,
dataNode, self.envFile)
if insType not in (MODE_PRIMARY, MODE_STANDBY, MODE_NORMAL):
GaussLog.exitWithError(ErrorCode.GAUSS_357["GAUSS_35703"] %
(hostName, self.user, dataNode, dataNode))
self.logger.log("Successfully checked the database with locale mode.")
def preInstall(self):
"""
preinstall on new hosts.
"""
self.logger.log("Start to preinstall database on the new \
standby nodes.")
self.sendSoftToHosts()
self.generateAndSendXmlFile()
self.preInstallOnHosts()
self.logger.log("Successfully preinstall database on the new \
standby nodes.")
def clearTmpFile(self):
"""
clear temporary file after expansion success
"""
self.logger.debug("start to delete temporary file")
hostNames = self.context.nodeNameList
sshTool = SshTool(hostNames)
clearCmd = "source %s ; rm -rf %s" % (self.envFile, self.tempFileDir)
result, output = sshTool.getSshStatusOutput(clearCmd,
hostNames, self.envFile)
self.logger.debug(output)
def installAndExpansion(self):
"""
install database and expansion standby node with db om user
"""
pvalue = Value('i', 0)
proc = Process(target=self.installProcess, args=(pvalue,))
proc.start()
proc.join()
if not pvalue.value:
sys.exit(1)
else:
proc.terminate()
def installProcess(self, pvalue):
# change to db manager user. the below steps run with db manager user.
self.changeUser()
if not self.context.standbyLocalMode:
self.logger.log("\nStart to install database on the new \
standby nodes.")
self.installDatabaseOnHosts()
else:
self.logger.log("\nStandby nodes is installed with locale mode.")
self.checkLocalModeOnStandbyHosts()
self.logger.log("\nDatabase on standby nodes installed finished. \
Start to establish the primary-standby relationship.")
self.buildStandbyRelation()
# process success
pvalue.value = 1
def run(self):
"""
start expansion
"""
# preinstall on standby nodes with root user.
if not self.context.standbyLocalMode:
self.preInstall()
self.installAndExpansion()
self.clearTmpFile()
self.logger.log("\nSuccess to expansion standby nodes.")
class GsCtlCommon:
def __init__(self, expansion):
"""
"""
self.logger = expansion.logger
def queryInstanceStatus(self, host, datanode, env):
"""
"""
command = "source %s ; gs_ctl query -D %s" % (env, datanode)
sshTool = SshTool([datanode])
resultMap, outputCollect = sshTool.getSshStatusOutput(command,
[host], env)
self.logger.debug(outputCollect)
localRole = re.findall(r"local_role.*: (.*?)\n", outputCollect)
db_state = re.findall(r"db_state.*: (.*?)\n", outputCollect)
insType = ""
if(len(localRole)) == 0:
insType = ""
else:
insType = localRole[0]
dbStatus = ""
if(len(db_state)) == 0:
dbStatus = ""
else:
dbStatus = db_state[0]
return insType.strip().lower(), dbStatus.strip().lower()
def stopInstance(self, host, datanode, env):
"""
"""
command = "source %s ; gs_ctl stop -D %s" % (env, datanode)
sshTool = SshTool([host])
resultMap, outputCollect = sshTool.getSshStatusOutput(command,
[host], env)
self.logger.debug(host)
self.logger.debug(outputCollect)
def startInstanceWithMode(self, host, datanode, mode, env):
"""
"""
command = "source %s ; gs_ctl start -D %s -M %s" % (env, datanode, mode)
self.logger.debug(command)
sshTool = SshTool([host])
resultMap, outputCollect = sshTool.getSshStatusOutput(command,
[host], env)
self.logger.debug(host)
self.logger.debug(outputCollect)
def buildInstance(self, host, datanode, mode, env):
command = "source %s ; gs_ctl build -D %s -M %s" % (env, datanode, mode)
self.logger.debug(command)
sshTool = SshTool([host])
resultMap, outputCollect = sshTool.getSshStatusOutput(command,
[host], env)
self.logger.debug(host)
self.logger.debug(outputCollect)
def startOmCluster(self, host, env):
"""
om tool start cluster
"""
command = "source %s ; gs_om -t start" % env
self.logger.debug(command)
sshTool = SshTool([host])
resultMap, outputCollect = sshTool.getSshStatusOutput(command,
[host], env)
self.logger.debug(host)
self.logger.debug(outputCollect)
def queryOmCluster(self, host, env):
"""
query om cluster detail with command:
gs_om -t status --detail
"""
command = "source %s ; gs_om -t status --detail" % env
sshTool = SshTool([host])
resultMap, outputCollect = sshTool.getSshStatusOutput(command,
[host], env)
self.logger.debug(host)
self.logger.debug(outputCollect)
return outputCollect

View File

@ -1146,6 +1146,7 @@ WHERE d.classoid IS NULL AND p1.oid <= 9999 order by 1;
2096 | pg_terminate_backend
2097 | pg_get_variable_info
2098 | pg_get_functiondef
2099 | pg_terminate_session
2100 | avg
2101 | avg
2102 | avg
@ -2637,7 +2638,7 @@ WHERE d.classoid IS NULL AND p1.oid <= 9999 order by 1;
9016 | pg_advisory_lock
9017 | pgxc_unlock_for_sp_database
9999 | pg_test_err_contain_err
(2275 rows)
(2276 rows)
-- **************** pg_cast ****************
-- Catch bogus values in pg_cast columns (other than cases detected by

View File

@ -0,0 +1,751 @@
DROP TABLE IF EXISTS pt2;
NOTICE: table "pt2" does not exist, skipping
DROP TABLE IF EXISTS pt1;
NOTICE: table "pt1" does not exist, skipping
CREATE TABLE pt1(
d_date date UNIQUE
)partition BY RANGE (d_date) INTERVAL('1 day')
(PARTITION part1 VALUES LESS THAN ('1900-01-01'));
NOTICE: CREATE TABLE / UNIQUE will create implicit index "pt1_d_date_key" for table "pt1"
CREATE TABLE pt2(
d_date date
)partition BY RANGE (d_date) INTERVAL('1 day')
(PARTITION part1 VALUES LESS THAN ('1900-01-01'));
ALTER TABLE pt2 ADD CONSTRAINT test_foreign FOREIGN KEY(d_date)
REFERENCES pt1(d_date) on UPDATE CASCADE ON DELETE CASCADE;
INSERT into pt1 VALUES('1999-01-01'),('1999-01-02'),('1999-01-03'),('1999-01-04');
INSERT into pt2 VALUES('1999-01-01');
INSERT into pt2 VALUES('2000-01-01');
ERROR: insert or update on table "pt2" violates foreign key constraint "test_foreign"
DETAIL: Key (d_date)=(Sat Jan 01 00:00:00 2000) is not present in table "pt1".
update pt2 set pt2.d_date = '2000-01-01' where pt2.d_date = '1999-01-01';
ERROR: insert or update on table "pt2" violates foreign key constraint "test_foreign"
DETAIL: Key (d_date)=(Sat Jan 01 00:00:00 2000) is not present in table "pt1".
update pt2 set pt2.d_date = '1999-01-02' where pt2.d_date = '1999-01-01';
SELECT * FROM pt2;
d_date
--------------------------
Sat Jan 02 00:00:00 1999
(1 row)
SELECT * FROM pt2 PARTITION(sys_p2);
d_date
--------------------------
Sat Jan 02 00:00:00 1999
(1 row)
delete from pt2;
INSERT into pt2 VALUES('1999-01-01'), ('1999-01-03'),('1999-01-04');
INSERT into pt1 VALUES('1999-01-08');
INSERT into pt2 VALUES('1999-01-08');
update pt1 set pt1.d_date = '2000-01-01' where pt1.d_date = '1999-01-08';
delete from pt1 where pt1.d_date = '2000-01-01';
DROP TABLE pt2;
DROP TABLE pt1;
CREATE TABLE pt1(
d_date date UNIQUE
)partition BY RANGE (d_date) INTERVAL('1 month')
(PARTITION part1 VALUES LESS THAN ('1900-01-01'));
NOTICE: CREATE TABLE / UNIQUE will create implicit index "pt1_d_date_key" for table "pt1"
CREATE TABLE pt2(
d_date date
)partition BY RANGE (d_date) INTERVAL('1 month')
(PARTITION part1 VALUES LESS THAN ('1900-01-01'));
ALTER TABLE pt2 ADD CONSTRAINT test_foreign FOREIGN KEY(d_date)
REFERENCES pt1(d_date) on UPDATE CASCADE ON DELETE CASCADE;
INSERT INTO pt1 VALUES
('1999-01-01'),('1999-01-02'),('1999-01-019'),('1999-01-20'),
('1999-02-01'),('1999-02-02'),('1999-02-19'),('1999-02-20'),
('1999-03-01'),('1999-03-02'),('1999-03-19'),('1999-03-20'),
('1999-04-01'),('1999-04-02'),('1999-04-19'),('1999-04-20'),
('1999-05-01'),('1999-05-02'),('1999-05-19'),('1999-05-20'),
('1999-06-01'),('1999-06-02'),('1999-06-19'),('1999-06-20'),
('1999-07-01'),('1999-07-02'),('1999-07-19'),('1999-07-20'),
('1999-08-01'),('1999-08-02'),('1999-08-19'),('1999-08-20'),
('1999-09-01'),('1999-09-02'),('1999-09-19'),('1999-09-20'),
('1999-10-01'),('1999-10-02'),('1999-10-19'),('1999-10-20'),
('1999-11-01'),('1999-11-02'),('1999-11-19'),('1999-11-20'),
('1999-12-01'),('1999-12-02'),('1999-12-19'),('1999-12-20');
INSERT INTO pt2 VALUES
('1999-01-01'),('1999-01-02'),('1999-01-019'),('1999-01-20'),
('1999-02-01'),('1999-02-02'),('1999-02-19'),('1999-02-20'),
('1999-03-01'),('1999-03-02'),('1999-03-19'),('1999-03-20'),
('1999-04-01'),('1999-04-02'),('1999-04-19'),('1999-04-20'),
('1999-05-01'),('1999-05-02'),('1999-05-19'),('1999-05-20'),
('1999-06-01'),('1999-06-02'),('1999-06-19'),('1999-06-20'),
('1999-07-01'),('1999-07-02'),('1999-07-19'),('1999-07-20'),
('1999-08-01'),('1999-08-02'),('1999-08-19'),('1999-08-20'),
('1999-09-01'),('1999-09-02'),('1999-09-19'),('1999-09-20'),
('1999-10-01'),('1999-10-02'),('1999-10-19'),('1999-10-20'),
('1999-11-01'),('1999-11-02'),('1999-11-19'),('1999-11-20'),
('1999-12-01'),('1999-12-02'),('1999-12-19'),('1999-12-20');
delete from pt2 where pt2.d_date<'1999-03-01';
select * from pt2 where pt2.d_date<'1999-06-01';
d_date
--------------------------
Mon Mar 01 00:00:00 1999
Tue Mar 02 00:00:00 1999
Fri Mar 19 00:00:00 1999
Sat Mar 20 00:00:00 1999
Thu Apr 01 00:00:00 1999
Fri Apr 02 00:00:00 1999
Mon Apr 19 00:00:00 1999
Tue Apr 20 00:00:00 1999
Sat May 01 00:00:00 1999
Sun May 02 00:00:00 1999
Wed May 19 00:00:00 1999
Thu May 20 00:00:00 1999
(12 rows)
delete from pt1 where pt1.d_date<'1999-05-01';
delete from pt2 where pt2.d_date>'1999-11-15' and pt2.d_date<'1999-12-15';
SELECT * FROM pt2 WHERE pt2.d_date>='1999-10-01';
d_date
--------------------------
Fri Oct 01 00:00:00 1999
Sat Oct 02 00:00:00 1999
Tue Oct 19 00:00:00 1999
Wed Oct 20 00:00:00 1999
Mon Nov 01 00:00:00 1999
Tue Nov 02 00:00:00 1999
Sun Dec 19 00:00:00 1999
Mon Dec 20 00:00:00 1999
(8 rows)
delete from pt1 where pt1.d_date>'1999-10-15' and pt1.d_date<'1999-11-15';
SELECT * FROM pt1 WHERE pt1.d_date>='1999-10-01';
d_date
--------------------------
Fri Oct 01 00:00:00 1999
Sat Oct 02 00:00:00 1999
Fri Nov 19 00:00:00 1999
Sat Nov 20 00:00:00 1999
Wed Dec 01 00:00:00 1999
Thu Dec 02 00:00:00 1999
Sun Dec 19 00:00:00 1999
Mon Dec 20 00:00:00 1999
(8 rows)
SELECT * FROM pt2 WHERE pt2.d_date>='1999-10-01';
d_date
--------------------------
Fri Oct 01 00:00:00 1999
Sat Oct 02 00:00:00 1999
Sun Dec 19 00:00:00 1999
Mon Dec 20 00:00:00 1999
(4 rows)
UPDATE pt2 set d_date = d_date - INTERVAL '4' month where d_date>='1999-05-01' and d_date<'1999-06-01';
ERROR: insert or update on table "pt2" violates foreign key constraint "test_foreign"
DETAIL: Key (d_date)=(Fri Jan 01 00:00:00 1999) is not present in table "pt1".
UPDATE pt1 set d_date = d_date - INTERVAL '4' month where d_date>='1999-05-01' and d_date<'1999-06-01';
SELECT * FROM pt1 WHERE d_date<'1999-07-01';
d_date
--------------------------
Fri Jan 01 00:00:00 1999
Sat Jan 02 00:00:00 1999
Tue Jan 19 00:00:00 1999
Wed Jan 20 00:00:00 1999
Tue Jun 01 00:00:00 1999
Wed Jun 02 00:00:00 1999
Sat Jun 19 00:00:00 1999
Sun Jun 20 00:00:00 1999
(8 rows)
SELECT * FROM pt1 WHERE d_date<'1999-07-01';
d_date
--------------------------
Fri Jan 01 00:00:00 1999
Sat Jan 02 00:00:00 1999
Tue Jan 19 00:00:00 1999
Wed Jan 20 00:00:00 1999
Tue Jun 01 00:00:00 1999
Wed Jun 02 00:00:00 1999
Sat Jun 19 00:00:00 1999
Sun Jun 20 00:00:00 1999
(8 rows)
UPDATE pt2 set d_date = d_date - INTERVAL '1' month where d_date>='1999-06-01' and d_date<='1999-07-15';
ERROR: insert or update on table "pt2" violates foreign key constraint "test_foreign"
DETAIL: Key (d_date)=(Sat May 01 00:00:00 1999) is not present in table "pt1".
UPDATE pt1 set d_date = d_date - INTERVAL '1' month where d_date>='1999-06-01' and d_date<='1999-07-15';
SELECT * FROM pt1 WHERE d_date<'1999-08-01';
d_date
--------------------------
Fri Jan 01 00:00:00 1999
Sat Jan 02 00:00:00 1999
Tue Jan 19 00:00:00 1999
Wed Jan 20 00:00:00 1999
Sat May 01 00:00:00 1999
Sun May 02 00:00:00 1999
Wed May 19 00:00:00 1999
Thu May 20 00:00:00 1999
Tue Jun 01 00:00:00 1999
Wed Jun 02 00:00:00 1999
Mon Jul 19 00:00:00 1999
Tue Jul 20 00:00:00 1999
(12 rows)
SELECT * FROM pt2 WHERE d_date<'1999-08-01';
d_date
--------------------------
Fri Jan 01 00:00:00 1999
Sat Jan 02 00:00:00 1999
Tue Jan 19 00:00:00 1999
Wed Jan 20 00:00:00 1999
Sat May 01 00:00:00 1999
Sun May 02 00:00:00 1999
Wed May 19 00:00:00 1999
Thu May 20 00:00:00 1999
Tue Jun 01 00:00:00 1999
Wed Jun 02 00:00:00 1999
Mon Jul 19 00:00:00 1999
Tue Jul 20 00:00:00 1999
(12 rows)
DROP TABLE IF EXISTS pt2;
DROP TABLE IF EXISTS pt1;
CREATE TABLE pt1(
d_date date UNIQUE
)partition BY RANGE (d_date) INTERVAL('1 month')
(PARTITION part1 VALUES LESS THAN ('1900-01-01'))
;
NOTICE: CREATE TABLE / UNIQUE will create implicit index "pt1_d_date_key" for table "pt1"
CREATE TABLE pt2(
d_date date,
d_date_backup date
)partition BY RANGE (d_date_backup) INTERVAL('1 month')
(PARTITION part1 VALUES LESS THAN ('1900-01-01'));
ALTER TABLE pt2 ADD CONSTRAINT test_foreign FOREIGN KEY(d_date)
REFERENCES pt1(d_date) on UPDATE SET NULL ON DELETE SET NULL;
INSERT INTO pt1 VALUES
('1999-01-01'),('1999-01-02'),('1999-01-019'),('1999-01-20'),
('1999-02-01'),('1999-02-02'),('1999-02-19'),('1999-02-20'),
('1999-03-01'),('1999-03-02'),('1999-03-19'),('1999-03-20'),
('1999-04-01'),('1999-04-02'),('1999-04-19'),('1999-04-20'),
('1999-05-01'),('1999-05-02'),('1999-05-19'),('1999-05-20'),
('1999-06-01'),('1999-06-02'),('1999-06-19'),('1999-06-20'),
('1999-07-01'),('1999-07-02'),('1999-07-19'),('1999-07-20'),
('1999-08-01'),('1999-08-02'),('1999-08-19'),('1999-08-20'),
('1999-09-01'),('1999-09-02'),('1999-09-19'),('1999-09-20'),
('1999-10-01'),('1999-10-02'),('1999-10-19'),('1999-10-20'),
('1999-11-01'),('1999-11-02'),('1999-11-19'),('1999-11-20'),
('1999-12-01'),('1999-12-02'),('1999-12-19'),('1999-12-20');
INSERT INTO pt2 VALUES
('1999-01-01','1999-01-01'),('1999-01-02','1999-01-02'),
('1999-01-19','1999-01-19'),('1999-01-20','1999-01-20'),
('1999-02-01','1999-02-01'),('1999-02-02','1999-02-02'),
('1999-02-19','1999-02-19'),('1999-02-20','1999-02-20'),
('1999-03-01','1999-03-01'),('1999-03-02','1999-03-02'),
('1999-03-19','1999-03-19'),('1999-03-20','1999-03-20'),
('1999-04-01','1999-04-01'),('1999-04-02','1999-04-02'),
('1999-04-19','1999-04-19'),('1999-04-20','1999-04-20'),
('1999-05-01','1999-05-01'),('1999-05-02','1999-05-02'),
('1999-05-19','1999-05-19'),('1999-05-20','1999-05-20'),
('1999-06-01','1999-06-01'),('1999-06-02','1999-06-02'),
('1999-06-19','1999-06-19'),('1999-06-20','1999-06-20'),
('1999-07-01','1999-07-01'),('1999-07-02','1999-07-02'),
('1999-07-19','1999-07-19'),('1999-07-20','1999-07-20'),
('1999-08-01','1999-08-01'),('1999-08-02','1999-08-02'),
('1999-08-19','1999-08-19'),('1999-08-20','1999-08-20'),
('1999-09-01','1999-09-01'),('1999-09-02','1999-09-02'),
('1999-09-19','1999-09-19'),('1999-09-20','1999-09-20'),
('1999-10-01','1999-10-01'),('1999-10-02','1999-10-02'),
('1999-10-19','1999-10-19'),('1999-10-20','1999-10-20'),
('1999-11-01','1999-11-01'),('1999-11-02','1999-11-02'),
('1999-11-19','1999-11-19'),('1999-11-20','1999-11-20'),
('1999-12-01','1999-12-01'),('1999-12-02','1999-12-02'),
('1999-12-19','1999-12-19'),('1999-12-20','1999-12-20');
insert into pt1 VALUES('2000-01-01'),('2000-01-02'),
('2000-01-19'),('2000-01-20'),
('2000-02-01'),('2000-02-02'),
('2000-02-19'),('2000-02-20');
SELECT * FROM pt1 WHERE d_date>='2000-01-01';
d_date
--------------------------
Sat Jan 01 00:00:00 2000
Sun Jan 02 00:00:00 2000
Wed Jan 19 00:00:00 2000
Thu Jan 20 00:00:00 2000
Tue Feb 01 00:00:00 2000
Wed Feb 02 00:00:00 2000
Sat Feb 19 00:00:00 2000
Sun Feb 20 00:00:00 2000
(8 rows)
update pt1 set d_date = '2000-02-21' WHERE d_date = '2000-02-20';
SELECT * FROM pt1 WHERE d_date>='2000-02-01';
d_date
--------------------------
Tue Feb 01 00:00:00 2000
Wed Feb 02 00:00:00 2000
Sat Feb 19 00:00:00 2000
Mon Feb 21 00:00:00 2000
(4 rows)
DELETE FROM pt1 WHERE d_date = '2000-02-21';
SELECT * FROM pt1 WHERE d_date>='2000-02-01';
d_date
--------------------------
Tue Feb 01 00:00:00 2000
Wed Feb 02 00:00:00 2000
Sat Feb 19 00:00:00 2000
(3 rows)
SELECT * FROM pt1 PARTITION FOR('1999-06-16');
d_date
--------------------------
Tue Jun 01 00:00:00 1999
Wed Jun 02 00:00:00 1999
Sat Jun 19 00:00:00 1999
Sun Jun 20 00:00:00 1999
(4 rows)
INSERT into pt2 VALUES('2020-08-19','2020-08-19');
ERROR: insert or update on table "pt2" violates foreign key constraint "test_foreign"
DETAIL: Key (d_date)=(Wed Aug 19 00:00:00 2020) is not present in table "pt1".
INSERT into pt2 VALUES('2000-01-01','2000-01-01');
update pt2 set pt2.d_date = '2020-08-13'
where pt2.d_date = '1999-01-01';
ERROR: insert or update on table "pt2" violates foreign key constraint "test_foreign"
DETAIL: Key (d_date)=(Thu Aug 13 00:00:00 2020) is not present in table "pt1".
update pt2 set pt2.d_date = '2000-02-01',pt2.d_date_backup = '2000-02-01'
where pt2.d_date = '2000-01-01';
SELECT * FROM pt2;
d_date | d_date_backup
--------------------------+--------------------------
Fri Jan 01 00:00:00 1999 | Fri Jan 01 00:00:00 1999
Sat Jan 02 00:00:00 1999 | Sat Jan 02 00:00:00 1999
Tue Jan 19 00:00:00 1999 | Tue Jan 19 00:00:00 1999
Wed Jan 20 00:00:00 1999 | Wed Jan 20 00:00:00 1999
Mon Feb 01 00:00:00 1999 | Mon Feb 01 00:00:00 1999
Tue Feb 02 00:00:00 1999 | Tue Feb 02 00:00:00 1999
Fri Feb 19 00:00:00 1999 | Fri Feb 19 00:00:00 1999
Sat Feb 20 00:00:00 1999 | Sat Feb 20 00:00:00 1999
Mon Mar 01 00:00:00 1999 | Mon Mar 01 00:00:00 1999
Tue Mar 02 00:00:00 1999 | Tue Mar 02 00:00:00 1999
Fri Mar 19 00:00:00 1999 | Fri Mar 19 00:00:00 1999
Sat Mar 20 00:00:00 1999 | Sat Mar 20 00:00:00 1999
Thu Apr 01 00:00:00 1999 | Thu Apr 01 00:00:00 1999
Fri Apr 02 00:00:00 1999 | Fri Apr 02 00:00:00 1999
Mon Apr 19 00:00:00 1999 | Mon Apr 19 00:00:00 1999
Tue Apr 20 00:00:00 1999 | Tue Apr 20 00:00:00 1999
Sat May 01 00:00:00 1999 | Sat May 01 00:00:00 1999
Sun May 02 00:00:00 1999 | Sun May 02 00:00:00 1999
Wed May 19 00:00:00 1999 | Wed May 19 00:00:00 1999
Thu May 20 00:00:00 1999 | Thu May 20 00:00:00 1999
Tue Jun 01 00:00:00 1999 | Tue Jun 01 00:00:00 1999
Wed Jun 02 00:00:00 1999 | Wed Jun 02 00:00:00 1999
Sat Jun 19 00:00:00 1999 | Sat Jun 19 00:00:00 1999
Sun Jun 20 00:00:00 1999 | Sun Jun 20 00:00:00 1999
Thu Jul 01 00:00:00 1999 | Thu Jul 01 00:00:00 1999
Fri Jul 02 00:00:00 1999 | Fri Jul 02 00:00:00 1999
Mon Jul 19 00:00:00 1999 | Mon Jul 19 00:00:00 1999
Tue Jul 20 00:00:00 1999 | Tue Jul 20 00:00:00 1999
Sun Aug 01 00:00:00 1999 | Sun Aug 01 00:00:00 1999
Mon Aug 02 00:00:00 1999 | Mon Aug 02 00:00:00 1999
Thu Aug 19 00:00:00 1999 | Thu Aug 19 00:00:00 1999
Fri Aug 20 00:00:00 1999 | Fri Aug 20 00:00:00 1999
Wed Sep 01 00:00:00 1999 | Wed Sep 01 00:00:00 1999
Thu Sep 02 00:00:00 1999 | Thu Sep 02 00:00:00 1999
Sun Sep 19 00:00:00 1999 | Sun Sep 19 00:00:00 1999
Mon Sep 20 00:00:00 1999 | Mon Sep 20 00:00:00 1999
Fri Oct 01 00:00:00 1999 | Fri Oct 01 00:00:00 1999
Sat Oct 02 00:00:00 1999 | Sat Oct 02 00:00:00 1999
Tue Oct 19 00:00:00 1999 | Tue Oct 19 00:00:00 1999
Wed Oct 20 00:00:00 1999 | Wed Oct 20 00:00:00 1999
Mon Nov 01 00:00:00 1999 | Mon Nov 01 00:00:00 1999
Tue Nov 02 00:00:00 1999 | Tue Nov 02 00:00:00 1999
Fri Nov 19 00:00:00 1999 | Fri Nov 19 00:00:00 1999
Sat Nov 20 00:00:00 1999 | Sat Nov 20 00:00:00 1999
Wed Dec 01 00:00:00 1999 | Wed Dec 01 00:00:00 1999
Thu Dec 02 00:00:00 1999 | Thu Dec 02 00:00:00 1999
Sun Dec 19 00:00:00 1999 | Sun Dec 19 00:00:00 1999
Mon Dec 20 00:00:00 1999 | Mon Dec 20 00:00:00 1999
Tue Feb 01 00:00:00 2000 | Tue Feb 01 00:00:00 2000
(49 rows)
SELECT * FROM pt2 PARTITION(sys_p2);
d_date | d_date_backup
--------------------------+--------------------------
Mon Feb 01 00:00:00 1999 | Mon Feb 01 00:00:00 1999
Tue Feb 02 00:00:00 1999 | Tue Feb 02 00:00:00 1999
Fri Feb 19 00:00:00 1999 | Fri Feb 19 00:00:00 1999
Sat Feb 20 00:00:00 1999 | Sat Feb 20 00:00:00 1999
(4 rows)
delete from pt2 where pt2.d_date<'1999-03-01';
select * from pt2 where pt2.d_date<'1999-06-01';
d_date | d_date_backup
--------------------------+--------------------------
Mon Mar 01 00:00:00 1999 | Mon Mar 01 00:00:00 1999
Tue Mar 02 00:00:00 1999 | Tue Mar 02 00:00:00 1999
Fri Mar 19 00:00:00 1999 | Fri Mar 19 00:00:00 1999
Sat Mar 20 00:00:00 1999 | Sat Mar 20 00:00:00 1999
Thu Apr 01 00:00:00 1999 | Thu Apr 01 00:00:00 1999
Fri Apr 02 00:00:00 1999 | Fri Apr 02 00:00:00 1999
Mon Apr 19 00:00:00 1999 | Mon Apr 19 00:00:00 1999
Tue Apr 20 00:00:00 1999 | Tue Apr 20 00:00:00 1999
Sat May 01 00:00:00 1999 | Sat May 01 00:00:00 1999
Sun May 02 00:00:00 1999 | Sun May 02 00:00:00 1999
Wed May 19 00:00:00 1999 | Wed May 19 00:00:00 1999
Thu May 20 00:00:00 1999 | Thu May 20 00:00:00 1999
(12 rows)
delete from pt1 where d_date<'1999-05-01';
select * from pt1 where d_date<'1999-06-01';
d_date
--------------------------
Sat May 01 00:00:00 1999
Sun May 02 00:00:00 1999
Wed May 19 00:00:00 1999
Thu May 20 00:00:00 1999
(4 rows)
select * from pt2 where d_date_backup<'1999-06-01';
d_date | d_date_backup
--------------------------+--------------------------
| Mon Mar 01 00:00:00 1999
| Tue Mar 02 00:00:00 1999
| Fri Mar 19 00:00:00 1999
| Sat Mar 20 00:00:00 1999
| Thu Apr 01 00:00:00 1999
| Fri Apr 02 00:00:00 1999
| Mon Apr 19 00:00:00 1999
| Tue Apr 20 00:00:00 1999
Sat May 01 00:00:00 1999 | Sat May 01 00:00:00 1999
Sun May 02 00:00:00 1999 | Sun May 02 00:00:00 1999
Wed May 19 00:00:00 1999 | Wed May 19 00:00:00 1999
Thu May 20 00:00:00 1999 | Thu May 20 00:00:00 1999
(12 rows)
delete from pt2 where pt2.d_date>'1999-11-15' and pt2.d_date<'1999-12-15';
SELECT * FROM pt2 WHERE pt2.d_date>='1999-10-01';
d_date | d_date_backup
--------------------------+--------------------------
Fri Oct 01 00:00:00 1999 | Fri Oct 01 00:00:00 1999
Sat Oct 02 00:00:00 1999 | Sat Oct 02 00:00:00 1999
Tue Oct 19 00:00:00 1999 | Tue Oct 19 00:00:00 1999
Wed Oct 20 00:00:00 1999 | Wed Oct 20 00:00:00 1999
Mon Nov 01 00:00:00 1999 | Mon Nov 01 00:00:00 1999
Tue Nov 02 00:00:00 1999 | Tue Nov 02 00:00:00 1999
Sun Dec 19 00:00:00 1999 | Sun Dec 19 00:00:00 1999
Mon Dec 20 00:00:00 1999 | Mon Dec 20 00:00:00 1999
Tue Feb 01 00:00:00 2000 | Tue Feb 01 00:00:00 2000
(9 rows)
delete from pt1 where pt1.d_date>'1999-10-15' and pt1.d_date<'1999-11-15';
SELECT * FROM pt1 WHERE pt1.d_date>='1999-10-01';
d_date
--------------------------
Fri Oct 01 00:00:00 1999
Sat Oct 02 00:00:00 1999
Fri Nov 19 00:00:00 1999
Sat Nov 20 00:00:00 1999
Wed Dec 01 00:00:00 1999
Thu Dec 02 00:00:00 1999
Sun Dec 19 00:00:00 1999
Mon Dec 20 00:00:00 1999
Sat Jan 01 00:00:00 2000
Sun Jan 02 00:00:00 2000
Wed Jan 19 00:00:00 2000
Thu Jan 20 00:00:00 2000
Tue Feb 01 00:00:00 2000
Wed Feb 02 00:00:00 2000
Sat Feb 19 00:00:00 2000
(15 rows)
SELECT * FROM pt2 WHERE pt2.d_date_backup>='1999-10-01';
d_date | d_date_backup
--------------------------+--------------------------
Fri Oct 01 00:00:00 1999 | Fri Oct 01 00:00:00 1999
Sat Oct 02 00:00:00 1999 | Sat Oct 02 00:00:00 1999
| Tue Oct 19 00:00:00 1999
| Wed Oct 20 00:00:00 1999
| Mon Nov 01 00:00:00 1999
| Tue Nov 02 00:00:00 1999
Sun Dec 19 00:00:00 1999 | Sun Dec 19 00:00:00 1999
Mon Dec 20 00:00:00 1999 | Mon Dec 20 00:00:00 1999
Tue Feb 01 00:00:00 2000 | Tue Feb 01 00:00:00 2000
(9 rows)
UPDATE pt2 set d_date = d_date - INTERVAL '4' month where d_date>='1999-05-01' and d_date<'1999-06-01';
ERROR: insert or update on table "pt2" violates foreign key constraint "test_foreign"
DETAIL: Key (d_date)=(Fri Jan 01 00:00:00 1999) is not present in table "pt1".
UPDATE pt1 set d_date = d_date - INTERVAL '4' month where d_date>='1999-05-01' and d_date<'1999-06-01';
SELECT * FROM pt1 WHERE d_date<'1999-07-01';
d_date
--------------------------
Fri Jan 01 00:00:00 1999
Sat Jan 02 00:00:00 1999
Tue Jan 19 00:00:00 1999
Wed Jan 20 00:00:00 1999
Tue Jun 01 00:00:00 1999
Wed Jun 02 00:00:00 1999
Sat Jun 19 00:00:00 1999
Sun Jun 20 00:00:00 1999
(8 rows)
SELECT * FROM pt2 WHERE d_date_backup<'1999-07-01';
d_date | d_date_backup
--------------------------+--------------------------
| Mon Mar 01 00:00:00 1999
| Tue Mar 02 00:00:00 1999
| Fri Mar 19 00:00:00 1999
| Sat Mar 20 00:00:00 1999
| Thu Apr 01 00:00:00 1999
| Fri Apr 02 00:00:00 1999
| Mon Apr 19 00:00:00 1999
| Tue Apr 20 00:00:00 1999
| Sat May 01 00:00:00 1999
| Sun May 02 00:00:00 1999
| Wed May 19 00:00:00 1999
| Thu May 20 00:00:00 1999
Tue Jun 01 00:00:00 1999 | Tue Jun 01 00:00:00 1999
Wed Jun 02 00:00:00 1999 | Wed Jun 02 00:00:00 1999
Sat Jun 19 00:00:00 1999 | Sat Jun 19 00:00:00 1999
Sun Jun 20 00:00:00 1999 | Sun Jun 20 00:00:00 1999
(16 rows)
UPDATE pt2 set d_date = d_date - INTERVAL '1' month where d_date>='1999-06-01' and d_date<='1999-07-15';
ERROR: insert or update on table "pt2" violates foreign key constraint "test_foreign"
DETAIL: Key (d_date)=(Sat May 01 00:00:00 1999) is not present in table "pt1".
UPDATE pt1 set d_date = d_date - INTERVAL '1' month where d_date>='1999-06-01' and d_date<='1999-07-15';
SELECT * FROM pt1 WHERE d_date<'1999-08-01';
d_date
--------------------------
Fri Jan 01 00:00:00 1999
Sat Jan 02 00:00:00 1999
Tue Jan 19 00:00:00 1999
Wed Jan 20 00:00:00 1999
Sat May 01 00:00:00 1999
Sun May 02 00:00:00 1999
Wed May 19 00:00:00 1999
Thu May 20 00:00:00 1999
Tue Jun 01 00:00:00 1999
Wed Jun 02 00:00:00 1999
Mon Jul 19 00:00:00 1999
Tue Jul 20 00:00:00 1999
(12 rows)
SELECT * FROM pt2 WHERE d_date_backup<'1999-08-01';
d_date | d_date_backup
--------------------------+--------------------------
| Mon Mar 01 00:00:00 1999
| Tue Mar 02 00:00:00 1999
| Fri Mar 19 00:00:00 1999
| Sat Mar 20 00:00:00 1999
| Thu Apr 01 00:00:00 1999
| Fri Apr 02 00:00:00 1999
| Mon Apr 19 00:00:00 1999
| Tue Apr 20 00:00:00 1999
| Sat May 01 00:00:00 1999
| Sun May 02 00:00:00 1999
| Wed May 19 00:00:00 1999
| Thu May 20 00:00:00 1999
| Tue Jun 01 00:00:00 1999
| Wed Jun 02 00:00:00 1999
| Sat Jun 19 00:00:00 1999
| Sun Jun 20 00:00:00 1999
Mon Jul 19 00:00:00 1999 | Mon Jul 19 00:00:00 1999
Tue Jul 20 00:00:00 1999 | Tue Jul 20 00:00:00 1999
| Thu Jul 01 00:00:00 1999
| Fri Jul 02 00:00:00 1999
(20 rows)
DROP TABLE IF EXISTS pt2;
DROP TABLE IF EXISTS pt1;
CREATE TABLE pt1(
d_date date UNIQUE
)partition BY RANGE (d_date) INTERVAL('1 month')
(PARTITION part1 VALUES LESS THAN ('1900-01-01'));
NOTICE: CREATE TABLE / UNIQUE will create implicit index "pt1_d_date_key" for table "pt1"
CREATE TABLE pt2(
d_date date,
d_date_backup date
)partition BY RANGE (d_date_backup) INTERVAL('1 month')
(PARTITION part1 VALUES LESS THAN ('1900-01-01'));
ALTER TABLE pt2 ADD CONSTRAINT test_foreign FOREIGN KEY(d_date)
REFERENCES pt1(d_date) on UPDATE RESTRICT ON DELETE RESTRICT;
INSERT INTO pt1 VALUES
('1999-01-01'),('1999-01-02'),('1999-01-019'),('1999-01-20'),
('1999-02-01'),('1999-02-02'),('1999-02-19'),('1999-02-20'),
('1999-03-01'),('1999-03-02'),('1999-03-19'),('1999-03-20'),
('1999-04-01'),('1999-04-02'),('1999-04-19'),('1999-04-20'),
('1999-05-01'),('1999-05-02'),('1999-05-19'),('1999-05-20'),
('1999-06-01'),('1999-06-02'),('1999-06-19'),('1999-06-20'),
('1999-07-01'),('1999-07-02'),('1999-07-19'),('1999-07-20'),
('1999-08-01'),('1999-08-02'),('1999-08-19'),('1999-08-20'),
('1999-09-01'),('1999-09-02'),('1999-09-19'),('1999-09-20'),
('1999-10-01'),('1999-10-02'),('1999-10-19'),('1999-10-20'),
('1999-11-01'),('1999-11-02'),('1999-11-19'),('1999-11-20'),
('1999-12-01'),('1999-12-02'),('1999-12-19'),('1999-12-20');
INSERT INTO pt2 VALUES
('1999-01-01','1999-01-01'),('1999-01-02','1999-01-02'),
('1999-01-19','1999-01-19'),('1999-01-20','1999-01-20'),
('1999-02-01','1999-02-01'),('1999-02-02','1999-02-02'),
('1999-02-19','1999-02-19'),('1999-02-20','1999-02-20'),
('1999-03-01','1999-03-01'),('1999-03-02','1999-03-02'),
('1999-03-19','1999-03-19'),('1999-03-20','1999-03-20'),
('1999-04-01','1999-04-01'),('1999-04-02','1999-04-02'),
('1999-04-19','1999-04-19'),('1999-04-20','1999-04-20'),
('1999-05-01','1999-05-01'),('1999-05-02','1999-05-02'),
('1999-05-19','1999-05-19'),('1999-05-20','1999-05-20'),
('1999-06-01','1999-06-01'),('1999-06-02','1999-06-02'),
('1999-06-19','1999-06-19'),('1999-06-20','1999-06-20'),
('1999-07-01','1999-07-01'),('1999-07-02','1999-07-02'),
('1999-07-19','1999-07-19'),('1999-07-20','1999-07-20'),
('1999-08-01','1999-08-01'),('1999-08-02','1999-08-02'),
('1999-08-19','1999-08-19'),('1999-08-20','1999-08-20'),
('1999-09-01','1999-09-01'),('1999-09-02','1999-09-02'),
('1999-09-19','1999-09-19'),('1999-09-20','1999-09-20'),
('1999-10-01','1999-10-01'),('1999-10-02','1999-10-02'),
('1999-10-19','1999-10-19'),('1999-10-20','1999-10-20'),
('1999-11-01','1999-11-01'),('1999-11-02','1999-11-02'),
('1999-11-19','1999-11-19'),('1999-11-20','1999-11-20'),
('1999-12-01','1999-12-01'),('1999-12-02','1999-12-02'),
('1999-12-19','1999-12-19'),('1999-12-20','1999-12-20');
delete from pt2 where pt2.d_date<'1999-03-01';
select * from pt2 where pt2.d_date<'1999-06-01';
d_date | d_date_backup
--------------------------+--------------------------
Mon Mar 01 00:00:00 1999 | Mon Mar 01 00:00:00 1999
Tue Mar 02 00:00:00 1999 | Tue Mar 02 00:00:00 1999
Fri Mar 19 00:00:00 1999 | Fri Mar 19 00:00:00 1999
Sat Mar 20 00:00:00 1999 | Sat Mar 20 00:00:00 1999
Thu Apr 01 00:00:00 1999 | Thu Apr 01 00:00:00 1999
Fri Apr 02 00:00:00 1999 | Fri Apr 02 00:00:00 1999
Mon Apr 19 00:00:00 1999 | Mon Apr 19 00:00:00 1999
Tue Apr 20 00:00:00 1999 | Tue Apr 20 00:00:00 1999
Sat May 01 00:00:00 1999 | Sat May 01 00:00:00 1999
Sun May 02 00:00:00 1999 | Sun May 02 00:00:00 1999
Wed May 19 00:00:00 1999 | Wed May 19 00:00:00 1999
Thu May 20 00:00:00 1999 | Thu May 20 00:00:00 1999
(12 rows)
delete from pt1 where d_date<'1999-05-01';
ERROR: update or delete on table "pt1" violates foreign key constraint "test_foreign" on table "pt2"
DETAIL: Key (d_date)=(Mon Mar 01 00:00:00 1999) is still referenced from table "pt2".
delete from pt2 where pt2.d_date>'1999-11-15' and pt2.d_date<'1999-12-15';
SELECT * FROM pt2 WHERE pt2.d_date>='1999-10-01';
d_date | d_date_backup
--------------------------+--------------------------
Fri Oct 01 00:00:00 1999 | Fri Oct 01 00:00:00 1999
Sat Oct 02 00:00:00 1999 | Sat Oct 02 00:00:00 1999
Tue Oct 19 00:00:00 1999 | Tue Oct 19 00:00:00 1999
Wed Oct 20 00:00:00 1999 | Wed Oct 20 00:00:00 1999
Mon Nov 01 00:00:00 1999 | Mon Nov 01 00:00:00 1999
Tue Nov 02 00:00:00 1999 | Tue Nov 02 00:00:00 1999
Sun Dec 19 00:00:00 1999 | Sun Dec 19 00:00:00 1999
Mon Dec 20 00:00:00 1999 | Mon Dec 20 00:00:00 1999
(8 rows)
delete from pt1 where pt1.d_date>'1999-10-15' and pt1.d_date<'1999-11-15';
ERROR: update or delete on table "pt1" violates foreign key constraint "test_foreign" on table "pt2"
DETAIL: Key (d_date)=(Tue Oct 19 00:00:00 1999) is still referenced from table "pt2".
delete from pt2 where pt2.d_date>='1999-01-01' and pt2.d_date<'1999-05-01';
delete from pt1 where pt1.d_date>='1999-01-01' and pt1.d_date<'1999-05-01';
UPDATE pt2 set d_date = d_date - INTERVAL '4' month where d_date>='1999-05-01' and d_date<'1999-06-01';
ERROR: insert or update on table "pt2" violates foreign key constraint "test_foreign"
DETAIL: Key (d_date)=(Fri Jan 01 00:00:00 1999) is not present in table "pt1".
UPDATE pt1 set d_date = d_date - INTERVAL '4' month where d_date>='1999-05-01' and d_date<'1999-06-01';
ERROR: update or delete on table "pt1" violates foreign key constraint "test_foreign" on table "pt2"
DETAIL: Key (d_date)=(Sat May 01 00:00:00 1999) is still referenced from table "pt2".
SELECT * FROM pt1 WHERE d_date<'1999-07-01';
d_date
--------------------------
Sat May 01 00:00:00 1999
Sun May 02 00:00:00 1999
Wed May 19 00:00:00 1999
Thu May 20 00:00:00 1999
Tue Jun 01 00:00:00 1999
Wed Jun 02 00:00:00 1999
Sat Jun 19 00:00:00 1999
Sun Jun 20 00:00:00 1999
(8 rows)
UPDATE pt2 set d_date = d_date - INTERVAL '1' month where d_date>='1999-06-01' and d_date<='1999-07-15';
UPDATE pt1 set d_date = d_date - INTERVAL '5' month where d_date>='1999-06-01' and d_date<='1999-07-15';
ERROR: update or delete on table "pt1" violates foreign key constraint "test_foreign" on table "pt2"
DETAIL: Key (d_date)=(Tue Jun 01 00:00:00 1999) is still referenced from table "pt2".
delete from pt2 where d_date>='1999-06-01' and d_date<='1999-07-15';
UPDATE pt1 set d_date = d_date - INTERVAL '5' month where d_date>='1999-06-01' and d_date<='1999-07-15';

View File

@ -0,0 +1,294 @@
DROP TABLE IF EXISTS pt2;
DROP TABLE IF EXISTS pt1;
DROP FUNCTION IF EXISTS test_function();
NOTICE: function test_function() does not exist, skipping
CREATE TABLE pt1(
d_date date UNIQUE
)partition BY RANGE (d_date) INTERVAL('1 month')
(PARTITION part1 VALUES LESS THAN ('1900-01-01'));
NOTICE: CREATE TABLE / UNIQUE will create implicit index "pt1_d_date_key" for table "pt1"
CREATE TABLE pt2(
d_date date
)partition BY RANGE (d_date) INTERVAL('1 month')
(PARTITION part1 VALUES LESS THAN ('1900-01-01'));
INSERT INTO pt1 VALUES
('1999-01-01'),('1999-01-02'),('1999-01-019'),('1999-01-20'),
('1999-02-01'),('1999-02-02'),('1999-02-19'),('1999-02-20'),
('1999-03-01'),('1999-03-02'),('1999-03-19'),('1999-03-20'),
('1999-04-01'),('1999-04-02'),('1999-04-19'),('1999-04-20'),
('1999-05-01'),('1999-05-02'),('1999-05-19'),('1999-05-20'),
('1999-06-01'),('1999-06-02'),('1999-06-19'),('1999-06-20'),
('1999-07-01'),('1999-07-02'),('1999-07-19'),('1999-07-20'),
('1999-08-01'),('1999-08-02'),('1999-08-19'),('1999-08-20'),
('1999-09-01'),('1999-09-02'),('1999-09-19'),('1999-09-20'),
('1999-10-01'),('1999-10-02'),('1999-10-19'),('1999-10-20'),
('1999-11-01'),('1999-11-02'),('1999-11-19'),('1999-11-20'),
('1999-12-01'),('1999-12-02'),('1999-12-19'),('1999-12-20');
INSERT INTO pt2 VALUES
('1999-01-01'),('1999-01-02'),('1999-01-019'),('1999-01-20'),
('1999-02-01'),('1999-02-02'),('1999-02-19'),('1999-02-20'),
('1999-03-01'),('1999-03-02'),('1999-03-19'),('1999-03-20'),
('1999-04-01'),('1999-04-02'),('1999-04-19'),('1999-04-20'),
('1999-05-01'),('1999-05-02'),('1999-05-19'),('1999-05-20'),
('1999-06-01'),('1999-06-02'),('1999-06-19'),('1999-06-20'),
('1999-07-01'),('1999-07-02'),('1999-07-19'),('1999-07-20'),
('1999-08-01'),('1999-08-02'),('1999-08-19'),('1999-08-20'),
('1999-09-01'),('1999-09-02'),('1999-09-19'),('1999-09-20'),
('1999-10-01'),('1999-10-02'),('1999-10-19'),('1999-10-20'),
('1999-11-01'),('1999-11-02'),('1999-11-19'),('1999-11-20'),
('1999-12-01'),('1999-12-02'),('1999-12-19'),('1999-12-20');
CREATE FUNCTION test_function()
RETURNS TRIGGER AS $$
BEGIN
IF(TG_OP = 'DELETE') THEN
DELETE FROM pt2 WHERE d_date=OLD.d_date;
RETURN OLD;
ELSEIF(TG_OP = 'UPDATE') THEN
UPDATE pt2 set d_date=NEW.d_date where d_date=OLD.d_date;
RETURN NEW;
ELSEIF(TG_OP = 'INSERT') THEN
INSERT INTO pt2 VALUES(NEW.d_date);
RETURN NEW;
END IF;
RETURN NULL;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER test_trigger
AFTER INSERT OR UPDATE OR DELETE on pt1
FOR EACH ROW EXECUTE PROCEDURE test_function();
INSERT INTO pt1 VALUES('2016-01-01');
UPDATE pt2 set d_date = d_date + INTERVAL '4' month where d_date>='1999-05-01';
DELETE FROM pt1 WHERE d_date<'1999-05-01';
SELECT * FROM pt1;
d_date
--------------------------
Sat May 01 00:00:00 1999
Sun May 02 00:00:00 1999
Wed May 19 00:00:00 1999
Thu May 20 00:00:00 1999
Tue Jun 01 00:00:00 1999
Wed Jun 02 00:00:00 1999
Sat Jun 19 00:00:00 1999
Sun Jun 20 00:00:00 1999
Thu Jul 01 00:00:00 1999
Fri Jul 02 00:00:00 1999
Mon Jul 19 00:00:00 1999
Tue Jul 20 00:00:00 1999
Sun Aug 01 00:00:00 1999
Mon Aug 02 00:00:00 1999
Thu Aug 19 00:00:00 1999
Fri Aug 20 00:00:00 1999
Wed Sep 01 00:00:00 1999
Thu Sep 02 00:00:00 1999
Sun Sep 19 00:00:00 1999
Mon Sep 20 00:00:00 1999
Fri Oct 01 00:00:00 1999
Sat Oct 02 00:00:00 1999
Tue Oct 19 00:00:00 1999
Wed Oct 20 00:00:00 1999
Mon Nov 01 00:00:00 1999
Tue Nov 02 00:00:00 1999
Fri Nov 19 00:00:00 1999
Sat Nov 20 00:00:00 1999
Wed Dec 01 00:00:00 1999
Thu Dec 02 00:00:00 1999
Sun Dec 19 00:00:00 1999
Mon Dec 20 00:00:00 1999
Fri Jan 01 00:00:00 2016
(33 rows)
SELECT * FROM pt2;
d_date
--------------------------
Wed Sep 01 00:00:00 1999
Thu Sep 02 00:00:00 1999
Sun Sep 19 00:00:00 1999
Mon Sep 20 00:00:00 1999
Fri Oct 01 00:00:00 1999
Sat Oct 02 00:00:00 1999
Tue Oct 19 00:00:00 1999
Wed Oct 20 00:00:00 1999
Mon Nov 01 00:00:00 1999
Tue Nov 02 00:00:00 1999
Fri Nov 19 00:00:00 1999
Sat Nov 20 00:00:00 1999
Wed Dec 01 00:00:00 1999
Thu Dec 02 00:00:00 1999
Sun Dec 19 00:00:00 1999
Mon Dec 20 00:00:00 1999
Sat Jan 01 00:00:00 2000
Sun Jan 02 00:00:00 2000
Wed Jan 19 00:00:00 2000
Thu Jan 20 00:00:00 2000
Tue Feb 01 00:00:00 2000
Wed Feb 02 00:00:00 2000
Sat Feb 19 00:00:00 2000
Sun Feb 20 00:00:00 2000
Wed Mar 01 00:00:00 2000
Thu Mar 02 00:00:00 2000
Sun Mar 19 00:00:00 2000
Mon Mar 20 00:00:00 2000
Sat Apr 01 00:00:00 2000
Sun Apr 02 00:00:00 2000
Wed Apr 19 00:00:00 2000
Thu Apr 20 00:00:00 2000
Sun May 01 00:00:00 2016
(33 rows)
DROP TABLE IF EXISTS pt2;
DROP TABLE IF EXISTS pt1;
DROP FUNCTION IF EXISTS test_function();
CREATE TABLE pt1(
d_date date UNIQUE
)partition BY RANGE (d_date) INTERVAL('1 month')
(PARTITION part1 VALUES LESS THAN ('1900-01-01'));
NOTICE: CREATE TABLE / UNIQUE will create implicit index "pt1_d_date_key" for table "pt1"
CREATE TABLE pt2(
d_date date
)partition BY RANGE (d_date) INTERVAL('1 month')
(PARTITION part1 VALUES LESS THAN ('1900-01-01'));
INSERT INTO pt1 VALUES
('1999-01-01'),('1999-01-02'),('1999-01-019'),('1999-01-20'),
('1999-02-01'),('1999-02-02'),('1999-02-19'),('1999-02-20'),
('1999-03-01'),('1999-03-02'),('1999-03-19'),('1999-03-20'),
('1999-04-01'),('1999-04-02'),('1999-04-19'),('1999-04-20'),
('1999-05-01'),('1999-05-02'),('1999-05-19'),('1999-05-20'),
('1999-06-01'),('1999-06-02'),('1999-06-19'),('1999-06-20'),
('1999-07-01'),('1999-07-02'),('1999-07-19'),('1999-07-20'),
('1999-08-01'),('1999-08-02'),('1999-08-19'),('1999-08-20'),
('1999-09-01'),('1999-09-02'),('1999-09-19'),('1999-09-20'),
('1999-10-01'),('1999-10-02'),('1999-10-19'),('1999-10-20'),
('1999-11-01'),('1999-11-02'),('1999-11-19'),('1999-11-20'),
('1999-12-01'),('1999-12-02'),('1999-12-19'),('1999-12-20');
INSERT INTO pt2 VALUES
('1999-01-01'),('1999-01-02'),('1999-01-019'),('1999-01-20'),
('1999-02-01'),('1999-02-02'),('1999-02-19'),('1999-02-20'),
('1999-03-01'),('1999-03-02'),('1999-03-19'),('1999-03-20'),
('1999-04-01'),('1999-04-02'),('1999-04-19'),('1999-04-20'),
('1999-05-01'),('1999-05-02'),('1999-05-19'),('1999-05-20'),
('1999-06-01'),('1999-06-02'),('1999-06-19'),('1999-06-20'),
('1999-07-01'),('1999-07-02'),('1999-07-19'),('1999-07-20'),
('1999-08-01'),('1999-08-02'),('1999-08-19'),('1999-08-20'),
('1999-09-01'),('1999-09-02'),('1999-09-19'),('1999-09-20'),
('1999-10-01'),('1999-10-02'),('1999-10-19'),('1999-10-20'),
('1999-11-01'),('1999-11-02'),('1999-11-19'),('1999-11-20'),
('1999-12-01'),('1999-12-02'),('1999-12-19'),('1999-12-20');
CREATE FUNCTION test_function()
RETURNS TRIGGER AS $$
BEGIN
IF(TG_OP = 'DELETE') THEN
DELETE FROM pt2 WHERE d_date=OLD.d_date;
RETURN OLD;
ELSEIF(TG_OP = 'UPDATE') THEN
UPDATE pt2 set d_date=NEW.d_date where d_date=OLD.d_date;
RETURN NEW;
ELSEIF(TG_OP = 'INSERT') THEN
INSERT INTO pt2 VALUES(NEW.d_date);
RETURN NEW;
END IF;
RETURN NULL;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER test_trigger
BEFORE INSERT OR UPDATE OR DELETE on pt1
FOR EACH ROW EXECUTE PROCEDURE test_function();
INSERT INTO pt1 VALUES('2016-01-01');
UPDATE pt2 set d_date = d_date + INTERVAL '4' month where d_date>='1999-05-01';
DELETE FROM pt1 WHERE d_date<'1999-05-01';
SELECT * FROM pt1;
d_date
--------------------------
Sat May 01 00:00:00 1999
Sun May 02 00:00:00 1999
Wed May 19 00:00:00 1999
Thu May 20 00:00:00 1999
Tue Jun 01 00:00:00 1999
Wed Jun 02 00:00:00 1999
Sat Jun 19 00:00:00 1999
Sun Jun 20 00:00:00 1999
Thu Jul 01 00:00:00 1999
Fri Jul 02 00:00:00 1999
Mon Jul 19 00:00:00 1999
Tue Jul 20 00:00:00 1999
Sun Aug 01 00:00:00 1999
Mon Aug 02 00:00:00 1999
Thu Aug 19 00:00:00 1999
Fri Aug 20 00:00:00 1999
Wed Sep 01 00:00:00 1999
Thu Sep 02 00:00:00 1999
Sun Sep 19 00:00:00 1999
Mon Sep 20 00:00:00 1999
Fri Oct 01 00:00:00 1999
Sat Oct 02 00:00:00 1999
Tue Oct 19 00:00:00 1999
Wed Oct 20 00:00:00 1999
Mon Nov 01 00:00:00 1999
Tue Nov 02 00:00:00 1999
Fri Nov 19 00:00:00 1999
Sat Nov 20 00:00:00 1999
Wed Dec 01 00:00:00 1999
Thu Dec 02 00:00:00 1999
Sun Dec 19 00:00:00 1999
Mon Dec 20 00:00:00 1999
Fri Jan 01 00:00:00 2016
(33 rows)
SELECT * FROM pt2;
d_date
--------------------------
Wed Sep 01 00:00:00 1999
Thu Sep 02 00:00:00 1999
Sun Sep 19 00:00:00 1999
Mon Sep 20 00:00:00 1999
Fri Oct 01 00:00:00 1999
Sat Oct 02 00:00:00 1999
Tue Oct 19 00:00:00 1999
Wed Oct 20 00:00:00 1999
Mon Nov 01 00:00:00 1999
Tue Nov 02 00:00:00 1999
Fri Nov 19 00:00:00 1999
Sat Nov 20 00:00:00 1999
Wed Dec 01 00:00:00 1999
Thu Dec 02 00:00:00 1999
Sun Dec 19 00:00:00 1999
Mon Dec 20 00:00:00 1999
Sat Jan 01 00:00:00 2000
Sun Jan 02 00:00:00 2000
Wed Jan 19 00:00:00 2000
Thu Jan 20 00:00:00 2000
Tue Feb 01 00:00:00 2000
Wed Feb 02 00:00:00 2000
Sat Feb 19 00:00:00 2000
Sun Feb 20 00:00:00 2000
Wed Mar 01 00:00:00 2000
Thu Mar 02 00:00:00 2000
Sun Mar 19 00:00:00 2000
Mon Mar 20 00:00:00 2000
Sat Apr 01 00:00:00 2000
Sun Apr 02 00:00:00 2000
Wed Apr 19 00:00:00 2000
Thu Apr 20 00:00:00 2000
Sun May 01 00:00:00 2016
(33 rows)

View File

@ -1185,6 +1185,7 @@ WHERE d.classoid IS NULL AND p1.oid <= 9999 order by 1;
2096 | pg_terminate_backend
2097 | pg_get_variable_info
2098 | pg_get_functiondef
2099 | pg_terminate_session
2100 | avg
2101 | avg
2102 | avg
@ -2676,7 +2677,7 @@ WHERE d.classoid IS NULL AND p1.oid <= 9999 order by 1;
9016 | pg_advisory_lock
9017 | pgxc_unlock_for_sp_database
9999 | pg_test_err_contain_err
(2275 rows)
(2276 rows)
-- Check prokind
select count(*) from pg_proc where prokind = 'a';
@ -2694,7 +2695,7 @@ select count(*) from pg_proc where prokind = 'w';
select count(*) from pg_proc where prokind = 'f';
count
-------
3149
3150
(1 row)
select count(*) from pg_proc where prokind = 'p';

View File

@ -2868,33 +2868,34 @@ NOTICE: CREATE TABLE will create implicit sequence "loc1_f1_seq" for serial col
create foreign table rem1 (f1 serial, f2 text)
server loopback options(table_name 'loc1');
NOTICE: CREATE FOREIGN TABLE will create implicit sequence "rem1_f1_seq" for serial column "rem1.f1"
ERROR: referenced relation "rem1" is not a table
select pg_catalog.setval('rem1_f1_seq', 10, false);
ERROR: relation "rem1_f1_seq" does not exist
LINE 1: select pg_catalog.setval('rem1_f1_seq', 10, false);
^
CONTEXT: referenced column: setval
setval
--------
10
(1 row)
insert into loc1(f2) values('hi');
insert into rem1(f2) values('hi remote');
ERROR: relation "rem1" does not exist on datanode1
LINE 1: insert into rem1(f2) values('hi remote');
^
insert into loc1(f2) values('bye');
insert into rem1(f2) values('bye remote');
ERROR: relation "rem1" does not exist on datanode1
LINE 1: insert into rem1(f2) values('bye remote');
^
select * from loc1;
f1 | f2
----+-----
f1 | f2
----+------------
1 | hi
10 | hi remote
2 | bye
(2 rows)
11 | bye remote
(4 rows)
select * from rem1;
ERROR: relation "rem1" does not exist on datanode1
LINE 1: select * from rem1;
^
f1 | f2
----+------------
1 | hi
10 | hi remote
2 | bye
11 | bye remote
(4 rows)
-- ===================================================================
-- test local triggers
-- ===================================================================
@ -2907,10 +2908,10 @@ BEGIN
END;$$;
CREATE TRIGGER trig_stmt_before BEFORE DELETE OR INSERT OR UPDATE ON rem1
FOR EACH STATEMENT EXECUTE PROCEDURE trigger_func();
ERROR: relation "rem1" does not exist
ERROR: "rem1" is not a table or view
CREATE TRIGGER trig_stmt_after AFTER DELETE OR INSERT OR UPDATE ON rem1
FOR EACH STATEMENT EXECUTE PROCEDURE trigger_func();
ERROR: relation "rem1" does not exist
ERROR: "rem1" is not a table or view
CREATE OR REPLACE FUNCTION trigger_data() RETURNS trigger
LANGUAGE plpgsql AS $$
@ -2953,97 +2954,67 @@ $$;
CREATE TRIGGER trig_row_before
BEFORE INSERT OR UPDATE OR DELETE ON rem1
FOR EACH ROW EXECUTE PROCEDURE trigger_data(23,'skidoo');
ERROR: relation "rem1" does not exist
ERROR: "rem1" is not a table or view
CREATE TRIGGER trig_row_after
AFTER INSERT OR UPDATE OR DELETE ON rem1
FOR EACH ROW EXECUTE PROCEDURE trigger_data(23,'skidoo');
ERROR: relation "rem1" does not exist
ERROR: "rem1" is not a table or view
delete from rem1;
ERROR: relation "rem1" does not exist on datanode1
LINE 1: delete from rem1;
^
insert into rem1 values(1,'insert');
ERROR: relation "rem1" does not exist on datanode1
LINE 1: insert into rem1 values(1,'insert');
^
update rem1 set f2 = 'update' where f1 = 1;
ERROR: relation "rem1" does not exist on datanode1
LINE 1: update rem1 set f2 = 'update' where f1 = 1;
^
update rem1 set f2 = f2 || f2;
ERROR: relation "rem1" does not exist on datanode1
LINE 1: update rem1 set f2 = f2 || f2;
^
-- cleanup
DROP TRIGGER trig_row_before ON rem1;
ERROR: relation "rem1" does not exist
ERROR: trigger "trig_row_before" for table "rem1" does not exist
DROP TRIGGER trig_row_after ON rem1;
ERROR: relation "rem1" does not exist
ERROR: trigger "trig_row_after" for table "rem1" does not exist
DROP TRIGGER trig_stmt_before ON rem1;
ERROR: relation "rem1" does not exist
ERROR: trigger "trig_stmt_before" for table "rem1" does not exist
DROP TRIGGER trig_stmt_after ON rem1;
ERROR: relation "rem1" does not exist
ERROR: trigger "trig_stmt_after" for table "rem1" does not exist
DELETE from rem1;
ERROR: relation "rem1" does not exist on datanode1
LINE 1: DELETE from rem1;
^
-- Test WHEN conditions
CREATE TRIGGER trig_row_before_insupd
BEFORE INSERT OR UPDATE ON rem1
FOR EACH ROW
WHEN (NEW.f2 like '%update%')
EXECUTE PROCEDURE trigger_data(23,'skidoo');
ERROR: relation "rem1" does not exist
ERROR: "rem1" is not a table or view
CREATE TRIGGER trig_row_after_insupd
AFTER INSERT OR UPDATE ON rem1
FOR EACH ROW
WHEN (NEW.f2 like '%update%')
EXECUTE PROCEDURE trigger_data(23,'skidoo');
ERROR: relation "rem1" does not exist
ERROR: "rem1" is not a table or view
-- Insert or update not matching: nothing happens
INSERT INTO rem1 values(1, 'insert');
ERROR: relation "rem1" does not exist on datanode1
LINE 1: INSERT INTO rem1 values(1, 'insert');
^
UPDATE rem1 set f2 = 'test';
ERROR: relation "rem1" does not exist on datanode1
LINE 1: UPDATE rem1 set f2 = 'test';
^
-- Insert or update matching: triggers are fired
INSERT INTO rem1 values(2, 'update');
ERROR: relation "rem1" does not exist on datanode1
LINE 1: INSERT INTO rem1 values(2, 'update');
^
UPDATE rem1 set f2 = 'update update' where f1 = '2';
ERROR: relation "rem1" does not exist on datanode1
LINE 1: UPDATE rem1 set f2 = 'update update' where f1 = '2';
^
CREATE TRIGGER trig_row_before_delete
BEFORE DELETE ON rem1
FOR EACH ROW
WHEN (OLD.f2 like '%update%')
EXECUTE PROCEDURE trigger_data(23,'skidoo');
ERROR: relation "rem1" does not exist
ERROR: "rem1" is not a table or view
CREATE TRIGGER trig_row_after_delete
AFTER DELETE ON rem1
FOR EACH ROW
WHEN (OLD.f2 like '%update%')
EXECUTE PROCEDURE trigger_data(23,'skidoo');
ERROR: relation "rem1" does not exist
ERROR: "rem1" is not a table or view
-- Trigger is fired for f1=2, not for f1=1
DELETE FROM rem1;
ERROR: relation "rem1" does not exist on datanode1
LINE 1: DELETE FROM rem1;
^
-- cleanup
DROP TRIGGER trig_row_before_insupd ON rem1;
ERROR: relation "rem1" does not exist
ERROR: trigger "trig_row_before_insupd" for table "rem1" does not exist
DROP TRIGGER trig_row_after_insupd ON rem1;
ERROR: relation "rem1" does not exist
ERROR: trigger "trig_row_after_insupd" for table "rem1" does not exist
DROP TRIGGER trig_row_before_delete ON rem1;
ERROR: relation "rem1" does not exist
ERROR: trigger "trig_row_before_delete" for table "rem1" does not exist
DROP TRIGGER trig_row_after_delete ON rem1;
ERROR: relation "rem1" does not exist
ERROR: trigger "trig_row_after_delete" for table "rem1" does not exist
-- Test various RETURN statements in BEFORE triggers.
CREATE FUNCTION trig_row_before_insupdate() RETURNS TRIGGER AS $$
BEGIN
@ -3054,134 +3025,123 @@ $$ language plpgsql;
CREATE TRIGGER trig_row_before_insupd
BEFORE INSERT OR UPDATE ON rem1
FOR EACH ROW EXECUTE PROCEDURE trig_row_before_insupdate();
ERROR: relation "rem1" does not exist
ERROR: "rem1" is not a table or view
-- The new values should have 'triggered' appended
INSERT INTO rem1 values(1, 'insert');
ERROR: relation "rem1" does not exist on datanode1
LINE 1: INSERT INTO rem1 values(1, 'insert');
^
SELECT * from loc1;
f1 | f2
----+-----
1 | hi
2 | bye
(2 rows)
f1 | f2
----+--------
1 | insert
(1 row)
INSERT INTO rem1 values(2, 'insert') RETURNING f2;
ERROR: relation "rem1" does not exist on datanode1
LINE 1: INSERT INTO rem1 values(2, 'insert') RETURNING f2;
^
f2
--------
insert
(1 row)
SELECT * from loc1;
f1 | f2
----+-----
1 | hi
2 | bye
f1 | f2
----+--------
1 | insert
2 | insert
(2 rows)
UPDATE rem1 set f2 = '';
ERROR: relation "rem1" does not exist on datanode1
LINE 1: UPDATE rem1 set f2 = '';
^
SELECT * from loc1;
f1 | f2
----+-----
1 | hi
2 | bye
f1 | f2
----+----
1 |
2 |
(2 rows)
UPDATE rem1 set f2 = 'skidoo' RETURNING f2;
ERROR: relation "rem1" does not exist on datanode1
LINE 1: UPDATE rem1 set f2 = 'skidoo' RETURNING f2;
^
f2
--------
skidoo
skidoo
(2 rows)
SELECT * from loc1;
f1 | f2
----+-----
1 | hi
2 | bye
f1 | f2
----+--------
1 | skidoo
2 | skidoo
(2 rows)
EXPLAIN (verbose, costs off)
UPDATE rem1 set f1 = 10; -- all columns should be transmitted
ERROR: relation "rem1" does not exist on datanode1
LINE 2: UPDATE rem1 set f1 = 10;
^
QUERY PLAN
-----------------------------------------------------------------
Update on public.rem1
-> Foreign Scan on public.rem1
Output: 10, f2, ctid
Remote SQL: SELECT f2, ctid FROM public.loc1 FOR UPDATE
(4 rows)
UPDATE rem1 set f1 = 10;
ERROR: relation "rem1" does not exist on datanode1
LINE 1: UPDATE rem1 set f1 = 10;
^
SELECT * from loc1;
f1 | f2
----+-----
1 | hi
2 | bye
f1 | f2
----+--------
10 | skidoo
10 | skidoo
(2 rows)
DELETE FROM rem1;
ERROR: relation "rem1" does not exist on datanode1
LINE 1: DELETE FROM rem1;
^
-- Add a second trigger, to check that the changes are propagated correctly
-- from trigger to trigger
CREATE TRIGGER trig_row_before_insupd2
BEFORE INSERT OR UPDATE ON rem1
FOR EACH ROW EXECUTE PROCEDURE trig_row_before_insupdate();
ERROR: relation "rem1" does not exist
ERROR: "rem1" is not a table or view
INSERT INTO rem1 values(1, 'insert');
ERROR: relation "rem1" does not exist on datanode1
LINE 1: INSERT INTO rem1 values(1, 'insert');
^
SELECT * from loc1;
f1 | f2
----+-----
1 | hi
2 | bye
(2 rows)
f1 | f2
----+--------
1 | insert
(1 row)
INSERT INTO rem1 values(2, 'insert') RETURNING f2;
ERROR: relation "rem1" does not exist on datanode1
LINE 1: INSERT INTO rem1 values(2, 'insert') RETURNING f2;
^
f2
--------
insert
(1 row)
SELECT * from loc1;
f1 | f2
----+-----
1 | hi
2 | bye
f1 | f2
----+--------
1 | insert
2 | insert
(2 rows)
UPDATE rem1 set f2 = '';
ERROR: relation "rem1" does not exist on datanode1
LINE 1: UPDATE rem1 set f2 = '';
^
SELECT * from loc1;
f1 | f2
----+-----
1 | hi
2 | bye
f1 | f2
----+----
1 |
2 |
(2 rows)
UPDATE rem1 set f2 = 'skidoo' RETURNING f2;
ERROR: relation "rem1" does not exist on datanode1
LINE 1: UPDATE rem1 set f2 = 'skidoo' RETURNING f2;
^
f2
--------
skidoo
skidoo
(2 rows)
SELECT * from loc1;
f1 | f2
----+-----
1 | hi
2 | bye
f1 | f2
----+--------
1 | skidoo
2 | skidoo
(2 rows)
DROP TRIGGER trig_row_before_insupd ON rem1;
ERROR: relation "rem1" does not exist
ERROR: trigger "trig_row_before_insupd" for table "rem1" does not exist
DROP TRIGGER trig_row_before_insupd2 ON rem1;
ERROR: relation "rem1" does not exist
ERROR: trigger "trig_row_before_insupd2" for table "rem1" does not exist
DELETE from rem1;
ERROR: relation "rem1" does not exist on datanode1
LINE 1: DELETE from rem1;
^
INSERT INTO rem1 VALUES (1, 'test');
ERROR: relation "rem1" does not exist on datanode1
LINE 1: INSERT INTO rem1 VALUES (1, 'test');
^
-- Test with a trigger returning NULL
CREATE FUNCTION trig_null() RETURNS TRIGGER AS $$
BEGIN
@ -3191,68 +3151,49 @@ $$ language plpgsql;
CREATE TRIGGER trig_null
BEFORE INSERT OR UPDATE OR DELETE ON rem1
FOR EACH ROW EXECUTE PROCEDURE trig_null();
ERROR: relation "rem1" does not exist
ERROR: "rem1" is not a table or view
-- Nothing should have changed.
INSERT INTO rem1 VALUES (2, 'test2');
ERROR: relation "rem1" does not exist on datanode1
LINE 1: INSERT INTO rem1 VALUES (2, 'test2');
^
SELECT * from loc1;
f1 | f2
----+-----
1 | hi
2 | bye
f1 | f2
----+-------
1 | test
2 | test2
(2 rows)
UPDATE rem1 SET f2 = 'test2';
ERROR: relation "rem1" does not exist on datanode1
LINE 1: UPDATE rem1 SET f2 = 'test2';
^
SELECT * from loc1;
f1 | f2
----+-----
1 | hi
2 | bye
f1 | f2
----+-------
1 | test2
2 | test2
(2 rows)
DELETE from rem1;
ERROR: relation "rem1" does not exist on datanode1
LINE 1: DELETE from rem1;
^
SELECT * from loc1;
f1 | f2
----+-----
1 | hi
2 | bye
(2 rows)
f1 | f2
----+----
(0 rows)
DROP TRIGGER trig_null ON rem1;
ERROR: relation "rem1" does not exist
ERROR: trigger "trig_null" for table "rem1" does not exist
DELETE from rem1;
ERROR: relation "rem1" does not exist on datanode1
LINE 1: DELETE from rem1;
^
-- Test a combination of local and remote triggers
CREATE TRIGGER trig_row_before
BEFORE INSERT OR UPDATE OR DELETE ON rem1
FOR EACH ROW EXECUTE PROCEDURE trigger_data(23,'skidoo');
ERROR: relation "rem1" does not exist
ERROR: "rem1" is not a table or view
CREATE TRIGGER trig_row_after
AFTER INSERT OR UPDATE OR DELETE ON rem1
FOR EACH ROW EXECUTE PROCEDURE trigger_data(23,'skidoo');
ERROR: relation "rem1" does not exist
ERROR: "rem1" is not a table or view
CREATE TRIGGER trig_local_before BEFORE INSERT OR UPDATE ON loc1
FOR EACH ROW EXECUTE PROCEDURE trig_row_before_insupdate();
INSERT INTO rem1(f2) VALUES ('test');
ERROR: relation "rem1" does not exist on datanode1
LINE 1: INSERT INTO rem1(f2) VALUES ('test');
^
UPDATE rem1 SET f2 = 'testo';
ERROR: relation "rem1" does not exist on datanode1
LINE 1: UPDATE rem1 SET f2 = 'testo';
^
-- Test returning a system attribute
INSERT INTO rem1(f2) VALUES ('test') RETURNING ctid;
ERROR: relation "rem1" does not exist on datanode1
ERROR: column "ctid" does not exist
LINE 1: INSERT INTO rem1(f2) VALUES ('test') RETURNING ctid;
^
^
CONTEXT: referenced column: ctid

View File

@ -74,3 +74,5 @@ test: with
# run alter object to test pg_object
#test: pg_object_test
test: partition_foreign_key
test: partition_trigger

View File

@ -0,0 +1,312 @@
DROP TABLE IF EXISTS pt2;
DROP TABLE IF EXISTS pt1;
CREATE TABLE pt1(
d_date date UNIQUE
)partition BY RANGE (d_date) INTERVAL('1 day')
(PARTITION part1 VALUES LESS THAN ('1900-01-01'));
CREATE TABLE pt2(
d_date date
)partition BY RANGE (d_date) INTERVAL('1 day')
(PARTITION part1 VALUES LESS THAN ('1900-01-01'));
ALTER TABLE pt2 ADD CONSTRAINT test_foreign FOREIGN KEY(d_date)
REFERENCES pt1(d_date) on UPDATE CASCADE ON DELETE CASCADE;
INSERT into pt1 VALUES('1999-01-01'),('1999-01-02'),('1999-01-03'),('1999-01-04');
INSERT into pt2 VALUES('1999-01-01');
INSERT into pt2 VALUES('2000-01-01');
update pt2 set pt2.d_date = '2000-01-01' where pt2.d_date = '1999-01-01';
update pt2 set pt2.d_date = '1999-01-02' where pt2.d_date = '1999-01-01';
SELECT * FROM pt2;
SELECT * FROM pt2 PARTITION(sys_p2);
delete from pt2;
INSERT into pt2 VALUES('1999-01-01'), ('1999-01-03'),('1999-01-04');
INSERT into pt1 VALUES('1999-01-08');
INSERT into pt2 VALUES('1999-01-08');
update pt1 set pt1.d_date = '2000-01-01' where pt1.d_date = '1999-01-08';
delete from pt1 where pt1.d_date = '2000-01-01';
DROP TABLE pt2;
DROP TABLE pt1;
CREATE TABLE pt1(
d_date date UNIQUE
)partition BY RANGE (d_date) INTERVAL('1 month')
(PARTITION part1 VALUES LESS THAN ('1900-01-01'));
CREATE TABLE pt2(
d_date date
)partition BY RANGE (d_date) INTERVAL('1 month')
(PARTITION part1 VALUES LESS THAN ('1900-01-01'));
ALTER TABLE pt2 ADD CONSTRAINT test_foreign FOREIGN KEY(d_date)
REFERENCES pt1(d_date) on UPDATE CASCADE ON DELETE CASCADE;
INSERT INTO pt1 VALUES
('1999-01-01'),('1999-01-02'),('1999-01-019'),('1999-01-20'),
('1999-02-01'),('1999-02-02'),('1999-02-19'),('1999-02-20'),
('1999-03-01'),('1999-03-02'),('1999-03-19'),('1999-03-20'),
('1999-04-01'),('1999-04-02'),('1999-04-19'),('1999-04-20'),
('1999-05-01'),('1999-05-02'),('1999-05-19'),('1999-05-20'),
('1999-06-01'),('1999-06-02'),('1999-06-19'),('1999-06-20'),
('1999-07-01'),('1999-07-02'),('1999-07-19'),('1999-07-20'),
('1999-08-01'),('1999-08-02'),('1999-08-19'),('1999-08-20'),
('1999-09-01'),('1999-09-02'),('1999-09-19'),('1999-09-20'),
('1999-10-01'),('1999-10-02'),('1999-10-19'),('1999-10-20'),
('1999-11-01'),('1999-11-02'),('1999-11-19'),('1999-11-20'),
('1999-12-01'),('1999-12-02'),('1999-12-19'),('1999-12-20');
INSERT INTO pt2 VALUES
('1999-01-01'),('1999-01-02'),('1999-01-019'),('1999-01-20'),
('1999-02-01'),('1999-02-02'),('1999-02-19'),('1999-02-20'),
('1999-03-01'),('1999-03-02'),('1999-03-19'),('1999-03-20'),
('1999-04-01'),('1999-04-02'),('1999-04-19'),('1999-04-20'),
('1999-05-01'),('1999-05-02'),('1999-05-19'),('1999-05-20'),
('1999-06-01'),('1999-06-02'),('1999-06-19'),('1999-06-20'),
('1999-07-01'),('1999-07-02'),('1999-07-19'),('1999-07-20'),
('1999-08-01'),('1999-08-02'),('1999-08-19'),('1999-08-20'),
('1999-09-01'),('1999-09-02'),('1999-09-19'),('1999-09-20'),
('1999-10-01'),('1999-10-02'),('1999-10-19'),('1999-10-20'),
('1999-11-01'),('1999-11-02'),('1999-11-19'),('1999-11-20'),
('1999-12-01'),('1999-12-02'),('1999-12-19'),('1999-12-20');
delete from pt2 where pt2.d_date<'1999-03-01';
select * from pt2 where pt2.d_date<'1999-06-01';
delete from pt1 where pt1.d_date<'1999-05-01';
delete from pt2 where pt2.d_date>'1999-11-15' and pt2.d_date<'1999-12-15';
SELECT * FROM pt2 WHERE pt2.d_date>='1999-10-01';
delete from pt1 where pt1.d_date>'1999-10-15' and pt1.d_date<'1999-11-15';
SELECT * FROM pt1 WHERE pt1.d_date>='1999-10-01';
SELECT * FROM pt2 WHERE pt2.d_date>='1999-10-01';
UPDATE pt2 set d_date = d_date - INTERVAL '4' month where d_date>='1999-05-01' and d_date<'1999-06-01';
UPDATE pt1 set d_date = d_date - INTERVAL '4' month where d_date>='1999-05-01' and d_date<'1999-06-01';
SELECT * FROM pt1 WHERE d_date<'1999-07-01';
SELECT * FROM pt1 WHERE d_date<'1999-07-01';
UPDATE pt2 set d_date = d_date - INTERVAL '1' month where d_date>='1999-06-01' and d_date<='1999-07-15';
UPDATE pt1 set d_date = d_date - INTERVAL '1' month where d_date>='1999-06-01' and d_date<='1999-07-15';
SELECT * FROM pt1 WHERE d_date<'1999-08-01';
SELECT * FROM pt2 WHERE d_date<'1999-08-01';
DROP TABLE IF EXISTS pt2;
DROP TABLE IF EXISTS pt1;
CREATE TABLE pt1(
d_date date UNIQUE
)partition BY RANGE (d_date) INTERVAL('1 month')
(PARTITION part1 VALUES LESS THAN ('1900-01-01'))
;
CREATE TABLE pt2(
d_date date,
d_date_backup date
)partition BY RANGE (d_date_backup) INTERVAL('1 month')
(PARTITION part1 VALUES LESS THAN ('1900-01-01'));
ALTER TABLE pt2 ADD CONSTRAINT test_foreign FOREIGN KEY(d_date)
REFERENCES pt1(d_date) on UPDATE SET NULL ON DELETE SET NULL;
INSERT INTO pt1 VALUES
('1999-01-01'),('1999-01-02'),('1999-01-019'),('1999-01-20'),
('1999-02-01'),('1999-02-02'),('1999-02-19'),('1999-02-20'),
('1999-03-01'),('1999-03-02'),('1999-03-19'),('1999-03-20'),
('1999-04-01'),('1999-04-02'),('1999-04-19'),('1999-04-20'),
('1999-05-01'),('1999-05-02'),('1999-05-19'),('1999-05-20'),
('1999-06-01'),('1999-06-02'),('1999-06-19'),('1999-06-20'),
('1999-07-01'),('1999-07-02'),('1999-07-19'),('1999-07-20'),
('1999-08-01'),('1999-08-02'),('1999-08-19'),('1999-08-20'),
('1999-09-01'),('1999-09-02'),('1999-09-19'),('1999-09-20'),
('1999-10-01'),('1999-10-02'),('1999-10-19'),('1999-10-20'),
('1999-11-01'),('1999-11-02'),('1999-11-19'),('1999-11-20'),
('1999-12-01'),('1999-12-02'),('1999-12-19'),('1999-12-20');
INSERT INTO pt2 VALUES
('1999-01-01','1999-01-01'),('1999-01-02','1999-01-02'),
('1999-01-19','1999-01-19'),('1999-01-20','1999-01-20'),
('1999-02-01','1999-02-01'),('1999-02-02','1999-02-02'),
('1999-02-19','1999-02-19'),('1999-02-20','1999-02-20'),
('1999-03-01','1999-03-01'),('1999-03-02','1999-03-02'),
('1999-03-19','1999-03-19'),('1999-03-20','1999-03-20'),
('1999-04-01','1999-04-01'),('1999-04-02','1999-04-02'),
('1999-04-19','1999-04-19'),('1999-04-20','1999-04-20'),
('1999-05-01','1999-05-01'),('1999-05-02','1999-05-02'),
('1999-05-19','1999-05-19'),('1999-05-20','1999-05-20'),
('1999-06-01','1999-06-01'),('1999-06-02','1999-06-02'),
('1999-06-19','1999-06-19'),('1999-06-20','1999-06-20'),
('1999-07-01','1999-07-01'),('1999-07-02','1999-07-02'),
('1999-07-19','1999-07-19'),('1999-07-20','1999-07-20'),
('1999-08-01','1999-08-01'),('1999-08-02','1999-08-02'),
('1999-08-19','1999-08-19'),('1999-08-20','1999-08-20'),
('1999-09-01','1999-09-01'),('1999-09-02','1999-09-02'),
('1999-09-19','1999-09-19'),('1999-09-20','1999-09-20'),
('1999-10-01','1999-10-01'),('1999-10-02','1999-10-02'),
('1999-10-19','1999-10-19'),('1999-10-20','1999-10-20'),
('1999-11-01','1999-11-01'),('1999-11-02','1999-11-02'),
('1999-11-19','1999-11-19'),('1999-11-20','1999-11-20'),
('1999-12-01','1999-12-01'),('1999-12-02','1999-12-02'),
('1999-12-19','1999-12-19'),('1999-12-20','1999-12-20');
insert into pt1 VALUES('2000-01-01'),('2000-01-02'),
('2000-01-19'),('2000-01-20'),
('2000-02-01'),('2000-02-02'),
('2000-02-19'),('2000-02-20');
SELECT * FROM pt1 WHERE d_date>='2000-01-01';
update pt1 set d_date = '2000-02-21' WHERE d_date = '2000-02-20';
SELECT * FROM pt1 WHERE d_date>='2000-02-01';
DELETE FROM pt1 WHERE d_date = '2000-02-21';
SELECT * FROM pt1 WHERE d_date>='2000-02-01';
SELECT * FROM pt1 PARTITION FOR('1999-06-16');
INSERT into pt2 VALUES('2020-08-19','2020-08-19');
INSERT into pt2 VALUES('2000-01-01','2000-01-01');
update pt2 set pt2.d_date = '2020-08-13'
where pt2.d_date = '1999-01-01';
update pt2 set pt2.d_date = '2000-02-01',pt2.d_date_backup = '2000-02-01'
where pt2.d_date = '2000-01-01';
SELECT * FROM pt2;
SELECT * FROM pt2 PARTITION(sys_p2);
delete from pt2 where pt2.d_date<'1999-03-01';
select * from pt2 where pt2.d_date<'1999-06-01';
delete from pt1 where d_date<'1999-05-01';
select * from pt1 where d_date<'1999-06-01';
select * from pt2 where d_date_backup<'1999-06-01';
delete from pt2 where pt2.d_date>'1999-11-15' and pt2.d_date<'1999-12-15';
SELECT * FROM pt2 WHERE pt2.d_date>='1999-10-01';
delete from pt1 where pt1.d_date>'1999-10-15' and pt1.d_date<'1999-11-15';
SELECT * FROM pt1 WHERE pt1.d_date>='1999-10-01';
SELECT * FROM pt2 WHERE pt2.d_date_backup>='1999-10-01';
UPDATE pt2 set d_date = d_date - INTERVAL '4' month where d_date>='1999-05-01' and d_date<'1999-06-01';
UPDATE pt1 set d_date = d_date - INTERVAL '4' month where d_date>='1999-05-01' and d_date<'1999-06-01';
SELECT * FROM pt1 WHERE d_date<'1999-07-01';
SELECT * FROM pt2 WHERE d_date_backup<'1999-07-01';
UPDATE pt2 set d_date = d_date - INTERVAL '1' month where d_date>='1999-06-01' and d_date<='1999-07-15';
UPDATE pt1 set d_date = d_date - INTERVAL '1' month where d_date>='1999-06-01' and d_date<='1999-07-15';
SELECT * FROM pt1 WHERE d_date<'1999-08-01';
SELECT * FROM pt2 WHERE d_date_backup<'1999-08-01';
DROP TABLE IF EXISTS pt2;
DROP TABLE IF EXISTS pt1;
CREATE TABLE pt1(
d_date date UNIQUE
)partition BY RANGE (d_date) INTERVAL('1 month')
(PARTITION part1 VALUES LESS THAN ('1900-01-01'));
CREATE TABLE pt2(
d_date date,
d_date_backup date
)partition BY RANGE (d_date_backup) INTERVAL('1 month')
(PARTITION part1 VALUES LESS THAN ('1900-01-01'));
ALTER TABLE pt2 ADD CONSTRAINT test_foreign FOREIGN KEY(d_date)
REFERENCES pt1(d_date) on UPDATE RESTRICT ON DELETE RESTRICT;
INSERT INTO pt1 VALUES
('1999-01-01'),('1999-01-02'),('1999-01-019'),('1999-01-20'),
('1999-02-01'),('1999-02-02'),('1999-02-19'),('1999-02-20'),
('1999-03-01'),('1999-03-02'),('1999-03-19'),('1999-03-20'),
('1999-04-01'),('1999-04-02'),('1999-04-19'),('1999-04-20'),
('1999-05-01'),('1999-05-02'),('1999-05-19'),('1999-05-20'),
('1999-06-01'),('1999-06-02'),('1999-06-19'),('1999-06-20'),
('1999-07-01'),('1999-07-02'),('1999-07-19'),('1999-07-20'),
('1999-08-01'),('1999-08-02'),('1999-08-19'),('1999-08-20'),
('1999-09-01'),('1999-09-02'),('1999-09-19'),('1999-09-20'),
('1999-10-01'),('1999-10-02'),('1999-10-19'),('1999-10-20'),
('1999-11-01'),('1999-11-02'),('1999-11-19'),('1999-11-20'),
('1999-12-01'),('1999-12-02'),('1999-12-19'),('1999-12-20');
INSERT INTO pt2 VALUES
('1999-01-01','1999-01-01'),('1999-01-02','1999-01-02'),
('1999-01-19','1999-01-19'),('1999-01-20','1999-01-20'),
('1999-02-01','1999-02-01'),('1999-02-02','1999-02-02'),
('1999-02-19','1999-02-19'),('1999-02-20','1999-02-20'),
('1999-03-01','1999-03-01'),('1999-03-02','1999-03-02'),
('1999-03-19','1999-03-19'),('1999-03-20','1999-03-20'),
('1999-04-01','1999-04-01'),('1999-04-02','1999-04-02'),
('1999-04-19','1999-04-19'),('1999-04-20','1999-04-20'),
('1999-05-01','1999-05-01'),('1999-05-02','1999-05-02'),
('1999-05-19','1999-05-19'),('1999-05-20','1999-05-20'),
('1999-06-01','1999-06-01'),('1999-06-02','1999-06-02'),
('1999-06-19','1999-06-19'),('1999-06-20','1999-06-20'),
('1999-07-01','1999-07-01'),('1999-07-02','1999-07-02'),
('1999-07-19','1999-07-19'),('1999-07-20','1999-07-20'),
('1999-08-01','1999-08-01'),('1999-08-02','1999-08-02'),
('1999-08-19','1999-08-19'),('1999-08-20','1999-08-20'),
('1999-09-01','1999-09-01'),('1999-09-02','1999-09-02'),
('1999-09-19','1999-09-19'),('1999-09-20','1999-09-20'),
('1999-10-01','1999-10-01'),('1999-10-02','1999-10-02'),
('1999-10-19','1999-10-19'),('1999-10-20','1999-10-20'),
('1999-11-01','1999-11-01'),('1999-11-02','1999-11-02'),
('1999-11-19','1999-11-19'),('1999-11-20','1999-11-20'),
('1999-12-01','1999-12-01'),('1999-12-02','1999-12-02'),
('1999-12-19','1999-12-19'),('1999-12-20','1999-12-20');
delete from pt2 where pt2.d_date<'1999-03-01';
select * from pt2 where pt2.d_date<'1999-06-01';
delete from pt1 where d_date<'1999-05-01';
delete from pt2 where pt2.d_date>'1999-11-15' and pt2.d_date<'1999-12-15';
SELECT * FROM pt2 WHERE pt2.d_date>='1999-10-01';
delete from pt1 where pt1.d_date>'1999-10-15' and pt1.d_date<'1999-11-15';
delete from pt2 where pt2.d_date>='1999-01-01' and pt2.d_date<'1999-05-01';
delete from pt1 where pt1.d_date>='1999-01-01' and pt1.d_date<'1999-05-01';
UPDATE pt2 set d_date = d_date - INTERVAL '4' month where d_date>='1999-05-01' and d_date<'1999-06-01';
UPDATE pt1 set d_date = d_date - INTERVAL '4' month where d_date>='1999-05-01' and d_date<'1999-06-01';
SELECT * FROM pt1 WHERE d_date<'1999-07-01';
UPDATE pt2 set d_date = d_date - INTERVAL '1' month where d_date>='1999-06-01' and d_date<='1999-07-15';
UPDATE pt1 set d_date = d_date - INTERVAL '5' month where d_date>='1999-06-01' and d_date<='1999-07-15';
delete from pt2 where d_date>='1999-06-01' and d_date<='1999-07-15';
UPDATE pt1 set d_date = d_date - INTERVAL '5' month where d_date>='1999-06-01' and d_date<='1999-07-15';

View File

@ -0,0 +1,143 @@
DROP TABLE IF EXISTS pt2;
DROP TABLE IF EXISTS pt1;
DROP FUNCTION IF EXISTS test_function();
CREATE TABLE pt1(
d_date date UNIQUE
)partition BY RANGE (d_date) INTERVAL('1 month')
(PARTITION part1 VALUES LESS THAN ('1900-01-01'));
CREATE TABLE pt2(
d_date date
)partition BY RANGE (d_date) INTERVAL('1 month')
(PARTITION part1 VALUES LESS THAN ('1900-01-01'));
INSERT INTO pt1 VALUES
('1999-01-01'),('1999-01-02'),('1999-01-019'),('1999-01-20'),
('1999-02-01'),('1999-02-02'),('1999-02-19'),('1999-02-20'),
('1999-03-01'),('1999-03-02'),('1999-03-19'),('1999-03-20'),
('1999-04-01'),('1999-04-02'),('1999-04-19'),('1999-04-20'),
('1999-05-01'),('1999-05-02'),('1999-05-19'),('1999-05-20'),
('1999-06-01'),('1999-06-02'),('1999-06-19'),('1999-06-20'),
('1999-07-01'),('1999-07-02'),('1999-07-19'),('1999-07-20'),
('1999-08-01'),('1999-08-02'),('1999-08-19'),('1999-08-20'),
('1999-09-01'),('1999-09-02'),('1999-09-19'),('1999-09-20'),
('1999-10-01'),('1999-10-02'),('1999-10-19'),('1999-10-20'),
('1999-11-01'),('1999-11-02'),('1999-11-19'),('1999-11-20'),
('1999-12-01'),('1999-12-02'),('1999-12-19'),('1999-12-20');
INSERT INTO pt2 VALUES
('1999-01-01'),('1999-01-02'),('1999-01-019'),('1999-01-20'),
('1999-02-01'),('1999-02-02'),('1999-02-19'),('1999-02-20'),
('1999-03-01'),('1999-03-02'),('1999-03-19'),('1999-03-20'),
('1999-04-01'),('1999-04-02'),('1999-04-19'),('1999-04-20'),
('1999-05-01'),('1999-05-02'),('1999-05-19'),('1999-05-20'),
('1999-06-01'),('1999-06-02'),('1999-06-19'),('1999-06-20'),
('1999-07-01'),('1999-07-02'),('1999-07-19'),('1999-07-20'),
('1999-08-01'),('1999-08-02'),('1999-08-19'),('1999-08-20'),
('1999-09-01'),('1999-09-02'),('1999-09-19'),('1999-09-20'),
('1999-10-01'),('1999-10-02'),('1999-10-19'),('1999-10-20'),
('1999-11-01'),('1999-11-02'),('1999-11-19'),('1999-11-20'),
('1999-12-01'),('1999-12-02'),('1999-12-19'),('1999-12-20');
CREATE FUNCTION test_function()
RETURNS TRIGGER AS $$
BEGIN
IF(TG_OP = 'DELETE') THEN
DELETE FROM pt2 WHERE d_date=OLD.d_date;
RETURN OLD;
ELSEIF(TG_OP = 'UPDATE') THEN
UPDATE pt2 set d_date=NEW.d_date where d_date=OLD.d_date;
RETURN NEW;
ELSEIF(TG_OP = 'INSERT') THEN
INSERT INTO pt2 VALUES(NEW.d_date);
RETURN NEW;
END IF;
RETURN NULL;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER test_trigger
AFTER INSERT OR UPDATE OR DELETE on pt1
FOR EACH ROW EXECUTE PROCEDURE test_function();
INSERT INTO pt1 VALUES('2016-01-01');
UPDATE pt2 set d_date = d_date + INTERVAL '4' month where d_date>='1999-05-01';
DELETE FROM pt1 WHERE d_date<'1999-05-01';
SELECT * FROM pt1;
SELECT * FROM pt2;
DROP TABLE IF EXISTS pt2;
DROP TABLE IF EXISTS pt1;
DROP FUNCTION IF EXISTS test_function();
CREATE TABLE pt1(
d_date date UNIQUE
)partition BY RANGE (d_date) INTERVAL('1 month')
(PARTITION part1 VALUES LESS THAN ('1900-01-01'));
CREATE TABLE pt2(
d_date date
)partition BY RANGE (d_date) INTERVAL('1 month')
(PARTITION part1 VALUES LESS THAN ('1900-01-01'));
INSERT INTO pt1 VALUES
('1999-01-01'),('1999-01-02'),('1999-01-019'),('1999-01-20'),
('1999-02-01'),('1999-02-02'),('1999-02-19'),('1999-02-20'),
('1999-03-01'),('1999-03-02'),('1999-03-19'),('1999-03-20'),
('1999-04-01'),('1999-04-02'),('1999-04-19'),('1999-04-20'),
('1999-05-01'),('1999-05-02'),('1999-05-19'),('1999-05-20'),
('1999-06-01'),('1999-06-02'),('1999-06-19'),('1999-06-20'),
('1999-07-01'),('1999-07-02'),('1999-07-19'),('1999-07-20'),
('1999-08-01'),('1999-08-02'),('1999-08-19'),('1999-08-20'),
('1999-09-01'),('1999-09-02'),('1999-09-19'),('1999-09-20'),
('1999-10-01'),('1999-10-02'),('1999-10-19'),('1999-10-20'),
('1999-11-01'),('1999-11-02'),('1999-11-19'),('1999-11-20'),
('1999-12-01'),('1999-12-02'),('1999-12-19'),('1999-12-20');
INSERT INTO pt2 VALUES
('1999-01-01'),('1999-01-02'),('1999-01-019'),('1999-01-20'),
('1999-02-01'),('1999-02-02'),('1999-02-19'),('1999-02-20'),
('1999-03-01'),('1999-03-02'),('1999-03-19'),('1999-03-20'),
('1999-04-01'),('1999-04-02'),('1999-04-19'),('1999-04-20'),
('1999-05-01'),('1999-05-02'),('1999-05-19'),('1999-05-20'),
('1999-06-01'),('1999-06-02'),('1999-06-19'),('1999-06-20'),
('1999-07-01'),('1999-07-02'),('1999-07-19'),('1999-07-20'),
('1999-08-01'),('1999-08-02'),('1999-08-19'),('1999-08-20'),
('1999-09-01'),('1999-09-02'),('1999-09-19'),('1999-09-20'),
('1999-10-01'),('1999-10-02'),('1999-10-19'),('1999-10-20'),
('1999-11-01'),('1999-11-02'),('1999-11-19'),('1999-11-20'),
('1999-12-01'),('1999-12-02'),('1999-12-19'),('1999-12-20');
CREATE FUNCTION test_function()
RETURNS TRIGGER AS $$
BEGIN
IF(TG_OP = 'DELETE') THEN
DELETE FROM pt2 WHERE d_date=OLD.d_date;
RETURN OLD;
ELSEIF(TG_OP = 'UPDATE') THEN
UPDATE pt2 set d_date=NEW.d_date where d_date=OLD.d_date;
RETURN NEW;
ELSEIF(TG_OP = 'INSERT') THEN
INSERT INTO pt2 VALUES(NEW.d_date);
RETURN NEW;
END IF;
RETURN NULL;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER test_trigger
BEFORE INSERT OR UPDATE OR DELETE on pt1
FOR EACH ROW EXECUTE PROCEDURE test_function();
INSERT INTO pt1 VALUES('2016-01-01');
UPDATE pt2 set d_date = d_date + INTERVAL '4' month where d_date>='1999-05-01';
DELETE FROM pt1 WHERE d_date<'1999-05-01';
SELECT * FROM pt1;
SELECT * FROM pt2;