Header And Logo

PostgreSQL
| The world's most advanced open source database.

Defines | Functions

plperl.h File Reference

#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
#include "ppport.h"
Include dependency graph for plperl.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Defines

#define NEED_eval_pv
#define NEED_newRV_noinc
#define NEED_sv_2pv_flags
#define HeUTF8(he)
#define GvCV_set(gv, cv)   (GvCV(gv) = cv)

Functions

HV * plperl_spi_exec (char *, int)
void plperl_return_next (SV *)
SV * plperl_spi_query (char *)
SV * plperl_spi_fetchrow (char *)
SV * plperl_spi_prepare (char *, int, SV **)
HV * plperl_spi_exec_prepared (char *, HV *, int, SV **)
SV * plperl_spi_query_prepared (char *, int, SV **)
void plperl_spi_freeplan (char *)
void plperl_spi_cursor_close (char *)
char * plperl_sv_to_literal (SV *, char *)

Define Documentation

#define GvCV_set (   gv,
  cv 
)    (GvCV(gv) = cv)

Definition at line 90 of file plperl.h.

Referenced by plperl_trusted_init().

#define HeUTF8 (   he  ) 
Value:
((HeKLEN(he) == HEf_SVKEY) ?               \
                                SvUTF8(HeKEY_sv(he)) :                 \
                                (U32)HeKUTF8(he))

Definition at line 83 of file plperl.h.

Referenced by hek2cstr().

#define NEED_eval_pv

Definition at line 71 of file plperl.h.

#define NEED_newRV_noinc

Definition at line 72 of file plperl.h.

#define NEED_sv_2pv_flags

Definition at line 73 of file plperl.h.


Function Documentation

void plperl_return_next ( SV *   ) 

Definition at line 2925 of file plperl.c.

References ALLOCSET_DEFAULT_INITSIZE, ALLOCSET_DEFAULT_MAXSIZE, ALLOCSET_DEFAULT_MINSIZE, AllocSetContextCreate(), ReturnSetInfo::allowedModes, Assert, CreateTupleDescCopy(), CurrentMemoryContext, ReturnSetInfo::econtext, ExprContext::ecxt_per_query_memory, ereport, errcode(), errmsg(), ERROR, ReturnSetInfo::expectedDesc, plperl_call_data::fcinfo, plperl_proc_desc::fn_retisset, plperl_proc_desc::fn_retistuple, get_call_result_type(), MemoryContextReset(), MemoryContextSwitchTo(), NULL, plperl_build_tuple_result(), plperl_sv_to_datum(), plperl_call_data::prodesc, plperl_proc_desc::result_in_func, plperl_proc_desc::result_oid, plperl_proc_desc::result_typioparam, FunctionCallInfoData::resultinfo, plperl_call_data::ret_tdesc, SFRM_Materialize_Random, plperl_call_data::tmp_cxt, plperl_call_data::tuple_store, tuplestore_begin_heap(), tuplestore_puttuple(), tuplestore_putvalues(), and work_mem.

Referenced by plperl_func_handler().

{
    plperl_proc_desc *prodesc;
    FunctionCallInfo fcinfo;
    ReturnSetInfo *rsi;
    MemoryContext old_cxt;

    if (!sv)
        return;

    prodesc = current_call_data->prodesc;
    fcinfo = current_call_data->fcinfo;
    rsi = (ReturnSetInfo *) fcinfo->resultinfo;

    if (!prodesc->fn_retisset)
        ereport(ERROR,
                (errcode(ERRCODE_SYNTAX_ERROR),
                 errmsg("cannot use return_next in a non-SETOF function")));

    if (!current_call_data->ret_tdesc)
    {
        TupleDesc   tupdesc;

        Assert(!current_call_data->tuple_store);

        /*
         * This is the first call to return_next in the current PL/Perl
         * function call, so memoize some lookups
         */
        if (prodesc->fn_retistuple)
            (void) get_call_result_type(fcinfo, NULL, &tupdesc);
        else
            tupdesc = rsi->expectedDesc;

        /*
         * Make sure the tuple_store and ret_tdesc are sufficiently
         * long-lived.
         */
        old_cxt = MemoryContextSwitchTo(rsi->econtext->ecxt_per_query_memory);

        current_call_data->ret_tdesc = CreateTupleDescCopy(tupdesc);
        current_call_data->tuple_store =
            tuplestore_begin_heap(rsi->allowedModes & SFRM_Materialize_Random,
                                  false, work_mem);

        MemoryContextSwitchTo(old_cxt);
    }

    /*
     * Producing the tuple we want to return requires making plenty of
     * palloc() allocations that are not cleaned up. Since this function can
     * be called many times before the current memory context is reset, we
     * need to do those allocations in a temporary context.
     */
    if (!current_call_data->tmp_cxt)
    {
        current_call_data->tmp_cxt =
            AllocSetContextCreate(CurrentMemoryContext,
                                  "PL/Perl return_next temporary cxt",
                                  ALLOCSET_DEFAULT_MINSIZE,
                                  ALLOCSET_DEFAULT_INITSIZE,
                                  ALLOCSET_DEFAULT_MAXSIZE);
    }

    old_cxt = MemoryContextSwitchTo(current_call_data->tmp_cxt);

    if (prodesc->fn_retistuple)
    {
        HeapTuple   tuple;

        if (!(SvOK(sv) && SvROK(sv) && SvTYPE(SvRV(sv)) == SVt_PVHV))
            ereport(ERROR,
                    (errcode(ERRCODE_DATATYPE_MISMATCH),
                     errmsg("SETOF-composite-returning PL/Perl function "
                            "must call return_next with reference to hash")));

        tuple = plperl_build_tuple_result((HV *) SvRV(sv),
                                          current_call_data->ret_tdesc);
        tuplestore_puttuple(current_call_data->tuple_store, tuple);
    }
    else
    {
        Datum       ret;
        bool        isNull;

        ret = plperl_sv_to_datum(sv,
                                 prodesc->result_oid,
                                 -1,
                                 fcinfo,
                                 &prodesc->result_in_func,
                                 prodesc->result_typioparam,
                                 &isNull);

        tuplestore_putvalues(current_call_data->tuple_store,
                             current_call_data->ret_tdesc,
                             &ret, &isNull);
    }

    MemoryContextSwitchTo(old_cxt);
    MemoryContextReset(current_call_data->tmp_cxt);
}

void plperl_spi_cursor_close ( char *   ) 
HV* plperl_spi_exec ( char *  ,
int   
)

Definition at line 2806 of file plperl.c.

References BeginInternalSubTransaction(), check_spi_usage_allowed(), CopyErrorData(), CurrentMemoryContext, CurrentResourceOwner, FlushErrorState(), plperl_proc_desc::fn_readonly, MemoryContextSwitchTo(), ErrorData::message, NULL, PG_CATCH, PG_END_TRY, PG_TRY, pg_verifymbstr(), plperl_spi_execute_fetch_result(), plperl_call_data::prodesc, ReleaseCurrentSubTransaction(), RollbackAndReleaseCurrentSubTransaction(), SPI_execute(), SPI_processed, SPI_restore_connection(), and SPI_tuptable.

{
    HV         *ret_hv;

    /*
     * Execute the query inside a sub-transaction, so we can cope with errors
     * sanely
     */
    MemoryContext oldcontext = CurrentMemoryContext;
    ResourceOwner oldowner = CurrentResourceOwner;

    check_spi_usage_allowed();

    BeginInternalSubTransaction(NULL);
    /* Want to run inside function's memory context */
    MemoryContextSwitchTo(oldcontext);

    PG_TRY();
    {
        int         spi_rv;

        pg_verifymbstr(query, strlen(query), false);

        spi_rv = SPI_execute(query, current_call_data->prodesc->fn_readonly,
                             limit);
        ret_hv = plperl_spi_execute_fetch_result(SPI_tuptable, SPI_processed,
                                                 spi_rv);

        /* Commit the inner transaction, return to outer xact context */
        ReleaseCurrentSubTransaction();
        MemoryContextSwitchTo(oldcontext);
        CurrentResourceOwner = oldowner;

        /*
         * AtEOSubXact_SPI() should not have popped any SPI context, but just
         * in case it did, make sure we remain connected.
         */
        SPI_restore_connection();
    }
    PG_CATCH();
    {
        ErrorData  *edata;

        /* Save error info */
        MemoryContextSwitchTo(oldcontext);
        edata = CopyErrorData();
        FlushErrorState();

        /* Abort the inner transaction */
        RollbackAndReleaseCurrentSubTransaction();
        MemoryContextSwitchTo(oldcontext);
        CurrentResourceOwner = oldowner;

        /*
         * If AtEOSubXact_SPI() popped any SPI context of the subxact, it will
         * have left us in a disconnected state.  We need this hack to return
         * to connected state.
         */
        SPI_restore_connection();

        /* Punt the error to Perl */
        croak("%s", edata->message);

        /* Can't get here, but keep compiler quiet */
        return NULL;
    }
    PG_END_TRY();

    return ret_hv;
}

HV* plperl_spi_exec_prepared ( char *  ,
HV *  ,
int  ,
SV **   
)

Definition at line 3375 of file plperl.c.

References plperl_query_desc::arginfuncs, plperl_query_desc::argtypes, plperl_query_desc::argtypioparams, BeginInternalSubTransaction(), check_spi_usage_allowed(), CopyErrorData(), CurrentMemoryContext, CurrentResourceOwner, elog, ERROR, FlushErrorState(), plperl_proc_desc::fn_readonly, HASH_FIND, hash_search(), hv_fetch_string(), i, MemoryContextSwitchTo(), ErrorData::message, plperl_query_desc::nargs, NULL, palloc(), pfree(), PG_CATCH, PG_END_TRY, PG_TRY, plperl_query_desc::plan, plperl_spi_execute_fetch_result(), plperl_sv_to_datum(), plperl_call_data::prodesc, plperl_query_entry::query_data, plperl_interp_desc::query_hash, ReleaseCurrentSubTransaction(), RollbackAndReleaseCurrentSubTransaction(), SPI_execute_plan(), SPI_processed, SPI_restore_connection(), and SPI_tuptable.

{
    HV         *ret_hv;
    SV        **sv;
    int         i,
                limit,
                spi_rv;
    char       *nulls;
    Datum      *argvalues;
    plperl_query_desc *qdesc;
    plperl_query_entry *hash_entry;

    /*
     * Execute the query inside a sub-transaction, so we can cope with errors
     * sanely
     */
    MemoryContext oldcontext = CurrentMemoryContext;
    ResourceOwner oldowner = CurrentResourceOwner;

    check_spi_usage_allowed();

    BeginInternalSubTransaction(NULL);
    /* Want to run inside function's memory context */
    MemoryContextSwitchTo(oldcontext);

    PG_TRY();
    {
        /************************************************************
         * Fetch the saved plan descriptor, see if it's o.k.
         ************************************************************/
        hash_entry = hash_search(plperl_active_interp->query_hash, query,
                                 HASH_FIND, NULL);
        if (hash_entry == NULL)
            elog(ERROR, "spi_exec_prepared: Invalid prepared query passed");

        qdesc = hash_entry->query_data;
        if (qdesc == NULL)
            elog(ERROR, "spi_exec_prepared: plperl query_hash value vanished");

        if (qdesc->nargs != argc)
            elog(ERROR, "spi_exec_prepared: expected %d argument(s), %d passed",
                 qdesc->nargs, argc);

        /************************************************************
         * Parse eventual attributes
         ************************************************************/
        limit = 0;
        if (attr != NULL)
        {
            sv = hv_fetch_string(attr, "limit");
            if (sv && *sv && SvIOK(*sv))
                limit = SvIV(*sv);
        }
        /************************************************************
         * Set up arguments
         ************************************************************/
        if (argc > 0)
        {
            nulls = (char *) palloc(argc);
            argvalues = (Datum *) palloc(argc * sizeof(Datum));
        }
        else
        {
            nulls = NULL;
            argvalues = NULL;
        }

        for (i = 0; i < argc; i++)
        {
            bool        isnull;

            argvalues[i] = plperl_sv_to_datum(argv[i],
                                              qdesc->argtypes[i],
                                              -1,
                                              NULL,
                                              &qdesc->arginfuncs[i],
                                              qdesc->argtypioparams[i],
                                              &isnull);
            nulls[i] = isnull ? 'n' : ' ';
        }

        /************************************************************
         * go
         ************************************************************/
        spi_rv = SPI_execute_plan(qdesc->plan, argvalues, nulls,
                             current_call_data->prodesc->fn_readonly, limit);
        ret_hv = plperl_spi_execute_fetch_result(SPI_tuptable, SPI_processed,
                                                 spi_rv);
        if (argc > 0)
        {
            pfree(argvalues);
            pfree(nulls);
        }

        /* Commit the inner transaction, return to outer xact context */
        ReleaseCurrentSubTransaction();
        MemoryContextSwitchTo(oldcontext);
        CurrentResourceOwner = oldowner;

        /*
         * AtEOSubXact_SPI() should not have popped any SPI context, but just
         * in case it did, make sure we remain connected.
         */
        SPI_restore_connection();
    }
    PG_CATCH();
    {
        ErrorData  *edata;

        /* Save error info */
        MemoryContextSwitchTo(oldcontext);
        edata = CopyErrorData();
        FlushErrorState();

        /* Abort the inner transaction */
        RollbackAndReleaseCurrentSubTransaction();
        MemoryContextSwitchTo(oldcontext);
        CurrentResourceOwner = oldowner;

        /*
         * If AtEOSubXact_SPI() popped any SPI context of the subxact, it will
         * have left us in a disconnected state.  We need this hack to return
         * to connected state.
         */
        SPI_restore_connection();

        /* Punt the error to Perl */
        croak("%s", edata->message);

        /* Can't get here, but keep compiler quiet */
        return NULL;
    }
    PG_END_TRY();

    return ret_hv;
}

SV* plperl_spi_fetchrow ( char *   ) 

Definition at line 3112 of file plperl.c.

References BeginInternalSubTransaction(), check_spi_usage_allowed(), CopyErrorData(), CurrentMemoryContext, CurrentResourceOwner, FlushErrorState(), MemoryContextSwitchTo(), ErrorData::message, NULL, PG_CATCH, PG_END_TRY, PG_TRY, plperl_hash_from_tuple(), ReleaseCurrentSubTransaction(), RollbackAndReleaseCurrentSubTransaction(), SPI_cursor_close(), SPI_cursor_fetch(), SPI_cursor_find(), SPI_freetuptable(), SPI_processed, SPI_restore_connection(), SPI_tuptable, SPITupleTable::tupdesc, and SPITupleTable::vals.

{
    SV         *row;

    /*
     * Execute the FETCH inside a sub-transaction, so we can cope with errors
     * sanely
     */
    MemoryContext oldcontext = CurrentMemoryContext;
    ResourceOwner oldowner = CurrentResourceOwner;

    check_spi_usage_allowed();

    BeginInternalSubTransaction(NULL);
    /* Want to run inside function's memory context */
    MemoryContextSwitchTo(oldcontext);

    PG_TRY();
    {
        Portal      p = SPI_cursor_find(cursor);

        if (!p)
        {
            row = &PL_sv_undef;
        }
        else
        {
            SPI_cursor_fetch(p, true, 1);
            if (SPI_processed == 0)
            {
                SPI_cursor_close(p);
                row = &PL_sv_undef;
            }
            else
            {
                row = plperl_hash_from_tuple(SPI_tuptable->vals[0],
                                             SPI_tuptable->tupdesc);
            }
            SPI_freetuptable(SPI_tuptable);
        }

        /* Commit the inner transaction, return to outer xact context */
        ReleaseCurrentSubTransaction();
        MemoryContextSwitchTo(oldcontext);
        CurrentResourceOwner = oldowner;

        /*
         * AtEOSubXact_SPI() should not have popped any SPI context, but just
         * in case it did, make sure we remain connected.
         */
        SPI_restore_connection();
    }
    PG_CATCH();
    {
        ErrorData  *edata;

        /* Save error info */
        MemoryContextSwitchTo(oldcontext);
        edata = CopyErrorData();
        FlushErrorState();

        /* Abort the inner transaction */
        RollbackAndReleaseCurrentSubTransaction();
        MemoryContextSwitchTo(oldcontext);
        CurrentResourceOwner = oldowner;

        /*
         * If AtEOSubXact_SPI() popped any SPI context of the subxact, it will
         * have left us in a disconnected state.  We need this hack to return
         * to connected state.
         */
        SPI_restore_connection();

        /* Punt the error to Perl */
        croak("%s", edata->message);

        /* Can't get here, but keep compiler quiet */
        return NULL;
    }
    PG_END_TRY();

    return row;
}

void plperl_spi_freeplan ( char *   ) 

Definition at line 3642 of file plperl.c.

References check_spi_usage_allowed(), elog, ERROR, HASH_FIND, HASH_REMOVE, hash_search(), MemoryContextDelete(), NULL, plperl_query_desc::plan, plperl_query_desc::plan_cxt, plperl_query_entry::query_data, plperl_interp_desc::query_hash, and SPI_freeplan().

{
    SPIPlanPtr  plan;
    plperl_query_desc *qdesc;
    plperl_query_entry *hash_entry;

    check_spi_usage_allowed();

    hash_entry = hash_search(plperl_active_interp->query_hash, query,
                             HASH_FIND, NULL);
    if (hash_entry == NULL)
        elog(ERROR, "spi_freeplan: Invalid prepared query passed");

    qdesc = hash_entry->query_data;
    if (qdesc == NULL)
        elog(ERROR, "spi_freeplan: plperl query_hash value vanished");
    plan = qdesc->plan;

    /*
     * free all memory before SPI_freeplan, so if it dies, nothing will be
     * left over
     */
    hash_search(plperl_active_interp->query_hash, query,
                HASH_REMOVE, NULL);

    MemoryContextDelete(qdesc->plan_cxt);

    SPI_freeplan(plan);
}

SV* plperl_spi_prepare ( char *  ,
int  ,
SV **   
)

Definition at line 3210 of file plperl.c.

References ALLOCSET_DEFAULT_INITSIZE, ALLOCSET_DEFAULT_MAXSIZE, ALLOCSET_DEFAULT_MINSIZE, ALLOCSET_SMALL_INITSIZE, ALLOCSET_SMALL_MAXSIZE, ALLOCSET_SMALL_MINSIZE, AllocSetContextCreate(), plperl_query_desc::arginfuncs, plperl_query_desc::argtypes, plperl_query_desc::argtypioparams, BeginInternalSubTransaction(), CHECK_FOR_INTERRUPTS, check_spi_usage_allowed(), CopyErrorData(), cstr2sv(), CurrentMemoryContext, CurrentResourceOwner, elog, ERROR, FlushErrorState(), fmgr_info_cxt(), getTypeInputInfo(), HASH_ENTER, HASH_REMOVE, hash_search(), i, MemoryContextDelete(), MemoryContextSwitchTo(), ErrorData::message, plperl_query_desc::nargs, NULL, palloc(), palloc0(), parseTypeString(), pfree(), PG_CATCH, PG_END_TRY, PG_TRY, pg_verifymbstr(), plperl_query_desc::plan, plperl_query_desc::plan_cxt, plperl_query_desc::qname, plperl_query_entry::query_data, plperl_interp_desc::query_hash, ReleaseCurrentSubTransaction(), RollbackAndReleaseCurrentSubTransaction(), snprintf(), SPI_freeplan(), SPI_keepplan(), SPI_prepare(), SPI_restore_connection(), SPI_result, SPI_result_code_string(), sv2cstr(), and TopMemoryContext.

{
    volatile SPIPlanPtr plan = NULL;
    volatile MemoryContext plan_cxt = NULL;
    plperl_query_desc *volatile qdesc = NULL;
    plperl_query_entry *volatile hash_entry = NULL;
    MemoryContext oldcontext = CurrentMemoryContext;
    ResourceOwner oldowner = CurrentResourceOwner;
    MemoryContext work_cxt;
    bool        found;
    int         i;

    check_spi_usage_allowed();

    BeginInternalSubTransaction(NULL);
    MemoryContextSwitchTo(oldcontext);

    PG_TRY();
    {
        CHECK_FOR_INTERRUPTS();

        /************************************************************
         * Allocate the new querydesc structure
         *
         * The qdesc struct, as well as all its subsidiary data, lives in its
         * plan_cxt.  But note that the SPIPlan does not.
         ************************************************************/
        plan_cxt = AllocSetContextCreate(TopMemoryContext,
                                         "PL/Perl spi_prepare query",
                                         ALLOCSET_SMALL_MINSIZE,
                                         ALLOCSET_SMALL_INITSIZE,
                                         ALLOCSET_SMALL_MAXSIZE);
        MemoryContextSwitchTo(plan_cxt);
        qdesc = (plperl_query_desc *) palloc0(sizeof(plperl_query_desc));
        snprintf(qdesc->qname, sizeof(qdesc->qname), "%p", qdesc);
        qdesc->plan_cxt = plan_cxt;
        qdesc->nargs = argc;
        qdesc->argtypes = (Oid *) palloc(argc * sizeof(Oid));
        qdesc->arginfuncs = (FmgrInfo *) palloc(argc * sizeof(FmgrInfo));
        qdesc->argtypioparams = (Oid *) palloc(argc * sizeof(Oid));
        MemoryContextSwitchTo(oldcontext);

        /************************************************************
         * Do the following work in a short-lived context so that we don't
         * leak a lot of memory in the PL/Perl function's SPI Proc context.
         ************************************************************/
        work_cxt = AllocSetContextCreate(CurrentMemoryContext,
                                         "PL/Perl spi_prepare workspace",
                                         ALLOCSET_DEFAULT_MINSIZE,
                                         ALLOCSET_DEFAULT_INITSIZE,
                                         ALLOCSET_DEFAULT_MAXSIZE);
        MemoryContextSwitchTo(work_cxt);

        /************************************************************
         * Resolve argument type names and then look them up by oid
         * in the system cache, and remember the required information
         * for input conversion.
         ************************************************************/
        for (i = 0; i < argc; i++)
        {
            Oid         typId,
                        typInput,
                        typIOParam;
            int32       typmod;
            char       *typstr;

            typstr = sv2cstr(argv[i]);
            parseTypeString(typstr, &typId, &typmod);
            pfree(typstr);

            getTypeInputInfo(typId, &typInput, &typIOParam);

            qdesc->argtypes[i] = typId;
            fmgr_info_cxt(typInput, &(qdesc->arginfuncs[i]), plan_cxt);
            qdesc->argtypioparams[i] = typIOParam;
        }

        /* Make sure the query is validly encoded */
        pg_verifymbstr(query, strlen(query), false);

        /************************************************************
         * Prepare the plan and check for errors
         ************************************************************/
        plan = SPI_prepare(query, argc, qdesc->argtypes);

        if (plan == NULL)
            elog(ERROR, "SPI_prepare() failed:%s",
                 SPI_result_code_string(SPI_result));

        /************************************************************
         * Save the plan into permanent memory (right now it's in the
         * SPI procCxt, which will go away at function end).
         ************************************************************/
        if (SPI_keepplan(plan))
            elog(ERROR, "SPI_keepplan() failed");
        qdesc->plan = plan;

        /************************************************************
         * Insert a hashtable entry for the plan.
         ************************************************************/
        hash_entry = hash_search(plperl_active_interp->query_hash,
                                 qdesc->qname,
                                 HASH_ENTER, &found);
        hash_entry->query_data = qdesc;

        /* Get rid of workspace */
        MemoryContextDelete(work_cxt);

        /* Commit the inner transaction, return to outer xact context */
        ReleaseCurrentSubTransaction();
        MemoryContextSwitchTo(oldcontext);
        CurrentResourceOwner = oldowner;

        /*
         * AtEOSubXact_SPI() should not have popped any SPI context, but just
         * in case it did, make sure we remain connected.
         */
        SPI_restore_connection();
    }
    PG_CATCH();
    {
        ErrorData  *edata;

        /* Save error info */
        MemoryContextSwitchTo(oldcontext);
        edata = CopyErrorData();
        FlushErrorState();

        /* Drop anything we managed to allocate */
        if (hash_entry)
            hash_search(plperl_active_interp->query_hash,
                        qdesc->qname,
                        HASH_REMOVE, NULL);
        if (plan_cxt)
            MemoryContextDelete(plan_cxt);
        if (plan)
            SPI_freeplan(plan);

        /* Abort the inner transaction */
        RollbackAndReleaseCurrentSubTransaction();
        MemoryContextSwitchTo(oldcontext);
        CurrentResourceOwner = oldowner;

        /*
         * If AtEOSubXact_SPI() popped any SPI context of the subxact, it will
         * have left us in a disconnected state.  We need this hack to return
         * to connected state.
         */
        SPI_restore_connection();

        /* Punt the error to Perl */
        croak("%s", edata->message);

        /* Can't get here, but keep compiler quiet */
        return NULL;
    }
    PG_END_TRY();

    /************************************************************
     * Return the query's hash key to the caller.
     ************************************************************/
    return cstr2sv(qdesc->qname);
}

SV* plperl_spi_query ( char *   ) 

Definition at line 3029 of file plperl.c.

References BeginInternalSubTransaction(), check_spi_usage_allowed(), CopyErrorData(), cstr2sv(), CurrentMemoryContext, CurrentResourceOwner, elog, ERROR, FlushErrorState(), MemoryContextSwitchTo(), ErrorData::message, PortalData::name, NULL, PG_CATCH, PG_END_TRY, PG_TRY, pg_verifymbstr(), ReleaseCurrentSubTransaction(), RollbackAndReleaseCurrentSubTransaction(), SPI_cursor_open(), SPI_freeplan(), SPI_prepare(), SPI_restore_connection(), SPI_result, and SPI_result_code_string().

{
    SV         *cursor;

    /*
     * Execute the query inside a sub-transaction, so we can cope with errors
     * sanely
     */
    MemoryContext oldcontext = CurrentMemoryContext;
    ResourceOwner oldowner = CurrentResourceOwner;

    check_spi_usage_allowed();

    BeginInternalSubTransaction(NULL);
    /* Want to run inside function's memory context */
    MemoryContextSwitchTo(oldcontext);

    PG_TRY();
    {
        SPIPlanPtr  plan;
        Portal      portal;

        /* Make sure the query is validly encoded */
        pg_verifymbstr(query, strlen(query), false);

        /* Create a cursor for the query */
        plan = SPI_prepare(query, 0, NULL);
        if (plan == NULL)
            elog(ERROR, "SPI_prepare() failed:%s",
                 SPI_result_code_string(SPI_result));

        portal = SPI_cursor_open(NULL, plan, NULL, NULL, false);
        SPI_freeplan(plan);
        if (portal == NULL)
            elog(ERROR, "SPI_cursor_open() failed:%s",
                 SPI_result_code_string(SPI_result));
        cursor = cstr2sv(portal->name);

        /* Commit the inner transaction, return to outer xact context */
        ReleaseCurrentSubTransaction();
        MemoryContextSwitchTo(oldcontext);
        CurrentResourceOwner = oldowner;

        /*
         * AtEOSubXact_SPI() should not have popped any SPI context, but just
         * in case it did, make sure we remain connected.
         */
        SPI_restore_connection();
    }
    PG_CATCH();
    {
        ErrorData  *edata;

        /* Save error info */
        MemoryContextSwitchTo(oldcontext);
        edata = CopyErrorData();
        FlushErrorState();

        /* Abort the inner transaction */
        RollbackAndReleaseCurrentSubTransaction();
        MemoryContextSwitchTo(oldcontext);
        CurrentResourceOwner = oldowner;

        /*
         * If AtEOSubXact_SPI() popped any SPI context of the subxact, it will
         * have left us in a disconnected state.  We need this hack to return
         * to connected state.
         */
        SPI_restore_connection();

        /* Punt the error to Perl */
        croak("%s", edata->message);

        /* Can't get here, but keep compiler quiet */
        return NULL;
    }
    PG_END_TRY();

    return cursor;
}

SV* plperl_spi_query_prepared ( char *  ,
int  ,
SV **   
)

Definition at line 3513 of file plperl.c.

References plperl_query_desc::arginfuncs, plperl_query_desc::argtypes, plperl_query_desc::argtypioparams, BeginInternalSubTransaction(), check_spi_usage_allowed(), CopyErrorData(), cstr2sv(), CurrentMemoryContext, CurrentResourceOwner, elog, ERROR, FlushErrorState(), plperl_proc_desc::fn_readonly, HASH_FIND, hash_search(), i, MemoryContextSwitchTo(), ErrorData::message, PortalData::name, plperl_query_desc::nargs, NULL, palloc(), pfree(), PG_CATCH, PG_END_TRY, PG_TRY, plperl_query_desc::plan, plperl_sv_to_datum(), plperl_call_data::prodesc, plperl_query_entry::query_data, plperl_interp_desc::query_hash, ReleaseCurrentSubTransaction(), RollbackAndReleaseCurrentSubTransaction(), SPI_cursor_open(), SPI_restore_connection(), SPI_result, and SPI_result_code_string().

{
    int         i;
    char       *nulls;
    Datum      *argvalues;
    plperl_query_desc *qdesc;
    plperl_query_entry *hash_entry;
    SV         *cursor;
    Portal      portal = NULL;

    /*
     * Execute the query inside a sub-transaction, so we can cope with errors
     * sanely
     */
    MemoryContext oldcontext = CurrentMemoryContext;
    ResourceOwner oldowner = CurrentResourceOwner;

    check_spi_usage_allowed();

    BeginInternalSubTransaction(NULL);
    /* Want to run inside function's memory context */
    MemoryContextSwitchTo(oldcontext);

    PG_TRY();
    {
        /************************************************************
         * Fetch the saved plan descriptor, see if it's o.k.
         ************************************************************/
        hash_entry = hash_search(plperl_active_interp->query_hash, query,
                                 HASH_FIND, NULL);
        if (hash_entry == NULL)
            elog(ERROR, "spi_query_prepared: Invalid prepared query passed");

        qdesc = hash_entry->query_data;
        if (qdesc == NULL)
            elog(ERROR, "spi_query_prepared: plperl query_hash value vanished");

        if (qdesc->nargs != argc)
            elog(ERROR, "spi_query_prepared: expected %d argument(s), %d passed",
                 qdesc->nargs, argc);

        /************************************************************
         * Set up arguments
         ************************************************************/
        if (argc > 0)
        {
            nulls = (char *) palloc(argc);
            argvalues = (Datum *) palloc(argc * sizeof(Datum));
        }
        else
        {
            nulls = NULL;
            argvalues = NULL;
        }

        for (i = 0; i < argc; i++)
        {
            bool        isnull;

            argvalues[i] = plperl_sv_to_datum(argv[i],
                                              qdesc->argtypes[i],
                                              -1,
                                              NULL,
                                              &qdesc->arginfuncs[i],
                                              qdesc->argtypioparams[i],
                                              &isnull);
            nulls[i] = isnull ? 'n' : ' ';
        }

        /************************************************************
         * go
         ************************************************************/
        portal = SPI_cursor_open(NULL, qdesc->plan, argvalues, nulls,
                                 current_call_data->prodesc->fn_readonly);
        if (argc > 0)
        {
            pfree(argvalues);
            pfree(nulls);
        }
        if (portal == NULL)
            elog(ERROR, "SPI_cursor_open() failed:%s",
                 SPI_result_code_string(SPI_result));

        cursor = cstr2sv(portal->name);

        /* Commit the inner transaction, return to outer xact context */
        ReleaseCurrentSubTransaction();
        MemoryContextSwitchTo(oldcontext);
        CurrentResourceOwner = oldowner;

        /*
         * AtEOSubXact_SPI() should not have popped any SPI context, but just
         * in case it did, make sure we remain connected.
         */
        SPI_restore_connection();
    }
    PG_CATCH();
    {
        ErrorData  *edata;

        /* Save error info */
        MemoryContextSwitchTo(oldcontext);
        edata = CopyErrorData();
        FlushErrorState();

        /* Abort the inner transaction */
        RollbackAndReleaseCurrentSubTransaction();
        MemoryContextSwitchTo(oldcontext);
        CurrentResourceOwner = oldowner;

        /*
         * If AtEOSubXact_SPI() popped any SPI context of the subxact, it will
         * have left us in a disconnected state.  We need this hack to return
         * to connected state.
         */
        SPI_restore_connection();

        /* Punt the error to Perl */
        croak("%s", edata->message);

        /* Can't get here, but keep compiler quiet */
        return NULL;
    }
    PG_END_TRY();

    return cursor;
}

char* plperl_sv_to_literal ( SV *  ,
char *   
)

Definition at line 1355 of file plperl.c.

References CStringGetDatum, DirectFunctionCall1, elog, ERROR, getTypeOutputInfo(), InvalidOid, NULL, OidIsValid, OidOutputFunctionCall(), plperl_sv_to_datum(), and regtypein().

{
    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,
                               typid, -1,
                               NULL, NULL, InvalidOid,
                               &isnull);

    if (isnull)
        return NULL;

    getTypeOutputInfo(typid,
                      &typoutput, &typisvarlena);

    return OidOutputFunctionCall(typoutput, datum);
}