forked from huawei/openGauss-server
Compare commits
4 Commits
| Author | SHA1 | Date |
|---|---|---|
|
|
c6cf59f29f | |
|
|
a5410b7f86 | |
|
|
c711c7dc5f | |
|
|
3bea35e8c1 |
|
|
@ -1,5 +1,4 @@
|
||||||
#!/usr/bin/perl
|
#!/usr/bin/perl
|
||||||
#Again
|
|
||||||
|
|
||||||
use warnings;
|
use warnings;
|
||||||
use strict;
|
use strict;
|
||||||
|
|
|
||||||
|
|
@ -72,7 +72,7 @@ select_package_command
|
||||||
export PLAT_FORM_STR=$(sh "${ROOT_DIR}/src/get_PlatForm_str.sh")
|
export PLAT_FORM_STR=$(sh "${ROOT_DIR}/src/get_PlatForm_str.sh")
|
||||||
if [ "${PLAT_FORM_STR}"x == "Failed"x -o "${PLAT_FORM_STR}"x == ""x ]
|
if [ "${PLAT_FORM_STR}"x == "Failed"x -o "${PLAT_FORM_STR}"x == ""x ]
|
||||||
then
|
then
|
||||||
echo "We only support openEuler(aarch64), EulerOS(aarch64), CentOS, Kylin(aarch64), Asianux platform."
|
echo "We only support openEuler(aarch64), EulerOS(aarch64), CentOS, Kylin(aarch64) platform."
|
||||||
exit 1;
|
exit 1;
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
@ -96,21 +96,16 @@ elif [[ "$PLAT_FORM_STR" =~ "kylin" ]]; then
|
||||||
if [ "$PLATFORM_ARCH"X == "aarch64"X ];then
|
if [ "$PLATFORM_ARCH"X == "aarch64"X ];then
|
||||||
GAUSSDB_EXTRA_FLAGS=" -D__USE_NUMA"
|
GAUSSDB_EXTRA_FLAGS=" -D__USE_NUMA"
|
||||||
fi
|
fi
|
||||||
elif [[ "$PLAT_FORM_STR" =~ "asianux" ]]; then
|
|
||||||
dist_version="Asianux"
|
|
||||||
if [ "$PLATFORM_ARCH"X == "aarch64"X ];then
|
|
||||||
GAUSSDB_EXTRA_FLAGS=" -D__USE_NUMA"
|
|
||||||
fi
|
|
||||||
else
|
else
|
||||||
echo "We only support openEuler(aarch64), EulerOS(aarch64), CentOS, Kylin(aarch64), Asianux platform."
|
echo "We only support openEuler(aarch64), EulerOS(aarch64), CentOS, Kylin(aarch64) platform."
|
||||||
echo "Kernel is $kernel"
|
echo "Kernel is $kernel"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
##add platform architecture information
|
##add platform architecture information
|
||||||
if [ "$PLATFORM_ARCH"X == "aarch64"X ] ; then
|
if [ "$PLATFORM_ARCH"X == "aarch64"X ] ; then
|
||||||
if [ "$dist_version" != "openEuler" ] && [ "$dist_version" != "EulerOS" ] && [ "$dist_version" != "Kylin" ] && [ "$dist_version" != "Asianux" ]; then
|
if [ "$dist_version" != "openEuler" ] && [ "$dist_version" != "EulerOS" ] && [ "$dist_version" != "Kylin" ] ; then
|
||||||
echo "We only support NUMA on openEuler(aarch64), EulerOS(aarch64), Kylin(aarch64), Asianux platform."
|
echo "We only support NUMA on openEuler(aarch64), EulerOS(aarch64), Kylin(aarch64) platform."
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,6 @@ Complete list of usable sgml source files in this directory.
|
||||||
<!ENTITY alterOperator SYSTEM "alter_operator.sgml">
|
<!ENTITY alterOperator SYSTEM "alter_operator.sgml">
|
||||||
<!ENTITY alterOperatorClass SYSTEM "alter_opclass.sgml">
|
<!ENTITY alterOperatorClass SYSTEM "alter_opclass.sgml">
|
||||||
<!ENTITY alterOperatorFamily SYSTEM "alter_opfamily.sgml">
|
<!ENTITY alterOperatorFamily SYSTEM "alter_opfamily.sgml">
|
||||||
<!ENTITY alterProcedure SYSTEM "alter_procedure.sgml">
|
|
||||||
<!ENTITY alterRole SYSTEM "alter_role.sgml">
|
<!ENTITY alterRole SYSTEM "alter_role.sgml">
|
||||||
<!ENTITY alterSchema SYSTEM "alter_schema.sgml">
|
<!ENTITY alterSchema SYSTEM "alter_schema.sgml">
|
||||||
<!ENTITY alterServer SYSTEM "alter_server.sgml">
|
<!ENTITY alterServer SYSTEM "alter_server.sgml">
|
||||||
|
|
|
||||||
|
|
@ -1,37 +0,0 @@
|
||||||
<refentry id="sql-alterprocedure">
|
|
||||||
<indexterm zone="sql-alterprocedure">
|
|
||||||
<primary>ALTER PROCEDURE</primary>
|
|
||||||
</indexterm>
|
|
||||||
|
|
||||||
<refmeta>
|
|
||||||
<refentrytitle>ALTER PROCEDURE</refentrytitle>
|
|
||||||
<manvolnum>7</manvolnum>
|
|
||||||
<refmiscinfo>SQL - Language Statements</refmiscinfo>
|
|
||||||
</refmeta>
|
|
||||||
|
|
||||||
<refnamediv>
|
|
||||||
<refname>ALTER PROCEDURE</refname>
|
|
||||||
<refpurpose>change the definition of a procedure</refpurpose>
|
|
||||||
</refnamediv>
|
|
||||||
|
|
||||||
<refsynopsisdiv>
|
|
||||||
<synopsis>
|
|
||||||
ALTER PROCEDURE <replaceable>name</replaceable> [ ( [ [ <replaceable class="parameter">argmode</replaceable> ] [ <replaceable class="parameter">argname</replaceable> ] <replaceable class="parameter">argtype</replaceable> [, ...] ] ) ]
|
|
||||||
<replaceable class="parameter">action</replaceable> [ ... ] [ RESTRICT ]
|
|
||||||
ALTER PROCEDURE <replaceable>name</replaceable> [ ( [ [ <replaceable class="parameter">argmode</replaceable> ] [ <replaceable class="parameter">argname</replaceable> ] <replaceable class="parameter">argtype</replaceable> [, ...] ] ) ]
|
|
||||||
RENAME TO <replaceable>new_name</replaceable>
|
|
||||||
ALTER PROCEDURE <replaceable>name</replaceable> [ ( [ [ <replaceable class="parameter">argmode</replaceable> ] [ <replaceable class="parameter">argname</replaceable> ] <replaceable class="parameter">argtype</replaceable> [, ...] ] ) ]
|
|
||||||
OWNER TO { <replaceable>new_owner</replaceable> | CURRENT_ROLE | CURRENT_USER | SESSION_USER }
|
|
||||||
ALTER PROCEDURE <replaceable>name</replaceable> [ ( [ [ <replaceable class="parameter">argmode</replaceable> ] [ <replaceable class="parameter">argname</replaceable> ] <replaceable class="parameter">argtype</replaceable> [, ...] ] ) ]
|
|
||||||
SET SCHEMA <replaceable>new_schema</replaceable>
|
|
||||||
|
|
||||||
<phrase>where <replaceable class="parameter">action</replaceable> is one of:</phrase>
|
|
||||||
|
|
||||||
[ EXTERNAL ] SECURITY INVOKER | [ EXTERNAL ] SECURITY DEFINER
|
|
||||||
SET <replaceable class="parameter">configuration_parameter</replaceable> { TO | = } { <replaceable class="parameter">value</replaceable> | DEFAULT }
|
|
||||||
SET <replaceable class="parameter">configuration_parameter</replaceable> FROM CURRENT
|
|
||||||
RESET <replaceable class="parameter">configuration_parameter</replaceable>
|
|
||||||
RESET ALL
|
|
||||||
</synopsis>
|
|
||||||
</refsynopsisdiv>
|
|
||||||
</refentry>
|
|
||||||
|
|
@ -11,7 +11,7 @@
|
||||||
<refsynopsisdiv>
|
<refsynopsisdiv>
|
||||||
<synopsis>
|
<synopsis>
|
||||||
DROP TABLE [ IF EXISTS ]
|
DROP TABLE [ IF EXISTS ]
|
||||||
{[schema.]table_name} [, ...] [ CASCADE | RESTRICT ] [ PURGE ];
|
{[schema.]table_name} [, ...] [ CASCADE | RESTRICT ] [ PURGE ]};
|
||||||
</synopsis>
|
</synopsis>
|
||||||
</refsynopsisdiv>
|
</refsynopsisdiv>
|
||||||
</refentry>
|
</refentry>
|
||||||
|
|
@ -27,14 +27,7 @@
|
||||||
#include "securec_check.h"
|
#include "securec_check.h"
|
||||||
#include "cipher.h"
|
#include "cipher.h"
|
||||||
#include "crypt.h"
|
#include "crypt.h"
|
||||||
/*
|
|
||||||
function name: crypt_malloc_zero
|
|
||||||
description: Distribute internal memory
|
|
||||||
arguments: An integer that designates the size of internal memory distributed
|
|
||||||
return value: A pointer of type void*
|
|
||||||
Note:If the size of internal memory distributed is zero, it's unreasonable. The size should be greater than zero.
|
|
||||||
At the same time, if malloc fails, program would exit.
|
|
||||||
*/
|
|
||||||
void* crypt_malloc_zero(size_t size)
|
void* crypt_malloc_zero(size_t size)
|
||||||
{
|
{
|
||||||
void* ret = NULL;
|
void* ret = NULL;
|
||||||
|
|
|
||||||
|
|
@ -34,14 +34,6 @@
|
||||||
static int check_key_num(const char* password);
|
static int check_key_num(const char* password);
|
||||||
static void create_child_dir(const char* pathdir);
|
static void create_child_dir(const char* pathdir);
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
function name: check_path
|
|
||||||
description: Check if the string delivered has the character that should not be included
|
|
||||||
arguments: A pointer to string that its type is const char
|
|
||||||
return value: void
|
|
||||||
Note:none
|
|
||||||
*/
|
|
||||||
void check_path(const char *path_name)
|
void check_path(const char *path_name)
|
||||||
{
|
{
|
||||||
const char* danger_character_list[] = {"|",
|
const char* danger_character_list[] = {"|",
|
||||||
|
|
@ -77,14 +69,6 @@ void check_path(const char *path_name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
function name: check_key_num
|
|
||||||
description: Check if the password is a null string, if so, then the password is invalid.
|
|
||||||
At the same time, the function check if the length of password exceeds MAX_CRYPT_LEN, if so, print the error.
|
|
||||||
arguments: A pointer to string that its type is const char
|
|
||||||
return value: An integer that its type is static int
|
|
||||||
Note:The length of password should not be zero, and never exceeds MAX_CRYPT_LEN
|
|
||||||
*/
|
|
||||||
static int check_key_num(const char* password)
|
static int check_key_num(const char* password)
|
||||||
{
|
{
|
||||||
int key_len = 0;
|
int key_len = 0;
|
||||||
|
|
@ -100,13 +84,6 @@ static int check_key_num(const char* password)
|
||||||
return key_len;
|
return key_len;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
function name: create_child_dir
|
|
||||||
description: 函数作用
|
|
||||||
arguments: A pointer to string that its type is const char
|
|
||||||
return value: static void
|
|
||||||
Note:函数中提醒阅读者需要注意的东西
|
|
||||||
*/
|
|
||||||
static void create_child_dir(const char* pathdir)
|
static void create_child_dir(const char* pathdir)
|
||||||
{
|
{
|
||||||
if (pathdir == NULL) {
|
if (pathdir == NULL) {
|
||||||
|
|
|
||||||
|
|
@ -5923,7 +5923,7 @@ int main(int argc, char** argv)
|
||||||
&option_index)) != -1)
|
&option_index)) != -1)
|
||||||
#endif
|
#endif
|
||||||
#else
|
#else
|
||||||
while ((c = getopt_long(argc, argv, "b:cD:e:fi:G:l:m:M:N:o:O:p:P:r:R:v:x:sS:t:u:U:wWZ:C:dqL:T:Q:", long_options,
|
while ((c = getopt_long(argc, argv, "b:cD:e:fi:G:l:m:M:N:o:O:p:P:r:R:v:x:sS:t:u:U:wWZ:dqL:T:Q:", long_options,
|
||||||
&option_index)) != -1)
|
&option_index)) != -1)
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -233,7 +233,6 @@ char* all_data_nodename_list = NULL;
|
||||||
const uint32 USTORE_UPGRADE_VERSION = 92368;
|
const uint32 USTORE_UPGRADE_VERSION = 92368;
|
||||||
const uint32 PACKAGE_ENHANCEMENT = 92444;
|
const uint32 PACKAGE_ENHANCEMENT = 92444;
|
||||||
const uint32 SUBSCRIPTION_VERSION = 92580;
|
const uint32 SUBSCRIPTION_VERSION = 92580;
|
||||||
const uint32 SUBSCRIPTION_BINARY_VERSION_NUM = 92606;
|
|
||||||
|
|
||||||
#ifdef DUMPSYSLOG
|
#ifdef DUMPSYSLOG
|
||||||
char* syslogpath = NULL;
|
char* syslogpath = NULL;
|
||||||
|
|
@ -4445,16 +4444,23 @@ void getSubscriptions(Archive *fout)
|
||||||
int i_subslotname;
|
int i_subslotname;
|
||||||
int i_subsynccommit;
|
int i_subsynccommit;
|
||||||
int i_subpublications;
|
int i_subpublications;
|
||||||
int i_subbinary;
|
int i, ntups;
|
||||||
int i;
|
|
||||||
int ntups;
|
|
||||||
|
|
||||||
if (no_subscriptions || GetVersionNum(fout) < SUBSCRIPTION_VERSION) {
|
if (no_subscriptions || GetVersionNum(fout) < SUBSCRIPTION_VERSION) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isExecUserSuperRole(fout)) {
|
if (!isExecUserSuperRole(fout)) {
|
||||||
write_msg(NULL, "WARNING: subscriptions not dumped because current user is not a superuser\n");
|
res = ExecuteSqlQuery(fout,
|
||||||
|
"SELECT count(*) FROM pg_subscription "
|
||||||
|
"WHERE subdbid = (SELECT oid FROM pg_catalog.pg_database"
|
||||||
|
" WHERE datname = current_database())",
|
||||||
|
PGRES_TUPLES_OK);
|
||||||
|
uint64 n = (res != NULL) ? strtoul(PQgetvalue(res, 0, 0), NULL, 10) : 0;
|
||||||
|
if (n > 0) {
|
||||||
|
write_msg(NULL, "WARNING: subscriptions not dumped because current user is not a superuser\n");
|
||||||
|
}
|
||||||
|
PQclear(res);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -4463,20 +4469,14 @@ void getSubscriptions(Archive *fout)
|
||||||
resetPQExpBuffer(query);
|
resetPQExpBuffer(query);
|
||||||
|
|
||||||
/* Get the subscriptions in current database. */
|
/* Get the subscriptions in current database. */
|
||||||
appendPQExpBuffer(query, "SELECT s.tableoid, s.oid, s.subname,"
|
appendPQExpBuffer(query,
|
||||||
"(%s s.subowner) AS rolname, s.subconninfo, s.subslotname, "
|
"SELECT s.tableoid, s.oid, s.subname,"
|
||||||
"s.subsynccommit, s.subpublications, \n", username_subquery);
|
"(%s s.subowner) AS rolname, "
|
||||||
|
" s.subconninfo, s.subslotname, s.subsynccommit, s.subpublications "
|
||||||
if (GetVersionNum(fout) >= SUBSCRIPTION_BINARY_VERSION_NUM) {
|
"FROM pg_catalog.pg_subscription s "
|
||||||
appendPQExpBuffer(query, " s.subbinary\n");
|
|
||||||
} else {
|
|
||||||
appendPQExpBuffer(query, " false AS subbinary\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
appendPQExpBuffer(query, "FROM pg_catalog.pg_subscription s "
|
|
||||||
"WHERE s.subdbid = (SELECT oid FROM pg_catalog.pg_database"
|
"WHERE s.subdbid = (SELECT oid FROM pg_catalog.pg_database"
|
||||||
" WHERE datname = current_database())");
|
" WHERE datname = current_database())",
|
||||||
|
username_subquery);
|
||||||
res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
|
res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
|
||||||
|
|
||||||
ntups = PQntuples(res);
|
ntups = PQntuples(res);
|
||||||
|
|
@ -4494,7 +4494,6 @@ void getSubscriptions(Archive *fout)
|
||||||
i_subslotname = PQfnumber(res, "subslotname");
|
i_subslotname = PQfnumber(res, "subslotname");
|
||||||
i_subsynccommit = PQfnumber(res, "subsynccommit");
|
i_subsynccommit = PQfnumber(res, "subsynccommit");
|
||||||
i_subpublications = PQfnumber(res, "subpublications");
|
i_subpublications = PQfnumber(res, "subpublications");
|
||||||
i_subbinary = PQfnumber(res, "subbinary");
|
|
||||||
|
|
||||||
subinfo = (SubscriptionInfo *)pg_malloc(ntups * sizeof(SubscriptionInfo));
|
subinfo = (SubscriptionInfo *)pg_malloc(ntups * sizeof(SubscriptionInfo));
|
||||||
|
|
||||||
|
|
@ -4513,7 +4512,6 @@ void getSubscriptions(Archive *fout)
|
||||||
}
|
}
|
||||||
subinfo[i].subsynccommit = gs_strdup(PQgetvalue(res, i, i_subsynccommit));
|
subinfo[i].subsynccommit = gs_strdup(PQgetvalue(res, i, i_subsynccommit));
|
||||||
subinfo[i].subpublications = gs_strdup(PQgetvalue(res, i, i_subpublications));
|
subinfo[i].subpublications = gs_strdup(PQgetvalue(res, i, i_subpublications));
|
||||||
subinfo[i].subbinary = gs_strdup(PQgetvalue(res, i, i_subbinary));
|
|
||||||
|
|
||||||
if (strlen(subinfo[i].rolname) == 0) {
|
if (strlen(subinfo[i].rolname) == 0) {
|
||||||
write_msg(NULL, "WARNING: owner of subscription \"%s\" appears to be invalid\n", subinfo[i].dobj.name);
|
write_msg(NULL, "WARNING: owner of subscription \"%s\" appears to be invalid\n", subinfo[i].dobj.name);
|
||||||
|
|
@ -4580,10 +4578,6 @@ static void dumpSubscription(Archive *fout, const SubscriptionInfo *subinfo)
|
||||||
appendPQExpBufferStr(query, "NONE");
|
appendPQExpBufferStr(query, "NONE");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strcmp(subinfo->subbinary, "t") == 0) {
|
|
||||||
appendPQExpBuffer(query, ", binary = true");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (strcmp(subinfo->subsynccommit, "off") != 0) {
|
if (strcmp(subinfo->subsynccommit, "off") != 0) {
|
||||||
appendPQExpBuffer(query, ", synchronous_commit = %s", fmtId(subinfo->subsynccommit));
|
appendPQExpBuffer(query, ", synchronous_commit = %s", fmtId(subinfo->subsynccommit));
|
||||||
}
|
}
|
||||||
|
|
@ -10786,11 +10780,6 @@ static void dumpDirectory(Archive* fout)
|
||||||
char* dirpath = NULL;
|
char* dirpath = NULL;
|
||||||
char* diracl = NULL;
|
char* diracl = NULL;
|
||||||
|
|
||||||
if (!isExecUserSuperRole(fout)) {
|
|
||||||
write_msg(NULL, "WARNING: directory not dumped because current user is not a superuser\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Make sure we are in proper schema */
|
/* Make sure we are in proper schema */
|
||||||
selectSourceSchema(fout, "pg_catalog");
|
selectSourceSchema(fout, "pg_catalog");
|
||||||
|
|
||||||
|
|
@ -21400,11 +21389,6 @@ static void dumpSynonym(Archive* fout)
|
||||||
PQExpBuffer q;
|
PQExpBuffer q;
|
||||||
PQExpBuffer delq;
|
PQExpBuffer delq;
|
||||||
|
|
||||||
if (!isExecUserSuperRole(fout)) {
|
|
||||||
write_msg(NULL, "WARNING: synonym not dumped because current user is not a superuser\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
selectSourceSchema(fout, "pg_catalog");
|
selectSourceSchema(fout, "pg_catalog");
|
||||||
query = createPQExpBuffer();
|
query = createPQExpBuffer();
|
||||||
printfPQExpBuffer(query,
|
printfPQExpBuffer(query,
|
||||||
|
|
|
||||||
|
|
@ -498,7 +498,6 @@ typedef struct _SubscriptionInfo {
|
||||||
char *subslotname;
|
char *subslotname;
|
||||||
char *subsynccommit;
|
char *subsynccommit;
|
||||||
char *subpublications;
|
char *subpublications;
|
||||||
char *subbinary;
|
|
||||||
} SubscriptionInfo;
|
} SubscriptionInfo;
|
||||||
|
|
||||||
/* global decls */
|
/* global decls */
|
||||||
|
|
|
||||||
|
|
@ -31,9 +31,6 @@
|
||||||
it will be backuped up in external dirs */
|
it will be backuped up in external dirs */
|
||||||
parray *pgdata_nobackup_dir = NULL;
|
parray *pgdata_nobackup_dir = NULL;
|
||||||
|
|
||||||
/* list of logical replication slots */
|
|
||||||
parray *logical_replslot = NULL;
|
|
||||||
|
|
||||||
static int standby_message_timeout_local = 10 ; /* 10 sec = default */
|
static int standby_message_timeout_local = 10 ; /* 10 sec = default */
|
||||||
static XLogRecPtr stop_backup_lsn = InvalidXLogRecPtr;
|
static XLogRecPtr stop_backup_lsn = InvalidXLogRecPtr;
|
||||||
static XLogRecPtr stop_stream_lsn = InvalidXLogRecPtr;
|
static XLogRecPtr stop_stream_lsn = InvalidXLogRecPtr;
|
||||||
|
|
@ -92,11 +89,10 @@ static void backup_cleanup(bool fatal, void *userdata);
|
||||||
|
|
||||||
static void *backup_files(void *arg);
|
static void *backup_files(void *arg);
|
||||||
|
|
||||||
static void do_backup_instance(PGconn *backup_conn, PGNodeInfo *nodeInfo, bool no_sync, bool backup_logs,
|
static void do_backup_instance(PGconn *backup_conn, PGNodeInfo *nodeInfo, bool no_sync, bool backup_logs);
|
||||||
bool backup_replslots);
|
|
||||||
|
|
||||||
static void pg_start_backup(const char *label, bool smooth, pgBackup *backup,
|
static void pg_start_backup(const char *label, bool smooth, pgBackup *backup,
|
||||||
PGNodeInfo *nodeInfo, PGconn *conn, bool backup_replslots);
|
PGNodeInfo *nodeInfo, PGconn *conn);
|
||||||
static void pg_stop_backup(pgBackup *backup, PGconn *pg_startbackup_conn, PGNodeInfo *nodeInfo);
|
static void pg_stop_backup(pgBackup *backup, PGconn *pg_startbackup_conn, PGNodeInfo *nodeInfo);
|
||||||
static int checkpoint_timeout(PGconn *backup_conn);
|
static int checkpoint_timeout(PGconn *backup_conn);
|
||||||
|
|
||||||
|
|
@ -562,7 +558,7 @@ static void sync_files(parray *database_map, const char *database_path, parray *
|
||||||
* Move files from 'pgdata' to a subdirectory in 'backup_path'.
|
* Move files from 'pgdata' to a subdirectory in 'backup_path'.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
do_backup_instance(PGconn *backup_conn, PGNodeInfo *nodeInfo, bool no_sync, bool backup_logs, bool backup_replslots)
|
do_backup_instance(PGconn *backup_conn, PGNodeInfo *nodeInfo, bool no_sync, bool backup_logs)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
char database_path[MAXPGPATH];
|
char database_path[MAXPGPATH];
|
||||||
|
|
@ -595,7 +591,7 @@ do_backup_instance(PGconn *backup_conn, PGNodeInfo *nodeInfo, bool no_sync, bool
|
||||||
securec_check_c(rc, "\0", "\0");
|
securec_check_c(rc, "\0", "\0");
|
||||||
|
|
||||||
/* Call pg_start_backup function in openGauss connect */
|
/* Call pg_start_backup function in openGauss connect */
|
||||||
pg_start_backup(label, smooth_checkpoint, ¤t, nodeInfo, backup_conn, backup_replslots);
|
pg_start_backup(label, smooth_checkpoint, ¤t, nodeInfo, backup_conn);
|
||||||
|
|
||||||
/* Obtain current timeline */
|
/* Obtain current timeline */
|
||||||
#if PG_VERSION_NUM >= 90600
|
#if PG_VERSION_NUM >= 90600
|
||||||
|
|
@ -628,10 +624,10 @@ do_backup_instance(PGconn *backup_conn, PGNodeInfo *nodeInfo, bool no_sync, bool
|
||||||
/* list files with the logical path. omit $PGDATA */
|
/* list files with the logical path. omit $PGDATA */
|
||||||
if (fio_is_remote(FIO_DB_HOST))
|
if (fio_is_remote(FIO_DB_HOST))
|
||||||
fio_list_dir(backup_files_list, instance_config.pgdata,
|
fio_list_dir(backup_files_list, instance_config.pgdata,
|
||||||
true, true, false, backup_logs, true, 0, backup_replslots);
|
true, true, false, backup_logs, true, 0);
|
||||||
else
|
else
|
||||||
dir_list_file(backup_files_list, instance_config.pgdata,
|
dir_list_file(backup_files_list, instance_config.pgdata,
|
||||||
true, true, false, backup_logs, true, 0, FIO_LOCAL_HOST, backup_replslots);
|
true, true, false, backup_logs, true, 0, FIO_LOCAL_HOST);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Get database_map (name to oid) for use in partial restore feature.
|
* Get database_map (name to oid) for use in partial restore feature.
|
||||||
|
|
@ -753,11 +749,6 @@ do_backup_instance(PGconn *backup_conn, PGNodeInfo *nodeInfo, bool no_sync, bool
|
||||||
}
|
}
|
||||||
pgdata_nobackup_dir = NULL;
|
pgdata_nobackup_dir = NULL;
|
||||||
|
|
||||||
if (logical_replslot) {
|
|
||||||
free_dir_list(logical_replslot);
|
|
||||||
}
|
|
||||||
logical_replslot = NULL;
|
|
||||||
|
|
||||||
/* Cleanup */
|
/* Cleanup */
|
||||||
if (backup_list)
|
if (backup_list)
|
||||||
{
|
{
|
||||||
|
|
@ -858,7 +849,7 @@ static void do_after_backup()
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
do_backup(time_t start_time, pgSetBackupParams *set_backup_params,
|
do_backup(time_t start_time, pgSetBackupParams *set_backup_params,
|
||||||
bool no_validate, bool no_sync, bool backup_logs, bool backup_replslots)
|
bool no_validate, bool no_sync, bool backup_logs)
|
||||||
{
|
{
|
||||||
PGconn *backup_conn = NULL;
|
PGconn *backup_conn = NULL;
|
||||||
PGNodeInfo nodeInfo;
|
PGNodeInfo nodeInfo;
|
||||||
|
|
@ -934,7 +925,7 @@ do_backup(time_t start_time, pgSetBackupParams *set_backup_params,
|
||||||
add_note(¤t, set_backup_params->note);
|
add_note(¤t, set_backup_params->note);
|
||||||
|
|
||||||
/* backup data */
|
/* backup data */
|
||||||
do_backup_instance(backup_conn, &nodeInfo, no_sync, backup_logs, backup_replslots);
|
do_backup_instance(backup_conn, &nodeInfo, no_sync, backup_logs);
|
||||||
pgut_atexit_pop(backup_cleanup, NULL);
|
pgut_atexit_pop(backup_cleanup, NULL);
|
||||||
|
|
||||||
/* compute size of wal files of this backup stored in the archive */
|
/* compute size of wal files of this backup stored in the archive */
|
||||||
|
|
@ -1043,15 +1034,13 @@ confirm_block_size(PGconn *conn, const char *name, int blcksz)
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
pg_start_backup(const char *label, bool smooth, pgBackup *backup,
|
pg_start_backup(const char *label, bool smooth, pgBackup *backup,
|
||||||
PGNodeInfo *nodeInfo, PGconn *conn, bool backup_replslots)
|
PGNodeInfo *nodeInfo, PGconn *conn)
|
||||||
{
|
{
|
||||||
PGresult *res;
|
PGresult *res;
|
||||||
const char *params[2];
|
const char *params[2];
|
||||||
uint32 lsn_hi;
|
uint32 lsn_hi;
|
||||||
uint32 lsn_lo;
|
uint32 lsn_lo;
|
||||||
int ret;
|
int ret;
|
||||||
int i;
|
|
||||||
XLogRecPtr startLsn;
|
|
||||||
|
|
||||||
params[0] = label;
|
params[0] = label;
|
||||||
|
|
||||||
|
|
@ -1079,33 +1068,7 @@ pg_start_backup(const char *label, bool smooth, pgBackup *backup,
|
||||||
XLogDataFromLSN(ret, PQgetvalue(res, 0, 0), &lsn_hi, &lsn_lo);
|
XLogDataFromLSN(ret, PQgetvalue(res, 0, 0), &lsn_hi, &lsn_lo);
|
||||||
securec_check_for_sscanf_s(ret, 2, "\0", "\0");
|
securec_check_for_sscanf_s(ret, 2, "\0", "\0");
|
||||||
/* Calculate LSN */
|
/* Calculate LSN */
|
||||||
startLsn = ((uint64) lsn_hi )<< 32 | lsn_lo;
|
backup->start_lsn = ((uint64) lsn_hi )<< 32 | lsn_lo;
|
||||||
|
|
||||||
if (backup_replslots) {
|
|
||||||
logical_replslot = parray_new();
|
|
||||||
/* query for logical replication slots of subscriptions */
|
|
||||||
res = pgut_execute(conn,
|
|
||||||
"SELECT slot_name, restart_lsn FROM pg_catalog.pg_get_replication_slots()"
|
|
||||||
"WHERE slot_type = 'logical' AND plugin = 'pgoutput'", 0, NULL);
|
|
||||||
if (PQntuples(res) == 0) {
|
|
||||||
elog(LOG, "logical replication slots for subscriptions not found");
|
|
||||||
} else {
|
|
||||||
XLogRecPtr repslotLsn;
|
|
||||||
|
|
||||||
for (i = 0; i < PQntuples(res); i++) {
|
|
||||||
XLogDataFromLSN(ret, PQgetvalue(res, i, 1), &lsn_hi, &lsn_lo);
|
|
||||||
securec_check_for_sscanf_s(ret, 2, "\0", "\0");
|
|
||||||
repslotLsn = ((uint64) lsn_hi )<< 32 | lsn_lo;
|
|
||||||
startLsn = Min(startLsn, repslotLsn);
|
|
||||||
|
|
||||||
char* slotname = pg_strdup(PQgetvalue(res, i, 0));
|
|
||||||
parray_append(logical_replslot, slotname);
|
|
||||||
}
|
|
||||||
elog(WARNING, "logical replication slots for subscriptions will be backed up. "
|
|
||||||
"If don't use them after restoring, please drop them to avoid affecting xlog recycling.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
backup->start_lsn = startLsn;
|
|
||||||
|
|
||||||
PQclear(res);
|
PQclear(res);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -42,6 +42,13 @@ const char *pgdata_exclude_dir[] =
|
||||||
(const char *)"pg_stat_tmp",
|
(const char *)"pg_stat_tmp",
|
||||||
(const char *)"pgsql_tmp",
|
(const char *)"pgsql_tmp",
|
||||||
|
|
||||||
|
/*
|
||||||
|
* It is generally not useful to backup the contents of this directory even
|
||||||
|
* if the intention is to restore to another master. See backup.sgml for a
|
||||||
|
* more detailed description.
|
||||||
|
*/
|
||||||
|
(const char *)"pg_replslot",
|
||||||
|
|
||||||
/* Contents removed on startup, see dsm_cleanup_for_mmap(). */
|
/* Contents removed on startup, see dsm_cleanup_for_mmap(). */
|
||||||
(const char *)"pg_dynshmem",
|
(const char *)"pg_dynshmem",
|
||||||
|
|
||||||
|
|
@ -61,7 +68,7 @@ const char *pgdata_exclude_dir[] =
|
||||||
(const char *)"pg_subtrans",
|
(const char *)"pg_subtrans",
|
||||||
|
|
||||||
/* end of list */
|
/* end of list */
|
||||||
NULL, /* pg_log and pg_replslot will be set later */
|
NULL, /* pg_log will be set later */
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -121,20 +128,17 @@ may be removed int the future */
|
||||||
|
|
||||||
static int pgCompareString(const void *str1, const void *str2);
|
static int pgCompareString(const void *str1, const void *str2);
|
||||||
|
|
||||||
static char dir_check_file(pgFile *file, bool backup_logs, bool backup_replslots);
|
static char dir_check_file(pgFile *file, bool backup_logs);
|
||||||
static char check_in_tablespace(pgFile *file, bool in_tablespace);
|
static char check_in_tablespace(pgFile *file, bool in_tablespace);
|
||||||
static char check_db_dir(pgFile *file);
|
static char check_db_dir(pgFile *file);
|
||||||
static char check_digit_file(pgFile *file);
|
static char check_digit_file(pgFile *file);
|
||||||
static char check_nobackup_dir(pgFile *file);
|
static char check_nobackup_dir(pgFile *file);
|
||||||
static void dir_list_file_internal(parray *files, pgFile *parent, const char *parent_dir,
|
static void dir_list_file_internal(parray *files, pgFile *parent, const char *parent_dir,
|
||||||
bool exclude, bool follow_symlink, bool backup_logs,
|
bool exclude, bool follow_symlink, bool backup_logs,
|
||||||
bool skip_hidden, int external_dir_num, fio_location location,
|
bool skip_hidden, int external_dir_num, fio_location location);
|
||||||
bool backup_replslots);
|
|
||||||
static void opt_path_map(ConfigOption *opt, const char *arg,
|
static void opt_path_map(ConfigOption *opt, const char *arg,
|
||||||
TablespaceList *list, const char *type);
|
TablespaceList *list, const char *type);
|
||||||
|
|
||||||
char check_logical_replslot_dir(const char *rel_path);
|
|
||||||
|
|
||||||
/* Tablespace mapping */
|
/* Tablespace mapping */
|
||||||
static TablespaceList tablespace_dirs = {NULL, NULL};
|
static TablespaceList tablespace_dirs = {NULL, NULL};
|
||||||
/* Extra directories mapping */
|
/* Extra directories mapping */
|
||||||
|
|
@ -534,7 +538,7 @@ db_map_entry_free(void *entry)
|
||||||
void
|
void
|
||||||
dir_list_file(parray *files, const char *root, bool exclude, bool follow_symlink,
|
dir_list_file(parray *files, const char *root, bool exclude, bool follow_symlink,
|
||||||
bool add_root, bool backup_logs, bool skip_hidden, int external_dir_num,
|
bool add_root, bool backup_logs, bool skip_hidden, int external_dir_num,
|
||||||
fio_location location, bool backup_replslots)
|
fio_location location)
|
||||||
{
|
{
|
||||||
pgFile *file;
|
pgFile *file;
|
||||||
|
|
||||||
|
|
@ -561,7 +565,7 @@ dir_list_file(parray *files, const char *root, bool exclude, bool follow_symlink
|
||||||
parray_append(files, file);
|
parray_append(files, file);
|
||||||
|
|
||||||
dir_list_file_internal(files, file, root, exclude, follow_symlink,
|
dir_list_file_internal(files, file, root, exclude, follow_symlink,
|
||||||
backup_logs, skip_hidden, external_dir_num, location, backup_replslots);
|
backup_logs, skip_hidden, external_dir_num, location);
|
||||||
|
|
||||||
if (!add_root)
|
if (!add_root)
|
||||||
pgFileFree(file);
|
pgFileFree(file);
|
||||||
|
|
@ -585,7 +589,7 @@ dir_list_file(parray *files, const char *root, bool exclude, bool follow_symlink
|
||||||
* - datafiles
|
* - datafiles
|
||||||
*/
|
*/
|
||||||
static char
|
static char
|
||||||
dir_check_file(pgFile *file, bool backup_logs, bool backup_replslots)
|
dir_check_file(pgFile *file, bool backup_logs)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
int sscanf_res;
|
int sscanf_res;
|
||||||
|
|
@ -648,29 +652,6 @@ dir_check_file(pgFile *file, bool backup_logs, bool backup_replslots)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Backup pg_replslot if it is specified.
|
|
||||||
* It is generally not useful to backup the contents of this directory even
|
|
||||||
* if the intention is to restore to another master. See backup.sgml for a
|
|
||||||
* more detailed description.
|
|
||||||
*/
|
|
||||||
if (!backup_replslots) {
|
|
||||||
if (strcmp(file->rel_path, PG_REPLSLOT_DIR) == 0) {
|
|
||||||
/* Skip */
|
|
||||||
elog(VERBOSE, "Excluding directory content: %s", file->rel_path);
|
|
||||||
return CHECK_EXCLUDE_FALSE;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
/*
|
|
||||||
* Check file that under pg_replslot and judge whether it
|
|
||||||
* belonged to logical replication slots for subscriptions.
|
|
||||||
*/
|
|
||||||
if (strcmp(file->rel_path, PG_REPLSLOT_DIR) != 0 &&
|
|
||||||
path_is_prefix_of_path(PG_REPLSLOT_DIR, file->rel_path)) {
|
|
||||||
return check_logical_replslot_dir(file->rel_path);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = check_nobackup_dir(file);
|
ret = check_nobackup_dir(file);
|
||||||
if (ret != -1) { /* -1 means need backup */
|
if (ret != -1) { /* -1 means need backup */
|
||||||
return ret;
|
return ret;
|
||||||
|
|
@ -768,35 +749,6 @@ static char check_nobackup_dir(pgFile *file)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
char check_logical_replslot_dir(const char *rel_path)
|
|
||||||
{
|
|
||||||
char ret = CHECK_FALSE;
|
|
||||||
int i = 0;
|
|
||||||
char *tmp = pg_strdup(rel_path);
|
|
||||||
char *p;
|
|
||||||
#define DIRECTORY_DELIMITER "/"
|
|
||||||
|
|
||||||
if (logical_replslot) {
|
|
||||||
/* extract slot name from rel_path, such as sub1 from pg_replslot/sub1/snap */
|
|
||||||
p = strtok(tmp, DIRECTORY_DELIMITER);
|
|
||||||
if (p != NULL) {
|
|
||||||
p = strtok(NULL, DIRECTORY_DELIMITER);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; p != NULL && i < (int)parray_num(logical_replslot); i++) {
|
|
||||||
char *slotName = (char *)parray_get(logical_replslot, i);
|
|
||||||
if (strcmp(p, slotName) == 0) {
|
|
||||||
pfree(tmp);
|
|
||||||
return CHECK_TRUE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
ret = CHECK_TRUE;
|
|
||||||
}
|
|
||||||
pfree(tmp);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static char check_db_dir(pgFile *file)
|
static char check_db_dir(pgFile *file)
|
||||||
{
|
{
|
||||||
char ret = -1;
|
char ret = -1;
|
||||||
|
|
@ -937,8 +889,7 @@ bool SkipSomeDirFile(pgFile *file, struct dirent *dent, bool skipHidden)
|
||||||
static void
|
static void
|
||||||
dir_list_file_internal(parray *files, pgFile *parent, const char *parent_dir,
|
dir_list_file_internal(parray *files, pgFile *parent, const char *parent_dir,
|
||||||
bool exclude, bool follow_symlink, bool backup_logs,
|
bool exclude, bool follow_symlink, bool backup_logs,
|
||||||
bool skip_hidden, int external_dir_num, fio_location location,
|
bool skip_hidden, int external_dir_num, fio_location location)
|
||||||
bool backup_replslots)
|
|
||||||
{
|
{
|
||||||
DIR *dir;
|
DIR *dir;
|
||||||
struct dirent *dent;
|
struct dirent *dent;
|
||||||
|
|
@ -986,7 +937,7 @@ dir_list_file_internal(parray *files, pgFile *parent, const char *parent_dir,
|
||||||
|
|
||||||
if (exclude)
|
if (exclude)
|
||||||
{
|
{
|
||||||
check_res = dir_check_file(file, backup_logs, backup_replslots);
|
check_res = dir_check_file(file, backup_logs);
|
||||||
if (check_res == CHECK_FALSE)
|
if (check_res == CHECK_FALSE)
|
||||||
{
|
{
|
||||||
/* Skip */
|
/* Skip */
|
||||||
|
|
@ -1012,7 +963,7 @@ dir_list_file_internal(parray *files, pgFile *parent, const char *parent_dir,
|
||||||
*/
|
*/
|
||||||
if (S_ISDIR(file->mode))
|
if (S_ISDIR(file->mode))
|
||||||
dir_list_file_internal(files, file, child, exclude, follow_symlink,
|
dir_list_file_internal(files, file, child, exclude, follow_symlink,
|
||||||
backup_logs, skip_hidden, external_dir_num, location, backup_replslots);
|
backup_logs, skip_hidden, external_dir_num, location);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (errno && errno != ENOENT)
|
if (errno && errno != ENOENT)
|
||||||
|
|
|
||||||
|
|
@ -51,7 +51,6 @@ typedef struct
|
||||||
bool exclusive_backup;
|
bool exclusive_backup;
|
||||||
bool skip_hidden;
|
bool skip_hidden;
|
||||||
int external_dir_num;
|
int external_dir_num;
|
||||||
bool backup_replslots;
|
|
||||||
} fio_list_dir_request;
|
} fio_list_dir_request;
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
|
|
@ -1795,7 +1794,7 @@ cleanup:
|
||||||
/* Compile the array of files located on remote machine in directory root */
|
/* Compile the array of files located on remote machine in directory root */
|
||||||
void fio_list_dir(parray *files, const char *root, bool exclude,
|
void fio_list_dir(parray *files, const char *root, bool exclude,
|
||||||
bool follow_symlink, bool add_root, bool backup_logs,
|
bool follow_symlink, bool add_root, bool backup_logs,
|
||||||
bool skip_hidden, int external_dir_num, bool backup_replslots)
|
bool skip_hidden, int external_dir_num)
|
||||||
{
|
{
|
||||||
fio_header hdr;
|
fio_header hdr;
|
||||||
fio_list_dir_request req;
|
fio_list_dir_request req;
|
||||||
|
|
@ -1812,7 +1811,6 @@ void fio_list_dir(parray *files, const char *root, bool exclude,
|
||||||
req.exclusive_backup = exclusive_backup;
|
req.exclusive_backup = exclusive_backup;
|
||||||
req.skip_hidden = skip_hidden;
|
req.skip_hidden = skip_hidden;
|
||||||
req.external_dir_num = external_dir_num;
|
req.external_dir_num = external_dir_num;
|
||||||
req.backup_replslots = backup_replslots;
|
|
||||||
|
|
||||||
hdr.cop = FIO_LIST_DIR;
|
hdr.cop = FIO_LIST_DIR;
|
||||||
hdr.size = sizeof(req);
|
hdr.size = sizeof(req);
|
||||||
|
|
@ -1872,14 +1870,7 @@ void fio_list_dir(parray *files, const char *root, bool exclude,
|
||||||
securec_check_ss_c(nRet, "\0", "\0");
|
securec_check_ss_c(nRet, "\0", "\0");
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Check file that under pg_replslot and judge whether it
|
|
||||||
* belonged to logical replication slots for subscriptions.
|
|
||||||
*/
|
|
||||||
if (backup_replslots && strcmp(buf, PG_REPLSLOT_DIR) != 0 &&
|
|
||||||
path_is_prefix_of_path(PG_REPLSLOT_DIR, buf) && check_logical_replslot_dir(file->rel_path) != 1) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
parray_append(files, file);
|
parray_append(files, file);
|
||||||
}
|
}
|
||||||
|
|
@ -1923,7 +1914,7 @@ static void fio_list_dir_impl(int out, char* buf)
|
||||||
|
|
||||||
dir_list_file(file_files, req->path, req->exclude, req->follow_symlink,
|
dir_list_file(file_files, req->path, req->exclude, req->follow_symlink,
|
||||||
req->add_root, req->backup_logs, req->skip_hidden,
|
req->add_root, req->backup_logs, req->skip_hidden,
|
||||||
req->external_dir_num, FIO_LOCAL_HOST, req->backup_replslots);
|
req->external_dir_num, FIO_LOCAL_HOST);
|
||||||
|
|
||||||
/* send information about files to the main process */
|
/* send information about files to the main process */
|
||||||
for (i = 0; i < (int)parray_num(file_files); i++)
|
for (i = 0; i < (int)parray_num(file_files); i++)
|
||||||
|
|
|
||||||
|
|
@ -163,7 +163,5 @@ extern z_off_t fio_gzseek(gzFile f, z_off_t offset, int whence);
|
||||||
extern const char* fio_gzerror(gzFile file, int *errnum);
|
extern const char* fio_gzerror(gzFile file, int *errnum);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
extern char check_logical_replslot_dir(const char *rel_path);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -154,7 +154,6 @@ void help_pg_probackup(void)
|
||||||
printf(_(" [--remote-port=port] [--ssh-options=ssh_options]\n"));
|
printf(_(" [--remote-port=port] [--ssh-options=ssh_options]\n"));
|
||||||
printf(_(" [--remote-libpath=libpath]\n"));
|
printf(_(" [--remote-libpath=libpath]\n"));
|
||||||
printf(_(" [--ttl=interval] [--expire-time=time]\n"));
|
printf(_(" [--ttl=interval] [--expire-time=time]\n"));
|
||||||
printf(_(" [--backup-pg-replslot]\n"));
|
|
||||||
printf(_(" [--help]\n"));
|
printf(_(" [--help]\n"));
|
||||||
|
|
||||||
printf(_("\n %s restore -B backup-path --instance=instance_name\n"), PROGRAM_NAME);
|
printf(_("\n %s restore -B backup-path --instance=instance_name\n"), PROGRAM_NAME);
|
||||||
|
|
@ -421,7 +420,6 @@ static void help_backup(void)
|
||||||
printf(_(" [--remote-port=port] [--ssh-options=ssh_options]\n"));
|
printf(_(" [--remote-port=port] [--ssh-options=ssh_options]\n"));
|
||||||
printf(_(" [--remote-libpath=libpath]\n"));
|
printf(_(" [--remote-libpath=libpath]\n"));
|
||||||
printf(_(" [--ttl=interval] [--expire-time=time]\n\n"));
|
printf(_(" [--ttl=interval] [--expire-time=time]\n\n"));
|
||||||
printf(_(" [--backup-pg-replslot]\n"));
|
|
||||||
|
|
||||||
printf(_(" -B, --backup-path=backup-path location of the backup storage area\n"));
|
printf(_(" -B, --backup-path=backup-path location of the backup storage area\n"));
|
||||||
printf(_(" --instance=instance_name name of the instance\n"));
|
printf(_(" --instance=instance_name name of the instance\n"));
|
||||||
|
|
@ -443,7 +441,6 @@ static void help_backup(void)
|
||||||
printf(_(" --note=text add note to backup\n"));
|
printf(_(" --note=text add note to backup\n"));
|
||||||
printf(_(" (example: --note='backup before app update to v13.1')\n"));
|
printf(_(" (example: --note='backup before app update to v13.1')\n"));
|
||||||
printf(_(" --archive-timeout=timeout wait timeout for WAL segment archiving (default: 5min)\n"));
|
printf(_(" --archive-timeout=timeout wait timeout for WAL segment archiving (default: 5min)\n"));
|
||||||
printf(_(" --backup-pg-replslot] backup of '%s' directory\n"), PG_REPLSLOT_DIR);
|
|
||||||
|
|
||||||
printf(_("\n Logging options:\n"));
|
printf(_("\n Logging options:\n"));
|
||||||
printf(_(" --log-level-console=log-level-console\n"));
|
printf(_(" --log-level-console=log-level-console\n"));
|
||||||
|
|
|
||||||
|
|
@ -77,7 +77,6 @@ int rw_timeout = 0;
|
||||||
|
|
||||||
/* backup options */
|
/* backup options */
|
||||||
bool backup_logs = false;
|
bool backup_logs = false;
|
||||||
bool backup_replslots = false;
|
|
||||||
bool smooth_checkpoint;
|
bool smooth_checkpoint;
|
||||||
char *remote_agent;
|
char *remote_agent;
|
||||||
static char *backup_note = NULL;
|
static char *backup_note = NULL;
|
||||||
|
|
@ -187,7 +186,6 @@ static ConfigOption cmd_options[] =
|
||||||
{ 'b', 145, "wal", &delete_wal, SOURCE_CMD_STRICT },
|
{ 'b', 145, "wal", &delete_wal, SOURCE_CMD_STRICT },
|
||||||
{ 'b', 146, "expired", &delete_expired, SOURCE_CMD_STRICT },
|
{ 'b', 146, "expired", &delete_expired, SOURCE_CMD_STRICT },
|
||||||
{ 's', 172, "status", &delete_status, SOURCE_CMD_STRICT },
|
{ 's', 172, "status", &delete_status, SOURCE_CMD_STRICT },
|
||||||
{ 'b', 186, "backup-pg-replslot", &backup_replslots, SOURCE_CMD_STRICT},
|
|
||||||
|
|
||||||
{ 'b', 147, "force", &force, SOURCE_CMD_STRICT },
|
{ 'b', 147, "force", &force, SOURCE_CMD_STRICT },
|
||||||
{ 'b', 148, "compress", &compress_shortcut, SOURCE_CMD_STRICT },
|
{ 'b', 148, "compress", &compress_shortcut, SOURCE_CMD_STRICT },
|
||||||
|
|
@ -552,7 +550,7 @@ static int do_actual_operate()
|
||||||
elog(ERROR, "required parameter not specified: BACKUP_MODE "
|
elog(ERROR, "required parameter not specified: BACKUP_MODE "
|
||||||
"(-b, --backup-mode)");
|
"(-b, --backup-mode)");
|
||||||
|
|
||||||
return do_backup(start_time, set_backup_params, no_validate, no_sync, backup_logs, backup_replslots);
|
return do_backup(start_time, set_backup_params, no_validate, no_sync, backup_logs);
|
||||||
}
|
}
|
||||||
case RESTORE_CMD:
|
case RESTORE_CMD:
|
||||||
return do_restore_or_validate(current.backup_id,
|
return do_restore_or_validate(current.backup_id,
|
||||||
|
|
|
||||||
|
|
@ -69,7 +69,6 @@ extern const char *PROGRAM_FULL_PATH;
|
||||||
#define HEADER_MAP "page_header_map"
|
#define HEADER_MAP "page_header_map"
|
||||||
#define HEADER_MAP_TMP "page_header_map_tmp"
|
#define HEADER_MAP_TMP "page_header_map_tmp"
|
||||||
#define PG_RELATIVE_TBLSPC_DIR "pg_location"
|
#define PG_RELATIVE_TBLSPC_DIR "pg_location"
|
||||||
#define PG_REPLSLOT_DIR "pg_replslot"
|
|
||||||
|
|
||||||
/* Timeout defaults */
|
/* Timeout defaults */
|
||||||
#define ARCHIVE_TIMEOUT_DEFAULT 300
|
#define ARCHIVE_TIMEOUT_DEFAULT 300
|
||||||
|
|
|
||||||
|
|
@ -54,9 +54,6 @@ extern bool smooth_checkpoint;
|
||||||
it will be backuped up in external dirs */
|
it will be backuped up in external dirs */
|
||||||
extern parray *pgdata_nobackup_dir;
|
extern parray *pgdata_nobackup_dir;
|
||||||
|
|
||||||
/* list of logical replication slots */
|
|
||||||
extern parray *logical_replslot;
|
|
||||||
|
|
||||||
/* remote probackup options */
|
/* remote probackup options */
|
||||||
extern char* remote_agent;
|
extern char* remote_agent;
|
||||||
|
|
||||||
|
|
@ -92,7 +89,7 @@ extern const char *pgdata_exclude_dir[];
|
||||||
|
|
||||||
/* in backup.c */
|
/* in backup.c */
|
||||||
extern int do_backup(time_t start_time, pgSetBackupParams *set_backup_params,
|
extern int do_backup(time_t start_time, pgSetBackupParams *set_backup_params,
|
||||||
bool no_validate, bool no_sync, bool backup_logs, bool backup_replslots);
|
bool no_validate, bool no_sync, bool backup_logs);
|
||||||
extern BackupMode parse_backup_mode(const char *value);
|
extern BackupMode parse_backup_mode(const char *value);
|
||||||
extern const char *deparse_backup_mode(BackupMode mode);
|
extern const char *deparse_backup_mode(BackupMode mode);
|
||||||
extern void process_block_change(ForkNumber forknum, const RelFileNode rnode,
|
extern void process_block_change(ForkNumber forknum, const RelFileNode rnode,
|
||||||
|
|
@ -242,8 +239,7 @@ extern const char* deparse_compress_alg(int alg);
|
||||||
/* in dir.c */
|
/* in dir.c */
|
||||||
extern void dir_list_file(parray *files, const char *root, bool exclude,
|
extern void dir_list_file(parray *files, const char *root, bool exclude,
|
||||||
bool follow_symlink, bool add_root, bool backup_logs,
|
bool follow_symlink, bool add_root, bool backup_logs,
|
||||||
bool skip_hidden, int external_dir_num, fio_location location,
|
bool skip_hidden, int external_dir_num, fio_location location);
|
||||||
bool backup_replslots = false);
|
|
||||||
|
|
||||||
extern void create_data_directories(parray *dest_files,
|
extern void create_data_directories(parray *dest_files,
|
||||||
const char *data_dir,
|
const char *data_dir,
|
||||||
|
|
@ -436,8 +432,7 @@ extern int fio_send_file(const char *from_fullpath, const char *to_fullpath, FIL
|
||||||
pgFile *file, char **errormsg);
|
pgFile *file, char **errormsg);
|
||||||
|
|
||||||
extern void fio_list_dir(parray *files, const char *root, bool exclude, bool follow_symlink,
|
extern void fio_list_dir(parray *files, const char *root, bool exclude, bool follow_symlink,
|
||||||
bool add_root, bool backup_logs, bool skip_hidden, int external_dir_num,
|
bool add_root, bool backup_logs, bool skip_hidden, int external_dir_num);
|
||||||
bool backup_replslots = false);
|
|
||||||
|
|
||||||
extern bool pgut_rmtree(const char *path, bool rmtopdir, bool strict);
|
extern bool pgut_rmtree(const char *path, bool rmtopdir, bool strict);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6230,7 +6230,7 @@ Datum GetPartBoundaryByTuple(Relation rel, HeapTuple tuple)
|
||||||
return Timestamp2Boundarys(rel, Align2UpBoundary(value, partMap->intervalValue, boundaryTs));
|
return Timestamp2Boundarys(rel, Align2UpBoundary(value, partMap->intervalValue, boundaryTs));
|
||||||
}
|
}
|
||||||
|
|
||||||
Oid AddNewIntervalPartition(Relation rel, void* insertTuple, bool isDDL)
|
Oid AddNewIntervalPartition(Relation rel, void* insertTuple)
|
||||||
{
|
{
|
||||||
Relation pgPartRel = NULL;
|
Relation pgPartRel = NULL;
|
||||||
Oid newPartOid = InvalidOid;
|
Oid newPartOid = InvalidOid;
|
||||||
|
|
@ -6327,13 +6327,7 @@ Oid AddNewIntervalPartition(Relation rel, void* insertTuple, bool isDDL)
|
||||||
*/
|
*/
|
||||||
CommandCounterIncrement();
|
CommandCounterIncrement();
|
||||||
|
|
||||||
/*
|
UpdatePgObjectChangecsn(RelationGetRelid(rel), rel->rd_rel->relkind);
|
||||||
* If add interval partition in the DDL, do not need to change the csn
|
|
||||||
* because the scn has been changed in the DDL.
|
|
||||||
*/
|
|
||||||
if (!isDDL) {
|
|
||||||
UpdatePgObjectChangecsn(RelationGetRelid(rel), rel->rd_rel->relkind);
|
|
||||||
}
|
|
||||||
|
|
||||||
return newPartOid;
|
return newPartOid;
|
||||||
}
|
}
|
||||||
|
|
@ -7119,7 +7113,7 @@ int lookupHBucketid(oidvector *buckets, int low, int2 bktId)
|
||||||
* Description :
|
* Description :
|
||||||
* Notes :
|
* Notes :
|
||||||
*/
|
*/
|
||||||
Oid heapTupleGetPartitionId(Relation rel, void *tuple, bool isDDL)
|
Oid heapTupleGetPartitionId(Relation rel, void *tuple)
|
||||||
{
|
{
|
||||||
Oid partitionid = InvalidOid;
|
Oid partitionid = InvalidOid;
|
||||||
|
|
||||||
|
|
@ -7146,7 +7140,7 @@ Oid heapTupleGetPartitionId(Relation rel, void *tuple, bool isDDL)
|
||||||
(errcode(ERRCODE_NO_DATA_FOUND), errmsg("inserted partition key does not map to any table partition")));
|
(errcode(ERRCODE_NO_DATA_FOUND), errmsg("inserted partition key does not map to any table partition")));
|
||||||
} break;
|
} break;
|
||||||
case PART_AREA_INTERVAL: {
|
case PART_AREA_INTERVAL: {
|
||||||
return AddNewIntervalPartition(rel, tuple, isDDL);
|
return AddNewIntervalPartition(rel, tuple);
|
||||||
} break;
|
} break;
|
||||||
case PART_AREA_LIST: {
|
case PART_AREA_LIST: {
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
|
|
|
||||||
|
|
@ -52,7 +52,7 @@ static_assert(sizeof(false) == sizeof(char), "illegal bool size");
|
||||||
static struct HTAB* nameHash = NULL;
|
static struct HTAB* nameHash = NULL;
|
||||||
static struct HTAB* oidHash = NULL;
|
static struct HTAB* oidHash = NULL;
|
||||||
|
|
||||||
/* for dolphin */
|
/* for b_sql_plugin */
|
||||||
struct HTAB* b_nameHash = NULL;
|
struct HTAB* b_nameHash = NULL;
|
||||||
struct HTAB* b_oidHash = NULL;
|
struct HTAB* b_oidHash = NULL;
|
||||||
|
|
||||||
|
|
@ -118,7 +118,7 @@ static const FuncGroup* NameHashTableAccess(HASHACTION action, const char* name,
|
||||||
|
|
||||||
Assert(name != NULL);
|
Assert(name != NULL);
|
||||||
|
|
||||||
if (DB_IS_CMPT(B_FORMAT) && b_nameHash != NULL && u_sess->attr.attr_sql.dolphin) {
|
if (DB_IS_CMPT(B_FORMAT) && b_nameHash != NULL && u_sess->attr.attr_sql.b_sql_plugin) {
|
||||||
result = (HashEntryNameToFuncGroup *)hash_search(b_nameHash, &temp_name, action, &found);
|
result = (HashEntryNameToFuncGroup *)hash_search(b_nameHash, &temp_name, action, &found);
|
||||||
} else {
|
} else {
|
||||||
result = (HashEntryNameToFuncGroup *)hash_search(nameHash, &temp_name, action, &found);
|
result = (HashEntryNameToFuncGroup *)hash_search(nameHash, &temp_name, action, &found);
|
||||||
|
|
@ -144,7 +144,7 @@ static const Builtin_func* OidHashTableAccess(HASHACTION action, Oid oid, const
|
||||||
bool found = false;
|
bool found = false;
|
||||||
Assert(oid > 0);
|
Assert(oid > 0);
|
||||||
|
|
||||||
if (DB_IS_CMPT(B_FORMAT) && b_oidHash != NULL && u_sess->attr.attr_sql.dolphin) {
|
if (DB_IS_CMPT(B_FORMAT) && b_oidHash != NULL && u_sess->attr.attr_sql.b_sql_plugin) {
|
||||||
result = (HashEntryOidToBuiltinFunc *)hash_search(b_oidHash, &oid, action, &found);
|
result = (HashEntryOidToBuiltinFunc *)hash_search(b_oidHash, &oid, action, &found);
|
||||||
} else {
|
} else {
|
||||||
result = (HashEntryOidToBuiltinFunc *)hash_search(oidHash, &oid, action, &found);
|
result = (HashEntryOidToBuiltinFunc *)hash_search(oidHash, &oid, action, &found);
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,7 @@
|
||||||
#include "utils/builtins.h"
|
#include "utils/builtins.h"
|
||||||
#include "utils/fmgroids.h"
|
#include "utils/fmgroids.h"
|
||||||
#include "utils/syscache.h"
|
#include "utils/syscache.h"
|
||||||
|
#include "replication/worker_internal.h"
|
||||||
|
|
||||||
static List *textarray_to_stringlist(ArrayType *textarray);
|
static List *textarray_to_stringlist(ArrayType *textarray);
|
||||||
|
|
||||||
|
|
@ -90,13 +91,6 @@ Subscription *GetSubscription(Oid subid, bool missing_ok)
|
||||||
}
|
}
|
||||||
sub->publications = textarray_to_stringlist(DatumGetArrayTypeP(datum));
|
sub->publications = textarray_to_stringlist(DatumGetArrayTypeP(datum));
|
||||||
|
|
||||||
datum = SysCacheGetAttr(SUBSCRIPTIONOID, tup, Anum_pg_subscription_subbinary, &isnull);
|
|
||||||
if (unlikely(isnull)) {
|
|
||||||
sub->binary = false;
|
|
||||||
} else {
|
|
||||||
sub->binary = DatumGetBool(datum);
|
|
||||||
}
|
|
||||||
|
|
||||||
ReleaseSysCache(tup);
|
ReleaseSysCache(tup);
|
||||||
|
|
||||||
return sub;
|
return sub;
|
||||||
|
|
@ -189,7 +183,7 @@ char *get_subscription_name(Oid subid, bool missing_ok)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Clear the list content, only deal with DefElem and string content */
|
/* Clear the list content, only deal with DefElem and string content */
|
||||||
void ClearListContent(List *list)
|
static void ClearListContent(List *list)
|
||||||
{
|
{
|
||||||
ListCell *cell = NULL;
|
ListCell *cell = NULL;
|
||||||
foreach(cell, list) {
|
foreach(cell, list) {
|
||||||
|
|
@ -209,6 +203,25 @@ void ClearListContent(List *list)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Decrypt conninfo for subscription.
|
||||||
|
* IMPORTANT: caller should clear and free the memory after using it immediately
|
||||||
|
*/
|
||||||
|
char *DecryptConninfo(char *encryptConninfo)
|
||||||
|
{
|
||||||
|
const char* sensitiveOptionsArray[] = {"password"};
|
||||||
|
const int sensitiveArrayLength = lengthof(sensitiveOptionsArray);
|
||||||
|
List *defList = ConninfoToDefList(encryptConninfo);
|
||||||
|
DecryptOptions(defList, sensitiveOptionsArray, sensitiveArrayLength, SUBSCRIPTION_MODE);
|
||||||
|
char *decryptConninfo = DefListToString(defList);
|
||||||
|
|
||||||
|
/* defList has plain content, clear it before free */
|
||||||
|
ClearListContent(defList);
|
||||||
|
list_free_ext(defList);
|
||||||
|
/* IMPORTANT: caller should clear and free the memory after using it immediately */
|
||||||
|
return decryptConninfo;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Convert text array to list of strings.
|
* Convert text array to list of strings.
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -70,7 +70,6 @@
|
||||||
|
|
||||||
THR_LOCAL bool skip_read_extern_fields = false;
|
THR_LOCAL bool skip_read_extern_fields = false;
|
||||||
|
|
||||||
#define IS_DATANODE_BUT_NOT_SINGLENODE (IS_PGXC_DATANODE && !IS_SINGLE_NODE)
|
|
||||||
/*
|
/*
|
||||||
* Macros to simplify reading of different kinds of fields. Use these
|
* Macros to simplify reading of different kinds of fields. Use these
|
||||||
* wherever possible to reduce the chance for silly typos. Note that these
|
* wherever possible to reduce the chance for silly typos. Note that these
|
||||||
|
|
@ -402,27 +401,24 @@ THR_LOCAL bool skip_read_extern_fields = false;
|
||||||
token = pg_strtok(&length); /* skip :fldname */ \
|
token = pg_strtok(&length); /* skip :fldname */ \
|
||||||
local_node->fldname = _readBitmapset()
|
local_node->fldname = _readBitmapset()
|
||||||
|
|
||||||
#define READ_TYPEINFO_FIELD(fldname) \
|
#define READ_TYPEINFO_FIELD(fldname) \
|
||||||
do { \
|
do { \
|
||||||
if (local_node->fldname >= FirstBootstrapObjectId) { \
|
if (local_node->fldname >= FirstBootstrapObjectId) { \
|
||||||
IF_EXIST(exprtypename) \
|
IF_EXIST(exprtypename) \
|
||||||
{ \
|
{ \
|
||||||
char* exprtypename = NULL; \
|
char* exprtypename = NULL; \
|
||||||
char* exprtypenamespace = NULL; \
|
char* exprtypenamespace = NULL; \
|
||||||
token = pg_strtok(&length); \
|
token = pg_strtok(&length); \
|
||||||
token = pg_strtok(&length); \
|
token = pg_strtok(&length); \
|
||||||
exprtypename = nullable_string(token, length); \
|
exprtypename = nullable_string(token, length); \
|
||||||
token = pg_strtok(&length); \
|
token = pg_strtok(&length); \
|
||||||
token = pg_strtok(&length); \
|
token = pg_strtok(&length); \
|
||||||
exprtypenamespace = nullable_string(token, length); \
|
exprtypenamespace = nullable_string(token, length); \
|
||||||
/* No need to reset field on CN or singlenode, keep pg_strtok() for forward compatibility */ \
|
local_node->fldname = get_typeoid(get_namespace_oid(exprtypenamespace, false), exprtypename); \
|
||||||
if (IS_DATANODE_BUT_NOT_SINGLENODE) { \
|
pfree_ext(exprtypename); \
|
||||||
local_node->fldname = get_typeoid(get_namespace_oid(exprtypenamespace, false), exprtypename); \
|
pfree_ext(exprtypenamespace); \
|
||||||
} \
|
} \
|
||||||
pfree_ext(exprtypename); \
|
} \
|
||||||
pfree_ext(exprtypenamespace); \
|
|
||||||
} \
|
|
||||||
} \
|
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define READ_TYPEINFO(typePtr) \
|
#define READ_TYPEINFO(typePtr) \
|
||||||
|
|
@ -497,30 +493,9 @@ THR_LOCAL bool skip_read_extern_fields = false;
|
||||||
token = pg_strtok(&length); \
|
token = pg_strtok(&length); \
|
||||||
token = pg_strtok(&length); \
|
token = pg_strtok(&length); \
|
||||||
funcnamespace = nullable_string(token, length); \
|
funcnamespace = nullable_string(token, length); \
|
||||||
bool notfound = false; \
|
if (IS_PGXC_DATANODE && !skip_read_extern_fields) { \
|
||||||
if (IS_DATANODE_BUT_NOT_SINGLENODE && !skip_read_extern_fields) { \
|
local_node->fldname = \
|
||||||
Oid funcoid = InvalidOid; \
|
get_func_oid(funcname, get_namespace_oid(funcnamespace, false), (Expr*)local_node); \
|
||||||
do { \
|
|
||||||
Oid nspid = get_namespace_oid(funcnamespace, true); \
|
|
||||||
if (!OidIsValid(nspid)) { \
|
|
||||||
notfound = true; \
|
|
||||||
break; \
|
|
||||||
} \
|
|
||||||
funcoid = get_func_oid(funcname, nspid, (Expr*)local_node); \
|
|
||||||
} while (0); \
|
|
||||||
if (notfound || !OidIsValid(funcoid)) { \
|
|
||||||
ereport(ERROR, \
|
|
||||||
(errmodule(MOD_OPT), errcode(ERRCODE_UNDEFINED_OBJECT), \
|
|
||||||
errmsg("Cannot identify function %s.%s while deserializing field.", \
|
|
||||||
funcname, funcnamespace), \
|
|
||||||
errdetail("Function with oid %u or its namespace may be renamed", \
|
|
||||||
local_node->fldname), \
|
|
||||||
errhint("Please rebuild column defalt expression, views etc. that are" \
|
|
||||||
" related to this renamed object."), \
|
|
||||||
errcause("Object renamed after recorded as nodetree."), \
|
|
||||||
erraction("Rebuild relevant object."))); \
|
|
||||||
} \
|
|
||||||
local_node->fldname = funcoid; \
|
|
||||||
} \
|
} \
|
||||||
pfree_ext(funcname); \
|
pfree_ext(funcname); \
|
||||||
pfree_ext(funcnamespace); \
|
pfree_ext(funcnamespace); \
|
||||||
|
|
@ -550,7 +525,7 @@ THR_LOCAL bool skip_read_extern_fields = false;
|
||||||
token = pg_strtok(&length); \
|
token = pg_strtok(&length); \
|
||||||
token = pg_strtok(&length); \
|
token = pg_strtok(&length); \
|
||||||
oprrightname = nullable_string(token, length); \
|
oprrightname = nullable_string(token, length); \
|
||||||
if (IS_DATANODE_BUT_NOT_SINGLENODE) { \
|
if (IS_PGXC_DATANODE) { \
|
||||||
namespaceId = get_namespace_oid(opnamespace, false); \
|
namespaceId = get_namespace_oid(opnamespace, false); \
|
||||||
oprleft = get_typeoid(namespaceId, oprleftname); \
|
oprleft = get_typeoid(namespaceId, oprleftname); \
|
||||||
oprright = oprleft; \
|
oprright = oprleft; \
|
||||||
|
|
@ -593,7 +568,7 @@ THR_LOCAL bool skip_read_extern_fields = false;
|
||||||
token = pg_strtok(&length); \
|
token = pg_strtok(&length); \
|
||||||
token = pg_strtok(&length); \
|
token = pg_strtok(&length); \
|
||||||
oprrightname = nullable_string(token, length); \
|
oprrightname = nullable_string(token, length); \
|
||||||
if (IS_DATANODE_BUT_NOT_SINGLENODE) { \
|
if (IS_PGXC_DATANODE) { \
|
||||||
namespaceId = get_namespace_oid(opnamespace, false); \
|
namespaceId = get_namespace_oid(opnamespace, false); \
|
||||||
oprleft = get_typeoid(namespaceId, oprleftname); \
|
oprleft = get_typeoid(namespaceId, oprleftname); \
|
||||||
oprright = oprleft; \
|
oprright = oprleft; \
|
||||||
|
|
@ -2151,21 +2126,14 @@ static FuncExpr* _readFuncExpr(void)
|
||||||
ereport(ERROR, (errcode(ERRCODE_UNEXPECTED_NULL_VALUE), errmsg("NULL seqNamespace for nextval()")));
|
ereport(ERROR, (errcode(ERRCODE_UNEXPECTED_NULL_VALUE), errmsg("NULL seqNamespace for nextval()")));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IS_DATANODE_BUT_NOT_SINGLENODE && !skip_read_extern_fields) {
|
if (!IS_PGXC_COORDINATOR && !skip_read_extern_fields) {
|
||||||
|
Oid seqid = get_valid_relname_relid(seqNamespace, seqName);
|
||||||
|
|
||||||
Oid seqid = get_valid_relname_relid(seqNamespace, seqName, true);
|
|
||||||
Const* firstArg = (Const*)linitial(local_node->args);
|
|
||||||
if (OidIsValid(seqid)) {
|
if (OidIsValid(seqid)) {
|
||||||
|
Const* firstArg = (Const*)linitial(local_node->args);
|
||||||
if (firstArg != NULL) {
|
if (firstArg != NULL) {
|
||||||
firstArg->constvalue = ObjectIdGetDatum(seqid);
|
firstArg->constvalue = ObjectIdGetDatum(seqid);
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
ereport(ERROR, (errmodule(MOD_OPT), errcode(ERRCODE_UNDEFINED_OBJECT),
|
|
||||||
errmsg("Cannot identify sequence %s.%s while deserializing field.", seqNamespace, seqName),
|
|
||||||
errdetail("Sequence with oid %u or its namespace may be renamed",
|
|
||||||
DatumGetObjectId(firstArg->constvalue)),
|
|
||||||
errhint("Please rebuild column defalt expression, views etc. that are related to this sequence"),
|
|
||||||
errcause("Object renamed after recorded as nodetree."), erraction("Rebuild relevant object.")));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pfree_ext(seqName);
|
pfree_ext(seqName);
|
||||||
|
|
|
||||||
|
|
@ -1455,13 +1455,6 @@ FuncCandidateList sort_candidate_func_list(FuncCandidateList oldCandidates)
|
||||||
candidates[smallestIndex] = NULL;
|
candidates[smallestIndex] = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < size; i++) {
|
|
||||||
if (candidates[i] != NULL) {
|
|
||||||
lastCandidate->next = candidates[i];
|
|
||||||
lastCandidate = lastCandidate->next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
lastCandidate->next = NULL;
|
|
||||||
pfree(candidates);
|
pfree(candidates);
|
||||||
return sortedCandidates;
|
return sortedCandidates;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -61,7 +61,7 @@ void GlobalBaseDefCache::RemoveElemFromBucket(GlobalBaseEntry *base)
|
||||||
if (is_relation) {
|
if (is_relation) {
|
||||||
GlobalRelationEntry *entry = (GlobalRelationEntry *)base;
|
GlobalRelationEntry *entry = (GlobalRelationEntry *)base;
|
||||||
uint64 rel_size = GetRelEstimateSize(entry);
|
uint64 rel_size = GetRelEstimateSize(entry);
|
||||||
pg_atomic_fetch_sub_u64(&m_base_space, AllocSetContextUsedSpace(((AllocSet)entry->rel_mem_manager)));
|
pg_atomic_fetch_sub_u64(&m_base_space, rel_size);
|
||||||
m_db_entry->MemoryEstimateSub(rel_size);
|
m_db_entry->MemoryEstimateSub(rel_size);
|
||||||
} else {
|
} else {
|
||||||
GlobalPartitionEntry *entry = (GlobalPartitionEntry *)base;
|
GlobalPartitionEntry *entry = (GlobalPartitionEntry *)base;
|
||||||
|
|
@ -77,7 +77,7 @@ void GlobalBaseDefCache::AddHeadToBucket(Index hash_index, GlobalBaseEntry *base
|
||||||
if (is_relation) {
|
if (is_relation) {
|
||||||
GlobalRelationEntry *entry = (GlobalRelationEntry *)base;
|
GlobalRelationEntry *entry = (GlobalRelationEntry *)base;
|
||||||
uint64 rel_size = GetRelEstimateSize(entry);
|
uint64 rel_size = GetRelEstimateSize(entry);
|
||||||
pg_atomic_fetch_add_u64(&m_base_space, AllocSetContextUsedSpace(((AllocSet)entry->rel_mem_manager)));
|
pg_atomic_fetch_add_u64(&m_base_space, rel_size);
|
||||||
m_db_entry->MemoryEstimateAdd(rel_size);
|
m_db_entry->MemoryEstimateAdd(rel_size);
|
||||||
} else {
|
} else {
|
||||||
GlobalPartitionEntry *entry = (GlobalPartitionEntry *)base;
|
GlobalPartitionEntry *entry = (GlobalPartitionEntry *)base;
|
||||||
|
|
|
||||||
|
|
@ -659,27 +659,7 @@ void GlobalSysDBCache::InitSysCacheRelIds()
|
||||||
*/
|
*/
|
||||||
void GlobalSysDBCache::RefreshHotStandby()
|
void GlobalSysDBCache::RefreshHotStandby()
|
||||||
{
|
{
|
||||||
if (!EnableGlobalSysCache()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
hot_standby = (t_thrd.postmaster_cxt.HaShmData->current_mode != STANDBY_MODE || XLogStandbyInfoActive());
|
hot_standby = (t_thrd.postmaster_cxt.HaShmData->current_mode != STANDBY_MODE || XLogStandbyInfoActive());
|
||||||
if (hot_standby || !m_is_inited) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
/* clean all */
|
|
||||||
for (int hash_index = 0; hash_index < m_nbuckets; hash_index ++) {
|
|
||||||
PthreadRWlockRdlock(LOCAL_SYSDB_RESOWNER, &m_db_locks[hash_index]);
|
|
||||||
for (Dlelem * elt = DLGetTail(m_bucket_list.GetBucket(hash_index)); elt != NULL;) {
|
|
||||||
GlobalSysDBCacheEntry *entry = (GlobalSysDBCacheEntry *)DLE_VAL(elt);
|
|
||||||
elt = DLGetPred(elt);
|
|
||||||
entry->ResetDBCache<true>();
|
|
||||||
}
|
|
||||||
PthreadRWlockUnlock(LOCAL_SYSDB_RESOWNER, &m_db_locks[hash_index]);
|
|
||||||
}
|
|
||||||
if (m_global_shared_db_entry != NULL) {
|
|
||||||
m_global_shared_db_entry->ResetDBCache<true>();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GlobalSysDBCache::Init(MemoryContext parent)
|
void GlobalSysDBCache::Init(MemoryContext parent)
|
||||||
|
|
@ -1292,15 +1272,6 @@ int ResizeHashBucket(int origin_nbucket, DynamicHashBucketStrategy strategy)
|
||||||
return cc_nbuckets;
|
return cc_nbuckets;
|
||||||
}
|
}
|
||||||
|
|
||||||
void NotifyGscRecoveryStarted()
|
|
||||||
{
|
|
||||||
if (!EnableGlobalSysCache()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
g_instance.global_sysdbcache.recovery_finished = false;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void NotifyGscRecoveryFinished()
|
void NotifyGscRecoveryFinished()
|
||||||
{
|
{
|
||||||
if (EnableGlobalSysCache()) {
|
if (EnableGlobalSysCache()) {
|
||||||
|
|
|
||||||
|
|
@ -183,7 +183,7 @@ void GlobalSysTabCache::InvalidTuples(int cache_id, uint32 hash_value, bool rese
|
||||||
|
|
||||||
/* maybe upgrade from version before v5r2c00, the cacheid is out of order
|
/* maybe upgrade from version before v5r2c00, the cacheid is out of order
|
||||||
* whatever, we cache nothing except relmap, so just ignore the catcache invalmsg */
|
* whatever, we cache nothing except relmap, so just ignore the catcache invalmsg */
|
||||||
if (unlikely(!g_instance.global_sysdbcache.recovery_finished && m_global_systupcaches[cache_id] == NULL)) {
|
if (unlikely(!g_instance.global_sysdbcache.recovery_finished) && m_global_systupcaches[cache_id] == NULL) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -74,7 +74,7 @@ Partition LocalPartDefCache::SearchPartitionFromGlobalCopy(Oid part_oid)
|
||||||
if (!g_instance.global_sysdbcache.hot_standby) {
|
if (!g_instance.global_sysdbcache.hot_standby) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
if (unlikely(!IsPrimaryRecoveryFinished())) {
|
if (unlikely(!g_instance.global_sysdbcache.recovery_finished)) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
uint32 hash_value = oid_hash((void *)&(part_oid), sizeof(Oid));
|
uint32 hash_value = oid_hash((void *)&(part_oid), sizeof(Oid));
|
||||||
|
|
@ -165,7 +165,7 @@ static bool IsPartOidStoreInGlobal(Oid part_oid)
|
||||||
if (!g_instance.global_sysdbcache.hot_standby) {
|
if (!g_instance.global_sysdbcache.hot_standby) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (unlikely(!IsPrimaryRecoveryFinished())) {
|
if (unlikely(!g_instance.global_sysdbcache.recovery_finished)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (g_instance.global_sysdbcache.StopInsertGSC()) {
|
if (g_instance.global_sysdbcache.StopInsertGSC()) {
|
||||||
|
|
|
||||||
|
|
@ -433,7 +433,7 @@ LocalCatCTup *LocalSysTupCache::SearchTupleFromGlobal(Datum *arguments, uint32 h
|
||||||
bool bypass_gsc = HistoricSnapshotActive() ||
|
bool bypass_gsc = HistoricSnapshotActive() ||
|
||||||
m_global_systupcache->enable_rls ||
|
m_global_systupcache->enable_rls ||
|
||||||
!g_instance.global_sysdbcache.hot_standby ||
|
!g_instance.global_sysdbcache.hot_standby ||
|
||||||
unlikely(!IsPrimaryRecoveryFinished());
|
unlikely(!g_instance.global_sysdbcache.recovery_finished);
|
||||||
if (invalid_entries.ExistTuple(hash_value) || bypass_gsc) {
|
if (invalid_entries.ExistTuple(hash_value) || bypass_gsc) {
|
||||||
global_ct = m_global_systupcache->SearchTupleFromFile(hash_value, arguments, true);
|
global_ct = m_global_systupcache->SearchTupleFromFile(hash_value, arguments, true);
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -585,7 +585,7 @@ LocalCatCList *LocalSysTupCache::SearchListFromGlobal(int nkeys, Datum *argument
|
||||||
bool bypass_gsc = HistoricSnapshotActive() ||
|
bool bypass_gsc = HistoricSnapshotActive() ||
|
||||||
m_global_systupcache->enable_rls ||
|
m_global_systupcache->enable_rls ||
|
||||||
!g_instance.global_sysdbcache.hot_standby ||
|
!g_instance.global_sysdbcache.hot_standby ||
|
||||||
unlikely(!IsPrimaryRecoveryFinished());
|
unlikely(!g_instance.global_sysdbcache.recovery_finished);
|
||||||
GlobalCatCList *global_cl;
|
GlobalCatCList *global_cl;
|
||||||
if (invalid_entries.ExistList() || bypass_gsc) {
|
if (invalid_entries.ExistList() || bypass_gsc) {
|
||||||
global_cl = m_global_systupcache->SearchListFromFile(hash_value, nkeys, arguments, true);
|
global_cl = m_global_systupcache->SearchListFromFile(hash_value, nkeys, arguments, true);
|
||||||
|
|
@ -703,7 +703,7 @@ LocalCatCTup *LocalSysTupCache::SearchTupleFromGlobalForProcAllArgs(
|
||||||
bool bypass_gsc = HistoricSnapshotActive() ||
|
bool bypass_gsc = HistoricSnapshotActive() ||
|
||||||
m_global_systupcache->enable_rls ||
|
m_global_systupcache->enable_rls ||
|
||||||
!g_instance.global_sysdbcache.hot_standby ||
|
!g_instance.global_sysdbcache.hot_standby ||
|
||||||
unlikely(!IsPrimaryRecoveryFinished());
|
unlikely(!g_instance.global_sysdbcache.recovery_finished);
|
||||||
if (invalid_entries.ExistTuple(hash_value) || bypass_gsc) {
|
if (invalid_entries.ExistTuple(hash_value) || bypass_gsc) {
|
||||||
global_ct = m_global_systupcache->SearchTupleFromFileWithArgModes(hash_value, arguments, argModes, true);
|
global_ct = m_global_systupcache->SearchTupleFromFileWithArgModes(hash_value, arguments, argModes, true);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -93,7 +93,7 @@ Relation LocalTabDefCache::SearchRelationFromGlobalCopy(Oid rel_oid)
|
||||||
if (!g_instance.global_sysdbcache.hot_standby) {
|
if (!g_instance.global_sysdbcache.hot_standby) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
if (unlikely(!IsPrimaryRecoveryFinished())) {
|
if (unlikely(!g_instance.global_sysdbcache.recovery_finished)) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
uint32 hash_value = oid_hash((void *)&(rel_oid), sizeof(Oid));
|
uint32 hash_value = oid_hash((void *)&(rel_oid), sizeof(Oid));
|
||||||
|
|
@ -190,7 +190,7 @@ static bool IsRelOidStoreInGlobal(Oid rel_oid)
|
||||||
if (!g_instance.global_sysdbcache.hot_standby) {
|
if (!g_instance.global_sysdbcache.hot_standby) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (unlikely(!IsPrimaryRecoveryFinished())) {
|
if (unlikely(!g_instance.global_sysdbcache.recovery_finished)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (g_instance.global_sysdbcache.StopInsertGSC()) {
|
if (g_instance.global_sysdbcache.StopInsertGSC()) {
|
||||||
|
|
|
||||||
|
|
@ -1723,7 +1723,7 @@ char* get_relname_relid_extend(
|
||||||
extern bool StreamTopConsumerAmI();
|
extern bool StreamTopConsumerAmI();
|
||||||
|
|
||||||
/* same as get_relname_relid except we check for cache invalidation here */
|
/* same as get_relname_relid except we check for cache invalidation here */
|
||||||
Oid get_valid_relname_relid(const char* relnamespace, const char* relname, bool nsp_missing_ok)
|
Oid get_valid_relname_relid(const char* relnamespace, const char* relname)
|
||||||
{
|
{
|
||||||
Oid nspid = InvalidOid;
|
Oid nspid = InvalidOid;
|
||||||
Oid oldnspid = InvalidOid;
|
Oid oldnspid = InvalidOid;
|
||||||
|
|
@ -1747,10 +1747,7 @@ Oid get_valid_relname_relid(const char* relnamespace, const char* relname, bool
|
||||||
if (EnableLocalSysCache()) {
|
if (EnableLocalSysCache()) {
|
||||||
thrd_inval_count = t_thrd.lsc_cxt.lsc->inval_cxt.SIMCounter;
|
thrd_inval_count = t_thrd.lsc_cxt.lsc->inval_cxt.SIMCounter;
|
||||||
}
|
}
|
||||||
nspid = get_namespace_oid(relnamespace, nsp_missing_ok);
|
nspid = get_namespace_oid(relnamespace, false);
|
||||||
if (!OidIsValid(nspid)) {
|
|
||||||
return InvalidOid;
|
|
||||||
}
|
|
||||||
relid = get_relname_relid(relname, nspid);
|
relid = get_relname_relid(relname, nspid);
|
||||||
/*
|
/*
|
||||||
* In bootstrap processing mode, we don't bother with locking
|
* In bootstrap processing mode, we don't bother with locking
|
||||||
|
|
|
||||||
|
|
@ -59,7 +59,7 @@ bool open_join_children = true;
|
||||||
bool will_shutdown = false;
|
bool will_shutdown = false;
|
||||||
|
|
||||||
/* hard-wired binary version number */
|
/* hard-wired binary version number */
|
||||||
const uint32 GRAND_VERSION_NUM = 92606;
|
const uint32 GRAND_VERSION_NUM = 92605;
|
||||||
|
|
||||||
const uint32 PREDPUSH_SAME_LEVEL_VERSION_NUM = 92522;
|
const uint32 PREDPUSH_SAME_LEVEL_VERSION_NUM = 92522;
|
||||||
const uint32 UPSERT_WHERE_VERSION_NUM = 92514;
|
const uint32 UPSERT_WHERE_VERSION_NUM = 92514;
|
||||||
|
|
@ -101,7 +101,6 @@ const uint32 PRIVS_DIRECTORY_VERSION_NUM = 92460;
|
||||||
const uint32 COMMENT_RECORD_PARAM_VERSION_NUM = 92484;
|
const uint32 COMMENT_RECORD_PARAM_VERSION_NUM = 92484;
|
||||||
const uint32 SCAN_BATCH_MODE_VERSION_NUM = 92568;
|
const uint32 SCAN_BATCH_MODE_VERSION_NUM = 92568;
|
||||||
const uint32 PUBLICATION_VERSION_NUM = 92580;
|
const uint32 PUBLICATION_VERSION_NUM = 92580;
|
||||||
const uint32 SUBSCRIPTION_BINARY_VERSION_NUM = 92606;
|
|
||||||
|
|
||||||
/* Version number of the guc parameter backend_version added in V500R001C20 */
|
/* Version number of the guc parameter backend_version added in V500R001C20 */
|
||||||
const uint32 V5R1C20_BACKEND_VERSION_NUM = 92305;
|
const uint32 V5R1C20_BACKEND_VERSION_NUM = 92305;
|
||||||
|
|
|
||||||
|
|
@ -2712,8 +2712,8 @@ void PostgresInitializer::InitExtensionVariable()
|
||||||
}
|
}
|
||||||
|
|
||||||
/* check whether the extension has been created */
|
/* check whether the extension has been created */
|
||||||
const char* dolphin = "dolphin";
|
const char* b_sql_plugin = "b_sql_plugin";
|
||||||
u_sess->attr.attr_sql.dolphin = CheckIfExtensionExists(dolphin);
|
u_sess->attr.attr_sql.b_sql_plugin = CheckIfExtensionExists(b_sql_plugin);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PostgresInitializer::FinishInit()
|
void PostgresInitializer::FinishInit()
|
||||||
|
|
|
||||||
|
|
@ -10340,16 +10340,7 @@ check_sql_expr(const char *stmt, int location, int leaderlen)
|
||||||
|
|
||||||
oldCxt = MemoryContextSwitchTo(u_sess->plsql_cxt.curr_compile_context->compile_tmp_cxt);
|
oldCxt = MemoryContextSwitchTo(u_sess->plsql_cxt.curr_compile_context->compile_tmp_cxt);
|
||||||
u_sess->plsql_cxt.plpgsql_yylloc = plpgsql_yylloc;
|
u_sess->plsql_cxt.plpgsql_yylloc = plpgsql_yylloc;
|
||||||
RawParserHook parser_hook= raw_parser;
|
(void) raw_parser(stmt);
|
||||||
#ifndef ENABLE_MULTIPLE_NODES
|
|
||||||
if (u_sess->attr.attr_sql.dolphin) {
|
|
||||||
int id = GetCustomParserId();
|
|
||||||
if (id >= 0 && g_instance.raw_parser_hook[id] != NULL) {
|
|
||||||
parser_hook = (RawParserHook)g_instance.raw_parser_hook[id];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
(void)parser_hook(stmt, NULL);
|
|
||||||
MemoryContextSwitchTo(oldCxt);
|
MemoryContextSwitchTo(oldCxt);
|
||||||
|
|
||||||
/* Restore former ereport callback */
|
/* Restore former ereport callback */
|
||||||
|
|
|
||||||
|
|
@ -44,22 +44,11 @@ static int g_iPosBlackList = 0;
|
||||||
/* array store for black list */
|
/* array store for black list */
|
||||||
static BBOX_BLACKLIST_STRU g_stBlackList[BBOX_BLACK_LIST_COUNT_MAX];
|
static BBOX_BLACKLIST_STRU g_stBlackList[BBOX_BLACK_LIST_COUNT_MAX];
|
||||||
|
|
||||||
/*
|
/*
|
||||||
function name: BBOX_DetermineMsb
|
* Determines whether the byte order of the local machine is large or small
|
||||||
description: The function should judge the mode that PC uses to store data is Big-endian/Little-endian.
|
* return : ELFDATA2LSB - large
|
||||||
arguments: void
|
* : ELFDATA2MSB - small
|
||||||
return value: An integer that indicates the mode is Big-endian/Little-endian,
|
*/
|
||||||
if it is ELFDATA2LSB, the mode is Little-endian,
|
|
||||||
if it is ELFDATA2MSB, the mode is Big-endian.
|
|
||||||
note:The way that this function judge the mode that PC uses to store data is through a union variable unProbe,
|
|
||||||
at first we give its first member variable sShortInt a value BBOX_MSB_LSB_INT of type short, then its second
|
|
||||||
member variable cSplit[sizeof(short)] equaling to cSplit[2] would have the equal value of the first. Finally we
|
|
||||||
just need to compare BBOX_LITTER_BITS and BBOX_HIGH_BITS, namely the low byte and high byte of
|
|
||||||
BBOX_MSB_LSB_INT, with unProbe.cSplit[0] and unProbe.cSplit[1], if they are correspondingly equal, the mode is
|
|
||||||
Little-endian, else is the Big-endian.
|
|
||||||
date: 2022/8/2
|
|
||||||
contact tel: 18720816902
|
|
||||||
*/
|
|
||||||
int BBOX_DetermineMsb(void)
|
int BBOX_DetermineMsb(void)
|
||||||
{
|
{
|
||||||
union INT_PROBE {
|
union INT_PROBE {
|
||||||
|
|
|
||||||
|
|
@ -51,19 +51,8 @@ struct PIPE_IDS {
|
||||||
static struct PIPE_IDS astPipeIds[BBOX_MAX_PIDS];
|
static struct PIPE_IDS astPipeIds[BBOX_MAX_PIDS];
|
||||||
|
|
||||||
/*
|
/*
|
||||||
function name: bbox_strncmp
|
* compare string pszSrc and pszTarget
|
||||||
description: To compare two substrings, the pointers pszSrc and pszTarget store their host strings'addresses.
|
*/
|
||||||
arguments: Two pointers of type const char*, pointing to two strings needed to be compared.
|
|
||||||
An integer indicates the number of characters at the former of two strings that
|
|
||||||
will be compared.
|
|
||||||
return value: Type s32, an interger.
|
|
||||||
If it's zero, then the former substrings of string pszSrc and pszTarget are same,
|
|
||||||
else it indicates the difference between the first two characters that these two
|
|
||||||
strings can't match.
|
|
||||||
note:The two pointers shouldn't be null. The last argument shouldn't less than zero.
|
|
||||||
date: 2022/8/2
|
|
||||||
contact tel: 18720816902
|
|
||||||
*/
|
|
||||||
s32 bbox_strncmp(const char* pszSrc, const char* pszTarget, s32 count)
|
s32 bbox_strncmp(const char* pszSrc, const char* pszTarget, s32 count)
|
||||||
{
|
{
|
||||||
signed char cRes = 0;
|
signed char cRes = 0;
|
||||||
|
|
@ -79,20 +68,8 @@ s32 bbox_strncmp(const char* pszSrc, const char* pszTarget, s32 count)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
function name: bbox_strcmp
|
* compare string pszSrc and pszTarget
|
||||||
description: compare two strings, the pointer pszSrc and pszTarget store their addresses.
|
*/
|
||||||
arguments: Two pointers of type const char*, pointing to two strings needed to be compared.
|
|
||||||
An integer indicates the number of characters at the former of two strings that
|
|
||||||
will be compared.
|
|
||||||
return value: Type s32, an interger.
|
|
||||||
If it's zero, then the former substrings of string pszSrc and pszTarget are same,
|
|
||||||
else if it's 1, then it indicates between first two characters that these two
|
|
||||||
strings can't match, the character of first string that pszSrc points is greater,
|
|
||||||
else if it's -1, the character of second string that pszTarget points is greater.
|
|
||||||
note:The two pointers shouldn't be null. The last argument shouldn't less than zero.
|
|
||||||
date: 2022/8/2
|
|
||||||
contact tel:same
|
|
||||||
*/
|
|
||||||
s32 bbox_strcmp(const char* pszSrc, const char* pszTarget)
|
s32 bbox_strcmp(const char* pszSrc, const char* pszTarget)
|
||||||
{
|
{
|
||||||
unsigned char c1, c2;
|
unsigned char c1, c2;
|
||||||
|
|
@ -113,15 +90,8 @@ s32 bbox_strcmp(const char* pszSrc, const char* pszTarget)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
function name: bbox_strlen
|
* get the length of string pszString
|
||||||
description: Calculate the length of string.
|
*/
|
||||||
arguments: An pointer that indicates the address of a string.
|
|
||||||
return value: Type s32, an integer indicating the length of string.
|
|
||||||
note: the length of string=(address of the last character not '\0'-address of the first character)/sizeof(char), and sizeof(char)
|
|
||||||
equals to 1, so the length of string=(address of the last character not '\0'-address of the first character).
|
|
||||||
date: 2022/8/2
|
|
||||||
contact tel:same
|
|
||||||
*/
|
|
||||||
s32 bbox_strlen(const char* pszString)
|
s32 bbox_strlen(const char* pszString)
|
||||||
{
|
{
|
||||||
const char* pszTemp = NULL;
|
const char* pszTemp = NULL;
|
||||||
|
|
@ -135,16 +105,8 @@ s32 bbox_strlen(const char* pszString)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
function name: bbox_strnlen
|
* get the length of string pszString
|
||||||
description: Calculate the length of string, but having some restrictive conditions.
|
*/
|
||||||
arguments: An pointer that indicates the address of a string.
|
|
||||||
And an integer that indicates the maxlenth.
|
|
||||||
return value: Type s32, an integer indicating the length of string.
|
|
||||||
note: If the length of string exceed the argument count, then return the length of string,
|
|
||||||
else return the argument count.
|
|
||||||
date: 2022/8/2
|
|
||||||
contact tel:same
|
|
||||||
*/
|
|
||||||
s32 bbox_strnlen(const char* pszString, s32 count)
|
s32 bbox_strnlen(const char* pszString, s32 count)
|
||||||
{
|
{
|
||||||
const char* pszTemp = NULL;
|
const char* pszTemp = NULL;
|
||||||
|
|
@ -157,16 +119,8 @@ s32 bbox_strnlen(const char* pszString, s32 count)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
function name: bbox_atoi
|
* convert a string to interger
|
||||||
description: Convert a string that includes continuous digital characters to an integer,
|
*/
|
||||||
if the first character of the string is '-', then we will return a negative result.
|
|
||||||
arguments: An pointer that indicates the address of a string.
|
|
||||||
return value: Type s32, an integer indicating the result of string converted.
|
|
||||||
note: I think the function isn't perfect, though it's not a core function. For example, what about
|
|
||||||
the condition that the first character of the string is '+'?
|
|
||||||
date: 2022/8/2
|
|
||||||
contact tel:same
|
|
||||||
*/
|
|
||||||
s32 bbox_atoi(const char* pszString)
|
s32 bbox_atoi(const char* pszString)
|
||||||
{
|
{
|
||||||
s32 n = 0;
|
s32 n = 0;
|
||||||
|
|
@ -186,18 +140,10 @@ s32 bbox_atoi(const char* pszString)
|
||||||
|
|
||||||
return iNeg ? -n : n;
|
return iNeg ? -n : n;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
function name: bbox_memcmp
|
* compare memory
|
||||||
description: Compare former count bytes in ASCII of data stored in two areas that pointers cs and ct direct.
|
*/
|
||||||
arguments: Two pointers to areas of memory, and an integer indicating the max counts compared.
|
|
||||||
return value: Type s32, an integer.
|
|
||||||
If the value returned is 0, then the data stored in two areas destined are same,
|
|
||||||
else if is 1, then between two first data in ASCII of byte different, cs's is greater,
|
|
||||||
else if is -1, then ct's is greater.
|
|
||||||
note: The two pointers should not be null, it's dangerous.
|
|
||||||
date: 2022/8/2
|
|
||||||
contact tel: same
|
|
||||||
*/
|
|
||||||
s32 bbox_memcmp(const void* cs, const void* ct, s32 count)
|
s32 bbox_memcmp(const void* cs, const void* ct, s32 count)
|
||||||
{
|
{
|
||||||
const unsigned char *su1 = NULL;
|
const unsigned char *su1 = NULL;
|
||||||
|
|
@ -213,18 +159,8 @@ s32 bbox_memcmp(const void* cs, const void* ct, s32 count)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
function name: bbox_strstr
|
* search string l2 in l1
|
||||||
description: Judge if the string s2 directs is substring of string s1 directs.
|
*/
|
||||||
arguments: Two pointers of type const char*, pointing to two strings.
|
|
||||||
return value: Type char*, a pointer. Actually it's a address, if s2 directs a
|
|
||||||
null string, then return the address of the first character of s1,
|
|
||||||
if the string s2 directs isn't substring of string s1 directs, return
|
|
||||||
null, if the string s2 directs is substring of string s1 directs, then return
|
|
||||||
the address of first character matched.
|
|
||||||
note: The two pointers should not be null, it's dangerous.
|
|
||||||
date: 2022/8/2
|
|
||||||
contact tel: same
|
|
||||||
*/
|
|
||||||
char* bbox_strstr(const char* s1, const char* s2)
|
char* bbox_strstr(const char* s1, const char* s2)
|
||||||
{
|
{
|
||||||
int l1, l2;
|
int l1, l2;
|
||||||
|
|
@ -246,17 +182,8 @@ char* bbox_strstr(const char* s1, const char* s2)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
function name: bbox_mkdir
|
* make a directory
|
||||||
description: We distinguish parent directory and child directory through character '/',
|
*/
|
||||||
normally through a for loop, we can make sure all directories above the directory
|
|
||||||
we want to creat exist, finally we will creat the flag directory after its parent.
|
|
||||||
arguments: A pointers of type const char*, pointing to one strings, which indicates the filename and its full path.
|
|
||||||
return value: An integer of type s32, if it's RET_ERR, then we fail to make a directory, else if it's RET_OK then we succeed.
|
|
||||||
note: Take care the last non-null character of the string needed to be '/', and once if flag directory's
|
|
||||||
ancestors aren't exist, the function return RET_ERR.
|
|
||||||
date: 2022/8/2
|
|
||||||
contact tel: same
|
|
||||||
*/
|
|
||||||
s32 bbox_mkdir(const char* pszDir)
|
s32 bbox_mkdir(const char* pszDir)
|
||||||
{
|
{
|
||||||
char szDirName[BBOX_TMP_LEN_32 * 16];
|
char szDirName[BBOX_TMP_LEN_32 * 16];
|
||||||
|
|
@ -301,16 +228,8 @@ s32 bbox_mkdir(const char* pszDir)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
function name: bbox_GetFreePid
|
* search free pipe id
|
||||||
description: Through a for loop, we search a free pipe in a structure array, to an array element if its
|
*/
|
||||||
member variable isUsed's value is 0, we return the array element's another member variable
|
|
||||||
stPid's address.
|
|
||||||
arguments: void
|
|
||||||
return value: An pointer of type struct PIPE_ID* or NULL.
|
|
||||||
note: none
|
|
||||||
date: 2022/8/2
|
|
||||||
contact tel: same
|
|
||||||
*/
|
|
||||||
struct PIPE_ID* bbox_GetFreePid(void)
|
struct PIPE_ID* bbox_GetFreePid(void)
|
||||||
{
|
{
|
||||||
u32 i;
|
u32 i;
|
||||||
|
|
@ -326,14 +245,8 @@ struct PIPE_ID* bbox_GetFreePid(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
function name: bbox_PutPid
|
* Release the occupied pipeid
|
||||||
description: Release the occupied pipe.
|
*/
|
||||||
arguments: A pointer of type struct PIPE_ID*.
|
|
||||||
return value: void
|
|
||||||
note: If the argument pointer is null, then there is no need to free the storage, the function ends.
|
|
||||||
date: 2022/8/2
|
|
||||||
contact tel: same
|
|
||||||
*/
|
|
||||||
void bbox_PutPid(struct PIPE_ID* pstPid)
|
void bbox_PutPid(struct PIPE_ID* pstPid)
|
||||||
{
|
{
|
||||||
struct PIPE_IDS* pstPids = NULL;
|
struct PIPE_IDS* pstPids = NULL;
|
||||||
|
|
@ -348,16 +261,8 @@ void bbox_PutPid(struct PIPE_ID* pstPid)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
function name: bbox_FindPid
|
* find available pipe id by file handle
|
||||||
description: In all occupied pipes, the function search the flag pipe through compare all structure
|
*/
|
||||||
array elements's member variable stPid's member variable iFd with the function
|
|
||||||
argument iFd, if they are equal, then return the addres of this array elements.
|
|
||||||
arguments: An integer that indicates a file's file handle.
|
|
||||||
return value: A pointer of type struct PIPE_ID* or NULL.
|
|
||||||
note: none
|
|
||||||
date: 2022/8/2
|
|
||||||
contact tel: same
|
|
||||||
*/
|
|
||||||
struct PIPE_ID* bbox_FindPid(int iFd)
|
struct PIPE_ID* bbox_FindPid(int iFd)
|
||||||
{
|
{
|
||||||
u32 i;
|
u32 i;
|
||||||
|
|
@ -376,17 +281,8 @@ struct PIPE_ID* bbox_FindPid(int iFd)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
function name: sys_popen
|
* run popen
|
||||||
description: The function gets a free pipe by function bbox_GetFreePid, if normally, then creat a pipe
|
*/
|
||||||
through sys_pipe, andcreat a child process through function sys_fork, execute a shell command
|
|
||||||
to run a process.
|
|
||||||
arguments: One pointer to a string that represents command line, another pointer of type const char*
|
|
||||||
indicates that the file file handle directs is used in the this mode.
|
|
||||||
return value: A pointer of type struct PIPE_ID* or NULL.
|
|
||||||
note: The string that indicates pszMode should only be "r" or "w",
|
|
||||||
date: 2022/8/2
|
|
||||||
contact tel: same
|
|
||||||
*/
|
|
||||||
s32 sys_popen(char* pszCmd, const char* pszMode)
|
s32 sys_popen(char* pszCmd, const char* pszMode)
|
||||||
{
|
{
|
||||||
struct PIPE_ID* volatile stCurPid = NULL;
|
struct PIPE_ID* volatile stCurPid = NULL;
|
||||||
|
|
@ -491,15 +387,8 @@ s32 sys_popen(char* pszCmd, const char* pszMode)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
function name: sys_pclose
|
* close file handle
|
||||||
description: The function has an contrary action to function sys_popen, it close the pipe
|
*/
|
||||||
that sys_popen open.
|
|
||||||
arguments: iFd, an integer that indicates a file handle.
|
|
||||||
return value: An integer that indicates the final status of the process working before.
|
|
||||||
note: none
|
|
||||||
date: 2022/8/2
|
|
||||||
contact tel: same
|
|
||||||
*/
|
|
||||||
int sys_pclose(s32 iFd)
|
int sys_pclose(s32 iFd)
|
||||||
{
|
{
|
||||||
struct PIPE_ID* pstCur = NULL;
|
struct PIPE_ID* pstCur = NULL;
|
||||||
|
|
@ -522,17 +411,8 @@ int sys_pclose(s32 iFd)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
function name: bbox_listdir
|
* list file in directory
|
||||||
description: The function list all files below this path in directory.
|
*/
|
||||||
arguments: The first argument is a pointer to a string representing a file path, all files below
|
|
||||||
this path will be listed in directory. The second argument is a pointer to a callback
|
|
||||||
function. The last is a pointer of type void*, it indicates a command line.
|
|
||||||
return value: An integer that indicates the result of function, if normal, it's RET_OK, else
|
|
||||||
it's RET_ERR.
|
|
||||||
note: The path that the first argument represents should be absolute path, take care.
|
|
||||||
date: 2022/8/2
|
|
||||||
contact tel: same
|
|
||||||
*/
|
|
||||||
s32 bbox_listdir(const char* pstPath, BBOX_LIST_DIR_CALLBACK callback, void* pArgs)
|
s32 bbox_listdir(const char* pstPath, BBOX_LIST_DIR_CALLBACK callback, void* pArgs)
|
||||||
{
|
{
|
||||||
struct linux_dirent* pstEntry = NULL;
|
struct linux_dirent* pstEntry = NULL;
|
||||||
|
|
|
||||||
|
|
@ -57,37 +57,23 @@ void bbox_initlog(int iLogScreen)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
function name: bbox_itoc
|
* convert int to string
|
||||||
description: Convert an integer to a character.
|
*/
|
||||||
arguments: An integer needed to be converted.
|
|
||||||
return value: An character that corresponds to the function's integer argument.
|
|
||||||
note: The integer argument can be converted in radices more than decimalism.
|
|
||||||
date: 2022/8/2
|
|
||||||
contact tel: 18720816902
|
|
||||||
*/
|
|
||||||
inline char bbox_itoc(u8 sNum)
|
inline char bbox_itoc(u8 sNum)
|
||||||
{
|
{
|
||||||
return (char)((sNum < 10) ? (sNum + 48) : (sNum + 87));
|
return (char)((sNum < 10) ? (sNum + 48) : (sNum + 87));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
function name: bbox_put_dox
|
* convert int to string
|
||||||
description: Conversion of number systems.
|
* in : pCallback - call back function
|
||||||
arguments: The first argument pCallback is a pointer to a callback function, we
|
* ptr - private data to call this function
|
||||||
use it to reverse the final result. The second argument is a pointer of
|
* piCount - offset pointer
|
||||||
type void* used as a argument of function pCallback. The third argument
|
* iSize - buffer size
|
||||||
piCount is a pointer of type int, an offset pointer, also be used as a argument
|
* uNum - the variable to convert
|
||||||
of pCallback. The fourth argument is an integer of 32 bits, it indicates the buffer
|
* sSys - type of variable
|
||||||
size pCallback uses.The fifth argument uNum is a decimal integer that will
|
* isNeg - is negative
|
||||||
be converted to an integer in another radix. The sixth argument is used as
|
* return : need call back
|
||||||
base to conversion of number systems. The last argument indicates the integer
|
*/
|
||||||
after converted is a negative integer or not.
|
|
||||||
return value: An integer, indicating if the function pCallback work successfully.
|
|
||||||
note: The argument uNum should be a positive integer, after conversion of number systems
|
|
||||||
the sign will be appended to string's tail.
|
|
||||||
date: 2022/8/2
|
|
||||||
contact tel: 18720816902
|
|
||||||
*/
|
|
||||||
s32 bbox_put_dox(BBOX_vnprintCallBack pCallback, void* ptr, s32* piCount, u32 iSize, u64 uNum, s32 sSys, s32 isNeg)
|
s32 bbox_put_dox(BBOX_vnprintCallBack pCallback, void* ptr, s32* piCount, u32 iSize, u64 uNum, s32 sSys, s32 isNeg)
|
||||||
{
|
{
|
||||||
s64 i = 0;
|
s64 i = 0;
|
||||||
|
|
@ -128,7 +114,7 @@ s32 bbox_put_dox(BBOX_vnprintCallBack pCallback, void* ptr, s32* piCount, u32 iS
|
||||||
* ptr - private data to call this function
|
* ptr - private data to call this function
|
||||||
* iSize - buffer size
|
* iSize - buffer size
|
||||||
* pFmt - format type
|
* pFmt - format type
|
||||||
* ap - parameter list pointer<EFBFBD><EFBFBD>ʽ
|
* ap - parameter list pointer¸ñʽ
|
||||||
* return : length of string
|
* return : length of string
|
||||||
*/
|
*/
|
||||||
s32 bbox_vsnprintf(BBOX_vnprintCallBack pCallback, void* ptr, s32 iSize, const char* pFmt, va_list ap)
|
s32 bbox_vsnprintf(BBOX_vnprintCallBack pCallback, void* ptr, s32 iSize, const char* pFmt, va_list ap)
|
||||||
|
|
|
||||||
|
|
@ -222,7 +222,6 @@ NON_EXEC_STATIC void PercentileMain()
|
||||||
g_instance.stat_cxt.force_process = false;
|
g_instance.stat_cxt.force_process = false;
|
||||||
sleep(SLEEP_INTERVAL);
|
sleep(SLEEP_INTERVAL);
|
||||||
}
|
}
|
||||||
elog(LOG, "instrumention percentile ended");
|
|
||||||
gs_thread_exit(0);
|
gs_thread_exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,23 +14,11 @@ import os
|
||||||
|
|
||||||
from . import feature_mapping
|
from . import feature_mapping
|
||||||
from . import features
|
from . import features
|
||||||
# To import file feature_mapping and features from parent folder
|
|
||||||
|
|
||||||
#function name: load_feature_lib
|
|
||||||
#description: Print the variable FEATURE_LIB in the file-- features
|
|
||||||
#return value: The value of FEATURE_LIB
|
|
||||||
#date: 2022/8/2
|
|
||||||
#contact: 1865997821
|
|
||||||
|
|
||||||
def load_feature_lib():
|
def load_feature_lib():
|
||||||
return features.FEATURE_LIB
|
return features.FEATURE_LIB
|
||||||
|
|
||||||
#function name: get_feature_mapper
|
|
||||||
#description: Get the item and value of a dictionary type in the file-- feature_mapping and output it as a generator.
|
|
||||||
#return value: The item and value in _dict_ variable
|
|
||||||
#note:Dictionary key-value pairs must start with C then the item and value will be return.
|
|
||||||
#date: 2022/8/2
|
|
||||||
#contact: 1865997821
|
|
||||||
|
|
||||||
def get_feature_mapper():
|
def get_feature_mapper():
|
||||||
return {
|
return {
|
||||||
|
|
|
||||||
|
|
@ -11,27 +11,22 @@
|
||||||
# MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
# MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||||
# See the Mulan PSL v2 for more details.
|
# See the Mulan PSL v2 for more details.
|
||||||
import csv
|
import csv
|
||||||
#import csv packet
|
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
from typing import List
|
from typing import List
|
||||||
# To import defaultdict in the parent floder collections and List in the parent floder typing
|
|
||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
# import numpy packet as the name np
|
|
||||||
|
|
||||||
from ..analyzer import _euclid_distance as euclid_distance
|
from ..analyzer import _euclid_distance as euclid_distance
|
||||||
from dbmind.common.utils import ExceptionCatch
|
from dbmind.common.utils import ExceptionCatch
|
||||||
#To import private function-- _euclid_distance as euclid_distance
|
|
||||||
|
|
||||||
#function name: calculate_weight
|
|
||||||
#description: This function will output feature_weight (= residual_vector / the sum of residual_vector)
|
|
||||||
#The data used for the calculation is from the features_labels_dict, and the key value pairs of the features_labels_dict are filtered
|
|
||||||
#arguments: np.ndarray and np.ndarray
|
|
||||||
#return value: weight_matrix
|
|
||||||
#date: 2022/8/2
|
|
||||||
#contact: 1865997821
|
|
||||||
|
|
||||||
def calculate_weight(features: np.ndarray, labels: np.ndarray) -> List:
|
def calculate_weight(features: np.ndarray, labels: np.ndarray) -> List:
|
||||||
|
"""
|
||||||
|
Calculate weight matrix based on feature set
|
||||||
|
:param features: feature set
|
||||||
|
:param labels: label set
|
||||||
|
:return: weight_matrix
|
||||||
|
"""
|
||||||
normalize_features, normalize_labels = [], []
|
normalize_features, normalize_labels = [], []
|
||||||
features_labels_dict = defaultdict(list)
|
features_labels_dict = defaultdict(list)
|
||||||
for i in range(len(labels)):
|
for i in range(len(labels)):
|
||||||
|
|
@ -61,16 +56,6 @@ def calculate_weight(features: np.ndarray, labels: np.ndarray) -> List:
|
||||||
return weight_matrix
|
return weight_matrix
|
||||||
|
|
||||||
|
|
||||||
# function name: build_model
|
|
||||||
# description: Create two variables-- features and labels.There are refer to two numpy array(all elements are zero)
|
|
||||||
# The features array's size is feature_number and dimension is feature_dimension
|
|
||||||
# This function will read the two arrays and write it as a matrix in a csv file(the save path is './features_new.npz')
|
|
||||||
# And then it will call the function calculate_weight to calculate the matrix
|
|
||||||
# arguments: feature_path, feature_number, feature_dimension
|
|
||||||
# return value: None
|
|
||||||
# note:A ExceptionCatch function modifier is used
|
|
||||||
# date: 2022/8/2
|
|
||||||
#contact: 1865997821
|
|
||||||
@ExceptionCatch(strategy='exit', name='FEATURE')
|
@ExceptionCatch(strategy='exit', name='FEATURE')
|
||||||
def build_model(feature_path: str, feature_number: int, feature_dimension: int,
|
def build_model(feature_path: str, feature_number: int, feature_dimension: int,
|
||||||
save_path: str = './features_new.npz') -> None:
|
save_path: str = './features_new.npz') -> None:
|
||||||
|
|
|
||||||
|
|
@ -11,13 +11,6 @@
|
||||||
# MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
# MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||||
# See the Mulan PSL v2 for more details.
|
# See the Mulan PSL v2 for more details.
|
||||||
|
|
||||||
#function name: detect
|
|
||||||
#description: if the method is "bool" type, then call the functions sum_detect、avg_detect、ks_detect to diagnose errors
|
|
||||||
#These functions are in the parent slow_sql/significance_detection
|
|
||||||
#arguments: data1(array), data2(array), method
|
|
||||||
#return value: bool type
|
|
||||||
#date: 2022/8/2
|
|
||||||
#contact: 1865997821
|
|
||||||
|
|
||||||
def detect(data1, data2, method='bool', threshold=0.01, p_value=0.5):
|
def detect(data1, data2, method='bool', threshold=0.01, p_value=0.5):
|
||||||
if method == 'bool':
|
if method == 'bool':
|
||||||
|
|
|
||||||
|
|
@ -12,16 +12,17 @@
|
||||||
# See the Mulan PSL v2 for more details.
|
# See the Mulan PSL v2 for more details.
|
||||||
|
|
||||||
alpha = 1e-10
|
alpha = 1e-10
|
||||||
#Define a minimum number of errors
|
|
||||||
|
|
||||||
#function name: detect
|
|
||||||
#description: Calculate whether the data has abrupt changes based on the average value
|
|
||||||
#arguments: data1, data2, threshold,method
|
|
||||||
#return value: bool
|
|
||||||
#date: 2022/8/
|
|
||||||
#contact: 1865997821
|
|
||||||
|
|
||||||
def detect(data1, data2, threshold=0.5, method='bool'):
|
def detect(data1, data2, threshold=0.5, method='bool'):
|
||||||
|
"""
|
||||||
|
Calculate whether the data has abrupt changes based on the average value
|
||||||
|
:param data1: input data array
|
||||||
|
:param data2: input data array
|
||||||
|
:param threshold: Mutation rate
|
||||||
|
:param method: The way to calculate the mutation
|
||||||
|
:return: bool
|
||||||
|
"""
|
||||||
if not isinstance(data1, list) or not isinstance(data2, list):
|
if not isinstance(data1, list) or not isinstance(data2, list):
|
||||||
raise TypeError("The format of the input data is wrong.")
|
raise TypeError("The format of the input data is wrong.")
|
||||||
avg1 = sum(data1) / len(data1) if data1 else 0
|
avg1 = sum(data1) / len(data1) if data1 else 0
|
||||||
|
|
|
||||||
|
|
@ -26,11 +26,9 @@ import logging
|
||||||
try:
|
try:
|
||||||
from .dao.gsql_execute import GSqlExecute
|
from .dao.gsql_execute import GSqlExecute
|
||||||
from .dao.execute_factory import ExecuteFactory
|
from .dao.execute_factory import ExecuteFactory
|
||||||
from .mcts import MCTS
|
|
||||||
except ImportError:
|
except ImportError:
|
||||||
from dao.gsql_execute import GSqlExecute
|
from dao.gsql_execute import GSqlExecute
|
||||||
from dao.execute_factory import ExecuteFactory
|
from dao.execute_factory import ExecuteFactory
|
||||||
from mcts import MCTS
|
|
||||||
|
|
||||||
ENABLE_MULTI_NODE = False
|
ENABLE_MULTI_NODE = False
|
||||||
SAMPLE_NUM = 5
|
SAMPLE_NUM = 5
|
||||||
|
|
@ -194,12 +192,9 @@ class IndexAdvisor:
|
||||||
self.workload_used_index))
|
self.workload_used_index))
|
||||||
if DRIVER:
|
if DRIVER:
|
||||||
self.db.close_conn()
|
self.db.close_conn()
|
||||||
if MAX_INDEX_STORAGE:
|
|
||||||
opt_config = MCTS(self.workload_info[0], atomic_config_total, candidate_indexes,
|
opt_config = greedy_determine_opt_config(self.workload_info[0], atomic_config_total,
|
||||||
MAX_INDEX_STORAGE, MAX_INDEX_NUM)
|
candidate_indexes, self.index_cost_total[0])
|
||||||
else:
|
|
||||||
opt_config = greedy_determine_opt_config(self.workload_info[0], atomic_config_total,
|
|
||||||
candidate_indexes, self.index_cost_total[0])
|
|
||||||
self.retain_lower_cost_index(candidate_indexes)
|
self.retain_lower_cost_index(candidate_indexes)
|
||||||
if len(opt_config) == 0:
|
if len(opt_config) == 0:
|
||||||
print("No optimal indexes generated!")
|
print("No optimal indexes generated!")
|
||||||
|
|
@ -948,7 +943,7 @@ def check_parameter(args):
|
||||||
raise argparse.ArgumentTypeError("%s is an invalid positive int value" %
|
raise argparse.ArgumentTypeError("%s is an invalid positive int value" %
|
||||||
args.max_index_num)
|
args.max_index_num)
|
||||||
if args.max_index_storage is not None and args.max_index_storage <= 0:
|
if args.max_index_storage is not None and args.max_index_storage <= 0:
|
||||||
raise argparse.ArgumentTypeError("%s is an invalid positive float value" %
|
raise argparse.ArgumentTypeError("%s is an invalid positive int value" %
|
||||||
args.max_index_storage)
|
args.max_index_storage)
|
||||||
JSON_TYPE = args.json
|
JSON_TYPE = args.json
|
||||||
MAX_INDEX_NUM = args.max_index_num
|
MAX_INDEX_NUM = args.max_index_num
|
||||||
|
|
@ -976,7 +971,7 @@ def main(argv):
|
||||||
arg_parser.add_argument(
|
arg_parser.add_argument(
|
||||||
"--max_index_num", help="Maximum number of suggested indexes", type=int)
|
"--max_index_num", help="Maximum number of suggested indexes", type=int)
|
||||||
arg_parser.add_argument("--max_index_storage",
|
arg_parser.add_argument("--max_index_storage",
|
||||||
help="Maximum storage of suggested indexes/MB", type=float)
|
help="Maximum storage of suggested indexes/MB", type=int)
|
||||||
arg_parser.add_argument("--multi_iter_mode", action='store_true',
|
arg_parser.add_argument("--multi_iter_mode", action='store_true',
|
||||||
help="Whether to use multi-iteration algorithm", default=False)
|
help="Whether to use multi-iteration algorithm", default=False)
|
||||||
arg_parser.add_argument("--multi_node", action='store_true',
|
arg_parser.add_argument("--multi_node", action='store_true',
|
||||||
|
|
|
||||||
|
|
@ -1,397 +0,0 @@
|
||||||
import sys
|
|
||||||
import math
|
|
||||||
import random
|
|
||||||
import copy
|
|
||||||
|
|
||||||
STORAGE_THRESHOLD = 0
|
|
||||||
AVAILABLE_CHOICES = None
|
|
||||||
ATOMIC_CHOICES = None
|
|
||||||
WORKLOAD_INFO = None
|
|
||||||
MAX_INDEX_NUM = 0
|
|
||||||
|
|
||||||
|
|
||||||
def is_same_index(index, compared_index):
|
|
||||||
return index.table == compared_index.table and \
|
|
||||||
index.columns == compared_index.columns and \
|
|
||||||
index.index_type == compared_index.index_type
|
|
||||||
|
|
||||||
|
|
||||||
def atomic_config_is_valid(atomic_config, config):
|
|
||||||
# if candidate indexes contains all atomic index of current config1, then record it
|
|
||||||
for atomic_index in atomic_config:
|
|
||||||
is_exist = False
|
|
||||||
for index in config:
|
|
||||||
if is_same_index(index, atomic_index):
|
|
||||||
index.storage = atomic_index.storage
|
|
||||||
is_exist = True
|
|
||||||
break
|
|
||||||
if not is_exist:
|
|
||||||
return False
|
|
||||||
return True
|
|
||||||
|
|
||||||
|
|
||||||
def find_subsets_num(choice):
|
|
||||||
atomic_subsets_num = []
|
|
||||||
for pos, atomic in enumerate(ATOMIC_CHOICES):
|
|
||||||
if not atomic or len(atomic) > len(choice):
|
|
||||||
continue
|
|
||||||
# find valid atomic index
|
|
||||||
if atomic_config_is_valid(atomic, choice):
|
|
||||||
atomic_subsets_num.append(pos)
|
|
||||||
# find the same atomic index as the candidate index
|
|
||||||
if len(atomic) == 1 and (is_same_index(choice[-1], atomic[0])):
|
|
||||||
choice[-1].atomic_pos = pos
|
|
||||||
return atomic_subsets_num
|
|
||||||
|
|
||||||
|
|
||||||
def find_best_benefit(choice):
|
|
||||||
atomic_subsets_num = find_subsets_num(choice)
|
|
||||||
total_benefit = 0
|
|
||||||
for ind, obj in enumerate(WORKLOAD_INFO):
|
|
||||||
# calculate the best benefit for the current sql
|
|
||||||
max_benefit = 0
|
|
||||||
for pos in atomic_subsets_num:
|
|
||||||
if (obj.cost_list[0] - obj.cost_list[pos]) > max_benefit:
|
|
||||||
max_benefit = obj.cost_list[0] - obj.cost_list[pos]
|
|
||||||
total_benefit += max_benefit
|
|
||||||
return total_benefit
|
|
||||||
|
|
||||||
|
|
||||||
def get_diff(available_choices, choices):
|
|
||||||
except_choices = copy.copy(available_choices)
|
|
||||||
for i in available_choices:
|
|
||||||
for j in choices:
|
|
||||||
if is_same_index(i, j):
|
|
||||||
except_choices.remove(i)
|
|
||||||
return except_choices
|
|
||||||
|
|
||||||
|
|
||||||
class State(object):
|
|
||||||
"""
|
|
||||||
The game state of the Monte Carlo tree search,
|
|
||||||
the state data recorded under a certain Node node,
|
|
||||||
including the current game score, the current number of game rounds,
|
|
||||||
and the execution record from the beginning to the current.
|
|
||||||
|
|
||||||
It is necessary to realize whether the current state has reached the end of the game state,
|
|
||||||
and support the operation of randomly fetching from the Action collection.
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
self.current_storage = 0.0
|
|
||||||
self.current_benefit = 0.0
|
|
||||||
# record the sum of choices up to the current state
|
|
||||||
self.accumulation_choices = []
|
|
||||||
# record available choices of current state
|
|
||||||
self.available_choices = []
|
|
||||||
self.displayable_choices = []
|
|
||||||
|
|
||||||
def get_available_choices(self):
|
|
||||||
return self.available_choices
|
|
||||||
|
|
||||||
def set_available_choices(self, choices):
|
|
||||||
self.available_choices = choices
|
|
||||||
|
|
||||||
def get_current_storage(self):
|
|
||||||
return self.current_storage
|
|
||||||
|
|
||||||
def set_current_storage(self, value):
|
|
||||||
self.current_storage = value
|
|
||||||
|
|
||||||
def get_current_benefit(self):
|
|
||||||
return self.current_benefit
|
|
||||||
|
|
||||||
def set_current_benefit(self, value):
|
|
||||||
self.current_benefit = value
|
|
||||||
|
|
||||||
def get_accumulation_choices(self):
|
|
||||||
return self.accumulation_choices
|
|
||||||
|
|
||||||
def set_accumulation_choices(self, choices):
|
|
||||||
self.accumulation_choices = choices
|
|
||||||
|
|
||||||
def is_terminal(self):
|
|
||||||
# the current node is a leaf node
|
|
||||||
return len(self.accumulation_choices) == MAX_INDEX_NUM
|
|
||||||
|
|
||||||
def compute_benefit(self):
|
|
||||||
return self.current_benefit
|
|
||||||
|
|
||||||
def get_next_state_with_random_choice(self):
|
|
||||||
# ensure that the choices taken are not repeated
|
|
||||||
if not self.available_choices:
|
|
||||||
return None
|
|
||||||
random_choice = random.choice([choice for choice in self.available_choices])
|
|
||||||
self.available_choices.remove(random_choice)
|
|
||||||
choice = copy.copy(self.accumulation_choices)
|
|
||||||
choice.append(random_choice)
|
|
||||||
benefit = find_best_benefit(choice)
|
|
||||||
# if current choice not satisfy restrictions, then continue get next choice
|
|
||||||
if benefit <= self.current_benefit or \
|
|
||||||
self.current_storage + random_choice.storage > STORAGE_THRESHOLD:
|
|
||||||
return self.get_next_state_with_random_choice()
|
|
||||||
|
|
||||||
next_state = State()
|
|
||||||
# initialize the properties of the new state
|
|
||||||
next_state.set_accumulation_choices(choice)
|
|
||||||
next_state.set_current_benefit(benefit)
|
|
||||||
next_state.set_current_storage(self.current_storage + random_choice.storage)
|
|
||||||
next_state.set_available_choices(get_diff(AVAILABLE_CHOICES, choice))
|
|
||||||
return next_state
|
|
||||||
|
|
||||||
def __repr__(self):
|
|
||||||
self.displayable_choices = ['{}: {}'.format(choice.table, choice.columns)
|
|
||||||
for choice in self.accumulation_choices]
|
|
||||||
return "reward: {}, storage :{}, choices: {}".format(
|
|
||||||
self.current_benefit, self.current_storage, self.displayable_choices)
|
|
||||||
|
|
||||||
|
|
||||||
class Node(object):
|
|
||||||
"""
|
|
||||||
The Node of the Monte Carlo tree search tree contains the parent node and
|
|
||||||
current point information,
|
|
||||||
which is used to calculate the traversal times and quality value of the UCB,
|
|
||||||
and the State of the Node selected by the game.
|
|
||||||
"""
|
|
||||||
def __init__(self):
|
|
||||||
self.visit_number = 0
|
|
||||||
self.quality = 0.0
|
|
||||||
|
|
||||||
self.parent = None
|
|
||||||
self.children = []
|
|
||||||
self.state = None
|
|
||||||
|
|
||||||
def get_parent(self):
|
|
||||||
return self.parent
|
|
||||||
|
|
||||||
def set_parent(self, parent):
|
|
||||||
self.parent = parent
|
|
||||||
|
|
||||||
def get_children(self):
|
|
||||||
return self.children
|
|
||||||
|
|
||||||
def expand_child(self, node):
|
|
||||||
node.set_parent(self)
|
|
||||||
self.children.append(node)
|
|
||||||
|
|
||||||
def set_state(self, state):
|
|
||||||
self.state = state
|
|
||||||
|
|
||||||
def get_state(self):
|
|
||||||
return self.state
|
|
||||||
|
|
||||||
def get_visit_number(self):
|
|
||||||
return self.visit_number
|
|
||||||
|
|
||||||
def set_visit_number(self, number):
|
|
||||||
self.visit_number = number
|
|
||||||
|
|
||||||
def update_visit_number(self):
|
|
||||||
self.visit_number += 1
|
|
||||||
|
|
||||||
def get_quality_value(self):
|
|
||||||
return self.quality
|
|
||||||
|
|
||||||
def set_quality_value(self, value):
|
|
||||||
self.quality = value
|
|
||||||
|
|
||||||
def update_quality_value(self, reward):
|
|
||||||
self.quality += reward
|
|
||||||
|
|
||||||
def is_all_expand(self):
|
|
||||||
return len(self.children) == \
|
|
||||||
len(AVAILABLE_CHOICES) - len(self.get_state().get_accumulation_choices())
|
|
||||||
|
|
||||||
def __repr__(self):
|
|
||||||
return "Node: {}, Q/N: {}/{}, State: {}".format(
|
|
||||||
hash(self), self.quality, self.visit_number, self.state)
|
|
||||||
|
|
||||||
|
|
||||||
def tree_policy(node):
|
|
||||||
"""
|
|
||||||
In the Selection and Expansion stages of Monte Carlo tree search,
|
|
||||||
the node that needs to be searched (such as the root node) is passed in,
|
|
||||||
and the best node that needs to be expanded is returned
|
|
||||||
according to the exploration/exploitation algorithm.
|
|
||||||
Note that if the node is a leaf node, it will be returned directly.
|
|
||||||
|
|
||||||
The basic strategy is to first find the child nodes that have not been selected at present,
|
|
||||||
and select them randomly if there are more than one. If both are selected,
|
|
||||||
find the one with the largest UCB value that has weighed exploration/exploitation,
|
|
||||||
and randomly select if the UCB values are equal.
|
|
||||||
"""
|
|
||||||
|
|
||||||
# check if the current node is leaf node
|
|
||||||
while node and not node.get_state().is_terminal():
|
|
||||||
|
|
||||||
if node.is_all_expand():
|
|
||||||
node = best_child(node, True)
|
|
||||||
else:
|
|
||||||
# return the new sub node
|
|
||||||
sub_node = expand(node)
|
|
||||||
# when there is no node that satisfies the condition in the remaining nodes,
|
|
||||||
# this state is empty
|
|
||||||
if sub_node.get_state():
|
|
||||||
return sub_node
|
|
||||||
|
|
||||||
# return the leaf node
|
|
||||||
return node
|
|
||||||
|
|
||||||
|
|
||||||
def default_policy(node):
|
|
||||||
"""
|
|
||||||
In the Simulation stage of Monte Carlo tree search, input a node that needs to be expanded,
|
|
||||||
create a new node after random operation, and return the reward of the new node.
|
|
||||||
Note that the input node should not be a child node,
|
|
||||||
and there are unexecuted Actions that can be expendable.
|
|
||||||
|
|
||||||
The basic strategy is to choose the Action at random.
|
|
||||||
"""
|
|
||||||
|
|
||||||
# get the state of the game
|
|
||||||
current_state = copy.deepcopy(node.get_state())
|
|
||||||
|
|
||||||
# run until the game over
|
|
||||||
while not current_state.is_terminal():
|
|
||||||
# pick one random action to play and get next state
|
|
||||||
next_state = current_state.get_next_state_with_random_choice()
|
|
||||||
if not next_state:
|
|
||||||
break
|
|
||||||
current_state = next_state
|
|
||||||
|
|
||||||
final_state_reward = current_state.compute_benefit()
|
|
||||||
return final_state_reward
|
|
||||||
|
|
||||||
|
|
||||||
def expand(node):
|
|
||||||
"""
|
|
||||||
Enter a node, expand a new node on the node, use the random method to execute the Action,
|
|
||||||
and return the new node. Note that it is necessary to ensure that the newly
|
|
||||||
added nodes are different from other node Action
|
|
||||||
"""
|
|
||||||
|
|
||||||
new_state = node.get_state().get_next_state_with_random_choice()
|
|
||||||
sub_node = Node()
|
|
||||||
sub_node.set_state(new_state)
|
|
||||||
node.expand_child(sub_node)
|
|
||||||
|
|
||||||
return sub_node
|
|
||||||
|
|
||||||
|
|
||||||
def best_child(node, is_exploration):
|
|
||||||
"""
|
|
||||||
Using the UCB algorithm,
|
|
||||||
select the child node with the highest score after weighing the exploration and exploitation.
|
|
||||||
Note that if it is the prediction stage,
|
|
||||||
the current Q-value score with the highest score is directly selected.
|
|
||||||
"""
|
|
||||||
|
|
||||||
best_score = -sys.maxsize
|
|
||||||
best_sub_node = None
|
|
||||||
|
|
||||||
# travel all sub nodes to find the best one
|
|
||||||
for sub_node in node.get_children():
|
|
||||||
# The children nodes of the node contains the children node whose state is empty,
|
|
||||||
# this kind of node comes from the node that does not meet the conditions.
|
|
||||||
if not sub_node.get_state():
|
|
||||||
continue
|
|
||||||
# ignore exploration for inference
|
|
||||||
if is_exploration:
|
|
||||||
C = 1 / math.sqrt(2.0)
|
|
||||||
else:
|
|
||||||
C = 0.0
|
|
||||||
|
|
||||||
# UCB = quality / times + C * sqrt(2 * ln(total_times) / times)
|
|
||||||
left = sub_node.get_quality_value() / sub_node.get_visit_number()
|
|
||||||
right = 2.0 * math.log(node.get_visit_number()) / sub_node.get_visit_number()
|
|
||||||
score = left + C * math.sqrt(right)
|
|
||||||
# get the maximum score, while filtering nodes that do not meet the space constraints and
|
|
||||||
# nodes that have no revenue
|
|
||||||
if score > best_score \
|
|
||||||
and sub_node.get_state().get_current_storage() <= STORAGE_THRESHOLD \
|
|
||||||
and sub_node.get_state().get_current_benefit() > 0:
|
|
||||||
best_sub_node = sub_node
|
|
||||||
best_score = score
|
|
||||||
|
|
||||||
return best_sub_node
|
|
||||||
|
|
||||||
|
|
||||||
def backpropagate(node, reward):
|
|
||||||
"""
|
|
||||||
In the Backpropagation stage of Monte Carlo tree search,
|
|
||||||
input the node that needs to be expended and the reward of the newly executed Action,
|
|
||||||
feed it back to the expend node and all upstream nodes,
|
|
||||||
and update the corresponding data.
|
|
||||||
"""
|
|
||||||
|
|
||||||
# update util the root node
|
|
||||||
while node is not None:
|
|
||||||
# update the visit number
|
|
||||||
node.update_visit_number()
|
|
||||||
|
|
||||||
# update the quality value
|
|
||||||
node.update_quality_value(reward)
|
|
||||||
|
|
||||||
# change the node to the parent node
|
|
||||||
node = node.parent
|
|
||||||
|
|
||||||
|
|
||||||
def monte_carlo_tree_search(node):
|
|
||||||
"""
|
|
||||||
Implement the Monte Carlo tree search algorithm, pass in a root node,
|
|
||||||
expand new nodes and update data according to the
|
|
||||||
tree structure that has been explored before in a limited time,
|
|
||||||
and then return as long as the child node with the highest exploitation.
|
|
||||||
|
|
||||||
When making predictions,
|
|
||||||
you only need to select the node with the largest exploitation according to the Q value,
|
|
||||||
and find the next optimal node.
|
|
||||||
"""
|
|
||||||
|
|
||||||
computation_budget = len(AVAILABLE_CHOICES) * 3
|
|
||||||
|
|
||||||
# run as much as possible under the computation budget
|
|
||||||
for i in range(computation_budget):
|
|
||||||
# 1. find the best node to expand
|
|
||||||
expand_node = tree_policy(node)
|
|
||||||
if not expand_node:
|
|
||||||
# when it is None, it means that all nodes are added but no nodes meet the space limit
|
|
||||||
break
|
|
||||||
# 2. random get next action and get reward
|
|
||||||
reward = default_policy(expand_node)
|
|
||||||
|
|
||||||
# 3. update all passing nodes with reward
|
|
||||||
backpropagate(expand_node, reward)
|
|
||||||
|
|
||||||
# get the best next node
|
|
||||||
best_next_node = best_child(node, False)
|
|
||||||
|
|
||||||
return best_next_node
|
|
||||||
|
|
||||||
|
|
||||||
def MCTS(workload_info, atomic_choices, available_choices, storage_threshold, max_index_num):
|
|
||||||
global ATOMIC_CHOICES, STORAGE_THRESHOLD, WORKLOAD_INFO, AVAILABLE_CHOICES, MAX_INDEX_NUM
|
|
||||||
WORKLOAD_INFO = workload_info
|
|
||||||
AVAILABLE_CHOICES = available_choices
|
|
||||||
ATOMIC_CHOICES = atomic_choices
|
|
||||||
STORAGE_THRESHOLD = storage_threshold
|
|
||||||
MAX_INDEX_NUM = max_index_num if max_index_num else len(available_choices)
|
|
||||||
|
|
||||||
# create the initialized state and initialized node
|
|
||||||
init_state = State()
|
|
||||||
choices = copy.copy(available_choices)
|
|
||||||
init_state.set_available_choices(choices)
|
|
||||||
init_node = Node()
|
|
||||||
init_node.set_state(init_state)
|
|
||||||
current_node = init_node
|
|
||||||
|
|
||||||
opt_config = []
|
|
||||||
# set the rounds to play
|
|
||||||
for i in range(len(AVAILABLE_CHOICES)):
|
|
||||||
if current_node:
|
|
||||||
current_node = monte_carlo_tree_search(current_node)
|
|
||||||
if current_node:
|
|
||||||
opt_config = current_node.state.accumulation_choices
|
|
||||||
else:
|
|
||||||
break
|
|
||||||
return opt_config
|
|
||||||
|
|
@ -27,7 +27,6 @@ from collections.abc import Iterable
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
|
|
||||||
import index_advisor_workload as iaw
|
import index_advisor_workload as iaw
|
||||||
import mcts
|
|
||||||
|
|
||||||
|
|
||||||
def hash_any(obj):
|
def hash_any(obj):
|
||||||
|
|
@ -228,32 +227,6 @@ select * from student_range_part1 where credit=1;
|
||||||
|
|
||||||
class IndexAdvisorTester(unittest.TestCase):
|
class IndexAdvisorTester(unittest.TestCase):
|
||||||
|
|
||||||
def test_mcts(self):
|
|
||||||
storage_threshold = 12
|
|
||||||
index1 = iaw.IndexItem('public.a', 'col1', index_type='global')
|
|
||||||
index2 = iaw.IndexItem('public.b', 'col1', index_type='global')
|
|
||||||
index3 = iaw.IndexItem('public.c', 'col1', index_type='global')
|
|
||||||
index4 = iaw.IndexItem('public.d', 'col1', index_type='global')
|
|
||||||
|
|
||||||
atomic_index1 = iaw.IndexItem('public.a', 'col1', index_type='global')
|
|
||||||
atomic_index2 = iaw.IndexItem('public.b', 'col1', index_type='global')
|
|
||||||
atomic_index3 = iaw.IndexItem('public.c', 'col1', index_type='global')
|
|
||||||
atomic_index4 = iaw.IndexItem('public.d', 'col1', index_type='global')
|
|
||||||
|
|
||||||
atomic_index1.storage = 10
|
|
||||||
atomic_index2.storage = 4
|
|
||||||
atomic_index3.storage = 7
|
|
||||||
available_choices = [index1, index2, index3, index4]
|
|
||||||
atomic_choices = [[], [atomic_index2], [atomic_index1], [atomic_index3],
|
|
||||||
[atomic_index2, atomic_index3], [atomic_index4]]
|
|
||||||
query = iaw.QueryItem('select * from gia_01', 1)
|
|
||||||
query.cost_list = [10, 7, 5, 9, 4, 11]
|
|
||||||
workload_info = [query]
|
|
||||||
|
|
||||||
results = mcts.MCTS(workload_info, atomic_choices, available_choices, storage_threshold, 2)
|
|
||||||
self.assertLessEqual([index1.atomic_pos, index2.atomic_pos, index3.atomic_pos], [2, 1, 3])
|
|
||||||
self.assertSetEqual({results[0].table, results[1].table}, {'public.b', 'public.c'})
|
|
||||||
|
|
||||||
def test_get_indexable_columns(self):
|
def test_get_indexable_columns(self):
|
||||||
tables = 'table1 table2 table2 table3 table3 table3'.split()
|
tables = 'table1 table2 table2 table3 table3 table3'.split()
|
||||||
columns = 'col1,col2 col2 col3 col1,col2 col2,col3 col2,col5'.split()
|
columns = 'col1,col2 col2 col3 col1,col2 col2,col3 col2,col5'.split()
|
||||||
|
|
|
||||||
|
|
@ -90,10 +90,7 @@ static void DropExtensionInListIsSupported(List* objname)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Enable DROP operation of the above objects during inplace upgrade or support_extended_features is true */
|
ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("EXTENSION is not yet supported.")));
|
||||||
if (!u_sess->attr.attr_common.IsInplaceUpgrade && !g_instance.attr.attr_common.support_extended_features) {
|
|
||||||
ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("EXTENSION is not yet supported.")));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
||||||
|
|
@ -1175,7 +1175,7 @@ void CreateExtension(CreateExtensionStmt* stmt)
|
||||||
FEATURE_NOT_PUBLIC_ERROR("EXTENSION is not yet supported.");
|
FEATURE_NOT_PUBLIC_ERROR("EXTENSION is not yet supported.");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pg_strcasecmp(stmt->extname, "dolphin") == 0 && !DB_IS_CMPT(B_FORMAT)) {
|
if (pg_strcasecmp(stmt->extname, "b_sql_plugin") == 0 && !DB_IS_CMPT(B_FORMAT)) {
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errmsg("please create extension \"%s\" with B type DBCOMPATIBILITY", stmt->extname)));
|
(errmsg("please create extension \"%s\" with B type DBCOMPATIBILITY", stmt->extname)));
|
||||||
}
|
}
|
||||||
|
|
@ -1418,8 +1418,8 @@ void CreateExtension(CreateExtensionStmt* stmt)
|
||||||
|
|
||||||
u_sess->exec_cxt.extension_is_valid = true;
|
u_sess->exec_cxt.extension_is_valid = true;
|
||||||
|
|
||||||
if (pg_strcasecmp(stmt->extname, "dolphin") == 0) {
|
if (pg_strcasecmp(stmt->extname, "b_sql_plugin") == 0) {
|
||||||
u_sess->attr.attr_sql.dolphin = true;
|
u_sess->attr.attr_sql.b_sql_plugin = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,7 @@
|
||||||
#include "utils/array.h"
|
#include "utils/array.h"
|
||||||
#include "utils/acl.h"
|
#include "utils/acl.h"
|
||||||
|
|
||||||
static bool ConnectPublisher(char* conninfo, char* slotname);
|
static void ConnectPublisher(char *conninfo, char* slotname);
|
||||||
static void CreateSlotInPublisher(char *slotname);
|
static void CreateSlotInPublisher(char *slotname);
|
||||||
static void ValidateReplicationSlot(char *slotname, List *publications);
|
static void ValidateReplicationSlot(char *slotname, List *publications);
|
||||||
|
|
||||||
|
|
@ -56,7 +56,7 @@ static void ValidateReplicationSlot(char *slotname, List *publications);
|
||||||
* accommodate that.
|
* accommodate that.
|
||||||
*/
|
*/
|
||||||
static void parse_subscription_options(const List *options, char **conninfo, List **publications, bool *enabled_given,
|
static void parse_subscription_options(const List *options, char **conninfo, List **publications, bool *enabled_given,
|
||||||
bool *enabled, bool *slot_name_given, char **slot_name, char **synchronous_commit, bool *binary_given, bool *binary)
|
bool *enabled, bool *slot_name_given, char **slot_name, char **synchronous_commit)
|
||||||
{
|
{
|
||||||
ListCell *lc;
|
ListCell *lc;
|
||||||
|
|
||||||
|
|
@ -76,10 +76,6 @@ static void parse_subscription_options(const List *options, char **conninfo, Lis
|
||||||
if (synchronous_commit) {
|
if (synchronous_commit) {
|
||||||
*synchronous_commit = NULL;
|
*synchronous_commit = NULL;
|
||||||
}
|
}
|
||||||
if (binary) {
|
|
||||||
*binary_given = false;
|
|
||||||
*binary = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Parse options */
|
/* Parse options */
|
||||||
foreach (lc, options) {
|
foreach (lc, options) {
|
||||||
|
|
@ -128,15 +124,6 @@ static void parse_subscription_options(const List *options, char **conninfo, Lis
|
||||||
/* Test if the given value is valid for synchronous_commit GUC. */
|
/* Test if the given value is valid for synchronous_commit GUC. */
|
||||||
(void)set_config_option("synchronous_commit", *synchronous_commit, PGC_BACKEND, PGC_S_TEST, GUC_ACTION_SET,
|
(void)set_config_option("synchronous_commit", *synchronous_commit, PGC_BACKEND, PGC_S_TEST, GUC_ACTION_SET,
|
||||||
false, 0, false);
|
false, 0, false);
|
||||||
} else if (strcmp(defel->defname, "binary") == 0 && binary) {
|
|
||||||
if (*binary_given) {
|
|
||||||
ereport(ERROR,
|
|
||||||
(errcode(ERRCODE_SYNTAX_ERROR),
|
|
||||||
errmsg("conflicting or redundant options")));
|
|
||||||
}
|
|
||||||
|
|
||||||
*binary_given = true;
|
|
||||||
*binary = defGetBoolean(defel);
|
|
||||||
} else {
|
} else {
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_SYNTAX_ERROR), errmsg("unrecognized subscription parameter: %s", defel->defname)));
|
(errcode(ERRCODE_SYNTAX_ERROR), errmsg("unrecognized subscription parameter: %s", defel->defname)));
|
||||||
|
|
@ -210,82 +197,26 @@ static Datum publicationListToArray(List *publist)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Parse the original connection string which is encrypted, poll all hosts and ports,
|
* connect publisher and create slot.
|
||||||
* and try to connect to the publisher.
|
* the input conninfo should be encrypt, we will decrypt password inside
|
||||||
* When checkRemoteMode is true, the remotemode must be normal or primary.
|
|
||||||
* Return true to indicate successful connection.
|
|
||||||
*/
|
*/
|
||||||
bool AttemptConnectPublisher(const char *conninfoOriginal, char* slotname, bool checkRemoteMode)
|
static void ConnectPublisher(char *conninfo, char *slotname)
|
||||||
{
|
|
||||||
size_t conninfoLen = strlen(conninfoOriginal) + 1;
|
|
||||||
|
|
||||||
char* conninfo = NULL;
|
|
||||||
StringInfoData conninfoWithoutHostport;
|
|
||||||
initStringInfo(&conninfoWithoutHostport);
|
|
||||||
HostPort* hostPortList[MAX_REPLNODE_NUM] = {NULL};
|
|
||||||
ParseConninfo(conninfoOriginal, &conninfoWithoutHostport, hostPortList);
|
|
||||||
if (hostPortList[0] == NULL) {
|
|
||||||
ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg(
|
|
||||||
"invalid connection string syntax, missing host and port")));
|
|
||||||
}
|
|
||||||
bool connectSuccess = false;
|
|
||||||
conninfo = (char*)palloc(conninfoLen * sizeof(char));
|
|
||||||
for (int i = 0; i < MAX_REPLNODE_NUM; ++i) {
|
|
||||||
if (hostPortList[i] == NULL) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
int ret = snprintf_s(conninfo, conninfoLen, conninfoLen - 1,
|
|
||||||
"%s host=%s port=%s", conninfoWithoutHostport.data,
|
|
||||||
hostPortList[i]->host, hostPortList[i]->port);
|
|
||||||
securec_check_ss(ret, "\0", "\0");
|
|
||||||
|
|
||||||
connectSuccess = ConnectPublisher(conninfo, slotname);
|
|
||||||
if (!connectSuccess) {
|
|
||||||
/* try next host */
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (!checkRemoteMode) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
ServerMode publisherServerMde = IdentifyRemoteMode();
|
|
||||||
if (publisherServerMde == NORMAL_MODE || publisherServerMde == PRIMARY_MODE) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
/* it's a standby, try next host */
|
|
||||||
(WalReceiverFuncTable[GET_FUNC_IDX]).walrcv_disconnect();
|
|
||||||
connectSuccess = false;
|
|
||||||
}
|
|
||||||
pfree_ext(conninfo);
|
|
||||||
|
|
||||||
/* clean up */
|
|
||||||
FreeStringInfo(&conninfoWithoutHostport);
|
|
||||||
for (int i = 0; i < MAX_REPLNODE_NUM; ++i) {
|
|
||||||
if (hostPortList[i] == NULL) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
pfree_ext(hostPortList[i]->host);
|
|
||||||
pfree_ext(hostPortList[i]->port);
|
|
||||||
pfree_ext(hostPortList[i]);
|
|
||||||
}
|
|
||||||
return connectSuccess;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* connect to publisher with conninfo
|
|
||||||
*/
|
|
||||||
static bool ConnectPublisher(char* conninfo, char* slotname)
|
|
||||||
{
|
{
|
||||||
/* Try to connect to the publisher. */
|
/* Try to connect to the publisher. */
|
||||||
volatile WalRcvData *walrcv = t_thrd.walreceiverfuncs_cxt.WalRcv;
|
volatile WalRcvData *walrcv = t_thrd.walreceiverfuncs_cxt.WalRcv;
|
||||||
SpinLockAcquire(&walrcv->mutex);
|
SpinLockAcquire(&walrcv->mutex);
|
||||||
walrcv->conn_target = REPCONNTARGET_PUBLICATION;
|
walrcv->conn_target = REPCONNTARGET_PUBLICATION;
|
||||||
SpinLockRelease(&walrcv->mutex);
|
SpinLockRelease(&walrcv->mutex);
|
||||||
char* decryptConninfo = EncryptOrDecryptConninfo(conninfo, 'D');
|
|
||||||
|
char *decryptConninfo = DecryptConninfo(conninfo);
|
||||||
bool connectSuccess = (WalReceiverFuncTable[GET_FUNC_IDX]).walrcv_connect(decryptConninfo, NULL, slotname, -1);
|
bool connectSuccess = (WalReceiverFuncTable[GET_FUNC_IDX]).walrcv_connect(decryptConninfo, NULL, slotname, -1);
|
||||||
int rc = memset_s(decryptConninfo, strlen(decryptConninfo), 0, strlen(decryptConninfo));
|
int rc = memset_s(decryptConninfo, strlen(decryptConninfo), 0, strlen(decryptConninfo));
|
||||||
securec_check(rc, "", "");
|
securec_check(rc, "", "");
|
||||||
pfree_ext(decryptConninfo);
|
pfree_ext(decryptConninfo);
|
||||||
return connectSuccess;
|
|
||||||
|
if (!connectSuccess) {
|
||||||
|
ereport(ERROR, (errcode(ERRCODE_CONNECTION_FAILURE), errmsg("could not connect to the publisher")));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -362,10 +293,9 @@ ObjectAddress CreateSubscription(CreateSubscriptionStmt *stmt, bool isTopLevel)
|
||||||
bool enabled_given = false;
|
bool enabled_given = false;
|
||||||
bool enabled = true;
|
bool enabled = true;
|
||||||
char *synchronous_commit;
|
char *synchronous_commit;
|
||||||
|
char *conninfo;
|
||||||
char *slotname;
|
char *slotname;
|
||||||
bool slotname_given;
|
bool slotname_given;
|
||||||
bool binary;
|
|
||||||
bool binary_given;
|
|
||||||
char originname[NAMEDATALEN];
|
char originname[NAMEDATALEN];
|
||||||
List *publications;
|
List *publications;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
@ -375,7 +305,7 @@ ObjectAddress CreateSubscription(CreateSubscriptionStmt *stmt, bool isTopLevel)
|
||||||
* Connection and publication should not be specified here.
|
* Connection and publication should not be specified here.
|
||||||
*/
|
*/
|
||||||
parse_subscription_options(stmt->options, NULL, NULL, &enabled_given, &enabled, &slotname_given, &slotname,
|
parse_subscription_options(stmt->options, NULL, NULL, &enabled_given, &enabled, &slotname_given, &slotname,
|
||||||
&synchronous_commit, &binary_given, &binary);
|
&synchronous_commit);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Since creating a replication slot is not transactional, rolling back
|
* Since creating a replication slot is not transactional, rolling back
|
||||||
|
|
@ -403,10 +333,11 @@ ObjectAddress CreateSubscription(CreateSubscriptionStmt *stmt, bool isTopLevel)
|
||||||
synchronous_commit = "off";
|
synchronous_commit = "off";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
conninfo = stmt->conninfo;
|
||||||
publications = stmt->publication;
|
publications = stmt->publication;
|
||||||
|
|
||||||
/* Check the connection info string. */
|
/* Check the connection info string. */
|
||||||
libpqrcv_check_conninfo(stmt->conninfo);
|
libpqrcv_check_conninfo(conninfo);
|
||||||
|
|
||||||
/* Everything ok, form a new tuple. */
|
/* Everything ok, form a new tuple. */
|
||||||
rc = memset_s(values, sizeof(values), 0, sizeof(values));
|
rc = memset_s(values, sizeof(values), 0, sizeof(values));
|
||||||
|
|
@ -418,12 +349,18 @@ ObjectAddress CreateSubscription(CreateSubscriptionStmt *stmt, bool isTopLevel)
|
||||||
values[Anum_pg_subscription_subname - 1] = DirectFunctionCall1(namein, CStringGetDatum(stmt->subname));
|
values[Anum_pg_subscription_subname - 1] = DirectFunctionCall1(namein, CStringGetDatum(stmt->subname));
|
||||||
values[Anum_pg_subscription_subowner - 1] = ObjectIdGetDatum(owner);
|
values[Anum_pg_subscription_subowner - 1] = ObjectIdGetDatum(owner);
|
||||||
values[Anum_pg_subscription_subenabled - 1] = BoolGetDatum(enabled);
|
values[Anum_pg_subscription_subenabled - 1] = BoolGetDatum(enabled);
|
||||||
values[Anum_pg_subscription_subbinary - 1] = BoolGetDatum(binary);
|
|
||||||
|
|
||||||
/* encrypt conninfo */
|
/* encrypt conninfo */
|
||||||
char *encryptConninfo = EncryptOrDecryptConninfo(stmt->conninfo, 'E');
|
List *conninfoList = ConninfoToDefList(stmt->conninfo);
|
||||||
|
/* Sensitive options for subscription, will be encrypted when saved to catalog. */
|
||||||
|
const char* sensitiveOptionsArray[] = {"password"};
|
||||||
|
const int sensitiveArrayLength = lengthof(sensitiveOptionsArray);
|
||||||
|
EncryptGenericOptions(conninfoList, sensitiveOptionsArray, sensitiveArrayLength, SUBSCRIPTION_MODE);
|
||||||
|
char *encryptConninfo = DefListToString(conninfoList);
|
||||||
|
|
||||||
values[Anum_pg_subscription_subconninfo - 1] = CStringGetTextDatum(encryptConninfo);
|
values[Anum_pg_subscription_subconninfo - 1] = CStringGetTextDatum(encryptConninfo);
|
||||||
|
|
||||||
|
pfree_ext(conninfoList);
|
||||||
if (enabled) {
|
if (enabled) {
|
||||||
if (!slotname_given) {
|
if (!slotname_given) {
|
||||||
slotname = stmt->subname;
|
slotname = stmt->subname;
|
||||||
|
|
@ -459,14 +396,11 @@ ObjectAddress CreateSubscription(CreateSubscriptionStmt *stmt, bool isTopLevel)
|
||||||
*/
|
*/
|
||||||
if (enabled) {
|
if (enabled) {
|
||||||
Assert(slotname);
|
Assert(slotname);
|
||||||
|
ConnectPublisher(encryptConninfo, slotname);
|
||||||
if (!AttemptConnectPublisher(encryptConninfo, slotname, true)) {
|
|
||||||
ereport(ERROR, (errcode(ERRCODE_CONNECTION_FAILURE), errmsg("Failed to connect to publisher.")));
|
|
||||||
}
|
|
||||||
|
|
||||||
CreateSlotInPublisher(slotname);
|
CreateSlotInPublisher(slotname);
|
||||||
(WalReceiverFuncTable[GET_FUNC_IDX]).walrcv_disconnect();
|
(WalReceiverFuncTable[GET_FUNC_IDX]).walrcv_disconnect();
|
||||||
}
|
}
|
||||||
|
|
||||||
pfree_ext(encryptConninfo);
|
pfree_ext(encryptConninfo);
|
||||||
heap_close(rel, RowExclusiveLock);
|
heap_close(rel, RowExclusiveLock);
|
||||||
rc = memset_s(stmt->conninfo, strlen(stmt->conninfo), 0, strlen(stmt->conninfo));
|
rc = memset_s(stmt->conninfo, strlen(stmt->conninfo), 0, strlen(stmt->conninfo));
|
||||||
|
|
@ -505,8 +439,6 @@ ObjectAddress AlterSubscription(AlterSubscriptionStmt *stmt)
|
||||||
Oid subid;
|
Oid subid;
|
||||||
bool enabled_given = false;
|
bool enabled_given = false;
|
||||||
bool enabled;
|
bool enabled;
|
||||||
bool binary_given;
|
|
||||||
bool binary;
|
|
||||||
char *synchronous_commit;
|
char *synchronous_commit;
|
||||||
char *conninfo;
|
char *conninfo;
|
||||||
char *slot_name;
|
char *slot_name;
|
||||||
|
|
@ -541,7 +473,7 @@ ObjectAddress AlterSubscription(AlterSubscriptionStmt *stmt)
|
||||||
|
|
||||||
/* Parse options. */
|
/* Parse options. */
|
||||||
parse_subscription_options(stmt->options, &conninfo, &publications, &enabled_given, &enabled, &slotname_given,
|
parse_subscription_options(stmt->options, &conninfo, &publications, &enabled_given, &enabled, &slotname_given,
|
||||||
&slot_name, &synchronous_commit, &binary_given, &binary);
|
&slot_name, &synchronous_commit);
|
||||||
|
|
||||||
/* Form a new tuple. */
|
/* Form a new tuple. */
|
||||||
rc = memset_s(nulls, sizeof(nulls), false, sizeof(nulls));
|
rc = memset_s(nulls, sizeof(nulls), false, sizeof(nulls));
|
||||||
|
|
@ -558,15 +490,23 @@ ObjectAddress AlterSubscription(AlterSubscriptionStmt *stmt)
|
||||||
if (conninfo) {
|
if (conninfo) {
|
||||||
/* Check the connection info string. */
|
/* Check the connection info string. */
|
||||||
libpqrcv_check_conninfo(conninfo);
|
libpqrcv_check_conninfo(conninfo);
|
||||||
encryptConninfo = EncryptOrDecryptConninfo(conninfo, 'E');
|
|
||||||
rc = memset_s(conninfo, strlen(conninfo), 0, strlen(conninfo));
|
/* encrypt conninfo */
|
||||||
securec_check(rc, "\0", "\0");
|
List *conninfoList = ConninfoToDefList(conninfo);
|
||||||
values[Anum_pg_subscription_subconninfo - 1] = CStringGetTextDatum(encryptConninfo);
|
/* Sensitive options for subscription, will be encrypted when saved to catalog. */
|
||||||
replaces[Anum_pg_subscription_subconninfo - 1] = true;
|
const char* sensitiveOptionsArray[] = {"password"};
|
||||||
|
const int sensitiveArrayLength = lengthof(sensitiveOptionsArray);
|
||||||
|
EncryptGenericOptions(conninfoList, sensitiveOptionsArray, sensitiveArrayLength, SUBSCRIPTION_MODE);
|
||||||
|
encryptConninfo = DefListToString(conninfoList);
|
||||||
needFreeConninfo = true;
|
needFreeConninfo = true;
|
||||||
|
|
||||||
/* need to check whether new conninfo can be used to connect to new publisher */
|
values[Anum_pg_subscription_subconninfo - 1] = CStringGetTextDatum(encryptConninfo);
|
||||||
|
replaces[Anum_pg_subscription_subconninfo - 1] = true;
|
||||||
|
|
||||||
|
pfree_ext(conninfoList);
|
||||||
|
|
||||||
if (sub->enabled || (enabled_given && enabled)) {
|
if (sub->enabled || (enabled_given && enabled)) {
|
||||||
|
/* we need to check whether new conninfo can be used to connect to new publisher */
|
||||||
checkConn = true;
|
checkConn = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -608,10 +548,6 @@ ObjectAddress AlterSubscription(AlterSubscriptionStmt *stmt)
|
||||||
values[Anum_pg_subscription_subsynccommit - 1] = CStringGetTextDatum(synchronous_commit);
|
values[Anum_pg_subscription_subsynccommit - 1] = CStringGetTextDatum(synchronous_commit);
|
||||||
replaces[Anum_pg_subscription_subsynccommit - 1] = true;
|
replaces[Anum_pg_subscription_subsynccommit - 1] = true;
|
||||||
}
|
}
|
||||||
if (binary_given) {
|
|
||||||
values[Anum_pg_subscription_subbinary - 1] = BoolGetDatum(binary);
|
|
||||||
replaces[Anum_pg_subscription_subbinary - 1] = true;
|
|
||||||
}
|
|
||||||
if (publications != NIL) {
|
if (publications != NIL) {
|
||||||
values[Anum_pg_subscription_subpublications - 1] = publicationListToArray(publications);
|
values[Anum_pg_subscription_subpublications - 1] = publicationListToArray(publications);
|
||||||
replaces[Anum_pg_subscription_subpublications - 1] = true;
|
replaces[Anum_pg_subscription_subpublications - 1] = true;
|
||||||
|
|
@ -634,18 +570,16 @@ ObjectAddress AlterSubscription(AlterSubscriptionStmt *stmt)
|
||||||
if (sub->enabled && !enabled) {
|
if (sub->enabled && !enabled) {
|
||||||
ereport(ERROR, (errmsg("If you want to deactivate this subscription, use DROP SUBSCRIPTION.")));
|
ereport(ERROR, (errmsg("If you want to deactivate this subscription, use DROP SUBSCRIPTION.")));
|
||||||
}
|
}
|
||||||
/* enabling subscription, but slot hasn't been created,
|
/* enable subscription */
|
||||||
* then mark createSlot to true.
|
if (!sub->enabled && enabled) {
|
||||||
*/
|
/* if slot hasn't been created, then create it */
|
||||||
if (!sub->enabled && enabled && (!sub->slotname || !*(sub->slotname))) {
|
if (!sub->slotname || !*(sub->slotname)) {
|
||||||
createSlot = true;
|
createSlot = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (checkConn || createSlot || validateSlot) {
|
if (checkConn || createSlot || validateSlot) {
|
||||||
if (!AttemptConnectPublisher(encryptConninfo, finalSlotName, true)) {
|
ConnectPublisher(encryptConninfo, finalSlotName);
|
||||||
ereport(ERROR, (errcode(ERRCODE_CONNECTION_FAILURE), errmsg(
|
|
||||||
checkConn ? "The new conninfo cannot connect to new publisher." : "Failed to connect to publisher.")));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (createSlot) {
|
if (createSlot) {
|
||||||
CreateSlotInPublisher(finalSlotName);
|
CreateSlotInPublisher(finalSlotName);
|
||||||
|
|
@ -663,6 +597,12 @@ ObjectAddress AlterSubscription(AlterSubscriptionStmt *stmt)
|
||||||
if (needFreeConninfo) {
|
if (needFreeConninfo) {
|
||||||
pfree_ext(encryptConninfo);
|
pfree_ext(encryptConninfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (conninfo) {
|
||||||
|
rc = memset_s(conninfo, strlen(conninfo), 0, strlen(conninfo));
|
||||||
|
securec_check(rc, "", "");
|
||||||
|
}
|
||||||
|
|
||||||
return myself;
|
return myself;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -813,11 +753,7 @@ void DropSubscription(DropSubscriptionStmt *stmt, bool isTopLevel)
|
||||||
initStringInfo(&cmd);
|
initStringInfo(&cmd);
|
||||||
appendStringInfo(&cmd, "DROP_REPLICATION_SLOT %s", quote_identifier(slotname));
|
appendStringInfo(&cmd, "DROP_REPLICATION_SLOT %s", quote_identifier(slotname));
|
||||||
|
|
||||||
if (!AttemptConnectPublisher(conninfo, slotname, true)) {
|
ConnectPublisher(conninfo, slotname);
|
||||||
ereport(ERROR, (errcode(ERRCODE_CONNECTION_FAILURE), errmsg(
|
|
||||||
"could not connect to publisher.")));
|
|
||||||
}
|
|
||||||
|
|
||||||
PG_TRY();
|
PG_TRY();
|
||||||
{
|
{
|
||||||
int sqlstate = 0;
|
int sqlstate = 0;
|
||||||
|
|
@ -843,7 +779,6 @@ void DropSubscription(DropSubscriptionStmt *stmt, bool isTopLevel)
|
||||||
|
|
||||||
(WalReceiverFuncTable[GET_FUNC_IDX]).walrcv_disconnect();
|
(WalReceiverFuncTable[GET_FUNC_IDX]).walrcv_disconnect();
|
||||||
|
|
||||||
pfree_ext(conninfo);
|
|
||||||
pfree(cmd.data);
|
pfree(cmd.data);
|
||||||
heap_close(rel, NoLock);
|
heap_close(rel, NoLock);
|
||||||
}
|
}
|
||||||
|
|
@ -973,149 +908,3 @@ void RenameSubscription(List *oldname, const char *newname)
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Parse the host or port string into a string array,
|
|
||||||
* where host and port are separated by ",".
|
|
||||||
* input: conn --- host or port string separated by ","
|
|
||||||
* output: connArray --- host or port string array
|
|
||||||
* return: the length of connArray
|
|
||||||
* for example:
|
|
||||||
* (1):
|
|
||||||
* conn = 1.1.1.1,2.2.2.2,...,9.9.9.9
|
|
||||||
* connArray = {
|
|
||||||
* 1,.1.1.1,
|
|
||||||
* 2.2.2.2,
|
|
||||||
* ...,
|
|
||||||
* 9.9.9.9
|
|
||||||
* }
|
|
||||||
* return 9
|
|
||||||
* (2):
|
|
||||||
* conn = 1,2,...,9
|
|
||||||
* connArray = {1,2,...,9}
|
|
||||||
* return 9
|
|
||||||
*/
|
|
||||||
static int HostsPortsToArray(const char* conn, char** connArray)
|
|
||||||
{
|
|
||||||
if (conn == NULL) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
char* cp = NULL;
|
|
||||||
char* cur = NULL;
|
|
||||||
char *buf = pstrdup(conn);
|
|
||||||
|
|
||||||
cp = buf;
|
|
||||||
int i = 0;
|
|
||||||
while (*cp) {
|
|
||||||
cur = cp;
|
|
||||||
while (*cp && *cp != ',') {
|
|
||||||
++cp;
|
|
||||||
}
|
|
||||||
if (*cp == ',') {
|
|
||||||
*cp = '\0';
|
|
||||||
++cp;
|
|
||||||
}
|
|
||||||
if (i >= MAX_REPLNODE_NUM) {
|
|
||||||
ereport(ERROR, (errmsg("Currently, a maximum of %d servers are "
|
|
||||||
"supported.", MAX_REPLNODE_NUM)));
|
|
||||||
}
|
|
||||||
connArray[i++] = pstrdup(cur);
|
|
||||||
|
|
||||||
if (*cp == 0) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pfree(buf);
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* parse host and port
|
|
||||||
*/
|
|
||||||
static void ParseHostPort(char* hoststr, char* portstr, HostPort** hostPortList)
|
|
||||||
{
|
|
||||||
char* hosts[MAX_REPLNODE_NUM] = {NULL};
|
|
||||||
char* ports[MAX_REPLNODE_NUM] = {NULL};
|
|
||||||
int hostNum = HostsPortsToArray(hoststr, hosts);
|
|
||||||
int portNum = HostsPortsToArray(portstr, ports);
|
|
||||||
if (hostNum != portNum) {
|
|
||||||
ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("The number of host and port are inconsistent.")));
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < hostNum; ++i) {
|
|
||||||
hostPortList[i] = (HostPort*)palloc(sizeof(HostPort));
|
|
||||||
hostPortList[i]->host = hosts[i];
|
|
||||||
hostPortList[i]->port = ports[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Parse conninfo
|
|
||||||
* conninfo format:
|
|
||||||
* 'dbname=abc user=username password=xxxx host=ip1,ip2,...,ip9 port=p1,p2,...,p9'
|
|
||||||
* after parsing:
|
|
||||||
* conninfoWithoutHostPort:
|
|
||||||
* 'dbname=abc user=username password=xxxx'
|
|
||||||
* hostPortList:
|
|
||||||
* {
|
|
||||||
* {host=ip1, port=p1},
|
|
||||||
* {host=ip2, port=p2},
|
|
||||||
* ...
|
|
||||||
* {host=ip9, port=p9}
|
|
||||||
* }
|
|
||||||
*/
|
|
||||||
void ParseConninfo(const char* conninfo, StringInfoData* conninfoWithoutHostPort, HostPort** hostPortList)
|
|
||||||
{
|
|
||||||
List* conninfoList = ConninfoToDefList(conninfo);
|
|
||||||
ListCell* l = NULL;
|
|
||||||
|
|
||||||
char* hostStr = NULL;
|
|
||||||
char* portStr = NULL;
|
|
||||||
foreach (l, conninfoList) {
|
|
||||||
DefElem* defel = (DefElem*)lfirst(l);
|
|
||||||
if (pg_strcasecmp(defel->defname, "host") == 0) {
|
|
||||||
hostStr = defGetString(defel);
|
|
||||||
} else if (pg_strcasecmp(defel->defname, "port") == 0) {
|
|
||||||
portStr = defGetString(defel);
|
|
||||||
} else {
|
|
||||||
appendStringInfo(conninfoWithoutHostPort, "%s=%s ", defel->defname, defGetString(defel));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (hostPortList != NULL) {
|
|
||||||
ParseHostPort(hostStr, portStr, hostPortList);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* encrypt conninfo when action = 'E'
|
|
||||||
* decrypt conninfo when action = 'D'
|
|
||||||
* conninfoNew: encrypted or decrypted conninfo
|
|
||||||
*/
|
|
||||||
char* EncryptOrDecryptConninfo(const char* conninfo, const char action)
|
|
||||||
{
|
|
||||||
/* parse conninfo to list */
|
|
||||||
List *conninfoList = ConninfoToDefList(conninfo);
|
|
||||||
/* Sensitive options for subscription */
|
|
||||||
const char* sensitiveOptionsArray[] = {"password"};
|
|
||||||
const int sensitiveArrayLength = lengthof(sensitiveOptionsArray);
|
|
||||||
switch (action) {
|
|
||||||
/* Encrypt */
|
|
||||||
case 'E':
|
|
||||||
EncryptGenericOptions(conninfoList, sensitiveOptionsArray, sensitiveArrayLength, SUBSCRIPTION_MODE);
|
|
||||||
break;
|
|
||||||
|
|
||||||
/* Decrypt */
|
|
||||||
case 'D':
|
|
||||||
DecryptOptions(conninfoList, sensitiveOptionsArray, sensitiveArrayLength, SUBSCRIPTION_MODE);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
char* conninfoNew = DefListToString(conninfoList);
|
|
||||||
ClearListContent(conninfoList);
|
|
||||||
list_free_ext(conninfoList);
|
|
||||||
|
|
||||||
return conninfoNew;
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -23175,7 +23175,7 @@ static void checkValidationForExchangeTable(Relation partTableRel, Relation ordT
|
||||||
int2 bucketId = InvalidBktId;
|
int2 bucketId = InvalidBktId;
|
||||||
|
|
||||||
// get right partition oid for the tuple
|
// get right partition oid for the tuple
|
||||||
targetPartOid = heapTupleGetPartitionId(partTableRel, (HeapTuple)tuple, true);
|
targetPartOid = heapTupleGetPartitionId(partTableRel, (HeapTuple) tuple);
|
||||||
|
|
||||||
searchFakeReationForPartitionOid(
|
searchFakeReationForPartitionOid(
|
||||||
partRelHTAB, CurrentMemoryContext, partTableRel, targetPartOid, partRel, part, RowExclusiveLock);
|
partRelHTAB, CurrentMemoryContext, partTableRel, targetPartOid, partRel, part, RowExclusiveLock);
|
||||||
|
|
@ -24797,8 +24797,7 @@ static Oid AddTemporaryPartitionForAlterPartitions(const AlterTableCmd* cmd, Rel
|
||||||
destPartOid = AddTemporaryHashPartitionForAlterPartitions(cmd, partTableRel, partSeq, renameTargetPart);
|
destPartOid = AddTemporaryHashPartitionForAlterPartitions(cmd, partTableRel, partSeq, renameTargetPart);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case PART_TYPE_RANGE:
|
case PART_TYPE_RANGE: {
|
||||||
case PART_TYPE_INTERVAL: {
|
|
||||||
destPartOid = AddTemporaryRangePartitionForAlterPartitions(cmd, partTableRel, partSeq, renameTargetPart);
|
destPartOid = AddTemporaryRangePartitionForAlterPartitions(cmd, partTableRel, partSeq, renameTargetPart);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -25099,11 +25098,11 @@ static void readTuplesAndInsertInternal(Relation tempTableRel, Relation partTabl
|
||||||
|
|
||||||
/* tableam_tops_copy_tuple is not ready so we add UStore hack path */
|
/* tableam_tops_copy_tuple is not ready so we add UStore hack path */
|
||||||
copyTuple = tableam_tops_copy_tuple(tuple);
|
copyTuple = tableam_tops_copy_tuple(tuple);
|
||||||
targetPartOid = heapTupleGetPartitionId(partTableRel, (void *)tuple, true);
|
targetPartOid = heapTupleGetPartitionId(partTableRel, (void *)tuple);
|
||||||
searchFakeReationForPartitionOid(
|
searchFakeReationForPartitionOid(
|
||||||
partRelHTAB, CurrentMemoryContext, partTableRel, targetPartOid, partRel, part, RowExclusiveLock);
|
partRelHTAB, CurrentMemoryContext, partTableRel, targetPartOid, partRel, part, RowExclusiveLock);
|
||||||
if (RelationIsSubPartitioned(partTableRel)) {
|
if (RelationIsSubPartitioned(partTableRel)) {
|
||||||
targetPartOid = heapTupleGetPartitionId(partRel, (void *)tuple, true);
|
targetPartOid = heapTupleGetPartitionId(partRel, (void *)tuple);
|
||||||
searchFakeReationForPartitionOid(partRelHTAB, CurrentMemoryContext, partRel, targetPartOid, subPartRel,
|
searchFakeReationForPartitionOid(partRelHTAB, CurrentMemoryContext, partRel, targetPartOid, subPartRel,
|
||||||
subPart, RowExclusiveLock);
|
subPart, RowExclusiveLock);
|
||||||
partRel = subPartRel;
|
partRel = subPartRel;
|
||||||
|
|
|
||||||
|
|
@ -1181,17 +1181,6 @@ static Node* pull_up_simple_subquery(PlannerInfo* root, Node* jtnode, RangeTblEn
|
||||||
return jtnode;
|
return jtnode;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* We must flatten any join alias Vars in the subquery's targetlist,
|
|
||||||
* because pulling up the subquery's subqueries might have changed their
|
|
||||||
* expansions into arbitrary expressions, which could affect
|
|
||||||
* pullup_replace_vars' decisions about whether PlaceHolderVar wrappers
|
|
||||||
* are needed for tlist entries. (Likely it'd be better to do
|
|
||||||
* flatten_join_alias_vars on the whole query tree at some earlier stage,
|
|
||||||
* maybe even in the rewriter; but for now let's just fix this case here.)
|
|
||||||
*/
|
|
||||||
subquery->targetList = (List *) flatten_join_alias_vars(subroot, (Node *) subquery->targetList);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Adjust level-0 varnos in subquery so that we can append its rangetable
|
* Adjust level-0 varnos in subquery so that we can append its rangetable
|
||||||
* to upper query's. We have to fix the subquery's append_rel_list as
|
* to upper query's. We have to fix the subquery's append_rel_list as
|
||||||
|
|
|
||||||
|
|
@ -1263,7 +1263,7 @@ static void ckpt_pagewriter_main_thread_loop(void)
|
||||||
HandlePageWriterMainInterrupts();
|
HandlePageWriterMainInterrupts();
|
||||||
|
|
||||||
candidate_num = get_curr_candidate_nums(false) + get_curr_candidate_nums(true);
|
candidate_num = get_curr_candidate_nums(false) + get_curr_candidate_nums(true);
|
||||||
if (candidate_num == 0 && !t_thrd.pagewriter_cxt.shutdown_requested) {
|
if (candidate_num == 0) {
|
||||||
/* wakeup sub thread scan the buffer pool, init the candidate list */
|
/* wakeup sub thread scan the buffer pool, init the candidate list */
|
||||||
wakeup_sub_thread();
|
wakeup_sub_thread();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -825,10 +825,10 @@ void client_read_ended(void)
|
||||||
#define INIT_PLUGIN_OBJECT "init_plugin_object"
|
#define INIT_PLUGIN_OBJECT "init_plugin_object"
|
||||||
void InitBSqlPluginHookIfNeeded()
|
void InitBSqlPluginHookIfNeeded()
|
||||||
{
|
{
|
||||||
const char* dolphin = "dolphin";
|
const char* b_sql_plugin = "b_sql_plugin";
|
||||||
CFunInfo tmpCF;
|
CFunInfo tmpCF;
|
||||||
|
|
||||||
tmpCF = load_external_function(dolphin, INIT_PLUGIN_OBJECT, false, false);
|
tmpCF = load_external_function(b_sql_plugin, INIT_PLUGIN_OBJECT, false, false);
|
||||||
if (tmpCF.user_fn != NULL) {
|
if (tmpCF.user_fn != NULL) {
|
||||||
((void* (*)(void))(tmpCF.user_fn))();
|
((void* (*)(void))(tmpCF.user_fn))();
|
||||||
}
|
}
|
||||||
|
|
@ -862,11 +862,9 @@ List* pg_parse_query(const char* query_string, List** query_string_locationlist)
|
||||||
|
|
||||||
List* (*parser_hook)(const char*, List**) = raw_parser;
|
List* (*parser_hook)(const char*, List**) = raw_parser;
|
||||||
#ifndef ENABLE_MULTIPLE_NODES
|
#ifndef ENABLE_MULTIPLE_NODES
|
||||||
if (u_sess->attr.attr_sql.dolphin) {
|
int id = GetCustomParserId();
|
||||||
int id = GetCustomParserId();
|
if (id >= 0 && g_instance.raw_parser_hook[id] != NULL) {
|
||||||
if (id >= 0 && g_instance.raw_parser_hook[id] != NULL) {
|
parser_hook = (List* (*)(const char*, List**))g_instance.raw_parser_hook[id];
|
||||||
parser_hook = (List* (*)(const char*, List**))g_instance.raw_parser_hook[id];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
raw_parsetree_list = parser_hook(query_string, query_string_locationlist);
|
raw_parsetree_list = parser_hook(query_string, query_string_locationlist);
|
||||||
|
|
@ -6114,9 +6112,6 @@ void ProcessInterrupts(void)
|
||||||
|
|
||||||
/* The logical replication launcher can be stopped at any time. */
|
/* The logical replication launcher can be stopped at any time. */
|
||||||
proc_exit(0);
|
proc_exit(0);
|
||||||
} else if (IsLogicalWorker()) {
|
|
||||||
ereport(FATAL, (errcode(ERRCODE_ADMIN_SHUTDOWN),
|
|
||||||
errmsg("terminating logical replication worker due to administrator command")));
|
|
||||||
#endif
|
#endif
|
||||||
} else if (IsTxnSnapCapturerProcess()) {
|
} else if (IsTxnSnapCapturerProcess()) {
|
||||||
ereport(FATAL,
|
ereport(FATAL,
|
||||||
|
|
@ -7574,7 +7569,7 @@ int PostgresMain(int argc, char* argv[], const char* dbname, const char* usernam
|
||||||
init_set_params_htab();
|
init_set_params_htab();
|
||||||
|
|
||||||
#ifndef ENABLE_MULTIPLE_NODES
|
#ifndef ENABLE_MULTIPLE_NODES
|
||||||
if (u_sess->proc_cxt.MyDatabaseId != InvalidOid && DB_IS_CMPT(B_FORMAT) && u_sess->attr.attr_sql.dolphin) {
|
if (u_sess->proc_cxt.MyDatabaseId != InvalidOid && DB_IS_CMPT(B_FORMAT) && u_sess->attr.attr_sql.b_sql_plugin) {
|
||||||
InitBSqlPluginHookIfNeeded();
|
InitBSqlPluginHookIfNeeded();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -848,7 +848,7 @@ static bool InitSession(knl_session_context* session)
|
||||||
t_thrd.proc_cxt.PostInit->InitSession();
|
t_thrd.proc_cxt.PostInit->InitSession();
|
||||||
|
|
||||||
#ifndef ENABLE_MULTIPLE_NODES
|
#ifndef ENABLE_MULTIPLE_NODES
|
||||||
if (u_sess->proc_cxt.MyDatabaseId != InvalidOid && DB_IS_CMPT(B_FORMAT) && u_sess->attr.attr_sql.dolphin) {
|
if (u_sess->proc_cxt.MyDatabaseId != InvalidOid && DB_IS_CMPT(B_FORMAT) && u_sess->attr.attr_sql.b_sql_plugin) {
|
||||||
InitBSqlPluginHookIfNeeded();
|
InitBSqlPluginHookIfNeeded();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -720,6 +720,7 @@ static Datum ExecEvalWholeRowVar(
|
||||||
{
|
{
|
||||||
Var* variable = (Var*)wrvstate->xprstate.expr;
|
Var* variable = (Var*)wrvstate->xprstate.expr;
|
||||||
TupleTableSlot* slot = NULL;
|
TupleTableSlot* slot = NULL;
|
||||||
|
TupleDesc slot_tupdesc;
|
||||||
bool needslow = false;
|
bool needslow = false;
|
||||||
|
|
||||||
if (isDone != NULL)
|
if (isDone != NULL)
|
||||||
|
|
@ -801,13 +802,21 @@ static Datum ExecEvalWholeRowVar(
|
||||||
if (wrvstate->wrv_junkFilter != NULL)
|
if (wrvstate->wrv_junkFilter != NULL)
|
||||||
slot = ExecFilterJunk(wrvstate->wrv_junkFilter, slot);
|
slot = ExecFilterJunk(wrvstate->wrv_junkFilter, slot);
|
||||||
|
|
||||||
|
slot_tupdesc = slot->tts_tupleDescriptor;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
* If it's a RECORD Var, we'll use the slot's type ID info. It's likely
|
||||||
|
* that the slot's type is also RECORD; if so, make sure it's been
|
||||||
|
* "blessed", so that the Datum can be interpreted later.
|
||||||
|
*
|
||||||
* If the Var identifies a named composite type, we must check that the
|
* If the Var identifies a named composite type, we must check that the
|
||||||
* actual tuple type is compatible with it.
|
* actual tuple type is compatible with it.
|
||||||
*/
|
*/
|
||||||
if (variable->vartype != RECORDOID) {
|
if (variable->vartype == RECORDOID) {
|
||||||
|
if (slot_tupdesc->tdtypeid == RECORDOID && slot_tupdesc->tdtypmod < 0)
|
||||||
|
assign_record_type_typmod(slot_tupdesc);
|
||||||
|
} else {
|
||||||
TupleDesc var_tupdesc;
|
TupleDesc var_tupdesc;
|
||||||
TupleDesc slot_tupdesc;
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -824,8 +833,6 @@ static Datum ExecEvalWholeRowVar(
|
||||||
*/
|
*/
|
||||||
var_tupdesc = lookup_rowtype_tupdesc(variable->vartype, -1);
|
var_tupdesc = lookup_rowtype_tupdesc(variable->vartype, -1);
|
||||||
|
|
||||||
slot_tupdesc = slot->tts_tupleDescriptor;
|
|
||||||
|
|
||||||
if (var_tupdesc->natts != slot_tupdesc->natts)
|
if (var_tupdesc->natts != slot_tupdesc->natts)
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_DATATYPE_MISMATCH),
|
(errcode(ERRCODE_DATATYPE_MISMATCH),
|
||||||
|
|
@ -879,7 +886,6 @@ static Datum ExecEvalWholeRowFast(
|
||||||
{
|
{
|
||||||
Var* variable = (Var*)wrvstate->xprstate.expr;
|
Var* variable = (Var*)wrvstate->xprstate.expr;
|
||||||
TupleTableSlot* slot = NULL;
|
TupleTableSlot* slot = NULL;
|
||||||
TupleDesc slot_tupdesc;
|
|
||||||
HeapTuple tuple;
|
HeapTuple tuple;
|
||||||
TupleDesc tupleDesc;
|
TupleDesc tupleDesc;
|
||||||
HeapTupleHeader dtuple;
|
HeapTupleHeader dtuple;
|
||||||
|
|
@ -909,17 +915,6 @@ static Datum ExecEvalWholeRowFast(
|
||||||
if (wrvstate->wrv_junkFilter != NULL)
|
if (wrvstate->wrv_junkFilter != NULL)
|
||||||
slot = ExecFilterJunk(wrvstate->wrv_junkFilter, slot);
|
slot = ExecFilterJunk(wrvstate->wrv_junkFilter, slot);
|
||||||
|
|
||||||
/*
|
|
||||||
* If it's a RECORD Var, we'll use the slot's type ID info. It's likely
|
|
||||||
* that the slot's type is also RECORD; if so, make sure it's been
|
|
||||||
* "blessed", so that the Datum can be interpreted later.
|
|
||||||
*/
|
|
||||||
slot_tupdesc = slot->tts_tupleDescriptor;
|
|
||||||
if (variable->vartype == RECORDOID) {
|
|
||||||
if (slot_tupdesc->tdtypeid == RECORDOID && slot_tupdesc->tdtypmod < 0)
|
|
||||||
assign_record_type_typmod(slot_tupdesc);
|
|
||||||
}
|
|
||||||
|
|
||||||
tuple = ExecFetchSlotTuple(slot);
|
tuple = ExecFetchSlotTuple(slot);
|
||||||
tupleDesc = slot->tts_tupleDescriptor;
|
tupleDesc = slot->tts_tupleDescriptor;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -322,6 +322,7 @@ static bool RelationFindReplTupleByIndex(EState *estate, Relation rel, Relation
|
||||||
}
|
}
|
||||||
if (found) {
|
if (found) {
|
||||||
/* Found tuple, try to lock it in the lockmode. */
|
/* Found tuple, try to lock it in the lockmode. */
|
||||||
|
outslot->tts_tuple = ExecMaterializeSlot(outslot);
|
||||||
xwait = TransactionIdIsValid(snap.xmin) ? snap.xmin : snap.xmax;
|
xwait = TransactionIdIsValid(snap.xmin) ? snap.xmin : snap.xmax;
|
||||||
/*
|
/*
|
||||||
* If the tuple is locked, wait for locking transaction to finish
|
* If the tuple is locked, wait for locking transaction to finish
|
||||||
|
|
@ -345,16 +346,12 @@ static bool RelationFindReplTupleByIndex(EState *estate, Relation rel, Relation
|
||||||
ItemPointer tid = tableam_tops_get_t_self(targetRel, outslot->tts_tuple);
|
ItemPointer tid = tableam_tops_get_t_self(targetRel, outslot->tts_tuple);
|
||||||
|
|
||||||
if (RelationIsUstoreFormat(targetRel)) {
|
if (RelationIsUstoreFormat(targetRel)) {
|
||||||
/* materialize the slot, so we can visit it after the scan is end */
|
|
||||||
outslot->tts_tuple = UHeapMaterialize(outslot);
|
|
||||||
ItemPointerCopy(tid, &UHeaplocktup.ctid);
|
ItemPointerCopy(tid, &UHeaplocktup.ctid);
|
||||||
rc = memset_s(&tbuf, sizeof(tbuf), 0, sizeof(tbuf));
|
rc = memset_s(&tbuf, sizeof(tbuf), 0, sizeof(tbuf));
|
||||||
securec_check(rc, "\0", "\0");
|
securec_check(rc, "\0", "\0");
|
||||||
UHeaplocktup.disk_tuple = &tbuf.hdr;
|
UHeaplocktup.disk_tuple = &tbuf.hdr;
|
||||||
locktup = &UHeaplocktup;
|
locktup = &UHeaplocktup;
|
||||||
} else {
|
} else {
|
||||||
/* materialize the slot, so we can visit it after the scan is end */
|
|
||||||
outslot->tts_tuple = ExecMaterializeSlot(outslot);
|
|
||||||
ItemPointerCopy(tid, &heaplocktup.t_self);
|
ItemPointerCopy(tid, &heaplocktup.t_self);
|
||||||
locktup = &heaplocktup;
|
locktup = &heaplocktup;
|
||||||
}
|
}
|
||||||
|
|
@ -404,10 +401,6 @@ static bool tuple_equals_slot(TupleDesc desc, const Tuple tup, TupleTableSlot *s
|
||||||
/* Check equality of the attributes. */
|
/* Check equality of the attributes. */
|
||||||
for (attrnum = 0; attrnum < desc->natts; attrnum++) {
|
for (attrnum = 0; attrnum < desc->natts; attrnum++) {
|
||||||
TypeCacheEntry *typentry;
|
TypeCacheEntry *typentry;
|
||||||
/* skip generate column */
|
|
||||||
if (GetGeneratedCol(desc, attrnum)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
/*
|
/*
|
||||||
* If one value is NULL and other is not, then they are certainly not
|
* If one value is NULL and other is not, then they are certainly not
|
||||||
* equal
|
* equal
|
||||||
|
|
@ -485,6 +478,7 @@ static bool RelationFindReplTupleSeq(Relation rel, LockTupleMode lockmode, Tuple
|
||||||
|
|
||||||
found = true;
|
found = true;
|
||||||
ExecStoreTuple(scantuple, outslot, InvalidBuffer, false);
|
ExecStoreTuple(scantuple, outslot, InvalidBuffer, false);
|
||||||
|
outslot->tts_tuple = ExecMaterializeSlot(outslot);
|
||||||
|
|
||||||
xwait = TransactionIdIsValid(snap.xmin) ? snap.xmin : snap.xmax;
|
xwait = TransactionIdIsValid(snap.xmin) ? snap.xmin : snap.xmax;
|
||||||
/*
|
/*
|
||||||
|
|
@ -517,16 +511,12 @@ static bool RelationFindReplTupleSeq(Relation rel, LockTupleMode lockmode, Tuple
|
||||||
ItemPointer tid = tableam_tops_get_t_self(rel, outslot->tts_tuple);
|
ItemPointer tid = tableam_tops_get_t_self(rel, outslot->tts_tuple);
|
||||||
|
|
||||||
if (RelationIsUstoreFormat(targetRel)) {
|
if (RelationIsUstoreFormat(targetRel)) {
|
||||||
/* materialize the slot, so we can visit it after the scan is end */
|
|
||||||
outslot->tts_tuple = UHeapMaterialize(outslot);
|
|
||||||
ItemPointerCopy(tid, &UHeaplocktup.ctid);
|
ItemPointerCopy(tid, &UHeaplocktup.ctid);
|
||||||
rc = memset_s(&tbuf, sizeof(tbuf), 0, sizeof(tbuf));
|
rc = memset_s(&tbuf, sizeof(tbuf), 0, sizeof(tbuf));
|
||||||
securec_check(rc, "\0", "\0");
|
securec_check(rc, "\0", "\0");
|
||||||
UHeaplocktup.disk_tuple = &tbuf.hdr;
|
UHeaplocktup.disk_tuple = &tbuf.hdr;
|
||||||
locktup = &UHeaplocktup;
|
locktup = &UHeaplocktup;
|
||||||
} else {
|
} else {
|
||||||
/* materialize the slot, so we can visit it after the scan is end */
|
|
||||||
outslot->tts_tuple = ExecMaterializeSlot(outslot);
|
|
||||||
ItemPointerCopy(tid, &heaplocktup.t_self);
|
ItemPointerCopy(tid, &heaplocktup.t_self);
|
||||||
locktup = &heaplocktup;
|
locktup = &heaplocktup;
|
||||||
}
|
}
|
||||||
|
|
@ -663,6 +653,7 @@ void ExecSimpleRelationUpdate(EState *estate, EPQState *epqstate, TupleTableSlot
|
||||||
/* Compute stored generated columns */
|
/* Compute stored generated columns */
|
||||||
if (rel->rd_att->constr && rel->rd_att->constr->has_generated_stored) {
|
if (rel->rd_att->constr && rel->rd_att->constr->has_generated_stored) {
|
||||||
ExecComputeStoredGenerated(resultRelInfo, estate, slot, tuple, CMD_UPDATE);
|
ExecComputeStoredGenerated(resultRelInfo, estate, slot, tuple, CMD_UPDATE);
|
||||||
|
tuple = slot->tts_tuple;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check the constraints of the tuple */
|
/* Check the constraints of the tuple */
|
||||||
|
|
@ -681,11 +672,10 @@ void ExecSimpleRelationUpdate(EState *estate, EPQState *epqstate, TupleTableSlot
|
||||||
rowMovement = true;
|
rowMovement = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
tuple = slot->tts_tuple;
|
|
||||||
CommandId cid = GetCurrentCommandId(true);
|
CommandId cid = GetCurrentCommandId(true);
|
||||||
/* OK, update the tuple and index entries for it */
|
/* OK, update the tuple and index entries for it */
|
||||||
if (!rowMovement) {
|
if (!rowMovement) {
|
||||||
res = tableam_tuple_update(targetRelation, parentRelation, searchSlotTid, tuple, cid,
|
res = tableam_tuple_update(targetRelation, parentRelation, searchSlotTid, slot->tts_tuple, cid,
|
||||||
InvalidSnapshot, estate->es_snapshot, true, &oldslot, &tmfd, &updateIndexes, &modifiedIdxAttrs,
|
InvalidSnapshot, estate->es_snapshot, true, &oldslot, &tmfd, &updateIndexes, &modifiedIdxAttrs,
|
||||||
false, allowInplaceUpdate);
|
false, allowInplaceUpdate);
|
||||||
CheckTupleModifyRes(res);
|
CheckTupleModifyRes(res);
|
||||||
|
|
|
||||||
|
|
@ -2947,9 +2947,9 @@ void SetOneOfCompressOption(DefElem* defElem, TableCreateSupport* tableCreateSup
|
||||||
} else if (pg_strcasecmp(defname, "compress_level") == 0) {
|
} else if (pg_strcasecmp(defname, "compress_level") == 0) {
|
||||||
tableCreateSupport->compressLevel = true;
|
tableCreateSupport->compressLevel = true;
|
||||||
} else if (pg_strcasecmp(defname, "compress_byte_convert") == 0) {
|
} else if (pg_strcasecmp(defname, "compress_byte_convert") == 0) {
|
||||||
tableCreateSupport->compressByteConvert = defGetBoolean(defElem);
|
tableCreateSupport->compressByteConvert = true;
|
||||||
} else if (pg_strcasecmp(defname, "compress_diff_convert") == 0) {
|
} else if (pg_strcasecmp(defname, "compress_diff_convert") == 0) {
|
||||||
tableCreateSupport->compressDiffConvert = defGetBoolean(defElem);
|
tableCreateSupport->compressDiffConvert = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8965,8 +8965,6 @@ void StartupXLOG(void)
|
||||||
g_instance.comm_cxt.predo_cxt.redoPf.redo_done_time = 0;
|
g_instance.comm_cxt.predo_cxt.redoPf.redo_done_time = 0;
|
||||||
pg_atomic_write_u32(&(g_instance.comm_cxt.localinfo_cxt.is_finish_redo), 0);
|
pg_atomic_write_u32(&(g_instance.comm_cxt.localinfo_cxt.is_finish_redo), 0);
|
||||||
|
|
||||||
NotifyGscRecoveryStarted();
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Initialize WAL insert status array and the flush index - lastWalStatusEntryFlushed.
|
* Initialize WAL insert status array and the flush index - lastWalStatusEntryFlushed.
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -1818,47 +1818,3 @@ void UHeapSlotStoreUHeapTuple(UHeapTuple utuple, TupleTableSlot *slot, bool shou
|
||||||
/* Mark extracted state invalid */
|
/* Mark extracted state invalid */
|
||||||
slot->tts_nvalid = 0;
|
slot->tts_nvalid = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Make the contents of the uheap table's slot contents solely depend on the slot(make them a local copy),
|
|
||||||
* and not on underlying external resources like another memory context, buffers etc.
|
|
||||||
*
|
|
||||||
* @pram slot: slot to be materialized.
|
|
||||||
*/
|
|
||||||
Tuple UHeapMaterialize(TupleTableSlot *slot)
|
|
||||||
{
|
|
||||||
Assert(!slot->tts_isempty);
|
|
||||||
Assert(slot->tts_tupslotTableAm == TAM_USTORE);
|
|
||||||
Assert(slot->tts_tupleDescriptor != NULL);
|
|
||||||
/*
|
|
||||||
* If we have a regular physical tuple, and it's locally palloc'd, we have
|
|
||||||
* nothing to do.
|
|
||||||
*/
|
|
||||||
if (slot->tts_tuple && slot->tts_shouldFree) {
|
|
||||||
return slot->tts_tuple;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Otherwise, copy or build a physical tuple, and store it into the slot.
|
|
||||||
*
|
|
||||||
* We may be called in a context that is shorter-lived than the tuple
|
|
||||||
* slot, but we have to ensure that the materialized tuple will survive
|
|
||||||
* anyway.
|
|
||||||
*/
|
|
||||||
MemoryContext old_context = MemoryContextSwitchTo(slot->tts_mcxt);
|
|
||||||
if (slot->tts_tuple != NULL) {
|
|
||||||
slot->tts_tuple = UHeapCopyTuple((UHeapTuple)slot->tts_tuple);
|
|
||||||
} else {
|
|
||||||
slot->tts_tuple = UHeapFormTuple(slot->tts_tupleDescriptor, slot->tts_values, slot->tts_isnull);
|
|
||||||
}
|
|
||||||
slot->tts_shouldFree = true;
|
|
||||||
MemoryContextSwitchTo(old_context);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Have to deform from scratch, otherwise tts_values[] entries could point
|
|
||||||
* into the non-materialized tuple (which might be gone when accessed).
|
|
||||||
*/
|
|
||||||
slot->tts_nvalid = 0;
|
|
||||||
return slot->tts_tuple;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -238,19 +238,15 @@ public:
|
||||||
return m_purpose;
|
return m_purpose;
|
||||||
}
|
}
|
||||||
|
|
||||||
GcEpochType GcStartInnerTxn()
|
void GcStartTxnMTtests()
|
||||||
{
|
{
|
||||||
m_gcEpoch = GetGlobalEpoch();
|
if (m_gcEpoch != GetGlobalEpoch())
|
||||||
|
m_gcEpoch = GetGlobalEpoch();
|
||||||
return m_gcEpoch;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GcEndInnerTxn(bool clean_gc)
|
void GcEndTxnMTtests()
|
||||||
{
|
{
|
||||||
if (clean_gc) {
|
RunQuicese();
|
||||||
RunQuicese();
|
|
||||||
}
|
|
||||||
m_gcEpoch = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GcStartTxn()
|
void GcStartTxn()
|
||||||
|
|
@ -276,7 +272,6 @@ public:
|
||||||
RunQuicese();
|
RunQuicese();
|
||||||
m_managerLock.unlock();
|
m_managerLock.unlock();
|
||||||
}
|
}
|
||||||
m_gcEpoch = 0;
|
|
||||||
m_isTxnStarted = false;
|
m_isTxnStarted = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -318,6 +313,7 @@ public:
|
||||||
{
|
{
|
||||||
if (m_performGcEpoch != g_gcActiveEpoch)
|
if (m_performGcEpoch != g_gcActiveEpoch)
|
||||||
HardQuiesce(m_rcuFreeCount);
|
HardQuiesce(m_rcuFreeCount);
|
||||||
|
m_gcEpoch = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @brief Clean all object at the end of the session */
|
/** @brief Clean all object at the end of the session */
|
||||||
|
|
|
||||||
|
|
@ -258,15 +258,6 @@ bool Index::IndexInsert(Sentinel*& outputSentinel, const Key* key, uint32_t pid,
|
||||||
outputSentinel = IndexInsertImpl(key, sentinel, inserted, pid);
|
outputSentinel = IndexInsertImpl(key, sentinel, inserted, pid);
|
||||||
// sync between rollback/delete and insert
|
// sync between rollback/delete and insert
|
||||||
if (inserted == false) {
|
if (inserted == false) {
|
||||||
if (unlikely(outputSentinel == nullptr)) {
|
|
||||||
MOT_REPORT_ERROR(
|
|
||||||
MOT_ERROR_OOM, "Index Insert", "Failed to insert sentinel to index %s", m_name.c_str());
|
|
||||||
rc = RC_MEMORY_ALLOCATION_ERROR;
|
|
||||||
m_sentinelPool->Release<Sentinel>(sentinel);
|
|
||||||
sentinel = nullptr;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Spin if the counter is 0 - aborting in parallel or sentinel is marks for commit
|
// Spin if the counter is 0 - aborting in parallel or sentinel is marks for commit
|
||||||
if (outputSentinel->RefCountUpdate(INC, pid) == RC_OK)
|
if (outputSentinel->RefCountUpdate(INC, pid) == RC_OK)
|
||||||
retryInsert = false;
|
retryInsert = false;
|
||||||
|
|
@ -309,16 +300,8 @@ Sentinel* Index::IndexInsert(const Key* key, Row* row, uint32_t pid)
|
||||||
// no need to report to full error stack
|
// no need to report to full error stack
|
||||||
SetLastError(MOT_ERROR_UNIQUE_VIOLATION, MOT_SEVERITY_NORMAL);
|
SetLastError(MOT_ERROR_UNIQUE_VIOLATION, MOT_SEVERITY_NORMAL);
|
||||||
m_sentinelPool->Release<Sentinel>(sentinel);
|
m_sentinelPool->Release<Sentinel>(sentinel);
|
||||||
sentinel = nullptr;
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
} else {
|
} else {
|
||||||
if (inserted == false) {
|
|
||||||
MOT_REPORT_ERROR(MOT_ERROR_OOM, "Index Insert", "Failed to insert sentinel to index %s", m_name.c_str());
|
|
||||||
m_sentinelPool->Release<Sentinel>(sentinel);
|
|
||||||
sentinel = nullptr;
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (GetIndexOrder() == IndexOrder::INDEX_ORDER_PRIMARY) {
|
if (GetIndexOrder() == IndexOrder::INDEX_ORDER_PRIMARY) {
|
||||||
sentinel->SetPrimaryIndex();
|
sentinel->SetPrimaryIndex();
|
||||||
sentinel->SetNextPtr(row);
|
sentinel->SetNextPtr(row);
|
||||||
|
|
@ -360,6 +343,9 @@ Sentinel* Index::IndexReadHeader(const Key* key, uint32_t pid) const
|
||||||
Sentinel* Index::IndexRemove(const Key* key, uint32_t pid)
|
Sentinel* Index::IndexRemove(const Key* key, uint32_t pid)
|
||||||
{
|
{
|
||||||
Sentinel* sentinel = IndexRemoveImpl(key, pid);
|
Sentinel* sentinel = IndexRemoveImpl(key, pid);
|
||||||
|
|
||||||
|
MOT_ASSERT(sentinel != nullptr);
|
||||||
|
MOT_ASSERT(sentinel->GetCounter() == 0);
|
||||||
return sentinel;
|
return sentinel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -56,22 +56,12 @@ void* basic_table<P>::insert(MOT::Key const* const& key, void* const& entry, boo
|
||||||
5. Update the the key slice, keylen, key suffix and key's value in the
|
5. Update the the key slice, keylen, key suffix and key's value in the
|
||||||
leaf
|
leaf
|
||||||
6. Add the key's location in permutation's back (key is not visible for
|
6. Add the key's location in permutation's back (key is not visible for
|
||||||
readers yet) as key's location is not part of the permutation yet, the key
|
readers yet) As key's location is not part of the permutation yet, the key
|
||||||
is not reachable (aka not present). In addition, the leaf is still locked.
|
is not reachable (aka not present). In addition, the leaf is still locked.
|
||||||
Unlocking the node and enter the key into the permutation will be done
|
Unlocking the node and enter the key into the permutation will be done
|
||||||
later in finish_insert (done in lp.finish function). */
|
later in finish_insert (called from lp.finish). */
|
||||||
|
|
||||||
bool found = false;
|
bool found = lp.find_insert(*mtSessionThreadInfo);
|
||||||
if (!lp.find_insert(*mtSessionThreadInfo, found)) {
|
|
||||||
// Failed to insert key due to memory allocation failure.
|
|
||||||
MOT_ASSERT(!mtSessionThreadInfo->non_disruptive_error());
|
|
||||||
MOT_ASSERT(found == false);
|
|
||||||
lp.finish(0, *mtSessionThreadInfo);
|
|
||||||
result = false;
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
MOT_ASSERT(mtSessionThreadInfo->non_disruptive_error());
|
|
||||||
|
|
||||||
// If the key is new (not previously existing) then we record the entry under
|
// If the key is new (not previously existing) then we record the entry under
|
||||||
// that key
|
// that key
|
||||||
|
|
|
||||||
|
|
@ -33,15 +33,15 @@ namespace Masstree {
|
||||||
template <typename P>
|
template <typename P>
|
||||||
struct gc_layer_rcu_callback_ng : public P::threadinfo_type::mrcu_callback {
|
struct gc_layer_rcu_callback_ng : public P::threadinfo_type::mrcu_callback {
|
||||||
typedef typename P::threadinfo_type threadinfo;
|
typedef typename P::threadinfo_type threadinfo;
|
||||||
node_base<P>** root_ref_;
|
node_base<P>* root_;
|
||||||
int len_;
|
int len_;
|
||||||
size_t size_;
|
size_t size_;
|
||||||
MOT::MasstreePrimaryIndex* index_;
|
MOT::MasstreePrimaryIndex* index_;
|
||||||
char s_[0];
|
char s_[0];
|
||||||
gc_layer_rcu_callback_ng(node_base<P>** root_ref, Str prefix, size_t size)
|
gc_layer_rcu_callback_ng(node_base<P>* root, Str prefix, size_t size)
|
||||||
: root_ref_(root_ref), len_(prefix.length()), size_(size), index_(mtSessionThreadInfo->get_working_index())
|
: root_(root), len_(prefix.length()), size_(size), index_(mtSessionThreadInfo->get_working_index())
|
||||||
{
|
{
|
||||||
errno_t erc = memcpy_s(s_, len_, prefix.data(), len_);
|
errno_t erc = memcpy_s(s_, size_, prefix.data(), len_);
|
||||||
securec_check(erc, "\0", "\0");
|
securec_check(erc, "\0", "\0");
|
||||||
}
|
}
|
||||||
size_t operator()(bool drop_index);
|
size_t operator()(bool drop_index);
|
||||||
|
|
@ -51,7 +51,7 @@ struct gc_layer_rcu_callback_ng : public P::threadinfo_type::mrcu_callback {
|
||||||
return size_;
|
return size_;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void make(node_base<P>** root_ref, Str prefix, threadinfo& ti);
|
static void make(node_base<P>* root, Str prefix, threadinfo& ti);
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename P>
|
template <typename P>
|
||||||
|
|
@ -60,8 +60,8 @@ size_t gc_layer_rcu_callback_ng<P>::operator()(bool drop_index)
|
||||||
// If drop_index == true, all index's pools are going to be cleaned, so we can skip gc_layer call (which might add
|
// If drop_index == true, all index's pools are going to be cleaned, so we can skip gc_layer call (which might add
|
||||||
// more elements into GC)
|
// more elements into GC)
|
||||||
if (drop_index == false) {
|
if (drop_index == false) {
|
||||||
// GC layer remove might delete elements from tree and might create new gc layer removal requests and add them to GC.
|
// GC layer remove might delete elements from tree and add them to the limbolist. Index must be provided to
|
||||||
// Index must be provided to allow access to the memory pools.
|
// allow access to the memory pools.
|
||||||
mtSessionThreadInfo->set_working_index(index_);
|
mtSessionThreadInfo->set_working_index(index_);
|
||||||
(*this)(*mtSessionThreadInfo);
|
(*this)(*mtSessionThreadInfo);
|
||||||
mtSessionThreadInfo->set_working_index(NULL);
|
mtSessionThreadInfo->set_working_index(NULL);
|
||||||
|
|
@ -73,33 +73,30 @@ size_t gc_layer_rcu_callback_ng<P>::operator()(bool drop_index)
|
||||||
template <typename P>
|
template <typename P>
|
||||||
void gc_layer_rcu_callback_ng<P>::operator()(threadinfo& ti)
|
void gc_layer_rcu_callback_ng<P>::operator()(threadinfo& ti)
|
||||||
{
|
{
|
||||||
masstree_invariant(root_ref_);
|
// root_ node while creating gc_layer_rcu_callback_ng might not be the current root. Find updated tree's root.
|
||||||
|
while (!root_->is_root()) {
|
||||||
tcursor<P> node_cursor(root_ref_, s_, len_);
|
root_ = root_->maybe_parent();
|
||||||
bool do_remove = node_cursor.gc_layer(ti);
|
|
||||||
if (!do_remove || !node_cursor.finish_remove(ti)) {
|
|
||||||
node_cursor.n_->unlock();
|
|
||||||
}
|
}
|
||||||
ti.add_nodes_to_gc();
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename P>
|
// If root was already deleted, do nothing.
|
||||||
void gc_layer_rcu_callback_ng<P>::make(node_base<P>** root_ref, Str prefix, threadinfo& ti)
|
if (root_->deleted()) {
|
||||||
{
|
|
||||||
size_t sz = prefix.len + sizeof(gc_layer_rcu_callback_ng<P>);
|
|
||||||
// As we are using slab allocator for allocation, sz is will be updated by ti.allocate with the real allocation
|
|
||||||
// size. We need this size for GC deallocation size report
|
|
||||||
void* data = ti.allocate(sz, memtag_masstree_gc, &sz /* IN/OUT PARAM */);
|
|
||||||
if (!data) {
|
|
||||||
// If allocation fails, gc layer removal command will not be added to GC and this layer wont be removed.
|
|
||||||
// We might deal with this issue in the future by replacing the current mechanism with one of the following options:
|
|
||||||
// 1. Use thread local GC layer removal object (per threadinfo) and keep list of key suffixes to clean (also in threadinfo)
|
|
||||||
// 2. Move this feature to VACUUM process: Create special iterator that adds GC Layer callbacks when it finds empty layers
|
|
||||||
ti.set_last_error(MT_MERR_GC_LAYER_REMOVAL_MAKE);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
gc_layer_rcu_callback_ng<P>* cb = new (data) gc_layer_rcu_callback_ng<P>(root_ref, prefix, sz);
|
tcursor<P> node_cursor(root_, s_, len_);
|
||||||
|
if (!node_cursor.gc_layer(ti) || !node_cursor.finish_remove(ti)) {
|
||||||
|
node_cursor.n_->unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename P>
|
||||||
|
void gc_layer_rcu_callback_ng<P>::make(node_base<P>* root, Str prefix, threadinfo& ti)
|
||||||
|
{
|
||||||
|
size_t sz = prefix.len + sizeof(gc_layer_rcu_callback_ng<P>);
|
||||||
|
// As we are using slab allocator to allocate the memory, sz is will updated in ti.allocate with the real allocated
|
||||||
|
// size
|
||||||
|
void* data = ti.allocate(sz, memtag_masstree_gc, &sz /*OUT PARAM*/);
|
||||||
|
gc_layer_rcu_callback_ng<P>* cb = new (data) gc_layer_rcu_callback_ng<P>(root, prefix, sz);
|
||||||
ti.rcu_register(cb, sz);
|
ti.rcu_register(cb, sz);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -69,17 +69,14 @@ Sentinel* MasstreePrimaryIndex::IndexInsertImpl(const Key* key, Sentinel* sentin
|
||||||
mtSessionThreadInfo->set_gc_session(
|
mtSessionThreadInfo->set_gc_session(
|
||||||
MOTEngine::GetInstance()->GetCurrentGcSession()); // set current GC session in thread-pooled envelope
|
MOTEngine::GetInstance()->GetCurrentGcSession()); // set current GC session in thread-pooled envelope
|
||||||
|
|
||||||
mtSessionThreadInfo->set_last_error(MT_MERR_OK);
|
|
||||||
|
|
||||||
existingItem = m_index.insert(key, sentinel, inserted, pid);
|
existingItem = m_index.insert(key, sentinel, inserted, pid);
|
||||||
|
|
||||||
mtSessionThreadInfo->set_gc_session(NULL);
|
mtSessionThreadInfo->set_gc_session(NULL);
|
||||||
mtSessionThreadInfo->set_working_index(NULL);
|
mtSessionThreadInfo->set_working_index(NULL);
|
||||||
|
|
||||||
if (!inserted && existingItem) { // key mapping already exists in unique index
|
if (!inserted) { // key mapping already exists in unique index
|
||||||
result = reinterpret_cast<Sentinel*>(existingItem);
|
result = reinterpret_cast<Sentinel*>(existingItem);
|
||||||
} // otherwise return null pointer (if !inserted && !existingItem, Key does not exist and insertation failed due to
|
} // otherwise return null pointer
|
||||||
// memory issue)
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
@ -111,8 +108,6 @@ Sentinel* MasstreePrimaryIndex::IndexRemoveImpl(const Key* key, uint32_t pid)
|
||||||
mtSessionThreadInfo->set_gc_session(
|
mtSessionThreadInfo->set_gc_session(
|
||||||
MOTEngine::GetInstance()->GetCurrentGcSession()); // set current GC session in thread-pooled envelope
|
MOTEngine::GetInstance()->GetCurrentGcSession()); // set current GC session in thread-pooled envelope
|
||||||
|
|
||||||
mtSessionThreadInfo->set_last_error(MT_MERR_OK);
|
|
||||||
|
|
||||||
output = m_index.remove(key->GetKeyBuf(), key->GetKeyLength(), result, pid);
|
output = m_index.remove(key->GetKeyBuf(), key->GetKeyLength(), result, pid);
|
||||||
|
|
||||||
mtSessionThreadInfo->set_gc_session(NULL);
|
mtSessionThreadInfo->set_gc_session(NULL);
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,6 @@
|
||||||
#include "masstree/mot_masstree_struct.hpp"
|
#include "masstree/mot_masstree_struct.hpp"
|
||||||
#include "masstree/mot_masstree_iterator.hpp"
|
#include "masstree/mot_masstree_iterator.hpp"
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include "mot_engine.h"
|
|
||||||
|
|
||||||
namespace MOT {
|
namespace MOT {
|
||||||
/**
|
/**
|
||||||
|
|
@ -303,38 +302,11 @@ public:
|
||||||
/**
|
/**
|
||||||
* @brief Print Masstree pools memory consumption details to log.
|
* @brief Print Masstree pools memory consumption details to log.
|
||||||
*/
|
*/
|
||||||
virtual void PrintPoolsStats(LogLevel level = LogLevel::LL_DEBUG)
|
virtual void PrintPoolsStats()
|
||||||
{
|
{
|
||||||
m_leafsPool->Print("Leafs pool", level);
|
m_leafsPool->Print("Leafs pool: ");
|
||||||
m_internodesPool->Print("Internode pool", level);
|
m_internodesPool->Print("Internode pool: ");
|
||||||
m_ksuffixSlab->Print("Ksuffix slab", level);
|
m_ksuffixSlab->Print("Ksuffix slab: ");
|
||||||
}
|
|
||||||
|
|
||||||
virtual void GetLeafsPoolStats(uint64_t& objSize, uint64_t& numUsedObj, uint64_t& totalSize, uint64_t& netto)
|
|
||||||
{
|
|
||||||
PoolStatsSt stats = {};
|
|
||||||
m_leafsPool->GetStats(stats);
|
|
||||||
|
|
||||||
objSize = stats.m_objSize;
|
|
||||||
numUsedObj = stats.m_totalObjCount - stats.m_freeObjCount;
|
|
||||||
totalSize = stats.m_poolCount * stats.m_poolGrossSize;
|
|
||||||
netto = numUsedObj * objSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void GetInternodesPoolStats(uint64_t& objSize, uint64_t& numUsedObj, uint64_t& totalSize, uint64_t& netto)
|
|
||||||
{
|
|
||||||
PoolStatsSt stats = {};
|
|
||||||
m_internodesPool->GetStats(stats);
|
|
||||||
|
|
||||||
objSize = stats.m_objSize;
|
|
||||||
numUsedObj = stats.m_totalObjCount - stats.m_freeObjCount;
|
|
||||||
totalSize = stats.m_poolCount * stats.m_poolGrossSize;
|
|
||||||
netto = numUsedObj * objSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual PoolStatsSt* GetKsuffixSlabStats()
|
|
||||||
{
|
|
||||||
return m_ksuffixSlab->GetStats();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -344,8 +316,6 @@ public:
|
||||||
{
|
{
|
||||||
m_initialized = false;
|
m_initialized = false;
|
||||||
DestroyPools();
|
DestroyPools();
|
||||||
// remove masstree's root pointer (not valid anymore)
|
|
||||||
*(m_index.root_ref()) = nullptr;
|
|
||||||
|
|
||||||
return IndexInitImpl(NULL);
|
return IndexInitImpl(NULL);
|
||||||
}
|
}
|
||||||
|
|
@ -362,7 +332,7 @@ public:
|
||||||
* @param tag Hint to determine which pool to use.
|
* @param tag Hint to determine which pool to use.
|
||||||
* @return Pointer to allocated memory.
|
* @return Pointer to allocated memory.
|
||||||
*/
|
*/
|
||||||
virtual void* AllocateMem(int& size, enum memtag tag)
|
void* AllocateMem(int& size, enum memtag tag)
|
||||||
{
|
{
|
||||||
switch (tag) {
|
switch (tag) {
|
||||||
case memtag_masstree_leaf:
|
case memtag_masstree_leaf:
|
||||||
|
|
@ -390,7 +360,7 @@ public:
|
||||||
* @param Pointer to allocated memory.
|
* @param Pointer to allocated memory.
|
||||||
* @return True if deallocation succeeded.
|
* @return True if deallocation succeeded.
|
||||||
*/
|
*/
|
||||||
virtual bool DeallocateMem(void* ptr, int size, enum memtag tag)
|
bool DeallocateMem(void* ptr, int size, enum memtag tag)
|
||||||
{
|
{
|
||||||
switch (tag) {
|
switch (tag) {
|
||||||
case memtag_masstree_leaf:
|
case memtag_masstree_leaf:
|
||||||
|
|
@ -461,16 +431,10 @@ public:
|
||||||
{
|
{
|
||||||
// If dropIndex == true, all index's pools are going to be cleaned, so we skip the release here
|
// If dropIndex == true, all index's pools are going to be cleaned, so we skip the release here
|
||||||
mtSessionThreadInfo->set_gc_session(GetCurrentGcSession());
|
mtSessionThreadInfo->set_gc_session(GetCurrentGcSession());
|
||||||
GcEpochType local_epoch =
|
|
||||||
GetSessionManager()->GetCurrentSessionContext()->GetTxnManager()->GetGcSession()->GcStartInnerTxn();
|
|
||||||
|
|
||||||
size_t allocationSize = (*static_cast<mrcu_callback*>(gcRemoveLayerFuncObjPtr))(dropIndex);
|
size_t allocationSize = (*static_cast<mrcu_callback*>(gcRemoveLayerFuncObjPtr))(dropIndex);
|
||||||
|
|
||||||
if (dropIndex == false) {
|
if (dropIndex == false) {
|
||||||
((SlabAllocator*)slab)->Release(gcRemoveLayerFuncObjPtr, allocationSize);
|
((SlabAllocator*)slab)->Release(gcRemoveLayerFuncObjPtr, allocationSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
GetSessionManager()->GetCurrentSessionContext()->GetTxnManager()->GetGcSession()->GcEndInnerTxn(false);
|
|
||||||
mtSessionThreadInfo->set_gc_session(NULL);
|
mtSessionThreadInfo->set_gc_session(NULL);
|
||||||
return allocationSize;
|
return allocationSize;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -582,7 +582,6 @@ Row* Table::RemoveKeyFromIndex(Row* row, Sentinel* sentinel, uint64_t tid, GcMan
|
||||||
#endif
|
#endif
|
||||||
currSentinel = ix->IndexRemove(&key, tid);
|
currSentinel = ix->IndexRemove(&key, tid);
|
||||||
MOT_ASSERT(currSentinel == sentinel);
|
MOT_ASSERT(currSentinel == sentinel);
|
||||||
MOT_ASSERT(currSentinel->GetCounter() == 0);
|
|
||||||
if (likely(gc != nullptr)) {
|
if (likely(gc != nullptr)) {
|
||||||
if (ix->GetIndexOrder() == IndexOrder::INDEX_ORDER_PRIMARY) {
|
if (ix->GetIndexOrder() == IndexOrder::INDEX_ORDER_PRIMARY) {
|
||||||
OutputRow = currSentinel->GetData();
|
OutputRow = currSentinel->GetData();
|
||||||
|
|
|
||||||
|
|
@ -413,8 +413,6 @@ RC TxnManager::RollbackInsert(Access* ac)
|
||||||
#endif
|
#endif
|
||||||
outputSen = index_->IndexRemove(&m_key, GetThdId());
|
outputSen = index_->IndexRemove(&m_key, GetThdId());
|
||||||
MOT_ASSERT(outputSen != nullptr);
|
MOT_ASSERT(outputSen != nullptr);
|
||||||
MOT_ASSERT(outputSen->GetCounter() == 0);
|
|
||||||
|
|
||||||
GcSessionRecordRcu(index_->GetIndexId(), outputSen, nullptr, Index::SentinelDtor, SENTINEL_SIZE(index_));
|
GcSessionRecordRcu(index_->GetIndexId(), outputSen, nullptr, Index::SentinelDtor, SENTINEL_SIZE(index_));
|
||||||
// If we are the owner of the key and insert on top of a deleted row,
|
// If we are the owner of the key and insert on top of a deleted row,
|
||||||
// lets check if we can reclaim the deleted row
|
// lets check if we can reclaim the deleted row
|
||||||
|
|
@ -822,8 +820,6 @@ void TxnInsertAction::CleanupOptimisticInsert(
|
||||||
MOT_ASSERT(pIndexInsertResult->GetCounter() == 0);
|
MOT_ASSERT(pIndexInsertResult->GetCounter() == 0);
|
||||||
Sentinel* outputSen = index_->IndexRemove(currentItem->m_key, m_manager->GetThdId());
|
Sentinel* outputSen = index_->IndexRemove(currentItem->m_key, m_manager->GetThdId());
|
||||||
MOT_ASSERT(outputSen != nullptr);
|
MOT_ASSERT(outputSen != nullptr);
|
||||||
MOT_ASSERT(outputSen->GetCounter() == 0);
|
|
||||||
|
|
||||||
m_manager->GcSessionRecordRcu(
|
m_manager->GcSessionRecordRcu(
|
||||||
index_->GetIndexId(), outputSen, nullptr, Index::SentinelDtor, SENTINEL_SIZE(index_));
|
index_->GetIndexId(), outputSen, nullptr, Index::SentinelDtor, SENTINEL_SIZE(index_));
|
||||||
m_manager->m_accessMgr->IncreaseTableStat(table);
|
m_manager->m_accessMgr->IncreaseTableStat(table);
|
||||||
|
|
|
||||||
|
|
@ -255,14 +255,8 @@ void StartRemoteStreaming(const LibpqrcvConnectParam *options)
|
||||||
stringlist_to_identifierstr(t_thrd.libwalreceiver_cxt.streamConn, options->publicationNames);
|
stringlist_to_identifierstr(t_thrd.libwalreceiver_cxt.streamConn, options->publicationNames);
|
||||||
appendStringInfo(&cmd, ", publication_names %s",
|
appendStringInfo(&cmd, ", publication_names %s",
|
||||||
PQescapeLiteral(t_thrd.libwalreceiver_cxt.streamConn, pubnames_str, strlen(pubnames_str)));
|
PQescapeLiteral(t_thrd.libwalreceiver_cxt.streamConn, pubnames_str, strlen(pubnames_str)));
|
||||||
pfree(pubnames_str);
|
|
||||||
|
|
||||||
if (options->binary && PQserverVersion(t_thrd.libwalreceiver_cxt.streamConn) >= 90204) {
|
|
||||||
appendStringInfoString(&cmd, ", binary 'true'");
|
|
||||||
ereport(DEBUG5, (errmsg("append binary true")));
|
|
||||||
}
|
|
||||||
|
|
||||||
appendStringInfoChar(&cmd, ')');
|
appendStringInfoChar(&cmd, ')');
|
||||||
|
pfree(pubnames_str);
|
||||||
}
|
}
|
||||||
|
|
||||||
PGresult *res = libpqrcv_PQexec(cmd.data);
|
PGresult *res = libpqrcv_PQexec(cmd.data);
|
||||||
|
|
@ -426,7 +420,7 @@ void IdentifyRemoteSystem(bool checkRemote)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* identify remote mode, should do this after connect success. */
|
/* identify remote mode, should do this after connect success. */
|
||||||
ServerMode IdentifyRemoteMode()
|
static ServerMode IdentifyRemoteMode()
|
||||||
{
|
{
|
||||||
Assert(t_thrd.libwalreceiver_cxt.streamConn != NULL);
|
Assert(t_thrd.libwalreceiver_cxt.streamConn != NULL);
|
||||||
volatile WalRcvData *walrcv = t_thrd.walreceiverfuncs_cxt.WalRcv;
|
volatile WalRcvData *walrcv = t_thrd.walreceiverfuncs_cxt.WalRcv;
|
||||||
|
|
@ -449,9 +443,7 @@ ServerMode IdentifyRemoteMode()
|
||||||
num_fields)));
|
num_fields)));
|
||||||
}
|
}
|
||||||
remoteMode = (ServerMode)pg_strtoint32(PQgetvalue(res, 0, 0));
|
remoteMode = (ServerMode)pg_strtoint32(PQgetvalue(res, 0, 0));
|
||||||
if (walrcv->conn_target != REPCONNTARGET_PUBLICATION &&
|
if (!t_thrd.walreceiver_cxt.AmWalReceiverForFailover && (!IS_PRIMARY_NORMAL(remoteMode)) &&
|
||||||
!t_thrd.walreceiver_cxt.AmWalReceiverForFailover &&
|
|
||||||
(!IS_PRIMARY_NORMAL(remoteMode)) &&
|
|
||||||
/* remoteMode of cascade standby is a standby */
|
/* remoteMode of cascade standby is a standby */
|
||||||
!t_thrd.xlog_cxt.is_cascade_standby && !IS_SHARED_STORAGE_MODE) {
|
!t_thrd.xlog_cxt.is_cascade_standby && !IS_SHARED_STORAGE_MODE) {
|
||||||
PQclear(res);
|
PQclear(res);
|
||||||
|
|
|
||||||
|
|
@ -223,7 +223,6 @@ void LogicalDecodingProcessRecord(LogicalDecodingContext *ctx, XLogReaderState *
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ResourceOwner tmpOwner = t_thrd.utils_cxt.CurrentResourceOwner;
|
|
||||||
/* cast so we get a warning when new rmgrs are added */
|
/* cast so we get a warning when new rmgrs are added */
|
||||||
switch ((RmgrIds)XLogRecGetRmid(record)) {
|
switch ((RmgrIds)XLogRecGetRmid(record)) {
|
||||||
/*
|
/*
|
||||||
|
|
@ -258,7 +257,6 @@ void LogicalDecodingProcessRecord(LogicalDecodingContext *ctx, XLogReaderState *
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
t_thrd.utils_cxt.CurrentResourceOwner = tmpOwner;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@
|
||||||
#include "catalog/pg_type.h"
|
#include "catalog/pg_type.h"
|
||||||
#include "libpq/pqformat.h"
|
#include "libpq/pqformat.h"
|
||||||
#include "replication/logicalproto.h"
|
#include "replication/logicalproto.h"
|
||||||
|
#include "utils/builtins.h"
|
||||||
#include "utils/lsyscache.h"
|
#include "utils/lsyscache.h"
|
||||||
#include "utils/syscache.h"
|
#include "utils/syscache.h"
|
||||||
|
|
||||||
|
|
@ -27,7 +28,7 @@
|
||||||
static const int LOGICALREP_IS_REPLICA_IDENTITY = 1;
|
static const int LOGICALREP_IS_REPLICA_IDENTITY = 1;
|
||||||
|
|
||||||
static void logicalrep_write_attrs(StringInfo out, Relation rel);
|
static void logicalrep_write_attrs(StringInfo out, Relation rel);
|
||||||
static void logicalrep_write_tuple(StringInfo out, Relation rel, HeapTuple tuple, bool binary);
|
static void logicalrep_write_tuple(StringInfo out, Relation rel, HeapTuple tuple);
|
||||||
|
|
||||||
static void logicalrep_read_attrs(StringInfo in, LogicalRepRelation *rel);
|
static void logicalrep_read_attrs(StringInfo in, LogicalRepRelation *rel);
|
||||||
static void logicalrep_read_tuple(StringInfo in, LogicalRepTupleData *tuple);
|
static void logicalrep_read_tuple(StringInfo in, LogicalRepTupleData *tuple);
|
||||||
|
|
@ -114,7 +115,7 @@ void logicalrep_write_origin(StringInfo out, const char *origin, XLogRecPtr orig
|
||||||
/*
|
/*
|
||||||
* Write INSERT to the output stream.
|
* Write INSERT to the output stream.
|
||||||
*/
|
*/
|
||||||
void logicalrep_write_insert(StringInfo out, Relation rel, HeapTuple newtuple, bool binary)
|
void logicalrep_write_insert(StringInfo out, Relation rel, HeapTuple newtuple)
|
||||||
{
|
{
|
||||||
pq_sendbyte(out, 'I'); /* action INSERT */
|
pq_sendbyte(out, 'I'); /* action INSERT */
|
||||||
|
|
||||||
|
|
@ -122,7 +123,7 @@ void logicalrep_write_insert(StringInfo out, Relation rel, HeapTuple newtuple, b
|
||||||
pq_sendint32(out, RelationGetRelid(rel));
|
pq_sendint32(out, RelationGetRelid(rel));
|
||||||
|
|
||||||
pq_sendbyte(out, 'N'); /* new tuple follows */
|
pq_sendbyte(out, 'N'); /* new tuple follows */
|
||||||
logicalrep_write_tuple(out, rel, newtuple, binary);
|
logicalrep_write_tuple(out, rel, newtuple);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -150,7 +151,7 @@ LogicalRepRelId logicalrep_read_insert(StringInfo in, LogicalRepTupleData *newtu
|
||||||
/*
|
/*
|
||||||
* Write UPDATE to the output stream.
|
* Write UPDATE to the output stream.
|
||||||
*/
|
*/
|
||||||
void logicalrep_write_update(StringInfo out, Relation rel, HeapTuple oldtuple, HeapTuple newtuple, bool binary)
|
void logicalrep_write_update(StringInfo out, Relation rel, HeapTuple oldtuple, HeapTuple newtuple)
|
||||||
{
|
{
|
||||||
pq_sendbyte(out, 'U'); /* action UPDATE */
|
pq_sendbyte(out, 'U'); /* action UPDATE */
|
||||||
|
|
||||||
|
|
@ -165,11 +166,11 @@ void logicalrep_write_update(StringInfo out, Relation rel, HeapTuple oldtuple, H
|
||||||
pq_sendbyte(out, 'O'); /* old tuple follows */
|
pq_sendbyte(out, 'O'); /* old tuple follows */
|
||||||
else
|
else
|
||||||
pq_sendbyte(out, 'K'); /* old key follows */
|
pq_sendbyte(out, 'K'); /* old key follows */
|
||||||
logicalrep_write_tuple(out, rel, oldtuple, binary);
|
logicalrep_write_tuple(out, rel, oldtuple);
|
||||||
}
|
}
|
||||||
|
|
||||||
pq_sendbyte(out, 'N'); /* new tuple follows */
|
pq_sendbyte(out, 'N'); /* new tuple follows */
|
||||||
logicalrep_write_tuple(out, rel, newtuple, binary);
|
logicalrep_write_tuple(out, rel, newtuple);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -212,7 +213,7 @@ LogicalRepRelId logicalrep_read_update(StringInfo in, bool *has_oldtuple, Logica
|
||||||
/*
|
/*
|
||||||
* Write DELETE to the output stream.
|
* Write DELETE to the output stream.
|
||||||
*/
|
*/
|
||||||
void logicalrep_write_delete(StringInfo out, Relation rel, HeapTuple oldtuple, bool binary)
|
void logicalrep_write_delete(StringInfo out, Relation rel, HeapTuple oldtuple)
|
||||||
{
|
{
|
||||||
char relreplident = RelationGetRelReplident(rel);
|
char relreplident = RelationGetRelReplident(rel);
|
||||||
Assert(relreplident == REPLICA_IDENTITY_DEFAULT ||
|
Assert(relreplident == REPLICA_IDENTITY_DEFAULT ||
|
||||||
|
|
@ -228,7 +229,7 @@ void logicalrep_write_delete(StringInfo out, Relation rel, HeapTuple oldtuple, b
|
||||||
else
|
else
|
||||||
pq_sendbyte(out, 'K'); /* old key follows */
|
pq_sendbyte(out, 'K'); /* old key follows */
|
||||||
|
|
||||||
logicalrep_write_tuple(out, rel, oldtuple, binary);
|
logicalrep_write_tuple(out, rel, oldtuple);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -343,7 +344,7 @@ void logicalrep_read_typ(StringInfo in, LogicalRepTyp *ltyp)
|
||||||
/*
|
/*
|
||||||
* Write a tuple to the outputstream, in the most efficient format possible.
|
* Write a tuple to the outputstream, in the most efficient format possible.
|
||||||
*/
|
*/
|
||||||
static void logicalrep_write_tuple(StringInfo out, Relation rel, HeapTuple tuple, bool binary)
|
static void logicalrep_write_tuple(StringInfo out, Relation rel, HeapTuple tuple)
|
||||||
{
|
{
|
||||||
TupleDesc desc;
|
TupleDesc desc;
|
||||||
Datum values[MaxTupleAttributeNumber];
|
Datum values[MaxTupleAttributeNumber];
|
||||||
|
|
@ -370,6 +371,7 @@ static void logicalrep_write_tuple(StringInfo out, Relation rel, HeapTuple tuple
|
||||||
HeapTuple typtup;
|
HeapTuple typtup;
|
||||||
Form_pg_type typclass;
|
Form_pg_type typclass;
|
||||||
Form_pg_attribute att = desc->attrs[i];
|
Form_pg_attribute att = desc->attrs[i];
|
||||||
|
char *outputstr;
|
||||||
|
|
||||||
/* skip dropped columns */
|
/* skip dropped columns */
|
||||||
if (att->attisdropped || GetGeneratedCol(desc, i)) {
|
if (att->attisdropped || GetGeneratedCol(desc, i)) {
|
||||||
|
|
@ -377,7 +379,7 @@ static void logicalrep_write_tuple(StringInfo out, Relation rel, HeapTuple tuple
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isnull[i]) {
|
if (isnull[i]) {
|
||||||
pq_sendbyte(out, LOGICALREP_COLUMN_NULL); /* null column */
|
pq_sendbyte(out, 'n'); /* null column */
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -386,91 +388,61 @@ static void logicalrep_write_tuple(StringInfo out, Relation rel, HeapTuple tuple
|
||||||
elog(ERROR, "cache lookup failed for type %u", att->atttypid);
|
elog(ERROR, "cache lookup failed for type %u", att->atttypid);
|
||||||
typclass = (Form_pg_type)GETSTRUCT(typtup);
|
typclass = (Form_pg_type)GETSTRUCT(typtup);
|
||||||
|
|
||||||
/*
|
pq_sendbyte(out, 't'); /* 'text' data follows */
|
||||||
* Send in binary if requested and type has suitable send function.
|
if (!typclass->typbyval && typclass->typlen == -1) {
|
||||||
*/
|
/* definitely detoasted Datum */
|
||||||
if (binary && OidIsValid(typclass->typsend)) {
|
Datum val = PointerGetDatum(PG_DETOAST_DATUM(values[i]));
|
||||||
bytea* outputbytes = NULL;
|
outputstr = OidOutputFunctionCall(typclass->typoutput, val);
|
||||||
pq_sendbyte(out, LOGICALREP_COLUMN_BINARY);
|
|
||||||
if (!typclass->typbyval && typclass->typlen == -1) {
|
|
||||||
/* definitely detoasted Datum */
|
|
||||||
Datum val = PointerGetDatum(PG_DETOAST_DATUM(values[i]));
|
|
||||||
outputbytes = OidSendFunctionCall(typclass->typsend, val);
|
|
||||||
} else {
|
|
||||||
outputbytes = OidSendFunctionCall(typclass->typsend, values[i]);
|
|
||||||
}
|
|
||||||
int len = VARSIZE(outputbytes) - VARHDRSZ;
|
|
||||||
pq_sendint(out, len, 4); /* length */
|
|
||||||
pq_sendbytes(out, VARDATA(outputbytes), len); /* data */
|
|
||||||
if (outputbytes != NULL) {
|
|
||||||
pfree(outputbytes);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
char* outputstr = NULL;
|
outputstr = OidOutputFunctionCall(typclass->typoutput, values[i]);
|
||||||
pq_sendbyte(out, LOGICALREP_COLUMN_TEXT);
|
|
||||||
if (!typclass->typbyval && typclass->typlen == -1) {
|
|
||||||
/* definitely detoasted Datum */
|
|
||||||
Datum val = PointerGetDatum(PG_DETOAST_DATUM(values[i]));
|
|
||||||
outputstr = OidOutputFunctionCall(typclass->typoutput, val);
|
|
||||||
} else {
|
|
||||||
outputstr = OidOutputFunctionCall(typclass->typoutput, values[i]);
|
|
||||||
}
|
|
||||||
pq_sendcountedtext(out, outputstr, strlen(outputstr), false);
|
|
||||||
if (outputstr != NULL) {
|
|
||||||
pfree(outputstr);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
pq_sendcountedtext(out, outputstr, strlen(outputstr), false);
|
||||||
|
pfree(outputstr);
|
||||||
ReleaseSysCache(typtup);
|
ReleaseSysCache(typtup);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Read tuple in logical replication format from stream.
|
* Read tuple in remote format from stream.
|
||||||
|
*
|
||||||
|
* The returned tuple points into the input stringinfo.
|
||||||
*/
|
*/
|
||||||
static void logicalrep_read_tuple(StringInfo in, LogicalRepTupleData *tuple)
|
static void logicalrep_read_tuple(StringInfo in, LogicalRepTupleData *tuple)
|
||||||
{
|
{
|
||||||
/* Get number of attributes. */
|
uint16 i;
|
||||||
uint16 natts = pq_getmsgint(in, sizeof(uint16));
|
uint16 natts;
|
||||||
|
int rc;
|
||||||
|
|
||||||
/* Allocate space for per-column values; zero out unused StringInfoDatas */
|
/* Get number of attributes. */
|
||||||
tuple->colvalues = (StringInfoData *) palloc0(natts * sizeof(StringInfoData));
|
natts = pq_getmsgint(in, sizeof(uint16));
|
||||||
tuple->colstatus = (char *) palloc(natts * sizeof(char));
|
|
||||||
|
rc = memset_s(tuple->changed, sizeof(tuple->changed), 0, sizeof(tuple->changed));
|
||||||
|
securec_check(rc, "", "");
|
||||||
tuple->ncols = natts;
|
tuple->ncols = natts;
|
||||||
|
|
||||||
/* Read the data */
|
/* Read the data */
|
||||||
for (uint16 i = 0; i < natts; i++) {
|
for (i = 0; i < natts; i++) {
|
||||||
char kind = pq_getmsgbyte(in);
|
char kind;
|
||||||
tuple->colstatus[i] = kind;
|
|
||||||
uint32 len;
|
kind = pq_getmsgbyte(in);
|
||||||
StringInfo value = &tuple->colvalues[i];
|
|
||||||
|
|
||||||
switch (kind) {
|
switch (kind) {
|
||||||
case LOGICALREP_COLUMN_NULL: /* null */
|
case 'n': /* null */
|
||||||
/* nothing more to do */
|
tuple->values[i] = NULL;
|
||||||
|
tuple->changed[i] = true;
|
||||||
break;
|
break;
|
||||||
case LOGICALREP_COLUMN_TEXT:
|
case 't': { /* text formatted value */
|
||||||
len = pq_getmsgint(in, sizeof(uint32)); /* read length */
|
uint32 len;
|
||||||
|
tuple->changed[i] = true;
|
||||||
|
|
||||||
|
len = pq_getmsgint(in, sizeof(uint32)); /* read length */
|
||||||
|
|
||||||
/* and data */
|
/* and data */
|
||||||
value->data = (char *) palloc((len + 1) * sizeof(char));
|
tuple->values[i] = (char *)palloc(len + 1);
|
||||||
pq_copymsgbytes(in, value->data, len);
|
pq_copymsgbytes(in, tuple->values[i], len);
|
||||||
value->data[len] = '\0';
|
tuple->values[i][len] = '\0';
|
||||||
/* make StringInfo fully valid */
|
|
||||||
value->len = len;
|
|
||||||
value->cursor = 0;
|
|
||||||
value->maxlen = len;
|
|
||||||
break;
|
|
||||||
case LOGICALREP_COLUMN_BINARY:
|
|
||||||
len = pq_getmsgint(in, sizeof(uint32)); /* read length */
|
|
||||||
|
|
||||||
/* and data */
|
|
||||||
value->data = (char *)palloc0((len + 1) * sizeof(char));
|
|
||||||
pq_copymsgbytes(in, value->data, len);
|
|
||||||
/* make StringInfo fully valid */
|
|
||||||
value->len = len;
|
|
||||||
value->cursor = 0;
|
|
||||||
value->maxlen = len;
|
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
elog(ERROR, "unrecognized data representation type '%c'", kind);
|
elog(ERROR, "unrecognized data representation type '%c'", kind);
|
||||||
break;
|
break;
|
||||||
|
|
@ -479,7 +451,7 @@ static void logicalrep_read_tuple(StringInfo in, LogicalRepTupleData *tuple)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Write relation attributes metadata to the stream.
|
* Write relation attributes to the stream.
|
||||||
*/
|
*/
|
||||||
static void logicalrep_write_attrs(StringInfo out, Relation rel)
|
static void logicalrep_write_attrs(StringInfo out, Relation rel)
|
||||||
{
|
{
|
||||||
|
|
@ -532,7 +504,7 @@ static void logicalrep_write_attrs(StringInfo out, Relation rel)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Read relation attribute metadata from the stream.
|
* Read relation attribute names from the stream.
|
||||||
*/
|
*/
|
||||||
static void logicalrep_read_attrs(StringInfo in, LogicalRepRelation *rel)
|
static void logicalrep_read_attrs(StringInfo in, LogicalRepRelation *rel)
|
||||||
{
|
{
|
||||||
|
|
@ -601,25 +573,3 @@ static const char *logicalrep_read_namespace(StringInfo in)
|
||||||
|
|
||||||
return nspname;
|
return nspname;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Write conninfo to the output stream.
|
|
||||||
*/
|
|
||||||
void logicalrep_write_conninfo(StringInfo out, char* conninfo)
|
|
||||||
{
|
|
||||||
pq_sendbyte(out, 'S'); /* action */
|
|
||||||
|
|
||||||
pq_writestring(out, conninfo); /* conninfo follows */
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Read conninfo from stream.
|
|
||||||
*/
|
|
||||||
void logicalrep_read_conninfo(StringInfo in, char** conninfo)
|
|
||||||
{
|
|
||||||
const char* conninfoTemp = pq_getmsgstring(in);
|
|
||||||
size_t conninfoLen = strlen(conninfoTemp) + 1;
|
|
||||||
*conninfo = (char*)palloc(conninfoLen);
|
|
||||||
int rc = strcpy_s(*conninfo, conninfoLen, conninfoTemp);
|
|
||||||
securec_check(rc, "", "");
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,6 @@
|
||||||
#include "catalog/pg_partition_fn.h"
|
#include "catalog/pg_partition_fn.h"
|
||||||
|
|
||||||
#include "commands/trigger.h"
|
#include "commands/trigger.h"
|
||||||
#include "commands/subscriptioncmds.h"
|
|
||||||
|
|
||||||
#include "executor/executor.h"
|
#include "executor/executor.h"
|
||||||
#include "executor/node/nodeModifyTable.h"
|
#include "executor/node/nodeModifyTable.h"
|
||||||
|
|
@ -112,8 +111,6 @@ static void store_flush_position(XLogRecPtr remote_lsn);
|
||||||
static void reread_subscription(void);
|
static void reread_subscription(void);
|
||||||
static void ApplyWorkerProcessMsg(char type, StringInfo s, XLogRecPtr *lastRcv);
|
static void ApplyWorkerProcessMsg(char type, StringInfo s, XLogRecPtr *lastRcv);
|
||||||
static void apply_dispatch(StringInfo s);
|
static void apply_dispatch(StringInfo s);
|
||||||
static void apply_handle_conninfo(StringInfo s);
|
|
||||||
static void UpdateConninfo(char* standbysInfo);
|
|
||||||
|
|
||||||
/* SIGHUP: set flag to re-read config file at next convenient time */
|
/* SIGHUP: set flag to re-read config file at next convenient time */
|
||||||
static void LogicalrepWorkerSighub(SIGNAL_ARGS)
|
static void LogicalrepWorkerSighub(SIGNAL_ARGS)
|
||||||
|
|
@ -121,6 +118,18 @@ static void LogicalrepWorkerSighub(SIGNAL_ARGS)
|
||||||
t_thrd.applyworker_cxt.got_SIGHUP = true;
|
t_thrd.applyworker_cxt.got_SIGHUP = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* SIGTERM: time to die */
|
||||||
|
static void LogicalrepWorkerSigterm(SIGNAL_ARGS)
|
||||||
|
{
|
||||||
|
int saveErrno = errno;
|
||||||
|
|
||||||
|
t_thrd.applyworker_cxt.got_SIGTERM = true;
|
||||||
|
if (t_thrd.proc)
|
||||||
|
SetLatch(&t_thrd.proc->procLatch);
|
||||||
|
|
||||||
|
errno = saveErrno;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Make sure that we started local transaction.
|
* Make sure that we started local transaction.
|
||||||
*
|
*
|
||||||
|
|
@ -256,11 +265,11 @@ static void slot_store_error_callback(void *arg)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Store tuple data into slot.
|
* Store data in C string form into slot.
|
||||||
*
|
* This is similar to BuildTupleFromCStrings but TupleTableSlot fits our
|
||||||
* Incoming data can be either text or binary format.
|
* use better.
|
||||||
*/
|
*/
|
||||||
static void slot_store_data(TupleTableSlot *slot, LogicalRepRelMapEntry *rel, LogicalRepTupleData *tupleData)
|
static void slot_store_cstrings(TupleTableSlot *slot, LogicalRepRelMapEntry *rel, char **values)
|
||||||
{
|
{
|
||||||
int natts = slot->tts_tupleDescriptor->natts;
|
int natts = slot->tts_tupleDescriptor->natts;
|
||||||
int i;
|
int i;
|
||||||
|
|
@ -277,52 +286,19 @@ static void slot_store_data(TupleTableSlot *slot, LogicalRepRelMapEntry *rel, Lo
|
||||||
errcallback.previous = t_thrd.log_cxt.error_context_stack;
|
errcallback.previous = t_thrd.log_cxt.error_context_stack;
|
||||||
t_thrd.log_cxt.error_context_stack = &errcallback;
|
t_thrd.log_cxt.error_context_stack = &errcallback;
|
||||||
|
|
||||||
/* Call the "in" function for each non-dropped, non-null attribute */
|
/* Call the "in" function for each non-dropped attribute */
|
||||||
for (i = 0; i < natts; i++) {
|
for (i = 0; i < natts; i++) {
|
||||||
Form_pg_attribute att = slot->tts_tupleDescriptor->attrs[i];
|
Form_pg_attribute att = slot->tts_tupleDescriptor->attrs[i];
|
||||||
int remoteattnum = rel->attrmap[i];
|
int remoteattnum = rel->attrmap[i];
|
||||||
|
Oid typinput;
|
||||||
|
Oid typioparam;
|
||||||
|
|
||||||
if (!att->attisdropped && remoteattnum >= 0) {
|
if (!att->attisdropped && remoteattnum >= 0 && values[remoteattnum] != NULL) {
|
||||||
StringInfo colvalue = &tupleData->colvalues[remoteattnum];
|
|
||||||
errarg.remote_attnum = remoteattnum;
|
errarg.remote_attnum = remoteattnum;
|
||||||
|
|
||||||
if (tupleData->colstatus[remoteattnum] == LOGICALREP_COLUMN_TEXT) {
|
getTypeInputInfo(att->atttypid, &typinput, &typioparam);
|
||||||
Oid typinput;
|
slot->tts_values[i] = OidInputFunctionCall(typinput, values[remoteattnum], typioparam, att->atttypmod);
|
||||||
Oid typioparam;
|
slot->tts_isnull[i] = false;
|
||||||
|
|
||||||
getTypeInputInfo(att->atttypid, &typinput, &typioparam);
|
|
||||||
slot->tts_values[i] = OidInputFunctionCall(typinput, colvalue->data, typioparam, att->atttypmod);
|
|
||||||
slot->tts_isnull[i] = false;
|
|
||||||
} else if (tupleData->colstatus[remoteattnum] == LOGICALREP_COLUMN_BINARY) {
|
|
||||||
Oid typreceive;
|
|
||||||
Oid typioparam;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* In some code paths we may be asked to re-parse the same
|
|
||||||
* tuple data. Reset the StringInfo's cursor so that works.
|
|
||||||
*/
|
|
||||||
colvalue->cursor = 0;
|
|
||||||
|
|
||||||
getTypeBinaryInputInfo(att->atttypid, &typreceive, &typioparam);
|
|
||||||
slot->tts_values[i] = OidReceiveFunctionCall(typreceive, colvalue, typioparam, att->atttypmod);
|
|
||||||
|
|
||||||
/* Trouble if it didn't eat the whole buffer */
|
|
||||||
if (colvalue->cursor != colvalue->len) {
|
|
||||||
ereport(ERROR, (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
|
|
||||||
errmsg("incorrect binary data format in logical replication column %d",
|
|
||||||
remoteattnum + 1)));
|
|
||||||
}
|
|
||||||
slot->tts_isnull[i] = false;
|
|
||||||
} else {
|
|
||||||
/*
|
|
||||||
* NULL value from remote. (We don't expect to see
|
|
||||||
* LOGICALREP_COLUMN_UNCHANGED here, but if we do, treat it as
|
|
||||||
* NULL.)
|
|
||||||
*/
|
|
||||||
slot->tts_values[i] = (Datum) 0;
|
|
||||||
slot->tts_isnull[i] = true;
|
|
||||||
}
|
|
||||||
/* Reset attnum for error callback */
|
|
||||||
errarg.remote_attnum = -1;
|
errarg.remote_attnum = -1;
|
||||||
} else {
|
} else {
|
||||||
/*
|
/*
|
||||||
|
|
@ -342,19 +318,18 @@ static void slot_store_data(TupleTableSlot *slot, LogicalRepRelMapEntry *rel, Lo
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Replace updated columns with data from the LogicalRepTupleData struct.
|
* Replace selected columns with user data provided as C strings.
|
||||||
* This is somewhat similar to heap_modify_tuple but also calls the type
|
* This is somewhat similar to heap_modify_tuple but also calls the type
|
||||||
* input functions on the user data.
|
* input functions on the user data.
|
||||||
*
|
* "slot" is filled with a copy of the tuple in "srcslot", with
|
||||||
* "slot" is filled with a copy of the tuple in "srcslot", replacing
|
* columns selected by the "replaces" array replaced with data values
|
||||||
* columns provided in "tupleData" and leaving others as-is.
|
* from "values".
|
||||||
*
|
|
||||||
* Caution: unreplaced pass-by-ref columns in "slot" will point into the
|
* Caution: unreplaced pass-by-ref columns in "slot" will point into the
|
||||||
* storage for "srcslot". This is OK for current usage, but someday we may
|
* storage for "srcslot". This is OK for current usage, but someday we may
|
||||||
* need to materialize "slot" at the end to make it independent of "srcslot".
|
* need to materialize "slot" at the end to make it independent of "srcslot".
|
||||||
*/
|
*/
|
||||||
static void slot_modify_data(TupleTableSlot *slot, TupleTableSlot *srcslot, LogicalRepRelMapEntry *rel,
|
static void slot_modify_cstrings(TupleTableSlot *slot, TupleTableSlot *srcslot, LogicalRepRelMapEntry *rel,
|
||||||
LogicalRepTupleData *tupleData)
|
char **values, const bool *replaces)
|
||||||
{
|
{
|
||||||
int natts = slot->tts_tupleDescriptor->natts;
|
int natts = slot->tts_tupleDescriptor->natts;
|
||||||
int i;
|
int i;
|
||||||
|
|
@ -389,47 +364,23 @@ static void slot_modify_data(TupleTableSlot *slot, TupleTableSlot *srcslot, Logi
|
||||||
Form_pg_attribute att = slot->tts_tupleDescriptor->attrs[i];
|
Form_pg_attribute att = slot->tts_tupleDescriptor->attrs[i];
|
||||||
int remoteattnum = rel->attrmap[i];
|
int remoteattnum = rel->attrmap[i];
|
||||||
|
|
||||||
if (remoteattnum < 0) {
|
if (remoteattnum < 0 || !replaces[remoteattnum]) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tupleData->colstatus[remoteattnum] != LOGICALREP_COLUMN_UNCHANGED) {
|
if (values[remoteattnum] != NULL) {
|
||||||
StringInfo colvalue = &tupleData->colvalues[remoteattnum];
|
Oid typinput;
|
||||||
|
Oid typioparam;
|
||||||
|
|
||||||
errarg.remote_attnum = remoteattnum;
|
errarg.remote_attnum = remoteattnum;
|
||||||
|
|
||||||
if (tupleData->colstatus[remoteattnum] == LOGICALREP_COLUMN_TEXT) {
|
getTypeInputInfo(att->atttypid, &typinput, &typioparam);
|
||||||
Oid typinput;
|
slot->tts_values[i] = OidInputFunctionCall(typinput, values[remoteattnum], typioparam, att->atttypmod);
|
||||||
Oid typioparam;
|
slot->tts_isnull[i] = false;
|
||||||
|
|
||||||
getTypeInputInfo(att->atttypid, &typinput, &typioparam);
|
|
||||||
slot->tts_values[i] = OidInputFunctionCall(typinput, colvalue->data, typioparam, att->atttypmod);
|
|
||||||
slot->tts_isnull[i] = false;
|
|
||||||
} else if (tupleData->colstatus[remoteattnum] == LOGICALREP_COLUMN_BINARY) {
|
|
||||||
Oid typreceive;
|
|
||||||
Oid typioparam;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* In some code paths we may be asked to re-parse the same
|
|
||||||
* tuple data. Reset the StringInfo's cursor so that works.
|
|
||||||
*/
|
|
||||||
colvalue->cursor = 0;
|
|
||||||
|
|
||||||
getTypeBinaryInputInfo(att->atttypid, &typreceive, &typioparam);
|
|
||||||
slot->tts_values[i] = OidReceiveFunctionCall(typreceive, colvalue, typioparam, att->atttypmod);
|
|
||||||
|
|
||||||
/* Trouble if it didn't eat the whole buffer */
|
|
||||||
if (colvalue->cursor != colvalue->len) {
|
|
||||||
ereport(ERROR, (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
|
|
||||||
errmsg("incorrect binary data format in logical replication column %d", remoteattnum + 1)));
|
|
||||||
}
|
|
||||||
slot->tts_isnull[i] = false;
|
|
||||||
} else {
|
|
||||||
/* must be LOGICALREP_COLUMN_NULL */
|
|
||||||
slot->tts_values[i] = (Datum) 0;
|
|
||||||
slot->tts_isnull[i] = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
errarg.remote_attnum = -1;
|
errarg.remote_attnum = -1;
|
||||||
|
} else {
|
||||||
|
slot->tts_values[i] = (Datum)0;
|
||||||
|
slot->tts_isnull[i] = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -565,7 +516,7 @@ static void apply_handle_insert(StringInfo s)
|
||||||
PushActiveSnapshot(GetTransactionSnapshot());
|
PushActiveSnapshot(GetTransactionSnapshot());
|
||||||
/* Process and store remote tuple in the slot */
|
/* Process and store remote tuple in the slot */
|
||||||
oldctx = MemoryContextSwitchTo(GetPerTupleMemoryContext(estate));
|
oldctx = MemoryContextSwitchTo(GetPerTupleMemoryContext(estate));
|
||||||
slot_store_data(remoteslot, rel, &newtup);
|
slot_store_cstrings(remoteslot, rel, newtup.values);
|
||||||
slot_fill_defaults(rel, estate, remoteslot);
|
slot_fill_defaults(rel, estate, remoteslot);
|
||||||
MemoryContextSwitchTo(oldctx);
|
MemoryContextSwitchTo(oldctx);
|
||||||
|
|
||||||
|
|
@ -695,7 +646,7 @@ static void apply_handle_update(StringInfo s)
|
||||||
int remoteattnum = rel->attrmap[i];
|
int remoteattnum = rel->attrmap[i];
|
||||||
if (!att->attisdropped && remoteattnum >= 0) {
|
if (!att->attisdropped && remoteattnum >= 0) {
|
||||||
Assert(remoteattnum < newtup.ncols);
|
Assert(remoteattnum < newtup.ncols);
|
||||||
if (newtup.colstatus[i] != LOGICALREP_COLUMN_UNCHANGED) {
|
if (newtup.changed[i]) {
|
||||||
target_rte->updatedCols = bms_add_member(target_rte->updatedCols,
|
target_rte->updatedCols = bms_add_member(target_rte->updatedCols,
|
||||||
i + 1 - FirstLowInvalidHeapAttributeNumber);
|
i + 1 - FirstLowInvalidHeapAttributeNumber);
|
||||||
}
|
}
|
||||||
|
|
@ -709,7 +660,7 @@ static void apply_handle_update(StringInfo s)
|
||||||
|
|
||||||
/* Build the search tuple. */
|
/* Build the search tuple. */
|
||||||
oldctx = MemoryContextSwitchTo(GetPerTupleMemoryContext(estate));
|
oldctx = MemoryContextSwitchTo(GetPerTupleMemoryContext(estate));
|
||||||
slot_store_data(remoteslot, rel, has_oldtup ? &oldtup : &newtup);
|
slot_store_cstrings(remoteslot, rel, has_oldtup ? oldtup.values : newtup.values);
|
||||||
MemoryContextSwitchTo(oldctx);
|
MemoryContextSwitchTo(oldctx);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -732,7 +683,7 @@ static void apply_handle_update(StringInfo s)
|
||||||
if (found) {
|
if (found) {
|
||||||
/* Process and store remote tuple in the slot */
|
/* Process and store remote tuple in the slot */
|
||||||
oldctx = MemoryContextSwitchTo(GetPerTupleMemoryContext(estate));
|
oldctx = MemoryContextSwitchTo(GetPerTupleMemoryContext(estate));
|
||||||
slot_modify_data(remoteslot, localslot, rel, &newtup);
|
slot_modify_cstrings(remoteslot, localslot, rel, newtup.values, newtup.changed);
|
||||||
MemoryContextSwitchTo(oldctx);
|
MemoryContextSwitchTo(oldctx);
|
||||||
|
|
||||||
EvalPlanQualSetSlot(&epqstate, remoteslot);
|
EvalPlanQualSetSlot(&epqstate, remoteslot);
|
||||||
|
|
@ -797,7 +748,7 @@ static void apply_handle_delete(StringInfo s)
|
||||||
|
|
||||||
/* Find the tuple using the replica identity index. */
|
/* Find the tuple using the replica identity index. */
|
||||||
oldctx = MemoryContextSwitchTo(GetPerTupleMemoryContext(estate));
|
oldctx = MemoryContextSwitchTo(GetPerTupleMemoryContext(estate));
|
||||||
slot_store_data(remoteslot, rel, &oldtup);
|
slot_store_cstrings(remoteslot, rel, oldtup.values);
|
||||||
MemoryContextSwitchTo(oldctx);
|
MemoryContextSwitchTo(oldctx);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -873,9 +824,6 @@ static void apply_dispatch(StringInfo s)
|
||||||
case 'O':
|
case 'O':
|
||||||
apply_handle_origin(s);
|
apply_handle_origin(s);
|
||||||
break;
|
break;
|
||||||
case 'S':
|
|
||||||
apply_handle_conninfo(s);
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
ereport(ERROR, (errcode(ERRCODE_PROTOCOL_VIOLATION),
|
ereport(ERROR, (errcode(ERRCODE_PROTOCOL_VIOLATION),
|
||||||
errmsg("invalid logical replication message type \"%c\"", action)));
|
errmsg("invalid logical replication message type \"%c\"", action)));
|
||||||
|
|
@ -1056,15 +1004,13 @@ static void ApplyLoop(void)
|
||||||
/* mark as idle, before starting to loop */
|
/* mark as idle, before starting to loop */
|
||||||
pgstat_report_activity(STATE_IDLE, NULL);
|
pgstat_report_activity(STATE_IDLE, NULL);
|
||||||
|
|
||||||
for (;;) {
|
while (!t_thrd.applyworker_cxt.got_SIGTERM) {
|
||||||
MemoryContextSwitchTo(t_thrd.applyworker_cxt.messageContext);
|
MemoryContextSwitchTo(t_thrd.applyworker_cxt.messageContext);
|
||||||
|
|
||||||
int len;
|
int len;
|
||||||
char *buf = NULL;
|
char *buf = NULL;
|
||||||
unsigned char type;
|
unsigned char type;
|
||||||
|
|
||||||
CHECK_FOR_INTERRUPTS();
|
|
||||||
|
|
||||||
/* Wait a while for data to arrive */
|
/* Wait a while for data to arrive */
|
||||||
if ((WalReceiverFuncTable[GET_FUNC_IDX]).walrcv_receive(NAPTIME_PER_CYCLE, &type, &buf, &len)) {
|
if ((WalReceiverFuncTable[GET_FUNC_IDX]).walrcv_receive(NAPTIME_PER_CYCLE, &type, &buf, &len)) {
|
||||||
StringInfoData s;
|
StringInfoData s;
|
||||||
|
|
@ -1278,17 +1224,6 @@ static void reread_subscription(void)
|
||||||
proc_exit(0);
|
proc_exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Exit if any parameter that affects the remote connection was changed.
|
|
||||||
* The launcher will start a new worker.
|
|
||||||
*/
|
|
||||||
if (strcmp(newsub->name, t_thrd.applyworker_cxt.mySubscription->name) != 0 ||
|
|
||||||
newsub->binary != t_thrd.applyworker_cxt.mySubscription->binary) {
|
|
||||||
ereport(LOG, (errmsg("logical replication apply worker for subscription \"%s\" "
|
|
||||||
"will restart because of a parameter change", t_thrd.applyworker_cxt.mySubscription->name)));
|
|
||||||
proc_exit(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* !slotname should never happen when enabled is true. */
|
/* !slotname should never happen when enabled is true. */
|
||||||
Assert(newsub->slotname);
|
Assert(newsub->slotname);
|
||||||
|
|
||||||
|
|
@ -1361,7 +1296,7 @@ void ApplyWorkerMain()
|
||||||
*/
|
*/
|
||||||
gspqsignal(SIGHUP, LogicalrepWorkerSighub);
|
gspqsignal(SIGHUP, LogicalrepWorkerSighub);
|
||||||
gspqsignal(SIGINT, StatementCancelHandler);
|
gspqsignal(SIGINT, StatementCancelHandler);
|
||||||
gspqsignal(SIGTERM, die);
|
gspqsignal(SIGTERM, LogicalrepWorkerSigterm);
|
||||||
|
|
||||||
gspqsignal(SIGQUIT, quickdie);
|
gspqsignal(SIGQUIT, quickdie);
|
||||||
gspqsignal(SIGALRM, handle_sig_alarm);
|
gspqsignal(SIGALRM, handle_sig_alarm);
|
||||||
|
|
@ -1487,9 +1422,14 @@ void ApplyWorkerMain()
|
||||||
|
|
||||||
CommitTransactionCommand();
|
CommitTransactionCommand();
|
||||||
|
|
||||||
if (!AttemptConnectPublisher(t_thrd.applyworker_cxt.mySubscription->conninfo,
|
char *decryptConnInfo = DecryptConninfo(t_thrd.applyworker_cxt.mySubscription->conninfo);
|
||||||
t_thrd.applyworker_cxt.mySubscription->name, true)) {
|
bool connectSuccess = (WalReceiverFuncTable[GET_FUNC_IDX]).walrcv_connect(decryptConnInfo, NULL,
|
||||||
ereport(ERROR, (errcode(ERRCODE_CONNECTION_FAILURE), errmsg("Failed to connect to publisher.")));
|
t_thrd.applyworker_cxt.mySubscription->name, -1);
|
||||||
|
rc = memset_s(decryptConnInfo, strlen(decryptConnInfo), 0, strlen(decryptConnInfo));
|
||||||
|
securec_check(rc, "", "");
|
||||||
|
pfree_ext(decryptConnInfo);
|
||||||
|
if (!connectSuccess) {
|
||||||
|
ereport(ERROR, (errcode(ERRCODE_CONNECTION_FAILURE), errmsg("could not connect to the publisher")));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -1507,7 +1447,6 @@ void ApplyWorkerMain()
|
||||||
options.slotname = t_thrd.applyworker_cxt.mySubscription->slotname;
|
options.slotname = t_thrd.applyworker_cxt.mySubscription->slotname;
|
||||||
options.protoVersion = LOGICALREP_PROTO_VERSION_NUM;
|
options.protoVersion = LOGICALREP_PROTO_VERSION_NUM;
|
||||||
options.publicationNames = t_thrd.applyworker_cxt.mySubscription->publications;
|
options.publicationNames = t_thrd.applyworker_cxt.mySubscription->publications;
|
||||||
options.binary = t_thrd.applyworker_cxt.mySubscription->binary;
|
|
||||||
|
|
||||||
/* Start streaming from the slot. */
|
/* Start streaming from the slot. */
|
||||||
(WalReceiverFuncTable[GET_FUNC_IDX]).walrcv_startstreaming(&options);
|
(WalReceiverFuncTable[GET_FUNC_IDX]).walrcv_startstreaming(&options);
|
||||||
|
|
@ -1656,72 +1595,3 @@ char* DefListToString(const List *defList)
|
||||||
return buf.data;
|
return buf.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Handle conninfo update message.
|
|
||||||
*/
|
|
||||||
static void apply_handle_conninfo(StringInfo s)
|
|
||||||
{
|
|
||||||
char* standbysInfo = NULL;
|
|
||||||
logicalrep_read_conninfo(s, &standbysInfo);
|
|
||||||
UpdateConninfo(standbysInfo);
|
|
||||||
pfree_ext(standbysInfo);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void UpdateConninfo(char* standbysInfo)
|
|
||||||
{
|
|
||||||
Relation rel;
|
|
||||||
bool nulls[Natts_pg_subscription];
|
|
||||||
bool replaces[Natts_pg_subscription];
|
|
||||||
Datum values[Natts_pg_subscription];
|
|
||||||
HeapTuple tup;
|
|
||||||
Subscription* sub = t_thrd.applyworker_cxt.mySubscription;
|
|
||||||
Oid subid = sub->oid;
|
|
||||||
|
|
||||||
StartTransactionCommand();
|
|
||||||
rel = heap_open(SubscriptionRelationId, RowExclusiveLock);
|
|
||||||
/* Fetch the existing tuple. */
|
|
||||||
tup = SearchSysCacheCopy2(SUBSCRIPTIONNAME, u_sess->proc_cxt.MyDatabaseId,
|
|
||||||
CStringGetDatum(t_thrd.applyworker_cxt.mySubscription->name));
|
|
||||||
if (!HeapTupleIsValid(tup)) {
|
|
||||||
ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("subscription \"%s\" does not exist",
|
|
||||||
t_thrd.applyworker_cxt.mySubscription->name)));
|
|
||||||
}
|
|
||||||
subid = HeapTupleGetOid(tup);
|
|
||||||
|
|
||||||
/* Form a new tuple. */
|
|
||||||
int rc = memset_s(nulls, sizeof(nulls), false, sizeof(nulls));
|
|
||||||
securec_check(rc, "", "");
|
|
||||||
rc = memset_s(values, sizeof(values), 0, sizeof(values));
|
|
||||||
securec_check(rc, "", "");
|
|
||||||
rc = memset_s(replaces, sizeof(replaces), false, sizeof(replaces));
|
|
||||||
securec_check(rc, "", "");
|
|
||||||
|
|
||||||
/* get conninfoWithoutHostport */
|
|
||||||
StringInfoData conninfoWithoutHostport;
|
|
||||||
initStringInfo(&conninfoWithoutHostport);
|
|
||||||
ParseConninfo(sub->conninfo, &conninfoWithoutHostport, (HostPort**)NULL);
|
|
||||||
|
|
||||||
/* join conninfoWithoutHostport together with standbysinfo */
|
|
||||||
appendStringInfo(&conninfoWithoutHostport, " %s", standbysInfo);
|
|
||||||
/* Replace connection information */
|
|
||||||
values[Anum_pg_subscription_subconninfo - 1] = CStringGetTextDatum(conninfoWithoutHostport.data);
|
|
||||||
replaces[Anum_pg_subscription_subconninfo - 1] = true;
|
|
||||||
tup = heap_modify_tuple(tup, RelationGetDescr(rel), values, nulls, replaces);
|
|
||||||
|
|
||||||
/* Update the catalog. */
|
|
||||||
simple_heap_update(rel, &tup->t_self, tup);
|
|
||||||
CatalogUpdateIndexes(rel, tup);
|
|
||||||
|
|
||||||
heap_close(rel, RowExclusiveLock);
|
|
||||||
CommitTransactionCommand();
|
|
||||||
|
|
||||||
ereport(LOG, (errmsg("Update conninfo successfully, new conninfo %s.", standbysInfo)));
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Is current process a logical replication worker?
|
|
||||||
*/
|
|
||||||
bool IsLogicalWorker(void)
|
|
||||||
{
|
|
||||||
return t_thrd.applyworker_cxt.curWorker != NULL;
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -15,8 +15,6 @@
|
||||||
|
|
||||||
#include "catalog/pg_publication.h"
|
#include "catalog/pg_publication.h"
|
||||||
|
|
||||||
#include "commands/defrem.h"
|
|
||||||
|
|
||||||
#include "replication/logical.h"
|
#include "replication/logical.h"
|
||||||
#include "replication/logicalproto.h"
|
#include "replication/logicalproto.h"
|
||||||
#include "replication/origin.h"
|
#include "replication/origin.h"
|
||||||
|
|
@ -46,8 +44,6 @@ static bool pgoutput_origin_filter(LogicalDecodingContext *ctx, RepOriginId orig
|
||||||
|
|
||||||
static List *LoadPublications(List *pubnames);
|
static List *LoadPublications(List *pubnames);
|
||||||
static void publication_invalidation_cb(Datum arg, int cacheid, uint32 hashvalue);
|
static void publication_invalidation_cb(Datum arg, int cacheid, uint32 hashvalue);
|
||||||
static bool ReplconninfoChanged();
|
|
||||||
static void GetConninfo(StringInfoData* standbysInfo);
|
|
||||||
|
|
||||||
/* Entry in the map used to remember which relation schemas we sent. */
|
/* Entry in the map used to remember which relation schemas we sent. */
|
||||||
typedef struct RelationSyncEntry {
|
typedef struct RelationSyncEntry {
|
||||||
|
|
@ -83,9 +79,6 @@ static void parse_output_parameters(List *options, PGOutputData *data)
|
||||||
ListCell *lc;
|
ListCell *lc;
|
||||||
bool protocol_version_given = false;
|
bool protocol_version_given = false;
|
||||||
bool publication_names_given = false;
|
bool publication_names_given = false;
|
||||||
bool binary_option_given = false;
|
|
||||||
|
|
||||||
data->binary = false;
|
|
||||||
|
|
||||||
foreach (lc, options) {
|
foreach (lc, options) {
|
||||||
DefElem *defel = (DefElem *)lfirst(lc);
|
DefElem *defel = (DefElem *)lfirst(lc);
|
||||||
|
|
@ -115,12 +108,6 @@ static void parse_output_parameters(List *options, PGOutputData *data)
|
||||||
|
|
||||||
if (!SplitIdentifierString(strVal(defel->arg), ',', &(data->publication_names)))
|
if (!SplitIdentifierString(strVal(defel->arg), ',', &(data->publication_names)))
|
||||||
ereport(ERROR, (errcode(ERRCODE_INVALID_NAME), errmsg("invalid publication_names syntax")));
|
ereport(ERROR, (errcode(ERRCODE_INVALID_NAME), errmsg("invalid publication_names syntax")));
|
||||||
} else if (strcmp(defel->defname, "binary") == 0) {
|
|
||||||
if (binary_option_given)
|
|
||||||
ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("conflicting or redundant options")));
|
|
||||||
binary_option_given = true;
|
|
||||||
|
|
||||||
data->binary = defGetBoolean(defel);
|
|
||||||
} else
|
} else
|
||||||
elog(ERROR, "unrecognized pgoutput option: %s", defel->defname);
|
elog(ERROR, "unrecognized pgoutput option: %s", defel->defname);
|
||||||
}
|
}
|
||||||
|
|
@ -219,22 +206,6 @@ static void pgoutput_commit_txn(LogicalDecodingContext *ctx, ReorderBufferTXN *t
|
||||||
OutputPluginPrepareWrite(ctx, true);
|
OutputPluginPrepareWrite(ctx, true);
|
||||||
logicalrep_write_commit(ctx->out, txn, commit_lsn);
|
logicalrep_write_commit(ctx->out, txn, commit_lsn);
|
||||||
OutputPluginWrite(ctx, true);
|
OutputPluginWrite(ctx, true);
|
||||||
|
|
||||||
/*
|
|
||||||
* Send the newest connecttion information to the subscriber,
|
|
||||||
* when the connection information about the standby changes.
|
|
||||||
*/
|
|
||||||
if (ReplconninfoChanged()) {
|
|
||||||
StringInfoData standbysInfo;
|
|
||||||
initStringInfo(&standbysInfo);
|
|
||||||
|
|
||||||
GetConninfo(&standbysInfo);
|
|
||||||
OutputPluginPrepareWrite(ctx, true);
|
|
||||||
logicalrep_write_conninfo(ctx->out, standbysInfo.data);
|
|
||||||
OutputPluginWrite(ctx, true);
|
|
||||||
|
|
||||||
FreeStringInfo(&standbysInfo);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -329,19 +300,19 @@ static void pgoutput_change(LogicalDecodingContext *ctx, ReorderBufferTXN *txn,
|
||||||
switch (change->action) {
|
switch (change->action) {
|
||||||
case REORDER_BUFFER_CHANGE_INSERT:
|
case REORDER_BUFFER_CHANGE_INSERT:
|
||||||
OutputPluginPrepareWrite(ctx, true);
|
OutputPluginPrepareWrite(ctx, true);
|
||||||
logicalrep_write_insert(ctx->out, relation, &change->data.tp.newtuple->tuple, data->binary);
|
logicalrep_write_insert(ctx->out, relation, &change->data.tp.newtuple->tuple);
|
||||||
OutputPluginWrite(ctx, true);
|
OutputPluginWrite(ctx, true);
|
||||||
break;
|
break;
|
||||||
case REORDER_BUFFER_CHANGE_UINSERT:
|
case REORDER_BUFFER_CHANGE_UINSERT:
|
||||||
OutputPluginPrepareWrite(ctx, true);
|
OutputPluginPrepareWrite(ctx, true);
|
||||||
logicalrep_write_insert(ctx->out, relation, (HeapTuple)(&change->data.utp.newtuple->tuple), data->binary);
|
logicalrep_write_insert(ctx->out, relation, (HeapTuple)(&change->data.utp.newtuple->tuple));
|
||||||
OutputPluginWrite(ctx, true);
|
OutputPluginWrite(ctx, true);
|
||||||
break;
|
break;
|
||||||
case REORDER_BUFFER_CHANGE_UPDATE: {
|
case REORDER_BUFFER_CHANGE_UPDATE: {
|
||||||
HeapTuple oldtuple = change->data.tp.oldtuple ? &change->data.tp.oldtuple->tuple : NULL;
|
HeapTuple oldtuple = change->data.tp.oldtuple ? &change->data.tp.oldtuple->tuple : NULL;
|
||||||
|
|
||||||
OutputPluginPrepareWrite(ctx, true);
|
OutputPluginPrepareWrite(ctx, true);
|
||||||
logicalrep_write_update(ctx->out, relation, oldtuple, &change->data.tp.newtuple->tuple, data->binary);
|
logicalrep_write_update(ctx->out, relation, oldtuple, &change->data.tp.newtuple->tuple);
|
||||||
OutputPluginWrite(ctx, true);
|
OutputPluginWrite(ctx, true);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -349,14 +320,14 @@ static void pgoutput_change(LogicalDecodingContext *ctx, ReorderBufferTXN *txn,
|
||||||
HeapTuple oldtuple = change->data.utp.oldtuple ? ((HeapTuple)(&change->data.utp.oldtuple->tuple)) : NULL;
|
HeapTuple oldtuple = change->data.utp.oldtuple ? ((HeapTuple)(&change->data.utp.oldtuple->tuple)) : NULL;
|
||||||
|
|
||||||
OutputPluginPrepareWrite(ctx, true);
|
OutputPluginPrepareWrite(ctx, true);
|
||||||
logicalrep_write_update(ctx->out, relation, oldtuple, (HeapTuple)(&change->data.utp.newtuple->tuple), data->binary);
|
logicalrep_write_update(ctx->out, relation, oldtuple, (HeapTuple)(&change->data.utp.newtuple->tuple));
|
||||||
OutputPluginWrite(ctx, true);
|
OutputPluginWrite(ctx, true);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case REORDER_BUFFER_CHANGE_DELETE:
|
case REORDER_BUFFER_CHANGE_DELETE:
|
||||||
if (change->data.tp.oldtuple) {
|
if (change->data.tp.oldtuple) {
|
||||||
OutputPluginPrepareWrite(ctx, true);
|
OutputPluginPrepareWrite(ctx, true);
|
||||||
logicalrep_write_delete(ctx->out, relation, &change->data.tp.oldtuple->tuple, data->binary);
|
logicalrep_write_delete(ctx->out, relation, &change->data.tp.oldtuple->tuple);
|
||||||
OutputPluginWrite(ctx, true);
|
OutputPluginWrite(ctx, true);
|
||||||
} else
|
} else
|
||||||
elog(DEBUG1, "didn't send DELETE change because of missing oldtuple");
|
elog(DEBUG1, "didn't send DELETE change because of missing oldtuple");
|
||||||
|
|
@ -364,7 +335,7 @@ static void pgoutput_change(LogicalDecodingContext *ctx, ReorderBufferTXN *txn,
|
||||||
case REORDER_BUFFER_CHANGE_UDELETE:
|
case REORDER_BUFFER_CHANGE_UDELETE:
|
||||||
if (change->data.utp.oldtuple) {
|
if (change->data.utp.oldtuple) {
|
||||||
OutputPluginPrepareWrite(ctx, true);
|
OutputPluginPrepareWrite(ctx, true);
|
||||||
logicalrep_write_delete(ctx->out, relation, (HeapTuple)(&change->data.utp.oldtuple->tuple), data->binary);
|
logicalrep_write_delete(ctx->out, relation, (HeapTuple)(&change->data.utp.oldtuple->tuple));
|
||||||
OutputPluginWrite(ctx, true);
|
OutputPluginWrite(ctx, true);
|
||||||
} else
|
} else
|
||||||
elog(DEBUG1, "didn't send DELETE change because of missing oldtuple");
|
elog(DEBUG1, "didn't send DELETE change because of missing oldtuple");
|
||||||
|
|
@ -634,43 +605,3 @@ static void rel_sync_cache_publication_cb(Datum arg, int cacheid, uint32 hashval
|
||||||
entry->pubactions.pubdelete = false;
|
entry->pubactions.pubdelete = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void GetConninfo(StringInfoData* standbysInfo)
|
|
||||||
{
|
|
||||||
bool primaryJoined = false;
|
|
||||||
StringInfoData hosts;
|
|
||||||
StringInfoData ports;
|
|
||||||
initStringInfo(&hosts);
|
|
||||||
initStringInfo(&ports);
|
|
||||||
for (int i = 1; i < MAX_REPLNODE_NUM + 1; ++i) {
|
|
||||||
t_thrd.postmaster_cxt.ReplConnChangeType[i] = 0;
|
|
||||||
if (t_thrd.postmaster_cxt.ReplConnArray[i] == NULL) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (!primaryJoined) {
|
|
||||||
appendStringInfo(&hosts, "%s,%s",
|
|
||||||
t_thrd.postmaster_cxt.ReplConnArray[i]->localhost,
|
|
||||||
t_thrd.postmaster_cxt.ReplConnArray[i]->remotehost);
|
|
||||||
appendStringInfo(&ports, "%d,%d",
|
|
||||||
t_thrd.postmaster_cxt.ReplConnArray[i]->localport,
|
|
||||||
t_thrd.postmaster_cxt.ReplConnArray[i]->remoteport);
|
|
||||||
primaryJoined = true;
|
|
||||||
} else {
|
|
||||||
appendStringInfo(&hosts, ",%s",
|
|
||||||
t_thrd.postmaster_cxt.ReplConnArray[i]->remotehost);
|
|
||||||
appendStringInfo(&ports, ",%d",
|
|
||||||
t_thrd.postmaster_cxt.ReplConnArray[i]->remoteport);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
appendStringInfo(standbysInfo, "host=%s port=%s", hosts.data, ports.data);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline bool ReplconninfoChanged()
|
|
||||||
{
|
|
||||||
for (int i = 1; i < MAX_REPLNODE_NUM; ++i) {
|
|
||||||
if (t_thrd.postmaster_cxt.ReplConnChangeType[i]) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1934,18 +1934,14 @@ ArchiveConfig* formArchiveConfigFromStr(char *content, bool encrypted)
|
||||||
ArchiveConnConfig* conn_config = NULL;
|
ArchiveConnConfig* conn_config = NULL;
|
||||||
char* media_type = NULL;
|
char* media_type = NULL;
|
||||||
errno_t rc = EOK;
|
errno_t rc = EOK;
|
||||||
char *content_copy = NULL;
|
/* SplitIdentifierString will change origin string */
|
||||||
|
char *content_copy = pstrdup(content);
|
||||||
char *tmp = NULL;
|
char *tmp = NULL;
|
||||||
List* elemlist = NIL;
|
List* elemlist = NIL;
|
||||||
int param_num = 0;
|
int param_num = 0;
|
||||||
size_t elem_index = 0;
|
size_t elem_index = 0;
|
||||||
archive_config = (ArchiveConfig *)palloc0(sizeof(ArchiveConfig));
|
archive_config = (ArchiveConfig *)palloc0(sizeof(ArchiveConfig));
|
||||||
char decryptSecretAccessKeyStr[DEST_CIPHER_LENGTH] = {'\0'};
|
char decryptSecretAccessKeyStr[DEST_CIPHER_LENGTH] = {'\0'};
|
||||||
if (content == NULL || strlen(content) == 0) {
|
|
||||||
goto FAILURE;
|
|
||||||
}
|
|
||||||
/* SplitIdentifierString will change origin string */
|
|
||||||
content_copy = pstrdup(content);
|
|
||||||
/* Parse string into list of identifiers */
|
/* Parse string into list of identifiers */
|
||||||
if (!SplitIdentifierString(content_copy, ';', &elemlist, false, false)) {
|
if (!SplitIdentifierString(content_copy, ';', &elemlist, false, false)) {
|
||||||
goto FAILURE;
|
goto FAILURE;
|
||||||
|
|
|
||||||
|
|
@ -401,7 +401,6 @@ int WalSenderMain(void)
|
||||||
t_thrd.walsender_cxt.server_run_mode = t_thrd.postmaster_cxt.HaShmData->current_mode;
|
t_thrd.walsender_cxt.server_run_mode = t_thrd.postmaster_cxt.HaShmData->current_mode;
|
||||||
|
|
||||||
SetHaWalSenderChannel();
|
SetHaWalSenderChannel();
|
||||||
Assert(t_thrd.utils_cxt.CurrentResourceOwner != NULL);
|
|
||||||
/* Handle handshake messages before streaming */
|
/* Handle handshake messages before streaming */
|
||||||
WalSndHandshake();
|
WalSndHandshake();
|
||||||
|
|
||||||
|
|
@ -497,7 +496,6 @@ static void WalSndHandshake(void)
|
||||||
|
|
||||||
while (!repCxt.replicationStarted) {
|
while (!repCxt.replicationStarted) {
|
||||||
int firstchar;
|
int firstchar;
|
||||||
Assert(t_thrd.utils_cxt.CurrentResourceOwner != NULL);
|
|
||||||
|
|
||||||
WalSndSetState(WALSNDSTATE_STARTUP);
|
WalSndSetState(WALSNDSTATE_STARTUP);
|
||||||
set_ps_display("idle", false);
|
set_ps_display("idle", false);
|
||||||
|
|
@ -2035,8 +2033,6 @@ bool isLogicalSlotExist(char* slotName)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void IdentifyCommand(Node* cmd_node, ReplicationCxt* repCxt, const char *cmd_string){
|
static void IdentifyCommand(Node* cmd_node, ReplicationCxt* repCxt, const char *cmd_string){
|
||||||
ResourceOwner tmpOwner = t_thrd.utils_cxt.CurrentResourceOwner;
|
|
||||||
Assert(tmpOwner != NULL);
|
|
||||||
switch (cmd_node->type) {
|
switch (cmd_node->type) {
|
||||||
case T_IdentifySystemCmd:
|
case T_IdentifySystemCmd:
|
||||||
IdentifySystem();
|
IdentifySystem();
|
||||||
|
|
@ -2144,7 +2140,7 @@ static void IdentifyCommand(Node* cmd_node, ReplicationCxt* repCxt, const char *
|
||||||
ereport(FATAL,
|
ereport(FATAL,
|
||||||
(errcode(ERRCODE_PROTOCOL_VIOLATION), errmsg("invalid standby query string: %s", cmd_string)));
|
(errcode(ERRCODE_PROTOCOL_VIOLATION), errmsg("invalid standby query string: %s", cmd_string)));
|
||||||
}
|
}
|
||||||
t_thrd.utils_cxt.CurrentResourceOwner = tmpOwner;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -3600,12 +3596,8 @@ static int WalSndLoop(WalSndSendDataCallback send_data)
|
||||||
t_thrd.walsender_cxt.last_logical_xlog_advanced_timestamp = GetCurrentTimestamp();
|
t_thrd.walsender_cxt.last_logical_xlog_advanced_timestamp = GetCurrentTimestamp();
|
||||||
t_thrd.walsender_cxt.waiting_for_ping_response = false;
|
t_thrd.walsender_cxt.waiting_for_ping_response = false;
|
||||||
|
|
||||||
ResourceOwner tmpOwner = t_thrd.utils_cxt.CurrentResourceOwner;
|
|
||||||
Assert(!IsTransactionOrTransactionBlock() &&
|
|
||||||
strcmp(ResourceOwnerGetName(tmpOwner), "walsender top-level resource owner") == 0);
|
|
||||||
/* Loop forever, unless we get an error */
|
/* Loop forever, unless we get an error */
|
||||||
for (;;) {
|
for (;;) {
|
||||||
t_thrd.utils_cxt.CurrentResourceOwner = tmpOwner;
|
|
||||||
TimestampTz now;
|
TimestampTz now;
|
||||||
|
|
||||||
/* Clear any already-pending wakeups */
|
/* Clear any already-pending wakeups */
|
||||||
|
|
@ -4014,7 +4006,6 @@ static int WalSndLoop(WalSndSendDataCallback send_data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
t_thrd.utils_cxt.CurrentResourceOwner = tmpOwner;
|
|
||||||
WalSndShutdown();
|
WalSndShutdown();
|
||||||
return 1; /* keep the compiler quiet */
|
return 1; /* keep the compiler quiet */
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -394,6 +394,8 @@ void mdcreate(SMgrRelation reln, ForkNumber forkNum, bool isRedo)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fd < 0) {
|
if (fd < 0) {
|
||||||
|
int save_errno = errno;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* During bootstrap, there are cases where a system relation will be
|
* During bootstrap, there are cases where a system relation will be
|
||||||
* accessed (by internal backend processes) before the bootstrap
|
* accessed (by internal backend processes) before the bootstrap
|
||||||
|
|
@ -405,7 +407,26 @@ void mdcreate(SMgrRelation reln, ForkNumber forkNum, bool isRedo)
|
||||||
* new catalogs can by no means be used by other relations, we simply
|
* new catalogs can by no means be used by other relations, we simply
|
||||||
* truncate them.
|
* truncate them.
|
||||||
*/
|
*/
|
||||||
fd = RetryDataFileIdOpenFile(isRedo, path, filenode, flags);
|
if (isRedo || IsBootstrapProcessingMode() ||
|
||||||
|
(u_sess->attr.attr_common.IsInplaceUpgrade && filenode.rnode.node.relNode < FirstNormalObjectId)) {
|
||||||
|
ADIO_RUN()
|
||||||
|
{
|
||||||
|
flags = O_RDWR | PG_BINARY | O_DIRECT | (u_sess->attr.attr_common.IsInplaceUpgrade ? O_TRUNC : 0);
|
||||||
|
}
|
||||||
|
ADIO_ELSE()
|
||||||
|
{
|
||||||
|
flags = O_RDWR | PG_BINARY | (u_sess->attr.attr_common.IsInplaceUpgrade ? O_TRUNC : 0);
|
||||||
|
}
|
||||||
|
ADIO_END();
|
||||||
|
|
||||||
|
fd = DataFileIdOpenFile(path, filenode, flags, 0600);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fd < 0) {
|
||||||
|
/* be sure to report the error reported by create, not open */
|
||||||
|
errno = save_errno;
|
||||||
|
ereport(ERROR, (errcode_for_file_access(), errmsg("could not create file \"%s\": %m", path)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
File fd_pca = -1;
|
File fd_pca = -1;
|
||||||
|
|
|
||||||
|
|
@ -145,29 +145,6 @@ then
|
||||||
plat_form_str=ubuntu18.04_"$cpu_bit"
|
plat_form_str=ubuntu18.04_"$cpu_bit"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
##################################################################################
|
|
||||||
# the modification here will also lead to the synchronous modification of the 3rd-party compilation library path
|
|
||||||
# PR link : https://gitee.com/opengauss/openGauss-third_party/pulls/130
|
|
||||||
# redflag platform
|
|
||||||
# the result form like this: asianux_x86_64
|
|
||||||
##################################################################################
|
|
||||||
if [ "$kernel"x = "redflag"x ]
|
|
||||||
then
|
|
||||||
plat_form_str=asianux7.6_"$cpu_bit"
|
|
||||||
fi
|
|
||||||
|
|
||||||
|
|
||||||
##################################################################################
|
|
||||||
# the modification here will also lead to the synchronous modification of the 3rd-party compilation library path
|
|
||||||
# PR link : https://gitee.com/opengauss/openGauss-third_party/pulls/130
|
|
||||||
# asianux platform
|
|
||||||
# the result form like this: asianux_aarch64
|
|
||||||
##################################################################################
|
|
||||||
if [ "$kernel"x = "asianux"x ]
|
|
||||||
then
|
|
||||||
plat_form_str=asianux7.5_"$cpu_bit"
|
|
||||||
fi
|
|
||||||
|
|
||||||
##################################################################################
|
##################################################################################
|
||||||
#
|
#
|
||||||
# other platform
|
# other platform
|
||||||
|
|
|
||||||
|
|
@ -314,5 +314,4 @@ template<bool hasnull>
|
||||||
void UHeapFillDiskTuple(TupleDesc tupleDesc, Datum *values, const bool *isnull, UHeapDiskTupleData *diskTuple,
|
void UHeapFillDiskTuple(TupleDesc tupleDesc, Datum *values, const bool *isnull, UHeapDiskTupleData *diskTuple,
|
||||||
uint32 dataSize, bool enableReverseBitmap, bool enableReserve);
|
uint32 dataSize, bool enableReverseBitmap, bool enableReserve);
|
||||||
void CheckTupleValidity(Relation rel, UHeapTuple utuple);
|
void CheckTupleValidity(Relation rel, UHeapTuple utuple);
|
||||||
Tuple UHeapMaterialize(TupleTableSlot *slot);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -165,7 +165,7 @@ extern void addNewPartitionTuple(Relation pg_part_desc, Partition new_part_desc,
|
||||||
Datum interval, Datum maxValues, Datum transitionPoint, Datum reloptions);
|
Datum interval, Datum maxValues, Datum transitionPoint, Datum reloptions);
|
||||||
|
|
||||||
extern void heap_truncate_one_part(Relation rel , Oid partOid);
|
extern void heap_truncate_one_part(Relation rel , Oid partOid);
|
||||||
extern Oid heapTupleGetPartitionId(Relation rel, void *tuple, bool isDDL = false);
|
extern Oid heapTupleGetPartitionId(Relation rel, void *tuple);
|
||||||
extern Oid heapTupleGetSubPartitionId(Relation rel, void *tuple);
|
extern Oid heapTupleGetSubPartitionId(Relation rel, void *tuple);
|
||||||
extern void heap_truncate(List *relids);
|
extern void heap_truncate(List *relids);
|
||||||
extern void heap_truncate_one_rel(Relation rel);
|
extern void heap_truncate_one_rel(Relation rel);
|
||||||
|
|
@ -240,7 +240,7 @@ extern char* make_column_map(TupleDesc tuple_desc);
|
||||||
*/
|
*/
|
||||||
extern bool* CheckPartkeyHasTimestampwithzone(Relation partTableRel, bool isForSubPartition = false);
|
extern bool* CheckPartkeyHasTimestampwithzone(Relation partTableRel, bool isForSubPartition = false);
|
||||||
|
|
||||||
extern Oid AddNewIntervalPartition(Relation rel, void* insertTuple, bool isDDL = false);
|
extern Oid AddNewIntervalPartition(Relation rel, void* insertTuple);
|
||||||
|
|
||||||
extern int GetIndexKeyAttsByTuple(Relation relation, HeapTuple indexTuple);
|
extern int GetIndexKeyAttsByTuple(Relation relation, HeapTuple indexTuple);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -50,15 +50,13 @@ CATALOG(pg_subscription,6126) BKI_SHARED_RELATION BKI_ROWTYPE_OID(6128) BKI_SCHE
|
||||||
NameData subslotname; /* Slot name on publisher */
|
NameData subslotname; /* Slot name on publisher */
|
||||||
text subsynccommit; /* Synchronous commit setting for worker */
|
text subsynccommit; /* Synchronous commit setting for worker */
|
||||||
text subpublications[1]; /* List of publications subscribed to */
|
text subpublications[1]; /* List of publications subscribed to */
|
||||||
bool subbinary; /* True if the subscription wants the
|
|
||||||
* publisher to send data in binary */
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
FormData_pg_subscription;
|
FormData_pg_subscription;
|
||||||
|
|
||||||
typedef FormData_pg_subscription *Form_pg_subscription;
|
typedef FormData_pg_subscription *Form_pg_subscription;
|
||||||
|
|
||||||
#define Natts_pg_subscription 9
|
#define Natts_pg_subscription 8
|
||||||
#define Anum_pg_subscription_subdbid 1
|
#define Anum_pg_subscription_subdbid 1
|
||||||
#define Anum_pg_subscription_subname 2
|
#define Anum_pg_subscription_subname 2
|
||||||
#define Anum_pg_subscription_subowner 3
|
#define Anum_pg_subscription_subowner 3
|
||||||
|
|
@ -67,7 +65,6 @@ typedef FormData_pg_subscription *Form_pg_subscription;
|
||||||
#define Anum_pg_subscription_subslotname 6
|
#define Anum_pg_subscription_subslotname 6
|
||||||
#define Anum_pg_subscription_subsynccommit 7
|
#define Anum_pg_subscription_subsynccommit 7
|
||||||
#define Anum_pg_subscription_subpublications 8
|
#define Anum_pg_subscription_subpublications 8
|
||||||
#define Anum_pg_subscription_subbinary 9
|
|
||||||
|
|
||||||
|
|
||||||
typedef struct Subscription {
|
typedef struct Subscription {
|
||||||
|
|
@ -80,7 +77,6 @@ typedef struct Subscription {
|
||||||
char *slotname; /* Name of the replication slot */
|
char *slotname; /* Name of the replication slot */
|
||||||
char *synccommit; /* Synchronous commit setting for worker */
|
char *synccommit; /* Synchronous commit setting for worker */
|
||||||
List *publications; /* List of publication names to subscribe to */
|
List *publications; /* List of publication names to subscribe to */
|
||||||
bool binary; /* Indicates if the subscription wants data in binary format */
|
|
||||||
} Subscription;
|
} Subscription;
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -90,7 +86,6 @@ extern Oid get_subscription_oid(const char *subname, bool missing_ok);
|
||||||
extern char *get_subscription_name(Oid subid, bool missing_ok);
|
extern char *get_subscription_name(Oid subid, bool missing_ok);
|
||||||
|
|
||||||
extern int CountDBSubscriptions(Oid dbid);
|
extern int CountDBSubscriptions(Oid dbid);
|
||||||
extern void ClearListContent(List *list);
|
extern char *DecryptConninfo(char *encryptConninfo);
|
||||||
|
|
||||||
|
|
||||||
#endif /* PG_SUBSCRIPTION_H */
|
#endif /* PG_SUBSCRIPTION_H */
|
||||||
|
|
|
||||||
|
|
@ -17,11 +17,6 @@
|
||||||
|
|
||||||
#include "nodes/parsenodes.h"
|
#include "nodes/parsenodes.h"
|
||||||
|
|
||||||
typedef struct HostPort {
|
|
||||||
char* host;
|
|
||||||
char* port;
|
|
||||||
} HostPort;
|
|
||||||
|
|
||||||
extern ObjectAddress CreateSubscription(CreateSubscriptionStmt *stmt, bool isTopLevel);
|
extern ObjectAddress CreateSubscription(CreateSubscriptionStmt *stmt, bool isTopLevel);
|
||||||
extern ObjectAddress AlterSubscription(AlterSubscriptionStmt *stmt);
|
extern ObjectAddress AlterSubscription(AlterSubscriptionStmt *stmt);
|
||||||
extern void DropSubscription(DropSubscriptionStmt *stmt, bool isTopLevel);
|
extern void DropSubscription(DropSubscriptionStmt *stmt, bool isTopLevel);
|
||||||
|
|
@ -29,12 +24,6 @@ extern void DropSubscription(DropSubscriptionStmt *stmt, bool isTopLevel);
|
||||||
extern ObjectAddress AlterSubscriptionOwner(const char *name, Oid newOwnerId);
|
extern ObjectAddress AlterSubscriptionOwner(const char *name, Oid newOwnerId);
|
||||||
extern void AlterSubscriptionOwner_oid(Oid subid, Oid newOwnerId);
|
extern void AlterSubscriptionOwner_oid(Oid subid, Oid newOwnerId);
|
||||||
extern void RenameSubscription(List* oldname, const char* newname);
|
extern void RenameSubscription(List* oldname, const char* newname);
|
||||||
extern void AddStandbysInfo(char* standbysInfo);
|
|
||||||
extern void DropStandbysInfo(char* standbysInfo);
|
|
||||||
|
|
||||||
extern void ParseConninfo(const char* conninfo, StringInfoData* conninfoWithoutHostPort, HostPort** hostPortList);
|
|
||||||
extern char* EncryptOrDecryptConninfo(const char* conninfo, const char action);
|
|
||||||
extern bool AttemptConnectPublisher(const char *conninfoOriginal, char* slotname, bool checkRemoteMode);
|
|
||||||
|
|
||||||
#endif /* SUBSCRIPTIONCMDS_H */
|
#endif /* SUBSCRIPTIONCMDS_H */
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -238,7 +238,7 @@ typedef struct knl_session_attr_sql {
|
||||||
#ifndef ENABLE_MULTIPLE_NODES
|
#ifndef ENABLE_MULTIPLE_NODES
|
||||||
bool enable_custom_parser;
|
bool enable_custom_parser;
|
||||||
#endif
|
#endif
|
||||||
bool dolphin;
|
bool b_sql_plugin;
|
||||||
} knl_session_attr_sql;
|
} knl_session_attr_sql;
|
||||||
|
|
||||||
#endif /* SRC_INCLUDE_KNL_KNL_SESSION_ATTR_SQL */
|
#endif /* SRC_INCLUDE_KNL_KNL_SESSION_ATTR_SQL */
|
||||||
|
|
|
||||||
|
|
@ -90,7 +90,6 @@ extern const uint32 SUPPORT_DATA_REPAIR;
|
||||||
extern const uint32 SCAN_BATCH_MODE_VERSION_NUM;
|
extern const uint32 SCAN_BATCH_MODE_VERSION_NUM;
|
||||||
extern const uint32 RELMAP_4K_VERSION_NUM;
|
extern const uint32 RELMAP_4K_VERSION_NUM;
|
||||||
extern const uint32 PUBLICATION_VERSION_NUM;
|
extern const uint32 PUBLICATION_VERSION_NUM;
|
||||||
extern const uint32 SUBSCRIPTION_BINARY_VERSION_NUM;
|
|
||||||
extern const uint32 ANALYZER_HOOK_VERSION_NUM;
|
extern const uint32 ANALYZER_HOOK_VERSION_NUM;
|
||||||
extern const uint32 SUPPORT_HASH_XLOG_VERSION_NUM;
|
extern const uint32 SUPPORT_HASH_XLOG_VERSION_NUM;
|
||||||
extern const uint32 PITR_INIT_VERSION_NUM;
|
extern const uint32 PITR_INIT_VERSION_NUM;
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,6 @@ typedef struct LibpqrcvConnectParam {
|
||||||
bool logical;
|
bool logical;
|
||||||
uint32 protoVersion; /* Logical protocol version */
|
uint32 protoVersion; /* Logical protocol version */
|
||||||
List *publicationNames; /* String list of publications */
|
List *publicationNames; /* String list of publications */
|
||||||
bool binary; /* Ask publisher to use binary */
|
|
||||||
}LibpqrcvConnectParam;
|
}LibpqrcvConnectParam;
|
||||||
|
|
||||||
extern int32 pg_atoi(char* s, int size, int c);
|
extern int32 pg_atoi(char* s, int size, int c);
|
||||||
|
|
@ -54,6 +53,5 @@ extern bool libpqrcv_command(const char *cmd, char **err, int *sqlstate);
|
||||||
extern void IdentifyRemoteSystem(bool checkRemote);
|
extern void IdentifyRemoteSystem(bool checkRemote);
|
||||||
extern void CreateRemoteReplicationSlot(XLogRecPtr startpoint, const char* slotname, bool isLogical);
|
extern void CreateRemoteReplicationSlot(XLogRecPtr startpoint, const char* slotname, bool isLogical);
|
||||||
extern void StartRemoteStreaming(const LibpqrcvConnectParam *options);
|
extern void StartRemoteStreaming(const LibpqrcvConnectParam *options);
|
||||||
extern ServerMode IdentifyRemoteMode();
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,6 @@
|
||||||
#include "access/extreme_rto/spsc_blocking_queue.h"
|
#include "access/extreme_rto/spsc_blocking_queue.h"
|
||||||
#include "access/parallel_recovery/redo_item.h"
|
#include "access/parallel_recovery/redo_item.h"
|
||||||
|
|
||||||
#include "nodes/parsenodes_common.h"
|
|
||||||
#include "nodes/replnodes.h"
|
#include "nodes/replnodes.h"
|
||||||
#include "access/ustore/knl_utuple.h"
|
#include "access/ustore/knl_utuple.h"
|
||||||
#include "replication/logical_queue.h"
|
#include "replication/logical_queue.h"
|
||||||
|
|
|
||||||
|
|
@ -35,21 +35,12 @@
|
||||||
* Keep in mind that the columns correspond to the *remote* table.
|
* Keep in mind that the columns correspond to the *remote* table.
|
||||||
*/
|
*/
|
||||||
typedef struct LogicalRepTupleData {
|
typedef struct LogicalRepTupleData {
|
||||||
/* Array of StringInfos, one per column; some may be unused */
|
char *values[MaxTupleAttributeNumber]; /* value in out function format or NULL if values is NULL */
|
||||||
StringInfoData *colvalues;
|
bool changed[MaxTupleAttributeNumber]; /* marker for changed/unchanged values */
|
||||||
/* Array of markers for null/unchanged/text/binary, one per column */
|
|
||||||
char *colstatus;
|
|
||||||
/* Length of above arrays */
|
/* Length of above arrays */
|
||||||
int ncols;
|
int ncols;
|
||||||
} LogicalRepTupleData;
|
} LogicalRepTupleData;
|
||||||
|
|
||||||
/* Possible values for LogicalRepTupleData.colstatus[colnum] */
|
|
||||||
/* These values are also used in the on-the-wire protocol */
|
|
||||||
#define LOGICALREP_COLUMN_NULL 'n'
|
|
||||||
#define LOGICALREP_COLUMN_UNCHANGED 'u'
|
|
||||||
#define LOGICALREP_COLUMN_TEXT 't'
|
|
||||||
#define LOGICALREP_COLUMN_BINARY 'b' /* added in PG14 */
|
|
||||||
|
|
||||||
typedef uint32 LogicalRepRelId;
|
typedef uint32 LogicalRepRelId;
|
||||||
|
|
||||||
/* Relation information */
|
/* Relation information */
|
||||||
|
|
@ -90,18 +81,16 @@ extern void logicalrep_read_begin(StringInfo in, LogicalRepBeginData *begin_data
|
||||||
extern void logicalrep_write_commit(StringInfo out, ReorderBufferTXN *txn, XLogRecPtr commit_lsn);
|
extern void logicalrep_write_commit(StringInfo out, ReorderBufferTXN *txn, XLogRecPtr commit_lsn);
|
||||||
extern void logicalrep_read_commit(StringInfo in, LogicalRepCommitData *commit_data);
|
extern void logicalrep_read_commit(StringInfo in, LogicalRepCommitData *commit_data);
|
||||||
extern void logicalrep_write_origin(StringInfo out, const char *origin, XLogRecPtr origin_lsn);
|
extern void logicalrep_write_origin(StringInfo out, const char *origin, XLogRecPtr origin_lsn);
|
||||||
extern void logicalrep_write_insert(StringInfo out, Relation rel, HeapTuple newtuple, bool binary);
|
extern void logicalrep_write_insert(StringInfo out, Relation rel, HeapTuple newtuple);
|
||||||
extern LogicalRepRelId logicalrep_read_insert(StringInfo in, LogicalRepTupleData *newtup);
|
extern LogicalRepRelId logicalrep_read_insert(StringInfo in, LogicalRepTupleData *newtup);
|
||||||
extern void logicalrep_write_update(StringInfo out, Relation rel, HeapTuple oldtuple, HeapTuple newtuple, bool binary);
|
extern void logicalrep_write_update(StringInfo out, Relation rel, HeapTuple oldtuple, HeapTuple newtuple);
|
||||||
extern LogicalRepRelId logicalrep_read_update(StringInfo in, bool *has_oldtuple, LogicalRepTupleData *oldtup,
|
extern LogicalRepRelId logicalrep_read_update(StringInfo in, bool *has_oldtuple, LogicalRepTupleData *oldtup,
|
||||||
LogicalRepTupleData *newtup);
|
LogicalRepTupleData *newtup);
|
||||||
extern void logicalrep_write_delete(StringInfo out, Relation rel, HeapTuple oldtuple, bool binary);
|
extern void logicalrep_write_delete(StringInfo out, Relation rel, HeapTuple oldtuple);
|
||||||
extern LogicalRepRelId logicalrep_read_delete(StringInfo in, LogicalRepTupleData *oldtup);
|
extern LogicalRepRelId logicalrep_read_delete(StringInfo in, LogicalRepTupleData *oldtup);
|
||||||
extern void logicalrep_write_rel(StringInfo out, Relation rel);
|
extern void logicalrep_write_rel(StringInfo out, Relation rel);
|
||||||
extern LogicalRepRelation *logicalrep_read_rel(StringInfo in);
|
extern LogicalRepRelation *logicalrep_read_rel(StringInfo in);
|
||||||
extern void logicalrep_write_typ(StringInfo out, Oid typoid);
|
extern void logicalrep_write_typ(StringInfo out, Oid typoid);
|
||||||
extern void logicalrep_read_typ(StringInfo out, LogicalRepTyp *ltyp);
|
extern void logicalrep_read_typ(StringInfo out, LogicalRepTyp *ltyp);
|
||||||
extern void logicalrep_write_conninfo(StringInfo out, char* conninfo);
|
|
||||||
extern void logicalrep_read_conninfo(StringInfo in, char** conninfo);
|
|
||||||
|
|
||||||
#endif /* LOGICALREP_PROTO_H */
|
#endif /* LOGICALREP_PROTO_H */
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,5 @@
|
||||||
#define LOGICALWORKER_H
|
#define LOGICALWORKER_H
|
||||||
|
|
||||||
extern void ApplyWorkerMain();
|
extern void ApplyWorkerMain();
|
||||||
extern bool IsLogicalWorker(void);
|
|
||||||
|
|
||||||
#endif /* LOGICALWORKER_H */
|
#endif /* LOGICALWORKER_H */
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,6 @@ typedef struct PGOutputData {
|
||||||
|
|
||||||
List *publication_names;
|
List *publication_names;
|
||||||
List *publications;
|
List *publications;
|
||||||
bool binary;
|
|
||||||
} PGOutputData;
|
} PGOutputData;
|
||||||
|
|
||||||
#endif /* PGOUTPUT_H */
|
#endif /* PGOUTPUT_H */
|
||||||
|
|
|
||||||
|
|
@ -229,15 +229,10 @@ private:
|
||||||
bool m_syscache_relids[FirstNormalObjectId];
|
bool m_syscache_relids[FirstNormalObjectId];
|
||||||
|
|
||||||
};
|
};
|
||||||
void NotifyGscRecoveryStarted();
|
|
||||||
void NotifyGscRecoveryFinished();
|
void NotifyGscRecoveryFinished();
|
||||||
extern Datum gs_gsc_dbstat_info(PG_FUNCTION_ARGS);
|
extern Datum gs_gsc_dbstat_info(PG_FUNCTION_ARGS);
|
||||||
extern Datum gs_gsc_clean(PG_FUNCTION_ARGS);
|
extern Datum gs_gsc_clean(PG_FUNCTION_ARGS);
|
||||||
extern Datum gs_gsc_catalog_detail(PG_FUNCTION_ARGS);
|
extern Datum gs_gsc_catalog_detail(PG_FUNCTION_ARGS);
|
||||||
extern Datum gs_gsc_table_detail(PG_FUNCTION_ARGS);
|
extern Datum gs_gsc_table_detail(PG_FUNCTION_ARGS);
|
||||||
extern int ResizeHashBucket(int origin_nbucket, DynamicHashBucketStrategy strategy);
|
extern int ResizeHashBucket(int origin_nbucket, DynamicHashBucketStrategy strategy);
|
||||||
|
|
||||||
/* only primary node check recovery, recovery from upgrade may have misorder cacheids */
|
|
||||||
#define IsPrimaryRecoveryFinished() \
|
|
||||||
(g_instance.global_sysdbcache.recovery_finished || t_thrd.postmaster_cxt.HaShmData->current_mode == STANDBY_MODE)
|
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -213,7 +213,7 @@ extern bool check_rel_is_partitioned(Oid relid);
|
||||||
extern Oid partid_get_parentid(Oid partid);
|
extern Oid partid_get_parentid(Oid partid);
|
||||||
extern bool is_not_strict_agg(Oid funcOid);
|
extern bool is_not_strict_agg(Oid funcOid);
|
||||||
extern bool is_pgxc_class_table(Oid tableoid);
|
extern bool is_pgxc_class_table(Oid tableoid);
|
||||||
extern Oid get_valid_relname_relid(const char* relnamespace, const char* relname, bool nsp_missing_ok = false);
|
extern Oid get_valid_relname_relid(const char* relnamespace, const char* relname);
|
||||||
extern bool get_func_iswindow(Oid funcid);
|
extern bool get_func_iswindow(Oid funcid);
|
||||||
extern char get_func_prokind(Oid funcid);
|
extern char get_func_prokind(Oid funcid);
|
||||||
extern char get_typecategory(Oid typid);
|
extern char get_typecategory(Oid typid);
|
||||||
|
|
|
||||||
|
|
@ -1385,8 +1385,6 @@ typedef struct PlDebugEntry {
|
||||||
PLpgSQL_function* func;
|
PLpgSQL_function* func;
|
||||||
} PlDebugEntry;
|
} PlDebugEntry;
|
||||||
|
|
||||||
typedef List* (*RawParserHook)(const char*, List**);
|
|
||||||
|
|
||||||
const int MAXINT8LEN = 25;
|
const int MAXINT8LEN = 25;
|
||||||
const int DEFAULT_DEBUG_BUF_SIZE = 1024;
|
const int DEFAULT_DEBUG_BUF_SIZE = 1024;
|
||||||
const long NANOSECOND_PER_SECOND = 1000000000L; /* 1s */
|
const long NANOSECOND_PER_SECOND = 1000000000L; /* 1s */
|
||||||
|
|
|
||||||
|
|
@ -1,37 +0,0 @@
|
||||||
--
|
|
||||||
-- check for over-optimization of whole-row Var referencing an Append plan
|
|
||||||
--
|
|
||||||
create table int4_test(f1 int4);
|
|
||||||
select (select q from (select 1,2,3 where f1>0 union all select 4,5,6 where f1<=0) q) from int4_test;
|
|
||||||
q
|
|
||||||
---
|
|
||||||
(0 rows)
|
|
||||||
|
|
||||||
select (select q from (select 1,2,3 where f1>0 union all select 4,5,6.0 where f1<=0) q) from int4_test;
|
|
||||||
q
|
|
||||||
---
|
|
||||||
(0 rows)
|
|
||||||
|
|
||||||
insert into int4_test(f1) values(' 0 ');
|
|
||||||
insert into int4_test(f1) values('123456 ');
|
|
||||||
select * from int4_test;
|
|
||||||
f1
|
|
||||||
--------
|
|
||||||
0
|
|
||||||
123456
|
|
||||||
(2 rows)
|
|
||||||
|
|
||||||
select (select q from (select 1,2,3 where f1>0 union all select 4,5,6 where f1<=0) q) from int4_test;
|
|
||||||
q
|
|
||||||
---------
|
|
||||||
(4,5,6)
|
|
||||||
(1,2,3)
|
|
||||||
(2 rows)
|
|
||||||
|
|
||||||
select (select q from (select 1,2,3 where f1>0 union all select 4,5,6.0 where f1<=0) q) from int4_test;
|
|
||||||
q
|
|
||||||
-----------
|
|
||||||
(4,5,6.0)
|
|
||||||
(1,2,3)
|
|
||||||
(2 rows)
|
|
||||||
|
|
||||||
|
|
@ -1,116 +0,0 @@
|
||||||
create schema deserialize_func1;
|
|
||||||
set current_schema = deserialize_func1;
|
|
||||||
create sequence test_seq;
|
|
||||||
create or replace function test_func() return int
|
|
||||||
as
|
|
||||||
begin
|
|
||||||
return 1;
|
|
||||||
end;
|
|
||||||
/
|
|
||||||
create table t1(key int, id int default nextval('test_seq'));
|
|
||||||
create table t2(key int, id int default test_func());
|
|
||||||
select * from pg_get_tabledef('deserialize_func1.t1');
|
|
||||||
pg_get_tabledef
|
|
||||||
------------------------------------------------------
|
|
||||||
SET search_path = deserialize_func1; +
|
|
||||||
CREATE TABLE t1 ( +
|
|
||||||
key integer, +
|
|
||||||
id integer DEFAULT nextval('test_seq'::regclass)+
|
|
||||||
) +
|
|
||||||
WITH (orientation=row, compression=no);
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
select * from pg_get_tabledef('deserialize_func1.t2');
|
|
||||||
pg_get_tabledef
|
|
||||||
-----------------------------------------
|
|
||||||
SET search_path = deserialize_func1; +
|
|
||||||
CREATE TABLE t2 ( +
|
|
||||||
key integer, +
|
|
||||||
id integer DEFAULT test_func() +
|
|
||||||
) +
|
|
||||||
WITH (orientation=row, compression=no);
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
alter schema deserialize_func1 rename to deserialize_func2;
|
|
||||||
select * from pg_get_tabledef('deserialize_func2.t1');
|
|
||||||
pg_get_tabledef
|
|
||||||
------------------------------------------------------------------------
|
|
||||||
SET search_path = deserialize_func2; +
|
|
||||||
CREATE TABLE t1 ( +
|
|
||||||
key integer, +
|
|
||||||
id integer DEFAULT nextval('deserialize_func2.test_seq'::regclass)+
|
|
||||||
) +
|
|
||||||
WITH (orientation=row, compression=no);
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
select * from pg_get_tabledef('deserialize_func2.t2');
|
|
||||||
pg_get_tabledef
|
|
||||||
------------------------------------------------------
|
|
||||||
SET search_path = deserialize_func2; +
|
|
||||||
CREATE TABLE t2 ( +
|
|
||||||
key integer, +
|
|
||||||
id integer DEFAULT deserialize_func2.test_func()+
|
|
||||||
) +
|
|
||||||
WITH (orientation=row, compression=no);
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
alter table deserialize_func2.t1 alter column id drop default;
|
|
||||||
alter table deserialize_func2.t1 alter column id set default nextval('deserialize_func2.test_seq');
|
|
||||||
select * from pg_get_tabledef('deserialize_func2.t1');
|
|
||||||
pg_get_tabledef
|
|
||||||
------------------------------------------------------------------------
|
|
||||||
SET search_path = deserialize_func2; +
|
|
||||||
CREATE TABLE t1 ( +
|
|
||||||
key integer, +
|
|
||||||
id integer DEFAULT nextval('deserialize_func2.test_seq'::regclass)+
|
|
||||||
) +
|
|
||||||
WITH (orientation=row, compression=no);
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
alter table deserialize_func2.t2 alter column id drop default;
|
|
||||||
alter table deserialize_func2.t2 alter column id set default deserialize_func2.test_func();
|
|
||||||
select * from pg_get_tabledef('deserialize_func2.t2');
|
|
||||||
pg_get_tabledef
|
|
||||||
------------------------------------------------------
|
|
||||||
SET search_path = deserialize_func2; +
|
|
||||||
CREATE TABLE t2 ( +
|
|
||||||
key integer, +
|
|
||||||
id integer DEFAULT deserialize_func2.test_func()+
|
|
||||||
) +
|
|
||||||
WITH (orientation=row, compression=no);
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
set current_schema = deserialize_func2;
|
|
||||||
create type type1 as (a int);
|
|
||||||
create view v1 as select '(1)'::type1;
|
|
||||||
alter type type1 rename to type2;
|
|
||||||
select pg_get_viewdef('v1');
|
|
||||||
pg_get_viewdef
|
|
||||||
-------------------------------
|
|
||||||
SELECT '(1)'::type2 AS type1;
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
drop view v1 cascade;
|
|
||||||
create table atest12 as select x as a, 10001-x as b from generate_series(1, 10000) x;
|
|
||||||
create function func1(integer, integer) returns boolean as $$begin return $1 < $2; end $$ language plpgsql immutable;
|
|
||||||
create operator <<< (procedure=func1, leftarg=integer, rightarg=integer, restrict=scalarltsel);
|
|
||||||
create view atest12v as select * from atest12 where b <<< 5;
|
|
||||||
select pg_get_viewdef('atest12v');
|
|
||||||
pg_get_viewdef
|
|
||||||
-------------------------------------------------
|
|
||||||
SELECT * FROM atest12 WHERE (atest12.b <<< 5);
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
drop schema if exists deserialize_func1 cascade;
|
|
||||||
NOTICE: schema "deserialize_func1" does not exist, skipping
|
|
||||||
drop schema if exists deserialize_func2 cascade;
|
|
||||||
NOTICE: drop cascades to 9 other objects
|
|
||||||
DETAIL: drop cascades to sequence test_seq
|
|
||||||
drop cascades to function test_func()
|
|
||||||
drop cascades to table t1
|
|
||||||
drop cascades to table t2
|
|
||||||
drop cascades to type type2
|
|
||||||
drop cascades to table atest12
|
|
||||||
drop cascades to function func1(integer,integer)
|
|
||||||
drop cascades to operator <<<(integer,integer)
|
|
||||||
drop cascades to view atest12v
|
|
||||||
|
|
@ -132,14 +132,11 @@ DROP EXTENSION test_extension_exists;
|
||||||
ERROR: extension "test_extension_exists" does not exist
|
ERROR: extension "test_extension_exists" does not exist
|
||||||
DROP EXTENSION IF EXISTS test_extension_exists;
|
DROP EXTENSION IF EXISTS test_extension_exists;
|
||||||
NOTICE: extension "test_extension_exists" does not exist, skipping
|
NOTICE: extension "test_extension_exists" does not exist, skipping
|
||||||
-- only extension in white list support drop, but the guc support_extended_features is true in pg_regress mode, so hdfs_fdw can be droped
|
-- exists but doesn't support drop
|
||||||
CREATE DATABASE ext_test_db;
|
DROP EXTENSION plpgsql;
|
||||||
\c ext_test_db
|
ERROR: EXTENSION is not yet supported.
|
||||||
DROP EXTENSION hdfs_fdw;
|
DROP EXTENSION IF EXISTS plpgsql;
|
||||||
DROP EXTENSION IF EXISTS hdfs_fdw;
|
ERROR: EXTENSION is not yet supported.
|
||||||
NOTICE: extension "hdfs_fdw" does not exist, skipping
|
|
||||||
\c regression
|
|
||||||
DROP DATABASE ext_test_db;
|
|
||||||
-- functions
|
-- functions
|
||||||
DROP FUNCTION test_function_exists();
|
DROP FUNCTION test_function_exists();
|
||||||
ERROR: function test_function_exists does not exist
|
ERROR: function test_function_exists does not exist
|
||||||
|
|
|
||||||
|
|
@ -215,107 +215,3 @@ select * from interval_normal_exchange where logdate > '2020-06-01' order by log
|
||||||
(0 rows)
|
(0 rows)
|
||||||
|
|
||||||
drop table interval_normal_exchange;
|
drop table interval_normal_exchange;
|
||||||
drop table table_001;
|
|
||||||
ERROR: table "table_001" does not exist
|
|
||||||
create table table_001(
|
|
||||||
COL_1 smallint,
|
|
||||||
COL_2 char(5),
|
|
||||||
COL_3 int,
|
|
||||||
COL_4 date,
|
|
||||||
COL_5 boolean,
|
|
||||||
COL_6 nchar(5),
|
|
||||||
COL_7 float
|
|
||||||
);
|
|
||||||
drop table partition_table_001;
|
|
||||||
ERROR: table "partition_table_001" does not exist
|
|
||||||
create table partition_table_001(
|
|
||||||
COL_1 smallint,
|
|
||||||
COL_2 char(5),
|
|
||||||
COL_3 int,
|
|
||||||
COL_4 date,
|
|
||||||
COL_5 boolean,
|
|
||||||
COL_6 nchar(5),
|
|
||||||
COL_7 float
|
|
||||||
)
|
|
||||||
PARTITION BY RANGE (COL_4)
|
|
||||||
INTERVAL ('1 month')
|
|
||||||
(
|
|
||||||
PARTITION partition_table_001_p1 VALUES LESS THAN ('2020-03-01'),
|
|
||||||
PARTITION partition_table_001_p2 VALUES LESS THAN ('2020-04-01'),
|
|
||||||
PARTITION partition_table_001_p3 VALUES LESS THAN ('2020-05-01')
|
|
||||||
);
|
|
||||||
insert into partition_table_001 values (1,'aaa',1,'2020-02-23',true,'aaa',1.1);
|
|
||||||
insert into partition_table_001 values (2,'bbb',2,'2020-03-23',false,'bbb',2.2);
|
|
||||||
insert into partition_table_001 values (3,'ccc',3,'2020-04-23',true,'ccc',3.3);
|
|
||||||
insert into partition_table_001 values (4,'ddd',4,'2020-05-23',false,'ddd',4.4);
|
|
||||||
insert into partition_table_001 values (5,'eee',5,'2020-06-23',true,'eee',5.5);
|
|
||||||
insert into partition_table_001 values (6,'fff',6,'2020-07-23',false,'fff',6.6);
|
|
||||||
ALTER TABLE partition_table_001 EXCHANGE PARTITION (sys_p1) WITH TABLE table_001;
|
|
||||||
select * from table_001 order by 1;
|
|
||||||
col_1 | col_2 | col_3 | col_4 | col_5 | col_6 | col_7
|
|
||||||
-------+-------+-------+--------------------------+-------+-------+-------
|
|
||||||
4 | ddd | 4 | Sat May 23 00:00:00 2020 | f | ddd | 4.4
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
select * from partition_table_001 order by 1;
|
|
||||||
col_1 | col_2 | col_3 | col_4 | col_5 | col_6 | col_7
|
|
||||||
-------+-------+-------+--------------------------+-------+-------+-------
|
|
||||||
1 | aaa | 1 | Sun Feb 23 00:00:00 2020 | t | aaa | 1.1
|
|
||||||
2 | bbb | 2 | Mon Mar 23 00:00:00 2020 | f | bbb | 2.2
|
|
||||||
3 | ccc | 3 | Thu Apr 23 00:00:00 2020 | t | ccc | 3.3
|
|
||||||
5 | eee | 5 | Tue Jun 23 00:00:00 2020 | t | eee | 5.5
|
|
||||||
6 | fff | 6 | Thu Jul 23 00:00:00 2020 | f | fff | 6.6
|
|
||||||
(5 rows)
|
|
||||||
|
|
||||||
select relname, parttype, partstrategy, boundaries from pg_partition
|
|
||||||
where parentid = (select oid from pg_class where relname = 'partition_table_001')
|
|
||||||
order by relname;
|
|
||||||
relname | parttype | partstrategy | boundaries
|
|
||||||
------------------------+----------+--------------+------------------------------
|
|
||||||
partition_table_001 | r | i |
|
|
||||||
partition_table_001_p1 | p | r | {2020-03-01}
|
|
||||||
partition_table_001_p2 | p | r | {2020-04-01}
|
|
||||||
partition_table_001_p3 | p | r | {2020-05-01}
|
|
||||||
sys_p1 | p | i | {"Mon Jun 01 00:00:00 2020"}
|
|
||||||
sys_p2 | p | i | {"Wed Jul 01 00:00:00 2020"}
|
|
||||||
sys_p3 | p | i | {"Sat Aug 01 00:00:00 2020"}
|
|
||||||
(7 rows)
|
|
||||||
|
|
||||||
ALTER TABLE partition_table_001 EXCHANGE PARTITION (sys_p1) WITH TABLE table_001;
|
|
||||||
select * from table_001 order by 1;
|
|
||||||
col_1 | col_2 | col_3 | col_4 | col_5 | col_6 | col_7
|
|
||||||
-------+-------+-------+-------+-------+-------+-------
|
|
||||||
(0 rows)
|
|
||||||
|
|
||||||
select * from partition_table_001 order by 1;
|
|
||||||
col_1 | col_2 | col_3 | col_4 | col_5 | col_6 | col_7
|
|
||||||
-------+-------+-------+--------------------------+-------+-------+-------
|
|
||||||
1 | aaa | 1 | Sun Feb 23 00:00:00 2020 | t | aaa | 1.1
|
|
||||||
2 | bbb | 2 | Mon Mar 23 00:00:00 2020 | f | bbb | 2.2
|
|
||||||
3 | ccc | 3 | Thu Apr 23 00:00:00 2020 | t | ccc | 3.3
|
|
||||||
4 | ddd | 4 | Sat May 23 00:00:00 2020 | f | ddd | 4.4
|
|
||||||
5 | eee | 5 | Tue Jun 23 00:00:00 2020 | t | eee | 5.5
|
|
||||||
6 | fff | 6 | Thu Jul 23 00:00:00 2020 | f | fff | 6.6
|
|
||||||
(6 rows)
|
|
||||||
|
|
||||||
insert into table_001 values (7,'eee',7,'2020-08-23',true,'eee',7.7);
|
|
||||||
ALTER TABLE partition_table_001 EXCHANGE PARTITION (sys_p1) WITH TABLE table_001 with validation verbose;
|
|
||||||
select * from table_001 order by 1;
|
|
||||||
col_1 | col_2 | col_3 | col_4 | col_5 | col_6 | col_7
|
|
||||||
-------+-------+-------+--------------------------+-------+-------+-------
|
|
||||||
4 | ddd | 4 | Sat May 23 00:00:00 2020 | f | ddd | 4.4
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
select * from partition_table_001 order by 1;
|
|
||||||
col_1 | col_2 | col_3 | col_4 | col_5 | col_6 | col_7
|
|
||||||
-------+-------+-------+--------------------------+-------+-------+-------
|
|
||||||
1 | aaa | 1 | Sun Feb 23 00:00:00 2020 | t | aaa | 1.1
|
|
||||||
2 | bbb | 2 | Mon Mar 23 00:00:00 2020 | f | bbb | 2.2
|
|
||||||
3 | ccc | 3 | Thu Apr 23 00:00:00 2020 | t | ccc | 3.3
|
|
||||||
5 | eee | 5 | Tue Jun 23 00:00:00 2020 | t | eee | 5.5
|
|
||||||
6 | fff | 6 | Thu Jul 23 00:00:00 2020 | f | fff | 6.6
|
|
||||||
7 | eee | 7 | Sun Aug 23 00:00:00 2020 | t | eee | 7.7
|
|
||||||
(6 rows)
|
|
||||||
|
|
||||||
drop table table_001;
|
|
||||||
drop table partition_table_001;
|
|
||||||
|
|
|
||||||
|
|
@ -1,55 +0,0 @@
|
||||||
CREATE TABLE t11 (
|
|
||||||
sec_code character(6) NOT NULL,
|
|
||||||
issue_type character(3) NOT NULL
|
|
||||||
);
|
|
||||||
CREATE TABLE t22 (
|
|
||||||
company_code character(6) NOT NULL,
|
|
||||||
list_profit_flag character(1) NOT NULL
|
|
||||||
);
|
|
||||||
CREATE TABLE t33 (
|
|
||||||
company_code character(6) NOT NULL,
|
|
||||||
issue_flag character(6) NOT NULL
|
|
||||||
);
|
|
||||||
insert into t11 values(1,'S04');
|
|
||||||
insert into t22 values(1,'Y');
|
|
||||||
insert into t33 values(1,'1');
|
|
||||||
insert into t33 values(2,'2');
|
|
||||||
select
|
|
||||||
T5.issue_type
|
|
||||||
,T6.is_type
|
|
||||||
from
|
|
||||||
(
|
|
||||||
select T1.sec_code
|
|
||||||
,issue_type
|
|
||||||
--,case when list_profit_flag='Y' then '是' else '否' end as list_profit_flag
|
|
||||||
from
|
|
||||||
(
|
|
||||||
select sec_code
|
|
||||||
,case when issue_type in ('S04','S05','S06','S09') then '增发'
|
|
||||||
when issue_type in ('S01','S02') then '首发'
|
|
||||||
else '其他' end as issue_type
|
|
||||||
from t11
|
|
||||||
)T1
|
|
||||||
left join
|
|
||||||
(
|
|
||||||
select list_profit_flag
|
|
||||||
,company_code
|
|
||||||
from t22
|
|
||||||
)T2
|
|
||||||
on T1.sec_code=T2.company_code
|
|
||||||
)T5
|
|
||||||
full join
|
|
||||||
(
|
|
||||||
SELECT CASE
|
|
||||||
WHEN issue_flag = ANY (ARRAY['1'::bpchar, '3'::bpchar, '11'::bpchar]) THEN '首发'::text
|
|
||||||
ELSE '增发'::text
|
|
||||||
END AS is_type from t33
|
|
||||||
)T6
|
|
||||||
on T5.issue_type=T6.is_type
|
|
||||||
;
|
|
||||||
issue_type | is_type
|
|
||||||
------------+---------
|
|
||||||
增发 | 增发
|
|
||||||
| 首发
|
|
||||||
(2 rows)
|
|
||||||
|
|
||||||
|
|
@ -89,8 +89,5 @@ ERROR: Can not use compress option in ustore index.
|
||||||
-- segment
|
-- segment
|
||||||
CREATE TABLE unspported_feature.segment_table(id int, c1 text) WITH(compresstype=2, segment=on); --failed
|
CREATE TABLE unspported_feature.segment_table(id int, c1 text) WITH(compresstype=2, segment=on); --failed
|
||||||
ERROR: only row orientation table support compresstype.
|
ERROR: only row orientation table support compresstype.
|
||||||
CREATE INDEX on unspported_feature.index_test(c1) WITH(compresstype=2, segment=on); --failed
|
CREATE INDEX on unspported_feature.index_test(c1) WITH(compresstype=2, segment=on); --faled
|
||||||
ERROR: Can not use compress option in segment storage.
|
ERROR: Can not use compress option in segment storage.
|
||||||
-- set compress_diff_convert
|
|
||||||
create table unspported_feature.compress_byte_test(id int) with (compresstype=2, compress_byte_convert=false, compress_diff_convert = true); -- failed
|
|
||||||
ERROR: compress_diff_convert should be used with compress_byte_convert.
|
|
||||||
|
|
|
||||||
|
|
@ -1062,73 +1062,6 @@ select /*+ indexscan(tg_hash i_tg_hash_local_a) */ * from tg_hash where a < 9;
|
||||||
(81 rows)
|
(81 rows)
|
||||||
|
|
||||||
drop table tg_hash;
|
drop table tg_hash;
|
||||||
drop table if exists test_ugi_045;
|
|
||||||
NOTICE: table "test_ugi_045" does not exist, skipping
|
|
||||||
create table test_ugi_045
|
|
||||||
(
|
|
||||||
c_id integer not null,
|
|
||||||
c_date DATE,
|
|
||||||
c_info varchar(20) not null
|
|
||||||
)
|
|
||||||
partition by range(c_date)
|
|
||||||
interval('2 day')
|
|
||||||
(
|
|
||||||
partition p1 values less than ('2021-06-01 00:00:00'),
|
|
||||||
partition p2 values less than ('2021-06-03 00:00:00'),
|
|
||||||
partition p3 values less than ('2021-06-05 00:00:00'),
|
|
||||||
partition p4 values less than ('2021-06-07 00:00:00'),
|
|
||||||
partition p5 values less than ('2021-06-09 00:00:00')
|
|
||||||
);
|
|
||||||
insert into test_ugi_045(c_id, c_date, c_info) values(1, '2021-05-30 00:00:00', '1-1');
|
|
||||||
insert into test_ugi_045(c_id, c_date, c_info) values(2, '2021-05-31 00:00:00', '1-1');
|
|
||||||
insert into test_ugi_045(c_id, c_date, c_info) values(3, '2021-06-01 00:00:00', '1-1');
|
|
||||||
insert into test_ugi_045(c_id, c_date, c_info) values(4, '2021-06-02 00:00:00', '1-2');
|
|
||||||
insert into test_ugi_045(c_id, c_date, c_info) values(5, '2021-06-03 00:00:00', '1-2');
|
|
||||||
insert into test_ugi_045(c_id, c_date, c_info) values(6, '2021-06-04 00:00:00', '1-3');
|
|
||||||
insert into test_ugi_045(c_id, c_date, c_info) values(7, '2021-06-05 00:00:00', '1-3');
|
|
||||||
insert into test_ugi_045(c_id, c_date, c_info) values(8, '2021-06-06 00:00:00', '1-4');
|
|
||||||
insert into test_ugi_045(c_id, c_date, c_info) values(9, '2021-06-07 00:00:00', '1-4');
|
|
||||||
insert into test_ugi_045(c_id, c_date, c_info) values(10, '2021-06-08 00:00:00', '1-5');
|
|
||||||
create index global_index_id_045 on test_ugi_045(c_date) global;
|
|
||||||
create index global_index_info_045 on test_ugi_045(c_info) global;
|
|
||||||
select *from test_ugi_045;
|
|
||||||
c_id | c_date | c_info
|
|
||||||
------+---------------------+--------
|
|
||||||
1 | 2021-05-30 00:00:00 | 1-1
|
|
||||||
2 | 2021-05-31 00:00:00 | 1-1
|
|
||||||
3 | 2021-06-01 00:00:00 | 1-1
|
|
||||||
4 | 2021-06-02 00:00:00 | 1-2
|
|
||||||
5 | 2021-06-03 00:00:00 | 1-2
|
|
||||||
6 | 2021-06-04 00:00:00 | 1-3
|
|
||||||
7 | 2021-06-05 00:00:00 | 1-3
|
|
||||||
8 | 2021-06-06 00:00:00 | 1-4
|
|
||||||
9 | 2021-06-07 00:00:00 | 1-4
|
|
||||||
10 | 2021-06-08 00:00:00 | 1-5
|
|
||||||
(10 rows)
|
|
||||||
|
|
||||||
alter table test_ugi_045 truncate partition p3 update global index;
|
|
||||||
set enable_seqscan = off;
|
|
||||||
set enable_bitmapscan = off;
|
|
||||||
select *from test_ugi_045;
|
|
||||||
c_id | c_date | c_info
|
|
||||||
------+---------------------+--------
|
|
||||||
1 | 2021-05-30 00:00:00 | 1-1
|
|
||||||
2 | 2021-05-31 00:00:00 | 1-1
|
|
||||||
3 | 2021-06-01 00:00:00 | 1-1
|
|
||||||
4 | 2021-06-02 00:00:00 | 1-2
|
|
||||||
7 | 2021-06-05 00:00:00 | 1-3
|
|
||||||
8 | 2021-06-06 00:00:00 | 1-4
|
|
||||||
9 | 2021-06-07 00:00:00 | 1-4
|
|
||||||
10 | 2021-06-08 00:00:00 | 1-5
|
|
||||||
(8 rows)
|
|
||||||
|
|
||||||
select *from test_ugi_045 where c_info = '1-2';
|
|
||||||
c_id | c_date | c_info
|
|
||||||
------+---------------------+--------
|
|
||||||
4 | 2021-06-02 00:00:00 | 1-2
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
drop table if exists test_ugi_045;
|
|
||||||
-- 清理过程
|
-- 清理过程
|
||||||
drop view check_truncate_results;
|
drop view check_truncate_results;
|
||||||
drop materialized view pg_partition_before_truncate;
|
drop materialized view pg_partition_before_truncate;
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,6 @@ CREATE SUBSCRIPTION testsub CONNECTION 'foo';
|
||||||
CREATE SUBSCRIPTION testsub PUBLICATION foo;
|
CREATE SUBSCRIPTION testsub PUBLICATION foo;
|
||||||
-- fail - could not connect to the publisher
|
-- fail - could not connect to the publisher
|
||||||
create subscription testsub2 connection 'host=abc' publication pub;
|
create subscription testsub2 connection 'host=abc' publication pub;
|
||||||
create subscription testsub2 connection 'host=abc port=12345' publication pub;
|
|
||||||
set client_min_messages to error;
|
set client_min_messages to error;
|
||||||
-- fail - syntax error, invalid connection string syntax: missing "="
|
-- fail - syntax error, invalid connection string syntax: missing "="
|
||||||
CREATE SUBSCRIPTION testsub CONNECTION 'testconn' PUBLICATION testpub;
|
CREATE SUBSCRIPTION testsub CONNECTION 'testconn' PUBLICATION testpub;
|
||||||
|
|
@ -33,15 +32,12 @@ CREATE SUBSCRIPTION testsub CONNECTION 'dbname=doesnotexist' PUBLICATION testpub
|
||||||
CREATE SUBSCRIPTION testsub CONNECTION 'dbname=doesnotexist' PUBLICATION testpub WITH (ENABLED=false, slot_name='testsub', synchronous_commit=off);
|
CREATE SUBSCRIPTION testsub CONNECTION 'dbname=doesnotexist' PUBLICATION testpub WITH (ENABLED=false, slot_name='testsub', synchronous_commit=off);
|
||||||
-- create SUBSCRIPTION with conninfo in two single quote, used to check mask string bug
|
-- create SUBSCRIPTION with conninfo in two single quote, used to check mask string bug
|
||||||
CREATE SUBSCRIPTION testsub_maskconninfo CONNECTION 'host=''1.2.3.4'' port=''12345'' user=''username'' dbname=''postgres'' password=''password_1234''' PUBLICATION testpub WITH (ENABLED=false, slot_name='testsub', synchronous_commit=off);
|
CREATE SUBSCRIPTION testsub_maskconninfo CONNECTION 'host=''1.2.3.4'' port=''12345'' user=''username'' dbname=''postgres'' password=''password_1234''' PUBLICATION testpub WITH (ENABLED=false, slot_name='testsub', synchronous_commit=off);
|
||||||
-- fail - The number of host and port are inconsistent
|
|
||||||
create subscription sub1 connection 'dbname=postgres user=pubusr password=Huawei@123 host=192.168.0.38,192.168.0.38,192.168.0.38 port=14001,14501' publication pub1;
|
|
||||||
-- fail - a maximum of 9 servers are supported
|
|
||||||
create subscription sub1 connection 'dbname=postgres user=pubusr password=Huawei@123 host=192.168.0.38,192.168.0.38,192.168.0.38,192.168.0.38,192.168.0.38,192.168.0.38,192.168.0.38,192.168.0.38,192.168.0.38,192.168.0.38 port=14001,14501' publication pub1;
|
|
||||||
-- alter connection
|
-- alter connection
|
||||||
ALTER SUBSCRIPTION testsub CONNECTION 'host=''1.2.3.4'' port=''12345'' user=''username'' dbname=''postgres'' password=''password_1234''';
|
ALTER SUBSCRIPTION testsub CONNECTION 'host=''1.2.3.4'' port=''12345'' user=''username'' dbname=''postgres'' password=''password_1234''';
|
||||||
ALTER SUBSCRIPTION testsub CONNECTION 'dbname=does_not_exist';
|
ALTER SUBSCRIPTION testsub CONNECTION 'dbname=does_not_exist';
|
||||||
reset client_min_messages;
|
reset client_min_messages;
|
||||||
select subname, pg_get_userbyid(subowner) as Owner, subenabled, subconninfo, subpublications, subbinary from pg_subscription where subname='testsub';
|
select subname, pg_get_userbyid(subowner) as Owner, subenabled, subconninfo, subpublications from pg_subscription where subname='testsub';
|
||||||
--- alter subscription
|
--- alter subscription
|
||||||
------ set publication
|
------ set publication
|
||||||
ALTER SUBSCRIPTION testsub SET PUBLICATION testpub2, testpub3;
|
ALTER SUBSCRIPTION testsub SET PUBLICATION testpub2, testpub3;
|
||||||
|
|
@ -61,9 +57,6 @@ select subname, subenabled, subsynccommit from pg_subscription where subname='t
|
||||||
ALTER SUBSCRIPTION testsub SET (slot_name='testsub');
|
ALTER SUBSCRIPTION testsub SET (slot_name='testsub');
|
||||||
-- alter owner
|
-- alter owner
|
||||||
ALTER SUBSCRIPTION testsub owner to regress_subscription_user2;
|
ALTER SUBSCRIPTION testsub owner to regress_subscription_user2;
|
||||||
-- alter subbinary to true
|
|
||||||
ALTER SUBSCRIPTION testsub SET (binary=true);
|
|
||||||
select subname, subbinary from pg_subscription where subname='testsub';
|
|
||||||
--rename
|
--rename
|
||||||
ALTER SUBSCRIPTION testsub rename to testsub_rename;
|
ALTER SUBSCRIPTION testsub rename to testsub_rename;
|
||||||
--- inside a transaction block
|
--- inside a transaction block
|
||||||
|
|
|
||||||
|
|
@ -60,10 +60,8 @@ LINE 1: CREATE SUBSCRIPTION testsub PUBLICATION foo;
|
||||||
^
|
^
|
||||||
-- fail - could not connect to the publisher
|
-- fail - could not connect to the publisher
|
||||||
create subscription testsub2 connection 'host=abc' publication pub;
|
create subscription testsub2 connection 'host=abc' publication pub;
|
||||||
ERROR: The number of host and port are inconsistent.
|
|
||||||
create subscription testsub2 connection 'host=abc port=12345' publication pub;
|
|
||||||
WARNING: apply worker could not connect to the remote server
|
WARNING: apply worker could not connect to the remote server
|
||||||
ERROR: Failed to connect to publisher.
|
ERROR: could not connect to the publisher
|
||||||
set client_min_messages to error;
|
set client_min_messages to error;
|
||||||
-- fail - syntax error, invalid connection string syntax: missing "="
|
-- fail - syntax error, invalid connection string syntax: missing "="
|
||||||
CREATE SUBSCRIPTION testsub CONNECTION 'testconn' PUBLICATION testpub;
|
CREATE SUBSCRIPTION testsub CONNECTION 'testconn' PUBLICATION testpub;
|
||||||
|
|
@ -74,20 +72,14 @@ ERROR: unrecognized subscription parameter: create_slot
|
||||||
CREATE SUBSCRIPTION testsub CONNECTION 'dbname=doesnotexist' PUBLICATION testpub WITH (ENABLED=false, slot_name='testsub', synchronous_commit=off);
|
CREATE SUBSCRIPTION testsub CONNECTION 'dbname=doesnotexist' PUBLICATION testpub WITH (ENABLED=false, slot_name='testsub', synchronous_commit=off);
|
||||||
-- create SUBSCRIPTION with conninfo in two single quote, used to check mask string bug
|
-- create SUBSCRIPTION with conninfo in two single quote, used to check mask string bug
|
||||||
CREATE SUBSCRIPTION testsub_maskconninfo CONNECTION 'host=''1.2.3.4'' port=''12345'' user=''username'' dbname=''postgres'' password=''password_1234''' PUBLICATION testpub WITH (ENABLED=false, slot_name='testsub', synchronous_commit=off);
|
CREATE SUBSCRIPTION testsub_maskconninfo CONNECTION 'host=''1.2.3.4'' port=''12345'' user=''username'' dbname=''postgres'' password=''password_1234''' PUBLICATION testpub WITH (ENABLED=false, slot_name='testsub', synchronous_commit=off);
|
||||||
-- fail - The number of host and port are inconsistent
|
|
||||||
create subscription sub1 connection 'dbname=postgres user=pubusr password=Huawei@123 host=192.168.0.38,192.168.0.38,192.168.0.38 port=14001,14501' publication pub1;
|
|
||||||
ERROR: The number of host and port are inconsistent.
|
|
||||||
-- fail - a maximum of 9 servers are supported
|
|
||||||
create subscription sub1 connection 'dbname=postgres user=pubusr password=Huawei@123 host=192.168.0.38,192.168.0.38,192.168.0.38,192.168.0.38,192.168.0.38,192.168.0.38,192.168.0.38,192.168.0.38,192.168.0.38,192.168.0.38 port=14001,14501' publication pub1;
|
|
||||||
ERROR: Currently, a maximum of 9 servers are supported.
|
|
||||||
-- alter connection
|
-- alter connection
|
||||||
ALTER SUBSCRIPTION testsub CONNECTION 'host=''1.2.3.4'' port=''12345'' user=''username'' dbname=''postgres'' password=''password_1234''';
|
ALTER SUBSCRIPTION testsub CONNECTION 'host=''1.2.3.4'' port=''12345'' user=''username'' dbname=''postgres'' password=''password_1234''';
|
||||||
ALTER SUBSCRIPTION testsub CONNECTION 'dbname=does_not_exist';
|
ALTER SUBSCRIPTION testsub CONNECTION 'dbname=does_not_exist';
|
||||||
reset client_min_messages;
|
reset client_min_messages;
|
||||||
select subname, pg_get_userbyid(subowner) as Owner, subenabled, subconninfo, subpublications, subbinary from pg_subscription where subname='testsub';
|
select subname, pg_get_userbyid(subowner) as Owner, subenabled, subconninfo, subpublications from pg_subscription where subname='testsub';
|
||||||
subname | owner | subenabled | subconninfo | subpublications | subbinary
|
subname | owner | subenabled | subconninfo | subpublications
|
||||||
---------+---------------------------+------------+------------------------+-----------------+-----------
|
---------+---------------------------+------------+------------------------+-----------------
|
||||||
testsub | regress_subscription_user | f | dbname=does_not_exist | {testpub} | f
|
testsub | regress_subscription_user | f | dbname=does_not_exist | {testpub}
|
||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
--- alter subscription
|
--- alter subscription
|
||||||
|
|
@ -130,14 +122,6 @@ ALTER SUBSCRIPTION testsub SET (slot_name='testsub');
|
||||||
ERROR: Currently enabled=false, cannot change slot_name to a non-null value.
|
ERROR: Currently enabled=false, cannot change slot_name to a non-null value.
|
||||||
-- alter owner
|
-- alter owner
|
||||||
ALTER SUBSCRIPTION testsub owner to regress_subscription_user2;
|
ALTER SUBSCRIPTION testsub owner to regress_subscription_user2;
|
||||||
-- alter subbinary to true
|
|
||||||
ALTER SUBSCRIPTION testsub SET (binary=true);
|
|
||||||
select subname, subbinary from pg_subscription where subname='testsub';
|
|
||||||
subname | subbinary
|
|
||||||
---------+-----------
|
|
||||||
testsub | t
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
--rename
|
--rename
|
||||||
ALTER SUBSCRIPTION testsub rename to testsub_rename;
|
ALTER SUBSCRIPTION testsub rename to testsub_rename;
|
||||||
--- inside a transaction block
|
--- inside a transaction block
|
||||||
|
|
@ -150,7 +134,8 @@ COMMIT;
|
||||||
-- -- active SUBSCRIPTION
|
-- -- active SUBSCRIPTION
|
||||||
BEGIN;
|
BEGIN;
|
||||||
ALTER SUBSCRIPTION testsub_rename ENABLE;
|
ALTER SUBSCRIPTION testsub_rename ENABLE;
|
||||||
ERROR: invalid connection string syntax, missing host and port
|
WARNING: apply worker could not connect to the remote server
|
||||||
|
ERROR: could not connect to the publisher
|
||||||
select subname, subenabled from pg_subscription where subname='testsub_rename';
|
select subname, subenabled from pg_subscription where subname='testsub_rename';
|
||||||
ERROR: current transaction is aborted, commands ignored until end of transaction block, firstChar[Q]
|
ERROR: current transaction is aborted, commands ignored until end of transaction block, firstChar[Q]
|
||||||
ALTER SUBSCRIPTION testsub_rename SET (ENABLED=false);
|
ALTER SUBSCRIPTION testsub_rename SET (ENABLED=false);
|
||||||
|
|
@ -296,11 +281,10 @@ SELECT object_name,detail_info FROM pg_query_audit('2022-01-13 9:30:00', '2031-1
|
||||||
testsub_maskconninfo | ALTER SUBSCRIPTION testsub_maskconninfo SET (conninfo='*************************************************************************************************************************;
|
testsub_maskconninfo | ALTER SUBSCRIPTION testsub_maskconninfo SET (conninfo='*************************************************************************************************************************;
|
||||||
testsub | ALTER SUBSCRIPTION testsub SET (synchronous_commit=on);
|
testsub | ALTER SUBSCRIPTION testsub SET (synchronous_commit=on);
|
||||||
testsub | ALTER SUBSCRIPTION testsub owner to regress_subscription_user2;
|
testsub | ALTER SUBSCRIPTION testsub owner to regress_subscription_user2;
|
||||||
testsub | ALTER SUBSCRIPTION testsub SET (binary=true);
|
|
||||||
testsub | ALTER SUBSCRIPTION testsub rename to testsub_rename;
|
testsub | ALTER SUBSCRIPTION testsub rename to testsub_rename;
|
||||||
testsub_rename | DROP SUBSCRIPTION IF EXISTS testsub_rename;
|
testsub_rename | DROP SUBSCRIPTION IF EXISTS testsub_rename;
|
||||||
testsub_maskconninfo | DROP SUBSCRIPTION IF EXISTS testsub_maskconninfo;
|
testsub_maskconninfo | DROP SUBSCRIPTION IF EXISTS testsub_maskconninfo;
|
||||||
(15 rows)
|
(14 rows)
|
||||||
|
|
||||||
--clear audit log
|
--clear audit log
|
||||||
SELECT pg_delete_audit('1012-11-10', '3012-11-11');
|
SELECT pg_delete_audit('1012-11-10', '3012-11-11');
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ test: pldeveloper_gs_source
|
||||||
test: index_advisor
|
test: index_advisor
|
||||||
test: pl_debugger_server pl_debugger_client
|
test: pl_debugger_server pl_debugger_client
|
||||||
test: update_for_wait_s1 update_for_wait_s2
|
test: update_for_wait_s1 update_for_wait_s2
|
||||||
test: plan_hint plan_hint_set plan_hint_no_expand plan_hint_iud null_test_opt deserialize_func
|
test: plan_hint plan_hint_set plan_hint_no_expand plan_hint_iud null_test_opt
|
||||||
test: large_sequence int16 gs_dump_sequence
|
test: large_sequence int16 gs_dump_sequence
|
||||||
test: gs_dump_tableof
|
test: gs_dump_tableof
|
||||||
test: analyze_commands
|
test: analyze_commands
|
||||||
|
|
@ -916,5 +916,3 @@ test: fdw_audit
|
||||||
test: gs_global_config_audit
|
test: gs_global_config_audit
|
||||||
test: detail
|
test: detail
|
||||||
test: gs_dump_encrypt
|
test: gs_dump_encrypt
|
||||||
test: composite_datum_record
|
|
||||||
test: join_test_alias
|
|
||||||
|
|
|
||||||
|
|
@ -5238,7 +5238,7 @@ static void check_global_variables()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#define BASE_PGXC_LIKE_MACRO_NUM 1402
|
#define BASE_PGXC_LIKE_MACRO_NUM 1401
|
||||||
static void check_pgxc_like_macros()
|
static void check_pgxc_like_macros()
|
||||||
{
|
{
|
||||||
#ifdef BUILD_BY_CMAKE
|
#ifdef BUILD_BY_CMAKE
|
||||||
|
|
|
||||||
|
|
@ -1,11 +0,0 @@
|
||||||
--
|
|
||||||
-- check for over-optimization of whole-row Var referencing an Append plan
|
|
||||||
--
|
|
||||||
create table int4_test(f1 int4);
|
|
||||||
select (select q from (select 1,2,3 where f1>0 union all select 4,5,6 where f1<=0) q) from int4_test;
|
|
||||||
select (select q from (select 1,2,3 where f1>0 union all select 4,5,6.0 where f1<=0) q) from int4_test;
|
|
||||||
insert into int4_test(f1) values(' 0 ');
|
|
||||||
insert into int4_test(f1) values('123456 ');
|
|
||||||
select * from int4_test;
|
|
||||||
select (select q from (select 1,2,3 where f1>0 union all select 4,5,6 where f1<=0) q) from int4_test;
|
|
||||||
select (select q from (select 1,2,3 where f1>0 union all select 4,5,6.0 where f1<=0) q) from int4_test;
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue