diff options
Diffstat (limited to 'src/pl/plperl/plperl.c')
-rw-r--r-- | src/pl/plperl/plperl.c | 690 |
1 files changed, 502 insertions, 188 deletions
diff --git a/src/pl/plperl/plperl.c b/src/pl/plperl/plperl.c index 5bc8db76472..5f40f1e501a 100644 --- a/src/pl/plperl/plperl.c +++ b/src/pl/plperl/plperl.c @@ -109,6 +109,7 @@ typedef struct plperl_proc_desc int nargs; FmgrInfo arg_out_func[FUNC_MAX_ARGS]; bool arg_is_rowtype[FUNC_MAX_ARGS]; + Oid arg_arraytype[FUNC_MAX_ARGS]; /* InvalidOid if not an array */ SV *reference; } plperl_proc_desc; @@ -179,6 +180,19 @@ typedef struct plperl_query_entry } plperl_query_entry; /********************************************************************** + * Information for PostgreSQL - Perl array conversion. + **********************************************************************/ +typedef struct plperl_array_info +{ + int ndims; + bool elem_is_rowtype; /* 't' if element type is a rowtype */ + Datum *elements; + bool *nulls; + int *nelems; + FmgrInfo proc; +} plperl_array_info; + +/********************************************************************** * Global data **********************************************************************/ @@ -221,6 +235,19 @@ static Datum plperl_trigger_handler(PG_FUNCTION_ARGS); static plperl_proc_desc *compile_plperl_function(Oid fn_oid, bool is_trigger); static SV *plperl_hash_from_tuple(HeapTuple tuple, TupleDesc tupdesc); +static SV *plperl_hash_from_datum(Datum attr); +static SV *plperl_ref_from_pg_array(Datum arg, Oid typid); +static SV *split_array(plperl_array_info *info, int first, int last, int nest); +static SV *make_array_ref(plperl_array_info *info, int first, int last); +static SV *get_perl_array_ref(SV *sv); +static Datum plperl_sv_to_datum(SV *sv, FmgrInfo *func, Oid typid, + Oid typioparam, int32 typmod, bool *isnull); +static void _sv_to_datum_finfo(FmgrInfo *fcinfo, Oid typid, Oid *typioparam); +static Datum plperl_array_to_datum(SV *src, Oid typid); +static ArrayBuildState *_array_to_datum(AV *av, int *ndims, int *dims, + int cur_depth, ArrayBuildState *astate, Oid typid, Oid atypid); +static Datum plperl_hash_to_datum(SV *src, TupleDesc td); + static void plperl_init_shared_libs(pTHX); static void plperl_trusted_init(void); static void plperl_untrusted_init(void); @@ -960,12 +987,14 @@ static HeapTuple plperl_build_tuple_result(HV *perlhash, AttInMetadata *attinmeta) { TupleDesc td = attinmeta->tupdesc; - char **values; + Datum *values; + bool *nulls; HE *he; HeapTuple tup; - int i; - values = (char **) palloc0(td->natts * sizeof(char *)); + values = palloc0(sizeof(Datum) * td->natts); + nulls = palloc(sizeof(bool) * td->natts); + memset(nulls, true, sizeof(bool) * td->natts); hv_iterinit(perlhash); while ((he = hv_iternext(perlhash))) @@ -973,65 +1002,378 @@ plperl_build_tuple_result(HV *perlhash, AttInMetadata *attinmeta) SV *val = HeVAL(he); char *key = hek2cstr(he); int attn = SPI_fnumber(td, key); + bool isnull; if (attn <= 0 || td->attrs[attn - 1]->attisdropped) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_COLUMN), errmsg("Perl hash contains nonexistent column \"%s\"", key))); - if (SvOK(val)) - { - values[attn - 1] = sv2cstr(val); - } + + values[attn - 1] = plperl_sv_to_datum(val, + NULL, + td->attrs[attn - 1]->atttypid, + InvalidOid, + td->attrs[attn - 1]->atttypmod, + &isnull); + nulls[attn - 1] = isnull; pfree(key); } hv_iterinit(perlhash); - tup = BuildTupleFromCStrings(attinmeta, values); + tup = heap_form_tuple(td, values, nulls); + pfree(values); + pfree(nulls); + return tup; +} - for (i = 0; i < td->natts; i++) +/* convert a hash reference to a datum */ +static Datum +plperl_hash_to_datum(SV *src, TupleDesc td) +{ + AttInMetadata *attinmeta = TupleDescGetAttInMetadata(td); + HeapTuple tup = plperl_build_tuple_result((HV *) SvRV(src), attinmeta); + + return HeapTupleGetDatum(tup); +} + +/* + * if we are an array ref return the reference. this is special in that if we + * are a PostgreSQL::InServer::ARRAY object we will return the 'magic' array. + */ +static SV * +get_perl_array_ref(SV *sv) +{ + if (SvOK(sv) && SvROK(sv)) { - if (values[i]) - pfree(values[i]); + if (SvTYPE(SvRV(sv)) == SVt_PVAV) + return sv; + else if (sv_isa(sv, "PostgreSQL::InServer::ARRAY")) + { + HV *hv = (HV *) SvRV(sv); + SV **sav = hv_fetch_string(hv, "array"); + + if (*sav && SvOK(*sav) && SvROK(*sav) && + SvTYPE(SvRV(*sav)) == SVt_PVAV) + return *sav; + + elog(ERROR, "could not get array reference from PostgreSQL::InServer::ARRAY object"); + } } - pfree(values); + return NULL; +} - return tup; +/* + * helper function for plperl_array_to_datum, does the main recursing + */ +static ArrayBuildState * +_array_to_datum(AV *av, int *ndims, int *dims, int cur_depth, + ArrayBuildState *astate, Oid typid, Oid atypid) +{ + int i = 0; + int len = av_len(av) + 1; + + if (len == 0) + astate = accumArrayResult(astate, (Datum) 0, true, atypid, NULL); + + for (i = 0; i < len; i++) + { + SV **svp = av_fetch(av, i, FALSE); + SV *sav = svp ? get_perl_array_ref(*svp) : NULL; + + if (sav) + { + AV *nav = (AV *) SvRV(sav); + + 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))); + + /* size based off the first element */ + if (i == 0 && *ndims == cur_depth) + { + dims[*ndims] = av_len(nav) + 1; + (*ndims)++; + } + else + { + if (av_len(nav) + 1 != dims[cur_depth]) + ereport(ERROR, + (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), + errmsg("multidimensional arrays must have array expressions with matching dimensions"))); + } + + astate = _array_to_datum(nav, ndims, dims, cur_depth + 1, astate, + typid, atypid); + } + else + { + bool isnull; + Datum dat = plperl_sv_to_datum(svp ? *svp : NULL, NULL, + atypid, 0, -1, &isnull); + + astate = accumArrayResult(astate, dat, isnull, atypid, NULL); + } + } + + return astate; +} + +/* + * convert perl array ref to a datum + */ +static Datum +plperl_array_to_datum(SV *src, Oid typid) +{ + ArrayBuildState *astate = NULL; + Oid atypid; + int dims[MAXDIM]; + int lbs[MAXDIM]; + int ndims = 1; + int i; + + atypid = get_element_type(typid); + if (!atypid) + atypid = typid; + + memset(dims, 0, sizeof(dims)); + dims[0] = av_len((AV *) SvRV(src)) + 1; + + astate = _array_to_datum((AV *) SvRV(src), &ndims, dims, 1, astate, typid, + atypid); + + for (i = 0; i < ndims; i++) + lbs[i] = 1; + + return makeMdArrayResult(astate, ndims, dims, lbs, CurrentMemoryContext, true); +} + +static void +_sv_to_datum_finfo(FmgrInfo *fcinfo, Oid typid, Oid *typioparam) +{ + Oid typinput; + + /* XXX would be better to cache these lookups */ + getTypeInputInfo(typid, + &typinput, typioparam); + fmgr_info(typinput, fcinfo); +} + +/* + * convert a sv to datum + * fcinfo and typioparam are optional and will be looked-up if needed + */ +static Datum +plperl_sv_to_datum(SV *sv, FmgrInfo *finfo, Oid typid, Oid typioparam, + int32 typmod, bool *isnull) +{ + FmgrInfo tmp; + + /* we might recurse */ + check_stack_depth(); + + if (isnull) + *isnull = false; + + if (!sv || !SvOK(sv)) + { + if (!finfo) + { + _sv_to_datum_finfo(&tmp, typid, &typioparam); + finfo = &tmp; + } + if (isnull) + *isnull = true; + return InputFunctionCall(finfo, NULL, typioparam, typmod); + } + else if (SvROK(sv)) + { + SV *sav = get_perl_array_ref(sv); + + if (sav) + { + return plperl_array_to_datum(sav, typid); + } + else if (SvTYPE(SvRV(sv)) == SVt_PVHV) + { + TupleDesc td = lookup_rowtype_tupdesc(typid, typmod); + Datum ret = plperl_hash_to_datum(sv, td); + + ReleaseTupleDesc(td); + return ret; + } + + ereport(ERROR, + (errcode(ERRCODE_DATATYPE_MISMATCH), + errmsg("PL/Perl function must return reference to hash or array"))); + return (Datum) 0; /* shut up compiler */ + } + else + { + Datum ret; + char *str = sv2cstr(sv); + + if (!finfo) + { + _sv_to_datum_finfo(&tmp, typid, &typioparam); + finfo = &tmp; + } + + ret = InputFunctionCall(finfo, str, typioparam, typmod); + pfree(str); + + return ret; + } +} + +/* Convert the perl SV to a string returned by the type output function */ +char * +plperl_sv_to_literal(SV *sv, char *fqtypename) +{ + Datum str = CStringGetDatum(fqtypename); + Oid typid = DirectFunctionCall1(regtypein, str); + Oid typoutput; + Datum datum; + bool typisvarlena, + isnull; + + if (!OidIsValid(typid)) + elog(ERROR, "lookup failed for type %s", fqtypename); + + datum = plperl_sv_to_datum(sv, NULL, typid, 0, -1, &isnull); + + if (isnull) + return NULL; + + getTypeOutputInfo(typid, + &typoutput, &typisvarlena); + + return OidOutputFunctionCall(typoutput, datum); } /* - * convert perl array to postgres string representation + * Convert PostgreSQL array datum to a perl array reference. + * + * typid is arg's OID, which must be an array type. */ static SV * -plperl_convert_to_pg_array(SV *src) +plperl_ref_from_pg_array(Datum arg, Oid typid) { - SV *rv; - int count; + ArrayType *ar = DatumGetArrayTypeP(arg); + Oid elementtype = ARR_ELEMTYPE(ar); + int16 typlen; + bool typbyval; + char typalign, + typdelim; + Oid typioparam; + Oid typoutputfunc; + int i, + nitems, + *dims; + plperl_array_info *info; + SV *av; + HV *hv; - dSP; + info = palloc(sizeof(plperl_array_info)); - PUSHMARK(SP); - XPUSHs(src); - PUTBACK; + /* get element type information, including output conversion function */ + get_type_io_data(elementtype, IOFunc_output, + &typlen, &typbyval, &typalign, + &typdelim, &typioparam, &typoutputfunc); - count = perl_call_pv("::encode_array_literal", G_SCALAR); + perm_fmgr_info(typoutputfunc, &info->proc); - SPAGAIN; + info->elem_is_rowtype = type_is_rowtype(elementtype); - if (count != 1) - elog(ERROR, "unexpected encode_array_literal failure"); + /* Get the number and bounds of array dimensions */ + info->ndims = ARR_NDIM(ar); + dims = ARR_DIMS(ar); - rv = POPs; + deconstruct_array(ar, elementtype, typlen, typbyval, + typalign, &info->elements, &info->nulls, + &nitems); - PUTBACK; + /* Get total number of elements in each dimension */ + info->nelems = palloc(sizeof(int) * info->ndims); + info->nelems[0] = nitems; + for (i = 1; i < info->ndims; i++) + info->nelems[i] = info->nelems[i - 1] / dims[i - 1]; - return rv; + av = split_array(info, 0, nitems, 0); + + hv = newHV(); + (void) hv_store(hv, "array", 5, av, 0); + (void) hv_store(hv, "typeoid", 7, newSViv(typid), 0); + + return sv_bless(newRV_noinc((SV *) hv), + gv_stashpv("PostgreSQL::InServer::ARRAY", 0)); } +/* + * Recursively form array references from splices of the initial array + */ +static SV * +split_array(plperl_array_info *info, int first, int last, int nest) +{ + int i; + AV *result; -/* Set up the arguments for a trigger call. */ + /* since this function recurses, it could be driven to stack overflow */ + check_stack_depth(); + + /* + * Base case, return a reference to a single-dimensional array + */ + if (nest >= info->ndims - 1) + return make_array_ref(info, first, last); + + result = newAV(); + for (i = first; i < last; i += info->nelems[nest + 1]) + { + /* Recursively form references to arrays of lower dimensions */ + SV *ref = split_array(info, i, i + info->nelems[nest + 1], nest + 1); + + av_push(result, ref); + } + return newRV_noinc((SV *) result); +} + +/* + * Create a Perl reference from a one-dimensional C array, converting + * composite type elements to hash references. + */ +static SV * +make_array_ref(plperl_array_info *info, int first, int last) +{ + int i; + AV *result = newAV(); + + for (i = first; i < last; i++) + { + if (info->nulls[i]) + av_push(result, &PL_sv_undef); + else + { + Datum itemvalue = info->elements[i]; + /* Handle composite type elements */ + if (info->elem_is_rowtype) + av_push(result, plperl_hash_from_datum(itemvalue)); + else + { + char *val = OutputFunctionCall(&info->proc, itemvalue); + + av_push(result, cstr2sv(val)); + } + } + } + return newRV_noinc((SV *) result); +} + +/* Set up the arguments for a trigger call. */ static SV * plperl_trigger_build_args(FunctionCallInfo fcinfo) { @@ -1174,12 +1516,9 @@ plperl_modify_tuple(HV *hvTD, TriggerData *tdata, HeapTuple otup) hv_iterinit(hvNew); while ((he = hv_iternext(hvNew))) { - Oid typinput; - Oid typioparam; - int32 atttypmod; - FmgrInfo finfo; - SV *val = HeVAL(he); + bool isnull; char *key = hek2cstr(he); + SV *val = HeVAL(he); int attn = SPI_fnumber(tupdesc, key); if (attn <= 0 || tupdesc->attrs[attn - 1]->attisdropped) @@ -1187,30 +1526,15 @@ plperl_modify_tuple(HV *hvTD, TriggerData *tdata, HeapTuple otup) (errcode(ERRCODE_UNDEFINED_COLUMN), errmsg("Perl hash contains nonexistent column \"%s\"", key))); - /* XXX would be better to cache these lookups */ - getTypeInputInfo(tupdesc->attrs[attn - 1]->atttypid, - &typinput, &typioparam); - fmgr_info(typinput, &finfo); - atttypmod = tupdesc->attrs[attn - 1]->atttypmod; - if (SvOK(val)) - { - char *str = sv2cstr(val); - - modvalues[slotsused] = InputFunctionCall(&finfo, - str, - typioparam, - atttypmod); - modnulls[slotsused] = ' '; - pfree(str); - } - else - { - modvalues[slotsused] = InputFunctionCall(&finfo, - NULL, - typioparam, - atttypmod); - modnulls[slotsused] = 'n'; - } + + modvalues[slotsused] = plperl_sv_to_datum(val, + NULL, + tupdesc->attrs[attn - 1]->atttypid, + InvalidOid, + tupdesc->attrs[attn - 1]->atttypmod, + &isnull); + + modnulls[slotsused] = isnull ? 'n' : ' '; modattrs[slotsused] = attn; slotsused++; @@ -1530,7 +1854,6 @@ plperl_call_perl_func(plperl_proc_desc *desc, FunctionCallInfo fcinfo) SV *retval; int i; int count; - SV *sv; ENTER; SAVETMPS; @@ -1544,35 +1867,27 @@ plperl_call_perl_func(plperl_proc_desc *desc, FunctionCallInfo fcinfo) PUSHs(&PL_sv_undef); else if (desc->arg_is_rowtype[i]) { - HeapTupleHeader td; - Oid tupType; - int32 tupTypmod; - TupleDesc tupdesc; - HeapTupleData tmptup; - SV *hashref; - - td = DatumGetHeapTupleHeader(fcinfo->arg[i]); - /* Extract rowtype info and find a tupdesc */ - tupType = HeapTupleHeaderGetTypeId(td); - tupTypmod = HeapTupleHeaderGetTypMod(td); - tupdesc = lookup_rowtype_tupdesc(tupType, tupTypmod); - /* Build a temporary HeapTuple control structure */ - tmptup.t_len = HeapTupleHeaderGetDatumLength(td); - tmptup.t_data = td; - - hashref = plperl_hash_from_tuple(&tmptup, tupdesc); - PUSHs(sv_2mortal(hashref)); - ReleaseTupleDesc(tupdesc); + SV *sv = plperl_hash_from_datum(fcinfo->arg[i]); + + PUSHs(sv_2mortal(sv)); } else { - char *tmp; + SV *sv; + + if (OidIsValid(desc->arg_arraytype[i])) + sv = plperl_ref_from_pg_array(fcinfo->arg[i], desc->arg_arraytype[i]); + else + { + char *tmp; + + tmp = OutputFunctionCall(&(desc->arg_out_func[i]), + fcinfo->arg[i]); + sv = cstr2sv(tmp); + pfree(tmp); + } - tmp = OutputFunctionCall(&(desc->arg_out_func[i]), - fcinfo->arg[i]); - sv = cstr2sv(tmp); PUSHs(sv_2mortal(sv)); - pfree(tmp); } } PUTBACK; @@ -1677,8 +1992,8 @@ plperl_func_handler(PG_FUNCTION_ARGS) SV *perlret; Datum retval; ReturnSetInfo *rsi; - SV *array_ret = NULL; ErrorContextCallback pl_error_context; + bool has_retval = false; /* * Create the call_data beforing connecting to SPI, so that it is not @@ -1728,19 +2043,20 @@ plperl_func_handler(PG_FUNCTION_ARGS) if (prodesc->fn_retisset) { + SV *sav; + /* * If the Perl function returned an arrayref, we pretend that it * called return_next() for each element of the array, to handle old * SRFs that didn't know about return_next(). Any other sort of return * value is an error, except undef which means return an empty set. */ - if (SvOK(perlret) && - SvROK(perlret) && - SvTYPE(SvRV(perlret)) == SVt_PVAV) + sav = get_perl_array_ref(perlret); + if (sav) { int i = 0; SV **svp = 0; - AV *rav = (AV *) SvRV(perlret); + AV *rav = (AV *) SvRV(sav); while ((svp = av_fetch(rav, i, FALSE)) != NULL) { @@ -1763,22 +2079,18 @@ plperl_func_handler(PG_FUNCTION_ARGS) rsi->setDesc = current_call_data->ret_tdesc; } retval = (Datum) 0; + has_retval = true; } else if (!SvOK(perlret)) { /* Return NULL if Perl code returned undef */ if (rsi && IsA(rsi, ReturnSetInfo)) rsi->isDone = ExprEndResult; - retval = InputFunctionCall(&prodesc->result_in_func, NULL, - prodesc->result_typioparam, -1); - fcinfo->isnull = true; } else if (prodesc->fn_retistuple) { /* Return a perl hash converted to a Datum */ TupleDesc td; - AttInMetadata *attinmeta; - HeapTuple tup; if (!SvOK(perlret) || !SvROK(perlret) || SvTYPE(SvRV(perlret)) != SVt_PVHV) @@ -1798,35 +2110,26 @@ plperl_func_handler(PG_FUNCTION_ARGS) "that cannot accept type record"))); } - attinmeta = TupleDescGetAttInMetadata(td); - tup = plperl_build_tuple_result((HV *) SvRV(perlret), attinmeta); - retval = HeapTupleGetDatum(tup); + retval = plperl_hash_to_datum(perlret, td); + has_retval = true; } - else - { - /* Return a perl string converted to a Datum */ - char *str; - if (prodesc->fn_retisarray && SvROK(perlret) && - SvTYPE(SvRV(perlret)) == SVt_PVAV) - { - array_ret = plperl_convert_to_pg_array(perlret); - SvREFCNT_dec(perlret); - perlret = array_ret; - } + if (!has_retval) + { + bool isnull; - str = sv2cstr(perlret); - retval = InputFunctionCall(&prodesc->result_in_func, - str, - prodesc->result_typioparam, -1); - pfree(str); + retval = plperl_sv_to_datum(perlret, + &prodesc->result_in_func, + prodesc->result_oid, + prodesc->result_typioparam, -1, &isnull); + fcinfo->isnull = isnull; + has_retval = true; } /* Restore the previous error callback */ error_context_stack = pl_error_context.previous; - if (array_ret == NULL) - SvREFCNT_dec(perlret); + SvREFCNT_dec(perlret); return retval; } @@ -2181,6 +2484,12 @@ compile_plperl_function(Oid fn_oid, bool is_trigger) &(prodesc->arg_out_func[i])); } + /* Identify array attributes */ + if (typeStruct->typelem != 0 && typeStruct->typlen == -1) + prodesc->arg_arraytype[i] = procStruct->proargtypes.values[i]; + else + prodesc->arg_arraytype[i] = InvalidOid; + ReleaseSysCache(typeTup); } } @@ -2234,26 +2543,54 @@ compile_plperl_function(Oid fn_oid, bool is_trigger) return prodesc; } +/* Build a hash from a given composite/row datum */ +static SV * +plperl_hash_from_datum(Datum attr) +{ + HeapTupleHeader td; + Oid tupType; + int32 tupTypmod; + TupleDesc tupdesc; + HeapTupleData tmptup; + SV *sv; -/* Build a hash from all attributes of a given tuple. */ + td = DatumGetHeapTupleHeader(attr); + + /* Extract rowtype info and find a tupdesc */ + tupType = HeapTupleHeaderGetTypeId(td); + tupTypmod = HeapTupleHeaderGetTypMod(td); + tupdesc = lookup_rowtype_tupdesc(tupType, tupTypmod); + + /* Build a temporary HeapTuple control structure */ + tmptup.t_len = HeapTupleHeaderGetDatumLength(td); + tmptup.t_data = td; + sv = plperl_hash_from_tuple(&tmptup, tupdesc); + ReleaseTupleDesc(tupdesc); + + return sv; +} + +/* Build a hash from all attributes of a given tuple. */ static SV * plperl_hash_from_tuple(HeapTuple tuple, TupleDesc tupdesc) { HV *hv; int i; + /* since this function recurses, it could be driven to stack overflow */ + check_stack_depth(); + hv = newHV(); hv_ksplit(hv, tupdesc->natts); /* pre-grow the hash */ for (i = 0; i < tupdesc->natts; i++) { Datum attr; - bool isnull; + bool isnull, + typisvarlena; char *attname; - char *outputstr; Oid typoutput; - bool typisvarlena; if (tupdesc->attrs[i]->attisdropped) continue; @@ -2264,21 +2601,38 @@ plperl_hash_from_tuple(HeapTuple tuple, TupleDesc tupdesc) if (isnull) { /* Store (attname => undef) and move on. */ - hv_store_string(hv, attname, newSV(0)); + hv_store_string(hv, attname, &PL_sv_undef); continue; } - /* XXX should have a way to cache these lookups */ - getTypeOutputInfo(tupdesc->attrs[i]->atttypid, - &typoutput, &typisvarlena); + if (type_is_rowtype(tupdesc->attrs[i]->atttypid)) + { + SV *sv = plperl_hash_from_datum(attr); + + hv_store_string(hv, attname, sv); + } + else + { + SV *sv; + + if (OidIsValid(get_base_element_type(tupdesc->attrs[i]->atttypid))) + sv = plperl_ref_from_pg_array(attr, tupdesc->attrs[i]->atttypid); + else + { + char *outputstr; - outputstr = OidOutputFunctionCall(typoutput, attr); + /* XXX should have a way to cache these lookups */ + getTypeOutputInfo(tupdesc->attrs[i]->atttypid, + &typoutput, &typisvarlena); - hv_store_string(hv, attname, cstr2sv(outputstr)); + outputstr = OidOutputFunctionCall(typoutput, attr); + sv = cstr2sv(outputstr); + pfree(outputstr); + } - pfree(outputstr); + hv_store_string(hv, attname, sv); + } } - return newRV_noinc((SV *) hv); } @@ -2507,29 +2861,11 @@ plperl_return_next(SV *sv) Datum ret; bool isNull; - if (SvOK(sv)) - { - char *str; - - if (prodesc->fn_retisarray && SvROK(sv) && - SvTYPE(SvRV(sv)) == SVt_PVAV) - { - sv = plperl_convert_to_pg_array(sv); - } - - str = sv2cstr(sv); - ret = InputFunctionCall(&prodesc->result_in_func, - str, - prodesc->result_typioparam, -1); - isNull = false; - pfree(str); - } - else - { - ret = InputFunctionCall(&prodesc->result_in_func, NULL, - prodesc->result_typioparam, -1); - isNull = true; - } + ret = plperl_sv_to_datum(sv, + &prodesc->result_in_func, + prodesc->result_oid, + prodesc->result_typioparam, + -1, &isNull); tuplestore_putvalues(current_call_data->tuple_store, current_call_data->ret_tdesc, @@ -2910,7 +3246,7 @@ plperl_spi_exec_prepared(char *query, HV *attr, int argc, SV **argv) if (attr != NULL) { sv = hv_fetch_string(attr, "limit"); - if (*sv && SvIOK(*sv)) + if (sv && *sv && SvIOK(*sv)) limit = SvIV(*sv); } /************************************************************ @@ -2929,25 +3265,14 @@ plperl_spi_exec_prepared(char *query, HV *attr, int argc, SV **argv) for (i = 0; i < argc; i++) { - if (SvOK(argv[i])) - { - char *str = sv2cstr(argv[i]); - - argvalues[i] = InputFunctionCall(&qdesc->arginfuncs[i], - str, - qdesc->argtypioparams[i], - -1); - nulls[i] = ' '; - pfree(str); - } - else - { - argvalues[i] = InputFunctionCall(&qdesc->arginfuncs[i], - NULL, - qdesc->argtypioparams[i], - -1); - nulls[i] = 'n'; - } + bool isnull; + + argvalues[i] = plperl_sv_to_datum(argv[i], + &qdesc->arginfuncs[i], + qdesc->argtypes[i], + qdesc->argtypioparams[i], + -1, &isnull); + nulls[i] = isnull ? 'n' : ' '; } /************************************************************ @@ -3065,25 +3390,14 @@ plperl_spi_query_prepared(char *query, int argc, SV **argv) for (i = 0; i < argc; i++) { - if (SvOK(argv[i])) - { - char *str = sv2cstr(argv[i]); - - argvalues[i] = InputFunctionCall(&qdesc->arginfuncs[i], - str, - qdesc->argtypioparams[i], - -1); - nulls[i] = ' '; - pfree(str); - } - else - { - argvalues[i] = InputFunctionCall(&qdesc->arginfuncs[i], - NULL, - qdesc->argtypioparams[i], - -1); - nulls[i] = 'n'; - } + bool isnull; + + argvalues[i] = plperl_sv_to_datum(argv[i], + &qdesc->arginfuncs[i], + qdesc->argtypes[i], + qdesc->argtypioparams[i], + -1, &isnull); + nulls[i] = isnull ? 'n' : ' '; } /************************************************************ |