mirror of
https://github.com/postgres/postgres.git
synced 2025-06-14 18:42:34 +03:00
Fix array coercion expressions to ensure that the correct volatility is
seen by code inspecting the expression. The best way to do this seems to be to drop the original representation as a function invocation, and instead make a special expression node type that represents applying the element-type coercion function to each array element. In this way the element function is exposed and will be checked for volatility. Per report from Guillaume Smet.
This commit is contained in:
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/parser/parse_expr.c,v 1.214 2007/03/17 01:15:55 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/parser/parse_expr.c,v 1.215 2007/03/27 23:21:10 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -265,6 +265,7 @@ transformExpr(ParseState *pstate, Node *expr)
|
||||
case T_FieldSelect:
|
||||
case T_FieldStore:
|
||||
case T_RelabelType:
|
||||
case T_ArrayCoerceExpr:
|
||||
case T_ConvertRowtypeExpr:
|
||||
case T_CaseTestExpr:
|
||||
case T_CoerceToDomain:
|
||||
@ -1804,6 +1805,9 @@ exprType(Node *expr)
|
||||
case T_RelabelType:
|
||||
type = ((RelabelType *) expr)->resulttype;
|
||||
break;
|
||||
case T_ArrayCoerceExpr:
|
||||
type = ((ArrayCoerceExpr *) expr)->resulttype;
|
||||
break;
|
||||
case T_ConvertRowtypeExpr:
|
||||
type = ((ConvertRowtypeExpr *) expr)->resulttype;
|
||||
break;
|
||||
@ -1918,6 +1922,8 @@ exprTypmod(Node *expr)
|
||||
return ((FieldSelect *) expr)->resulttypmod;
|
||||
case T_RelabelType:
|
||||
return ((RelabelType *) expr)->resulttypmod;
|
||||
case T_ArrayCoerceExpr:
|
||||
return ((ArrayCoerceExpr *) expr)->resulttypmod;
|
||||
case T_CaseExpr:
|
||||
{
|
||||
/*
|
||||
@ -2072,47 +2078,68 @@ exprTypmod(Node *expr)
|
||||
bool
|
||||
exprIsLengthCoercion(Node *expr, int32 *coercedTypmod)
|
||||
{
|
||||
FuncExpr *func;
|
||||
int nargs;
|
||||
Const *second_arg;
|
||||
|
||||
if (coercedTypmod != NULL)
|
||||
*coercedTypmod = -1; /* default result on failure */
|
||||
|
||||
/* Is it a function-call at all? */
|
||||
if (expr == NULL || !IsA(expr, FuncExpr))
|
||||
return false;
|
||||
func = (FuncExpr *) expr;
|
||||
|
||||
/*
|
||||
* If it didn't come from a coercion context, reject.
|
||||
* Scalar-type length coercions are FuncExprs, array-type length
|
||||
* coercions are ArrayCoerceExprs
|
||||
*/
|
||||
if (func->funcformat != COERCE_EXPLICIT_CAST &&
|
||||
func->funcformat != COERCE_IMPLICIT_CAST)
|
||||
return false;
|
||||
if (expr && IsA(expr, FuncExpr))
|
||||
{
|
||||
FuncExpr *func = (FuncExpr *) expr;
|
||||
int nargs;
|
||||
Const *second_arg;
|
||||
|
||||
/*
|
||||
* If it's not a two-argument or three-argument function with the second
|
||||
* argument being an int4 constant, it can't have been created from a
|
||||
* length coercion (it must be a type coercion, instead).
|
||||
*/
|
||||
nargs = list_length(func->args);
|
||||
if (nargs < 2 || nargs > 3)
|
||||
return false;
|
||||
/*
|
||||
* If it didn't come from a coercion context, reject.
|
||||
*/
|
||||
if (func->funcformat != COERCE_EXPLICIT_CAST &&
|
||||
func->funcformat != COERCE_IMPLICIT_CAST)
|
||||
return false;
|
||||
|
||||
second_arg = (Const *) lsecond(func->args);
|
||||
if (!IsA(second_arg, Const) ||
|
||||
second_arg->consttype != INT4OID ||
|
||||
second_arg->constisnull)
|
||||
return false;
|
||||
/*
|
||||
* If it's not a two-argument or three-argument function with the
|
||||
* second argument being an int4 constant, it can't have been created
|
||||
* from a length coercion (it must be a type coercion, instead).
|
||||
*/
|
||||
nargs = list_length(func->args);
|
||||
if (nargs < 2 || nargs > 3)
|
||||
return false;
|
||||
|
||||
/*
|
||||
* OK, it is indeed a length-coercion function.
|
||||
*/
|
||||
if (coercedTypmod != NULL)
|
||||
*coercedTypmod = DatumGetInt32(second_arg->constvalue);
|
||||
second_arg = (Const *) lsecond(func->args);
|
||||
if (!IsA(second_arg, Const) ||
|
||||
second_arg->consttype != INT4OID ||
|
||||
second_arg->constisnull)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
/*
|
||||
* OK, it is indeed a length-coercion function.
|
||||
*/
|
||||
if (coercedTypmod != NULL)
|
||||
*coercedTypmod = DatumGetInt32(second_arg->constvalue);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (expr && IsA(expr, ArrayCoerceExpr))
|
||||
{
|
||||
ArrayCoerceExpr *acoerce = (ArrayCoerceExpr *) expr;
|
||||
|
||||
/* It's not a length coercion unless there's a nondefault typmod */
|
||||
if (acoerce->resulttypmod < 0)
|
||||
return false;
|
||||
|
||||
/*
|
||||
* OK, it is indeed a length-coercion expression.
|
||||
*/
|
||||
if (coercedTypmod != NULL)
|
||||
*coercedTypmod = acoerce->resulttypmod;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
|
Reference in New Issue
Block a user