/* Take care of joins */ void pathman_join_pathlist_hook(PlannerInfo *root, RelOptInfo *joinrel, RelOptInfo *outerrel, RelOptInfo *innerrel, JoinType jointype, JoinPathExtraData *extra) { JoinCostWorkspace workspace; JoinType saved_jointype = jointype; RangeTblEntry *inner_rte = root->simple_rte_array[innerrel->relid]; const PartRelationInfo *inner_prel; List *joinclauses, *otherclauses; WalkerContext context; double paramsel; Node *part_expr; ListCell *lc; /* Call hooks set by other extensions */ if (pathman_set_join_pathlist_next) pathman_set_join_pathlist_next(root, joinrel, outerrel, innerrel, jointype, extra); /* Check that both pg_pathman & RuntimeAppend nodes are enabled */ if (!IsPathmanReady() || !pg_pathman_enable_runtimeappend) return; /* We should only consider base relations */ if (innerrel->reloptkind != RELOPT_BASEREL) return; /* We shouldn't process tables with active children */ if (inner_rte->inh) return; /* We can't handle full or right outer joins */ if (jointype == JOIN_FULL || jointype == JOIN_RIGHT) return; /* Check that innerrel is a BASEREL with PartRelationInfo */ if (innerrel->reloptkind != RELOPT_BASEREL || !(inner_prel = get_pathman_relation_info(inner_rte->relid))) return; /* * Check if query is: * 1) UPDATE part_table SET = .. FROM part_table. * 2) DELETE FROM part_table USING part_table. * * Either outerrel or innerrel may be a result relation. */ if ((root->parse->resultRelation == outerrel->relid || root->parse->resultRelation == innerrel->relid) && (root->parse->commandType == CMD_UPDATE || root->parse->commandType == CMD_DELETE)) { int rti = -1, count = 0; /* Inner relation must be partitioned */ Assert(inner_prel); /* Check each base rel of outer relation */ while ((rti = bms_next_member(outerrel->relids, rti)) >= 0) { Oid outer_baserel = root->simple_rte_array[rti]->relid; /* Is it partitioned? */ if (get_pathman_relation_info(outer_baserel)) count++; } if (count > 0) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("DELETE and UPDATE queries with a join " "of partitioned tables are not supported"))); } /* Skip if inner table is not allowed to act as parent (e.g. FROM ONLY) */ if (PARENTHOOD_DISALLOWED == get_rel_parenthood_status(inner_rte)) return; /* * These codes are used internally in the planner, but are not supported * by the executor (nor, indeed, by most of the planner). */ if (jointype == JOIN_UNIQUE_OUTER || jointype == JOIN_UNIQUE_INNER) jointype = JOIN_INNER; /* replace with a proper value */ /* Extract join clauses which will separate partitions */ if (IS_OUTER_JOIN(extra->sjinfo->jointype)) { extract_actual_join_clauses_compat(extra->restrictlist, joinrel->relids, &joinclauses, &otherclauses); } else { /* We can treat all clauses alike for an inner join */ joinclauses = extract_actual_clauses(extra->restrictlist, false); otherclauses = NIL; } /* Make copy of partitioning expression and fix Var's varno attributes */ part_expr = PrelExpressionForRelid(inner_prel, innerrel->relid); paramsel = 1.0; foreach (lc, joinclauses) { WrapperNode *wrap; InitWalkerContext(&context, part_expr, inner_prel, NULL); wrap = walk_expr_tree((Expr *) lfirst(lc), &context); paramsel *= wrap->paramsel; }
/* Take care of joins */ void pathman_join_pathlist_hook(PlannerInfo *root, RelOptInfo *joinrel, RelOptInfo *outerrel, RelOptInfo *innerrel, JoinType jointype, JoinPathExtraData *extra) { JoinCostWorkspace workspace; JoinType saved_jointype = jointype; RangeTblEntry *inner_rte = root->simple_rte_array[innerrel->relid]; const PartRelationInfo *inner_prel; List *joinclauses, *otherclauses; WalkerContext context; double paramsel; Node *part_expr; ListCell *lc; /* Call hooks set by other extensions */ if (set_join_pathlist_next) set_join_pathlist_next(root, joinrel, outerrel, innerrel, jointype, extra); /* Check that both pg_pathman & RuntimeAppend nodes are enabled */ if (!IsPathmanReady() || !pg_pathman_enable_runtimeappend) return; /* We should only consider base relations */ if (innerrel->reloptkind != RELOPT_BASEREL) return; /* We shouldn't process tables with active children */ if (inner_rte->inh) return; /* We can't handle full or right outer joins */ if (jointype == JOIN_FULL || jointype == JOIN_RIGHT) return; /* Check that innerrel is a BASEREL with PartRelationInfo */ if (innerrel->reloptkind != RELOPT_BASEREL || !(inner_prel = get_pathman_relation_info(inner_rte->relid))) return; /* Skip if inner table is not allowed to act as parent (e.g. FROM ONLY) */ if (PARENTHOOD_DISALLOWED == get_rel_parenthood_status(root->parse->queryId, inner_rte)) return; /* * These codes are used internally in the planner, but are not supported * by the executor (nor, indeed, by most of the planner). */ if (jointype == JOIN_UNIQUE_OUTER || jointype == JOIN_UNIQUE_INNER) jointype = JOIN_INNER; /* replace with a proper value */ /* Extract join clauses which will separate partitions */ if (IS_OUTER_JOIN(extra->sjinfo->jointype)) { extract_actual_join_clauses(extra->restrictlist, &joinclauses, &otherclauses); } else { /* We can treat all clauses alike for an inner join */ joinclauses = extract_actual_clauses(extra->restrictlist, false); otherclauses = NIL; } /* Make copy of partitioning expression and fix Var's varno attributes */ part_expr = PrelExpressionForRelid(inner_prel, innerrel->relid); paramsel = 1.0; foreach (lc, joinclauses) { WrapperNode *wrap; InitWalkerContext(&context, part_expr, inner_prel, NULL); wrap = walk_expr_tree((Expr *) lfirst(lc), &context); paramsel *= wrap->paramsel; }