1 /* 2 * contrib/btree_gist/btree_time.c 3 */ 4 #include "postgres.h" 5 6 #include "btree_gist.h" 7 #include "btree_utils_num.h" 8 #include "utils/builtins.h" 9 #include "utils/date.h" 10 #include "utils/timestamp.h" 11 12 typedef struct 13 { 14 TimeADT lower; 15 TimeADT upper; 16 } timeKEY; 17 18 /* 19 ** time ops 20 */ 21 PG_FUNCTION_INFO_V1(gbt_time_compress); 22 PG_FUNCTION_INFO_V1(gbt_timetz_compress); 23 PG_FUNCTION_INFO_V1(gbt_time_fetch); 24 PG_FUNCTION_INFO_V1(gbt_time_union); 25 PG_FUNCTION_INFO_V1(gbt_time_picksplit); 26 PG_FUNCTION_INFO_V1(gbt_time_consistent); 27 PG_FUNCTION_INFO_V1(gbt_time_distance); 28 PG_FUNCTION_INFO_V1(gbt_timetz_consistent); 29 PG_FUNCTION_INFO_V1(gbt_time_penalty); 30 PG_FUNCTION_INFO_V1(gbt_time_same); 31 32 33 #ifdef USE_FLOAT8_BYVAL 34 #define TimeADTGetDatumFast(X) TimeADTGetDatum(X) 35 #else 36 #define TimeADTGetDatumFast(X) PointerGetDatum(&(X)) 37 #endif 38 39 40 static bool 41 gbt_timegt(const void *a, const void *b, FmgrInfo *flinfo) 42 { 43 const TimeADT *aa = (const TimeADT *) a; 44 const TimeADT *bb = (const TimeADT *) b; 45 46 return DatumGetBool(DirectFunctionCall2(time_gt, 47 TimeADTGetDatumFast(*aa), 48 TimeADTGetDatumFast(*bb))); 49 } 50 51 static bool 52 gbt_timege(const void *a, const void *b, FmgrInfo *flinfo) 53 { 54 const TimeADT *aa = (const TimeADT *) a; 55 const TimeADT *bb = (const TimeADT *) b; 56 57 return DatumGetBool(DirectFunctionCall2(time_ge, 58 TimeADTGetDatumFast(*aa), 59 TimeADTGetDatumFast(*bb))); 60 } 61 62 static bool 63 gbt_timeeq(const void *a, const void *b, FmgrInfo *flinfo) 64 { 65 const TimeADT *aa = (const TimeADT *) a; 66 const TimeADT *bb = (const TimeADT *) b; 67 68 return DatumGetBool(DirectFunctionCall2(time_eq, 69 TimeADTGetDatumFast(*aa), 70 TimeADTGetDatumFast(*bb))); 71 } 72 73 static bool 74 gbt_timele(const void *a, const void *b, FmgrInfo *flinfo) 75 { 76 const TimeADT *aa = (const TimeADT *) a; 77 const TimeADT *bb = (const TimeADT *) b; 78 79 return DatumGetBool(DirectFunctionCall2(time_le, 80 TimeADTGetDatumFast(*aa), 81 TimeADTGetDatumFast(*bb))); 82 } 83 84 static bool 85 gbt_timelt(const void *a, const void *b, FmgrInfo *flinfo) 86 { 87 const TimeADT *aa = (const TimeADT *) a; 88 const TimeADT *bb = (const TimeADT *) b; 89 90 return DatumGetBool(DirectFunctionCall2(time_lt, 91 TimeADTGetDatumFast(*aa), 92 TimeADTGetDatumFast(*bb))); 93 } 94 95 96 97 static int 98 gbt_timekey_cmp(const void *a, const void *b, FmgrInfo *flinfo) 99 { 100 timeKEY *ia = (timeKEY *) (((const Nsrt *) a)->t); 101 timeKEY *ib = (timeKEY *) (((const Nsrt *) b)->t); 102 int res; 103 104 res = DatumGetInt32(DirectFunctionCall2(time_cmp, TimeADTGetDatumFast(ia->lower), TimeADTGetDatumFast(ib->lower))); 105 if (res == 0) 106 return DatumGetInt32(DirectFunctionCall2(time_cmp, TimeADTGetDatumFast(ia->upper), TimeADTGetDatumFast(ib->upper))); 107 108 return res; 109 } 110 111 static float8 112 gbt_time_dist(const void *a, const void *b, FmgrInfo *flinfo) 113 { 114 const TimeADT *aa = (const TimeADT *) a; 115 const TimeADT *bb = (const TimeADT *) b; 116 Interval *i; 117 118 i = DatumGetIntervalP(DirectFunctionCall2(time_mi_time, 119 TimeADTGetDatumFast(*aa), 120 TimeADTGetDatumFast(*bb))); 121 return (float8) Abs(INTERVAL_TO_SEC(i)); 122 } 123 124 125 static const gbtree_ninfo tinfo = 126 { 127 gbt_t_time, 128 sizeof(TimeADT), 129 16, /* sizeof(gbtreekey16) */ 130 gbt_timegt, 131 gbt_timege, 132 gbt_timeeq, 133 gbt_timele, 134 gbt_timelt, 135 gbt_timekey_cmp, 136 gbt_time_dist 137 }; 138 139 140 PG_FUNCTION_INFO_V1(time_dist); 141 Datum 142 time_dist(PG_FUNCTION_ARGS) 143 { 144 Datum diff = DirectFunctionCall2(time_mi_time, 145 PG_GETARG_DATUM(0), 146 PG_GETARG_DATUM(1)); 147 148 PG_RETURN_INTERVAL_P(abs_interval(DatumGetIntervalP(diff))); 149 } 150 151 152 /************************************************** 153 * time ops 154 **************************************************/ 155 156 157 158 Datum 159 gbt_time_compress(PG_FUNCTION_ARGS) 160 { 161 GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0); 162 163 PG_RETURN_POINTER(gbt_num_compress(entry, &tinfo)); 164 } 165 166 167 Datum 168 gbt_timetz_compress(PG_FUNCTION_ARGS) 169 { 170 GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0); 171 GISTENTRY *retval; 172 173 if (entry->leafkey) 174 { 175 timeKEY *r = (timeKEY *) palloc(sizeof(timeKEY)); 176 TimeTzADT *tz = DatumGetTimeTzADTP(entry->key); 177 TimeADT tmp; 178 179 retval = palloc(sizeof(GISTENTRY)); 180 181 /* We are using the time + zone only to compress */ 182 tmp = tz->time + (tz->zone * INT64CONST(1000000)); 183 r->lower = r->upper = tmp; 184 gistentryinit(*retval, PointerGetDatum(r), 185 entry->rel, entry->page, 186 entry->offset, false); 187 } 188 else 189 retval = entry; 190 PG_RETURN_POINTER(retval); 191 } 192 193 Datum 194 gbt_time_fetch(PG_FUNCTION_ARGS) 195 { 196 GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0); 197 198 PG_RETURN_POINTER(gbt_num_fetch(entry, &tinfo)); 199 } 200 201 Datum 202 gbt_time_consistent(PG_FUNCTION_ARGS) 203 { 204 GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0); 205 TimeADT query = PG_GETARG_TIMEADT(1); 206 StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2); 207 208 /* Oid subtype = PG_GETARG_OID(3); */ 209 bool *recheck = (bool *) PG_GETARG_POINTER(4); 210 timeKEY *kkk = (timeKEY *) DatumGetPointer(entry->key); 211 GBT_NUMKEY_R key; 212 213 /* All cases served by this function are exact */ 214 *recheck = false; 215 216 key.lower = (GBT_NUMKEY *) &kkk->lower; 217 key.upper = (GBT_NUMKEY *) &kkk->upper; 218 219 PG_RETURN_BOOL( 220 gbt_num_consistent(&key, (void *) &query, &strategy, GIST_LEAF(entry), &tinfo, fcinfo->flinfo) 221 ); 222 } 223 224 Datum 225 gbt_time_distance(PG_FUNCTION_ARGS) 226 { 227 GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0); 228 TimeADT query = PG_GETARG_TIMEADT(1); 229 230 /* Oid subtype = PG_GETARG_OID(3); */ 231 timeKEY *kkk = (timeKEY *) DatumGetPointer(entry->key); 232 GBT_NUMKEY_R key; 233 234 key.lower = (GBT_NUMKEY *) &kkk->lower; 235 key.upper = (GBT_NUMKEY *) &kkk->upper; 236 237 PG_RETURN_FLOAT8( 238 gbt_num_distance(&key, (void *) &query, GIST_LEAF(entry), &tinfo, fcinfo->flinfo) 239 ); 240 } 241 242 Datum 243 gbt_timetz_consistent(PG_FUNCTION_ARGS) 244 { 245 GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0); 246 TimeTzADT *query = PG_GETARG_TIMETZADT_P(1); 247 StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2); 248 249 /* Oid subtype = PG_GETARG_OID(3); */ 250 bool *recheck = (bool *) PG_GETARG_POINTER(4); 251 timeKEY *kkk = (timeKEY *) DatumGetPointer(entry->key); 252 TimeADT qqq; 253 GBT_NUMKEY_R key; 254 255 /* All cases served by this function are inexact */ 256 *recheck = true; 257 258 qqq = query->time + (query->zone * INT64CONST(1000000)); 259 260 key.lower = (GBT_NUMKEY *) &kkk->lower; 261 key.upper = (GBT_NUMKEY *) &kkk->upper; 262 263 PG_RETURN_BOOL( 264 gbt_num_consistent(&key, (void *) &qqq, &strategy, GIST_LEAF(entry), &tinfo, fcinfo->flinfo) 265 ); 266 } 267 268 269 Datum 270 gbt_time_union(PG_FUNCTION_ARGS) 271 { 272 GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0); 273 void *out = palloc(sizeof(timeKEY)); 274 275 *(int *) PG_GETARG_POINTER(1) = sizeof(timeKEY); 276 PG_RETURN_POINTER(gbt_num_union((void *) out, entryvec, &tinfo, fcinfo->flinfo)); 277 } 278 279 280 Datum 281 gbt_time_penalty(PG_FUNCTION_ARGS) 282 { 283 timeKEY *origentry = (timeKEY *) DatumGetPointer(((GISTENTRY *) PG_GETARG_POINTER(0))->key); 284 timeKEY *newentry = (timeKEY *) DatumGetPointer(((GISTENTRY *) PG_GETARG_POINTER(1))->key); 285 float *result = (float *) PG_GETARG_POINTER(2); 286 Interval *intr; 287 double res; 288 double res2; 289 290 intr = DatumGetIntervalP(DirectFunctionCall2( 291 time_mi_time, 292 TimeADTGetDatumFast(newentry->upper), 293 TimeADTGetDatumFast(origentry->upper))); 294 res = INTERVAL_TO_SEC(intr); 295 res = Max(res, 0); 296 297 intr = DatumGetIntervalP(DirectFunctionCall2( 298 time_mi_time, 299 TimeADTGetDatumFast(origentry->lower), 300 TimeADTGetDatumFast(newentry->lower))); 301 res2 = INTERVAL_TO_SEC(intr); 302 res2 = Max(res2, 0); 303 304 res += res2; 305 306 *result = 0.0; 307 308 if (res > 0) 309 { 310 intr = DatumGetIntervalP(DirectFunctionCall2( 311 time_mi_time, 312 TimeADTGetDatumFast(origentry->upper), 313 TimeADTGetDatumFast(origentry->lower))); 314 *result += FLT_MIN; 315 *result += (float) (res / (res + INTERVAL_TO_SEC(intr))); 316 *result *= (FLT_MAX / (((GISTENTRY *) PG_GETARG_POINTER(0))->rel->rd_att->natts + 1)); 317 } 318 319 PG_RETURN_POINTER(result); 320 } 321 322 323 Datum 324 gbt_time_picksplit(PG_FUNCTION_ARGS) 325 { 326 PG_RETURN_POINTER(gbt_num_picksplit( 327 (GistEntryVector *) PG_GETARG_POINTER(0), 328 (GIST_SPLITVEC *) PG_GETARG_POINTER(1), 329 &tinfo, fcinfo->flinfo 330 )); 331 } 332 333 Datum 334 gbt_time_same(PG_FUNCTION_ARGS) 335 { 336 timeKEY *b1 = (timeKEY *) PG_GETARG_POINTER(0); 337 timeKEY *b2 = (timeKEY *) PG_GETARG_POINTER(1); 338 bool *result = (bool *) PG_GETARG_POINTER(2); 339 340 *result = gbt_num_same((void *) b1, (void *) b2, &tinfo, fcinfo->flinfo); 341 PG_RETURN_POINTER(result); 342 } 343