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