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 *
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);
104105static void get_tle_expr (TargetEntry * tle ,deparse_context * context );
105106static void get_const_expr (Const * constval ,deparse_context * context );
106107static void get_sublink_expr (Node * node ,deparse_context * context );
108+ static char * quote_identifier (char * ident );
107109static char * get_relation_name (Oid relid );
108110static char * get_attribute_name (Oid relid ,int2 attnum );
109111static bool check_if_rte_used (Node * node ,Index rt_index ,int levelsup );
@@ -404,9 +406,11 @@ pg_get_indexdef(Oid indexrelid)
404406spi_nulls [1 ]= '\0' ;
405407spirc = SPI_execp (plan_getam ,spi_args ,spi_nulls ,1 );
406408if (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 )));
408411if (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 )));
410414spi_tup = SPI_tuptable -> vals [0 ];
411415spi_ttc = SPI_tuptable -> tupdesc ;
412416spi_fno = SPI_fnumber (spi_ttc ,"amname" );
@@ -416,11 +420,12 @@ pg_get_indexdef(Oid indexrelid)
416420 * ----------
417421 */
418422initStringInfo (& buf );
419- appendStringInfo (& buf ,"CREATE %sINDEX\"%s\" ON\"%s\" USING %s (" ,
423+ appendStringInfo (& buf ,"CREATE %sINDEX%s ON%s USING %s (" ,
420424idxrec -> 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)
464466spi_tup = SPI_tuptable -> vals [0 ];
465467spi_ttc = SPI_tuptable -> tupdesc ;
466468spi_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)
484487elog (ERROR ,"cache lookup for proc %u failed" ,idxrec -> indproc );
485488
486489procStruct = (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 ) )),
489492keybuf .data );
490493
491494spi_args [0 ]= ObjectIdGetDatum (idxrec -> indclass [0 ]);
@@ -499,8 +502,9 @@ pg_get_indexdef(Oid indexrelid)
499502spi_tup = SPI_tuptable -> vals [0 ];
500503spi_ttc = SPI_tuptable -> tupdesc ;
501504spi_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}
505509else
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 */
664669switch (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 )));
690696if (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 */
695702if (ev_qual == NULL )
@@ -954,7 +961,8 @@ get_select_query_def(Query *query, deparse_context *context)
954961
955962/* and do if so */
956963if (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
979987appendStringInfo (buf ,sep );
980988sep = ", " ;
981- appendStringInfo (buf ,"\"%s\"" ,rte -> relname );
989+ appendStringInfo (buf ,"%s" ,
990+ quote_identifier (rte -> relname ));
982991if (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 */
10741084rte = (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 */
10781089sep = " (" ;
@@ -1082,7 +1093,7 @@ get_insert_query_def(Query *query, deparse_context *context)
10821093
10831094appendStringInfo (buf ,sep );
10841095sep = ", " ;
1085- appendStringInfo (buf ,"\"%s\"" , tle -> resdom -> resname );
1096+ appendStringInfo (buf ,"%s" , quote_identifier ( tle -> resdom -> resname ) );
10861097}
10871098appendStringInfo (buf ,") " );
10881099
@@ -1124,7 +1135,8 @@ get_update_query_def(Query *query, deparse_context *context)
11241135 * ----------
11251136 */
11261137rte = (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' */
11301142sep = "" ;
@@ -1134,7 +1146,8 @@ get_update_query_def(Query *query, deparse_context *context)
11341146
11351147appendStringInfo (buf ,sep );
11361148sep = ", " ;
1137- appendStringInfo (buf ,"\"%s\" = " ,tle -> resdom -> resname );
1149+ appendStringInfo (buf ,"%s = " ,
1150+ quote_identifier (tle -> resdom -> resname ));
11381151get_tle_expr (tle ,context );
11391152}
11401153
@@ -1162,7 +1175,8 @@ get_delete_query_def(Query *query, deparse_context *context)
11621175 * ----------
11631176 */
11641177rte = (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 */
11681182if (query -> qual != NULL )
@@ -1227,11 +1241,12 @@ get_rule_expr(Node *node, deparse_context *context)
12271241else if (!strcmp (rte -> refname ,"*CURRENT*" ))
12281242appendStringInfo (buf ,"old." );
12291243else
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}
12361251break ;
12371252
@@ -1332,7 +1347,8 @@ get_rule_expr(Node *node, deparse_context *context)
13321347{
13331348Aggref * aggref = (Aggref * )node ;
13341349
1335- appendStringInfo (buf ,"\"%s\"(" ,aggref -> aggname );
1350+ appendStringInfo (buf ,"%s(" ,
1351+ quote_identifier (aggref -> aggname ));
13361352get_rule_expr (aggref -> target ,context );
13371353appendStringInfo (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 ) );
14571473sep = "" ;
14581474foreach (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 representationwith the type cast out of a Const
1585+ *Make a string representation of a Const
15701586 * ----------
15711587 */
15721588static void
@@ -1598,34 +1614,55 @@ get_const_expr(Const *constval, deparse_context *context)
15981614extval = (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 );
16281651pfree (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)
16961733appendStringInfo (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)
17291812Form_pg_attribute attStruct ;
17301813
17311814atttup = SearchSysCacheTuple (ATTNUM ,
1732- ObjectIdGetDatum (relid ), (Datum )attnum ,0 ,0 );
1815+ ObjectIdGetDatum (relid ), (Datum )attnum ,
1816+ 0 ,0 );
17331817if (!HeapTupleIsValid (atttup ))
17341818elog (ERROR ,"cache lookup of attribute %d in relation %u failed" ,
17351819attnum ,relid );