New patch version in attachment.
Thanks.
--
Yury Zhuravlev
Postgres Professional: http://www.postgrespro.com
The Russian Postgres Company
diff --git a/doc/src/sgml/array.sgml b/doc/src/sgml/array.sgml
index 4385a09..305cabb 100644
--- a/doc/src/sgml/array.sgml
+++ b/doc/src/sgml/array.sgml
@@ -257,6 +257,26 @@ SELECT schedule[1:2][1:1] FROM sal_emp WHERE name = 'Bill';
(1 row)
</programlisting>
+ It is possible to omit <literal><replaceable>lower-bound</replaceable></literal> or
+ <literal><replaceable>upper-bound</replaceable></literal>
+ of slice operator, since the missing bound will default to the index of the corresponding item.
+
+<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
dimensions are treated as slices. Any dimension that has only a single
number (no colon) is treated as being from 1
diff --git a/src/backend/executor/execQual.c b/src/backend/executor/execQual.c
index 29f058c..f586d57 100644
--- a/src/backend/executor/execQual.c
+++ b/src/backend/executor/execQual.c
@@ -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,29 @@ ExecEvalArrayRef(ArrayRefExprState *astate,
errmsg("number of array dimensions (%d) exceeds the maximum allowed (%d)",
i + 1, MAXDIM)));
- upper.indx[i++] = DatumGetInt32(ExecEvalExpr(eltstate,
- econtext,
- &eisnull,
- NULL));
+ if (eltstate == NULL)
+ {
+ if (isAssignment)
+ ereport(ERROR,
+ (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
+ errmsg("cannot determine upper index for empty array")));
+
+ if (astate->refattrlength > 0)
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("slices of fixed-length arrays not implemented")));
+
+ 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 +343,7 @@ ExecEvalArrayRef(ArrayRefExprState *astate,
foreach(l, astate->reflowerindexpr)
{
ExprState *eltstate = (ExprState *) lfirst(l);
+ eisnull = false;
if (j >= MAXDIM)
ereport(ERROR,
@@ -328,10 +351,19 @@ ExecEvalArrayRef(ArrayRefExprState *astate,
errmsg("number of array dimensions (%d) exceeds the maximum allowed (%d)",
j + 1, MAXDIM)));
- lower.indx[j++] = DatumGetInt32(ExecEvalExpr(eltstate,
- econtext,
- &eisnull,
- NULL));
+ 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)
{
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index 26264cb..fe848d5 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -2417,6 +2417,7 @@ _copyAIndices(const A_Indices *from)
COPY_NODE_FIELD(lidx);
COPY_NODE_FIELD(uidx);
+ COPY_SCALAR_FIELD(is_slice);
return newnode;
}
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index aa6e102..00f98ef 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -2162,6 +2162,7 @@ _equalAIndices(const A_Indices *a, const A_Indices *b)
{
COMPARE_NODE_FIELD(lidx);
COMPARE_NODE_FIELD(uidx);
+ COMPARE_SCALAR_FIELD(is_slice);
return true;
}
diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index 012c14b..5c6326d 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -2773,6 +2773,7 @@ _outA_Indices(StringInfo str, const A_Indices *node)
WRITE_NODE_FIELD(lidx);
WRITE_NODE_FIELD(uidx);
+ WRITE_BOOL_FIELD(is_slice);
}
static void
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 7916df8..4afc572 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -13191,6 +13191,31 @@ indirection_el:
A_Indices *ai = makeNode(A_Indices);
ai->lidx = NULL;
ai->uidx = $2;
+ ai->is_slice = false;
+ $$ = (Node *) ai;
+ }
+ | '[' ':' ']'
+ {
+ A_Indices *ai = makeNode(A_Indices);
+ ai->lidx = NULL;
+ ai->uidx = NULL;
+ ai->is_slice = true;
+ $$ = (Node *) ai;
+ }
+ | '[' ':' a_expr ']'
+ {
+ A_Indices *ai = makeNode(A_Indices);
+ ai->lidx = NULL;
+ ai->uidx = $3;
+ ai->is_slice = true;
+ $$ = (Node *) ai;
+ }
+ | '[' a_expr ':' ']'
+ {
+ A_Indices *ai = makeNode(A_Indices);
+ ai->lidx = $2;
+ ai->uidx = NULL;
+ ai->is_slice = true;
$$ = (Node *) ai;
}
| '[' a_expr ':' a_expr ']'
@@ -13198,6 +13223,7 @@ indirection_el:
A_Indices *ai = makeNode(A_Indices);
ai->lidx = $2;
ai->uidx = $4;
+ ai->is_slice = true;
$$ = (Node *) ai;
}
;
diff --git a/src/backend/parser/parse_node.c b/src/backend/parser/parse_node.c
index 4130cbf..b02bdc2 100644
--- a/src/backend/parser/parse_node.c
+++ b/src/backend/parser/parse_node.c
@@ -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->is_slice)
{
isSlice = true;
break;
@@ -335,9 +335,19 @@ 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->is_slice
+ && (ai->lidx == NULL || ai->uidx == NULL)
+ && 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)
@@ -354,34 +364,30 @@ transformArraySubscripts(ParseState *pstate,
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("array subscript must have type integer"),
- parser_errposition(pstate, exprLocation(ai->lidx))));
+ parser_errposition(pstate, exprLocation(ai->lidx))));
}
else
- {
- /* Make a constant 1 */
- subexpr = (Node *) makeConst(INT4OID,
- -1,
- InvalidOid,
- sizeof(int32),
- Int32GetDatum(1),
- false,
- true); /* pass by value */
- }
+ subexpr = NULL;
lowerIndexpr = lappend(lowerIndexpr, subexpr);
}
- subexpr = transformExpr(pstate, ai->uidx, pstate->p_expr_kind);
- /* If it's not int4 already, try to coerce */
- subexpr = coerce_to_target_type(pstate,
- subexpr, exprType(subexpr),
- INT4OID, -1,
- COERCION_ASSIGNMENT,
- COERCE_IMPLICIT_CAST,
- -1);
- if (subexpr == NULL)
- ereport(ERROR,
- (errcode(ERRCODE_DATATYPE_MISMATCH),
- errmsg("array subscript must have type integer"),
- parser_errposition(pstate, exprLocation(ai->uidx))));
+ if (ai->is_slice && ai->uidx == NULL)
+ subexpr = NULL;
+ else
+ {
+ subexpr = transformExpr(pstate, ai->uidx, pstate->p_expr_kind);
+ /* If it's not int4 already, try to coerce */
+ subexpr = coerce_to_target_type(pstate,
+ subexpr, exprType(subexpr),
+ INT4OID, -1,
+ COERCION_ASSIGNMENT,
+ COERCE_IMPLICIT_CAST,
+ -1);
+ if (subexpr == NULL)
+ ereport(ERROR,
+ (errcode(ERRCODE_DATATYPE_MISMATCH),
+ errmsg("array subscript must have type integer"),
+ parser_errposition(pstate, exprLocation(ai->uidx))));
+ }
upperIndexpr = lappend(upperIndexpr, subexpr);
}
diff --git a/src/backend/parser/parse_target.c b/src/backend/parser/parse_target.c
index 1b3fcd6..8c2c38d 100644
--- a/src/backend/parser/parse_target.c
+++ b/src/backend/parser/parse_target.c
@@ -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)->is_slice)
isSlice = true;
}
else if (IsA(n, A_Star))
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index 9142e94..a8c12bc 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -357,7 +357,8 @@ typedef struct A_Indices
{
NodeTag type;
Node *lidx; /* NULL if it's a single subscript */
- Node *uidx;
+ Node *uidx; /* upper bound */
+ bool is_slice; /* true if slice bounds */
} A_Indices;
/*
diff --git a/src/test/regress/expected/arrays.out b/src/test/regress/expected/arrays.out
index 73fb5a2..3084fe0 100644
--- a/src/test/regress/expected/arrays.out
+++ b/src/test/regress/expected/arrays.out
@@ -2031,3 +2031,59 @@ 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
+-- access to fixed-lenght arrays
+CREATE TEMP TABLE POINT_TBL(f1 point);
+INSERT INTO POINT_TBL(f1) VALUES ('(0.0,0.0)');
+SELECT f1[0] FROM POINT_TBL;
+ f1
+----
+ 0
+(1 row)
+
+-- errors
+SELECT f1[0:1] FROM POINT_TBL;
+ERROR: slices of fixed-length arrays not implemented
+SELECT f1[0:] FROM POINT_TBL;
+ERROR: slices of fixed-length arrays not implemented
+SELECT f1[:1] FROM POINT_TBL;
+ERROR: slices of fixed-length arrays not implemented
diff --git a/src/test/regress/output/misc.source b/src/test/regress/output/misc.source
index 5f263f9..155972b 100644
--- a/src/test/regress/output/misc.source
+++ b/src/test/regress/output/misc.source
@@ -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
diff --git a/src/test/regress/sql/arrays.sql b/src/test/regress/sql/arrays.sql
index b1dd651..b5fa7a3 100644
--- a/src/test/regress/sql/arrays.sql
+++ b/src/test/regress/sql/arrays.sql
@@ -609,3 +609,28 @@ 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}';
+
+-- access to fixed-lenght arrays
+CREATE TEMP TABLE POINT_TBL(f1 point);
+INSERT INTO POINT_TBL(f1) VALUES ('(0.0,0.0)');
+SELECT f1[0] FROM POINT_TBL;
+
+-- errors
+SELECT f1[0:1] FROM POINT_TBL;
+SELECT f1[0:] FROM POINT_TBL;
+SELECT f1[:1] FROM POINT_TBL;
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers