From 478cacb50e4851760db9b8e75b2256085b571965 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Fri, 5 Apr 2019 12:59:46 -0400 Subject: [PATCH] Ensure consistent name matching behavior in processSQLNamePattern(). MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Prior to v12, if you used a collation-sensitive regex feature in a pattern handled by processSQLNamePattern() (for instance, \d '\\w+' in psql), the behavior you got matched the database's default collation. Since commit 586b98fdf you'd usually get C-collation behavior, because the catalog "name"-type columns are now marked as COLLATE "C". Add explicit COLLATE specifications to restore the prior behavior. (Note for whoever writes the v12 release notes: the need for this shows that while 586b98fdf preserved pre-v12 behavior of "name" columns for simple comparison operators, it changed the behavior of regex operators on those columns. Although this patch fixes it for pattern matches generated by our own tools, user-written queries will still be affected. So we'd better mention this issue as a compatibility item.) Daniel Vérité Discussion: https://postgr.es/m/701e51f0-0ec0-4e70-a365-1958d66dd8d2@manitou-mail.org --- src/fe_utils/string_utils.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/fe_utils/string_utils.c b/src/fe_utils/string_utils.c index 5c1732aabe..58610dbf57 100644 --- a/src/fe_utils/string_utils.c +++ b/src/fe_utils/string_utils.c @@ -956,6 +956,12 @@ processSQLNamePattern(PGconn *conn, PQExpBuffer buf, const char *pattern, * Now decide what we need to emit. We may run under a hostile * search_path, so qualify EVERY name. Note there will be a leading "^(" * in the patterns in any case. + * + * We want the regex matches to use the database's default collation where + * collation-sensitive behavior is required (for example, which characters + * match '\w'). That happened by default before PG v12, but if the server + * is >= v12 then we need to force it through explicit COLLATE clauses, + * otherwise the "C" collation attached to "name" catalog columns wins. */ if (namebuf.len > 2) { @@ -971,16 +977,22 @@ processSQLNamePattern(PGconn *conn, PQExpBuffer buf, const char *pattern, appendPQExpBuffer(buf, "(%s OPERATOR(pg_catalog.~) ", namevar); appendStringLiteralConn(buf, namebuf.data, conn); + if (PQserverVersion(conn) >= 120000) + appendPQExpBufferStr(buf, " COLLATE pg_catalog.default"); appendPQExpBuffer(buf, "\n OR %s OPERATOR(pg_catalog.~) ", altnamevar); appendStringLiteralConn(buf, namebuf.data, conn); + if (PQserverVersion(conn) >= 120000) + appendPQExpBufferStr(buf, " COLLATE pg_catalog.default"); appendPQExpBufferStr(buf, ")\n"); } else { appendPQExpBuffer(buf, "%s OPERATOR(pg_catalog.~) ", namevar); appendStringLiteralConn(buf, namebuf.data, conn); + if (PQserverVersion(conn) >= 120000) + appendPQExpBufferStr(buf, " COLLATE pg_catalog.default"); appendPQExpBufferChar(buf, '\n'); } } @@ -997,6 +1009,8 @@ processSQLNamePattern(PGconn *conn, PQExpBuffer buf, const char *pattern, WHEREAND(); appendPQExpBuffer(buf, "%s OPERATOR(pg_catalog.~) ", schemavar); appendStringLiteralConn(buf, schemabuf.data, conn); + if (PQserverVersion(conn) >= 120000) + appendPQExpBufferStr(buf, " COLLATE pg_catalog.default"); appendPQExpBufferChar(buf, '\n'); } }