Compare commits

..

4 Commits

Author SHA1 Message Date
opengauss-bot c6cf59f29f
!1669 add wm_concat function to use internal datatype
Merge pull request !1669 from 吕辉/wm_concat
2022-05-24 01:44:32 +00:00
opengauss-bot a5410b7f86
!1667 修复enable_global_syscache关闭时连接B兼容性数据库的core问题
Merge pull request !1667 from chenxiaobin/3.0.0
2022-04-11 11:11:06 +00:00
lvhui c711c7dc5f add wm_concat in InternalAggIsSupported 2022-04-11 17:41:56 +08:00
chenxiaobin19 3bea35e8c1 修复enable_global_syscache关闭时连接B兼容性数据库的core问题 2022-04-08 11:11:57 +08:00
143 changed files with 1131 additions and 5668 deletions

View File

@ -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), Asianux platform."
echo "We only support openEuler(aarch64), EulerOS(aarch64), CentOS, Kylin(aarch64) platform."
exit 1;
fi
@ -96,21 +96,16 @@ 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), Asianux platform."
echo "We only support openEuler(aarch64), EulerOS(aarch64), CentOS, Kylin(aarch64) 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" ] && [ "$dist_version" != "Asianux" ]; then
echo "We only support NUMA on openEuler(aarch64), EulerOS(aarch64), Kylin(aarch64), Asianux platform."
if [ "$dist_version" != "openEuler" ] && [ "$dist_version" != "EulerOS" ] && [ "$dist_version" != "Kylin" ] ; then
echo "We only support NUMA on openEuler(aarch64), EulerOS(aarch64), Kylin(aarch64) platform."
exit 1
fi
fi

View File

@ -26,7 +26,6 @@ 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">

View File

@ -1,37 +0,0 @@
<refentry id="sql-alterprocedure">
<indexterm zone="sql-alterprocedure">
<primary>ALTER PROCEDURE</primary>
</indexterm>
<refmeta>
<refentrytitle>ALTER PROCEDURE</refentrytitle>
<manvolnum>7</manvolnum>
<refmiscinfo>SQL - Language Statements</refmiscinfo>
</refmeta>
<refnamediv>
<refname>ALTER PROCEDURE</refname>
<refpurpose>change the definition of a procedure</refpurpose>
</refnamediv>
<refsynopsisdiv>
<synopsis>
ALTER PROCEDURE <replaceable>name</replaceable> [ ( [ [ <replaceable class="parameter">argmode</replaceable> ] [ <replaceable class="parameter">argname</replaceable> ] <replaceable class="parameter">argtype</replaceable> [, ...] ] ) ]
<replaceable class="parameter">action</replaceable> [ ... ] [ RESTRICT ]
ALTER PROCEDURE <replaceable>name</replaceable> [ ( [ [ <replaceable class="parameter">argmode</replaceable> ] [ <replaceable class="parameter">argname</replaceable> ] <replaceable class="parameter">argtype</replaceable> [, ...] ] ) ]
RENAME TO <replaceable>new_name</replaceable>
ALTER PROCEDURE <replaceable>name</replaceable> [ ( [ [ <replaceable class="parameter">argmode</replaceable> ] [ <replaceable class="parameter">argname</replaceable> ] <replaceable class="parameter">argtype</replaceable> [, ...] ] ) ]
OWNER TO { <replaceable>new_owner</replaceable> | CURRENT_ROLE | CURRENT_USER | SESSION_USER }
ALTER PROCEDURE <replaceable>name</replaceable> [ ( [ [ <replaceable class="parameter">argmode</replaceable> ] [ <replaceable class="parameter">argname</replaceable> ] <replaceable class="parameter">argtype</replaceable> [, ...] ] ) ]
SET SCHEMA <replaceable>new_schema</replaceable>
<phrase>where <replaceable class="parameter">action</replaceable> is one of:</phrase>
[ EXTERNAL ] SECURITY INVOKER | [ EXTERNAL ] SECURITY DEFINER
SET <replaceable class="parameter">configuration_parameter</replaceable> { TO | = } { <replaceable class="parameter">value</replaceable> | DEFAULT }
SET <replaceable class="parameter">configuration_parameter</replaceable> FROM CURRENT
RESET <replaceable class="parameter">configuration_parameter</replaceable>
RESET ALL
</synopsis>
</refsynopsisdiv>
</refentry>

View File

@ -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>

View File

@ -27,14 +27,7 @@
#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*
NoteIf 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;

View File

@ -34,14 +34,6 @@
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
Notenone
*/
void check_path(const char *path_name)
{
const char* danger_character_list[] = {"|",
@ -77,14 +69,6 @@ void check_path(const char *path_name)
}
}
/*
function name: check_key_num
description: Check if the password is a null string, if so, then the password is invalid.
At the same time, the function check if the length of password exceeds MAX_CRYPT_LEN, if so, print the error.
arguments: A pointer to string that its type is const char
return value: An integer that its type is static int
NoteThe 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;

View File

@ -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:C:dqL:T:Q:", long_options,
while ((c = getopt_long(argc, argv, "b:cD:e:fi:G:l:m:M:N:o:O:p:P:r:R:v:x:sS:t:u:U:wWZ:dqL:T:Q:", long_options,
&option_index)) != -1)
#endif
#endif

View File

@ -233,7 +233,6 @@ 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 = 92606;
#ifdef DUMPSYSLOG
char* syslogpath = NULL;
@ -4445,16 +4444,23 @@ void getSubscriptions(Archive *fout)
int i_subslotname;
int i_subsynccommit;
int i_subpublications;
int i_subbinary;
int i;
int ntups;
int i, ntups;
if (no_subscriptions || GetVersionNum(fout) < SUBSCRIPTION_VERSION) {
return;
}
if (!isExecUserSuperRole(fout)) {
write_msg(NULL, "WARNING: subscriptions not dumped because current user is not a superuser\n");
res = ExecuteSqlQuery(fout,
"SELECT count(*) FROM pg_subscription "
"WHERE subdbid = (SELECT oid FROM pg_catalog.pg_database"
" WHERE datname = current_database())",
PGRES_TUPLES_OK);
uint64 n = (res != NULL) ? strtoul(PQgetvalue(res, 0, 0), NULL, 10) : 0;
if (n > 0) {
write_msg(NULL, "WARNING: subscriptions not dumped because current user is not a superuser\n");
}
PQclear(res);
return;
}
@ -4463,20 +4469,14 @@ void getSubscriptions(Archive *fout)
resetPQExpBuffer(query);
/* Get the subscriptions in current database. */
appendPQExpBuffer(query, "SELECT s.tableoid, s.oid, s.subname,"
"(%s s.subowner) AS rolname, s.subconninfo, s.subslotname, "
"s.subsynccommit, s.subpublications, \n", username_subquery);
if (GetVersionNum(fout) >= SUBSCRIPTION_BINARY_VERSION_NUM) {
appendPQExpBuffer(query, " s.subbinary\n");
} else {
appendPQExpBuffer(query, " false AS subbinary\n");
}
appendPQExpBuffer(query, "FROM pg_catalog.pg_subscription s "
appendPQExpBuffer(query,
"SELECT s.tableoid, s.oid, s.subname,"
"(%s s.subowner) AS rolname, "
" s.subconninfo, s.subslotname, s.subsynccommit, s.subpublications "
"FROM pg_catalog.pg_subscription s "
"WHERE s.subdbid = (SELECT oid FROM pg_catalog.pg_database"
" WHERE datname = current_database())");
" WHERE datname = current_database())",
username_subquery);
res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
ntups = PQntuples(res);
@ -4494,7 +4494,6 @@ void getSubscriptions(Archive *fout)
i_subslotname = PQfnumber(res, "subslotname");
i_subsynccommit = PQfnumber(res, "subsynccommit");
i_subpublications = PQfnumber(res, "subpublications");
i_subbinary = PQfnumber(res, "subbinary");
subinfo = (SubscriptionInfo *)pg_malloc(ntups * sizeof(SubscriptionInfo));
@ -4513,7 +4512,6 @@ void getSubscriptions(Archive *fout)
}
subinfo[i].subsynccommit = gs_strdup(PQgetvalue(res, i, i_subsynccommit));
subinfo[i].subpublications = gs_strdup(PQgetvalue(res, i, i_subpublications));
subinfo[i].subbinary = gs_strdup(PQgetvalue(res, i, i_subbinary));
if (strlen(subinfo[i].rolname) == 0) {
write_msg(NULL, "WARNING: owner of subscription \"%s\" appears to be invalid\n", subinfo[i].dobj.name);
@ -4580,10 +4578,6 @@ static void dumpSubscription(Archive *fout, const SubscriptionInfo *subinfo)
appendPQExpBufferStr(query, "NONE");
}
if (strcmp(subinfo->subbinary, "t") == 0) {
appendPQExpBuffer(query, ", binary = true");
}
if (strcmp(subinfo->subsynccommit, "off") != 0) {
appendPQExpBuffer(query, ", synchronous_commit = %s", fmtId(subinfo->subsynccommit));
}
@ -10786,11 +10780,6 @@ 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");
@ -21400,11 +21389,6 @@ 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,

View File

@ -498,7 +498,6 @@ typedef struct _SubscriptionInfo {
char *subslotname;
char *subsynccommit;
char *subpublications;
char *subbinary;
} SubscriptionInfo;
/* global decls */

View File

@ -31,9 +31,6 @@
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;
@ -92,11 +89,10 @@ 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,
bool backup_replslots);
static void do_backup_instance(PGconn *backup_conn, PGNodeInfo *nodeInfo, bool no_sync, bool backup_logs);
static void pg_start_backup(const char *label, bool smooth, pgBackup *backup,
PGNodeInfo *nodeInfo, PGconn *conn, bool backup_replslots);
PGNodeInfo *nodeInfo, PGconn *conn);
static void pg_stop_backup(pgBackup *backup, PGconn *pg_startbackup_conn, PGNodeInfo *nodeInfo);
static int checkpoint_timeout(PGconn *backup_conn);
@ -562,7 +558,7 @@ static void sync_files(parray *database_map, const char *database_path, parray *
* Move files from 'pgdata' to a subdirectory in 'backup_path'.
*/
static void
do_backup_instance(PGconn *backup_conn, PGNodeInfo *nodeInfo, bool no_sync, bool backup_logs, bool backup_replslots)
do_backup_instance(PGconn *backup_conn, PGNodeInfo *nodeInfo, bool no_sync, bool backup_logs)
{
int i;
char database_path[MAXPGPATH];
@ -595,7 +591,7 @@ do_backup_instance(PGconn *backup_conn, PGNodeInfo *nodeInfo, bool no_sync, bool
securec_check_c(rc, "\0", "\0");
/* Call pg_start_backup function in openGauss connect */
pg_start_backup(label, smooth_checkpoint, &current, nodeInfo, backup_conn, backup_replslots);
pg_start_backup(label, smooth_checkpoint, &current, nodeInfo, backup_conn);
/* Obtain current timeline */
#if PG_VERSION_NUM >= 90600
@ -628,10 +624,10 @@ do_backup_instance(PGconn *backup_conn, PGNodeInfo *nodeInfo, bool no_sync, bool
/* list files with the logical path. omit $PGDATA */
if (fio_is_remote(FIO_DB_HOST))
fio_list_dir(backup_files_list, instance_config.pgdata,
true, true, false, backup_logs, true, 0, backup_replslots);
true, true, false, backup_logs, true, 0);
else
dir_list_file(backup_files_list, instance_config.pgdata,
true, true, false, backup_logs, true, 0, FIO_LOCAL_HOST, backup_replslots);
true, true, false, backup_logs, true, 0, FIO_LOCAL_HOST);
/*
* Get database_map (name to oid) for use in partial restore feature.
@ -753,11 +749,6 @@ 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)
{
@ -858,7 +849,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 backup_replslots)
bool no_validate, bool no_sync, bool backup_logs)
{
PGconn *backup_conn = NULL;
PGNodeInfo nodeInfo;
@ -934,7 +925,7 @@ do_backup(time_t start_time, pgSetBackupParams *set_backup_params,
add_note(&current, set_backup_params->note);
/* backup data */
do_backup_instance(backup_conn, &nodeInfo, no_sync, backup_logs, backup_replslots);
do_backup_instance(backup_conn, &nodeInfo, no_sync, backup_logs);
pgut_atexit_pop(backup_cleanup, NULL);
/* compute size of wal files of this backup stored in the archive */
@ -1043,15 +1034,13 @@ confirm_block_size(PGconn *conn, const char *name, int blcksz)
*/
static void
pg_start_backup(const char *label, bool smooth, pgBackup *backup,
PGNodeInfo *nodeInfo, PGconn *conn, bool backup_replslots)
PGNodeInfo *nodeInfo, PGconn *conn)
{
PGresult *res;
const char *params[2];
uint32 lsn_hi;
uint32 lsn_lo;
int ret;
int i;
XLogRecPtr startLsn;
params[0] = label;
@ -1079,33 +1068,7 @@ pg_start_backup(const char *label, bool smooth, pgBackup *backup,
XLogDataFromLSN(ret, PQgetvalue(res, 0, 0), &lsn_hi, &lsn_lo);
securec_check_for_sscanf_s(ret, 2, "\0", "\0");
/* Calculate LSN */
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;
backup->start_lsn = ((uint64) lsn_hi )<< 32 | lsn_lo;
PQclear(res);
}

View File

@ -42,6 +42,13 @@ 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",
@ -61,7 +68,7 @@ const char *pgdata_exclude_dir[] =
(const char *)"pg_subtrans",
/* end of list */
NULL, /* pg_log and pg_replslot will be set later */
NULL, /* pg_log will be set later */
NULL
};
@ -121,20 +128,17 @@ 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, bool backup_replslots);
static char dir_check_file(pgFile *file, bool backup_logs);
static char check_in_tablespace(pgFile *file, bool in_tablespace);
static char check_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 backup_replslots);
bool skip_hidden, int external_dir_num, fio_location location);
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 */
@ -534,7 +538,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, bool backup_replslots)
fio_location location)
{
pgFile *file;
@ -561,7 +565,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_replslots);
backup_logs, skip_hidden, external_dir_num, location);
if (!add_root)
pgFileFree(file);
@ -585,7 +589,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, bool backup_replslots)
dir_check_file(pgFile *file, bool backup_logs)
{
int i;
int sscanf_res;
@ -648,29 +652,6 @@ dir_check_file(pgFile *file, bool backup_logs, bool backup_replslots)
}
}
/*
* Backup pg_replslot if it is specified.
* It is generally not useful to backup the contents of this directory even
* if the intention is to restore to another master. See backup.sgml for a
* more detailed description.
*/
if (!backup_replslots) {
if (strcmp(file->rel_path, PG_REPLSLOT_DIR) == 0) {
/* Skip */
elog(VERBOSE, "Excluding directory content: %s", file->rel_path);
return CHECK_EXCLUDE_FALSE;
}
} else {
/*
* Check file that under pg_replslot and judge whether it
* belonged to logical replication slots for subscriptions.
*/
if (strcmp(file->rel_path, PG_REPLSLOT_DIR) != 0 &&
path_is_prefix_of_path(PG_REPLSLOT_DIR, file->rel_path)) {
return check_logical_replslot_dir(file->rel_path);
}
}
ret = check_nobackup_dir(file);
if (ret != -1) { /* -1 means need backup */
return ret;
@ -768,35 +749,6 @@ 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;
@ -937,8 +889,7 @@ 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 backup_replslots)
bool skip_hidden, int external_dir_num, fio_location location)
{
DIR *dir;
struct dirent *dent;
@ -986,7 +937,7 @@ dir_list_file_internal(parray *files, pgFile *parent, const char *parent_dir,
if (exclude)
{
check_res = dir_check_file(file, backup_logs, backup_replslots);
check_res = dir_check_file(file, backup_logs);
if (check_res == CHECK_FALSE)
{
/* Skip */
@ -1012,7 +963,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_replslots);
backup_logs, skip_hidden, external_dir_num, location);
}
if (errno && errno != ENOENT)

View File

@ -51,7 +51,6 @@ typedef struct
bool exclusive_backup;
bool skip_hidden;
int external_dir_num;
bool backup_replslots;
} fio_list_dir_request;
typedef struct
@ -1795,7 +1794,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 backup_replslots)
bool skip_hidden, int external_dir_num)
{
fio_header hdr;
fio_list_dir_request req;
@ -1812,7 +1811,6 @@ void fio_list_dir(parray *files, const char *root, bool exclude,
req.exclusive_backup = exclusive_backup;
req.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);
@ -1872,14 +1870,7 @@ 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);
}
@ -1923,7 +1914,7 @@ static void fio_list_dir_impl(int out, char* buf)
dir_list_file(file_files, req->path, req->exclude, req->follow_symlink,
req->add_root, req->backup_logs, req->skip_hidden,
req->external_dir_num, FIO_LOCAL_HOST, req->backup_replslots);
req->external_dir_num, FIO_LOCAL_HOST);
/* send information about files to the main process */
for (i = 0; i < (int)parray_num(file_files); i++)

View File

@ -163,7 +163,5 @@ extern z_off_t fio_gzseek(gzFile f, z_off_t offset, int whence);
extern const char* fio_gzerror(gzFile file, int *errnum);
#endif
extern char check_logical_replslot_dir(const char *rel_path);
#endif

View File

@ -154,7 +154,6 @@ 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);
@ -421,7 +420,6 @@ 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"));
@ -443,7 +441,6 @@ 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"));

View File

@ -77,7 +77,6 @@ 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;
@ -187,7 +186,6 @@ 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 },
@ -552,7 +550,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, backup_replslots);
return do_backup(start_time, set_backup_params, no_validate, no_sync, backup_logs);
}
case RESTORE_CMD:
return do_restore_or_validate(current.backup_id,

View File

@ -69,7 +69,6 @@ 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

View File

@ -54,9 +54,6 @@ 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;
@ -92,7 +89,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 backup_replslots);
bool no_validate, bool no_sync, bool backup_logs);
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,
@ -242,8 +239,7 @@ 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 backup_replslots = false);
bool skip_hidden, int external_dir_num, fio_location location);
extern void create_data_directories(parray *dest_files,
const char *data_dir,
@ -436,8 +432,7 @@ extern int fio_send_file(const char *from_fullpath, const char *to_fullpath, FIL
pgFile *file, char **errormsg);
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 backup_replslots = false);
bool add_root, bool backup_logs, bool skip_hidden, int external_dir_num);
extern bool pgut_rmtree(const char *path, bool rmtopdir, bool strict);

View File

