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