Skip to content

Commit ad429fe

Browse files
committed
Teach nodeMergejoin how to handle DESC and/or NULLS FIRST sort orders.
So far only tested by hacking the planner ...
1 parent 5b88b85 commit ad429fe

File tree

1 file changed

+55
-77
lines changed

1 file changed

+55
-77
lines changed

src/backend/executor/nodeMergejoin.c

Lines changed: 55 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/executor/nodeMergejoin.c,v 1.85 2007/01/10 18:06:02 tgl Exp $
11+
* $PostgreSQL: pgsql/src/backend/executor/nodeMergejoin.c,v 1.86 2007/01/11 17:19:13 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -39,12 +39,13 @@
3939
* therefore it should scan the outer relation first to find a
4040
* matching tuple and so on.
4141
*
42-
* Therefore, when initializing the merge-join node, we look up the
43-
* associated sort operators. We assume the planner has seen to it
44-
* that the inputs are correctly sorted by these operators. Rather
45-
* than directly executing the merge join clauses, we evaluate the
46-
* left and right key expressions separately and then compare the
47-
* columns one at a time (see MJCompare).
42+
* Therefore, rather than directly executing the merge join clauses,
43+
* we evaluate the left and right key expressions separately and then
44+
* compare the columns one at a time (see MJCompare). The planner
45+
* passes us enough information about the sort ordering of the inputs
46+
* to allow us to determine how to make the comparison. We may use the
47+
* appropriate btree comparison function, since Postgres' only notion
48+
* of ordering is specified by btree opfamilies.
4849
*
4950
*
5051
* Consider the above relations and suppose that the executor has
@@ -104,19 +105,8 @@
104105

105106

106107
/*
107-
* Comparison strategies supported by MJCompare
108-
*
109-
* XXX eventually should extend MJCompare to support descending-order sorts.
110-
* There are some tricky issues however about being sure we are on the same
111-
* page as the underlying sort or index as to which end NULLs sort to.
108+
* Runtime data for each mergejoin clause
112109
*/
113-
typedef enum
114-
{
115-
MERGEFUNC_CMP, /* -1 / 0 / 1 three-way comparator */
116-
MERGEFUNC_REV_CMP /* same, reversing the sense of the result */
117-
} MergeFunctionKind;
118-
119-
/* Runtime data for each mergejoin clause */
120110
typedef struct MergeJoinClauseData
121111
{
122112
/* Executable expression trees */
@@ -136,7 +126,8 @@ typedef struct MergeJoinClauseData
136126
* The comparison strategy in use, and the lookup info to let us call the
137127
* btree comparison support function.
138128
*/
139-
MergeFunctionKind cmpstrategy;
129+
bool reverse; /* if true, negate the cmpfn's output */
130+
bool nulls_first; /* if true, nulls sort low */
140131
FmgrInfo cmpfinfo;
141132
} MergeJoinClauseData;
142133

