From 3e21ecbbe6b3a9eb4b1f8373b006d21b9634be65 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Mon, 4 Oct 1999 04:37:23 +0000 Subject: [PATCH] Make the rule deparser a little less quote-happy, so that display of default expressions isn't quite so ugly. --- src/backend/utils/adt/ruleutils.c | 210 ++++++++++++++++++++++++++------------ 1 file changed, 147 insertions(+), 63 deletions(-) diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c index bcaa0f0d68..445da996d1 100644 --- a/src/backend/utils/adt/ruleutils.c +++ b/src/backend/utils/adt/ruleutils.c @@ -3,7 +3,7 @@ * out of it's tuple * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.27 1999/10/03 23:55:31 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.28 1999/10/04 04:37:23 tgl Exp $ * * This software is copyrighted by Jan Wieck - Hamburg. * @@ -47,6 +47,7 @@ #include "catalog/pg_index.h" #include "catalog/pg_operator.h" #include "catalog/pg_shadow.h" +#include "catalog/pg_type.h" #include "utils/builtins.h" #include "utils/lsyscache.h" @@ -104,6 +105,7 @@ static void get_func_expr(Expr *expr, deparse_context *context); static void get_tle_expr(TargetEntry *tle, deparse_context *context); static void get_const_expr(Const *constval, deparse_context *context); static void get_sublink_expr(Node *node, deparse_context *context); +static char *quote_identifier(char *ident); static char *get_relation_name(Oid relid); static char *get_attribute_name(Oid relid, int2 attnum); static bool check_if_rte_used(Node *node, Index rt_index, int levelsup); @@ -404,9 +406,11 @@ pg_get_indexdef(Oid indexrelid) spi_nulls[1] = '\0'; spirc = SPI_execp(plan_getam, spi_args, spi_nulls, 1); if (spirc != SPI_OK_SELECT) - elog(ERROR, "failed to get pg_am tuple for index %s", nameout(&(idxrelrec->relname))); + elog(ERROR, "failed to get pg_am tuple for index %s", + nameout(&(idxrelrec->relname))); if (SPI_processed != 1) - elog(ERROR, "failed to get pg_am tuple for index %s", nameout(&(idxrelrec->relname))); + elog(ERROR, "failed to get pg_am tuple for index %s", + nameout(&(idxrelrec->relname))); spi_tup = SPI_tuptable->vals[0]; spi_ttc = SPI_tuptable->tupdesc; spi_fno = SPI_fnumber(spi_ttc, "amname"); @@ -416,11 +420,12 @@ pg_get_indexdef(Oid indexrelid) * ---------- */ initStringInfo(&buf); - appendStringInfo(&buf, "CREATE %sINDEX \"%s\" ON \"%s\" USING %s (", + appendStringInfo(&buf, "CREATE %sINDEX %s ON %s USING %s (", idxrec->indisunique ? "UNIQUE " : "", - nameout(&(idxrelrec->relname)), - nameout(&(indrelrec->relname)), - SPI_getvalue(spi_tup, spi_ttc, spi_fno)); + quote_identifier(nameout(&(idxrelrec->relname))), + quote_identifier(nameout(&(indrelrec->relname))), + quote_identifier(SPI_getvalue(spi_tup, spi_ttc, + spi_fno))); /* ---------- * Collect the indexed attributes @@ -440,12 +445,9 @@ pg_get_indexdef(Oid indexrelid) * Add the indexed field name * ---------- */ - if (idxrec->indkey[keyno] == ObjectIdAttributeNumber - 1) - appendStringInfo(&keybuf, "\"oid\""); - else - appendStringInfo(&keybuf, "\"%s\"", - get_attribute_name(idxrec->indrelid, - idxrec->indkey[keyno])); + appendStringInfo(&keybuf, "%s", + quote_identifier(get_attribute_name(idxrec->indrelid, + idxrec->indkey[keyno]))); /* ---------- * If not a functional index, add the operator class name @@ -464,8 +466,9 @@ pg_get_indexdef(Oid indexrelid) spi_tup = SPI_tuptable->vals[0]; spi_ttc = SPI_tuptable->tupdesc; spi_fno = SPI_fnumber(spi_ttc, "opcname"); - appendStringInfo(&keybuf, " \"%s\"", - SPI_getvalue(spi_tup, spi_ttc, spi_fno)); + appendStringInfo(&keybuf, " %s", + quote_identifier(SPI_getvalue(spi_tup, spi_ttc, + spi_fno))); } } @@ -484,8 +487,8 @@ pg_get_indexdef(Oid indexrelid) elog(ERROR, "cache lookup for proc %u failed", idxrec->indproc); procStruct = (Form_pg_proc) GETSTRUCT(proctup); - appendStringInfo(&buf, "\"%s\" (%s) ", - nameout(&(procStruct->proname)), + appendStringInfo(&buf, "%s(%s) ", + quote_identifier(nameout(&(procStruct->proname))), keybuf.data); spi_args[0] = ObjectIdGetDatum(idxrec->indclass[0]); @@ -499,8 +502,9 @@ pg_get_indexdef(Oid indexrelid) spi_tup = SPI_tuptable->vals[0]; spi_ttc = SPI_tuptable->tupdesc; spi_fno = SPI_fnumber(spi_ttc, "opcname"); - appendStringInfo(&buf, "\"%s\"", - SPI_getvalue(spi_tup, spi_ttc, spi_fno)); + appendStringInfo(&buf, "%s", + quote_identifier(SPI_getvalue(spi_tup, spi_ttc, + spi_fno))); } else /* ---------- @@ -658,7 +662,8 @@ make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc) * Build the rules definition text * ---------- */ - appendStringInfo(buf, "CREATE RULE \"%s\" AS ON ", rulename); + appendStringInfo(buf, "CREATE RULE %s AS ON ", + quote_identifier(rulename)); /* The event the rule is fired for */ switch (ev_type) @@ -686,10 +691,12 @@ make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc) } /* The relation the rule is fired on */ - appendStringInfo(buf, " TO \"%s\"", get_relation_name(ev_class)); + appendStringInfo(buf, " TO %s", + quote_identifier(get_relation_name(ev_class))); if (ev_attr > 0) - appendStringInfo(buf, ".\"%s\"", - get_attribute_name(ev_class, ev_attr)); + appendStringInfo(buf, ".%s", + quote_identifier(get_attribute_name(ev_class, + ev_attr))); /* If the rule has an event qualification, add it */ if (ev_qual == NULL) @@ -954,7 +961,8 @@ get_select_query_def(Query *query, deparse_context *context) /* and do if so */ if (tell_as) - appendStringInfo(buf, " AS \"%s\"", tle->resdom->resname); + appendStringInfo(buf, " AS %s", + quote_identifier(tle->resdom->resname)); } /* 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) appendStringInfo(buf, sep); sep = ", "; - appendStringInfo(buf, "\"%s\"", rte->relname); + appendStringInfo(buf, "%s", + quote_identifier(rte->relname)); if (strcmp(rte->relname, rte->refname) != 0) - appendStringInfo(buf, " \"%s\"", rte->refname); + appendStringInfo(buf, " %s", + quote_identifier(rte->refname)); } } } @@ -1072,7 +1082,8 @@ get_insert_query_def(Query *query, deparse_context *context) * ---------- */ rte = (RangeTblEntry *) nth(query->resultRelation - 1, query->rtable); - appendStringInfo(buf, "INSERT INTO \"%s\"", rte->relname); + appendStringInfo(buf, "INSERT INTO %s", + quote_identifier(rte->relname)); /* Add the target list */ sep = " ("; @@ -1082,7 +1093,7 @@ get_insert_query_def(Query *query, deparse_context *context) appendStringInfo(buf, sep); sep = ", "; - appendStringInfo(buf, "\"%s\"", tle->resdom->resname); + appendStringInfo(buf, "%s", quote_identifier(tle->resdom->resname)); } appendStringInfo(buf, ") "); @@ -1124,7 +1135,8 @@ get_update_query_def(Query *query, deparse_context *context) * ---------- */ rte = (RangeTblEntry *) nth(query->resultRelation - 1, query->rtable); - appendStringInfo(buf, "UPDATE \"%s\" SET ", rte->relname); + appendStringInfo(buf, "UPDATE %s SET ", + quote_identifier(rte->relname)); /* Add the comma separated list of 'attname = value' */ sep = ""; @@ -1134,7 +1146,8 @@ get_update_query_def(Query *query, deparse_context *context) appendStringInfo(buf, sep); sep = ", "; - appendStringInfo(buf, "\"%s\" = ", tle->resdom->resname); + appendStringInfo(buf, "%s = ", + quote_identifier(tle->resdom->resname)); get_tle_expr(tle, context); } @@ -1162,7 +1175,8 @@ get_delete_query_def(Query *query, deparse_context *context) * ---------- */ rte = (RangeTblEntry *) nth(query->resultRelation - 1, query->rtable); - appendStringInfo(buf, "DELETE FROM \"%s\"", rte->relname); + appendStringInfo(buf, "DELETE FROM %s", + quote_identifier(rte->relname)); /* Add a WHERE clause if given */ if (query->qual != NULL) @@ -1227,11 +1241,12 @@ get_rule_expr(Node *node, deparse_context *context) else if (!strcmp(rte->refname, "*CURRENT*")) appendStringInfo(buf, "old."); else - appendStringInfo(buf, "\"%s\".", rte->refname); + appendStringInfo(buf, "%s.", + quote_identifier(rte->refname)); } - appendStringInfo(buf, "\"%s\"", - get_attribute_name(rte->relid, - var->varattno)); + appendStringInfo(buf, "%s", + quote_identifier(get_attribute_name(rte->relid, + var->varattno))); } break; @@ -1332,7 +1347,8 @@ get_rule_expr(Node *node, deparse_context *context) { Aggref *aggref = (Aggref *) node; - appendStringInfo(buf, "\"%s\"(", aggref->aggname); + appendStringInfo(buf, "%s(", + quote_identifier(aggref->aggname)); get_rule_expr(aggref->target, context); appendStringInfo(buf, ")"); } @@ -1453,7 +1469,7 @@ get_func_expr(Expr *expr, deparse_context *context) * Build a string of proname(args) * ---------- */ - appendStringInfo(buf, "\"%s\"(", proname); + appendStringInfo(buf, "%s(", quote_identifier(proname)); sep = ""; foreach(l, expr->args) { @@ -1566,7 +1582,7 @@ get_tle_expr(TargetEntry *tle, deparse_context *context) /* ---------- * get_const_expr * - * Make a string representation with the type cast out of a Const + * Make a string representation of a Const * ---------- */ static void @@ -1598,34 +1614,55 @@ get_const_expr(Const *constval, deparse_context *context) extval = (char *) (*fmgr_faddr(&finfo_output)) (constval->constvalue, &isnull, -1); - /* - * We must quote any funny characters in the constant's representation. - * XXX Any MULTIBYTE considerations here? - */ - appendStringInfoChar(buf, '\''); - for (valptr = extval; *valptr; valptr++) + switch (constval->consttype) { - char ch = *valptr; - if (ch == '\'' || ch == '\\') - { - appendStringInfoChar(buf, '\\'); - appendStringInfoChar(buf, ch); - } - else if (ch >= 0 && ch < ' ') - { - appendStringInfo(buf, "\\%03o", ch); - } - else - appendStringInfoChar(buf, ch); + case INT2OID: + case INT4OID: + case OIDOID: /* int types */ + case FLOAT4OID: + case FLOAT8OID: /* float types */ + /* These types are printed without quotes */ + appendStringInfo(buf, extval); + break; + default: + /* + * We must quote any funny characters in the constant's + * representation. + * XXX Any MULTIBYTE considerations here? + */ + appendStringInfoChar(buf, '\''); + for (valptr = extval; *valptr; valptr++) + { + char ch = *valptr; + if (ch == '\'' || ch == '\\') + { + appendStringInfoChar(buf, '\\'); + appendStringInfoChar(buf, ch); + } + else if (ch >= 0 && ch < ' ') + appendStringInfo(buf, "\\%03o", (int) ch); + else + appendStringInfoChar(buf, ch); + } + appendStringInfoChar(buf, '\''); + break; } - appendStringInfoChar(buf, '\''); - pfree(extval); - extval = (char *) nameout(&(typeStruct->typname)); - /* probably would be better to recognize UNKNOWN by OID... */ - if (strcmp(extval, "unknown") != 0) - appendStringInfo(buf, "::\"%s\"", extval); pfree(extval); + + switch (constval->consttype) + { + case INT4OID: + case FLOAT8OID: + case UNKNOWNOID: + /* These types can be left unlabeled */ + break; + default: + extval = (char *) nameout(&(typeStruct->typname)); + appendStringInfo(buf, "::%s", quote_identifier(extval)); + pfree(extval); + break; + } } @@ -1696,6 +1733,52 @@ get_sublink_expr(Node *node, deparse_context *context) appendStringInfo(buf, "))"); } +/* ---------- + * quote_identifier - Quote an identifier only if needed + * + * When quotes are needed, we palloc the required space; slightly + * space-wasteful but well worth it for notational simplicity. + * ---------- + */ +static char * +quote_identifier(char *ident) +{ + /* + * Can avoid quoting if ident starts with a lowercase letter and + * contains only lowercase letters, digits, and underscores. + * Otherwise, supply quotes. + */ + bool safe; + char *result; + + /* + * would like to use macros here, but they might yield + * unwanted locale-specific results... + */ + safe = (ident[0] >= 'a' && ident[0] <= 'z'); + if (safe) + { + char *ptr; + + for (ptr = ident+1; *ptr; ptr++) + { + char ch = *ptr; + + safe = ((ch >= 'a' && ch <= 'z') || + (ch >= '0' && ch <= '9') || + (ch == '_')); + if (! safe) + break; + } + } + + if (safe) + return ident; /* no change needed */ + + result = (char *) palloc(strlen(ident) + 2 + 1); + sprintf(result, "\"%s\"", ident); + return result; +} /* ---------- * get_relation_name - Get a relation name by Oid @@ -1729,7 +1812,8 @@ get_attribute_name(Oid relid, int2 attnum) Form_pg_attribute attStruct; atttup = SearchSysCacheTuple(ATTNUM, - ObjectIdGetDatum(relid), (Datum) attnum, 0, 0); + ObjectIdGetDatum(relid), (Datum) attnum, + 0, 0); if (!HeapTupleIsValid(atttup)) elog(ERROR, "cache lookup of attribute %d in relation %u failed", attnum, relid); -- 2.11.0