Branch data Line data Source code
1 : : /*-------------------------------------------------------------------------
2 : : *
3 : : * nbtcompare.c
4 : : * Comparison functions for btree access method.
5 : : *
6 : : * Portions Copyright (c) 1996-2026, 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 : :
73 : : Datum
74 : 1406979 : btboolcmp(PG_FUNCTION_ARGS)
75 : : {
76 : 1406979 : bool a = PG_GETARG_BOOL(0);
77 : 1406979 : bool b = PG_GETARG_BOOL(1);
78 : :
79 : 2813958 : PG_RETURN_INT32((int32) a - (int32) b);
80 : 1406979 : }
81 : :
82 : : static Datum
83 : 0 : bool_decrement(Relation rel, Datum existing, bool *underflow)
84 : : {
85 : 0 : bool bexisting = DatumGetBool(existing);
86 : :
87 [ # # ]: 0 : if (bexisting == false)
88 : : {
89 : : /* return value is undefined */
90 : 0 : *underflow = true;
91 : 0 : return (Datum) 0;
92 : : }
93 : :
94 : 0 : *underflow = false;
95 : 0 : return BoolGetDatum(bexisting - 1);
96 : 0 : }
97 : :
98 : : static Datum
99 : 0 : bool_increment(Relation rel, Datum existing, bool *overflow)
100 : : {
101 : 0 : bool bexisting = DatumGetBool(existing);
102 : :
103 [ # # ]: 0 : if (bexisting == true)
104 : : {
105 : : /* return value is undefined */
106 : 0 : *overflow = true;
107 : 0 : return (Datum) 0;
108 : : }
109 : :
110 : 0 : *overflow = false;
111 : 0 : return BoolGetDatum(bexisting + 1);
112 : 0 : }
113 : :
114 : : Datum
115 : 0 : btboolskipsupport(PG_FUNCTION_ARGS)
116 : : {
117 : 0 : SkipSupport sksup = (SkipSupport) PG_GETARG_POINTER(0);
118 : :
119 : 0 : sksup->decrement = bool_decrement;
120 : 0 : sksup->increment = bool_increment;
121 : 0 : sksup->low_elem = BoolGetDatum(false);
122 : 0 : sksup->high_elem = BoolGetDatum(true);
123 : :
124 : 0 : PG_RETURN_VOID();
125 : 0 : }
126 : :
127 : : Datum
128 : 608573 : btint2cmp(PG_FUNCTION_ARGS)
129 : : {
130 : 608573 : int16 a = PG_GETARG_INT16(0);
131 : 608573 : int16 b = PG_GETARG_INT16(1);
132 : :
133 : 1217146 : PG_RETURN_INT32((int32) a - (int32) b);
134 : 608573 : }
135 : :
136 : : static int
137 : 245017 : btint2fastcmp(Datum x, Datum y, SortSupport ssup)
138 : : {
139 : 245017 : int16 a = DatumGetInt16(x);
140 : 245017 : int16 b = DatumGetInt16(y);
141 : :
142 : 490034 : return (int) a - (int) b;
143 : 245017 : }
144 : :
145 : : Datum
146 : 382 : btint2sortsupport(PG_FUNCTION_ARGS)
147 : : {
148 : 382 : SortSupport ssup = (SortSupport) PG_GETARG_POINTER(0);
149 : :
150 : 382 : ssup->comparator = btint2fastcmp;
151 : 382 : PG_RETURN_VOID();
152 : 382 : }
153 : :
154 : : static Datum
155 : 0 : int2_decrement(Relation rel, Datum existing, bool *underflow)
156 : : {
157 : 0 : int16 iexisting = DatumGetInt16(existing);
158 : :
159 [ # # ]: 0 : if (iexisting == PG_INT16_MIN)
160 : : {
161 : : /* return value is undefined */
162 : 0 : *underflow = true;
163 : 0 : return (Datum) 0;
164 : : }
165 : :
166 : 0 : *underflow = false;
167 : 0 : return Int16GetDatum(iexisting - 1);
168 : 0 : }
169 : :
170 : : static Datum
171 : 0 : int2_increment(Relation rel, Datum existing, bool *overflow)
172 : : {
173 : 0 : int16 iexisting = DatumGetInt16(existing);
174 : :
175 [ # # ]: 0 : if (iexisting == PG_INT16_MAX)
176 : : {
177 : : /* return value is undefined */
178 : 0 : *overflow = true;
179 : 0 : return (Datum) 0;
180 : : }
181 : :
182 : 0 : *overflow = false;
183 : 0 : return Int16GetDatum(iexisting + 1);
184 : 0 : }
185 : :
186 : : Datum
187 : 27 : btint2skipsupport(PG_FUNCTION_ARGS)
188 : : {
189 : 27 : SkipSupport sksup = (SkipSupport) PG_GETARG_POINTER(0);
190 : :
191 : 27 : sksup->decrement = int2_decrement;
192 : 27 : sksup->increment = int2_increment;
193 : 27 : sksup->low_elem = Int16GetDatum(PG_INT16_MIN);
194 : 27 : sksup->high_elem = Int16GetDatum(PG_INT16_MAX);
195 : :
196 : 27 : PG_RETURN_VOID();
197 : 27 : }
198 : :
199 : : Datum
200 : 16922858 : btint4cmp(PG_FUNCTION_ARGS)
201 : : {
202 : 16922858 : int32 a = PG_GETARG_INT32(0);
203 : 16922858 : int32 b = PG_GETARG_INT32(1);
204 : :
205 [ + + ]: 16922858 : if (a > b)
206 : 5281175 : PG_RETURN_INT32(A_GREATER_THAN_B);
207 [ + + ]: 11641683 : else if (a == b)
208 : 3062015 : PG_RETURN_INT32(0);
209 : : else
210 : 8579668 : PG_RETURN_INT32(A_LESS_THAN_B);
211 : 16922858 : }
212 : :
213 : : Datum
214 : 22771 : btint4sortsupport(PG_FUNCTION_ARGS)
215 : : {
216 : 22771 : SortSupport ssup = (SortSupport) PG_GETARG_POINTER(0);
217 : :
218 : 22771 : ssup->comparator = ssup_datum_int32_cmp;
219 : 22771 : PG_RETURN_VOID();
220 : 22771 : }
221 : :
222 : : static Datum
223 : 661 : int4_decrement(Relation rel, Datum existing, bool *underflow)
224 : : {
225 : 661 : int32 iexisting = DatumGetInt32(existing);
226 : :
227 [ - + ]: 661 : if (iexisting == PG_INT32_MIN)
228 : : {
229 : : /* return value is undefined */
230 : 0 : *underflow = true;
231 : 0 : return (Datum) 0;
232 : : }
233 : :
234 : 661 : *underflow = false;
235 : 661 : return Int32GetDatum(iexisting - 1);
236 : 661 : }
237 : :
238 : : static Datum
239 : 637 : int4_increment(Relation rel, Datum existing, bool *overflow)
240 : : {
241 : 637 : int32 iexisting = DatumGetInt32(existing);
242 : :
243 [ + + ]: 637 : if (iexisting == PG_INT32_MAX)
244 : : {
245 : : /* return value is undefined */
246 : 5 : *overflow = true;
247 : 5 : return (Datum) 0;
248 : : }
249 : :
250 : 632 : *overflow = false;
251 : 632 : return Int32GetDatum(iexisting + 1);
252 : 637 : }
253 : :
254 : : Datum
255 : 41 : btint4skipsupport(PG_FUNCTION_ARGS)
256 : : {
257 : 41 : SkipSupport sksup = (SkipSupport) PG_GETARG_POINTER(0);
258 : :
259 : 41 : sksup->decrement = int4_decrement;
260 : 41 : sksup->increment = int4_increment;
261 : 41 : sksup->low_elem = Int32GetDatum(PG_INT32_MIN);
262 : 41 : sksup->high_elem = Int32GetDatum(PG_INT32_MAX);
263 : :
264 : 41 : PG_RETURN_VOID();
265 : 41 : }
266 : :
267 : : Datum
268 : 43920 : btint8cmp(PG_FUNCTION_ARGS)
269 : : {
270 : 43920 : int64 a = PG_GETARG_INT64(0);
271 : 43920 : int64 b = PG_GETARG_INT64(1);
272 : :
273 [ + + ]: 43920 : if (a > b)
274 : 17295 : PG_RETURN_INT32(A_GREATER_THAN_B);
275 [ + + ]: 26625 : else if (a == b)
276 : 2984 : PG_RETURN_INT32(0);
277 : : else
278 : 23641 : PG_RETURN_INT32(A_LESS_THAN_B);
279 : 43920 : }
280 : :
281 : : Datum
282 : 447 : btint8sortsupport(PG_FUNCTION_ARGS)
283 : : {
284 : 447 : SortSupport ssup = (SortSupport) PG_GETARG_POINTER(0);
285 : :
286 : 447 : ssup->comparator = ssup_datum_signed_cmp;
287 : 447 : PG_RETURN_VOID();
288 : 447 : }
289 : :
290 : : static Datum
291 : 0 : int8_decrement(Relation rel, Datum existing, bool *underflow)
292 : : {
293 : 0 : int64 iexisting = DatumGetInt64(existing);
294 : :
295 [ # # ]: 0 : if (iexisting == PG_INT64_MIN)
296 : : {
297 : : /* return value is undefined */
298 : 0 : *underflow = true;
299 : 0 : return (Datum) 0;
300 : : }
301 : :
302 : 0 : *underflow = false;
303 : 0 : return Int64GetDatum(iexisting - 1);
304 : 0 : }
305 : :
306 : : static Datum
307 : 0 : int8_increment(Relation rel, Datum existing, bool *overflow)
308 : : {
309 : 0 : int64 iexisting = DatumGetInt64(existing);
310 : :
311 [ # # ]: 0 : if (iexisting == PG_INT64_MAX)
312 : : {
313 : : /* return value is undefined */
314 : 0 : *overflow = true;
315 : 0 : return (Datum) 0;
316 : : }
317 : :
318 : 0 : *overflow = false;
319 : 0 : return Int64GetDatum(iexisting + 1);
320 : 0 : }
321 : :
322 : : Datum
323 : 0 : btint8skipsupport(PG_FUNCTION_ARGS)
324 : : {
325 : 0 : SkipSupport sksup = (SkipSupport) PG_GETARG_POINTER(0);
326 : :
327 : 0 : sksup->decrement = int8_decrement;
328 : 0 : sksup->increment = int8_increment;
329 : 0 : sksup->low_elem = Int64GetDatum(PG_INT64_MIN);
330 : 0 : sksup->high_elem = Int64GetDatum(PG_INT64_MAX);
331 : :
332 : 0 : PG_RETURN_VOID();
333 : 0 : }
334 : :
335 : : Datum
336 : 242 : btint48cmp(PG_FUNCTION_ARGS)
337 : : {
338 : 242 : int32 a = PG_GETARG_INT32(0);
339 : 242 : int64 b = PG_GETARG_INT64(1);
340 : :
341 [ + + ]: 242 : if (a > b)
342 : 83 : PG_RETURN_INT32(A_GREATER_THAN_B);
343 [ + + ]: 159 : else if (a == b)
344 : 11 : PG_RETURN_INT32(0);
345 : : else
346 : 148 : PG_RETURN_INT32(A_LESS_THAN_B);
347 : 242 : }
348 : :
349 : : Datum
350 : 31 : btint84cmp(PG_FUNCTION_ARGS)
351 : : {
352 : 31 : int64 a = PG_GETARG_INT64(0);
353 : 31 : int32 b = PG_GETARG_INT32(1);
354 : :
355 [ + + ]: 31 : if (a > b)
356 : 11 : PG_RETURN_INT32(A_GREATER_THAN_B);
357 [ + + ]: 20 : else if (a == b)
358 : 8 : PG_RETURN_INT32(0);
359 : : else
360 : 12 : PG_RETURN_INT32(A_LESS_THAN_B);
361 : 31 : }
362 : :
363 : : Datum
364 : 4957 : btint24cmp(PG_FUNCTION_ARGS)
365 : : {
366 : 4957 : int16 a = PG_GETARG_INT16(0);
367 : 4957 : int32 b = PG_GETARG_INT32(1);
368 : :
369 [ + + ]: 4957 : if (a > b)
370 : 2476 : PG_RETURN_INT32(A_GREATER_THAN_B);
371 [ + + ]: 2481 : else if (a == b)
372 : 176 : PG_RETURN_INT32(0);
373 : : else
374 : 2305 : PG_RETURN_INT32(A_LESS_THAN_B);
375 : 4957 : }
376 : :
377 : : Datum
378 : 236 : btint42cmp(PG_FUNCTION_ARGS)
379 : : {
380 : 236 : int32 a = PG_GETARG_INT32(0);
381 : 236 : int16 b = PG_GETARG_INT16(1);
382 : :
383 [ + + ]: 236 : if (a > b)
384 : 11 : PG_RETURN_INT32(A_GREATER_THAN_B);
385 [ + + ]: 225 : else if (a == b)
386 : 45 : PG_RETURN_INT32(0);
387 : : else
388 : 180 : PG_RETURN_INT32(A_LESS_THAN_B);
389 : 236 : }
390 : :
391 : : Datum
392 : 6 : btint28cmp(PG_FUNCTION_ARGS)
393 : : {
394 : 6 : int16 a = PG_GETARG_INT16(0);
395 : 6 : int64 b = PG_GETARG_INT64(1);
396 : :
397 [ - + ]: 6 : if (a > b)
398 : 0 : PG_RETURN_INT32(A_GREATER_THAN_B);
399 [ - + ]: 6 : else if (a == b)
400 : 0 : PG_RETURN_INT32(0);
401 : : else
402 : 6 : PG_RETURN_INT32(A_LESS_THAN_B);
403 : 6 : }
404 : :
405 : : Datum
406 : 0 : btint82cmp(PG_FUNCTION_ARGS)
407 : : {
408 : 0 : int64 a = PG_GETARG_INT64(0);
409 : 0 : int16 b = PG_GETARG_INT16(1);
410 : :
411 [ # # ]: 0 : if (a > b)
412 : 0 : PG_RETURN_INT32(A_GREATER_THAN_B);
413 [ # # ]: 0 : else if (a == b)
414 : 0 : PG_RETURN_INT32(0);
415 : : else
416 : 0 : PG_RETURN_INT32(A_LESS_THAN_B);
417 : 0 : }
418 : :
419 : : Datum
420 : 15236104 : btoidcmp(PG_FUNCTION_ARGS)
421 : : {
422 : 15236104 : Oid a = PG_GETARG_OID(0);
423 : 15236104 : Oid b = PG_GETARG_OID(1);
424 : :
425 [ + + ]: 15236104 : if (a > b)
426 : 3252147 : PG_RETURN_INT32(A_GREATER_THAN_B);
427 [ + + ]: 11983957 : else if (a == b)
428 : 3867694 : PG_RETURN_INT32(0);
429 : : else
430 : 8116263 : PG_RETURN_INT32(A_LESS_THAN_B);
431 : 15236104 : }
432 : :
433 : : static int
434 : 1246771 : btoidfastcmp(Datum x, Datum y, SortSupport ssup)
435 : : {
436 : 1246771 : Oid a = DatumGetObjectId(x);
437 : 1246771 : Oid b = DatumGetObjectId(y);
438 : :
439 [ + + ]: 1246771 : if (a > b)
440 : 295273 : return A_GREATER_THAN_B;
441 [ + + ]: 951498 : else if (a == b)
442 : 603623 : return 0;
443 : : else
444 : 347875 : return A_LESS_THAN_B;
445 : 1246771 : }
446 : :
447 : : Datum
448 : 4235 : btoidsortsupport(PG_FUNCTION_ARGS)
449 : : {
450 : 4235 : SortSupport ssup = (SortSupport) PG_GETARG_POINTER(0);
451 : :
452 : 4235 : ssup->comparator = btoidfastcmp;
453 : 4235 : PG_RETURN_VOID();
454 : 4235 : }
455 : :
456 : : static Datum
457 : 0 : oid_decrement(Relation rel, Datum existing, bool *underflow)
458 : : {
459 : 0 : Oid oexisting = DatumGetObjectId(existing);
460 : :
461 [ # # ]: 0 : if (oexisting == InvalidOid)
462 : : {
463 : : /* return value is undefined */
464 : 0 : *underflow = true;
465 : 0 : return (Datum) 0;
466 : : }
467 : :
468 : 0 : *underflow = false;
469 : 0 : return ObjectIdGetDatum(oexisting - 1);
470 : 0 : }
471 : :
472 : : static Datum
473 : 68 : oid_increment(Relation rel, Datum existing, bool *overflow)
474 : : {
475 : 68 : Oid oexisting = DatumGetObjectId(existing);
476 : :
477 [ + - ]: 68 : if (oexisting == OID_MAX)
478 : : {
479 : : /* return value is undefined */
480 : 0 : *overflow = true;
481 : 0 : return (Datum) 0;
482 : : }
483 : :
484 : 68 : *overflow = false;
485 : 68 : return ObjectIdGetDatum(oexisting + 1);
486 : 68 : }
487 : :
488 : : Datum
489 : 225 : btoidskipsupport(PG_FUNCTION_ARGS)
490 : : {
491 : 225 : SkipSupport sksup = (SkipSupport) PG_GETARG_POINTER(0);
492 : :
493 : 225 : sksup->decrement = oid_decrement;
494 : 225 : sksup->increment = oid_increment;
495 : 225 : sksup->low_elem = ObjectIdGetDatum(InvalidOid);
496 : 225 : sksup->high_elem = ObjectIdGetDatum(OID_MAX);
497 : :
498 : 225 : PG_RETURN_VOID();
499 : 225 : }
500 : :
501 : : Datum
502 : 3 : btoid8cmp(PG_FUNCTION_ARGS)
503 : : {
504 : 3 : Oid8 a = PG_GETARG_OID8(0);
505 : 3 : Oid8 b = PG_GETARG_OID8(1);
506 : :
507 [ + + ]: 3 : if (a > b)
508 : 1 : PG_RETURN_INT32(A_GREATER_THAN_B);
509 [ + + ]: 2 : else if (a == b)
510 : 1 : PG_RETURN_INT32(0);
511 : : else
512 : 1 : PG_RETURN_INT32(A_LESS_THAN_B);
513 : 3 : }
514 : :
515 : : static int
516 : 729 : btoid8fastcmp(Datum x, Datum y, SortSupport ssup)
517 : : {
518 : 729 : Oid8 a = DatumGetObjectId8(x);
519 : 729 : Oid8 b = DatumGetObjectId8(y);
520 : :
521 [ + + ]: 729 : if (a > b)
522 : 439 : return A_GREATER_THAN_B;
523 [ - + ]: 290 : else if (a == b)
524 : 0 : return 0;
525 : : else
526 : 290 : return A_LESS_THAN_B;
527 : 729 : }
528 : :
529 : : Datum
530 : 2 : btoid8sortsupport(PG_FUNCTION_ARGS)
531 : : {
532 : 2 : SortSupport ssup = (SortSupport) PG_GETARG_POINTER(0);
533 : :
534 : 2 : ssup->comparator = btoid8fastcmp;
535 : 2 : PG_RETURN_VOID();
536 : 2 : }
537 : :
538 : : static Datum
539 : 0 : oid8_decrement(Relation rel, Datum existing, bool *underflow)
540 : : {
541 : 0 : Oid8 oexisting = DatumGetObjectId8(existing);
542 : :
543 [ # # ]: 0 : if (oexisting == InvalidOid8)
544 : : {
545 : : /* return value is undefined */
546 : 0 : *underflow = true;
547 : 0 : return (Datum) 0;
548 : : }
549 : :
550 : 0 : *underflow = false;
551 : 0 : return ObjectId8GetDatum(oexisting - 1);
552 : 0 : }
553 : :
554 : : static Datum
555 : 0 : oid8_increment(Relation rel, Datum existing, bool *overflow)
556 : : {
557 : 0 : Oid8 oexisting = DatumGetObjectId8(existing);
558 : :
559 [ # # ]: 0 : if (oexisting == OID8_MAX)
560 : : {
561 : : /* return value is undefined */
562 : 0 : *overflow = true;
563 : 0 : return (Datum) 0;
564 : : }
565 : :
566 : 0 : *overflow = false;
567 : 0 : return ObjectId8GetDatum(oexisting + 1);
568 : 0 : }
569 : :
570 : : Datum
571 : 0 : btoid8skipsupport(PG_FUNCTION_ARGS)
572 : : {
573 : 0 : SkipSupport sksup = (SkipSupport) PG_GETARG_POINTER(0);
574 : :
575 : 0 : sksup->decrement = oid8_decrement;
576 : 0 : sksup->increment = oid8_increment;
577 : 0 : sksup->low_elem = ObjectId8GetDatum(InvalidOid8);
578 : 0 : sksup->high_elem = ObjectId8GetDatum(OID8_MAX);
579 : :
580 : 0 : PG_RETURN_VOID();
581 : 0 : }
582 : :
583 : : Datum
584 : 57078 : btoidvectorcmp(PG_FUNCTION_ARGS)
585 : : {
586 : 57078 : oidvector *a = (oidvector *) PG_GETARG_POINTER(0);
587 : 57078 : oidvector *b = (oidvector *) PG_GETARG_POINTER(1);
588 : 57078 : int i;
589 : :
590 : : /* We arbitrarily choose to sort first by vector length */
591 [ + + ]: 57078 : if (a->dim1 != b->dim1)
592 : 12687 : PG_RETURN_INT32(a->dim1 - b->dim1);
593 : :
594 [ + + ]: 82075 : for (i = 0; i < a->dim1; i++)
595 : : {
596 [ + + ]: 61256 : if (a->values[i] != b->values[i])
597 : : {
598 [ + + ]: 23572 : if (a->values[i] > b->values[i])
599 : 11484 : PG_RETURN_INT32(A_GREATER_THAN_B);
600 : : else
601 : 12088 : PG_RETURN_INT32(A_LESS_THAN_B);
602 : : }
603 : 37684 : }
604 : 20819 : PG_RETURN_INT32(0);
605 : 57078 : }
606 : :
607 : : Datum
608 : 341347 : btcharcmp(PG_FUNCTION_ARGS)
609 : : {
610 : 341347 : char a = PG_GETARG_CHAR(0);
611 : 341347 : char b = PG_GETARG_CHAR(1);
612 : :
613 : : /* Be careful to compare chars as unsigned */
614 : 682694 : PG_RETURN_INT32((int32) ((uint8) a) - (int32) ((uint8) b));
615 : 341347 : }
616 : :
617 : : static Datum
618 : 0 : char_decrement(Relation rel, Datum existing, bool *underflow)
619 : : {
620 : 0 : uint8 cexisting = DatumGetUInt8(existing);
621 : :
622 [ # # ]: 0 : if (cexisting == 0)
623 : : {
624 : : /* return value is undefined */
625 : 0 : *underflow = true;
626 : 0 : return (Datum) 0;
627 : : }
628 : :
629 : 0 : *underflow = false;
630 : 0 : return CharGetDatum((uint8) cexisting - 1);
631 : 0 : }
632 : :
633 : : static Datum
634 : 0 : char_increment(Relation rel, Datum existing, bool *overflow)
635 : : {
636 : 0 : uint8 cexisting = DatumGetUInt8(existing);
637 : :
638 [ # # ]: 0 : if (cexisting == UCHAR_MAX)
639 : : {
640 : : /* return value is undefined */
641 : 0 : *overflow = true;
642 : 0 : return (Datum) 0;
643 : : }
644 : :
645 : 0 : *overflow = false;
646 : 0 : return CharGetDatum((uint8) cexisting + 1);
647 : 0 : }
648 : :
649 : : Datum
650 : 0 : btcharskipsupport(PG_FUNCTION_ARGS)
651 : : {
652 : 0 : SkipSupport sksup = (SkipSupport) PG_GETARG_POINTER(0);
653 : :
654 : 0 : sksup->decrement = char_decrement;
655 : 0 : sksup->increment = char_increment;
656 : :
657 : : /* btcharcmp compares chars as unsigned */
658 : 0 : sksup->low_elem = UInt8GetDatum(0);
659 : 0 : sksup->high_elem = UInt8GetDatum(UCHAR_MAX);
660 : :
661 : 0 : PG_RETURN_VOID();
662 : 0 : }
|