From 0f4ff460c479e9c9bff90e8208f0a5272b9925df Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Sat, 17 Mar 2007 00:11:05 +0000 Subject: [PATCH] Fix up the remaining places where the expression node structure would lose available information about the typmod of an expression; namely, Const, ArrayRef, ArrayExpr, and EXPR and ARRAY SubLinks. In the ArrayExpr and SubLink cases it wasn't really the data structure's fault, but exprTypmod() being lazy. This seems like a good idea in view of the expected increase in typmod usage from Teodor's work to allow user-defined types to have typmods. In particular this responds to the concerns we had about eliminating the special-purpose hack that exprTypmod() used to have for BPCHAR Consts. We can now tell whether or not such a Const has been cast to a specific length, and report or display properly if so. initdb forced due to changes in stored rules. --- src/backend/nodes/copyfuncs.c | 5 +- src/backend/nodes/equalfuncs.c | 5 +- src/backend/nodes/makefuncs.c | 10 ++- src/backend/nodes/outfuncs.c | 5 +- src/backend/nodes/readfuncs.c | 5 +- src/backend/optimizer/path/indxpath.c | 9 +- src/backend/optimizer/plan/planagg.c | 4 +- src/backend/optimizer/prep/preptlist.c | 5 +- src/backend/optimizer/prep/prepunion.c | 3 +- src/backend/optimizer/util/clauses.c | 56 +++++++------ src/backend/optimizer/util/predtest.c | 3 +- src/backend/parser/parse_coerce.c | 5 +- src/backend/parser/parse_expr.c | 73 ++++++++++++++-- src/backend/parser/parse_node.c | 21 ++--- src/backend/rewrite/rewriteHandler.c | 4 +- src/backend/utils/adt/ruleutils.c | 112 +++++++++++++++++-------- src/backend/utils/adt/selfuncs.c | 8 +- src/backend/utils/cache/lsyscache.c | 3 +- src/include/catalog/catversion.h | 4 +- src/include/nodes/makefuncs.h | 3 +- src/include/nodes/primnodes.h | 13 +-- 21 files changed, 239 insertions(+), 117 deletions(-) diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c index 4ca9ba4c0e..f5dcc5b274 100644 --- a/src/backend/nodes/copyfuncs.c +++ b/src/backend/nodes/copyfuncs.c @@ -15,7 +15,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.370 2007/03/13 00:33:40 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.371 2007/03/17 00:11:03 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -773,6 +773,7 @@ _copyConst(Const *from) Const *newnode = makeNode(Const); COPY_SCALAR_FIELD(consttype); + COPY_SCALAR_FIELD(consttypmod); COPY_SCALAR_FIELD(constlen); if (from->constbyval || from->constisnull) @@ -841,9 +842,9 @@ _copyArrayRef(ArrayRef *from) { ArrayRef *newnode = makeNode(ArrayRef); - COPY_SCALAR_FIELD(refrestype); COPY_SCALAR_FIELD(refarraytype); COPY_SCALAR_FIELD(refelemtype); + COPY_SCALAR_FIELD(reftypmod); COPY_NODE_FIELD(refupperindexpr); COPY_NODE_FIELD(reflowerindexpr); COPY_NODE_FIELD(refexpr); diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c index ae247dfa3e..5863977611 100644 --- a/src/backend/nodes/equalfuncs.c +++ b/src/backend/nodes/equalfuncs.c @@ -18,7 +18,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.301 2007/03/13 00:33:40 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.302 2007/03/17 00:11:03 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -139,6 +139,7 @@ static bool _equalConst(Const *a, Const *b) { COMPARE_SCALAR_FIELD(consttype); + COMPARE_SCALAR_FIELD(consttypmod); COMPARE_SCALAR_FIELD(constlen); COMPARE_SCALAR_FIELD(constisnull); COMPARE_SCALAR_FIELD(constbyval); @@ -180,9 +181,9 @@ _equalAggref(Aggref *a, Aggref *b) static bool _equalArrayRef(ArrayRef *a, ArrayRef *b) { - COMPARE_SCALAR_FIELD(refrestype); COMPARE_SCALAR_FIELD(refarraytype); COMPARE_SCALAR_FIELD(refelemtype); + COMPARE_SCALAR_FIELD(reftypmod); COMPARE_NODE_FIELD(refupperindexpr); COMPARE_NODE_FIELD(reflowerindexpr); COMPARE_NODE_FIELD(refexpr); diff --git a/src/backend/nodes/makefuncs.c b/src/backend/nodes/makefuncs.c index 83dd71737c..9b7f42e463 100644 --- a/src/backend/nodes/makefuncs.c +++ b/src/backend/nodes/makefuncs.c @@ -9,7 +9,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/nodes/makefuncs.c,v 1.54 2007/01/05 22:19:30 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/nodes/makefuncs.c,v 1.55 2007/03/17 00:11:03 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -140,6 +140,7 @@ flatCopyTargetEntry(TargetEntry *src_tle) */ Const * makeConst(Oid consttype, + int32 consttypmod, int constlen, Datum constvalue, bool constisnull, @@ -148,6 +149,7 @@ makeConst(Oid consttype, Const *cnst = makeNode(Const); cnst->consttype = consttype; + cnst->consttypmod = consttypmod; cnst->constlen = constlen; cnst->constvalue = constvalue; cnst->constisnull = constisnull; @@ -159,6 +161,8 @@ makeConst(Oid consttype, /* * makeNullConst - * creates a Const node representing a NULL of the specified type + * + * Note: for all current uses, OK to set typmod of the Const to -1. */ Const * makeNullConst(Oid consttype) @@ -168,6 +172,7 @@ makeNullConst(Oid consttype) get_typlenbyval(consttype, &typLen, &typByVal); return makeConst(consttype, + -1, (int) typLen, (Datum) 0, true, @@ -182,7 +187,8 @@ Node * makeBoolConst(bool value, bool isnull) { /* note that pg_type.h hardwires size of bool as 1 ... duplicate it */ - return (Node *) makeConst(BOOLOID, 1, BoolGetDatum(value), isnull, true); + return (Node *) makeConst(BOOLOID, -1, 1, + BoolGetDatum(value), isnull, true); } /* diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c index 68025ab368..083f016cf8 100644 --- a/src/backend/nodes/outfuncs.c +++ b/src/backend/nodes/outfuncs.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.303 2007/03/13 00:33:40 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.304 2007/03/17 00:11:03 tgl Exp $ * * NOTES * Every node type that can appear in stored rules' parsetrees *must* @@ -685,6 +685,7 @@ _outConst(StringInfo str, Const *node) WRITE_NODE_TYPE("CONST"); WRITE_OID_FIELD(consttype); + WRITE_INT_FIELD(consttypmod); WRITE_INT_FIELD(constlen); WRITE_BOOL_FIELD(constbyval); WRITE_BOOL_FIELD(constisnull); @@ -725,9 +726,9 @@ _outArrayRef(StringInfo str, ArrayRef *node) { WRITE_NODE_TYPE("ARRAYREF"); - WRITE_OID_FIELD(refrestype); WRITE_OID_FIELD(refarraytype); WRITE_OID_FIELD(refelemtype); + WRITE_INT_FIELD(reftypmod); WRITE_NODE_FIELD(refupperindexpr); WRITE_NODE_FIELD(reflowerindexpr); WRITE_NODE_FIELD(refexpr); diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c index 6478dce4b1..70612c864f 100644 --- a/src/backend/nodes/readfuncs.c +++ b/src/backend/nodes/readfuncs.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/nodes/readfuncs.c,v 1.203 2007/02/20 17:32:15 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/nodes/readfuncs.c,v 1.204 2007/03/17 00:11:04 tgl Exp $ * * NOTES * Path and Plan nodes do not have any readfuncs support, because we @@ -324,6 +324,7 @@ _readConst(void) READ_LOCALS(Const); READ_OID_FIELD(consttype); + READ_INT_FIELD(consttypmod); READ_INT_FIELD(constlen); READ_BOOL_FIELD(constbyval); READ_BOOL_FIELD(constisnull); @@ -379,9 +380,9 @@ _readArrayRef(void) { READ_LOCALS(ArrayRef); - READ_OID_FIELD(refrestype); READ_OID_FIELD(refarraytype); READ_OID_FIELD(refelemtype); + READ_INT_FIELD(reftypmod); READ_NODE_FIELD(refupperindexpr); READ_NODE_FIELD(reflowerindexpr); READ_NODE_FIELD(refexpr); diff --git a/src/backend/optimizer/path/indxpath.c b/src/backend/optimizer/path/indxpath.c index 0146cacf4e..04e029beb2 100644 --- a/src/backend/optimizer/path/indxpath.c +++ b/src/backend/optimizer/path/indxpath.c @@ -9,7 +9,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/optimizer/path/indxpath.c,v 1.216 2007/01/20 20:45:39 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/path/indxpath.c,v 1.217 2007/03/17 00:11:04 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -2628,7 +2628,7 @@ network_prefix_quals(Node *leftop, Oid expr_op, Oid opfamily, Datum rightop) expr = make_opclause(opr1oid, BOOLOID, false, (Expr *) leftop, - (Expr *) makeConst(datatype, -1, opr1right, + (Expr *) makeConst(datatype, -1, -1, opr1right, false, false)); result = list_make1(make_restrictinfo(expr, true, false, false, NULL)); @@ -2643,7 +2643,7 @@ network_prefix_quals(Node *leftop, Oid expr_op, Oid opfamily, Datum rightop) expr = make_opclause(opr2oid, BOOLOID, false, (Expr *) leftop, - (Expr *) makeConst(datatype, -1, opr2right, + (Expr *) makeConst(datatype, -1, -1, opr2right, false, false)); result = lappend(result, make_restrictinfo(expr, true, false, false, NULL)); @@ -2683,6 +2683,7 @@ string_to_const(const char *str, Oid datatype) { Datum conval = string_to_datum(str, datatype); - return makeConst(datatype, ((datatype == NAMEOID) ? NAMEDATALEN : -1), + return makeConst(datatype, -1, + ((datatype == NAMEOID) ? NAMEDATALEN : -1), conval, false, false); } diff --git a/src/backend/optimizer/plan/planagg.c b/src/backend/optimizer/plan/planagg.c index 5411072b8d..95f0e64cc4 100644 --- a/src/backend/optimizer/plan/planagg.c +++ b/src/backend/optimizer/plan/planagg.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/optimizer/plan/planagg.c,v 1.29 2007/02/22 22:00:24 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/plan/planagg.c,v 1.30 2007/03/17 00:11:04 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -477,7 +477,7 @@ make_agg_subplan(PlannerInfo *root, MinMaxAggInfo *info) /* set up LIMIT 1 */ subparse->limitOffset = NULL; - subparse->limitCount = (Node *) makeConst(INT8OID, sizeof(int64), + subparse->limitCount = (Node *) makeConst(INT8OID, -1, sizeof(int64), Int64GetDatum(1), false, false /* not by val */ ); diff --git a/src/backend/optimizer/prep/preptlist.c b/src/backend/optimizer/prep/preptlist.c index 310b57392c..587e8f8918 100644 --- a/src/backend/optimizer/prep/preptlist.c +++ b/src/backend/optimizer/prep/preptlist.c @@ -16,7 +16,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/optimizer/prep/preptlist.c,v 1.86 2007/02/19 07:03:30 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/prep/preptlist.c,v 1.87 2007/03/17 00:11:04 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -281,6 +281,7 @@ expand_targetlist(List *tlist, int command_type, if (!att_tup->attisdropped) { new_expr = (Node *) makeConst(atttype, + -1, att_tup->attlen, (Datum) 0, true, /* isnull */ @@ -296,6 +297,7 @@ expand_targetlist(List *tlist, int command_type, { /* Insert NULL for dropped column */ new_expr = (Node *) makeConst(INT4OID, + -1, sizeof(int32), (Datum) 0, true, /* isnull */ @@ -315,6 +317,7 @@ expand_targetlist(List *tlist, int command_type, { /* Insert NULL for dropped column */ new_expr = (Node *) makeConst(INT4OID, + -1, sizeof(int32), (Datum) 0, true, /* isnull */ diff --git a/src/backend/optimizer/prep/prepunion.c b/src/backend/optimizer/prep/prepunion.c index f09ddb1d23..5b4b312df1 100644 --- a/src/backend/optimizer/prep/prepunion.c +++ b/src/backend/optimizer/prep/prepunion.c @@ -22,7 +22,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/optimizer/prep/prepunion.c,v 1.139 2007/02/22 22:00:24 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/prep/prepunion.c,v 1.140 2007/03/17 00:11:04 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -545,6 +545,7 @@ generate_setop_tlist(List *colTypes, int flag, /* Add a resjunk flag column */ /* flag value is the given constant */ expr = (Node *) makeConst(INT4OID, + -1, sizeof(int4), Int32GetDatum(flag), false, diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c index 11d2119f3c..1fa45e02a9 100644 --- a/src/backend/optimizer/util/clauses.c +++ b/src/backend/optimizer/util/clauses.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.238 2007/03/13 00:33:41 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.239 2007/03/17 00:11:04 tgl Exp $ * * HISTORY * AUTHOR DATE MAJOR EVENT @@ -82,10 +82,12 @@ static List *simplify_and_arguments(List *args, eval_const_expressions_context *context, bool *haveNull, bool *forceFalse); static Expr *simplify_boolean_equality(List *args); -static Expr *simplify_function(Oid funcid, Oid result_type, List *args, +static Expr *simplify_function(Oid funcid, + Oid result_type, int32 result_typmod, List *args, bool allow_inline, eval_const_expressions_context *context); -static Expr *evaluate_function(Oid funcid, Oid result_type, List *args, +static Expr *evaluate_function(Oid funcid, + Oid result_type, int32 result_typmod, List *args, HeapTuple func_tuple, eval_const_expressions_context *context); static Expr *inline_function(Oid funcid, Oid result_type, List *args, @@ -96,7 +98,7 @@ static Node *substitute_actual_parameters(Node *expr, int nargs, List *args, static Node *substitute_actual_parameters_mutator(Node *node, substitute_actual_parameters_context *context); static void sql_inline_error_callback(void *arg); -static Expr *evaluate_expr(Expr *expr, Oid result_type); +static Expr *evaluate_expr(Expr *expr, Oid result_type, int32 result_typmod); /***************************************************************************** @@ -934,8 +936,6 @@ contain_nonstrict_functions_walker(Node *node, void *context) return true; if (IsA(node, CaseExpr)) return true; - if (IsA(node, CaseWhen)) - return true; if (IsA(node, ArrayExpr)) return true; if (IsA(node, RowExpr)) @@ -1654,6 +1654,7 @@ eval_const_expressions_mutator(Node *node, else pval = datumCopy(prm->value, typByVal, typLen); return (Node *) makeConst(param->paramtype, + param->paramtypmod, (int) typLen, pval, prm->isnull, @@ -1682,9 +1683,13 @@ eval_const_expressions_mutator(Node *node, /* * Code for op/func reduction is pretty bulky, so split it out as a - * separate function. + * separate function. Note: exprTypmod normally returns -1 for a + * FuncExpr, but not when the node is recognizably a length coercion; + * we want to preserve the typmod in the eventual Const if so. */ - simple = simplify_function(expr->funcid, expr->funcresulttype, args, + simple = simplify_function(expr->funcid, + expr->funcresulttype, exprTypmod(node), + args, true, context); if (simple) /* successfully simplified it */ return (Node *) simple; @@ -1728,7 +1733,9 @@ eval_const_expressions_mutator(Node *node, * Code for op/func reduction is pretty bulky, so split it out as a * separate function. */ - simple = simplify_function(expr->opfuncid, expr->opresulttype, args, + simple = simplify_function(expr->opfuncid, + expr->opresulttype, -1, + args, true, context); if (simple) /* successfully simplified it */ return (Node *) simple; @@ -1816,8 +1823,10 @@ eval_const_expressions_mutator(Node *node, * Code for op/func reduction is pretty bulky, so split it out as * a separate function. */ - simple = simplify_function(expr->opfuncid, expr->opresulttype, - args, false, context); + simple = simplify_function(expr->opfuncid, + expr->opresulttype, -1, + args, + false, context); if (simple) /* successfully simplified it */ { /* @@ -1961,12 +1970,7 @@ eval_const_expressions_mutator(Node *node, Const *con = (Const *) arg; con->consttype = relabel->resulttype; - - /* - * relabel's resulttypmod is discarded, which is OK for now; if - * the type actually needs a runtime length coercion then there - * should be a function call to do it just above this node. - */ + con->consttypmod = relabel->resulttypmod; return (Node *) con; } else @@ -2134,7 +2138,8 @@ eval_const_expressions_mutator(Node *node, if (all_const) return (Node *) evaluate_expr((Expr *) newarray, - newarray->array_typeid); + newarray->array_typeid, + exprTypmod(node)); return (Node *) newarray; } @@ -2637,14 +2642,15 @@ simplify_boolean_equality(List *args) * (which might originally have been an operator; we don't care) * * Inputs are the function OID, actual result type OID (which is needed for - * polymorphic functions), and the pre-simplified argument list; + * polymorphic functions) and typmod, and the pre-simplified argument list; * also the context data for eval_const_expressions. * * Returns a simplified expression if successful, or NULL if cannot * simplify the function call. */ static Expr * -simplify_function(Oid funcid, Oid result_type, List *args, +simplify_function(Oid funcid, Oid result_type, int32 result_typmod, + List *args, bool allow_inline, eval_const_expressions_context *context) { @@ -2665,7 +2671,7 @@ simplify_function(Oid funcid, Oid result_type, List *args, if (!HeapTupleIsValid(func_tuple)) elog(ERROR, "cache lookup failed for function %u", funcid); - newexpr = evaluate_function(funcid, result_type, args, + newexpr = evaluate_function(funcid, result_type, result_typmod, args, func_tuple, context); if (!newexpr && allow_inline) @@ -2689,7 +2695,7 @@ simplify_function(Oid funcid, Oid result_type, List *args, * simplify the function. */ static Expr * -evaluate_function(Oid funcid, Oid result_type, List *args, +evaluate_function(Oid funcid, Oid result_type, int32 result_typmod, List *args, HeapTuple func_tuple, eval_const_expressions_context *context) { @@ -2773,7 +2779,7 @@ evaluate_function(Oid funcid, Oid result_type, List *args, newexpr->funcformat = COERCE_DONTCARE; /* doesn't matter */ newexpr->args = args; - return evaluate_expr((Expr *) newexpr, result_type); + return evaluate_expr((Expr *) newexpr, result_type, result_typmod); } /* @@ -3133,7 +3139,7 @@ sql_inline_error_callback(void *arg) * code and ensure we get the same result as the executor would get. */ static Expr * -evaluate_expr(Expr *expr, Oid result_type) +evaluate_expr(Expr *expr, Oid result_type, int32 result_typmod) { EState *estate; ExprState *exprstate; @@ -3184,7 +3190,7 @@ evaluate_expr(Expr *expr, Oid result_type) /* * Make the constant result node. */ - return (Expr *) makeConst(result_type, resultTypLen, + return (Expr *) makeConst(result_type, result_typmod, resultTypLen, const_val, const_is_null, resultTypByVal); } diff --git a/src/backend/optimizer/util/predtest.c b/src/backend/optimizer/util/predtest.c index 62548ae45c..5da4d30020 100644 --- a/src/backend/optimizer/util/predtest.c +++ b/src/backend/optimizer/util/predtest.c @@ -9,7 +9,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/optimizer/util/predtest.c,v 1.13 2007/01/05 22:19:33 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/util/predtest.c,v 1.14 2007/03/17 00:11:04 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -828,6 +828,7 @@ arrayconst_startup_fn(Node *clause, PredIterInfo info) /* Set up a dummy Const node to hold the per-element values */ state->constexpr.xpr.type = T_Const; state->constexpr.consttype = ARR_ELEMTYPE(arrayval); + state->constexpr.consttypmod = -1; state->constexpr.constlen = elmlen; state->constexpr.constbyval = elmbyval; lsecond(state->opexpr.args) = &state->constexpr; diff --git a/src/backend/parser/parse_coerce.c b/src/backend/parser/parse_coerce.c index 55f50713b3..00ce2a9927 100644 --- a/src/backend/parser/parse_coerce.c +++ b/src/backend/parser/parse_coerce.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/parser/parse_coerce.c,v 2.150 2007/01/05 22:19:34 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/parser/parse_coerce.c,v 2.151 2007/03/17 00:11:04 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -186,6 +186,7 @@ coerce_type(ParseState *pstate, Node *node, targetType = typeidType(baseTypeId); newcon->consttype = baseTypeId; + newcon->consttypmod = -1; newcon->constlen = typeLen(targetType); newcon->constbyval = typeByVal(targetType); newcon->constisnull = con->constisnull; @@ -661,6 +662,7 @@ build_coercion_expression(Node *node, Oid funcId, { /* Pass target typmod as an int4 constant */ cons = makeConst(INT4OID, + -1, sizeof(int32), Int32GetDatum(targetTypMod), false, @@ -673,6 +675,7 @@ build_coercion_expression(Node *node, Oid funcId, { /* Pass it a boolean isExplicit parameter, too */ cons = makeConst(BOOLOID, + -1, sizeof(bool), BoolGetDatum(isExplicit), false, diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c index 5791215a95..3da003fd09 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.212 2007/02/22 22:00:25 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/parser/parse_expr.c,v 1.213 2007/03/17 00:11:04 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -312,7 +312,7 @@ transformIndirection(ParseState *pstate, Node *basenode, List *indirection) result, exprType(result), InvalidOid, - -1, + exprTypmod(result), subscripts, NULL); subscripts = NIL; @@ -330,7 +330,7 @@ transformIndirection(ParseState *pstate, Node *basenode, List *indirection) result, exprType(result), InvalidOid, - -1, + exprTypmod(result), subscripts, NULL); @@ -1705,7 +1705,15 @@ exprType(Node *expr) type = ((Aggref *) expr)->aggtype; break; case T_ArrayRef: - type = ((ArrayRef *) expr)->refrestype; + { + ArrayRef *arrayref = (ArrayRef *) expr; + + /* slice and/or store operations yield the array type */ + if (arrayref->reflowerindexpr || arrayref->refassgnexpr) + type = arrayref->refarraytype; + else + type = arrayref->refelemtype; + } break; case T_FuncExpr: type = ((FuncExpr *) expr)->funcresulttype; @@ -1802,9 +1810,6 @@ exprType(Node *expr) case T_CaseExpr: type = ((CaseExpr *) expr)->casetype; break; - case T_CaseWhen: - type = exprType((Node *) ((CaseWhen *) expr)->result); - break; case T_CaseTestExpr: type = ((CaseTestExpr *) expr)->typeId; break; @@ -1872,8 +1877,13 @@ exprTypmod(Node *expr) { case T_Var: return ((Var *) expr)->vartypmod; + case T_Const: + return ((Const *) expr)->consttypmod; case T_Param: return ((Param *) expr)->paramtypmod; + case T_ArrayRef: + /* typmod is the same for array or element */ + return ((ArrayRef *) expr)->reftypmod; case T_FuncExpr: { int32 coercedTypmod; @@ -1883,6 +1893,27 @@ exprTypmod(Node *expr) return coercedTypmod; } break; + case T_SubLink: + { + SubLink *sublink = (SubLink *) expr; + + if (sublink->subLinkType == EXPR_SUBLINK || + sublink->subLinkType == ARRAY_SUBLINK) + { + /* get the typmod of the subselect's first target column */ + Query *qtree = (Query *) sublink->subselect; + TargetEntry *tent; + + if (!qtree || !IsA(qtree, Query)) + elog(ERROR, "cannot get type for untransformed sublink"); + tent = (TargetEntry *) linitial(qtree->targetList); + Assert(IsA(tent, TargetEntry)); + Assert(!tent->resjunk); + return exprTypmod((Node *) tent->expr); + /* note we don't need to care if it's an array */ + } + } + break; case T_FieldSelect: return ((FieldSelect *) expr)->resulttypmod; case T_RelabelType: @@ -1920,6 +1951,34 @@ exprTypmod(Node *expr) break; case T_CaseTestExpr: return ((CaseTestExpr *) expr)->typeMod; + case T_ArrayExpr: + { + /* + * If all the elements agree on type/typmod, return that + * typmod, else use -1 + */ + ArrayExpr *arrayexpr = (ArrayExpr *) expr; + Oid arraytype = arrayexpr->array_typeid; + int32 typmod; + ListCell *elem; + + if (arrayexpr->elements == NIL) + return -1; + typmod = exprTypmod((Node *) linitial(arrayexpr->elements)); + if (typmod < 0) + return -1; /* no point in trying harder */ + foreach(elem, arrayexpr->elements) + { + Node *e = (Node *) lfirst(elem); + + if (exprType(e) != arraytype) + return -1; + if (exprTypmod(e) != typmod) + return -1; + } + return typmod; + } + break; case T_CoalesceExpr: { /* diff --git a/src/backend/parser/parse_node.c b/src/backend/parser/parse_node.c index 4836159805..a8dfa2666b 100644 --- a/src/backend/parser/parse_node.c +++ b/src/backend/parser/parse_node.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/parser/parse_node.c,v 1.96 2007/01/05 22:19:34 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/parser/parse_node.c,v 1.97 2007/03/17 00:11:04 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -153,7 +153,8 @@ transformArrayType(Oid arrayType) * arrayType OID of array's datatype (should match type of arrayBase) * elementType OID of array's element type (fetch with transformArrayType, * or pass InvalidOid to do it here) - * elementTypMod typmod to be applied to array elements (if storing) + * elementTypMod typmod to be applied to array elements (if storing) or of + * the source array (if fetching) * indirection Untransformed list of subscripts (must not be NIL) * assignFrom NULL for array fetch, else transformed expression for source. */ @@ -166,7 +167,6 @@ transformArraySubscripts(ParseState *pstate, List *indirection, Node *assignFrom) { - Oid resultType; bool isSlice = false; List *upperIndexpr = NIL; List *lowerIndexpr = NIL; @@ -196,16 +196,6 @@ transformArraySubscripts(ParseState *pstate, } } - /* - * The type represented by the subscript expression is the element type if - * we are fetching a single element, but it is the same as the array type - * if we are fetching a slice or storing. - */ - if (isSlice || assignFrom != NULL) - resultType = arrayType; - else - resultType = elementType; - /* * Transform the subscript expressions. */ @@ -235,6 +225,7 @@ transformArraySubscripts(ParseState *pstate, { /* Make a constant 1 */ subexpr = (Node *) makeConst(INT4OID, + -1, sizeof(int32), Int32GetDatum(1), false, @@ -284,9 +275,9 @@ transformArraySubscripts(ParseState *pstate, * Ready to build the ArrayRef node. */ aref = makeNode(ArrayRef); - aref->refrestype = resultType; aref->refarraytype = arrayType; aref->refelemtype = elementType; + aref->reftypmod = elementTypMod; aref->refupperindexpr = upperIndexpr; aref->reflowerindexpr = lowerIndexpr; aref->refexpr = (Expr *) arrayBase; @@ -399,6 +390,7 @@ make_const(Value *value) case T_Null: /* return a null const */ con = makeConst(UNKNOWNOID, + -1, -2, (Datum) 0, true, @@ -411,6 +403,7 @@ make_const(Value *value) } con = makeConst(typeid, + -1, /* typmod -1 is OK for all cases */ typelen, val, false, diff --git a/src/backend/rewrite/rewriteHandler.c b/src/backend/rewrite/rewriteHandler.c index b63fb4aff3..e5a1d4c747 100644 --- a/src/backend/rewrite/rewriteHandler.c +++ b/src/backend/rewrite/rewriteHandler.c @@ -7,7 +7,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/rewrite/rewriteHandler.c,v 1.171 2007/03/01 18:50:28 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/rewrite/rewriteHandler.c,v 1.172 2007/03/17 00:11:04 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -643,6 +643,7 @@ rewriteTargetList(Query *parsetree, Relation target_relation, else { new_expr = (Node *) makeConst(att_tup->atttypid, + -1, att_tup->attlen, (Datum) 0, true, /* isnull */ @@ -981,6 +982,7 @@ rewriteValuesRTE(RangeTblEntry *rte, Relation target_relation, List *attrnos) if (!new_expr) { new_expr = (Node *) makeConst(att_tup->atttypid, + -1, att_tup->attlen, (Datum) 0, true, /* isnull */ diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c index 9ec0aa56f0..b1294b6d32 100644 --- a/src/backend/utils/adt/ruleutils.c +++ b/src/backend/utils/adt/ruleutils.c @@ -9,7 +9,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.253 2007/03/15 23:12:06 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.254 2007/03/17 00:11:05 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -170,7 +170,11 @@ static void get_oper_expr(OpExpr *expr, deparse_context *context); static void get_func_expr(FuncExpr *expr, deparse_context *context, bool showimplicit); static void get_agg_expr(Aggref *aggref, deparse_context *context); -static void get_const_expr(Const *constval, deparse_context *context); +static void get_coercion_expr(Node *arg, deparse_context *context, + Oid resulttype, int32 resulttypmod, + Node *parentNode); +static void get_const_expr(Const *constval, deparse_context *context, + bool showtype); static void get_sublink_expr(SubLink *sublink, deparse_context *context); static void get_from_clause(Query *query, const char *prefix, deparse_context *context); @@ -3364,7 +3368,7 @@ get_rule_expr(Node *node, deparse_context *context, break; case T_Const: - get_const_expr((Const *) node, context); + get_const_expr((Const *) node, context, true); break; case T_Param: @@ -3576,14 +3580,10 @@ get_rule_expr(Node *node, deparse_context *context, } else { - if (!PRETTY_PAREN(context)) - appendStringInfoChar(buf, '('); - get_rule_expr_paren(arg, context, false, node); - if (!PRETTY_PAREN(context)) - appendStringInfoChar(buf, ')'); - appendStringInfo(buf, "::%s", - format_type_with_typemod(relabel->resulttype, - relabel->resulttypmod)); + get_coercion_expr(arg, context, + relabel->resulttype, + relabel->resulttypmod, + node); } } break; @@ -3601,13 +3601,9 @@ get_rule_expr(Node *node, deparse_context *context, } else { - if (!PRETTY_PAREN(context)) - appendStringInfoChar(buf, '('); - get_rule_expr_paren(arg, context, false, node); - if (!PRETTY_PAREN(context)) - appendStringInfoChar(buf, ')'); - appendStringInfo(buf, "::%s", - format_type_with_typemod(convert->resulttype, -1)); + get_coercion_expr(arg, context, + convert->resulttype, -1, + node); } } break; @@ -4070,14 +4066,10 @@ get_rule_expr(Node *node, deparse_context *context, } else { - if (!PRETTY_PAREN(context)) - appendStringInfoChar(buf, '('); - get_rule_expr_paren(arg, context, false, node); - if (!PRETTY_PAREN(context)) - appendStringInfoChar(buf, ')'); - appendStringInfo(buf, "::%s", - format_type_with_typemod(ctest->resulttype, - ctest->resulttypmod)); + get_coercion_expr(arg, context, + ctest->resulttype, + ctest->resulttypmod, + node); } } break; @@ -4213,13 +4205,9 @@ get_func_expr(FuncExpr *expr, deparse_context *context, /* Get the typmod if this is a length-coercion function */ (void) exprIsLengthCoercion((Node *) expr, &coercedTypmod); - if (!PRETTY_PAREN(context)) - appendStringInfoChar(buf, '('); - get_rule_expr_paren(arg, context, false, (Node *) expr); - if (!PRETTY_PAREN(context)) - appendStringInfoChar(buf, ')'); - appendStringInfo(buf, "::%s", - format_type_with_typemod(rettype, coercedTypmod)); + get_coercion_expr(arg, context, + rettype, coercedTypmod, + (Node *) expr); return; } @@ -4278,15 +4266,58 @@ get_agg_expr(Aggref *aggref, deparse_context *context) appendStringInfoChar(buf, ')'); } +/* ---------- + * get_coercion_expr + * + * Make a string representation of a value coerced to a specific type + * ---------- + */ +static void +get_coercion_expr(Node *arg, deparse_context *context, + Oid resulttype, int32 resulttypmod, + Node *parentNode) +{ + StringInfo buf = context->buf; + + /* + * Since parse_coerce.c doesn't immediately collapse application of + * length-coercion functions to constants, what we'll typically see + * in such cases is a Const with typmod -1 and a length-coercion + * function right above it. Avoid generating redundant output. + * However, beware of suppressing casts when the user actually wrote + * something like 'foo'::text::char(3). + */ + if (arg && IsA(arg, Const) && + ((Const *) arg)->consttype == resulttype && + ((Const *) arg)->consttypmod == -1) + { + /* Show the constant without normal ::typename decoration */ + get_const_expr((Const *) arg, context, false); + } + else + { + if (!PRETTY_PAREN(context)) + appendStringInfoChar(buf, '('); + get_rule_expr_paren(arg, context, false, parentNode); + if (!PRETTY_PAREN(context)) + appendStringInfoChar(buf, ')'); + } + appendStringInfo(buf, "::%s", + format_type_with_typemod(resulttype, resulttypmod)); +} /* ---------- * get_const_expr * * Make a string representation of a Const + * + * Note: if showtype is false, the Const is the direct argument of a coercion + * operation with the same target type, and so we should suppress "::typename" + * to avoid redundant output. * ---------- */ static void -get_const_expr(Const *constval, deparse_context *context) +get_const_expr(Const *constval, deparse_context *context, bool showtype) { StringInfo buf = context->buf; Oid typoutput; @@ -4302,8 +4333,11 @@ get_const_expr(Const *constval, deparse_context *context) * Always label the type of a NULL constant to prevent misdecisions * about type when reparsing. */ - appendStringInfo(buf, "NULL::%s", - format_type_with_typemod(constval->consttype, -1)); + appendStringInfo(buf, "NULL"); + if (showtype) + appendStringInfo(buf, "::%s", + format_type_with_typemod(constval->consttype, + constval->consttypmod)); return; } @@ -4376,6 +4410,9 @@ get_const_expr(Const *constval, deparse_context *context) pfree(extval); + if (!showtype) + return; + /* * Append ::typename unless the constant will be implicitly typed as the * right type when it is read in. XXX this code has to be kept in sync @@ -4399,7 +4436,8 @@ get_const_expr(Const *constval, deparse_context *context) } if (needlabel) appendStringInfo(buf, "::%s", - format_type_with_typemod(constval->consttype, -1)); + format_type_with_typemod(constval->consttype, + constval->consttypmod)); } diff --git a/src/backend/utils/adt/selfuncs.c b/src/backend/utils/adt/selfuncs.c index 1588ac405a..df61fea567 100644 --- a/src/backend/utils/adt/selfuncs.c +++ b/src/backend/utils/adt/selfuncs.c @@ -15,7 +15,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/adt/selfuncs.c,v 1.228 2007/02/27 23:48:09 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/utils/adt/selfuncs.c,v 1.229 2007/03/17 00:11:05 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -1599,6 +1599,7 @@ scalararraysel(PlannerInfo *root, args = list_make2(leftop, makeConst(nominal_element_type, + -1, elmlen, elem_values[i], elem_nulls[i], @@ -4717,7 +4718,8 @@ string_to_const(const char *str, Oid datatype) { Datum conval = string_to_datum(str, datatype); - return makeConst(datatype, ((datatype == NAMEOID) ? NAMEDATALEN : -1), + return makeConst(datatype, -1, + ((datatype == NAMEOID) ? NAMEDATALEN : -1), conval, false, false); } @@ -4734,7 +4736,7 @@ string_to_bytea_const(const char *str, size_t str_len) SET_VARSIZE(bstr, VARHDRSZ + str_len); conval = PointerGetDatum(bstr); - return makeConst(BYTEAOID, -1, conval, false, false); + return makeConst(BYTEAOID, -1, -1, conval, false, false); } /*------------------------------------------------------------------------- diff --git a/src/backend/utils/cache/lsyscache.c b/src/backend/utils/cache/lsyscache.c index d6ff883c92..6df288da45 100644 --- a/src/backend/utils/cache/lsyscache.c +++ b/src/backend/utils/cache/lsyscache.c @@ -7,7 +7,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/cache/lsyscache.c,v 1.148 2007/02/14 01:58:57 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/utils/cache/lsyscache.c,v 1.149 2007/03/17 00:11:05 tgl Exp $ * * NOTES * Eventually, the index information should go through here, too. @@ -1964,6 +1964,7 @@ get_typdefault(Oid typid) getTypeIOParam(typeTuple), -1); /* Build a Const node containing the value */ expr = (Node *) makeConst(typid, + -1, type->typlen, datum, false, diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h index 206cad6ba9..0ae5f0c899 100644 --- a/src/include/catalog/catversion.h +++ b/src/include/catalog/catversion.h @@ -37,7 +37,7 @@ * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.390 2007/03/16 17:57:36 mha Exp $ + * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.391 2007/03/17 00:11:05 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -53,6 +53,6 @@ */ /* yyyymmddN */ -#define CATALOG_VERSION_NO 200703161 +#define CATALOG_VERSION_NO 200703162 #endif diff --git a/src/include/nodes/makefuncs.h b/src/include/nodes/makefuncs.h index 470d0e137e..b500024e93 100644 --- a/src/include/nodes/makefuncs.h +++ b/src/include/nodes/makefuncs.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/nodes/makefuncs.h,v 1.57 2007/01/05 22:19:55 momjian Exp $ + * $PostgreSQL: pgsql/src/include/nodes/makefuncs.h,v 1.58 2007/03/17 00:11:05 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -37,6 +37,7 @@ extern TargetEntry *makeTargetEntry(Expr *expr, extern TargetEntry *flatCopyTargetEntry(TargetEntry *src_tle); extern Const *makeConst(Oid consttype, + int32 consttypmod, int constlen, Datum constvalue, bool constisnull, diff --git a/src/include/nodes/primnodes.h b/src/include/nodes/primnodes.h index 7efb6ec77c..475bc149d7 100644 --- a/src/include/nodes/primnodes.h +++ b/src/include/nodes/primnodes.h @@ -10,7 +10,7 @@ * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/nodes/primnodes.h,v 1.127 2007/02/22 22:00:25 tgl Exp $ + * $PostgreSQL: pgsql/src/include/nodes/primnodes.h,v 1.128 2007/03/17 00:11:05 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -154,7 +154,8 @@ typedef struct Var typedef struct Const { Expr xpr; - Oid consttype; /* PG_TYPE OID of the constant's datatype */ + Oid consttype; /* pg_type OID of the constant's datatype */ + int32 consttypmod; /* typmod value, if any */ int constlen; /* typlen of the constant's datatype */ Datum constvalue; /* the constant's value */ bool constisnull; /* whether the constant is null (if true, @@ -236,17 +237,17 @@ typedef struct Aggref * reflowerindexpr must be the same length as refupperindexpr when it * is not NIL. * - * Note: refrestype is NOT the element type, but the array type, - * when doing subarray fetch or either type of store. + * Note: the result datatype is the element type when fetching a single + * element; but it is the array type when doing subarray fetch or either + * type of store. * ---------------- */ typedef struct ArrayRef { Expr xpr; - Oid refrestype; /* type of the result of the ArrayRef - * operation */ Oid refarraytype; /* type of the array proper */ Oid refelemtype; /* type of the array elements */ + int32 reftypmod; /* typmod of the array (and elements too) */ List *refupperindexpr;/* expressions that evaluate to upper array * indexes */ List *reflowerindexpr;/* expressions that evaluate to lower array