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_type.h"
#include "common/int.h"
#include "common/pg_prng.h"
#include "libpq/pqformat.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/typcache.h"
Include dependency graph for array_userfuncs.c:

Go to the source code of this file.

Data Structures

struct  SerialIOData
 
struct  DeserialIOData
 

Typedefs

typedef struct SerialIOData SerialIOData
 
typedef struct DeserialIOData DeserialIOData
 

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)
 

Typedef Documentation

◆ DeserialIOData

◆ SerialIOData

typedef struct SerialIOData SerialIOData

Function Documentation

◆ array_agg_array_combine()

Datum array_agg_array_combine ( PG_FUNCTION_ARGS  )

Definition at line 962 of file array_userfuncs.c.

963{
964 ArrayBuildStateArr *state1;
965 ArrayBuildStateArr *state2;
966 MemoryContext agg_context;
967 MemoryContext old_context;
968
969 if (!AggCheckCallContext(fcinfo, &agg_context))
970 elog(ERROR, "aggregate function called in non-aggregate context");
971
972 state1 = PG_ARGISNULL(0) ? NULL : (ArrayBuildStateArr *) PG_GETARG_POINTER(0);
973 state2 = PG_ARGISNULL(1) ? NULL : (ArrayBuildStateArr *) PG_GETARG_POINTER(1);
974
975 if (state2 == NULL)
976 {
977 /*
978 * NULL state2 is easy, just return state1, which we know is already
979 * in the agg_context
980 */
981 if (state1 == NULL)
983 PG_RETURN_POINTER(state1);
984 }
985
986 if (state1 == NULL)
987 {
988 /* We must copy state2's data into the agg_context */
989 old_context = MemoryContextSwitchTo(agg_context);
990
991 state1 = initArrayResultArr(state2->array_type, InvalidOid,
992 agg_context, false);
993
994 state1->abytes = state2->abytes;
995 state1->data = (char *) palloc(state1->abytes);
996
997 if (state2->nullbitmap)
998 {
999 int size = (state2->aitems + 7) / 8;
1000
1001 state1->nullbitmap = (bits8 *) palloc(size);
1002 memcpy(state1->nullbitmap, state2->nullbitmap, size);
1003 }
1004
1005 memcpy(state1->data, state2->data, state2->nbytes);
1006 state1->nbytes = state2->nbytes;
1007 state1->aitems = state2->aitems;
1008 state1->nitems = state2->nitems;
1009 state1->ndims = state2->ndims;
1010 memcpy(state1->dims, state2->dims, sizeof(state2->dims));
1011 memcpy(state1->lbs, state2->lbs, sizeof(state2->lbs));
1012 state1->array_type = state2->array_type;
1013 state1->element_type = state2->element_type;
1014
1015 MemoryContextSwitchTo(old_context);
1016
1017 PG_RETURN_POINTER(state1);
1018 }
1019
1020 /* We only need to combine the two states if state2 has any items */
1021 else if (state2->nitems > 0)
1022 {
1023 MemoryContext oldContext;
1024 int reqsize = state1->nbytes + state2->nbytes;
1025 int i;
1026
1027 /*
1028 * Check the states are compatible with each other. Ensure we use the
1029 * same error messages that are listed in accumArrayResultArr so that
1030 * the same error is shown as would have been if we'd not used the
1031 * combine function for the aggregation.
1032 */
1033 if (state1->ndims != state2->ndims)
1034 ereport(ERROR,
1035 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
1036 errmsg("cannot accumulate arrays of different dimensionality")));
1037
1038 /* Check dimensions match ignoring the first dimension. */
1039 for (i = 1; i < state1->ndims; i++)
1040 {
1041 if (state1->dims[i] != state2->dims[i] || state1->lbs[i] != state2->lbs[i])
1042 ereport(ERROR,
1043 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
1044 errmsg("cannot accumulate arrays of different dimensionality")));
1045 }
1046
1047
1048 oldContext = MemoryContextSwitchTo(state1->mcontext);
1049
1050 /*
1051 * If there's not enough space in state1 then we'll need to reallocate
1052 * more.
1053 */
1054 if (state1->abytes < reqsize)
1055 {
1056 /* use a power of 2 size rather than allocating just reqsize */
1057 state1->abytes = pg_nextpower2_32(reqsize);
1058 state1->data = (char *) repalloc(state1->data, state1->abytes);
1059 }
1060
1061 if (state2->nullbitmap)
1062 {
1063 int newnitems = state1->nitems + state2->nitems;
1064
1065 if (state1->nullbitmap == NULL)
1066 {
1067 /*
1068 * First input with nulls; we must retrospectively handle any
1069 * previous inputs by marking all their items non-null.
1070 */
1071 state1->aitems = pg_nextpower2_32(Max(256, newnitems + 1));
1072 state1->nullbitmap = (bits8 *) palloc((state1->aitems + 7) / 8);
1073 array_bitmap_copy(state1->nullbitmap, 0,
1074 NULL, 0,
1075 state1->nitems);
1076 }
1077 else if (newnitems > state1->aitems)
1078 {
1079 int newaitems = state1->aitems + state2->aitems;
1080
1081 state1->aitems = pg_nextpower2_32(newaitems);
1082 state1->nullbitmap = (bits8 *)
1083 repalloc(state1->nullbitmap, (state1->aitems + 7) / 8);
1084 }
1085 array_bitmap_copy(state1->nullbitmap, state1->nitems,
1086 state2->nullbitmap, 0,
1087 state2->nitems);
1088 }
1089
1090 memcpy(state1->data + state1->nbytes, state2->data, state2->nbytes);
1091 state1->nbytes += state2->nbytes;
1092 state1->nitems += state2->nitems;
1093
1094 state1->dims[0] += state2->dims[0];
1095 /* remaining dims already match, per test above */
1096
1097 Assert(state1->array_type == state2->array_type);
1098 Assert(state1->element_type == state2->element_type);
1099
1100 MemoryContextSwitchTo(oldContext);
1101 }
1102
1103 PG_RETURN_POINTER(state1);
1104}
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:853
int errmsg(const char *fmt,...)
Definition: elog.c:1070
#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:1544
void * palloc(Size size)
Definition: mcxt.c:1317
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 1170 of file array_userfuncs.c.

1171{
1172 bytea *sstate;
1173 ArrayBuildStateArr *result;
1175 Oid element_type;
1176 Oid array_type;
1177 int nbytes;
1178 const char *temp;
1179
1180 /* cannot be called directly because of internal-type argument */
1181 Assert(AggCheckCallContext(fcinfo, NULL));
1182
1183 sstate = PG_GETARG_BYTEA_PP(0);
1184
1185 /*
1186 * Initialize a StringInfo so that we can "receive" it using the standard
1187 * recv-function infrastructure.
1188 */
1190 VARSIZE_ANY_EXHDR(sstate));
1191
1192 /* element_type */
1193 element_type = pq_getmsgint(&buf, 4);
1194
1195 /* array_type */
1196 array_type = pq_getmsgint(&buf, 4);
1197
1198 /* nbytes */
1199 nbytes = pq_getmsgint(&buf, 4);
1200
1201 result = initArrayResultArr(array_type, element_type,
1202 CurrentMemoryContext, false);
1203
1204 result->abytes = 1024;
1205 while (result->abytes < nbytes)
1206 result->abytes *= 2;
1207
1208 result->data = (char *) palloc(result->abytes);
1209
1210 /* data */
1211 temp = pq_getmsgbytes(&buf, nbytes);
1212 memcpy(result->data, temp, nbytes);
1213 result->nbytes = nbytes;
1214
1215 /* abytes */
1216 result->abytes = pq_getmsgint(&buf, 4);
1217
1218 /* aitems: might be 0 */
1219 result->aitems = pq_getmsgint(&buf, 4);
1220
1221 /* nullbitmap */
1222 if (result->aitems > 0)
1223 {
1224 int size = (result->aitems + 7) / 8;
1225
1226 result->nullbitmap = (bits8 *) palloc(size);
1227 temp = pq_getmsgbytes(&buf, size);
1228 memcpy(result->nullbitmap, temp, size);
1229 }
1230 else
1231 result->nullbitmap = NULL;
1232
1233 /* nitems */
1234 result->nitems = pq_getmsgint(&buf, 4);
1235
1236 /* ndims */
1237 result->ndims = pq_getmsgint(&buf, 4);
1238
1239 /* dims */
1240 temp = pq_getmsgbytes(&buf, sizeof(result->dims));
1241 memcpy(result->dims, temp, sizeof(result->dims));
1242
1243 /* lbs */
1244 temp = pq_getmsgbytes(&buf, sizeof(result->lbs));
1245 memcpy(result->lbs, temp, sizeof(result->lbs));
1246
1247 pq_getmsgend(&buf);
1248
1249 PG_RETURN_POINTER(result);
1250}
#define PG_GETARG_BYTEA_PP(n)
Definition: fmgr.h:308
MemoryContext CurrentMemoryContext
Definition: mcxt.c:143
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 1253 of file array_userfuncs.c.

1254{
1255 Datum result;
1257
1258 /* cannot be called directly because of internal-type argument */
1259 Assert(AggCheckCallContext(fcinfo, NULL));
1260
1262
1263 if (state == NULL)
1264 PG_RETURN_NULL(); /* returns null iff no input values */
1265
1266 /*
1267 * Make the result. We cannot release the ArrayBuildStateArr because
1268 * sometimes aggregate final functions are re-executed. Rather, it is
1269 * nodeAgg.c's responsibility to reset the aggcontext when it's safe to do
1270 * so.
1271 */
1273
1274 PG_RETURN_DATUM(result);
1275}
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 1111 of file array_userfuncs.c.

1112{
1115 bytea *result;
1116
1117 /* cannot be called directly because of internal-type argument */
1118 Assert(AggCheckCallContext(fcinfo, NULL));
1119
1121
1123
1124 /*
1125 * element_type. Putting this first is more convenient in deserialization
1126 * so that we can init the new state sooner.
1127 */
1128 pq_sendint32(&buf, state->element_type);
1129
1130 /* array_type */
1131 pq_sendint32(&buf, state->array_type);
1132
1133 /* nbytes */
1134 pq_sendint32(&buf, state->nbytes);
1135
1136 /* data */
1137 pq_sendbytes(&buf, state->data, state->nbytes);
1138
1139 /* abytes */
1140 pq_sendint32(&buf, state->abytes);
1141
1142 /* aitems */
1143 pq_sendint32(&buf, state->aitems);
1144
1145 /* nullbitmap */
1146 if (state->nullbitmap)
1147 {
1148 Assert(state->aitems > 0);
1149 pq_sendbytes(&buf, state->nullbitmap, (state->aitems + 7) / 8);
1150 }
1151
1152 /* nitems */
1153 pq_sendint32(&buf, state->nitems);
1154
1155 /* ndims */
1156 pq_sendint32(&buf, state->ndims);
1157
1158 /* dims: XXX should we just send ndims elements? */
1159 pq_sendbytes(&buf, state->dims, sizeof(state->dims));
1160
1161 /* lbs */
1162 pq_sendbytes(&buf, state->lbs, sizeof(state->lbs));
1163
1164 result = pq_endtypsend(&buf);
1165
1166 PG_RETURN_BYTEA_P(result);
1167}
#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 918 of file array_userfuncs.c.

919{
920 Oid arg1_typeid = get_fn_expr_argtype(fcinfo->flinfo, 1);
921 MemoryContext aggcontext;
923
924 if (arg1_typeid == InvalidOid)
926 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
927 errmsg("could not determine input data type")));
928
929 /*
930 * Note: we do not need a run-time check about whether arg1_typeid is a
931 * valid array type, because the parser would have verified that while
932 * resolving the input/result types of this polymorphic aggregate.
933 */
934
935 if (!AggCheckCallContext(fcinfo, &aggcontext))
936 {
937 /* cannot be called directly because of internal-type argument */
938 elog(ERROR, "array_agg_array_transfn called in non-aggregate context");
939 }
940
941
942 if (PG_ARGISNULL(0))
943 state = initArrayResultArr(arg1_typeid, InvalidOid, aggcontext, false);
944 else
946
949 PG_ARGISNULL(1),
950 arg1_typeid,
951 aggcontext);
952
953 /*
954 * The transition type for array_agg() is declared to be "internal", which
955 * is a pass-by-value type the same size as a pointer. So we can safely
956 * pass the ArrayBuildStateArr pointer through nodeAgg.c's machinations.
957 */
959}
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 586 of file array_userfuncs.c.

