PostgreSQL Source Code git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
array_userfuncs.c
Go to the documentation of this file.
1/*-------------------------------------------------------------------------
2 *
3 * array_userfuncs.c
4 * Misc user-visible array support functions
5 *
6 * Copyright (c) 2003-2025, PostgreSQL Global Development Group
7 *
8 * IDENTIFICATION
9 * src/backend/utils/adt/array_userfuncs.c
10 *
11 *-------------------------------------------------------------------------
12 */
13#include "postgres.h"
14
15#include "catalog/pg_operator_d.h"
16#include "catalog/pg_type.h"
17#include "common/int.h"
18#include "common/pg_prng.h"
19#include "libpq/pqformat.h"
20#include "miscadmin.h"
21#include "nodes/supportnodes.h"
22#include "port/pg_bitutils.h"
23#include "utils/array.h"
24#include "utils/builtins.h"
25#include "utils/datum.h"
26#include "utils/lsyscache.h"
27#include "utils/tuplesort.h"
28#include "utils/typcache.h"
29
30/*
31 * SerialIOData
32 * Used for caching element-type data in array_agg_serialize
33 */
34typedef struct SerialIOData
35{
38
39/*
40 * DeserialIOData
41 * Used for caching element-type data in array_agg_deserialize
42 */
43typedef struct DeserialIOData
44{
48
49/*
50 * ArraySortCachedInfo
51 * Used for caching catalog data in array_sort
52 */
53typedef struct ArraySortCachedInfo
54{
55 ArrayMetaState array_meta; /* metadata for array_create_iterator */
56 Oid elem_lt_opr; /* "<" operator for element type */
57 Oid elem_gt_opr; /* ">" operator for element type */
58 Oid array_type; /* pg_type OID of array type */
60
62
63
64/*
65 * fetch_array_arg_replace_nulls
66 *
67 * Fetch an array-valued argument in expanded form; if it's null, construct an
68 * empty array value of the proper data type. Also cache basic element type
69 * information in fn_extra.
70 *
71 * Caution: if the input is a read/write pointer, this returns the input
72 * argument; so callers must be sure that their changes are "safe", that is
73 * they cannot leave the array in a corrupt state.
74 *
75 * If we're being called as an aggregate function, make sure any newly-made
76 * expanded array is allocated in the aggregate state context, so as to save
77 * copying operations.
78 */
81{
83 Oid element_type;
84 ArrayMetaState *my_extra;
85 MemoryContext resultcxt;
86
87 /* If first time through, create datatype cache struct */
88 my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra;
89 if (my_extra == NULL)
90 {
91 my_extra = (ArrayMetaState *)
93 sizeof(ArrayMetaState));
94 my_extra->element_type = InvalidOid;
95 fcinfo->flinfo->fn_extra = my_extra;
96 }
97
98 /* Figure out which context we want the result in */
99 if (!AggCheckCallContext(fcinfo, &resultcxt))
100 resultcxt = CurrentMemoryContext;
101
102 /* Now collect the array value */
103 if (!PG_ARGISNULL(argno))
104 {
105 MemoryContext oldcxt = MemoryContextSwitchTo(resultcxt);
106
107 eah = PG_GETARG_EXPANDED_ARRAYX(argno, my_extra);
108 MemoryContextSwitchTo(oldcxt);
109 }
110 else
111 {
112 /* We have to look up the array type and element type */
113 Oid arr_typeid = get_fn_expr_argtype(fcinfo->flinfo, argno);
114
115 if (!OidIsValid(arr_typeid))
117 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
118 errmsg("could not determine input data type")));
119 element_type = get_element_type(arr_typeid);
120 if (!OidIsValid(element_type))
122 (errcode(ERRCODE_DATATYPE_MISMATCH),
123 errmsg("input data type is not an array")));
124
125 eah = construct_empty_expanded_array(element_type,
126 resultcxt,
127 my_extra);
128 }
129
130 return eah;
131}
132
133/*-----------------------------------------------------------------------------
134 * array_append :
135 * push an element onto the end of a one-dimensional array
136 *----------------------------------------------------------------------------
137 */
138Datum
140{
142 Datum newelem;
143 bool isNull;
144 Datum result;
145 int *dimv,
146 *lb;
147 int indx;
148 ArrayMetaState *my_extra;
149
150 eah = fetch_array_arg_replace_nulls(fcinfo, 0);
151 isNull = PG_ARGISNULL(1);
152 if (isNull)
153 newelem = (Datum) 0;
154 else
155 newelem = PG_GETARG_DATUM(1);
156
157 if (eah->ndims == 1)
158 {
159 /* append newelem */
160 lb = eah->lbound;
161 dimv = eah->dims;
162
163 /* index of added elem is at lb[0] + (dimv[0] - 1) + 1 */
164 if (pg_add_s32_overflow(lb[0], dimv[0], &indx))
166 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
167 errmsg("integer out of range")));
168 }
169 else if (eah->ndims == 0)
170 indx = 1;
171 else
173 (errcode(ERRCODE_DATA_EXCEPTION),
174 errmsg("argument must be empty or one-dimensional array")));
175
176 /* Perform element insertion */
177 my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra;
178
179 result = array_set_element(EOHPGetRWDatum(&eah->hdr),
180 1, &indx, newelem, isNull,
181 -1, my_extra->typlen, my_extra->typbyval, my_extra->typalign);
182
183 PG_RETURN_DATUM(result);
184}
185
186/*
187 * array_append_support()
188 *
189 * Planner support function for array_append()
190 */
191Datum
193{
194 Node *rawreq = (Node *) PG_GETARG_POINTER(0);
195 Node *ret = NULL;
196
197 if (IsA(rawreq, SupportRequestModifyInPlace))
198 {
199 /*
200 * We can optimize in-place appends if the function's array argument
201 * is the array being assigned to. We don't need to worry about array
202 * references within the other argument.
203 */
205 Param *arg = (Param *) linitial(req->args);
206
207 if (arg && IsA(arg, Param) &&
208 arg->paramkind == PARAM_EXTERN &&
209 arg->paramid == req->paramid)
210 ret = (Node *) arg;
211 }
212
214}
215
216/*-----------------------------------------------------------------------------
217 * array_prepend :
218 * push an element onto the front of a one-dimensional array
219 *----------------------------------------------------------------------------
220 */
221Datum
223{
225 Datum newelem;
226 bool isNull;
227 Datum result;
228 int *lb;
229 int indx;
230 int lb0;
231 ArrayMetaState *my_extra;
232
233 isNull = PG_ARGISNULL(0);
234 if (isNull)
235 newelem = (Datum) 0;
236 else
237 newelem = PG_GETARG_DATUM(0);
238 eah = fetch_array_arg_replace_nulls(fcinfo, 1);
239
240 if (eah->ndims == 1)
241 {
242 /* prepend newelem */
243 lb = eah->lbound;
244 lb0 = lb[0];
245
246 if (pg_sub_s32_overflow(lb0, 1, &indx))
248 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
249 errmsg("integer out of range")));
250 }
251 else if (eah->ndims == 0)
252 {
253 indx = 1;
254 lb0 = 1;
255 }
256 else
258 (errcode(ERRCODE_DATA_EXCEPTION),
259 errmsg("argument must be empty or one-dimensional array")));
260
261 /* Perform element insertion */
262 my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra;
263
264 result = array_set_element(EOHPGetRWDatum(&eah->hdr),
265 1, &indx, newelem, isNull,
266 -1, my_extra->typlen, my_extra->typbyval, my_extra->typalign);
267
268 /* Readjust result's LB to match the input's, as expected for prepend */
269 Assert(result == EOHPGetRWDatum(&eah->hdr));
270 if (eah->ndims == 1)
271 {
272 /* This is ok whether we've deconstructed or not */
273 eah->lbound[0] = lb0;
274 }
275
276 PG_RETURN_DATUM(result);
277}
278
279/*
280 * array_prepend_support()
281 *
282 * Planner support function for array_prepend()
283 */
284Datum
286{
287 Node *rawreq = (Node *) PG_GETARG_POINTER(0);
288 Node *ret = NULL;
289
290 if (IsA(rawreq, SupportRequestModifyInPlace))
291 {
292 /*
293 * We can optimize in-place prepends if the function's array argument
294 * is the array being assigned to. We don't need to worry about array
295 * references within the other argument.
296 */
298 Param *arg = (Param *) lsecond(req->args);
299
300 if (arg && IsA(arg, Param) &&
301 arg->paramkind == PARAM_EXTERN &&
302 arg->paramid == req->paramid)
303 ret = (Node *) arg;
304 }
305
307}
308
309/*-----------------------------------------------------------------------------
310 * array_cat :
311 * concatenate two nD arrays to form an nD array, or
312 * push an (n-1)D array onto the end of an nD array
313 *----------------------------------------------------------------------------
314 */
315Datum
317{
318 ArrayType *v1,
319 *v2;
320 ArrayType *result;
321 int *dims,
322 *lbs,
323 ndims,
324 nitems,
325 ndatabytes,
326 nbytes;
327 int *dims1,
328 *lbs1,
329 ndims1,
330 nitems1,
331 ndatabytes1;
332 int *dims2,
333 *lbs2,
334 ndims2,
335 nitems2,
336 ndatabytes2;
337 int i;
338 char *dat1,
339 *dat2;
340 bits8 *bitmap1,
341 *bitmap2;
342 Oid element_type;
343 Oid element_type1;
344 Oid element_type2;
345 int32 dataoffset;
346
347 /* Concatenating a null array is a no-op, just return the other input */
348 if (PG_ARGISNULL(0))
349 {
350 if (PG_ARGISNULL(1))
352 result = PG_GETARG_ARRAYTYPE_P(1);
353 PG_RETURN_ARRAYTYPE_P(result);
354 }
355 if (PG_ARGISNULL(1))
356 {
357 result = PG_GETARG_ARRAYTYPE_P(0);
358 PG_RETURN_ARRAYTYPE_P(result);
359 }
360
361 v1 = PG_GETARG_ARRAYTYPE_P(0);
362 v2 = PG_GETARG_ARRAYTYPE_P(1);
363
364 element_type1 = ARR_ELEMTYPE(v1);
365 element_type2 = ARR_ELEMTYPE(v2);
366
367 /* Check we have matching element types */
368 if (element_type1 != element_type2)
370 (errcode(ERRCODE_DATATYPE_MISMATCH),
371 errmsg("cannot concatenate incompatible arrays"),
372 errdetail("Arrays with element types %s and %s are not "
373 "compatible for concatenation.",
374 format_type_be(element_type1),
375 format_type_be(element_type2))));
376
377 /* OK, use it */
378 element_type = element_type1;
379
380 /*----------
381 * We must have one of the following combinations of inputs:
382 * 1) one empty array, and one non-empty array
383 * 2) both arrays empty
384 * 3) two arrays with ndims1 == ndims2
385 * 4) ndims1 == ndims2 - 1
386 * 5) ndims1 == ndims2 + 1
387 *----------
388 */
389 ndims1 = ARR_NDIM(v1);
390 ndims2 = ARR_NDIM(v2);
391
392 /*
393 * short circuit - if one input array is empty, and the other is not, we
394 * return the non-empty one as the result
395 *
396 * if both are empty, return the first one
397 */
398 if (ndims1 == 0 && ndims2 > 0)
400
401 if (ndims2 == 0)
403
404 /* the rest fall under rule 3, 4, or 5 */
405 if (ndims1 != ndims2 &&
406 ndims1 != ndims2 - 1 &&
407 ndims1 != ndims2 + 1)
409 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
410 errmsg("cannot concatenate incompatible arrays"),
411 errdetail("Arrays of %d and %d dimensions are not "
412 "compatible for concatenation.",
413 ndims1, ndims2)));
414
415 /* get argument array details */
416 lbs1 = ARR_LBOUND(v1);
417 lbs2 = ARR_LBOUND(v2);
418 dims1 = ARR_DIMS(v1);
419 dims2 = ARR_DIMS(v2);
420 dat1 = ARR_DATA_PTR(v1);
421 dat2 = ARR_DATA_PTR(v2);
422 bitmap1 = ARR_NULLBITMAP(v1);
423 bitmap2 = ARR_NULLBITMAP(v2);
424 nitems1 = ArrayGetNItems(ndims1, dims1);
425 nitems2 = ArrayGetNItems(ndims2, dims2);
426 ndatabytes1 = ARR_SIZE(v1) - ARR_DATA_OFFSET(v1);
427 ndatabytes2 = ARR_SIZE(v2) - ARR_DATA_OFFSET(v2);
428
429 if (ndims1 == ndims2)
430 {
431 /*
432 * resulting array is made up of the elements (possibly arrays
433 * themselves) of the input argument arrays
434 */
435 ndims = ndims1;
436 dims = (int *) palloc(ndims * sizeof(int));
437 lbs = (int *) palloc(ndims * sizeof(int));
438
439 dims[0] = dims1[0] + dims2[0];
440 lbs[0] = lbs1[0];
441
442 for (i = 1; i < ndims; i++)
443 {
444 if (dims1[i] != dims2[i] || lbs1[i] != lbs2[i])
446 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
447 errmsg("cannot concatenate incompatible arrays"),
448 errdetail("Arrays with differing element dimensions are "
449 "not compatible for concatenation.")));
450
451 dims[i] = dims1[i];
452 lbs[i] = lbs1[i];
453 }
454 }
455 else if (ndims1 == ndims2 - 1)
456 {
457 /*
458 * resulting array has the second argument as the outer array, with
459 * the first argument inserted at the front of the outer dimension
460 */
461 ndims = ndims2;
462 dims = (int *) palloc(ndims * sizeof(int));
463 lbs = (int *) palloc(ndims * sizeof(int));
464 memcpy(dims, dims2, ndims * sizeof(int));
465 memcpy(lbs, lbs2, ndims * sizeof(int));
466
467 /* increment number of elements in outer array */
468 dims[0] += 1;
469
470 /* make sure the added element matches our existing elements */
471 for (i = 0; i < ndims1; i++)
472 {
473 if (dims1[i] != dims[i + 1] || lbs1[i] != lbs[i + 1])
475 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
476 errmsg("cannot concatenate incompatible arrays"),
477 errdetail("Arrays with differing dimensions are not "
478 "compatible for concatenation.")));
479 }
480 }
481 else
482 {
483 /*
484 * (ndims1 == ndims2 + 1)
485 *
486 * resulting array has the first argument as the outer array, with the
487 * second argument appended to the end of the outer dimension
488 */
489 ndims = ndims1;
490 dims = (int *) palloc(ndims * sizeof(int));
491 lbs = (int *) palloc(ndims * sizeof(int));
492 memcpy(dims, dims1, ndims * sizeof(int));
493 memcpy(lbs, lbs1, ndims * sizeof(int));
494
495 /* increment number of elements in outer array */
496 dims[0] += 1;
497
498 /* make sure the added element matches our existing elements */
499 for (i = 0; i < ndims2; i++)
500 {
501 if (dims2[i] != dims[i + 1] || lbs2[i] != lbs[i + 1])
503 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
504 errmsg("cannot concatenate incompatible arrays"),
505 errdetail("Arrays with differing dimensions are not "
506 "compatible for concatenation.")));
507 }
508 }
509
510 /* Do this mainly for overflow checking */
511 nitems = ArrayGetNItems(ndims, dims);
512 ArrayCheckBounds(ndims, dims, lbs);
513
514 /* build the result array */
515 ndatabytes = ndatabytes1 + ndatabytes2;
516 if (ARR_HASNULL(v1) || ARR_HASNULL(v2))
517 {
518 dataoffset = ARR_OVERHEAD_WITHNULLS(ndims, nitems);
519 nbytes = ndatabytes + dataoffset;
520 }
521 else
522 {
523 dataoffset = 0; /* marker for no null bitmap */
524 nbytes = ndatabytes + ARR_OVERHEAD_NONULLS(ndims);
525 }
526 result = (ArrayType *) palloc0(nbytes);
527 SET_VARSIZE(result, nbytes);
528 result->ndim = ndims;
529 result->dataoffset = dataoffset;
530 result->elemtype = element_type;
531 memcpy(ARR_DIMS(result), dims, ndims * sizeof(int));
532 memcpy(ARR_LBOUND(result), lbs, ndims * sizeof(int));
533 /* data area is arg1 then arg2 */
534 memcpy(ARR_DATA_PTR(result), dat1, ndatabytes1);
535 memcpy(ARR_DATA_PTR(result) + ndatabytes1, dat2, ndatabytes2);
536 /* handle the null bitmap if needed */
537 if (ARR_HASNULL(result))
538 {
540 bitmap1, 0,
541 nitems1);
542 array_bitmap_copy(ARR_NULLBITMAP(result), nitems1,
543 bitmap2, 0,
544 nitems2);
545 }
546
547 PG_RETURN_ARRAYTYPE_P(result);
548}
549
550
551/*
552 * ARRAY_AGG(anynonarray) aggregate function
553 */
554Datum
556{
557 Oid arg1_typeid = get_fn_expr_argtype(fcinfo->flinfo, 1);
558 MemoryContext aggcontext;
560 Datum elem;
561
562 if (arg1_typeid == InvalidOid)
564 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
565 errmsg("could not determine input data type")));
566
567 /*
568 * Note: we do not need a run-time check about whether arg1_typeid is a
569 * valid array element type, because the parser would have verified that
570 * while resolving the input/result types of this polymorphic aggregate.
571 */
572
573 if (!AggCheckCallContext(fcinfo, &aggcontext))
574 {
575 /* cannot be called directly because of internal-type argument */
576 elog(ERROR, "array_agg_transfn called in non-aggregate context");
577 }
578
579 if (PG_ARGISNULL(0))
580 state = initArrayResult(arg1_typeid, aggcontext, false);
581 else
583
584 elem = PG_ARGISNULL(1) ? (Datum) 0 : PG_GETARG_DATUM(1);
585
587 elem,
588 PG_ARGISNULL(1),
589 arg1_typeid,
590 aggcontext);
591
592 /*
593 * The transition type for array_agg() is declared to be "internal", which
594 * is a pass-by-value type the same size as a pointer. So we can safely
595 * pass the ArrayBuildState pointer through nodeAgg.c's machinations.
596 */
598}
599
600Datum
602{
603 ArrayBuildState *state1;
604 ArrayBuildState *state2;
605 MemoryContext agg_context;
606 MemoryContext old_context;
607
608 if (!AggCheckCallContext(fcinfo, &agg_context))
609 elog(ERROR, "aggregate function called in non-aggregate context");
610
611 state1 = PG_ARGISNULL(0) ? NULL : (ArrayBuildState *) PG_GETARG_POINTER(0);
612 state2 = PG_ARGISNULL(1) ? NULL : (ArrayBuildState *) PG_GETARG_POINTER(1);
613
614 if (state2 == NULL)
615 {
616 /*
617 * NULL state2 is easy, just return state1, which we know is already
618 * in the agg_context
619 */
620 if (state1 == NULL)
622 PG_RETURN_POINTER(state1);
623 }
624
625 if (state1 == NULL)
626 {
627 /* We must copy state2's data into the agg_context */
628 state1 = initArrayResultWithSize(state2->element_type, agg_context,
629 false, state2->alen);
630
631 old_context = MemoryContextSwitchTo(agg_context);
632
633 for (int i = 0; i < state2->nelems; i++)
634 {
635 if (!state2->dnulls[i])
636 state1->dvalues[i] = datumCopy(state2->dvalues[i],
637 state1->typbyval,
638 state1->typlen);
639 else
640 state1->dvalues[i] = (Datum) 0;
641 }
642
643 MemoryContextSwitchTo(old_context);
644
645 memcpy(state1->dnulls, state2->dnulls, sizeof(bool) * state2->nelems);
646
647 state1->nelems = state2->nelems;
648
649 PG_RETURN_POINTER(state1);
650 }
651 else if (state2->nelems > 0)
652 {
653 /* We only need to combine the two states if state2 has any elements */
654 int reqsize = state1->nelems + state2->nelems;
655 MemoryContext oldContext = MemoryContextSwitchTo(state1->mcontext);
656
657 Assert(state1->element_type == state2->element_type);
658
659 /* Enlarge state1 arrays if needed */
660 if (state1->alen < reqsize)
661 {
662 /* Use a power of 2 size rather than allocating just reqsize */
663 state1->alen = pg_nextpower2_32(reqsize);
664 state1->dvalues = (Datum *) repalloc(state1->dvalues,
665 state1->alen * sizeof(Datum));
666 state1->dnulls = (bool *) repalloc(state1->dnulls,
667 state1->alen * sizeof(bool));
668 }
669
670 /* Copy in the state2 elements to the end of the state1 arrays */
671 for (int i = 0; i < state2->nelems; i++)
672 {
673 if (!state2->dnulls[i])
674 state1->dvalues[i + state1->nelems] =
675 datumCopy(state2->dvalues[i],
676 state1->typbyval,
677 state1->typlen);
678 else
679 state1->dvalues[i + state1->nelems] = (Datum) 0;
680 }
681
682 memcpy(&state1->dnulls[state1->nelems], state2->dnulls,
683 sizeof(bool) * state2->nelems);
684
685 state1->nelems = reqsize;
686
687 MemoryContextSwitchTo(oldContext);
688 }
689
690 PG_RETURN_POINTER(state1);
691}
692
693/*
694 * array_agg_serialize
695 * Serialize ArrayBuildState into bytea.
696 */
697Datum
699{
702 bytea *result;
703
704 /* cannot be called directly because of internal-type argument */
705 Assert(AggCheckCallContext(fcinfo, NULL));
706
708
710
711 /*
712 * element_type. Putting this first is more convenient in deserialization
713 */
714 pq_sendint32(&buf, state->element_type);
715
716 /*
717 * nelems -- send first so we know how large to make the dvalues and
718 * dnulls array during deserialization.
719 */
720 pq_sendint64(&buf, state->nelems);
721
722 /* alen can be decided during deserialization */
723
724 /* typlen */
725 pq_sendint16(&buf, state->typlen);
726
727 /* typbyval */
728 pq_sendbyte(&buf, state->typbyval);
729
730 /* typalign */
731 pq_sendbyte(&buf, state->typalign);
732
733 /* dnulls */
734 pq_sendbytes(&buf, state->dnulls, sizeof(bool) * state->nelems);
735
736 /*
737 * dvalues. By agreement with array_agg_deserialize, when the element
738 * type is byval, we just transmit the Datum array as-is, including any
739 * null elements. For by-ref types, we must invoke the element type's
740 * send function, and we skip null elements (which is why the nulls flags
741 * must be sent first).
742 */
743 if (state->typbyval)
744 pq_sendbytes(&buf, state->dvalues, sizeof(Datum) * state->nelems);
745 else
746 {
747 SerialIOData *iodata;
748 int i;
749
750 /* Avoid repeat catalog lookups for typsend function */
751 iodata = (SerialIOData *) fcinfo->flinfo->fn_extra;
752 if (iodata == NULL)
753 {
754 Oid typsend;
755 bool typisvarlena;
756
757 iodata = (SerialIOData *)
758 MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
759 sizeof(SerialIOData));
760 getTypeBinaryOutputInfo(state->element_type, &typsend,
761 &typisvarlena);
762 fmgr_info_cxt(typsend, &iodata->typsend,
763 fcinfo->flinfo->fn_mcxt);
764 fcinfo->flinfo->fn_extra = iodata;
765 }
766
767 for (i = 0; i < state->nelems; i++)
768 {
769 bytea *outputbytes;
770
771 if (state->dnulls[i])
772 continue;
773 outputbytes = SendFunctionCall(&iodata->typsend,
774 state->dvalues[i]);
775 pq_sendint32(&buf, VARSIZE(outputbytes) - VARHDRSZ);
776 pq_sendbytes(&buf, VARDATA(outputbytes),
777 VARSIZE(outputbytes) - VARHDRSZ);
778 }
779 }
780
781 result = pq_endtypsend(&buf);
782
783 PG_RETURN_BYTEA_P(result);
784}
785
786Datum
788{
789 bytea *sstate;
790 ArrayBuildState *result;
792 Oid element_type;
793 int64 nelems;
794 const char *temp;
795
796 if (!AggCheckCallContext(fcinfo, NULL))
797 elog(ERROR, "aggregate function called in non-aggregate context");
798
799 sstate = PG_GETARG_BYTEA_PP(0);
800
801 /*
802 * Initialize a StringInfo so that we can "receive" it using the standard
803 * recv-function infrastructure.
804 */
806 VARSIZE_ANY_EXHDR(sstate));
807
808 /* element_type */
809 element_type = pq_getmsgint(&buf, 4);
810
811 /* nelems */
812 nelems = pq_getmsgint64(&buf);
813
814 /* Create output ArrayBuildState with the needed number of elements */
815 result = initArrayResultWithSize(element_type, CurrentMemoryContext,
816 false, nelems);
817 result->nelems = nelems;
818
819 /* typlen */
820 result->typlen = pq_getmsgint(&buf, 2);
821
822 /* typbyval */
823 result->typbyval = pq_getmsgbyte(&buf);
824
825 /* typalign */
826 result->typalign = pq_getmsgbyte(&buf);
827
828 /* dnulls */
829 temp = pq_getmsgbytes(&buf, sizeof(bool) * nelems);
830 memcpy(result->dnulls, temp, sizeof(bool) * nelems);
831
832 /* dvalues --- see comment in array_agg_serialize */
833 if (result->typbyval)
834 {
835 temp = pq_getmsgbytes(&buf, sizeof(Datum) * nelems);
836 memcpy(result->dvalues, temp, sizeof(Datum) * nelems);
837 }
838 else
839 {
840 DeserialIOData *iodata;
841
842 /* Avoid repeat catalog lookups for typreceive function */
843 iodata = (DeserialIOData *) fcinfo->flinfo->fn_extra;
844 if (iodata == NULL)
845 {
846 Oid typreceive;
847
848 iodata = (DeserialIOData *)
849 MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
850 sizeof(DeserialIOData));
851 getTypeBinaryInputInfo(element_type, &typreceive,
852 &iodata->typioparam);
853 fmgr_info_cxt(typreceive, &iodata->typreceive,
854 fcinfo->flinfo->fn_mcxt);
855 fcinfo->flinfo->fn_extra = iodata;
856 }
857
858 for (int i = 0; i < nelems; i++)
859 {
860 int itemlen;
861 StringInfoData elem_buf;
862
863 if (result->dnulls[i])
864 {
865 result->dvalues[i] = (Datum) 0;
866 continue;
867 }
868
869 itemlen = pq_getmsgint(&buf, 4);
870 if (itemlen < 0 || itemlen > (buf.len - buf.cursor))
872 (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
873 errmsg("insufficient data left in message")));
874
875 /*
876 * Rather than copying data around, we just initialize a
877 * StringInfo pointing to the correct portion of the message
878 * buffer.
879 */
880 initReadOnlyStringInfo(&elem_buf, &buf.data[buf.cursor], itemlen);
881
882 buf.cursor += itemlen;
883
884 /* Now call the element's receiveproc */
885 result->dvalues[i] = ReceiveFunctionCall(&iodata->typreceive,
886 &elem_buf,
887 iodata->typioparam,
888 -1);
889 }
890 }
891
893
894 PG_RETURN_POINTER(result);
895}
896
897Datum
899{
900 Datum result;
902 int dims[1];
903 int lbs[1];
904
905 /* cannot be called directly because of internal-type argument */
906 Assert(AggCheckCallContext(fcinfo, NULL));
907
909
910 if (state == NULL)
911 PG_RETURN_NULL(); /* returns null iff no input values */
912
913 dims[0] = state->nelems;
914 lbs[0] = 1;
915
916 /*
917 * Make the result. We cannot release the ArrayBuildState because
918 * sometimes aggregate final functions are re-executed. Rather, it is
919 * nodeAgg.c's responsibility to reset the aggcontext when it's safe to do
920 * so.
921 */
922 result = makeMdArrayResult(state, 1, dims, lbs,
924 false);
925
926 PG_RETURN_DATUM(result);
927}
928
929/*
930 * ARRAY_AGG(anyarray) aggregate function
931 */
932Datum
934{
935 Oid arg1_typeid = get_fn_expr_argtype(fcinfo->flinfo, 1);
936 MemoryContext aggcontext;
938
939 if (arg1_typeid == InvalidOid)
941 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
942 errmsg("could not determine input data type")));
943
944 /*
945 * Note: we do not need a run-time check about whether arg1_typeid is a
946 * valid array type, because the parser would have verified that while
947 * resolving the input/result types of this polymorphic aggregate.
948 */
949
950 if (!AggCheckCallContext(fcinfo, &aggcontext))
951 {
952 /* cannot be called directly because of internal-type argument */
953 elog(ERROR, "array_agg_array_transfn called in non-aggregate context");
954 }
955
956
957 if (PG_ARGISNULL(0))
958 state = initArrayResultArr(arg1_typeid, InvalidOid, aggcontext, false);
959 else
961
964 PG_ARGISNULL(1),
965 arg1_typeid,
966 aggcontext);
967
968 /*
969 * The transition type for array_agg() is declared to be "internal", which
970 * is a pass-by-value type the same size as a pointer. So we can safely
971 * pass the ArrayBuildStateArr pointer through nodeAgg.c's machinations.
972 */
974}
975
976Datum
978{
979 ArrayBuildStateArr *state1;
980 ArrayBuildStateArr *state2;
981 MemoryContext agg_context;
982 MemoryContext old_context;
983
984 if (!AggCheckCallContext(fcinfo, &agg_context))
985 elog(ERROR, "aggregate function called in non-aggregate context");
986
987 state1 = PG_ARGISNULL(0) ? NULL : (ArrayBuildStateArr *) PG_GETARG_POINTER(0);
988 state2 = PG_ARGISNULL(1) ? NULL : (ArrayBuildStateArr *) PG_GETARG_POINTER(1);
989
990 if (state2 == NULL)
991 {
992 /*
993 * NULL state2 is easy, just return state1, which we know is already
994 * in the agg_context
995 */
996 if (state1 == NULL)
998 PG_RETURN_POINTER(state1);
999 }
1000
1001 if (state1 == NULL)
1002 {
1003 /* We must copy state2's data into the agg_context */
1004 old_context = MemoryContextSwitchTo(agg_context);
1005
1006 state1 = initArrayResultArr(state2->array_type, InvalidOid,
1007 agg_context, false);
1008
1009 state1->abytes = state2->abytes;
1010 state1->data = (char *) palloc(state1->abytes);
1011
1012 if (state2->nullbitmap)
1013 {
1014 int size = (state2->aitems + 7) / 8;
1015
1016 state1->nullbitmap = (bits8 *) palloc(size);
1017 memcpy(state1->nullbitmap, state2->nullbitmap, size);
1018 }
1019
1020 memcpy(state1->data, state2->data, state2->nbytes);
1021 state1->nbytes = state2->nbytes;
1022 state1->aitems = state2->aitems;
1023 state1->nitems = state2->nitems;
1024 state1->ndims = state2->ndims;
1025 memcpy(state1->dims, state2->dims, sizeof(state2->dims));
1026 memcpy(state1->lbs, state2->lbs, sizeof(state2->lbs));
1027 state1->array_type = state2->array_type;
1028 state1->element_type = state2->element_type;
1029
1030 MemoryContextSwitchTo(old_context);
1031
1032 PG_RETURN_POINTER(state1);
1033 }
1034
1035 /* We only need to combine the two states if state2 has any items */
1036 else if (state2->nitems > 0)
1037 {
1038 MemoryContext oldContext;
1039 int reqsize = state1->nbytes + state2->nbytes;
1040 int i;
1041
1042 /*
1043 * Check the states are compatible with each other. Ensure we use the
1044 * same error messages that are listed in accumArrayResultArr so that
1045 * the same error is shown as would have been if we'd not used the
1046 * combine function for the aggregation.
1047 */
1048 if (state1->ndims != state2->ndims)
1049 ereport(ERROR,
1050 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
1051 errmsg("cannot accumulate arrays of different dimensionality")));
1052
1053 /* Check dimensions match ignoring the first dimension. */
1054 for (i = 1; i < state1->ndims; i++)
1055 {
1056 if (state1->dims[i] != state2->dims[i] || state1->lbs[i] != state2->lbs[i])
1057 ereport(ERROR,
1058 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
1059 errmsg("cannot accumulate arrays of different dimensionality")));
1060 }
1061
1062
1063 oldContext = MemoryContextSwitchTo(state1->mcontext);
1064
1065 /*
1066 * If there's not enough space in state1 then we'll need to reallocate
1067 * more.
1068 */
1069 if (state1->abytes < reqsize)
1070 {
1071 /* use a power of 2 size rather than allocating just reqsize */
1072 state1->abytes = pg_nextpower2_32(reqsize);
1073 state1->data = (char *) repalloc(state1->data, state1->abytes);
1074 }
1075
1076 if (state2->nullbitmap)
1077 {
1078 int newnitems = state1->nitems + state2->nitems;
1079
1080 if (state1->nullbitmap == NULL)
1081 {
1082 /*
1083 * First input with nulls; we must retrospectively handle any
1084 * previous inputs by marking all their items non-null.
1085 */
1086 state1->aitems = pg_nextpower2_32(Max(256, newnitems + 1));
1087 state1->nullbitmap = (bits8 *) palloc((state1->aitems + 7) / 8);
1088 array_bitmap_copy(state1->nullbitmap, 0,
1089 NULL, 0,
1090 state1->nitems);
1091 }
1092 else if (newnitems > state1->aitems)
1093 {
1094 int newaitems = state1->aitems + state2->aitems;
1095
1096 state1->aitems = pg_nextpower2_32(newaitems);
1097 state1->nullbitmap = (bits8 *)
1098 repalloc(state1->nullbitmap, (state1->aitems + 7) / 8);
1099 }
1100 array_bitmap_copy(state1->nullbitmap, state1->nitems,
1101 state2->nullbitmap, 0,
1102 state2->nitems);
1103 }
1104
1105 memcpy(state1->data + state1->nbytes, state2->data, state2->nbytes);
1106 state1->nbytes += state2->nbytes;
1107 state1->nitems += state2->nitems;
1108
1109 state1->dims[0] += state2->dims[0];
1110 /* remaining dims already match, per test above */
1111
1112 Assert(state1->array_type == state2->array_type);
1113 Assert(state1->element_type == state2->element_type);
1114
1115 MemoryContextSwitchTo(oldContext);
1116 }
1117
1118 PG_RETURN_POINTER(state1);
1119}
1120
1121/*
1122 * array_agg_array_serialize
1123 * Serialize ArrayBuildStateArr into bytea.
1124 */
1125Datum
1127{
1130 bytea *result;
1131
1132 /* cannot be called directly because of internal-type argument */
1133 Assert(AggCheckCallContext(fcinfo, NULL));
1134
1136
1138
1139 /*
1140 * element_type. Putting this first is more convenient in deserialization
1141 * so that we can init the new state sooner.
1142 */
1143 pq_sendint32(&buf, state->element_type);
1144
1145 /* array_type */
1146 pq_sendint32(&buf, state->array_type);
1147
1148 /* nbytes */
1149 pq_sendint32(&buf, state->nbytes);
1150
1151 /* data */
1152 pq_sendbytes(&buf, state->data, state->nbytes);
1153
1154 /* abytes */
1155 pq_sendint32(&buf, state->abytes);
1156
1157 /* aitems */
1158 pq_sendint32(&buf, state->aitems);
1159
1160 /* nullbitmap */
1161 if (state->nullbitmap)
1162 {
1163 Assert(state->aitems > 0);
1164 pq_sendbytes(&buf, state->nullbitmap, (state->aitems + 7) / 8);
1165 }
1166
1167 /* nitems */
1168 pq_sendint32(&buf, state->nitems);
1169
1170 /* ndims */
1171 pq_sendint32(&buf, state->ndims);
1172
1173 /* dims: XXX should we just send ndims elements? */
1174 pq_sendbytes(&buf, state->dims, sizeof(state->dims));
1175
1176 /* lbs */
1177 pq_sendbytes(&buf, state->lbs, sizeof(state->lbs));
1178
1179 result = pq_endtypsend(&buf);
1180
1181 PG_RETURN_BYTEA_P(result);
1182}
1183
1184Datum
1186{
1187 bytea *sstate;
1188 ArrayBuildStateArr *result;
1190 Oid element_type;
1191 Oid array_type;
1192 int nbytes;
1193 const char *temp;
1194
1195 /* cannot be called directly because of internal-type argument */
1196 Assert(AggCheckCallContext(fcinfo, NULL));
1197
1198 sstate = PG_GETARG_BYTEA_PP(0);
1199
1200 /*
1201 * Initialize a StringInfo so that we can "receive" it using the standard
1202 * recv-function infrastructure.
1203 */
1205 VARSIZE_ANY_EXHDR(sstate));
1206
1207 /* element_type */
1208 element_type = pq_getmsgint(&buf, 4);
1209
1210 /* array_type */
1211 array_type = pq_getmsgint(&buf, 4);
1212
1213 /* nbytes */
1214 nbytes = pq_getmsgint(&buf, 4);
1215
1216 result = initArrayResultArr(array_type, element_type,
1217 CurrentMemoryContext, false);
1218
1219 result->abytes = 1024;
1220 while (result->abytes < nbytes)
1221 result->abytes *= 2;
1222
1223 result->data = (char *) palloc(result->abytes);
1224
1225 /* data */
1226 temp = pq_getmsgbytes(&buf, nbytes);
1227 memcpy(result->data, temp, nbytes);
1228 result->nbytes = nbytes;
1229
1230 /* abytes */
1231 result->abytes = pq_getmsgint(&buf, 4);
1232
1233 /* aitems: might be 0 */
1234 result->aitems = pq_getmsgint(&buf, 4);
1235
1236 /* nullbitmap */
1237 if (result->aitems > 0)
1238 {
1239 int size = (result->aitems + 7) / 8;
1240
1241 result->nullbitmap = (bits8 *) palloc(size);
1242 temp = pq_getmsgbytes(&buf, size);
1243 memcpy(result->nullbitmap, temp, size);
1244 }
1245 else
1246 result->nullbitmap = NULL;
1247
1248 /* nitems */
1249 result->nitems = pq_getmsgint(&buf, 4);
1250
1251 /* ndims */
1252 result->ndims = pq_getmsgint(&buf, 4);
1253
1254 /* dims */
1255 temp = pq_getmsgbytes(&buf, sizeof(result->dims));
1256 memcpy(result->dims, temp, sizeof(result->dims));
1257
1258 /* lbs */
1259 temp = pq_getmsgbytes(&buf, sizeof(result->lbs));
1260 memcpy(result->lbs, temp, sizeof(result->lbs));
1261
1262 pq_getmsgend(&buf);
1263
1264 PG_RETURN_POINTER(result);
1265}
1266
1267Datum
1269{
1270 Datum result;
1272
1273 /* cannot be called directly because of internal-type argument */
1274 Assert(AggCheckCallContext(fcinfo, NULL));
1275
1277
1278 if (state == NULL)
1279 PG_RETURN_NULL(); /* returns null iff no input values */
1280
1281 /*
1282 * Make the result. We cannot release the ArrayBuildStateArr because
1283 * sometimes aggregate final functions are re-executed. Rather, it is
1284 * nodeAgg.c's responsibility to reset the aggcontext when it's safe to do
1285 * so.
1286 */
1288
1289 PG_RETURN_DATUM(result);
1290}
1291
1292/*-----------------------------------------------------------------------------
1293 * array_position, array_position_start :
1294 * return the offset of a value in an array.
1295 *
1296 * IS NOT DISTINCT FROM semantics are used for comparisons. Return NULL when
1297 * the value is not found.
1298 *-----------------------------------------------------------------------------
1299 */
1300Datum
1302{
1303 return array_position_common(fcinfo);
1304}
1305
1306Datum
1308{
1309 return array_position_common(fcinfo);
1310}
1311
1312/*
1313 * array_position_common
1314 * Common code for array_position and array_position_start
1315 *
1316 * These are separate wrappers for the sake of opr_sanity regression test.
1317 * They are not strict so we have to test for null inputs explicitly.
1318 */
1319static Datum
1321{
1322 ArrayType *array;
1323 Oid collation = PG_GET_COLLATION();
1324 Oid element_type;
1325 Datum searched_element,
1326 value;
1327 bool isnull;
1328 int position,
1329 position_min;
1330 bool found = false;
1331 TypeCacheEntry *typentry;
1332 ArrayMetaState *my_extra;
1333 bool null_search;
1335
1336 if (PG_ARGISNULL(0))
1338
1339 array = PG_GETARG_ARRAYTYPE_P(0);
1340
1341 /*
1342 * We refuse to search for elements in multi-dimensional arrays, since we
1343 * have no good way to report the element's location in the array.
1344 */
1345 if (ARR_NDIM(array) > 1)
1346 ereport(ERROR,
1347 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1348 errmsg("searching for elements in multidimensional arrays is not supported")));
1349
1350 /* Searching in an empty array is well-defined, though: it always fails */
1351 if (ARR_NDIM(array) < 1)
1353
1354 if (PG_ARGISNULL(1))
1355 {
1356 /* fast return when the array doesn't have nulls */
1357 if (!array_contains_nulls(array))
1359 searched_element = (Datum) 0;
1360 null_search = true;
1361 }
1362 else
1363 {
1364 searched_element = PG_GETARG_DATUM(1);
1365 null_search = false;
1366 }
1367
1368 element_type = ARR_ELEMTYPE(array);
1369 position = (ARR_LBOUND(array))[0] - 1;
1370
1371 /* figure out where to start */
1372 if (PG_NARGS() == 3)
1373 {
1374 if (PG_ARGISNULL(2))
1375 ereport(ERROR,
1376 (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
1377 errmsg("initial position must not be null")));
1378
1379 position_min = PG_GETARG_INT32(2);
1380 }
1381 else
1382 position_min = (ARR_LBOUND(array))[0];
1383
1384 /*
1385 * We arrange to look up type info for array_create_iterator only once per
1386 * series of calls, assuming the element type doesn't change underneath
1387 * us.
1388 */
1389 my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra;
1390 if (my_extra == NULL)
1391 {
1392 fcinfo->flinfo->fn_extra = MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
1393 sizeof(ArrayMetaState));
1394 my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra;
1395 my_extra->element_type = ~element_type;
1396 }
1397
1398 if (my_extra->element_type != element_type)
1399 {
1400 get_typlenbyvalalign(element_type,
1401 &my_extra->typlen,
1402 &my_extra->typbyval,
1403 &my_extra->typalign);
1404
1405 typentry = lookup_type_cache(element_type, TYPECACHE_EQ_OPR_FINFO);
1406
1407 if (!OidIsValid(typentry->eq_opr_finfo.fn_oid))
1408 ereport(ERROR,
1409 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1410 errmsg("could not identify an equality operator for type %s",
1411 format_type_be(element_type))));
1412
1413 my_extra->element_type = element_type;
1414 fmgr_info_cxt(typentry->eq_opr_finfo.fn_oid, &my_extra->proc,
1415 fcinfo->flinfo->fn_mcxt);
1416 }
1417
1418 /* Examine each array element until we find a match. */
1419 array_iterator = array_create_iterator(array, 0, my_extra);
1420 while (array_iterate(array_iterator, &value, &isnull))
1421 {
1422 position++;
1423
1424 /* skip initial elements if caller requested so */
1425 if (position < position_min)
1426 continue;
1427
1428 /*
1429 * Can't look at the array element's value if it's null; but if we
1430 * search for null, we have a hit and are done.
1431 */
1432 if (isnull || null_search)
1433 {
1434 if (isnull && null_search)
1435 {
1436 found = true;
1437 break;
1438 }
1439 else
1440 continue;
1441 }
1442
1443 /* not nulls, so run the operator */
1444 if (DatumGetBool(FunctionCall2Coll(&my_extra->proc, collation,
1445 searched_element, value)))
1446 {
1447 found = true;
1448 break;
1449 }
1450 }
1451
1453
1454 /* Avoid leaking memory when handed toasted input */
1455 PG_FREE_IF_COPY(array, 0);
1456
1457 if (!found)
1459
1460 PG_RETURN_INT32(position);
1461}
1462
1463/*-----------------------------------------------------------------------------
1464 * array_positions :
1465 * return an array of positions of a value in an array.
1466 *
1467 * IS NOT DISTINCT FROM semantics are used for comparisons. Returns NULL when
1468 * the input array is NULL. When the value is not found in the array, returns
1469 * an empty array.
1470 *
1471 * This is not strict so we have to test for null inputs explicitly.
1472 *-----------------------------------------------------------------------------
1473 */
1474Datum
1476{
1477 ArrayType *array;
1478 Oid collation = PG_GET_COLLATION();
1479 Oid element_type;
1480 Datum searched_element,
1481 value;
1482 bool isnull;
1483 int position;
1484 TypeCacheEntry *typentry;
1485 ArrayMetaState *my_extra;
1486 bool null_search;
1488 ArrayBuildState *astate = NULL;
1489
1490 if (PG_ARGISNULL(0))
1492
1493 array = PG_GETARG_ARRAYTYPE_P(0);
1494
1495 /*
1496 * We refuse to search for elements in multi-dimensional arrays, since we
1497 * have no good way to report the element's location in the array.
1498 */
1499 if (ARR_NDIM(array) > 1)
1500 ereport(ERROR,
1501 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1502 errmsg("searching for elements in multidimensional arrays is not supported")));
1503
1504 astate = initArrayResult(INT4OID, CurrentMemoryContext, false);
1505
1506 /* Searching in an empty array is well-defined, though: it always fails */
1507 if (ARR_NDIM(array) < 1)
1509
1510 if (PG_ARGISNULL(1))
1511 {
1512 /* fast return when the array doesn't have nulls */
1513 if (!array_contains_nulls(array))
1515 searched_element = (Datum) 0;
1516 null_search = true;
1517 }
1518 else
1519 {
1520 searched_element = PG_GETARG_DATUM(1);
1521 null_search = false;
1522 }
1523
1524 element_type = ARR_ELEMTYPE(array);
1525 position = (ARR_LBOUND(array))[0] - 1;
1526
1527 /*
1528 * We arrange to look up type info for array_create_iterator only once per
1529 * series of calls, assuming the element type doesn't change underneath
1530 * us.
1531 */
1532 my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra;
1533 if (my_extra == NULL)
1534 {
1535 fcinfo->flinfo->fn_extra = MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
1536 sizeof(ArrayMetaState));
1537 my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra;
1538 my_extra->element_type = ~element_type;
1539 }
1540
1541 if (my_extra->element_type != element_type)
1542 {
1543 get_typlenbyvalalign(element_type,
1544 &my_extra->typlen,
1545 &my_extra->typbyval,
1546 &my_extra->typalign);
1547
1548 typentry = lookup_type_cache(element_type, TYPECACHE_EQ_OPR_FINFO);
1549
1550 if (!OidIsValid(typentry->eq_opr_finfo.fn_oid))
1551 ereport(ERROR,
1552 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1553 errmsg("could not identify an equality operator for type %s",
1554 format_type_be(element_type))));
1555
1556 my_extra->element_type = element_type;
1557 fmgr_info_cxt(typentry->eq_opr_finfo.fn_oid, &my_extra->proc,
1558 fcinfo->flinfo->fn_mcxt);
1559 }
1560
1561 /*
1562 * Accumulate each array position iff the element matches the given
1563 * element.
1564 */
1565 array_iterator = array_create_iterator(array, 0, my_extra);
1566 while (array_iterate(array_iterator, &value, &isnull))
1567 {
1568 position += 1;
1569
1570 /*
1571 * Can't look at the array element's value if it's null; but if we
1572 * search for null, we have a hit.
1573 */
1574 if (isnull || null_search)
1575 {
1576 if (isnull && null_search)
1577 astate =
1578 accumArrayResult(astate, Int32GetDatum(position), false,
1579 INT4OID, CurrentMemoryContext);
1580
1581 continue;
1582 }
1583
1584 /* not nulls, so run the operator */
1585 if (DatumGetBool(FunctionCall2Coll(&my_extra->proc, collation,
1586 searched_element, value)))
1587 astate =
1588 accumArrayResult(astate, Int32GetDatum(position), false,
1589 INT4OID, CurrentMemoryContext);
1590 }
1591
1593
1594 /* Avoid leaking memory when handed toasted input */
1595 PG_FREE_IF_COPY(array, 0);
1596
1598}
1599
1600/*
1601 * array_shuffle_n
1602 * Return a copy of array with n randomly chosen items.
1603 *
1604 * The number of items must not exceed the size of the first dimension of the
1605 * array. We preserve the first dimension's lower bound if keep_lb,
1606 * else it's set to 1. Lower-order dimensions are preserved in any case.
1607 *
1608 * NOTE: it would be cleaner to look up the elmlen/elmbval/elmalign info
1609 * from the system catalogs, given only the elmtyp. However, the caller is
1610 * in a better position to cache this info across multiple calls.
1611 */
1612static ArrayType *
1613array_shuffle_n(ArrayType *array, int n, bool keep_lb,
1614 Oid elmtyp, TypeCacheEntry *typentry)
1615{
1616 ArrayType *result;
1617 int ndim,
1618 *dims,
1619 *lbs,
1620 nelm,
1621 nitem,
1622 rdims[MAXDIM],
1623 rlbs[MAXDIM];
1624 int16 elmlen;
1625 bool elmbyval;
1626 char elmalign;
1627 Datum *elms,
1628 *ielms;
1629 bool *nuls,
1630 *inuls;
1631
1632 ndim = ARR_NDIM(array);
1633 dims = ARR_DIMS(array);
1634 lbs = ARR_LBOUND(array);
1635
1636 elmlen = typentry->typlen;
1637 elmbyval = typentry->typbyval;
1638 elmalign = typentry->typalign;
1639
1640 /* If the target array is empty, exit fast */
1641 if (ndim < 1 || dims[0] < 1 || n < 1)
1642 return construct_empty_array(elmtyp);
1643
1644 deconstruct_array(array, elmtyp, elmlen, elmbyval, elmalign,
1645 &elms, &nuls, &nelm);
1646
1647 nitem = dims[0]; /* total number of items */
1648 nelm /= nitem; /* number of elements per item */
1649
1650 Assert(n <= nitem); /* else it's caller error */
1651
1652 /*
1653 * Shuffle array using Fisher-Yates algorithm. Scan the array and swap
1654 * current item (nelm datums starting at ielms) with a randomly chosen
1655 * later item (nelm datums starting at jelms) in each iteration. We can
1656 * stop once we've done n iterations; then first n items are the result.
1657 */
1658 ielms = elms;
1659 inuls = nuls;
1660 for (int i = 0; i < n; i++)
1661 {
1662 int j = (int) pg_prng_uint64_range(&pg_global_prng_state, i, nitem - 1) * nelm;
1663 Datum *jelms = elms + j;
1664 bool *jnuls = nuls + j;
1665
1666 /* Swap i'th and j'th items; advance ielms/inuls to next item */
1667 for (int k = 0; k < nelm; k++)
1668 {
1669 Datum elm = *ielms;
1670 bool nul = *inuls;
1671
1672 *ielms++ = *jelms;
1673 *inuls++ = *jnuls;
1674 *jelms++ = elm;
1675 *jnuls++ = nul;
1676 }
1677 }
1678
1679 /* Set up dimensions of the result */
1680 memcpy(rdims, dims, ndim * sizeof(int));
1681 memcpy(rlbs, lbs, ndim * sizeof(int));
1682 rdims[0] = n;
1683 if (!keep_lb)
1684 rlbs[0] = 1;
1685
1686 result = construct_md_array(elms, nuls, ndim, rdims, rlbs,
1687 elmtyp, elmlen, elmbyval, elmalign);
1688
1689 pfree(elms);
1690 pfree(nuls);
1691
1692 return result;
1693}
1694
1695/*
1696 * array_shuffle
1697 *
1698 * Returns an array with the same dimensions as the input array, with its
1699 * first-dimension elements in random order.
1700 */
1701Datum
1703{
1704 ArrayType *array = PG_GETARG_ARRAYTYPE_P(0);
1705 ArrayType *result;
1706 Oid elmtyp;
1707 TypeCacheEntry *typentry;
1708
1709 /*
1710 * There is no point in shuffling empty arrays or arrays with less than
1711 * two items.
1712 */
1713 if (ARR_NDIM(array) < 1 || ARR_DIMS(array)[0] < 2)
1714 PG_RETURN_ARRAYTYPE_P(array);
1715
1716 elmtyp = ARR_ELEMTYPE(array);
1717 typentry = (TypeCacheEntry *) fcinfo->flinfo->fn_extra;
1718 if (typentry == NULL || typentry->type_id != elmtyp)
1719 {
1720 typentry = lookup_type_cache(elmtyp, 0);
1721 fcinfo->flinfo->fn_extra = typentry;
1722 }
1723
1724 result = array_shuffle_n(array, ARR_DIMS(array)[0], true, elmtyp, typentry);
1725
1726 PG_RETURN_ARRAYTYPE_P(result);
1727}
1728
1729/*
1730 * array_sample
1731 *
1732 * Returns an array of n randomly chosen first-dimension elements
1733 * from the input array.
1734 */
1735Datum
1737{
1738 ArrayType *array = PG_GETARG_ARRAYTYPE_P(0);
1739 int n = PG_GETARG_INT32(1);
1740 ArrayType *result;
1741 Oid elmtyp;
1742 TypeCacheEntry *typentry;
1743 int nitem;
1744
1745 nitem = (ARR_NDIM(array) < 1) ? 0 : ARR_DIMS(array)[0];
1746
1747 if (n < 0 || n > nitem)
1748 ereport(ERROR,
1749 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1750 errmsg("sample size must be between 0 and %d", nitem)));
1751
1752 elmtyp = ARR_ELEMTYPE(array);
1753 typentry = (TypeCacheEntry *) fcinfo->flinfo->fn_extra;
1754 if (typentry == NULL || typentry->type_id != elmtyp)
1755 {
1756 typentry = lookup_type_cache(elmtyp, 0);
1757 fcinfo->flinfo->fn_extra = typentry;
1758 }
1759
1760 result = array_shuffle_n(array, n, false, elmtyp, typentry);
1761
1762 PG_RETURN_ARRAYTYPE_P(result);
1763}
1764
1765
1766/*
1767 * array_reverse_n
1768 * Return a copy of array with reversed items.
1769 *
1770 * NOTE: it would be cleaner to look up the elmlen/elmbval/elmalign info
1771 * from the system catalogs, given only the elmtyp. However, the caller is
1772 * in a better position to cache this info across multiple calls.
1773 */
1774static ArrayType *
1776{
1777 ArrayType *result;
1778 int ndim,
1779 *dims,
1780 *lbs,
1781 nelm,
1782 nitem,
1783 rdims[MAXDIM],
1784 rlbs[MAXDIM];
1785 int16 elmlen;
1786 bool elmbyval;
1787 char elmalign;
1788 Datum *elms,
1789 *ielms;
1790 bool *nuls,
1791 *inuls;
1792
1793 ndim = ARR_NDIM(array);
1794 dims = ARR_DIMS(array);
1795 lbs = ARR_LBOUND(array);
1796
1797 elmlen = typentry->typlen;
1798 elmbyval = typentry->typbyval;
1799 elmalign = typentry->typalign;
1800
1801 deconstruct_array(array, elmtyp, elmlen, elmbyval, elmalign,
1802 &elms, &nuls, &nelm);
1803
1804 nitem = dims[0]; /* total number of items */
1805 nelm /= nitem; /* number of elements per item */
1806
1807 /* Reverse the array */
1808 ielms = elms;
1809 inuls = nuls;
1810 for (int i = 0; i < nitem / 2; i++)
1811 {
1812 int j = (nitem - i - 1) * nelm;
1813 Datum *jelms = elms + j;
1814 bool *jnuls = nuls + j;
1815
1816 /* Swap i'th and j'th items; advance ielms/inuls to next item */
1817 for (int k = 0; k < nelm; k++)
1818 {
1819 Datum elm = *ielms;
1820 bool nul = *inuls;
1821
1822 *ielms++ = *jelms;
1823 *inuls++ = *jnuls;
1824 *jelms++ = elm;
1825 *jnuls++ = nul;
1826 }
1827 }
1828
1829 /* Set up dimensions of the result */
1830 memcpy(rdims, dims, ndim * sizeof(int));
1831 memcpy(rlbs, lbs, ndim * sizeof(int));
1832 rdims[0] = nitem;
1833
1834 result = construct_md_array(elms, nuls, ndim, rdims, rlbs,
1835 elmtyp, elmlen, elmbyval, elmalign);
1836
1837 pfree(elms);
1838 pfree(nuls);
1839
1840 return result;
1841}
1842
1843/*
1844 * array_reverse
1845 *
1846 * Returns an array with the same dimensions as the input array, with its
1847 * first-dimension elements in reverse order.
1848 */
1849Datum
1851{
1852 ArrayType *array = PG_GETARG_ARRAYTYPE_P(0);
1853 ArrayType *result;
1854 Oid elmtyp;
1855 TypeCacheEntry *typentry;
1856
1857 /*
1858 * There is no point in reversing empty arrays or arrays with less than
1859 * two items.
1860 */
1861 if (ARR_NDIM(array) < 1 || ARR_DIMS(array)[0] < 2)
1862 PG_RETURN_ARRAYTYPE_P(array);
1863
1864 elmtyp = ARR_ELEMTYPE(array);
1865 typentry = (TypeCacheEntry *) fcinfo->flinfo->fn_extra;
1866 if (typentry == NULL || typentry->type_id != elmtyp)
1867 {
1868 typentry = lookup_type_cache(elmtyp, 0);
1869 fcinfo->flinfo->fn_extra = (void *) typentry;
1870 }
1871
1872 result = array_reverse_n(array, elmtyp, typentry);
1873
1874 PG_RETURN_ARRAYTYPE_P(result);
1875}
1876
1877/*
1878 * array_sort
1879 *
1880 * Sorts the first dimension of the array.
1881 */
1882static ArrayType *
1883array_sort_internal(ArrayType *array, bool descending, bool nulls_first,
1884 FunctionCallInfo fcinfo)
1885{
1886 ArrayType *newarray;
1887 Oid collation = PG_GET_COLLATION();
1888 int ndim,
1889 *dims,
1890 *lbs;
1891 ArraySortCachedInfo *cache_info;
1892 Oid elmtyp;
1893 Oid sort_typ;
1894 Oid sort_opr;
1895 Tuplesortstate *tuplesortstate;
1897 Datum value;
1898 bool isnull;
1899 ArrayBuildStateAny *astate = NULL;
1900
1901 ndim = ARR_NDIM(array);
1902 dims = ARR_DIMS(array);
1903 lbs = ARR_LBOUND(array);
1904
1905 /* Quick exit if we don't need to sort */
1906 if (ndim < 1 || dims[0] < 2)
1907 return array;
1908
1909 /* Set up cache area if we didn't already */
1910 cache_info = (ArraySortCachedInfo *) fcinfo->flinfo->fn_extra;
1911 if (cache_info == NULL)
1912 {
1913 cache_info = (ArraySortCachedInfo *)
1915 sizeof(ArraySortCachedInfo));
1916 fcinfo->flinfo->fn_extra = cache_info;
1917 }
1918
1919 /* Fetch and cache required data if we don't have it */
1920 elmtyp = ARR_ELEMTYPE(array);
1921 if (elmtyp != cache_info->array_meta.element_type)
1922 {
1923 TypeCacheEntry *typentry;
1924
1925 typentry = lookup_type_cache(elmtyp,
1927 cache_info->array_meta.element_type = elmtyp;
1928 cache_info->array_meta.typlen = typentry->typlen;
1929 cache_info->array_meta.typbyval = typentry->typbyval;
1930 cache_info->array_meta.typalign = typentry->typalign;
1931 cache_info->elem_lt_opr = typentry->lt_opr;
1932 cache_info->elem_gt_opr = typentry->gt_opr;
1933 cache_info->array_type = typentry->typarray;
1934 }
1935
1936 /* Identify the sort operator to use */
1937 if (ndim == 1)
1938 {
1939 /* Need to sort the element type */
1940 sort_typ = elmtyp;
1941 sort_opr = (descending ? cache_info->elem_gt_opr : cache_info->elem_lt_opr);
1942 }
1943 else
1944 {
1945 /* Otherwise we're sorting arrays */
1946 sort_typ = cache_info->array_type;
1947 if (!OidIsValid(sort_typ))
1948 ereport(ERROR,
1949 (errcode(ERRCODE_UNDEFINED_OBJECT),
1950 errmsg("could not find array type for data type %s",
1951 format_type_be(elmtyp))));
1952 /* We know what operators to use for arrays */
1953 sort_opr = (descending ? ARRAY_GT_OP : ARRAY_LT_OP);
1954 }
1955
1956 /*
1957 * Fail if we don't know how to sort. The error message is chosen to
1958 * match what array_lt()/array_gt() will say in the multidimensional case.
1959 */
1960 if (!OidIsValid(sort_opr))
1961 ereport(ERROR,
1962 errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1963 errmsg("could not identify a comparison function for type %s",
1964 format_type_be(elmtyp)));
1965
1966 /* Put the things to be sorted (elements or sub-arrays) into a tuplesort */
1967 tuplesortstate = tuplesort_begin_datum(sort_typ,
1968 sort_opr,
1969 collation,
1970 nulls_first,
1971 work_mem,
1972 NULL,
1974
1975 array_iterator = array_create_iterator(array, ndim - 1,
1976 &cache_info->array_meta);
1977 while (array_iterate(array_iterator, &value, &isnull))
1978 {
1979 tuplesort_putdatum(tuplesortstate, value, isnull);
1980 }
1982
1983 /* Do the sort */
1984 tuplesort_performsort(tuplesortstate);
1985
1986 /* Extract results into a new array */
1987 while (tuplesort_getdatum(tuplesortstate, true, false, &value, &isnull, NULL))
1988 {
1989 astate = accumArrayResultAny(astate, value, isnull,
1990 sort_typ, CurrentMemoryContext);
1991 }
1992 tuplesort_end(tuplesortstate);
1993
1994 newarray = DatumGetArrayTypeP(makeArrayResultAny(astate,
1996 true));
1997
1998 /* Adjust lower bound to match the input */
1999 ARR_LBOUND(newarray)[0] = lbs[0];
2000
2001 return newarray;
2002}
2003
2004Datum
2006{
2007 ArrayType *array = PG_GETARG_ARRAYTYPE_P(0);
2008
2010 false,
2011 false,
2012 fcinfo));
2013}
2014
2015Datum
2017{
2018 ArrayType *array = PG_GETARG_ARRAYTYPE_P(0);
2019 bool descending = PG_GETARG_BOOL(1);
2020
2022 descending,
2023 descending,
2024 fcinfo));
2025}
2026
2027Datum
2029{
2030 ArrayType *array = PG_GETARG_ARRAYTYPE_P(0);
2031 bool descending = PG_GETARG_BOOL(1);
2032 bool nulls_first = PG_GETARG_BOOL(2);
2033
2035 descending,
2036 nulls_first,
2037 fcinfo));
2038}
static bool array_iterator(ArrayType *la, PGCALL2 callback, void *param, ltree **found)
Definition: _ltree_op.c:38
#define ARR_NDIM(a)
Definition: array.h:290
#define PG_GETARG_ARRAYTYPE_P(n)
Definition: array.h:263
#define ARR_DATA_PTR(a)
Definition: array.h:322
#define MAXDIM
Definition: array.h:75
#define ARR_NULLBITMAP(a)
Definition: array.h:300
#define ARR_OVERHEAD_WITHNULLS(ndims, nitems)
Definition: array.h:312
#define DatumGetArrayTypeP(X)
Definition: array.h:261
#define ARR_ELEMTYPE(a)
Definition: array.h:292
#define PG_RETURN_ARRAYTYPE_P(x)
Definition: array.h:265
#define ARR_SIZE(a)
Definition: array.h:289
#define ARR_OVERHEAD_NONULLS(ndims)
Definition: array.h:310
#define ARR_DATA_OFFSET(a)
Definition: array.h:316
#define ARR_DIMS(a)
Definition: array.h:294
#define ARR_HASNULL(a)
Definition: array.h:291
#define PG_GETARG_EXPANDED_ARRAYX(n, metacache)
Definition: array.h:269
#define ARR_LBOUND(a)
Definition: array.h:296
Datum array_sample(PG_FUNCTION_ARGS)
struct DeserialIOData DeserialIOData
Datum array_prepend(PG_FUNCTION_ARGS)
Datum array_agg_deserialize(PG_FUNCTION_ARGS)
Datum array_positions(PG_FUNCTION_ARGS)
static Datum array_position_common(FunctionCallInfo fcinfo)
Datum array_position(PG_FUNCTION_ARGS)
static ExpandedArrayHeader * fetch_array_arg_replace_nulls(FunctionCallInfo fcinfo, int argno)
struct SerialIOData SerialIOData
struct ArraySortCachedInfo ArraySortCachedInfo
Datum array_agg_combine(PG_FUNCTION_ARGS)
Datum array_sort(PG_FUNCTION_ARGS)
Datum array_reverse(PG_FUNCTION_ARGS)
Datum array_append(PG_FUNCTION_ARGS)
Datum array_agg_array_combine(PG_FUNCTION_ARGS)
Datum array_agg_serialize(PG_FUNCTION_ARGS)
Datum array_agg_array_deserialize(PG_FUNCTION_ARGS)
Datum array_append_support(PG_FUNCTION_ARGS)
Datum array_agg_finalfn(PG_FUNCTION_ARGS)
Datum array_agg_array_transfn(PG_FUNCTION_ARGS)
Datum array_position_start(PG_FUNCTION_ARGS)
static ArrayType * array_sort_internal(ArrayType *array, bool descending, bool nulls_first, FunctionCallInfo fcinfo)
Datum array_shuffle(PG_FUNCTION_ARGS)
Datum array_cat(PG_FUNCTION_ARGS)
static ArrayType * array_reverse_n(ArrayType *array, Oid elmtyp, TypeCacheEntry *typentry)
Datum array_sort_order(PG_FUNCTION_ARGS)
static ArrayType * array_shuffle_n(ArrayType *array, int n, bool keep_lb, Oid elmtyp, TypeCacheEntry *typentry)
Datum array_sort_order_nulls_first(PG_FUNCTION_ARGS)
Datum array_agg_transfn(PG_FUNCTION_ARGS)
Datum array_agg_array_finalfn(PG_FUNCTION_ARGS)
Datum array_agg_array_serialize(PG_FUNCTION_ARGS)
Datum array_prepend_support(PG_FUNCTION_ARGS)
bool array_contains_nulls(ArrayType *array)
Definition: arrayfuncs.c:3767
ArrayBuildState * accumArrayResult(ArrayBuildState *astate, Datum dvalue, bool disnull, Oid element_type, MemoryContext rcontext)
Definition: arrayfuncs.c:5350
ExpandedArrayHeader * construct_empty_expanded_array(Oid element_type, MemoryContext parentcontext, ArrayMetaState *metacache)
Definition: arrayfuncs.c:3597
bool array_iterate(ArrayIterator iterator, Datum *value, bool *isnull)
Definition: arrayfuncs.c:4676
void array_free_iterator(ArrayIterator iterator)
Definition: arrayfuncs.c:4759
ArrayBuildStateAny * accumArrayResultAny(ArrayBuildStateAny *astate, Datum dvalue, bool disnull, Oid input_type, MemoryContext rcontext)
Definition: arrayfuncs.c:5829
ArrayType * construct_empty_array(Oid elmtype)
Definition: arrayfuncs.c:3580
Datum makeArrayResultArr(ArrayBuildStateArr *astate, MemoryContext rcontext, bool release)
Definition: arrayfuncs.c:5703
Datum makeArrayResultAny(ArrayBuildStateAny *astate, MemoryContext rcontext, bool release)
Definition: arrayfuncs.c:5857
Datum array_set_element(Datum arraydatum, int nSubscripts, int *indx, Datum dataValue, bool isNull, int arraytyplen, int elmlen, bool elmbyval, char elmalign)
Definition: arrayfuncs.c:2201
Datum makeMdArrayResult(ArrayBuildState *astate, int ndims, int *dims, int *lbs, MemoryContext rcontext, bool release)
Definition: arrayfuncs.c:5452
ArrayBuildStateArr * initArrayResultArr(Oid array_type, Oid element_type, MemoryContext rcontext, bool subcontext)
Definition: arrayfuncs.c:5504
ArrayBuildStateArr * accumArrayResultArr(ArrayBuildStateArr *astate, Datum dvalue, bool disnull, Oid array_type, MemoryContext rcontext)
Definition: arrayfuncs.c:5550
ArrayIterator array_create_iterator(ArrayType *arr, int slice_ndim, ArrayMetaState *mstate)
Definition: arrayfuncs.c:4597
ArrayBuildState * initArrayResultWithSize(Oid element_type, MemoryContext rcontext, bool subcontext, int initsize)
Definition: arrayfuncs.c:5310
void deconstruct_array(ArrayType *array, Oid elmtype, int elmlen, bool elmbyval, char elmalign, Datum **elemsp, bool **nullsp, int *nelemsp)
Definition: arrayfuncs.c:3631
ArrayType * construct_md_array(Datum *elems, bool *nulls, int ndims, int *dims, int *lbs, Oid elmtype, int elmlen, bool elmbyval, char elmalign)
Definition: arrayfuncs.c:3494
ArrayBuildState * initArrayResult(Oid element_type, MemoryContext rcontext, bool subcontext)
Definition: arrayfuncs.c:5293
Datum makeArrayResult(ArrayBuildState *astate, MemoryContext rcontext)
Definition: arrayfuncs.c:5420
void array_bitmap_copy(bits8 *destbitmap, int destoffset, const bits8 *srcbitmap, int srcoffset, int nitems)
Definition: arrayfuncs.c:4966
int ArrayGetNItems(int ndim, const int *dims)
Definition: arrayutils.c:57
void ArrayCheckBounds(int ndim, const int *dims, const int *lb)
Definition: arrayutils.c:117
#define Max(x, y)
Definition: c.h:969
#define VARHDRSZ
Definition: c.h:663
int64_t int64
Definition: c.h:499
int16_t int16
Definition: c.h:497
uint8 bits8
Definition: c.h:509
int32_t int32
Definition: c.h:498
#define OidIsValid(objectId)
Definition: c.h:746
Datum datumCopy(Datum value, bool typByVal, int typLen)
Definition: datum.c:132
int errdetail(const char *fmt,...)
Definition: elog.c:1204
int errcode(int sqlerrcode)
Definition: elog.c:854
int errmsg(const char *fmt,...)
Definition: elog.c:1071
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:226
#define ereport(elevel,...)
Definition: elog.h:149
static Datum EOHPGetRWDatum(const struct ExpandedObjectHeader *eohptr)
Datum FunctionCall2Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2)
Definition: fmgr.c:1149
void fmgr_info_cxt(Oid functionId, FmgrInfo *finfo, MemoryContext mcxt)
Definition: fmgr.c:137
bytea * SendFunctionCall(FmgrInfo *flinfo, Datum val)
Definition: fmgr.c:1744
Oid get_fn_expr_argtype(FmgrInfo *flinfo, int argnum)
Definition: fmgr.c:1910
Datum ReceiveFunctionCall(FmgrInfo *flinfo, StringInfo buf, Oid typioparam, int32 typmod)
Definition: fmgr.c:1697
#define PG_FREE_IF_COPY(ptr, n)
Definition: fmgr.h:260
#define PG_GETARG_BYTEA_PP(n)
Definition: fmgr.h:308
#define PG_RETURN_BYTEA_P(x)
Definition: fmgr.h:371
#define PG_GETARG_POINTER(n)
Definition: fmgr.h:276
#define PG_ARGISNULL(n)
Definition: fmgr.h:209
#define PG_GETARG_DATUM(n)
Definition: fmgr.h:268
#define PG_NARGS()
Definition: fmgr.h:203
#define PG_RETURN_NULL()
Definition: fmgr.h:345
#define PG_RETURN_INT32(x)
Definition: fmgr.h:354
#define PG_GETARG_INT32(n)
Definition: fmgr.h:269
#define PG_GETARG_BOOL(n)
Definition: fmgr.h:274
#define PG_RETURN_DATUM(x)
Definition: fmgr.h:353
#define PG_RETURN_POINTER(x)
Definition: fmgr.h:361
#define PG_GET_COLLATION()
Definition: fmgr.h:198
#define PG_FUNCTION_ARGS
Definition: fmgr.h:193
char * format_type_be(Oid type_oid)
Definition: format_type.c:343
int work_mem
Definition: globals.c:132
Assert(PointerIsAligned(start, uint64))
#define nitems(x)
Definition: indent.h:31
static struct @165 value
static bool pg_sub_s32_overflow(int32 a, int32 b, int32 *result)
Definition: int.h:169
static bool pg_add_s32_overflow(int32 a, int32 b, int32 *result)
Definition: int.h:151
int j
Definition: isn.c:78
int i
Definition: isn.c:77
if(TABLE==NULL||TABLE_index==NULL)
Definition: isn.c:81
void getTypeBinaryOutputInfo(Oid type, Oid *typSend, bool *typIsVarlena)
Definition: lsyscache.c:3113
Oid get_element_type(Oid typid)
Definition: lsyscache.c:2899
void get_typlenbyvalalign(Oid typid, int16 *typlen, bool *typbyval, char *typalign)
Definition: lsyscache.c:2411
void getTypeBinaryInputInfo(Oid type, Oid *typReceive, Oid *typIOParam)
Definition: lsyscache.c:3080
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:1256
void * MemoryContextAllocZero(MemoryContext context, Size size)
Definition: mcxt.c:1290
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:2167
void pfree(void *pointer)
Definition: mcxt.c:2147
void * palloc0(Size size)
Definition: mcxt.c:1970
void * palloc(Size size)
Definition: mcxt.c:1940
MemoryContext CurrentMemoryContext
Definition: mcxt.c:159
int AggCheckCallContext(FunctionCallInfo fcinfo, MemoryContext *aggcontext)
Definition: nodeAgg.c:4614
#define IsA(nodeptr, _type_)
Definition: nodes.h:164
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:124
void * arg
static uint32 pg_nextpower2_32(uint32 num)
Definition: pg_bitutils.h:189
#define linitial(l)
Definition: pg_list.h:178
#define lsecond(l)
Definition: pg_list.h:183
uint64 pg_prng_uint64_range(pg_prng_state *state, uint64 rmin, uint64 rmax)
Definition: pg_prng.c:144
pg_prng_state pg_global_prng_state
Definition: pg_prng.c:34
static char * buf
Definition: pg_test_fsync.c:72
static bool DatumGetBool(Datum X)
Definition: postgres.h:95
uintptr_t Datum
Definition: postgres.h:69
static Datum Int32GetDatum(int32 X)
Definition: postgres.h:217
#define InvalidOid
Definition: postgres_ext.h:35
unsigned int Oid
Definition: postgres_ext.h:30
unsigned int pq_getmsgint(StringInfo msg, int b)
Definition: pqformat.c:415
void pq_sendbytes(StringInfo buf, const void *data, int datalen)
Definition: pqformat.c:126
void pq_getmsgend(StringInfo msg)
Definition: pqformat.c:635
void pq_begintypsend(StringInfo buf)
Definition: pqformat.c:326
int pq_getmsgbyte(StringInfo msg)
Definition: pqformat.c:399
int64 pq_getmsgint64(StringInfo msg)
Definition: pqformat.c:453
const char * pq_getmsgbytes(StringInfo msg, int datalen)
Definition: pqformat.c:508
bytea * pq_endtypsend(StringInfo buf)
Definition: pqformat.c:346
static void pq_sendint32(StringInfo buf, uint32 i)
Definition: pqformat.h:144
static void pq_sendbyte(StringInfo buf, uint8 byt)
Definition: pqformat.h:160
static void pq_sendint64(StringInfo buf, uint64 i)
Definition: pqformat.h:152
static void pq_sendint16(StringInfo buf, uint16 i)
Definition: pqformat.h:136
@ PARAM_EXTERN
Definition: primnodes.h:384
static void initReadOnlyStringInfo(StringInfo str, char *data, int len)
Definition: stringinfo.h:157
bits8 * nullbitmap
Definition: array.h:209
int lbs[MAXDIM]
Definition: array.h:216
MemoryContext mcontext
Definition: array.h:207
int dims[MAXDIM]
Definition: array.h:215
bool * dnulls
Definition: array.h:191
bool typbyval
Definition: array.h:196
MemoryContext mcontext
Definition: array.h:189
int16 typlen
Definition: array.h:195
char typalign
Definition: array.h:197
Oid element_type
Definition: array.h:194
Datum * dvalues
Definition: array.h:190
char typalign
Definition: array.h:241
int16 typlen
Definition: array.h:239
Oid element_type
Definition: array.h:238
FmgrInfo proc
Definition: array.h:245
bool typbyval
Definition: array.h:240
ArrayMetaState array_meta
Oid elemtype
Definition: array.h:97
int ndim
Definition: array.h:95
int32 dataoffset
Definition: array.h:96
FmgrInfo typreceive
ExpandedObjectHeader hdr
Definition: array.h:118
Definition: fmgr.h:57
void * fn_extra
Definition: fmgr.h:64
MemoryContext fn_mcxt
Definition: fmgr.h:65
Oid fn_oid
Definition: fmgr.h:59
FmgrInfo * flinfo
Definition: fmgr.h:87
Definition: nodes.h:135
FmgrInfo typsend
char typalign
Definition: typcache.h:41
FmgrInfo eq_opr_finfo
Definition: typcache.h:76
bool typbyval
Definition: typcache.h:40
int16 typlen
Definition: typcache.h:39
Definition: regguts.h:323
Definition: c.h:658
void tuplesort_performsort(Tuplesortstate *state)
Definition: tuplesort.c:1363
void tuplesort_end(Tuplesortstate *state)
Definition: tuplesort.c:951
#define TUPLESORT_NONE
Definition: tuplesort.h:94
void tuplesort_putdatum(Tuplesortstate *state, Datum val, bool isNull)
Tuplesortstate * tuplesort_begin_datum(Oid datumType, Oid sortOperator, Oid sortCollation, bool nullsFirstFlag, int workMem, SortCoordinate coordinate, int sortopt)
bool tuplesort_getdatum(Tuplesortstate *state, bool forward, bool copy, Datum *val, bool *isNull, Datum *abbrev)
TypeCacheEntry * lookup_type_cache(Oid type_id, int flags)
Definition: typcache.c:386
#define TYPECACHE_EQ_OPR_FINFO
Definition: typcache.h:143
#define TYPECACHE_GT_OPR
Definition: typcache.h:140
#define TYPECACHE_LT_OPR
Definition: typcache.h:139
#define VARDATA(PTR)
Definition: varatt.h:278
#define VARDATA_ANY(PTR)
Definition: varatt.h:324
#define SET_VARSIZE(PTR, len)
Definition: varatt.h:305
#define VARSIZE(PTR)
Definition: varatt.h:279
#define VARSIZE_ANY_EXHDR(PTR)
Definition: varatt.h:317