mirror of
https://git.postgresql.org/git/postgresql.git
synced 2024-12-15 08:20:16 +08:00
05d8449e73
This also involves renaming src/include/utils/hashutils.h, which becomes src/include/common/hashfn.h. Perhaps an argument can be made for keeping the hashutils.h name, but it seemed more consistent to make it match the name of the file, and also more descriptive of what is actually going on here. Patch by me, reviewed by Suraj Kharage and Mark Dilger. Off-list advice on how not to break the Windows build from Davinder Singh and Amit Kapila. Discussion: http://postgr.es/m/CA+TgmoaRiG4TXND8QuM6JXFRkM_1wL2ZNhzaUKsuec9-4yrkgw@mail.gmail.com
409 lines
8.4 KiB
C
409 lines
8.4 KiB
C
/*
|
|
* contrib/citext/citext.c
|
|
*/
|
|
#include "postgres.h"
|
|
|
|
#include "catalog/pg_collation.h"
|
|
#include "common/hashfn.h"
|
|
#include "utils/builtins.h"
|
|
#include "utils/formatting.h"
|
|
#include "utils/varlena.h"
|
|
|
|
PG_MODULE_MAGIC;
|
|
|
|
/*
|
|
* ====================
|
|
* FORWARD DECLARATIONS
|
|
* ====================
|
|
*/
|
|
|
|
static int32 citextcmp(text *left, text *right, Oid collid);
|
|
static int32 internal_citext_pattern_cmp(text *left, text *right, Oid collid);
|
|
|
|
/*
|
|
* =================
|
|
* UTILITY FUNCTIONS
|
|
* =================
|
|
*/
|
|
|
|
/*
|
|
* citextcmp()
|
|
* Internal comparison function for citext strings.
|
|
* Returns int32 negative, zero, or positive.
|
|
*/
|
|
static int32
|
|
citextcmp(text *left, text *right, Oid collid)
|
|
{
|
|
char *lcstr,
|
|
*rcstr;
|
|
int32 result;
|
|
|
|
/*
|
|
* We must do our str_tolower calls with DEFAULT_COLLATION_OID, not the
|
|
* input collation as you might expect. This is so that the behavior of
|
|
* citext's equality and hashing functions is not collation-dependent. We
|
|
* should change this once the core infrastructure is able to cope with
|
|
* collation-dependent equality and hashing functions.
|
|
*/
|
|
|
|
lcstr = str_tolower(VARDATA_ANY(left), VARSIZE_ANY_EXHDR(left), DEFAULT_COLLATION_OID);
|
|
rcstr = str_tolower(VARDATA_ANY(right), VARSIZE_ANY_EXHDR(right), DEFAULT_COLLATION_OID);
|
|
|
|
result = varstr_cmp(lcstr, strlen(lcstr),
|
|
rcstr, strlen(rcstr),
|
|
collid);
|
|
|
|
pfree(lcstr);
|
|
pfree(rcstr);
|
|
|
|
return result;
|
|
}
|
|
|
|
/*
|
|
* citext_pattern_cmp()
|
|
* Internal character-by-character comparison function for citext strings.
|
|
* Returns int32 negative, zero, or positive.
|
|
*/
|
|
static int32
|
|
internal_citext_pattern_cmp(text *left, text *right, Oid collid)
|
|
{
|
|
char *lcstr,
|
|
*rcstr;
|
|
int llen,
|
|
rlen;
|
|
int32 result;
|
|
|
|
lcstr = str_tolower(VARDATA_ANY(left), VARSIZE_ANY_EXHDR(left), DEFAULT_COLLATION_OID);
|
|
rcstr = str_tolower(VARDATA_ANY(right), VARSIZE_ANY_EXHDR(right), DEFAULT_COLLATION_OID);
|
|
|
|
llen = strlen(lcstr);
|
|
rlen = strlen(rcstr);
|
|
|
|
result = memcmp((void *) lcstr, (void *) rcstr, Min(llen, rlen));
|
|
if (result == 0)
|
|
{
|
|
if (llen < rlen)
|
|
result = -1;
|
|
else if (llen > rlen)
|
|
result = 1;
|
|
}
|
|
|
|
pfree(lcstr);
|
|
pfree(rcstr);
|
|
|
|
return result;
|
|
}
|
|
|
|
/*
|
|
* ==================
|
|
* INDEXING FUNCTIONS
|
|
* ==================
|
|
*/
|
|
|
|
PG_FUNCTION_INFO_V1(citext_cmp);
|
|
|
|
Datum
|
|
citext_cmp(PG_FUNCTION_ARGS)
|
|
{
|
|
text *left = PG_GETARG_TEXT_PP(0);
|
|
text *right = PG_GETARG_TEXT_PP(1);
|
|
int32 result;
|
|
|
|
result = citextcmp(left, right, PG_GET_COLLATION());
|
|
|
|
PG_FREE_IF_COPY(left, 0);
|
|
PG_FREE_IF_COPY(right, 1);
|
|
|
|
PG_RETURN_INT32(result);
|
|
}
|
|
|
|
PG_FUNCTION_INFO_V1(citext_pattern_cmp);
|
|
|
|
Datum
|
|
citext_pattern_cmp(PG_FUNCTION_ARGS)
|
|
{
|
|
text *left = PG_GETARG_TEXT_PP(0);
|
|
text *right = PG_GETARG_TEXT_PP(1);
|
|
int32 result;
|
|
|
|
result = internal_citext_pattern_cmp(left, right, PG_GET_COLLATION());
|
|
|
|
PG_FREE_IF_COPY(left, 0);
|
|
PG_FREE_IF_COPY(right, 1);
|
|
|
|
PG_RETURN_INT32(result);
|
|
}
|
|
|
|
PG_FUNCTION_INFO_V1(citext_hash);
|
|
|
|
Datum
|
|
citext_hash(PG_FUNCTION_ARGS)
|
|
{
|
|
text *txt = PG_GETARG_TEXT_PP(0);
|
|
char *str;
|
|
Datum result;
|
|
|
|
str = str_tolower(VARDATA_ANY(txt), VARSIZE_ANY_EXHDR(txt), DEFAULT_COLLATION_OID);
|
|
result = hash_any((unsigned char *) str, strlen(str));
|
|
pfree(str);
|
|
|
|
/* Avoid leaking memory for toasted inputs */
|
|
PG_FREE_IF_COPY(txt, 0);
|
|
|
|
PG_RETURN_DATUM(result);
|
|
}
|
|
|
|
PG_FUNCTION_INFO_V1(citext_hash_extended);
|
|
|
|
Datum
|
|
citext_hash_extended(PG_FUNCTION_ARGS)
|
|
{
|
|
text *txt = PG_GETARG_TEXT_PP(0);
|
|
uint64 seed = PG_GETARG_INT64(1);
|
|
char *str;
|
|
Datum result;
|
|
|
|
str = str_tolower(VARDATA_ANY(txt), VARSIZE_ANY_EXHDR(txt), DEFAULT_COLLATION_OID);
|
|
result = hash_any_extended((unsigned char *) str, strlen(str), seed);
|
|
pfree(str);
|
|
|
|
/* Avoid leaking memory for toasted inputs */
|
|
PG_FREE_IF_COPY(txt, 0);
|
|
|
|
PG_RETURN_DATUM(result);
|
|
}
|
|
|
|
/*
|
|
* ==================
|
|
* OPERATOR FUNCTIONS
|
|
* ==================
|
|
*/
|
|
|
|
PG_FUNCTION_INFO_V1(citext_eq);
|
|
|
|
Datum
|
|
citext_eq(PG_FUNCTION_ARGS)
|
|
{
|
|
text *left = PG_GETARG_TEXT_PP(0);
|
|
text *right = PG_GETARG_TEXT_PP(1);
|
|
char *lcstr,
|
|
*rcstr;
|
|
bool result;
|
|
|
|
/* We can't compare lengths in advance of downcasing ... */
|
|
|
|
lcstr = str_tolower(VARDATA_ANY(left), VARSIZE_ANY_EXHDR(left), DEFAULT_COLLATION_OID);
|
|
rcstr = str_tolower(VARDATA_ANY(right), VARSIZE_ANY_EXHDR(right), DEFAULT_COLLATION_OID);
|
|
|
|
/*
|
|
* Since we only care about equality or not-equality, we can avoid all the
|
|
* expense of strcoll() here, and just do bitwise comparison.
|
|
*/
|
|
result = (strcmp(lcstr, rcstr) == 0);
|
|
|
|
pfree(lcstr);
|
|
pfree(rcstr);
|
|
PG_FREE_IF_COPY(left, 0);
|
|
PG_FREE_IF_COPY(right, 1);
|
|
|
|
PG_RETURN_BOOL(result);
|
|
}
|
|
|
|
PG_FUNCTION_INFO_V1(citext_ne);
|
|
|
|
Datum
|
|
citext_ne(PG_FUNCTION_ARGS)
|
|
{
|
|
text *left = PG_GETARG_TEXT_PP(0);
|
|
text *right = PG_GETARG_TEXT_PP(1);
|
|
char *lcstr,
|
|
*rcstr;
|
|
bool result;
|
|
|
|
/* We can't compare lengths in advance of downcasing ... */
|
|
|
|
lcstr = str_tolower(VARDATA_ANY(left), VARSIZE_ANY_EXHDR(left), DEFAULT_COLLATION_OID);
|
|
rcstr = str_tolower(VARDATA_ANY(right), VARSIZE_ANY_EXHDR(right), DEFAULT_COLLATION_OID);
|
|
|
|
/*
|
|
* Since we only care about equality or not-equality, we can avoid all the
|
|
* expense of strcoll() here, and just do bitwise comparison.
|
|
*/
|
|
result = (strcmp(lcstr, rcstr) != 0);
|
|
|
|
pfree(lcstr);
|
|
pfree(rcstr);
|
|
PG_FREE_IF_COPY(left, 0);
|
|
PG_FREE_IF_COPY(right, 1);
|
|
|
|
PG_RETURN_BOOL(result);
|
|
}
|
|
|
|
PG_FUNCTION_INFO_V1(citext_lt);
|
|
|
|
Datum
|
|
citext_lt(PG_FUNCTION_ARGS)
|
|
{
|
|
text *left = PG_GETARG_TEXT_PP(0);
|
|
text *right = PG_GETARG_TEXT_PP(1);
|
|
bool result;
|
|
|
|
result = citextcmp(left, right, PG_GET_COLLATION()) < 0;
|
|
|
|
PG_FREE_IF_COPY(left, 0);
|
|
PG_FREE_IF_COPY(right, 1);
|
|
|
|
PG_RETURN_BOOL(result);
|
|
}
|
|
|
|
PG_FUNCTION_INFO_V1(citext_le);
|
|
|
|
Datum
|
|
citext_le(PG_FUNCTION_ARGS)
|
|
{
|
|
text *left = PG_GETARG_TEXT_PP(0);
|
|
text *right = PG_GETARG_TEXT_PP(1);
|
|
bool result;
|
|
|
|
result = citextcmp(left, right, PG_GET_COLLATION()) <= 0;
|
|
|
|
PG_FREE_IF_COPY(left, 0);
|
|
PG_FREE_IF_COPY(right, 1);
|
|
|
|
PG_RETURN_BOOL(result);
|
|
}
|
|
|
|
PG_FUNCTION_INFO_V1(citext_gt);
|
|
|
|
Datum
|
|
citext_gt(PG_FUNCTION_ARGS)
|
|
{
|
|
text *left = PG_GETARG_TEXT_PP(0);
|
|
text *right = PG_GETARG_TEXT_PP(1);
|
|
bool result;
|
|
|
|
result = citextcmp(left, right, PG_GET_COLLATION()) > 0;
|
|
|
|
PG_FREE_IF_COPY(left, 0);
|
|
PG_FREE_IF_COPY(right, 1);
|
|
|
|
PG_RETURN_BOOL(result);
|
|
}
|
|
|
|
PG_FUNCTION_INFO_V1(citext_ge);
|
|
|
|
Datum
|
|
citext_ge(PG_FUNCTION_ARGS)
|
|
{
|
|
text *left = PG_GETARG_TEXT_PP(0);
|
|
text *right = PG_GETARG_TEXT_PP(1);
|
|
bool result;
|
|
|
|
result = citextcmp(left, right, PG_GET_COLLATION()) >= 0;
|
|
|
|
PG_FREE_IF_COPY(left, 0);
|
|
PG_FREE_IF_COPY(right, 1);
|
|
|
|
PG_RETURN_BOOL(result);
|
|
}
|
|
|
|
PG_FUNCTION_INFO_V1(citext_pattern_lt);
|
|
|
|
Datum
|
|
citext_pattern_lt(PG_FUNCTION_ARGS)
|
|
{
|
|
text *left = PG_GETARG_TEXT_PP(0);
|
|
text *right = PG_GETARG_TEXT_PP(1);
|
|
bool result;
|
|
|
|
result = internal_citext_pattern_cmp(left, right, PG_GET_COLLATION()) < 0;
|
|
|
|
PG_FREE_IF_COPY(left, 0);
|
|
PG_FREE_IF_COPY(right, 1);
|
|
|
|
PG_RETURN_BOOL(result);
|
|
}
|
|
|
|
PG_FUNCTION_INFO_V1(citext_pattern_le);
|
|
|
|
Datum
|
|
citext_pattern_le(PG_FUNCTION_ARGS)
|
|
{
|
|
text *left = PG_GETARG_TEXT_PP(0);
|
|
text *right = PG_GETARG_TEXT_PP(1);
|
|
bool result;
|
|
|
|
result = internal_citext_pattern_cmp(left, right, PG_GET_COLLATION()) <= 0;
|
|
|
|
PG_FREE_IF_COPY(left, 0);
|
|
PG_FREE_IF_COPY(right, 1);
|
|
|
|
PG_RETURN_BOOL(result);
|
|
}
|
|
|
|
PG_FUNCTION_INFO_V1(citext_pattern_gt);
|
|
|
|
Datum
|
|
citext_pattern_gt(PG_FUNCTION_ARGS)
|
|
{
|
|
text *left = PG_GETARG_TEXT_PP(0);
|
|
text *right = PG_GETARG_TEXT_PP(1);
|
|
bool result;
|
|
|
|
result = internal_citext_pattern_cmp(left, right, PG_GET_COLLATION()) > 0;
|
|
|
|
PG_FREE_IF_COPY(left, 0);
|
|
PG_FREE_IF_COPY(right, 1);
|
|
|
|
PG_RETURN_BOOL(result);
|
|
}
|
|
|
|
PG_FUNCTION_INFO_V1(citext_pattern_ge);
|
|
|
|
Datum
|
|
citext_pattern_ge(PG_FUNCTION_ARGS)
|
|
{
|
|
text *left = PG_GETARG_TEXT_PP(0);
|
|
text *right = PG_GETARG_TEXT_PP(1);
|
|
bool result;
|
|
|
|
result = internal_citext_pattern_cmp(left, right, PG_GET_COLLATION()) >= 0;
|
|
|
|
PG_FREE_IF_COPY(left, 0);
|
|
PG_FREE_IF_COPY(right, 1);
|
|
|
|
PG_RETURN_BOOL(result);
|
|
}
|
|
|
|
/*
|
|
* ===================
|
|
* AGGREGATE FUNCTIONS
|
|
* ===================
|
|
*/
|
|
|
|
PG_FUNCTION_INFO_V1(citext_smaller);
|
|
|
|
Datum
|
|
citext_smaller(PG_FUNCTION_ARGS)
|
|
{
|
|
text *left = PG_GETARG_TEXT_PP(0);
|
|
text *right = PG_GETARG_TEXT_PP(1);
|
|
text *result;
|
|
|
|
result = citextcmp(left, right, PG_GET_COLLATION()) < 0 ? left : right;
|
|
PG_RETURN_TEXT_P(result);
|
|
}
|
|
|
|
PG_FUNCTION_INFO_V1(citext_larger);
|
|
|
|
Datum
|
|
citext_larger(PG_FUNCTION_ARGS)
|
|
{
|
|
text *left = PG_GETARG_TEXT_PP(0);
|
|
text *right = PG_GETARG_TEXT_PP(1);
|
|
text *result;
|
|
|
|
result = citextcmp(left, right, PG_GET_COLLATION()) > 0 ? left : right;
|
|
PG_RETURN_TEXT_P(result);
|
|
}
|