PostgreSQL Source Code git master
Loading...
Searching...
No Matches
array_userfuncs.c File Reference
#include "postgres.h"
#include "catalog/pg_operator_d.h"
#include "catalog/pg_type.h"
#include "common/int.h"
#include "common/pg_prng.h"
#include "libpq/pqformat.h"
#include "miscadmin.h"
#include "nodes/supportnodes.h"
#include "port/pg_bitutils.h"
#include "utils/array.h"
#include "utils/builtins.h"
#include "utils/datum.h"
#include "utils/lsyscache.h"
#include "utils/memutils.h"
#include "utils/tuplesort.h"
#include "utils/typcache.h"
Include dependency graph for array_userfuncs.c:

Go to the source code of this file.

Data Structures

struct  SerialIOData
 
struct  DeserialIOData
 
struct  ArraySortCachedInfo
 

Typedefs

typedef struct SerialIOData SerialIOData
 
typedef struct DeserialIOData DeserialIOData
 
typedef struct ArraySortCachedInfo ArraySortCachedInfo
 

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_append_support (PG_FUNCTION_ARGS)
 
Datum array_prepend (PG_FUNCTION_ARGS)
 
Datum array_prepend_support (PG_FUNCTION_ARGS)
 
Datum array_cat (PG_FUNCTION_ARGS)
 
Datum array_agg_transfn (PG_FUNCTION_ARGS)
 
Datum array_agg_combine (PG_FUNCTION_ARGS)
 
Datum array_agg_serialize (PG_FUNCTION_ARGS)
 
Datum array_agg_deserialize (PG_FUNCTION_ARGS)
 
Datum array_agg_finalfn (PG_FUNCTION_ARGS)
 
Datum array_agg_array_transfn (PG_FUNCTION_ARGS)
 
Datum array_agg_array_combine (PG_FUNCTION_ARGS)
 
Datum array_agg_array_serialize (PG_FUNCTION_ARGS)
 
Datum array_agg_array_deserialize (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)
 
static ArrayTypearray_shuffle_n (ArrayType *array, int n, bool keep_lb, Oid elmtyp, TypeCacheEntry *typentry)
 
Datum array_shuffle (PG_FUNCTION_ARGS)
 
Datum array_sample (PG_FUNCTION_ARGS)
 
static ArrayTypearray_reverse_n (ArrayType *array, Oid elmtyp, TypeCacheEntry *typentry)
 
Datum array_reverse (PG_FUNCTION_ARGS)
 
static ArrayTypearray_sort_internal (ArrayType *array, bool descending, bool nulls_first, FunctionCallInfo fcinfo)
 
Datum array_sort (PG_FUNCTION_ARGS)
 
Datum array_sort_order (PG_FUNCTION_ARGS)
 
Datum array_sort_order_nulls_first (PG_FUNCTION_ARGS)
 

Typedef Documentation

◆ ArraySortCachedInfo

◆ DeserialIOData

◆ SerialIOData

Function Documentation

◆ array_agg_array_combine()

Datum array_agg_array_combine ( PG_FUNCTION_ARGS  )

Definition at line 978 of file array_userfuncs.c.

979{
982 MemoryContext agg_context;
984
985 if (!AggCheckCallContext(fcinfo, &agg_context))
986 elog(ERROR, "aggregate function called in non-aggregate context");
987
990
991 if (state2 == NULL)
992 {
993 /*
994 * NULL state2 is easy, just return state1, which we know is already
995 * in the agg_context
996 */
997 if (state1 == NULL)
1000 }
1001
1002 if (state1 == NULL)
1003 {
1004 /* We must copy state2's data into the agg_context */
1005 old_context = MemoryContextSwitchTo(agg_context);
1006
1008 agg_context, false);
1009
1010 state1->abytes = state2->abytes;
1011 state1->data = (char *) palloc(state1->abytes);
1012
1013 if (state2->nullbitmap)
1014 {
1015 int size = (state2->aitems + 7) / 8;
1016
1017 state1->nullbitmap = (uint8 *) palloc(size);
1018 memcpy(state1->nullbitmap, state2->nullbitmap, size);
1019 }
1020
1021 memcpy(state1->data, state2->data, state2->nbytes);
1022 state1->nbytes = state2->nbytes;
1023 state1->aitems = state2->aitems;
1024 state1->nitems = state2->nitems;
1025 state1->ndims = state2->ndims;
1026 memcpy(state1->dims, state2->dims, sizeof(state2->dims));
1027 memcpy(state1->lbs, state2->lbs, sizeof(state2->lbs));
1028 state1->array_type = state2->array_type;
1029 state1->element_type = state2->element_type;
1030
1032
1034 }
1035
1036 /* We only need to combine the two states if state2 has any items */
1037 if (state2->nitems > 0)
1038 {
1040 int reqsize;
1041 int newnitems;
1042 int i;
1043
1044 /*
1045 * Check the states are compatible with each other. Ensure we use the
1046 * same error messages that are listed in accumArrayResultArr so that
1047 * the same error is shown as would have been if we'd not used the
1048 * combine function for the aggregation.
1049 */
1050 if (state1->ndims != state2->ndims)
1051 ereport(ERROR,
1053 errmsg("cannot accumulate arrays of different dimensionality")));
1054
1055 /* Check dimensions match ignoring the first dimension. */
1056 for (i = 1; i < state1->ndims; i++)
1057 {
1058 if (state1->dims[i] != state2->dims[i] || state1->lbs[i] != state2->lbs[i])
1059 ereport(ERROR,
1061 errmsg("cannot accumulate arrays of different dimensionality")));
1062 }
1063
1064 /* Types should match already. */
1065 Assert(state1->array_type == state2->array_type);
1066 Assert(state1->element_type == state2->element_type);
1067
1068 /* Calculate new sizes, guarding against overflow. */
1069 if (pg_add_s32_overflow(state1->nbytes, state2->nbytes, &reqsize) ||
1070 pg_add_s32_overflow(state1->nitems, state2->nitems, &newnitems))
1071 ereport(ERROR,
1073 errmsg("array size exceeds the maximum allowed (%zu)",
1074 MaxArraySize)));
1075
1077
1078 /*
1079 * If there's not enough space in state1 then we'll need to reallocate
1080 * more.
1081 */
1082 if (state1->abytes < reqsize)
1083 {
1084 /* use a power of 2 size rather than allocating just reqsize */
1085 state1->abytes = pg_nextpower2_32(reqsize);
1086 state1->data = (char *) repalloc(state1->data, state1->abytes);
1087 }
1088
1089 /* Combine the null bitmaps, if present. */
1090 if (state1->nullbitmap || state2->nullbitmap)
1091 {
1092 if (state1->nullbitmap == NULL)
1093 {
1094 /*
1095 * First input with nulls; we must retrospectively handle any
1096 * previous inputs by marking all their items non-null.
1097 */
1098 state1->aitems = pg_nextpower2_32(Max(256, newnitems));
1099 state1->nullbitmap = (uint8 *) palloc((state1->aitems + 7) / 8);
1100 array_bitmap_copy(state1->nullbitmap, 0,
1101 NULL, 0,
1102 state1->nitems);
1103 }
1104 else if (newnitems > state1->aitems)
1105 {
1107 state1->nullbitmap = (uint8 *)
1108 repalloc(state1->nullbitmap, (state1->aitems + 7) / 8);
1109 }
1110 /* This will do the right thing if state2->nullbitmap is NULL: */
1111 array_bitmap_copy(state1->nullbitmap, state1->nitems,
1112 state2->nullbitmap, 0,
1113 state2->nitems);
1114 }
1115
1116 /* Finally, combine the data and adjust sizes. */
1117 memcpy(state1->data + state1->nbytes, state2->data, state2->nbytes);
1118 state1->nbytes += state2->nbytes;
1119 state1->nitems += state2->nitems;
1120
1121 state1->dims[0] += state2->dims[0];
1122 /* remaining dims already match, per test above */
1123
1125 }
1126
1128}
#define MaxArraySize
Definition array.h:82
void array_bitmap_copy(uint8 *destbitmap, int destoffset, const uint8 *srcbitmap, int srcoffset, int nitems)
ArrayBuildStateArr * initArrayResultArr(Oid array_type, Oid element_type, MemoryContext rcontext, bool subcontext)
uint8_t uint8
Definition c.h:622
#define Max(x, y)
Definition c.h:1085
#define Assert(condition)
Definition c.h:943
memcpy(sums, checksumBaseOffsets, sizeof(checksumBaseOffsets))
int errcode(int sqlerrcode)
Definition elog.c:874
#define ERROR
Definition elog.h:40
#define elog(elevel,...)
Definition elog.h:228
#define ereport(elevel,...)
Definition elog.h:152
#define PG_GETARG_POINTER(n)
Definition fmgr.h:277
#define PG_ARGISNULL(n)
Definition fmgr.h:209
#define PG_RETURN_NULL()
Definition fmgr.h:346
#define PG_RETURN_POINTER(x)
Definition fmgr.h:363
static bool pg_add_s32_overflow(int32 a, int32 b, int32 *result)
Definition int.h:151
int i
Definition isn.c:77
void * repalloc(void *pointer, Size size)
Definition mcxt.c:1632
void * palloc(Size size)
Definition mcxt.c:1387
int AggCheckCallContext(FunctionCallInfo fcinfo, MemoryContext *aggcontext)
Definition nodeAgg.c:4609
static char * errmsg
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition palloc.h:124
static uint32 pg_nextpower2_32(uint32 num)
#define InvalidOid
static int fb(int x)

References AggCheckCallContext(), array_bitmap_copy(), Assert, elog, ereport, errcode(), errmsg, ERROR, fb(), i, initArrayResultArr(), InvalidOid, Max, MaxArraySize, memcpy(), MemoryContextSwitchTo(), palloc(), pg_add_s32_overflow(), PG_ARGISNULL, PG_GETARG_POINTER, pg_nextpower2_32(), PG_RETURN_NULL, PG_RETURN_POINTER, and repalloc().

◆ array_agg_array_deserialize()

Datum array_agg_array_deserialize ( PG_FUNCTION_ARGS  )

Definition at line 1194 of file array_userfuncs.c.

1195{
1196 bytea *sstate;
1199 Oid element_type;
1200 Oid array_type;
1201 int nbytes;
1202 const char *temp;
1203
1204 /* cannot be called directly because of internal-type argument */
1206
1207 sstate = PG_GETARG_BYTEA_PP(0);
1208
1209 /*
1210 * Initialize a StringInfo so that we can "receive" it using the standard
1211 * recv-function infrastructure.
1212 */
1214 VARSIZE_ANY_EXHDR(sstate));
1215
1216 /* element_type */
1217 element_type = pq_getmsgint(&buf, 4);
1218
1219 /* array_type */
1220 array_type = pq_getmsgint(&buf, 4);
1221
1222 /* nbytes */
1223 nbytes = pq_getmsgint(&buf, 4);
1224
1225 result = initArrayResultArr(array_type, element_type,
1226 CurrentMemoryContext, false);
1227
1228 result->abytes = 1024;
1229 while (result->abytes < nbytes)
1230 result->abytes *= 2;
1231
1232 result->data = (char *) palloc(result->abytes);
1233
1234 /* data */
1235 temp = pq_getmsgbytes(&buf, nbytes);
1236 memcpy(result->data, temp, nbytes);
1237 result->nbytes = nbytes;
1238
1239 /* abytes */
1240 result->abytes = pq_getmsgint(&buf, 4);
1241
1242 /* aitems: might be 0 */
1243 result->aitems = pq_getmsgint(&buf, 4);
1244
1245 /* nullbitmap */
1246 if (result->aitems > 0)
1247 {
1248 int size = (result->aitems + 7) / 8;
1249
1250 result->nullbitmap = (uint8 *) palloc(size);
1251 temp = pq_getmsgbytes(&buf, size);
1252 memcpy(result->nullbitmap, temp, size);
1253 }
1254 else
1255 result->nullbitmap = NULL;
1256
1257 /* nitems */
1258 result->nitems = pq_getmsgint(&buf, 4);
1259
1260 /* ndims */
1261 result->ndims = pq_getmsgint(&buf, 4);
1262
1263 /* dims */
1264 temp = pq_getmsgbytes(&buf, sizeof(result->dims));
1265 memcpy(result->dims, temp, sizeof(result->dims));
1266
1267 /* lbs */
1268 temp = pq_getmsgbytes(&buf, sizeof(result->lbs));
1269 memcpy(result->lbs, temp, sizeof(result->lbs));
1270
1271 pq_getmsgend(&buf);
1272
1274}
uint32 result
#define PG_GETARG_BYTEA_PP(n)
Definition fmgr.h:309
MemoryContext CurrentMemoryContext
Definition mcxt.c:160
static char buf[DEFAULT_XLOG_SEG_SIZE]
unsigned int Oid
unsigned int pq_getmsgint(StringInfo msg, int b)
Definition pqformat.c:414
void pq_getmsgend(StringInfo msg)
Definition pqformat.c:634
const char * pq_getmsgbytes(StringInfo msg, int datalen)
Definition pqformat.c:507
static void initReadOnlyStringInfo(StringInfo str, char *data, int len)
Definition stringinfo.h:157
Definition c.h:776
static Size VARSIZE_ANY_EXHDR(const void *PTR)
Definition varatt.h:472
static char * VARDATA_ANY(const void *PTR)
Definition varatt.h:486

References AggCheckCallContext(), Assert, buf, CurrentMemoryContext, fb(), initArrayResultArr(), initReadOnlyStringInfo(), memcpy(), palloc(), PG_GETARG_BYTEA_PP, PG_RETURN_POINTER, pq_getmsgbytes(), pq_getmsgend(), pq_getmsgint(), result, VARDATA_ANY(), and VARSIZE_ANY_EXHDR().

◆ array_agg_array_finalfn()

Datum array_agg_array_finalfn ( PG_FUNCTION_ARGS  )

Definition at line 1277 of file array_userfuncs.c.

1278{
1279 Datum result;
1281
1282 /* cannot be called directly because of internal-type argument */
1284
1286
1287 if (state == NULL)
1288 PG_RETURN_NULL(); /* returns null iff no input values */
1289
1290 /*
1291 * Make the result. We cannot release the ArrayBuildStateArr because
1292 * sometimes aggregate final functions are re-executed. Rather, it is
1293 * nodeAgg.c's responsibility to reset the aggcontext when it's safe to do
1294 * so.
1295 */
1297
1299}
Datum makeArrayResultArr(ArrayBuildStateArr *astate, MemoryContext rcontext, bool release)
#define PG_RETURN_DATUM(x)
Definition fmgr.h:354
uint64_t Datum
Definition postgres.h:70

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

◆ array_agg_array_serialize()

Datum array_agg_array_serialize ( PG_FUNCTION_ARGS  )

Definition at line 1135 of file array_userfuncs.c.

1136{
1139 bytea *result;
1140
1141 /* cannot be called directly because of internal-type argument */
1143
1145
1147
1148 /*
1149 * element_type. Putting this first is more convenient in deserialization
1150 * so that we can init the new state sooner.
1151 */
1152 pq_sendint32(&buf, state->element_type);
1153
1154 /* array_type */
1155 pq_sendint32(&buf, state->array_type);
1156
1157 /* nbytes */
1158 pq_sendint32(&buf, state->nbytes);
1159
1160 /* data */
1161 pq_sendbytes(&buf, state->data, state->nbytes);
1162
1163 /* abytes */
1164 pq_sendint32(&buf, state->abytes);
1165
1166 /* aitems */
1167 pq_sendint32(&buf, state->aitems);
1168
1169 /* nullbitmap */
1170 if (state->nullbitmap)
1171 {
1172 Assert(state->aitems > 0);
1173 pq_sendbytes(&buf, state->nullbitmap, (state->aitems + 7) / 8);
1174 }
1175
1176 /* nitems */
1177 pq_sendint32(&buf, state->nitems);
1178
1179 /* ndims */
1180 pq_sendint32(&buf, state->ndims);
1181
1182 /* dims: XXX should we just send ndims elements? */
1183 pq_sendbytes(&buf, state->dims, sizeof(state->dims));
1184
1185 /* lbs */
1186 pq_sendbytes(&buf, state->lbs, sizeof(state->lbs));
1187
1189
1191}
#define PG_RETURN_BYTEA_P(x)
Definition fmgr.h:373
void pq_sendbytes(StringInfo buf, const void *data, int datalen)
Definition pqformat.c:126
void pq_begintypsend(StringInfo buf)
Definition pqformat.c:325
bytea * pq_endtypsend(StringInfo buf)
Definition pqformat.c:345
static void pq_sendint32(StringInfo buf, uint32 i)
Definition pqformat.h:144

References AggCheckCallContext(), Assert, buf, fb(), PG_GETARG_POINTER, PG_RETURN_BYTEA_P, pq_begintypsend(), pq_endtypsend(), pq_sendbytes(), pq_sendint32(), and result.

◆ array_agg_array_transfn()

Datum array_agg_array_transfn ( PG_FUNCTION_ARGS  )

Definition at line 934 of file array_userfuncs.c.

935{
936 Oid arg1_typeid = get_fn_expr_argtype(fcinfo->flinfo, 1);
937 MemoryContext aggcontext;
939
940 if (arg1_typeid == InvalidOid)
943 errmsg("could not determine input data type")));
944
945 /*
946 * Note: we do not need a run-time check about whether arg1_typeid is a
947 * valid array type, because the parser would have verified that while
948 * resolving the input/result types of this polymorphic aggregate.
949 */
950
951 if (!AggCheckCallContext(fcinfo, &aggcontext))
952 {
953 /* cannot be called directly because of internal-type argument */
954 elog(ERROR, "array_agg_array_transfn called in non-aggregate context");
955 }
956
957
958 if (PG_ARGISNULL(0))
959 state = initArrayResultArr(arg1_typeid, InvalidOid, aggcontext, false);
960 else
962
965 PG_ARGISNULL(1),
967 aggcontext);
968
969 /*
970 * The transition type for array_agg() is declared to be "internal", which
971 * is a pass-by-value type the same size as a pointer. So we can safely
972 * pass the ArrayBuildStateArr pointer through nodeAgg.c's machinations.
973 */
975}
ArrayBuildStateArr * accumArrayResultArr(ArrayBuildStateArr *astate, Datum dvalue, bool disnull, Oid array_type, MemoryContext rcontext)
Oid get_fn_expr_argtype(FmgrInfo *flinfo, int argnum)
Definition fmgr.c:1876
#define PG_GETARG_DATUM(n)
Definition fmgr.h:268

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

◆ array_agg_combine()

Datum array_agg_combine ( PG_FUNCTION_ARGS  )

Definition at line 602 of file array_userfuncs.c.

603{
606 MemoryContext agg_context;
608
609 if (!AggCheckCallContext(fcinfo, &agg_context))
610 elog(ERROR, "aggregate function called in non-aggregate context");
611
614
615 if (state2 == NULL)
616 {
617 /*
618 * NULL state2 is easy, just return state1, which we know is already
619 * in the agg_context
620 */
621 if (state1 == NULL)
624 }
625
626 if (state1 == NULL)
627 {
628 /* We must copy state2's data into the agg_context */
629 state1 = initArrayResultWithSize(state2->element_type, agg_context,
630 false, state2->alen);
631
632 old_context = MemoryContextSwitchTo(agg_context);
633
634 for (int i = 0; i < state2->nelems; i++)
635 {
636 if (!state2->dnulls[i])
637 state1->dvalues[i] = datumCopy(state2->dvalues[i],
638 state1->typbyval,
639 state1->typlen);
640 else
641 state1->dvalues[i] = (Datum) 0;
642 }
643
645
646 memcpy(state1->dnulls, state2->dnulls, sizeof(bool) * state2->nelems);
647
648 state1->nelems = state2->nelems;
649
651 }
652 else if (state2->nelems > 0)
653 {
654 /* We only need to combine the two states if state2 has any elements */
655 int reqsize = state1->nelems + state2->nelems;
657
658 Assert(state1->element_type == state2->element_type);
659
660 /* Enlarge state1 arrays if needed */
661 if (state1->alen < reqsize)
662 {
663 /* Use a power of 2 size rather than allocating just reqsize */
665 state1->dvalues = (Datum *) repalloc(state1->dvalues,
666 state1->alen * sizeof(Datum));
667 state1->dnulls = (bool *) repalloc(state1->dnulls,
668 state1->alen * sizeof(bool));
669 }
670
671 /* Copy in the state2 elements to the end of the state1 arrays */
672 for (int i = 0; i < state2->nelems; i++)
673 {
674 if (!state2->dnulls[i])
675 state1->dvalues[i + state1->nelems] =
676 datumCopy(state2->dvalues[i],
677 state1->typbyval,
678 state1->typlen);
679 else
680 state1->dvalues[i + state1->nelems] = (Datum) 0;
681 }
682
683 memcpy(&state1->dnulls[state1->nelems], state2->dnulls,
684 sizeof(bool) * state2->nelems);
685
686 state1->nelems = reqsize;
687
689 }
690
692}
ArrayBuildState * initArrayResultWithSize(Oid element_type, MemoryContext rcontext, bool subcontext, int initsize)
Datum datumCopy(Datum value, bool typByVal, int typLen)
Definition datum.c:132

References AggCheckCallContext(), Assert, datumCopy(), elog, ERROR, fb(), i, initArrayResultWithSize(), memcpy(), MemoryContextSwitchTo(), PG_ARGISNULL, PG_GETARG_POINTER, pg_nextpower2_32(), PG_RETURN_NULL, PG_RETURN_POINTER, and repalloc().

◆ array_agg_deserialize()

Datum array_agg_deserialize ( PG_FUNCTION_ARGS  )

Definition at line 788 of file array_userfuncs.c.

789{
790 bytea *sstate;
793 Oid element_type;
794 int64 nelems;
795 const char *temp;
796
797 if (!AggCheckCallContext(fcinfo, NULL))
798 elog(ERROR, "aggregate function called in non-aggregate context");
799
800 sstate = PG_GETARG_BYTEA_PP(0);
801
802 /*
803 * Initialize a StringInfo so that we can "receive" it using the standard
804 * recv-function infrastructure.
805 */
807 VARSIZE_ANY_EXHDR(sstate));
808
809 /* element_type */
810 element_type = pq_getmsgint(&buf, 4);
811
812 /* nelems */
813 nelems = pq_getmsgint64(&buf);
814
815 /* Create output ArrayBuildState with the needed number of elements */
817 false, nelems);
818 result->nelems = nelems;
819
820 /* typlen */
821 result->typlen = pq_getmsgint(&buf, 2);
822
823 /* typbyval */
824 result->typbyval = pq_getmsgbyte(&buf);
825
826 /* typalign */
827 result->typalign = pq_getmsgbyte(&buf);
828
829 /* dnulls */
830 temp = pq_getmsgbytes(&buf, sizeof(bool) * nelems);
831 memcpy(result->dnulls, temp, sizeof(bool) * nelems);
832
833 /* dvalues --- see comment in array_agg_serialize */
834 if (result->typbyval)
835 {
836 temp = pq_getmsgbytes(&buf, sizeof(Datum) * nelems);
837 memcpy(result->dvalues, temp, sizeof(Datum) * nelems);
838 }
839 else
840 {
842
843 /* Avoid repeat catalog lookups for typreceive function */
844 iodata = (DeserialIOData *) fcinfo->flinfo->fn_extra;
845 if (iodata == NULL)
846 {
847 Oid typreceive;
848
850 MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
851 sizeof(DeserialIOData));
852 getTypeBinaryInputInfo(element_type, &typreceive,
853 &iodata->typioparam);
854 fmgr_info_cxt(typreceive, &iodata->typreceive,
855 fcinfo->flinfo->fn_mcxt);
856 fcinfo->flinfo->fn_extra = iodata;
857 }
858
859 for (int i = 0; i < nelems; i++)
860 {
861 int itemlen;
863
864 if (result->dnulls[i])
865 {
866 result->dvalues[i] = (Datum) 0;
867 continue;
868 }
869
870 itemlen = pq_getmsgint(&buf, 4);
871 if (itemlen < 0 || itemlen > (buf.len - buf.cursor))
874 errmsg("insufficient data left in message")));
875
876 /*
877 * Rather than copying data around, we just initialize a
878 * StringInfo pointing to the correct portion of the message
879 * buffer.
880 */
882
883 buf.cursor += itemlen;
884
885 /* Now call the element's receiveproc */
886 result->dvalues[i] = ReceiveFunctionCall(&iodata->typreceive,
887 &elem_buf,
888 iodata->typioparam,
889 -1);
890 }
891 }
892
894
896}
int64_t int64
Definition c.h:621
void fmgr_info_cxt(Oid functionId, FmgrInfo *finfo, MemoryContext mcxt)
Definition fmgr.c:139
Datum ReceiveFunctionCall(FmgrInfo *flinfo, StringInfo buf, Oid typioparam, int32 typmod)
Definition fmgr.c:1698
void getTypeBinaryInputInfo(Oid type, Oid *typReceive, Oid *typIOParam)
Definition lsyscache.c:3162
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition mcxt.c:1232
int pq_getmsgbyte(StringInfo msg)
Definition pqformat.c:398
int64 pq_getmsgint64(StringInfo msg)
Definition pqformat.c:452

References AggCheckCallContext(), buf, CurrentMemoryContext, elog, ereport, errcode(), errmsg, ERROR, fb(), fmgr_info_cxt(), getTypeBinaryInputInfo(), i, initArrayResultWithSize(), initReadOnlyStringInfo(), memcpy(), MemoryContextAlloc(), PG_GETARG_BYTEA_PP, PG_RETURN_POINTER, pq_getmsgbyte(), pq_getmsgbytes(), pq_getmsgend(), pq_getmsgint(), pq_getmsgint64(), ReceiveFunctionCall(), result, VARDATA_ANY(), and VARSIZE_ANY_EXHDR().

◆ array_agg_finalfn()

Datum array_agg_finalfn ( PG_FUNCTION_ARGS  )

Definition at line 899 of file array_userfuncs.c.

900{
903 int dims[1];
904 int lbs[1];
905
906 /* cannot be called directly because of internal-type argument */
908
910
911 if (state == NULL)
912 PG_RETURN_NULL(); /* returns null iff no input values */
913
914 dims[0] = state->nelems;
915 lbs[0] = 1;
916
917 /*
918 * Make the result. We cannot release the ArrayBuildState because
919 * sometimes aggregate final functions are re-executed. Rather, it is
920 * nodeAgg.c's responsibility to reset the aggcontext when it's safe to do
921 * so.
922 */
923 result = makeMdArrayResult(state, 1, dims, lbs,
925 false);
926
928}
Datum makeMdArrayResult(ArrayBuildState *astate, int ndims, int *dims, int *lbs, MemoryContext rcontext, bool release)

References AggCheckCallContext(), Assert, CurrentMemoryContext, fb(), makeMdArrayResult(), PG_ARGISNULL, PG_GETARG_POINTER, PG_RETURN_DATUM, PG_RETURN_NULL, and result.

◆ array_agg_serialize()

Datum array_agg_serialize ( PG_FUNCTION_ARGS  )

Definition at line 699 of file array_userfuncs.c.

700{
703 bytea *result;
704
705 /* cannot be called directly because of internal-type argument */
707
709
711
712 /*
713 * element_type. Putting this first is more convenient in deserialization
714 */
715 pq_sendint32(&buf, state->element_type);
716
717 /*
718 * nelems -- send first so we know how large to make the dvalues and
719 * dnulls array during deserialization.
720 */
721 pq_sendint64(&buf, state->nelems);
722
723 /* alen can be decided during deserialization */
724
725 /* typlen */
726 pq_sendint16(&buf, state->typlen);
727
728 /* typbyval */
729 pq_sendbyte(&buf, state->typbyval);
730
731 /* typalign */
732 pq_sendbyte(&buf, state->typalign);
733
734 /* dnulls */
735 pq_sendbytes(&buf, state->dnulls, sizeof(bool) * state->nelems);
736
737 /*
738 * dvalues. By agreement with array_agg_deserialize, when the element
739 * type is byval, we just transmit the Datum array as-is, including any
740 * null elements. For by-ref types, we must invoke the element type's
741 * send function, and we skip null elements (which is why the nulls flags
742 * must be sent first).
743 */
744 if (state->typbyval)
745 pq_sendbytes(&buf, state->dvalues, sizeof(Datum) * state->nelems);
746 else
747 {
749 int i;
750
751 /* Avoid repeat catalog lookups for typsend function */
752 iodata = (SerialIOData *) fcinfo->flinfo->fn_extra;
753 if (iodata == NULL)
754 {
755 Oid typsend;
756 bool typisvarlena;
757
758 iodata = (SerialIOData *)
759 MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
760 sizeof(SerialIOData));
761 getTypeBinaryOutputInfo(state->element_type, &typsend,
762 &typisvarlena);
763 fmgr_info_cxt(typsend, &iodata->typsend,
764 fcinfo->flinfo->fn_mcxt);
765 fcinfo->flinfo->fn_extra = iodata;
766 }
767
768 for (i = 0; i < state->nelems; i++)
769 {
771
772 if (state->dnulls[i])
773 continue;
775 state->dvalues[i]);
779 }
780 }
781
783
785}
#define VARHDRSZ
Definition c.h:781
bytea * SendFunctionCall(FmgrInfo *flinfo, Datum val)
Definition fmgr.c:1745
void getTypeBinaryOutputInfo(Oid type, Oid *typSend, bool *typIsVarlena)
Definition lsyscache.c:3195
static void pq_sendbyte(StringInfo buf, uint8 byt)
Definition pqformat.h:160
static void pq_sendint64(StringInfo buf, uint64 i)
Definition pqformat.h:152
static void pq_sendint16(StringInfo buf, uint16 i)
Definition pqformat.h:136
static Size VARSIZE(const void *PTR)
Definition varatt.h:298
static char * VARDATA(const void *PTR)
Definition varatt.h:305

References AggCheckCallContext(), Assert, buf, fb(), fmgr_info_cxt(), getTypeBinaryOutputInfo(), i, MemoryContextAlloc(), PG_GETARG_POINTER, PG_RETURN_BYTEA_P, pq_begintypsend(), pq_endtypsend(), pq_sendbyte(), pq_sendbytes(), pq_sendint16(), pq_sendint32(), pq_sendint64(), result, SendFunctionCall(), VARDATA(), VARHDRSZ, and VARSIZE().

◆ array_agg_transfn()

Datum array_agg_transfn ( PG_FUNCTION_ARGS  )

Definition at line 556 of file array_userfuncs.c.

557{
558 Oid arg1_typeid = get_fn_expr_argtype(fcinfo->flinfo, 1);
559 MemoryContext aggcontext;
561 Datum elem;
562
563 if (arg1_typeid == InvalidOid)
566 errmsg("could not determine input data type")));
567
568 /*
569 * Note: we do not need a run-time check about whether arg1_typeid is a
570 * valid array element type, because the parser would have verified that
571 * while resolving the input/result types of this polymorphic aggregate.
572 */
573
574 if (!AggCheckCallContext(fcinfo, &aggcontext))
575 {
576 /* cannot be called directly because of internal-type argument */
577 elog(ERROR, "array_agg_transfn called in non-aggregate context");
578 }
579
580 if (PG_ARGISNULL(0))
581 state = initArrayResult(arg1_typeid, aggcontext, false);
582 else
584
585 elem = PG_ARGISNULL(1) ? (Datum) 0 : PG_GETARG_DATUM(1);
586
588 elem,
589 PG_ARGISNULL(1),
591 aggcontext);
592
593 /*
594 * The transition type for array_agg() is declared to be "internal", which
595 * is a pass-by-value type the same size as a pointer. So we can safely
596 * pass the ArrayBuildState pointer through nodeAgg.c's machinations.
597 */
599}
ArrayBuildState * accumArrayResult(ArrayBuildState *astate, Datum dvalue, bool disnull, Oid element_type, MemoryContext rcontext)
ArrayBuildState * initArrayResult(Oid element_type, MemoryContext rcontext, bool subcontext)

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

◆ array_append()

Datum array_append ( PG_FUNCTION_ARGS  )

Definition at line 140 of file array_userfuncs.c.

141{
144 bool isNull;
146 int *dimv,
147 *lb;
148 int indx;
150
152 isNull = PG_ARGISNULL(1);
153 if (isNull)
154 newelem = (Datum) 0;
155 else
157
158 if (eah->ndims == 1)
159 {
160 /* append newelem */
161 lb = eah->lbound;
162 dimv = eah->dims;
163
164 /* index of added elem is at lb[0] + (dimv[0] - 1) + 1 */
165 if (pg_add_s32_overflow(lb[0], dimv[0], &indx))
168 errmsg("integer out of range")));
169 }
170 else if (eah->ndims == 0)
171 indx = 1;
172 else
175 errmsg("argument must be empty or one-dimensional array")));
176
177 /* Perform element insertion */
178 my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra;
179
181 1, &indx, newelem, isNull,
182 -1, my_extra->typlen, my_extra->typbyval, my_extra->typalign);
183
185}
static ExpandedArrayHeader * fetch_array_arg_replace_nulls(FunctionCallInfo fcinfo, int argno)
Datum array_set_element(Datum arraydatum, int nSubscripts, int *indx, Datum dataValue, bool isNull, int arraytyplen, int elmlen, bool elmbyval, char elmalign)
static Datum EOHPGetRWDatum(const struct ExpandedObjectHeader *eohptr)

References array_set_element(), EOHPGetRWDatum(), ereport, errcode(), errmsg, ERROR, fb(), fetch_array_arg_replace_nulls(), pg_add_s32_overflow(), PG_ARGISNULL, PG_GETARG_DATUM, PG_RETURN_DATUM, and result.

◆ array_append_support()

Datum array_append_support ( PG_FUNCTION_ARGS  )

Definition at line 193 of file array_userfuncs.c.

194{
196 Node *ret = NULL;
197
199 {
200 /*
201 * We can optimize in-place appends if the function's array argument
202 * is the array being assigned to. We don't need to worry about array
203 * references within the other argument.
204 */
206 Param *arg = (Param *) linitial(req->args);
207
208 if (arg && IsA(arg, Param) &&
209 arg->paramkind == PARAM_EXTERN &&
210 arg->paramid == req->paramid)
211 ret = (Node *) arg;
212 }
213
215}
Datum arg
Definition elog.c:1322
#define IsA(nodeptr, _type_)
Definition nodes.h:164
#define linitial(l)
Definition pg_list.h:178
@ PARAM_EXTERN
Definition primnodes.h:385
Definition nodes.h:135

References arg, fb(), IsA, linitial, PARAM_EXTERN, PG_GETARG_POINTER, and PG_RETURN_POINTER.

◆ array_cat()

Datum array_cat ( PG_FUNCTION_ARGS  )

Definition at line 317 of file array_userfuncs.c.

