PostgreSQL Source Code git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
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/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

typedef struct SerialIOData SerialIOData

Function Documentation

◆ array_agg_array_combine()

Datum array_agg_array_combine ( PG_FUNCTION_ARGS  )

Definition at line 977 of file array_userfuncs.c.

978{
979 ArrayBuildStateArr *state1;
980 ArrayBuildStateArr *state2;
981 MemoryContext agg_context;
982 MemoryContext old_context;
983
984 if (!AggCheckCallContext(fcinfo, &agg_context))
985 elog(ERROR, "aggregate function called in non-aggregate context");
986
987 state1 = PG_ARGISNULL(0) ? NULL : (ArrayBuildStateArr *) PG_GETARG_POINTER(0);
988 state2 = PG_ARGISNULL(1) ? NULL : (ArrayBuildStateArr *) PG_GETARG_POINTER(1);
989
990 if (state2 == NULL)
991 {
992 /*
993 * NULL state2 is easy, just return state1, which we know is already
994 * in the agg_context
995 */
996 if (state1 == NULL)
998 PG_RETURN_POINTER(state1);
999 }
1000
1001 if (state1 == NULL)
1002 {
1003 /* We must copy state2's data into the agg_context */
1004 old_context = MemoryContextSwitchTo(agg_context);
1005
1006 state1 = initArrayResultArr(state2->array_type, InvalidOid,
1007 agg_context, false);
1008
1009 state1->abytes = state2->abytes;
1010 state1->data = (char *) palloc(state1->abytes);
1011
1012 if (state2->nullbitmap)
1013 {
1014 int size = (state2->aitems + 7) / 8;
1015
1016 state1->nullbitmap = (bits8 *) palloc(size);
1017 memcpy(state1->nullbitmap, state2->nullbitmap, size);
1018 }
1019
1020 memcpy(state1->data, state2->data, state2->nbytes);
1021 state1->nbytes = state2->nbytes;
1022 state1->aitems = state2->aitems;
1023 state1->nitems = state2->nitems;
1024 state1->ndims = state2->ndims;
1025 memcpy(state1->dims, state2->dims, sizeof(state2->dims));
1026 memcpy(state1->lbs, state2->lbs, sizeof(state2->lbs));
1027 state1->array_type = state2->array_type;
1028 state1->element_type = state2->element_type;
1029
1030 MemoryContextSwitchTo(old_context);
1031
1032 PG_RETURN_POINTER(state1);
1033 }
1034
1035 /* We only need to combine the two states if state2 has any items */
1036 else if (state2->nitems > 0)
1037 {
1038 MemoryContext oldContext;
1039 int reqsize = state1->nbytes + state2->nbytes;
1040 int i;
1041
1042 /*
1043 * Check the states are compatible with each other. Ensure we use the
1044 * same error messages that are listed in accumArrayResultArr so that
1045 * the same error is shown as would have been if we'd not used the
1046 * combine function for the aggregation.
1047 */
1048 if (state1->ndims != state2->ndims)
1049 ereport(ERROR,
1050 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
1051 errmsg("cannot accumulate arrays of different dimensionality")));
1052
1053 /* Check dimensions match ignoring the first dimension. */
1054 for (i = 1; i < state1->ndims; i++)
1055 {
1056 if (state1->dims[i] != state2->dims[i] || state1->lbs[i] != state2->lbs[i])
1057 ereport(ERROR,
1058 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
1059 errmsg("cannot accumulate arrays of different dimensionality")));
1060 }
1061
1062
1063 oldContext = MemoryContextSwitchTo(state1->mcontext);
1064
1065 /*
1066 * If there's not enough space in state1 then we'll need to reallocate
1067 * more.
1068 */
1069 if (state1->abytes < reqsize)
1070 {
1071 /* use a power of 2 size rather than allocating just reqsize */
1072 state1->abytes = pg_nextpower2_32(reqsize);
1073 state1->data = (char *) repalloc(state1->data, state1->abytes);
1074 }
1075
1076 if (state2->nullbitmap)
1077 {
1078 int newnitems = state1->nitems + state2->nitems;
1079
1080 if (state1->nullbitmap == NULL)
1081 {
1082 /*
1083 * First input with nulls; we must retrospectively handle any
1084 * previous inputs by marking all their items non-null.
1085 */
1086 state1->aitems = pg_nextpower2_32(Max(256, newnitems + 1));
1087 state1->nullbitmap = (bits8 *) palloc((state1->aitems + 7) / 8);
1088 array_bitmap_copy(state1->nullbitmap, 0,
1089 NULL, 0,
1090 state1->nitems);
1091 }
1092 else if (newnitems > state1->aitems)
1093 {
1094 int newaitems = state1->aitems + state2->aitems;
1095
1096 state1->aitems = pg_nextpower2_32(newaitems);
1097 state1->nullbitmap = (bits8 *)
1098 repalloc(state1->nullbitmap, (state1->aitems + 7) / 8);
1099 }
1100 array_bitmap_copy(state1->nullbitmap, state1->nitems,
1101 state2->nullbitmap, 0,
1102 state2->nitems);
1103 }
1104
1105 memcpy(state1->data + state1->nbytes, state2->data, state2->nbytes);
1106 state1->nbytes += state2->nbytes;
1107 state1->nitems += state2->nitems;
1108
1109 state1->dims[0] += state2->dims[0];
1110 /* remaining dims already match, per test above */
1111
1112 Assert(state1->array_type == state2->array_type);
1113 Assert(state1->element_type == state2->element_type);
1114
1115 MemoryContextSwitchTo(oldContext);
1116 }
1117
1118 PG_RETURN_POINTER(state1);
1119}
ArrayBuildStateArr * initArrayResultArr(Oid array_type, Oid element_type, MemoryContext rcontext, bool subcontext)
Definition: arrayfuncs.c:5504
void array_bitmap_copy(bits8 *destbitmap, int destoffset, const bits8 *srcbitmap, int srcoffset, int nitems)
Definition: arrayfuncs.c:4966
#define Max(x, y)
Definition: c.h:969
uint8 bits8
Definition: c.h:509
int errcode(int sqlerrcode)
Definition: elog.c:854
int errmsg(const char *fmt,...)
Definition: elog.c:1071
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:225
#define ereport(elevel,...)
Definition: elog.h:149
#define PG_GETARG_POINTER(n)
Definition: fmgr.h:276
#define PG_ARGISNULL(n)
Definition: fmgr.h:209
#define PG_RETURN_NULL()
Definition: fmgr.h:345
#define PG_RETURN_POINTER(x)
Definition: fmgr.h:361
Assert(PointerIsAligned(start, uint64))
int i
Definition: isn.c:77
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:2172
void * palloc(Size size)
Definition: mcxt.c:1945
int AggCheckCallContext(FunctionCallInfo fcinfo, MemoryContext *aggcontext)
Definition: nodeAgg.c:4614
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:124
static uint32 pg_nextpower2_32(uint32 num)
Definition: pg_bitutils.h:189
#define InvalidOid
Definition: postgres_ext.h:35
bits8 * nullbitmap
Definition: array.h:209
int lbs[MAXDIM]
Definition: array.h:216
MemoryContext mcontext
Definition: array.h:207
int dims[MAXDIM]
Definition: array.h:215

