Skip to content

Commit 730840c

Browse files
committed
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.
1 parent 6fb5115 commit 730840c

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+2597
-479
lines changed

src/backend/catalog/pg_proc.c

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $Header: /cvsroot/pgsql/src/backend/catalog/pg_proc.c,v 1.95 2002/12/12 15:49:24 tgl Exp $
11+
* $Header: /cvsroot/pgsql/src/backend/catalog/pg_proc.c,v 1.96 2003/04/08 23:20:00 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -86,6 +86,29 @@ ProcedureCreate(const char *procedureName,
8686
elog(ERROR, "functions cannot have more than %d arguments",
8787
FUNC_MAX_ARGS);
8888

89+
/*
90+
* Do not allow return type ANYARRAY or ANYELEMENT unless at least one
91+
* argument is also ANYARRAY or ANYELEMENT
92+
*/
93+
if (returnType == ANYARRAYOID || returnType == ANYELEMENTOID)
94+
{
95+
bool genericParam = false;
96+
97+
for (i = 0; i < parameterCount; i++)
98+
{
99+
if (parameterTypes[i] == ANYARRAYOID ||
100+
parameterTypes[i] == ANYELEMENTOID)
101+
{
102+
genericParam = true;
103+
break;
104+
}
105+
}
106+
107+
if (!genericParam)
108+
elog(ERROR, "functions returning ANYARRAY or ANYELEMENT must " \
109+
"have at least one argument of either type");
110+
}
111+
89112
/* Make sure we have a zero-padded param type array */
90113
MemSet(typev, 0, FUNC_MAX_ARGS * sizeof(Oid));
91114
if (parameterCount > 0)

src/backend/executor/execQual.c

Lines changed: 208 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.127 2003/03/27 16:51:27 momjian Exp $
11+
* $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.128 2003/04/08 23:20:00 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -75,6 +75,9 @@ static Datum ExecEvalAnd(BoolExprState *andExpr, ExprContext *econtext,
7575
bool *isNull);
7676
static Datum ExecEvalCase(CaseExprState *caseExpr, ExprContext *econtext,
7777
bool *isNull, ExprDoneCond *isDone);
78+
static Datum ExecEvalArray(ArrayExprState *astate,
79+
ExprContext *econtext,
80+
bool *isNull);
7881
static Datum ExecEvalCoalesce(CoalesceExprState *coalesceExpr,
7982
ExprContext *econtext,
8083
bool *isNull);
@@ -246,38 +249,38 @@ ExecEvalArrayRef(ArrayRefExprState *astate,
246249
resultArray = array_set(array_source, i,
247250
upper.indx,
248251
sourceData,
249-
arrayRef->refattrlength,
250-
arrayRef->refelemlength,
251-
arrayRef->refelembyval,
252-
arrayRef->refelemalign,
252+
astate->refattrlength,
253+
astate->refelemlength,
254+
astate->refelembyval,
255+
astate->refelemalign,
253256
isNull);
254257
else
255258
resultArray = array_set_slice(array_source, i,
256259
upper.indx, lower.indx,
257260
(ArrayType *) DatumGetPointer(sourceData),
258-
arrayRef->refattrlength,
259-
arrayRef->refelemlength,
260-
arrayRef->refelembyval,
261-
arrayRef->refelemalign,
261+
astate->refattrlength,
262+
astate->refelemlength,
263+
astate->refelembyval,
264+
astate->refelemalign,
262265
isNull);
263266
return PointerGetDatum(resultArray);
264267
}
265268

266269
if (lIndex == NULL)
267270
return array_ref(array_source, i, upper.indx,
268-
arrayRef->refattrlength,
269-
arrayRef->refelemlength,
270-
arrayRef->refelembyval,
271-
arrayRef->refelemalign,
271+
astate->refattrlength,
272+
astate->refelemlength,
273+
astate->refelembyval,
274+
astate->refelemalign,
272275
isNull);
273276
else
274277
{
275278
resultArray = array_get_slice(array_source, i,
276279
upper.indx, lower.indx,
277-
arrayRef->refattrlength,
278-
arrayRef->refelemlength,
279-
arrayRef->refelembyval,
280-
arrayRef->refelemalign,
280+
astate->refattrlength,
281+
astate->refelemlength,
282+
astate->refelembyval,
283+
astate->refelemalign,
281284
isNull);
282285
return PointerGetDatum(resultArray);
283286
}
@@ -613,6 +616,7 @@ init_fcache(Oid foid, FuncExprState *fcache, MemoryContext fcacheCxt)
613616

614617
/* Initialize additional info */
615618
fcache->setArgsValid = false;
619+
fcache->func.fn_expr = (Node *) fcache->xprstate.expr;
616620
}
617621

