diff options
Diffstat (limited to 'src/pl/plperl/plperl.c')
-rw-r--r-- | src/pl/plperl/plperl.c | 62 |
1 files changed, 39 insertions, 23 deletions
diff --git a/src/pl/plperl/plperl.c b/src/pl/plperl/plperl.c index d7d9c1bee3..02b89ac5f7 100644 --- a/src/pl/plperl/plperl.c +++ b/src/pl/plperl/plperl.c @@ -272,9 +272,9 @@ static Datum plperl_sv_to_datum(SV *sv, Oid typid, int32 typmod, bool *isnull); static void _sv_to_datum_finfo(Oid typid, FmgrInfo *finfo, Oid *typioparam); static Datum plperl_array_to_datum(SV *src, Oid typid, int32 typmod); -static void array_to_datum_internal(AV *av, ArrayBuildState *astate, +static void array_to_datum_internal(AV *av, ArrayBuildState **astatep, int *ndims, int *dims, int cur_depth, - Oid arraytypid, Oid elemtypid, int32 typmod, + Oid elemtypid, int32 typmod, FmgrInfo *finfo, Oid typioparam); static Datum plperl_hash_to_datum(SV *src, TupleDesc td); @@ -1160,11 +1160,16 @@ get_perl_array_ref(SV *sv) /* * helper function for plperl_array_to_datum, recurses for multi-D arrays + * + * The ArrayBuildState is created only when we first find a scalar element; + * if we didn't do it like that, we'd need some other convention for knowing + * whether we'd already found any scalars (and thus the number of dimensions + * is frozen). */ static void -array_to_datum_internal(AV *av, ArrayBuildState *astate, +array_to_datum_internal(AV *av, ArrayBuildState **astatep, int *ndims, int *dims, int cur_depth, - Oid arraytypid, Oid elemtypid, int32 typmod, + Oid elemtypid, int32 typmod, FmgrInfo *finfo, Oid typioparam) { dTHX; @@ -1184,28 +1189,34 @@ array_to_datum_internal(AV *av, ArrayBuildState *astate, { AV *nav = (AV *) SvRV(sav); - /* dimensionality checks */ - if (cur_depth + 1 > MAXDIM) - ereport(ERROR, - (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), - errmsg("number of array dimensions (%d) exceeds the maximum allowed (%d)", - cur_depth + 1, MAXDIM))); - /* set size when at first element in this level, else compare */ if (i == 0 && *ndims == cur_depth) { + /* array after some scalars at same level? */ + if (*astatep != NULL) + ereport(ERROR, + (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), + errmsg("multidimensional arrays must have array expressions with matching dimensions"))); + /* too many dimensions? */ + if (cur_depth + 1 > MAXDIM) + ereport(ERROR, + (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), + errmsg("number of array dimensions (%d) exceeds the maximum allowed (%d)", + cur_depth + 1, MAXDIM))); + /* OK, add a dimension */ dims[*ndims] = av_len(nav) + 1; (*ndims)++; } - else if (av_len(nav) + 1 != dims[cur_depth]) + else if (cur_depth >= *ndims || + av_len(nav) + 1 != dims[cur_depth]) ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("multidimensional arrays must have array expressions with matching dimensions"))); /* recurse to fetch elements of this sub-array */ - array_to_datum_internal(nav, astate, + array_to_datum_internal(nav, astatep, ndims, dims, cur_depth + 1, - arraytypid, elemtypid, typmod, + elemtypid, typmod, finfo, typioparam); } else @@ -1227,7 +1238,13 @@ array_to_datum_internal(AV *av, ArrayBuildState *astate, typioparam, &isnull); - (void) accumArrayResult(astate, dat, isnull, + /* Create ArrayBuildState if we didn't already */ + if (*astatep == NULL) + *astatep = initArrayResult(elemtypid, + CurrentMemoryContext, true); + + /* ... and save the element value in it */ + (void) accumArrayResult(*astatep, dat, isnull, elemtypid, CurrentMemoryContext); } } @@ -1240,7 +1257,8 @@ static Datum plperl_array_to_datum(SV *src, Oid typid, int32 typmod) { dTHX; - ArrayBuildState *astate; + AV *nav = (AV *) SvRV(src); + ArrayBuildState *astate = NULL; Oid elemtypid; FmgrInfo finfo; Oid typioparam; @@ -1256,21 +1274,19 @@ plperl_array_to_datum(SV *src, Oid typid, int32 typmod) errmsg("cannot convert Perl array to non-array type %s", format_type_be(typid)))); - astate = initArrayResult(elemtypid, CurrentMemoryContext, true); - _sv_to_datum_finfo(elemtypid, &finfo, &typioparam); memset(dims, 0, sizeof(dims)); - dims[0] = av_len((AV *) SvRV(src)) + 1; + dims[0] = av_len(nav) + 1; - array_to_datum_internal((AV *) SvRV(src), astate, + array_to_datum_internal(nav, &astate, &ndims, dims, 1, - typid, elemtypid, typmod, + elemtypid, typmod, &finfo, typioparam); /* ensure we get zero-D array for no inputs, as per PG convention */ - if (dims[0] <= 0) - ndims = 0; + if (astate == NULL) + return PointerGetDatum(construct_empty_array(elemtypid)); for (i = 0; i < ndims; i++) lbs[i] = 1; |