mirror of
https://github.com/postgres/postgres.git
synced 2025-07-03 20:02:46 +03:00
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:
@ -67,9 +67,10 @@ static bool get_last_attnums_walker(Node *node, LastAttnumInfo *info);
|
||||
static void ExecComputeSlotInfo(ExprState *state, ExprEvalStep *op);
|
||||
static void ExecInitWholeRowVar(ExprEvalStep *scratch, Var *variable,
|
||||
ExprState *state);
|
||||
static void ExecInitArrayRef(ExprEvalStep *scratch, ArrayRef *aref,
|
||||
ExprState *state,
|
||||
Datum *resv, bool *resnull);
|
||||
static void ExecInitSubscriptingRef(ExprEvalStep *scratch,
|
||||
SubscriptingRef *sbsref,
|
||||
ExprState *state,
|
||||
Datum *resv, bool *resnull);
|
||||
static bool isAssignmentIndirectionExpr(Expr *expr);
|
||||
static void ExecInitCoerceToDomain(ExprEvalStep *scratch, CoerceToDomain *ctest,
|
||||
ExprState *state,
|
||||
@ -867,11 +868,11 @@ ExecInitExprRec(Expr *node, ExprState *state,
|
||||
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;
|
||||
}
|
||||
|
||||
@ -1186,13 +1187,14 @@ ExecInitExprRec(Expr *node, ExprState *state,
|
||||
/*
|
||||
* Use the CaseTestExpr mechanism to pass down the old
|
||||
* value of the field being replaced; this is needed in
|
||||
* case the newval is itself a FieldStore or ArrayRef that
|
||||
* has to obtain and modify the old value. It's safe to
|
||||
* reuse the CASE mechanism because there cannot be a CASE
|
||||
* between here and where the value would be needed, and a
|
||||
* field assignment can't be within a CASE either. (So
|
||||
* saving and restoring innermost_caseval is just
|
||||
* paranoia, but let's do it anyway.)
|
||||
* case the newval is itself a FieldStore or
|
||||
* SubscriptingRef that has to obtain and modify the old
|
||||
* value. It's safe to reuse the CASE mechanism because
|
||||
* there cannot be a CASE between here and where the value
|
||||
* would be needed, and a field assignment can't be within
|
||||
* a CASE either. (So saving and restoring
|
||||
* innermost_caseval is just paranoia, but let's do it
|
||||
* anyway.)
|
||||
*
|
||||
* Another non-obvious point is that it's safe to use the
|
||||
* 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
|
||||
ExecInitArrayRef(ExprEvalStep *scratch, ArrayRef *aref,
|
||||
ExprState *state, Datum *resv, bool *resnull)
|
||||
ExecInitSubscriptingRef(ExprEvalStep *scratch, SubscriptingRef *sbsref,
|
||||
ExprState *state, Datum *resv, bool *resnull)
|
||||
{
|
||||
bool isAssignment = (aref->refassgnexpr != NULL);
|
||||
ArrayRefState *arefstate = palloc0(sizeof(ArrayRefState));
|
||||
bool isAssignment = (sbsref->refassgnexpr != NULL);
|
||||
SubscriptingRefState *sbsrefstate = palloc0(sizeof(SubscriptingRefState));
|
||||
List *adjust_jumps = NIL;
|
||||
ListCell *lc;
|
||||
int i;
|
||||
|
||||
/* Fill constant fields of ArrayRefState */
|
||||
arefstate->isassignment = isAssignment;
|
||||
arefstate->refelemtype = aref->refelemtype;
|
||||
arefstate->refattrlength = get_typlen(aref->refarraytype);
|
||||
get_typlenbyvalalign(aref->refelemtype,
|
||||
&arefstate->refelemlength,
|
||||
&arefstate->refelembyval,
|
||||
&arefstate->refelemalign);
|
||||
/* Fill constant fields of SubscriptingRefState */
|
||||
sbsrefstate->isassignment = isAssignment;
|
||||
sbsrefstate->refelemtype = sbsref->refelemtype;
|
||||
sbsrefstate->refattrlength = get_typlen(sbsref->refcontainertype);
|
||||
get_typlenbyvalalign(sbsref->refelemtype,
|
||||
&sbsrefstate->refelemlength,
|
||||
&sbsrefstate->refelembyval,
|
||||
&sbsrefstate->refelemalign);
|
||||
|
||||
/*
|
||||
* 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
|
||||
* 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.
|
||||
*/
|
||||
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
|
||||
@ -2572,87 +2574,87 @@ ExecInitArrayRef(ExprEvalStep *scratch, ArrayRef *aref,
|
||||
}
|
||||
|
||||
/* Verify subscript list lengths are within limit */
|
||||
if (list_length(aref->refupperindexpr) > MAXDIM)
|
||||
if (list_length(sbsref->refupperindexpr) > MAXDIM)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
|
||||
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,
|
||||
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
|
||||
errmsg("number of array dimensions (%d) exceeds the maximum allowed (%d)",
|
||||
list_length(aref->reflowerindexpr), MAXDIM)));
|
||||
list_length(sbsref->reflowerindexpr), MAXDIM)));
|
||||
|
||||
/* Evaluate upper subscripts */
|
||||
i = 0;
|
||||
foreach(lc, aref->refupperindexpr)
|
||||
foreach(lc, sbsref->refupperindexpr)
|
||||
{
|
||||
Expr *e = (Expr *) lfirst(lc);
|
||||
|
||||
/* When slicing, individual subscript bounds can be omitted */
|
||||
if (!e)
|
||||
{
|
||||
arefstate->upperprovided[i] = false;
|
||||
sbsrefstate->upperprovided[i] = false;
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
|
||||
arefstate->upperprovided[i] = true;
|
||||
sbsrefstate->upperprovided[i] = true;
|
||||
|
||||
/* Each subscript is evaluated into subscriptvalue/subscriptnull */
|
||||
ExecInitExprRec(e, state,
|
||||
&arefstate->subscriptvalue, &arefstate->subscriptnull);
|
||||
&sbsrefstate->subscriptvalue, &sbsrefstate->subscriptnull);
|
||||
|
||||
/* ... and then ARRAYREF_SUBSCRIPT saves it into step's workspace */
|
||||
scratch->opcode = EEOP_ARRAYREF_SUBSCRIPT;
|
||||
scratch->d.arrayref_subscript.state = arefstate;
|
||||
scratch->d.arrayref_subscript.off = i;
|
||||
scratch->d.arrayref_subscript.isupper = true;
|
||||
scratch->d.arrayref_subscript.jumpdone = -1; /* adjust later */
|
||||
/* ... and then SBSREF_SUBSCRIPT saves it into step's workspace */
|
||||
scratch->opcode = EEOP_SBSREF_SUBSCRIPT;
|
||||
scratch->d.sbsref_subscript.state = sbsrefstate;
|
||||
scratch->d.sbsref_subscript.off = i;
|
||||
scratch->d.sbsref_subscript.isupper = true;
|
||||
scratch->d.sbsref_subscript.jumpdone = -1; /* adjust later */
|
||||
ExprEvalPushStep(state, scratch);
|
||||
adjust_jumps = lappend_int(adjust_jumps,
|
||||
state->steps_len - 1);
|
||||
i++;
|
||||
}
|
||||
arefstate->numupper = i;
|
||||
sbsrefstate->numupper = i;
|
||||
|
||||
/* Evaluate lower subscripts similarly */
|
||||
i = 0;
|
||||
foreach(lc, aref->reflowerindexpr)
|
||||
foreach(lc, sbsref->reflowerindexpr)
|
||||
{
|
||||
Expr *e = (Expr *) lfirst(lc);
|
||||
|
||||
/* When slicing, individual subscript bounds can be omitted */
|
||||
if (!e)
|
||||
{
|
||||
arefstate->lowerprovided[i] = false;
|
||||
sbsrefstate->lowerprovided[i] = false;
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
|
||||
arefstate->lowerprovided[i] = true;
|
||||
sbsrefstate->lowerprovided[i] = true;
|
||||
|
||||
/* Each subscript is evaluated into subscriptvalue/subscriptnull */
|
||||
ExecInitExprRec(e, state,
|
||||
&arefstate->subscriptvalue, &arefstate->subscriptnull);
|
||||
&sbsrefstate->subscriptvalue, &sbsrefstate->subscriptnull);
|
||||
|
||||
/* ... and then ARRAYREF_SUBSCRIPT saves it into step's workspace */
|
||||
scratch->opcode = EEOP_ARRAYREF_SUBSCRIPT;
|
||||
scratch->d.arrayref_subscript.state = arefstate;
|
||||
scratch->d.arrayref_subscript.off = i;
|
||||
scratch->d.arrayref_subscript.isupper = false;
|
||||
scratch->d.arrayref_subscript.jumpdone = -1; /* adjust later */
|
||||
/* ... and then SBSREF_SUBSCRIPT saves it into step's workspace */
|
||||
scratch->opcode = EEOP_SBSREF_SUBSCRIPT;
|
||||
scratch->d.sbsref_subscript.state = sbsrefstate;
|
||||
scratch->d.sbsref_subscript.off = i;
|
||||
scratch->d.sbsref_subscript.isupper = false;
|
||||
scratch->d.sbsref_subscript.jumpdone = -1; /* adjust later */
|
||||
ExprEvalPushStep(state, scratch);
|
||||
adjust_jumps = lappend_int(adjust_jumps,
|
||||
state->steps_len - 1);
|
||||
i++;
|
||||
}
|
||||
arefstate->numlower = i;
|
||||
sbsrefstate->numlower = i;
|
||||
|
||||
/* Should be impossible if parser is sane, but check anyway: */
|
||||
if (arefstate->numlower != 0 &&
|
||||
arefstate->numupper != arefstate->numlower)
|
||||
if (sbsrefstate->numlower != 0 &&
|
||||
sbsrefstate->numupper != sbsrefstate->numlower)
|
||||
elog(ERROR, "upper and lower index lists are not same length");
|
||||
|
||||
if (isAssignment)
|
||||
@ -2662,49 +2664,51 @@ ExecInitArrayRef(ExprEvalStep *scratch, ArrayRef *aref,
|
||||
|
||||
/*
|
||||
* We might have a nested-assignment situation, in which the
|
||||
* refassgnexpr is itself a FieldStore or ArrayRef that needs to
|
||||
* obtain and modify the previous value of the array element or slice
|
||||
* being replaced. If so, we have to extract that value from the
|
||||
* array and pass it down via the CaseTestExpr mechanism. It's safe
|
||||
* to reuse the CASE mechanism because there cannot be a CASE between
|
||||
* here and where the value would be needed, and an array assignment
|
||||
* can't be within a CASE either. (So saving and restoring
|
||||
* refassgnexpr is itself a FieldStore or SubscriptingRef that needs
|
||||
* to obtain and modify the previous value of the array element or
|
||||
* slice being replaced. If so, we have to extract that value from
|
||||
* the array and pass it down via the CaseTestExpr mechanism. It's
|
||||
* safe to reuse the CASE mechanism because there cannot be a CASE
|
||||
* between here and where the value would be needed, and an array
|
||||
* assignment can't be within a CASE either. (So saving and restoring
|
||||
* innermost_caseval is just paranoia, but let's do it anyway.)
|
||||
*
|
||||
* Since fetching the old element might be a nontrivial expense, do it
|
||||
* only if the argument actually needs it.
|
||||
*/
|
||||
if (isAssignmentIndirectionExpr(aref->refassgnexpr))
|
||||
if (isAssignmentIndirectionExpr(sbsref->refassgnexpr))
|
||||
{
|
||||
scratch->opcode = EEOP_ARRAYREF_OLD;
|
||||
scratch->d.arrayref.state = arefstate;
|
||||
scratch->opcode = EEOP_SBSREF_OLD;
|
||||
scratch->d.sbsref.state = sbsrefstate;
|
||||
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_casenull = state->innermost_casenull;
|
||||
state->innermost_caseval = &arefstate->prevvalue;
|
||||
state->innermost_casenull = &arefstate->prevnull;
|
||||
state->innermost_caseval = &sbsrefstate->prevvalue;
|
||||
state->innermost_casenull = &sbsrefstate->prevnull;
|
||||
|
||||
/* evaluate replacement value into replacevalue/replacenull */
|
||||
ExecInitExprRec(aref->refassgnexpr, state,
|
||||
&arefstate->replacevalue, &arefstate->replacenull);
|
||||
ExecInitExprRec(sbsref->refassgnexpr, state,
|
||||
&sbsrefstate->replacevalue, &sbsrefstate->replacenull);
|
||||
|
||||
state->innermost_caseval = save_innermost_caseval;
|
||||
state->innermost_casenull = save_innermost_casenull;
|
||||
|
||||
/* and perform the assignment */
|
||||
scratch->opcode = EEOP_ARRAYREF_ASSIGN;
|
||||
scratch->d.arrayref.state = arefstate;
|
||||
scratch->opcode = EEOP_SBSREF_ASSIGN;
|
||||
scratch->d.sbsref.state = sbsrefstate;
|
||||
ExprEvalPushStep(state, scratch);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
/* array fetch is much simpler */
|
||||
scratch->opcode = EEOP_ARRAYREF_FETCH;
|
||||
scratch->d.arrayref.state = arefstate;
|
||||
scratch->opcode = EEOP_SBSREF_FETCH;
|
||||
scratch->d.sbsref.state = sbsrefstate;
|
||||
ExprEvalPushStep(state, scratch);
|
||||
|
||||
}
|
||||
|
||||
/* adjust jump targets */
|
||||
@ -2712,10 +2716,10 @@ ExecInitArrayRef(ExprEvalStep *scratch, ArrayRef *aref,
|
||||
{
|
||||
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);
|
||||
as->d.arrayref_subscript.jumpdone = state->steps_len;
|
||||
Assert(as->d.sbsref_subscript.jumpdone == -1);
|
||||
as->d.sbsref_subscript.jumpdone = state->steps_len;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -2727,8 +2731,9 @@ ExecInitArrayRef(ExprEvalStep *scratch, ArrayRef *aref,
|
||||
}
|
||||
|
||||
/*
|
||||
* Helper for preparing ArrayRef expressions for evaluation: is expr a nested
|
||||
* FieldStore or ArrayRef that needs the old element value passed down?
|
||||
* Helper for preparing SubscriptingRef expressions for evaluation: is expr
|
||||
* 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
|
||||
* value is so cheap there's no need.)
|
||||
@ -2751,11 +2756,11 @@ isAssignmentIndirectionExpr(Expr *expr)
|
||||
if (fstore->arg && IsA(fstore->arg, CaseTestExpr))
|
||||
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 false;
|
||||
|
@ -370,10 +370,10 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
|
||||
&&CASE_EEOP_FIELDSELECT,
|
||||
&&CASE_EEOP_FIELDSTORE_DEFORM,
|
||||
&&CASE_EEOP_FIELDSTORE_FORM,
|
||||
&&CASE_EEOP_ARRAYREF_SUBSCRIPT,
|
||||
&&CASE_EEOP_ARRAYREF_OLD,
|
||||
&&CASE_EEOP_ARRAYREF_ASSIGN,
|
||||
&&CASE_EEOP_ARRAYREF_FETCH,
|
||||
&&CASE_EEOP_SBSREF_SUBSCRIPT,
|
||||
&&CASE_EEOP_SBSREF_OLD,
|
||||
&&CASE_EEOP_SBSREF_ASSIGN,
|
||||
&&CASE_EEOP_SBSREF_FETCH,
|
||||
&&CASE_EEOP_DOMAIN_TESTVAL,
|
||||
&&CASE_EEOP_DOMAIN_NOTNULL,
|
||||
&&CASE_EEOP_DOMAIN_CHECK,
|
||||
@ -1347,43 +1347,43 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
|
||||
EEO_NEXT();
|
||||
}
|
||||
|
||||
EEO_CASE(EEOP_ARRAYREF_SUBSCRIPT)
|
||||
EEO_CASE(EEOP_SBSREF_SUBSCRIPT)
|
||||
{
|
||||
/* Process an array subscript */
|
||||
|
||||
/* too complex for an inline implementation */
|
||||
if (ExecEvalArrayRefSubscript(state, op))
|
||||
if (ExecEvalSubscriptingRef(state, op))
|
||||
{
|
||||
EEO_NEXT();
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Subscript is null, short-circuit ArrayRef to NULL */
|
||||
EEO_JUMP(op->d.arrayref_subscript.jumpdone);
|
||||
/* Subscript is null, short-circuit SubscriptingRef to NULL */
|
||||
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
|
||||
* expression.
|
||||
*/
|
||||
|
||||
/* too complex for an inline implementation */
|
||||
ExecEvalArrayRefOld(state, op);
|
||||
ExecEvalSubscriptingRefOld(state, op);
|
||||
|
||||
EEO_NEXT();
|
||||
}
|
||||
|
||||
/*
|
||||
* Perform ArrayRef assignment
|
||||
* Perform SubscriptingRef assignment
|
||||
*/
|
||||
EEO_CASE(EEOP_ARRAYREF_ASSIGN)
|
||||
EEO_CASE(EEOP_SBSREF_ASSIGN)
|
||||
{
|
||||
/* too complex for an inline implementation */
|
||||
ExecEvalArrayRefAssign(state, op);
|
||||
ExecEvalSubscriptingRefAssign(state, op);
|
||||
|
||||
EEO_NEXT();
|
||||
}
|
||||
@ -1391,10 +1391,10 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
|
||||
/*
|
||||
* Fetch subset of an array.
|
||||
*/
|
||||
EEO_CASE(EEOP_ARRAYREF_FETCH)
|
||||
EEO_CASE(EEOP_SBSREF_FETCH)
|
||||
{
|
||||
/* too complex for an inline implementation */
|
||||
ExecEvalArrayRefFetch(state, op);
|
||||
ExecEvalSubscriptingRefFetch(state, op);
|
||||
|
||||
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
|
||||
* 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.
|
||||
* On success, integer subscript value has been saved in upperindex[] or
|
||||
* lowerindex[] for use later.
|
||||
*/
|
||||
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 off;
|
||||
|
||||
/* 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,
|
||||
(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
|
||||
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 */
|
||||
if (op->d.arrayref_subscript.isupper)
|
||||
indexes = arefstate->upperindex;
|
||||
if (op->d.sbsref_subscript.isupper)
|
||||
indexes = sbsrefstate->upperindex;
|
||||
else
|
||||
indexes = arefstate->lowerindex;
|
||||
off = op->d.arrayref_subscript.off;
|
||||
indexes = sbsrefstate->lowerindex;
|
||||
off = op->d.sbsref_subscript.off;
|
||||
|
||||
indexes[off] = DatumGetInt32(arefstate->subscriptvalue);
|
||||
indexes[off] = DatumGetInt32(sbsrefstate->subscriptvalue);
|
||||
|
||||
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
|
||||
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));
|
||||
|
||||
if (arefstate->numlower == 0)
|
||||
if (sbsrefstate->numlower == 0)
|
||||
{
|
||||
/* Scalar case */
|
||||
*op->resvalue = array_get_element(*op->resvalue,
|
||||
arefstate->numupper,
|
||||
arefstate->upperindex,
|
||||
arefstate->refattrlength,
|
||||
arefstate->refelemlength,
|
||||
arefstate->refelembyval,
|
||||
arefstate->refelemalign,
|
||||
sbsrefstate->numupper,
|
||||
sbsrefstate->upperindex,
|
||||
sbsrefstate->refattrlength,
|
||||
sbsrefstate->refelemlength,
|
||||
sbsrefstate->refelembyval,
|
||||
sbsrefstate->refelemalign,
|
||||
op->resnull);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Slice case */
|
||||
*op->resvalue = array_get_slice(*op->resvalue,
|
||||
arefstate->numupper,
|
||||
arefstate->upperindex,
|
||||
arefstate->lowerindex,
|
||||
arefstate->upperprovided,
|
||||
arefstate->lowerprovided,
|
||||
arefstate->refattrlength,
|
||||
arefstate->refelemlength,
|
||||
arefstate->refelembyval,
|
||||
arefstate->refelemalign);
|
||||
sbsrefstate->numupper,
|
||||
sbsrefstate->upperindex,
|
||||
sbsrefstate->lowerindex,
|
||||
sbsrefstate->upperprovided,
|
||||
sbsrefstate->lowerprovided,
|
||||
sbsrefstate->refattrlength,
|
||||
sbsrefstate->refelemlength,
|
||||
sbsrefstate->refelembyval,
|
||||
sbsrefstate->refelemalign);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Compute old array element/slice value for an ArrayRef assignment
|
||||
* expression. Will only be generated if the new-value subexpression
|
||||
* contains ArrayRef or FieldStore. The value is stored into the
|
||||
* ArrayRefState's prevvalue/prevnull fields.
|
||||
* Compute old container element/slice value for a SubscriptingRef assignment
|
||||
* expression. Will only be generated if the new-value subexpression
|
||||
* contains SubscriptingRef or FieldStore. The value is stored into the
|
||||
* SubscriptingRefState's prevvalue/prevnull fields.
|
||||
*/
|
||||
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)
|
||||
{
|
||||
/* whole array is null, so any element or slice is too */
|
||||
arefstate->prevvalue = (Datum) 0;
|
||||
arefstate->prevnull = true;
|
||||
sbsrefstate->prevvalue = (Datum) 0;
|
||||
sbsrefstate->prevnull = true;
|
||||
}
|
||||
else if (arefstate->numlower == 0)
|
||||
else if (sbsrefstate->numlower == 0)
|
||||
{
|
||||
/* Scalar case */
|
||||
arefstate->prevvalue = array_get_element(*op->resvalue,
|
||||
arefstate->numupper,
|
||||
arefstate->upperindex,
|
||||
arefstate->refattrlength,
|
||||
arefstate->refelemlength,
|
||||
arefstate->refelembyval,
|
||||
arefstate->refelemalign,
|
||||
&arefstate->prevnull);
|
||||
sbsrefstate->prevvalue = array_get_element(*op->resvalue,
|
||||
sbsrefstate->numupper,
|
||||
sbsrefstate->upperindex,
|
||||
sbsrefstate->refattrlength,
|
||||
sbsrefstate->refelemlength,
|
||||
sbsrefstate->refelembyval,
|
||||
sbsrefstate->refelemalign,
|
||||
&sbsrefstate->prevnull);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Slice case */
|
||||
/* this is currently unreachable */
|
||||
arefstate->prevvalue = array_get_slice(*op->resvalue,
|
||||
arefstate->numupper,
|
||||
arefstate->upperindex,
|
||||
arefstate->lowerindex,
|
||||
arefstate->upperprovided,
|
||||
arefstate->lowerprovided,
|
||||
arefstate->refattrlength,
|
||||
arefstate->refelemlength,
|
||||
arefstate->refelembyval,
|
||||
arefstate->refelemalign);
|
||||
arefstate->prevnull = false;
|
||||
sbsrefstate->prevvalue = array_get_slice(*op->resvalue,
|
||||
sbsrefstate->numupper,
|
||||
sbsrefstate->upperindex,
|
||||
sbsrefstate->lowerindex,
|
||||
sbsrefstate->upperprovided,
|
||||
sbsrefstate->lowerprovided,
|
||||
sbsrefstate->refattrlength,
|
||||
sbsrefstate->refelemlength,
|
||||
sbsrefstate->refelembyval,
|
||||
sbsrefstate->refelemalign);
|
||||
sbsrefstate->prevnull = false;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Evaluate ArrayRef assignment.
|
||||
* Evaluate SubscriptingRef assignment.
|
||||
*
|
||||
* Input array (possibly null) is in result area, replacement value is in
|
||||
* ArrayRefState's replacevalue/replacenull.
|
||||
* Input container (possibly null) is in result area, replacement value is in
|
||||
* SubscriptingRefState's replacevalue/replacenull.
|
||||
*/
|
||||
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
|
||||
* and the value to be assigned into it must be non-NULL, else we punt and
|
||||
* return the original array.
|
||||
* For an assignment to a fixed-length container type, both the original
|
||||
* container and the value to be assigned into it must be non-NULL, else
|
||||
* 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;
|
||||
}
|
||||
|
||||
@ -3202,38 +3202,38 @@ ExecEvalArrayRefAssign(ExprState *state, ExprEvalStep *op)
|
||||
*/
|
||||
if (*op->resnull)
|
||||
{
|
||||
*op->resvalue = PointerGetDatum(construct_empty_array(arefstate->refelemtype));
|
||||
*op->resvalue = PointerGetDatum(construct_empty_array(sbsrefstate->refelemtype));
|
||||
*op->resnull = false;
|
||||
}
|
||||
|
||||
if (arefstate->numlower == 0)
|
||||
if (sbsrefstate->numlower == 0)
|
||||
{
|
||||
/* Scalar case */
|
||||
*op->resvalue = array_set_element(*op->resvalue,
|
||||
arefstate->numupper,
|
||||
arefstate->upperindex,
|
||||
arefstate->replacevalue,
|
||||
arefstate->replacenull,
|
||||
arefstate->refattrlength,
|
||||
arefstate->refelemlength,
|
||||
arefstate->refelembyval,
|
||||
arefstate->refelemalign);
|
||||
sbsrefstate->numupper,
|
||||
sbsrefstate->upperindex,
|
||||
sbsrefstate->replacevalue,
|
||||
sbsrefstate->replacenull,
|
||||
sbsrefstate->refattrlength,
|
||||
sbsrefstate->refelemlength,
|
||||
sbsrefstate->refelembyval,
|
||||
sbsrefstate->refelemalign);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Slice case */
|
||||
*op->resvalue = array_set_slice(*op->resvalue,
|
||||
arefstate->numupper,
|
||||
arefstate->upperindex,
|
||||
arefstate->lowerindex,
|
||||
arefstate->upperprovided,
|
||||
arefstate->lowerprovided,
|
||||
arefstate->replacevalue,
|
||||
arefstate->replacenull,
|
||||
arefstate->refattrlength,
|
||||
arefstate->refelemlength,
|
||||
arefstate->refelembyval,
|
||||
arefstate->refelemalign);
|
||||
sbsrefstate->numupper,
|
||||
sbsrefstate->upperindex,
|
||||
sbsrefstate->lowerindex,
|
||||
sbsrefstate->upperprovided,
|
||||
sbsrefstate->lowerprovided,
|
||||
sbsrefstate->replacevalue,
|
||||
sbsrefstate->replacenull,
|
||||
sbsrefstate->refattrlength,
|
||||
sbsrefstate->refelemlength,
|
||||
sbsrefstate->refelembyval,
|
||||
sbsrefstate->refelemalign);
|
||||
}
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user