~ubuntu-branches/ubuntu/trusty/postgresql-9.3/trusty-proposed

1 by Martin Pitt
Import upstream version 9.3~beta1
1
/*
2
 * contrib/btree_gist/btree_ts.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/datetime.h"
10
11
typedef struct
12
{
13
	Timestamp	lower;
14
	Timestamp	upper;
15
} tsKEY;
16
17
/*
18
** timestamp ops
19
*/
20
PG_FUNCTION_INFO_V1(gbt_ts_compress);
21
PG_FUNCTION_INFO_V1(gbt_tstz_compress);
22
PG_FUNCTION_INFO_V1(gbt_ts_union);
23
PG_FUNCTION_INFO_V1(gbt_ts_picksplit);
24
PG_FUNCTION_INFO_V1(gbt_ts_consistent);
25
PG_FUNCTION_INFO_V1(gbt_ts_distance);
26
PG_FUNCTION_INFO_V1(gbt_tstz_consistent);
27
PG_FUNCTION_INFO_V1(gbt_tstz_distance);
28
PG_FUNCTION_INFO_V1(gbt_ts_penalty);
29
PG_FUNCTION_INFO_V1(gbt_ts_same);
30
31
Datum		gbt_ts_compress(PG_FUNCTION_ARGS);
32
Datum		gbt_tstz_compress(PG_FUNCTION_ARGS);
33
Datum		gbt_ts_union(PG_FUNCTION_ARGS);
34
Datum		gbt_ts_picksplit(PG_FUNCTION_ARGS);
35
Datum		gbt_ts_consistent(PG_FUNCTION_ARGS);
36
Datum		gbt_ts_distance(PG_FUNCTION_ARGS);
37
Datum		gbt_tstz_consistent(PG_FUNCTION_ARGS);
38
Datum		gbt_tstz_distance(PG_FUNCTION_ARGS);
39
Datum		gbt_ts_penalty(PG_FUNCTION_ARGS);
40
Datum		gbt_ts_same(PG_FUNCTION_ARGS);
41
42
43
#ifdef USE_FLOAT8_BYVAL
44
#define TimestampGetDatumFast(X) TimestampGetDatum(X)
45
#else
46
#define TimestampGetDatumFast(X) PointerGetDatum(&(X))
47
#endif
48
49
50
static bool
51
gbt_tsgt(const void *a, const void *b)
52
{
53
	const Timestamp *aa = (const Timestamp *) a;
54
	const Timestamp *bb = (const Timestamp *) b;
55
56
	return DatumGetBool(DirectFunctionCall2(timestamp_gt,
57
											TimestampGetDatumFast(*aa),
58
											TimestampGetDatumFast(*bb)));
59
}
60
61
static bool
62
gbt_tsge(const void *a, const void *b)
63
{
64
	const Timestamp *aa = (const Timestamp *) a;
65
	const Timestamp *bb = (const Timestamp *) b;
66
67
	return DatumGetBool(DirectFunctionCall2(timestamp_ge,
68
											TimestampGetDatumFast(*aa),
69
											TimestampGetDatumFast(*bb)));
70
}
71
72
static bool
73
gbt_tseq(const void *a, const void *b)
74
{
75
	const Timestamp *aa = (const Timestamp *) a;
76
	const Timestamp *bb = (const Timestamp *) b;
77
78
	return DatumGetBool(DirectFunctionCall2(timestamp_eq,
79
											TimestampGetDatumFast(*aa),
80
											TimestampGetDatumFast(*bb)));
81
}
82
83
static bool
84
gbt_tsle(const void *a, const void *b)
85
{
86
	const Timestamp *aa = (const Timestamp *) a;
87
	const Timestamp *bb = (const Timestamp *) b;
88
89
	return DatumGetBool(DirectFunctionCall2(timestamp_le,
90
											TimestampGetDatumFast(*aa),
91
											TimestampGetDatumFast(*bb)));
92
}
93
94
static bool
95
gbt_tslt(const void *a, const void *b)
96
{
97
	const Timestamp *aa = (const Timestamp *) a;
98
	const Timestamp *bb = (const Timestamp *) b;
99
100
	return DatumGetBool(DirectFunctionCall2(timestamp_lt,
101
											TimestampGetDatumFast(*aa),
102
											TimestampGetDatumFast(*bb)));
103
}
104
105
106
static int
107
gbt_tskey_cmp(const void *a, const void *b)
108
{
109
	tsKEY	   *ia = (tsKEY *) (((const Nsrt *) a)->t);
110
	tsKEY	   *ib = (tsKEY *) (((const Nsrt *) b)->t);
111
	int			res;
112
113
	res = DatumGetInt32(DirectFunctionCall2(timestamp_cmp, TimestampGetDatumFast(ia->lower), TimestampGetDatumFast(ib->lower)));
114
	if (res == 0)
115
		return DatumGetInt32(DirectFunctionCall2(timestamp_cmp, TimestampGetDatumFast(ia->upper), TimestampGetDatumFast(ib->upper)));
116
117
	return res;
118
}
119
120
static float8
121
gbt_ts_dist(const void *a, const void *b)
122
{
123
	const Timestamp *aa = (const Timestamp *) a;
124
	const Timestamp *bb = (const Timestamp *) b;
125
	Interval   *i;
126
127
	if (TIMESTAMP_NOT_FINITE(*aa) || TIMESTAMP_NOT_FINITE(*bb))
128
		return get_float8_infinity();
129
130
	i = DatumGetIntervalP(DirectFunctionCall2(timestamp_mi,
131
											  TimestampGetDatumFast(*aa),
132
											  TimestampGetDatumFast(*bb)));
133
	return (float8) Abs(INTERVAL_TO_SEC(i));
134
}
135
136
137
static const gbtree_ninfo tinfo =
138
{
139
	gbt_t_ts,
140
	sizeof(Timestamp),
141
	gbt_tsgt,
142
	gbt_tsge,
143
	gbt_tseq,
144
	gbt_tsle,
145
	gbt_tslt,
146
	gbt_tskey_cmp,
147
	gbt_ts_dist
148
};
149
150
151
PG_FUNCTION_INFO_V1(ts_dist);
152
Datum		ts_dist(PG_FUNCTION_ARGS);
153
Datum
154
ts_dist(PG_FUNCTION_ARGS)
155
{
156
	Timestamp	a = PG_GETARG_TIMESTAMP(0);
157
	Timestamp	b = PG_GETARG_TIMESTAMP(1);
158
	Interval   *r;
159
160
	if (TIMESTAMP_NOT_FINITE(a) || TIMESTAMP_NOT_FINITE(b))
161
	{
162
		Interval   *p = palloc(sizeof(Interval));
163
164
		p->day = INT_MAX;
165
		p->month = INT_MAX;
166
#ifdef HAVE_INT64_TIMESTAMP
167
		p->time = INT64CONST(0x7FFFFFFFFFFFFFFF);
168
#else
169
		p->time = DBL_MAX;
170
#endif
171
		PG_RETURN_INTERVAL_P(p);
172
	}
173
	else
174
		r = DatumGetIntervalP(DirectFunctionCall2(timestamp_mi,
175
												  PG_GETARG_DATUM(0),
176
												  PG_GETARG_DATUM(1)));
177
	PG_RETURN_INTERVAL_P(abs_interval(r));
178
}
179
180
PG_FUNCTION_INFO_V1(tstz_dist);
181
Datum		tstz_dist(PG_FUNCTION_ARGS);
182
Datum
183
tstz_dist(PG_FUNCTION_ARGS)
184
{
185
	TimestampTz a = PG_GETARG_TIMESTAMPTZ(0);
186
	TimestampTz b = PG_GETARG_TIMESTAMPTZ(1);
187
	Interval   *r;
188
189
	if (TIMESTAMP_NOT_FINITE(a) || TIMESTAMP_NOT_FINITE(b))
190
	{
191
		Interval   *p = palloc(sizeof(Interval));
192
193
		p->day = INT_MAX;
194
		p->month = INT_MAX;
195
#ifdef HAVE_INT64_TIMESTAMP
196
		p->time = INT64CONST(0x7FFFFFFFFFFFFFFF);
197
#else
198
		p->time = DBL_MAX;
199
#endif
200
		PG_RETURN_INTERVAL_P(p);
201
	}
202
203
	r = DatumGetIntervalP(DirectFunctionCall2(timestamp_mi,
204
											  PG_GETARG_DATUM(0),
205
											  PG_GETARG_DATUM(1)));
206
	PG_RETURN_INTERVAL_P(abs_interval(r));
207
}
208
209
210
/**************************************************
211
 * timestamp ops
212
 **************************************************/
