aboutsummaryrefslogtreecommitdiff
path: root/src/backend
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend')
-rw-r--r--src/backend/executor/execQual.c44
-rw-r--r--src/backend/nodes/copyfuncs.c2
-rw-r--r--src/backend/nodes/equalfuncs.c2
-rw-r--r--src/backend/nodes/outfuncs.c2
-rw-r--r--src/backend/parser/gram.y31
-rw-r--r--src/backend/parser/parse_node.c49
-rw-r--r--src/backend/parser/parse_target.c2
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))