Skip to content

Commit 3e21ecb

Browse files
committed
Make the rule deparser a little less quote-happy, so that
display of default expressions isn't quite so ugly.
1 parent 7cd67c8 commit 3e21ecb

File tree

1 file changed

+147
-63
lines changed

1 file changed

+147
-63
lines changed

src/backend/utils/adt/ruleutils.c

Lines changed: 147 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
* out of it's tuple
44
*
55
* IDENTIFICATION
6-
* $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.27 1999/10/03 23:55:31 tgl Exp $
6+
* $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.28 1999/10/04 04:37:23 tgl Exp $
77
*
88
* This software is copyrighted by Jan Wieck - Hamburg.
99
*
@@ -47,6 +47,7 @@
4747
#include "catalog/pg_index.h"
4848
#include "catalog/pg_operator.h"
4949
#include "catalog/pg_shadow.h"
50+
#include "catalog/pg_type.h"
5051
#include "utils/builtins.h"
5152
#include "utils/lsyscache.h"
5253

@@ -104,6 +105,7 @@ static void get_func_expr(Expr *expr, deparse_context *context);
104105
static void get_tle_expr(TargetEntry *tle, deparse_context *context);
105106
static void get_const_expr(Const *constval, deparse_context *context);
106107
static void get_sublink_expr(Node *node, deparse_context *context);
108+
static char *quote_identifier(char *ident);
107109
static char *get_relation_name(Oid relid);
108110
static char *get_attribute_name(Oid relid, int2 attnum);
109111
static bool check_if_rte_used(Node *node, Index rt_index, int levelsup);
@@ -404,9 +406,11 @@ pg_get_indexdef(Oid indexrelid)
404406
spi_nulls[1] = '\0';
405407
spirc = SPI_execp(plan_getam, spi_args, spi_nulls, 1);
406408
if (spirc != SPI_OK_SELECT)
407-
elog(ERROR, "failed to get pg_am tuple for index %s", nameout(&(idxrelrec->relname)));
409+
elog(ERROR, "failed to get pg_am tuple for index %s",
410+
nameout(&(idxrelrec->relname)));
408411
if (SPI_processed != 1)
409-
elog(ERROR, "failed to get pg_am tuple for index %s", nameout(&(idxrelrec->relname)));
412+
elog(ERROR, "failed to get pg_am tuple for index %s",
413+
nameout(&(idxrelrec->relname)));
410414
spi_tup = SPI_tuptable->vals[0];
411415
spi_ttc = SPI_tuptable->tupdesc;
412416
spi_fno = SPI_fnumber(spi_ttc, "amname");
@@ -416,11 +420,12 @@ pg_get_indexdef(Oid indexrelid)
416420
* ----------
417421
*/
418422
initStringInfo(&buf);
419-
appendStringInfo(&buf, "CREATE %sINDEX \"%s\" ON \"%s\" USING %s (",
423+
appendStringInfo(&buf, "CREATE %sINDEX %s ON %s USING %s (",
420424
idxrec->indisunique ? "UNIQUE " : "",
421-
nameout(&(idxrelrec->relname)),
422-
nameout(&(indrelrec->relname)),
423-
SPI_getvalue(spi_tup, spi_ttc, spi_fno));
425+
quote_identifier(nameout(&(idxrelrec->relname))),
426+
quote_identifier(nameout(&(indrelrec->relname))),
427+
quote_identifier(SPI_getvalue(spi_tup, spi_ttc,
428+
spi_fno)));
424429

425430
/* ----------
426431
* Collect the indexed attributes
@@ -440,12 +445,9 @@ pg_get_indexdef(Oid indexrelid)
440445
* Add the indexed field name
441446
* ----------
442447
*/
443-
if (idxrec->indkey[keyno] == ObjectIdAttributeNumber - 1)
444-
appendStringInfo(&keybuf, "\"oid\"");
445-
else
446-
appendStringInfo(&keybuf, "\"%s\"",
447-
get_attribute_name(idxrec->indrelid,
448-
idxrec->indkey[keyno]));
448+
appendStringInfo(&keybuf, "%s",
449+
quote_identifier(get_attribute_name(idxrec->indrelid,
450+
idxrec->indkey[keyno])));
449451

