PostgreSQL Source Code  git master
array_userfuncs.c File Reference
#include "postgres.h"
#include "catalog/pg_type.h"
#include "common/int.h"
#include "utils/array.h"
#include "utils/builtins.h"
#include "utils/lsyscache.h"
#include "utils/typcache.h"
Include dependency graph for array_userfuncs.c:

Go to the source code of this file.

Functions

static Datum array_position_common (FunctionCallInfo fcinfo)
 
static ExpandedArrayHeaderfetch_array_arg_replace_nulls (FunctionCallInfo fcinfo, int argno)
 
Datum array_append (PG_FUNCTION_ARGS)
 
Datum array_prepend (PG_FUNCTION_ARGS)
 
Datum array_cat (PG_FUNCTION_ARGS)
 
Datum array_agg_transfn (PG_FUNCTION_ARGS)
 
Datum array_agg_finalfn (PG_FUNCTION_ARGS)
 
Datum array_agg_array_transfn (PG_FUNCTION_ARGS)
 
Datum array_agg_array_finalfn (PG_FUNCTION_ARGS)
 
Datum array_position (PG_FUNCTION_ARGS)
 
Datum array_position_start (PG_FUNCTION_ARGS)
 
Datum array_positions (PG_FUNCTION_ARGS)
 

Function Documentation

◆ array_agg_array_finalfn()

Datum array_agg_array_finalfn ( PG_FUNCTION_ARGS  )

Definition at line 582 of file array_userfuncs.c.

References AggCheckCallContext(), Assert, CurrentMemoryContext, makeArrayResultArr(), PG_ARGISNULL, PG_GETARG_POINTER, PG_RETURN_DATUM, and PG_RETURN_NULL.

583 {
584  Datum result;
586 
587  /* cannot be called directly because of internal-type argument */
588  Assert(AggCheckCallContext(fcinfo, NULL));
589 
590  state = PG_ARGISNULL(0) ? NULL : (ArrayBuildStateArr *) PG_GETARG_POINTER(0);
591 
592  if (state == NULL)
593  PG_RETURN_NULL(); /* returns null iff no input values */
594 
595  /*
596  * Make the result. We cannot release the ArrayBuildStateArr because
597  * sometimes aggregate final functions are re-executed. Rather, it is
598  * nodeAgg.c's responsibility to reset the aggcontext when it's safe to do
599  * so.
600  */
601  result = makeArrayResultArr(state, CurrentMemoryContext, false);
602 
603  PG_RETURN_DATUM(result);
604 }
Datum makeArrayResultArr(ArrayBuildStateArr *astate, MemoryContext rcontext, bool release)
Definition: arrayfuncs.c:5434
#define PG_GETARG_POINTER(n)
Definition: fmgr.h:276
MemoryContext CurrentMemoryContext
Definition: mcxt.c:42
uintptr_t Datum
Definition: postgres.h:411
#define PG_RETURN_DATUM(x)
Definition: fmgr.h:353
#define PG_ARGISNULL(n)
Definition: fmgr.h:209
#define Assert(condition)
Definition: c.h:804
Definition: regguts.h:317
int AggCheckCallContext(FunctionCallInfo fcinfo, MemoryContext *aggcontext)
Definition: nodeAgg.c:4588
#define PG_RETURN_NULL()
Definition: fmgr.h:345

◆ array_agg_array_transfn()

Datum array_agg_array_transfn ( PG_FUNCTION_ARGS  )

Definition at line 538 of file array_userfuncs.c.

References accumArrayResultArr(), AggCheckCallContext(), elog, ereport, errcode(), errmsg(), ERROR, get_fn_expr_argtype(), initArrayResultArr(), InvalidOid, PG_ARGISNULL, PG_GETARG_DATUM, PG_GETARG_POINTER, and PG_RETURN_POINTER.

539 {
540  Oid arg1_typeid = get_fn_expr_argtype(fcinfo->flinfo, 1);
541  MemoryContext aggcontext;
543 
544  if (arg1_typeid == InvalidOid)
545  ereport(ERROR,
546  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
547  errmsg("could not determine input data type")));
548 
549  /*
550  * Note: we do not need a run-time check about whether arg1_typeid is a
551  * valid array type, because the parser would have verified that while
552  * resolving the input/result types of this polymorphic aggregate.
553  */
554 
555  if (!AggCheckCallContext(fcinfo, &aggcontext))
556  {
557  /* cannot be called directly because of internal-type argument */
558  elog(ERROR, "array_agg_array_transfn called in non-aggregate context");
559  }
560 
561 
562  if (PG_ARGISNULL(0))
563  state = initArrayResultArr(arg1_typeid, InvalidOid, aggcontext, false);
564  else
565  state = (ArrayBuildStateArr *) PG_GETARG_POINTER(0);
566 
567  state = accumArrayResultArr(state,
568  PG_GETARG_DATUM(1),
569  PG_ARGISNULL(1),
570  arg1_typeid,
571  aggcontext);
572 
573  /*
574  * The transition type for array_agg() is declared to be "internal", which
575  * is a pass-by-value type the same size as a pointer. So we can safely
576  * pass the ArrayBuildStateArr pointer through nodeAgg.c's machinations.
577  */
578  PG_RETURN_POINTER(state);
579 }
#define PG_RETURN_POINTER(x)
Definition: fmgr.h:361
#define PG_GETARG_DATUM(n)
Definition: fmgr.h:268
int errcode(int sqlerrcode)
Definition: elog.c:698
#define PG_GETARG_POINTER(n)
Definition: fmgr.h:276
unsigned int Oid
Definition: postgres_ext.h:31
ArrayBuildStateArr * initArrayResultArr(Oid array_type, Oid element_type, MemoryContext rcontext, bool subcontext)
Definition: arrayfuncs.c:5235
#define ERROR
Definition: elog.h:46
Oid get_fn_expr_argtype(FmgrInfo *flinfo, int argnum)
Definition: fmgr.c:1800
ArrayBuildStateArr * accumArrayResultArr(ArrayBuildStateArr *astate, Datum dvalue, bool disnull, Oid array_type, MemoryContext rcontext)
Definition: arrayfuncs.c:5281
#define InvalidOid
Definition: postgres_ext.h:36
#define ereport(elevel,...)
Definition: elog.h:157
#define PG_ARGISNULL(n)
Definition: fmgr.h:209
Definition: regguts.h:317
int AggCheckCallContext(FunctionCallInfo fcinfo, MemoryContext *aggcontext)
Definition: nodeAgg.c:4588
int errmsg(const char *fmt,...)
Definition: elog.c:909
#define elog(elevel,...)
Definition: elog.h:232

