Commit 9246af67 authored by Teodor Sigaev's avatar Teodor Sigaev

Allow to omit boundaries in array subscript

Allow to omiy lower or upper or both boundaries in array subscript
for selecting slice of array.

Author: YUriy Zhuravlev
parent 33bd250f
......@@ -255,6 +255,26 @@ SELECT schedule[1:2][1:1] FROM sal_emp WHERE name = 'Bill';
------------------------
{{meeting},{training}}
(1 row)
</programlisting>
Possible to skip the <literal><replaceable>lower-bound</replaceable></literal> or
<literal><replaceable>upper-bound</replaceable></literal>
for get first or last element in slice.
<programlisting>
SELECT schedule[:][:] FROM sal_emp WHERE name = 'Bill';
schedule
------------------------
{{meeting,lunch},{training,presentation}}
(1 row)
SELECT schedule[:2][2:] FROM sal_emp WHERE name = 'Bill';
schedule
------------------------
{{lunch},{presentation}}
(1 row)
</programlisting>
If any dimension is written as a slice, i.e., contains a colon, then all
......
......@@ -268,10 +268,12 @@ ExecEvalArrayRef(ArrayRefExprState *astate,
bool eisnull;
ListCell *l;
int i = 0,
j = 0;
j = 0,
indexexpr;
IntArray upper,
lower;
int *lIndex;
AnyArrayType *arrays;
array_source = ExecEvalExpr(astate->refexpr,
econtext,
......@@ -293,6 +295,7 @@ ExecEvalArrayRef(ArrayRefExprState *astate,
foreach(l, astate->refupperindexpr)
{
ExprState *eltstate = (ExprState *) lfirst(l);
eisnull = false;
if (i >= MAXDIM)
ereport(ERROR,
......@@ -300,10 +303,23 @@ ExecEvalArrayRef(ArrayRefExprState *astate,
errmsg("number of array dimensions (%d) exceeds the maximum allowed (%d)",
i + 1, MAXDIM)));
upper.indx[i++] = DatumGetInt32(ExecEvalExpr(eltstate,
if (eltstate == NULL && astate->refattrlength <= 0)
{
if (isAssignment)
ereport(ERROR,
(errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
errmsg("cannot determine upper index for empty array")));
arrays = (AnyArrayType *)DatumGetArrayTypeP(array_source);
indexexpr = AARR_LBOUND(arrays)[i] + AARR_DIMS(arrays)[i] - 1;
}
else
indexexpr = DatumGetInt32(ExecEvalExpr(eltstate,
econtext,
&eisnull,
NULL));
upper.indx[i++] = indexexpr;
/* If any index expr yields NULL, result is NULL or error */
if (eisnull)
{
......@@ -321,6 +337,7 @@ ExecEvalArrayRef(ArrayRefExprState *astate,
foreach(l, astate->reflowerindexpr)
{
ExprState *eltstate = (ExprState *) lfirst(l);
eisnull = false;
if (j >= MAXDIM)
ereport(ERROR,
......@@ -328,10 +345,19 @@ ExecEvalArrayRef(ArrayRefExprState *astate,
errmsg("number of array dimensions (%d) exceeds the maximum allowed (%d)",
j + 1, MAXDIM)));
lower.indx[j++] = DatumGetInt32(ExecEvalExpr(eltstate,
if (eltstate == NULL)
{
arrays = (AnyArrayType *)DatumGetArrayTypeP(array_source);
indexexpr = AARR_LBOUND(arrays)[j];
}
else
indexexpr = DatumGetInt32(ExecEvalExpr(eltstate,
econtext,
&eisnull,
NULL));
lower.indx[j++] = indexexpr;
/* If any index expr yields NULL, result is NULL or error */
if (eisnull)
{
......
......@@ -2403,6 +2403,8 @@ _copyAIndices(const A_Indices *from)
COPY_NODE_FIELD(lidx);
COPY_NODE_FIELD(uidx);
COPY_SCALAR_FIELD(lidx_default);
COPY_SCALAR_FIELD(uidx_default);
return newnode;
}
......
......@@ -2153,6 +2153,8 @@ _equalAIndices(const A_Indices *a, const A_Indices *b)
{
COMPARE_NODE_FIELD(lidx);
COMPARE_NODE_FIELD(uidx);
COMPARE_SCALAR_FIELD(lidx_default);
COMPARE_SCALAR_FIELD(uidx_default);
return true;
}
......
......@@ -2765,6 +2765,8 @@ _outA_Indices(StringInfo str, const A_Indices *node)
WRITE_NODE_FIELD(lidx);
WRITE_NODE_FIELD(uidx);
WRITE_BOOL_FIELD(lidx_default);
WRITE_BOOL_FIELD(uidx_default);
}
static void
......
......@@ -13193,6 +13193,35 @@ indirection_el:
A_Indices *ai = makeNode(A_Indices);
ai->lidx = NULL;
ai->uidx = $2;
ai->lidx_default = false;
ai->uidx_default = false;
$$ = (Node *) ai;
}
| '[' ':' ']'
{
A_Indices *ai = makeNode(A_Indices);
ai->lidx = NULL;
ai->uidx = NULL;
ai->lidx_default = true;
ai->uidx_default = true;
$$ = (Node *) ai;
}
| '[' ':' a_expr ']'
{
A_Indices *ai = makeNode(A_Indices);
ai->lidx = NULL;
ai->uidx = $3;
ai->lidx_default = true;
ai->uidx_default = false;
$$ = (Node *) ai;
}
| '[' a_expr ':' ']'
{
A_Indices *ai = makeNode(A_Indices);
ai->lidx = $2;
ai->uidx = NULL;
ai->lidx_default = false;
ai->uidx_default = true;
$$ = (Node *) ai;
}
| '[' a_expr ':' a_expr ']'
......@@ -13200,6 +13229,8 @@ indirection_el:
A_Indices *ai = makeNode(A_Indices);
ai->lidx = $2;
ai->uidx = $4;
ai->lidx_default = false;
ai->uidx_default = false;
$$ = (Node *) ai;
}
;
......
......@@ -311,7 +311,7 @@ transformArraySubscripts(ParseState *pstate,
elementType = transformArrayType(&arrayType, &arrayTypMod);
/*
* A list containing only single subscripts refers to a single array
* A list containing only single subscripts (uidx) refers to a single array
* element. If any of the items are double subscripts (lower:upper), then
* the subscript expression means an array slice operation. In this case,
* we supply a default lower bound of 1 for any items that contain only a
......@@ -322,7 +322,7 @@ transformArraySubscripts(ParseState *pstate,
{
A_Indices *ai = (A_Indices *) lfirst(idx);
if (ai->lidx != NULL)
if (ai->lidx != NULL || ai->lidx_default)
{
isSlice = true;
break;
......@@ -335,9 +335,17 @@ transformArraySubscripts(ParseState *pstate,
foreach(idx, indirection)
{
A_Indices *ai = (A_Indices *) lfirst(idx);
Node *subexpr;
Node *subexpr = NULL;
Assert(IsA(ai, A_Indices));
if ((ai->uidx_default || ai->lidx_default) && assignFrom != NULL)
ereport(ERROR,
(errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
errmsg("array subscript must have both boundaries"),
errhint("You can't omit the upper or lower"
" boundaries when updating or inserting"),
parser_errposition(pstate, exprLocation(arrayBase))));
if (isSlice)
{
if (ai->lidx)
......@@ -356,7 +364,7 @@ transformArraySubscripts(ParseState *pstate,
errmsg("array subscript must have type integer"),
parser_errposition(pstate, exprLocation(ai->lidx))));
}
else
else if (ai->lidx_default == false)
{
/* Make a constant 1 */
subexpr = (Node *) makeConst(INT4OID,
......@@ -369,6 +377,9 @@ transformArraySubscripts(ParseState *pstate,
}
lowerIndexpr = lappend(lowerIndexpr, subexpr);
}
if (ai->uidx_default == false)
{
subexpr = transformExpr(pstate, ai->uidx, pstate->p_expr_kind);
/* If it's not int4 already, try to coerce */
subexpr = coerce_to_target_type(pstate,
......@@ -382,6 +393,10 @@ transformArraySubscripts(ParseState *pstate,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("array subscript must have type integer"),
parser_errposition(pstate, exprLocation(ai->uidx))));
}
else
subexpr = NULL;
upperIndexpr = lappend(upperIndexpr, subexpr);
}
......
......@@ -650,7 +650,7 @@ transformAssignmentIndirection(ParseState *pstate,
if (IsA(n, A_Indices))
{
subscripts = lappend(subscripts, n);
if (((A_Indices *) n)->lidx != NULL)
if (((A_Indices *) n)->lidx != NULL || ((A_Indices *) n)->lidx_default)
isSlice = true;
}
else if (IsA(n, A_Star))
......
......@@ -358,6 +358,8 @@ typedef struct A_Indices
NodeTag type;
Node *lidx; /* NULL if it's a single subscript */
Node *uidx;
bool lidx_default;
bool uidx_default;
} A_Indices;
/*
......
......@@ -2031,3 +2031,43 @@ SELECT width_bucket(5, ARRAY[3, 4, NULL]);
ERROR: thresholds array must not contain NULLs
SELECT width_bucket(5, ARRAY[ARRAY[1, 2], ARRAY[3, 4]]);
ERROR: thresholds must be one-dimensional array
-- slices with empty lower and/or upper index
CREATE TABLE arrtest_s (
a int2[],
b int2[][]
);
INSERT INTO arrtest_s VALUES ('{1,2,3,4,5}', '{{1,2,3}, {4,5,6}, {7,8,9}}');
SELECT a[:3], b[:2][:2] FROM arrtest_s;
a | b
---------+---------------
{1,2,3} | {{1,2},{4,5}}
(1 row)
SELECT a[2:], b[2:][2:] FROM arrtest_s;
a | b
-----------+---------------
{2,3,4,5} | {{5,6},{8,9}}
(1 row)
SELECT a[:], b[:] FROM arrtest_s;
a | b
-------------+---------------------------
{1,2,3,4,5} | {{1,2,3},{4,5,6},{7,8,9}}
(1 row)
-- errors
UPDATE arrtest_s SET a[:3] = '{11, 12, 13}', b[:2][:2] = '{{11,12}, {14, 15}}';
ERROR: array subscript must have both boundaries
LINE 1: UPDATE arrtest_s SET a[:3] = '{11, 12, 13}', b[:2][:2] = '{{...
^
HINT: You can't omit the upper or lower boundaries when updating or inserting
UPDATE arrtest_s SET a[3:] = '{23, 24, 25}', b[2:][2:] = '{{25,26}, {28, 29}}';
ERROR: array subscript must have both boundaries
LINE 1: UPDATE arrtest_s SET a[3:] = '{23, 24, 25}', b[2:][2:] = '{{...
^
HINT: You can't omit the upper or lower boundaries when updating or inserting
UPDATE arrtest_s SET a[:] = '{23, 24, 25}';
ERROR: array subscript must have both boundaries
LINE 1: UPDATE arrtest_s SET a[:] = '{23, 24, 25}';
^
HINT: You can't omit the upper or lower boundaries when updating or inserting
......@@ -586,6 +586,7 @@ SELECT user_relns() AS user_relns
array_index_op_test
array_op_test
arrtest
arrtest_s
b
b_star
bb
......@@ -710,7 +711,7 @@ SELECT user_relns() AS user_relns
tvvmv
varchar_tbl
xacttest
(132 rows)
(133 rows)
SELECT name(equipment(hobby_construct(text 'skywalking', text 'mer')));
name
......
......@@ -609,3 +609,18 @@ SELECT width_bucket(5, '{}');
SELECT width_bucket('5'::text, ARRAY[3, 4]::integer[]);
SELECT width_bucket(5, ARRAY[3, 4, NULL]);
SELECT width_bucket(5, ARRAY[ARRAY[1, 2], ARRAY[3, 4]]);
-- slices with empty lower and/or upper index
CREATE TABLE arrtest_s (
a int2[],
b int2[][]
);
INSERT INTO arrtest_s VALUES ('{1,2,3,4,5}', '{{1,2,3}, {4,5,6}, {7,8,9}}');
SELECT a[:3], b[:2][:2] FROM arrtest_s;
SELECT a[2:], b[2:][2:] FROM arrtest_s;
SELECT a[:], b[:] FROM arrtest_s;
-- errors
UPDATE arrtest_s SET a[:3] = '{11, 12, 13}', b[:2][:2] = '{{11,12}, {14, 15}}';
UPDATE arrtest_s SET a[3:] = '{23, 24, 25}', b[2:][2:] = '{{25,26}, {28, 29}}';
UPDATE arrtest_s SET a[:] = '{23, 24, 25}';
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment