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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy