Header And Logo

PostgreSQL
| The world's most advanced open source database.

citext.c

Go to the documentation of this file.
00001 /*
00002  * contrib/citext/citext.c
00003  */
00004 #include "postgres.h"
00005 
00006 #include "access/hash.h"
00007 #include "catalog/pg_collation.h"
00008 #include "utils/builtins.h"
00009 #include "utils/formatting.h"
00010 
00011 #ifdef PG_MODULE_MAGIC
00012 PG_MODULE_MAGIC;
00013 #endif
00014 
00015 /*
00016  *      ====================
00017  *      FORWARD DECLARATIONS
00018  *      ====================
00019  */
00020 
00021 static int32 citextcmp(text *left, text *right, Oid collid);
00022 extern Datum citext_cmp(PG_FUNCTION_ARGS);
00023 extern Datum citext_hash(PG_FUNCTION_ARGS);
00024 extern Datum citext_eq(PG_FUNCTION_ARGS);
00025 extern Datum citext_ne(PG_FUNCTION_ARGS);
00026 extern Datum citext_gt(PG_FUNCTION_ARGS);
00027 extern Datum citext_ge(PG_FUNCTION_ARGS);
00028 extern Datum citext_lt(PG_FUNCTION_ARGS);
00029 extern Datum citext_le(PG_FUNCTION_ARGS);
00030 extern Datum citext_smaller(PG_FUNCTION_ARGS);
00031 extern Datum citext_larger(PG_FUNCTION_ARGS);
00032 
00033 /*
00034  *      =================
00035  *      UTILITY FUNCTIONS
00036  *      =================
00037  */
00038 
00039 /*
00040  * citextcmp()
00041  * Internal comparison function for citext strings.
00042  * Returns int32 negative, zero, or positive.
00043  */
00044 static int32
00045 citextcmp(text *left, text *right, Oid collid)
00046 {
00047     char       *lcstr,
00048                *rcstr;
00049     int32       result;
00050 
00051     /*
00052      * We must do our str_tolower calls with DEFAULT_COLLATION_OID, not the
00053      * input collation as you might expect.  This is so that the behavior of
00054      * citext's equality and hashing functions is not collation-dependent.  We
00055      * should change this once the core infrastructure is able to cope with
00056      * collation-dependent equality and hashing functions.
00057      */
00058 
00059     lcstr = str_tolower(VARDATA_ANY(left), VARSIZE_ANY_EXHDR(left), DEFAULT_COLLATION_OID);
00060     rcstr = str_tolower(VARDATA_ANY(right), VARSIZE_ANY_EXHDR(right), DEFAULT_COLLATION_OID);
00061 
00062     result = varstr_cmp(lcstr, strlen(lcstr),
00063                         rcstr, strlen(rcstr),
00064                         collid);
00065 
00066     pfree(lcstr);
00067     pfree(rcstr);
00068 
00069     return result;
00070 }
00071 
00072 /*
00073  *      ==================
00074  *      INDEXING FUNCTIONS
00075  *      ==================
00076  */
00077 
00078 PG_FUNCTION_INFO_V1(citext_cmp);
00079 
00080 Datum
00081 citext_cmp(PG_FUNCTION_ARGS)
00082 {
00083     text       *left = PG_GETARG_TEXT_PP(0);
00084     text       *right = PG_GETARG_TEXT_PP(1);
00085     int32       result;
00086 
00087     result = citextcmp(left, right, PG_GET_COLLATION());
00088 
00089     PG_FREE_IF_COPY(left, 0);
00090     PG_FREE_IF_COPY(right, 1);
00091 
00092     PG_RETURN_INT32(result);
00093 }
00094 
00095 PG_FUNCTION_INFO_V1(citext_hash);
00096 
00097 Datum
00098 citext_hash(PG_FUNCTION_ARGS)
00099 {
00100     text       *txt = PG_GETARG_TEXT_PP(0);
00101     char       *str;
00102     Datum       result;
00103 
00104     str = str_tolower(VARDATA_ANY(txt), VARSIZE_ANY_EXHDR(txt), DEFAULT_COLLATION_OID);
00105     result = hash_any((unsigned char *) str, strlen(str));
00106     pfree(str);
00107 
00108     /* Avoid leaking memory for toasted inputs */
00109     PG_FREE_IF_COPY(txt, 0);
00110 
00111     PG_RETURN_DATUM(result);
00112 }
00113 
00114 /*
00115  *      ==================
00116  *      OPERATOR FUNCTIONS
00117  *      ==================
00118  */
00119 
00120 PG_FUNCTION_INFO_V1(citext_eq);
00121 
00122 Datum
00123 citext_eq(PG_FUNCTION_ARGS)
00124 {
00125     text       *left = PG_GETARG_TEXT_PP(0);
00126     text       *right = PG_GETARG_TEXT_PP(1);
00127     char       *lcstr,
00128                *rcstr;
00129     bool        result;
00130 
00131     /* We can't compare lengths in advance of downcasing ... */
00132 
00133     lcstr = str_tolower(VARDATA_ANY(left), VARSIZE_ANY_EXHDR(left), DEFAULT_COLLATION_OID);
00134     rcstr = str_tolower(VARDATA_ANY(right), VARSIZE_ANY_EXHDR(right), DEFAULT_COLLATION_OID);
00135 
00136     /*
00137      * Since we only care about equality or not-equality, we can avoid all the
00138      * expense of strcoll() here, and just do bitwise comparison.
00139      */
00140     result = (strcmp(lcstr, rcstr) == 0);
00141 
00142     pfree(lcstr);
00143     pfree(rcstr);
00144     PG_FREE_IF_COPY(left, 0);
00145     PG_FREE_IF_COPY(right, 1);
00146 
00147     PG_RETURN_BOOL(result);
00148 }
00149 
00150 PG_FUNCTION_INFO_V1(citext_ne);
00151 
00152 Datum
00153 citext_ne(PG_FUNCTION_ARGS)
00154 {
00155     text       *left = PG_GETARG_TEXT_PP(0);
00156     text       *right = PG_GETARG_TEXT_PP(1);
00157     char       *lcstr,
00158                *rcstr;
00159     bool        result;
00160 
00161     /* We can't compare lengths in advance of downcasing ... */
00162 
00163     lcstr = str_tolower(VARDATA_ANY(left), VARSIZE_ANY_EXHDR(left), DEFAULT_COLLATION_OID);
00164     rcstr = str_tolower(VARDATA_ANY(right), VARSIZE_ANY_EXHDR(right), DEFAULT_COLLATION_OID);
00165 
00166     /*
00167      * Since we only care about equality or not-equality, we can avoid all the
00168      * expense of strcoll() here, and just do bitwise comparison.
00169      */
00170     result = (strcmp(lcstr, rcstr) != 0);
00171 
00172     pfree(lcstr);
00173     pfree(rcstr);
00174     PG_FREE_IF_COPY(left, 0);
00175     PG_FREE_IF_COPY(right, 1);
00176 
00177     PG_RETURN_BOOL(result);
00178 }
00179 
00180 PG_FUNCTION_INFO_V1(citext_lt);
00181 
00182 Datum
00183 citext_lt(PG_FUNCTION_ARGS)
00184 {
00185     text       *left = PG_GETARG_TEXT_PP(0);
00186     text       *right = PG_GETARG_TEXT_PP(1);
00187     bool        result;
00188 
00189     result = citextcmp(left, right, PG_GET_COLLATION()) < 0;
00190 
00191     PG_FREE_IF_COPY(left, 0);
00192     PG_FREE_IF_COPY(right, 1);
00193 
00194     PG_RETURN_BOOL(result);
00195 }
00196 
00197 PG_FUNCTION_INFO_V1(citext_le);
00198 
00199 Datum
00200 citext_le(PG_FUNCTION_ARGS)
00201 {
00202     text       *left = PG_GETARG_TEXT_PP(0);
00203     text       *right = PG_GETARG_TEXT_PP(1);
00204     bool        result;
00205 
00206     result = citextcmp(left, right, PG_GET_COLLATION()) <= 0;
00207 
00208     PG_FREE_IF_COPY(left, 0);
00209     PG_FREE_IF_COPY(right, 1);
00210 
00211     PG_RETURN_BOOL(result);
00212 }
00213 
00214 PG_FUNCTION_INFO_V1(citext_gt);
00215 
00216 Datum
00217 citext_gt(PG_FUNCTION_ARGS)
00218 {
00219     text       *left = PG_GETARG_TEXT_PP(0);
00220     text       *right = PG_GETARG_TEXT_PP(1);
00221     bool        result;
00222 
00223     result = citextcmp(left, right, PG_GET_COLLATION()) > 0;
00224 
00225     PG_FREE_IF_COPY(left, 0);
00226     PG_FREE_IF_COPY(right, 1);
00227 
00228     PG_RETURN_BOOL(result);
00229 }
00230 
00231 PG_FUNCTION_INFO_V1(citext_ge);
00232 
00233 Datum
00234 citext_ge(PG_FUNCTION_ARGS)
00235 {
00236     text       *left = PG_GETARG_TEXT_PP(0);
00237     text       *right = PG_GETARG_TEXT_PP(1);
00238     bool        result;
00239 
00240     result = citextcmp(left, right, PG_GET_COLLATION()) >= 0;
00241 
00242     PG_FREE_IF_COPY(left, 0);
00243     PG_FREE_IF_COPY(right, 1);
00244 
00245     PG_RETURN_BOOL(result);
00246 }
00247 
00248 /*
00249  *      ===================
00250  *      AGGREGATE FUNCTIONS
00251  *      ===================
00252  */
00253 
00254 PG_FUNCTION_INFO_V1(citext_smaller);
00255 
00256 Datum
00257 citext_smaller(PG_FUNCTION_ARGS)
00258 {
00259     text       *left = PG_GETARG_TEXT_PP(0);
00260     text       *right = PG_GETARG_TEXT_PP(1);
00261     text       *result;
00262 
00263     result = citextcmp(left, right, PG_GET_COLLATION()) < 0 ? left : right;
00264     PG_RETURN_TEXT_P(result);
00265 }
00266 
00267 PG_FUNCTION_INFO_V1(citext_larger);
00268 
00269 Datum
00270 citext_larger(PG_FUNCTION_ARGS)
00271 {
00272     text       *left = PG_GETARG_TEXT_PP(0);
00273     text       *right = PG_GETARG_TEXT_PP(1);
00274     text       *result;
00275 
00276     result = citextcmp(left, right, PG_GET_COLLATION()) > 0 ? left : right;
00277     PG_RETURN_TEXT_P(result);
00278 }