diff options
Diffstat (limited to 'src/backend/utils/adt/ruleutils.c')
-rw-r--r-- | src/backend/utils/adt/ruleutils.c | 91 |
1 files changed, 52 insertions, 39 deletions
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c index 28e1acfb86a..29b5b1b8945 100644 --- a/src/backend/utils/adt/ruleutils.c +++ b/src/backend/utils/adt/ruleutils.c @@ -15,6 +15,7 @@ */ #include "postgres.h" +#include <ctype.h> #include <unistd.h> #include <fcntl.h> @@ -7977,6 +7978,13 @@ get_coercion_expr(Node *arg, deparse_context *context, * right above it. Avoid generating redundant output. However, beware of * suppressing casts when the user actually wrote something like * 'foo'::text::char(3). + * + * Note: it might seem that we are missing the possibility of needing to + * print a COLLATE clause for such a Const. However, a Const could only + * have nondefault collation in a post-constant-folding tree, in which the + * length coercion would have been folded too. See also the special + * handling of CollateExpr in coerce_to_target_type(): any collation + * marking will be above the coercion node, not below it. */ if (arg && IsA(arg, Const) && ((Const *) arg)->consttype == resulttype && @@ -8007,8 +8015,9 @@ get_coercion_expr(Node *arg, deparse_context *context, * the right type by default. * * If the Const's collation isn't default for its type, show that too. - * This can only happen in trees that have been through constant-folding. - * We assume we don't need to do this when showtype is -1. + * We mustn't do this when showtype is -1 (since that means the caller will + * print "::typename", and we can't put a COLLATE clause in between). It's + * caller's responsibility that collation isn't missed in such cases. * ---------- */ static void @@ -8018,8 +8027,7 @@ get_const_expr(Const *constval, deparse_context *context, int showtype) Oid typoutput; bool typIsVarlena; char *extval; - bool isfloat = false; - bool needlabel; + bool needlabel = false; if (constval->constisnull) { @@ -8045,40 +8053,42 @@ get_const_expr(Const *constval, deparse_context *context, int showtype) switch (constval->consttype) { - case INT2OID: case INT4OID: - case INT8OID: - case OIDOID: - case FLOAT4OID: - case FLOAT8OID: + + /* + * INT4 can be printed without any decoration, unless it is + * negative; in that case print it as '-nnn'::integer to ensure + * that the output will re-parse as a constant, not as a constant + * plus operator. In most cases we could get away with printing + * (-nnn) instead, because of the way that gram.y handles negative + * literals; but that doesn't work for INT_MIN, and it doesn't + * seem that much prettier anyway. + */ + if (extval[0] != '-') + appendStringInfoString(buf, extval); + else + { + appendStringInfo(buf, "'%s'", extval); + needlabel = true; /* we must attach a cast */ + } + break; + case NUMERICOID: + + /* + * NUMERIC can be printed without quotes if it looks like a float + * constant (not an integer, and not Infinity or NaN) and doesn't + * have a leading sign (for the same reason as for INT4). + */ + if (isdigit((unsigned char) extval[0]) && + strcspn(extval, "eE.") != strlen(extval)) { - /* - * These types are printed without quotes unless they contain - * values that aren't accepted by the scanner unquoted (e.g., - * 'NaN'). Note that strtod() and friends might accept NaN, - * so we can't use that to test. - * - * In reality we only need to defend against infinity and NaN, - * so we need not get too crazy about pattern matching here. - * - * There is a special-case gotcha: if the constant is signed, - * we need to parenthesize it, else the parser might see a - * leading plus/minus as binding less tightly than adjacent - * operators --- particularly, the cast that we might attach - * below. - */ - if (strspn(extval, "0123456789+-eE.") == strlen(extval)) - { - if (extval[0] == '+' || extval[0] == '-') - appendStringInfo(buf, "(%s)", extval); - else - appendStringInfoString(buf, extval); - if (strcspn(extval, "eE.") != strlen(extval)) - isfloat = true; /* it looks like a float */ - } - else - appendStringInfo(buf, "'%s'", extval); + appendStringInfoString(buf, extval); + } + else + { + appendStringInfo(buf, "'%s'", extval); + needlabel = true; /* we must attach a cast */ } break; @@ -8114,18 +8124,21 @@ get_const_expr(Const *constval, deparse_context *context, int showtype) switch (constval->consttype) { case BOOLOID: - case INT4OID: case UNKNOWNOID: /* These types can be left unlabeled */ needlabel = false; break; + case INT4OID: + /* We determined above whether a label is needed */ + break; case NUMERICOID: /* - * Float-looking constants will be typed as numeric, but if - * there's a specific typmod we need to show it. + * Float-looking constants will be typed as numeric, which we + * checked above; but if there's a nondefault typmod we need to + * show it. */ - needlabel = !isfloat || (constval->consttypmod >= 0); + needlabel |= (constval->consttypmod >= 0); break; default: needlabel = true; |