450452
/* ----------
451453
* If not a functional index, add the operator class name
@@ -464,8 +466,9 @@ pg_get_indexdef(Oid indexrelid)
464466
spi_tup = SPI_tuptable->vals[0];
465467
spi_ttc = SPI_tuptable->tupdesc;
466468
spi_fno = SPI_fnumber(spi_ttc, "opcname");
467-
appendStringInfo(&keybuf, " \"%s\"",
468-
SPI_getvalue(spi_tup, spi_ttc, spi_fno));
469+
appendStringInfo(&keybuf, " %s",
470+
quote_identifier(SPI_getvalue(spi_tup, spi_ttc,
471+
spi_fno)));
469472
}
470473
}
471474

@@ -484,8 +487,8 @@ pg_get_indexdef(Oid indexrelid)
484487
elog(ERROR, "cache lookup for proc %u failed", idxrec->indproc);
485488

486489
procStruct = (Form_pg_proc) GETSTRUCT(proctup);
487-
appendStringInfo(&buf, "\"%s\" (%s) ",
488-
nameout(&(procStruct->proname)),
490+
appendStringInfo(&buf, "%s(%s) ",
491+
quote_identifier(nameout(&(procStruct->proname))),
489492
keybuf.data);
490493

491494
spi_args[0] = ObjectIdGetDatum(idxrec->indclass[0]);
@@ -499,8 +502,9 @@ pg_get_indexdef(Oid indexrelid)
499502
spi_tup = SPI_tuptable->vals[0];
500503
spi_ttc = SPI_tuptable->tupdesc;
501504
spi_fno = SPI_fnumber(spi_ttc, "opcname");
502-
appendStringInfo(&buf, "\"%s\"",
503-
SPI_getvalue(spi_tup, spi_ttc, spi_fno));
505+
appendStringInfo(&buf, "%s",
506+
quote_identifier(SPI_getvalue(spi_tup, spi_ttc,
507+
spi_fno)));
504508
}
505509
else
506510
/* ----------
@@ -658,7 +662,8 @@ make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc)
658662
* Build the rules definition text
659663
* ----------
660664
*/
661-
appendStringInfo(buf, "CREATE RULE \"%s\" AS ON ", rulename);
665+
appendStringInfo(buf, "CREATE RULE %s AS ON ",
666+
quote_identifier(rulename));
662667

663668
/* The event the rule is fired for */
664669
switch (ev_type)
@@ -686,10 +691,12 @@ make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc)
686691
}
687692

688693
/* The relation the rule is fired on */
689-
appendStringInfo(buf, " TO \"%s\"", get_relation_name(ev_class));
694+
appendStringInfo(buf, " TO %s",
695+
quote_identifier(get_relation_name(ev_class)));
690696
if (ev_attr > 0)
691-
appendStringInfo(buf, ".\"%s\"",
692-
get_attribute_name(ev_class, ev_attr));
697+
appendStringInfo(buf, ".%s",
698+
quote_identifier(get_attribute_name(ev_class,
699+
ev_attr)));
693700

694701
/* If the rule has an event qualification, add it */
695702
if (ev_qual == NULL)
@@ -954,7 +961,8 @@ get_select_query_def(Query *query, deparse_context *context)
954961

955962
/* and do if so */
956963
if (tell_as)
957-
appendStringInfo(buf, " AS \"%s\"", tle->resdom->resname);
964+
appendStringInfo(buf, " AS %s",
965+
quote_identifier(tle->resdom->resname));
958966
}
959967

960968
/* If we need other tables that *NEW* or *CURRENT* add the FROM clause */
@@ -978,9 +986,11 @@ get_select_query_def(Query *query, deparse_context *context)
978986

979987
appendStringInfo(buf, sep);
980988
sep = ", ";
981-
appendStringInfo(buf, "\"%s\"", rte->relname);
989+
appendStringInfo(buf, "%s",
990+
quote_identifier(rte->relname));
982991
if (strcmp(rte->relname, rte->refname) != 0)
983-
appendStringInfo(buf, " \"%s\"", rte->refname);
992+
appendStringInfo(buf, " %s",
993+
quote_identifier(rte->refname));
984994
}
985995
}
986996
}
@@ -1072,7 +1082,8 @@ get_insert_query_def(Query *query, deparse_context *context)
10721082
* ----------
10731083
*/
10741084
rte = (RangeTblEntry *) nth(query->resultRelation - 1, query->rtable);
1075-
appendStringInfo(buf, "INSERT INTO \"%s\"", rte->relname);
1085+
appendStringInfo(buf, "INSERT INTO %s",
1086+
quote_identifier(rte->relname));
10761087

10771088
/* Add the target list */
10781089
sep = " (";
@@ -1082,7 +1093,7 @@ get_insert_query_def(Query *query, deparse_context *context)
10821093

10831094
appendStringInfo(buf, sep);
10841095
sep = ", ";
1085-
appendStringInfo(buf, "\"%s\"", tle->resdom->resname);
1096+
appendStringInfo(buf, "%s", quote_identifier(tle->resdom->resname));
10861097
}
10871098
appendStringInfo(buf, ") ");
10881099

@@ -1124,7 +1135,8 @@ get_update_query_def(Query *query, deparse_context *context)
11241135
* ----------
11251136
*/
11261137
rte = (RangeTblEntry *) nth(query->resultRelation - 1, query->rtable);
1127-
appendStringInfo(buf, "UPDATE \"%s\" SET ", rte->relname);
1138+
appendStringInfo(buf, "UPDATE %s SET ",
1139+
quote_identifier(rte->relname));
11281140

11291141
/* Add the comma separated list of 'attname = value' */
11301142
sep = "";
@@ -1134,7 +1146,8 @@ get_update_query_def(Query *query, deparse_context *context)
11341146

11351147
appendStringInfo(buf, sep);
11361148
sep = ", ";
1137-
appendStringInfo(buf, "\"%s\" = ", tle->resdom->resname);
1149+
appendStringInfo(buf, "%s = ",
1150+
quote_identifier(tle->resdom->resname));
11381151
get_tle_expr(tle, context);
11391152
}
11401153

@@ -1162,7 +1175,8 @@ get_delete_query_def(Query *query, deparse_context *context)
11621175
* ----------
11631176
*/
11641177
rte = (RangeTblEntry *) nth(query->resultRelation - 1, query->rtable);
1165-
appendStringInfo(buf, "DELETE FROM \"%s\"", rte->relname);
1178+
appendStringInfo(buf, "DELETE FROM %s",
1179+
quote_identifier(rte->relname));
11661180

11671181
/* Add a WHERE clause if given */
11681182
if (query->qual != NULL)
@@ -1227,11 +1241,12 @@ get_rule_expr(Node *node, deparse_context *context)
12271241
else if (!strcmp(rte->refname, "*CURRENT*"))
12281242
appendStringInfo(buf, "old.");
12291243
else
1230-
appendStringInfo(buf, "\"%s\".", rte->refname);
1244+
appendStringInfo(buf, "%s.",
1245+
quote_identifier(rte->refname));
12311246
}
1232-
appendStringInfo(buf, "\"%s\"",
1233-
get_attribute_name(rte->relid,
1234-
var->varattno));
1247+
appendStringInfo(buf, "%s",
1248+
quote_identifier(get_attribute_name(rte->relid,
1249+
var->varattno)));
12351250
}
12361251
break;
12371252

