PostgreSQL Source Code git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
nbtcompare.c
Go to the documentation of this file.
1/*-------------------------------------------------------------------------
2 *
3 * nbtcompare.c
4 * Comparison functions for btree access method.
5 *
6 * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
8 *
9 *
10 * IDENTIFICATION
11 * src/backend/access/nbtree/nbtcompare.c
12 *
13 * NOTES
14 *
15 * These functions are stored in pg_amproc. For each operator class
16 * defined on btrees, they compute
17 *
18 * compare(a, b):
19 * < 0 if a < b,
20 * = 0 if a == b,
21 * > 0 if a > b.
22 *
23 * The result is always an int32 regardless of the input datatype.
24 *
25 * Although any negative int32 is acceptable for reporting "<",
26 * and any positive int32 is acceptable for reporting ">", routines
27 * that work on 32-bit or wider datatypes can't just return "a - b".
28 * That could overflow and give the wrong answer.
29 *
30 * NOTE: it is critical that the comparison function impose a total order
31 * on all non-NULL values of the data type, and that the datatype's
32 * boolean comparison operators (= < >= etc) yield results consistent
33 * with the comparison routine. Otherwise bad behavior may ensue.
34 * (For example, the comparison operators must NOT punt when faced with
35 * NAN or other funny values; you must devise some collation sequence for
36 * all such values.) If the datatype is not trivial, this is most
37 * reliably done by having the boolean operators invoke the same
38 * three-way comparison code that the btree function does. Therefore,
39 * this file contains only btree support for "trivial" datatypes ---
40 * all others are in the /utils/adt/ files that implement their datatypes.
41 *
42 * NOTE: these routines must not leak memory, since memory allocated
43 * during an index access won't be recovered till end of query. This
44 * primarily affects comparison routines for toastable datatypes;
45 * they have to be careful to free any detoasted copy of an input datum.
46 *
47 * NOTE: we used to forbid comparison functions from returning INT_MIN,
48 * but that proves to be too error-prone because some platforms' versions
49 * of memcmp() etc can return INT_MIN. As a means of stress-testing
50 * callers, this file can be compiled with STRESS_SORT_INT_MIN defined
51 * to cause many of these functions to return INT_MIN or INT_MAX instead of
52 * their customary -1/+1. For production, though, that's not a good idea
53 * since users or third-party code might expect the traditional results.
54 *-------------------------------------------------------------------------
55 */
56#include "postgres.h"
57
58#include <limits.h>
59
60#include "utils/fmgrprotos.h"
61#include "utils/skipsupport.h"
62#include "utils/sortsupport.h"
63
64#ifdef STRESS_SORT_INT_MIN
65#define A_LESS_THAN_B INT_MIN
66#define A_GREATER_THAN_B INT_MAX
67#else
68#define A_LESS_THAN_B (-1)
69#define A_GREATER_THAN_B 1
70#endif
71
72
75{
76 bool a = PG_GETARG_BOOL(0);
77 bool b = PG_GETARG_BOOL(1);
78
80}
81
82static Datum
83bool_decrement(Relation rel, Datum existing, bool *underflow)
84{
85 bool bexisting = DatumGetBool(existing);
86
87 if (bexisting == false)
88 {
89 /* return value is undefined */
90 *underflow = true;
91 return (Datum) 0;
92 }
93
94 *underflow = false;
95 return BoolGetDatum(bexisting - 1);
96}
97
98static Datum
99bool_increment(Relation rel, Datum existing, bool *overflow)
100{
101 bool bexisting = DatumGetBool(existing);
102
103 if (bexisting == true)
104 {
105 /* return value is undefined */
106 *overflow = true;
107 return (Datum) 0;
108 }
109
110 *overflow = false;
111 return BoolGetDatum(bexisting + 1);
112}
113
114Datum
116{
118
119 sksup->decrement = bool_decrement;
120 sksup->increment = bool_increment;
121 sksup->low_elem = BoolGetDatum(false);
122 sksup->high_elem = BoolGetDatum(true);
123
125}
126
127Datum
129{
132
134}
135
136static int
138{
141
142 return (int) a - (int) b;
143}
144
145Datum
147{
149
152}
153
154static Datum
155int2_decrement(Relation rel, Datum existing, bool *underflow)
156{
157 int16 iexisting = DatumGetInt16(existing);
158
159 if (iexisting == PG_INT16_MIN)
160 {
161 /* return value is undefined */
162 *underflow = true;
163 return (Datum) 0;
164 }
165
166 *underflow = false;
167 return Int16GetDatum(iexisting - 1);
168}
169
170static Datum
171int2_increment(Relation rel, Datum existing, bool *overflow)
172{
173 int16 iexisting = DatumGetInt16(existing);
174
175 if (iexisting == PG_INT16_MAX)
176 {
177 /* return value is undefined */
178 *overflow = true;
179 return (Datum) 0;
180 }
181
182 *overflow = false;
183 return Int16GetDatum(iexisting + 1);
184}
185
186Datum
188{
190
191 sksup->decrement = int2_decrement;
192 sksup->increment = int2_increment;
195
197}
198
199Datum
201{
204
205 if (a > b)
207 else if (a == b)
209 else
211}
212
213Datum
215{
217
220}
221
222static Datum
223int4_decrement(Relation rel, Datum existing, bool *underflow)
224{
225 int32 iexisting = DatumGetInt32(existing);
226
227 if (iexisting == PG_INT32_MIN)
228 {
229 /* return value is undefined */
230 *underflow = true;
231 return (Datum) 0;
232 }
233
234 *underflow = false;
235 return Int32GetDatum(iexisting - 1);
236}
237
238static Datum
239int4_increment(Relation rel, Datum existing, bool *overflow)
240{
241 int32 iexisting = DatumGetInt32(existing);
242
243 if (iexisting == PG_INT32_MAX)
244 {
245 /* return value is undefined */
246 *overflow = true;
247 return (Datum) 0;
248 }
249
250 *overflow = false;
251 return Int32GetDatum(iexisting + 1);
252}
253
254Datum
256{
258
259 sksup->decrement = int4_decrement;
260 sksup->increment = int4_increment;
263
265}
266
267Datum
269{
272
273 if (a > b)
275 else if (a == b)
277 else
279}
280
281Datum
283{
285
288}
289
290static Datum
291int8_decrement(Relation rel, Datum existing, bool *underflow)
292{
293 int64 iexisting = DatumGetInt64(existing);
294
295 if (iexisting == PG_INT64_MIN)
296 {
297 /* return value is undefined */
298 *underflow = true;
299 return (Datum) 0;
300 }
301
302 *underflow = false;
303 return Int64GetDatum(iexisting - 1);
304}
305
306static Datum
307int8_increment(Relation rel, Datum existing, bool *overflow)
308{
309 int64 iexisting = DatumGetInt64(existing);
310
311 if (iexisting == PG_INT64_MAX)
312 {
313 /* return value is undefined */
314 *overflow = true;
315 return (Datum) 0;
316 }
317
318 *overflow = false;
319 return Int64GetDatum(iexisting + 1);
320}
321
322Datum
324{
326
327 sksup->decrement = int8_decrement;
328 sksup->increment = int8_increment;
331
333}
334
335Datum
337{
340
341 if (a > b)
343 else if (a == b)
345 else
347}
348
349Datum
351{
354
355 if (a > b)
357 else if (a == b)
359 else
361}
362
363Datum
365{
368
369 if (a > b)
371 else if (a == b)
373 else
375}
376
377Datum
379{
382
383 if (a > b)
385 else if (a == b)
387 else
389}
390
391Datum
393{
396
397 if (a > b)
399 else if (a == b)
401 else
403}
404
405Datum
407{
410
411 if (a > b)
413 else if (a == b)
415 else
417}
418
419Datum
421{
422 Oid a = PG_GETARG_OID(0);
423 Oid b = PG_GETARG_OID(1);
424
425 if (a > b)
427 else if (a == b)
429 else
431}
432
433static int
435{
438
439 if (a > b)
440 return A_GREATER_THAN_B;
441 else if (a == b)
442 return 0;
443 else
444 return A_LESS_THAN_B;
445}
446
447Datum
449{
451
452 ssup->comparator = btoidfastcmp;
454}
455
456static Datum
457oid_decrement(Relation rel, Datum existing, bool *underflow)
458{
459 Oid oexisting = DatumGetObjectId(existing);
460
461 if (oexisting == InvalidOid)
462 {
463 /* return value is undefined */
464 *underflow = true;
465 return (Datum) 0;
466 }
467
468 *underflow = false;
469 return ObjectIdGetDatum(oexisting - 1);
470}
471
472static Datum
473oid_increment(Relation rel, Datum existing, bool *overflow)
474{
475 Oid oexisting = DatumGetObjectId(existing);
476
477 if (oexisting == OID_MAX)
478 {
479 /* return value is undefined */
480 *overflow = true;
481 return (Datum) 0;
482 }
483
484 *overflow = false;
485 return ObjectIdGetDatum(oexisting + 1);
486}
487
488Datum
490{
492
493 sksup->decrement = oid_decrement;
494 sksup->increment = oid_increment;
497
499}
500
501Datum
503{
506 int i;
507
508 /* We arbitrarily choose to sort first by vector length */
509 if (a->dim1 != b->dim1)
510 PG_RETURN_INT32(a->dim1 - b->dim1);
511
512 for (i = 0; i < a->dim1; i++)
513 {
514 if (a->values[i] != b->values[i])
515 {
516 if (a->values[i] > b->values[i])
518 else
520 }
521 }
523}
524
525Datum
527{
528 char a = PG_GETARG_CHAR(0);
529 char b = PG_GETARG_CHAR(1);
530
531 /* Be careful to compare chars as unsigned */
532 PG_RETURN_INT32((int32) ((uint8) a) - (int32) ((uint8) b));
533}
534
535static Datum
536char_decrement(Relation rel, Datum existing, bool *underflow)
537{
538 uint8 cexisting = DatumGetUInt8(existing);
539
540 if (cexisting == 0)
541 {
542 /* return value is undefined */
543 *underflow = true;
544 return (Datum) 0;
545 }
546
547 *underflow = false;
548 return CharGetDatum((uint8) cexisting - 1);
549}
550
551static Datum
552char_increment(Relation rel, Datum existing, bool *overflow)
553{
554 uint8 cexisting = DatumGetUInt8(existing);
555
556 if (cexisting == UCHAR_MAX)
557 {
558 /* return value is undefined */
559 *overflow = true;
560 return (Datum) 0;
561 }
562
563 *overflow = false;
564 return CharGetDatum((uint8) cexisting + 1);
565}
566
567Datum
569{
571
572 sksup->decrement = char_decrement;
573 sksup->increment = char_increment;
574
575 /* btcharcmp compares chars as unsigned */
576 sksup->low_elem = UInt8GetDatum(0);
577 sksup->high_elem = UInt8GetDatum(UCHAR_MAX);
578
580}
#define PG_INT32_MAX
Definition: c.h:598
uint8_t uint8
Definition: c.h:540
int64_t int64
Definition: c.h:539
int16_t int16
Definition: c.h:537
#define PG_INT16_MIN
Definition: c.h:594
int32_t int32
Definition: c.h:538
#define PG_INT64_MAX
Definition: c.h:601
#define PG_INT64_MIN
Definition: c.h:600
#define PG_INT32_MIN
Definition: c.h:597
#define PG_INT16_MAX
Definition: c.h:595
#define PG_RETURN_VOID()
Definition: fmgr.h:349
#define PG_GETARG_OID(n)
Definition: fmgr.h:275
#define PG_GETARG_CHAR(n)
Definition: fmgr.h:273
#define PG_GETARG_POINTER(n)
Definition: fmgr.h:276
#define PG_GETARG_INT64(n)
Definition: fmgr.h:283
#define PG_RETURN_INT32(x)
Definition: fmgr.h:354
#define PG_GETARG_INT32(n)
Definition: fmgr.h:269
#define PG_GETARG_BOOL(n)
Definition: fmgr.h:274
#define PG_FUNCTION_ARGS
Definition: fmgr.h:193
#define PG_GETARG_INT16(n)
Definition: fmgr.h:271
int y
Definition: isn.c:76
int b
Definition: isn.c:74
int x
Definition: isn.c:75
int a
Definition: isn.c:73
int i
Definition: isn.c:77
Datum btoidvectorcmp(PG_FUNCTION_ARGS)
Definition: nbtcompare.c:502
Datum btint4cmp(PG_FUNCTION_ARGS)
Definition: nbtcompare.c:200
static Datum char_decrement(Relation rel, Datum existing, bool *underflow)
Definition: nbtcompare.c:536
Datum btint4skipsupport(PG_FUNCTION_ARGS)
Definition: nbtcompare.c:255
static Datum int8_decrement(Relation rel, Datum existing, bool *underflow)
Definition: nbtcompare.c:291
Datum btboolcmp(PG_FUNCTION_ARGS)
Definition: nbtcompare.c:74
static Datum bool_increment(Relation rel, Datum existing, bool *overflow)
Definition: nbtcompare.c:99
static Datum int2_decrement(Relation rel, Datum existing, bool *underflow)
Definition: nbtcompare.c:155
#define A_GREATER_THAN_B
Definition: nbtcompare.c:69
Datum btint2cmp(PG_FUNCTION_ARGS)
Definition: nbtcompare.c:128
Datum btint24cmp(PG_FUNCTION_ARGS)
Definition: nbtcompare.c:364
static Datum int4_increment(Relation rel, Datum existing, bool *overflow)
Definition: nbtcompare.c:239
static Datum int4_decrement(Relation rel, Datum existing, bool *underflow)
Definition: nbtcompare.c:223
static Datum oid_increment(Relation rel, Datum existing, bool *overflow)
Definition: nbtcompare.c:473
Datum btoidcmp(PG_FUNCTION_ARGS)
Definition: nbtcompare.c:420
Datum btoidskipsupport(PG_FUNCTION_ARGS)
Definition: nbtcompare.c:489
static Datum bool_decrement(Relation rel, Datum existing, bool *underflow)
Definition: nbtcompare.c:83
Datum btint2skipsupport(PG_FUNCTION_ARGS)
Definition: nbtcompare.c:187
static Datum oid_decrement(Relation rel, Datum existing, bool *underflow)
Definition: nbtcompare.c:457
static int btint2fastcmp(Datum x, Datum y, SortSupport ssup)
Definition: nbtcompare.c:137
Datum btint84cmp(PG_FUNCTION_ARGS)
Definition: nbtcompare.c:350
Datum btoidsortsupport(PG_FUNCTION_ARGS)
Definition: nbtcompare.c:448
Datum btcharcmp(PG_FUNCTION_ARGS)
Definition: nbtcompare.c:526
#define A_LESS_THAN_B
Definition: nbtcompare.c:68
Datum btboolskipsupport(PG_FUNCTION_ARGS)
Definition: nbtcompare.c:115
static int btoidfastcmp(Datum x, Datum y, SortSupport ssup)
Definition: nbtcompare.c:434
Datum btint8sortsupport(PG_FUNCTION_ARGS)
Definition: nbtcompare.c:282
Datum btint82cmp(PG_FUNCTION_ARGS)
Definition: nbtcompare.c:406
static Datum int8_increment(Relation rel, Datum existing, bool *overflow)
Definition: nbtcompare.c:307
Datum btint8skipsupport(PG_FUNCTION_ARGS)
Definition: nbtcompare.c:323
Datum btint48cmp(PG_FUNCTION_ARGS)
Definition: nbtcompare.c:336
static Datum int2_increment(Relation rel, Datum existing, bool *overflow)
Definition: nbtcompare.c:171
static Datum char_increment(Relation rel, Datum existing, bool *overflow)
Definition: nbtcompare.c:552
Datum btcharskipsupport(PG_FUNCTION_ARGS)
Definition: nbtcompare.c:568
Datum btint8cmp(PG_FUNCTION_ARGS)
Definition: nbtcompare.c:268
Datum btint4sortsupport(PG_FUNCTION_ARGS)
Definition: nbtcompare.c:214
Datum btint42cmp(PG_FUNCTION_ARGS)
Definition: nbtcompare.c:378
Datum btint28cmp(PG_FUNCTION_ARGS)
Definition: nbtcompare.c:392
Datum btint2sortsupport(PG_FUNCTION_ARGS)
Definition: nbtcompare.c:146
static Datum Int64GetDatum(int64 X)
Definition: postgres.h:403
static bool DatumGetBool(Datum X)
Definition: postgres.h:100
static int64 DatumGetInt64(Datum X)
Definition: postgres.h:393
static Oid DatumGetObjectId(Datum X)
Definition: postgres.h:252
static Datum Int16GetDatum(int16 X)
Definition: postgres.h:182
static Datum BoolGetDatum(bool X)
Definition: postgres.h:112
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:262
uint64_t Datum
Definition: postgres.h:70
static uint8 DatumGetUInt8(Datum X)
Definition: postgres.h:152
static Datum UInt8GetDatum(uint8 X)
Definition: postgres.h:162
static Datum Int32GetDatum(int32 X)
Definition: postgres.h:222
static int16 DatumGetInt16(Datum X)
Definition: postgres.h:172
static int32 DatumGetInt32(Datum X)
Definition: postgres.h:212
static Datum CharGetDatum(char X)
Definition: postgres.h:132
#define InvalidOid
Definition: postgres_ext.h:37
unsigned int Oid
Definition: postgres_ext.h:32
#define OID_MAX
Definition: postgres_ext.h:40
struct SkipSupportData * SkipSupport
Definition: skipsupport.h:50
struct SortSupportData * SortSupport
Definition: sortsupport.h:58
SkipSupportIncDec decrement
Definition: skipsupport.h:91
SkipSupportIncDec increment
Definition: skipsupport.h:92
int(* comparator)(Datum x, Datum y, SortSupport ssup)
Definition: sortsupport.h:106
Definition: c.h:735
int ssup_datum_signed_cmp(Datum x, Datum y, SortSupport ssup)
Definition: tuplesort.c:3144
int ssup_datum_int32_cmp(Datum x, Datum y, SortSupport ssup)
Definition: tuplesort.c:3158