00001
00002
00003
00004 #include "postgres.h"
00005
00006 #include "btree_gist.h"
00007 #include "btree_utils_num.h"
00008 #include "utils/builtins.h"
00009 #include "utils/datetime.h"
00010
00011 typedef struct
00012 {
00013 Timestamp lower;
00014 Timestamp upper;
00015 } tsKEY;
00016
00017
00018
00019
00020 PG_FUNCTION_INFO_V1(gbt_ts_compress);
00021 PG_FUNCTION_INFO_V1(gbt_tstz_compress);
00022 PG_FUNCTION_INFO_V1(gbt_ts_union);
00023 PG_FUNCTION_INFO_V1(gbt_ts_picksplit);
00024 PG_FUNCTION_INFO_V1(gbt_ts_consistent);
00025 PG_FUNCTION_INFO_V1(gbt_ts_distance);
00026 PG_FUNCTION_INFO_V1(gbt_tstz_consistent);
00027 PG_FUNCTION_INFO_V1(gbt_tstz_distance);
00028 PG_FUNCTION_INFO_V1(gbt_ts_penalty);
00029 PG_FUNCTION_INFO_V1(gbt_ts_same);
00030
00031 Datum gbt_ts_compress(PG_FUNCTION_ARGS);
00032 Datum gbt_tstz_compress(PG_FUNCTION_ARGS);
00033 Datum gbt_ts_union(PG_FUNCTION_ARGS);
00034 Datum gbt_ts_picksplit(PG_FUNCTION_ARGS);
00035 Datum gbt_ts_consistent(PG_FUNCTION_ARGS);
00036 Datum gbt_ts_distance(PG_FUNCTION_ARGS);
00037 Datum gbt_tstz_consistent(PG_FUNCTION_ARGS);
00038 Datum gbt_tstz_distance(PG_FUNCTION_ARGS);
00039 Datum gbt_ts_penalty(PG_FUNCTION_ARGS);
00040 Datum gbt_ts_same(PG_FUNCTION_ARGS);
00041
00042
00043 #ifdef USE_FLOAT8_BYVAL
00044 #define TimestampGetDatumFast(X) TimestampGetDatum(X)
00045 #else
00046 #define TimestampGetDatumFast(X) PointerGetDatum(&(X))
00047 #endif
00048
00049
00050 static bool
00051 gbt_tsgt(const void *a, const void *b)
00052 {
00053 const Timestamp *aa = (const Timestamp *) a;
00054 const Timestamp *bb = (const Timestamp *) b;
00055
00056 return DatumGetBool(DirectFunctionCall2(timestamp_gt,
00057 TimestampGetDatumFast(*aa),
00058 TimestampGetDatumFast(*bb)));
00059 }
00060
00061 static bool
00062 gbt_tsge(const void *a, const void *b)
00063 {
00064 const Timestamp *aa = (const Timestamp *) a;
00065 const Timestamp *bb = (const Timestamp *) b;
00066
00067 return DatumGetBool(DirectFunctionCall2(timestamp_ge,
00068 TimestampGetDatumFast(*aa),
00069 TimestampGetDatumFast(*bb)));
00070 }
00071
00072 static bool
00073 gbt_tseq(const void *a, const void *b)
00074 {
00075 const Timestamp *aa = (const Timestamp *) a;
00076 const Timestamp *bb = (const Timestamp *) b;
00077
00078 return DatumGetBool(DirectFunctionCall2(timestamp_eq,
00079 TimestampGetDatumFast(*aa),
00080 TimestampGetDatumFast(*bb)));
00081 }
00082
00083 static bool
00084 gbt_tsle(const void *a, const void *b)
00085 {
00086 const Timestamp *aa = (const Timestamp *) a;
00087 const Timestamp *bb = (const Timestamp *) b;
00088
00089 return DatumGetBool(DirectFunctionCall2(timestamp_le,
00090 TimestampGetDatumFast(*aa),
00091 TimestampGetDatumFast(*bb)));
00092 }
00093
00094 static bool
00095 gbt_tslt(const void *a, const void *b)
00096 {
00097 const Timestamp *aa = (const Timestamp *) a;
00098 const Timestamp *bb = (const Timestamp *) b;
00099
00100 return DatumGetBool(DirectFunctionCall2(timestamp_lt,
00101 TimestampGetDatumFast(*aa),
00102 TimestampGetDatumFast(*bb)));
00103 }
00104
00105
00106 static int
00107 gbt_tskey_cmp(const void *a, const void *b)
00108 {
00109 tsKEY *ia = (tsKEY *) (((const Nsrt *) a)->t);
00110 tsKEY *ib = (tsKEY *) (((const Nsrt *) b)->t);
00111 int res;
00112
00113 res = DatumGetInt32(DirectFunctionCall2(timestamp_cmp, TimestampGetDatumFast(ia->lower), TimestampGetDatumFast(ib->lower)));
00114 if (res == 0)
00115 return DatumGetInt32(DirectFunctionCall2(timestamp_cmp, TimestampGetDatumFast(ia->upper), TimestampGetDatumFast(ib->upper)));
00116
00117 return res;
00118 }
00119
00120 static float8
00121 gbt_ts_dist(const void *a, const void *b)
00122 {
00123 const Timestamp *aa = (const Timestamp *) a;
00124 const Timestamp *bb = (const Timestamp *) b;
00125 Interval *i;
00126
00127 if (TIMESTAMP_NOT_FINITE(*aa) || TIMESTAMP_NOT_FINITE(*bb))
00128 return get_float8_infinity();
00129
00130 i = DatumGetIntervalP(DirectFunctionCall2(timestamp_mi,
00131 TimestampGetDatumFast(*aa),
00132 TimestampGetDatumFast(*bb)));
00133 return (float8) Abs(INTERVAL_TO_SEC(i));
00134 }
00135
00136
00137 static const gbtree_ninfo tinfo =
00138 {
00139 gbt_t_ts,
00140 sizeof(Timestamp),
00141 gbt_tsgt,
00142 gbt_tsge,
00143 gbt_tseq,
00144 gbt_tsle,
00145 gbt_tslt,
00146 gbt_tskey_cmp,
00147 gbt_ts_dist
00148 };
00149
00150
00151 PG_FUNCTION_INFO_V1(ts_dist);
00152 Datum ts_dist(PG_FUNCTION_ARGS);
00153 Datum
00154 ts_dist(PG_FUNCTION_ARGS)
00155 {
00156 Timestamp a = PG_GETARG_TIMESTAMP(0);
00157 Timestamp b = PG_GETARG_TIMESTAMP(1);
00158 Interval *r;
00159
00160 if (TIMESTAMP_NOT_FINITE(a) || TIMESTAMP_NOT_FINITE(b))
00161 {
00162 Interval *p = palloc(sizeof(Interval));
00163
00164 p->day = INT_MAX;
00165 p->month = INT_MAX;
00166 #ifdef HAVE_INT64_TIMESTAMP
00167 p->time = INT64CONST(0x7FFFFFFFFFFFFFFF);
00168 #else
00169 p->time = DBL_MAX;
00170 #endif
00171 PG_RETURN_INTERVAL_P(p);
00172 }
00173 else
00174 r = DatumGetIntervalP(DirectFunctionCall2(timestamp_mi,
00175 PG_GETARG_DATUM(0),
00176 PG_GETARG_DATUM(1)));
00177 PG_RETURN_INTERVAL_P(abs_interval(r));
00178 }
00179
00180 PG_FUNCTION_INFO_V1(tstz_dist);
00181 Datum tstz_dist(PG_FUNCTION_ARGS);
00182 Datum
00183 tstz_dist(PG_FUNCTION_ARGS)
00184 {
00185 TimestampTz a = PG_GETARG_TIMESTAMPTZ(0);
00186 TimestampTz b = PG_GETARG_TIMESTAMPTZ(1);
00187 Interval *r;
00188
00189 if (TIMESTAMP_NOT_FINITE(a) || TIMESTAMP_NOT_FINITE(b))
00190 {
00191 Interval *p = palloc(sizeof(Interval));
00192
00193 p->day = INT_MAX;
00194 p->month = INT_MAX;
00195 #ifdef HAVE_INT64_TIMESTAMP
00196 p->time = INT64CONST(0x7FFFFFFFFFFFFFFF);
00197 #else
00198 p->time = DBL_MAX;
00199 #endif
00200 PG_RETURN_INTERVAL_P(p);
00201 }
00202
00203 r = DatumGetIntervalP(DirectFunctionCall2(timestamp_mi,
00204 PG_GETARG_DATUM(0),
00205 PG_GETARG_DATUM(1)));
00206 PG_RETURN_INTERVAL_P(abs_interval(r));
00207 }
00208
00209
00210
00211
00212
00213
00214
00215 static Timestamp
00216 tstz_to_ts_gmt(TimestampTz ts)
00217 {
00218 Timestamp gmt;
00219 int val,
00220 tz;
00221
00222 gmt = ts;
00223 DecodeSpecial(0, "gmt", &val);
00224
00225 if (ts < DT_NOEND && ts > DT_NOBEGIN)
00226 {
00227 tz = val * 60;
00228
00229 #ifdef HAVE_INT64_TIMESTAMP
00230 gmt -= (tz * INT64CONST(1000000));
00231 #else
00232 gmt -= tz;
00233 #endif
00234 }
00235 return gmt;
00236 }
00237
00238
00239 Datum
00240 gbt_ts_compress(PG_FUNCTION_ARGS)
00241 {
00242 GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
00243 GISTENTRY *retval = NULL;
00244
00245 PG_RETURN_POINTER(gbt_num_compress(retval, entry, &tinfo));
00246 }
00247
00248
00249 Datum
00250 gbt_tstz_compress(PG_FUNCTION_ARGS)
00251 {
00252 GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
00253 GISTENTRY *retval;
00254
00255 if (entry->leafkey)
00256 {
00257 tsKEY *r = (tsKEY *) palloc(sizeof(tsKEY));
00258 TimestampTz ts = DatumGetTimestampTz(entry->key);
00259 Timestamp gmt;
00260
00261 gmt = tstz_to_ts_gmt(ts);
00262
00263 retval = palloc(sizeof(GISTENTRY));
00264 r->lower = r->upper = gmt;
00265 gistentryinit(*retval, PointerGetDatum(r),
00266 entry->rel, entry->page,
00267 entry->offset, FALSE);
00268 }
00269 else
00270 retval = entry;
00271
00272 PG_RETURN_POINTER(retval);
00273 }
00274
00275
00276 Datum
00277 gbt_ts_consistent(PG_FUNCTION_ARGS)
00278 {
00279 GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
00280 Timestamp query = PG_GETARG_TIMESTAMP(1);
00281 StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
00282
00283
00284 bool *recheck = (bool *) PG_GETARG_POINTER(4);
00285 tsKEY *kkk = (tsKEY *) DatumGetPointer(entry->key);
00286 GBT_NUMKEY_R key;
00287
00288
00289 *recheck = false;
00290
00291 key.lower = (GBT_NUMKEY *) &kkk->lower;
00292 key.upper = (GBT_NUMKEY *) &kkk->upper;
00293
00294 PG_RETURN_BOOL(
00295 gbt_num_consistent(&key, (void *) &query, &strategy, GIST_LEAF(entry), &tinfo)
00296 );
00297 }
00298
00299 Datum
00300 gbt_ts_distance(PG_FUNCTION_ARGS)
00301 {
00302 GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
00303 Timestamp query = PG_GETARG_TIMESTAMP(1);
00304
00305
00306 tsKEY *kkk = (tsKEY *) DatumGetPointer(entry->key);
00307 GBT_NUMKEY_R key;
00308
00309 key.lower = (GBT_NUMKEY *) &kkk->lower;
00310 key.upper = (GBT_NUMKEY *) &kkk->upper;
00311
00312 PG_RETURN_FLOAT8(
00313 gbt_num_distance(&key, (void *) &query, GIST_LEAF(entry), &tinfo)
00314 );
00315 }
00316
00317 Datum
00318 gbt_tstz_consistent(PG_FUNCTION_ARGS)
00319 {
00320 GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
00321 TimestampTz query = PG_GETARG_TIMESTAMPTZ(1);
00322 StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
00323
00324
00325 bool *recheck = (bool *) PG_GETARG_POINTER(4);
00326 char *kkk = (char *) DatumGetPointer(entry->key);
00327 GBT_NUMKEY_R key;
00328 Timestamp qqq;
00329
00330
00331 *recheck = false;
00332
00333 key.lower = (GBT_NUMKEY *) &kkk[0];
00334 key.upper = (GBT_NUMKEY *) &kkk[MAXALIGN(tinfo.size)];
00335 qqq = tstz_to_ts_gmt(query);
00336
00337 PG_RETURN_BOOL(
00338 gbt_num_consistent(&key, (void *) &qqq, &strategy, GIST_LEAF(entry), &tinfo)
00339 );
00340 }
00341
00342 Datum
00343 gbt_tstz_distance(PG_FUNCTION_ARGS)
00344 {
00345 GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
00346 TimestampTz query = PG_GETARG_TIMESTAMPTZ(1);
00347
00348
00349 char *kkk = (char *) DatumGetPointer(entry->key);
00350 GBT_NUMKEY_R key;
00351 Timestamp qqq;
00352
00353 key.lower = (GBT_NUMKEY *) &kkk[0];
00354 key.upper = (GBT_NUMKEY *) &kkk[MAXALIGN(tinfo.size)];
00355 qqq = tstz_to_ts_gmt(query);
00356
00357 PG_RETURN_FLOAT8(
00358 gbt_num_distance(&key, (void *) &qqq, GIST_LEAF(entry), &tinfo)
00359 );
00360 }
00361
00362
00363 Datum
00364 gbt_ts_union(PG_FUNCTION_ARGS)
00365 {
00366 GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
00367 void *out = palloc(sizeof(tsKEY));
00368
00369 *(int *) PG_GETARG_POINTER(1) = sizeof(tsKEY);
00370 PG_RETURN_POINTER(gbt_num_union((void *) out, entryvec, &tinfo));
00371 }
00372
00373
00374 #define penalty_check_max_float(val) do { \
00375 if ( val > FLT_MAX ) \
00376 val = FLT_MAX; \
00377 if ( val < -FLT_MAX ) \
00378 val = -FLT_MAX; \
00379 } while(false);
00380
00381
00382 Datum
00383 gbt_ts_penalty(PG_FUNCTION_ARGS)
00384 {
00385
00386 tsKEY *origentry = (tsKEY *) DatumGetPointer(((GISTENTRY *) PG_GETARG_POINTER(0))->key);
00387 tsKEY *newentry = (tsKEY *) DatumGetPointer(((GISTENTRY *) PG_GETARG_POINTER(1))->key);
00388 float *result = (float *) PG_GETARG_POINTER(2);
00389
00390 double orgdbl[2],
00391 newdbl[2];
00392
00393
00394
00395
00396
00397 orgdbl[0] = ((double) origentry->lower);
00398 orgdbl[1] = ((double) origentry->upper);
00399 newdbl[0] = ((double) newentry->lower);
00400 newdbl[1] = ((double) newentry->upper);
00401
00402 penalty_check_max_float(orgdbl[0]);
00403 penalty_check_max_float(orgdbl[1]);
00404 penalty_check_max_float(newdbl[0]);
00405 penalty_check_max_float(newdbl[1]);
00406
00407 penalty_num(result, orgdbl[0], orgdbl[1], newdbl[0], newdbl[1]);
00408
00409 PG_RETURN_POINTER(result);
00410
00411 }
00412
00413
00414 Datum
00415 gbt_ts_picksplit(PG_FUNCTION_ARGS)
00416 {
00417 PG_RETURN_POINTER(gbt_num_picksplit(
00418 (GistEntryVector *) PG_GETARG_POINTER(0),
00419 (GIST_SPLITVEC *) PG_GETARG_POINTER(1),
00420 &tinfo
00421 ));
00422 }
00423
00424 Datum
00425 gbt_ts_same(PG_FUNCTION_ARGS)
00426 {
00427 tsKEY *b1 = (tsKEY *) PG_GETARG_POINTER(0);
00428 tsKEY *b2 = (tsKEY *) PG_GETARG_POINTER(1);
00429 bool *result = (bool *) PG_GETARG_POINTER(2);
00430
00431 *result = gbt_num_same((void *) b1, (void *) b2, &tinfo);
00432 PG_RETURN_POINTER(result);
00433 }