318{
319 ArrayType *v1,
320 *v2;
322 int *dims,
323 *lbs,
324 ndims,
325 nitems,
327 nbytes;
328 int *dims1,
329 *lbs1,
330 ndims1,
331 nitems1,
333 int *dims2,
334 *lbs2,
335 ndims2,
336 nitems2,
338 int i;
339 char *dat1,
340 *dat2;
341 uint8 *bitmap1,
342 *bitmap2;
343 Oid element_type;
346 int32 dataoffset;
347
348 /* Concatenating a null array is a no-op, just return the other input */
349 if (PG_ARGISNULL(0))
350 {
351 if (PG_ARGISNULL(1))
355 }
356 if (PG_ARGISNULL(1))
357 {
360 }
361
362 v1 = PG_GETARG_ARRAYTYPE_P(0);
364
367
368 /* Check we have matching element types */
372 errmsg("cannot concatenate incompatible arrays"),
373 errdetail("Arrays with element types %s and %s are not "
374 "compatible for concatenation.",
377
378 /* OK, use it */
379 element_type = element_type1;
380
381 /*----------
382 * We must have one of the following combinations of inputs:
383 * 1) one empty array, and one non-empty array
384 * 2) both arrays empty
385 * 3) two arrays with ndims1 == ndims2
386 * 4) ndims1 == ndims2 - 1
387 * 5) ndims1 == ndims2 + 1
388 *----------
389 */
390 ndims1 = ARR_NDIM(v1);
391 ndims2 = ARR_NDIM(v2);
392
393 /*
394 * short circuit - if one input array is empty, and the other is not, we
395 * return the non-empty one as the result
396 *
397 * if both are empty, return the first one
398 */
399 if (ndims1 == 0 && ndims2 > 0)
401
402 if (ndims2 == 0)
404
405 /* the rest fall under rule 3, 4, or 5 */
406 if (ndims1 != ndims2 &&
407 ndims1 != ndims2 - 1 &&
408 ndims1 != ndims2 + 1)
411 errmsg("cannot concatenate incompatible arrays"),
412 errdetail("Arrays of %d and %d dimensions are not "
413 "compatible for concatenation.",
414 ndims1, ndims2)));
415
416 /* get argument array details */
417 lbs1 = ARR_LBOUND(v1);
418 lbs2 = ARR_LBOUND(v2);
419 dims1 = ARR_DIMS(v1);
420 dims2 = ARR_DIMS(v2);
421 dat1 = ARR_DATA_PTR(v1);
429
430 if (ndims1 == ndims2)
431 {
432 /*
433 * resulting array is made up of the elements (possibly arrays
434 * themselves) of the input argument arrays
435 */
436 ndims = ndims1;
437 dims = palloc_array(int, ndims);
438 lbs = palloc_array(int, ndims);
439
440 dims[0] = dims1[0] + dims2[0];
441 lbs[0] = lbs1[0];
442
443 for (i = 1; i < ndims; i++)
444 {
445 if (dims1[i] != dims2[i] || lbs1[i] != lbs2[i])
448 errmsg("cannot concatenate incompatible arrays"),
449 errdetail("Arrays with differing element dimensions are "
450 "not compatible for concatenation.")));
451
452 dims[i] = dims1[i];
453 lbs[i] = lbs1[i];
454 }
455 }
456 else if (ndims1 == ndims2 - 1)
457 {
458 /*
459 * resulting array has the second argument as the outer array, with
460 * the first argument inserted at the front of the outer dimension
461 */
462 ndims = ndims2;
463 dims = palloc_array(int, ndims);
464 lbs = palloc_array(int, ndims);
465 memcpy(dims, dims2, ndims * sizeof(int));
466 memcpy(lbs, lbs2, ndims * sizeof(int));
467
468 /* increment number of elements in outer array */
469 dims[0] += 1;
470
471 /* make sure the added element matches our existing elements */
472 for (i = 0; i < ndims1; i++)
473 {
474 if (dims1[i] != dims[i + 1] || lbs1[i] != lbs[i + 1])
477 errmsg("cannot concatenate incompatible arrays"),
478 errdetail("Arrays with differing dimensions are not "
479 "compatible for concatenation.")));
480 }
481 }
482 else
483 {
484 /*
485 * (ndims1 == ndims2 + 1)
486 *
487 * resulting array has the first argument as the outer array, with the
488 * second argument appended to the end of the outer dimension
489 */
490 ndims = ndims1;
491 dims = palloc_array(int, ndims);
492 lbs = palloc_array(int, ndims);
493 memcpy(dims, dims1, ndims * sizeof(int));
494 memcpy(lbs, lbs1, ndims * sizeof(int));
495
496 /* increment number of elements in outer array */
497 dims[0] += 1;
498
499 /* make sure the added element matches our existing elements */
500 for (i = 0; i < ndims2; i++)
501 {
502 if (dims2[i] != dims[i + 1] || lbs2[i] != lbs[i + 1])
505 errmsg("cannot concatenate incompatible arrays"),
506 errdetail("Arrays with differing dimensions are not "
507 "compatible for concatenation.")));
508 }
509 }
510
511 /* Do this mainly for overflow checking */
512 nitems = ArrayGetNItems(ndims, dims);
513 ArrayCheckBounds(ndims, dims, lbs);
514
515 /* build the result array */
517 if (ARR_HASNULL(v1) || ARR_HASNULL(v2))
518 {
519 dataoffset = ARR_OVERHEAD_WITHNULLS(ndims, nitems);
520 nbytes = ndatabytes + dataoffset;
521 }
522 else
523 {
524 dataoffset = 0; /* marker for no null bitmap */
525 nbytes = ndatabytes + ARR_OVERHEAD_NONULLS(ndims);
526 }
527 result = (ArrayType *) palloc0(nbytes);
528 SET_VARSIZE(result, nbytes);
529 result->ndim = ndims;
530 result->dataoffset = dataoffset;
531 result->elemtype = element_type;
532 memcpy(ARR_DIMS(result), dims, ndims * sizeof(int));
533 memcpy(ARR_LBOUND(result), lbs, ndims * sizeof(int));
534 /* data area is arg1 then arg2 */
537 /* handle the null bitmap if needed */
538 if (ARR_HASNULL(result))
539 {
541 bitmap1, 0,
542 nitems1);
544 bitmap2, 0,
545 nitems2);
546 }
547
549}
#define ARR_NDIM(a)
Definition array.h:290
#define PG_GETARG_ARRAYTYPE_P(n)
Definition array.h:263
#define ARR_DATA_PTR(a)
Definition array.h:322
#define ARR_NULLBITMAP(a)
Definition array.h:300
#define ARR_OVERHEAD_WITHNULLS(ndims, nitems)
Definition array.h:312
#define ARR_ELEMTYPE(a)
Definition array.h:292
#define PG_RETURN_ARRAYTYPE_P(x)
Definition array.h:265
#define ARR_SIZE(a)
Definition array.h:289
#define ARR_OVERHEAD_NONULLS(ndims)
Definition array.h:310
#define ARR_DATA_OFFSET(a)
Definition array.h:316
#define ARR_DIMS(a)
Definition array.h:294
#define ARR_HASNULL(a)
Definition array.h:291
#define ARR_LBOUND(a)
Definition array.h:296
int ArrayGetNItems(int ndim, const int *dims)
Definition arrayutils.c:57
void ArrayCheckBounds(int ndim, const int *dims, const int *lb)
Definition arrayutils.c:117
int32_t int32
Definition c.h:620
int errdetail(const char *fmt,...) pg_attribute_printf(1
#define palloc_array(type, count)
Definition fe_memutils.h:76
char * format_type_be(Oid type_oid)
#define nitems(x)
Definition indent.h:31
void * palloc0(Size size)
Definition mcxt.c:1417
static void SET_VARSIZE(void *PTR, Size len)
Definition varatt.h:432

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(), ereport, errcode(), errdetail(), errmsg, ERROR, fb(), format_type_be(), i, memcpy(), nitems, palloc0(), palloc_array, PG_ARGISNULL, PG_GETARG_ARRAYTYPE_P, PG_RETURN_ARRAYTYPE_P, PG_RETURN_NULL, result, and SET_VARSIZE().

◆ array_position()

Datum array_position ( PG_FUNCTION_ARGS  )

Definition at line 1310 of file array_userfuncs.c.

1311{
1312 return array_position_common(fcinfo);
1313}
static Datum array_position_common(FunctionCallInfo fcinfo)

References array_position_common().

◆ array_position_common()

static Datum array_position_common ( FunctionCallInfo  fcinfo)
static

Definition at line 1329 of file array_userfuncs.c.

1330{
1331 ArrayType *array;
1332 Oid collation = PG_GET_COLLATION();
1333 Oid element_type;
1335 value;
1336 bool isnull;
1337 int position,
1339 bool found = false;
1340 TypeCacheEntry *typentry;
1342 bool null_search;
1344
1345 if (PG_ARGISNULL(0))
1347
1348 array = PG_GETARG_ARRAYTYPE_P(0);
1349
1350 /*
1351 * We refuse to search for elements in multi-dimensional arrays, since we
1352 * have no good way to report the element's location in the array.
1353 */
1354 if (ARR_NDIM(array) > 1)
1355 ereport(ERROR,
1357 errmsg("searching for elements in multidimensional arrays is not supported")));
1358
1359 /* Searching in an empty array is well-defined, though: it always fails */
1360 if (ARR_NDIM(array) < 1)
1362
1363 if (PG_ARGISNULL(1))
1364 {
1365 /* fast return when the array doesn't have nulls */
1366 if (!array_contains_nulls(array))
1368 searched_element = (Datum) 0;
1369 null_search = true;
1370 }
1371 else
1372 {
1374 null_search = false;
1375 }
1376
1377 element_type = ARR_ELEMTYPE(array);
1378 position = (ARR_LBOUND(array))[0] - 1;
1379
1380 /* figure out where to start */
1381 if (PG_NARGS() == 3)
1382 {
1383 if (PG_ARGISNULL(2))
1384 ereport(ERROR,
1386 errmsg("initial position must not be null")));
1387
1389 }
1390 else
1391 position_min = (ARR_LBOUND(array))[0];
1392
1393 /*
1394 * We arrange to look up type info for array_create_iterator only once per
1395 * series of calls, assuming the element type doesn't change underneath
1396 * us.
1397 */
1398 my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra;
1399 if (my_extra == NULL)
1400 {
1401 fcinfo->flinfo->fn_extra = MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
1402 sizeof(ArrayMetaState));
1403 my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra;
1404 my_extra->element_type = ~element_type;
1405 }
1406
1407 if (my_extra->element_type != element_type)
1408 {
1409 get_typlenbyvalalign(element_type,
1410 &my_extra->typlen,
1411 &my_extra->typbyval,
1412 &my_extra->typalign);
1413
1414 typentry = lookup_type_cache(element_type, TYPECACHE_EQ_OPR_FINFO);
1415
1416 if (!OidIsValid(typentry->eq_opr_finfo.fn_oid))
1417 ereport(ERROR,
1419 errmsg("could not identify an equality operator for type %s",
1420 format_type_be(element_type))));
1421
1422 my_extra->element_type = element_type;
1423 fmgr_info_cxt(typentry->eq_opr_finfo.fn_oid, &my_extra->proc,
1424 fcinfo->flinfo->fn_mcxt);
1425 }
1426
1427 /* Examine each array element until we find a match. */
1429 while (array_iterate(array_iterator, &value, &isnull))
1430 {
1431 position++;
1432
1433 /* skip initial elements if caller requested so */
1434 if (position < position_min)
1435 continue;
1436
1437 /*
1438 * Can't look at the array element's value if it's null; but if we
1439 * search for null, we have a hit and are done.
1440 */
1441 if (isnull || null_search)
1442 {
1443 if (isnull && null_search)
1444 {
1445 found = true;
1446 break;
1447 }
1448 else
1449 continue;
1450 }
1451
1452 /* not nulls, so run the operator */
1453 if (DatumGetBool(FunctionCall2Coll(&my_extra->proc, collation,
1455 {
1456 found = true;
1457 break;
1458 }
1459 }
1460
1462
1463 /* Avoid leaking memory when handed toasted input */
1464 PG_FREE_IF_COPY(array, 0);
1465
1466 if (!found)
1468
1469 PG_RETURN_INT32(position);
1470}
static bool array_iterator(ArrayType *la, PGCALL2 callback, void *param, ltree **found)
Definition _ltree_op.c:38
bool array_iterate(ArrayIterator iterator, Datum *value, bool *isnull)
void array_free_iterator(ArrayIterator iterator)
bool array_contains_nulls(const ArrayType *array)
ArrayIterator array_create_iterator(ArrayType *arr, int slice_ndim, ArrayMetaState *mstate)
#define OidIsValid(objectId)
Definition c.h:858
Datum FunctionCall2Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2)
Definition fmgr.c:1151
#define PG_FREE_IF_COPY(ptr, n)
Definition fmgr.h:260
#define PG_NARGS()
Definition fmgr.h:203
#define PG_RETURN_INT32(x)
Definition fmgr.h:355
#define PG_GETARG_INT32(n)
Definition fmgr.h:269
#define PG_GET_COLLATION()
Definition fmgr.h:198
static struct @177 value
void get_typlenbyvalalign(Oid typid, int16 *typlen, bool *typbyval, char *typalign)
Definition lsyscache.c:2491
static bool DatumGetBool(Datum X)
Definition postgres.h:100
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 eq_opr_finfo
Definition typcache.h:76
TypeCacheEntry * lookup_type_cache(Oid type_id, int flags)
Definition typcache.c:389
#define TYPECACHE_EQ_OPR_FINFO
Definition typcache.h:143

References ARR_ELEMTYPE, ARR_LBOUND, ARR_NDIM, array_contains_nulls(), array_create_iterator(), array_free_iterator(), array_iterate(), array_iterator(), DatumGetBool(), TypeCacheEntry::eq_opr_finfo, ereport, errcode(), errmsg, ERROR, fb(), 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, TYPECACHE_EQ_OPR_FINFO, and value.

Referenced by array_position(), and array_position_start().

◆ array_position_start()

Datum array_position_start ( PG_FUNCTION_ARGS  )

Definition at line 1316 of file array_userfuncs.c.

1317{
1318 return array_position_common(fcinfo);
1319}

References array_position_common().

◆ array_positions()

Datum array_positions ( PG_FUNCTION_ARGS  )

Definition at line 1484 of file array_userfuncs.c.

1485{
1486 ArrayType *array;
1487 Oid collation = PG_GET_COLLATION();
1488 Oid element_type;
1490 value;
1491 bool isnull;
1492 int position;
1493 TypeCacheEntry *typentry;
1495 bool null_search;
1497 ArrayBuildState *astate = NULL;
1498
1499 if (PG_ARGISNULL(0))
1501
1502 array = PG_GETARG_ARRAYTYPE_P(0);
1503
1504 /*
1505 * We refuse to search for elements in multi-dimensional arrays, since we
1506 * have no good way to report the element's location in the array.
1507 */
1508 if (ARR_NDIM(array) > 1)
1509 ereport(ERROR,
1511 errmsg("searching for elements in multidimensional arrays is not supported")));
1512
1514
1515 /* Searching in an empty array is well-defined, though: it always fails */
1516 if (ARR_NDIM(array) < 1)
1518
1519 if (PG_ARGISNULL(1))
1520 {
1521 /* fast return when the array doesn't have nulls */
1522 if (!array_contains_nulls(array))
1524 searched_element = (Datum) 0;
1525 null_search = true;
1526 }
1527 else
1528 {
1530 null_search = false;
1531 }
1532
1533 element_type = ARR_ELEMTYPE(array);
1534 position = (ARR_LBOUND(array))[0] - 1;
1535
1536 /*
1537 * We arrange to look up type info for array_create_iterator only once per
1538 * series of calls, assuming the element type doesn't change underneath
1539 * us.
1540 */
1541 my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra;
1542 if (my_extra == NULL)
1543 {
1544 fcinfo->flinfo->fn_extra = MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
1545 sizeof(ArrayMetaState));
1546 my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra;
1547 my_extra->element_type = ~element_type;
1548 }
1549
1550 if (my_extra->element_type != element_type)
1551 {
1552 get_typlenbyvalalign(element_type,
1553 &my_extra->typlen,
1554 &my_extra->typbyval,
1555 &my_extra->typalign);
1556
1557 typentry = lookup_type_cache(element_type, TYPECACHE_EQ_OPR_FINFO);
1558
1559 if (!OidIsValid(typentry->eq_opr_finfo.fn_oid))
1560 ereport(ERROR,
1562 errmsg("could not identify an equality operator for type %s",
1563 format_type_be(element_type))));
1564
1565 my_extra->element_type = element_type;
1566 fmgr_info_cxt(typentry->eq_opr_finfo.fn_oid, &my_extra->proc,
1567 fcinfo->flinfo->fn_mcxt);
1568 }
1569
1570 /*
1571 * Accumulate each array position iff the element matches the given
1572 * element.
1573 */
1575 while (array_iterate(array_iterator, &value, &isnull))
1576 {
1577 position += 1;
1578
1579 /*
1580 * Can't look at the array element's value if it's null; but if we
1581 * search for null, we have a hit.
1582 */
1583 if (isnull || null_search)
1584 {
1585 if (isnull && null_search)
1586 astate =
1587 accumArrayResult(astate, Int32GetDatum(position), false,
1589
1590 continue;
1591 }
1592
1593 /* not nulls, so run the operator */
1594 if (DatumGetBool(FunctionCall2Coll(&my_extra->proc, collation,
1596 astate =
1597 accumArrayResult(astate, Int32GetDatum(position), false,
1599 }
1600
1602
1603 /* Avoid leaking memory when handed toasted input */
1604 PG_FREE_IF_COPY(array, 0);
1605
1607}
Datum makeArrayResult(ArrayBuildState *astate, MemoryContext rcontext)
static Datum Int32GetDatum(int32 X)
Definition postgres.h:212

References accumArrayResult(), ARR_ELEMTYPE, ARR_LBOUND, ARR_NDIM, array_contains_nulls(), array_create_iterator(), array_free_iterator(), array_iterate(), array_iterator(), CurrentMemoryContext, DatumGetBool(), TypeCacheEntry::eq_opr_finfo, ereport, errcode(), errmsg, ERROR, fb(), fmgr_info_cxt(), 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, TYPECACHE_EQ_OPR_FINFO, and value.

◆ array_prepend()

Datum array_prepend ( PG_FUNCTION_ARGS  )

Definition at line 223 of file array_userfuncs.c.

224{
227 bool isNull;
229 int *lb;
230 int indx;
231 int lb0;
233
234 isNull = PG_ARGISNULL(0);
235 if (isNull)
236 newelem = (Datum) 0;
237 else
240
241 if (eah->ndims == 1)
242 {
243 /* prepend newelem */
244 lb = eah->lbound;
245 lb0 = lb[0];
246
247 if (pg_sub_s32_overflow(lb0, 1, &indx))
250 errmsg("integer out of range")));
251 }
252 else if (eah->ndims == 0)
253 {
254 indx = 1;
255 lb0 = 1;
256 }
257 else
260 errmsg("argument must be empty or one-dimensional array")));
261
262 /* Perform element insertion */
263 my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra;
264
266 1, &indx, newelem, isNull,
267 -1, my_extra->typlen, my_extra->typbyval, my_extra->typalign);
268
269 /* Readjust result's LB to match the input's, as expected for prepend */
270 Assert(result == EOHPGetRWDatum(&eah->hdr));
271 if (eah->ndims == 1)
272 {
273 /* This is ok whether we've deconstructed or not */
274 eah->lbound[0] = lb0;
275 }
276
278}
static bool pg_sub_s32_overflow(int32 a, int32 b, int32 *result)
Definition int.h:169

