]> granicus.if.org Git - postgresql/blob - src/backend/executor/nodeSubplan.c
Some changes to prepare for LONG attributes.
[postgresql] / src / backend / executor / nodeSubplan.c
1 /*-------------------------------------------------------------------------
2  *
3  * nodeSubplan.c
4  *        routines to support subselects
5  *
6  * Copyright (c) 1994, Regents of the University of California
7  *
8  * IDENTIFICATION
9  *        $Header: /cvsroot/pgsql/src/backend/executor/nodeSubplan.c,v 1.18 1999/12/16 22:19:44 wieck Exp $
10  *
11  *-------------------------------------------------------------------------
12  */
13 /*
14  *       INTERFACE ROUTINES
15  *              ExecSubPlan  - process a subselect
16  *              ExecInitSubPlan - initialize a subselect
17  *              ExecEndSubPlan  - shut down a subselect
18  */
19 #include "postgres.h"
20
21 #include "access/heapam.h"
22 #include "executor/executor.h"
23 #include "executor/nodeSubplan.h"
24 #include "tcop/pquery.h"
25
26 /* should be exported by execMain.c */
27 extern void ExecCheckPerms(CmdType op, int resRel, List *rtable, Query *q);
28
29 /* ----------------------------------------------------------------
30  *              ExecSubPlan(node)
31  *
32  * ----------------------------------------------------------------
33  */
34 Datum
35 ExecSubPlan(SubPlan *node, List *pvar, ExprContext *econtext, bool *isNull)
36 {
37         Plan       *plan = node->plan;
38         SubLink    *sublink = node->sublink;
39         SubLinkType subLinkType = sublink->subLinkType;
40         bool            useor = sublink->useor;
41         TupleTableSlot *slot;
42         Datum           result;
43         bool            found = false;  /* TRUE if got at least one subplan tuple */
44         List       *lst;
45
46         if (node->setParam != NIL)
47                 elog(ERROR, "ExecSubPlan: can't set parent params from subquery");
48
49         /*
50          * Set Params of this plan from parent plan correlation Vars
51          */
52         if (node->parParam != NIL)
53         {
54                 foreach(lst, node->parParam)
55                 {
56                         ParamExecData *prm = &(econtext->ecxt_param_exec_vals[lfirsti(lst)]);
57
58                         Assert(pvar != NIL);
59                         prm->value = ExecEvalExpr((Node *) lfirst(pvar),
60                                                                           econtext,
61                                                                           &(prm->isnull), NULL);
62                         pvar = lnext(pvar);
63                 }
64                 plan->chgParam = nconc(plan->chgParam, listCopy(node->parParam));
65         }
66         Assert(pvar == NIL);
67
68         ExecReScan(plan, (ExprContext *) NULL, plan);
69
70         /*
71          * For all sublink types except EXPR_SUBLINK, the result is boolean
72          * as are the results of the combining operators.  We combine results
73          * within a tuple (if there are multiple columns) using OR semantics
74          * if "useor" is true, AND semantics if not.  We then combine results
75          * across tuples (if the subplan produces more than one) using OR
76          * semantics for ANY_SUBLINK or AND semantics for ALL_SUBLINK.
77          * (MULTIEXPR_SUBLINK doesn't allow multiple tuples from the subplan.)
78          * NULL results from the combining operators are handled according to
79          * the usual SQL semantics for OR and AND.  The result for no input
80          * tuples is FALSE for ANY_SUBLINK, TRUE for ALL_SUBLINK, NULL for
81          * MULTIEXPR_SUBLINK.
82          *
83          * For EXPR_SUBLINK we require the subplan to produce no more than one
84          * tuple, else an error is raised.  If zero tuples are produced, we
85          * return NULL.  Assuming we get a tuple, we just return its first
86          * column (there can be only one non-junk column in this case).
87          */
88         result = (Datum) (subLinkType == ALL_SUBLINK ? true : false);
89         *isNull = false;
90
91         for (slot = ExecProcNode(plan, plan);
92                  !TupIsNull(slot);
93                  slot = ExecProcNode(plan, plan))
94         {
95                 HeapTuple       tup = slot->val;
96                 TupleDesc       tdesc = slot->ttc_tupleDescriptor;
97                 Datum           rowresult = (Datum) (useor ? false : true);
98                 bool            rownull = false;
99                 int                     col = 1;
100
101                 if (subLinkType == EXISTS_SUBLINK)
102                         return (Datum) true;
103
104                 if (subLinkType == EXPR_SUBLINK)
105                 {
106                         /* cannot allow multiple input tuples for EXPR sublink */
107                         if (found)
108                                 elog(ERROR, "ExecSubPlan: more than one tuple returned by expression subselect");
109                         found = true;
110                         /*
111                          * We need to copy the subplan's tuple in case the result is of
112                          * pass-by-ref type --- our return value will point into this
113                          * copied tuple!  Can't use the subplan's instance of the tuple
114                          * since it won't still be valid after next ExecProcNode() call.
115                          * node->curTuple keeps track of the copied tuple for eventual
116                          * freeing.
117                          */
118                         tup = heap_copytuple(tup);
119                         if (node->curTuple)
120                                 heap_freetuple(node->curTuple);
121                         node->curTuple = tup;
122                         result = heap_getattr(tup, col, tdesc, isNull);
123                         /* keep scanning subplan to make sure there's only one tuple */
124                         continue;
125                 }
126
127                 /* cannot allow multiple input tuples for MULTIEXPR sublink either */
128                 if (subLinkType == MULTIEXPR_SUBLINK && found)
129                         elog(ERROR, "ExecSubPlan: more than one tuple returned by expression subselect");
130
131                 found = true;
132
133                 /* For ALL, ANY, and MULTIEXPR sublinks, iterate over combining
134                  * operators for columns of tuple.
135                  */
136                 foreach(lst, sublink->oper)
137                 {
138                         Expr       *expr = (Expr *) lfirst(lst);
139                         Const      *con = lsecond(expr->args);
140                         Datum           expresult;
141                         bool            expnull;
142
143                         /*
144                          * The righthand side of the expression should be either a Const
145                          * or a function call taking a Const as arg (the function would
146                          * be a run-time type coercion inserted by the parser to get to
147                          * the input type needed by the operator).  Find the Const node
148                          * and insert the actual righthand side value into it.
149                          */
150                         if (! IsA(con, Const))
151                         {
152                                 Assert(IsA(con, Expr));
153                                 con = lfirst(((Expr *) con)->args);
154                                 Assert(IsA(con, Const));
155                         }
156                         con->constvalue = heap_getattr(tup, col, tdesc,
157                                                                                    &(con->constisnull));
158                         /*
159                          * Now we can eval the combining operator for this column.
160                          */
161                         expresult = ExecEvalExpr((Node *) expr, econtext, &expnull,
162                                                                          (bool *) NULL);
163                         /*
164                          * Combine the result into the row result as appropriate.
165                          */
166                         if (col == 1)
167                         {
168                                 rowresult = expresult;
169                                 rownull = expnull;
170                         }
171                         else if (useor)
172                         {
173                                 /* combine within row per OR semantics */
174                                 if (expnull)
175                                         rownull = true;
176                                 else if (DatumGetInt32(expresult) != 0)
177                                 {
178                                         rowresult = (Datum) true;
179                                         rownull = false;
180                                         break;          /* needn't look at any more columns */
181                                 }
182                         }
183                         else
184                         {
185                                 /* combine within row per AND semantics */
186                                 if (expnull)
187                                         rownull = true;
188                                 else if (DatumGetInt32(expresult) == 0)
189                                 {
190                                         rowresult = (Datum) false;
191                                         rownull = false;
192                                         break;          /* needn't look at any more columns */
193                                 }
194                         }
195                         col++;
196                 }
197
198                 if (subLinkType == ANY_SUBLINK)
199                 {
200                         /* combine across rows per OR semantics */
201                         if (rownull)
202                                 *isNull = true;
203                         else if (DatumGetInt32(rowresult) != 0)
204                         {
205                                 result = (Datum) true;
206                                 *isNull = false;
207                                 break;                  /* needn't look at any more rows */
208                         }
209                 }
210                 else if (subLinkType == ALL_SUBLINK)
211                 {
212                         /* combine across rows per AND semantics */
213                         if (rownull)
214                                 *isNull = true;
215                         else if (DatumGetInt32(rowresult) == 0)
216                         {
217                                 result = (Datum) false;
218                                 *isNull = false;
219                                 break;                  /* needn't look at any more rows */
220                         }
221                 }
222                 else
223                 {
224                         /* must be MULTIEXPR_SUBLINK */
225                         result = rowresult;
226                         *isNull = rownull;
227                 }
228         }
229
230         if (!found)
231         {
232                 /* deal with empty subplan result.  result/isNull were previously
233                  * initialized correctly for all sublink types except EXPR and
234                  * MULTIEXPR; for those, return NULL.
235                  */
236                 if (subLinkType == EXPR_SUBLINK || subLinkType == MULTIEXPR_SUBLINK)
237                 {
238                                 result = (Datum) false;
239                                 *isNull = true;
240                 }
241         }
242
243         return result;
244 }
245
246 /* ----------------------------------------------------------------
247  *              ExecInitSubPlan
248  *
249  * ----------------------------------------------------------------
250  */
251 bool
252 ExecInitSubPlan(SubPlan *node, EState *estate, Plan *parent)
253 {
254         EState     *sp_estate = CreateExecutorState();
255
256         ExecCheckPerms(CMD_SELECT, 0, node->rtable, (Query *) NULL);
257
258         sp_estate->es_range_table = node->rtable;
259         sp_estate->es_param_list_info = estate->es_param_list_info;
260         sp_estate->es_param_exec_vals = estate->es_param_exec_vals;
261         sp_estate->es_tupleTable =
262                 ExecCreateTupleTable(ExecCountSlotsNode(node->plan) + 10);
263         sp_estate->es_snapshot = estate->es_snapshot;
264
265         node->shutdown = false;
266         node->curTuple = NULL;
267
268         if (!ExecInitNode(node->plan, sp_estate, NULL))
269                 return false;
270
271         node->shutdown = true;          /* now we need to shutdown the subplan */
272
273         /*
274          * If this plan is un-correlated or undirect correlated one and want
275          * to set params for parent plan then prepare parameters.
276          */
277         if (node->setParam != NIL)
278         {
279                 List       *lst;
280
281                 foreach(lst, node->setParam)
282                 {
283                         ParamExecData *prm = &(estate->es_param_exec_vals[lfirsti(lst)]);
284
285                         prm->execPlan = node;
286                 }
287
288                 /*
289                  * Note that in the case of un-correlated subqueries we don't care
290                  * about setting parent->chgParam here: indices take care about
291                  * it, for others - it doesn't matter...
292                  */
293         }
294
295         return true;
296 }
297
298 /* ----------------------------------------------------------------
299  *              ExecSetParamPlan
300  *
301  *              Executes plan of node and sets parameters.
302  * ----------------------------------------------------------------
303  */
304 void
305 ExecSetParamPlan(SubPlan *node)
306 {
307         Plan       *plan = node->plan;
308         SubLink    *sublink = node->sublink;
309         TupleTableSlot *slot;
310         List       *lst;
311         bool            found = false;
312
313         if (sublink->subLinkType == ANY_SUBLINK ||
314                 sublink->subLinkType == ALL_SUBLINK)
315                 elog(ERROR, "ExecSetParamPlan: ANY/ALL subselect unsupported");
316
317         if (plan->chgParam != NULL)
318                 ExecReScan(plan, (ExprContext *) NULL, plan);
319
320         for (slot = ExecProcNode(plan, plan);
321                  !TupIsNull(slot);
322                  slot = ExecProcNode(plan, plan))
323         {
324                 HeapTuple       tup = slot->val;
325                 TupleDesc       tdesc = slot->ttc_tupleDescriptor;
326                 int                     i = 1;
327
328                 if (sublink->subLinkType == EXISTS_SUBLINK)
329                 {
330                         ParamExecData *prm = &(plan->state->es_param_exec_vals[lfirsti(node->setParam)]);
331
332                         prm->execPlan = NULL;
333                         prm->value = (Datum) true;
334                         prm->isnull = false;
335                         found = true;
336                         break;
337                 }
338
339                 if (found &&
340                         (sublink->subLinkType == EXPR_SUBLINK ||
341                          sublink->subLinkType == MULTIEXPR_SUBLINK))
342                         elog(ERROR, "ExecSetParamPlan: more than one tuple returned by expression subselect");
343
344                 found = true;
345
346                 /*
347                  * We need to copy the subplan's tuple in case any of the params
348                  * are pass-by-ref type --- the pointers stored in the param structs
349                  * will point at this copied tuple!  node->curTuple keeps track
350                  * of the copied tuple for eventual freeing.
351                  */
352                 tup = heap_copytuple(tup);
353                 if (node->curTuple)
354                         heap_freetuple(node->curTuple);
355                 node->curTuple = tup;
356
357                 foreach(lst, node->setParam)
358                 {
359                         ParamExecData *prm = &(plan->state->es_param_exec_vals[lfirsti(lst)]);
360
361                         prm->execPlan = NULL;
362                         prm->value = heap_getattr(tup, i, tdesc, &(prm->isnull));
363                         i++;
364                 }
365         }
366
367         if (!found)
368         {
369                 if (sublink->subLinkType == EXISTS_SUBLINK)
370                 {
371                         ParamExecData *prm = &(plan->state->es_param_exec_vals[lfirsti(node->setParam)]);
372
373                         prm->execPlan = NULL;
374                         prm->value = (Datum) false;
375                         prm->isnull = false;
376                 }
377                 else
378                 {
379                         foreach(lst, node->setParam)
380                         {
381                                 ParamExecData *prm = &(plan->state->es_param_exec_vals[lfirsti(lst)]);
382
383                                 prm->execPlan = NULL;
384                                 prm->value = (Datum) NULL;
385                                 prm->isnull = true;
386                         }
387                 }
388         }
389
390         if (plan->extParam == NULL) /* un-correlated ... */
391         {
392                 ExecEndNode(plan, plan);
393                 node->shutdown = false;
394         }
395 }
396
397 /* ----------------------------------------------------------------
398  *              ExecEndSubPlan
399  * ----------------------------------------------------------------
400  */
401 void
402 ExecEndSubPlan(SubPlan *node)
403 {
404         if (node->shutdown)
405         {
406                 ExecEndNode(node->plan, node->plan);
407                 node->shutdown = false;
408         }
409         if (node->curTuple)
410         {
411                 heap_freetuple(node->curTuple);
412                 node->curTuple = NULL;
413         }
414 }
415
416 void
417 ExecReScanSetParamPlan(SubPlan *node, Plan *parent)
418 {
419         Plan       *plan = node->plan;
420         List       *lst;
421
422         if (node->parParam != NULL)
423                 elog(ERROR, "ExecReScanSetParamPlan: direct correlated subquery unsupported, yet");
424         if (node->setParam == NULL)
425                 elog(ERROR, "ExecReScanSetParamPlan: setParam list is NULL");
426         if (plan->extParam == NULL)
427                 elog(ERROR, "ExecReScanSetParamPlan: extParam list of plan is NULL");
428
429         /*
430          * Don't actual re-scan: ExecSetParamPlan does re-scan if
431          * node->plan->chgParam is not NULL... ExecReScan (plan, NULL, plan);
432          */
433
434         foreach(lst, node->setParam)
435         {
436                 ParamExecData *prm = &(plan->state->es_param_exec_vals[lfirsti(lst)]);
437
438                 prm->execPlan = node;
439         }
440
441         parent->chgParam = nconc(parent->chgParam, listCopy(node->setParam));
442
443 }