213
214
1.2.1 by Martin Pitt
Import upstream version 9.3.6
215
static inline Timestamp
1 by Martin Pitt
Import upstream version 9.3~beta1
216
tstz_to_ts_gmt(TimestampTz ts)
217
{
1.2.1 by Martin Pitt
Import upstream version 9.3.6
218
	/* No timezone correction is needed, since GMT is offset 0 by definition */
219
	return (Timestamp) ts;
1 by Martin Pitt
Import upstream version 9.3~beta1
220
}
221
222
223
Datum
224
gbt_ts_compress(PG_FUNCTION_ARGS)
225
{
226
	GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
227
	GISTENTRY  *retval = NULL;
228
229
	PG_RETURN_POINTER(gbt_num_compress(retval, entry, &tinfo));
230
}
231
232
233
Datum
234
gbt_tstz_compress(PG_FUNCTION_ARGS)
235
{
236
	GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
237
	GISTENTRY  *retval;
238
239
	if (entry->leafkey)
240
	{
241
		tsKEY	   *r = (tsKEY *) palloc(sizeof(tsKEY));
242
		TimestampTz ts = DatumGetTimestampTz(entry->key);
243
		Timestamp	gmt;
244
245
		gmt = tstz_to_ts_gmt(ts);
246
247
		retval = palloc(sizeof(GISTENTRY));
248
		r->lower = r->upper = gmt;
249
		gistentryinit(*retval, PointerGetDatum(r),
250
					  entry->rel, entry->page,
251
					  entry->offset, FALSE);
252
	}
253
	else
254
		retval = entry;
255
256
	PG_RETURN_POINTER(retval);
257
}
258
259
260
Datum
261
gbt_ts_consistent(PG_FUNCTION_ARGS)
262
{
263
	GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
264
	Timestamp	query = PG_GETARG_TIMESTAMP(1);
265
	StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
266
267
	/* Oid		subtype = PG_GETARG_OID(3); */
268
	bool	   *recheck = (bool *) PG_GETARG_POINTER(4);
269
	tsKEY	   *kkk = (tsKEY *) DatumGetPointer(entry->key);
270
	GBT_NUMKEY_R key;
271
272
	/* All cases served by this function are exact */
273
	*recheck = false;
274
275
	key.lower = (GBT_NUMKEY *) &kkk->lower;
276
	key.upper = (GBT_NUMKEY *) &kkk->upper;
277
278
	PG_RETURN_BOOL(
279
				   gbt_num_consistent(&key, (void *) &query, &strategy, GIST_LEAF(entry), &tinfo)
280
		);
281
}
282
283
Datum
284
gbt_ts_distance(PG_FUNCTION_ARGS)
285
{
286
	GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
287
	Timestamp	query = PG_GETARG_TIMESTAMP(1);
288
289
	/* Oid		subtype = PG_GETARG_OID(3); */
290
	tsKEY	   *kkk = (tsKEY *) DatumGetPointer(entry->key);
291
	GBT_NUMKEY_R key;
292
293
	key.lower = (GBT_NUMKEY *) &kkk->lower;
294
	key.upper = (GBT_NUMKEY *) &kkk->upper;
295
296
	PG_RETURN_FLOAT8(
297
			gbt_num_distance(&key, (void *) &query, GIST_LEAF(entry), &tinfo)
298
		);
299
}
300
301
Datum
302
gbt_tstz_consistent(PG_FUNCTION_ARGS)
303
{
304
	GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
305
	TimestampTz query = PG_GETARG_TIMESTAMPTZ(1);
306
	StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
307
308
	/* Oid		subtype = PG_GETARG_OID(3); */
309
	bool	   *recheck = (bool *) PG_GETARG_POINTER(4);
310
	char	   *kkk = (char *) DatumGetPointer(entry->key);
311
	GBT_NUMKEY_R key;
312
	Timestamp	qqq;
313
314
	/* All cases served by this function are exact */
315
	*recheck = false;
316
317
	key.lower = (GBT_NUMKEY *) &kkk[0];
318
	key.upper = (GBT_NUMKEY *) &kkk[MAXALIGN(tinfo.size)];
319
	qqq = tstz_to_ts_gmt(query);
320
321
	PG_RETURN_BOOL(
322
				   gbt_num_consistent(&key, (void *) &qqq, &strategy, GIST_LEAF(entry), &tinfo)
323
		);
324
}
325
326
Datum
327
gbt_tstz_distance(PG_FUNCTION_ARGS)
328
{
329
	GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
330
	TimestampTz query = PG_GETARG_TIMESTAMPTZ(1);
331
332
	/* Oid		subtype = PG_GETARG_OID(3); */
333
	char	   *kkk = (char *) DatumGetPointer(entry->key);
334
	GBT_NUMKEY_R key;
335
	Timestamp	qqq;
336
337
	key.lower = (GBT_NUMKEY *) &kkk[0];
338
	key.upper = (GBT_NUMKEY *) &kkk[MAXALIGN(tinfo.size)];
339
	qqq = tstz_to_ts_gmt(query);
340
341
	PG_RETURN_FLOAT8(
342
			  gbt_num_distance(&key, (void *) &qqq, GIST_LEAF(entry), &tinfo)
343
		);
344
}
345
346
347
Datum
348
gbt_ts_union(PG_FUNCTION_ARGS)
349
{
350
	GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
351
	void	   *out = palloc(sizeof(tsKEY));
352
353
	*(int *) PG_GETARG_POINTER(1) = sizeof(tsKEY);
354
	PG_RETURN_POINTER(gbt_num_union((void *) out, entryvec, &tinfo));
355
}
356
357
358
#define penalty_check_max_float(val) do { \
359
		if ( val > FLT_MAX ) \
