77 *
88 *
99 * 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 $
1111 *
1212 *-------------------------------------------------------------------------
1313 */
6767#include "postgres.h"
6868
6969#include "access/heapam.h"
70+ #include "catalog/pg_operator.h"
7071#include "executor/executor.h"
7172#include "executor/execdefs.h"
7273#include "executor/nodeMergejoin.h"
@@ -87,28 +88,31 @@ static bool MergeCompare(List *eqQual, List *compareQual, ExprContext *econtext)
8788
8889
8990/* ----------------------------------------------------------------
90- *MJFormOSortopI
91+ *MJFormSkipQual
9192 *
9293 *This takes the mergeclause which is a qualification of the
9394 *form ((= expr expr) (= expr expr) ...) and forms a new
9495 *qualification like ((> expr expr) (> expr expr) ...) which
9596 *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.)
103103 * ----------------------------------------------------------------
104104 */
105105static List *
106- MJFormOSortopI (List * qualList ,Oid sortOp )
106+ MJFormSkipQual (List * qualList ,char * replaceopname )
107107{
108108List * qualCopy ;
109109List * qualcdr ;
110110Expr * qual ;
111111Oper * op ;
112+ HeapTuple optup ;
113+ Form_pg_operator opform ;
114+ Oid oprleft ,
115+ oprright ;
112116
113117/* ----------------
114118 *qualList is a list: ((op .. ..) ...)
@@ -132,73 +136,50 @@ MJFormOSortopI(List *qualList, Oid sortOp)
132136 */
133137op = (Oper * )qual -> oper ;
134138if (!IsA (op ,Oper ))
135- {
136- elog (DEBUG ,"MJFormOSortopI: op not an Oper!" );
137- return NIL ;
138- }
139+ elog (ERROR ,"MJFormSkipQual: op not an Oper!" );
139140
140141/* ----------------
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.
146148 * ----------------
147149 */
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 ;
192156
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 );
194172
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 ;
199180}
200181
201- return ISortopO ;
182+ return qualCopy ;
202183}
203184
204185/* ----------------------------------------------------------------
@@ -215,6 +196,7 @@ MJFormISortopO(List *qualList, Oid sortOp)
215196 *the first keys being most significant. Therefore, the clauses
216197 *are evaluated in order and the 'compareQual' is satisfied
217198 *if (key1i > key2i) is true and (key1j = key2j) for 0 < j < i.
199+ *We use the original mergeclause items to detect equality.
218200 * ----------------------------------------------------------------
219201 */
220202static bool
@@ -386,12 +368,16 @@ ExecMergeTupleDump(ExprContext *econtext, MergeJoinState *mergestate)
386368 *
387369 *Therefore, when initializing the merge-join node, the executor
388370 *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.
395381 *
396382 *(2) repositioning inner "cursor"
397383 *
@@ -452,13 +438,13 @@ ExecMergeJoin(MergeJoin *node)
452438
453439if (ScanDirectionIsForward (direction ))
454440{
455- outerSkipQual = mergestate -> mj_OSortopI ;
456- innerSkipQual = mergestate -> mj_ISortopO ;
441+ outerSkipQual = mergestate -> mj_OuterSkipQual ;
442+ innerSkipQual = mergestate -> mj_InnerSkipQual ;
457443}
458444else
459445{
460- outerSkipQual = mergestate -> mj_ISortopO ;
461- innerSkipQual = mergestate -> mj_OSortopI ;
446+ outerSkipQual = mergestate -> mj_InnerSkipQual ;
447+ innerSkipQual = mergestate -> mj_OuterSkipQual ;
462448}
463449
464450/* ----------------
@@ -1130,14 +1116,8 @@ ExecInitMergeJoin(MergeJoin *node, EState *estate, Plan *parent)
11301116{
11311117MergeJoinState * mergestate ;
11321118List * joinclauses ;
1133- RegProcedure rightsortop ;
1134- RegProcedure leftsortop ;
1135- RegProcedure sortop ;
11361119TupleTableSlot * mjSlot ;
11371120
1138- List * OSortopI ;
1139- List * ISortopO ;
1140-
11411121MJ1_printf ("ExecInitMergeJoin: %s\n" ,
11421122"initializing node" );
11431123
@@ -1153,14 +1133,14 @@ ExecInitMergeJoin(MergeJoin *node, EState *estate, Plan *parent)
11531133 * ----------------
11541134 */
11551135mergestate = makeNode (MergeJoinState );
1156- mergestate -> mj_OSortopI = NIL ;
1157- mergestate -> mj_ISortopO = NIL ;
1136+ mergestate -> mj_OuterSkipQual = NIL ;
1137+ mergestate -> mj_InnerSkipQual = NIL ;
11581138mergestate -> mj_JoinState = 0 ;
11591139mergestate -> mj_MarkedTupleSlot = NULL ;
11601140node -> mergestate = mergestate ;
11611141
11621142/* ----------------
1163- *Miscellanious initialization
1143+ *Miscellaneous initialization
11641144 *
11651145 * +assign node's base_id
11661146 * +assign debugging hooks and
@@ -1185,40 +1165,17 @@ ExecInitMergeJoin(MergeJoin *node, EState *estate, Plan *parent)
11851165mergestate -> mj_MarkedTupleSlot = mjSlot ;
11861166
11871167/* ----------------
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
11931169 * ----------------
11941170 */
11951171joinclauses = node -> mergeclauses ;
1172+ mergestate -> mj_OuterSkipQual = MJFormSkipQual (joinclauses ,"<" );
1173+ mergestate -> mj_InnerSkipQual = MJFormSkipQual (joinclauses ,">" );
11961174
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 );
12221179MJ_printf ("\n" );
12231180
12241181/* ----------------