public inbox for [email protected]
help / color / mirror / Atom feedFrom: Chao Li <[email protected]>
To: Postgres hackers <[email protected]>
Subject: Re: quoteOneName() inconsistency with quote_all_identifiers — replacement API proposed
Date: Thu, 20 Nov 2025 16:19:00 +0800
Message-ID: <CAEoWx2=vRfws6C2svUWdmNA10no+g71HABDqqKdbL43adC-VuQ@mail.gmail.com> (raw)
In-Reply-To: <CAEoWx2=g2RVkxXB=JzWphgfg4QGV+spaA3PQ1rBM2iMehrVvjg@mail.gmail.com>
References: <CAEoWx2=g2RVkxXB=JzWphgfg4QGV+spaA3PQ1rBM2iMehrVvjg@mail.gmail.com>
On Mon, Nov 17, 2025 at 5:48 PM Chao Li <[email protected]> wrote:
> Hi Hackers,
>
> == Background ==
>
> While reviewing a patch, I noticed that quoteOneName() duplicates the
> logic of quote_identifier() for adding double quotes to identifiers. The
> main difference is that quoteOneName() does *not* honor the GUC
> `quote_all_identifiers`.
>
> The typical usage pattern of quoteOneName() looks like this:
>
> ```
> // Define a local buffer with size MAX_QUOTED_NAME_LEN
> // MAX_QUOTED_NAME_LEN = MAX_NAMELEN * 2 + 3 to ensure no overflow
> char attname[MAX_QUOTED_NAME_LEN];
>
> // Add quotes and copy into the stack buffer
> quoteOneName(attname, RIAttName(pk_rel,
> riinfo->pk_attnums[riinfo->nkeys - 1]));
>
> // Copy the quoted identifier into a StringInfo
> appendStringInfoString(&querybuf, attname);
> ```
>
> This pattern is expensive because:
>
> * it allocates a larger-than-necessary buffer on the stack
> * it incurs two pallocs and two data copies
>
> Looking further, the common pattern around quote_identifier() is similar:
>
> ```
> appendStringInfoString(&relations, quote_identifier(relname));
> ```
>
> This also incurs two pallocs and two copies: quote_identifier() allocates
> a temporary buffer and copies the quoted identifier into it, and then
> appendStringInfoString() may allocate and copy again.
>
> == Idea ==
>
> I'd like to propose introducing `appendStringInfoIdentifier()`, which adds
> the quoting logic directly to StringInfo. The goals are:
>
> * eventually deprecate quoteOneName() — I'm not aware of a reason why it
> should ignore the GUC `quote_all_identifiers`
> * simplify the usage patterns for quoting identifiers
> * avoid unnecessary intermediate buffers, pallocs, and data copies
>
> == About the attached patch ==
>
> Attached v1 is not intended to be the final version — it is mainly to
> demonstrate the idea and get feedback on the design direction.
>
> * 0001 implements `appendStringInfoIdentifier()` and uses it in a few
> places
> * 0002 switches ri_triggers.c to use it, resolving a complicated usage
> pattern and showing a path toward removing quoteOneName()
>
> Comments and suggestions on the overall direction would be very welcome.
>
>
CF entry added: https://commitfest.postgresql.org/patch/6240/. And here
comes the v2 patch set.
Best regards,
Chao Li (Evan)
---------------------
HighGo Software Co., Ltd.
https://www.highgo.com/
Attachments:
[application/octet-stream] v2-0001-Add-appendStringInfoIdentifier-to-avoid-intermedi.patch (11.3K, 3-v2-0001-Add-appendStringInfoIdentifier-to-avoid-intermedi.patch)
download | inline diff:
From 70971d0e75ab61436d0328a88e5441cf2751a9b6 Mon Sep 17 00:00:00 2001
From: "Chao Li (Evan)" <[email protected]>
Date: Fri, 14 Nov 2025 21:44:29 +0800
Subject: [PATCH v2 1/4] Add appendStringInfoIdentifier() to avoid intermediate
quoting buffers
Introduce appendStringInfoIdentifier() and
appendStringInfoQualifiedIdentifier(), helper functions that append an SQL
identifier directly to a StringInfo while applying quoting rules when
necessary. This avoids allocating and copying through temporary palloc
buffers, as currently happens with quote_identifier() when used together
with appendStringInfoString().
The new functions improve both readability and efficiency of call sites that
construct SQL fragments, especially those that need to build qualified
names such as schema.table.
Convert several existing callers in objectaddress.c, explain.c and
ruleutils.c to use appendStringInfoIdentifier() /
appendStringInfoQualifiedIdentifier() as examples.
No functional behavior change is intended.
Author: Chao Li <[email protected]>
Discussion: https://postgr.es/m/CAEoWx2=g2RVkxXB=JzWphgfg4QGV+spaA3PQ1rBM2iMehrVvjg@mail.gmail.com
---
src/backend/catalog/objectaddress.c | 20 ++--
src/backend/commands/explain.c | 3 +-
src/backend/utils/adt/ri_triggers.c | 8 +-
src/backend/utils/adt/ruleutils.c | 142 +++++++++++++++++++++++-----
src/include/utils/builtins.h | 6 ++
5 files changed, 136 insertions(+), 43 deletions(-)
diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c75b7131ed7..fbb0b4f30f3 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -3611,9 +3611,9 @@ getObjectDescription(const ObjectAddress *object, bool missing_ok)
else
nspname = get_namespace_name(cfgForm->cfgnamespace);
- appendStringInfo(&buffer, _("text search configuration %s"),
- quote_qualified_identifier(nspname,
- NameStr(cfgForm->cfgname)));
+ appendStringInfoQualifiedIdentifier(&buffer,
+ _("text search configuration "),
+ nspname, NameStr(cfgForm->cfgname), NULL);
ReleaseSysCache(tup);
break;
}
@@ -4883,8 +4883,7 @@ getObjectIdentityParts(const ObjectAddress *object,
if (attr)
{
- appendStringInfo(&buffer, ".%s",
- quote_identifier(attr));
+ appendStringInfoIdentifier(&buffer, ".", attr, NULL);
if (objname)
*objname = lappend(*objname, attr);
}
@@ -5395,8 +5394,7 @@ getObjectIdentityParts(const ObjectAddress *object,
object->objectId);
break;
}
- appendStringInfoString(&buffer,
- quote_identifier(nspname));
+ appendStringInfoIdentifier(&buffer, NULL, nspname, NULL);
if (objname)
*objname = list_make1(nspname);
break;
@@ -5739,16 +5737,12 @@ getObjectIdentityParts(const ObjectAddress *object,
defacl = (Form_pg_default_acl) GETSTRUCT(tup);
username = GetUserNameFromId(defacl->defaclrole, false);
- appendStringInfo(&buffer,
- "for role %s",
- quote_identifier(username));
+ appendStringInfoIdentifier(&buffer, "for role ", username, NULL);
if (OidIsValid(defacl->defaclnamespace))
{
schema = get_namespace_name_or_temp(defacl->defaclnamespace);
- appendStringInfo(&buffer,
- " in schema %s",
- quote_identifier(schema));
+ appendStringInfoIdentifier(&buffer, " in schema ", schema, NULL);
}
else
schema = NULL;
diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c
index 7e699f8595e..cc979737845 100644
--- a/src/backend/commands/explain.c
+++ b/src/backend/commands/explain.c
@@ -1705,8 +1705,7 @@ ExplainNode(PlanState *planstate, List *ancestors,
explain_get_index_name(bitmapindexscan->indexid);
if (es->format == EXPLAIN_FORMAT_TEXT)
- appendStringInfo(es->str, " on %s",
- quote_identifier(indexname));
+ appendStringInfoIdentifier(es->str, " on ", indexname, NULL);
else
ExplainPropertyText("Index Name", indexname, es);
}
diff --git a/src/backend/utils/adt/ri_triggers.c b/src/backend/utils/adt/ri_triggers.c
index 059fc5ebf60..9e13f526994 100644
--- a/src/backend/utils/adt/ri_triggers.c
+++ b/src/backend/utils/adt/ri_triggers.c
@@ -395,7 +395,6 @@ RI_FKey_check(TriggerData *trigdata)
{
quoteOneName(attname,
RIAttName(pk_rel, riinfo->pk_attnums[riinfo->nkeys - 1]));
-
appendStringInfo(&querybuf,
"SELECT 1 FROM (SELECT %s AS r FROM %s%s x",
attname, pk_only, pkrelname);
@@ -2095,7 +2094,6 @@ ri_GenerateQualCollation(StringInfo buf, Oid collation)
HeapTuple tp;
Form_pg_collation colltup;
char *collname;
- char onename[MAX_QUOTED_NAME_LEN];
/* Nothing to do if it's a noncollatable data type */
if (!OidIsValid(collation))
@@ -2111,10 +2109,8 @@ ri_GenerateQualCollation(StringInfo buf, Oid collation)
* We qualify the name always, for simplicity and to ensure the query is
* not search-path-dependent.
*/
- quoteOneName(onename, get_namespace_name(colltup->collnamespace));
- appendStringInfo(buf, " COLLATE %s", onename);
- quoteOneName(onename, collname);
- appendStringInfo(buf, ".%s", onename);
+ appendStringInfoIdentifier(buf, " COLLATE ", get_namespace_name(colltup->collnamespace), NULL);
+ appendStringInfoIdentifier(buf, ".", collname, NULL);
ReleaseSysCache(tp);
}
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index 556ab057e5a..1d767deb6c4 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -13052,25 +13052,17 @@ printSubscripts(SubscriptingRef *sbsref, deparse_context *context)
}
}
-/*
- * 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.
- */
-const char *
-quote_identifier(const char *ident)
+static inline bool
+is_identifier_safe(const char *ident, int *nquotes)
{
/*
* Can avoid quoting if ident starts with a lowercase letter or underscore
* and contains only lowercase letters, digits, and underscores, *and* is
* not any SQL keyword. Otherwise, supply quotes.
*/
- int nquotes = 0;
bool safe;
- const char *ptr;
- char *result;
- char *optr;
+
+ *nquotes = 0;
/*
* would like to use <ctype.h> macros here, but they might yield unwanted
@@ -13078,7 +13070,7 @@ quote_identifier(const char *ident)
*/
safe = ((ident[0] >= 'a' && ident[0] <= 'z') || ident[0] == '_');
- for (ptr = ident; *ptr; ptr++)
+ for (const char *ptr = ident; *ptr; ptr++)
{
char ch = *ptr;
@@ -13092,7 +13084,7 @@ quote_identifier(const char *ident)
{
safe = false;
if (ch == '"')
- nquotes++;
+ (*nquotes)++;
}
}
@@ -13115,14 +13107,20 @@ quote_identifier(const char *ident)
safe = false;
}
- if (safe)
- return ident; /* no change needed */
+ return safe;
+}
- result = (char *) palloc(strlen(ident) + nquotes + 2 + 1);
+static inline const char *
+quote_identifier_internal(const char *ident, int nquotes, char **result)
+{
+ char *optr;
- optr = result;
+ if (*result == NULL)
+ *result = (char *) palloc(strlen(ident) + nquotes + 2 + 1);
+
+ optr = *result;
*optr++ = '"';
- for (ptr = ident; *ptr; ptr++)
+ for (const char *ptr = ident; *ptr; ptr++)
{
char ch = *ptr;
@@ -13133,7 +13131,107 @@ quote_identifier(const char *ident)
*optr++ = '"';
*optr = '\0';
- return result;
+ return *result;
+}
+
+/*
+ * 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.
+ */
+const char *
+quote_identifier(const char *ident)
+{
+ int nquotes;
+ bool safe;
+ char *result = NULL;
+
+ safe = is_identifier_safe(ident, &nquotes);
+ if (safe)
+ return ident; /* no change needed */
+
+ return quote_identifier_internal(ident, nquotes, &result);
+}
+
+/*
+ * appendStringInfoIdentifier
+ * Append an SQL identifier to a StringInfo, quoting if required.
+ *
+ * This behaves like writing prefix + quote_identifier(ident) + suffix into
+ * the StringInfo, but emits the identifier directly into the buffer to avoid
+ * an intermediate palloc. prefix and suffix may be NULL.
+ *
+ * The identifier is copied verbatim if it is safe to leave unquoted; otherwise
+ * it is written with double quotes and embedded double quotes are doubled.
+ * Quoting rules are local to ruleutils, so this helper is defined here rather
+ * than in stringinfo.c.
+ */
+
+void
+appendStringInfoIdentifier(StringInfo str, const char *prefix,
+ const char *ident, const char *suffix)
+{
+ int nquotes;
+ bool safe;
+ int ident_len;
+ int prefix_len = 0;
+ int suffix_len = 0;
+
+ safe = is_identifier_safe(ident, &nquotes);
+ if (safe)
+ ident_len = strlen(ident);
+ else
+ ident_len = strlen(ident) + nquotes + 2; /* quotes + possible
+ * escapes */
+
+ if (prefix != NULL)
+ prefix_len = strlen(prefix);
+
+ if (suffix != NULL)
+ suffix_len = strlen(suffix);
+
+ enlargeStringInfo(str, ident_len + prefix_len + suffix_len + 1); /* +1 for trailing null */
+
+ if (prefix != NULL)
+ appendBinaryStringInfo(str, prefix, prefix_len);
+
+ if (safe)
+ appendBinaryStringInfo(str, ident, ident_len);
+ else
+ {
+ char *result = str->data + str->len;
+
+ (void) quote_identifier_internal(ident, nquotes, &result);
+ str->len += ident_len;
+ str->data[str->len] = '\0';
+ }
+
+ if (suffix != NULL)
+ appendBinaryStringInfo(str, suffix, suffix_len);
+}
+
+/*
+ * appendStringInfoQualifiedIdentifier
+ * Append a (possibly) qualified SQL identifier to a StringInfo.
+ *
+ * Writes prefix + qualifier + '.' + ident + suffix, quoting each identifier
+ * component if needed. If no qualifier is given, only ident (plus optional
+ * prefix/suffix) is appended. prefix and suffix may be NULL.
+ *
+ * This is a convenience wrapper around appendStringInfoIdentifier().
+ */
+void
+appendStringInfoQualifiedIdentifier(StringInfo str, const char *prefix,
+ const char *qualifier, const char *ident,
+ const char *suffix)
+{
+ if (qualifier)
+ {
+ appendStringInfoIdentifier(str, prefix, qualifier, ".");
+ prefix = NULL;
+ }
+ appendStringInfoIdentifier(str, prefix, ident, suffix);
}
/*
@@ -13150,8 +13248,8 @@ quote_qualified_identifier(const char *qualifier,
initStringInfo(&buf);
if (qualifier)
- appendStringInfo(&buf, "%s.", quote_identifier(qualifier));
- appendStringInfoString(&buf, quote_identifier(ident));
+ appendStringInfoIdentifier(&buf, NULL, qualifier, ".");
+ appendStringInfoIdentifier(&buf, NULL, ident, NULL);
return buf.data;
}
diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h
index ce6285a2c03..ff4ba7265c2 100644
--- a/src/include/utils/builtins.h
+++ b/src/include/utils/builtins.h
@@ -84,6 +84,12 @@ extern void generate_operator_clause(StringInfo buf,
const char *leftop, Oid leftoptype,
Oid opoid,
const char *rightop, Oid rightoptype);
+extern void appendStringInfoIdentifier(StringInfo str, const char *prefix, const char *ident, const char *suffix);
+extern void appendStringInfoQualifiedIdentifier(StringInfo str,
+ const char *prefix,
+ const char *qualifier,
+ const char *ident,
+ const char *suffix);
/* varchar.c */
extern int bpchartruelen(char *s, int len);
--
2.39.5 (Apple Git-154)
[application/octet-stream] v2-0004-Use-appendStringInfoIdentifier-in-more-places.patch (35.6K, 4-v2-0004-Use-appendStringInfoIdentifier-in-more-places.patch)
download | inline diff:
From 12cc4e6619f7cb273a1f02dc1706cac842c89ac3 Mon Sep 17 00:00:00 2001
From: "Chao Li (Evan)" <[email protected]>
Date: Wed, 19 Nov 2025 15:55:23 +0800
Subject: [PATCH v2 4/4] Use appendStringInfoIdentifier() in more places.
Author: Chao Li <[email protected]>
Discussion: https://postgr.es/m/CAEoWx2=g2RVkxXB=JzWphgfg4QGV+spaA3PQ1rBM2iMehrVvjg@mail.gmail.com
---
src/backend/catalog/namespace.c | 6 +-
src/backend/catalog/objectaddress.c | 64 +++----
src/backend/utils/adt/ri_triggers.c | 8 +-
src/backend/utils/adt/ruleutils.c | 260 ++++++++++++----------------
4 files changed, 147 insertions(+), 191 deletions(-)
diff --git a/src/backend/catalog/namespace.c b/src/backend/catalog/namespace.c
index d23474da4fb..7c3b0bb7853 100644
--- a/src/backend/catalog/namespace.c
+++ b/src/backend/catalog/namespace.c
@@ -3699,14 +3699,14 @@ NameListToQuotedString(const List *names)
{
StringInfoData string;
ListCell *l;
+ const char *sep = "";
initStringInfo(&string);
foreach(l, names)
{
- if (l != list_head(names))
- appendStringInfoChar(&string, '.');
- appendStringInfoString(&string, quote_identifier(strVal(lfirst(l))));
+ appendStringInfoIdentifier(&string, sep, strVal(lfirst(l)), NULL);
+ sep = ".";
}
return string.data;
diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index fbb0b4f30f3..ee495fc5155 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -5004,8 +5004,7 @@ getObjectIdentityParts(const ObjectAddress *object,
if (OidIsValid(con->conrelid))
{
- appendStringInfo(&buffer, "%s on ",
- quote_identifier(NameStr(con->conname)));
+ appendStringInfoIdentifier(&buffer, NULL, NameStr(con->conname), " on ");
getRelationIdentity(&buffer, con->conrelid, objname,
false);
if (objname)
@@ -5020,10 +5019,10 @@ getObjectIdentityParts(const ObjectAddress *object,
domain.objectId = con->contypid;
domain.objectSubId = 0;
- appendStringInfo(&buffer, "%s on %s",
- quote_identifier(NameStr(con->conname)),
- getObjectIdentityParts(&domain, objname,
- objargs, false));
+ appendStringInfoIdentifier(&buffer, NULL, NameStr(con->conname), " on ");
+ appendStringInfoString(&buffer,
+ getObjectIdentityParts(&domain, objname,
+ objargs, false));
if (objname)
*objargs = lappend(*objargs, pstrdup(NameStr(con->conname)));
@@ -5096,8 +5095,8 @@ getObjectIdentityParts(const ObjectAddress *object,
break;
}
langForm = (Form_pg_language) GETSTRUCT(langTup);
- appendStringInfoString(&buffer,
- quote_identifier(NameStr(langForm->lanname)));
+ appendStringInfoIdentifier(&buffer, NULL,
+ NameStr(langForm->lanname), NULL);
if (objname)
*objname = list_make1(pstrdup(NameStr(langForm->lanname)));
ReleaseSysCache(langTup);
@@ -5155,10 +5154,11 @@ getObjectIdentityParts(const ObjectAddress *object,
opcForm->opcmethod);
amForm = (Form_pg_am) GETSTRUCT(amTup);
- appendStringInfo(&buffer, "%s USING %s",
- quote_qualified_identifier(schema,
- NameStr(opcForm->opcname)),
- quote_identifier(NameStr(amForm->amname)));
+ appendStringInfoQualifiedIdentifier(&buffer, NULL,
+ schema, NameStr(opcForm->opcname),
+ " USING ");
+ appendStringInfoIdentifier(&buffer, NULL,
+ NameStr(amForm->amname), NULL);
if (objname)
*objname = list_make3(pstrdup(NameStr(amForm->amname)),
schema,
@@ -5186,7 +5186,7 @@ getObjectIdentityParts(const ObjectAddress *object,
object->objectId);
break;
}
- appendStringInfoString(&buffer, quote_identifier(amname));
+ appendStringInfoIdentifier(&buffer, NULL, amname, NULL);
if (objname)
*objname = list_make1(amname);
}
@@ -5339,8 +5339,7 @@ getObjectIdentityParts(const ObjectAddress *object,
rule = (Form_pg_rewrite) GETSTRUCT(tup);
- appendStringInfo(&buffer, "%s on ",
- quote_identifier(NameStr(rule->rulename)));
+ appendStringInfoIdentifier(&buffer, NULL, NameStr(rule->rulename), " on ");
getRelationIdentity(&buffer, rule->ev_class, objname, false);
if (objname)
*objname = lappend(*objname, pstrdup(NameStr(rule->rulename)));
@@ -5372,8 +5371,7 @@ getObjectIdentityParts(const ObjectAddress *object,
trig = (Form_pg_trigger) GETSTRUCT(tup);
- appendStringInfo(&buffer, "%s on ",
- quote_identifier(NameStr(trig->tgname)));
+ appendStringInfoIdentifier(&buffer, NULL, NameStr(trig->tgname), " on ");
getRelationIdentity(&buffer, trig->tgrelid, objname, false);
if (objname)
*objname = lappend(*objname, pstrdup(NameStr(trig->tgname)));
@@ -5544,8 +5542,7 @@ getObjectIdentityParts(const ObjectAddress *object,
break;
if (objname)
*objname = list_make1(username);
- appendStringInfoString(&buffer,
- quote_identifier(username));
+ appendStringInfoIdentifier(&buffer, NULL, username, NULL);
break;
}
@@ -5606,8 +5603,7 @@ getObjectIdentityParts(const ObjectAddress *object,
}
if (objname)
*objname = list_make1(datname);
- appendStringInfoString(&buffer,
- quote_identifier(datname));
+ appendStringInfoIdentifier(&buffer, NULL, datname, NULL);
break;
}
@@ -5625,8 +5621,7 @@ getObjectIdentityParts(const ObjectAddress *object,
}
if (objname)
*objname = list_make1(tblspace);
- appendStringInfoString(&buffer,
- quote_identifier(tblspace));
+ appendStringInfoIdentifier(&buffer, NULL, tblspace, NULL);
break;
}
@@ -5638,7 +5633,7 @@ getObjectIdentityParts(const ObjectAddress *object,
missing_ok);
if (fdw)
{
- appendStringInfoString(&buffer, quote_identifier(fdw->fdwname));
+ appendStringInfoIdentifier(&buffer, NULL, fdw->fdwname, NULL);
if (objname)
*objname = list_make1(pstrdup(fdw->fdwname));
}
@@ -5653,8 +5648,7 @@ getObjectIdentityParts(const ObjectAddress *object,
missing_ok);
if (srv)
{
- appendStringInfoString(&buffer,
- quote_identifier(srv->servername));
+ appendStringInfoIdentifier(&buffer, NULL, srv->servername, NULL);
if (objname)
*objname = list_make1(pstrdup(srv->servername));
}
@@ -5695,9 +5689,8 @@ getObjectIdentityParts(const ObjectAddress *object,
*objargs = list_make1(pstrdup(srv->servername));
}
- appendStringInfo(&buffer, "%s on server %s",
- quote_identifier(usename),
- srv->servername);
+ appendStringInfoIdentifier(&buffer, NULL, usename, " on server ");
+ appendStringInfoString(&buffer, srv->servername);
break;
}
@@ -5800,7 +5793,7 @@ getObjectIdentityParts(const ObjectAddress *object,
object->objectId);
break;
}
- appendStringInfoString(&buffer, quote_identifier(extname));
+ appendStringInfoIdentifier(&buffer, NULL, extname, NULL);
if (objname)
*objname = list_make1(extname);
break;
@@ -5823,7 +5816,7 @@ getObjectIdentityParts(const ObjectAddress *object,
}
trigForm = (Form_pg_event_trigger) GETSTRUCT(tup);
evtname = pstrdup(NameStr(trigForm->evtname));
- appendStringInfoString(&buffer, quote_identifier(evtname));
+ appendStringInfoIdentifier(&buffer, NULL, evtname, NULL);
if (objname)
*objname = list_make1(evtname);
ReleaseSysCache(tup);
@@ -5878,8 +5871,7 @@ getObjectIdentityParts(const ObjectAddress *object,
policy = (Form_pg_policy) GETSTRUCT(tup);
- appendStringInfo(&buffer, "%s on ",
- quote_identifier(NameStr(policy->polname)));
+ appendStringInfoIdentifier(&buffer, NULL, NameStr(policy->polname), " on ");
getRelationIdentity(&buffer, policy->polrelid, objname, false);
if (objname)
*objname = lappend(*objname, pstrdup(NameStr(policy->polname)));
@@ -5895,8 +5887,7 @@ getObjectIdentityParts(const ObjectAddress *object,
pubname = get_publication_name(object->objectId, missing_ok);
if (pubname)
{
- appendStringInfoString(&buffer,
- quote_identifier(pubname));
+ appendStringInfoIdentifier(&buffer, NULL, pubname, NULL);
if (objname)
*objname = list_make1(pubname);
}
@@ -5963,8 +5954,7 @@ getObjectIdentityParts(const ObjectAddress *object,
subname = get_subscription_name(object->objectId, missing_ok);
if (subname)
{
- appendStringInfoString(&buffer,
- quote_identifier(subname));
+ appendStringInfoIdentifier(&buffer, NULL, subname, NULL);
if (objname)
*objname = list_make1(subname);
}
diff --git a/src/backend/utils/adt/ri_triggers.c b/src/backend/utils/adt/ri_triggers.c
index d676930aca2..5b1c6547519 100644
--- a/src/backend/utils/adt/ri_triggers.c
+++ b/src/backend/utils/adt/ri_triggers.c
@@ -825,9 +825,11 @@ ri_restrict(TriggerData *trigdata, bool is_no_action)
/* Find the remaining history */
initStringInfo(&replacementsbuf);
- appendStringInfoString(&replacementsbuf, "(SELECT pg_catalog.range_agg(r) FROM ");
- appendStringInfoIdentifier(&replacementsbuf, "(SELECT y.", RIAttName(pk_rel, riinfo->pk_attnums[riinfo->nkeys - 1]), " r FROM ");
+ appendStringInfoIdentifier(&replacementsbuf,
+ "(SELECT pg_catalog.range_agg(r) FROM (SELECT y.",
+ RIAttName(pk_rel, riinfo->pk_attnums[riinfo->nkeys - 1]),
+ " r FROM ");
appendRelationName(&replacementsbuf, pk_rel, pk_only, " y");
/* Restrict pk rows to what matches */
@@ -1821,8 +1823,6 @@ RI_PartitionRemove_Check(Trigger *trigger, Relation fk_rel, Relation pk_rel)
appendRelationName(&querybuf, fk_rel, fk_only, " fk JOIN ");
appendRelationName(&querybuf, pk_rel, NULL, " pk ON");
- /* strcpy(pkattname, "pk."); */
- /* strcpy(fkattname, "fk."); */
sep = "(";
for (i = 0; i < riinfo->nkeys; i++)
{
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index b212a28d9be..a83cac7f03a 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -979,18 +979,17 @@ pg_get_triggerdef_worker(Oid trigid, bool pretty)
/* tgattr is first var-width field, so OK to access directly */
if (trigrec->tgattr.dim1 > 0)
{
- int i;
+ const char *sep = "";
appendStringInfoString(&buf, " OF ");
- for (i = 0; i < trigrec->tgattr.dim1; i++)
+ for (int i = 0; i < trigrec->tgattr.dim1; i++)
{
char *attname;
- if (i > 0)
- appendStringInfoString(&buf, ", ");
attname = get_attname(trigrec->tgrelid,
trigrec->tgattr.values[i], false);
- appendStringInfoString(&buf, quote_identifier(attname));
+ appendStringInfoIdentifier(&buf, sep, attname, NULL);
+ sep = ", ";
}
}
}
@@ -1042,11 +1041,9 @@ pg_get_triggerdef_worker(Oid trigid, bool pretty)
{
appendStringInfoString(&buf, "REFERENCING ");
if (tgoldtable != NULL)
- appendStringInfo(&buf, "OLD TABLE AS %s ",
- quote_identifier(tgoldtable));
+ appendStringInfoIdentifier(&buf, "OLD TABLE AS ", tgoldtable, " ");
if (tgnewtable != NULL)
- appendStringInfo(&buf, "NEW TABLE AS %s ",
- quote_identifier(tgnewtable));
+ appendStringInfoIdentifier(&buf, "NEW TABLE AS ", tgnewtable, " ");
}
if (TRIGGER_FOR_ROW(trigrec->tgtype))
@@ -1387,8 +1384,7 @@ pg_get_indexdef_worker(Oid indexrelid, int colno,
generate_qualified_relation_name(indrelid),
quote_identifier(NameStr(amrec->amname)));
else /* currently, must be EXCLUDE constraint */
- appendStringInfo(&buf, "EXCLUDE USING %s (",
- quote_identifier(NameStr(amrec->amname)));
+ appendStringInfoIdentifier(&buf, "EXCLUDE USING ", NameStr(amrec->amname), " (");
}
/*
@@ -1426,7 +1422,7 @@ pg_get_indexdef_worker(Oid indexrelid, int colno,
attname = get_attname(indrelid, attnum, false);
if (!colno || colno == keyno + 1)
- appendStringInfoString(&buf, quote_identifier(attname));
+ appendStringInfoIdentifier(&buf, NULL, attname, NULL);
get_atttypetypmodcoll(indrelid, attnum,
&keycoltype, &keycoltypmod,
&keycolcollation);
@@ -1536,8 +1532,8 @@ pg_get_indexdef_worker(Oid indexrelid, int colno,
{
if (isConstraint)
appendStringInfoString(&buf, " USING INDEX");
- appendStringInfo(&buf, " TABLESPACE %s",
- quote_identifier(get_tablespace_name(tblspc)));
+ appendStringInfoIdentifier(&buf, " TABLESPACE ",
+ get_tablespace_name(tblspc), NULL);
}
}
@@ -1794,7 +1790,7 @@ pg_get_statisticsobj_worker(Oid statextid, bool columns_only, bool missing_ok)
attname = get_attname(statextrec->stxrelid, attnum, false);
- appendStringInfoString(&buf, quote_identifier(attname));
+ appendStringInfoIdentifier(&buf, NULL, attname, NULL);
}
context = deparse_context_for(get_relation_name(statextrec->stxrelid),
@@ -2038,7 +2034,7 @@ pg_get_partkeydef_worker(Oid relid, int prettyFlags,
int32 keycoltypmod;
attname = get_attname(relid, attnum, false);
- appendStringInfoString(&buf, quote_identifier(attname));
+ appendStringInfoIdentifier(&buf, NULL, attname, NULL);
get_atttypetypmodcoll(relid, attnum,
&keycoltype, &keycoltypmod,
&keycolcollation);
@@ -2246,17 +2242,19 @@ pg_get_constraintdef_worker(Oid constraintId, bool fullCommand,
* we might need to let callers specify whether to put ONLY in the
* command.
*/
- appendStringInfo(&buf, "ALTER TABLE %s ADD CONSTRAINT %s ",
- generate_qualified_relation_name(conForm->conrelid),
- quote_identifier(NameStr(conForm->conname)));
+ appendStringInfo(&buf, "ALTER TABLE %s ",
+ generate_qualified_relation_name(conForm->conrelid));
+ appendStringInfoIdentifier(&buf, "ADD CONSTRAINT ",
+ NameStr(conForm->conname), " ");
}
else
{
/* Must be a domain constraint */
Assert(OidIsValid(conForm->contypid));
- appendStringInfo(&buf, "ALTER DOMAIN %s ADD CONSTRAINT %s ",
- generate_qualified_type_name(conForm->contypid),
- quote_identifier(NameStr(conForm->conname)));
+ appendStringInfo(&buf, "ALTER DOMAIN %s ",
+ generate_qualified_type_name(conForm->contypid));
+ appendStringInfoIdentifier(&buf, "ADD CONSTRAINT ",
+ NameStr(conForm->conname), " ");
}
}
@@ -2423,6 +2421,7 @@ pg_get_constraintdef_worker(Oid constraintId, bool fullCommand,
Datum *keys;
int nKeys;
int j;
+ const char *sep = "";
appendStringInfoString(&buf, " INCLUDE (");
@@ -2438,9 +2437,8 @@ pg_get_constraintdef_worker(Oid constraintId, bool fullCommand,
colName = get_attname(conForm->conrelid,
DatumGetInt16(keys[j]), false);
- if (j > keyatts)
- appendStringInfoString(&buf, ", ");
- appendStringInfoString(&buf, quote_identifier(colName));
+ appendStringInfoIdentifier(&buf, sep, colName, NULL);
+ sep = ", ";
}
appendStringInfoChar(&buf, ')');
@@ -2467,8 +2465,8 @@ pg_get_constraintdef_worker(Oid constraintId, bool fullCommand,
*/
tblspc = get_rel_tablespace(indexId);
if (OidIsValid(tblspc))
- appendStringInfo(&buf, " USING INDEX TABLESPACE %s",
- quote_identifier(get_tablespace_name(tblspc)));
+ appendStringInfoIdentifier(&buf, " USING INDEX TABLESPACE ",
+ get_tablespace_name(tblspc), NULL);
}
break;
@@ -2529,9 +2527,9 @@ pg_get_constraintdef_worker(Oid constraintId, bool fullCommand,
attnum = extractNotNullColumn(tup);
- appendStringInfo(&buf, "NOT NULL %s",
- quote_identifier(get_attname(conForm->conrelid,
- attnum, false)));
+ appendStringInfoIdentifier(&buf, "NOT NULL ",
+ get_attname(conForm->conrelid,
+ attnum, false), NULL);
if (((Form_pg_constraint) GETSTRUCT(tup))->connoinherit)
appendStringInfoString(&buf, " NO INHERIT");
}
@@ -2635,11 +2633,14 @@ decompile_column_index_array(Datum column_index_array, Oid relId,
colName = get_attname(relId, DatumGetInt16(keys[j]), false);
if (j == 0)
- appendStringInfoString(buf, quote_identifier(colName));
+ appendStringInfoIdentifier(buf, NULL, colName, NULL);
else
- appendStringInfo(buf, ", %s%s",
- (withPeriod && j == nKeys - 1) ? "PERIOD " : "",
- quote_identifier(colName));
+ {
+ appendStringInfoString(buf, ", ");
+ appendStringInfoIdentifier(buf,
+ (withPeriod && j == nKeys - 1) ? "PERIOD " : "",
+ colName, NULL);
+ }
}
return nKeys;
@@ -2975,8 +2976,8 @@ pg_get_functiondef(PG_FUNCTION_ARGS)
print_function_trftypes(&buf, proctup);
- appendStringInfo(&buf, " LANGUAGE %s\n",
- quote_identifier(get_language_name(proc->prolang, false)));
+ appendStringInfoIdentifier(&buf, " LANGUAGE ",
+ get_language_name(proc->prolang, false), "\n");
/* Emit some miscellaneous options on one line */
oldlen = buf.len;
@@ -3075,8 +3076,7 @@ pg_get_functiondef(PG_FUNCTION_ARGS)
continue;
*pos++ = '\0';
- appendStringInfo(&buf, " SET %s TO ",
- quote_identifier(configitem));
+ appendStringInfoIdentifier(&buf, " SET ", configitem, " TO ");
/*
* Variables that are marked GUC_LIST_QUOTE were already fully
@@ -3418,7 +3418,7 @@ print_function_arguments(StringInfo buf, HeapTuple proctup,
appendStringInfoString(buf, modename);
if (argname && argname[0])
- appendStringInfo(buf, "%s ", quote_identifier(argname));
+ appendStringInfoIdentifier(buf, NULL, argname, " ");
appendStringInfoString(buf, format_type_be(argtype));
if (print_defaults && isinput && inputargno > nlackdefaults)
{
@@ -5402,8 +5402,7 @@ make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc,
/*
* Build the rules definition text
*/
- appendStringInfo(buf, "CREATE RULE %s AS",
- quote_identifier(rulename));
+ appendStringInfoIdentifier(buf, "CREATE RULE ", rulename, " AS");
if (prettyFlags & PRETTYFLAG_INDENT)
appendStringInfoString(buf, "\n ON ");
@@ -5791,21 +5790,18 @@ get_with_clause(Query *query, deparse_context *context)
CommonTableExpr *cte = (CommonTableExpr *) lfirst(l);
appendStringInfoString(buf, sep);
- appendStringInfoString(buf, quote_identifier(cte->ctename));
+ appendStringInfoIdentifier(buf, NULL, cte->ctename, NULL);
if (cte->aliascolnames)
{
- bool first = true;
ListCell *col;
+ const char *colsep = "";
appendStringInfoChar(buf, '(');
foreach(col, cte->aliascolnames)
{
- if (first)
- first = false;
- else
- appendStringInfoString(buf, ", ");
- appendStringInfoString(buf,
- quote_identifier(strVal(lfirst(col))));
+ appendStringInfoIdentifier(buf, colsep,
+ strVal(lfirst(col)), NULL);
+ colsep = ", ";
}
appendStringInfoChar(buf, ')');
}
@@ -5834,43 +5830,35 @@ get_with_clause(Query *query, deparse_context *context)
if (cte->search_clause)
{
- bool first = true;
ListCell *lc;
+ const char *colsep = "";
appendStringInfo(buf, " SEARCH %s FIRST BY ",
cte->search_clause->search_breadth_first ? "BREADTH" : "DEPTH");
foreach(lc, cte->search_clause->search_col_list)
{
- if (first)
- first = false;
- else
- appendStringInfoString(buf, ", ");
- appendStringInfoString(buf,
- quote_identifier(strVal(lfirst(lc))));
+ appendStringInfoIdentifier(buf, colsep, strVal(lfirst(lc)), NULL);
+ colsep = ", ";
}
- appendStringInfo(buf, " SET %s", quote_identifier(cte->search_clause->search_seq_column));
+ appendStringInfoIdentifier(buf, " SET ", cte->search_clause->search_seq_column, NULL);
}
if (cte->cycle_clause)
{
- bool first = true;
ListCell *lc;
+ const char *sep = "";
appendStringInfoString(buf, " CYCLE ");
foreach(lc, cte->cycle_clause->cycle_col_list)
{
- if (first)
- first = false;
- else
- appendStringInfoString(buf, ", ");
- appendStringInfoString(buf,
- quote_identifier(strVal(lfirst(lc))));
+ appendStringInfoIdentifier(buf, sep, strVal(lfirst(lc)), NULL);
+ sep = ", ";
}
- appendStringInfo(buf, " SET %s", quote_identifier(cte->cycle_clause->cycle_mark_column));
+ appendStringInfoIdentifier(buf, " SET ", cte->cycle_clause->cycle_mark_column, NULL);
{
Const *cmv = castNode(Const, cte->cycle_clause->cycle_mark_value);
@@ -5886,7 +5874,7 @@ get_with_clause(Query *query, deparse_context *context)
}
}
- appendStringInfo(buf, " USING %s", quote_identifier(cte->cycle_clause->cycle_path_column));
+ appendStringInfoIdentifier(buf, " USING ", cte->cycle_clause->cycle_path_column, NULL);
}
sep = ", ";
@@ -6022,9 +6010,7 @@ get_select_query_def(Query *query, deparse_context *context)
break;
}
- appendStringInfo(buf, " OF %s",
- quote_identifier(get_rtable_name(rc->rti,
- context)));
+ appendStringInfoIdentifier(buf, " OF ", get_rtable_name(rc->rti, context), NULL);
if (rc->waitPolicy == LockWaitError)
appendStringInfoString(buf, " NOWAIT");
else if (rc->waitPolicy == LockWaitSkip)
@@ -6317,7 +6303,7 @@ get_target_list(List *targetList, deparse_context *context)
if (colname) /* resname could be NULL */
{
if (attname == NULL || strcmp(attname, colname) != 0)
- appendStringInfo(&targetbuf, " AS %s", quote_identifier(colname));
+ appendStringInfoIdentifier(&targetbuf, " AS ", colname, NULL);
}
/* Restore context's output buffer */
@@ -6391,19 +6377,16 @@ get_returning_clause(Query *query, deparse_context *context)
/* Add WITH (OLD/NEW) options, if they're not the defaults */
if (query->returningOldAlias && strcmp(query->returningOldAlias, "old") != 0)
{
- appendStringInfo(buf, " WITH (OLD AS %s",
- quote_identifier(query->returningOldAlias));
+ appendStringInfoIdentifier(buf, " WITH (OLD AS ", query->returningOldAlias, NULL);
have_with = true;
}
if (query->returningNewAlias && strcmp(query->returningNewAlias, "new") != 0)
{
if (have_with)
- appendStringInfo(buf, ", NEW AS %s",
- quote_identifier(query->returningNewAlias));
+ appendStringInfoIdentifier(buf, ", NEW AS ", query->returningNewAlias, NULL);
else
{
- appendStringInfo(buf, " WITH (NEW AS %s",
- quote_identifier(query->returningNewAlias));
+ appendStringInfoIdentifier(buf, " WITH (NEW AS ", query->returningNewAlias, NULL);
have_with = true;
}
}
@@ -6771,7 +6754,7 @@ get_rule_windowclause(Query *query, deparse_context *context)
else
appendStringInfoString(buf, sep);
- appendStringInfo(buf, "%s AS ", quote_identifier(wc->name));
+ appendStringInfoIdentifier(buf, NULL, wc->name, " AS ");
get_rule_windowspec(wc, query->targetList, context);
@@ -6794,7 +6777,7 @@ get_rule_windowspec(WindowClause *wc, List *targetList,
appendStringInfoChar(buf, '(');
if (wc->refname)
{
- appendStringInfoString(buf, quote_identifier(wc->refname));
+ appendStringInfoIdentifier(buf, NULL, wc->refname, NULL);
needspace = true;
}
/* partition clauses are always inherited, so only print if no refname */
@@ -7021,10 +7004,8 @@ get_insert_query_def(Query *query, deparse_context *context)
* Put out name of target column; look in the catalogs, not at
* tle->resname, since resname will fail to track RENAME.
*/
- appendStringInfoString(buf,
- quote_identifier(get_attname(rte->relid,
- tle->resno,
- false)));
+ appendStringInfoIdentifier(buf, NULL,
+ get_attname(rte->relid, tle->resno, false), NULL);
/*
* Print any indirection needed (subfields or subscripts), and strip
@@ -7117,8 +7098,7 @@ get_insert_query_def(Query *query, deparse_context *context)
if (!constraint)
elog(ERROR, "cache lookup failed for constraint %u",
confl->constraint);
- appendStringInfo(buf, " ON CONSTRAINT %s",
- quote_identifier(constraint));
+ appendStringInfoIdentifier(buf, " ON CONSTRAINT ", constraint, NULL);
}
if (confl->action == ONCONFLICT_NOTHING)
@@ -7320,10 +7300,7 @@ get_update_query_targetlist_def(Query *query, List *targetList,
* Put out name of target column; look in the catalogs, not at
* tle->resname, since resname will fail to track RENAME.
*/
- appendStringInfoString(buf,
- quote_identifier(get_attname(rte->relid,
- tle->resno,
- false)));
+ appendStringInfoIdentifier(buf, NULL, get_attname(rte->relid, tle->resno, false), NULL);
/*
* Print any indirection needed (subfields or subscripts), and strip
@@ -7511,10 +7488,10 @@ get_merge_query_def(Query *query, deparse_context *context)
appendStringInfoString(buf, sep);
sep = ", ";
- appendStringInfoString(buf,
- quote_identifier(get_attname(rte->relid,
- tle->resno,
- false)));
+ appendStringInfoIdentifier(buf, NULL,
+ get_attname(rte->relid,
+ tle->resno,
+ false), NULL);
strippedexprs = lappend(strippedexprs,
processIndirection((Node *) tle->expr,
context));
@@ -7573,8 +7550,8 @@ get_utility_query_def(Query *query, deparse_context *context)
appendContextKeyword(context, "",
0, PRETTYINDENT_STD, 1);
- appendStringInfo(buf, "NOTIFY %s",
- quote_identifier(stmt->conditionname));
+ appendStringInfoIdentifier(buf, "NOTIFY ",
+ stmt->conditionname, NULL);
if (stmt->payload)
{
appendStringInfoString(buf, ", ");
@@ -7865,11 +7842,11 @@ get_variable(Var *var, int levelsup, bool istoplevel, deparse_context *context)
if (refname && need_prefix)
{
- appendStringInfoString(buf, quote_identifier(refname));
+ appendStringInfoIdentifier(buf, NULL, refname, NULL);
appendStringInfoChar(buf, '.');
}
if (attname)
- appendStringInfoString(buf, quote_identifier(attname));
+ appendStringInfoIdentifier(buf, NULL, attname, NULL);
else
{
appendStringInfoChar(buf, '*');
@@ -8806,11 +8783,10 @@ get_parameter(Param *param, deparse_context *context)
}
if (should_qualify)
{
- appendStringInfoString(context->buf, quote_identifier(dpns->funcname));
- appendStringInfoChar(context->buf, '.');
+ appendStringInfoIdentifier(context->buf, NULL, dpns->funcname, ".");
}
- appendStringInfoString(context->buf, quote_identifier(argname));
+ appendStringInfoIdentifier(context->buf, NULL, argname, NULL);
return;
}
}
@@ -9391,7 +9367,7 @@ get_rule_expr(Node *node, deparse_context *context,
{
NamedArgExpr *na = (NamedArgExpr *) node;
- appendStringInfo(buf, "%s => ", quote_identifier(na->name));
+ appendStringInfoIdentifier(buf, NULL, na->name, " => ");
get_rule_expr((Node *) na->arg, context, showimplicit);
}
break;
@@ -9679,7 +9655,7 @@ get_rule_expr(Node *node, deparse_context *context,
*/
fieldname = get_name_for_var_field((Var *) arg, fno,
0, context);
- appendStringInfo(buf, ".%s", quote_identifier(fieldname));
+ appendStringInfoIdentifier(buf, ".", fieldname, NULL);
}
break;
@@ -10131,8 +10107,8 @@ get_rule_expr(Node *node, deparse_context *context,
}
if (xexpr->name)
{
- appendStringInfo(buf, "NAME %s",
- quote_identifier(map_xml_name_to_sql_identifier(xexpr->name)));
+ appendStringInfoIdentifier(buf, "NAME ",
+ map_xml_name_to_sql_identifier(xexpr->name), NULL);
needcomma = true;
}
if (xexpr->named_args)
@@ -10152,8 +10128,8 @@ get_rule_expr(Node *node, deparse_context *context,
if (needcomma)
appendStringInfoString(buf, ", ");
get_rule_expr((Node *) e, context, true);
- appendStringInfo(buf, " AS %s",
- quote_identifier(map_xml_name_to_sql_identifier(argname)));
+ appendStringInfoIdentifier(buf, " AS ",
+ map_xml_name_to_sql_identifier(argname), NULL);
needcomma = true;
}
if (xexpr->op != IS_XMLFOREST)
@@ -10369,8 +10345,8 @@ get_rule_expr(Node *node, deparse_context *context,
CurrentOfExpr *cexpr = (CurrentOfExpr *) node;
if (cexpr->cursor_name)
- appendStringInfo(buf, "CURRENT OF %s",
- quote_identifier(cexpr->cursor_name));
+ appendStringInfoIdentifier(buf, "CURRENT OF ",
+ cexpr->cursor_name, NULL);
else
appendStringInfo(buf, "CURRENT OF $%d",
cexpr->cursor_param);
@@ -10604,8 +10580,8 @@ get_rule_expr(Node *node, deparse_context *context,
needcomma = true;
get_rule_expr((Node *) lfirst(lc2), context, showimplicit);
- appendStringInfo(buf, " AS %s",
- quote_identifier(lfirst_node(String, lc1)->sval));
+ appendStringInfoIdentifier(buf, " AS ",
+ lfirst_node(String, lc1)->sval, NULL);
}
}
@@ -11135,7 +11111,7 @@ get_windowfunc_expr_helper(WindowFunc *wfunc, deparse_context *context,
if (wc->winref == wfunc->winref)
{
if (wc->name)
- appendStringInfoString(buf, quote_identifier(wc->name));
+ appendStringInfoIdentifier(buf, NULL, wc->name, NULL);
else
get_rule_windowspec(wc, context->targetList, context);
break;
@@ -11161,7 +11137,7 @@ get_windowfunc_expr_helper(WindowFunc *wfunc, deparse_context *context,
if (wagg->winref == wfunc->winref)
{
- appendStringInfoString(buf, quote_identifier(wagg->winname));
+ appendStringInfoIdentifier(buf, NULL, wagg->winname, NULL);
break;
}
}
@@ -12001,8 +11977,8 @@ get_xmltable(TableFunc *tf, deparse_context *context, bool showimplicit)
if (ns_node != NULL)
{
get_rule_expr(expr, context, showimplicit);
- appendStringInfo(buf, " AS %s",
- quote_identifier(strVal(ns_node)));
+ appendStringInfoIdentifier(buf, " AS ",
+ strVal(ns_node), NULL);
}
else
{
@@ -12088,7 +12064,7 @@ get_json_table_nested_columns(TableFunc *tf, JsonTablePlan *plan,
appendStringInfoChar(context->buf, ' ');
appendContextKeyword(context, "NESTED PATH ", 0, 0, 0);
get_const_expr(scan->path->value, context, -1);
- appendStringInfo(context->buf, " AS %s", quote_identifier(scan->path->name));
+ appendStringInfoIdentifier(context->buf, " AS ", scan->path->name, NULL);
get_json_table_columns(tf, scan, context, showimplicit);
}
else if (IsA(plan, JsonTableSiblingJoin))
@@ -12231,7 +12207,7 @@ get_json_table(TableFunc *tf, deparse_context *context, bool showimplicit)
get_const_expr(root->path->value, context, -1);
- appendStringInfo(buf, " AS %s", quote_identifier(root->path->name));
+ appendStringInfoIdentifier(buf, " AS ", root->path->name, NULL);
if (jexpr->passing_values)
{
@@ -12255,9 +12231,7 @@ get_json_table(TableFunc *tf, deparse_context *context, bool showimplicit)
appendContextKeyword(context, "", 0, 0, 0);
get_rule_expr((Node *) lfirst(lc2), context, false);
- appendStringInfo(buf, " AS %s",
- quote_identifier((lfirst_node(String, lc1))->sval)
- );
+ appendStringInfoIdentifier(buf, " AS ", lfirst_node(String, lc1)->sval, NULL);
}
if (PRETTY_INDENT(context))
@@ -12533,7 +12507,7 @@ get_from_clause_item(Node *jtnode, Query *query, deparse_context *context)
appendStringInfoChar(buf, ')');
break;
case RTE_CTE:
- appendStringInfoString(buf, quote_identifier(rte->ctename));
+ appendStringInfoIdentifier(buf, NULL, rte->ctename, NULL);
break;
default:
elog(ERROR, "unrecognized RTE kind: %d", (int) rte->rtekind);
@@ -12620,7 +12594,7 @@ get_from_clause_item(Node *jtnode, Query *query, deparse_context *context)
if (j->usingClause)
{
ListCell *lc;
- bool first = true;
+ const char *sep = "";
appendStringInfoString(buf, " USING (");
/* Use the assigned names, not what's in usingClause */
@@ -12628,17 +12602,13 @@ get_from_clause_item(Node *jtnode, Query *query, deparse_context *context)
{
char *colname = (char *) lfirst(lc);
- if (first)
- first = false;
- else
- appendStringInfoString(buf, ", ");
- appendStringInfoString(buf, quote_identifier(colname));
+ appendStringInfoIdentifier(buf, sep, colname, NULL);
+ sep = ", ";
}
appendStringInfoChar(buf, ')');
if (j->join_using_alias)
- appendStringInfo(buf, " AS %s",
- quote_identifier(j->join_using_alias->aliasname));
+ appendStringInfoIdentifier(buf, " AS ", j->join_using_alias->aliasname, NULL);
}
else if (j->quals)
{
@@ -12668,9 +12638,9 @@ get_from_clause_item(Node *jtnode, Query *query, deparse_context *context)
* subtleties we don't want. However, we might print a different
* alias name than was there originally.
*/
- appendStringInfo(buf, " %s",
- quote_identifier(get_rtable_name(j->rtindex,
- context)));
+ appendStringInfoIdentifier(buf, " ",
+ get_rtable_name(j->rtindex,
+ context), NULL);
get_column_alias_list(colinfo, context);
}
}
@@ -12745,9 +12715,9 @@ get_rte_alias(RangeTblEntry *rte, int varno, bool use_as,
}
if (printalias)
- appendStringInfo(context->buf, "%s%s",
- use_as ? " AS " : " ",
- quote_identifier(refname));
+ appendStringInfoIdentifier(context->buf,
+ use_as ? " AS " : " ",
+ refname, NULL);
}
/*
@@ -12777,7 +12747,7 @@ get_column_alias_list(deparse_columns *colinfo, deparse_context *context)
}
else
appendStringInfoString(buf, ", ");
- appendStringInfoString(buf, quote_identifier(colname));
+ appendStringInfoIdentifier(buf, NULL, colname, NULL);
}
if (!first)
appendStringInfoChar(buf, ')');
@@ -12910,13 +12880,11 @@ get_opclass_name(Oid opclass, Oid actual_datatype,
/* Okay, we need the opclass name. Do we need to qualify it? */
opcname = NameStr(opcrec->opcname);
if (OpclassIsVisible(opclass))
- appendStringInfo(buf, " %s", quote_identifier(opcname));
+ appendStringInfoIdentifier(buf, " ", opcname, NULL);
else
{
nspname = get_namespace_name_or_temp(opcrec->opcnamespace);
- appendStringInfo(buf, " %s.%s",
- quote_identifier(nspname),
- quote_identifier(opcname));
+ appendStringInfoQualifiedIdentifier(buf, NULL, nspname, opcname, NULL);
}
}
ReleaseSysCache(ht_opc);
@@ -12980,7 +12948,7 @@ processIndirection(Node *node, deparse_context *context)
Assert(list_length(fstore->fieldnums) == 1);
fieldname = get_attname(typrelid,
linitial_int(fstore->fieldnums), false);
- appendStringInfo(buf, ".%s", quote_identifier(fieldname));
+ appendStringInfoIdentifier(buf, ".", fieldname, NULL);
/*
* We ignore arg since it should be an uninteresting reference to
@@ -13535,7 +13503,7 @@ generate_operator_name(Oid operid, Oid arg1, Oid arg2)
else
{
nspname = get_namespace_name_or_temp(operform->oprnamespace);
- appendStringInfo(&buf, "OPERATOR(%s.", quote_identifier(nspname));
+ appendStringInfoIdentifier(&buf, "OPERATOR(", nspname, ".");
}
appendStringInfoString(&buf, oprname);
@@ -13641,8 +13609,7 @@ add_cast_to(StringInfo buf, Oid typid)
typname = NameStr(typform->typname);
nspname = get_namespace_name_or_temp(typform->typnamespace);
- appendStringInfo(buf, "::%s.%s",
- quote_identifier(nspname), quote_identifier(typname));
+ appendStringInfoQualifiedIdentifier(buf, "::", nspname, typname, NULL);
ReleaseSysCache(typetup);
}
@@ -13739,12 +13706,12 @@ get_reloptions(StringInfo buf, Datum reloptions)
{
Datum *options;
int noptions;
- int i;
+ const char *sep = "";
deconstruct_array_builtin(DatumGetArrayTypeP(reloptions), TEXTOID,
&options, NULL, &noptions);
- for (i = 0; i < noptions; i++)
+ for (int i = 0; i < noptions; i++)
{
char *option = TextDatumGetCString(options[i]);
char *name;
@@ -13765,9 +13732,8 @@ get_reloptions(StringInfo buf, Datum reloptions)
else
value = "";
- if (i > 0)
- appendStringInfoString(buf, ", ");
- appendStringInfo(buf, "%s=", quote_identifier(name));
+ appendStringInfoIdentifier(buf, sep, name, "=");
+ sep = ", ";
/*
* In general we need to quote the value; but to avoid unnecessary
--
2.39.5 (Apple Git-154)
[application/octet-stream] v2-0003-Remove-quoteOneName-and-related-buffer-sizing-mac.patch (11.5K, 5-v2-0003-Remove-quoteOneName-and-related-buffer-sizing-mac.patch)
download | inline diff:
From a26c32c5a2f9b538a2db266245790d29907b42c5 Mon Sep 17 00:00:00 2001
From: "Chao Li (Evan)" <[email protected]>
Date: Tue, 18 Nov 2025 17:13:07 +0800
Subject: [PATCH v2 3/4] Remove quoteOneName() and related buffer-sizing macros
from ri_triggers.c
After the previous refactoring, quoteOneName() and its callers are no longer
needed. Remove the function along with MAX_QUOTED_NAME_LEN,
MAX_QUOTED_REL_NAME_LEN, and quoteRelationName(), and introduce
appendRelationName() as the remaining helper for writing qualified relation
names using appendStringInfoQualifiedIdentifier().
This reduces redundant quoting code and centralizes identifier handling in
appendStringInfoIdentifier() / appendStringInfoQualifiedIdentifier(), making
RI triggers consistent with other code that generates SQL fragments.
No functional behavior change is expected.
Author: Chao Li <[email protected]>
Discussion: https://postgr.es/m/CAEoWx2=g2RVkxXB=JzWphgfg4QGV+spaA3PQ1rBM2iMehrVvjg@mail.gmail.com
---
src/backend/utils/adt/ri_triggers.c | 112 ++++++++--------------------
1 file changed, 30 insertions(+), 82 deletions(-)
diff --git a/src/backend/utils/adt/ri_triggers.c b/src/backend/utils/adt/ri_triggers.c
index 3cc4dc2b7c8..d676930aca2 100644
--- a/src/backend/utils/adt/ri_triggers.c
+++ b/src/backend/utils/adt/ri_triggers.c
@@ -80,9 +80,6 @@
#define RI_PLAN_SETDEFAULT_ONDELETE 9
#define RI_PLAN_SETDEFAULT_ONUPDATE 10
-#define MAX_QUOTED_NAME_LEN (NAMEDATALEN*2+3)
-#define MAX_QUOTED_REL_NAME_LEN (MAX_QUOTED_NAME_LEN*2)
-
#define RIAttName(rel, attnum) NameStr(*attnumAttName(rel, attnum))
#define RIAttType(rel, attnum) attnumTypeId(rel, attnum)
#define RIAttCollation(rel, attnum) attnumCollationId(rel, attnum)
@@ -192,8 +189,7 @@ static bool ri_Check_Pk_Match(Relation pk_rel, Relation fk_rel,
const RI_ConstraintInfo *riinfo);
static Datum ri_restrict(TriggerData *trigdata, bool is_no_action);
static Datum ri_set(TriggerData *trigdata, bool is_set_null, int tgkind);
-static void quoteOneName(char *buffer, const char *name);
-static void quoteRelationName(char *buffer, Relation rel);
+static void appendRelationName(StringInfo buffer, Relation rel, const char *prefix, const char *suffix);
static void ri_GenerateQual(StringInfo buf,
const char *sep,
const char *leftopprefix, const char *leftop, Oid leftoptype, bool quoteleftop,
@@ -357,7 +353,6 @@ RI_FKey_check(TriggerData *trigdata)
if ((qplan = ri_FetchPreparedPlan(&qkey)) == NULL)
{
StringInfoData querybuf;
- char pkrelname[MAX_QUOTED_REL_NAME_LEN];
const char *attname;
char paramname[16];
const char *querysep;
@@ -390,19 +385,16 @@ RI_FKey_check(TriggerData *trigdata)
initStringInfo(&querybuf);
pk_only = pk_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE ?
"" : "ONLY ";
- quoteRelationName(pkrelname, pk_rel);
if (riinfo->hasperiod)
{
attname = RIAttName(pk_rel, riinfo->pk_attnums[riinfo->nkeys - 1]);
appendStringInfoIdentifier(&querybuf, "SELECT 1 FROM (SELECT ", attname, " AS r FROM ");
- appendStringInfo(&querybuf,
- "%s%s x",
- pk_only, pkrelname);
+ appendRelationName(&querybuf, pk_rel, pk_only, " x");
}
else
{
- appendStringInfo(&querybuf, "SELECT 1 FROM %s%s x",
- pk_only, pkrelname);
+ appendStringInfoString(&querybuf, "SELECT 1 FROM ");
+ appendRelationName(&querybuf, pk_rel, pk_only, " x");
}
querysep = "WHERE";
for (int i = 0; i < riinfo->nkeys; i++)
@@ -526,7 +518,6 @@ ri_Check_Pk_Match(Relation pk_rel, Relation fk_rel,
if ((qplan = ri_FetchPreparedPlan(&qkey)) == NULL)
{
StringInfoData querybuf;
- char pkrelname[MAX_QUOTED_REL_NAME_LEN];
const char *attname;
char paramname[16];
const char *querysep;
@@ -559,19 +550,16 @@ ri_Check_Pk_Match(Relation pk_rel, Relation fk_rel,
initStringInfo(&querybuf);
pk_only = pk_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE ?
"" : "ONLY ";
- quoteRelationName(pkrelname, pk_rel);
if (riinfo->hasperiod)
{
attname = RIAttName(pk_rel, riinfo->pk_attnums[riinfo->nkeys - 1]);
appendStringInfoIdentifier(&querybuf, "SELECT 1 FROM (SELECT ", attname, " AS r FROM ");
- appendStringInfo(&querybuf,
- "%s%s x",
- pk_only, pkrelname);
+ appendRelationName(&querybuf, pk_rel, pk_only, " x");
}
else
{
- appendStringInfo(&querybuf, "SELECT 1 FROM %s%s x",
- pk_only, pkrelname);
+ appendStringInfoString(&querybuf, "SELECT 1 FROM ");
+ appendRelationName(&querybuf, pk_rel, pk_only, " x");
}
querysep = "WHERE";
for (int i = 0; i < riinfo->nkeys; i++)
@@ -753,10 +741,7 @@ ri_restrict(TriggerData *trigdata, bool is_no_action)
if ((qplan = ri_FetchPreparedPlan(&qkey)) == NULL)
{
StringInfoData querybuf;
- char pkrelname[MAX_QUOTED_REL_NAME_LEN];
- char fkrelname[MAX_QUOTED_REL_NAME_LEN];
const char *attname;
- char periodattname[MAX_QUOTED_NAME_LEN];
char paramname[16];
const char *querysep;
Oid queryoids[RI_MAX_NUMKEYS];
@@ -773,9 +758,8 @@ ri_restrict(TriggerData *trigdata, bool is_no_action)
initStringInfo(&querybuf);
fk_only = fk_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE ?
"" : "ONLY ";
- quoteRelationName(fkrelname, fk_rel);
- appendStringInfo(&querybuf, "SELECT 1 FROM %s%s x",
- fk_only, fkrelname);
+ appendStringInfoString(&querybuf, "SELECT 1 FROM ");
+ appendRelationName(&querybuf, fk_rel, fk_only, " x");
querysep = "WHERE";
for (int i = 0; i < riinfo->nkeys; i++)
{
@@ -843,10 +827,8 @@ ri_restrict(TriggerData *trigdata, bool is_no_action)
initStringInfo(&replacementsbuf);
appendStringInfoString(&replacementsbuf, "(SELECT pg_catalog.range_agg(r) FROM ");
- quoteOneName(periodattname, RIAttName(pk_rel, riinfo->pk_attnums[riinfo->nkeys - 1]));
- quoteRelationName(pkrelname, pk_rel);
- appendStringInfo(&replacementsbuf, "(SELECT y.%s r FROM %s%s y",
- periodattname, pk_only, pkrelname);
+ appendStringInfoIdentifier(&replacementsbuf, "(SELECT y.", RIAttName(pk_rel, riinfo->pk_attnums[riinfo->nkeys - 1]), " r FROM ");
+ appendRelationName(&replacementsbuf, pk_rel, pk_only, " y");
/* Restrict pk rows to what matches */
querysep = "WHERE";
@@ -939,7 +921,6 @@ RI_FKey_cascade_del(PG_FUNCTION_ARGS)
if ((qplan = ri_FetchPreparedPlan(&qkey)) == NULL)
{
StringInfoData querybuf;
- char fkrelname[MAX_QUOTED_REL_NAME_LEN];
const char *attname;
char paramname[16];
const char *querysep;
@@ -956,9 +937,8 @@ RI_FKey_cascade_del(PG_FUNCTION_ARGS)
initStringInfo(&querybuf);
fk_only = fk_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE ?
"" : "ONLY ";
- quoteRelationName(fkrelname, fk_rel);
- appendStringInfo(&querybuf, "DELETE FROM %s%s",
- fk_only, fkrelname);
+ appendStringInfoString(&querybuf, "DELETE FROM ");
+ appendRelationName(&querybuf, fk_rel, fk_only, NULL);
querysep = "WHERE";
for (int i = 0; i < riinfo->nkeys; i++)
{
@@ -1044,7 +1024,6 @@ RI_FKey_cascade_upd(PG_FUNCTION_ARGS)
{
StringInfoData querybuf;
StringInfoData qualbuf;
- char fkrelname[MAX_QUOTED_REL_NAME_LEN];
const char *attname;
char paramname[16];
const char *querysep;
@@ -1066,9 +1045,8 @@ RI_FKey_cascade_upd(PG_FUNCTION_ARGS)
initStringInfo(&qualbuf);
fk_only = fk_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE ?
"" : "ONLY ";
- quoteRelationName(fkrelname, fk_rel);
- appendStringInfo(&querybuf, "UPDATE %s%s SET",
- fk_only, fkrelname);
+ appendStringInfoString(&querybuf, "UPDATE ");
+ appendRelationName(&querybuf, fk_rel, fk_only, " SET");
querysep = "";
qualsep = "WHERE";
for (int i = 0, j = riinfo->nkeys; i < riinfo->nkeys; i++, j++)
@@ -1232,7 +1210,6 @@ ri_set(TriggerData *trigdata, bool is_set_null, int tgkind)
if ((qplan = ri_FetchPreparedPlan(&qkey)) == NULL)
{
StringInfoData querybuf;
- char fkrelname[MAX_QUOTED_REL_NAME_LEN];
const char *attname;
char paramname[16];
const char *querysep;
@@ -1281,9 +1258,8 @@ ri_set(TriggerData *trigdata, bool is_set_null, int tgkind)
initStringInfo(&querybuf);
fk_only = fk_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE ?
"" : "ONLY ";
- quoteRelationName(fkrelname, fk_rel);
- appendStringInfo(&querybuf, "UPDATE %s%s SET",
- fk_only, fkrelname);
+ appendStringInfo(&querybuf, "UPDATE ");
+ appendRelationName(&querybuf, fk_rel, fk_only, " SET");
/*
* Add assignment clauses
@@ -1509,8 +1485,6 @@ RI_Initial_Check(Trigger *trigger, Relation fk_rel, Relation pk_rel)
{
const RI_ConstraintInfo *riinfo;
StringInfoData querybuf;
- char pkrelname[MAX_QUOTED_REL_NAME_LEN];
- char fkrelname[MAX_QUOTED_REL_NAME_LEN];
const char *pkattname;
const char *fkattname;
RangeTblEntry *rte;
@@ -1613,15 +1587,13 @@ RI_Initial_Check(Trigger *trigger, Relation fk_rel, Relation pk_rel)
sep = ", ";
}
- quoteRelationName(pkrelname, pk_rel);
- quoteRelationName(fkrelname, fk_rel);
fk_only = fk_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE ?
"" : "ONLY ";
pk_only = pk_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE ?
"" : "ONLY ";
- appendStringInfo(&querybuf,
- " FROM %s%s fk LEFT OUTER JOIN %s%s pk ON",
- fk_only, fkrelname, pk_only, pkrelname);
+ appendStringInfoString(&querybuf, " FROM ");
+ appendRelationName(&querybuf, fk_rel, fk_only, " fk LEFT OUTER JOIN ");
+ appendRelationName(&querybuf, pk_rel, pk_only, " pk ON");
sep = "(";
for (int i = 0; i < riinfo->nkeys; i++)
@@ -1799,8 +1771,6 @@ RI_PartitionRemove_Check(Trigger *trigger, Relation fk_rel, Relation pk_rel)
const RI_ConstraintInfo *riinfo;
StringInfoData querybuf;
char *constraintDef;
- char pkrelname[MAX_QUOTED_REL_NAME_LEN];
- char fkrelname[MAX_QUOTED_REL_NAME_LEN];
const char *pkattname;
const char *fkattname;
const char *sep;
@@ -1845,13 +1815,12 @@ RI_PartitionRemove_Check(Trigger *trigger, Relation fk_rel, Relation pk_rel)
sep = ", ";
}
- quoteRelationName(pkrelname, pk_rel);
- quoteRelationName(fkrelname, fk_rel);
fk_only = fk_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE ?
"" : "ONLY ";
- appendStringInfo(&querybuf,
- " FROM %s%s fk JOIN %s pk ON",
- fk_only, fkrelname, pkrelname);
+ appendStringInfoString(&querybuf, " FROM ");
+ appendRelationName(&querybuf, fk_rel, fk_only, " fk JOIN ");
+ appendRelationName(&querybuf, pk_rel, NULL, " pk ON");
+
/* strcpy(pkattname, "pk."); */
/* strcpy(fkattname, "fk."); */
sep = "(";
@@ -2004,37 +1973,16 @@ RI_PartitionRemove_Check(Trigger *trigger, Relation fk_rel, Relation pk_rel)
/*
- * quoteOneName --- safely quote a single SQL name
- *
- * buffer must be MAX_QUOTED_NAME_LEN long (includes room for \0)
- */
-static void
-quoteOneName(char *buffer, const char *name)
-{
- /* Rather than trying to be smart, just always quote it. */
- *buffer++ = '"';
- while (*name)
- {
- if (*name == '"')
- *buffer++ = '"';
- *buffer++ = *name++;
- }
- *buffer++ = '"';
- *buffer = '\0';
-}
+ * appendRelationName --- safely append a quoted fully qualified relation name
-/*
- * quoteRelationName --- safely quote a fully qualified relation name
- *
- * buffer must be MAX_QUOTED_REL_NAME_LEN long (includes room for \0)
*/
static void
-quoteRelationName(char *buffer, Relation rel)
+appendRelationName(StringInfo buffer, Relation rel,
+ const char *prefix, const char *suffix)
{
- quoteOneName(buffer, get_namespace_name(RelationGetNamespace(rel)));
- buffer += strlen(buffer);
- *buffer++ = '.';
- quoteOneName(buffer, RelationGetRelationName(rel));
+ appendStringInfoQualifiedIdentifier(buffer, prefix,
+ get_namespace_name(RelationGetNamespace(rel)),
+ RelationGetRelationName(rel), suffix);
}
/*
--
2.39.5 (Apple Git-154)
[application/octet-stream] v2-0002-Use-appendStringInfoIdentifier-throughout-ri_trig.patch (22.2K, 6-v2-0002-Use-appendStringInfoIdentifier-throughout-ri_trig.patch)
download | inline diff:
From a6075d489778b3d8e5f70de38ef5b5b97226d905 Mon Sep 17 00:00:00 2001
From: "Chao Li (Evan)" <[email protected]>
Date: Mon, 17 Nov 2025 12:09:12 +0800
Subject: [PATCH v2 2/4] Use appendStringInfoIdentifier() throughout
ri_triggers.c
Replace most uses of quoteOneName() and manual stack buffers in
ri_triggers.c with appendStringInfoIdentifier() and related infrastructure.
This simplifies the construction of SQL queries generated by RI triggers and
eliminates the need for MAX_QUOTED_NAME_LEN / stack-allocated intermediate
buffers. It also removes several code paths where identifiers were quoted
manually, making the quoting rules consistent with ruleutils.c and the GUC
quote_all_identifiers.
This commit also adjusts generate_operator_clause() to support prefixed
arguments and identifier quoting directly, reducing the number of places
where callers need to inject string concatenation logic.
No user-visible behavior change is intended; the generated SQL should be
equivalent to the previous version.
Author: Chao Li <[email protected]>
Discussion: https://postgr.es/m/CAEoWx2=g2RVkxXB=JzWphgfg4QGV+spaA3PQ1rBM2iMehrVvjg@mail.gmail.com
---
src/backend/commands/matview.c | 4 +-
src/backend/utils/adt/ri_triggers.c | 188 +++++++++++++---------------
src/backend/utils/adt/ruleutils.c | 31 +++--
src/include/utils/builtins.h | 9 +-
4 files changed, 120 insertions(+), 112 deletions(-)
diff --git a/src/backend/commands/matview.c b/src/backend/commands/matview.c
index ef7c0d624f1..f1ad5a8e059 100644
--- a/src/backend/commands/matview.c
+++ b/src/backend/commands/matview.c
@@ -797,9 +797,9 @@ refresh_by_match_merge(Oid matviewOid, Oid tempOid, Oid relowner,
NameStr(attr->attname));
generate_operator_clause(&querybuf,
- leftop, attrtype,
+ NULL, leftop, attrtype, false,
op,
- rightop, attrtype);
+ NULL, rightop, attrtype, false);
foundUniqueIndex = true;
}
diff --git a/src/backend/utils/adt/ri_triggers.c b/src/backend/utils/adt/ri_triggers.c
index 9e13f526994..3cc4dc2b7c8 100644
--- a/src/backend/utils/adt/ri_triggers.c
+++ b/src/backend/utils/adt/ri_triggers.c
@@ -196,9 +196,9 @@ static void quoteOneName(char *buffer, const char *name);
static void quoteRelationName(char *buffer, Relation rel);
static void ri_GenerateQual(StringInfo buf,
const char *sep,
- const char *leftop, Oid leftoptype,
+ const char *leftopprefix, const char *leftop, Oid leftoptype, bool quoteleftop,
Oid opoid,
- const char *rightop, Oid rightoptype);
+ const char *rightopprefix, const char *rightop, Oid rightoptype, bool quoterightop);
static void ri_GenerateQualCollation(StringInfo buf, Oid collation);
static int ri_NullCheck(TupleDesc tupDesc, TupleTableSlot *slot,
const RI_ConstraintInfo *riinfo, bool rel_is_pk);
@@ -358,7 +358,7 @@ RI_FKey_check(TriggerData *trigdata)
{
StringInfoData querybuf;
char pkrelname[MAX_QUOTED_REL_NAME_LEN];
- char attname[MAX_QUOTED_NAME_LEN];
+ const char *attname;
char paramname[16];
const char *querysep;
Oid queryoids[RI_MAX_NUMKEYS];
@@ -393,11 +393,11 @@ RI_FKey_check(TriggerData *trigdata)
quoteRelationName(pkrelname, pk_rel);
if (riinfo->hasperiod)
{
- quoteOneName(attname,
- RIAttName(pk_rel, riinfo->pk_attnums[riinfo->nkeys - 1]));
+ attname = RIAttName(pk_rel, riinfo->pk_attnums[riinfo->nkeys - 1]);
+ appendStringInfoIdentifier(&querybuf, "SELECT 1 FROM (SELECT ", attname, " AS r FROM ");
appendStringInfo(&querybuf,
- "SELECT 1 FROM (SELECT %s AS r FROM %s%s x",
- attname, pk_only, pkrelname);
+ "%s%s x",
+ pk_only, pkrelname);
}
else
{
@@ -410,13 +410,12 @@ RI_FKey_check(TriggerData *trigdata)
Oid pk_type = RIAttType(pk_rel, riinfo->pk_attnums[i]);
Oid fk_type = RIAttType(fk_rel, riinfo->fk_attnums[i]);
- quoteOneName(attname,
- RIAttName(pk_rel, riinfo->pk_attnums[i]));
+ attname = RIAttName(pk_rel, riinfo->pk_attnums[i]);
sprintf(paramname, "$%d", i + 1);
ri_GenerateQual(&querybuf, querysep,
- attname, pk_type,
+ NULL, attname, pk_type, true,
riinfo->pf_eq_oprs[i],
- paramname, fk_type);
+ NULL, paramname, fk_type, false);
querysep = "AND";
queryoids[i] = fk_type;
}
@@ -428,9 +427,9 @@ RI_FKey_check(TriggerData *trigdata)
appendStringInfoString(&querybuf, ") x1 HAVING ");
sprintf(paramname, "$%d", riinfo->nkeys);
ri_GenerateQual(&querybuf, "",
- paramname, fk_type,
+ NULL, paramname, fk_type, false,
riinfo->agged_period_contained_by_oper,
- "pg_catalog.range_agg", ANYMULTIRANGEOID);
+ NULL, "pg_catalog.range_agg", ANYMULTIRANGEOID, false);
appendStringInfoString(&querybuf, "(x1.r)");
}
@@ -528,7 +527,7 @@ ri_Check_Pk_Match(Relation pk_rel, Relation fk_rel,
{
StringInfoData querybuf;
char pkrelname[MAX_QUOTED_REL_NAME_LEN];
- char attname[MAX_QUOTED_NAME_LEN];
+ const char *attname;
char paramname[16];
const char *querysep;
const char *pk_only;
@@ -563,11 +562,11 @@ ri_Check_Pk_Match(Relation pk_rel, Relation fk_rel,
quoteRelationName(pkrelname, pk_rel);
if (riinfo->hasperiod)
{
- quoteOneName(attname, RIAttName(pk_rel, riinfo->pk_attnums[riinfo->nkeys - 1]));
-
+ attname = RIAttName(pk_rel, riinfo->pk_attnums[riinfo->nkeys - 1]);
+ appendStringInfoIdentifier(&querybuf, "SELECT 1 FROM (SELECT ", attname, " AS r FROM ");
appendStringInfo(&querybuf,
- "SELECT 1 FROM (SELECT %s AS r FROM %s%s x",
- attname, pk_only, pkrelname);
+ "%s%s x",
+ pk_only, pkrelname);
}
else
{
@@ -579,13 +578,12 @@ ri_Check_Pk_Match(Relation pk_rel, Relation fk_rel,
{
Oid pk_type = RIAttType(pk_rel, riinfo->pk_attnums[i]);
- quoteOneName(attname,
- RIAttName(pk_rel, riinfo->pk_attnums[i]));
+ attname = RIAttName(pk_rel, riinfo->pk_attnums[i]);
sprintf(paramname, "$%d", i + 1);
ri_GenerateQual(&querybuf, querysep,
- attname, pk_type,
+ NULL, attname, pk_type, true,
riinfo->pp_eq_oprs[i],
- paramname, pk_type);
+ NULL, paramname, pk_type, false);
querysep = "AND";
queryoids[i] = pk_type;
}
@@ -597,9 +595,9 @@ ri_Check_Pk_Match(Relation pk_rel, Relation fk_rel,
appendStringInfoString(&querybuf, ") x1 HAVING ");
sprintf(paramname, "$%d", riinfo->nkeys);
ri_GenerateQual(&querybuf, "",
- paramname, fk_type,
+ NULL, paramname, fk_type, false,
riinfo->agged_period_contained_by_oper,
- "pg_catalog.range_agg", ANYMULTIRANGEOID);
+ NULL, "pg_catalog.range_agg", ANYMULTIRANGEOID, false);
appendStringInfoString(&querybuf, "(x1.r)");
}
@@ -757,7 +755,7 @@ ri_restrict(TriggerData *trigdata, bool is_no_action)
StringInfoData querybuf;
char pkrelname[MAX_QUOTED_REL_NAME_LEN];
char fkrelname[MAX_QUOTED_REL_NAME_LEN];
- char attname[MAX_QUOTED_NAME_LEN];
+ const char *attname;
char periodattname[MAX_QUOTED_NAME_LEN];
char paramname[16];
const char *querysep;
@@ -784,13 +782,12 @@ ri_restrict(TriggerData *trigdata, bool is_no_action)
Oid pk_type = RIAttType(pk_rel, riinfo->pk_attnums[i]);
Oid fk_type = RIAttType(fk_rel, riinfo->fk_attnums[i]);
- quoteOneName(attname,
- RIAttName(fk_rel, riinfo->fk_attnums[i]));
+ attname = RIAttName(fk_rel, riinfo->fk_attnums[i]);
sprintf(paramname, "$%d", i + 1);
ri_GenerateQual(&querybuf, querysep,
- paramname, pk_type,
+ NULL, paramname, pk_type, false,
riinfo->pf_eq_oprs[i],
- attname, fk_type);
+ NULL, attname, fk_type, true);
querysep = "AND";
queryoids[i] = pk_type;
}
@@ -828,7 +825,7 @@ ri_restrict(TriggerData *trigdata, bool is_no_action)
char *pk_only = pk_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE ?
"" : "ONLY ";
- quoteOneName(attname, RIAttName(fk_rel, riinfo->fk_attnums[riinfo->nkeys - 1]));
+ attname = RIAttName(fk_rel, riinfo->fk_attnums[riinfo->nkeys - 1]);
sprintf(paramname, "$%d", riinfo->nkeys);
appendStringInfoString(&querybuf, " AND NOT coalesce(");
@@ -837,9 +834,9 @@ ri_restrict(TriggerData *trigdata, bool is_no_action)
initStringInfo(&intersectbuf);
appendStringInfoChar(&intersectbuf, '(');
ri_GenerateQual(&intersectbuf, "",
- attname, fk_period_type,
+ NULL, attname, fk_period_type, true,
riinfo->period_intersect_oper,
- paramname, pk_period_type);
+ NULL, paramname, pk_period_type, false);
appendStringInfoChar(&intersectbuf, ')');
/* Find the remaining history */
@@ -857,22 +854,21 @@ ri_restrict(TriggerData *trigdata, bool is_no_action)
{
Oid pk_type = RIAttType(pk_rel, riinfo->pk_attnums[i]);
- quoteOneName(attname,
- RIAttName(pk_rel, riinfo->pk_attnums[i]));
+ attname = RIAttName(pk_rel, riinfo->pk_attnums[i]);
sprintf(paramname, "$%d", i + 1);
ri_GenerateQual(&replacementsbuf, querysep,
- paramname, pk_type,
+ NULL, paramname, pk_type, false,
riinfo->pp_eq_oprs[i],
- attname, pk_type);
+ NULL, attname, pk_type, true);
querysep = "AND";
queryoids[i] = pk_type;
}
appendStringInfoString(&replacementsbuf, " FOR KEY SHARE OF y) y2)");
ri_GenerateQual(&querybuf, "",
- intersectbuf.data, fk_period_type,
+ NULL, intersectbuf.data, fk_period_type, false,
riinfo->agged_period_contained_by_oper,
- replacementsbuf.data, ANYMULTIRANGEOID);
+ NULL, replacementsbuf.data, ANYMULTIRANGEOID, false);
/* end of coalesce: */
appendStringInfoString(&querybuf, ", false)");
}
@@ -944,7 +940,7 @@ RI_FKey_cascade_del(PG_FUNCTION_ARGS)
{
StringInfoData querybuf;
char fkrelname[MAX_QUOTED_REL_NAME_LEN];
- char attname[MAX_QUOTED_NAME_LEN];
+ const char *attname;
char paramname[16];
const char *querysep;
Oid queryoids[RI_MAX_NUMKEYS];
@@ -969,13 +965,12 @@ RI_FKey_cascade_del(PG_FUNCTION_ARGS)
Oid pk_type = RIAttType(pk_rel, riinfo->pk_attnums[i]);
Oid fk_type = RIAttType(fk_rel, riinfo->fk_attnums[i]);
- quoteOneName(attname,
- RIAttName(fk_rel, riinfo->fk_attnums[i]));
+ attname = RIAttName(fk_rel, riinfo->fk_attnums[i]);
sprintf(paramname, "$%d", i + 1);
ri_GenerateQual(&querybuf, querysep,
- paramname, pk_type,
+ NULL, paramname, pk_type, false,
riinfo->pf_eq_oprs[i],
- attname, fk_type);
+ NULL, attname, fk_type, true);
querysep = "AND";
queryoids[i] = pk_type;
}
@@ -1050,7 +1045,7 @@ RI_FKey_cascade_upd(PG_FUNCTION_ARGS)
StringInfoData querybuf;
StringInfoData qualbuf;
char fkrelname[MAX_QUOTED_REL_NAME_LEN];
- char attname[MAX_QUOTED_NAME_LEN];
+ const char *attname;
char paramname[16];
const char *querysep;
const char *qualsep;
@@ -1081,16 +1076,15 @@ RI_FKey_cascade_upd(PG_FUNCTION_ARGS)
Oid pk_type = RIAttType(pk_rel, riinfo->pk_attnums[i]);
Oid fk_type = RIAttType(fk_rel, riinfo->fk_attnums[i]);
- quoteOneName(attname,
- RIAttName(fk_rel, riinfo->fk_attnums[i]));
- appendStringInfo(&querybuf,
- "%s %s = $%d",
- querysep, attname, i + 1);
+ attname = RIAttName(fk_rel, riinfo->fk_attnums[i]);
+ appendStringInfoString(&querybuf, querysep);
+ appendStringInfoIdentifier(&querybuf, " ", attname, " = ");
+ appendStringInfo(&querybuf, "$%d", i + 1);
sprintf(paramname, "$%d", j + 1);
ri_GenerateQual(&qualbuf, qualsep,
- paramname, pk_type,
+ NULL, paramname, pk_type, false,
riinfo->pf_eq_oprs[i],
- attname, fk_type);
+ NULL, attname, fk_type, true);
querysep = ",";
qualsep = "AND";
queryoids[i] = pk_type;
@@ -1239,7 +1233,7 @@ ri_set(TriggerData *trigdata, bool is_set_null, int tgkind)
{
StringInfoData querybuf;
char fkrelname[MAX_QUOTED_REL_NAME_LEN];
- char attname[MAX_QUOTED_NAME_LEN];
+ const char *attname;
char paramname[16];
const char *querysep;
const char *qualsep;
@@ -1297,11 +1291,10 @@ ri_set(TriggerData *trigdata, bool is_set_null, int tgkind)
querysep = "";
for (int i = 0; i < num_cols_to_set; i++)
{
- quoteOneName(attname, RIAttName(fk_rel, set_cols[i]));
- appendStringInfo(&querybuf,
- "%s %s = %s",
- querysep, attname,
- is_set_null ? "NULL" : "DEFAULT");
+ attname = RIAttName(fk_rel, set_cols[i]);
+ appendStringInfoString(&querybuf, querysep);
+ appendStringInfoIdentifier(&querybuf, " ", attname, " = ");
+ appendStringInfoString(&querybuf, is_set_null ? "NULL" : "DEFAULT");
querysep = ",";
}
@@ -1314,14 +1307,13 @@ ri_set(TriggerData *trigdata, bool is_set_null, int tgkind)
Oid pk_type = RIAttType(pk_rel, riinfo->pk_attnums[i]);
Oid fk_type = RIAttType(fk_rel, riinfo->fk_attnums[i]);
- quoteOneName(attname,
- RIAttName(fk_rel, riinfo->fk_attnums[i]));
+ attname = RIAttName(fk_rel, riinfo->fk_attnums[i]);
sprintf(paramname, "$%d", i + 1);
ri_GenerateQual(&querybuf, qualsep,
- paramname, pk_type,
+ NULL, paramname, pk_type, false,
riinfo->pf_eq_oprs[i],
- attname, fk_type);
+ NULL, attname, fk_type, true);
qualsep = "AND";
queryoids[i] = pk_type;
}
@@ -1519,8 +1511,8 @@ RI_Initial_Check(Trigger *trigger, Relation fk_rel, Relation pk_rel)
StringInfoData querybuf;
char pkrelname[MAX_QUOTED_REL_NAME_LEN];
char fkrelname[MAX_QUOTED_REL_NAME_LEN];
- char pkattname[MAX_QUOTED_NAME_LEN + 3];
- char fkattname[MAX_QUOTED_NAME_LEN + 3];
+ const char *pkattname;
+ const char *fkattname;
RangeTblEntry *rte;
RTEPermissionInfo *pk_perminfo;
RTEPermissionInfo *fk_perminfo;
@@ -1615,9 +1607,9 @@ RI_Initial_Check(Trigger *trigger, Relation fk_rel, Relation pk_rel)
sep = "";
for (int i = 0; i < riinfo->nkeys; i++)
{
- quoteOneName(fkattname,
- RIAttName(fk_rel, riinfo->fk_attnums[i]));
- appendStringInfo(&querybuf, "%sfk.%s", sep, fkattname);
+ fkattname = RIAttName(fk_rel, riinfo->fk_attnums[i]);
+ appendStringInfoString(&querybuf, sep);
+ appendStringInfoIdentifier(&querybuf, "fk.", fkattname, NULL);
sep = ", ";
}
@@ -1631,8 +1623,6 @@ RI_Initial_Check(Trigger *trigger, Relation fk_rel, Relation pk_rel)
" FROM %s%s fk LEFT OUTER JOIN %s%s pk ON",
fk_only, fkrelname, pk_only, pkrelname);
- strcpy(pkattname, "pk.");
- strcpy(fkattname, "fk.");
sep = "(";
for (int i = 0; i < riinfo->nkeys; i++)
{
@@ -1641,14 +1631,12 @@ RI_Initial_Check(Trigger *trigger, Relation fk_rel, Relation pk_rel)
Oid pk_coll = RIAttCollation(pk_rel, riinfo->pk_attnums[i]);
Oid fk_coll = RIAttCollation(fk_rel, riinfo->fk_attnums[i]);
- quoteOneName(pkattname + 3,
- RIAttName(pk_rel, riinfo->pk_attnums[i]));
- quoteOneName(fkattname + 3,
- RIAttName(fk_rel, riinfo->fk_attnums[i]));
+ pkattname = RIAttName(pk_rel, riinfo->pk_attnums[i]);
+ fkattname = RIAttName(fk_rel, riinfo->fk_attnums[i]);
ri_GenerateQual(&querybuf, sep,
- pkattname, pk_type,
+ "pk.", pkattname, pk_type, true,
riinfo->pf_eq_oprs[i],
- fkattname, fk_type);
+ "fk.", fkattname, fk_type, true);
if (pk_coll != fk_coll)
ri_GenerateQualCollation(&querybuf, pk_coll);
sep = "AND";
@@ -1658,16 +1646,15 @@ RI_Initial_Check(Trigger *trigger, Relation fk_rel, Relation pk_rel)
* It's sufficient to test any one pk attribute for null to detect a join
* failure.
*/
- quoteOneName(pkattname, RIAttName(pk_rel, riinfo->pk_attnums[0]));
- appendStringInfo(&querybuf, ") WHERE pk.%s IS NULL AND (", pkattname);
+ pkattname = RIAttName(pk_rel, riinfo->pk_attnums[0]);
+ appendStringInfoIdentifier(&querybuf, ") WHERE pk.", pkattname, " IS NULL AND (");
sep = "";
for (int i = 0; i < riinfo->nkeys; i++)
{
- quoteOneName(fkattname, RIAttName(fk_rel, riinfo->fk_attnums[i]));
- appendStringInfo(&querybuf,
- "%sfk.%s IS NOT NULL",
- sep, fkattname);
+ fkattname = RIAttName(fk_rel, riinfo->fk_attnums[i]);
+ appendStringInfoString(&querybuf, sep);
+ appendStringInfoIdentifier(&querybuf, "fk.", fkattname, " IS NOT NULL");
switch (riinfo->confmatchtype)
{
case FKCONSTR_MATCH_SIMPLE:
@@ -1814,8 +1801,8 @@ RI_PartitionRemove_Check(Trigger *trigger, Relation fk_rel, Relation pk_rel)
char *constraintDef;
char pkrelname[MAX_QUOTED_REL_NAME_LEN];
char fkrelname[MAX_QUOTED_REL_NAME_LEN];
- char pkattname[MAX_QUOTED_NAME_LEN + 3];
- char fkattname[MAX_QUOTED_NAME_LEN + 3];
+ const char *pkattname;
+ const char *fkattname;
const char *sep;
const char *fk_only;
int save_nestlevel;
@@ -1852,9 +1839,9 @@ RI_PartitionRemove_Check(Trigger *trigger, Relation fk_rel, Relation pk_rel)
sep = "";
for (i = 0; i < riinfo->nkeys; i++)
{
- quoteOneName(fkattname,
- RIAttName(fk_rel, riinfo->fk_attnums[i]));
- appendStringInfo(&querybuf, "%sfk.%s", sep, fkattname);
+ fkattname = RIAttName(fk_rel, riinfo->fk_attnums[i]);
+ appendStringInfoString(&querybuf, sep);
+ appendStringInfoIdentifier(&querybuf, "fk.", fkattname, NULL);
sep = ", ";
}
@@ -1865,8 +1852,8 @@ RI_PartitionRemove_Check(Trigger *trigger, Relation fk_rel, Relation pk_rel)
appendStringInfo(&querybuf,
" FROM %s%s fk JOIN %s pk ON",
fk_only, fkrelname, pkrelname);
- strcpy(pkattname, "pk.");
- strcpy(fkattname, "fk.");
+ /* strcpy(pkattname, "pk."); */
+ /* strcpy(fkattname, "fk."); */
sep = "(";
for (i = 0; i < riinfo->nkeys; i++)
{
@@ -1875,14 +1862,12 @@ RI_PartitionRemove_Check(Trigger *trigger, Relation fk_rel, Relation pk_rel)
Oid pk_coll = RIAttCollation(pk_rel, riinfo->pk_attnums[i]);
Oid fk_coll = RIAttCollation(fk_rel, riinfo->fk_attnums[i]);
- quoteOneName(pkattname + 3,
- RIAttName(pk_rel, riinfo->pk_attnums[i]));
- quoteOneName(fkattname + 3,
- RIAttName(fk_rel, riinfo->fk_attnums[i]));
+ pkattname = RIAttName(pk_rel, riinfo->pk_attnums[i]);
+ fkattname = RIAttName(fk_rel, riinfo->fk_attnums[i]);
ri_GenerateQual(&querybuf, sep,
- pkattname, pk_type,
+ "pk.", pkattname, pk_type, true,
riinfo->pf_eq_oprs[i],
- fkattname, fk_type);
+ "fk.", fkattname, fk_type, true);
if (pk_coll != fk_coll)
ri_GenerateQualCollation(&querybuf, pk_coll);
sep = "AND";
@@ -1903,10 +1888,9 @@ RI_PartitionRemove_Check(Trigger *trigger, Relation fk_rel, Relation pk_rel)
sep = "";
for (i = 0; i < riinfo->nkeys; i++)
{
- quoteOneName(fkattname, RIAttName(fk_rel, riinfo->fk_attnums[i]));
- appendStringInfo(&querybuf,
- "%sfk.%s IS NOT NULL",
- sep, fkattname);
+ fkattname = RIAttName(fk_rel, riinfo->fk_attnums[i]);
+ appendStringInfoString(&querybuf, sep);
+ appendStringInfoIdentifier(&querybuf, "fk.", fkattname, " IS NOT NULL");
switch (riinfo->confmatchtype)
{
case FKCONSTR_MATCH_SIMPLE:
@@ -2064,13 +2048,15 @@ quoteRelationName(char *buffer, Relation rel)
static void
ri_GenerateQual(StringInfo buf,
const char *sep,
- const char *leftop, Oid leftoptype,
+ const char *leftopprefix, const char *leftop, Oid leftoptype, bool quoteleftop,
Oid opoid,
- const char *rightop, Oid rightoptype)
+ const char *rightopprefix, const char *rightop, Oid rightoptype, bool quoterightop)
{
appendStringInfo(buf, " %s ", sep);
- generate_operator_clause(buf, leftop, leftoptype, opoid,
- rightop, rightoptype);
+ generate_operator_clause(buf,
+ leftopprefix, leftop, leftoptype, quoteleftop,
+ opoid,
+ rightopprefix, rightop, rightoptype, quoterightop);
}
/*
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index 1d767deb6c4..b212a28d9be 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -13570,9 +13570,9 @@ generate_operator_name(Oid operid, Oid arg1, Oid arg2)
*/
void
generate_operator_clause(StringInfo buf,
- const char *leftop, Oid leftoptype,
+ const char *leftopprefix, const char *leftop, Oid leftoptype, bool quoteleftop,
Oid opoid,
- const char *rightop, Oid rightoptype)
+ const char *rightopprefix, const char *rightop, Oid rightoptype, bool quoterightop)
{
HeapTuple opertup;
Form_pg_operator operform;
@@ -13585,15 +13585,32 @@ generate_operator_clause(StringInfo buf,
operform = (Form_pg_operator) GETSTRUCT(opertup);
Assert(operform->oprkind == 'b');
oprname = NameStr(operform->oprname);
-
nspname = get_namespace_name(operform->oprnamespace);
- appendStringInfoString(buf, leftop);
+ if (quoteleftop)
+ appendStringInfoIdentifier(buf, leftopprefix, leftop, NULL);
+ else
+ {
+ if (leftopprefix)
+ appendStringInfoString(buf, leftopprefix);
+ appendStringInfoString(buf, leftop);
+ }
+
if (leftoptype != operform->oprleft)
add_cast_to(buf, operform->oprleft);
- appendStringInfo(buf, " OPERATOR(%s.", quote_identifier(nspname));
- appendStringInfoString(buf, oprname);
- appendStringInfo(buf, ") %s", rightop);
+
+ appendStringInfoIdentifier(buf, " OPERATOR(", nspname, ".");
+ appendStringInfo(buf, "%s) ", oprname);
+
+ if (quoterightop)
+ appendStringInfoIdentifier(buf, rightopprefix, rightop, NULL);
+ else
+ {
+ if (rightopprefix)
+ appendStringInfoString(buf, rightopprefix);
+ appendStringInfoString(buf, rightop);
+ }
+
if (rightoptype != operform->oprright)
add_cast_to(buf, operform->oprright);
diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h
index ff4ba7265c2..fc4de4446ac 100644
--- a/src/include/utils/builtins.h
+++ b/src/include/utils/builtins.h
@@ -80,10 +80,15 @@ extern PGDLLIMPORT bool quote_all_identifiers;
extern const char *quote_identifier(const char *ident);
extern char *quote_qualified_identifier(const char *qualifier,
const char *ident);
+
+/* extern void generate_operator_clause(StringInfo buf, */
+/* const char *leftop, Oid leftoptype, */
+/* Oid opoid, */
+/* const char *rightop, Oid rightoptype); */
extern void generate_operator_clause(StringInfo buf,
- const char *leftop, Oid leftoptype,
+ const char *leftopprefix, const char *leftop, Oid leftoptype, bool quoteleftop,
Oid opoid,
- const char *rightop, Oid rightoptype);
+ const char *rightopprefix, const char *rightop, Oid rightoptype, bool quoterightop);
extern void appendStringInfoIdentifier(StringInfo str, const char *prefix, const char *ident, const char *suffix);
extern void appendStringInfoQualifiedIdentifier(StringInfo str,
const char *prefix,
--
2.39.5 (Apple Git-154)
view thread (8+ messages) latest in thread
reply
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Reply to all the recipients using the --to and --cc options:
reply via email
To: [email protected]
Cc: [email protected], [email protected]
Subject: Re: Re: quoteOneName() inconsistency with quote_all_identifiers — replacement API proposed
In-Reply-To: <CAEoWx2=vRfws6C2svUWdmNA10no+g71HABDqqKdbL43adC-VuQ@mail.gmail.com>
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
This inbox is served by agora; see mirroring instructions
for how to clone and mirror all data and code used for this inbox