Renaming for new subscripting mechanism

Over at patch https://commitfest.postgresql.org/21/1062/ Dmitry wants to
introduce a more generic subscription mechanism, which allows
subscripting not only arrays but also other object types such as JSONB.
That functionality is introduced in a largish invasive patch, out of
which this internal renaming patch was extracted.

Author: Dmitry Dolgov
Reviewed-by: Tom Lane, Arthur Zakirov
Discussion: https://postgr.es/m/CA+q6zcUK4EqPAu7XRRO5CCjMwhz5zvg+rfWuLzVoxp_5sKS6=w@mail.gmail.com
This commit is contained in:
Alvaro Herrera 2019-02-01 12:50:32 -03:00
parent f831d4accd
commit 558d77f20e
26 changed files with 555 additions and 523 deletions

View File

@ -2579,14 +2579,14 @@ JumbleExpr(pgssJumbleState *jstate, Node *node)
JumbleExpr(jstate, (Node *) expr->aggfilter); JumbleExpr(jstate, (Node *) expr->aggfilter);
} }
break; break;
case T_ArrayRef: case T_SubscriptingRef:
{ {
ArrayRef *aref = (ArrayRef *) node; SubscriptingRef *sbsref = (SubscriptingRef *) node;
JumbleExpr(jstate, (Node *) aref->refupperindexpr); JumbleExpr(jstate, (Node *) sbsref->refupperindexpr);
JumbleExpr(jstate, (Node *) aref->reflowerindexpr); JumbleExpr(jstate, (Node *) sbsref->reflowerindexpr);
JumbleExpr(jstate, (Node *) aref->refexpr); JumbleExpr(jstate, (Node *) sbsref->refexpr);
JumbleExpr(jstate, (Node *) aref->refassgnexpr); JumbleExpr(jstate, (Node *) sbsref->refassgnexpr);
} }
break; break;
case T_FuncExpr: case T_FuncExpr:

View File

@ -149,7 +149,7 @@ static void deparseExpr(Expr *expr, deparse_expr_cxt *context);
static void deparseVar(Var *node, deparse_expr_cxt *context); static void deparseVar(Var *node, deparse_expr_cxt *context);
static void deparseConst(Const *node, deparse_expr_cxt *context, int showtype); static void deparseConst(Const *node, deparse_expr_cxt *context, int showtype);
static void deparseParam(Param *node, deparse_expr_cxt *context); static void deparseParam(Param *node, deparse_expr_cxt *context);
static void deparseArrayRef(ArrayRef *node, deparse_expr_cxt *context); static void deparseSubscriptingRef(SubscriptingRef *node, deparse_expr_cxt *context);
static void deparseFuncExpr(FuncExpr *node, deparse_expr_cxt *context); static void deparseFuncExpr(FuncExpr *node, deparse_expr_cxt *context);
static void deparseOpExpr(OpExpr *node, deparse_expr_cxt *context); static void deparseOpExpr(OpExpr *node, deparse_expr_cxt *context);
static void deparseOperatorName(StringInfo buf, Form_pg_operator opform); static void deparseOperatorName(StringInfo buf, Form_pg_operator opform);
@ -401,34 +401,34 @@ foreign_expr_walker(Node *node,
state = FDW_COLLATE_UNSAFE; state = FDW_COLLATE_UNSAFE;
} }
break; break;
case T_ArrayRef: case T_SubscriptingRef:
{ {
ArrayRef *ar = (ArrayRef *) node; SubscriptingRef *sr = (SubscriptingRef *) node;
/* Assignment should not be in restrictions. */ /* Assignment should not be in restrictions. */
if (ar->refassgnexpr != NULL) if (sr->refassgnexpr != NULL)
return false; return false;
/* /*
* Recurse to remaining subexpressions. Since the array * Recurse to remaining subexpressions. Since the container
* subscripts must yield (noncollatable) integers, they won't * subscripts must yield (noncollatable) integers, they won't
* affect the inner_cxt state. * affect the inner_cxt state.
*/ */
if (!foreign_expr_walker((Node *) ar->refupperindexpr, if (!foreign_expr_walker((Node *) sr->refupperindexpr,
glob_cxt, &inner_cxt)) glob_cxt, &inner_cxt))
return false; return false;
if (!foreign_expr_walker((Node *) ar->reflowerindexpr, if (!foreign_expr_walker((Node *) sr->reflowerindexpr,
glob_cxt, &inner_cxt)) glob_cxt, &inner_cxt))
return false; return false;
if (!foreign_expr_walker((Node *) ar->refexpr, if (!foreign_expr_walker((Node *) sr->refexpr,
glob_cxt, &inner_cxt)) glob_cxt, &inner_cxt))
return false; return false;
/* /*
* Array subscripting should yield same collation as input, * Container subscripting should yield same collation as
* but for safety use same logic as for function nodes. * input, but for safety use same logic as for function nodes.
*/ */
collation = ar->refcollid; collation = sr->refcollid;
if (collation == InvalidOid) if (collation == InvalidOid)
state = FDW_COLLATE_NONE; state = FDW_COLLATE_NONE;
else if (inner_cxt.state == FDW_COLLATE_SAFE && else if (inner_cxt.state == FDW_COLLATE_SAFE &&
@ -2270,8 +2270,8 @@ deparseExpr(Expr *node, deparse_expr_cxt *context)
case T_Param: case T_Param:
deparseParam((Param *) node, context); deparseParam((Param *) node, context);
break; break;
case T_ArrayRef: case T_SubscriptingRef:
deparseArrayRef((ArrayRef *) node, context); deparseSubscriptingRef((SubscriptingRef *) node, context);
break; break;
case T_FuncExpr: case T_FuncExpr:
deparseFuncExpr((FuncExpr *) node, context); deparseFuncExpr((FuncExpr *) node, context);
@ -2518,10 +2518,10 @@ deparseParam(Param *node, deparse_expr_cxt *context)
} }
/* /*
* Deparse an array subscript expression. * Deparse a container subscript expression.
*/ */
static void static void
deparseArrayRef(ArrayRef *node, deparse_expr_cxt *context) deparseSubscriptingRef(SubscriptingRef *node, deparse_expr_cxt *context)
{ {
StringInfo buf = context->buf; StringInfo buf = context->buf;
ListCell *lowlist_item; ListCell *lowlist_item;

View File

@ -67,9 +67,10 @@ static bool get_last_attnums_walker(Node *node, LastAttnumInfo *info);
static void ExecComputeSlotInfo(ExprState *state, ExprEvalStep *op); static void ExecComputeSlotInfo(ExprState *state, ExprEvalStep *op);
static void ExecInitWholeRowVar(ExprEvalStep *scratch, Var *variable, static void ExecInitWholeRowVar(ExprEvalStep *scratch, Var *variable,
ExprState *state); ExprState *state);
static void ExecInitArrayRef(ExprEvalStep *scratch, ArrayRef *aref, static void ExecInitSubscriptingRef(ExprEvalStep *scratch,
ExprState *state, SubscriptingRef *sbsref,
Datum *resv, bool *resnull); ExprState *state,
Datum *resv, bool *resnull);
static bool isAssignmentIndirectionExpr(Expr *expr); static bool isAssignmentIndirectionExpr(Expr *expr);
static void ExecInitCoerceToDomain(ExprEvalStep *scratch, CoerceToDomain *ctest, static void ExecInitCoerceToDomain(ExprEvalStep *scratch, CoerceToDomain *ctest,
ExprState *state, ExprState *state,
@ -867,11 +868,11 @@ ExecInitExprRec(Expr *node, ExprState *state,
break; break;
} }
case T_ArrayRef: case T_SubscriptingRef:
{ {
ArrayRef *aref = (ArrayRef *) node; SubscriptingRef *sbsref = (SubscriptingRef *) node;
ExecInitArrayRef(&scratch, aref, state, resv, resnull); ExecInitSubscriptingRef(&scratch, sbsref, state, resv, resnull);
break; break;
} }
@ -1186,13 +1187,14 @@ ExecInitExprRec(Expr *node, ExprState *state,
/* /*
* Use the CaseTestExpr mechanism to pass down the old * Use the CaseTestExpr mechanism to pass down the old
* value of the field being replaced; this is needed in * value of the field being replaced; this is needed in
* case the newval is itself a FieldStore or ArrayRef that * case the newval is itself a FieldStore or
* has to obtain and modify the old value. It's safe to * SubscriptingRef that has to obtain and modify the old
* reuse the CASE mechanism because there cannot be a CASE * value. It's safe to reuse the CASE mechanism because
* between here and where the value would be needed, and a * there cannot be a CASE between here and where the value
* field assignment can't be within a CASE either. (So * would be needed, and a field assignment can't be within
* saving and restoring innermost_caseval is just * a CASE either. (So saving and restoring
* paranoia, but let's do it anyway.) * innermost_caseval is just paranoia, but let's do it
* anyway.)
* *
* Another non-obvious point is that it's safe to use the * Another non-obvious point is that it's safe to use the
* field's values[]/nulls[] entries as both the caseval * field's values[]/nulls[] entries as both the caseval
@ -2528,34 +2530,34 @@ ExecInitWholeRowVar(ExprEvalStep *scratch, Var *variable, ExprState *state)
} }
/* /*
* Prepare evaluation of an ArrayRef expression. * Prepare evaluation of a SubscriptingRef expression.
*/ */
static void static void
ExecInitArrayRef(ExprEvalStep *scratch, ArrayRef *aref, ExecInitSubscriptingRef(ExprEvalStep *scratch, SubscriptingRef *sbsref,
ExprState *state, Datum *resv, bool *resnull) ExprState *state, Datum *resv, bool *resnull)
{ {
bool isAssignment = (aref->refassgnexpr != NULL); bool isAssignment = (sbsref->refassgnexpr != NULL);
ArrayRefState *arefstate = palloc0(sizeof(ArrayRefState)); SubscriptingRefState *sbsrefstate = palloc0(sizeof(SubscriptingRefState));
List *adjust_jumps = NIL; List *adjust_jumps = NIL;
ListCell *lc; ListCell *lc;
int i; int i;
/* Fill constant fields of ArrayRefState */ /* Fill constant fields of SubscriptingRefState */
arefstate->isassignment = isAssignment; sbsrefstate->isassignment = isAssignment;
arefstate->refelemtype = aref->refelemtype; sbsrefstate->refelemtype = sbsref->refelemtype;
arefstate->refattrlength = get_typlen(aref->refarraytype); sbsrefstate->refattrlength = get_typlen(sbsref->refcontainertype);
get_typlenbyvalalign(aref->refelemtype, get_typlenbyvalalign(sbsref->refelemtype,
&arefstate->refelemlength, &sbsrefstate->refelemlength,
&arefstate->refelembyval, &sbsrefstate->refelembyval,
&arefstate->refelemalign); &sbsrefstate->refelemalign);
/* /*
* Evaluate array input. It's safe to do so into resv/resnull, because we * Evaluate array input. It's safe to do so into resv/resnull, because we
* won't use that as target for any of the other subexpressions, and it'll * won't use that as target for any of the other subexpressions, and it'll
* be overwritten by the final EEOP_ARRAYREF_FETCH/ASSIGN step, which is * be overwritten by the final EEOP_SBSREF_FETCH/ASSIGN step, which is
* pushed last. * pushed last.
*/ */
ExecInitExprRec(aref->refexpr, state, resv, resnull); ExecInitExprRec(sbsref->refexpr, state, resv, resnull);
/* /*
* If refexpr yields NULL, and it's a fetch, then result is NULL. We can * If refexpr yields NULL, and it's a fetch, then result is NULL. We can
@ -2572,87 +2574,87 @@ ExecInitArrayRef(ExprEvalStep *scratch, ArrayRef *aref,
} }
/* Verify subscript list lengths are within limit */ /* Verify subscript list lengths are within limit */
if (list_length(aref->refupperindexpr) > MAXDIM) if (list_length(sbsref->refupperindexpr) > MAXDIM)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
errmsg("number of array dimensions (%d) exceeds the maximum allowed (%d)", errmsg("number of array dimensions (%d) exceeds the maximum allowed (%d)",
list_length(aref->refupperindexpr), MAXDIM))); list_length(sbsref->refupperindexpr), MAXDIM)));
if (list_length(aref->reflowerindexpr) > MAXDIM) if (list_length(sbsref->reflowerindexpr) > MAXDIM)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
errmsg("number of array dimensions (%d) exceeds the maximum allowed (%d)", errmsg("number of array dimensions (%d) exceeds the maximum allowed (%d)",
list_length(aref->reflowerindexpr), MAXDIM))); list_length(sbsref->reflowerindexpr), MAXDIM)));
/* Evaluate upper subscripts */ /* Evaluate upper subscripts */
i = 0; i = 0;
foreach(lc, aref->refupperindexpr) foreach(lc, sbsref->refupperindexpr)
{ {
Expr *e = (Expr *) lfirst(lc); Expr *e = (Expr *) lfirst(lc);
/* When slicing, individual subscript bounds can be omitted */ /* When slicing, individual subscript bounds can be omitted */
if (!e) if (!e)
{ {
arefstate->upperprovided[i] = false; sbsrefstate->upperprovided[i] = false;
i++; i++;
continue; continue;
} }
arefstate->upperprovided[i] = true; sbsrefstate->upperprovided[i] = true;
/* Each subscript is evaluated into subscriptvalue/subscriptnull */ /* Each subscript is evaluated into subscriptvalue/subscriptnull */
ExecInitExprRec(e, state, ExecInitExprRec(e, state,
&arefstate->subscriptvalue, &arefstate->subscriptnull); &sbsrefstate->subscriptvalue, &sbsrefstate->subscriptnull);
/* ... and then ARRAYREF_SUBSCRIPT saves it into step's workspace */ /* ... and then SBSREF_SUBSCRIPT saves it into step's workspace */
scratch->opcode = EEOP_ARRAYREF_SUBSCRIPT; scratch->opcode = EEOP_SBSREF_SUBSCRIPT;
scratch->d.arrayref_subscript.state = arefstate; scratch->d.sbsref_subscript.state = sbsrefstate;
scratch->d.arrayref_subscript.off = i; scratch->d.sbsref_subscript.off = i;
scratch->d.arrayref_subscript.isupper = true; scratch->d.sbsref_subscript.isupper = true;
scratch->d.arrayref_subscript.jumpdone = -1; /* adjust later */ scratch->d.sbsref_subscript.jumpdone = -1; /* adjust later */
ExprEvalPushStep(state, scratch); ExprEvalPushStep(state, scratch);
adjust_jumps = lappend_int(adjust_jumps, adjust_jumps = lappend_int(adjust_jumps,
state->steps_len - 1); state->steps_len - 1);
i++; i++;
} }
arefstate->numupper = i; sbsrefstate->numupper = i;
/* Evaluate lower subscripts similarly */ /* Evaluate lower subscripts similarly */
i = 0; i = 0;
foreach(lc, aref->reflowerindexpr) foreach(lc, sbsref->reflowerindexpr)
{ {
Expr *e = (Expr *) lfirst(lc); Expr *e = (Expr *) lfirst(lc);
/* When slicing, individual subscript bounds can be omitted */ /* When slicing, individual subscript bounds can be omitted */
if (!e) if (!e)
{ {
arefstate->lowerprovided[i] = false; sbsrefstate->lowerprovided[i] = false;
i++; i++;
continue; continue;
} }
arefstate->lowerprovided[i] = true; sbsrefstate->lowerprovided[i] = true;
/* Each subscript is evaluated into subscriptvalue/subscriptnull */ /* Each subscript is evaluated into subscriptvalue/subscriptnull */
ExecInitExprRec(e, state, ExecInitExprRec(e, state,
&arefstate->subscriptvalue, &arefstate->subscriptnull); &sbsrefstate->subscriptvalue, &sbsrefstate->subscriptnull);
/* ... and then ARRAYREF_SUBSCRIPT saves it into step's workspace */ /* ... and then SBSREF_SUBSCRIPT saves it into step's workspace */
scratch->opcode = EEOP_ARRAYREF_SUBSCRIPT; scratch->opcode = EEOP_SBSREF_SUBSCRIPT;
scratch->d.arrayref_subscript.state = arefstate; scratch->d.sbsref_subscript.state = sbsrefstate;
scratch->d.arrayref_subscript.off = i; scratch->d.sbsref_subscript.off = i;
scratch->d.arrayref_subscript.isupper = false; scratch->d.sbsref_subscript.isupper = false;
scratch->d.arrayref_subscript.jumpdone = -1; /* adjust later */ scratch->d.sbsref_subscript.jumpdone = -1; /* adjust later */
ExprEvalPushStep(state, scratch); ExprEvalPushStep(state, scratch);
adjust_jumps = lappend_int(adjust_jumps, adjust_jumps = lappend_int(adjust_jumps,
state->steps_len - 1); state->steps_len - 1);
i++; i++;
} }
arefstate->numlower = i; sbsrefstate->numlower = i;
/* Should be impossible if parser is sane, but check anyway: */ /* Should be impossible if parser is sane, but check anyway: */
if (arefstate->numlower != 0 && if (sbsrefstate->numlower != 0 &&
arefstate->numupper != arefstate->numlower) sbsrefstate->numupper != sbsrefstate->numlower)
elog(ERROR, "upper and lower index lists are not same length"); elog(ERROR, "upper and lower index lists are not same length");
if (isAssignment) if (isAssignment)
@ -2662,49 +2664,51 @@ ExecInitArrayRef(ExprEvalStep *scratch, ArrayRef *aref,
/* /*
* We might have a nested-assignment situation, in which the * We might have a nested-assignment situation, in which the
* refassgnexpr is itself a FieldStore or ArrayRef that needs to * refassgnexpr is itself a FieldStore or SubscriptingRef that needs
* obtain and modify the previous value of the array element or slice * to obtain and modify the previous value of the array element or
* being replaced. If so, we have to extract that value from the * slice being replaced. If so, we have to extract that value from
* array and pass it down via the CaseTestExpr mechanism. It's safe * the array and pass it down via the CaseTestExpr mechanism. It's
* to reuse the CASE mechanism because there cannot be a CASE between * safe to reuse the CASE mechanism because there cannot be a CASE
* here and where the value would be needed, and an array assignment * between here and where the value would be needed, and an array
* can't be within a CASE either. (So saving and restoring * assignment can't be within a CASE either. (So saving and restoring
* innermost_caseval is just paranoia, but let's do it anyway.) * innermost_caseval is just paranoia, but let's do it anyway.)
* *
* Since fetching the old element might be a nontrivial expense, do it * Since fetching the old element might be a nontrivial expense, do it
* only if the argument actually needs it. * only if the argument actually needs it.
*/ */
if (isAssignmentIndirectionExpr(aref->refassgnexpr)) if (isAssignmentIndirectionExpr(sbsref->refassgnexpr))
{ {
scratch->opcode = EEOP_ARRAYREF_OLD; scratch->opcode = EEOP_SBSREF_OLD;
scratch->d.arrayref.state = arefstate; scratch->d.sbsref.state = sbsrefstate;
ExprEvalPushStep(state, scratch); ExprEvalPushStep(state, scratch);
} }
/* ARRAYREF_OLD puts extracted value into prevvalue/prevnull */ /* SBSREF_OLD puts extracted value into prevvalue/prevnull */
save_innermost_caseval = state->innermost_caseval; save_innermost_caseval = state->innermost_caseval;
save_innermost_casenull = state->innermost_casenull; save_innermost_casenull = state->innermost_casenull;
state->innermost_caseval = &arefstate->prevvalue; state->innermost_caseval = &sbsrefstate->prevvalue;
state->innermost_casenull = &arefstate->prevnull; state->innermost_casenull = &sbsrefstate->prevnull;
/* evaluate replacement value into replacevalue/replacenull */ /* evaluate replacement value into replacevalue/replacenull */
ExecInitExprRec(aref->refassgnexpr, state, ExecInitExprRec(sbsref->refassgnexpr, state,
&arefstate->replacevalue, &arefstate->replacenull); &sbsrefstate->replacevalue, &sbsrefstate->replacenull);
state->innermost_caseval = save_innermost_caseval; state->innermost_caseval = save_innermost_caseval;
state->innermost_casenull = save_innermost_casenull; state->innermost_casenull = save_innermost_casenull;
/* and perform the assignment */ /* and perform the assignment */
scratch->opcode = EEOP_ARRAYREF_ASSIGN; scratch->opcode = EEOP_SBSREF_ASSIGN;
scratch->d.arrayref.state = arefstate; scratch->d.sbsref.state = sbsrefstate;
ExprEvalPushStep(state, scratch); ExprEvalPushStep(state, scratch);
} }
else else
{ {
/* array fetch is much simpler */ /* array fetch is much simpler */
scratch->opcode = EEOP_ARRAYREF_FETCH; scratch->opcode = EEOP_SBSREF_FETCH;
scratch->d.arrayref.state = arefstate; scratch->d.sbsref.state = sbsrefstate;
ExprEvalPushStep(state, scratch); ExprEvalPushStep(state, scratch);
} }
/* adjust jump targets */ /* adjust jump targets */
@ -2712,10 +2716,10 @@ ExecInitArrayRef(ExprEvalStep *scratch, ArrayRef *aref,
{ {
ExprEvalStep *as = &state->steps[lfirst_int(lc)]; ExprEvalStep *as = &state->steps[lfirst_int(lc)];
if (as->opcode == EEOP_ARRAYREF_SUBSCRIPT) if (as->opcode == EEOP_SBSREF_SUBSCRIPT)
{ {
Assert(as->d.arrayref_subscript.jumpdone == -1); Assert(as->d.sbsref_subscript.jumpdone == -1);
as->d.arrayref_subscript.jumpdone = state->steps_len; as->d.sbsref_subscript.jumpdone = state->steps_len;
} }
else else
{ {
@ -2727,8 +2731,9 @@ ExecInitArrayRef(ExprEvalStep *scratch, ArrayRef *aref,
} }
/* /*
* Helper for preparing ArrayRef expressions for evaluation: is expr a nested * Helper for preparing SubscriptingRef expressions for evaluation: is expr
* FieldStore or ArrayRef that needs the old element value passed down? * a nested FieldStore or SubscriptingRef that needs the old element value
* passed down?
* *
* (We could use this in FieldStore too, but in that case passing the old * (We could use this in FieldStore too, but in that case passing the old
* value is so cheap there's no need.) * value is so cheap there's no need.)
@ -2751,11 +2756,11 @@ isAssignmentIndirectionExpr(Expr *expr)
if (fstore->arg && IsA(fstore->arg, CaseTestExpr)) if (fstore->arg && IsA(fstore->arg, CaseTestExpr))
return true; return true;
} }
else if (IsA(expr, ArrayRef)) else if (IsA(expr, SubscriptingRef))
{ {
ArrayRef *arrayRef = (ArrayRef *) expr; SubscriptingRef *sbsRef = (SubscriptingRef *) expr;
if (arrayRef->refexpr && IsA(arrayRef->refexpr, CaseTestExpr)) if (sbsRef->refexpr && IsA(sbsRef->refexpr, CaseTestExpr))
return true; return true;
} }
return false; return false;

View File

@ -370,10 +370,10 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
&&CASE_EEOP_FIELDSELECT, &&CASE_EEOP_FIELDSELECT,
&&CASE_EEOP_FIELDSTORE_DEFORM, &&CASE_EEOP_FIELDSTORE_DEFORM,
&&CASE_EEOP_FIELDSTORE_FORM, &&CASE_EEOP_FIELDSTORE_FORM,
&&CASE_EEOP_ARRAYREF_SUBSCRIPT, &&CASE_EEOP_SBSREF_SUBSCRIPT,
&&CASE_EEOP_ARRAYREF_OLD, &&CASE_EEOP_SBSREF_OLD,
&&CASE_EEOP_ARRAYREF_ASSIGN, &&CASE_EEOP_SBSREF_ASSIGN,
&&CASE_EEOP_ARRAYREF_FETCH, &&CASE_EEOP_SBSREF_FETCH,
&&CASE_EEOP_DOMAIN_TESTVAL, &&CASE_EEOP_DOMAIN_TESTVAL,
&&CASE_EEOP_DOMAIN_NOTNULL, &&CASE_EEOP_DOMAIN_NOTNULL,
&&CASE_EEOP_DOMAIN_CHECK, &&CASE_EEOP_DOMAIN_CHECK,
@ -1347,43 +1347,43 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
EEO_NEXT(); EEO_NEXT();
} }
EEO_CASE(EEOP_ARRAYREF_SUBSCRIPT) EEO_CASE(EEOP_SBSREF_SUBSCRIPT)
{ {
/* Process an array subscript */ /* Process an array subscript */
/* too complex for an inline implementation */ /* too complex for an inline implementation */
if (ExecEvalArrayRefSubscript(state, op)) if (ExecEvalSubscriptingRef(state, op))
{ {
EEO_NEXT(); EEO_NEXT();
} }
else else
{ {
/* Subscript is null, short-circuit ArrayRef to NULL */ /* Subscript is null, short-circuit SubscriptingRef to NULL */
EEO_JUMP(op->d.arrayref_subscript.jumpdone); EEO_JUMP(op->d.sbsref_subscript.jumpdone);
} }
} }
EEO_CASE(EEOP_ARRAYREF_OLD) EEO_CASE(EEOP_SBSREF_OLD)
{ {
/* /*
* Fetch the old value in an arrayref assignment, in case it's * Fetch the old value in an sbsref assignment, in case it's
* referenced (via a CaseTestExpr) inside the assignment * referenced (via a CaseTestExpr) inside the assignment
* expression. * expression.
*/ */
/* too complex for an inline implementation */ /* too complex for an inline implementation */
ExecEvalArrayRefOld(state, op); ExecEvalSubscriptingRefOld(state, op);
EEO_NEXT(); EEO_NEXT();
} }
/* /*
* Perform ArrayRef assignment * Perform SubscriptingRef assignment
*/ */
EEO_CASE(EEOP_ARRAYREF_ASSIGN) EEO_CASE(EEOP_SBSREF_ASSIGN)
{ {
/* too complex for an inline implementation */ /* too complex for an inline implementation */
ExecEvalArrayRefAssign(state, op); ExecEvalSubscriptingRefAssign(state, op);
EEO_NEXT(); EEO_NEXT();
} }
@ -1391,10 +1391,10 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
/* /*
* Fetch subset of an array. * Fetch subset of an array.
*/ */
EEO_CASE(EEOP_ARRAYREF_FETCH) EEO_CASE(EEOP_SBSREF_FETCH)
{ {
/* too complex for an inline implementation */ /* too complex for an inline implementation */
ExecEvalArrayRefFetch(state, op); ExecEvalSubscriptingRefFetch(state, op);
EEO_NEXT(); EEO_NEXT();
} }
@ -3044,27 +3044,27 @@ ExecEvalFieldStoreForm(ExprState *state, ExprEvalStep *op, ExprContext *econtext
} }
/* /*
* Process a subscript in an ArrayRef expression. * Process a subscript in a SubscriptingRef expression.
* *
* If subscript is NULL, throw error in assignment case, or in fetch case * If subscript is NULL, throw error in assignment case, or in fetch case
* set result to NULL and return false (instructing caller to skip the rest * set result to NULL and return false (instructing caller to skip the rest
* of the ArrayRef sequence). * of the SubscriptingRef sequence).
* *
* Subscript expression result is in subscriptvalue/subscriptnull. * Subscript expression result is in subscriptvalue/subscriptnull.
* On success, integer subscript value has been saved in upperindex[] or * On success, integer subscript value has been saved in upperindex[] or
* lowerindex[] for use later. * lowerindex[] for use later.
*/ */
bool bool
ExecEvalArrayRefSubscript(ExprState *state, ExprEvalStep *op) ExecEvalSubscriptingRef(ExprState *state, ExprEvalStep *op)
{ {
ArrayRefState *arefstate = op->d.arrayref_subscript.state; SubscriptingRefState *sbsrefstate = op->d.sbsref_subscript.state;
int *indexes; int *indexes;
int off; int off;
/* If any index expr yields NULL, result is NULL or error */ /* If any index expr yields NULL, result is NULL or error */
if (arefstate->subscriptnull) if (sbsrefstate->subscriptnull)
{ {
if (arefstate->isassignment) if (sbsrefstate->isassignment)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
errmsg("array subscript in assignment must not be null"))); errmsg("array subscript in assignment must not be null")));
@ -3073,124 +3073,124 @@ ExecEvalArrayRefSubscript(ExprState *state, ExprEvalStep *op)
} }
/* Convert datum to int, save in appropriate place */ /* Convert datum to int, save in appropriate place */
if (op->d.arrayref_subscript.isupper) if (op->d.sbsref_subscript.isupper)
indexes = arefstate->upperindex; indexes = sbsrefstate->upperindex;
else else
indexes = arefstate->lowerindex; indexes = sbsrefstate->lowerindex;
off = op->d.arrayref_subscript.off; off = op->d.sbsref_subscript.off;
indexes[off] = DatumGetInt32(arefstate->subscriptvalue); indexes[off] = DatumGetInt32(sbsrefstate->subscriptvalue);
return true; return true;
} }
/* /*
* Evaluate ArrayRef fetch. * Evaluate SubscriptingRef fetch.
* *
* Source array is in step's result variable. * Source container is in step's result variable.
*/ */
void void
ExecEvalArrayRefFetch(ExprState *state, ExprEvalStep *op) ExecEvalSubscriptingRefFetch(ExprState *state, ExprEvalStep *op)
{ {
ArrayRefState *arefstate = op->d.arrayref.state; SubscriptingRefState *sbsrefstate = op->d.sbsref.state;
/* Should not get here if source array (or any subscript) is null */ /* Should not get here if source container (or any subscript) is null */
Assert(!(*op->resnull)); Assert(!(*op->resnull));
if (arefstate->numlower == 0) if (sbsrefstate->numlower == 0)
{ {
/* Scalar case */ /* Scalar case */
*op->resvalue = array_get_element(*op->resvalue, *op->resvalue = array_get_element(*op->resvalue,
arefstate->numupper, sbsrefstate->numupper,
arefstate->upperindex, sbsrefstate->upperindex,
arefstate->refattrlength, sbsrefstate->refattrlength,
arefstate->refelemlength, sbsrefstate->refelemlength,
arefstate->refelembyval, sbsrefstate->refelembyval,
arefstate->refelemalign, sbsrefstate->refelemalign,
op->resnull); op->resnull);
} }
else else
{ {
/* Slice case */ /* Slice case */
*op->resvalue = array_get_slice(*op->resvalue, *op->resvalue = array_get_slice(*op->resvalue,
arefstate->numupper, sbsrefstate->numupper,
arefstate->upperindex, sbsrefstate->upperindex,
arefstate->lowerindex, sbsrefstate->lowerindex,
arefstate->upperprovided, sbsrefstate->upperprovided,
arefstate->lowerprovided, sbsrefstate->lowerprovided,
arefstate->refattrlength, sbsrefstate->refattrlength,
arefstate->refelemlength, sbsrefstate->refelemlength,
arefstate->refelembyval, sbsrefstate->refelembyval,
arefstate->refelemalign); sbsrefstate->refelemalign);
} }
} }
/* /*
* Compute old array element/slice value for an ArrayRef assignment * Compute old container element/slice value for a SubscriptingRef assignment
* expression. Will only be generated if the new-value subexpression * expression. Will only be generated if the new-value subexpression
* contains ArrayRef or FieldStore. The value is stored into the * contains SubscriptingRef or FieldStore. The value is stored into the
* ArrayRefState's prevvalue/prevnull fields. * SubscriptingRefState's prevvalue/prevnull fields.
*/ */
void void
ExecEvalArrayRefOld(ExprState *state, ExprEvalStep *op) ExecEvalSubscriptingRefOld(ExprState *state, ExprEvalStep *op)
{ {
ArrayRefState *arefstate = op->d.arrayref.state; SubscriptingRefState *sbsrefstate = op->d.sbsref.state;
if (*op->resnull) if (*op->resnull)
{ {
/* whole array is null, so any element or slice is too */ /* whole array is null, so any element or slice is too */
arefstate->prevvalue = (Datum) 0; sbsrefstate->prevvalue = (Datum) 0;
arefstate->prevnull = true; sbsrefstate->prevnull = true;
} }
else if (arefstate->numlower == 0) else if (sbsrefstate->numlower == 0)
{ {
/* Scalar case */ /* Scalar case */
arefstate->prevvalue = array_get_element(*op->resvalue, sbsrefstate->prevvalue = array_get_element(*op->resvalue,
arefstate->numupper, sbsrefstate->numupper,
arefstate->upperindex, sbsrefstate->upperindex,
arefstate->refattrlength, sbsrefstate->refattrlength,
arefstate->refelemlength, sbsrefstate->refelemlength,
arefstate->refelembyval, sbsrefstate->refelembyval,
arefstate->refelemalign, sbsrefstate->refelemalign,
&arefstate->prevnull); &sbsrefstate->prevnull);
} }
else else
{ {
/* Slice case */ /* Slice case */
/* this is currently unreachable */ /* this is currently unreachable */
arefstate->prevvalue = array_get_slice(*op->resvalue, sbsrefstate->prevvalue = array_get_slice(*op->resvalue,
arefstate->numupper, sbsrefstate->numupper,
arefstate->upperindex, sbsrefstate->upperindex,
arefstate->lowerindex, sbsrefstate->lowerindex,
arefstate->upperprovided, sbsrefstate->upperprovided,
arefstate->lowerprovided, sbsrefstate->lowerprovided,
arefstate->refattrlength, sbsrefstate->refattrlength,
arefstate->refelemlength, sbsrefstate->refelemlength,
arefstate->refelembyval, sbsrefstate->refelembyval,
arefstate->refelemalign); sbsrefstate->refelemalign);
arefstate->prevnull = false; sbsrefstate->prevnull = false;
} }
} }
/* /*
* Evaluate ArrayRef assignment. * Evaluate SubscriptingRef assignment.
* *
* Input array (possibly null) is in result area, replacement value is in * Input container (possibly null) is in result area, replacement value is in
* ArrayRefState's replacevalue/replacenull. * SubscriptingRefState's replacevalue/replacenull.
*/ */
void void
ExecEvalArrayRefAssign(ExprState *state, ExprEvalStep *op) ExecEvalSubscriptingRefAssign(ExprState *state, ExprEvalStep *op)
{ {
ArrayRefState *arefstate = op->d.arrayref.state; SubscriptingRefState *sbsrefstate = op->d.sbsref_subscript.state;
/* /*
* For an assignment to a fixed-length array type, both the original array * For an assignment to a fixed-length container type, both the original
* and the value to be assigned into it must be non-NULL, else we punt and * container and the value to be assigned into it must be non-NULL, else
* return the original array. * we punt and return the original container.
*/ */
if (arefstate->refattrlength > 0) /* fixed-length array? */ if (sbsrefstate->refattrlength > 0)
{ {
if (*op->resnull || arefstate->replacenull) if (*op->resnull || sbsrefstate->replacenull)
return; return;
} }
@ -3202,38 +3202,38 @@ ExecEvalArrayRefAssign(ExprState *state, ExprEvalStep *op)
*/ */
if (*op->resnull) if (*op->resnull)
{ {
*op->resvalue = PointerGetDatum(construct_empty_array(arefstate->refelemtype)); *op->resvalue = PointerGetDatum(construct_empty_array(sbsrefstate->refelemtype));
*op->resnull = false; *op->resnull = false;
} }
if (arefstate->numlower == 0) if (sbsrefstate->numlower == 0)
{ {
/* Scalar case */ /* Scalar case */
*op->resvalue = array_set_element(*op->resvalue, *op->resvalue = array_set_element(*op->resvalue,
arefstate->numupper, sbsrefstate->numupper,
arefstate->upperindex, sbsrefstate->upperindex,
arefstate->replacevalue, sbsrefstate->replacevalue,
arefstate->replacenull, sbsrefstate->replacenull,
arefstate->refattrlength, sbsrefstate->refattrlength,
arefstate->refelemlength, sbsrefstate->refelemlength,
arefstate->refelembyval, sbsrefstate->refelembyval,
arefstate->refelemalign); sbsrefstate->refelemalign);
} }
else else
{ {
/* Slice case */ /* Slice case */
*op->resvalue = array_set_slice(*op->resvalue, *op->resvalue = array_set_slice(*op->resvalue,
arefstate->numupper, sbsrefstate->numupper,
arefstate->upperindex, sbsrefstate->upperindex,
arefstate->lowerindex, sbsrefstate->lowerindex,
arefstate->upperprovided, sbsrefstate->upperprovided,
arefstate->lowerprovided, sbsrefstate->lowerprovided,
arefstate->replacevalue, sbsrefstate->replacevalue,
arefstate->replacenull, sbsrefstate->replacenull,
arefstate->refattrlength, sbsrefstate->refattrlength,
arefstate->refelemlength, sbsrefstate->refelemlength,
arefstate->refelembyval, sbsrefstate->refelembyval,
arefstate->refelemalign); sbsrefstate->refelemalign);
} }
} }

