mirror of
https://github.com/postgres/postgres.git
synced 2025-07-28 23:42:10 +03:00
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.
This commit is contained in:
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.127 2003/03/27 16:51:27 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.128 2003/04/08 23:20:00 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -75,6 +75,9 @@ static Datum ExecEvalAnd(BoolExprState *andExpr, ExprContext *econtext,
|
||||
bool *isNull);
|
||||
static Datum ExecEvalCase(CaseExprState *caseExpr, ExprContext *econtext,
|
||||
bool *isNull, ExprDoneCond *isDone);
|
||||
static Datum ExecEvalArray(ArrayExprState *astate,
|
||||
ExprContext *econtext,
|
||||
bool *isNull);
|
||||
static Datum ExecEvalCoalesce(CoalesceExprState *coalesceExpr,
|
||||
ExprContext *econtext,
|
||||
bool *isNull);
|
||||
@ -246,38 +249,38 @@ ExecEvalArrayRef(ArrayRefExprState *astate,
|
||||
resultArray = array_set(array_source, i,
|
||||
upper.indx,
|
||||
sourceData,
|
||||
arrayRef->refattrlength,
|
||||
arrayRef->refelemlength,
|
||||
arrayRef->refelembyval,
|
||||
arrayRef->refelemalign,
|
||||
astate->refattrlength,
|
||||
astate->refelemlength,
|
||||
astate->refelembyval,
|
||||
astate->refelemalign,
|
||||
isNull);
|
||||
else
|
||||
resultArray = array_set_slice(array_source, i,
|
||||
upper.indx, lower.indx,
|
||||
(ArrayType *) DatumGetPointer(sourceData),
|
||||
arrayRef->refattrlength,
|
||||
arrayRef->refelemlength,
|
||||
arrayRef->refelembyval,
|
||||
arrayRef->refelemalign,
|
||||
astate->refattrlength,
|
||||
astate->refelemlength,
|
||||
astate->refelembyval,
|
||||
astate->refelemalign,
|
||||
isNull);
|
||||
return PointerGetDatum(resultArray);
|
||||
}
|
||||
|
||||
if (lIndex == NULL)
|
||||
return array_ref(array_source, i, upper.indx,
|
||||
arrayRef->refattrlength,
|
||||
arrayRef->refelemlength,
|
||||
arrayRef->refelembyval,
|
||||
arrayRef->refelemalign,
|
||||
astate->refattrlength,
|
||||
astate->refelemlength,
|
||||
astate->refelembyval,
|
||||
astate->refelemalign,
|
||||
isNull);
|
||||
else
|
||||
{
|
||||
resultArray = array_get_slice(array_source, i,
|
||||
upper.indx, lower.indx,
|
||||
arrayRef->refattrlength,
|
||||
arrayRef->refelemlength,
|
||||
arrayRef->refelembyval,
|
||||
arrayRef->refelemalign,
|
||||
astate->refattrlength,
|
||||
astate->refelemlength,
|
||||
astate->refelembyval,
|
||||
astate->refelemalign,
|
||||
isNull);
|
||||
return PointerGetDatum(resultArray);
|
||||
}
|
||||
@ -613,6 +616,7 @@ init_fcache(Oid foid, FuncExprState *fcache, MemoryContext fcacheCxt)
|
||||
|
||||
/* Initialize additional info */
|
||||
fcache->setArgsValid = false;
|
||||
fcache->func.fn_expr = (Node *) fcache->xprstate.expr;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1426,6 +1430,158 @@ ExecEvalCase(CaseExprState *caseExpr, ExprContext *econtext,
|
||||
return (Datum) 0;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
* ExecEvalArray - ARRAY[] expressions
|
||||
* ----------------------------------------------------------------
|
||||
*/
|
||||
static Datum
|
||||
ExecEvalArray(ArrayExprState *astate, ExprContext *econtext,
|
||||
bool *isNull)
|
||||
{
|
||||
ArrayExpr *arrayExpr = (ArrayExpr *) astate->xprstate.expr;
|
||||
ArrayType *result;
|
||||
List *element;
|
||||
Oid element_type = arrayExpr->element_typeid;
|
||||
int ndims = arrayExpr->ndims;
|
||||
int dims[MAXDIM];
|
||||
int lbs[MAXDIM];
|
||||
|
||||
if (ndims == 1)
|
||||
{
|
||||
int nelems;
|
||||
Datum *dvalues;
|
||||
int i = 0;
|
||||
|
||||
nelems = length(astate->elements);
|
||||
|
||||
/* Shouldn't happen here, but if length is 0, return NULL */
|
||||
if (nelems == 0)
|
||||
{
|
||||
*isNull = true;
|
||||
return (Datum) 0;
|
||||
}
|
||||
|
||||
dvalues = (Datum *) palloc(nelems * sizeof(Datum));
|
||||
|
||||
/* loop through and build array of datums */
|
||||
foreach(element, astate->elements)
|
||||
{
|
||||
ExprState *e = (ExprState *) lfirst(element);
|
||||
bool eisnull;
|
||||
|
||||
dvalues[i++] = ExecEvalExpr(e, econtext, &eisnull, NULL);
|
||||
if (eisnull)
|
||||
elog(ERROR, "Arrays cannot have NULL elements");
|
||||
}
|
||||
|
||||
/* setup for 1-D array of the given length */
|
||||
dims[0] = nelems;
|
||||
lbs[0] = 1;
|
||||
|
||||
result = construct_md_array(dvalues, ndims, dims, lbs,
|
||||
element_type,
|
||||
astate->elemlength,
|
||||
astate->elembyval,
|
||||
astate->elemalign);
|
||||
}
|
||||
else
|
||||
{
|
||||
char *dat = NULL;
|
||||
Size ndatabytes = 0;
|
||||
int nbytes;
|
||||
int outer_nelems = length(astate->elements);
|
||||
int elem_ndims = 0;
|
||||
int *elem_dims = NULL;
|
||||
int *elem_lbs = NULL;
|
||||
bool firstone = true;
|
||||
int i;
|
||||
|
||||
if (ndims <= 0 || ndims > MAXDIM)
|
||||
elog(ERROR, "Arrays cannot have more than %d dimensions", MAXDIM);
|
||||
|
||||
/* loop through and get data area from each element */
|
||||
foreach(element, astate->elements)
|
||||
{
|
||||
ExprState *e = (ExprState *) lfirst(element);
|
||||
bool eisnull;
|
||||
Datum arraydatum;
|
||||
ArrayType *array;
|
||||
int elem_ndatabytes;
|
||||
|
||||
arraydatum = ExecEvalExpr(e, econtext, &eisnull, NULL);
|
||||
if (eisnull)
|
||||
elog(ERROR, "Arrays cannot have NULL elements");
|
||||
|
||||
array = DatumGetArrayTypeP(arraydatum);
|
||||
|
||||
if (firstone)
|
||||
{
|
||||
/* Get sub-array details from first member */
|
||||
elem_ndims = ARR_NDIM(array);
|
||||
elem_dims = (int *) palloc(elem_ndims * sizeof(int));
|
||||
memcpy(elem_dims, ARR_DIMS(array), elem_ndims * sizeof(int));
|
||||
elem_lbs = (int *) palloc(elem_ndims * sizeof(int));
|
||||
memcpy(elem_lbs, ARR_LBOUND(array), elem_ndims * sizeof(int));
|
||||
firstone = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Check other sub-arrays are compatible */
|
||||
if (elem_ndims != ARR_NDIM(array))
|
||||
elog(ERROR, "Multiple dimension arrays must have array "
|
||||
"expressions with matching number of dimensions");
|
||||
|
||||
if (memcmp(elem_dims, ARR_DIMS(array),
|
||||
elem_ndims * sizeof(int)) != 0)
|
||||
elog(ERROR, "Multiple dimension arrays must have array "
|
||||
"expressions with matching dimensions");
|
||||
|
||||
if (memcmp(elem_lbs, ARR_LBOUND(array),
|
||||
elem_ndims * sizeof(int)) != 0)
|
||||
elog(ERROR, "Multiple dimension arrays must have array "
|
||||
"expressions with matching dimensions");
|
||||
}
|
||||
|
||||
elem_ndatabytes = ARR_SIZE(array) - ARR_OVERHEAD(elem_ndims);
|
||||
ndatabytes += elem_ndatabytes;
|
||||
if (dat == NULL)
|
||||
dat = (char *) palloc(ndatabytes);
|
||||
else
|
||||
dat = (char *) repalloc(dat, ndatabytes);
|
||||
|
||||
memcpy(dat + (ndatabytes - elem_ndatabytes),
|
||||
ARR_DATA_PTR(array),
|
||||
elem_ndatabytes);
|
||||
}
|
||||
|
||||
/* setup for multi-D array */
|
||||
dims[0] = outer_nelems;
|
||||
lbs[0] = 1;
|
||||
for (i = 1; i < ndims; i++)
|
||||
{
|
||||
dims[i] = elem_dims[i - 1];
|
||||
lbs[i] = elem_lbs[i - 1];
|
||||
}
|
||||
|
||||
nbytes = ndatabytes + ARR_OVERHEAD(ndims);
|
||||
result = (ArrayType *) palloc(nbytes);
|
||||
|
||||
result->size = nbytes;
|
||||
result->ndim = ndims;
|
||||
result->flags = 0;
|
||||
result->elemtype = element_type;
|
||||
memcpy(ARR_DIMS(result), dims, ndims * sizeof(int));
|
||||
memcpy(ARR_LBOUND(result), lbs, ndims * sizeof(int));
|
||||
if (ndatabytes > 0)
|
||||
memcpy(ARR_DATA_PTR(result), dat, ndatabytes);
|
||||
|
||||
if (dat != NULL)
|
||||
pfree(dat);
|
||||
}
|
||||
|
||||
return PointerGetDatum(result);
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
* ExecEvalCoalesce
|
||||
* ----------------------------------------------------------------
|
||||
@ -1908,6 +2064,11 @@ ExecEvalExpr(ExprState *expression,
|
||||
isNull,
|
||||
isDone);
|
||||
break;
|
||||
case T_ArrayExpr:
|
||||
retDatum = ExecEvalArray((ArrayExprState *) expression,
|
||||
econtext,
|
||||
isNull);
|
||||
break;
|
||||
case T_CoalesceExpr:
|
||||
retDatum = ExecEvalCoalesce((CoalesceExprState *) expression,
|
||||
econtext,
|
||||
@ -2060,6 +2221,12 @@ ExecInitExpr(Expr *node, PlanState *parent)
|
||||
astate->refexpr = ExecInitExpr(aref->refexpr, parent);
|
||||
astate->refassgnexpr = ExecInitExpr(aref->refassgnexpr,
|
||||
parent);
|
||||
/* do one-time catalog lookups for type info */
|
||||
astate->refattrlength = get_typlen(aref->refarraytype);
|
||||
get_typlenbyvalalign(aref->refelemtype,
|
||||
&astate->refelemlength,
|
||||
&astate->refelembyval,
|
||||
&astate->refelemalign);
|
||||
state = (ExprState *) astate;
|
||||
}
|
||||
break;
|
||||
@ -2174,6 +2341,30 @@ ExecInitExpr(Expr *node, PlanState *parent)
|
||||
state = (ExprState *) cstate;
|
||||
}
|
||||
break;
|
||||
case T_ArrayExpr:
|
||||
{
|
||||
ArrayExpr *arrayexpr = (ArrayExpr *) node;
|
||||
ArrayExprState *astate = makeNode(ArrayExprState);
|
||||
List *outlist = NIL;
|
||||
List *inlist;
|
||||
|
||||
foreach(inlist, arrayexpr->elements)
|
||||
{
|
||||
Expr *e = (Expr *) lfirst(inlist);
|
||||
ExprState *estate;
|
||||
|
||||
estate = ExecInitExpr(e, parent);
|
||||
outlist = lappend(outlist, estate);
|
||||
}
|
||||
astate->elements = outlist;
|
||||
/* do one-time catalog lookup for type info */
|
||||
get_typlenbyvalalign(arrayexpr->element_typeid,
|
||||
&astate->elemlength,
|
||||
&astate->elembyval,
|
||||
&astate->elemalign);
|
||||
state = (ExprState *) astate;
|
||||
}
|
||||
break;
|
||||
case T_CoalesceExpr:
|
||||
{
|
||||
CoalesceExpr *coalesceexpr = (CoalesceExpr *) node;
|
||||
|
@ -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);
|
||||
}
|
||||
|
Reference in New Issue
Block a user