Header And Logo

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

btree_gin.c

Go to the documentation of this file.
00001 /*
00002  * contrib/btree_gin/btree_gin.c
00003  */
00004 #include "postgres.h"
00005 
00006 #include <limits.h>
00007 
00008 #include "access/skey.h"
00009 #include "utils/builtins.h"
00010 #include "utils/bytea.h"
00011 #include "utils/cash.h"
00012 #include "utils/date.h"
00013 #include "utils/inet.h"
00014 #include "utils/numeric.h"
00015 #include "utils/timestamp.h"
00016 #include "utils/varbit.h"
00017 
00018 PG_MODULE_MAGIC;
00019 
00020 typedef struct TypeInfo
00021 {
00022     bool        is_varlena;
00023     Datum       (*leftmostvalue) (void);
00024     Datum       (*typecmp) (FunctionCallInfo);
00025 } TypeInfo;
00026 
00027 typedef struct QueryInfo
00028 {
00029     StrategyNumber strategy;
00030     Datum       datum;
00031 } QueryInfo;
00032 
00033 #define  GIN_EXTRACT_VALUE(type)                                            \
00034 PG_FUNCTION_INFO_V1(gin_extract_value_##type);                              \
00035 Datum       gin_extract_value_##type(PG_FUNCTION_ARGS);                     \
00036 Datum                                                                       \
00037 gin_extract_value_##type(PG_FUNCTION_ARGS)                                  \
00038 {                                                                           \
00039     Datum       datum = PG_GETARG_DATUM(0);                                 \
00040     int32      *nentries = (int32 *) PG_GETARG_POINTER(1);                  \
00041     Datum      *entries = (Datum *) palloc(sizeof(Datum));                  \
00042                                                                             \
00043     if ( TypeInfo_##type.is_varlena )                                       \
00044         datum = PointerGetDatum(PG_DETOAST_DATUM(datum));                   \
00045     entries[0] = datum;                                                     \
00046     *nentries = 1;                                                          \
00047                                                                             \
00048     PG_RETURN_POINTER(entries);                                             \
00049 }
00050 
00051 /*
00052  * For BTGreaterEqualStrategyNumber, BTGreaterStrategyNumber, and
00053  * BTEqualStrategyNumber we want to start the index scan at the
00054  * supplied query datum, and work forward. For BTLessStrategyNumber
00055  * and BTLessEqualStrategyNumber, we need to start at the leftmost
00056  * key, and work forward until the supplied query datum (which must be
00057  * sent along inside the QueryInfo structure).
00058  */
00059 
00060 #define GIN_EXTRACT_QUERY(type)                                             \
00061 PG_FUNCTION_INFO_V1(gin_extract_query_##type);                              \
00062 Datum       gin_extract_query_##type(PG_FUNCTION_ARGS);                     \
00063 Datum                                                                       \
00064 gin_extract_query_##type(PG_FUNCTION_ARGS)                                  \
00065 {                                                                           \
00066     Datum       datum = PG_GETARG_DATUM(0);                                 \
00067     int32      *nentries = (int32 *) PG_GETARG_POINTER(1);                  \
00068     StrategyNumber strategy = PG_GETARG_UINT16(2);                          \
00069     bool      **partialmatch = (bool **) PG_GETARG_POINTER(3);              \
00070     Pointer   **extra_data = (Pointer **) PG_GETARG_POINTER(4);             \
00071     Datum      *entries = (Datum *) palloc(sizeof(Datum));                  \
00072     QueryInfo  *data = (QueryInfo *) palloc(sizeof(QueryInfo));             \
00073     bool       *ptr_partialmatch;                                           \
00074                                                                             \
00075     *nentries = 1;                                                          \
00076     ptr_partialmatch = *partialmatch = (bool *) palloc(sizeof(bool));       \
00077     *ptr_partialmatch = false;                                              \
00078     if ( TypeInfo_##type.is_varlena )                                       \
00079         datum = PointerGetDatum(PG_DETOAST_DATUM(datum));                   \
00080     data->strategy = strategy;                                              \
00081     data->datum = datum;                                                    \
00082     *extra_data = (Pointer *) palloc(sizeof(Pointer));                      \
00083     **extra_data = (Pointer) data;                                          \
00084                                                                             \
00085     switch (strategy)                                                       \
00086     {                                                                       \
00087         case BTLessStrategyNumber:                                          \
00088         case BTLessEqualStrategyNumber:                                     \
00089             entries[0] = TypeInfo_##type.leftmostvalue();                   \
00090             *ptr_partialmatch = true;                                       \
00091             break;                                                          \
00092         case BTGreaterEqualStrategyNumber:                                  \
00093         case BTGreaterStrategyNumber:                                       \
00094             *ptr_partialmatch = true;                                       \
00095         case BTEqualStrategyNumber:                                         \
00096             entries[0] = datum;                                             \
00097             break;                                                          \
00098         default:                                                            \
00099             elog(ERROR, "unrecognized strategy number: %d", strategy);      \
00100     }                                                                       \
00101                                                                             \
00102     PG_RETURN_POINTER(entries);                                             \
00103 }
00104 
00105 /*
00106  * Datum a is a value from extract_query method and for BTLess*
00107  * strategy it is a left-most value.  So, use original datum from QueryInfo
00108  * to decide to stop scanning or not.  Datum b is always from index.
00109  */
00110 #define GIN_COMPARE_PREFIX(type)                                            \
00111 PG_FUNCTION_INFO_V1(gin_compare_prefix_##type);                             \
00112 Datum       gin_compare_prefix_##type(PG_FUNCTION_ARGS);                    \
00113 Datum                                                                       \
00114 gin_compare_prefix_##type(PG_FUNCTION_ARGS)                                 \
00115 {                                                                           \
00116     Datum       a = PG_GETARG_DATUM(0);                                     \
00117     Datum       b = PG_GETARG_DATUM(1);                                     \
00118     QueryInfo  *data = (QueryInfo *) PG_GETARG_POINTER(3);                  \
00119     int32       res,                                                        \
00120                 cmp;                                                        \
00121                                                                             \
00122     cmp = DatumGetInt32(DirectFunctionCall2Coll(                            \
00123                 TypeInfo_##type.typecmp,                                    \
00124                 PG_GET_COLLATION(),                                         \
00125                 (data->strategy == BTLessStrategyNumber ||                  \
00126                  data->strategy == BTLessEqualStrategyNumber)               \
00127                  ? data->datum : a,                                         \
00128                 b));                                                        \
00129                                                                             \
00130     switch (data->strategy)                                                 \
00131     {                                                                       \
00132         case BTLessStrategyNumber:                                          \
00133             /* If original datum > indexed one then return match */         \
00134             if (cmp > 0)                                                    \
00135                 res = 0;                                                    \
00136             else                                                            \
00137                 res = 1;                                                    \
00138             break;                                                          \
00139         case BTLessEqualStrategyNumber:                                     \
00140             /* The same except equality */                                  \
00141             if (cmp >= 0)                                                   \
00142                 res = 0;                                                    \
00143             else                                                            \
00144                 res = 1;                                                    \
00145             break;                                                          \
00146         case BTEqualStrategyNumber:                                         \
00147             if (cmp != 0)                                                   \
00148                 res = 1;                                                    \
00149             else                                                            \
00150                 res = 0;                                                    \
00151             break;                                                          \
00152         case BTGreaterEqualStrategyNumber:                                  \
00153             /* If original datum <= indexed one then return match */        \
00154             if (cmp <= 0)                                                   \
00155                 res = 0;                                                    \
00156             else                                                            \
00157                 res = 1;                                                    \
00158             break;                                                          \
00159         case BTGreaterStrategyNumber:                                       \
00160             /* If original datum <= indexed one then return match */        \
00161             /* If original datum == indexed one then continue scan */       \
00162             if (cmp < 0)                                                    \
00163                 res = 0;                                                    \
00164             else if (cmp == 0)                                              \
00165                 res = -1;                                                   \
00166             else                                                            \
00167                 res = 1;                                                    \
00168             break;                                                          \
00169         default:                                                            \
00170             elog(ERROR, "unrecognized strategy number: %d",                 \
00171                  data->strategy);                                           \
00172             res = 0;                                                        \
00173     }                                                                       \
00174                                                                             \
00175     PG_RETURN_INT32(res);                                                   \
00176 }
00177 
00178 #define GIN_SUPPORT(type)           \
00179     GIN_EXTRACT_VALUE(type)         \
00180     GIN_EXTRACT_QUERY(type)         \
00181     GIN_COMPARE_PREFIX(type)
00182 
00183 
00184 PG_FUNCTION_INFO_V1(gin_btree_consistent);
00185 Datum       gin_btree_consistent(PG_FUNCTION_ARGS);
00186 Datum
00187 gin_btree_consistent(PG_FUNCTION_ARGS)
00188 {
00189     bool       *recheck = (bool *) PG_GETARG_POINTER(5);
00190 
00191     *recheck = false;
00192     PG_RETURN_BOOL(true);
00193 }
00194 
00195 static Datum
00196 leftmostvalue_int2(void)
00197 {
00198     return Int16GetDatum(SHRT_MIN);
00199 }
00200 static TypeInfo TypeInfo_int2 = {false, leftmostvalue_int2, btint2cmp};
00201 
00202 GIN_SUPPORT(int2)
00203 
00204 static Datum
00205 leftmostvalue_int4(void)
00206 {
00207     return Int32GetDatum(INT_MIN);
00208 }
00209 static TypeInfo TypeInfo_int4 = {false, leftmostvalue_int4, btint4cmp};
00210 
00211 GIN_SUPPORT(int4)
00212 
00213 static Datum
00214 leftmostvalue_int8(void)
00215 {
00216     /*
00217      * Use sequence's definition to keep compatibility.
00218      */
00219     return Int64GetDatum(SEQ_MINVALUE);
00220 }
00221 static TypeInfo TypeInfo_int8 = {false, leftmostvalue_int8, btint8cmp};
00222 
00223 GIN_SUPPORT(int8)
00224 
00225 static Datum
00226 leftmostvalue_float4(void)
00227 {
00228     return Float4GetDatum(-get_float4_infinity());
00229 }
00230 static TypeInfo TypeInfo_float4 = {false, leftmostvalue_float4, btfloat4cmp};
00231 
00232 GIN_SUPPORT(float4)
00233 
00234 static Datum
00235 leftmostvalue_float8(void)
00236 {
00237     return Float8GetDatum(-get_float8_infinity());
00238 }
00239 static TypeInfo TypeInfo_float8 = {false, leftmostvalue_float8, btfloat8cmp};
00240 
00241 GIN_SUPPORT(float8)
00242 
00243 static Datum
00244 leftmostvalue_money(void)
00245 {
00246     /*
00247      * Use sequence's definition to keep compatibility.
00248      */
00249     return Int64GetDatum(SEQ_MINVALUE);
00250 }
00251 static TypeInfo TypeInfo_money = {false, leftmostvalue_money, cash_cmp};
00252 
00253 GIN_SUPPORT(money)
00254 
00255 static Datum
00256 leftmostvalue_oid(void)
00257 {
00258     return ObjectIdGetDatum(0);
00259 }
00260 static TypeInfo TypeInfo_oid = {false, leftmostvalue_oid, btoidcmp};
00261 
00262 GIN_SUPPORT(oid)
00263 
00264 static Datum
00265 leftmostvalue_timestamp(void)
00266 {
00267     return TimestampGetDatum(DT_NOBEGIN);
00268 }
00269 static TypeInfo TypeInfo_timestamp = {false, leftmostvalue_timestamp, timestamp_cmp};
00270 
00271 GIN_SUPPORT(timestamp)
00272 
00273 static TypeInfo TypeInfo_timestamptz = {false, leftmostvalue_timestamp, timestamp_cmp};
00274 
00275 GIN_SUPPORT(timestamptz)
00276 
00277 static Datum
00278 leftmostvalue_time(void)
00279 {
00280     return TimeADTGetDatum(0);
00281 }
00282 static TypeInfo TypeInfo_time = {false, leftmostvalue_time, time_cmp};
00283 
00284 GIN_SUPPORT(time)
00285 
00286 static Datum
00287 leftmostvalue_timetz(void)
00288 {
00289     TimeTzADT  *v = palloc(sizeof(TimeTzADT));
00290 
00291     v->time = 0;
00292     v->zone = -24 * 3600;       /* XXX is that true? */
00293 
00294     return TimeTzADTPGetDatum(v);
00295 }
00296 static TypeInfo TypeInfo_timetz = {false, leftmostvalue_timetz, timetz_cmp};
00297 
00298 GIN_SUPPORT(timetz)
00299 
00300 static Datum
00301 leftmostvalue_date(void)
00302 {
00303     return DateADTGetDatum(DATEVAL_NOBEGIN);
00304 }
00305 static TypeInfo TypeInfo_date = {false, leftmostvalue_date, date_cmp};
00306 
00307 GIN_SUPPORT(date)
00308 
00309 static Datum
00310 leftmostvalue_interval(void)
00311 {
00312     Interval   *v = palloc(sizeof(Interval));
00313 
00314     v->time = DT_NOBEGIN;
00315     v->day = 0;
00316     v->month = 0;
00317     return IntervalPGetDatum(v);
00318 }
00319 static TypeInfo TypeInfo_interval = {false, leftmostvalue_interval, interval_cmp};
00320 
00321 GIN_SUPPORT(interval)
00322 
00323 static Datum
00324 leftmostvalue_macaddr(void)
00325 {
00326     macaddr    *v = palloc0(sizeof(macaddr));
00327 
00328     return MacaddrPGetDatum(v);
00329 }
00330 static TypeInfo TypeInfo_macaddr = {false, leftmostvalue_macaddr, macaddr_cmp};
00331 
00332 GIN_SUPPORT(macaddr)
00333 
00334 static Datum
00335 leftmostvalue_inet(void)
00336 {
00337     return DirectFunctionCall3(inet_in,
00338                                CStringGetDatum("0.0.0.0/0"),
00339                                ObjectIdGetDatum(0),
00340                                Int32GetDatum(-1));
00341 }
00342 static TypeInfo TypeInfo_inet = {true, leftmostvalue_inet, network_cmp};
00343 
00344 GIN_SUPPORT(inet)
00345 
00346 static TypeInfo TypeInfo_cidr = {true, leftmostvalue_inet, network_cmp};
00347 
00348 GIN_SUPPORT(cidr)
00349 
00350 static Datum
00351 leftmostvalue_text(void)
00352 {
00353     return PointerGetDatum(cstring_to_text_with_len("", 0));
00354 }
00355 static TypeInfo TypeInfo_text = {true, leftmostvalue_text, bttextcmp};
00356 
00357 GIN_SUPPORT(text)
00358 
00359 static Datum
00360 leftmostvalue_char(void)
00361 {
00362     return CharGetDatum(SCHAR_MIN);
00363 }
00364 static TypeInfo TypeInfo_char = {false, leftmostvalue_char, btcharcmp};
00365 
00366 GIN_SUPPORT(char)
00367 
00368 static TypeInfo TypeInfo_bytea = {true, leftmostvalue_text, byteacmp};
00369 
00370 GIN_SUPPORT(bytea)
00371 
00372 static Datum
00373 leftmostvalue_bit(void)
00374 {
00375     return DirectFunctionCall3(bit_in,
00376                                CStringGetDatum(""),
00377                                ObjectIdGetDatum(0),
00378                                Int32GetDatum(-1));
00379 }
00380 static TypeInfo TypeInfo_bit = {true, leftmostvalue_bit, bitcmp};
00381 
00382 GIN_SUPPORT(bit)
00383 
00384 static Datum
00385 leftmostvalue_varbit(void)
00386 {
00387     return DirectFunctionCall3(varbit_in,
00388                                CStringGetDatum(""),
00389                                ObjectIdGetDatum(0),
00390                                Int32GetDatum(-1));
00391 }
00392 static TypeInfo TypeInfo_varbit = {true, leftmostvalue_varbit, bitcmp};
00393 
00394 GIN_SUPPORT(varbit)
00395 
00396 /*
00397  * Numeric type hasn't a real left-most value, so we use PointerGetDatum(NULL)
00398  * (*not* a SQL NULL) to represent that.  We can get away with that because
00399  * the value returned by our leftmostvalue function will never be stored in
00400  * the index nor passed to anything except our compare and prefix-comparison
00401  * functions.  The same trick could be used for other pass-by-reference types.
00402  */
00403 
00404 #define NUMERIC_IS_LEFTMOST(x)  ((x) == NULL)
00405 
00406 PG_FUNCTION_INFO_V1(gin_numeric_cmp);
00407 Datum       gin_numeric_cmp(PG_FUNCTION_ARGS);
00408 
00409 Datum
00410 gin_numeric_cmp(PG_FUNCTION_ARGS)
00411 {
00412     Numeric     a = (Numeric) PG_GETARG_POINTER(0);
00413     Numeric     b = (Numeric) PG_GETARG_POINTER(1);
00414     int         res = 0;
00415 
00416     if (NUMERIC_IS_LEFTMOST(a))
00417     {
00418         res = (NUMERIC_IS_LEFTMOST(b)) ? 0 : -1;
00419     }
00420     else if (NUMERIC_IS_LEFTMOST(b))
00421     {
00422         res = 1;
00423     }
00424     else
00425     {
00426         res = DatumGetInt32(DirectFunctionCall2(numeric_cmp,
00427                                                 NumericGetDatum(a),
00428                                                 NumericGetDatum(b)));
00429     }
00430 
00431     PG_RETURN_INT32(res);
00432 }
00433 
00434 static Datum
00435 leftmostvalue_numeric(void)
00436 {
00437     return PointerGetDatum(NULL);
00438 }
00439 
00440 static TypeInfo TypeInfo_numeric = {true, leftmostvalue_numeric, gin_numeric_cmp};
00441 
00442 GIN_SUPPORT(numeric)