18
18
#include "executor/nodeSubplan.h"
19
19
#include "tcop/pquery.h"
20
20
21
+ /* should be exported by execMain.c */
22
+ extern void ExecCheckPerms (CmdType op , int resRel , List * rtable , Query * q );
23
+
21
24
/* ----------------------------------------------------------------
22
25
* ExecSubPlan(node)
23
26
*
24
27
* ----------------------------------------------------------------
25
28
*/
26
29
Datum
27
- ExecSubPlan (SubPlan * node , List * pvar , ExprContext * econtext )
30
+ ExecSubPlan (SubPlan * node , List * pvar , ExprContext * econtext , bool * isNull )
28
31
{
29
32
Plan * plan = node -> plan ;
30
33
SubLink * sublink = node -> sublink ;
31
34
SubLinkType subLinkType = sublink -> subLinkType ;
35
+ bool useor = sublink -> useor ;
32
36
TupleTableSlot * slot ;
33
- List * lst ;
34
- Datum result = (Datum ) false;
37
+ Datum result ;
35
38
bool found = false; /* TRUE if got at least one subplan tuple */
39
+ List * lst ;
36
40
37
- if (node -> setParam != NULL )
41
+ if (node -> setParam != NIL )
38
42
elog (ERROR , "ExecSubPlan: can't set parent params from subquery" );
39
43
40
44
/*
41
45
* Set Params of this plan from parent plan correlation Vars
42
46
*/
43
- if (node -> parParam != NULL )
47
+ if (node -> parParam != NIL )
44
48
{
45
49
foreach (lst , node -> parParam )
46
50
{
47
51
ParamExecData * prm = & (econtext -> ecxt_param_exec_vals [lfirsti (lst )]);
48
52
53
+ Assert (pvar != NIL );
49
54
prm -> value = ExecEvalExpr ((Node * ) lfirst (pvar ),
50
55
econtext ,
51
56
& (prm -> isnull ), NULL );
52
57
pvar = lnext (pvar );
53
58
}
54
59
plan -> chgParam = nconc (plan -> chgParam , listCopy (node -> parParam ));
55
60
}
61
+ Assert (pvar == NIL );
56
62
57
63
ExecReScan (plan , (ExprContext * ) NULL , plan );
58
64
59
65
/*
60
- * For all sublink types except EXPR_SUBLINK, the result type is
61
- * boolean, and we have a fairly clear idea of how to combine multiple
62
- * subitems and deal with NULL values or an empty subplan result.
66
+ * For all sublink types except EXPR_SUBLINK, the result is boolean
67
+ * as are the results of the combining operators. We combine results
68
+ * within a tuple (if there are multiple columns) using OR semantics
69
+ * if "useor" is true, AND semantics if not. We then combine results
70
+ * across tuples (if the subplan produces more than one) using OR
71
+ * semantics for ANY_SUBLINK or AND semantics for ALL_SUBLINK. NULL
72
+ * results from the combining operators are handled according to the
73
+ * usual SQL semantics for OR and AND. The result for no input
74
+ * tuples is FALSE for ANY_SUBLINK, TRUE for ALL_SUBLINK.
63
75
*
64
- * For EXPR_SUBLINK, the result type is whatever the combining operator
65
- * returns. We have no way to deal with more than one column in the
66
- * subplan result --- hopefully the parser forbids that. More
67
- * seriously, it's unclear what to do with NULL values or an empty
68
- * subplan result. For now, we error out, but should something else
69
- * happen?
76
+ * For EXPR_SUBLINK we require the subplan to produce no more than one
77
+ * tuple, else an error is raised. If zero tuples are produced, we
78
+ * return NULL. (XXX it would probably be more correct to evaluate
79
+ * the combining operator with a NULL input?) Assuming we get a tuple:
80
+ * if there is only one column then we just return its result as-is, NULL
81
+ * or otherwise. If there is more than one column we combine the results
82
+ * per "useor" --- this only makes sense if the combining operators yield
83
+ * boolean, and we assume the parser has checked that.
70
84
*/
85
+ result = (Datum ) (subLinkType == ALL_SUBLINK ? true : false);
86
+ * isNull = false;
71
87
72
88
for (slot = ExecProcNode (plan , plan );
73
89
!TupIsNull (slot );
74
90
slot = ExecProcNode (plan , plan ))
75
91
{
76
92
HeapTuple tup = slot -> val ;
77
93
TupleDesc tdesc = slot -> ttc_tupleDescriptor ;
78
- int i = 1 ;
79
-
80
- if (subLinkType == EXPR_SUBLINK && found )
81
- {
82
- elog (ERROR , "ExecSubPlan: more than one tuple returned by expression subselect" );
83
- return (Datum ) false;
84
- }
94
+ Datum rowresult = (Datum ) (useor ? false : true);
95
+ bool rownull = false;
96
+ int col = 1 ;
85
97
86
98
if (subLinkType == EXISTS_SUBLINK )
87
99
return (Datum ) true;
88
100
101
+ /* cannot allow multiple input tuples for EXPR sublink */
102
+ if (subLinkType == EXPR_SUBLINK && found )
103
+ elog (ERROR , "ExecSubPlan: more than one tuple returned by expression subselect" );
104
+
89
105
found = true;
90
106
107
+ /* iterate over combining operators for columns of tuple */
91
108
foreach (lst , sublink -> oper )
92
109
{
93
110
Expr * expr = (Expr * ) lfirst (lst );
94
111
Const * con = lsecond (expr -> args );
95
- bool isnull ;
112
+ Datum expresult ;
113
+ bool expnull ;
96
114
97
115
/*
98
116
* The righthand side of the expression should be either a Const
@@ -107,41 +125,90 @@ ExecSubPlan(SubPlan *node, List *pvar, ExprContext *econtext)
107
125
con = lfirst (((Expr * ) con )-> args );
108
126
Assert (IsA (con , Const ));
109
127
}
110
- con -> constvalue = heap_getattr (tup , i , tdesc , & (con -> constisnull ));
128
+ con -> constvalue = heap_getattr (tup , col , tdesc ,
129
+ & (con -> constisnull ));
111
130
/*
112
- * Now we can eval the expression .
131
+ * Now we can eval the combining operator for this column .
113
132
*/
114
- result = ExecEvalExpr ((Node * ) expr , econtext , & isnull ,
115
- (bool * ) NULL );
116
- if (isnull )
133
+ expresult = ExecEvalExpr ((Node * ) expr , econtext , & expnull ,
134
+ (bool * ) NULL );
135
+ /*
136
+ * Combine the result into the row result as appropriate.
137
+ */
138
+ if (col == 1 )
117
139
{
118
- if (subLinkType == EXPR_SUBLINK )
119
- elog (ERROR , "ExecSubPlan: null value returned by expression subselect" );
120
- else
121
- result = (Datum ) false;
140
+ rowresult = expresult ;
141
+ rownull = expnull ;
122
142
}
123
- if (subLinkType != EXPR_SUBLINK )
143
+ else if (useor )
124
144
{
125
- if ((!(bool ) result && !(sublink -> useor )) ||
126
- ((bool ) result && sublink -> useor ))
127
- break ;
145
+ /* combine within row per OR semantics */
146
+ if (expnull )
147
+ rownull = true;
148
+ else if (DatumGetInt32 (expresult ) != 0 )
149
+ {
150
+ rowresult = (Datum ) true;
151
+ rownull = false;
152
+ break ; /* needn't look at any more columns */
153
+ }
128
154
}
129
- i ++ ;
155
+ else
156
+ {
157
+ /* combine within row per AND semantics */
158
+ if (expnull )
159
+ rownull = true;
160
+ else if (DatumGetInt32 (expresult ) == 0 )
161
+ {
162
+ rowresult = (Datum ) false;
163
+ rownull = false;
164
+ break ; /* needn't look at any more columns */
165
+ }
166
+ }
167
+ col ++ ;
130
168
}
131
169
132
- if (subLinkType == ALL_SUBLINK && !(bool ) result )
133
- break ;
134
- if (subLinkType == ANY_SUBLINK && (bool ) result )
135
- break ;
170
+ if (subLinkType == ANY_SUBLINK )
171
+ {
172
+ /* combine across rows per OR semantics */
173
+ if (rownull )
174
+ * isNull = true;
175
+ else if (DatumGetInt32 (rowresult ) != 0 )
176
+ {
177
+ result = (Datum ) true;
178
+ * isNull = false;
179
+ break ; /* needn't look at any more rows */
180
+ }
181
+ }
182
+ else if (subLinkType == ALL_SUBLINK )
183
+ {
184
+ /* combine across rows per AND semantics */
185
+ if (rownull )
186
+ * isNull = true;
187
+ else if (DatumGetInt32 (rowresult ) == 0 )
188
+ {
189
+ result = (Datum ) false;
190
+ * isNull = false;
191
+ break ; /* needn't look at any more rows */
192
+ }
193
+ }
194
+ else
195
+ {
196
+ /* must be EXPR_SUBLINK */
197
+ result = rowresult ;
198
+ * isNull = rownull ;
199
+ }
136
200
}
137
201
138
202
if (!found )
139
203
{
140
- /* deal with empty subplan result. Note default result is 'false' */
141
- if (subLinkType == ALL_SUBLINK )
142
- result = (Datum ) true;
143
- else if (subLinkType == EXPR_SUBLINK )
144
- elog (ERROR , "ExecSubPlan: no tuples returned by expression subselect" );
204
+ /* deal with empty subplan result. result/isNull were previously
205
+ * initialized correctly for all sublink types except EXPR.
206
+ */
207
+ if (subLinkType == EXPR_SUBLINK )
208
+ {
209
+ result = (Datum ) false;
210
+ * isNull = true;
211
+ }
145
212
}
146
213
147
214
return result ;
@@ -152,7 +219,6 @@ ExecSubPlan(SubPlan *node, List *pvar, ExprContext *econtext)
152
219
*
153
220
* ----------------------------------------------------------------
154
221
*/
155
- extern void ExecCheckPerms (CmdType op , int resRel , List * rtable , Query * q );
156
222
bool
157
223
ExecInitSubPlan (SubPlan * node , EState * estate , Plan * parent )
158
224
{
0 commit comments