00001
00002
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
00053
00054
00055
00056
00057
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
00107
00108
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 \
00134 if (cmp > 0) \
00135 res = 0; \
00136 else \
00137 res = 1; \
00138 break; \
00139 case BTLessEqualStrategyNumber: \
00140 \
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 \
00154 if (cmp <= 0) \
00155 res = 0; \
00156 else \
00157 res = 1; \
00158 break; \
00159 case BTGreaterStrategyNumber: \
00160 \
00161 \
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
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
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;
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
00398
00399
00400
00401
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)