1 | /*------------------------------------------------------------------------- |
2 | * |
3 | * int8.c |
4 | * Internal 64-bit integer operations |
5 | * |
6 | * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group |
7 | * Portions Copyright (c) 1994, Regents of the University of California |
8 | * |
9 | * IDENTIFICATION |
10 | * src/backend/utils/adt/int8.c |
11 | * |
12 | *------------------------------------------------------------------------- |
13 | */ |
14 | #include "postgres.h" |
15 | |
16 | #include <ctype.h> |
17 | #include <limits.h> |
18 | #include <math.h> |
19 | |
20 | #include "common/int.h" |
21 | #include "funcapi.h" |
22 | #include "libpq/pqformat.h" |
23 | #include "nodes/nodeFuncs.h" |
24 | #include "nodes/supportnodes.h" |
25 | #include "optimizer/optimizer.h" |
26 | #include "utils/int8.h" |
27 | #include "utils/builtins.h" |
28 | |
29 | |
30 | #define MAXINT8LEN 25 |
31 | |
32 | typedef struct |
33 | { |
34 | int64 current; |
35 | int64 finish; |
36 | int64 step; |
37 | } generate_series_fctx; |
38 | |
39 | |
40 | /*********************************************************************** |
41 | ** |
42 | ** Routines for 64-bit integers. |
43 | ** |
44 | ***********************************************************************/ |
45 | |
46 | /*---------------------------------------------------------- |
47 | * Formatting and conversion routines. |
48 | *---------------------------------------------------------*/ |
49 | |
50 | /* |
51 | * scanint8 --- try to parse a string into an int8. |
52 | * |
53 | * If errorOK is false, ereport a useful error message if the string is bad. |
54 | * If errorOK is true, just return "false" for bad input. |
55 | */ |
56 | bool |
57 | scanint8(const char *str, bool errorOK, int64 *result) |
58 | { |
59 | const char *ptr = str; |
60 | int64 tmp = 0; |
61 | bool neg = false; |
62 | |
63 | /* |
64 | * Do our own scan, rather than relying on sscanf which might be broken |
65 | * for long long. |
66 | * |
67 | * As INT64_MIN can't be stored as a positive 64 bit integer, accumulate |
68 | * value as a negative number. |
69 | */ |
70 | |
71 | /* skip leading spaces */ |
72 | while (*ptr && isspace((unsigned char) *ptr)) |
73 | ptr++; |
74 | |
75 | /* handle sign */ |
76 | if (*ptr == '-') |
77 | { |
78 | ptr++; |
79 | neg = true; |
80 | } |
81 | else if (*ptr == '+') |
82 | ptr++; |
83 | |
84 | /* require at least one digit */ |
85 | if (unlikely(!isdigit((unsigned char) *ptr))) |
86 | goto invalid_syntax; |
87 | |
88 | /* process digits */ |
89 | while (*ptr && isdigit((unsigned char) *ptr)) |
90 | { |
91 | int8 digit = (*ptr++ - '0'); |
92 | |
93 | if (unlikely(pg_mul_s64_overflow(tmp, 10, &tmp)) || |
94 | unlikely(pg_sub_s64_overflow(tmp, digit, &tmp))) |
95 | goto out_of_range; |
96 | } |
97 | |
98 | /* allow trailing whitespace, but not other trailing chars */ |
99 | while (*ptr != '\0' && isspace((unsigned char) *ptr)) |
100 | ptr++; |
101 | |
102 | if (unlikely(*ptr != '\0')) |
103 | goto invalid_syntax; |
104 | |
105 | if (!neg) |
106 | { |
107 | /* could fail if input is most negative number */ |
108 | if (unlikely(tmp == PG_INT64_MIN)) |
109 | goto out_of_range; |
110 | tmp = -tmp; |
111 | } |
112 | |
113 | *result = tmp; |
114 | return true; |
115 | |
116 | out_of_range: |
117 | if (!errorOK) |
118 | ereport(ERROR, |
119 | (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), |
120 | errmsg("value \"%s\" is out of range for type %s" , |
121 | str, "bigint" ))); |
122 | return false; |
123 | |
124 | invalid_syntax: |
125 | if (!errorOK) |
126 | ereport(ERROR, |
127 | (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), |
128 | errmsg("invalid input syntax for type %s: \"%s\"" , |
129 | "bigint" , str))); |
130 | return false; |
131 | } |
132 | |
133 | /* int8in() |
134 | */ |
135 | Datum |
136 | int8in(PG_FUNCTION_ARGS) |
137 | { |
138 | char *str = PG_GETARG_CSTRING(0); |
139 | int64 result; |
140 | |
141 | (void) scanint8(str, false, &result); |
142 | PG_RETURN_INT64(result); |
143 | } |
144 | |
145 | |
146 | /* int8out() |
147 | */ |
148 | Datum |
149 | int8out(PG_FUNCTION_ARGS) |
150 | { |
151 | int64 val = PG_GETARG_INT64(0); |
152 | char buf[MAXINT8LEN + 1]; |
153 | char *result; |
154 | |
155 | pg_lltoa(val, buf); |
156 | result = pstrdup(buf); |
157 | PG_RETURN_CSTRING(result); |
158 | } |
159 | |
160 | /* |
161 | * int8recv - converts external binary format to int8 |
162 | */ |
163 | Datum |
164 | int8recv(PG_FUNCTION_ARGS) |
165 | { |
166 | StringInfo buf = (StringInfo) PG_GETARG_POINTER(0); |
167 | |
168 | PG_RETURN_INT64(pq_getmsgint64(buf)); |
169 | } |
170 | |
171 | /* |
172 | * int8send - converts int8 to binary format |
173 | */ |
174 | Datum |
175 | int8send(PG_FUNCTION_ARGS) |
176 | { |
177 | int64 arg1 = PG_GETARG_INT64(0); |
178 | StringInfoData buf; |
179 | |
180 | pq_begintypsend(&buf); |
181 | pq_sendint64(&buf, arg1); |
182 | PG_RETURN_BYTEA_P(pq_endtypsend(&buf)); |
183 | } |
184 | |
185 | |
186 | /*---------------------------------------------------------- |
187 | * Relational operators for int8s, including cross-data-type comparisons. |
188 | *---------------------------------------------------------*/ |
189 | |
190 | /* int8relop() |
191 | * Is val1 relop val2? |
192 | */ |
193 | Datum |
194 | int8eq(PG_FUNCTION_ARGS) |
195 | { |
196 | int64 val1 = PG_GETARG_INT64(0); |
197 | int64 val2 = PG_GETARG_INT64(1); |
198 | |
199 | PG_RETURN_BOOL(val1 == val2); |
200 | } |
201 | |
202 | Datum |
203 | int8ne(PG_FUNCTION_ARGS) |
204 | { |
205 | int64 val1 = PG_GETARG_INT64(0); |
206 | int64 val2 = PG_GETARG_INT64(1); |
207 | |
208 | PG_RETURN_BOOL(val1 != val2); |
209 | } |
210 | |
211 | Datum |
212 | int8lt(PG_FUNCTION_ARGS) |
213 | { |
214 | int64 val1 = PG_GETARG_INT64(0); |
215 | int64 val2 = PG_GETARG_INT64(1); |
216 | |
217 | PG_RETURN_BOOL(val1 < val2); |
218 | } |
219 | |
220 | Datum |
221 | int8gt(PG_FUNCTION_ARGS) |
222 | { |
223 | int64 val1 = PG_GETARG_INT64(0); |
224 | int64 val2 = PG_GETARG_INT64(1); |
225 | |
226 | PG_RETURN_BOOL(val1 > val2); |
227 | } |
228 | |
229 | Datum |
230 | int8le(PG_FUNCTION_ARGS) |
231 | { |
232 | int64 val1 = PG_GETARG_INT64(0); |
233 | int64 val2 = PG_GETARG_INT64(1); |
234 | |
235 | PG_RETURN_BOOL(val1 <= val2); |
236 | } |
237 | |
238 | Datum |
239 | int8ge(PG_FUNCTION_ARGS) |
240 | { |
241 | int64 val1 = PG_GETARG_INT64(0); |
242 | int64 val2 = PG_GETARG_INT64(1); |
243 | |
244 | PG_RETURN_BOOL(val1 >= val2); |
245 | } |
246 | |
247 | /* int84relop() |
248 | * Is 64-bit val1 relop 32-bit val2? |
249 | */ |
250 | Datum |
251 | int84eq(PG_FUNCTION_ARGS) |
252 | { |
253 | int64 val1 = PG_GETARG_INT64(0); |
254 | int32 val2 = PG_GETARG_INT32(1); |
255 | |
256 | PG_RETURN_BOOL(val1 == val2); |
257 | } |
258 | |
259 | Datum |
260 | int84ne(PG_FUNCTION_ARGS) |
261 | { |
262 | int64 val1 = PG_GETARG_INT64(0); |
263 | int32 val2 = PG_GETARG_INT32(1); |
264 | |
265 | PG_RETURN_BOOL(val1 != val2); |
266 | } |
267 | |
268 | Datum |
269 | int84lt(PG_FUNCTION_ARGS) |
270 | { |
271 | int64 val1 = PG_GETARG_INT64(0); |
272 | int32 val2 = PG_GETARG_INT32(1); |
273 | |
274 | PG_RETURN_BOOL(val1 < val2); |
275 | } |
276 | |
277 | Datum |
278 | int84gt(PG_FUNCTION_ARGS) |
279 | { |
280 | int64 val1 = PG_GETARG_INT64(0); |
281 | int32 val2 = PG_GETARG_INT32(1); |
282 | |
283 | PG_RETURN_BOOL(val1 > val2); |
284 | } |
285 | |
286 | Datum |
287 | int84le(PG_FUNCTION_ARGS) |
288 | { |
289 | int64 val1 = PG_GETARG_INT64(0); |
290 | int32 val2 = PG_GETARG_INT32(1); |
291 | |
292 | PG_RETURN_BOOL(val1 <= val2); |
293 | } |
294 | |
295 | Datum |
296 | int84ge(PG_FUNCTION_ARGS) |
297 | { |
298 | int64 val1 = PG_GETARG_INT64(0); |
299 | int32 val2 = PG_GETARG_INT32(1); |
300 | |
301 | PG_RETURN_BOOL(val1 >= val2); |
302 | } |
303 | |
304 | /* int48relop() |
305 | * Is 32-bit val1 relop 64-bit val2? |
306 | */ |
307 | Datum |
308 | int48eq(PG_FUNCTION_ARGS) |
309 | { |
310 | int32 val1 = PG_GETARG_INT32(0); |
311 | int64 val2 = PG_GETARG_INT64(1); |
312 | |
313 | PG_RETURN_BOOL(val1 == val2); |
314 | } |
315 | |
316 | Datum |
317 | int48ne(PG_FUNCTION_ARGS) |
318 | { |
319 | int32 val1 = PG_GETARG_INT32(0); |
320 | int64 val2 = PG_GETARG_INT64(1); |
321 | |
322 | PG_RETURN_BOOL(val1 != val2); |
323 | } |
324 | |
325 | Datum |
326 | int48lt(PG_FUNCTION_ARGS) |
327 | { |
328 | int32 val1 = PG_GETARG_INT32(0); |
329 | int64 val2 = PG_GETARG_INT64(1); |
330 | |
331 | PG_RETURN_BOOL(val1 < val2); |
332 | } |
333 | |
334 | Datum |
335 | int48gt(PG_FUNCTION_ARGS) |
336 | { |
337 | int32 val1 = PG_GETARG_INT32(0); |
338 | int64 val2 = PG_GETARG_INT64(1); |
339 | |
340 | PG_RETURN_BOOL(val1 > val2); |
341 | } |
342 | |
343 | Datum |
344 | int48le(PG_FUNCTION_ARGS) |
345 | { |
346 | int32 val1 = PG_GETARG_INT32(0); |
347 | int64 val2 = PG_GETARG_INT64(1); |
348 | |
349 | PG_RETURN_BOOL(val1 <= val2); |
350 | } |
351 | |
352 | Datum |
353 | int48ge(PG_FUNCTION_ARGS) |
354 | { |
355 | int32 val1 = PG_GETARG_INT32(0); |
356 | int64 val2 = PG_GETARG_INT64(1); |
357 | |
358 | PG_RETURN_BOOL(val1 >= val2); |
359 | } |
360 | |
361 | /* int82relop() |
362 | * Is 64-bit val1 relop 16-bit val2? |
363 | */ |
364 | Datum |
365 | int82eq(PG_FUNCTION_ARGS) |
366 | { |
367 | int64 val1 = PG_GETARG_INT64(0); |
368 | int16 val2 = PG_GETARG_INT16(1); |
369 | |
370 | PG_RETURN_BOOL(val1 == val2); |
371 | } |
372 | |
373 | Datum |
374 | int82ne(PG_FUNCTION_ARGS) |
375 | { |
376 | int64 val1 = PG_GETARG_INT64(0); |
377 | int16 val2 = PG_GETARG_INT16(1); |
378 | |
379 | PG_RETURN_BOOL(val1 != val2); |
380 | } |
381 | |
382 | Datum |
383 | int82lt(PG_FUNCTION_ARGS) |
384 | { |
385 | int64 val1 = PG_GETARG_INT64(0); |
386 | int16 val2 = PG_GETARG_INT16(1); |
387 | |
388 | PG_RETURN_BOOL(val1 < val2); |
389 | } |
390 | |
391 | Datum |
392 | int82gt(PG_FUNCTION_ARGS) |
393 | { |
394 | int64 val1 = PG_GETARG_INT64(0); |
395 | int16 val2 = PG_GETARG_INT16(1); |
396 | |
397 | PG_RETURN_BOOL(val1 > val2); |
398 | } |
399 | |
400 | Datum |
401 | int82le(PG_FUNCTION_ARGS) |
402 | { |
403 | int64 val1 = PG_GETARG_INT64(0); |
404 | int16 val2 = PG_GETARG_INT16(1); |
405 | |
406 | PG_RETURN_BOOL(val1 <= val2); |
407 | } |
408 | |
409 | Datum |
410 | int82ge(PG_FUNCTION_ARGS) |
411 | { |
412 | int64 val1 = PG_GETARG_INT64(0); |
413 | int16 val2 = PG_GETARG_INT16(1); |
414 | |
415 | PG_RETURN_BOOL(val1 >= val2); |
416 | } |
417 | |
418 | /* int28relop() |
419 | * Is 16-bit val1 relop 64-bit val2? |
420 | */ |
421 | Datum |
422 | int28eq(PG_FUNCTION_ARGS) |
423 | { |
424 | int16 val1 = PG_GETARG_INT16(0); |
425 | int64 val2 = PG_GETARG_INT64(1); |
426 | |
427 | PG_RETURN_BOOL(val1 == val2); |
428 | } |
429 | |
430 | Datum |
431 | int28ne(PG_FUNCTION_ARGS) |
432 | { |
433 | int16 val1 = PG_GETARG_INT16(0); |
434 | int64 val2 = PG_GETARG_INT64(1); |
435 | |
436 | PG_RETURN_BOOL(val1 != val2); |
437 | } |
438 | |
439 | Datum |
440 | int28lt(PG_FUNCTION_ARGS) |
441 | { |
442 | int16 val1 = PG_GETARG_INT16(0); |
443 | int64 val2 = PG_GETARG_INT64(1); |
444 | |
445 | PG_RETURN_BOOL(val1 < val2); |
446 | } |
447 | |
448 | Datum |
449 | int28gt(PG_FUNCTION_ARGS) |
450 | { |
451 | int16 val1 = PG_GETARG_INT16(0); |
452 | int64 val2 = PG_GETARG_INT64(1); |
453 | |
454 | PG_RETURN_BOOL(val1 > val2); |
455 | } |
456 | |
457 | Datum |
458 | int28le(PG_FUNCTION_ARGS) |
459 | { |
460 | int16 val1 = PG_GETARG_INT16(0); |
461 | int64 val2 = PG_GETARG_INT64(1); |
462 | |
463 | PG_RETURN_BOOL(val1 <= val2); |
464 | } |
465 | |
466 | Datum |
467 | int28ge(PG_FUNCTION_ARGS) |
468 | { |
469 | int16 val1 = PG_GETARG_INT16(0); |
470 | int64 val2 = PG_GETARG_INT64(1); |
471 | |
472 | PG_RETURN_BOOL(val1 >= val2); |
473 | } |
474 | |
475 | /* |
476 | * in_range support function for int8. |
477 | * |
478 | * Note: we needn't supply int8_int4 or int8_int2 variants, as implicit |
479 | * coercion of the offset value takes care of those scenarios just as well. |
480 | */ |
481 | Datum |
482 | in_range_int8_int8(PG_FUNCTION_ARGS) |
483 | { |
484 | int64 val = PG_GETARG_INT64(0); |
485 | int64 base = PG_GETARG_INT64(1); |
486 | int64 offset = PG_GETARG_INT64(2); |
487 | bool sub = PG_GETARG_BOOL(3); |
488 | bool less = PG_GETARG_BOOL(4); |
489 | int64 sum; |
490 | |
491 | if (offset < 0) |
492 | ereport(ERROR, |
493 | (errcode(ERRCODE_INVALID_PRECEDING_OR_FOLLOWING_SIZE), |
494 | errmsg("invalid preceding or following size in window function" ))); |
495 | |
496 | if (sub) |
497 | offset = -offset; /* cannot overflow */ |
498 | |
499 | if (unlikely(pg_add_s64_overflow(base, offset, &sum))) |
500 | { |
501 | /* |
502 | * If sub is false, the true sum is surely more than val, so correct |
503 | * answer is the same as "less". If sub is true, the true sum is |
504 | * surely less than val, so the answer is "!less". |
505 | */ |
506 | PG_RETURN_BOOL(sub ? !less : less); |
507 | } |
508 | |
509 | if (less) |
510 | PG_RETURN_BOOL(val <= sum); |
511 | else |
512 | PG_RETURN_BOOL(val >= sum); |
513 | } |
514 | |
515 | |
516 | /*---------------------------------------------------------- |
517 | * Arithmetic operators on 64-bit integers. |
518 | *---------------------------------------------------------*/ |
519 | |
520 | Datum |
521 | int8um(PG_FUNCTION_ARGS) |
522 | { |
523 | int64 arg = PG_GETARG_INT64(0); |
524 | int64 result; |
525 | |
526 | if (unlikely(arg == PG_INT64_MIN)) |
527 | ereport(ERROR, |
528 | (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), |
529 | errmsg("bigint out of range" ))); |
530 | result = -arg; |
531 | PG_RETURN_INT64(result); |
532 | } |
533 | |
534 | Datum |
535 | int8up(PG_FUNCTION_ARGS) |
536 | { |
537 | int64 arg = PG_GETARG_INT64(0); |
538 | |
539 | PG_RETURN_INT64(arg); |
540 | } |
541 | |
542 | Datum |
543 | int8pl(PG_FUNCTION_ARGS) |
544 | { |
545 | int64 arg1 = PG_GETARG_INT64(0); |
546 | int64 arg2 = PG_GETARG_INT64(1); |
547 | int64 result; |
548 | |
549 | if (unlikely(pg_add_s64_overflow(arg1, arg2, &result))) |
550 | ereport(ERROR, |
551 | (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), |
552 | errmsg("bigint out of range" ))); |
553 | PG_RETURN_INT64(result); |
554 | } |
555 | |
556 | Datum |
557 | int8mi(PG_FUNCTION_ARGS) |
558 | { |
559 | int64 arg1 = PG_GETARG_INT64(0); |
560 | int64 arg2 = PG_GETARG_INT64(1); |
561 | int64 result; |
562 | |
563 | if (unlikely(pg_sub_s64_overflow(arg1, arg2, &result))) |
564 | ereport(ERROR, |
565 | (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), |
566 | errmsg("bigint out of range" ))); |
567 | PG_RETURN_INT64(result); |
568 | } |
569 | |
570 | Datum |
571 | int8mul(PG_FUNCTION_ARGS) |
572 | { |
573 | int64 arg1 = PG_GETARG_INT64(0); |
574 | int64 arg2 = PG_GETARG_INT64(1); |
575 | int64 result; |
576 | |
577 | if (unlikely(pg_mul_s64_overflow(arg1, arg2, &result))) |
578 | ereport(ERROR, |
579 | (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), |
580 | errmsg("bigint out of range" ))); |
581 | PG_RETURN_INT64(result); |
582 | } |
583 | |
584 | Datum |
585 | int8div(PG_FUNCTION_ARGS) |
586 | { |
587 | int64 arg1 = PG_GETARG_INT64(0); |
588 | int64 arg2 = PG_GETARG_INT64(1); |
589 | int64 result; |
590 | |
591 | if (arg2 == 0) |
592 | { |
593 | ereport(ERROR, |
594 | (errcode(ERRCODE_DIVISION_BY_ZERO), |
595 | errmsg("division by zero" ))); |
596 | /* ensure compiler realizes we mustn't reach the division (gcc bug) */ |
597 | PG_RETURN_NULL(); |
598 | } |
599 | |
600 | /* |
601 | * INT64_MIN / -1 is problematic, since the result can't be represented on |
602 | * a two's-complement machine. Some machines produce INT64_MIN, some |
603 | * produce zero, some throw an exception. We can dodge the problem by |
604 | * recognizing that division by -1 is the same as negation. |
605 | */ |
606 | if (arg2 == -1) |
607 | { |
608 | if (unlikely(arg1 == PG_INT64_MIN)) |
609 | ereport(ERROR, |
610 | (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), |
611 | errmsg("bigint out of range" ))); |
612 | result = -arg1; |
613 | PG_RETURN_INT64(result); |
614 | } |
615 | |
616 | /* No overflow is possible */ |
617 | |
618 | result = arg1 / arg2; |
619 | |
620 | PG_RETURN_INT64(result); |
621 | } |
622 | |
623 | /* int8abs() |
624 | * Absolute value |
625 | */ |
626 | Datum |
627 | int8abs(PG_FUNCTION_ARGS) |
628 | { |
629 | int64 arg1 = PG_GETARG_INT64(0); |
630 | int64 result; |
631 | |
632 | if (unlikely(arg1 == PG_INT64_MIN)) |
633 | ereport(ERROR, |
634 | (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), |
635 | errmsg("bigint out of range" ))); |
636 | result = (arg1 < 0) ? -arg1 : arg1; |
637 | PG_RETURN_INT64(result); |
638 | } |
639 | |
640 | /* int8mod() |
641 | * Modulo operation. |
642 | */ |
643 | Datum |
644 | int8mod(PG_FUNCTION_ARGS) |
645 | { |
646 | int64 arg1 = PG_GETARG_INT64(0); |
647 | int64 arg2 = PG_GETARG_INT64(1); |
648 | |
649 | if (unlikely(arg2 == 0)) |
650 | { |
651 | ereport(ERROR, |
652 | (errcode(ERRCODE_DIVISION_BY_ZERO), |
653 | errmsg("division by zero" ))); |
654 | /* ensure compiler realizes we mustn't reach the division (gcc bug) */ |
655 | PG_RETURN_NULL(); |
656 | } |
657 | |
658 | /* |
659 | * Some machines throw a floating-point exception for INT64_MIN % -1, |
660 | * which is a bit silly since the correct answer is perfectly |
661 | * well-defined, namely zero. |
662 | */ |
663 | if (arg2 == -1) |
664 | PG_RETURN_INT64(0); |
665 | |
666 | /* No overflow is possible */ |
667 | |
668 | PG_RETURN_INT64(arg1 % arg2); |
669 | } |
670 | |
671 | |
672 | Datum |
673 | int8inc(PG_FUNCTION_ARGS) |
674 | { |
675 | /* |
676 | * When int8 is pass-by-reference, we provide this special case to avoid |
677 | * palloc overhead for COUNT(): when called as an aggregate, we know that |
678 | * the argument is modifiable local storage, so just update it in-place. |
679 | * (If int8 is pass-by-value, then of course this is useless as well as |
680 | * incorrect, so just ifdef it out.) |
681 | */ |
682 | #ifndef USE_FLOAT8_BYVAL /* controls int8 too */ |
683 | if (AggCheckCallContext(fcinfo, NULL)) |
684 | { |
685 | int64 *arg = (int64 *) PG_GETARG_POINTER(0); |
686 | |
687 | if (unlikely(pg_add_s64_overflow(*arg, 1, arg))) |
688 | ereport(ERROR, |
689 | (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), |
690 | errmsg("bigint out of range" ))); |
691 | |
692 | PG_RETURN_POINTER(arg); |
693 | } |
694 | else |
695 | #endif |
696 | { |
697 | /* Not called as an aggregate, so just do it the dumb way */ |
698 | int64 arg = PG_GETARG_INT64(0); |
699 | int64 result; |
700 | |
701 | if (unlikely(pg_add_s64_overflow(arg, 1, &result))) |
702 | ereport(ERROR, |
703 | (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), |
704 | errmsg("bigint out of range" ))); |
705 | |
706 | PG_RETURN_INT64(result); |
707 | } |
708 | } |
709 | |
710 | Datum |
711 | int8dec(PG_FUNCTION_ARGS) |
712 | { |
713 | /* |
714 | * When int8 is pass-by-reference, we provide this special case to avoid |
715 | * palloc overhead for COUNT(): when called as an aggregate, we know that |
716 | * the argument is modifiable local storage, so just update it in-place. |
717 | * (If int8 is pass-by-value, then of course this is useless as well as |
718 | * incorrect, so just ifdef it out.) |
719 | */ |
720 | #ifndef USE_FLOAT8_BYVAL /* controls int8 too */ |
721 | if (AggCheckCallContext(fcinfo, NULL)) |
722 | { |
723 | int64 *arg = (int64 *) PG_GETARG_POINTER(0); |
724 | |
725 | if (unlikely(pg_sub_s64_overflow(*arg, 1, arg))) |
726 | ereport(ERROR, |
727 | (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), |
728 | errmsg("bigint out of range" ))); |
729 | PG_RETURN_POINTER(arg); |
730 | } |
731 | else |
732 | #endif |
733 | { |
734 | /* Not called as an aggregate, so just do it the dumb way */ |
735 | int64 arg = PG_GETARG_INT64(0); |
736 | int64 result; |
737 | |
738 | if (unlikely(pg_sub_s64_overflow(arg, 1, &result))) |
739 | ereport(ERROR, |
740 | (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), |
741 | errmsg("bigint out of range" ))); |
742 | |
743 | PG_RETURN_INT64(result); |
744 | } |
745 | } |
746 | |
747 | |
748 | /* |
749 | * These functions are exactly like int8inc/int8dec but are used for |
750 | * aggregates that count only non-null values. Since the functions are |
751 | * declared strict, the null checks happen before we ever get here, and all we |
752 | * need do is increment the state value. We could actually make these pg_proc |
753 | * entries point right at int8inc/int8dec, but then the opr_sanity regression |
754 | * test would complain about mismatched entries for a built-in function. |
755 | */ |
756 | |
757 | Datum |
758 | int8inc_any(PG_FUNCTION_ARGS) |
759 | { |
760 | return int8inc(fcinfo); |
761 | } |
762 | |
763 | Datum |
764 | int8inc_float8_float8(PG_FUNCTION_ARGS) |
765 | { |
766 | return int8inc(fcinfo); |
767 | } |
768 | |
769 | Datum |
770 | int8dec_any(PG_FUNCTION_ARGS) |
771 | { |
772 | return int8dec(fcinfo); |
773 | } |
774 | |
775 | |
776 | Datum |
777 | int8larger(PG_FUNCTION_ARGS) |
778 | { |
779 | int64 arg1 = PG_GETARG_INT64(0); |
780 | int64 arg2 = PG_GETARG_INT64(1); |
781 | int64 result; |
782 | |
783 | result = ((arg1 > arg2) ? arg1 : arg2); |
784 | |
785 | PG_RETURN_INT64(result); |
786 | } |
787 | |
788 | Datum |
789 | int8smaller(PG_FUNCTION_ARGS) |
790 | { |
791 | int64 arg1 = PG_GETARG_INT64(0); |
792 | int64 arg2 = PG_GETARG_INT64(1); |
793 | int64 result; |
794 | |
795 | result = ((arg1 < arg2) ? arg1 : arg2); |
796 | |
797 | PG_RETURN_INT64(result); |
798 | } |
799 | |
800 | Datum |
801 | int84pl(PG_FUNCTION_ARGS) |
802 | { |
803 | int64 arg1 = PG_GETARG_INT64(0); |
804 | int32 arg2 = PG_GETARG_INT32(1); |
805 | int64 result; |
806 | |
807 | if (unlikely(pg_add_s64_overflow(arg1, (int64) arg2, &result))) |
808 | ereport(ERROR, |
809 | (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), |
810 | errmsg("bigint out of range" ))); |
811 | PG_RETURN_INT64(result); |
812 | } |
813 | |
814 | Datum |
815 | int84mi(PG_FUNCTION_ARGS) |
816 | { |
817 | int64 arg1 = PG_GETARG_INT64(0); |
818 | int32 arg2 = PG_GETARG_INT32(1); |
819 | int64 result; |
820 | |
821 | if (unlikely(pg_sub_s64_overflow(arg1, (int64) arg2, &result))) |
822 | ereport(ERROR, |
823 | (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), |
824 | errmsg("bigint out of range" ))); |
825 | PG_RETURN_INT64(result); |
826 | } |
827 | |
828 | Datum |
829 | int84mul(PG_FUNCTION_ARGS) |
830 | { |
831 | int64 arg1 = PG_GETARG_INT64(0); |
832 | int32 arg2 = PG_GETARG_INT32(1); |
833 | int64 result; |
834 | |
835 | if (unlikely(pg_mul_s64_overflow(arg1, (int64) arg2, &result))) |
836 | ereport(ERROR, |
837 | (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), |
838 | errmsg("bigint out of range" ))); |
839 | PG_RETURN_INT64(result); |
840 | } |
841 | |
842 | Datum |
843 | int84div(PG_FUNCTION_ARGS) |
844 | { |
845 | int64 arg1 = PG_GETARG_INT64(0); |
846 | int32 arg2 = PG_GETARG_INT32(1); |
847 | int64 result; |
848 | |
849 | if (arg2 == 0) |
850 | { |
851 | ereport(ERROR, |
852 | (errcode(ERRCODE_DIVISION_BY_ZERO), |
853 | errmsg("division by zero" ))); |
854 | /* ensure compiler realizes we mustn't reach the division (gcc bug) */ |
855 | PG_RETURN_NULL(); |
856 | } |
857 | |
858 | /* |
859 | * INT64_MIN / -1 is problematic, since the result can't be represented on |
860 | * a two's-complement machine. Some machines produce INT64_MIN, some |
861 | * produce zero, some throw an exception. We can dodge the problem by |
862 | * recognizing that division by -1 is the same as negation. |
863 | */ |
864 | if (arg2 == -1) |
865 | { |
866 | if (unlikely(arg1 == PG_INT64_MIN)) |
867 | ereport(ERROR, |
868 | (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), |
869 | errmsg("bigint out of range" ))); |
870 | result = -arg1; |
871 | PG_RETURN_INT64(result); |
872 | } |
873 | |
874 | /* No overflow is possible */ |
875 | |
876 | result = arg1 / arg2; |
877 | |
878 | PG_RETURN_INT64(result); |
879 | } |
880 | |
881 | Datum |
882 | int48pl(PG_FUNCTION_ARGS) |
883 | { |
884 | int32 arg1 = PG_GETARG_INT32(0); |
885 | int64 arg2 = PG_GETARG_INT64(1); |
886 | int64 result; |
887 | |
888 | if (unlikely(pg_add_s64_overflow((int64) arg1, arg2, &result))) |
889 | ereport(ERROR, |
890 | (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), |
891 | errmsg("bigint out of range" ))); |
892 | PG_RETURN_INT64(result); |
893 | } |
894 | |
895 | Datum |
896 | int48mi(PG_FUNCTION_ARGS) |
897 | { |
898 | int32 arg1 = PG_GETARG_INT32(0); |
899 | int64 arg2 = PG_GETARG_INT64(1); |
900 | int64 result; |
901 | |
902 | if (unlikely(pg_sub_s64_overflow((int64) arg1, arg2, &result))) |
903 | ereport(ERROR, |
904 | (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), |
905 | errmsg("bigint out of range" ))); |
906 | PG_RETURN_INT64(result); |
907 | } |
908 | |
909 | Datum |
910 | int48mul(PG_FUNCTION_ARGS) |
911 | { |
912 | int32 arg1 = PG_GETARG_INT32(0); |
913 | int64 arg2 = PG_GETARG_INT64(1); |
914 | int64 result; |
915 | |
916 | if (unlikely(pg_mul_s64_overflow((int64) arg1, arg2, &result))) |
917 | ereport(ERROR, |
918 | (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), |
919 | errmsg("bigint out of range" ))); |
920 | PG_RETURN_INT64(result); |
921 | } |
922 | |
923 | Datum |
924 | int48div(PG_FUNCTION_ARGS) |
925 | { |
926 | int32 arg1 = PG_GETARG_INT32(0); |
927 | int64 arg2 = PG_GETARG_INT64(1); |
928 | |
929 | if (unlikely(arg2 == 0)) |
930 | { |
931 | ereport(ERROR, |
932 | (errcode(ERRCODE_DIVISION_BY_ZERO), |
933 | errmsg("division by zero" ))); |
934 | /* ensure compiler realizes we mustn't reach the division (gcc bug) */ |
935 | PG_RETURN_NULL(); |
936 | } |
937 | |
938 | /* No overflow is possible */ |
939 | PG_RETURN_INT64((int64) arg1 / arg2); |
940 | } |
941 | |
942 | Datum |
943 | int82pl(PG_FUNCTION_ARGS) |
944 | { |
945 | int64 arg1 = PG_GETARG_INT64(0); |
946 | int16 arg2 = PG_GETARG_INT16(1); |
947 | int64 result; |
948 | |
949 | if (unlikely(pg_add_s64_overflow(arg1, (int64) arg2, &result))) |
950 | ereport(ERROR, |
951 | (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), |
952 | errmsg("bigint out of range" ))); |
953 | PG_RETURN_INT64(result); |
954 | } |
955 | |
956 | Datum |
957 | int82mi(PG_FUNCTION_ARGS) |
958 | { |
959 | int64 arg1 = PG_GETARG_INT64(0); |
960 | int16 arg2 = PG_GETARG_INT16(1); |
961 | int64 result; |
962 | |
963 | if (unlikely(pg_sub_s64_overflow(arg1, (int64) arg2, &result))) |
964 | ereport(ERROR, |
965 | (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), |
966 | errmsg("bigint out of range" ))); |
967 | PG_RETURN_INT64(result); |
968 | } |
969 | |
970 | Datum |
971 | int82mul(PG_FUNCTION_ARGS) |
972 | { |
973 | int64 arg1 = PG_GETARG_INT64(0); |
974 | int16 arg2 = PG_GETARG_INT16(1); |
975 | int64 result; |
976 | |
977 | if (unlikely(pg_mul_s64_overflow(arg1, (int64) arg2, &result))) |
978 | ereport(ERROR, |
979 | (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), |
980 | errmsg("bigint out of range" ))); |
981 | PG_RETURN_INT64(result); |
982 | } |
983 | |
984 | Datum |
985 | int82div(PG_FUNCTION_ARGS) |
986 | { |
987 | int64 arg1 = PG_GETARG_INT64(0); |
988 | int16 arg2 = PG_GETARG_INT16(1); |
989 | int64 result; |
990 | |
991 | if (unlikely(arg2 == 0)) |
992 | { |
993 | ereport(ERROR, |
994 | (errcode(ERRCODE_DIVISION_BY_ZERO), |
995 | errmsg("division by zero" ))); |
996 | /* ensure compiler realizes we mustn't reach the division (gcc bug) */ |
997 | PG_RETURN_NULL(); |
998 | } |
999 | |
1000 | /* |
1001 | * INT64_MIN / -1 is problematic, since the result can't be represented on |
1002 | * a two's-complement machine. Some machines produce INT64_MIN, some |
1003 | * produce zero, some throw an exception. We can dodge the problem by |
1004 | * recognizing that division by -1 is the same as negation. |
1005 | */ |
1006 | if (arg2 == -1) |
1007 | { |
1008 | if (unlikely(arg1 == PG_INT64_MIN)) |
1009 | ereport(ERROR, |
1010 | (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), |
1011 | errmsg("bigint out of range" ))); |
1012 | result = -arg1; |
1013 | PG_RETURN_INT64(result); |
1014 | } |
1015 | |
1016 | /* No overflow is possible */ |
1017 | |
1018 | result = arg1 / arg2; |
1019 | |
1020 | PG_RETURN_INT64(result); |
1021 | } |
1022 | |
1023 | Datum |
1024 | int28pl(PG_FUNCTION_ARGS) |
1025 | { |
1026 | int16 arg1 = PG_GETARG_INT16(0); |
1027 | int64 arg2 = PG_GETARG_INT64(1); |
1028 | int64 result; |
1029 | |
1030 | if (unlikely(pg_add_s64_overflow((int64) arg1, arg2, &result))) |
1031 | ereport(ERROR, |
1032 | (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), |
1033 | errmsg("bigint out of range" ))); |
1034 | PG_RETURN_INT64(result); |
1035 | } |
1036 | |
1037 | Datum |
1038 | int28mi(PG_FUNCTION_ARGS) |
1039 | { |
1040 | int16 arg1 = PG_GETARG_INT16(0); |
1041 | int64 arg2 = PG_GETARG_INT64(1); |
1042 | int64 result; |
1043 | |
1044 | if (unlikely(pg_sub_s64_overflow((int64) arg1, arg2, &result))) |
1045 | ereport(ERROR, |
1046 | (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), |
1047 | errmsg("bigint out of range" ))); |
1048 | PG_RETURN_INT64(result); |
1049 | } |
1050 | |
1051 | Datum |
1052 | int28mul(PG_FUNCTION_ARGS) |
1053 | { |
1054 | int16 arg1 = PG_GETARG_INT16(0); |
1055 | int64 arg2 = PG_GETARG_INT64(1); |
1056 | int64 result; |
1057 | |
1058 | if (unlikely(pg_mul_s64_overflow((int64) arg1, arg2, &result))) |
1059 | ereport(ERROR, |
1060 | (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), |
1061 | errmsg("bigint out of range" ))); |
1062 | PG_RETURN_INT64(result); |
1063 | } |
1064 | |
1065 | Datum |
1066 | int28div(PG_FUNCTION_ARGS) |
1067 | { |
1068 | int16 arg1 = PG_GETARG_INT16(0); |
1069 | int64 arg2 = PG_GETARG_INT64(1); |
1070 | |
1071 | if (unlikely(arg2 == 0)) |
1072 | { |
1073 | ereport(ERROR, |
1074 | (errcode(ERRCODE_DIVISION_BY_ZERO), |
1075 | errmsg("division by zero" ))); |
1076 | /* ensure compiler realizes we mustn't reach the division (gcc bug) */ |
1077 | PG_RETURN_NULL(); |
1078 | } |
1079 | |
1080 | /* No overflow is possible */ |
1081 | PG_RETURN_INT64((int64) arg1 / arg2); |
1082 | } |
1083 | |
1084 | /* Binary arithmetics |
1085 | * |
1086 | * int8and - returns arg1 & arg2 |
1087 | * int8or - returns arg1 | arg2 |
1088 | * int8xor - returns arg1 # arg2 |
1089 | * int8not - returns ~arg1 |
1090 | * int8shl - returns arg1 << arg2 |
1091 | * int8shr - returns arg1 >> arg2 |
1092 | */ |
1093 | |
1094 | Datum |
1095 | int8and(PG_FUNCTION_ARGS) |
1096 | { |
1097 | int64 arg1 = PG_GETARG_INT64(0); |
1098 | int64 arg2 = PG_GETARG_INT64(1); |
1099 | |
1100 | PG_RETURN_INT64(arg1 & arg2); |
1101 | } |
1102 | |
1103 | Datum |
1104 | int8or(PG_FUNCTION_ARGS) |
1105 | { |
1106 | int64 arg1 = PG_GETARG_INT64(0); |
1107 | int64 arg2 = PG_GETARG_INT64(1); |
1108 | |
1109 | PG_RETURN_INT64(arg1 | arg2); |
1110 | } |
1111 | |
1112 | Datum |
1113 | int8xor(PG_FUNCTION_ARGS) |
1114 | { |
1115 | int64 arg1 = PG_GETARG_INT64(0); |
1116 | int64 arg2 = PG_GETARG_INT64(1); |
1117 | |
1118 | PG_RETURN_INT64(arg1 ^ arg2); |
1119 | } |
1120 | |
1121 | Datum |
1122 | int8not(PG_FUNCTION_ARGS) |
1123 | { |
1124 | int64 arg1 = PG_GETARG_INT64(0); |
1125 | |
1126 | PG_RETURN_INT64(~arg1); |
1127 | } |
1128 | |
1129 | Datum |
1130 | int8shl(PG_FUNCTION_ARGS) |
1131 | { |
1132 | int64 arg1 = PG_GETARG_INT64(0); |
1133 | int32 arg2 = PG_GETARG_INT32(1); |
1134 | |
1135 | PG_RETURN_INT64(arg1 << arg2); |
1136 | } |
1137 | |
1138 | Datum |
1139 | int8shr(PG_FUNCTION_ARGS) |
1140 | { |
1141 | int64 arg1 = PG_GETARG_INT64(0); |
1142 | int32 arg2 = PG_GETARG_INT32(1); |
1143 | |
1144 | PG_RETURN_INT64(arg1 >> arg2); |
1145 | } |
1146 | |
1147 | /*---------------------------------------------------------- |
1148 | * Conversion operators. |
1149 | *---------------------------------------------------------*/ |
1150 | |
1151 | Datum |
1152 | int48(PG_FUNCTION_ARGS) |
1153 | { |
1154 | int32 arg = PG_GETARG_INT32(0); |
1155 | |
1156 | PG_RETURN_INT64((int64) arg); |
1157 | } |
1158 | |
1159 | Datum |
1160 | int84(PG_FUNCTION_ARGS) |
1161 | { |
1162 | int64 arg = PG_GETARG_INT64(0); |
1163 | |
1164 | if (unlikely(arg < PG_INT32_MIN) || unlikely(arg > PG_INT32_MAX)) |
1165 | ereport(ERROR, |
1166 | (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), |
1167 | errmsg("integer out of range" ))); |
1168 | |
1169 | PG_RETURN_INT32((int32) arg); |
1170 | } |
1171 | |
1172 | Datum |
1173 | int28(PG_FUNCTION_ARGS) |
1174 | { |
1175 | int16 arg = PG_GETARG_INT16(0); |
1176 | |
1177 | PG_RETURN_INT64((int64) arg); |
1178 | } |
1179 | |
1180 | Datum |
1181 | int82(PG_FUNCTION_ARGS) |
1182 | { |
1183 | int64 arg = PG_GETARG_INT64(0); |
1184 | |
1185 | if (unlikely(arg < PG_INT16_MIN) || unlikely(arg > PG_INT16_MAX)) |
1186 | ereport(ERROR, |
1187 | (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), |
1188 | errmsg("smallint out of range" ))); |
1189 | |
1190 | PG_RETURN_INT16((int16) arg); |
1191 | } |
1192 | |
1193 | Datum |
1194 | i8tod(PG_FUNCTION_ARGS) |
1195 | { |
1196 | int64 arg = PG_GETARG_INT64(0); |
1197 | float8 result; |
1198 | |
1199 | result = arg; |
1200 | |
1201 | PG_RETURN_FLOAT8(result); |
1202 | } |
1203 | |
1204 | /* dtoi8() |
1205 | * Convert float8 to 8-byte integer. |
1206 | */ |
1207 | Datum |
1208 | dtoi8(PG_FUNCTION_ARGS) |
1209 | { |
1210 | float8 num = PG_GETARG_FLOAT8(0); |
1211 | |
1212 | /* |
1213 | * Get rid of any fractional part in the input. This is so we don't fail |
1214 | * on just-out-of-range values that would round into range. Note |
1215 | * assumption that rint() will pass through a NaN or Inf unchanged. |
1216 | */ |
1217 | num = rint(num); |
1218 | |
1219 | /* |
1220 | * Range check. We must be careful here that the boundary values are |
1221 | * expressed exactly in the float domain. We expect PG_INT64_MIN to be an |
1222 | * exact power of 2, so it will be represented exactly; but PG_INT64_MAX |
1223 | * isn't, and might get rounded off, so avoid using it. |
1224 | */ |
1225 | if (unlikely(num < (float8) PG_INT64_MIN || |
1226 | num >= -((float8) PG_INT64_MIN) || |
1227 | isnan(num))) |
1228 | ereport(ERROR, |
1229 | (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), |
1230 | errmsg("bigint out of range" ))); |
1231 | |
1232 | PG_RETURN_INT64((int64) num); |
1233 | } |
1234 | |
1235 | Datum |
1236 | i8tof(PG_FUNCTION_ARGS) |
1237 | { |
1238 | int64 arg = PG_GETARG_INT64(0); |
1239 | float4 result; |
1240 | |
1241 | result = arg; |
1242 | |
1243 | PG_RETURN_FLOAT4(result); |
1244 | } |
1245 | |
1246 | /* ftoi8() |
1247 | * Convert float4 to 8-byte integer. |
1248 | */ |
1249 | Datum |
1250 | ftoi8(PG_FUNCTION_ARGS) |
1251 | { |
1252 | float4 num = PG_GETARG_FLOAT4(0); |
1253 | |
1254 | /* |
1255 | * Get rid of any fractional part in the input. This is so we don't fail |
1256 | * on just-out-of-range values that would round into range. Note |
1257 | * assumption that rint() will pass through a NaN or Inf unchanged. |
1258 | */ |
1259 | num = rint(num); |
1260 | |
1261 | /* |
1262 | * Range check. We must be careful here that the boundary values are |
1263 | * expressed exactly in the float domain. We expect PG_INT64_MIN to be an |
1264 | * exact power of 2, so it will be represented exactly; but PG_INT64_MAX |
1265 | * isn't, and might get rounded off, so avoid using it. |
1266 | */ |
1267 | if (unlikely(num < (float4) PG_INT64_MIN || |
1268 | num >= -((float4) PG_INT64_MIN) || |
1269 | isnan(num))) |
1270 | ereport(ERROR, |
1271 | (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), |
1272 | errmsg("bigint out of range" ))); |
1273 | |
1274 | PG_RETURN_INT64((int64) num); |
1275 | } |
1276 | |
1277 | Datum |
1278 | i8tooid(PG_FUNCTION_ARGS) |
1279 | { |
1280 | int64 arg = PG_GETARG_INT64(0); |
1281 | |
1282 | if (unlikely(arg < 0) || unlikely(arg > PG_UINT32_MAX)) |
1283 | ereport(ERROR, |
1284 | (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), |
1285 | errmsg("OID out of range" ))); |
1286 | |
1287 | PG_RETURN_OID((Oid) arg); |
1288 | } |
1289 | |
1290 | Datum |
1291 | oidtoi8(PG_FUNCTION_ARGS) |
1292 | { |
1293 | Oid arg = PG_GETARG_OID(0); |
1294 | |
1295 | PG_RETURN_INT64((int64) arg); |
1296 | } |
1297 | |
1298 | /* |
1299 | * non-persistent numeric series generator |
1300 | */ |
1301 | Datum |
1302 | generate_series_int8(PG_FUNCTION_ARGS) |
1303 | { |
1304 | return generate_series_step_int8(fcinfo); |
1305 | } |
1306 | |
1307 | Datum |
1308 | generate_series_step_int8(PG_FUNCTION_ARGS) |
1309 | { |
1310 | FuncCallContext *funcctx; |
1311 | generate_series_fctx *fctx; |
1312 | int64 result; |
1313 | MemoryContext oldcontext; |
1314 | |
1315 | /* stuff done only on the first call of the function */ |
1316 | if (SRF_IS_FIRSTCALL()) |
1317 | { |
1318 | int64 start = PG_GETARG_INT64(0); |
1319 | int64 finish = PG_GETARG_INT64(1); |
1320 | int64 step = 1; |
1321 | |
1322 | /* see if we were given an explicit step size */ |
1323 | if (PG_NARGS() == 3) |
1324 | step = PG_GETARG_INT64(2); |
1325 | if (step == 0) |
1326 | ereport(ERROR, |
1327 | (errcode(ERRCODE_INVALID_PARAMETER_VALUE), |
1328 | errmsg("step size cannot equal zero" ))); |
1329 | |
1330 | /* create a function context for cross-call persistence */ |
1331 | funcctx = SRF_FIRSTCALL_INIT(); |
1332 | |
1333 | /* |
1334 | * switch to memory context appropriate for multiple function calls |
1335 | */ |
1336 | oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); |
1337 | |
1338 | /* allocate memory for user context */ |
1339 | fctx = (generate_series_fctx *) palloc(sizeof(generate_series_fctx)); |
1340 | |
1341 | /* |
1342 | * Use fctx to keep state from call to call. Seed current with the |
1343 | * original start value |
1344 | */ |
1345 | fctx->current = start; |
1346 | fctx->finish = finish; |
1347 | fctx->step = step; |
1348 | |
1349 | funcctx->user_fctx = fctx; |
1350 | MemoryContextSwitchTo(oldcontext); |
1351 | } |
1352 | |
1353 | /* stuff done on every call of the function */ |
1354 | funcctx = SRF_PERCALL_SETUP(); |
1355 | |
1356 | /* |
1357 | * get the saved state and use current as the result for this iteration |
1358 | */ |
1359 | fctx = funcctx->user_fctx; |
1360 | result = fctx->current; |
1361 | |
1362 | if ((fctx->step > 0 && fctx->current <= fctx->finish) || |
1363 | (fctx->step < 0 && fctx->current >= fctx->finish)) |
1364 | { |
1365 | /* |
1366 | * Increment current in preparation for next iteration. If next-value |
1367 | * computation overflows, this is the final result. |
1368 | */ |
1369 | if (pg_add_s64_overflow(fctx->current, fctx->step, &fctx->current)) |
1370 | fctx->step = 0; |
1371 | |
1372 | /* do when there is more left to send */ |
1373 | SRF_RETURN_NEXT(funcctx, Int64GetDatum(result)); |
1374 | } |
1375 | else |
1376 | /* do when there is no more left */ |
1377 | SRF_RETURN_DONE(funcctx); |
1378 | } |
1379 | |
1380 | /* |
1381 | * Planner support function for generate_series(int8, int8 [, int8]) |
1382 | */ |
1383 | Datum |
1384 | generate_series_int8_support(PG_FUNCTION_ARGS) |
1385 | { |
1386 | Node *rawreq = (Node *) PG_GETARG_POINTER(0); |
1387 | Node *ret = NULL; |
1388 | |
1389 | if (IsA(rawreq, SupportRequestRows)) |
1390 | { |
1391 | /* Try to estimate the number of rows returned */ |
1392 | SupportRequestRows *req = (SupportRequestRows *) rawreq; |
1393 | |
1394 | if (is_funcclause(req->node)) /* be paranoid */ |
1395 | { |
1396 | List *args = ((FuncExpr *) req->node)->args; |
1397 | Node *arg1, |
1398 | *arg2, |
1399 | *arg3; |
1400 | |
1401 | /* We can use estimated argument values here */ |
1402 | arg1 = estimate_expression_value(req->root, linitial(args)); |
1403 | arg2 = estimate_expression_value(req->root, lsecond(args)); |
1404 | if (list_length(args) >= 3) |
1405 | arg3 = estimate_expression_value(req->root, lthird(args)); |
1406 | else |
1407 | arg3 = NULL; |
1408 | |
1409 | /* |
1410 | * If any argument is constant NULL, we can safely assume that |
1411 | * zero rows are returned. Otherwise, if they're all non-NULL |
1412 | * constants, we can calculate the number of rows that will be |
1413 | * returned. Use double arithmetic to avoid overflow hazards. |
1414 | */ |
1415 | if ((IsA(arg1, Const) && |
1416 | ((Const *) arg1)->constisnull) || |
1417 | (IsA(arg2, Const) && |
1418 | ((Const *) arg2)->constisnull) || |
1419 | (arg3 != NULL && IsA(arg3, Const) && |
1420 | ((Const *) arg3)->constisnull)) |
1421 | { |
1422 | req->rows = 0; |
1423 | ret = (Node *) req; |
1424 | } |
1425 | else if (IsA(arg1, Const) && |
1426 | IsA(arg2, Const) && |
1427 | (arg3 == NULL || IsA(arg3, Const))) |
1428 | { |
1429 | double start, |
1430 | finish, |
1431 | step; |
1432 | |
1433 | start = DatumGetInt64(((Const *) arg1)->constvalue); |
1434 | finish = DatumGetInt64(((Const *) arg2)->constvalue); |
1435 | step = arg3 ? DatumGetInt64(((Const *) arg3)->constvalue) : 1; |
1436 | |
1437 | /* This equation works for either sign of step */ |
1438 | if (step != 0) |
1439 | { |
1440 | req->rows = floor((finish - start + step) / step); |
1441 | ret = (Node *) req; |
1442 | } |
1443 | } |
1444 | } |
1445 | } |
1446 | |
1447 | PG_RETURN_POINTER(ret); |
1448 | } |
1449 | |