1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-07 00:36:50 +03:00

Make type "name" collation-aware.

The "name" comparison operators now all support collations, making them
functionally equivalent to "text" comparisons, except for the different
physical representation of the datatype.  They do, in fact, mostly share
the varstr_cmp and varstr_sortsupport infrastructure, which has been
slightly enlarged to handle the case.

To avoid changes in the default behavior of the datatype, set name's
typcollation to C_COLLATION_OID not DEFAULT_COLLATION_OID, so that
by default comparisons to a name value will continue to use strcmp
semantics.  (This would have been the case for system catalog columns
anyway, because of commit 6b0faf723, but doing this makes it true for
user-created name columns as well.  In particular, this avoids
locale-dependent changes in our regression test results.)

In consequence, tweak a couple of places that made assumptions about
collatable base types always having typcollation DEFAULT_COLLATION_OID.
I have not, however, attempted to relax the restriction that user-
defined collatable types must have that.  Hence, "name" doesn't
behave quite like a user-defined type; it acts more like a domain
with COLLATE "C".  (Conceivably, if we ever get rid of the need for
catalog name columns to be fixed-length, "name" could actually become
such a domain over text.  But that'd be a pretty massive undertaking,
and I'm not volunteering.)

Discussion: https://postgr.es/m/15938.1544377821@sss.pgh.pa.us
This commit is contained in:
Tom Lane
2018-12-19 17:35:12 -05:00
parent 68f6f2b739
commit 586b98fdf1
16 changed files with 211 additions and 125 deletions

View File

@ -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);
MemoryContextSwitchTo(oldcontext);
PG_RETURN_VOID();
}
/* (see char.c for comparison/operation routines) */
/*****************************************************************************
* 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)
{