References ArrayBuildStateArr::abytes, AggCheckCallContext(), ArrayBuildStateArr::aitems, array_bitmap_copy(), ArrayBuildStateArr::array_type, Assert(), ArrayBuildStateArr::data, ArrayBuildStateArr::dims, ArrayBuildStateArr::element_type, elog, ereport, errcode(), errmsg(), ERROR, i, initArrayResultArr(), InvalidOid, ArrayBuildStateArr::lbs, Max, ArrayBuildStateArr::mcontext, MemoryContextSwitchTo(), ArrayBuildStateArr::nbytes, ArrayBuildStateArr::ndims, ArrayBuildStateArr::nitems, ArrayBuildStateArr::nullbitmap, palloc(), 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 1185 of file array_userfuncs.c.

1186{
1187 bytea *sstate;
1188 ArrayBuildStateArr *result;
1190 Oid element_type;
1191 Oid array_type;
1192 int nbytes;
1193 const char *temp;
1194
1195 /* cannot be called directly because of internal-type argument */
1196 Assert(AggCheckCallContext(fcinfo, NULL));
1197
1198 sstate = PG_GETARG_BYTEA_PP(0);
1199
1200 /*
1201 * Initialize a StringInfo so that we can "receive" it using the standard
1202 * recv-function infrastructure.
1203 */
1205 VARSIZE_ANY_EXHDR(sstate));
1206
1207 /* element_type */
1208 element_type = pq_getmsgint(&buf, 4);
1209
1210 /* array_type */
1211 array_type = pq_getmsgint(&buf, 4);
1212
1213 /* nbytes */
1214 nbytes = pq_getmsgint(&buf, 4);
1215
1216 result = initArrayResultArr(array_type, element_type,
1217 CurrentMemoryContext, false);
1218
1219 result->abytes = 1024;
1220 while (result->abytes < nbytes)
1221 result->abytes *= 2;
1222
1223 result->data = (char *) palloc(result->abytes);
1224
1225 /* data */
1226 temp = pq_getmsgbytes(&buf, nbytes);
1227 memcpy(result->data, temp, nbytes);
1228 result->nbytes = nbytes;
1229
1230 /* abytes */
1231 result->abytes = pq_getmsgint(&buf, 4);
1232
1233 /* aitems: might be 0 */
1234 result->aitems = pq_getmsgint(&buf, 4);
1235
1236 /* nullbitmap */
1237 if (result->aitems > 0)
1238 {
1239 int size = (result->aitems + 7) / 8;
1240
1241 result->nullbitmap = (bits8 *) palloc(size);
1242 temp = pq_getmsgbytes(&buf, size);
1243 memcpy(result->nullbitmap, temp, size);
1244 }
1245 else
1246 result->nullbitmap = NULL;
1247
1248 /* nitems */
1249 result->nitems = pq_getmsgint(&buf, 4);
1250
1251 /* ndims */
1252 result->ndims = pq_getmsgint(&buf, 4);
1253
1254 /* dims */
1255 temp = pq_getmsgbytes(&buf, sizeof(result->dims));
1256 memcpy(result->dims, temp, sizeof(result->dims));
1257
1258 /* lbs */
1259 temp = pq_getmsgbytes(&buf, sizeof(result->lbs));
1260 memcpy(result->lbs, temp, sizeof(result->lbs));
1261
1262 pq_getmsgend(&buf);
1263
1264 PG_RETURN_POINTER(result);
1265}
#define PG_GETARG_BYTEA_PP(n)
Definition: fmgr.h:308
MemoryContext CurrentMemoryContext
Definition: mcxt.c:159
static char * buf
Definition: pg_test_fsync.c:72
unsigned int Oid
Definition: postgres_ext.h:30
unsigned int pq_getmsgint(StringInfo msg, int b)
Definition: pqformat.c:415
void pq_getmsgend(StringInfo msg)
Definition: pqformat.c:635
const char * pq_getmsgbytes(StringInfo msg, int datalen)
Definition: pqformat.c:508
static void initReadOnlyStringInfo(StringInfo str, char *data, int len)
Definition: stringinfo.h:157
Definition: c.h:658
#define VARDATA_ANY(PTR)
Definition: varatt.h:324
#define VARSIZE_ANY_EXHDR(PTR)
Definition: varatt.h:317

References ArrayBuildStateArr::abytes, AggCheckCallContext(), ArrayBuildStateArr::aitems, Assert(), buf, CurrentMemoryContext, ArrayBuildStateArr::data, ArrayBuildStateArr::dims, initArrayResultArr(), initReadOnlyStringInfo(), ArrayBuildStateArr::lbs, ArrayBuildStateArr::nbytes, ArrayBuildStateArr::ndims, ArrayBuildStateArr::nitems, ArrayBuildStateArr::nullbitmap, palloc(), PG_GETARG_BYTEA_PP, PG_RETURN_POINTER, pq_getmsgbytes(), pq_getmsgend(), pq_getmsgint(), VARDATA_ANY, and VARSIZE_ANY_EXHDR.

◆ array_agg_array_finalfn()

Datum array_agg_array_finalfn ( PG_FUNCTION_ARGS  )

Definition at line 1268 of file array_userfuncs.c.

1269{
1270 Datum result;
1272
1273 /* cannot be called directly because of internal-type argument */
1274 Assert(AggCheckCallContext(fcinfo, NULL));
1275
1277
1278 if (state == NULL)
1279 PG_RETURN_NULL(); /* returns null iff no input values */
1280
1281 /*
1282 * Make the result. We cannot release the ArrayBuildStateArr because
1283 * sometimes aggregate final functions are re-executed. Rather, it is
1284 * nodeAgg.c's responsibility to reset the aggcontext when it's safe to do
1285 * so.
1286 */
1288
1289 PG_RETURN_DATUM(result);
1290}
Datum makeArrayResultArr(ArrayBuildStateArr *astate, MemoryContext rcontext, bool release)
Definition: arrayfuncs.c:5703
#define PG_RETURN_DATUM(x)
Definition: fmgr.h:353
uintptr_t Datum
Definition: postgres.h:69
Definition: regguts.h:323

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

◆ array_agg_array_serialize()

Datum array_agg_array_serialize ( PG_FUNCTION_ARGS  )

Definition at line 1126 of file array_userfuncs.c.

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

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

◆ array_agg_array_transfn()

Datum array_agg_array_transfn ( PG_FUNCTION_ARGS  )

Definition at line 933 of file array_userfuncs.c.

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

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.

◆ array_agg_combine()

Datum array_agg_combine ( PG_FUNCTION_ARGS  )

Definition at line 601 of file array_userfuncs.c.

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

References AggCheckCallContext(), ArrayBuildState::alen, Assert(), datumCopy(), ArrayBuildState::dnulls, ArrayBuildState::dvalues, ArrayBuildState::element_type, elog, ERROR, i, initArrayResultWithSize(), ArrayBuildState::mcontext, MemoryContextSwitchTo(), ArrayBuildState::nelems, PG_ARGISNULL, PG_GETARG_POINTER, pg_nextpower2_32(), PG_RETURN_NULL, PG_RETURN_POINTER, repalloc(), ArrayBuildState::typbyval, and ArrayBuildState::typlen.

◆ array_agg_deserialize()

Datum array_agg_deserialize ( PG_FUNCTION_ARGS  )

Definition at line 787 of file array_userfuncs.c.

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

References AggCheckCallContext(), buf, CurrentMemoryContext, ArrayBuildState::dnulls, ArrayBuildState::dvalues, elog, ereport, errcode(), errmsg(), ERROR, fmgr_info_cxt(), FmgrInfo::fn_mcxt, getTypeBinaryInputInfo(), i, if(), initArrayResultWithSize(), initReadOnlyStringInfo(), MemoryContextAlloc(), ArrayBuildState::nelems, PG_GETARG_BYTEA_PP, PG_RETURN_POINTER, pq_getmsgbyte(), pq_getmsgbytes(), pq_getmsgend(), pq_getmsgint(), pq_getmsgint64(), ReceiveFunctionCall(), ArrayBuildState::typalign, ArrayBuildState::typbyval, DeserialIOData::typioparam, ArrayBuildState::typlen, DeserialIOData::typreceive, VARDATA_ANY, and VARSIZE_ANY_EXHDR.

◆ array_agg_finalfn()

Datum array_agg_finalfn ( PG_FUNCTION_ARGS  )

Definition at line 898 of file array_userfuncs.c.

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

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

◆ array_agg_serialize()

Datum array_agg_serialize ( PG_FUNCTION_ARGS  )

Definition at line 698 of file array_userfuncs.c.

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

References AggCheckCallContext(), Assert(), buf, fmgr_info_cxt(), FmgrInfo::fn_mcxt, getTypeBinaryOutputInfo(), i, if(), MemoryContextAlloc(), PG_GETARG_POINTER, PG_RETURN_BYTEA_P, pq_begintypsend(), pq_endtypsend(), pq_sendbyte(), pq_sendbytes(), pq_sendint16(), pq_sendint32(), pq_sendint64(), SendFunctionCall(), SerialIOData::typsend, VARDATA, VARHDRSZ, and VARSIZE.

◆ array_agg_transfn()

Datum array_agg_transfn ( PG_FUNCTION_ARGS  )

Definition at line 555 of file array_userfuncs.c.

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

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.

◆ array_append()

Datum array_append ( PG_FUNCTION_ARGS  )

Definition at line 139 of file array_userfuncs.c.

140{
142 Datum newelem;
143 bool isNull;
144 Datum result;
145 int *dimv,
146 *lb;
147 int indx;
148 ArrayMetaState *my_extra;
149
150 eah = fetch_array_arg_replace_nulls(fcinfo, 0);
151 isNull = PG_ARGISNULL(1);
152 if (isNull)
153 newelem = (Datum) 0;
154 else
155 newelem = PG_GETARG_DATUM(1);
156
157 if (eah->ndims == 1)
158 {
159 /* append newelem */
160 lb = eah->lbound;
161 dimv = eah->dims;
162
163 /* index of added elem is at lb[0] + (dimv[0] - 1) + 1 */
164 if (pg_add_s32_overflow(lb[0], dimv[0], &indx))
166 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
167 errmsg("integer out of range")));
168 }
169 else if (eah->ndims == 0)
170 indx = 1;
171 else
173 (errcode(ERRCODE_DATA_EXCEPTION),
174 errmsg("argument must be empty or one-dimensional array")));
175
176 /* Perform element insertion */
177 my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra;
178
179 result = array_set_element(EOHPGetRWDatum(&eah->hdr),
180 1, &indx, newelem, isNull,
181 -1, my_extra->typlen, my_extra->typbyval, my_extra->typalign);
182
183 PG_RETURN_DATUM(result);
184}
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)
Definition: arrayfuncs.c:2201
static Datum EOHPGetRWDatum(const struct ExpandedObjectHeader *eohptr)
static bool pg_add_s32_overflow(int32 a, int32 b, int32 *result)
Definition: int.h:151
char typalign
Definition: array.h:241
int16 typlen
Definition: array.h:239
bool typbyval
Definition: array.h:240
ExpandedObjectHeader hdr
Definition: array.h:118

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.