◆ array_agg_finalfn()

Datum array_agg_finalfn ( PG_FUNCTION_ARGS  )

Definition at line 503 of file array_userfuncs.c.

References AggCheckCallContext(), Assert, CurrentMemoryContext, makeMdArrayResult(), ArrayBuildState::nelems, PG_ARGISNULL, PG_GETARG_POINTER, PG_RETURN_DATUM, and PG_RETURN_NULL.

504 {
505  Datum result;
507  int dims[1];
508  int lbs[1];
509 
510  /* cannot be called directly because of internal-type argument */
511  Assert(AggCheckCallContext(fcinfo, NULL));
512 
513  state = PG_ARGISNULL(0) ? NULL : (ArrayBuildState *) PG_GETARG_POINTER(0);
514 
515  if (state == NULL)
516  PG_RETURN_NULL(); /* returns null iff no input values */
517 
518  dims[0] = state->nelems;
519  lbs[0] = 1;
520 
521  /*
522  * Make the result. We cannot release the ArrayBuildState because
523  * sometimes aggregate final functions are re-executed. Rather, it is
524  * nodeAgg.c's responsibility to reset the aggcontext when it's safe to do
525  * so.
526  */
527  result = makeMdArrayResult(state, 1, dims, lbs,
529  false);
530 
531  PG_RETURN_DATUM(result);
532 }
Datum makeMdArrayResult(ArrayBuildState *astate, int ndims, int *dims, int *lbs, MemoryContext rcontext, bool release)
Definition: arrayfuncs.c:5183
#define PG_GETARG_POINTER(n)
Definition: fmgr.h:276
MemoryContext CurrentMemoryContext
Definition: mcxt.c:42
uintptr_t Datum
Definition: postgres.h:411
#define PG_RETURN_DATUM(x)
Definition: fmgr.h:353
#define PG_ARGISNULL(n)
Definition: fmgr.h:209
#define Assert(condition)
Definition: c.h:804
Definition: regguts.h:317
int AggCheckCallContext(FunctionCallInfo fcinfo, MemoryContext *aggcontext)
Definition: nodeAgg.c:4588
#define PG_RETURN_NULL()
Definition: fmgr.h:345

◆ array_agg_transfn()

Datum array_agg_transfn ( PG_FUNCTION_ARGS  )

Definition at line 457 of file array_userfuncs.c.

References accumArrayResult(), AggCheckCallContext(), elog, ereport, errcode(), errmsg(), ERROR, get_fn_expr_argtype(), initArrayResult(), InvalidOid, PG_ARGISNULL, PG_GETARG_DATUM, PG_GETARG_POINTER, and PG_RETURN_POINTER.

458 {
459  Oid arg1_typeid = get_fn_expr_argtype(fcinfo->flinfo, 1);
460  MemoryContext aggcontext;
462  Datum elem;
463 
464  if (arg1_typeid == InvalidOid)
465  ereport(ERROR,
466  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
467  errmsg("could not determine input data type")));
468 
469  /*
470  * Note: we do not need a run-time check about whether arg1_typeid is a
471  * valid array element type, because the parser would have verified that
472  * while resolving the input/result types of this polymorphic aggregate.
473  */
474 
475  if (!AggCheckCallContext(fcinfo, &aggcontext))
476  {
477  /* cannot be called directly because of internal-type argument */
478  elog(ERROR, "array_agg_transfn called in non-aggregate context");
479  }
480 
481  if (PG_ARGISNULL(0))
482  state = initArrayResult(arg1_typeid, aggcontext, false);
483  else
484  state = (ArrayBuildState *) PG_GETARG_POINTER(0);
485 
486  elem = PG_ARGISNULL(1) ? (Datum) 0 : PG_GETARG_DATUM(1);
487 
488  state = accumArrayResult(state,
489  elem,
490  PG_ARGISNULL(1),
491  arg1_typeid,
492  aggcontext);
493 
494  /*
495  * The transition type for array_agg() is declared to be "internal", which
496  * is a pass-by-value type the same size as a pointer. So we can safely
497  * pass the ArrayBuildState pointer through nodeAgg.c's machinations.
498  */
499  PG_RETURN_POINTER(state);
500 }
#define PG_RETURN_POINTER(x)
Definition: fmgr.h:361
ArrayBuildState * initArrayResult(Oid element_type, MemoryContext rcontext, bool subcontext)
Definition: arrayfuncs.c:5048
#define PG_GETARG_DATUM(n)
Definition: fmgr.h:268
int errcode(int sqlerrcode)
Definition: elog.c:698
#define PG_GETARG_POINTER(n)
Definition: fmgr.h:276
unsigned int Oid
Definition: postgres_ext.h:31
#define ERROR
Definition: elog.h:46
Oid get_fn_expr_argtype(FmgrInfo *flinfo, int argnum)
Definition: fmgr.c:1800
uintptr_t Datum
Definition: postgres.h:411
#define InvalidOid
Definition: postgres_ext.h:36
#define ereport(elevel,...)
Definition: elog.h:157
#define PG_ARGISNULL(n)
Definition: fmgr.h:209
Definition: regguts.h:317
int AggCheckCallContext(FunctionCallInfo fcinfo, MemoryContext *aggcontext)
Definition: nodeAgg.c:4588
ArrayBuildState * accumArrayResult(ArrayBuildState *astate, Datum dvalue, bool disnull, Oid element_type, MemoryContext rcontext)
Definition: arrayfuncs.c:5087
int errmsg(const char *fmt,...)
Definition: elog.c:909
#define elog(elevel,...)
Definition: elog.h:232

◆ array_append()

Datum array_append ( PG_FUNCTION_ARGS  )

Definition at line 101 of file array_userfuncs.c.

References array_set_element(), ExpandedArrayHeader::dims, EOHPGetRWDatum, ereport, errcode(), errmsg(), ERROR, fetch_array_arg_replace_nulls(), ExpandedArrayHeader::hdr, ExpandedArrayHeader::lbound, ExpandedArrayHeader::ndims, pg_add_s32_overflow(), PG_ARGISNULL, PG_GETARG_DATUM, PG_RETURN_DATUM, ArrayMetaState::typalign, ArrayMetaState::typbyval, and ArrayMetaState::typlen.

