diff options
Diffstat (limited to 'src/backend/executor')
-rw-r--r-- | src/backend/executor/nodeMergeAppend.c | 77 | ||||
-rw-r--r-- | src/backend/executor/nodeMergejoin.c | 146 |
2 files changed, 72 insertions, 151 deletions
diff --git a/src/backend/executor/nodeMergeAppend.c b/src/backend/executor/nodeMergeAppend.c index 43059664b93..6065e2176ac 100644 --- a/src/backend/executor/nodeMergeAppend.c +++ b/src/backend/executor/nodeMergeAppend.c @@ -38,10 +38,8 @@ #include "postgres.h" -#include "access/nbtree.h" #include "executor/execdebug.h" #include "executor/nodeMergeAppend.h" -#include "utils/lsyscache.h" /* * It gets quite confusing having a heap array (indexed by integers) which @@ -128,38 +126,18 @@ ExecInitMergeAppend(MergeAppend *node, EState *estate, int eflags) * initialize sort-key information */ mergestate->ms_nkeys = node->numCols; - mergestate->ms_scankeys = palloc0(sizeof(ScanKeyData) * node->numCols); + mergestate->ms_sortkeys = palloc0(sizeof(SortSupportData) * node->numCols); for (i = 0; i < node->numCols; i++) { - Oid sortFunction; - bool reverse; - int flags; - - if (!get_compare_function_for_ordering_op(node->sortOperators[i], - &sortFunction, &reverse)) - elog(ERROR, "operator %u is not a valid ordering operator", - node->sortOperators[i]); - - /* We use btree's conventions for encoding directionality */ - flags = 0; - if (reverse) - flags |= SK_BT_DESC; - if (node->nullsFirst[i]) - flags |= SK_BT_NULLS_FIRST; + SortSupport sortKey = mergestate->ms_sortkeys + i; - /* - * We needn't fill in sk_strategy or sk_subtype since these scankeys - * will never be passed to an index. - */ - ScanKeyEntryInitialize(&mergestate->ms_scankeys[i], - flags, - node->sortColIdx[i], - InvalidStrategy, - InvalidOid, - node->collations[i], - sortFunction, - (Datum) 0); + sortKey->ssup_cxt = CurrentMemoryContext; + sortKey->ssup_collation = node->collations[i]; + sortKey->ssup_nulls_first = node->nullsFirst[i]; + sortKey->ssup_attno = node->sortColIdx[i]; + + PrepareSortSupportFromOrderingOp(node->sortOperators[i], sortKey); } /* @@ -298,45 +276,22 @@ heap_compare_slots(MergeAppendState *node, SlotNumber slot1, SlotNumber slot2) for (nkey = 0; nkey < node->ms_nkeys; nkey++) { - ScanKey scankey = node->ms_scankeys + nkey; - AttrNumber attno = scankey->sk_attno; + SortSupport sortKey = node->ms_sortkeys + nkey; + AttrNumber attno = sortKey->ssup_attno; Datum datum1, datum2; bool isNull1, isNull2; - int32 compare; + int compare; datum1 = slot_getattr(s1, attno, &isNull1); datum2 = slot_getattr(s2, attno, &isNull2); - if (isNull1) - { - if (isNull2) - continue; /* NULL "=" NULL */ - else if (scankey->sk_flags & SK_BT_NULLS_FIRST) - return -1; /* NULL "<" NOT_NULL */ - else - return 1; /* NULL ">" NOT_NULL */ - } - else if (isNull2) - { - if (scankey->sk_flags & SK_BT_NULLS_FIRST) - return 1; /* NOT_NULL ">" NULL */ - else - return -1; /* NOT_NULL "<" NULL */ - } - else - { - compare = DatumGetInt32(FunctionCall2Coll(&scankey->sk_func, - scankey->sk_collation, - datum1, datum2)); - if (compare != 0) - { - if (scankey->sk_flags & SK_BT_DESC) - compare = -compare; - return compare; - } - } + compare = ApplySortComparator(datum1, isNull1, + datum2, isNull2, + sortKey); + if (compare != 0) + return compare; } return 0; } diff --git a/src/backend/executor/nodeMergejoin.c b/src/backend/executor/nodeMergejoin.c index deaa79ed9fb..634931da425 100644 --- a/src/backend/executor/nodeMergejoin.c +++ b/src/backend/executor/nodeMergejoin.c @@ -95,8 +95,6 @@ #include "access/nbtree.h" #include "executor/execdebug.h" #include "executor/nodeMergejoin.h" -#include "miscadmin.h" -#include "utils/acl.h" #include "utils/lsyscache.h" #include "utils/memutils.h" @@ -135,13 +133,10 @@ typedef struct MergeJoinClauseData bool risnull; /* - * The comparison strategy in use, and the lookup info to let us call the - * btree comparison support function, and the collation to use. + * Everything we need to know to compare the left and right values is + * stored here. */ - bool reverse; /* if true, negate the cmpfn's output */ - bool nulls_first; /* if true, nulls sort low */ - FmgrInfo cmpfinfo; - Oid collation; + SortSupportData ssup; } MergeJoinClauseData; /* Result type for MJEvalOuterValues and MJEvalInnerValues */ @@ -203,8 +198,7 @@ MJExamineQuals(List *mergeclauses, int op_strategy; Oid op_lefttype; Oid op_righttype; - RegProcedure cmpproc; - AclResult aclresult; + Oid sortfunc; if (!IsA(qual, OpExpr)) elog(ERROR, "mergejoin clause is not an OpExpr"); @@ -215,6 +209,17 @@ MJExamineQuals(List *mergeclauses, clause->lexpr = ExecInitExpr((Expr *) linitial(qual->args), parent); clause->rexpr = ExecInitExpr((Expr *) lsecond(qual->args), parent); + /* Set up sort support data */ + clause->ssup.ssup_cxt = CurrentMemoryContext; + clause->ssup.ssup_collation = collation; + if (opstrategy == BTLessStrategyNumber) + clause->ssup.ssup_reverse = false; + else if (opstrategy == BTGreaterStrategyNumber) + clause->ssup.ssup_reverse = true; + else /* planner screwed up */ + elog(ERROR, "unsupported mergejoin strategy %d", opstrategy); + clause->ssup.ssup_nulls_first = nulls_first; + /* Extract the operator's declared left/right datatypes */ get_op_opfamily_properties(qual->opno, opfamily, false, &op_strategy, @@ -224,36 +229,30 @@ MJExamineQuals(List *mergeclauses, elog(ERROR, "cannot merge using non-equality operator %u", qual->opno); - /* And get the matching support procedure (comparison function) */ - cmpproc = get_opfamily_proc(opfamily, - op_lefttype, - op_righttype, - BTORDER_PROC); - if (!RegProcedureIsValid(cmpproc)) /* should not happen */ - elog(ERROR, "missing support function %d(%u,%u) in opfamily %u", - BTORDER_PROC, op_lefttype, op_righttype, opfamily); - - /* Check permission to call cmp function */ - aclresult = pg_proc_aclcheck(cmpproc, GetUserId(), ACL_EXECUTE); - if (aclresult != ACLCHECK_OK) - aclcheck_error(aclresult, ACL_KIND_PROC, - get_func_name(cmpproc)); - - /* Set up the fmgr lookup information */ - fmgr_info(cmpproc, &(clause->cmpfinfo)); - - /* Fill the additional comparison-strategy flags */ - if (opstrategy == BTLessStrategyNumber) - clause->reverse = false; - else if (opstrategy == BTGreaterStrategyNumber) - clause->reverse = true; - else /* planner screwed up */ - elog(ERROR, "unsupported mergejoin strategy %d", opstrategy); - - clause->nulls_first = nulls_first; - - /* ... and the collation too */ - clause->collation = collation; + /* And get the matching support or comparison function */ + sortfunc = get_opfamily_proc(opfamily, + op_lefttype, + op_righttype, + BTSORTSUPPORT_PROC); + if (OidIsValid(sortfunc)) + { + /* The sort support function should provide a comparator */ + OidFunctionCall1(sortfunc, PointerGetDatum(&clause->ssup)); + Assert(clause->ssup.comparator != NULL); + } + else + { + /* opfamily doesn't provide sort support, get comparison func */ + sortfunc = get_opfamily_proc(opfamily, + op_lefttype, + op_righttype, + BTORDER_PROC); + if (!OidIsValid(sortfunc)) /* should not happen */ + elog(ERROR, "missing support function %d(%u,%u) in opfamily %u", + BTORDER_PROC, op_lefttype, op_righttype, opfamily); + /* We'll use a shim to call the old-style btree comparator */ + PrepareSortSupportComparisonShim(sortfunc, &clause->ssup); + } iClause++; } @@ -310,7 +309,8 @@ MJEvalOuterValues(MergeJoinState *mergestate) if (clause->lisnull) { /* match is impossible; can we end the join early? */ - if (i == 0 && !clause->nulls_first && !mergestate->mj_FillOuter) + if (i == 0 && !clause->ssup.ssup_nulls_first && + !mergestate->mj_FillOuter) result = MJEVAL_ENDOFJOIN; else if (result == MJEVAL_MATCHABLE) result = MJEVAL_NONMATCHABLE; @@ -356,7 +356,8 @@ MJEvalInnerValues(MergeJoinState *mergestate, TupleTableSlot *innerslot) if (clause->risnull) { /* match is impossible; can we end the join early? */ - if (i == 0 && !clause->nulls_first && !mergestate->mj_FillInner) + if (i == 0 && !clause->ssup.ssup_nulls_first && + !mergestate->mj_FillInner) result = MJEVAL_ENDOFJOIN; else if (result == MJEVAL_MATCHABLE) result = MJEVAL_NONMATCHABLE; @@ -373,20 +374,19 @@ MJEvalInnerValues(MergeJoinState *mergestate, TupleTableSlot *innerslot) * * Compare the mergejoinable values of the current two input tuples * and return 0 if they are equal (ie, the mergejoin equalities all - * succeed), +1 if outer > inner, -1 if outer < inner. + * succeed), >0 if outer > inner, <0 if outer < inner. * * MJEvalOuterValues and MJEvalInnerValues must already have been called * for the current outer and inner tuples, respectively. */ -static int32 +static int MJCompare(MergeJoinState *mergestate) { - int32 result = 0; + int result = 0; bool nulleqnull = false; ExprContext *econtext = mergestate->js.ps.ps_ExprContext; int i; MemoryContext oldContext; - FunctionCallInfoData fcinfo; /* * Call the comparison functions in short-lived context, in case they leak @@ -399,62 +399,28 @@ MJCompare(MergeJoinState *mergestate) for (i = 0; i < mergestate->mj_NumClauses; i++) { MergeJoinClause clause = &mergestate->mj_Clauses[i]; - Datum fresult; - - /* - * Deal with null inputs. - */ - if (clause->lisnull) - { - if (clause->risnull) - { - nulleqnull = true; /* NULL "=" NULL */ - continue; - } - if (clause->nulls_first) - result = -1; /* NULL "<" NOT_NULL */ - else - result = 1; /* NULL ">" NOT_NULL */ - break; - } - if (clause->risnull) - { - if (clause->nulls_first) - result = 1; /* NOT_NULL ">" NULL */ - else - result = -1; /* NOT_NULL "<" NULL */ - break; - } /* - * OK to call the comparison function. + * Special case for NULL-vs-NULL, else use standard comparison. */ - InitFunctionCallInfoData(fcinfo, &(clause->cmpfinfo), 2, - clause->collation, NULL, NULL); - fcinfo.arg[0] = clause->ldatum; - fcinfo.arg[1] = clause->rdatum; - fcinfo.argnull[0] = false; - fcinfo.argnull[1] = false; - fresult = FunctionCallInvoke(&fcinfo); - if (fcinfo.isnull) + if (clause->lisnull && clause->risnull) { - nulleqnull = true; /* treat like NULL = NULL */ + nulleqnull = true; /* NULL "=" NULL */ continue; } - result = DatumGetInt32(fresult); - if (clause->reverse) - result = -result; + result = ApplySortComparator(clause->ldatum, clause->lisnull, + clause->rdatum, clause->risnull, + &clause->ssup); if (result != 0) break; } /* - * If we had any null comparison results or NULL-vs-NULL inputs, we do not - * want to report that the tuples are equal. Instead, if result is still - * 0, change it to +1. This will result in advancing the inner side of - * the join. + * If we had any NULL-vs-NULL inputs, we do not want to report that the + * tuples are equal. Instead, if result is still 0, change it to +1. + * This will result in advancing the inner side of the join. * * Likewise, if there was a constant-false joinqual, do not report * equality. We have to check this as part of the mergequals, else the @@ -647,7 +613,7 @@ ExecMergeJoin(MergeJoinState *node) List *joinqual; List *otherqual; bool qualResult; - int32 compareResult; + int compareResult; PlanState *innerPlan; TupleTableSlot *innerTupleSlot; PlanState *outerPlan; |