Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
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)