forked from huawei/openGauss-server
Compare commits
115 Commits
undorecycl
...
master
| Author | SHA1 | Date |
|---|---|---|
|
|
991925bfe1 | |
|
|
6021c26abe | |
|
|
817264937d | |
|
|
62e2170f65 | |
|
|
2812c3315c | |
|
|
5c988a09f4 | |
|
|
4cd25670b5 | |
|
|
f70898ecf5 | |
|
|
95466298fa | |
|
|
119d5d39da | |
|
|
537cba6247 | |
|
|
14c4068daa | |
|
|
cf8e1541b1 | |
|
|
58d5c900c9 | |
|
|
25332da4aa | |
|
|
fd0098411a | |
|
|
b4f33b07cf | |
|
|
caccfc026d | |
|
|
30621924cf | |
|
|
abb0cee0fc | |
|
|
0c2af1d742 | |
|
|
09e299ac8a | |
|
|
7dc9903be8 | |
|
|
bc0dc304c8 | |
|
|
5f334a5656 | |
|
|
4ec1513e05 | |
|
|
fb0026b93b | |
|
|
ce56fb62b6 | |
|
|
2b198387ab | |
|
|
72f4d68de6 | |
|
|
62e3bed09b | |
|
|
7d4d95a5ad | |
|
|
240f61c595 | |
|
|
a0d1a547f8 | |
|
|
df804a8a91 | |
|
|
91917dcfaf | |
|
|
e2163187ca | |
|
|
1d7eadd778 | |
|
|
b335ef9af7 | |
|
|
572d99d03c | |
|
|
0b0959fc69 | |
|
|
238ee19a59 | |
|
|
d199d90a71 | |
|
|
2a77a3cebc | |
|
|
214d01ddb6 | |
|
|
4f024161f0 | |
|
|
82d5ac65b0 | |
|
|
7edda5e2a4 | |
|
|
e10c482649 | |
|
|
0a29277070 | |
|
|
96dad83a1d | |
|
|
d433ee097a | |
|
|
a590e0b47f | |
|
|
7f8b900e69 | |
|
|
f14255f040 | |
|
|
5af581f12a | |
|
|
26793e3bf2 | |
|
|
dbcf479205 | |
|
|
ae11cad2c3 | |
|
|
57bc5c4a37 | |
|
|
fb449157d0 | |
|
|
6c5898646e | |
|
|
c1335bebc9 | |
|
|
b2c6e04eab | |
|
|
16d32d3978 | |
|
|
3e14e85fdf | |
|
|
438bba32ff | |
|
|
d82eba4790 | |
|
|
4b7080c8ef | |
|
|
5e1d9b79f6 | |
|
|
51c355c7b6 | |
|
|
4c0a495a18 | |
|
|
cbb8fd609b | |
|
|
475170ca0c | |
|
|
7f9a1f5428 | |
|
|
c04e377cdc | |
|
|
6380ca0f4d | |
|
|
4898f04a3c | |
|
|
11a1a5c9ad | |
|
|
a30ae9d5ad | |
|
|
0b70c7ab70 | |
|
|
f719422916 | |
|
|
88dcc7f99e | |
|
|
dbd9958443 | |
|
|
38b5a0ac95 | |
|
|
a548f5c3c6 | |
|
|
eb4e54d4eb | |
|
|
3f7a909887 | |
|
|
d8b89ceea5 | |
|
|
2250adfd4b | |
|
|
fd34b5da2a | |
|
|
7f97d633f1 | |
|
|
6ba4c95f5f | |
|
|
5755feee5d | |
|
|
cd5d44d66c | |
|
|
2d657cddbe | |
|
|
ccd674c159 | |
|
|
8292238381 | |
|
|
5054ddd002 | |
|
|
48a5033c18 | |
|
|
811a9afcd9 | |
|
|
bb0aa02eb0 | |
|
|
02c14696bf | |
|
|
877f0b69e3 | |
|
|
120ddcc6d8 | |
|
|
2cc80a5727 | |
|
|
6d8bec171c | |
|
|
9f7da01725 | |
|
|
ea938c947e | |
|
|
498d7ac08d | |
|
|
40b717d9dd | |
|
|
94aeb766e5 | |
|
|
8577a61c7b | |
|
|
59db2a14cc | |
|
|
e7795cd01c |
|
|
@ -1,4 +1,5 @@
|
|||
#!/usr/bin/perl
|
||||
#Again
|
||||
|
||||
use warnings;
|
||||
use strict;
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@ select_package_command
|
|||
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 ]
|
||||
then
|
||||
echo "We only support openEuler(aarch64), EulerOS(aarch64), CentOS, Kylin(aarch64) platform."
|
||||
echo "We only support openEuler(aarch64), EulerOS(aarch64), CentOS, Kylin(aarch64), Asianux platform."
|
||||
exit 1;
|
||||
fi
|
||||
|
||||
|
|
@ -96,16 +96,21 @@ elif [[ "$PLAT_FORM_STR" =~ "kylin" ]]; then
|
|||
if [ "$PLATFORM_ARCH"X == "aarch64"X ];then
|
||||
GAUSSDB_EXTRA_FLAGS=" -D__USE_NUMA"
|
||||
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
|
||||
echo "We only support openEuler(aarch64), EulerOS(aarch64), CentOS, Kylin(aarch64) platform."
|
||||
echo "We only support openEuler(aarch64), EulerOS(aarch64), CentOS, Kylin(aarch64), Asianux platform."
|
||||
echo "Kernel is $kernel"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
##add platform architecture information
|
||||
if [ "$PLATFORM_ARCH"X == "aarch64"X ] ; then
|
||||
if [ "$dist_version" != "openEuler" ] && [ "$dist_version" != "EulerOS" ] && [ "$dist_version" != "Kylin" ] ; then
|
||||
echo "We only support NUMA on openEuler(aarch64), EulerOS(aarch64), Kylin(aarch64) platform."
|
||||
if [ "$dist_version" != "openEuler" ] && [ "$dist_version" != "EulerOS" ] && [ "$dist_version" != "Kylin" ] && [ "$dist_version" != "Asianux" ]; then
|
||||
echo "We only support NUMA on openEuler(aarch64), EulerOS(aarch64), Kylin(aarch64), Asianux platform."
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ Complete list of usable sgml source files in this directory.
|
|||
<!ENTITY alterOperator SYSTEM "alter_operator.sgml">
|
||||
<!ENTITY alterOperatorClass SYSTEM "alter_opclass.sgml">
|
||||
<!ENTITY alterOperatorFamily SYSTEM "alter_opfamily.sgml">
|
||||
<!ENTITY alterProcedure SYSTEM "alter_procedure.sgml">
|
||||
<!ENTITY alterRole SYSTEM "alter_role.sgml">
|
||||
<!ENTITY alterSchema SYSTEM "alter_schema.sgml">
|
||||
<!ENTITY alterServer SYSTEM "alter_server.sgml">
|
||||
|
|
|
|||
|
|
@ -0,0 +1,37 @@
|
|||
<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>
|
||||
<synopsis>
|
||||
DROP TABLE [ IF EXISTS ]
|
||||
{[schema.]table_name} [, ...] [ CASCADE | RESTRICT ] [ PURGE ]};
|
||||
{[schema.]table_name} [, ...] [ CASCADE | RESTRICT ] [ PURGE ];
|
||||
</synopsis>
|
||||
</refsynopsisdiv>
|
||||
</refentry>
|
||||
|
|
@ -27,7 +27,14 @@
|
|||
#include "securec_check.h"
|
||||
#include "cipher.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* ret = NULL;
|
||||
|
|
|
|||
|
|
@ -34,6 +34,14 @@
|
|||
static int check_key_num(const char* password);
|
||||
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)
|
||||
{
|
||||
const char* danger_character_list[] = {"|",
|
||||
|
|
@ -69,6 +77,14 @@ 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)
|
||||
{
|
||||
int key_len = 0;
|
||||
|
|
@ -84,6 +100,13 @@ static int check_key_num(const char* password)
|
|||
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)
|
||||
{
|
||||
if (pathdir == NULL) {
|
||||
|
|
|
|||
|
|
@ -1229,6 +1229,12 @@ parse_next_sync_groups(char **pgroup, char *result)
|
|||
static int
|
||||
transform_az_name(char *config_value, char *allAZString, int allAZStringBufLen, const char *data_dir)
|
||||
{
|
||||
if (strcmp(config_value, "''") == 0) {
|
||||
errno_t rc = strncpy_s(allAZString, allAZStringBufLen, config_value, strlen(config_value));
|
||||
securec_check_c(rc, "\0", "\0");
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
char *azString = NULL;
|
||||
char *buf = allAZString;
|
||||
int buflen = allAZStringBufLen;
|
||||
|
|
|
|||
|
|
@ -5923,7 +5923,7 @@ int main(int argc, char** argv)
|
|||
&option_index)) != -1)
|
||||
#endif
|
||||
#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: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:C:dqL:T:Q:", long_options,
|
||||
&option_index)) != -1)
|
||||
#endif
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -233,7 +233,7 @@ char* all_data_nodename_list = NULL;
|
|||
const uint32 USTORE_UPGRADE_VERSION = 92368;
|
||||
const uint32 PACKAGE_ENHANCEMENT = 92444;
|
||||
const uint32 SUBSCRIPTION_VERSION = 92580;
|
||||
const uint32 SUBSCRIPTION_BINARY_VERSION_NUM = 92607;
|
||||
const uint32 SUBSCRIPTION_BINARY_VERSION_NUM = 92606;
|
||||
|
||||
#ifdef DUMPSYSLOG
|
||||
char* syslogpath = NULL;
|
||||
|
|
@ -4454,16 +4454,7 @@ void getSubscriptions(Archive *fout)
|
|||
}
|
||||
|
||||
if (!isExecUserSuperRole(fout)) {
|
||||
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);
|
||||
write_msg(NULL, "WARNING: subscriptions not dumped because current user is not a superuser\n");
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -10795,6 +10786,11 @@ static void dumpDirectory(Archive* fout)
|
|||
char* dirpath = 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 */
|
||||
selectSourceSchema(fout, "pg_catalog");
|
||||
|
||||
|
|
@ -21404,6 +21400,11 @@ static void dumpSynonym(Archive* fout)
|
|||
PQExpBuffer q;
|
||||
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");
|
||||
query = createPQExpBuffer();
|
||||
printfPQExpBuffer(query,
|
||||
|
|
|
|||
|
|
@ -31,6 +31,9 @@
|
|||
it will be backuped up in external dirs */
|
||||
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 XLogRecPtr stop_backup_lsn = InvalidXLogRecPtr;
|
||||
static XLogRecPtr stop_stream_lsn = InvalidXLogRecPtr;
|
||||
|
|
@ -89,10 +92,11 @@ static void backup_cleanup(bool fatal, void *userdata);
|
|||
|
||||
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,
|
||||
PGNodeInfo *nodeInfo, PGconn *conn);
|
||||
PGNodeInfo *nodeInfo, PGconn *conn, bool backup_replslots);
|
||||
static void pg_stop_backup(pgBackup *backup, PGconn *pg_startbackup_conn, PGNodeInfo *nodeInfo);
|
||||
static int checkpoint_timeout(PGconn *backup_conn);
|
||||
|
||||
|
|
@ -558,7 +562,7 @@ static void sync_files(parray *database_map, const char *database_path, parray *
|
|||
* Move files from 'pgdata' to a subdirectory in 'backup_path'.
|
||||
*/
|
||||
static void
|
||||
do_backup_instance(PGconn *backup_conn, PGNodeInfo *nodeInfo, bool no_sync, bool backup_logs)
|
||||
do_backup_instance(PGconn *backup_conn, PGNodeInfo *nodeInfo, bool no_sync, bool backup_logs, bool backup_replslots)
|
||||
{
|
||||
int i;
|
||||
char database_path[MAXPGPATH];
|
||||
|
|
@ -591,7 +595,7 @@ do_backup_instance(PGconn *backup_conn, PGNodeInfo *nodeInfo, bool no_sync, bool
|
|||
securec_check_c(rc, "\0", "\0");
|
||||
|
||||
/* Call pg_start_backup function in openGauss connect */
|
||||
pg_start_backup(label, smooth_checkpoint, ¤t, nodeInfo, backup_conn);
|
||||
pg_start_backup(label, smooth_checkpoint, ¤t, nodeInfo, backup_conn, backup_replslots);
|
||||
|
||||
/* Obtain current timeline */
|
||||
#if PG_VERSION_NUM >= 90600
|
||||
|
|
@ -624,10 +628,10 @@ do_backup_instance(PGconn *backup_conn, PGNodeInfo *nodeInfo, bool no_sync, bool
|
|||
/* list files with the logical path. omit $PGDATA */
|
||||
if (fio_is_remote(FIO_DB_HOST))
|
||||
fio_list_dir(backup_files_list, instance_config.pgdata,
|
||||
true, true, false, backup_logs, true, 0);
|
||||
true, true, false, backup_logs, true, 0, backup_replslots);
|
||||
else
|
||||
dir_list_file(backup_files_list, instance_config.pgdata,
|
||||
true, true, false, backup_logs, true, 0, FIO_LOCAL_HOST);
|
||||
true, true, false, backup_logs, true, 0, FIO_LOCAL_HOST, backup_replslots);
|
||||
|
||||
/*
|
||||
* Get database_map (name to oid) for use in partial restore feature.
|
||||
|
|
@ -749,6 +753,11 @@ do_backup_instance(PGconn *backup_conn, PGNodeInfo *nodeInfo, bool no_sync, bool
|
|||
}
|
||||
pgdata_nobackup_dir = NULL;
|
||||
|
||||
if (logical_replslot) {
|
||||
free_dir_list(logical_replslot);
|
||||
}
|
||||
logical_replslot = NULL;
|
||||
|
||||
/* Cleanup */
|
||||
if (backup_list)
|
||||
{
|
||||
|
|
@ -849,7 +858,7 @@ static void do_after_backup()
|
|||
*/
|
||||
int
|
||||
do_backup(time_t start_time, pgSetBackupParams *set_backup_params,
|
||||
bool no_validate, bool no_sync, bool backup_logs)
|
||||
bool no_validate, bool no_sync, bool backup_logs, bool backup_replslots)
|
||||
{
|
||||
PGconn *backup_conn = NULL;
|
||||
PGNodeInfo nodeInfo;
|
||||
|
|
@ -925,7 +934,7 @@ do_backup(time_t start_time, pgSetBackupParams *set_backup_params,
|
|||
add_note(¤t, set_backup_params->note);
|
||||
|
||||
/* backup data */
|
||||
do_backup_instance(backup_conn, &nodeInfo, no_sync, backup_logs);
|
||||
do_backup_instance(backup_conn, &nodeInfo, no_sync, backup_logs, backup_replslots);
|
||||
pgut_atexit_pop(backup_cleanup, NULL);
|
||||
|
||||
/* compute size of wal files of this backup stored in the archive */
|
||||
|
|
@ -1034,13 +1043,15 @@ confirm_block_size(PGconn *conn, const char *name, int blcksz)
|
|||
*/
|
||||
static void
|
||||
pg_start_backup(const char *label, bool smooth, pgBackup *backup,
|
||||
PGNodeInfo *nodeInfo, PGconn *conn)
|
||||
PGNodeInfo *nodeInfo, PGconn *conn, bool backup_replslots)
|
||||
{
|
||||
PGresult *res;
|
||||
const char *params[2];
|
||||
uint32 lsn_hi;
|
||||
uint32 lsn_lo;
|
||||
int ret;
|
||||
int i;
|
||||
XLogRecPtr startLsn;
|
||||
|
||||
params[0] = label;
|
||||
|
||||
|
|
@ -1068,7 +1079,33 @@ pg_start_backup(const char *label, bool smooth, pgBackup *backup,
|
|||
XLogDataFromLSN(ret, PQgetvalue(res, 0, 0), &lsn_hi, &lsn_lo);
|
||||
securec_check_for_sscanf_s(ret, 2, "\0", "\0");
|
||||
/* Calculate LSN */
|
||||
backup->start_lsn = ((uint64) lsn_hi )<< 32 | lsn_lo;
|
||||
startLsn = ((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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,13 +42,6 @@ const char *pgdata_exclude_dir[] =
|
|||
(const char *)"pg_stat_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(). */
|
||||
(const char *)"pg_dynshmem",
|
||||
|
||||
|
|
@ -68,7 +61,7 @@ const char *pgdata_exclude_dir[] =
|
|||
(const char *)"pg_subtrans",
|
||||
|
||||
/* end of list */
|
||||
NULL, /* pg_log will be set later */
|
||||
NULL, /* pg_log and pg_replslot will be set later */
|
||||
NULL
|
||||
};
|
||||
|
||||
|
|
@ -128,17 +121,20 @@ may be removed int the future */
|
|||
|
||||
static int pgCompareString(const void *str1, const void *str2);
|
||||
|
||||
static char dir_check_file(pgFile *file, bool backup_logs);
|
||||
static char dir_check_file(pgFile *file, bool backup_logs, bool backup_replslots);
|
||||
static char check_in_tablespace(pgFile *file, bool in_tablespace);
|
||||
static char check_db_dir(pgFile *file);
|
||||
static char check_digit_file(pgFile *file);
|
||||
static char check_nobackup_dir(pgFile *file);
|
||||
static void dir_list_file_internal(parray *files, pgFile *parent, const char *parent_dir,
|
||||
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,
|
||||
TablespaceList *list, const char *type);
|
||||
|
||||
char check_logical_replslot_dir(const char *rel_path);
|
||||
|
||||
/* Tablespace mapping */
|
||||
static TablespaceList tablespace_dirs = {NULL, NULL};
|
||||
/* Extra directories mapping */
|
||||
|
|
@ -538,7 +534,7 @@ db_map_entry_free(void *entry)
|
|||
void
|
||||
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,
|
||||
fio_location location)
|
||||
fio_location location, bool backup_replslots)
|
||||
{
|
||||
pgFile *file;
|
||||
|
||||
|
|
@ -565,7 +561,7 @@ dir_list_file(parray *files, const char *root, bool exclude, bool follow_symlink
|
|||
parray_append(files, file);
|
||||
|
||||
dir_list_file_internal(files, file, root, exclude, follow_symlink,
|
||||
backup_logs, skip_hidden, external_dir_num, location);
|
||||
backup_logs, skip_hidden, external_dir_num, location, backup_replslots);
|
||||
|
||||
if (!add_root)
|
||||
pgFileFree(file);
|
||||
|
|
@ -589,7 +585,7 @@ dir_list_file(parray *files, const char *root, bool exclude, bool follow_symlink
|
|||
* - datafiles
|
||||
*/
|
||||
static char
|
||||
dir_check_file(pgFile *file, bool backup_logs)
|
||||
dir_check_file(pgFile *file, bool backup_logs, bool backup_replslots)
|
||||
{
|
||||
int i;
|
||||
int sscanf_res;
|
||||
|
|
@ -652,6 +648,29 @@ dir_check_file(pgFile *file, bool backup_logs)
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 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);
|
||||
if (ret != -1) { /* -1 means need backup */
|
||||
return ret;
|
||||
|
|
@ -749,6 +768,35 @@ static char check_nobackup_dir(pgFile *file)
|
|||
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)
|
||||
{
|
||||
char ret = -1;
|
||||
|
|
@ -889,7 +937,8 @@ bool SkipSomeDirFile(pgFile *file, struct dirent *dent, bool skipHidden)
|
|||
static void
|
||||
dir_list_file_internal(parray *files, pgFile *parent, const char *parent_dir,
|
||||
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;
|
||||
struct dirent *dent;
|
||||
|
|
@ -937,7 +986,7 @@ dir_list_file_internal(parray *files, pgFile *parent, const char *parent_dir,
|
|||
|
||||
if (exclude)
|
||||
{
|
||||
check_res = dir_check_file(file, backup_logs);
|
||||
check_res = dir_check_file(file, backup_logs, backup_replslots);
|
||||
if (check_res == CHECK_FALSE)
|
||||
{
|
||||
/* Skip */
|
||||
|
|
@ -963,7 +1012,7 @@ dir_list_file_internal(parray *files, pgFile *parent, const char *parent_dir,
|
|||
*/
|
||||
if (S_ISDIR(file->mode))
|
||||
dir_list_file_internal(files, file, child, exclude, follow_symlink,
|
||||
backup_logs, skip_hidden, external_dir_num, location);
|
||||
backup_logs, skip_hidden, external_dir_num, location, backup_replslots);
|
||||
}
|
||||
|
||||
if (errno && errno != ENOENT)
|
||||
|
|
|
|||
|
|
@ -51,6 +51,7 @@ typedef struct
|
|||
bool exclusive_backup;
|
||||
bool skip_hidden;
|
||||
int external_dir_num;
|
||||
bool backup_replslots;
|
||||
} fio_list_dir_request;
|
||||
|
||||
typedef struct
|
||||
|
|
@ -1794,7 +1795,7 @@ cleanup:
|
|||
/* Compile the array of files located on remote machine in directory root */
|
||||
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 skip_hidden, int external_dir_num, bool backup_replslots)
|
||||
{
|
||||
fio_header hdr;
|
||||
fio_list_dir_request req;
|
||||
|
|
@ -1811,6 +1812,7 @@ void fio_list_dir(parray *files, const char *root, bool exclude,
|
|||
req.exclusive_backup = exclusive_backup;
|
||||
req.skip_hidden = skip_hidden;
|
||||
req.external_dir_num = external_dir_num;
|
||||
req.backup_replslots = backup_replslots;
|
||||
|
||||
hdr.cop = FIO_LIST_DIR;
|
||||
hdr.size = sizeof(req);
|
||||
|
|
@ -1870,7 +1872,14 @@ void fio_list_dir(parray *files, const char *root, bool exclude,
|
|||
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);
|
||||
}
|
||||
|
|
@ -1914,7 +1923,7 @@ static void fio_list_dir_impl(int out, char* buf)
|
|||
|
||||
dir_list_file(file_files, req->path, req->exclude, req->follow_symlink,
|
||||
req->add_root, req->backup_logs, req->skip_hidden,
|
||||
req->external_dir_num, FIO_LOCAL_HOST);
|
||||
req->external_dir_num, FIO_LOCAL_HOST, req->backup_replslots);
|
||||
|
||||
/* send information about files to the main process */
|
||||
for (i = 0; i < (int)parray_num(file_files); i++)
|
||||
|
|
|
|||
|
|
@ -163,5 +163,7 @@ extern z_off_t fio_gzseek(gzFile f, z_off_t offset, int whence);
|
|||
extern const char* fio_gzerror(gzFile file, int *errnum);
|
||||
#endif
|
||||
|
||||
extern char check_logical_replslot_dir(const char *rel_path);
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
|||
|
|
@ -154,6 +154,7 @@ void help_pg_probackup(void)
|
|||
printf(_(" [--remote-port=port] [--ssh-options=ssh_options]\n"));
|
||||
printf(_(" [--remote-libpath=libpath]\n"));
|
||||
printf(_(" [--ttl=interval] [--expire-time=time]\n"));
|
||||
printf(_(" [--backup-pg-replslot]\n"));
|
||||
printf(_(" [--help]\n"));
|
||||
|
||||
printf(_("\n %s restore -B backup-path --instance=instance_name\n"), PROGRAM_NAME);
|
||||
|
|
@ -420,6 +421,7 @@ static void help_backup(void)
|
|||
printf(_(" [--remote-port=port] [--ssh-options=ssh_options]\n"));
|
||||
printf(_(" [--remote-libpath=libpath]\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(_(" --instance=instance_name name of the instance\n"));
|
||||
|
|
@ -441,6 +443,7 @@ static void help_backup(void)
|
|||
printf(_(" --note=text add note to backup\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(_(" --backup-pg-replslot] backup of '%s' directory\n"), PG_REPLSLOT_DIR);
|
||||
|
||||
printf(_("\n Logging options:\n"));
|
||||
printf(_(" --log-level-console=log-level-console\n"));
|
||||
|
|
|
|||
|
|
@ -77,6 +77,7 @@ int rw_timeout = 0;
|
|||
|
||||
/* backup options */
|
||||
bool backup_logs = false;
|
||||
bool backup_replslots = false;
|
||||
bool smooth_checkpoint;
|
||||
char *remote_agent;
|
||||
static char *backup_note = NULL;
|
||||
|
|
@ -186,6 +187,7 @@ static ConfigOption cmd_options[] =
|
|||
{ 'b', 145, "wal", &delete_wal, SOURCE_CMD_STRICT },
|
||||
{ 'b', 146, "expired", &delete_expired, 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', 148, "compress", &compress_shortcut, SOURCE_CMD_STRICT },
|
||||
|
|
@ -550,7 +552,7 @@ static int do_actual_operate()
|
|||
elog(ERROR, "required parameter not specified: BACKUP_MODE "
|
||||
"(-b, --backup-mode)");
|
||||
|
||||
return do_backup(start_time, set_backup_params, no_validate, no_sync, backup_logs);
|
||||
return do_backup(start_time, set_backup_params, no_validate, no_sync, backup_logs, backup_replslots);
|
||||
}
|
||||
case RESTORE_CMD:
|
||||
return do_restore_or_validate(current.backup_id,
|
||||
|
|
|
|||
|
|
@ -69,6 +69,7 @@ extern const char *PROGRAM_FULL_PATH;
|
|||
#define HEADER_MAP "page_header_map"
|
||||
#define HEADER_MAP_TMP "page_header_map_tmp"
|
||||
#define PG_RELATIVE_TBLSPC_DIR "pg_location"
|
||||
#define PG_REPLSLOT_DIR "pg_replslot"
|
||||
|
||||
/* Timeout defaults */
|
||||
#define ARCHIVE_TIMEOUT_DEFAULT 300
|
||||
|
|
|
|||
|
|
@ -54,6 +54,9 @@ extern bool smooth_checkpoint;
|
|||
it will be backuped up in external dirs */
|
||||
extern parray *pgdata_nobackup_dir;
|
||||
|
||||
/* list of logical replication slots */
|
||||
extern parray *logical_replslot;
|
||||
|
||||
/* remote probackup options */
|
||||
extern char* remote_agent;
|
||||
|
||||
|
|
@ -89,7 +92,7 @@ extern const char *pgdata_exclude_dir[];
|
|||
|
||||
/* in backup.c */
|
||||
extern int do_backup(time_t start_time, pgSetBackupParams *set_backup_params,
|
||||
bool no_validate, bool no_sync, bool backup_logs);
|
||||
bool no_validate, bool no_sync, bool backup_logs, bool backup_replslots);
|
||||
extern BackupMode parse_backup_mode(const char *value);
|
||||
extern const char *deparse_backup_mode(BackupMode mode);
|
||||
extern void process_block_change(ForkNumber forknum, const RelFileNode rnode,
|
||||
|
|
@ -239,7 +242,8 @@ extern const char* deparse_compress_alg(int alg);
|
|||
/* in dir.c */
|
||||
extern void 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, 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,
|
||||
const char *data_dir,
|
||||
|
|
@ -432,7 +436,8 @@ extern int fio_send_file(const char *from_fullpath, const char *to_fullpath, FIL
|
|||
pgFile *file, char **errormsg);
|
||||
|
||||
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);
|
||||
|
||||
|
|
|
|||
|
|
@ -8641,7 +8641,7 @@
|
|||
),
|
||||
AddFuncGroup(
|
||||
"pg_stat_get_wal_senders", 1,
|
||||
AddBuiltinFunc(_0(3099), _1("pg_stat_get_wal_senders"), _2(0), _3(false), _4(true), _5(pg_stat_get_wal_senders), _6(2249), _7(PG_CATALOG_NAMESPACE), _8(BOOTSTRAP_SUPERUSERID), _9(INTERNALlanguageId), _10(1), _11(10), _12(0), _13(0), _14(false), _15(false), _16(false), _17(false), _18('s'), _19(0), _20(0), _21(22, 20, 23, 25, 25, 25, 25, 1184, 1184, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 23, 23, 25, 25), _22(22, 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o'), _23(22, "pid", "sender_pid", "local_role", "peer_role", "peer_state", "state", "catchup_start", "catchup_end", "sender_sent_location", "sender_write_location", "sender_flush_location", "sender_replay_location", "receiver_received_location", "receiver_write_location", "receiver_flush_location", "receiver_replay_location", "sync_percent", "sync_state", "sync_group", "sync_priority", "sync_most_available", "channel"), _24(NULL), _25("pg_stat_get_wal_senders"), _26(NULL), _27(NULL), _28(NULL), _29(0), _30(false), _31(NULL), _32(false), _33("statistics: information about currently active replication"), _34('f'), _35(NULL), _36(0), _37(false), _38(NULL), _39(NULL), _40(0))
|
||||
AddBuiltinFunc(_0(3099), _1("pg_stat_get_wal_senders"), _2(0), _3(false), _4(true), _5(pg_stat_get_wal_senders), _6(2249), _7(PG_CATALOG_NAMESPACE), _8(BOOTSTRAP_SUPERUSERID), _9(INTERNALlanguageId), _10(1), _11(10), _12(0), _13(0), _14(false), _15(false), _16(false), _17(false), _18('s'), _19(0), _20(0), _21(21, 20, 23, 25, 25, 25, 25, 1184, 1184, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 23, 25, 25), _22(21, 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o'), _23(21, "pid", "sender_pid", "local_role", "peer_role", "peer_state", "state", "catchup_start", "catchup_end", "sender_sent_location", "sender_write_location", "sender_flush_location", "sender_replay_location", "receiver_received_location", "receiver_write_location", "receiver_flush_location", "receiver_replay_location", "sync_percent", "sync_state", "sync_priority", "sync_most_available", "channel"), _24(NULL), _25("pg_stat_get_wal_senders"), _26(NULL), _27(NULL), _28(NULL), _29(0), _30(false), _31(NULL), _32(false), _33("statistics: information about currently active replication"), _34('f'), _35(NULL), _36(0), _37(false), _38(NULL), _39(NULL), _40(0))
|
||||
),
|
||||
AddFuncGroup(
|
||||
"pg_stat_get_wlm_ec_operator_info", 1,
|
||||
|
|
|
|||
|
|
@ -6230,7 +6230,7 @@ Datum GetPartBoundaryByTuple(Relation rel, HeapTuple tuple)
|
|||
return Timestamp2Boundarys(rel, Align2UpBoundary(value, partMap->intervalValue, boundaryTs));
|
||||
}
|
||||
|
||||
Oid AddNewIntervalPartition(Relation rel, void* insertTuple)
|
||||
Oid AddNewIntervalPartition(Relation rel, void* insertTuple, bool isDDL)
|
||||
{
|
||||
Relation pgPartRel = NULL;
|
||||
Oid newPartOid = InvalidOid;
|
||||
|
|
@ -6327,7 +6327,13 @@ Oid AddNewIntervalPartition(Relation rel, void* insertTuple)
|
|||
*/
|
||||
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;
|
||||
}
|
||||
|
|
@ -7113,7 +7119,7 @@ int lookupHBucketid(oidvector *buckets, int low, int2 bktId)
|
|||
* Description :
|
||||
* Notes :
|
||||
*/
|
||||
Oid heapTupleGetPartitionId(Relation rel, void *tuple)
|
||||
Oid heapTupleGetPartitionId(Relation rel, void *tuple, bool isDDL)
|
||||
{
|
||||
Oid partitionid = InvalidOid;
|
||||
|
||||
|
|
@ -7140,7 +7146,7 @@ Oid heapTupleGetPartitionId(Relation rel, void *tuple)
|
|||
(errcode(ERRCODE_NO_DATA_FOUND), errmsg("inserted partition key does not map to any table partition")));
|
||||
} break;
|
||||
case PART_AREA_INTERVAL: {
|
||||
return AddNewIntervalPartition(rel, tuple);
|
||||
return AddNewIntervalPartition(rel, tuple, isDDL);
|
||||
} break;
|
||||
case PART_AREA_LIST: {
|
||||
ereport(ERROR,
|
||||
|
|
|
|||
|
|
@ -47,7 +47,8 @@ static void InternalAggIsSupported(const char *aggName)
|
|||
"json_agg",
|
||||
"json_object_agg",
|
||||
"st_summarystatsagg",
|
||||
"st_union"
|
||||
"st_union",
|
||||
"wm_concat"
|
||||
};
|
||||
|
||||
uint len = lengthof(supportList);
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ static_assert(sizeof(false) == sizeof(char), "illegal bool size");
|
|||
static struct HTAB* nameHash = NULL;
|
||||
static struct HTAB* oidHash = NULL;
|
||||
|
||||
/* for b_sql_plugin */
|
||||
/* for dolphin */
|
||||
struct HTAB* b_nameHash = NULL;
|
||||
struct HTAB* b_oidHash = NULL;
|
||||
|
||||
|
|
@ -118,7 +118,7 @@ static const FuncGroup* NameHashTableAccess(HASHACTION action, const char* name,
|
|||
|
||||
Assert(name != NULL);
|
||||
|
||||
if (DB_IS_CMPT(B_FORMAT) && b_nameHash != NULL && u_sess->attr.attr_sql.b_sql_plugin) {
|
||||
if (DB_IS_CMPT(B_FORMAT) && b_nameHash != NULL && u_sess->attr.attr_sql.dolphin) {
|
||||
result = (HashEntryNameToFuncGroup *)hash_search(b_nameHash, &temp_name, action, &found);
|
||||
} else {
|
||||
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;
|
||||
Assert(oid > 0);
|
||||
|
||||
if (DB_IS_CMPT(B_FORMAT) && b_oidHash != NULL && u_sess->attr.attr_sql.b_sql_plugin) {
|
||||
if (DB_IS_CMPT(B_FORMAT) && b_oidHash != NULL && u_sess->attr.attr_sql.dolphin) {
|
||||
result = (HashEntryOidToBuiltinFunc *)hash_search(b_oidHash, &oid, action, &found);
|
||||
} else {
|
||||
result = (HashEntryOidToBuiltinFunc *)hash_search(oidHash, &oid, action, &found);
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ Subscription *GetSubscription(Oid subid, bool missing_ok)
|
|||
|
||||
/* Get slotname */
|
||||
datum = SysCacheGetAttr(SUBSCRIPTIONOID, tup, Anum_pg_subscription_subslotname, &isnull);
|
||||
if (unlikely(isnull)) {
|
||||
if (!isnull) {
|
||||
sub->slotname = pstrdup(NameStr(*DatumGetName(datum)));
|
||||
} else {
|
||||
sub->slotname = NULL;
|
||||
|
|
@ -92,10 +92,10 @@ Subscription *GetSubscription(Oid subid, bool missing_ok)
|
|||
|
||||
datum = SysCacheGetAttr(SUBSCRIPTIONOID, tup, Anum_pg_subscription_subbinary, &isnull);
|
||||
if (unlikely(isnull)) {
|
||||
ereport(ERROR, (errcode(ERRCODE_UNEXPECTED_NULL_VALUE),
|
||||
errmsg("null binary for subscription %u", subid)));
|
||||
sub->binary = false;
|
||||
} else {
|
||||
sub->binary = DatumGetBool(datum);
|
||||
}
|
||||
sub->binary = DatumGetBool(datum);
|
||||
|
||||
ReleaseSysCache(tup);
|
||||
|
||||
|
|
|
|||
|
|
@ -70,6 +70,7 @@
|
|||
|
||||
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
|
||||
* wherever possible to reduce the chance for silly typos. Note that these
|
||||
|
|
@ -401,24 +402,27 @@ THR_LOCAL bool skip_read_extern_fields = false;
|
|||
token = pg_strtok(&length); /* skip :fldname */ \
|
||||
local_node->fldname = _readBitmapset()
|
||||
|
||||
#define READ_TYPEINFO_FIELD(fldname) \
|
||||
do { \
|
||||
if (local_node->fldname >= FirstBootstrapObjectId) { \
|
||||
IF_EXIST(exprtypename) \
|
||||
{ \
|
||||
char* exprtypename = NULL; \
|
||||
char* exprtypenamespace = NULL; \
|
||||
token = pg_strtok(&length); \
|
||||
token = pg_strtok(&length); \
|
||||
exprtypename = nullable_string(token, length); \
|
||||
token = pg_strtok(&length); \
|
||||
token = pg_strtok(&length); \
|
||||
exprtypenamespace = nullable_string(token, length); \
|
||||
local_node->fldname = get_typeoid(get_namespace_oid(exprtypenamespace, false), exprtypename); \
|
||||
pfree_ext(exprtypename); \
|
||||
pfree_ext(exprtypenamespace); \
|
||||
} \
|
||||
} \
|
||||
#define READ_TYPEINFO_FIELD(fldname) \
|
||||
do { \
|
||||
if (local_node->fldname >= FirstBootstrapObjectId) { \
|
||||
IF_EXIST(exprtypename) \
|
||||
{ \
|
||||
char* exprtypename = NULL; \
|
||||
char* exprtypenamespace = NULL; \
|
||||
token = pg_strtok(&length); \
|
||||
token = pg_strtok(&length); \
|
||||
exprtypename = nullable_string(token, length); \
|
||||
token = pg_strtok(&length); \
|
||||
token = pg_strtok(&length); \
|
||||
exprtypenamespace = nullable_string(token, length); \
|
||||
/* No need to reset field on CN or singlenode, keep pg_strtok() for forward compatibility */ \
|
||||
if (IS_DATANODE_BUT_NOT_SINGLENODE) { \
|
||||
local_node->fldname = get_typeoid(get_namespace_oid(exprtypenamespace, false), exprtypename); \
|
||||
} \
|
||||
pfree_ext(exprtypename); \
|
||||
pfree_ext(exprtypenamespace); \
|
||||
} \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define READ_TYPEINFO(typePtr) \
|
||||
|
|
@ -493,9 +497,30 @@ THR_LOCAL bool skip_read_extern_fields = false;
|
|||
token = pg_strtok(&length); \
|
||||
token = pg_strtok(&length); \
|
||||
funcnamespace = nullable_string(token, length); \
|
||||
if (IS_PGXC_DATANODE && !skip_read_extern_fields) { \
|
||||
local_node->fldname = \
|
||||
get_func_oid(funcname, get_namespace_oid(funcnamespace, false), (Expr*)local_node); \
|
||||
bool notfound = false; \
|
||||
if (IS_DATANODE_BUT_NOT_SINGLENODE && !skip_read_extern_fields) { \
|
||||
Oid funcoid = InvalidOid; \
|
||||
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(funcnamespace); \
|
||||
|
|
@ -525,7 +550,7 @@ THR_LOCAL bool skip_read_extern_fields = false;
|
|||
token = pg_strtok(&length); \
|
||||
token = pg_strtok(&length); \
|
||||
oprrightname = nullable_string(token, length); \
|
||||
if (IS_PGXC_DATANODE) { \
|
||||
if (IS_DATANODE_BUT_NOT_SINGLENODE) { \
|
||||
namespaceId = get_namespace_oid(opnamespace, false); \
|
||||
oprleft = get_typeoid(namespaceId, oprleftname); \
|
||||
oprright = oprleft; \
|
||||
|
|
@ -568,7 +593,7 @@ THR_LOCAL bool skip_read_extern_fields = false;
|
|||
token = pg_strtok(&length); \
|
||||
token = pg_strtok(&length); \
|
||||
oprrightname = nullable_string(token, length); \
|
||||
if (IS_PGXC_DATANODE) { \
|
||||
if (IS_DATANODE_BUT_NOT_SINGLENODE) { \
|
||||
namespaceId = get_namespace_oid(opnamespace, false); \
|
||||
oprleft = get_typeoid(namespaceId, oprleftname); \
|
||||
oprright = oprleft; \
|
||||
|
|
@ -2126,14 +2151,21 @@ static FuncExpr* _readFuncExpr(void)
|
|||
ereport(ERROR, (errcode(ERRCODE_UNEXPECTED_NULL_VALUE), errmsg("NULL seqNamespace for nextval()")));
|
||||
}
|
||||
|
||||
if (!IS_PGXC_COORDINATOR && !skip_read_extern_fields) {
|
||||
Oid seqid = get_valid_relname_relid(seqNamespace, seqName);
|
||||
if (IS_DATANODE_BUT_NOT_SINGLENODE && !skip_read_extern_fields) {
|
||||
|
||||
Oid seqid = get_valid_relname_relid(seqNamespace, seqName, true);
|
||||
Const* firstArg = (Const*)linitial(local_node->args);
|
||||
if (OidIsValid(seqid)) {
|
||||
Const* firstArg = (Const*)linitial(local_node->args);
|
||||
if (firstArg != NULL) {
|
||||
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);
|
||||
|
|
|
|||
|
|
@ -1454,7 +1454,14 @@ FuncCandidateList sort_candidate_func_list(FuncCandidateList oldCandidates)
|
|||
}
|
||||
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);
|
||||
return sortedCandidates;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ void GlobalBaseDefCache::RemoveElemFromBucket(GlobalBaseEntry *base)
|
|||
if (is_relation) {
|
||||
GlobalRelationEntry *entry = (GlobalRelationEntry *)base;
|
||||
uint64 rel_size = GetRelEstimateSize(entry);
|
||||
pg_atomic_fetch_sub_u64(&m_base_space, rel_size);
|
||||
pg_atomic_fetch_sub_u64(&m_base_space, AllocSetContextUsedSpace(((AllocSet)entry->rel_mem_manager)));
|
||||
m_db_entry->MemoryEstimateSub(rel_size);
|
||||
} else {
|
||||
GlobalPartitionEntry *entry = (GlobalPartitionEntry *)base;
|
||||
|
|
@ -77,7 +77,7 @@ void GlobalBaseDefCache::AddHeadToBucket(Index hash_index, GlobalBaseEntry *base
|
|||
if (is_relation) {
|
||||
GlobalRelationEntry *entry = (GlobalRelationEntry *)base;
|
||||
uint64 rel_size = GetRelEstimateSize(entry);
|
||||
pg_atomic_fetch_add_u64(&m_base_space, rel_size);
|
||||
pg_atomic_fetch_add_u64(&m_base_space, AllocSetContextUsedSpace(((AllocSet)entry->rel_mem_manager)));
|
||||
m_db_entry->MemoryEstimateAdd(rel_size);
|
||||
} else {
|
||||
GlobalPartitionEntry *entry = (GlobalPartitionEntry *)base;
|
||||
|
|
@ -400,4 +400,4 @@ GlobalBaseDefCache::GlobalBaseDefCache(Oid db_oid, bool is_shared, GlobalSysDBCa
|
|||
m_base_space = 0;
|
||||
m_obj_locks = NULL;
|
||||
m_db_entry = entry;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -659,7 +659,27 @@ void GlobalSysDBCache::InitSysCacheRelIds()
|
|||
*/
|
||||
void GlobalSysDBCache::RefreshHotStandby()
|
||||
{
|
||||
if (!EnableGlobalSysCache()) {
|
||||
return;
|
||||
}
|
||||
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)
|
||||
|
|
@ -1272,9 +1292,18 @@ int ResizeHashBucket(int origin_nbucket, DynamicHashBucketStrategy strategy)
|
|||
return cc_nbuckets;
|
||||
}
|
||||
|
||||
void NotifyGscRecoveryStarted()
|
||||
{
|
||||
if (!EnableGlobalSysCache()) {
|
||||
return;
|
||||
}
|
||||
g_instance.global_sysdbcache.recovery_finished = false;
|
||||
|
||||
}
|
||||
|
||||
void NotifyGscRecoveryFinished()
|
||||
{
|
||||
if (EnableGlobalSysCache()) {
|
||||
g_instance.global_sysdbcache.recovery_finished = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
* 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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@ Partition LocalPartDefCache::SearchPartitionFromGlobalCopy(Oid part_oid)
|
|||
if (!g_instance.global_sysdbcache.hot_standby) {
|
||||
return NULL;
|
||||
}
|
||||
if (unlikely(!g_instance.global_sysdbcache.recovery_finished)) {
|
||||
if (unlikely(!IsPrimaryRecoveryFinished())) {
|
||||
return NULL;
|
||||
}
|
||||
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) {
|
||||
return false;
|
||||
}
|
||||
if (unlikely(!g_instance.global_sysdbcache.recovery_finished)) {
|
||||
if (unlikely(!IsPrimaryRecoveryFinished())) {
|
||||
return false;
|
||||
}
|
||||
if (g_instance.global_sysdbcache.StopInsertGSC()) {
|
||||
|
|
@ -456,4 +456,4 @@ Partition LocalPartDefCache::PartitionIdGetPartition(Oid part_oid, StorageType s
|
|||
}
|
||||
|
||||
return pd;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -433,7 +433,7 @@ LocalCatCTup *LocalSysTupCache::SearchTupleFromGlobal(Datum *arguments, uint32 h
|
|||
bool bypass_gsc = HistoricSnapshotActive() ||
|
||||
m_global_systupcache->enable_rls ||
|
||||
!g_instance.global_sysdbcache.hot_standby ||
|
||||
unlikely(!g_instance.global_sysdbcache.recovery_finished);
|
||||
unlikely(!IsPrimaryRecoveryFinished());
|
||||
if (invalid_entries.ExistTuple(hash_value) || bypass_gsc) {
|
||||
global_ct = m_global_systupcache->SearchTupleFromFile(hash_value, arguments, true);
|
||||
} else {
|
||||
|
|
@ -585,7 +585,7 @@ LocalCatCList *LocalSysTupCache::SearchListFromGlobal(int nkeys, Datum *argument
|
|||
bool bypass_gsc = HistoricSnapshotActive() ||
|
||||
m_global_systupcache->enable_rls ||
|
||||
!g_instance.global_sysdbcache.hot_standby ||
|
||||
unlikely(!g_instance.global_sysdbcache.recovery_finished);
|
||||
unlikely(!IsPrimaryRecoveryFinished());
|
||||
GlobalCatCList *global_cl;
|
||||
if (invalid_entries.ExistList() || bypass_gsc) {
|
||||
global_cl = m_global_systupcache->SearchListFromFile(hash_value, nkeys, arguments, true);
|
||||
|
|
@ -703,7 +703,7 @@ LocalCatCTup *LocalSysTupCache::SearchTupleFromGlobalForProcAllArgs(
|
|||
bool bypass_gsc = HistoricSnapshotActive() ||
|
||||
m_global_systupcache->enable_rls ||
|
||||
!g_instance.global_sysdbcache.hot_standby ||
|
||||
unlikely(!g_instance.global_sysdbcache.recovery_finished);
|
||||
unlikely(!IsPrimaryRecoveryFinished());
|
||||
if (invalid_entries.ExistTuple(hash_value) || bypass_gsc) {
|
||||
global_ct = m_global_systupcache->SearchTupleFromFileWithArgModes(hash_value, arguments, argModes, true);
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -93,7 +93,7 @@ Relation LocalTabDefCache::SearchRelationFromGlobalCopy(Oid rel_oid)
|
|||
if (!g_instance.global_sysdbcache.hot_standby) {
|
||||
return NULL;
|
||||
}
|
||||
if (unlikely(!g_instance.global_sysdbcache.recovery_finished)) {
|
||||
if (unlikely(!IsPrimaryRecoveryFinished())) {
|
||||
return NULL;
|
||||
}
|
||||
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) {
|
||||
return false;
|
||||
}
|
||||
if (unlikely(!g_instance.global_sysdbcache.recovery_finished)) {
|
||||
if (unlikely(!IsPrimaryRecoveryFinished())) {
|
||||
return false;
|
||||
}
|
||||
if (g_instance.global_sysdbcache.StopInsertGSC()) {
|
||||
|
|
@ -1137,4 +1137,4 @@ void LocalTabDefCache::ResetInitFlag()
|
|||
m_is_inited_phase3 = false;
|
||||
|
||||
m_db_id = InvalidOid;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1723,7 +1723,7 @@ char* get_relname_relid_extend(
|
|||
extern bool StreamTopConsumerAmI();
|
||||
|
||||
/* same as get_relname_relid except we check for cache invalidation here */
|
||||
Oid get_valid_relname_relid(const char* relnamespace, const char* relname)
|
||||
Oid get_valid_relname_relid(const char* relnamespace, const char* relname, bool nsp_missing_ok)
|
||||
{
|
||||
Oid nspid = InvalidOid;
|
||||
Oid oldnspid = InvalidOid;
|
||||
|
|
@ -1747,7 +1747,10 @@ Oid get_valid_relname_relid(const char* relnamespace, const char* relname)
|
|||
if (EnableLocalSysCache()) {
|
||||
thrd_inval_count = t_thrd.lsc_cxt.lsc->inval_cxt.SIMCounter;
|
||||
}
|
||||
nspid = get_namespace_oid(relnamespace, false);
|
||||
nspid = get_namespace_oid(relnamespace, nsp_missing_ok);
|
||||
if (!OidIsValid(nspid)) {
|
||||
return InvalidOid;
|
||||
}
|
||||
relid = get_relname_relid(relname, nspid);
|
||||
/*
|
||||
* In bootstrap processing mode, we don't bother with locking
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ bool open_join_children = true;
|
|||
bool will_shutdown = false;
|
||||
|
||||
/* hard-wired binary version number */
|
||||
const uint32 GRAND_VERSION_NUM = 92607;
|
||||
const uint32 GRAND_VERSION_NUM = 92606;
|
||||
|
||||
const uint32 PREDPUSH_SAME_LEVEL_VERSION_NUM = 92522;
|
||||
const uint32 UPSERT_WHERE_VERSION_NUM = 92514;
|
||||
|
|
@ -101,7 +101,7 @@ const uint32 PRIVS_DIRECTORY_VERSION_NUM = 92460;
|
|||
const uint32 COMMENT_RECORD_PARAM_VERSION_NUM = 92484;
|
||||
const uint32 SCAN_BATCH_MODE_VERSION_NUM = 92568;
|
||||
const uint32 PUBLICATION_VERSION_NUM = 92580;
|
||||
const uint32 SUBSCRIPTION_BINARY_VERSION_NUM = 92607;
|
||||
const uint32 SUBSCRIPTION_BINARY_VERSION_NUM = 92606;
|
||||
|
||||
/* Version number of the guc parameter backend_version added in V500R001C20 */
|
||||
const uint32 V5R1C20_BACKEND_VERSION_NUM = 92305;
|
||||
|
|
|
|||
|
|
@ -2712,8 +2712,8 @@ void PostgresInitializer::InitExtensionVariable()
|
|||
}
|
||||
|
||||
/* check whether the extension has been created */
|
||||
const char* b_sql_plugin = "b_sql_plugin";
|
||||
u_sess->attr.attr_sql.b_sql_plugin = CheckIfExtensionExists(b_sql_plugin);
|
||||
const char* dolphin = "dolphin";
|
||||
u_sess->attr.attr_sql.dolphin = CheckIfExtensionExists(dolphin);
|
||||
}
|
||||
|
||||
void PostgresInitializer::FinishInit()
|
||||
|
|
|
|||
|
|
@ -10340,7 +10340,16 @@ check_sql_expr(const char *stmt, int location, int leaderlen)
|
|||
|
||||
oldCxt = MemoryContextSwitchTo(u_sess->plsql_cxt.curr_compile_context->compile_tmp_cxt);
|
||||
u_sess->plsql_cxt.plpgsql_yylloc = plpgsql_yylloc;
|
||||
(void) raw_parser(stmt);
|
||||
RawParserHook parser_hook= raw_parser;
|
||||
#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);
|
||||
|
||||
/* Restore former ereport callback */
|
||||
|
|
|
|||
|
|
@ -44,11 +44,22 @@ static int g_iPosBlackList = 0;
|
|||
/* array store for black list */
|
||||
static BBOX_BLACKLIST_STRU g_stBlackList[BBOX_BLACK_LIST_COUNT_MAX];
|
||||
|
||||
/*
|
||||
* Determines whether the byte order of the local machine is large or small
|
||||
* return : ELFDATA2LSB - large
|
||||
* : ELFDATA2MSB - small
|
||||
*/
|
||||
/*
|
||||
function name: BBOX_DetermineMsb
|
||||
description: The function should judge the mode that PC uses to store data is Big-endian/Little-endian.
|
||||
arguments: void
|
||||
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)
|
||||
{
|
||||
union INT_PROBE {
|
||||
|
|
|
|||
|
|
@ -51,8 +51,19 @@ struct PIPE_IDS {
|
|||
static struct PIPE_IDS astPipeIds[BBOX_MAX_PIDS];
|
||||
|
||||
/*
|
||||
* compare string pszSrc and pszTarget
|
||||
*/
|
||||
function name: bbox_strncmp
|
||||
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)
|
||||
{
|
||||
signed char cRes = 0;
|
||||
|
|
@ -68,8 +79,20 @@ s32 bbox_strncmp(const char* pszSrc, const char* pszTarget, s32 count)
|
|||
}
|
||||
|
||||
/*
|
||||
* compare string pszSrc and pszTarget
|
||||
*/
|
||||
function name: bbox_strcmp
|
||||
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)
|
||||
{
|
||||
unsigned char c1, c2;
|
||||
|
|
@ -90,8 +113,15 @@ s32 bbox_strcmp(const char* pszSrc, const char* pszTarget)
|
|||
}
|
||||
|
||||
/*
|
||||
* get the length of string pszString
|
||||
*/
|
||||
function name: bbox_strlen
|
||||
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)
|
||||
{
|
||||
const char* pszTemp = NULL;
|
||||
|
|
@ -105,8 +135,16 @@ s32 bbox_strlen(const char* pszString)
|
|||
}
|
||||
|
||||
/*
|
||||
* get the length of string pszString
|
||||
*/
|
||||
function name: bbox_strnlen
|
||||
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)
|
||||
{
|
||||
const char* pszTemp = NULL;
|
||||
|
|
@ -119,8 +157,16 @@ s32 bbox_strnlen(const char* pszString, s32 count)
|
|||
}
|
||||
|
||||
/*
|
||||
* convert a string to interger
|
||||
*/
|
||||
function name: bbox_atoi
|
||||
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 n = 0;
|
||||
|
|
@ -140,10 +186,18 @@ s32 bbox_atoi(const char* pszString)
|
|||
|
||||
return iNeg ? -n : n;
|
||||
}
|
||||
|
||||
/*
|
||||
* compare memory
|
||||
*/
|
||||
function name: bbox_memcmp
|
||||
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)
|
||||
{
|
||||
const unsigned char *su1 = NULL;
|
||||
|
|
@ -159,8 +213,18 @@ s32 bbox_memcmp(const void* cs, const void* ct, s32 count)
|
|||
}
|
||||
|
||||
/*
|
||||
* search string l2 in l1
|
||||
*/
|
||||
function name: bbox_strstr
|
||||
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)
|
||||
{
|
||||
int l1, l2;
|
||||
|
|
@ -182,8 +246,17 @@ char* bbox_strstr(const char* s1, const char* s2)
|
|||
}
|
||||
|
||||
/*
|
||||
* make a directory
|
||||
*/
|
||||
function name: bbox_mkdir
|
||||
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)
|
||||
{
|
||||
char szDirName[BBOX_TMP_LEN_32 * 16];
|
||||
|
|
@ -228,8 +301,16 @@ s32 bbox_mkdir(const char* pszDir)
|
|||
}
|
||||
|
||||
/*
|
||||
* search free pipe id
|
||||
*/
|
||||
function name: bbox_GetFreePid
|
||||
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)
|
||||
{
|
||||
u32 i;
|
||||
|
|
@ -245,8 +326,14 @@ struct PIPE_ID* bbox_GetFreePid(void)
|
|||
}
|
||||
|
||||
/*
|
||||
* Release the occupied pipeid
|
||||
*/
|
||||
function name: bbox_PutPid
|
||||
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)
|
||||
{
|
||||
struct PIPE_IDS* pstPids = NULL;
|
||||
|
|
@ -261,8 +348,16 @@ void bbox_PutPid(struct PIPE_ID* pstPid)
|
|||
}
|
||||
|
||||
/*
|
||||
* find available pipe id by file handle
|
||||
*/
|
||||
function name: bbox_FindPid
|
||||
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)
|
||||
{
|
||||
u32 i;
|
||||
|
|
@ -281,8 +376,17 @@ struct PIPE_ID* bbox_FindPid(int iFd)
|
|||
}
|
||||
|
||||
/*
|
||||
* run popen
|
||||
*/
|
||||
function name: sys_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)
|
||||
{
|
||||
struct PIPE_ID* volatile stCurPid = NULL;
|
||||
|
|
@ -387,8 +491,15 @@ s32 sys_popen(char* pszCmd, const char* pszMode)
|
|||
}
|
||||
|
||||
/*
|
||||
* close file handle
|
||||
*/
|
||||
function name: sys_pclose
|
||||
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)
|
||||
{
|
||||
struct PIPE_ID* pstCur = NULL;
|
||||
|
|
@ -411,8 +522,17 @@ int sys_pclose(s32 iFd)
|
|||
}
|
||||
|
||||
/*
|
||||
* list file in directory
|
||||
*/
|
||||
function name: bbox_listdir
|
||||
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)
|
||||
{
|
||||
struct linux_dirent* pstEntry = NULL;
|
||||
|
|
|
|||
|
|
@ -57,23 +57,37 @@ void bbox_initlog(int iLogScreen)
|
|||
}
|
||||
|
||||
/*
|
||||
* convert int to string
|
||||
*/
|
||||
function name: bbox_itoc
|
||||
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)
|
||||
{
|
||||
return (char)((sNum < 10) ? (sNum + 48) : (sNum + 87));
|
||||
}
|
||||
|
||||
/*
|
||||
* convert int to string
|
||||
* in : pCallback - call back function
|
||||
* ptr - private data to call this function
|
||||
* piCount - offset pointer
|
||||
* iSize - buffer size
|
||||
* uNum - the variable to convert
|
||||
* sSys - type of variable
|
||||
* isNeg - is negative
|
||||
* return : need call back
|
||||
*/
|
||||
function name: bbox_put_dox
|
||||
description: Conversion of number systems.
|
||||
arguments: The first argument pCallback is a pointer to a callback function, we
|
||||
use it to reverse the final result. The second argument is a pointer of
|
||||
type void* used as a argument of function pCallback. The third argument
|
||||
piCount is a pointer of type int, an offset pointer, also be used as a argument
|
||||
of pCallback. The fourth argument is an integer of 32 bits, it indicates the buffer
|
||||
size pCallback uses.The fifth argument uNum is a decimal integer that will
|
||||
be converted to an integer in another radix. The sixth argument is used as
|
||||
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)
|
||||
{
|
||||
s64 i = 0;
|
||||
|
|
@ -114,7 +128,7 @@ s32 bbox_put_dox(BBOX_vnprintCallBack pCallback, void* ptr, s32* piCount, u32 iS
|
|||
* ptr - private data to call this function
|
||||
* iSize - buffer size
|
||||
* pFmt - format type
|
||||
* ap - parameter list pointer¸ñʽ
|
||||
* ap - parameter list pointer<EFBFBD><EFBFBD>ʽ
|
||||
* return : length of string
|
||||
*/
|
||||
s32 bbox_vsnprintf(BBOX_vnprintCallBack pCallback, void* ptr, s32 iSize, const char* pFmt, va_list ap)
|
||||
|
|
|
|||
|
|
@ -222,6 +222,7 @@ NON_EXEC_STATIC void PercentileMain()
|
|||
g_instance.stat_cxt.force_process = false;
|
||||
sleep(SLEEP_INTERVAL);
|
||||
}
|
||||
elog(LOG, "instrumention percentile ended");
|
||||
gs_thread_exit(0);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -14,11 +14,23 @@ import os
|
|||
|
||||
from . import feature_mapping
|
||||
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():
|
||||
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():
|
||||
return {
|
||||
|
|
|
|||
|
|
@ -11,22 +11,27 @@
|
|||
# MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
# See the Mulan PSL v2 for more details.
|
||||
import csv
|
||||
#import csv packet
|
||||
from collections import defaultdict
|
||||
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 packet as the name np
|
||||
|
||||
from ..analyzer import _euclid_distance as euclid_distance
|
||||
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:
|
||||
"""
|
||||
Calculate weight matrix based on feature set
|
||||
:param features: feature set
|
||||
:param labels: label set
|
||||
:return: weight_matrix
|
||||
"""
|
||||
normalize_features, normalize_labels = [], []
|
||||
features_labels_dict = defaultdict(list)
|
||||
for i in range(len(labels)):
|
||||
|
|
@ -56,6 +61,16 @@ def calculate_weight(features: np.ndarray, labels: np.ndarray) -> List:
|
|||
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')
|
||||
def build_model(feature_path: str, feature_number: int, feature_dimension: int,
|
||||
save_path: str = './features_new.npz') -> None:
|
||||
|
|
|
|||
|
|
@ -11,6 +11,13 @@
|
|||
# MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
# 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):
|
||||
if method == 'bool':
|
||||
|
|
|
|||
|
|
@ -12,17 +12,16 @@
|
|||
# See the Mulan PSL v2 for more details.
|
||||
|
||||
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'):
|
||||
"""
|
||||
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):
|
||||
raise TypeError("The format of the input data is wrong.")
|
||||
avg1 = sum(data1) / len(data1) if data1 else 0
|
||||
|
|
|
|||
|
|
@ -26,9 +26,11 @@ import logging
|
|||
try:
|
||||
from .dao.gsql_execute import GSqlExecute
|
||||
from .dao.execute_factory import ExecuteFactory
|
||||
from .mcts import MCTS
|
||||
except ImportError:
|
||||
from dao.gsql_execute import GSqlExecute
|
||||
from dao.execute_factory import ExecuteFactory
|
||||
from mcts import MCTS
|
||||
|
||||
ENABLE_MULTI_NODE = False
|
||||
SAMPLE_NUM = 5
|
||||
|
|
@ -192,9 +194,12 @@ class IndexAdvisor:
|
|||
self.workload_used_index))
|
||||
if DRIVER:
|
||||
self.db.close_conn()
|
||||
|
||||
opt_config = greedy_determine_opt_config(self.workload_info[0], atomic_config_total,
|
||||
candidate_indexes, self.index_cost_total[0])
|
||||
if MAX_INDEX_STORAGE:
|
||||
opt_config = MCTS(self.workload_info[0], atomic_config_total, candidate_indexes,
|
||||
MAX_INDEX_STORAGE, MAX_INDEX_NUM)
|
||||
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)
|
||||
if len(opt_config) == 0:
|
||||
print("No optimal indexes generated!")
|
||||
|
|
@ -943,7 +948,7 @@ def check_parameter(args):
|
|||
raise argparse.ArgumentTypeError("%s is an invalid positive int value" %
|
||||
args.max_index_num)
|
||||
if args.max_index_storage is not None and args.max_index_storage <= 0:
|
||||
raise argparse.ArgumentTypeError("%s is an invalid positive int value" %
|
||||
raise argparse.ArgumentTypeError("%s is an invalid positive float value" %
|
||||
args.max_index_storage)
|
||||
JSON_TYPE = args.json
|
||||
MAX_INDEX_NUM = args.max_index_num
|
||||
|
|
@ -971,7 +976,7 @@ def main(argv):
|
|||
arg_parser.add_argument(
|
||||
"--max_index_num", help="Maximum number of suggested indexes", type=int)
|
||||
arg_parser.add_argument("--max_index_storage",
|
||||
help="Maximum storage of suggested indexes/MB", type=int)
|
||||
help="Maximum storage of suggested indexes/MB", type=float)
|
||||
arg_parser.add_argument("--multi_iter_mode", action='store_true',
|
||||
help="Whether to use multi-iteration algorithm", default=False)
|
||||
arg_parser.add_argument("--multi_node", action='store_true',
|
||||
|
|
|
|||
|
|
@ -0,0 +1,397 @@
|
|||
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
|
||||
|
|
@ -539,13 +539,14 @@ class RnnModel():
|
|||
keras.backend.clear_session()
|
||||
set_session(self.session)
|
||||
with self.graph.as_default():
|
||||
# Judge whether the model needs to be initialized according to the changes of the model input and output dimensions.
|
||||
feature, label, need_init = self.parse(filename)
|
||||
os.environ['CUDA_VISIBLE_DEVICES'] = '0'
|
||||
epsilon = self.model_info.make_epsilon()
|
||||
if need_init:
|
||||
if need_init:# Cold start training
|
||||
epoch_start = 0
|
||||
self.model = self._build_model(epsilon)
|
||||
else:
|
||||
else:# Incremental training
|
||||
epoch_start = int(self.model_info.last_epoch)
|
||||
ratio_error = ratio_error_loss_wrapper(epsilon)
|
||||
ratio_acc_2 = ratio_error_acc_wrapper(epsilon, 2)
|
||||
|
|
@ -556,12 +557,16 @@ class RnnModel():
|
|||
log_path = os.path.realpath(os.path.join(settings.PATH_LOG, self.model_info.model_name + '_log.json'))
|
||||
if not os.path.exists(log_path):
|
||||
os.mknod(log_path, mode=0o600)
|
||||
# Training logging callback function
|
||||
json_logging_callback = LossHistory(log_path, self.model_info.model_name, self.model_info.last_epoch)
|
||||
# Data segmentation
|
||||
X_train, X_val, y_train, y_val = \
|
||||
train_test_split(feature, label, test_size=0.1)
|
||||
# model training
|
||||
self.model.fit(X_train, y_train, epochs=self.model_info.last_epoch,
|
||||
batch_size=int(self.model_info.batch_size), validation_data=(X_val, y_val),
|
||||
verbose=0, initial_epoch=epoch_start, callbacks=[json_logging_callback])
|
||||
# save model
|
||||
self.model.save(self.model_info.model_path)
|
||||
val_pred = self.model.predict(X_val)
|
||||
val_re = get_ratio_errors_general(val_pred, y_val, epsilon)
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ from . import AbstractModel
|
|||
|
||||
|
||||
class TemplateModel(AbstractModel):
|
||||
# Initialize algorithm parameters
|
||||
def __init__(self, params):
|
||||
super().__init__(params)
|
||||
self.bias = 1e-5
|
||||
|
|
|
|||
|
|
@ -173,11 +173,16 @@ def procedure_main(mode, db_info, config):
|
|||
def rl_model(mode, env, config):
|
||||
# Lazy loading. Because loading Tensorflow takes a long time.
|
||||
from tuner.algorithms.rl_agent import RLAgent
|
||||
# Start reinforcement learning agent class.
|
||||
rl = RLAgent(env, alg=config['rl_algorithm'])
|
||||
# The two modes of training and tuning correspond to different execution processes.
|
||||
# The model needs to be trained before it can be used for tuning. The output of the training and tuning process is the list of parameters to be tuned. Because they share a set of models, it is required that the list of parameters to be tuned must be consistent in the two modes, otherwise exceptions with different output dimensions will be thrown.
|
||||
if mode == 'train':
|
||||
logging.warning('The list of tuned knobs in the training mode '
|
||||
'based on the reinforcement learning algorithm must be the same as '
|
||||
'that in the tuning mode. ')
|
||||
# The key parameter is the maximum iteration round rl_ steps, theoretically, the longer the more accurate, but also more time-consuming.
|
||||
# max_episode_steps is the maximum number of rounds in each round of reinforcement learning algorithm. In the implementation of x-tuner, this parameter is weakened, and it is generally default.
|
||||
rl.fit(config['rl_steps'], nb_max_episode_steps=config['max_episode_steps'])
|
||||
rl.save(config['rl_model_path'])
|
||||
logging.info('Saved reinforcement learning model at %s.', config['rl_model_path'])
|
||||
|
|
@ -200,6 +205,7 @@ def rl_model(mode, env, config):
|
|||
|
||||
def global_search(env, config):
|
||||
method = config['gop_algorithm']
|
||||
# Determine which algorithm to use.
|
||||
if method == 'bayes':
|
||||
from bayes_opt import BayesianOptimization
|
||||
|
||||
|
|
@ -207,6 +213,13 @@ def global_search(env, config):
|
|||
pbound = {name: (0, 1) for name in env.db.ordered_knob_list}
|
||||
|
||||
def performance_function(**params):
|
||||
"""
|
||||
function name: performance_function
|
||||
description: Define a black box function to adapt to the interface of the third-party library.
|
||||
author: Li Xinran
|
||||
date: 2022/8/4
|
||||
contact: 19154068808
|
||||
"""
|
||||
if not len(params) == env.nb_actions:
|
||||
raise AssertionError('Failed to check the input feature dimension.')
|
||||
|
||||
|
|
@ -222,12 +235,21 @@ def global_search(env, config):
|
|||
pbounds=pbound
|
||||
)
|
||||
optimizer.maximize(
|
||||
# The larger the maximum iteration round, the more accurate the result is, but it is also more time-consuming.
|
||||
n_iter=config['max_iterations']
|
||||
)
|
||||
elif method == 'pso':
|
||||
from tuner.algorithms.pso import Pso
|
||||
|
||||
def performance_function(v):
|
||||
"""
|
||||
function name: performance_function
|
||||
description: Find the global minimum value.
|
||||
note: Because the implementation of PSO algorithm is to find the global minimum value, take the opposite number here, so we need to change to take the global maximum value.
|
||||
author: Li Xinran
|
||||
date: 2022/8/4
|
||||
contact: 19154068808
|
||||
"""
|
||||
s, r, d, _ = env.step(v)
|
||||
return -r # Use -reward because PSO wishes to minimize.
|
||||
|
||||
|
|
@ -237,6 +259,7 @@ def global_search(env, config):
|
|||
particle_nums=config['particle_nums'],
|
||||
# max_iterations on the PSO indicates the maximum number of iterations per particle,
|
||||
# so it must be divided by the number of particles to be consistent with Bayes.
|
||||
# The larger the maximum iteration round is, the more accurate the result is, but also the more time-consuming.
|
||||
max_iteration=config['max_iterations'] // config['particle_nums'],
|
||||
x_min=0, x_max=1, max_vel=0.5
|
||||
)
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ from collections.abc import Iterable
|
|||
from collections import defaultdict
|
||||
|
||||
import index_advisor_workload as iaw
|
||||
import mcts
|
||||
|
||||
|
||||
def hash_any(obj):
|
||||
|
|
@ -227,6 +228,32 @@ select * from student_range_part1 where credit=1;
|
|||
|
||||
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):
|
||||
tables = 'table1 table2 table2 table3 table3 table3'.split()
|
||||
columns = 'col1,col2 col2 col3 col1,col2 col2,col3 col2,col5'.split()
|
||||
|
|
|
|||
|
|
@ -90,7 +90,10 @@ static void DropExtensionInListIsSupported(List* objname)
|
|||
}
|
||||
}
|
||||
|
||||
ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("EXTENSION is not yet supported.")));
|
||||
/* Enable DROP operation of the above objects during inplace upgrade or support_extended_features is true */
|
||||
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.");
|
||||
}
|
||||
|
||||
if (pg_strcasecmp(stmt->extname, "b_sql_plugin") == 0 && !DB_IS_CMPT(B_FORMAT)) {
|
||||
if (pg_strcasecmp(stmt->extname, "dolphin") == 0 && !DB_IS_CMPT(B_FORMAT)) {
|
||||
ereport(ERROR,
|
||||
(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;
|
||||
|
||||
if (pg_strcasecmp(stmt->extname, "b_sql_plugin") == 0) {
|
||||
u_sess->attr.attr_sql.b_sql_plugin = true;
|
||||
if (pg_strcasecmp(stmt->extname, "dolphin") == 0) {
|
||||
u_sess->attr.attr_sql.dolphin = true;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -23175,7 +23175,7 @@ static void checkValidationForExchangeTable(Relation partTableRel, Relation ordT
|
|||
int2 bucketId = InvalidBktId;
|
||||
|
||||
// get right partition oid for the tuple
|
||||
targetPartOid = heapTupleGetPartitionId(partTableRel, (HeapTuple) tuple);
|
||||
targetPartOid = heapTupleGetPartitionId(partTableRel, (HeapTuple)tuple, true);
|
||||
|
||||
searchFakeReationForPartitionOid(
|
||||
partRelHTAB, CurrentMemoryContext, partTableRel, targetPartOid, partRel, part, RowExclusiveLock);
|
||||
|
|
@ -24797,7 +24797,8 @@ static Oid AddTemporaryPartitionForAlterPartitions(const AlterTableCmd* cmd, Rel
|
|||
destPartOid = AddTemporaryHashPartitionForAlterPartitions(cmd, partTableRel, partSeq, renameTargetPart);
|
||||
break;
|
||||
}
|
||||
case PART_TYPE_RANGE: {
|
||||
case PART_TYPE_RANGE:
|
||||
case PART_TYPE_INTERVAL: {
|
||||
destPartOid = AddTemporaryRangePartitionForAlterPartitions(cmd, partTableRel, partSeq, renameTargetPart);
|
||||
break;
|
||||
}
|
||||
|
|
@ -25098,11 +25099,11 @@ static void readTuplesAndInsertInternal(Relation tempTableRel, Relation partTabl
|
|||
|
||||
/* tableam_tops_copy_tuple is not ready so we add UStore hack path */
|
||||
copyTuple = tableam_tops_copy_tuple(tuple);
|
||||
targetPartOid = heapTupleGetPartitionId(partTableRel, (void *)tuple);
|
||||
targetPartOid = heapTupleGetPartitionId(partTableRel, (void *)tuple, true);
|
||||
searchFakeReationForPartitionOid(
|
||||
partRelHTAB, CurrentMemoryContext, partTableRel, targetPartOid, partRel, part, RowExclusiveLock);
|
||||
if (RelationIsSubPartitioned(partTableRel)) {
|
||||
targetPartOid = heapTupleGetPartitionId(partRel, (void *)tuple);
|
||||
targetPartOid = heapTupleGetPartitionId(partRel, (void *)tuple, true);
|
||||
searchFakeReationForPartitionOid(partRelHTAB, CurrentMemoryContext, partRel, targetPartOid, subPartRel,
|
||||
subPart, RowExclusiveLock);
|
||||
partRel = subPartRel;
|
||||
|
|
|
|||
|
|
@ -1181,6 +1181,17 @@ static Node* pull_up_simple_subquery(PlannerInfo* root, Node* jtnode, RangeTblEn
|
|||
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
|
||||
* 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();
|
||||
|
||||
candidate_num = get_curr_candidate_nums(false) + get_curr_candidate_nums(true);
|
||||
if (candidate_num == 0) {
|
||||
if (candidate_num == 0 && !t_thrd.pagewriter_cxt.shutdown_requested) {
|
||||
/* wakeup sub thread scan the buffer pool, init the candidate list */
|
||||
wakeup_sub_thread();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -825,13 +825,10 @@ void client_read_ended(void)
|
|||
#define INIT_PLUGIN_OBJECT "init_plugin_object"
|
||||
void InitBSqlPluginHookIfNeeded()
|
||||
{
|
||||
const char* b_sql_plugin = "b_sql_plugin";
|
||||
const char* dolphin = "dolphin";
|
||||
CFunInfo tmpCF;
|
||||
if (!CheckIfExtensionExists(b_sql_plugin)) {
|
||||
return;
|
||||
}
|
||||
|
||||
tmpCF = load_external_function(b_sql_plugin, INIT_PLUGIN_OBJECT, false, false);
|
||||
tmpCF = load_external_function(dolphin, INIT_PLUGIN_OBJECT, false, false);
|
||||
if (tmpCF.user_fn != NULL) {
|
||||
((void* (*)(void))(tmpCF.user_fn))();
|
||||
}
|
||||
|
|
@ -865,9 +862,11 @@ List* pg_parse_query(const char* query_string, List** query_string_locationlist)
|
|||
|
||||
List* (*parser_hook)(const char*, List**) = raw_parser;
|
||||
#ifndef ENABLE_MULTIPLE_NODES
|
||||
int id = GetCustomParserId();
|
||||
if (id >= 0 && g_instance.raw_parser_hook[id] != NULL) {
|
||||
parser_hook = (List* (*)(const char*, List**))g_instance.raw_parser_hook[id];
|
||||
if (u_sess->attr.attr_sql.dolphin) {
|
||||
int id = GetCustomParserId();
|
||||
if (id >= 0 && g_instance.raw_parser_hook[id] != NULL) {
|
||||
parser_hook = (List* (*)(const char*, List**))g_instance.raw_parser_hook[id];
|
||||
}
|
||||
}
|
||||
#endif
|
||||
raw_parsetree_list = parser_hook(query_string, query_string_locationlist);
|
||||
|
|
@ -6115,6 +6114,9 @@ void ProcessInterrupts(void)
|
|||
|
||||
/* The logical replication launcher can be stopped at any time. */
|
||||
proc_exit(0);
|
||||
} else if (IsLogicalWorker()) {
|
||||
ereport(FATAL, (errcode(ERRCODE_ADMIN_SHUTDOWN),
|
||||
errmsg("terminating logical replication worker due to administrator command")));
|
||||
#endif
|
||||
} else if (IsTxnSnapCapturerProcess()) {
|
||||
ereport(FATAL,
|
||||
|
|
@ -7572,7 +7574,7 @@ int PostgresMain(int argc, char* argv[], const char* dbname, const char* usernam
|
|||
init_set_params_htab();
|
||||
|
||||
#ifndef ENABLE_MULTIPLE_NODES
|
||||
if (u_sess->proc_cxt.MyDatabaseId != InvalidOid && DB_IS_CMPT(B_FORMAT)) {
|
||||
if (u_sess->proc_cxt.MyDatabaseId != InvalidOid && DB_IS_CMPT(B_FORMAT) && u_sess->attr.attr_sql.dolphin) {
|
||||
InitBSqlPluginHookIfNeeded();
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -848,7 +848,7 @@ static bool InitSession(knl_session_context* session)
|
|||
t_thrd.proc_cxt.PostInit->InitSession();
|
||||
|
||||
#ifndef ENABLE_MULTIPLE_NODES
|
||||
if (u_sess->proc_cxt.MyDatabaseId != InvalidOid && DB_IS_CMPT(B_FORMAT)) {
|
||||
if (u_sess->proc_cxt.MyDatabaseId != InvalidOid && DB_IS_CMPT(B_FORMAT) && u_sess->attr.attr_sql.dolphin) {
|
||||
InitBSqlPluginHookIfNeeded();
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -720,7 +720,6 @@ static Datum ExecEvalWholeRowVar(
|
|||
{
|
||||
Var* variable = (Var*)wrvstate->xprstate.expr;
|
||||
TupleTableSlot* slot = NULL;
|
||||
TupleDesc slot_tupdesc;
|
||||
bool needslow = false;
|
||||
|
||||
if (isDone != NULL)
|
||||
|
|
@ -802,21 +801,13 @@ static Datum ExecEvalWholeRowVar(
|
|||
if (wrvstate->wrv_junkFilter != NULL)
|
||||
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
|
||||
* actual tuple type is compatible with it.
|
||||
*/
|
||||
if (variable->vartype == RECORDOID) {
|
||||
if (slot_tupdesc->tdtypeid == RECORDOID && slot_tupdesc->tdtypmod < 0)
|
||||
assign_record_type_typmod(slot_tupdesc);
|
||||
} else {
|
||||
if (variable->vartype != RECORDOID) {
|
||||
TupleDesc var_tupdesc;
|
||||
TupleDesc slot_tupdesc;
|
||||
int i;
|
||||
|
||||
/*
|
||||
|
|
@ -833,6 +824,8 @@ static Datum ExecEvalWholeRowVar(
|
|||
*/
|
||||
var_tupdesc = lookup_rowtype_tupdesc(variable->vartype, -1);
|
||||
|
||||
slot_tupdesc = slot->tts_tupleDescriptor;
|
||||
|
||||
if (var_tupdesc->natts != slot_tupdesc->natts)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_DATATYPE_MISMATCH),
|
||||
|
|
@ -886,6 +879,7 @@ static Datum ExecEvalWholeRowFast(
|
|||
{
|
||||
Var* variable = (Var*)wrvstate->xprstate.expr;
|
||||
TupleTableSlot* slot = NULL;
|
||||
TupleDesc slot_tupdesc;
|
||||
HeapTuple tuple;
|
||||
TupleDesc tupleDesc;
|
||||
HeapTupleHeader dtuple;
|
||||
|
|
@ -915,6 +909,17 @@ static Datum ExecEvalWholeRowFast(
|
|||
if (wrvstate->wrv_junkFilter != NULL)
|
||||
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);
|
||||
tupleDesc = slot->tts_tupleDescriptor;
|
||||
|
||||
|
|
|
|||
|
|
@ -322,7 +322,6 @@ static bool RelationFindReplTupleByIndex(EState *estate, Relation rel, Relation
|
|||
}
|
||||
if (found) {
|
||||
/* Found tuple, try to lock it in the lockmode. */
|
||||
outslot->tts_tuple = ExecMaterializeSlot(outslot);
|
||||
xwait = TransactionIdIsValid(snap.xmin) ? snap.xmin : snap.xmax;
|
||||
/*
|
||||
* If the tuple is locked, wait for locking transaction to finish
|
||||
|
|
@ -346,12 +345,16 @@ static bool RelationFindReplTupleByIndex(EState *estate, Relation rel, Relation
|
|||
ItemPointer tid = tableam_tops_get_t_self(targetRel, outslot->tts_tuple);
|
||||
|
||||
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);
|
||||
rc = memset_s(&tbuf, sizeof(tbuf), 0, sizeof(tbuf));
|
||||
securec_check(rc, "\0", "\0");
|
||||
UHeaplocktup.disk_tuple = &tbuf.hdr;
|
||||
locktup = &UHeaplocktup;
|
||||
} else {
|
||||
/* materialize the slot, so we can visit it after the scan is end */
|
||||
outslot->tts_tuple = ExecMaterializeSlot(outslot);
|
||||
ItemPointerCopy(tid, &heaplocktup.t_self);
|
||||
locktup = &heaplocktup;
|
||||
}
|
||||
|
|
@ -401,6 +404,10 @@ static bool tuple_equals_slot(TupleDesc desc, const Tuple tup, TupleTableSlot *s
|
|||
/* Check equality of the attributes. */
|
||||
for (attrnum = 0; attrnum < desc->natts; attrnum++) {
|
||||
TypeCacheEntry *typentry;
|
||||
/* skip generate column */
|
||||
if (GetGeneratedCol(desc, attrnum)) {
|
||||
continue;
|
||||
}
|
||||
/*
|
||||
* If one value is NULL and other is not, then they are certainly not
|
||||
* equal
|
||||
|
|
@ -478,7 +485,6 @@ static bool RelationFindReplTupleSeq(Relation rel, LockTupleMode lockmode, Tuple
|
|||
|
||||
found = true;
|
||||
ExecStoreTuple(scantuple, outslot, InvalidBuffer, false);
|
||||
outslot->tts_tuple = ExecMaterializeSlot(outslot);
|
||||
|
||||
xwait = TransactionIdIsValid(snap.xmin) ? snap.xmin : snap.xmax;
|
||||
/*
|
||||
|
|
@ -511,12 +517,16 @@ static bool RelationFindReplTupleSeq(Relation rel, LockTupleMode lockmode, Tuple
|
|||
ItemPointer tid = tableam_tops_get_t_self(rel, outslot->tts_tuple);
|
||||
|
||||
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);
|
||||
rc = memset_s(&tbuf, sizeof(tbuf), 0, sizeof(tbuf));
|
||||
securec_check(rc, "\0", "\0");
|
||||
UHeaplocktup.disk_tuple = &tbuf.hdr;
|
||||
locktup = &UHeaplocktup;
|
||||
} else {
|
||||
/* materialize the slot, so we can visit it after the scan is end */
|
||||
outslot->tts_tuple = ExecMaterializeSlot(outslot);
|
||||
ItemPointerCopy(tid, &heaplocktup.t_self);
|
||||
locktup = &heaplocktup;
|
||||
}
|
||||
|
|
@ -653,7 +663,6 @@ void ExecSimpleRelationUpdate(EState *estate, EPQState *epqstate, TupleTableSlot
|
|||
/* Compute stored generated columns */
|
||||
if (rel->rd_att->constr && rel->rd_att->constr->has_generated_stored) {
|
||||
ExecComputeStoredGenerated(resultRelInfo, estate, slot, tuple, CMD_UPDATE);
|
||||
tuple = slot->tts_tuple;
|
||||
}
|
||||
|
||||
/* Check the constraints of the tuple */
|
||||
|
|
@ -672,10 +681,11 @@ void ExecSimpleRelationUpdate(EState *estate, EPQState *epqstate, TupleTableSlot
|
|||
rowMovement = true;
|
||||
}
|
||||
|
||||
tuple = slot->tts_tuple;
|
||||
CommandId cid = GetCurrentCommandId(true);
|
||||
/* OK, update the tuple and index entries for it */
|
||||
if (!rowMovement) {
|
||||
res = tableam_tuple_update(targetRelation, parentRelation, searchSlotTid, slot->tts_tuple, cid,
|
||||
res = tableam_tuple_update(targetRelation, parentRelation, searchSlotTid, tuple, cid,
|
||||
InvalidSnapshot, estate->es_snapshot, true, &oldslot, &tmfd, &updateIndexes, &modifiedIdxAttrs,
|
||||
false, allowInplaceUpdate);
|
||||
CheckTupleModifyRes(res);
|
||||
|
|
|
|||
|
|
@ -2947,9 +2947,9 @@ void SetOneOfCompressOption(DefElem* defElem, TableCreateSupport* tableCreateSup
|
|||
} else if (pg_strcasecmp(defname, "compress_level") == 0) {
|
||||
tableCreateSupport->compressLevel = true;
|
||||
} else if (pg_strcasecmp(defname, "compress_byte_convert") == 0) {
|
||||
tableCreateSupport->compressByteConvert = true;
|
||||
tableCreateSupport->compressByteConvert = defGetBoolean(defElem);
|
||||
} else if (pg_strcasecmp(defname, "compress_diff_convert") == 0) {
|
||||
tableCreateSupport->compressDiffConvert = true;
|
||||
tableCreateSupport->compressDiffConvert = defGetBoolean(defElem);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1278,13 +1278,10 @@ static const char *MXStatusToString(MultiXactStatus status)
|
|||
|
||||
static char *mxid_to_string(MultiXactId multi, int nmembers, MultiXactMember *members)
|
||||
{
|
||||
static char *str = NULL;
|
||||
char *str = NULL;
|
||||
StringInfoData buf;
|
||||
int i;
|
||||
|
||||
if (str != NULL)
|
||||
pfree(str);
|
||||
|
||||
initStringInfo(&buf);
|
||||
|
||||
appendStringInfo(&buf, XID_FMT " %d[" XID_FMT " (%s)", multi, nmembers,
|
||||
|
|
@ -1295,7 +1292,7 @@ static char *mxid_to_string(MultiXactId multi, int nmembers, MultiXactMember *me
|
|||
}
|
||||
|
||||
appendStringInfoChar(&buf, ']');
|
||||
str = MemoryContextStrdup(TopMemoryContext, buf.data);
|
||||
str = MemoryContextStrdup(SESS_GET_MEM_CXT_GROUP(MEMORY_CONTEXT_STORAGE), buf.data);
|
||||
pfree(buf.data);
|
||||
return str;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8965,6 +8965,8 @@ void StartupXLOG(void)
|
|||
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);
|
||||
|
||||
NotifyGscRecoveryStarted();
|
||||
|
||||
/*
|
||||
* Initialize WAL insert status array and the flush index - lastWalStatusEntryFlushed.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -1818,3 +1818,47 @@ void UHeapSlotStoreUHeapTuple(UHeapTuple utuple, TupleTableSlot *slot, bool shou
|
|||
/* Mark extracted state invalid */
|
||||
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,15 +238,19 @@ public:
|
|||
return m_purpose;
|
||||
}
|
||||
|
||||
void GcStartTxnMTtests()
|
||||
GcEpochType GcStartInnerTxn()
|
||||
{
|
||||
if (m_gcEpoch != GetGlobalEpoch())
|
||||
m_gcEpoch = GetGlobalEpoch();
|
||||
m_gcEpoch = GetGlobalEpoch();
|
||||
|
||||
return m_gcEpoch;
|
||||
}
|
||||
|
||||
void GcEndTxnMTtests()
|
||||
void GcEndInnerTxn(bool clean_gc)
|
||||
{
|
||||
RunQuicese();
|
||||
if (clean_gc) {
|
||||
RunQuicese();
|
||||
}
|
||||
m_gcEpoch = 0;
|
||||
}
|
||||
|
||||
void GcStartTxn()
|
||||
|
|
@ -272,6 +276,7 @@ public:
|
|||
RunQuicese();
|
||||
m_managerLock.unlock();
|
||||
}
|
||||
m_gcEpoch = 0;
|
||||
m_isTxnStarted = false;
|
||||
}
|
||||
|
||||
|
|
@ -313,7 +318,6 @@ public:
|
|||
{
|
||||
if (m_performGcEpoch != g_gcActiveEpoch)
|
||||
HardQuiesce(m_rcuFreeCount);
|
||||
m_gcEpoch = 0;
|
||||
}
|
||||
|
||||
/** @brief Clean all object at the end of the session */
|
||||
|
|
|
|||
|
|
@ -258,6 +258,15 @@ bool Index::IndexInsert(Sentinel*& outputSentinel, const Key* key, uint32_t pid,
|
|||
outputSentinel = IndexInsertImpl(key, sentinel, inserted, pid);
|
||||
// sync between rollback/delete and insert
|
||||
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
|
||||
if (outputSentinel->RefCountUpdate(INC, pid) == RC_OK)
|
||||
retryInsert = false;
|
||||
|
|
@ -300,8 +309,16 @@ Sentinel* Index::IndexInsert(const Key* key, Row* row, uint32_t pid)
|
|||
// no need to report to full error stack
|
||||
SetLastError(MOT_ERROR_UNIQUE_VIOLATION, MOT_SEVERITY_NORMAL);
|
||||
m_sentinelPool->Release<Sentinel>(sentinel);
|
||||
sentinel = nullptr;
|
||||
return nullptr;
|
||||
} 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) {
|
||||
sentinel->SetPrimaryIndex();
|
||||
sentinel->SetNextPtr(row);
|
||||
|
|
@ -343,9 +360,6 @@ Sentinel* Index::IndexReadHeader(const Key* key, uint32_t pid) const
|
|||
Sentinel* Index::IndexRemove(const Key* key, uint32_t pid)
|
||||
{
|
||||
Sentinel* sentinel = IndexRemoveImpl(key, pid);
|
||||
|
||||
MOT_ASSERT(sentinel != nullptr);
|
||||
MOT_ASSERT(sentinel->GetCounter() == 0);
|
||||
return sentinel;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -56,12 +56,22 @@ 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
|
||||
leaf
|
||||
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.
|
||||
Unlocking the node and enter the key into the permutation will be done
|
||||
later in finish_insert (called from lp.finish). */
|
||||
later in finish_insert (done in lp.finish function). */
|
||||
|
||||
bool found = lp.find_insert(*mtSessionThreadInfo);
|
||||
bool found = false;
|
||||
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
|
||||
// that key
|
||||
|
|
|
|||
|
|
@ -33,15 +33,15 @@ namespace Masstree {
|
|||
template <typename P>
|
||||
struct gc_layer_rcu_callback_ng : public P::threadinfo_type::mrcu_callback {
|
||||
typedef typename P::threadinfo_type threadinfo;
|
||||
node_base<P>* root_;
|
||||
node_base<P>** root_ref_;
|
||||
int len_;
|
||||
size_t size_;
|
||||
MOT::MasstreePrimaryIndex* index_;
|
||||
char s_[0];
|
||||
gc_layer_rcu_callback_ng(node_base<P>* root, Str prefix, size_t size)
|
||||
: root_(root), len_(prefix.length()), size_(size), index_(mtSessionThreadInfo->get_working_index())
|
||||
gc_layer_rcu_callback_ng(node_base<P>** root_ref, Str prefix, size_t size)
|
||||
: root_ref_(root_ref), len_(prefix.length()), size_(size), index_(mtSessionThreadInfo->get_working_index())
|
||||
{
|
||||
errno_t erc = memcpy_s(s_, size_, prefix.data(), len_);
|
||||
errno_t erc = memcpy_s(s_, len_, prefix.data(), len_);
|
||||
securec_check(erc, "\0", "\0");
|
||||
}
|
||||
size_t operator()(bool drop_index);
|
||||
|
|
@ -51,7 +51,7 @@ struct gc_layer_rcu_callback_ng : public P::threadinfo_type::mrcu_callback {
|
|||
return size_;
|
||||
}
|
||||
|
||||
static void make(node_base<P>* root, Str prefix, threadinfo& ti);
|
||||
static void make(node_base<P>** root_ref, Str prefix, threadinfo& ti);
|
||||
};
|
||||
|
||||
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
|
||||
// more elements into GC)
|
||||
if (drop_index == false) {
|
||||
// GC layer remove might delete elements from tree and add them to the limbolist. Index must be provided to
|
||||
// allow access to the memory pools.
|
||||
// GC layer remove might delete elements from tree and might create new gc layer removal requests and add them to GC.
|
||||
// Index must be provided to allow access to the memory pools.
|
||||
mtSessionThreadInfo->set_working_index(index_);
|
||||
(*this)(*mtSessionThreadInfo);
|
||||
mtSessionThreadInfo->set_working_index(NULL);
|
||||
|
|
@ -73,30 +73,33 @@ size_t gc_layer_rcu_callback_ng<P>::operator()(bool drop_index)
|
|||
template <typename P>
|
||||
void gc_layer_rcu_callback_ng<P>::operator()(threadinfo& ti)
|
||||
{
|
||||
// root_ node while creating gc_layer_rcu_callback_ng might not be the current root. Find updated tree's root.
|
||||
while (!root_->is_root()) {
|
||||
root_ = root_->maybe_parent();
|
||||
}
|
||||
masstree_invariant(root_ref_);
|
||||
|
||||
// If root was already deleted, do nothing.
|
||||
if (root_->deleted()) {
|
||||
return;
|
||||
}
|
||||
|
||||
tcursor<P> node_cursor(root_, s_, len_);
|
||||
if (!node_cursor.gc_layer(ti) || !node_cursor.finish_remove(ti)) {
|
||||
tcursor<P> node_cursor(root_ref_, s_, len_);
|
||||
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>
|
||||
void gc_layer_rcu_callback_ng<P>::make(node_base<P>* root, Str prefix, threadinfo& ti)
|
||||
void gc_layer_rcu_callback_ng<P>::make(node_base<P>** root_ref, 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);
|
||||
// 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;
|
||||
}
|
||||
|
||||
gc_layer_rcu_callback_ng<P>* cb = new (data) gc_layer_rcu_callback_ng<P>(root_ref, prefix, sz);
|
||||
ti.rcu_register(cb, sz);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -69,14 +69,17 @@ Sentinel* MasstreePrimaryIndex::IndexInsertImpl(const Key* key, Sentinel* sentin
|
|||
mtSessionThreadInfo->set_gc_session(
|
||||
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);
|
||||
|
||||
mtSessionThreadInfo->set_gc_session(NULL);
|
||||
mtSessionThreadInfo->set_working_index(NULL);
|
||||
|
||||
if (!inserted) { // key mapping already exists in unique index
|
||||
if (!inserted && existingItem) { // key mapping already exists in unique index
|
||||
result = reinterpret_cast<Sentinel*>(existingItem);
|
||||
} // otherwise return null pointer
|
||||
} // otherwise return null pointer (if !inserted && !existingItem, Key does not exist and insertation failed due to
|
||||
// memory issue)
|
||||
|
||||
return result;
|
||||
}
|
||||
|
|
@ -108,6 +111,8 @@ Sentinel* MasstreePrimaryIndex::IndexRemoveImpl(const Key* key, uint32_t pid)
|
|||
mtSessionThreadInfo->set_gc_session(
|
||||
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);
|
||||
|
||||
mtSessionThreadInfo->set_gc_session(NULL);
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@
|
|||
#include "masstree/mot_masstree_struct.hpp"
|
||||
#include "masstree/mot_masstree_iterator.hpp"
|
||||
#include <cmath>
|
||||
#include "mot_engine.h"
|
||||
|
||||
namespace MOT {
|
||||
/**
|
||||
|
|
@ -302,11 +303,38 @@ public:
|
|||
/**
|
||||
* @brief Print Masstree pools memory consumption details to log.
|
||||
*/
|
||||
virtual void PrintPoolsStats()
|
||||
virtual void PrintPoolsStats(LogLevel level = LogLevel::LL_DEBUG)
|
||||
{
|
||||
m_leafsPool->Print("Leafs pool: ");
|
||||
m_internodesPool->Print("Internode pool: ");
|
||||
m_ksuffixSlab->Print("Ksuffix slab: ");
|
||||
m_leafsPool->Print("Leafs pool", level);
|
||||
m_internodesPool->Print("Internode pool", level);
|
||||
m_ksuffixSlab->Print("Ksuffix slab", level);
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -316,6 +344,8 @@ public:
|
|||
{
|
||||
m_initialized = false;
|
||||
DestroyPools();
|
||||
// remove masstree's root pointer (not valid anymore)
|
||||
*(m_index.root_ref()) = nullptr;
|
||||
|
||||
return IndexInitImpl(NULL);
|
||||
}
|
||||
|
|
@ -332,7 +362,7 @@ public:
|
|||
* @param tag Hint to determine which pool to use.
|
||||
* @return Pointer to allocated memory.
|
||||
*/
|
||||
void* AllocateMem(int& size, enum memtag tag)
|
||||
virtual void* AllocateMem(int& size, enum memtag tag)
|
||||
{
|
||||
switch (tag) {
|
||||
case memtag_masstree_leaf:
|
||||
|
|
@ -360,7 +390,7 @@ public:
|
|||
* @param Pointer to allocated memory.
|
||||
* @return True if deallocation succeeded.
|
||||
*/
|
||||
bool DeallocateMem(void* ptr, int size, enum memtag tag)
|
||||
virtual bool DeallocateMem(void* ptr, int size, enum memtag tag)
|
||||
{
|
||||
switch (tag) {
|
||||
case memtag_masstree_leaf:
|
||||
|
|
@ -431,10 +461,16 @@ public:
|
|||
{
|
||||
// If dropIndex == true, all index's pools are going to be cleaned, so we skip the release here
|
||||
mtSessionThreadInfo->set_gc_session(GetCurrentGcSession());
|
||||
GcEpochType local_epoch =
|
||||
GetSessionManager()->GetCurrentSessionContext()->GetTxnManager()->GetGcSession()->GcStartInnerTxn();
|
||||
|
||||
size_t allocationSize = (*static_cast<mrcu_callback*>(gcRemoveLayerFuncObjPtr))(dropIndex);
|
||||
|
||||
if (dropIndex == false) {
|
||||
((SlabAllocator*)slab)->Release(gcRemoveLayerFuncObjPtr, allocationSize);
|
||||
}
|
||||
|
||||
GetSessionManager()->GetCurrentSessionContext()->GetTxnManager()->GetGcSession()->GcEndInnerTxn(false);
|
||||
mtSessionThreadInfo->set_gc_session(NULL);
|
||||
return allocationSize;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -582,6 +582,7 @@ Row* Table::RemoveKeyFromIndex(Row* row, Sentinel* sentinel, uint64_t tid, GcMan
|
|||
#endif
|
||||
currSentinel = ix->IndexRemove(&key, tid);
|
||||
MOT_ASSERT(currSentinel == sentinel);
|
||||
MOT_ASSERT(currSentinel->GetCounter() == 0);
|
||||
if (likely(gc != nullptr)) {
|
||||
if (ix->GetIndexOrder() == IndexOrder::INDEX_ORDER_PRIMARY) {
|
||||
OutputRow = currSentinel->GetData();
|
||||
|
|
|
|||
|
|
@ -413,6 +413,8 @@ RC TxnManager::RollbackInsert(Access* ac)
|
|||
#endif
|
||||
outputSen = index_->IndexRemove(&m_key, GetThdId());
|
||||
MOT_ASSERT(outputSen != nullptr);
|
||||
MOT_ASSERT(outputSen->GetCounter() == 0);
|
||||
|
||||
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,
|
||||
// lets check if we can reclaim the deleted row
|
||||
|
|
@ -820,6 +822,8 @@ void TxnInsertAction::CleanupOptimisticInsert(
|
|||
MOT_ASSERT(pIndexInsertResult->GetCounter() == 0);
|
||||
Sentinel* outputSen = index_->IndexRemove(currentItem->m_key, m_manager->GetThdId());
|
||||
MOT_ASSERT(outputSen != nullptr);
|
||||
MOT_ASSERT(outputSen->GetCounter() == 0);
|
||||
|
||||
m_manager->GcSessionRecordRcu(
|
||||
index_->GetIndexId(), outputSen, nullptr, Index::SentinelDtor, SENTINEL_SIZE(index_));
|
||||
m_manager->m_accessMgr->IncreaseTableStat(table);
|
||||
|
|
|
|||
|
|
@ -223,6 +223,7 @@ void LogicalDecodingProcessRecord(LogicalDecodingContext *ctx, XLogReaderState *
|
|||
return;
|
||||
}
|
||||
|
||||
ResourceOwner tmpOwner = t_thrd.utils_cxt.CurrentResourceOwner;
|
||||
/* cast so we get a warning when new rmgrs are added */
|
||||
switch ((RmgrIds)XLogRecGetRmid(record)) {
|
||||
/*
|
||||
|
|
@ -257,6 +258,7 @@ void LogicalDecodingProcessRecord(LogicalDecodingContext *ctx, XLogReaderState *
|
|||
default:
|
||||
break;
|
||||
}
|
||||
t_thrd.utils_cxt.CurrentResourceOwner = tmpOwner;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -406,7 +406,7 @@ static void logicalrep_write_tuple(StringInfo out, Relation rel, HeapTuple tuple
|
|||
pfree(outputbytes);
|
||||
}
|
||||
} else {
|
||||
char *outputstr;
|
||||
char* outputstr = NULL;
|
||||
pq_sendbyte(out, LOGICALREP_COLUMN_TEXT);
|
||||
if (!typclass->typbyval && typclass->typlen == -1) {
|
||||
/* definitely detoasted Datum */
|
||||
|
|
@ -464,10 +464,8 @@ static void logicalrep_read_tuple(StringInfo in, LogicalRepTupleData *tuple)
|
|||
len = pq_getmsgint(in, sizeof(uint32)); /* read length */
|
||||
|
||||
/* and data */
|
||||
value->data = (char *) palloc((len + 1) * sizeof(char));
|
||||
value->data = (char *)palloc0((len + 1) * sizeof(char));
|
||||
pq_copymsgbytes(in, value->data, len);
|
||||
/* not strictly necessary but per StringInfo practice */
|
||||
value->data[len] = '\0';
|
||||
/* make StringInfo fully valid */
|
||||
value->len = len;
|
||||
value->cursor = 0;
|
||||
|
|
|
|||
|
|
@ -94,7 +94,7 @@
|
|||
#include "utils/relcache.h"
|
||||
|
||||
static const int NAPTIME_PER_CYCLE = 10; /* max sleep time between cycles (10ms) */
|
||||
static const float HALF = 0.5;
|
||||
static const double HALF = 0.5;
|
||||
|
||||
typedef struct FlushPosition {
|
||||
dlist_node node;
|
||||
|
|
@ -121,18 +121,6 @@ static void LogicalrepWorkerSighub(SIGNAL_ARGS)
|
|||
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.
|
||||
*
|
||||
|
|
@ -1068,13 +1056,15 @@ static void ApplyLoop(void)
|
|||
/* mark as idle, before starting to loop */
|
||||
pgstat_report_activity(STATE_IDLE, NULL);
|
||||
|
||||
while (!t_thrd.applyworker_cxt.got_SIGTERM) {
|
||||
for (;;) {
|
||||
MemoryContextSwitchTo(t_thrd.applyworker_cxt.messageContext);
|
||||
|
||||
int len;
|
||||
char *buf = NULL;
|
||||
unsigned char type;
|
||||
|
||||
CHECK_FOR_INTERRUPTS();
|
||||
|
||||
/* Wait a while for data to arrive */
|
||||
if ((WalReceiverFuncTable[GET_FUNC_IDX]).walrcv_receive(NAPTIME_PER_CYCLE, &type, &buf, &len)) {
|
||||
StringInfoData s;
|
||||
|
|
@ -1371,7 +1361,7 @@ void ApplyWorkerMain()
|
|||
*/
|
||||
gspqsignal(SIGHUP, LogicalrepWorkerSighub);
|
||||
gspqsignal(SIGINT, StatementCancelHandler);
|
||||
gspqsignal(SIGTERM, LogicalrepWorkerSigterm);
|
||||
gspqsignal(SIGTERM, die);
|
||||
|
||||
gspqsignal(SIGQUIT, quickdie);
|
||||
gspqsignal(SIGALRM, handle_sig_alarm);
|
||||
|
|
@ -1727,3 +1717,11 @@ static void UpdateConninfo(char* standbysInfo)
|
|||
|
||||
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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -78,7 +78,7 @@ void _PG_output_plugin_init(OutputPluginCallbacks *cb)
|
|||
cb->shutdown_cb = pgoutput_shutdown;
|
||||
}
|
||||
|
||||
static void parse_output_parameters(List* options, PGOutputData* data)
|
||||
static void parse_output_parameters(List *options, PGOutputData *data)
|
||||
{
|
||||
ListCell *lc;
|
||||
bool protocol_version_given = false;
|
||||
|
|
|
|||
|
|
@ -1934,14 +1934,18 @@ ArchiveConfig* formArchiveConfigFromStr(char *content, bool encrypted)
|
|||
ArchiveConnConfig* conn_config = NULL;
|
||||
char* media_type = NULL;
|
||||
errno_t rc = EOK;
|
||||
/* SplitIdentifierString will change origin string */
|
||||
char *content_copy = pstrdup(content);
|
||||
char *content_copy = NULL;
|
||||
char *tmp = NULL;
|
||||
List* elemlist = NIL;
|
||||
int param_num = 0;
|
||||
size_t elem_index = 0;
|
||||
archive_config = (ArchiveConfig *)palloc0(sizeof(ArchiveConfig));
|
||||
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 */
|
||||
if (!SplitIdentifierString(content_copy, ';', &elemlist, false, false)) {
|
||||
goto FAILURE;
|
||||
|
|
|
|||
|
|
@ -401,6 +401,7 @@ int WalSenderMain(void)
|
|||
t_thrd.walsender_cxt.server_run_mode = t_thrd.postmaster_cxt.HaShmData->current_mode;
|
||||
|
||||
SetHaWalSenderChannel();
|
||||
Assert(t_thrd.utils_cxt.CurrentResourceOwner != NULL);
|
||||
/* Handle handshake messages before streaming */
|
||||
WalSndHandshake();
|
||||
|
||||
|
|
@ -496,6 +497,7 @@ static void WalSndHandshake(void)
|
|||
|
||||
while (!repCxt.replicationStarted) {
|
||||
int firstchar;
|
||||
Assert(t_thrd.utils_cxt.CurrentResourceOwner != NULL);
|
||||
|
||||
WalSndSetState(WALSNDSTATE_STARTUP);
|
||||
set_ps_display("idle", false);
|
||||
|
|
@ -2033,6 +2035,8 @@ bool isLogicalSlotExist(char* slotName)
|
|||
}
|
||||
|
||||
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) {
|
||||
case T_IdentifySystemCmd:
|
||||
IdentifySystem();
|
||||
|
|
@ -2140,7 +2144,7 @@ static void IdentifyCommand(Node* cmd_node, ReplicationCxt* repCxt, const char *
|
|||
ereport(FATAL,
|
||||
(errcode(ERRCODE_PROTOCOL_VIOLATION), errmsg("invalid standby query string: %s", cmd_string)));
|
||||
}
|
||||
|
||||
t_thrd.utils_cxt.CurrentResourceOwner = tmpOwner;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -3596,8 +3600,12 @@ static int WalSndLoop(WalSndSendDataCallback send_data)
|
|||
t_thrd.walsender_cxt.last_logical_xlog_advanced_timestamp = GetCurrentTimestamp();
|
||||
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 */
|
||||
for (;;) {
|
||||
t_thrd.utils_cxt.CurrentResourceOwner = tmpOwner;
|
||||
TimestampTz now;
|
||||
|
||||
/* Clear any already-pending wakeups */
|
||||
|
|
@ -4006,6 +4014,7 @@ static int WalSndLoop(WalSndSendDataCallback send_data)
|
|||
}
|
||||
}
|
||||
|
||||
t_thrd.utils_cxt.CurrentResourceOwner = tmpOwner;
|
||||
WalSndShutdown();
|
||||
return 1; /* keep the compiler quiet */
|
||||
}
|
||||
|
|
@ -5814,7 +5823,7 @@ Datum gs_paxos_stat_replication(PG_FUNCTION_ARGS)
|
|||
*/
|
||||
Datum pg_stat_get_wal_senders(PG_FUNCTION_ARGS)
|
||||
{
|
||||
#define PG_STAT_GET_WAL_SENDERS_COLS 22
|
||||
#define PG_STAT_GET_WAL_SENDERS_COLS 21
|
||||
|
||||
TupleDesc tupdesc;
|
||||
int *sync_priority = NULL;
|
||||
|
|
@ -6051,11 +6060,9 @@ Datum pg_stat_get_wal_senders(PG_FUNCTION_ARGS)
|
|||
/* sync_state and sync_prority */
|
||||
if (!SyncRepRequested()) {
|
||||
values[j++] = CStringGetTextDatum("Async");
|
||||
nulls[j++] = true;
|
||||
values[j++] = Int32GetDatum(0);
|
||||
} else {
|
||||
values[j++] = CStringGetTextDatum("Sync");
|
||||
nulls[j++] = true;
|
||||
values[j++] = Int32GetDatum(sync_priority[i]);
|
||||
}
|
||||
} else {
|
||||
|
|
@ -6077,15 +6084,12 @@ Datum pg_stat_get_wal_senders(PG_FUNCTION_ARGS)
|
|||
*/
|
||||
if (priority == 0) {
|
||||
values[j++] = CStringGetTextDatum("Async");
|
||||
nulls[j++] = true;
|
||||
} else if (list_member_int((List*)list_nth(sync_standbys, group), i)) {
|
||||
values[j++] = GetWalsndSyncRepConfig(walsnd)->syncrep_method == SYNC_REP_PRIORITY
|
||||
? CStringGetTextDatum("Sync")
|
||||
: CStringGetTextDatum("Quorum");
|
||||
values[j++] = Int32GetDatum(group);
|
||||
} else {
|
||||
values[j++] = CStringGetTextDatum("Potential");
|
||||
values[j++] = Int32GetDatum(group);
|
||||
}
|
||||
values[j++] = Int32GetDatum(priority);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -394,8 +394,6 @@ void mdcreate(SMgrRelation reln, ForkNumber forkNum, bool isRedo)
|
|||
}
|
||||
|
||||
if (fd < 0) {
|
||||
int save_errno = errno;
|
||||
|
||||
/*
|
||||
* During bootstrap, there are cases where a system relation will be
|
||||
* accessed (by internal backend processes) before the bootstrap
|
||||
|
|
@ -407,26 +405,7 @@ void mdcreate(SMgrRelation reln, ForkNumber forkNum, bool isRedo)
|
|||
* new catalogs can by no means be used by other relations, we simply
|
||||
* truncate them.
|
||||
*/
|
||||
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)));
|
||||
}
|
||||
fd = RetryDataFileIdOpenFile(isRedo, path, filenode, flags);
|
||||
}
|
||||
|
||||
File fd_pca = -1;
|
||||
|
|
|
|||
|
|
@ -145,6 +145,29 @@ then
|
|||
plat_form_str=ubuntu18.04_"$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
|
||||
# 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
|
||||
|
|
|
|||
|
|
@ -314,4 +314,5 @@ template<bool hasnull>
|
|||
void UHeapFillDiskTuple(TupleDesc tupleDesc, Datum *values, const bool *isnull, UHeapDiskTupleData *diskTuple,
|
||||
uint32 dataSize, bool enableReverseBitmap, bool enableReserve);
|
||||
void CheckTupleValidity(Relation rel, UHeapTuple utuple);
|
||||
Tuple UHeapMaterialize(TupleTableSlot *slot);
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -165,7 +165,7 @@ extern void addNewPartitionTuple(Relation pg_part_desc, Partition new_part_desc,
|
|||
Datum interval, Datum maxValues, Datum transitionPoint, Datum reloptions);
|
||||
|
||||
extern void heap_truncate_one_part(Relation rel , Oid partOid);
|
||||
extern Oid heapTupleGetPartitionId(Relation rel, void *tuple);
|
||||
extern Oid heapTupleGetPartitionId(Relation rel, void *tuple, bool isDDL = false);
|
||||
extern Oid heapTupleGetSubPartitionId(Relation rel, void *tuple);
|
||||
extern void heap_truncate(List *relids);
|
||||
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 Oid AddNewIntervalPartition(Relation rel, void* insertTuple);
|
||||
extern Oid AddNewIntervalPartition(Relation rel, void* insertTuple, bool isDDL = false);
|
||||
|
||||
extern int GetIndexKeyAttsByTuple(Relation relation, HeapTuple indexTuple);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,37 +0,0 @@
|
|||
-- for any x group
|
||||
DO $$
|
||||
DECLARE
|
||||
ans boolean;
|
||||
BEGIN
|
||||
select case when working_version_num()=92301 then true else false end as ans into ans;
|
||||
if ans = false then
|
||||
DROP FUNCTION IF EXISTS pg_catalog.pg_stat_get_wal_senders() CASCADE;
|
||||
SET LOCAL inplace_upgrade_next_system_object_oids = IUO_PROC, 3099;
|
||||
CREATE FUNCTION pg_catalog.pg_stat_get_wal_senders(
|
||||
OUT pid bigint,
|
||||
OUT sender_pid integer,
|
||||
OUT local_role text,
|
||||
OUT peer_role text,
|
||||
OUT peer_state text,
|
||||
OUT state text,
|
||||
OUT catchup_start timestamp with time zone,
|
||||
OUT catchup_end timestamp with time zone,
|
||||
OUT sender_sent_location text,
|
||||
OUT sender_write_location text,
|
||||
OUT sender_flush_location text,
|
||||
OUT sender_replay_location text,
|
||||
OUT receiver_received_location text,
|
||||
OUT receiver_write_location text,
|
||||
OUT receiver_flush_location text,
|
||||
OUT receiver_replay_location text,
|
||||
OUT sync_percent text,
|
||||
OUT sync_state text,
|
||||
OUT sync_priority integer,
|
||||
OUT sync_most_available text,
|
||||
OUT channel text
|
||||
) RETURNS SETOF record
|
||||
STABLE NOT FENCED NOT SHIPPABLE ROWS 10
|
||||
LANGUAGE internal AS 'pg_stat_get_wal_senders';
|
||||
end if;
|
||||
END$$;
|
||||
SET LOCAL inplace_upgrade_next_system_object_oids = IUO_PROC, 0;
|
||||
|
|
@ -1,37 +0,0 @@
|
|||
-- for any x group
|
||||
DO $$
|
||||
DECLARE
|
||||
ans boolean;
|
||||
BEGIN
|
||||
select case when working_version_num()=92301 then true else false end as ans into ans;
|
||||
if ans = false then
|
||||
DROP FUNCTION IF EXISTS pg_catalog.pg_stat_get_wal_senders() CASCADE;
|
||||
SET LOCAL inplace_upgrade_next_system_object_oids = IUO_PROC, 3099;
|
||||
CREATE FUNCTION pg_catalog.pg_stat_get_wal_senders(
|
||||
OUT pid bigint,
|
||||
OUT sender_pid integer,
|
||||
OUT local_role text,
|
||||
OUT peer_role text,
|
||||
OUT peer_state text,
|
||||
OUT state text,
|
||||
OUT catchup_start timestamp with time zone,
|
||||
OUT catchup_end timestamp with time zone,
|
||||
OUT sender_sent_location text,
|
||||
OUT sender_write_location text,
|
||||
OUT sender_flush_location text,
|
||||
OUT sender_replay_location text,
|
||||
OUT receiver_received_location text,
|
||||
OUT receiver_write_location text,
|
||||
OUT receiver_flush_location text,
|
||||
OUT receiver_replay_location text,
|
||||
OUT sync_percent text,
|
||||
OUT sync_state text,
|
||||
OUT sync_priority integer,
|
||||
OUT sync_most_available text,
|
||||
OUT channel text
|
||||
) RETURNS SETOF record
|
||||
STABLE NOT FENCED NOT SHIPPABLE ROWS 10
|
||||
LANGUAGE internal AS 'pg_stat_get_wal_senders';
|
||||
end if;
|
||||
END$$;
|
||||
SET LOCAL inplace_upgrade_next_system_object_oids = IUO_PROC, 0;
|
||||
|
|
@ -1,38 +0,0 @@
|
|||
-- for any x group
|
||||
DO $$
|
||||
DECLARE
|
||||
ans boolean;
|
||||
BEGIN
|
||||
select case when working_version_num()=92301 then true else false end as ans into ans;
|
||||
if ans = false then
|
||||
DROP FUNCTION IF EXISTS pg_catalog.pg_stat_get_wal_senders() CASCADE;
|
||||
SET LOCAL inplace_upgrade_next_system_object_oids = IUO_PROC, 3099;
|
||||
CREATE FUNCTION pg_catalog.pg_stat_get_wal_senders(
|
||||
OUT pid bigint,
|
||||
OUT sender_pid integer,
|
||||
OUT local_role text,
|
||||
OUT peer_role text,
|
||||
OUT peer_state text,
|
||||
OUT state text,
|
||||
OUT catchup_start timestamp with time zone,
|
||||
OUT catchup_end timestamp with time zone,
|
||||
OUT sender_sent_location text,
|
||||
OUT sender_write_location text,
|
||||
OUT sender_flush_location text,
|
||||
OUT sender_replay_location text,
|
||||
OUT receiver_received_location text,
|
||||
OUT receiver_write_location text,
|
||||
OUT receiver_flush_location text,
|
||||
OUT receiver_replay_location text,
|
||||
OUT sync_percent text,
|
||||
OUT sync_state text,
|
||||
OUT sync_group integer,
|
||||
OUT sync_priority integer,
|
||||
OUT sync_most_available text,
|
||||
OUT channel text
|
||||
) RETURNS SETOF record
|
||||
STABLE NOT FENCED NOT SHIPPABLE ROWS 10
|
||||
LANGUAGE internal AS 'pg_stat_get_wal_senders';
|
||||
end if;
|
||||
END$$;
|
||||
SET LOCAL inplace_upgrade_next_system_object_oids = IUO_PROC, 0;
|
||||
|
|
@ -1,38 +0,0 @@
|
|||
-- for any x group
|
||||
DO $$
|
||||
DECLARE
|
||||
ans boolean;
|
||||
BEGIN
|
||||
select case when working_version_num()=92301 then true else false end as ans into ans;
|
||||
if ans = false then
|
||||
DROP FUNCTION IF EXISTS pg_catalog.pg_stat_get_wal_senders() CASCADE;
|
||||
SET LOCAL inplace_upgrade_next_system_object_oids = IUO_PROC, 3099;
|
||||
CREATE FUNCTION pg_catalog.pg_stat_get_wal_senders(
|
||||
OUT pid bigint,
|
||||
OUT sender_pid integer,
|
||||
OUT local_role text,
|
||||
OUT peer_role text,
|
||||
OUT peer_state text,
|
||||
OUT state text,
|
||||
OUT catchup_start timestamp with time zone,
|
||||
OUT catchup_end timestamp with time zone,
|
||||
OUT sender_sent_location text,
|
||||
OUT sender_write_location text,
|
||||
OUT sender_flush_location text,
|
||||
OUT sender_replay_location text,
|
||||
OUT receiver_received_location text,
|
||||
OUT receiver_write_location text,
|
||||
OUT receiver_flush_location text,
|
||||
OUT receiver_replay_location text,
|
||||
OUT sync_percent text,
|
||||
OUT sync_state text,
|
||||
OUT sync_group integer,
|
||||
OUT sync_priority integer,
|
||||
OUT sync_most_available text,
|
||||
OUT channel text
|
||||
) RETURNS SETOF record
|
||||
STABLE NOT FENCED NOT SHIPPABLE ROWS 10
|
||||
LANGUAGE internal AS 'pg_stat_get_wal_senders';
|
||||
end if;
|
||||
END$$;
|
||||
SET LOCAL inplace_upgrade_next_system_object_oids = IUO_PROC, 0;
|
||||
|
|
@ -238,7 +238,7 @@ typedef struct knl_session_attr_sql {
|
|||
#ifndef ENABLE_MULTIPLE_NODES
|
||||
bool enable_custom_parser;
|
||||
#endif
|
||||
bool b_sql_plugin;
|
||||
bool dolphin;
|
||||
} knl_session_attr_sql;
|
||||
|
||||
#endif /* SRC_INCLUDE_KNL_KNL_SESSION_ATTR_SQL */
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@
|
|||
#include "access/extreme_rto/spsc_blocking_queue.h"
|
||||
#include "access/parallel_recovery/redo_item.h"
|
||||
|
||||
#include "nodes/parsenodes_common.h"
|
||||
#include "nodes/replnodes.h"
|
||||
#include "access/ustore/knl_utuple.h"
|
||||
#include "replication/logical_queue.h"
|
||||
|
|
|
|||
|
|
@ -13,5 +13,6 @@
|
|||
#define LOGICALWORKER_H
|
||||
|
||||
extern void ApplyWorkerMain();
|
||||
extern bool IsLogicalWorker(void);
|
||||
|
||||
#endif /* LOGICALWORKER_H */
|
||||
|
|
|
|||
|
|
@ -229,10 +229,15 @@ private:
|
|||
bool m_syscache_relids[FirstNormalObjectId];
|
||||
|
||||
};
|
||||
void NotifyGscRecoveryStarted();
|
||||
void NotifyGscRecoveryFinished();
|
||||
extern Datum gs_gsc_dbstat_info(PG_FUNCTION_ARGS);
|
||||
extern Datum gs_gsc_clean(PG_FUNCTION_ARGS);
|
||||
extern Datum gs_gsc_catalog_detail(PG_FUNCTION_ARGS);
|
||||
extern Datum gs_gsc_table_detail(PG_FUNCTION_ARGS);
|
||||
extern int ResizeHashBucket(int origin_nbucket, DynamicHashBucketStrategy strategy);
|
||||
#endif
|
||||
|
||||
/* 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
|
||||
|
|
|
|||
|
|
@ -213,7 +213,7 @@ extern bool check_rel_is_partitioned(Oid relid);
|
|||
extern Oid partid_get_parentid(Oid partid);
|
||||
extern bool is_not_strict_agg(Oid funcOid);
|
||||
extern bool is_pgxc_class_table(Oid tableoid);
|
||||
extern Oid get_valid_relname_relid(const char* relnamespace, const char* relname);
|
||||
extern Oid get_valid_relname_relid(const char* relnamespace, const char* relname, bool nsp_missing_ok = false);
|
||||
extern bool get_func_iswindow(Oid funcid);
|
||||
extern char get_func_prokind(Oid funcid);
|
||||
extern char get_typecategory(Oid typid);
|
||||
|
|
|
|||
|
|
@ -1385,6 +1385,8 @@ typedef struct PlDebugEntry {
|
|||
PLpgSQL_function* func;
|
||||
} PlDebugEntry;
|
||||
|
||||
typedef List* (*RawParserHook)(const char*, List**);
|
||||
|
||||
const int MAXINT8LEN = 25;
|
||||
const int DEFAULT_DEBUG_BUF_SIZE = 1024;
|
||||
const long NANOSECOND_PER_SECOND = 1000000000L; /* 1s */
|
||||
|
|
|
|||
|
|
@ -0,0 +1,37 @@
|
|||
--
|
||||
-- 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)
|
||||
|
||||
|
|
@ -0,0 +1,116 @@
|
|||
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,11 +132,14 @@ DROP EXTENSION test_extension_exists;
|
|||
ERROR: extension "test_extension_exists" does not exist
|
||||
DROP EXTENSION IF EXISTS test_extension_exists;
|
||||
NOTICE: extension "test_extension_exists" does not exist, skipping
|
||||
-- exists but doesn't support drop
|
||||
DROP EXTENSION plpgsql;
|
||||
ERROR: EXTENSION is not yet supported.
|
||||
DROP EXTENSION IF EXISTS plpgsql;
|
||||
ERROR: EXTENSION is not yet supported.
|
||||
-- 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
|
||||
CREATE DATABASE ext_test_db;
|
||||
\c ext_test_db
|
||||
DROP EXTENSION hdfs_fdw;
|
||||
DROP EXTENSION IF EXISTS hdfs_fdw;
|
||||
NOTICE: extension "hdfs_fdw" does not exist, skipping
|
||||
\c regression
|
||||
DROP DATABASE ext_test_db;
|
||||
-- functions
|
||||
DROP FUNCTION test_function_exists();
|
||||
ERROR: function test_function_exists does not exist
|
||||
|
|
|
|||
|
|
@ -215,3 +215,107 @@ select * from interval_normal_exchange where logdate > '2020-06-01' order by log
|
|||
(0 rows)
|
||||
|
||||
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;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,55 @@
|
|||
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,5 +89,8 @@ ERROR: Can not use compress option in ustore index.
|
|||
-- segment
|
||||
CREATE TABLE unspported_feature.segment_table(id int, c1 text) WITH(compresstype=2, segment=on); --failed
|
||||
ERROR: only row orientation table support compresstype.
|
||||
CREATE INDEX on unspported_feature.index_test(c1) WITH(compresstype=2, segment=on); --faled
|
||||
CREATE INDEX on unspported_feature.index_test(c1) WITH(compresstype=2, segment=on); --failed
|
||||
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,6 +1062,73 @@ select /*+ indexscan(tg_hash i_tg_hash_local_a) */ * from tg_hash where a < 9;
|
|||
(81 rows)
|
||||
|
||||
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 materialized view pg_partition_before_truncate;
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ test: pldeveloper_gs_source
|
|||
test: index_advisor
|
||||
test: pl_debugger_server pl_debugger_client
|
||||
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
|
||||
test: plan_hint plan_hint_set plan_hint_no_expand plan_hint_iud null_test_opt deserialize_func
|
||||
test: large_sequence int16 gs_dump_sequence
|
||||
test: gs_dump_tableof
|
||||
test: analyze_commands
|
||||
|
|
@ -916,3 +916,5 @@ test: fdw_audit
|
|||
test: gs_global_config_audit
|
||||
test: detail
|
||||
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 1401
|
||||
#define BASE_PGXC_LIKE_MACRO_NUM 1402
|
||||
static void check_pgxc_like_macros()
|
||||
{
|
||||
#ifdef BUILD_BY_CMAKE
|
||||
|
|
|
|||
|
|
@ -0,0 +1,11 @@
|
|||
--
|
||||
-- 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