Compare commits

..

73 Commits

Author SHA1 Message Date
opengauss-bot 72f4d68de6
!1772 修复在部分场景下,非sysadmin用户执行gs_dump失败的问题
Merge pull request !1772 from pengjiong/drop_ext
2022-05-28 11:52:08 +00:00
TotaJ 62e3bed09b Fix gs_dump 2022-05-28 17:58:05 +08:00
opengauss-bot 7d4d95a5ad
!1764 函数使用internal类型的限制添加wm_concat
Merge pull request !1764 from 吕辉/wm_concat
2022-05-28 07:00:10 +00:00
opengauss-bot 240f61c595
!1740 compressByteConvert\compressDiffConvert内存判断当且仅当用户输入为true而不是判断用户是否使用该参数
Merge pull request !1740 from 吴岳川/I54KW0
2022-05-28 02:02:39 +00:00
opengauss-bot a0d1a547f8
!1741 【压缩特性】在回放过程中,假设表文件已经被创建而表_pca等文件未被创建,flags会被修改,丢失O_CREATE标记,导致备机回放失败
Merge pull request !1741 from 吴岳川/I56GGM
2022-05-28 01:43:32 +00:00
opengauss-bot df804a8a91
!1763 在support_extended_features场景下,支持删除插件
Merge pull request !1763 from pengjiong/drop_ext
2022-05-26 11:10:25 +00:00
TotaJ 91917dcfaf Fix drop extension. 2022-05-26 16:22:52 +08:00
lvhui e2163187ca add wm_concat in InternalAggIsSupported 2022-05-26 15:34:47 +08:00
opengauss-bot 1d7eadd778
!1762 [bugfix] 修复host_standby=off/wal_level=archive场景下failover/switchover出现tuple concurrently updated的问题
Merge pull request !1762 from 周斌/gsc_hoststandby
2022-05-26 01:31:22 +00:00
opengauss-bot b335ef9af7
!1761 [feature] 修复GSC函数接口内存重复统计问题
Merge pull request !1761 from 周斌/gsc_cache_duplicate
2022-05-26 01:30:00 +00:00
justbk 572d99d03c repair wal_level=archive in switchover/failover get tuple concurrently updated issue 2022-05-25 20:17:01 +08:00
opengauss-bot 0b0959fc69
!1760 DFX: add exit log in PercentileMain
Merge pull request !1760 from 吴岳川/I5696K
2022-05-25 11:25:07 +00:00
justbk 238ee19a59 repair gs_gsc_memory_detail memory info inaccurate issue 2022-05-25 15:43:39 +08:00
opengauss-bot d199d90a71
!1747 修复复合datum产生的record报错
Merge pull request !1747 from 仲夏十三/helper
2022-05-25 03:17:57 +00:00
opengauss-bot 2a77a3cebc
!1751 增加alter procedure帮助说明
Merge pull request !1751 from 仲夏十三/helper2
2022-05-25 03:15:27 +00:00
opengauss-bot 214d01ddb6
!1759 [bugfix] 修复备机GSC不缓存数据问题
Merge pull request !1759 from 周斌/no_gsc_cache
2022-05-25 02:40:49 +00:00
opengauss-bot 4f024161f0
!1758 [bugfix] 修复openGauss数据库关闭时pagewriter主线程退出失败的问题
Merge pull request !1758 from 周斌/master
2022-05-25 02:38:02 +00:00
wuyuechuan 82d5ac65b0 DFX: add exit log in PercentileMain 2022-05-25 10:13:36 +08:00
justbk 7edda5e2a4 repair GSC no cache issue 2022-05-24 21:47:43 +08:00
justbk e10c482649 repair opengauss close failed issue 2022-05-24 20:29:11 +08:00
opengauss-bot 0a29277070
!1739 修复wal2json插件编译时报logical.h文件中的DefElem类型未声明的错误
Merge pull request !1739 from 薛蒙恩/com_wal2json
2022-05-23 12:20:33 +00:00
xue_meng_en 96dad83a1d 修复wal2json插件编译时报logical.h文件中的DefElem类型未声明的错误 2022-05-23 17:27:49 +08:00
opengauss-bot d433ee097a
!1746 Masstree OOM feature
Merge pull request !1746 from Vinoth Veeraraghavan/master
2022-05-23 03:32:46 +00:00
ganyang a590e0b47f add alter procedure helper note 2022-05-23 11:00:17 +08:00
仲夏十三 7f8b900e69 Merge branch 'master' of gitee.com:opengauss/openGauss-server into helper 2022-05-20 07:40:19 +00:00
ganyang f14255f040 fix record type issue caused by composite datum 2022-05-20 15:38:19 +08:00
wuyuechuan 5af581f12a use `RetryDataFileIdOpenFile` to prevent the flags from being modified 2022-05-20 11:57:25 +08:00
Vinoth Veeraraghavan 26793e3bf2 Masstree out of memory feature:
1. Fix RCU bug in masstree (GC layer removal flow)
    2. Support pool allocation failure in masstree
    3. Add new masstree API changes
2022-05-20 10:46:52 +08:00
wuyuechuan dbcf479205 set compressByteConvert/compressDiffConvert to true when defElem is set to true 2022-05-18 14:41:15 +08:00
opengauss-bot ae11cad2c3
!1738 修复\h drop table 查看语法帮助显示语法错误
Merge pull request !1738 from 仲夏十三/helper
2022-05-17 09:50:24 +00:00
ganyang 57bc5c4a37 fix helper note 2022-05-17 10:22:29 +08:00
opengauss-bot fb449157d0
!1710 修复join结果不正确的bug
Merge pull request !1710 from Cross-罗/join_alias
2022-05-16 07:21:34 +00:00
opengauss-bot 6c5898646e
!1726 修复视图中包含自定义操作符时,获取视图定义失败的问题
Merge pull request !1726 from pengjiong/logical_core
2022-05-13 09:11:34 +00:00
TotaJ c1335bebc9 Fix deserialize func and view. 2022-05-13 14:55:39 +08:00
opengauss-bot b2c6e04eab
!1725 重命名b_sql_plugin
Merge pull request !1725 from 仲夏十三/dolphin
2022-05-12 08:34:58 +00:00
ganyang 16d32d3978 rename b_sql_plugin 2022-05-12 14:30:24 +08:00
opengauss-bot 3e14e85fdf
!1698 添加对asianux平台支持
Merge pull request !1698 from zhangminjie/master
2022-05-10 07:35:19 +00:00
opengauss-bot 438bba32ff
!1705 修复 master 分支 和 3.0.0 分支创建 postgis_raster 扩展失败问题
Merge pull request !1705 from sungwu/master
2022-05-10 06:07:23 +00:00
opengauss-bot d82eba4790
!1721 【bugfix】修复interval分区exchange失败的问题
Merge pull request !1721 from cchen676/master1
2022-05-10 02:19:45 +00:00
arcoalien@qq.com 4b7080c8ef [回合主线]fix bug interval分区exchange失败 2022-05-09 20:55:12 +08:00
zhangminjie1997 5e1d9b79f6 添加对asianux平台支持 2022-05-09 11:40:22 +08:00
opengauss-bot 51c355c7b6
!1699 fix core of function pg_create_physical_replication_slot_extern
Merge pull request !1699 from 胡正超/repslot
2022-05-09 02:48:37 +00:00
luozihao 4c0a495a18 fixed the bug of join 2022-05-05 09:45:50 +08:00
wusong cbb8fd609b fix #I51OZS 修复在扩展中无法调用已创建函数问题,sort_candidate_func_list 函数实现 bug 2022-04-27 20:15:23 +08:00
opengauss-bot 475170ca0c
!1703 修复plpgsql在使用b_sql_plugin插件的情况下没有正确使用插件语法解析器的bug
Merge pull request !1703 from Cross-罗/plpgsql
2022-04-27 11:01:46 +00:00
l00584793 7f9a1f5428 Fix the bug that the pgplsql invokes the syntax parser error. 2022-04-27 16:35:38 +08:00
opengauss-bot c04e377cdc
!1701 修复升级后subbinary为空导致发布订阅报错问题
Merge pull request !1701 from 薛蒙恩/pubsub_bnrupg
2022-04-27 02:08:51 +00:00
opengauss-bot 6380ca0f4d
!1702 修复分区表issue
Merge pull request !1702 from 仲夏十三/333
2022-04-26 12:43:21 +00:00
kidhasdream 4898f04a3c change fastcheck 2022-04-26 20:06:11 +08:00
ganyang 11a1a5c9ad fix partition error 2022-04-26 19:15:23 +08:00
opengauss-bot a30ae9d5ad
!1700 修复ustore二级分区以及生成列场景下,发布订阅数据同步失败的问题
Merge pull request !1700 from pengjiong/logical_core
2022-04-26 07:24:18 +00:00
xue_meng_en 0b70c7ab70 修复升级后subbinary为空导致发布订阅报错问题 2022-04-26 11:29:41 +08:00
TotaJ f719422916 Fix ustore bug in publication. 2022-04-26 09:35:24 +08:00
opengauss-bot 88dcc7f99e
!1697 修复由于CurrentResourceOwner为NULL导致的逻辑解码core问题
Merge pull request !1697 from pengjiong/logical_core
2022-04-25 11:59:17 +00:00
gentle_hu dbd9958443 fix core of function pg_create_physical_replication_slot_extern 2022-04-25 19:09:58 +08:00
TotaJ 38b5a0ac95 Fix logical decode core. 2022-04-25 17:48:53 +08:00
opengauss-bot a548f5c3c6
!1675 修复发布订阅死锁问题
Merge pull request !1675 from 薛蒙恩/pubsub_deadlock
2022-04-24 01:53:42 +00:00
opengauss-bot eb4e54d4eb
!1678 openGauss 发布订阅支持gs_probackup备份恢复后连接不断开
Merge pull request !1678 from chenxiaobin/probackup
2022-04-22 02:42:08 +00:00
chenxiaobin19 3f7a909887 gs_probackup支持备份发布订阅的逻辑复制槽 2022-04-18 20:56:52 +08:00
xue_meng_en d8b89ceea5 修复发布订阅死锁问题 2022-04-16 19:34:20 +08:00
opengauss-bot 2250adfd4b
!1671 Implementing Monte Carlo Tree Search Algorithm
Merge pull request !1671 from liuly/master
2022-04-15 07:36:01 +00:00
flyly fd34b5da2a Implementing Monte Carlo Tree Search Algorithm 2022-04-14 17:11:09 +08:00
opengauss-bot 7f97d633f1
!1665 发布订阅支持以二进制格式发送数据和发布端主备切换不断开
Merge pull request !1665 from 薛蒙恩/pubsub330
2022-04-12 01:32:52 +00:00
opengauss-bot 6ba4c95f5f
!1666 修复enable_global_syscache关闭时连接B兼容性数据库的core问题
Merge pull request !1666 from chenxiaobin/fixbcore
2022-04-11 11:10:58 +00:00
xue_meng_en 5755feee5d 发布订阅支持主备切换不断开 2022-04-11 10:14:20 +08:00
opengauss-bot cd5d44d66c
!1668 gs_ctl添加-C参数适配流式容灾
Merge pull request !1668 from zhangxubo/master
2022-04-08 08:37:04 +00:00
zhang_xubo 2d657cddbe 添加参数适配流式容灾 2022-04-08 15:13:35 +08:00
chenxiaobin19 ccd674c159 修复enable_global_syscache关闭时连接B兼容性数据库的core问题 2022-04-08 11:11:07 +08:00
xue_meng_en 8292238381 发布订阅支持以二进制格式发送数据 2022-04-07 11:08:45 +08:00
opengauss-bot 5054ddd002
!1661 修复sql插件切换数据库插件依然存在
Merge pull request !1661 from 仲夏十三/bb0aa02e
2022-04-06 08:26:34 +00:00
ganyang 48a5033c18 fix space error 2022-04-06 10:32:10 +08:00
ganyang 811a9afcd9 optimize judgement 2022-04-02 16:44:36 +08:00
ganyang bb0aa02eb0 fix plugin hook issue 2022-04-02 15:01:58 +08:00
96 changed files with 2434 additions and 437 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) platform."
echo "We only support openEuler(aarch64), EulerOS(aarch64), CentOS, Kylin(aarch64), Asianux platform."
exit 1;
fi
@ -96,16 +96,21 @@ elif [[ "$PLAT_FORM_STR" =~ "kylin" ]]; then
if [ "$PLATFORM_ARCH"X == "aarch64"X ];then
GAUSSDB_EXTRA_FLAGS=" -D__USE_NUMA"
fi
elif [[ "$PLAT_FORM_STR" =~ "asianux" ]]; then
dist_version="Asianux"
if [ "$PLATFORM_ARCH"X == "aarch64"X ];then
GAUSSDB_EXTRA_FLAGS=" -D__USE_NUMA"
fi
else
echo "We only support openEuler(aarch64), EulerOS(aarch64), CentOS, Kylin(aarch64) platform."
echo "We only support openEuler(aarch64), EulerOS(aarch64), CentOS, Kylin(aarch64), Asianux platform."
echo "Kernel is $kernel"
exit 1
fi
##add platform architecture information
if [ "$PLATFORM_ARCH"X == "aarch64"X ] ; then
if [ "$dist_version" != "openEuler" ] && [ "$dist_version" != "EulerOS" ] && [ "$dist_version" != "Kylin" ] ; then
echo "We only support NUMA on openEuler(aarch64), EulerOS(aarch64), Kylin(aarch64) platform."
if [ "$dist_version" != "openEuler" ] && [ "$dist_version" != "EulerOS" ] && [ "$dist_version" != "Kylin" ] && [ "$dist_version" != "Asianux" ]; then
echo "We only support NUMA on openEuler(aarch64), EulerOS(aarch64), Kylin(aarch64), Asianux platform."
exit 1
fi
fi

View File

@ -26,6 +26,7 @@ Complete list of usable sgml source files in this directory.
<!ENTITY alterOperator SYSTEM "alter_operator.sgml">
<!ENTITY alterOperatorClass SYSTEM "alter_opclass.sgml">
<!ENTITY alterOperatorFamily SYSTEM "alter_opfamily.sgml">
<!ENTITY alterProcedure SYSTEM "alter_procedure.sgml">
<!ENTITY alterRole SYSTEM "alter_role.sgml">
<!ENTITY alterSchema SYSTEM "alter_schema.sgml">
<!ENTITY alterServer SYSTEM "alter_server.sgml">

View File

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

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

