8
8
*
9
9
*
10
10
* 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 $
12
12
*
13
13
*-------------------------------------------------------------------------
14
14
*/
39
39
* therefore it should scan the outer relation first to find a
40
40
* matching tuple and so on.
41
41
*
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.
48
49
*
49
50
*
50
51
* Consider the above relations and suppose that the executor has
104
105
105
106
106
107
/*
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
112
109
*/
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 */
120
110
typedef struct MergeJoinClauseData
121
111
{
122
112
/* Executable expression trees */
@@ -136,7 +126,8 @@ typedef struct MergeJoinClauseData
136
126
* The comparison strategy in use, and the lookup info to let us call the
137
127
* btree comparison support function.
138
128
*/
139
- MergeFunctionKind cmpstrategy ;
129
+ bool reverse ; /* if true, negate the cmpfn's output */
130
+ bool nulls_first ; /* if true, nulls sort low */
140
131
FmgrInfo cmpfinfo ;
141
132
} MergeJoinClauseData ;
142
133
@@ -158,11 +149,11 @@ typedef struct MergeJoinClauseData
158
149
* In addition to the expressions themselves, the planner passes the btree
159
150
* opfamily OID, btree strategy number (BTLessStrategyNumber or
160
151
* 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
162
153
* equality operator in this opfamily, and the two inputs are guaranteed to be
163
154
* 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.
166
157
*/
167
158
static MergeJoinClause
168
159
MJExamineQuals (List * mergeclauses ,
@@ -193,11 +184,6 @@ MJExamineQuals(List *mergeclauses,
193
184
RegProcedure cmpproc ;
194
185
AclResult aclresult ;
195
186
196
- /* Later we'll support both ascending and descending sort... */
197
- Assert (opstrategy == BTLessStrategyNumber );
198
- clause -> cmpstrategy = MERGEFUNC_CMP ;
199
- Assert (!nulls_first );
200
-
201
187
if (!IsA (qual , OpExpr ))
202
188
elog (ERROR , "mergejoin clause is not an OpExpr" );
203
189
@@ -213,15 +199,19 @@ MJExamineQuals(List *mergeclauses,
213
199
& op_lefttype ,
214
200
& op_righttype ,
215
201
& 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 */
218
206
219
207
/* And get the matching support procedure (comparison function) */
220
208
cmpproc = get_opfamily_proc (opfamily ,
221
209
op_lefttype ,
222
210
op_righttype ,
223
211
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 );
225
215
226
216
/* Check permission to call cmp function */
227
217
aclresult = pg_proc_aclcheck (cmpproc , GetUserId (), ACL_EXECUTE );
@@ -232,6 +222,16 @@ MJExamineQuals(List *mergeclauses,
232
222
/* Set up the fmgr lookup information */
233
223
fmgr_info (cmpproc , & (clause -> cmpfinfo ));
234
224
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
+
235
235
iClause ++ ;
236
236
}
237
237
@@ -324,10 +324,10 @@ MJEvalInnerValues(MergeJoinState *mergestate, TupleTableSlot *innerslot)
324
324
* MJEvalOuterValues and MJEvalInnerValues must already have been called
325
325
* for the current outer and inner tuples, respectively.
326
326
*/
327
- static int
327
+ static int32
328
328
MJCompare (MergeJoinState * mergestate )
329
329
{
330
- int result = 0 ;
330
+ int32 result = 0 ;
331
331
bool nulleqnull = false;
332
332
ExprContext * econtext = mergestate -> js .ps .ps_ExprContext ;
333
333
int i ;
@@ -348,26 +348,33 @@ MJCompare(MergeJoinState *mergestate)
348
348
Datum fresult ;
349
349
350
350
/*
351
- * Deal with null inputs. We treat NULL as sorting after non-NULL.
351
+ * Deal with null inputs.
352
352
*/
353
353
if (clause -> lisnull )
354
354
{
355
355
if (clause -> risnull )
356
356
{
357
- nulleqnull = true;
357
+ nulleqnull = true; /* NULL "=" NULL */
358
358
continue ;
359
359
}
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 */
362
364
break ;
363
365
}
364
366
if (clause -> risnull )
365
367
{
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 */
368
372
break ;
369
373
}
370
374
375
+ /*
376
+ * OK to call the comparison function.
377
+ */
371
378
InitFunctionCallInfoData (fcinfo , & (clause -> cmpfinfo ), 2 ,
372
379
NULL , NULL );
373
380
fcinfo .arg [0 ] = clause -> ldatum ;
@@ -377,45 +384,16 @@ MJCompare(MergeJoinState *mergestate)
377
384
fresult = FunctionCallInvoke (& fcinfo );
378
385
if (fcinfo .isnull )
379
386
{
380
- nulleqnull = true;
381
- continue ;
382
- }
383
- if (DatumGetInt32 (fresult ) == 0 )
384
- {
385
- /* equal */
387
+ nulleqnull = true; /* treat like NULL = NULL */
386
388
continue ;
387
389
}
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 ;
419
397
}
420
398
421
399
/*
@@ -581,7 +559,7 @@ ExecMergeJoin(MergeJoinState *node)
581
559
List * joinqual ;
582
560
List * otherqual ;
583
561
bool qualResult ;
584
- int compareResult ;
562
+ int32 compareResult ;
585
563
PlanState * innerPlan ;
586
564
TupleTableSlot * innerTupleSlot ;
587
565
PlanState * outerPlan ;
0 commit comments