@@ -1332,7 +1347,8 @@ get_rule_expr(Node *node, deparse_context *context)
13321347
{
13331348
Aggref *aggref = (Aggref *) node;
13341349

1335-
appendStringInfo(buf, "\"%s\"(", aggref->aggname);
1350+
appendStringInfo(buf, "%s(",
1351+
quote_identifier(aggref->aggname));
13361352
get_rule_expr(aggref->target, context);
13371353
appendStringInfo(buf, ")");
13381354
}
@@ -1453,7 +1469,7 @@ get_func_expr(Expr *expr, deparse_context *context)
14531469
* Build a string of proname(args)
14541470
* ----------
14551471
*/
1456-
appendStringInfo(buf, "\"%s\"(", proname);
1472+
appendStringInfo(buf, "%s(", quote_identifier(proname));
14571473
sep = "";
14581474
foreach(l, expr->args)
14591475
{
@@ -1566,7 +1582,7 @@ get_tle_expr(TargetEntry *tle, deparse_context *context)
15661582
/* ----------
15671583
* get_const_expr
15681584
*
1569-
* Make a string representation with the type cast out of a Const
1585+
* Make a string representation of a Const
15701586
* ----------
15711587
*/
15721588
static void
@@ -1598,34 +1614,55 @@ get_const_expr(Const *constval, deparse_context *context)
15981614
extval = (char *) (*fmgr_faddr(&finfo_output)) (constval->constvalue,
15991615
&isnull, -1);
16001616

1601-
/*
1602-
* We must quote any funny characters in the constant's representation.
1603-
* XXX Any MULTIBYTE considerations here?
1604-
*/
1605-
appendStringInfoChar(buf, '\'');
1606-
for (valptr = extval; *valptr; valptr++)
1617+
switch (constval->consttype)
16071618
{
1608-
char ch = *valptr;
1609-
if (ch == '\'' || ch == '\\')
1610-
{
1611-
appendStringInfoChar(buf, '\\');
1612-
appendStringInfoChar(buf, ch);
1613-
}
1614-
else if (ch >= 0 && ch < ' ')
1615-
{
1616-
appendStringInfo(buf, "\\%03o", ch);
1617-
}
1618-
else
1619-
appendStringInfoChar(buf, ch);
1619+
case INT2OID:
1620+
case INT4OID:
1621+
case OIDOID: /* int types */
1622+
case FLOAT4OID:
1623+
case FLOAT8OID: /* float types */
1624+
/* These types are printed without quotes */
1625+
appendStringInfo(buf, extval);
1626+
break;
1627+
default:
1628+
/*
1629+
* We must quote any funny characters in the constant's
1630+
* representation.
1631+
* XXX Any MULTIBYTE considerations here?
1632+
*/
1633+
appendStringInfoChar(buf, '\'');
1634+
for (valptr = extval; *valptr; valptr++)
1635+
{
1636+
char ch = *valptr;
1637+
if (ch == '\'' || ch == '\\')
1638+
{
1639+
appendStringInfoChar(buf, '\\');
1640+
appendStringInfoChar(buf, ch);
1641+
}
1642+
else if (ch >= 0 && ch < ' ')
1643+
appendStringInfo(buf, "\\%03o", (int) ch);
1644+
else
1645+
appendStringInfoChar(buf, ch);
1646+
}
1647+
appendStringInfoChar(buf, '\'');
1648+
break;
16201649
}
1621-
appendStringInfoChar(buf, '\'');
1622-
pfree(extval);
16231650

1624-
extval = (char *) nameout(&(typeStruct->typname));
1625-
/* probably would be better to recognize UNKNOWN by OID... */
1626-
if (strcmp(extval, "unknown") != 0)
1627-
appendStringInfo(buf, "::\"%s\"", extval);
16281651
pfree(extval);
1652+
1653+
switch (constval->consttype)
1654+
{
1655+
case INT4OID:
1656+
case FLOAT8OID:
1657+
case UNKNOWNOID:
1658+
/* These types can be left unlabeled */
1659+
break;
1660+
default:
1661+
extval = (char *) nameout(&(typeStruct->typname));
1662+
appendStringInfo(buf, "::%s", quote_identifier(extval));
1663+
pfree(extval);
1664+
break;
1665+
}
16291666
}
16301667

16311668

@@ -1696,6 +1733,52 @@ get_sublink_expr(Node *node, deparse_context *context)
16961733
appendStringInfo(buf, "))");
16971734
}
16981735

1736+
/* ----------
1737+
* quote_identifier - Quote an identifier only if needed
1738+
*
1739+
* When quotes are needed, we palloc the required space; slightly
1740+
* space-wasteful but well worth it for notational simplicity.
1741+
* ----------
1742+
*/
1743+
static char *
1744+
quote_identifier(char *ident)
1745+
{
1746+
/*
1747+
* Can avoid quoting if ident starts with a lowercase letter and
1748+
* contains only lowercase letters, digits, and underscores.
1749+
* Otherwise, supply quotes.
1750+
*/
1751+
bool safe;
1752+
char *result;
1753+
1754+
/*
1755+
* would like to use <ctype.h> macros here, but they might yield
1756+
* unwanted locale-specific results...
1757+
*/
1758+
safe = (ident[0] >= 'a' && ident[0] <= 'z');
1759+
if (safe)
1760+
{
1761+
char *ptr;
1762+
1763+
for (ptr = ident+1; *ptr; ptr++)
1764+
{
1765+
char ch = *ptr;
1766+
1767+
safe = ((ch >= 'a' && ch <= 'z') ||
1768+
(ch >= '0' && ch <= '9') ||
1769+
(ch == '_'));
1770+
if (! safe)
1771+
break;
1772+
}
1773+
}
1774+
1775+
if (safe)
1776+
return ident; /* no change needed */
1777+
1778+
result = (char *) palloc(strlen(ident) + 2 + 1);
1779+
sprintf(result, "\"%s\"", ident);
1780+
return result;
1781+
}
16991782

17001783
/* ----------
17011784
* get_relation_name - Get a relation name by Oid
@@ -1729,7 +1812,8 @@ get_attribute_name(Oid relid, int2 attnum)
17291812
Form_pg_attribute attStruct;
17301813

17311814
atttup = SearchSysCacheTuple(ATTNUM,
1732-
ObjectIdGetDatum(relid), (Datum) attnum, 0, 0);
1815+
ObjectIdGetDatum(relid), (Datum) attnum,
1816+
0, 0);
17331817
if (!HeapTupleIsValid(atttup))
17341818
elog(ERROR, "cache lookup of attribute %d in relation %u failed",
17351819
attnum, relid);

0 commit comments

Comments
 (0)