diff --git a/src/gausskernel/optimizer/path/clausesel.cpp b/src/gausskernel/optimizer/path/clausesel.cpp index f9f40091f395720ba4d11fac00f9569437baa70d..b89d68697a4208d03dca4672fb9f7b45d0bbdd9a 100755 --- a/src/gausskernel/optimizer/path/clausesel.cpp +++ b/src/gausskernel/optimizer/path/clausesel.cpp @@ -768,10 +768,13 @@ Selectivity clause_selectivity(PlannerInfo* root, Node* clause, int varRelid, Jo * if it is filter for baserel and cached, or not inner join, * we should cache the var's selectivity into relation. */ - if (use_poisson && - ((RatioType_Filter == ratiotype && varratio_cached) || (jointype == JOIN_SEMI) || (jointype == JOIN_ANTI)) && - (!check_scalarop || !is_rangequery_contain_scalarop(clause, rinfo))) - get_vardata_for_filter_or_semijoin(root, clause, varRelid, s1, sjinfo, ratiotype); + if (u_sess->opfusion_reuse_ctx.opfusionObj == NULL) { + if (use_poisson && + ((RatioType_Filter == ratiotype && varratio_cached) || (jointype == JOIN_SEMI) || (jointype == JOIN_ANTI)) && + (!check_scalarop || !is_rangequery_contain_scalarop(clause, rinfo))) { + get_vardata_for_filter_or_semijoin(root, clause, varRelid, s1, sjinfo, ratiotype); + } + } #ifdef SELECTIVITY_DEBUG ereport(DEBUG4, (errmodule(MOD_OPT_JOIN), (errmsg("clause_selectivity: s1 %f", s1)))); diff --git a/src/gausskernel/optimizer/plan/createplan.cpp b/src/gausskernel/optimizer/plan/createplan.cpp index 2ad67890ea9b76b6f2c364470d8b49615514bec7..b598f88b69323893543cd95ed6250e3274733cd3 100755 --- a/src/gausskernel/optimizer/plan/createplan.cpp +++ b/src/gausskernel/optimizer/plan/createplan.cpp @@ -2054,12 +2054,13 @@ static void add_distribute_info(PlannerInfo* root, Plan* scanPlan, Index relInde Assert(bestPath->locator_type == LOCATOR_TYPE_REPLICATED); execNodes = ng_convert_to_exec_nodes(&bestPath->distribution, bestPath->locator_type, RELATION_ACCESS_READ); } else { +#ifdef ENABLE_MULTIPLE_NODES List* quals = scanClauses; /* A hashed table may have filter quals, it's exec nodes are not equal to it's data nodes */ execNodes = GetRelationNodesByQuals( (void*)root->parse, rte->relid, relIndex, (Node*)quals, RELATION_ACCESS_READ, NULL, false); - +#endif if (execNodes == NULL) { elog(DEBUG1, "[add_distribute_info] execNodes is NULL. Oid [%u]", rte->relid); Assert(rte->relid < FirstNormalObjectId || IS_PGXC_DATANODE); @@ -7785,7 +7786,9 @@ Agg* make_agg(PlannerInfo* root, List* tlist, List* qual, AggStrategy aggstrateg if (qual != NIL && plan_rows >= HAVING_THRESHOLD && !need_stream) plan_rows = clamp_row_est(plan_rows * DEFAULT_MATCH_SEL); - if (plan->exec_nodes->baselocatortype == LOCATOR_TYPE_REPLICATED && is_execute_on_datanodes(plan)) { + if (plan->exec_nodes ==NULL) { + + } else if (plan->exec_nodes->baselocatortype == LOCATOR_TYPE_REPLICATED && is_execute_on_datanodes(plan)) { plan->multiple = 1.0; plan->plan_rows = plan_rows; } else { @@ -8959,7 +8962,9 @@ ModifyTable* make_modifytable(CmdType operation, bool canSetTag, List* resultRel * If the subplan already parallelize, * add local gather. */ - deparallelize_modifytable(subplans); + if (u_sess->opt_cxt.query_dop > 1) { + deparallelize_modifytable(subplans); + } foreach (subnode, subplans) { Plan* subplan = (Plan*)lfirst(subnode); diff --git a/src/gausskernel/optimizer/util/clauses.cpp b/src/gausskernel/optimizer/util/clauses.cpp index f67ce201f301614e4940af8bf47bee83be464184..940a9e132d4c5e2b2c7e4d343993d9a3411960a4 100644 --- a/src/gausskernel/optimizer/util/clauses.cpp +++ b/src/gausskernel/optimizer/util/clauses.cpp @@ -4726,6 +4726,57 @@ static void sql_inline_error_callback(void* arg) errcontext("SQL function \"%s\" during inlining", callback_arg->proname); } +ExprContext* MakePerTupleExprContextForOpFusion(EState* estate) +{ + ExprContext* econtext = NULL; + MemoryContext oldcontext; + + /* Create the ExprContext node within the per-query memory context */ + oldcontext = MemoryContextSwitchTo(estate->es_query_cxt); + + econtext = makeNode(ExprContext); + + /* Initialize fields of ExprContext */ + econtext->ecxt_scantuple = NULL; + econtext->ecxt_innertuple = NULL; + econtext->ecxt_outertuple = NULL; + + econtext->ecxt_per_query_memory = estate->es_query_cxt; + + /* + * Create working memory for expression evaluation in this context. + */ + econtext->ecxt_per_tuple_memory = u_sess->iud_expr_reuse_ctx; + econtext->ecxt_param_exec_vals = estate->es_param_exec_vals; + econtext->ecxt_param_list_info = estate->es_param_list_info; + + econtext->ecxt_aggvalues = NULL; + econtext->ecxt_aggnulls = NULL; + + econtext->caseValue_datum = (Datum)0; + econtext->caseValue_isNull = true; + + econtext->domainValue_datum = (Datum)0; + econtext->domainValue_isNull = true; + + econtext->ecxt_estate = estate; + + econtext->ecxt_callbacks = NULL; + econtext->plpgsql_estate = NULL; + + /* + * Link the ExprContext into the EState to ensure it is shut down when the + * EState is freed. Because we use lcons(), shutdowns will occur in + * reverse order of creation, which may not be essential but can't hurt. + */ + estate->es_exprcontexts = lcons(econtext, estate->es_exprcontexts); + + MemoryContextSwitchTo(oldcontext); + estate->es_per_tuple_exprcontext = econtext; + + return econtext; +} + /* * evaluate_expr: pre-evaluate a constant expression * @@ -4743,11 +4794,20 @@ Expr* evaluate_expr(Expr* expr, Oid result_type, int32 result_typmod, Oid result bool const_is_null = false; int16 resultTypLen; bool resultTypByVal = false; - + bool isFusion = false; + if (u_sess->iud_expr_reuse_ctx == NULL) { + u_sess->iud_expr_reuse_ctx = AllocSetContextCreate(u_sess->top_transaction_mem_cxt, "IudExprReuseContext", ALLOCSET_DEFAULT_MINSIZE, + ALLOCSET_DEFAULT_INITSIZE, ALLOCSET_DEFAULT_MAXSIZE); + } /* * To use the executor, we need an EState. */ - estate = CreateExecutorState(); + if (u_sess->iud_expr_reuse_ctx != NULL) { + estate = CreateExecutorState(); + isFusion = true; + } else { + estate = CreateExecutorState(); + } /* We can use the estate's working context to avoid memory leaks. */ oldcontext = MemoryContextSwitchTo(estate->es_query_cxt); @@ -4769,6 +4829,9 @@ Expr* evaluate_expr(Expr* expr, Oid result_type, int32 result_typmod, Oid result * fortuitous, but it's not so unreasonable --- a constant expression does * not depend on context, by definition, n'est ce pas? */ + if (isFusion && estate->es_per_tuple_exprcontext == NULL) { + MakePerTupleExprContextForOpFusion(estate); + } ExprContext* econtext = GetPerTupleExprContext(estate); if (econtext != NULL) { econtext->can_ignore = can_ignore; @@ -4796,7 +4859,9 @@ Expr* evaluate_expr(Expr* expr, Oid result_type, int32 result_typmod, Oid result } /* Release all the junk we just created */ - FreeExecutorState(estate); + if (!isFusion) { + FreeExecutorState(estate); + } /* * Make the constant result node. diff --git a/src/gausskernel/optimizer/util/pathnode.cpp b/src/gausskernel/optimizer/util/pathnode.cpp index afa419a29d7cbaa510c31a24977990fc240cb082..6317cc957be2ec1ff9e6744d53d274d322f6cd2b 100755 --- a/src/gausskernel/optimizer/util/pathnode.cpp +++ b/src/gausskernel/optimizer/util/pathnode.cpp @@ -440,12 +440,7 @@ RemoteQueryExecType SetExectypeForJoinPath(Path* inner_path, Path* outer_path) RemoteQueryExecType SetBasePathExectype(PlannerInfo* root, RelOptInfo* rel) { - RangeTblEntry* rte = root->simple_rte_array[rel->relid]; - if (rte->rtekind == RTE_RELATION && is_sys_table(rte->relid)) { - return EXEC_ON_COORDS; - } else { - return EXEC_ON_DATANODES; - } + return EXEC_ON_DATANODES; } /* @@ -2907,9 +2902,10 @@ ResultPath* create_result_path(PlannerInfo *root, RelOptInfo *rel, List* quals, pathnode->path.total_cost = u_sess->attr.attr_sql.cpu_tuple_cost; pathnode->path.stream_cost = 0; pathnode->path.exec_type = EXEC_ON_ALL_NODES; - +#ifdef ENABLE_MULTIPLE_NODES Distribution* distribution = ng_get_default_computing_group_distribution(); ng_set_distribution(&pathnode->path.distribution, distribution); +#endif } /* diff --git a/src/gausskernel/runtime/executor/execUtils.cpp b/src/gausskernel/runtime/executor/execUtils.cpp index 06d632b6196225338a6710f33ec37058401c9535..50de2f74c4238d57d43a41da413df638ee91d2ce 100644 --- a/src/gausskernel/runtime/executor/execUtils.cpp +++ b/src/gausskernel/runtime/executor/execUtils.cpp @@ -1300,7 +1300,28 @@ void ExecCloseIndices(ResultRelInfo* resultRelInfo) * such stuff will be cleaned up automatically in FreeExecutorState. */ } +void OpFusionExecCloseIndices(ResultRelInfo* resultRelInfo) +{ + int i; + int numIndices; + RelationPtr indexDescs; + + numIndices = resultRelInfo->ri_NumIndices; + indexDescs = resultRelInfo->ri_IndexRelationDescs; + for (i = 0; i < numIndices; i++) { + if (indexDescs[i] == NULL) + continue; /* shouldn't happen? */ + + /* Drop lock acquired by ExecOpenIndices */ + index_close(indexDescs[i], NoLock); + } + + /* + * XXX should free indexInfo array here too? Currently we assume that + * such stuff will be cleaned up automatically in FreeExecutorState. + */ +} /* * Copied from ExecInsertIndexTuples */ diff --git a/src/gausskernel/runtime/opfusion/opfusion.cpp b/src/gausskernel/runtime/opfusion/opfusion.cpp index 96b7189e017d0c811f3fe78e9a7d2ef0a3928571..f26b8a13c7cb139fe5ba822e7706eec69a85b05f 100644 --- a/src/gausskernel/runtime/opfusion/opfusion.cpp +++ b/src/gausskernel/runtime/opfusion/opfusion.cpp @@ -114,8 +114,9 @@ void OpFusion::InitGlobals(MemoryContext context, CachedPlanSource *psrc, List * cxt = AllocSetContextCreate(GLOBAL_PLANCACHE_MEMCONTEXT, "SharedOpfusionContext", ALLOCSET_DEFAULT_MINSIZE, ALLOCSET_DEFAULT_INITSIZE, ALLOCSET_DEFAULT_MAXSIZE, SHARED_CONTEXT); } else { - cxt = AllocSetContextCreate(context, "OpfusionContext", ALLOCSET_DEFAULT_MINSIZE, ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE, STANDARD_CONTEXT); + u_sess->opfusion_cxt = AllocSetContextCreate(context, "OpfusionContext", ALLOCSET_DEFAULT_MINSIZE, ALLOCSET_DEFAULT_INITSIZE, + ALLOCSET_DEFAULT_MAXSIZE); + cxt = u_sess->opfusion_cxt; } MemoryContext old_context = MemoryContextSwitchTo(cxt); @@ -661,7 +662,7 @@ static void* TryReuseOpfusionObj(FusionType ftype, MemoryContext context, Cached * we save the obj without FusionType check in FusionFactory * so must check here */ - if (INSERT_FUSION != ftype) { + if (INSERT_FUSION != ftype && DELETE_FUSION != ftype) { return NULL; } @@ -681,12 +682,13 @@ static void* TryReuseOpfusionObj(FusionType ftype, MemoryContext context, Cached } /* check the resultdesc*/ - Relation rel = heap_open(rel_oid, AccessShareLock); - TupleDesc rel_tupDesc = CreateTupleDescCopy(RelationGetDescr(rel)); - heap_close(rel, AccessShareLock); - if (!equalTupleDescs(rel_tupDesc, checkOpfusionObj->m_global->m_tupDesc)) { - return NULL; + Relation rel = heap_open(rel_oid, RowExclusiveLock); + if (!opFusionReuseEqualTupleDescs(RelationGetDescr(rel), checkOpfusionObj->m_global->m_tupDesc)) { + heap_close(rel, NoLock); + return NULL; } + + heap_close(rel, NoLock); /* call specific reset function here*/ if (!checkOpfusionObj->ResetReuseFusion(context, psrc, plantree_list, params)){ @@ -1471,4 +1473,5 @@ void AtEOXact_OpfusionReuse() * the are the sub nodes of the top transaction ctx */ u_sess->opfusion_reuse_ctx.opfusionObj = NULL; + u_sess->iud_expr_reuse_ctx = NULL; } diff --git a/src/gausskernel/runtime/opfusion/opfusion_delete.cpp b/src/gausskernel/runtime/opfusion/opfusion_delete.cpp index d0ddeb05bf7fc46cca87faf4a2c82e498d42b538..6055f95f35fe2ad958fcdab2e22e0ea04b7ffa99 100644 --- a/src/gausskernel/runtime/opfusion/opfusion_delete.cpp +++ b/src/gausskernel/runtime/opfusion/opfusion_delete.cpp @@ -26,6 +26,7 @@ #include "access/tableam.h" #include "commands/matview.h" +#include "opfusion/opfusion_indexscan.h" DeleteFusion::DeleteFusion(MemoryContext context, CachedPlanSource* psrc, List* plantree_list, ParamListInfo params) : OpFusion(context, psrc, plantree_list) @@ -47,7 +48,7 @@ void DeleteFusion::InitLocals(ParamListInfo params) m_local.m_tmpvals = NULL; m_local.m_tmpisnull = NULL; - m_c_local.m_estate = CreateExecutorState(); + m_c_local.m_estate = CreateExecutorStateForOpfusion(m_local.m_localContext, m_local.m_tmpContext); m_c_local.m_estate->es_range_table = m_global->m_planstmt->rtable; m_local.m_reslot = MakeSingleTupleTableSlot(m_global->m_tupDesc); @@ -73,14 +74,14 @@ void DeleteFusion::InitGlobals() { m_global->m_reloid = getrelid(linitial_int((List*)linitial(m_global->m_planstmt->resultRelations)), m_global->m_planstmt->rtable); - Relation rel = heap_open(m_global->m_reloid, AccessShareLock); + Relation rel = heap_open(m_global->m_reloid, RowExclusiveLock); m_global->m_natts = RelationGetDescr(rel)->natts; m_global->m_tupDesc = CreateTupleDescCopy(RelationGetDescr(rel)); m_global->m_is_bucket_rel = RELATION_OWN_BUCKET(rel); m_global->m_table_type = RelationIsUstoreFormat(rel) ? TAM_USTORE : TAM_HEAP; m_global->m_tupDesc->td_tam_ops = GetTableAmRoutine(m_global->m_table_type); m_global->m_exec_func_ptr = (OpFusionExecfuncType)&DeleteFusion::ExecDelete; - heap_close(rel, AccessShareLock); + heap_close(rel, NoLock); } @@ -283,7 +284,7 @@ bool DeleteFusion::execute(long max_rows, char *completionTag) /* *************** * step 3: done * *************** */ - ExecCloseIndices(result_rel_info); + OpFusionExecCloseIndices(result_rel_info); m_local.m_isCompleted = true; m_local.m_scan->End(true); ExecDoneStepInFusion(m_c_local.m_estate); @@ -296,7 +297,44 @@ bool DeleteFusion::execute(long max_rows, char *completionTag) snprintf_s(completionTag, COMPLETION_TAG_BUFSIZE, COMPLETION_TAG_BUFSIZE - 1, "DELETE %ld", nprocessed); } securec_check_ss(errorno, "\0", "\0"); + FreeExecutorStateForOpfusion(m_c_local.m_estate); u_sess->statement_cxt.current_row_count = nprocessed; u_sess->statement_cxt.last_row_count = u_sess->statement_cxt.current_row_count; return success; } + +bool DeleteFusion::ResetReuseFusion(MemoryContext context, CachedPlanSource* psrc, List* plantree_list, ParamListInfo params) +{ + PlannedStmt *curr_plan = (PlannedStmt *)linitial(plantree_list); + int rtindex = linitial_int((List*)linitial(curr_plan->resultRelations)); + Oid curr_relid = getrelid(rtindex, curr_plan->rtable); + + if (curr_relid != m_global->m_reloid) { + return false; + } + m_global->m_planstmt = curr_plan; + + m_local.m_tmpvals = NULL; + m_local.m_tmpisnull = NULL; + + m_local.m_receiver = NULL; + m_local.m_isInsideRec = true; + + m_c_local.m_estate->es_range_table = m_global->m_planstmt->rtable; + m_c_local.m_estate->es_plannedstmt = m_global->m_planstmt; + + initParams(params); + + ModifyTable* node = (ModifyTable*)m_global->m_planstmt->planTree; + Plan *deletePlan = (Plan *)linitial(node->plans); + IndexScan* indexscan = (IndexScan *)JudgePlanIsPartIterator(deletePlan); + if (IsA(indexscan, IndexScan) && typeid(*(m_local.m_scan)) == typeid(IndexScanFusion)) { + ((IndexScanFusion *)m_local.m_scan)->ResetIndexScanFusion(indexscan, m_global->m_planstmt, + m_local.m_outParams ? m_local.m_outParams : m_local.m_params); + } else { + m_local.m_scan = ScanFusion::getScanFusion((Node*)indexscan, m_global->m_planstmt, + m_local.m_outParams ? m_local.m_outParams : m_local.m_params); + } + + return true; +} diff --git a/src/gausskernel/runtime/opfusion/opfusion_indexscan.cpp b/src/gausskernel/runtime/opfusion/opfusion_indexscan.cpp index a61c0b6dfeeed7e314b879e714a46a942683fdd1..5120073db5d2cdb7b5727f759b94a92c89a4608e 100644 --- a/src/gausskernel/runtime/opfusion/opfusion_indexscan.cpp +++ b/src/gausskernel/runtime/opfusion/opfusion_indexscan.cpp @@ -102,6 +102,7 @@ IndexScanFusion::IndexScanFusion(IndexScan* node, PlannedStmt* planstmt, ParamLi setAttrNo(); Relation dummyIndex = NULL; ExeceDoneInIndexFusionConstruct(m_node->scan.isPartTbl, &m_parentRel, &m_partRel, &dummyIndex, &m_rel); + m_can_reused = false; } @@ -171,7 +172,11 @@ void IndexScanFusion::Init(long max_rows) } m_epq_indexqual = m_node->indexqualorig; - m_reslot = MakeSingleTupleTableSlot(m_tupDesc, false, m_rel->rd_tam_ops); + if (m_can_reused && m_reslot != NULL) { + ExecSetSlotDescriptor(m_reslot, m_tupDesc); + } else { + m_reslot = MakeSingleTupleTableSlot(m_tupDesc, false, m_rel->rd_tam_ops); + } } HeapTuple IndexScanFusion::getTuple() @@ -255,7 +260,6 @@ void IndexScanFusion::End(bool isCompleted) return; if (m_reslot != NULL) { - (void)ExecClearTuple(m_reslot); m_reslot = NULL; } if (m_scandesc != NULL) { @@ -289,3 +293,47 @@ void IndexScanFusion::End(bool isCompleted) } } +void IndexScanFusion::ResetIndexScanFusion(IndexScan* node, PlannedStmt* planstmt, ParamListInfo params) +{ + m_node = node; + m_keyInit = false; + m_keyNum = list_length(node->indexqual); + + m_scanKeys = (ScanKey)palloc0(m_keyNum * sizeof(ScanKeyData)); + + /* init params */ + m_paramLoc = NULL; + m_paramNum = 0; + if (params != NULL) { + m_paramLoc = (ParamLoc*)palloc0(m_keyNum * sizeof(ParamLoc)); + + ListCell* lc = NULL; + int i = 0; + foreach (lc, node->indexqual) { + if (IsA(lfirst(lc), NullTest)) { + i++; + continue; + } + + Assert(IsA(lfirst(lc), OpExpr)); + + OpExpr* opexpr = (OpExpr*)lfirst(lc); + Expr* var = (Expr*)lsecond(opexpr->args); + + if (IsA(var, RelabelType)) { + var = ((RelabelType*)var)->arg; + } + + if (IsA(var, Param)) { + Param* param = (Param*)var; + m_paramLoc[m_paramNum].paramId = param->paramid; + m_paramLoc[m_paramNum++].scanKeyIndx = i; + } + i++; + } + } + m_targetList = m_node->scan.plan.targetlist; + + setAttrNo(); + m_can_reused = true; +} \ No newline at end of file diff --git a/src/gausskernel/runtime/opfusion/opfusion_insert.cpp b/src/gausskernel/runtime/opfusion/opfusion_insert.cpp index 5ad238a07848fdf087606150bbc7e41c5a88d608..519677a22d5caf94fef391f48350ba0a50dd9cfa 100644 --- a/src/gausskernel/runtime/opfusion/opfusion_insert.cpp +++ b/src/gausskernel/runtime/opfusion/opfusion_insert.cpp @@ -231,7 +231,7 @@ static void ExecReleaseResource(Tuple tuple, TupleTableSlot *slot, ResultRelInfo { tableam_tops_free_tuple(tuple); (void)ExecClearTuple(slot); - ExecCloseIndices(result_rel_info); + OpFusionExecCloseIndices(result_rel_info); ExecDoneStepInFusion(estate); if (bucket_rel != NULL) { bucketCloseRelation(bucket_rel); @@ -436,7 +436,7 @@ bool InsertFusion::execute(long max_rows, char* completionTag) ************************/ unsigned long nprocessed = (this->*(m_global->m_exec_func_ptr))(rel, result_rel_info); - heap_close(rel, RowExclusiveLock); + heap_close(rel, NoLock); /**************** * step 3: done * @@ -482,10 +482,12 @@ bool InsertFusion::ResetReuseFusion(MemoryContext context, CachedPlanSource* psr InitBaseParam(targetList); // local + m_local.m_reslot->tts_tam_ops = GetTableAmRoutine(m_global->m_table_type); m_c_local.m_estate->es_range_table = NIL; m_c_local.m_estate->es_range_table = m_global->m_planstmt->rtable; m_c_local.m_estate->es_plannedstmt = m_global->m_planstmt; initParams(params); return true; -} \ No newline at end of file +} + diff --git a/src/gausskernel/runtime/opfusion/opfusion_update.cpp b/src/gausskernel/runtime/opfusion/opfusion_update.cpp index 70b10e37b301933ec3ec6a62af2e47ddccd76af5..657d81b2b165977c5c2a0f8fbe6f5bec450b6293 100644 --- a/src/gausskernel/runtime/opfusion/opfusion_update.cpp +++ b/src/gausskernel/runtime/opfusion/opfusion_update.cpp @@ -116,7 +116,7 @@ void UpdateFusion::InitGlobals() m_global->m_reloid = getrelid(linitial_int((List*)linitial(m_global->m_planstmt->resultRelations)), m_global->m_planstmt->rtable); - Relation rel = heap_open(m_global->m_reloid, AccessShareLock); + Relation rel = heap_open(m_global->m_reloid, RowExclusiveLock); m_global->m_table_type = RelationIsUstoreFormat(rel) ? TAM_USTORE : TAM_HEAP; m_global->m_exec_func_ptr = (OpFusionExecfuncType)&UpdateFusion::ExecUpdate; m_global->m_is_bucket_rel = RELATION_OWN_BUCKET(rel); @@ -124,7 +124,7 @@ void UpdateFusion::InitGlobals() m_global->m_tupDesc = CreateTupleDescCopy(RelationGetDescr(rel)); m_global->m_tupDesc->td_tam_ops = GetTableAmRoutine(m_global->m_table_type); hash_col_num = rel->rd_isblockchain ? 1 : 0; - heap_close(rel, AccessShareLock); + heap_close(rel, NoLock); #ifdef USE_ASSERT_CHECKING if (m_global->m_is_bucket_rel) { @@ -571,7 +571,7 @@ lreplace: /**************** * step 3: done * ****************/ - ExecCloseIndices(result_rel_info); + OpFusionExecCloseIndices(result_rel_info); m_local.m_isCompleted = true; m_local.m_scan->End(true); ExecDoneStepInFusion(m_c_local.m_estate); diff --git a/src/gausskernel/runtime/opfusion/opfusion_util.cpp b/src/gausskernel/runtime/opfusion/opfusion_util.cpp index 321b80a8a84bc434112e7cdf8f65fdfda2440096..5b1facfbb30dce7f555190f5920bf8c28144ce0f 100644 --- a/src/gausskernel/runtime/opfusion/opfusion_util.cpp +++ b/src/gausskernel/runtime/opfusion/opfusion_util.cpp @@ -29,6 +29,7 @@ #include "access/transam.h" #include "catalog/pg_aggregate.h" #include "catalog/pg_partition_fn.h" +#include "catalog/pg_proc.h" #include "commands/copy.h" #include "executor/node/nodeIndexscan.h" #include "libpq/pqformat.h" @@ -328,7 +329,7 @@ bool checkFusionParam(Param *param, ParamListInfo boundParams) return false; } -static bool checkFlinfo(Node *node) +static bool checkFlinfo(Node *node, bool *is_nextval) { /* check whether the flinfo satisfy conditon */ FmgrInfo *flinfo = NULL; @@ -338,6 +339,10 @@ static bool checkFlinfo(Node *node) pfree(flinfo); flinfo = NULL; return false; + } + /* Help function nextval_oid support SQL Bypass */ + if (flinfo->fn_oid == NEXTVALFUNCOID) { + *is_nextval = true; } pfree(flinfo); flinfo = NULL; @@ -360,9 +365,13 @@ static bool checkExpr(Node *node, bool is_first) if (is_first == false) { return false; } - if (!checkFlinfo(node)) { + bool is_nextval = false; + if (!checkFlinfo(node, &is_nextval)) { return false; } + if (is_nextval) { + return true; + } bool found_ptr = true; void *ans = NULL; ans = hash_search(g_instance.exec_cxt.function_id_hashtbl, (void *)&((FuncExpr *)node)->funcid, HASH_FIND, @@ -526,10 +535,10 @@ template FusionType checkFusionIndexScan(Node *n index = index_open(indexOid, AccessShareLock); if (!OID_IS_BTREE(index->rd_rel->relam)) { - index_close(index, AccessShareLock); + index_close(index, NoLock); return NOBYPASS_ONLY_SUPPORT_BTREE_INDEX; } - index_close(index, AccessShareLock); + index_close(index, NoLock); ListCell *lc = NULL; @@ -944,7 +953,7 @@ FusionType getInsertFusionType(List *stmt_list, ParamListInfo params) return NOBYPASS_INVALID_MODIFYTABLE; } #else - if (!IsA(top_plan, ModifyTable) || top_plan->plan_node_id != 1) { + if (!IsA(top_plan, ModifyTable)) { return NOBYPASS_INVALID_MODIFYTABLE; } #endif @@ -960,7 +969,7 @@ FusionType getInsertFusionType(List *stmt_list, ParamListInfo params) /* check relation */ Index res_rel_idx = linitial_int((List*)linitial(plannedstmt->resultRelations)); Oid relid = getrelid(res_rel_idx, plannedstmt->rtable); - Relation rel = heap_open(relid, AccessShareLock); + Relation rel = heap_open(relid, RowExclusiveLock); for (int i = 0; i < rel->rd_att->natts; i++) { if (rel->rd_att->attrs[i].attisdropped) { @@ -976,27 +985,27 @@ FusionType getInsertFusionType(List *stmt_list, ParamListInfo params) Form_pg_type type_form = (Form_pg_type)GETSTRUCT(tuple); ReleaseSysCache(tuple); if (type_form->typtype != 'b') { - heap_close(rel, AccessShareLock); + heap_close(rel, NoLock); return NOBYPASS_DML_TARGET_TYPE_INVALID; } } if (checkDMLRelation(rel, plannedstmt, true, RELATION_IS_PARTITIONED(rel))) { - heap_close(rel, AccessShareLock); + heap_close(rel, NoLock); return NOBYPASS_DML_RELATION_NOT_SUPPORT; } if (RELATION_IS_PARTITIONED(rel) && !u_sess->attr.attr_sql.enable_partition_opfusion) { - heap_close(rel, AccessShareLock); + heap_close(rel, NoLock); return NOBYPASS_PARTITION_BYPASS_NOT_OPEN; } if (RELATION_IS_PARTITIONED(rel) && ENABLE_GPC) { - heap_close(rel, AccessShareLock); + heap_close(rel, NoLock); return NOBYPASS_GPC_NOT_SUPPORT_PARTITION_BYPASS; } if (checkPartitionType(rel)) { - heap_close(rel, AccessShareLock); + heap_close(rel, NoLock); return NOBYPASS_PARTITION_TYPE_NOT_SUPPORT; } - heap_close(rel, AccessShareLock); + heap_close(rel, NoLock); /* * check targetlist * maybe expr type is FuncExpr because of type conversion. @@ -1022,7 +1031,7 @@ FusionType getUpdateFusionType(List *stmt_list, ParamListInfo params) return NOBYPASS_INVALID_MODIFYTABLE; } #else - if (!IsA(top_plan, ModifyTable) || top_plan->plan_node_id != 1) { + if (!IsA(top_plan, ModifyTable)) { return NOBYPASS_INVALID_MODIFYTABLE; } #endif @@ -1059,16 +1068,16 @@ FusionType getUpdateFusionType(List *stmt_list, ParamListInfo params) IndexScan *indexscan = (IndexScan *)updatePlan; Index res_rel_idx = linitial_int((List*)linitial(plannedstmt->resultRelations)); Oid relid = getrelid(res_rel_idx, plannedstmt->rtable); - Relation rel = heap_open(relid, AccessShareLock); + Relation rel = heap_open(relid, RowExclusiveLock); if (checkDMLRelation(rel, plannedstmt, false, indexscan->scan.isPartTbl)) { - heap_close(rel, AccessShareLock); + heap_close(rel, NoLock); return NOBYPASS_DML_RELATION_NOT_SUPPORT; } if (checkPartitionType(rel)) { - heap_close(rel, AccessShareLock); + heap_close(rel, NoLock); return NOBYPASS_PARTITION_TYPE_NOT_SUPPORT; } - heap_close(rel, AccessShareLock); + heap_close(rel, NoLock); /* check target list */ if (node->partKeyUpdated) { @@ -1103,7 +1112,7 @@ FusionType getDeleteFusionType(List *stmt_list, ParamListInfo params) return NOBYPASS_INVALID_MODIFYTABLE; } #else - if (!IsA(top_plan, ModifyTable) || top_plan->plan_node_id != 1) { + if (!IsA(top_plan, ModifyTable)) { return NOBYPASS_INVALID_MODIFYTABLE; } #endif @@ -1138,16 +1147,16 @@ FusionType getDeleteFusionType(List *stmt_list, ParamListInfo params) /* check relation */ Index res_rel_idx = linitial_int((List*)linitial(plannedstmt->resultRelations)); Oid relid = getrelid(res_rel_idx, plannedstmt->rtable); - Relation rel = heap_open(relid, AccessShareLock); + Relation rel = heap_open(relid, RowExclusiveLock); if (checkDMLRelation(rel, plannedstmt, false, indexscan->scan.isPartTbl)) { - heap_close(rel, AccessShareLock); + heap_close(rel, NoLock); return NOBYPASS_DML_RELATION_NOT_SUPPORT; } if (checkPartitionType(rel)) { - heap_close(rel, AccessShareLock); + heap_close(rel, NoLock); return NOBYPASS_PARTITION_TYPE_NOT_SUPPORT; } - heap_close(rel, AccessShareLock); + heap_close(rel, NoLock); /* check the number of partitions */ if (indexscan->scan.isPartTbl) { diff --git a/src/gausskernel/storage/access/common/tupdesc.cpp b/src/gausskernel/storage/access/common/tupdesc.cpp index d0cc0741fd075b81db18feed7735820cf8626182..668a56423957bcf168fa8a938ad1a2fb723f853c 100644 --- a/src/gausskernel/storage/access/common/tupdesc.cpp +++ b/src/gausskernel/storage/access/common/tupdesc.cpp @@ -664,6 +664,112 @@ bool equalTupleDescs(TupleDesc tupdesc1, TupleDesc tupdesc2) return compareInitdefvals(tupdesc1, tupdesc2); } +bool opFusionReuseEqualTupleDescs(TupleDesc tupdesc1, TupleDesc tupdesc2) +{ + int i; + + if (tupdesc1->natts != tupdesc2->natts) { + return false; + } + if (tupdesc1->tdtypeid != tupdesc2->tdtypeid) { + return false; + } + if (tupdesc1->tdhasoid != tupdesc2->tdhasoid) { + return false; + } + + if (tupdesc1->tdisredistable != tupdesc2->tdisredistable) { + return false; + } + + if (tupdesc1->td_tam_ops != tupdesc2->td_tam_ops) { + return false; + } + + for (i = 0; i < tupdesc1->natts; i++) { + Form_pg_attribute attr1 = &tupdesc1->attrs[i]; + Form_pg_attribute attr2 = &tupdesc2->attrs[i]; + + /* + * We do not need to check every single field here: we can disregard + * attrelid and attnum (which were used to place the row in the attrs + * array in the first place). It might look like we could dispense + * with checking attlen/attbyval/attalign, since these are derived + * from atttypid; but in the case of dropped columns we must check + * them (since atttypid will be zero for all dropped columns) and in + * general it seems safer to check them always. + * + * attcacheoff must NOT be checked since it's possibly not set in both + * copies. + */ + if (strcmp(NameStr(attr1->attname), NameStr(attr2->attname)) != 0) { + return false; + } + + if (attr1->attnum != attr2->attnum) { + return false; + } + + const bool cl_skip = IsClientLogicType(attr1->atttypid) && (Oid)attr1->atttypmod == attr2->atttypid; + if (attr1->atttypid != attr2->atttypid && !cl_skip) { + return false; + } + if (attr1->attstattarget != attr2->attstattarget) { + return false; + } + if (attr1->attlen != attr2->attlen) { + return false; + } + if (attr1->attndims != attr2->attndims) { + return false; + } + if (attr1->atttypmod != attr2->atttypmod && !cl_skip) { + return false; + } + if (attr1->attbyval != attr2->attbyval) { + return false; + } + if (attr1->attstorage != attr2->attstorage && !cl_skip) { + return false; + } + if (attr1->attkvtype != attr2->attkvtype) { + return false; + } + if (attr1->attcmprmode != attr2->attcmprmode) { + return false; + } + if (attr1->attalign != attr2->attalign) { + return false; + } + if (attr2->attnotnull) { + return false; + } + if (attr2->atthasdef) { + return false; + } + if (attr1->attisdropped != attr2->attisdropped) { + return false; + } + if (attr1->attislocal != attr2->attislocal) { + return false; + } + if (attr1->attinhcount != attr2->attinhcount) { + return false; + } + if (attr1->attcollation != attr2->attcollation && !cl_skip) { + return false; + } + /* attacl, attoptions and attfdwoptions are not even present... */ + } + + if (tupdesc2->constr != NULL) { + return false; + } + + /* compare the attinitdefval */ + return compareInitdefvals(tupdesc1, tupdesc2); +} + static bool ComparePgAttribute(Form_pg_attribute attr1, Form_pg_attribute attr2) { /* diff --git a/src/gausskernel/storage/buffer/bufmgr.cpp b/src/gausskernel/storage/buffer/bufmgr.cpp index 8e79236af711c0ec7e26450202fa4179e59f8163..285172e5fc948101e82cb93f7a037ae2ca27f309 100644 --- a/src/gausskernel/storage/buffer/bufmgr.cpp +++ b/src/gausskernel/storage/buffer/bufmgr.cpp @@ -2032,11 +2032,7 @@ static bool ReadBuffer_common_ReadBlock(SMgrRelation smgr, char relpersistence, pgstat_count_buffer_read_time(INSTR_TIME_GET_MICROSEC(io_time)); INSTR_TIME_ADD(u_sess->instr_cxt.pg_buffer_usage->blk_read_time, io_time); pgstatCountBlocksReadTime4SessionLevel(INSTR_TIME_GET_MICROSEC(io_time)); - } else { - INSTR_TIME_SET_CURRENT(io_time); - INSTR_TIME_SUBTRACT(io_time, io_start); - pgstatCountBlocksReadTime4SessionLevel(INSTR_TIME_GET_MICROSEC(io_time)); - } + } /* check for garbage data */ if (rdStatus == SMGR_RD_CRC_ERROR) { diff --git a/src/include/access/tupdesc.h b/src/include/access/tupdesc.h index 42b8146dc96196f61a7ce47a6955f4cc737bea22..7fd743daf34722b886dc5b668793e83b109f985b 100644 --- a/src/include/access/tupdesc.h +++ b/src/include/access/tupdesc.h @@ -195,6 +195,7 @@ extern void DecrTupleDescRefCount(TupleDesc tupdesc); } while (0) extern bool equalTupleDescs(TupleDesc tupdesc1, TupleDesc tupdesc2); +extern bool opFusionReuseEqualTupleDescs(TupleDesc tupdesc1, TupleDesc tupdesc2); extern bool equalDeltaTupleDescs(TupleDesc main_tupdesc, TupleDesc delta_tupdesc); extern void TupleDescInitEntry( diff --git a/src/include/executor/executor.h b/src/include/executor/executor.h index 14ee0ad6ad067dedb0f7de60bbcaf52116b0665b..7f2b5828adc341296458cac599b8d06b1dad1642 100755 --- a/src/include/executor/executor.h +++ b/src/include/executor/executor.h @@ -644,6 +644,7 @@ extern Partition ExecOpenScanParitition( extern void ExecOpenIndices(ResultRelInfo* resultRelInfo, bool speculative); extern void ExecCloseIndices(ResultRelInfo* resultRelInfo); +extern void OpFusionExecCloseIndices(ResultRelInfo* resultRelInfo); extern List* ExecInsertIndexTuples( TupleTableSlot* slot, ItemPointer tupleid, EState* estate, Relation targetPartRel, Partition p, int2 bucketId, bool* conflict, Bitmapset *modifiedIdxAttrs, bool inplaceUpdated = false); diff --git a/src/include/knl/knl_session.h b/src/include/knl/knl_session.h index e27a936d42926ae705c46e7792e78a2c86592579..ed5dfad4930bda9c90bb7d3f81a0d0320f73ed6d 100644 --- a/src/include/knl/knl_session.h +++ b/src/include/knl/knl_session.h @@ -2913,6 +2913,7 @@ typedef struct knl_session_context { knl_u_dolphin_errdata_context dolphin_errdata_ctx; knl_u_opfusion_reuse_context opfusion_reuse_ctx; + MemoryContext iud_expr_reuse_ctx; /* * Initialize context which records time for client connection establish. @@ -2925,6 +2926,8 @@ typedef struct knl_session_context { knl_u_hook_context hook_cxt; + MemoryContext opfusion_cxt; + /* The datetime cache in current transaction. */ TimestampTz cache_ts = 0; pg_tz* cache_timezone = NULL; diff --git a/src/include/opfusion/opfusion_delete.h b/src/include/opfusion/opfusion_delete.h index 9e0c8fb439f7791f86ac10949bf4a16b5e3baccd..f437bd2d0108dc557b5e9c11b73ead97a0dc5b19 100644 --- a/src/include/opfusion/opfusion_delete.h +++ b/src/include/opfusion/opfusion_delete.h @@ -38,6 +38,7 @@ public: void InitLocals(ParamListInfo params); void InitGlobals(); + bool ResetReuseFusion(MemoryContext context, CachedPlanSource* psrc, List* plantree_list, ParamListInfo params); private: struct DeleteFusionLocaleVariable { EState* m_estate; diff --git a/src/include/opfusion/opfusion_indexscan.h b/src/include/opfusion/opfusion_indexscan.h index a9bb62e96de590e166866fb6e0a7402cdf06527f..4102dd19d0ec659775e890c170a48557072b54fd 100644 --- a/src/include/opfusion/opfusion_indexscan.h +++ b/src/include/opfusion/opfusion_indexscan.h @@ -46,8 +46,10 @@ public: TupleTableSlot* getTupleSlot(); + void ResetIndexScanFusion(IndexScan* node, PlannedStmt* planstmt, ParamListInfo params); private: struct IndexScan* m_node; + bool m_can_reused; }; #endif /* SRC_INCLUDE_OPFUSION_OPFUSION_INDEXSCAN_H_ */ \ No newline at end of file diff --git a/src/test/regress/expected/unsupported_features.out b/src/test/regress/expected/unsupported_features.out index 1692f8fb531ac8d0c03154f3befb821a6597b15b..31e6b98a40e0535f95aeceddede1a108daffa73a 100644 --- a/src/test/regress/expected/unsupported_features.out +++ b/src/test/regress/expected/unsupported_features.out @@ -6,9 +6,10 @@ CREATE SEQUENCE CURRVAL_SEQUENCE_009 INCREMENT BY 100 START WITH 1; explain (costs off) INSERT INTO SEQ_CURRVAL_TABLE_009 VALUES('nextval',nextval('CURRVAL_SEQUENCE_009')); QUERY PLAN --------------------------------- + [Bypass] Insert on seq_currval_table_009 -> Result -(2 rows) +(3 rows) INSERT INTO SEQ_CURRVAL_TABLE_009 VALUES('nextval',nextval('CURRVAL_SEQUENCE_009')); INSERT INTO SEQ_CURRVAL_TABLE_009 VALUES('nextval',nextval('CURRVAL_SEQUENCE_009'));