diff --git a/src/backend/catalog/namespace.c b/src/backend/catalog/namespace.c index d23474da4fb2..7c3b0bb7853f 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 c75b7131ed70..fa8762db10d5 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -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); } @@ -5005,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) @@ -5021,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))); @@ -5097,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); @@ -5156,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, @@ -5187,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); } @@ -5340,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))); @@ -5373,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))); @@ -5395,8 +5392,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; @@ -5546,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; } @@ -5608,8 +5603,7 @@ getObjectIdentityParts(const ObjectAddress *object, } if (objname) *objname = list_make1(datname); - appendStringInfoString(&buffer, - quote_identifier(datname)); + appendStringInfoIdentifier(&buffer, NULL, datname, NULL); break; } @@ -5627,8 +5621,7 @@ getObjectIdentityParts(const ObjectAddress *object, } if (objname) *objname = list_make1(tblspace); - appendStringInfoString(&buffer, - quote_identifier(tblspace)); + appendStringInfoIdentifier(&buffer, NULL, tblspace, NULL); break; } @@ -5640,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)); } @@ -5655,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)); } @@ -5697,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; } @@ -5739,16 +5730,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; @@ -5806,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; @@ -5829,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); @@ -5884,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))); @@ -5901,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); } @@ -5969,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/commands/explain.c b/src/backend/commands/explain.c index 7e699f8595e0..cc9797378451 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/commands/matview.c b/src/backend/commands/matview.c index ef7c0d624f13..f1ad5a8e059b 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 059fc5ebf601..5b1c65475191 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,13 +189,12 @@ 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 *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); @@ -357,8 +353,7 @@ RI_FKey_check(TriggerData *trigdata) if ((qplan = ri_FetchPreparedPlan(&qkey)) == NULL) { 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]; @@ -390,20 +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) { - 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); + attname = RIAttName(pk_rel, riinfo->pk_attnums[riinfo->nkeys - 1]); + appendStringInfoIdentifier(&querybuf, "SELECT 1 FROM (SELECT ", attname, " AS r FROM "); + 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++) @@ -411,13 +402,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; } @@ -429,9 +419,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,8 +518,7 @@ 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]; - char attname[MAX_QUOTED_NAME_LEN]; + const char *attname; char paramname[16]; const char *querysep; const char *pk_only; @@ -561,32 +550,28 @@ 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) { - 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); + attname = RIAttName(pk_rel, riinfo->pk_attnums[riinfo->nkeys - 1]); + appendStringInfoIdentifier(&querybuf, "SELECT 1 FROM (SELECT ", attname, " AS r FROM "); + 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++) { 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; } @@ -598,9 +583,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)"); } @@ -756,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]; - char attname[MAX_QUOTED_NAME_LEN]; - char periodattname[MAX_QUOTED_NAME_LEN]; + const char *attname; char paramname[16]; const char *querysep; Oid queryoids[RI_MAX_NUMKEYS]; @@ -776,22 +758,20 @@ 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++) { 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; } @@ -829,7 +809,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("); @@ -838,19 +818,19 @@ 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 */ 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 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 */ querysep = "WHERE"; @@ -858,22 +838,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,8 +923,7 @@ RI_FKey_cascade_del(PG_FUNCTION_ARGS) if ((qplan = ri_FetchPreparedPlan(&qkey)) == NULL) { 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]; @@ -961,22 +939,20 @@ 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++) { 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,8 +1026,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; @@ -1072,9 +1047,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++) @@ -1082,16 +1056,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,8 +1212,7 @@ 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]; - char attname[MAX_QUOTED_NAME_LEN]; + const char *attname; char paramname[16]; const char *querysep; const char *qualsep; @@ -1288,9 +1260,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 @@ -1298,11 +1269,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 = ","; } @@ -1315,14 +1285,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; } @@ -1518,10 +1487,8 @@ 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]; - 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; @@ -1616,24 +1583,20 @@ 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 = ", "; } - 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"); - strcpy(pkattname, "pk."); - strcpy(fkattname, "fk."); sep = "("; for (int i = 0; i < riinfo->nkeys; i++) { @@ -1642,14 +1605,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"; @@ -1659,16 +1620,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: @@ -1813,10 +1773,8 @@ 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]; - 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; @@ -1853,21 +1811,18 @@ 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 = ", "; } - 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); - strcpy(pkattname, "pk."); - strcpy(fkattname, "fk."); + appendStringInfoString(&querybuf, " FROM "); + appendRelationName(&querybuf, fk_rel, fk_only, " fk JOIN "); + appendRelationName(&querybuf, pk_rel, NULL, " pk ON"); + sep = "("; for (i = 0; i < riinfo->nkeys; i++) { @@ -1876,14 +1831,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"; @@ -1904,10 +1857,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: @@ -2021,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); } /* @@ -2065,13 +1996,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); } /* @@ -2095,7 +2028,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 +2043,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 556ab057e5a9..cafc4d9c002b 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 *colsep = ""; 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, colsep, strVal(lfirst(lc)), NULL); + colsep = ", "; } - 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 @@ -13052,25 +13020,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 macros here, but they might yield unwanted @@ -13078,7 +13038,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 +13052,7 @@ quote_identifier(const char *ident) { safe = false; if (ch == '"') - nquotes++; + (*nquotes)++; } } @@ -13115,14 +13075,20 @@ quote_identifier(const char *ident) safe = false; } - if (safe) - return ident; /* no change needed */ + return safe; +} + +static inline const char * +quote_identifier_internal(const char *ident, int nquotes, char **result) +{ + char *optr; - result = (char *) palloc(strlen(ident) + nquotes + 2 + 1); + if (*result == NULL) + *result = (char *) palloc(strlen(ident) + nquotes + 2 + 1); - optr = result; + optr = *result; *optr++ = '"'; - for (ptr = ident; *ptr; ptr++) + for (const char *ptr = ident; *ptr; ptr++) { char ch = *ptr; @@ -13133,7 +13099,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 +13216,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; } @@ -13437,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); @@ -13472,9 +13538,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; @@ -13487,15 +13553,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); @@ -13526,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); } @@ -13624,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; @@ -13650,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 diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h index ce6285a2c037..4bd04e1a57a2 100644 --- a/src/include/utils/builtins.h +++ b/src/include/utils/builtins.h @@ -81,9 +81,15 @@ 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, + 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, + const char *qualifier, + const char *ident, + const char *suffix); /* varchar.c */ extern int bpchartruelen(char *s, int len);