View File

@ -85,7 +85,7 @@ LLVMValueRef FuncVarsizeAny;
LLVMValueRef FuncSlotGetsomeattrsInt; LLVMValueRef FuncSlotGetsomeattrsInt;
LLVMValueRef FuncSlotGetmissingattrs; LLVMValueRef FuncSlotGetmissingattrs;
LLVMValueRef FuncMakeExpandedObjectReadOnlyInternal; LLVMValueRef FuncMakeExpandedObjectReadOnlyInternal;
LLVMValueRef FuncExecEvalArrayRefSubscript; LLVMValueRef FuncExecEvalSubscriptingRef;
LLVMValueRef FuncExecEvalSysVar; LLVMValueRef FuncExecEvalSysVar;
LLVMValueRef FuncExecAggTransReparent; LLVMValueRef FuncExecAggTransReparent;
LLVMValueRef FuncExecAggInitGroup; LLVMValueRef FuncExecAggInitGroup;
@ -829,7 +829,7 @@ llvm_create_types(void)
FuncSlotGetsomeattrsInt = LLVMGetNamedFunction(mod, "slot_getsomeattrs_int"); FuncSlotGetsomeattrsInt = LLVMGetNamedFunction(mod, "slot_getsomeattrs_int");
FuncSlotGetmissingattrs = LLVMGetNamedFunction(mod, "slot_getmissingattrs"); FuncSlotGetmissingattrs = LLVMGetNamedFunction(mod, "slot_getmissingattrs");
FuncMakeExpandedObjectReadOnlyInternal = LLVMGetNamedFunction(mod, "MakeExpandedObjectReadOnlyInternal"); FuncMakeExpandedObjectReadOnlyInternal = LLVMGetNamedFunction(mod, "MakeExpandedObjectReadOnlyInternal");
FuncExecEvalArrayRefSubscript = LLVMGetNamedFunction(mod, "ExecEvalArrayRefSubscript"); FuncExecEvalSubscriptingRef = LLVMGetNamedFunction(mod, "ExecEvalSubscriptingRef");
FuncExecEvalSysVar = LLVMGetNamedFunction(mod, "ExecEvalSysVar"); FuncExecEvalSysVar = LLVMGetNamedFunction(mod, "ExecEvalSysVar");
FuncExecAggTransReparent = LLVMGetNamedFunction(mod, "ExecAggTransReparent"); FuncExecAggTransReparent = LLVMGetNamedFunction(mod, "ExecAggTransReparent");
FuncExecAggInitGroup = LLVMGetNamedFunction(mod, "ExecAggInitGroup"); FuncExecAggInitGroup = LLVMGetNamedFunction(mod, "ExecAggInitGroup");