@ -6230,7 +6230,7 @@ Datum GetPartBoundaryByTuple(Relation rel, HeapTuple tuple)
return Timestamp2Boundarys(rel, Align2UpBoundary(value, partMap->intervalValue, boundaryTs));
}
Oid AddNewIntervalPartition(Relation rel, void* insertTuple, bool isDDL)
Oid AddNewIntervalPartition(Relation rel, void* insertTuple)
{
Relation pgPartRel = NULL;
Oid newPartOid = InvalidOid;
@ -6327,13 +6327,7 @@ Oid AddNewIntervalPartition(Relation rel, void* insertTuple, bool isDDL)
*/
CommandCounterIncrement();
/*
* 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);
}
UpdatePgObjectChangecsn(RelationGetRelid(rel), rel->rd_rel->relkind);
return newPartOid;
}
@ -7119,7 +7113,7 @@ int lookupHBucketid(oidvector *buckets, int low, int2 bktId)
* Description :
* Notes :
*/
Oid heapTupleGetPartitionId(Relation rel, void *tuple, bool isDDL)
Oid heapTupleGetPartitionId(Relation rel, void *tuple)
{
Oid partitionid = InvalidOid;
@ -7146,7 +7140,7 @@ Oid heapTupleGetPartitionId(Relation rel, void *tuple, bool isDDL)
(errcode(ERRCODE_NO_DATA_FOUND), errmsg("inserted partition key does not map to any table partition")));
} break;
case PART_AREA_INTERVAL: {
return AddNewIntervalPartition(rel, tuple, isDDL);
return AddNewIntervalPartition(rel, tuple);
} break;
case PART_AREA_LIST: {
ereport(ERROR,

View File

@ -52,7 +52,7 @@ static_assert(sizeof(false) == sizeof(char), "illegal bool size");
static struct HTAB* nameHash = NULL;
static struct HTAB* oidHash = NULL;
/* for dolphin */
/* for b_sql_plugin */
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.dolphin) {
if (DB_IS_CMPT(B_FORMAT) && b_nameHash != NULL && u_sess->attr.attr_sql.b_sql_plugin) {
result = (HashEntryNameToFuncGroup *)hash_search(b_nameHash, &temp_name, action, &found);
} 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.dolphin) {
if (DB_IS_CMPT(B_FORMAT) && b_oidHash != NULL && u_sess->attr.attr_sql.b_sql_plugin) {
result = (HashEntryOidToBuiltinFunc *)hash_search(b_oidHash, &oid, action, &found);
} else {
result = (HashEntryOidToBuiltinFunc *)hash_search(oidHash, &oid, action, &found);

View File

@ -28,6 +28,7 @@
#include "utils/builtins.h"
#include "utils/fmgroids.h"
#include "utils/syscache.h"
#include "replication/worker_internal.h"
static List *textarray_to_stringlist(ArrayType *textarray);
@ -90,13 +91,6 @@ Subscription *GetSubscription(Oid subid, bool missing_ok)
}
sub->publications = textarray_to_stringlist(DatumGetArrayTypeP(datum));
datum = SysCacheGetAttr(SUBSCRIPTIONOID, tup, Anum_pg_subscription_subbinary, &isnull);
if (unlikely(isnull)) {
sub->binary = false;
} else {
sub->binary = DatumGetBool(datum);
}
ReleaseSysCache(tup);
return sub;
@ -189,7 +183,7 @@ char *get_subscription_name(Oid subid, bool missing_ok)
}
/* Clear the list content, only deal with DefElem and string content */
void ClearListContent(List *list)
static void ClearListContent(List *list)
{
ListCell *cell = NULL;
foreach(cell, list) {
@ -209,6 +203,25 @@ void ClearListContent(List *list)
}
}
/*
* Decrypt conninfo for subscription.
* IMPORTANT: caller should clear and free the memory after using it immediately
*/
char *DecryptConninfo(char *encryptConninfo)
{
const char* sensitiveOptionsArray[] = {"password"};
const int sensitiveArrayLength = lengthof(sensitiveOptionsArray);
List *defList = ConninfoToDefList(encryptConninfo);
DecryptOptions(defList, sensitiveOptionsArray, sensitiveArrayLength, SUBSCRIPTION_MODE);
char *decryptConninfo = DefListToString(defList);
/* defList has plain content, clear it before free */
ClearListContent(defList);
list_free_ext(defList);
/* IMPORTANT: caller should clear and free the memory after using it immediately */
return decryptConninfo;
}
/*
* Convert text array to list of strings.
*

View File

@ -309,7 +309,6 @@ bool pg_md5_encrypt(const char* passwd, const char* salt, size_t salt_len, char*
{
size_t passwd_len = strlen(passwd);
errno_t rc = EOK;
/* the length of salt and password is <= SIZE_MAX */
#ifndef WIN32
if (unlikely(passwd_len >= SIZE_MAX - salt_len)) {
return false;
@ -323,7 +322,6 @@ bool pg_md5_encrypt(const char* passwd, const char* salt, size_t salt_len, char*
char* crypt_buf = (char*)malloc(passwd_len + salt_len + 1);
bool ret = false;
/* the buffer is not exist */
if (crypt_buf == NULL)
return false;

View File

@ -772,15 +772,6 @@ bool pg_sha256_encrypt_for_md5(const char* password, const char* salt, size_t sa
return true;
}
/*
* @Description: calculate the encrypted password for GsSm3.
* @const char* password : the password need be encrypted.
* @const char* salt_s : the content fo the slat.
* @size_t salt_len : the length fo the slat.
* @char* buf : the buffer to store the encrypted key with GsSm3.
* @char* client_key_buf : the buffer to store the key of client.
* @int iteration_count : to record the number of the iteration.
*/
bool GsSm3Encrypt(
const char* password, const char* salt_s, size_t salt_len, char* buf, char* client_key_buf, int iteration_count)
{
@ -808,7 +799,6 @@ bool GsSm3Encrypt(
}
password_len = strlen(password);
/* Tranform string(64Bytes) to binary(32Bytes) */
sha_hex_to_bytes32(salt, (char*)salt_s);
/* calculate k */
pkcs_ret = PKCS5_PBKDF2_HMAC((char*)password,

View File

@ -70,7 +70,6 @@
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
@ -402,27 +401,24 @@ 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); \
/* 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); \
} \
} \
#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); \
} \
} \
} while (0)
#define READ_TYPEINFO(typePtr) \
@ -497,30 +493,9 @@ THR_LOCAL bool skip_read_extern_fields = false;
token = pg_strtok(&length); \
token = pg_strtok(&length); \
funcnamespace = nullable_string(token, length); \
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; \
if (IS_PGXC_DATANODE && !skip_read_extern_fields) { \
local_node->fldname = \
get_func_oid(funcname, get_namespace_oid(funcnamespace, false), (Expr*)local_node); \
} \
pfree_ext(funcname); \
pfree_ext(funcnamespace); \
@ -550,7 +525,7 @@ THR_LOCAL bool skip_read_extern_fields = false;
token = pg_strtok(&length); \
token = pg_strtok(&length); \
oprrightname = nullable_string(token, length); \
if (IS_DATANODE_BUT_NOT_SINGLENODE) { \
if (IS_PGXC_DATANODE) { \
namespaceId = get_namespace_oid(opnamespace, false); \
oprleft = get_typeoid(namespaceId, oprleftname); \
oprright = oprleft; \
@ -593,7 +568,7 @@ THR_LOCAL bool skip_read_extern_fields = false;
token = pg_strtok(&length); \
token = pg_strtok(&length); \
oprrightname = nullable_string(token, length); \
if (IS_DATANODE_BUT_NOT_SINGLENODE) { \
if (IS_PGXC_DATANODE) { \
namespaceId = get_namespace_oid(opnamespace, false); \
oprleft = get_typeoid(namespaceId, oprleftname); \
oprright = oprleft; \
@ -2151,21 +2126,14 @@ static FuncExpr* _readFuncExpr(void)
ereport(ERROR, (errcode(ERRCODE_UNEXPECTED_NULL_VALUE), errmsg("NULL seqNamespace for nextval()")));
}
if (IS_DATANODE_BUT_NOT_SINGLENODE && !skip_read_extern_fields) {
if (!IS_PGXC_COORDINATOR && !skip_read_extern_fields) {
Oid seqid = get_valid_relname_relid(seqNamespace, seqName);
Oid seqid = get_valid_relname_relid(seqNamespace, seqName, true);
Const* firstArg = (Const*)linitial(local_node->args);
if (OidIsValid(seqid)) {
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);

File diff suppressed because it is too large Load Diff

View File

@ -1454,14 +1454,7 @@ 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;
}

View File

@ -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, AllocSetContextUsedSpace(((AllocSet)entry->rel_mem_manager)));
pg_atomic_fetch_sub_u64(&m_base_space, rel_size);
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, AllocSetContextUsedSpace(((AllocSet)entry->rel_mem_manager)));
pg_atomic_fetch_add_u64(&m_base_space, rel_size);
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;
}
}

View File

@ -659,27 +659,7 @@ 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)
@ -1292,18 +1272,9 @@ 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;
}
}
}

View File

@ -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;
}

View File

@ -74,7 +74,7 @@ Partition LocalPartDefCache::SearchPartitionFromGlobalCopy(Oid part_oid)
if (!g_instance.global_sysdbcache.hot_standby) {
return NULL;
}
if (unlikely(!IsPrimaryRecoveryFinished())) {
if (unlikely(!g_instance.global_sysdbcache.recovery_finished)) {
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(!IsPrimaryRecoveryFinished())) {
if (unlikely(!g_instance.global_sysdbcache.recovery_finished)) {
return false;
}
if (g_instance.global_sysdbcache.StopInsertGSC()) {
@ -456,4 +456,4 @@ Partition LocalPartDefCache::PartitionIdGetPartition(Oid part_oid, StorageType s
}
return pd;
}
}

View File

@ -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(!IsPrimaryRecoveryFinished());
unlikely(!g_instance.global_sysdbcache.recovery_finished);
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(!IsPrimaryRecoveryFinished());
unlikely(!g_instance.global_sysdbcache.recovery_finished);
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(!IsPrimaryRecoveryFinished());
unlikely(!g_instance.global_sysdbcache.recovery_finished);
if (invalid_entries.ExistTuple(hash_value) || bypass_gsc) {
global_ct = m_global_systupcache->SearchTupleFromFileWithArgModes(hash_value, arguments, argModes, true);
} else {

View File

@ -93,7 +93,7 @@ Relation LocalTabDefCache::SearchRelationFromGlobalCopy(Oid rel_oid)
if (!g_instance.global_sysdbcache.hot_standby) {
return NULL;
}
if (unlikely(!IsPrimaryRecoveryFinished())) {
if (unlikely(!g_instance.global_sysdbcache.recovery_finished)) {
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(!IsPrimaryRecoveryFinished())) {
if (unlikely(!g_instance.global_sysdbcache.recovery_finished)) {
return false;
}
if (g_instance.global_sysdbcache.StopInsertGSC()) {
@ -1137,4 +1137,4 @@ void LocalTabDefCache::ResetInitFlag()
m_is_inited_phase3 = false;
m_db_id = InvalidOid;
}
}

View File

@ -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, bool nsp_missing_ok)
Oid get_valid_relname_relid(const char* relnamespace, const char* relname)
{
Oid nspid = InvalidOid;
Oid oldnspid = InvalidOid;
@ -1747,10 +1747,7 @@ Oid get_valid_relname_relid(const char* relnamespace, const char* relname, bool
if (EnableLocalSysCache()) {
thrd_inval_count = t_thrd.lsc_cxt.lsc->inval_cxt.SIMCounter;
}
nspid = get_namespace_oid(relnamespace, nsp_missing_ok);
if (!OidIsValid(nspid)) {
return InvalidOid;
}
nspid = get_namespace_oid(relnamespace, false);
relid = get_relname_relid(relname, nspid);
/*
* In bootstrap processing mode, we don't bother with locking

View File

@ -59,7 +59,7 @@ bool open_join_children = true;
bool will_shutdown = false;
/* hard-wired binary version number */
const uint32 GRAND_VERSION_NUM = 92606;
const uint32 GRAND_VERSION_NUM = 92605;
const uint32 PREDPUSH_SAME_LEVEL_VERSION_NUM = 92522;
const uint32 UPSERT_WHERE_VERSION_NUM = 92514;
@ -101,7 +101,6 @@ const uint32 PRIVS_DIRECTORY_VERSION_NUM = 92460;
const uint32 COMMENT_RECORD_PARAM_VERSION_NUM = 92484;
const uint32 SCAN_BATCH_MODE_VERSION_NUM = 92568;
const uint32 PUBLICATION_VERSION_NUM = 92580;
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;

View File

@ -2712,8 +2712,8 @@ void PostgresInitializer::InitExtensionVariable()
}
/* check whether the extension has been created */
const char* dolphin = "dolphin";
u_sess->attr.attr_sql.dolphin = CheckIfExtensionExists(dolphin);
const char* b_sql_plugin = "b_sql_plugin";
u_sess->attr.attr_sql.b_sql_plugin = CheckIfExtensionExists(b_sql_plugin);
}
void PostgresInitializer::FinishInit()

View File

@ -10340,16 +10340,7 @@ check_sql_expr(const char *stmt, int location, int leaderlen)
oldCxt = MemoryContextSwitchTo(u_sess->plsql_cxt.curr_compile_context->compile_tmp_cxt);
u_sess->plsql_cxt.plpgsql_yylloc = plpgsql_yylloc;
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);
(void) raw_parser(stmt);
MemoryContextSwitchTo(oldCxt);
/* Restore former ereport callback */

View File

@ -44,22 +44,11 @@ static int g_iPosBlackList = 0;
/* array store for black list */
static BBOX_BLACKLIST_STRU g_stBlackList[BBOX_BLACK_LIST_COUNT_MAX];
/*
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.
noteThe 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
*/
/*
* Determines whether the byte order of the local machine is large or small
* return : ELFDATA2LSB - large
* : ELFDATA2MSB - small
*/
int BBOX_DetermineMsb(void)
{
union INT_PROBE {

View File

@ -51,19 +51,8 @@ struct PIPE_IDS {
static struct PIPE_IDS astPipeIds[BBOX_MAX_PIDS];
/*
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.
noteThe two pointers shouldn't be null. The last argument shouldn't less than zero.
date: 2022/8/2
contact tel: 18720816902
*/
* compare string pszSrc and pszTarget
*/
s32 bbox_strncmp(const char* pszSrc, const char* pszTarget, s32 count)
{
signed char cRes = 0;
@ -79,20 +68,8 @@ s32 bbox_strncmp(const char* pszSrc, const char* pszTarget, s32 count)
}
/*
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.
noteThe two pointers shouldn't be null. The last argument shouldn't less than zero.
date: 2022/8/2
contact tel:same
*/
* compare string pszSrc and pszTarget
*/
s32 bbox_strcmp(const char* pszSrc, const char* pszTarget)
{
unsigned char c1, c2;
@ -113,15 +90,8 @@ s32 bbox_strcmp(const char* pszSrc, const char* pszTarget)
}
/*
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
*/
* get the length of string pszString
*/
s32 bbox_strlen(const char* pszString)
{
const char* pszTemp = NULL;
@ -135,16 +105,8 @@ s32 bbox_strlen(const char* 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
*/
* get the length of string pszString
*/
s32 bbox_strnlen(const char* pszString, s32 count)
{
const char* pszTemp = NULL;
@ -157,16 +119,8 @@ s32 bbox_strnlen(const char* pszString, s32 count)
}
/*
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
*/
* convert a string to interger
*/
s32 bbox_atoi(const char* pszString)
{
s32 n = 0;
@ -186,18 +140,10 @@ s32 bbox_atoi(const char* pszString)
return iNeg ? -n : n;
}
/*
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
*/
* compare memory
*/
s32 bbox_memcmp(const void* cs, const void* ct, s32 count)
{
const unsigned char *su1 = NULL;
@ -213,18 +159,8 @@ s32 bbox_memcmp(const void* cs, const void* ct, s32 count)
}
/*
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
*/
* search string l2 in l1
*/
char* bbox_strstr(const char* s1, const char* s2)
{
int l1, l2;
@ -246,17 +182,8 @@ char* bbox_strstr(const char* s1, const char* s2)
}
/*
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
*/
* make a directory
*/
s32 bbox_mkdir(const char* pszDir)
{
char szDirName[BBOX_TMP_LEN_32 * 16];
@ -301,16 +228,8 @@ s32 bbox_mkdir(const char* pszDir)
}
/*
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
*/
* search free pipe id
*/
struct PIPE_ID* bbox_GetFreePid(void)
{
u32 i;
@ -326,14 +245,8 @@ struct PIPE_ID* bbox_GetFreePid(void)
}
/*
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
*/
* Release the occupied pipeid
*/
void bbox_PutPid(struct PIPE_ID* pstPid)
{
struct PIPE_IDS* pstPids = NULL;
@ -348,16 +261,8 @@ void bbox_PutPid(struct PIPE_ID* pstPid)
}
/*
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
*/
* find available pipe id by file handle
*/
struct PIPE_ID* bbox_FindPid(int iFd)
{
u32 i;
@ -376,17 +281,8 @@ struct PIPE_ID* bbox_FindPid(int iFd)
}
/*
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
*/
* run popen
*/
s32 sys_popen(char* pszCmd, const char* pszMode)
{
struct PIPE_ID* volatile stCurPid = NULL;
@ -491,15 +387,8 @@ s32 sys_popen(char* pszCmd, const char* pszMode)
}
/*
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
*/
* close file handle
*/
int sys_pclose(s32 iFd)
{
struct PIPE_ID* pstCur = NULL;
@ -522,17 +411,8 @@ int sys_pclose(s32 iFd)
}
/*
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
*/
* list file in directory
*/
s32 bbox_listdir(const char* pstPath, BBOX_LIST_DIR_CALLBACK callback, void* pArgs)
{
struct linux_dirent* pstEntry = NULL;

View File

@ -57,37 +57,23 @@ void bbox_initlog(int iLogScreen)
}
/*
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
*/
* convert int to string
*/
inline char bbox_itoc(u8 sNum)
{
return (char)((sNum < 10) ? (sNum + 48) : (sNum + 87));
}
/*
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
*/
* 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
*/
s32 bbox_put_dox(BBOX_vnprintCallBack pCallback, void* ptr, s32* piCount, u32 iSize, u64 uNum, s32 sSys, s32 isNeg)
{
s64 i = 0;
@ -122,21 +108,15 @@ s32 bbox_put_dox(BBOX_vnprintCallBack pCallback, void* ptr, s32* piCount, u32 iS
return iRet;
}
/*
function name: bbox_vsnprintf
description: The function is used to print string in corresponding array.
arguments: The first argument is a pointer to a callback function, the next is a
pointer to private data to call this function, also to buffer.
The third is used to destine buffer size. The forth is used to destine
the print format of deferent string, the last is a pointer to variable parameter list.
return value: An integer, if iSize is big enough, then the return value is the length of
string been written in destined memory successfully, not include '\0',
if function makes errors, the return value is a negative integer.
note: none
date: 2022/8/3
contact tel: 18720816902
*/
* simple signal-safe function vsnprintf
* in : pCallback - call back function
* ptr - private data to call this function
* iSize - buffer size
* pFmt - format type
* ap - parameter list pointer¸ñʽ
* return : length of string
*/
s32 bbox_vsnprintf(BBOX_vnprintCallBack pCallback, void* ptr, s32 iSize, const char* pFmt, va_list ap)
{
@ -255,20 +235,13 @@ s32 bbox_vsnprintf(BBOX_vnprintCallBack pCallback, void* ptr, s32 iSize, const c
}
/*
function name: bbox_SnprintCallback
description: The function is used to print string in corresponding array, usually
used as the first argument of function bbox_vsnprintf.
arguments: The first argument is a character waited to be written into buffer that
pPtr directs, the second argument directs a buffer area, the third is a
pointer to an integera used to record the count to call this callback function,
at the same time, it represents the count of characters written into buffer, it's
a pointer so that we can conveniently modify data storedin it. The last
argument destines the size of buffer, it represents the limit of length.
return value: An integer, if written successfully, it's RET_OK, else it's RET_ERR.
note: none
date: 2022/8/3
contact tel: 18720816902
*/
* call back function of snprintf_s
* in : c - string to calculate
* pPtr - pointer to buffer
* piCount - count of character
* iSize - limit of length
* return : length of string
*/
s32 bbox_SnprintCallback(char c, void* pPtr, s32* piCount, s32 iSize)
{
char** pszBuff = (char**)pPtr;

View File

@ -64,14 +64,8 @@ u8 g_szAltStackMem[BBOX_ALT_STACKSIZE]; /* independent thread stack memory */
BBOX_ATOMIC_STRU g_isBusy = BBOX_ATOMIC_INIT(0); /* whether deal with core file. */
/*
function name: BBOX_ReserveZeroStack
description: The function creat a empty stack, and its size depend on argument count.
arguments: An integer of type s32, namely int, it destines the storage of stack.
return value: void
note: The stack this function creats is actually a character array.
date: 2022/8/3
contact tel: 18720816902
*/
* reserved count bytes on current stack, and set 0
*/
void BBOX_ReserveZeroStack(s32 count)
{
char buff[count];
@ -101,14 +95,8 @@ s32 BBOX_CloneRun(u32 uFlags, s32 (*pFn)(void*), void* pArg, ...)
}
/*
function name: BBOX_GetTaskNumber
description: When get a path to specific process, this function will return count of threads below it.
arguments: A pointer of type char*, including a path to specific process.
return value: An integer that indicates the count of threads below specific process.
note: none
date: 2022/8/3
contact tel: 18720816902
*/
* get count of thread
*/
s32 BBOX_GetTaskNumber(char* szTaskPath)
{
struct kernel_stat stProcSB = {0};
@ -142,17 +130,8 @@ s32 BBOX_GetTaskNumber(char* szTaskPath)
}
/*
function name: BBOX_GetTaskId
description: When get a path to specific process, this function will return count of threads below it.
arguments: The first argument is a structure pointer named pstTaskInfo,its type is struct TASK_ATTACH_INFO*,
we use it as a structure array to store requisite thread infomation, the next argument destines
the max size of the array that the first argument destines. The last argument is a pointer of type
char*, including a path to specific process.
return value: An integer that indicates the count of threads stored in structure array.
note: none
date: 2022/8/3
contact tel: 18720816902
*/
* get thread pid
*/
s32 BBOX_GetTaskId(struct TASK_ATTACH_INFO* pstTaskInfo, s32 iSize, char* szTaskPath)
{
s32 iProc = -1;
@ -235,19 +214,13 @@ errout:
}
/*
function name: BBOX_PtraceAttachPid
description: The function is used to check the process whose id stored in structure array pstTaskInfo work normally.
arguments: The first argument is a structure pointer named pstTaskInfo,its type is struct TASK_ATTACH_INFO*,
it is used as a structure array that has stored requisite thread infomation, the next argument destines
the size of the array that the first argument destines, namely how many elements the array has.
The last argument is an integer to decide if need to check if the trace to destined process
work normally, if normal, corresponding element of array pstTaskInfo's member variable cIsAttached
will change from 0 to 1.
return value: An integer, if function work normally, the value is RET_OK, else is RET_ERR.
note: none
date: 2022/8/3
contact tel: 18720816902
*/
* a ptrace debug thread
* in : TASK_ATTACH_INFO - thread information
* iPidCount - count of thread information
* iDoPtraceCheck - check if ptrace success
* return : 0 - success
* err code - failed
*/
s32 BBOX_PtraceAttachPid(struct TASK_ATTACH_INFO* pstTaskInfo, s32 iPidCount, s32 iDoPtraceCheck)
{
u32 i;
@ -299,18 +272,13 @@ s32 BBOX_PtraceAttachPid(struct TASK_ATTACH_INFO* pstTaskInfo, s32 iPidCount, s3
}
/*
function name: BBOX_DetachAllThread
description: The function is used to cancel checking the process whose id stored in structure array pstTaskInfo
work normally, "work normally" means in array pstTaskInfo corresponding element's member
variable cIsAttached's value is 1.
arguments: The first argument is a structure pointer named pstTaskInfo,its type is struct TASK_ATTACH_INFO*,
it is used as a structure array that has stored requisite thread infomation, the next argument destines
the size of the array that the first argument destines, namely how many elements the array has.
return value: void
note: none
date: 2022/8/3
contact tel: 18720816902
*/
* cancel ptrace debug thread
* in : TASK_ATTACH_INFO - thread information
* iPidCount - count of thread information
* iDoPtraceCheck - check if ptrace success
* return : 0 - success
* err code - failed
*/
void BBOX_DetachAllThread(struct TASK_ATTACH_INFO* pstTaskInfo, s32 iPidCount)
{
u32 i;
@ -355,18 +323,12 @@ void BBOX_CheckResumeThread(void* pArgs)
}
/*
function name: BBOX_PtraceAndRun
description: When get a path to specific process, this function will trace the threads below it, and get the
information for example how many threads work normally then store it in pstArgs.
arguments: The first argument is a structure pointer named pstArgs, its type is struct BBOX_ListParams*,
what matters is its member variable callback function pointer, the next argument destines
the max count of the thread. The last argument is a pointer of type char*, including a path
to specific process.
return value: An integer, if function work normally, the value is RET_OK, else is RET_ERR.
note: none
date: 2022/8/3
contact tel: 18720816902
*/
* ptrace thread and run function.
* in : pstArgs - information of callback function
* iMaxThreadCount - max count of thread
* pszProcSelfTask - /proc/[pid]/task of current tracked thread.
* return 0 if success else err code.
*/
s32 BBOX_PtraceAndRun(struct BBOX_ListParams* pstArgs, s32 iMaxThreadCount, char* pszProcSelfTask)
{
struct TASK_ATTACH_INFO stTaskInfo[iMaxThreadCount];
@ -445,15 +407,8 @@ errout:
}
/*
function name: BBOX_PrintFailedLog
description: Write log infomation into specific file, if errors arise, print the infomation about errors.
arguments: The only argument is a pointer of type const char* to a filename string, if this file doesn't
exist, we will creat a new file named it.
return value: An integer, if function work normally, the value is RET_OK, else is RET_ERR.
note: none
date: 2022/8/3
contact tel: 18720816902
*/
* print log information if export failed.
*/
void BBOX_PrintFailedLog(const char* pFileName)
{
ssize_t iRet = 0;
@ -482,15 +437,8 @@ void BBOX_PrintFailedLog(const char* pFileName)
}
/*
function name: BBOX_ListThread
description: Export thread information.
arguments: The only argument is a structure pointer named pstArgs, its type is struct BBOX_ListParams*,
what matters is its member variable callback function pointer and thread infomation.
return value: void
note: none
date: 2022/8/3
contact tel: 18720816902
*/
* export thread information.
*/
void BBOX_ListThread(struct BBOX_ListParams* pstArgs)
{
pid_t ppid = 0;
@ -597,18 +545,12 @@ errout:
}
/*
function name: BBOX_GetClonePidResult
description: The function get the status of child process at first, then according to it assign pstArgs's
member variables iError and iResult appropriate values.
arguments: The first argument is a integer named iClonePid, it represents the pid of child process.
The second argument is a structure pointer named pstArgs, its type is struct BBOX_ListParams*,
what matters is its member variable callback function pointer and thread infomation.
The third argument is a integer indicating error code.
return value: An integer, if function work normally, the value is RET_OK, else is RET_ERR.
note: none
date: 2022/8/3
contact tel: 18720816902
*/
* get return value of child process
* in : iClonePid - PID of child process
* pstArgs - parameter
* iCloneErrno - err code
* return 0 if success else failed.
*/
s32 BBOX_GetClonePidResult(pid_t iClonePid, struct BBOX_ListParams* pstArgs, s32 iCloneErrno)
{
s32 iStatus = 0;

View File

@ -57,22 +57,6 @@ BlacklistItem g_blacklist_items[] = {
{DATA_WRITER_QUEUE, "DATA_WRITER_QUEUE", false}
};
/*
function name: coredump_handler
description: When a program is abnormal, but the exception appears in the core of process and wasn't caught,
The function will generate a file to store the information about memory of process, status of register
and running stack.
arguments: The first argument is an integer indicating signal code that usually used in program of processing
signal as variable.
The second argument is a structure pointer of type siginfo_t*, the memory that this pointer
directs stores comprehensive information about signal, for example, which process sends
and which user sends.
The third argument is a pointer of type void*, other kinds of pointers can directly used here.
return value: void
note: none
date: 2022/8/4
contact tel: 18720816902
*/
static void coredump_handler(int sig, siginfo_t *si, void *uc)
{
static volatile int64 first_tid = INVALID_TID;
@ -100,19 +84,8 @@ static void coredump_handler(int sig, siginfo_t *si, void *uc)
}
/*
function name: bbox_handler
description: Handle signal conditions for bbox.
arguments: The first argument is an integer indicating signal code that usually used in program of processing
signal as variable.
The second argument is a structure pointer of type siginfo_t*, the memory that this pointer
directs stores comprehensive information about signal, for example, which process sends
and which user sends.
The third argument is a pointer of type void*, other kinds of pointers can directly used here.
return value: void
note: none
date: 2022/8/4
contact tel: 18720816902
*/
* bbox_handler - handle signal conditions for bbox
*/
static void bbox_handler(int sig, siginfo_t *si, void *uc)
{
static volatile int64 first_tid = INVALID_TID;
@ -152,16 +125,8 @@ static void bbox_handler(int sig, siginfo_t *si, void *uc)
}
/*
function name: get_bbox_coredump_pattern_path
description: Get the core dump file's path from the file "/proc/sys/kernel/core_pattern".
arguments: The first argument is a pointer to string, we use it to store core dump file's path acquired
from the file "/proc/sys/kernel/core_pattern", the next argument is the number of characters
reading from the file "/proc/sys/kernel/core_pattern", all len-1 characters or less if appear '\n'.
return value: void
note: none
date: 2022/8/4
contact tel: 18720816902
*/
* get_bbox_coredump_pattern_path - get the core dump path from the file "/proc/sys/kernel/core_pattern"
*/
static void get_bbox_coredump_pattern_path(char* path, Size len)
{
FILE* fp = NULL;
@ -191,17 +156,7 @@ static void get_bbox_coredump_pattern_path(char* path, Size len)
}
}
/*
function name: build_bbox_corepath
description: Get the core dump file's path.
arguments: The first argument is a pointer to string, we use it to store core dump file's path,
the next argument is the size of the path's name, the last argument is a pointer
to string that indicates maybe store a path to configure the core dump file.
return value: void
note: none
date: 2022/8/4
contact tel: 18720816902
*/
/* compute directory into which bbox dump core files are saved. */
static void build_bbox_corepath(char *bbox_core_path, Size path_size, char *config_path)
{
struct stat stat_buf;
@ -277,15 +232,6 @@ void assign_bbox_corepath(const char* newval, void* extra)
return;
}
/*
function name: show_bbox_dump_path
description: Get the dump file's path.
arguments: void
return value: A pointer of type const char*, directing the path to dump or NULL.
note: none
date: 2022/8/4
contact tel: 18720816902
*/
const char* show_bbox_dump_path(void)
{
const char* path = g_bbox_dump_path;
@ -293,15 +239,6 @@ const char* show_bbox_dump_path(void)
return (path != NULL) ? path : "";
}
/*
function name: split_string_into_blacklist
description: Get all strings been divided into character ',' in source string.
arguments: A pointer of type const char*, directing the source string.
return value: A pointer of type static List*.
note: none
date: 2022/8/4
contact tel: 18720816902
*/
static List* split_string_into_blacklist(const char* source)
{
List *result = NIL;
@ -327,6 +264,7 @@ static List* split_string_into_blacklist(const char* source)
return result;
}
bool check_bbox_blacklist(char** newval, void** extra, GucSource source)
{
if (t_thrd.proc_cxt.MyProcPid != PostmasterPid)
@ -464,15 +402,10 @@ void bbox_blacklist_remove(BlacklistIndex item, void* addr)
}
/*
function name: CheckFilenameValid
description: Check if the filename is in line with norms, or if dangerous characters appear
the filename is invalid.
arguments: A pointer to string indicating filename.
return value: An integer, if function works normally, the value is RET_OK, else it's RET_ERR.
note: none
date: 2022/8/4
contact tel: 18720816902
*/
* @Description: check the value from environment variablethe to prevent command injection.
* @in input_env_value : the input value need be checked.
*
*/
int CheckFilenameValid(const char* inputEnvValue)
{
const int maxLen = 1024;

View File

@ -45,15 +45,6 @@
static bool CommCheckFilterMatch(const char *filter, int len, const char *ip, int port);
/*
function name: SetCPUAffinity
description: The function set the affinity of CPU or CPUs destined by argument cpu_id.
arguments: An integer representing the id of one CPU or more.
return value: void
note: none
date: 2022/8/5
contact: 18720816902
*/
void SetCPUAffinity(int cpu_id)
{
cpu_set_t mask;
@ -279,15 +270,6 @@ IPAddrType CommLibNetGetIPType(unsigned int ip)
#define CMD_STR_MAX 512
#define CMD_OUTPUT_BUFFER_SIZE 1024
/*
function name: CommCheckLtranProcess
description: The function check if the process currently working has loaded transactions.
arguments: void
return value: 0 or 1, if 1, then at least one loaded transcation exists, if 0, no one.
note: none
date: 2022/8/5
contact: 18720816902
*/
int CommCheckLtranProcess()
{
AutoContextSwitch commContext(g_instance.comm_cxt.comm_global_mem_cxt);
@ -405,21 +387,6 @@ static T GetCommProxySubParameter(const char* str_attr, const char* key)
return res;
}
/*
function name: ParseCommProxyNumaBind
description: Get the ids of CPU to bind process with specific CPU.
arguments: The first argument is a pointer of type const char* to a string that indicating
the id of CPUs below NUMA, not necessarily all CPUs.
The second argument is an integer telling us we will get CPUs' id from which position
of array str_attr.
The third argument tells us the number of NUMA system framework.
The fourth argument is a pointer to an integer array used to store CPUs' id gotten
from string str_attr, we can use these ids to bind specific CPU.
return value: void
note: none
date: 2022/8/5
contact: 18720816902
*/
static void ParseCommProxyNumaBind(
const char* str_attr, const int pos, const int numa_num, int* numa_bind)
{
@ -520,22 +487,6 @@ bool ParseCommProxyAttr(CommProxyConfig* config)
return true;
}
/*
function name: CommCheckFilterMatch
description: This function compare the ip and port allowed with ip and port gotten from
Filter, if they are correspondingly same, it will return true value.
arguments: The first argument is a pointer of type const char* to a string that indicating
the id and port of the request been sent to Filter, the id and port have been
separated by character ':'.
The second argument is an integer telling us we the length of the string first
argument directs.
The third argument tells us the ip allowed.
The fourth argument tells us the port allowed.
return value: static bool
note: none
date: 2022/8/4
contact: 18720816902
*/
static bool CommCheckFilterMatch(const char *filter, int len, const char *ip, int port)
{
char *str_ip = NULL;

View File

@ -175,24 +175,6 @@ void UpdateTxRxStats(int msg_level)
last_rx_nbytes = current_rx_nbytes;
}
/*
function name: parse_monitor_sock_queue
description: Compare the string recv_buffer with "sockqueue fd:fd", the "fd"
after character ':' is an integer indicating file descriptor. If recv_buffer
accords with the format, the function will takes next action to see if
fd is 0, which represents stdin, so the function ends with returned value 0.
If fd isn't 0, compare the third argument type with ParseMonitorTypeSet,
if equal, then get a structure variable including socket descriptor
destined by the fd gotten from the first argument, if it's NULL, we can
write "fd:[%d], type:[normal fd], no sock queue" into send_buffer.
arguments: The first argument is a pointer to a string indicating request infomation.
The second argument is a pointer to a string to store sent infomation.
The third argument tells the kind of socket request.
return value: 0 or 1.
note: none
date: 2022/8/5
contact tel: 18720816902
*/
int parse_monitor_sock_queue(char* recv_buffer, char* send_buffer, ParseMonitorType type)
{
int length;
@ -223,25 +205,6 @@ int parse_monitor_sock_queue(char* recv_buffer, char* send_buffer, ParseMonitorT
return 0;
}
/*
function name: parse_monitor_fd
description: Compare the string recv_buffer with "query fd:fd", the "fd"
after character ':' is an integer indicating file descriptor. If recv_buffer
accords with the format, the function will takes next action to see if
fd is 0, which represents stdin, so the function ends with returned value 0.
If fd isn't 0, compare the third argument type with ParseMonitorTypeSet,
if equal, then get a structure variable including socket descriptor
destined by the fd gotten from the first argument, if it's NULL, we can
write "fd:[%d], type:[normal fd]"(%d--fd) into send_buffer, else write
"fd:[%d], type:[%d]"(%d--fd,%d--sock_desc->m_fd_type).
arguments: The first argument is a pointer to a string indicating request infomation.
The second argument is a pointer to a string to store sent infomation.
The third argument tells the kind of socket request.
return value: 0 or 1.
note: none
date: 2022/8/5
contact tel: 18720816902
*/
int parse_monitor_fd(char* recv_buffer, char* send_buffer, ParseMonitorType type)
{
int length;

View File

@ -53,24 +53,6 @@ static void comm_wait_broadcast_end(SocketRequest** req_arr, int num);
* export function definition
************************************************************************************
*/
/*
function name: comm_proxy_socket
description: This function creates a socket file descriptor whose protocol family is
domain, protocol type is type, and protocol number is protocol. If the
function call is successful, it will return a file descriptor that identifies
the socket. If it fails, it will return - 1.
arguments: The first argument specifies the protocol family, it's used as domain to
set up network communication.
The second argument is used to set the type of socket communication.
The third argument is used to specify a specific type of a protocol, which
is a type in the second argument types' type.
return value: If the function call is successful, it will return a file descriptor that
identifies the socket. If it fails, it will return - 1.
note: none
date: 2022/8/8
contact tel: 18720816902
*/
int comm_proxy_socket(int domain, int type, int protocol)
{
SocketRequest req;
@ -172,16 +154,6 @@ ssize_t comm_proxy_addr_recv(int sockfd, void *buf, size_t len, int flags)
return comm_proxy_recv(sockfd, buf, len, flags);
}
/*
function name: comm_proxy_close
description: The function is used to release the resources allocated
to the socket by the system.
arguments: The argument is the socket file descriptor to be closed.
return value: If the call is successful, return 0; otherwise, return - 1 and set errno.
note: none
date: 2022/8/8
contact tel: 18720816902
*/
int comm_proxy_close(int fd)
{
SocketRequest req;
@ -233,18 +205,6 @@ int comm_proxy_close(int fd)
return result.s_ret;
}
/*
function name: comm_proxy_shutdown
description: The function is used to release the resources allocated
to the socket by the system.
arguments: The first argument is a descriptor used to identify a socket.
The second argument is used to describe which operations
are prohibited, which determines the behavior of the function.
return value: If the call is successful, return 0; otherwise, return - 1 and set errno.
note: none
date: 2022/8/8
contact tel: 18720816902
*/
int comm_proxy_shutdown(int fd, int how)
{
SocketRequest req;
@ -299,21 +259,6 @@ int comm_proxy_shutdown(int fd, int how)
return result.s_ret;
}
/*
function name: comm_proxy_accept
description: This function extracts the first connection from the waiting connection queue of S, creates
a new socket interface similar to s and returns a handle.
arguments: The first argument is a socket descriptor, which listens for connection after comm_proxy_listen().
The second argument is a optional pointer pointing to a buffer where the address of the
connection entity known to the communication layer is received. The actual format of the
addr argument is determined by the address family generated when the socket is created.
The third argument is a optional pointer, used together with addr, pointing to the integer
number with the length of addr address.
return value: The return value is a new socket descriptor, which represents a new connection with the client.
note: none
date: 2022/8/8
contact tel: 18720816902
*/
int comm_proxy_accept(int sockfd, struct sockaddr* addr, socklen_t* addrlen)
{
SocketRequest req;
@ -398,17 +343,6 @@ int comm_proxy_accept4(int sockfd, struct sockaddr* addr, socklen_t* addrlen, in
return comm_proxy_accept(sockfd, addr, addrlen);
}
/*
function name: comm_proxy_connect
description: This function is used to establish a connection with a specified socket.
arguments: The first argument is used to identify an unconnected socket.
The second argument is a pointer to the sockaddr structure to socket will be connected.
The third argument is byte length of sockaddr structure.
return value: The return value is 0 if succeed, - 1 is returned for failure and error reason is stored in errno.
note: none
date: 2022/8/8
contact tel: 18720816902
*/
int comm_proxy_connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen)
{
SocketRequest req;
@ -460,17 +394,6 @@ int comm_proxy_connect(int sockfd, const struct sockaddr *addr, socklen_t addrle
return result.s_ret;
}
/*
function name: comm_proxy_bind
description: This function binds a local address with a set of interfaces.
arguments: The first argument indicates the socket descriptor that has been established.
The second argument is a pointer to the sockaddr structure to socket.
The third argument is byte length of sockaddr structure.
return value: The return value is 0 if succeed, - 1 is returned for failure and error reason is stored in errno.
note: none
date: 2022/8/8
contact tel: 18720816902
*/
int comm_proxy_bind(int sockfd, const struct sockaddr* ServerAddr, socklen_t addrlen)
{
SocketRequest req;
@ -498,16 +421,6 @@ int comm_proxy_bind(int sockfd, const struct sockaddr* ServerAddr, socklen_t add
return result.s_ret;
}
/*
function name: comm_proxy_listen
description: This function creates a socket interface and listens for the requested connection.
arguments: The first argument is a descriptor used to identify a bundled but unconnected socket.
The second argument indicates the maximum length of waiting for connection queue
return value: The return value is 0 if succeed, - 1 is returned for failure and error reason is stored in errno.
note: none
date: 2022/8/8
contact tel: 18720816902
*/
int comm_proxy_listen(int sockfd, int backlog)
{
SocketRequest req;
@ -534,19 +447,6 @@ int comm_proxy_listen(int sockfd, int backlog)
return result.s_ret;
}
/*
function name: comm_proxy_setsockopt
description: The function is used to set option values for sockets of any type and any state.
arguments: The first argument is a descriptor that identifies a socket interface.
The second argument indicates the level defined by the option.
The third argument specifies the option to be set.
The fourth argument is a pointer to the buffer where the new value of the option to be set is stored.
The fifth argument indicates optval buffer length.
return value: The return value is 0 if succeed, - 1 is returned for failure and error reason is stored in errno.
note: none
date: 2022/8/8
contact tel: 18720816902
*/
int comm_proxy_setsockopt(int sockfd, int level, int optname, const void* optval, socklen_t optlen)
{
SocketRequest req;
@ -576,19 +476,6 @@ int comm_proxy_setsockopt(int sockfd, int level, int optname, const void* optval
return result.s_ret;
}
/*
function name: comm_proxy_getsockopt
description: The function is used to obtain the current value of the option of any type and any state socket, and store the result in optval.
arguments: The first argument is a descriptor that identifies a socket interface.
The second argument indicates the level defined by the option.
The third argument specifies the socket options to be obtained.
The fourth argument is a pointer to the buffer where the obtained option value is stored.
The fifth argument is a pointer to the length value of optval buffer.
return value: The return value is 0 if succeed, - 1 is returned for failure and error reason is stored in errno.
note: none
date: 2022/8/8
contact tel: 18720816902
*/
int comm_proxy_getsockopt(int sockfd, int level, int optname, void* optval, socklen_t* optlen)
{
SocketRequest req;
@ -617,18 +504,6 @@ int comm_proxy_getsockopt(int sockfd, int level, int optname, void* optval, sock
return result.s_ret;
}
/*
function name: comm_proxy_getsockname
description: The function is used to get the name of a socket. It is used for a bundled or
connected socket, and the local address will be returned.
arguments: The first argument is a descriptor that identifies a socket interface.
The second argument indicates the address of the receiving socket.
The third argument specifies the length of the name buffer.
return value: The return value is 0 if succeed, - 1 is returned for failure and error reason is stored in errno.
note: none
date: 2022/8/8
contact tel: 18720816902
*/
int comm_proxy_getsockname(int sockfd, struct sockaddr* addr, socklen_t* addrlen)
{
SocketRequest req;
@ -655,17 +530,6 @@ int comm_proxy_getsockname(int sockfd, struct sockaddr* addr, socklen_t* addrlen
return result.s_ret;
}
/*
function name: comm_proxy_getpeername
description: The function is used to obtain the foreign protocol address associated with a socket.
arguments: The first argument is a descriptor that identifies a socket interface.
The second argument indicates the name structure of the receiver address.
The third argument specifies the length of the name structure.
return value: The return value is 0 if succeed, - 1 is returned for failure and error reason is stored in errno.
note: none
date: 2022/8/8
contact tel: 18720816902
*/
int comm_proxy_getpeername(int sockfd, struct sockaddr* addr, socklen_t* addrlen)
{
SocketRequest req;
@ -692,19 +556,6 @@ int comm_proxy_getpeername(int sockfd, struct sockaddr* addr, socklen_t* addrlen
return result.s_ret;
}
/*
function name: comm_proxy_fcntl
description: The function can change the nature of the opened file, it provides control over descriptors.
The argument sockfd is a descriptor operated by the argument cmd. For the value of cmd,
fcntl can accept the third argument arg, which is a variable argument.
arguments: The first argument is a descriptor that identifies a socket interface.
The second argument represents the instruction to be operated.
The third argument is a variable argument
return value: The return value is 0 if succeed, - 1 is returned for failure and error reason is stored in errno.
note: none
date: 2022/8/8
contact tel: 18720816902
*/
int comm_proxy_fcntl(int sockfd, int cmd, ...)
{
SocketRequest req;
@ -771,17 +622,6 @@ int comm_proxy_fcntl(int sockfd, int cmd, ...)
return result.s_ret;
}
/*
function name: comm_proxy_poll
description: The function is used to hang the current file pointer to the waiting queue.
arguments: The first argument is an array of struct pollfd structure type, used to store the socket descriptor whose state needs to be detected.
The second argument is used to mark the total number of structural elements in the array fdarray;
The third argument is the blocking time of the comm_proxy_poll function call.
return value: The return value is 0 if succeed, - 1 is returned for failure and error reason is stored in errno.
note: none
date: 2022/8/8
contact tel: 18720816902
*/
int comm_proxy_poll(struct pollfd* fdarray, unsigned long nfds, int timeout)
{
CommWaitPollParam param;
@ -818,15 +658,6 @@ int comm_proxy_poll(struct pollfd* fdarray, unsigned long nfds, int timeout)
return param.s_ret;
}
/*
function name: comm_proxy_epoll_create
description: The function is used to create a handle to epoll.
arguments: The only argument size is used to tell the kernel how many listeners there are.
return value: Returns a file descriptor that points to the newly created epoll instance
note: none
date: 2022/8/8
contact tel: 18720816902
*/
int comm_proxy_epoll_create(int size)
{
/*
@ -856,21 +687,6 @@ int comm_proxy_epoll_create1(int flag)
return comm_proxy_epoll_create(1);
}
/*
function name: comm_proxy_epoll_ctl
description: This system call performs control operations on the epoll instance referenced
by the file descriptor epfd. It requires the operation op to execute the target
file descriptor fd. It's used as epoll's event registration function, it adds,
modifies, or deletes events of interest to the epoll object.
arguments: The first argument is a specific file descriptor for epoll generated by epoll_ create.
The second argument indicates the actions to be taken, such as registering events.
The third argument is associated file descriptor.
The fourth argument is a pointer of type struct epoll_event, used to tell the kernel what events and actions to listen for.
return value: The return value is 0 if succeed, - 1 is returned for failure and error reason is stored in errno.
note: none
date: 2022/8/8
contact tel: 18720816902
*/
int comm_proxy_epoll_ctl(int epfd, int op, int fd, struct epoll_event* event)
{
SocketRequest req;
@ -1110,23 +926,6 @@ int comm_proxy_epoll_ctl(int epfd, int op, int fd, struct epoll_event* event)
return result.s_ret;
}
/*
function name: comm_proxy_epoll_wait
description: Wait for IO events on the specified epoll file descriptor.
arguments: The first argument is a specific file descriptor for epoll generated by epoll_ create.
The second argument is a pointer to type epoll_ event structure, but it is now used
as a container to get the collection of events from the kernel.
The third argument is used to tell how large the container is (number of event
array members), that is, the number of events that can be processed each time.
The fourth argument is the timeout value for waiting for IO events.
return value: When successful, comm_proxy_epoll_wait() returns the number of file descriptors
ready for the requested IO. Returns zero if no file descriptor is ready within the
requested timeout milliseconds. When an error occurs, comm_proxy_epoll_wait()
returns - 1 and sets errno correctly.
note: none
date: 2022/8/8
contact tel: 18720816902
*/
int comm_proxy_epoll_wait(int epfd, struct epoll_event* events, int maxevents, int timeout)
{
CommWaitEpollWaitParam param;

View File

@ -81,27 +81,6 @@ void mc_tcp_set_keepalive(int fd)
mc_tcp_setsockopt(fd, IPPROTO_TCP, TCP_KEEPCNT, (char*)&count, sizeof(count));
}
/*
function name: mc_tcp_get_peer_name
description: This function is used to obtain the host IP and port number of the host bound to the specific socket.
arguments: The first argument is a descriptor to a specified socket.
The second argument is used to store the host IP address bound to the socket determined by the first parameter, in dotted decimal.
The third parameter is used to store the port number bound to a specific socket, in the order of host bytes.
return value: Return 0 if the function runs successfully.
When the call to the getpeername() function fails
1Return EBADF if the socket argument is not a valid file descriptor.
2Return EINVAL if the socket has been shut down.
3Return ENOTCONN if the socket is not connected or otherwise has not had the peer pre-specified.
4Return ENOTSOCK if the socket argument does not refer to a socket.
5Return EOPNOTSUPP if the operation is not supported for the socket protocol.
6Return ENOBUFS if insufficient resources were available in the system to complete the call.
Return -2 when the host IP address belongs to IPv4 type, it fails to convert it to dotted decimal.
Return -3 when the host IP address belongs to IPv6 type, it fails to convert it to dotted decimal.
Return -4 when the error type is not any of the above.
note: Allocate a certain amount of memory space for the host and port pointers respectively in advance.
date: 2022/8/9
contact tel: 18720816902
*/
int mc_tcp_get_peer_name(int fd, char* host, int* port)
{
struct sockaddr peeraddr = {0};
@ -142,17 +121,6 @@ int mc_tcp_set_cloexec(int fd)
return set_socketopt(fd, 1, FD_CLOEXEC);
}
/*
function name: mc_tcp_accept
description: This function will block the process by default until a client connection is established and returns a new available socket.
arguments: The first argument is a socket descriptor to a specific socket.
The second argument is a result parameter, which is used to accept a return value that specifies the address of the client.
The third argument is also a result argument, which is used to accept the size of the sockaddr structure. It indicates the number of bytes occupied by the sockaddr structure.
return value: Return a value less than 0 if an error occurred when call the function accept4(), else return the new fd of socket.
note: none
date: 2022/8/9
contact tel: 18720816902
*/
int mc_tcp_accept(int fd, struct sockaddr* sa, socklen_t* salenptr)
{
int new_fd;
@ -179,17 +147,6 @@ again:
return (new_fd);
}
/*
function name: mc_tcp_bind
description: This function binds the specified socket to a specific IP address and port.
arguments: The first argument indicates the socket descriptor that has been established.
The second argument is a pointer to the sockaddr structure to socket.
The third argument is byte length of sockaddr structure.
return value: Return errno, the return value is 0 if succeed, else one of other error types is returned for failure.
note: none
date: 2022/8/9
contact tel: 18720816902
*/
int mc_tcp_bind(int fd, const struct sockaddr* sa, socklen_t salen)
{
int error = -1;
@ -234,20 +191,6 @@ static void mc_tcp_do_listen(int fd, int backlog)
}
}
/*
function name: mc_tcp_read_block
description: This function receives data from the other end of TCP in a blocking manner, the receiving
process will not end until the data of size byte length is successfully received or a real error occurs in the receiving process
arguments: The first argument indicates the specific socket that has been established.
The second argument is a pointer to memory area, we use it to store received data.
The third argument is byte length of the memory area pointed to by the data pointer.
The fourth argument specifies additional operations in addition to the read operation.
return value: If there is no error, it returns the byte length of the successfully read data. If an error
occurs, return - 1.
note: When the data is read successfully, the byte length of the data is greater than 0.
date: 2022/8/10
contact tel: 18720816902
*/
int mc_tcp_read_block(int fd, void* data, int size, int flags)
{
#ifdef LIBCOMM_FAULT_INJECTION_ENABLE
@ -318,20 +261,6 @@ int mc_tcp_read_block(int fd, void* data, int size, int flags)
return (size_t)nbytes;
}
/*
function name: mc_tcp_read_nonblock
description: This function receives data from the other end of TCP in a non blocking manner,
the data receiving process is only performed once.
arguments: The first argument indicates the specific socket that has been established.
The second argument is a pointer to memory area, we use it to store received data.
The third argument is byte length of the memory area pointed to by the data pointer.
The fourth argument specifies additional operations in addition to the read operation.
return value: If the error type is one of the errors represented by EAGAIN, EWOULDBLOCK and EINTR, it returns 0;
other error types return - 1; if there is no error, it returns the byte length of the successfully read data.
note: When the data is read successfully, the byte length of the data is greater than 0.
date: 2022/8/10
contact tel: 18720816902
*/
int mc_tcp_read_nonblock(int fd, void* data, int size, int flags)
{
#ifdef LIBCOMM_FAULT_INJECTION_ENABLE
@ -377,17 +306,6 @@ int mc_tcp_read_nonblock(int fd, void* data, int size, int flags)
return (size_t)nbytes;
}
/*
function name: mc_tcp_check_socket
description: This function binds the specified socket to a specific IP address and port.
arguments: The only argument indicates the specific socket that has been established.
return value: Return -1 if when the recv function wait for the protocol to receive data,
the other end of TCP closes the connection or a real error occurred while
reading data. In other cases, 0 is returned.
note: none
date: 2022/8/10
contact tel: 18720816902
*/
int mc_tcp_check_socket(int sock)
{
char temp_buf[IOV_DATA_SIZE] = {0};
@ -450,19 +368,6 @@ int mc_tcp_check_socket(int sock)
return 0;
}
/*
function name: mc_tcp_write_block
description: This function writes data to the specified socket in blocking mode, the sending process
will not end until all the data are successfully sent or a real error occurs during the sending process
arguments: The first argument indicates the specific socket that has been established.
The second argument is a pointer to memory area, we use it to store data to be sent.
The third argument is byte length of data to be sent.
return value: If there is no error, it returns the byte length of the successfully sent data. If an error
occurs, return - 1.
note: none
date: 2022/8/10
contact tel: 18720816902
*/
int mc_tcp_write_block(int fd, const void* data, int size)
{
#ifdef LIBCOMM_FAULT_INJECTION_ENABLE
@ -521,21 +426,6 @@ int mc_tcp_write_block(int fd, const void* data, int size)
return (size_t)nSend;
}
/*
function name: mc_tcp_write_noblock
description: This function writes data to the specified socket in non blocking mode,
the data transmission process is only performed once.
arguments: The first argument indicates the specific socket that has been established.
The second argument is a pointer to memory area, we use it to store data to be sent.
The third argument is byte length of data to be sent.
return value: If the sending fails but the failure reason is one of the error types represented by EAGAIN
EWOULDBLOCKEINTR ENOBUFS, then 0 is returned; if the error type is other, then - 1
is returned; If the transmission is successful, the byte length of the successfully transmitted
data is returned
note: none
date: 2022/8/10
contact tel: 18720816902
*/
int mc_tcp_write_noblock(int fd, const void* data, int size)
{
#ifdef LIBCOMM_FAULT_INJECTION_ENABLE
@ -629,17 +519,6 @@ int mc_tcp_addr_init(const char* host, int port, struct sockaddr_storage* ss, in
return (error == 1) ? 0 : error;
}
/*
function name: mc_tcp_connect_nonblock
description: This function is used to create a socket and establish a connection with the port of the specified host
in non blocking mode.
arguments: The first parameter specifies a specific host, and the second parameter specifies a specific port of the host.
return value: If the connection is successfully established, the file descriptor of the socket connected to the port of the
specified host is returned; otherwise, - 1 is returned.
note: none
date: 2022/8/10
contact tel: 18720816902
*/
int mc_tcp_connect_nonblock(const char* host, int port)
{
int sockfd, n;
@ -687,18 +566,6 @@ int mc_tcp_connect_nonblock(const char* host, int port)
return sockfd;
}
/*
function name: mc_tcp_connect
description: This function first obtains the ports of other hosts with the same domain name stored through
the ports of specific hosts, and creates a socket to establish a connection with an appropriate
one of these ports.
arguments: The first parameter specifies a specific host, and the second parameter specifies a specific port of the host.
return value: The key is to successfully establish a connection with a port in the linked list. If the connection is successful, the
socket file descriptor connected to it will be returned. Otherwise, it will return - 1.
note: We finally get the infomation of the ports of other hosts through a linked list.
date: 2022/8/10
contact tel: 18720816902
*/
int mc_tcp_connect(const char* host, int port)
{
#ifdef LIBCOMM_FAULT_INJECTION_ENABLE
@ -789,18 +656,6 @@ retry:
return (sockfd);
}
/*
function name: mc_tcp_listen
description: This function first obtains the ports of other hosts with the same domain name stored through
the ports of specific hosts, and creates a socket to bind with an appropriate one of these ports.
arguments: The first parameter specifies a specific host, and the second parameter specifies a specific port of the host.
The third is used to store size of protocol address.
return value: The key lies in the successful binding with a port in the linked list. If the binding is successful, the socket file
descriptor connected to it will be returned. Otherwise, it will return - 1.
note: We finally get the infomation of the ports of other hosts through a linked list.
date: 2022/8/10
contact tel: 18720816902
*/
int mc_tcp_listen(const char* host, int port, socklen_t* addrlenp)
{
#ifdef LIBCOMM_FAULT_INJECTION_ENABLE

View File

@ -232,21 +232,6 @@ static int gs_tcp_write_noblock(int node_idx, int sock, const char* msg, int msg
return send_bytes;
}
/*
function name: libcomm_tcp_send
description: This function is used to send the message including message head and message body, to
a specific socket.
arguments: send_ info is a pointer of LibcommRecvInfo* type, pointing to the memory storing the data
waiting to be sent.
return value: Data will be sent twice in total. Before sending data, if it is found that the socket to receive
data is not matched with the specified socket, then - 1 will be returned; If the sending of
message head or message body fails, return - 1; If the function runs successfully, the byte
length of the message body sent successfully is returned.
note: none
date: 2022/8/11
contact tel: 18720816902
*/
static int libcomm_tcp_send(LibcommSendInfo* send_info)
{
int sock = send_info->socket;
@ -337,19 +322,6 @@ static int libcomm_tcp_send(LibcommSendInfo* send_info)
return send_bytes;
}
/*
function name: libcomm_tcp_recv_noidx
description: This function is used to store the message transmitted from the sender, specifically to obtain
the message from a specific socket.
arguments: recv_ info is a pointer of LibcommRecvInfo* type, pointing to the memory to store the data
received.
return value: If it fails to allocate memory for iov_ Item, return RECV_MEM_ERROR;
If it fails to obtain data, no matter it is a message header or a message body, from the specified socket in blocking mode, return RECV_NET_ERROR;
If the function runs successfully, the byte length of the read message body is returned.
note: none
date: 2022/8/11
contact tel: 18720816902
*/
static int libcomm_tcp_recv_noidx(LibcommRecvInfo* recv_info)
{
int sock = recv_info->socket;
@ -399,23 +371,6 @@ static int libcomm_tcp_recv_noidx(LibcommRecvInfo* recv_info)
return error;
}
/*
function name: libcomm_tcp_recv
description: This function is used to store the message transmitted from the sender, specifically to obtain
the message from a specific socket.
arguments: recv_ info is a pointer of LibcommRecvInfo* type, pointing to the memory to store the data
received.
return value: If the receiver has not been determined, call libcomm_tcp_recv_noidx() and take the return value
of (libcomm_tcp_recv_noidx (recv_info)); Return RECV_NET_ERROR if there is an error in the
process of reading the message heade or message body; If there is no data readable in the
receiving buffer of the specified socket at this time or the number of bytes of the data that
has been read is not enough, it returns RECV_NEED_RETRY; If iov_item is NULL, it returns
RECV_MEM_ERROR if it fails to allocate space for it; If the function runs successfully, then
the byte length of the read message head and message body is returned.
note: none
date: 2022/8/11
contact tel: 18720816902
*/
int libcomm_tcp_recv(LibcommRecvInfo* recv_info)
{
MsgHead* msg_head = NULL;

View File

@ -137,16 +137,6 @@ static int LibCommClientSSLDHVerifyCb(const SSL* s, const SSL_CTX* ctx,
return 1;
}
/*
function name: ssl_cipher_list2string
description: This function converts the two-dimensional character array storing the key into a one-dimensional character array.
arguments: The first argument represents the two-dimensional character array to be converted.
The second argument indicates the number of one-dimensional arrays contained in this two-dimensional array.
return value: Returns a pointer to the one-dimensional character array that has been successfully converted. If the conversion fails, NULL is returned.
note: none
date: 2022/8/12
contact tel: 18720816902
*/
static char* ssl_cipher_list2string(const char* ciphers[], const int num) {
int i;
int catlen = 0;
@ -237,20 +227,7 @@ char* LibCommErrMessage(void) {
return errBuf;
}
/*
function name: LibCommClientSSLPasswd
description: As a client, this function is used to detect whether there is a file with a valid key in the specified
directory and whether there is permission to operate it. If so, the password will be decrypted by
using the file.
arguments: The first parameter is a pointer of type (SSL *).
The second parameter is used to obtain the absolute path of the certificate file.
The third parameter represents the user name.
The fourth parameter is a pointer of type (libcommconn *), whose member variable contains the ciphertext to be decrypted.
return value: If the path is empty or does not have operation permission to the directory where the certificate file is located, a non-1 value is returned; otherwise, 0 is returned.
note: none
date: 2022/8/12
contact tel: 18720816902
*/
int LibCommClientSSLPasswd(SSL* pstContext, const char * path, const char * userName, LibCommConn * conn) {
char* CertFilesDir = NULL;
char CertFilesPath[MAXPATH] = {0};
@ -274,8 +251,8 @@ int LibCommClientSSLPasswd(SSL* pstContext, const char * path, const char * user
/*check whether the cipher and rand files begins with userName exist.
if exist, decrypt it.
if not,decrypt the default cipher and rand files begins with client.
Because,for every client user may own certification and private key*/
if not,decrypt the default cipher and rand files begins with client%.
Because,for every client user mayown certification and private key*/
if (NULL == userName) {
retval = LibCommClientCheckPermissionCipherFile(CertFilesDir, conn, NULL);
if (retval != 1)

View File

@ -33,16 +33,6 @@ inline int mc_lqueue_item_size(struct mc_lqueue_item* q_item)
return q_item->element.data->iov_len;
}
/*
function name: mc_lqueue_add
description: Add an element to a specific queue.
arguments: The first parameter is a pointer of type (mc_lqueue *), whose member variable list points to the target queue.
The second parameter points to the element to be added to the queue.
return value: Returns 1 if the element is successfully added to the queue, otherwise returns - 1.
note: none
date: 2022/8/13
contact tel: 18720816902
*/
int mc_lqueue_add(struct mc_lqueue* q, struct mc_lqueue_item* q_item)
{
if (q == NULL || q_item == NULL) {
@ -70,17 +60,6 @@ int mc_lqueue_add(struct mc_lqueue* q, struct mc_lqueue_item* q_item)
return 1;
}
/*
function name: mc_lqueue_remove
description: Remove the head element in a specific queue.
arguments: The first parameter is a pointer of type (mc_lqueue *), whose member variable list points to the target queue.
The second parameter points to the queue head element used to store the removal from the queue.
return value: Return NULL if an error occurs during the removal of the queue head element, otherwise a pointer to
the successfully removed queue head element is returned.
note: none
date: 2022/8/13
contact tel: 18720816902
*/
struct mc_lqueue_item* mc_lqueue_remove(struct mc_lqueue* q, struct mc_lqueue_item* q_item)
{
if (q == NULL) {
@ -110,18 +89,6 @@ struct mc_lqueue_item* mc_lqueue_remove(struct mc_lqueue* q, struct mc_lqueue_it
return q_item;
}
/*
function name: mc_lqueue_init
description: This function is used to open an area in the memory area. One part of the area is used to store a queue with
a certain specification, and the other part is used to store the information of the queue, such as the specification
and the number of elements. Finally, a pointer to the area is returned.
arguments: This parameter specifies that the maximum number of elements that the queue can hold is size, but this does
not mean that the size of the queue is so large at the beginning.
return value: If the function runs successfully, it returns a pointer to the opened memory area; otherwise, it returns NULL.
note: none
date: 2022/8/13
contact tel: 18720816902
*/
struct mc_lqueue* mc_lqueue_init(unsigned long size)
{
if (size == 0) {

View File

@ -222,7 +222,6 @@ NON_EXEC_STATIC void PercentileMain()
g_instance.stat_cxt.force_process = false;
sleep(SLEEP_INTERVAL);
}
elog(LOG, "instrumention percentile ended");
gs_thread_exit(0);
}

View File

@ -14,23 +14,11 @@ 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
#noteDictionary 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 {

View File

@ -11,27 +11,22 @@
# 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)):
@ -61,16 +56,6 @@ 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
# noteA 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:

View File

@ -11,13 +11,6 @@
# 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':

View File

@ -12,16 +12,17 @@
# 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

View File

@ -13,14 +13,8 @@
import sys
from .cli import DBMindRun
#To import DBMindRun method from the parent file cli
#function name: main
#description: Get the system command parameters, pass to the DBMindRun and call this function,if an InterruptedError is reported, the program will exit( sys.exit(1)).
#arguments: None
#return value: None
#date: 2022/8/3
#contact: 1865997821
def main() -> None:
try:
DBMindRun(sys.argv[1:])

View File

@ -55,12 +55,7 @@ CONFIG_OPTIONS = {
'LOG-level': ['DEBUG', 'INFO', 'WARNING', 'ERROR']
}
#function name: check_config_validity
#description: Checks the validity of the passed parameter
#arguments: section, option, value
#return value: bool and string
#date: 2022/8/
#contact: 1865997821
def check_config_validity(section, option, value):
config_item = '%s-%s' % (section, option)
# exceptional cases:
@ -92,16 +87,6 @@ def check_config_validity(section, option, value):
return True, None
#function name: load_sys_configs
#description: Create and load the modification file
#arguments: The configuration to modify
#return value: a new configuration file
#noteTo facilitate the user to modify the configuration items through the
#configuration file easily, we add inline comments to the file, but we need to remove the inline comments while parsing.
#Otherwise, it will cause the read configuration items to be wrong.
#date: 2022/8/
#contact: 1865997821
def load_sys_configs(confile):
# Note: To facilitate the user to modify the configuration items through the
# configuration file easily, we add inline comments to the file, but we need
@ -111,8 +96,6 @@ def load_sys_configs(confile):
with open(file=confile, mode='r') as fp:
configs.read_file(fp)
# Define a class that encapsulates the modification item
class ConfigWrapper(object):
def __getattribute__(self, name):
try:
@ -139,7 +122,7 @@ def load_sys_configs(confile):
return ConfigWrapper()
# Defines a class that updates the encapsulated modification file
class ConfigUpdater:
def __init__(self, filepath):
self.config = ConfigParser(inline_comment_prefixes=None)
@ -187,7 +170,7 @@ class ConfigUpdater:
self.fp.flush()
self.fp.close()
# Defines a class that dynamically displays a modified item
class DynamicConfig:
@staticmethod
def get(*args, **kwargs):

View File

@ -43,7 +43,6 @@ except ImportError:
SKIP_LIST = ('COMMENT', 'LOG')
# The global variable acts as a switch that controls whether the program runs
dbmind_master_should_exit = False
@ -58,16 +57,8 @@ def _process_clean(force=False):
global_vars.worker.terminate(cancel_futures=force)
TimedTaskManager.stop()
#function name: signal_handler
#description: The function processes the received signal parameters, reassigns variable x according to different signals
#or calls other functions to complete the content indicated by signals
#arguments: signum, frame
#return value: bool (dbmind_master_should_exit)
#date: 2022/8/3
#contact: 1865997821
def signal_handler(signum, frame):
# The global variable dbmind_master_should_exit can be modified in this function to continue to play a control role
global dbmind_master_should_exit
if signum == signal.SIGINT or signum == signal.SIGHUP:
@ -157,12 +148,10 @@ class DBMindMain(Daemon):
time.sleep(1)
logging.info('DBMind will close.')
# Emptying the execution pool
def clean(self):
if os.path.exists(self.pid_file):
os.unlink(self.pid_file)
# Reload the execution pool and solve the error
def reload(self):
pid = read_dbmind_pid_file(self.pid_file)
if pid > 0:

View File

@ -27,17 +27,6 @@ def do_after(rt_result):
def do_exception(exception):
"""Nothing"""
#function name: around
#description: Preserve the function properties and prevent an error from terminating the program
#arguments: One or more functions
#return value: none
#note Decorators are implemented in such a way that the function being decorated is actually another function (the function name and other properties change).
#To avoid this, Python's FuncTools package provides a decorator called wraps to remove such side effects.
#When writing a decorator, it is a good idea to wrap FuncTools before implementing it.
#It preserves the name and properties of the original function
#date: 2022/8/4
#contact: 1865997821
def around(func, *args, **kw):
@wraps(func)
def wrapper():

View File

@ -15,11 +15,7 @@ from typing import Optional, Iterable, Union
from .root_cause import RootCause
from .enumerations import ALARM_TYPES, ALARM_LEVEL
#Define an Alarm class that takes the error parameters entered by the user and displays the error content and cause
#methodDisplay the error content and suggestions, and retrieve suggestions provided by the system. If there are no suggestions, return “ no suggestions”
#noteThe property decorator turns a method into a property call.(root_causes、suggestions)
#date2022/8/4
#contact18365997821
class Alarm:
def __init__(self,
host: Union[str],

View File

@ -12,11 +12,7 @@
# See the Mulan PSL v2 for more details.
from .root_cause import RootCause
#Define anSlowQuery class thatSlow query accepts user input commands and performs operations on the database
#methodDisplay the error content and suggestions, and retrieve suggestions provided by the system. If there are no suggestions, return “ no suggestions”
#noteThe property decorator turns a method into a property call.(root_causes、suggestions)
#date2022/8/4
#contact18365997821
class SlowQuery:
def __init__(self, db_host, db_port, db_name, schema_name, query, start_timestamp, duration_time,
hit_rate=None, fetch_rate=None, cpu_time=None, data_io_time=None, template_id=None, sort_count=None,

View File

@ -18,19 +18,13 @@ import psycopg2
from .execute_factory import ExecuteFactory
from .execute_factory import IndexInfo
#class name: DriverExecute Inherits from the parent class ExecuteFactory
#description: The SQL statement performs the operations associated with the call
#date: 2022/8/10
#contact: 1865997821
class DriverExecute(ExecuteFactory):
def __init__(self, *arg):
#Call the arguments of the parent class __init__ method
super(DriverExecute, self).__init__(*arg)
self.conn = None
self.cur = None
#Connecting to the database
def init_conn_handle(self):
self.conn = psycopg2.connect(dbname=self.dbname,
user=self.user,
@ -39,7 +33,6 @@ class DriverExecute(ExecuteFactory):
port=self.port)
self.cur = self.conn.cursor()
#If an error occurs after the SQL statement is executed, the error information is reported to the user
def execute(self, sql):
try:
self.cur.execute(sql)
@ -48,13 +41,11 @@ class DriverExecute(ExecuteFactory):
except Exception:
self.conn.commit()
#Disconnecting from the database
def close_conn(self):
if self.conn and self.cur:
self.cur.close()
self.conn.close()
#Check whether multiple nodes exist
def is_multi_node(self):
self.init_conn_handle()
try:

View File

@ -13,11 +13,6 @@
import re
#class name: IndexInfo
#description: Define information about table indexes
#methods: __init__
#date: 2022/8/10
#contact: 1865997821
class IndexInfo:
def __init__(self, schema, table, indexname, columns, indexdef):
@ -29,9 +24,7 @@ class IndexInfo:
self.primary_key = False
self.redundant_obj = []
#class name: ExecuteFactory
#date: 2022/8/10
#contact: 1865997821
class ExecuteFactory:
def __init__(self, dbname, user, password, host, port, schema, multi_node, max_index_storage):
self.dbname = dbname
@ -43,11 +36,11 @@ class ExecuteFactory:
self.max_index_storage = max_index_storage
self.multi_node = multi_node
# Record redundant indexes
@staticmethod
def record_redundant_indexes(cur_table_indexes, redundant_indexes):
cur_table_indexes = sorted(cur_table_indexes,
key=lambda index_obj: len(index_obj.columns.split(',')))
# record redundant indexes
for pos, index in enumerate(cur_table_indexes[:-1]):
is_redundant = False
for candidate_index in cur_table_indexes[pos + 1:]:
@ -59,7 +52,6 @@ class ExecuteFactory:
if is_redundant:
redundant_indexes.append(index)
#Match the name of the table against the index of the query
@staticmethod
def match_table_name(table_name, query_index_dict):
for elem in query_index_dict.keys():
@ -74,7 +66,6 @@ class ExecuteFactory:
return False, table_name
return True, table_name
#Retrieves a valid index based on the regular expression, adding the corresponding index and empty element if none exists
@staticmethod
def get_valid_indexes(record, hypoid_table_column, valid_indexes):
tokens = record.split(' ')
@ -97,7 +88,6 @@ class ExecuteFactory:
if columns not in valid_indexes[table_name]:
valid_indexes[table_name].append((columns, index_type))
#Record invalid SQL statements and returns the corresponding help information that matches the corresponding SQL statement
@staticmethod
def record_ineffective_negative_sql(candidate_index, obj, ind):
cur_table = candidate_index.table
@ -135,7 +125,6 @@ class ExecuteFactory:
candidate_index.ineffective_pos.append(ind)
candidate_index.total_sql_num += obj.frequency
#Returns the last input and the corresponding result
@staticmethod
def match_last_result(table_name, index_column, history_indexes, history_invalid_indexes):
for column in history_indexes.get(table_name, dict()):
@ -153,7 +142,6 @@ class ExecuteFactory:
if not history_indexes[table_name]:
del history_indexes[table_name]
#Correcting SQL statements
@staticmethod
def make_single_advisor_sql(ori_sql):
sql = 'select gs_index_advise(\''

View File

@ -23,16 +23,12 @@ from .execute_factory import IndexInfo
BASE_CMD = None
#class name: GSqlExecute
#description: Solve the optimization problem of GSQL statement execution
#date: 2022/8/11
#contact: 1865997821
class GSqlExecute(ExecuteFactory):
def __init__(self, *args):
super(GSqlExecute, self).__init__(*args)
def init_conn_handle(self):
#define a global variable BASE_CMD,it is a connection command statement
global BASE_CMD
BASE_CMD = 'gsql -p ' + str(self.port) + ' -d ' + self.dbname
if self.host:
@ -42,7 +38,6 @@ class GSqlExecute(ExecuteFactory):
if self.password:
BASE_CMD += ' -W ' + self.password
#Run the shell command in BASE_CMD
def run_shell_cmd(self, target_sql_list):
cmd = BASE_CMD + ' -c \"'
if self.schema:
@ -52,7 +47,6 @@ class GSqlExecute(ExecuteFactory):
cmd += '\"'
proc = subprocess.Popen(
cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
#Read data from stdout and stderr,If an error message is displayed, an error message is displayed
(stdout, stderr) = proc.communicate()
stdout, stderr = stdout.decode(), stderr.decode()
if 'gsql: FATAL:' in stderr or 'failed to connect' in stderr:
@ -80,7 +74,6 @@ class GSqlExecute(ExecuteFactory):
print(e.output.decode(), file=sys.stderr)
return int(ret.decode().strip().split()[2]) > 0
#Parse the recommended result returned
@staticmethod
def parse_single_advisor_result(res, table_index_dict):
if len(res) > 2 and res[0:2] == ' (':
@ -190,7 +183,6 @@ class GSqlExecute(ExecuteFactory):
total_cost = 0
found_plan = False
hypo_index = False
# create hypo-indexes
for line in res:
if 'QUERY PLAN' in line:
found_plan = True
@ -230,7 +222,6 @@ class GSqlExecute(ExecuteFactory):
i += 1
return total_cost
#Production workflows consume report files
def estimate_workload_cost_file(self, workload, index_config=None, ori_indexes_name=None):
sql_file = str(time.time()) + '.sql'
is_computed = False
@ -273,7 +264,6 @@ class GSqlExecute(ExecuteFactory):
return total_cost
#Check for empty indexes and note them to optimize the table structure
def check_useless_index(self, history_indexes, history_invalid_indexes):
schemas = [elem.lower()
for elem in filter(None, self.schema.split(','))]

View File

@ -26,11 +26,9 @@ 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
@ -194,12 +192,9 @@ class IndexAdvisor:
self.workload_used_index))
if DRIVER:
self.db.close_conn()
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])
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!")
@ -948,7 +943,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 float value" %
raise argparse.ArgumentTypeError("%s is an invalid positive int value" %
args.max_index_storage)
JSON_TYPE = args.json
MAX_INDEX_NUM = args.max_index_num
@ -976,7 +971,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=float)
help="Maximum storage of suggested indexes/MB", type=int)
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',

View File

@ -1,397 +0,0 @@
import sys
import math
import random
import copy
STORAGE_THRESHOLD = 0
AVAILABLE_CHOICES = None
ATOMIC_CHOICES = None
WORKLOAD_INFO = None
MAX_INDEX_NUM = 0
def is_same_index(index, compared_index):
return index.table == compared_index.table and \
index.columns == compared_index.columns and \
index.index_type == compared_index.index_type
def atomic_config_is_valid(atomic_config, config):
# if candidate indexes contains all atomic index of current config1, then record it
for atomic_index in atomic_config:
is_exist = False
for index in config:
if is_same_index(index, atomic_index):
index.storage = atomic_index.storage
is_exist = True
break
if not is_exist:
return False
return True
def find_subsets_num(choice):
atomic_subsets_num = []
for pos, atomic in enumerate(ATOMIC_CHOICES):
if not atomic or len(atomic) > len(choice):
continue
# find valid atomic index
if atomic_config_is_valid(atomic, choice):
atomic_subsets_num.append(pos)
# find the same atomic index as the candidate index
if len(atomic) == 1 and (is_same_index(choice[-1], atomic[0])):
choice[-1].atomic_pos = pos
return atomic_subsets_num
def find_best_benefit(choice):
atomic_subsets_num = find_subsets_num(choice)
total_benefit = 0
for ind, obj in enumerate(WORKLOAD_INFO):
# calculate the best benefit for the current sql
max_benefit = 0
for pos in atomic_subsets_num:
if (obj.cost_list[0] - obj.cost_list[pos]) > max_benefit:
max_benefit = obj.cost_list[0] - obj.cost_list[pos]
total_benefit += max_benefit
return total_benefit
def get_diff(available_choices, choices):
except_choices = copy.copy(available_choices)
for i in available_choices:
for j in choices:
if is_same_index(i, j):
except_choices.remove(i)
return except_choices
class State(object):
"""
The game state of the Monte Carlo tree search,
the state data recorded under a certain Node node,
including the current game score, the current number of game rounds,
and the execution record from the beginning to the current.
It is necessary to realize whether the current state has reached the end of the game state,
and support the operation of randomly fetching from the Action collection.
"""
def __init__(self):
self.current_storage = 0.0
self.current_benefit = 0.0
# record the sum of choices up to the current state
self.accumulation_choices = []
# record available choices of current state
self.available_choices = []
self.displayable_choices = []
def get_available_choices(self):
return self.available_choices
def set_available_choices(self, choices):
self.available_choices = choices
def get_current_storage(self):
return self.current_storage
def set_current_storage(self, value):
self.current_storage = value
def get_current_benefit(self):
return self.current_benefit
def set_current_benefit(self, value):
self.current_benefit = value
def get_accumulation_choices(self):
return self.accumulation_choices
def set_accumulation_choices(self, choices):
self.accumulation_choices = choices
def is_terminal(self):
# the current node is a leaf node
return len(self.accumulation_choices) == MAX_INDEX_NUM
def compute_benefit(self):
return self.current_benefit
def get_next_state_with_random_choice(self):
# ensure that the choices taken are not repeated
if not self.available_choices:
return None
random_choice = random.choice([choice for choice in self.available_choices])
self.available_choices.remove(random_choice)
choice = copy.copy(self.accumulation_choices)
choice.append(random_choice)
benefit = find_best_benefit(choice)
# if current choice not satisfy restrictions, then continue get next choice
if benefit <= self.current_benefit or \
self.current_storage + random_choice.storage > STORAGE_THRESHOLD:
return self.get_next_state_with_random_choice()
next_state = State()
# initialize the properties of the new state
next_state.set_accumulation_choices(choice)
next_state.set_current_benefit(benefit)
next_state.set_current_storage(self.current_storage + random_choice.storage)
next_state.set_available_choices(get_diff(AVAILABLE_CHOICES, choice))
return next_state
def __repr__(self):
self.displayable_choices = ['{}: {}'.format(choice.table, choice.columns)
for choice in self.accumulation_choices]
return "reward: {}, storage :{}, choices: {}".format(
self.current_benefit, self.current_storage, self.displayable_choices)
class Node(object):
"""
The Node of the Monte Carlo tree search tree contains the parent node and
current point information,
which is used to calculate the traversal times and quality value of the UCB,
and the State of the Node selected by the game.
"""
def __init__(self):
self.visit_number = 0
self.quality = 0.0
self.parent = None
self.children = []
self.state = None
def get_parent(self):
return self.parent
def set_parent(self, parent):
self.parent = parent
def get_children(self):
return self.children
def expand_child(self, node):
node.set_parent(self)
self.children.append(node)
def set_state(self, state):
self.state = state
def get_state(self):
return self.state
def get_visit_number(self):
return self.visit_number
def set_visit_number(self, number):
self.visit_number = number
def update_visit_number(self):
self.visit_number += 1
def get_quality_value(self):
return self.quality
def set_quality_value(self, value):
self.quality = value
def update_quality_value(self, reward):
self.quality += reward
def is_all_expand(self):
return len(self.children) == \
len(AVAILABLE_CHOICES) - len(self.get_state().get_accumulation_choices())
def __repr__(self):
return "Node: {}, Q/N: {}/{}, State: {}".format(
hash(self), self.quality, self.visit_number, self.state)
def tree_policy(node):
"""
In the Selection and Expansion stages of Monte Carlo tree search,
the node that needs to be searched (such as the root node) is passed in,
and the best node that needs to be expanded is returned
according to the exploration/exploitation algorithm.
Note that if the node is a leaf node, it will be returned directly.
The basic strategy is to first find the child nodes that have not been selected at present,
and select them randomly if there are more than one. If both are selected,
find the one with the largest UCB value that has weighed exploration/exploitation,
and randomly select if the UCB values are equal.
"""
# check if the current node is leaf node
while node and not node.get_state().is_terminal():
if node.is_all_expand():
node = best_child(node, True)
else:
# return the new sub node
sub_node = expand(node)
# when there is no node that satisfies the condition in the remaining nodes,
# this state is empty
if sub_node.get_state():
return sub_node
# return the leaf node
return node
def default_policy(node):
"""
In the Simulation stage of Monte Carlo tree search, input a node that needs to be expanded,
create a new node after random operation, and return the reward of the new node.
Note that the input node should not be a child node,
and there are unexecuted Actions that can be expendable.
The basic strategy is to choose the Action at random.
"""
# get the state of the game
current_state = copy.deepcopy(node.get_state())
# run until the game over
while not current_state.is_terminal():
# pick one random action to play and get next state
next_state = current_state.get_next_state_with_random_choice()
if not next_state:
break
current_state = next_state
final_state_reward = current_state.compute_benefit()
return final_state_reward
def expand(node):
"""
Enter a node, expand a new node on the node, use the random method to execute the Action,
and return the new node. Note that it is necessary to ensure that the newly
added nodes are different from other node Action
"""
new_state = node.get_state().get_next_state_with_random_choice()
sub_node = Node()
sub_node.set_state(new_state)
node.expand_child(sub_node)
return sub_node
def best_child(node, is_exploration):
"""
Using the UCB algorithm,
select the child node with the highest score after weighing the exploration and exploitation.
Note that if it is the prediction stage,
the current Q-value score with the highest score is directly selected.
"""
best_score = -sys.maxsize
best_sub_node = None
# travel all sub nodes to find the best one
for sub_node in node.get_children():
# The children nodes of the node contains the children node whose state is empty,
# this kind of node comes from the node that does not meet the conditions.
if not sub_node.get_state():
continue
# ignore exploration for inference
if is_exploration:
C = 1 / math.sqrt(2.0)
else:
C = 0.0
# UCB = quality / times + C * sqrt(2 * ln(total_times) / times)
left = sub_node.get_quality_value() / sub_node.get_visit_number()
right = 2.0 * math.log(node.get_visit_number()) / sub_node.get_visit_number()
score = left + C * math.sqrt(right)
# get the maximum score, while filtering nodes that do not meet the space constraints and
# nodes that have no revenue
if score > best_score \
and sub_node.get_state().get_current_storage() <= STORAGE_THRESHOLD \
and sub_node.get_state().get_current_benefit() > 0:
best_sub_node = sub_node
best_score = score
return best_sub_node
def backpropagate(node, reward):
"""
In the Backpropagation stage of Monte Carlo tree search,
input the node that needs to be expended and the reward of the newly executed Action,
feed it back to the expend node and all upstream nodes,
and update the corresponding data.
"""
# update util the root node
while node is not None:
# update the visit number
node.update_visit_number()
# update the quality value
node.update_quality_value(reward)
# change the node to the parent node
node = node.parent
def monte_carlo_tree_search(node):
"""
Implement the Monte Carlo tree search algorithm, pass in a root node,
expand new nodes and update data according to the
tree structure that has been explored before in a limited time,
and then return as long as the child node with the highest exploitation.
When making predictions,
you only need to select the node with the largest exploitation according to the Q value,
and find the next optimal node.
"""
computation_budget = len(AVAILABLE_CHOICES) * 3
# run as much as possible under the computation budget
for i in range(computation_budget):
# 1. find the best node to expand
expand_node = tree_policy(node)
if not expand_node:
# when it is None, it means that all nodes are added but no nodes meet the space limit
break
# 2. random get next action and get reward
reward = default_policy(expand_node)
# 3. update all passing nodes with reward
backpropagate(expand_node, reward)
# get the best next node
best_next_node = best_child(node, False)
return best_next_node
def MCTS(workload_info, atomic_choices, available_choices, storage_threshold, max_index_num):
global ATOMIC_CHOICES, STORAGE_THRESHOLD, WORKLOAD_INFO, AVAILABLE_CHOICES, MAX_INDEX_NUM
WORKLOAD_INFO = workload_info
AVAILABLE_CHOICES = available_choices
ATOMIC_CHOICES = atomic_choices
STORAGE_THRESHOLD = storage_threshold
MAX_INDEX_NUM = max_index_num if max_index_num else len(available_choices)
# create the initialized state and initialized node
init_state = State()
choices = copy.copy(available_choices)
init_state.set_available_choices(choices)
init_node = Node()
init_node.set_state(init_state)
current_node = init_node
opt_config = []
# set the rounds to play
for i in range(len(AVAILABLE_CHOICES)):
if current_node:
current_node = monte_carlo_tree_search(current_node)
if current_node:
opt_config = current_node.state.accumulation_choices
else:
break
return opt_config

View File

@ -539,14 +539,13 @@ 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:# Cold start training
if need_init:
epoch_start = 0
self.model = self._build_model(epsilon)
else:# Incremental training
else:
epoch_start = int(self.model_info.last_epoch)
ratio_error = ratio_error_loss_wrapper(epsilon)
ratio_acc_2 = ratio_error_acc_wrapper(epsilon, 2)
@ -557,16 +556,12 @@ 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)

View File

@ -27,7 +27,6 @@ from . import AbstractModel
class TemplateModel(AbstractModel):
# Initialize algorithm parameters
def __init__(self, params):
super().__init__(params)
self.bias = 1e-5

View File

@ -173,16 +173,11 @@ 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'])
@ -205,7 +200,6 @@ 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
@ -213,13 +207,6 @@ 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.')
@ -235,21 +222,12 @@ 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.
@ -259,7 +237,6 @@ 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
)

View File

@ -27,7 +27,6 @@ from collections.abc import Iterable
from collections import defaultdict
import index_advisor_workload as iaw
import mcts
def hash_any(obj):
@ -228,32 +227,6 @@ 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()

View File

@ -90,10 +90,7 @@ static void DropExtensionInListIsSupported(List* objname)
}
}
/* Enable DROP operation of the above objects during inplace upgrade or support_extended_features is true */
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.")));
}
ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("EXTENSION is not yet supported.")));
}
/*

View File

@ -1175,7 +1175,7 @@ void CreateExtension(CreateExtensionStmt* stmt)
FEATURE_NOT_PUBLIC_ERROR("EXTENSION is not yet supported.");
}
if (pg_strcasecmp(stmt->extname, "dolphin") == 0 && !DB_IS_CMPT(B_FORMAT)) {
if (pg_strcasecmp(stmt->extname, "b_sql_plugin") == 0 && !DB_IS_CMPT(B_FORMAT)) {
ereport(ERROR,
(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, "dolphin") == 0) {
u_sess->attr.attr_sql.dolphin = true;
if (pg_strcasecmp(stmt->extname, "b_sql_plugin") == 0) {
u_sess->attr.attr_sql.b_sql_plugin = true;
}
/*

View File

@ -44,7 +44,7 @@
#include "utils/array.h"
#include "utils/acl.h"
static bool ConnectPublisher(char* conninfo, char* slotname);
static void ConnectPublisher(char *conninfo, char* slotname);
static void CreateSlotInPublisher(char *slotname);
static void ValidateReplicationSlot(char *slotname, List *publications);
@ -56,7 +56,7 @@ static void ValidateReplicationSlot(char *slotname, List *publications);
* accommodate that.
*/
static void parse_subscription_options(const List *options, char **conninfo, List **publications, bool *enabled_given,
bool *enabled, bool *slot_name_given, char **slot_name, char **synchronous_commit, bool *binary_given, bool *binary)
bool *enabled, bool *slot_name_given, char **slot_name, char **synchronous_commit)
{
ListCell *lc;
@ -76,10 +76,6 @@ static void parse_subscription_options(const List *options, char **conninfo, Lis
if (synchronous_commit) {
*synchronous_commit = NULL;
}
if (binary) {
*binary_given = false;
*binary = false;
}
/* Parse options */
foreach (lc, options) {
@ -128,15 +124,6 @@ static void parse_subscription_options(const List *options, char **conninfo, Lis
/* Test if the given value is valid for synchronous_commit GUC. */
(void)set_config_option("synchronous_commit", *synchronous_commit, PGC_BACKEND, PGC_S_TEST, GUC_ACTION_SET,
false, 0, false);
} else if (strcmp(defel->defname, "binary") == 0 && binary) {
if (*binary_given) {
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("conflicting or redundant options")));
}
*binary_given = true;
*binary = defGetBoolean(defel);
} else {
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR), errmsg("unrecognized subscription parameter: %s", defel->defname)));
@ -210,82 +197,26 @@ static Datum publicationListToArray(List *publist)
}
/*
* Parse the original connection string which is encrypted, poll all hosts and ports,
* and try to connect to the publisher.
* When checkRemoteMode is true, the remotemode must be normal or primary.
* Return true to indicate successful connection.
* connect publisher and create slot.
* the input conninfo should be encrypt, we will decrypt password inside
*/
bool AttemptConnectPublisher(const char *conninfoOriginal, char* slotname, bool checkRemoteMode)
{
size_t conninfoLen = strlen(conninfoOriginal) + 1;
char* conninfo = NULL;
StringInfoData conninfoWithoutHostport;
initStringInfo(&conninfoWithoutHostport);
HostPort* hostPortList[MAX_REPLNODE_NUM] = {NULL};
ParseConninfo(conninfoOriginal, &conninfoWithoutHostport, hostPortList);
if (hostPortList[0] == NULL) {
ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg(
"invalid connection string syntax, missing host and port")));
}
bool connectSuccess = false;
conninfo = (char*)palloc(conninfoLen * sizeof(char));
for (int i = 0; i < MAX_REPLNODE_NUM; ++i) {
if (hostPortList[i] == NULL) {
break;
}
int ret = snprintf_s(conninfo, conninfoLen, conninfoLen - 1,
"%s host=%s port=%s", conninfoWithoutHostport.data,
hostPortList[i]->host, hostPortList[i]->port);
securec_check_ss(ret, "\0", "\0");
connectSuccess = ConnectPublisher(conninfo, slotname);
if (!connectSuccess) {
/* try next host */
continue;
}
if (!checkRemoteMode) {
break;
}
ServerMode publisherServerMde = IdentifyRemoteMode();
if (publisherServerMde == NORMAL_MODE || publisherServerMde == PRIMARY_MODE) {
break;
}
/* it's a standby, try next host */
(WalReceiverFuncTable[GET_FUNC_IDX]).walrcv_disconnect();
connectSuccess = false;
}
pfree_ext(conninfo);
/* clean up */
FreeStringInfo(&conninfoWithoutHostport);
for (int i = 0; i < MAX_REPLNODE_NUM; ++i) {
if (hostPortList[i] == NULL) {
break;
}
pfree_ext(hostPortList[i]->host);
pfree_ext(hostPortList[i]->port);
pfree_ext(hostPortList[i]);
}
return connectSuccess;
}
/*
* connect to publisher with conninfo
*/
static bool ConnectPublisher(char* conninfo, char* slotname)
static void ConnectPublisher(char *conninfo, char *slotname)
{
/* Try to connect to the publisher. */
volatile WalRcvData *walrcv = t_thrd.walreceiverfuncs_cxt.WalRcv;
SpinLockAcquire(&walrcv->mutex);
walrcv->conn_target = REPCONNTARGET_PUBLICATION;
SpinLockRelease(&walrcv->mutex);
char* decryptConninfo = EncryptOrDecryptConninfo(conninfo, 'D');
char *decryptConninfo = DecryptConninfo(conninfo);
bool connectSuccess = (WalReceiverFuncTable[GET_FUNC_IDX]).walrcv_connect(decryptConninfo, NULL, slotname, -1);
int rc = memset_s(decryptConninfo, strlen(decryptConninfo), 0, strlen(decryptConninfo));
securec_check(rc, "", "");
pfree_ext(decryptConninfo);
return connectSuccess;
if (!connectSuccess) {
ereport(ERROR, (errcode(ERRCODE_CONNECTION_FAILURE), errmsg("could not connect to the publisher")));
}
}
/*
@ -362,10 +293,9 @@ ObjectAddress CreateSubscription(CreateSubscriptionStmt *stmt, bool isTopLevel)
bool enabled_given = false;
bool enabled = true;
char *synchronous_commit;
char *conninfo;
char *slotname;
bool slotname_given;
bool binary;
bool binary_given;
char originname[NAMEDATALEN];
List *publications;
int rc;
@ -375,7 +305,7 @@ ObjectAddress CreateSubscription(CreateSubscriptionStmt *stmt, bool isTopLevel)
* Connection and publication should not be specified here.
*/
parse_subscription_options(stmt->options, NULL, NULL, &enabled_given, &enabled, &slotname_given, &slotname,
&synchronous_commit, &binary_given, &binary);
&synchronous_commit);
/*
* Since creating a replication slot is not transactional, rolling back
@ -403,10 +333,11 @@ ObjectAddress CreateSubscription(CreateSubscriptionStmt *stmt, bool isTopLevel)
synchronous_commit = "off";
}
conninfo = stmt->conninfo;
publications = stmt->publication;
/* Check the connection info string. */
libpqrcv_check_conninfo(stmt->conninfo);
libpqrcv_check_conninfo(conninfo);
/* Everything ok, form a new tuple. */
rc = memset_s(values, sizeof(values), 0, sizeof(values));
@ -418,12 +349,18 @@ ObjectAddress CreateSubscription(CreateSubscriptionStmt *stmt, bool isTopLevel)
values[Anum_pg_subscription_subname - 1] = DirectFunctionCall1(namein, CStringGetDatum(stmt->subname));
values[Anum_pg_subscription_subowner - 1] = ObjectIdGetDatum(owner);
values[Anum_pg_subscription_subenabled - 1] = BoolGetDatum(enabled);
values[Anum_pg_subscription_subbinary - 1] = BoolGetDatum(binary);
/* encrypt conninfo */
char *encryptConninfo = EncryptOrDecryptConninfo(stmt->conninfo, 'E');
List *conninfoList = ConninfoToDefList(stmt->conninfo);
/* Sensitive options for subscription, will be encrypted when saved to catalog. */
const char* sensitiveOptionsArray[] = {"password"};
const int sensitiveArrayLength = lengthof(sensitiveOptionsArray);
EncryptGenericOptions(conninfoList, sensitiveOptionsArray, sensitiveArrayLength, SUBSCRIPTION_MODE);
char *encryptConninfo = DefListToString(conninfoList);
values[Anum_pg_subscription_subconninfo - 1] = CStringGetTextDatum(encryptConninfo);
pfree_ext(conninfoList);
if (enabled) {
if (!slotname_given) {
slotname = stmt->subname;
@ -459,14 +396,11 @@ ObjectAddress CreateSubscription(CreateSubscriptionStmt *stmt, bool isTopLevel)
*/
if (enabled) {
Assert(slotname);
if (!AttemptConnectPublisher(encryptConninfo, slotname, true)) {
ereport(ERROR, (errcode(ERRCODE_CONNECTION_FAILURE), errmsg("Failed to connect to publisher.")));
}
ConnectPublisher(encryptConninfo, slotname);
CreateSlotInPublisher(slotname);
(WalReceiverFuncTable[GET_FUNC_IDX]).walrcv_disconnect();
}
pfree_ext(encryptConninfo);
heap_close(rel, RowExclusiveLock);
rc = memset_s(stmt->conninfo, strlen(stmt->conninfo), 0, strlen(stmt->conninfo));
@ -505,8 +439,6 @@ ObjectAddress AlterSubscription(AlterSubscriptionStmt *stmt)
Oid subid;
bool enabled_given = false;
bool enabled;
bool binary_given;
bool binary;
char *synchronous_commit;
char *conninfo;
char *slot_name;
@ -541,7 +473,7 @@ ObjectAddress AlterSubscription(AlterSubscriptionStmt *stmt)
/* Parse options. */
parse_subscription_options(stmt->options, &conninfo, &publications, &enabled_given, &enabled, &slotname_given,
&slot_name, &synchronous_commit, &binary_given, &binary);
&slot_name, &synchronous_commit);
/* Form a new tuple. */
rc = memset_s(nulls, sizeof(nulls), false, sizeof(nulls));
@ -558,15 +490,23 @@ ObjectAddress AlterSubscription(AlterSubscriptionStmt *stmt)
if (conninfo) {
/* Check the connection info string. */
libpqrcv_check_conninfo(conninfo);
encryptConninfo = EncryptOrDecryptConninfo(conninfo, 'E');
rc = memset_s(conninfo, strlen(conninfo), 0, strlen(conninfo));
securec_check(rc, "\0", "\0");
values[Anum_pg_subscription_subconninfo - 1] = CStringGetTextDatum(encryptConninfo);
replaces[Anum_pg_subscription_subconninfo - 1] = true;
/* encrypt conninfo */
List *conninfoList = ConninfoToDefList(conninfo);
/* Sensitive options for subscription, will be encrypted when saved to catalog. */
const char* sensitiveOptionsArray[] = {"password"};
const int sensitiveArrayLength = lengthof(sensitiveOptionsArray);
EncryptGenericOptions(conninfoList, sensitiveOptionsArray, sensitiveArrayLength, SUBSCRIPTION_MODE);
encryptConninfo = DefListToString(conninfoList);
needFreeConninfo = true;
/* need to check whether new conninfo can be used to connect to new publisher */
values[Anum_pg_subscription_subconninfo - 1] = CStringGetTextDatum(encryptConninfo);
replaces[Anum_pg_subscription_subconninfo - 1] = true;
pfree_ext(conninfoList);
if (sub->enabled || (enabled_given && enabled)) {
/* we need to check whether new conninfo can be used to connect to new publisher */
checkConn = true;
}
}
@ -608,10 +548,6 @@ ObjectAddress AlterSubscription(AlterSubscriptionStmt *stmt)
values[Anum_pg_subscription_subsynccommit - 1] = CStringGetTextDatum(synchronous_commit);
replaces[Anum_pg_subscription_subsynccommit - 1] = true;
}
if (binary_given) {
values[Anum_pg_subscription_subbinary - 1] = BoolGetDatum(binary);
replaces[Anum_pg_subscription_subbinary - 1] = true;
}
if (publications != NIL) {
values[Anum_pg_subscription_subpublications - 1] = publicationListToArray(publications);
replaces[Anum_pg_subscription_subpublications - 1] = true;
@ -634,18 +570,16 @@ ObjectAddress AlterSubscription(AlterSubscriptionStmt *stmt)
if (sub->enabled && !enabled) {
ereport(ERROR, (errmsg("If you want to deactivate this subscription, use DROP SUBSCRIPTION.")));
}
/* enabling subscription, but slot hasn't been created,
* then mark createSlot to true.
*/
if (!sub->enabled && enabled && (!sub->slotname || !*(sub->slotname))) {
/* enable subscription */
if (!sub->enabled && enabled) {
/* if slot hasn't been created, then create it */
if (!sub->slotname || !*(sub->slotname)) {
createSlot = true;
}
}
if (checkConn || createSlot || validateSlot) {
if (!AttemptConnectPublisher(encryptConninfo, finalSlotName, true)) {
ereport(ERROR, (errcode(ERRCODE_CONNECTION_FAILURE), errmsg(
checkConn ? "The new conninfo cannot connect to new publisher." : "Failed to connect to publisher.")));
}
ConnectPublisher(encryptConninfo, finalSlotName);
if (createSlot) {
CreateSlotInPublisher(finalSlotName);
@ -663,6 +597,12 @@ ObjectAddress AlterSubscription(AlterSubscriptionStmt *stmt)
if (needFreeConninfo) {
pfree_ext(encryptConninfo);
}
if (conninfo) {
rc = memset_s(conninfo, strlen(conninfo), 0, strlen(conninfo));
securec_check(rc, "", "");
}
return myself;
}
@ -813,11 +753,7 @@ void DropSubscription(DropSubscriptionStmt *stmt, bool isTopLevel)
initStringInfo(&cmd);
appendStringInfo(&cmd, "DROP_REPLICATION_SLOT %s", quote_identifier(slotname));
if (!AttemptConnectPublisher(conninfo, slotname, true)) {
ereport(ERROR, (errcode(ERRCODE_CONNECTION_FAILURE), errmsg(
"could not connect to publisher.")));
}
ConnectPublisher(conninfo, slotname);
PG_TRY();
{
int sqlstate = 0;
@ -843,7 +779,6 @@ void DropSubscription(DropSubscriptionStmt *stmt, bool isTopLevel)
(WalReceiverFuncTable[GET_FUNC_IDX]).walrcv_disconnect();
pfree_ext(conninfo);
pfree(cmd.data);
heap_close(rel, NoLock);
}
@ -973,149 +908,3 @@ void RenameSubscription(List *oldname, const char *newname)
return;
}
/*
* Parse the host or port string into a string array,
* where host and port are separated by ",".
* input: conn --- host or port string separated by ","
* output: connArray --- host or port string array
* return: the length of connArray
* for example:
* (1):
* conn = 1.1.1.1,2.2.2.2,...,9.9.9.9
* connArray = {
* 1,.1.1.1,
* 2.2.2.2,
* ...,
* 9.9.9.9
* }
* return 9
* (2):
* conn = 1,2,...,9
* connArray = {1,2,...,9}
* return 9
*/
static int HostsPortsToArray(const char* conn, char** connArray)
{
if (conn == NULL) {
return 0;
}
char* cp = NULL;
char* cur = NULL;
char *buf = pstrdup(conn);
cp = buf;
int i = 0;
while (*cp) {
cur = cp;
while (*cp && *cp != ',') {
++cp;
}
if (*cp == ',') {
*cp = '\0';
++cp;
}
if (i >= MAX_REPLNODE_NUM) {
ereport(ERROR, (errmsg("Currently, a maximum of %d servers are "
"supported.", MAX_REPLNODE_NUM)));
}
connArray[i++] = pstrdup(cur);
if (*cp == 0) {
break;
}
}
pfree(buf);
return i;
}
/*
* parse host and port
*/
static void ParseHostPort(char* hoststr, char* portstr, HostPort** hostPortList)
{
char* hosts[MAX_REPLNODE_NUM] = {NULL};
char* ports[MAX_REPLNODE_NUM] = {NULL};
int hostNum = HostsPortsToArray(hoststr, hosts);
int portNum = HostsPortsToArray(portstr, ports);
if (hostNum != portNum) {
ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("The number of host and port are inconsistent.")));
}
for (int i = 0; i < hostNum; ++i) {
hostPortList[i] = (HostPort*)palloc(sizeof(HostPort));
hostPortList[i]->host = hosts[i];
hostPortList[i]->port = ports[i];
}
}
/*
* Parse conninfo
* conninfo format:
* 'dbname=abc user=username password=xxxx host=ip1,ip2,...,ip9 port=p1,p2,...,p9'
* after parsing:
* conninfoWithoutHostPort:
* 'dbname=abc user=username password=xxxx'
* hostPortList:
* {
* {host=ip1, port=p1},
* {host=ip2, port=p2},
* ...
* {host=ip9, port=p9}
* }
*/
void ParseConninfo(const char* conninfo, StringInfoData* conninfoWithoutHostPort, HostPort** hostPortList)
{
List* conninfoList = ConninfoToDefList(conninfo);
ListCell* l = NULL;
char* hostStr = NULL;
char* portStr = NULL;
foreach (l, conninfoList) {
DefElem* defel = (DefElem*)lfirst(l);
if (pg_strcasecmp(defel->defname, "host") == 0) {
hostStr = defGetString(defel);
} else if (pg_strcasecmp(defel->defname, "port") == 0) {
portStr = defGetString(defel);
} else {
appendStringInfo(conninfoWithoutHostPort, "%s=%s ", defel->defname, defGetString(defel));
}
}
if (hostPortList != NULL) {
ParseHostPort(hostStr, portStr, hostPortList);
}
}
/*
* encrypt conninfo when action = 'E'
* decrypt conninfo when action = 'D'
* conninfoNew: encrypted or decrypted conninfo
*/
char* EncryptOrDecryptConninfo(const char* conninfo, const char action)
{
/* parse conninfo to list */
List *conninfoList = ConninfoToDefList(conninfo);
/* Sensitive options for subscription */
const char* sensitiveOptionsArray[] = {"password"};
const int sensitiveArrayLength = lengthof(sensitiveOptionsArray);
switch (action) {
/* Encrypt */
case 'E':
EncryptGenericOptions(conninfoList, sensitiveOptionsArray, sensitiveArrayLength, SUBSCRIPTION_MODE);
break;
/* Decrypt */
case 'D':
DecryptOptions(conninfoList, sensitiveOptionsArray, sensitiveArrayLength, SUBSCRIPTION_MODE);
break;
default:
break;
}
char* conninfoNew = DefListToString(conninfoList);
ClearListContent(conninfoList);
list_free_ext(conninfoList);
return conninfoNew;
}

View File

@ -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, true);
targetPartOid = heapTupleGetPartitionId(partTableRel, (HeapTuple) tuple);
searchFakeReationForPartitionOid(
partRelHTAB, CurrentMemoryContext, partTableRel, targetPartOid, partRel, part, RowExclusiveLock);
@ -24797,8 +24797,7 @@ static Oid AddTemporaryPartitionForAlterPartitions(const AlterTableCmd* cmd, Rel
destPartOid = AddTemporaryHashPartitionForAlterPartitions(cmd, partTableRel, partSeq, renameTargetPart);
break;
}
case PART_TYPE_RANGE:
case PART_TYPE_INTERVAL: {
case PART_TYPE_RANGE: {
destPartOid = AddTemporaryRangePartitionForAlterPartitions(cmd, partTableRel, partSeq, renameTargetPart);
break;
}
@ -25099,11 +25098,11 @@ static void readTuplesAndInsertInternal(Relation tempTableRel, Relation partTabl
/* tableam_tops_copy_tuple is not ready so we add UStore hack path */
copyTuple = tableam_tops_copy_tuple(tuple);
targetPartOid = heapTupleGetPartitionId(partTableRel, (void *)tuple, true);
targetPartOid = heapTupleGetPartitionId(partTableRel, (void *)tuple);
searchFakeReationForPartitionOid(
partRelHTAB, CurrentMemoryContext, partTableRel, targetPartOid, partRel, part, RowExclusiveLock);
if (RelationIsSubPartitioned(partTableRel)) {
targetPartOid = heapTupleGetPartitionId(partRel, (void *)tuple, true);
targetPartOid = heapTupleGetPartitionId(partRel, (void *)tuple);
searchFakeReationForPartitionOid(partRelHTAB, CurrentMemoryContext, partRel, targetPartOid, subPartRel,
subPart, RowExclusiveLock);
partRel = subPartRel;

6
src/gausskernel/optimizer/commands/user.cpp Normal file → Executable file
View File

@ -5911,7 +5911,6 @@ Datum calculate_encrypted_combined_password(const char* password, const char* ro
errno_t rc = EOK;
/* For PG ecological compatibility, we stored both sha256 and md5 password. */
/* the encrypted method of sha256 */
if (!pg_sha256_encrypt(password,
salt_string,
strlen(salt_string),
@ -5922,7 +5921,7 @@ Datum calculate_encrypted_combined_password(const char* password, const char* ro
securec_check(rc, "\0", "\0");
ereport(ERROR, (errcode(ERRCODE_INVALID_PASSWORD), errmsg("first stage encryption password failed")));
}
/* the encrypted method of md5 */
if (!pg_md5_encrypt(password, rolname, strlen(rolname), encrypted_md5_password)) {
rc = memset_s(encrypted_md5_password, MD5_PASSWD_LEN + 1, 0, MD5_PASSWD_LEN + 1);
securec_check(rc, "\0", "\0");
@ -6053,7 +6052,6 @@ static Datum gs_calculate_encrypted_sm3_password(const char* password, const cha
Datum calculate_encrypted_password(bool is_encrypted, const char* password, const char* rolname,
const char* salt_string)
{
/* If the password is '\0' or not exist */
if (password == NULL || password[0] == '\0') {
ereport(ERROR, (errcode(ERRCODE_INVALID_PASSWORD), errmsg("The password could not be NULL.")));
}
@ -6061,7 +6059,6 @@ Datum calculate_encrypted_password(bool is_encrypted, const char* password, cons
char encrypted_md5_password[MD5_PASSWD_LEN + 1] = {0};
Datum datum_value;
/* If the password has encrypted */
if (!is_encrypted || isPWDENCRYPTED(password)) {
return CStringGetTextDatum(password);
}
@ -6071,7 +6068,6 @@ Datum calculate_encrypted_password(bool is_encrypted, const char* password, cons
* if Password_encryption_type is 0, the encrypted password is md5.
* if Password_encryption_type is 1, the encrypted password is sha256 + md5.
* if Password_encryption_type is 2, the encrypted password is sha256.
* if Password_encryption_type is 3, the encrypted password is SM3.
*/
if (u_sess->attr.attr_security.Password_encryption_type == 0) {
if (!pg_md5_encrypt(password, rolname, strlen(rolname), encrypted_md5_password)) {

View File

@ -109,21 +109,6 @@ static void updateRelOptInfoMinSecurity(RelOptInfo* rel);
static void find_index_path(RelOptInfo* rel);
static void bitmap_path_walker(Path* path);
/*
function name: check_func_walker
description: This function recursively traverses an expression tree to determine if there are any FuncExpr nodes present.
arguments: The first argument represents the current node in the expression tree.
The second argument indicates the pointer to a boolean variable that indicates whether a function call node has been found.
return value: Returns true if a FuncExpr node is found, otherwise returns false. The "found" variable is modified accordingly to indicate the presence of a FuncExpr node during the traversal.
note: The main process is as follows:
-> Recursively traverses the given expression tree, examining each node.
-> If the current node is NULL, it returns `false`.
-> If the node is of type `FuncExpr` (function call node), sets the `found` variable to `true` and returns `true`.
-> Otherwise, invokes the general expression tree walker `expression_tree_walker` to traverse child nodes, passing along the `found` variable.
-> Returns a boolean value indicating whether a function call node was found in the expression tree.
date: 2023/8/12
contact tel: 18720816902
*/
static bool check_func_walker(Node* node, bool* found)
{
if (node == NULL) {
@ -436,22 +421,6 @@ static bool reduce_predpush_broadcast(PlannerInfo* root, Path *path)
return reduce;
}
/*
function name: make_predpush_subpath
description: This function is responsible for generating a subpath for predicate pushdown. It extracts restriction conditions from the given relation's restrictinfo and creates a new subpath incorporating these conditions.
arguments: The first argument represents the pointer of a PlannerInfo structure containing query planner context.
The second argument indicates the RelOptInfo structure containing information about the relation being optimized.
The third argument indicates the Path to be processed.
return value: Returns the newly generated subpath that incorporates the extracted restriction conditions and supports predicate pushdown optimization. This function plays a role in query optimization, enhancing the execution plan by considering relevant conditions during subpath creation.
note: The main process is as follows:
-> Initialize the "quals" list to hold restriction conditions.
-> Iterate through the "subplanrestrictinfo" list within the given "rel", which contains restriction information.
-> If the condition "SUBQUERY_PREDPUSH(root)" is met, collect upper-level parameter IDs using the "collect_param_clause" function from the condition expressions.
-> Create a new subpath "subpath" using the "create_result_path" function, passing in "root", "rel", "quals", "path", and "upper_params" as arguments.
-> Return the newly created subpath "subpath".
date: 2023/8/13
contact tel: 18720816902
*/
static Path *make_predpush_subpath(PlannerInfo* root, RelOptInfo* rel, Path *path)
{
List* quals = NULL;
@ -890,19 +859,6 @@ static void set_rel_pathlist(PlannerInfo* root, RelOptInfo* rel, Index rti, Rang
#endif
}
/*
function name: SetPlainReSizeWithPruningRatio
description: This function adjusts the estimated size of a partitioned relation and its associated indexes based on a pruning ratio. It modifies the estimated number of pages in the relation and its indexes to reflect the effect of pruning.
arguments: The first argument represents the pointer to the RelOptInfo structure representing the partitioned relation.
The second argument indicates the ratio by which to adjust the estimated size due to pruning.
return value: This function does not return a value; it directly modifies the estimated page counts for the partitioned relation and its indexes based on the provided pruning ratio. The adjustment accounts for the pruning effect on the size estimates, contributing to accurate query planning and optimization for partitioned tables.
note: The main process is as follows:
-> Validate that the given relation is a partitioned table (assertion).
-> Update the estimated number of pages in the partitioned relation by multiplying it with the given pruningRatio and applying a clamp function (clamp_row_est).
-> Iterate through the list of indexes associated with the partitioned relation.
date: 2023/8/13
contact tel: 18720816902
*/
static void SetPlainReSizeWithPruningRatio(RelOptInfo *rel, double pruningRatio)
{
ListCell *cell = NULL;
@ -2234,27 +2190,6 @@ static bool has_multiple_baserels(PlannerInfo* root)
return false;
}
/*
function name: can_push_qual_into_subquery
description: This function determines whether a restriction condition can be pushed into a subquery. It evaluates various criteria including pseudoconstant, security barrier, safe pushdown conditions, and partial push conditions to make this determination.
arguments:
- `root`: PlannerInfo context for query planning.
- `rinfo`: RestrictInfo representing the restriction condition.
- `rte`: RangeTblEntry representing the table entry.
- `rti`: Index of the range table entry.
- `clause`: The restriction condition expression to be evaluated.
- `unsafeColumns`: A boolean array indicating the presence of unsafe columns.
return value: A boolean value indicating whether the given restriction condition can be pushed into a subquery. This function is utilized in query planning to make informed decisions about optimization strategies, ensuring that the pushdown of restriction conditions is performed while considering multiple crucial factors.
note: The main process is as follows:
-> Retrieve the subquery from the RangeTblEntry `rte`.
-> Check the `pseudoconstant` property of the RestrictInfo. If true, return `false`, indicating the restriction condition cannot be pushed.
-> If the `security_barrier` property of the RangeTblEntry is true and the restriction condition contains leaky functions (`contain_leaky_functions`), return `false`.
-> Call the `qual_is_pushdown_safe` function to assess whether the restriction condition can be safely pushed into the subquery.
-> Call the `qual_pushdown_in_partialpush` function to determine whether the restriction condition can be pushed under partial push conditions.
-> Return `true` if all checks are satisfied, indicating that the restriction condition can be pushed into the subquery.
date: 2023/8/13
contact tel: 18720816902
*/
static bool can_push_qual_into_subquery(PlannerInfo* root,
RestrictInfo* rinfo,
RangeTblEntry* rte,
@ -2294,22 +2229,6 @@ typedef struct trans_lateral_vars_t
int levelsup;
}trans_lateral_vars_t;
/*
function name: trans_lateral_vars_mutator
description: This function recursively traverses an expression tree and performs transformations on Var nodes based on the given lateral_vars information. It handles the conversion of inner Vars to subquery form and outer Vars to Params.
arguments:
- `node`: The current node being processed in the expression tree.
- `lateral_vars`: A structure containing information about the transformation process.
return value: A modified expression tree with transformed Var nodes.
note: The main process is as follows:
-> If the node is NULL, return NULL.
-> If the node is a Var:
- If it's an inner Var (varno matches lateral_vars->rti), convert it to subquery form using target_list and return the transformed expression.
- If it's an outer Var, convert it to Param by adjusting varlevelsup and return the new Var.
-> Recursively traverse the expression tree using expression_tree_mutator, applying the trans_lateral_vars_mutator function.
date: 2023/8/13
contact tel: 18720816902
*/
static Node* trans_lateral_vars_mutator(Node *node, trans_lateral_vars_t *lateral_vars)
{
if (node == NULL)
@ -2342,21 +2261,6 @@ static Node* trans_lateral_vars_mutator(Node *node, trans_lateral_vars_t *latera
(Node* (*)(Node*, void*))trans_lateral_vars_mutator, lateral_vars);
}
/*
function name: trans_lateral_vars
description: This function performs the transformation of lateral references within a given subquery. It recursively traverses the expression tree using the trans_lateral_vars_mutator function to convert internal Var nodes into subquery forms and external Var nodes into Param nodes.
arguments:
- `subquery`: The subquery in which lateral references are to be transformed.
- `rti`: The index of the subquery in the RangeTblEntry array.
- `qual`: The restriction condition expression to be transformed.
- `levelsup`: The number of levels up in which the transformation occurs within the subquery.
return value: The transformed restriction condition expression.
note: The main process is as follows:
-> Create a trans_lateral_vars_t structure containing information such as subquery, target_list, rti, and levelsup.
-> Recursively traverse the restriction condition expression using the query_or_expression_tree_mutator function, applying the trans_lateral_vars_mutator function for the conversion.
date: 2023/8/13
contact tel: 18720816902
*/
static Node* trans_lateral_vars(Query *subquery, Index rti, Node *qual, int levelsup)
{
trans_lateral_vars_t lateral_vars;
@ -2378,21 +2282,6 @@ typedef struct collect_lateral_vars_t
RelOptInfo *rel;
}collect_lateral_vars_t;
/*
function name: collect_lateral_vars_walker
description: This function is used for walking through an expression tree and collecting lateral variables within it. It identifies outer Var nodes that reference tables outside the current relation and adds them to the lateral_relids and lateral_vars fields of the provided RelOptInfo structure. It also updates the lateral_info structures for the query planner's root.
arguments:
- `node`: The current node in the expression tree being traversed.
- `context`: The context containing information about the relation and query planner.
return value: A boolean value indicating whether the traversal should continue (always false).
note: The main process is as follows:
-> Extract RelOptInfo and PlannerInfo from the lateral_context.
-> If the current node is a Var node and references a table outside the current relation, add its varno to the lateral_relids and add the Var to the lateral_vars list.
-> Update lateral_info for the root by adding lateral reference information.
-> If the current node is a RestrictInfo, extract its clause and continue traversal.
date: 2023/8/13
contact tel: 18720816902
*/
static bool collect_lateral_vars_walker(Node *node, void *context)
{
collect_lateral_vars_t *lateral_context = (collect_lateral_vars_t *)context;
@ -2426,20 +2315,6 @@ static bool collect_lateral_vars_walker(Node *node, void *context)
return expression_tree_walker(node, (bool (*)())collect_lateral_vars_walker, context);
}
/*
function name: collect_lateral_vars
description: This function collects lateral variables within a given restriction condition expression. It utilizes the collect_lateral_vars_walker function to traverse the expression tree and identify outer Var nodes that reference tables outside the current relation. The lateral_relids and lateral_vars fields of the provided RelOptInfo structure are updated accordingly.
arguments:
- `root`: PlannerInfo context for query planning.
- `restrict`: The restriction condition expression to be traversed.
- `rel`: The RelOptInfo structure representing the current relation.
return value: A boolean value indicating whether the traversal was successful (always true).
note: The main process is as follows:
-> Initialize the lateral_context containing PlannerInfo and RelOptInfo.
-> Invoke the expression_tree_walker function with the restrict expression and the collect_lateral_vars_walker function as the walker.
date: 2023/8/13
contact tel: 18720816902
*/
static bool
collect_lateral_vars(PlannerInfo *root, Node *restrict, RelOptInfo *rel)
{
@ -2475,20 +2350,6 @@ static Relids collect_child_relids(PlannerInfo* root, Index rti)
return result;
}
/*
function name: predpush_candidates_append
description: This function identifies potential append children for predicate pushdown based on the provided parent relation IDs. It iterates through each parent relation ID in the provided Relids set and collects the child relation IDs for each parent using the collect_child_relids function. The resulting child relation IDs are unioned to form the final set of potential append children for predicate pushdown.
arguments:
- `root`: PlannerInfo context for query planning.
- `parents`: A set of parent relation IDs representing the potential append parents.
return value: A Relids set containing the union of child relation IDs for all provided parent relation IDs.
note: The main process is as follows:
-> Initialize parent_id to -1.
-> Iterate through each parent relation ID in the parents set.
-> For each parent relation ID, collect the child relation IDs using collect_child_relids and union them with the results set.
date: 2023/8/13
contact tel: 18720816902
*/
static Relids predpush_candidates_append(PlannerInfo *root, Relids parents)
{
int parent_id = -1;
@ -2500,24 +2361,6 @@ static Relids predpush_candidates_append(PlannerInfo *root, Relids parents)
return results;
}
/*
function name: predpush_candidates
description: This function identifies potential relations for predicate pushdown based on the given PlannerInfo and destination relation ID. It examines the hintState and predpush_hint in the parse tree's HintState to determine potential candidates for predicate pushdown. The function iterates through each PredpushHint in the hint list and, based on the dest_id and parent_rti, constructs a set of potential candidates for predicate pushdown. It then combines these candidates using union operations and returns the resulting Relids set.
arguments:
- `root`: PlannerInfo context for query planning.
- `dest_id`: Destination relation ID for which predicate pushdown candidates are to be determined.
return value: A Relids set containing the potential candidates for predicate pushdown based on the given PlannerInfo and destination relation ID.
note: The main process is as follows:
-> Retrieve the hintState from the parse tree's HintState.
-> If hintState or predpush_hint is NULL, return NULL indicating no candidates.
-> Initialize an empty result set.
-> Iterate through each PredpushHint in the predpush_hint list.
-> For each PredpushHint, check if dest_id matches or if dest_id is the parent_rti, and construct candidates using predpush_candidates_append.
-> Union the constructed candidates with the result set and return it if a match is found.
-> If no match is found, union the result set with candidates based on result itself using predpush_candidates_append.
date: 2023/8/13
contact tel: 18720816902
*/
static Relids predpush_candidates(PlannerInfo *root, int dest_id)
{
HintState *hstate = root->parse->hintState;
@ -2565,29 +2408,6 @@ static Relids predpush_candidates(PlannerInfo *root, int dest_id)
return result;
}
/*
function name: extract_predpush_equivclause
description: This function extracts the predicate pushdown candidate equivalence clauses for a given relation based on the provided candidates, RelOptInfo, and relation index (rti). It iterates through the simple_rel_array and checks each relation to identify candidates for equivalence clauses that can be pushed down to the given relation. The function takes into account various conditions, including relation kinds, indexes, and parent-child relationships for append relations.
arguments:
- `root`: PlannerInfo context for query planning.
- `candidates`: Relids set indicating potential candidates for predicate pushdown.
- `rel`: RelOptInfo representing the given relation.
- `rti`: Index of the relation.
return value: A List containing the extracted candidate equivalence clauses for predicate pushdown to the given relation.
note: The main process is as follows:
-> Initialize an empty List to hold candidate_restricts.
-> Iterate through the simple_rel_array using the `i` loop variable.
-> For each relation in simple_rel_array, check its kind and index conditions.
-> If candidates are specified and the relation is not a candidate, continue to the next relation.
-> If ENABLE_PRED_PUSH_FORCE is not set and `i` is greater than `rti`, continue to the next relation.
-> If the current relation is the same as the given `rel`, continue to the next relation.
-> Generate candidate equivalence clauses based on join_relids and append relationships (if applicable).
-> If generated restrict_list is empty, continue to the next relation.
-> Concatenate the generated restrict_list with the candidate_restricts List.
-> After processing all relations, return the candidate_restricts List containing extracted candidate equivalence clauses.
date: 2023/8/13
contact tel: 18720816902
*/
static List *extract_predpush_equivclause(PlannerInfo* root, Relids candidates,
RelOptInfo* rel, Index rti)
{
@ -2777,29 +2597,6 @@ static bool predpush_subquery(PlannerInfo* root, RelOptInfo* rel, Index rti,
return predpush;
}
/*
function name: judge_predpush_subquery
description: This function determines whether predicate pushdown into a subquery is feasible based on various conditions. It evaluates criteria such as safe pushdown, relation kinds, recursion, enabling options, root conditions, and null handling. The function is utilized to make informed decisions about whether to proceed with predicate pushdown optimization.
arguments:
- `root`: PlannerInfo context for query planning.
- `safe_pushdown`: A boolean indicating whether safe pushdown is possible.
- `rel`: RelOptInfo representing the relation.
- `rti`: Index of the relation in the range table.
- `rte`: RangeTblEntry corresponding to the relation.
return value: A boolean value indicating whether predicate pushdown into the subquery is a viable optimization strategy.
note: The main process is as follows:
-> Check whether safe pushdown is not possible, and return `false` if true.
-> Check whether the relation kind is RELOPT_BASEREL or RELOPT_OTHER_MEMBER_REL, and return `false` if not.
-> Check whether the query involves recursion or is under a recursive CTE, and return `false` if true.
-> Check whether the ENABLE_PRED_PUSH_ALL option is not set, and return `false` if true.
-> Check whether the given `rte` matches the corresponding simple_rte_array entry, and return `false` if not.
-> Check whether the join_null_info is not empty, and return `false` if true.
-> Check whether stream support is enabled using check_stream_support(), and return `false` if not.
-> If the query is a sublink and rel has subplanrestrictinfo, return `false`.
-> If all checks pass, return `true` indicating that predicate pushdown into the subquery is feasible.
date: 2023/8/13
contact tel: 18720816902
*/
static bool judge_predpush_subquery(PlannerInfo* root, bool safe_pushdown, RelOptInfo* rel,
Index rti, RangeTblEntry *rte)
{
@ -3780,33 +3577,6 @@ static bool qual_is_pushdown_to_EXCEPT(PlannerInfo* root, Query* subquery,
return true;
}
/*
function name: qual_is_pushdown_safe
description: This function checks whether it is safe to push a given qualification clause into a subquery based on various conditions. It evaluates criteria including subselects, volatile functions, window functions, PHV (PlaceHolderVars), aggregates, subquery types, and attribute numbers. The function is used in query planning to determine the feasibility of pushdown optimization.
arguments:
- `root`: PlannerInfo context for query planning.
- `subquery`: Subquery where the pushdown is being considered.
- `rti`: Index of the range table entry corresponding to the subquery.
- `qual`: The qualification clause to be evaluated for pushdown.
- `unsafeColumns`: An array of booleans indicating unsafe columns.
- `predpush`: A boolean indicating whether predpush is being considered.
return value: A boolean value indicating whether the given qualification clause can be safely pushed into the subquery. If any of the safety checks fail, the function returns `false`, indicating that pushdown is not safe.
note: The main process is as follows:
-> Check if the qualification clause contains subselects using contain_subplans() and return `false` if true.
-> If multiple nodes are not enabled, check if the qualification clause contains volatile functions, and return `false` if true.
-> Check if the qualification clause contains window functions using contain_window_function() and AssertEreport() to indicate that this should not happen.
-> Check whether the qualification clause is safe for pushdown to EXCEPT clauses using qual_is_pushdown_to_EXCEPT() and return `false` if false.
-> Pull all Vars used in the clause, and iterate over them.
-> If the Var is not an instance of Var, set `safe` to `false` and break.
-> If predpush is enabled and the Var corresponds to a CTE, set `safe` to `false` and break.
-> If the Var's varno does not match rti, continue to the next iteration.
-> Check whether the Var's varattno is valid and not zero, and set `safe` to `false` and break if not.
-> Check whether the Var's varattno corresponds to an unsafe column using the `unsafeColumns` array, and set `safe` to `false` and break if true.
-> Free the memory allocated for the vars list using list_free_ext().
-> Return `safe`, indicating whether the pushdown is safe.
date: 2023/8/14
contact tel: 18720816902
*/
static bool qual_is_pushdown_safe(PlannerInfo* root, Query* subquery, Index rti,
Node* qual, const bool* unsafeColumns, bool predpush)
{
@ -4242,19 +4012,6 @@ bool CheckPathUseGlobalPartIndex(Path* path)
return false;
}
/*
* function name: create_partiterator_path
* description: This function creates a PartIteratorPath for partitioned tables, which allows parallel scan and access to partitions based on the specified path type.
* arguments:
* - `root`: PlannerInfo context for query planning.
* - `rel`: RelOptInfo representing the relation.
* - `path`: The original path to be transformed into a PartIteratorPath.
* - `relation`: The underlying partitioned relation.
* return value: A pointer to the created PartIteratorPath representing the scan of partitions based on the specified path type. If the path type is not recognized or suitable, an error is raised.
* note: The function first switches based on the original path type, and if it matches certain supported path types (such as sequential scan, index scan, etc.), it constructs a PartIteratorPath. The PartIteratorPath allows for parallel scanning of partitions, inherits pathkeys from the original path, and sets other relevant information.
* date: 2023/8/14
* contact tel: 18720816902
*/
static Path* create_partiterator_path(PlannerInfo* root, RelOptInfo* rel, Path* path, Relation relation)
{
Path* result = NULL;
@ -4442,17 +4199,6 @@ bool is_single_baseresult_plan(Plan* plan)
*****************************************************************************/
#ifdef OPTIMIZER_DEBUG
/*
* function name: print_relids
* description: This function prints the IDs and names of relations represented by the given Relids set. It uses the RangeTblEntry information from the provided list to retrieve relation names.
* arguments:
* - `relids`: The set of relation IDs to be printed.
* - `rtable`: List of RangeTblEntry representing the available relations.
* return value: None.
* note: The function iterates over the given Relids set, retrieves the corresponding relation name from the RangeTblEntry list, and prints the relation ID and name.
* date: 2023/8/14
* contact tel: 18720816902
*/
static void print_relids(Relids relids, List* rtable)
{
Relids tmprelids;
@ -4472,17 +4218,6 @@ static void print_relids(Relids relids, List* rtable)
bms_free_ext(tmprelids);
}
/*
* function name: print_restrictclauses
* description: This function prints the clauses within the given list of RestrictInfo structures, using the provided PlannerInfo context to access the range table.
* arguments:
* - `root`: PlannerInfo context for query planning.
* - `clauses`: List of RestrictInfo structures containing the clauses to be printed.
* return value: None.
* note: The function iterates over the list of RestrictInfo structures, extracts the clause expression from each structure, and prints it using the provided range table information. The clauses are printed comma-separated.
* date: 2023/8/14
* contact tel: 18720816902
*/
static void print_restrictclauses(PlannerInfo* root, List* clauses)
{
ListCell* l = NULL;
@ -4496,37 +4231,12 @@ static void print_restrictclauses(PlannerInfo* root, List* clauses)
}
}
/*
* function name: print_tab
* description: This inline function prints a specified number of tab characters, used for indentation purposes.
* arguments:
* - `indent`: The number of tab characters to print for indentation.
* return value: None.
* note: The function prints the specified number of tab characters ('\t') to provide indentation in the output.
* date: 2023/8/14
* contact tel: 18720816902
*/
inline void print_tab(int indent)
{
for (int i = 0; i < indent; i++)
printf("\t");
}
/*
* function name: print_path
* description: This function prints the details of a given query planning path, including its type, relevant information,
* and any subpaths in the plan.
* arguments:
* - `root`: PlannerInfo context for query planning.
* - `path`: The query planning path to be printed.
* - `indent`: The number of tab characters for indentation in the output.
* return value: None.
* note: The function outputs the path type and corresponding information, such as parent relations, rows, and cost.
* It also prints any associated path keys and clauses. In the case of join paths, it recursively prints the details
* of the outer and inner join paths. For material and unique paths, it prints details about their subpaths.
* date: 2023/8/14
* contact tel: 18720816902
*/
static void print_path(PlannerInfo* root, Path* path, int indent)
{
const char* ptype = NULL;
@ -4604,21 +4314,6 @@ static void print_path(PlannerInfo* root, Path* path, int indent)
print_path(root, subpath, indent + 1);
}
/*
* function name: debug_print_rel
* description: This function prints debugging information about a given RelOptInfo structure, providing details about
* its rows, multiple, width, baserestrictinfo, joininfo, and paths.
* arguments:
* - `root`: PlannerInfo context for query planning.
* - `rel`: The RelOptInfo structure to be debug printed.
* return value: None.
* note: The function prints the RelOptInfo's rows, multiple, and width values, followed by its baserestrictinfo and
* joininfo clauses if they exist. It then iterates through the path list and prints details of each path,
* including path type, parent relations, rows, cost, and pathkeys. The cheapest startup path and cheapest total path
* are also printed.
* date: 2023/8/14
* contact tel: 18720816902
*/
void debug_print_rel(PlannerInfo* root, RelOptInfo* rel)
{
ListCell* l = NULL;

View File

@ -816,21 +816,6 @@ static List* switch_arg_items(Node* funExpr, Const* cnst, Oid* eqlOprOid, Oid* i
return argList;
}
/*
* function name: do_restrictinfo_conversion
* description: This function performs restrictinfo conversion by switching argument items for equality operator.
* arguments:
* - `args`: List containing two arguments.
* - `eqlOprOid`: Pointer to the OID of the equality operator.
* - `inputcollid`: Pointer to the OID of the input collation.
* - `isequal`: Boolean indicating whether it's an equality operation.
* return value: List of argument items after performing the conversion.
* note: The function checks whether the two argument items in the list are constants. If one is a constant and the other
* is not, it performs a switch of argument items using the `switch_arg_items` function. The resulting list of
* argument items is returned.
* date: 2023/8/15
* contact tel: 18720816902
*/
static List* do_restrictinfo_conversion(List* args, Oid* eqlOprOid, Oid* inputcollid, bool isequal)
{
AssertEreport(list_length(args) == 2, MOD_OPT, "");
@ -914,21 +899,6 @@ static void get_vardata_for_filter_or_semijoin(
}
}
/*
* function name: do_restrictinfo_conversion
* description: This function performs restrictinfo conversion by switching argument items for equality operator.
* arguments:
* - `args`: List containing two arguments.
* - `eqlOprOid`: Pointer to the OID of the equality operator.
* - `inputcollid`: Pointer to the OID of the input collation.
* - `isequal`: Boolean indicating whether it's an equality operation.
* return value: List of argument items after performing the conversion.
* note: The function checks whether the two argument items in the list are constants. If one is a constant and the other
* is not, it performs a switch of argument items using the `switch_arg_items` function. The resulting list of
* argument items is returned.
* date: 2023/8/15
* contact tel: 18720816902
*/
void getVardataFromScalarArray(Node* node, get_vardata_for_filter_or_semijoin_context* context)
{
Node* left = NULL;

View File

@ -151,22 +151,6 @@ void init_plan_cost(Plan* plan)
plan->pred_max_memory = -1;
}
/*
* function name: get_info_from_rel
* description: This function retrieves various information from a given relation and updates the provided pointers
* with the respective values.
* arguments:
* - `relation`: The relation for which information needs to be retrieved.
* - `maxBatchRow`: Pointer to an integer to store the maximum batch rows.
* - `isPartTable`: Pointer to a boolean to indicate whether the relation is partitioned.
* - `isValuePartTable`: Pointer to a boolean to indicate whether the relation is value-partitioned.
* - `partialClusterRows`: Pointer to an integer to store the partial cluster rows.
* return value: None (void function).
* note: The function uses macros and functions provided by the relation to extract the required information and
* updates the pointers accordingly.
* date: 2023/8/15
* contact tel: 18720816902
*/
static inline void get_info_from_rel(
Relation relation, int* maxBatchRow, bool* isPartTable, bool* isValuePartTable, int* partialClusterRows)
{

View File

@ -661,21 +661,6 @@ void generate_base_implied_qualities(PlannerInfo* root)
}
}
/*
* function name: generate_base_implied_quality_clause
* description: This function generates implied quality clauses based on equivalence classes and a given restrict info.
* arguments:
* - `root`: PlannerInfo context for query planning.
* - `rel`: The relational optimization info for the relation.
* - `rinfo`: The restrict info for which implied quality clauses need to be generated.
* return value: None (void function).
* note: The function iterates through the equivalence classes and identifies potential sources to generate implied quality
* clauses. It considers conditions like the number of members in the equivalence class, the presence of volatile
* expressions, and subset relationships with the restrict info. It then processes and generates implied quality
* clauses for the identified conditions.
* date: 2023/8/16
* contact tel: 18720816902
*/
static void generate_base_implied_quality_clause(PlannerInfo* root, RelOptInfo* rel, RestrictInfo* rinfo)
{
ListCell* em_cell = NULL;

View File

@ -59,15 +59,6 @@ bool ES_SELECTIVITY::ContainIndexCols(const es_candidate* es, const IndexOptInfo
return true;
}
/*
* function name: MatchUniqueIndex
* description: This function checks if there is a unique B-tree index that matches the given es_candidate's columns.
* arguments:
* - `es`: The es_candidate containing information about the candidate equivalence set and its components.
* return value: A boolean indicating whether a matching unique B-tree index was found (true) or not (false).
* date: 2023/8/16
* contact tel: 18720816902
*/
bool ES_SELECTIVITY::MatchUniqueIndex(const es_candidate* es) const
{
ListCell* lci = NULL;
@ -656,19 +647,6 @@ void ES_SELECTIVITY::modify_distinct_by_possion_model(es_candidate* es, bool lef
return;
}
/*
* function name: ClauseIsLegal
* description: This function checks if a given clause is legal for the given type of equivalence set.
* arguments:
* - `type`: The type of equivalence set (ES_EQSEL, ES_EQJOINSEL, etc.).
* - `left`: The left-hand side of the clause.
* - `right`: The right-hand side of the clause.
* - `leftAttnum`: The attribute number of the left-hand side.
* - `rightAttnum`: The attribute number of the right-hand side.
* return value: A boolean indicating whether the clause is legal (true) or not (false) for the given equivalence set type.
* date: 2023/8/16
* contact tel: 18720816902
*/
static bool ClauseIsLegal(es_type type, const Node* left, const Node* right, int leftAttnum, int rightAttnum)
{
if (leftAttnum < 0 || rightAttnum < 0) {
@ -692,33 +670,11 @@ static bool ClauseIsLegal(es_type type, const Node* left, const Node* right, int
return true;
}
/*
* function name: RteIsValid
* description: This function checks whether a given RangeTblEntry pointer is valid and represents a relation.
* arguments:
* - `rte`: The RangeTblEntry pointer to be checked.
* return value: A boolean indicating whether the RangeTblEntry is valid and represents a relation (true) or not (false).
* note: This function is used to determine if a RangeTblEntry is correctly formed and corresponds to a relation.
* date: 2023/8/16
* contact tel: 18720816902
*/
static inline bool RteIsValid(const RangeTblEntry* rte)
{
return (rte != NULL && rte->rtekind == RTE_RELATION);
}
/*
* function name: setup_es
* description: This function sets up an equivalence set candidate with relevant information.
* arguments:
* - `es`: Pointer to the equivalence set candidate to be set up.
* - `type`: The type of the equivalence set (ES_EQSEL, ES_EQJOINSEL, etc.).
* - `clause`: The RestrictInfo clause associated with the equivalence set.
* return value: none
* note: This function initializes an equivalence set candidate by assigning its type, clause_relids, and other attributes.
* date: 2023/8/16
* contact tel: 18720816902
*/
void ES_SELECTIVITY::setup_es(es_candidate* es, es_type type, RestrictInfo* clause)
{
es->tag = type;
@ -729,20 +685,6 @@ void ES_SELECTIVITY::setup_es(es_candidate* es, es_type type, RestrictInfo* clau
es->right_first_mcvfreq = 0.0;
}
/*
* function name: build_es_candidate_for_eqsel
* description: This function builds an equivalence set candidate for an equality selectivity calculation.
* arguments:
* - `es`: Pointer to the equivalence set candidate being built.
* - `var`: The variable node representing the column being analyzed.
* - `attnum`: The attribute number of the column being analyzed.
* - `left`: A boolean indicating whether the variable is on the left-hand side of the clause.
* - `clause`: The RestrictInfo clause associated with the equivalence set.
* return value: A boolean indicating the success (true) or failure (false) of building the candidate.
* note: This function sets up an equivalence set candidate for equality selectivity calculation by extracting relevant information from the variable, clause, and left/right context.
* date: 2023/8/16
* contact tel: 18720816902
*/
bool ES_SELECTIVITY::build_es_candidate_for_eqsel(es_candidate* es, Node* var, int attnum, bool left,
RestrictInfo* clause)
{
@ -898,16 +840,6 @@ void ES_SELECTIVITY::recheck_candidate_list()
return;
}
/*
* function name: IsUnsupportedCases
* description: This function checks whether the given EquivalenceClass falls under unsupported cases for generating substitutes.
* arguments:
* - `ec`: Pointer to the EquivalenceClass being checked.
* return value: A boolean indicating whether the EquivalenceClass is unsupported (true) or not (false) for generating substitutes.
* note: This function considers various conditions such as having constants, being a broken equivalence class, or having too few members.
* date: 2023/8/16
* contact tel: 18720816902
*/
static inline bool IsUnsupportedCases(const EquivalenceClass* ec)
{
/* only consider var = var situation */
@ -1144,16 +1076,6 @@ void ES_SELECTIVITY::read_statistic()
return;
}
/*
* function name: cal_stadistinct_eqjoinsel
* description: This function calculates the selectivity for equality join clauses based on statistical information.
* arguments:
* - `es`: Pointer to the es_candidate containing the join candidate information.
* return value: A boolean indicating whether the selectivity calculation was successful (true) or not (false).
* note: This function considers various statistical information to calculate the selectivity for equality join clauses.
* date: 2023/8/16
* contact tel: 18720816902
*/
bool ES_SELECTIVITY::cal_stadistinct_eqjoinsel(es_candidate* es)
{
/*
@ -1207,18 +1129,6 @@ bool ES_SELECTIVITY::cal_stadistinct_eqjoinsel(es_candidate* es)
return false;
}
/*
* Macro name: CLEAN_UP_TEMP_OBJECTS
* description: This macro is used to clean up temporary objects and resources used in a block of code.
* arguments:
* - `tmp_left`: Temporary object to be cleaned up.
* - `tmp_right`: Temporary object to be cleaned up.
* - `left_stats_list`: List of extended statistics objects to be cleared.
* - `right_stats_list`: List of extended statistics objects to be cleared.
* usage: Use this macro to conveniently clean up temporary objects and lists after a block of code.
* date: 2023/8/16
* contact tel: 18720816902
*/
#define CLEAN_UP_TEMP_OBJECTS(tmp_left, tmp_right, left_stats_list, right_stats_list) \
do { \
bms_free_ext(tmp_left); \
@ -1310,18 +1220,6 @@ void ES_SELECTIVITY::read_statistic_eqjoinsel(es_candidate* es)
return;
}
/*
* function name: remove_members_without_es_stats
* description: This function removes members from an equivalence set candidate that do not have extended statistics.
* arguments:
* - `max_matched`: The maximum number of members matched.
* - `num_members`: The total number of members.
* - `es`: The equivalence set candidate to modify.
* note: The function removes members from the `es` candidate's `left_attnums` and calls `remove_attnum` to remove
* the corresponding attribute numbers.
* date: 2023/8/16
* contact tel: 18720816902
*/
void ES_SELECTIVITY::remove_members_without_es_stats(int max_matched, int num_members, es_candidate* es)
{
if (max_matched != num_members) {
@ -1335,15 +1233,6 @@ void ES_SELECTIVITY::remove_members_without_es_stats(int max_matched, int num_me
}
}
/*
* function name: cal_stadistinct_eqsel
* description: This function calculates the distinct estimate for an equivalence set candidate using extended statistics.
* arguments:
* - `es`: The equivalence set candidate to calculate distinct estimate for.
* note: The function calculates the distinct estimate for the `es` candidate's left-hand side using extended statistics.
* date: 2023/8/16
* contact tel: 18720816902
*/
void ES_SELECTIVITY::cal_stadistinct_eqsel(es_candidate* es)
{
/*
@ -1472,17 +1361,6 @@ int ES_SELECTIVITY::read_attnum(Node* node) const
return attnum;
}
/*
* function name: BuildNewRelList
* description: This function builds a new relation list based on the given attribute numbers and relation ID.
* arguments:
* - `attnumsTmp`: A Bitmapset containing attribute numbers.
* - `relidOid`: The OID of the relation.
* return value: A List containing the new relation list information.
* note: The function constructs a new relation list by combining the attribute numbers and relation ID.
* date: 2023/8/16
* contact tel: 18720816902
*/
static List* BuildNewRelList(Bitmapset* attnumsTmp, Oid relidOid)
{
List* record = NIL;
@ -1573,20 +1451,6 @@ void ES_SELECTIVITY::report_no_stats(Oid relid_oid, Bitmapset* attnums) const
return;
}
/*
* function name: MatchOnSameSide
* description: This function checks if a given clause matches on the same side of the equivalence set.
* arguments:
* - `clause`: The RestrictInfo clause to check.
* - `temp`: The es_candidate structure.
* - `leftAttnum`: The attribute number on the left side.
* - `rightAttnum`: The attribute number on the right side.
* return value: A boolean indicating whether the clause matches on the same side (true) or not (false).
* note: The function checks if the clause's left_relids and right_relids are equal to temp's left_relids and right_relids,
* and also ensures that the leftAttnum and rightAttnum are not members of temp's left_attnums and right_attnums.
* date: 2023/8/16
* contact tel: 18720816902
*/
static bool MatchOnSameSide(RestrictInfo* clause, es_candidate* temp, int leftAttnum, int rightAttnum)
{
return bms_equal(clause->left_relids, temp->left_relids) &&
@ -1594,20 +1458,6 @@ static bool MatchOnSameSide(RestrictInfo* clause, es_candidate* temp, int leftAt
!bms_is_member(leftAttnum, temp->left_attnums) && !bms_is_member(rightAttnum, temp->right_attnums);
}
/*
* function name: MatchOnOtherSide
* description: This function checks if a given clause matches on the other side of the equivalence set.
* arguments:
* - `clause`: The RestrictInfo clause to check.
* - `temp`: The es_candidate structure.
* - `leftAttnum`: The attribute number on the left side.
* - `rightAttnum`: The attribute number on the right side.
* return value: A boolean indicating whether the clause matches on the other side (true) or not (false).
* note: The function checks if the clause's right_relids and left_relids are equal to temp's left_relids and right_relids,
* and also ensures that the rightAttnum and leftAttnum are not members of temp's left_attnums and right_attnums.
* date: 2023/8/16
* contact tel: 18720816902
*/
static bool MatchOnOtherSide(RestrictInfo* clause, es_candidate* temp, int leftAttnum, int rightAttnum)
{
return bms_equal(clause->right_relids, temp->left_relids) &&
@ -1616,17 +1466,6 @@ static bool MatchOnOtherSide(RestrictInfo* clause, es_candidate* temp, int leftA
!bms_is_member(leftAttnum, temp->right_attnums);
}
/*
* function name: AttnumIsInvalid
* description: This function checks if the given attribute numbers are invalid.
* arguments:
* - `leftAttnum`: The attribute number on the left side.
* - `rightAttnum`: The attribute number on the right side.
* return value: A boolean indicating whether the attribute numbers are invalid (true) or not (false).
* note: The function checks if either of the attribute numbers is less than 0 or if both attribute numbers are 0.
* date: 2023/8/16
* contact tel: 18720816902
*/
static inline bool AttnumIsInvalid(int leftAttnum, int rightAttnum)
{
return (leftAttnum < 0 || rightAttnum < 0 || (leftAttnum == 0 && rightAttnum == 0));
@ -1769,20 +1608,6 @@ void ES_SELECTIVITY::read_rel_rte(Node* node, RelOptInfo** rel, RangeTblEntry**
return;
}
/*
* function name: save_selectivity
* description: This function saves selectivity information for the given equivalence set candidate.
* arguments:
* - `es`: The equivalence set candidate for which to save selectivity information.
* - `left_join_ratio`: The join ratio for the left side of the join.
* - `right_join_ratio`: The join ratio for the right side of the join.
* - `save_semi_join`: A boolean indicating whether to save information for a semi-join (true) or not (false).
* return value: None
* note: The function sets selectivity information for the provided equivalence set candidate, including calculating
* and saving selectivity ratios for the variables involved in the equivalence set.
* date: 2023/8/16
* contact tel: 18720816902
*/
void ES_SELECTIVITY::save_selectivity(
es_candidate* es, double left_join_ratio, double right_join_ratio, bool save_semi_join)
{
@ -1867,20 +1692,6 @@ void ES_SELECTIVITY::cal_bucket_size(es_candidate* es, es_bucketsize* bucket) co
return;
}
/*
* function name: estimate_hash_bucketsize
* description: This function estimates the bucket size for hash joins.
* arguments:
* - `es_bucket`: The es_bucketsize structure containing information needed for the estimation.
* - `distinctnum`: Pointer to the estimated number of distinct values.
* - `left`: A boolean indicating whether to estimate for the left side (true) or the right side (false) of the join.
* - `inner_path`: The inner side path of the join.
* - `nbuckets`: The number of hash buckets.
* return value: The estimated bucket size as a Selectivity value.
* note: This function calculates an estimated bucket size for hash joins based on various statistics and factors.
* date: 2023/8/16
* contact tel: 18720816902
*/
Selectivity ES_SELECTIVITY::estimate_hash_bucketsize(
es_bucketsize* es_bucket, double* distinctnum, bool left, Path* inner_path, double nbuckets)
{
@ -2002,17 +1813,6 @@ double ES_SELECTIVITY::estimate_local_numdistinct(es_bucketsize* bucket, bool le
return ndistinct;
}
/*
* function name: cal_eqjoinsel
* description: This function calculates the selectivity for equality join conditions.
* arguments:
* - `es`: The es_candidate structure containing information needed for the calculation.
* - `jointype`: The type of join (JOIN_INNER, JOIN_LEFT, JOIN_FULL, etc.).
* return value: The calculated selectivity as a Selectivity value.
* note: This function calculates the selectivity for equality join conditions based on the provided information and join type.
* date: 2023/8/16
* contact tel: 18720816902
*/
Selectivity ES_SELECTIVITY::cal_eqjoinsel(es_candidate* es, JoinType jointype)
{
Selectivity result = 1.0;
@ -2415,18 +2215,6 @@ Selectivity ES_SELECTIVITY::cal_eqjoinsel_inner(es_candidate* es)
return result;
}
/*
* function name: cal_eqjoinsel_semi
* description: This function calculates the selectivity for equality semi-join conditions.
* arguments:
* - `es`: The es_candidate structure containing information needed for the calculation.
* - `inner_rel`: The inner relation for the join.
* - `inner_on_left`: A boolean indicating whether the inner relation is on the left side of the join.
* return value: The calculated selectivity as a Selectivity value.
* note: This function calculates the selectivity for equality semi-join conditions based on the provided information.
* date: 2023/8/16
* contact tel: 18720816902
*/
Selectivity ES_SELECTIVITY::cal_eqjoinsel_semi(es_candidate* es, RelOptInfo* inner_rel, bool inner_on_left)
{
Assert(es->left_extended_stats);
@ -2742,17 +2530,6 @@ void ES_SELECTIVITY::debug_print()
return;
}
/*
* function name: print_rel
* description: This function prints information about a relation.
* arguments:
* - `rel`: The RangeTblEntry structure representing the relation.
* return value: None
* note: This function initializes a StringInfoData structure to format and print
* information about the given relation, including its name, kind, and inheritance status.
* date: 2023/8/16
* contact tel: 18720816902
*/
void ES_SELECTIVITY::print_rel(RangeTblEntry* rel) const
{
StringInfoData buf;
@ -2763,18 +2540,6 @@ void ES_SELECTIVITY::print_rel(RangeTblEntry* rel) const
return;
}
/*
* function name: print_relids
* description: This function prints a set of relation identifiers along with a provided string.
* arguments:
* - `relids`: The Bitmapset representing the set of relation identifiers.
* - `str`: The string to be included in the output.
* return value: None
* note: This function initializes a StringInfoData structure to format and print
* the provided string along with the identifiers from the Bitmapset.
* date: 2023/8/16
* contact tel: 18720816902
*/
void ES_SELECTIVITY::print_relids(Bitmapset* relids, const char* str) const
{
StringInfoData buf;
@ -2791,17 +2556,6 @@ void ES_SELECTIVITY::print_relids(Bitmapset* relids, const char* str) const
return;
}
/*
* function name: print_clauses
* description: This function prints a list of clauses along with their expressions.
* arguments:
* - `clauses`: The list of RestrictInfo clauses to be printed.
* return value: None
* note: This function initializes a StringInfoData structure to format and print
* the list of clauses and their expressions.
* date: 2023/8/16
* contact tel: 18720816902
*/
void ES_SELECTIVITY::print_clauses(List* clauses) const
{
if (root == NULL || list_length(clauses) == 0)
@ -2829,17 +2583,6 @@ void ES_SELECTIVITY::print_clauses(List* clauses) const
return;
}
/*
* function name: print_expr
* description: This function converts a given expression node to its string representation.
* arguments:
* - `expr`: The expression node to be converted to string.
* - `rtable`: The list of RangeTblEntry entries used for resolving references in the expression.
* return value: A dynamically allocated string representing the expression.
* note: This function utilizes the ExprToString function to convert the expression node.
* date: 2023/8/16
* contact tel: 18720816902
*/
char* ES_SELECTIVITY::print_expr(const Node* expr, const List* rtable) const
{
return ExprToString(expr, rtable);

View File

@ -743,16 +743,6 @@ static void get_index_paths(
}
}
/*
* function name: index_relation_has_bucket
* description: This function checks if an index relation has a bucket.
* arguments:
* - `index`: The IndexOptInfo structure representing the index.
* return value: A boolean indicating whether the index relation has a bucket (true) or not (false).
* note: This function opens the underlying heap relation of the index to check for the presence of a bucket.
* date: 2023/8/16
* contact tel: 18720816902
*/
static inline bool index_relation_has_bucket(IndexOptInfo* index)
{
Assert(index != NULL);
@ -763,16 +753,6 @@ static inline bool index_relation_has_bucket(IndexOptInfo* index)
return hasBucket;
}
/*
* function name: IsEqRestrict
* description: This function checks if a RestrictInfo represents an equality restriction.
* arguments:
* - `rinfo`: The RestrictInfo structure representing the restriction.
* return value: A boolean indicating whether the restriction is an equality restriction (true) or not (false).
* note: The function checks if the given clause is an equality operator clause and if the operator's result type is EQSELRETURNOID.
* date: 2023/8/16
* contact tel: 18720816902
*/
inline bool IsEqRestrict(const RestrictInfo* rinfo)
{
Expr* clause = rinfo->clause;
@ -834,17 +814,6 @@ void MarkUniqueIndexFirstRule(const RelOptInfo* rel, const IndexOptInfo* index,
}
}
/*
* function name: PathkeysIsUnusefulForPartition
* description: This function checks if the path keys of an index are unuseful for partitioning purposes.
* arguments:
* - `index`: The IndexOptInfo structure representing the index.
* return value: A boolean indicating whether the path keys are unuseful for partitioning (true) or not (false).
* note: The function considers various conditions, including if the index is a partitioned index, if it's global or hypothetical,
* and the type of partitioning being used.
* date: 2023/8/16
* contact tel: 18720816902
*/
static bool PathkeysIsUnusefulForPartition(const IndexOptInfo* index)
{
if (!index->ispartitionedindex) {

View File

@ -76,18 +76,6 @@ static void getBoundaryFromPartSeq(
static Path* fakePathForPWJ(Path* path);
static bool* calculate_join_georgraphy(
PlannerInfo* root, RelOptInfo* outerrel, RelOptInfo* innerrel, List* joinclauses);
/*
* function name: debug1_print_outerrel_and_innerrel
* description: This function prints debug information about outer and inner relations during join planning.
* arguments:
* - `root`: The PlannerInfo structure representing the query being planned.
* - `outerrel`: The outer relation being joined.
* - `innerrel`: The inner relation being joined.
* return value: None.
* note: The function checks if the log_min_messages level is low enough for DEBUG1 messages before printing the information.
* date: 2023/8/16
* contact tel: 18720816902
*/
void debug1_print_outerrel_and_innerrel(PlannerInfo* root, RelOptInfo* outerrel, RelOptInfo* innerrel)
{
if (log_min_messages > DEBUG1)
@ -490,18 +478,6 @@ static bool add_path_hintcheck(
return false;
}
/*
* function name: get_join_distribution_perference_type
* description: This function determines the distribution preference type for a join operation.
* arguments:
* - `joinRel`: The joined relation.
* - `innerPath`: The path for the inner relation.
* - `outerPath`: The path for the outer relation.
* return value: The distribution preference type (DPT_SINGLE or DPT_SHUFFLE).
* note: The function checks the enable_dngather and is_dngather_support settings before making a decision.
* date: 2023/8/17
* contact tel: 18720816902
*/
DistrbutionPreferenceType get_join_distribution_perference_type(RelOptInfo* joinRel, Path* innerPath, Path* outerPath)
{
if (!u_sess->attr.attr_sql.enable_dngather || !u_sess->opt_cxt.is_dngather_support) {
@ -909,26 +885,6 @@ static void try_mergejoin_path(PlannerInfo* root, RelOptInfo* joinrel, JoinType
}
}
/*
* function name: TryHashJoinPathSingle
* description: Tries to generate a hash join path for a single pair of relations.
* arguments:
* - `root`: PlannerInfo containing the query context.
* - `joinrel`: The joined relation.
* - `jointype`: The type of join to be performed.
* - `sjinfo`: SpecialJoinInfo for special join cases.
* - `semifactors`: Factors for semi-joins or anti-joins.
* - `outerPath`: Path for the outer relation.
* - `innerPath`: Path for the inner relation.
* - `restrictClauses`: List of join clauses.
* - `hashclauses`: List of hash clauses.
* - `requiredOuter`: Required outer relation.
* - `workspace`: JoinCostWorkspace for cost estimation.
* note: This function attempts to use partitionwise join if applicable, and adds the hash join path to the
* joinrel's path list.
* date: 2023/8/16
* contact tel: 18720816902
*/
static void TryHashJoinPathSingle(PlannerInfo* root, RelOptInfo* joinrel, JoinType jointype,
SpecialJoinInfo* sjinfo, SemiAntiJoinFactors* semifactors, Path* outerPath, Path* innerPath,
List* restrictClauses, List* hashclauses, Relids requiredOuter, JoinCostWorkspace* workspace)
@ -2078,19 +2034,6 @@ static List* select_mergejoin_clauses(PlannerInfo* root, RelOptInfo* joinrel, Re
return result_list;
}
/*
* function name: checkForPWJ
* description: Checks if partitionwise join is applicable for the given paths and conditions.
* arguments:
* - `root`: PlannerInfo containing the query context.
* - `outer_path`: Path for the outer relation.
* - `inner_path`: Path for the inner relation.
* - `jointype`: The type of join to be performed.
* - `joinrestrict`: List of join clauses.
* returns: True if partitionwise join is applicable, false otherwise.
* date: 2023/8/16
* contact tel: 18720816902
*/
static bool checkForPWJ(PlannerInfo* root, Path* outer_path, Path* inner_path, JoinType jointype, List* joinrestrict)
{
/* Validate configuration */
@ -2148,15 +2091,6 @@ static bool checkForPWJ(PlannerInfo* root, Path* outer_path, Path* inner_path, J
return true;
}
/*
* function name: checkIndexPathForPWJ
* description: Checks if the given partition iterator path's index subpath is usable for partitionwise join.
* arguments:
* - `pIterpath`: Partition iterator path to be checked.
* returns: True if the index subpath is usable, false otherwise.
* date: 2023/8/16
* contact tel: 18720816902
*/
static bool checkIndexPathForPWJ(PartIteratorPath* pIterpath)
{
bool result = false;
@ -2176,16 +2110,6 @@ static bool checkIndexPathForPWJ(PartIteratorPath* pIterpath)
return result;
}
/*
* function name: checkPathForPWJ
* description: Checks if the given path is usable for partitionwise join.
* arguments:
* - `root`: PlannerInfo struct for the current query.
* - `path`: Path to be checked.
* returns: True if the path is usable, false otherwise.
* date: 2023/8/16
* contact tel: 18720816902
*/
static bool checkPathForPWJ(PlannerInfo* root, Path* path)
{
bool result = false;
@ -2213,16 +2137,6 @@ static bool checkPathForPWJ(PlannerInfo* root, Path* path)
return result;
}
/*
* function name: checkPruningResultForPWJ
* description: Checks if the pruning result of outer and inner paths match for partitionwise join.
* arguments:
* - `outerpath`: Outer PartIteratorPath.
* - `innerpath`: Inner PartIteratorPath.
* returns: True if the pruning results match, false otherwise.
* date: 2023/8/16
* contact tel: 18720816902
*/
static bool checkPruningResultForPWJ(PartIteratorPath* outerpath, PartIteratorPath* innerpath)
{
if (outerpath->itrs > 0 && innerpath->itrs > 0 && outerpath->itrs == innerpath->itrs) {
@ -2232,16 +2146,6 @@ static bool checkPruningResultForPWJ(PartIteratorPath* outerpath, PartIteratorPa
return false;
}
/*
* function name: checkScanDirectionPWJ
* description: Checks if the scan directions of outer and inner paths match for partitionwise join.
* arguments:
* - `outerpath`: Outer PartIteratorPath.
* - `innerpath`: Inner PartIteratorPath.
* returns: True if the scan directions match, false otherwise.
* date: 2023/8/16
* contact tel: 18720816902
*/
static bool checkScanDirectionPWJ(PartIteratorPath* outerpath, PartIteratorPath* innerpath)
{
if (outerpath->direction != innerpath->direction)
@ -2250,17 +2154,6 @@ static bool checkScanDirectionPWJ(PartIteratorPath* outerpath, PartIteratorPath*
return true;
}
/*
* function name: checkPartitionkeyForPWJ
* description: Checks if the partition keys of outer and inner paths are compatible for partitionwise join.
* arguments:
* - `root`: PlannerInfo struct.
* - `outer_path`: Outer path for join.
* - `inner_path`: Inner path for join.
* returns: True if partition keys are compatible, false otherwise.
* date: 2023/8/16
* contact tel: 18720816902
*/
static bool checkPartitionkeyForPWJ(PlannerInfo* root, Path* outer_path, Path* inner_path)
{
bool result = true;
@ -2453,17 +2346,6 @@ static bool checkJoinClauseForPWJ(PlannerInfo* root, List* joinclause)
return result;
}
/*
* function name: checkBoundaryForPWJ
* description: Checks if the boundary information of outer and inner paths is valid for partitionwise join.
* arguments:
* - `root`: PlannerInfo struct.
* - `outerpath`: Outer PartIteratorPath for join.
* - `innerpath`: Inner PartIteratorPath for join.
* returns: True if boundary information is valid, false otherwise.
* date: 2023/8/16
* contact tel: 18720816902
*/
static bool checkBoundaryForPWJ(PlannerInfo* root, PartIteratorPath* outerpath, PartIteratorPath* innerpath)
{
RelOptInfo* outerrel = outerpath->path.parent;
@ -2489,16 +2371,6 @@ static bool checkBoundaryForPWJ(PlannerInfo* root, PartIteratorPath* outerpath,
return result;
}
/*
* function name: checkBoundary
* description: Checks if the boundary values of outer and inner partitions match for partitionwise join.
* arguments:
* - `outer_list`: List of Const values representing the boundary of outer partition.
* - `inner_list`: List of Const values representing the boundary of inner partition.
* returns: True if boundaries match, false otherwise.
* date: 2023/8/16
* contact tel: 18720816902
*/
static bool checkBoundary(List* outer_list, List* inner_list)
{
ListCell* outer_cell = NULL;
@ -2519,16 +2391,6 @@ static bool checkBoundary(List* outer_list, List* inner_list)
return result;
}
/*
* function name: getPartitionkeyDataType
* description: Gets the data types of the partition key columns for a given relation.
* arguments:
* - `root`: PlannerInfo structure containing query information.
* - `rel`: RelOptInfo structure for the relation whose partition key data types are needed.
* returns: List of OIDs representing the data types of the partition key columns.
* date: 2023/8/16
* contact tel: 18720816902
*/
static List* getPartitionkeyDataType(PlannerInfo* root, RelOptInfo* rel)
{
List* result = NIL;
@ -2576,16 +2438,6 @@ static List* getPartitionkeyDataType(PlannerInfo* root, RelOptInfo* rel)
return result;
}
/*
* function name: getPartIteratorPathForPWJ
* description: Retrieves the PartIteratorPath from a given path. It traverses through possible MaterialPath
* wrappers to find the underlying PartIteratorPath.
* arguments:
* - `path`: The path from which the PartIteratorPath is to be retrieved.
* returns: A pointer to the PartIteratorPath, or NULL if not found.
* date: 2023/8/16
* contact tel: 18720816902
*/
static PartIteratorPath* getPartIteratorPathForPWJ(Path* path)
{
Path* result = NULL;
@ -2605,17 +2457,6 @@ static PartIteratorPath* getPartIteratorPathForPWJ(Path* path)
return (PartIteratorPath*)result;
}
/*
* function name: getBoundaryFromBaseRel
* description: Retrieves the upper and lower boundaries from a base relation's pruning result
* and sets them in the provided PartIteratorPath structure.
* arguments:
* - `root`: The planner's root node.
* - `itrpath`: The PartIteratorPath for which to set the boundaries.
* returns: None.
* date: 2023/8/16
* contact tel: 18720816902
*/
static void getBoundaryFromBaseRel(PlannerInfo* root, PartIteratorPath* itrpath)
{
ListCell* cell = NULL;
@ -2687,20 +2528,6 @@ static void getBoundaryFromBaseRel(PlannerInfo* root, PartIteratorPath* itrpath)
heap_close(relation, NoLock);
}
/*
* function name: getBoundaryFromPartSeq
* description: Retrieves the upper and lower boundary constants from a partition map based on the provided
* partition sequence and attribute information.
* arguments:
* - `map`: The PartitionMap containing the partition information.
* - `partitionSeq`: The sequence number of the partition for which to retrieve the boundaries.
* - `att`: The Form_pg_attribute structure representing the attribute information.
* - `upper`: A pointer to a Const pointer where the upper boundary constant will be stored.
* - `lower`: A pointer to a Const pointer where the lower boundary constant will be stored.
* returns: None.
* date: 2023/8/16
* contact tel: 18720816902
*/
static void getBoundaryFromPartSeq(
PartitionMap* map, int partitionSeq, Form_pg_attribute att, Const** upper, Const** lower)
{
@ -2733,18 +2560,6 @@ static void getBoundaryFromPartSeq(
}
}
/*
* function name: buildPartitionWiseJoinPath
* description: Builds a partitionwise join path based on the provided join path, outer path, and inner path.
* arguments:
* - `jpath`: The original join path to be used as the subpath for the partitionwise join path.
* - `outter_path`: The outer path of the join.
* - `inner_path`: The inner path of the join.
* returns:
* A new Path representing the partitionwise join path.
* date: 2023/8/16
* contact tel: 18720816902
*/
static Path* buildPartitionWiseJoinPath(Path* jpath, Path* outter_path, Path* inner_path)
{
PartIteratorPath* pwjpath = NULL;
@ -2783,16 +2598,13 @@ static Path* buildPartitionWiseJoinPath(Path* jpath, Path* outter_path, Path* in
}
/*
* function name: fakePathForPWJ
* description: Creates a "fake" path suitable for use in partitionwise join processing.
* This function is used to replace the current path with a path that conforms
* to the requirements of partitionwise join.
* arguments:
* - `path`: The original path that needs to be replaced.
* returns:
* A new Path structure that meets the requirements of partitionwise join.
* date: 2023/8/16
* contact tel: 18720816902
* @@GaussDB@@
* Target : data partition
* Brief :
* Description :
* Input :
* Output :
* Notes :
*/
static Path* fakePathForPWJ(Path* path)
{

View File

@ -1072,18 +1072,6 @@ List* find_mergeclauses_for_outer_pathkeys(PlannerInfo* root, List* pathkeys, Li
return mergeclauses;
}
/*
* function name: get_pathkey_index
* description: Returns the index of the given EquivalenceClass pointer in the array of EquivalenceClass pointers.
* arguments:
* - `ecs`: An array of EquivalenceClass pointers.
* - `necs`: The number of elements in the `ecs` array.
* - `key`: The EquivalenceClass pointer to search for.
* returns:
* The index of the `key` pointer in the `ecs` array if found, or the index after the last element if not found.
* date: 2023/8/16
* contact tel: 18720816902
*/
inline int get_pathkey_index(EquivalenceClass** ecs, int necs, EquivalenceClass* key)
{
int idx;

View File

@ -253,14 +253,6 @@ void JoinPathGenBase::init()
m_redistributeOuter = false;
}
/*
* function name: initRangeListDistribution
* description: This function initializes the distribution strategy for a join path based on range or list distribution.
* arguments: None
* returns: None
* date: 2023/8/16
* contact tel: 18720816902
*/
void JoinPathGenBase::initRangeListDistribution()
{
m_rangelistOuter = IsLocatorDistributedBySlice(m_outerPath->locator_type);

File diff suppressed because it is too large Load Diff

View File

@ -1181,17 +1181,6 @@ 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

View File

@ -1045,22 +1045,7 @@ Node* replace_rte_variables(Node* node, int target_varno, int sublevels_up, repl
return result;
}
/*
function name: replace_rte_variables_mutator
description: This function recursively replaces Range Table Entry (RTE) variables in an expression tree with provided substitutions.
arguments: The first argument represents the pointer of the current node in the expression tree.
The second argument indicates the context information for the replacement process.
return value: Returns the modified expression tree with RTE variable substitutions or the original tree if no changes were made.
note: The main process is as follows:
-> Traverses the expression tree recursively, handling different node types.
-> If the node is a Var (RTE variable), substitutes it if matching target conditions.
-> Handles CurrentOfExpr for applicable cases.
-> Handles GroupingFunc nodes, checking for subplans.
-> Recurses into Query nodes, updating inserted_sublink and hasSubLinks flags.
-> Returns the modified expression tree.
date: 2023/8/12
contact tel: 18720816902
*/
Node* replace_rte_variables_mutator(Node* node, replace_rte_variables_context* context)
{
if (node == NULL)

View File

@ -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 && !t_thrd.pagewriter_cxt.shutdown_requested) {
if (candidate_num == 0) {
/* wakeup sub thread scan the buffer pool, init the candidate list */
wakeup_sub_thread();
}

View File

@ -825,10 +825,10 @@ void client_read_ended(void)
#define INIT_PLUGIN_OBJECT "init_plugin_object"
void InitBSqlPluginHookIfNeeded()
{
const char* dolphin = "dolphin";
const char* b_sql_plugin = "b_sql_plugin";
CFunInfo tmpCF;
tmpCF = load_external_function(dolphin, INIT_PLUGIN_OBJECT, false, false);
tmpCF = load_external_function(b_sql_plugin, INIT_PLUGIN_OBJECT, false, false);
if (tmpCF.user_fn != NULL) {
((void* (*)(void))(tmpCF.user_fn))();
}
@ -862,11 +862,9 @@ List* pg_parse_query(const char* query_string, List** query_string_locationlist)
List* (*parser_hook)(const char*, List**) = raw_parser;
#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 = (List* (*)(const char*, List**))g_instance.raw_parser_hook[id];
}
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);
@ -6114,9 +6112,6 @@ 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,
@ -7574,7 +7569,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) && u_sess->attr.attr_sql.dolphin) {
if (u_sess->proc_cxt.MyDatabaseId != InvalidOid && DB_IS_CMPT(B_FORMAT) && u_sess->attr.attr_sql.b_sql_plugin) {
InitBSqlPluginHookIfNeeded();
}
#endif

View File

@ -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) && u_sess->attr.attr_sql.dolphin) {
if (u_sess->proc_cxt.MyDatabaseId != InvalidOid && DB_IS_CMPT(B_FORMAT) && u_sess->attr.attr_sql.b_sql_plugin) {
InitBSqlPluginHookIfNeeded();
}
#endif

View File

@ -720,6 +720,7 @@ static Datum ExecEvalWholeRowVar(
{
Var* variable = (Var*)wrvstate->xprstate.expr;
TupleTableSlot* slot = NULL;
TupleDesc slot_tupdesc;
bool needslow = false;
if (isDone != NULL)
@ -801,13 +802,21 @@ 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 (variable->vartype == RECORDOID) {
if (slot_tupdesc->tdtypeid == RECORDOID && slot_tupdesc->tdtypmod < 0)
assign_record_type_typmod(slot_tupdesc);
} else {
TupleDesc var_tupdesc;
TupleDesc slot_tupdesc;
int i;
/*
@ -824,8 +833,6 @@ 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),
@ -879,7 +886,6 @@ static Datum ExecEvalWholeRowFast(
{
Var* variable = (Var*)wrvstate->xprstate.expr;
TupleTableSlot* slot = NULL;
TupleDesc slot_tupdesc;
HeapTuple tuple;
TupleDesc tupleDesc;
HeapTupleHeader dtuple;
@ -909,17 +915,6 @@ 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;
@ -1901,13 +1896,6 @@ static void set_result_for_plpgsql_language_function_with_outparam(FuncExprState
* @bool has_cursor_return - need store out-args cursor info.
* @bool has_refcursor - need store in-args cursor info.
* @bool isSetReturnFunc - indicate function returns a set.
*The execution process of the ExecMakeFunctionResult function is as follows.
* (1) Check whether funcResultStore exists, if so, get the result and return it
(2) The calculated parameter values are stored in fcinfo.
(3) Pass the parameter into the expression function to calculate the expression,
first determine whether the parameter args exists null, and then determine the return mode of the function that returns the set,
SFRM_ValuePerCall mode is to return a value each time the call, The SFRM_Materialize schema is the result set instantiated in Tuplestore.
(4) Calculate and return results according to different modes.
*/
template <bool has_refcursor, bool has_cursor_return, bool isSetReturnFunc>
static Datum ExecMakeFunctionResult(FuncExprState* fcache, ExprContext* econtext, bool* isNull, ExprDoneCond* isDone)
@ -3089,10 +3077,6 @@ no_function_result:
/* ----------------------------------------------------------------
* ExecEvalFunc
* ----------------------------------------------------------------
*The execution process of the ExecEvalFunc function is as follows.
(1) Initialize the FuncExprState node by init_fcache function, including initialization parameters, memory management, etc.
(2) Judge whether the returned result is of set type according to the data in the FuncExprState function,
and call the corresponding function to calculate the result.
*/
static Datum ExecEvalFunc(FuncExprState* fcache, ExprContext* econtext, bool* isNull, ExprDoneCond* isDone)
{
@ -3537,10 +3521,6 @@ static Datum ExecEvalNot(BoolExprState* notclause, ExprContext* econtext, bool*
/* ----------------------------------------------------------------
* ExecEvalOr
* ----------------------------------------------------------------
*The main execution process of ExecEvalOr function is as follows.
(1) Traverse child expression clauses.
(2) Use the function ExecEvalExpr to call the expression calculation function in clause and calculate the result.
(3) To judge the results, if there is a result in the or expression that meets the conditions, it will jump out of the loop and return directly.
*/
static Datum ExecEvalOr(BoolExprState* orExpr, ExprContext* econtext, bool* isNull, ExprDoneCond* isDone)
{
@ -5179,11 +5159,6 @@ Datum ExecEvalExprSwitchContext(ExprState* expression, ExprContext* econtext, bo
* 'parent' may be NULL if we are preparing an expression that is not
* associated with a plan tree. (If so, it can't have aggs or subplans.)
* This case should usually come through ExecPrepareExpr, not directly here.
*The execution process of the ExecInitExpr function is as follows.
(1) Determine whether the input node is empty. If it is empty,return NULL directly, indicating that there is no restriction for expression.
(2) According to the type of node input,Initialize variable evalfunc which is the execution function corresponding to node,
If the node has parameters or expressions, the function ExecInitExpr will be recursively called and ExprState tree will be generated.
(3) Return ExprState tree, and execute the expression recursively according to ExprState tree.
*/
ExprState* ExecInitExpr(Expr* node, PlanState* parent)
{
@ -6143,10 +6118,6 @@ Datum fetch_lob_value_from_tuple(varatt_lob_pointer* lob_pointer, Oid update_oid
* of *isDone = ExprMultipleResult signifies a set element, and a return
* of *isDone = ExprEndResult signifies end of the set of tuple.
* We assume that *isDone has been initialized to ExprSingleResult by caller.
* The execution process of the ExecTargetList function is as follows.
(1) Iterate over the expressions in targetlist.
(2) Calculation of expression results.
(3) Judge the itemIsDone[resind] parameter in the results and generate the final tuple.
*/
static bool ExecTargetList(List* targetlist, ExprContext* econtext, Datum* values, bool* isnull,
ExprDoneCond* itemIsDone, ExprDoneCond* isDone)

View File

@ -322,6 +322,7 @@ 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
@ -345,16 +346,12 @@ 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;
}
@ -404,10 +401,6 @@ 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
@ -485,6 +478,7 @@ 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;
/*
@ -517,16 +511,12 @@ 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;
}
@ -663,6 +653,7 @@ 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 */
@ -681,11 +672,10 @@ 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, tuple, cid,
res = tableam_tuple_update(targetRelation, parentRelation, searchSlotTid, slot->tts_tuple, cid,
InvalidSnapshot, estate->es_snapshot, true, &oldslot, &tmfd, &updateIndexes, &modifiedIdxAttrs,
false, allowInplaceUpdate);
CheckTupleModifyRes(res);

View File

@ -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 = defGetBoolean(defElem);
tableCreateSupport->compressByteConvert = true;
} else if (pg_strcasecmp(defname, "compress_diff_convert") == 0) {
tableCreateSupport->compressDiffConvert = defGetBoolean(defElem);
tableCreateSupport->compressDiffConvert = true;
}
}

View File

@ -8965,8 +8965,6 @@ 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.
*/

View File

@ -1818,47 +1818,3 @@ 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;
}

View File

@ -238,19 +238,15 @@ public:
return m_purpose;
}
GcEpochType GcStartInnerTxn()
void GcStartTxnMTtests()
{
m_gcEpoch = GetGlobalEpoch();
return m_gcEpoch;
if (m_gcEpoch != GetGlobalEpoch())
m_gcEpoch = GetGlobalEpoch();
}
void GcEndInnerTxn(bool clean_gc)
void GcEndTxnMTtests()
{
if (clean_gc) {
RunQuicese();
}
m_gcEpoch = 0;
RunQuicese();
}
void GcStartTxn()
@ -276,7 +272,6 @@ public:
RunQuicese();
m_managerLock.unlock();
}
m_gcEpoch = 0;
m_isTxnStarted = false;
}
@ -318,6 +313,7 @@ public:
{
if (m_performGcEpoch != g_gcActiveEpoch)
HardQuiesce(m_rcuFreeCount);
m_gcEpoch = 0;
}
/** @brief Clean all object at the end of the session */

View File

@ -258,15 +258,6 @@ 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;
@ -309,16 +300,8 @@ 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);
@ -360,6 +343,9 @@ 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;
}

View File

@ -56,22 +56,12 @@ void* basic_table<P>::insert(MOT::Key const* const& key, void* const& entry, boo
5. Update the the key slice, keylen, key suffix and key's value in the
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 (done in lp.finish function). */
later in finish_insert (called from lp.finish). */
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());
bool found = lp.find_insert(*mtSessionThreadInfo);
// If the key is new (not previously existing) then we record the entry under
// that key

View File

@ -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_ref_;
node_base<P>* root_;
int len_;
size_t size_;
MOT::MasstreePrimaryIndex* index_;
char s_[0];
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())
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())
{
errno_t erc = memcpy_s(s_, len_, prefix.data(), len_);
errno_t erc = memcpy_s(s_, size_, prefix.data(), len_);
securec_check(erc, "\0", "\0");
}
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_ref, Str prefix, threadinfo& ti);
static void make(node_base<P>* root, 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 might create new gc layer removal requests and add them to GC.
// Index must be provided to allow access to the memory pools.
// 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.
mtSessionThreadInfo->set_working_index(index_);
(*this)(*mtSessionThreadInfo);
mtSessionThreadInfo->set_working_index(NULL);
@ -73,33 +73,30 @@ 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)
{
masstree_invariant(root_ref_);
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();
// 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();
}
ti.add_nodes_to_gc();
}
template <typename P>
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 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);
// If root was already deleted, do nothing.
if (root_->deleted()) {
return;
}
gc_layer_rcu_callback_ng<P>* cb = new (data) gc_layer_rcu_callback_ng<P>(root_ref, prefix, sz);
tcursor<P> node_cursor(root_, s_, len_);
if (!node_cursor.gc_layer(ti) || !node_cursor.finish_remove(ti)) {
node_cursor.n_->unlock();
}
}
template <typename P>
void gc_layer_rcu_callback_ng<P>::make(node_base<P>* root, Str prefix, threadinfo& ti)
{
size_t sz = prefix.len + sizeof(gc_layer_rcu_callback_ng<P>);
// As we are using slab allocator to allocate the memory, sz is will updated in ti.allocate with the real allocated
// size
void* data = ti.allocate(sz, memtag_masstree_gc, &sz /*OUT PARAM*/);
gc_layer_rcu_callback_ng<P>* cb = new (data) gc_layer_rcu_callback_ng<P>(root, prefix, sz);
ti.rcu_register(cb, sz);
}

View File

@ -69,17 +69,14 @@ 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 && existingItem) { // key mapping already exists in unique index
if (!inserted) { // key mapping already exists in unique index
result = reinterpret_cast<Sentinel*>(existingItem);
} // otherwise return null pointer (if !inserted && !existingItem, Key does not exist and insertation failed due to
// memory issue)
} // otherwise return null pointer
return result;
}
@ -111,8 +108,6 @@ 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);

View File

@ -37,7 +37,6 @@
#include "masstree/mot_masstree_struct.hpp"
#include "masstree/mot_masstree_iterator.hpp"
#include <cmath>
#include "mot_engine.h"
namespace MOT {
/**
@ -303,38 +302,11 @@ public:
/**
* @brief Print Masstree pools memory consumption details to log.
*/
virtual void PrintPoolsStats(LogLevel level = LogLevel::LL_DEBUG)
virtual void PrintPoolsStats()
{
m_leafsPool->Print("Leafs pool", level);
m_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();
m_leafsPool->Print("Leafs pool: ");
m_internodesPool->Print("Internode pool: ");
m_ksuffixSlab->Print("Ksuffix slab: ");
}
/**
@ -344,8 +316,6 @@ public:
{
m_initialized = false;
DestroyPools();
// remove masstree's root pointer (not valid anymore)
*(m_index.root_ref()) = nullptr;
return IndexInitImpl(NULL);
}
@ -362,7 +332,7 @@ public:
* @param tag Hint to determine which pool to use.
* @return Pointer to allocated memory.
*/
virtual void* AllocateMem(int& size, enum memtag tag)
void* AllocateMem(int& size, enum memtag tag)
{
switch (tag) {
case memtag_masstree_leaf:
@ -390,7 +360,7 @@ public:
* @param Pointer to allocated memory.
* @return True if deallocation succeeded.
*/
virtual bool DeallocateMem(void* ptr, int size, enum memtag tag)
bool DeallocateMem(void* ptr, int size, enum memtag tag)
{
switch (tag) {
case memtag_masstree_leaf:
@ -461,16 +431,10 @@ public:
{
// If dropIndex == true, all index's pools are going to be cleaned, so we skip the release here
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;
}

View File

@ -582,7 +582,6 @@ 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();

View File

@ -413,8 +413,6 @@ 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
@ -822,8 +820,6 @@ 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);

Some files were not shown because too many files have changed in this diff Show More