Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitdc77be0

Browse files
committed
Fix executor to work correctly with mergejoins where left and
right sides have different data types.
1 parent98f7394 commitdc77be0

File tree

2 files changed

+80
-123
lines changed

2 files changed

+80
-123
lines changed

‎src/backend/executor/nodeMergejoin.c

Lines changed: 75 additions & 118 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
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
*/
@@ -67,6 +67,7 @@
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
*/
105105
staticList*
106-
MJFormOSortopI(List*qualList,OidsortOp)
106+
MJFormSkipQual(List*qualList,char*replaceopname)
107107
{
108108
List*qualCopy;
109109
List*qualcdr;
110110
Expr*qual;
111111
Oper*op;
112+
HeapTupleoptup;
113+
Form_pg_operatoropform;
114+
Oidoprleft,
115+
oprright;
112116

113117
/* ----------------
114118
*qualList is a list: ((op .. ..) ...)
@@ -132,73 +136,50 @@ MJFormOSortopI(List *qualList, Oid sortOp)
132136
*/
133137
op= (Oper*)qual->oper;
134138
if (!IsA(op,Oper))
135-
{
136-
elog(DEBUG,"MJFormOSortopI: op not an Oper!");
137-
returnNIL;
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-
returnqualCopy;
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-
staticList*
170-
MJFormISortopO(List*qualList,OidsortOp)
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-
returnISortopO;
182+
returnqualCopy;
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
*/
220202
staticbool
@@ -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

453439
if (ScanDirectionIsForward(direction))
454440
{
455-
outerSkipQual=mergestate->mj_OSortopI;
456-
innerSkipQual=mergestate->mj_ISortopO;
441+
outerSkipQual=mergestate->mj_OuterSkipQual;
442+
innerSkipQual=mergestate->mj_InnerSkipQual;
457443
}
458444
else
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
{
11311117
MergeJoinState*mergestate;
11321118
List*joinclauses;
1133-
RegProcedurerightsortop;
1134-
RegProcedureleftsortop;
1135-
RegProceduresortop;
11361119
TupleTableSlot*mjSlot;
11371120

1138-
List*OSortopI;
1139-
List*ISortopO;
1140-
11411121
MJ1_printf("ExecInitMergeJoin: %s\n",
11421122
"initializing node");
11431123

@@ -1153,14 +1133,14 @@ ExecInitMergeJoin(MergeJoin *node, EState *estate, Plan *parent)
11531133
* ----------------
11541134
*/
11551135
mergestate=makeNode(MergeJoinState);
1156-
mergestate->mj_OSortopI=NIL;
1157-
mergestate->mj_ISortopO=NIL;
1136+
mergestate->mj_OuterSkipQual=NIL;
1137+
mergestate->mj_InnerSkipQual=NIL;
11581138
mergestate->mj_JoinState=0;
11591139
mergestate->mj_MarkedTupleSlot=NULL;
11601140
node->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)
11851165
mergestate->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
*/
11951171
joinclauses=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);
12221179
MJ_printf("\n");
12231180

12241181
/* ----------------

‎src/include/nodes/execnodes.h

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
*
77
* Copyright (c) 1994, Regents of the University of California
88
*
9-
* $Id: execnodes.h,v 1.25 1999/02/23 07:55:23 thomas Exp $
9+
* $Id: execnodes.h,v 1.26 1999/02/28 00:36:04 tgl Exp $
1010
*
1111
*-------------------------------------------------------------------------
1212
*/
@@ -463,8 +463,8 @@ typedef struct NestLoopState
463463
/* ----------------
464464
* MergeJoinState information
465465
*
466-
*OSortopI outerKey1sortOp innerKey1 ...
467-
*ISortopOinnerkey1 sortOp outerkey1 ...
466+
*OuterSkipQual outerKey1< innerKey1 ...
467+
*InnerSkipQualouterKey1 > innerKey1 ...
468468
*JoinState current "state" of join. see executor.h
469469
*MarkedTupleSlot pointer to slot in tuple table for marked tuple
470470
*
@@ -483,8 +483,8 @@ typedef struct NestLoopState
483483
typedefstructMergeJoinState
484484
{
485485
JoinStatejstate;/* its first field is NodeTag */
486-
List*mj_OSortopI;
487-
List*mj_ISortopO;
486+
List*mj_OuterSkipQual;
487+
List*mj_InnerSkipQual;
488488
intmj_JoinState;
489489
TupleTableSlot*mj_MarkedTupleSlot;
490490
}MergeJoinState;

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp