diff options
Diffstat (limited to 'src/backend')
-rw-r--r-- | src/backend/executor/execQual.c | 44 | ||||
-rw-r--r-- | src/backend/nodes/copyfuncs.c | 2 | ||||
-rw-r--r-- | src/backend/nodes/equalfuncs.c | 2 | ||||
-rw-r--r-- | src/backend/nodes/outfuncs.c | 2 | ||||
-rw-r--r-- | src/backend/parser/gram.y | 31 | ||||
-rw-r--r-- | src/backend/parser/parse_node.c | 49 | ||||
-rw-r--r-- | src/backend/parser/parse_target.c | 2 |
7 files changed, 105 insertions, 27 deletions
diff --git a/src/backend/executor/execQual.c b/src/backend/executor/execQual.c index 29f058ce5cb..d9bf9773fe8 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,23 @@ 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 && 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, - 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 ba04b7227ca..6fc9886209d 100644 --- a/src/backend/nodes/copyfuncs.c +++ b/src/backend/nodes/copyfuncs.c @@ -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; } diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c index 356fcafeb49..deca3b787dd 100644 --- a/src/backend/nodes/equalfuncs.c +++ b/src/backend/nodes/equalfuncs.c @@ -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; } diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c index 63fae82aba0..1a28dfd2b96 100644 --- a/src/backend/nodes/outfuncs.c +++ b/src/backend/nodes/outfuncs.c @@ -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 diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index c4bed8a5ef7..ce95f0f2a73 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -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; } ; diff --git a/src/backend/parser/parse_node.c b/src/backend/parser/parse_node.c index 4130cbff5ed..de6e0b89342 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->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,19 +377,26 @@ transformArraySubscripts(ParseState *pstate, } 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->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, + 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 + subexpr = NULL; + upperIndexpr = lappend(upperIndexpr, subexpr); } diff --git a/src/backend/parser/parse_target.c b/src/backend/parser/parse_target.c index 1b3fcd629c1..df41f9fc9b8 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)->lidx != NULL || ((A_Indices *) n)->lidx_default) isSlice = true; } else if (IsA(n, A_Star)) |