587{
588 ArrayBuildState *state1;
589 ArrayBuildState *state2;
590 MemoryContext agg_context;
591 MemoryContext old_context;
592
593 if (!AggCheckCallContext(fcinfo, &agg_context))
594 elog(ERROR, "aggregate function called in non-aggregate context");
595
596 state1 = PG_ARGISNULL(0) ? NULL : (ArrayBuildState *) PG_GETARG_POINTER(0);
597 state2 = PG_ARGISNULL(1) ? NULL : (ArrayBuildState *) PG_GETARG_POINTER(1);
598
599 if (state2 == NULL)
600 {
601 /*
602 * NULL state2 is easy, just return state1, which we know is already
603 * in the agg_context
604 */
605 if (state1 == NULL)
607 PG_RETURN_POINTER(state1);
608 }
609
610 if (state1 == NULL)
611 {
612 /* We must copy state2's data into the agg_context */
613 state1 = initArrayResultWithSize(state2->element_type, agg_context,
614 false, state2->alen);
615
616 old_context = MemoryContextSwitchTo(agg_context);
617
618 for (int i = 0; i < state2->nelems; i++)
619 {
620 if (!state2->dnulls[i])
621 state1->dvalues[i] = datumCopy(state2->dvalues[i],
622 state1->typbyval,
623 state1->typlen);
624 else
625 state1->dvalues[i] = (Datum) 0;
626 }
627
628 MemoryContextSwitchTo(old_context);
629
630 memcpy(state1->dnulls, state2->dnulls, sizeof(bool) * state2->nelems);
631
632 state1->nelems = state2->nelems;
633
634 PG_RETURN_POINTER(state1);
635 }
636 else if (state2->nelems > 0)
637 {
638 /* We only need to combine the two states if state2 has any elements */
639 int reqsize = state1->nelems + state2->nelems;
640 MemoryContext oldContext = MemoryContextSwitchTo(state1->mcontext);
641
642 Assert(state1->element_type == state2->element_type);
643
644 /* Enlarge state1 arrays if needed */
645 if (state1->alen < reqsize)
646 {
647 /* Use a power of 2 size rather than allocating just reqsize */
648 state1->alen = pg_nextpower2_32(reqsize);
649 state1->dvalues = (Datum *) repalloc(state1->dvalues,
650 state1->alen * sizeof(Datum));
651 state1->dnulls = (bool *) repalloc(state1->dnulls,
652 state1->alen * sizeof(bool));
653 }
654
655 /* Copy in the state2 elements to the end of the state1 arrays */
656 for (int i = 0; i < state2->nelems; i++)
657 {
658 if (!state2->dnulls[i])
659 state1->dvalues[i + state1->nelems] =
660 datumCopy(state2->dvalues[i],
661 state1->typbyval,
662 state1->typlen);
663 else
664 state1->dvalues[i + state1->nelems] = (Datum) 0;
665 }
666
667 memcpy(&state1->dnulls[state1->nelems], state2->dnulls,
668 sizeof(bool) * state2->nelems);
669
670 state1->nelems = reqsize;
671
672 MemoryContextSwitchTo(oldContext);
673 }
674
675 PG_RETURN_POINTER(state1);
676}
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 772 of file array_userfuncs.c.

773{
774 bytea *sstate;
775 ArrayBuildState *result;
777 Oid element_type;
778 int64 nelems;
779 const char *temp;
780
781 if (!AggCheckCallContext(fcinfo, NULL))
782 elog(ERROR, "aggregate function called in non-aggregate context");
783
784 sstate = PG_GETARG_BYTEA_PP(0);
785
786 /*
787 * Initialize a StringInfo so that we can "receive" it using the standard
788 * recv-function infrastructure.
789 */
791 VARSIZE_ANY_EXHDR(sstate));
792
793 /* element_type */
794 element_type = pq_getmsgint(&buf, 4);
795
796 /* nelems */
797 nelems = pq_getmsgint64(&buf);
798
799 /* Create output ArrayBuildState with the needed number of elements */
800 result = initArrayResultWithSize(element_type, CurrentMemoryContext,
801 false, nelems);
802 result->nelems = nelems;
803
804 /* typlen */
805 result->typlen = pq_getmsgint(&buf, 2);
806
807 /* typbyval */
808 result->typbyval = pq_getmsgbyte(&buf);
809
810 /* typalign */
811 result->typalign = pq_getmsgbyte(&buf);
812
813 /* dnulls */
814 temp = pq_getmsgbytes(&buf, sizeof(bool) * nelems);
815 memcpy(result->dnulls, temp, sizeof(bool) * nelems);
816
817 /* dvalues --- see comment in array_agg_serialize */
818 if (result->typbyval)
819 {
820 temp = pq_getmsgbytes(&buf, sizeof(Datum) * nelems);
821 memcpy(result->dvalues, temp, sizeof(Datum) * nelems);
822 }
823 else
824 {
825 DeserialIOData *iodata;
826
827 /* Avoid repeat catalog lookups for typreceive function */
828 iodata = (DeserialIOData *) fcinfo->flinfo->fn_extra;
829 if (iodata == NULL)
830 {
831 Oid typreceive;
832
833 iodata = (DeserialIOData *)
834 MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
835 sizeof(DeserialIOData));
836 getTypeBinaryInputInfo(element_type, &typreceive,
837 &iodata->typioparam);
838 fmgr_info_cxt(typreceive, &iodata->typreceive,
839 fcinfo->flinfo->fn_mcxt);
840 fcinfo->flinfo->fn_extra = iodata;
841 }
842
843 for (int i = 0; i < nelems; i++)
844 {
845 int itemlen;
846 StringInfoData elem_buf;
847
848 if (result->dnulls[i])
849 {
850 result->dvalues[i] = (Datum) 0;
851 continue;
852 }
853
854 itemlen = pq_getmsgint(&buf, 4);
855 if (itemlen < 0 || itemlen > (buf.len - buf.cursor))
857 (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
858 errmsg("insufficient data left in message")));
859
860 /*
861 * Rather than copying data around, we just initialize a
862 * StringInfo pointing to the correct portion of the message
863 * buffer.
864 */
865 initReadOnlyStringInfo(&elem_buf, &buf.data[buf.cursor], itemlen);
866
867 buf.cursor += itemlen;
868
869 /* Now call the element's receiveproc */
870 result->dvalues[i] = ReceiveFunctionCall(&iodata->typreceive,
871 &elem_buf,
872 iodata->typioparam,
873 -1);
874 }
875 }
876
878
879 PG_RETURN_POINTER(result);
880}
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:3023
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:1181
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 883 of file array_userfuncs.c.

884{
885 Datum result;
887 int dims[1];
888 int lbs[1];
889
890 /* cannot be called directly because of internal-type argument */
891 Assert(AggCheckCallContext(fcinfo, NULL));
892
894
895 if (state == NULL)
896 PG_RETURN_NULL(); /* returns null iff no input values */
897
898 dims[0] = state->nelems;
899 lbs[0] = 1;
900
901 /*
902 * Make the result. We cannot release the ArrayBuildState because
903 * sometimes aggregate final functions are re-executed. Rather, it is
904 * nodeAgg.c's responsibility to reset the aggcontext when it's safe to do
905 * so.
906 */
907 result = makeMdArrayResult(state, 1, dims, lbs,
909 false);
910
911 PG_RETURN_DATUM(result);
912}
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 683 of file array_userfuncs.c.

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

541{
542 Oid arg1_typeid = get_fn_expr_argtype(fcinfo->flinfo, 1);
543 MemoryContext aggcontext;
545 Datum elem;
546
547 if (arg1_typeid == InvalidOid)
549 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
550 errmsg("could not determine input data type")));
551
552 /*
553 * Note: we do not need a run-time check about whether arg1_typeid is a
554 * valid array element type, because the parser would have verified that
555 * while resolving the input/result types of this polymorphic aggregate.
556 */
557
558 if (!AggCheckCallContext(fcinfo, &aggcontext))
559 {
560 /* cannot be called directly because of internal-type argument */
561 elog(ERROR, "array_agg_transfn called in non-aggregate context");
562 }
563
564 if (PG_ARGISNULL(0))
565 state = initArrayResult(arg1_typeid, aggcontext, false);
566 else
568
569 elem = PG_ARGISNULL(1) ? (Datum) 0 : PG_GETARG_DATUM(1);
570
572 elem,
573 PG_ARGISNULL(1),
574 arg1_typeid,
575 aggcontext);
576
577 /*
578 * The transition type for array_agg() is declared to be "internal", which
579 * is a pass-by-value type the same size as a pointer. So we can safely
580 * pass the ArrayBuildState pointer through nodeAgg.c's machinations.
581 */
583}
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 124 of file array_userfuncs.c.

125{
127 Datum newelem;
128 bool isNull;
129 Datum result;
130 int *dimv,
131 *lb;
132 int indx;
133 ArrayMetaState *my_extra;
134
135 eah = fetch_array_arg_replace_nulls(fcinfo, 0);
136 isNull = PG_ARGISNULL(1);
137 if (isNull)
138 newelem = (Datum) 0;
139 else
140 newelem = PG_GETARG_DATUM(1);
141
142 if (eah->ndims == 1)
143 {
144 /* append newelem */
145 lb = eah->lbound;
146 dimv = eah->dims;
147
148 /* index of added elem is at lb[0] + (dimv[0] - 1) + 1 */
149 if (pg_add_s32_overflow(lb[0], dimv[0], &indx))
151 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
152 errmsg("integer out of range")));
153 }
154 else if (eah->ndims == 0)
155 indx = 1;
156 else
158 (errcode(ERRCODE_DATA_EXCEPTION),
159 errmsg("argument must be empty or one-dimensional array")));
160
161 /* Perform element insertion */
162 my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra;
163
164 result = array_set_element(EOHPGetRWDatum(&eah->hdr),
165 1, &indx, newelem, isNull,
166 -1, my_extra->typlen, my_extra->typbyval, my_extra->typalign);
167
168 PG_RETURN_DATUM(result);
169}
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 177 of file array_userfuncs.c.

178{
179 Node *rawreq = (Node *) PG_GETARG_POINTER(0);
180 Node *ret = NULL;
181
182 if (IsA(rawreq, SupportRequestModifyInPlace))
183 {
184 /*
185 * We can optimize in-place appends if the function's array argument
186 * is the array being assigned to. We don't need to worry about array
187 * references within the other argument.
188 */
190 Param *arg = (Param *) linitial(req->args);
191
192 if (arg && IsA(arg, Param) &&
193 arg->paramkind == PARAM_EXTERN &&
194 arg->paramid == req->paramid)
195 ret = (Node *) arg;
196 }
197
199}
#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 301 of file array_userfuncs.c.

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

1287{
1288 return array_position_common(fcinfo);
1289}
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 1305 of file array_userfuncs.c.

1306{
1307 ArrayType *array;
1308 Oid collation = PG_GET_COLLATION();
1309 Oid element_type;
1310 Datum searched_element,
1311 value;
1312 bool isnull;
1313 int position,
1314 position_min;
1315 bool found = false;
1316 TypeCacheEntry *typentry;
1317 ArrayMetaState *my_extra;
1318 bool null_search;
1320
1321 if (PG_ARGISNULL(0))
1323
1324 array = PG_GETARG_ARRAYTYPE_P(0);
1325
1326 /*
1327 * We refuse to search for elements in multi-dimensional arrays, since we
1328 * have no good way to report the element's location in the array.
1329 */
1330 if (ARR_NDIM(array) > 1)
1331 ereport(ERROR,
1332 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1333 errmsg("searching for elements in multidimensional arrays is not supported")));
1334
1335 /* Searching in an empty array is well-defined, though: it always fails */
1336 if (ARR_NDIM(array) < 1)
1338
1339 if (PG_ARGISNULL(1))
1340 {
1341 /* fast return when the array doesn't have nulls */
1342 if (!array_contains_nulls(array))
1344 searched_element = (Datum) 0;
1345 null_search = true;
1346 }
1347 else
1348 {
1349 searched_element = PG_GETARG_DATUM(1);
1350 null_search = false;
1351 }
1352
1353 element_type = ARR_ELEMTYPE(array);
1354 position = (ARR_LBOUND(array))[0] - 1;
1355
1356 /* figure out where to start */
1357 if (PG_NARGS() == 3)
1358 {
1359 if (PG_ARGISNULL(2))
1360 ereport(ERROR,
1361 (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
1362 errmsg("initial position must not be null")));
1363
1364 position_min = PG_GETARG_INT32(2);
1365 }
1366 else
1367 position_min = (ARR_LBOUND(array))[0];
1368
1369 /*
1370 * We arrange to look up type info for array_create_iterator only once per
1371 * series of calls, assuming the element type doesn't change underneath
1372 * us.
1373 */
1374 my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra;
1375 if (my_extra == NULL)
1376 {
1377 fcinfo->flinfo->fn_extra = MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
1378 sizeof(ArrayMetaState));
1379 my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra;
1380 my_extra->element_type = ~element_type;
1381 }
1382
1383 if (my_extra->element_type != element_type)
1384 {
1385 get_typlenbyvalalign(element_type,
1386 &my_extra->typlen,
1387 &my_extra->typbyval,
1388 &my_extra->typalign);
1389
1390 typentry = lookup_type_cache(element_type, TYPECACHE_EQ_OPR_FINFO);
1391
1392 if (!OidIsValid(typentry->eq_opr_finfo.fn_oid))
1393 ereport(ERROR,
1394 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1395 errmsg("could not identify an equality operator for type %s",
1396 format_type_be(element_type))));
1397
1398 my_extra->element_type = element_type;
1399 fmgr_info_cxt(typentry->eq_opr_finfo.fn_oid, &my_extra->proc,
1400 fcinfo->flinfo->fn_mcxt);
1401 }
1402
1403 /* Examine each array element until we find a match. */
1404 array_iterator = array_create_iterator(array, 0, my_extra);
1405 while (array_iterate(array_iterator, &value, &isnull))
1406 {
1407 position++;
1408
1409 /* skip initial elements if caller requested so */
1410 if (position < position_min)
1411 continue;
1412
1413 /*
1414 * Can't look at the array element's value if it's null; but if we
1415 * search for null, we have a hit and are done.
1416 */
1417 if (isnull || null_search)
1418 {
1419 if (isnull && null_search)
1420 {
1421 found = true;
1422 break;
1423 }
1424 else
1425 continue;
1426 }
1427
1428 /* not nulls, so run the operator */
1429 if (DatumGetBool(FunctionCall2Coll(&my_extra->proc, collation,
1430 searched_element, value)))
1431 {
1432 found = true;
1433 break;
1434 }
1435 }
1436
1438
1439 /* Avoid leaking memory when handed toasted input */
1440 PG_FREE_IF_COPY(array, 0);
1441
1442 if (!found)
1444
1445 PG_RETURN_INT32(position);
1446}
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:2354
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:75
TypeCacheEntry * lookup_type_cache(Oid type_id, int flags)
Definition: typcache.c:386
#define TYPECACHE_EQ_OPR_FINFO
Definition: typcache.h:142

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 1292 of file array_userfuncs.c.

1293{
1294 return array_position_common(fcinfo);
1295}

References array_position_common().

◆ array_positions()

Datum array_positions ( PG_FUNCTION_ARGS  )

Definition at line 1460 of file array_userfuncs.c.

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

