1
0
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:
Tom Lane
2007-03-27 23:21:12 +00:00
parent 87564ffc6a
commit bf94076348
24 changed files with 564 additions and 440 deletions

View File

@ -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;
}
/*