102 {
103  ExpandedArrayHeader *eah;
104  Datum newelem;
105  bool isNull;
106  Datum result;
107  int *dimv,
108  *lb;
109  int indx;
110  ArrayMetaState *my_extra;
111 
112  eah = fetch_array_arg_replace_nulls(fcinfo, 0);
113  isNull = PG_ARGISNULL(1);
114  if (isNull)
115  newelem = (Datum) 0;
116  else
117  newelem = PG_GETARG_DATUM(1);
118 
119  if (eah->ndims == 1)
120  {
121  /* append newelem */
122  lb = eah->lbound;
123  dimv = eah->dims;
124 
125  /* index of added elem is at lb[0] + (dimv[0] - 1) + 1 */
126  if (pg_add_s32_overflow(lb[0], dimv[0], &indx))
127  ereport(ERROR,
128  (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
129  errmsg("integer out of range")));
130  }
131  else if (eah->ndims == 0)
132  indx = 1;
133  else
134  ereport(ERROR,
135  (errcode(ERRCODE_DATA_EXCEPTION),
136  errmsg("argument must be empty or one-dimensional array")));
137 
138  /* Perform element insertion */
139  my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra;
140 
141  result = array_set_element(EOHPGetRWDatum(&eah->hdr),
142  1, &indx, newelem, isNull,
143  -1, my_extra->typlen, my_extra->typbyval, my_extra->typalign);
144 
145  PG_RETURN_DATUM(result);
146 }
#define PG_GETARG_DATUM(n)
Definition: fmgr.h:268
int errcode(int sqlerrcode)
Definition: elog.c:698
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:2211
bool typbyval
Definition: array.h:233
static ExpandedArrayHeader * fetch_array_arg_replace_nulls(FunctionCallInfo fcinfo, int argno)
#define ERROR
Definition: elog.h:46
ExpandedObjectHeader hdr
Definition: array.h:111
int16 typlen
Definition: array.h:232
uintptr_t Datum
Definition: postgres.h:411
#define PG_RETURN_DATUM(x)
Definition: fmgr.h:353
#define ereport(elevel,...)
Definition: elog.h:157
#define PG_ARGISNULL(n)
Definition: fmgr.h:209
static bool pg_add_s32_overflow(int32 a, int32 b, int32 *result)
Definition: int.h:104
char typalign
Definition: array.h:234
#define EOHPGetRWDatum(eohptr)
int errmsg(const char *fmt,...)
Definition: elog.c:909

◆ array_cat()

Datum array_cat ( PG_FUNCTION_ARGS  )

Definition at line 218 of file array_userfuncs.c.

References ARR_DATA_OFFSET, ARR_DATA_PTR, ARR_DIMS, ARR_ELEMTYPE, ARR_HASNULL, ARR_LBOUND, ARR_NDIM, ARR_NULLBITMAP, ARR_OVERHEAD_NONULLS, ARR_OVERHEAD_WITHNULLS, ARR_SIZE, array_bitmap_copy(), ArrayCheckBounds(), ArrayGetNItems(), ArrayType::dataoffset, ArrayType::elemtype, ereport, errcode(), errdetail(), errmsg(), ERROR, format_type_be(), i, ArrayType::ndim, palloc(), palloc0(), PG_ARGISNULL, PG_GETARG_ARRAYTYPE_P, PG_RETURN_ARRAYTYPE_P, PG_RETURN_NULL, and SET_VARSIZE.

