diff options
Diffstat (limited to 'src/backend')
-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 |
9 files changed, 106 insertions, 26 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, ']'); } |