Fix up the remaining places where the expression node structure would lose
authorTom Lane <tgl@sss.pgh.pa.us>
Sat, 17 Mar 2007 00:11:05 +0000 (00:11 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Sat, 17 Mar 2007 00:11:05 +0000 (00:11 +0000)
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.

21 files changed:
src/backend/nodes/copyfuncs.c
src/backend/nodes/equalfuncs.c
src/backend/nodes/makefuncs.c
src/backend/nodes/outfuncs.c
src/backend/nodes/readfuncs.c
src/backend/optimizer/path/indxpath.c
src/backend/optimizer/plan/planagg.c
src/backend/optimizer/prep/preptlist.c
src/backend/optimizer/prep/prepunion.c
src/backend/optimizer/util/clauses.c
src/backend/optimizer/util/predtest.c
src/backend/parser/parse_coerce.c
src/backend/parser/parse_expr.c
src/backend/parser/parse_node.c
src/backend/rewrite/rewriteHandler.c
src/backend/utils/adt/ruleutils.c
src/backend/utils/adt/selfuncs.c
src/backend/utils/cache/lsyscache.c
src/include/catalog/catversion.h
src/include/nodes/makefuncs.h
src/include/nodes/primnodes.h

index 4ca9ba4c0e27ef4d94bf6feefe74802ddfe8f95c..f5dcc5b274e4a2ea35ea653979a69f8aace32a9f 100644 (file)
@@ -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);
index ae247dfa3ea11366656104f1621e4ae0f2e9d534..586397761191f74a7333463479b0b542dff760e9 100644 (file)
@@ -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);
index 83dd71737c0ef539ac84ea3d3225c0ec2ff5e875..9b7f42e463175b35aea9c1dc414339d3fcfebc8f 100644 (file)
@@ -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);
 }
 
 /*
index 68025ab36861fcd4b32b7c50e03eff07e4b70fe8..083f016cf8fb8893ce948f7a6028b74584446759 100644 (file)
@@ -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);
index 6478dce4b1c14e5a0b7a24379d6d07f08b4f97ac..70612c864f757471439dd4f34d95c2afd425fa5e 100644 (file)
@@ -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);
index 0146cacf4e5f9a4b8a5e726e4ee398b6bb0b1f5e..04e029beb28b7deee2345c27939cd214b48df5ef 100644 (file)
@@ -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);
 }
index 5411072b8dbb5f15e2c365f874b817ebc21bd197..95f0e64cc4190e7aa680de1b3740d1eeed287398 100644 (file)
@@ -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 */ );
 
index 310b57392cd9460e14039d3920929e9f6256d45d..587e8f8918dfda9398c17e7dab0d0ed38771d363 100644 (file)
@@ -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 */
index f09ddb1d23d1111205017deea44617f66fef7be0..5b4b312df1108789191c0a656676806fd7d11d78 100644 (file)
@@ -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,
index 11d2119f3c6c6df4352fcfdf71c34052cfc59640..1fa45e02a9c2b4f10b1ea9ba9590ae9afada5b0e 100644 (file)
@@ -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);
 }
index 62548ae45cbd48dbf87a6ab6479abb9d17cb7687..5da4d300204f503fb43086d37e5665f47f10c1e9 100644 (file)
@@ -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;
index 55f50713b31ea91c3f9cfac8450eac2cc299d2f2..00ce2a9927f433598a4b0b8e9438e55982d6537d 100644 (file)
@@ -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,
index 5791215a95f29589e5ab9375498d0a6e3f182c61..3da003fd09a17cb5210f2a32e77e554719101d9b 100644 (file)
@@ -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:
            {
                /*
index 4836159805b26270ff5251503e5abc0f21ebf610..a8dfa2666bb193f74077603dbc4f9c1fd9af3f11 100644 (file)
@@ -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,
index b63fb4aff39738b73613c5637907873baedad482..e5a1d4c74725f172e826eb917f683fef9a9d8693 100644 (file)
@@ -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 */
index 9ec0aa56f0aa201c6727f29a72656aeb26fbbea1..b1294b6d3222239cf8ad55596ff055cdac33ddda 100644 (file)
@@ -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));
 }
 
 
index 1588ac405a2fa6e0cf846aec5c908347c82a9be6..df61fea567b7e76db22cca5caa5e75dec74140ad 100644 (file)
@@ -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);
 }
 
 /*-------------------------------------------------------------------------
index d6ff883c92497d7066869801064200de5a1b70dd..6df288da45fed20202e9eb071cf48dd89e99f062 100644 (file)
@@ -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,
index 206cad6ba9fec276786c234a723b1ab1704dd016..0ae5f0c8991f0411c4e5a06761f84d8dddf34274 100644 (file)
@@ -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
index 470d0e137eb9a3e190636de8e264d71b459f8723..b500024e932880e2677961721cadfbf2fecbf48e 100644 (file)
@@ -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,
index 7efb6ec77cfaa970fa1062b1d976d6ed97e85bac..475bc149d7358338352502bc42f1eafc88583b49 100644 (file)
@@ -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