219 {
220  ArrayType *v1,
221  *v2;
222  ArrayType *result;
223  int *dims,
224  *lbs,
225  ndims,
226  nitems,
227  ndatabytes,
228  nbytes;
229  int *dims1,
230  *lbs1,
231  ndims1,
232  nitems1,
233  ndatabytes1;
234  int *dims2,
235  *lbs2,
236  ndims2,
237  nitems2,
238  ndatabytes2;
239  int i;
240  char *dat1,
241  *dat2;
242  bits8 *bitmap1,
243  *bitmap2;
244  Oid element_type;
245  Oid element_type1;
246  Oid element_type2;
247  int32 dataoffset;
248 
249  /* Concatenating a null array is a no-op, just return the other input */
250  if (PG_ARGISNULL(0))
251  {
252  if (PG_ARGISNULL(1))
253  PG_RETURN_NULL();
254  result = PG_GETARG_ARRAYTYPE_P(1);
255  PG_RETURN_ARRAYTYPE_P(result);
256  }
257  if (PG_ARGISNULL(1))
258  {
259  result = PG_GETARG_ARRAYTYPE_P(0);
260  PG_RETURN_ARRAYTYPE_P(result);
261  }
262 
263  v1 = PG_GETARG_ARRAYTYPE_P(0);
264  v2 = PG_GETARG_ARRAYTYPE_P(1);
265 
266  element_type1 = ARR_ELEMTYPE(v1);
267  element_type2 = ARR_ELEMTYPE(v2);
268 
269  /* Check we have matching element types */
270  if (element_type1 != element_type2)
271  ereport(ERROR,
272  (errcode(ERRCODE_DATATYPE_MISMATCH),
273  errmsg("cannot concatenate incompatible arrays"),
274  errdetail("Arrays with element types %s and %s are not "
275  "compatible for concatenation.",
276  format_type_be(element_type1),
277  format_type_be(element_type2))));
278 
279  /* OK, use it */
280  element_type = element_type1;
281 
282  /*----------
283  * We must have one of the following combinations of inputs:
284  * 1) one empty array, and one non-empty array
285  * 2) both arrays empty
286  * 3) two arrays with ndims1 == ndims2
287  * 4) ndims1 == ndims2 - 1
288  * 5) ndims1 == ndims2 + 1
289  *----------
290  */
291  ndims1 = ARR_NDIM(v1);
292  ndims2 = ARR_NDIM(v2);
293 
294  /*
295  * short circuit - if one input array is empty, and the other is not, we
296  * return the non-empty one as the result
297  *
298  * if both are empty, return the first one
299  */
300  if (ndims1 == 0 && ndims2 > 0)
302 
303  if (ndims2 == 0)
305 
306  /* the rest fall under rule 3, 4, or 5 */
307  if (ndims1 != ndims2 &&
308  ndims1 != ndims2 - 1 &&
309  ndims1 != ndims2 + 1)
310  ereport(ERROR,
311  (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
312  errmsg("cannot concatenate incompatible arrays"),
313  errdetail("Arrays of %d and %d dimensions are not "
314  "compatible for concatenation.",
315  ndims1, ndims2)));
316 
317  /* get argument array details */
318  lbs1 = ARR_LBOUND(v1);
319  lbs2 = ARR_LBOUND(v2);
320  dims1 = ARR_DIMS(v1);
321  dims2 = ARR_DIMS(v2);
322  dat1 = ARR_DATA_PTR(v1);
323  dat2 = ARR_DATA_PTR(v2);
324  bitmap1 = ARR_NULLBITMAP(v1);
325  bitmap2 = ARR_NULLBITMAP(v2);
326  nitems1 = ArrayGetNItems(ndims1, dims1);
327  nitems2 = ArrayGetNItems(ndims2, dims2);
328  ndatabytes1 = ARR_SIZE(v1) - ARR_DATA_OFFSET(v1);
329  ndatabytes2 = ARR_SIZE(v2) - ARR_DATA_OFFSET(v2);
330 
331  if (ndims1 == ndims2)
332  {
333  /*
334  * resulting array is made up of the elements (possibly arrays
335  * themselves) of the input argument arrays
336  */
337  ndims = ndims1;
338  dims = (int *) palloc(ndims * sizeof(int));
339  lbs = (int *) palloc(ndims * sizeof(int));
340 
341  dims[0] = dims1[0] + dims2[0];
342  lbs[0] = lbs1[0];
343 
344  for (i = 1; i < ndims; i++)
345  {
346  if (dims1[i] != dims2[i] || lbs1[i] != lbs2[i])
347  ereport(ERROR,
348  (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
349  errmsg("cannot concatenate incompatible arrays"),
350  errdetail("Arrays with differing element dimensions are "
351  "not compatible for concatenation.")));
352 
353  dims[i] = dims1[i];
354  lbs[i] = lbs1[i];
355  }
356  }
357  else if (ndims1 == ndims2 - 1)
358  {
359  /*
360  * resulting array has the second argument as the outer array, with
361  * the first argument inserted at the front of the outer dimension
362  */
363  ndims = ndims2;
364  dims = (int *) palloc(ndims * sizeof(int));
365  lbs = (int *) palloc(ndims * sizeof(int));
366  memcpy(dims, dims2, ndims * sizeof(int));
367  memcpy(lbs, lbs2, ndims * sizeof(int));
368 
369  /* increment number of elements in outer array */
370  dims[0] += 1;
371 
372  /* make sure the added element matches our existing elements */
373  for (i = 0; i < ndims1; i++)
374  {
375  if (dims1[i] != dims[i + 1] || lbs1[i] != lbs[i + 1])
376  ereport(ERROR,
377  (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
378  errmsg("cannot concatenate incompatible arrays"),
379  errdetail("Arrays with differing dimensions are not "
380  "compatible for concatenation.")));
381  }
382  }
383  else
384  {
385  /*
386  * (ndims1 == ndims2 + 1)
387  *
388  * resulting array has the first argument as the outer array, with the
389  * second argument appended to the end of the outer dimension
390  */
391  ndims = ndims1;
392  dims = (int *) palloc(ndims * sizeof(int));
393  lbs = (int *) palloc(ndims * sizeof(int));
394  memcpy(dims, dims1, ndims * sizeof(int));
395  memcpy(lbs, lbs1, ndims * sizeof(int));
396 
397  /* increment number of elements in outer array */
398  dims[0] += 1;
399 
400  /* make sure the added element matches our existing elements */
401  for (i = 0; i < ndims2; i++)
402  {
403  if (dims2[i] != dims[i + 1] || lbs2[i] != lbs[i + 1])
404  ereport(ERROR,
405  (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
406  errmsg("cannot concatenate incompatible arrays"),
407  errdetail("Arrays with differing dimensions are not "
408  "compatible for concatenation.")));
409  }
410  }
411 
412  /* Do this mainly for overflow checking */
413  nitems = ArrayGetNItems(ndims, dims);
414  ArrayCheckBounds(ndims, dims, lbs);
415 
416  /* build the result array */
417  ndatabytes = ndatabytes1 + ndatabytes2;
418  if (ARR_HASNULL(v1) || ARR_HASNULL(v2))
419  {
420  dataoffset = ARR_OVERHEAD_WITHNULLS(ndims, nitems);
421  nbytes = ndatabytes + dataoffset;
422  }
423  else
424  {
425  dataoffset = 0; /* marker for no null bitmap */
426  nbytes = ndatabytes + ARR_OVERHEAD_NONULLS(ndims);
427  }
428  result = (ArrayType *) palloc0(nbytes);
429  SET_VARSIZE(result, nbytes);
430  result->ndim = ndims;
431  result->dataoffset = dataoffset;
432  result->elemtype = element_type;
433  memcpy(ARR_DIMS(result), dims, ndims * sizeof(int));
434  memcpy(ARR_LBOUND(result), lbs, ndims * sizeof(int));
435  /* data area is arg1 then arg2 */
436  memcpy(ARR_DATA_PTR(result), dat1, ndatabytes1);
437  memcpy(ARR_DATA_PTR(result) + ndatabytes1, dat2, ndatabytes2);
438  /* handle the null bitmap if needed */
439  if (ARR_HASNULL(result))
440  {
442  bitmap1, 0,
443  nitems1);
444  array_bitmap_copy(ARR_NULLBITMAP(result), nitems1,
445  bitmap2, 0,
446  nitems2);
447  }
448 
449  PG_RETURN_ARRAYTYPE_P(result);
450 }
#define ARR_OVERHEAD_NONULLS(ndims)
Definition: array.h:303
#define ARR_SIZE(a)
Definition: array.h:282
void array_bitmap_copy(bits8 *destbitmap, int destoffset, const bits8 *srcbitmap, int srcoffset, int nitems)
Definition: arrayfuncs.c:4721
int32 dataoffset
Definition: array.h:89
int ArrayGetNItems(int ndim, const int *dims)
Definition: arrayutils.c:76
int errcode(int sqlerrcode)
Definition: elog.c:698
char * format_type_be(Oid type_oid)
Definition: format_type.c:339
unsigned int Oid
Definition: postgres_ext.h:31
#define ARR_OVERHEAD_WITHNULLS(ndims, nitems)
Definition: array.h:305
signed int int32
Definition: c.h:429
#define ARR_DATA_OFFSET(a)
Definition: array.h:309
#define ARR_LBOUND(a)
Definition: array.h:289
#define PG_GETARG_ARRAYTYPE_P(n)
Definition: array.h:256
#define ERROR
Definition: elog.h:46
Oid elemtype
Definition: array.h:90
#define ARR_DIMS(a)
Definition: array.h:287
#define ARR_DATA_PTR(a)
Definition: array.h:315
int errdetail(const char *fmt,...)
Definition: elog.c:1042
#define ARR_HASNULL(a)
Definition: array.h:284
#define PG_RETURN_ARRAYTYPE_P(x)
Definition: array.h:258
void ArrayCheckBounds(int ndim, const int *dims, const int *lb)
Definition: arrayutils.c:128
uint8 bits8
Definition: c.h:448
void * palloc0(Size size)
Definition: mcxt.c:1093
#define ereport(elevel,...)
Definition: elog.h:157
#define PG_ARGISNULL(n)
Definition: fmgr.h:209
#define ARR_NDIM(a)
Definition: array.h:283
void * palloc(Size size)
Definition: mcxt.c:1062
int errmsg(const char *fmt,...)
Definition: elog.c:909
int i
#define SET_VARSIZE(PTR, len)
Definition: postgres.h:342
#define ARR_ELEMTYPE(a)
Definition: array.h:285
#define ARR_NULLBITMAP(a)
Definition: array.h:293
#define PG_RETURN_NULL()
Definition: fmgr.h:345
int ndim
Definition: array.h:88

◆ array_position()

Datum array_position ( PG_FUNCTION_ARGS  )

Definition at line 615 of file array_userfuncs.c.

References array_position_common().

Referenced by MakeOldSnapshotTimeMappingTuple().

616 {
617  return array_position_common(fcinfo);
618 }
static Datum array_position_common(FunctionCallInfo fcinfo)

◆ array_position_common()

static Datum array_position_common ( FunctionCallInfo  fcinfo)
static

Definition at line 634 of file array_userfuncs.c.

References ARR_ELEMTYPE, ARR_LBOUND, ARR_NDIM, array_contains_nulls(), array_create_iterator(), array_free_iterator(), array_iterate(), array_iterator(), DatumGetBool, ArrayMetaState::element_type, TypeCacheEntry::eq_opr_finfo, ereport, errcode(), errmsg(), ERROR, FunctionCallInfoBaseData::flinfo, fmgr_info_cxt(), FmgrInfo::fn_extra, FmgrInfo::fn_mcxt, FmgrInfo::fn_oid, format_type_be(), FunctionCall2Coll(), get_typlenbyvalalign(), lookup_type_cache(), MemoryContextAlloc(), OidIsValid, PG_ARGISNULL, PG_FREE_IF_COPY, PG_GET_COLLATION, PG_GETARG_ARRAYTYPE_P, PG_GETARG_DATUM, PG_GETARG_INT32, PG_NARGS, PG_RETURN_INT32, PG_RETURN_NULL, ArrayMetaState::proc, ArrayMetaState::typalign, ArrayMetaState::typbyval, TYPECACHE_EQ_OPR_FINFO, ArrayMetaState::typlen, and value.

Referenced by array_position(), and array_position_start().

