diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2003-04-08 23:20:04 +0000 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2003-04-08 23:20:04 +0000 |
commit | 730840c9b649a48604083270d48792915ca89233 (patch) | |
tree | cf3ccc25e61cdfc07061ebec63393d77b3a2f643 /src/backend/executor/nodeSubplan.c | |
parent | 6fb5115850be766c42177cebf672c68c7d8e3ddd (diff) | |
download | postgresql-730840c9b649a48604083270d48792915ca89233.tar.gz postgresql-730840c9b649a48604083270d48792915ca89233.zip |
First phase of work on array improvements. ARRAY[x,y,z] constructor
expressions, ARRAY(sub-SELECT) expressions, some array functions.
Polymorphic functions using ANYARRAY/ANYELEMENT argument and return
types. Some regression tests in place, documentation is lacking.
Joe Conway, with some kibitzing from Tom Lane.
Diffstat (limited to 'src/backend/executor/nodeSubplan.c')
-rw-r--r-- | src/backend/executor/nodeSubplan.c | 200 |
1 files changed, 188 insertions, 12 deletions
diff --git a/src/backend/executor/nodeSubplan.c b/src/backend/executor/nodeSubplan.c index 4fd8af2ae4d..5d9bdc84241 100644 --- a/src/backend/executor/nodeSubplan.c +++ b/src/backend/executor/nodeSubplan.c @@ -7,7 +7,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/executor/nodeSubplan.c,v 1.44 2003/02/09 00:30:39 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/executor/nodeSubplan.c,v 1.45 2003/04/08 23:20:01 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -24,9 +24,27 @@ #include "executor/nodeSubplan.h" #include "nodes/makefuncs.h" #include "parser/parse_expr.h" -#include "tcop/pquery.h" +#include "utils/array.h" +#include "utils/datum.h" +#include "utils/lsyscache.h" +typedef struct ArrayBuildState +{ + MemoryContext mcontext; /* where all the temp stuff is kept */ + Datum *dvalues; /* array of accumulated Datums */ + /* + * The allocated size of dvalues[] is always a multiple of + * ARRAY_ELEMS_CHUNKSIZE + */ +#define ARRAY_ELEMS_CHUNKSIZE 64 + int nelems; /* number of valid Datums in dvalues[] */ + Oid element_type; /* data type of the Datums */ + int16 typlen; /* needed info about datatype */ + bool typbyval; + char typalign; +} ArrayBuildState; + static Datum ExecHashSubPlan(SubPlanState *node, ExprContext *econtext, bool *isNull); @@ -36,6 +54,12 @@ static Datum ExecScanSubPlan(SubPlanState *node, static void buildSubPlanHash(SubPlanState *node); static bool findPartialMatch(TupleHashTable hashtable, TupleTableSlot *slot); static bool tupleAllNulls(HeapTuple tuple); +static ArrayBuildState *accumArrayResult(ArrayBuildState *astate, + Datum dvalue, bool disnull, + Oid element_type, + MemoryContext rcontext); +static Datum makeArrayResult(ArrayBuildState *astate, + MemoryContext rcontext); /* ---------------------------------------------------------------- @@ -206,6 +230,7 @@ ExecScanSubPlan(SubPlanState *node, bool found = false; /* TRUE if got at least one subplan tuple */ List *pvar; List *lst; + ArrayBuildState *astate = NULL; /* * We are probably in a short-lived expression-evaluation context. @@ -236,11 +261,11 @@ ExecScanSubPlan(SubPlanState *node, ExecReScan(planstate, NULL); /* - * For all sublink types except EXPR_SUBLINK, the result is boolean as - * are the results of the combining operators. We combine results - * within a tuple (if there are multiple columns) using OR semantics - * if "useOr" is true, AND semantics if not. We then combine results - * across tuples (if the subplan produces more than one) using OR + * For all sublink types except EXPR_SUBLINK and ARRAY_SUBLINK, the result + * is boolean as are the results of the combining operators. We combine + * results within a tuple (if there are multiple columns) using OR + * semantics if "useOr" is true, AND semantics if not. We then combine + * results across tuples (if the subplan produces more than one) using OR * semantics for ANY_SUBLINK or AND semantics for ALL_SUBLINK. * (MULTIEXPR_SUBLINK doesn't allow multiple tuples from the subplan.) * NULL results from the combining operators are handled according to @@ -249,9 +274,10 @@ ExecScanSubPlan(SubPlanState *node, * MULTIEXPR_SUBLINK. * * For EXPR_SUBLINK we require the subplan to produce no more than one - * tuple, else an error is raised. If zero tuples are produced, we - * return NULL. Assuming we get a tuple, we just return its first - * column (there can be only one non-junk column in this case). + * tuple, else an error is raised. For ARRAY_SUBLINK we allow the subplan + * to produce more than one tuple. In either case, if zero tuples are + * produced, we return NULL. Assuming we get a tuple, we just use its + * first column (there can be only one non-junk column in this case). */ result = BoolGetDatum(subLinkType == ALL_SUBLINK); *isNull = false; @@ -301,6 +327,21 @@ ExecScanSubPlan(SubPlanState *node, continue; } + if (subLinkType == ARRAY_SUBLINK) + { + Datum dvalue; + bool disnull; + + found = true; + /* stash away current value */ + dvalue = heap_getattr(tup, 1, tdesc, &disnull); + astate = accumArrayResult(astate, dvalue, disnull, + tdesc->attrs[0]->atttypid, + oldcontext); + /* keep scanning subplan to collect all values */ + continue; + } + /* cannot allow multiple input tuples for MULTIEXPR sublink either */ if (subLinkType == MULTIEXPR_SUBLINK && found) elog(ERROR, "More than one tuple returned by a subselect used as an expression."); @@ -407,15 +448,23 @@ ExecScanSubPlan(SubPlanState *node, { /* * deal with empty subplan result. result/isNull were previously - * initialized correctly for all sublink types except EXPR and + * initialized correctly for all sublink types except EXPR, ARRAY, and * MULTIEXPR; for those, return NULL. */ - if (subLinkType == EXPR_SUBLINK || subLinkType == MULTIEXPR_SUBLINK) + if (subLinkType == EXPR_SUBLINK || + subLinkType == ARRAY_SUBLINK || + subLinkType == MULTIEXPR_SUBLINK) { result = (Datum) 0; *isNull = true; } } + else if (subLinkType == ARRAY_SUBLINK) + { + Assert(astate != NULL); + /* We return the result in the caller's context */ + result = makeArrayResult(astate, oldcontext); + } MemoryContextSwitchTo(oldcontext); @@ -797,6 +846,7 @@ ExecInitSubPlan(SubPlanState *node, EState *estate) /* Lookup the combining function */ fmgr_info(opexpr->opfuncid, &node->eqfunctions[i-1]); + node->eqfunctions[i-1].fn_expr = (Node *) opexpr; i++; } @@ -857,6 +907,7 @@ ExecSetParamPlan(SubPlanState *node, ExprContext *econtext) TupleTableSlot *slot; List *lst; bool found = false; + ArrayBuildState *astate = NULL; /* * Must switch to child query's per-query memory context. @@ -891,6 +942,21 @@ ExecSetParamPlan(SubPlanState *node, ExprContext *econtext) break; } + if (subLinkType == ARRAY_SUBLINK) + { + Datum dvalue; + bool disnull; + + found = true; + /* stash away current value */ + dvalue = heap_getattr(tup, 1, tdesc, &disnull); + astate = accumArrayResult(astate, dvalue, disnull, + tdesc->attrs[0]->atttypid, + oldcontext); + /* keep scanning subplan to collect all values */ + continue; + } + if (found && (subLinkType == EXPR_SUBLINK || subLinkType == MULTIEXPR_SUBLINK)) @@ -951,6 +1017,18 @@ ExecSetParamPlan(SubPlanState *node, ExprContext *econtext) } } } + else if (subLinkType == ARRAY_SUBLINK) + { + /* There can be only one param... */ + int paramid = lfirsti(subplan->setParam); + ParamExecData *prm = &(econtext->ecxt_param_exec_vals[paramid]); + + Assert(astate != NULL); + prm->execPlan = NULL; + /* We build the result in query context so it won't disappear */ + prm->value = makeArrayResult(astate, econtext->ecxt_per_query_memory); + prm->isnull = false; + } MemoryContextSwitchTo(oldcontext); } @@ -1007,3 +1085,101 @@ ExecReScanSetParamPlan(SubPlanState *node, PlanState *parent) parent->chgParam = bms_add_member(parent->chgParam, paramid); } } + +/* + * accumArrayResult - accumulate one (more) Datum for an ARRAY_SUBLINK + * + * astate is working state (NULL on first call) + * rcontext is where to keep working state + */ +static ArrayBuildState * +accumArrayResult(ArrayBuildState *astate, + Datum dvalue, bool disnull, + Oid element_type, + MemoryContext rcontext) +{ + MemoryContext arr_context, + oldcontext; + + if (astate == NULL) + { + /* First time through --- initialize */ + + /* Make a temporary context to hold all the junk */ + arr_context = AllocSetContextCreate(rcontext, + "ARRAY_SUBLINK Result", + ALLOCSET_DEFAULT_MINSIZE, + ALLOCSET_DEFAULT_INITSIZE, + ALLOCSET_DEFAULT_MAXSIZE); + oldcontext = MemoryContextSwitchTo(arr_context); + astate = (ArrayBuildState *) palloc(sizeof(ArrayBuildState)); + astate->mcontext = arr_context; + astate->dvalues = (Datum *) + palloc(ARRAY_ELEMS_CHUNKSIZE * sizeof(Datum)); + astate->nelems = 0; + astate->element_type = element_type; + get_typlenbyvalalign(element_type, + &astate->typlen, + &astate->typbyval, + &astate->typalign); + } + else + { + oldcontext = MemoryContextSwitchTo(astate->mcontext); + Assert(astate->element_type == element_type); + /* enlarge dvalues[] if needed */ + if ((astate->nelems % ARRAY_ELEMS_CHUNKSIZE) == 0) + astate->dvalues = (Datum *) + repalloc(astate->dvalues, + (astate->nelems + ARRAY_ELEMS_CHUNKSIZE) * sizeof(Datum)); + } + + if (disnull) + elog(ERROR, "NULL elements not allowed in Arrays"); + + /* Use datumCopy to ensure pass-by-ref stuff is copied into mcontext */ + astate->dvalues[astate->nelems++] = + datumCopy(dvalue, astate->typbyval, astate->typlen); + + MemoryContextSwitchTo(oldcontext); + + return astate; +} + +/* + * makeArrayResult - produce final result of ARRAY_SUBLINK + * + * astate is working state (not NULL) + * rcontext is where to construct result + */ +static Datum +makeArrayResult(ArrayBuildState *astate, + MemoryContext rcontext) +{ + ArrayType *result; + int dims[1]; + int lbs[1]; + MemoryContext oldcontext; + + /* Build the final array result in rcontext */ + oldcontext = MemoryContextSwitchTo(rcontext); + + dims[0] = astate->nelems; + lbs[0] = 1; + + result = construct_md_array(astate->dvalues, + 1, + dims, + lbs, + astate->element_type, + astate->typlen, + astate->typbyval, + astate->typalign); + + MemoryContextSwitchTo(oldcontext); + + /* Clean up all the junk */ + MemoryContextDelete(astate->mcontext); + + return PointerGetDatum(result); +} |