◆ array_append_support()

Datum array_append_support ( PG_FUNCTION_ARGS  )

Definition at line 192 of file array_userfuncs.c.

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

References arg, SupportRequestModifyInPlace::args, IsA, linitial, PARAM_EXTERN, SupportRequestModifyInPlace::paramid, PG_GETARG_POINTER, and PG_RETURN_POINTER.

◆ array_cat()

Datum array_cat ( PG_FUNCTION_ARGS  )

Definition at line 316 of file array_userfuncs.c.

317{
318 ArrayType *v1,
319 *v2;
320 ArrayType *result;
321 int *dims,
322 *lbs,
323 ndims,
324 nitems,
325 ndatabytes,
326 nbytes;
327 int *dims1,
328 *lbs1,
329 ndims1,
330 nitems1,
331 ndatabytes1;
332 int *dims2,
333 *lbs2,
334 ndims2,
335 nitems2,
336 ndatabytes2;
337 int i;
338 char *dat1,
339 *dat2;
340 bits8 *bitmap1,
341 *bitmap2;
342 Oid element_type;
343 Oid element_type1;
344 Oid element_type2;
345 int32 dataoffset;
346
347 /* Concatenating a null array is a no-op, just return the other input */
348 if (PG_ARGISNULL(0))
349 {
350 if (PG_ARGISNULL(1))
352 result = PG_GETARG_ARRAYTYPE_P(1);
353 PG_RETURN_ARRAYTYPE_P(result);
354 }
355 if (PG_ARGISNULL(1))
356 {
357 result = PG_GETARG_ARRAYTYPE_P(0);
358 PG_RETURN_ARRAYTYPE_P(result);
359 }
360
361 v1 = PG_GETARG_ARRAYTYPE_P(0);
362 v2 = PG_GETARG_ARRAYTYPE_P(1);
363
364 element_type1 = ARR_ELEMTYPE(v1);
365 element_type2 = ARR_ELEMTYPE(v2);
366
367 /* Check we have matching element types */
368 if (element_type1 != element_type2)
370 (errcode(ERRCODE_DATATYPE_MISMATCH),
371 errmsg("cannot concatenate incompatible arrays"),
372 errdetail("Arrays with element types %s and %s are not "
373 "compatible for concatenation.",
374 format_type_be(element_type1),
375 format_type_be(element_type2))));
376
377 /* OK, use it */
378 element_type = element_type1;
379
380 /*----------
381 * We must have one of the following combinations of inputs:
382 * 1) one empty array, and one non-empty array
383 * 2) both arrays empty
384 * 3) two arrays with ndims1 == ndims2
385 * 4) ndims1 == ndims2 - 1
386 * 5) ndims1 == ndims2 + 1
387 *----------
388 */
389 ndims1 = ARR_NDIM(v1);
390 ndims2 = ARR_NDIM(v2);
391
392 /*
393 * short circuit - if one input array is empty, and the other is not, we
394 * return the non-empty one as the result
395 *
396 * if both are empty, return the first one
397 */
398 if (ndims1 == 0 && ndims2 > 0)
400
401 if (ndims2 == 0)
403
404 /* the rest fall under rule 3, 4, or 5 */
405 if (ndims1 != ndims2 &&
406 ndims1 != ndims2 - 1 &&
407 ndims1 != ndims2 + 1)
409 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
410 errmsg("cannot concatenate incompatible arrays"),
411 errdetail("Arrays of %d and %d dimensions are not "
412 "compatible for concatenation.",
413 ndims1, ndims2)));
414
415 /* get argument array details */
416 lbs1 = ARR_LBOUND(v1);
417 lbs2 = ARR_LBOUND(v2);
418 dims1 = ARR_DIMS(v1);
419 dims2 = ARR_DIMS(v2);
420 dat1 = ARR_DATA_PTR(v1);
421 dat2 = ARR_DATA_PTR(v2);
422 bitmap1 = ARR_NULLBITMAP(v1);
423 bitmap2 = ARR_NULLBITMAP(v2);
424 nitems1 = ArrayGetNItems(ndims1, dims1);
425 nitems2 = ArrayGetNItems(ndims2, dims2);
426 ndatabytes1 = ARR_SIZE(v1) - ARR_DATA_OFFSET(v1);
427 ndatabytes2 = ARR_SIZE(v2) - ARR_DATA_OFFSET(v2);
428
429 if (ndims1 == ndims2)
430 {
431 /*
432 * resulting array is made up of the elements (possibly arrays
433 * themselves) of the input argument arrays
434 */
435 ndims = ndims1;
436 dims = (int *) palloc(ndims * sizeof(int));
437 lbs = (int *) palloc(ndims * sizeof(int));
438
439 dims[0] = dims1[0] + dims2[0];
440 lbs[0] = lbs1[0];
441
442 for (i = 1; i < ndims; i++)
443 {
444 if (dims1[i] != dims2[i] || lbs1[i] != lbs2[i])
446 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
447 errmsg("cannot concatenate incompatible arrays"),
448 errdetail("Arrays with differing element dimensions are "
449 "not compatible for concatenation.")));
450
451 dims[i] = dims1[i];
452 lbs[i] = lbs1[i];
453 }
454 }
455 else if (ndims1 == ndims2 - 1)
456 {
457 /*
458 * resulting array has the second argument as the outer array, with
459 * the first argument inserted at the front of the outer dimension
460 */
461 ndims = ndims2;
462 dims = (int *) palloc(ndims * sizeof(int));
463 lbs = (int *) palloc(ndims * sizeof(int));
464 memcpy(dims, dims2, ndims * sizeof(int));
465 memcpy(lbs, lbs2, ndims * sizeof(int));
466
467 /* increment number of elements in outer array */
468 dims[0] += 1;
469
470 /* make sure the added element matches our existing elements */
471 for (i = 0; i < ndims1; i++)
472 {
473 if (dims1[i] != dims[i + 1] || lbs1[i] != lbs[i + 1])
475 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
476 errmsg("cannot concatenate incompatible arrays"),
477 errdetail("Arrays with differing dimensions are not "
478 "compatible for concatenation.")));
479 }
480 }
481 else
482 {
483 /*
484 * (ndims1 == ndims2 + 1)
485 *
486 * resulting array has the first argument as the outer array, with the
487 * second argument appended to the end of the outer dimension
488 */
489 ndims = ndims1;
490 dims = (int *) palloc(ndims * sizeof(int));
491 lbs = (int *) palloc(ndims * sizeof(int));
492 memcpy(dims, dims1, ndims * sizeof(int));
493 memcpy(lbs, lbs1, ndims * sizeof(int));
494
495 /* increment number of elements in outer array */
496 dims[0] += 1;
497
498 /* make sure the added element matches our existing elements */
499 for (i = 0; i < ndims2; i++)
500 {
501 if (dims2[i] != dims[i + 1] || lbs2[i] != lbs[i + 1])
503 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
504 errmsg("cannot concatenate incompatible arrays"),
505 errdetail("Arrays with differing dimensions are not "
506 "compatible for concatenation.")));
507 }
508 }
509
510 /* Do this mainly for overflow checking */
511 nitems = ArrayGetNItems(ndims, dims);
512 ArrayCheckBounds(ndims, dims, lbs);
513
514 /* build the result array */
515 ndatabytes = ndatabytes1 + ndatabytes2;
516 if (ARR_HASNULL(v1) || ARR_HASNULL(v2))
517 {
518 dataoffset = ARR_OVERHEAD_WITHNULLS(ndims, nitems);
519 nbytes = ndatabytes + dataoffset;
520 }
521 else
522 {
523 dataoffset = 0; /* marker for no null bitmap */
524 nbytes = ndatabytes + ARR_OVERHEAD_NONULLS(ndims);
525 }
526 result = (ArrayType *) palloc0(nbytes);
527 SET_VARSIZE(result, nbytes);
528 result->ndim = ndims;
529 result->dataoffset = dataoffset;
530 result->elemtype = element_type;
531 memcpy(ARR_DIMS(result), dims, ndims * sizeof(int));
532 memcpy(ARR_LBOUND(result), lbs, ndims * sizeof(int));
533 /* data area is arg1 then arg2 */
534 memcpy(ARR_DATA_PTR(result), dat1, ndatabytes1);
535 memcpy(ARR_DATA_PTR(result) + ndatabytes1, dat2, ndatabytes2);
536 /* handle the null bitmap if needed */
537 if (ARR_HASNULL(result))
538 {
540 bitmap1, 0,
541 nitems1);
542 array_bitmap_copy(ARR_NULLBITMAP(result), nitems1,
543 bitmap2, 0,
544 nitems2);
545 }
546
547 PG_RETURN_ARRAYTYPE_P(result);
548}
#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:498
int errdetail(const char *fmt,...)
Definition: elog.c:1204
char * format_type_be(Oid type_oid)
Definition: format_type.c:343
#define nitems(x)
Definition: indent.h:31
void * palloc0(Size size)
Definition: mcxt.c:1975
Oid elemtype
Definition: array.h:97
int ndim
Definition: array.h:95
int32 dataoffset
Definition: array.h:96
#define SET_VARSIZE(PTR, len)
Definition: varatt.h:305

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, nitems, palloc(), palloc0(), PG_ARGISNULL, PG_GETARG_ARRAYTYPE_P, PG_RETURN_ARRAYTYPE_P, PG_RETURN_NULL, and SET_VARSIZE.

◆ array_position()

Datum array_position ( PG_FUNCTION_ARGS  )

Definition at line 1301 of file array_userfuncs.c.

1302{
1303 return array_position_common(fcinfo);
1304}
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 1320 of file array_userfuncs.c.

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

◆ array_position_start()

Datum array_position_start ( PG_FUNCTION_ARGS  )

Definition at line 1307 of file array_userfuncs.c.

1308{
1309 return array_position_common(fcinfo);
1310}

References array_position_common().

◆ array_positions()

Datum array_positions ( PG_FUNCTION_ARGS  )

Definition at line 1475 of file array_userfuncs.c.

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

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(), if(), 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.

◆ array_prepend()

Datum array_prepend ( PG_FUNCTION_ARGS  )

Definition at line 222 of file array_userfuncs.c.

223{
225 Datum newelem;
226 bool isNull;
227 Datum result;
228 int *lb;
229 int indx;
230 int lb0;
231 ArrayMetaState *my_extra;
232
233 isNull = PG_ARGISNULL(0);
234 if (isNull)
235 newelem = (Datum) 0;
236 else
237 newelem = PG_GETARG_DATUM(0);
238 eah = fetch_array_arg_replace_nulls(fcinfo, 1);
239
240 if (eah->ndims == 1)
241 {
242 /* prepend newelem */
243 lb = eah->lbound;
244 lb0 = lb[0];
245
246 if (pg_sub_s32_overflow(lb0, 1, &indx))
248 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
249 errmsg("integer out of range")));
250 }
251 else if (eah->ndims == 0)
252 {
253 indx = 1;
254 lb0 = 1;
255 }
256 else
258 (errcode(ERRCODE_DATA_EXCEPTION),
259 errmsg("argument must be empty or one-dimensional array")));
260
261 /* Perform element insertion */
262 my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra;
263
264 result = array_set_element(EOHPGetRWDatum(&eah->hdr),
265 1, &indx, newelem, isNull,
266 -1, my_extra->typlen, my_extra->typbyval, my_extra->typalign);
267
268 /* Readjust result's LB to match the input's, as expected for prepend */
269 Assert(result == EOHPGetRWDatum(&eah->hdr));
270 if (eah->ndims == 1)
271 {
272 /* This is ok whether we've deconstructed or not */
273 eah->lbound[0] = lb0;
274 }
275
276 PG_RETURN_DATUM(result);
277}
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, 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.

