1 /*-------------------------------------------------------------------------
2 *
3 * int.c
4 * Functions for the built-in integer types (except int8).
5 *
6 * Portions Copyright (c) 1996-2018, 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
34 #include "catalog/pg_type.h"
35 #include "common/int.h"
36 #include "funcapi.h"
37 #include "libpq/pqformat.h"
38 #include "utils/array.h"
39 #include "utils/builtins.h"
40
41 #define Int2VectorSize(n) (offsetof(int2vector, values) + (n) * sizeof(int16))
42
43 typedef struct
44 {
45 int32 current;
46 int32 finish;
47 int32 step;
48 } generate_series_fctx;
49
50
51 /*****************************************************************************
52 * USER I/O ROUTINES *
53 *****************************************************************************/
54
55 /*
56 * int2in - converts "num" to short
57 */
58 Datum
int2in(PG_FUNCTION_ARGS)59 int2in(PG_FUNCTION_ARGS)
60 {
61 char *num = PG_GETARG_CSTRING(0);
62
63 PG_RETURN_INT16(pg_atoi(num, sizeof(int16), '\0'));
64 }
65
66 /*
67 * int2out - converts short to "num"
68 */
69 Datum
int2out(PG_FUNCTION_ARGS)70 int2out(PG_FUNCTION_ARGS)
71 {
72 int16 arg1 = PG_GETARG_INT16(0);
73 char *result = (char *) palloc(7); /* sign, 5 digits, '\0' */
74
75 pg_itoa(arg1, result);
76 PG_RETURN_CSTRING(result);
77 }
78
79 /*
80 * int2recv - converts external binary format to int2
81 */
82 Datum
int2recv(PG_FUNCTION_ARGS)83 int2recv(PG_FUNCTION_ARGS)
84 {
85 StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
86
87 PG_RETURN_INT16((int16) pq_getmsgint(buf, sizeof(int16)));
88 }
89
90 /*
91 * int2send - converts int2 to binary format
92 */
93 Datum
int2send(PG_FUNCTION_ARGS)94 int2send(PG_FUNCTION_ARGS)
95 {
96 int16 arg1 = PG_GETARG_INT16(0);
97 StringInfoData buf;
98
99 pq_begintypsend(&buf);
100 pq_sendint16(&buf, arg1);
101 PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
102 }
103
104 /*
105 * construct int2vector given a raw array of int2s
106 *
107 * If int2s is NULL then caller must fill values[] afterward
108 */
109 int2vector *
buildint2vector(const int16 * int2s,int n)110 buildint2vector(const int16 *int2s, int n)
111 {
112 int2vector *result;
113
114 result = (int2vector *) palloc0(Int2VectorSize(n));
115
116 if (n > 0 && int2s)
117 memcpy(result->values, int2s, n * sizeof(int16));
118
119 /*
120 * Attach standard array header. For historical reasons, we set the index
121 * lower bound to 0 not 1.
122 */
123 SET_VARSIZE(result, Int2VectorSize(n));
124 result->ndim = 1;
125 result->dataoffset = 0; /* never any nulls */
126 result->elemtype = INT2OID;
127 result->dim1 = n;
128 result->lbound1 = 0;
129
130 return result;
131 }
132
133 /*
134 * int2vectorin - converts "num num ..." to internal form
135 */
136 Datum
int2vectorin(PG_FUNCTION_ARGS)137 int2vectorin(PG_FUNCTION_ARGS)
138 {
139 char *intString = PG_GETARG_CSTRING(0);
140 int2vector *result;
141 int n;
142
143 result = (int2vector *) palloc0(Int2VectorSize(FUNC_MAX_ARGS));
144
145 for (n = 0; *intString && n < FUNC_MAX_ARGS; n++)
146 {
147 while (*intString && isspace((unsigned char) *intString))
148 intString++;
149 if (*intString == '\0')
150 break;
151 result->values[n] = pg_atoi(intString, sizeof(int16), ' ');
152 while (*intString && !isspace((unsigned char) *intString))
153 intString++;
154 }
155 while (*intString && isspace((unsigned char) *intString))
156 intString++;
157 if (*intString)
158 ereport(ERROR,
159 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
160 errmsg("int2vector has too many elements")));
161
162 SET_VARSIZE(result, Int2VectorSize(n));
163 result->ndim = 1;
164 result->dataoffset = 0; /* never any nulls */
165 result->elemtype = INT2OID;
166 result->dim1 = n;
167 result->lbound1 = 0;
168
169 PG_RETURN_POINTER(result);
170 }
171
172 /*
173 * int2vectorout - converts internal form to "num num ..."
174 */
175 Datum
int2vectorout(PG_FUNCTION_ARGS)176 int2vectorout(PG_FUNCTION_ARGS)
177 {
178 int2vector *int2Array = (int2vector *) PG_GETARG_POINTER(0);
179 int num,
180 nnums = int2Array->dim1;
181 char *rp;
182 char *result;
183
184 /* assumes sign, 5 digits, ' ' */
185 rp = result = (char *) palloc(nnums * 7 + 1);
186 for (num = 0; num < nnums; num++)
187 {
188 if (num != 0)
189 *rp++ = ' ';
190 pg_itoa(int2Array->values[num], rp);
191 while (*++rp != '\0')
192 ;
193 }
194 *rp = '\0';
195 PG_RETURN_CSTRING(result);
196 }
197
198 /*
199 * int2vectorrecv - converts external binary format to int2vector
200 */
201 Datum
int2vectorrecv(PG_FUNCTION_ARGS)202 int2vectorrecv(PG_FUNCTION_ARGS)
203 {
204 StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
205 FunctionCallInfoData locfcinfo;
206 int2vector *result;
207
208 /*
209 * Normally one would call array_recv() using DirectFunctionCall3, but
210 * that does not work since array_recv wants to cache some data using
211 * fcinfo->flinfo->fn_extra. So we need to pass it our own flinfo
212 * parameter.
213 */
214 InitFunctionCallInfoData(locfcinfo, fcinfo->flinfo, 3,
215 InvalidOid, NULL, NULL);
216
217 locfcinfo.arg[0] = PointerGetDatum(buf);
218 locfcinfo.arg[1] = ObjectIdGetDatum(INT2OID);
219 locfcinfo.arg[2] = Int32GetDatum(-1);
220 locfcinfo.argnull[0] = false;
221 locfcinfo.argnull[1] = false;
222 locfcinfo.argnull[2] = false;
223
224 result = (int2vector *) DatumGetPointer(array_recv(&locfcinfo));
225
226 Assert(!locfcinfo.isnull);
227
228 /* sanity checks: int2vector must be 1-D, 0-based, no nulls */
229 if (ARR_NDIM(result) != 1 ||
230 ARR_HASNULL(result) ||
231 ARR_ELEMTYPE(result) != INT2OID ||
232 ARR_LBOUND(result)[0] != 0)
233 ereport(ERROR,
234 (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
235 errmsg("invalid int2vector data")));
236
237 /* check length for consistency with int2vectorin() */
238 if (ARR_DIMS(result)[0] > FUNC_MAX_ARGS)
239 ereport(ERROR,
240 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
241 errmsg("oidvector has too many elements")));
242
243 PG_RETURN_POINTER(result);
244 }
245
246 /*
247 * int2vectorsend - converts int2vector to binary format
248 */
249 Datum
int2vectorsend(PG_FUNCTION_ARGS)250 int2vectorsend(PG_FUNCTION_ARGS)
251 {
252 return array_send(fcinfo);
253 }
254
255
256 /*****************************************************************************
257 * PUBLIC ROUTINES *
258 *****************************************************************************/
259
260 /*
261 * int4in - converts "num" to int4
262 */
263 Datum
int4in(PG_FUNCTION_ARGS)264 int4in(PG_FUNCTION_ARGS)
265 {
266 char *num = PG_GETARG_CSTRING(0);
267
268 PG_RETURN_INT32(pg_atoi(num, sizeof(int32), '\0'));
269 }
270
271 /*
272 * int4out - converts int4 to "num"
273 */
274 Datum
int4out(PG_FUNCTION_ARGS)275 int4out(PG_FUNCTION_ARGS)
276 {
277 int32 arg1 = PG_GETARG_INT32(0);
278 char *result = (char *) palloc(12); /* sign, 10 digits, '\0' */
279
280 pg_ltoa(arg1, result);
281 PG_RETURN_CSTRING(result);
282 }
283
284 /*
285 * int4recv - converts external binary format to int4
286 */
287 Datum
int4recv(PG_FUNCTION_ARGS)288 int4recv(PG_FUNCTION_ARGS)
289 {
290 StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
291
292 PG_RETURN_INT32((int32) pq_getmsgint(buf, sizeof(int32)));
293 }
294
295 /*
296 * int4send - converts int4 to binary format
297 */
298 Datum
int4send(PG_FUNCTION_ARGS)299 int4send(PG_FUNCTION_ARGS)
300 {
301 int32 arg1 = PG_GETARG_INT32(0);
302 StringInfoData buf;
303
304 pq_begintypsend(&buf);
305 pq_sendint32(&buf, arg1);
306 PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
307 }
308
309
310 /*
311 * ===================
312 * CONVERSION ROUTINES
313 * ===================
314 */
315
316 Datum
i2toi4(PG_FUNCTION_ARGS)317 i2toi4(PG_FUNCTION_ARGS)
318 {
319 int16 arg1 = PG_GETARG_INT16(0);
320
321 PG_RETURN_INT32((int32) arg1);
322 }
323
324 Datum
i4toi2(PG_FUNCTION_ARGS)325 i4toi2(PG_FUNCTION_ARGS)
326 {
327 int32 arg1 = PG_GETARG_INT32(0);
328
329 if (unlikely(arg1 < SHRT_MIN) || unlikely(arg1 > SHRT_MAX))
330 ereport(ERROR,
331 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
332 errmsg("smallint out of range")));
333
334 PG_RETURN_INT16((int16) arg1);
335 }
336
337 /* Cast int4 -> bool */
338 Datum
int4_bool(PG_FUNCTION_ARGS)339 int4_bool(PG_FUNCTION_ARGS)
340 {
341 if (PG_GETARG_INT32(0) == 0)
342 PG_RETURN_BOOL(false);
343 else
344 PG_RETURN_BOOL(true);
345 }
346
347 /* Cast bool -> int4 */
348 Datum
bool_int4(PG_FUNCTION_ARGS)349 bool_int4(PG_FUNCTION_ARGS)
350 {
351 if (PG_GETARG_BOOL(0) == false)
352 PG_RETURN_INT32(0);
353 else
354 PG_RETURN_INT32(1);
355 }
356
357 /*
358 * ============================
359 * COMPARISON OPERATOR ROUTINES
360 * ============================
361 */
362
363 /*
364 * inteq - returns 1 iff arg1 == arg2
365 * intne - returns 1 iff arg1 != arg2
366 * intlt - returns 1 iff arg1 < arg2
367 * intle - returns 1 iff arg1 <= arg2
368 * intgt - returns 1 iff arg1 > arg2
369 * intge - returns 1 iff arg1 >= arg2
370 */
371
372 Datum
int4eq(PG_FUNCTION_ARGS)373 int4eq(PG_FUNCTION_ARGS)
374 {
375 int32 arg1 = PG_GETARG_INT32(0);
376 int32 arg2 = PG_GETARG_INT32(1);
377
378 PG_RETURN_BOOL(arg1 == arg2);
379 }
380
381 Datum
int4ne(PG_FUNCTION_ARGS)382 int4ne(PG_FUNCTION_ARGS)
383 {
384 int32 arg1 = PG_GETARG_INT32(0);
385 int32 arg2 = PG_GETARG_INT32(1);
386
387 PG_RETURN_BOOL(arg1 != arg2);
388 }
389
390 Datum
int4lt(PG_FUNCTION_ARGS)391 int4lt(PG_FUNCTION_ARGS)
392 {
393 int32 arg1 = PG_GETARG_INT32(0);
394 int32 arg2 = PG_GETARG_INT32(1);
395
396 PG_RETURN_BOOL(arg1 < arg2);
397 }
398
399 Datum
int4le(PG_FUNCTION_ARGS)400 int4le(PG_FUNCTION_ARGS)
401 {
402 int32 arg1 = PG_GETARG_INT32(0);
403 int32 arg2 = PG_GETARG_INT32(1);
404
405 PG_RETURN_BOOL(arg1 <= arg2);
406 }
407
408 Datum
int4gt(PG_FUNCTION_ARGS)409 int4gt(PG_FUNCTION_ARGS)
410 {
411 int32 arg1 = PG_GETARG_INT32(0);
412 int32 arg2 = PG_GETARG_INT32(1);
413
414 PG_RETURN_BOOL(arg1 > arg2);
415 }
416
417 Datum
int4ge(PG_FUNCTION_ARGS)418 int4ge(PG_FUNCTION_ARGS)
419 {
420 int32 arg1 = PG_GETARG_INT32(0);
421 int32 arg2 = PG_GETARG_INT32(1);
422
423 PG_RETURN_BOOL(arg1 >= arg2);
424 }
425
426 Datum
int2eq(PG_FUNCTION_ARGS)427 int2eq(PG_FUNCTION_ARGS)
428 {
429 int16 arg1 = PG_GETARG_INT16(0);
430 int16 arg2 = PG_GETARG_INT16(1);
431
432 PG_RETURN_BOOL(arg1 == arg2);
433 }
434
435 Datum
int2ne(PG_FUNCTION_ARGS)436 int2ne(PG_FUNCTION_ARGS)
437 {
438 int16 arg1 = PG_GETARG_INT16(0);
439 int16 arg2 = PG_GETARG_INT16(1);
440
441 PG_RETURN_BOOL(arg1 != arg2);
442 }
443
444 Datum
int2lt(PG_FUNCTION_ARGS)445 int2lt(PG_FUNCTION_ARGS)
446 {
447 int16 arg1 = PG_GETARG_INT16(0);
448 int16 arg2 = PG_GETARG_INT16(1);
449
450 PG_RETURN_BOOL(arg1 < arg2);
451 }
452
453 Datum
int2le(PG_FUNCTION_ARGS)454 int2le(PG_FUNCTION_ARGS)
455 {
456 int16 arg1 = PG_GETARG_INT16(0);
457 int16 arg2 = PG_GETARG_INT16(1);
458
459 PG_RETURN_BOOL(arg1 <= arg2);
460 }
461
462 Datum
int2gt(PG_FUNCTION_ARGS)463 int2gt(PG_FUNCTION_ARGS)
464 {
465 int16 arg1 = PG_GETARG_INT16(0);
466 int16 arg2 = PG_GETARG_INT16(1);
467
468 PG_RETURN_BOOL(arg1 > arg2);
469 }
470
471 Datum
int2ge(PG_FUNCTION_ARGS)472 int2ge(PG_FUNCTION_ARGS)
473 {
474 int16 arg1 = PG_GETARG_INT16(0);
475 int16 arg2 = PG_GETARG_INT16(1);
476
477 PG_RETURN_BOOL(arg1 >= arg2);
478 }
479
480 Datum
int24eq(PG_FUNCTION_ARGS)481 int24eq(PG_FUNCTION_ARGS)
482 {
483 int16 arg1 = PG_GETARG_INT16(0);
484 int32 arg2 = PG_GETARG_INT32(1);
485
486 PG_RETURN_BOOL(arg1 == arg2);
487 }
488
489 Datum
int24ne(PG_FUNCTION_ARGS)490 int24ne(PG_FUNCTION_ARGS)
491 {
492 int16 arg1 = PG_GETARG_INT16(0);
493 int32 arg2 = PG_GETARG_INT32(1);
494
495 PG_RETURN_BOOL(arg1 != arg2);
496 }
497
498 Datum
int24lt(PG_FUNCTION_ARGS)499 int24lt(PG_FUNCTION_ARGS)
500 {
501 int16 arg1 = PG_GETARG_INT16(0);
502 int32 arg2 = PG_GETARG_INT32(1);
503
504 PG_RETURN_BOOL(arg1 < arg2);
505 }
506
507 Datum
int24le(PG_FUNCTION_ARGS)508 int24le(PG_FUNCTION_ARGS)
509 {
510 int16 arg1 = PG_GETARG_INT16(0);
511 int32 arg2 = PG_GETARG_INT32(1);
512
513 PG_RETURN_BOOL(arg1 <= arg2);
514 }
515
516 Datum
int24gt(PG_FUNCTION_ARGS)517 int24gt(PG_FUNCTION_ARGS)
518 {
519 int16 arg1 = PG_GETARG_INT16(0);
520 int32 arg2 = PG_GETARG_INT32(1);
521
522 PG_RETURN_BOOL(arg1 > arg2);
523 }
524
525 Datum
int24ge(PG_FUNCTION_ARGS)526 int24ge(PG_FUNCTION_ARGS)
527 {
528 int16 arg1 = PG_GETARG_INT16(0);
529 int32 arg2 = PG_GETARG_INT32(1);
530
531 PG_RETURN_BOOL(arg1 >= arg2);
532 }
533
534 Datum
int42eq(PG_FUNCTION_ARGS)535 int42eq(PG_FUNCTION_ARGS)
536 {
537 int32 arg1 = PG_GETARG_INT32(0);
538 int16 arg2 = PG_GETARG_INT16(1);
539
540 PG_RETURN_BOOL(arg1 == arg2);
541 }
542
543 Datum
int42ne(PG_FUNCTION_ARGS)544 int42ne(PG_FUNCTION_ARGS)
545 {
546 int32 arg1 = PG_GETARG_INT32(0);
547 int16 arg2 = PG_GETARG_INT16(1);
548
549 PG_RETURN_BOOL(arg1 != arg2);
550 }
551
552 Datum
int42lt(PG_FUNCTION_ARGS)553 int42lt(PG_FUNCTION_ARGS)
554 {
555 int32 arg1 = PG_GETARG_INT32(0);
556 int16 arg2 = PG_GETARG_INT16(1);
557
558 PG_RETURN_BOOL(arg1 < arg2);
559 }
560
561 Datum
int42le(PG_FUNCTION_ARGS)562 int42le(PG_FUNCTION_ARGS)
563 {
564 int32 arg1 = PG_GETARG_INT32(0);
565 int16 arg2 = PG_GETARG_INT16(1);
566
567 PG_RETURN_BOOL(arg1 <= arg2);
568 }
569
570 Datum
int42gt(PG_FUNCTION_ARGS)571 int42gt(PG_FUNCTION_ARGS)
572 {
573 int32 arg1 = PG_GETARG_INT32(0);
574 int16 arg2 = PG_GETARG_INT16(1);
575
576 PG_RETURN_BOOL(arg1 > arg2);
577 }
578
579 Datum
int42ge(PG_FUNCTION_ARGS)580 int42ge(PG_FUNCTION_ARGS)
581 {
582 int32 arg1 = PG_GETARG_INT32(0);
583 int16 arg2 = PG_GETARG_INT16(1);
584
585 PG_RETURN_BOOL(arg1 >= arg2);
586 }
587
588
589 /*----------------------------------------------------------
590 * in_range functions for int4 and int2,
591 * including cross-data-type comparisons.
592 *
593 * Note: we provide separate intN_int8 functions for performance
594 * reasons. This forces also providing intN_int2, else cases with a
595 * smallint offset value would fail to resolve which function to use.
596 * But that's an unlikely situation, so don't duplicate code for it.
597 *---------------------------------------------------------*/
598
599 Datum
in_range_int4_int4(PG_FUNCTION_ARGS)600 in_range_int4_int4(PG_FUNCTION_ARGS)
601 {
602 int32 val = PG_GETARG_INT32(0);
603 int32 base = PG_GETARG_INT32(1);
604 int32 offset = PG_GETARG_INT32(2);
605 bool sub = PG_GETARG_BOOL(3);
606 bool less = PG_GETARG_BOOL(4);
607 int32 sum;
608
609 if (offset < 0)
610 ereport(ERROR,
611 (errcode(ERRCODE_INVALID_PRECEDING_OR_FOLLOWING_SIZE),
612 errmsg("invalid preceding or following size in window function")));
613
614 if (sub)
615 offset = -offset; /* cannot overflow */
616
617 if (unlikely(pg_add_s32_overflow(base, offset, &sum)))
618 {
619 /*
620 * If sub is false, the true sum is surely more than val, so correct
621 * answer is the same as "less". If sub is true, the true sum is
622 * surely less than val, so the answer is "!less".
623 */
624 PG_RETURN_BOOL(sub ? !less : less);
625 }
626
627 if (less)
628 PG_RETURN_BOOL(val <= sum);
629 else
630 PG_RETURN_BOOL(val >= sum);
631 }
632
633 Datum
in_range_int4_int2(PG_FUNCTION_ARGS)634 in_range_int4_int2(PG_FUNCTION_ARGS)
635 {
636 /* Doesn't seem worth duplicating code for, so just invoke int4_int4 */
637 return DirectFunctionCall5(in_range_int4_int4,
638 PG_GETARG_DATUM(0),
639 PG_GETARG_DATUM(1),
640 Int32GetDatum((int32) PG_GETARG_INT16(2)),
641 PG_GETARG_DATUM(3),
642 PG_GETARG_DATUM(4));
643 }
644
645 Datum
in_range_int4_int8(PG_FUNCTION_ARGS)646 in_range_int4_int8(PG_FUNCTION_ARGS)
647 {
648 /* We must do all the math in int64 */
649 int64 val = (int64) PG_GETARG_INT32(0);
650 int64 base = (int64) PG_GETARG_INT32(1);
651 int64 offset = PG_GETARG_INT64(2);
652 bool sub = PG_GETARG_BOOL(3);
653 bool less = PG_GETARG_BOOL(4);
654 int64 sum;
655
656 if (offset < 0)
657 ereport(ERROR,
658 (errcode(ERRCODE_INVALID_PRECEDING_OR_FOLLOWING_SIZE),
659 errmsg("invalid preceding or following size in window function")));
660
661 if (sub)
662 offset = -offset; /* cannot overflow */
663
664 if (unlikely(pg_add_s64_overflow(base, offset, &sum)))
665 {
666 /*
667 * If sub is false, the true sum is surely more than val, so correct
668 * answer is the same as "less". If sub is true, the true sum is
669 * surely less than val, so the answer is "!less".
670 */
671 PG_RETURN_BOOL(sub ? !less : less);
672 }
673
674 if (less)
675 PG_RETURN_BOOL(val <= sum);
676 else
677 PG_RETURN_BOOL(val >= sum);
678 }
679
680 Datum
in_range_int2_int4(PG_FUNCTION_ARGS)681 in_range_int2_int4(PG_FUNCTION_ARGS)
682 {
683 /* We must do all the math in int32 */
684 int32 val = (int32) PG_GETARG_INT16(0);
685 int32 base = (int32) PG_GETARG_INT16(1);
686 int32 offset = PG_GETARG_INT32(2);
687 bool sub = PG_GETARG_BOOL(3);
688 bool less = PG_GETARG_BOOL(4);
689 int32 sum;
690
691 if (offset < 0)
692 ereport(ERROR,
693 (errcode(ERRCODE_INVALID_PRECEDING_OR_FOLLOWING_SIZE),
694 errmsg("invalid preceding or following size in window function")));
695
696 if (sub)
697 offset = -offset; /* cannot overflow */
698
699 if (unlikely(pg_add_s32_overflow(base, offset, &sum)))
700 {
701 /*
702 * If sub is false, the true sum is surely more than val, so correct
703 * answer is the same as "less". If sub is true, the true sum is
704 * surely less than val, so the answer is "!less".
705 */
706 PG_RETURN_BOOL(sub ? !less : less);
707 }
708
709 if (less)
710 PG_RETURN_BOOL(val <= sum);
711 else
712 PG_RETURN_BOOL(val >= sum);
713 }
714
715 Datum
in_range_int2_int2(PG_FUNCTION_ARGS)716 in_range_int2_int2(PG_FUNCTION_ARGS)
717 {
718 /* Doesn't seem worth duplicating code for, so just invoke int2_int4 */
719 return DirectFunctionCall5(in_range_int2_int4,
720 PG_GETARG_DATUM(0),
721 PG_GETARG_DATUM(1),
722 Int32GetDatum((int32) PG_GETARG_INT16(2)),
723 PG_GETARG_DATUM(3),
724 PG_GETARG_DATUM(4));
725 }
726
727 Datum
in_range_int2_int8(PG_FUNCTION_ARGS)728 in_range_int2_int8(PG_FUNCTION_ARGS)
729 {
730 /* Doesn't seem worth duplicating code for, so just invoke int4_int8 */
731 return DirectFunctionCall5(in_range_int4_int8,
732 Int32GetDatum((int32) PG_GETARG_INT16(0)),
733 Int32GetDatum((int32) PG_GETARG_INT16(1)),
734 PG_GETARG_DATUM(2),
735 PG_GETARG_DATUM(3),
736 PG_GETARG_DATUM(4));
737 }
738
739
740 /*
741 * int[24]pl - returns arg1 + arg2
742 * int[24]mi - returns arg1 - arg2
743 * int[24]mul - returns arg1 * arg2
744 * int[24]div - returns arg1 / arg2
745 */
746
747 Datum
int4um(PG_FUNCTION_ARGS)748 int4um(PG_FUNCTION_ARGS)
749 {
750 int32 arg = PG_GETARG_INT32(0);
751
752 if (unlikely(arg == PG_INT32_MIN))
753 ereport(ERROR,
754 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
755 errmsg("integer out of range")));
756 PG_RETURN_INT32(-arg);
757 }
758
759 Datum
int4up(PG_FUNCTION_ARGS)760 int4up(PG_FUNCTION_ARGS)
761 {
762 int32 arg = PG_GETARG_INT32(0);
763
764 PG_RETURN_INT32(arg);
765 }
766
767 Datum
int4pl(PG_FUNCTION_ARGS)768 int4pl(PG_FUNCTION_ARGS)
769 {
770 int32 arg1 = PG_GETARG_INT32(0);
771 int32 arg2 = PG_GETARG_INT32(1);
772 int32 result;
773
774 if (unlikely(pg_add_s32_overflow(arg1, arg2, &result)))
775 ereport(ERROR,
776 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
777 errmsg("integer out of range")));
778 PG_RETURN_INT32(result);
779 }
780
781 Datum
int4mi(PG_FUNCTION_ARGS)782 int4mi(PG_FUNCTION_ARGS)
783 {
784 int32 arg1 = PG_GETARG_INT32(0);
785 int32 arg2 = PG_GETARG_INT32(1);
786 int32 result;
787
788 if (unlikely(pg_sub_s32_overflow(arg1, arg2, &result)))
789 ereport(ERROR,
790 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
791 errmsg("integer out of range")));
792 PG_RETURN_INT32(result);
793 }
794
795 Datum
int4mul(PG_FUNCTION_ARGS)796 int4mul(PG_FUNCTION_ARGS)
797 {
798 int32 arg1 = PG_GETARG_INT32(0);
799 int32 arg2 = PG_GETARG_INT32(1);
800 int32 result;
801
802 if (unlikely(pg_mul_s32_overflow(arg1, arg2, &result)))
803 ereport(ERROR,
804 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
805 errmsg("integer out of range")));
806 PG_RETURN_INT32(result);
807 }
808
809 Datum
int4div(PG_FUNCTION_ARGS)810 int4div(PG_FUNCTION_ARGS)
811 {
812 int32 arg1 = PG_GETARG_INT32(0);
813 int32 arg2 = PG_GETARG_INT32(1);
814 int32 result;
815
816 if (arg2 == 0)
817 {
818 ereport(ERROR,
819 (errcode(ERRCODE_DIVISION_BY_ZERO),
820 errmsg("division by zero")));
821 /* ensure compiler realizes we mustn't reach the division (gcc bug) */
822 PG_RETURN_NULL();
823 }
824
825 /*
826 * INT_MIN / -1 is problematic, since the result can't be represented on a
827 * two's-complement machine. Some machines produce INT_MIN, some produce
828 * zero, some throw an exception. We can dodge the problem by recognizing
829 * that division by -1 is the same as negation.
830 */
831 if (arg2 == -1)
832 {
833 if (unlikely(arg1 == PG_INT32_MIN))
834 ereport(ERROR,
835 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
836 errmsg("integer out of range")));
837 result = -arg1;
838 PG_RETURN_INT32(result);
839 }
840
841 /* No overflow is possible */
842
843 result = arg1 / arg2;
844
845 PG_RETURN_INT32(result);
846 }
847
848 Datum
int4inc(PG_FUNCTION_ARGS)849 int4inc(PG_FUNCTION_ARGS)
850 {
851 int32 arg = PG_GETARG_INT32(0);
852 int32 result;
853
854 if (unlikely(pg_add_s32_overflow(arg, 1, &result)))
855 ereport(ERROR,
856 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
857 errmsg("integer out of range")));
858
859 PG_RETURN_INT32(result);
860 }
861
862 Datum
int2um(PG_FUNCTION_ARGS)863 int2um(PG_FUNCTION_ARGS)
864 {
865 int16 arg = PG_GETARG_INT16(0);
866
867 if (unlikely(arg == PG_INT16_MIN))
868 ereport(ERROR,
869 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
870 errmsg("smallint out of range")));
871 PG_RETURN_INT16(-arg);
872 }
873
874 Datum
int2up(PG_FUNCTION_ARGS)875 int2up(PG_FUNCTION_ARGS)
876 {
877 int16 arg = PG_GETARG_INT16(0);
878
879 PG_RETURN_INT16(arg);
880 }
881
882 Datum
int2pl(PG_FUNCTION_ARGS)883 int2pl(PG_FUNCTION_ARGS)
884 {
885 int16 arg1 = PG_GETARG_INT16(0);
886 int16 arg2 = PG_GETARG_INT16(1);
887 int16 result;
888
889 if (unlikely(pg_add_s16_overflow(arg1, arg2, &result)))
890 ereport(ERROR,
891 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
892 errmsg("smallint out of range")));
893 PG_RETURN_INT16(result);
894 }
895
896 Datum
int2mi(PG_FUNCTION_ARGS)897 int2mi(PG_FUNCTION_ARGS)
898 {
899 int16 arg1 = PG_GETARG_INT16(0);
900 int16 arg2 = PG_GETARG_INT16(1);
901 int16 result;
902
903 if (unlikely(pg_sub_s16_overflow(arg1, arg2, &result)))
904 ereport(ERROR,
905 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
906 errmsg("smallint out of range")));
907 PG_RETURN_INT16(result);
908 }
909
910 Datum
int2mul(PG_FUNCTION_ARGS)911 int2mul(PG_FUNCTION_ARGS)
912 {
913 int16 arg1 = PG_GETARG_INT16(0);
914 int16 arg2 = PG_GETARG_INT16(1);
915 int16 result;
916
917 if (unlikely(pg_mul_s16_overflow(arg1, arg2, &result)))
918 ereport(ERROR,
919 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
920 errmsg("smallint out of range")));
921
922 PG_RETURN_INT16(result);
923 }
924
925 Datum
int2div(PG_FUNCTION_ARGS)926 int2div(PG_FUNCTION_ARGS)
927 {
928 int16 arg1 = PG_GETARG_INT16(0);
929 int16 arg2 = PG_GETARG_INT16(1);
930 int16 result;
931
932 if (arg2 == 0)
933 {
934 ereport(ERROR,
935 (errcode(ERRCODE_DIVISION_BY_ZERO),
936 errmsg("division by zero")));
937 /* ensure compiler realizes we mustn't reach the division (gcc bug) */
938 PG_RETURN_NULL();
939 }
940
941 /*
942 * SHRT_MIN / -1 is problematic, since the result can't be represented on
943 * a two's-complement machine. Some machines produce SHRT_MIN, some
944 * produce zero, some throw an exception. We can dodge the problem by
945 * recognizing that division by -1 is the same as negation.
946 */
947 if (arg2 == -1)
948 {
949 if (unlikely(arg1 == PG_INT16_MIN))
950 ereport(ERROR,
951 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
952 errmsg("smallint out of range")));
953 result = -arg1;
954 PG_RETURN_INT16(result);
955 }
956
957 /* No overflow is possible */
958
959 result = arg1 / arg2;
960
961 PG_RETURN_INT16(result);
962 }
963
964 Datum
int24pl(PG_FUNCTION_ARGS)965 int24pl(PG_FUNCTION_ARGS)
966 {
967 int16 arg1 = PG_GETARG_INT16(0);
968 int32 arg2 = PG_GETARG_INT32(1);
969 int32 result;
970
971 if (unlikely(pg_add_s32_overflow((int32) arg1, arg2, &result)))
972 ereport(ERROR,
973 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
974 errmsg("integer out of range")));
975 PG_RETURN_INT32(result);
976 }
977
978 Datum
int24mi(PG_FUNCTION_ARGS)979 int24mi(PG_FUNCTION_ARGS)
980 {
981 int16 arg1 = PG_GETARG_INT16(0);
982 int32 arg2 = PG_GETARG_INT32(1);
983 int32 result;
984
985 if (unlikely(pg_sub_s32_overflow((int32) arg1, arg2, &result)))
986 ereport(ERROR,
987 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
988 errmsg("integer out of range")));
989 PG_RETURN_INT32(result);
990 }
991
992 Datum
int24mul(PG_FUNCTION_ARGS)993 int24mul(PG_FUNCTION_ARGS)
994 {
995 int16 arg1 = PG_GETARG_INT16(0);
996 int32 arg2 = PG_GETARG_INT32(1);
997 int32 result;
998
999 if (unlikely(pg_mul_s32_overflow((int32) arg1, arg2, &result)))
1000 ereport(ERROR,
1001 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
1002 errmsg("integer out of range")));
1003 PG_RETURN_INT32(result);
1004 }
1005
1006 Datum
int24div(PG_FUNCTION_ARGS)1007 int24div(PG_FUNCTION_ARGS)
1008 {
1009 int16 arg1 = PG_GETARG_INT16(0);
1010 int32 arg2 = PG_GETARG_INT32(1);
1011
1012 if (unlikely(arg2 == 0))
1013 {
1014 ereport(ERROR,
1015 (errcode(ERRCODE_DIVISION_BY_ZERO),
1016 errmsg("division by zero")));
1017 /* ensure compiler realizes we mustn't reach the division (gcc bug) */
1018 PG_RETURN_NULL();
1019 }
1020
1021 /* No overflow is possible */
1022 PG_RETURN_INT32((int32) arg1 / arg2);
1023 }
1024
1025 Datum
int42pl(PG_FUNCTION_ARGS)1026 int42pl(PG_FUNCTION_ARGS)
1027 {
1028 int32 arg1 = PG_GETARG_INT32(0);
1029 int16 arg2 = PG_GETARG_INT16(1);
1030 int32 result;
1031
1032 if (unlikely(pg_add_s32_overflow(arg1, (int32) arg2, &result)))
1033 ereport(ERROR,
1034 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
1035 errmsg("integer out of range")));
1036 PG_RETURN_INT32(result);
1037 }
1038
1039 Datum
int42mi(PG_FUNCTION_ARGS)1040 int42mi(PG_FUNCTION_ARGS)
1041 {
1042 int32 arg1 = PG_GETARG_INT32(0);
1043 int16 arg2 = PG_GETARG_INT16(1);
1044 int32 result;
1045
1046 if (unlikely(pg_sub_s32_overflow(arg1, (int32) arg2, &result)))
1047 ereport(ERROR,
1048 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
1049 errmsg("integer out of range")));
1050 PG_RETURN_INT32(result);
1051 }
1052
1053 Datum
int42mul(PG_FUNCTION_ARGS)1054 int42mul(PG_FUNCTION_ARGS)
1055 {
1056 int32 arg1 = PG_GETARG_INT32(0);
1057 int16 arg2 = PG_GETARG_INT16(1);
1058 int32 result;
1059
1060 if (unlikely(pg_mul_s32_overflow(arg1, (int32) arg2, &result)))
1061 ereport(ERROR,
1062 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
1063 errmsg("integer out of range")));
1064 PG_RETURN_INT32(result);
1065 }
1066
1067 Datum
int42div(PG_FUNCTION_ARGS)1068 int42div(PG_FUNCTION_ARGS)
1069 {
1070 int32 arg1 = PG_GETARG_INT32(0);
1071 int16 arg2 = PG_GETARG_INT16(1);
1072 int32 result;
1073
1074 if (unlikely(arg2 == 0))
1075 {
1076 ereport(ERROR,
1077 (errcode(ERRCODE_DIVISION_BY_ZERO),
1078 errmsg("division by zero")));
1079 /* ensure compiler realizes we mustn't reach the division (gcc bug) */
1080 PG_RETURN_NULL();
1081 }
1082
1083 /*
1084 * INT_MIN / -1 is problematic, since the result can't be represented on a
1085 * two's-complement machine. Some machines produce INT_MIN, some produce
1086 * zero, some throw an exception. We can dodge the problem by recognizing
1087 * that division by -1 is the same as negation.
1088 */
1089 if (arg2 == -1)
1090 {
1091 if (unlikely(arg1 == PG_INT32_MIN))
1092 ereport(ERROR,
1093 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
1094 errmsg("integer out of range")));
1095 result = -arg1;
1096 PG_RETURN_INT32(result);
1097 }
1098
1099 /* No overflow is possible */
1100
1101 result = arg1 / arg2;
1102
1103 PG_RETURN_INT32(result);
1104 }
1105
1106 Datum
int4mod(PG_FUNCTION_ARGS)1107 int4mod(PG_FUNCTION_ARGS)
1108 {
1109 int32 arg1 = PG_GETARG_INT32(0);
1110 int32 arg2 = PG_GETARG_INT32(1);
1111
1112 if (unlikely(arg2 == 0))
1113 {
1114 ereport(ERROR,
1115 (errcode(ERRCODE_DIVISION_BY_ZERO),
1116 errmsg("division by zero")));
1117 /* ensure compiler realizes we mustn't reach the division (gcc bug) */
1118 PG_RETURN_NULL();
1119 }
1120
1121 /*
1122 * Some machines throw a floating-point exception for INT_MIN % -1, which
1123 * is a bit silly since the correct answer is perfectly well-defined,
1124 * namely zero.
1125 */
1126 if (arg2 == -1)
1127 PG_RETURN_INT32(0);
1128
1129 /* No overflow is possible */
1130
1131 PG_RETURN_INT32(arg1 % arg2);
1132 }
1133
1134 Datum
int2mod(PG_FUNCTION_ARGS)1135 int2mod(PG_FUNCTION_ARGS)
1136 {
1137 int16 arg1 = PG_GETARG_INT16(0);
1138 int16 arg2 = PG_GETARG_INT16(1);
1139
1140 if (unlikely(arg2 == 0))
1141 {
1142 ereport(ERROR,
1143 (errcode(ERRCODE_DIVISION_BY_ZERO),
1144 errmsg("division by zero")));
1145 /* ensure compiler realizes we mustn't reach the division (gcc bug) */
1146 PG_RETURN_NULL();
1147 }
1148
1149 /*
1150 * Some machines throw a floating-point exception for INT_MIN % -1, which
1151 * is a bit silly since the correct answer is perfectly well-defined,
1152 * namely zero. (It's not clear this ever happens when dealing with
1153 * int16, but we might as well have the test for safety.)
1154 */
1155 if (arg2 == -1)
1156 PG_RETURN_INT16(0);
1157
1158 /* No overflow is possible */
1159
1160 PG_RETURN_INT16(arg1 % arg2);
1161 }
1162
1163
1164 /* int[24]abs()
1165 * Absolute value
1166 */
1167 Datum
int4abs(PG_FUNCTION_ARGS)1168 int4abs(PG_FUNCTION_ARGS)
1169 {
1170 int32 arg1 = PG_GETARG_INT32(0);
1171 int32 result;
1172
1173 if (unlikely(arg1 == PG_INT32_MIN))
1174 ereport(ERROR,
1175 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
1176 errmsg("integer out of range")));
1177 result = (arg1 < 0) ? -arg1 : arg1;
1178 PG_RETURN_INT32(result);
1179 }
1180
1181 Datum
int2abs(PG_FUNCTION_ARGS)1182 int2abs(PG_FUNCTION_ARGS)
1183 {
1184 int16 arg1 = PG_GETARG_INT16(0);
1185 int16 result;
1186
1187 if (unlikely(arg1 == PG_INT16_MIN))
1188 ereport(ERROR,
1189 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
1190 errmsg("smallint out of range")));
1191 result = (arg1 < 0) ? -arg1 : arg1;
1192 PG_RETURN_INT16(result);
1193 }
1194
1195 Datum
int2larger(PG_FUNCTION_ARGS)1196 int2larger(PG_FUNCTION_ARGS)
1197 {
1198 int16 arg1 = PG_GETARG_INT16(0);
1199 int16 arg2 = PG_GETARG_INT16(1);
1200
1201 PG_RETURN_INT16((arg1 > arg2) ? arg1 : arg2);
1202 }
1203
1204 Datum
int2smaller(PG_FUNCTION_ARGS)1205 int2smaller(PG_FUNCTION_ARGS)
1206 {
1207 int16 arg1 = PG_GETARG_INT16(0);
1208 int16 arg2 = PG_GETARG_INT16(1);
1209
1210 PG_RETURN_INT16((arg1 < arg2) ? arg1 : arg2);
1211 }
1212
1213 Datum
int4larger(PG_FUNCTION_ARGS)1214 int4larger(PG_FUNCTION_ARGS)
1215 {
1216 int32 arg1 = PG_GETARG_INT32(0);
1217 int32 arg2 = PG_GETARG_INT32(1);
1218
1219 PG_RETURN_INT32((arg1 > arg2) ? arg1 : arg2);
1220 }
1221
1222 Datum
int4smaller(PG_FUNCTION_ARGS)1223 int4smaller(PG_FUNCTION_ARGS)
1224 {
1225 int32 arg1 = PG_GETARG_INT32(0);
1226 int32 arg2 = PG_GETARG_INT32(1);
1227
1228 PG_RETURN_INT32((arg1 < arg2) ? arg1 : arg2);
1229 }
1230
1231 /*
1232 * Bit-pushing operators
1233 *
1234 * int[24]and - returns arg1 & arg2
1235 * int[24]or - returns arg1 | arg2
1236 * int[24]xor - returns arg1 # arg2
1237 * int[24]not - returns ~arg1
1238 * int[24]shl - returns arg1 << arg2
1239 * int[24]shr - returns arg1 >> arg2
1240 */
1241
1242 Datum
int4and(PG_FUNCTION_ARGS)1243 int4and(PG_FUNCTION_ARGS)
1244 {
1245 int32 arg1 = PG_GETARG_INT32(0);
1246 int32 arg2 = PG_GETARG_INT32(1);
1247
1248 PG_RETURN_INT32(arg1 & arg2);
1249 }
1250
1251 Datum
int4or(PG_FUNCTION_ARGS)1252 int4or(PG_FUNCTION_ARGS)
1253 {
1254 int32 arg1 = PG_GETARG_INT32(0);
1255 int32 arg2 = PG_GETARG_INT32(1);
1256
1257 PG_RETURN_INT32(arg1 | arg2);
1258 }
1259
1260 Datum
int4xor(PG_FUNCTION_ARGS)1261 int4xor(PG_FUNCTION_ARGS)
1262 {
1263 int32 arg1 = PG_GETARG_INT32(0);
1264 int32 arg2 = PG_GETARG_INT32(1);
1265
1266 PG_RETURN_INT32(arg1 ^ arg2);
1267 }
1268
1269 Datum
int4shl(PG_FUNCTION_ARGS)1270 int4shl(PG_FUNCTION_ARGS)
1271 {
1272 int32 arg1 = PG_GETARG_INT32(0);
1273 int32 arg2 = PG_GETARG_INT32(1);
1274
1275 PG_RETURN_INT32(arg1 << arg2);
1276 }
1277
1278 Datum
int4shr(PG_FUNCTION_ARGS)1279 int4shr(PG_FUNCTION_ARGS)
1280 {
1281 int32 arg1 = PG_GETARG_INT32(0);
1282 int32 arg2 = PG_GETARG_INT32(1);
1283
1284 PG_RETURN_INT32(arg1 >> arg2);
1285 }
1286
1287 Datum
int4not(PG_FUNCTION_ARGS)1288 int4not(PG_FUNCTION_ARGS)
1289 {
1290 int32 arg1 = PG_GETARG_INT32(0);
1291
1292 PG_RETURN_INT32(~arg1);
1293 }
1294
1295 Datum
int2and(PG_FUNCTION_ARGS)1296 int2and(PG_FUNCTION_ARGS)
1297 {
1298 int16 arg1 = PG_GETARG_INT16(0);
1299 int16 arg2 = PG_GETARG_INT16(1);
1300
1301 PG_RETURN_INT16(arg1 & arg2);
1302 }
1303
1304 Datum
int2or(PG_FUNCTION_ARGS)1305 int2or(PG_FUNCTION_ARGS)
1306 {
1307 int16 arg1 = PG_GETARG_INT16(0);
1308 int16 arg2 = PG_GETARG_INT16(1);
1309
1310 PG_RETURN_INT16(arg1 | arg2);
1311 }
1312
1313 Datum
int2xor(PG_FUNCTION_ARGS)1314 int2xor(PG_FUNCTION_ARGS)
1315 {
1316 int16 arg1 = PG_GETARG_INT16(0);
1317 int16 arg2 = PG_GETARG_INT16(1);
1318
1319 PG_RETURN_INT16(arg1 ^ arg2);
1320 }
1321
1322 Datum
int2not(PG_FUNCTION_ARGS)1323 int2not(PG_FUNCTION_ARGS)
1324 {
1325 int16 arg1 = PG_GETARG_INT16(0);
1326
1327 PG_RETURN_INT16(~arg1);
1328 }
1329
1330
1331 Datum
int2shl(PG_FUNCTION_ARGS)1332 int2shl(PG_FUNCTION_ARGS)
1333 {
1334 int16 arg1 = PG_GETARG_INT16(0);
1335 int32 arg2 = PG_GETARG_INT32(1);
1336
1337 PG_RETURN_INT16(arg1 << arg2);
1338 }
1339
1340 Datum
int2shr(PG_FUNCTION_ARGS)1341 int2shr(PG_FUNCTION_ARGS)
1342 {
1343 int16 arg1 = PG_GETARG_INT16(0);
1344 int32 arg2 = PG_GETARG_INT32(1);
1345
1346 PG_RETURN_INT16(arg1 >> arg2);
1347 }
1348
1349 /*
1350 * non-persistent numeric series generator
1351 */
1352 Datum
generate_series_int4(PG_FUNCTION_ARGS)1353 generate_series_int4(PG_FUNCTION_ARGS)
1354 {
1355 return generate_series_step_int4(fcinfo);
1356 }
1357
1358 Datum
generate_series_step_int4(PG_FUNCTION_ARGS)1359 generate_series_step_int4(PG_FUNCTION_ARGS)
1360 {
1361 FuncCallContext *funcctx;
1362 generate_series_fctx *fctx;
1363 int32 result;
1364 MemoryContext oldcontext;
1365
1366 /* stuff done only on the first call of the function */
1367 if (SRF_IS_FIRSTCALL())
1368 {
1369 int32 start = PG_GETARG_INT32(0);
1370 int32 finish = PG_GETARG_INT32(1);
1371 int32 step = 1;
1372
1373 /* see if we were given an explicit step size */
1374 if (PG_NARGS() == 3)
1375 step = PG_GETARG_INT32(2);
1376 if (step == 0)
1377 ereport(ERROR,
1378 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1379 errmsg("step size cannot equal zero")));
1380
1381 /* create a function context for cross-call persistence */
1382 funcctx = SRF_FIRSTCALL_INIT();
1383
1384 /*
1385 * switch to memory context appropriate for multiple function calls
1386 */
1387 oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
1388
1389 /* allocate memory for user context */
1390 fctx = (generate_series_fctx *) palloc(sizeof(generate_series_fctx));
1391
1392 /*
1393 * Use fctx to keep state from call to call. Seed current with the
1394 * original start value
1395 */
1396 fctx->current = start;
1397 fctx->finish = finish;
1398 fctx->step = step;
1399
1400 funcctx->user_fctx = fctx;
1401 MemoryContextSwitchTo(oldcontext);
1402 }
1403
1404 /* stuff done on every call of the function */
1405 funcctx = SRF_PERCALL_SETUP();
1406
1407 /*
1408 * get the saved state and use current as the result for this iteration
1409 */
1410 fctx = funcctx->user_fctx;
1411 result = fctx->current;
1412
1413 if ((fctx->step > 0 && fctx->current <= fctx->finish) ||
1414 (fctx->step < 0 && fctx->current >= fctx->finish))
1415 {
1416 /*
1417 * Increment current in preparation for next iteration. If next-value
1418 * computation overflows, this is the final result.
1419 */
1420 if (pg_add_s32_overflow(fctx->current, fctx->step, &fctx->current))
1421 fctx->step = 0;
1422
1423 /* do when there is more left to send */
1424 SRF_RETURN_NEXT(funcctx, Int32GetDatum(result));
1425 }
1426 else
1427 /* do when there is no more left */
1428 SRF_RETURN_DONE(funcctx);
1429 }
1430