From: Tom Lane <tgl@sss.pgh.pa.us>
To: Robert Haas <robertmhaas@gmail.com>
Cc: PostgreSQL Hackers <pgsql-hackers@lists.postgresql.org>
Subject: Re: Collatability of type "name"
Date: Wed, 19 Dec 2018 14:02:07 -0500
Message-ID: <18204.1545246127@sss.pgh.pa.us> (raw)
In-Reply-To: <21253.1545170114@sss.pgh.pa.us>
References: <15938.1544377821@sss.pgh.pa.us>
<CA+TgmoZJ5_-0s8ekitepGxdzG12em0LOt9cKaPA9UpZRY_On_w@mail.gmail.com>
<21253.1545170114@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
Attachments:make-type-name-collatable-2.patch (text/x-diff, 26.0K) downloaddiff --git a/doc/src/sgml/catalogs.sgml b/doc/src/sgml/catalogs.sgmlindex 8d0cab5..af4d062 100644--- a/doc/src/sgml/catalogs.sgml+++ b/doc/src/sgml/catalogs.sgml@@ -7866,10 +7866,10 @@ SCRAM-SHA-256$<replaceable><iteration count></replaceable>:<replaceable>&l
<entry><para>
<structfield>typcollation</structfield> 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- <symbol>DEFAULT_COLLATION_OID</symbol> 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 <symbol>DEFAULT_COLLATION_OID</symbol>.+ A domain over a collatable type can have a collation OID different+ from its base type's, if one was specified for the domain.
</para></entry>
</row>
diff --git a/src/backend/access/nbtree/nbtcompare.c b/src/backend/access/nbtree/nbtcompare.cindex 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 = PG_GETARG_NAME(0);- Name b = PG_GETARG_NAME(1);-- PG_RETURN_INT32(strncmp(NameStr(*a), NameStr(*b), NAMEDATALEN));-}--static int-btnamefastcmp(Datum x, Datum y, SortSupport ssup)-{- Name a = DatumGetName(x);- Name b = DatumGetName(y);-- return strncmp(NameStr(*a), NameStr(*b), NAMEDATALEN);-}--Datum-btnamesortsupport(PG_FUNCTION_ARGS)-{- SortSupport ssup = (SortSupport) PG_GETARG_POINTER(0);-- ssup->comparator = btnamefastcmp;- PG_RETURN_VOID();-}diff --git a/src/backend/bootstrap/bootstrap.c b/src/backend/bootstrap/bootstrap.cindex 8e42255..fc1927c 100644--- a/src/backend/bootstrap/bootstrap.c+++ b/src/backend/bootstrap/bootstrap.c@@ -111,7 +111,7 @@ static const struct typinfo TypInfo[] = {
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.cindex 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 *sortexpr,
TYPECACHE_LT_OPR | TYPECACHE_GT_OPR);
/*
- * Print COLLATE if it's not default. There are some cases where this is- * 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 whose+ * declared collation is that collation, but it's hard to distinguish that+ * here (and arguably, printing COLLATE explicitly is a good idea anyway+ * in such cases).
*/
- if (OidIsValid(collation) && collation != DEFAULT_COLLATION_OID)+ if (OidIsValid(collation) && collation != get_typcollation(sortcoltype))
{
char *collname = get_collation_name(collation);
diff --git a/src/backend/nodes/nodeFuncs.c b/src/backend/nodes/nodeFuncs.cindex 54b3dcf..a813e38 100644--- a/src/backend/nodes/nodeFuncs.c+++ b/src/backend/nodes/nodeFuncs.c@@ -862,7 +862,11 @@ exprCollation(const Node *expr)
coll = ((const MinMaxExpr *) expr)->minmaxcollid;
break;
case T_SQLValueFunction:
- coll = InvalidOid; /* all cases return non-collatable types */+ /* Returns either NAME or a non-collatable type */+ if (((const SQLValueFunction *) expr)->type == NAMEOID)+ coll = C_COLLATION_OID;+ else+ coll = InvalidOid;
break;
case T_XmlExpr:
@@ -1075,7 +1079,9 @@ exprSetCollation(Node *expr, Oid collation)
((MinMaxExpr *) expr)->minmaxcollid = collation;
break;
case T_SQLValueFunction:
- Assert(!OidIsValid(collation)); /* no collatable results */+ Assert((((SQLValueFunction *) expr)->type == NAMEOID) ?+ (collation == C_COLLATION_OID) :+ (collation == InvalidOid));
break;
case T_XmlExpr:
Assert((((XmlExpr *) expr)->op == IS_XMLSERIALIZE) ?
diff --git a/src/backend/optimizer/path/indxpath.c b/src/backend/optimizer/path/indxpath.cindex 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 = InvalidOid;+ collation = C_COLLATION_OID;
constlen = NAMEDATALEN;
break;
diff --git a/src/backend/parser/parse_clause.c b/src/backend/parser/parse_clause.cindex 4ba5120..2099724 100644--- a/src/backend/parser/parse_clause.c+++ b/src/backend/parser/parse_clause.c@@ -788,7 +788,7 @@ transformRangeTableFunc(ParseState *pstate, RangeTableFunc *rtf)
tf->coltypes = lappend_oid(tf->coltypes, typid);
tf->coltypmods = lappend_int(tf->coltypmods, typmod);
tf->colcollations = 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.cindex 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 <= b
* namegt - returns 1 iff a > b
* namege - returns 1 iff a >= b
*
+ * Note that the use of strncmp with NAMEDATALEN limit is mostly historical;+ * 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 = PG_GETARG_NAME(0);
Name arg2 = PG_GETARG_NAME(1);
+ /* Collation doesn't matter: equal only if bitwise-equal */
PG_RETURN_BOOL(strncmp(NameStr(*arg1), NameStr(*arg2), NAMEDATALEN) == 0);
}
@@ -145,16 +147,30 @@ namene(PG_FUNCTION_ARGS)
Name arg1 = PG_GETARG_NAME(0);
Name arg2 = PG_GETARG_NAME(1);
+ /* Collation doesn't matter: equal only if bitwise-equal */
PG_RETURN_BOOL(strncmp(NameStr(*arg1), NameStr(*arg2), NAMEDATALEN) != 0);
}
+static int+namecmp(Name arg1, Name arg2, Oid collid)+{+ /* Fast path for common case used in system catalogs */+ if (collid == 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 = PG_GETARG_NAME(0);
Name arg2 = 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 = PG_GETARG_NAME(0);
Name arg2 = 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
@@ -172,7 +188,7 @@ namegt(PG_FUNCTION_ARGS)
Name arg1 = PG_GETARG_NAME(0);
Name arg2 = 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 = PG_GETARG_NAME(0);
Name arg2 = 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+btnamecmp(PG_FUNCTION_ARGS)+{+ Name arg1 = PG_GETARG_NAME(0);+ Name arg2 = PG_GETARG_NAME(1);++ PG_RETURN_INT32(namecmp(arg1, arg2, PG_GET_COLLATION()));
}
+Datum+btnamesortsupport(PG_FUNCTION_ARGS)+{+ SortSupport ssup = (SortSupport) PG_GETARG_POINTER(0);+ Oid collid = ssup->ssup_collation;+ MemoryContext oldcontext;++ oldcontext = 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/selfuncs.cindex 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, FmgrInfo *ltproc, Oid collation)
char *workstr;
int len;
Datum cmpstr;
- text *cmptxt = NULL;+ char *cmptxt = NULL;
mbcharacter_incrementer charinc;
/*
* Get a modifiable copy of the prefix string in C-string format, and set
* up the string we will compare to as a Datum. In C locale this can just
- * 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 == NAMEOID)- {- workstr = DatumGetCString(DirectFunctionCall1(nameout,- str_const->constvalue));- len = strlen(workstr);- cmpstr = str_const->constvalue;- }- else if (datatype == BYTEAOID)+ if (datatype == BYTEAOID)
{
bytea *bstr = DatumGetByteaPP(str_const->constvalue);
@@ -6369,7 +6362,11 @@ make_greater_string(const Const *str_const, FmgrInfo *ltproc, Oid collation)
}
else
{
- workstr = TextDatumGetCString(str_const->constvalue);+ if (datatype == NAMEOID)+ workstr = DatumGetCString(DirectFunctionCall1(nameout,+ str_const->constvalue));+ else+ workstr = TextDatumGetCString(str_const->constvalue);
len = strlen(workstr);
if (lc_collate_is_c(collation) || len == 0)
cmpstr = str_const->constvalue;
@@ -6395,11 +6392,22 @@ make_greater_string(const Const *str_const, FmgrInfo *ltproc, Oid collation)
}
/* And build the string to compare to */
- cmptxt = (text *) palloc(VARHDRSZ + len + 1);- SET_VARSIZE(cmptxt, VARHDRSZ + len + 1);- memcpy(VARDATA(cmptxt), workstr, len);- *(VARDATA(cmptxt) + len) = suffixchar;- cmpstr = PointerGetDatum(cmptxt);+ if (datatype == NAMEOID)+ {+ cmptxt = palloc(len + 2);+ memcpy(cmptxt, workstr, len);+ cmptxt[len] = suffixchar;+ cmptxt[len + 1] = '\0';+ cmpstr = PointerGetDatum(cmptxt);+ }+ else+ {+ cmptxt = palloc(VARHDRSZ + len + 1);+ SET_VARSIZE(cmptxt, VARHDRSZ + len + 1);+ memcpy(VARDATA(cmptxt), workstr, len);+ *(VARDATA(cmptxt) + len) = suffixchar;+ cmpstr = PointerGetDatum(cmptxt);+ }
}
}
@@ -6518,7 +6526,7 @@ string_to_const(const char *str, Oid datatype)
break;
case NAMEOID:
- collation = InvalidOid;+ collation = C_COLLATION_OID;
constlen = NAMEDATALEN;
break;
diff --git a/src/backend/utils/adt/varchar.c b/src/backend/utils/adt/varchar.cindex 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 = 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 = 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/varlena.cindex 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 = 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 = ssup->abbreviate;
bool collate_c = false;
@@ -1845,18 +1848,25 @@ varstr_sortsupport(SortSupport ssup, Oid collid, bool 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, which- * uses strcoll() to perform comparisons and knows about the special- * requirements of BpChar callers. However, if LC_COLLATE = 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 = 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 = varstrfastcmp_c;- else+ if (typeid == BPCHAROID)
ssup->comparator = bpcharfastcmp_c;
+ else if (typeid == NAMEOID)+ {+ ssup->comparator = namefastcmp_c;+ /* Not supporting abbreviation with type NAME, for now */+ abbreviate = false;+ }+ else+ ssup->comparator = varstrfastcmp_c;
collate_c = true;
}
@@ -1897,7 +1907,17 @@ varstr_sortsupport(SortSupport ssup, Oid collid, bool bpchar)
return;
#endif
- ssup->comparator = varstrfastcmp_locale;+ /*+ * We use varlenafastcmp_locale except for type NAME.+ */+ if (typeid == NAMEOID)+ {+ ssup->comparator = namefastcmp_locale;+ /* Not supporting abbreviation with type NAME, for now */+ abbreviate = false;+ }+ else+ ssup->comparator = varlenafastcmp_locale;
}
/*
@@ -1963,7 +1983,7 @@ varstr_sortsupport(SortSupport ssup, Oid collid, bool bpchar)
*/
sss->cache_blob = true;
sss->collate_c = collate_c;
- sss->bpchar = bpchar;+ sss->typeid = typeid;
ssup->ssup_extra = 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 = DatumGetName(x);+ Name arg2 = 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 = DatumGetVarStringPP(x);
VarString *arg2 = DatumGetVarStringPP(y);
- bool arg1_match;- VarStringSortSupport *sss = (VarStringSortSupport *) ssup->ssup_extra;-- /* working state */
char *a1p,
*a2p;
int len1,
@@ -2078,6 +2106,41 @@ varstrfastcmp_locale(Datum x, Datum y, SortSupport ssup)
len1 = VARSIZE_ANY_EXHDR(arg1);
len2 = VARSIZE_ANY_EXHDR(arg2);
+ result = varstrfastcmp_locale(a1p, len1, a2p, len2, ssup);++ /* We can't afford to leak memory here. */+ if (PointerGetDatum(arg1) != x)+ pfree(arg1);+ if (PointerGetDatum(arg2) != 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 = DatumGetName(x);+ Name arg2 = 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, SortSupport ssup)+{+ VarStringSortSupport *sss = (VarStringSortSupport *) ssup->ssup_extra;+ int result;+ bool arg1_match;+
/* Fast pre-check for equality, as discussed in varstr_cmp() */
if (len1 == len2 && memcmp(a1p, a2p, len1) == 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 = 0;- goto done;+ return 0;
}
- if (sss->bpchar)+ if (sss->typeid == BPCHAROID)
{
/* Get true number of bytes, ignoring trailing spaces */
len1 = bpchartruelen(a1p, len1);
@@ -2152,8 +2214,7 @@ varstrfastcmp_locale(Datum x, Datum y, SortSupport ssup)
else if (arg1_match && !sss->cache_blob)
{
/* Use result cached following last actual strcoll() call */
- result = 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 = false;
sss->last_returned = result;
-done:- /* We can't afford to leak memory here. */- if (PointerGetDatum(arg1) != x)- pfree(arg1);- if (PointerGetDatum(arg2) != 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 *equality*
* 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 ssup)
len = VARSIZE_ANY_EXHDR(authoritative);
/* Get number of bytes, ignoring trailing spaces */
- if (sss->bpchar)+ if (sss->typeid == BPCHAROID)
len = bpchartruelen(authoritative_data, len);
/*
@@ -2758,7 +2812,7 @@ bttext_pattern_sortsupport(PG_FUNCTION_ARGS)
oldcontext = 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 = 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.datindex d295eae..7bca400 100644--- a/src/include/catalog/pg_type.dat+++ b/src/include/catalog/pg_type.dat@@ -54,7 +54,7 @@
typname => 'name', typlen => 'NAMEDATALEN', typbyval => 'f',
typcategory => 'S', typelem => 'char', typinput => 'namein',
typoutput => 'nameout', typreceive => 'namerecv', typsend => 'namesend',
- typalign => 'c' },+ typalign => 'c', typcollation => '950' },
{ oid => '20', array_type_oid => '1016',
descr => '~18 digit integer, 8-byte storage',
typname => 'int8', typlen => '8', typbyval => 'FLOAT8PASSBYVAL',
diff --git a/src/include/catalog/pg_type.h b/src/include/catalog/pg_type.hindex 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.hindex 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 len2, 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.cindex 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 = plpgsql_build_variable("tg_name", 0,
plpgsql_build_datatype(NAMEOID,
-1,
- InvalidOid),+ function->fn_input_collation),
true);
Assert(var->dtype == PLPGSQL_DTYPE_VAR);
var->dtype = PLPGSQL_DTYPE_PROMISE;
@@ -657,7 +657,7 @@ do_compile(FunctionCallInfo fcinfo,
var = plpgsql_build_variable("tg_relname", 0,
plpgsql_build_datatype(NAMEOID,
-1,
- InvalidOid),+ function->fn_input_collation),
true);
Assert(var->dtype == PLPGSQL_DTYPE_VAR);
var->dtype = PLPGSQL_DTYPE_PROMISE;
@@ -667,7 +667,7 @@ do_compile(FunctionCallInfo fcinfo,
var = plpgsql_build_variable("tg_table_name", 0,
plpgsql_build_datatype(NAMEOID,
-1,
- InvalidOid),+ function->fn_input_collation),
true);
Assert(var->dtype == PLPGSQL_DTYPE_VAR);
var->dtype = PLPGSQL_DTYPE_PROMISE;
@@ -677,7 +677,7 @@ do_compile(FunctionCallInfo fcinfo,
var = plpgsql_build_variable("tg_table_schema", 0,
plpgsql_build_datatype(NAMEOID,
-1,
- InvalidOid),+ function->fn_input_collation),
true);
Assert(var->dtype == PLPGSQL_DTYPE_VAR);
var->dtype = PLPGSQL_DTYPE_PROMISE;
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Reply to all the recipients using the --to and --cc options:
reply via email
To: pgsql-hackers@postgresql.org
Cc: tgl@sss.pgh.pa.us, robertmhaas@gmail.com, pgsql-hackers@lists.postgresql.org
Subject: Re: Collatability of type "name"
In-Reply-To: <18204.1545246127@sss.pgh.pa.us>
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
This inbox is served by DDX for PostgreSQL; see mirroring instructions
for how to clone and mirror all data and code used for this inbox