00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include "postgres.h"
00016
00017 #include <ctype.h>
00018
00019 #include "access/htup_details.h"
00020 #include "funcapi.h"
00021 #include "libpq/pqformat.h"
00022 #include "utils/array.h"
00023 #include "utils/builtins.h"
00024 #include "utils/datum.h"
00025 #include "utils/lsyscache.h"
00026 #include "utils/memutils.h"
00027 #include "utils/typcache.h"
00028
00029
00030
00031
00032
00033 bool Array_nulls = true;
00034
00035
00036
00037
00038 #define ASSGN "="
00039
00040 typedef enum
00041 {
00042 ARRAY_NO_LEVEL,
00043 ARRAY_LEVEL_STARTED,
00044 ARRAY_ELEM_STARTED,
00045 ARRAY_ELEM_COMPLETED,
00046 ARRAY_QUOTED_ELEM_STARTED,
00047 ARRAY_QUOTED_ELEM_COMPLETED,
00048 ARRAY_ELEM_DELIMITED,
00049 ARRAY_LEVEL_COMPLETED,
00050 ARRAY_LEVEL_DELIMITED
00051 } ArrayParseState;
00052
00053
00054 typedef struct ArrayIteratorData
00055 {
00056
00057 ArrayType *arr;
00058 bits8 *nullbitmap;
00059 int nitems;
00060 int16 typlen;
00061 bool typbyval;
00062 char typalign;
00063
00064
00065 int slice_ndim;
00066 int slice_len;
00067 int *slice_dims;
00068 int *slice_lbound;
00069 Datum *slice_values;
00070 bool *slice_nulls;
00071
00072
00073 char *data_ptr;
00074 int current_item;
00075 } ArrayIteratorData;
00076
00077 static bool array_isspace(char ch);
00078 static int ArrayCount(const char *str, int *dim, char typdelim);
00079 static void ReadArrayStr(char *arrayStr, const char *origStr,
00080 int nitems, int ndim, int *dim,
00081 FmgrInfo *inputproc, Oid typioparam, int32 typmod,
00082 char typdelim,
00083 int typlen, bool typbyval, char typalign,
00084 Datum *values, bool *nulls,
00085 bool *hasnulls, int32 *nbytes);
00086 static void ReadArrayBinary(StringInfo buf, int nitems,
00087 FmgrInfo *receiveproc, Oid typioparam, int32 typmod,
00088 int typlen, bool typbyval, char typalign,
00089 Datum *values, bool *nulls,
00090 bool *hasnulls, int32 *nbytes);
00091 static void CopyArrayEls(ArrayType *array,
00092 Datum *values, bool *nulls, int nitems,
00093 int typlen, bool typbyval, char typalign,
00094 bool freedata);
00095 static bool array_get_isnull(const bits8 *nullbitmap, int offset);
00096 static void array_set_isnull(bits8 *nullbitmap, int offset, bool isNull);
00097 static Datum ArrayCast(char *value, bool byval, int len);
00098 static int ArrayCastAndSet(Datum src,
00099 int typlen, bool typbyval, char typalign,
00100 char *dest);
00101 static char *array_seek(char *ptr, int offset, bits8 *nullbitmap, int nitems,
00102 int typlen, bool typbyval, char typalign);
00103 static int array_nelems_size(char *ptr, int offset, bits8 *nullbitmap,
00104 int nitems, int typlen, bool typbyval, char typalign);
00105 static int array_copy(char *destptr, int nitems,
00106 char *srcptr, int offset, bits8 *nullbitmap,
00107 int typlen, bool typbyval, char typalign);
00108 static int array_slice_size(char *arraydataptr, bits8 *arraynullsptr,
00109 int ndim, int *dim, int *lb,
00110 int *st, int *endp,
00111 int typlen, bool typbyval, char typalign);
00112 static void array_extract_slice(ArrayType *newarray,
00113 int ndim, int *dim, int *lb,
00114 char *arraydataptr, bits8 *arraynullsptr,
00115 int *st, int *endp,
00116 int typlen, bool typbyval, char typalign);
00117 static void array_insert_slice(ArrayType *destArray, ArrayType *origArray,
00118 ArrayType *srcArray,
00119 int ndim, int *dim, int *lb,
00120 int *st, int *endp,
00121 int typlen, bool typbyval, char typalign);
00122 static int array_cmp(FunctionCallInfo fcinfo);
00123 static ArrayType *create_array_envelope(int ndims, int *dimv, int *lbv, int nbytes,
00124 Oid elmtype, int dataoffset);
00125 static ArrayType *array_fill_internal(ArrayType *dims, ArrayType *lbs,
00126 Datum value, bool isnull, Oid elmtype,
00127 FunctionCallInfo fcinfo);
00128 static ArrayType *array_replace_internal(ArrayType *array,
00129 Datum search, bool search_isnull,
00130 Datum replace, bool replace_isnull,
00131 bool remove, Oid collation,
00132 FunctionCallInfo fcinfo);
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143 Datum
00144 array_in(PG_FUNCTION_ARGS)
00145 {
00146 char *string = PG_GETARG_CSTRING(0);
00147 Oid element_type = PG_GETARG_OID(1);
00148
00149 int32 typmod = PG_GETARG_INT32(2);
00150 int typlen;
00151 bool typbyval;
00152 char typalign;
00153 char typdelim;
00154 Oid typioparam;
00155 char *string_save,
00156 *p;
00157 int i,
00158 nitems;
00159 Datum *dataPtr;
00160 bool *nullsPtr;
00161 bool hasnulls;
00162 int32 nbytes;
00163 int32 dataoffset;
00164 ArrayType *retval;
00165 int ndim,
00166 dim[MAXDIM],
00167 lBound[MAXDIM];
00168 ArrayMetaState *my_extra;
00169
00170
00171
00172
00173
00174
00175 my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra;
00176 if (my_extra == NULL)
00177 {
00178 fcinfo->flinfo->fn_extra = MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
00179 sizeof(ArrayMetaState));
00180 my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra;
00181 my_extra->element_type = ~element_type;
00182 }
00183
00184 if (my_extra->element_type != element_type)
00185 {
00186
00187
00188
00189 get_type_io_data(element_type, IOFunc_input,
00190 &my_extra->typlen, &my_extra->typbyval,
00191 &my_extra->typalign, &my_extra->typdelim,
00192 &my_extra->typioparam, &my_extra->typiofunc);
00193 fmgr_info_cxt(my_extra->typiofunc, &my_extra->proc,
00194 fcinfo->flinfo->fn_mcxt);
00195 my_extra->element_type = element_type;
00196 }
00197 typlen = my_extra->typlen;
00198 typbyval = my_extra->typbyval;
00199 typalign = my_extra->typalign;
00200 typdelim = my_extra->typdelim;
00201 typioparam = my_extra->typioparam;
00202
00203
00204 string_save = pstrdup(string);
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214 p = string_save;
00215 ndim = 0;
00216 for (;;)
00217 {
00218 char *q;
00219 int ub;
00220
00221
00222
00223
00224
00225 while (array_isspace(*p))
00226 p++;
00227 if (*p != '[')
00228 break;
00229 p++;
00230 if (ndim >= MAXDIM)
00231 ereport(ERROR,
00232 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
00233 errmsg("number of array dimensions (%d) exceeds the maximum allowed (%d)",
00234 ndim + 1, MAXDIM)));
00235
00236 for (q = p; isdigit((unsigned char) *q) || (*q == '-') || (*q == '+'); q++);
00237 if (q == p)
00238 ereport(ERROR,
00239 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
00240 errmsg("missing dimension value")));
00241
00242 if (*q == ':')
00243 {
00244
00245 *q = '\0';
00246 lBound[ndim] = atoi(p);
00247 p = q + 1;
00248 for (q = p; isdigit((unsigned char) *q) || (*q == '-') || (*q == '+'); q++);
00249 if (q == p)
00250 ereport(ERROR,
00251 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
00252 errmsg("missing dimension value")));
00253 }
00254 else
00255 {
00256
00257 lBound[ndim] = 1;
00258 }
00259 if (*q != ']')
00260 ereport(ERROR,
00261 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
00262 errmsg("missing \"]\" in array dimensions")));
00263
00264 *q = '\0';
00265 ub = atoi(p);
00266 p = q + 1;
00267 if (ub < lBound[ndim])
00268 ereport(ERROR,
00269 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
00270 errmsg("upper bound cannot be less than lower bound")));
00271
00272 dim[ndim] = ub - lBound[ndim] + 1;
00273 ndim++;
00274 }
00275
00276 if (ndim == 0)
00277 {
00278
00279 if (*p != '{')
00280 ereport(ERROR,
00281 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
00282 errmsg("array value must start with \"{\" or dimension information")));
00283 ndim = ArrayCount(p, dim, typdelim);
00284 for (i = 0; i < ndim; i++)
00285 lBound[i] = 1;
00286 }
00287 else
00288 {
00289 int ndim_braces,
00290 dim_braces[MAXDIM];
00291
00292
00293 if (strncmp(p, ASSGN, strlen(ASSGN)) != 0)
00294 ereport(ERROR,
00295 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
00296 errmsg("missing assignment operator")));
00297 p += strlen(ASSGN);
00298 while (array_isspace(*p))
00299 p++;
00300
00301
00302
00303
00304
00305 if (*p != '{')
00306 ereport(ERROR,
00307 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
00308 errmsg("array value must start with \"{\" or dimension information")));
00309 ndim_braces = ArrayCount(p, dim_braces, typdelim);
00310 if (ndim_braces != ndim)
00311 ereport(ERROR,
00312 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
00313 errmsg("array dimensions incompatible with array literal")));
00314 for (i = 0; i < ndim; ++i)
00315 {
00316 if (dim[i] != dim_braces[i])
00317 ereport(ERROR,
00318 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
00319 errmsg("array dimensions incompatible with array literal")));
00320 }
00321 }
00322
00323 #ifdef ARRAYDEBUG
00324 printf("array_in- ndim %d (", ndim);
00325 for (i = 0; i < ndim; i++)
00326 {
00327 printf(" %d", dim[i]);
00328 };
00329 printf(") for %s\n", string);
00330 #endif
00331
00332
00333 nitems = ArrayGetNItems(ndim, dim);
00334
00335 if (nitems == 0)
00336 PG_RETURN_ARRAYTYPE_P(construct_empty_array(element_type));
00337
00338 dataPtr = (Datum *) palloc(nitems * sizeof(Datum));
00339 nullsPtr = (bool *) palloc(nitems * sizeof(bool));
00340 ReadArrayStr(p, string,
00341 nitems, ndim, dim,
00342 &my_extra->proc, typioparam, typmod,
00343 typdelim,
00344 typlen, typbyval, typalign,
00345 dataPtr, nullsPtr,
00346 &hasnulls, &nbytes);
00347 if (hasnulls)
00348 {
00349 dataoffset = ARR_OVERHEAD_WITHNULLS(ndim, nitems);
00350 nbytes += dataoffset;
00351 }
00352 else
00353 {
00354 dataoffset = 0;
00355 nbytes += ARR_OVERHEAD_NONULLS(ndim);
00356 }
00357 retval = (ArrayType *) palloc0(nbytes);
00358 SET_VARSIZE(retval, nbytes);
00359 retval->ndim = ndim;
00360 retval->dataoffset = dataoffset;
00361
00362
00363
00364
00365
00366
00367 retval->elemtype = element_type;
00368 memcpy(ARR_DIMS(retval), dim, ndim * sizeof(int));
00369 memcpy(ARR_LBOUND(retval), lBound, ndim * sizeof(int));
00370
00371 CopyArrayEls(retval,
00372 dataPtr, nullsPtr, nitems,
00373 typlen, typbyval, typalign,
00374 true);
00375
00376 pfree(dataPtr);
00377 pfree(nullsPtr);
00378 pfree(string_save);
00379
00380 PG_RETURN_ARRAYTYPE_P(retval);
00381 }
00382
00383
00384
00385
00386
00387
00388
00389
00390
00391 static bool
00392 array_isspace(char ch)
00393 {
00394 if (ch == ' ' ||
00395 ch == '\t' ||
00396 ch == '\n' ||
00397 ch == '\r' ||
00398 ch == '\v' ||
00399 ch == '\f')
00400 return true;
00401 return false;
00402 }
00403
00404
00405
00406
00407
00408
00409
00410
00411 static int
00412 ArrayCount(const char *str, int *dim, char typdelim)
00413 {
00414 int nest_level = 0,
00415 i;
00416 int ndim = 1,
00417 temp[MAXDIM],
00418 nelems[MAXDIM],
00419 nelems_last[MAXDIM];
00420 bool in_quotes = false;
00421 bool eoArray = false;
00422 bool empty_array = true;
00423 const char *ptr;
00424 ArrayParseState parse_state = ARRAY_NO_LEVEL;
00425
00426 for (i = 0; i < MAXDIM; ++i)
00427 {
00428 temp[i] = dim[i] = 0;
00429 nelems_last[i] = nelems[i] = 1;
00430 }
00431
00432 ptr = str;
00433 while (!eoArray)
00434 {
00435 bool itemdone = false;
00436
00437 while (!itemdone)
00438 {
00439 if (parse_state == ARRAY_ELEM_STARTED ||
00440 parse_state == ARRAY_QUOTED_ELEM_STARTED)
00441 empty_array = false;
00442
00443 switch (*ptr)
00444 {
00445 case '\0':
00446
00447 ereport(ERROR,
00448 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
00449 errmsg("malformed array literal: \"%s\"", str)));
00450 break;
00451 case '\\':
00452
00453
00454
00455
00456
00457
00458 if (parse_state != ARRAY_LEVEL_STARTED &&
00459 parse_state != ARRAY_ELEM_STARTED &&
00460 parse_state != ARRAY_QUOTED_ELEM_STARTED &&
00461 parse_state != ARRAY_ELEM_DELIMITED)
00462 ereport(ERROR,
00463 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
00464 errmsg("malformed array literal: \"%s\"", str)));
00465 if (parse_state != ARRAY_QUOTED_ELEM_STARTED)
00466 parse_state = ARRAY_ELEM_STARTED;
00467
00468 if (*(ptr + 1))
00469 ptr++;
00470 else
00471 ereport(ERROR,
00472 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
00473 errmsg("malformed array literal: \"%s\"", str)));
00474 break;
00475 case '\"':
00476
00477
00478
00479
00480
00481
00482 if (parse_state != ARRAY_LEVEL_STARTED &&
00483 parse_state != ARRAY_QUOTED_ELEM_STARTED &&
00484 parse_state != ARRAY_ELEM_DELIMITED)
00485 ereport(ERROR,
00486 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
00487 errmsg("malformed array literal: \"%s\"", str)));
00488 in_quotes = !in_quotes;
00489 if (in_quotes)
00490 parse_state = ARRAY_QUOTED_ELEM_STARTED;
00491 else
00492 parse_state = ARRAY_QUOTED_ELEM_COMPLETED;
00493 break;
00494 case '{':
00495 if (!in_quotes)
00496 {
00497
00498
00499
00500
00501
00502 if (parse_state != ARRAY_NO_LEVEL &&
00503 parse_state != ARRAY_LEVEL_STARTED &&
00504 parse_state != ARRAY_LEVEL_DELIMITED)
00505 ereport(ERROR,
00506 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
00507 errmsg("malformed array literal: \"%s\"", str)));
00508 parse_state = ARRAY_LEVEL_STARTED;
00509 if (nest_level >= MAXDIM)
00510 ereport(ERROR,
00511 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
00512 errmsg("number of array dimensions (%d) exceeds the maximum allowed (%d)",
00513 nest_level + 1, MAXDIM)));
00514 temp[nest_level] = 0;
00515 nest_level++;
00516 if (ndim < nest_level)
00517 ndim = nest_level;
00518 }
00519 break;
00520 case '}':
00521 if (!in_quotes)
00522 {
00523
00524
00525
00526
00527
00528 if (parse_state != ARRAY_ELEM_STARTED &&
00529 parse_state != ARRAY_ELEM_COMPLETED &&
00530 parse_state != ARRAY_QUOTED_ELEM_COMPLETED &&
00531 parse_state != ARRAY_LEVEL_COMPLETED &&
00532 !(nest_level == 1 && parse_state == ARRAY_LEVEL_STARTED))
00533 ereport(ERROR,
00534 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
00535 errmsg("malformed array literal: \"%s\"", str)));
00536 parse_state = ARRAY_LEVEL_COMPLETED;
00537 if (nest_level == 0)
00538 ereport(ERROR,
00539 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
00540 errmsg("malformed array literal: \"%s\"", str)));
00541 nest_level--;
00542
00543 if ((nelems_last[nest_level] != 1) &&
00544 (nelems[nest_level] != nelems_last[nest_level]))
00545 ereport(ERROR,
00546 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
00547 errmsg("multidimensional arrays must have "
00548 "array expressions with matching "
00549 "dimensions")));
00550 nelems_last[nest_level] = nelems[nest_level];
00551 nelems[nest_level] = 1;
00552 if (nest_level == 0)
00553 eoArray = itemdone = true;
00554 else
00555 {
00556
00557
00558
00559
00560 temp[nest_level - 1]++;
00561 }
00562 }
00563 break;
00564 default:
00565 if (!in_quotes)
00566 {
00567 if (*ptr == typdelim)
00568 {
00569
00570
00571
00572
00573
00574 if (parse_state != ARRAY_ELEM_STARTED &&
00575 parse_state != ARRAY_ELEM_COMPLETED &&
00576 parse_state != ARRAY_QUOTED_ELEM_COMPLETED &&
00577 parse_state != ARRAY_LEVEL_COMPLETED)
00578 ereport(ERROR,
00579 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
00580 errmsg("malformed array literal: \"%s\"", str)));
00581 if (parse_state == ARRAY_LEVEL_COMPLETED)
00582 parse_state = ARRAY_LEVEL_DELIMITED;
00583 else
00584 parse_state = ARRAY_ELEM_DELIMITED;
00585 itemdone = true;
00586 nelems[nest_level - 1]++;
00587 }
00588 else if (!array_isspace(*ptr))
00589 {
00590
00591
00592
00593
00594
00595
00596 if (parse_state != ARRAY_LEVEL_STARTED &&
00597 parse_state != ARRAY_ELEM_STARTED &&
00598 parse_state != ARRAY_ELEM_DELIMITED)
00599 ereport(ERROR,
00600 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
00601 errmsg("malformed array literal: \"%s\"", str)));
00602 parse_state = ARRAY_ELEM_STARTED;
00603 }
00604 }
00605 break;
00606 }
00607 if (!itemdone)
00608 ptr++;
00609 }
00610 temp[ndim - 1]++;
00611 ptr++;
00612 }
00613
00614
00615 while (*ptr)
00616 {
00617 if (!array_isspace(*ptr++))
00618 ereport(ERROR,
00619 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
00620 errmsg("malformed array literal: \"%s\"", str)));
00621 }
00622
00623
00624 if (empty_array)
00625 return 0;
00626
00627 for (i = 0; i < ndim; ++i)
00628 dim[i] = temp[i];
00629
00630 return ndim;
00631 }
00632
00633
00634
00635
00636
00637
00638
00639
00640
00641
00642
00643
00644
00645
00646
00647
00648
00649
00650
00651
00652
00653
00654
00655
00656
00657
00658
00659
00660
00661 static void
00662 ReadArrayStr(char *arrayStr,
00663 const char *origStr,
00664 int nitems,
00665 int ndim,
00666 int *dim,
00667 FmgrInfo *inputproc,
00668 Oid typioparam,
00669 int32 typmod,
00670 char typdelim,
00671 int typlen,
00672 bool typbyval,
00673 char typalign,
00674 Datum *values,
00675 bool *nulls,
00676 bool *hasnulls,
00677 int32 *nbytes)
00678 {
00679 int i,
00680 nest_level = 0;
00681 char *srcptr;
00682 bool in_quotes = false;
00683 bool eoArray = false;
00684 bool hasnull;
00685 int32 totbytes;
00686 int indx[MAXDIM],
00687 prod[MAXDIM];
00688
00689 mda_get_prod(ndim, dim, prod);
00690 MemSet(indx, 0, sizeof(indx));
00691
00692
00693 memset(nulls, true, nitems * sizeof(bool));
00694
00695
00696
00697
00698
00699
00700
00701
00702
00703
00704
00705
00706
00707
00708
00709 srcptr = arrayStr;
00710 while (!eoArray)
00711 {
00712 bool itemdone = false;
00713 bool leadingspace = true;
00714 bool hasquoting = false;
00715 char *itemstart;
00716 char *dstptr;
00717 char *dstendptr;
00718
00719 i = -1;
00720 itemstart = dstptr = dstendptr = srcptr;
00721
00722 while (!itemdone)
00723 {
00724 switch (*srcptr)
00725 {
00726 case '\0':
00727
00728 ereport(ERROR,
00729 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
00730 errmsg("malformed array literal: \"%s\"",
00731 origStr)));
00732 break;
00733 case '\\':
00734
00735 srcptr++;
00736 if (*srcptr == '\0')
00737 ereport(ERROR,
00738 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
00739 errmsg("malformed array literal: \"%s\"",
00740 origStr)));
00741 *dstptr++ = *srcptr++;
00742
00743 leadingspace = false;
00744 dstendptr = dstptr;
00745 hasquoting = true;
00746 break;
00747 case '\"':
00748 in_quotes = !in_quotes;
00749 if (in_quotes)
00750 leadingspace = false;
00751 else
00752 {
00753
00754
00755
00756
00757
00758 dstendptr = dstptr;
00759 }
00760 hasquoting = true;
00761 srcptr++;
00762 break;
00763 case '{':
00764 if (!in_quotes)
00765 {
00766 if (nest_level >= ndim)
00767 ereport(ERROR,
00768 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
00769 errmsg("malformed array literal: \"%s\"",
00770 origStr)));
00771 nest_level++;
00772 indx[nest_level - 1] = 0;
00773 srcptr++;
00774 }
00775 else
00776 *dstptr++ = *srcptr++;
00777 break;
00778 case '}':
00779 if (!in_quotes)
00780 {
00781 if (nest_level == 0)
00782 ereport(ERROR,
00783 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
00784 errmsg("malformed array literal: \"%s\"",
00785 origStr)));
00786 if (i == -1)
00787 i = ArrayGetOffset0(ndim, indx, prod);
00788 indx[nest_level - 1] = 0;
00789 nest_level--;
00790 if (nest_level == 0)
00791 eoArray = itemdone = true;
00792 else
00793 indx[nest_level - 1]++;
00794 srcptr++;
00795 }
00796 else
00797 *dstptr++ = *srcptr++;
00798 break;
00799 default:
00800 if (in_quotes)
00801 *dstptr++ = *srcptr++;
00802 else if (*srcptr == typdelim)
00803 {
00804 if (i == -1)
00805 i = ArrayGetOffset0(ndim, indx, prod);
00806 itemdone = true;
00807 indx[ndim - 1]++;
00808 srcptr++;
00809 }
00810 else if (array_isspace(*srcptr))
00811 {
00812
00813
00814
00815
00816 if (leadingspace)
00817 srcptr++;
00818 else
00819 *dstptr++ = *srcptr++;
00820 }
00821 else
00822 {
00823 *dstptr++ = *srcptr++;
00824 leadingspace = false;
00825 dstendptr = dstptr;
00826 }
00827 break;
00828 }
00829 }
00830
00831 Assert(dstptr < srcptr);
00832 *dstendptr = '\0';
00833
00834 if (i < 0 || i >= nitems)
00835 ereport(ERROR,
00836 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
00837 errmsg("malformed array literal: \"%s\"",
00838 origStr)));
00839
00840 if (Array_nulls && !hasquoting &&
00841 pg_strcasecmp(itemstart, "NULL") == 0)
00842 {
00843
00844 values[i] = InputFunctionCall(inputproc, NULL,
00845 typioparam, typmod);
00846 nulls[i] = true;
00847 }
00848 else
00849 {
00850 values[i] = InputFunctionCall(inputproc, itemstart,
00851 typioparam, typmod);
00852 nulls[i] = false;
00853 }
00854 }
00855
00856
00857
00858
00859 hasnull = false;
00860 totbytes = 0;
00861 for (i = 0; i < nitems; i++)
00862 {
00863 if (nulls[i])
00864 hasnull = true;
00865 else
00866 {
00867
00868 if (typlen == -1)
00869 values[i] = PointerGetDatum(PG_DETOAST_DATUM(values[i]));
00870 totbytes = att_addlength_datum(totbytes, typlen, values[i]);
00871 totbytes = att_align_nominal(totbytes, typalign);
00872
00873 if (!AllocSizeIsValid(totbytes))
00874 ereport(ERROR,
00875 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
00876 errmsg("array size exceeds the maximum allowed (%d)",
00877 (int) MaxAllocSize)));
00878 }
00879 }
00880 *hasnulls = hasnull;
00881 *nbytes = totbytes;
00882 }
00883
00884
00885
00886
00887
00888
00889
00890
00891
00892
00893
00894
00895
00896
00897
00898
00899
00900 static void
00901 CopyArrayEls(ArrayType *array,
00902 Datum *values,
00903 bool *nulls,
00904 int nitems,
00905 int typlen,
00906 bool typbyval,
00907 char typalign,
00908 bool freedata)
00909 {
00910 char *p = ARR_DATA_PTR(array);
00911 bits8 *bitmap = ARR_NULLBITMAP(array);
00912 int bitval = 0;
00913 int bitmask = 1;
00914 int i;
00915
00916 if (typbyval)
00917 freedata = false;
00918
00919 for (i = 0; i < nitems; i++)
00920 {
00921 if (nulls && nulls[i])
00922 {
00923 if (!bitmap)
00924 elog(ERROR, "null array element where not supported");
00925
00926 }
00927 else
00928 {
00929 bitval |= bitmask;
00930 p += ArrayCastAndSet(values[i], typlen, typbyval, typalign, p);
00931 if (freedata)
00932 pfree(DatumGetPointer(values[i]));
00933 }
00934 if (bitmap)
00935 {
00936 bitmask <<= 1;
00937 if (bitmask == 0x100)
00938 {
00939 *bitmap++ = bitval;
00940 bitval = 0;
00941 bitmask = 1;
00942 }
00943 }
00944 }
00945
00946 if (bitmap && bitmask != 1)
00947 *bitmap = bitval;
00948 }
00949
00950
00951
00952
00953
00954
00955 Datum
00956 array_out(PG_FUNCTION_ARGS)
00957 {
00958 ArrayType *v = PG_GETARG_ARRAYTYPE_P(0);
00959 Oid element_type = ARR_ELEMTYPE(v);
00960 int typlen;
00961 bool typbyval;
00962 char typalign;
00963 char typdelim;
00964 char *p,
00965 *tmp,
00966 *retval,
00967 **values,
00968 dims_str[(MAXDIM * 33) + 2];
00969
00970
00971
00972
00973
00974
00975 bits8 *bitmap;
00976 int bitmask;
00977 bool *needquotes,
00978 needdims = false;
00979 int nitems,
00980 overall_length,
00981 i,
00982 j,
00983 k,
00984 indx[MAXDIM];
00985 int ndim,
00986 *dims,
00987 *lb;
00988 ArrayMetaState *my_extra;
00989
00990
00991
00992
00993
00994
00995 my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra;
00996 if (my_extra == NULL)
00997 {
00998 fcinfo->flinfo->fn_extra = MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
00999 sizeof(ArrayMetaState));
01000 my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra;
01001 my_extra->element_type = ~element_type;
01002 }
01003
01004 if (my_extra->element_type != element_type)
01005 {
01006
01007
01008
01009 get_type_io_data(element_type, IOFunc_output,
01010 &my_extra->typlen, &my_extra->typbyval,
01011 &my_extra->typalign, &my_extra->typdelim,
01012 &my_extra->typioparam, &my_extra->typiofunc);
01013 fmgr_info_cxt(my_extra->typiofunc, &my_extra->proc,
01014 fcinfo->flinfo->fn_mcxt);
01015 my_extra->element_type = element_type;
01016 }
01017 typlen = my_extra->typlen;
01018 typbyval = my_extra->typbyval;
01019 typalign = my_extra->typalign;
01020 typdelim = my_extra->typdelim;
01021
01022 ndim = ARR_NDIM(v);
01023 dims = ARR_DIMS(v);
01024 lb = ARR_LBOUND(v);
01025 nitems = ArrayGetNItems(ndim, dims);
01026
01027 if (nitems == 0)
01028 {
01029 retval = pstrdup("{}");
01030 PG_RETURN_CSTRING(retval);
01031 }
01032
01033
01034
01035
01036
01037 for (i = 0; i < ndim; i++)
01038 {
01039 if (lb[i] != 1)
01040 {
01041 needdims = true;
01042 break;
01043 }
01044 }
01045
01046
01047
01048
01049
01050
01051 values = (char **) palloc(nitems * sizeof(char *));
01052 needquotes = (bool *) palloc(nitems * sizeof(bool));
01053 overall_length = 1;
01054
01055 p = ARR_DATA_PTR(v);
01056 bitmap = ARR_NULLBITMAP(v);
01057 bitmask = 1;
01058
01059 for (i = 0; i < nitems; i++)
01060 {
01061 bool needquote;
01062
01063
01064 if (bitmap && (*bitmap & bitmask) == 0)
01065 {
01066 values[i] = pstrdup("NULL");
01067 overall_length += 4;
01068 needquote = false;
01069 }
01070 else
01071 {
01072 Datum itemvalue;
01073
01074 itemvalue = fetch_att(p, typbyval, typlen);
01075 values[i] = OutputFunctionCall(&my_extra->proc, itemvalue);
01076 p = att_addlength_pointer(p, typlen, p);
01077 p = (char *) att_align_nominal(p, typalign);
01078
01079
01080 if (values[i][0] == '\0')
01081 needquote = true;
01082 else if (pg_strcasecmp(values[i], "NULL") == 0)
01083 needquote = true;
01084 else
01085 needquote = false;
01086
01087 for (tmp = values[i]; *tmp != '\0'; tmp++)
01088 {
01089 char ch = *tmp;
01090
01091 overall_length += 1;
01092 if (ch == '"' || ch == '\\')
01093 {
01094 needquote = true;
01095 overall_length += 1;
01096 }
01097 else if (ch == '{' || ch == '}' || ch == typdelim ||
01098 array_isspace(ch))
01099 needquote = true;
01100 }
01101 }
01102
01103 needquotes[i] = needquote;
01104
01105
01106 if (needquote)
01107 overall_length += 2;
01108
01109 overall_length += 1;
01110
01111
01112 if (bitmap)
01113 {
01114 bitmask <<= 1;
01115 if (bitmask == 0x100)
01116 {
01117 bitmap++;
01118 bitmask = 1;
01119 }
01120 }
01121 }
01122
01123
01124
01125
01126 for (i = j = 0, k = 1; i < ndim; i++)
01127 k *= dims[i], j += k;
01128
01129 dims_str[0] = '\0';
01130
01131
01132 if (needdims)
01133 {
01134 char *ptr = dims_str;
01135
01136 for (i = 0; i < ndim; i++)
01137 {
01138 sprintf(ptr, "[%d:%d]", lb[i], lb[i] + dims[i] - 1);
01139 ptr += strlen(ptr);
01140 }
01141 *ptr++ = *ASSGN;
01142 *ptr = '\0';
01143 }
01144
01145 retval = (char *) palloc(strlen(dims_str) + overall_length + 2 * j);
01146 p = retval;
01147
01148 #define APPENDSTR(str) (strcpy(p, (str)), p += strlen(p))
01149 #define APPENDCHAR(ch) (*p++ = (ch), *p = '\0')
01150
01151 if (needdims)
01152 APPENDSTR(dims_str);
01153 APPENDCHAR('{');
01154 for (i = 0; i < ndim; i++)
01155 indx[i] = 0;
01156 j = 0;
01157 k = 0;
01158 do
01159 {
01160 for (i = j; i < ndim - 1; i++)
01161 APPENDCHAR('{');
01162
01163 if (needquotes[k])
01164 {
01165 APPENDCHAR('"');
01166 for (tmp = values[k]; *tmp; tmp++)
01167 {
01168 char ch = *tmp;
01169
01170 if (ch == '"' || ch == '\\')
01171 *p++ = '\\';
01172 *p++ = ch;
01173 }
01174 *p = '\0';
01175 APPENDCHAR('"');
01176 }
01177 else
01178 APPENDSTR(values[k]);
01179 pfree(values[k++]);
01180
01181 for (i = ndim - 1; i >= 0; i--)
01182 {
01183 indx[i] = (indx[i] + 1) % dims[i];
01184 if (indx[i])
01185 {
01186 APPENDCHAR(typdelim);
01187 break;
01188 }
01189 else
01190 APPENDCHAR('}');
01191 }
01192 j = i;
01193 } while (j != -1);
01194
01195 #undef APPENDSTR
01196 #undef APPENDCHAR
01197
01198 pfree(values);
01199 pfree(needquotes);
01200
01201 PG_RETURN_CSTRING(retval);
01202 }
01203
01204
01205
01206
01207
01208
01209
01210
01211
01212 Datum
01213 array_recv(PG_FUNCTION_ARGS)
01214 {
01215 StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
01216 Oid spec_element_type = PG_GETARG_OID(1);
01217
01218 int32 typmod = PG_GETARG_INT32(2);
01219 Oid element_type;
01220 int typlen;
01221 bool typbyval;
01222 char typalign;
01223 Oid typioparam;
01224 int i,
01225 nitems;
01226 Datum *dataPtr;
01227 bool *nullsPtr;
01228 bool hasnulls;
01229 int32 nbytes;
01230 int32 dataoffset;
01231 ArrayType *retval;
01232 int ndim,
01233 flags,
01234 dim[MAXDIM],
01235 lBound[MAXDIM];
01236 ArrayMetaState *my_extra;
01237
01238
01239 ndim = pq_getmsgint(buf, 4);
01240 if (ndim < 0)
01241 ereport(ERROR,
01242 (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
01243 errmsg("invalid number of dimensions: %d", ndim)));
01244 if (ndim > MAXDIM)
01245 ereport(ERROR,
01246 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
01247 errmsg("number of array dimensions (%d) exceeds the maximum allowed (%d)",
01248 ndim, MAXDIM)));
01249
01250 flags = pq_getmsgint(buf, 4);
01251 if (flags != 0 && flags != 1)
01252 ereport(ERROR,
01253 (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
01254 errmsg("invalid array flags")));
01255
01256 element_type = pq_getmsgint(buf, sizeof(Oid));
01257 if (element_type != spec_element_type)
01258 {
01259
01260 ereport(ERROR,
01261 (errcode(ERRCODE_DATATYPE_MISMATCH),
01262 errmsg("wrong element type")));
01263 }
01264
01265 for (i = 0; i < ndim; i++)
01266 {
01267 dim[i] = pq_getmsgint(buf, 4);
01268 lBound[i] = pq_getmsgint(buf, 4);
01269
01270
01271
01272
01273
01274 if (dim[i] != 0)
01275 {
01276 int ub = lBound[i] + dim[i] - 1;
01277
01278 if (lBound[i] > ub)
01279 ereport(ERROR,
01280 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
01281 errmsg("integer out of range")));
01282 }
01283 }
01284
01285
01286 nitems = ArrayGetNItems(ndim, dim);
01287
01288
01289
01290
01291
01292
01293 my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra;
01294 if (my_extra == NULL)
01295 {
01296 fcinfo->flinfo->fn_extra = MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
01297 sizeof(ArrayMetaState));
01298 my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra;
01299 my_extra->element_type = ~element_type;
01300 }
01301
01302 if (my_extra->element_type != element_type)
01303 {
01304
01305 get_type_io_data(element_type, IOFunc_receive,
01306 &my_extra->typlen, &my_extra->typbyval,
01307 &my_extra->typalign, &my_extra->typdelim,
01308 &my_extra->typioparam, &my_extra->typiofunc);
01309 if (!OidIsValid(my_extra->typiofunc))
01310 ereport(ERROR,
01311 (errcode(ERRCODE_UNDEFINED_FUNCTION),
01312 errmsg("no binary input function available for type %s",
01313 format_type_be(element_type))));
01314 fmgr_info_cxt(my_extra->typiofunc, &my_extra->proc,
01315 fcinfo->flinfo->fn_mcxt);
01316 my_extra->element_type = element_type;
01317 }
01318
01319 if (nitems == 0)
01320 {
01321
01322 PG_RETURN_ARRAYTYPE_P(construct_empty_array(element_type));
01323 }
01324
01325 typlen = my_extra->typlen;
01326 typbyval = my_extra->typbyval;
01327 typalign = my_extra->typalign;
01328 typioparam = my_extra->typioparam;
01329
01330 dataPtr = (Datum *) palloc(nitems * sizeof(Datum));
01331 nullsPtr = (bool *) palloc(nitems * sizeof(bool));
01332 ReadArrayBinary(buf, nitems,
01333 &my_extra->proc, typioparam, typmod,
01334 typlen, typbyval, typalign,
01335 dataPtr, nullsPtr,
01336 &hasnulls, &nbytes);
01337 if (hasnulls)
01338 {
01339 dataoffset = ARR_OVERHEAD_WITHNULLS(ndim, nitems);
01340 nbytes += dataoffset;
01341 }
01342 else
01343 {
01344 dataoffset = 0;
01345 nbytes += ARR_OVERHEAD_NONULLS(ndim);
01346 }
01347 retval = (ArrayType *) palloc0(nbytes);
01348 SET_VARSIZE(retval, nbytes);
01349 retval->ndim = ndim;
01350 retval->dataoffset = dataoffset;
01351 retval->elemtype = element_type;
01352 memcpy(ARR_DIMS(retval), dim, ndim * sizeof(int));
01353 memcpy(ARR_LBOUND(retval), lBound, ndim * sizeof(int));
01354
01355 CopyArrayEls(retval,
01356 dataPtr, nullsPtr, nitems,
01357 typlen, typbyval, typalign,
01358 true);
01359
01360 pfree(dataPtr);
01361 pfree(nullsPtr);
01362
01363 PG_RETURN_ARRAYTYPE_P(retval);
01364 }
01365
01366
01367
01368
01369
01370
01371
01372
01373
01374
01375
01376
01377
01378
01379
01380
01381
01382
01383
01384
01385
01386
01387 static void
01388 ReadArrayBinary(StringInfo buf,
01389 int nitems,
01390 FmgrInfo *receiveproc,
01391 Oid typioparam,
01392 int32 typmod,
01393 int typlen,
01394 bool typbyval,
01395 char typalign,
01396 Datum *values,
01397 bool *nulls,
01398 bool *hasnulls,
01399 int32 *nbytes)
01400 {
01401 int i;
01402 bool hasnull;
01403 int32 totbytes;
01404
01405 for (i = 0; i < nitems; i++)
01406 {
01407 int itemlen;
01408 StringInfoData elem_buf;
01409 char csave;
01410
01411
01412 itemlen = pq_getmsgint(buf, 4);
01413 if (itemlen < -1 || itemlen > (buf->len - buf->cursor))
01414 ereport(ERROR,
01415 (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
01416 errmsg("insufficient data left in message")));
01417
01418 if (itemlen == -1)
01419 {
01420
01421 values[i] = ReceiveFunctionCall(receiveproc, NULL,
01422 typioparam, typmod);
01423 nulls[i] = true;
01424 continue;
01425 }
01426
01427
01428
01429
01430
01431
01432
01433 elem_buf.data = &buf->data[buf->cursor];
01434 elem_buf.maxlen = itemlen + 1;
01435 elem_buf.len = itemlen;
01436 elem_buf.cursor = 0;
01437
01438 buf->cursor += itemlen;
01439
01440 csave = buf->data[buf->cursor];
01441 buf->data[buf->cursor] = '\0';
01442
01443
01444 values[i] = ReceiveFunctionCall(receiveproc, &elem_buf,
01445 typioparam, typmod);
01446 nulls[i] = false;
01447
01448
01449 if (elem_buf.cursor != itemlen)
01450 ereport(ERROR,
01451 (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
01452 errmsg("improper binary format in array element %d",
01453 i + 1)));
01454
01455 buf->data[buf->cursor] = csave;
01456 }
01457
01458
01459
01460
01461 hasnull = false;
01462 totbytes = 0;
01463 for (i = 0; i < nitems; i++)
01464 {
01465 if (nulls[i])
01466 hasnull = true;
01467 else
01468 {
01469
01470 if (typlen == -1)
01471 values[i] = PointerGetDatum(PG_DETOAST_DATUM(values[i]));
01472 totbytes = att_addlength_datum(totbytes, typlen, values[i]);
01473 totbytes = att_align_nominal(totbytes, typalign);
01474
01475 if (!AllocSizeIsValid(totbytes))
01476 ereport(ERROR,
01477 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
01478 errmsg("array size exceeds the maximum allowed (%d)",
01479 (int) MaxAllocSize)));
01480 }
01481 }
01482 *hasnulls = hasnull;
01483 *nbytes = totbytes;
01484 }
01485
01486
01487
01488
01489
01490
01491
01492 Datum
01493 array_send(PG_FUNCTION_ARGS)
01494 {
01495 ArrayType *v = PG_GETARG_ARRAYTYPE_P(0);
01496 Oid element_type = ARR_ELEMTYPE(v);
01497 int typlen;
01498 bool typbyval;
01499 char typalign;
01500 char *p;
01501 bits8 *bitmap;
01502 int bitmask;
01503 int nitems,
01504 i;
01505 int ndim,
01506 *dim;
01507 StringInfoData buf;
01508 ArrayMetaState *my_extra;
01509
01510
01511
01512
01513
01514
01515 my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra;
01516 if (my_extra == NULL)
01517 {
01518 fcinfo->flinfo->fn_extra = MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
01519 sizeof(ArrayMetaState));
01520 my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra;
01521 my_extra->element_type = ~element_type;
01522 }
01523
01524 if (my_extra->element_type != element_type)
01525 {
01526
01527 get_type_io_data(element_type, IOFunc_send,
01528 &my_extra->typlen, &my_extra->typbyval,
01529 &my_extra->typalign, &my_extra->typdelim,
01530 &my_extra->typioparam, &my_extra->typiofunc);
01531 if (!OidIsValid(my_extra->typiofunc))
01532 ereport(ERROR,
01533 (errcode(ERRCODE_UNDEFINED_FUNCTION),
01534 errmsg("no binary output function available for type %s",
01535 format_type_be(element_type))));
01536 fmgr_info_cxt(my_extra->typiofunc, &my_extra->proc,
01537 fcinfo->flinfo->fn_mcxt);
01538 my_extra->element_type = element_type;
01539 }
01540 typlen = my_extra->typlen;
01541 typbyval = my_extra->typbyval;
01542 typalign = my_extra->typalign;
01543
01544 ndim = ARR_NDIM(v);
01545 dim = ARR_DIMS(v);
01546 nitems = ArrayGetNItems(ndim, dim);
01547
01548 pq_begintypsend(&buf);
01549
01550
01551 pq_sendint(&buf, ndim, 4);
01552 pq_sendint(&buf, ARR_HASNULL(v) ? 1 : 0, 4);
01553 pq_sendint(&buf, element_type, sizeof(Oid));
01554 for (i = 0; i < ndim; i++)
01555 {
01556 pq_sendint(&buf, ARR_DIMS(v)[i], 4);
01557 pq_sendint(&buf, ARR_LBOUND(v)[i], 4);
01558 }
01559
01560
01561 p = ARR_DATA_PTR(v);
01562 bitmap = ARR_NULLBITMAP(v);
01563 bitmask = 1;
01564
01565 for (i = 0; i < nitems; i++)
01566 {
01567
01568 if (bitmap && (*bitmap & bitmask) == 0)
01569 {
01570
01571 pq_sendint(&buf, -1, 4);
01572 }
01573 else
01574 {
01575 Datum itemvalue;
01576 bytea *outputbytes;
01577
01578 itemvalue = fetch_att(p, typbyval, typlen);
01579 outputbytes = SendFunctionCall(&my_extra->proc, itemvalue);
01580 pq_sendint(&buf, VARSIZE(outputbytes) - VARHDRSZ, 4);
01581 pq_sendbytes(&buf, VARDATA(outputbytes),
01582 VARSIZE(outputbytes) - VARHDRSZ);
01583 pfree(outputbytes);
01584
01585 p = att_addlength_pointer(p, typlen, p);
01586 p = (char *) att_align_nominal(p, typalign);
01587 }
01588
01589
01590 if (bitmap)
01591 {
01592 bitmask <<= 1;
01593 if (bitmask == 0x100)
01594 {
01595 bitmap++;
01596 bitmask = 1;
01597 }
01598 }
01599 }
01600
01601 PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
01602 }
01603
01604
01605
01606
01607
01608 Datum
01609 array_ndims(PG_FUNCTION_ARGS)
01610 {
01611 ArrayType *v = PG_GETARG_ARRAYTYPE_P(0);
01612
01613
01614 if (ARR_NDIM(v) <= 0 || ARR_NDIM(v) > MAXDIM)
01615 PG_RETURN_NULL();
01616
01617 PG_RETURN_INT32(ARR_NDIM(v));
01618 }
01619
01620
01621
01622
01623
01624 Datum
01625 array_dims(PG_FUNCTION_ARGS)
01626 {
01627 ArrayType *v = PG_GETARG_ARRAYTYPE_P(0);
01628 char *p;
01629 int i;
01630 int *dimv,
01631 *lb;
01632
01633
01634
01635
01636
01637
01638 char buf[MAXDIM * 33 + 1];
01639
01640
01641 if (ARR_NDIM(v) <= 0 || ARR_NDIM(v) > MAXDIM)
01642 PG_RETURN_NULL();
01643
01644 dimv = ARR_DIMS(v);
01645 lb = ARR_LBOUND(v);
01646
01647 p = buf;
01648 for (i = 0; i < ARR_NDIM(v); i++)
01649 {
01650 sprintf(p, "[%d:%d]", lb[i], dimv[i] + lb[i] - 1);
01651 p += strlen(p);
01652 }
01653
01654 PG_RETURN_TEXT_P(cstring_to_text(buf));
01655 }
01656
01657
01658
01659
01660
01661
01662 Datum
01663 array_lower(PG_FUNCTION_ARGS)
01664 {
01665 ArrayType *v = PG_GETARG_ARRAYTYPE_P(0);
01666 int reqdim = PG_GETARG_INT32(1);
01667 int *lb;
01668 int result;
01669
01670
01671 if (ARR_NDIM(v) <= 0 || ARR_NDIM(v) > MAXDIM)
01672 PG_RETURN_NULL();
01673
01674
01675 if (reqdim <= 0 || reqdim > ARR_NDIM(v))
01676 PG_RETURN_NULL();
01677
01678 lb = ARR_LBOUND(v);
01679 result = lb[reqdim - 1];
01680
01681 PG_RETURN_INT32(result);
01682 }
01683
01684
01685
01686
01687
01688
01689 Datum
01690 array_upper(PG_FUNCTION_ARGS)
01691 {
01692 ArrayType *v = PG_GETARG_ARRAYTYPE_P(0);
01693 int reqdim = PG_GETARG_INT32(1);
01694 int *dimv,
01695 *lb;
01696 int result;
01697
01698
01699 if (ARR_NDIM(v) <= 0 || ARR_NDIM(v) > MAXDIM)
01700 PG_RETURN_NULL();
01701
01702
01703 if (reqdim <= 0 || reqdim > ARR_NDIM(v))
01704 PG_RETURN_NULL();
01705
01706 lb = ARR_LBOUND(v);
01707 dimv = ARR_DIMS(v);
01708
01709 result = dimv[reqdim - 1] + lb[reqdim - 1] - 1;
01710
01711 PG_RETURN_INT32(result);
01712 }
01713
01714
01715
01716
01717
01718
01719 Datum
01720 array_length(PG_FUNCTION_ARGS)
01721 {
01722 ArrayType *v = PG_GETARG_ARRAYTYPE_P(0);
01723 int reqdim = PG_GETARG_INT32(1);
01724 int *dimv;
01725 int result;
01726
01727
01728 if (ARR_NDIM(v) <= 0 || ARR_NDIM(v) > MAXDIM)
01729 PG_RETURN_NULL();
01730
01731
01732 if (reqdim <= 0 || reqdim > ARR_NDIM(v))
01733 PG_RETURN_NULL();
01734
01735 dimv = ARR_DIMS(v);
01736
01737 result = dimv[reqdim - 1];
01738
01739 PG_RETURN_INT32(result);
01740 }
01741
01742
01743
01744
01745
01746
01747
01748
01749
01750
01751
01752
01753
01754
01755
01756
01757
01758
01759
01760
01761
01762
01763 Datum
01764 array_ref(ArrayType *array,
01765 int nSubscripts,
01766 int *indx,
01767 int arraytyplen,
01768 int elmlen,
01769 bool elmbyval,
01770 char elmalign,
01771 bool *isNull)
01772 {
01773 int i,
01774 ndim,
01775 *dim,
01776 *lb,
01777 offset,
01778 fixedDim[1],
01779 fixedLb[1];
01780 char *arraydataptr,
01781 *retptr;
01782 bits8 *arraynullsptr;
01783
01784 if (arraytyplen > 0)
01785 {
01786
01787
01788
01789 ndim = 1;
01790 fixedDim[0] = arraytyplen / elmlen;
01791 fixedLb[0] = 0;
01792 dim = fixedDim;
01793 lb = fixedLb;
01794 arraydataptr = (char *) array;
01795 arraynullsptr = NULL;
01796 }
01797 else
01798 {
01799
01800 array = DatumGetArrayTypeP(PointerGetDatum(array));
01801
01802 ndim = ARR_NDIM(array);
01803 dim = ARR_DIMS(array);
01804 lb = ARR_LBOUND(array);
01805 arraydataptr = ARR_DATA_PTR(array);
01806 arraynullsptr = ARR_NULLBITMAP(array);
01807 }
01808
01809
01810
01811
01812 if (ndim != nSubscripts || ndim <= 0 || ndim > MAXDIM)
01813 {
01814 *isNull = true;
01815 return (Datum) 0;
01816 }
01817 for (i = 0; i < ndim; i++)
01818 {
01819 if (indx[i] < lb[i] || indx[i] >= (dim[i] + lb[i]))
01820 {
01821 *isNull = true;
01822 return (Datum) 0;
01823 }
01824 }
01825
01826
01827
01828
01829 offset = ArrayGetOffset(nSubscripts, dim, lb, indx);
01830
01831
01832
01833
01834 if (array_get_isnull(arraynullsptr, offset))
01835 {
01836 *isNull = true;
01837 return (Datum) 0;
01838 }
01839
01840
01841
01842
01843 *isNull = false;
01844 retptr = array_seek(arraydataptr, 0, arraynullsptr, offset,
01845 elmlen, elmbyval, elmalign);
01846 return ArrayCast(retptr, elmbyval, elmlen);
01847 }
01848
01849
01850
01851
01852
01853
01854
01855
01856
01857
01858
01859
01860
01861
01862
01863
01864
01865
01866
01867
01868
01869
01870
01871
01872
01873 ArrayType *
01874 array_get_slice(ArrayType *array,
01875 int nSubscripts,
01876 int *upperIndx,
01877 int *lowerIndx,
01878 int arraytyplen,
01879 int elmlen,
01880 bool elmbyval,
01881 char elmalign)
01882 {
01883 ArrayType *newarray;
01884 int i,
01885 ndim,
01886 *dim,
01887 *lb,
01888 *newlb;
01889 int fixedDim[1],
01890 fixedLb[1];
01891 Oid elemtype;
01892 char *arraydataptr;
01893 bits8 *arraynullsptr;
01894 int32 dataoffset;
01895 int bytes,
01896 span[MAXDIM];
01897
01898 if (arraytyplen > 0)
01899 {
01900
01901
01902
01903
01904
01905
01906 ereport(ERROR,
01907 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
01908 errmsg("slices of fixed-length arrays not implemented")));
01909
01910
01911
01912
01913
01914
01915 ndim = 1;
01916 fixedDim[0] = arraytyplen / elmlen;
01917 fixedLb[0] = 0;
01918 dim = fixedDim;
01919 lb = fixedLb;
01920 elemtype = InvalidOid;
01921 arraydataptr = (char *) array;
01922 arraynullsptr = NULL;
01923 }
01924 else
01925 {
01926
01927 array = DatumGetArrayTypeP(PointerGetDatum(array));
01928
01929 ndim = ARR_NDIM(array);
01930 dim = ARR_DIMS(array);
01931 lb = ARR_LBOUND(array);
01932 elemtype = ARR_ELEMTYPE(array);
01933 arraydataptr = ARR_DATA_PTR(array);
01934 arraynullsptr = ARR_NULLBITMAP(array);
01935 }
01936
01937
01938
01939
01940
01941
01942 if (ndim < nSubscripts || ndim <= 0 || ndim > MAXDIM)
01943 return construct_empty_array(elemtype);
01944
01945 for (i = 0; i < nSubscripts; i++)
01946 {
01947 if (lowerIndx[i] < lb[i])
01948 lowerIndx[i] = lb[i];
01949 if (upperIndx[i] >= (dim[i] + lb[i]))
01950 upperIndx[i] = dim[i] + lb[i] - 1;
01951 if (lowerIndx[i] > upperIndx[i])
01952 return construct_empty_array(elemtype);
01953 }
01954
01955 for (; i < ndim; i++)
01956 {
01957 lowerIndx[i] = lb[i];
01958 upperIndx[i] = dim[i] + lb[i] - 1;
01959 if (lowerIndx[i] > upperIndx[i])
01960 return construct_empty_array(elemtype);
01961 }
01962
01963 mda_get_range(ndim, span, lowerIndx, upperIndx);
01964
01965 bytes = array_slice_size(arraydataptr, arraynullsptr,
01966 ndim, dim, lb,
01967 lowerIndx, upperIndx,
01968 elmlen, elmbyval, elmalign);
01969
01970
01971
01972
01973
01974 if (arraynullsptr)
01975 {
01976 dataoffset = ARR_OVERHEAD_WITHNULLS(ndim, ArrayGetNItems(ndim, span));
01977 bytes += dataoffset;
01978 }
01979 else
01980 {
01981 dataoffset = 0;
01982 bytes += ARR_OVERHEAD_NONULLS(ndim);
01983 }
01984
01985 newarray = (ArrayType *) palloc0(bytes);
01986 SET_VARSIZE(newarray, bytes);
01987 newarray->ndim = ndim;
01988 newarray->dataoffset = dataoffset;
01989 newarray->elemtype = elemtype;
01990 memcpy(ARR_DIMS(newarray), span, ndim * sizeof(int));
01991
01992
01993
01994
01995
01996 newlb = ARR_LBOUND(newarray);
01997 for (i = 0; i < ndim; i++)
01998 newlb[i] = 1;
01999
02000 array_extract_slice(newarray,
02001 ndim, dim, lb,
02002 arraydataptr, arraynullsptr,
02003 lowerIndx, upperIndx,
02004 elmlen, elmbyval, elmalign);
02005
02006 return newarray;
02007 }
02008
02009
02010
02011
02012
02013
02014
02015
02016
02017
02018
02019
02020
02021
02022
02023
02024
02025
02026
02027
02028
02029
02030
02031
02032
02033
02034
02035
02036
02037
02038
02039 ArrayType *
02040 array_set(ArrayType *array,
02041 int nSubscripts,
02042 int *indx,
02043 Datum dataValue,
02044 bool isNull,
02045 int arraytyplen,
02046 int elmlen,
02047 bool elmbyval,
02048 char elmalign)
02049 {
02050 ArrayType *newarray;
02051 int i,
02052 ndim,
02053 dim[MAXDIM],
02054 lb[MAXDIM],
02055 offset;
02056 char *elt_ptr;
02057 bool newhasnulls;
02058 bits8 *oldnullbitmap;
02059 int oldnitems,
02060 newnitems,
02061 olddatasize,
02062 newsize,
02063 olditemlen,
02064 newitemlen,
02065 overheadlen,
02066 oldoverheadlen,
02067 addedbefore,
02068 addedafter,
02069 lenbefore,
02070 lenafter;
02071
02072 if (arraytyplen > 0)
02073 {
02074
02075
02076
02077
02078 if (nSubscripts != 1)
02079 ereport(ERROR,
02080 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
02081 errmsg("wrong number of array subscripts")));
02082
02083 if (indx[0] < 0 || indx[0] * elmlen >= arraytyplen)
02084 ereport(ERROR,
02085 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
02086 errmsg("array subscript out of range")));
02087
02088 if (isNull)
02089 ereport(ERROR,
02090 (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
02091 errmsg("cannot assign null value to an element of a fixed-length array")));
02092
02093 newarray = (ArrayType *) palloc(arraytyplen);
02094 memcpy(newarray, array, arraytyplen);
02095 elt_ptr = (char *) newarray + indx[0] * elmlen;
02096 ArrayCastAndSet(dataValue, elmlen, elmbyval, elmalign, elt_ptr);
02097 return newarray;
02098 }
02099
02100 if (nSubscripts <= 0 || nSubscripts > MAXDIM)
02101 ereport(ERROR,
02102 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
02103 errmsg("wrong number of array subscripts")));
02104
02105
02106 if (elmlen == -1 && !isNull)
02107 dataValue = PointerGetDatum(PG_DETOAST_DATUM(dataValue));
02108
02109
02110 array = DatumGetArrayTypeP(PointerGetDatum(array));
02111
02112 ndim = ARR_NDIM(array);
02113
02114
02115
02116
02117
02118
02119 if (ndim == 0)
02120 {
02121 Oid elmtype = ARR_ELEMTYPE(array);
02122
02123 for (i = 0; i < nSubscripts; i++)
02124 {
02125 dim[i] = 1;
02126 lb[i] = indx[i];
02127 }
02128
02129 return construct_md_array(&dataValue, &isNull, nSubscripts,
02130 dim, lb, elmtype,
02131 elmlen, elmbyval, elmalign);
02132 }
02133
02134 if (ndim != nSubscripts)
02135 ereport(ERROR,
02136 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
02137 errmsg("wrong number of array subscripts")));
02138
02139
02140 memcpy(dim, ARR_DIMS(array), ndim * sizeof(int));
02141 memcpy(lb, ARR_LBOUND(array), ndim * sizeof(int));
02142
02143 newhasnulls = (ARR_HASNULL(array) || isNull);
02144 addedbefore = addedafter = 0;
02145
02146
02147
02148
02149 if (ndim == 1)
02150 {
02151 if (indx[0] < lb[0])
02152 {
02153 addedbefore = lb[0] - indx[0];
02154 dim[0] += addedbefore;
02155 lb[0] = indx[0];
02156 if (addedbefore > 1)
02157 newhasnulls = true;
02158 }
02159 if (indx[0] >= (dim[0] + lb[0]))
02160 {
02161 addedafter = indx[0] - (dim[0] + lb[0]) + 1;
02162 dim[0] += addedafter;
02163 if (addedafter > 1)
02164 newhasnulls = true;
02165 }
02166 }
02167 else
02168 {
02169
02170
02171
02172
02173 for (i = 0; i < ndim; i++)
02174 {
02175 if (indx[i] < lb[i] ||
02176 indx[i] >= (dim[i] + lb[i]))
02177 ereport(ERROR,
02178 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
02179 errmsg("array subscript out of range")));
02180 }
02181 }
02182
02183
02184
02185
02186 newnitems = ArrayGetNItems(ndim, dim);
02187 if (newhasnulls)
02188 overheadlen = ARR_OVERHEAD_WITHNULLS(ndim, newnitems);
02189 else
02190 overheadlen = ARR_OVERHEAD_NONULLS(ndim);
02191 oldnitems = ArrayGetNItems(ndim, ARR_DIMS(array));
02192 oldnullbitmap = ARR_NULLBITMAP(array);
02193 oldoverheadlen = ARR_DATA_OFFSET(array);
02194 olddatasize = ARR_SIZE(array) - oldoverheadlen;
02195 if (addedbefore)
02196 {
02197 offset = 0;
02198 lenbefore = 0;
02199 olditemlen = 0;
02200 lenafter = olddatasize;
02201 }
02202 else if (addedafter)
02203 {
02204 offset = oldnitems;
02205 lenbefore = olddatasize;
02206 olditemlen = 0;
02207 lenafter = 0;
02208 }
02209 else
02210 {
02211 offset = ArrayGetOffset(nSubscripts, dim, lb, indx);
02212 elt_ptr = array_seek(ARR_DATA_PTR(array), 0, oldnullbitmap, offset,
02213 elmlen, elmbyval, elmalign);
02214 lenbefore = (int) (elt_ptr - ARR_DATA_PTR(array));
02215 if (array_get_isnull(oldnullbitmap, offset))
02216 olditemlen = 0;
02217 else
02218 {
02219 olditemlen = att_addlength_pointer(0, elmlen, elt_ptr);
02220 olditemlen = att_align_nominal(olditemlen, elmalign);
02221 }
02222 lenafter = (int) (olddatasize - lenbefore - olditemlen);
02223 }
02224
02225 if (isNull)
02226 newitemlen = 0;
02227 else
02228 {
02229 newitemlen = att_addlength_datum(0, elmlen, dataValue);
02230 newitemlen = att_align_nominal(newitemlen, elmalign);
02231 }
02232
02233 newsize = overheadlen + lenbefore + newitemlen + lenafter;
02234
02235
02236
02237
02238 newarray = (ArrayType *) palloc0(newsize);
02239 SET_VARSIZE(newarray, newsize);
02240 newarray->ndim = ndim;
02241 newarray->dataoffset = newhasnulls ? overheadlen : 0;
02242 newarray->elemtype = ARR_ELEMTYPE(array);
02243 memcpy(ARR_DIMS(newarray), dim, ndim * sizeof(int));
02244 memcpy(ARR_LBOUND(newarray), lb, ndim * sizeof(int));
02245
02246
02247
02248
02249 memcpy((char *) newarray + overheadlen,
02250 (char *) array + oldoverheadlen,
02251 lenbefore);
02252 if (!isNull)
02253 ArrayCastAndSet(dataValue, elmlen, elmbyval, elmalign,
02254 (char *) newarray + overheadlen + lenbefore);
02255 memcpy((char *) newarray + overheadlen + lenbefore + newitemlen,
02256 (char *) array + oldoverheadlen + lenbefore + olditemlen,
02257 lenafter);
02258
02259
02260
02261
02262
02263
02264
02265 if (newhasnulls)
02266 {
02267 bits8 *newnullbitmap = ARR_NULLBITMAP(newarray);
02268
02269
02270 MemSet(newnullbitmap, 0, (newnitems + 7) / 8);
02271
02272 if (addedafter)
02273 array_set_isnull(newnullbitmap, newnitems - 1, isNull);
02274 else
02275 array_set_isnull(newnullbitmap, offset, isNull);
02276
02277 if (addedbefore)
02278 array_bitmap_copy(newnullbitmap, addedbefore,
02279 oldnullbitmap, 0,
02280 oldnitems);
02281 else
02282 {
02283 array_bitmap_copy(newnullbitmap, 0,
02284 oldnullbitmap, 0,
02285 offset);
02286 if (addedafter == 0)
02287 array_bitmap_copy(newnullbitmap, offset + 1,
02288 oldnullbitmap, offset + 1,
02289 oldnitems - offset - 1);
02290 }
02291 }
02292
02293 return newarray;
02294 }
02295
02296
02297
02298
02299
02300
02301
02302
02303
02304
02305
02306
02307
02308
02309
02310
02311
02312
02313
02314
02315
02316
02317
02318
02319
02320
02321
02322
02323
02324
02325
02326
02327
02328
02329
02330
02331 ArrayType *
02332 array_set_slice(ArrayType *array,
02333 int nSubscripts,
02334 int *upperIndx,
02335 int *lowerIndx,
02336 ArrayType *srcArray,
02337 bool isNull,
02338 int arraytyplen,
02339 int elmlen,
02340 bool elmbyval,
02341 char elmalign)
02342 {
02343 ArrayType *newarray;
02344 int i,
02345 ndim,
02346 dim[MAXDIM],
02347 lb[MAXDIM],
02348 span[MAXDIM];
02349 bool newhasnulls;
02350 int nitems,
02351 nsrcitems,
02352 olddatasize,
02353 newsize,
02354 olditemsize,
02355 newitemsize,
02356 overheadlen,
02357 oldoverheadlen,
02358 addedbefore,
02359 addedafter,
02360 lenbefore,
02361 lenafter,
02362 itemsbefore,
02363 itemsafter,
02364 nolditems;
02365
02366
02367 if (isNull)
02368 return array;
02369
02370 if (arraytyplen > 0)
02371 {
02372
02373
02374
02375 ereport(ERROR,
02376 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
02377 errmsg("updates on slices of fixed-length arrays not implemented")));
02378 }
02379
02380
02381 array = DatumGetArrayTypeP(PointerGetDatum(array));
02382 srcArray = DatumGetArrayTypeP(PointerGetDatum(srcArray));
02383
02384
02385
02386 ndim = ARR_NDIM(array);
02387
02388
02389
02390
02391
02392
02393 if (ndim == 0)
02394 {
02395 Datum *dvalues;
02396 bool *dnulls;
02397 int nelems;
02398 Oid elmtype = ARR_ELEMTYPE(array);
02399
02400 deconstruct_array(srcArray, elmtype, elmlen, elmbyval, elmalign,
02401 &dvalues, &dnulls, &nelems);
02402
02403 for (i = 0; i < nSubscripts; i++)
02404 {
02405 dim[i] = 1 + upperIndx[i] - lowerIndx[i];
02406 lb[i] = lowerIndx[i];
02407 }
02408
02409
02410 if (nelems < ArrayGetNItems(nSubscripts, dim))
02411 ereport(ERROR,
02412 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
02413 errmsg("source array too small")));
02414
02415 return construct_md_array(dvalues, dnulls, nSubscripts,
02416 dim, lb, elmtype,
02417 elmlen, elmbyval, elmalign);
02418 }
02419
02420 if (ndim < nSubscripts || ndim <= 0 || ndim > MAXDIM)
02421 ereport(ERROR,
02422 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
02423 errmsg("wrong number of array subscripts")));
02424
02425
02426 memcpy(dim, ARR_DIMS(array), ndim * sizeof(int));
02427 memcpy(lb, ARR_LBOUND(array), ndim * sizeof(int));
02428
02429 newhasnulls = (ARR_HASNULL(array) || ARR_HASNULL(srcArray));
02430 addedbefore = addedafter = 0;
02431
02432
02433
02434
02435 if (ndim == 1)
02436 {
02437 Assert(nSubscripts == 1);
02438 if (lowerIndx[0] > upperIndx[0])
02439 ereport(ERROR,
02440 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
02441 errmsg("upper bound cannot be less than lower bound")));
02442 if (lowerIndx[0] < lb[0])
02443 {
02444 if (upperIndx[0] < lb[0] - 1)
02445 newhasnulls = true;
02446 addedbefore = lb[0] - lowerIndx[0];
02447 dim[0] += addedbefore;
02448 lb[0] = lowerIndx[0];
02449 }
02450 if (upperIndx[0] >= (dim[0] + lb[0]))
02451 {
02452 if (lowerIndx[0] > (dim[0] + lb[0]))
02453 newhasnulls = true;
02454 addedafter = upperIndx[0] - (dim[0] + lb[0]) + 1;
02455 dim[0] += addedafter;
02456 }
02457 }
02458 else
02459 {
02460
02461
02462
02463
02464 for (i = 0; i < nSubscripts; i++)
02465 {
02466 if (lowerIndx[i] > upperIndx[i])
02467 ereport(ERROR,
02468 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
02469 errmsg("upper bound cannot be less than lower bound")));
02470 if (lowerIndx[i] < lb[i] ||
02471 upperIndx[i] >= (dim[i] + lb[i]))
02472 ereport(ERROR,
02473 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
02474 errmsg("array subscript out of range")));
02475 }
02476
02477 for (; i < ndim; i++)
02478 {
02479 lowerIndx[i] = lb[i];
02480 upperIndx[i] = dim[i] + lb[i] - 1;
02481 if (lowerIndx[i] > upperIndx[i])
02482 ereport(ERROR,
02483 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
02484 errmsg("upper bound cannot be less than lower bound")));
02485 }
02486 }
02487
02488
02489 nitems = ArrayGetNItems(ndim, dim);
02490
02491
02492
02493
02494
02495 mda_get_range(ndim, span, lowerIndx, upperIndx);
02496 nsrcitems = ArrayGetNItems(ndim, span);
02497 if (nsrcitems > ArrayGetNItems(ARR_NDIM(srcArray), ARR_DIMS(srcArray)))
02498 ereport(ERROR,
02499 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
02500 errmsg("source array too small")));
02501
02502
02503
02504
02505
02506 if (newhasnulls)
02507 overheadlen = ARR_OVERHEAD_WITHNULLS(ndim, nitems);
02508 else
02509 overheadlen = ARR_OVERHEAD_NONULLS(ndim);
02510 newitemsize = array_nelems_size(ARR_DATA_PTR(srcArray), 0,
02511 ARR_NULLBITMAP(srcArray), nsrcitems,
02512 elmlen, elmbyval, elmalign);
02513 oldoverheadlen = ARR_DATA_OFFSET(array);
02514 olddatasize = ARR_SIZE(array) - oldoverheadlen;
02515 if (ndim > 1)
02516 {
02517
02518
02519
02520
02521 olditemsize = array_slice_size(ARR_DATA_PTR(array),
02522 ARR_NULLBITMAP(array),
02523 ndim, dim, lb,
02524 lowerIndx, upperIndx,
02525 elmlen, elmbyval, elmalign);
02526 lenbefore = lenafter = 0;
02527 itemsbefore = itemsafter = nolditems = 0;
02528 }
02529 else
02530 {
02531
02532
02533
02534
02535 int oldlb = ARR_LBOUND(array)[0];
02536 int oldub = oldlb + ARR_DIMS(array)[0] - 1;
02537 int slicelb = Max(oldlb, lowerIndx[0]);
02538 int sliceub = Min(oldub, upperIndx[0]);
02539 char *oldarraydata = ARR_DATA_PTR(array);
02540 bits8 *oldarraybitmap = ARR_NULLBITMAP(array);
02541
02542
02543 itemsbefore = Min(slicelb, oldub + 1) - oldlb;
02544 lenbefore = array_nelems_size(oldarraydata, 0, oldarraybitmap,
02545 itemsbefore,
02546 elmlen, elmbyval, elmalign);
02547
02548 if (slicelb > sliceub)
02549 {
02550 nolditems = 0;
02551 olditemsize = 0;
02552 }
02553 else
02554 {
02555 nolditems = sliceub - slicelb + 1;
02556 olditemsize = array_nelems_size(oldarraydata + lenbefore,
02557 itemsbefore, oldarraybitmap,
02558 nolditems,
02559 elmlen, elmbyval, elmalign);
02560 }
02561
02562 itemsafter = oldub + 1 - Max(sliceub + 1, oldlb);
02563 lenafter = olddatasize - lenbefore - olditemsize;
02564 }
02565
02566 newsize = overheadlen + olddatasize - olditemsize + newitemsize;
02567
02568 newarray = (ArrayType *) palloc0(newsize);
02569 SET_VARSIZE(newarray, newsize);
02570 newarray->ndim = ndim;
02571 newarray->dataoffset = newhasnulls ? overheadlen : 0;
02572 newarray->elemtype = ARR_ELEMTYPE(array);
02573 memcpy(ARR_DIMS(newarray), dim, ndim * sizeof(int));
02574 memcpy(ARR_LBOUND(newarray), lb, ndim * sizeof(int));
02575
02576 if (ndim > 1)
02577 {
02578
02579
02580
02581
02582 array_insert_slice(newarray, array, srcArray,
02583 ndim, dim, lb,
02584 lowerIndx, upperIndx,
02585 elmlen, elmbyval, elmalign);
02586 }
02587 else
02588 {
02589
02590 memcpy((char *) newarray + overheadlen,
02591 (char *) array + oldoverheadlen,
02592 lenbefore);
02593 memcpy((char *) newarray + overheadlen + lenbefore,
02594 ARR_DATA_PTR(srcArray),
02595 newitemsize);
02596 memcpy((char *) newarray + overheadlen + lenbefore + newitemsize,
02597 (char *) array + oldoverheadlen + lenbefore + olditemsize,
02598 lenafter);
02599
02600 if (newhasnulls)
02601 {
02602 bits8 *newnullbitmap = ARR_NULLBITMAP(newarray);
02603 bits8 *oldnullbitmap = ARR_NULLBITMAP(array);
02604
02605
02606 MemSet(newnullbitmap, 0, (nitems + 7) / 8);
02607 array_bitmap_copy(newnullbitmap, addedbefore,
02608 oldnullbitmap, 0,
02609 itemsbefore);
02610 array_bitmap_copy(newnullbitmap, lowerIndx[0] - lb[0],
02611 ARR_NULLBITMAP(srcArray), 0,
02612 nsrcitems);
02613 array_bitmap_copy(newnullbitmap, addedbefore + itemsbefore + nolditems,
02614 oldnullbitmap, itemsbefore + nolditems,
02615 itemsafter);
02616 }
02617 }
02618
02619 return newarray;
02620 }
02621
02622
02623
02624
02625
02626
02627
02628
02629
02630
02631
02632
02633
02634
02635
02636
02637
02638
02639
02640
02641
02642
02643
02644
02645
02646
02647
02648
02649
02650
02651
02652 Datum
02653 array_map(FunctionCallInfo fcinfo, Oid inpType, Oid retType,
02654 ArrayMapState *amstate)
02655 {
02656 ArrayType *v;
02657 ArrayType *result;
02658 Datum *values;
02659 bool *nulls;
02660 Datum elt;
02661 int *dim;
02662 int ndim;
02663 int nitems;
02664 int i;
02665 int32 nbytes = 0;
02666 int32 dataoffset;
02667 bool hasnulls;
02668 int inp_typlen;
02669 bool inp_typbyval;
02670 char inp_typalign;
02671 int typlen;
02672 bool typbyval;
02673 char typalign;
02674 char *s;
02675 bits8 *bitmap;
02676 int bitmask;
02677 ArrayMetaState *inp_extra;
02678 ArrayMetaState *ret_extra;
02679
02680
02681 if (fcinfo->nargs < 1)
02682 elog(ERROR, "invalid nargs: %d", fcinfo->nargs);
02683 if (PG_ARGISNULL(0))
02684 elog(ERROR, "null input array");
02685 v = PG_GETARG_ARRAYTYPE_P(0);
02686
02687 Assert(ARR_ELEMTYPE(v) == inpType);
02688
02689 ndim = ARR_NDIM(v);
02690 dim = ARR_DIMS(v);
02691 nitems = ArrayGetNItems(ndim, dim);
02692
02693
02694 if (nitems <= 0)
02695 {
02696
02697 PG_RETURN_ARRAYTYPE_P(construct_empty_array(retType));
02698 }
02699
02700
02701
02702
02703
02704
02705 inp_extra = &amstate->inp_extra;
02706 ret_extra = &amstate->ret_extra;
02707
02708 if (inp_extra->element_type != inpType)
02709 {
02710 get_typlenbyvalalign(inpType,
02711 &inp_extra->typlen,
02712 &inp_extra->typbyval,
02713 &inp_extra->typalign);
02714 inp_extra->element_type = inpType;
02715 }
02716 inp_typlen = inp_extra->typlen;
02717 inp_typbyval = inp_extra->typbyval;
02718 inp_typalign = inp_extra->typalign;
02719
02720 if (ret_extra->element_type != retType)
02721 {
02722 get_typlenbyvalalign(retType,
02723 &ret_extra->typlen,
02724 &ret_extra->typbyval,
02725 &ret_extra->typalign);
02726 ret_extra->element_type = retType;
02727 }
02728 typlen = ret_extra->typlen;
02729 typbyval = ret_extra->typbyval;
02730 typalign = ret_extra->typalign;
02731
02732
02733 values = (Datum *) palloc(nitems * sizeof(Datum));
02734 nulls = (bool *) palloc(nitems * sizeof(bool));
02735
02736
02737 s = ARR_DATA_PTR(v);
02738 bitmap = ARR_NULLBITMAP(v);
02739 bitmask = 1;
02740 hasnulls = false;
02741
02742 for (i = 0; i < nitems; i++)
02743 {
02744 bool callit = true;
02745
02746
02747 if (bitmap && (*bitmap & bitmask) == 0)
02748 {
02749 fcinfo->argnull[0] = true;
02750 }
02751 else
02752 {
02753 elt = fetch_att(s, inp_typbyval, inp_typlen);
02754 s = att_addlength_datum(s, inp_typlen, elt);
02755 s = (char *) att_align_nominal(s, inp_typalign);
02756 fcinfo->arg[0] = elt;
02757 fcinfo->argnull[0] = false;
02758 }
02759
02760
02761
02762
02763 if (fcinfo->flinfo->fn_strict)
02764 {
02765 int j;
02766
02767 for (j = 0; j < fcinfo->nargs; j++)
02768 {
02769 if (fcinfo->argnull[j])
02770 {
02771 callit = false;
02772 break;
02773 }
02774 }
02775 }
02776
02777 if (callit)
02778 {
02779 fcinfo->isnull = false;
02780 values[i] = FunctionCallInvoke(fcinfo);
02781 }
02782 else
02783 fcinfo->isnull = true;
02784
02785 nulls[i] = fcinfo->isnull;
02786 if (fcinfo->isnull)
02787 hasnulls = true;
02788 else
02789 {
02790
02791 if (typlen == -1)
02792 values[i] = PointerGetDatum(PG_DETOAST_DATUM(values[i]));
02793
02794 nbytes = att_addlength_datum(nbytes, typlen, values[i]);
02795 nbytes = att_align_nominal(nbytes, typalign);
02796
02797 if (!AllocSizeIsValid(nbytes))
02798 ereport(ERROR,
02799 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
02800 errmsg("array size exceeds the maximum allowed (%d)",
02801 (int) MaxAllocSize)));
02802 }
02803
02804
02805 if (bitmap)
02806 {
02807 bitmask <<= 1;
02808 if (bitmask == 0x100)
02809 {
02810 bitmap++;
02811 bitmask = 1;
02812 }
02813 }
02814 }
02815
02816
02817 if (hasnulls)
02818 {
02819 dataoffset = ARR_OVERHEAD_WITHNULLS(ndim, nitems);
02820 nbytes += dataoffset;
02821 }
02822 else
02823 {
02824 dataoffset = 0;
02825 nbytes += ARR_OVERHEAD_NONULLS(ndim);
02826 }
02827 result = (ArrayType *) palloc0(nbytes);
02828 SET_VARSIZE(result, nbytes);
02829 result->ndim = ndim;
02830 result->dataoffset = dataoffset;
02831 result->elemtype = retType;
02832 memcpy(ARR_DIMS(result), ARR_DIMS(v), 2 * ndim * sizeof(int));
02833
02834
02835
02836
02837 CopyArrayEls(result,
02838 values, nulls, nitems,
02839 typlen, typbyval, typalign,
02840 false);
02841
02842 pfree(values);
02843 pfree(nulls);
02844
02845 PG_RETURN_ARRAYTYPE_P(result);
02846 }
02847
02848
02849
02850
02851
02852
02853
02854
02855
02856
02857
02858
02859
02860
02861
02862
02863
02864 ArrayType *
02865 construct_array(Datum *elems, int nelems,
02866 Oid elmtype,
02867 int elmlen, bool elmbyval, char elmalign)
02868 {
02869 int dims[1];
02870 int lbs[1];
02871
02872 dims[0] = nelems;
02873 lbs[0] = 1;
02874
02875 return construct_md_array(elems, NULL, 1, dims, lbs,
02876 elmtype, elmlen, elmbyval, elmalign);
02877 }
02878
02879
02880
02881
02882
02883
02884
02885
02886
02887
02888
02889
02890
02891
02892
02893
02894
02895
02896
02897
02898 ArrayType *
02899 construct_md_array(Datum *elems,
02900 bool *nulls,
02901 int ndims,
02902 int *dims,
02903 int *lbs,
02904 Oid elmtype, int elmlen, bool elmbyval, char elmalign)
02905 {
02906 ArrayType *result;
02907 bool hasnulls;
02908 int32 nbytes;
02909 int32 dataoffset;
02910 int i;
02911 int nelems;
02912
02913 if (ndims < 0)
02914 ereport(ERROR,
02915 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
02916 errmsg("invalid number of dimensions: %d", ndims)));
02917 if (ndims > MAXDIM)
02918 ereport(ERROR,
02919 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
02920 errmsg("number of array dimensions (%d) exceeds the maximum allowed (%d)",
02921 ndims, MAXDIM)));
02922
02923
02924 if (ndims == 0)
02925 return construct_empty_array(elmtype);
02926
02927 nelems = ArrayGetNItems(ndims, dims);
02928
02929
02930 nbytes = 0;
02931 hasnulls = false;
02932 for (i = 0; i < nelems; i++)
02933 {
02934 if (nulls && nulls[i])
02935 {
02936 hasnulls = true;
02937 continue;
02938 }
02939
02940 if (elmlen == -1)
02941 elems[i] = PointerGetDatum(PG_DETOAST_DATUM(elems[i]));
02942 nbytes = att_addlength_datum(nbytes, elmlen, elems[i]);
02943 nbytes = att_align_nominal(nbytes, elmalign);
02944
02945 if (!AllocSizeIsValid(nbytes))
02946 ereport(ERROR,
02947 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
02948 errmsg("array size exceeds the maximum allowed (%d)",
02949 (int) MaxAllocSize)));
02950 }
02951
02952
02953 if (hasnulls)
02954 {
02955 dataoffset = ARR_OVERHEAD_WITHNULLS(ndims, nelems);
02956 nbytes += dataoffset;
02957 }
02958 else
02959 {
02960 dataoffset = 0;
02961 nbytes += ARR_OVERHEAD_NONULLS(ndims);
02962 }
02963 result = (ArrayType *) palloc0(nbytes);
02964 SET_VARSIZE(result, nbytes);
02965 result->ndim = ndims;
02966 result->dataoffset = dataoffset;
02967 result->elemtype = elmtype;
02968 memcpy(ARR_DIMS(result), dims, ndims * sizeof(int));
02969 memcpy(ARR_LBOUND(result), lbs, ndims * sizeof(int));
02970
02971 CopyArrayEls(result,
02972 elems, nulls, nelems,
02973 elmlen, elmbyval, elmalign,
02974 false);
02975
02976 return result;
02977 }
02978
02979
02980
02981
02982 ArrayType *
02983 construct_empty_array(Oid elmtype)
02984 {
02985 ArrayType *result;
02986
02987 result = (ArrayType *) palloc0(sizeof(ArrayType));
02988 SET_VARSIZE(result, sizeof(ArrayType));
02989 result->ndim = 0;
02990 result->dataoffset = 0;
02991 result->elemtype = elmtype;
02992 return result;
02993 }
02994
02995
02996
02997
02998
02999
03000
03001
03002
03003
03004
03005
03006
03007
03008
03009
03010
03011
03012
03013
03014
03015
03016 void
03017 deconstruct_array(ArrayType *array,
03018 Oid elmtype,
03019 int elmlen, bool elmbyval, char elmalign,
03020 Datum **elemsp, bool **nullsp, int *nelemsp)
03021 {
03022 Datum *elems;
03023 bool *nulls;
03024 int nelems;
03025 char *p;
03026 bits8 *bitmap;
03027 int bitmask;
03028 int i;
03029
03030 Assert(ARR_ELEMTYPE(array) == elmtype);
03031
03032 nelems = ArrayGetNItems(ARR_NDIM(array), ARR_DIMS(array));
03033 *elemsp = elems = (Datum *) palloc(nelems * sizeof(Datum));
03034 if (nullsp)
03035 *nullsp = nulls = (bool *) palloc0(nelems * sizeof(bool));
03036 else
03037 nulls = NULL;
03038 *nelemsp = nelems;
03039
03040 p = ARR_DATA_PTR(array);
03041 bitmap = ARR_NULLBITMAP(array);
03042 bitmask = 1;
03043
03044 for (i = 0; i < nelems; i++)
03045 {
03046
03047 if (bitmap && (*bitmap & bitmask) == 0)
03048 {
03049 elems[i] = (Datum) 0;
03050 if (nulls)
03051 nulls[i] = true;
03052 else
03053 ereport(ERROR,
03054 (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
03055 errmsg("null array element not allowed in this context")));
03056 }
03057 else
03058 {
03059 elems[i] = fetch_att(p, elmbyval, elmlen);
03060 p = att_addlength_pointer(p, elmlen, p);
03061 p = (char *) att_align_nominal(p, elmalign);
03062 }
03063
03064
03065 if (bitmap)
03066 {
03067 bitmask <<= 1;
03068 if (bitmask == 0x100)
03069 {
03070 bitmap++;
03071 bitmask = 1;
03072 }
03073 }
03074 }
03075 }
03076
03077
03078
03079
03080
03081
03082
03083 bool
03084 array_contains_nulls(ArrayType *array)
03085 {
03086 int nelems;
03087 bits8 *bitmap;
03088 int bitmask;
03089
03090
03091 if (!ARR_HASNULL(array))
03092 return false;
03093
03094 nelems = ArrayGetNItems(ARR_NDIM(array), ARR_DIMS(array));
03095
03096 bitmap = ARR_NULLBITMAP(array);
03097
03098
03099 while (nelems >= 8)
03100 {
03101 if (*bitmap != 0xFF)
03102 return true;
03103 bitmap++;
03104 nelems -= 8;
03105 }
03106
03107
03108 bitmask = 1;
03109 while (nelems > 0)
03110 {
03111 if ((*bitmap & bitmask) == 0)
03112 return true;
03113 bitmask <<= 1;
03114 nelems--;
03115 }
03116
03117 return false;
03118 }
03119
03120
03121
03122
03123
03124
03125
03126
03127
03128
03129
03130 Datum
03131 array_eq(PG_FUNCTION_ARGS)
03132 {
03133 ArrayType *array1 = PG_GETARG_ARRAYTYPE_P(0);
03134 ArrayType *array2 = PG_GETARG_ARRAYTYPE_P(1);
03135 Oid collation = PG_GET_COLLATION();
03136 int ndims1 = ARR_NDIM(array1);
03137 int ndims2 = ARR_NDIM(array2);
03138 int *dims1 = ARR_DIMS(array1);
03139 int *dims2 = ARR_DIMS(array2);
03140 Oid element_type = ARR_ELEMTYPE(array1);
03141 bool result = true;
03142 int nitems;
03143 TypeCacheEntry *typentry;
03144 int typlen;
03145 bool typbyval;
03146 char typalign;
03147 char *ptr1;
03148 char *ptr2;
03149 bits8 *bitmap1;
03150 bits8 *bitmap2;
03151 int bitmask;
03152 int i;
03153 FunctionCallInfoData locfcinfo;
03154
03155 if (element_type != ARR_ELEMTYPE(array2))
03156 ereport(ERROR,
03157 (errcode(ERRCODE_DATATYPE_MISMATCH),
03158 errmsg("cannot compare arrays of different element types")));
03159
03160
03161 if (ndims1 != ndims2 ||
03162 memcmp(dims1, dims2, 2 * ndims1 * sizeof(int)) != 0)
03163 result = false;
03164 else
03165 {
03166
03167
03168
03169
03170
03171
03172 typentry = (TypeCacheEntry *) fcinfo->flinfo->fn_extra;
03173 if (typentry == NULL ||
03174 typentry->type_id != element_type)
03175 {
03176 typentry = lookup_type_cache(element_type,
03177 TYPECACHE_EQ_OPR_FINFO);
03178 if (!OidIsValid(typentry->eq_opr_finfo.fn_oid))
03179 ereport(ERROR,
03180 (errcode(ERRCODE_UNDEFINED_FUNCTION),
03181 errmsg("could not identify an equality operator for type %s",
03182 format_type_be(element_type))));
03183 fcinfo->flinfo->fn_extra = (void *) typentry;
03184 }
03185 typlen = typentry->typlen;
03186 typbyval = typentry->typbyval;
03187 typalign = typentry->typalign;
03188
03189
03190
03191
03192 InitFunctionCallInfoData(locfcinfo, &typentry->eq_opr_finfo, 2,
03193 collation, NULL, NULL);
03194
03195
03196 nitems = ArrayGetNItems(ndims1, dims1);
03197 ptr1 = ARR_DATA_PTR(array1);
03198 ptr2 = ARR_DATA_PTR(array2);
03199 bitmap1 = ARR_NULLBITMAP(array1);
03200 bitmap2 = ARR_NULLBITMAP(array2);
03201 bitmask = 1;
03202
03203 for (i = 0; i < nitems; i++)
03204 {
03205 Datum elt1;
03206 Datum elt2;
03207 bool isnull1;
03208 bool isnull2;
03209 bool oprresult;
03210
03211
03212 if (bitmap1 && (*bitmap1 & bitmask) == 0)
03213 {
03214 isnull1 = true;
03215 elt1 = (Datum) 0;
03216 }
03217 else
03218 {
03219 isnull1 = false;
03220 elt1 = fetch_att(ptr1, typbyval, typlen);
03221 ptr1 = att_addlength_pointer(ptr1, typlen, ptr1);
03222 ptr1 = (char *) att_align_nominal(ptr1, typalign);
03223 }
03224
03225 if (bitmap2 && (*bitmap2 & bitmask) == 0)
03226 {
03227 isnull2 = true;
03228 elt2 = (Datum) 0;
03229 }
03230 else
03231 {
03232 isnull2 = false;
03233 elt2 = fetch_att(ptr2, typbyval, typlen);
03234 ptr2 = att_addlength_pointer(ptr2, typlen, ptr2);
03235 ptr2 = (char *) att_align_nominal(ptr2, typalign);
03236 }
03237
03238
03239 bitmask <<= 1;
03240 if (bitmask == 0x100)
03241 {
03242 if (bitmap1)
03243 bitmap1++;
03244 if (bitmap2)
03245 bitmap2++;
03246 bitmask = 1;
03247 }
03248
03249
03250
03251
03252 if (isnull1 && isnull2)
03253 continue;
03254 if (isnull1 || isnull2)
03255 {
03256 result = false;
03257 break;
03258 }
03259
03260
03261
03262
03263 locfcinfo.arg[0] = elt1;
03264 locfcinfo.arg[1] = elt2;
03265 locfcinfo.argnull[0] = false;
03266 locfcinfo.argnull[1] = false;
03267 locfcinfo.isnull = false;
03268 oprresult = DatumGetBool(FunctionCallInvoke(&locfcinfo));
03269 if (!oprresult)
03270 {
03271 result = false;
03272 break;
03273 }
03274 }
03275 }
03276
03277
03278 PG_FREE_IF_COPY(array1, 0);
03279 PG_FREE_IF_COPY(array2, 1);
03280
03281 PG_RETURN_BOOL(result);
03282 }
03283
03284
03285
03286
03287
03288
03289
03290
03291
03292
03293
03294 Datum
03295 array_ne(PG_FUNCTION_ARGS)
03296 {
03297 PG_RETURN_BOOL(!DatumGetBool(array_eq(fcinfo)));
03298 }
03299
03300 Datum
03301 array_lt(PG_FUNCTION_ARGS)
03302 {
03303 PG_RETURN_BOOL(array_cmp(fcinfo) < 0);
03304 }
03305
03306 Datum
03307 array_gt(PG_FUNCTION_ARGS)
03308 {
03309 PG_RETURN_BOOL(array_cmp(fcinfo) > 0);
03310 }
03311
03312 Datum
03313 array_le(PG_FUNCTION_ARGS)
03314 {
03315 PG_RETURN_BOOL(array_cmp(fcinfo) <= 0);
03316 }
03317
03318 Datum
03319 array_ge(PG_FUNCTION_ARGS)
03320 {
03321 PG_RETURN_BOOL(array_cmp(fcinfo) >= 0);
03322 }
03323
03324 Datum
03325 btarraycmp(PG_FUNCTION_ARGS)
03326 {
03327 PG_RETURN_INT32(array_cmp(fcinfo));
03328 }
03329
03330
03331
03332
03333
03334
03335
03336 static int
03337 array_cmp(FunctionCallInfo fcinfo)
03338 {
03339 ArrayType *array1 = PG_GETARG_ARRAYTYPE_P(0);
03340 ArrayType *array2 = PG_GETARG_ARRAYTYPE_P(1);
03341 Oid collation = PG_GET_COLLATION();
03342 int ndims1 = ARR_NDIM(array1);
03343 int ndims2 = ARR_NDIM(array2);
03344 int *dims1 = ARR_DIMS(array1);
03345 int *dims2 = ARR_DIMS(array2);
03346 int nitems1 = ArrayGetNItems(ndims1, dims1);
03347 int nitems2 = ArrayGetNItems(ndims2, dims2);
03348 Oid element_type = ARR_ELEMTYPE(array1);
03349 int result = 0;
03350 TypeCacheEntry *typentry;
03351 int typlen;
03352 bool typbyval;
03353 char typalign;
03354 int min_nitems;
03355 char *ptr1;
03356 char *ptr2;
03357 bits8 *bitmap1;
03358 bits8 *bitmap2;
03359 int bitmask;
03360 int i;
03361 FunctionCallInfoData locfcinfo;
03362
03363 if (element_type != ARR_ELEMTYPE(array2))
03364 ereport(ERROR,
03365 (errcode(ERRCODE_DATATYPE_MISMATCH),
03366 errmsg("cannot compare arrays of different element types")));
03367
03368
03369
03370
03371
03372
03373
03374 typentry = (TypeCacheEntry *) fcinfo->flinfo->fn_extra;
03375 if (typentry == NULL ||
03376 typentry->type_id != element_type)
03377 {
03378 typentry = lookup_type_cache(element_type,
03379 TYPECACHE_CMP_PROC_FINFO);
03380 if (!OidIsValid(typentry->cmp_proc_finfo.fn_oid))
03381 ereport(ERROR,
03382 (errcode(ERRCODE_UNDEFINED_FUNCTION),
03383 errmsg("could not identify a comparison function for type %s",
03384 format_type_be(element_type))));
03385 fcinfo->flinfo->fn_extra = (void *) typentry;
03386 }
03387 typlen = typentry->typlen;
03388 typbyval = typentry->typbyval;
03389 typalign = typentry->typalign;
03390
03391
03392
03393
03394 InitFunctionCallInfoData(locfcinfo, &typentry->cmp_proc_finfo, 2,
03395 collation, NULL, NULL);
03396
03397
03398 min_nitems = Min(nitems1, nitems2);
03399 ptr1 = ARR_DATA_PTR(array1);
03400 ptr2 = ARR_DATA_PTR(array2);
03401 bitmap1 = ARR_NULLBITMAP(array1);
03402 bitmap2 = ARR_NULLBITMAP(array2);
03403 bitmask = 1;
03404
03405 for (i = 0; i < min_nitems; i++)
03406 {
03407 Datum elt1;
03408 Datum elt2;
03409 bool isnull1;
03410 bool isnull2;
03411 int32 cmpresult;
03412
03413
03414 if (bitmap1 && (*bitmap1 & bitmask) == 0)
03415 {
03416 isnull1 = true;
03417 elt1 = (Datum) 0;
03418 }
03419 else
03420 {
03421 isnull1 = false;
03422 elt1 = fetch_att(ptr1, typbyval, typlen);
03423 ptr1 = att_addlength_pointer(ptr1, typlen, ptr1);
03424 ptr1 = (char *) att_align_nominal(ptr1, typalign);
03425 }
03426
03427 if (bitmap2 && (*bitmap2 & bitmask) == 0)
03428 {
03429 isnull2 = true;
03430 elt2 = (Datum) 0;
03431 }
03432 else
03433 {
03434 isnull2 = false;
03435 elt2 = fetch_att(ptr2, typbyval, typlen);
03436 ptr2 = att_addlength_pointer(ptr2, typlen, ptr2);
03437 ptr2 = (char *) att_align_nominal(ptr2, typalign);
03438 }
03439
03440
03441 bitmask <<= 1;
03442 if (bitmask == 0x100)
03443 {
03444 if (bitmap1)
03445 bitmap1++;
03446 if (bitmap2)
03447 bitmap2++;
03448 bitmask = 1;
03449 }
03450
03451
03452
03453
03454 if (isnull1 && isnull2)
03455 continue;
03456 if (isnull1)
03457 {
03458
03459 result = 1;
03460 break;
03461 }
03462 if (isnull2)
03463 {
03464
03465 result = -1;
03466 break;
03467 }
03468
03469
03470 locfcinfo.arg[0] = elt1;
03471 locfcinfo.arg[1] = elt2;
03472 locfcinfo.argnull[0] = false;
03473 locfcinfo.argnull[1] = false;
03474 locfcinfo.isnull = false;
03475 cmpresult = DatumGetInt32(FunctionCallInvoke(&locfcinfo));
03476
03477 if (cmpresult == 0)
03478 continue;
03479
03480 if (cmpresult < 0)
03481 {
03482
03483 result = -1;
03484 break;
03485 }
03486 else
03487 {
03488
03489 result = 1;
03490 break;
03491 }
03492 }
03493
03494
03495
03496
03497
03498
03499
03500 if (result == 0)
03501 {
03502 if (nitems1 != nitems2)
03503 result = (nitems1 < nitems2) ? -1 : 1;
03504 else if (ndims1 != ndims2)
03505 result = (ndims1 < ndims2) ? -1 : 1;
03506 else
03507 {
03508
03509 for (i = 0; i < ndims1 * 2; i++)
03510 {
03511 if (dims1[i] != dims2[i])
03512 {
03513 result = (dims1[i] < dims2[i]) ? -1 : 1;
03514 break;
03515 }
03516 }
03517 }
03518 }
03519
03520
03521 PG_FREE_IF_COPY(array1, 0);
03522 PG_FREE_IF_COPY(array2, 1);
03523
03524 return result;
03525 }
03526
03527
03528
03529
03530
03531
03532
03533
03534 Datum
03535 hash_array(PG_FUNCTION_ARGS)
03536 {
03537 ArrayType *array = PG_GETARG_ARRAYTYPE_P(0);
03538 int ndims = ARR_NDIM(array);
03539 int *dims = ARR_DIMS(array);
03540 Oid element_type = ARR_ELEMTYPE(array);
03541 uint32 result = 1;
03542 int nitems;
03543 TypeCacheEntry *typentry;
03544 int typlen;
03545 bool typbyval;
03546 char typalign;
03547 char *ptr;
03548 bits8 *bitmap;
03549 int bitmask;
03550 int i;
03551 FunctionCallInfoData locfcinfo;
03552
03553
03554
03555
03556
03557
03558
03559 typentry = (TypeCacheEntry *) fcinfo->flinfo->fn_extra;
03560 if (typentry == NULL ||
03561 typentry->type_id != element_type)
03562 {
03563 typentry = lookup_type_cache(element_type,
03564 TYPECACHE_HASH_PROC_FINFO);
03565 if (!OidIsValid(typentry->hash_proc_finfo.fn_oid))
03566 ereport(ERROR,
03567 (errcode(ERRCODE_UNDEFINED_FUNCTION),
03568 errmsg("could not identify a hash function for type %s",
03569 format_type_be(element_type))));
03570 fcinfo->flinfo->fn_extra = (void *) typentry;
03571 }
03572 typlen = typentry->typlen;
03573 typbyval = typentry->typbyval;
03574 typalign = typentry->typalign;
03575
03576
03577
03578
03579 InitFunctionCallInfoData(locfcinfo, &typentry->hash_proc_finfo, 1,
03580 InvalidOid, NULL, NULL);
03581
03582
03583 nitems = ArrayGetNItems(ndims, dims);
03584 ptr = ARR_DATA_PTR(array);
03585 bitmap = ARR_NULLBITMAP(array);
03586 bitmask = 1;
03587
03588 for (i = 0; i < nitems; i++)
03589 {
03590 uint32 elthash;
03591
03592
03593 if (bitmap && (*bitmap & bitmask) == 0)
03594 {
03595
03596 elthash = 0;
03597 }
03598 else
03599 {
03600 Datum elt;
03601
03602 elt = fetch_att(ptr, typbyval, typlen);
03603 ptr = att_addlength_pointer(ptr, typlen, ptr);
03604 ptr = (char *) att_align_nominal(ptr, typalign);
03605
03606
03607 locfcinfo.arg[0] = elt;
03608 locfcinfo.argnull[0] = false;
03609 locfcinfo.isnull = false;
03610 elthash = DatumGetUInt32(FunctionCallInvoke(&locfcinfo));
03611 }
03612
03613
03614 if (bitmap)
03615 {
03616 bitmask <<= 1;
03617 if (bitmask == 0x100)
03618 {
03619 bitmap++;
03620 bitmask = 1;
03621 }
03622 }
03623
03624
03625
03626
03627
03628
03629
03630
03631
03632
03633
03634
03635 result = (result << 5) - result + elthash;
03636 }
03637
03638
03639 PG_FREE_IF_COPY(array, 0);
03640
03641 PG_RETURN_UINT32(result);
03642 }
03643
03644
03645
03646
03647
03648
03649
03650
03651
03652
03653
03654
03655
03656
03657
03658
03659 static bool
03660 array_contain_compare(ArrayType *array1, ArrayType *array2, Oid collation,
03661 bool matchall, void **fn_extra)
03662 {
03663 bool result = matchall;
03664 Oid element_type = ARR_ELEMTYPE(array1);
03665 TypeCacheEntry *typentry;
03666 int nelems1;
03667 Datum *values2;
03668 bool *nulls2;
03669 int nelems2;
03670 int typlen;
03671 bool typbyval;
03672 char typalign;
03673 char *ptr1;
03674 bits8 *bitmap1;
03675 int bitmask;
03676 int i;
03677 int j;
03678 FunctionCallInfoData locfcinfo;
03679
03680 if (element_type != ARR_ELEMTYPE(array2))
03681 ereport(ERROR,
03682 (errcode(ERRCODE_DATATYPE_MISMATCH),
03683 errmsg("cannot compare arrays of different element types")));
03684
03685
03686
03687
03688
03689
03690
03691 typentry = (TypeCacheEntry *) *fn_extra;
03692 if (typentry == NULL ||
03693 typentry->type_id != element_type)
03694 {
03695 typentry = lookup_type_cache(element_type,
03696 TYPECACHE_EQ_OPR_FINFO);
03697 if (!OidIsValid(typentry->eq_opr_finfo.fn_oid))
03698 ereport(ERROR,
03699 (errcode(ERRCODE_UNDEFINED_FUNCTION),
03700 errmsg("could not identify an equality operator for type %s",
03701 format_type_be(element_type))));
03702 *fn_extra = (void *) typentry;
03703 }
03704 typlen = typentry->typlen;
03705 typbyval = typentry->typbyval;
03706 typalign = typentry->typalign;
03707
03708
03709
03710
03711
03712
03713 deconstruct_array(array2, element_type, typlen, typbyval, typalign,
03714 &values2, &nulls2, &nelems2);
03715
03716
03717
03718
03719 InitFunctionCallInfoData(locfcinfo, &typentry->eq_opr_finfo, 2,
03720 collation, NULL, NULL);
03721
03722
03723 nelems1 = ArrayGetNItems(ARR_NDIM(array1), ARR_DIMS(array1));
03724 ptr1 = ARR_DATA_PTR(array1);
03725 bitmap1 = ARR_NULLBITMAP(array1);
03726 bitmask = 1;
03727
03728 for (i = 0; i < nelems1; i++)
03729 {
03730 Datum elt1;
03731 bool isnull1;
03732
03733
03734 if (bitmap1 && (*bitmap1 & bitmask) == 0)
03735 {
03736 isnull1 = true;
03737 elt1 = (Datum) 0;
03738 }
03739 else
03740 {
03741 isnull1 = false;
03742 elt1 = fetch_att(ptr1, typbyval, typlen);
03743 ptr1 = att_addlength_pointer(ptr1, typlen, ptr1);
03744 ptr1 = (char *) att_align_nominal(ptr1, typalign);
03745 }
03746
03747
03748 bitmask <<= 1;
03749 if (bitmask == 0x100)
03750 {
03751 if (bitmap1)
03752 bitmap1++;
03753 bitmask = 1;
03754 }
03755
03756
03757
03758
03759
03760
03761 if (isnull1)
03762 {
03763 if (matchall)
03764 {
03765 result = false;
03766 break;
03767 }
03768 continue;
03769 }
03770
03771 for (j = 0; j < nelems2; j++)
03772 {
03773 Datum elt2 = values2[j];
03774 bool isnull2 = nulls2[j];
03775 bool oprresult;
03776
03777 if (isnull2)
03778 continue;
03779
03780
03781
03782
03783 locfcinfo.arg[0] = elt1;
03784 locfcinfo.arg[1] = elt2;
03785 locfcinfo.argnull[0] = false;
03786 locfcinfo.argnull[1] = false;
03787 locfcinfo.isnull = false;
03788 oprresult = DatumGetBool(FunctionCallInvoke(&locfcinfo));
03789 if (oprresult)
03790 break;
03791 }
03792
03793 if (j < nelems2)
03794 {
03795
03796 if (!matchall)
03797 {
03798 result = true;
03799 break;
03800 }
03801 }
03802 else
03803 {
03804
03805 if (matchall)
03806 {
03807 result = false;
03808 break;
03809 }
03810 }
03811 }
03812
03813 pfree(values2);
03814 pfree(nulls2);
03815
03816 return result;
03817 }
03818
03819 Datum
03820 arrayoverlap(PG_FUNCTION_ARGS)
03821 {
03822 ArrayType *array1 = PG_GETARG_ARRAYTYPE_P(0);
03823 ArrayType *array2 = PG_GETARG_ARRAYTYPE_P(1);
03824 Oid collation = PG_GET_COLLATION();
03825 bool result;
03826
03827 result = array_contain_compare(array1, array2, collation, false,
03828 &fcinfo->flinfo->fn_extra);
03829
03830
03831 PG_FREE_IF_COPY(array1, 0);
03832 PG_FREE_IF_COPY(array2, 1);
03833
03834 PG_RETURN_BOOL(result);
03835 }
03836
03837 Datum
03838 arraycontains(PG_FUNCTION_ARGS)
03839 {
03840 ArrayType *array1 = PG_GETARG_ARRAYTYPE_P(0);
03841 ArrayType *array2 = PG_GETARG_ARRAYTYPE_P(1);
03842 Oid collation = PG_GET_COLLATION();
03843 bool result;
03844
03845 result = array_contain_compare(array2, array1, collation, true,
03846 &fcinfo->flinfo->fn_extra);
03847
03848
03849 PG_FREE_IF_COPY(array1, 0);
03850 PG_FREE_IF_COPY(array2, 1);
03851
03852 PG_RETURN_BOOL(result);
03853 }
03854
03855 Datum
03856 arraycontained(PG_FUNCTION_ARGS)
03857 {
03858 ArrayType *array1 = PG_GETARG_ARRAYTYPE_P(0);
03859 ArrayType *array2 = PG_GETARG_ARRAYTYPE_P(1);
03860 Oid collation = PG_GET_COLLATION();
03861 bool result;
03862
03863 result = array_contain_compare(array1, array2, collation, true,
03864 &fcinfo->flinfo->fn_extra);
03865
03866
03867 PG_FREE_IF_COPY(array1, 0);
03868 PG_FREE_IF_COPY(array2, 1);
03869
03870 PG_RETURN_BOOL(result);
03871 }
03872
03873
03874
03875
03876
03877
03878
03879
03880
03881
03882
03883
03884
03885
03886
03887
03888
03889
03890
03891
03892 ArrayIterator
03893 array_create_iterator(ArrayType *arr, int slice_ndim)
03894 {
03895 ArrayIterator iterator = palloc0(sizeof(ArrayIteratorData));
03896
03897
03898
03899
03900 Assert(PointerIsValid(arr));
03901 if (slice_ndim < 0 || slice_ndim > ARR_NDIM(arr))
03902 elog(ERROR, "invalid arguments to array_create_iterator");
03903
03904
03905
03906
03907 iterator->arr = arr;
03908 iterator->nullbitmap = ARR_NULLBITMAP(arr);
03909 iterator->nitems = ArrayGetNItems(ARR_NDIM(arr), ARR_DIMS(arr));
03910 get_typlenbyvalalign(ARR_ELEMTYPE(arr),
03911 &iterator->typlen,
03912 &iterator->typbyval,
03913 &iterator->typalign);
03914
03915
03916
03917
03918 iterator->slice_ndim = slice_ndim;
03919
03920 if (slice_ndim > 0)
03921 {
03922
03923
03924
03925
03926
03927 iterator->slice_dims = ARR_DIMS(arr) + ARR_NDIM(arr) - slice_ndim;
03928 iterator->slice_lbound = ARR_LBOUND(arr) + ARR_NDIM(arr) - slice_ndim;
03929
03930
03931
03932
03933 iterator->slice_len = ArrayGetNItems(slice_ndim,
03934 iterator->slice_dims);
03935
03936
03937
03938
03939 iterator->slice_values = (Datum *)
03940 palloc(iterator->slice_len * sizeof(Datum));
03941 iterator->slice_nulls = (bool *)
03942 palloc(iterator->slice_len * sizeof(bool));
03943 }
03944
03945
03946
03947
03948
03949 iterator->data_ptr = ARR_DATA_PTR(arr);
03950 iterator->current_item = 0;
03951
03952 return iterator;
03953 }
03954
03955
03956
03957
03958
03959
03960
03961 bool
03962 array_iterate(ArrayIterator iterator, Datum *value, bool *isnull)
03963 {
03964
03965 if (iterator->current_item >= iterator->nitems)
03966 return false;
03967
03968 if (iterator->slice_ndim == 0)
03969 {
03970
03971
03972
03973 if (array_get_isnull(iterator->nullbitmap, iterator->current_item++))
03974 {
03975 *isnull = true;
03976 *value = (Datum) 0;
03977 }
03978 else
03979 {
03980
03981 char *p = iterator->data_ptr;
03982
03983 *isnull = false;
03984 *value = fetch_att(p, iterator->typbyval, iterator->typlen);
03985
03986
03987 p = att_addlength_pointer(p, iterator->typlen, p);
03988 p = (char *) att_align_nominal(p, iterator->typalign);
03989 iterator->data_ptr = p;
03990 }
03991 }
03992 else
03993 {
03994
03995
03996
03997 ArrayType *result;
03998 Datum *values = iterator->slice_values;
03999 bool *nulls = iterator->slice_nulls;
04000 char *p = iterator->data_ptr;
04001 int i;
04002
04003 for (i = 0; i < iterator->slice_len; i++)
04004 {
04005 if (array_get_isnull(iterator->nullbitmap,
04006 iterator->current_item++))
04007 {
04008 nulls[i] = true;
04009 values[i] = (Datum) 0;
04010 }
04011 else
04012 {
04013 nulls[i] = false;
04014 values[i] = fetch_att(p, iterator->typbyval, iterator->typlen);
04015
04016
04017 p = att_addlength_pointer(p, iterator->typlen, p);
04018 p = (char *) att_align_nominal(p, iterator->typalign);
04019 }
04020 }
04021
04022 iterator->data_ptr = p;
04023
04024 result = construct_md_array(values,
04025 nulls,
04026 iterator->slice_ndim,
04027 iterator->slice_dims,
04028 iterator->slice_lbound,
04029 ARR_ELEMTYPE(iterator->arr),
04030 iterator->typlen,
04031 iterator->typbyval,
04032 iterator->typalign);
04033
04034 *isnull = false;
04035 *value = PointerGetDatum(result);
04036 }
04037
04038 return true;
04039 }
04040
04041
04042
04043
04044 void
04045 array_free_iterator(ArrayIterator iterator)
04046 {
04047 if (iterator->slice_ndim > 0)
04048 {
04049 pfree(iterator->slice_values);
04050 pfree(iterator->slice_nulls);
04051 }
04052 pfree(iterator);
04053 }
04054
04055
04056
04057
04058
04059
04060
04061
04062
04063
04064
04065
04066 static bool
04067 array_get_isnull(const bits8 *nullbitmap, int offset)
04068 {
04069 if (nullbitmap == NULL)
04070 return false;
04071 if (nullbitmap[offset / 8] & (1 << (offset % 8)))
04072 return false;
04073 return true;
04074 }
04075
04076
04077
04078
04079
04080
04081
04082
04083 static void
04084 array_set_isnull(bits8 *nullbitmap, int offset, bool isNull)
04085 {
04086 int bitmask;
04087
04088 nullbitmap += offset / 8;
04089 bitmask = 1 << (offset % 8);
04090 if (isNull)
04091 *nullbitmap &= ~bitmask;
04092 else
04093 *nullbitmap |= bitmask;
04094 }
04095
04096
04097
04098
04099
04100
04101 static Datum
04102 ArrayCast(char *value, bool byval, int len)
04103 {
04104 return fetch_att(value, byval, len);
04105 }
04106
04107
04108
04109
04110
04111
04112 static int
04113 ArrayCastAndSet(Datum src,
04114 int typlen,
04115 bool typbyval,
04116 char typalign,
04117 char *dest)
04118 {
04119 int inc;
04120
04121 if (typlen > 0)
04122 {
04123 if (typbyval)
04124 store_att_byval(dest, src, typlen);
04125 else
04126 memmove(dest, DatumGetPointer(src), typlen);
04127 inc = att_align_nominal(typlen, typalign);
04128 }
04129 else
04130 {
04131 Assert(!typbyval);
04132 inc = att_addlength_datum(0, typlen, src);
04133 memmove(dest, DatumGetPointer(src), inc);
04134 inc = att_align_nominal(inc, typalign);
04135 }
04136
04137 return inc;
04138 }
04139
04140
04141
04142
04143
04144
04145
04146
04147
04148
04149
04150
04151 static char *
04152 array_seek(char *ptr, int offset, bits8 *nullbitmap, int nitems,
04153 int typlen, bool typbyval, char typalign)
04154 {
04155 int bitmask;
04156 int i;
04157
04158
04159 if (typlen > 0 && !nullbitmap)
04160 return ptr + nitems * ((Size) att_align_nominal(typlen, typalign));
04161
04162
04163 if (nullbitmap)
04164 {
04165 nullbitmap += offset / 8;
04166 bitmask = 1 << (offset % 8);
04167
04168 for (i = 0; i < nitems; i++)
04169 {
04170 if (*nullbitmap & bitmask)
04171 {
04172 ptr = att_addlength_pointer(ptr, typlen, ptr);
04173 ptr = (char *) att_align_nominal(ptr, typalign);
04174 }
04175 bitmask <<= 1;
04176 if (bitmask == 0x100)
04177 {
04178 nullbitmap++;
04179 bitmask = 1;
04180 }
04181 }
04182 }
04183 else
04184 {
04185 for (i = 0; i < nitems; i++)
04186 {
04187 ptr = att_addlength_pointer(ptr, typlen, ptr);
04188 ptr = (char *) att_align_nominal(ptr, typalign);
04189 }
04190 }
04191 return ptr;
04192 }
04193
04194
04195
04196
04197
04198
04199 static int
04200 array_nelems_size(char *ptr, int offset, bits8 *nullbitmap, int nitems,
04201 int typlen, bool typbyval, char typalign)
04202 {
04203 return array_seek(ptr, offset, nullbitmap, nitems,
04204 typlen, typbyval, typalign) - ptr;
04205 }
04206
04207
04208
04209
04210
04211
04212
04213
04214
04215
04216
04217
04218
04219
04220
04221 static int
04222 array_copy(char *destptr, int nitems,
04223 char *srcptr, int offset, bits8 *nullbitmap,
04224 int typlen, bool typbyval, char typalign)
04225 {
04226 int numbytes;
04227
04228 numbytes = array_nelems_size(srcptr, offset, nullbitmap, nitems,
04229 typlen, typbyval, typalign);
04230 memcpy(destptr, srcptr, numbytes);
04231 return numbytes;
04232 }
04233
04234
04235
04236
04237
04238
04239
04240
04241
04242
04243
04244
04245
04246
04247
04248
04249
04250
04251 void
04252 array_bitmap_copy(bits8 *destbitmap, int destoffset,
04253 const bits8 *srcbitmap, int srcoffset,
04254 int nitems)
04255 {
04256 int destbitmask,
04257 destbitval,
04258 srcbitmask,
04259 srcbitval;
04260
04261 Assert(destbitmap);
04262 if (nitems <= 0)
04263 return;
04264 destbitmap += destoffset / 8;
04265 destbitmask = 1 << (destoffset % 8);
04266 destbitval = *destbitmap;
04267 if (srcbitmap)
04268 {
04269 srcbitmap += srcoffset / 8;
04270 srcbitmask = 1 << (srcoffset % 8);
04271 srcbitval = *srcbitmap;
04272 while (nitems-- > 0)
04273 {
04274 if (srcbitval & srcbitmask)
04275 destbitval |= destbitmask;
04276 else
04277 destbitval &= ~destbitmask;
04278 destbitmask <<= 1;
04279 if (destbitmask == 0x100)
04280 {
04281 *destbitmap++ = destbitval;
04282 destbitmask = 1;
04283 if (nitems > 0)
04284 destbitval = *destbitmap;
04285 }
04286 srcbitmask <<= 1;
04287 if (srcbitmask == 0x100)
04288 {
04289 srcbitmap++;
04290 srcbitmask = 1;
04291 if (nitems > 0)
04292 srcbitval = *srcbitmap;
04293 }
04294 }
04295 if (destbitmask != 1)
04296 *destbitmap = destbitval;
04297 }
04298 else
04299 {
04300 while (nitems-- > 0)
04301 {
04302 destbitval |= destbitmask;
04303 destbitmask <<= 1;
04304 if (destbitmask == 0x100)
04305 {
04306 *destbitmap++ = destbitval;
04307 destbitmask = 1;
04308 if (nitems > 0)
04309 destbitval = *destbitmap;
04310 }
04311 }
04312 if (destbitmask != 1)
04313 *destbitmap = destbitval;
04314 }
04315 }
04316
04317
04318
04319
04320
04321
04322 static int
04323 array_slice_size(char *arraydataptr, bits8 *arraynullsptr,
04324 int ndim, int *dim, int *lb,
04325 int *st, int *endp,
04326 int typlen, bool typbyval, char typalign)
04327 {
04328 int src_offset,
04329 span[MAXDIM],
04330 prod[MAXDIM],
04331 dist[MAXDIM],
04332 indx[MAXDIM];
04333 char *ptr;
04334 int i,
04335 j,
04336 inc;
04337 int count = 0;
04338
04339 mda_get_range(ndim, span, st, endp);
04340
04341
04342 if (typlen > 0 && !arraynullsptr)
04343 return ArrayGetNItems(ndim, span) * att_align_nominal(typlen, typalign);
04344
04345
04346 src_offset = ArrayGetOffset(ndim, dim, lb, st);
04347 ptr = array_seek(arraydataptr, 0, arraynullsptr, src_offset,
04348 typlen, typbyval, typalign);
04349 mda_get_prod(ndim, dim, prod);
04350 mda_get_offset_values(ndim, dist, prod, span);
04351 for (i = 0; i < ndim; i++)
04352 indx[i] = 0;
04353 j = ndim - 1;
04354 do
04355 {
04356 if (dist[j])
04357 {
04358 ptr = array_seek(ptr, src_offset, arraynullsptr, dist[j],
04359 typlen, typbyval, typalign);
04360 src_offset += dist[j];
04361 }
04362 if (!array_get_isnull(arraynullsptr, src_offset))
04363 {
04364 inc = att_addlength_pointer(0, typlen, ptr);
04365 inc = att_align_nominal(inc, typalign);
04366 ptr += inc;
04367 count += inc;
04368 }
04369 src_offset++;
04370 } while ((j = mda_next_tuple(ndim, indx, span)) != -1);
04371 return count;
04372 }
04373
04374
04375
04376
04377
04378
04379
04380
04381
04382 static void
04383 array_extract_slice(ArrayType *newarray,
04384 int ndim,
04385 int *dim,
04386 int *lb,
04387 char *arraydataptr,
04388 bits8 *arraynullsptr,
04389 int *st,
04390 int *endp,
04391 int typlen,
04392 bool typbyval,
04393 char typalign)
04394 {
04395 char *destdataptr = ARR_DATA_PTR(newarray);
04396 bits8 *destnullsptr = ARR_NULLBITMAP(newarray);
04397 char *srcdataptr;
04398 int src_offset,
04399 dest_offset,
04400 prod[MAXDIM],
04401 span[MAXDIM],
04402 dist[MAXDIM],
04403 indx[MAXDIM];
04404 int i,
04405 j,
04406 inc;
04407
04408 src_offset = ArrayGetOffset(ndim, dim, lb, st);
04409 srcdataptr = array_seek(arraydataptr, 0, arraynullsptr, src_offset,
04410 typlen, typbyval, typalign);
04411 mda_get_prod(ndim, dim, prod);
04412 mda_get_range(ndim, span, st, endp);
04413 mda_get_offset_values(ndim, dist, prod, span);
04414 for (i = 0; i < ndim; i++)
04415 indx[i] = 0;
04416 dest_offset = 0;
04417 j = ndim - 1;
04418 do
04419 {
04420 if (dist[j])
04421 {
04422
04423 srcdataptr = array_seek(srcdataptr, src_offset, arraynullsptr,
04424 dist[j],
04425 typlen, typbyval, typalign);
04426 src_offset += dist[j];
04427 }
04428 inc = array_copy(destdataptr, 1,
04429 srcdataptr, src_offset, arraynullsptr,
04430 typlen, typbyval, typalign);
04431 if (destnullsptr)
04432 array_bitmap_copy(destnullsptr, dest_offset,
04433 arraynullsptr, src_offset,
04434 1);
04435 destdataptr += inc;
04436 srcdataptr += inc;
04437 src_offset++;
04438 dest_offset++;
04439 } while ((j = mda_next_tuple(ndim, indx, span)) != -1);
04440 }
04441
04442
04443
04444
04445
04446
04447
04448
04449
04450
04451
04452
04453
04454
04455 static void
04456 array_insert_slice(ArrayType *destArray,
04457 ArrayType *origArray,
04458 ArrayType *srcArray,
04459 int ndim,
04460 int *dim,
04461 int *lb,
04462 int *st,
04463 int *endp,
04464 int typlen,
04465 bool typbyval,
04466 char typalign)
04467 {
04468 char *destPtr = ARR_DATA_PTR(destArray);
04469 char *origPtr = ARR_DATA_PTR(origArray);
04470 char *srcPtr = ARR_DATA_PTR(srcArray);
04471 bits8 *destBitmap = ARR_NULLBITMAP(destArray);
04472 bits8 *origBitmap = ARR_NULLBITMAP(origArray);
04473 bits8 *srcBitmap = ARR_NULLBITMAP(srcArray);
04474 int orignitems = ArrayGetNItems(ARR_NDIM(origArray),
04475 ARR_DIMS(origArray));
04476 int dest_offset,
04477 orig_offset,
04478 src_offset,
04479 prod[MAXDIM],
04480 span[MAXDIM],
04481 dist[MAXDIM],
04482 indx[MAXDIM];
04483 int i,
04484 j,
04485 inc;
04486
04487 dest_offset = ArrayGetOffset(ndim, dim, lb, st);
04488
04489 inc = array_copy(destPtr, dest_offset,
04490 origPtr, 0, origBitmap,
04491 typlen, typbyval, typalign);
04492 destPtr += inc;
04493 origPtr += inc;
04494 if (destBitmap)
04495 array_bitmap_copy(destBitmap, 0, origBitmap, 0, dest_offset);
04496 orig_offset = dest_offset;
04497 mda_get_prod(ndim, dim, prod);
04498 mda_get_range(ndim, span, st, endp);
04499 mda_get_offset_values(ndim, dist, prod, span);
04500 for (i = 0; i < ndim; i++)
04501 indx[i] = 0;
04502 src_offset = 0;
04503 j = ndim - 1;
04504 do
04505 {
04506
04507 if (dist[j])
04508 {
04509 inc = array_copy(destPtr, dist[j],
04510 origPtr, orig_offset, origBitmap,
04511 typlen, typbyval, typalign);
04512 destPtr += inc;
04513 origPtr += inc;
04514 if (destBitmap)
04515 array_bitmap_copy(destBitmap, dest_offset,
04516 origBitmap, orig_offset,
04517 dist[j]);
04518 dest_offset += dist[j];
04519 orig_offset += dist[j];
04520 }
04521
04522 inc = array_copy(destPtr, 1,
04523 srcPtr, src_offset, srcBitmap,
04524 typlen, typbyval, typalign);
04525 if (destBitmap)
04526 array_bitmap_copy(destBitmap, dest_offset,
04527 srcBitmap, src_offset,
04528 1);
04529 destPtr += inc;
04530 srcPtr += inc;
04531 dest_offset++;
04532 src_offset++;
04533
04534 origPtr = array_seek(origPtr, orig_offset, origBitmap, 1,
04535 typlen, typbyval, typalign);
04536 orig_offset++;
04537 } while ((j = mda_next_tuple(ndim, indx, span)) != -1);
04538
04539
04540 array_copy(destPtr, orignitems - orig_offset,
04541 origPtr, orig_offset, origBitmap,
04542 typlen, typbyval, typalign);
04543 if (destBitmap)
04544 array_bitmap_copy(destBitmap, dest_offset,
04545 origBitmap, orig_offset,
04546 orignitems - orig_offset);
04547 }
04548
04549
04550
04551
04552
04553
04554
04555 ArrayBuildState *
04556 accumArrayResult(ArrayBuildState *astate,
04557 Datum dvalue, bool disnull,
04558 Oid element_type,
04559 MemoryContext rcontext)
04560 {
04561 MemoryContext arr_context,
04562 oldcontext;
04563
04564 if (astate == NULL)
04565 {
04566
04567
04568
04569 arr_context = AllocSetContextCreate(rcontext,
04570 "accumArrayResult",
04571 ALLOCSET_DEFAULT_MINSIZE,
04572 ALLOCSET_DEFAULT_INITSIZE,
04573 ALLOCSET_DEFAULT_MAXSIZE);
04574 oldcontext = MemoryContextSwitchTo(arr_context);
04575 astate = (ArrayBuildState *) palloc(sizeof(ArrayBuildState));
04576 astate->mcontext = arr_context;
04577 astate->alen = 64;
04578 astate->dvalues = (Datum *) palloc(astate->alen * sizeof(Datum));
04579 astate->dnulls = (bool *) palloc(astate->alen * sizeof(bool));
04580 astate->nelems = 0;
04581 astate->element_type = element_type;
04582 get_typlenbyvalalign(element_type,
04583 &astate->typlen,
04584 &astate->typbyval,
04585 &astate->typalign);
04586 }
04587 else
04588 {
04589 oldcontext = MemoryContextSwitchTo(astate->mcontext);
04590 Assert(astate->element_type == element_type);
04591
04592 if (astate->nelems >= astate->alen)
04593 {
04594 astate->alen *= 2;
04595 astate->dvalues = (Datum *)
04596 repalloc(astate->dvalues, astate->alen * sizeof(Datum));
04597 astate->dnulls = (bool *)
04598 repalloc(astate->dnulls, astate->alen * sizeof(bool));
04599 }
04600 }
04601
04602
04603
04604
04605
04606
04607
04608
04609
04610 if (!disnull && !astate->typbyval)
04611 {
04612 if (astate->typlen == -1)
04613 dvalue = PointerGetDatum(PG_DETOAST_DATUM_COPY(dvalue));
04614 else
04615 dvalue = datumCopy(dvalue, astate->typbyval, astate->typlen);
04616 }
04617
04618 astate->dvalues[astate->nelems] = dvalue;
04619 astate->dnulls[astate->nelems] = disnull;
04620 astate->nelems++;
04621
04622 MemoryContextSwitchTo(oldcontext);
04623
04624 return astate;
04625 }
04626
04627
04628
04629
04630
04631
04632
04633 Datum
04634 makeArrayResult(ArrayBuildState *astate,
04635 MemoryContext rcontext)
04636 {
04637 int dims[1];
04638 int lbs[1];
04639
04640 dims[0] = astate->nelems;
04641 lbs[0] = 1;
04642
04643 return makeMdArrayResult(astate, 1, dims, lbs, rcontext, true);
04644 }
04645
04646
04647
04648
04649
04650
04651
04652
04653
04654
04655
04656 Datum
04657 makeMdArrayResult(ArrayBuildState *astate,
04658 int ndims,
04659 int *dims,
04660 int *lbs,
04661 MemoryContext rcontext,
04662 bool release)
04663 {
04664 ArrayType *result;
04665 MemoryContext oldcontext;
04666
04667
04668 oldcontext = MemoryContextSwitchTo(rcontext);
04669
04670 result = construct_md_array(astate->dvalues,
04671 astate->dnulls,
04672 ndims,
04673 dims,
04674 lbs,
04675 astate->element_type,
04676 astate->typlen,
04677 astate->typbyval,
04678 astate->typalign);
04679
04680 MemoryContextSwitchTo(oldcontext);
04681
04682
04683 if (release)
04684 MemoryContextDelete(astate->mcontext);
04685
04686 return PointerGetDatum(result);
04687 }
04688
04689 Datum
04690 array_larger(PG_FUNCTION_ARGS)
04691 {
04692 ArrayType *v1,
04693 *v2,
04694 *result;
04695
04696 v1 = PG_GETARG_ARRAYTYPE_P(0);
04697 v2 = PG_GETARG_ARRAYTYPE_P(1);
04698
04699 result = ((array_cmp(fcinfo) > 0) ? v1 : v2);
04700
04701 PG_RETURN_ARRAYTYPE_P(result);
04702 }
04703
04704 Datum
04705 array_smaller(PG_FUNCTION_ARGS)
04706 {
04707 ArrayType *v1,
04708 *v2,
04709 *result;
04710
04711 v1 = PG_GETARG_ARRAYTYPE_P(0);
04712 v2 = PG_GETARG_ARRAYTYPE_P(1);
04713
04714 result = ((array_cmp(fcinfo) < 0) ? v1 : v2);
04715
04716 PG_RETURN_ARRAYTYPE_P(result);
04717 }
04718
04719
04720 typedef struct generate_subscripts_fctx
04721 {
04722 int32 lower;
04723 int32 upper;
04724 bool reverse;
04725 } generate_subscripts_fctx;
04726
04727
04728
04729
04730
04731 Datum
04732 generate_subscripts(PG_FUNCTION_ARGS)
04733 {
04734 FuncCallContext *funcctx;
04735 MemoryContext oldcontext;
04736 generate_subscripts_fctx *fctx;
04737
04738
04739 if (SRF_IS_FIRSTCALL())
04740 {
04741 ArrayType *v = PG_GETARG_ARRAYTYPE_P(0);
04742 int reqdim = PG_GETARG_INT32(1);
04743 int *lb,
04744 *dimv;
04745
04746
04747 funcctx = SRF_FIRSTCALL_INIT();
04748
04749
04750 if (ARR_NDIM(v) <= 0 || ARR_NDIM(v) > MAXDIM)
04751 SRF_RETURN_DONE(funcctx);
04752
04753
04754 if (reqdim <= 0 || reqdim > ARR_NDIM(v))
04755 SRF_RETURN_DONE(funcctx);
04756
04757
04758
04759
04760 oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
04761 fctx = (generate_subscripts_fctx *) palloc(sizeof(generate_subscripts_fctx));
04762
04763 lb = ARR_LBOUND(v);
04764 dimv = ARR_DIMS(v);
04765
04766 fctx->lower = lb[reqdim - 1];
04767 fctx->upper = dimv[reqdim - 1] + lb[reqdim - 1] - 1;
04768 fctx->reverse = (PG_NARGS() < 3) ? false : PG_GETARG_BOOL(2);
04769
04770 funcctx->user_fctx = fctx;
04771
04772 MemoryContextSwitchTo(oldcontext);
04773 }
04774
04775 funcctx = SRF_PERCALL_SETUP();
04776
04777 fctx = funcctx->user_fctx;
04778
04779 if (fctx->lower <= fctx->upper)
04780 {
04781 if (!fctx->reverse)
04782 SRF_RETURN_NEXT(funcctx, Int32GetDatum(fctx->lower++));
04783 else
04784 SRF_RETURN_NEXT(funcctx, Int32GetDatum(fctx->upper--));
04785 }
04786 else
04787
04788 SRF_RETURN_DONE(funcctx);
04789 }
04790
04791
04792
04793
04794
04795 Datum
04796 generate_subscripts_nodir(PG_FUNCTION_ARGS)
04797 {
04798
04799 return generate_subscripts(fcinfo);
04800 }
04801
04802
04803
04804
04805
04806 Datum
04807 array_fill_with_lower_bounds(PG_FUNCTION_ARGS)
04808 {
04809 ArrayType *dims;
04810 ArrayType *lbs;
04811 ArrayType *result;
04812 Oid elmtype;
04813 Datum value;
04814 bool isnull;
04815
04816 if (PG_ARGISNULL(1) || PG_ARGISNULL(2))
04817 ereport(ERROR,
04818 (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
04819 errmsg("dimension array or low bound array cannot be null")));
04820
04821 dims = PG_GETARG_ARRAYTYPE_P(1);
04822 lbs = PG_GETARG_ARRAYTYPE_P(2);
04823
04824 if (!PG_ARGISNULL(0))
04825 {
04826 value = PG_GETARG_DATUM(0);
04827 isnull = false;
04828 }
04829 else
04830 {
04831 value = 0;
04832 isnull = true;
04833 }
04834
04835 elmtype = get_fn_expr_argtype(fcinfo->flinfo, 0);
04836 if (!OidIsValid(elmtype))
04837 elog(ERROR, "could not determine data type of input");
04838
04839 result = array_fill_internal(dims, lbs, value, isnull, elmtype, fcinfo);
04840 PG_RETURN_ARRAYTYPE_P(result);
04841 }
04842
04843
04844
04845
04846
04847 Datum
04848 array_fill(PG_FUNCTION_ARGS)
04849 {
04850 ArrayType *dims;
04851 ArrayType *result;
04852 Oid elmtype;
04853 Datum value;
04854 bool isnull;
04855
04856 if (PG_ARGISNULL(1))
04857 ereport(ERROR,
04858 (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
04859 errmsg("dimension array or low bound array cannot be null")));
04860
04861 dims = PG_GETARG_ARRAYTYPE_P(1);
04862
04863 if (!PG_ARGISNULL(0))
04864 {
04865 value = PG_GETARG_DATUM(0);
04866 isnull = false;
04867 }
04868 else
04869 {
04870 value = 0;
04871 isnull = true;
04872 }
04873
04874 elmtype = get_fn_expr_argtype(fcinfo->flinfo, 0);
04875 if (!OidIsValid(elmtype))
04876 elog(ERROR, "could not determine data type of input");
04877
04878 result = array_fill_internal(dims, NULL, value, isnull, elmtype, fcinfo);
04879 PG_RETURN_ARRAYTYPE_P(result);
04880 }
04881
04882 static ArrayType *
04883 create_array_envelope(int ndims, int *dimv, int *lbsv, int nbytes,
04884 Oid elmtype, int dataoffset)
04885 {
04886 ArrayType *result;
04887
04888 result = (ArrayType *) palloc0(nbytes);
04889 SET_VARSIZE(result, nbytes);
04890 result->ndim = ndims;
04891 result->dataoffset = dataoffset;
04892 result->elemtype = elmtype;
04893 memcpy(ARR_DIMS(result), dimv, ndims * sizeof(int));
04894 memcpy(ARR_LBOUND(result), lbsv, ndims * sizeof(int));
04895
04896 return result;
04897 }
04898
04899 static ArrayType *
04900 array_fill_internal(ArrayType *dims, ArrayType *lbs,
04901 Datum value, bool isnull, Oid elmtype,
04902 FunctionCallInfo fcinfo)
04903 {
04904 ArrayType *result;
04905 int *dimv;
04906 int *lbsv;
04907 int ndims;
04908 int nitems;
04909 int deflbs[MAXDIM];
04910 int16 elmlen;
04911 bool elmbyval;
04912 char elmalign;
04913 ArrayMetaState *my_extra;
04914
04915
04916
04917
04918 if (ARR_NDIM(dims) != 1)
04919 ereport(ERROR,
04920 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
04921 errmsg("wrong number of array subscripts"),
04922 errdetail("Dimension array must be one dimensional.")));
04923
04924 if (ARR_LBOUND(dims)[0] != 1)
04925 ereport(ERROR,
04926 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
04927 errmsg("wrong range of array subscripts"),
04928 errdetail("Lower bound of dimension array must be one.")));
04929
04930 if (array_contains_nulls(dims))
04931 ereport(ERROR,
04932 (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
04933 errmsg("dimension values cannot be null")));
04934
04935 dimv = (int *) ARR_DATA_PTR(dims);
04936 ndims = ARR_DIMS(dims)[0];
04937
04938 if (ndims < 0)
04939 ereport(ERROR,
04940 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
04941 errmsg("invalid number of dimensions: %d", ndims)));
04942 if (ndims > MAXDIM)
04943 ereport(ERROR,
04944 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
04945 errmsg("number of array dimensions (%d) exceeds the maximum allowed (%d)",
04946 ndims, MAXDIM)));
04947
04948 if (lbs != NULL)
04949 {
04950 if (ARR_NDIM(lbs) != 1)
04951 ereport(ERROR,
04952 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
04953 errmsg("wrong number of array subscripts"),
04954 errdetail("Dimension array must be one dimensional.")));
04955
04956 if (ARR_LBOUND(lbs)[0] != 1)
04957 ereport(ERROR,
04958 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
04959 errmsg("wrong range of array subscripts"),
04960 errdetail("Lower bound of dimension array must be one.")));
04961
04962 if (array_contains_nulls(lbs))
04963 ereport(ERROR,
04964 (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
04965 errmsg("dimension values cannot be null")));
04966
04967 if (ARR_DIMS(lbs)[0] != ndims)
04968 ereport(ERROR,
04969 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
04970 errmsg("wrong number of array subscripts"),
04971 errdetail("Low bound array has different size than dimensions array.")));
04972
04973 lbsv = (int *) ARR_DATA_PTR(lbs);
04974 }
04975 else
04976 {
04977 int i;
04978
04979 for (i = 0; i < MAXDIM; i++)
04980 deflbs[i] = 1;
04981
04982 lbsv = deflbs;
04983 }
04984
04985
04986 if (ndims == 0)
04987 return construct_empty_array(elmtype);
04988
04989 nitems = ArrayGetNItems(ndims, dimv);
04990
04991
04992
04993
04994
04995 my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra;
04996 if (my_extra == NULL)
04997 {
04998 fcinfo->flinfo->fn_extra = MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
04999 sizeof(ArrayMetaState));
05000 my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra;
05001 my_extra->element_type = InvalidOid;
05002 }
05003
05004 if (my_extra->element_type != elmtype)
05005 {
05006
05007 get_typlenbyvalalign(elmtype,
05008 &my_extra->typlen,
05009 &my_extra->typbyval,
05010 &my_extra->typalign);
05011 my_extra->element_type = elmtype;
05012 }
05013
05014 elmlen = my_extra->typlen;
05015 elmbyval = my_extra->typbyval;
05016 elmalign = my_extra->typalign;
05017
05018
05019 if (!isnull)
05020 {
05021 int i;
05022 char *p;
05023 int nbytes;
05024 int totbytes;
05025
05026
05027 if (elmlen == -1)
05028 value = PointerGetDatum(PG_DETOAST_DATUM(value));
05029
05030 nbytes = att_addlength_datum(0, elmlen, value);
05031 nbytes = att_align_nominal(nbytes, elmalign);
05032 Assert(nbytes > 0);
05033
05034 totbytes = nbytes * nitems;
05035
05036
05037 if (totbytes / nbytes != nitems ||
05038 !AllocSizeIsValid(totbytes))
05039 ereport(ERROR,
05040 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
05041 errmsg("array size exceeds the maximum allowed (%d)",
05042 (int) MaxAllocSize)));
05043
05044
05045
05046
05047
05048 totbytes += ARR_OVERHEAD_NONULLS(ndims);
05049
05050 result = create_array_envelope(ndims, dimv, lbsv, totbytes,
05051 elmtype, 0);
05052
05053 p = ARR_DATA_PTR(result);
05054 for (i = 0; i < nitems; i++)
05055 p += ArrayCastAndSet(value, elmlen, elmbyval, elmalign, p);
05056 }
05057 else
05058 {
05059 int nbytes;
05060 int dataoffset;
05061
05062 dataoffset = ARR_OVERHEAD_WITHNULLS(ndims, nitems);
05063 nbytes = dataoffset;
05064
05065 result = create_array_envelope(ndims, dimv, lbsv, nbytes,
05066 elmtype, dataoffset);
05067
05068
05069 }
05070
05071 return result;
05072 }
05073
05074
05075
05076
05077
05078 Datum
05079 array_unnest(PG_FUNCTION_ARGS)
05080 {
05081 typedef struct
05082 {
05083 ArrayType *arr;
05084 int nextelem;
05085 int numelems;
05086 char *elemdataptr;
05087 bits8 *arraynullsptr;
05088 int16 elmlen;
05089 bool elmbyval;
05090 char elmalign;
05091 } array_unnest_fctx;
05092
05093 FuncCallContext *funcctx;
05094 array_unnest_fctx *fctx;
05095 MemoryContext oldcontext;
05096
05097
05098 if (SRF_IS_FIRSTCALL())
05099 {
05100 ArrayType *arr;
05101
05102
05103 funcctx = SRF_FIRSTCALL_INIT();
05104
05105
05106
05107
05108 oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
05109
05110
05111
05112
05113
05114
05115
05116
05117 arr = PG_GETARG_ARRAYTYPE_P(0);
05118
05119
05120 fctx = (array_unnest_fctx *) palloc(sizeof(array_unnest_fctx));
05121
05122
05123 fctx->arr = arr;
05124 fctx->nextelem = 0;
05125 fctx->numelems = ArrayGetNItems(ARR_NDIM(arr), ARR_DIMS(arr));
05126
05127 fctx->elemdataptr = ARR_DATA_PTR(arr);
05128 fctx->arraynullsptr = ARR_NULLBITMAP(arr);
05129
05130 get_typlenbyvalalign(ARR_ELEMTYPE(arr),
05131 &fctx->elmlen,
05132 &fctx->elmbyval,
05133 &fctx->elmalign);
05134
05135 funcctx->user_fctx = fctx;
05136 MemoryContextSwitchTo(oldcontext);
05137 }
05138
05139
05140 funcctx = SRF_PERCALL_SETUP();
05141 fctx = funcctx->user_fctx;
05142
05143 if (fctx->nextelem < fctx->numelems)
05144 {
05145 int offset = fctx->nextelem++;
05146 Datum elem;
05147
05148
05149
05150
05151 if (array_get_isnull(fctx->arraynullsptr, offset))
05152 {
05153 fcinfo->isnull = true;
05154 elem = (Datum) 0;
05155
05156 }
05157 else
05158 {
05159
05160
05161
05162 char *ptr = fctx->elemdataptr;
05163
05164 fcinfo->isnull = false;
05165 elem = ArrayCast(ptr, fctx->elmbyval, fctx->elmlen);
05166
05167
05168
05169
05170 ptr = att_addlength_pointer(ptr, fctx->elmlen, ptr);
05171 ptr = (char *) att_align_nominal(ptr, fctx->elmalign);
05172 fctx->elemdataptr = ptr;
05173 }
05174
05175 SRF_RETURN_NEXT(funcctx, elem);
05176 }
05177 else
05178 {
05179
05180 SRF_RETURN_DONE(funcctx);
05181 }
05182 }
05183
05184
05185
05186
05187
05188
05189
05190
05191
05192
05193 static ArrayType *
05194 array_replace_internal(ArrayType *array,
05195 Datum search, bool search_isnull,
05196 Datum replace, bool replace_isnull,
05197 bool remove, Oid collation,
05198 FunctionCallInfo fcinfo)
05199 {
05200 ArrayType *result;
05201 Oid element_type;
05202 Datum *values;
05203 bool *nulls;
05204 int *dim;
05205 int ndim;
05206 int nitems,
05207 nresult;
05208 int i;
05209 int32 nbytes = 0;
05210 int32 dataoffset;
05211 bool hasnulls;
05212 int typlen;
05213 bool typbyval;
05214 char typalign;
05215 char *arraydataptr;
05216 bits8 *bitmap;
05217 int bitmask;
05218 bool changed = false;
05219 TypeCacheEntry *typentry;
05220 FunctionCallInfoData locfcinfo;
05221
05222 element_type = ARR_ELEMTYPE(array);
05223 ndim = ARR_NDIM(array);
05224 dim = ARR_DIMS(array);
05225 nitems = ArrayGetNItems(ndim, dim);
05226
05227
05228 if (nitems <= 0)
05229 return array;
05230
05231
05232
05233
05234
05235 if (remove && ndim > 1)
05236 ereport(ERROR,
05237 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
05238 errmsg("removing elements from multidimensional arrays is not supported")));
05239
05240
05241
05242
05243
05244 typentry = (TypeCacheEntry *) fcinfo->flinfo->fn_extra;
05245 if (typentry == NULL ||
05246 typentry->type_id != element_type)
05247 {
05248 typentry = lookup_type_cache(element_type,
05249 TYPECACHE_EQ_OPR_FINFO);
05250 if (!OidIsValid(typentry->eq_opr_finfo.fn_oid))
05251 ereport(ERROR,
05252 (errcode(ERRCODE_UNDEFINED_FUNCTION),
05253 errmsg("could not identify an equality operator for type %s",
05254 format_type_be(element_type))));
05255 fcinfo->flinfo->fn_extra = (void *) typentry;
05256 }
05257 typlen = typentry->typlen;
05258 typbyval = typentry->typbyval;
05259 typalign = typentry->typalign;
05260
05261
05262
05263
05264
05265
05266 if (typlen == -1)
05267 {
05268 if (!search_isnull)
05269 search = PointerGetDatum(PG_DETOAST_DATUM(search));
05270 if (!replace_isnull)
05271 replace = PointerGetDatum(PG_DETOAST_DATUM(replace));
05272 }
05273
05274
05275 InitFunctionCallInfoData(locfcinfo, &typentry->eq_opr_finfo, 2,
05276 collation, NULL, NULL);
05277
05278
05279 values = (Datum *) palloc(nitems * sizeof(Datum));
05280 nulls = (bool *) palloc(nitems * sizeof(bool));
05281
05282
05283 arraydataptr = ARR_DATA_PTR(array);
05284 bitmap = ARR_NULLBITMAP(array);
05285 bitmask = 1;
05286 hasnulls = false;
05287 nresult = 0;
05288
05289 for (i = 0; i < nitems; i++)
05290 {
05291 Datum elt;
05292 bool isNull;
05293 bool oprresult;
05294 bool skip = false;
05295
05296
05297 if (bitmap && (*bitmap & bitmask) == 0)
05298 {
05299 isNull = true;
05300
05301 if (search_isnull)
05302 {
05303 if (remove)
05304 {
05305 skip = true;
05306 changed = true;
05307 }
05308 else if (!replace_isnull)
05309 {
05310 values[nresult] = replace;
05311 isNull = false;
05312 changed = true;
05313 }
05314 }
05315 }
05316 else
05317 {
05318 isNull = false;
05319 elt = fetch_att(arraydataptr, typbyval, typlen);
05320 arraydataptr = att_addlength_datum(arraydataptr, typlen, elt);
05321 arraydataptr = (char *) att_align_nominal(arraydataptr, typalign);
05322
05323 if (search_isnull)
05324 {
05325
05326 values[nresult] = elt;
05327 }
05328 else
05329 {
05330
05331
05332
05333 locfcinfo.arg[0] = elt;
05334 locfcinfo.arg[1] = search;
05335 locfcinfo.argnull[0] = false;
05336 locfcinfo.argnull[1] = false;
05337 locfcinfo.isnull = false;
05338 oprresult = DatumGetBool(FunctionCallInvoke(&locfcinfo));
05339 if (!oprresult)
05340 {
05341
05342 values[nresult] = elt;
05343 }
05344 else
05345 {
05346
05347 changed = true;
05348 if (remove)
05349 skip = true;
05350 else
05351 {
05352 values[nresult] = replace;
05353 isNull = replace_isnull;
05354 }
05355 }
05356 }
05357 }
05358
05359 if (!skip)
05360 {
05361 nulls[nresult] = isNull;
05362 if (isNull)
05363 hasnulls = true;
05364 else
05365 {
05366
05367 nbytes = att_addlength_datum(nbytes, typlen, values[nresult]);
05368 nbytes = att_align_nominal(nbytes, typalign);
05369
05370 if (!AllocSizeIsValid(nbytes))
05371 ereport(ERROR,
05372 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
05373 errmsg("array size exceeds the maximum allowed (%d)",
05374 (int) MaxAllocSize)));
05375 }
05376 nresult++;
05377 }
05378
05379
05380 if (bitmap)
05381 {
05382 bitmask <<= 1;
05383 if (bitmask == 0x100)
05384 {
05385 bitmap++;
05386 bitmask = 1;
05387 }
05388 }
05389 }
05390
05391
05392
05393
05394 if (!changed)
05395 {
05396 pfree(values);
05397 pfree(nulls);
05398 return array;
05399 }
05400
05401
05402 if (hasnulls)
05403 {
05404 dataoffset = ARR_OVERHEAD_WITHNULLS(ndim, nresult);
05405 nbytes += dataoffset;
05406 }
05407 else
05408 {
05409 dataoffset = 0;
05410 nbytes += ARR_OVERHEAD_NONULLS(ndim);
05411 }
05412 result = (ArrayType *) palloc0(nbytes);
05413 SET_VARSIZE(result, nbytes);
05414 result->ndim = ndim;
05415 result->dataoffset = dataoffset;
05416 result->elemtype = element_type;
05417 memcpy(ARR_DIMS(result), ARR_DIMS(array), 2 * ndim * sizeof(int));
05418
05419 if (remove)
05420 {
05421
05422 ARR_DIMS(result)[0] = nresult;
05423 }
05424
05425
05426 CopyArrayEls(result,
05427 values, nulls, nresult,
05428 typlen, typbyval, typalign,
05429 false);
05430
05431 pfree(values);
05432 pfree(nulls);
05433
05434 return result;
05435 }
05436
05437
05438
05439
05440
05441
05442 Datum
05443 array_remove(PG_FUNCTION_ARGS)
05444 {
05445 ArrayType *array;
05446 Datum search = PG_GETARG_DATUM(1);
05447 bool search_isnull = PG_ARGISNULL(1);
05448
05449 if (PG_ARGISNULL(0))
05450 PG_RETURN_NULL();
05451 array = PG_GETARG_ARRAYTYPE_P(0);
05452
05453 array = array_replace_internal(array,
05454 search, search_isnull,
05455 (Datum) 0, true,
05456 true, PG_GET_COLLATION(),
05457 fcinfo);
05458 PG_RETURN_ARRAYTYPE_P(array);
05459 }
05460
05461
05462
05463
05464 Datum
05465 array_replace(PG_FUNCTION_ARGS)
05466 {
05467 ArrayType *array;
05468 Datum search = PG_GETARG_DATUM(1);
05469 bool search_isnull = PG_ARGISNULL(1);
05470 Datum replace = PG_GETARG_DATUM(2);
05471 bool replace_isnull = PG_ARGISNULL(2);
05472
05473 if (PG_ARGISNULL(0))
05474 PG_RETURN_NULL();
05475 array = PG_GETARG_ARRAYTYPE_P(0);
05476
05477 array = array_replace_internal(array,
05478 search, search_isnull,
05479 replace, replace_isnull,
05480 false, PG_GET_COLLATION(),
05481 fcinfo);
05482 PG_RETURN_ARRAYTYPE_P(array);
05483 }