@ -5923,7 +5923,7 @@ int main(int argc, char** argv)
&option_index)) != -1)
#endif
#else
while ((c = getopt_long(argc, argv, "b:cD:e:fi:G:l:m:M:N:o:O:p:P:r:R:v:x:sS:t:u:U:wWZ:dqL:T:Q:", long_options,
while ((c = getopt_long(argc, argv, "b:cD:e:fi:G:l:m:M:N:o:O:p:P:r:R:v:x:sS:t:u:U:wWZ:C:dqL:T:Q:", long_options,
&option_index)) != -1)
#endif
#endif

View File

@ -233,6 +233,7 @@ char* all_data_nodename_list = NULL;
const uint32 USTORE_UPGRADE_VERSION = 92368;
const uint32 PACKAGE_ENHANCEMENT = 92444;
const uint32 SUBSCRIPTION_VERSION = 92580;
const uint32 SUBSCRIPTION_BINARY_VERSION_NUM = 92606;
#ifdef DUMPSYSLOG
char* syslogpath = NULL;
@ -4444,23 +4445,16 @@ void getSubscriptions(Archive *fout)
int i_subslotname;
int i_subsynccommit;
int i_subpublications;
int i, ntups;
int i_subbinary;
int i;
int ntups;
if (no_subscriptions || GetVersionNum(fout) < SUBSCRIPTION_VERSION) {
return;
}
if (!isExecUserSuperRole(fout)) {
res = ExecuteSqlQuery(fout,
"SELECT count(*) FROM pg_subscription "
"WHERE subdbid = (SELECT oid FROM pg_catalog.pg_database"
" WHERE datname = current_database())",
PGRES_TUPLES_OK);
uint64 n = (res != NULL) ? strtoul(PQgetvalue(res, 0, 0), NULL, 10) : 0;
if (n > 0) {
write_msg(NULL, "WARNING: subscriptions not dumped because current user is not a superuser\n");
}
PQclear(res);
write_msg(NULL, "WARNING: subscriptions not dumped because current user is not a superuser\n");
return;
}
@ -4469,14 +4463,20 @@ 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 "
"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, \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 "
"WHERE s.subdbid = (SELECT oid FROM pg_catalog.pg_database"
" WHERE datname = current_database())",
username_subquery);
" WHERE datname = current_database())");
res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
ntups = PQntuples(res);
@ -4494,6 +4494,7 @@ 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));
@ -4512,6 +4513,7 @@ 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);
@ -4578,6 +4580,10 @@ 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));
}
@ -10780,6 +10786,11 @@ static void dumpDirectory(Archive* fout)
char* dirpath = NULL;
char* diracl = NULL;
if (!isExecUserSuperRole(fout)) {
write_msg(NULL, "WARNING: directory not dumped because current user is not a superuser\n");
return;
}
/* Make sure we are in proper schema */
selectSourceSchema(fout, "pg_catalog");
@ -21389,6 +21400,11 @@ static void dumpSynonym(Archive* fout)
PQExpBuffer q;
PQExpBuffer delq;
if (!isExecUserSuperRole(fout)) {
write_msg(NULL, "WARNING: synonym not dumped because current user is not a superuser\n");
return;
}
selectSourceSchema(fout, "pg_catalog");
query = createPQExpBuffer();
printfPQExpBuffer(query,

View File

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

View File

@ -31,6 +31,9 @@
it will be backuped up in external dirs */
parray *pgdata_nobackup_dir = NULL;
/* list of logical replication slots */
parray *logical_replslot = NULL;
static int standby_message_timeout_local = 10 ; /* 10 sec = default */
static XLogRecPtr stop_backup_lsn = InvalidXLogRecPtr;
static XLogRecPtr stop_stream_lsn = InvalidXLogRecPtr;
@ -89,10 +92,11 @@ static void backup_cleanup(bool fatal, void *userdata);
static void *backup_files(void *arg);
static void do_backup_instance(PGconn *backup_conn, PGNodeInfo *nodeInfo, bool no_sync, bool backup_logs);
static void do_backup_instance(PGconn *backup_conn, PGNodeInfo *nodeInfo, bool no_sync, bool backup_logs,
bool backup_replslots);
static void pg_start_backup(const char *label, bool smooth, pgBackup *backup,
PGNodeInfo *nodeInfo, PGconn *conn);
PGNodeInfo *nodeInfo, PGconn *conn, bool backup_replslots);
static void pg_stop_backup(pgBackup *backup, PGconn *pg_startbackup_conn, PGNodeInfo *nodeInfo);
static int checkpoint_timeout(PGconn *backup_conn);
@ -558,7 +562,7 @@ static void sync_files(parray *database_map, const char *database_path, parray *
* Move files from 'pgdata' to a subdirectory in 'backup_path'.
*/
static void
do_backup_instance(PGconn *backup_conn, PGNodeInfo *nodeInfo, bool no_sync, bool backup_logs)
do_backup_instance(PGconn *backup_conn, PGNodeInfo *nodeInfo, bool no_sync, bool backup_logs, bool backup_replslots)
{
int i;
char database_path[MAXPGPATH];
@ -591,7 +595,7 @@ do_backup_instance(PGconn *backup_conn, PGNodeInfo *nodeInfo, bool no_sync, bool
securec_check_c(rc, "\0", "\0");
/* Call pg_start_backup function in openGauss connect */
pg_start_backup(label, smooth_checkpoint, &current, nodeInfo, backup_conn);
pg_start_backup(label, smooth_checkpoint, &current, nodeInfo, backup_conn, backup_replslots);
/* Obtain current timeline */
#if PG_VERSION_NUM >= 90600
@ -624,10 +628,10 @@ do_backup_instance(PGconn *backup_conn, PGNodeInfo *nodeInfo, bool no_sync, bool
/* list files with the logical path. omit $PGDATA */
if (fio_is_remote(FIO_DB_HOST))
fio_list_dir(backup_files_list, instance_config.pgdata,
true, true, false, backup_logs, true, 0);
true, true, false, backup_logs, true, 0, backup_replslots);
else
dir_list_file(backup_files_list, instance_config.pgdata,
true, true, false, backup_logs, true, 0, FIO_LOCAL_HOST);
true, true, false, backup_logs, true, 0, FIO_LOCAL_HOST, backup_replslots);
/*
* Get database_map (name to oid) for use in partial restore feature.
@ -749,6 +753,11 @@ do_backup_instance(PGconn *backup_conn, PGNodeInfo *nodeInfo, bool no_sync, bool
}
pgdata_nobackup_dir = NULL;
if (logical_replslot) {
free_dir_list(logical_replslot);
}
logical_replslot = NULL;
/* Cleanup */
if (backup_list)
{
@ -849,7 +858,7 @@ static void do_after_backup()
*/
int
do_backup(time_t start_time, pgSetBackupParams *set_backup_params,
bool no_validate, bool no_sync, bool backup_logs)
bool no_validate, bool no_sync, bool backup_logs, bool backup_replslots)
{
PGconn *backup_conn = NULL;
PGNodeInfo nodeInfo;
@ -925,7 +934,7 @@ do_backup(time_t start_time, pgSetBackupParams *set_backup_params,
add_note(&current, set_backup_params->note);
/* backup data */
do_backup_instance(backup_conn, &nodeInfo, no_sync, backup_logs);
do_backup_instance(backup_conn, &nodeInfo, no_sync, backup_logs, backup_replslots);
pgut_atexit_pop(backup_cleanup, NULL);
/* compute size of wal files of this backup stored in the archive */
@ -1034,13 +1043,15 @@ confirm_block_size(PGconn *conn, const char *name, int blcksz)
*/
static void
pg_start_backup(const char *label, bool smooth, pgBackup *backup,
PGNodeInfo *nodeInfo, PGconn *conn)
PGNodeInfo *nodeInfo, PGconn *conn, bool backup_replslots)
{
PGresult *res;
const char *params[2];
uint32 lsn_hi;
uint32 lsn_lo;
int ret;
int i;
XLogRecPtr startLsn;
params[0] = label;
@ -1068,7 +1079,33 @@ pg_start_backup(const char *label, bool smooth, pgBackup *backup,
XLogDataFromLSN(ret, PQgetvalue(res, 0, 0), &lsn_hi, &lsn_lo);
securec_check_for_sscanf_s(ret, 2, "\0", "\0");
/* Calculate LSN */
backup->start_lsn = ((uint64) lsn_hi )<< 32 | lsn_lo;
startLsn = ((uint64) lsn_hi )<< 32 | lsn_lo;
if (backup_replslots) {
logical_replslot = parray_new();
/* query for logical replication slots of subscriptions */
res = pgut_execute(conn,
"SELECT slot_name, restart_lsn FROM pg_catalog.pg_get_replication_slots()"
"WHERE slot_type = 'logical' AND plugin = 'pgoutput'", 0, NULL);
if (PQntuples(res) == 0) {
elog(LOG, "logical replication slots for subscriptions not found");
} else {
XLogRecPtr repslotLsn;
for (i = 0; i < PQntuples(res); i++) {
XLogDataFromLSN(ret, PQgetvalue(res, i, 1), &lsn_hi, &lsn_lo);
securec_check_for_sscanf_s(ret, 2, "\0", "\0");
repslotLsn = ((uint64) lsn_hi )<< 32 | lsn_lo;
startLsn = Min(startLsn, repslotLsn);
char* slotname = pg_strdup(PQgetvalue(res, i, 0));
parray_append(logical_replslot, slotname);
}
elog(WARNING, "logical replication slots for subscriptions will be backed up. "
"If don't use them after restoring, please drop them to avoid affecting xlog recycling.");
}
}
backup->start_lsn = startLsn;
PQclear(res);
}

View File

@ -42,13 +42,6 @@ const char *pgdata_exclude_dir[] =
(const char *)"pg_stat_tmp",
(const char *)"pgsql_tmp",
/*
* It is generally not useful to backup the contents of this directory even
* if the intention is to restore to another master. See backup.sgml for a
* more detailed description.
*/
(const char *)"pg_replslot",
/* Contents removed on startup, see dsm_cleanup_for_mmap(). */
(const char *)"pg_dynshmem",
@ -68,7 +61,7 @@ const char *pgdata_exclude_dir[] =
(const char *)"pg_subtrans",
/* end of list */
NULL, /* pg_log will be set later */
NULL, /* pg_log and pg_replslot will be set later */
NULL
};
@ -128,17 +121,20 @@ may be removed int the future */
static int pgCompareString(const void *str1, const void *str2);
static char dir_check_file(pgFile *file, bool backup_logs);
static char dir_check_file(pgFile *file, bool backup_logs, bool backup_replslots);
static char check_in_tablespace(pgFile *file, bool in_tablespace);
static char check_db_dir(pgFile *file);
static char check_digit_file(pgFile *file);
static char check_nobackup_dir(pgFile *file);
static void dir_list_file_internal(parray *files, pgFile *parent, const char *parent_dir,
bool exclude, bool follow_symlink, bool backup_logs,
bool skip_hidden, int external_dir_num, fio_location location);
bool skip_hidden, int external_dir_num, fio_location location,
bool backup_replslots);
static void opt_path_map(ConfigOption *opt, const char *arg,
TablespaceList *list, const char *type);
char check_logical_replslot_dir(const char *rel_path);
/* Tablespace mapping */
static TablespaceList tablespace_dirs = {NULL, NULL};
/* Extra directories mapping */
@ -538,7 +534,7 @@ db_map_entry_free(void *entry)
void
dir_list_file(parray *files, const char *root, bool exclude, bool follow_symlink,
bool add_root, bool backup_logs, bool skip_hidden, int external_dir_num,
fio_location location)
fio_location location, bool backup_replslots)
{
pgFile *file;
@ -565,7 +561,7 @@ dir_list_file(parray *files, const char *root, bool exclude, bool follow_symlink
parray_append(files, file);
dir_list_file_internal(files, file, root, exclude, follow_symlink,
backup_logs, skip_hidden, external_dir_num, location);
backup_logs, skip_hidden, external_dir_num, location, backup_replslots);
if (!add_root)
pgFileFree(file);
@ -589,7 +585,7 @@ dir_list_file(parray *files, const char *root, bool exclude, bool follow_symlink
* - datafiles
*/
static char
dir_check_file(pgFile *file, bool backup_logs)
dir_check_file(pgFile *file, bool backup_logs, bool backup_replslots)
{
int i;
int sscanf_res;
@ -652,6 +648,29 @@ dir_check_file(pgFile *file, bool backup_logs)
}
}
/*
* Backup pg_replslot if it is specified.
* It is generally not useful to backup the contents of this directory even
* if the intention is to restore to another master. See backup.sgml for a
* more detailed description.
*/
if (!backup_replslots) {
if (strcmp(file->rel_path, PG_REPLSLOT_DIR) == 0) {
/* Skip */
elog(VERBOSE, "Excluding directory content: %s", file->rel_path);
return CHECK_EXCLUDE_FALSE;
}
} else {
/*
* Check file that under pg_replslot and judge whether it
* belonged to logical replication slots for subscriptions.
*/
if (strcmp(file->rel_path, PG_REPLSLOT_DIR) != 0 &&
path_is_prefix_of_path(PG_REPLSLOT_DIR, file->rel_path)) {
return check_logical_replslot_dir(file->rel_path);
}
}
ret = check_nobackup_dir(file);
if (ret != -1) { /* -1 means need backup */
return ret;
@ -749,6 +768,35 @@ static char check_nobackup_dir(pgFile *file)
return ret;
}
char check_logical_replslot_dir(const char *rel_path)
{
char ret = CHECK_FALSE;
int i = 0;
char *tmp = pg_strdup(rel_path);
char *p;
#define DIRECTORY_DELIMITER "/"
if (logical_replslot) {
/* extract slot name from rel_path, such as sub1 from pg_replslot/sub1/snap */
p = strtok(tmp, DIRECTORY_DELIMITER);
if (p != NULL) {
p = strtok(NULL, DIRECTORY_DELIMITER);
}
for (i = 0; p != NULL && i < (int)parray_num(logical_replslot); i++) {
char *slotName = (char *)parray_get(logical_replslot, i);
if (strcmp(p, slotName) == 0) {
pfree(tmp);
return CHECK_TRUE;
}
}
} else {
ret = CHECK_TRUE;
}
pfree(tmp);
return ret;
}
static char check_db_dir(pgFile *file)
{
char ret = -1;
@ -889,7 +937,8 @@ bool SkipSomeDirFile(pgFile *file, struct dirent *dent, bool skipHidden)
static void
dir_list_file_internal(parray *files, pgFile *parent, const char *parent_dir,
bool exclude, bool follow_symlink, bool backup_logs,
bool skip_hidden, int external_dir_num, fio_location location)
bool skip_hidden, int external_dir_num, fio_location location,
bool backup_replslots)
{
DIR *dir;
struct dirent *dent;
@ -937,7 +986,7 @@ dir_list_file_internal(parray *files, pgFile *parent, const char *parent_dir,
if (exclude)
{
check_res = dir_check_file(file, backup_logs);
check_res = dir_check_file(file, backup_logs, backup_replslots);
if (check_res == CHECK_FALSE)
{
/* Skip */
@ -963,7 +1012,7 @@ dir_list_file_internal(parray *files, pgFile *parent, const char *parent_dir,
*/
if (S_ISDIR(file->mode))
dir_list_file_internal(files, file, child, exclude, follow_symlink,
backup_logs, skip_hidden, external_dir_num, location);
backup_logs, skip_hidden, external_dir_num, location, backup_replslots);
}
if (errno && errno != ENOENT)

View File

@ -51,6 +51,7 @@ typedef struct
bool exclusive_backup;
bool skip_hidden;
int external_dir_num;
bool backup_replslots;
} fio_list_dir_request;
typedef struct
@ -1794,7 +1795,7 @@ cleanup:
/* Compile the array of files located on remote machine in directory root */
void fio_list_dir(parray *files, const char *root, bool exclude,
bool follow_symlink, bool add_root, bool backup_logs,
bool skip_hidden, int external_dir_num)
bool skip_hidden, int external_dir_num, bool backup_replslots)
{
fio_header hdr;
fio_list_dir_request req;
@ -1811,6 +1812,7 @@ void fio_list_dir(parray *files, const char *root, bool exclude,
req.exclusive_backup = exclusive_backup;
req.skip_hidden = skip_hidden;
req.external_dir_num = external_dir_num;
req.backup_replslots = backup_replslots;
hdr.cop = FIO_LIST_DIR;
hdr.size = sizeof(req);
@ -1870,7 +1872,14 @@ void fio_list_dir(parray *files, const char *root, bool exclude,
securec_check_ss_c(nRet, "\0", "\0");
}
/*
* Check file that under pg_replslot and judge whether it
* belonged to logical replication slots for subscriptions.
*/
if (backup_replslots && strcmp(buf, PG_REPLSLOT_DIR) != 0 &&
path_is_prefix_of_path(PG_REPLSLOT_DIR, buf) && check_logical_replslot_dir(file->rel_path) != 1) {
continue;
}
parray_append(files, file);
}
@ -1914,7 +1923,7 @@ static void fio_list_dir_impl(int out, char* buf)
dir_list_file(file_files, req->path, req->exclude, req->follow_symlink,
req->add_root, req->backup_logs, req->skip_hidden,
req->external_dir_num, FIO_LOCAL_HOST);
req->external_dir_num, FIO_LOCAL_HOST, req->backup_replslots);
/* send information about files to the main process */
for (i = 0; i < (int)parray_num(file_files); i++)

View File

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

View File

@ -154,6 +154,7 @@ void help_pg_probackup(void)
printf(_(" [--remote-port=port] [--ssh-options=ssh_options]\n"));
printf(_(" [--remote-libpath=libpath]\n"));
printf(_(" [--ttl=interval] [--expire-time=time]\n"));
printf(_(" [--backup-pg-replslot]\n"));
printf(_(" [--help]\n"));
printf(_("\n %s restore -B backup-path --instance=instance_name\n"), PROGRAM_NAME);
@ -420,6 +421,7 @@ static void help_backup(void)
printf(_(" [--remote-port=port] [--ssh-options=ssh_options]\n"));
printf(_(" [--remote-libpath=libpath]\n"));
printf(_(" [--ttl=interval] [--expire-time=time]\n\n"));
printf(_(" [--backup-pg-replslot]\n"));
printf(_(" -B, --backup-path=backup-path location of the backup storage area\n"));
printf(_(" --instance=instance_name name of the instance\n"));
@ -441,6 +443,7 @@ static void help_backup(void)
printf(_(" --note=text add note to backup\n"));
printf(_(" (example: --note='backup before app update to v13.1')\n"));
printf(_(" --archive-timeout=timeout wait timeout for WAL segment archiving (default: 5min)\n"));
printf(_(" --backup-pg-replslot] backup of '%s' directory\n"), PG_REPLSLOT_DIR);
printf(_("\n Logging options:\n"));
printf(_(" --log-level-console=log-level-console\n"));

View File

@ -77,6 +77,7 @@ int rw_timeout = 0;
/* backup options */
bool backup_logs = false;
bool backup_replslots = false;
bool smooth_checkpoint;
char *remote_agent;
static char *backup_note = NULL;
@ -186,6 +187,7 @@ static ConfigOption cmd_options[] =
{ 'b', 145, "wal", &delete_wal, SOURCE_CMD_STRICT },
{ 'b', 146, "expired", &delete_expired, SOURCE_CMD_STRICT },
{ 's', 172, "status", &delete_status, SOURCE_CMD_STRICT },
{ 'b', 186, "backup-pg-replslot", &backup_replslots, SOURCE_CMD_STRICT},
{ 'b', 147, "force", &force, SOURCE_CMD_STRICT },
{ 'b', 148, "compress", &compress_shortcut, SOURCE_CMD_STRICT },
@ -550,7 +552,7 @@ static int do_actual_operate()
elog(ERROR, "required parameter not specified: BACKUP_MODE "
"(-b, --backup-mode)");
return do_backup(start_time, set_backup_params, no_validate, no_sync, backup_logs);
return do_backup(start_time, set_backup_params, no_validate, no_sync, backup_logs, backup_replslots);
}
case RESTORE_CMD:
return do_restore_or_validate(current.backup_id,

View File

@ -69,6 +69,7 @@ extern const char *PROGRAM_FULL_PATH;
#define HEADER_MAP "page_header_map"
#define HEADER_MAP_TMP "page_header_map_tmp"
#define PG_RELATIVE_TBLSPC_DIR "pg_location"
#define PG_REPLSLOT_DIR "pg_replslot"
/* Timeout defaults */
#define ARCHIVE_TIMEOUT_DEFAULT 300

View File

@ -54,6 +54,9 @@ extern bool smooth_checkpoint;
it will be backuped up in external dirs */
extern parray *pgdata_nobackup_dir;
/* list of logical replication slots */
extern parray *logical_replslot;
/* remote probackup options */
extern char* remote_agent;
@ -89,7 +92,7 @@ extern const char *pgdata_exclude_dir[];
/* in backup.c */
extern int do_backup(time_t start_time, pgSetBackupParams *set_backup_params,
bool no_validate, bool no_sync, bool backup_logs);
bool no_validate, bool no_sync, bool backup_logs, bool backup_replslots);
extern BackupMode parse_backup_mode(const char *value);
extern const char *deparse_backup_mode(BackupMode mode);
extern void process_block_change(ForkNumber forknum, const RelFileNode rnode,
@ -239,7 +242,8 @@ extern const char* deparse_compress_alg(int alg);
/* in dir.c */
extern void dir_list_file(parray *files, const char *root, bool exclude,
bool follow_symlink, bool add_root, bool backup_logs,
bool skip_hidden, int external_dir_num, fio_location location);
bool skip_hidden, int external_dir_num, fio_location location,
bool backup_replslots = false);
extern void create_data_directories(parray *dest_files,
const char *data_dir,
@ -432,7 +436,8 @@ extern int fio_send_file(const char *from_fullpath, const char *to_fullpath, FIL
pgFile *file, char **errormsg);
extern void fio_list_dir(parray *files, const char *root, bool exclude, bool follow_symlink,
bool add_root, bool backup_logs, bool skip_hidden, int external_dir_num);
bool add_root, bool backup_logs, bool skip_hidden, int external_dir_num,
bool backup_replslots = false);
extern bool pgut_rmtree(const char *path, bool rmtopdir, bool strict);

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)
Oid AddNewIntervalPartition(Relation rel, void* insertTuple, bool isDDL)
{
Relation pgPartRel = NULL;
Oid newPartOid = InvalidOid;
@ -6327,7 +6327,13 @@ Oid AddNewIntervalPartition(Relation rel, void* insertTuple)
*/
CommandCounterIncrement();
UpdatePgObjectChangecsn(RelationGetRelid(rel), rel->rd_rel->relkind);
/*
* If add interval partition in the DDL, do not need to change the csn
* because the scn has been changed in the DDL.
*/
if (!isDDL) {
UpdatePgObjectChangecsn(RelationGetRelid(rel), rel->rd_rel->relkind);
}
return newPartOid;
}
@ -7113,7 +7119,7 @@ int lookupHBucketid(oidvector *buckets, int low, int2 bktId)
* Description :
* Notes :
*/
Oid heapTupleGetPartitionId(Relation rel, void *tuple)
Oid heapTupleGetPartitionId(Relation rel, void *tuple, bool isDDL)
{
Oid partitionid = InvalidOid;
@ -7140,7 +7146,7 @@ Oid heapTupleGetPartitionId(Relation rel, void *tuple)
(errcode(ERRCODE_NO_DATA_FOUND), errmsg("inserted partition key does not map to any table partition")));
} break;
case PART_AREA_INTERVAL: {
return AddNewIntervalPartition(rel, tuple);
return AddNewIntervalPartition(rel, tuple, isDDL);
} break;
case PART_AREA_LIST: {
ereport(ERROR,

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 b_sql_plugin */
/* for dolphin */
struct HTAB* b_nameHash = NULL;
struct HTAB* b_oidHash = NULL;
@ -118,7 +118,7 @@ static const FuncGroup* NameHashTableAccess(HASHACTION action, const char* name,
Assert(name != NULL);
if (DB_IS_CMPT(B_FORMAT) && b_nameHash != NULL && u_sess->attr.attr_sql.b_sql_plugin) {
if (DB_IS_CMPT(B_FORMAT) && b_nameHash != NULL && u_sess->attr.attr_sql.dolphin) {
result = (HashEntryNameToFuncGroup *)hash_search(b_nameHash, &temp_name, action, &found);
} else {
result = (HashEntryNameToFuncGroup *)hash_search(nameHash, &temp_name, action, &found);
@ -144,7 +144,7 @@ static const Builtin_func* OidHashTableAccess(HASHACTION action, Oid oid, const
bool found = false;
Assert(oid > 0);
if (DB_IS_CMPT(B_FORMAT) && b_oidHash != NULL && u_sess->attr.attr_sql.b_sql_plugin) {
if (DB_IS_CMPT(B_FORMAT) && b_oidHash != NULL && u_sess->attr.attr_sql.dolphin) {
result = (HashEntryOidToBuiltinFunc *)hash_search(b_oidHash, &oid, action, &found);
} else {
result = (HashEntryOidToBuiltinFunc *)hash_search(oidHash, &oid, action, &found);

View File

@ -28,7 +28,6 @@
#include "utils/builtins.h"
#include "utils/fmgroids.h"
#include "utils/syscache.h"
#include "replication/worker_internal.h"
static List *textarray_to_stringlist(ArrayType *textarray);
@ -91,6 +90,13 @@ 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;
@ -183,7 +189,7 @@ char *get_subscription_name(Oid subid, bool missing_ok)
}
/* Clear the list content, only deal with DefElem and string content */
static void ClearListContent(List *list)
void ClearListContent(List *list)
{
ListCell *cell = NULL;
foreach(cell, list) {
@ -203,25 +209,6 @@ static 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

@ -70,6 +70,7 @@
THR_LOCAL bool skip_read_extern_fields = false;
#define IS_DATANODE_BUT_NOT_SINGLENODE (IS_PGXC_DATANODE && !IS_SINGLE_NODE)
/*
* Macros to simplify reading of different kinds of fields. Use these
* wherever possible to reduce the chance for silly typos. Note that these
@ -401,24 +402,27 @@ THR_LOCAL bool skip_read_extern_fields = false;
token = pg_strtok(&length); /* skip :fldname */ \
local_node->fldname = _readBitmapset()
#define READ_TYPEINFO_FIELD(fldname) \
do { \
if (local_node->fldname >= FirstBootstrapObjectId) { \
IF_EXIST(exprtypename) \
{ \
char* exprtypename = NULL; \
char* exprtypenamespace = NULL; \
token = pg_strtok(&length); \
token = pg_strtok(&length); \
exprtypename = nullable_string(token, length); \
token = pg_strtok(&length); \
token = pg_strtok(&length); \
exprtypenamespace = nullable_string(token, length); \
local_node->fldname = get_typeoid(get_namespace_oid(exprtypenamespace, false), exprtypename); \
pfree_ext(exprtypename); \
pfree_ext(exprtypenamespace); \
} \
} \
#define READ_TYPEINFO_FIELD(fldname) \
do { \
if (local_node->fldname >= FirstBootstrapObjectId) { \
IF_EXIST(exprtypename) \
{ \
char* exprtypename = NULL; \
char* exprtypenamespace = NULL; \
token = pg_strtok(&length); \
token = pg_strtok(&length); \
exprtypename = nullable_string(token, length); \
token = pg_strtok(&length); \
token = pg_strtok(&length); \
exprtypenamespace = nullable_string(token, length); \
/* No need to reset field on CN or singlenode, keep pg_strtok() for forward compatibility */ \
if (IS_DATANODE_BUT_NOT_SINGLENODE) { \
local_node->fldname = get_typeoid(get_namespace_oid(exprtypenamespace, false), exprtypename); \
} \
pfree_ext(exprtypename); \
pfree_ext(exprtypenamespace); \
} \
} \
} while (0)
#define READ_TYPEINFO(typePtr) \
@ -493,9 +497,30 @@ THR_LOCAL bool skip_read_extern_fields = false;
token = pg_strtok(&length); \
token = pg_strtok(&length); \
funcnamespace = nullable_string(token, length); \
if (IS_PGXC_DATANODE && !skip_read_extern_fields) { \
local_node->fldname = \
get_func_oid(funcname, get_namespace_oid(funcnamespace, false), (Expr*)local_node); \
bool notfound = false; \
if (IS_DATANODE_BUT_NOT_SINGLENODE && !skip_read_extern_fields) { \
Oid funcoid = InvalidOid; \
do { \
Oid nspid = get_namespace_oid(funcnamespace, true); \
if (!OidIsValid(nspid)) { \
notfound = true; \
break; \
} \
funcoid = get_func_oid(funcname, nspid, (Expr*)local_node); \
} while (0); \
if (notfound || !OidIsValid(funcoid)) { \
ereport(ERROR, \
(errmodule(MOD_OPT), errcode(ERRCODE_UNDEFINED_OBJECT), \
errmsg("Cannot identify function %s.%s while deserializing field.", \
funcname, funcnamespace), \
errdetail("Function with oid %u or its namespace may be renamed", \
local_node->fldname), \
errhint("Please rebuild column defalt expression, views etc. that are" \
" related to this renamed object."), \
errcause("Object renamed after recorded as nodetree."), \
erraction("Rebuild relevant object."))); \
} \
local_node->fldname = funcoid; \
} \
pfree_ext(funcname); \
pfree_ext(funcnamespace); \
@ -525,7 +550,7 @@ THR_LOCAL bool skip_read_extern_fields = false;
token = pg_strtok(&length); \
token = pg_strtok(&length); \
oprrightname = nullable_string(token, length); \
if (IS_PGXC_DATANODE) { \
if (IS_DATANODE_BUT_NOT_SINGLENODE) { \
namespaceId = get_namespace_oid(opnamespace, false); \
oprleft = get_typeoid(namespaceId, oprleftname); \
oprright = oprleft; \
@ -568,7 +593,7 @@ THR_LOCAL bool skip_read_extern_fields = false;
token = pg_strtok(&length); \
token = pg_strtok(&length); \
oprrightname = nullable_string(token, length); \
if (IS_PGXC_DATANODE) { \
if (IS_DATANODE_BUT_NOT_SINGLENODE) { \
namespaceId = get_namespace_oid(opnamespace, false); \
oprleft = get_typeoid(namespaceId, oprleftname); \
oprright = oprleft; \
@ -2126,14 +2151,21 @@ static FuncExpr* _readFuncExpr(void)
ereport(ERROR, (errcode(ERRCODE_UNEXPECTED_NULL_VALUE), errmsg("NULL seqNamespace for nextval()")));
}
if (!IS_PGXC_COORDINATOR && !skip_read_extern_fields) {
Oid seqid = get_valid_relname_relid(seqNamespace, seqName);
if (IS_DATANODE_BUT_NOT_SINGLENODE && !skip_read_extern_fields) {
Oid seqid = get_valid_relname_relid(seqNamespace, seqName, true);
Const* firstArg = (Const*)linitial(local_node->args);
if (OidIsValid(seqid)) {
Const* firstArg = (Const*)linitial(local_node->args);
if (firstArg != NULL) {
firstArg->constvalue = ObjectIdGetDatum(seqid);
}
} else {
ereport(ERROR, (errmodule(MOD_OPT), errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("Cannot identify sequence %s.%s while deserializing field.", seqNamespace, seqName),
errdetail("Sequence with oid %u or its namespace may be renamed",
DatumGetObjectId(firstArg->constvalue)),
errhint("Please rebuild column defalt expression, views etc. that are related to this sequence"),
errcause("Object renamed after recorded as nodetree."), erraction("Rebuild relevant object.")));
}
}
pfree_ext(seqName);

View File

@ -1454,7 +1454,14 @@ FuncCandidateList sort_candidate_func_list(FuncCandidateList oldCandidates)
}
candidates[smallestIndex] = NULL;
}
for (int i = 0; i < size; i++) {
if (candidates[i] != NULL) {
lastCandidate->next = candidates[i];
lastCandidate = lastCandidate->next;
}
}
lastCandidate->next = NULL;
pfree(candidates);
return sortedCandidates;
}

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, rel_size);
pg_atomic_fetch_sub_u64(&m_base_space, AllocSetContextUsedSpace(((AllocSet)entry->rel_mem_manager)));
m_db_entry->MemoryEstimateSub(rel_size);
} else {
GlobalPartitionEntry *entry = (GlobalPartitionEntry *)base;
@ -77,7 +77,7 @@ void GlobalBaseDefCache::AddHeadToBucket(Index hash_index, GlobalBaseEntry *base
if (is_relation) {
GlobalRelationEntry *entry = (GlobalRelationEntry *)base;
uint64 rel_size = GetRelEstimateSize(entry);
pg_atomic_fetch_add_u64(&m_base_space, rel_size);
pg_atomic_fetch_add_u64(&m_base_space, AllocSetContextUsedSpace(((AllocSet)entry->rel_mem_manager)));
m_db_entry->MemoryEstimateAdd(rel_size);
} else {
GlobalPartitionEntry *entry = (GlobalPartitionEntry *)base;
@ -400,4 +400,4 @@ GlobalBaseDefCache::GlobalBaseDefCache(Oid db_oid, bool is_shared, GlobalSysDBCa
m_base_space = 0;
m_obj_locks = NULL;
m_db_entry = entry;
}
}

View File

@ -659,7 +659,27 @@ void GlobalSysDBCache::InitSysCacheRelIds()
*/
void GlobalSysDBCache::RefreshHotStandby()
{
if (!EnableGlobalSysCache()) {
return;
}
hot_standby = (t_thrd.postmaster_cxt.HaShmData->current_mode != STANDBY_MODE || XLogStandbyInfoActive());
if (hot_standby || !m_is_inited) {
return;
}
/* clean all */
for (int hash_index = 0; hash_index < m_nbuckets; hash_index ++) {
PthreadRWlockRdlock(LOCAL_SYSDB_RESOWNER, &m_db_locks[hash_index]);
for (Dlelem * elt = DLGetTail(m_bucket_list.GetBucket(hash_index)); elt != NULL;) {
GlobalSysDBCacheEntry *entry = (GlobalSysDBCacheEntry *)DLE_VAL(elt);
elt = DLGetPred(elt);
entry->ResetDBCache<true>();
}
PthreadRWlockUnlock(LOCAL_SYSDB_RESOWNER, &m_db_locks[hash_index]);
}
if (m_global_shared_db_entry != NULL) {
m_global_shared_db_entry->ResetDBCache<true>();
}
}
void GlobalSysDBCache::Init(MemoryContext parent)
@ -1272,9 +1292,18 @@ int ResizeHashBucket(int origin_nbucket, DynamicHashBucketStrategy strategy)
return cc_nbuckets;
}
void NotifyGscRecoveryStarted()
{
if (!EnableGlobalSysCache()) {
return;
}
g_instance.global_sysdbcache.recovery_finished = false;
}
void NotifyGscRecoveryFinished()
{
if (EnableGlobalSysCache()) {
g_instance.global_sysdbcache.recovery_finished = true;
}
}
}

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(!g_instance.global_sysdbcache.recovery_finished)) {
if (unlikely(!IsPrimaryRecoveryFinished())) {
return NULL;
}
uint32 hash_value = oid_hash((void *)&(part_oid), sizeof(Oid));
@ -165,7 +165,7 @@ static bool IsPartOidStoreInGlobal(Oid part_oid)
if (!g_instance.global_sysdbcache.hot_standby) {
return false;
}
if (unlikely(!g_instance.global_sysdbcache.recovery_finished)) {
if (unlikely(!IsPrimaryRecoveryFinished())) {
return false;
}
if (g_instance.global_sysdbcache.StopInsertGSC()) {
@ -456,4 +456,4 @@ Partition LocalPartDefCache::PartitionIdGetPartition(Oid part_oid, StorageType s
}
return pd;
}
}

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(!g_instance.global_sysdbcache.recovery_finished);
unlikely(!IsPrimaryRecoveryFinished());
if (invalid_entries.ExistTuple(hash_value) || bypass_gsc) {
global_ct = m_global_systupcache->SearchTupleFromFile(hash_value, arguments, true);
} else {
@ -585,7 +585,7 @@ LocalCatCList *LocalSysTupCache::SearchListFromGlobal(int nkeys, Datum *argument
bool bypass_gsc = HistoricSnapshotActive() ||
m_global_systupcache->enable_rls ||
!g_instance.global_sysdbcache.hot_standby ||
unlikely(!g_instance.global_sysdbcache.recovery_finished);
unlikely(!IsPrimaryRecoveryFinished());
GlobalCatCList *global_cl;
if (invalid_entries.ExistList() || bypass_gsc) {
global_cl = m_global_systupcache->SearchListFromFile(hash_value, nkeys, arguments, true);
@ -703,7 +703,7 @@ LocalCatCTup *LocalSysTupCache::SearchTupleFromGlobalForProcAllArgs(
bool bypass_gsc = HistoricSnapshotActive() ||
m_global_systupcache->enable_rls ||
!g_instance.global_sysdbcache.hot_standby ||
unlikely(!g_instance.global_sysdbcache.recovery_finished);
unlikely(!IsPrimaryRecoveryFinished());
if (invalid_entries.ExistTuple(hash_value) || bypass_gsc) {
global_ct = m_global_systupcache->SearchTupleFromFileWithArgModes(hash_value, arguments, argModes, true);
} else {

View File

@ -93,7 +93,7 @@ Relation LocalTabDefCache::SearchRelationFromGlobalCopy(Oid rel_oid)
if (!g_instance.global_sysdbcache.hot_standby) {
return NULL;
}
if (unlikely(!g_instance.global_sysdbcache.recovery_finished)) {
if (unlikely(!IsPrimaryRecoveryFinished())) {
return NULL;
}
uint32 hash_value = oid_hash((void *)&(rel_oid), sizeof(Oid));
@ -190,7 +190,7 @@ static bool IsRelOidStoreInGlobal(Oid rel_oid)
if (!g_instance.global_sysdbcache.hot_standby) {
return false;
}
if (unlikely(!g_instance.global_sysdbcache.recovery_finished)) {
if (unlikely(!IsPrimaryRecoveryFinished())) {
return false;
}
if (g_instance.global_sysdbcache.StopInsertGSC()) {
@ -1137,4 +1137,4 @@ void LocalTabDefCache::ResetInitFlag()
m_is_inited_phase3 = false;
m_db_id = InvalidOid;
}
}

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

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 = 92605;
const uint32 GRAND_VERSION_NUM = 92606;
const uint32 PREDPUSH_SAME_LEVEL_VERSION_NUM = 92522;
const uint32 UPSERT_WHERE_VERSION_NUM = 92514;
@ -101,6 +101,7 @@ const uint32 PRIVS_DIRECTORY_VERSION_NUM = 92460;
const uint32 COMMENT_RECORD_PARAM_VERSION_NUM = 92484;
const uint32 SCAN_BATCH_MODE_VERSION_NUM = 92568;
const uint32 PUBLICATION_VERSION_NUM = 92580;
const uint32 SUBSCRIPTION_BINARY_VERSION_NUM = 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* b_sql_plugin = "b_sql_plugin";
u_sess->attr.attr_sql.b_sql_plugin = CheckIfExtensionExists(b_sql_plugin);
const char* dolphin = "dolphin";
u_sess->attr.attr_sql.dolphin = CheckIfExtensionExists(dolphin);
}
void PostgresInitializer::FinishInit()

View File

@ -10340,7 +10340,16 @@ check_sql_expr(const char *stmt, int location, int leaderlen)
oldCxt = MemoryContextSwitchTo(u_sess->plsql_cxt.curr_compile_context->compile_tmp_cxt);
u_sess->plsql_cxt.plpgsql_yylloc = plpgsql_yylloc;
(void) raw_parser(stmt);
RawParserHook parser_hook= raw_parser;
#ifndef ENABLE_MULTIPLE_NODES
if (u_sess->attr.attr_sql.dolphin) {
int id = GetCustomParserId();
if (id >= 0 && g_instance.raw_parser_hook[id] != NULL) {
parser_hook = (RawParserHook)g_instance.raw_parser_hook[id];
}
}
#endif
(void)parser_hook(stmt, NULL);
MemoryContextSwitchTo(oldCxt);
/* Restore former ereport callback */

View File

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

View File

@ -26,9 +26,11 @@ import logging
try:
from .dao.gsql_execute import GSqlExecute
from .dao.execute_factory import ExecuteFactory
from .mcts import MCTS
except ImportError:
from dao.gsql_execute import GSqlExecute
from dao.execute_factory import ExecuteFactory
from mcts import MCTS
ENABLE_MULTI_NODE = False
SAMPLE_NUM = 5
@ -192,9 +194,12 @@ class IndexAdvisor:
self.workload_used_index))
if DRIVER:
self.db.close_conn()
opt_config = greedy_determine_opt_config(self.workload_info[0], atomic_config_total,
candidate_indexes, self.index_cost_total[0])
if MAX_INDEX_STORAGE:
opt_config = MCTS(self.workload_info[0], atomic_config_total, candidate_indexes,
MAX_INDEX_STORAGE, MAX_INDEX_NUM)
else:
opt_config = greedy_determine_opt_config(self.workload_info[0], atomic_config_total,
candidate_indexes, self.index_cost_total[0])
self.retain_lower_cost_index(candidate_indexes)
if len(opt_config) == 0:
print("No optimal indexes generated!")
@ -943,7 +948,7 @@ def check_parameter(args):
raise argparse.ArgumentTypeError("%s is an invalid positive int value" %
args.max_index_num)
if args.max_index_storage is not None and args.max_index_storage <= 0:
raise argparse.ArgumentTypeError("%s is an invalid positive int value" %
raise argparse.ArgumentTypeError("%s is an invalid positive float value" %
args.max_index_storage)
JSON_TYPE = args.json
MAX_INDEX_NUM = args.max_index_num
@ -971,7 +976,7 @@ def main(argv):
arg_parser.add_argument(
"--max_index_num", help="Maximum number of suggested indexes", type=int)
arg_parser.add_argument("--max_index_storage",
help="Maximum storage of suggested indexes/MB", type=int)
help="Maximum storage of suggested indexes/MB", type=float)
arg_parser.add_argument("--multi_iter_mode", action='store_true',
help="Whether to use multi-iteration algorithm", default=False)
arg_parser.add_argument("--multi_node", action='store_true',

View File

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

View File

@ -27,6 +27,7 @@ from collections.abc import Iterable
from collections import defaultdict
import index_advisor_workload as iaw
import mcts
def hash_any(obj):
@ -227,6 +228,32 @@ select * from student_range_part1 where credit=1;
class IndexAdvisorTester(unittest.TestCase):
def test_mcts(self):
storage_threshold = 12
index1 = iaw.IndexItem('public.a', 'col1', index_type='global')
index2 = iaw.IndexItem('public.b', 'col1', index_type='global')
index3 = iaw.IndexItem('public.c', 'col1', index_type='global')
index4 = iaw.IndexItem('public.d', 'col1', index_type='global')
atomic_index1 = iaw.IndexItem('public.a', 'col1', index_type='global')
atomic_index2 = iaw.IndexItem('public.b', 'col1', index_type='global')
atomic_index3 = iaw.IndexItem('public.c', 'col1', index_type='global')
atomic_index4 = iaw.IndexItem('public.d', 'col1', index_type='global')
atomic_index1.storage = 10
atomic_index2.storage = 4
atomic_index3.storage = 7
available_choices = [index1, index2, index3, index4]
atomic_choices = [[], [atomic_index2], [atomic_index1], [atomic_index3],
[atomic_index2, atomic_index3], [atomic_index4]]
query = iaw.QueryItem('select * from gia_01', 1)
query.cost_list = [10, 7, 5, 9, 4, 11]
workload_info = [query]
results = mcts.MCTS(workload_info, atomic_choices, available_choices, storage_threshold, 2)
self.assertLessEqual([index1.atomic_pos, index2.atomic_pos, index3.atomic_pos], [2, 1, 3])
self.assertSetEqual({results[0].table, results[1].table}, {'public.b', 'public.c'})
def test_get_indexable_columns(self):
tables = 'table1 table2 table2 table3 table3 table3'.split()
columns = 'col1,col2 col2 col3 col1,col2 col2,col3 col2,col5'.split()

View File

@ -90,7 +90,10 @@ static void DropExtensionInListIsSupported(List* objname)
}
}
ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("EXTENSION is not yet supported.")));
/* Enable DROP operation of the above objects during inplace upgrade or support_extended_features is true */
if (!u_sess->attr.attr_common.IsInplaceUpgrade && !g_instance.attr.attr_common.support_extended_features) {
ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("EXTENSION is not yet supported.")));
}
}
/*

View File

@ -1175,7 +1175,7 @@ void CreateExtension(CreateExtensionStmt* stmt)
FEATURE_NOT_PUBLIC_ERROR("EXTENSION is not yet supported.");
}
if (pg_strcasecmp(stmt->extname, "b_sql_plugin") == 0 && !DB_IS_CMPT(B_FORMAT)) {
if (pg_strcasecmp(stmt->extname, "dolphin") == 0 && !DB_IS_CMPT(B_FORMAT)) {
ereport(ERROR,
(errmsg("please create extension \"%s\" with B type DBCOMPATIBILITY", stmt->extname)));
}
@ -1418,8 +1418,8 @@ void CreateExtension(CreateExtensionStmt* stmt)
u_sess->exec_cxt.extension_is_valid = true;
if (pg_strcasecmp(stmt->extname, "b_sql_plugin") == 0) {
u_sess->attr.attr_sql.b_sql_plugin = true;
if (pg_strcasecmp(stmt->extname, "dolphin") == 0) {
u_sess->attr.attr_sql.dolphin = true;
}
/*

View File

@ -44,7 +44,7 @@
#include "utils/array.h"
#include "utils/acl.h"
static void ConnectPublisher(char *conninfo, char* slotname);
static bool 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 *enabled, bool *slot_name_given, char **slot_name, char **synchronous_commit, bool *binary_given, bool *binary)
{
ListCell *lc;
@ -76,6 +76,10 @@ 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) {
@ -124,6 +128,15 @@ 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)));
@ -197,26 +210,82 @@ static Datum publicationListToArray(List *publist)
}
/*
* connect publisher and create slot.
* the input conninfo should be encrypt, we will decrypt password inside
* 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.
*/
static void ConnectPublisher(char *conninfo, char *slotname)
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)
{
/* 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 = DecryptConninfo(conninfo);
char* decryptConninfo = EncryptOrDecryptConninfo(conninfo, 'D');
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);
if (!connectSuccess) {
ereport(ERROR, (errcode(ERRCODE_CONNECTION_FAILURE), errmsg("could not connect to the publisher")));
}
return connectSuccess;
}
/*
@ -293,9 +362,10 @@ 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;
@ -305,7 +375,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);
&synchronous_commit, &binary_given, &binary);
/*
* Since creating a replication slot is not transactional, rolling back
@ -333,11 +403,10 @@ ObjectAddress CreateSubscription(CreateSubscriptionStmt *stmt, bool isTopLevel)
synchronous_commit = "off";
}
conninfo = stmt->conninfo;
publications = stmt->publication;
/* Check the connection info string. */
libpqrcv_check_conninfo(conninfo);
libpqrcv_check_conninfo(stmt->conninfo);
/* Everything ok, form a new tuple. */
rc = memset_s(values, sizeof(values), 0, sizeof(values));
@ -349,18 +418,12 @@ 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 */
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);
char *encryptConninfo = EncryptOrDecryptConninfo(stmt->conninfo, 'E');
values[Anum_pg_subscription_subconninfo - 1] = CStringGetTextDatum(encryptConninfo);
pfree_ext(conninfoList);
if (enabled) {
if (!slotname_given) {
slotname = stmt->subname;
@ -396,11 +459,14 @@ ObjectAddress CreateSubscription(CreateSubscriptionStmt *stmt, bool isTopLevel)
*/
if (enabled) {
Assert(slotname);
ConnectPublisher(encryptConninfo, slotname);
if (!AttemptConnectPublisher(encryptConninfo, slotname, true)) {
ereport(ERROR, (errcode(ERRCODE_CONNECTION_FAILURE), errmsg("Failed to connect to publisher.")));
}
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));
@ -439,6 +505,8 @@ 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;
@ -473,7 +541,7 @@ ObjectAddress AlterSubscription(AlterSubscriptionStmt *stmt)
/* Parse options. */
parse_subscription_options(stmt->options, &conninfo, &publications, &enabled_given, &enabled, &slotname_given,
&slot_name, &synchronous_commit);
&slot_name, &synchronous_commit, &binary_given, &binary);
/* Form a new tuple. */
rc = memset_s(nulls, sizeof(nulls), false, sizeof(nulls));
@ -490,23 +558,15 @@ ObjectAddress AlterSubscription(AlterSubscriptionStmt *stmt)
if (conninfo) {
/* Check the connection info string. */
libpqrcv_check_conninfo(conninfo);
/* 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;
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;
needFreeConninfo = true;
pfree_ext(conninfoList);
/* need to check whether new conninfo can be used to connect to new publisher */
if (sub->enabled || (enabled_given && enabled)) {
/* we need to check whether new conninfo can be used to connect to new publisher */
checkConn = true;
}
}
@ -548,6 +608,10 @@ 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;
@ -570,16 +634,18 @@ ObjectAddress AlterSubscription(AlterSubscriptionStmt *stmt)
if (sub->enabled && !enabled) {
ereport(ERROR, (errmsg("If you want to deactivate this subscription, use DROP SUBSCRIPTION.")));
}
/* enable subscription */
if (!sub->enabled && enabled) {
/* if slot hasn't been created, then create it */
if (!sub->slotname || !*(sub->slotname)) {
/* enabling subscription, but slot hasn't been created,
* then mark createSlot to true.
*/
if (!sub->enabled && enabled && (!sub->slotname || !*(sub->slotname))) {
createSlot = true;
}
}
if (checkConn || createSlot || validateSlot) {
ConnectPublisher(encryptConninfo, finalSlotName);
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.")));
}
if (createSlot) {
CreateSlotInPublisher(finalSlotName);
@ -597,12 +663,6 @@ 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;
}
@ -753,7 +813,11 @@ void DropSubscription(DropSubscriptionStmt *stmt, bool isTopLevel)
initStringInfo(&cmd);
appendStringInfo(&cmd, "DROP_REPLICATION_SLOT %s", quote_identifier(slotname));
ConnectPublisher(conninfo, slotname);
if (!AttemptConnectPublisher(conninfo, slotname, true)) {
ereport(ERROR, (errcode(ERRCODE_CONNECTION_FAILURE), errmsg(
"could not connect to publisher.")));
}
PG_TRY();
{
int sqlstate = 0;
@ -779,6 +843,7 @@ void DropSubscription(DropSubscriptionStmt *stmt, bool isTopLevel)
(WalReceiverFuncTable[GET_FUNC_IDX]).walrcv_disconnect();
pfree_ext(conninfo);
pfree(cmd.data);
heap_close(rel, NoLock);
}
@ -908,3 +973,149 @@ 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);
targetPartOid = heapTupleGetPartitionId(partTableRel, (HeapTuple)tuple, true);
searchFakeReationForPartitionOid(
partRelHTAB, CurrentMemoryContext, partTableRel, targetPartOid, partRel, part, RowExclusiveLock);
@ -24797,7 +24797,8 @@ static Oid AddTemporaryPartitionForAlterPartitions(const AlterTableCmd* cmd, Rel
destPartOid = AddTemporaryHashPartitionForAlterPartitions(cmd, partTableRel, partSeq, renameTargetPart);
break;
}
case PART_TYPE_RANGE: {
case PART_TYPE_RANGE:
case PART_TYPE_INTERVAL: {
destPartOid = AddTemporaryRangePartitionForAlterPartitions(cmd, partTableRel, partSeq, renameTargetPart);
break;
}
@ -25098,11 +25099,11 @@ static void readTuplesAndInsertInternal(Relation tempTableRel, Relation partTabl
/* tableam_tops_copy_tuple is not ready so we add UStore hack path */
copyTuple = tableam_tops_copy_tuple(tuple);
targetPartOid = heapTupleGetPartitionId(partTableRel, (void *)tuple);
targetPartOid = heapTupleGetPartitionId(partTableRel, (void *)tuple, true);
searchFakeReationForPartitionOid(
partRelHTAB, CurrentMemoryContext, partTableRel, targetPartOid, partRel, part, RowExclusiveLock);
if (RelationIsSubPartitioned(partTableRel)) {
targetPartOid = heapTupleGetPartitionId(partRel, (void *)tuple);
targetPartOid = heapTupleGetPartitionId(partRel, (void *)tuple, true);
searchFakeReationForPartitionOid(partRelHTAB, CurrentMemoryContext, partRel, targetPartOid, subPartRel,
subPart, RowExclusiveLock);
partRel = subPartRel;

View File

@ -1181,6 +1181,17 @@ static Node* pull_up_simple_subquery(PlannerInfo* root, Node* jtnode, RangeTblEn
return jtnode;
}
/*
* We must flatten any join alias Vars in the subquery's targetlist,
* because pulling up the subquery's subqueries might have changed their
* expansions into arbitrary expressions, which could affect
* pullup_replace_vars' decisions about whether PlaceHolderVar wrappers
* are needed for tlist entries. (Likely it'd be better to do
* flatten_join_alias_vars on the whole query tree at some earlier stage,
* maybe even in the rewriter; but for now let's just fix this case here.)
*/
subquery->targetList = (List *) flatten_join_alias_vars(subroot, (Node *) subquery->targetList);
/*
* Adjust level-0 varnos in subquery so that we can append its rangetable
* to upper query's. We have to fix the subquery's append_rel_list as

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) {
if (candidate_num == 0 && !t_thrd.pagewriter_cxt.shutdown_requested) {
/* 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* b_sql_plugin = "b_sql_plugin";
const char* dolphin = "dolphin";
CFunInfo tmpCF;
tmpCF = load_external_function(b_sql_plugin, INIT_PLUGIN_OBJECT, false, false);
tmpCF = load_external_function(dolphin, INIT_PLUGIN_OBJECT, false, false);
if (tmpCF.user_fn != NULL) {
((void* (*)(void))(tmpCF.user_fn))();
}
@ -862,9 +862,11 @@ List* pg_parse_query(const char* query_string, List** query_string_locationlist)
List* (*parser_hook)(const char*, List**) = raw_parser;
#ifndef ENABLE_MULTIPLE_NODES
int id = GetCustomParserId();
if (id >= 0 && g_instance.raw_parser_hook[id] != NULL) {
parser_hook = (List* (*)(const char*, List**))g_instance.raw_parser_hook[id];
if (u_sess->attr.attr_sql.dolphin) {
int id = GetCustomParserId();
if (id >= 0 && g_instance.raw_parser_hook[id] != NULL) {
parser_hook = (List* (*)(const char*, List**))g_instance.raw_parser_hook[id];
}
}
#endif
raw_parsetree_list = parser_hook(query_string, query_string_locationlist);
@ -6112,6 +6114,9 @@ void ProcessInterrupts(void)
/* The logical replication launcher can be stopped at any time. */
proc_exit(0);
} else if (IsLogicalWorker()) {
ereport(FATAL, (errcode(ERRCODE_ADMIN_SHUTDOWN),
errmsg("terminating logical replication worker due to administrator command")));
#endif
} else if (IsTxnSnapCapturerProcess()) {
ereport(FATAL,
@ -7569,7 +7574,7 @@ int PostgresMain(int argc, char* argv[], const char* dbname, const char* usernam
init_set_params_htab();
#ifndef ENABLE_MULTIPLE_NODES
if (u_sess->proc_cxt.MyDatabaseId != InvalidOid && DB_IS_CMPT(B_FORMAT) && u_sess->attr.attr_sql.b_sql_plugin) {
if (u_sess->proc_cxt.MyDatabaseId != InvalidOid && DB_IS_CMPT(B_FORMAT) && u_sess->attr.attr_sql.dolphin) {
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.b_sql_plugin) {
if (u_sess->proc_cxt.MyDatabaseId != InvalidOid && DB_IS_CMPT(B_FORMAT) && u_sess->attr.attr_sql.dolphin) {
InitBSqlPluginHookIfNeeded();
}
#endif

View File

@ -720,7 +720,6 @@ static Datum ExecEvalWholeRowVar(
{
Var* variable = (Var*)wrvstate->xprstate.expr;
TupleTableSlot* slot = NULL;
TupleDesc slot_tupdesc;
bool needslow = false;
if (isDone != NULL)
@ -802,21 +801,13 @@ static Datum ExecEvalWholeRowVar(
if (wrvstate->wrv_junkFilter != NULL)
slot = ExecFilterJunk(wrvstate->wrv_junkFilter, slot);
slot_tupdesc = slot->tts_tupleDescriptor;
/*
* If it's a RECORD Var, we'll use the slot's type ID info. It's likely
* that the slot's type is also RECORD; if so, make sure it's been
* "blessed", so that the Datum can be interpreted later.
*
* If the Var identifies a named composite type, we must check that the
* actual tuple type is compatible with it.
*/
if (variable->vartype == RECORDOID) {
if (slot_tupdesc->tdtypeid == RECORDOID && slot_tupdesc->tdtypmod < 0)
assign_record_type_typmod(slot_tupdesc);
} else {
if (variable->vartype != RECORDOID) {
TupleDesc var_tupdesc;
TupleDesc slot_tupdesc;
int i;
/*
@ -833,6 +824,8 @@ static Datum ExecEvalWholeRowVar(
*/
var_tupdesc = lookup_rowtype_tupdesc(variable->vartype, -1);
slot_tupdesc = slot->tts_tupleDescriptor;
if (var_tupdesc->natts != slot_tupdesc->natts)
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
@ -886,6 +879,7 @@ static Datum ExecEvalWholeRowFast(
{
Var* variable = (Var*)wrvstate->xprstate.expr;
TupleTableSlot* slot = NULL;
TupleDesc slot_tupdesc;
HeapTuple tuple;
TupleDesc tupleDesc;
HeapTupleHeader dtuple;
@ -915,6 +909,17 @@ static Datum ExecEvalWholeRowFast(
if (wrvstate->wrv_junkFilter != NULL)
slot = ExecFilterJunk(wrvstate->wrv_junkFilter, slot);
/*
* If it's a RECORD Var, we'll use the slot's type ID info. It's likely
* that the slot's type is also RECORD; if so, make sure it's been
* "blessed", so that the Datum can be interpreted later.
*/
slot_tupdesc = slot->tts_tupleDescriptor;
if (variable->vartype == RECORDOID) {
if (slot_tupdesc->tdtypeid == RECORDOID && slot_tupdesc->tdtypmod < 0)
assign_record_type_typmod(slot_tupdesc);
}
tuple = ExecFetchSlotTuple(slot);
tupleDesc = slot->tts_tupleDescriptor;

View File

@ -322,7 +322,6 @@ static bool RelationFindReplTupleByIndex(EState *estate, Relation rel, Relation
}
if (found) {
/* Found tuple, try to lock it in the lockmode. */
outslot->tts_tuple = ExecMaterializeSlot(outslot);
xwait = TransactionIdIsValid(snap.xmin) ? snap.xmin : snap.xmax;
/*
* If the tuple is locked, wait for locking transaction to finish
@ -346,12 +345,16 @@ static bool RelationFindReplTupleByIndex(EState *estate, Relation rel, Relation
ItemPointer tid = tableam_tops_get_t_self(targetRel, outslot->tts_tuple);
if (RelationIsUstoreFormat(targetRel)) {
/* materialize the slot, so we can visit it after the scan is end */
outslot->tts_tuple = UHeapMaterialize(outslot);
ItemPointerCopy(tid, &UHeaplocktup.ctid);
rc = memset_s(&tbuf, sizeof(tbuf), 0, sizeof(tbuf));
securec_check(rc, "\0", "\0");
UHeaplocktup.disk_tuple = &tbuf.hdr;
locktup = &UHeaplocktup;
} else {
/* materialize the slot, so we can visit it after the scan is end */
outslot->tts_tuple = ExecMaterializeSlot(outslot);
ItemPointerCopy(tid, &heaplocktup.t_self);
locktup = &heaplocktup;
}
@ -401,6 +404,10 @@ static bool tuple_equals_slot(TupleDesc desc, const Tuple tup, TupleTableSlot *s
/* Check equality of the attributes. */
for (attrnum = 0; attrnum < desc->natts; attrnum++) {
TypeCacheEntry *typentry;
/* skip generate column */
if (GetGeneratedCol(desc, attrnum)) {
continue;
}
/*
* If one value is NULL and other is not, then they are certainly not
* equal
@ -478,7 +485,6 @@ static bool RelationFindReplTupleSeq(Relation rel, LockTupleMode lockmode, Tuple
found = true;
ExecStoreTuple(scantuple, outslot, InvalidBuffer, false);
outslot->tts_tuple = ExecMaterializeSlot(outslot);
xwait = TransactionIdIsValid(snap.xmin) ? snap.xmin : snap.xmax;
/*
@ -511,12 +517,16 @@ static bool RelationFindReplTupleSeq(Relation rel, LockTupleMode lockmode, Tuple
ItemPointer tid = tableam_tops_get_t_self(rel, outslot->tts_tuple);
if (RelationIsUstoreFormat(targetRel)) {
/* materialize the slot, so we can visit it after the scan is end */
outslot->tts_tuple = UHeapMaterialize(outslot);
ItemPointerCopy(tid, &UHeaplocktup.ctid);
rc = memset_s(&tbuf, sizeof(tbuf), 0, sizeof(tbuf));
securec_check(rc, "\0", "\0");
UHeaplocktup.disk_tuple = &tbuf.hdr;
locktup = &UHeaplocktup;
} else {
/* materialize the slot, so we can visit it after the scan is end */
outslot->tts_tuple = ExecMaterializeSlot(outslot);
ItemPointerCopy(tid, &heaplocktup.t_self);
locktup = &heaplocktup;
}
@ -653,7 +663,6 @@ void ExecSimpleRelationUpdate(EState *estate, EPQState *epqstate, TupleTableSlot
/* Compute stored generated columns */
if (rel->rd_att->constr && rel->rd_att->constr->has_generated_stored) {
ExecComputeStoredGenerated(resultRelInfo, estate, slot, tuple, CMD_UPDATE);
tuple = slot->tts_tuple;
}
/* Check the constraints of the tuple */
@ -672,10 +681,11 @@ void ExecSimpleRelationUpdate(EState *estate, EPQState *epqstate, TupleTableSlot
rowMovement = true;
}
tuple = slot->tts_tuple;
CommandId cid = GetCurrentCommandId(true);
/* OK, update the tuple and index entries for it */
if (!rowMovement) {
res = tableam_tuple_update(targetRelation, parentRelation, searchSlotTid, slot->tts_tuple, cid,
res = tableam_tuple_update(targetRelation, parentRelation, searchSlotTid, tuple, cid,
InvalidSnapshot, estate->es_snapshot, true, &oldslot, &tmfd, &updateIndexes, &modifiedIdxAttrs,
false, allowInplaceUpdate);
CheckTupleModifyRes(res);

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

View File

@ -8965,6 +8965,8 @@ void StartupXLOG(void)
g_instance.comm_cxt.predo_cxt.redoPf.redo_done_time = 0;
pg_atomic_write_u32(&(g_instance.comm_cxt.localinfo_cxt.is_finish_redo), 0);
NotifyGscRecoveryStarted();
/*
* Initialize WAL insert status array and the flush index - lastWalStatusEntryFlushed.
*/

View File

@ -1818,3 +1818,47 @@ void UHeapSlotStoreUHeapTuple(UHeapTuple utuple, TupleTableSlot *slot, bool shou
/* Mark extracted state invalid */
slot->tts_nvalid = 0;
}
/*
* Make the contents of the uheap table's slot contents solely depend on the slot(make them a local copy),
* and not on underlying external resources like another memory context, buffers etc.
*
* @pram slot: slot to be materialized.
*/
Tuple UHeapMaterialize(TupleTableSlot *slot)
{
Assert(!slot->tts_isempty);
Assert(slot->tts_tupslotTableAm == TAM_USTORE);
Assert(slot->tts_tupleDescriptor != NULL);
/*
* If we have a regular physical tuple, and it's locally palloc'd, we have
* nothing to do.
*/
if (slot->tts_tuple && slot->tts_shouldFree) {
return slot->tts_tuple;
}
/*
* Otherwise, copy or build a physical tuple, and store it into the slot.
*
* We may be called in a context that is shorter-lived than the tuple
* slot, but we have to ensure that the materialized tuple will survive
* anyway.
*/
MemoryContext old_context = MemoryContextSwitchTo(slot->tts_mcxt);
if (slot->tts_tuple != NULL) {
slot->tts_tuple = UHeapCopyTuple((UHeapTuple)slot->tts_tuple);
} else {
slot->tts_tuple = UHeapFormTuple(slot->tts_tupleDescriptor, slot->tts_values, slot->tts_isnull);
}
slot->tts_shouldFree = true;
MemoryContextSwitchTo(old_context);
/*
* Have to deform from scratch, otherwise tts_values[] entries could point
* into the non-materialized tuple (which might be gone when accessed).
*/
slot->tts_nvalid = 0;
return slot->tts_tuple;
}

View File

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

View File

@ -258,6 +258,15 @@ bool Index::IndexInsert(Sentinel*& outputSentinel, const Key* key, uint32_t pid,
outputSentinel = IndexInsertImpl(key, sentinel, inserted, pid);
// sync between rollback/delete and insert
if (inserted == false) {
if (unlikely(outputSentinel == nullptr)) {
MOT_REPORT_ERROR(
MOT_ERROR_OOM, "Index Insert", "Failed to insert sentinel to index %s", m_name.c_str());
rc = RC_MEMORY_ALLOCATION_ERROR;
m_sentinelPool->Release<Sentinel>(sentinel);
sentinel = nullptr;
return false;
}
// Spin if the counter is 0 - aborting in parallel or sentinel is marks for commit
if (outputSentinel->RefCountUpdate(INC, pid) == RC_OK)
retryInsert = false;
@ -300,8 +309,16 @@ Sentinel* Index::IndexInsert(const Key* key, Row* row, uint32_t pid)
// no need to report to full error stack
SetLastError(MOT_ERROR_UNIQUE_VIOLATION, MOT_SEVERITY_NORMAL);
m_sentinelPool->Release<Sentinel>(sentinel);
sentinel = nullptr;
return nullptr;
} else {
if (inserted == false) {
MOT_REPORT_ERROR(MOT_ERROR_OOM, "Index Insert", "Failed to insert sentinel to index %s", m_name.c_str());
m_sentinelPool->Release<Sentinel>(sentinel);
sentinel = nullptr;
return nullptr;
}
if (GetIndexOrder() == IndexOrder::INDEX_ORDER_PRIMARY) {
sentinel->SetPrimaryIndex();
sentinel->SetNextPtr(row);
@ -343,9 +360,6 @@ Sentinel* Index::IndexReadHeader(const Key* key, uint32_t pid) const
Sentinel* Index::IndexRemove(const Key* key, uint32_t pid)
{
Sentinel* sentinel = IndexRemoveImpl(key, pid);
MOT_ASSERT(sentinel != nullptr);
MOT_ASSERT(sentinel->GetCounter() == 0);
return sentinel;
}

View File

@ -56,12 +56,22 @@ void* basic_table<P>::insert(MOT::Key const* const& key, void* const& entry, boo
5. Update the the key slice, keylen, key suffix and key's value in the
leaf
6. Add the key's location in permutation's back (key is not visible for
readers yet) As key's location is not part of the permutation yet, the key
readers yet) as key's location is not part of the permutation yet, the key
is not reachable (aka not present). In addition, the leaf is still locked.
Unlocking the node and enter the key into the permutation will be done
later in finish_insert (called from lp.finish). */
later in finish_insert (done in lp.finish function). */
bool found = lp.find_insert(*mtSessionThreadInfo);
bool found = false;
if (!lp.find_insert(*mtSessionThreadInfo, found)) {
// Failed to insert key due to memory allocation failure.
MOT_ASSERT(!mtSessionThreadInfo->non_disruptive_error());
MOT_ASSERT(found == false);
lp.finish(0, *mtSessionThreadInfo);
result = false;
return nullptr;
}
MOT_ASSERT(mtSessionThreadInfo->non_disruptive_error());
// If the key is new (not previously existing) then we record the entry under
// that key

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_;
node_base<P>** root_ref_;
int len_;
size_t size_;
MOT::MasstreePrimaryIndex* index_;
char s_[0];
gc_layer_rcu_callback_ng(node_base<P>* root, Str prefix, size_t size)
: root_(root), len_(prefix.length()), size_(size), index_(mtSessionThreadInfo->get_working_index())
gc_layer_rcu_callback_ng(node_base<P>** root_ref, Str prefix, size_t size)
: root_ref_(root_ref), len_(prefix.length()), size_(size), index_(mtSessionThreadInfo->get_working_index())
{
errno_t erc = memcpy_s(s_, size_, prefix.data(), len_);
errno_t erc = memcpy_s(s_, len_, prefix.data(), len_);
securec_check(erc, "\0", "\0");
}
size_t operator()(bool drop_index);
@ -51,7 +51,7 @@ struct gc_layer_rcu_callback_ng : public P::threadinfo_type::mrcu_callback {
return size_;
}
static void make(node_base<P>* root, Str prefix, threadinfo& ti);
static void make(node_base<P>** root_ref, Str prefix, threadinfo& ti);
};
template <typename P>
@ -60,8 +60,8 @@ size_t gc_layer_rcu_callback_ng<P>::operator()(bool drop_index)
// If drop_index == true, all index's pools are going to be cleaned, so we can skip gc_layer call (which might add
// more elements into GC)
if (drop_index == false) {
// GC layer remove might delete elements from tree and add them to the limbolist. Index must be provided to
// allow access to the memory pools.
// GC layer remove might delete elements from tree and might create new gc layer removal requests and add them to GC.
// Index must be provided to allow access to the memory pools.
mtSessionThreadInfo->set_working_index(index_);
(*this)(*mtSessionThreadInfo);
mtSessionThreadInfo->set_working_index(NULL);
@ -73,30 +73,33 @@ size_t gc_layer_rcu_callback_ng<P>::operator()(bool drop_index)
template <typename P>
void gc_layer_rcu_callback_ng<P>::operator()(threadinfo& ti)
{
// root_ node while creating gc_layer_rcu_callback_ng might not be the current root. Find updated tree's root.
while (!root_->is_root()) {
root_ = root_->maybe_parent();
}
masstree_invariant(root_ref_);
// If root was already deleted, do nothing.
if (root_->deleted()) {
return;
}
tcursor<P> node_cursor(root_, s_, len_);
if (!node_cursor.gc_layer(ti) || !node_cursor.finish_remove(ti)) {
tcursor<P> node_cursor(root_ref_, s_, len_);
bool do_remove = node_cursor.gc_layer(ti);
if (!do_remove || !node_cursor.finish_remove(ti)) {
node_cursor.n_->unlock();
}
ti.add_nodes_to_gc();
}
template <typename P>
void gc_layer_rcu_callback_ng<P>::make(node_base<P>* root, Str prefix, threadinfo& ti)
void gc_layer_rcu_callback_ng<P>::make(node_base<P>** root_ref, Str prefix, threadinfo& ti)
{
size_t sz = prefix.len + sizeof(gc_layer_rcu_callback_ng<P>);
// As we are using slab allocator to allocate the memory, sz is will updated in ti.allocate with the real allocated
// size
void* data = ti.allocate(sz, memtag_masstree_gc, &sz /*OUT PARAM*/);
gc_layer_rcu_callback_ng<P>* cb = new (data) gc_layer_rcu_callback_ng<P>(root, prefix, sz);
// As we are using slab allocator for allocation, sz is will be updated by ti.allocate with the real allocation
// size. We need this size for GC deallocation size report
void* data = ti.allocate(sz, memtag_masstree_gc, &sz /* IN/OUT PARAM */);
if (!data) {
// If allocation fails, gc layer removal command will not be added to GC and this layer wont be removed.
// We might deal with this issue in the future by replacing the current mechanism with one of the following options:
// 1. Use thread local GC layer removal object (per threadinfo) and keep list of key suffixes to clean (also in threadinfo)
// 2. Move this feature to VACUUM process: Create special iterator that adds GC Layer callbacks when it finds empty layers
ti.set_last_error(MT_MERR_GC_LAYER_REMOVAL_MAKE);
return;
}
gc_layer_rcu_callback_ng<P>* cb = new (data) gc_layer_rcu_callback_ng<P>(root_ref, prefix, sz);
ti.rcu_register(cb, sz);
}

View File

@ -69,14 +69,17 @@ Sentinel* MasstreePrimaryIndex::IndexInsertImpl(const Key* key, Sentinel* sentin
mtSessionThreadInfo->set_gc_session(
MOTEngine::GetInstance()->GetCurrentGcSession()); // set current GC session in thread-pooled envelope
mtSessionThreadInfo->set_last_error(MT_MERR_OK);
existingItem = m_index.insert(key, sentinel, inserted, pid);
mtSessionThreadInfo->set_gc_session(NULL);
mtSessionThreadInfo->set_working_index(NULL);
if (!inserted) { // key mapping already exists in unique index
if (!inserted && existingItem) { // key mapping already exists in unique index
result = reinterpret_cast<Sentinel*>(existingItem);
} // otherwise return null pointer
} // otherwise return null pointer (if !inserted && !existingItem, Key does not exist and insertation failed due to
// memory issue)
return result;
}
@ -108,6 +111,8 @@ Sentinel* MasstreePrimaryIndex::IndexRemoveImpl(const Key* key, uint32_t pid)
mtSessionThreadInfo->set_gc_session(
MOTEngine::GetInstance()->GetCurrentGcSession()); // set current GC session in thread-pooled envelope
mtSessionThreadInfo->set_last_error(MT_MERR_OK);
output = m_index.remove(key->GetKeyBuf(), key->GetKeyLength(), result, pid);
mtSessionThreadInfo->set_gc_session(NULL);

View File

@ -37,6 +37,7 @@
#include "masstree/mot_masstree_struct.hpp"
#include "masstree/mot_masstree_iterator.hpp"
#include <cmath>
#include "mot_engine.h"
namespace MOT {
/**
@ -302,11 +303,38 @@ public:
/**
* @brief Print Masstree pools memory consumption details to log.
*/
virtual void PrintPoolsStats()
virtual void PrintPoolsStats(LogLevel level = LogLevel::LL_DEBUG)
{
m_leafsPool->Print("Leafs pool: ");
m_internodesPool->Print("Internode pool: ");
m_ksuffixSlab->Print("Ksuffix slab: ");
m_leafsPool->Print("Leafs pool", level);
m_internodesPool->Print("Internode pool", level);
m_ksuffixSlab->Print("Ksuffix slab", level);
}
virtual void GetLeafsPoolStats(uint64_t& objSize, uint64_t& numUsedObj, uint64_t& totalSize, uint64_t& netto)
{
PoolStatsSt stats = {};
m_leafsPool->GetStats(stats);
objSize = stats.m_objSize;
numUsedObj = stats.m_totalObjCount - stats.m_freeObjCount;
totalSize = stats.m_poolCount * stats.m_poolGrossSize;
netto = numUsedObj * objSize;
}
virtual void GetInternodesPoolStats(uint64_t& objSize, uint64_t& numUsedObj, uint64_t& totalSize, uint64_t& netto)
{
PoolStatsSt stats = {};
m_internodesPool->GetStats(stats);
objSize = stats.m_objSize;
numUsedObj = stats.m_totalObjCount - stats.m_freeObjCount;
totalSize = stats.m_poolCount * stats.m_poolGrossSize;
netto = numUsedObj * objSize;
}
virtual PoolStatsSt* GetKsuffixSlabStats()
{
return m_ksuffixSlab->GetStats();
}
/**
@ -316,6 +344,8 @@ public:
{
m_initialized = false;
DestroyPools();
// remove masstree's root pointer (not valid anymore)
*(m_index.root_ref()) = nullptr;
return IndexInitImpl(NULL);
}
@ -332,7 +362,7 @@ public:
* @param tag Hint to determine which pool to use.
* @return Pointer to allocated memory.
*/
void* AllocateMem(int& size, enum memtag tag)
virtual void* AllocateMem(int& size, enum memtag tag)
{
switch (tag) {
case memtag_masstree_leaf:
@ -360,7 +390,7 @@ public:
* @param Pointer to allocated memory.
* @return True if deallocation succeeded.
*/
bool DeallocateMem(void* ptr, int size, enum memtag tag)
virtual bool DeallocateMem(void* ptr, int size, enum memtag tag)
{
switch (tag) {
case memtag_masstree_leaf:
@ -431,10 +461,16 @@ public:
{
// If dropIndex == true, all index's pools are going to be cleaned, so we skip the release here
mtSessionThreadInfo->set_gc_session(GetCurrentGcSession());
GcEpochType local_epoch =
GetSessionManager()->GetCurrentSessionContext()->GetTxnManager()->GetGcSession()->GcStartInnerTxn();
size_t allocationSize = (*static_cast<mrcu_callback*>(gcRemoveLayerFuncObjPtr))(dropIndex);
if (dropIndex == false) {
((SlabAllocator*)slab)->Release(gcRemoveLayerFuncObjPtr, allocationSize);
}
GetSessionManager()->GetCurrentSessionContext()->GetTxnManager()->GetGcSession()->GcEndInnerTxn(false);
mtSessionThreadInfo->set_gc_session(NULL);
return allocationSize;
}

View File

@ -582,6 +582,7 @@ Row* Table::RemoveKeyFromIndex(Row* row, Sentinel* sentinel, uint64_t tid, GcMan
#endif
currSentinel = ix->IndexRemove(&key, tid);
MOT_ASSERT(currSentinel == sentinel);
MOT_ASSERT(currSentinel->GetCounter() == 0);
if (likely(gc != nullptr)) {
if (ix->GetIndexOrder() == IndexOrder::INDEX_ORDER_PRIMARY) {
OutputRow = currSentinel->GetData();

View File

@ -413,6 +413,8 @@ RC TxnManager::RollbackInsert(Access* ac)
#endif
outputSen = index_->IndexRemove(&m_key, GetThdId());
MOT_ASSERT(outputSen != nullptr);
MOT_ASSERT(outputSen->GetCounter() == 0);
GcSessionRecordRcu(index_->GetIndexId(), outputSen, nullptr, Index::SentinelDtor, SENTINEL_SIZE(index_));
// If we are the owner of the key and insert on top of a deleted row,
// lets check if we can reclaim the deleted row
@ -820,6 +822,8 @@ void TxnInsertAction::CleanupOptimisticInsert(
MOT_ASSERT(pIndexInsertResult->GetCounter() == 0);
Sentinel* outputSen = index_->IndexRemove(currentItem->m_key, m_manager->GetThdId());
MOT_ASSERT(outputSen != nullptr);
MOT_ASSERT(outputSen->GetCounter() == 0);
m_manager->GcSessionRecordRcu(
index_->GetIndexId(), outputSen, nullptr, Index::SentinelDtor, SENTINEL_SIZE(index_));
m_manager->m_accessMgr->IncreaseTableStat(table);

View File

@ -255,8 +255,14 @@ void StartRemoteStreaming(const LibpqrcvConnectParam *options)
stringlist_to_identifierstr(t_thrd.libwalreceiver_cxt.streamConn, options->publicationNames);
appendStringInfo(&cmd, ", publication_names %s",
PQescapeLiteral(t_thrd.libwalreceiver_cxt.streamConn, pubnames_str, strlen(pubnames_str)));
appendStringInfoChar(&cmd, ')');
pfree(pubnames_str);
if (options->binary && PQserverVersion(t_thrd.libwalreceiver_cxt.streamConn) >= 90204) {
appendStringInfoString(&cmd, ", binary 'true'");
ereport(DEBUG5, (errmsg("append binary true")));
}
appendStringInfoChar(&cmd, ')');
}
PGresult *res = libpqrcv_PQexec(cmd.data);
@ -420,7 +426,7 @@ void IdentifyRemoteSystem(bool checkRemote)
}
/* identify remote mode, should do this after connect success. */
static ServerMode IdentifyRemoteMode()
ServerMode IdentifyRemoteMode()
{
Assert(t_thrd.libwalreceiver_cxt.streamConn != NULL);
volatile WalRcvData *walrcv = t_thrd.walreceiverfuncs_cxt.WalRcv;
@ -443,7 +449,9 @@ static ServerMode IdentifyRemoteMode()
num_fields)));
}
remoteMode = (ServerMode)pg_strtoint32(PQgetvalue(res, 0, 0));
if (!t_thrd.walreceiver_cxt.AmWalReceiverForFailover && (!IS_PRIMARY_NORMAL(remoteMode)) &&
if (walrcv->conn_target != REPCONNTARGET_PUBLICATION &&
!t_thrd.walreceiver_cxt.AmWalReceiverForFailover &&
(!IS_PRIMARY_NORMAL(remoteMode)) &&
/* remoteMode of cascade standby is a standby */
!t_thrd.xlog_cxt.is_cascade_standby && !IS_SHARED_STORAGE_MODE) {
PQclear(res);

View File

@ -223,6 +223,7 @@ void LogicalDecodingProcessRecord(LogicalDecodingContext *ctx, XLogReaderState *
return;
}
ResourceOwner tmpOwner = t_thrd.utils_cxt.CurrentResourceOwner;
/* cast so we get a warning when new rmgrs are added */
switch ((RmgrIds)XLogRecGetRmid(record)) {
/*
@ -257,6 +258,7 @@ void LogicalDecodingProcessRecord(LogicalDecodingContext *ctx, XLogReaderState *
default:
break;
}
t_thrd.utils_cxt.CurrentResourceOwner = tmpOwner;
}
/*

View File

@ -18,7 +18,6 @@
#include "catalog/pg_type.h"
#include "libpq/pqformat.h"
#include "replication/logicalproto.h"
#include "utils/builtins.h"
#include "utils/lsyscache.h"
#include "utils/syscache.h"
@ -28,7 +27,7 @@
static const int LOGICALREP_IS_REPLICA_IDENTITY = 1;
static void logicalrep_write_attrs(StringInfo out, Relation rel);
static void logicalrep_write_tuple(StringInfo out, Relation rel, HeapTuple tuple);
static void logicalrep_write_tuple(StringInfo out, Relation rel, HeapTuple tuple, bool binary);
static void logicalrep_read_attrs(StringInfo in, LogicalRepRelation *rel);
static void logicalrep_read_tuple(StringInfo in, LogicalRepTupleData *tuple);
@ -115,7 +114,7 @@ void logicalrep_write_origin(StringInfo out, const char *origin, XLogRecPtr orig
/*
* Write INSERT to the output stream.
*/
void logicalrep_write_insert(StringInfo out, Relation rel, HeapTuple newtuple)
void logicalrep_write_insert(StringInfo out, Relation rel, HeapTuple newtuple, bool binary)
{
pq_sendbyte(out, 'I'); /* action INSERT */
@ -123,7 +122,7 @@ void logicalrep_write_insert(StringInfo out, Relation rel, HeapTuple newtuple)
pq_sendint32(out, RelationGetRelid(rel));
pq_sendbyte(out, 'N'); /* new tuple follows */
logicalrep_write_tuple(out, rel, newtuple);
logicalrep_write_tuple(out, rel, newtuple, binary);
}
/*
@ -151,7 +150,7 @@ LogicalRepRelId logicalrep_read_insert(StringInfo in, LogicalRepTupleData *newtu
/*
* Write UPDATE to the output stream.
*/
void logicalrep_write_update(StringInfo out, Relation rel, HeapTuple oldtuple, HeapTuple newtuple)
void logicalrep_write_update(StringInfo out, Relation rel, HeapTuple oldtuple, HeapTuple newtuple, bool binary)
{
pq_sendbyte(out, 'U'); /* action UPDATE */
@ -166,11 +165,11 @@ void logicalrep_write_update(StringInfo out, Relation rel, HeapTuple oldtuple, H
pq_sendbyte(out, 'O'); /* old tuple follows */
else
pq_sendbyte(out, 'K'); /* old key follows */
logicalrep_write_tuple(out, rel, oldtuple);
logicalrep_write_tuple(out, rel, oldtuple, binary);
}
pq_sendbyte(out, 'N'); /* new tuple follows */
logicalrep_write_tuple(out, rel, newtuple);
logicalrep_write_tuple(out, rel, newtuple, binary);
}
/*
@ -213,7 +212,7 @@ LogicalRepRelId logicalrep_read_update(StringInfo in, bool *has_oldtuple, Logica
/*
* Write DELETE to the output stream.
*/
void logicalrep_write_delete(StringInfo out, Relation rel, HeapTuple oldtuple)
void logicalrep_write_delete(StringInfo out, Relation rel, HeapTuple oldtuple, bool binary)
{
char relreplident = RelationGetRelReplident(rel);
Assert(relreplident == REPLICA_IDENTITY_DEFAULT ||
@ -229,7 +228,7 @@ void logicalrep_write_delete(StringInfo out, Relation rel, HeapTuple oldtuple)
else
pq_sendbyte(out, 'K'); /* old key follows */
logicalrep_write_tuple(out, rel, oldtuple);
logicalrep_write_tuple(out, rel, oldtuple, binary);
}
/*
@ -344,7 +343,7 @@ void logicalrep_read_typ(StringInfo in, LogicalRepTyp *ltyp)
/*
* Write a tuple to the outputstream, in the most efficient format possible.
*/
static void logicalrep_write_tuple(StringInfo out, Relation rel, HeapTuple tuple)
static void logicalrep_write_tuple(StringInfo out, Relation rel, HeapTuple tuple, bool binary)
{
TupleDesc desc;
Datum values[MaxTupleAttributeNumber];
@ -371,7 +370,6 @@ static void logicalrep_write_tuple(StringInfo out, Relation rel, HeapTuple tuple
HeapTuple typtup;
Form_pg_type typclass;
Form_pg_attribute att = desc->attrs[i];
char *outputstr;
/* skip dropped columns */
if (att->attisdropped || GetGeneratedCol(desc, i)) {
@ -379,7 +377,7 @@ static void logicalrep_write_tuple(StringInfo out, Relation rel, HeapTuple tuple
}
if (isnull[i]) {
pq_sendbyte(out, 'n'); /* null column */
pq_sendbyte(out, LOGICALREP_COLUMN_NULL); /* null column */
continue;
}
@ -388,61 +386,91 @@ static void logicalrep_write_tuple(StringInfo out, Relation rel, HeapTuple tuple
elog(ERROR, "cache lookup failed for type %u", att->atttypid);
typclass = (Form_pg_type)GETSTRUCT(typtup);
pq_sendbyte(out, 't'); /* 'text' data follows */
if (!typclass->typbyval && typclass->typlen == -1) {
/* definitely detoasted Datum */
Datum val = PointerGetDatum(PG_DETOAST_DATUM(values[i]));
outputstr = OidOutputFunctionCall(typclass->typoutput, val);
/*
* Send in binary if requested and type has suitable send function.
*/
if (binary && OidIsValid(typclass->typsend)) {
bytea* outputbytes = NULL;
pq_sendbyte(out, LOGICALREP_COLUMN_BINARY);
if (!typclass->typbyval && typclass->typlen == -1) {
/* definitely detoasted Datum */
Datum val = PointerGetDatum(PG_DETOAST_DATUM(values[i]));
outputbytes = OidSendFunctionCall(typclass->typsend, val);
} else {
outputbytes = OidSendFunctionCall(typclass->typsend, values[i]);
}
int len = VARSIZE(outputbytes) - VARHDRSZ;
pq_sendint(out, len, 4); /* length */
pq_sendbytes(out, VARDATA(outputbytes), len); /* data */
if (outputbytes != NULL) {
pfree(outputbytes);
}
} else {
outputstr = OidOutputFunctionCall(typclass->typoutput, values[i]);
char* outputstr = NULL;
pq_sendbyte(out, LOGICALREP_COLUMN_TEXT);
if (!typclass->typbyval && typclass->typlen == -1) {
/* definitely detoasted Datum */
Datum val = PointerGetDatum(PG_DETOAST_DATUM(values[i]));
outputstr = OidOutputFunctionCall(typclass->typoutput, val);
} else {
outputstr = OidOutputFunctionCall(typclass->typoutput, values[i]);
}
pq_sendcountedtext(out, outputstr, strlen(outputstr), false);
if (outputstr != NULL) {
pfree(outputstr);
}
}
pq_sendcountedtext(out, outputstr, strlen(outputstr), false);
pfree(outputstr);
ReleaseSysCache(typtup);
}
}
/*
* Read tuple in remote format from stream.
*
* The returned tuple points into the input stringinfo.
* Read tuple in logical replication format from stream.
*/
static void logicalrep_read_tuple(StringInfo in, LogicalRepTupleData *tuple)
{
uint16 i;
uint16 natts;
int rc;
/* Get number of attributes. */
natts = pq_getmsgint(in, sizeof(uint16));
uint16 natts = pq_getmsgint(in, sizeof(uint16));
rc = memset_s(tuple->changed, sizeof(tuple->changed), 0, sizeof(tuple->changed));
securec_check(rc, "", "");
/* Allocate space for per-column values; zero out unused StringInfoDatas */
tuple->colvalues = (StringInfoData *) palloc0(natts * sizeof(StringInfoData));
tuple->colstatus = (char *) palloc(natts * sizeof(char));
tuple->ncols = natts;
/* Read the data */
for (i = 0; i < natts; i++) {
char kind;
kind = pq_getmsgbyte(in);
for (uint16 i = 0; i < natts; i++) {
char kind = pq_getmsgbyte(in);
tuple->colstatus[i] = kind;
uint32 len;
StringInfo value = &tuple->colvalues[i];
switch (kind) {
case 'n': /* null */
tuple->values[i] = NULL;
tuple->changed[i] = true;
case LOGICALREP_COLUMN_NULL: /* null */
/* nothing more to do */
break;
case 't': { /* text formatted value */
uint32 len;
tuple->changed[i] = true;
len = pq_getmsgint(in, sizeof(uint32)); /* read length */
case LOGICALREP_COLUMN_TEXT:
len = pq_getmsgint(in, sizeof(uint32)); /* read length */
/* and data */
tuple->values[i] = (char *)palloc(len + 1);
pq_copymsgbytes(in, tuple->values[i], len);
tuple->values[i][len] = '\0';
value->data = (char *) palloc((len + 1) * sizeof(char));
pq_copymsgbytes(in, value->data, len);
value->data[len] = '\0';
/* make StringInfo fully valid */
value->len = len;
value->cursor = 0;
value->maxlen = len;
break;
case LOGICALREP_COLUMN_BINARY:
len = pq_getmsgint(in, sizeof(uint32)); /* read length */
/* and data */
value->data = (char *)palloc0((len + 1) * sizeof(char));
pq_copymsgbytes(in, value->data, len);
/* make StringInfo fully valid */
value->len = len;
value->cursor = 0;
value->maxlen = len;
break;
}
default:
elog(ERROR, "unrecognized data representation type '%c'", kind);
break;
@ -451,7 +479,7 @@ static void logicalrep_read_tuple(StringInfo in, LogicalRepTupleData *tuple)
}
/*
* Write relation attributes to the stream.
* Write relation attributes metadata to the stream.
*/
static void logicalrep_write_attrs(StringInfo out, Relation rel)
{
@ -504,7 +532,7 @@ static void logicalrep_write_attrs(StringInfo out, Relation rel)
}
/*
* Read relation attribute names from the stream.
* Read relation attribute metadata from the stream.
*/
static void logicalrep_read_attrs(StringInfo in, LogicalRepRelation *rel)
{
@ -573,3 +601,25 @@ static const char *logicalrep_read_namespace(StringInfo in)
return nspname;
}
/*
* Write conninfo to the output stream.
*/
void logicalrep_write_conninfo(StringInfo out, char* conninfo)
{
pq_sendbyte(out, 'S'); /* action */
pq_writestring(out, conninfo); /* conninfo follows */
}
/*
* Read conninfo from stream.
*/
void logicalrep_read_conninfo(StringInfo in, char** conninfo)
{
const char* conninfoTemp = pq_getmsgstring(in);
size_t conninfoLen = strlen(conninfoTemp) + 1;
*conninfo = (char*)palloc(conninfoLen);
int rc = strcpy_s(*conninfo, conninfoLen, conninfoTemp);
securec_check(rc, "", "");
}

View File

@ -41,6 +41,7 @@
#include "catalog/pg_partition_fn.h"
#include "commands/trigger.h"
#include "commands/subscriptioncmds.h"
#include "executor/executor.h"
#include "executor/node/nodeModifyTable.h"
@ -111,6 +112,8 @@ static void store_flush_position(XLogRecPtr remote_lsn);
static void reread_subscription(void);
static void ApplyWorkerProcessMsg(char type, StringInfo s, XLogRecPtr *lastRcv);
static void apply_dispatch(StringInfo s);
static void apply_handle_conninfo(StringInfo s);
static void UpdateConninfo(char* standbysInfo);
/* SIGHUP: set flag to re-read config file at next convenient time */
static void LogicalrepWorkerSighub(SIGNAL_ARGS)
@ -118,18 +121,6 @@ static void LogicalrepWorkerSighub(SIGNAL_ARGS)
t_thrd.applyworker_cxt.got_SIGHUP = true;
}
/* SIGTERM: time to die */
static void LogicalrepWorkerSigterm(SIGNAL_ARGS)
{
int saveErrno = errno;
t_thrd.applyworker_cxt.got_SIGTERM = true;
if (t_thrd.proc)
SetLatch(&t_thrd.proc->procLatch);
errno = saveErrno;
}
/*
* Make sure that we started local transaction.
*
@ -265,11 +256,11 @@ static void slot_store_error_callback(void *arg)
}
/*
* Store data in C string form into slot.
* This is similar to BuildTupleFromCStrings but TupleTableSlot fits our
* use better.
* Store tuple data into slot.
*
* Incoming data can be either text or binary format.
*/
static void slot_store_cstrings(TupleTableSlot *slot, LogicalRepRelMapEntry *rel, char **values)
static void slot_store_data(TupleTableSlot *slot, LogicalRepRelMapEntry *rel, LogicalRepTupleData *tupleData)
{
int natts = slot->tts_tupleDescriptor->natts;
int i;
@ -286,19 +277,52 @@ static void slot_store_cstrings(TupleTableSlot *slot, LogicalRepRelMapEntry *rel
errcallback.previous = t_thrd.log_cxt.error_context_stack;
t_thrd.log_cxt.error_context_stack = &errcallback;
/* Call the "in" function for each non-dropped attribute */
/* Call the "in" function for each non-dropped, non-null attribute */
for (i = 0; i < natts; i++) {
Form_pg_attribute att = slot->tts_tupleDescriptor->attrs[i];
int remoteattnum = rel->attrmap[i];
Oid typinput;
Oid typioparam;
if (!att->attisdropped && remoteattnum >= 0 && values[remoteattnum] != NULL) {
if (!att->attisdropped && remoteattnum >= 0) {
StringInfo colvalue = &tupleData->colvalues[remoteattnum];
errarg.remote_attnum = remoteattnum;
getTypeInputInfo(att->atttypid, &typinput, &typioparam);
slot->tts_values[i] = OidInputFunctionCall(typinput, values[remoteattnum], typioparam, att->atttypmod);
slot->tts_isnull[i] = false;
if (tupleData->colstatus[remoteattnum] == LOGICALREP_COLUMN_TEXT) {
Oid typinput;
Oid typioparam;
getTypeInputInfo(att->atttypid, &typinput, &typioparam);
slot->tts_values[i] = OidInputFunctionCall(typinput, colvalue->data, typioparam, att->atttypmod);
slot->tts_isnull[i] = false;
} else if (tupleData->colstatus[remoteattnum] == LOGICALREP_COLUMN_BINARY) {
Oid typreceive;
Oid typioparam;
/*
* In some code paths we may be asked to re-parse the same
* tuple data. Reset the StringInfo's cursor so that works.
*/
colvalue->cursor = 0;
getTypeBinaryInputInfo(att->atttypid, &typreceive, &typioparam);
slot->tts_values[i] = OidReceiveFunctionCall(typreceive, colvalue, typioparam, att->atttypmod);
/* Trouble if it didn't eat the whole buffer */
if (colvalue->cursor != colvalue->len) {
ereport(ERROR, (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
errmsg("incorrect binary data format in logical replication column %d",
remoteattnum + 1)));
}
slot->tts_isnull[i] = false;
} else {
/*
* NULL value from remote. (We don't expect to see
* LOGICALREP_COLUMN_UNCHANGED here, but if we do, treat it as
* NULL.)
*/
slot->tts_values[i] = (Datum) 0;
slot->tts_isnull[i] = true;
}
/* Reset attnum for error callback */
errarg.remote_attnum = -1;
} else {
/*
@ -318,18 +342,19 @@ static void slot_store_cstrings(TupleTableSlot *slot, LogicalRepRelMapEntry *rel
}
/*
* Replace selected columns with user data provided as C strings.
* Replace updated columns with data from the LogicalRepTupleData struct.
* This is somewhat similar to heap_modify_tuple but also calls the type
* input functions on the user data.
* "slot" is filled with a copy of the tuple in "srcslot", with
* columns selected by the "replaces" array replaced with data values
* from "values".
*
* "slot" is filled with a copy of the tuple in "srcslot", replacing
* columns provided in "tupleData" and leaving others as-is.
*
* Caution: unreplaced pass-by-ref columns in "slot" will point into the
* storage for "srcslot". This is OK for current usage, but someday we may
* need to materialize "slot" at the end to make it independent of "srcslot".
*/
static void slot_modify_cstrings(TupleTableSlot *slot, TupleTableSlot *srcslot, LogicalRepRelMapEntry *rel,
char **values, const bool *replaces)
static void slot_modify_data(TupleTableSlot *slot, TupleTableSlot *srcslot, LogicalRepRelMapEntry *rel,
LogicalRepTupleData *tupleData)
{
int natts = slot->tts_tupleDescriptor->natts;
int i;
@ -364,23 +389,47 @@ static void slot_modify_cstrings(TupleTableSlot *slot, TupleTableSlot *srcslot,
Form_pg_attribute att = slot->tts_tupleDescriptor->attrs[i];
int remoteattnum = rel->attrmap[i];
if (remoteattnum < 0 || !replaces[remoteattnum]) {
if (remoteattnum < 0) {
continue;
}
if (values[remoteattnum] != NULL) {
Oid typinput;
Oid typioparam;
if (tupleData->colstatus[remoteattnum] != LOGICALREP_COLUMN_UNCHANGED) {
StringInfo colvalue = &tupleData->colvalues[remoteattnum];
errarg.remote_attnum = remoteattnum;
getTypeInputInfo(att->atttypid, &typinput, &typioparam);
slot->tts_values[i] = OidInputFunctionCall(typinput, values[remoteattnum], typioparam, att->atttypmod);
slot->tts_isnull[i] = false;
if (tupleData->colstatus[remoteattnum] == LOGICALREP_COLUMN_TEXT) {
Oid typinput;
Oid typioparam;
getTypeInputInfo(att->atttypid, &typinput, &typioparam);
slot->tts_values[i] = OidInputFunctionCall(typinput, colvalue->data, typioparam, att->atttypmod);
slot->tts_isnull[i] = false;
} else if (tupleData->colstatus[remoteattnum] == LOGICALREP_COLUMN_BINARY) {
Oid typreceive;
Oid typioparam;
/*
* In some code paths we may be asked to re-parse the same
* tuple data. Reset the StringInfo's cursor so that works.
*/
colvalue->cursor = 0;
getTypeBinaryInputInfo(att->atttypid, &typreceive, &typioparam);
slot->tts_values[i] = OidReceiveFunctionCall(typreceive, colvalue, typioparam, att->atttypmod);
/* Trouble if it didn't eat the whole buffer */
if (colvalue->cursor != colvalue->len) {
ereport(ERROR, (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
errmsg("incorrect binary data format in logical replication column %d", remoteattnum + 1)));
}
slot->tts_isnull[i] = false;
} else {
/* must be LOGICALREP_COLUMN_NULL */
slot->tts_values[i] = (Datum) 0;
slot->tts_isnull[i] = true;
}
errarg.remote_attnum = -1;
} else {
slot->tts_values[i] = (Datum)0;
slot->tts_isnull[i] = true;
}
}
@ -516,7 +565,7 @@ static void apply_handle_insert(StringInfo s)
PushActiveSnapshot(GetTransactionSnapshot());
/* Process and store remote tuple in the slot */
oldctx = MemoryContextSwitchTo(GetPerTupleMemoryContext(estate));
slot_store_cstrings(remoteslot, rel, newtup.values);
slot_store_data(remoteslot, rel, &newtup);
slot_fill_defaults(rel, estate, remoteslot);
MemoryContextSwitchTo(oldctx);
@ -646,7 +695,7 @@ static void apply_handle_update(StringInfo s)
int remoteattnum = rel->attrmap[i];
if (!att->attisdropped && remoteattnum >= 0) {
Assert(remoteattnum < newtup.ncols);
if (newtup.changed[i]) {
if (newtup.colstatus[i] != LOGICALREP_COLUMN_UNCHANGED) {
target_rte->updatedCols = bms_add_member(target_rte->updatedCols,
i + 1 - FirstLowInvalidHeapAttributeNumber);
}
@ -660,7 +709,7 @@ static void apply_handle_update(StringInfo s)
/* Build the search tuple. */
oldctx = MemoryContextSwitchTo(GetPerTupleMemoryContext(estate));
slot_store_cstrings(remoteslot, rel, has_oldtup ? oldtup.values : newtup.values);
slot_store_data(remoteslot, rel, has_oldtup ? &oldtup : &newtup);
MemoryContextSwitchTo(oldctx);
/*
@ -683,7 +732,7 @@ static void apply_handle_update(StringInfo s)
if (found) {
/* Process and store remote tuple in the slot */
oldctx = MemoryContextSwitchTo(GetPerTupleMemoryContext(estate));
slot_modify_cstrings(remoteslot, localslot, rel, newtup.values, newtup.changed);
slot_modify_data(remoteslot, localslot, rel, &newtup);
MemoryContextSwitchTo(oldctx);
EvalPlanQualSetSlot(&epqstate, remoteslot);
@ -748,7 +797,7 @@ static void apply_handle_delete(StringInfo s)
/* Find the tuple using the replica identity index. */
oldctx = MemoryContextSwitchTo(GetPerTupleMemoryContext(estate));
slot_store_cstrings(remoteslot, rel, oldtup.values);
slot_store_data(remoteslot, rel, &oldtup);
MemoryContextSwitchTo(oldctx);
/*
@ -824,6 +873,9 @@ static void apply_dispatch(StringInfo s)
case 'O':
apply_handle_origin(s);
break;
case 'S':
apply_handle_conninfo(s);
break;
default:
ereport(ERROR, (errcode(ERRCODE_PROTOCOL_VIOLATION),
errmsg("invalid logical replication message type \"%c\"", action)));
@ -1004,13 +1056,15 @@ static void ApplyLoop(void)
/* mark as idle, before starting to loop */
pgstat_report_activity(STATE_IDLE, NULL);
while (!t_thrd.applyworker_cxt.got_SIGTERM) {
for (;;) {
MemoryContextSwitchTo(t_thrd.applyworker_cxt.messageContext);
int len;
char *buf = NULL;
unsigned char type;
CHECK_FOR_INTERRUPTS();
/* Wait a while for data to arrive */
if ((WalReceiverFuncTable[GET_FUNC_IDX]).walrcv_receive(NAPTIME_PER_CYCLE, &type, &buf, &len)) {
StringInfoData s;
@ -1224,6 +1278,17 @@ static void reread_subscription(void)
proc_exit(0);
}
/*
* Exit if any parameter that affects the remote connection was changed.
* The launcher will start a new worker.
*/
if (strcmp(newsub->name, t_thrd.applyworker_cxt.mySubscription->name) != 0 ||
newsub->binary != t_thrd.applyworker_cxt.mySubscription->binary) {
ereport(LOG, (errmsg("logical replication apply worker for subscription \"%s\" "
"will restart because of a parameter change", t_thrd.applyworker_cxt.mySubscription->name)));
proc_exit(0);
}
/* !slotname should never happen when enabled is true. */
Assert(newsub->slotname);
@ -1296,7 +1361,7 @@ void ApplyWorkerMain()
*/
gspqsignal(SIGHUP, LogicalrepWorkerSighub);
gspqsignal(SIGINT, StatementCancelHandler);
gspqsignal(SIGTERM, LogicalrepWorkerSigterm);
gspqsignal(SIGTERM, die);
gspqsignal(SIGQUIT, quickdie);
gspqsignal(SIGALRM, handle_sig_alarm);
@ -1422,14 +1487,9 @@ void ApplyWorkerMain()
CommitTransactionCommand();
char *decryptConnInfo = DecryptConninfo(t_thrd.applyworker_cxt.mySubscription->conninfo);
bool connectSuccess = (WalReceiverFuncTable[GET_FUNC_IDX]).walrcv_connect(decryptConnInfo, NULL,
t_thrd.applyworker_cxt.mySubscription->name, -1);
rc = memset_s(decryptConnInfo, strlen(decryptConnInfo), 0, strlen(decryptConnInfo));
securec_check(rc, "", "");
pfree_ext(decryptConnInfo);
if (!connectSuccess) {
ereport(ERROR, (errcode(ERRCODE_CONNECTION_FAILURE), errmsg("could not connect to the publisher")));
if (!AttemptConnectPublisher(t_thrd.applyworker_cxt.mySubscription->conninfo,
t_thrd.applyworker_cxt.mySubscription->name, true)) {
ereport(ERROR, (errcode(ERRCODE_CONNECTION_FAILURE), errmsg("Failed to connect to publisher.")));
}
/*
@ -1447,6 +1507,7 @@ void ApplyWorkerMain()
options.slotname = t_thrd.applyworker_cxt.mySubscription->slotname;
options.protoVersion = LOGICALREP_PROTO_VERSION_NUM;
options.publicationNames = t_thrd.applyworker_cxt.mySubscription->publications;
options.binary = t_thrd.applyworker_cxt.mySubscription->binary;
/* Start streaming from the slot. */
(WalReceiverFuncTable[GET_FUNC_IDX]).walrcv_startstreaming(&options);
@ -1595,3 +1656,72 @@ char* DefListToString(const List *defList)
return buf.data;
}
/*
* Handle conninfo update message.
*/
static void apply_handle_conninfo(StringInfo s)
{
char* standbysInfo = NULL;
logicalrep_read_conninfo(s, &standbysInfo);
UpdateConninfo(standbysInfo);
pfree_ext(standbysInfo);
}
static void UpdateConninfo(char* standbysInfo)
{
Relation rel;
bool nulls[Natts_pg_subscription];
bool replaces[Natts_pg_subscription];
Datum values[Natts_pg_subscription];
HeapTuple tup;
Subscription* sub = t_thrd.applyworker_cxt.mySubscription;
Oid subid = sub->oid;
StartTransactionCommand();
rel = heap_open(SubscriptionRelationId, RowExclusiveLock);
/* Fetch the existing tuple. */
tup = SearchSysCacheCopy2(SUBSCRIPTIONNAME, u_sess->proc_cxt.MyDatabaseId,
CStringGetDatum(t_thrd.applyworker_cxt.mySubscription->name));
if (!HeapTupleIsValid(tup)) {
ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("subscription \"%s\" does not exist",
t_thrd.applyworker_cxt.mySubscription->name)));
}
subid = HeapTupleGetOid(tup);
/* Form a new tuple. */
int rc = memset_s(nulls, sizeof(nulls), false, sizeof(nulls));
securec_check(rc, "", "");
rc = memset_s(values, sizeof(values), 0, sizeof(values));
securec_check(rc, "", "");
rc = memset_s(replaces, sizeof(replaces), false, sizeof(replaces));
securec_check(rc, "", "");
/* get conninfoWithoutHostport */
StringInfoData conninfoWithoutHostport;
initStringInfo(&conninfoWithoutHostport);
ParseConninfo(sub->conninfo, &conninfoWithoutHostport, (HostPort**)NULL);
/* join conninfoWithoutHostport together with standbysinfo */
appendStringInfo(&conninfoWithoutHostport, " %s", standbysInfo);
/* Replace connection information */
values[Anum_pg_subscription_subconninfo - 1] = CStringGetTextDatum(conninfoWithoutHostport.data);
replaces[Anum_pg_subscription_subconninfo - 1] = true;
tup = heap_modify_tuple(tup, RelationGetDescr(rel), values, nulls, replaces);
/* Update the catalog. */
simple_heap_update(rel, &tup->t_self, tup);
CatalogUpdateIndexes(rel, tup);
heap_close(rel, RowExclusiveLock);
CommitTransactionCommand();
ereport(LOG, (errmsg("Update conninfo successfully, new conninfo %s.", standbysInfo)));
}
/*
* Is current process a logical replication worker?
*/
bool IsLogicalWorker(void)
{
return t_thrd.applyworker_cxt.curWorker != NULL;
}

View File

@ -15,6 +15,8 @@
#include "catalog/pg_publication.h"
#include "commands/defrem.h"
#include "replication/logical.h"
#include "replication/logicalproto.h"
#include "replication/origin.h"
@ -44,6 +46,8 @@ static bool pgoutput_origin_filter(LogicalDecodingContext *ctx, RepOriginId orig
static List *LoadPublications(List *pubnames);
static void publication_invalidation_cb(Datum arg, int cacheid, uint32 hashvalue);
static bool ReplconninfoChanged();
static void GetConninfo(StringInfoData* standbysInfo);
/* Entry in the map used to remember which relation schemas we sent. */
typedef struct RelationSyncEntry {
@ -79,6 +83,9 @@ static void parse_output_parameters(List *options, PGOutputData *data)
ListCell *lc;
bool protocol_version_given = false;
bool publication_names_given = false;
bool binary_option_given = false;
data->binary = false;
foreach (lc, options) {
DefElem *defel = (DefElem *)lfirst(lc);
@ -108,6 +115,12 @@ static void parse_output_parameters(List *options, PGOutputData *data)
if (!SplitIdentifierString(strVal(defel->arg), ',', &(data->publication_names)))
ereport(ERROR, (errcode(ERRCODE_INVALID_NAME), errmsg("invalid publication_names syntax")));
} else if (strcmp(defel->defname, "binary") == 0) {
if (binary_option_given)
ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("conflicting or redundant options")));
binary_option_given = true;
data->binary = defGetBoolean(defel);
} else
elog(ERROR, "unrecognized pgoutput option: %s", defel->defname);
}
@ -206,6 +219,22 @@ static void pgoutput_commit_txn(LogicalDecodingContext *ctx, ReorderBufferTXN *t
OutputPluginPrepareWrite(ctx, true);
logicalrep_write_commit(ctx->out, txn, commit_lsn);
OutputPluginWrite(ctx, true);
/*
* Send the newest connecttion information to the subscriber,
* when the connection information about the standby changes.
*/
if (ReplconninfoChanged()) {
StringInfoData standbysInfo;
initStringInfo(&standbysInfo);
GetConninfo(&standbysInfo);
OutputPluginPrepareWrite(ctx, true);
logicalrep_write_conninfo(ctx->out, standbysInfo.data);
OutputPluginWrite(ctx, true);
FreeStringInfo(&standbysInfo);
}
}
/*
@ -300,19 +329,19 @@ static void pgoutput_change(LogicalDecodingContext *ctx, ReorderBufferTXN *txn,
switch (change->action) {
case REORDER_BUFFER_CHANGE_INSERT:
OutputPluginPrepareWrite(ctx, true);
logicalrep_write_insert(ctx->out, relation, &change->data.tp.newtuple->tuple);
logicalrep_write_insert(ctx->out, relation, &change->data.tp.newtuple->tuple, data->binary);
OutputPluginWrite(ctx, true);
break;
case REORDER_BUFFER_CHANGE_UINSERT:
OutputPluginPrepareWrite(ctx, true);
logicalrep_write_insert(ctx->out, relation, (HeapTuple)(&change->data.utp.newtuple->tuple));
logicalrep_write_insert(ctx->out, relation, (HeapTuple)(&change->data.utp.newtuple->tuple), data->binary);
OutputPluginWrite(ctx, true);
break;
case REORDER_BUFFER_CHANGE_UPDATE: {
HeapTuple oldtuple = change->data.tp.oldtuple ? &change->data.tp.oldtuple->tuple : NULL;
OutputPluginPrepareWrite(ctx, true);
logicalrep_write_update(ctx->out, relation, oldtuple, &change->data.tp.newtuple->tuple);
logicalrep_write_update(ctx->out, relation, oldtuple, &change->data.tp.newtuple->tuple, data->binary);
OutputPluginWrite(ctx, true);
break;
}
@ -320,14 +349,14 @@ static void pgoutput_change(LogicalDecodingContext *ctx, ReorderBufferTXN *txn,
HeapTuple oldtuple = change->data.utp.oldtuple ? ((HeapTuple)(&change->data.utp.oldtuple->tuple)) : NULL;
OutputPluginPrepareWrite(ctx, true);
logicalrep_write_update(ctx->out, relation, oldtuple, (HeapTuple)(&change->data.utp.newtuple->tuple));
logicalrep_write_update(ctx->out, relation, oldtuple, (HeapTuple)(&change->data.utp.newtuple->tuple), data->binary);
OutputPluginWrite(ctx, true);
break;
}
case REORDER_BUFFER_CHANGE_DELETE:
if (change->data.tp.oldtuple) {
OutputPluginPrepareWrite(ctx, true);
logicalrep_write_delete(ctx->out, relation, &change->data.tp.oldtuple->tuple);
logicalrep_write_delete(ctx->out, relation, &change->data.tp.oldtuple->tuple, data->binary);
OutputPluginWrite(ctx, true);
} else
elog(DEBUG1, "didn't send DELETE change because of missing oldtuple");
@ -335,7 +364,7 @@ static void pgoutput_change(LogicalDecodingContext *ctx, ReorderBufferTXN *txn,
case REORDER_BUFFER_CHANGE_UDELETE:
if (change->data.utp.oldtuple) {
OutputPluginPrepareWrite(ctx, true);
logicalrep_write_delete(ctx->out, relation, (HeapTuple)(&change->data.utp.oldtuple->tuple));
logicalrep_write_delete(ctx->out, relation, (HeapTuple)(&change->data.utp.oldtuple->tuple), data->binary);
OutputPluginWrite(ctx, true);
} else
elog(DEBUG1, "didn't send DELETE change because of missing oldtuple");
@ -605,3 +634,43 @@ static void rel_sync_cache_publication_cb(Datum arg, int cacheid, uint32 hashval
entry->pubactions.pubdelete = false;
}
}
static void GetConninfo(StringInfoData* standbysInfo)
{
bool primaryJoined = false;
StringInfoData hosts;
StringInfoData ports;
initStringInfo(&hosts);
initStringInfo(&ports);
for (int i = 1; i < MAX_REPLNODE_NUM + 1; ++i) {
t_thrd.postmaster_cxt.ReplConnChangeType[i] = 0;
if (t_thrd.postmaster_cxt.ReplConnArray[i] == NULL) {
continue;
}
if (!primaryJoined) {
appendStringInfo(&hosts, "%s,%s",
t_thrd.postmaster_cxt.ReplConnArray[i]->localhost,
t_thrd.postmaster_cxt.ReplConnArray[i]->remotehost);
appendStringInfo(&ports, "%d,%d",
t_thrd.postmaster_cxt.ReplConnArray[i]->localport,
t_thrd.postmaster_cxt.ReplConnArray[i]->remoteport);
primaryJoined = true;
} else {
appendStringInfo(&hosts, ",%s",
t_thrd.postmaster_cxt.ReplConnArray[i]->remotehost);
appendStringInfo(&ports, ",%d",
t_thrd.postmaster_cxt.ReplConnArray[i]->remoteport);
}
}
appendStringInfo(standbysInfo, "host=%s port=%s", hosts.data, ports.data);
}
static inline bool ReplconninfoChanged()
{
for (int i = 1; i < MAX_REPLNODE_NUM; ++i) {
if (t_thrd.postmaster_cxt.ReplConnChangeType[i]) {
return true;
}
}
return false;
}

View File

@ -1934,14 +1934,18 @@ ArchiveConfig* formArchiveConfigFromStr(char *content, bool encrypted)
ArchiveConnConfig* conn_config = NULL;
char* media_type = NULL;
errno_t rc = EOK;
/* SplitIdentifierString will change origin string */
char *content_copy = pstrdup(content);
char *content_copy = NULL;
char *tmp = NULL;
List* elemlist = NIL;
int param_num = 0;
size_t elem_index = 0;
archive_config = (ArchiveConfig *)palloc0(sizeof(ArchiveConfig));
char decryptSecretAccessKeyStr[DEST_CIPHER_LENGTH] = {'\0'};
if (content == NULL || strlen(content) == 0) {
goto FAILURE;
}
/* SplitIdentifierString will change origin string */
content_copy = pstrdup(content);
/* Parse string into list of identifiers */
if (!SplitIdentifierString(content_copy, ';', &elemlist, false, false)) {
goto FAILURE;

View File

@ -401,6 +401,7 @@ int WalSenderMain(void)
t_thrd.walsender_cxt.server_run_mode = t_thrd.postmaster_cxt.HaShmData->current_mode;
SetHaWalSenderChannel();
Assert(t_thrd.utils_cxt.CurrentResourceOwner != NULL);
/* Handle handshake messages before streaming */
WalSndHandshake();
@ -496,6 +497,7 @@ static void WalSndHandshake(void)
while (!repCxt.replicationStarted) {
int firstchar;
Assert(t_thrd.utils_cxt.CurrentResourceOwner != NULL);
WalSndSetState(WALSNDSTATE_STARTUP);
set_ps_display("idle", false);
@ -2033,6 +2035,8 @@ bool isLogicalSlotExist(char* slotName)
}
static void IdentifyCommand(Node* cmd_node, ReplicationCxt* repCxt, const char *cmd_string){
ResourceOwner tmpOwner = t_thrd.utils_cxt.CurrentResourceOwner;
Assert(tmpOwner != NULL);
switch (cmd_node->type) {
case T_IdentifySystemCmd:
IdentifySystem();
@ -2140,7 +2144,7 @@ static void IdentifyCommand(Node* cmd_node, ReplicationCxt* repCxt, const char *
ereport(FATAL,
(errcode(ERRCODE_PROTOCOL_VIOLATION), errmsg("invalid standby query string: %s", cmd_string)));
}
t_thrd.utils_cxt.CurrentResourceOwner = tmpOwner;
}
/*
@ -3596,8 +3600,12 @@ static int WalSndLoop(WalSndSendDataCallback send_data)
t_thrd.walsender_cxt.last_logical_xlog_advanced_timestamp = GetCurrentTimestamp();
t_thrd.walsender_cxt.waiting_for_ping_response = false;
ResourceOwner tmpOwner = t_thrd.utils_cxt.CurrentResourceOwner;
Assert(!IsTransactionOrTransactionBlock() &&
strcmp(ResourceOwnerGetName(tmpOwner), "walsender top-level resource owner") == 0);
/* Loop forever, unless we get an error */
for (;;) {
t_thrd.utils_cxt.CurrentResourceOwner = tmpOwner;
TimestampTz now;
/* Clear any already-pending wakeups */
@ -4006,6 +4014,7 @@ static int WalSndLoop(WalSndSendDataCallback send_data)
}
}
t_thrd.utils_cxt.CurrentResourceOwner = tmpOwner;
WalSndShutdown();
return 1; /* keep the compiler quiet */
}

View File

@ -394,8 +394,6 @@ void mdcreate(SMgrRelation reln, ForkNumber forkNum, bool isRedo)
}
if (fd < 0) {
int save_errno = errno;
/*
* During bootstrap, there are cases where a system relation will be
* accessed (by internal backend processes) before the bootstrap
@ -407,26 +405,7 @@ void mdcreate(SMgrRelation reln, ForkNumber forkNum, bool isRedo)
* new catalogs can by no means be used by other relations, we simply
* truncate them.
*/
if (isRedo || IsBootstrapProcessingMode() ||
(u_sess->attr.attr_common.IsInplaceUpgrade && filenode.rnode.node.relNode < FirstNormalObjectId)) {
ADIO_RUN()
{
flags = O_RDWR | PG_BINARY | O_DIRECT | (u_sess->attr.attr_common.IsInplaceUpgrade ? O_TRUNC : 0);
}
ADIO_ELSE()
{
flags = O_RDWR | PG_BINARY | (u_sess->attr.attr_common.IsInplaceUpgrade ? O_TRUNC : 0);
}
ADIO_END();
fd = DataFileIdOpenFile(path, filenode, flags, 0600);
}
if (fd < 0) {
/* be sure to report the error reported by create, not open */
errno = save_errno;
ereport(ERROR, (errcode_for_file_access(), errmsg("could not create file \"%s\": %m", path)));
}
fd = RetryDataFileIdOpenFile(isRedo, path, filenode, flags);
}
File fd_pca = -1;

View File

@ -145,6 +145,29 @@ then
plat_form_str=ubuntu18.04_"$cpu_bit"
fi
##################################################################################
# the modification here will also lead to the synchronous modification of the 3rd-party compilation library path
# PR link : https://gitee.com/opengauss/openGauss-third_party/pulls/130
# redflag platform
# the result form like this: asianux_x86_64
##################################################################################
if [ "$kernel"x = "redflag"x ]
then
plat_form_str=asianux7.6_"$cpu_bit"
fi
##################################################################################
# the modification here will also lead to the synchronous modification of the 3rd-party compilation library path
# PR link : https://gitee.com/opengauss/openGauss-third_party/pulls/130
# asianux platform
# the result form like this: asianux_aarch64
##################################################################################
if [ "$kernel"x = "asianux"x ]
then
plat_form_str=asianux7.5_"$cpu_bit"
fi
##################################################################################
#
# other platform

View File

@ -314,4 +314,5 @@ template<bool hasnull>
void UHeapFillDiskTuple(TupleDesc tupleDesc, Datum *values, const bool *isnull, UHeapDiskTupleData *diskTuple,
uint32 dataSize, bool enableReverseBitmap, bool enableReserve);
void CheckTupleValidity(Relation rel, UHeapTuple utuple);
Tuple UHeapMaterialize(TupleTableSlot *slot);
#endif

View File

@ -165,7 +165,7 @@ extern void addNewPartitionTuple(Relation pg_part_desc, Partition new_part_desc,
Datum interval, Datum maxValues, Datum transitionPoint, Datum reloptions);
extern void heap_truncate_one_part(Relation rel , Oid partOid);
extern Oid heapTupleGetPartitionId(Relation rel, void *tuple);
extern Oid heapTupleGetPartitionId(Relation rel, void *tuple, bool isDDL = false);
extern Oid heapTupleGetSubPartitionId(Relation rel, void *tuple);
extern void heap_truncate(List *relids);
extern void heap_truncate_one_rel(Relation rel);
@ -240,7 +240,7 @@ extern char* make_column_map(TupleDesc tuple_desc);
*/
extern bool* CheckPartkeyHasTimestampwithzone(Relation partTableRel, bool isForSubPartition = false);
extern Oid AddNewIntervalPartition(Relation rel, void* insertTuple);
extern Oid AddNewIntervalPartition(Relation rel, void* insertTuple, bool isDDL = false);
extern int GetIndexKeyAttsByTuple(Relation relation, HeapTuple indexTuple);

View File

@ -50,13 +50,15 @@ CATALOG(pg_subscription,6126) BKI_SHARED_RELATION BKI_ROWTYPE_OID(6128) BKI_SCHE
NameData subslotname; /* Slot name on publisher */
text subsynccommit; /* Synchronous commit setting for worker */
text subpublications[1]; /* List of publications subscribed to */
bool subbinary; /* True if the subscription wants the
* publisher to send data in binary */
#endif
}
FormData_pg_subscription;
typedef FormData_pg_subscription *Form_pg_subscription;
#define Natts_pg_subscription 8
#define Natts_pg_subscription 9
#define Anum_pg_subscription_subdbid 1
#define Anum_pg_subscription_subname 2
#define Anum_pg_subscription_subowner 3
@ -65,6 +67,7 @@ typedef FormData_pg_subscription *Form_pg_subscription;
#define Anum_pg_subscription_subslotname 6
#define Anum_pg_subscription_subsynccommit 7
#define Anum_pg_subscription_subpublications 8
#define Anum_pg_subscription_subbinary 9
typedef struct Subscription {
@ -77,6 +80,7 @@ typedef struct Subscription {
char *slotname; /* Name of the replication slot */
char *synccommit; /* Synchronous commit setting for worker */
List *publications; /* List of publication names to subscribe to */
bool binary; /* Indicates if the subscription wants data in binary format */
} Subscription;
@ -86,6 +90,7 @@ extern Oid get_subscription_oid(const char *subname, bool missing_ok);
extern char *get_subscription_name(Oid subid, bool missing_ok);
extern int CountDBSubscriptions(Oid dbid);
extern char *DecryptConninfo(char *encryptConninfo);
extern void ClearListContent(List *list);
#endif /* PG_SUBSCRIPTION_H */

View File

@ -17,6 +17,11 @@
#include "nodes/parsenodes.h"
typedef struct HostPort {
char* host;
char* port;
} HostPort;
extern ObjectAddress CreateSubscription(CreateSubscriptionStmt *stmt, bool isTopLevel);
extern ObjectAddress AlterSubscription(AlterSubscriptionStmt *stmt);
extern void DropSubscription(DropSubscriptionStmt *stmt, bool isTopLevel);
@ -24,6 +29,12 @@ extern void DropSubscription(DropSubscriptionStmt *stmt, bool isTopLevel);
extern ObjectAddress AlterSubscriptionOwner(const char *name, Oid newOwnerId);
extern void AlterSubscriptionOwner_oid(Oid subid, Oid newOwnerId);
extern void RenameSubscription(List* oldname, const char* newname);
extern void AddStandbysInfo(char* standbysInfo);
extern void DropStandbysInfo(char* standbysInfo);
extern void ParseConninfo(const char* conninfo, StringInfoData* conninfoWithoutHostPort, HostPort** hostPortList);
extern char* EncryptOrDecryptConninfo(const char* conninfo, const char action);
extern bool AttemptConnectPublisher(const char *conninfoOriginal, char* slotname, bool checkRemoteMode);
#endif /* SUBSCRIPTIONCMDS_H */

View File

@ -238,7 +238,7 @@ typedef struct knl_session_attr_sql {
#ifndef ENABLE_MULTIPLE_NODES
bool enable_custom_parser;
#endif
bool b_sql_plugin;
bool dolphin;
} knl_session_attr_sql;
#endif /* SRC_INCLUDE_KNL_KNL_SESSION_ATTR_SQL */

View File

@ -90,6 +90,7 @@ extern const uint32 SUPPORT_DATA_REPAIR;
extern const uint32 SCAN_BATCH_MODE_VERSION_NUM;
extern const uint32 RELMAP_4K_VERSION_NUM;
extern const uint32 PUBLICATION_VERSION_NUM;
extern const uint32 SUBSCRIPTION_BINARY_VERSION_NUM;
extern const uint32 ANALYZER_HOOK_VERSION_NUM;
extern const uint32 SUPPORT_HASH_XLOG_VERSION_NUM;
extern const uint32 PITR_INIT_VERSION_NUM;

View File

@ -35,6 +35,7 @@ typedef struct LibpqrcvConnectParam {
bool logical;
uint32 protoVersion; /* Logical protocol version */
List *publicationNames; /* String list of publications */
bool binary; /* Ask publisher to use binary */
}LibpqrcvConnectParam;
extern int32 pg_atoi(char* s, int size, int c);
@ -53,5 +54,6 @@ extern bool libpqrcv_command(const char *cmd, char **err, int *sqlstate);
extern void IdentifyRemoteSystem(bool checkRemote);
extern void CreateRemoteReplicationSlot(XLogRecPtr startpoint, const char* slotname, bool isLogical);
extern void StartRemoteStreaming(const LibpqrcvConnectParam *options);
extern ServerMode IdentifyRemoteMode();
#endif

View File

@ -31,6 +31,7 @@
#include "access/extreme_rto/spsc_blocking_queue.h"
#include "access/parallel_recovery/redo_item.h"
#include "nodes/parsenodes_common.h"
#include "nodes/replnodes.h"
#include "access/ustore/knl_utuple.h"
#include "replication/logical_queue.h"

View File

@ -35,12 +35,21 @@
* Keep in mind that the columns correspond to the *remote* table.
*/
typedef struct LogicalRepTupleData {
char *values[MaxTupleAttributeNumber]; /* value in out function format or NULL if values is NULL */
bool changed[MaxTupleAttributeNumber]; /* marker for changed/unchanged values */
/* Array of StringInfos, one per column; some may be unused */
StringInfoData *colvalues;
/* Array of markers for null/unchanged/text/binary, one per column */
char *colstatus;
/* Length of above arrays */
int ncols;
} LogicalRepTupleData;
/* Possible values for LogicalRepTupleData.colstatus[colnum] */
/* These values are also used in the on-the-wire protocol */
#define LOGICALREP_COLUMN_NULL 'n'
#define LOGICALREP_COLUMN_UNCHANGED 'u'
#define LOGICALREP_COLUMN_TEXT 't'
#define LOGICALREP_COLUMN_BINARY 'b' /* added in PG14 */
typedef uint32 LogicalRepRelId;
/* Relation information */
@ -81,16 +90,18 @@ extern void logicalrep_read_begin(StringInfo in, LogicalRepBeginData *begin_data
extern void logicalrep_write_commit(StringInfo out, ReorderBufferTXN *txn, XLogRecPtr commit_lsn);
extern void logicalrep_read_commit(StringInfo in, LogicalRepCommitData *commit_data);
extern void logicalrep_write_origin(StringInfo out, const char *origin, XLogRecPtr origin_lsn);
extern void logicalrep_write_insert(StringInfo out, Relation rel, HeapTuple newtuple);
extern void logicalrep_write_insert(StringInfo out, Relation rel, HeapTuple newtuple, bool binary);
extern LogicalRepRelId logicalrep_read_insert(StringInfo in, LogicalRepTupleData *newtup);
extern void logicalrep_write_update(StringInfo out, Relation rel, HeapTuple oldtuple, HeapTuple newtuple);
extern void logicalrep_write_update(StringInfo out, Relation rel, HeapTuple oldtuple, HeapTuple newtuple, bool binary);
extern LogicalRepRelId logicalrep_read_update(StringInfo in, bool *has_oldtuple, LogicalRepTupleData *oldtup,
LogicalRepTupleData *newtup);
extern void logicalrep_write_delete(StringInfo out, Relation rel, HeapTuple oldtuple);
extern void logicalrep_write_delete(StringInfo out, Relation rel, HeapTuple oldtuple, bool binary);
extern LogicalRepRelId logicalrep_read_delete(StringInfo in, LogicalRepTupleData *oldtup);
extern void logicalrep_write_rel(StringInfo out, Relation rel);
extern LogicalRepRelation *logicalrep_read_rel(StringInfo in);
extern void logicalrep_write_typ(StringInfo out, Oid typoid);
extern void logicalrep_read_typ(StringInfo out, LogicalRepTyp *ltyp);
extern void logicalrep_write_conninfo(StringInfo out, char* conninfo);
extern void logicalrep_read_conninfo(StringInfo in, char** conninfo);
#endif /* LOGICALREP_PROTO_H */

View File

@ -13,5 +13,6 @@
#define LOGICALWORKER_H
extern void ApplyWorkerMain();
extern bool IsLogicalWorker(void);
#endif /* LOGICALWORKER_H */

View File

@ -24,6 +24,7 @@ typedef struct PGOutputData {
List *publication_names;
List *publications;
bool binary;
} PGOutputData;
#endif /* PGOUTPUT_H */

View File

@ -229,10 +229,15 @@ private:
bool m_syscache_relids[FirstNormalObjectId];
};
void NotifyGscRecoveryStarted();
void NotifyGscRecoveryFinished();
extern Datum gs_gsc_dbstat_info(PG_FUNCTION_ARGS);
extern Datum gs_gsc_clean(PG_FUNCTION_ARGS);
extern Datum gs_gsc_catalog_detail(PG_FUNCTION_ARGS);
extern Datum gs_gsc_table_detail(PG_FUNCTION_ARGS);
extern int ResizeHashBucket(int origin_nbucket, DynamicHashBucketStrategy strategy);
#endif
/* only primary node check recovery, recovery from upgrade may have misorder cacheids */
#define IsPrimaryRecoveryFinished() \
(g_instance.global_sysdbcache.recovery_finished || t_thrd.postmaster_cxt.HaShmData->current_mode == STANDBY_MODE)
#endif

View File

@ -213,7 +213,7 @@ extern bool check_rel_is_partitioned(Oid relid);
extern Oid partid_get_parentid(Oid partid);
extern bool is_not_strict_agg(Oid funcOid);
extern bool is_pgxc_class_table(Oid tableoid);
extern Oid get_valid_relname_relid(const char* relnamespace, const char* relname);
extern Oid get_valid_relname_relid(const char* relnamespace, const char* relname, bool nsp_missing_ok = false);
extern bool get_func_iswindow(Oid funcid);
extern char get_func_prokind(Oid funcid);
extern char get_typecategory(Oid typid);

View File

@ -1385,6 +1385,8 @@ typedef struct PlDebugEntry {
PLpgSQL_function* func;
} PlDebugEntry;
typedef List* (*RawParserHook)(const char*, List**);
const int MAXINT8LEN = 25;
const int DEFAULT_DEBUG_BUF_SIZE = 1024;
const long NANOSECOND_PER_SECOND = 1000000000L; /* 1s */

View File

@ -0,0 +1,37 @@
--
-- check for over-optimization of whole-row Var referencing an Append plan
--
create table int4_test(f1 int4);
select (select q from (select 1,2,3 where f1>0 union all select 4,5,6 where f1<=0) q) from int4_test;
q
---
(0 rows)
select (select q from (select 1,2,3 where f1>0 union all select 4,5,6.0 where f1<=0) q) from int4_test;
q
---
(0 rows)
insert into int4_test(f1) values(' 0 ');
insert into int4_test(f1) values('123456 ');
select * from int4_test;
f1
--------
0
123456
(2 rows)
select (select q from (select 1,2,3 where f1>0 union all select 4,5,6 where f1<=0) q) from int4_test;
q
---------
(4,5,6)
(1,2,3)
(2 rows)
select (select q from (select 1,2,3 where f1>0 union all select 4,5,6.0 where f1<=0) q) from int4_test;
q
-----------
(4,5,6.0)
(1,2,3)
(2 rows)

View File

@ -0,0 +1,116 @@
create schema deserialize_func1;
set current_schema = deserialize_func1;
create sequence test_seq;
create or replace function test_func() return int
as
begin
return 1;
end;
/
create table t1(key int, id int default nextval('test_seq'));
create table t2(key int, id int default test_func());
select * from pg_get_tabledef('deserialize_func1.t1');
pg_get_tabledef
------------------------------------------------------
SET search_path = deserialize_func1; +
CREATE TABLE t1 ( +
key integer, +
id integer DEFAULT nextval('test_seq'::regclass)+
) +
WITH (orientation=row, compression=no);
(1 row)
select * from pg_get_tabledef('deserialize_func1.t2');
pg_get_tabledef
-----------------------------------------
SET search_path = deserialize_func1; +
CREATE TABLE t2 ( +
key integer, +
id integer DEFAULT test_func() +
) +
WITH (orientation=row, compression=no);
(1 row)
alter schema deserialize_func1 rename to deserialize_func2;
select * from pg_get_tabledef('deserialize_func2.t1');
pg_get_tabledef
------------------------------------------------------------------------
SET search_path = deserialize_func2; +
CREATE TABLE t1 ( +
key integer, +
id integer DEFAULT nextval('deserialize_func2.test_seq'::regclass)+
) +
WITH (orientation=row, compression=no);
(1 row)
select * from pg_get_tabledef('deserialize_func2.t2');
pg_get_tabledef
------------------------------------------------------
SET search_path = deserialize_func2; +
CREATE TABLE t2 ( +
key integer, +
id integer DEFAULT deserialize_func2.test_func()+
) +
WITH (orientation=row, compression=no);
(1 row)
alter table deserialize_func2.t1 alter column id drop default;
alter table deserialize_func2.t1 alter column id set default nextval('deserialize_func2.test_seq');
select * from pg_get_tabledef('deserialize_func2.t1');
pg_get_tabledef
------------------------------------------------------------------------
SET search_path = deserialize_func2; +
CREATE TABLE t1 ( +
key integer, +
id integer DEFAULT nextval('deserialize_func2.test_seq'::regclass)+
) +
WITH (orientation=row, compression=no);
(1 row)
alter table deserialize_func2.t2 alter column id drop default;
alter table deserialize_func2.t2 alter column id set default deserialize_func2.test_func();
select * from pg_get_tabledef('deserialize_func2.t2');
pg_get_tabledef
------------------------------------------------------
SET search_path = deserialize_func2; +
CREATE TABLE t2 ( +
key integer, +
id integer DEFAULT deserialize_func2.test_func()+
) +
WITH (orientation=row, compression=no);
(1 row)
set current_schema = deserialize_func2;
create type type1 as (a int);
create view v1 as select '(1)'::type1;
alter type type1 rename to type2;
select pg_get_viewdef('v1');
pg_get_viewdef
-------------------------------
SELECT '(1)'::type2 AS type1;
(1 row)
drop view v1 cascade;
create table atest12 as select x as a, 10001-x as b from generate_series(1, 10000) x;
create function func1(integer, integer) returns boolean as $$begin return $1 < $2; end $$ language plpgsql immutable;
create operator <<< (procedure=func1, leftarg=integer, rightarg=integer, restrict=scalarltsel);
create view atest12v as select * from atest12 where b <<< 5;
select pg_get_viewdef('atest12v');
pg_get_viewdef
-------------------------------------------------
SELECT * FROM atest12 WHERE (atest12.b <<< 5);
(1 row)
drop schema if exists deserialize_func1 cascade;
NOTICE: schema "deserialize_func1" does not exist, skipping
drop schema if exists deserialize_func2 cascade;
NOTICE: drop cascades to 9 other objects
DETAIL: drop cascades to sequence test_seq
drop cascades to function test_func()
drop cascades to table t1
drop cascades to table t2
drop cascades to type type2
drop cascades to table atest12
drop cascades to function func1(integer,integer)
drop cascades to operator <<<(integer,integer)
drop cascades to view atest12v

View File

@ -132,11 +132,14 @@ DROP EXTENSION test_extension_exists;
ERROR: extension "test_extension_exists" does not exist
DROP EXTENSION IF EXISTS test_extension_exists;
NOTICE: extension "test_extension_exists" does not exist, skipping
-- exists but doesn't support drop
DROP EXTENSION plpgsql;
ERROR: EXTENSION is not yet supported.
DROP EXTENSION IF EXISTS plpgsql;
ERROR: EXTENSION is not yet supported.
-- only extension in white list support drop, but the guc support_extended_features is true in pg_regress mode, so hdfs_fdw can be droped
CREATE DATABASE ext_test_db;
\c ext_test_db
DROP EXTENSION hdfs_fdw;
DROP EXTENSION IF EXISTS hdfs_fdw;
NOTICE: extension "hdfs_fdw" does not exist, skipping
\c regression
DROP DATABASE ext_test_db;
-- functions
DROP FUNCTION test_function_exists();
ERROR: function test_function_exists does not exist

View File

@ -215,3 +215,107 @@ select * from interval_normal_exchange where logdate > '2020-06-01' order by log
(0 rows)
drop table interval_normal_exchange;
drop table table_001;
ERROR: table "table_001" does not exist
create table table_001(
COL_1 smallint,
COL_2 char(5),
COL_3 int,
COL_4 date,
COL_5 boolean,
COL_6 nchar(5),
COL_7 float
);
drop table partition_table_001;
ERROR: table "partition_table_001" does not exist
create table partition_table_001(
COL_1 smallint,
COL_2 char(5),
COL_3 int,
COL_4 date,
COL_5 boolean,
COL_6 nchar(5),
COL_7 float
)
PARTITION BY RANGE (COL_4)
INTERVAL ('1 month')
(
PARTITION partition_table_001_p1 VALUES LESS THAN ('2020-03-01'),
PARTITION partition_table_001_p2 VALUES LESS THAN ('2020-04-01'),
PARTITION partition_table_001_p3 VALUES LESS THAN ('2020-05-01')
);
insert into partition_table_001 values (1,'aaa',1,'2020-02-23',true,'aaa',1.1);
insert into partition_table_001 values (2,'bbb',2,'2020-03-23',false,'bbb',2.2);
insert into partition_table_001 values (3,'ccc',3,'2020-04-23',true,'ccc',3.3);
insert into partition_table_001 values (4,'ddd',4,'2020-05-23',false,'ddd',4.4);
insert into partition_table_001 values (5,'eee',5,'2020-06-23',true,'eee',5.5);
insert into partition_table_001 values (6,'fff',6,'2020-07-23',false,'fff',6.6);
ALTER TABLE partition_table_001 EXCHANGE PARTITION (sys_p1) WITH TABLE table_001;
select * from table_001 order by 1;
col_1 | col_2 | col_3 | col_4 | col_5 | col_6 | col_7
-------+-------+-------+--------------------------+-------+-------+-------
4 | ddd | 4 | Sat May 23 00:00:00 2020 | f | ddd | 4.4
(1 row)
select * from partition_table_001 order by 1;
col_1 | col_2 | col_3 | col_4 | col_5 | col_6 | col_7
-------+-------+-------+--------------------------+-------+-------+-------
1 | aaa | 1 | Sun Feb 23 00:00:00 2020 | t | aaa | 1.1
2 | bbb | 2 | Mon Mar 23 00:00:00 2020 | f | bbb | 2.2
3 | ccc | 3 | Thu Apr 23 00:00:00 2020 | t | ccc | 3.3
5 | eee | 5 | Tue Jun 23 00:00:00 2020 | t | eee | 5.5
6 | fff | 6 | Thu Jul 23 00:00:00 2020 | f | fff | 6.6
(5 rows)
select relname, parttype, partstrategy, boundaries from pg_partition
where parentid = (select oid from pg_class where relname = 'partition_table_001')
order by relname;
relname | parttype | partstrategy | boundaries
------------------------+----------+--------------+------------------------------
partition_table_001 | r | i |
partition_table_001_p1 | p | r | {2020-03-01}
partition_table_001_p2 | p | r | {2020-04-01}
partition_table_001_p3 | p | r | {2020-05-01}
sys_p1 | p | i | {"Mon Jun 01 00:00:00 2020"}
sys_p2 | p | i | {"Wed Jul 01 00:00:00 2020"}
sys_p3 | p | i | {"Sat Aug 01 00:00:00 2020"}
(7 rows)
ALTER TABLE partition_table_001 EXCHANGE PARTITION (sys_p1) WITH TABLE table_001;
select * from table_001 order by 1;
col_1 | col_2 | col_3 | col_4 | col_5 | col_6 | col_7
-------+-------+-------+-------+-------+-------+-------
(0 rows)
select * from partition_table_001 order by 1;
col_1 | col_2 | col_3 | col_4 | col_5 | col_6 | col_7
-------+-------+-------+--------------------------+-------+-------+-------
1 | aaa | 1 | Sun Feb 23 00:00:00 2020 | t | aaa | 1.1
2 | bbb | 2 | Mon Mar 23 00:00:00 2020 | f | bbb | 2.2
3 | ccc | 3 | Thu Apr 23 00:00:00 2020 | t | ccc | 3.3
4 | ddd | 4 | Sat May 23 00:00:00 2020 | f | ddd | 4.4
5 | eee | 5 | Tue Jun 23 00:00:00 2020 | t | eee | 5.5
6 | fff | 6 | Thu Jul 23 00:00:00 2020 | f | fff | 6.6
(6 rows)
insert into table_001 values (7,'eee',7,'2020-08-23',true,'eee',7.7);
ALTER TABLE partition_table_001 EXCHANGE PARTITION (sys_p1) WITH TABLE table_001 with validation verbose;
select * from table_001 order by 1;
col_1 | col_2 | col_3 | col_4 | col_5 | col_6 | col_7
-------+-------+-------+--------------------------+-------+-------+-------
4 | ddd | 4 | Sat May 23 00:00:00 2020 | f | ddd | 4.4
(1 row)
select * from partition_table_001 order by 1;
col_1 | col_2 | col_3 | col_4 | col_5 | col_6 | col_7
-------+-------+-------+--------------------------+-------+-------+-------
1 | aaa | 1 | Sun Feb 23 00:00:00 2020 | t | aaa | 1.1
2 | bbb | 2 | Mon Mar 23 00:00:00 2020 | f | bbb | 2.2
3 | ccc | 3 | Thu Apr 23 00:00:00 2020 | t | ccc | 3.3
5 | eee | 5 | Tue Jun 23 00:00:00 2020 | t | eee | 5.5
6 | fff | 6 | Thu Jul 23 00:00:00 2020 | f | fff | 6.6
7 | eee | 7 | Sun Aug 23 00:00:00 2020 | t | eee | 7.7
(6 rows)
drop table table_001;
drop table partition_table_001;

View File

@ -0,0 +1,55 @@
CREATE TABLE t11 (
sec_code character(6) NOT NULL,
issue_type character(3) NOT NULL
);
CREATE TABLE t22 (
company_code character(6) NOT NULL,
list_profit_flag character(1) NOT NULL
);
CREATE TABLE t33 (
company_code character(6) NOT NULL,
issue_flag character(6) NOT NULL
);
insert into t11 values(1,'S04');
insert into t22 values(1,'Y');
insert into t33 values(1,'1');
insert into t33 values(2,'2');
select
T5.issue_type
,T6.is_type
from
(
select T1.sec_code
,issue_type
--,case when list_profit_flag='Y' then '是' else '否' end as list_profit_flag
from
(
select sec_code
,case when issue_type in ('S04','S05','S06','S09') then '增发'
when issue_type in ('S01','S02') then '首发'
else '其他' end as issue_type
from t11
)T1
left join
(
select list_profit_flag
,company_code
from t22
)T2
on T1.sec_code=T2.company_code
)T5
full join
(
SELECT CASE
WHEN issue_flag = ANY (ARRAY['1'::bpchar, '3'::bpchar, '11'::bpchar]) THEN '首发'::text
ELSE '增发'::text
END AS is_type from t33
)T6
on T5.issue_type=T6.is_type
;
issue_type | is_type
------------+---------
增发 | 增发
| 首发
(2 rows)

View File

@ -89,5 +89,8 @@ ERROR: Can not use compress option in ustore index.
-- segment
CREATE TABLE unspported_feature.segment_table(id int, c1 text) WITH(compresstype=2, segment=on); --failed
ERROR: only row orientation table support compresstype.
CREATE INDEX on unspported_feature.index_test(c1) WITH(compresstype=2, segment=on); --faled
CREATE INDEX on unspported_feature.index_test(c1) WITH(compresstype=2, segment=on); --failed
ERROR: Can not use compress option in segment storage.
-- set compress_diff_convert
create table unspported_feature.compress_byte_test(id int) with (compresstype=2, compress_byte_convert=false, compress_diff_convert = true); -- failed
ERROR: compress_diff_convert should be used with compress_byte_convert.

View File

@ -1062,6 +1062,73 @@ select /*+ indexscan(tg_hash i_tg_hash_local_a) */ * from tg_hash where a < 9;
(81 rows)
drop table tg_hash;
drop table if exists test_ugi_045;
NOTICE: table "test_ugi_045" does not exist, skipping
create table test_ugi_045
(
c_id integer not null,
c_date DATE,
c_info varchar(20) not null
)
partition by range(c_date)
interval('2 day')
(
partition p1 values less than ('2021-06-01 00:00:00'),
partition p2 values less than ('2021-06-03 00:00:00'),
partition p3 values less than ('2021-06-05 00:00:00'),
partition p4 values less than ('2021-06-07 00:00:00'),
partition p5 values less than ('2021-06-09 00:00:00')
);
insert into test_ugi_045(c_id, c_date, c_info) values(1, '2021-05-30 00:00:00', '1-1');
insert into test_ugi_045(c_id, c_date, c_info) values(2, '2021-05-31 00:00:00', '1-1');
insert into test_ugi_045(c_id, c_date, c_info) values(3, '2021-06-01 00:00:00', '1-1');
insert into test_ugi_045(c_id, c_date, c_info) values(4, '2021-06-02 00:00:00', '1-2');
insert into test_ugi_045(c_id, c_date, c_info) values(5, '2021-06-03 00:00:00', '1-2');
insert into test_ugi_045(c_id, c_date, c_info) values(6, '2021-06-04 00:00:00', '1-3');
insert into test_ugi_045(c_id, c_date, c_info) values(7, '2021-06-05 00:00:00', '1-3');
insert into test_ugi_045(c_id, c_date, c_info) values(8, '2021-06-06 00:00:00', '1-4');
insert into test_ugi_045(c_id, c_date, c_info) values(9, '2021-06-07 00:00:00', '1-4');
insert into test_ugi_045(c_id, c_date, c_info) values(10, '2021-06-08 00:00:00', '1-5');
create index global_index_id_045 on test_ugi_045(c_date) global;
create index global_index_info_045 on test_ugi_045(c_info) global;
select *from test_ugi_045;
c_id | c_date | c_info
------+---------------------+--------
1 | 2021-05-30 00:00:00 | 1-1
2 | 2021-05-31 00:00:00 | 1-1
3 | 2021-06-01 00:00:00 | 1-1
4 | 2021-06-02 00:00:00 | 1-2
5 | 2021-06-03 00:00:00 | 1-2
6 | 2021-06-04 00:00:00 | 1-3
7 | 2021-06-05 00:00:00 | 1-3
8 | 2021-06-06 00:00:00 | 1-4
9 | 2021-06-07 00:00:00 | 1-4
10 | 2021-06-08 00:00:00 | 1-5
(10 rows)
alter table test_ugi_045 truncate partition p3 update global index;
set enable_seqscan = off;
set enable_bitmapscan = off;
select *from test_ugi_045;
c_id | c_date | c_info
------+---------------------+--------
1 | 2021-05-30 00:00:00 | 1-1
2 | 2021-05-31 00:00:00 | 1-1
3 | 2021-06-01 00:00:00 | 1-1
4 | 2021-06-02 00:00:00 | 1-2
7 | 2021-06-05 00:00:00 | 1-3
8 | 2021-06-06 00:00:00 | 1-4
9 | 2021-06-07 00:00:00 | 1-4
10 | 2021-06-08 00:00:00 | 1-5
(8 rows)
select *from test_ugi_045 where c_info = '1-2';
c_id | c_date | c_info
------+---------------------+--------
4 | 2021-06-02 00:00:00 | 1-2
(1 row)
drop table if exists test_ugi_045;
-- 清理过程
drop view check_truncate_results;
drop materialized view pg_partition_before_truncate;

View File

@ -24,6 +24,7 @@ CREATE SUBSCRIPTION testsub CONNECTION 'foo';
CREATE SUBSCRIPTION testsub PUBLICATION foo;
-- fail - could not connect to the publisher
create subscription testsub2 connection 'host=abc' publication pub;
create subscription testsub2 connection 'host=abc port=12345' publication pub;
set client_min_messages to error;
-- fail - syntax error, invalid connection string syntax: missing "="
CREATE SUBSCRIPTION testsub CONNECTION 'testconn' PUBLICATION testpub;
@ -32,12 +33,15 @@ CREATE SUBSCRIPTION testsub CONNECTION 'dbname=doesnotexist' PUBLICATION testpub
CREATE SUBSCRIPTION testsub CONNECTION 'dbname=doesnotexist' PUBLICATION testpub WITH (ENABLED=false, slot_name='testsub', synchronous_commit=off);
-- create SUBSCRIPTION with conninfo in two single quote, used to check mask string bug
CREATE SUBSCRIPTION testsub_maskconninfo CONNECTION 'host=''1.2.3.4'' port=''12345'' user=''username'' dbname=''postgres'' password=''password_1234''' PUBLICATION testpub WITH (ENABLED=false, slot_name='testsub', synchronous_commit=off);
-- fail - The number of host and port are inconsistent
create subscription sub1 connection 'dbname=postgres user=pubusr password=Huawei@123 host=192.168.0.38,192.168.0.38,192.168.0.38 port=14001,14501' publication pub1;
-- fail - a maximum of 9 servers are supported
create subscription sub1 connection 'dbname=postgres user=pubusr password=Huawei@123 host=192.168.0.38,192.168.0.38,192.168.0.38,192.168.0.38,192.168.0.38,192.168.0.38,192.168.0.38,192.168.0.38,192.168.0.38,192.168.0.38 port=14001,14501' publication pub1;
-- alter connection
ALTER SUBSCRIPTION testsub CONNECTION 'host=''1.2.3.4'' port=''12345'' user=''username'' dbname=''postgres'' password=''password_1234''';
ALTER SUBSCRIPTION testsub CONNECTION 'dbname=does_not_exist';
reset client_min_messages;
select subname, pg_get_userbyid(subowner) as Owner, subenabled, subconninfo, subpublications from pg_subscription where subname='testsub';
select subname, pg_get_userbyid(subowner) as Owner, subenabled, subconninfo, subpublications, subbinary from pg_subscription where subname='testsub';
--- alter subscription
------ set publication
ALTER SUBSCRIPTION testsub SET PUBLICATION testpub2, testpub3;
@ -57,6 +61,9 @@ select subname, subenabled, subsynccommit from pg_subscription where subname='t
ALTER SUBSCRIPTION testsub SET (slot_name='testsub');
-- alter owner
ALTER SUBSCRIPTION testsub owner to regress_subscription_user2;
-- alter subbinary to true
ALTER SUBSCRIPTION testsub SET (binary=true);
select subname, subbinary from pg_subscription where subname='testsub';
--rename
ALTER SUBSCRIPTION testsub rename to testsub_rename;
--- inside a transaction block

View File

@ -60,8 +60,10 @@ LINE 1: CREATE SUBSCRIPTION testsub PUBLICATION foo;
^
-- fail - could not connect to the publisher
create subscription testsub2 connection 'host=abc' publication pub;
ERROR: The number of host and port are inconsistent.
create subscription testsub2 connection 'host=abc port=12345' publication pub;
WARNING: apply worker could not connect to the remote server
ERROR: could not connect to the publisher
ERROR: Failed to connect to publisher.
set client_min_messages to error;
-- fail - syntax error, invalid connection string syntax: missing "="
CREATE SUBSCRIPTION testsub CONNECTION 'testconn' PUBLICATION testpub;
@ -72,14 +74,20 @@ ERROR: unrecognized subscription parameter: create_slot
CREATE SUBSCRIPTION testsub CONNECTION 'dbname=doesnotexist' PUBLICATION testpub WITH (ENABLED=false, slot_name='testsub', synchronous_commit=off);
-- create SUBSCRIPTION with conninfo in two single quote, used to check mask string bug
CREATE SUBSCRIPTION testsub_maskconninfo CONNECTION 'host=''1.2.3.4'' port=''12345'' user=''username'' dbname=''postgres'' password=''password_1234''' PUBLICATION testpub WITH (ENABLED=false, slot_name='testsub', synchronous_commit=off);
-- fail - The number of host and port are inconsistent
create subscription sub1 connection 'dbname=postgres user=pubusr password=Huawei@123 host=192.168.0.38,192.168.0.38,192.168.0.38 port=14001,14501' publication pub1;
ERROR: The number of host and port are inconsistent.
-- fail - a maximum of 9 servers are supported
create subscription sub1 connection 'dbname=postgres user=pubusr password=Huawei@123 host=192.168.0.38,192.168.0.38,192.168.0.38,192.168.0.38,192.168.0.38,192.168.0.38,192.168.0.38,192.168.0.38,192.168.0.38,192.168.0.38 port=14001,14501' publication pub1;
ERROR: Currently, a maximum of 9 servers are supported.
-- alter connection
ALTER SUBSCRIPTION testsub CONNECTION 'host=''1.2.3.4'' port=''12345'' user=''username'' dbname=''postgres'' password=''password_1234''';
ALTER SUBSCRIPTION testsub CONNECTION 'dbname=does_not_exist';
reset client_min_messages;
select subname, pg_get_userbyid(subowner) as Owner, subenabled, subconninfo, subpublications from pg_subscription where subname='testsub';
subname | owner | subenabled | subconninfo | subpublications
---------+---------------------------+------------+------------------------+-----------------
testsub | regress_subscription_user | f | dbname=does_not_exist | {testpub}
select subname, pg_get_userbyid(subowner) as Owner, subenabled, subconninfo, subpublications, subbinary from pg_subscription where subname='testsub';
subname | owner | subenabled | subconninfo | subpublications | subbinary
---------+---------------------------+------------+------------------------+-----------------+-----------
testsub | regress_subscription_user | f | dbname=does_not_exist | {testpub} | f
(1 row)
--- alter subscription
@ -122,6 +130,14 @@ ALTER SUBSCRIPTION testsub SET (slot_name='testsub');
ERROR: Currently enabled=false, cannot change slot_name to a non-null value.
-- alter owner
ALTER SUBSCRIPTION testsub owner to regress_subscription_user2;
-- alter subbinary to true
ALTER SUBSCRIPTION testsub SET (binary=true);
select subname, subbinary from pg_subscription where subname='testsub';
subname | subbinary
---------+-----------
testsub | t
(1 row)
--rename
ALTER SUBSCRIPTION testsub rename to testsub_rename;
--- inside a transaction block
@ -134,8 +150,7 @@ COMMIT;
-- -- active SUBSCRIPTION
BEGIN;
ALTER SUBSCRIPTION testsub_rename ENABLE;
WARNING: apply worker could not connect to the remote server
ERROR: could not connect to the publisher
ERROR: invalid connection string syntax, missing host and port
select subname, subenabled from pg_subscription where subname='testsub_rename';
ERROR: current transaction is aborted, commands ignored until end of transaction block, firstChar[Q]
ALTER SUBSCRIPTION testsub_rename SET (ENABLED=false);
@ -281,10 +296,11 @@ SELECT object_name,detail_info FROM pg_query_audit('2022-01-13 9:30:00', '2031-1
testsub_maskconninfo | ALTER SUBSCRIPTION testsub_maskconninfo SET (conninfo='*************************************************************************************************************************;
testsub | ALTER SUBSCRIPTION testsub SET (synchronous_commit=on);
testsub | ALTER SUBSCRIPTION testsub owner to regress_subscription_user2;
testsub | ALTER SUBSCRIPTION testsub SET (binary=true);
testsub | ALTER SUBSCRIPTION testsub rename to testsub_rename;
testsub_rename | DROP SUBSCRIPTION IF EXISTS testsub_rename;
testsub_maskconninfo | DROP SUBSCRIPTION IF EXISTS testsub_maskconninfo;
(14 rows)
(15 rows)
--clear audit log
SELECT pg_delete_audit('1012-11-10', '3012-11-11');

View File

@ -25,7 +25,7 @@ test: pldeveloper_gs_source
test: index_advisor
test: pl_debugger_server pl_debugger_client
test: update_for_wait_s1 update_for_wait_s2
test: plan_hint plan_hint_set plan_hint_no_expand plan_hint_iud null_test_opt
test: plan_hint plan_hint_set plan_hint_no_expand plan_hint_iud null_test_opt deserialize_func
test: large_sequence int16 gs_dump_sequence
test: gs_dump_tableof
test: analyze_commands
@ -916,3 +916,5 @@ test: fdw_audit
test: gs_global_config_audit
test: detail
test: gs_dump_encrypt
test: composite_datum_record
test: join_test_alias

View File

@ -5238,7 +5238,7 @@ static void check_global_variables()
}
}
#define BASE_PGXC_LIKE_MACRO_NUM 1401
#define BASE_PGXC_LIKE_MACRO_NUM 1402
static void check_pgxc_like_macros()
{
#ifdef BUILD_BY_CMAKE

View File

@ -0,0 +1,11 @@
--
-- check for over-optimization of whole-row Var referencing an Append plan
--
create table int4_test(f1 int4);
select (select q from (select 1,2,3 where f1>0 union all select 4,5,6 where f1<=0) q) from int4_test;
select (select q from (select 1,2,3 where f1>0 union all select 4,5,6.0 where f1<=0) q) from int4_test;
insert into int4_test(f1) values(' 0 ');
insert into int4_test(f1) values('123456 ');
select * from int4_test;
select (select q from (select 1,2,3 where f1>0 union all select 4,5,6 where f1<=0) q) from int4_test;
select (select q from (select 1,2,3 where f1>0 union all select 4,5,6.0 where f1<=0) q) from int4_test;

View File

@ -0,0 +1,63 @@
create schema deserialize_func1;
set current_schema = deserialize_func1;
create sequence test_seq;
create or replace function test_func() return int
as
begin
return 1;
end;
/
create table t1(key int, id int default nextval('test_seq'));
create table t2(key int, id int default test_func());
select * from pg_get_tabledef('deserialize_func1.t1');
select * from pg_get_tabledef('deserialize_func1.t2');
alter schema deserialize_func1 rename to deserialize_func2;
select * from pg_get_tabledef('deserialize_func2.t1');
select * from pg_get_tabledef('deserialize_func2.t2');
alter table deserialize_func2.t1 alter column id drop default;
alter table deserialize_func2.t1 alter column id set default nextval('deserialize_func2.test_seq');
select * from pg_get_tabledef('deserialize_func2.t1');
alter table deserialize_func2.t2 alter column id drop default;
alter table deserialize_func2.t2 alter column id set default deserialize_func2.test_func();
select * from pg_get_tabledef('deserialize_func2.t2');
set current_schema = deserialize_func2;
create type type1 as (a int);
create view v1 as select '(1)'::type1;
alter type type1 rename to type2;
select pg_get_viewdef('v1');
drop view v1 cascade;
create table atest12 as select x as a, 10001-x as b from generate_series(1, 10000) x;
create function func1(integer, integer) returns boolean as $$begin return $1 < $2; end $$ language plpgsql immutable;
create operator <<< (procedure=func1, leftarg=integer, rightarg=integer, restrict=scalarltsel);
create view atest12v as select * from atest12 where b <<< 5;
select pg_get_viewdef('atest12v');
drop schema if exists deserialize_func1 cascade;
drop schema if exists deserialize_func2 cascade;

View File

@ -145,9 +145,13 @@ DROP TEXT SEARCH CONFIGURATION test_tsconfig_exists;
-- doesn't exists
DROP EXTENSION test_extension_exists;
DROP EXTENSION IF EXISTS test_extension_exists;
-- exists but doesn't support drop
DROP EXTENSION plpgsql;
DROP EXTENSION IF EXISTS plpgsql;
-- only extension in white list support drop, but the guc support_extended_features is true in pg_regress mode, so hdfs_fdw can be droped
CREATE DATABASE ext_test_db;
\c ext_test_db
DROP EXTENSION hdfs_fdw;
DROP EXTENSION IF EXISTS hdfs_fdw;
\c regression
DROP DATABASE ext_test_db;
-- functions
DROP FUNCTION test_function_exists();

View File

@ -97,3 +97,61 @@ select * from interval_exchange_test order by logdate;
select * from interval_normal_exchange order by logdate;
select * from interval_normal_exchange where logdate > '2020-06-01' order by logdate;
drop table interval_normal_exchange;
drop table table_001;
create table table_001(
COL_1 smallint,
COL_2 char(5),
COL_3 int,
COL_4 date,
COL_5 boolean,
COL_6 nchar(5),
COL_7 float
);
drop table partition_table_001;
create table partition_table_001(
COL_1 smallint,
COL_2 char(5),
COL_3 int,
COL_4 date,
COL_5 boolean,
COL_6 nchar(5),
COL_7 float
)
PARTITION BY RANGE (COL_4)
INTERVAL ('1 month')
(
PARTITION partition_table_001_p1 VALUES LESS THAN ('2020-03-01'),
PARTITION partition_table_001_p2 VALUES LESS THAN ('2020-04-01'),
PARTITION partition_table_001_p3 VALUES LESS THAN ('2020-05-01')
);
insert into partition_table_001 values (1,'aaa',1,'2020-02-23',true,'aaa',1.1);
insert into partition_table_001 values (2,'bbb',2,'2020-03-23',false,'bbb',2.2);
insert into partition_table_001 values (3,'ccc',3,'2020-04-23',true,'ccc',3.3);
insert into partition_table_001 values (4,'ddd',4,'2020-05-23',false,'ddd',4.4);
insert into partition_table_001 values (5,'eee',5,'2020-06-23',true,'eee',5.5);
insert into partition_table_001 values (6,'fff',6,'2020-07-23',false,'fff',6.6);
ALTER TABLE partition_table_001 EXCHANGE PARTITION (sys_p1) WITH TABLE table_001;
select * from table_001 order by 1;
select * from partition_table_001 order by 1;
select relname, parttype, partstrategy, boundaries from pg_partition
where parentid = (select oid from pg_class where relname = 'partition_table_001')
order by relname;
ALTER TABLE partition_table_001 EXCHANGE PARTITION (sys_p1) WITH TABLE table_001;
select * from table_001 order by 1;
select * from partition_table_001 order by 1;
insert into table_001 values (7,'eee',7,'2020-08-23',true,'eee',7.7);
ALTER TABLE partition_table_001 EXCHANGE PARTITION (sys_p1) WITH TABLE table_001 with validation verbose;
select * from table_001 order by 1;
select * from partition_table_001 order by 1;
drop table table_001;
drop table partition_table_001;

View File

@ -0,0 +1,53 @@
CREATE TABLE t11 (
sec_code character(6) NOT NULL,
issue_type character(3) NOT NULL
);
CREATE TABLE t22 (
company_code character(6) NOT NULL,
list_profit_flag character(1) NOT NULL
);
CREATE TABLE t33 (
company_code character(6) NOT NULL,
issue_flag character(6) NOT NULL
);
insert into t11 values(1,'S04');
insert into t22 values(1,'Y');
insert into t33 values(1,'1');
insert into t33 values(2,'2');
select
T5.issue_type
,T6.is_type
from
(
select T1.sec_code
,issue_type
--,case when list_profit_flag='Y' then '' else '' end as list_profit_flag
from
(
select sec_code
,case when issue_type in ('S04','S05','S06','S09') then '增发'
when issue_type in ('S01','S02') then '首发'
else '其他' end as issue_type
from t11
)T1
left join
(
select list_profit_flag
,company_code
from t22
)T2
on T1.sec_code=T2.company_code
)T5
full join
(
SELECT CASE
WHEN issue_flag = ANY (ARRAY['1'::bpchar, '3'::bpchar, '11'::bpchar]) THEN '首发'::text
ELSE '增发'::text
END AS is_type from t33
)T6
on T5.issue_type=T6.is_type
;

View File

@ -57,4 +57,6 @@ CREATE TABLE unspported_feature.ustore_table(id int, c1 text) WITH(compresstype=
CREATE INDEX tbl_pc_idx1 on unspported_feature.index_test(c1) WITH(compresstype=2, storage_type=ustore); --failed
-- segment
CREATE TABLE unspported_feature.segment_table(id int, c1 text) WITH(compresstype=2, segment=on); --failed
CREATE INDEX on unspported_feature.index_test(c1) WITH(compresstype=2, segment=on); --faled
CREATE INDEX on unspported_feature.index_test(c1) WITH(compresstype=2, segment=on); --failed
-- set compress_diff_convert
create table unspported_feature.compress_byte_test(id int) with (compresstype=2, compress_byte_convert=false, compress_diff_convert = true); -- failed

View File

@ -192,6 +192,46 @@ explain(costs off) select /*+ indexscan(tg_hash i_tg_hash_local_a) */ * from tg_
select /*+ indexscan(tg_hash i_tg_hash_local_a) */ * from tg_hash where a < 9;
drop table tg_hash;
drop table if exists test_ugi_045;
create table test_ugi_045
(
c_id integer not null,
c_date DATE,
c_info varchar(20) not null
)
partition by range(c_date)
interval('2 day')
(
partition p1 values less than ('2021-06-01 00:00:00'),
partition p2 values less than ('2021-06-03 00:00:00'),
partition p3 values less than ('2021-06-05 00:00:00'),
partition p4 values less than ('2021-06-07 00:00:00'),
partition p5 values less than ('2021-06-09 00:00:00')
);
insert into test_ugi_045(c_id, c_date, c_info) values(1, '2021-05-30 00:00:00', '1-1');
insert into test_ugi_045(c_id, c_date, c_info) values(2, '2021-05-31 00:00:00', '1-1');
insert into test_ugi_045(c_id, c_date, c_info) values(3, '2021-06-01 00:00:00', '1-1');
insert into test_ugi_045(c_id, c_date, c_info) values(4, '2021-06-02 00:00:00', '1-2');
insert into test_ugi_045(c_id, c_date, c_info) values(5, '2021-06-03 00:00:00', '1-2');
insert into test_ugi_045(c_id, c_date, c_info) values(6, '2021-06-04 00:00:00', '1-3');
insert into test_ugi_045(c_id, c_date, c_info) values(7, '2021-06-05 00:00:00', '1-3');
insert into test_ugi_045(c_id, c_date, c_info) values(8, '2021-06-06 00:00:00', '1-4');
insert into test_ugi_045(c_id, c_date, c_info) values(9, '2021-06-07 00:00:00', '1-4');
insert into test_ugi_045(c_id, c_date, c_info) values(10, '2021-06-08 00:00:00', '1-5');
create index global_index_id_045 on test_ugi_045(c_date) global;
create index global_index_info_045 on test_ugi_045(c_info) global;
select *from test_ugi_045;
alter table test_ugi_045 truncate partition p3 update global index;
set enable_seqscan = off;
set enable_bitmapscan = off;
select *from test_ugi_045;
select *from test_ugi_045 where c_info = '1-2';
drop table if exists test_ugi_045;
-- 清理过程
drop view check_truncate_results;
drop materialized view pg_partition_before_truncate;
drop materialized view pg_partition_before_truncate;