Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_CBC_SHA1:256) (Exim 4.89) (envelope-from ) id 1gZh6q-0002RJ-2x for pgsql-hackers@arkaria.postgresql.org; Wed, 19 Dec 2018 19:02:20 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.89) (envelope-from ) id 1gZh6n-0005ZG-8q for pgsql-hackers@arkaria.postgresql.org; Wed, 19 Dec 2018 19:02:17 +0000 Received: from makus.postgresql.org ([2001:4800:3e1:1::229]) by malur.postgresql.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_CBC_SHA1:256) (Exim 4.89) (envelope-from ) id 1gZh6m-0005Z9-Pj for pgsql-hackers@lists.postgresql.org; Wed, 19 Dec 2018 19:02:17 +0000 Received: from sss.pgh.pa.us ([66.207.139.130]) by makus.postgresql.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_CBC_SHA1:256) (Exim 4.89) (envelope-from ) id 1gZh6i-0003KB-87 for pgsql-hackers@lists.postgresql.org; Wed, 19 Dec 2018 19:02:14 +0000 Received: from sss1.sss.pgh.pa.us (localhost [127.0.0.1]) by sss.pgh.pa.us (8.14.4/8.14.4) with ESMTP id wBJJ27Ql018205; Wed, 19 Dec 2018 14:02:07 -0500 From: Tom Lane To: Robert Haas cc: PostgreSQL Hackers Subject: Re: Collatability of type "name" In-reply-to: <21253.1545170114@sss.pgh.pa.us> References: <15938.1544377821@sss.pgh.pa.us> <21253.1545170114@sss.pgh.pa.us> Comments: In-reply-to Tom Lane message dated "Tue, 18 Dec 2018 16:55:14 -0500" MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="----- =_aaaaaaaaaa0" Content-ID: <18010.1545245841.0@sss.pgh.pa.us> Date: Wed, 19 Dec 2018 14:02:07 -0500 Message-ID: <18204.1545246127@sss.pgh.pa.us> List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Precedence: bulk ------- =_aaaaaaaaaa0 Content-Type: text/plain; charset="us-ascii" Content-ID: <18010.1545245841.1@sss.pgh.pa.us> I wrote: > We could eliminate those two problems if we made "name" have > typcollation "C" rather than "default", so that its semantics > wouldn't change without explicit collation specs. This feels > like pretty much of a wart to me, but maybe it's worth doing > in the name of avoiding compatibility issues. We could still > unify name_ops with text_ops, but now "name" would act more like > a domain with an explicit collation spec. Here's a variant patch that does it like that. On reflection this seems like a safer way to proceed. It feels like a wart because it violates the system's original assumption that collatable base types all have DEFAULT_COLLATION_OID, but as far as I can tell that doesn't have any really severe consequences. The main ugliness is that CREATE TYPE can only set typcollation to 0 or DEFAULT_COLLATION_OID for new base types, meaning that it's impossible to duplicate the behavior of type "name" in a user-defined type, which seems like an extensibility failure. But it's not one that I'm sufficiently excited about to wish to fix. Another point is that there are places in parse_collate.c that suppose that "domain's typcollation is different from DEFAULT_COLLATION_OID" is equivalent to "domain's collation was explicitly specified", which would not be the case for domains over type name. But this seems to be isomorphic to the situation where "name" is a domain with COLLATE "C" over some anonymous base type, so I don't think that any fundamental semantic breakage ensues. Barring objections I'm going to push forward with committing this and unifying name_ops with text_ops. regards, tom lane ------- =_aaaaaaaaaa0 Content-Type: text/x-diff; name="make-type-name-collatable-2.patch"; charset="us-ascii" Content-ID: <18010.1545245841.2@sss.pgh.pa.us> Content-Description: make-type-name-collatable-2.patch Content-Transfer-Encoding: quoted-printable diff --git a/doc/src/sgml/catalogs.sgml b/doc/src/sgml/catalogs.sgml index 8d0cab5..af4d062 100644 --- a/doc/src/sgml/catalogs.sgml +++ b/doc/src/sgml/catalogs.sgml @@ -7866,10 +7866,10 @@ SCRAM-SHA-256$<iteration count>= :&l typcollation specifies the collation of the type. If the type does not support collations, this will - be zero. A base type that supports collations will have - DEFAULT_COLLATION_OID here. A domain over a - collatable type can have some other collation OID, if one was - specified for the domain. + be zero. A base type that supports collations will have a nonzero + value here, typically DEFAULT_COLLATION_OID. + A domain over a collatable type can have a collation OID different + from its base type's, if one was specified for the domain. = diff --git a/src/backend/access/nbtree/nbtcompare.c b/src/backend/access/n= btree/nbtcompare.c index 6f2ad23..94ef6ea 100644 --- a/src/backend/access/nbtree/nbtcompare.c +++ b/src/backend/access/nbtree/nbtcompare.c @@ -333,30 +333,3 @@ btcharcmp(PG_FUNCTION_ARGS) /* Be careful to compare chars as unsigned */ PG_RETURN_INT32((int32) ((uint8) a) - (int32) ((uint8) b)); } - -Datum -btnamecmp(PG_FUNCTION_ARGS) -{ - Name a =3D PG_GETARG_NAME(0); - Name b =3D PG_GETARG_NAME(1); - - PG_RETURN_INT32(strncmp(NameStr(*a), NameStr(*b), NAMEDATALEN)); -} - -static int -btnamefastcmp(Datum x, Datum y, SortSupport ssup) -{ - Name a =3D DatumGetName(x); - Name b =3D DatumGetName(y); - - return strncmp(NameStr(*a), NameStr(*b), NAMEDATALEN); -} - -Datum -btnamesortsupport(PG_FUNCTION_ARGS) -{ - SortSupport ssup =3D (SortSupport) PG_GETARG_POINTER(0); - - ssup->comparator =3D btnamefastcmp; - PG_RETURN_VOID(); -} diff --git a/src/backend/bootstrap/bootstrap.c b/src/backend/bootstrap/boo= tstrap.c index 8e42255..fc1927c 100644 --- a/src/backend/bootstrap/bootstrap.c +++ b/src/backend/bootstrap/bootstrap.c @@ -111,7 +111,7 @@ static const struct typinfo TypInfo[] =3D { F_INT4IN, F_INT4OUT}, {"float4", FLOAT4OID, 0, 4, FLOAT4PASSBYVAL, 'i', 'p', InvalidOid, F_FLOAT4IN, F_FLOAT4OUT}, - {"name", NAMEOID, CHAROID, NAMEDATALEN, false, 'c', 'p', InvalidOid, + {"name", NAMEOID, CHAROID, NAMEDATALEN, false, 'c', 'p', C_COLLATION_OID= , F_NAMEIN, F_NAMEOUT}, {"regclass", REGCLASSOID, 0, 4, true, 'i', 'p', InvalidOid, F_REGCLASSIN, F_REGCLASSOUT}, diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain= .c index de09ded..094e977 100644 --- a/src/backend/commands/explain.c +++ b/src/backend/commands/explain.c @@ -14,7 +14,6 @@ #include "postgres.h" = #include "access/xact.h" -#include "catalog/pg_collation.h" #include "catalog/pg_type.h" #include "commands/createas.h" #include "commands/defrem.h" @@ -2347,11 +2346,13 @@ show_sortorder_options(StringInfo buf, Node *sorte= xpr, TYPECACHE_LT_OPR | TYPECACHE_GT_OPR); = /* - * Print COLLATE if it's not default. There are some cases where this i= s - * redundant, eg if expression is a column whose declared collation is - * that collation, but it's hard to distinguish that here. + * Print COLLATE if it's not default for the column's type. There are + * some cases where this is redundant, eg if expression is a column whos= e + * declared collation is that collation, but it's hard to distinguish th= at + * here (and arguably, printing COLLATE explicitly is a good idea anyway + * in such cases). */ - if (OidIsValid(collation) && collation !=3D DEFAULT_COLLATION_OID) + if (OidIsValid(collation) && collation !=3D get_typcollation(sortcoltype= )) { char *collname =3D get_collation_name(collation); = diff --git a/src/backend/nodes/nodeFuncs.c b/src/backend/nodes/nodeFuncs.c index 54b3dcf..a813e38 100644 --- a/src/backend/nodes/nodeFuncs.c +++ b/src/backend/nodes/nodeFuncs.c @@ -862,7 +862,11 @@ exprCollation(const Node *expr) coll =3D ((const MinMaxExpr *) expr)->minmaxcollid; break; case T_SQLValueFunction: - coll =3D InvalidOid; /* all cases return non-collatable types */ + /* Returns either NAME or a non-collatable type */ + if (((const SQLValueFunction *) expr)->type =3D=3D NAMEOID) + coll =3D C_COLLATION_OID; + else + coll =3D InvalidOid; break; case T_XmlExpr: = @@ -1075,7 +1079,9 @@ exprSetCollation(Node *expr, Oid collation) ((MinMaxExpr *) expr)->minmaxcollid =3D collation; break; case T_SQLValueFunction: - Assert(!OidIsValid(collation)); /* no collatable results */ + Assert((((SQLValueFunction *) expr)->type =3D=3D NAMEOID) ? + (collation =3D=3D C_COLLATION_OID) : + (collation =3D=3D InvalidOid)); break; case T_XmlExpr: Assert((((XmlExpr *) expr)->op =3D=3D IS_XMLSERIALIZE) ? diff --git a/src/backend/optimizer/path/indxpath.c b/src/backend/optimizer= /path/indxpath.c index 5f46415..965d964 100644 --- a/src/backend/optimizer/path/indxpath.c +++ b/src/backend/optimizer/path/indxpath.c @@ -4344,7 +4344,7 @@ string_to_const(const char *str, Oid datatype) break; = case NAMEOID: - collation =3D InvalidOid; + collation =3D C_COLLATION_OID; constlen =3D NAMEDATALEN; break; = diff --git a/src/backend/parser/parse_clause.c b/src/backend/parser/parse_= clause.c index 4ba5120..2099724 100644 --- a/src/backend/parser/parse_clause.c +++ b/src/backend/parser/parse_clause.c @@ -788,7 +788,7 @@ transformRangeTableFunc(ParseState *pstate, RangeTable= Func *rtf) tf->coltypes =3D lappend_oid(tf->coltypes, typid); tf->coltypmods =3D lappend_int(tf->coltypmods, typmod); tf->colcollations =3D lappend_oid(tf->colcollations, - type_is_collatable(typid) ? DEFAULT_COLLATION_OID : InvalidOid)= ; + get_typcollation(typid)); = /* Transform the PATH and DEFAULT expressions */ if (rawc->colexpr) diff --git a/src/backend/utils/adt/name.c b/src/backend/utils/adt/name.c index c266da2..0cf8b9d 100644 --- a/src/backend/utils/adt/name.c +++ b/src/backend/utils/adt/name.c @@ -21,6 +21,7 @@ #include "postgres.h" = #include "catalog/namespace.h" +#include "catalog/pg_collation.h" #include "catalog/pg_type.h" #include "libpq/pqformat.h" #include "mb/pg_wchar.h" @@ -28,6 +29,7 @@ #include "utils/array.h" #include "utils/builtins.h" #include "utils/lsyscache.h" +#include "utils/varlena.h" = = /************************************************************************= ***** @@ -113,22 +115,21 @@ namesend(PG_FUNCTION_ARGS) = = /************************************************************************= ***** - * PUBLIC ROUTINES * + * COMPARISON/SORTING ROUTINES * ************************************************************************= *****/ = /* * nameeq - returns 1 iff arguments are equal * namene - returns 1 iff arguments are not equal - * - * BUGS: - * Assumes that "xy\0\0a" should be equal to "xy\0b". - * If not, can do the comparison backwards for efficiency. - * * namelt - returns 1 iff a < b * namele - returns 1 iff a <=3D b * namegt - returns 1 iff a > b * namege - returns 1 iff a >=3D b * + * Note that the use of strncmp with NAMEDATALEN limit is mostly historic= al; + * strcmp would do as well, because we do not allow NAME values that don'= t + * have a '\0' terminator. Whatever might be past the terminator is not + * considered relevant to comparisons. */ Datum nameeq(PG_FUNCTION_ARGS) @@ -136,6 +137,7 @@ nameeq(PG_FUNCTION_ARGS) Name arg1 =3D PG_GETARG_NAME(0); Name arg2 =3D PG_GETARG_NAME(1); = + /* Collation doesn't matter: equal only if bitwise-equal */ PG_RETURN_BOOL(strncmp(NameStr(*arg1), NameStr(*arg2), NAMEDATALEN) =3D=3D= 0); } = @@ -145,16 +147,30 @@ namene(PG_FUNCTION_ARGS) Name arg1 =3D PG_GETARG_NAME(0); Name arg2 =3D PG_GETARG_NAME(1); = + /* Collation doesn't matter: equal only if bitwise-equal */ PG_RETURN_BOOL(strncmp(NameStr(*arg1), NameStr(*arg2), NAMEDATALEN) !=3D= 0); } = +static int +namecmp(Name arg1, Name arg2, Oid collid) +{ + /* Fast path for common case used in system catalogs */ + if (collid =3D=3D C_COLLATION_OID) + return strncmp(NameStr(*arg1), NameStr(*arg2), NAMEDATALEN); + + /* Else rely on the varstr infrastructure */ + return varstr_cmp(NameStr(*arg1), strlen(NameStr(*arg1)), + NameStr(*arg2), strlen(NameStr(*arg2)), + collid); +} + Datum namelt(PG_FUNCTION_ARGS) { Name arg1 =3D PG_GETARG_NAME(0); Name arg2 =3D PG_GETARG_NAME(1); = - PG_RETURN_BOOL(strncmp(NameStr(*arg1), NameStr(*arg2), NAMEDATALEN) < 0)= ; + PG_RETURN_BOOL(namecmp(arg1, arg2, PG_GET_COLLATION()) < 0); } = Datum @@ -163,7 +179,7 @@ namele(PG_FUNCTION_ARGS) Name arg1 =3D PG_GETARG_NAME(0); Name arg2 =3D PG_GETARG_NAME(1); = - PG_RETURN_BOOL(strncmp(NameStr(*arg1), NameStr(*arg2), NAMEDATALEN) <=3D= 0); + PG_RETURN_BOOL(namecmp(arg1, arg2, PG_GET_COLLATION()) <=3D 0); } = Datum @@ -172,7 +188,7 @@ namegt(PG_FUNCTION_ARGS) Name arg1 =3D PG_GETARG_NAME(0); Name arg2 =3D PG_GETARG_NAME(1); = - PG_RETURN_BOOL(strncmp(NameStr(*arg1), NameStr(*arg2), NAMEDATALEN) > 0)= ; + PG_RETURN_BOOL(namecmp(arg1, arg2, PG_GET_COLLATION()) > 0); } = Datum @@ -181,11 +197,39 @@ namege(PG_FUNCTION_ARGS) Name arg1 =3D PG_GETARG_NAME(0); Name arg2 =3D PG_GETARG_NAME(1); = - PG_RETURN_BOOL(strncmp(NameStr(*arg1), NameStr(*arg2), NAMEDATALEN) >=3D= 0); + PG_RETURN_BOOL(namecmp(arg1, arg2, PG_GET_COLLATION()) >=3D 0); +} + +Datum +btnamecmp(PG_FUNCTION_ARGS) +{ + Name arg1 =3D PG_GETARG_NAME(0); + Name arg2 =3D PG_GETARG_NAME(1); + + PG_RETURN_INT32(namecmp(arg1, arg2, PG_GET_COLLATION())); } = +Datum +btnamesortsupport(PG_FUNCTION_ARGS) +{ + SortSupport ssup =3D (SortSupport) PG_GETARG_POINTER(0); + Oid collid =3D ssup->ssup_collation; + MemoryContext oldcontext; + + oldcontext =3D MemoryContextSwitchTo(ssup->ssup_cxt); + + /* Use generic string SortSupport */ + varstr_sortsupport(ssup, NAMEOID, collid); = -/* (see char.c for comparison/operation routines) */ + MemoryContextSwitchTo(oldcontext); + + PG_RETURN_VOID(); +} + + +/************************************************************************= ***** + * MISCELLANEOUS PUBLIC ROUTINES * + ************************************************************************= *****/ = int namecpy(Name n1, const NameData *n2) @@ -204,14 +248,6 @@ namecat(Name n1, Name n2) } #endif = -#ifdef NOT_USED -int -namecmp(Name n1, Name n2) -{ - return strncmp(NameStr(*n1), NameStr(*n2), NAMEDATALEN); -} -#endif - int namestrcpy(Name name, const char *str) { @@ -243,6 +279,12 @@ namestrcat(Name name, const char *str) } #endif = +/* + * Compare a NAME to a C string + * + * Assumes C collation always; be careful when using this for + * anything but equality checks! + */ int namestrcmp(Name name, const char *str) { diff --git a/src/backend/utils/adt/selfuncs.c b/src/backend/utils/adt/self= uncs.c index c3db9ea..ebedb26 100644 --- a/src/backend/utils/adt/selfuncs.c +++ b/src/backend/utils/adt/selfuncs.c @@ -6341,23 +6341,16 @@ make_greater_string(const Const *str_const, FmgrIn= fo *ltproc, Oid collation) char *workstr; int len; Datum cmpstr; - text *cmptxt =3D NULL; + char *cmptxt =3D NULL; mbcharacter_incrementer charinc; = /* * Get a modifiable copy of the prefix string in C-string format, and se= t * up the string we will compare to as a Datum. In C locale this can ju= st - * be the given prefix string, otherwise we need to add a suffix. Types - * NAME and BYTEA sort bytewise so they don't need a suffix either. + * be the given prefix string, otherwise we need to add a suffix. Type + * BYTEA sorts bytewise so it never needs a suffix either. */ - if (datatype =3D=3D NAMEOID) - { - workstr =3D DatumGetCString(DirectFunctionCall1(nameout, - str_const->constvalue)); - len =3D strlen(workstr); - cmpstr =3D str_const->constvalue; - } - else if (datatype =3D=3D BYTEAOID) + if (datatype =3D=3D BYTEAOID) { bytea *bstr =3D DatumGetByteaPP(str_const->constvalue); = @@ -6369,7 +6362,11 @@ make_greater_string(const Const *str_const, FmgrInf= o *ltproc, Oid collation) } else { - workstr =3D TextDatumGetCString(str_const->constvalue); + if (datatype =3D=3D NAMEOID) + workstr =3D DatumGetCString(DirectFunctionCall1(nameout, + str_const->constvalue)); + else + workstr =3D TextDatumGetCString(str_const->constvalue); len =3D strlen(workstr); if (lc_collate_is_c(collation) || len =3D=3D 0) cmpstr =3D str_const->constvalue; @@ -6395,11 +6392,22 @@ make_greater_string(const Const *str_const, FmgrIn= fo *ltproc, Oid collation) } = /* And build the string to compare to */ - cmptxt =3D (text *) palloc(VARHDRSZ + len + 1); - SET_VARSIZE(cmptxt, VARHDRSZ + len + 1); - memcpy(VARDATA(cmptxt), workstr, len); - *(VARDATA(cmptxt) + len) =3D suffixchar; - cmpstr =3D PointerGetDatum(cmptxt); + if (datatype =3D=3D NAMEOID) + { + cmptxt =3D palloc(len + 2); + memcpy(cmptxt, workstr, len); + cmptxt[len] =3D suffixchar; + cmptxt[len + 1] =3D '\0'; + cmpstr =3D PointerGetDatum(cmptxt); + } + else + { + cmptxt =3D palloc(VARHDRSZ + len + 1); + SET_VARSIZE(cmptxt, VARHDRSZ + len + 1); + memcpy(VARDATA(cmptxt), workstr, len); + *(VARDATA(cmptxt) + len) =3D suffixchar; + cmpstr =3D PointerGetDatum(cmptxt); + } } } = @@ -6518,7 +6526,7 @@ string_to_const(const char *str, Oid datatype) break; = case NAMEOID: - collation =3D InvalidOid; + collation =3D C_COLLATION_OID; constlen =3D NAMEDATALEN; break; = diff --git a/src/backend/utils/adt/varchar.c b/src/backend/utils/adt/varch= ar.c index 8f07b1e..d5a5800 100644 --- a/src/backend/utils/adt/varchar.c +++ b/src/backend/utils/adt/varchar.c @@ -18,6 +18,7 @@ #include "access/hash.h" #include "access/tuptoaster.h" #include "catalog/pg_collation.h" +#include "catalog/pg_type.h" #include "libpq/pqformat.h" #include "nodes/nodeFuncs.h" #include "utils/array.h" @@ -876,7 +877,7 @@ bpchar_sortsupport(PG_FUNCTION_ARGS) oldcontext =3D MemoryContextSwitchTo(ssup->ssup_cxt); = /* Use generic string SortSupport */ - varstr_sortsupport(ssup, collid, true); + varstr_sortsupport(ssup, BPCHAROID, collid); = MemoryContextSwitchTo(oldcontext); = @@ -1085,7 +1086,7 @@ btbpchar_pattern_sortsupport(PG_FUNCTION_ARGS) oldcontext =3D MemoryContextSwitchTo(ssup->ssup_cxt); = /* Use generic string SortSupport, forcing "C" collation */ - varstr_sortsupport(ssup, C_COLLATION_OID, true); + varstr_sortsupport(ssup, BPCHAROID, C_COLLATION_OID); = MemoryContextSwitchTo(oldcontext); = diff --git a/src/backend/utils/adt/varlena.c b/src/backend/utils/adt/varle= na.c index 0fd3b15..a4fb588 100644 --- a/src/backend/utils/adt/varlena.c +++ b/src/backend/utils/adt/varlena.c @@ -69,7 +69,7 @@ typedef struct int last_returned; /* Last comparison result (cache) */ bool cache_blob; /* Does buf2 contain strxfrm() blob, etc? */ bool collate_c; - bool bpchar; /* Sorting bpchar, not varchar/text/bytea? */ + Oid typeid; /* Actual datatype (text/bpchar/bytea/name) */ hyperLogLogState abbr_card; /* Abbreviated key cardinality state */ hyperLogLogState full_card; /* Full key cardinality state */ double prop_card; /* Required cardinality proportion */ @@ -93,7 +93,10 @@ typedef struct = static int varstrfastcmp_c(Datum x, Datum y, SortSupport ssup); static int bpcharfastcmp_c(Datum x, Datum y, SortSupport ssup); -static int varstrfastcmp_locale(Datum x, Datum y, SortSupport ssup); +static int namefastcmp_c(Datum x, Datum y, SortSupport ssup); +static int varlenafastcmp_locale(Datum x, Datum y, SortSupport ssup); +static int namefastcmp_locale(Datum x, Datum y, SortSupport ssup); +static int varstrfastcmp_locale(char *a1p, int len1, char *a2p, int len2,= SortSupport ssup); static int varstrcmp_abbrev(Datum x, Datum y, SortSupport ssup); static Datum varstr_abbrev_convert(Datum original, SortSupport ssup); static bool varstr_abbrev_abort(int memtupcount, SortSupport ssup); @@ -1814,7 +1817,7 @@ bttextsortsupport(PG_FUNCTION_ARGS) oldcontext =3D MemoryContextSwitchTo(ssup->ssup_cxt); = /* Use generic string SortSupport */ - varstr_sortsupport(ssup, collid, false); + varstr_sortsupport(ssup, TEXTOID, collid); = MemoryContextSwitchTo(oldcontext); = @@ -1832,7 +1835,7 @@ bttextsortsupport(PG_FUNCTION_ARGS) * this will not work with any other collation, though. */ void -varstr_sortsupport(SortSupport ssup, Oid collid, bool bpchar) +varstr_sortsupport(SortSupport ssup, Oid typeid, Oid collid) { bool abbreviate =3D ssup->abbreviate; bool collate_c =3D false; @@ -1845,18 +1848,25 @@ varstr_sortsupport(SortSupport ssup, Oid collid, b= ool bpchar) * overhead of a trip through the fmgr layer for every comparison, which * can be substantial. * - * Most typically, we'll set the comparator to varstrfastcmp_locale, whi= ch - * uses strcoll() to perform comparisons and knows about the special - * requirements of BpChar callers. However, if LC_COLLATE =3D C, we can - * make things quite a bit faster with varstrfastcmp_c or bpcharfastcmp_= c, - * both of which use memcmp() rather than strcoll(). + * Most typically, we'll set the comparator to varlenafastcmp_locale, + * which uses strcoll() to perform comparisons. We use that for the + * BpChar case too, but type NAME uses namefastcmp_locale. However, if + * LC_COLLATE =3D C, we can make things quite a bit faster with + * varstrfastcmp_c, bpcharfastcmp_c, or namefastcmp_c, all of which use + * memcmp() rather than strcoll(). */ if (lc_collate_is_c(collid)) { - if (!bpchar) - ssup->comparator =3D varstrfastcmp_c; - else + if (typeid =3D=3D BPCHAROID) ssup->comparator =3D bpcharfastcmp_c; + else if (typeid =3D=3D NAMEOID) + { + ssup->comparator =3D namefastcmp_c; + /* Not supporting abbreviation with type NAME, for now */ + abbreviate =3D false; + } + else + ssup->comparator =3D varstrfastcmp_c; = collate_c =3D true; } @@ -1897,7 +1907,17 @@ varstr_sortsupport(SortSupport ssup, Oid collid, bo= ol bpchar) return; #endif = - ssup->comparator =3D varstrfastcmp_locale; + /* + * We use varlenafastcmp_locale except for type NAME. + */ + if (typeid =3D=3D NAMEOID) + { + ssup->comparator =3D namefastcmp_locale; + /* Not supporting abbreviation with type NAME, for now */ + abbreviate =3D false; + } + else + ssup->comparator =3D varlenafastcmp_locale; } = /* @@ -1963,7 +1983,7 @@ varstr_sortsupport(SortSupport ssup, Oid collid, boo= l bpchar) */ sss->cache_blob =3D true; sss->collate_c =3D collate_c; - sss->bpchar =3D bpchar; + sss->typeid =3D typeid; ssup->ssup_extra =3D sss; = /* @@ -2055,17 +2075,25 @@ bpcharfastcmp_c(Datum x, Datum y, SortSupport ssup= ) } = /* - * sortsupport comparison func (for locale case) + * sortsupport comparison func (for NAME C locale case) + */ +static int +namefastcmp_c(Datum x, Datum y, SortSupport ssup) +{ + Name arg1 =3D DatumGetName(x); + Name arg2 =3D DatumGetName(y); + + return strncmp(NameStr(*arg1), NameStr(*arg2), NAMEDATALEN); +} + +/* + * sortsupport comparison func (for locale case with all varlena types) */ static int -varstrfastcmp_locale(Datum x, Datum y, SortSupport ssup) +varlenafastcmp_locale(Datum x, Datum y, SortSupport ssup) { VarString *arg1 =3D DatumGetVarStringPP(x); VarString *arg2 =3D DatumGetVarStringPP(y); - bool arg1_match; - VarStringSortSupport *sss =3D (VarStringSortSupport *) ssup->ssup_extra; - - /* working state */ char *a1p, *a2p; int len1, @@ -2078,6 +2106,41 @@ varstrfastcmp_locale(Datum x, Datum y, SortSupport = ssup) len1 =3D VARSIZE_ANY_EXHDR(arg1); len2 =3D VARSIZE_ANY_EXHDR(arg2); = + result =3D varstrfastcmp_locale(a1p, len1, a2p, len2, ssup); + + /* We can't afford to leak memory here. */ + if (PointerGetDatum(arg1) !=3D x) + pfree(arg1); + if (PointerGetDatum(arg2) !=3D y) + pfree(arg2); + + return result; +} + +/* + * sortsupport comparison func (for locale case with NAME type) + */ +static int +namefastcmp_locale(Datum x, Datum y, SortSupport ssup) +{ + Name arg1 =3D DatumGetName(x); + Name arg2 =3D DatumGetName(y); + + return varstrfastcmp_locale(NameStr(*arg1), strlen(NameStr(*arg1)), + NameStr(*arg2), strlen(NameStr(*arg2)), + ssup); +} + +/* + * sortsupport comparison func for locale cases + */ +static int +varstrfastcmp_locale(char *a1p, int len1, char *a2p, int len2, SortSuppor= t ssup) +{ + VarStringSortSupport *sss =3D (VarStringSortSupport *) ssup->ssup_extra; + int result; + bool arg1_match; + /* Fast pre-check for equality, as discussed in varstr_cmp() */ if (len1 =3D=3D len2 && memcmp(a1p, a2p, len1) =3D=3D 0) { @@ -2094,11 +2157,10 @@ varstrfastcmp_locale(Datum x, Datum y, SortSupport= ssup) * (not limited to padding), so we need make no distinction between * padding space characters and "real" space characters. */ - result =3D 0; - goto done; + return 0; } = - if (sss->bpchar) + if (sss->typeid =3D=3D BPCHAROID) { /* Get true number of bytes, ignoring trailing spaces */ len1 =3D bpchartruelen(a1p, len1); @@ -2152,8 +2214,7 @@ varstrfastcmp_locale(Datum x, Datum y, SortSupport s= sup) else if (arg1_match && !sss->cache_blob) { /* Use result cached following last actual strcoll() call */ - result =3D sss->last_returned; - goto done; + return sss->last_returned; } = if (sss->locale) @@ -2222,13 +2283,6 @@ varstrfastcmp_locale(Datum x, Datum y, SortSupport = ssup) /* Cache result, perhaps saving an expensive strcoll() call next time */ sss->cache_blob =3D false; sss->last_returned =3D result; -done: - /* We can't afford to leak memory here. */ - if (PointerGetDatum(arg1) !=3D x) - pfree(arg1); - if (PointerGetDatum(arg2) !=3D y) - pfree(arg2); - return result; } = @@ -2240,7 +2294,7 @@ varstrcmp_abbrev(Datum x, Datum y, SortSupport ssup) { /* * When 0 is returned, the core system will call varstrfastcmp_c() - * (bpcharfastcmp_c() in BpChar case) or varstrfastcmp_locale(). Even a + * (bpcharfastcmp_c() in BpChar case) or varlenafastcmp_locale(). Even = a * strcmp() on two non-truncated strxfrm() blobs cannot indicate *equali= ty* * authoritatively, for the same reason that there is a strcoll() * tie-breaker call to strcmp() in varstr_cmp(). @@ -2279,7 +2333,7 @@ varstr_abbrev_convert(Datum original, SortSupport ss= up) len =3D VARSIZE_ANY_EXHDR(authoritative); = /* Get number of bytes, ignoring trailing spaces */ - if (sss->bpchar) + if (sss->typeid =3D=3D BPCHAROID) len =3D bpchartruelen(authoritative_data, len); = /* @@ -2758,7 +2812,7 @@ bttext_pattern_sortsupport(PG_FUNCTION_ARGS) oldcontext =3D MemoryContextSwitchTo(ssup->ssup_cxt); = /* Use generic string SortSupport, forcing "C" collation */ - varstr_sortsupport(ssup, C_COLLATION_OID, false); + varstr_sortsupport(ssup, TEXTOID, C_COLLATION_OID); = MemoryContextSwitchTo(oldcontext); = @@ -3798,7 +3852,7 @@ bytea_sortsupport(PG_FUNCTION_ARGS) oldcontext =3D MemoryContextSwitchTo(ssup->ssup_cxt); = /* Use generic string SortSupport, forcing "C" collation */ - varstr_sortsupport(ssup, C_COLLATION_OID, false); + varstr_sortsupport(ssup, BYTEAOID, C_COLLATION_OID); = MemoryContextSwitchTo(oldcontext); = diff --git a/src/include/catalog/pg_type.dat b/src/include/catalog/pg_type= .dat index d295eae..7bca400 100644 --- a/src/include/catalog/pg_type.dat +++ b/src/include/catalog/pg_type.dat @@ -54,7 +54,7 @@ typname =3D> 'name', typlen =3D> 'NAMEDATALEN', typbyval =3D> 'f', typcategory =3D> 'S', typelem =3D> 'char', typinput =3D> 'namein', typoutput =3D> 'nameout', typreceive =3D> 'namerecv', typsend =3D> 'nam= esend', - typalign =3D> 'c' }, + typalign =3D> 'c', typcollation =3D> '950' }, { oid =3D> '20', array_type_oid =3D> '1016', descr =3D> '~18 digit integer, 8-byte storage', typname =3D> 'int8', typlen =3D> '8', typbyval =3D> 'FLOAT8PASSBYVAL', diff --git a/src/include/catalog/pg_type.h b/src/include/catalog/pg_type.h index 05185dd..43bc08e 100644 --- a/src/include/catalog/pg_type.h +++ b/src/include/catalog/pg_type.h @@ -211,8 +211,9 @@ CATALOG(pg_type,1247,TypeRelationId) BKI_BOOTSTRAP BKI= _ROWTYPE_OID(71,TypeRelati int32 typndims BKI_DEFAULT(0); = /* - * Collation: 0 if type cannot use collations, DEFAULT_COLLATION_OID for - * collatable base types, possibly other OID for domains + * Collation: 0 if type cannot use collations, nonzero (typically + * DEFAULT_COLLATION_OID) for collatable base types, possibly some other + * OID for domains over collatable types */ Oid typcollation BKI_DEFAULT(0); = diff --git a/src/include/utils/varlena.h b/src/include/utils/varlena.h index c776931..ee3e205 100644 --- a/src/include/utils/varlena.h +++ b/src/include/utils/varlena.h @@ -17,7 +17,7 @@ #include "utils/sortsupport.h" = extern int varstr_cmp(const char *arg1, int len1, const char *arg2, int l= en2, Oid collid); -extern void varstr_sortsupport(SortSupport ssup, Oid collid, bool bpchar)= ; +extern void varstr_sortsupport(SortSupport ssup, Oid typeid, Oid collid); extern int varstr_levenshtein(const char *source, int slen, const char *target, int tlen, int ins_c, int del_c, int sub_c, diff --git a/src/pl/plpgsql/src/pl_comp.c b/src/pl/plpgsql/src/pl_comp.c index 8bacc74..fb3fb5b 100644 --- a/src/pl/plpgsql/src/pl_comp.c +++ b/src/pl/plpgsql/src/pl_comp.c @@ -607,7 +607,7 @@ do_compile(FunctionCallInfo fcinfo, var =3D plpgsql_build_variable("tg_name", 0, plpgsql_build_datatype(NAMEOID, -1, - InvalidOid), + function->fn_input_collation), true); Assert(var->dtype =3D=3D PLPGSQL_DTYPE_VAR); var->dtype =3D PLPGSQL_DTYPE_PROMISE; @@ -657,7 +657,7 @@ do_compile(FunctionCallInfo fcinfo, var =3D plpgsql_build_variable("tg_relname", 0, plpgsql_build_datatype(NAMEOID, -1, - InvalidOid), + function->fn_input_collation), true); Assert(var->dtype =3D=3D PLPGSQL_DTYPE_VAR); var->dtype =3D PLPGSQL_DTYPE_PROMISE; @@ -667,7 +667,7 @@ do_compile(FunctionCallInfo fcinfo, var =3D plpgsql_build_variable("tg_table_name", 0, plpgsql_build_datatype(NAMEOID, -1, - InvalidOid), + function->fn_input_collation), true); Assert(var->dtype =3D=3D PLPGSQL_DTYPE_VAR); var->dtype =3D PLPGSQL_DTYPE_PROMISE; @@ -677,7 +677,7 @@ do_compile(FunctionCallInfo fcinfo, var =3D plpgsql_build_variable("tg_table_schema", 0, plpgsql_build_datatype(NAMEOID, -1, - InvalidOid), + function->fn_input_collation), true); Assert(var->dtype =3D=3D PLPGSQL_DTYPE_VAR); var->dtype =3D PLPGSQL_DTYPE_PROMISE; ------- =_aaaaaaaaaa0--