3
3
* out of it's tuple
4
4
*
5
5
* 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 $
7
7
*
8
8
* This software is copyrighted by Jan Wieck - Hamburg.
9
9
*
47
47
#include "catalog/pg_index.h"
48
48
#include "catalog/pg_operator.h"
49
49
#include "catalog/pg_shadow.h"
50
+ #include "catalog/pg_type.h"
50
51
#include "utils/builtins.h"
51
52
#include "utils/lsyscache.h"
52
53
@@ -104,6 +105,7 @@ static void get_func_expr(Expr *expr, deparse_context *context);
104
105
static void get_tle_expr (TargetEntry * tle , deparse_context * context );
105
106
static void get_const_expr (Const * constval , deparse_context * context );
106
107
static void get_sublink_expr (Node * node , deparse_context * context );
108
+ static char * quote_identifier (char * ident );
107
109
static char * get_relation_name (Oid relid );
108
110
static char * get_attribute_name (Oid relid , int2 attnum );
109
111
static bool check_if_rte_used (Node * node , Index rt_index , int levelsup );
@@ -404,9 +406,11 @@ pg_get_indexdef(Oid indexrelid)
404
406
spi_nulls [1 ] = '\0' ;
405
407
spirc = SPI_execp (plan_getam , spi_args , spi_nulls , 1 );
406
408
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 )));
408
411
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 )));
410
414
spi_tup = SPI_tuptable -> vals [0 ];
411
415
spi_ttc = SPI_tuptable -> tupdesc ;
412
416
spi_fno = SPI_fnumber (spi_ttc , "amname" );
@@ -416,11 +420,12 @@ pg_get_indexdef(Oid indexrelid)
416
420
* ----------
417
421
*/
418
422
initStringInfo (& buf );
419
- appendStringInfo (& buf , "CREATE %sINDEX \"%s\" ON \"%s\" USING %s (" ,
423
+ appendStringInfo (& buf , "CREATE %sINDEX %s ON %s USING %s (" ,
420
424
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 )));
424
429
425
430
/* ----------
426
431
* Collect the indexed attributes
@@ -440,12 +445,9 @@ pg_get_indexdef(Oid indexrelid)
440
445
* Add the indexed field name
441
446
* ----------
442
447
*/
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 ])));
449
451
450
452
/* ----------
451
453
* If not a functional index, add the operator class name
@@ -464,8 +466,9 @@ pg_get_indexdef(Oid indexrelid)
464
466
spi_tup = SPI_tuptable -> vals [0 ];
465
467
spi_ttc = SPI_tuptable -> tupdesc ;
466
468
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 )));
469
472
}
470
473
}
471
474
@@ -484,8 +487,8 @@ pg_get_indexdef(Oid indexrelid)
484
487
elog (ERROR , "cache lookup for proc %u failed" , idxrec -> indproc );
485
488
486
489
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 ) )),
489
492
keybuf .data );
490
493
491
494
spi_args [0 ] = ObjectIdGetDatum (idxrec -> indclass [0 ]);
@@ -499,8 +502,9 @@ pg_get_indexdef(Oid indexrelid)
499
502
spi_tup = SPI_tuptable -> vals [0 ];
500
503
spi_ttc = SPI_tuptable -> tupdesc ;
501
504
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 )));
504
508
}
505
509
else
506
510
/* ----------
@@ -658,7 +662,8 @@ make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc)
658
662
* Build the rules definition text
659
663
* ----------
660
664
*/
661
- appendStringInfo (buf , "CREATE RULE \"%s\" AS ON " , rulename );
665
+ appendStringInfo (buf , "CREATE RULE %s AS ON " ,
666
+ quote_identifier (rulename ));
662
667
663
668
/* The event the rule is fired for */
664
669
switch (ev_type )
@@ -686,10 +691,12 @@ make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc)
686
691
}
687
692
688
693
/* 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 )));
690
696
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 )));
693
700
694
701
/* If the rule has an event qualification, add it */
695
702
if (ev_qual == NULL )
@@ -954,7 +961,8 @@ get_select_query_def(Query *query, deparse_context *context)
954
961
955
962
/* and do if so */
956
963
if (tell_as )
957
- appendStringInfo (buf , " AS \"%s\"" , tle -> resdom -> resname );
964
+ appendStringInfo (buf , " AS %s" ,
965
+ quote_identifier (tle -> resdom -> resname ));
958
966
}
959
967
960
968
/* 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)
978
986
979
987
appendStringInfo (buf , sep );
980
988
sep = ", " ;
981
- appendStringInfo (buf , "\"%s\"" , rte -> relname );
989
+ appendStringInfo (buf , "%s" ,
990
+ quote_identifier (rte -> relname ));
982
991
if (strcmp (rte -> relname , rte -> refname ) != 0 )
983
- appendStringInfo (buf , " \"%s\"" , rte -> refname );
992
+ appendStringInfo (buf , " %s" ,
993
+ quote_identifier (rte -> refname ));
984
994
}
985
995
}
986
996
}
@@ -1072,7 +1082,8 @@ get_insert_query_def(Query *query, deparse_context *context)
1072
1082
* ----------
1073
1083
*/
1074
1084
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 ));
1076
1087
1077
1088
/* Add the target list */
1078
1089
sep = " (" ;
@@ -1082,7 +1093,7 @@ get_insert_query_def(Query *query, deparse_context *context)
1082
1093
1083
1094
appendStringInfo (buf , sep );
1084
1095
sep = ", " ;
1085
- appendStringInfo (buf , "\"%s\"" , tle -> resdom -> resname );
1096
+ appendStringInfo (buf , "%s" , quote_identifier ( tle -> resdom -> resname ) );
1086
1097
}
1087
1098
appendStringInfo (buf , ") " );
1088
1099
@@ -1124,7 +1135,8 @@ get_update_query_def(Query *query, deparse_context *context)
1124
1135
* ----------
1125
1136
*/
1126
1137
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 ));
1128
1140
1129
1141
/* Add the comma separated list of 'attname = value' */
1130
1142
sep = "" ;
@@ -1134,7 +1146,8 @@ get_update_query_def(Query *query, deparse_context *context)
1134
1146
1135
1147
appendStringInfo (buf , sep );
1136
1148
sep = ", " ;
1137
- appendStringInfo (buf , "\"%s\" = " , tle -> resdom -> resname );
1149
+ appendStringInfo (buf , "%s = " ,
1150
+ quote_identifier (tle -> resdom -> resname ));
1138
1151
get_tle_expr (tle , context );
1139
1152
}
1140
1153
@@ -1162,7 +1175,8 @@ get_delete_query_def(Query *query, deparse_context *context)
1162
1175
* ----------
1163
1176
*/
1164
1177
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 ));
1166
1180
1167
1181
/* Add a WHERE clause if given */
1168
1182
if (query -> qual != NULL )
@@ -1227,11 +1241,12 @@ get_rule_expr(Node *node, deparse_context *context)
1227
1241
else if (!strcmp (rte -> refname , "*CURRENT*" ))
1228
1242
appendStringInfo (buf , "old." );
1229
1243
else
1230
- appendStringInfo (buf , "\"%s\"." , rte -> refname );
1244
+ appendStringInfo (buf , "%s." ,
1245
+ quote_identifier (rte -> refname ));
1231
1246
}
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 ) ));
1235
1250
}
1236
1251
break ;
1237
1252
@@ -1332,7 +1347,8 @@ get_rule_expr(Node *node, deparse_context *context)
1332
1347
{
1333
1348
Aggref * aggref = (Aggref * ) node ;
1334
1349
1335
- appendStringInfo (buf , "\"%s\"(" , aggref -> aggname );
1350
+ appendStringInfo (buf , "%s(" ,
1351
+ quote_identifier (aggref -> aggname ));
1336
1352
get_rule_expr (aggref -> target , context );
1337
1353
appendStringInfo (buf , ")" );
1338
1354
}
@@ -1453,7 +1469,7 @@ get_func_expr(Expr *expr, deparse_context *context)
1453
1469
* Build a string of proname(args)
1454
1470
* ----------
1455
1471
*/
1456
- appendStringInfo (buf , "\"%s\" (" , proname );
1472
+ appendStringInfo (buf , "%s (" , quote_identifier ( proname ) );
1457
1473
sep = "" ;
1458
1474
foreach (l , expr -> args )
1459
1475
{
@@ -1566,7 +1582,7 @@ get_tle_expr(TargetEntry *tle, deparse_context *context)
1566
1582
/* ----------
1567
1583
* get_const_expr
1568
1584
*
1569
- * Make a string representation with the type cast out of a Const
1585
+ * Make a string representation of a Const
1570
1586
* ----------
1571
1587
*/
1572
1588
static void
@@ -1598,34 +1614,55 @@ get_const_expr(Const *constval, deparse_context *context)
1598
1614
extval = (char * ) (* fmgr_faddr (& finfo_output )) (constval -> constvalue ,
1599
1615
& isnull , -1 );
1600
1616
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 )
1607
1618
{
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 ;
1620
1649
}
1621
- appendStringInfoChar (buf , '\'' );
1622
- pfree (extval );
1623
1650
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 );
1628
1651
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
+ }
1629
1666
}
1630
1667
1631
1668
@@ -1696,6 +1733,52 @@ get_sublink_expr(Node *node, deparse_context *context)
1696
1733
appendStringInfo (buf , "))" );
1697
1734
}
1698
1735
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
+ }
1699
1782
1700
1783
/* ----------
1701
1784
* get_relation_name - Get a relation name by Oid
@@ -1729,7 +1812,8 @@ get_attribute_name(Oid relid, int2 attnum)
1729
1812
Form_pg_attribute attStruct ;
1730
1813
1731
1814
atttup = SearchSysCacheTuple (ATTNUM ,
1732
- ObjectIdGetDatum (relid ), (Datum ) attnum , 0 , 0 );
1815
+ ObjectIdGetDatum (relid ), (Datum ) attnum ,
1816
+ 0 , 0 );
1733
1817
if (!HeapTupleIsValid (atttup ))
1734
1818
elog (ERROR , "cache lookup of attribute %d in relation %u failed" ,
1735
1819
attnum , relid );
0 commit comments