◆ array_prepend_support()

Datum array_prepend_support ( PG_FUNCTION_ARGS  )

Definition at line 285 of file array_userfuncs.c.

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

References arg, SupportRequestModifyInPlace::args, IsA, lsecond, PARAM_EXTERN, SupportRequestModifyInPlace::paramid, PG_GETARG_POINTER, and PG_RETURN_POINTER.

◆ array_reverse()

Datum array_reverse ( PG_FUNCTION_ARGS  )

Definition at line 1850 of file array_userfuncs.c.

1851{
1852 ArrayType *array = PG_GETARG_ARRAYTYPE_P(0);
1853 ArrayType *result;
1854 Oid elmtyp;
1855 TypeCacheEntry *typentry;
1856
1857 /*
1858 * There is no point in reversing empty arrays or arrays with less than
1859 * two items.
1860 */
1861 if (ARR_NDIM(array) < 1 || ARR_DIMS(array)[0] < 2)
1862 PG_RETURN_ARRAYTYPE_P(array);
1863
1864 elmtyp = ARR_ELEMTYPE(array);
1865 typentry = (TypeCacheEntry *) fcinfo->flinfo->fn_extra;
1866 if (typentry == NULL || typentry->type_id != elmtyp)
1867 {
1868 typentry = lookup_type_cache(elmtyp, 0);
1869 fcinfo->flinfo->fn_extra = (void *) typentry;
1870 }
1871
1872 result = array_reverse_n(array, elmtyp, typentry);
1873
1874 PG_RETURN_ARRAYTYPE_P(result);
1875}
static ArrayType * array_reverse_n(ArrayType *array, Oid elmtyp, TypeCacheEntry *typentry)

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

◆ array_reverse_n()

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

Definition at line 1775 of file array_userfuncs.c.

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

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

Referenced by array_reverse().

◆ array_sample()

Datum array_sample ( PG_FUNCTION_ARGS  )

Definition at line 1736 of file array_userfuncs.c.

1737{
1738 ArrayType *array = PG_GETARG_ARRAYTYPE_P(0);
1739 int n = PG_GETARG_INT32(1);
1740 ArrayType *result;
1741 Oid elmtyp;
1742 TypeCacheEntry *typentry;
1743 int nitem;
1744
1745 nitem = (ARR_NDIM(array) < 1) ? 0 : ARR_DIMS(array)[0];
1746
1747 if (n < 0 || n > nitem)
1748 ereport(ERROR,
1749 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1750 errmsg("sample size must be between 0 and %d", nitem)));
1751
1752 elmtyp = ARR_ELEMTYPE(array);
1753 typentry = (TypeCacheEntry *) fcinfo->flinfo->fn_extra;
1754 if (typentry == NULL || typentry->type_id != elmtyp)
1755 {
1756 typentry = lookup_type_cache(elmtyp, 0);
1757 fcinfo->flinfo->fn_extra = typentry;
1758 }
1759
1760 result = array_shuffle_n(array, n, false, elmtyp, typentry);
1761
1762 PG_RETURN_ARRAYTYPE_P(result);
1763}
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, if(), lookup_type_cache(), PG_GETARG_ARRAYTYPE_P, PG_GETARG_INT32, PG_RETURN_ARRAYTYPE_P, and TypeCacheEntry::type_id.

◆ array_shuffle()

Datum array_shuffle ( PG_FUNCTION_ARGS  )

Definition at line 1702 of file array_userfuncs.c.

1703{
1704 ArrayType *array = PG_GETARG_ARRAYTYPE_P(0);
1705 ArrayType *result;
1706 Oid elmtyp;
1707 TypeCacheEntry *typentry;
1708
1709 /*
1710 * There is no point in shuffling empty arrays or arrays with less than
1711 * two items.
1712 */
1713 if (ARR_NDIM(array) < 1 || ARR_DIMS(array)[0] < 2)
1714 PG_RETURN_ARRAYTYPE_P(array);
1715
1716 elmtyp = ARR_ELEMTYPE(array);
1717 typentry = (TypeCacheEntry *) fcinfo->flinfo->fn_extra;
1718 if (typentry == NULL || typentry->type_id != elmtyp)
1719 {
1720 typentry = lookup_type_cache(elmtyp, 0);
1721 fcinfo->flinfo->fn_extra = typentry;
1722 }
1723
1724 result = array_shuffle_n(array, ARR_DIMS(array)[0], true, elmtyp, typentry);
1725
1726 PG_RETURN_ARRAYTYPE_P(result);
1727}

References ARR_DIMS, ARR_ELEMTYPE, ARR_NDIM, array_shuffle_n(), if(), lookup_type_cache(), PG_GETARG_ARRAYTYPE_P, PG_RETURN_ARRAYTYPE_P, 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 1613 of file array_userfuncs.c.

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

2006{
2007 ArrayType *array = PG_GETARG_ARRAYTYPE_P(0);
2008
2010 false,
2011 false,
2012 fcinfo));
2013}
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 1883 of file array_userfuncs.c.

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

2017{
2018 ArrayType *array = PG_GETARG_ARRAYTYPE_P(0);
2019 bool descending = PG_GETARG_BOOL(1);
2020
2022 descending,
2023 descending,
2024 fcinfo));
2025}
#define PG_GETARG_BOOL(n)
Definition: fmgr.h:274

References array_sort_internal(), 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 2028 of file array_userfuncs.c.

2029{
2030 ArrayType *array = PG_GETARG_ARRAYTYPE_P(0);
2031 bool descending = PG_GETARG_BOOL(1);
2032 bool nulls_first = PG_GETARG_BOOL(2);
2033
2035 descending,
2036 nulls_first,
2037 fcinfo));
2038}

References array_sort_internal(), 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 80 of file array_userfuncs.c.

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

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(), if(), InvalidOid, MemoryContextAlloc(), MemoryContextSwitchTo(), OidIsValid, PG_ARGISNULL, and PG_GETARG_EXPANDED_ARRAYX.

Referenced by array_append(), and array_prepend().