From d2d85d80185e1c1cd7ebd95bc3d28de2af1af26c Mon Sep 17 00:00:00 2001 From: TotaJ Date: Sat, 8 Aug 2020 16:04:34 +0800 Subject: [PATCH] Support COPY FROM for oracle_fdw and mysql_fdw. Fix gs_popen_security failed in debug mode. --- src/common/backend/parser/analyze.cpp | 3 +- src/common/port/gs_system.cpp | 11 +- .../cbb/extension/foreign/foreign.cpp | 38 +++ src/gausskernel/optimizer/commands/copy.cpp | 14 +- src/gausskernel/optimizer/plan/createplan.cpp | 3 +- src/gausskernel/storage/ipc/ipc.cpp | 4 +- src/include/foreign/foreign.h | 7 + src/include/knl/knl_session.h | 16 +- src/include/tcop/utility.h | 5 +- .../huawei_mysql_fdw-2.5.3_patch.patch | 315 +++++++++++++++--- .../huawei_oracle_fdw-2.2.0_patch.patch | 180 +++++++--- 11 files changed, 481 insertions(+), 115 deletions(-) diff --git a/src/common/backend/parser/analyze.cpp b/src/common/backend/parser/analyze.cpp index efa5a80a12..29ce110a87 100644 --- a/src/common/backend/parser/analyze.cpp +++ b/src/common/backend/parser/analyze.cpp @@ -868,8 +868,7 @@ static void CheckUnsupportInsertSelectClause(Query* query) AssertEreport(query->commandType == CMD_INSERT, MOD_OPT, "Only deal with CMD_INSERT commondType here"); if (result->relkind == RELKIND_FOREIGN_TABLE) { - if (isMOTFromTblOid(result->relid) || isMysqlFDWFromTblOid(result->relid) || - isOracleFDWFromTblOid(result->relid)) { + if (CheckSupportedFDWType(result->relid)) { return; } diff --git a/src/common/port/gs_system.cpp b/src/common/port/gs_system.cpp index 4a727c1920..67d3fff41b 100644 --- a/src/common/port/gs_system.cpp +++ b/src/common/port/gs_system.cpp @@ -157,12 +157,14 @@ FILE* popen_security(const char* command, char type) if (cmd == NULL) { _exit(1); } + /* cmd should be freed after execvp, cause argv point to cmd */ argv = parseStringToArgs(cmd, &argc); - free(cmd); if (argv == NULL || argc == 0) { + free(cmd); _exit(1); } (void)execvp(argv[0], argv); + free(cmd); _exit(127); default: /* in parent process */ break; @@ -301,11 +303,14 @@ int gs_system_security(const char* command) cmd = strdup(command); if (cmd == NULL) _exit(1); + /* cmd should be freed after execvp, cause argv point to cmd */ argv = parseStringToArgs(cmd, &argc); - free(cmd); - if (argv == NULL || argc == 0) + if (argv == NULL || argc == 0) { + free(cmd); _exit(1); + } (void)execvp(argv[0], argv); + free(cmd); _exit(127); default: /* parent */ do { diff --git a/src/gausskernel/cbb/extension/foreign/foreign.cpp b/src/gausskernel/cbb/extension/foreign/foreign.cpp index 40664fb9db..25efc1f7e6 100644 --- a/src/gausskernel/cbb/extension/foreign/foreign.cpp +++ b/src/gausskernel/cbb/extension/foreign/foreign.cpp @@ -246,6 +246,44 @@ bool IsSpecifiedFDWFromRelid(Oid relId, const char* SepcifiedType) return IsSpecifiedTable; } +/** + * @Description: Jude whether type of the foreign table support SELECT/INSERT/UPDATE/DELETE/COPY + * @in relId: The foreign table Oid. + * @return Rreturn true if the foreign table support those DML. + */ +bool CheckSupportedFDWType(Oid relId) +{ + static const char* supportFDWType[] = {MOT_FDW, MYSQL_FDW, ORACLE_FDW}; + int size = sizeof(supportFDWType) / sizeof(supportFDWType[0]); + bool support = false; + + if (u_sess->opt_cxt.ft_context == NULL) { + u_sess->opt_cxt.ft_context = AllocSetContextCreate(u_sess->top_mem_cxt, + "ForeignTableTemp1", + ALLOCSET_DEFAULT_MINSIZE, + ALLOCSET_DEFAULT_INITSIZE, + ALLOCSET_DEFAULT_MAXSIZE); + } else { + MemoryContextReset(u_sess->opt_cxt.ft_context); + } + MemoryContext oldContext = MemoryContextSwitchTo(u_sess->opt_cxt.ft_context); + + ForeignTable* ftbl = GetForeignTable(relId); + ForeignServer* fsvr = GetForeignServer(ftbl->serverid); + ForeignDataWrapper* fdw = GetForeignDataWrapper(fsvr->fdwid); + + for (int i = 0; i < size; i++) { + if (pg_strcasecmp(fdw->fdwname, supportFDWType[i]) == 0) { + support = true; + break; + } + } + + MemoryContextSwitchTo(oldContext); + MemoryContextReset(u_sess->opt_cxt.ft_context); + return support; +} + bool isSpecifiedSrvTypeFromRelId(Oid relId, const char* SepcifiedType) { ForeignTable* ftbl = NULL; diff --git a/src/gausskernel/optimizer/commands/copy.cpp b/src/gausskernel/optimizer/commands/copy.cpp index 261a4bff53..634ef82ed0 100644 --- a/src/gausskernel/optimizer/commands/copy.cpp +++ b/src/gausskernel/optimizer/commands/copy.cpp @@ -3396,6 +3396,7 @@ static uint64 CopyFrom(CopyState cstate) bool hasBucket = false; MemInfoArg* CopyMem = NULL; bool needflush = false; + bool isForeignTbl = false; /* Whether this foreign table support COPY */ Assert(cstate->rel); if (cstate->rel->rd_rel->relkind != RELKIND_RELATION) { @@ -3404,10 +3405,11 @@ static uint64 CopyFrom(CopyState cstate) (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("cannot copy to view \"%s\"", RelationGetRelationName(cstate->rel)))); else if (cstate->rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE) { - if (!isMOTFromTblOid(RelationGetRelid(cstate->rel))) + if (!CheckSupportedFDWType(RelationGetRelid(cstate->rel))) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("cannot copy to foreign table \"%s\"", RelationGetRelationName(cstate->rel)))); + isForeignTbl = true; } else if (cstate->rel->rd_rel->relkind == RELKIND_SEQUENCE) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), @@ -3953,8 +3955,7 @@ static uint64 CopyFrom(CopyState cstate) tuple = ExecMaterializeSlot(slot); } - if (!skip_tuple && resultRelInfo->ri_FdwRoutine && resultRelInfo->ri_FdwRoutine->GetFdwType && - resultRelInfo->ri_FdwRoutine->GetFdwType() == MOT_ORC) { + if (!skip_tuple && isForeignTbl) { resultRelInfo->ri_FdwRoutine->ExecForeignInsert(estate, resultRelInfo, slot, NULL); processed++; } else if (!skip_tuple) { @@ -4168,6 +4169,13 @@ static uint64 CopyFrom(CopyState cstate) /* Handle queued AFTER triggers */ AfterTriggerEndQuery(estate); + /* To free the statement allocated in ExecForeignInsert */ + if (resultRelInfo->ri_FdwRoutine && resultRelInfo->ri_FdwRoutine->GetFdwType && + (resultRelInfo->ri_FdwRoutine->GetFdwType() == MYSQL_ORC || + resultRelInfo->ri_FdwRoutine->GetFdwType() == ORACLE_ORC)) { + resultRelInfo->ri_FdwRoutine->EndForeignModify(estate, resultRelInfo); + } + pfree_ext(values); pfree_ext(nulls); diff --git a/src/gausskernel/optimizer/plan/createplan.cpp b/src/gausskernel/optimizer/plan/createplan.cpp index 186cfb588d..9979d44b85 100644 --- a/src/gausskernel/optimizer/plan/createplan.cpp +++ b/src/gausskernel/optimizer/plan/createplan.cpp @@ -8464,8 +8464,7 @@ ModifyTable* make_modifytable(CmdType operation, bool canSetTag, List* resultRel Plan* subplan = (Plan*)(linitial(subplans)); ForeignScan* fscan = NULL; if ((fscan = (ForeignScan*)FindForeignScan(subplan)) != NULL) { - if (!isMOTFromTblOid(fscan->scan_relid) && !isMysqlFDWFromTblOid(fscan->scan_relid) && - !isOracleFDWFromTblOid(fscan->scan_relid)) + if (!CheckSupportedFDWType(fscan->scan_relid)) ereport(ERROR, (errmodule(MOD_OPT), errcode(ERRCODE_FEATURE_NOT_SUPPORTED), diff --git a/src/gausskernel/storage/ipc/ipc.cpp b/src/gausskernel/storage/ipc/ipc.cpp index f70a047593..8ff26a6db5 100644 --- a/src/gausskernel/storage/ipc/ipc.cpp +++ b/src/gausskernel/storage/ipc/ipc.cpp @@ -443,8 +443,8 @@ void sess_exit_prepare(int code) /* FDW exit callback, used to free connections to other server, check FDW code for detail. */ for (int i = 0; i < MAX_TYPE_FDW; i++) { - if (u_sess->fdw_ctx[i].fdwExitFunc != NULL) { - (u_sess->fdw_ctx[i].fdwExitFunc)(code, UInt32GetDatum(NULL)); + if (u_sess->ext_fdw_ctx[i].fdwExitFunc != NULL) { + (u_sess->ext_fdw_ctx[i].fdwExitFunc)(code, UInt32GetDatum(NULL)); } } diff --git a/src/include/foreign/foreign.h b/src/include/foreign/foreign.h index 369b091bd6..94fb4dfe48 100644 --- a/src/include/foreign/foreign.h +++ b/src/include/foreign/foreign.h @@ -209,6 +209,13 @@ extern char* GetForeignServerName(Oid serverid); */ extern bool IsSpecifiedFDWFromRelid(Oid relId, const char* SepcifiedType); +/** + * @Description: Jude whether type of the foreign table support SELECT/INSERT/UPDATE/DELETE/COPY + * @in relId: The foreign table Oid. + * @return Rreturn true if the foreign table support those DML. + */ +extern bool CheckSupportedFDWType(Oid relId); + /** * @Description: Get the all options for the OBS foreign table. * we store the option into ObsOptions. diff --git a/src/include/knl/knl_session.h b/src/include/knl/knl_session.h index ee1f7f8308..1697297243 100644 --- a/src/include/knl/knl_session.h +++ b/src/include/knl/knl_session.h @@ -2014,18 +2014,18 @@ typedef struct knl_u_gtt_context { pg_on_exit_callback gtt_sess_exit; } knl_u_gtt_context; -enum knl_fdw_type { +enum knl_ext_fdw_type { MYSQL_TYPE_FDW, ORACLE_TYPE_FDW, POSTGRES_TYPE_FDW, - /* Add new FDW type before MAX_TYPE_FDW */ + /* Add new external FDW type before MAX_TYPE_FDW */ MAX_TYPE_FDW }; -typedef struct knl_u_fdw_context { - void* connList; - pg_on_exit_callback fdwExitFunc; -} knl_u_fdw_context; +typedef struct knl_u_ext_fdw_context { + void* connList; /* Connection info to other DB */ + pg_on_exit_callback fdwExitFunc; /* Exit callback, will be called when session exit */ +} knl_u_ext_fdw_context; enum knl_session_status { KNL_SESS_FAKE, @@ -2120,8 +2120,8 @@ typedef struct knl_session_context { /* GTT */ knl_u_gtt_context gtt_ctx; - /* FDW */ - knl_u_fdw_context fdw_ctx[MAX_TYPE_FDW]; + /* external FDW */ + knl_u_ext_fdw_context ext_fdw_ctx[MAX_TYPE_FDW]; } knl_session_context; extern knl_session_context* create_session_context(MemoryContext parent, uint64 id); diff --git a/src/include/tcop/utility.h b/src/include/tcop/utility.h index 091f921fce..a6a0a12d57 100755 --- a/src/include/tcop/utility.h +++ b/src/include/tcop/utility.h @@ -154,7 +154,10 @@ typedef struct VerifyDesc { enum FOREIGNTABLEFILETYPE_ { HDFS_ORC = 1, - MOT_ORC = 2 + MOT_ORC = 2, + MYSQL_ORC = 3, + ORACLE_ORC = 4, + POSTGRES_ORC = 5 }; typedef enum FOREIGNTABLEFILETYPE_ FOREIGNTABLEFILETYPE; diff --git a/third_party/dependency/mysql_fdw/huawei_mysql_fdw-2.5.3_patch.patch b/third_party/dependency/mysql_fdw/huawei_mysql_fdw-2.5.3_patch.patch index d3ba1e0876..1d4b241e45 100644 --- a/third_party/dependency/mysql_fdw/huawei_mysql_fdw-2.5.3_patch.patch +++ b/third_party/dependency/mysql_fdw/huawei_mysql_fdw-2.5.3_patch.patch @@ -41,7 +41,7 @@ index d5e7b362..34667e12 100644 endif diff --git connection.cpp connection.cpp -index a517a738..51554000 100644 +index a517a738..d9b097f0 100644 --- connection.cpp +++ connection.cpp @@ -24,6 +24,7 @@ @@ -73,7 +73,7 @@ index a517a738..51554000 100644 /* First time through, initialize connection cache hashtable */ - if (ConnectionHash == NULL) -+ if (u_sess->fdw_ctx[MYSQL_TYPE_FDW].connList == NULL) ++ if (u_sess->ext_fdw_ctx[MYSQL_TYPE_FDW].connList == NULL) { HASHCTL ctl; MemSet(&ctl, 0, sizeof(ctl)); @@ -84,7 +84,7 @@ index a517a738..51554000 100644 - ctl.hcxt = CacheMemoryContext; - ConnectionHash = hash_create("mysql_fdw connections", 8, + ctl.hcxt = u_sess->cache_mem_cxt; -+ u_sess->fdw_ctx[MYSQL_TYPE_FDW].connList = hash_create("mysql_fdw connections", 8, ++ u_sess->ext_fdw_ctx[MYSQL_TYPE_FDW].connList = hash_create("mysql_fdw connections", 8, &ctl, HASH_ELEM | HASH_FUNCTION | HASH_CONTEXT); @@ -94,7 +94,7 @@ index a517a738..51554000 100644 mysql_inval_callback, (Datum) 0); + if (IS_THREAD_POOL_SESSION) + { -+ u_sess->fdw_ctx[MYSQL_TYPE_FDW].fdwExitFunc = mysql_fdw_exit; ++ u_sess->ext_fdw_ctx[MYSQL_TYPE_FDW].fdwExitFunc = mysql_fdw_exit; + } + else + { @@ -108,7 +108,7 @@ index a517a738..51554000 100644 * Find or create cached entry for requested connection. */ - entry = hash_search(ConnectionHash, &key, HASH_ENTER, &found); -+ entry = (ConnCacheEntry*)hash_search((HTAB*)u_sess->fdw_ctx[MYSQL_TYPE_FDW].connList, &key, HASH_ENTER, &found); ++ entry = (ConnCacheEntry*)hash_search((HTAB*)u_sess->ext_fdw_ctx[MYSQL_TYPE_FDW].connList, &key, HASH_ENTER, &found); if (!found) { /* initialize new hashtable entry (key is already filled in) */ @@ -117,11 +117,11 @@ index a517a738..51554000 100644 ConnCacheEntry *entry; - if (ConnectionHash == NULL) -+ if (u_sess->fdw_ctx[MYSQL_TYPE_FDW].connList == NULL) ++ if (u_sess->ext_fdw_ctx[MYSQL_TYPE_FDW].connList == NULL) return; - hash_seq_init(&scan, ConnectionHash); -+ hash_seq_init(&scan, (HTAB*)u_sess->fdw_ctx[MYSQL_TYPE_FDW].connList); ++ hash_seq_init(&scan, (HTAB*)u_sess->ext_fdw_ctx[MYSQL_TYPE_FDW].connList); while ((entry = (ConnCacheEntry *) hash_seq_search(&scan))) { if (entry->conn == NULL) @@ -130,8 +130,8 @@ index a517a738..51554000 100644 entry->conn = NULL; } + /* clean-up memory */ -+ hash_destroy((HTAB*)u_sess->fdw_ctx[MYSQL_TYPE_FDW].connList); -+ u_sess->fdw_ctx[MYSQL_TYPE_FDW].connList = NULL; ++ hash_destroy((HTAB*)u_sess->ext_fdw_ctx[MYSQL_TYPE_FDW].connList); ++ u_sess->ext_fdw_ctx[MYSQL_TYPE_FDW].connList = NULL; } /* @@ -140,11 +140,11 @@ index a517a738..51554000 100644 ConnCacheEntry *entry; - if (ConnectionHash == NULL) -+ if (u_sess->fdw_ctx[MYSQL_TYPE_FDW].connList == NULL) ++ if (u_sess->ext_fdw_ctx[MYSQL_TYPE_FDW].connList == NULL) return; - hash_seq_init(&scan, ConnectionHash); -+ hash_seq_init(&scan, (HTAB*)u_sess->fdw_ctx[MYSQL_TYPE_FDW].connList); ++ hash_seq_init(&scan, (HTAB*)u_sess->ext_fdw_ctx[MYSQL_TYPE_FDW].connList); while ((entry = (ConnCacheEntry *) hash_seq_search(&scan))) { if (entry->conn == NULL) @@ -153,12 +153,12 @@ index a517a738..51554000 100644 /* ConnectionHash must exist already, if we're registered */ - hash_seq_init(&scan, ConnectionHash); -+ hash_seq_init(&scan, (HTAB*)u_sess->fdw_ctx[MYSQL_TYPE_FDW].connList); ++ hash_seq_init(&scan, (HTAB*)u_sess->ext_fdw_ctx[MYSQL_TYPE_FDW].connList); while ((entry = (ConnCacheEntry *) hash_seq_search(&scan))) { /* Ignore invalid entries */ diff --git deparse.cpp deparse.cpp -index a75c2705..94b1799c 100644 +index a75c2705..ac72295e 100644 --- deparse.cpp +++ deparse.cpp @@ -20,7 +20,7 @@ @@ -170,6 +170,15 @@ index a75c2705..94b1799c 100644 #include "access/sysattr.h" #include "access/transam.h" #include "catalog/pg_collation.h" +@@ -113,7 +113,7 @@ static void mysql_print_remote_placeholder(Oid paramtype, int32 paramtypmod, + static void mysql_deparse_relation(StringInfo buf, Relation rel); + static void mysql_deparse_target_list(StringInfo buf, PlannerInfo *root, Index rtindex, Relation rel, + Bitmapset *attrs_used, List **retrieved_attrs); +-static void mysql_deparse_column_ref(StringInfo buf, int varno, int varattno, PlannerInfo *root); ++static void mysql_deparse_column_ref(StringInfo buf, int varno, int varattno, RangeTblEntry *rte); + + /* + * Functions to construct string representation of a specific types. @@ -169,7 +169,7 @@ mysql_deparse_relation(StringInfo buf, Relation rel) static char * mysql_quote_identifier(const char *s , char q) @@ -179,7 +188,55 @@ index a75c2705..94b1799c 100644 char *r = result; *r++ = q; -@@ -451,7 +451,7 @@ mysql_deparse_string(StringInfo buf, const char *val, bool isstr) +@@ -224,7 +224,7 @@ mysql_deparse_select(StringInfo buf, + * to *retrieved_attrs. + */ + void +-mysql_deparse_insert(StringInfo buf, PlannerInfo *root, ++mysql_deparse_insert(StringInfo buf, RangeTblEntry *rte, + Index rtindex, Relation rel, + List *targetAttrs) + { +@@ -248,7 +248,7 @@ mysql_deparse_insert(StringInfo buf, PlannerInfo *root, + appendStringInfoString(buf, ", "); + first = false; + +- mysql_deparse_column_ref(buf, rtindex, attnum, root); ++ mysql_deparse_column_ref(buf, rtindex, attnum, rte); + } + + appendStringInfoString(buf, ") VALUES ("); +@@ -320,7 +320,7 @@ mysql_deparse_target_list(StringInfo buf, + appendStringInfoString(buf, ", "); + first = false; + +- mysql_deparse_column_ref(buf, rtindex, i, root); ++ mysql_deparse_column_ref(buf, rtindex, i, planner_rt_fetch(rtindex, root)); + *retrieved_attrs = lappend_int(*retrieved_attrs, i); + } + } +@@ -389,9 +389,8 @@ mysql_append_where_clause(StringInfo buf, + * If it has a column_name FDW option, use that instead of attribute name. + */ + static void +-mysql_deparse_column_ref(StringInfo buf, int varno, int varattno, PlannerInfo *root) ++mysql_deparse_column_ref(StringInfo buf, int varno, int varattno, RangeTblEntry *rte) + { +- RangeTblEntry *rte; + char *colname = NULL; + List *options; + ListCell *lc; +@@ -399,9 +398,6 @@ mysql_deparse_column_ref(StringInfo buf, int varno, int varattno, PlannerInfo *r + /* varno must not be any of OUTER_VAR, INNER_VAR and INDEX_VAR. */ + Assert(!IS_SPECIAL_VARNO(varno)); + +- /* Get RangeTblEntry from array in PlannerInfo. */ +- rte = planner_rt_fetch(varno, root); +- + /* + * If it's a column of a foreign table, and it has the column_name FDW + * option, use that value. +@@ -451,7 +447,7 @@ mysql_deparse_string(StringInfo buf, const char *val, bool isstr) * Remove '{', '}' and \" character from the string. Because * this syntax is not recognize by the remote MySQL server. */ @@ -188,7 +245,25 @@ index a75c2705..94b1799c 100644 continue; if (ch == ',' && isstr) -@@ -869,11 +869,11 @@ mysql_deparse_array_ref(SubscriptingRef *node, deparse_expr_cxt *context) +@@ -638,7 +634,7 @@ mysql_deparse_update(StringInfo buf, PlannerInfo *root, + appendStringInfoString(buf, ", "); + first = false; + +- mysql_deparse_column_ref(buf, rtindex, attnum, root); ++ mysql_deparse_column_ref(buf, rtindex, attnum, planner_rt_fetch(rtindex, root)); + appendStringInfo(buf, " = ?"); + pindex++; + } +@@ -680,7 +676,7 @@ mysql_deparse_var(Var *node, deparse_expr_cxt *context) + node->varlevelsup == 0) + { + /* Var belongs to foreign table */ +- mysql_deparse_column_ref(buf, node->varno, node->varattno, context->root); ++ mysql_deparse_column_ref(buf, node->varno, node->varattno, planner_rt_fetch(node->varno, context->root)); + } + else + { +@@ -869,11 +865,11 @@ mysql_deparse_array_ref(SubscriptingRef *node, deparse_expr_cxt *context) appendStringInfoChar(buf, '['); if (lowlist_item) { @@ -202,7 +277,7 @@ index a75c2705..94b1799c 100644 appendStringInfoChar(buf, ']'); } -@@ -965,7 +965,7 @@ mysql_deparse_op_expr(OpExpr *node, deparse_expr_cxt *context) +@@ -965,7 +961,7 @@ mysql_deparse_op_expr(OpExpr *node, deparse_expr_cxt *context) if (oprkind == 'r' || oprkind == 'b') { arg = list_head(node->args); @@ -211,7 +286,7 @@ index a75c2705..94b1799c 100644 appendStringInfoChar(buf, ' '); } -@@ -977,7 +977,7 @@ mysql_deparse_op_expr(OpExpr *node, deparse_expr_cxt *context) +@@ -977,7 +973,7 @@ mysql_deparse_op_expr(OpExpr *node, deparse_expr_cxt *context) { arg = list_tail(node->args); appendStringInfoChar(buf, ' '); @@ -220,7 +295,7 @@ index a75c2705..94b1799c 100644 } appendStringInfoChar(buf, ')'); -@@ -1056,9 +1056,9 @@ mysql_deparse_distinct_expr(DistinctExpr *node, deparse_expr_cxt *context) +@@ -1056,9 +1052,9 @@ mysql_deparse_distinct_expr(DistinctExpr *node, deparse_expr_cxt *context) Assert(list_length(node->args) == 2); appendStringInfoChar(buf, '('); @@ -232,7 +307,7 @@ index a75c2705..94b1799c 100644 appendStringInfoChar(buf, ')'); } -@@ -1089,7 +1089,7 @@ mysql_deparse_scalar_array_op_expr(ScalarArrayOpExpr *node, deparse_expr_cxt *co +@@ -1089,7 +1085,7 @@ mysql_deparse_scalar_array_op_expr(ScalarArrayOpExpr *node, deparse_expr_cxt *co Assert(list_length(node->args) == 2); /* Deparse left operand. */ @@ -241,7 +316,7 @@ index a75c2705..94b1799c 100644 deparseExpr(arg1, context); appendStringInfoChar(buf, ' '); -@@ -1101,7 +1101,7 @@ mysql_deparse_scalar_array_op_expr(ScalarArrayOpExpr *node, deparse_expr_cxt *co +@@ -1101,7 +1097,7 @@ mysql_deparse_scalar_array_op_expr(ScalarArrayOpExpr *node, deparse_expr_cxt *co appendStringInfo(buf, " IN ("); /* Deparse right operand. */ @@ -250,7 +325,7 @@ index a75c2705..94b1799c 100644 switch (nodeTag((Node*)arg2)) { case T_Const: -@@ -1116,7 +1116,7 @@ mysql_deparse_scalar_array_op_expr(ScalarArrayOpExpr *node, deparse_expr_cxt *co +@@ -1116,7 +1112,7 @@ mysql_deparse_scalar_array_op_expr(ScalarArrayOpExpr *node, deparse_expr_cxt *co switch (c->consttype) { case INT4ARRAYOID: @@ -259,7 +334,7 @@ index a75c2705..94b1799c 100644 mysql_deparse_string(buf, extval, false); break; default: -@@ -1172,7 +1172,7 @@ mysql_deparse_bool_expr(BoolExpr *node, deparse_expr_cxt *context) +@@ -1172,7 +1168,7 @@ mysql_deparse_bool_expr(BoolExpr *node, deparse_expr_cxt *context) break; case NOT_EXPR: appendStringInfoString(buf, "(NOT "); @@ -268,7 +343,7 @@ index a75c2705..94b1799c 100644 appendStringInfoChar(buf, ')'); return; } -@@ -1220,7 +1220,7 @@ mysql_deparse_array_expr(ArrayExpr *node, deparse_expr_cxt *context) +@@ -1220,7 +1216,7 @@ mysql_deparse_array_expr(ArrayExpr *node, deparse_expr_cxt *context) { if (!first) appendStringInfoString(buf, ", "); @@ -278,7 +353,7 @@ index a75c2705..94b1799c 100644 } appendStringInfoChar(buf, ']'); diff --git mysql_fdw.cpp mysql_fdw.cpp -index d518e2ec..a56fae67 100644 +index d518e2ec..06469703 100644 --- mysql_fdw.cpp +++ mysql_fdw.cpp @@ -53,7 +53,7 @@ @@ -350,7 +425,16 @@ index d518e2ec..a56fae67 100644 /* * FDW callback routines */ -@@ -219,36 +261,36 @@ mysql_load_library(void) +@@ -175,6 +217,8 @@ static void process_query_params(ExprContext *econtext, + + static void create_cursor(ForeignScanState *node); + ++static MySQLFdwExecState* getFdwState(EState* estate, ResultRelInfo* resultRelInfo); ++ + void* mysql_dll_handle = NULL; + static int wait_timeout = WAIT_TIMEOUT; + static int interactive_timeout = INTERACTIVE_TIMEOUT; +@@ -219,36 +263,36 @@ mysql_load_library(void) if(mysql_dll_handle == NULL) return false; @@ -417,7 +501,7 @@ index d518e2ec..a56fae67 100644 if (_mysql_stmt_bind_param == NULL || _mysql_stmt_bind_result == NULL || -@@ -297,43 +339,37 @@ _PG_init(void) +@@ -297,43 +341,42 @@ _PG_init(void) errmsg("failed to load the mysql query: \n%s", dlerror()), errhint("export LD_LIBRARY_PATH to locate the library"))); @@ -449,7 +533,6 @@ index d518e2ec..a56fae67 100644 - NULL, - NULL); - on_proc_exit(&mysql_fdw_exit, PointerGetDatum(NULL)); --} + if (GetConfigOption("mysql_fdw.wait_timeout", true, true) == NULL) { + DefineCustomIntVariable("mysql_fdw.wait_timeout", + "Server-side wait_timeout", @@ -465,14 +548,7 @@ index d518e2ec..a56fae67 100644 + NULL, + NULL); + } - --/* -- * mysql_fdw_exit: Exit callback function. -- */ --static void --mysql_fdw_exit(int code, Datum arg) --{ -- mysql_cleanup_connection(); ++ + if (GetConfigOption("mysql_fdw.interactive_timeout", true, true) == NULL) { + DefineCustomIntVariable("mysql_fdw.interactive_timeout", + "Server-side interactive timeout", @@ -490,8 +566,19 @@ index d518e2ec..a56fae67 100644 + } } +-/* +- * mysql_fdw_exit: Exit callback function. +- */ +-static void +-mysql_fdw_exit(int code, Datum arg) ++static int mysqlGetFdwType() + { +- mysql_cleanup_connection(); ++ return MYSQL_ORC; + } + /* -@@ -348,7 +384,7 @@ mysql_fdw_handler(PG_FUNCTION_ARGS) +@@ -348,7 +391,7 @@ mysql_fdw_handler(PG_FUNCTION_ARGS) /* Callback functions for readable FDW */ fdwroutine->GetForeignRelSize = mysqlGetForeignRelSize; fdwroutine->GetForeignPaths = mysqlGetForeignPaths; @@ -500,7 +587,16 @@ index d518e2ec..a56fae67 100644 fdwroutine->GetForeignPlan = mysqlGetForeignPlan; fdwroutine->ExplainForeignScan = mysqlExplainForeignScan; fdwroutine->BeginForeignScan = mysqlBeginForeignScan; -@@ -427,7 +463,7 @@ mysqlBeginForeignScan(ForeignScanState *node, int eflags) +@@ -369,6 +412,8 @@ mysql_fdw_handler(PG_FUNCTION_ARGS) + fdwroutine->ExecForeignDelete = mysqlExecForeignDelete; + fdwroutine->EndForeignModify = mysqlEndForeignModify; + ++ fdwroutine->GetFdwType = mysqlGetFdwType; ++ + PG_RETURN_POINTER(fdwroutine); + } + +@@ -427,7 +472,7 @@ mysqlBeginForeignScan(ForeignScanState *node, int eflags) /* Stash away the state info we have already */ festate->query = strVal(list_nth(fsplan->fdw_private, 0)); @@ -509,7 +605,7 @@ index d518e2ec..a56fae67 100644 festate->conn = conn; festate->cursor_exists = false; -@@ -1052,12 +1088,12 @@ mysqlGetForeignPaths(PlannerInfo *root,RelOptInfo *baserel,Oid foreigntableid) +@@ -1052,12 +1097,12 @@ mysqlGetForeignPaths(PlannerInfo *root,RelOptInfo *baserel,Oid foreigntableid) mysqlEstimateCosts(root, baserel, &startup_cost, &total_cost, foreigntableid); /* Create a ForeignPath node and add it as only possible path */ @@ -524,7 +620,7 @@ index d518e2ec..a56fae67 100644 startup_cost, total_cost, NIL, /* no pathkeys */ -@@ -1160,7 +1196,7 @@ mysqlGetForeignPlan( +@@ -1160,7 +1205,7 @@ mysqlGetForeignPlan( mysql_append_where_clause(&sql, root, baserel, remote_conds, true, ¶ms_list); @@ -533,7 +629,7 @@ index d518e2ec..a56fae67 100644 (root->parse->commandType == CMD_UPDATE || root->parse->commandType == CMD_DELETE)) { -@@ -1330,7 +1366,7 @@ mysqlPlanForeignModify(PlannerInfo *root, +@@ -1330,7 +1375,7 @@ mysqlPlanForeignModify(PlannerInfo *root, #if PG_VERSION_NUM >= 90500 Bitmapset *tmpset = bms_copy(rte->updatedCols); #else @@ -542,7 +638,37 @@ index d518e2ec..a56fae67 100644 #endif AttrNumber col; -@@ -1644,7 +1680,7 @@ mysqlExecForeignUpdate(EState *estate, +@@ -1367,7 +1412,7 @@ mysqlPlanForeignModify(PlannerInfo *root, + switch (operation) + { + case CMD_INSERT: +- mysql_deparse_insert(&sql, root, resultRelation, rel, targetAttrs); ++ mysql_deparse_insert(&sql, planner_rt_fetch(resultRelation, root), resultRelation, rel, targetAttrs); + break; + case CMD_UPDATE: + mysql_deparse_update(&sql, root, resultRelation, rel, targetAttrs, attname); +@@ -1517,7 +1562,6 @@ mysqlBeginForeignModify(ModifyTableState *mtstate, + resultRelInfo->ri_FdwState = fmstate; + } + +- + /* + * mysqlExecForeignInsert: Insert one row into a foreign table + */ +@@ -1535,6 +1579,12 @@ mysqlExecForeignInsert(EState *estate, + MemoryContext oldcontext; + + fmstate = (MySQLFdwExecState *) resultRelInfo->ri_FdwState; ++ if (fmstate == NULL) ++ { ++ fmstate = getFdwState(estate, resultRelInfo); ++ resultRelInfo->ri_FdwState = fmstate; ++ } ++ + n_params = list_length(fmstate->retrieved_attrs); + + oldcontext = MemoryContextSwitchTo(fmstate->temp_cxt); +@@ -1644,7 +1694,7 @@ mysqlExecForeignUpdate(EState *estate, n_params = list_length(fmstate->retrieved_attrs); mysql_bind_buffer = (MYSQL_BIND*) palloc0(sizeof(MYSQL_BIND) * n_params); @@ -551,7 +677,7 @@ index d518e2ec..a56fae67 100644 /* Bind the values */ foreach(lc, fmstate->retrieved_attrs) -@@ -1833,7 +1869,7 @@ mysqlExecForeignDelete(EState *estate, +@@ -1833,7 +1883,7 @@ mysqlExecForeignDelete(EState *estate, static void mysqlEndForeignModify(EState *estate, ResultRelInfo *resultRelInfo) { @@ -560,8 +686,102 @@ index d518e2ec..a56fae67 100644 if (festate && festate->stmt) { +@@ -2115,6 +2165,93 @@ mysqlImportForeignSchema(ImportForeignSchemaStmt *stmt, Oid serverOid) + } + #endif + ++static MySQLFdwExecState* getFdwState(EState* estate, ResultRelInfo* resultRelInfo) ++{ ++ Relation rel = resultRelInfo->ri_RelationDesc; ++ RangeTblEntry* rte = rt_fetch(resultRelInfo->ri_RangeTableIndex, estate->es_range_table); ++ Oid userid = rte->checkAsUser ? rte->checkAsUser : GetUserId(); ++ Oid foreignTableId = RelationGetRelid(rel); ++ ++ if (!mysql_is_column_unique(foreignTableId)) ++ elog(ERROR, "first column of remote table must be unique for COPY operation"); ++ ++ ForeignTable* table = GetForeignTable(foreignTableId); ++ ForeignServer* server = GetForeignServer(table->serverid); ++ UserMapping* user = GetUserMapping(userid, server->serverid); ++ StringInfoData sql; ++ ++ MySQLFdwExecState* fmstate = (MySQLFdwExecState *)palloc0(sizeof(MySQLFdwExecState)); ++ fmstate->rel = rel; ++ fmstate->mysqlFdwOptions = mysql_get_options(foreignTableId); ++ fmstate->conn = mysql_get_connection(server, user, fmstate->mysqlFdwOptions); ++ fmstate->temp_cxt = AllocSetContextCreate(estate->es_query_cxt, "mysql_fdw temporary data", ++#if PG_VERSION_NUM >= 110000 ++ ALLOCSET_DEFAULT_SIZES); ++#else ++ ALLOCSET_SMALL_MINSIZE, ++ ALLOCSET_SMALL_INITSIZE, ++ ALLOCSET_SMALL_MAXSIZE); ++#endif ++ ++ TupleDesc tupdesc = RelationGetDescr(rel); ++ int attnum; ++ List* targetAttrs = NULL; ++ ++ for (attnum = 1; attnum <= tupdesc->natts; attnum++) ++ { ++ Form_pg_attribute attr = TupleDescAttr(tupdesc, attnum - 1); ++ ++ if (!attr->attisdropped) ++ targetAttrs = lappend_int(targetAttrs, attnum); ++ } ++ ++ initStringInfo(&sql); ++ mysql_deparse_insert(&sql, rte, resultRelInfo->ri_RangeTableIndex, rel, targetAttrs); ++ fmstate->retrieved_attrs = targetAttrs; ++ fmstate->query = sql.data; ++ fmstate->stmt = _mysql_stmt_init(fmstate->conn); ++ if (!fmstate->stmt) ++ { ++ char *err = pstrdup(_mysql_error(fmstate->conn)); ++ ereport(ERROR, (errcode(ERRCODE_FDW_UNABLE_TO_CREATE_EXECUTION), ++ errmsg("failed to initialize the MySQL query: \n%s", err))); ++ } ++ ++ /* Prepare mysql statment */ ++ if (_mysql_stmt_prepare(fmstate->stmt, fmstate->query, strlen(fmstate->query)) != 0) ++ { ++ switch(_mysql_stmt_errno(fmstate->stmt)) ++ { ++ case CR_NO_ERROR: ++ break; ++ ++ case CR_OUT_OF_MEMORY: ++ case CR_SERVER_GONE_ERROR: ++ case CR_SERVER_LOST: ++ { ++ char *err = pstrdup(_mysql_error(fmstate->conn)); ++ mysql_rel_connection(fmstate->conn); ++ ereport(ERROR, ++ (errcode(ERRCODE_FDW_UNABLE_TO_CREATE_EXECUTION), ++ errmsg("failed to prepare the MySQL query: \n%s", err))); ++ } ++ break; ++ case CR_COMMANDS_OUT_OF_SYNC: ++ case CR_UNKNOWN_ERROR: ++ default: ++ { ++ char *err = pstrdup(_mysql_error(fmstate->conn)); ++ ereport(ERROR, ++ (errcode(ERRCODE_FDW_UNABLE_TO_CREATE_EXECUTION), ++ errmsg("failed to prepare the MySQL query: \n%s", err))); ++ } ++ break; ++ } ++ } ++ ++ return fmstate; ++} ++ + /* + * Prepare for processing of parameters used in remote query. + */ diff --git mysql_fdw.h mysql_fdw.h -index 5b543cd0..ea58af7f 100644 +index 5b543cd0..93c2f63c 100644 --- mysql_fdw.h +++ mysql_fdw.h @@ -135,31 +135,31 @@ extern bool is_foreign_expr(PlannerInfo *root, @@ -643,6 +863,15 @@ index 5b543cd0..ea58af7f 100644 /* option.c headers */ +@@ -185,7 +185,7 @@ extern mysql_opt *mysql_get_options(Oid foreigntableid); + /* depare.c headers */ + extern void mysql_deparse_select(StringInfo buf, PlannerInfo *root, RelOptInfo *baserel, + Bitmapset *attrs_used, char *svr_table, List **retrieved_attrs); +-extern void mysql_deparse_insert(StringInfo buf, PlannerInfo *root, Index rtindex, Relation rel, List *targetAttrs); ++extern void mysql_deparse_insert(StringInfo buf, RangeTblEntry *rte, Index rtindex, Relation rel, List *targetAttrs); + extern void mysql_deparse_update(StringInfo buf, PlannerInfo *root, Index rtindex, Relation rel, List *targetAttrs, char *attname); + extern void mysql_deparse_delete(StringInfo buf, PlannerInfo *root, Index rtindex, Relation rel, char *name); + extern void mysql_append_where_clause(StringInfo buf, PlannerInfo *root, RelOptInfo *baserel, List *exprs, diff --git mysql_query.cpp mysql_query.cpp index 8c25f5cc..64fd770a 100644 --- mysql_query.cpp diff --git a/third_party/dependency/oracle_fdw/huawei_oracle_fdw-2.2.0_patch.patch b/third_party/dependency/oracle_fdw/huawei_oracle_fdw-2.2.0_patch.patch index 424f54b387..8dc0938e49 100644 --- a/third_party/dependency/oracle_fdw/huawei_oracle_fdw-2.2.0_patch.patch +++ b/third_party/dependency/oracle_fdw/huawei_oracle_fdw-2.2.0_patch.patch @@ -20,7 +20,7 @@ index 5f8b100..7fdd24f 100644 +override CPPFLAGS := $(filter-out $(exclude_option),$(CPPFLAGS)) \ No newline at end of file diff --git oracle_fdw.cpp oracle_fdw.cpp -index e75b6ab..0a9683d 100644 +index e75b6ab..113dda5 100644 --- oracle_fdw.cpp +++ oracle_fdw.cpp @@ -92,13 +92,13 @@ @@ -89,6 +89,16 @@ index e75b6ab..0a9683d 100644 #endif /* OLD_FDW_API */ static void oracleExplainForeignScan(ForeignScanState *node, ExplainState *es); static void oracleBeginForeignScan(ForeignScanState *node, int eflags); +@@ -317,8 +317,8 @@ static void oracleReScanForeignScan(ForeignScanState *node); + static void oracleAddForeignUpdateTargets(Query *parsetree, RangeTblEntry *target_rte, Relation target_relation); + static List *oraclePlanForeignModify(PlannerInfo *root, ModifyTable *plan, Index resultRelation, int subplan_index); + static void oracleBeginForeignModify(ModifyTableState *mtstate, ResultRelInfo *rinfo, List *fdw_private, int subplan_index, int eflags); ++static void oracleBeginForeignInsert(EState *estate, ResultRelInfo *rinfo); + #if PG_VERSION_NUM >= 110000 +-static void oracleBeginForeignInsert(ModifyTableState *mtstate, ResultRelInfo *rinfo); + static void oracleEndForeignInsert(EState *estate, ResultRelInfo *rinfo); + #endif /*PG_VERSION_NUM */ + static TupleTableSlot *oracleExecForeignInsert(EState *estate, ResultRelInfo *rinfo, TupleTableSlot *slot, TupleTableSlot *planSlot); @@ -348,7 +348,7 @@ static struct oraTable *build_join_oratable(struct OracleFdwState *fdwState, Lis #endif /* JOIN_API */ static void getColumnData(Oid foreigntableid, struct oraTable *oraTable); @@ -121,7 +131,19 @@ index e75b6ab..0a9683d 100644 #ifdef IMPORT_API static char *fold_case(char *name, fold_t foldcase, int collation); #endif /* IMPORT_API */ -@@ -403,7 +404,7 @@ PGDLLEXPORT Datum +@@ -395,6 +396,11 @@ static char *fold_case(char *name, fold_t foldcase, int collation); + #define ADD_REL_QUALIFIER(buf, varno) \ + appendStringInfo((buf), "%s%d.", REL_ALIAS_PREFIX, (varno)) + ++static int oracleGetFdwType() ++{ ++ return ORACLE_ORC; ++} ++ + /* + * Foreign-data wrapper handler function: return a struct with pointers + * to callback routines. +@@ -403,7 +409,7 @@ PGDLLEXPORT Datum oracle_fdw_handler(PG_FUNCTION_ARGS) { FdwRoutine *fdwroutine = makeNode(FdwRoutine); @@ -130,7 +152,26 @@ index e75b6ab..0a9683d 100644 #ifdef OLD_FDW_API fdwroutine->PlanForeignScan = oraclePlanForeignScan; #else -@@ -457,7 +458,7 @@ oracle_fdw_validator(PG_FUNCTION_ARGS) +@@ -425,8 +431,8 @@ oracle_fdw_handler(PG_FUNCTION_ARGS) + fdwroutine->PlanForeignModify = oraclePlanForeignModify; + fdwroutine->BeginForeignModify = oracleBeginForeignModify; + #if PG_VERSION_NUM >= 110000 +- fdwroutine->BeginForeignInsert = oracleBeginForeignInsert; +- fdwroutine->EndForeignInsert = oracleEndForeignInsert; ++ //fdwroutine->BeginForeignInsert = oracleBeginForeignInsert; ++ //fdwroutine->EndForeignInsert = oracleEndForeignInsert; + #endif /*PG_VERSION_NUM */ + fdwroutine->ExecForeignInsert = oracleExecForeignInsert; + fdwroutine->ExecForeignUpdate = oracleExecForeignUpdate; +@@ -438,6 +444,7 @@ oracle_fdw_handler(PG_FUNCTION_ARGS) + #ifdef IMPORT_API + fdwroutine->ImportForeignSchema = oracleImportForeignSchema; + #endif /* IMPORT_API */ ++ fdwroutine->GetFdwType = oracleGetFdwType; + + PG_RETURN_POINTER(fdwroutine); + } +@@ -457,7 +464,7 @@ oracle_fdw_validator(PG_FUNCTION_ARGS) Oid catalog = PG_GETARG_OID(1); ListCell *cell; bool option_given[option_count] = { false }; @@ -139,7 +180,7 @@ index e75b6ab..0a9683d 100644 /* * Check that only options supported by oracle_fdw, and allowed for the -@@ -752,9 +753,6 @@ _PG_init(void) +@@ -752,9 +759,6 @@ _PG_init(void) errmsg("PostgreSQL version \"%s\" not supported by oracle_fdw", GetConfigOptionByName("server_version", NULL)), errhint("You'll have to update PostgreSQL to a later minor release."))); @@ -149,7 +190,7 @@ index e75b6ab..0a9683d 100644 } #ifdef OLD_FDW_API -@@ -989,18 +987,18 @@ oracleGetForeignPaths(PlannerInfo *root, RelOptInfo *baserel, Oid foreigntableid +@@ -989,18 +993,18 @@ oracleGetForeignPaths(PlannerInfo *root, RelOptInfo *baserel, Oid foreigntableid fdwState->order_clause = orderedquery.data; /* add the only path */ @@ -171,7 +212,7 @@ index e75b6ab..0a9683d 100644 #if PG_VERSION_NUM >= 90500 NULL, /* no extra plan */ #endif /* PG_VERSION_NUM */ -@@ -1152,7 +1150,7 @@ ForeignScan +@@ -1152,7 +1156,7 @@ ForeignScan scan_relid = foreignrel->relid; /* check if the foreign scan is for an UPDATE or DELETE */ @@ -180,7 +221,7 @@ index e75b6ab..0a9683d 100644 (root->parse->commandType == CMD_UPDATE || root->parse->commandType == CMD_DELETE)) { -@@ -1182,8 +1180,10 @@ ForeignScan +@@ -1182,8 +1186,10 @@ ForeignScan rel = heap_open(foreigntableid, NoLock); /* is there an AFTER trigger FOR EACH ROW? */ @@ -193,7 +234,7 @@ index e75b6ab..0a9683d 100644 heap_close(rel, NoLock); -@@ -1284,7 +1284,7 @@ ForeignScan +@@ -1284,7 +1290,7 @@ ForeignScan } bool @@ -202,7 +243,7 @@ index e75b6ab..0a9683d 100644 { *func = acquireSampleRowsFunc; /* use positive page count as a sign that the table has been ANALYZEd */ -@@ -1631,7 +1631,7 @@ oraclePlanForeignModify(PlannerInfo *root, ModifyTable *plan, Index resultRelati +@@ -1631,7 +1637,7 @@ oraclePlanForeignModify(PlannerInfo *root, ModifyTable *plan, Index resultRelati #endif /* PG_VERSION_NUM */ /* check if the foreign table is scanned and we already planned that scan */ @@ -211,7 +252,7 @@ index e75b6ab..0a9683d 100644 && root->simple_rel_array[resultRelation] != NULL && root->simple_rel_array[resultRelation]->fdw_private != NULL) { -@@ -1682,7 +1682,7 @@ oraclePlanForeignModify(PlannerInfo *root, ModifyTable *plan, Index resultRelati +@@ -1682,7 +1688,7 @@ oraclePlanForeignModify(PlannerInfo *root, ModifyTable *plan, Index resultRelati #if PG_VERSION_NUM >= 90500 tmpset = bms_copy(rte->updatedCols); #else @@ -220,7 +261,44 @@ index e75b6ab..0a9683d 100644 #endif /* PG_VERSION_NUM */ while ((col = bms_first_member(tmpset)) >= 0) -@@ -2492,7 +2492,7 @@ oracleImportForeignSchema(ImportForeignSchemaStmt *stmt, Oid serverOid) +@@ -1893,14 +1899,12 @@ oracleBeginForeignModify(ModifyTableState *mtstate, ResultRelInfo *rinfo, List * + ALLOCSET_SMALL_SIZES); + } + +-#if PG_VERSION_NUM >= 110000 + /* + * oracleBeginForeignInsert + * Initialize the FDW state for COPY to a foreign table. + */ +-void oracleBeginForeignInsert(ModifyTableState *mtstate, ResultRelInfo *rinfo) ++void oracleBeginForeignInsert(EState *estate, ResultRelInfo *rinfo) + { +- EState *estate = mtstate->ps.state; + struct OracleFdwState *fdw_state; + StringInfoData buf; + struct paramDesc *param; +@@ -1982,6 +1986,7 @@ void oracleBeginForeignInsert(ModifyTableState *mtstate, ResultRelInfo *rinfo) + rinfo->ri_FdwState = (void *)fdw_state; + } + ++#if PG_VERSION_NUM >= 110000 + void + oracleEndForeignInsert(EState *estate, ResultRelInfo *rinfo) + { +@@ -2010,6 +2015,12 @@ oracleExecForeignInsert(EState *estate, ResultRelInfo *rinfo, TupleTableSlot *sl + int rows; + MemoryContext oldcontext; + ++ if (fdw_state == NULL) ++ { ++ oracleBeginForeignInsert(estate, rinfo); ++ fdw_state = (struct OracleFdwState *)rinfo->ri_FdwState; ++ } ++ + elog(DEBUG3, "oracle_fdw: execute foreign table insert on %d", RelationGetRelid(rinfo->ri_RelationDesc)); + + ++fdw_state->rowcount; +@@ -2492,7 +2503,7 @@ oracleImportForeignSchema(ImportForeignSchemaStmt *stmt, Oid serverOid) struct OracleFdwState *getFdwState(Oid foreigntableid, double *sample_percent) { @@ -229,7 +307,7 @@ index e75b6ab..0a9683d 100644 char *pgtablename = get_rel_name(foreigntableid); List *options; ListCell *cell; -@@ -3341,7 +3341,7 @@ build_join_oratable(struct OracleFdwState *fdwState, List *fdw_scan_tlist) +@@ -3341,7 +3352,7 @@ build_join_oratable(struct OracleFdwState *fdwState, List *fdw_scan_tlist) * exceeding this is not used by compute_scalar_stats(). */ int @@ -238,7 +316,7 @@ index e75b6ab..0a9683d 100644 { int collected_rows = 0, i; struct OracleFdwState *fdw_state; -@@ -3813,7 +3813,7 @@ deparseExpr(oracleSession *session, RelOptInfo *foreignrel, Expr *expr, const st +@@ -3813,7 +3824,7 @@ deparseExpr(oracleSession *session, RelOptInfo *foreignrel, Expr *expr, const st || strcmp(opername, "|/") == 0 || strcmp(opername, "@") == 0) { @@ -247,7 +325,7 @@ index e75b6ab..0a9683d 100644 if (left == NULL) { pfree(opername); -@@ -3823,7 +3823,7 @@ deparseExpr(oracleSession *session, RelOptInfo *foreignrel, Expr *expr, const st +@@ -3823,7 +3834,7 @@ deparseExpr(oracleSession *session, RelOptInfo *foreignrel, Expr *expr, const st if (oprkind == 'b') { /* binary operator */ @@ -256,7 +334,7 @@ index e75b6ab..0a9683d 100644 if (right == NULL) { pfree(left); -@@ -3932,7 +3932,7 @@ deparseExpr(oracleSession *session, RelOptInfo *foreignrel, Expr *expr, const st +@@ -3932,7 +3943,7 @@ deparseExpr(oracleSession *session, RelOptInfo *foreignrel, Expr *expr, const st if (! canHandleType(leftargtype)) return NULL; @@ -265,7 +343,7 @@ index e75b6ab..0a9683d 100644 if (left == NULL) return NULL; -@@ -4052,12 +4052,12 @@ deparseExpr(oracleSession *session, RelOptInfo *foreignrel, Expr *expr, const st +@@ -4052,12 +4063,12 @@ deparseExpr(oracleSession *session, RelOptInfo *foreignrel, Expr *expr, const st if (! canHandleType(rightargtype)) return NULL; @@ -280,7 +358,7 @@ index e75b6ab..0a9683d 100644 if (right == NULL) { pfree(left); -@@ -4071,7 +4071,7 @@ deparseExpr(oracleSession *session, RelOptInfo *foreignrel, Expr *expr, const st +@@ -4071,7 +4082,7 @@ deparseExpr(oracleSession *session, RelOptInfo *foreignrel, Expr *expr, const st case T_BoolExpr: boolexpr = (BoolExpr *)expr; @@ -289,7 +367,7 @@ index e75b6ab..0a9683d 100644 if (arg == NULL) return NULL; -@@ -4140,7 +4140,7 @@ deparseExpr(oracleSession *session, RelOptInfo *foreignrel, Expr *expr, const st +@@ -4140,7 +4151,7 @@ deparseExpr(oracleSession *session, RelOptInfo *foreignrel, Expr *expr, const st else { /* for CASE arg WHEN ..., use only the right branch of the equality */ @@ -298,7 +376,7 @@ index e75b6ab..0a9683d 100644 } if (arg == NULL) -@@ -4245,7 +4245,7 @@ deparseExpr(oracleSession *session, RelOptInfo *foreignrel, Expr *expr, const st +@@ -4245,7 +4256,7 @@ deparseExpr(oracleSession *session, RelOptInfo *foreignrel, Expr *expr, const st /* do nothing for implicit casts */ if (func->funcformat == COERCE_IMPLICIT_CAST) @@ -307,7 +385,7 @@ index e75b6ab..0a9683d 100644 /* get function name and schema */ tuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(func->funcid)); -@@ -4325,7 +4325,7 @@ deparseExpr(oracleSession *session, RelOptInfo *foreignrel, Expr *expr, const st +@@ -4325,7 +4336,7 @@ deparseExpr(oracleSession *session, RelOptInfo *foreignrel, Expr *expr, const st first_arg = true; foreach(cell, func->args) { @@ -316,7 +394,7 @@ index e75b6ab..0a9683d 100644 if (arg == NULL) { pfree(result.data); -@@ -4350,7 +4350,7 @@ deparseExpr(oracleSession *session, RelOptInfo *foreignrel, Expr *expr, const st +@@ -4350,7 +4361,7 @@ deparseExpr(oracleSession *session, RelOptInfo *foreignrel, Expr *expr, const st else if (strcmp(opername, "date_part") == 0) { /* special case: EXTRACT */ @@ -325,7 +403,7 @@ index e75b6ab..0a9683d 100644 if (left == NULL) { pfree(opername); -@@ -4370,7 +4370,7 @@ deparseExpr(oracleSession *session, RelOptInfo *foreignrel, Expr *expr, const st +@@ -4370,7 +4381,7 @@ deparseExpr(oracleSession *session, RelOptInfo *foreignrel, Expr *expr, const st /* remove final quote */ left[strlen(left) - 1] = '\0'; @@ -334,7 +412,7 @@ index e75b6ab..0a9683d 100644 if (right == NULL) { pfree(opername); -@@ -4608,7 +4608,7 @@ getUsedColumns(Expr *expr, struct oraTable *oraTable, int foreignrelid) +@@ -4608,7 +4619,7 @@ getUsedColumns(Expr *expr, struct oraTable *oraTable, int foreignrelid) variable = (Var *)expr; /* ignore columns belonging to a different foreign table */ @@ -343,7 +421,7 @@ index e75b6ab..0a9683d 100644 break; /* ignore system columns */ -@@ -5195,7 +5195,7 @@ Const +@@ -5195,7 +5206,7 @@ Const struct OracleFdwState *deserializePlanData(List *list) { @@ -352,7 +430,7 @@ index e75b6ab..0a9683d 100644 ListCell *cell = list_head(list); int i, len; struct paramDesc *param; -@@ -5213,23 +5213,23 @@ struct OracleFdwState +@@ -5213,23 +5224,23 @@ struct OracleFdwState state->order_clause = NULL; /* dbserver */ @@ -381,7 +459,7 @@ index e75b6ab..0a9683d 100644 cell = list_next(list, cell); /* Oracle prefetch count */ -@@ -5238,9 +5238,9 @@ struct OracleFdwState +@@ -5238,9 +5249,9 @@ struct OracleFdwState /* table data */ state->oraTable = (struct oraTable *)palloc(sizeof(struct oraTable)); @@ -393,7 +471,7 @@ index e75b6ab..0a9683d 100644 cell = list_next(list, cell); state->oraTable->ncols = (int)DatumGetInt32(((Const *)lfirst(cell))->constvalue); cell = list_next(list, cell); -@@ -5252,13 +5252,13 @@ struct OracleFdwState +@@ -5252,13 +5263,13 @@ struct OracleFdwState for (i=0; ioraTable->ncols; ++i) { state->oraTable->cols[i] = (struct oraColumn *)palloc(sizeof(struct oraColumn)); @@ -409,7 +487,7 @@ index e75b6ab..0a9683d 100644 cell = list_next(list, cell); state->oraTable->cols[i]->pgattnum = (int)DatumGetInt32(((Const *)lfirst(cell))->constvalue); cell = list_next(list, cell); -@@ -5270,7 +5270,7 @@ struct OracleFdwState +@@ -5270,7 +5281,7 @@ struct OracleFdwState cell = list_next(list, cell); state->oraTable->cols[i]->pkey = (int)DatumGetInt32(((Const *)lfirst(cell))->constvalue); cell = list_next(list, cell); @@ -418,7 +496,7 @@ index e75b6ab..0a9683d 100644 cell = list_next(list, cell); /* allocate memory for the result value */ state->oraTable->cols[i]->val = (char *)palloc(state->oraTable->cols[i]->val_size + 1); -@@ -5288,14 +5288,14 @@ struct OracleFdwState +@@ -5288,14 +5299,14 @@ struct OracleFdwState for (i=0; ivalue = NULL; param->node = NULL; -@@ -5365,7 +5365,7 @@ find_em_expr_for_rel(EquivalenceClass *ec, RelOptInfo *rel) +@@ -5365,7 +5376,7 @@ find_em_expr_for_rel(EquivalenceClass *ec, RelOptInfo *rel) foreach(lc_em, ec->ec_members) { @@ -444,7 +522,7 @@ index e75b6ab..0a9683d 100644 if (bms_equal(em->em_relids, rel->relids)) { -@@ -5511,7 +5511,7 @@ struct OracleFdwState +@@ -5511,7 +5522,7 @@ struct OracleFdwState *copyPlanData(struct OracleFdwState *orig) { int i; @@ -453,7 +531,7 @@ index e75b6ab..0a9683d 100644 copy->dbserver = pstrdup(orig->dbserver); copy->user = pstrdup(orig->user); -@@ -5565,8 +5565,8 @@ void +@@ -5565,8 +5576,8 @@ void subtransactionCallback(SubXactEvent event, SubTransactionId mySubid, SubTransactionId parentSubid, void *arg) { /* rollback to the appropriate savepoint on subtransaction abort */ @@ -464,7 +542,7 @@ index e75b6ab..0a9683d 100644 } /* -@@ -5579,7 +5579,7 @@ addParam(struct paramDesc **paramList, char *name, Oid pgtype, oraType oratype, +@@ -5579,7 +5590,7 @@ addParam(struct paramDesc **paramList, char *name, Oid pgtype, oraType oratype, { struct paramDesc *param; @@ -473,7 +551,7 @@ index e75b6ab..0a9683d 100644 param->name = pstrdup(name); param->type = pgtype; switch (oratype) -@@ -5790,7 +5790,7 @@ setModifyParameters(struct paramDesc *paramList, TupleTableSlot *newslot, TupleT +@@ -5790,7 +5801,7 @@ setModifyParameters(struct paramDesc *paramList, TupleTableSlot *newslot, TupleT value_len = VARSIZE(datum) - VARHDRSZ; /* the first 4 bytes contain the length */ @@ -482,7 +560,7 @@ index e75b6ab..0a9683d 100644 memcpy(param->value, (const char *)&value_len, 4); memcpy(param->value + 4, VARDATA(datum), value_len); break; -@@ -5985,7 +5985,7 @@ appendReturningClause(StringInfo sql, struct OracleFdwState *fdwState) +@@ -5985,7 +5996,7 @@ appendReturningClause(StringInfo sql, struct OracleFdwState *fdwState) param->name = pstrdup(paramName); param->type = fdwState->oraTable->cols[i]->pgtype; param->bindType = BIND_OUTPUT; @@ -491,7 +569,7 @@ index e75b6ab..0a9683d 100644 param->node = NULL; param->bindh = NULL; param->colnum = i; -@@ -6013,20 +6013,6 @@ transactionCallback(XactEvent event, void *arg) +@@ -6013,20 +6024,6 @@ transactionCallback(XactEvent event, void *arg) { switch(event) { @@ -512,7 +590,7 @@ index e75b6ab..0a9683d 100644 case XACT_EVENT_COMMIT: case XACT_EVENT_PREPARE: #if PG_VERSION_NUM >= 90500 -@@ -6046,6 +6032,8 @@ transactionCallback(XactEvent event, void *arg) +@@ -6046,6 +6043,8 @@ transactionCallback(XactEvent event, void *arg) /* remote rollback */ oracleEndTransaction(arg, 0, 1); break; @@ -521,7 +599,7 @@ index e75b6ab..0a9683d 100644 } dml_in_transaction = false; -@@ -6254,14 +6242,14 @@ convertTuple(struct OracleFdwState *fdw_state, Datum *values, bool *nulls, bool +@@ -6254,14 +6253,14 @@ convertTuple(struct OracleFdwState *fdw_state, Datum *values, bool *nulls, bool ora_geometry *geom = (ora_geometry *)fdw_state->oraTable->cols[index]->val; /* install error context callback */ @@ -539,7 +617,7 @@ index e75b6ab..0a9683d 100644 value = NULL; /* we will fetch that later to avoid unnecessary copying */ } -@@ -6303,8 +6291,8 @@ convertTuple(struct OracleFdwState *fdw_state, Datum *values, bool *nulls, bool +@@ -6303,8 +6302,8 @@ convertTuple(struct OracleFdwState *fdw_state, Datum *values, bool *nulls, bool struct varlena *result = NULL; /* install error context callback */ @@ -550,7 +628,7 @@ index e75b6ab..0a9683d 100644 fdw_state->columnindex = index; result = (bytea *)palloc(value_len + VARHDRSZ); -@@ -6312,7 +6300,7 @@ convertTuple(struct OracleFdwState *fdw_state, Datum *values, bool *nulls, bool +@@ -6312,7 +6311,7 @@ convertTuple(struct OracleFdwState *fdw_state, Datum *values, bool *nulls, bool SET_VARSIZE(result, value_len + VARHDRSZ); /* uninstall error context callback */ @@ -559,7 +637,7 @@ index e75b6ab..0a9683d 100644 values[j] = PointerGetDatum(result); -@@ -6342,7 +6330,7 @@ convertTuple(struct OracleFdwState *fdw_state, Datum *values, bool *nulls, bool +@@ -6342,7 +6341,7 @@ convertTuple(struct OracleFdwState *fdw_state, Datum *values, bool *nulls, bool if (fdw_state->oraTable->cols[index]->oratype == ORA_TYPE_INTERVALD2S && value[0] == '-') { @@ -568,7 +646,7 @@ index e75b6ab..0a9683d 100644 char *pos = strchr(value, ' '); if (pos == NULL) -@@ -6367,8 +6355,8 @@ convertTuple(struct OracleFdwState *fdw_state, Datum *values, bool *nulls, bool +@@ -6367,8 +6366,8 @@ convertTuple(struct OracleFdwState *fdw_state, Datum *values, bool *nulls, bool dat = CStringGetDatum(value); /* install error context callback */ @@ -579,7 +657,7 @@ index e75b6ab..0a9683d 100644 fdw_state->columnindex = index; /* for string types, check that the data are in the database encoding */ -@@ -6396,7 +6384,7 @@ convertTuple(struct OracleFdwState *fdw_state, Datum *values, bool *nulls, bool +@@ -6396,7 +6395,7 @@ convertTuple(struct OracleFdwState *fdw_state, Datum *values, bool *nulls, bool } /* uninstall error context callback */ @@ -588,7 +666,7 @@ index e75b6ab..0a9683d 100644 } /* free the data buffer for LOBs */ -@@ -6465,8 +6453,9 @@ oracleGetShareFileName(const char *relativename) +@@ -6465,8 +6464,9 @@ oracleGetShareFileName(const char *relativename) get_share_path(my_exec_path, share_path); @@ -600,7 +678,7 @@ index e75b6ab..0a9683d 100644 return result; } -@@ -6655,8 +6644,7 @@ void +@@ -6655,8 +6655,7 @@ void initializePostGIS() { CatCList *catlist; @@ -610,7 +688,7 @@ index e75b6ab..0a9683d 100644 /* this needs to be done only once per database session */ if (geometry_is_setup) -@@ -6665,10 +6653,9 @@ initializePostGIS() +@@ -6665,10 +6664,9 @@ initializePostGIS() geometry_is_setup = true; /* find all functions called "geometry_recv" with "internal" argument type */ @@ -623,28 +701,28 @@ index e75b6ab..0a9683d 100644 for (i = 0; i < catlist->n_members; i++) { -@@ -6695,3 +6682,28 @@ initializePostGIS() +@@ -6695,3 +6693,28 @@ initializePostGIS() } ReleaseSysCacheList(catlist); } + +struct envEntry* oracleGetConnList(void) +{ -+ return (struct envEntry*)u_sess->fdw_ctx[ORACLE_TYPE_FDW].connList; ++ return (struct envEntry*)u_sess->ext_fdw_ctx[ORACLE_TYPE_FDW].connList; +} + +void oracleSetConnList(struct envEntry* connList) +{ -+ u_sess->fdw_ctx[ORACLE_TYPE_FDW].connList = connList; ++ u_sess->ext_fdw_ctx[ORACLE_TYPE_FDW].connList = connList; +} + +void oracleRegExitProc(void) +{ -+ if (u_sess->fdw_ctx[ORACLE_TYPE_FDW].connList == NULL) ++ if (u_sess->ext_fdw_ctx[ORACLE_TYPE_FDW].connList == NULL) + { + if (IS_THREAD_POOL_SESSION) + { -+ u_sess->fdw_ctx[ORACLE_TYPE_FDW].fdwExitFunc = exitHook; ++ u_sess->ext_fdw_ctx[ORACLE_TYPE_FDW].fdwExitFunc = exitHook; + } + else + { -- Gitee