References array_set_element(), Assert, EOHPGetRWDatum(), ereport, errcode(), errmsg, ERROR, fb(), fetch_array_arg_replace_nulls(), PG_ARGISNULL, PG_GETARG_DATUM, PG_RETURN_DATUM, pg_sub_s32_overflow(), and result.

◆ array_prepend_support()

Datum array_prepend_support ( PG_FUNCTION_ARGS  )

Definition at line 286 of file array_userfuncs.c.

287{
289 Node *ret = NULL;
290
292 {
293 /*
294 * We can optimize in-place prepends if the function's array argument
295 * is the array being assigned to. We don't need to worry about array
296 * references within the other argument.
297 */
299 Param *arg = (Param *) lsecond(req->args);
300
301 if (arg && IsA(arg, Param) &&
302 arg->paramkind == PARAM_EXTERN &&
303 arg->paramid == req->paramid)
304 ret = (Node *) arg;
305 }
306
308}
#define lsecond(l)
Definition pg_list.h:183

References arg, fb(), IsA, lsecond, PARAM_EXTERN, PG_GETARG_POINTER, and PG_RETURN_POINTER.

◆ array_reverse()

Datum array_reverse ( PG_FUNCTION_ARGS  )

Definition at line 1859 of file array_userfuncs.c.

1860{
1861 ArrayType *array = PG_GETARG_ARRAYTYPE_P(0);
1863 Oid elmtyp;
1864 TypeCacheEntry *typentry;
1865
1866 /*
1867 * There is no point in reversing empty arrays or arrays with less than
1868 * two items.
1869 */
1870 if (ARR_NDIM(array) < 1 || ARR_DIMS(array)[0] < 2)
1871 PG_RETURN_ARRAYTYPE_P(array);
1872
1873 elmtyp = ARR_ELEMTYPE(array);
1874 typentry = (TypeCacheEntry *) fcinfo->flinfo->fn_extra;
1875 if (typentry == NULL || typentry->type_id != elmtyp)
1876 {
1877 typentry = lookup_type_cache(elmtyp, 0);
1878 fcinfo->flinfo->fn_extra = (void *) typentry;
1879 }
1880
1881 result = array_reverse_n(array, elmtyp, typentry);
1882
1884}
static ArrayType * array_reverse_n(ArrayType *array, Oid elmtyp, TypeCacheEntry *typentry)

References ARR_DIMS, ARR_ELEMTYPE, ARR_NDIM, array_reverse_n(), fb(), lookup_type_cache(), PG_GETARG_ARRAYTYPE_P, PG_RETURN_ARRAYTYPE_P, result, and TypeCacheEntry::type_id.

◆ array_reverse_n()

static ArrayType * array_reverse_n ( ArrayType array,
Oid  elmtyp,
TypeCacheEntry typentry 
)
static

