Commit 3e21ecbb authored by Tom Lane's avatar Tom Lane

Make the rule deparser a little less quote-happy, so that

display of default expressions isn't quite so ugly.
parent 7cd67c80
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
* out of it's tuple * out of it's tuple
* *
* IDENTIFICATION * 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. * This software is copyrighted by Jan Wieck - Hamburg.
* *
...@@ -47,6 +47,7 @@ ...@@ -47,6 +47,7 @@
#include "catalog/pg_index.h" #include "catalog/pg_index.h"
#include "catalog/pg_operator.h" #include "catalog/pg_operator.h"
#include "catalog/pg_shadow.h" #include "catalog/pg_shadow.h"
#include "catalog/pg_type.h"
#include "utils/builtins.h" #include "utils/builtins.h"
#include "utils/lsyscache.h" #include "utils/lsyscache.h"
...@@ -104,6 +105,7 @@ static void get_func_expr(Expr *expr, deparse_context *context); ...@@ -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_tle_expr(TargetEntry *tle, deparse_context *context);
static void get_const_expr(Const *constval, deparse_context *context); static void get_const_expr(Const *constval, deparse_context *context);
static void get_sublink_expr(Node *node, 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_relation_name(Oid relid);
static char *get_attribute_name(Oid relid, int2 attnum); static char *get_attribute_name(Oid relid, int2 attnum);
static bool check_if_rte_used(Node *node, Index rt_index, int levelsup); static bool check_if_rte_used(Node *node, Index rt_index, int levelsup);
...@@ -404,9 +406,11 @@ pg_get_indexdef(Oid indexrelid) ...@@ -404,9 +406,11 @@ pg_get_indexdef(Oid indexrelid)
spi_nulls[1] = '\0'; spi_nulls[1] = '\0';
spirc = SPI_execp(plan_getam, spi_args, spi_nulls, 1); spirc = SPI_execp(plan_getam, spi_args, spi_nulls, 1);
if (spirc != SPI_OK_SELECT) 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) 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_tup = SPI_tuptable->vals[0];
spi_ttc = SPI_tuptable->tupdesc; spi_ttc = SPI_tuptable->tupdesc;
spi_fno = SPI_fnumber(spi_ttc, "amname"); spi_fno = SPI_fnumber(spi_ttc, "amname");
...@@ -416,11 +420,12 @@ pg_get_indexdef(Oid indexrelid) ...@@ -416,11 +420,12 @@ pg_get_indexdef(Oid indexrelid)
* ---------- * ----------
*/ */
initStringInfo(&buf); initStringInfo(&buf);
appendStringInfo(&buf, "CREATE %sINDEX \"%s\" ON \"%s\" USING %s (", appendStringInfo(&buf, "CREATE %sINDEX %s ON %s USING %s (",
idxrec->indisunique ? "UNIQUE " : "", idxrec->indisunique ? "UNIQUE " : "",
nameout(&(idxrelrec->relname)), quote_identifier(nameout(&(idxrelrec->relname))),
nameout(&(indrelrec->relname)), quote_identifier(nameout(&(indrelrec->relname))),
SPI_getvalue(spi_tup, spi_ttc, spi_fno)); quote_identifier(SPI_getvalue(spi_tup, spi_ttc,
spi_fno)));
/* ---------- /* ----------
* Collect the indexed attributes * Collect the indexed attributes
...@@ -440,12 +445,9 @@ pg_get_indexdef(Oid indexrelid) ...@@ -440,12 +445,9 @@ pg_get_indexdef(Oid indexrelid)
* Add the indexed field name * Add the indexed field name
* ---------- * ----------
*/ */
if (idxrec->indkey[keyno] == ObjectIdAttributeNumber - 1) appendStringInfo(&keybuf, "%s",
appendStringInfo(&keybuf, "\"oid\""); quote_identifier(get_attribute_name(idxrec->indrelid,
else idxrec->indkey[keyno])));
appendStringInfo(&keybuf, "\"%s\"",
get_attribute_name(idxrec->indrelid,
idxrec->indkey[keyno]));
/* ---------- /* ----------
* If not a functional index, add the operator class name * If not a functional index, add the operator class name
...@@ -464,8 +466,9 @@ pg_get_indexdef(Oid indexrelid) ...@@ -464,8 +466,9 @@ pg_get_indexdef(Oid indexrelid)
spi_tup = SPI_tuptable->vals[0]; spi_tup = SPI_tuptable->vals[0];
spi_ttc = SPI_tuptable->tupdesc; spi_ttc = SPI_tuptable->tupdesc;
spi_fno = SPI_fnumber(spi_ttc, "opcname"); spi_fno = SPI_fnumber(spi_ttc, "opcname");
appendStringInfo(&keybuf, " \"%s\"", appendStringInfo(&keybuf, " %s",
SPI_getvalue(spi_tup, spi_ttc, spi_fno)); quote_identifier(SPI_getvalue(spi_tup, spi_ttc,
spi_fno)));
} }
} }
...@@ -484,8 +487,8 @@ pg_get_indexdef(Oid indexrelid) ...@@ -484,8 +487,8 @@ pg_get_indexdef(Oid indexrelid)
elog(ERROR, "cache lookup for proc %u failed", idxrec->indproc); elog(ERROR, "cache lookup for proc %u failed", idxrec->indproc);
procStruct = (Form_pg_proc) GETSTRUCT(proctup); procStruct = (Form_pg_proc) GETSTRUCT(proctup);
appendStringInfo(&buf, "\"%s\" (%s) ", appendStringInfo(&buf, "%s(%s) ",
nameout(&(procStruct->proname)), quote_identifier(nameout(&(procStruct->proname))),
keybuf.data); keybuf.data);
spi_args[0] = ObjectIdGetDatum(idxrec->indclass[0]); spi_args[0] = ObjectIdGetDatum(idxrec->indclass[0]);
...@@ -499,8 +502,9 @@ pg_get_indexdef(Oid indexrelid) ...@@ -499,8 +502,9 @@ pg_get_indexdef(Oid indexrelid)
spi_tup = SPI_tuptable->vals[0]; spi_tup = SPI_tuptable->vals[0];
spi_ttc = SPI_tuptable->tupdesc; spi_ttc = SPI_tuptable->tupdesc;
spi_fno = SPI_fnumber(spi_ttc, "opcname"); spi_fno = SPI_fnumber(spi_ttc, "opcname");
appendStringInfo(&buf, "\"%s\"", appendStringInfo(&buf, "%s",
SPI_getvalue(spi_tup, spi_ttc, spi_fno)); quote_identifier(SPI_getvalue(spi_tup, spi_ttc,
spi_fno)));
} }
else else
/* ---------- /* ----------
...@@ -658,7 +662,8 @@ make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc) ...@@ -658,7 +662,8 @@ make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc)
* Build the rules definition text * 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 */ /* The event the rule is fired for */
switch (ev_type) switch (ev_type)
...@@ -686,10 +691,12 @@ make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc) ...@@ -686,10 +691,12 @@ make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc)
} }
/* The relation the rule is fired on */ /* 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) if (ev_attr > 0)
appendStringInfo(buf, ".\"%s\"", appendStringInfo(buf, ".%s",
get_attribute_name(ev_class, ev_attr)); quote_identifier(get_attribute_name(ev_class,
ev_attr)));
/* If the rule has an event qualification, add it */ /* If the rule has an event qualification, add it */
if (ev_qual == NULL) if (ev_qual == NULL)
...@@ -954,7 +961,8 @@ get_select_query_def(Query *query, deparse_context *context) ...@@ -954,7 +961,8 @@ get_select_query_def(Query *query, deparse_context *context)
/* and do if so */ /* and do if so */
if (tell_as) 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 */ /* 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,9 +986,11 @@ get_select_query_def(Query *query, deparse_context *context)
appendStringInfo(buf, sep); appendStringInfo(buf, sep);
sep = ", "; sep = ", ";
appendStringInfo(buf, "\"%s\"", rte->relname); appendStringInfo(buf, "%s",
quote_identifier(rte->relname));
if (strcmp(rte->relname, rte->refname) != 0) 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) ...@@ -1072,7 +1082,8 @@ get_insert_query_def(Query *query, deparse_context *context)
* ---------- * ----------
*/ */
rte = (RangeTblEntry *) nth(query->resultRelation - 1, query->rtable); 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 */ /* Add the target list */
sep = " ("; sep = " (";
...@@ -1082,7 +1093,7 @@ get_insert_query_def(Query *query, deparse_context *context) ...@@ -1082,7 +1093,7 @@ get_insert_query_def(Query *query, deparse_context *context)
appendStringInfo(buf, sep); appendStringInfo(buf, sep);
sep = ", "; sep = ", ";
appendStringInfo(buf, "\"%s\"", tle->resdom->resname); appendStringInfo(buf, "%s", quote_identifier(tle->resdom->resname));
} }
appendStringInfo(buf, ") "); appendStringInfo(buf, ") ");
...@@ -1124,7 +1135,8 @@ get_update_query_def(Query *query, deparse_context *context) ...@@ -1124,7 +1135,8 @@ get_update_query_def(Query *query, deparse_context *context)
* ---------- * ----------
*/ */
rte = (RangeTblEntry *) nth(query->resultRelation - 1, query->rtable); 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' */ /* Add the comma separated list of 'attname = value' */
sep = ""; sep = "";
...@@ -1134,7 +1146,8 @@ get_update_query_def(Query *query, deparse_context *context) ...@@ -1134,7 +1146,8 @@ get_update_query_def(Query *query, deparse_context *context)
appendStringInfo(buf, sep); appendStringInfo(buf, sep);
sep = ", "; sep = ", ";
appendStringInfo(buf, "\"%s\" = ", tle->resdom->resname); appendStringInfo(buf, "%s = ",
quote_identifier(tle->resdom->resname));
get_tle_expr(tle, context); get_tle_expr(tle, context);
} }
...@@ -1162,7 +1175,8 @@ get_delete_query_def(Query *query, deparse_context *context) ...@@ -1162,7 +1175,8 @@ get_delete_query_def(Query *query, deparse_context *context)
* ---------- * ----------
*/ */
rte = (RangeTblEntry *) nth(query->resultRelation - 1, query->rtable); 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 */ /* Add a WHERE clause if given */
if (query->qual != NULL) if (query->qual != NULL)
...@@ -1227,11 +1241,12 @@ get_rule_expr(Node *node, deparse_context *context) ...@@ -1227,11 +1241,12 @@ get_rule_expr(Node *node, deparse_context *context)
else if (!strcmp(rte->refname, "*CURRENT*")) else if (!strcmp(rte->refname, "*CURRENT*"))
appendStringInfo(buf, "old."); appendStringInfo(buf, "old.");
else else
appendStringInfo(buf, "\"%s\".", rte->refname); appendStringInfo(buf, "%s.",
quote_identifier(rte->refname));
} }
appendStringInfo(buf, "\"%s\"", appendStringInfo(buf, "%s",
get_attribute_name(rte->relid, quote_identifier(get_attribute_name(rte->relid,
var->varattno)); var->varattno)));
} }
break; break;
...@@ -1332,7 +1347,8 @@ get_rule_expr(Node *node, deparse_context *context) ...@@ -1332,7 +1347,8 @@ get_rule_expr(Node *node, deparse_context *context)
{ {
Aggref *aggref = (Aggref *) node; Aggref *aggref = (Aggref *) node;
appendStringInfo(buf, "\"%s\"(", aggref->aggname); appendStringInfo(buf, "%s(",
quote_identifier(aggref->aggname));
get_rule_expr(aggref->target, context); get_rule_expr(aggref->target, context);
appendStringInfo(buf, ")"); appendStringInfo(buf, ")");
} }
...@@ -1453,7 +1469,7 @@ get_func_expr(Expr *expr, deparse_context *context) ...@@ -1453,7 +1469,7 @@ get_func_expr(Expr *expr, deparse_context *context)
* Build a string of proname(args) * Build a string of proname(args)
* ---------- * ----------
*/ */
appendStringInfo(buf, "\"%s\"(", proname); appendStringInfo(buf, "%s(", quote_identifier(proname));
sep = ""; sep = "";
foreach(l, expr->args) foreach(l, expr->args)
{ {
...@@ -1566,7 +1582,7 @@ get_tle_expr(TargetEntry *tle, deparse_context *context) ...@@ -1566,7 +1582,7 @@ get_tle_expr(TargetEntry *tle, deparse_context *context)
/* ---------- /* ----------
* get_const_expr * get_const_expr
* *
* Make a string representation with the type cast out of a Const * Make a string representation of a Const
* ---------- * ----------
*/ */
static void static void
...@@ -1598,8 +1614,20 @@ get_const_expr(Const *constval, deparse_context *context) ...@@ -1598,8 +1614,20 @@ get_const_expr(Const *constval, deparse_context *context)
extval = (char *) (*fmgr_faddr(&finfo_output)) (constval->constvalue, extval = (char *) (*fmgr_faddr(&finfo_output)) (constval->constvalue,
&isnull, -1); &isnull, -1);
switch (constval->consttype)
{
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. * We must quote any funny characters in the constant's
* representation.
* XXX Any MULTIBYTE considerations here? * XXX Any MULTIBYTE considerations here?
*/ */
appendStringInfoChar(buf, '\''); appendStringInfoChar(buf, '\'');
...@@ -1612,20 +1640,29 @@ get_const_expr(Const *constval, deparse_context *context) ...@@ -1612,20 +1640,29 @@ get_const_expr(Const *constval, deparse_context *context)
appendStringInfoChar(buf, ch); appendStringInfoChar(buf, ch);
} }
else if (ch >= 0 && ch < ' ') else if (ch >= 0 && ch < ' ')
{ appendStringInfo(buf, "\\%03o", (int) ch);
appendStringInfo(buf, "\\%03o", ch);
}
else else
appendStringInfoChar(buf, ch); appendStringInfoChar(buf, ch);
} }
appendStringInfoChar(buf, '\''); appendStringInfoChar(buf, '\'');
break;
}
pfree(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)); extval = (char *) nameout(&(typeStruct->typname));
/* probably would be better to recognize UNKNOWN by OID... */ appendStringInfo(buf, "::%s", quote_identifier(extval));
if (strcmp(extval, "unknown") != 0)
appendStringInfo(buf, "::\"%s\"", extval);
pfree(extval); pfree(extval);
break;
}
} }
...@@ -1696,6 +1733,52 @@ get_sublink_expr(Node *node, deparse_context *context) ...@@ -1696,6 +1733,52 @@ get_sublink_expr(Node *node, deparse_context *context)
appendStringInfo(buf, "))"); 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 <ctype.h> 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 * get_relation_name - Get a relation name by Oid
...@@ -1729,7 +1812,8 @@ get_attribute_name(Oid relid, int2 attnum) ...@@ -1729,7 +1812,8 @@ get_attribute_name(Oid relid, int2 attnum)
Form_pg_attribute attStruct; Form_pg_attribute attStruct;
atttup = SearchSysCacheTuple(ATTNUM, atttup = SearchSysCacheTuple(ATTNUM,
ObjectIdGetDatum(relid), (Datum) attnum, 0, 0); ObjectIdGetDatum(relid), (Datum) attnum,
0, 0);
if (!HeapTupleIsValid(atttup)) if (!HeapTupleIsValid(atttup))
elog(ERROR, "cache lookup of attribute %d in relation %u failed", elog(ERROR, "cache lookup of attribute %d in relation %u failed",
attnum, relid); attnum, relid);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment