diff --git a/src/bin/gs_guc/cluster_guc.conf b/src/bin/gs_guc/cluster_guc.conf index e800cc499..2d0ac8415 100755 --- a/src/bin/gs_guc/cluster_guc.conf +++ b/src/bin/gs_guc/cluster_guc.conf @@ -219,6 +219,7 @@ enable_global_syscache|bool|0,0|NULL|NULL| gpc_clean_timeout|int|300,86400|NULL|NULL| enable_hashagg|bool|0,0|NULL|NULL| enable_hashjoin|bool|0,0|NULL|NULL| +enable_heap_multi_insert_for_insert_select|bool|0,0|NULL|NULL| enable_sortgroup_agg|bool|0,0|NULL|NULL| enable_hdfs_predicate_pushdown|bool|0,0|NULL|NULL| enable_hypo_index|bool|0,0|NULL|NULL| diff --git a/src/common/backend/nodes/copyfuncs.cpp b/src/common/backend/nodes/copyfuncs.cpp index 47ce926f5..885eef2b0 100644 --- a/src/common/backend/nodes/copyfuncs.cpp +++ b/src/common/backend/nodes/copyfuncs.cpp @@ -4938,6 +4938,7 @@ static Query* _copyQuery(const Query* from) COPY_STRING_FIELD(unique_sql_text); #endif COPY_SCALAR_FIELD(can_push); + COPY_SCALAR_FIELD(is_dist_insertselect); COPY_SCALAR_FIELD(unique_check); COPY_NODE_FIELD(resultRelations); COPY_NODE_FIELD(withCheckOptions); @@ -5008,6 +5009,7 @@ static InsertStmt* _copyInsertStmt(const InsertStmt* from) } COPY_SCALAR_FIELD(isRewritten); COPY_SCALAR_FIELD(hasIgnore); + COPY_SCALAR_FIELD(is_dist_insertselect); return newnode; } diff --git a/src/common/backend/nodes/equalfuncs.cpp b/src/common/backend/nodes/equalfuncs.cpp index 8e48359b3..be45e6873 100644 --- a/src/common/backend/nodes/equalfuncs.cpp +++ b/src/common/backend/nodes/equalfuncs.cpp @@ -979,6 +979,7 @@ static bool _equalQuery(const Query* a, const Query* b) COMPARE_SCALAR_FIELD(use_star_targets); COMPARE_SCALAR_FIELD(is_from_full_join_rewrite); COMPARE_SCALAR_FIELD(can_push); + COMPARE_SCALAR_FIELD(is_dist_insertselect); COMPARE_SCALAR_FIELD(unique_check); COMPARE_NODE_FIELD(resultRelations); COMPARE_NODE_FIELD(withCheckOptions); @@ -1011,6 +1012,7 @@ static bool _equalInsertStmt(const InsertStmt* a, const InsertStmt* b) } COMPARE_NODE_FIELD(upsertClause); COMPARE_SCALAR_FIELD(hasIgnore); + COMPARE_SCALAR_FIELD(is_dist_insertselect); return true; } diff --git a/src/common/backend/nodes/outfuncs.cpp b/src/common/backend/nodes/outfuncs.cpp index 7c4096165..5c968c58a 100755 --- a/src/common/backend/nodes/outfuncs.cpp +++ b/src/common/backend/nodes/outfuncs.cpp @@ -4174,6 +4174,9 @@ static void _outInsertStmt(StringInfo str, InsertStmt* node) if (t_thrd.proc->workingVersionNum >= KEYWORD_IGNORE_COMPART_VERSION_NUM) { WRITE_BOOL_FIELD(hasIgnore); } + if (t_thrd.proc->workingVersionNum >= INSERT_INTO_SELECT_VERSION_NUM) { + WRITE_BOOL_FIELD(is_dist_insertselect); + } } static void _outUpdateStmt(StringInfo str, UpdateStmt* node) @@ -4956,6 +4959,9 @@ static void _outQuery(StringInfo str, Query* node) if (t_thrd.proc->workingVersionNum >= PARTIALPUSH_VERSION_NUM) { WRITE_BOOL_FIELD(can_push); } + if (t_thrd.proc->workingVersionNum >= INSERT_INTO_SELECT_VERSION_NUM) { + WRITE_BOOL_FIELD(is_dist_insertselect); + } if (t_thrd.proc->workingVersionNum >= SUBLINKPULLUP_VERSION_NUM) { WRITE_BOOL_FIELD(unique_check); } diff --git a/src/common/backend/nodes/readfuncs.cpp b/src/common/backend/nodes/readfuncs.cpp index 815eb8d4a..f9f97a17c 100755 --- a/src/common/backend/nodes/readfuncs.cpp +++ b/src/common/backend/nodes/readfuncs.cpp @@ -1629,6 +1629,10 @@ static Query* _readQuery(void) { READ_BOOL_FIELD(can_push); } + IF_EXIST(is_dist_insertselect) + { + READ_BOOL_FIELD(is_dist_insertselect); + } IF_EXIST(unique_check) { diff --git a/src/common/backend/parser/analyze.cpp b/src/common/backend/parser/analyze.cpp index 658823c2f..ead1a76f4 100644 --- a/src/common/backend/parser/analyze.cpp +++ b/src/common/backend/parser/analyze.cpp @@ -1885,10 +1885,15 @@ static Query* transformInsertStmt(ParseState* pstate, InsertStmt* stmt) pstate->p_relnamespace = NIL; sub_varnamespace = pstate->p_varnamespace; pstate->p_varnamespace = NIL; + if (stmt->returningList || stmt->upsertClause) + qry->is_dist_insertselect = false; + else + qry->is_dist_insertselect = stmt->is_dist_insertselect; } else { sub_rtable = NIL; /* not used, but keep compiler quiet */ sub_relnamespace = NIL; sub_varnamespace = NIL; + qry->is_dist_insertselect = false; } /* @@ -1912,6 +1917,19 @@ static Query* transformInsertStmt(ParseState* pstate, InsertStmt* stmt) (errcode(ERRCODE_INVALID_OPERATION), errmsg("Not allowed to insert into relation pg_auth_history."))); } + if (qry->is_dist_insertselect) { + Oid relid = RelationGetRelid(targetrel); + HeapTuple classtup = SearchSysCache1(RELOID, relid); + Form_pg_class class_struct = (Form_pg_class)GETSTRUCT(classtup); + if (class_struct->parttype == PARTTYPE_PARTITIONED_RELATION || + class_struct->parttype == PARTTYPE_SUBPARTITIONED_RELATION || + class_struct->parttype == PARTTYPE_VALUE_PARTITIONED_RELATION ) { + qry->is_dist_insertselect = false; + } + ReleaseSysCache(classtup); + } + + if (targetrel != NULL && ((unsigned int)RelationGetInternalMask(targetrel) & INTERNAL_MASK_DINSERT)) { ereport(ERROR, diff --git a/src/common/backend/parser/gram.y b/src/common/backend/parser/gram.y index 7b3d52ea3..77c8687fd 100644 --- a/src/common/backend/parser/gram.y +++ b/src/common/backend/parser/gram.y @@ -23028,6 +23028,8 @@ insert_rest: $$->cols = NIL; $$->selectStmt = $1; $$->isRewritten = false; + if (((SelectStmt*)$1)->valuesLists == NULL) + $$->is_dist_insertselect = true; } | '(' insert_column_list ')' SelectStmt { @@ -23035,6 +23037,8 @@ insert_rest: $$->cols = $2; $$->selectStmt = $4; $$->isRewritten = false; + if (((SelectStmt*)$4)->valuesLists == NULL) + $$->is_dist_insertselect = true; } | DEFAULT VALUES { @@ -23042,6 +23046,7 @@ insert_rest: $$->cols = NIL; $$->selectStmt = NULL; $$->isRewritten = false; + $$->is_dist_insertselect = false; } ; diff --git a/src/common/backend/utils/init/globals.cpp b/src/common/backend/utils/init/globals.cpp index 3904cc882..48e2e01c2 100644 --- a/src/common/backend/utils/init/globals.cpp +++ b/src/common/backend/utils/init/globals.cpp @@ -81,6 +81,7 @@ const uint32 GRAND_VERSION_NUM = 92938; * 2.VERSION NUM FOR EACH FEATURE * Please write indescending order. ********************************************/ +const uint32 INSERT_INTO_SELECT_VERSION_NUM = 92938; const uint32 ROTATE_UNROTATE_VERSION_NUM = 92937; const uint32 PIPELINED_FUNCTION_VERSION_NUM = 92936; const uint32 DISABLE_CONSTRAINT_VERSION_NUM = 92931; diff --git a/src/common/backend/utils/misc/guc.cpp b/src/common/backend/utils/misc/guc.cpp index f805cb740..12ababad0 100755 --- a/src/common/backend/utils/misc/guc.cpp +++ b/src/common/backend/utils/misc/guc.cpp @@ -1956,6 +1956,20 @@ static void InitConfigureNamesBool() NULL, NULL }, + {{ + "enable_heap_multi_insert_for_insert_select", + PGC_USERSET, + NODE_SINGLENODE, + QUERY_TUNING, + gettext_noop("Enable enable heap_multi_insert for query like 'insert into xxx select yyy', as fast as the copy command"), + NULL + }, + &u_sess->attr.attr_storage.enable_heap_multi_insert_for_insert_select, + true, + NULL, + NULL, + NULL + }, {{"enable_default_ustore_table", PGC_USERSET, NODE_SINGLENODE, diff --git a/src/gausskernel/optimizer/plan/createplan.cpp b/src/gausskernel/optimizer/plan/createplan.cpp index 8df755db7..1e5dd03e1 100755 --- a/src/gausskernel/optimizer/plan/createplan.cpp +++ b/src/gausskernel/optimizer/plan/createplan.cpp @@ -9005,6 +9005,7 @@ ModifyTable* make_modifytable(CmdType operation, bool canSetTag, List* resultRel { ModifyTable* node = makeNode(ModifyTable); Plan* plan = &node->plan; + node->is_dist_insertselect = root->parse->is_dist_insertselect; double total_size; ListCell* subnode = NULL; double local_rows = 0; diff --git a/src/gausskernel/runtime/executor/nodeModifyTable.cpp b/src/gausskernel/runtime/executor/nodeModifyTable.cpp index 0073239a3..43522e620 100644 --- a/src/gausskernel/runtime/executor/nodeModifyTable.cpp +++ b/src/gausskernel/runtime/executor/nodeModifyTable.cpp @@ -3544,13 +3544,23 @@ static TupleTableSlot* ExecModifyTable(PlanState* state) #endif if (operation == CMD_INSERT) { - if (node->ps.type == T_ModifyTableState || node->mt_upsert->us_action != UPSERT_NONE || node->isReplace || - (result_rel_info->ri_TrigDesc != NULL && (result_rel_info->ri_TrigDesc->trig_insert_before_row || - result_rel_info->ri_TrigDesc->trig_insert_instead_row))) + if (node->ps.type == T_ModifyTableState || + node->mt_upsert->us_action != UPSERT_NONE || + node->isReplace || + (result_rel_info->ri_TrigDesc != NULL && (result_rel_info->ri_TrigDesc->trig_insert_before_row || + result_rel_info->ri_TrigDesc->trig_insert_instead_row)) || + !ENABLE_HEAP_MULTI_INSERT_FOR_INSERT_SELECT || + (result_rel_info->ri_RelationDesc->rd_att->constr != NULL && + result_rel_info->ri_RelationDesc->rd_att->constr->cons_autoinc != NULL) || + RelationIsPartition(result_rel_info->ri_RelationDesc)) { ExecInsert = ExecInsertT; - else { - use_heap_multi_insert = true; - ExecInsert = ExecInsertT; + } else { + if (RelationIsAstoreFormat(result_rel_info->ri_RelationDesc)) { + use_heap_multi_insert = true; + ExecInsert = ExecInsertT; + } else { + ExecInsert = ExecInsertT; + } } if (use_heap_multi_insert) { diff --git a/src/include/executor/node/nodeModifyTable.h b/src/include/executor/node/nodeModifyTable.h index 27b99ec4f..bca90151d 100644 --- a/src/include/executor/node/nodeModifyTable.h +++ b/src/include/executor/node/nodeModifyTable.h @@ -69,4 +69,7 @@ extern void ExecComputeStoredGenerated(ResultRelInfo *resultRelInfo, EState *est extern bool ExecComputeStoredUpdateExpr(ResultRelInfo *resultRelInfo, EState *estate, TupleTableSlot *slot, Tuple tuple, CmdType cmdtype, ItemPointer otid, Oid oldPartitionOid, int2 bucketid); +extern bool isSingleMode; +extern bool isRestoreMode; +#define ENABLE_HEAP_MULTI_INSERT_FOR_INSERT_SELECT ((!isSingleMode) && (!isRestoreMode) && (u_sess->attr.attr_storage.enable_heap_multi_insert_for_insert_select)) #endif /* NODEMODIFYTABLE_H */ diff --git a/src/include/knl/knl_guc/knl_session_attr_storage.h b/src/include/knl/knl_guc/knl_session_attr_storage.h index 427942bf7..ed796f3af 100755 --- a/src/include/knl/knl_guc/knl_session_attr_storage.h +++ b/src/include/knl/knl_guc/knl_session_attr_storage.h @@ -310,7 +310,7 @@ typedef struct knl_session_attr_storage { /* pre-read parms */ int heap_bulk_read_size; int vacuum_bulk_read_size; - + bool enable_heap_multi_insert_for_insert_select; } knl_session_attr_storage; #endif /* SRC_INCLUDE_KNL_KNL_SESSION_ATTR_STORAGE */ diff --git a/src/include/miscadmin.h b/src/include/miscadmin.h index f6d569bad..1a3366c1c 100644 --- a/src/include/miscadmin.h +++ b/src/include/miscadmin.h @@ -48,6 +48,7 @@ extern const uint32 NBTREE_DEDUPLICATION_VERSION_NUM; extern const uint32 MULTI_CHARSET_VERSION_NUM; extern const uint32 SRF_FUSION_VERSION_NUM; extern const uint32 INNER_UNIQUE_VERSION_NUM; +extern const uint32 INSERT_INTO_SELECT_VERSION_NUM; extern const uint32 PARTITION_ENHANCE_VERSION_NUM; extern const uint32 SELECT_INTO_FILE_VERSION_NUM; extern const uint32 CHARACTER_SET_VERSION_NUM; diff --git a/src/include/nodes/parsenodes_common.h b/src/include/nodes/parsenodes_common.h index 13236a155..6ddb03ab9 100644 --- a/src/include/nodes/parsenodes_common.h +++ b/src/include/nodes/parsenodes_common.h @@ -482,6 +482,7 @@ typedef struct InsertStmt { List *targetList; bool isRewritten; /* is this Stmt created by rewritter or end user? */ bool hasIgnore; /* is this Stmt containing ignore keyword? */ + bool is_dist_insertselect; } InsertStmt; /* ---------------------- @@ -2156,6 +2157,7 @@ typedef struct Query { char* unique_sql_text; /* used by unique sql plain text */ #endif bool can_push; + bool is_dist_insertselect; bool unique_check; /* true if the subquery is generated by general * sublink pullup, and scalar output is needed */ Oid* fixed_paramTypes; /* For plpy CTAS query. CTAS is a recursive call.CREATE query is the first rewrited. diff --git a/src/test/regress/expected/iud_heap_multi_insert.out b/src/test/regress/expected/iud_heap_multi_insert.out new file mode 100644 index 000000000..c28be3d0d --- /dev/null +++ b/src/test/regress/expected/iud_heap_multi_insert.out @@ -0,0 +1,20 @@ +NOTICE: table "prep202407_hmi" does not exist, skipping +DROP TABLE +NOTICE: table "dest202407_hmi" does not exist, skipping +DROP TABLE +CREATE TABLE +CREATE TABLE + enable_heap_multi_insert_for_insert_select +-------------------------------------------- + on +(1 row) + +INSERT 0 10000 +INSERT 0 10000 + count +------- + 10000 +(1 row) + +DROP TABLE +DROP TABLE diff --git a/src/test/regress/output/recovery_2pc_tools.source b/src/test/regress/output/recovery_2pc_tools.source index d43f31df0..a0897fa15 100644 --- a/src/test/regress/output/recovery_2pc_tools.source +++ b/src/test/regress/output/recovery_2pc_tools.source @@ -282,6 +282,7 @@ select name,vartype,unit,min_val,max_val from pg_settings where name <> 'qunit_c enable_hashagg | bool | | | enable_hashjoin | bool | | | enable_hdfs_predicate_pushdown | bool | | | + enable_heap_multi_insert_for_insert_select | bool | | | enable_huge_pages | bool | | | enable_hypo_index | bool | | | enable_ignore_case_in_dquotes | bool | | | diff --git a/src/test/regress/parallel_schedule0 b/src/test/regress/parallel_schedule0 index 95c8b87ee..7684bd914 100644 --- a/src/test/regress/parallel_schedule0 +++ b/src/test/regress/parallel_schedule0 @@ -1121,6 +1121,8 @@ test: slow_sql # test user@host test: user_host_test +# test for batchcmd insert for IUD +test: iud_heap_multi_insert # test for new_expr_by_flatten test: enable_expr_fusion_flatten # test for on update timestamp and generated column diff --git a/src/test/regress/sql/iud_heap_multi_insert.sql b/src/test/regress/sql/iud_heap_multi_insert.sql new file mode 100644 index 000000000..684da55cf --- /dev/null +++ b/src/test/regress/sql/iud_heap_multi_insert.sql @@ -0,0 +1,13 @@ +DROP TABLE IF EXISTS prep202407_hmi; +DROP TABLE IF EXISTS dest202407_hmi; + +CREATE TABLE prep202407_hmi (i int); +CREATE TABLE dest202407_hmi (i int); + +SHOW enable_heap_multi_insert_for_insert_select; +INSERT INTO prep202407_hmi SELECT generate_series(1,10000); +INSERT INTO dest202407_hmi SELECT * FROM prep202407_hmi; +SELECT count(*) FROM dest202407_hmi; + +DROP TABLE IF EXISTS prep202407_hmi; +DROP TABLE IF EXISTS dest202407_hmi;