Definition at line 1784 of file array_userfuncs.c.

1785{
1787 int ndim,
1788 *dims,
1789 *lbs,
1790 nelm,
1791 nitem,
1792 rdims[MAXDIM],
1793 rlbs[MAXDIM];
1794 int16 elmlen;
1795 bool elmbyval;
1796 char elmalign;
1797 Datum *elms,
1798 *ielms;
1799 bool *nuls,
1800 *inuls;
1801
1802 ndim = ARR_NDIM(array);
1803 dims = ARR_DIMS(array);
1804 lbs = ARR_LBOUND(array);
1805
1806 elmlen = typentry->typlen;
1807 elmbyval = typentry->typbyval;
1808 elmalign = typentry->typalign;
1809
1810 deconstruct_array(array, elmtyp, elmlen, elmbyval, elmalign,
1811 &elms, &nuls, &nelm);
1812
1813 nitem = dims[0]; /* total number of items */
1814 nelm /= nitem; /* number of elements per item */
1815
1816 /* Reverse the array */
1817 ielms = elms;
1818 inuls = nuls;
1819 for (int i = 0; i < nitem / 2; i++)
1820 {
1821 int j = (nitem - i - 1) * nelm;
1822 Datum *jelms = elms + j;
1823 bool *jnuls = nuls + j;
1824
1825 /* Swap i'th and j'th items; advance ielms/inuls to next item */
1826 for (int k = 0; k < nelm; k++)
1827 {
1828 Datum elm = *ielms;
1829 bool nul = *inuls;
1830
1831 *ielms++ = *jelms;
1832 *inuls++ = *jnuls;
1833 *jelms++ = elm;
1834 *jnuls++ = nul;
1835 }
1836 }
1837
1838 /* Set up dimensions of the result */
1839 memcpy(rdims, dims, ndim * sizeof(int));
1840 memcpy(rlbs, lbs, ndim * sizeof(int));
1841 rdims[0] = nitem;
1842
1843 result = construct_md_array(elms, nuls, ndim, rdims, rlbs,
1844 elmtyp, elmlen, elmbyval, elmalign);
1845
1846 pfree(elms);
1847 pfree(nuls);
1848
1849 return result;
1850}
#define MAXDIM
Definition array.h:75
ArrayType * construct_md_array(Datum *elems, bool *nulls, int ndims, int *dims, int *lbs, Oid elmtype, int elmlen, bool elmbyval, char elmalign)
void deconstruct_array(const ArrayType *array, Oid elmtype, int elmlen, bool elmbyval, char elmalign, Datum **elemsp, bool **nullsp, int *nelemsp)
int16_t int16
Definition c.h:619
int j
Definition isn.c:78
void pfree(void *pointer)
Definition mcxt.c:1616

References ARR_DIMS, ARR_LBOUND, ARR_NDIM, construct_md_array(), deconstruct_array(), fb(), i, j, MAXDIM, memcpy(), pfree(), result, TypeCacheEntry::typalign, TypeCacheEntry::typbyval, and TypeCacheEntry::typlen.

Referenced by array_reverse().

◆ array_sample()

Datum array_sample ( PG_FUNCTION_ARGS  )

Definition at line 1745 of file array_userfuncs.c.

1746{
1747 ArrayType *array = PG_GETARG_ARRAYTYPE_P(0);
1748 int n = PG_GETARG_INT32(1);
1750 Oid elmtyp;
1751 TypeCacheEntry *typentry;
1752 int nitem;
1753
1754 nitem = (ARR_NDIM(array) < 1) ? 0 : ARR_DIMS(array)[0];
1755
1756 if (n < 0 || n > nitem)
1757 ereport(ERROR,
1759 errmsg("sample size must be between 0 and %d", nitem)));
1760
1761 elmtyp = ARR_ELEMTYPE(array);
1762 typentry = (TypeCacheEntry *) fcinfo->flinfo->fn_extra;
1763 if (typentry == NULL || typentry->type_id != elmtyp)
1764 {
1765 typentry = lookup_type_cache(elmtyp, 0);
1766 fcinfo->flinfo->fn_extra = typentry;
1767 }
1768
1769 result = array_shuffle_n(array, n, false, elmtyp, typentry);
1770
1772}
static ArrayType * array_shuffle_n(ArrayType *array, int n, bool keep_lb, Oid elmtyp, TypeCacheEntry *typentry)

References ARR_DIMS, ARR_ELEMTYPE, ARR_NDIM, array_shuffle_n(), ereport, errcode(), errmsg, ERROR, fb(), lookup_type_cache(), PG_GETARG_ARRAYTYPE_P, PG_GETARG_INT32, PG_RETURN_ARRAYTYPE_P, result, and TypeCacheEntry::type_id.

◆ array_shuffle()

Datum array_shuffle ( PG_FUNCTION_ARGS  )

Definition at line 1711 of file array_userfuncs.c.

1712{
1713 ArrayType *array = PG_GETARG_ARRAYTYPE_P(0);
1715 Oid elmtyp;
1716 TypeCacheEntry *typentry;
1717
1718 /*
1719 * There is no point in shuffling empty arrays or arrays with less than
1720 * two items.
1721 */
1722 if (ARR_NDIM(array) < 1 || ARR_DIMS(array)[0] < 2)
1723 PG_RETURN_ARRAYTYPE_P(array);
1724
1725 elmtyp = ARR_ELEMTYPE(array);
1726 typentry = (TypeCacheEntry *) fcinfo->flinfo->fn_extra;
1727 if (typentry == NULL || typentry->type_id != elmtyp)
1728 {
1729 typentry = lookup_type_cache(elmtyp, 0);
1730 fcinfo->flinfo->fn_extra = typentry;
1731 }
1732
1733 result = array_shuffle_n(array, ARR_DIMS(array)[0], true, elmtyp, typentry);
1734
1736}

References ARR_DIMS, ARR_ELEMTYPE, ARR_NDIM, array_shuffle_n(), fb(), lookup_type_cache(), PG_GETARG_ARRAYTYPE_P, PG_RETURN_ARRAYTYPE_P, result, and TypeCacheEntry::type_id.

◆ array_shuffle_n()

static ArrayType * array_shuffle_n ( ArrayType array,
int  n,
bool  keep_lb,
Oid  elmtyp,
TypeCacheEntry typentry 
)
static

Definition at line 1622 of file array_userfuncs.c.

1624{
1626 int ndim,
1627 *dims,
1628 *lbs,
1629 nelm,
1630 nitem,
1631 rdims[MAXDIM],
1632 rlbs[MAXDIM];
1633 int16 elmlen;
1634 bool elmbyval;
1635 char elmalign;
1636 Datum *elms,
1637 *ielms;
1638 bool *nuls,
1639 *inuls;
1640
1641 ndim = ARR_NDIM(array);
1642 dims = ARR_DIMS(array);
1643 lbs = ARR_LBOUND(array);
1644
1645 elmlen = typentry->typlen;
1646 elmbyval = typentry->typbyval;
1647 elmalign = typentry->typalign;
1648
1649 /* If the target array is empty, exit fast */
1650 if (ndim < 1 || dims[0] < 1 || n < 1)
1652
1653 deconstruct_array(array, elmtyp, elmlen, elmbyval, elmalign,
1654 &elms, &nuls, &nelm);
1655
1656 nitem = dims[0]; /* total number of items */
1657 nelm /= nitem; /* number of elements per item */
1658
1659 Assert(n <= nitem); /* else it's caller error */
1660
1661 /*
1662 * Shuffle array using Fisher-Yates algorithm. Scan the array and swap
1663 * current item (nelm datums starting at ielms) with a randomly chosen
1664 * later item (nelm datums starting at jelms) in each iteration. We can
1665 * stop once we've done n iterations; then first n items are the result.
1666 */
1667 ielms = elms;
1668 inuls = nuls;
1669 for (int i = 0; i < n; i++)
1670 {
1671 int j = (int) pg_prng_uint64_range(&pg_global_prng_state, i, nitem - 1) * nelm;
1672 Datum *jelms = elms + j;
1673 bool *jnuls = nuls + j;
1674
1675 /* Swap i'th and j'th items; advance ielms/inuls to next item */
1676 for (int k = 0; k < nelm; k++)
1677 {
1678 Datum elm = *ielms;
1679 bool nul = *inuls;
1680
1681 *ielms++ = *jelms;
1682 *inuls++ = *jnuls;
1683 *jelms++ = elm;
1684 *jnuls++ = nul;
1685 }
1686 }
1687
1688 /* Set up dimensions of the result */
1689 memcpy(rdims, dims, ndim * sizeof(int));
1690 memcpy(rlbs, lbs, ndim * sizeof(int));
1691 rdims[0] = n;
1692 if (!keep_lb)
1693 rlbs[0] = 1;
1694
1695 result = construct_md_array(elms, nuls, ndim, rdims, rlbs,
1696 elmtyp, elmlen, elmbyval, elmalign);
1697
1698 pfree(elms);
1699 pfree(nuls);
1700
1701 return result;
1702}
ArrayType * construct_empty_array(Oid elmtype)
uint64 pg_prng_uint64_range(pg_prng_state *state, uint64 rmin, uint64 rmax)
Definition pg_prng.c:144
pg_prng_state pg_global_prng_state
Definition pg_prng.c:34

References ARR_DIMS, ARR_LBOUND, ARR_NDIM, Assert, construct_empty_array(), construct_md_array(), deconstruct_array(), fb(), i, j, MAXDIM, memcpy(), pfree(), pg_global_prng_state, pg_prng_uint64_range(), result, TypeCacheEntry::typalign, TypeCacheEntry::typbyval, and TypeCacheEntry::typlen.

Referenced by array_sample(), and array_shuffle().

