Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * int.c
4 : * Functions for the built-in integer types (except int8).
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/utils/adt/int.c
12 : *
13 : *-------------------------------------------------------------------------
14 : */
15 : /*
16 : * OLD COMMENTS
17 : * I/O routines:
18 : * int2in, int2out, int2recv, int2send
19 : * int4in, int4out, int4recv, int4send
20 : * int2vectorin, int2vectorout, int2vectorrecv, int2vectorsend
21 : * Boolean operators:
22 : * inteq, intne, intlt, intle, intgt, intge
23 : * Arithmetic operators:
24 : * intpl, intmi, int4mul, intdiv
25 : *
26 : * Arithmetic operators:
27 : * intmod
28 : */
29 : #include "postgres.h"
30 :
31 : #include <ctype.h>
32 : #include <limits.h>
33 : #include <math.h>
34 :
35 : #include "catalog/pg_type.h"
36 : #include "common/int.h"
37 : #include "funcapi.h"
38 : #include "libpq/pqformat.h"
39 : #include "nodes/nodeFuncs.h"
40 : #include "nodes/supportnodes.h"
41 : #include "optimizer/optimizer.h"
42 : #include "utils/array.h"
43 : #include "utils/builtins.h"
44 :
45 : #define Int2VectorSize(n) (offsetof(int2vector, values) + (n) * sizeof(int16))
46 :
47 : typedef struct
48 : {
49 : int32 current;
50 : int32 finish;
51 : int32 step;
52 : } generate_series_fctx;
53 :
54 :
55 : /*****************************************************************************
56 : * USER I/O ROUTINES *
57 : *****************************************************************************/
58 :
59 : /*
60 : * int2in - converts "num" to short
61 : */
62 : Datum
63 541597 : int2in(PG_FUNCTION_ARGS)
64 : {
65 541597 : char *num = PG_GETARG_CSTRING(0);
66 :
67 541597 : PG_RETURN_INT16(pg_strtoint16_safe(num, fcinfo->context));
68 : }
69 :
70 : /*
71 : * int2out - converts short to "num"
72 : */
73 : Datum
74 382193 : int2out(PG_FUNCTION_ARGS)
75 : {
76 382193 : int16 arg1 = PG_GETARG_INT16(0);
77 382193 : char *result = (char *) palloc(7); /* sign, 5 digits, '\0' */
78 :
79 382193 : pg_itoa(arg1, result);
80 382193 : PG_RETURN_CSTRING(result);
81 : }
82 :
83 : /*
84 : * int2recv - converts external binary format to int2
85 : */
86 : Datum
87 0 : int2recv(PG_FUNCTION_ARGS)
88 : {
89 0 : StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
90 :
91 0 : PG_RETURN_INT16((int16) pq_getmsgint(buf, sizeof(int16)));
92 : }
93 :
94 : /*
95 : * int2send - converts int2 to binary format
96 : */
97 : Datum
98 13 : int2send(PG_FUNCTION_ARGS)
99 : {
100 13 : int16 arg1 = PG_GETARG_INT16(0);
101 : StringInfoData buf;
102 :
103 13 : pq_begintypsend(&buf);
104 13 : pq_sendint16(&buf, arg1);
105 13 : PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
106 : }
107 :
108 : /*
109 : * construct int2vector given a raw array of int2s
110 : *
111 : * If int2s is NULL then caller must fill values[] afterward
112 : */
113 : int2vector *
114 79004 : buildint2vector(const int16 *int2s, int n)
115 : {
116 : int2vector *result;
117 :
118 79004 : result = (int2vector *) palloc0(Int2VectorSize(n));
119 :
120 79004 : if (n > 0 && int2s)
121 35988 : memcpy(result->values, int2s, n * sizeof(int16));
122 :
123 : /*
124 : * Attach standard array header. For historical reasons, we set the index
125 : * lower bound to 0 not 1.
126 : */
127 79004 : SET_VARSIZE(result, Int2VectorSize(n));
128 79004 : result->ndim = 1;
129 79004 : result->dataoffset = 0; /* never any nulls */
130 79004 : result->elemtype = INT2OID;
131 79004 : result->dim1 = n;
132 79004 : result->lbound1 = 0;
133 :
134 79004 : return result;
135 : }
136 :
137 : /*
138 : * validate that an array object meets the restrictions of int2vector
139 : *
140 : * We need this because there are pathways by which a general int2[] array can
141 : * be cast to int2vector, allowing the type's restrictions to be violated.
142 : * All code that receives an int2vector as a SQL parameter should check this.
143 : */
144 : static void
145 7751 : check_valid_int2vector(const int2vector *int2Array)
146 : {
147 : /*
148 : * We insist on ndim == 1 and dataoffset == 0 (that is, no nulls) because
149 : * otherwise the array's layout will not be what calling code expects. We
150 : * needn't be picky about the index lower bound though. Checking elemtype
151 : * is just paranoia.
152 : */
153 7751 : if (int2Array->ndim != 1 ||
154 7747 : int2Array->dataoffset != 0 ||
155 7747 : int2Array->elemtype != INT2OID)
156 4 : ereport(ERROR,
157 : (errcode(ERRCODE_DATATYPE_MISMATCH),
158 : errmsg("array is not a valid int2vector")));
159 7747 : }
160 :
161 : /*
162 : * int2vectorin - converts "num num ..." to internal form
163 : */
164 : Datum
165 401 : int2vectorin(PG_FUNCTION_ARGS)
166 : {
167 401 : char *intString = PG_GETARG_CSTRING(0);
168 401 : Node *escontext = fcinfo->context;
169 : int2vector *result;
170 : int nalloc;
171 : int n;
172 :
173 401 : nalloc = 32; /* arbitrary initial size guess */
174 401 : result = (int2vector *) palloc0(Int2VectorSize(nalloc));
175 :
176 401 : for (n = 0;; n++)
177 741 : {
178 : long l;
179 : char *endp;
180 :
181 1502 : while (*intString && isspace((unsigned char) *intString))
182 360 : intString++;
183 1142 : if (*intString == '\0')
184 393 : break;
185 :
186 749 : if (n >= nalloc)
187 : {
188 0 : nalloc *= 2;
189 0 : result = (int2vector *) repalloc(result, Int2VectorSize(nalloc));
190 : }
191 :
192 749 : errno = 0;
193 749 : l = strtol(intString, &endp, 10);
194 :
195 749 : if (intString == endp)
196 8 : ereturn(escontext, (Datum) 0,
197 : (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
198 : errmsg("invalid input syntax for type %s: \"%s\"",
199 : "smallint", intString)));
200 :
201 745 : if (errno == ERANGE || l < SHRT_MIN || l > SHRT_MAX)
202 4 : ereturn(escontext, (Datum) 0,
203 : (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
204 : errmsg("value \"%s\" is out of range for type %s", intString,
205 : "smallint")));
206 :
207 741 : if (*endp && *endp != ' ')
208 0 : ereturn(escontext, (Datum) 0,
209 : (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
210 : errmsg("invalid input syntax for type %s: \"%s\"",
211 : "smallint", intString)));
212 :
213 741 : result->values[n] = l;
214 741 : intString = endp;
215 : }
216 :
217 393 : SET_VARSIZE(result, Int2VectorSize(n));
218 393 : result->ndim = 1;
219 393 : result->dataoffset = 0; /* never any nulls */
220 393 : result->elemtype = INT2OID;
221 393 : result->dim1 = n;
222 393 : result->lbound1 = 0;
223 :
224 393 : PG_RETURN_POINTER(result);
225 : }
226 :
227 : /*
228 : * int2vectorout - converts internal form to "num num ..."
229 : */
230 : Datum
231 7751 : int2vectorout(PG_FUNCTION_ARGS)
232 : {
233 7751 : int2vector *int2Array = (int2vector *) PG_GETARG_POINTER(0);
234 : int num,
235 : nnums;
236 : char *rp;
237 : char *result;
238 :
239 : /* validate input before fetching dim1 */
240 7751 : check_valid_int2vector(int2Array);
241 7747 : nnums = int2Array->dim1;
242 :
243 : /* assumes sign, 5 digits, ' ' */
244 7747 : rp = result = (char *) palloc(nnums * 7 + 1);
245 19863 : for (num = 0; num < nnums; num++)
246 : {
247 12116 : if (num != 0)
248 4992 : *rp++ = ' ';
249 12116 : rp += pg_itoa(int2Array->values[num], rp);
250 : }
251 7747 : *rp = '\0';
252 7747 : PG_RETURN_CSTRING(result);
253 : }
254 :
255 : /*
256 : * int2vectorrecv - converts external binary format to int2vector
257 : */
258 : Datum
259 0 : int2vectorrecv(PG_FUNCTION_ARGS)
260 : {
261 0 : LOCAL_FCINFO(locfcinfo, 3);
262 0 : StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
263 : int2vector *result;
264 :
265 : /*
266 : * Normally one would call array_recv() using DirectFunctionCall3, but
267 : * that does not work since array_recv wants to cache some data using
268 : * fcinfo->flinfo->fn_extra. So we need to pass it our own flinfo
269 : * parameter.
270 : */
271 0 : InitFunctionCallInfoData(*locfcinfo, fcinfo->flinfo, 3,
272 : InvalidOid, NULL, NULL);
273 :
274 0 : locfcinfo->args[0].value = PointerGetDatum(buf);
275 0 : locfcinfo->args[0].isnull = false;
276 0 : locfcinfo->args[1].value = ObjectIdGetDatum(INT2OID);
277 0 : locfcinfo->args[1].isnull = false;
278 0 : locfcinfo->args[2].value = Int32GetDatum(-1);
279 0 : locfcinfo->args[2].isnull = false;
280 :
281 0 : result = (int2vector *) DatumGetPointer(array_recv(locfcinfo));
282 :
283 : Assert(!locfcinfo->isnull);
284 :
285 : /* sanity checks: int2vector must be 1-D, 0-based, no nulls */
286 0 : if (ARR_NDIM(result) != 1 ||
287 0 : ARR_HASNULL(result) ||
288 0 : ARR_ELEMTYPE(result) != INT2OID ||
289 0 : ARR_LBOUND(result)[0] != 0)
290 0 : ereport(ERROR,
291 : (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
292 : errmsg("invalid int2vector data")));
293 :
294 0 : PG_RETURN_POINTER(result);
295 : }
296 :
297 : /*
298 : * int2vectorsend - converts int2vector to binary format
299 : */
300 : Datum
301 0 : int2vectorsend(PG_FUNCTION_ARGS)
302 : {
303 : /* We don't do check_valid_int2vector, since array_send won't care */
304 0 : return array_send(fcinfo);
305 : }
306 :
307 :
308 : /*****************************************************************************
309 : * PUBLIC ROUTINES *
310 : *****************************************************************************/
311 :
312 : /*
313 : * int4in - converts "num" to int4
314 : */
315 : Datum
316 2621011 : int4in(PG_FUNCTION_ARGS)
317 : {
318 2621011 : char *num = PG_GETARG_CSTRING(0);
319 :
320 2621011 : PG_RETURN_INT32(pg_strtoint32_safe(num, fcinfo->context));
321 : }
322 :
323 : /*
324 : * int4out - converts int4 to "num"
325 : */
326 : Datum
327 10148814 : int4out(PG_FUNCTION_ARGS)
328 : {
329 10148814 : int32 arg1 = PG_GETARG_INT32(0);
330 10148814 : char *result = (char *) palloc(12); /* sign, 10 digits, '\0' */
331 :
332 10148814 : pg_ltoa(arg1, result);
333 10148814 : PG_RETURN_CSTRING(result);
334 : }
335 :
336 : /*
337 : * int4recv - converts external binary format to int4
338 : */
339 : Datum
340 101792 : int4recv(PG_FUNCTION_ARGS)
341 : {
342 101792 : StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
343 :
344 101792 : PG_RETURN_INT32((int32) pq_getmsgint(buf, sizeof(int32)));
345 : }
346 :
347 : /*
348 : * int4send - converts int4 to binary format
349 : */
350 : Datum
351 104714 : int4send(PG_FUNCTION_ARGS)
352 : {
353 104714 : int32 arg1 = PG_GETARG_INT32(0);
354 : StringInfoData buf;
355 :
356 104714 : pq_begintypsend(&buf);
357 104714 : pq_sendint32(&buf, arg1);
358 104714 : PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
359 : }
360 :
361 :
362 : /*
363 : * ===================
364 : * CONVERSION ROUTINES
365 : * ===================
366 : */
367 :
368 : Datum
369 24553 : i2toi4(PG_FUNCTION_ARGS)
370 : {
371 24553 : int16 arg1 = PG_GETARG_INT16(0);
372 :
373 24553 : PG_RETURN_INT32((int32) arg1);
374 : }
375 :
376 : Datum
377 12255 : i4toi2(PG_FUNCTION_ARGS)
378 : {
379 12255 : int32 arg1 = PG_GETARG_INT32(0);
380 :
381 12255 : if (unlikely(arg1 < SHRT_MIN) || unlikely(arg1 > SHRT_MAX))
382 18 : ereturn(fcinfo->context, (Datum) 0,
383 : (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
384 : errmsg("smallint out of range")));
385 :
386 12237 : PG_RETURN_INT16((int16) arg1);
387 : }
388 :
389 : /* Cast int4 -> bool */
390 : Datum
391 23 : int4_bool(PG_FUNCTION_ARGS)
392 : {
393 23 : if (PG_GETARG_INT32(0) == 0)
394 9 : PG_RETURN_BOOL(false);
395 : else
396 14 : PG_RETURN_BOOL(true);
397 : }
398 :
399 : /* Cast bool -> int4 */
400 : Datum
401 1020 : bool_int4(PG_FUNCTION_ARGS)
402 : {
403 1020 : if (PG_GETARG_BOOL(0) == false)
404 520 : PG_RETURN_INT32(0);
405 : else
406 500 : PG_RETURN_INT32(1);
407 : }
408 :
409 : /*
410 : * ============================
411 : * COMPARISON OPERATOR ROUTINES
412 : * ============================
413 : */
414 :
415 : /*
416 : * inteq - returns 1 iff arg1 == arg2
417 : * intne - returns 1 iff arg1 != arg2
418 : * intlt - returns 1 iff arg1 < arg2
419 : * intle - returns 1 iff arg1 <= arg2
420 : * intgt - returns 1 iff arg1 > arg2
421 : * intge - returns 1 iff arg1 >= arg2
422 : */
423 :
424 : Datum
425 38553989 : int4eq(PG_FUNCTION_ARGS)
426 : {
427 38553989 : int32 arg1 = PG_GETARG_INT32(0);
428 38553989 : int32 arg2 = PG_GETARG_INT32(1);
429 :
430 38553989 : PG_RETURN_BOOL(arg1 == arg2);
431 : }
432 :
433 : Datum
434 270730 : int4ne(PG_FUNCTION_ARGS)
435 : {
436 270730 : int32 arg1 = PG_GETARG_INT32(0);
437 270730 : int32 arg2 = PG_GETARG_INT32(1);
438 :
439 270730 : PG_RETURN_BOOL(arg1 != arg2);
440 : }
441 :
442 : Datum
443 6951817 : int4lt(PG_FUNCTION_ARGS)
444 : {
445 6951817 : int32 arg1 = PG_GETARG_INT32(0);
446 6951817 : int32 arg2 = PG_GETARG_INT32(1);
447 :
448 6951817 : PG_RETURN_BOOL(arg1 < arg2);
449 : }
450 :
451 : Datum
452 945246 : int4le(PG_FUNCTION_ARGS)
453 : {
454 945246 : int32 arg1 = PG_GETARG_INT32(0);
455 945246 : int32 arg2 = PG_GETARG_INT32(1);
456 :
457 945246 : PG_RETURN_BOOL(arg1 <= arg2);
458 : }
459 :
460 : Datum
461 2714545 : int4gt(PG_FUNCTION_ARGS)
462 : {
463 2714545 : int32 arg1 = PG_GETARG_INT32(0);
464 2714545 : int32 arg2 = PG_GETARG_INT32(1);
465 :
466 2714545 : PG_RETURN_BOOL(arg1 > arg2);
467 : }
468 :
469 : Datum
470 453379 : int4ge(PG_FUNCTION_ARGS)
471 : {
472 453379 : int32 arg1 = PG_GETARG_INT32(0);
473 453379 : int32 arg2 = PG_GETARG_INT32(1);
474 :
475 453379 : PG_RETURN_BOOL(arg1 >= arg2);
476 : }
477 :
478 : Datum
479 2303536 : int2eq(PG_FUNCTION_ARGS)
480 : {
481 2303536 : int16 arg1 = PG_GETARG_INT16(0);
482 2303536 : int16 arg2 = PG_GETARG_INT16(1);
483 :
484 2303536 : PG_RETURN_BOOL(arg1 == arg2);
485 : }
486 :
487 : Datum
488 22731 : int2ne(PG_FUNCTION_ARGS)
489 : {
490 22731 : int16 arg1 = PG_GETARG_INT16(0);
491 22731 : int16 arg2 = PG_GETARG_INT16(1);
492 :
493 22731 : PG_RETURN_BOOL(arg1 != arg2);
494 : }
495 :
496 : Datum
497 449406 : int2lt(PG_FUNCTION_ARGS)
498 : {
499 449406 : int16 arg1 = PG_GETARG_INT16(0);
500 449406 : int16 arg2 = PG_GETARG_INT16(1);
501 :
502 449406 : PG_RETURN_BOOL(arg1 < arg2);
503 : }
504 :
505 : Datum
506 3031 : int2le(PG_FUNCTION_ARGS)
507 : {
508 3031 : int16 arg1 = PG_GETARG_INT16(0);
509 3031 : int16 arg2 = PG_GETARG_INT16(1);
510 :
511 3031 : PG_RETURN_BOOL(arg1 <= arg2);
512 : }
513 :
514 : Datum
515 4040155 : int2gt(PG_FUNCTION_ARGS)
516 : {
517 4040155 : int16 arg1 = PG_GETARG_INT16(0);
518 4040155 : int16 arg2 = PG_GETARG_INT16(1);
519 :
520 4040155 : PG_RETURN_BOOL(arg1 > arg2);
521 : }
522 :
523 : Datum
524 2476 : int2ge(PG_FUNCTION_ARGS)
525 : {
526 2476 : int16 arg1 = PG_GETARG_INT16(0);
527 2476 : int16 arg2 = PG_GETARG_INT16(1);
528 :
529 2476 : PG_RETURN_BOOL(arg1 >= arg2);
530 : }
531 :
532 : Datum
533 2383167 : int24eq(PG_FUNCTION_ARGS)
534 : {
535 2383167 : int16 arg1 = PG_GETARG_INT16(0);
536 2383167 : int32 arg2 = PG_GETARG_INT32(1);
537 :
538 2383167 : PG_RETURN_BOOL(arg1 == arg2);
539 : }
540 :
541 : Datum
542 50436 : int24ne(PG_FUNCTION_ARGS)
543 : {
544 50436 : int16 arg1 = PG_GETARG_INT16(0);
545 50436 : int32 arg2 = PG_GETARG_INT32(1);
546 :
547 50436 : PG_RETURN_BOOL(arg1 != arg2);
548 : }
549 :
550 : Datum
551 93128 : int24lt(PG_FUNCTION_ARGS)
552 : {
553 93128 : int16 arg1 = PG_GETARG_INT16(0);
554 93128 : int32 arg2 = PG_GETARG_INT32(1);
555 :
556 93128 : PG_RETURN_BOOL(arg1 < arg2);
557 : }
558 :
559 : Datum
560 40650 : int24le(PG_FUNCTION_ARGS)
561 : {
562 40650 : int16 arg1 = PG_GETARG_INT16(0);
563 40650 : int32 arg2 = PG_GETARG_INT32(1);
564 :
565 40650 : PG_RETURN_BOOL(arg1 <= arg2);
566 : }
567 :
568 : Datum
569 439432 : int24gt(PG_FUNCTION_ARGS)
570 : {
571 439432 : int16 arg1 = PG_GETARG_INT16(0);
572 439432 : int32 arg2 = PG_GETARG_INT32(1);
573 :
574 439432 : PG_RETURN_BOOL(arg1 > arg2);
575 : }
576 :
577 : Datum
578 6620 : int24ge(PG_FUNCTION_ARGS)
579 : {
580 6620 : int16 arg1 = PG_GETARG_INT16(0);
581 6620 : int32 arg2 = PG_GETARG_INT32(1);
582 :
583 6620 : PG_RETURN_BOOL(arg1 >= arg2);
584 : }
585 :
586 : Datum
587 145269 : int42eq(PG_FUNCTION_ARGS)
588 : {
589 145269 : int32 arg1 = PG_GETARG_INT32(0);
590 145269 : int16 arg2 = PG_GETARG_INT16(1);
591 :
592 145269 : PG_RETURN_BOOL(arg1 == arg2);
593 : }
594 :
595 : Datum
596 20 : int42ne(PG_FUNCTION_ARGS)
597 : {
598 20 : int32 arg1 = PG_GETARG_INT32(0);
599 20 : int16 arg2 = PG_GETARG_INT16(1);
600 :
601 20 : PG_RETURN_BOOL(arg1 != arg2);
602 : }
603 :
604 : Datum
605 12033 : int42lt(PG_FUNCTION_ARGS)
606 : {
607 12033 : int32 arg1 = PG_GETARG_INT32(0);
608 12033 : int16 arg2 = PG_GETARG_INT16(1);
609 :
610 12033 : PG_RETURN_BOOL(arg1 < arg2);
611 : }
612 :
613 : Datum
614 11851 : int42le(PG_FUNCTION_ARGS)
615 : {
616 11851 : int32 arg1 = PG_GETARG_INT32(0);
617 11851 : int16 arg2 = PG_GETARG_INT16(1);
618 :
619 11851 : PG_RETURN_BOOL(arg1 <= arg2);
620 : }
621 :
622 : Datum
623 2152 : int42gt(PG_FUNCTION_ARGS)
624 : {
625 2152 : int32 arg1 = PG_GETARG_INT32(0);
626 2152 : int16 arg2 = PG_GETARG_INT16(1);
627 :
628 2152 : PG_RETURN_BOOL(arg1 > arg2);
629 : }
630 :
631 : Datum
632 2304 : int42ge(PG_FUNCTION_ARGS)
633 : {
634 2304 : int32 arg1 = PG_GETARG_INT32(0);
635 2304 : int16 arg2 = PG_GETARG_INT16(1);
636 :
637 2304 : PG_RETURN_BOOL(arg1 >= arg2);
638 : }
639 :
640 :
641 : /*----------------------------------------------------------
642 : * in_range functions for int4 and int2,
643 : * including cross-data-type comparisons.
644 : *
645 : * Note: we provide separate intN_int8 functions for performance
646 : * reasons. This forces also providing intN_int2, else cases with a
647 : * smallint offset value would fail to resolve which function to use.
648 : * But that's an unlikely situation, so don't duplicate code for it.
649 : *---------------------------------------------------------*/
650 :
651 : Datum
652 2132 : in_range_int4_int4(PG_FUNCTION_ARGS)
653 : {
654 2132 : int32 val = PG_GETARG_INT32(0);
655 2132 : int32 base = PG_GETARG_INT32(1);
656 2132 : int32 offset = PG_GETARG_INT32(2);
657 2132 : bool sub = PG_GETARG_BOOL(3);
658 2132 : bool less = PG_GETARG_BOOL(4);
659 : int32 sum;
660 :
661 2132 : if (offset < 0)
662 8 : ereport(ERROR,
663 : (errcode(ERRCODE_INVALID_PRECEDING_OR_FOLLOWING_SIZE),
664 : errmsg("invalid preceding or following size in window function")));
665 :
666 2124 : if (sub)
667 960 : offset = -offset; /* cannot overflow */
668 :
669 2124 : if (unlikely(pg_add_s32_overflow(base, offset, &sum)))
670 : {
671 : /*
672 : * If sub is false, the true sum is surely more than val, so correct
673 : * answer is the same as "less". If sub is true, the true sum is
674 : * surely less than val, so the answer is "!less".
675 : */
676 24 : PG_RETURN_BOOL(sub ? !less : less);
677 : }
678 :
679 2100 : if (less)
680 1240 : PG_RETURN_BOOL(val <= sum);
681 : else
682 860 : PG_RETURN_BOOL(val >= sum);
683 : }
684 :
685 : Datum
686 604 : in_range_int4_int2(PG_FUNCTION_ARGS)
687 : {
688 : /* Doesn't seem worth duplicating code for, so just invoke int4_int4 */
689 604 : return DirectFunctionCall5(in_range_int4_int4,
690 : PG_GETARG_DATUM(0),
691 : PG_GETARG_DATUM(1),
692 : Int32GetDatum((int32) PG_GETARG_INT16(2)),
693 : PG_GETARG_DATUM(3),
694 : PG_GETARG_DATUM(4));
695 : }
696 :
697 : Datum
698 508 : in_range_int4_int8(PG_FUNCTION_ARGS)
699 : {
700 : /* We must do all the math in int64 */
701 508 : int64 val = (int64) PG_GETARG_INT32(0);
702 508 : int64 base = (int64) PG_GETARG_INT32(1);
703 508 : int64 offset = PG_GETARG_INT64(2);
704 508 : bool sub = PG_GETARG_BOOL(3);
705 508 : bool less = PG_GETARG_BOOL(4);
706 : int64 sum;
707 :
708 508 : if (offset < 0)
709 0 : ereport(ERROR,
710 : (errcode(ERRCODE_INVALID_PRECEDING_OR_FOLLOWING_SIZE),
711 : errmsg("invalid preceding or following size in window function")));
712 :
713 508 : if (sub)
714 460 : offset = -offset; /* cannot overflow */
715 :
716 508 : if (unlikely(pg_add_s64_overflow(base, offset, &sum)))
717 : {
718 : /*
719 : * If sub is false, the true sum is surely more than val, so correct
720 : * answer is the same as "less". If sub is true, the true sum is
721 : * surely less than val, so the answer is "!less".
722 : */
723 0 : PG_RETURN_BOOL(sub ? !less : less);
724 : }
725 :
726 508 : if (less)
727 48 : PG_RETURN_BOOL(val <= sum);
728 : else
729 460 : PG_RETURN_BOOL(val >= sum);
730 : }
731 :
732 : Datum
733 24 : in_range_int2_int4(PG_FUNCTION_ARGS)
734 : {
735 : /* We must do all the math in int32 */
736 24 : int32 val = (int32) PG_GETARG_INT16(0);
737 24 : int32 base = (int32) PG_GETARG_INT16(1);
738 24 : int32 offset = PG_GETARG_INT32(2);
739 24 : bool sub = PG_GETARG_BOOL(3);
740 24 : bool less = PG_GETARG_BOOL(4);
741 : int32 sum;
742 :
743 24 : if (offset < 0)
744 0 : ereport(ERROR,
745 : (errcode(ERRCODE_INVALID_PRECEDING_OR_FOLLOWING_SIZE),
746 : errmsg("invalid preceding or following size in window function")));
747 :
748 24 : if (sub)
749 12 : offset = -offset; /* cannot overflow */
750 :
751 24 : if (unlikely(pg_add_s32_overflow(base, offset, &sum)))
752 : {
753 : /*
754 : * If sub is false, the true sum is surely more than val, so correct
755 : * answer is the same as "less". If sub is true, the true sum is
756 : * surely less than val, so the answer is "!less".
757 : */
758 24 : PG_RETURN_BOOL(sub ? !less : less);
759 : }
760 :
761 0 : if (less)
762 0 : PG_RETURN_BOOL(val <= sum);
763 : else
764 0 : PG_RETURN_BOOL(val >= sum);
765 : }
766 :
767 : Datum
768 0 : in_range_int2_int2(PG_FUNCTION_ARGS)
769 : {
770 : /* Doesn't seem worth duplicating code for, so just invoke int2_int4 */
771 0 : return DirectFunctionCall5(in_range_int2_int4,
772 : PG_GETARG_DATUM(0),
773 : PG_GETARG_DATUM(1),
774 : Int32GetDatum((int32) PG_GETARG_INT16(2)),
775 : PG_GETARG_DATUM(3),
776 : PG_GETARG_DATUM(4));
777 : }
778 :
779 : Datum
780 0 : in_range_int2_int8(PG_FUNCTION_ARGS)
781 : {
782 : /* Doesn't seem worth duplicating code for, so just invoke int4_int8 */
783 0 : return DirectFunctionCall5(in_range_int4_int8,
784 : Int32GetDatum((int32) PG_GETARG_INT16(0)),
785 : Int32GetDatum((int32) PG_GETARG_INT16(1)),
786 : PG_GETARG_DATUM(2),
787 : PG_GETARG_DATUM(3),
788 : PG_GETARG_DATUM(4));
789 : }
790 :
791 :
792 : /*
793 : * int[24]pl - returns arg1 + arg2
794 : * int[24]mi - returns arg1 - arg2
795 : * int[24]mul - returns arg1 * arg2
796 : * int[24]div - returns arg1 / arg2
797 : */
798 :
799 : Datum
800 22557 : int4um(PG_FUNCTION_ARGS)
801 : {
802 22557 : int32 arg = PG_GETARG_INT32(0);
803 :
804 22557 : if (unlikely(arg == PG_INT32_MIN))
805 0 : ereport(ERROR,
806 : (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
807 : errmsg("integer out of range")));
808 22557 : PG_RETURN_INT32(-arg);
809 : }
810 :
811 : Datum
812 5 : int4up(PG_FUNCTION_ARGS)
813 : {
814 5 : int32 arg = PG_GETARG_INT32(0);
815 :
816 5 : PG_RETURN_INT32(arg);
817 : }
818 :
819 : Datum
820 6908017 : int4pl(PG_FUNCTION_ARGS)
821 : {
822 6908017 : int32 arg1 = PG_GETARG_INT32(0);
823 6908017 : int32 arg2 = PG_GETARG_INT32(1);
824 : int32 result;
825 :
826 6908017 : if (unlikely(pg_add_s32_overflow(arg1, arg2, &result)))
827 4 : ereport(ERROR,
828 : (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
829 : errmsg("integer out of range")));
830 6908013 : PG_RETURN_INT32(result);
831 : }
832 :
833 : Datum
834 1904629 : int4mi(PG_FUNCTION_ARGS)
835 : {
836 1904629 : int32 arg1 = PG_GETARG_INT32(0);
837 1904629 : int32 arg2 = PG_GETARG_INT32(1);
838 : int32 result;
839 :
840 1904629 : if (unlikely(pg_sub_s32_overflow(arg1, arg2, &result)))
841 4 : ereport(ERROR,
842 : (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
843 : errmsg("integer out of range")));
844 1904625 : PG_RETURN_INT32(result);
845 : }
846 :
847 : Datum
848 1868140 : int4mul(PG_FUNCTION_ARGS)
849 : {
850 1868140 : int32 arg1 = PG_GETARG_INT32(0);
851 1868140 : int32 arg2 = PG_GETARG_INT32(1);
852 : int32 result;
853 :
854 1868140 : if (unlikely(pg_mul_s32_overflow(arg1, arg2, &result)))
855 16 : ereport(ERROR,
856 : (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
857 : errmsg("integer out of range")));
858 1868124 : PG_RETURN_INT32(result);
859 : }
860 :
861 : Datum
862 967117 : int4div(PG_FUNCTION_ARGS)
863 : {
864 967117 : int32 arg1 = PG_GETARG_INT32(0);
865 967117 : int32 arg2 = PG_GETARG_INT32(1);
866 : int32 result;
867 :
868 967117 : if (arg2 == 0)
869 : {
870 204 : ereport(ERROR,
871 : (errcode(ERRCODE_DIVISION_BY_ZERO),
872 : errmsg("division by zero")));
873 : /* ensure compiler realizes we mustn't reach the division (gcc bug) */
874 : PG_RETURN_NULL();
875 : }
876 :
877 : /*
878 : * INT_MIN / -1 is problematic, since the result can't be represented on a
879 : * two's-complement machine. Some machines produce INT_MIN, some produce
880 : * zero, some throw an exception. We can dodge the problem by recognizing
881 : * that division by -1 is the same as negation.
882 : */
883 966913 : if (arg2 == -1)
884 : {
885 9 : if (unlikely(arg1 == PG_INT32_MIN))
886 4 : ereport(ERROR,
887 : (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
888 : errmsg("integer out of range")));
889 5 : result = -arg1;
890 5 : PG_RETURN_INT32(result);
891 : }
892 :
893 : /* No overflow is possible */
894 :
895 966904 : result = arg1 / arg2;
896 :
897 966904 : PG_RETURN_INT32(result);
898 : }
899 :
900 : Datum
901 0 : int4inc(PG_FUNCTION_ARGS)
902 : {
903 0 : int32 arg = PG_GETARG_INT32(0);
904 : int32 result;
905 :
906 0 : if (unlikely(pg_add_s32_overflow(arg, 1, &result)))
907 0 : ereport(ERROR,
908 : (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
909 : errmsg("integer out of range")));
910 :
911 0 : PG_RETURN_INT32(result);
912 : }
913 :
914 : Datum
915 13 : int2um(PG_FUNCTION_ARGS)
916 : {
917 13 : int16 arg = PG_GETARG_INT16(0);
918 :
919 13 : if (unlikely(arg == PG_INT16_MIN))
920 0 : ereport(ERROR,
921 : (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
922 : errmsg("smallint out of range")));
923 13 : PG_RETURN_INT16(-arg);
924 : }
925 :
926 : Datum
927 0 : int2up(PG_FUNCTION_ARGS)
928 : {
929 0 : int16 arg = PG_GETARG_INT16(0);
930 :
931 0 : PG_RETURN_INT16(arg);
932 : }
933 :
934 : Datum
935 37 : int2pl(PG_FUNCTION_ARGS)
936 : {
937 37 : int16 arg1 = PG_GETARG_INT16(0);
938 37 : int16 arg2 = PG_GETARG_INT16(1);
939 : int16 result;
940 :
941 37 : if (unlikely(pg_add_s16_overflow(arg1, arg2, &result)))
942 4 : ereport(ERROR,
943 : (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
944 : errmsg("smallint out of range")));
945 33 : PG_RETURN_INT16(result);
946 : }
947 :
948 : Datum
949 85 : int2mi(PG_FUNCTION_ARGS)
950 : {
951 85 : int16 arg1 = PG_GETARG_INT16(0);
952 85 : int16 arg2 = PG_GETARG_INT16(1);
953 : int16 result;
954 :
955 85 : if (unlikely(pg_sub_s16_overflow(arg1, arg2, &result)))
956 4 : ereport(ERROR,
957 : (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
958 : errmsg("smallint out of range")));
959 81 : PG_RETURN_INT16(result);
960 : }
961 :
962 : Datum
963 37 : int2mul(PG_FUNCTION_ARGS)
964 : {
965 37 : int16 arg1 = PG_GETARG_INT16(0);
966 37 : int16 arg2 = PG_GETARG_INT16(1);
967 : int16 result;
968 :
969 37 : if (unlikely(pg_mul_s16_overflow(arg1, arg2, &result)))
970 8 : ereport(ERROR,
971 : (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
972 : errmsg("smallint out of range")));
973 :
974 29 : PG_RETURN_INT16(result);
975 : }
976 :
977 : Datum
978 29 : int2div(PG_FUNCTION_ARGS)
979 : {
980 29 : int16 arg1 = PG_GETARG_INT16(0);
981 29 : int16 arg2 = PG_GETARG_INT16(1);
982 : int16 result;
983 :
984 29 : if (arg2 == 0)
985 : {
986 0 : ereport(ERROR,
987 : (errcode(ERRCODE_DIVISION_BY_ZERO),
988 : errmsg("division by zero")));
989 : /* ensure compiler realizes we mustn't reach the division (gcc bug) */
990 : PG_RETURN_NULL();
991 : }
992 :
993 : /*
994 : * SHRT_MIN / -1 is problematic, since the result can't be represented on
995 : * a two's-complement machine. Some machines produce SHRT_MIN, some
996 : * produce zero, some throw an exception. We can dodge the problem by
997 : * recognizing that division by -1 is the same as negation.
998 : */
999 29 : if (arg2 == -1)
1000 : {
1001 4 : if (unlikely(arg1 == PG_INT16_MIN))
1002 4 : ereport(ERROR,
1003 : (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
1004 : errmsg("smallint out of range")));
1005 0 : result = -arg1;
1006 0 : PG_RETURN_INT16(result);
1007 : }
1008 :
1009 : /* No overflow is possible */
1010 :
1011 25 : result = arg1 / arg2;
1012 :
1013 25 : PG_RETURN_INT16(result);
1014 : }
1015 :
1016 : Datum
1017 1504 : int24pl(PG_FUNCTION_ARGS)
1018 : {
1019 1504 : int16 arg1 = PG_GETARG_INT16(0);
1020 1504 : int32 arg2 = PG_GETARG_INT32(1);
1021 : int32 result;
1022 :
1023 1504 : if (unlikely(pg_add_s32_overflow((int32) arg1, arg2, &result)))
1024 0 : ereport(ERROR,
1025 : (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
1026 : errmsg("integer out of range")));
1027 1504 : PG_RETURN_INT32(result);
1028 : }
1029 :
1030 : Datum
1031 17584 : int24mi(PG_FUNCTION_ARGS)
1032 : {
1033 17584 : int16 arg1 = PG_GETARG_INT16(0);
1034 17584 : int32 arg2 = PG_GETARG_INT32(1);
1035 : int32 result;
1036 :
1037 17584 : if (unlikely(pg_sub_s32_overflow((int32) arg1, arg2, &result)))
1038 0 : ereport(ERROR,
1039 : (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
1040 : errmsg("integer out of range")));
1041 17584 : PG_RETURN_INT32(result);
1042 : }
1043 :
1044 : Datum
1045 25 : int24mul(PG_FUNCTION_ARGS)
1046 : {
1047 25 : int16 arg1 = PG_GETARG_INT16(0);
1048 25 : int32 arg2 = PG_GETARG_INT32(1);
1049 : int32 result;
1050 :
1051 25 : if (unlikely(pg_mul_s32_overflow((int32) arg1, arg2, &result)))
1052 0 : ereport(ERROR,
1053 : (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
1054 : errmsg("integer out of range")));
1055 25 : PG_RETURN_INT32(result);
1056 : }
1057 :
1058 : Datum
1059 29 : int24div(PG_FUNCTION_ARGS)
1060 : {
1061 29 : int16 arg1 = PG_GETARG_INT16(0);
1062 29 : int32 arg2 = PG_GETARG_INT32(1);
1063 :
1064 29 : if (unlikely(arg2 == 0))
1065 : {
1066 4 : ereport(ERROR,
1067 : (errcode(ERRCODE_DIVISION_BY_ZERO),
1068 : errmsg("division by zero")));
1069 : /* ensure compiler realizes we mustn't reach the division (gcc bug) */
1070 : PG_RETURN_NULL();
1071 : }
1072 :
1073 : /* No overflow is possible */
1074 25 : PG_RETURN_INT32((int32) arg1 / arg2);
1075 : }
1076 :
1077 : Datum
1078 32 : int42pl(PG_FUNCTION_ARGS)
1079 : {
1080 32 : int32 arg1 = PG_GETARG_INT32(0);
1081 32 : int16 arg2 = PG_GETARG_INT16(1);
1082 : int32 result;
1083 :
1084 32 : if (unlikely(pg_add_s32_overflow(arg1, (int32) arg2, &result)))
1085 4 : ereport(ERROR,
1086 : (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
1087 : errmsg("integer out of range")));
1088 28 : PG_RETURN_INT32(result);
1089 : }
1090 :
1091 : Datum
1092 36 : int42mi(PG_FUNCTION_ARGS)
1093 : {
1094 36 : int32 arg1 = PG_GETARG_INT32(0);
1095 36 : int16 arg2 = PG_GETARG_INT16(1);
1096 : int32 result;
1097 :
1098 36 : if (unlikely(pg_sub_s32_overflow(arg1, (int32) arg2, &result)))
1099 4 : ereport(ERROR,
1100 : (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
1101 : errmsg("integer out of range")));
1102 32 : PG_RETURN_INT32(result);
1103 : }
1104 :
1105 : Datum
1106 37 : int42mul(PG_FUNCTION_ARGS)
1107 : {
1108 37 : int32 arg1 = PG_GETARG_INT32(0);
1109 37 : int16 arg2 = PG_GETARG_INT16(1);
1110 : int32 result;
1111 :
1112 37 : if (unlikely(pg_mul_s32_overflow(arg1, (int32) arg2, &result)))
1113 8 : ereport(ERROR,
1114 : (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
1115 : errmsg("integer out of range")));
1116 29 : PG_RETURN_INT32(result);
1117 : }
1118 :
1119 : Datum
1120 33 : int42div(PG_FUNCTION_ARGS)
1121 : {
1122 33 : int32 arg1 = PG_GETARG_INT32(0);
1123 33 : int16 arg2 = PG_GETARG_INT16(1);
1124 : int32 result;
1125 :
1126 33 : if (unlikely(arg2 == 0))
1127 : {
1128 4 : ereport(ERROR,
1129 : (errcode(ERRCODE_DIVISION_BY_ZERO),
1130 : errmsg("division by zero")));
1131 : /* ensure compiler realizes we mustn't reach the division (gcc bug) */
1132 : PG_RETURN_NULL();
1133 : }
1134 :
1135 : /*
1136 : * INT_MIN / -1 is problematic, since the result can't be represented on a
1137 : * two's-complement machine. Some machines produce INT_MIN, some produce
1138 : * zero, some throw an exception. We can dodge the problem by recognizing
1139 : * that division by -1 is the same as negation.
1140 : */
1141 29 : if (arg2 == -1)
1142 : {
1143 4 : if (unlikely(arg1 == PG_INT32_MIN))
1144 4 : ereport(ERROR,
1145 : (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
1146 : errmsg("integer out of range")));
1147 0 : result = -arg1;
1148 0 : PG_RETURN_INT32(result);
1149 : }
1150 :
1151 : /* No overflow is possible */
1152 :
1153 25 : result = arg1 / arg2;
1154 :
1155 25 : PG_RETURN_INT32(result);
1156 : }
1157 :
1158 : Datum
1159 5563722 : int4mod(PG_FUNCTION_ARGS)
1160 : {
1161 5563722 : int32 arg1 = PG_GETARG_INT32(0);
1162 5563722 : int32 arg2 = PG_GETARG_INT32(1);
1163 :
1164 5563722 : if (unlikely(arg2 == 0))
1165 : {
1166 0 : ereport(ERROR,
1167 : (errcode(ERRCODE_DIVISION_BY_ZERO),
1168 : errmsg("division by zero")));
1169 : /* ensure compiler realizes we mustn't reach the division (gcc bug) */
1170 : PG_RETURN_NULL();
1171 : }
1172 :
1173 : /*
1174 : * Some machines throw a floating-point exception for INT_MIN % -1, which
1175 : * is a bit silly since the correct answer is perfectly well-defined,
1176 : * namely zero.
1177 : */
1178 5563722 : if (arg2 == -1)
1179 10 : PG_RETURN_INT32(0);
1180 :
1181 : /* No overflow is possible */
1182 :
1183 5563712 : PG_RETURN_INT32(arg1 % arg2);
1184 : }
1185 :
1186 : Datum
1187 25 : int2mod(PG_FUNCTION_ARGS)
1188 : {
1189 25 : int16 arg1 = PG_GETARG_INT16(0);
1190 25 : int16 arg2 = PG_GETARG_INT16(1);
1191 :
1192 25 : if (unlikely(arg2 == 0))
1193 : {
1194 0 : ereport(ERROR,
1195 : (errcode(ERRCODE_DIVISION_BY_ZERO),
1196 : errmsg("division by zero")));
1197 : /* ensure compiler realizes we mustn't reach the division (gcc bug) */
1198 : PG_RETURN_NULL();
1199 : }
1200 :
1201 : /*
1202 : * Some machines throw a floating-point exception for INT_MIN % -1, which
1203 : * is a bit silly since the correct answer is perfectly well-defined,
1204 : * namely zero. (It's not clear this ever happens when dealing with
1205 : * int16, but we might as well have the test for safety.)
1206 : */
1207 25 : if (arg2 == -1)
1208 5 : PG_RETURN_INT16(0);
1209 :
1210 : /* No overflow is possible */
1211 :
1212 20 : PG_RETURN_INT16(arg1 % arg2);
1213 : }
1214 :
1215 :
1216 : /*
1217 : * int[24]abs()
1218 : * Absolute value
1219 : */
1220 : Datum
1221 84742 : int4abs(PG_FUNCTION_ARGS)
1222 : {
1223 84742 : int32 arg1 = PG_GETARG_INT32(0);
1224 : int32 result;
1225 :
1226 84742 : if (unlikely(arg1 == PG_INT32_MIN))
1227 0 : ereport(ERROR,
1228 : (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
1229 : errmsg("integer out of range")));
1230 84742 : result = (arg1 < 0) ? -arg1 : arg1;
1231 84742 : PG_RETURN_INT32(result);
1232 : }
1233 :
1234 : Datum
1235 20 : int2abs(PG_FUNCTION_ARGS)
1236 : {
1237 20 : int16 arg1 = PG_GETARG_INT16(0);
1238 : int16 result;
1239 :
1240 20 : if (unlikely(arg1 == PG_INT16_MIN))
1241 0 : ereport(ERROR,
1242 : (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
1243 : errmsg("smallint out of range")));
1244 20 : result = (arg1 < 0) ? -arg1 : arg1;
1245 20 : PG_RETURN_INT16(result);
1246 : }
1247 :
1248 : /*
1249 : * Greatest Common Divisor
1250 : *
1251 : * Returns the largest positive integer that exactly divides both inputs.
1252 : * Special cases:
1253 : * - gcd(x, 0) = gcd(0, x) = abs(x)
1254 : * because 0 is divisible by anything
1255 : * - gcd(0, 0) = 0
1256 : * complies with the previous definition and is a common convention
1257 : *
1258 : * Special care must be taken if either input is INT_MIN --- gcd(0, INT_MIN),
1259 : * gcd(INT_MIN, 0) and gcd(INT_MIN, INT_MIN) are all equal to abs(INT_MIN),
1260 : * which cannot be represented as a 32-bit signed integer.
1261 : */
1262 : static int32
1263 176 : int4gcd_internal(int32 arg1, int32 arg2)
1264 : {
1265 : int32 swap;
1266 : int32 a1,
1267 : a2;
1268 :
1269 : /*
1270 : * Put the greater absolute value in arg1.
1271 : *
1272 : * This would happen automatically in the loop below, but avoids an
1273 : * expensive modulo operation, and simplifies the special-case handling
1274 : * for INT_MIN below.
1275 : *
1276 : * We do this in negative space in order to handle INT_MIN.
1277 : */
1278 176 : a1 = (arg1 < 0) ? arg1 : -arg1;
1279 176 : a2 = (arg2 < 0) ? arg2 : -arg2;
1280 176 : if (a1 > a2)
1281 : {
1282 64 : swap = arg1;
1283 64 : arg1 = arg2;
1284 64 : arg2 = swap;
1285 : }
1286 :
1287 : /* Special care needs to be taken with INT_MIN. See comments above. */
1288 176 : if (arg1 == PG_INT32_MIN)
1289 : {
1290 60 : if (arg2 == 0 || arg2 == PG_INT32_MIN)
1291 8 : ereport(ERROR,
1292 : (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
1293 : errmsg("integer out of range")));
1294 :
1295 : /*
1296 : * Some machines throw a floating-point exception for INT_MIN % -1,
1297 : * which is a bit silly since the correct answer is perfectly
1298 : * well-defined, namely zero. Guard against this and just return the
1299 : * result, gcd(INT_MIN, -1) = 1.
1300 : */
1301 52 : if (arg2 == -1)
1302 8 : return 1;
1303 : }
1304 :
1305 : /* Use the Euclidean algorithm to find the GCD */
1306 628 : while (arg2 != 0)
1307 : {
1308 468 : swap = arg2;
1309 468 : arg2 = arg1 % arg2;
1310 468 : arg1 = swap;
1311 : }
1312 :
1313 : /*
1314 : * Make sure the result is positive. (We know we don't have INT_MIN
1315 : * anymore).
1316 : */
1317 160 : if (arg1 < 0)
1318 68 : arg1 = -arg1;
1319 :
1320 160 : return arg1;
1321 : }
1322 :
1323 : Datum
1324 120 : int4gcd(PG_FUNCTION_ARGS)
1325 : {
1326 120 : int32 arg1 = PG_GETARG_INT32(0);
1327 120 : int32 arg2 = PG_GETARG_INT32(1);
1328 : int32 result;
1329 :
1330 120 : result = int4gcd_internal(arg1, arg2);
1331 :
1332 112 : PG_RETURN_INT32(result);
1333 : }
1334 :
1335 : /*
1336 : * Least Common Multiple
1337 : */
1338 : Datum
1339 104 : int4lcm(PG_FUNCTION_ARGS)
1340 : {
1341 104 : int32 arg1 = PG_GETARG_INT32(0);
1342 104 : int32 arg2 = PG_GETARG_INT32(1);
1343 : int32 gcd;
1344 : int32 result;
1345 :
1346 : /*
1347 : * Handle lcm(x, 0) = lcm(0, x) = 0 as a special case. This prevents a
1348 : * division-by-zero error below when x is zero, and an overflow error from
1349 : * the GCD computation when x = INT_MIN.
1350 : */
1351 104 : if (arg1 == 0 || arg2 == 0)
1352 48 : PG_RETURN_INT32(0);
1353 :
1354 : /* lcm(x, y) = abs(x / gcd(x, y) * y) */
1355 56 : gcd = int4gcd_internal(arg1, arg2);
1356 56 : arg1 = arg1 / gcd;
1357 :
1358 56 : if (unlikely(pg_mul_s32_overflow(arg1, arg2, &result)))
1359 4 : ereport(ERROR,
1360 : (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
1361 : errmsg("integer out of range")));
1362 :
1363 : /* If the result is INT_MIN, it cannot be represented. */
1364 52 : if (unlikely(result == PG_INT32_MIN))
1365 4 : ereport(ERROR,
1366 : (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
1367 : errmsg("integer out of range")));
1368 :
1369 48 : if (result < 0)
1370 24 : result = -result;
1371 :
1372 48 : PG_RETURN_INT32(result);
1373 : }
1374 :
1375 : Datum
1376 268 : int2larger(PG_FUNCTION_ARGS)
1377 : {
1378 268 : int16 arg1 = PG_GETARG_INT16(0);
1379 268 : int16 arg2 = PG_GETARG_INT16(1);
1380 :
1381 268 : PG_RETURN_INT16((arg1 > arg2) ? arg1 : arg2);
1382 : }
1383 :
1384 : Datum
1385 0 : int2smaller(PG_FUNCTION_ARGS)
1386 : {
1387 0 : int16 arg1 = PG_GETARG_INT16(0);
1388 0 : int16 arg2 = PG_GETARG_INT16(1);
1389 :
1390 0 : PG_RETURN_INT16((arg1 < arg2) ? arg1 : arg2);
1391 : }
1392 :
1393 : Datum
1394 616689 : int4larger(PG_FUNCTION_ARGS)
1395 : {
1396 616689 : int32 arg1 = PG_GETARG_INT32(0);
1397 616689 : int32 arg2 = PG_GETARG_INT32(1);
1398 :
1399 616689 : PG_RETURN_INT32((arg1 > arg2) ? arg1 : arg2);
1400 : }
1401 :
1402 : Datum
1403 364593 : int4smaller(PG_FUNCTION_ARGS)
1404 : {
1405 364593 : int32 arg1 = PG_GETARG_INT32(0);
1406 364593 : int32 arg2 = PG_GETARG_INT32(1);
1407 :
1408 364593 : PG_RETURN_INT32((arg1 < arg2) ? arg1 : arg2);
1409 : }
1410 :
1411 : /*
1412 : * Bit-pushing operators
1413 : *
1414 : * int[24]and - returns arg1 & arg2
1415 : * int[24]or - returns arg1 | arg2
1416 : * int[24]xor - returns arg1 # arg2
1417 : * int[24]not - returns ~arg1
1418 : * int[24]shl - returns arg1 << arg2
1419 : * int[24]shr - returns arg1 >> arg2
1420 : */
1421 :
1422 : Datum
1423 4560 : int4and(PG_FUNCTION_ARGS)
1424 : {
1425 4560 : int32 arg1 = PG_GETARG_INT32(0);
1426 4560 : int32 arg2 = PG_GETARG_INT32(1);
1427 :
1428 4560 : PG_RETURN_INT32(arg1 & arg2);
1429 : }
1430 :
1431 : Datum
1432 12 : int4or(PG_FUNCTION_ARGS)
1433 : {
1434 12 : int32 arg1 = PG_GETARG_INT32(0);
1435 12 : int32 arg2 = PG_GETARG_INT32(1);
1436 :
1437 12 : PG_RETURN_INT32(arg1 | arg2);
1438 : }
1439 :
1440 : Datum
1441 12 : int4xor(PG_FUNCTION_ARGS)
1442 : {
1443 12 : int32 arg1 = PG_GETARG_INT32(0);
1444 12 : int32 arg2 = PG_GETARG_INT32(1);
1445 :
1446 12 : PG_RETURN_INT32(arg1 ^ arg2);
1447 : }
1448 :
1449 : Datum
1450 1034 : int4shl(PG_FUNCTION_ARGS)
1451 : {
1452 1034 : int32 arg1 = PG_GETARG_INT32(0);
1453 1034 : int32 arg2 = PG_GETARG_INT32(1);
1454 :
1455 1034 : PG_RETURN_INT32(arg1 << arg2);
1456 : }
1457 :
1458 : Datum
1459 0 : int4shr(PG_FUNCTION_ARGS)
1460 : {
1461 0 : int32 arg1 = PG_GETARG_INT32(0);
1462 0 : int32 arg2 = PG_GETARG_INT32(1);
1463 :
1464 0 : PG_RETURN_INT32(arg1 >> arg2);
1465 : }
1466 :
1467 : Datum
1468 0 : int4not(PG_FUNCTION_ARGS)
1469 : {
1470 0 : int32 arg1 = PG_GETARG_INT32(0);
1471 :
1472 0 : PG_RETURN_INT32(~arg1);
1473 : }
1474 :
1475 : Datum
1476 16 : int2and(PG_FUNCTION_ARGS)
1477 : {
1478 16 : int16 arg1 = PG_GETARG_INT16(0);
1479 16 : int16 arg2 = PG_GETARG_INT16(1);
1480 :
1481 16 : PG_RETURN_INT16(arg1 & arg2);
1482 : }
1483 :
1484 : Datum
1485 16 : int2or(PG_FUNCTION_ARGS)
1486 : {
1487 16 : int16 arg1 = PG_GETARG_INT16(0);
1488 16 : int16 arg2 = PG_GETARG_INT16(1);
1489 :
1490 16 : PG_RETURN_INT16(arg1 | arg2);
1491 : }
1492 :
1493 : Datum
1494 16 : int2xor(PG_FUNCTION_ARGS)
1495 : {
1496 16 : int16 arg1 = PG_GETARG_INT16(0);
1497 16 : int16 arg2 = PG_GETARG_INT16(1);
1498 :
1499 16 : PG_RETURN_INT16(arg1 ^ arg2);
1500 : }
1501 :
1502 : Datum
1503 0 : int2not(PG_FUNCTION_ARGS)
1504 : {
1505 0 : int16 arg1 = PG_GETARG_INT16(0);
1506 :
1507 0 : PG_RETURN_INT16(~arg1);
1508 : }
1509 :
1510 :
1511 : Datum
1512 10 : int2shl(PG_FUNCTION_ARGS)
1513 : {
1514 10 : int16 arg1 = PG_GETARG_INT16(0);
1515 10 : int32 arg2 = PG_GETARG_INT32(1);
1516 :
1517 10 : PG_RETURN_INT16(arg1 << arg2);
1518 : }
1519 :
1520 : Datum
1521 0 : int2shr(PG_FUNCTION_ARGS)
1522 : {
1523 0 : int16 arg1 = PG_GETARG_INT16(0);
1524 0 : int32 arg2 = PG_GETARG_INT32(1);
1525 :
1526 0 : PG_RETURN_INT16(arg1 >> arg2);
1527 : }
1528 :
1529 : /*
1530 : * non-persistent numeric series generator
1531 : */
1532 : Datum
1533 11481266 : generate_series_int4(PG_FUNCTION_ARGS)
1534 : {
1535 11481266 : return generate_series_step_int4(fcinfo);
1536 : }
1537 :
1538 : Datum
1539 11691424 : generate_series_step_int4(PG_FUNCTION_ARGS)
1540 : {
1541 : FuncCallContext *funcctx;
1542 : generate_series_fctx *fctx;
1543 : int32 result;
1544 : MemoryContext oldcontext;
1545 :
1546 : /* stuff done only on the first call of the function */
1547 11691424 : if (SRF_IS_FIRSTCALL())
1548 : {
1549 49910 : int32 start = PG_GETARG_INT32(0);
1550 49910 : int32 finish = PG_GETARG_INT32(1);
1551 49910 : int32 step = 1;
1552 :
1553 : /* see if we were given an explicit step size */
1554 49910 : if (PG_NARGS() == 3)
1555 247 : step = PG_GETARG_INT32(2);
1556 49910 : if (step == 0)
1557 0 : ereport(ERROR,
1558 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1559 : errmsg("step size cannot equal zero")));
1560 :
1561 : /* create a function context for cross-call persistence */
1562 49910 : funcctx = SRF_FIRSTCALL_INIT();
1563 :
1564 : /*
1565 : * switch to memory context appropriate for multiple function calls
1566 : */
1567 49910 : oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
1568 :
1569 : /* allocate memory for user context */
1570 49910 : fctx = palloc_object(generate_series_fctx);
1571 :
1572 : /*
1573 : * Use fctx to keep state from call to call. Seed current with the
1574 : * original start value
1575 : */
1576 49910 : fctx->current = start;
1577 49910 : fctx->finish = finish;
1578 49910 : fctx->step = step;
1579 :
1580 49910 : funcctx->user_fctx = fctx;
1581 49910 : MemoryContextSwitchTo(oldcontext);
1582 : }
1583 :
1584 : /* stuff done on every call of the function */
1585 11691424 : funcctx = SRF_PERCALL_SETUP();
1586 :
1587 : /*
1588 : * get the saved state and use current as the result for this iteration
1589 : */
1590 11691424 : fctx = funcctx->user_fctx;
1591 11691424 : result = fctx->current;
1592 :
1593 11691424 : if ((fctx->step > 0 && fctx->current <= fctx->finish) ||
1594 149883 : (fctx->step < 0 && fctx->current >= fctx->finish))
1595 : {
1596 : /*
1597 : * Increment current in preparation for next iteration. If next-value
1598 : * computation overflows, this is the final result.
1599 : */
1600 11641546 : if (pg_add_s32_overflow(fctx->current, fctx->step, &fctx->current))
1601 0 : fctx->step = 0;
1602 :
1603 : /* do when there is more left to send */
1604 11641546 : SRF_RETURN_NEXT(funcctx, Int32GetDatum(result));
1605 : }
1606 : else
1607 : /* do when there is no more left */
1608 49878 : SRF_RETURN_DONE(funcctx);
1609 : }
1610 :
1611 : /*
1612 : * Planner support function for generate_series(int4, int4 [, int4])
1613 : */
1614 : Datum
1615 41568 : generate_series_int4_support(PG_FUNCTION_ARGS)
1616 : {
1617 41568 : Node *rawreq = (Node *) PG_GETARG_POINTER(0);
1618 41568 : Node *ret = NULL;
1619 :
1620 41568 : if (IsA(rawreq, SupportRequestRows))
1621 : {
1622 : /* Try to estimate the number of rows returned */
1623 10688 : SupportRequestRows *req = (SupportRequestRows *) rawreq;
1624 :
1625 10688 : if (is_funcclause(req->node)) /* be paranoid */
1626 : {
1627 10688 : List *args = ((FuncExpr *) req->node)->args;
1628 : Node *arg1,
1629 : *arg2,
1630 : *arg3;
1631 :
1632 : /* We can use estimated argument values here */
1633 10688 : arg1 = estimate_expression_value(req->root, linitial(args));
1634 10688 : arg2 = estimate_expression_value(req->root, lsecond(args));
1635 10688 : if (list_length(args) >= 3)
1636 316 : arg3 = estimate_expression_value(req->root, lthird(args));
1637 : else
1638 10372 : arg3 = NULL;
1639 :
1640 : /*
1641 : * If any argument is constant NULL, we can safely assume that
1642 : * zero rows are returned. Otherwise, if they're all non-NULL
1643 : * constants, we can calculate the number of rows that will be
1644 : * returned. Use double arithmetic to avoid overflow hazards.
1645 : */
1646 10688 : if ((IsA(arg1, Const) &&
1647 10622 : ((Const *) arg1)->constisnull) ||
1648 10688 : (IsA(arg2, Const) &&
1649 10688 : ((Const *) arg2)->constisnull) ||
1650 316 : (arg3 != NULL && IsA(arg3, Const) &&
1651 316 : ((Const *) arg3)->constisnull))
1652 : {
1653 0 : req->rows = 0;
1654 0 : ret = (Node *) req;
1655 : }
1656 10688 : else if (IsA(arg1, Const) &&
1657 10622 : IsA(arg2, Const) &&
1658 316 : (arg3 == NULL || IsA(arg3, Const)))
1659 : {
1660 : double start,
1661 : finish,
1662 : step;
1663 :
1664 7358 : start = DatumGetInt32(((Const *) arg1)->constvalue);
1665 7358 : finish = DatumGetInt32(((Const *) arg2)->constvalue);
1666 7358 : step = arg3 ? DatumGetInt32(((Const *) arg3)->constvalue) : 1;
1667 :
1668 : /* This equation works for either sign of step */
1669 7358 : if (step != 0)
1670 : {
1671 7358 : req->rows = floor((finish - start + step) / step);
1672 7358 : ret = (Node *) req;
1673 : }
1674 : }
1675 : }
1676 : }
1677 :
1678 41568 : PG_RETURN_POINTER(ret);
1679 : }
|