1818#include "executor/nodeSubplan.h"
1919#include "tcop/pquery.h"
2020
21+ /* should be exported by execMain.c */
22+ extern void ExecCheckPerms (CmdType op ,int resRel ,List * rtable ,Query * q );
23+
2124/* ----------------------------------------------------------------
2225 *ExecSubPlan(node)
2326 *
2427 * ----------------------------------------------------------------
2528 */
2629Datum
27- ExecSubPlan (SubPlan * node ,List * pvar ,ExprContext * econtext )
30+ ExecSubPlan (SubPlan * node ,List * pvar ,ExprContext * econtext , bool * isNull )
2831{
2932Plan * plan = node -> plan ;
3033SubLink * sublink = node -> sublink ;
3134SubLinkType subLinkType = sublink -> subLinkType ;
35+ bool useor = sublink -> useor ;
3236TupleTableSlot * slot ;
33- List * lst ;
34- Datum result = (Datum ) false;
37+ Datum result ;
3538bool found = false;/* TRUE if got at least one subplan tuple */
39+ List * lst ;
3640
37- if (node -> setParam != NULL )
41+ if (node -> setParam != NIL )
3842elog (ERROR ,"ExecSubPlan: can't set parent params from subquery" );
3943
4044/*
4145 * Set Params of this plan from parent plan correlation Vars
4246 */
43- if (node -> parParam != NULL )
47+ if (node -> parParam != NIL )
4448{
4549foreach (lst ,node -> parParam )
4650{
4751ParamExecData * prm = & (econtext -> ecxt_param_exec_vals [lfirsti (lst )]);
4852
53+ Assert (pvar != NIL );
4954prm -> value = ExecEvalExpr ((Node * )lfirst (pvar ),
5055econtext ,
5156& (prm -> isnull ),NULL );
5257pvar = lnext (pvar );
5358}
5459plan -> chgParam = nconc (plan -> chgParam ,listCopy (node -> parParam ));
5560}
61+ Assert (pvar == NIL );
5662
5763ExecReScan (plan , (ExprContext * )NULL ,plan );
5864
5965/*
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.
6375 *
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.
7084 */
85+ result = (Datum ) (subLinkType == ALL_SUBLINK ? true : false);
86+ * isNull = false;
7187
7288for (slot = ExecProcNode (plan ,plan );
7389 !TupIsNull (slot );
7490slot = ExecProcNode (plan ,plan ))
7591{
7692HeapTuple tup = slot -> val ;
7793TupleDesc 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 ;
8597
8698if (subLinkType == EXISTS_SUBLINK )
8799return (Datum ) true;
88100
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+
89105found = true;
90106
107+ /* iterate over combining operators for columns of tuple */
91108foreach (lst ,sublink -> oper )
92109{
93110Expr * expr = (Expr * )lfirst (lst );
94111Const * con = lsecond (expr -> args );
95- bool isnull ;
112+ Datum expresult ;
113+ bool expnull ;
96114
97115/*
98116 * The righthand side of the expression should be either a Const
@@ -107,41 +125,90 @@ ExecSubPlan(SubPlan *node, List *pvar, ExprContext *econtext)
107125con = lfirst (((Expr * )con )-> args );
108126Assert (IsA (con ,Const ));
109127}
110- con -> constvalue = heap_getattr (tup ,i ,tdesc ,& (con -> constisnull ));
128+ con -> constvalue = heap_getattr (tup ,col ,tdesc ,
129+ & (con -> constisnull ));
111130/*
112- * Now we can eval theexpression .
131+ * Now we can eval thecombining operator for this column .
113132 */
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 )
117139{
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 ;
122142}
123- if (subLinkType != EXPR_SUBLINK )
143+ else if (useor )
124144{
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+ }
128154}
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 ++ ;
130168}
131169
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+ }
136200}
137201
138202if (!found )
139203{
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+ }
145212}
146213
147214return result ;
@@ -152,7 +219,6 @@ ExecSubPlan(SubPlan *node, List *pvar, ExprContext *econtext)
152219 *
153220 * ----------------------------------------------------------------
154221 */
155- extern void ExecCheckPerms (CmdType op ,int resRel ,List * rtable ,Query * q );
156222bool
157223ExecInitSubPlan (SubPlan * node ,EState * estate ,Plan * parent )
158224{