mirror of
https://git.postgresql.org/git/postgresql.git
synced 2024-12-27 08:39:28 +08:00
d747140279
provided by Andrew.
270 lines
5.2 KiB
C
270 lines
5.2 KiB
C
/*
|
|
* $PostgreSQL: pgsql/contrib/citext/citext.c,v 1.2 2009/06/11 14:48:50 momjian Exp $
|
|
*/
|
|
#include "postgres.h"
|
|
|
|
#include "access/hash.h"
|
|
#include "fmgr.h"
|
|
#include "utils/builtins.h"
|
|
#include "utils/formatting.h"
|
|
|
|
#ifdef PG_MODULE_MAGIC
|
|
PG_MODULE_MAGIC;
|
|
#endif
|
|
|
|
/*
|
|
* ====================
|
|
* FORWARD DECLARATIONS
|
|
* ====================
|
|
*/
|
|
|
|
static int32 citextcmp(text *left, text *right);
|
|
extern Datum citext_cmp(PG_FUNCTION_ARGS);
|
|
extern Datum citext_hash(PG_FUNCTION_ARGS);
|
|
extern Datum citext_eq(PG_FUNCTION_ARGS);
|
|
extern Datum citext_ne(PG_FUNCTION_ARGS);
|
|
extern Datum citext_gt(PG_FUNCTION_ARGS);
|
|
extern Datum citext_ge(PG_FUNCTION_ARGS);
|
|
extern Datum citext_lt(PG_FUNCTION_ARGS);
|
|
extern Datum citext_le(PG_FUNCTION_ARGS);
|
|
extern Datum citext_smaller(PG_FUNCTION_ARGS);
|
|
extern Datum citext_larger(PG_FUNCTION_ARGS);
|
|
|
|
/*
|
|
* =================
|
|
* UTILITY FUNCTIONS
|
|
* =================
|
|
*/
|
|
|
|
/*
|
|
* citextcmp()
|
|
* Internal comparison function for citext strings.
|
|
* Returns int32 negative, zero, or positive.
|
|
*/
|
|
static int32
|
|
citextcmp(text *left, text *right)
|
|
{
|
|
char *lcstr,
|
|
*rcstr;
|
|
int32 result;
|
|
|
|
lcstr = str_tolower(VARDATA_ANY(left), VARSIZE_ANY_EXHDR(left));
|
|
rcstr = str_tolower(VARDATA_ANY(right), VARSIZE_ANY_EXHDR(right));
|
|
|
|
result = varstr_cmp(lcstr, strlen(lcstr),
|
|
rcstr, strlen(rcstr));
|
|
|
|
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_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));
|
|
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);
|
|
}
|
|
|
|
/*
|
|
* ==================
|
|
* 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));
|
|
rcstr = str_tolower(VARDATA_ANY(right), VARSIZE_ANY_EXHDR(right));
|
|
|
|
/*
|
|
* 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));
|
|
rcstr = str_tolower(VARDATA_ANY(right), VARSIZE_ANY_EXHDR(right));
|
|
|
|
/*
|
|
* 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) < 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) <= 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) > 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) >= 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) < 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) > 0 ? left : right;
|
|
PG_RETURN_TEXT_P(result);
|
|
}
|