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
281#if SIZEOF_DATUM < 8
282static int
284{
287
288 if (a > b)
289 return A_GREATER_THAN_B;
290 else if (a == b)
291 return 0;
292 else
293 return A_LESS_THAN_B;
294}
295#endif
296
297Datum
299{
301
302#if SIZEOF_DATUM >= 8
303 ssup->comparator = ssup_datum_signed_cmp;
304#else
306#endif
308}
309
310static Datum
311int8_decrement(Relation rel, Datum existing, bool *underflow)
312{
313 int64 iexisting = DatumGetInt64(existing);
314
315 if (iexisting == PG_INT64_MIN)
316 {
317 /* return value is undefined */
318 *underflow = true;
319 return (Datum) 0;
320 }
321
322 *underflow = false;
323 return Int64GetDatum(iexisting - 1);
324}
325
326static Datum
327int8_increment(Relation rel, Datum existing, bool *overflow)
328{
329 int64 iexisting = DatumGetInt64(existing);
330
331 if (iexisting == PG_INT64_MAX)
332 {
333 /* return value is undefined */
334 *overflow = true;
335 return (Datum) 0;
336 }
337
338 *overflow = false;
339 return Int64GetDatum(iexisting + 1);
340}
341
342Datum
344{
346
347 sksup->decrement = int8_decrement;
348 sksup->increment = int8_increment;
351
353}
354
355Datum
357{
360
361 if (a > b)
363 else if (a == b)
365 else
367}
368
369Datum
371{
374
375 if (a > b)
377 else if (a == b)
379 else
381}
382
383Datum
385{
388
389 if (a > b)
391 else if (a == b)
393 else
395}
396
397Datum
399{
402
403 if (a > b)
405 else if (a == b)
407 else
409}
410
411Datum
413{
416
417 if (a > b)
419 else if (a == b)
421 else
423}
424
425Datum
427{
430
431 if (a > b)
433 else if (a == b)
435 else
437}
438
439Datum
441{
442 Oid a = PG_GETARG_OID(0);
443 Oid b = PG_GETARG_OID(1);
444
445 if (a > b)
447 else if (a == b)
449 else
451}
452
453static int
455{
458
459 if (a > b)
460 return A_GREATER_THAN_B;
461 else if (a == b)
462 return 0;
463 else
464 return A_LESS_THAN_B;
465}
466
467Datum
469{
471
472 ssup->comparator = btoidfastcmp;
474}
475
476static Datum
477oid_decrement(Relation rel, Datum existing, bool *underflow)
478{
479 Oid oexisting = DatumGetObjectId(existing);
480
481 if (oexisting == InvalidOid)
482 {
483 /* return value is undefined */
484 *underflow = true;
485 return (Datum) 0;
486 }
487
488 *underflow = false;
489 return ObjectIdGetDatum(oexisting - 1);
490}
491
492static Datum
493oid_increment(Relation rel, Datum existing, bool *overflow)
494{
495 Oid oexisting = DatumGetObjectId(existing);
496
497 if (oexisting == OID_MAX)
498 {
499 /* return value is undefined */
500 *overflow = true;
501 return (Datum) 0;
502 }
503
504 *overflow = false;
505 return ObjectIdGetDatum(oexisting + 1);
506}
507
508Datum
510{
512
513 sksup->decrement = oid_decrement;
514 sksup->increment = oid_increment;
517
519}
520
521Datum
523{
526 int i;
527
528 /* We arbitrarily choose to sort first by vector length */
529 if (a->dim1 != b->dim1)
530 PG_RETURN_INT32(a->dim1 - b->dim1);
531
532 for (i = 0; i < a->dim1; i++)
533 {
534 if (a->values[i] != b->values[i])
535 {
536 if (a->values[i] > b->values[i])
538 else
540 }
541 }
543}
544
545Datum
547{
548 char a = PG_GETARG_CHAR(0);
549 char b = PG_GETARG_CHAR(1);
550
551 /* Be careful to compare chars as unsigned */
552 PG_RETURN_INT32((int32) ((uint8) a) - (int32) ((uint8) b));
553}
554
555static Datum
556char_decrement(Relation rel, Datum existing, bool *underflow)
557{
558 uint8 cexisting = UInt8GetDatum(existing);
559
560 if (cexisting == 0)
561 {
562 /* return value is undefined */
563 *underflow = true;
564 return (Datum) 0;
565 }
566
567 *underflow = false;
568 return CharGetDatum((uint8) cexisting - 1);
569}
570
571static Datum
572char_increment(Relation rel, Datum existing, bool *overflow)
573{
574 uint8 cexisting = UInt8GetDatum(existing);
575
576 if (cexisting == UCHAR_MAX)
577 {
578 /* return value is undefined */
579 *overflow = true;
580 return (Datum) 0;
581 }
582
583 *overflow = false;
584 return CharGetDatum((uint8) cexisting + 1);
585}
586
587Datum
589{
591
592 sksup->decrement = char_decrement;
593 sksup->increment = char_increment;
594
595 /* btcharcmp compares chars as unsigned */
596 sksup->low_elem = UInt8GetDatum(0);
597 sksup->high_elem = UInt8GetDatum(UCHAR_MAX);
598
600}
#define PG_INT32_MAX
Definition: c.h:560
uint8_t uint8
Definition: c.h:500
int64_t int64
Definition: c.h:499
int16_t int16
Definition: c.h:497
#define PG_INT16_MIN
Definition: c.h:556
int32_t int32
Definition: c.h:498
#define PG_INT64_MAX
Definition: c.h:563
#define PG_INT64_MIN
Definition: c.h:562
#define PG_INT32_MIN
Definition: c.h:559
#define PG_INT16_MAX
Definition: c.h:557
Datum Int64GetDatum(int64 X)
Definition: fmgr.c:1807
#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:522
Datum btint4cmp(PG_FUNCTION_ARGS)
Definition: nbtcompare.c:200
static Datum char_decrement(Relation rel, Datum existing, bool *underflow)
Definition: nbtcompare.c:556
Datum btint4skipsupport(PG_FUNCTION_ARGS)
Definition: nbtcompare.c:255
static Datum int8_decrement(Relation rel, Datum existing, bool *underflow)
Definition: nbtcompare.c:311
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:384
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:493
Datum btoidcmp(PG_FUNCTION_ARGS)
Definition: nbtcompare.c:440
Datum btoidskipsupport(PG_FUNCTION_ARGS)
Definition: nbtcompare.c:509
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:477
static int btint2fastcmp(Datum x, Datum y, SortSupport ssup)
Definition: nbtcompare.c:137
Datum btint84cmp(PG_FUNCTION_ARGS)
Definition: nbtcompare.c:370
Datum btoidsortsupport(PG_FUNCTION_ARGS)
Definition: nbtcompare.c:468
Datum btcharcmp(PG_FUNCTION_ARGS)
Definition: nbtcompare.c:546
#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:454
static int btint8fastcmp(Datum x, Datum y, SortSupport ssup)
Definition: nbtcompare.c:283
Datum btint8sortsupport(PG_FUNCTION_ARGS)
Definition: nbtcompare.c:298
Datum btint82cmp(PG_FUNCTION_ARGS)
Definition: nbtcompare.c:426
static Datum int8_increment(Relation rel, Datum existing, bool *overflow)
Definition: nbtcompare.c:327
Datum btint8skipsupport(PG_FUNCTION_ARGS)
Definition: nbtcompare.c:343
Datum btint48cmp(PG_FUNCTION_ARGS)
Definition: nbtcompare.c:356
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:572
Datum btcharskipsupport(PG_FUNCTION_ARGS)
Definition: nbtcompare.c:588
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:398
Datum btint28cmp(PG_FUNCTION_ARGS)
Definition: nbtcompare.c:412
Datum btint2sortsupport(PG_FUNCTION_ARGS)
Definition: nbtcompare.c:146
static bool DatumGetBool(Datum X)
Definition: postgres.h:95
static int64 DatumGetInt64(Datum X)
Definition: postgres.h:390
uintptr_t Datum
Definition: postgres.h:69
static Oid DatumGetObjectId(Datum X)
Definition: postgres.h:247
static Datum Int16GetDatum(int16 X)
Definition: postgres.h:177
static Datum BoolGetDatum(bool X)
Definition: postgres.h:107
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:257
static Datum UInt8GetDatum(uint8 X)
Definition: postgres.h:157
static Datum Int32GetDatum(int32 X)
Definition: postgres.h:217
static int16 DatumGetInt16(Datum X)
Definition: postgres.h:167
static int32 DatumGetInt32(Datum X)
Definition: postgres.h:207
static Datum CharGetDatum(char X)
Definition: postgres.h:127
#define InvalidOid
Definition: postgres_ext.h:35
unsigned int Oid
Definition: postgres_ext.h:30
#define OID_MAX
Definition: postgres_ext.h:38
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:697
int ssup_datum_int32_cmp(Datum x, Datum y, SortSupport ssup)
Definition: tuplesort.c:3166