208{
210 Datum newelem;
211 bool isNull;
212 Datum result;
213 int *lb;
214 int indx;
215 int lb0;
216 ArrayMetaState *my_extra;
217
218 isNull = PG_ARGISNULL(0);
219 if (isNull)
220 newelem = (Datum) 0;
221 else
222 newelem = PG_GETARG_DATUM(0);
223 eah = fetch_array_arg_replace_nulls(fcinfo, 1);
224
225 if (eah->ndims == 1)
226 {
227 /* prepend newelem */
228 lb = eah->lbound;
229 lb0 = lb[0];
230
231 if (pg_sub_s32_overflow(lb0, 1, &indx))
233 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
234 errmsg("integer out of range")));
235 }
236 else if (eah->ndims == 0)
237 {
238 indx = 1;
239 lb0 = 1;
240 }
241 else
243 (errcode(ERRCODE_DATA_EXCEPTION),
244 errmsg("argument must be empty or one-dimensional array")));
245
246 /* Perform element insertion */
247 my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra;
248
249 result = array_set_element(EOHPGetRWDatum(&eah->hdr),
250 1, &indx, newelem, isNull,
251 -1, my_extra->typlen, my_extra->typbyval, my_extra->typalign);
252
253 /* Readjust result's LB to match the input's, as expected for prepend */
254 Assert(result == EOHPGetRWDatum(&eah->hdr));
255 if (eah->ndims == 1)
256 {
257 /* This is ok whether we've deconstructed or not */
258 eah->lbound[0] = lb0;
259 }
260
261 PG_RETURN_DATUM(result);
262}
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 270 of file array_userfuncs.c.

271{
272 Node *rawreq = (Node *) PG_GETARG_POINTER(0);
273 Node *ret = NULL;
274
275 if (IsA(rawreq, SupportRequestModifyInPlace))
276 {
277 /*
278 * We can optimize in-place prepends if the function's array argument
279 * is the array being assigned to. We don't need to worry about array
280 * references within the other argument.
281 */
283 Param *arg = (Param *) lsecond(req->args);
284
285 if (arg && IsA(arg, Param) &&
286 arg->paramkind == PARAM_EXTERN &&
287 arg->paramid == req->paramid)
288 ret = (Node *) arg;
289 }
290
292}
#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 1835 of file array_userfuncs.c.

1836{
1837 ArrayType *array = PG_GETARG_ARRAYTYPE_P(0);
1838 ArrayType *result;
1839 Oid elmtyp;
1840 TypeCacheEntry *typentry;
1841
1842 /*
1843 * There is no point in reversing empty arrays or arrays with less than
1844 * two items.
1845 */
1846 if (ARR_NDIM(array) < 1 || ARR_DIMS(array)[0] < 2)
1847 PG_RETURN_ARRAYTYPE_P(array);
1848
1849 elmtyp = ARR_ELEMTYPE(array);
1850 typentry = (TypeCacheEntry *) fcinfo->flinfo->fn_extra;
1851 if (typentry == NULL || typentry->type_id != elmtyp)
1852 {
1853 typentry = lookup_type_cache(elmtyp, 0);
1854 fcinfo->flinfo->fn_extra = (void *) typentry;
1855 }
1856
1857 result = array_reverse_n(array, elmtyp, typentry);
1858
1859 PG_RETURN_ARRAYTYPE_P(result);
1860}
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 1760 of file array_userfuncs.c.

1761{
1762 ArrayType *result;
1763 int ndim,
1764 *dims,
1765 *lbs,
1766 nelm,
1767 nitem,
1768 rdims[MAXDIM],
1769 rlbs[MAXDIM];
1770 int16 elmlen;
1771 bool elmbyval;
1772 char elmalign;
1773 Datum *elms,
1774 *ielms;
1775 bool *nuls,
1776 *inuls;
1777
1778 ndim = ARR_NDIM(array);
1779 dims = ARR_DIMS(array);
1780 lbs = ARR_LBOUND(array);
1781
1782 elmlen = typentry->typlen;
1783 elmbyval = typentry->typbyval;
1784 elmalign = typentry->typalign;
1785
1786 deconstruct_array(array, elmtyp, elmlen, elmbyval, elmalign,
1787 &elms, &nuls, &nelm);
1788
1789 nitem = dims[0]; /* total number of items */
1790 nelm /= nitem; /* number of elements per item */
1791
1792 /* Reverse the array */
1793 ielms = elms;
1794 inuls = nuls;
1795 for (int i = 0; i < nitem / 2; i++)
1796 {
1797 int j = (nitem - i - 1) * nelm;
1798 Datum *jelms = elms + j;
1799 bool *jnuls = nuls + j;
1800
1801 /* Swap i'th and j'th items; advance ielms/inuls to next item */
1802 for (int k = 0; k < nelm; k++)
1803 {
1804 Datum elm = *ielms;
1805 bool nul = *inuls;
1806
1807 *ielms++ = *jelms;
1808 *inuls++ = *jnuls;
1809 *jelms++ = elm;
1810 *jnuls++ = nul;
1811 }
1812 }
1813
1814 /* Set up dimensions of the result */
1815 memcpy(rdims, dims, ndim * sizeof(int));
1816 memcpy(rlbs, lbs, ndim * sizeof(int));
1817 rdims[0] = nitem;
1818
1819 result = construct_md_array(elms, nuls, ndim, rdims, rlbs,
1820 elmtyp, elmlen, elmbyval, elmalign);
1821
1822 pfree(elms);
1823 pfree(nuls);
1824
1825 return result;
1826}
#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:1524
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 1721 of file array_userfuncs.c.

