diff --git a/src/backend/distributed/planner/merge_planner.c b/src/backend/distributed/planner/merge_planner.c index e8f11cda4..730c53d39 100644 --- a/src/backend/distributed/planner/merge_planner.c +++ b/src/backend/distributed/planner/merge_planner.c @@ -157,6 +157,32 @@ CreateMergePlan(uint64 planId, Query *originalQuery, Query *query, } +/* + * GetMergeJoinConditionList returns all the Join conditions from the ON clause + */ +List * +GetMergeJoinConditionList(Query *mergeQuery) +{ +#if PG_VERSION_NUM >= PG_VERSION_17 + List *mergeJoinConditionList = NIL; + if (IsA(mergeQuery->mergeJoinCondition, List)) + { + mergeJoinConditionList = (List *) mergeQuery->mergeJoinCondition; + } + else + { + Node *joinClause = + eval_const_expressions(NULL, mergeQuery->mergeJoinCondition); + joinClause = (Node *) canonicalize_qual((Expr *) joinClause, false); + mergeJoinConditionList = make_ands_implicit((Expr *) joinClause); + } +#else + List *mergeJoinConditionList = WhereClauseList(mergeQuery->jointree); +#endif + return mergeJoinConditionList; +} + + #if PG_VERSION_NUM >= PG_VERSION_15 /* @@ -563,7 +589,6 @@ MergeQualAndTargetListFunctionsSupported(Oid resultRelationId, Query *query, List *targetList, CmdType commandType) { uint32 targetRangeTableIndex = query->resultRelation; - FromExpr *joinTree = query->jointree; Var *distributionColumn = NULL; if (IsCitusTable(resultRelationId) && HasDistributionKey(resultRelationId)) { @@ -601,7 +626,8 @@ MergeQualAndTargetListFunctionsSupported(Oid resultRelationId, Query *query, } if (targetEntryDistributionColumn && - TargetEntryChangesValue(targetEntry, distributionColumn, joinTree)) + TargetEntryChangesValue(targetEntry, distributionColumn, (Node *) query, + CMD_MERGE)) { return DeferredError(ERRCODE_FEATURE_NOT_SUPPORTED, "updating the distribution column is not " @@ -723,8 +749,13 @@ ErrorIfRepartitionMergeNotSupported(Oid targetRelationId, Query *mergeQuery, /* * Sub-queries and CTEs are not allowed in actions and ON clause */ - if (FindNodeMatchingCheckFunction((Node *) mergeQuery->mergeJoinCondition, - IsNodeSubquery)) +#if PG_VERSION_NUM >= PG_VERSION_17 + Node *joinCondition = (Node *) mergeQuery->mergeJoinCondition; +#else + Node *joinCondition = (Node *) mergeQuery->jointree->quals; +#endif + + if (FindNodeMatchingCheckFunction(joinCondition, IsNodeSubquery)) { ereport(ERROR, (errmsg("Sub-queries and CTEs are not allowed in ON clause for MERGE " @@ -1224,11 +1255,17 @@ ErrorIfMergeQueryQualAndTargetListNotSupported(Oid targetRelationId, Query *orig "supported in MERGE sql with distributed tables"))); } +#if PG_VERSION_NUM >= PG_VERSION_17 + Node *joinCondition = (Node *) originalQuery->mergeJoinCondition; +#else + Node *joinCondition = (Node *) originalQuery->jointree->quals; +#endif + DeferredErrorMessage *deferredError = MergeQualAndTargetListFunctionsSupported( targetRelationId, originalQuery, - originalQuery->mergeJoinCondition, + joinCondition, originalQuery->targetList, originalQuery->commandType); @@ -1304,20 +1341,7 @@ static int SourceResultPartitionColumnIndex(Query *mergeQuery, List *sourceTargetList, CitusTableCacheEntry *targetRelation) { - /* Get all the Join conditions from the ON clause */ - List *mergeJoinConditionList = NIL; - if (IsA(mergeQuery->mergeJoinCondition, List)) - { - mergeJoinConditionList = (List *) mergeQuery->mergeJoinCondition; - } - else - { - Node *joinClause = - eval_const_expressions(NULL, mergeQuery->mergeJoinCondition); - joinClause = (Node *) canonicalize_qual((Expr *) joinClause, false); - mergeJoinConditionList = make_ands_implicit((Expr *) joinClause); - } - + List *mergeJoinConditionList = GetMergeJoinConditionList(mergeQuery); Var *targetColumn = targetRelation->partitionColumn; Var *sourceRepartitionVar = NULL; bool foundTypeMismatch = false; diff --git a/src/backend/distributed/planner/multi_router_planner.c b/src/backend/distributed/planner/multi_router_planner.c index bb1f64488..ee88bb551 100644 --- a/src/backend/distributed/planner/multi_router_planner.c +++ b/src/backend/distributed/planner/multi_router_planner.c @@ -597,9 +597,9 @@ TargetlistAndFunctionsSupported(Oid resultRelationId, FromExpr *joinTree, Node * NULL, NULL); } - if (commandType == CMD_UPDATE && targetEntryPartitionColumn && + if (targetEntryPartitionColumn && TargetEntryChangesValue(targetEntry, partitionColumn, - joinTree)) + (Node *) joinTree, commandType)) { return DeferredError(ERRCODE_FEATURE_NOT_SUPPORTED, "modifying the partition value of rows is not " @@ -1611,8 +1611,15 @@ MasterIrreducibleExpressionFunctionChecker(Oid func_id, void *context) * tree, or the target entry sets a different column. */ bool -TargetEntryChangesValue(TargetEntry *targetEntry, Var *column, FromExpr *joinTree) +TargetEntryChangesValue(TargetEntry *targetEntry, Var *column, Node *node, CmdType + commandType) { + if (commandType != CMD_UPDATE && commandType != CMD_MERGE) + { + /* no-op */ + return false; + } + bool isColumnValueChanged = true; Expr *setExpr = targetEntry->expr; @@ -1628,7 +1635,6 @@ TargetEntryChangesValue(TargetEntry *targetEntry, Var *column, FromExpr *joinTre else if (IsA(setExpr, Const)) { Const *newValue = (Const *) setExpr; - List *restrictClauseList = WhereClauseList(joinTree); OpExpr *equalityExpr = MakeOpExpression(column, BTEqualStrategyNumber); Node *rightOp = get_rightop((Expr *) equalityExpr); @@ -1640,6 +1646,16 @@ TargetEntryChangesValue(TargetEntry *targetEntry, Var *column, FromExpr *joinTre rightConst->constisnull = newValue->constisnull; rightConst->constbyval = newValue->constbyval; + List *restrictClauseList = NIL; + if (commandType == CMD_UPDATE) + { + restrictClauseList = WhereClauseList((FromExpr *) node); + } + else + { + restrictClauseList = GetMergeJoinConditionList((Query *) node); + } + bool predicateIsImplied = predicate_implied_by(list_make1(equalityExpr), restrictClauseList, false); if (predicateIsImplied) diff --git a/src/include/distributed/merge_planner.h b/src/include/distributed/merge_planner.h index b6636687a..a1470caa7 100644 --- a/src/include/distributed/merge_planner.h +++ b/src/include/distributed/merge_planner.h @@ -32,6 +32,7 @@ extern void NonPushableMergeCommandExplainScan(CustomScanState *node, List *ance struct ExplainState *es); extern Var * FetchAndValidateInsertVarIfExists(Oid targetRelationId, Query *query); extern RangeTblEntry * ExtractMergeSourceRangeTableEntry(Query *query, bool joinSourceOk); +extern List * GetMergeJoinConditionList(Query *mergeQuery); #endif /* MERGE_PLANNER_H */ diff --git a/src/include/distributed/multi_router_planner.h b/src/include/distributed/multi_router_planner.h index ae75ee631..b80b10530 100644 --- a/src/include/distributed/multi_router_planner.h +++ b/src/include/distributed/multi_router_planner.h @@ -111,7 +111,7 @@ extern DeferredErrorMessage * TargetlistAndFunctionsSupported(Oid resultRelation List *returningList); extern bool NodeIsFieldStore(Node *node); extern bool TargetEntryChangesValue(TargetEntry *targetEntry, Var *column, - FromExpr *joinTree); + Node *node, CmdType commandType); extern bool MasterIrreducibleExpression(Node *expression, bool *varArgument, bool *badCoalesce); extern bool HasDangerousJoinUsing(List *rtableList, Node *jtnode); diff --git a/src/test/regress/expected/merge_unsupported_0.out b/src/test/regress/expected/merge_unsupported_0.out new file mode 100644 index 000000000..a7e3fbf20 --- /dev/null +++ b/src/test/regress/expected/merge_unsupported_0.out @@ -0,0 +1,6 @@ +SHOW server_version \gset +SELECT substring(:'server_version', '\d+')::int >= 15 AS server_version_ge_15 +\gset +\if :server_version_ge_15 +\else +\q