aboutsummaryrefslogtreecommitdiff
path: root/src/backend/parser/parse_expr.c
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2007-03-27 23:21:12 +0000
committerTom Lane <tgl@sss.pgh.pa.us>2007-03-27 23:21:12 +0000
commitbf94076348ef7e0a81e3fe4ededb2fdcd14b303b (patch)
treee513ac49a62f2fbde540bbc57b3e162d7ff13624 /src/backend/parser/parse_expr.c
parent87564ffc6a87c6cdcc669472892be2ef0870a0f3 (diff)
downloadpostgresql-bf94076348ef7e0a81e3fe4ededb2fdcd14b303b.tar.gz
postgresql-bf94076348ef7e0a81e3fe4ededb2fdcd14b303b.zip
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.
Diffstat (limited to 'src/backend/parser/parse_expr.c')
-rw-r--r--src/backend/parser/parse_expr.c93
1 files changed, 60 insertions, 33 deletions
diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c
index 9f0a501dc53..45e488e33f5 100644
--- a/src/backend/parser/parse_expr.c
+++ b/src/backend/parser/parse_expr.c
@@ -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;
+
+ /*
+ * 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 true;
+ return false;
}
/*