View File

@ -1144,20 +1144,20 @@ llvm_compile_expr(ExprState *state)
break; break;
} }
case EEOP_ARRAYREF_OLD: case EEOP_SBSREF_OLD:
build_EvalXFunc(b, mod, "ExecEvalArrayRefOld", build_EvalXFunc(b, mod, "ExecEvalSubscriptingRefOld",
v_state, v_econtext, op); v_state, v_econtext, op);
LLVMBuildBr(b, opblocks[i + 1]); LLVMBuildBr(b, opblocks[i + 1]);
break; break;
case EEOP_ARRAYREF_ASSIGN: case EEOP_SBSREF_ASSIGN:
build_EvalXFunc(b, mod, "ExecEvalArrayRefAssign", build_EvalXFunc(b, mod, "ExecEvalSubscriptingRefAssign",
v_state, v_econtext, op); v_state, v_econtext, op);
LLVMBuildBr(b, opblocks[i + 1]); LLVMBuildBr(b, opblocks[i + 1]);
break; break;
case EEOP_ARRAYREF_FETCH: case EEOP_SBSREF_FETCH:
build_EvalXFunc(b, mod, "ExecEvalArrayRefFetch", build_EvalXFunc(b, mod, "ExecEvalSubscriptingRefFetch",
v_state, v_econtext, op); v_state, v_econtext, op);
LLVMBuildBr(b, opblocks[i + 1]); LLVMBuildBr(b, opblocks[i + 1]);
break; break;
@ -1775,14 +1775,14 @@ llvm_compile_expr(ExprState *state)
LLVMBuildBr(b, opblocks[i + 1]); LLVMBuildBr(b, opblocks[i + 1]);
break; break;
case EEOP_ARRAYREF_SUBSCRIPT: case EEOP_SBSREF_SUBSCRIPT:
{ {
LLVMValueRef v_fn; LLVMValueRef v_fn;
int jumpdone = op->d.arrayref_subscript.jumpdone; int jumpdone = op->d.sbsref_subscript.jumpdone;
LLVMValueRef v_params[2]; LLVMValueRef v_params[2];
LLVMValueRef v_ret; LLVMValueRef v_ret;
v_fn = llvm_get_decl(mod, FuncExecEvalArrayRefSubscript); v_fn = llvm_get_decl(mod, FuncExecEvalSubscriptingRef);
v_params[0] = v_state; v_params[0] = v_state;
v_params[1] = l_ptr_const(op, l_ptr(StructExprEvalStep)); v_params[1] = l_ptr_const(op, l_ptr(StructExprEvalStep));

View File

@ -103,7 +103,7 @@ void *referenced_functions[] =
slot_getsomeattrs_int, slot_getsomeattrs_int,
slot_getmissingattrs, slot_getmissingattrs,
MakeExpandedObjectReadOnlyInternal, MakeExpandedObjectReadOnlyInternal,
ExecEvalArrayRefSubscript, ExecEvalSubscriptingRef,
ExecEvalSysVar, ExecEvalSysVar,
ExecAggTransReparent, ExecAggTransReparent,
ExecAggInitGroup ExecAggInitGroup

View File

@ -1486,14 +1486,14 @@ _copyWindowFunc(const WindowFunc *from)
} }
/* /*
* _copyArrayRef * _copySubscriptingRef
*/ */
static ArrayRef * static SubscriptingRef *
_copyArrayRef(const ArrayRef *from) _copySubscriptingRef(const SubscriptingRef *from)
{ {
ArrayRef *newnode = makeNode(ArrayRef); SubscriptingRef *newnode = makeNode(SubscriptingRef);
COPY_SCALAR_FIELD(refarraytype); COPY_SCALAR_FIELD(refcontainertype);
COPY_SCALAR_FIELD(refelemtype); COPY_SCALAR_FIELD(refelemtype);
COPY_SCALAR_FIELD(reftypmod); COPY_SCALAR_FIELD(reftypmod);
COPY_SCALAR_FIELD(refcollid); COPY_SCALAR_FIELD(refcollid);
@ -4963,8 +4963,8 @@ copyObjectImpl(const void *from)
case T_WindowFunc: case T_WindowFunc:
retval = _copyWindowFunc(from); retval = _copyWindowFunc(from);
break; break;
case T_ArrayRef: case T_SubscriptingRef:
retval = _copyArrayRef(from); retval = _copySubscriptingRef(from);
break; break;
case T_FuncExpr: case T_FuncExpr:
retval = _copyFuncExpr(from); retval = _copyFuncExpr(from);

View File

@ -265,9 +265,9 @@ _equalWindowFunc(const WindowFunc *a, const WindowFunc *b)
} }
static bool static bool
_equalArrayRef(const ArrayRef *a, const ArrayRef *b) _equalSubscriptingRef(const SubscriptingRef *a, const SubscriptingRef *b)
{ {
COMPARE_SCALAR_FIELD(refarraytype); COMPARE_SCALAR_FIELD(refcontainertype);
COMPARE_SCALAR_FIELD(refelemtype); COMPARE_SCALAR_FIELD(refelemtype);
COMPARE_SCALAR_FIELD(reftypmod); COMPARE_SCALAR_FIELD(reftypmod);
COMPARE_SCALAR_FIELD(refcollid); COMPARE_SCALAR_FIELD(refcollid);
@ -3041,8 +3041,8 @@ equal(const void *a, const void *b)
case T_WindowFunc: case T_WindowFunc:
retval = _equalWindowFunc(a, b); retval = _equalWindowFunc(a, b);
break; break;
case T_ArrayRef: case T_SubscriptingRef:
retval = _equalArrayRef(a, b); retval = _equalSubscriptingRef(a, b);
break; break;
case T_FuncExpr: case T_FuncExpr:
retval = _equalFuncExpr(a, b); retval = _equalFuncExpr(a, b);

View File

@ -66,15 +66,15 @@ exprType(const Node *expr)
case T_WindowFunc: case T_WindowFunc:
type = ((const WindowFunc *) expr)->wintype; type = ((const WindowFunc *) expr)->wintype;
break; break;
case T_ArrayRef: case T_SubscriptingRef:
{ {
const ArrayRef *arrayref = (const ArrayRef *) expr; const SubscriptingRef *sbsref = (const SubscriptingRef *) expr;
/* slice and/or store operations yield the array type */ /* slice and/or store operations yield the container type */
if (arrayref->reflowerindexpr || arrayref->refassgnexpr) if (sbsref->reflowerindexpr || sbsref->refassgnexpr)
type = arrayref->refarraytype; type = sbsref->refcontainertype;
else else
type = arrayref->refelemtype; type = sbsref->refelemtype;
} }
break; break;
case T_FuncExpr: case T_FuncExpr:
@ -286,9 +286,9 @@ exprTypmod(const Node *expr)
return ((const Const *) expr)->consttypmod; return ((const Const *) expr)->consttypmod;
case T_Param: case T_Param:
return ((const Param *) expr)->paramtypmod; return ((const Param *) expr)->paramtypmod;
case T_ArrayRef: case T_SubscriptingRef:
/* typmod is the same for array or element */ /* typmod is the same for container or element */
return ((const ArrayRef *) expr)->reftypmod; return ((const SubscriptingRef *) expr)->reftypmod;
case T_FuncExpr: case T_FuncExpr:
{ {
int32 coercedTypmod; int32 coercedTypmod;
@ -744,8 +744,8 @@ exprCollation(const Node *expr)
case T_WindowFunc: case T_WindowFunc:
coll = ((const WindowFunc *) expr)->wincollid; coll = ((const WindowFunc *) expr)->wincollid;
break; break;
case T_ArrayRef: case T_SubscriptingRef:
coll = ((const ArrayRef *) expr)->refcollid; coll = ((const SubscriptingRef *) expr)->refcollid;
break; break;
case T_FuncExpr: case T_FuncExpr:
coll = ((const FuncExpr *) expr)->funccollid; coll = ((const FuncExpr *) expr)->funccollid;
@ -992,8 +992,8 @@ exprSetCollation(Node *expr, Oid collation)
case T_WindowFunc: case T_WindowFunc:
((WindowFunc *) expr)->wincollid = collation; ((WindowFunc *) expr)->wincollid = collation;
break; break;
case T_ArrayRef: case T_SubscriptingRef:
((ArrayRef *) expr)->refcollid = collation; ((SubscriptingRef *) expr)->refcollid = collation;
break; break;
case T_FuncExpr: case T_FuncExpr:
((FuncExpr *) expr)->funccollid = collation; ((FuncExpr *) expr)->funccollid = collation;
@ -1223,9 +1223,9 @@ exprLocation(const Node *expr)
/* function name should always be the first thing */ /* function name should always be the first thing */
loc = ((const WindowFunc *) expr)->location; loc = ((const WindowFunc *) expr)->location;
break; break;
case T_ArrayRef: case T_SubscriptingRef:
/* just use array argument's location */ /* just use container argument's location */
loc = exprLocation((Node *) ((const ArrayRef *) expr)->refexpr); loc = exprLocation((Node *) ((const SubscriptingRef *) expr)->refexpr);
break; break;
case T_FuncExpr: case T_FuncExpr:
{ {
@ -1916,21 +1916,22 @@ expression_tree_walker(Node *node,
return true; return true;
} }
break; break;
case T_ArrayRef: case T_SubscriptingRef:
{ {
ArrayRef *aref = (ArrayRef *) node; SubscriptingRef *sbsref = (SubscriptingRef *) node;
/* recurse directly for upper/lower array index lists */ /* recurse directly for upper/lower container index lists */
if (expression_tree_walker((Node *) aref->refupperindexpr, if (expression_tree_walker((Node *) sbsref->refupperindexpr,
walker, context)) walker, context))
return true; return true;
if (expression_tree_walker((Node *) aref->reflowerindexpr, if (expression_tree_walker((Node *) sbsref->reflowerindexpr,
walker, context)) walker, context))
return true; return true;
/* walker must see the refexpr and refassgnexpr, however */ /* walker must see the refexpr and refassgnexpr, however */
if (walker(aref->refexpr, context)) if (walker(sbsref->refexpr, context))
return true; return true;
if (walker(aref->refassgnexpr, context))
if (walker(sbsref->refassgnexpr, context))
return true; return true;
} }
break; break;
@ -2554,20 +2555,21 @@ expression_tree_mutator(Node *node,
return (Node *) newnode; return (Node *) newnode;
} }
break; break;
case T_ArrayRef: case T_SubscriptingRef:
{ {
ArrayRef *arrayref = (ArrayRef *) node; SubscriptingRef *sbsref = (SubscriptingRef *) node;
ArrayRef *newnode; SubscriptingRef *newnode;
FLATCOPY(newnode, arrayref, ArrayRef); FLATCOPY(newnode, sbsref, SubscriptingRef);
MUTATE(newnode->refupperindexpr, arrayref->refupperindexpr, MUTATE(newnode->refupperindexpr, sbsref->refupperindexpr,
List *); List *);
MUTATE(newnode->reflowerindexpr, arrayref->reflowerindexpr, MUTATE(newnode->reflowerindexpr, sbsref->reflowerindexpr,
List *); List *);
MUTATE(newnode->refexpr, arrayref->refexpr, MUTATE(newnode->refexpr, sbsref->refexpr,
Expr *); Expr *);
MUTATE(newnode->refassgnexpr, arrayref->refassgnexpr, MUTATE(newnode->refassgnexpr, sbsref->refassgnexpr,
Expr *); Expr *);
return (Node *) newnode; return (Node *) newnode;
} }
break; break;

View File

@ -1153,11 +1153,11 @@ _outWindowFunc(StringInfo str, const WindowFunc *node)
} }
static void static void
_outArrayRef(StringInfo str, const ArrayRef *node) _outSubscriptingRef(StringInfo str, const SubscriptingRef *node)
{ {
WRITE_NODE_TYPE("ARRAYREF"); WRITE_NODE_TYPE("SUBSCRIPTINGREF");
WRITE_OID_FIELD(refarraytype); WRITE_OID_FIELD(refcontainertype);
WRITE_OID_FIELD(refelemtype); WRITE_OID_FIELD(refelemtype);
WRITE_INT_FIELD(reftypmod); WRITE_INT_FIELD(reftypmod);
WRITE_OID_FIELD(refcollid); WRITE_OID_FIELD(refcollid);
@ -3789,8 +3789,8 @@ outNode(StringInfo str, const void *obj)
case T_WindowFunc: case T_WindowFunc:
_outWindowFunc(str, obj); _outWindowFunc(str, obj);
break; break;
case T_ArrayRef: case T_SubscriptingRef:
_outArrayRef(str, obj); _outSubscriptingRef(str, obj);
break; break;
case T_FuncExpr: case T_FuncExpr:
_outFuncExpr(str, obj); _outFuncExpr(str, obj);

View File

@ -657,14 +657,14 @@ _readWindowFunc(void)
} }
/* /*
* _readArrayRef * _readSubscriptingRef
*/ */
static ArrayRef * static SubscriptingRef *
_readArrayRef(void) _readSubscriptingRef(void)
{ {
READ_LOCALS(ArrayRef); READ_LOCALS(SubscriptingRef);
READ_OID_FIELD(refarraytype); READ_OID_FIELD(refcontainertype);
READ_OID_FIELD(refelemtype); READ_OID_FIELD(refelemtype);
READ_INT_FIELD(reftypmod); READ_INT_FIELD(reftypmod);
READ_OID_FIELD(refcollid); READ_OID_FIELD(refcollid);
@ -2597,8 +2597,8 @@ parseNodeString(void)
return_value = _readGroupingFunc(); return_value = _readGroupingFunc();
else if (MATCH("WINDOWFUNC", 10)) else if (MATCH("WINDOWFUNC", 10))
return_value = _readWindowFunc(); return_value = _readWindowFunc();
else if (MATCH("ARRAYREF", 8)) else if (MATCH("SUBSCRIPTINGREF", 15))
return_value = _readArrayRef(); return_value = _readSubscriptingRef();
else if (MATCH("FUNCEXPR", 8)) else if (MATCH("FUNCEXPR", 8))
return_value = _readFuncExpr(); return_value = _readFuncExpr();
else if (MATCH("NAMEDARGEXPR", 12)) else if (MATCH("NAMEDARGEXPR", 12))

View File

@ -1120,11 +1120,15 @@ contain_nonstrict_functions_walker(Node *node, void *context)
/* a window function could return non-null with null input */ /* a window function could return non-null with null input */
return true; return true;
} }
if (IsA(node, ArrayRef)) if (IsA(node, SubscriptingRef))
{ {
/* array assignment is nonstrict, but subscripting is strict */ /*
if (((ArrayRef *) node)->refassgnexpr != NULL) * subscripting assignment is nonstrict, but subscripting itself is
* strict
*/
if (((SubscriptingRef *) node)->refassgnexpr != NULL)
return true; return true;
/* else fall through to check args */ /* else fall through to check args */
} }
if (IsA(node, DistinctExpr)) if (IsA(node, DistinctExpr))
@ -1328,7 +1332,6 @@ contain_leaked_vars_walker(Node *node, void *context)
case T_Var: case T_Var:
case T_Const: case T_Const:
case T_Param: case T_Param:
case T_ArrayRef:
case T_ArrayExpr: case T_ArrayExpr:
case T_FieldSelect: case T_FieldSelect:
case T_FieldStore: case T_FieldStore:
@ -1358,6 +1361,7 @@ contain_leaked_vars_walker(Node *node, void *context)
case T_ScalarArrayOpExpr: case T_ScalarArrayOpExpr:
case T_CoerceViaIO: case T_CoerceViaIO:
case T_ArrayCoerceExpr: case T_ArrayCoerceExpr:
case T_SubscriptingRef:
/* /*
* If node contains a leaky function call, and there's any Var * If node contains a leaky function call, and there's any Var
@ -3181,7 +3185,7 @@ eval_const_expressions_mutator(Node *node,
else else
return copyObject(node); return copyObject(node);
} }
case T_ArrayRef: case T_SubscriptingRef:
case T_ArrayExpr: case T_ArrayExpr:
case T_RowExpr: case T_RowExpr:
case T_MinMaxExpr: case T_MinMaxExpr:

View File

@ -976,13 +976,14 @@ transformInsertRow(ParseState *pstate, List *exprlist,
expr = (Expr *) linitial(fstore->newvals); expr = (Expr *) linitial(fstore->newvals);
} }
else if (IsA(expr, ArrayRef)) else if (IsA(expr, SubscriptingRef))
{ {
ArrayRef *aref = (ArrayRef *) expr; SubscriptingRef *sbsref = (SubscriptingRef *) expr;
if (aref->refassgnexpr == NULL) if (sbsref->refassgnexpr == NULL)
break; break;
expr = aref->refassgnexpr;
expr = sbsref->refassgnexpr;
} }
else else
break; break;

View File

@ -465,13 +465,13 @@ transformIndirection(ParseState *pstate, A_Indirection *ind)
/* process subscripts before this field selection */ /* process subscripts before this field selection */
if (subscripts) if (subscripts)
result = (Node *) transformArraySubscripts(pstate, result = (Node *) transformContainerSubscripts(pstate,
result, result,
exprType(result), exprType(result),
InvalidOid, InvalidOid,
exprTypmod(result), exprTypmod(result),
subscripts, subscripts,
NULL); NULL);
subscripts = NIL; subscripts = NIL;
newresult = ParseFuncOrColumn(pstate, newresult = ParseFuncOrColumn(pstate,
@ -488,13 +488,13 @@ transformIndirection(ParseState *pstate, A_Indirection *ind)
} }
/* process trailing subscripts, if any */ /* process trailing subscripts, if any */
if (subscripts) if (subscripts)
result = (Node *) transformArraySubscripts(pstate, result = (Node *) transformContainerSubscripts(pstate,
result, result,
exprType(result), exprType(result),
InvalidOid, InvalidOid,
exprTypmod(result), exprTypmod(result),
subscripts, subscripts,
NULL); NULL);
return result; return result;
} }