635 {
636  ArrayType *array;
637  Oid collation = PG_GET_COLLATION();
638  Oid element_type;
639  Datum searched_element,
640  value;
641  bool isnull;
642  int position,
643  position_min;
644  bool found = false;
645  TypeCacheEntry *typentry;
646  ArrayMetaState *my_extra;
647  bool null_search;
649 
650  if (PG_ARGISNULL(0))
651  PG_RETURN_NULL();
652 
653  array = PG_GETARG_ARRAYTYPE_P(0);
654  element_type = ARR_ELEMTYPE(array);
655 
656  /*
657  * We refuse to search for elements in multi-dimensional arrays, since we
658  * have no good way to report the element's location in the array.
659  */
660  if (ARR_NDIM(array) > 1)
661  ereport(ERROR,
662  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
663  errmsg("searching for elements in multidimensional arrays is not supported")));
664 
665  if (PG_ARGISNULL(1))
666  {
667  /* fast return when the array doesn't have nulls */
668  if (!array_contains_nulls(array))
669  PG_RETURN_NULL();
670  searched_element = (Datum) 0;
671  null_search = true;
672  }
673  else
674  {
675  searched_element = PG_GETARG_DATUM(1);
676  null_search = false;
677  }
678 
679  position = (ARR_LBOUND(array))[0] - 1;
680 
681  /* figure out where to start */
682  if (PG_NARGS() == 3)
683  {
684  if (PG_ARGISNULL(2))
685  ereport(ERROR,
686  (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
687  errmsg("initial position must not be null")));
688 
689  position_min = PG_GETARG_INT32(2);
690  }
691  else
692  position_min = (ARR_LBOUND(array))[0];
693 
694  /*
695  * We arrange to look up type info for array_create_iterator only once per
696  * series of calls, assuming the element type doesn't change underneath
697  * us.
698  */
699  my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra;
700  if (my_extra == NULL)
701  {
702  fcinfo->flinfo->fn_extra = MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
703  sizeof(ArrayMetaState));
704  my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra;
705  my_extra->element_type = ~element_type;
706  }
707 
708  if (my_extra->element_type != element_type)
709  {
710  get_typlenbyvalalign(element_type,
711  &my_extra->typlen,
712  &my_extra->typbyval,
713  &my_extra->typalign);
714 
715  typentry = lookup_type_cache(element_type, TYPECACHE_EQ_OPR_FINFO);
716 
717  if (!OidIsValid(typentry->eq_opr_finfo.fn_oid))
718  ereport(ERROR,
719  (errcode(ERRCODE_UNDEFINED_FUNCTION),
720  errmsg("could not identify an equality operator for type %s",
721  format_type_be(element_type))));
722 
723  my_extra->element_type = element_type;
724  fmgr_info_cxt(typentry->eq_opr_finfo.fn_oid, &my_extra->proc,
725  fcinfo->flinfo->fn_mcxt);
726  }
727 
728  /* Examine each array element until we find a match. */
729  array_iterator = array_create_iterator(array, 0, my_extra);
730  while (array_iterate(array_iterator, &value, &isnull))
731  {
732  position++;
733 
734  /* skip initial elements if caller requested so */
735  if (position < position_min)
736  continue;
737 
738  /*
739  * Can't look at the array element's value if it's null; but if we
740  * search for null, we have a hit and are done.
741  */
742  if (isnull || null_search)
743  {
744  if (isnull && null_search)
745  {
746  found = true;
747  break;
748  }
749  else
750  continue;
751  }
752 
753  /* not nulls, so run the operator */
754  if (DatumGetBool(FunctionCall2Coll(&my_extra->proc, collation,
755  searched_element, value)))
756  {
757  found = true;
758  break;
759  }
760  }
761 
762  array_free_iterator(array_iterator);
763 
764  /* Avoid leaking memory when handed toasted input */
765  PG_FREE_IF_COPY(array, 0);
766 
767  if (!found)
768  PG_RETURN_NULL();
769 
770  PG_RETURN_INT32(position);
771 }
ArrayIterator array_create_iterator(ArrayType *arr, int slice_ndim, ArrayMetaState *mstate)
Definition: arrayfuncs.c:4352
#define PG_GETARG_INT32(n)
Definition: fmgr.h:269
MemoryContext fn_mcxt
Definition: fmgr.h:65
static struct @142 value
void get_typlenbyvalalign(Oid typid, int16 *typlen, bool *typbyval, char *typalign)
Definition: lsyscache.c:2218
#define PG_GETARG_DATUM(n)
Definition: fmgr.h:268
#define TYPECACHE_EQ_OPR_FINFO
Definition: typcache.h:141
#define PG_RETURN_INT32(x)
Definition: fmgr.h:354
int errcode(int sqlerrcode)
Definition: elog.c:698
char * format_type_be(Oid type_oid)
Definition: format_type.c:339
Datum FunctionCall2Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2)
Definition: fmgr.c:1148
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:710
#define PG_GET_COLLATION()
Definition: fmgr.h:198
#define ARR_LBOUND(a)
Definition: array.h:289
bool typbyval
Definition: array.h:233
#define PG_GETARG_ARRAYTYPE_P(n)
Definition: array.h:256
bool array_iterate(ArrayIterator iterator, Datum *value, bool *isnull)
Definition: arrayfuncs.c:4431
#define ERROR
Definition: elog.h:46
static bool array_iterator(ArrayType *la, PGCALL2 callback, void *param, ltree **found)
Definition: _ltree_op.c:37
int16 typlen
Definition: array.h:232
#define DatumGetBool(X)
Definition: postgres.h:437
void fmgr_info_cxt(Oid functionId, FmgrInfo *finfo, MemoryContext mcxt)
Definition: fmgr.c:136
uintptr_t Datum
Definition: postgres.h:411
FmgrInfo * flinfo
Definition: fmgr.h:87
FmgrInfo eq_opr_finfo
Definition: typcache.h:75
TypeCacheEntry * lookup_type_cache(Oid type_id, int flags)
Definition: typcache.c:338
Oid fn_oid
Definition: fmgr.h:59
#define ereport(elevel,...)
Definition: elog.h:157
void array_free_iterator(ArrayIterator iterator)
Definition: arrayfuncs.c:4514
#define PG_ARGISNULL(n)
Definition: fmgr.h:209
#define PG_FREE_IF_COPY(ptr, n)
Definition: fmgr.h:260
#define PG_NARGS()
Definition: fmgr.h:203
void * fn_extra
Definition: fmgr.h:64
#define ARR_NDIM(a)
Definition: array.h:283
char typalign
Definition: array.h:234
int errmsg(const char *fmt,...)
Definition: elog.c:909
FmgrInfo proc
Definition: array.h:238
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:863
Oid element_type
Definition: array.h:231
bool array_contains_nulls(ArrayType *array)
Definition: arrayfuncs.c:3557
#define ARR_ELEMTYPE(a)
Definition: array.h:285
#define PG_RETURN_NULL()
Definition: fmgr.h:345

◆ array_position_start()

Datum array_position_start ( PG_FUNCTION_ARGS  )

Definition at line 621 of file array_userfuncs.c.

References array_position_common().

622 {
623  return array_position_common(fcinfo);
624 }
static Datum array_position_common(FunctionCallInfo fcinfo)

◆ array_positions()

Datum array_positions ( PG_FUNCTION_ARGS  )

Definition at line 785 of file array_userfuncs.c.

References accumArrayResult(), ARR_ELEMTYPE, ARR_LBOUND, ARR_NDIM, array_contains_nulls(), array_create_iterator(), array_free_iterator(), array_iterate(), array_iterator(), CurrentMemoryContext, DatumGetBool, ArrayMetaState::element_type, TypeCacheEntry::eq_opr_finfo, ereport, errcode(), errmsg(), ERROR, fmgr_info_cxt(), FmgrInfo::fn_mcxt, FmgrInfo::fn_oid, format_type_be(), FunctionCall2Coll(), get_typlenbyvalalign(), initArrayResult(), Int32GetDatum, lookup_type_cache(), makeArrayResult(), MemoryContextAlloc(), OidIsValid, PG_ARGISNULL, PG_FREE_IF_COPY, PG_GET_COLLATION, PG_GETARG_ARRAYTYPE_P, PG_GETARG_DATUM, PG_RETURN_DATUM, PG_RETURN_NULL, ArrayMetaState::proc, ArrayMetaState::typalign, ArrayMetaState::typbyval, TYPECACHE_EQ_OPR_FINFO, ArrayMetaState::typlen, and value.