618622
/*
@@ -1426,6 +1430,158 @@ ExecEvalCase(CaseExprState *caseExpr, ExprContext *econtext,
14261430
return (Datum) 0;
14271431
}
14281432

1433+
/* ----------------------------------------------------------------
1434+
* ExecEvalArray - ARRAY[] expressions
1435+
* ----------------------------------------------------------------
1436+
*/
1437+
static Datum
1438+
ExecEvalArray(ArrayExprState *astate, ExprContext *econtext,
1439+
bool *isNull)
1440+
{
1441+
ArrayExpr *arrayExpr = (ArrayExpr *) astate->xprstate.expr;
1442+
ArrayType *result;
1443+
List *element;
1444+
Oid element_type = arrayExpr->element_typeid;
1445+
int ndims = arrayExpr->ndims;
1446+
int dims[MAXDIM];
1447+
int lbs[MAXDIM];
1448+
1449+
if (ndims == 1)
1450+
{
1451+
int nelems;
1452+
Datum *dvalues;
1453+
int i = 0;
1454+
1455+
nelems = length(astate->elements);
1456+
1457+
/* Shouldn't happen here, but if length is 0, return NULL */
1458+
if (nelems == 0)
1459+
{
1460+
*isNull = true;
1461+
return (Datum) 0;
1462+
}
1463+
1464+
dvalues = (Datum *) palloc(nelems * sizeof(Datum));
1465+
1466+
/* loop through and build array of datums */
1467+
foreach(element, astate->elements)
1468+
{
1469+
ExprState *e = (ExprState *) lfirst(element);
1470+
bool eisnull;
1471+
1472+
dvalues[i++] = ExecEvalExpr(e, econtext, &eisnull, NULL);
1473+
if (eisnull)
1474+
elog(ERROR, "Arrays cannot have NULL elements");
1475+
}
1476+
1477+
/* setup for 1-D array of the given length */
1478+
dims[0] = nelems;
1479+
lbs[0] = 1;
1480+
1481+
result = construct_md_array(dvalues, ndims, dims, lbs,
1482+
element_type,
1483+
astate->elemlength,
1484+
astate->elembyval,
1485+
astate->elemalign);
1486+
}
1487+
else
1488+
{
1489+
char *dat = NULL;
1490+
Size ndatabytes = 0;
1491+
int nbytes;
1492+
int outer_nelems = length(astate->elements);
1493+
int elem_ndims = 0;
1494+
int *elem_dims = NULL;
1495+
int *elem_lbs = NULL;
1496+
bool firstone = true;
1497+
int i;
1498+
1499+
if (ndims <= 0 || ndims > MAXDIM)
1500+
elog(ERROR, "Arrays cannot have more than %d dimensions", MAXDIM);
1501+
1502+
/* loop through and get data area from each element */
1503+
foreach(element, astate->elements)
1504+
{
1505+
ExprState *e = (ExprState *) lfirst(element);
1506+
bool eisnull;
1507+
Datum arraydatum;
1508+
ArrayType *array;
1509+
int elem_ndatabytes;
1510+
1511+
arraydatum = ExecEvalExpr(e, econtext, &eisnull, NULL);
1512+
if (eisnull)
1513+
elog(ERROR, "Arrays cannot have NULL elements");
1514+
1515+
array = DatumGetArrayTypeP(arraydatum);
1516+
1517+
if (firstone)
1518+
{
1519+
/* Get sub-array details from first member */
1520+
elem_ndims = ARR_NDIM(array);
1521+
elem_dims = (int *) palloc(elem_ndims * sizeof(int));
1522+
memcpy(elem_dims, ARR_DIMS(array), elem_ndims * sizeof(int));
1523+
elem_lbs = (int *) palloc(elem_ndims * sizeof(int));
1524+
memcpy(elem_lbs, ARR_LBOUND(array), elem_ndims * sizeof(int));
1525+
firstone = false;
1526+
}
1527+
else
1528+
{
1529+
/* Check other sub-arrays are compatible */
1530+
if (elem_ndims != ARR_NDIM(array))
1531+
elog(ERROR, "Multiple dimension arrays must have array "
1532+
"expressions with matching number of dimensions");
1533+
1534+
if (memcmp(elem_dims, ARR_DIMS(array),
1535+
elem_ndims * sizeof(int)) != 0)
1536+
elog(ERROR, "Multiple dimension arrays must have array "
1537+
"expressions with matching dimensions");
1538+
1539+
if (memcmp(elem_lbs, ARR_LBOUND(array),
1540+
elem_ndims * sizeof(int)) != 0)
1541+
elog(ERROR, "Multiple dimension arrays must have array "
1542+
"expressions with matching dimensions");
1543+
}
1544+
1545+
elem_ndatabytes = ARR_SIZE(array) - ARR_OVERHEAD(elem_ndims);
1546+
ndatabytes += elem_ndatabytes;
1547+
if (dat == NULL)
1548+
dat = (char *) palloc(ndatabytes);
1549+
else
1550+
dat = (char *) repalloc(dat, ndatabytes);
1551+
1552+
memcpy(dat + (ndatabytes - elem_ndatabytes),
1553+
ARR_DATA_PTR(array),
1554+
elem_ndatabytes);
1555+
}
1556+
1557+
/* setup for multi-D array */
1558+
dims[0] = outer_nelems;
1559+
lbs[0] = 1;
1560+
for (i = 1; i < ndims; i++)
1561+
{
1562+
dims[i] = elem_dims[i - 1];
1563+
lbs[i] = elem_lbs[i - 1];
1564+
}
1565+
1566+
nbytes = ndatabytes + ARR_OVERHEAD(ndims);
1567+
result = (ArrayType *) palloc(nbytes);
1568+
1569+
result->size = nbytes;
1570+
result->ndim = ndims;
1571+
result->flags = 0;
1572+
result->elemtype = element_type;
1573+
memcpy(ARR_DIMS(result), dims, ndims * sizeof(int));
1574+
memcpy(ARR_LBOUND(result), lbs, ndims * sizeof(int));
1575+
if (ndatabytes > 0)
1576+
memcpy(ARR_DATA_PTR(result), dat, ndatabytes);
1577+
1578+
if (dat != NULL)
1579+
pfree(dat);
1580+
}
1581+
1582+
return PointerGetDatum(result);
1583+
}
1584+
14291585
/* ----------------------------------------------------------------
14301586
* ExecEvalCoalesce
14311587
* ----------------------------------------------------------------
@@ -1908,6 +2064,11 @@ ExecEvalExpr(ExprState *expression,
19082064
isNull,
19092065
isDone);
19102066
break;
2067+
case T_ArrayExpr:
2068+
retDatum = ExecEvalArray((ArrayExprState *) expression,
2069+
econtext,
2070+
isNull);
2071+
break;
19112072
case T_CoalesceExpr:
19122073
retDatum = ExecEvalCoalesce((CoalesceExprState *) expression,
19132074
econtext,
@@ -2060,6 +2221,12 @@ ExecInitExpr(Expr *node, PlanState *parent)
20602221
astate->refexpr = ExecInitExpr(aref->refexpr, parent);
20612222
astate->refassgnexpr = ExecInitExpr(aref->refassgnexpr,
20622223
parent);
2224+
/* do one-time catalog lookups for type info */
2225+
astate->refattrlength = get_typlen(aref->refarraytype);
2226+
get_typlenbyvalalign(aref->refelemtype,
2227+
&astate->refelemlength,
2228+
&astate->refelembyval,
2229+
&astate->refelemalign);
20632230
state = (ExprState *) astate;
20642231
}
20652232
break;
@@ -2174,6 +2341,30 @@ ExecInitExpr(Expr *node, PlanState *parent)
21742341
state = (ExprState *) cstate;
21752342
}
21762343
break;
2344+
case T_ArrayExpr:
2345+
{
2346+
ArrayExpr *arrayexpr = (ArrayExpr *) node;
2347+
ArrayExprState *astate = makeNode(ArrayExprState);
2348+
List *outlist = NIL;
2349+
List *inlist;
2350+
2351+
foreach(inlist, arrayexpr->elements)
2352+
{
2353+
Expr *e = (Expr *) lfirst(inlist);
2354+
ExprState *estate;
2355+
2356+
estate = ExecInitExpr(e, parent);
2357+
outlist = lappend(outlist, estate);
2358+
}
2359+
astate->elements = outlist;
2360+
/* do one-time catalog lookup for type info */
2361+
get_typlenbyvalalign(arrayexpr->element_typeid,
2362+
&astate->elemlength,
2363+
&astate->elembyval,
2364+
&astate->elemalign);
2365+
state = (ExprState *) astate;
2366+
}
2367+
break;
21772368
case T_CoalesceExpr:
21782369
{
21792370
CoalesceExpr *coalesceexpr = (CoalesceExpr *) node;

0 commit comments

Comments
 (0)