diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2015-12-22 21:05:16 -0500 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2015-12-22 21:05:29 -0500 |
commit | 6efbded6e4672c597a6f0dc0f09263e7db7369ff (patch) | |
tree | 2ee78e250058cdbc4021f24c6ae0bf4e92098c4b /src | |
parent | 0ba3f3bc65f1176250b942e14fd9e4975a5d3913 (diff) | |
download | postgresql-6efbded6e4672c597a6f0dc0f09263e7db7369ff.tar.gz postgresql-6efbded6e4672c597a6f0dc0f09263e7db7369ff.zip |
Allow omitting one or both boundaries in an array slice specifier.
Omitted boundaries represent the upper or lower limit of the corresponding
array subscript. This allows simpler specification of many common
use-cases.
(Revised version of commit 9246af6799819847faa33baf441251003acbb8fe)
YUriy Zhuravlev
Diffstat (limited to 'src')
-rw-r--r-- | src/backend/executor/execQual.c | 22 | ||||
-rw-r--r-- | src/backend/nodes/copyfuncs.c | 1 | ||||
-rw-r--r-- | src/backend/nodes/equalfuncs.c | 1 | ||||
-rw-r--r-- | src/backend/nodes/outfuncs.c | 1 | ||||
-rw-r--r-- | src/backend/parser/gram.y | 11 | ||||
-rw-r--r-- | src/backend/parser/parse_node.c | 59 | ||||
-rw-r--r-- | src/backend/parser/parse_target.c | 2 | ||||
-rw-r--r-- | src/backend/utils/adt/arrayfuncs.c | 33 | ||||
-rw-r--r-- | src/backend/utils/adt/ruleutils.c | 2 | ||||
-rw-r--r-- | src/include/nodes/parsenodes.h | 17 | ||||
-rw-r--r-- | src/include/nodes/primnodes.h | 5 | ||||
-rw-r--r-- | src/include/utils/array.h | 2 | ||||
-rw-r--r-- | src/test/regress/expected/arrays.out | 111 | ||||
-rw-r--r-- | src/test/regress/sql/arrays.sql | 41 |
14 files changed, 275 insertions, 33 deletions
diff --git a/src/backend/executor/execQual.c b/src/backend/executor/execQual.c index 29f058ce5cb..d4dc2dcd21a 100644 --- a/src/backend/executor/execQual.c +++ b/src/backend/executor/execQual.c @@ -271,6 +271,8 @@ ExecEvalArrayRef(ArrayRefExprState *astate, j = 0; IntArray upper, lower; + bool upperProvided[MAXDIM], + lowerProvided[MAXDIM]; int *lIndex; array_source = ExecEvalExpr(astate->refexpr, @@ -300,6 +302,15 @@ ExecEvalArrayRef(ArrayRefExprState *astate, errmsg("number of array dimensions (%d) exceeds the maximum allowed (%d)", i + 1, MAXDIM))); + if (eltstate == NULL) + { + /* Slice bound is omitted, so use array's upper bound */ + Assert(astate->reflowerindexpr != NIL); + upperProvided[i++] = false; + continue; + } + upperProvided[i] = true; + upper.indx[i++] = DatumGetInt32(ExecEvalExpr(eltstate, econtext, &eisnull, @@ -328,6 +339,14 @@ ExecEvalArrayRef(ArrayRefExprState *astate, errmsg("number of array dimensions (%d) exceeds the maximum allowed (%d)", j + 1, MAXDIM))); + if (eltstate == NULL) + { + /* Slice bound is omitted, so use array's lower bound */ + lowerProvided[j++] = false; + continue; + } + lowerProvided[j] = true; + lower.indx[j++] = DatumGetInt32(ExecEvalExpr(eltstate, econtext, &eisnull, @@ -398,6 +417,7 @@ ExecEvalArrayRef(ArrayRefExprState *astate, econtext->caseValue_datum = array_get_slice(array_source, i, upper.indx, lower.indx, + upperProvided, lowerProvided, astate->refattrlength, astate->refelemlength, astate->refelembyval, @@ -456,6 +476,7 @@ ExecEvalArrayRef(ArrayRefExprState *astate, else return array_set_slice(array_source, i, upper.indx, lower.indx, + upperProvided, lowerProvided, sourceData, eisnull, astate->refattrlength, @@ -475,6 +496,7 @@ ExecEvalArrayRef(ArrayRefExprState *astate, else return array_get_slice(array_source, i, upper.indx, lower.indx, + upperProvided, lowerProvided, astate->refattrlength, astate->refelemlength, astate->refelembyval, diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c index ba04b7227ca..4cf14b6f71f 100644 --- a/src/backend/nodes/copyfuncs.c +++ b/src/backend/nodes/copyfuncs.c @@ -2401,6 +2401,7 @@ _copyAIndices(const A_Indices *from) { A_Indices *newnode = makeNode(A_Indices); + COPY_SCALAR_FIELD(is_slice); COPY_NODE_FIELD(lidx); COPY_NODE_FIELD(uidx); diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c index 356fcafeb49..a13d83181b9 100644 --- a/src/backend/nodes/equalfuncs.c +++ b/src/backend/nodes/equalfuncs.c @@ -2151,6 +2151,7 @@ _equalAStar(const A_Star *a, const A_Star *b) static bool _equalAIndices(const A_Indices *a, const A_Indices *b) { + COMPARE_SCALAR_FIELD(is_slice); COMPARE_NODE_FIELD(lidx); COMPARE_NODE_FIELD(uidx); diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c index 63fae82aba0..fe2c643c348 100644 --- a/src/backend/nodes/outfuncs.c +++ b/src/backend/nodes/outfuncs.c @@ -2763,6 +2763,7 @@ _outA_Indices(StringInfo str, const A_Indices *node) { WRITE_NODE_TYPE("A_INDICES"); + WRITE_BOOL_FIELD(is_slice); WRITE_NODE_FIELD(lidx); WRITE_NODE_FIELD(uidx); } diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index c4bed8a5ef7..223ef175dee 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -434,7 +434,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); %type <node> columnDef columnOptions %type <defelt> def_elem reloption_elem old_aggr_elem operator_def_elem %type <node> def_arg columnElem where_clause where_or_current_clause - a_expr b_expr c_expr AexprConst indirection_el + a_expr b_expr c_expr AexprConst indirection_el opt_slice_bound columnref in_expr having_clause func_table array_expr ExclusionWhereClause %type <list> rowsfrom_item rowsfrom_list opt_col_def_list @@ -13191,19 +13191,26 @@ indirection_el: | '[' a_expr ']' { A_Indices *ai = makeNode(A_Indices); + ai->is_slice = false; ai->lidx = NULL; ai->uidx = $2; $$ = (Node *) ai; } - | '[' a_expr ':' a_expr ']' + | '[' opt_slice_bound ':' opt_slice_bound ']' { A_Indices *ai = makeNode(A_Indices); + ai->is_slice = true; ai->lidx = $2; ai->uidx = $4; $$ = (Node *) ai; } ; +opt_slice_bound: + a_expr { $$ = $1; } + | /*EMPTY*/ { $$ = NULL; } + ; + indirection: indirection_el { $$ = list_make1($1); } | indirection indirection_el { $$ = lappend($1, $2); } diff --git a/src/backend/parser/parse_node.c b/src/backend/parser/parse_node.c index 4130cbff5ed..591a1f3a681 100644 --- a/src/backend/parser/parse_node.c +++ b/src/backend/parser/parse_node.c @@ -311,18 +311,18 @@ transformArraySubscripts(ParseState *pstate, elementType = transformArrayType(&arrayType, &arrayTypMod); /* - * A list containing only single subscripts 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 - * single subscript. We have to prescan the indirection list to see if - * there are any double subscripts. + * A list containing only simple subscripts refers to a single array + * element. If any of the items are slice specifiers (lower:upper), then + * the subscript expression means an array slice operation. In this case, + * we convert any non-slice items to slices by treating the single + * subscript as the upper bound and supplying an assumed lower bound of 1. + * We have to prescan the list to see if there are any slice items. */ foreach(idx, indirection) { A_Indices *ai = (A_Indices *) lfirst(idx); - if (ai->lidx != NULL) + if (ai->is_slice) { isSlice = true; break; @@ -356,7 +356,7 @@ transformArraySubscripts(ParseState *pstate, errmsg("array subscript must have type integer"), parser_errposition(pstate, exprLocation(ai->lidx)))); } - else + else if (!ai->is_slice) { /* Make a constant 1 */ subexpr = (Node *) makeConst(INT4OID, @@ -367,21 +367,38 @@ transformArraySubscripts(ParseState *pstate, false, true); /* pass by value */ } + else + { + /* Slice with omitted lower bound, put NULL into the list */ + 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)))); + else + Assert(ai->lidx == NULL && !ai->is_slice); + + if (ai->uidx) + { + 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)))); + } + else + { + /* Slice with omitted upper bound, put NULL into the list */ + Assert(isSlice && ai->is_slice); + subexpr = NULL; + } upperIndexpr = lappend(upperIndexpr, subexpr); } diff --git a/src/backend/parser/parse_target.c b/src/backend/parser/parse_target.c index 1b3fcd629c1..8c2c38dbe67 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/backend/utils/adt/arrayfuncs.c b/src/backend/utils/adt/arrayfuncs.c index 67c9b357c85..359fb1462bc 100644 --- a/src/backend/utils/adt/arrayfuncs.c +++ b/src/backend/utils/adt/arrayfuncs.c @@ -1995,6 +1995,8 @@ array_get_element_expanded(Datum arraydatum, * nSubscripts: number of subscripts supplied (must be same for upper/lower) * upperIndx[]: the upper subscript values * lowerIndx[]: the lower subscript values + * upperProvided[]: true for provided upper subscript values + * lowerProvided[]: true for provided lower subscript values * arraytyplen: pg_type.typlen for the array type * elmlen: pg_type.typlen for the array's element type * elmbyval: pg_type.typbyval for the array's element type @@ -2003,6 +2005,9 @@ array_get_element_expanded(Datum arraydatum, * Outputs: * The return value is the new array Datum (it's never NULL) * + * Omitted upper and lower subscript values are replaced by the corresponding + * array bound. + * * NOTE: we assume it is OK to scribble on the provided subscript arrays * lowerIndx[] and upperIndx[]. These are generally just temporaries. */ @@ -2011,6 +2016,8 @@ array_get_slice(Datum arraydatum, int nSubscripts, int *upperIndx, int *lowerIndx, + bool *upperProvided, + bool *lowerProvided, int arraytyplen, int elmlen, bool elmbyval, @@ -2081,9 +2088,9 @@ array_get_slice(Datum arraydatum, for (i = 0; i < nSubscripts; i++) { - if (lowerIndx[i] < lb[i]) + if (!lowerProvided[i] || lowerIndx[i] < lb[i]) lowerIndx[i] = lb[i]; - if (upperIndx[i] >= (dim[i] + lb[i])) + if (!upperProvided[i] || upperIndx[i] >= (dim[i] + lb[i])) upperIndx[i] = dim[i] + lb[i] - 1; if (lowerIndx[i] > upperIndx[i]) return PointerGetDatum(construct_empty_array(elemtype)); @@ -2708,6 +2715,8 @@ array_set_element_expanded(Datum arraydatum, * nSubscripts: number of subscripts supplied (must be same for upper/lower) * upperIndx[]: the upper subscript values * lowerIndx[]: the lower subscript values + * upperProvided[]: true for provided upper subscript values + * lowerProvided[]: true for provided lower subscript values * srcArrayDatum: the source for the inserted values * isNull: indicates whether srcArrayDatum is NULL * arraytyplen: pg_type.typlen for the array type @@ -2719,6 +2728,9 @@ array_set_element_expanded(Datum arraydatum, * A new array is returned, just like the old except for the * modified range. The original array object is not changed. * + * Omitted upper and lower subscript values are replaced by the corresponding + * array bound. + * * For one-dimensional arrays only, we allow the array to be extended * by assigning to positions outside the existing subscript range; any * positions between the existing elements and the new ones are set to NULLs. @@ -2735,6 +2747,8 @@ array_set_slice(Datum arraydatum, int nSubscripts, int *upperIndx, int *lowerIndx, + bool *upperProvided, + bool *lowerProvided, Datum srcArrayDatum, bool isNull, int arraytyplen, @@ -2806,6 +2820,13 @@ array_set_slice(Datum arraydatum, for (i = 0; i < nSubscripts; i++) { + if (!upperProvided[i] || !lowerProvided[i]) + ereport(ERROR, + (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), + errmsg("array slice subscript must provide both boundaries"), + errdetail("When assigning to a slice of an empty array value," + " slice boundaries must be fully specified."))); + dim[i] = 1 + upperIndx[i] - lowerIndx[i]; lb[i] = lowerIndx[i]; } @@ -2839,6 +2860,10 @@ array_set_slice(Datum arraydatum, if (ndim == 1) { Assert(nSubscripts == 1); + if (!lowerProvided[0]) + lowerIndx[0] = lb[0]; + if (!upperProvided[0]) + upperIndx[0] = dim[0] + lb[0] - 1; if (lowerIndx[0] > upperIndx[0]) ereport(ERROR, (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), @@ -2867,6 +2892,10 @@ array_set_slice(Datum arraydatum, */ for (i = 0; i < nSubscripts; i++) { + if (!lowerProvided[i]) + lowerIndx[i] = lb[i]; + if (!upperProvided[i]) + upperIndx[i] = dim[i] + lb[i] - 1; if (lowerIndx[i] > upperIndx[i]) ereport(ERROR, (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c index 0ab839dc736..280808ae4f9 100644 --- a/src/backend/utils/adt/ruleutils.c +++ b/src/backend/utils/adt/ruleutils.c @@ -9372,10 +9372,12 @@ printSubscripts(ArrayRef *aref, deparse_context *context) appendStringInfoChar(buf, '['); if (lowlist_item) { + /* If subexpression is NULL, get_rule_expr prints nothing */ get_rule_expr((Node *) lfirst(lowlist_item), context, false); appendStringInfoChar(buf, ':'); lowlist_item = lnext(lowlist_item); } + /* If subexpression is NULL, get_rule_expr prints nothing */ get_rule_expr((Node *) lfirst(uplist_item), context, false); appendStringInfoChar(buf, ']'); } diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h index 9142e94b070..abd4dd166cc 100644 --- a/src/include/nodes/parsenodes.h +++ b/src/include/nodes/parsenodes.h @@ -157,9 +157,10 @@ typedef struct Query List *constraintDeps; /* a list of pg_constraint OIDs that the query * depends on to be semantically valid */ - List *withCheckOptions; /* a list of WithCheckOption's, which are - * only added during rewrite and therefore - * are not written out as part of Query. */ + List *withCheckOptions; /* a list of WithCheckOption's, which + * are only added during rewrite and + * therefore are not written out as + * part of Query. */ } Query; @@ -351,13 +352,17 @@ typedef struct A_Star } A_Star; /* - * A_Indices - array subscript or slice bounds ([lidx:uidx] or [uidx]) + * A_Indices - array subscript or slice bounds ([idx] or [lidx:uidx]) + * + * In slice case, either or both of lidx and uidx can be NULL (omitted). + * In non-slice case, uidx holds the single subscript and lidx is always NULL. */ typedef struct A_Indices { NodeTag type; - Node *lidx; /* NULL if it's a single subscript */ - Node *uidx; + bool is_slice; /* true if slice (i.e., colon present) */ + Node *lidx; /* slice lower bound, if any */ + Node *uidx; /* subscript, or slice upper bound if any */ } A_Indices; /* diff --git a/src/include/nodes/primnodes.h b/src/include/nodes/primnodes.h index 60c1ca2c8dc..4dbcc10e337 100644 --- a/src/include/nodes/primnodes.h +++ b/src/include/nodes/primnodes.h @@ -341,6 +341,9 @@ typedef struct WindowFunc * reflowerindexpr must be the same length as refupperindexpr when it * is not NIL. * + * In the slice case, individual expressions in the subscript lists can be + * NULL, meaning "substitute the array's current lower or upper bound". + * * Note: the result datatype is the element type when fetching a single * element; but it is the array type when doing subarray fetch or either * type of store. @@ -360,7 +363,7 @@ typedef struct ArrayRef List *refupperindexpr;/* expressions that evaluate to upper array * indexes */ List *reflowerindexpr;/* expressions that evaluate to lower array - * indexes */ + * indexes, or NIL for single array element */ Expr *refexpr; /* the expression that evaluates to an array * value */ Expr *refassgnexpr; /* expression for the source value, or NULL if diff --git a/src/include/utils/array.h b/src/include/utils/array.h index c25b80d272a..716e75637b0 100644 --- a/src/include/utils/array.h +++ b/src/include/utils/array.h @@ -377,9 +377,11 @@ extern Datum array_set_element(Datum arraydatum, int nSubscripts, int *indx, int arraytyplen, int elmlen, bool elmbyval, char elmalign); extern Datum array_get_slice(Datum arraydatum, int nSubscripts, int *upperIndx, int *lowerIndx, + bool *upperProvided, bool *lowerProvided, int arraytyplen, int elmlen, bool elmbyval, char elmalign); extern Datum array_set_slice(Datum arraydatum, int nSubscripts, int *upperIndx, int *lowerIndx, + bool *upperProvided, bool *lowerProvided, Datum srcArrayDatum, bool isNull, int arraytyplen, int elmlen, bool elmbyval, char elmalign); diff --git a/src/test/regress/expected/arrays.out b/src/test/regress/expected/arrays.out index 73fb5a248b4..baccca14afd 100644 --- a/src/test/regress/expected/arrays.out +++ b/src/test/regress/expected/arrays.out @@ -125,6 +125,16 @@ SELECT a[1:3], {16,25,23} | {} | {foobar,new_word} | {{elt2}} (3 rows) +SELECT b[1:1][2][2], + d[1:1][2] + FROM arrtest; + b | d +-----------------------+--------------- + {{{113,142},{1,147}}} | {} + {} | {} + {} | {{elt1,elt2}} +(3 rows) + INSERT INTO arrtest(a) VALUES('{1,null,3}'); SELECT a FROM arrtest; a @@ -152,6 +162,107 @@ SELECT a,b,c FROM arrtest; [4:4]={NULL} | {3,4} | {foo,new_word} (3 rows) +-- test mixed slice/scalar subscripting +select '{{1,2,3},{4,5,6},{7,8,9}}'::int[]; + int4 +--------------------------- + {{1,2,3},{4,5,6},{7,8,9}} +(1 row) + +select ('{{1,2,3},{4,5,6},{7,8,9}}'::int[])[1:2][2]; + int4 +--------------- + {{1,2},{4,5}} +(1 row) + +select '[0:2][0:2]={{1,2,3},{4,5,6},{7,8,9}}'::int[]; + int4 +-------------------------------------- + [0:2][0:2]={{1,2,3},{4,5,6},{7,8,9}} +(1 row) + +select ('[0:2][0:2]={{1,2,3},{4,5,6},{7,8,9}}'::int[])[1:2][2]; + int4 +--------------- + {{5,6},{8,9}} +(1 row) + +-- test slices with empty lower and/or upper index +CREATE TEMP 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}}'); +INSERT INTO arrtest_s VALUES ('[0:4]={1,2,3,4,5}', '[0:2][0:2]={{1,2,3}, {4,5,6}, {7,8,9}}'); +SELECT * FROM arrtest_s; + a | b +-------------------+-------------------------------------- + {1,2,3,4,5} | {{1,2,3},{4,5,6},{7,8,9}} + [0:4]={1,2,3,4,5} | [0:2][0:2]={{1,2,3},{4,5,6},{7,8,9}} +(2 rows) + +SELECT a[:3], b[:2][:2] FROM arrtest_s; + a | b +-----------+--------------------------- + {1,2,3} | {{1,2},{4,5}} + {1,2,3,4} | {{1,2,3},{4,5,6},{7,8,9}} +(2 rows) + +SELECT a[2:], b[2:][2:] FROM arrtest_s; + a | b +-----------+--------------- + {2,3,4,5} | {{5,6},{8,9}} + {3,4,5} | {{9}} +(2 rows) + +SELECT a[:], b[:] FROM arrtest_s; + a | b +-------------+--------------------------- + {1,2,3,4,5} | {{1,2,3},{4,5,6},{7,8,9}} + {1,2,3,4,5} | {{1,2,3},{4,5,6},{7,8,9}} +(2 rows) + +-- updates +UPDATE arrtest_s SET a[:3] = '{11, 12, 13}', b[:2][:2] = '{{11,12}, {14,15}}' + WHERE array_lower(a,1) = 1; +SELECT * FROM arrtest_s; + a | b +-------------------+-------------------------------------- + [0:4]={1,2,3,4,5} | [0:2][0:2]={{1,2,3},{4,5,6},{7,8,9}} + {11,12,13,4,5} | {{11,12,3},{14,15,6},{7,8,9}} +(2 rows) + +UPDATE arrtest_s SET a[3:] = '{23, 24, 25}', b[2:][2:] = '{{25,26}, {28,29}}'; +SELECT * FROM arrtest_s; + a | b +---------------------+--------------------------------------- + [0:4]={1,2,3,23,24} | [0:2][0:2]={{1,2,3},{4,5,6},{7,8,25}} + {11,12,23,24,25} | {{11,12,3},{14,25,26},{7,28,29}} +(2 rows) + +UPDATE arrtest_s SET a[:] = '{11, 12, 13, 14, 15}'; +SELECT * FROM arrtest_s; + a | b +------------------------+--------------------------------------- + [0:4]={11,12,13,14,15} | [0:2][0:2]={{1,2,3},{4,5,6},{7,8,25}} + {11,12,13,14,15} | {{11,12,3},{14,25,26},{7,28,29}} +(2 rows) + +UPDATE arrtest_s SET a[:] = '{23, 24, 25}'; -- fail, too small +ERROR: source array too small +INSERT INTO arrtest_s VALUES(NULL, NULL); +UPDATE arrtest_s SET a[:] = '{11, 12, 13, 14, 15}'; -- fail, no good with null +ERROR: array slice subscript must provide both boundaries +DETAIL: When assigning to a slice of an empty array value, slice boundaries must be fully specified. +-- check with fixed-length-array type, such as point +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 +SELECT f1[:] FROM POINT_TBL; +ERROR: slices of fixed-length arrays not implemented -- -- test array extension -- diff --git a/src/test/regress/sql/arrays.sql b/src/test/regress/sql/arrays.sql index b1dd6514405..a2c3db11274 100644 --- a/src/test/regress/sql/arrays.sql +++ b/src/test/regress/sql/arrays.sql @@ -86,6 +86,10 @@ SELECT a[1:3], d[1:1][2:2] FROM arrtest; +SELECT b[1:1][2][2], + d[1:1][2] + FROM arrtest; + INSERT INTO arrtest(a) VALUES('{1,null,3}'); SELECT a FROM arrtest; UPDATE arrtest SET a[4] = NULL WHERE a[2] IS NULL; @@ -93,6 +97,43 @@ SELECT a FROM arrtest WHERE a[2] IS NULL; DELETE FROM arrtest WHERE a[2] IS NULL AND b IS NULL; SELECT a,b,c FROM arrtest; +-- test mixed slice/scalar subscripting +select '{{1,2,3},{4,5,6},{7,8,9}}'::int[]; +select ('{{1,2,3},{4,5,6},{7,8,9}}'::int[])[1:2][2]; +select '[0:2][0:2]={{1,2,3},{4,5,6},{7,8,9}}'::int[]; +select ('[0:2][0:2]={{1,2,3},{4,5,6},{7,8,9}}'::int[])[1:2][2]; + +-- test slices with empty lower and/or upper index +CREATE TEMP 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}}'); +INSERT INTO arrtest_s VALUES ('[0:4]={1,2,3,4,5}', '[0:2][0:2]={{1,2,3}, {4,5,6}, {7,8,9}}'); + +SELECT * FROM arrtest_s; +SELECT a[:3], b[:2][:2] FROM arrtest_s; +SELECT a[2:], b[2:][2:] FROM arrtest_s; +SELECT a[:], b[:] FROM arrtest_s; + +-- updates +UPDATE arrtest_s SET a[:3] = '{11, 12, 13}', b[:2][:2] = '{{11,12}, {14,15}}' + WHERE array_lower(a,1) = 1; +SELECT * FROM arrtest_s; +UPDATE arrtest_s SET a[3:] = '{23, 24, 25}', b[2:][2:] = '{{25,26}, {28,29}}'; +SELECT * FROM arrtest_s; +UPDATE arrtest_s SET a[:] = '{11, 12, 13, 14, 15}'; +SELECT * FROM arrtest_s; +UPDATE arrtest_s SET a[:] = '{23, 24, 25}'; -- fail, too small +INSERT INTO arrtest_s VALUES(NULL, NULL); +UPDATE arrtest_s SET a[:] = '{11, 12, 13, 14, 15}'; -- fail, no good with null + +-- check with fixed-length-array type, such as point +SELECT f1[0:1] FROM POINT_TBL; +SELECT f1[0:] FROM POINT_TBL; +SELECT f1[:1] FROM POINT_TBL; +SELECT f1[:] FROM POINT_TBL; + -- -- test array extension -- |