@@ -158,11 +149,11 @@ typedef struct MergeJoinClauseData
158149
* In addition to the expressions themselves, the planner passes the btree
159150
* opfamily OID, btree strategy number (BTLessStrategyNumber or
160151
* BTGreaterStrategyNumber), and nulls-first flag that identify the intended
161-
* merge semantics for each merge key. The mergejoinable operator is an
152+
* sort ordering for each merge key. The mergejoinable operator is an
162153
* equality operator in this opfamily, and the two inputs are guaranteed to be
163154
* ordered in either increasing or decreasing (respectively) order according
164-
* to this opfamily. This allows us to obtain the needed comparison functions
165-
* from the opfamily.
155+
* to this opfamily, with nulls at the indicated end of the range. This
156+
* allows us to obtain the needed comparison function from the opfamily.
166157
*/
167158
static MergeJoinClause
168159
MJExamineQuals(List *mergeclauses,
@@ -193,11 +184,6 @@ MJExamineQuals(List *mergeclauses,
193184
RegProcedure cmpproc;
194185
AclResult aclresult;
195186

196-
/* Later we'll support both ascending and descending sort... */
197-
Assert(opstrategy == BTLessStrategyNumber);
198-
clause->cmpstrategy = MERGEFUNC_CMP;
199-
Assert(!nulls_first);
200-
201187
if (!IsA(qual, OpExpr))
202188
elog(ERROR, "mergejoin clause is not an OpExpr");
203189

@@ -213,15 +199,19 @@ MJExamineQuals(List *mergeclauses,
213199
&op_lefttype,
214200
&op_righttype,
215201
&op_recheck);
216-
Assert(op_strategy == BTEqualStrategyNumber);
217-
Assert(!op_recheck);
202+
if (op_strategy != BTEqualStrategyNumber) /* should not happen */
203+
elog(ERROR, "cannot merge using non-equality operator %u",
204+
qual->opno);
205+
Assert(!op_recheck); /* never true for btree */
218206

219207
/* And get the matching support procedure (comparison function) */
220208
cmpproc = get_opfamily_proc(opfamily,
221209
op_lefttype,
222210
op_righttype,
223211
BTORDER_PROC);
224-
Assert(RegProcedureIsValid(cmpproc));
212+
if (!RegProcedureIsValid(cmpproc)) /* should not happen */
213+
elog(ERROR, "missing support function %d(%u,%u) in opfamily %u",
214+
BTORDER_PROC, op_lefttype, op_righttype, opfamily);
225215

226216
/* Check permission to call cmp function */
227217
aclresult = pg_proc_aclcheck(cmpproc, GetUserId(), ACL_EXECUTE);
@@ -232,6 +222,16 @@ MJExamineQuals(List *mergeclauses,
232222
/* Set up the fmgr lookup information */
233223
fmgr_info(cmpproc, &(clause->cmpfinfo));
234224

225+
/* Fill the additional comparison-strategy flags */
226+
if (opstrategy == BTLessStrategyNumber)
227+
clause->reverse = false;
228+
else if (opstrategy == BTGreaterStrategyNumber)
229+
clause->reverse = true;
230+
else /* planner screwed up */
231+
elog(ERROR, "unsupported mergejoin strategy %d", opstrategy);
232+
233+
clause->nulls_first = nulls_first;
234+
235235
iClause++;
236236
}
237237

@@ -324,10 +324,10 @@ MJEvalInnerValues(MergeJoinState *mergestate, TupleTableSlot *innerslot)
324324
* MJEvalOuterValues and MJEvalInnerValues must already have been called
325325
* for the current outer and inner tuples, respectively.
326326
*/
327-
static int
327+
static int32
328328
MJCompare(MergeJoinState *mergestate)
329329
{
330-
int result = 0;
330+
int32 result = 0;
331331
bool nulleqnull = false;
332332
ExprContext *econtext = mergestate->js.ps.ps_ExprContext;
333333
int i;
@@ -348,26 +348,33 @@ MJCompare(MergeJoinState *mergestate)
348348
Datum fresult;
349349

350350
/*
351-
* Deal with null inputs. We treat NULL as sorting after non-NULL.
351+
* Deal with null inputs.
352352
*/
353353
if (clause->lisnull)
354354
{
355355
if (clause->risnull)
356356
{
357-
nulleqnull = true;
357+
nulleqnull = true; /* NULL "=" NULL */
358358
continue;
359359
}
360-
/* NULL > non-NULL */
361-
result = 1;
360+
if (clause->nulls_first)
361+
result = -1; /* NULL "<" NOT_NULL */
362+
else
363+
result = 1; /* NULL ">" NOT_NULL */
362364
break;
363365
}
364366
if (clause->risnull)
365367
{
366-
/* non-NULL < NULL */
367-
result = -1;
368+
if (clause->nulls_first)
369+
result = 1; /* NOT_NULL ">" NULL */
370+
else
371+
result = -1; /* NOT_NULL "<" NULL */
368372
break;
369373
}
370374

375+
/*
376+
* OK to call the comparison function.
377+
*/
371378
InitFunctionCallInfoData(fcinfo, &(clause->cmpfinfo), 2,
372379
NULL, NULL);
373380
fcinfo.arg[0] = clause->ldatum;
@@ -377,45 +384,16 @@ MJCompare(MergeJoinState *mergestate)
377384
fresult = FunctionCallInvoke(&fcinfo);
378385
if (fcinfo.isnull)
379386
{
380-
nulleqnull = true;
381-
continue;
382-
}
383-
if (DatumGetInt32(fresult) == 0)
384-
{
385-
/* equal */
387+
nulleqnull = true; /* treat like NULL = NULL */
386388
continue;
387389
}
388-
if (clause->cmpstrategy == MERGEFUNC_CMP)
389-
{
390-
if (DatumGetInt32(fresult) < 0)
391-
{
392-
/* less than */
393-
result = -1;
394-
break;
395-
}
396-
else
397-
{
398-
/* greater than */
399-
result = 1;
400-
break;
401-
}
402-
}
403-
else
404-
{
405-
/* reverse the sort order */
406-
if (DatumGetInt32(fresult) > 0)
407-
{
408-
/* less than */
409-
result = -1;
410-
break;
411-
}
412-
else
413-
{
414-
/* greater than */
415-
result = 1;
416-
break;
417-
}
418-
}
390+
result = DatumGetInt32(fresult);
391+
392+
if (clause->reverse)
393+
result = -result;
394+
395+
if (result != 0)
396+
break;
419397
}
420398

421399
/*
@@ -581,7 +559,7 @@ ExecMergeJoin(MergeJoinState *node)
581559
List *joinqual;
582560
List *otherqual;
583561
bool qualResult;
584-
int compareResult;
562+
int32 compareResult;
585563
PlanState *innerPlan;
586564
TupleTableSlot *innerTupleSlot;
587565
PlanState *outerPlan;

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy