diff --git a/contrib/hstore/hstore_gin.c b/contrib/hstore/hstore_gin.c index 766c00bb6a7..b6bd617df45 100644 --- a/contrib/hstore/hstore_gin.c +++ b/contrib/hstore/hstore_gin.c @@ -127,7 +127,7 @@ gin_extract_hstore_query(PG_FUNCTION_ARGS) /* Nulls in the array are ignored, cf hstoreArrayToPairs */ if (key_nulls[i]) continue; - item = makeitem(VARDATA(key_datums[i]), VARSIZE(key_datums[i]) - VARHDRSZ, KEYFLAG); + item = makeitem(VARDATA_ANY(key_datums[i]), VARSIZE_ANY_EXHDR(key_datums[i]), KEYFLAG); entries[j++] = PointerGetDatum(item); } diff --git a/contrib/hstore/hstore_gist.c b/contrib/hstore/hstore_gist.c index a3b08af3850..9e330d7be4f 100644 --- a/contrib/hstore/hstore_gist.c +++ b/contrib/hstore/hstore_gist.c @@ -576,7 +576,7 @@ ghstore_consistent(PG_FUNCTION_ARGS) if (key_nulls[i]) continue; - crc = crc32_sz(VARDATA(key_datums[i]), VARSIZE(key_datums[i]) - VARHDRSZ); + crc = crc32_sz(VARDATA_ANY(key_datums[i]), VARSIZE_ANY_EXHDR(key_datums[i])); if (!(GETBIT(sign, HASHVAL(crc, siglen)))) res = false; } @@ -599,7 +599,7 @@ ghstore_consistent(PG_FUNCTION_ARGS) if (key_nulls[i]) continue; - crc = crc32_sz(VARDATA(key_datums[i]), VARSIZE(key_datums[i]) - VARHDRSZ); + crc = crc32_sz(VARDATA_ANY(key_datums[i]), VARSIZE_ANY_EXHDR(key_datums[i])); if (GETBIT(sign, HASHVAL(crc, siglen))) res = true; } diff --git a/contrib/hstore/hstore_io.c b/contrib/hstore/hstore_io.c index 2125436e40c..51461a6ec32 100644 --- a/contrib/hstore/hstore_io.c +++ b/contrib/hstore/hstore_io.c @@ -681,22 +681,22 @@ hstore_from_arrays(PG_FUNCTION_ARGS) if (!value_nulls || value_nulls[i]) { - pairs[i].key = VARDATA(key_datums[i]); + pairs[i].key = VARDATA_ANY(key_datums[i]); pairs[i].val = NULL; pairs[i].keylen = - hstoreCheckKeyLen(VARSIZE(key_datums[i]) - VARHDRSZ); + hstoreCheckKeyLen(VARSIZE_ANY_EXHDR(key_datums[i])); pairs[i].vallen = 4; pairs[i].isnull = true; pairs[i].needfree = false; } else { - pairs[i].key = VARDATA(key_datums[i]); - pairs[i].val = VARDATA(value_datums[i]); + pairs[i].key = VARDATA_ANY(key_datums[i]); + pairs[i].val = VARDATA_ANY(value_datums[i]); pairs[i].keylen = - hstoreCheckKeyLen(VARSIZE(key_datums[i]) - VARHDRSZ); + hstoreCheckKeyLen(VARSIZE_ANY_EXHDR(key_datums[i])); pairs[i].vallen = - hstoreCheckValLen(VARSIZE(value_datums[i]) - VARHDRSZ); + hstoreCheckValLen(VARSIZE_ANY_EXHDR(value_datums[i])); pairs[i].isnull = false; pairs[i].needfree = false; } @@ -775,22 +775,22 @@ hstore_from_array(PG_FUNCTION_ARGS) if (in_nulls[i * 2 + 1]) { - pairs[i].key = VARDATA(in_datums[i * 2]); + pairs[i].key = VARDATA_ANY(in_datums[i * 2]); pairs[i].val = NULL; pairs[i].keylen = - hstoreCheckKeyLen(VARSIZE(in_datums[i * 2]) - VARHDRSZ); + hstoreCheckKeyLen(VARSIZE_ANY_EXHDR(in_datums[i * 2])); pairs[i].vallen = 4; pairs[i].isnull = true; pairs[i].needfree = false; } else { - pairs[i].key = VARDATA(in_datums[i * 2]); - pairs[i].val = VARDATA(in_datums[i * 2 + 1]); + pairs[i].key = VARDATA_ANY(in_datums[i * 2]); + pairs[i].val = VARDATA_ANY(in_datums[i * 2 + 1]); pairs[i].keylen = - hstoreCheckKeyLen(VARSIZE(in_datums[i * 2]) - VARHDRSZ); + hstoreCheckKeyLen(VARSIZE_ANY_EXHDR(in_datums[i * 2])); pairs[i].vallen = - hstoreCheckValLen(VARSIZE(in_datums[i * 2 + 1]) - VARHDRSZ); + hstoreCheckValLen(VARSIZE_ANY_EXHDR(in_datums[i * 2 + 1])); pairs[i].isnull = false; pairs[i].needfree = false; } diff --git a/contrib/hstore/hstore_op.c b/contrib/hstore/hstore_op.c index 5e57eceffc8..da6aa12e8c4 100644 --- a/contrib/hstore/hstore_op.c +++ b/contrib/hstore/hstore_op.c @@ -107,8 +107,8 @@ hstoreArrayToPairs(ArrayType *a, int *npairs) { if (!key_nulls[i]) { - key_pairs[j].key = VARDATA(key_datums[i]); - key_pairs[j].keylen = VARSIZE(key_datums[i]) - VARHDRSZ; + key_pairs[j].key = VARDATA_ANY(key_datums[i]); + key_pairs[j].keylen = VARSIZE_ANY_EXHDR(key_datums[i]); key_pairs[j].val = NULL; key_pairs[j].vallen = 0; key_pairs[j].needfree = 0; @@ -599,7 +599,7 @@ hstore_slice_to_array(PG_FUNCTION_ARGS) if (key_nulls[i]) idx = -1; else - idx = hstoreFindKey(hs, NULL, VARDATA(key), VARSIZE(key) - VARHDRSZ); + idx = hstoreFindKey(hs, NULL, VARDATA_ANY(key), VARSIZE_ANY_EXHDR(key)); if (idx < 0 || HSTORE_VALISNULL(entries, idx)) { @@ -619,7 +619,8 @@ hstore_slice_to_array(PG_FUNCTION_ARGS) ARR_NDIM(key_array), ARR_DIMS(key_array), ARR_LBOUND(key_array), - TEXTOID, -1, false, TYPALIGN_INT); + TEXTOID, -1, false, + TYPALIGN_INT, TYPSTORAGE_EXTENDED); PG_RETURN_POINTER(aout); } @@ -762,7 +763,8 @@ hstore_avals(PG_FUNCTION_ARGS) } a = construct_md_array(d, nulls, 1, &count, &lb, - TEXTOID, -1, false, TYPALIGN_INT); + TEXTOID, -1, false, + TYPALIGN_INT, TYPSTORAGE_EXTENDED); PG_RETURN_POINTER(a); } @@ -814,7 +816,8 @@ hstore_to_array_internal(HStore *hs, int ndims) return construct_md_array(out_datums, out_nulls, ndims, out_size, lb, - TEXTOID, -1, false, TYPALIGN_INT); + TEXTOID, -1, false, + TYPALIGN_INT, TYPSTORAGE_EXTENDED); } PG_FUNCTION_INFO_V1(hstore_to_array); diff --git a/contrib/ltree/_ltree_gist.c b/contrib/ltree/_ltree_gist.c index 286ad24fbe8..ce84ee89d8e 100644 --- a/contrib/ltree/_ltree_gist.c +++ b/contrib/ltree/_ltree_gist.c @@ -26,7 +26,7 @@ PG_FUNCTION_INFO_V1(_ltree_consistent); PG_FUNCTION_INFO_V1(_ltree_gist_options); #define GETENTRY(vec,pos) ((ltree_gist *) DatumGetPointer((vec)->vector[(pos)].key)) -#define NEXTVAL(x) ( (ltree*)( (char*)(x) + INTALIGN( VARSIZE(x) ) ) ) +#define NEXTVAL(x) ( (ltree*)( (char*)(x) + INTALIGN( VARSIZE_ANY(x) ) ) ) #define WISH_F(a,b,c) (double)( -(double)(((a)-(b))*((a)-(b))*((a)-(b)))*(c) ) @@ -60,6 +60,7 @@ _ltree_compress(PG_FUNCTION_ARGS) ArrayType *val = DatumGetArrayTypeP(entry->key); int num = ArrayGetNItems(ARR_NDIM(val), ARR_DIMS(val)); ltree *item = (ltree *) ARR_DATA_PTR(val); + ltree *newitem; if (ARR_NDIM(val) > 1) ereport(ERROR, @@ -74,7 +75,10 @@ _ltree_compress(PG_FUNCTION_ARGS) while (num > 0) { - hashing(LTG_SIGN(key), item, siglen); + newitem = (ltree *)ltree_norm_short_item((char *)item); + + hashing(LTG_SIGN(key), newitem, siglen); + PFREE_IF_NEW(newitem, item); num--; item = NEXTVAL(item); } @@ -481,6 +485,7 @@ static bool _arrq_cons(ltree_gist *key, ArrayType *_query, int siglen) { lquery *query = (lquery *) ARR_DATA_PTR(_query); + lquery *newqry; int num = ArrayGetNItems(ARR_NDIM(_query), ARR_DIMS(_query)); if (ARR_NDIM(_query) > 1) @@ -494,8 +499,16 @@ _arrq_cons(ltree_gist *key, ArrayType *_query, int siglen) while (num > 0) { - if (gist_qe(key, query, siglen)) + newqry = (lquery *)ltree_norm_short_item((char *)query); + + if (gist_qe(key, newqry, siglen)) + { + PFREE_IF_NEW(newqry, query); return true; + } + + PFREE_IF_NEW(newqry, query); + num--; query = (lquery *) NEXTVAL(query); } diff --git a/contrib/ltree/_ltree_op.c b/contrib/ltree/_ltree_op.c index b4a8097328d..274f8c6bd79 100644 --- a/contrib/ltree/_ltree_op.c +++ b/contrib/ltree/_ltree_op.c @@ -32,13 +32,14 @@ PG_FUNCTION_INFO_V1(_lca); typedef Datum (*PGCALL2) (PG_FUNCTION_ARGS); -#define NEXTVAL(x) ( (ltree*)( (char*)(x) + INTALIGN( VARSIZE(x) ) ) ) +#define NEXTVAL(x) ( (ltree*)( (char*)(x) + INTALIGN( VARSIZE_ANY(x) ) ) ) static bool array_iterator(ArrayType *la, PGCALL2 callback, void *param, ltree **found) { int num = ArrayGetNItems(ARR_NDIM(la), ARR_DIMS(la)); ltree *item = (ltree *) ARR_DATA_PTR(la); + ltree *newitem; if (ARR_NDIM(la) > 1) ereport(ERROR, @@ -53,14 +54,20 @@ array_iterator(ArrayType *la, PGCALL2 callback, void *param, ltree **found) *found = NULL; while (num > 0) { + newitem = (ltree *)ltree_norm_short_item((char *)item); + if (DatumGetBool(DirectFunctionCall2(callback, - PointerGetDatum(item), PointerGetDatum(param)))) + PointerGetDatum(newitem), PointerGetDatum(param)))) { + PFREE_IF_NEW(newitem, item); if (found) *found = item; return true; } + + PFREE_IF_NEW(newitem, item); + num--; item = NEXTVAL(item); } @@ -137,6 +144,7 @@ _lt_q_regex(PG_FUNCTION_ARGS) ArrayType *_tree = PG_GETARG_ARRAYTYPE_P(0); ArrayType *_query = PG_GETARG_ARRAYTYPE_P(1); lquery *query = (lquery *) ARR_DATA_PTR(_query); + lquery *newqry; bool res = false; int num = ArrayGetNItems(ARR_NDIM(_query), ARR_DIMS(_query)); @@ -151,11 +159,18 @@ _lt_q_regex(PG_FUNCTION_ARGS) while (num > 0) { - if (array_iterator(_tree, ltq_regex, query, NULL)) + newqry = (lquery *)ltree_norm_short_item((char *)query); + + if (array_iterator(_tree, ltq_regex, newqry, NULL)) { + PFREE_IF_NEW(newqry, query); + res = true; break; } + + PFREE_IF_NEW(newqry, query); + num--; query = (lquery *) NEXTVAL(query); } @@ -297,6 +312,8 @@ _lca(PG_FUNCTION_ARGS) ltree *item = (ltree *) ARR_DATA_PTR(la); ltree **a, *res; + int i; + bool *copied; if (ARR_NDIM(la) > 1) ereport(ERROR, @@ -308,14 +325,25 @@ _lca(PG_FUNCTION_ARGS) errmsg("array must not contain nulls"))); a = (ltree **) palloc(sizeof(ltree *) * num); - while (num > 0) + copied = (bool *)palloc(sizeof(bool) * num); + + for (i = 0; i < num; i++) { - num--; - a[num] = item; + a[i] = (ltree *)ltree_norm_short_item((char *)item); + copied[i] = (a[i] != item); item = NEXTVAL(item); } + res = lca_inner(a, ArrayGetNItems(ARR_NDIM(la), ARR_DIMS(la))); + + for (i = 0; i < num; i++) + { + if (copied[i]) + pfree(a[i]); + } + pfree(a); + pfree(copied); PG_FREE_IF_COPY(la, 0); diff --git a/contrib/ltree/lquery_op.c b/contrib/ltree/lquery_op.c index a6466f575fd..a55ee51de04 100644 --- a/contrib/ltree/lquery_op.c +++ b/contrib/ltree/lquery_op.c @@ -19,7 +19,7 @@ PG_FUNCTION_INFO_V1(ltq_rregex); PG_FUNCTION_INFO_V1(lt_q_regex); PG_FUNCTION_INFO_V1(lt_q_rregex); -#define NEXTVAL(x) ( (lquery*)( (char*)(x) + INTALIGN( VARSIZE(x) ) ) ) +#define NEXTVAL(x) ( (lquery*)( (char*)(x) + INTALIGN( VARSIZE_ANY(x) ) ) ) static char * getlexeme(char *start, char *end, int *len) @@ -241,6 +241,7 @@ lt_q_regex(PG_FUNCTION_ARGS) ltree *tree = PG_GETARG_LTREE_P(0); ArrayType *_query = PG_GETARG_ARRAYTYPE_P(1); lquery *query = (lquery *) ARR_DATA_PTR(_query); + lquery *newqry; bool res = false; int num = ArrayGetNItems(ARR_NDIM(_query), ARR_DIMS(_query)); @@ -255,13 +256,19 @@ lt_q_regex(PG_FUNCTION_ARGS) while (num > 0) { + newqry = (lquery *)ltree_norm_short_item((char *)query); + if (DatumGetBool(DirectFunctionCall2(ltq_regex, - PointerGetDatum(tree), PointerGetDatum(query)))) + PointerGetDatum(tree), PointerGetDatum(newqry)))) { + PFREE_IF_NEW(newqry, query); res = true; break; } + + PFREE_IF_NEW(newqry, query); + num--; query = NEXTVAL(query); } diff --git a/contrib/ltree/ltree.h b/contrib/ltree/ltree.h index 5e0761641d3..28075bd3498 100644 --- a/contrib/ltree/ltree.h +++ b/contrib/ltree/ltree.h @@ -6,6 +6,7 @@ #include "fmgr.h" #include "tsearch/ts_locale.h" #include "utils/memutils.h" +#include "varatt.h" /* ltree */ @@ -212,6 +213,29 @@ bool compare_subnode(ltree_level *t, char *qn, int len, ltree *lca_inner(ltree **a, int len); int ltree_strncasecmp(const char *a, const char *b, size_t s); +/* normalize ltree/lquery in array if it is short version. */ +static inline char* +ltree_norm_short_item(char *item) +{ + if (VARATT_IS_SHORT(item)) + { + /* + * This is a short-header varlena --- convert to 4-byte header format + */ + char *newitem; + Size data_size = VARSIZE_SHORT(item) - VARHDRSZ_SHORT; + Size new_size = data_size + VARHDRSZ; + + newitem = palloc(new_size); + SET_VARSIZE(newitem, new_size); + memcpy(VARDATA(newitem), VARDATA_SHORT(item), data_size); + + return newitem; + } + else + return item; +} + /* fmgr macros for ltree objects */ #define DatumGetLtreeP(X) ((ltree *) PG_DETOAST_DATUM(X)) #define DatumGetLtreePCopy(X) ((ltree *) PG_DETOAST_DATUM_COPY(X)) diff --git a/contrib/ltree/ltree_gist.c b/contrib/ltree/ltree_gist.c index 932f69bff2d..5733d5a1c2d 100644 --- a/contrib/ltree/ltree_gist.c +++ b/contrib/ltree/ltree_gist.c @@ -12,7 +12,7 @@ #include "ltree.h" #include "utils/array.h" -#define NEXTVAL(x) ( (lquery*)( (char*)(x) + INTALIGN( VARSIZE(x) ) ) ) +#define NEXTVAL(x) ( (lquery*)( (char*)(x) + INTALIGN( VARSIZE_ANY(x) ) ) ) #define ISEQ(a,b) ( (a)->numlevel == (b)->numlevel && ltree_compare(a,b)==0 ) PG_FUNCTION_INFO_V1(ltree_gist_in); @@ -592,6 +592,7 @@ static bool arrq_cons(ltree_gist *key, ArrayType *_query, int siglen) { lquery *query = (lquery *) ARR_DATA_PTR(_query); + lquery *newqry; int num = ArrayGetNItems(ARR_NDIM(_query), ARR_DIMS(_query)); if (ARR_NDIM(_query) > 1) @@ -605,11 +606,21 @@ arrq_cons(ltree_gist *key, ArrayType *_query, int siglen) while (num > 0) { - if (gist_qe(key, query, siglen) && gist_between(key, query, siglen)) + newqry = (lquery *)ltree_norm_short_item((char *)query); + + if (gist_qe(key, newqry, siglen) && gist_between(key, newqry, siglen)) + { + PFREE_IF_NEW(newqry, query); + return true; + } + + PFREE_IF_NEW(newqry, query); + num--; query = NEXTVAL(query); } + return false; } diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 49fd35bfc55..26e31a583a4 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -1179,8 +1179,8 @@ transformRelOptions(Datum oldOptions, List *defList, const char *namspace, for (i = 0; i < noldoptions; i++) { - char *text_str = VARDATA(oldoptions[i]); - int text_len = VARSIZE(oldoptions[i]) - VARHDRSZ; + char *text_str = VARDATA_ANY(oldoptions[i]); + int text_len = VARSIZE_ANY_EXHDR(oldoptions[i]); /* Search for a match in defList */ foreach(cell, defList) @@ -1436,8 +1436,8 @@ parseRelOptionsInternal(Datum options, bool validate, for (i = 0; i < noptions; i++) { - char *text_str = VARDATA(optiondatums[i]); - int text_len = VARSIZE(optiondatums[i]) - VARHDRSZ; + char *text_str = VARDATA_ANY(optiondatums[i]); + int text_len = VARSIZE_ANY_EXHDR(optiondatums[i]); int j; /* Search for a match in reloptions */ diff --git a/src/backend/access/gin/ginarrayproc.c b/src/backend/access/gin/ginarrayproc.c index 2373e76f77e..b8311d21858 100644 --- a/src/backend/access/gin/ginarrayproc.c +++ b/src/backend/access/gin/ginarrayproc.c @@ -39,16 +39,17 @@ ginarrayextract(PG_FUNCTION_ARGS) int16 elmlen; bool elmbyval; char elmalign; + char elmstor; Datum *elems; bool *nulls; int nelems; - get_typlenbyvalalign(ARR_ELEMTYPE(array), - &elmlen, &elmbyval, &elmalign); + get_type_stores(ARR_ELEMTYPE(array), + &elmlen, &elmbyval, &elmalign, &elmstor); deconstruct_array(array, ARR_ELEMTYPE(array), - elmlen, elmbyval, elmalign, + elmlen, elmbyval, elmalign, elmstor, &elems, &nulls, &nelems); *nkeys = nelems; @@ -90,16 +91,17 @@ ginqueryarrayextract(PG_FUNCTION_ARGS) int16 elmlen; bool elmbyval; char elmalign; + char elmstor; Datum *elems; bool *nulls; int nelems; - get_typlenbyvalalign(ARR_ELEMTYPE(array), - &elmlen, &elmbyval, &elmalign); + get_type_stores(ARR_ELEMTYPE(array), + &elmlen, &elmbyval, &elmalign, &elmstor); deconstruct_array(array, ARR_ELEMTYPE(array), - elmlen, elmbyval, elmalign, + elmlen, elmbyval, elmalign, elmstor, &elems, &nulls, &nelems); *nkeys = nelems; diff --git a/src/backend/access/nbtree/nbtutils.c b/src/backend/access/nbtree/nbtutils.c index a531d37908a..c3aa979c572 100644 --- a/src/backend/access/nbtree/nbtutils.c +++ b/src/backend/access/nbtree/nbtutils.c @@ -340,6 +340,7 @@ _bt_preprocess_array_keys(IndexScanDesc scan, int *new_numberOfKeys) int16 elmlen; bool elmbyval; char elmalign; + char elmstor; int num_elems; Datum *elem_values; bool *elem_nulls; @@ -364,11 +365,11 @@ _bt_preprocess_array_keys(IndexScanDesc scan, int *new_numberOfKeys) */ arrayval = DatumGetArrayTypeP(cur->sk_argument); /* We could cache this data, but not clear it's worth it */ - get_typlenbyvalalign(ARR_ELEMTYPE(arrayval), - &elmlen, &elmbyval, &elmalign); + get_type_stores(ARR_ELEMTYPE(arrayval), + &elmlen, &elmbyval, &elmalign, &elmstor); deconstruct_array(arrayval, ARR_ELEMTYPE(arrayval), - elmlen, elmbyval, elmalign, + elmlen, elmbyval, elmalign, elmstor, &elem_values, &elem_nulls, &num_elems); /* diff --git a/src/backend/bootstrap/bootstrap.c b/src/backend/bootstrap/bootstrap.c index e0cb70ee9da..79ebac5b78c 100644 --- a/src/backend/bootstrap/bootstrap.c +++ b/src/backend/bootstrap/bootstrap.c @@ -903,6 +903,105 @@ boot_get_type_io_data(Oid typid, } } +/* ---------------- + * boot_array_type_metadata + * + * Obtain type metadata at bootstrap time. This intentionally has + * almost the same API as lsyscache.c's array_type_metadata, except that + * we only support obtaining the typinput and typoutput routines, not + * the binary I/O routines. It is exported so that array_in and array_out + * can be made to work during early bootstrap. + * ---------------- + */ +void +boot_array_type_metadata(Oid typid, + IOFuncSelector which_func, + ArrayMetaState *metadata) +{ + if (Typ != NIL) + { + /* We have the boot-time contents of pg_type, so use it */ + struct typmap *ap = NULL; + ListCell *lc; + + foreach(lc, Typ) + { + ap = lfirst(lc); + if (ap->am_oid == typid) + break; + } + + if (!ap || ap->am_oid != typid) + elog(ERROR, "type OID %u not found in Typ list", typid); + + metadata->typlen = ap->am_typ.typlen; + metadata->typbyval = ap->am_typ.typbyval; + metadata->typalign = ap->am_typ.typalign; + metadata->typstorage = ap->am_typ.typstorage; + metadata->typdelim = ap->am_typ.typdelim; + + /* XXX this logic must match getTypeIOParam() */ + if (OidIsValid(ap->am_typ.typelem)) + metadata->typioparam = ap->am_typ.typelem; + else + metadata->typioparam = typid; + + switch (which_func) + { + case IOFunc_input: + metadata->typiofunc = ap->am_typ.typinput; + break; + case IOFunc_output: + metadata->typiofunc = ap->am_typ.typoutput; + break; + default: + elog(ERROR, "binary I/O not supported during bootstrap"); + break; + } + + return; + } + else + { + /* We don't have pg_type yet, so use the hard-wired TypInfo array */ + int typeindex; + + for (typeindex = 0; typeindex < n_types; typeindex++) + { + if (TypInfo[typeindex].oid == typid) + break; + } + if (typeindex >= n_types) + elog(ERROR, "type OID %u not found in TypInfo", typid); + + metadata->typlen = TypInfo[typeindex].len; + metadata->typbyval = TypInfo[typeindex].byval; + metadata->typalign = TypInfo[typeindex].align; + metadata->typstorage = TypInfo[typeindex].storage; + /* We assume typdelim is ',' for all boot-time types */ + metadata->typdelim = ','; + + /* XXX this logic must match getTypeIOParam() */ + if (OidIsValid(TypInfo[typeindex].elem)) + metadata->typioparam = TypInfo[typeindex].elem; + else + metadata->typioparam = typid; + + switch (which_func) + { + case IOFunc_input: + metadata->typiofunc = TypInfo[typeindex].inproc; + break; + case IOFunc_output: + metadata->typiofunc = TypInfo[typeindex].outproc; + break; + default: + elog(ERROR, "binary I/O not supported during bootstrap"); + break; + } + } +} + /* ---------------- * AllocateAttribute * diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index be7e4a5dd01..c9e6bf73872 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -6126,7 +6126,8 @@ strlist_to_textarray(List *list) lb[0] = 1; arr = construct_md_array(datums, nulls, 1, &j, - lb, TEXTOID, -1, false, TYPALIGN_INT); + lb, TEXTOID, -1, false, + TYPALIGN_INT, TYPSTORAGE_EXTENDED); MemoryContextDelete(memcxt); diff --git a/src/backend/catalog/pg_attrdef.c b/src/backend/catalog/pg_attrdef.c index 003ae70b4d2..ce73000e4c7 100644 --- a/src/backend/catalog/pg_attrdef.c +++ b/src/backend/catalog/pg_attrdef.c @@ -148,7 +148,8 @@ StoreAttrDefault(Relation rel, AttrNumber attnum, defAttStruct->atttypid, defAttStruct->attlen, defAttStruct->attbyval, - defAttStruct->attalign)); + defAttStruct->attalign, + defAttStruct->attstorage)); } valuesAtt[Anum_pg_attribute_atthasmissing - 1] = !missingIsNull; diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c index 9a56de2282f..ba449b2c495 100644 --- a/src/backend/commands/analyze.c +++ b/src/backend/commands/analyze.c @@ -1721,7 +1721,8 @@ update_attstats(Oid relid, bool inh, int natts, VacAttrStats **vacattrstats) stats->statypid[k], stats->statyplen[k], stats->statypbyval[k], - stats->statypalign[k]); + stats->statypalign[k], + stats->statypstorage[k]); values[i++] = PointerGetDatum(arry); /* stavaluesN */ } else diff --git a/src/backend/commands/extension.c b/src/backend/commands/extension.c index e683c520a82..b51348d65ce 100644 --- a/src/backend/commands/extension.c +++ b/src/backend/commands/extension.c @@ -2654,7 +2654,8 @@ pg_extension_config_dump(PG_FUNCTION_ARGS) -1 /* varlena array */ , sizeof(Oid) /* OID's typlen */ , true /* OID's typbyval */ , - TYPALIGN_INT /* OID's typalign */ ); + TYPALIGN_INT /* OID's typalign */, + TYPSTORAGE_PLAIN /* OID's typstorage */ ); } repl_val[Anum_pg_extension_extconfig - 1] = PointerGetDatum(a); repl_repl[Anum_pg_extension_extconfig - 1] = true; @@ -2690,7 +2691,8 @@ pg_extension_config_dump(PG_FUNCTION_ARGS) -1 /* varlena array */ , -1 /* TEXT's typlen */ , false /* TEXT's typbyval */ , - TYPALIGN_INT /* TEXT's typalign */ ); + TYPALIGN_INT /* TEXT's typalign */ , + TYPSTORAGE_EXTENDED /* TEXT's typstorage */ ); } repl_val[Anum_pg_extension_extcondition - 1] = PointerGetDatum(a); repl_repl[Anum_pg_extension_extcondition - 1] = true; diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index 49374782625..b4840d60e0a 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -13750,13 +13750,15 @@ ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel, attTup->attlen, attTup->attbyval, attTup->attalign, + attTup->attstorage, &isNull); missingval = PointerGetDatum(construct_array(&missingval, 1, targettype, tform->typlen, tform->typbyval, - tform->typalign)); + tform->typalign, + tform->typstorage)); valuesAtt[Anum_pg_attribute_attmissingval - 1] = missingval; replacesAtt[Anum_pg_attribute_attmissingval - 1] = true; diff --git a/src/backend/executor/execExpr.c b/src/backend/executor/execExpr.c index 3d01a90bd64..5d73e2b21b0 100644 --- a/src/backend/executor/execExpr.c +++ b/src/backend/executor/execExpr.c @@ -1886,10 +1886,11 @@ ExecInitExprRec(Expr *node, ExprState *state, scratch.d.arrayexpr.elemtype = arrayexpr->element_typeid; /* do one-time catalog lookup for type info */ - get_typlenbyvalalign(arrayexpr->element_typeid, - &scratch.d.arrayexpr.elemlength, - &scratch.d.arrayexpr.elembyval, - &scratch.d.arrayexpr.elemalign); + get_type_stores(arrayexpr->element_typeid, + &scratch.d.arrayexpr.elemlength, + &scratch.d.arrayexpr.elembyval, + &scratch.d.arrayexpr.elemalign, + &scratch.d.arrayexpr.elemstorage); /* prepare to evaluate all arguments */ elemoff = 0; diff --git a/src/backend/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c index d2987663e63..9de7f7b523b 100644 --- a/src/backend/executor/execExprInterp.c +++ b/src/backend/executor/execExprInterp.c @@ -3211,7 +3211,8 @@ ExecEvalArrayExpr(ExprState *state, ExprEvalStep *op) element_type, op->d.arrayexpr.elemlength, op->d.arrayexpr.elembyval, - op->d.arrayexpr.elemalign); + op->d.arrayexpr.elemalign, + op->d.arrayexpr.elemstorage); } else { diff --git a/src/backend/executor/nodeIndexscan.c b/src/backend/executor/nodeIndexscan.c index 8000feff4c9..7a33d697c35 100644 --- a/src/backend/executor/nodeIndexscan.c +++ b/src/backend/executor/nodeIndexscan.c @@ -678,6 +678,7 @@ ExecIndexEvalArrayKeys(ExprContext *econtext, int16 elmlen; bool elmbyval; char elmalign; + char elmstor; int num_elems; Datum *elem_values; bool *elem_nulls; @@ -696,11 +697,11 @@ ExecIndexEvalArrayKeys(ExprContext *econtext, } arrayval = DatumGetArrayTypeP(arraydatum); /* We could cache this data, but not clear it's worth it */ - get_typlenbyvalalign(ARR_ELEMTYPE(arrayval), - &elmlen, &elmbyval, &elmalign); + get_type_stores(ARR_ELEMTYPE(arrayval), + &elmlen, &elmbyval, &elmalign, &elmstor); deconstruct_array(arrayval, ARR_ELEMTYPE(arrayval), - elmlen, elmbyval, elmalign, + elmlen, elmbyval, elmalign, elmstor, &elem_values, &elem_nulls, &num_elems); if (num_elems <= 0) { diff --git a/src/backend/optimizer/path/indxpath.c b/src/backend/optimizer/path/indxpath.c index 5d102a0d371..83ee95a2656 100644 --- a/src/backend/optimizer/path/indxpath.c +++ b/src/backend/optimizer/path/indxpath.c @@ -3428,11 +3428,12 @@ match_orclause_to_indexcol(PlannerInfo *root, int16 typlen; bool typbyval; char typalign; + char typstor; Datum *elems; int i = 0; ArrayType *arrayConst; - get_typlenbyvalalign(consttype, &typlen, &typbyval, &typalign); + get_type_stores(consttype, &typlen, &typbyval, &typalign, &typstor); elems = (Datum *) palloc(sizeof(Datum) * list_length(consts)); foreach_node(Const, value, consts) @@ -3443,7 +3444,7 @@ match_orclause_to_indexcol(PlannerInfo *root, } arrayConst = construct_array(elems, i, consttype, - typlen, typbyval, typalign); + typlen, typbyval, typalign, typstor); arrayNode = (Node *) makeConst(arraytype, -1, inputcollid, -1, PointerGetDatum(arrayConst), false, false); diff --git a/src/backend/optimizer/util/predtest.c b/src/backend/optimizer/util/predtest.c index 0a132610140..20e7dd220f0 100644 --- a/src/backend/optimizer/util/predtest.c +++ b/src/backend/optimizer/util/predtest.c @@ -965,6 +965,7 @@ arrayconst_startup_fn(Node *clause, PredIterInfo info) int16 elmlen; bool elmbyval; char elmalign; + char elmstor; /* Create working state struct */ state = (ArrayConstIterState *) palloc(sizeof(ArrayConstIterState)); @@ -973,11 +974,11 @@ arrayconst_startup_fn(Node *clause, PredIterInfo info) /* Deconstruct the array literal */ arrayconst = (Const *) lsecond(saop->args); arrayval = DatumGetArrayTypeP(arrayconst->constvalue); - get_typlenbyvalalign(ARR_ELEMTYPE(arrayval), - &elmlen, &elmbyval, &elmalign); + get_type_stores(ARR_ELEMTYPE(arrayval), + &elmlen, &elmbyval, &elmalign, &elmstor); deconstruct_array(arrayval, ARR_ELEMTYPE(arrayval), - elmlen, elmbyval, elmalign, + elmlen, elmbyval, elmalign, elmstor, &state->elem_values, &state->elem_nulls, &state->num_elems); diff --git a/src/backend/partitioning/partbounds.c b/src/backend/partitioning/partbounds.c index c28639d2e3f..3064c943254 100644 --- a/src/backend/partitioning/partbounds.c +++ b/src/backend/partitioning/partbounds.c @@ -4778,6 +4778,7 @@ satisfies_hash_partition(PG_FUNCTION_ARGS) int16 variadic_typlen; bool variadic_typbyval; char variadic_typalign; + char variadic_typstorage; Oid partcollid[PARTITION_MAX_KEYS]; FmgrInfo partsupfunc[FLEXIBLE_ARRAY_MEMBER]; } ColumnsHashData; @@ -4881,10 +4882,11 @@ satisfies_hash_partition(PG_FUNCTION_ARGS) my_extra->relid = parentId; my_extra->nkeys = key->partnatts; my_extra->variadic_type = ARR_ELEMTYPE(variadic_array); - get_typlenbyvalalign(my_extra->variadic_type, + get_type_stores(my_extra->variadic_type, &my_extra->variadic_typlen, &my_extra->variadic_typbyval, - &my_extra->variadic_typalign); + &my_extra->variadic_typalign, + &my_extra->variadic_typstorage); my_extra->partcollid[0] = key->partcollation[0]; /* check argument types */ @@ -4949,6 +4951,7 @@ satisfies_hash_partition(PG_FUNCTION_ARGS) my_extra->variadic_typlen, my_extra->variadic_typbyval, my_extra->variadic_typalign, + my_extra->variadic_typstorage, &datum, &isnull, &nelems); /* complain if wrong number of column values */ diff --git a/src/backend/partitioning/partprune.c b/src/backend/partitioning/partprune.c index 4e12ae5d1e3..faf825b9cd5 100644 --- a/src/backend/partitioning/partprune.c +++ b/src/backend/partitioning/partprune.c @@ -2280,6 +2280,7 @@ match_clause_to_partition_key(GeneratePruningStepsContext *context, int16 elemlen; bool elembyval; char elemalign; + char elemstor; Datum *elem_values; bool *elem_nulls; int num_elems, @@ -2290,11 +2291,11 @@ match_clause_to_partition_key(GeneratePruningStepsContext *context, return PARTCLAUSE_MATCH_CONTRADICT; arrval = DatumGetArrayTypeP(arr->constvalue); - get_typlenbyvalalign(ARR_ELEMTYPE(arrval), - &elemlen, &elembyval, &elemalign); + get_type_stores(ARR_ELEMTYPE(arrval), + &elemlen, &elembyval, &elemalign, &elemstor); deconstruct_array(arrval, ARR_ELEMTYPE(arrval), - elemlen, elembyval, elemalign, + elemlen, elembyval, elemalign, elemstor, &elem_values, &elem_nulls, &num_elems); for (i = 0; i < num_elems; i++) diff --git a/src/backend/statistics/extended_stats.c b/src/backend/statistics/extended_stats.c index 99fdf208dba..3c1335fd707 100644 --- a/src/backend/statistics/extended_stats.c +++ b/src/backend/statistics/extended_stats.c @@ -575,6 +575,7 @@ examine_attribute(Node *expr) stats->statyplen[i] = stats->attrtype->typlen; stats->statypbyval[i] = stats->attrtype->typbyval; stats->statypalign[i] = stats->attrtype->typalign; + stats->statypstorage[i] = stats->attrtype->typstorage; } /* @@ -660,6 +661,7 @@ examine_expression(Node *expr, int stattarget) stats->statyplen[i] = stats->attrtype->typlen; stats->statypbyval[i] = stats->attrtype->typbyval; stats->statypalign[i] = stats->attrtype->typalign; + stats->statypstorage[i] = stats->attrtype->typstorage; } /* @@ -2393,7 +2395,8 @@ serialize_expr_stats(AnlExprData *exprdata, int nexprs) stats->statypid[k], stats->statyplen[k], stats->statypbyval[k], - stats->statypalign[k]); + stats->statypalign[k], + stats->statypstorage[k]); values[i++] = PointerGetDatum(arry); /* stavaluesN */ } else diff --git a/src/backend/statistics/mcv.c b/src/backend/statistics/mcv.c index b0e9aead84e..c2fddf69526 100644 --- a/src/backend/statistics/mcv.c +++ b/src/backend/statistics/mcv.c @@ -1724,6 +1724,7 @@ mcv_get_match_bitmap(PlannerInfo *root, List *clauses, int16 elmlen; bool elmbyval; char elmalign; + char elmstor; int num_elems; Datum *elem_values; bool *elem_nulls; @@ -1745,11 +1746,11 @@ mcv_get_match_bitmap(PlannerInfo *root, List *clauses, if (!cst->constisnull) { arrayval = DatumGetArrayTypeP(cst->constvalue); - get_typlenbyvalalign(ARR_ELEMTYPE(arrayval), - &elmlen, &elmbyval, &elmalign); + get_type_stores(ARR_ELEMTYPE(arrayval), + &elmlen, &elmbyval, &elmalign, &elmstor); deconstruct_array(arrayval, ARR_ELEMTYPE(arrayval), - elmlen, elmbyval, elmalign, + elmlen, elmbyval, elmalign, elmstor, &elem_values, &elem_nulls, &num_elems); } diff --git a/src/backend/utils/adt/array_expanded.c b/src/backend/utils/adt/array_expanded.c index cc3713b97b7..9882f1e0df8 100644 --- a/src/backend/utils/adt/array_expanded.c +++ b/src/backend/utils/adt/array_expanded.c @@ -92,6 +92,7 @@ expand_array(Datum arraydatum, MemoryContext parentcontext, metacache->typlen = oldeah->typlen; metacache->typbyval = oldeah->typbyval; metacache->typalign = oldeah->typalign; + metacache->typstorage = oldeah->typstorage; /* * If element type is pass-by-value and we have a Datum-array @@ -144,14 +145,17 @@ expand_array(Datum arraydatum, MemoryContext parentcontext, eah->typlen = metacache->typlen; eah->typbyval = metacache->typbyval; eah->typalign = metacache->typalign; + eah->typstorage = metacache->typstorage; } else { /* No, so look it up */ - get_typlenbyvalalign(eah->element_type, + get_type_stores(eah->element_type, &eah->typlen, &eah->typbyval, - &eah->typalign); + &eah->typalign, + &eah->typstorage); + /* Update cache if provided */ if (metacache) { @@ -159,6 +163,7 @@ expand_array(Datum arraydatum, MemoryContext parentcontext, metacache->typlen = eah->typlen; metacache->typbyval = eah->typbyval; metacache->typalign = eah->typalign; + metacache->typstorage = eah->typstorage; } } @@ -203,6 +208,7 @@ copy_byval_expanded_array(ExpandedArrayHeader *eah, eah->typlen = oldeah->typlen; eah->typbyval = oldeah->typbyval; eah->typalign = oldeah->typalign; + eah->typstorage = oldeah->typstorage; /* Copy the deconstructed representation */ eah->dvalues = (Datum *) MemoryContextAlloc(objcxt, @@ -333,7 +339,7 @@ EA_flatten_into(ExpandedObjectHeader *eohptr, CopyArrayEls(aresult, eah->dvalues, eah->dnulls, nelems, - eah->typlen, eah->typbyval, eah->typalign, + eah->typlen, eah->typbyval, eah->typalign, eah->typstorage, false); } @@ -384,6 +390,7 @@ DatumGetExpandedArrayX(Datum d, ArrayMetaState *metacache) metacache->typlen = eah->typlen; metacache->typbyval = eah->typbyval; metacache->typalign = eah->typalign; + metacache->typstorage = eah->typstorage; } return eah; } @@ -433,7 +440,8 @@ deconstruct_expanded_array(ExpandedArrayHeader *eah) dnulls = NULL; deconstruct_array(eah->fvalue, eah->element_type, - eah->typlen, eah->typbyval, eah->typalign, + eah->typlen, eah->typbyval, + eah->typalign, eah->typstorage, &dvalues, ARR_HASNULL(eah->fvalue) ? &dnulls : NULL, &nelems); diff --git a/src/backend/utils/adt/array_selfuncs.c b/src/backend/utils/adt/array_selfuncs.c index e2af89f5cc5..d1857fa66f3 100644 --- a/src/backend/utils/adt/array_selfuncs.c +++ b/src/backend/utils/adt/array_selfuncs.c @@ -448,6 +448,7 @@ mcelem_array_selec(ArrayType *array, TypeCacheEntry *typentry, typentry->typlen, typentry->typbyval, typentry->typalign, + typentry->typstorage, &elem_values, &elem_nulls, &num_elems); /* Collapse out any null elements */ diff --git a/src/backend/utils/adt/array_typanalyze.c b/src/backend/utils/adt/array_typanalyze.c index 2c633bee6b1..148197694b0 100644 --- a/src/backend/utils/adt/array_typanalyze.c +++ b/src/backend/utils/adt/array_typanalyze.c @@ -42,6 +42,7 @@ typedef struct bool typbyval; /* physical properties of element type */ int16 typlen; char typalign; + char typstorage; /* * Lookup data for element type's comparison and hash functions (these are @@ -139,6 +140,7 @@ array_typanalyze(PG_FUNCTION_ARGS) extra_data->typbyval = typentry->typbyval; extra_data->typlen = typentry->typlen; extra_data->typalign = typentry->typalign; + extra_data->typstorage = typentry->typstorage; extra_data->cmp = &typentry->cmp_proc_finfo; extra_data->hash = &typentry->hash_proc_finfo; @@ -340,6 +342,7 @@ compute_array_stats(VacAttrStats *stats, AnalyzeAttrFetchFunc fetchfunc, extra_data->typlen, extra_data->typbyval, extra_data->typalign, + extra_data->typstorage, &elem_values, &elem_nulls, &num_elems); /* @@ -568,6 +571,7 @@ compute_array_stats(VacAttrStats *stats, AnalyzeAttrFetchFunc fetchfunc, stats->statyplen[slot_idx] = extra_data->typlen; stats->statypbyval[slot_idx] = extra_data->typbyval; stats->statypalign[slot_idx] = extra_data->typalign; + stats->statypstorage[slot_idx] = extra_data->typstorage; slot_idx++; } diff --git a/src/backend/utils/adt/array_userfuncs.c b/src/backend/utils/adt/array_userfuncs.c index 304a93112e2..2d533a59185 100644 --- a/src/backend/utils/adt/array_userfuncs.c +++ b/src/backend/utils/adt/array_userfuncs.c @@ -161,8 +161,9 @@ array_append(PG_FUNCTION_ARGS) my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra; result = array_set_element(EOHPGetRWDatum(&eah->hdr), - 1, &indx, newelem, isNull, - -1, my_extra->typlen, my_extra->typbyval, my_extra->typalign); + 1, &indx, newelem, isNull, -1, + my_extra->typlen, my_extra->typbyval, + my_extra->typalign, my_extra->typstorage); PG_RETURN_DATUM(result); } @@ -216,8 +217,9 @@ array_prepend(PG_FUNCTION_ARGS) my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra; result = array_set_element(EOHPGetRWDatum(&eah->hdr), - 1, &indx, newelem, isNull, - -1, my_extra->typlen, my_extra->typbyval, my_extra->typalign); + 1, &indx, newelem, isNull, -1, + my_extra->typlen, my_extra->typbyval, + my_extra->typalign, my_extra->typstorage); /* Readjust result's LB to match the input's, as expected for prepend */ Assert(result == EOHPGetRWDatum(&eah->hdr)); @@ -654,6 +656,9 @@ array_agg_serialize(PG_FUNCTION_ARGS) /* typalign */ pq_sendbyte(&buf, state->typalign); + /* typstorage */ + pq_sendbyte(&buf, state->typstorage); + /* dnulls */ pq_sendbytes(&buf, state->dnulls, sizeof(bool) * state->nelems); @@ -749,6 +754,9 @@ array_agg_deserialize(PG_FUNCTION_ARGS) /* typalign */ result->typalign = pq_getmsgbyte(&buf); + /* typstorage */ + result->typstorage = pq_getmsgbyte(&buf); + /* dnulls */ temp = pq_getmsgbytes(&buf, sizeof(bool) * nelems); memcpy(result->dnulls, temp, sizeof(bool) * nelems); @@ -1321,10 +1329,11 @@ array_position_common(FunctionCallInfo fcinfo) if (my_extra->element_type != element_type) { - get_typlenbyvalalign(element_type, - &my_extra->typlen, - &my_extra->typbyval, - &my_extra->typalign); + get_type_stores(element_type, + &my_extra->typlen, + &my_extra->typbyval, + &my_extra->typalign, + &my_extra->typstorage); typentry = lookup_type_cache(element_type, TYPECACHE_EQ_OPR_FINFO); @@ -1464,10 +1473,12 @@ array_positions(PG_FUNCTION_ARGS) if (my_extra->element_type != element_type) { - get_typlenbyvalalign(element_type, - &my_extra->typlen, - &my_extra->typbyval, - &my_extra->typalign); + get_type_stores(element_type, + &my_extra->typlen, + &my_extra->typbyval, + &my_extra->typalign, + &my_extra->typstorage); + typentry = lookup_type_cache(element_type, TYPECACHE_EQ_OPR_FINFO); @@ -1548,6 +1559,7 @@ array_shuffle_n(ArrayType *array, int n, bool keep_lb, int16 elmlen; bool elmbyval; char elmalign; + char elmstor; Datum *elms, *ielms; bool *nuls, @@ -1560,12 +1572,13 @@ array_shuffle_n(ArrayType *array, int n, bool keep_lb, elmlen = typentry->typlen; elmbyval = typentry->typbyval; elmalign = typentry->typalign; + elmstor = typentry->typstorage; /* If the target array is empty, exit fast */ if (ndim < 1 || dims[0] < 1 || n < 1) return construct_empty_array(elmtyp); - deconstruct_array(array, elmtyp, elmlen, elmbyval, elmalign, + deconstruct_array(array, elmtyp, elmlen, elmbyval, elmalign, elmstor, &elms, &nuls, &nelm); nitem = dims[0]; /* total number of items */ @@ -1608,7 +1621,7 @@ array_shuffle_n(ArrayType *array, int n, bool keep_lb, rlbs[0] = 1; result = construct_md_array(elms, nuls, ndim, rdims, rlbs, - elmtyp, elmlen, elmbyval, elmalign); + elmtyp, elmlen, elmbyval, elmalign, elmstor); pfree(elms); pfree(nuls); @@ -1709,6 +1722,7 @@ array_reverse_n(ArrayType *array, Oid elmtyp, TypeCacheEntry *typentry) int16 elmlen; bool elmbyval; char elmalign; + char elmstor; Datum *elms, *ielms; bool *nuls, @@ -1721,8 +1735,9 @@ array_reverse_n(ArrayType *array, Oid elmtyp, TypeCacheEntry *typentry) elmlen = typentry->typlen; elmbyval = typentry->typbyval; elmalign = typentry->typalign; + elmstor = typentry->typstorage; - deconstruct_array(array, elmtyp, elmlen, elmbyval, elmalign, + deconstruct_array(array, elmtyp, elmlen, elmbyval, elmalign, elmstor, &elms, &nuls, &nelm); nitem = dims[0]; /* total number of items */ @@ -1756,7 +1771,7 @@ array_reverse_n(ArrayType *array, Oid elmtyp, TypeCacheEntry *typentry) rdims[0] = nitem; result = construct_md_array(elms, nuls, ndim, rdims, rlbs, - elmtyp, elmlen, elmbyval, elmalign); + elmtyp, elmlen, elmbyval, elmalign, elmstor); pfree(elms); pfree(nuls); diff --git a/src/backend/utils/adt/arrayfuncs.c b/src/backend/utils/adt/arrayfuncs.c index 593775c27f3..f8dad59c27f 100644 --- a/src/backend/utils/adt/arrayfuncs.c +++ b/src/backend/utils/adt/arrayfuncs.c @@ -74,6 +74,7 @@ typedef struct ArrayIteratorData int16 typlen; /* element type's length */ bool typbyval; /* element type's byval property */ char typalign; /* element type's align property */ + char typstorage; /* element type's storage property */ /* information about the requested slice size */ int slice_ndim; /* slice dimension, or 0 if not slicing */ @@ -105,46 +106,51 @@ static ArrayToken ReadArrayToken(char **srcptr, StringInfo elembuf, char typdeli const char *origStr, Node *escontext); static void ReadArrayBinary(StringInfo buf, int nitems, FmgrInfo *receiveproc, Oid typioparam, int32 typmod, - int typlen, bool typbyval, char typalign, + int typlen, bool typbyval, char typalign, char typstor, Datum *values, bool *nulls, bool *hasnulls, int32 *nbytes); static Datum array_get_element_expanded(Datum arraydatum, int nSubscripts, int *indx, int arraytyplen, - int elmlen, bool elmbyval, char elmalign, - bool *isNull); + int elmlen, bool elmbyval, + char elmalign, char typstor, bool *isNull); static Datum array_set_element_expanded(Datum arraydatum, int nSubscripts, int *indx, Datum dataValue, bool isNull, int arraytyplen, - int elmlen, bool elmbyval, char elmalign); + int elmlen, bool elmbyval, + char elmalign, char typstor); static bool array_get_isnull(const bits8 *nullbitmap, int offset); static void array_set_isnull(bits8 *nullbitmap, int offset, bool isNull); static Datum ArrayCast(char *value, bool byval, int len); static int ArrayCastAndSet(Datum src, - int typlen, bool typbyval, char typalign, - char *dest); + int typlen, bool typbyval, + char typalign, char typstor, char *dest); static char *array_seek(char *ptr, int offset, bits8 *nullbitmap, int nitems, - int typlen, bool typbyval, char typalign); + int typlen, bool typbyval, char typalign, char typstor); static int array_nelems_size(char *ptr, int offset, bits8 *nullbitmap, - int nitems, int typlen, bool typbyval, char typalign); + int nitems, int typlen, bool typbyval, + char typalign, char typstor); static int array_copy(char *destptr, int nitems, char *srcptr, int offset, bits8 *nullbitmap, - int typlen, bool typbyval, char typalign); + int typlen, bool typbyval, char typalign, char typstor); static int array_slice_size(char *arraydataptr, bits8 *arraynullsptr, int ndim, int *dim, int *lb, int *st, int *endp, - int typlen, bool typbyval, char typalign); + int typlen, bool typbyval, + char typalign, char typstor); static void array_extract_slice(ArrayType *newarray, int ndim, int *dim, int *lb, char *arraydataptr, bits8 *arraynullsptr, int *st, int *endp, - int typlen, bool typbyval, char typalign); + int typlen, bool typbyval, + char typalign, char typstor); static void array_insert_slice(ArrayType *destArray, ArrayType *origArray, ArrayType *srcArray, int ndim, int *dim, int *lb, int *st, int *endp, - int typlen, bool typbyval, char typalign); + int typlen, bool typbyval, + char typalign, char typstor); static int array_cmp(FunctionCallInfo fcinfo); static ArrayType *create_array_envelope(int ndims, int *dimv, int *lbsv, int nbytes, Oid elmtype, int dataoffset); @@ -187,6 +193,7 @@ array_in(PG_FUNCTION_ARGS) bool typbyval; char typalign; char typdelim; + char typstor; Oid typioparam; char *p; int nitems; @@ -220,10 +227,7 @@ array_in(PG_FUNCTION_ARGS) /* * Get info about element type, including its input conversion proc */ - get_type_io_data(element_type, IOFunc_input, - &my_extra->typlen, &my_extra->typbyval, - &my_extra->typalign, &my_extra->typdelim, - &my_extra->typioparam, &my_extra->typiofunc); + array_type_metadata(element_type, IOFunc_input, my_extra); fmgr_info_cxt(my_extra->typiofunc, &my_extra->proc, fcinfo->flinfo->fn_mcxt); my_extra->element_type = element_type; @@ -231,6 +235,7 @@ array_in(PG_FUNCTION_ARGS) typlen = my_extra->typlen; typbyval = my_extra->typbyval; typalign = my_extra->typalign; + typstor = my_extra->typstorage; typdelim = my_extra->typdelim; typioparam = my_extra->typioparam; @@ -326,7 +331,7 @@ array_in(PG_FUNCTION_ARGS) /* let's just make sure data is not toasted */ if (typlen == -1) values[i] = PointerGetDatum(PG_DETOAST_DATUM(values[i])); - nbytes = att_addlength_datum(nbytes, typlen, values[i]); + nbytes = att_addvarsize_datum(nbytes, typlen, typstor, values[i]); nbytes = att_align_nominal(nbytes, typalign); /* check for overflow of total request */ if (!AllocSizeIsValid(nbytes)) @@ -366,7 +371,7 @@ array_in(PG_FUNCTION_ARGS) CopyArrayEls(retval, values, nulls, nitems, - typlen, typbyval, typalign, + typlen, typbyval, typalign, typstor, true); pfree(values); @@ -949,7 +954,7 @@ ending_error: * values: array of Datums to be copied * nulls: array of is-null flags (can be NULL if no nulls) * nitems: number of Datums to be copied - * typbyval, typlen, typalign: info about element datatype + * typbyval, typlen, typalign, typstor: info about element datatype * freedata: if true and element type is pass-by-ref, pfree data values * referenced by Datums after copying them. * @@ -965,6 +970,7 @@ CopyArrayEls(ArrayType *array, int typlen, bool typbyval, char typalign, + char typstor, bool freedata) { char *p = ARR_DATA_PTR(array); @@ -987,7 +993,8 @@ CopyArrayEls(ArrayType *array, else { bitval |= bitmask; - p += ArrayCastAndSet(values[i], typlen, typbyval, typalign, p); + p += ArrayCastAndSet(values[i], + typlen, typbyval, typalign, typstor, p); if (freedata) pfree(DatumGetPointer(values[i])); } @@ -1065,10 +1072,7 @@ array_out(PG_FUNCTION_ARGS) /* * Get info about element type, including its output conversion proc */ - get_type_io_data(element_type, IOFunc_output, - &my_extra->typlen, &my_extra->typbyval, - &my_extra->typalign, &my_extra->typdelim, - &my_extra->typioparam, &my_extra->typiofunc); + array_type_metadata(element_type, IOFunc_output, my_extra); fmgr_info_cxt(my_extra->typiofunc, &my_extra->proc, fcinfo->flinfo->fn_mcxt); my_extra->element_type = element_type; @@ -1278,6 +1282,7 @@ array_recv(PG_FUNCTION_ARGS) int typlen; bool typbyval; char typalign; + char typstor; Oid typioparam; int i, nitems; @@ -1368,10 +1373,7 @@ array_recv(PG_FUNCTION_ARGS) if (my_extra->element_type != element_type) { /* Get info about element type, including its receive proc */ - get_type_io_data(element_type, IOFunc_receive, - &my_extra->typlen, &my_extra->typbyval, - &my_extra->typalign, &my_extra->typdelim, - &my_extra->typioparam, &my_extra->typiofunc); + array_type_metadata(element_type, IOFunc_receive, my_extra); if (!OidIsValid(my_extra->typiofunc)) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_FUNCTION), @@ -1391,13 +1393,14 @@ array_recv(PG_FUNCTION_ARGS) typlen = my_extra->typlen; typbyval = my_extra->typbyval; typalign = my_extra->typalign; + typstor = my_extra->typstorage; typioparam = my_extra->typioparam; dataPtr = (Datum *) palloc(nitems * sizeof(Datum)); nullsPtr = (bool *) palloc(nitems * sizeof(bool)); ReadArrayBinary(buf, nitems, &my_extra->proc, typioparam, typmod, - typlen, typbyval, typalign, + typlen, typbyval, typalign, typstor, dataPtr, nullsPtr, &hasnulls, &nbytes); if (hasnulls) @@ -1420,7 +1423,7 @@ array_recv(PG_FUNCTION_ARGS) CopyArrayEls(retval, dataPtr, nullsPtr, nitems, - typlen, typbyval, typalign, + typlen, typbyval, typalign, typstor, true); pfree(dataPtr); @@ -1438,7 +1441,7 @@ array_recv(PG_FUNCTION_ARGS) * nitems: total number of array elements (already read). * receiveproc: type-specific receive procedure for element datatype. * typioparam, typmod: auxiliary values to pass to receiveproc. - * typlen, typbyval, typalign: storage parameters of element datatype. + * typlen, typbyval, typalign, typstor: storage parameters of element datatype. * * Outputs: * values[]: filled with converted data values. @@ -1459,6 +1462,7 @@ ReadArrayBinary(StringInfo buf, int typlen, bool typbyval, char typalign, + char typstor, Datum *values, bool *nulls, bool *hasnulls, @@ -1524,7 +1528,7 @@ ReadArrayBinary(StringInfo buf, /* let's just make sure data is not toasted */ if (typlen == -1) values[i] = PointerGetDatum(PG_DETOAST_DATUM(values[i])); - totbytes = att_addlength_datum(totbytes, typlen, values[i]); + totbytes = att_addvarsize_datum(totbytes, typlen, typstor, values[i]); totbytes = att_align_nominal(totbytes, typalign); /* check for overflow of total request */ if (!AllocSizeIsValid(totbytes)) @@ -1578,10 +1582,7 @@ array_send(PG_FUNCTION_ARGS) if (my_extra->element_type != element_type) { /* Get info about element type, including its send proc */ - get_type_io_data(element_type, IOFunc_send, - &my_extra->typlen, &my_extra->typbyval, - &my_extra->typalign, &my_extra->typdelim, - &my_extra->typioparam, &my_extra->typiofunc); + array_type_metadata(element_type, IOFunc_send, my_extra); if (!OidIsValid(my_extra->typiofunc)) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_FUNCTION), @@ -1811,6 +1812,7 @@ array_cardinality(PG_FUNCTION_ARGS) * elmlen: pg_type.typlen for the array's element type * elmbyval: pg_type.typbyval for the array's element type * elmalign: pg_type.typalign for the array's element type + * elmstor: pg_type.typstorage for the array's element type * * Outputs: * The return value is the element Datum. @@ -1824,6 +1826,7 @@ array_get_element(Datum arraydatum, int elmlen, bool elmbyval, char elmalign, + char elmstor, bool *isNull) { int i, @@ -1860,6 +1863,7 @@ array_get_element(Datum arraydatum, elmlen, elmbyval, elmalign, + elmstor, isNull); } else @@ -1910,7 +1914,7 @@ array_get_element(Datum arraydatum, */ *isNull = false; retptr = array_seek(arraydataptr, 0, arraynullsptr, offset, - elmlen, elmbyval, elmalign); + elmlen, elmbyval, elmalign, elmstor); return ArrayCast(retptr, elmbyval, elmlen); } @@ -1921,7 +1925,8 @@ static Datum array_get_element_expanded(Datum arraydatum, int nSubscripts, int *indx, int arraytyplen, - int elmlen, bool elmbyval, char elmalign, + int elmlen, bool elmbyval, + char elmalign, char typstor, bool *isNull) { ExpandedArrayHeader *eah; @@ -1941,6 +1946,7 @@ array_get_element_expanded(Datum arraydatum, Assert(elmlen == eah->typlen); Assert(elmbyval == eah->typbyval); Assert(elmalign == eah->typalign); + Assert(typstor == eah->typstorage); ndim = eah->ndims; dim = eah->dims; @@ -2015,6 +2021,7 @@ array_get_element_expanded(Datum arraydatum, * elmlen: pg_type.typlen for the array's element type * elmbyval: pg_type.typbyval for the array's element type * elmalign: pg_type.typalign for the array's element type + * elmstor: pg_type.typstorage for the array's element type * * Outputs: * The return value is the new array Datum (it's never NULL) @@ -2036,7 +2043,8 @@ array_get_slice(Datum arraydatum, int arraytyplen, int elmlen, bool elmbyval, - char elmalign) + char elmalign, + char elmstor) { ArrayType *array; ArrayType *newarray; @@ -2124,7 +2132,7 @@ array_get_slice(Datum arraydatum, bytes = array_slice_size(arraydataptr, arraynullsptr, ndim, dim, lb, lowerIndx, upperIndx, - elmlen, elmbyval, elmalign); + elmlen, elmbyval, elmalign, elmstor); /* * Currently, we put a null bitmap in the result if the source has one; @@ -2160,7 +2168,7 @@ array_get_slice(Datum arraydatum, ndim, dim, lb, arraydataptr, arraynullsptr, lowerIndx, upperIndx, - elmlen, elmbyval, elmalign); + elmlen, elmbyval, elmalign, elmstor); return PointerGetDatum(newarray); } @@ -2182,6 +2190,7 @@ array_get_slice(Datum arraydatum, * elmlen: pg_type.typlen for the array's element type * elmbyval: pg_type.typbyval for the array's element type * elmalign: pg_type.typalign for the array's element type + * elmstor: pg_type.typstorage for the array's element type * * Result: * A new array is returned, just like the old except for the one @@ -2206,7 +2215,8 @@ array_set_element(Datum arraydatum, int arraytyplen, int elmlen, bool elmbyval, - char elmalign) + char elmalign, + char elmstor) { ArrayType *array; ArrayType *newarray; @@ -2257,7 +2267,7 @@ array_set_element(Datum arraydatum, resultarray = (char *) palloc(arraytyplen); memcpy(resultarray, DatumGetPointer(arraydatum), arraytyplen); elt_ptr = (char *) resultarray + indx[0] * elmlen; - ArrayCastAndSet(dataValue, elmlen, elmbyval, elmalign, elt_ptr); + ArrayCastAndSet(dataValue, elmlen, elmbyval, elmalign, elmstor, elt_ptr); return PointerGetDatum(resultarray); } @@ -2281,7 +2291,8 @@ array_set_element(Datum arraydatum, arraytyplen, elmlen, elmbyval, - elmalign); + elmalign, + elmstor); } /* detoast input array if necessary */ @@ -2307,7 +2318,8 @@ array_set_element(Datum arraydatum, return PointerGetDatum(construct_md_array(&dataValue, &isNull, nSubscripts, dim, lb, elmtype, - elmlen, elmbyval, elmalign)); + elmlen, elmbyval, + elmalign, elmstor)); } if (ndim != nSubscripts) @@ -2408,13 +2420,13 @@ array_set_element(Datum arraydatum, { offset = ArrayGetOffset(nSubscripts, dim, lb, indx); elt_ptr = array_seek(ARR_DATA_PTR(array), 0, oldnullbitmap, offset, - elmlen, elmbyval, elmalign); + elmlen, elmbyval, elmalign, elmstor); lenbefore = (int) (elt_ptr - ARR_DATA_PTR(array)); if (array_get_isnull(oldnullbitmap, offset)) olditemlen = 0; else { - olditemlen = att_addlength_pointer(0, elmlen, elt_ptr); + olditemlen = att_addvarsize_pointer(0, elmlen, elmstor, elt_ptr); olditemlen = att_align_nominal(olditemlen, elmalign); } lenafter = (int) (olddatasize - lenbefore - olditemlen); @@ -2424,7 +2436,7 @@ array_set_element(Datum arraydatum, newitemlen = 0; else { - newitemlen = att_addlength_datum(0, elmlen, dataValue); + newitemlen = att_addvarsize_datum(0, elmlen, elmstor, dataValue); newitemlen = att_align_nominal(newitemlen, elmalign); } @@ -2448,7 +2460,7 @@ array_set_element(Datum arraydatum, (char *) array + oldoverheadlen, lenbefore); if (!isNull) - ArrayCastAndSet(dataValue, elmlen, elmbyval, elmalign, + ArrayCastAndSet(dataValue, elmlen, elmbyval, elmalign, elmstor, (char *) newarray + overheadlen + lenbefore); memcpy((char *) newarray + overheadlen + lenbefore + newitemlen, (char *) array + oldoverheadlen + lenbefore + olditemlen, @@ -2502,7 +2514,8 @@ array_set_element_expanded(Datum arraydatum, int nSubscripts, int *indx, Datum dataValue, bool isNull, int arraytyplen, - int elmlen, bool elmbyval, char elmalign) + int elmlen, bool elmbyval, + char elmalign, char typstor) { ExpandedArrayHeader *eah; Datum *dvalues; @@ -2526,6 +2539,7 @@ array_set_element_expanded(Datum arraydatum, Assert(elmlen == eah->typlen); Assert(elmbyval == eah->typbyval); Assert(elmalign == eah->typalign); + Assert(typstor == eah->typstorage); /* * Copy dimension info into local storage. This allows us to modify the @@ -2782,6 +2796,7 @@ array_set_element_expanded(Datum arraydatum, * elmlen: pg_type.typlen for the array's element type * elmbyval: pg_type.typbyval for the array's element type * elmalign: pg_type.typalign for the array's element type + * elmstor: pg_type.typstorage for the array's element type * * Result: * A new array is returned, just like the old except for the @@ -2814,7 +2829,8 @@ array_set_slice(Datum arraydatum, int arraytyplen, int elmlen, bool elmbyval, - char elmalign) + char elmalign, + char elmstor) { ArrayType *array; ArrayType *srcArray; @@ -2875,7 +2891,7 @@ array_set_slice(Datum arraydatum, int nelems; Oid elmtype = ARR_ELEMTYPE(array); - deconstruct_array(srcArray, elmtype, elmlen, elmbyval, elmalign, + deconstruct_array(srcArray, elmtype, elmlen, elmbyval, elmalign, elmstor, &dvalues, &dnulls, &nelems); for (i = 0; i < nSubscripts; i++) @@ -2906,7 +2922,8 @@ array_set_slice(Datum arraydatum, return PointerGetDatum(construct_md_array(dvalues, dnulls, nSubscripts, dim, lb, elmtype, - elmlen, elmbyval, elmalign)); + elmlen, elmbyval, + elmalign, elmstor)); } if (ndim < nSubscripts || ndim <= 0 || ndim > MAXDIM) @@ -3026,7 +3043,7 @@ array_set_slice(Datum arraydatum, overheadlen = ARR_OVERHEAD_NONULLS(ndim); newitemsize = array_nelems_size(ARR_DATA_PTR(srcArray), 0, ARR_NULLBITMAP(srcArray), nsrcitems, - elmlen, elmbyval, elmalign); + elmlen, elmbyval, elmalign, elmstor); oldoverheadlen = ARR_DATA_OFFSET(array); olddatasize = ARR_SIZE(array) - oldoverheadlen; if (ndim > 1) @@ -3039,7 +3056,7 @@ array_set_slice(Datum arraydatum, ARR_NULLBITMAP(array), ndim, dim, lb, lowerIndx, upperIndx, - elmlen, elmbyval, elmalign); + elmlen, elmbyval, elmalign, elmstor); lenbefore = lenafter = 0; /* keep compiler quiet */ itemsbefore = itemsafter = nolditems = 0; } @@ -3060,7 +3077,7 @@ array_set_slice(Datum arraydatum, itemsbefore = Min(slicelb, oldub + 1) - oldlb; lenbefore = array_nelems_size(oldarraydata, 0, oldarraybitmap, itemsbefore, - elmlen, elmbyval, elmalign); + elmlen, elmbyval, elmalign, elmstor); /* count/size of old array entries that will be replaced by slice */ if (slicelb > sliceub) { @@ -3073,7 +3090,7 @@ array_set_slice(Datum arraydatum, olditemsize = array_nelems_size(oldarraydata + lenbefore, itemsbefore, oldarraybitmap, nolditems, - elmlen, elmbyval, elmalign); + elmlen, elmbyval, elmalign, elmstor); } /* count/size of old array entries that will go after the slice */ itemsafter = oldub + 1 - Max(sliceub + 1, oldlb); @@ -3099,7 +3116,7 @@ array_set_slice(Datum arraydatum, array_insert_slice(newarray, array, srcArray, ndim, dim, lb, lowerIndx, upperIndx, - elmlen, elmbyval, elmalign); + elmlen, elmbyval, elmalign, elmstor); } else { @@ -3144,11 +3161,11 @@ array_set_slice(Datum arraydatum, */ Datum array_ref(ArrayType *array, int nSubscripts, int *indx, - int arraytyplen, int elmlen, bool elmbyval, char elmalign, - bool *isNull) + int arraytyplen, int elmlen, bool elmbyval, + char elmalign, char elmstor, bool *isNull) { return array_get_element(PointerGetDatum(array), nSubscripts, indx, - arraytyplen, elmlen, elmbyval, elmalign, + arraytyplen, elmlen, elmbyval, elmalign, elmstor, isNull); } @@ -3161,14 +3178,15 @@ array_ref(ArrayType *array, int nSubscripts, int *indx, */ ArrayType * array_set(ArrayType *array, int nSubscripts, int *indx, - Datum dataValue, bool isNull, - int arraytyplen, int elmlen, bool elmbyval, char elmalign) + Datum dataValue, bool isNull, int arraytyplen, + int elmlen, bool elmbyval, char elmalign, char elmstor) { return DatumGetArrayTypeP(array_set_element(PointerGetDatum(array), nSubscripts, indx, dataValue, isNull, arraytyplen, - elmlen, elmbyval, elmalign)); + elmlen, elmbyval, + elmalign, elmstor)); } /* @@ -3220,6 +3238,7 @@ array_map(Datum arrayd, int typlen; bool typbyval; char typalign; + char typstor; array_iter iter; ArrayMetaState *inp_extra; ArrayMetaState *ret_extra; @@ -3260,15 +3279,17 @@ array_map(Datum arrayd, if (ret_extra->element_type != retType) { - get_typlenbyvalalign(retType, - &ret_extra->typlen, - &ret_extra->typbyval, - &ret_extra->typalign); + get_type_stores(retType, + &ret_extra->typlen, + &ret_extra->typbyval, + &ret_extra->typalign, + &ret_extra->typstorage); ret_extra->element_type = retType; } typlen = ret_extra->typlen; typbyval = ret_extra->typbyval; typalign = ret_extra->typalign; + typstor = ret_extra->typstorage; /* Allocate temporary arrays for new values */ values = (Datum *) palloc(nitems * sizeof(Datum)); @@ -3296,7 +3317,7 @@ array_map(Datum arrayd, if (typlen == -1) values[i] = PointerGetDatum(PG_DETOAST_DATUM(values[i])); /* Update total result size */ - nbytes = att_addlength_datum(nbytes, typlen, values[i]); + nbytes = att_addvarsize_datum(nbytes, typlen, typstor, values[i]); nbytes = att_align_nominal(nbytes, typalign); /* check for overflow of total request */ if (!AllocSizeIsValid(nbytes)) @@ -3328,7 +3349,7 @@ array_map(Datum arrayd, CopyArrayEls(result, values, nulls, nitems, - typlen, typbyval, typalign, + typlen, typbyval, typalign, typstor, false); /* @@ -3346,7 +3367,8 @@ array_map(Datum arrayd, * elems: array of Datum items to become the array contents * (NULL element values are not supported). * nelems: number of items - * elmtype, elmlen, elmbyval, elmalign: info for the datatype of the items + * elmtype, elmlen, elmbyval, elmalign, elmstor: + * info for the datatype of the items * * A palloc'd 1-D array object is constructed and returned. Note that * elem values will be copied into the object even if pass-by-ref type. @@ -3360,7 +3382,7 @@ array_map(Datum arrayd, ArrayType * construct_array(Datum *elems, int nelems, Oid elmtype, - int elmlen, bool elmbyval, char elmalign) + int elmlen, bool elmbyval, char elmalign, char elmstor) { int dims[1]; int lbs[1]; @@ -3369,13 +3391,13 @@ construct_array(Datum *elems, int nelems, lbs[0] = 1; return construct_md_array(elems, NULL, 1, dims, lbs, - elmtype, elmlen, elmbyval, elmalign); + elmtype, elmlen, elmbyval, elmalign, elmstor); } /* * Like construct_array(), where elmtype must be a built-in type, and - * elmlen/elmbyval/elmalign is looked up from hardcoded data. This is often - * useful when manipulating arrays from/for system catalogs. + * elmlen/elmbyval/elmalign/elmstor is looked up from hardcoded data. + * This is often useful when manipulating arrays from/for system catalogs. */ ArrayType * construct_array_builtin(Datum *elems, int nelems, Oid elmtype) @@ -3383,6 +3405,7 @@ construct_array_builtin(Datum *elems, int nelems, Oid elmtype) int elmlen; bool elmbyval; char elmalign; + char elmstor; switch (elmtype) { @@ -3390,48 +3413,56 @@ construct_array_builtin(Datum *elems, int nelems, Oid elmtype) elmlen = 1; elmbyval = true; elmalign = TYPALIGN_CHAR; + elmstor = TYPSTORAGE_PLAIN; break; case CSTRINGOID: elmlen = -2; elmbyval = false; elmalign = TYPALIGN_CHAR; + elmstor = TYPSTORAGE_PLAIN; break; case FLOAT4OID: elmlen = sizeof(float4); elmbyval = true; elmalign = TYPALIGN_INT; + elmstor = TYPSTORAGE_PLAIN; break; case FLOAT8OID: elmlen = sizeof(float8); elmbyval = FLOAT8PASSBYVAL; elmalign = TYPALIGN_DOUBLE; + elmstor = TYPSTORAGE_PLAIN; break; case INT2OID: elmlen = sizeof(int16); elmbyval = true; elmalign = TYPALIGN_SHORT; + elmstor = TYPSTORAGE_PLAIN; break; case INT4OID: elmlen = sizeof(int32); elmbyval = true; elmalign = TYPALIGN_INT; + elmstor = TYPSTORAGE_PLAIN; break; case INT8OID: elmlen = sizeof(int64); elmbyval = FLOAT8PASSBYVAL; elmalign = TYPALIGN_DOUBLE; + elmstor = TYPSTORAGE_PLAIN; break; case NAMEOID: elmlen = NAMEDATALEN; elmbyval = false; elmalign = TYPALIGN_CHAR; + elmstor = TYPSTORAGE_PLAIN; break; case OIDOID: @@ -3439,24 +3470,28 @@ construct_array_builtin(Datum *elems, int nelems, Oid elmtype) elmlen = sizeof(Oid); elmbyval = true; elmalign = TYPALIGN_INT; + elmstor = TYPSTORAGE_PLAIN; break; case TEXTOID: elmlen = -1; elmbyval = false; elmalign = TYPALIGN_INT; + elmstor = TYPSTORAGE_EXTENDED; break; case TIDOID: elmlen = sizeof(ItemPointerData); elmbyval = false; elmalign = TYPALIGN_SHORT; + elmstor = TYPSTORAGE_PLAIN; break; case XIDOID: elmlen = sizeof(TransactionId); elmbyval = true; elmalign = TYPALIGN_INT; + elmstor = TYPSTORAGE_PLAIN; break; default: @@ -3465,9 +3500,11 @@ construct_array_builtin(Datum *elems, int nelems, Oid elmtype) elmlen = 0; elmbyval = false; elmalign = 0; + elmstor = 0; } - return construct_array(elems, nelems, elmtype, elmlen, elmbyval, elmalign); + return construct_array(elems, nelems, elmtype, elmlen, elmbyval, + elmalign, elmstor); } /* @@ -3479,7 +3516,8 @@ construct_array_builtin(Datum *elems, int nelems, Oid elmtype) * ndims: number of dimensions * dims: integer array with size of each dimension * lbs: integer array with lower bound of each dimension - * elmtype, elmlen, elmbyval, elmalign: info for the datatype of the items + * elmtype, elmlen, elmbyval, elmalign, elmstor: + * info for the datatype of the items * * A palloc'd ndims-D array object is constructed and returned. Note that * elem values will be copied into the object even if pass-by-ref type. @@ -3496,7 +3534,8 @@ construct_md_array(Datum *elems, int ndims, int *dims, int *lbs, - Oid elmtype, int elmlen, bool elmbyval, char elmalign) + Oid elmtype, int elmlen, bool elmbyval, + char elmalign, char elmstor) { ArrayType *result; bool hasnulls; @@ -3536,7 +3575,7 @@ construct_md_array(Datum *elems, /* make sure data is not toasted */ if (elmlen == -1) elems[i] = PointerGetDatum(PG_DETOAST_DATUM(elems[i])); - nbytes = att_addlength_datum(nbytes, elmlen, elems[i]); + nbytes = att_addvarsize_datum(nbytes, elmlen, elmstor, elems[i]); nbytes = att_align_nominal(nbytes, elmalign); /* check for overflow of total request */ if (!AllocSizeIsValid(nbytes)) @@ -3567,7 +3606,7 @@ construct_md_array(Datum *elems, CopyArrayEls(result, elems, nulls, nelems, - elmlen, elmbyval, elmalign, + elmlen, elmbyval, elmalign, elmstor, false); return result; @@ -3610,7 +3649,8 @@ construct_empty_expanded_array(Oid element_type, * deconstruct_array --- simple method for extracting data from an array * * array: array object to examine (must not be NULL) - * elmtype, elmlen, elmbyval, elmalign: info for the datatype of the items + * elmtype, elmlen, elmbyval, elmalign, elmstor: + * info for the datatype of the items * elemsp: return value, set to point to palloc'd array of Datum values * nullsp: return value, set to point to palloc'd array of isnull markers * nelemsp: return value, set to number of extracted values @@ -3622,15 +3662,15 @@ construct_empty_expanded_array(Oid element_type, * If array elements are pass-by-ref data type, the returned Datums will * be pointers into the array object. * - * NOTE: it would be cleaner to look up the elmlen/elmbval/elmalign info - * from the system catalogs, given the elmtype. However, the caller is + * NOTE: it would be cleaner to look up the elmlen/elmbval/elmalign/elmstor + * info from the system catalogs, given the elmtype. However, the caller is * in a better position to cache this info across multiple uses, or even * to hard-wire values if the element type is hard-wired. */ void deconstruct_array(ArrayType *array, Oid elmtype, - int elmlen, bool elmbyval, char elmalign, + int elmlen, bool elmbyval, char elmalign, char elmstor, Datum **elemsp, bool **nullsp, int *nelemsp) { Datum *elems; @@ -3701,6 +3741,7 @@ deconstruct_array_builtin(ArrayType *array, int elmlen; bool elmbyval; char elmalign; + char elmstor; switch (elmtype) { @@ -3708,42 +3749,49 @@ deconstruct_array_builtin(ArrayType *array, elmlen = 1; elmbyval = true; elmalign = TYPALIGN_CHAR; + elmstor = TYPSTORAGE_PLAIN; break; case CSTRINGOID: elmlen = -2; elmbyval = false; elmalign = TYPALIGN_CHAR; + elmstor = TYPSTORAGE_PLAIN; break; case FLOAT8OID: elmlen = sizeof(float8); elmbyval = FLOAT8PASSBYVAL; elmalign = TYPALIGN_DOUBLE; + elmstor = TYPSTORAGE_PLAIN; break; case INT2OID: elmlen = sizeof(int16); elmbyval = true; elmalign = TYPALIGN_SHORT; + elmstor = TYPSTORAGE_PLAIN; break; case OIDOID: elmlen = sizeof(Oid); elmbyval = true; elmalign = TYPALIGN_INT; + elmstor = TYPSTORAGE_PLAIN; break; case TEXTOID: elmlen = -1; elmbyval = false; elmalign = TYPALIGN_INT; + elmstor = TYPSTORAGE_EXTENDED; break; case TIDOID: elmlen = sizeof(ItemPointerData); elmbyval = false; elmalign = TYPALIGN_SHORT; + elmstor = TYPSTORAGE_PLAIN; break; default: @@ -3752,9 +3800,11 @@ deconstruct_array_builtin(ArrayType *array, elmlen = 0; elmbyval = false; elmalign = 0; + elmstor = 0; } - deconstruct_array(array, elmtype, elmlen, elmbyval, elmalign, elemsp, nullsp, nelemsp); + deconstruct_array(array, elmtype, elmlen, elmbyval, elmalign, elmstor, + elemsp, nullsp, nelemsp); } /* @@ -4215,6 +4265,7 @@ hash_array(PG_FUNCTION_ARGS) record_typentry->typlen = typentry->typlen; record_typentry->typbyval = typentry->typbyval; record_typentry->typalign = typentry->typalign; + record_typentry->typstorage = typentry->typstorage; fmgr_info(F_HASH_RECORD, &record_typentry->hash_proc_finfo); MemoryContextSwitchTo(oldcontext); @@ -4392,6 +4443,7 @@ array_contain_compare(AnyArrayType *array1, AnyArrayType *array2, Oid collation, int typlen; bool typbyval; char typalign; + char typstor; int i; int j; array_iter it1; @@ -4423,6 +4475,7 @@ array_contain_compare(AnyArrayType *array1, AnyArrayType *array2, Oid collation, typlen = typentry->typlen; typbyval = typentry->typbyval; typalign = typentry->typalign; + typstor = typentry->typstorage; /* * Since we probably will need to scan array2 multiple times, it's @@ -4439,7 +4492,7 @@ array_contain_compare(AnyArrayType *array1, AnyArrayType *array2, Oid collation, } else deconstruct_array((ArrayType *) array2, - element_type, typlen, typbyval, typalign, + element_type, typlen, typbyval, typalign, typstor, &values2, &nulls2, &nelems2); /* @@ -4619,12 +4672,14 @@ array_create_iterator(ArrayType *arr, int slice_ndim, ArrayMetaState *mstate) iterator->typlen = mstate->typlen; iterator->typbyval = mstate->typbyval; iterator->typalign = mstate->typalign; + iterator->typstorage = mstate->typstorage; } else - get_typlenbyvalalign(ARR_ELEMTYPE(arr), - &iterator->typlen, - &iterator->typbyval, - &iterator->typalign); + get_type_stores(ARR_ELEMTYPE(arr), + &iterator->typlen, + &iterator->typbyval, + &iterator->typalign, + &iterator->typstorage); /* * Remember the slicing parameters. @@ -4743,7 +4798,8 @@ array_iterate(ArrayIterator iterator, Datum *value, bool *isnull) ARR_ELEMTYPE(iterator->arr), iterator->typlen, iterator->typbyval, - iterator->typalign); + iterator->typalign, + iterator->typstorage); *isnull = false; *value = PointerGetDatum(result); @@ -4828,6 +4884,7 @@ ArrayCastAndSet(Datum src, int typlen, bool typbyval, char typalign, + char typstor, char *dest) { int inc; @@ -4840,6 +4897,14 @@ ArrayCastAndSet(Datum src, memmove(dest, DatumGetPointer(src), typlen); inc = att_align_nominal(typlen, typalign); } + else if (TYPE_IS_PACKABLE(typlen, typstor) && VARATT_CAN_MAKE_SHORT(src)) + { + Assert(!typbyval); + inc = VARATT_CONVERTED_SHORT_SIZE(src); + SET_VARSIZE_SHORT(dest, inc); + memcpy(dest + 1, VARDATA(DatumGetPointer(src)), inc - 1); + inc = att_align_nominal(inc, typalign); + } else { Assert(!typbyval); @@ -4858,13 +4923,14 @@ ArrayCastAndSet(Datum src, * offset: 0-based linear element number of first element (the one at *ptr) * nullbitmap: start of array's null bitmap, or NULL if none * nitems: number of array elements to advance over (>= 0) - * typlen, typbyval, typalign: storage parameters of array element datatype + * typlen, typbyval, typalign, typstor: + * storage parameters of array element datatype * * It is caller's responsibility to ensure that nitems is within range */ static char * array_seek(char *ptr, int offset, bits8 *nullbitmap, int nitems, - int typlen, bool typbyval, char typalign) + int typlen, bool typbyval, char typalign, char typstor) { int bitmask; int i; @@ -4883,7 +4949,7 @@ array_seek(char *ptr, int offset, bits8 *nullbitmap, int nitems, { if (*nullbitmap & bitmask) { - ptr = att_addlength_pointer(ptr, typlen, ptr); + ptr = att_addvarsize_pointer(ptr, typlen, typstor, ptr); ptr = (char *) att_align_nominal(ptr, typalign); } bitmask <<= 1; @@ -4898,7 +4964,7 @@ array_seek(char *ptr, int offset, bits8 *nullbitmap, int nitems, { for (i = 0; i < nitems; i++) { - ptr = att_addlength_pointer(ptr, typlen, ptr); + ptr = att_addvarsize_pointer(ptr, typlen, typstor, ptr); ptr = (char *) att_align_nominal(ptr, typalign); } } @@ -4912,10 +4978,10 @@ array_seek(char *ptr, int offset, bits8 *nullbitmap, int nitems, */ static int array_nelems_size(char *ptr, int offset, bits8 *nullbitmap, int nitems, - int typlen, bool typbyval, char typalign) + int typlen, bool typbyval, char typalign, char typstor) { return array_seek(ptr, offset, nullbitmap, nitems, - typlen, typbyval, typalign) - ptr; + typlen, typbyval, typalign, typstor) - ptr; } /* @@ -4926,7 +4992,8 @@ array_nelems_size(char *ptr, int offset, bits8 *nullbitmap, int nitems, * srcptr: starting location in source array * offset: 0-based linear element number of first element (the one at *srcptr) * nullbitmap: start of source array's null bitmap, or NULL if none - * typlen, typbyval, typalign: storage parameters of array element datatype + * typlen, typbyval, typalign, typstor: + * storage parameters of array element datatype * * Returns number of bytes copied * @@ -4935,12 +5002,12 @@ array_nelems_size(char *ptr, int offset, bits8 *nullbitmap, int nitems, static int array_copy(char *destptr, int nitems, char *srcptr, int offset, bits8 *nullbitmap, - int typlen, bool typbyval, char typalign) + int typlen, bool typbyval, char typalign, char typstor) { int numbytes; numbytes = array_nelems_size(srcptr, offset, nullbitmap, nitems, - typlen, typbyval, typalign); + typlen, typbyval, typalign, typstor); memcpy(destptr, srcptr, numbytes); return numbytes; } @@ -5037,7 +5104,7 @@ static int array_slice_size(char *arraydataptr, bits8 *arraynullsptr, int ndim, int *dim, int *lb, int *st, int *endp, - int typlen, bool typbyval, char typalign) + int typlen, bool typbyval, char typalign, char typstor) { int src_offset, span[MAXDIM], @@ -5059,7 +5126,7 @@ array_slice_size(char *arraydataptr, bits8 *arraynullsptr, /* Else gotta do it the hard way */ src_offset = ArrayGetOffset(ndim, dim, lb, st); ptr = array_seek(arraydataptr, 0, arraynullsptr, src_offset, - typlen, typbyval, typalign); + typlen, typbyval, typalign, typstor); mda_get_prod(ndim, dim, prod); mda_get_offset_values(ndim, dist, prod, span); for (i = 0; i < ndim; i++) @@ -5070,12 +5137,12 @@ array_slice_size(char *arraydataptr, bits8 *arraynullsptr, if (dist[j]) { ptr = array_seek(ptr, src_offset, arraynullsptr, dist[j], - typlen, typbyval, typalign); + typlen, typbyval, typalign, typstor); src_offset += dist[j]; } if (!array_get_isnull(arraynullsptr, src_offset)) { - inc = att_addlength_pointer(0, typlen, ptr); + inc = att_addvarsize_pointer(0, typlen, typstor, ptr); inc = att_align_nominal(inc, typalign); ptr += inc; count += inc; @@ -5104,7 +5171,8 @@ array_extract_slice(ArrayType *newarray, int *endp, int typlen, bool typbyval, - char typalign) + char typalign, + char typstor) { char *destdataptr = ARR_DATA_PTR(newarray); bits8 *destnullsptr = ARR_NULLBITMAP(newarray); @@ -5121,7 +5189,7 @@ array_extract_slice(ArrayType *newarray, src_offset = ArrayGetOffset(ndim, dim, lb, st); srcdataptr = array_seek(arraydataptr, 0, arraynullsptr, src_offset, - typlen, typbyval, typalign); + typlen, typbyval, typalign, typstor); mda_get_prod(ndim, dim, prod); mda_get_range(ndim, span, st, endp); mda_get_offset_values(ndim, dist, prod, span); @@ -5136,12 +5204,12 @@ array_extract_slice(ArrayType *newarray, /* skip unwanted elements */ srcdataptr = array_seek(srcdataptr, src_offset, arraynullsptr, dist[j], - typlen, typbyval, typalign); + typlen, typbyval, typalign, typstor); src_offset += dist[j]; } inc = array_copy(destdataptr, 1, srcdataptr, src_offset, arraynullsptr, - typlen, typbyval, typalign); + typlen, typbyval, typalign, typstor); if (destnullsptr) array_bitmap_copy(destnullsptr, dest_offset, arraynullsptr, src_offset, @@ -5177,7 +5245,8 @@ array_insert_slice(ArrayType *destArray, int *endp, int typlen, bool typbyval, - char typalign) + char typalign, + char typstor) { char *destPtr = ARR_DATA_PTR(destArray); char *origPtr = ARR_DATA_PTR(origArray); @@ -5202,7 +5271,7 @@ array_insert_slice(ArrayType *destArray, /* copy items before the slice start */ inc = array_copy(destPtr, dest_offset, origPtr, 0, origBitmap, - typlen, typbyval, typalign); + typlen, typbyval, typalign, typstor); destPtr += inc; origPtr += inc; if (destBitmap) @@ -5222,7 +5291,7 @@ array_insert_slice(ArrayType *destArray, { inc = array_copy(destPtr, dist[j], origPtr, orig_offset, origBitmap, - typlen, typbyval, typalign); + typlen, typbyval, typalign, typstor); destPtr += inc; origPtr += inc; if (destBitmap) @@ -5235,7 +5304,7 @@ array_insert_slice(ArrayType *destArray, /* Copy new element at this slice position */ inc = array_copy(destPtr, 1, srcPtr, src_offset, srcBitmap, - typlen, typbyval, typalign); + typlen, typbyval, typalign, typstor); if (destBitmap) array_bitmap_copy(destBitmap, dest_offset, srcBitmap, src_offset, @@ -5246,14 +5315,14 @@ array_insert_slice(ArrayType *destArray, src_offset++; /* Advance over old element at this slice position */ origPtr = array_seek(origPtr, orig_offset, origBitmap, 1, - typlen, typbyval, typalign); + typlen, typbyval, typalign, typstor); orig_offset++; } while ((j = mda_next_tuple(ndim, indx, span)) != -1); /* don't miss any data at the end */ array_copy(destPtr, orignitems - orig_offset, origPtr, orig_offset, origBitmap, - typlen, typbyval, typalign); + typlen, typbyval, typalign, typstor); if (destBitmap) array_bitmap_copy(destBitmap, dest_offset, origBitmap, orig_offset, @@ -5330,10 +5399,11 @@ initArrayResultWithSize(Oid element_type, MemoryContext rcontext, MemoryContextAlloc(arr_context, astate->alen * sizeof(bool)); astate->nelems = 0; astate->element_type = element_type; - get_typlenbyvalalign(element_type, - &astate->typlen, - &astate->typbyval, - &astate->typalign); + get_type_stores(element_type, + &astate->typlen, + &astate->typbyval, + &astate->typalign, + &astate->typstorage); return astate; } @@ -5470,7 +5540,8 @@ makeMdArrayResult(ArrayBuildState *astate, astate->element_type, astate->typlen, astate->typbyval, - astate->typalign); + astate->typalign, + astate->typstorage); MemoryContextSwitchTo(oldcontext); @@ -6093,6 +6164,7 @@ array_fill_internal(ArrayType *dims, ArrayType *lbs, int16 elmlen; bool elmbyval; char elmalign; + char elmstor; ArrayMetaState *my_extra; /* @@ -6177,16 +6249,18 @@ array_fill_internal(ArrayType *dims, ArrayType *lbs, if (my_extra->element_type != elmtype) { /* Get info about element type */ - get_typlenbyvalalign(elmtype, - &my_extra->typlen, - &my_extra->typbyval, - &my_extra->typalign); + get_type_stores(elmtype, + &my_extra->typlen, + &my_extra->typbyval, + &my_extra->typalign, + &my_extra->typstorage); my_extra->element_type = elmtype; } elmlen = my_extra->typlen; elmbyval = my_extra->typbyval; elmalign = my_extra->typalign; + elmstor = my_extra->typstorage; /* compute required space */ if (!isnull) @@ -6225,7 +6299,7 @@ array_fill_internal(ArrayType *dims, ArrayType *lbs, p = ARR_DATA_PTR(result); for (i = 0; i < nitems; i++) - p += ArrayCastAndSet(value, elmlen, elmbyval, elmalign, p); + p += ArrayCastAndSet(value, elmlen, elmbyval, elmalign, elmstor, p); } else { @@ -6398,6 +6472,7 @@ array_replace_internal(ArrayType *array, int typlen; bool typbyval; char typalign; + char typstor; char *arraydataptr; bits8 *bitmap; int bitmask; @@ -6442,6 +6517,7 @@ array_replace_internal(ArrayType *array, typlen = typentry->typlen; typbyval = typentry->typbyval; typalign = typentry->typalign; + typstor = typentry->typstorage; /* * Detoast values if they are toasted. The replacement value must be @@ -6502,7 +6578,7 @@ array_replace_internal(ArrayType *array, { isNull = false; elt = fetch_att(arraydataptr, typbyval, typlen); - arraydataptr = att_addlength_datum(arraydataptr, typlen, elt); + arraydataptr = att_addvarsize_datum(arraydataptr, typlen, typstor, elt); arraydataptr = (char *) att_align_nominal(arraydataptr, typalign); if (search_isnull) @@ -6549,7 +6625,7 @@ array_replace_internal(ArrayType *array, else { /* Update total result size */ - nbytes = att_addlength_datum(nbytes, typlen, values[nresult]); + nbytes = att_addvarsize_datum(nbytes, typlen, typstor, values[nresult]); nbytes = att_align_nominal(nbytes, typalign); /* check for overflow of total request */ if (!AllocSizeIsValid(nbytes)) @@ -6619,7 +6695,7 @@ array_replace_internal(ArrayType *array, /* Insert data into result array */ CopyArrayEls(result, values, nulls, nresult, - typlen, typbyval, typalign, + typlen, typbyval, typalign, typstor, false); pfree(values); @@ -6925,6 +7001,7 @@ trim_array(PG_FUNCTION_ARGS) int16 elmlen; bool elmbyval; char elmalign; + char elmstor; int lower[MAXDIM]; int upper[MAXDIM]; bool lowerProvided[MAXDIM]; @@ -6948,12 +7025,12 @@ trim_array(PG_FUNCTION_ARGS) } /* Fetch the needed information about the element type */ - get_typlenbyvalalign(ARR_ELEMTYPE(v), &elmlen, &elmbyval, &elmalign); + get_type_stores(ARR_ELEMTYPE(v), &elmlen, &elmbyval, &elmalign, &elmstor); /* Get the slice */ result = array_get_slice(PointerGetDatum(v), 1, upper, lower, upperProvided, lowerProvided, - -1, elmlen, elmbyval, elmalign); + -1, elmlen, elmbyval, elmalign, elmstor); PG_RETURN_DATUM(result); } diff --git a/src/backend/utils/adt/arraysubs.c b/src/backend/utils/adt/arraysubs.c index 6f68dfa5b23..1af83eff70a 100644 --- a/src/backend/utils/adt/arraysubs.c +++ b/src/backend/utils/adt/arraysubs.c @@ -34,6 +34,7 @@ typedef struct ArraySubWorkspace int16 refelemlength; /* typlen of the array element type */ bool refelembyval; /* is the element type pass-by-value? */ char refelemalign; /* typalign of the element type */ + char refelemstorage; /* typstorage of the element type */ /* * Subscript values converted to integers. Note that these arrays must be @@ -250,6 +251,7 @@ array_subscript_fetch(ExprState *state, workspace->refelemlength, workspace->refelembyval, workspace->refelemalign, + workspace->refelemstorage, op->resnull); } @@ -280,7 +282,8 @@ array_subscript_fetch_slice(ExprState *state, workspace->refattrlength, workspace->refelemlength, workspace->refelembyval, - workspace->refelemalign); + workspace->refelemalign, + workspace->refelemstorage); /* The slice is never NULL, so no need to change *op->resnull */ } @@ -330,7 +333,8 @@ array_subscript_assign(ExprState *state, workspace->refattrlength, workspace->refelemlength, workspace->refelembyval, - workspace->refelemalign); + workspace->refelemalign, + workspace->refelemstorage); /* The result is never NULL, so no need to change *op->resnull */ } @@ -383,7 +387,8 @@ array_subscript_assign_slice(ExprState *state, workspace->refattrlength, workspace->refelemlength, workspace->refelembyval, - workspace->refelemalign); + workspace->refelemalign, + workspace->refelemstorage); /* The result is never NULL, so no need to change *op->resnull */ } @@ -417,6 +422,7 @@ array_subscript_fetch_old(ExprState *state, workspace->refelemlength, workspace->refelembyval, workspace->refelemalign, + workspace->refelemstorage, &sbsrefstate->prevnull); } @@ -460,7 +466,8 @@ array_subscript_fetch_old_slice(ExprState *state, workspace->refattrlength, workspace->refelemlength, workspace->refelembyval, - workspace->refelemalign); + workspace->refelemalign, + workspace->refelemstorage); /* slices of non-null arrays are never null */ sbsrefstate->prevnull = false; } @@ -504,10 +511,11 @@ array_exec_setup(const SubscriptingRef *sbsref, */ workspace->refelemtype = sbsref->refelemtype; workspace->refattrlength = get_typlen(sbsref->refcontainertype); - get_typlenbyvalalign(sbsref->refelemtype, - &workspace->refelemlength, - &workspace->refelembyval, - &workspace->refelemalign); + get_type_stores(sbsref->refelemtype, + &workspace->refelemlength, + &workspace->refelembyval, + &workspace->refelemalign, + &workspace->refelemstorage); /* * Pass back pointers to appropriate step execution functions. diff --git a/src/backend/utils/adt/enum.c b/src/backend/utils/adt/enum.c index d4c2aa0e7e9..4d74ac90117 100644 --- a/src/backend/utils/adt/enum.c +++ b/src/backend/utils/adt/enum.c @@ -608,7 +608,7 @@ enum_range_internal(Oid enumtypoid, Oid lower, Oid upper) /* and build the result array */ /* note this hardwires some details about the representation of Oid */ result = construct_array(elems, cnt, enumtypoid, - sizeof(Oid), true, TYPALIGN_INT); + sizeof(Oid), true, TYPALIGN_INT, TYPSTORAGE_PLAIN); pfree(elems); diff --git a/src/backend/utils/adt/json.c b/src/backend/utils/adt/json.c index 058aade2af4..ef473cec622 100644 --- a/src/backend/utils/adt/json.c +++ b/src/backend/utils/adt/json.c @@ -484,6 +484,7 @@ array_to_json_internal(Datum array, StringInfo result, bool use_line_feeds) int16 typlen; bool typbyval; char typalign; + char typstor; JsonTypeCategory tcategory; Oid outfuncoid; @@ -497,14 +498,14 @@ array_to_json_internal(Datum array, StringInfo result, bool use_line_feeds) return; } - get_typlenbyvalalign(element_type, - &typlen, &typbyval, &typalign); + get_type_stores(element_type, + &typlen, &typbyval, &typalign, &typstor); json_categorize_type(element_type, false, &tcategory, &outfuncoid); deconstruct_array(v, element_type, typlen, typbyval, - typalign, &elements, &nulls, + typalign, typstor, &elements, &nulls, &nitems); array_dim_to_json(result, 0, ndim, dim, elements, nulls, &count, tcategory, diff --git a/src/backend/utils/adt/jsonb.c b/src/backend/utils/adt/jsonb.c index d602df4eeb5..4ccf4400ea7 100644 --- a/src/backend/utils/adt/jsonb.c +++ b/src/backend/utils/adt/jsonb.c @@ -904,6 +904,7 @@ array_to_jsonb_internal(Datum array, JsonbInState *result) int16 typlen; bool typbyval; char typalign; + char typstor; JsonTypeCategory tcategory; Oid outfuncoid; @@ -918,14 +919,14 @@ array_to_jsonb_internal(Datum array, JsonbInState *result) return; } - get_typlenbyvalalign(element_type, - &typlen, &typbyval, &typalign); + get_type_stores(element_type, + &typlen, &typbyval, &typalign, &typstor); json_categorize_type(element_type, true, &tcategory, &outfuncoid); deconstruct_array(v, element_type, typlen, typbyval, - typalign, &elements, &nulls, + typalign, typstor, &elements, &nulls, &nitems); array_dim_to_jsonb(result, 0, ndim, dim, elements, nulls, &count, tcategory, diff --git a/src/backend/utils/adt/multirangetypes.c b/src/backend/utils/adt/multirangetypes.c index 35fd825babe..a28f9735606 100644 --- a/src/backend/utils/adt/multirangetypes.c +++ b/src/backend/utils/adt/multirangetypes.c @@ -996,7 +996,8 @@ multirange_constructor2(PG_FUNCTION_ARGS) else { deconstruct_array(rangeArray, rngtypid, rangetyp->typlen, rangetyp->typbyval, - rangetyp->typalign, &elements, &nulls, &range_count); + rangetyp->typalign, rangetyp->typstorage, + &elements, &nulls, &range_count); ranges = palloc0(range_count * sizeof(RangeType *)); for (i = 0; i < range_count; i++) diff --git a/src/backend/utils/adt/orderedsetaggs.c b/src/backend/utils/adt/orderedsetaggs.c index b8bdc667dbc..da63a04af31 100644 --- a/src/backend/utils/adt/orderedsetaggs.c +++ b/src/backend/utils/adt/orderedsetaggs.c @@ -80,6 +80,7 @@ typedef struct OSAPerQueryState int16 typLen; bool typByVal; char typAlign; + char typStorage; /* Info about sort ordering: */ Oid sortOperator; Oid eqOperator; @@ -264,10 +265,11 @@ ordered_set_startup(FunctionCallInfo fcinfo, bool use_tuples) qstate->sortNullsFirst = sortcl->nulls_first; /* Save datatype info */ - get_typlenbyvalalign(qstate->sortColType, - &qstate->typLen, - &qstate->typByVal, - &qstate->typAlign); + get_type_stores(qstate->sortColType, + &qstate->typLen, + &qstate->typByVal, + &qstate->typAlign, + &qstate->typStorage); } fcinfo->flinfo->fn_extra = qstate; @@ -838,7 +840,8 @@ percentile_disc_multi_final(PG_FUNCTION_ARGS) osastate->qstate->sortColType, osastate->qstate->typLen, osastate->qstate->typByVal, - osastate->qstate->typAlign)); + osastate->qstate->typAlign, + osastate->qstate->typStorage)); } /* @@ -847,7 +850,8 @@ percentile_disc_multi_final(PG_FUNCTION_ARGS) static Datum percentile_cont_multi_final_common(FunctionCallInfo fcinfo, Oid expect_type, - int16 typLen, bool typByVal, char typAlign, + int16 typLen, bool typByVal, + char typAlign, char typStor, LerpFunc lerpfunc) { OSAPerGroupState *osastate; @@ -994,7 +998,7 @@ percentile_cont_multi_final_common(FunctionCallInfo fcinfo, expect_type, typLen, typByVal, - typAlign)); + typAlign, typStor)); } /* @@ -1009,6 +1013,7 @@ percentile_cont_float8_multi_final(PG_FUNCTION_ARGS) sizeof(float8), FLOAT8PASSBYVAL, TYPALIGN_DOUBLE, + TYPSTORAGE_PLAIN, float8_lerp); } @@ -1022,6 +1027,7 @@ percentile_cont_interval_multi_final(PG_FUNCTION_ARGS) INTERVALOID, /* hard-wired info on type interval */ 16, false, TYPALIGN_DOUBLE, + TYPSTORAGE_PLAIN, interval_lerp); } diff --git a/src/backend/utils/adt/rangetypes.c b/src/backend/utils/adt/rangetypes.c index dc714345222..80b0a240251 100644 --- a/src/backend/utils/adt/rangetypes.c +++ b/src/backend/utils/adt/rangetypes.c @@ -30,6 +30,7 @@ */ #include "postgres.h" +#include "catalog/pg_type.h" #include "common/hashfn.h" #include "libpq/pqformat.h" #include "miscadmin.h" @@ -2671,10 +2672,6 @@ range_contains_elem_internal(TypeCacheEntry *typcache, const RangeType *r, Datum * details. */ -/* Does datatype allow packing into the 1-byte-header varlena format? */ -#define TYPE_IS_PACKABLE(typlen, typstorage) \ - ((typlen) == -1 && (typstorage) != TYPSTORAGE_PLAIN) - /* * Increment data_length by the space needed by the datum, including any * preceding alignment padding. diff --git a/src/backend/utils/adt/regexp.c b/src/backend/utils/adt/regexp.c index 42aec95738d..d6589bd24be 100644 --- a/src/backend/utils/adt/regexp.c +++ b/src/backend/utils/adt/regexp.c @@ -1664,7 +1664,8 @@ build_regexp_match_result(regexp_matches_ctx *matchctx) lbs[0] = 1; /* XXX: this hardcodes assumptions about the text type */ return construct_md_array(elems, nulls, 1, dims, lbs, - TEXTOID, -1, false, TYPALIGN_INT); + TEXTOID, -1, false, + TYPALIGN_INT, TYPSTORAGE_EXTENDED); } /* diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c index be1f1f50b78..15d769f55b9 100644 --- a/src/backend/utils/adt/ruleutils.c +++ b/src/backend/utils/adt/ruleutils.c @@ -3055,6 +3055,7 @@ pg_get_functiondef(PG_FUNCTION_ARGS) -1 /* TEXT's typlen */ , false /* TEXT's typbyval */ , TYPALIGN_INT /* TEXT's typalign */ , + TYPSTORAGE_EXTENDED /* TEXT's typalign */ , &isnull); if (!isnull) { diff --git a/src/backend/utils/adt/selfuncs.c b/src/backend/utils/adt/selfuncs.c index 08fa6774d9c..48e6212354c 100644 --- a/src/backend/utils/adt/selfuncs.c +++ b/src/backend/utils/adt/selfuncs.c @@ -1926,6 +1926,7 @@ scalararraysel(PlannerInfo *root, int16 elmlen; bool elmbyval; char elmalign; + char elmstor; int num_elems; Datum *elem_values; bool *elem_nulls; @@ -1934,11 +1935,11 @@ scalararraysel(PlannerInfo *root, if (arrayisnull) /* qual can't succeed if null array */ return (Selectivity) 0.0; arrayval = DatumGetArrayTypeP(arraydatum); - get_typlenbyvalalign(ARR_ELEMTYPE(arrayval), - &elmlen, &elmbyval, &elmalign); + get_type_stores(ARR_ELEMTYPE(arrayval), + &elmlen, &elmbyval, &elmalign, &elmstor); deconstruct_array(arrayval, ARR_ELEMTYPE(arrayval), - elmlen, elmbyval, elmalign, + elmlen, elmbyval, elmalign, elmstor, &elem_values, &elem_nulls, &num_elems); /* @@ -7488,6 +7489,7 @@ gincost_scalararrayopexpr(PlannerInfo *root, int16 elmlen; bool elmbyval; char elmalign; + char elmstor; int numElems; Datum *elemValues; bool *elemNulls; @@ -7523,11 +7525,11 @@ gincost_scalararrayopexpr(PlannerInfo *root, /* Otherwise, extract the array elements and iterate over them */ arrayval = DatumGetArrayTypeP(((Const *) rightop)->constvalue); - get_typlenbyvalalign(ARR_ELEMTYPE(arrayval), - &elmlen, &elmbyval, &elmalign); + get_type_stores(ARR_ELEMTYPE(arrayval), + &elmlen, &elmbyval, &elmalign, &elmstor); deconstruct_array(arrayval, ARR_ELEMTYPE(arrayval), - elmlen, elmbyval, elmalign, + elmlen, elmbyval, elmalign, elmstor, &elemValues, &elemNulls, &numElems); memset(&arraycounts, 0, sizeof(arraycounts)); diff --git a/src/backend/utils/adt/tsvector_op.c b/src/backend/utils/adt/tsvector_op.c index f75e25388ca..6c4c6c30163 100644 --- a/src/backend/utils/adt/tsvector_op.c +++ b/src/backend/utils/adt/tsvector_op.c @@ -329,8 +329,8 @@ tsvector_setweight_by_filter(PG_FUNCTION_ARGS) if (nulls[i]) continue; - lex = VARDATA(dlexemes[i]); - lex_len = VARSIZE(dlexemes[i]) - VARHDRSZ; + lex = VARDATA_ANY(dlexemes[i]); + lex_len = VARSIZE_ANY_EXHDR(dlexemes[i]); lex_pos = tsvector_bsearch(tsout, lex, lex_len); if (lex_pos >= 0 && (j = POSDATALEN(tsout, entry + lex_pos)) != 0) @@ -605,8 +605,8 @@ tsvector_delete_arr(PG_FUNCTION_ARGS) if (nulls[i]) continue; - lex = VARDATA(dlexemes[i]); - lex_len = VARSIZE(dlexemes[i]) - VARHDRSZ; + lex = VARDATA_ANY(dlexemes[i]); + lex_len = VARSIZE_ANY_EXHDR(dlexemes[i]); lex_pos = tsvector_bsearch(tsin, lex, lex_len); if (lex_pos >= 0) @@ -770,7 +770,7 @@ array_to_tsvector(PG_FUNCTION_ARGS) (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), errmsg("lexeme array may not contain nulls"))); - if (VARSIZE(dlexemes[i]) - VARHDRSZ == 0) + if (VARSIZE_ANY_EXHDR(dlexemes[i]) == 0) ereport(ERROR, (errcode(ERRCODE_ZERO_LENGTH_CHARACTER_STRING), errmsg("lexeme array may not contain empty strings"))); @@ -786,7 +786,7 @@ array_to_tsvector(PG_FUNCTION_ARGS) /* Calculate space needed for surviving lexemes. */ for (i = 0; i < nitems; i++) - datalen += VARSIZE(dlexemes[i]) - VARHDRSZ; + datalen += VARSIZE_ANY_EXHDR(dlexemes[i]); tslen = CALCDATASIZE(nitems, datalen); /* Allocate and fill tsvector. */ @@ -798,8 +798,8 @@ array_to_tsvector(PG_FUNCTION_ARGS) cur = STRPTR(tsout); for (i = 0; i < nitems; i++) { - char *lex = VARDATA(dlexemes[i]); - int lex_len = VARSIZE(dlexemes[i]) - VARHDRSZ; + char *lex = VARDATA_ANY(dlexemes[i]); + int lex_len = VARSIZE_ANY_EXHDR(dlexemes[i]); memcpy(cur, lex, lex_len); arrout[i].haspos = 0; diff --git a/src/backend/utils/adt/varlena.c b/src/backend/utils/adt/varlena.c index 533bebc1c7b..4b43f934c2a 100644 --- a/src/backend/utils/adt/varlena.c +++ b/src/backend/utils/adt/varlena.c @@ -4867,10 +4867,7 @@ array_to_text_internal(FunctionCallInfo fcinfo, ArrayType *v, /* * Get info about element type, including its output conversion proc */ - get_type_io_data(element_type, IOFunc_output, - &my_extra->typlen, &my_extra->typbyval, - &my_extra->typalign, &my_extra->typdelim, - &my_extra->typioparam, &my_extra->typiofunc); + array_type_metadata(element_type, IOFunc_output, my_extra); fmgr_info_cxt(my_extra->typiofunc, &my_extra->proc, fcinfo->flinfo->fn_mcxt); my_extra->element_type = element_type; @@ -5678,6 +5675,7 @@ text_format(PG_FUNCTION_ARGS) int16 elmlen; bool elmbyval; char elmalign; + char elmstor; int nitems; /* Should have just the one argument */ @@ -5702,12 +5700,12 @@ text_format(PG_FUNCTION_ARGS) /* Get info about array element type */ element_type = ARR_ELEMTYPE(arr); - get_typlenbyvalalign(element_type, - &elmlen, &elmbyval, &elmalign); + get_type_stores(element_type, + &elmlen, &elmbyval, &elmalign, &elmstor); /* Extract all array elements */ deconstruct_array(arr, element_type, elmlen, elmbyval, elmalign, - &elements, &nulls, &nitems); + elmstor, &elements, &nulls, &nitems); } nargs = nitems + 1; diff --git a/src/backend/utils/adt/xml.c b/src/backend/utils/adt/xml.c index 0898cb1be4c..fd28af187ad 100644 --- a/src/backend/utils/adt/xml.c +++ b/src/backend/utils/adt/xml.c @@ -2482,6 +2482,7 @@ map_sql_value_to_xml_value(Datum value, Oid type, bool xml_escape_strings) int16 elmlen; bool elmbyval; char elmalign; + char elmstor; int num_elems; Datum *elem_values; bool *elem_nulls; @@ -2490,10 +2491,11 @@ map_sql_value_to_xml_value(Datum value, Oid type, bool xml_escape_strings) array = DatumGetArrayTypeP(value); elmtype = ARR_ELEMTYPE(array); - get_typlenbyvalalign(elmtype, &elmlen, &elmbyval, &elmalign); + get_type_stores(elmtype, &elmlen, + &elmbyval, &elmalign, &elmstor); deconstruct_array(array, elmtype, - elmlen, elmbyval, elmalign, + elmlen, elmbyval, elmalign, elmstor, &elem_values, &elem_nulls, &num_elems); diff --git a/src/backend/utils/cache/lsyscache.c b/src/backend/utils/cache/lsyscache.c index a85dc0d891f..ec2775918ba 100644 --- a/src/backend/utils/cache/lsyscache.c +++ b/src/backend/utils/cache/lsyscache.c @@ -2284,6 +2284,30 @@ get_typlenbyvalalign(Oid typid, int16 *typlen, bool *typbyval, ReleaseSysCache(tp); } +/* + * get_type_stores + * + * A four-fer: given the type OID, return typlen, + * typbyval, typalign, typstorage. + */ +void +get_type_stores(Oid typid, int16 *typlen, bool *typbyval, + char *typalign, char *typstor) +{ + HeapTuple tp; + Form_pg_type typtup; + + tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid)); + if (!HeapTupleIsValid(tp)) + elog(ERROR, "cache lookup failed for type %u", typid); + typtup = (Form_pg_type) GETSTRUCT(tp); + *typlen = typtup->typlen; + *typbyval = typtup->typbyval; + *typalign = typtup->typalign; + *typstor = typtup->typstorage; + ReleaseSysCache(tp); +} + /* * getTypeIOParam * Given a pg_type row, select the type OID to pass to I/O functions @@ -2394,6 +2418,63 @@ get_type_io_data(Oid typid, ReleaseSysCache(typeTuple); } +/* + * array_type_metadata + * + * A six-fer: given the type OID, return typlen, typbyval, typalign, + * typdelim, typioparam, and IO function OID. The IO function + * returned is controlled by IOFuncSelector + */ +void +array_type_metadata(Oid typid, + IOFuncSelector which_func, + ArrayMetaState *metadata) +{ + HeapTuple typeTuple; + Form_pg_type typeStruct; + + /* + * In bootstrap mode, pass it off to bootstrap.c. This hack allows us to + * use array_in and array_out during bootstrap. + */ + if (unlikely(IsBootstrapProcessingMode())) + { + boot_array_type_metadata(typid, + which_func, + metadata); + + return; + } + + typeTuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid)); + if (!HeapTupleIsValid(typeTuple)) + elog(ERROR, "cache lookup failed for type %u", typid); + typeStruct = (Form_pg_type) GETSTRUCT(typeTuple); + + metadata->typlen = typeStruct->typlen; + metadata->typbyval = typeStruct->typbyval; + metadata->typalign = typeStruct->typalign; + metadata->typstorage = typeStruct->typstorage; + metadata->typdelim = typeStruct->typdelim; + metadata->typioparam = getTypeIOParam(typeTuple); + switch (which_func) + { + case IOFunc_input: + metadata->typiofunc = typeStruct->typinput; + break; + case IOFunc_output: + metadata->typiofunc = typeStruct->typoutput; + break; + case IOFunc_receive: + metadata->typiofunc = typeStruct->typreceive; + break; + case IOFunc_send: + metadata->typiofunc = typeStruct->typsend; + break; + } + ReleaseSysCache(typeTuple); +} + #ifdef NOT_USED char get_typalign(Oid typid) @@ -3287,6 +3368,7 @@ get_attstatsslot(AttStatsSlot *sslot, HeapTuple statstuple, typeForm->typlen, typeForm->typbyval, typeForm->typalign, + typeForm->typstorage, &sslot->values, NULL, &sslot->nvalues); /* diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c index 1ce7eb9da8f..f6483a6d02e 100644 --- a/src/backend/utils/cache/relcache.c +++ b/src/backend/utils/cache/relcache.c @@ -627,6 +627,7 @@ RelationBuildTupleDesc(Relation relation) attp->attlen, attp->attbyval, attp->attalign, + attp->attstorage, &is_null); Assert(!is_null); if (attp->attbyval) diff --git a/src/backend/utils/fmgr/funcapi.c b/src/backend/utils/fmgr/funcapi.c index 05d763fa06e..c85f6048029 100644 --- a/src/backend/utils/fmgr/funcapi.c +++ b/src/backend/utils/fmgr/funcapi.c @@ -2023,6 +2023,7 @@ extract_variadic_args(FunctionCallInfo fcinfo, int variadic_start, Oid element_type; bool typbyval; char typalign; + char typstor; int16 typlen; Assert(PG_NARGS() == variadic_start + 1); @@ -2033,10 +2034,10 @@ extract_variadic_args(FunctionCallInfo fcinfo, int variadic_start, array_in = PG_GETARG_ARRAYTYPE_P(variadic_start); element_type = ARR_ELEMTYPE(array_in); - get_typlenbyvalalign(element_type, - &typlen, &typbyval, &typalign); + get_type_stores(element_type, + &typlen, &typbyval, &typalign, &typstor); deconstruct_array(array_in, element_type, typlen, typbyval, - typalign, &args_res, &nulls_res, + typalign, typstor, &args_res, &nulls_res, &nargs); /* All the elements of the array have the same type */ diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index c10c0844ab6..c79a04a3472 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -6420,6 +6420,7 @@ TransformGUCArray(ArrayType *array, List **names, List **values) -1 /* TEXT's typlen */ , false /* TEXT's typbyval */ , TYPALIGN_INT /* TEXT's typalign */ , + TYPSTORAGE_EXTENDED /* TEXT's typalign */ , &isnull); if (isnull) @@ -6529,6 +6530,7 @@ GUCArrayAdd(ArrayType *array, const char *name, const char *value) -1 /* TEXT's typlen */ , false /* TEXT's typbyval */ , TYPALIGN_INT /* TEXT's typalign */ , + TYPSTORAGE_EXTENDED /* TEXT's typalign */ , &isnull); if (isnull) continue; @@ -6548,7 +6550,8 @@ GUCArrayAdd(ArrayType *array, const char *name, const char *value) -1 /* varlena array */ , -1 /* TEXT's typlen */ , false /* TEXT's typbyval */ , - TYPALIGN_INT /* TEXT's typalign */ ); + TYPALIGN_INT /* TEXT's typalign */ , + TYPSTORAGE_EXTENDED /* TEXT's typstorage */ ); } else a = construct_array_builtin(&datum, 1, TEXTOID); @@ -6598,6 +6601,7 @@ GUCArrayDelete(ArrayType *array, const char *name) -1 /* TEXT's typlen */ , false /* TEXT's typbyval */ , TYPALIGN_INT /* TEXT's typalign */ , + TYPSTORAGE_EXTENDED /* TEXT's typalign */ , &isnull); if (isnull) continue; @@ -6616,7 +6620,8 @@ GUCArrayDelete(ArrayType *array, const char *name) -1 /* varlenarray */ , -1 /* TEXT's typlen */ , false /* TEXT's typbyval */ , - TYPALIGN_INT /* TEXT's typalign */ ); + TYPALIGN_INT /* TEXT's typalign */ , + TYPSTORAGE_EXTENDED /* TEXT's typstorage */ ); else newarray = construct_array_builtin(&d, 1, TEXTOID); @@ -6662,6 +6667,7 @@ GUCArrayReset(ArrayType *array) -1 /* TEXT's typlen */ , false /* TEXT's typbyval */ , TYPALIGN_INT /* TEXT's typalign */ , + TYPSTORAGE_EXTENDED /* TEXT's typalign */ , &isnull); if (isnull) continue; @@ -6682,7 +6688,8 @@ GUCArrayReset(ArrayType *array) -1 /* varlenarray */ , -1 /* TEXT's typlen */ , false /* TEXT's typbyval */ , - TYPALIGN_INT /* TEXT's typalign */ ); + TYPALIGN_INT /* TEXT's typalign */ , + TYPSTORAGE_EXTENDED /* TEXT's typstorage */ ); else newarray = construct_array_builtin(&d, 1, TEXTOID); diff --git a/src/include/access/tupmacs.h b/src/include/access/tupmacs.h index 0de67e3602a..f2264767fbb 100644 --- a/src/include/access/tupmacs.h +++ b/src/include/access/tupmacs.h @@ -199,6 +199,35 @@ fetch_att(const void *T, bool attbyval, int attlen) )) \ ) +/* + * att_addvarsize_datum increments the given offset by the space needed for + * the given Datum variable to store it. attdatum is only accessed if we are + * dealing with a variable-length attribute. + */ +#define att_addvarsize_datum(cur_offset, typlen, typstor, datum) \ + att_addvarsize_pointer(cur_offset, typlen, typstor, DatumGetPointer(datum)) + +#define att_addvarsize_pointer(cur_offset, typlen, typstor, ptr) \ +( \ + ((typlen) > 0) ? \ + ( \ + (cur_offset) + (typlen) \ + ) \ + : (((typlen) == -1) ? \ + ( \ + ((TYPE_IS_PACKABLE(typlen, typstor) && VARATT_CAN_MAKE_SHORT(ptr)) ? \ + (cur_offset) + VARATT_CONVERTED_SHORT_SIZE(ptr) \ + : \ + (cur_offset) + VARSIZE_ANY(ptr) \ + ) \ + ) \ + : \ + ( \ + AssertMacro((typlen) == -2), \ + (cur_offset) + (strlen((char *) (ptr)) + 1) \ + )) \ +) + #ifndef FRONTEND /* * store_att_byval is a partial inverse of fetch_att: store a given Datum diff --git a/src/include/bootstrap/bootstrap.h b/src/include/bootstrap/bootstrap.h index 33035d4ed82..9d55dcc419e 100644 --- a/src/include/bootstrap/bootstrap.h +++ b/src/include/bootstrap/bootstrap.h @@ -16,6 +16,8 @@ #include "nodes/execnodes.h" #include "nodes/parsenodes.h" +#include "utils/array.h" +#include "utils/lsyscache.h" /* @@ -61,6 +63,10 @@ union YYSTYPE; typedef void *yyscan_t; #endif +extern void boot_array_type_metadata(Oid typid, + IOFuncSelector which_func, + ArrayMetaState *metadata); + extern int boot_yyparse(yyscan_t yyscanner); extern int boot_yylex_init(yyscan_t *yyscannerp); extern int boot_yylex(union YYSTYPE *yylval_param, yyscan_t yyscanner); diff --git a/src/include/catalog/pg_type.h b/src/include/catalog/pg_type.h index e9259697321..652e9467333 100644 --- a/src/include/catalog/pg_type.h +++ b/src/include/catalog/pg_type.h @@ -345,6 +345,10 @@ MAKE_SYSCACHE(TYPENAMENSP, pg_type_typname_nsp_index, 64); #endif /* EXPOSE_TO_CLIENT_CODE */ +/* Does datatype allow packing into the 1-byte-header varlena format? */ +#define TYPE_IS_PACKABLE(typlen, typstorage) \ + ((typlen) == -1 && (typstorage) != TYPSTORAGE_PLAIN) + extern ObjectAddress TypeShellMake(const char *typeName, Oid typeNamespace, Oid ownerId); diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h index 759f9a87d38..84e2def31cb 100644 --- a/src/include/commands/vacuum.h +++ b/src/include/commands/vacuum.h @@ -163,6 +163,7 @@ typedef struct VacAttrStats int16 statyplen[STATISTIC_NUM_SLOTS]; bool statypbyval[STATISTIC_NUM_SLOTS]; char statypalign[STATISTIC_NUM_SLOTS]; + char statypstorage[STATISTIC_NUM_SLOTS]; /* * These fields are private to the main ANALYZE code and should not be diff --git a/src/include/executor/execExpr.h b/src/include/executor/execExpr.h index 56fb0d0adbe..f17cedc26b0 100644 --- a/src/include/executor/execExpr.h +++ b/src/include/executor/execExpr.h @@ -458,6 +458,7 @@ typedef struct ExprEvalStep int16 elemlength; /* typlen of the array element type */ bool elembyval; /* is the element type pass-by-value? */ char elemalign; /* typalign of the element type */ + char elemstorage; /* typstorage of the element type */ bool multidims; /* is array expression multi-D? */ } arrayexpr; diff --git a/src/include/utils/array.h b/src/include/utils/array.h index 157cc0e4c6e..711b37f6714 100644 --- a/src/include/utils/array.h +++ b/src/include/utils/array.h @@ -130,6 +130,7 @@ typedef struct ExpandedArrayHeader int16 typlen; /* needed info about element datatype */ bool typbyval; char typalign; + char typstorage; /* * If we have a Datum-array representation of the array, it's kept here; @@ -195,6 +196,7 @@ typedef struct ArrayBuildState int16 typlen; /* needed info about datatype */ bool typbyval; char typalign; + char typstorage; bool private_cxt; /* use private memory context */ } ArrayBuildState; @@ -240,6 +242,7 @@ typedef struct ArrayMetaState bool typbyval; char typalign; char typdelim; + char typstorage; Oid typioparam; Oid typiofunc; FmgrInfo proc; @@ -358,30 +361,34 @@ extern void CopyArrayEls(ArrayType *array, int typlen, bool typbyval, char typalign, + char typstor, bool freedata); extern Datum array_get_element(Datum arraydatum, int nSubscripts, int *indx, - int arraytyplen, int elmlen, bool elmbyval, char elmalign, - bool *isNull); + int arraytyplen, int elmlen, bool elmbyval, + char elmalign, char elmstor, bool *isNull); extern Datum array_set_element(Datum arraydatum, int nSubscripts, int *indx, Datum dataValue, bool isNull, - int arraytyplen, int elmlen, bool elmbyval, char elmalign); + int arraytyplen, int elmlen, bool elmbyval, + char elmalign, char elmstor); extern Datum array_get_slice(Datum arraydatum, int nSubscripts, int *upperIndx, int *lowerIndx, bool *upperProvided, bool *lowerProvided, - int arraytyplen, int elmlen, bool elmbyval, char elmalign); + int arraytyplen, int elmlen, bool elmbyval, + char elmalign, char typstor); extern Datum array_set_slice(Datum arraydatum, int nSubscripts, int *upperIndx, int *lowerIndx, bool *upperProvided, bool *lowerProvided, Datum srcArrayDatum, bool isNull, - int arraytyplen, int elmlen, bool elmbyval, char elmalign); + int arraytyplen, int elmlen, bool elmbyval, + char elmalign, char elmstor); extern Datum array_ref(ArrayType *array, int nSubscripts, int *indx, int arraytyplen, int elmlen, bool elmbyval, char elmalign, - bool *isNull); + char elmstor, bool *isNull); extern ArrayType *array_set(ArrayType *array, int nSubscripts, int *indx, - Datum dataValue, bool isNull, - int arraytyplen, int elmlen, bool elmbyval, char elmalign); + Datum dataValue, bool isNull, int arraytyplen, + int elmlen, bool elmbyval, char elmalign, char elmstor); extern Datum array_map(Datum arrayd, struct ExprState *exprstate, struct ExprContext *econtext, @@ -393,21 +400,23 @@ extern void array_bitmap_copy(bits8 *destbitmap, int destoffset, extern ArrayType *construct_array(Datum *elems, int nelems, Oid elmtype, - int elmlen, bool elmbyval, char elmalign); + int elmlen, bool elmbyval, + char elmalign, char elmstor); extern ArrayType *construct_array_builtin(Datum *elems, int nelems, Oid elmtype); extern ArrayType *construct_md_array(Datum *elems, bool *nulls, int ndims, int *dims, int *lbs, - Oid elmtype, int elmlen, bool elmbyval, char elmalign); + Oid elmtype, int elmlen, bool elmbyval, + char elmalign, char elmstor); extern ArrayType *construct_empty_array(Oid elmtype); extern ExpandedArrayHeader *construct_empty_expanded_array(Oid element_type, MemoryContext parentcontext, ArrayMetaState *metacache); extern void deconstruct_array(ArrayType *array, Oid elmtype, - int elmlen, bool elmbyval, char elmalign, + int elmlen, bool elmbyval, char elmalign, char elmstor, Datum **elemsp, bool **nullsp, int *nelemsp); extern void deconstruct_array_builtin(ArrayType *array, Oid elmtype, diff --git a/src/include/utils/lsyscache.h b/src/include/utils/lsyscache.h index 20446f6f836..5ee3ab2cdb8 100644 --- a/src/include/utils/lsyscache.h +++ b/src/include/utils/lsyscache.h @@ -16,6 +16,7 @@ #include "access/attnum.h" #include "access/htup.h" #include "nodes/pg_list.h" +#include "utils/array.h" /* avoid including subscripting.h here */ struct SubscriptRoutines; @@ -150,7 +151,12 @@ extern bool get_typbyval(Oid typid); extern void get_typlenbyval(Oid typid, int16 *typlen, bool *typbyval); extern void get_typlenbyvalalign(Oid typid, int16 *typlen, bool *typbyval, char *typalign); +extern void get_type_stores(Oid typid, int16 *typlen, + bool *typbyval, char *typalign, char *typstor); extern Oid getTypeIOParam(HeapTuple typeTuple); +extern void array_type_metadata(Oid typid, + IOFuncSelector which_func, + ArrayMetaState *metadata); extern void get_type_io_data(Oid typid, IOFuncSelector which_func, int16 *typlen, diff --git a/src/include/utils/palloc.h b/src/include/utils/palloc.h index 773a5d2c347..339745f5081 100644 --- a/src/include/utils/palloc.h +++ b/src/include/utils/palloc.h @@ -85,6 +85,12 @@ extern pg_nodiscard void *repalloc_extended(void *pointer, extern pg_nodiscard void *repalloc0(void *pointer, Size oldsize, Size size); extern void pfree(void *pointer); +#define PFREE_IF_NEW(newptr, oldptr) \ + do { \ + if ((Pointer)(newptr) != (Pointer)(oldptr)) \ + pfree(newptr); \ + } while (0) + /* * Variants with easier notation and more type safety */ diff --git a/src/pl/plperl/plperl.c b/src/pl/plperl/plperl.c index 1b1677e333b..85b5b1be9f4 100644 --- a/src/pl/plperl/plperl.c +++ b/src/pl/plperl/plperl.c @@ -1484,6 +1484,7 @@ plperl_ref_from_pg_array(Datum arg, Oid typid) int16 typlen; bool typbyval; char typalign, + typstor, typdelim; Oid typioparam; Oid typoutputfunc; @@ -1506,6 +1507,8 @@ plperl_ref_from_pg_array(Datum arg, Oid typid) &typlen, &typbyval, &typalign, &typdelim, &typioparam, &typoutputfunc); + typstor = get_typstorage(elementtype); + /* Check for a transform function */ transform_funcid = get_transform_fromsql(elementtype, current_call_data->prodesc->lang_oid, @@ -1531,8 +1534,8 @@ plperl_ref_from_pg_array(Datum arg, Oid typid) else { deconstruct_array(ar, elementtype, typlen, typbyval, - typalign, &info->elements, &info->nulls, - &nitems); + typalign, typstor, + &info->elements, &info->nulls, &nitems); /* Get total number of elements in each dimension */ info->nelems = palloc(sizeof(int) * info->ndims); diff --git a/src/pl/plpgsql/src/pl_exec.c b/src/pl/plpgsql/src/pl_exec.c index e31206e7f4c..067b82427d6 100644 --- a/src/pl/plpgsql/src/pl_exec.c +++ b/src/pl/plpgsql/src/pl_exec.c @@ -1491,7 +1491,9 @@ plpgsql_fulfill_promise(PLpgSQL_execstate *estate, PointerGetDatum(construct_md_array(elems, NULL, 1, dims, lbs, TEXTOID, - -1, false, TYPALIGN_INT)), + -1, false, + TYPALIGN_INT, + TYPSTORAGE_EXTENDED)), false, true); } else diff --git a/src/test/modules/test_regex/test_regex.c b/src/test/modules/test_regex/test_regex.c index a780c678fbc..b3e0564f6da 100644 --- a/src/test/modules/test_regex/test_regex.c +++ b/src/test/modules/test_regex/test_regex.c @@ -678,7 +678,8 @@ build_test_info_result(regex_t *cpattern, test_re_flags *flags) lbs[0] = 1; /* XXX: this hardcodes assumptions about the text type */ return construct_md_array(elems, NULL, 1, dims, lbs, - TEXTOID, -1, false, TYPALIGN_INT); + TEXTOID, -1, false, + TYPALIGN_INT, TYPSTORAGE_EXTENDED); } /* @@ -758,5 +759,6 @@ build_test_match_result(test_regex_ctx *matchctx) lbs[0] = 1; /* XXX: this hardcodes assumptions about the text type */ return construct_md_array(elems, nulls, 1, dims, lbs, - TEXTOID, -1, false, TYPALIGN_INT); + TEXTOID, -1, false, + TYPALIGN_INT, TYPSTORAGE_EXTENDED); }