View File

@ -203,121 +203,126 @@ make_var(ParseState *pstate, RangeTblEntry *rte, int attrno, int location)
} }
/* /*
* transformArrayType() * transformContainerType()
* Identify the types involved in a subscripting operation * Identify the types involved in a subscripting operation for container
* *
* On entry, arrayType/arrayTypmod identify the type of the input value *
* to be subscripted (which could be a domain type). These are modified * On entry, containerType/containerTypmod identify the type of the input value
* if necessary to identify the actual array type and typmod, and the * to be subscripted (which could be a domain type). These are modified if
* array's element type is returned. An error is thrown if the input isn't * necessary to identify the actual container type and typmod, and the
* container's element type is returned. An error is thrown if the input isn't
* an array type. * an array type.
*/ */
Oid Oid
transformArrayType(Oid *arrayType, int32 *arrayTypmod) transformContainerType(Oid *containerType, int32 *containerTypmod)
{ {
Oid origArrayType = *arrayType; Oid origContainerType = *containerType;
Oid elementType; Oid elementType;
HeapTuple type_tuple_array; HeapTuple type_tuple_container;
Form_pg_type type_struct_array; Form_pg_type type_struct_container;
/* /*
* If the input is a domain, smash to base type, and extract the actual * If the input is a domain, smash to base type, and extract the actual
* typmod to be applied to the base type. Subscripting a domain is an * typmod to be applied to the base type. Subscripting a domain is an
* operation that necessarily works on the base array type, not the domain * operation that necessarily works on the base container type, not the
* itself. (Note that we provide no method whereby the creator of a * domain itself. (Note that we provide no method whereby the creator of a
* domain over an array type could hide its ability to be subscripted.) * domain over a container type could hide its ability to be subscripted.)
*/ */
*arrayType = getBaseTypeAndTypmod(*arrayType, arrayTypmod); *containerType = getBaseTypeAndTypmod(*containerType, containerTypmod);
/* /*
* We treat int2vector and oidvector as though they were domains over * Here is an array specific code. We treat int2vector and oidvector as
* int2[] and oid[]. This is needed because array slicing could create an * though they were domains over int2[] and oid[]. This is needed because
* array that doesn't satisfy the dimensionality constraints of the * array slicing could create an array that doesn't satisfy the
* xxxvector type; so we want the result of a slice operation to be * dimensionality constraints of the xxxvector type; so we want the result
* considered to be of the more general type. * of a slice operation to be considered to be of the more general type.
*/ */
if (*arrayType == INT2VECTOROID) if (*containerType == INT2VECTOROID)
*arrayType = INT2ARRAYOID; *containerType = INT2ARRAYOID;
else if (*arrayType == OIDVECTOROID) else if (*containerType == OIDVECTOROID)
*arrayType = OIDARRAYOID; *containerType = OIDARRAYOID;
/* Get the type tuple for the array */ /* Get the type tuple for the container */
type_tuple_array = SearchSysCache1(TYPEOID, ObjectIdGetDatum(*arrayType)); type_tuple_container = SearchSysCache1(TYPEOID, ObjectIdGetDatum(*containerType));
if (!HeapTupleIsValid(type_tuple_array)) if (!HeapTupleIsValid(type_tuple_container))
elog(ERROR, "cache lookup failed for type %u", *arrayType); elog(ERROR, "cache lookup failed for type %u", *containerType);
type_struct_array = (Form_pg_type) GETSTRUCT(type_tuple_array); type_struct_container = (Form_pg_type) GETSTRUCT(type_tuple_container);
/* needn't check typisdefined since this will fail anyway */ /* needn't check typisdefined since this will fail anyway */
elementType = type_struct_array->typelem; elementType = type_struct_container->typelem;
if (elementType == InvalidOid) if (elementType == InvalidOid)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH), (errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("cannot subscript type %s because it is not an array", errmsg("cannot subscript type %s because it is not an array",
format_type_be(origArrayType)))); format_type_be(origContainerType))));
ReleaseSysCache(type_tuple_array); ReleaseSysCache(type_tuple_container);
return elementType; return elementType;
} }
/* /*
* transformArraySubscripts() * transformContainerSubscripts()
* Transform array subscripting. This is used for both * Transform container (array, etc) subscripting. This is used for both
* array fetch and array assignment. * container fetch and container assignment.
* *
* In an array fetch, we are given a source array value and we produce an * In a container fetch, we are given a source container value and we produce
* expression that represents the result of extracting a single array element * an expression that represents the result of extracting a single container
* or an array slice. * element or a container slice.
* *
* In an array assignment, we are given a destination array value plus a * In a container assignment, we are given a destination container value plus a
* source value that is to be assigned to a single element or a slice of * source value that is to be assigned to a single element or a slice of that
* that array. We produce an expression that represents the new array value * container. We produce an expression that represents the new container value
* with the source data inserted into the right part of the array. * with the source data inserted into the right part of the container.
* *
* For both cases, if the source array is of a domain-over-array type, * For both cases, if the source container is of a domain-over-array type,
* the result is of the base array type or its element type; essentially, * the result is of the base array type or its element type; essentially,
* we must fold a domain to its base type before applying subscripting. * we must fold a domain to its base type before applying subscripting.
* (Note that int2vector and oidvector are treated as domains here.) * (Note that int2vector and oidvector are treated as domains here.)
* *
* pstate Parse state * pstate Parse state
* arrayBase Already-transformed expression for the array as a whole * containerBase Already-transformed expression for the container as a whole
* arrayType OID of array's datatype (should match type of arrayBase, * containerType OID of container's datatype (should match type of
* or be the base type of arrayBase's domain type) * containerBase, or be the base type of containerBase's
* elementType OID of array's element type (fetch with transformArrayType, * domain type)
* or pass InvalidOid to do it here) * elementType OID of container's element type (fetch with
* arrayTypMod typmod for the array (which is also typmod for the elements) * transformContainerType, or pass InvalidOid to do it here)
* indirection Untransformed list of subscripts (must not be NIL) * containerTypMod typmod for the container (which is also typmod for the
* assignFrom NULL for array fetch, else transformed expression for source. * elements)
* indirection Untransformed list of subscripts (must not be NIL)
* assignFrom NULL for container fetch, else transformed expression for
* source.
*/ */
ArrayRef * SubscriptingRef *
transformArraySubscripts(ParseState *pstate, transformContainerSubscripts(ParseState *pstate,
Node *arrayBase, Node *containerBase,
Oid arrayType, Oid containerType,
Oid elementType, Oid elementType,
int32 arrayTypMod, int32 containerTypMod,
List *indirection, List *indirection,
Node *assignFrom) Node *assignFrom)
{ {
bool isSlice = false; bool isSlice = false;
List *upperIndexpr = NIL; List *upperIndexpr = NIL;
List *lowerIndexpr = NIL; List *lowerIndexpr = NIL;
List *indexprSlice = NIL;
ListCell *idx; ListCell *idx;
ArrayRef *aref; SubscriptingRef *sbsref;
/* /*
* Caller may or may not have bothered to determine elementType. Note * Caller may or may not have bothered to determine elementType. Note
* that if the caller did do so, arrayType/arrayTypMod must be as modified * that if the caller did do so, containerType/containerTypMod must be as
* by transformArrayType, ie, smash domain to base type. * modified by transformContainerType, ie, smash domain to base type.
*/ */
if (!OidIsValid(elementType)) if (!OidIsValid(elementType))
elementType = transformArrayType(&arrayType, &arrayTypMod); elementType = transformContainerType(&containerType, &containerTypMod);
/* /*
* A list containing only simple subscripts refers to a single array * A list containing only simple subscripts refers to a single container
* element. If any of the items are slice specifiers (lower:upper), then * element. If any of the items are slice specifiers (lower:upper), then
* the subscript expression means an array slice operation. In this case, * the subscript expression means a container slice operation. In this
* we convert any non-slice items to slices by treating the single * 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. * 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. * We have to prescan the list to see if there are any slice items.
*/ */
@ -411,12 +416,12 @@ transformArraySubscripts(ParseState *pstate,
if (assignFrom != NULL) if (assignFrom != NULL)
{ {
Oid typesource = exprType(assignFrom); Oid typesource = exprType(assignFrom);
Oid typeneeded = isSlice ? arrayType : elementType; Oid typeneeded = isSlice ? containerType : elementType;
Node *newFrom; Node *newFrom;
newFrom = coerce_to_target_type(pstate, newFrom = coerce_to_target_type(pstate,
assignFrom, typesource, assignFrom, typesource,
typeneeded, arrayTypMod, typeneeded, containerTypMod,
COERCION_ASSIGNMENT, COERCION_ASSIGNMENT,
COERCE_IMPLICIT_CAST, COERCE_IMPLICIT_CAST,
-1); -1);
@ -433,19 +438,23 @@ transformArraySubscripts(ParseState *pstate,
} }
/* /*
* Ready to build the ArrayRef node. * Ready to build the SubscriptingRef node.
*/ */
aref = makeNode(ArrayRef); sbsref = (SubscriptingRef *) makeNode(SubscriptingRef);
aref->refarraytype = arrayType; if (assignFrom != NULL)
aref->refelemtype = elementType; sbsref->refassgnexpr = (Expr *) assignFrom;
aref->reftypmod = arrayTypMod;
/* refcollid will be set by parse_collate.c */
aref->refupperindexpr = upperIndexpr;
aref->reflowerindexpr = lowerIndexpr;
aref->refexpr = (Expr *) arrayBase;
aref->refassgnexpr = (Expr *) assignFrom;
return aref; sbsref->refcontainertype = containerType;
sbsref->refelemtype = elementType;
sbsref->reftypmod = containerTypMod;
/* refcollid will be set by parse_collate.c */
sbsref->refupperindexpr = upperIndexpr;
sbsref->reflowerindexpr = lowerIndexpr;
sbsref->refindexprslice = indexprSlice;
sbsref->refexpr = (Expr *) containerBase;
sbsref->refassgnexpr = (Expr *) assignFrom;
return sbsref;
} }
/* /*

View File

@ -655,7 +655,7 @@ updateTargetListEntry(ParseState *pstate,
* needed. * needed.
* *
* targetName is the name of the field or subfield we're assigning to, and * targetName is the name of the field or subfield we're assigning to, and
* targetIsArray is true if we're subscripting it. These are just for * targetIsSubscripting is true if we're subscripting it. These are just for
* error reporting. * error reporting.
* *
* targetTypeId, targetTypMod, targetCollation indicate the datatype and * targetTypeId, targetTypMod, targetCollation indicate the datatype and
@ -677,7 +677,7 @@ static Node *
transformAssignmentIndirection(ParseState *pstate, transformAssignmentIndirection(ParseState *pstate,
Node *basenode, Node *basenode,
const char *targetName, const char *targetName,
bool targetIsArray, bool targetIsSubscripting,
Oid targetTypeId, Oid targetTypeId,
int32 targetTypMod, int32 targetTypMod,
Oid targetCollation, Oid targetCollation,
@ -855,7 +855,7 @@ transformAssignmentIndirection(ParseState *pstate,
-1); -1);
if (result == NULL) if (result == NULL)
{ {
if (targetIsArray) if (targetIsSubscripting)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH), (errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("array assignment to \"%s\" requires type %s" errmsg("array assignment to \"%s\" requires type %s"
@ -881,7 +881,7 @@ transformAssignmentIndirection(ParseState *pstate,
} }
/* /*
* helper for transformAssignmentIndirection: process array assignment * helper for transformAssignmentIndirection: process container assignment
*/ */
static Node * static Node *
transformAssignmentSubscripts(ParseState *pstate, transformAssignmentSubscripts(ParseState *pstate,
@ -897,8 +897,8 @@ transformAssignmentSubscripts(ParseState *pstate,
int location) int location)
{ {
Node *result; Node *result;
Oid arrayType; Oid containerType;
int32 arrayTypMod; int32 containerTypMod;
Oid elementTypeId; Oid elementTypeId;
Oid typeNeeded; Oid typeNeeded;
Oid collationNeeded; Oid collationNeeded;
@ -906,46 +906,46 @@ transformAssignmentSubscripts(ParseState *pstate,
Assert(subscripts != NIL); Assert(subscripts != NIL);
/* Identify the actual array type and element type involved */ /* Identify the actual array type and element type involved */
arrayType = targetTypeId; containerType = targetTypeId;
arrayTypMod = targetTypMod; containerTypMod = targetTypMod;
elementTypeId = transformArrayType(&arrayType, &arrayTypMod); elementTypeId = transformContainerType(&containerType, &containerTypMod);
/* Identify type that RHS must provide */ /* Identify type that RHS must provide */
typeNeeded = isSlice ? arrayType : elementTypeId; typeNeeded = isSlice ? containerType : elementTypeId;
/* /*
* Array normally has same collation as elements, but there's an * container normally has same collation as elements, but there's an
* exception: we might be subscripting a domain over an array type. In * exception: we might be subscripting a domain over a container type. In
* that case use collation of the base type. * that case use collation of the base type.
*/ */
if (arrayType == targetTypeId) if (containerType == targetTypeId)
collationNeeded = targetCollation; collationNeeded = targetCollation;
else else
collationNeeded = get_typcollation(arrayType); collationNeeded = get_typcollation(containerType);
/* recurse to create appropriate RHS for array assign */ /* recurse to create appropriate RHS for container assign */
rhs = transformAssignmentIndirection(pstate, rhs = transformAssignmentIndirection(pstate,
NULL, NULL,
targetName, targetName,
true, true,
typeNeeded, typeNeeded,
arrayTypMod, containerTypMod,
collationNeeded, collationNeeded,
next_indirection, next_indirection,
rhs, rhs,
location); location);
/* process subscripts */ /* process subscripts */
result = (Node *) transformArraySubscripts(pstate, result = (Node *) transformContainerSubscripts(pstate,
basenode, basenode,
arrayType, containerType,
elementTypeId, elementTypeId,
arrayTypMod, containerTypMod,
subscripts, subscripts,
rhs); rhs);
/* If target was a domain over array, need to coerce up to the domain */ /* If target was a domain over container, need to coerce up to the domain */
if (arrayType != targetTypeId) if (containerType != targetTypeId)
{ {
Oid resulttype = exprType(result); Oid resulttype = exprType(result);

View File

@ -951,7 +951,7 @@ process_matched_tle(TargetEntry *src_tle,
/*---------- /*----------
* Multiple assignments to same attribute. Allow only if all are * Multiple assignments to same attribute. Allow only if all are
* FieldStore or ArrayRef assignment operations. This is a bit * FieldStore or SubscriptingRef assignment operations. This is a bit
* tricky because what we may actually be looking at is a nest of * tricky because what we may actually be looking at is a nest of
* such nodes; consider * such nodes; consider
* UPDATE tab SET col.fld1.subfld1 = x, col.fld2.subfld2 = y * UPDATE tab SET col.fld1.subfld1 = x, col.fld2.subfld2 = y
@ -959,7 +959,7 @@ process_matched_tle(TargetEntry *src_tle,
* FieldStore(col, fld1, FieldStore(placeholder, subfld1, x)) * FieldStore(col, fld1, FieldStore(placeholder, subfld1, x))
* FieldStore(col, fld2, FieldStore(placeholder, subfld2, y)) * FieldStore(col, fld2, FieldStore(placeholder, subfld2, y))
* However, we can ignore the substructure and just consider the top * However, we can ignore the substructure and just consider the top
* FieldStore or ArrayRef from each assignment, because it works to * FieldStore or SubscriptingRef from each assignment, because it works to
* combine these as * combine these as
* FieldStore(FieldStore(col, fld1, * FieldStore(FieldStore(col, fld1,
* FieldStore(placeholder, subfld1, x)), * FieldStore(placeholder, subfld1, x)),
@ -969,7 +969,7 @@ process_matched_tle(TargetEntry *src_tle,
* *
* For FieldStore, instead of nesting we can generate a single * For FieldStore, instead of nesting we can generate a single
* FieldStore with multiple target fields. We must nest when * FieldStore with multiple target fields. We must nest when
* ArrayRefs are involved though. * SubscriptingRefs are involved though.
* *
* As a further complication, the destination column might be a domain, * As a further complication, the destination column might be a domain,
* resulting in each assignment containing a CoerceToDomain node over a * resulting in each assignment containing a CoerceToDomain node over a
@ -1048,13 +1048,13 @@ process_matched_tle(TargetEntry *src_tle,
} }
newexpr = (Node *) fstore; newexpr = (Node *) fstore;
} }
else if (IsA(src_expr, ArrayRef)) else if (IsA(src_expr, SubscriptingRef))
{ {
ArrayRef *aref = makeNode(ArrayRef); SubscriptingRef *sbsref = makeNode(SubscriptingRef);
memcpy(aref, src_expr, sizeof(ArrayRef)); memcpy(sbsref, src_expr, sizeof(SubscriptingRef));
aref->refexpr = (Expr *) prior_expr; sbsref->refexpr = (Expr *) prior_expr;
newexpr = (Node *) aref; newexpr = (Node *) sbsref;
} }
else else
{ {
@ -1091,14 +1091,16 @@ get_assignment_input(Node *node)
return (Node *) fstore->arg; return (Node *) fstore->arg;
} }
else if (IsA(node, ArrayRef)) else if (IsA(node, SubscriptingRef))
{ {
ArrayRef *aref = (ArrayRef *) node; SubscriptingRef *sbsref = (SubscriptingRef *) node;
if (aref->refassgnexpr == NULL) if (sbsref->refassgnexpr == NULL)
return NULL; return NULL;
return (Node *) aref->refexpr;
return (Node *) sbsref->refexpr;
} }
return NULL; return NULL;
} }

View File

@ -456,7 +456,7 @@ static void get_tablesample_def(TableSampleClause *tablesample,
static void get_opclass_name(Oid opclass, Oid actual_datatype, static void get_opclass_name(Oid opclass, Oid actual_datatype,
StringInfo buf); StringInfo buf);
static Node *processIndirection(Node *node, deparse_context *context); static Node *processIndirection(Node *node, deparse_context *context);
static void printSubscripts(ArrayRef *aref, deparse_context *context); static void printSubscripts(SubscriptingRef *sbsref, deparse_context *context);
static char *get_relation_name(Oid relid); static char *get_relation_name(Oid relid);
static char *generate_relation_name(Oid relid, List *namespaces); static char *generate_relation_name(Oid relid, List *namespaces);
static char *generate_qualified_relation_name(Oid relid); static char *generate_qualified_relation_name(Oid relid);
@ -6400,12 +6400,12 @@ get_update_query_targetlist_def(Query *query, List *targetList,
{ {
/* /*
* We must dig down into the expr to see if it's a PARAM_MULTIEXPR * We must dig down into the expr to see if it's a PARAM_MULTIEXPR
* Param. That could be buried under FieldStores and ArrayRefs * Param. That could be buried under FieldStores and
* and CoerceToDomains (cf processIndirection()), and underneath * SubscriptingRefs and CoerceToDomains (cf processIndirection()),
* those there could be an implicit type coercion. Because we * and underneath those there could be an implicit type coercion.
* would ignore implicit type coercions anyway, we don't need to * Because we would ignore implicit type coercions anyway, we
* be as careful as processIndirection() is about descending past * don't need to be as careful as processIndirection() is about
* implicit CoerceToDomains. * descending past implicit CoerceToDomains.
*/ */
expr = (Node *) tle->expr; expr = (Node *) tle->expr;
while (expr) while (expr)
@ -6416,13 +6416,14 @@ get_update_query_targetlist_def(Query *query, List *targetList,
expr = (Node *) linitial(fstore->newvals); expr = (Node *) linitial(fstore->newvals);
} }
else if (IsA(expr, ArrayRef)) else if (IsA(expr, SubscriptingRef))
{ {
ArrayRef *aref = (ArrayRef *) expr; SubscriptingRef *sbsref = (SubscriptingRef *) expr;
if (aref->refassgnexpr == NULL) if (sbsref->refassgnexpr == NULL)
break; break;
expr = (Node *) aref->refassgnexpr;
expr = (Node *) sbsref->refassgnexpr;
} }
else if (IsA(expr, CoerceToDomain)) else if (IsA(expr, CoerceToDomain))
{ {
@ -7456,7 +7457,7 @@ isSimpleNode(Node *node, Node *parentNode, int prettyFlags)
/* single words: always simple */ /* single words: always simple */
return true; return true;
case T_ArrayRef: case T_SubscriptingRef:
case T_ArrayExpr: case T_ArrayExpr:
case T_RowExpr: case T_RowExpr:
case T_CoalesceExpr: case T_CoalesceExpr:
@ -7574,7 +7575,7 @@ isSimpleNode(Node *node, Node *parentNode, int prettyFlags)
return true; /* own parentheses */ return true; /* own parentheses */
} }
case T_BoolExpr: /* lower precedence */ case T_BoolExpr: /* lower precedence */
case T_ArrayRef: /* other separators */ case T_SubscriptingRef: /* other separators */
case T_ArrayExpr: /* other separators */ case T_ArrayExpr: /* other separators */
case T_RowExpr: /* other separators */ case T_RowExpr: /* other separators */
case T_CoalesceExpr: /* own parentheses */ case T_CoalesceExpr: /* own parentheses */
@ -7624,7 +7625,7 @@ isSimpleNode(Node *node, Node *parentNode, int prettyFlags)
return false; return false;
return true; /* own parentheses */ return true; /* own parentheses */
} }
case T_ArrayRef: /* other separators */ case T_SubscriptingRef: /* other separators */
case T_ArrayExpr: /* other separators */ case T_ArrayExpr: /* other separators */
case T_RowExpr: /* other separators */ case T_RowExpr: /* other separators */
case T_CoalesceExpr: /* own parentheses */ case T_CoalesceExpr: /* own parentheses */
@ -7810,9 +7811,9 @@ get_rule_expr(Node *node, deparse_context *context,
get_windowfunc_expr((WindowFunc *) node, context); get_windowfunc_expr((WindowFunc *) node, context);
break; break;
case T_ArrayRef: case T_SubscriptingRef:
{ {
ArrayRef *aref = (ArrayRef *) node; SubscriptingRef *sbsref = (SubscriptingRef *) node;
bool need_parens; bool need_parens;
/* /*
@ -7823,37 +7824,38 @@ get_rule_expr(Node *node, deparse_context *context,
* here too, and display only the assignment source * here too, and display only the assignment source
* expression. * expression.
*/ */
if (IsA(aref->refexpr, CaseTestExpr)) if (IsA(sbsref->refexpr, CaseTestExpr))
{ {
Assert(aref->refassgnexpr); Assert(sbsref->refassgnexpr);
get_rule_expr((Node *) aref->refassgnexpr, get_rule_expr((Node *) sbsref->refassgnexpr,
context, showimplicit); context, showimplicit);
break; break;
} }
/* /*
* Parenthesize the argument unless it's a simple Var or a * Parenthesize the argument unless it's a simple Var or a
* FieldSelect. (In particular, if it's another ArrayRef, we * FieldSelect. (In particular, if it's another
* *must* parenthesize to avoid confusion.) * SubscriptingRef, we *must* parenthesize to avoid
* confusion.)
*/ */
need_parens = !IsA(aref->refexpr, Var) && need_parens = !IsA(sbsref->refexpr, Var) &&
!IsA(aref->refexpr, FieldSelect); !IsA(sbsref->refexpr, FieldSelect);
if (need_parens) if (need_parens)
appendStringInfoChar(buf, '('); appendStringInfoChar(buf, '(');
get_rule_expr((Node *) aref->refexpr, context, showimplicit); get_rule_expr((Node *) sbsref->refexpr, context, showimplicit);
if (need_parens) if (need_parens)
appendStringInfoChar(buf, ')'); appendStringInfoChar(buf, ')');
/* /*
* If there's a refassgnexpr, we want to print the node in the * If there's a refassgnexpr, we want to print the node in the
* format "array[subscripts] := refassgnexpr". This is not * format "container[subscripts] := refassgnexpr". This is
* legal SQL, so decompilation of INSERT or UPDATE statements * not legal SQL, so decompilation of INSERT or UPDATE
* should always use processIndirection as part of the * statements should always use processIndirection as part of
* statement-level syntax. We should only see this when * the statement-level syntax. We should only see this when
* EXPLAIN tries to print the targetlist of a plan resulting * EXPLAIN tries to print the targetlist of a plan resulting
* from such a statement. * from such a statement.
*/ */
if (aref->refassgnexpr) if (sbsref->refassgnexpr)
{ {
Node *refassgnexpr; Node *refassgnexpr;
@ -7869,8 +7871,8 @@ get_rule_expr(Node *node, deparse_context *context,
} }
else else
{ {
/* Just an ordinary array fetch, so print subscripts */ /* Just an ordinary container fetch, so print subscripts */
printSubscripts(aref, context); printSubscripts(sbsref, context);
} }
} }
break; break;
@ -8068,12 +8070,13 @@ get_rule_expr(Node *node, deparse_context *context,
bool need_parens; bool need_parens;
/* /*
* Parenthesize the argument unless it's an ArrayRef or * Parenthesize the argument unless it's an SubscriptingRef or
* another FieldSelect. Note in particular that it would be * another FieldSelect. Note in particular that it would be
* WRONG to not parenthesize a Var argument; simplicity is not * WRONG to not parenthesize a Var argument; simplicity is not
* the issue here, having the right number of names is. * the issue here, having the right number of names is.
*/ */
need_parens = !IsA(arg, ArrayRef) &&!IsA(arg, FieldSelect); need_parens = !IsA(arg, SubscriptingRef) &&
!IsA(arg, FieldSelect);
if (need_parens) if (need_parens)
appendStringInfoChar(buf, '('); appendStringInfoChar(buf, '(');
get_rule_expr(arg, context, true); get_rule_expr(arg, context, true);
@ -10437,7 +10440,7 @@ get_opclass_name(Oid opclass, Oid actual_datatype,
/* /*
* processIndirection - take care of array and subfield assignment * processIndirection - take care of array and subfield assignment
* *
* We strip any top-level FieldStore or assignment ArrayRef nodes that * We strip any top-level FieldStore or assignment SubscriptingRef nodes that
* appear in the input, printing them as decoration for the base column * appear in the input, printing them as decoration for the base column
* name (which we assume the caller just printed). We might also need to * name (which we assume the caller just printed). We might also need to
* strip CoerceToDomain nodes, but only ones that appear above assignment * strip CoerceToDomain nodes, but only ones that appear above assignment
@ -10483,19 +10486,20 @@ processIndirection(Node *node, deparse_context *context)
*/ */
node = (Node *) linitial(fstore->newvals); node = (Node *) linitial(fstore->newvals);
} }
else if (IsA(node, ArrayRef)) else if (IsA(node, SubscriptingRef))
{ {
ArrayRef *aref = (ArrayRef *) node; SubscriptingRef *sbsref = (SubscriptingRef *) node;
if (aref->refassgnexpr == NULL) if (sbsref->refassgnexpr == NULL)
break; break;
printSubscripts(aref, context);
printSubscripts(sbsref, context);
/* /*
* We ignore refexpr since it should be an uninteresting reference * We ignore refexpr since it should be an uninteresting reference
* to the target column or subcolumn. * to the target column or subcolumn.
*/ */
node = (Node *) aref->refassgnexpr; node = (Node *) sbsref->refassgnexpr;
} }
else if (IsA(node, CoerceToDomain)) else if (IsA(node, CoerceToDomain))
{ {
@ -10523,14 +10527,14 @@ processIndirection(Node *node, deparse_context *context)
} }
static void static void
printSubscripts(ArrayRef *aref, deparse_context *context) printSubscripts(SubscriptingRef *sbsref, deparse_context *context)
{ {
StringInfo buf = context->buf; StringInfo buf = context->buf;
ListCell *lowlist_item; ListCell *lowlist_item;
ListCell *uplist_item; ListCell *uplist_item;
lowlist_item = list_head(aref->reflowerindexpr); /* could be NULL */ lowlist_item = list_head(sbsref->reflowerindexpr); /* could be NULL */
foreach(uplist_item, aref->refupperindexpr) foreach(uplist_item, sbsref->refupperindexpr)
{ {
appendStringInfoChar(buf, '['); appendStringInfoChar(buf, '[');
if (lowlist_item) if (lowlist_item)

View File

@ -19,7 +19,7 @@
/* forward references to avoid circularity */ /* forward references to avoid circularity */
struct ExprEvalStep; struct ExprEvalStep;
struct ArrayRefState; struct SubscriptingRefState;
/* Bits in ExprState->flags (see also execnodes.h for public flag bits): */ /* Bits in ExprState->flags (see also execnodes.h for public flag bits): */
/* expression's interpreter has been initialized */ /* expression's interpreter has been initialized */
@ -185,21 +185,21 @@ typedef enum ExprEvalOp
*/ */
EEOP_FIELDSTORE_FORM, EEOP_FIELDSTORE_FORM,
/* Process an array subscript; short-circuit expression to NULL if NULL */ /* Process a container subscript; short-circuit expression to NULL if NULL */
EEOP_ARRAYREF_SUBSCRIPT, EEOP_SBSREF_SUBSCRIPT,
/* /*
* Compute old array element/slice when an ArrayRef assignment expression * Compute old container element/slice when a SubscriptingRef assignment
* contains ArrayRef/FieldStore subexpressions. Value is accessed using * expression contains SubscriptingRef/FieldStore subexpressions. Value is
* the CaseTest mechanism. * accessed using the CaseTest mechanism.
*/ */
EEOP_ARRAYREF_OLD, EEOP_SBSREF_OLD,
/* compute new value for ArrayRef assignment expression */ /* compute new value for SubscriptingRef assignment expression */
EEOP_ARRAYREF_ASSIGN, EEOP_SBSREF_ASSIGN,
/* compute element/slice for ArrayRef fetch expression */ /* compute element/slice for SubscriptingRef fetch expression */
EEOP_ARRAYREF_FETCH, EEOP_SBSREF_FETCH,
/* evaluate value for CoerceToDomainValue */ /* evaluate value for CoerceToDomainValue */
EEOP_DOMAIN_TESTVAL, EEOP_DOMAIN_TESTVAL,
@ -492,22 +492,22 @@ typedef struct ExprEvalStep
int ncolumns; int ncolumns;
} fieldstore; } fieldstore;
/* for EEOP_ARRAYREF_SUBSCRIPT */ /* for EEOP_SBSREF_SUBSCRIPT */
struct struct
{ {
/* too big to have inline */ /* too big to have inline */
struct ArrayRefState *state; struct SubscriptingRefState *state;
int off; /* 0-based index of this subscript */ int off; /* 0-based index of this subscript */
bool isupper; /* is it upper or lower subscript? */ bool isupper; /* is it upper or lower subscript? */
int jumpdone; /* jump here on null */ int jumpdone; /* jump here on null */
} arrayref_subscript; } sbsref_subscript;
/* for EEOP_ARRAYREF_OLD / ASSIGN / FETCH */ /* for EEOP_SBSREF_OLD / ASSIGN / FETCH */
struct struct
{ {
/* too big to have inline */ /* too big to have inline */
struct ArrayRefState *state; struct SubscriptingRefState *state;
} arrayref; } sbsref;
/* for EEOP_DOMAIN_NOTNULL / DOMAIN_CHECK */ /* for EEOP_DOMAIN_NOTNULL / DOMAIN_CHECK */
struct struct
@ -658,14 +658,14 @@ typedef struct ExprEvalStep
} ExprEvalStep; } ExprEvalStep;
/* Non-inline data for array operations */ /* Non-inline data for container operations */
typedef struct ArrayRefState typedef struct SubscriptingRefState
{ {
bool isassignment; /* is it assignment, or just fetch? */ bool isassignment; /* is it assignment, or just fetch? */
Oid refelemtype; /* OID of the array element type */ Oid refelemtype; /* OID of the container element type */
int16 refattrlength; /* typlen of array type */ int16 refattrlength; /* typlen of container type */
int16 refelemlength; /* typlen of the array element type */ int16 refelemlength; /* typlen of the container element type */
bool refelembyval; /* is the element type pass-by-value? */ bool refelembyval; /* is the element type pass-by-value? */
char refelemalign; /* typalign of the element type */ char refelemalign; /* typalign of the element type */
@ -688,10 +688,10 @@ typedef struct ArrayRefState
Datum replacevalue; Datum replacevalue;
bool replacenull; bool replacenull;
/* if we have a nested assignment, ARRAYREF_OLD puts old value here */ /* if we have a nested assignment, SBSREF_OLD puts old value here */
Datum prevvalue; Datum prevvalue;
bool prevnull; bool prevnull;
} ArrayRefState; } SubscriptingRefState;
/* functions in execExpr.c */ /* functions in execExpr.c */
@ -735,10 +735,10 @@ extern void ExecEvalFieldStoreDeForm(ExprState *state, ExprEvalStep *op,
ExprContext *econtext); ExprContext *econtext);
extern void ExecEvalFieldStoreForm(ExprState *state, ExprEvalStep *op, extern void ExecEvalFieldStoreForm(ExprState *state, ExprEvalStep *op,
ExprContext *econtext); ExprContext *econtext);
extern bool ExecEvalArrayRefSubscript(ExprState *state, ExprEvalStep *op); extern bool ExecEvalSubscriptingRef(ExprState *state, ExprEvalStep *op);
extern void ExecEvalArrayRefFetch(ExprState *state, ExprEvalStep *op); extern void ExecEvalSubscriptingRefFetch(ExprState *state, ExprEvalStep *op);
extern void ExecEvalArrayRefOld(ExprState *state, ExprEvalStep *op); extern void ExecEvalSubscriptingRefOld(ExprState *state, ExprEvalStep *op);
extern void ExecEvalArrayRefAssign(ExprState *state, ExprEvalStep *op); extern void ExecEvalSubscriptingRefAssign(ExprState *state, ExprEvalStep *op);
extern void ExecEvalConvertRowtype(ExprState *state, ExprEvalStep *op, extern void ExecEvalConvertRowtype(ExprState *state, ExprEvalStep *op,
ExprContext *econtext); ExprContext *econtext);
extern void ExecEvalScalarArrayOp(ExprState *state, ExprEvalStep *op); extern void ExecEvalScalarArrayOp(ExprState *state, ExprEvalStep *op);

View File

@ -85,7 +85,7 @@ extern LLVMValueRef FuncVarsizeAny;
extern LLVMValueRef FuncSlotGetmissingattrs; extern LLVMValueRef FuncSlotGetmissingattrs;
extern LLVMValueRef FuncSlotGetsomeattrsInt; extern LLVMValueRef FuncSlotGetsomeattrsInt;
extern LLVMValueRef FuncMakeExpandedObjectReadOnlyInternal; extern LLVMValueRef FuncMakeExpandedObjectReadOnlyInternal;
extern LLVMValueRef FuncExecEvalArrayRefSubscript; extern LLVMValueRef FuncExecEvalSubscriptingRef;
extern LLVMValueRef FuncExecEvalSysVar; extern LLVMValueRef FuncExecEvalSysVar;
extern LLVMValueRef FuncExecAggTransReparent; extern LLVMValueRef FuncExecAggTransReparent;
extern LLVMValueRef FuncExecAggInitGroup; extern LLVMValueRef FuncExecAggInitGroup;

View File

@ -154,7 +154,7 @@ typedef enum NodeTag
T_Aggref, T_Aggref,
T_GroupingFunc, T_GroupingFunc,
T_WindowFunc, T_WindowFunc,
T_ArrayRef, T_SubscriptingRef,
T_FuncExpr, T_FuncExpr,
T_NamedArgExpr, T_NamedArgExpr,
T_OpExpr, T_OpExpr,

View File

@ -224,7 +224,7 @@ typedef struct TypeName
* Currently, A_Star must appear only as the last list element --- the grammar * Currently, A_Star must appear only as the last list element --- the grammar
* is responsible for enforcing this! * is responsible for enforcing this!
* *
* Note: any array subscripting or selection of fields from composite columns * Note: any container subscripting or selection of fields from composite columns
* is represented by an A_Indirection node above the ColumnRef. However, * is represented by an A_Indirection node above the ColumnRef. However,
* for simplicity in the normal case, initial field selection from a table * for simplicity in the normal case, initial field selection from a table
* name is represented within ColumnRef and not by adding A_Indirection. * name is represented within ColumnRef and not by adding A_Indirection.

View File

@ -368,18 +368,19 @@ typedef struct WindowFunc
} WindowFunc; } WindowFunc;
/* ---------------- /* ----------------
* ArrayRef: describes an array subscripting operation * SubscriptingRef: describes a subscripting operation over a container
* (array, etc).
* *
* An ArrayRef can describe fetching a single element from an array, * A SubscriptingRef can describe fetching a single element from a container,
* fetching a subarray (array slice), storing a single element into * fetching a part of container (e.g. array slice), storing a single element into
* an array, or storing a slice. The "store" cases work with an * a container, or storing a slice. The "store" cases work with an
* initial array value and a source value that is inserted into the * initial container value and a source value that is inserted into the
* appropriate part of the array; the result of the operation is an * appropriate part of the container; the result of the operation is an
* entire new modified array value. * entire new modified container value.
* *
* If reflowerindexpr = NIL, then we are fetching or storing a single array * If reflowerindexpr = NIL, then we are fetching or storing a single container
* element at the subscripts given by refupperindexpr. Otherwise we are * element at the subscripts given by refupperindexpr. Otherwise we are
* fetching or storing an array slice, that is a rectangular subarray * fetching or storing a container slice, that is a rectangular subcontainer
* with lower and upper bounds given by the index expressions. * with lower and upper bounds given by the index expressions.
* reflowerindexpr must be the same length as refupperindexpr when it * reflowerindexpr must be the same length as refupperindexpr when it
* is not NIL. * is not NIL.
@ -391,28 +392,31 @@ typedef struct WindowFunc
* element; but it is the array type when doing subarray fetch or either * element; but it is the array type when doing subarray fetch or either
* type of store. * type of store.
* *
* Note: for the cases where an array is returned, if refexpr yields a R/W * Note: for the cases where a container is returned, if refexpr yields a R/W
* expanded array, then the implementation is allowed to modify that object * expanded container, then the implementation is allowed to modify that object
* in-place and return the same object.) * in-place and return the same object.)
* ---------------- * ----------------
*/ */
typedef struct ArrayRef typedef struct SubscriptingRef
{ {
Expr xpr; Expr xpr;
Oid refarraytype; /* type of the array proper */ Oid refcontainertype; /* type of the container proper */
Oid refelemtype; /* type of the array elements */ Oid refelemtype; /* type of the container elements */
int32 reftypmod; /* typmod of the array (and elements too) */ int32 reftypmod; /* typmod of the container (and elements too) */
Oid refcollid; /* OID of collation, or InvalidOid if none */ Oid refcollid; /* OID of collation, or InvalidOid if none */
List *refupperindexpr; /* expressions that evaluate to upper List *refupperindexpr; /* expressions that evaluate to upper
* array indexes */ * container indexes */
List *reflowerindexpr; /* expressions that evaluate to lower List *reflowerindexpr; /* expressions that evaluate to lower
* array indexes, or NIL for single array * container indexes, or NIL for single
* element */ * container element */
Expr *refexpr; /* the expression that evaluates to an array List *refindexprslice; /* whether or not related indexpr from
* value */ * reflowerindexpr is a slice */
Expr *refexpr; /* the expression that evaluates to a
* container value */
Expr *refassgnexpr; /* expression for the source value, or NULL if Expr *refassgnexpr; /* expression for the source value, or NULL if
* fetch */ * fetch */
} ArrayRef; } SubscriptingRef;
/* /*
* CoercionContext - distinguishes the allowed set of type casts * CoercionContext - distinguishes the allowed set of type casts
@ -755,7 +759,7 @@ typedef struct FieldSelect
* *
* FieldStore represents the operation of modifying one field in a tuple * FieldStore represents the operation of modifying one field in a tuple
* value, yielding a new tuple value (the input is not touched!). Like * value, yielding a new tuple value (the input is not touched!). Like
* the assign case of ArrayRef, this is used to implement UPDATE of a * the assign case of SubscriptingRef, this is used to implement UPDATE of a
* portion of a column. * portion of a column.
* *
* resulttype is always a named composite type (not a domain). To update * resulttype is always a named composite type (not a domain). To update

View File

@ -273,14 +273,15 @@ extern void cancel_parser_errposition_callback(ParseCallbackState *pcbstate);
extern Var *make_var(ParseState *pstate, RangeTblEntry *rte, int attrno, extern Var *make_var(ParseState *pstate, RangeTblEntry *rte, int attrno,
int location); int location);
extern Oid transformArrayType(Oid *arrayType, int32 *arrayTypmod); extern Oid transformContainerType(Oid *containerType, int32 *containerTypmod);
extern ArrayRef *transformArraySubscripts(ParseState *pstate,
Node *arrayBase, extern SubscriptingRef *transformContainerSubscripts(ParseState *pstate,
Oid arrayType, Node *containerBase,
Oid elementType, Oid containerType,
int32 arrayTypMod, Oid elementType,
List *indirection, int32 containerTypMod,
Node *assignFrom); List *indirection,
Node *assignFrom);
extern Const *make_const(ParseState *pstate, Value *value, int location); extern Const *make_const(ParseState *pstate, Value *value, int location);
#endif /* PARSE_NODE_H */ #endif /* PARSE_NODE_H */

View File

@ -5207,8 +5207,8 @@ exec_assign_value(PLpgSQL_execstate *estate,
/* /*
* Evaluate the subscripts, switch into left-to-right order. * Evaluate the subscripts, switch into left-to-right order.
* Like the expression built by ExecInitArrayRef(), complain * Like the expression built by ExecInitSubscriptingRef(),
* if any subscript is null. * complain if any subscript is null.
*/ */
for (i = 0; i < nsubscripts; i++) for (i = 0; i < nsubscripts; i++)
{ {