aboutsummaryrefslogtreecommitdiff
path: root/src/backend/utils/adt/ruleutils.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/utils/adt/ruleutils.c')
-rw-r--r--src/backend/utils/adt/ruleutils.c91
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;