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