7
7
*
8
8
*
9
9
* IDENTIFICATION
10
- * $Header: /cvsroot/pgsql/src/backend/executor/nodeMergejoin.c,v 1.24 1999/02/24 10:20:07 momjian Exp $
10
+ * $Header: /cvsroot/pgsql/src/backend/executor/nodeMergejoin.c,v 1.25 1999/02/28 00:36:05 tgl Exp $
11
11
*
12
12
*-------------------------------------------------------------------------
13
13
*/
67
67
#include "postgres.h"
68
68
69
69
#include "access/heapam.h"
70
+ #include "catalog/pg_operator.h"
70
71
#include "executor/executor.h"
71
72
#include "executor/execdefs.h"
72
73
#include "executor/nodeMergejoin.h"
@@ -87,28 +88,31 @@ static bool MergeCompare(List *eqQual, List *compareQual, ExprContext *econtext)
87
88
88
89
89
90
/* ----------------------------------------------------------------
90
- * MJFormOSortopI
91
+ * MJFormSkipQual
91
92
*
92
93
* This takes the mergeclause which is a qualification of the
93
94
* form ((= expr expr) (= expr expr) ...) and forms a new
94
95
* qualification like ((> expr expr) (> expr expr) ...) which
95
96
* is used by ExecMergeJoin() in order to determine if we should
96
- * skip tuples.
97
- *
98
- * old comments
99
- * The 'qual' must be of the form:
100
- * {(= outerkey1 innerkey1)(= outerkey2 innerkey2) ...}
101
- * The "sortOp outerkey innerkey" is formed by substituting the "="
102
- * by "sortOp".
97
+ * skip tuples. The replacement operators are named either ">"
98
+ * or "<" according to the replaceopname parameter, and have the
99
+ * same operand data types as the "=" operators they replace.
100
+ * (We expect there to be such operators because the "=" operators
101
+ * were marked mergejoinable; however, there might be a different
102
+ * one needed in each qual clause.)
103
103
* ----------------------------------------------------------------
104
104
*/
105
105
static List *
106
- MJFormOSortopI (List * qualList , Oid sortOp )
106
+ MJFormSkipQual (List * qualList , char * replaceopname )
107
107
{
108
108
List * qualCopy ;
109
109
List * qualcdr ;
110
110
Expr * qual ;
111
111
Oper * op ;
112
+ HeapTuple optup ;
113
+ Form_pg_operator opform ;
114
+ Oid oprleft ,
115
+ oprright ;
112
116
113
117
/* ----------------
114
118
* qualList is a list: ((op .. ..) ...)
@@ -132,73 +136,50 @@ MJFormOSortopI(List *qualList, Oid sortOp)
132
136
*/
133
137
op = (Oper * ) qual -> oper ;
134
138
if (!IsA (op , Oper ))
135
- {
136
- elog (DEBUG , "MJFormOSortopI: op not an Oper!" );
137
- return NIL ;
138
- }
139
+ elog (ERROR , "MJFormSkipQual: op not an Oper!" );
139
140
140
141
/* ----------------
141
- * change it's opid and since Op nodes now carry around a
142
- * cached pointer to the associated op function, we have
143
- * to make sure we invalidate this. Otherwise you get bizarre
144
- * behavior when someone runs a mergejoin with _exec_repeat_ > 1
145
- * -cim 4/23/91
142
+ * Get the declared left and right operand types of the operator.
143
+ * Note we do *not* use the actual operand types, since those might
144
+ * be different in scenarios with binary-compatible data types.
145
+ * There should be "<" and ">" operators matching a mergejoinable
146
+ * "=" operator's declared operand types, but we might not find them
147
+ * if we search with the actual operand types.
146
148
* ----------------
147
149
*/
148
- op -> opid = sortOp ;
149
- op -> op_fcache = NULL ;
150
- }
151
-
152
- return qualCopy ;
153
- }
154
-
155
- /* ----------------------------------------------------------------
156
- * MJFormISortopO
157
- *
158
- * This does the same thing as MJFormOSortopI() except that
159
- * it also reverses the expressions in the qualifications.
160
- * For example: ((= expr1 expr2)) produces ((> expr2 expr1))
161
- *
162
- * old comments
163
- * The 'qual' must be of the form:
164
- * {(= outerkey1 innerkey1) (= outerkey2 innerkey2) ...}
165
- * The 'sortOp innerkey1 outerkey" is formed by substituting the "="
166
- * by "sortOp" and reversing the positions of the keys.
167
- * ----------------------------------------------------------------
168
- */
169
- static List *
170
- MJFormISortopO (List * qualList , Oid sortOp )
171
- {
172
- List * ISortopO ;
173
- List * qualcdr ;
174
-
175
- /* ----------------
176
- * first generate OSortopI, a list of the form
177
- * ((op outer inner) (op outer inner) ... )
178
- * ----------------
179
- */
180
- ISortopO = MJFormOSortopI (qualList , sortOp );
181
-
182
- /* ----------------
183
- * now swap the cadr and caddr of each qual to form ISortopO,
184
- * ((op inner outer) (op inner outer) ... )
185
- * ----------------
186
- */
187
- foreach (qualcdr , ISortopO )
188
- {
189
- Expr * qual ;
190
- List * inner ;
191
- List * outer ;
150
+ optup = get_operator_tuple (op -> opno );
151
+ if (!HeapTupleIsValid (optup )) /* shouldn't happen */
152
+ elog (ERROR , "MJFormSkipQual: operator %d not found" , op -> opno );
153
+ opform = (Form_pg_operator ) GETSTRUCT (optup );
154
+ oprleft = opform -> oprleft ;
155
+ oprright = opform -> oprright ;
192
156
193
- qual = lfirst (qualcdr );
157
+ /* ----------------
158
+ * Now look up the matching "<" or ">" operator. If there isn't one,
159
+ * whoever marked the "=" operator mergejoinable was a loser.
160
+ * ----------------
161
+ */
162
+ optup = SearchSysCacheTuple (OPRNAME ,
163
+ PointerGetDatum (replaceopname ),
164
+ ObjectIdGetDatum (oprleft ),
165
+ ObjectIdGetDatum (oprright ),
166
+ CharGetDatum ('b' ));
167
+ if (!HeapTupleIsValid (optup ))
168
+ elog (ERROR ,
169
+ "MJFormSkipQual: mergejoin operator %d has no matching %s op" ,
170
+ op -> opno , replaceopname );
171
+ opform = (Form_pg_operator ) GETSTRUCT (optup );
194
172
195
- inner = lfirst (qual -> args );
196
- outer = lfirst (lnext (qual -> args ));
197
- lfirst (qual -> args ) = outer ;
198
- lfirst (lnext (qual -> args )) = inner ;
173
+ /* ----------------
174
+ * And replace the data in the copied operator node.
175
+ * ----------------
176
+ */
177
+ op -> opno = optup -> t_data -> t_oid ;
178
+ op -> opid = opform -> oprcode ;
179
+ op -> op_fcache = NULL ;
199
180
}
200
181
201
- return ISortopO ;
182
+ return qualCopy ;
202
183
}
203
184
204
185
/* ----------------------------------------------------------------
@@ -215,6 +196,7 @@ MJFormISortopO(List *qualList, Oid sortOp)
215
196
* the first keys being most significant. Therefore, the clauses
216
197
* are evaluated in order and the 'compareQual' is satisfied
217
198
* if (key1i > key2i) is true and (key1j = key2j) for 0 < j < i.
199
+ * We use the original mergeclause items to detect equality.
218
200
* ----------------------------------------------------------------
219
201
*/
220
202
static bool
@@ -386,12 +368,16 @@ ExecMergeTupleDump(ExprContext *econtext, MergeJoinState *mergestate)
386
368
*
387
369
* Therefore, when initializing the merge-join node, the executor
388
370
* creates the "greater/smaller" clause by substituting the "="
389
- * operator in the join clauses with the sort operator used to
390
- * sort the outer and inner relation forming (outerKey sortOp innerKey).
391
- * The sort operator is "<" if the relations are in ascending order
392
- * otherwise, it is ">" if the relations are in descending order.
393
- * The opposite "smaller/greater" clause is formed by reversing the
394
- * outer and inner keys forming (innerKey sortOp outerKey).
371
+ * operator in the join clauses with the corresponding ">" operator.
372
+ * The opposite "smaller/greater" clause is formed by substituting "<".
373
+ *
374
+ * Note: prior to v6.5, the relational clauses were formed using the
375
+ * sort op used to sort the inner relation, which of course would fail
376
+ * if the outer and inner keys were of different data types.
377
+ * In the current code, we instead assume that operators named "<" and ">"
378
+ * will do the right thing. This should be true since the mergejoin "="
379
+ * operator's pg_operator entry will have told the planner to sort by
380
+ * "<" for each of the left and right sides.
395
381
*
396
382
* (2) repositioning inner "cursor"
397
383
*
@@ -452,13 +438,13 @@ ExecMergeJoin(MergeJoin *node)
452
438
453
439
if (ScanDirectionIsForward (direction ))
454
440
{
455
- outerSkipQual = mergestate -> mj_OSortopI ;
456
- innerSkipQual = mergestate -> mj_ISortopO ;
441
+ outerSkipQual = mergestate -> mj_OuterSkipQual ;
442
+ innerSkipQual = mergestate -> mj_InnerSkipQual ;
457
443
}
458
444
else
459
445
{
460
- outerSkipQual = mergestate -> mj_ISortopO ;
461
- innerSkipQual = mergestate -> mj_OSortopI ;
446
+ outerSkipQual = mergestate -> mj_InnerSkipQual ;
447
+ innerSkipQual = mergestate -> mj_OuterSkipQual ;
462
448
}
463
449
464
450
/* ----------------
@@ -1130,14 +1116,8 @@ ExecInitMergeJoin(MergeJoin *node, EState *estate, Plan *parent)
1130
1116
{
1131
1117
MergeJoinState * mergestate ;
1132
1118
List * joinclauses ;
1133
- RegProcedure rightsortop ;
1134
- RegProcedure leftsortop ;
1135
- RegProcedure sortop ;
1136
1119
TupleTableSlot * mjSlot ;
1137
1120
1138
- List * OSortopI ;
1139
- List * ISortopO ;
1140
-
1141
1121
MJ1_printf ("ExecInitMergeJoin: %s\n" ,
1142
1122
"initializing node" );
1143
1123
@@ -1153,14 +1133,14 @@ ExecInitMergeJoin(MergeJoin *node, EState *estate, Plan *parent)
1153
1133
* ----------------
1154
1134
*/
1155
1135
mergestate = makeNode (MergeJoinState );
1156
- mergestate -> mj_OSortopI = NIL ;
1157
- mergestate -> mj_ISortopO = NIL ;
1136
+ mergestate -> mj_OuterSkipQual = NIL ;
1137
+ mergestate -> mj_InnerSkipQual = NIL ;
1158
1138
mergestate -> mj_JoinState = 0 ;
1159
1139
mergestate -> mj_MarkedTupleSlot = NULL ;
1160
1140
node -> mergestate = mergestate ;
1161
1141
1162
1142
/* ----------------
1163
- * Miscellanious initialization
1143
+ * Miscellaneous initialization
1164
1144
*
1165
1145
* + assign node's base_id
1166
1146
* + assign debugging hooks and
@@ -1185,40 +1165,17 @@ ExecInitMergeJoin(MergeJoin *node, EState *estate, Plan *parent)
1185
1165
mergestate -> mj_MarkedTupleSlot = mjSlot ;
1186
1166
1187
1167
/* ----------------
1188
- * get merge sort operators.
1189
- *
1190
- * XXX for now we assume all quals in the joinclauses were
1191
- * sorted with the same operator in both the inner and
1192
- * outer relations. -cim 11/2/89
1168
+ * form merge skip qualifications
1193
1169
* ----------------
1194
1170
*/
1195
1171
joinclauses = node -> mergeclauses ;
1172
+ mergestate -> mj_OuterSkipQual = MJFormSkipQual (joinclauses , "<" );
1173
+ mergestate -> mj_InnerSkipQual = MJFormSkipQual (joinclauses , ">" );
1196
1174
1197
- rightsortop = get_opcode (node -> mergerightorder [0 ]);
1198
- leftsortop = get_opcode (node -> mergeleftorder [0 ]);
1199
-
1200
- if (leftsortop != rightsortop )
1201
- elog (NOTICE , "ExecInitMergeJoin: %s" ,
1202
- "left and right sortop's are unequal!" );
1203
-
1204
- sortop = rightsortop ;
1205
-
1206
- /* ----------------
1207
- * form merge skip qualifications
1208
- *
1209
- * XXX MJform routines need to be extended
1210
- * to take a list of sortops.. -cim 11/2/89
1211
- * ----------------
1212
- */
1213
- OSortopI = MJFormOSortopI (joinclauses , sortop );
1214
- ISortopO = MJFormISortopO (joinclauses , sortop );
1215
- mergestate -> mj_OSortopI = OSortopI ;
1216
- mergestate -> mj_ISortopO = ISortopO ;
1217
-
1218
- MJ_printf ("\nExecInitMergeJoin: OSortopI is " );
1219
- MJ_nodeDisplay (OSortopI );
1220
- MJ_printf ("\nExecInitMergeJoin: ISortopO is " );
1221
- MJ_nodeDisplay (ISortopO );
1175
+ MJ_printf ("\nExecInitMergeJoin: OuterSkipQual is " );
1176
+ MJ_nodeDisplay (mergestate -> mj_OuterSkipQual );
1177
+ MJ_printf ("\nExecInitMergeJoin: InnerSkipQual is " );
1178
+ MJ_nodeDisplay (mergestate -> mj_InnerSkipQual );
1222
1179
MJ_printf ("\n" );
1223
1180
1224
1181
/* ----------------
0 commit comments