Header And Logo

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

btree_ts.c

Go to the documentation of this file.
00001 /*
00002  * contrib/btree_gist/btree_ts.c
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 ** timestamp ops
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  * timestamp ops
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     /* Oid      subtype = PG_GETARG_OID(3); */
00284     bool       *recheck = (bool *) PG_GETARG_POINTER(4);
00285     tsKEY      *kkk = (tsKEY *) DatumGetPointer(entry->key);
00286     GBT_NUMKEY_R key;
00287 
00288     /* All cases served by this function are exact */
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     /* Oid      subtype = PG_GETARG_OID(3); */
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     /* Oid      subtype = PG_GETARG_OID(3); */
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     /* All cases served by this function are exact */
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     /* Oid      subtype = PG_GETARG_OID(3); */
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      * We are allways using "double" timestamps here. Precision should be good
00395      * enough.
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 }