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:
parent
f831d4accd
commit
558d77f20e
|
@ -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:
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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");
|
||||||
|
|
|
@ -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));
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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))
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
|
@ -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++)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue