A long time ago, Peter pointed out that ruleutils.c didn't dump simple
authorTom Lane <[email protected]>
Sun, 6 Jan 2008 01:03:31 +0000 (01:03 +0000)
committerTom Lane <[email protected]>
Sun, 6 Jan 2008 01:03:31 +0000 (01:03 +0000)
constant ORDER/GROUP BY entries properly:
http://archives.postgresql.org/pgsql-hackers/2001-04/msg00457.php
The original solution to that was in fact no good, as demonstrated by
today's report from Martin Pitt:
http://archives.postgresql.org/pgsql-bugs/2008-01/msg00027.php
We can't use the column-number-reference format for a constant that is
a resjunk targetlist entry, a case that was unfortunately not thought of
in the original discussion.  What we can do instead (which did not work
at the time, but does work in 7.3 and up) is to emit the constant with
explicit ::typename decoration, even if it otherwise wouldn't need it.
This is sufficient to keep the parser from thinking it's a column number
reference, and indeed is probably what the user must have done to get
such a thing into the querytree in the first place.

src/backend/utils/adt/ruleutils.c

index ba24ba96f6c7351f713507202b0e168050058f0e..c93aa1d7b07710407c79b24228471a370d9834a1 100644 (file)
@@ -200,7 +200,8 @@ 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_const_expr(Const *constval, deparse_context *context,
+                                                  int showtype);
 static void get_sublink_expr(SubLink *sublink, deparse_context *context);
 static void get_from_clause(Query *query, const char *prefix,
                                deparse_context *context);
@@ -2336,15 +2337,20 @@ get_rule_sortgroupclause(SortClause *srt, List *tlist, bool force_colno,
        expr = (Node *) tle->expr;
 
        /*
-        * Use column-number form if requested by caller or if expression is a
-        * constant --- a constant is ambiguous (and will be misinterpreted by
-        * findTargetlistEntry()) if we dump it explicitly.
+        * Use column-number form if requested by caller.  Otherwise, if
+        * expression is a constant, force it to be dumped with an explicit
+        * cast as decoration --- this is because a simple integer constant
+        * is ambiguous (and will be misinterpreted by findTargetlistEntry())
+        * if we dump it without any decoration.  Otherwise, just dump the
+        * expression normally.
         */
-       if (force_colno || (expr && IsA(expr, Const)))
+       if (force_colno)
        {
                Assert(!tle->resjunk);
                appendStringInfo(buf, "%d", tle->resno);
        }
+       else if (expr && IsA(expr, Const))
+               get_const_expr((Const *) expr, context, 1);
        else
                get_rule_expr(expr, context, true);
 
@@ -3244,7 +3250,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, 0);
                        break;
 
                case T_Param:
@@ -3981,10 +3987,14 @@ get_agg_expr(Aggref *aggref, deparse_context *context)
  * get_const_expr
  *
  *     Make a string representation of a Const
+ *
+ * showtype can be -1 to never show "::typename" decoration, or +1 to always
+ * show it, or 0 to show it only if the constant wouldn't be assumed to be
+ * the right type by default.
  * ----------
  */
 static void
-get_const_expr(Const *constval, deparse_context *context)
+get_const_expr(Const *constval, deparse_context *context, int showtype)
 {
        StringInfo      buf = context->buf;
        Oid                     typoutput;
@@ -4000,8 +4010,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 >= 0)
+                       appendStringInfo(buf, "::%s",
+                                                        format_type_with_typemod(constval->consttype,
+                                                                                                         -1));
                return;
        }
 
@@ -4088,10 +4101,15 @@ get_const_expr(Const *constval, deparse_context *context)
 
        pfree(extval);
 
+       if (showtype < 0)
+               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
-        * with the behavior of the parser, especially make_const.
+        * For showtype == 0, 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 with the behavior of the parser,
+        * especially make_const.
         */
        switch (constval->consttype)
        {
@@ -4109,7 +4127,7 @@ get_const_expr(Const *constval, deparse_context *context)
                        needlabel = true;
                        break;
        }
-       if (needlabel)
+       if (needlabel || showtype > 0)
                appendStringInfo(buf, "::%s",
                                                 format_type_with_typemod(constval->consttype, -1));
 }