786 {
787  ArrayType *array;
788  Oid collation = PG_GET_COLLATION();
789  Oid element_type;
790  Datum searched_element,
791  value;
792  bool isnull;
793  int position;
794  TypeCacheEntry *typentry;
795  ArrayMetaState *my_extra;
796  bool null_search;
798  ArrayBuildState *astate = NULL;
799 
800  if (PG_ARGISNULL(0))
801  PG_RETURN_NULL();
802 
803  array = PG_GETARG_ARRAYTYPE_P(0);
804  element_type = ARR_ELEMTYPE(array);
805 
806  position = (ARR_LBOUND(array))[0] - 1;
807 
808  /*
809  * We refuse to search for elements in multi-dimensional arrays, since we
810  * have no good way to report the element's location in the array.
811  */
812  if (ARR_NDIM(array) > 1)
813  ereport(ERROR,
814  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
815  errmsg("searching for elements in multidimensional arrays is not supported")));
816 
817  astate = initArrayResult(INT4OID, CurrentMemoryContext, false);
818 
819  if (PG_ARGISNULL(1))
820  {
821  /* fast return when the array doesn't have nulls */
822  if (!array_contains_nulls(array))
824  searched_element = (Datum) 0;
825  null_search = true;
826  }
827  else
828  {
829  searched_element = PG_GETARG_DATUM(1);
830  null_search = false;
831  }
832 
833  /*
834  * We arrange to look up type info for array_create_iterator only once per
835  * series of calls, assuming the element type doesn't change underneath
836  * us.
837  */
838  my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra;
839  if (my_extra == NULL)
840  {
841  fcinfo->flinfo->fn_extra = MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
842  sizeof(ArrayMetaState));
843  my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra;
844  my_extra->element_type = ~element_type;
845  }
846 
847  if (my_extra->element_type != element_type)
848  {
849  get_typlenbyvalalign(element_type,
850  &my_extra->typlen,
851  &my_extra->typbyval,
852  &my_extra->typalign);
853 
854  typentry = lookup_type_cache(element_type, TYPECACHE_EQ_OPR_FINFO);
855 
856  if (!OidIsValid(typentry->eq_opr_finfo.fn_oid))
857  ereport(ERROR,
858  (errcode(ERRCODE_UNDEFINED_FUNCTION),
859  errmsg("could not identify an equality operator for type %s",
860  format_type_be(element_type))));
861 
862  my_extra->element_type = element_type;
863  fmgr_info_cxt(typentry->eq_opr_finfo.fn_oid, &my_extra->proc,
864  fcinfo->flinfo->fn_mcxt);
865  }
866 
867  /*
868  * Accumulate each array position iff the element matches the given
869  * element.
870  */
871  array_iterator = array_create_iterator(array, 0, my_extra);
872  while (array_iterate(array_iterator, &value, &isnull))
873  {
874  position += 1;
875 
876  /*
877  * Can't look at the array element's value if it's null; but if we
878  * search for null, we have a hit.
879  */
880  if (isnull || null_search)
881  {
882  if (isnull && null_search)
883  astate =
884  accumArrayResult(astate, Int32GetDatum(position), false,
885  INT4OID, CurrentMemoryContext);
886 
887  continue;
888  }
889 
890  /* not nulls, so run the operator */
891  if (DatumGetBool(FunctionCall2Coll(&my_extra->proc, collation,
892  searched_element, value)))
893  astate =
894  accumArrayResult(astate, Int32GetDatum(position), false,
895  INT4OID, CurrentMemoryContext);
896  }
897 
898  array_free_iterator(array_iterator);
899 
900  /* Avoid leaking memory when handed toasted input */
901  PG_FREE_IF_COPY(array, 0);
902 
904 }
ArrayIterator array_create_iterator(ArrayType *arr, int slice_ndim, ArrayMetaState *mstate)
Definition: arrayfuncs.c:4352
MemoryContext fn_mcxt
Definition: fmgr.h:65
static struct @142 value
ArrayBuildState * initArrayResult(Oid element_type, MemoryContext rcontext, bool subcontext)
Definition: arrayfuncs.c:5048
void get_typlenbyvalalign(Oid typid, int16 *typlen, bool *typbyval, char *typalign)
Definition: lsyscache.c:2218
#define PG_GETARG_DATUM(n)
Definition: fmgr.h:268
#define TYPECACHE_EQ_OPR_FINFO
Definition: typcache.h:141
int errcode(int sqlerrcode)
Definition: elog.c:698
char * format_type_be(Oid type_oid)
Definition: format_type.c:339
Datum FunctionCall2Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2)
Definition: fmgr.c:1148
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:710
#define PG_GET_COLLATION()
Definition: fmgr.h:198
#define ARR_LBOUND(a)
Definition: array.h:289
bool typbyval
Definition: array.h:233
#define PG_GETARG_ARRAYTYPE_P(n)
Definition: array.h:256
bool array_iterate(ArrayIterator iterator, Datum *value, bool *isnull)
Definition: arrayfuncs.c:4431
#define ERROR
Definition: elog.h:46
static bool array_iterator(ArrayType *la, PGCALL2 callback, void *param, ltree **found)
Definition: _ltree_op.c:37
int16 typlen
Definition: array.h:232
#define DatumGetBool(X)
Definition: postgres.h:437
MemoryContext CurrentMemoryContext
Definition: mcxt.c:42
void fmgr_info_cxt(Oid functionId, FmgrInfo *finfo, MemoryContext mcxt)
Definition: fmgr.c:136
Datum makeArrayResult(ArrayBuildState *astate, MemoryContext rcontext)
Definition: arrayfuncs.c:5151
uintptr_t Datum
Definition: postgres.h:411
#define PG_RETURN_DATUM(x)
Definition: fmgr.h:353
FmgrInfo eq_opr_finfo
Definition: typcache.h:75
TypeCacheEntry * lookup_type_cache(Oid type_id, int flags)
Definition: typcache.c:338
Oid fn_oid
Definition: fmgr.h:59
#define ereport(elevel,...)
Definition: elog.h:157
void array_free_iterator(ArrayIterator iterator)
Definition: arrayfuncs.c:4514
#define PG_ARGISNULL(n)
Definition: fmgr.h:209
#define PG_FREE_IF_COPY(ptr, n)
Definition: fmgr.h:260
#define ARR_NDIM(a)
Definition: array.h:283
char typalign
Definition: array.h:234
ArrayBuildState * accumArrayResult(ArrayBuildState *astate, Datum dvalue, bool disnull, Oid element_type, MemoryContext rcontext)
Definition: arrayfuncs.c:5087
#define Int32GetDatum(X)
Definition: postgres.h:523
int errmsg(const char *fmt,...)
Definition: elog.c:909
FmgrInfo proc
Definition: array.h:238
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:863
Oid element_type
Definition: array.h:231
bool array_contains_nulls(ArrayType *array)
Definition: arrayfuncs.c:3557
#define ARR_ELEMTYPE(a)
Definition: array.h:285
#define PG_RETURN_NULL()
Definition: fmgr.h:345

◆ array_prepend()

Datum array_prepend ( PG_FUNCTION_ARGS  )

Definition at line 154 of file array_userfuncs.c.

References array_set_element(), Assert, EOHPGetRWDatum, ereport, errcode(), errmsg(), ERROR, fetch_array_arg_replace_nulls(), ExpandedArrayHeader::hdr, ExpandedArrayHeader::lbound, ExpandedArrayHeader::ndims, PG_ARGISNULL, PG_GETARG_DATUM, PG_RETURN_DATUM, pg_sub_s32_overflow(), ArrayMetaState::typalign, ArrayMetaState::typbyval, and ArrayMetaState::typlen.

