PostgreSQL Source Code  git master
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-2023, 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_type.h"
16 #include "libpq/pqformat.h"
17 #include "common/int.h"
18 #include "port/pg_bitutils.h"
19 #include "utils/array.h"
20 #include "utils/datum.h"
21 #include "utils/builtins.h"
22 #include "utils/lsyscache.h"
23 #include "utils/typcache.h"
24 
25 /*
26  * SerialIOData
27  * Used for caching element-type data in array_agg_serialize
28  */
29 typedef struct SerialIOData
30 {
33 
34 /*
35  * DeserialIOData
36  * Used for caching element-type data in array_agg_deserialize
37  */
38 typedef struct DeserialIOData
39 {
43 
45 
46 
47 /*
48  * fetch_array_arg_replace_nulls
49  *
50  * Fetch an array-valued argument in expanded form; if it's null, construct an
51  * empty array value of the proper data type. Also cache basic element type
52  * information in fn_extra.
53  *
54  * Caution: if the input is a read/write pointer, this returns the input
55  * argument; so callers must be sure that their changes are "safe", that is
56  * they cannot leave the array in a corrupt state.
57  *
58  * If we're being called as an aggregate function, make sure any newly-made
59  * expanded array is allocated in the aggregate state context, so as to save
60  * copying operations.
61  */
62 static ExpandedArrayHeader *
64 {
66  Oid element_type;
67  ArrayMetaState *my_extra;
68  MemoryContext resultcxt;
69 
70  /* If first time through, create datatype cache struct */
71  my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra;
72  if (my_extra == NULL)
73  {
74  my_extra = (ArrayMetaState *)
76  sizeof(ArrayMetaState));
77  my_extra->element_type = InvalidOid;
78  fcinfo->flinfo->fn_extra = my_extra;
79  }
80 
81  /* Figure out which context we want the result in */
82  if (!AggCheckCallContext(fcinfo, &resultcxt))
83  resultcxt = CurrentMemoryContext;
84 
85  /* Now collect the array value */
86  if (!PG_ARGISNULL(argno))
87  {
88  MemoryContext oldcxt = MemoryContextSwitchTo(resultcxt);
89 
90  eah = PG_GETARG_EXPANDED_ARRAYX(argno, my_extra);
91  MemoryContextSwitchTo(oldcxt);
92  }
93  else
94  {
95  /* We have to look up the array type and element type */
96  Oid arr_typeid = get_fn_expr_argtype(fcinfo->flinfo, argno);
97 
98  if (!OidIsValid(arr_typeid))
99  ereport(ERROR,
100  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
101  errmsg("could not determine input data type")));
102  element_type = get_element_type(arr_typeid);
103  if (!OidIsValid(element_type))
104  ereport(ERROR,
105  (errcode(ERRCODE_DATATYPE_MISMATCH),
106  errmsg("input data type is not an array")));
107 
108  eah = construct_empty_expanded_array(element_type,
109  resultcxt,
110  my_extra);
111  }
112 
113  return eah;
114 }
115 
116 /*-----------------------------------------------------------------------------
117  * array_append :
118  * push an element onto the end of a one-dimensional array
119  *----------------------------------------------------------------------------
120  */
121 Datum
123 {
124  ExpandedArrayHeader *eah;
125  Datum newelem;
126  bool isNull;
127  Datum result;
128  int *dimv,
129  *lb;
130  int indx;
131  ArrayMetaState *my_extra;
132 
133  eah = fetch_array_arg_replace_nulls(fcinfo, 0);
134  isNull = PG_ARGISNULL(1);
135  if (isNull)
136  newelem = (Datum) 0;
137  else
138  newelem = PG_GETARG_DATUM(1);
139 
140  if (eah->ndims == 1)
141  {
142  /* append newelem */
143  lb = eah->lbound;
144  dimv = eah->dims;
145 
146  /* index of added elem is at lb[0] + (dimv[0] - 1) + 1 */
147  if (pg_add_s32_overflow(lb[0], dimv[0], &indx))
148  ereport(ERROR,
149  (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
150  errmsg("integer out of range")));
151  }
152  else if (eah->ndims == 0)
153  indx = 1;
154  else
155  ereport(ERROR,
156  (errcode(ERRCODE_DATA_EXCEPTION),
157  errmsg("argument must be empty or one-dimensional array")));
158 
159  /* Perform element insertion */
160  my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra;
161 
162  result = array_set_element(EOHPGetRWDatum(&eah->hdr),
163  1, &indx, newelem, isNull,
164  -1, my_extra->typlen, my_extra->typbyval, my_extra->typalign);
165 
166  PG_RETURN_DATUM(result);
167 }
168 
169 /*-----------------------------------------------------------------------------
170  * array_prepend :
171  * push an element onto the front of a one-dimensional array
172  *----------------------------------------------------------------------------
173  */
174 Datum
176 {
177  ExpandedArrayHeader *eah;
178  Datum newelem;
179  bool isNull;
180  Datum result;
181  int *lb;
182  int indx;
183  int lb0;
184  ArrayMetaState *my_extra;
185 
186  isNull = PG_ARGISNULL(0);
187  if (isNull)
188  newelem = (Datum) 0;
189  else
190  newelem = PG_GETARG_DATUM(0);
191  eah = fetch_array_arg_replace_nulls(fcinfo, 1);
192 
193  if (eah->ndims == 1)
194  {
195  /* prepend newelem */
196  lb = eah->lbound;
197  lb0 = lb[0];
198 
199  if (pg_sub_s32_overflow(lb0, 1, &indx))
200  ereport(ERROR,
201  (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
202  errmsg("integer out of range")));
203  }
204  else if (eah->ndims == 0)
205  {
206  indx = 1;
207  lb0 = 1;
208  }
209  else
210  ereport(ERROR,
211  (errcode(ERRCODE_DATA_EXCEPTION),
212  errmsg("argument must be empty or one-dimensional array")));
213 
214  /* Perform element insertion */
215  my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra;
216 
217  result = array_set_element(EOHPGetRWDatum(&eah->hdr),
218  1, &indx, newelem, isNull,
219  -1, my_extra->typlen, my_extra->typbyval, my_extra->typalign);
220 
221  /* Readjust result's LB to match the input's, as expected for prepend */
222  Assert(result == EOHPGetRWDatum(&eah->hdr));
223  if (eah->ndims == 1)
224  {
225  /* This is ok whether we've deconstructed or not */
226  eah->lbound[0] = lb0;
227  }
228 
229  PG_RETURN_DATUM(result);
230 }
231 
232 /*-----------------------------------------------------------------------------
233  * array_cat :
234  * concatenate two nD arrays to form an nD array, or
235  * push an (n-1)D array onto the end of an nD array
236  *----------------------------------------------------------------------------
237  */
238 Datum
240 {
241  ArrayType *v1,
242  *v2;
243  ArrayType *result;
244  int *dims,
245  *lbs,
246  ndims,
247  nitems,
248  ndatabytes,
249  nbytes;
250  int *dims1,
251  *lbs1,
252  ndims1,
253  nitems1,
254  ndatabytes1;
255  int *dims2,
256  *lbs2,
257  ndims2,
258  nitems2,
259  ndatabytes2;
260  int i;
261  char *dat1,
262  *dat2;
263  bits8 *bitmap1,
264  *bitmap2;
265  Oid element_type;
266  Oid element_type1;
267  Oid element_type2;
268  int32 dataoffset;
269 
270  /* Concatenating a null array is a no-op, just return the other input */
271  if (PG_ARGISNULL(0))
272  {
273  if (PG_ARGISNULL(1))
274  PG_RETURN_NULL();
275  result = PG_GETARG_ARRAYTYPE_P(1);
276  PG_RETURN_ARRAYTYPE_P(result);
277  }
278  if (PG_ARGISNULL(1))
279  {
280  result = PG_GETARG_ARRAYTYPE_P(0);
281  PG_RETURN_ARRAYTYPE_P(result);
282  }
283 
284  v1 = PG_GETARG_ARRAYTYPE_P(0);
285  v2 = PG_GETARG_ARRAYTYPE_P(1);
286 
287  element_type1 = ARR_ELEMTYPE(v1);
288  element_type2 = ARR_ELEMTYPE(v2);
289 
290  /* Check we have matching element types */
291  if (element_type1 != element_type2)
292  ereport(ERROR,
293  (errcode(ERRCODE_DATATYPE_MISMATCH),
294  errmsg("cannot concatenate incompatible arrays"),
295  errdetail("Arrays with element types %s and %s are not "
296  "compatible for concatenation.",
297  format_type_be(element_type1),
298  format_type_be(element_type2))));
299 
300  /* OK, use it */
301  element_type = element_type1;
302 
303  /*----------
304  * We must have one of the following combinations of inputs:
305  * 1) one empty array, and one non-empty array
306  * 2) both arrays empty
307  * 3) two arrays with ndims1 == ndims2
308  * 4) ndims1 == ndims2 - 1
309  * 5) ndims1 == ndims2 + 1
310  *----------
311  */
312  ndims1 = ARR_NDIM(v1);
313  ndims2 = ARR_NDIM(v2);
314 
315  /*
316  * short circuit - if one input array is empty, and the other is not, we
317  * return the non-empty one as the result
318  *
319  * if both are empty, return the first one
320  */
321  if (ndims1 == 0 && ndims2 > 0)
323 
324  if (ndims2 == 0)
326 
327  /* the rest fall under rule 3, 4, or 5 */
328  if (ndims1 != ndims2 &&
329  ndims1 != ndims2 - 1 &&
330  ndims1 != ndims2 + 1)
331  ereport(ERROR,
332  (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
333  errmsg("cannot concatenate incompatible arrays"),
334  errdetail("Arrays of %d and %d dimensions are not "
335  "compatible for concatenation.",
336  ndims1, ndims2)));
337 
338  /* get argument array details */
339  lbs1 = ARR_LBOUND(v1);
340  lbs2 = ARR_LBOUND(v2);
341  dims1 = ARR_DIMS(v1);
342  dims2 = ARR_DIMS(v2);
343  dat1 = ARR_DATA_PTR(v1);
344  dat2 = ARR_DATA_PTR(v2);
345  bitmap1 = ARR_NULLBITMAP(v1);
346  bitmap2 = ARR_NULLBITMAP(v2);
347  nitems1 = ArrayGetNItems(ndims1, dims1);
348  nitems2 = ArrayGetNItems(ndims2, dims2);
349  ndatabytes1 = ARR_SIZE(v1) - ARR_DATA_OFFSET(v1);
350  ndatabytes2 = ARR_SIZE(v2) - ARR_DATA_OFFSET(v2);
351 
352  if (ndims1 == ndims2)
353  {
354  /*
355  * resulting array is made up of the elements (possibly arrays
356  * themselves) of the input argument arrays
357  */
358  ndims = ndims1;
359  dims = (int *) palloc(ndims * sizeof(int));
360  lbs = (int *) palloc(ndims * sizeof(int));
361 
362  dims[0] = dims1[0] + dims2[0];
363  lbs[0] = lbs1[0];
364 
365  for (i = 1; i < ndims; i++)
366  {
367  if (dims1[i] != dims2[i] || lbs1[i] != lbs2[i])
368  ereport(ERROR,
369  (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
370  errmsg("cannot concatenate incompatible arrays"),
371  errdetail("Arrays with differing element dimensions are "
372  "not compatible for concatenation.")));
373 
374  dims[i] = dims1[i];
375  lbs[i] = lbs1[i];
376  }
377  }
378  else if (ndims1 == ndims2 - 1)
379  {
380  /*
381  * resulting array has the second argument as the outer array, with
382  * the first argument inserted at the front of the outer dimension
383  */
384  ndims = ndims2;
385  dims = (int *) palloc(ndims * sizeof(int));
386  lbs = (int *) palloc(ndims * sizeof(int));
387  memcpy(dims, dims2, ndims * sizeof(int));
388  memcpy(lbs, lbs2, ndims * sizeof(int));
389 
390  /* increment number of elements in outer array */
391  dims[0] += 1;
392 
393  /* make sure the added element matches our existing elements */
394  for (i = 0; i < ndims1; i++)
395  {
396  if (dims1[i] != dims[i + 1] || lbs1[i] != lbs[i + 1])
397  ereport(ERROR,
398  (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
399  errmsg("cannot concatenate incompatible arrays"),
400  errdetail("Arrays with differing dimensions are not "
401  "compatible for concatenation.")));
402  }
403  }
404  else
405  {
406  /*
407  * (ndims1 == ndims2 + 1)
408  *
409  * resulting array has the first argument as the outer array, with the
410  * second argument appended to the end of the outer dimension
411  */
412  ndims = ndims1;
413  dims = (int *) palloc(ndims * sizeof(int));
414  lbs = (int *) palloc(ndims * sizeof(int));
415  memcpy(dims, dims1, ndims * sizeof(int));
416  memcpy(lbs, lbs1, ndims * sizeof(int));
417 
418  /* increment number of elements in outer array */
419  dims[0] += 1;
420 
421  /* make sure the added element matches our existing elements */
422  for (i = 0; i < ndims2; i++)
423  {
424  if (dims2[i] != dims[i + 1] || lbs2[i] != lbs[i + 1])
425  ereport(ERROR,
426  (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
427  errmsg("cannot concatenate incompatible arrays"),
428  errdetail("Arrays with differing dimensions are not "
429  "compatible for concatenation.")));
430  }
431  }
432 
433  /* Do this mainly for overflow checking */
434  nitems = ArrayGetNItems(ndims, dims);
435  ArrayCheckBounds(ndims, dims, lbs);
436 
437  /* build the result array */
438  ndatabytes = ndatabytes1 + ndatabytes2;
439  if (ARR_HASNULL(v1) || ARR_HASNULL(v2))
440  {
441  dataoffset = ARR_OVERHEAD_WITHNULLS(ndims, nitems);
442  nbytes = ndatabytes + dataoffset;
443  }
444  else
445  {
446  dataoffset = 0; /* marker for no null bitmap */
447  nbytes = ndatabytes + ARR_OVERHEAD_NONULLS(ndims);
448  }
449  result = (ArrayType *) palloc0(nbytes);
450  SET_VARSIZE(result, nbytes);
451  result->ndim = ndims;
452  result->dataoffset = dataoffset;
453  result->elemtype = element_type;
454  memcpy(ARR_DIMS(result), dims, ndims * sizeof(int));
455  memcpy(ARR_LBOUND(result), lbs, ndims * sizeof(int));
456  /* data area is arg1 then arg2 */
457  memcpy(ARR_DATA_PTR(result), dat1, ndatabytes1);
458  memcpy(ARR_DATA_PTR(result) + ndatabytes1, dat2, ndatabytes2);
459  /* handle the null bitmap if needed */
460  if (ARR_HASNULL(result))
461  {
463  bitmap1, 0,
464  nitems1);
465  array_bitmap_copy(ARR_NULLBITMAP(result), nitems1,
466  bitmap2, 0,
467  nitems2);
468  }
469 
470  PG_RETURN_ARRAYTYPE_P(result);
471 }
472 
473 
474 /*
475  * ARRAY_AGG(anynonarray) aggregate function
476  */
477 Datum
479 {
480  Oid arg1_typeid = get_fn_expr_argtype(fcinfo->flinfo, 1);
481  MemoryContext aggcontext;
483  Datum elem;
484 
485  if (arg1_typeid == InvalidOid)
486  ereport(ERROR,
487  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
488  errmsg("could not determine input data type")));
489 
490  /*
491  * Note: we do not need a run-time check about whether arg1_typeid is a
492  * valid array element type, because the parser would have verified that
493  * while resolving the input/result types of this polymorphic aggregate.
494  */
495 
496  if (!AggCheckCallContext(fcinfo, &aggcontext))
497  {
498  /* cannot be called directly because of internal-type argument */
499  elog(ERROR, "array_agg_transfn called in non-aggregate context");
500  }
501 
502  if (PG_ARGISNULL(0))
503  state = initArrayResult(arg1_typeid, aggcontext, false);
504  else
506 
507  elem = PG_ARGISNULL(1) ? (Datum) 0 : PG_GETARG_DATUM(1);
508 
510  elem,
511  PG_ARGISNULL(1),
512  arg1_typeid,
513  aggcontext);
514 
515  /*
516  * The transition type for array_agg() is declared to be "internal", which
517  * is a pass-by-value type the same size as a pointer. So we can safely
518  * pass the ArrayBuildState pointer through nodeAgg.c's machinations.
519  */
521 }
522 
523 Datum
525 {
526  ArrayBuildState *state1;
527  ArrayBuildState *state2;
528  MemoryContext agg_context;
529  MemoryContext old_context;
530 
531  if (!AggCheckCallContext(fcinfo, &agg_context))
532  elog(ERROR, "aggregate function called in non-aggregate context");
533 
534  state1 = PG_ARGISNULL(0) ? NULL : (ArrayBuildState *) PG_GETARG_POINTER(0);
535  state2 = PG_ARGISNULL(1) ? NULL : (ArrayBuildState *) PG_GETARG_POINTER(1);
536 
537  if (state2 == NULL)
538  {
539  /*
540  * NULL state2 is easy, just return state1, which we know is already
541  * in the agg_context
542  */
543  if (state1 == NULL)
544  PG_RETURN_NULL();
545  PG_RETURN_POINTER(state1);
546  }
547 
548  if (state1 == NULL)
549  {
550  /* We must copy state2's data into the agg_context */
551  state1 = initArrayResultWithSize(state2->element_type, agg_context,
552  false, state2->alen);
553 
554  old_context = MemoryContextSwitchTo(agg_context);
555 
556  for (int i = 0; i < state2->nelems; i++)
557  {
558  if (!state2->dnulls[i])
559  state1->dvalues[i] = datumCopy(state2->dvalues[i],
560  state1->typbyval,
561  state1->typlen);
562  else
563  state1->dvalues[i] = (Datum) 0;
564  }
565 
566  MemoryContextSwitchTo(old_context);
567 
568  memcpy(state1->dnulls, state2->dnulls, sizeof(bool) * state2->nelems);
569 
570  state1->nelems = state2->nelems;
571 
572  PG_RETURN_POINTER(state1);
573  }
574  else if (state2->nelems > 0)
575  {
576  /* We only need to combine the two states if state2 has any elements */
577  int reqsize = state1->nelems + state2->nelems;
578  MemoryContext oldContext = MemoryContextSwitchTo(state1->mcontext);
579 
580  Assert(state1->element_type == state2->element_type);
581 
582  /* Enlarge state1 arrays if needed */
583  if (state1->alen < reqsize)
584  {
585  /* Use a power of 2 size rather than allocating just reqsize */
586  state1->alen = pg_nextpower2_32(reqsize);
587  state1->dvalues = (Datum *) repalloc(state1->dvalues,
588  state1->alen * sizeof(Datum));
589  state1->dnulls = (bool *) repalloc(state1->dnulls,
590  state1->alen * sizeof(bool));
591  }
592 
593  /* Copy in the state2 elements to the end of the state1 arrays */
594  for (int i = 0; i < state2->nelems; i++)
595  {
596  if (!state2->dnulls[i])
597  state1->dvalues[i + state1->nelems] =
598  datumCopy(state2->dvalues[i],
599  state1->typbyval,
600  state1->typlen);
601  else
602  state1->dvalues[i + state1->nelems] = (Datum) 0;
603  }
604 
605  memcpy(&state1->dnulls[state1->nelems], state2->dnulls,
606  sizeof(bool) * state2->nelems);
607 
608  state1->nelems = reqsize;
609 
610  MemoryContextSwitchTo(oldContext);
611  }
612 
613  PG_RETURN_POINTER(state1);
614 }
615 
616 /*
617  * array_agg_serialize
618  * Serialize ArrayBuildState into bytea.
619  */
620 Datum
622 {
625  bytea *result;
626 
627  /* cannot be called directly because of internal-type argument */
628  Assert(AggCheckCallContext(fcinfo, NULL));
629 
631 
633 
634  /*
635  * element_type. Putting this first is more convenient in deserialization
636  */
637  pq_sendint32(&buf, state->element_type);
638 
639  /*
640  * nelems -- send first so we know how large to make the dvalues and
641  * dnulls array during deserialization.
642  */
643  pq_sendint64(&buf, state->nelems);
644 
645  /* alen can be decided during deserialization */
646 
647  /* typlen */
648  pq_sendint16(&buf, state->typlen);
649 
650  /* typbyval */
651  pq_sendbyte(&buf, state->typbyval);
652 
653  /* typalign */
654  pq_sendbyte(&buf, state->typalign);
655 
656  /* dnulls */
657  pq_sendbytes(&buf, state->dnulls, sizeof(bool) * state->nelems);
658 
659  /*
660  * dvalues. By agreement with array_agg_deserialize, when the element
661  * type is byval, we just transmit the Datum array as-is, including any
662  * null elements. For by-ref types, we must invoke the element type's
663  * send function, and we skip null elements (which is why the nulls flags
664  * must be sent first).
665  */
666  if (state->typbyval)
667  pq_sendbytes(&buf, state->dvalues, sizeof(Datum) * state->nelems);
668  else
669  {
670  SerialIOData *iodata;
671  int i;
672 
673  /* Avoid repeat catalog lookups for typsend function */
674  iodata = (SerialIOData *) fcinfo->flinfo->fn_extra;
675  if (iodata == NULL)
676  {
677  Oid typsend;
678  bool typisvarlena;
679 
680  iodata = (SerialIOData *)
681  MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
682  sizeof(SerialIOData));
683  getTypeBinaryOutputInfo(state->element_type, &typsend,
684  &typisvarlena);
685  fmgr_info_cxt(typsend, &iodata->typsend,
686  fcinfo->flinfo->fn_mcxt);
687  fcinfo->flinfo->fn_extra = (void *) iodata;
688  }
689 
690  for (i = 0; i < state->nelems; i++)
691  {
692  bytea *outputbytes;
693 
694  if (state->dnulls[i])
695  continue;
696  outputbytes = SendFunctionCall(&iodata->typsend,
697  state->dvalues[i]);
698  pq_sendint32(&buf, VARSIZE(outputbytes) - VARHDRSZ);
699  pq_sendbytes(&buf, VARDATA(outputbytes),
700  VARSIZE(outputbytes) - VARHDRSZ);
701  }
702  }
703 
704  result = pq_endtypsend(&buf);
705 
706  PG_RETURN_BYTEA_P(result);
707 }
708 
709 Datum
711 {
712  bytea *sstate;
713  ArrayBuildState *result;
715  Oid element_type;
716  int64 nelems;
717  const char *temp;
718 
719  if (!AggCheckCallContext(fcinfo, NULL))
720  elog(ERROR, "aggregate function called in non-aggregate context");
721 
722  sstate = PG_GETARG_BYTEA_PP(0);
723 
724  /*
725  * Copy the bytea into a StringInfo so that we can "receive" it using the
726  * standard recv-function infrastructure.
727  */
730  VARDATA_ANY(sstate), VARSIZE_ANY_EXHDR(sstate));
731 
732  /* element_type */
733  element_type = pq_getmsgint(&buf, 4);
734 
735  /* nelems */
736  nelems = pq_getmsgint64(&buf);
737 
738  /* Create output ArrayBuildState with the needed number of elements */
739  result = initArrayResultWithSize(element_type, CurrentMemoryContext,
740  false, nelems);
741  result->nelems = nelems;
742 
743  /* typlen */
744  result->typlen = pq_getmsgint(&buf, 2);
745 
746  /* typbyval */
747  result->typbyval = pq_getmsgbyte(&buf);
748 
749  /* typalign */
750  result->typalign = pq_getmsgbyte(&buf);
751 
752  /* dnulls */
753  temp = pq_getmsgbytes(&buf, sizeof(bool) * nelems);
754  memcpy(result->dnulls, temp, sizeof(bool) * nelems);
755 
756  /* dvalues --- see comment in array_agg_serialize */
757  if (result->typbyval)
758  {
759  temp = pq_getmsgbytes(&buf, sizeof(Datum) * nelems);
760  memcpy(result->dvalues, temp, sizeof(Datum) * nelems);
761  }
762  else
763  {
764  DeserialIOData *iodata;
765 
766  /* Avoid repeat catalog lookups for typreceive function */
767  iodata = (DeserialIOData *) fcinfo->flinfo->fn_extra;
768  if (iodata == NULL)
769  {
770  Oid typreceive;
771 
772  iodata = (DeserialIOData *)
773  MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
774  sizeof(DeserialIOData));
775  getTypeBinaryInputInfo(element_type, &typreceive,
776  &iodata->typioparam);
777  fmgr_info_cxt(typreceive, &iodata->typreceive,
778  fcinfo->flinfo->fn_mcxt);
779  fcinfo->flinfo->fn_extra = (void *) iodata;
780  }
781 
782  for (int i = 0; i < nelems; i++)
783  {
784  int itemlen;
785  StringInfoData elem_buf;
786  char csave;
787 
788  if (result->dnulls[i])
789  {
790  result->dvalues[i] = (Datum) 0;
791  continue;
792  }
793 
794  itemlen = pq_getmsgint(&buf, 4);
795  if (itemlen < 0 || itemlen > (buf.len - buf.cursor))
796  ereport(ERROR,
797  (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
798  errmsg("insufficient data left in message")));
799 
800  /*
801  * Rather than copying data around, we just set up a phony
802  * StringInfo pointing to the correct portion of the input buffer.
803  * We assume we can scribble on the input buffer so as to maintain
804  * the convention that StringInfos have a trailing null.
805  */
806  elem_buf.data = &buf.data[buf.cursor];
807  elem_buf.maxlen = itemlen + 1;
808  elem_buf.len = itemlen;
809  elem_buf.cursor = 0;
810 
811  buf.cursor += itemlen;
812 
813  csave = buf.data[buf.cursor];
814  buf.data[buf.cursor] = '\0';
815 
816  /* Now call the element's receiveproc */
817  result->dvalues[i] = ReceiveFunctionCall(&iodata->typreceive,
818  &elem_buf,
819  iodata->typioparam,
820  -1);
821 
822  buf.data[buf.cursor] = csave;
823  }
824  }
825 
826  pq_getmsgend(&buf);
827  pfree(buf.data);
828 
829  PG_RETURN_POINTER(result);
830 }
831 
832 Datum
834 {
835  Datum result;
837  int dims[1];
838  int lbs[1];
839 
840  /* cannot be called directly because of internal-type argument */
841  Assert(AggCheckCallContext(fcinfo, NULL));
842 
844 
845  if (state == NULL)
846  PG_RETURN_NULL(); /* returns null iff no input values */
847 
848  dims[0] = state->nelems;
849  lbs[0] = 1;
850 
851  /*
852  * Make the result. We cannot release the ArrayBuildState because
853  * sometimes aggregate final functions are re-executed. Rather, it is
854  * nodeAgg.c's responsibility to reset the aggcontext when it's safe to do
855  * so.
856  */
857  result = makeMdArrayResult(state, 1, dims, lbs,
859  false);
860 
861  PG_RETURN_DATUM(result);
862 }
863 
864 /*
865  * ARRAY_AGG(anyarray) aggregate function
866  */
867 Datum
869 {
870  Oid arg1_typeid = get_fn_expr_argtype(fcinfo->flinfo, 1);
871  MemoryContext aggcontext;
873 
874  if (arg1_typeid == InvalidOid)
875  ereport(ERROR,
876  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
877  errmsg("could not determine input data type")));
878 
879  /*
880  * Note: we do not need a run-time check about whether arg1_typeid is a
881  * valid array type, because the parser would have verified that while
882  * resolving the input/result types of this polymorphic aggregate.
883  */
884 
885  if (!AggCheckCallContext(fcinfo, &aggcontext))
886  {
887  /* cannot be called directly because of internal-type argument */
888  elog(ERROR, "array_agg_array_transfn called in non-aggregate context");
889  }
890 
891 
892  if (PG_ARGISNULL(0))
893  state = initArrayResultArr(arg1_typeid, InvalidOid, aggcontext, false);
894  else
896 
898  PG_GETARG_DATUM(1),
899  PG_ARGISNULL(1),
900  arg1_typeid,
901  aggcontext);
902 
903  /*
904  * The transition type for array_agg() is declared to be "internal", which
905  * is a pass-by-value type the same size as a pointer. So we can safely
906  * pass the ArrayBuildStateArr pointer through nodeAgg.c's machinations.
907  */
909 }
910 
911 Datum
913 {
914  ArrayBuildStateArr *state1;
915  ArrayBuildStateArr *state2;
916  MemoryContext agg_context;
917  MemoryContext old_context;
918 
919  if (!AggCheckCallContext(fcinfo, &agg_context))
920  elog(ERROR, "aggregate function called in non-aggregate context");
921 
922  state1 = PG_ARGISNULL(0) ? NULL : (ArrayBuildStateArr *) PG_GETARG_POINTER(0);
923  state2 = PG_ARGISNULL(1) ? NULL : (ArrayBuildStateArr *) PG_GETARG_POINTER(1);
924 
925  if (state2 == NULL)
926  {
927  /*
928  * NULL state2 is easy, just return state1, which we know is already
929  * in the agg_context
930  */
931  if (state1 == NULL)
932  PG_RETURN_NULL();
933  PG_RETURN_POINTER(state1);
934  }
935 
936  if (state1 == NULL)
937  {
938  /* We must copy state2's data into the agg_context */
939  old_context = MemoryContextSwitchTo(agg_context);
940 
941  state1 = initArrayResultArr(state2->array_type, InvalidOid,
942  agg_context, false);
943 
944  state1->abytes = state2->abytes;
945  state1->data = (char *) palloc(state1->abytes);
946 
947  if (state2->nullbitmap)
948  {
949  int size = (state2->aitems + 7) / 8;
950 
951  state1->nullbitmap = (bits8 *) palloc(size);
952  memcpy(state1->nullbitmap, state2->nullbitmap, size);
953  }
954 
955  memcpy(state1->data, state2->data, state2->nbytes);
956  state1->nbytes = state2->nbytes;
957  state1->aitems = state2->aitems;
958  state1->nitems = state2->nitems;
959  state1->ndims = state2->ndims;
960  memcpy(state1->dims, state2->dims, sizeof(state2->dims));
961  memcpy(state1->lbs, state2->lbs, sizeof(state2->lbs));
962  state1->array_type = state2->array_type;
963  state1->element_type = state2->element_type;
964 
965  MemoryContextSwitchTo(old_context);
966 
967  PG_RETURN_POINTER(state1);
968  }
969 
970  /* We only need to combine the two states if state2 has any items */
971  else if (state2->nitems > 0)
972  {
973  MemoryContext oldContext;
974  int reqsize = state1->nbytes + state2->nbytes;
975  int i;
976 
977  /*
978  * Check the states are compatible with each other. Ensure we use the
979  * same error messages that are listed in accumArrayResultArr so that
980  * the same error is shown as would have been if we'd not used the
981  * combine function for the aggregation.
982  */
983  if (state1->ndims != state2->ndims)
984  ereport(ERROR,
985  (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
986  errmsg("cannot accumulate arrays of different dimensionality")));
987 
988  /* Check dimensions match ignoring the first dimension. */
989  for (i = 1; i < state1->ndims; i++)
990  {
991  if (state1->dims[i] != state2->dims[i] || state1->lbs[i] != state2->lbs[i])
992  ereport(ERROR,
993  (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
994  errmsg("cannot accumulate arrays of different dimensionality")));
995  }
996 
997 
998  oldContext = MemoryContextSwitchTo(state1->mcontext);
999 
1000  /*
1001  * If there's not enough space in state1 then we'll need to reallocate
1002  * more.
1003  */
1004  if (state1->abytes < reqsize)
1005  {
1006  /* use a power of 2 size rather than allocating just reqsize */
1007  state1->abytes = pg_nextpower2_32(reqsize);
1008  state1->data = (char *) repalloc(state1->data, state1->abytes);
1009  }
1010 
1011  if (state2->nullbitmap)
1012  {
1013  int newnitems = state1->nitems + state2->nitems;
1014 
1015  if (state1->nullbitmap == NULL)
1016  {
1017  /*
1018  * First input with nulls; we must retrospectively handle any
1019  * previous inputs by marking all their items non-null.
1020  */
1021  state1->aitems = pg_nextpower2_32(Max(256, newnitems + 1));
1022  state1->nullbitmap = (bits8 *) palloc((state1->aitems + 7) / 8);
1023  array_bitmap_copy(state1->nullbitmap, 0,
1024  NULL, 0,
1025  state1->nitems);
1026  }
1027  else if (newnitems > state1->aitems)
1028  {
1029  int newaitems = state1->aitems + state2->aitems;
1030 
1031  state1->aitems = pg_nextpower2_32(newaitems);
1032  state1->nullbitmap = (bits8 *)
1033  repalloc(state1->nullbitmap, (state1->aitems + 7) / 8);
1034  }
1035  array_bitmap_copy(state1->nullbitmap, state1->nitems,
1036  state2->nullbitmap, 0,
1037  state2->nitems);
1038  }
1039 
1040  memcpy(state1->data + state1->nbytes, state2->data, state2->nbytes);
1041  state1->nbytes += state2->nbytes;
1042  state1->nitems += state2->nitems;
1043 
1044  state1->dims[0] += state2->dims[0];
1045  /* remaing dims already match, per test above */
1046 
1047  Assert(state1->array_type == state2->array_type);
1048  Assert(state1->element_type == state2->element_type);
1049 
1050  MemoryContextSwitchTo(oldContext);
1051  }
1052 
1053  PG_RETURN_POINTER(state1);
1054 }
1055 
1056 /*
1057  * array_agg_array_serialize
1058  * Serialize ArrayBuildStateArr into bytea.
1059  */
1060 Datum
1062 {
1065  bytea *result;
1066 
1067  /* cannot be called directly because of internal-type argument */
1068  Assert(AggCheckCallContext(fcinfo, NULL));
1069 
1071 
1072  pq_begintypsend(&buf);
1073 
1074  /*
1075  * element_type. Putting this first is more convenient in deserialization
1076  * so that we can init the new state sooner.
1077  */
1078  pq_sendint32(&buf, state->element_type);
1079 
1080  /* array_type */
1081  pq_sendint32(&buf, state->array_type);
1082 
1083  /* nbytes */
1084  pq_sendint32(&buf, state->nbytes);
1085 
1086  /* data */
1087  pq_sendbytes(&buf, state->data, state->nbytes);
1088 
1089  /* abytes */
1090  pq_sendint32(&buf, state->abytes);
1091 
1092  /* aitems */
1093  pq_sendint32(&buf, state->aitems);
1094 
1095  /* nullbitmap */
1096  if (state->nullbitmap)
1097  {
1098  Assert(state->aitems > 0);
1099  pq_sendbytes(&buf, state->nullbitmap, (state->aitems + 7) / 8);
1100  }
1101 
1102  /* nitems */
1103  pq_sendint32(&buf, state->nitems);
1104 
1105  /* ndims */
1106  pq_sendint32(&buf, state->ndims);
1107 
1108  /* dims: XXX should we just send ndims elements? */
1109  pq_sendbytes(&buf, state->dims, sizeof(state->dims));
1110 
1111  /* lbs */
1112  pq_sendbytes(&buf, state->lbs, sizeof(state->lbs));
1113 
1114  result = pq_endtypsend(&buf);
1115 
1116  PG_RETURN_BYTEA_P(result);
1117 }
1118 
1119 Datum
1121 {
1122  bytea *sstate;
1123  ArrayBuildStateArr *result;
1125  Oid element_type;
1126  Oid array_type;
1127  int nbytes;
1128  const char *temp;
1129 
1130  /* cannot be called directly because of internal-type argument */
1131  Assert(AggCheckCallContext(fcinfo, NULL));
1132 
1133  sstate = PG_GETARG_BYTEA_PP(0);
1134 
1135  /*
1136  * Copy the bytea into a StringInfo so that we can "receive" it using the
1137  * standard recv-function infrastructure.
1138  */
1139  initStringInfo(&buf);
1141  VARDATA_ANY(sstate), VARSIZE_ANY_EXHDR(sstate));
1142 
1143  /* element_type */
1144  element_type = pq_getmsgint(&buf, 4);
1145 
1146  /* array_type */
1147  array_type = pq_getmsgint(&buf, 4);
1148 
1149  /* nbytes */
1150  nbytes = pq_getmsgint(&buf, 4);
1151 
1152  result = initArrayResultArr(array_type, element_type,
1153  CurrentMemoryContext, false);
1154 
1155  result->abytes = 1024;
1156  while (result->abytes < nbytes)
1157  result->abytes *= 2;
1158 
1159  result->data = (char *) palloc(result->abytes);
1160 
1161  /* data */
1162  temp = pq_getmsgbytes(&buf, nbytes);
1163  memcpy(result->data, temp, nbytes);
1164  result->nbytes = nbytes;
1165 
1166  /* abytes */
1167  result->abytes = pq_getmsgint(&buf, 4);
1168 
1169  /* aitems: might be 0 */
1170  result->aitems = pq_getmsgint(&buf, 4);
1171 
1172  /* nullbitmap */
1173  if (result->aitems > 0)
1174  {
1175  int size = (result->aitems + 7) / 8;
1176 
1177  result->nullbitmap = (bits8 *) palloc(size);
1178  temp = pq_getmsgbytes(&buf, size);
1179  memcpy(result->nullbitmap, temp, size);
1180  }
1181  else
1182  result->nullbitmap = NULL;
1183 
1184  /* nitems */
1185  result->nitems = pq_getmsgint(&buf, 4);
1186 
1187  /* ndims */
1188  result->ndims = pq_getmsgint(&buf, 4);
1189 
1190  /* dims */
1191  temp = pq_getmsgbytes(&buf, sizeof(result->dims));
1192  memcpy(result->dims, temp, sizeof(result->dims));
1193 
1194  /* lbs */
1195  temp = pq_getmsgbytes(&buf, sizeof(result->lbs));
1196  memcpy(result->lbs, temp, sizeof(result->lbs));
1197 
1198  pq_getmsgend(&buf);
1199  pfree(buf.data);
1200 
1201  PG_RETURN_POINTER(result);
1202 }
1203 
1204 Datum
1206 {
1207  Datum result;
1209 
1210  /* cannot be called directly because of internal-type argument */
1211  Assert(AggCheckCallContext(fcinfo, NULL));
1212 
1214 
1215  if (state == NULL)
1216  PG_RETURN_NULL(); /* returns null iff no input values */
1217 
1218  /*
1219  * Make the result. We cannot release the ArrayBuildStateArr because
1220  * sometimes aggregate final functions are re-executed. Rather, it is
1221  * nodeAgg.c's responsibility to reset the aggcontext when it's safe to do
1222  * so.
1223  */
1224  result = makeArrayResultArr(state, CurrentMemoryContext, false);
1225 
1226  PG_RETURN_DATUM(result);
1227 }
1228 
1229 /*-----------------------------------------------------------------------------
1230  * array_position, array_position_start :
1231  * return the offset of a value in an array.
1232  *
1233  * IS NOT DISTINCT FROM semantics are used for comparisons. Return NULL when
1234  * the value is not found.
1235  *-----------------------------------------------------------------------------
1236  */
1237 Datum
1239 {
1240  return array_position_common(fcinfo);
1241 }
1242 
1243 Datum
1245 {
1246  return array_position_common(fcinfo);
1247 }
1248 
1249 /*
1250  * array_position_common
1251  * Common code for array_position and array_position_start
1252  *
1253  * These are separate wrappers for the sake of opr_sanity regression test.
1254  * They are not strict so we have to test for null inputs explicitly.
1255  */
1256 static Datum
1258 {
1259  ArrayType *array;
1260  Oid collation = PG_GET_COLLATION();
1261  Oid element_type;
1262  Datum searched_element,
1263  value;
1264  bool isnull;
1265  int position,
1266  position_min;
1267  bool found = false;
1268  TypeCacheEntry *typentry;
1269  ArrayMetaState *my_extra;
1270  bool null_search;
1272 
1273  if (PG_ARGISNULL(0))
1274  PG_RETURN_NULL();
1275 
1276  array = PG_GETARG_ARRAYTYPE_P(0);
1277  element_type = ARR_ELEMTYPE(array);
1278 
1279  /*
1280  * We refuse to search for elements in multi-dimensional arrays, since we
1281  * have no good way to report the element's location in the array.
1282  */
1283  if (ARR_NDIM(array) > 1)
1284  ereport(ERROR,
1285  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1286  errmsg("searching for elements in multidimensional arrays is not supported")));
1287 
1288  if (PG_ARGISNULL(1))
1289  {
1290  /* fast return when the array doesn't have nulls */
1291  if (!array_contains_nulls(array))
1292  PG_RETURN_NULL();
1293  searched_element = (Datum) 0;
1294  null_search = true;
1295  }
1296  else
1297  {
1298  searched_element = PG_GETARG_DATUM(1);
1299  null_search = false;
1300  }
1301 
1302  position = (ARR_LBOUND(array))[0] - 1;
1303 
1304  /* figure out where to start */
1305  if (PG_NARGS() == 3)
1306  {
1307  if (PG_ARGISNULL(2))
1308  ereport(ERROR,
1309  (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
1310  errmsg("initial position must not be null")));
1311 
1312  position_min = PG_GETARG_INT32(2);
1313  }
1314  else
1315  position_min = (ARR_LBOUND(array))[0];
1316 
1317  /*
1318  * We arrange to look up type info for array_create_iterator only once per
1319  * series of calls, assuming the element type doesn't change underneath
1320  * us.
1321  */
1322  my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra;
1323  if (my_extra == NULL)
1324  {
1325  fcinfo->flinfo->fn_extra = MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
1326  sizeof(ArrayMetaState));
1327  my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra;
1328  my_extra->element_type = ~element_type;
1329  }
1330 
1331  if (my_extra->element_type != element_type)
1332  {
1333  get_typlenbyvalalign(element_type,
1334  &my_extra->typlen,
1335  &my_extra->typbyval,
1336  &my_extra->typalign);
1337 
1338  typentry = lookup_type_cache(element_type, TYPECACHE_EQ_OPR_FINFO);
1339 
1340  if (!OidIsValid(typentry->eq_opr_finfo.fn_oid))
1341  ereport(ERROR,
1342  (errcode(ERRCODE_UNDEFINED_FUNCTION),
1343  errmsg("could not identify an equality operator for type %s",
1344  format_type_be(element_type))));
1345 
1346  my_extra->element_type = element_type;
1347  fmgr_info_cxt(typentry->eq_opr_finfo.fn_oid, &my_extra->proc,
1348  fcinfo->flinfo->fn_mcxt);
1349  }
1350 
1351  /* Examine each array element until we find a match. */
1352  array_iterator = array_create_iterator(array, 0, my_extra);
1353  while (array_iterate(array_iterator, &value, &isnull))
1354  {
1355  position++;
1356 
1357  /* skip initial elements if caller requested so */
1358  if (position < position_min)
1359  continue;
1360 
1361  /*
1362  * Can't look at the array element's value if it's null; but if we
1363  * search for null, we have a hit and are done.
1364  */
1365  if (isnull || null_search)
1366  {
1367  if (isnull && null_search)
1368  {
1369  found = true;
1370  break;
1371  }
1372  else
1373  continue;
1374  }
1375 
1376  /* not nulls, so run the operator */
1377  if (DatumGetBool(FunctionCall2Coll(&my_extra->proc, collation,
1378  searched_element, value)))
1379  {
1380  found = true;
1381  break;
1382  }
1383  }
1384 
1386 
1387  /* Avoid leaking memory when handed toasted input */
1388  PG_FREE_IF_COPY(array, 0);
1389 
1390  if (!found)
1391  PG_RETURN_NULL();
1392 
1393  PG_RETURN_INT32(position);
1394 }
1395 
1396 /*-----------------------------------------------------------------------------
1397  * array_positions :
1398  * return an array of positions of a value in an array.
1399  *
1400  * IS NOT DISTINCT FROM semantics are used for comparisons. Returns NULL when
1401  * the input array is NULL. When the value is not found in the array, returns
1402  * an empty array.
1403  *
1404  * This is not strict so we have to test for null inputs explicitly.
1405  *-----------------------------------------------------------------------------
1406  */
1407 Datum
1409 {
1410  ArrayType *array;
1411  Oid collation = PG_GET_COLLATION();
1412  Oid element_type;
1413  Datum searched_element,
1414  value;
1415  bool isnull;
1416  int position;
1417  TypeCacheEntry *typentry;
1418  ArrayMetaState *my_extra;
1419  bool null_search;
1421  ArrayBuildState *astate = NULL;
1422 
1423  if (PG_ARGISNULL(0))
1424  PG_RETURN_NULL();
1425 
1426  array = PG_GETARG_ARRAYTYPE_P(0);
1427  element_type = ARR_ELEMTYPE(array);
1428 
1429  position = (ARR_LBOUND(array))[0] - 1;
1430 
1431  /*
1432  * We refuse to search for elements in multi-dimensional arrays, since we
1433  * have no good way to report the element's location in the array.
1434  */
1435  if (ARR_NDIM(array) > 1)
1436  ereport(ERROR,
1437  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1438  errmsg("searching for elements in multidimensional arrays is not supported")));
1439 
1440  astate = initArrayResult(INT4OID, CurrentMemoryContext, false);
1441 
1442  if (PG_ARGISNULL(1))
1443  {
1444  /* fast return when the array doesn't have nulls */
1445  if (!array_contains_nulls(array))
1447  searched_element = (Datum) 0;
1448  null_search = true;
1449  }
1450  else
1451  {
1452  searched_element = PG_GETARG_DATUM(1);
1453  null_search = false;
1454  }
1455 
1456  /*
1457  * We arrange to look up type info for array_create_iterator only once per
1458  * series of calls, assuming the element type doesn't change underneath
1459  * us.
1460  */
1461  my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra;
1462  if (my_extra == NULL)
1463  {
1464  fcinfo->flinfo->fn_extra = MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
1465  sizeof(ArrayMetaState));
1466  my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra;
1467  my_extra->element_type = ~element_type;
1468  }
1469 
1470  if (my_extra->element_type != element_type)
1471  {
1472  get_typlenbyvalalign(element_type,
1473  &my_extra->typlen,
1474  &my_extra->typbyval,
1475  &my_extra->typalign);
1476 
1477  typentry = lookup_type_cache(element_type, TYPECACHE_EQ_OPR_FINFO);
1478 
1479  if (!OidIsValid(typentry->eq_opr_finfo.fn_oid))
1480  ereport(ERROR,
1481  (errcode(ERRCODE_UNDEFINED_FUNCTION),
1482  errmsg("could not identify an equality operator for type %s",
1483  format_type_be(element_type))));
1484 
1485  my_extra->element_type = element_type;
1486  fmgr_info_cxt(typentry->eq_opr_finfo.fn_oid, &my_extra->proc,
1487  fcinfo->flinfo->fn_mcxt);
1488  }
1489 
1490  /*
1491  * Accumulate each array position iff the element matches the given
1492  * element.
1493  */
1494  array_iterator = array_create_iterator(array, 0, my_extra);
1495  while (array_iterate(array_iterator, &value, &isnull))
1496  {
1497  position += 1;
1498 
1499  /*
1500  * Can't look at the array element's value if it's null; but if we
1501  * search for null, we have a hit.
1502  */
1503  if (isnull || null_search)
1504  {
1505  if (isnull && null_search)
1506  astate =
1507  accumArrayResult(astate, Int32GetDatum(position), false,
1508  INT4OID, CurrentMemoryContext);
1509 
1510  continue;
1511  }
1512 
1513  /* not nulls, so run the operator */
1514  if (DatumGetBool(FunctionCall2Coll(&my_extra->proc, collation,
1515  searched_element, value)))
1516  astate =
1517  accumArrayResult(astate, Int32GetDatum(position), false,
1518  INT4OID, CurrentMemoryContext);
1519  }
1520 
1522 
1523  /* Avoid leaking memory when handed toasted input */
1524  PG_FREE_IF_COPY(array, 0);
1525 
1527 }
static bool array_iterator(ArrayType *la, PGCALL2 callback, void *param, ltree **found)
Definition: _ltree_op.c:38
#define ARR_NDIM(a)
Definition: array.h:283
#define PG_GETARG_ARRAYTYPE_P(n)
Definition: array.h:256
#define ARR_DATA_PTR(a)
Definition: array.h:315
#define ARR_NULLBITMAP(a)
Definition: array.h:293
#define ARR_OVERHEAD_WITHNULLS(ndims, nitems)
Definition: array.h:305
#define ARR_ELEMTYPE(a)
Definition: array.h:285
#define PG_RETURN_ARRAYTYPE_P(x)
Definition: array.h:258
#define ARR_SIZE(a)
Definition: array.h:282
#define ARR_OVERHEAD_NONULLS(ndims)
Definition: array.h:303
#define ARR_DATA_OFFSET(a)
Definition: array.h:309
#define ARR_DIMS(a)
Definition: array.h:287
#define ARR_HASNULL(a)
Definition: array.h:284
#define PG_GETARG_EXPANDED_ARRAYX(n, metacache)
Definition: array.h:262
#define ARR_LBOUND(a)
Definition: array.h:289
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)
struct SerialIOData SerialIOData
Datum array_agg_combine(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_agg_finalfn(PG_FUNCTION_ARGS)
Datum array_agg_array_transfn(PG_FUNCTION_ARGS)
Datum array_position_start(PG_FUNCTION_ARGS)
static ExpandedArrayHeader * fetch_array_arg_replace_nulls(FunctionCallInfo fcinfo, int argno)
Datum array_cat(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)
bool array_contains_nulls(ArrayType *array)
Definition: arrayfuncs.c:3736
ArrayBuildState * accumArrayResult(ArrayBuildState *astate, Datum dvalue, bool disnull, Oid element_type, MemoryContext rcontext)
Definition: arrayfuncs.c:5319
ArrayBuildState * initArrayResult(Oid element_type, MemoryContext rcontext, bool subcontext)
Definition: arrayfuncs.c:5262
bool array_iterate(ArrayIterator iterator, Datum *value, bool *isnull)
Definition: arrayfuncs.c:4645
ArrayBuildState * initArrayResultWithSize(Oid element_type, MemoryContext rcontext, bool subcontext, int initsize)
Definition: arrayfuncs.c:5279
void array_free_iterator(ArrayIterator iterator)
Definition: arrayfuncs.c:4728
ArrayBuildStateArr * initArrayResultArr(Oid array_type, Oid element_type, MemoryContext rcontext, bool subcontext)
Definition: arrayfuncs.c:5467
Datum makeArrayResultArr(ArrayBuildStateArr *astate, MemoryContext rcontext, bool release)
Definition: arrayfuncs.c:5666
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:2236
Datum makeMdArrayResult(ArrayBuildState *astate, int ndims, int *dims, int *lbs, MemoryContext rcontext, bool release)
Definition: arrayfuncs.c:5415
ArrayIterator array_create_iterator(ArrayType *arr, int slice_ndim, ArrayMetaState *mstate)
Definition: arrayfuncs.c:4566
ArrayBuildStateArr * accumArrayResultArr(ArrayBuildStateArr *astate, Datum dvalue, bool disnull, Oid array_type, MemoryContext rcontext)
Definition: arrayfuncs.c:5513
Datum makeArrayResult(ArrayBuildState *astate, MemoryContext rcontext)
Definition: arrayfuncs.c:5383
void array_bitmap_copy(bits8 *destbitmap, int destoffset, const bits8 *srcbitmap, int srcoffset, int nitems)
Definition: arrayfuncs.c:4935
ExpandedArrayHeader * construct_empty_expanded_array(Oid element_type, MemoryContext parentcontext, ArrayMetaState *metacache)
Definition: arrayfuncs.c:3566
int ArrayGetNItems(int ndim, const int *dims)
Definition: arrayutils.c:76
void ArrayCheckBounds(int ndim, const int *dims, const int *lb)
Definition: arrayutils.c:138
signed int int32
Definition: c.h:478
#define Max(x, y)
Definition: c.h:982
#define VARHDRSZ
Definition: c.h:676
uint8 bits8
Definition: c.h:497
#define OidIsValid(objectId)
Definition: c.h:759
Datum datumCopy(Datum value, bool typByVal, int typLen)
Definition: datum.c:132
int errdetail(const char *fmt,...)
Definition: elog.c:1202
int errcode(int sqlerrcode)
Definition: elog.c:858
int errmsg(const char *fmt,...)
Definition: elog.c:1069
#define ERROR
Definition: elog.h:39
#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:1121
void fmgr_info_cxt(Oid functionId, FmgrInfo *finfo, MemoryContext mcxt)
Definition: fmgr.c:137
Oid get_fn_expr_argtype(FmgrInfo *flinfo, int argnum)
Definition: fmgr.c:1882
bytea * SendFunctionCall(FmgrInfo *flinfo, Datum val)
Definition: fmgr.c:1716
Datum ReceiveFunctionCall(FmgrInfo *flinfo, StringInfo buf, Oid typioparam, int32 typmod)
Definition: fmgr.c:1669
#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_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:339
#define nitems(x)
Definition: indent.h:31
static struct @145 value
static bool pg_sub_s32_overflow(int32 a, int32 b, int32 *result)
Definition: int.h:122
static bool pg_add_s32_overflow(int32 a, int32 b, int32 *result)
Definition: int.h:104
int i
Definition: isn.c:73
if(TABLE==NULL||TABLE_index==NULL)
Definition: isn.c:77
Assert(fmt[strlen(fmt) - 1] !='\n')
void getTypeBinaryOutputInfo(Oid type, Oid *typSend, bool *typIsVarlena)
Definition: lsyscache.c:2931
Oid get_element_type(Oid typid)
Definition: lsyscache.c:2717
void get_typlenbyvalalign(Oid typid, int16 *typlen, bool *typbyval, char *typalign)
Definition: lsyscache.c:2229
void getTypeBinaryInputInfo(Oid type, Oid *typReceive, Oid *typIOParam)
Definition: lsyscache.c:2898
void pfree(void *pointer)
Definition: mcxt.c:1436
void * palloc0(Size size)
Definition: mcxt.c:1241
MemoryContext CurrentMemoryContext
Definition: mcxt.c:135
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1456
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:1005
void * palloc(Size size)
Definition: mcxt.c:1210
int AggCheckCallContext(FunctionCallInfo fcinfo, MemoryContext *aggcontext)
Definition: nodeAgg.c:4514
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:138
static uint32 pg_nextpower2_32(uint32 num)
Definition: pg_bitutils.h:185
static char * buf
Definition: pg_test_fsync.c:67
static bool DatumGetBool(Datum X)
Definition: postgres.h:90
uintptr_t Datum
Definition: postgres.h:64
static Datum Int32GetDatum(int32 X)
Definition: postgres.h:212
#define InvalidOid
Definition: postgres_ext.h:36
unsigned int Oid
Definition: postgres_ext.h:31
unsigned int pq_getmsgint(StringInfo msg, int b)
Definition: pqformat.c:418
void pq_sendbytes(StringInfo buf, const void *data, int datalen)
Definition: pqformat.c:126
void pq_getmsgend(StringInfo msg)
Definition: pqformat.c:638
const char * pq_getmsgbytes(StringInfo msg, int datalen)
Definition: pqformat.c:511
void pq_begintypsend(StringInfo buf)
Definition: pqformat.c:329
int pq_getmsgbyte(StringInfo msg)
Definition: pqformat.c:402
int64 pq_getmsgint64(StringInfo msg)
Definition: pqformat.c:456
bytea * pq_endtypsend(StringInfo buf)
Definition: pqformat.c:349
static void pq_sendint32(StringInfo buf, uint32 i)
Definition: pqformat.h:145
static void pq_sendbyte(StringInfo buf, uint8 byt)
Definition: pqformat.h:161
static void pq_sendint64(StringInfo buf, uint64 i)
Definition: pqformat.h:153
static void pq_sendint16(StringInfo buf, uint16 i)
Definition: pqformat.h:137
void appendBinaryStringInfo(StringInfo str, const void *data, int datalen)
Definition: stringinfo.c:227
void initStringInfo(StringInfo str)
Definition: stringinfo.c:59
bits8 * nullbitmap
Definition: array.h:202
int lbs[MAXDIM]
Definition: array.h:209
MemoryContext mcontext
Definition: array.h:200
int dims[MAXDIM]
Definition: array.h:208
bool * dnulls
Definition: array.h:184
bool typbyval
Definition: array.h:189
MemoryContext mcontext
Definition: array.h:182
int16 typlen
Definition: array.h:188
char typalign
Definition: array.h:190
Oid element_type
Definition: array.h:187
Datum * dvalues
Definition: array.h:183
char typalign
Definition: array.h:234
int16 typlen
Definition: array.h:232
Oid element_type
Definition: array.h:231
FmgrInfo proc
Definition: array.h:238
bool typbyval
Definition: array.h:233
Oid elemtype
Definition: array.h:90
int ndim
Definition: array.h:88
int32 dataoffset
Definition: array.h:89
FmgrInfo typreceive
ExpandedObjectHeader hdr
Definition: array.h:111
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
FmgrInfo typsend
FmgrInfo eq_opr_finfo
Definition: typcache.h:75
Definition: regguts.h:318
Definition: c.h:671
TypeCacheEntry * lookup_type_cache(Oid type_id, int flags)
Definition: typcache.c:339
#define TYPECACHE_EQ_OPR_FINFO
Definition: typcache.h:141
#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