360
				val = FLT_MAX; \
361
		if ( val < -FLT_MAX ) \
362
				val = -FLT_MAX; \
363
} while(false);
364
365
366
Datum
367
gbt_ts_penalty(PG_FUNCTION_ARGS)
368
{
369
	tsKEY	   *origentry = (tsKEY *) DatumGetPointer(((GISTENTRY *) PG_GETARG_POINTER(0))->key);
370
	tsKEY	   *newentry = (tsKEY *) DatumGetPointer(((GISTENTRY *) PG_GETARG_POINTER(1))->key);
371
	float	   *result = (float *) PG_GETARG_POINTER(2);
372
373
	double		orgdbl[2],
374
				newdbl[2];
375
376
	/*
1.2.3 by Martin Pitt
Import upstream version 9.3.10
377
	 * We are always using "double" timestamps here. Precision should be good
1 by Martin Pitt
Import upstream version 9.3~beta1
378
	 * enough.
379
	 */
380
	orgdbl[0] = ((double) origentry->lower);
381
	orgdbl[1] = ((double) origentry->upper);
382
	newdbl[0] = ((double) newentry->lower);
383
	newdbl[1] = ((double) newentry->upper);
384
385
	penalty_check_max_float(orgdbl[0]);
386
	penalty_check_max_float(orgdbl[1]);
387
	penalty_check_max_float(newdbl[0]);
388
	penalty_check_max_float(newdbl[1]);
389
390
	penalty_num(result, orgdbl[0], orgdbl[1], newdbl[0], newdbl[1]);
391
392
	PG_RETURN_POINTER(result);
393
394
}
395
396
397
Datum
398
gbt_ts_picksplit(PG_FUNCTION_ARGS)
399
{
400
	PG_RETURN_POINTER(gbt_num_picksplit(
401
									(GistEntryVector *) PG_GETARG_POINTER(0),
402
									  (GIST_SPLITVEC *) PG_GETARG_POINTER(1),
403
										&tinfo
404
										));
405
}
406
407
Datum
408
gbt_ts_same(PG_FUNCTION_ARGS)
409
{
410
	tsKEY	   *b1 = (tsKEY *) PG_GETARG_POINTER(0);
411
	tsKEY	   *b2 = (tsKEY *) PG_GETARG_POINTER(1);
412
	bool	   *result = (bool *) PG_GETARG_POINTER(2);
413
414
	*result = gbt_num_same((void *) b1, (void *) b2, &tinfo);
415
	PG_RETURN_POINTER(result);
416
}