◆ array_sort()

Datum array_sort ( PG_FUNCTION_ARGS  )

Definition at line 2014 of file array_userfuncs.c.

2015{
2016 ArrayType *array = PG_GETARG_ARRAYTYPE_P(0);
2017
2019 false,
2020 false,
2021 fcinfo));
2022}
static ArrayType * array_sort_internal(ArrayType *array, bool descending, bool nulls_first, FunctionCallInfo fcinfo)

References array_sort_internal(), PG_GETARG_ARRAYTYPE_P, and PG_RETURN_ARRAYTYPE_P.

◆ array_sort_internal()

static ArrayType * array_sort_internal ( ArrayType array,
bool  descending,
bool  nulls_first,
FunctionCallInfo  fcinfo 
)
static

Definition at line 1892 of file array_userfuncs.c.

1894{
1896 Oid collation = PG_GET_COLLATION();
1897 int ndim,
1898 *dims,
1899 *lbs;
1901 Oid elmtyp;
1902 Oid sort_typ;
1903 Oid sort_opr;
1904 Tuplesortstate *tuplesortstate;
1906 Datum value;
1907 bool isnull;
1908 ArrayBuildStateAny *astate = NULL;
1909
1910 ndim = ARR_NDIM(array);
1911 dims = ARR_DIMS(array);
1912 lbs = ARR_LBOUND(array);
1913
1914 /* Quick exit if we don't need to sort */
1915 if (ndim < 1 || dims[0] < 2)
1916 return array;
1917
1918 /* Set up cache area if we didn't already */
1920 if (cache_info == NULL)
1921 {
1924 sizeof(ArraySortCachedInfo));
1925 fcinfo->flinfo->fn_extra = cache_info;
1926 }
1927
1928 /* Fetch and cache required data if we don't have it */
1929 elmtyp = ARR_ELEMTYPE(array);
1930 if (elmtyp != cache_info->array_meta.element_type)
1931 {
1932 TypeCacheEntry *typentry;
1933
1934 typentry = lookup_type_cache(elmtyp,
1936 cache_info->array_meta.element_type = elmtyp;
1937 cache_info->array_meta.typlen = typentry->typlen;
1938 cache_info->array_meta.typbyval = typentry->typbyval;
1939 cache_info->array_meta.typalign = typentry->typalign;
1940 cache_info->elem_lt_opr = typentry->lt_opr;
1941 cache_info->elem_gt_opr = typentry->gt_opr;
1942 cache_info->array_type = typentry->typarray;
1943 }
1944
1945 /* Identify the sort operator to use */
1946 if (ndim == 1)
1947 {
1948 /* Need to sort the element type */
1949 sort_typ = elmtyp;
1950 sort_opr = (descending ? cache_info->elem_gt_opr : cache_info->elem_lt_opr);
1951 }
1952 else
1953 {
1954 /* Otherwise we're sorting arrays */
1955 sort_typ = cache_info->array_type;
1956 if (!OidIsValid(sort_typ))
1957 ereport(ERROR,
1959 errmsg("could not find array type for data type %s",
1961 /* We know what operators to use for arrays */
1963 }
1964
1965 /*
1966 * Fail if we don't know how to sort. The error message is chosen to
1967 * match what array_lt()/array_gt() will say in the multidimensional case.
1968 */
1969 if (!OidIsValid(sort_opr))
1970 ereport(ERROR,
1972 errmsg("could not identify a comparison function for type %s",
1974
1975 /* Put the things to be sorted (elements or sub-arrays) into a tuplesort */
1976 tuplesortstate = tuplesort_begin_datum(sort_typ,
1977 sort_opr,
1978 collation,
1979 nulls_first,
1980 work_mem,
1981 NULL,
1983
1984 array_iterator = array_create_iterator(array, ndim - 1,
1985 &cache_info->array_meta);
1986 while (array_iterate(array_iterator, &value, &isnull))
1987 {
1988 tuplesort_putdatum(tuplesortstate, value, isnull);
1989 }
1991
1992 /* Do the sort */
1993 tuplesort_performsort(tuplesortstate);
1994
1995 /* Extract results into a new array */
1996 while (tuplesort_getdatum(tuplesortstate, true, false, &value, &isnull, NULL))
1997 {
1998 astate = accumArrayResultAny(astate, value, isnull,
2000 }
2001 tuplesort_end(tuplesortstate);
2002
2005 true));
2006
2007 /* Adjust lower bound to match the input */
2008 ARR_LBOUND(newarray)[0] = lbs[0];
2009
2010 return newarray;
2011}
#define DatumGetArrayTypeP(X)
Definition array.h:261
ArrayBuildStateAny * accumArrayResultAny(ArrayBuildStateAny *astate, Datum dvalue, bool disnull, Oid input_type, MemoryContext rcontext)
Datum makeArrayResultAny(ArrayBuildStateAny *astate, MemoryContext rcontext, bool release)
int work_mem
Definition globals.c:133
void * MemoryContextAllocZero(MemoryContext context, Size size)
Definition mcxt.c:1266
void tuplesort_performsort(Tuplesortstate *state)
Definition tuplesort.c:1260
void tuplesort_end(Tuplesortstate *state)
Definition tuplesort.c:848
#define TUPLESORT_NONE
Definition tuplesort.h:67
void tuplesort_putdatum(Tuplesortstate *state, Datum val, bool isNull)
Tuplesortstate * tuplesort_begin_datum(Oid datumType, Oid sortOperator, Oid sortCollation, bool nullsFirstFlag, int workMem, SortCoordinate coordinate, int sortopt)
bool tuplesort_getdatum(Tuplesortstate *state, bool forward, bool copy, Datum *val, bool *isNull, Datum *abbrev)
#define TYPECACHE_GT_OPR
Definition typcache.h:140
#define TYPECACHE_LT_OPR
Definition typcache.h:139

References accumArrayResultAny(), ARR_DIMS, ARR_ELEMTYPE, ARR_LBOUND, ARR_NDIM, array_create_iterator(), array_free_iterator(), array_iterate(), array_iterator(), CurrentMemoryContext, DatumGetArrayTypeP, ereport, errcode(), errmsg, ERROR, fb(), FunctionCallInfoBaseData::flinfo, FmgrInfo::fn_extra, FmgrInfo::fn_mcxt, format_type_be(), TypeCacheEntry::gt_opr, lookup_type_cache(), TypeCacheEntry::lt_opr, makeArrayResultAny(), MemoryContextAllocZero(), OidIsValid, PG_GET_COLLATION, tuplesort_begin_datum(), tuplesort_end(), tuplesort_getdatum(), TUPLESORT_NONE, tuplesort_performsort(), tuplesort_putdatum(), TypeCacheEntry::typalign, TypeCacheEntry::typarray, TypeCacheEntry::typbyval, TYPECACHE_GT_OPR, TYPECACHE_LT_OPR, TypeCacheEntry::typlen, value, and work_mem.

Referenced by array_sort(), array_sort_order(), and array_sort_order_nulls_first().

◆ array_sort_order()

Datum array_sort_order ( PG_FUNCTION_ARGS  )

Definition at line 2025 of file array_userfuncs.c.

2026{
2027 ArrayType *array = PG_GETARG_ARRAYTYPE_P(0);
2028 bool descending = PG_GETARG_BOOL(1);
2029
2031 descending,
2032 descending,
2033 fcinfo));
2034}
#define PG_GETARG_BOOL(n)
Definition fmgr.h:274

References array_sort_internal(), fb(), PG_GETARG_ARRAYTYPE_P, PG_GETARG_BOOL, and PG_RETURN_ARRAYTYPE_P.

◆ array_sort_order_nulls_first()

Datum array_sort_order_nulls_first ( PG_FUNCTION_ARGS  )

Definition at line 2037 of file array_userfuncs.c.

2038{
2039 ArrayType *array = PG_GETARG_ARRAYTYPE_P(0);
2040 bool descending = PG_GETARG_BOOL(1);
2041 bool nulls_first = PG_GETARG_BOOL(2);
2042
2044 descending,
2045 nulls_first,
2046 fcinfo));
2047}

References array_sort_internal(), fb(), PG_GETARG_ARRAYTYPE_P, PG_GETARG_BOOL, and PG_RETURN_ARRAYTYPE_P.

◆ fetch_array_arg_replace_nulls()

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

Definition at line 81 of file array_userfuncs.c.

82{
84 Oid element_type;
87
88 /* If first time through, create datatype cache struct */
90 if (my_extra == NULL)
91 {
94 sizeof(ArrayMetaState));
95 my_extra->element_type = InvalidOid;
96 fcinfo->flinfo->fn_extra = my_extra;
97 }
98
99 /* Figure out which context we want the result in */
100 if (!AggCheckCallContext(fcinfo, &resultcxt))
102
103 /* Now collect the array value */
104 if (!PG_ARGISNULL(argno))
105 {
107
110 }
111 else
112 {
113 /* We have to look up the array type and element type */
115
119 errmsg("could not determine input data type")));
120 element_type = get_element_type(arr_typeid);
121 if (!OidIsValid(element_type))
124 errmsg("input data type is not an array")));
125
126 eah = construct_empty_expanded_array(element_type,
127 resultcxt,
128 my_extra);
129 }
130
131 return eah;
132}
#define PG_GETARG_EXPANDED_ARRAYX(n, metacache)
Definition array.h:269
ExpandedArrayHeader * construct_empty_expanded_array(Oid element_type, MemoryContext parentcontext, ArrayMetaState *metacache)
Oid get_element_type(Oid typid)
Definition lsyscache.c:2981

References AggCheckCallContext(), construct_empty_expanded_array(), CurrentMemoryContext, ereport, errcode(), errmsg, ERROR, fb(), 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().