1722{
1723 ArrayType *array = PG_GETARG_ARRAYTYPE_P(0);
1724 int n = PG_GETARG_INT32(1);
1725 ArrayType *result;
1726 Oid elmtyp;
1727 TypeCacheEntry *typentry;
1728 int nitem;
1729
1730 nitem = (ARR_NDIM(array) < 1) ? 0 : ARR_DIMS(array)[0];
1731
1732 if (n < 0 || n > nitem)
1733 ereport(ERROR,
1734 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1735 errmsg("sample size must be between 0 and %d", nitem)));
1736
1737 elmtyp = ARR_ELEMTYPE(array);
1738 typentry = (TypeCacheEntry *) fcinfo->flinfo->fn_extra;
1739 if (typentry == NULL || typentry->type_id != elmtyp)
1740 {
1741 typentry = lookup_type_cache(elmtyp, 0);
1742 fcinfo->flinfo->fn_extra = typentry;
1743 }
1744
1745 result = array_shuffle_n(array, n, false, elmtyp, typentry);
1746
1747 PG_RETURN_ARRAYTYPE_P(result);
1748}
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 1687 of file array_userfuncs.c.

1688{
1689 ArrayType *array = PG_GETARG_ARRAYTYPE_P(0);
1690 ArrayType *result;
1691 Oid elmtyp;
1692 TypeCacheEntry *typentry;
1693
1694 /*
1695 * There is no point in shuffling empty arrays or arrays with less than
1696 * two items.
1697 */
1698 if (ARR_NDIM(array) < 1 || ARR_DIMS(array)[0] < 2)
1699 PG_RETURN_ARRAYTYPE_P(array);
1700
1701 elmtyp = ARR_ELEMTYPE(array);
1702 typentry = (TypeCacheEntry *) fcinfo->flinfo->fn_extra;
1703 if (typentry == NULL || typentry->type_id != elmtyp)
1704 {
1705 typentry = lookup_type_cache(elmtyp, 0);
1706 fcinfo->flinfo->fn_extra = typentry;
1707 }
1708
1709 result = array_shuffle_n(array, ARR_DIMS(array)[0], true, elmtyp, typentry);
1710
1711 PG_RETURN_ARRAYTYPE_P(result);
1712}

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 1598 of file array_userfuncs.c.

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

◆ fetch_array_arg_replace_nulls()

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

Definition at line 65 of file array_userfuncs.c.

66{
68 Oid element_type;
69 ArrayMetaState *my_extra;
70 MemoryContext resultcxt;
71
72 /* If first time through, create datatype cache struct */
73 my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra;
74 if (my_extra == NULL)
75 {
76 my_extra = (ArrayMetaState *)
78 sizeof(ArrayMetaState));
79 my_extra->element_type = InvalidOid;
80 fcinfo->flinfo->fn_extra = my_extra;
81 }
82
83 /* Figure out which context we want the result in */
84 if (!AggCheckCallContext(fcinfo, &resultcxt))
85 resultcxt = CurrentMemoryContext;
86
87 /* Now collect the array value */
88 if (!PG_ARGISNULL(argno))
89 {
90 MemoryContext oldcxt = MemoryContextSwitchTo(resultcxt);
91
92 eah = PG_GETARG_EXPANDED_ARRAYX(argno, my_extra);
94 }
95 else
96 {
97 /* We have to look up the array type and element type */
98 Oid arr_typeid = get_fn_expr_argtype(fcinfo->flinfo, argno);
99
100 if (!OidIsValid(arr_typeid))
102 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
103 errmsg("could not determine input data type")));
104 element_type = get_element_type(arr_typeid);
105 if (!OidIsValid(element_type))
107 (errcode(ERRCODE_DATATYPE_MISMATCH),
108 errmsg("input data type is not an array")));
109
110 eah = construct_empty_expanded_array(element_type,
111 resultcxt,
112 my_extra);
113 }
114
115 return eah;
116}
#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:2842

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