155 {
156  ExpandedArrayHeader *eah;
157  Datum newelem;
158  bool isNull;
159  Datum result;
160  int *lb;
161  int indx;
162  int lb0;
163  ArrayMetaState *my_extra;
164 
165  isNull = PG_ARGISNULL(0);
166  if (isNull)
167  newelem = (Datum) 0;
168  else
169  newelem = PG_GETARG_DATUM(0);
170  eah = fetch_array_arg_replace_nulls(fcinfo, 1);
171 
172  if (eah->ndims == 1)
173  {
174  /* prepend newelem */
175  lb = eah->lbound;
176  lb0 = lb[0];
177 
178  if (pg_sub_s32_overflow(lb0, 1, &indx))
179  ereport(ERROR,
180  (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
181  errmsg("integer out of range")));
182  }
183  else if (eah->ndims == 0)
184  {
185  indx = 1;
186  lb0 = 1;
187  }
188  else
189  ereport(ERROR,
190  (errcode(ERRCODE_DATA_EXCEPTION),
191  errmsg("argument must be empty or one-dimensional array")));
192 
193  /* Perform element insertion */
194  my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra;
195 
196  result = array_set_element(EOHPGetRWDatum(&eah->hdr),
197  1, &indx, newelem, isNull,
198  -1, my_extra->typlen, my_extra->typbyval, my_extra->typalign);
199 
200  /* Readjust result's LB to match the input's, as expected for prepend */
201  Assert(result == EOHPGetRWDatum(&eah->hdr));
202  if (eah->ndims == 1)
203  {
204  /* This is ok whether we've deconstructed or not */
205  eah->lbound[0] = lb0;
206  }
207 
208  PG_RETURN_DATUM(result);
209 }
#define PG_GETARG_DATUM(n)
Definition: fmgr.h:268
int errcode(int sqlerrcode)
Definition: elog.c:698
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:2211
bool typbyval
Definition: array.h:233
static ExpandedArrayHeader * fetch_array_arg_replace_nulls(FunctionCallInfo fcinfo, int argno)
#define ERROR
Definition: elog.h:46
ExpandedObjectHeader hdr
Definition: array.h:111
int16 typlen
Definition: array.h:232
static bool pg_sub_s32_overflow(int32 a, int32 b, int32 *result)
Definition: int.h:122
uintptr_t Datum
Definition: postgres.h:411
#define PG_RETURN_DATUM(x)
Definition: fmgr.h:353
#define ereport(elevel,...)
Definition: elog.h:157
#define PG_ARGISNULL(n)
Definition: fmgr.h:209
#define Assert(condition)
Definition: c.h:804
char typalign
Definition: array.h:234
#define EOHPGetRWDatum(eohptr)
int errmsg(const char *fmt,...)
Definition: elog.c:909

◆ fetch_array_arg_replace_nulls()

static ExpandedArrayHeader* fetch_array_arg_replace_nulls ( FunctionCallInfo  fcinfo,
int  argno 
)
static

Definition at line 42 of file array_userfuncs.c.

References AggCheckCallContext(), construct_empty_expanded_array(), CurrentMemoryContext, ArrayMetaState::element_type, ereport, errcode(), errmsg(), ERROR, FunctionCallInfoBaseData::flinfo, FmgrInfo::fn_extra, FmgrInfo::fn_mcxt, get_element_type(), get_fn_expr_argtype(), InvalidOid, MemoryContextAlloc(), MemoryContextSwitchTo(), OidIsValid, PG_ARGISNULL, and PG_GETARG_EXPANDED_ARRAYX.

Referenced by array_append(), and array_prepend().

43 {
45  Oid element_type;
46  ArrayMetaState *my_extra;
47  MemoryContext resultcxt;
48 
49  /* If first time through, create datatype cache struct */
50  my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra;
51  if (my_extra == NULL)
52  {
53  my_extra = (ArrayMetaState *)
55  sizeof(ArrayMetaState));
56  my_extra->element_type = InvalidOid;
57  fcinfo->flinfo->fn_extra = my_extra;
58  }
59 
60  /* Figure out which context we want the result in */
61  if (!AggCheckCallContext(fcinfo, &resultcxt))
62  resultcxt = CurrentMemoryContext;
63 
64  /* Now collect the array value */
65  if (!PG_ARGISNULL(argno))
66  {
67  MemoryContext oldcxt = MemoryContextSwitchTo(resultcxt);
68 
69  eah = PG_GETARG_EXPANDED_ARRAYX(argno, my_extra);
70  MemoryContextSwitchTo(oldcxt);
71  }
72  else
73  {
74  /* We have to look up the array type and element type */
75  Oid arr_typeid = get_fn_expr_argtype(fcinfo->flinfo, argno);
76 
77  if (!OidIsValid(arr_typeid))
78  ereport(ERROR,
79  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
80  errmsg("could not determine input data type")));
81  element_type = get_element_type(arr_typeid);
82  if (!OidIsValid(element_type))
83  ereport(ERROR,
84  (errcode(ERRCODE_DATATYPE_MISMATCH),
85  errmsg("input data type is not an array")));
86 
87  eah = construct_empty_expanded_array(element_type,
88  resultcxt,
89  my_extra);
90  }
91 
92  return eah;
93 }
MemoryContext fn_mcxt
Definition: fmgr.h:65
Oid get_element_type(Oid typid)
Definition: lsyscache.c:2706
#define PG_GETARG_EXPANDED_ARRAYX(n, metacache)
Definition: array.h:262
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
int errcode(int sqlerrcode)
Definition: elog.c:698
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:710
#define ERROR
Definition: elog.h:46
Oid get_fn_expr_argtype(FmgrInfo *flinfo, int argnum)
Definition: fmgr.c:1800
MemoryContext CurrentMemoryContext
Definition: mcxt.c:42
ExpandedArrayHeader * construct_empty_expanded_array(Oid element_type, MemoryContext parentcontext, ArrayMetaState *metacache)
Definition: arrayfuncs.c:3456
FmgrInfo * flinfo
Definition: fmgr.h:87
#define InvalidOid
Definition: postgres_ext.h:36
#define ereport(elevel,...)
Definition: elog.h:157
#define PG_ARGISNULL(n)
Definition: fmgr.h:209
int AggCheckCallContext(FunctionCallInfo fcinfo, MemoryContext *aggcontext)
Definition: nodeAgg.c:4588
void * fn_extra
Definition: fmgr.h:64
int errmsg(const char *fmt,...)
Definition: elog.c:909
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:863
Oid element_type
Definition: array.h:231