LCOV - code coverage report
Current view: top level - src/pl/plperl - plperl.c (source / functions) Coverage Total Hit
Test: Code coverage Lines: 0.0 % 1865 0
Test Date: 2026-01-26 10:56:24 Functions: 0.0 % 73 0
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /**********************************************************************
       2              :  * plperl.c - perl as a procedural language for PostgreSQL
       3              :  *
       4              :  *        src/pl/plperl/plperl.c
       5              :  *
       6              :  **********************************************************************/
       7              : 
       8              : #include "postgres.h"
       9              : 
      10              : /* system stuff */
      11              : #include <ctype.h>
      12              : #include <fcntl.h>
      13              : #include <limits.h>
      14              : #include <unistd.h>
      15              : 
      16              : /* postgreSQL stuff */
      17              : #include "access/htup_details.h"
      18              : #include "access/xact.h"
      19              : #include "catalog/pg_language.h"
      20              : #include "catalog/pg_proc.h"
      21              : #include "catalog/pg_type.h"
      22              : #include "commands/event_trigger.h"
      23              : #include "commands/trigger.h"
      24              : #include "executor/spi.h"
      25              : #include "funcapi.h"
      26              : #include "miscadmin.h"
      27              : #include "parser/parse_type.h"
      28              : #include "storage/ipc.h"
      29              : #include "tcop/tcopprot.h"
      30              : #include "utils/builtins.h"
      31              : #include "utils/fmgroids.h"
      32              : #include "utils/guc.h"
      33              : #include "utils/hsearch.h"
      34              : #include "utils/lsyscache.h"
      35              : #include "utils/memutils.h"
      36              : #include "utils/rel.h"
      37              : #include "utils/syscache.h"
      38              : #include "utils/typcache.h"
      39              : 
      40              : /* define our text domain for translations */
      41              : #undef TEXTDOMAIN
      42              : #define TEXTDOMAIN PG_TEXTDOMAIN("plperl")
      43              : 
      44              : /* perl stuff */
      45              : /* string literal macros defining chunks of perl code */
      46              : #include "perlchunks.h"
      47              : #include "plperl.h"
      48              : /* defines PLPERL_SET_OPMASK */
      49              : #include "plperl_opmask.h"
      50              : 
      51              : EXTERN_C void boot_DynaLoader(pTHX_ CV *cv);
      52              : EXTERN_C void boot_PostgreSQL__InServer__Util(pTHX_ CV *cv);
      53              : EXTERN_C void boot_PostgreSQL__InServer__SPI(pTHX_ CV *cv);
      54              : 
      55            0 : PG_MODULE_MAGIC_EXT(
      56              :                                         .name = "plperl",
      57              :                                         .version = PG_VERSION
      58              : );
      59              : 
      60              : /**********************************************************************
      61              :  * Information associated with a Perl interpreter.  We have one interpreter
      62              :  * that is used for all plperlu (untrusted) functions.  For plperl (trusted)
      63              :  * functions, there is a separate interpreter for each effective SQL userid.
      64              :  * (This is needed to ensure that an unprivileged user can't inject Perl code
      65              :  * that'll be executed with the privileges of some other SQL user.)
      66              :  *
      67              :  * The plperl_interp_desc structs are kept in a Postgres hash table indexed
      68              :  * by userid OID, with OID 0 used for the single untrusted interpreter.
      69              :  * Once created, an interpreter is kept for the life of the process.
      70              :  *
      71              :  * We start out by creating a "held" interpreter, which we initialize
      72              :  * only as far as we can do without deciding if it will be trusted or
      73              :  * untrusted.  Later, when we first need to run a plperl or plperlu
      74              :  * function, we complete the initialization appropriately and move the
      75              :  * PerlInterpreter pointer into the plperl_interp_hash hashtable.  If after
      76              :  * that we need more interpreters, we create them as needed if we can, or
      77              :  * fail if the Perl build doesn't support multiple interpreters.
      78              :  *
      79              :  * The reason for all the dancing about with a held interpreter is to make
      80              :  * it possible for people to preload a lot of Perl code at postmaster startup
      81              :  * (using plperl.on_init) and then use that code in backends.  Of course this
      82              :  * will only work for the first interpreter created in any backend, but it's
      83              :  * still useful with that restriction.
      84              :  **********************************************************************/
      85              : typedef struct plperl_interp_desc
      86              : {
      87              :         Oid                     user_id;                /* Hash key (must be first!) */
      88              :         PerlInterpreter *interp;        /* The interpreter */
      89              :         HTAB       *query_hash;         /* plperl_query_entry structs */
      90              : } plperl_interp_desc;
      91              : 
      92              : 
      93              : /**********************************************************************
      94              :  * The information we cache about loaded procedures
      95              :  *
      96              :  * The fn_refcount field counts the struct's reference from the hash table
      97              :  * shown below, plus one reference for each function call level that is using
      98              :  * the struct.  We can release the struct, and the associated Perl sub, when
      99              :  * the fn_refcount goes to zero.  Releasing the struct itself is done by
     100              :  * deleting the fn_cxt, which also gets rid of all subsidiary data.
     101              :  **********************************************************************/
     102              : typedef struct plperl_proc_desc
     103              : {
     104              :         char       *proname;            /* user name of procedure */
     105              :         MemoryContext fn_cxt;           /* memory context for this procedure */
     106              :         unsigned long fn_refcount;      /* number of active references */
     107              :         TransactionId fn_xmin;          /* xmin/TID of procedure's pg_proc tuple */
     108              :         ItemPointerData fn_tid;
     109              :         SV                 *reference;          /* CODE reference for Perl sub */
     110              :         plperl_interp_desc *interp; /* interpreter it's created in */
     111              :         bool            fn_readonly;    /* is function readonly (not volatile)? */
     112              :         Oid                     lang_oid;
     113              :         List       *trftypes;
     114              :         bool            lanpltrusted;   /* is it plperl, rather than plperlu? */
     115              :         bool            fn_retistuple;  /* true, if function returns tuple */
     116              :         bool            fn_retisset;    /* true, if function returns set */
     117              :         bool            fn_retisarray;  /* true if function returns array */
     118              :         /* Conversion info for function's result type: */
     119              :         Oid                     result_oid;             /* Oid of result type */
     120              :         FmgrInfo        result_in_func; /* I/O function and arg for result type */
     121              :         Oid                     result_typioparam;
     122              :         /* Per-argument info for function's argument types: */
     123              :         int                     nargs;
     124              :         FmgrInfo   *arg_out_func;       /* output fns for arg types */
     125              :         bool       *arg_is_rowtype; /* is each arg composite? */
     126              :         Oid                *arg_arraytype;      /* InvalidOid if not an array */
     127              : } plperl_proc_desc;
     128              : 
     129              : #define increment_prodesc_refcount(prodesc)  \
     130              :         ((prodesc)->fn_refcount++)
     131              : #define decrement_prodesc_refcount(prodesc)  \
     132              :         do { \
     133              :                 Assert((prodesc)->fn_refcount > 0); \
     134              :                 if (--((prodesc)->fn_refcount) == 0) \
     135              :                         free_plperl_function(prodesc); \
     136              :         } while(0)
     137              : 
     138              : /**********************************************************************
     139              :  * For speedy lookup, we maintain a hash table mapping from
     140              :  * function OID + trigger flag + user OID to plperl_proc_desc pointers.
     141              :  * The reason the plperl_proc_desc struct isn't directly part of the hash
     142              :  * entry is to simplify recovery from errors during compile_plperl_function.
     143              :  *
     144              :  * Note: if the same function is called by multiple userIDs within a session,
     145              :  * there will be a separate plperl_proc_desc entry for each userID in the case
     146              :  * of plperl functions, but only one entry for plperlu functions, because we
     147              :  * set user_id = 0 for that case.  If the user redeclares the same function
     148              :  * from plperl to plperlu or vice versa, there might be multiple
     149              :  * plperl_proc_ptr entries in the hashtable, but only one is valid.
     150              :  **********************************************************************/
     151              : typedef struct plperl_proc_key
     152              : {
     153              :         Oid                     proc_id;                /* Function OID */
     154              : 
     155              :         /*
     156              :          * is_trigger is really a bool, but declare as Oid to ensure this struct
     157              :          * contains no padding
     158              :          */
     159              :         Oid                     is_trigger;             /* is it a trigger function? */
     160              :         Oid                     user_id;                /* User calling the function, or 0 */
     161              : } plperl_proc_key;
     162              : 
     163              : typedef struct plperl_proc_ptr
     164              : {
     165              :         plperl_proc_key proc_key;       /* Hash key (must be first!) */
     166              :         plperl_proc_desc *proc_ptr;
     167              : } plperl_proc_ptr;
     168              : 
     169              : /*
     170              :  * The information we cache for the duration of a single call to a
     171              :  * function.
     172              :  */
     173              : typedef struct plperl_call_data
     174              : {
     175              :         plperl_proc_desc *prodesc;
     176              :         FunctionCallInfo fcinfo;
     177              :         /* remaining fields are used only in a function returning set: */
     178              :         Tuplestorestate *tuple_store;
     179              :         TupleDesc       ret_tdesc;
     180              :         Oid                     cdomain_oid;    /* 0 unless returning domain-over-composite */
     181              :         void       *cdomain_info;
     182              :         MemoryContext tmp_cxt;
     183              : } plperl_call_data;
     184              : 
     185              : /**********************************************************************
     186              :  * The information we cache about prepared and saved plans
     187              :  **********************************************************************/
     188              : typedef struct plperl_query_desc
     189              : {
     190              :         char            qname[24];
     191              :         MemoryContext plan_cxt;         /* context holding this struct */
     192              :         SPIPlanPtr      plan;
     193              :         int                     nargs;
     194              :         Oid                *argtypes;
     195              :         FmgrInfo   *arginfuncs;
     196              :         Oid                *argtypioparams;
     197              : } plperl_query_desc;
     198              : 
     199              : /* hash table entry for query desc      */
     200              : 
     201              : typedef struct plperl_query_entry
     202              : {
     203              :         char            query_name[NAMEDATALEN];
     204              :         plperl_query_desc *query_data;
     205              : } plperl_query_entry;
     206              : 
     207              : /**********************************************************************
     208              :  * Information for PostgreSQL - Perl array conversion.
     209              :  **********************************************************************/
     210              : typedef struct plperl_array_info
     211              : {
     212              :         int                     ndims;
     213              :         bool            elem_is_rowtype;        /* 't' if element type is a rowtype */
     214              :         Datum      *elements;
     215              :         bool       *nulls;
     216              :         int                *nelems;
     217              :         FmgrInfo        proc;
     218              :         FmgrInfo        transform_proc;
     219              : } plperl_array_info;
     220              : 
     221              : /**********************************************************************
     222              :  * Global data
     223              :  **********************************************************************/
     224              : 
     225              : static HTAB *plperl_interp_hash = NULL;
     226              : static HTAB *plperl_proc_hash = NULL;
     227              : static plperl_interp_desc *plperl_active_interp = NULL;
     228              : 
     229              : /* If we have an unassigned "held" interpreter, it's stored here */
     230              : static PerlInterpreter *plperl_held_interp = NULL;
     231              : 
     232              : /* GUC variables */
     233              : static bool plperl_use_strict = false;
     234              : static char *plperl_on_init = NULL;
     235              : static char *plperl_on_plperl_init = NULL;
     236              : static char *plperl_on_plperlu_init = NULL;
     237              : 
     238              : static bool plperl_ending = false;
     239              : static OP  *(*pp_require_orig) (pTHX) = NULL;
     240              : static char plperl_opmask[MAXO];
     241              : 
     242              : /* this is saved and restored by plperl_call_handler */
     243              : static plperl_call_data *current_call_data = NULL;
     244              : 
     245              : /**********************************************************************
     246              :  * Forward declarations
     247              :  **********************************************************************/
     248              : 
     249              : static PerlInterpreter *plperl_init_interp(void);
     250              : static void plperl_destroy_interp(PerlInterpreter **);
     251              : static void plperl_fini(int code, Datum arg);
     252              : static void set_interp_require(bool trusted);
     253              : 
     254              : static Datum plperl_func_handler(PG_FUNCTION_ARGS);
     255              : static Datum plperl_trigger_handler(PG_FUNCTION_ARGS);
     256              : static void plperl_event_trigger_handler(PG_FUNCTION_ARGS);
     257              : 
     258              : static void free_plperl_function(plperl_proc_desc *prodesc);
     259              : 
     260              : static plperl_proc_desc *compile_plperl_function(Oid fn_oid,
     261              :                                                                                                  bool is_trigger,
     262              :                                                                                                  bool is_event_trigger);
     263              : 
     264              : static SV  *plperl_hash_from_tuple(HeapTuple tuple, TupleDesc tupdesc, bool include_generated);
     265              : static SV  *plperl_hash_from_datum(Datum attr);
     266              : static void check_spi_usage_allowed(void);
     267              : static SV  *plperl_ref_from_pg_array(Datum arg, Oid typid);
     268              : static SV  *split_array(plperl_array_info *info, int first, int last, int nest);
     269              : static SV  *make_array_ref(plperl_array_info *info, int first, int last);
     270              : static SV  *get_perl_array_ref(SV *sv);
     271              : static Datum plperl_sv_to_datum(SV *sv, Oid typid, int32 typmod,
     272              :                                                                 FunctionCallInfo fcinfo,
     273              :                                                                 FmgrInfo *finfo, Oid typioparam,
     274              :                                                                 bool *isnull);
     275              : static void _sv_to_datum_finfo(Oid typid, FmgrInfo *finfo, Oid *typioparam);
     276              : static Datum plperl_array_to_datum(SV *src, Oid typid, int32 typmod);
     277              : static void array_to_datum_internal(AV *av, ArrayBuildState **astatep,
     278              :                                                                         int *ndims, int *dims, int cur_depth,
     279              :                                                                         Oid elemtypid, int32 typmod,
     280              :                                                                         FmgrInfo *finfo, Oid typioparam);
     281              : static Datum plperl_hash_to_datum(SV *src, TupleDesc td);
     282              : 
     283              : static void plperl_init_shared_libs(pTHX);
     284              : static void plperl_trusted_init(void);
     285              : static void plperl_untrusted_init(void);
     286              : static HV  *plperl_spi_execute_fetch_result(SPITupleTable *, uint64, int);
     287              : static void plperl_return_next_internal(SV *sv);
     288              : static char *hek2cstr(HE *he);
     289              : static SV **hv_store_string(HV *hv, const char *key, SV *val);
     290              : static SV **hv_fetch_string(HV *hv, const char *key);
     291              : static void plperl_create_sub(plperl_proc_desc *desc, const char *s, Oid fn_oid);
     292              : static SV  *plperl_call_perl_func(plperl_proc_desc *desc,
     293              :                                                                   FunctionCallInfo fcinfo);
     294              : static void plperl_compile_callback(void *arg);
     295              : static void plperl_exec_callback(void *arg);
     296              : static void plperl_inline_callback(void *arg);
     297              : static char *strip_trailing_ws(const char *msg);
     298              : static OP  *pp_require_safe(pTHX);
     299              : static void activate_interpreter(plperl_interp_desc *interp_desc);
     300              : 
     301              : #if defined(WIN32) && PERL_VERSION_LT(5, 28, 0)
     302              : static char *setlocale_perl(int category, char *locale);
     303              : #else
     304              : #define setlocale_perl(a,b)  Perl_setlocale(a,b)
     305              : #endif                                                  /* defined(WIN32) && PERL_VERSION_LT(5, 28, 0) */
     306              : 
     307              : /*
     308              :  * Decrement the refcount of the given SV within the active Perl interpreter
     309              :  *
     310              :  * This is handy because it reloads the active-interpreter pointer, saving
     311              :  * some notation in callers that switch the active interpreter.
     312              :  */
     313              : static inline void
     314            0 : SvREFCNT_dec_current(SV *sv)
     315              : {
     316            0 :         dTHX;
     317              : 
     318            0 :         SvREFCNT_dec(sv);
     319            0 : }
     320              : 
     321              : /*
     322              :  * convert a HE (hash entry) key to a cstr in the current database encoding
     323              :  */
     324              : static char *
     325            0 : hek2cstr(HE *he)
     326              : {
     327            0 :         dTHX;
     328            0 :         char       *ret;
     329            0 :         SV                 *sv;
     330              : 
     331              :         /*
     332              :          * HeSVKEY_force will return a temporary mortal SV*, so we need to make
     333              :          * sure to free it with ENTER/SAVE/FREE/LEAVE
     334              :          */
     335            0 :         ENTER;
     336            0 :         SAVETMPS;
     337              : 
     338              :         /*-------------------------
     339              :          * Unfortunately, while HeUTF8 is true for most things > 256, for values
     340              :          * 128..255 it's not, but perl will treat them as unicode code points if
     341              :          * the utf8 flag is not set ( see The "Unicode Bug" in perldoc perlunicode
     342              :          * for more)
     343              :          *
     344              :          * So if we did the expected:
     345              :          *        if (HeUTF8(he))
     346              :          *                utf_u2e(key...);
     347              :          *        else // must be ascii
     348              :          *                return HePV(he);
     349              :          * we won't match columns with codepoints from 128..255
     350              :          *
     351              :          * For a more concrete example given a column with the name of the unicode
     352              :          * codepoint U+00ae (registered sign) and a UTF8 database and the perl
     353              :          * return_next { "\N{U+00ae}=>'text } would always fail as heUTF8 returns
     354              :          * 0 and HePV() would give us a char * with 1 byte contains the decimal
     355              :          * value 174
     356              :          *
     357              :          * Perl has the brains to know when it should utf8 encode 174 properly, so
     358              :          * here we force it into an SV so that perl will figure it out and do the
     359              :          * right thing
     360              :          *-------------------------
     361              :          */
     362              : 
     363            0 :         sv = HeSVKEY_force(he);
     364            0 :         if (HeUTF8(he))
     365            0 :                 SvUTF8_on(sv);
     366            0 :         ret = sv2cstr(sv);
     367              : 
     368              :         /* free sv */
     369            0 :         FREETMPS;
     370            0 :         LEAVE;
     371              : 
     372            0 :         return ret;
     373            0 : }
     374              : 
     375              : 
     376              : /*
     377              :  * _PG_init()                   - library load-time initialization
     378              :  *
     379              :  * DO NOT make this static nor change its name!
     380              :  */
     381              : void
     382            0 : _PG_init(void)
     383              : {
     384              :         /*
     385              :          * Be sure we do initialization only once.
     386              :          *
     387              :          * If initialization fails due to, e.g., plperl_init_interp() throwing an
     388              :          * exception, then we'll return here on the next usage and the user will
     389              :          * get a rather cryptic: ERROR:  attempt to redefine parameter
     390              :          * "plperl.use_strict"
     391              :          */
     392              :         static bool inited = false;
     393            0 :         HASHCTL         hash_ctl;
     394              : 
     395            0 :         if (inited)
     396            0 :                 return;
     397              : 
     398              :         /*
     399              :          * Support localized messages.
     400              :          */
     401            0 :         pg_bindtextdomain(TEXTDOMAIN);
     402              : 
     403              :         /*
     404              :          * Initialize plperl's GUCs.
     405              :          */
     406            0 :         DefineCustomBoolVariable("plperl.use_strict",
     407              :                                                          gettext_noop("If true, trusted and untrusted Perl code will be compiled in strict mode."),
     408              :                                                          NULL,
     409              :                                                          &plperl_use_strict,
     410              :                                                          false,
     411              :                                                          PGC_USERSET, 0,
     412              :                                                          NULL, NULL, NULL);
     413              : 
     414              :         /*
     415              :          * plperl.on_init is marked PGC_SIGHUP to support the idea that it might
     416              :          * be executed in the postmaster (if plperl is loaded into the postmaster
     417              :          * via shared_preload_libraries).  This isn't really right either way,
     418              :          * though.
     419              :          */
     420            0 :         DefineCustomStringVariable("plperl.on_init",
     421              :                                                            gettext_noop("Perl initialization code to execute when a Perl interpreter is initialized."),
     422              :                                                            NULL,
     423              :                                                            &plperl_on_init,
     424              :                                                            NULL,
     425              :                                                            PGC_SIGHUP, 0,
     426              :                                                            NULL, NULL, NULL);
     427              : 
     428              :         /*
     429              :          * plperl.on_plperl_init is marked PGC_SUSET to avoid issues whereby a
     430              :          * user who might not even have USAGE privilege on the plperl language
     431              :          * could nonetheless use SET plperl.on_plperl_init='...' to influence the
     432              :          * behaviour of any existing plperl function that they can execute (which
     433              :          * might be SECURITY DEFINER, leading to a privilege escalation).  See
     434              :          * http://archives.postgresql.org/pgsql-hackers/2010-02/msg00281.php and
     435              :          * the overall thread.
     436              :          *
     437              :          * Note that because plperl.use_strict is USERSET, a nefarious user could
     438              :          * set it to be applied against other people's functions.  This is judged
     439              :          * OK since the worst result would be an error.  Your code oughta pass
     440              :          * use_strict anyway ;-)
     441              :          */
     442            0 :         DefineCustomStringVariable("plperl.on_plperl_init",
     443              :                                                            gettext_noop("Perl initialization code to execute once when plperl is first used."),
     444              :                                                            NULL,
     445              :                                                            &plperl_on_plperl_init,
     446              :                                                            NULL,
     447              :                                                            PGC_SUSET, 0,
     448              :                                                            NULL, NULL, NULL);
     449              : 
     450            0 :         DefineCustomStringVariable("plperl.on_plperlu_init",
     451              :                                                            gettext_noop("Perl initialization code to execute once when plperlu is first used."),
     452              :                                                            NULL,
     453              :                                                            &plperl_on_plperlu_init,
     454              :                                                            NULL,
     455              :                                                            PGC_SUSET, 0,
     456              :                                                            NULL, NULL, NULL);
     457              : 
     458            0 :         MarkGUCPrefixReserved("plperl");
     459              : 
     460              :         /*
     461              :          * Create hash tables.
     462              :          */
     463            0 :         hash_ctl.keysize = sizeof(Oid);
     464            0 :         hash_ctl.entrysize = sizeof(plperl_interp_desc);
     465            0 :         plperl_interp_hash = hash_create("PL/Perl interpreters",
     466              :                                                                          8,
     467              :                                                                          &hash_ctl,
     468              :                                                                          HASH_ELEM | HASH_BLOBS);
     469              : 
     470            0 :         hash_ctl.keysize = sizeof(plperl_proc_key);
     471            0 :         hash_ctl.entrysize = sizeof(plperl_proc_ptr);
     472            0 :         plperl_proc_hash = hash_create("PL/Perl procedures",
     473              :                                                                    32,
     474              :                                                                    &hash_ctl,
     475              :                                                                    HASH_ELEM | HASH_BLOBS);
     476              : 
     477              :         /*
     478              :          * Save the default opmask.
     479              :          */
     480            0 :         PLPERL_SET_OPMASK(plperl_opmask);
     481              : 
     482              :         /*
     483              :          * Create the first Perl interpreter, but only partially initialize it.
     484              :          */
     485            0 :         plperl_held_interp = plperl_init_interp();
     486              : 
     487            0 :         inited = true;
     488            0 : }
     489              : 
     490              : 
     491              : static void
     492            0 : set_interp_require(bool trusted)
     493              : {
     494            0 :         if (trusted)
     495              :         {
     496            0 :                 PL_ppaddr[OP_REQUIRE] = pp_require_safe;
     497            0 :                 PL_ppaddr[OP_DOFILE] = pp_require_safe;
     498            0 :         }
     499              :         else
     500              :         {
     501            0 :                 PL_ppaddr[OP_REQUIRE] = pp_require_orig;
     502            0 :                 PL_ppaddr[OP_DOFILE] = pp_require_orig;
     503              :         }
     504            0 : }
     505              : 
     506              : /*
     507              :  * Cleanup perl interpreters, including running END blocks.
     508              :  * Does not fully undo the actions of _PG_init() nor make it callable again.
     509              :  */
     510              : static void
     511            0 : plperl_fini(int code, Datum arg)
     512              : {
     513            0 :         HASH_SEQ_STATUS hash_seq;
     514            0 :         plperl_interp_desc *interp_desc;
     515              : 
     516            0 :         elog(DEBUG3, "plperl_fini");
     517              : 
     518              :         /*
     519              :          * Indicate that perl is terminating. Disables use of spi_* functions when
     520              :          * running END/DESTROY code. See check_spi_usage_allowed(). Could be
     521              :          * enabled in future, with care, using a transaction
     522              :          * http://archives.postgresql.org/pgsql-hackers/2010-01/msg02743.php
     523              :          */
     524            0 :         plperl_ending = true;
     525              : 
     526              :         /* Only perform perl cleanup if we're exiting cleanly */
     527            0 :         if (code)
     528              :         {
     529            0 :                 elog(DEBUG3, "plperl_fini: skipped");
     530            0 :                 return;
     531              :         }
     532              : 
     533              :         /* Zap the "held" interpreter, if we still have it */
     534            0 :         plperl_destroy_interp(&plperl_held_interp);
     535              : 
     536              :         /* Zap any fully-initialized interpreters */
     537            0 :         hash_seq_init(&hash_seq, plperl_interp_hash);
     538            0 :         while ((interp_desc = hash_seq_search(&hash_seq)) != NULL)
     539              :         {
     540            0 :                 if (interp_desc->interp)
     541              :                 {
     542            0 :                         activate_interpreter(interp_desc);
     543            0 :                         plperl_destroy_interp(&interp_desc->interp);
     544            0 :                 }
     545              :         }
     546              : 
     547            0 :         elog(DEBUG3, "plperl_fini: done");
     548            0 : }
     549              : 
     550              : 
     551              : /*
     552              :  * Select and activate an appropriate Perl interpreter.
     553              :  */
     554              : static void
     555            0 : select_perl_context(bool trusted)
     556              : {
     557            0 :         Oid                     user_id;
     558            0 :         plperl_interp_desc *interp_desc;
     559            0 :         bool            found;
     560            0 :         PerlInterpreter *interp = NULL;
     561              : 
     562              :         /* Find or create the interpreter hashtable entry for this userid */
     563            0 :         if (trusted)
     564            0 :                 user_id = GetUserId();
     565              :         else
     566            0 :                 user_id = InvalidOid;
     567              : 
     568            0 :         interp_desc = hash_search(plperl_interp_hash, &user_id,
     569              :                                                           HASH_ENTER,
     570              :                                                           &found);
     571            0 :         if (!found)
     572              :         {
     573              :                 /* Initialize newly-created hashtable entry */
     574            0 :                 interp_desc->interp = NULL;
     575            0 :                 interp_desc->query_hash = NULL;
     576            0 :         }
     577              : 
     578              :         /* Make sure we have a query_hash for this interpreter */
     579            0 :         if (interp_desc->query_hash == NULL)
     580              :         {
     581            0 :                 HASHCTL         hash_ctl;
     582              : 
     583            0 :                 hash_ctl.keysize = NAMEDATALEN;
     584            0 :                 hash_ctl.entrysize = sizeof(plperl_query_entry);
     585            0 :                 interp_desc->query_hash = hash_create("PL/Perl queries",
     586              :                                                                                           32,
     587              :                                                                                           &hash_ctl,
     588              :                                                                                           HASH_ELEM | HASH_STRINGS);
     589            0 :         }
     590              : 
     591              :         /*
     592              :          * Quick exit if already have an interpreter
     593              :          */
     594            0 :         if (interp_desc->interp)
     595              :         {
     596            0 :                 activate_interpreter(interp_desc);
     597            0 :                 return;
     598              :         }
     599              : 
     600              :         /*
     601              :          * adopt held interp if free, else create new one if possible
     602              :          */
     603            0 :         if (plperl_held_interp != NULL)
     604              :         {
     605              :                 /* first actual use of a perl interpreter */
     606            0 :                 interp = plperl_held_interp;
     607              : 
     608              :                 /*
     609              :                  * Reset the plperl_held_interp pointer first; if we fail during init
     610              :                  * we don't want to try again with the partially-initialized interp.
     611              :                  */
     612            0 :                 plperl_held_interp = NULL;
     613              : 
     614            0 :                 if (trusted)
     615            0 :                         plperl_trusted_init();
     616              :                 else
     617            0 :                         plperl_untrusted_init();
     618              : 
     619              :                 /* successfully initialized, so arrange for cleanup */
     620            0 :                 on_proc_exit(plperl_fini, 0);
     621            0 :         }
     622              :         else
     623              :         {
     624              : #ifdef MULTIPLICITY
     625              : 
     626              :                 /*
     627              :                  * plperl_init_interp will change Perl's idea of the active
     628              :                  * interpreter.  Reset plperl_active_interp temporarily, so that if we
     629              :                  * hit an error partway through here, we'll make sure to switch back
     630              :                  * to a non-broken interpreter before running any other Perl
     631              :                  * functions.
     632              :                  */
     633            0 :                 plperl_active_interp = NULL;
     634              : 
     635              :                 /* Now build the new interpreter */
     636            0 :                 interp = plperl_init_interp();
     637              : 
     638            0 :                 if (trusted)
     639            0 :                         plperl_trusted_init();
     640              :                 else
     641            0 :                         plperl_untrusted_init();
     642              : #else
     643              :                 ereport(ERROR,
     644              :                                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
     645              :                                  errmsg("cannot allocate multiple Perl interpreters on this platform")));
     646              : #endif
     647              :         }
     648              : 
     649            0 :         set_interp_require(trusted);
     650              : 
     651              :         /*
     652              :          * Since the timing of first use of PL/Perl can't be predicted, any
     653              :          * database interaction during initialization is problematic. Including,
     654              :          * but not limited to, security definer issues. So we only enable access
     655              :          * to the database AFTER on_*_init code has run. See
     656              :          * http://archives.postgresql.org/pgsql-hackers/2010-01/msg02669.php
     657              :          */
     658              :         {
     659            0 :                 dTHX;
     660              : 
     661            0 :                 newXS("PostgreSQL::InServer::SPI::bootstrap",
     662              :                           boot_PostgreSQL__InServer__SPI, __FILE__);
     663              : 
     664            0 :                 eval_pv("PostgreSQL::InServer::SPI::bootstrap()", FALSE);
     665            0 :                 if (SvTRUE(ERRSV))
     666            0 :                         ereport(ERROR,
     667              :                                         (errcode(ERRCODE_EXTERNAL_ROUTINE_EXCEPTION),
     668              :                                          errmsg("%s", strip_trailing_ws(sv2cstr(ERRSV))),
     669              :                                          errcontext("while executing PostgreSQL::InServer::SPI::bootstrap")));
     670            0 :         }
     671              : 
     672              :         /* Fully initialized, so mark the hashtable entry valid */
     673            0 :         interp_desc->interp = interp;
     674              : 
     675              :         /* And mark this as the active interpreter */
     676            0 :         plperl_active_interp = interp_desc;
     677            0 : }
     678              : 
     679              : /*
     680              :  * Make the specified interpreter the active one
     681              :  *
     682              :  * A call with NULL does nothing.  This is so that "restoring" to a previously
     683              :  * null state of plperl_active_interp doesn't result in useless thrashing.
     684              :  */
     685              : static void
     686            0 : activate_interpreter(plperl_interp_desc *interp_desc)
     687              : {
     688            0 :         if (interp_desc && plperl_active_interp != interp_desc)
     689              :         {
     690            0 :                 Assert(interp_desc->interp);
     691            0 :                 PERL_SET_CONTEXT(interp_desc->interp);
     692              :                 /* trusted iff user_id isn't InvalidOid */
     693            0 :                 set_interp_require(OidIsValid(interp_desc->user_id));
     694            0 :                 plperl_active_interp = interp_desc;
     695            0 :         }
     696            0 : }
     697              : 
     698              : /*
     699              :  * Create a new Perl interpreter.
     700              :  *
     701              :  * We initialize the interpreter as far as we can without knowing whether
     702              :  * it will become a trusted or untrusted interpreter; in particular, the
     703              :  * plperl.on_init code will get executed.  Later, either plperl_trusted_init
     704              :  * or plperl_untrusted_init must be called to complete the initialization.
     705              :  */
     706              : static PerlInterpreter *
     707            0 : plperl_init_interp(void)
     708              : {
     709            0 :         PerlInterpreter *plperl;
     710              : 
     711              :         static char *embedding[3 + 2] = {
     712              :                 "", "-e", PLC_PERLBOOT
     713              :         };
     714            0 :         int                     nargs = 3;
     715              : 
     716              : #ifdef WIN32
     717              : 
     718              :         /*
     719              :          * The perl library on startup does horrible things like call
     720              :          * setlocale(LC_ALL,""). We have protected against that on most platforms
     721              :          * by setting the environment appropriately. However, on Windows,
     722              :          * setlocale() does not consult the environment, so we need to save the
     723              :          * existing locale settings before perl has a chance to mangle them and
     724              :          * restore them after its dirty deeds are done.
     725              :          *
     726              :          * MSDN ref:
     727              :          * http://msdn.microsoft.com/library/en-us/vclib/html/_crt_locale.asp
     728              :          *
     729              :          * It appears that we only need to do this on interpreter startup, and
     730              :          * subsequent calls to the interpreter don't mess with the locale
     731              :          * settings.
     732              :          *
     733              :          * We restore them using setlocale_perl(), defined below, so that Perl
     734              :          * doesn't have a different idea of the locale from Postgres.
     735              :          *
     736              :          */
     737              : 
     738              :         char       *loc;
     739              :         char       *save_collate,
     740              :                            *save_ctype,
     741              :                            *save_monetary,
     742              :                            *save_numeric,
     743              :                            *save_time;
     744              : 
     745              :         loc = setlocale(LC_COLLATE, NULL);
     746              :         save_collate = loc ? pstrdup(loc) : NULL;
     747              :         loc = setlocale(LC_CTYPE, NULL);
     748              :         save_ctype = loc ? pstrdup(loc) : NULL;
     749              :         loc = setlocale(LC_MONETARY, NULL);
     750              :         save_monetary = loc ? pstrdup(loc) : NULL;
     751              :         loc = setlocale(LC_NUMERIC, NULL);
     752              :         save_numeric = loc ? pstrdup(loc) : NULL;
     753              :         loc = setlocale(LC_TIME, NULL);
     754              :         save_time = loc ? pstrdup(loc) : NULL;
     755              : 
     756              : #define PLPERL_RESTORE_LOCALE(name, saved) \
     757              :         STMT_START { \
     758              :                 if (saved != NULL) { setlocale_perl(name, saved); pfree(saved); } \
     759              :         } STMT_END
     760              : #endif                                                  /* WIN32 */
     761              : 
     762            0 :         if (plperl_on_init && *plperl_on_init)
     763              :         {
     764            0 :                 embedding[nargs++] = "-e";
     765            0 :                 embedding[nargs++] = plperl_on_init;
     766            0 :         }
     767              : 
     768              :         /*
     769              :          * The perl API docs state that PERL_SYS_INIT3 should be called before
     770              :          * allocating interpreters. Unfortunately, on some platforms this fails in
     771              :          * the Perl_do_taint() routine, which is called when the platform is using
     772              :          * the system's malloc() instead of perl's own. Other platforms, notably
     773              :          * Windows, fail if PERL_SYS_INIT3 is not called. So we call it if it's
     774              :          * available, unless perl is using the system malloc(), which is true when
     775              :          * MYMALLOC is set.
     776              :          */
     777              : #if defined(PERL_SYS_INIT3) && !defined(MYMALLOC)
     778              :         {
     779              :                 static int      perl_sys_init_done;
     780              : 
     781              :                 /* only call this the first time through, as per perlembed man page */
     782            0 :                 if (!perl_sys_init_done)
     783              :                 {
     784            0 :                         char       *dummy_env[1] = {NULL};
     785              : 
     786            0 :                         PERL_SYS_INIT3(&nargs, (char ***) &embedding, (char ***) &dummy_env);
     787              : 
     788              :                         /*
     789              :                          * For unclear reasons, PERL_SYS_INIT3 sets the SIGFPE handler to
     790              :                          * SIG_IGN.  Aside from being extremely unfriendly behavior for a
     791              :                          * library, this is dumb on the grounds that the results of a
     792              :                          * SIGFPE in this state are undefined according to POSIX, and in
     793              :                          * fact you get a forced process kill at least on Linux.  Hence,
     794              :                          * restore the SIGFPE handler to the backend's standard setting.
     795              :                          * (See Perl bug 114574 for more information.)
     796              :                          */
     797            0 :                         pqsignal(SIGFPE, FloatExceptionHandler);
     798              : 
     799            0 :                         perl_sys_init_done = 1;
     800              :                         /* quiet warning if PERL_SYS_INIT3 doesn't use the third argument */
     801            0 :                         dummy_env[0] = NULL;
     802            0 :                 }
     803              :         }
     804              : #endif
     805              : 
     806            0 :         plperl = perl_alloc();
     807            0 :         if (!plperl)
     808            0 :                 elog(ERROR, "could not allocate Perl interpreter");
     809              : 
     810            0 :         PERL_SET_CONTEXT(plperl);
     811            0 :         perl_construct(plperl);
     812              : 
     813              :         /*
     814              :          * Run END blocks in perl_destruct instead of perl_run.  Note that dTHX
     815              :          * loads up a pointer to the current interpreter, so we have to postpone
     816              :          * it to here rather than put it at the function head.
     817              :          */
     818              :         {
     819            0 :                 dTHX;
     820              : 
     821            0 :                 PL_exit_flags |= PERL_EXIT_DESTRUCT_END;
     822              : 
     823              :                 /*
     824              :                  * Record the original function for the 'require' and 'dofile'
     825              :                  * opcodes.  (They share the same implementation.)  Ensure it's used
     826              :                  * for new interpreters.
     827              :                  */
     828            0 :                 if (!pp_require_orig)
     829            0 :                         pp_require_orig = PL_ppaddr[OP_REQUIRE];
     830              :                 else
     831              :                 {
     832            0 :                         PL_ppaddr[OP_REQUIRE] = pp_require_orig;
     833            0 :                         PL_ppaddr[OP_DOFILE] = pp_require_orig;
     834              :                 }
     835              : 
     836              : #ifdef PLPERL_ENABLE_OPMASK_EARLY
     837              : 
     838              :                 /*
     839              :                  * For regression testing to prove that the PLC_PERLBOOT and
     840              :                  * PLC_TRUSTED code doesn't even compile any unsafe ops.  In future
     841              :                  * there may be a valid need for them to do so, in which case this
     842              :                  * could be softened (perhaps moved to plperl_trusted_init()) or
     843              :                  * removed.
     844              :                  */
     845              :                 PL_op_mask = plperl_opmask;
     846              : #endif
     847              : 
     848            0 :                 if (perl_parse(plperl, plperl_init_shared_libs,
     849            0 :                                            nargs, embedding, NULL) != 0)
     850            0 :                         ereport(ERROR,
     851              :                                         (errcode(ERRCODE_EXTERNAL_ROUTINE_EXCEPTION),
     852              :                                          errmsg("%s", strip_trailing_ws(sv2cstr(ERRSV))),
     853              :                                          errcontext("while parsing Perl initialization")));
     854              : 
     855            0 :                 if (perl_run(plperl) != 0)
     856            0 :                         ereport(ERROR,
     857              :                                         (errcode(ERRCODE_EXTERNAL_ROUTINE_EXCEPTION),
     858              :                                          errmsg("%s", strip_trailing_ws(sv2cstr(ERRSV))),
     859              :                                          errcontext("while running Perl initialization")));
     860              : 
     861              : #ifdef PLPERL_RESTORE_LOCALE
     862              :                 PLPERL_RESTORE_LOCALE(LC_COLLATE, save_collate);
     863              :                 PLPERL_RESTORE_LOCALE(LC_CTYPE, save_ctype);
     864              :                 PLPERL_RESTORE_LOCALE(LC_MONETARY, save_monetary);
     865              :                 PLPERL_RESTORE_LOCALE(LC_NUMERIC, save_numeric);
     866              :                 PLPERL_RESTORE_LOCALE(LC_TIME, save_time);
     867              : #endif
     868            0 :         }
     869              : 
     870            0 :         return plperl;
     871            0 : }
     872              : 
     873              : 
     874              : /*
     875              :  * Our safe implementation of the require opcode.
     876              :  * This is safe because it's completely unable to load any code.
     877              :  * If the requested file/module has already been loaded it'll return true.
     878              :  * If not, it'll die.
     879              :  * So now "use Foo;" will work iff Foo has already been loaded.
     880              :  */
     881              : static OP  *
     882            0 : pp_require_safe(pTHX)
     883              : {
     884              :         dVAR;
     885            0 :         dSP;
     886            0 :         SV                 *sv,
     887              :                           **svp;
     888            0 :         char       *name;
     889            0 :         STRLEN          len;
     890              : 
     891            0 :         sv = POPs;
     892            0 :         name = SvPV(sv, len);
     893            0 :         if (!(name && len > 0 && *name))
     894            0 :                 RETPUSHNO;
     895              : 
     896            0 :         svp = hv_fetch(GvHVn(PL_incgv), name, len, 0);
     897            0 :         if (svp && *svp != &PL_sv_undef)
     898            0 :                 RETPUSHYES;
     899              : 
     900            0 :         DIE(aTHX_ "Unable to load %s into plperl", name);
     901              : 
     902              :         /*
     903              :          * In most Perl versions, DIE() expands to a return statement, so the next
     904              :          * line is not necessary.  But in versions between but not including
     905              :          * 5.11.1 and 5.13.3 it does not, so the next line is necessary to avoid a
     906              :          * "control reaches end of non-void function" warning from gcc.  Other
     907              :          * compilers such as Solaris Studio will, however, issue a "statement not
     908              :          * reached" warning instead.
     909              :          */
     910              :         return NULL;
     911            0 : }
     912              : 
     913              : 
     914              : /*
     915              :  * Destroy one Perl interpreter ... actually we just run END blocks.
     916              :  *
     917              :  * Caller must have ensured this interpreter is the active one.
     918              :  */
     919              : static void
     920            0 : plperl_destroy_interp(PerlInterpreter **interp)
     921              : {
     922            0 :         if (interp && *interp)
     923              :         {
     924              :                 /*
     925              :                  * Only a very minimal destruction is performed: - just call END
     926              :                  * blocks.
     927              :                  *
     928              :                  * We could call perl_destruct() but we'd need to audit its actions
     929              :                  * very carefully and work-around any that impact us. (Calling
     930              :                  * sv_clean_objs() isn't an option because it's not part of perl's
     931              :                  * public API so isn't portably available.) Meanwhile END blocks can
     932              :                  * be used to perform manual cleanup.
     933              :                  */
     934            0 :                 dTHX;
     935              : 
     936              :                 /* Run END blocks - based on perl's perl_destruct() */
     937            0 :                 if (PL_exit_flags & PERL_EXIT_DESTRUCT_END)
     938              :                 {
     939            0 :                         dJMPENV;
     940            0 :                         int                     x = 0;
     941              : 
     942            0 :                         JMPENV_PUSH(x);
     943              :                         PERL_UNUSED_VAR(x);
     944            0 :                         if (PL_endav && !PL_minus_c)
     945            0 :                                 call_list(PL_scopestack_ix, PL_endav);
     946            0 :                         JMPENV_POP;
     947            0 :                 }
     948            0 :                 LEAVE;
     949            0 :                 FREETMPS;
     950              : 
     951            0 :                 *interp = NULL;
     952            0 :         }
     953            0 : }
     954              : 
     955              : /*
     956              :  * Initialize the current Perl interpreter as a trusted interp
     957              :  */
     958              : static void
     959            0 : plperl_trusted_init(void)
     960              : {
     961            0 :         dTHX;
     962            0 :         HV                 *stash;
     963            0 :         SV                 *sv;
     964            0 :         char       *key;
     965            0 :         I32                     klen;
     966              : 
     967              :         /* use original require while we set up */
     968            0 :         PL_ppaddr[OP_REQUIRE] = pp_require_orig;
     969            0 :         PL_ppaddr[OP_DOFILE] = pp_require_orig;
     970              : 
     971            0 :         eval_pv(PLC_TRUSTED, FALSE);
     972            0 :         if (SvTRUE(ERRSV))
     973            0 :                 ereport(ERROR,
     974              :                                 (errcode(ERRCODE_EXTERNAL_ROUTINE_EXCEPTION),
     975              :                                  errmsg("%s", strip_trailing_ws(sv2cstr(ERRSV))),
     976              :                                  errcontext("while executing PLC_TRUSTED")));
     977              : 
     978              :         /*
     979              :          * Force loading of utf8 module now to prevent errors that can arise from
     980              :          * the regex code later trying to load utf8 modules. See
     981              :          * http://rt.perl.org/rt3/Ticket/Display.html?id=47576
     982              :          */
     983            0 :         eval_pv("my $a=chr(0x100); return $a =~ /\\xa9/i", FALSE);
     984            0 :         if (SvTRUE(ERRSV))
     985            0 :                 ereport(ERROR,
     986              :                                 (errcode(ERRCODE_EXTERNAL_ROUTINE_EXCEPTION),
     987              :                                  errmsg("%s", strip_trailing_ws(sv2cstr(ERRSV))),
     988              :                                  errcontext("while executing utf8fix")));
     989              : 
     990              :         /*
     991              :          * Lock down the interpreter
     992              :          */
     993              : 
     994              :         /* switch to the safe require/dofile opcode for future code */
     995            0 :         PL_ppaddr[OP_REQUIRE] = pp_require_safe;
     996            0 :         PL_ppaddr[OP_DOFILE] = pp_require_safe;
     997              : 
     998              :         /*
     999              :          * prevent (any more) unsafe opcodes being compiled PL_op_mask is per
    1000              :          * interpreter, so this only needs to be set once
    1001              :          */
    1002            0 :         PL_op_mask = plperl_opmask;
    1003              : 
    1004              :         /* delete the DynaLoader:: namespace so extensions can't be loaded */
    1005            0 :         stash = gv_stashpv("DynaLoader", GV_ADDWARN);
    1006            0 :         hv_iterinit(stash);
    1007            0 :         while ((sv = hv_iternextsv(stash, &key, &klen)))
    1008              :         {
    1009            0 :                 if (!isGV_with_GP(sv) || !GvCV(sv))
    1010            0 :                         continue;
    1011            0 :                 SvREFCNT_dec(GvCV(sv)); /* free the CV */
    1012            0 :                 GvCV_set(sv, NULL);             /* prevent call via GV */
    1013              :         }
    1014            0 :         hv_clear(stash);
    1015              : 
    1016              :         /* invalidate assorted caches */
    1017            0 :         ++PL_sub_generation;
    1018            0 :         hv_clear(PL_stashcache);
    1019              : 
    1020              :         /*
    1021              :          * Execute plperl.on_plperl_init in the locked-down interpreter
    1022              :          */
    1023            0 :         if (plperl_on_plperl_init && *plperl_on_plperl_init)
    1024              :         {
    1025            0 :                 eval_pv(plperl_on_plperl_init, FALSE);
    1026              :                 /* XXX need to find a way to determine a better errcode here */
    1027            0 :                 if (SvTRUE(ERRSV))
    1028            0 :                         ereport(ERROR,
    1029              :                                         (errcode(ERRCODE_EXTERNAL_ROUTINE_EXCEPTION),
    1030              :                                          errmsg("%s", strip_trailing_ws(sv2cstr(ERRSV))),
    1031              :                                          errcontext("while executing plperl.on_plperl_init")));
    1032            0 :         }
    1033            0 : }
    1034              : 
    1035              : 
    1036              : /*
    1037              :  * Initialize the current Perl interpreter as an untrusted interp
    1038              :  */
    1039              : static void
    1040            0 : plperl_untrusted_init(void)
    1041              : {
    1042            0 :         dTHX;
    1043              : 
    1044              :         /*
    1045              :          * Nothing to do except execute plperl.on_plperlu_init
    1046              :          */
    1047            0 :         if (plperl_on_plperlu_init && *plperl_on_plperlu_init)
    1048              :         {
    1049            0 :                 eval_pv(plperl_on_plperlu_init, FALSE);
    1050            0 :                 if (SvTRUE(ERRSV))
    1051            0 :                         ereport(ERROR,
    1052              :                                         (errcode(ERRCODE_EXTERNAL_ROUTINE_EXCEPTION),
    1053              :                                          errmsg("%s", strip_trailing_ws(sv2cstr(ERRSV))),
    1054              :                                          errcontext("while executing plperl.on_plperlu_init")));
    1055            0 :         }
    1056            0 : }
    1057              : 
    1058              : 
    1059              : /*
    1060              :  * Perl likes to put a newline after its error messages; clean up such
    1061              :  */
    1062              : static char *
    1063            0 : strip_trailing_ws(const char *msg)
    1064              : {
    1065            0 :         char       *res = pstrdup(msg);
    1066            0 :         int                     len = strlen(res);
    1067              : 
    1068            0 :         while (len > 0 && isspace((unsigned char) res[len - 1]))
    1069            0 :                 res[--len] = '\0';
    1070            0 :         return res;
    1071            0 : }
    1072              : 
    1073              : 
    1074              : /* Build a tuple from a hash. */
    1075              : 
    1076              : static HeapTuple
    1077            0 : plperl_build_tuple_result(HV *perlhash, TupleDesc td)
    1078              : {
    1079            0 :         dTHX;
    1080            0 :         Datum      *values;
    1081            0 :         bool       *nulls;
    1082            0 :         HE                 *he;
    1083            0 :         HeapTuple       tup;
    1084              : 
    1085            0 :         values = palloc0_array(Datum, td->natts);
    1086            0 :         nulls = palloc_array(bool, td->natts);
    1087            0 :         memset(nulls, true, sizeof(bool) * td->natts);
    1088              : 
    1089            0 :         hv_iterinit(perlhash);
    1090            0 :         while ((he = hv_iternext(perlhash)))
    1091              :         {
    1092            0 :                 SV                 *val = HeVAL(he);
    1093            0 :                 char       *key = hek2cstr(he);
    1094            0 :                 int                     attn = SPI_fnumber(td, key);
    1095            0 :                 Form_pg_attribute attr = TupleDescAttr(td, attn - 1);
    1096              : 
    1097            0 :                 if (attn == SPI_ERROR_NOATTRIBUTE)
    1098            0 :                         ereport(ERROR,
    1099              :                                         (errcode(ERRCODE_UNDEFINED_COLUMN),
    1100              :                                          errmsg("Perl hash contains nonexistent column \"%s\"",
    1101              :                                                         key)));
    1102            0 :                 if (attn <= 0)
    1103            0 :                         ereport(ERROR,
    1104              :                                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    1105              :                                          errmsg("cannot set system attribute \"%s\"",
    1106              :                                                         key)));
    1107              : 
    1108            0 :                 values[attn - 1] = plperl_sv_to_datum(val,
    1109            0 :                                                                                           attr->atttypid,
    1110            0 :                                                                                           attr->atttypmod,
    1111              :                                                                                           NULL,
    1112              :                                                                                           NULL,
    1113              :                                                                                           InvalidOid,
    1114            0 :                                                                                           &nulls[attn - 1]);
    1115              : 
    1116            0 :                 pfree(key);
    1117            0 :         }
    1118            0 :         hv_iterinit(perlhash);
    1119              : 
    1120            0 :         tup = heap_form_tuple(td, values, nulls);
    1121            0 :         pfree(values);
    1122            0 :         pfree(nulls);
    1123            0 :         return tup;
    1124            0 : }
    1125              : 
    1126              : /* convert a hash reference to a datum */
    1127              : static Datum
    1128            0 : plperl_hash_to_datum(SV *src, TupleDesc td)
    1129              : {
    1130            0 :         HeapTuple       tup = plperl_build_tuple_result((HV *) SvRV(src), td);
    1131              : 
    1132            0 :         return HeapTupleGetDatum(tup);
    1133            0 : }
    1134              : 
    1135              : /*
    1136              :  * if we are an array ref return the reference. this is special in that if we
    1137              :  * are a PostgreSQL::InServer::ARRAY object we will return the 'magic' array.
    1138              :  */
    1139              : static SV  *
    1140            0 : get_perl_array_ref(SV *sv)
    1141              : {
    1142            0 :         dTHX;
    1143              : 
    1144            0 :         if (SvOK(sv) && SvROK(sv))
    1145              :         {
    1146            0 :                 if (SvTYPE(SvRV(sv)) == SVt_PVAV)
    1147            0 :                         return sv;
    1148            0 :                 else if (sv_isa(sv, "PostgreSQL::InServer::ARRAY"))
    1149              :                 {
    1150            0 :                         HV                 *hv = (HV *) SvRV(sv);
    1151            0 :                         SV                **sav = hv_fetch_string(hv, "array");
    1152              : 
    1153            0 :                         if (*sav && SvOK(*sav) && SvROK(*sav) &&
    1154            0 :                                 SvTYPE(SvRV(*sav)) == SVt_PVAV)
    1155            0 :                                 return *sav;
    1156              : 
    1157            0 :                         elog(ERROR, "could not get array reference from PostgreSQL::InServer::ARRAY object");
    1158            0 :                 }
    1159            0 :         }
    1160            0 :         return NULL;
    1161            0 : }
    1162              : 
    1163              : /*
    1164              :  * helper function for plperl_array_to_datum, recurses for multi-D arrays
    1165              :  *
    1166              :  * The ArrayBuildState is created only when we first find a scalar element;
    1167              :  * if we didn't do it like that, we'd need some other convention for knowing
    1168              :  * whether we'd already found any scalars (and thus the number of dimensions
    1169              :  * is frozen).
    1170              :  */
    1171              : static void
    1172            0 : array_to_datum_internal(AV *av, ArrayBuildState **astatep,
    1173              :                                                 int *ndims, int *dims, int cur_depth,
    1174              :                                                 Oid elemtypid, int32 typmod,
    1175              :                                                 FmgrInfo *finfo, Oid typioparam)
    1176              : {
    1177            0 :         dTHX;
    1178            0 :         int                     i;
    1179            0 :         int                     len = av_len(av) + 1;
    1180              : 
    1181            0 :         for (i = 0; i < len; i++)
    1182              :         {
    1183              :                 /* fetch the array element */
    1184            0 :                 SV                **svp = av_fetch(av, i, FALSE);
    1185              : 
    1186              :                 /* see if this element is an array, if so get that */
    1187            0 :                 SV                 *sav = svp ? get_perl_array_ref(*svp) : NULL;
    1188              : 
    1189              :                 /* multi-dimensional array? */
    1190            0 :                 if (sav)
    1191              :                 {
    1192            0 :                         AV                 *nav = (AV *) SvRV(sav);
    1193              : 
    1194              :                         /* set size when at first element in this level, else compare */
    1195            0 :                         if (i == 0 && *ndims == cur_depth)
    1196              :                         {
    1197              :                                 /* array after some scalars at same level? */
    1198            0 :                                 if (*astatep != NULL)
    1199            0 :                                         ereport(ERROR,
    1200              :                                                         (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
    1201              :                                                          errmsg("multidimensional arrays must have array expressions with matching dimensions")));
    1202              :                                 /* too many dimensions? */
    1203            0 :                                 if (cur_depth + 1 > MAXDIM)
    1204            0 :                                         ereport(ERROR,
    1205              :                                                         (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
    1206              :                                                          errmsg("number of array dimensions exceeds the maximum allowed (%d)",
    1207              :                                                                         MAXDIM)));
    1208              :                                 /* OK, add a dimension */
    1209            0 :                                 dims[*ndims] = av_len(nav) + 1;
    1210            0 :                                 (*ndims)++;
    1211            0 :                         }
    1212            0 :                         else if (cur_depth >= *ndims ||
    1213            0 :                                          av_len(nav) + 1 != dims[cur_depth])
    1214            0 :                                 ereport(ERROR,
    1215              :                                                 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
    1216              :                                                  errmsg("multidimensional arrays must have array expressions with matching dimensions")));
    1217              : 
    1218              :                         /* recurse to fetch elements of this sub-array */
    1219            0 :                         array_to_datum_internal(nav, astatep,
    1220            0 :                                                                         ndims, dims, cur_depth + 1,
    1221            0 :                                                                         elemtypid, typmod,
    1222            0 :                                                                         finfo, typioparam);
    1223            0 :                 }
    1224              :                 else
    1225              :                 {
    1226            0 :                         Datum           dat;
    1227            0 :                         bool            isnull;
    1228              : 
    1229              :                         /* scalar after some sub-arrays at same level? */
    1230            0 :                         if (*ndims != cur_depth)
    1231            0 :                                 ereport(ERROR,
    1232              :                                                 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
    1233              :                                                  errmsg("multidimensional arrays must have array expressions with matching dimensions")));
    1234              : 
    1235            0 :                         dat = plperl_sv_to_datum(svp ? *svp : NULL,
    1236            0 :                                                                          elemtypid,
    1237            0 :                                                                          typmod,
    1238              :                                                                          NULL,
    1239            0 :                                                                          finfo,
    1240            0 :                                                                          typioparam,
    1241              :                                                                          &isnull);
    1242              : 
    1243              :                         /* Create ArrayBuildState if we didn't already */
    1244            0 :                         if (*astatep == NULL)
    1245            0 :                                 *astatep = initArrayResult(elemtypid,
    1246            0 :                                                                                    CurrentMemoryContext, true);
    1247              : 
    1248              :                         /* ... and save the element value in it */
    1249            0 :                         (void) accumArrayResult(*astatep, dat, isnull,
    1250            0 :                                                                         elemtypid, CurrentMemoryContext);
    1251            0 :                 }
    1252            0 :         }
    1253            0 : }
    1254              : 
    1255              : /*
    1256              :  * convert perl array ref to a datum
    1257              :  */
    1258              : static Datum
    1259            0 : plperl_array_to_datum(SV *src, Oid typid, int32 typmod)
    1260              : {
    1261            0 :         dTHX;
    1262            0 :         AV                 *nav = (AV *) SvRV(src);
    1263            0 :         ArrayBuildState *astate = NULL;
    1264            0 :         Oid                     elemtypid;
    1265            0 :         FmgrInfo        finfo;
    1266            0 :         Oid                     typioparam;
    1267            0 :         int                     dims[MAXDIM];
    1268            0 :         int                     lbs[MAXDIM];
    1269            0 :         int                     ndims = 1;
    1270            0 :         int                     i;
    1271              : 
    1272            0 :         elemtypid = get_element_type(typid);
    1273            0 :         if (!elemtypid)
    1274            0 :                 ereport(ERROR,
    1275              :                                 (errcode(ERRCODE_DATATYPE_MISMATCH),
    1276              :                                  errmsg("cannot convert Perl array to non-array type %s",
    1277              :                                                 format_type_be(typid))));
    1278              : 
    1279            0 :         _sv_to_datum_finfo(elemtypid, &finfo, &typioparam);
    1280              : 
    1281            0 :         memset(dims, 0, sizeof(dims));
    1282            0 :         dims[0] = av_len(nav) + 1;
    1283              : 
    1284            0 :         array_to_datum_internal(nav, &astate,
    1285            0 :                                                         &ndims, dims, 1,
    1286            0 :                                                         elemtypid, typmod,
    1287            0 :                                                         &finfo, typioparam);
    1288              : 
    1289              :         /* ensure we get zero-D array for no inputs, as per PG convention */
    1290            0 :         if (astate == NULL)
    1291            0 :                 return PointerGetDatum(construct_empty_array(elemtypid));
    1292              : 
    1293            0 :         for (i = 0; i < ndims; i++)
    1294            0 :                 lbs[i] = 1;
    1295              : 
    1296            0 :         return makeMdArrayResult(astate, ndims, dims, lbs,
    1297            0 :                                                          CurrentMemoryContext, true);
    1298            0 : }
    1299              : 
    1300              : /* Get the information needed to convert data to the specified PG type */
    1301              : static void
    1302            0 : _sv_to_datum_finfo(Oid typid, FmgrInfo *finfo, Oid *typioparam)
    1303              : {
    1304            0 :         Oid                     typinput;
    1305              : 
    1306              :         /* XXX would be better to cache these lookups */
    1307            0 :         getTypeInputInfo(typid,
    1308            0 :                                          &typinput, typioparam);
    1309            0 :         fmgr_info(typinput, finfo);
    1310            0 : }
    1311              : 
    1312              : /*
    1313              :  * convert Perl SV to PG datum of type typid, typmod typmod
    1314              :  *
    1315              :  * Pass the PL/Perl function's fcinfo when attempting to convert to the
    1316              :  * function's result type; otherwise pass NULL.  This is used when we need to
    1317              :  * resolve the actual result type of a function returning RECORD.
    1318              :  *
    1319              :  * finfo and typioparam should be the results of _sv_to_datum_finfo for the
    1320              :  * given typid, or NULL/InvalidOid to let this function do the lookups.
    1321              :  *
    1322              :  * *isnull is an output parameter.
    1323              :  */
    1324              : static Datum
    1325            0 : plperl_sv_to_datum(SV *sv, Oid typid, int32 typmod,
    1326              :                                    FunctionCallInfo fcinfo,
    1327              :                                    FmgrInfo *finfo, Oid typioparam,
    1328              :                                    bool *isnull)
    1329              : {
    1330            0 :         FmgrInfo        tmp;
    1331            0 :         Oid                     funcid;
    1332              : 
    1333              :         /* we might recurse */
    1334            0 :         check_stack_depth();
    1335              : 
    1336            0 :         *isnull = false;
    1337              : 
    1338              :         /*
    1339              :          * Return NULL if result is undef, or if we're in a function returning
    1340              :          * VOID.  In the latter case, we should pay no attention to the last Perl
    1341              :          * statement's result, and this is a convenient means to ensure that.
    1342              :          */
    1343            0 :         if (!sv || !SvOK(sv) || typid == VOIDOID)
    1344              :         {
    1345              :                 /* look up type info if they did not pass it */
    1346            0 :                 if (!finfo)
    1347              :                 {
    1348            0 :                         _sv_to_datum_finfo(typid, &tmp, &typioparam);
    1349            0 :                         finfo = &tmp;
    1350            0 :                 }
    1351            0 :                 *isnull = true;
    1352              :                 /* must call typinput in case it wants to reject NULL */
    1353            0 :                 return InputFunctionCall(finfo, NULL, typioparam, typmod);
    1354              :         }
    1355            0 :         else if ((funcid = get_transform_tosql(typid, current_call_data->prodesc->lang_oid, current_call_data->prodesc->trftypes)))
    1356            0 :                 return OidFunctionCall1(funcid, PointerGetDatum(sv));
    1357            0 :         else if (SvROK(sv))
    1358              :         {
    1359              :                 /* handle references */
    1360            0 :                 SV                 *sav = get_perl_array_ref(sv);
    1361              : 
    1362            0 :                 if (sav)
    1363              :                 {
    1364              :                         /* handle an arrayref */
    1365            0 :                         return plperl_array_to_datum(sav, typid, typmod);
    1366              :                 }
    1367            0 :                 else if (SvTYPE(SvRV(sv)) == SVt_PVHV)
    1368              :                 {
    1369              :                         /* handle a hashref */
    1370            0 :                         Datum           ret;
    1371            0 :                         TupleDesc       td;
    1372            0 :                         bool            isdomain;
    1373              : 
    1374            0 :                         if (!type_is_rowtype(typid))
    1375            0 :                                 ereport(ERROR,
    1376              :                                                 (errcode(ERRCODE_DATATYPE_MISMATCH),
    1377              :                                                  errmsg("cannot convert Perl hash to non-composite type %s",
    1378              :                                                                 format_type_be(typid))));
    1379              : 
    1380            0 :                         td = lookup_rowtype_tupdesc_domain(typid, typmod, true);
    1381            0 :                         if (td != NULL)
    1382              :                         {
    1383              :                                 /* Did we look through a domain? */
    1384            0 :                                 isdomain = (typid != td->tdtypeid);
    1385            0 :                         }
    1386              :                         else
    1387              :                         {
    1388              :                                 /* Must be RECORD, try to resolve based on call info */
    1389            0 :                                 TypeFuncClass funcclass;
    1390              : 
    1391            0 :                                 if (fcinfo)
    1392            0 :                                         funcclass = get_call_result_type(fcinfo, &typid, &td);
    1393              :                                 else
    1394            0 :                                         funcclass = TYPEFUNC_OTHER;
    1395            0 :                                 if (funcclass != TYPEFUNC_COMPOSITE &&
    1396            0 :                                         funcclass != TYPEFUNC_COMPOSITE_DOMAIN)
    1397            0 :                                         ereport(ERROR,
    1398              :                                                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    1399              :                                                          errmsg("function returning record called in context "
    1400              :                                                                         "that cannot accept type record")));
    1401            0 :                                 Assert(td);
    1402            0 :                                 isdomain = (funcclass == TYPEFUNC_COMPOSITE_DOMAIN);
    1403            0 :                         }
    1404              : 
    1405            0 :                         ret = plperl_hash_to_datum(sv, td);
    1406              : 
    1407            0 :                         if (isdomain)
    1408            0 :                                 domain_check(ret, false, typid, NULL, NULL);
    1409              : 
    1410              :                         /* Release on the result of get_call_result_type is harmless */
    1411            0 :                         ReleaseTupleDesc(td);
    1412              : 
    1413            0 :                         return ret;
    1414            0 :                 }
    1415              : 
    1416              :                 /*
    1417              :                  * If it's a reference to something else, such as a scalar, just
    1418              :                  * recursively look through the reference.
    1419              :                  */
    1420            0 :                 return plperl_sv_to_datum(SvRV(sv), typid, typmod,
    1421            0 :                                                                   fcinfo, finfo, typioparam,
    1422            0 :                                                                   isnull);
    1423            0 :         }
    1424              :         else
    1425              :         {
    1426              :                 /* handle a string/number */
    1427            0 :                 Datum           ret;
    1428            0 :                 char       *str = sv2cstr(sv);
    1429              : 
    1430              :                 /* did not pass in any typeinfo? look it up */
    1431            0 :                 if (!finfo)
    1432              :                 {
    1433            0 :                         _sv_to_datum_finfo(typid, &tmp, &typioparam);
    1434            0 :                         finfo = &tmp;
    1435            0 :                 }
    1436              : 
    1437            0 :                 ret = InputFunctionCall(finfo, str, typioparam, typmod);
    1438            0 :                 pfree(str);
    1439              : 
    1440            0 :                 return ret;
    1441            0 :         }
    1442            0 : }
    1443              : 
    1444              : /* Convert the perl SV to a string returned by the type output function */
    1445              : char *
    1446            0 : plperl_sv_to_literal(SV *sv, char *fqtypename)
    1447              : {
    1448            0 :         Oid                     typid;
    1449            0 :         Oid                     typoutput;
    1450            0 :         Datum           datum;
    1451            0 :         bool            typisvarlena,
    1452              :                                 isnull;
    1453              : 
    1454            0 :         check_spi_usage_allowed();
    1455              : 
    1456            0 :         typid = DatumGetObjectId(DirectFunctionCall1(regtypein, CStringGetDatum(fqtypename)));
    1457            0 :         if (!OidIsValid(typid))
    1458            0 :                 ereport(ERROR,
    1459              :                                 (errcode(ERRCODE_UNDEFINED_OBJECT),
    1460              :                                  errmsg("lookup failed for type %s", fqtypename)));
    1461              : 
    1462            0 :         datum = plperl_sv_to_datum(sv,
    1463            0 :                                                            typid, -1,
    1464              :                                                            NULL, NULL, InvalidOid,
    1465              :                                                            &isnull);
    1466              : 
    1467            0 :         if (isnull)
    1468            0 :                 return NULL;
    1469              : 
    1470            0 :         getTypeOutputInfo(typid,
    1471              :                                           &typoutput, &typisvarlena);
    1472              : 
    1473            0 :         return OidOutputFunctionCall(typoutput, datum);
    1474            0 : }
    1475              : 
    1476              : /*
    1477              :  * Convert PostgreSQL array datum to a perl array reference.
    1478              :  *
    1479              :  * typid is arg's OID, which must be an array type.
    1480              :  */
    1481              : static SV  *
    1482            0 : plperl_ref_from_pg_array(Datum arg, Oid typid)
    1483              : {
    1484            0 :         dTHX;
    1485            0 :         ArrayType  *ar = DatumGetArrayTypeP(arg);
    1486            0 :         Oid                     elementtype = ARR_ELEMTYPE(ar);
    1487            0 :         int16           typlen;
    1488            0 :         bool            typbyval;
    1489            0 :         char            typalign,
    1490              :                                 typdelim;
    1491            0 :         Oid                     typioparam;
    1492            0 :         Oid                     typoutputfunc;
    1493            0 :         Oid                     transform_funcid;
    1494            0 :         int                     i,
    1495              :                                 nitems,
    1496              :                            *dims;
    1497            0 :         plperl_array_info *info;
    1498            0 :         SV                 *av;
    1499            0 :         HV                 *hv;
    1500              : 
    1501              :         /*
    1502              :          * Currently we make no effort to cache any of the stuff we look up here,
    1503              :          * which is bad.
    1504              :          */
    1505            0 :         info = palloc0_object(plperl_array_info);
    1506              : 
    1507              :         /* get element type information, including output conversion function */
    1508            0 :         get_type_io_data(elementtype, IOFunc_output,
    1509              :                                          &typlen, &typbyval, &typalign,
    1510              :                                          &typdelim, &typioparam, &typoutputfunc);
    1511              : 
    1512              :         /* Check for a transform function */
    1513            0 :         transform_funcid = get_transform_fromsql(elementtype,
    1514            0 :                                                                                          current_call_data->prodesc->lang_oid,
    1515            0 :                                                                                          current_call_data->prodesc->trftypes);
    1516              : 
    1517              :         /* Look up transform or output function as appropriate */
    1518            0 :         if (OidIsValid(transform_funcid))
    1519            0 :                 fmgr_info(transform_funcid, &info->transform_proc);
    1520              :         else
    1521            0 :                 fmgr_info(typoutputfunc, &info->proc);
    1522              : 
    1523            0 :         info->elem_is_rowtype = type_is_rowtype(elementtype);
    1524              : 
    1525              :         /* Get the number and bounds of array dimensions */
    1526            0 :         info->ndims = ARR_NDIM(ar);
    1527            0 :         dims = ARR_DIMS(ar);
    1528              : 
    1529              :         /* No dimensions? Return an empty array */
    1530            0 :         if (info->ndims == 0)
    1531              :         {
    1532            0 :                 av = newRV_noinc((SV *) newAV());
    1533            0 :         }
    1534              :         else
    1535              :         {
    1536            0 :                 deconstruct_array(ar, elementtype, typlen, typbyval,
    1537            0 :                                                   typalign, &info->elements, &info->nulls,
    1538              :                                                   &nitems);
    1539              : 
    1540              :                 /* Get total number of elements in each dimension */
    1541            0 :                 info->nelems = palloc_array(int, info->ndims);
    1542            0 :                 info->nelems[0] = nitems;
    1543            0 :                 for (i = 1; i < info->ndims; i++)
    1544            0 :                         info->nelems[i] = info->nelems[i - 1] / dims[i - 1];
    1545              : 
    1546            0 :                 av = split_array(info, 0, nitems, 0);
    1547              :         }
    1548              : 
    1549            0 :         hv = newHV();
    1550            0 :         (void) hv_store(hv, "array", 5, av, 0);
    1551            0 :         (void) hv_store(hv, "typeoid", 7, newSVuv(typid), 0);
    1552              : 
    1553            0 :         return sv_bless(newRV_noinc((SV *) hv),
    1554              :                                         gv_stashpv("PostgreSQL::InServer::ARRAY", 0));
    1555            0 : }
    1556              : 
    1557              : /*
    1558              :  * Recursively form array references from splices of the initial array
    1559              :  */
    1560              : static SV  *
    1561            0 : split_array(plperl_array_info *info, int first, int last, int nest)
    1562              : {
    1563            0 :         dTHX;
    1564            0 :         int                     i;
    1565            0 :         AV                 *result;
    1566              : 
    1567              :         /* we should only be called when we have something to split */
    1568            0 :         Assert(info->ndims > 0);
    1569              : 
    1570              :         /* since this function recurses, it could be driven to stack overflow */
    1571            0 :         check_stack_depth();
    1572              : 
    1573              :         /*
    1574              :          * Base case, return a reference to a single-dimensional array
    1575              :          */
    1576            0 :         if (nest >= info->ndims - 1)
    1577            0 :                 return make_array_ref(info, first, last);
    1578              : 
    1579            0 :         result = newAV();
    1580            0 :         for (i = first; i < last; i += info->nelems[nest + 1])
    1581              :         {
    1582              :                 /* Recursively form references to arrays of lower dimensions */
    1583            0 :                 SV                 *ref = split_array(info, i, i + info->nelems[nest + 1], nest + 1);
    1584              : 
    1585            0 :                 av_push(result, ref);
    1586            0 :         }
    1587            0 :         return newRV_noinc((SV *) result);
    1588            0 : }
    1589              : 
    1590              : /*
    1591              :  * Create a Perl reference from a one-dimensional C array, converting
    1592              :  * composite type elements to hash references.
    1593              :  */
    1594              : static SV  *
    1595            0 : make_array_ref(plperl_array_info *info, int first, int last)
    1596              : {
    1597            0 :         dTHX;
    1598            0 :         int                     i;
    1599            0 :         AV                 *result = newAV();
    1600              : 
    1601            0 :         for (i = first; i < last; i++)
    1602              :         {
    1603            0 :                 if (info->nulls[i])
    1604              :                 {
    1605              :                         /*
    1606              :                          * We can't use &PL_sv_undef here.  See "AVs, HVs and undefined
    1607              :                          * values" in perlguts.
    1608              :                          */
    1609            0 :                         av_push(result, newSV(0));
    1610            0 :                 }
    1611              :                 else
    1612              :                 {
    1613            0 :                         Datum           itemvalue = info->elements[i];
    1614              : 
    1615            0 :                         if (info->transform_proc.fn_oid)
    1616            0 :                                 av_push(result, (SV *) DatumGetPointer(FunctionCall1(&info->transform_proc, itemvalue)));
    1617            0 :                         else if (info->elem_is_rowtype)
    1618              :                                 /* Handle composite type elements */
    1619            0 :                                 av_push(result, plperl_hash_from_datum(itemvalue));
    1620              :                         else
    1621              :                         {
    1622            0 :                                 char       *val = OutputFunctionCall(&info->proc, itemvalue);
    1623              : 
    1624            0 :                                 av_push(result, cstr2sv(val));
    1625            0 :                         }
    1626            0 :                 }
    1627            0 :         }
    1628            0 :         return newRV_noinc((SV *) result);
    1629            0 : }
    1630              : 
    1631              : /* Set up the arguments for a trigger call. */
    1632              : static SV  *
    1633            0 : plperl_trigger_build_args(FunctionCallInfo fcinfo)
    1634              : {
    1635            0 :         dTHX;
    1636            0 :         TriggerData *tdata;
    1637            0 :         TupleDesc       tupdesc;
    1638            0 :         int                     i;
    1639            0 :         char       *level;
    1640            0 :         char       *event;
    1641            0 :         char       *relid;
    1642            0 :         char       *when;
    1643            0 :         HV                 *hv;
    1644              : 
    1645            0 :         hv = newHV();
    1646            0 :         hv_ksplit(hv, 12);                      /* pre-grow the hash */
    1647              : 
    1648            0 :         tdata = (TriggerData *) fcinfo->context;
    1649            0 :         tupdesc = tdata->tg_relation->rd_att;
    1650              : 
    1651            0 :         relid = DatumGetCString(DirectFunctionCall1(oidout,
    1652              :                                                                                                 ObjectIdGetDatum(tdata->tg_relation->rd_id)));
    1653              : 
    1654            0 :         hv_store_string(hv, "name", cstr2sv(tdata->tg_trigger->tgname));
    1655            0 :         hv_store_string(hv, "relid", cstr2sv(relid));
    1656              : 
    1657              :         /*
    1658              :          * Note: In BEFORE trigger, stored generated columns are not computed yet,
    1659              :          * so don't make them accessible in NEW row.
    1660              :          */
    1661              : 
    1662            0 :         if (TRIGGER_FIRED_BY_INSERT(tdata->tg_event))
    1663              :         {
    1664            0 :                 event = "INSERT";
    1665            0 :                 if (TRIGGER_FIRED_FOR_ROW(tdata->tg_event))
    1666            0 :                         hv_store_string(hv, "new",
    1667            0 :                                                         plperl_hash_from_tuple(tdata->tg_trigtuple,
    1668            0 :                                                                                                    tupdesc,
    1669            0 :                                                                                                    !TRIGGER_FIRED_BEFORE(tdata->tg_event)));
    1670            0 :         }
    1671            0 :         else if (TRIGGER_FIRED_BY_DELETE(tdata->tg_event))
    1672              :         {
    1673            0 :                 event = "DELETE";
    1674            0 :                 if (TRIGGER_FIRED_FOR_ROW(tdata->tg_event))
    1675            0 :                         hv_store_string(hv, "old",
    1676            0 :                                                         plperl_hash_from_tuple(tdata->tg_trigtuple,
    1677            0 :                                                                                                    tupdesc,
    1678              :                                                                                                    true));
    1679            0 :         }
    1680            0 :         else if (TRIGGER_FIRED_BY_UPDATE(tdata->tg_event))
    1681              :         {
    1682            0 :                 event = "UPDATE";
    1683            0 :                 if (TRIGGER_FIRED_FOR_ROW(tdata->tg_event))
    1684              :                 {
    1685            0 :                         hv_store_string(hv, "old",
    1686            0 :                                                         plperl_hash_from_tuple(tdata->tg_trigtuple,
    1687            0 :                                                                                                    tupdesc,
    1688              :                                                                                                    true));
    1689            0 :                         hv_store_string(hv, "new",
    1690            0 :                                                         plperl_hash_from_tuple(tdata->tg_newtuple,
    1691            0 :                                                                                                    tupdesc,
    1692            0 :                                                                                                    !TRIGGER_FIRED_BEFORE(tdata->tg_event)));
    1693            0 :                 }
    1694            0 :         }
    1695            0 :         else if (TRIGGER_FIRED_BY_TRUNCATE(tdata->tg_event))
    1696            0 :                 event = "TRUNCATE";
    1697              :         else
    1698            0 :                 event = "UNKNOWN";
    1699              : 
    1700            0 :         hv_store_string(hv, "event", cstr2sv(event));
    1701            0 :         hv_store_string(hv, "argc", newSViv(tdata->tg_trigger->tgnargs));
    1702              : 
    1703            0 :         if (tdata->tg_trigger->tgnargs > 0)
    1704              :         {
    1705            0 :                 AV                 *av = newAV();
    1706              : 
    1707            0 :                 av_extend(av, tdata->tg_trigger->tgnargs);
    1708            0 :                 for (i = 0; i < tdata->tg_trigger->tgnargs; i++)
    1709            0 :                         av_push(av, cstr2sv(tdata->tg_trigger->tgargs[i]));
    1710            0 :                 hv_store_string(hv, "args", newRV_noinc((SV *) av));
    1711            0 :         }
    1712              : 
    1713            0 :         hv_store_string(hv, "relname",
    1714            0 :                                         cstr2sv(SPI_getrelname(tdata->tg_relation)));
    1715              : 
    1716            0 :         hv_store_string(hv, "table_name",
    1717            0 :                                         cstr2sv(SPI_getrelname(tdata->tg_relation)));
    1718              : 
    1719            0 :         hv_store_string(hv, "table_schema",
    1720            0 :                                         cstr2sv(SPI_getnspname(tdata->tg_relation)));
    1721              : 
    1722            0 :         if (TRIGGER_FIRED_BEFORE(tdata->tg_event))
    1723            0 :                 when = "BEFORE";
    1724            0 :         else if (TRIGGER_FIRED_AFTER(tdata->tg_event))
    1725            0 :                 when = "AFTER";
    1726            0 :         else if (TRIGGER_FIRED_INSTEAD(tdata->tg_event))
    1727            0 :                 when = "INSTEAD OF";
    1728              :         else
    1729            0 :                 when = "UNKNOWN";
    1730            0 :         hv_store_string(hv, "when", cstr2sv(when));
    1731              : 
    1732            0 :         if (TRIGGER_FIRED_FOR_ROW(tdata->tg_event))
    1733            0 :                 level = "ROW";
    1734            0 :         else if (TRIGGER_FIRED_FOR_STATEMENT(tdata->tg_event))
    1735            0 :                 level = "STATEMENT";
    1736              :         else
    1737            0 :                 level = "UNKNOWN";
    1738            0 :         hv_store_string(hv, "level", cstr2sv(level));
    1739              : 
    1740            0 :         return newRV_noinc((SV *) hv);
    1741            0 : }
    1742              : 
    1743              : 
    1744              : /* Set up the arguments for an event trigger call. */
    1745              : static SV  *
    1746            0 : plperl_event_trigger_build_args(FunctionCallInfo fcinfo)
    1747              : {
    1748            0 :         dTHX;
    1749            0 :         EventTriggerData *tdata;
    1750            0 :         HV                 *hv;
    1751              : 
    1752            0 :         hv = newHV();
    1753              : 
    1754            0 :         tdata = (EventTriggerData *) fcinfo->context;
    1755              : 
    1756            0 :         hv_store_string(hv, "event", cstr2sv(tdata->event));
    1757            0 :         hv_store_string(hv, "tag", cstr2sv(GetCommandTagName(tdata->tag)));
    1758              : 
    1759            0 :         return newRV_noinc((SV *) hv);
    1760            0 : }
    1761              : 
    1762              : /* Construct the modified new tuple to be returned from a trigger. */
    1763              : static HeapTuple
    1764            0 : plperl_modify_tuple(HV *hvTD, TriggerData *tdata, HeapTuple otup)
    1765              : {
    1766            0 :         dTHX;
    1767            0 :         SV                **svp;
    1768            0 :         HV                 *hvNew;
    1769            0 :         HE                 *he;
    1770            0 :         HeapTuple       rtup;
    1771            0 :         TupleDesc       tupdesc;
    1772            0 :         int                     natts;
    1773            0 :         Datum      *modvalues;
    1774            0 :         bool       *modnulls;
    1775            0 :         bool       *modrepls;
    1776              : 
    1777            0 :         svp = hv_fetch_string(hvTD, "new");
    1778            0 :         if (!svp)
    1779            0 :                 ereport(ERROR,
    1780              :                                 (errcode(ERRCODE_UNDEFINED_COLUMN),
    1781              :                                  errmsg("$_TD->{new} does not exist")));
    1782            0 :         if (!SvOK(*svp) || !SvROK(*svp) || SvTYPE(SvRV(*svp)) != SVt_PVHV)
    1783            0 :                 ereport(ERROR,
    1784              :                                 (errcode(ERRCODE_DATATYPE_MISMATCH),
    1785              :                                  errmsg("$_TD->{new} is not a hash reference")));
    1786            0 :         hvNew = (HV *) SvRV(*svp);
    1787              : 
    1788            0 :         tupdesc = tdata->tg_relation->rd_att;
    1789            0 :         natts = tupdesc->natts;
    1790              : 
    1791            0 :         modvalues = (Datum *) palloc0(natts * sizeof(Datum));
    1792            0 :         modnulls = (bool *) palloc0(natts * sizeof(bool));
    1793            0 :         modrepls = (bool *) palloc0(natts * sizeof(bool));
    1794              : 
    1795            0 :         hv_iterinit(hvNew);
    1796            0 :         while ((he = hv_iternext(hvNew)))
    1797              :         {
    1798            0 :                 char       *key = hek2cstr(he);
    1799            0 :                 SV                 *val = HeVAL(he);
    1800            0 :                 int                     attn = SPI_fnumber(tupdesc, key);
    1801            0 :                 Form_pg_attribute attr = TupleDescAttr(tupdesc, attn - 1);
    1802              : 
    1803            0 :                 if (attn == SPI_ERROR_NOATTRIBUTE)
    1804            0 :                         ereport(ERROR,
    1805              :                                         (errcode(ERRCODE_UNDEFINED_COLUMN),
    1806              :                                          errmsg("Perl hash contains nonexistent column \"%s\"",
    1807              :                                                         key)));
    1808            0 :                 if (attn <= 0)
    1809            0 :                         ereport(ERROR,
    1810              :                                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    1811              :                                          errmsg("cannot set system attribute \"%s\"",
    1812              :                                                         key)));
    1813            0 :                 if (attr->attgenerated)
    1814            0 :                         ereport(ERROR,
    1815              :                                         (errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED),
    1816              :                                          errmsg("cannot set generated column \"%s\"",
    1817              :                                                         key)));
    1818              : 
    1819            0 :                 modvalues[attn - 1] = plperl_sv_to_datum(val,
    1820            0 :                                                                                                  attr->atttypid,
    1821            0 :                                                                                                  attr->atttypmod,
    1822              :                                                                                                  NULL,
    1823              :                                                                                                  NULL,
    1824              :                                                                                                  InvalidOid,
    1825            0 :                                                                                                  &modnulls[attn - 1]);
    1826            0 :                 modrepls[attn - 1] = true;
    1827              : 
    1828            0 :                 pfree(key);
    1829            0 :         }
    1830            0 :         hv_iterinit(hvNew);
    1831              : 
    1832            0 :         rtup = heap_modify_tuple(otup, tupdesc, modvalues, modnulls, modrepls);
    1833              : 
    1834            0 :         pfree(modvalues);
    1835            0 :         pfree(modnulls);
    1836            0 :         pfree(modrepls);
    1837              : 
    1838            0 :         return rtup;
    1839            0 : }
    1840              : 
    1841              : 
    1842              : /*
    1843              :  * There are three externally visible pieces to plperl: plperl_call_handler,
    1844              :  * plperl_inline_handler, and plperl_validator.
    1845              :  */
    1846              : 
    1847              : /*
    1848              :  * The call handler is called to run normal functions (including trigger
    1849              :  * functions) that are defined in pg_proc.
    1850              :  */
    1851            0 : PG_FUNCTION_INFO_V1(plperl_call_handler);
    1852              : 
    1853              : Datum
    1854            0 : plperl_call_handler(PG_FUNCTION_ARGS)
    1855              : {
    1856            0 :         Datum           retval = (Datum) 0;
    1857            0 :         plperl_call_data *volatile save_call_data = current_call_data;
    1858            0 :         plperl_interp_desc *volatile oldinterp = plperl_active_interp;
    1859            0 :         plperl_call_data this_call_data;
    1860              : 
    1861              :         /* Initialize current-call status record */
    1862            0 :         MemSet(&this_call_data, 0, sizeof(this_call_data));
    1863            0 :         this_call_data.fcinfo = fcinfo;
    1864              : 
    1865            0 :         PG_TRY();
    1866              :         {
    1867            0 :                 current_call_data = &this_call_data;
    1868            0 :                 if (CALLED_AS_TRIGGER(fcinfo))
    1869            0 :                         retval = plperl_trigger_handler(fcinfo);
    1870            0 :                 else if (CALLED_AS_EVENT_TRIGGER(fcinfo))
    1871              :                 {
    1872            0 :                         plperl_event_trigger_handler(fcinfo);
    1873            0 :                         retval = (Datum) 0;
    1874            0 :                 }
    1875              :                 else
    1876            0 :                         retval = plperl_func_handler(fcinfo);
    1877              :         }
    1878            0 :         PG_FINALLY();
    1879              :         {
    1880            0 :                 current_call_data = save_call_data;
    1881            0 :                 activate_interpreter(oldinterp);
    1882            0 :                 if (this_call_data.prodesc)
    1883            0 :                         decrement_prodesc_refcount(this_call_data.prodesc);
    1884              :         }
    1885            0 :         PG_END_TRY();
    1886              : 
    1887            0 :         return retval;
    1888            0 : }
    1889              : 
    1890              : /*
    1891              :  * The inline handler runs anonymous code blocks (DO blocks).
    1892              :  */
    1893            0 : PG_FUNCTION_INFO_V1(plperl_inline_handler);
    1894              : 
    1895              : Datum
    1896            0 : plperl_inline_handler(PG_FUNCTION_ARGS)
    1897              : {
    1898            0 :         LOCAL_FCINFO(fake_fcinfo, 0);
    1899            0 :         InlineCodeBlock *codeblock = (InlineCodeBlock *) PG_GETARG_POINTER(0);
    1900            0 :         FmgrInfo        flinfo;
    1901            0 :         plperl_proc_desc desc;
    1902            0 :         plperl_call_data *volatile save_call_data = current_call_data;
    1903            0 :         plperl_interp_desc *volatile oldinterp = plperl_active_interp;
    1904            0 :         plperl_call_data this_call_data;
    1905            0 :         ErrorContextCallback pl_error_context;
    1906              : 
    1907              :         /* Initialize current-call status record */
    1908            0 :         MemSet(&this_call_data, 0, sizeof(this_call_data));
    1909              : 
    1910              :         /* Set up a callback for error reporting */
    1911            0 :         pl_error_context.callback = plperl_inline_callback;
    1912            0 :         pl_error_context.previous = error_context_stack;
    1913            0 :         pl_error_context.arg = NULL;
    1914            0 :         error_context_stack = &pl_error_context;
    1915              : 
    1916              :         /*
    1917              :          * Set up a fake fcinfo and descriptor with just enough info to satisfy
    1918              :          * plperl_call_perl_func().  In particular note that this sets things up
    1919              :          * with no arguments passed, and a result type of VOID.
    1920              :          */
    1921            0 :         MemSet(fake_fcinfo, 0, SizeForFunctionCallInfo(0));
    1922            0 :         MemSet(&flinfo, 0, sizeof(flinfo));
    1923            0 :         MemSet(&desc, 0, sizeof(desc));
    1924            0 :         fake_fcinfo->flinfo = &flinfo;
    1925            0 :         flinfo.fn_oid = InvalidOid;
    1926            0 :         flinfo.fn_mcxt = CurrentMemoryContext;
    1927              : 
    1928            0 :         desc.proname = "inline_code_block";
    1929            0 :         desc.fn_readonly = false;
    1930              : 
    1931            0 :         desc.lang_oid = codeblock->langOid;
    1932            0 :         desc.trftypes = NIL;
    1933            0 :         desc.lanpltrusted = codeblock->langIsTrusted;
    1934              : 
    1935            0 :         desc.fn_retistuple = false;
    1936            0 :         desc.fn_retisset = false;
    1937            0 :         desc.fn_retisarray = false;
    1938            0 :         desc.result_oid = InvalidOid;
    1939            0 :         desc.nargs = 0;
    1940            0 :         desc.reference = NULL;
    1941              : 
    1942            0 :         this_call_data.fcinfo = fake_fcinfo;
    1943            0 :         this_call_data.prodesc = &desc;
    1944              :         /* we do not bother with refcounting the fake prodesc */
    1945              : 
    1946            0 :         PG_TRY();
    1947              :         {
    1948            0 :                 SV                 *perlret;
    1949              : 
    1950            0 :                 current_call_data = &this_call_data;
    1951              : 
    1952            0 :                 SPI_connect_ext(codeblock->atomic ? 0 : SPI_OPT_NONATOMIC);
    1953              : 
    1954            0 :                 select_perl_context(desc.lanpltrusted);
    1955              : 
    1956            0 :                 plperl_create_sub(&desc, codeblock->source_text, 0);
    1957              : 
    1958            0 :                 if (!desc.reference)    /* can this happen? */
    1959            0 :                         elog(ERROR, "could not create internal procedure for anonymous code block");
    1960              : 
    1961            0 :                 perlret = plperl_call_perl_func(&desc, fake_fcinfo);
    1962              : 
    1963            0 :                 SvREFCNT_dec_current(perlret);
    1964              : 
    1965            0 :                 if (SPI_finish() != SPI_OK_FINISH)
    1966            0 :                         elog(ERROR, "SPI_finish() failed");
    1967            0 :         }
    1968            0 :         PG_FINALLY();
    1969              :         {
    1970            0 :                 if (desc.reference)
    1971            0 :                         SvREFCNT_dec_current(desc.reference);
    1972            0 :                 current_call_data = save_call_data;
    1973            0 :                 activate_interpreter(oldinterp);
    1974              :         }
    1975            0 :         PG_END_TRY();
    1976              : 
    1977            0 :         error_context_stack = pl_error_context.previous;
    1978              : 
    1979            0 :         PG_RETURN_VOID();
    1980            0 : }
    1981              : 
    1982              : /*
    1983              :  * The validator is called during CREATE FUNCTION to validate the function
    1984              :  * being created/replaced. The precise behavior of the validator may be
    1985              :  * modified by the check_function_bodies GUC.
    1986              :  */
    1987            0 : PG_FUNCTION_INFO_V1(plperl_validator);
    1988              : 
    1989              : Datum
    1990            0 : plperl_validator(PG_FUNCTION_ARGS)
    1991              : {
    1992            0 :         Oid                     funcoid = PG_GETARG_OID(0);
    1993            0 :         HeapTuple       tuple;
    1994            0 :         Form_pg_proc proc;
    1995            0 :         char            functyptype;
    1996            0 :         int                     numargs;
    1997            0 :         Oid                *argtypes;
    1998            0 :         char      **argnames;
    1999            0 :         char       *argmodes;
    2000            0 :         bool            is_trigger = false;
    2001            0 :         bool            is_event_trigger = false;
    2002            0 :         int                     i;
    2003              : 
    2004            0 :         if (!CheckFunctionValidatorAccess(fcinfo->flinfo->fn_oid, funcoid))
    2005            0 :                 PG_RETURN_VOID();
    2006              : 
    2007              :         /* Get the new function's pg_proc entry */
    2008            0 :         tuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcoid));
    2009            0 :         if (!HeapTupleIsValid(tuple))
    2010            0 :                 elog(ERROR, "cache lookup failed for function %u", funcoid);
    2011            0 :         proc = (Form_pg_proc) GETSTRUCT(tuple);
    2012              : 
    2013            0 :         functyptype = get_typtype(proc->prorettype);
    2014              : 
    2015              :         /* Disallow pseudotype result */
    2016              :         /* except for TRIGGER, EVTTRIGGER, RECORD, or VOID */
    2017            0 :         if (functyptype == TYPTYPE_PSEUDO)
    2018              :         {
    2019            0 :                 if (proc->prorettype == TRIGGEROID)
    2020            0 :                         is_trigger = true;
    2021            0 :                 else if (proc->prorettype == EVENT_TRIGGEROID)
    2022            0 :                         is_event_trigger = true;
    2023            0 :                 else if (proc->prorettype != RECORDOID &&
    2024            0 :                                  proc->prorettype != VOIDOID)
    2025            0 :                         ereport(ERROR,
    2026              :                                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    2027              :                                          errmsg("PL/Perl functions cannot return type %s",
    2028              :                                                         format_type_be(proc->prorettype))));
    2029            0 :         }
    2030              : 
    2031              :         /* Disallow pseudotypes in arguments (either IN or OUT) */
    2032            0 :         numargs = get_func_arg_info(tuple,
    2033              :                                                                 &argtypes, &argnames, &argmodes);
    2034            0 :         for (i = 0; i < numargs; i++)
    2035              :         {
    2036            0 :                 if (get_typtype(argtypes[i]) == TYPTYPE_PSEUDO &&
    2037            0 :                         argtypes[i] != RECORDOID)
    2038            0 :                         ereport(ERROR,
    2039              :                                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    2040              :                                          errmsg("PL/Perl functions cannot accept type %s",
    2041              :                                                         format_type_be(argtypes[i]))));
    2042            0 :         }
    2043              : 
    2044            0 :         ReleaseSysCache(tuple);
    2045              : 
    2046              :         /* Postpone body checks if !check_function_bodies */
    2047            0 :         if (check_function_bodies)
    2048              :         {
    2049            0 :                 (void) compile_plperl_function(funcoid, is_trigger, is_event_trigger);
    2050            0 :         }
    2051              : 
    2052              :         /* the result of a validator is ignored */
    2053            0 :         PG_RETURN_VOID();
    2054            0 : }
    2055              : 
    2056              : 
    2057              : /*
    2058              :  * plperlu likewise requires three externally visible functions:
    2059              :  * plperlu_call_handler, plperlu_inline_handler, and plperlu_validator.
    2060              :  * These are currently just aliases that send control to the plperl
    2061              :  * handler functions, and we decide whether a particular function is
    2062              :  * trusted or not by inspecting the actual pg_language tuple.
    2063              :  */
    2064              : 
    2065            0 : PG_FUNCTION_INFO_V1(plperlu_call_handler);
    2066              : 
    2067              : Datum
    2068            0 : plperlu_call_handler(PG_FUNCTION_ARGS)
    2069              : {
    2070            0 :         return plperl_call_handler(fcinfo);
    2071              : }
    2072              : 
    2073            0 : PG_FUNCTION_INFO_V1(plperlu_inline_handler);
    2074              : 
    2075              : Datum
    2076            0 : plperlu_inline_handler(PG_FUNCTION_ARGS)
    2077              : {
    2078            0 :         return plperl_inline_handler(fcinfo);
    2079              : }
    2080              : 
    2081            0 : PG_FUNCTION_INFO_V1(plperlu_validator);
    2082              : 
    2083              : Datum
    2084            0 : plperlu_validator(PG_FUNCTION_ARGS)
    2085              : {
    2086              :         /* call plperl validator with our fcinfo so it gets our oid */
    2087            0 :         return plperl_validator(fcinfo);
    2088              : }
    2089              : 
    2090              : 
    2091              : /*
    2092              :  * Uses mkfunc to create a subroutine whose text is
    2093              :  * supplied in s, and returns a reference to it
    2094              :  */
    2095              : static void
    2096            0 : plperl_create_sub(plperl_proc_desc *prodesc, const char *s, Oid fn_oid)
    2097              : {
    2098            0 :         dTHX;
    2099            0 :         dSP;
    2100            0 :         char            subname[NAMEDATALEN + 40];
    2101            0 :         HV                 *pragma_hv = newHV();
    2102            0 :         SV                 *subref = NULL;
    2103            0 :         int                     count;
    2104              : 
    2105            0 :         sprintf(subname, "%s__%u", prodesc->proname, fn_oid);
    2106              : 
    2107            0 :         if (plperl_use_strict)
    2108            0 :                 hv_store_string(pragma_hv, "strict", (SV *) newAV());
    2109              : 
    2110            0 :         ENTER;
    2111            0 :         SAVETMPS;
    2112            0 :         PUSHMARK(SP);
    2113            0 :         EXTEND(SP, 4);
    2114            0 :         PUSHs(sv_2mortal(cstr2sv(subname)));
    2115            0 :         PUSHs(sv_2mortal(newRV_noinc((SV *) pragma_hv)));
    2116              : 
    2117              :         /*
    2118              :          * Use 'false' for $prolog in mkfunc, which is kept for compatibility in
    2119              :          * case a module such as PostgreSQL::PLPerl::NYTprof replaces the function
    2120              :          * compiler.
    2121              :          */
    2122            0 :         PUSHs(&PL_sv_no);
    2123            0 :         PUSHs(sv_2mortal(cstr2sv(s)));
    2124            0 :         PUTBACK;
    2125              : 
    2126              :         /*
    2127              :          * G_KEEPERR seems to be needed here, else we don't recognize compile
    2128              :          * errors properly.  Perhaps it's because there's another level of eval
    2129              :          * inside mkfunc?
    2130              :          */
    2131            0 :         count = call_pv("PostgreSQL::InServer::mkfunc",
    2132              :                                         G_SCALAR | G_EVAL | G_KEEPERR);
    2133            0 :         SPAGAIN;
    2134              : 
    2135            0 :         if (count == 1)
    2136              :         {
    2137            0 :                 SV                 *sub_rv = (SV *) POPs;
    2138              : 
    2139            0 :                 if (sub_rv && SvROK(sub_rv) && SvTYPE(SvRV(sub_rv)) == SVt_PVCV)
    2140              :                 {
    2141            0 :                         subref = newRV_inc(SvRV(sub_rv));
    2142            0 :                 }
    2143            0 :         }
    2144              : 
    2145            0 :         PUTBACK;
    2146            0 :         FREETMPS;
    2147            0 :         LEAVE;
    2148              : 
    2149            0 :         if (SvTRUE(ERRSV))
    2150            0 :                 ereport(ERROR,
    2151              :                                 (errcode(ERRCODE_SYNTAX_ERROR),
    2152              :                                  errmsg("%s", strip_trailing_ws(sv2cstr(ERRSV)))));
    2153              : 
    2154            0 :         if (!subref)
    2155            0 :                 ereport(ERROR,
    2156              :                                 (errcode(ERRCODE_SYNTAX_ERROR),
    2157              :                                  errmsg("didn't get a CODE reference from compiling function \"%s\"",
    2158              :                                                 prodesc->proname)));
    2159              : 
    2160            0 :         prodesc->reference = subref;
    2161            0 : }
    2162              : 
    2163              : 
    2164              : /**********************************************************************
    2165              :  * plperl_init_shared_libs()            -
    2166              :  **********************************************************************/
    2167              : 
    2168              : static void
    2169            0 : plperl_init_shared_libs(pTHX)
    2170              : {
    2171            0 :         char       *file = __FILE__;
    2172              : 
    2173            0 :         newXS("DynaLoader::boot_DynaLoader", boot_DynaLoader, file);
    2174            0 :         newXS("PostgreSQL::InServer::Util::bootstrap",
    2175              :                   boot_PostgreSQL__InServer__Util, file);
    2176              :         /* newXS for...::SPI::bootstrap is in select_perl_context() */
    2177            0 : }
    2178              : 
    2179              : 
    2180              : static SV  *
    2181            0 : plperl_call_perl_func(plperl_proc_desc *desc, FunctionCallInfo fcinfo)
    2182              : {
    2183            0 :         dTHX;
    2184            0 :         dSP;
    2185            0 :         SV                 *retval;
    2186            0 :         int                     i;
    2187            0 :         int                     count;
    2188            0 :         Oid                *argtypes = NULL;
    2189            0 :         int                     nargs = 0;
    2190              : 
    2191            0 :         ENTER;
    2192            0 :         SAVETMPS;
    2193              : 
    2194            0 :         PUSHMARK(SP);
    2195            0 :         EXTEND(sp, desc->nargs);
    2196              : 
    2197              :         /* Get signature for true functions; inline blocks have no args. */
    2198            0 :         if (fcinfo->flinfo->fn_oid)
    2199            0 :                 get_func_signature(fcinfo->flinfo->fn_oid, &argtypes, &nargs);
    2200            0 :         Assert(nargs == desc->nargs);
    2201              : 
    2202            0 :         for (i = 0; i < desc->nargs; i++)
    2203              :         {
    2204            0 :                 if (fcinfo->args[i].isnull)
    2205            0 :                         PUSHs(&PL_sv_undef);
    2206            0 :                 else if (desc->arg_is_rowtype[i])
    2207              :                 {
    2208            0 :                         SV                 *sv = plperl_hash_from_datum(fcinfo->args[i].value);
    2209              : 
    2210            0 :                         PUSHs(sv_2mortal(sv));
    2211            0 :                 }
    2212              :                 else
    2213              :                 {
    2214            0 :                         SV                 *sv;
    2215            0 :                         Oid                     funcid;
    2216              : 
    2217            0 :                         if (OidIsValid(desc->arg_arraytype[i]))
    2218            0 :                                 sv = plperl_ref_from_pg_array(fcinfo->args[i].value, desc->arg_arraytype[i]);
    2219            0 :                         else if ((funcid = get_transform_fromsql(argtypes[i], current_call_data->prodesc->lang_oid, current_call_data->prodesc->trftypes)))
    2220            0 :                                 sv = (SV *) DatumGetPointer(OidFunctionCall1(funcid, fcinfo->args[i].value));
    2221              :                         else
    2222              :                         {
    2223            0 :                                 char       *tmp;
    2224              : 
    2225            0 :                                 tmp = OutputFunctionCall(&(desc->arg_out_func[i]),
    2226            0 :                                                                                  fcinfo->args[i].value);
    2227            0 :                                 sv = cstr2sv(tmp);
    2228            0 :                                 pfree(tmp);
    2229            0 :                         }
    2230              : 
    2231            0 :                         PUSHs(sv_2mortal(sv));
    2232            0 :                 }
    2233            0 :         }
    2234            0 :         PUTBACK;
    2235              : 
    2236              :         /* Do NOT use G_KEEPERR here */
    2237            0 :         count = call_sv(desc->reference, G_SCALAR | G_EVAL);
    2238              : 
    2239            0 :         SPAGAIN;
    2240              : 
    2241            0 :         if (count != 1)
    2242              :         {
    2243            0 :                 PUTBACK;
    2244            0 :                 FREETMPS;
    2245            0 :                 LEAVE;
    2246            0 :                 ereport(ERROR,
    2247              :                                 (errcode(ERRCODE_EXTERNAL_ROUTINE_EXCEPTION),
    2248              :                                  errmsg("didn't get a return item from function")));
    2249            0 :         }
    2250              : 
    2251            0 :         if (SvTRUE(ERRSV))
    2252              :         {
    2253            0 :                 (void) POPs;
    2254            0 :                 PUTBACK;
    2255            0 :                 FREETMPS;
    2256            0 :                 LEAVE;
    2257              :                 /* XXX need to find a way to determine a better errcode here */
    2258            0 :                 ereport(ERROR,
    2259              :                                 (errcode(ERRCODE_EXTERNAL_ROUTINE_EXCEPTION),
    2260              :                                  errmsg("%s", strip_trailing_ws(sv2cstr(ERRSV)))));
    2261            0 :         }
    2262              : 
    2263            0 :         retval = newSVsv(POPs);
    2264              : 
    2265            0 :         PUTBACK;
    2266            0 :         FREETMPS;
    2267            0 :         LEAVE;
    2268              : 
    2269            0 :         return retval;
    2270            0 : }
    2271              : 
    2272              : 
    2273              : static SV  *
    2274            0 : plperl_call_perl_trigger_func(plperl_proc_desc *desc, FunctionCallInfo fcinfo,
    2275              :                                                           SV *td)
    2276              : {
    2277            0 :         dTHX;
    2278            0 :         dSP;
    2279            0 :         SV                 *retval,
    2280              :                            *TDsv;
    2281            0 :         int                     i,
    2282              :                                 count;
    2283            0 :         Trigger    *tg_trigger = ((TriggerData *) fcinfo->context)->tg_trigger;
    2284              : 
    2285            0 :         ENTER;
    2286            0 :         SAVETMPS;
    2287              : 
    2288            0 :         TDsv = get_sv("main::_TD", 0);
    2289            0 :         if (!TDsv)
    2290            0 :                 ereport(ERROR,
    2291              :                                 (errcode(ERRCODE_EXTERNAL_ROUTINE_EXCEPTION),
    2292              :                                  errmsg("couldn't fetch $_TD")));
    2293              : 
    2294            0 :         save_item(TDsv);                        /* local $_TD */
    2295            0 :         sv_setsv(TDsv, td);
    2296              : 
    2297            0 :         PUSHMARK(sp);
    2298            0 :         EXTEND(sp, tg_trigger->tgnargs);
    2299              : 
    2300            0 :         for (i = 0; i < tg_trigger->tgnargs; i++)
    2301            0 :                 PUSHs(sv_2mortal(cstr2sv(tg_trigger->tgargs[i])));
    2302            0 :         PUTBACK;
    2303              : 
    2304              :         /* Do NOT use G_KEEPERR here */
    2305            0 :         count = call_sv(desc->reference, G_SCALAR | G_EVAL);
    2306              : 
    2307            0 :         SPAGAIN;
    2308              : 
    2309            0 :         if (count != 1)
    2310              :         {
    2311            0 :                 PUTBACK;
    2312            0 :                 FREETMPS;
    2313            0 :                 LEAVE;
    2314            0 :                 ereport(ERROR,
    2315              :                                 (errcode(ERRCODE_EXTERNAL_ROUTINE_EXCEPTION),
    2316              :                                  errmsg("didn't get a return item from trigger function")));
    2317            0 :         }
    2318              : 
    2319            0 :         if (SvTRUE(ERRSV))
    2320              :         {
    2321            0 :                 (void) POPs;
    2322            0 :                 PUTBACK;
    2323            0 :                 FREETMPS;
    2324            0 :                 LEAVE;
    2325              :                 /* XXX need to find a way to determine a better errcode here */
    2326            0 :                 ereport(ERROR,
    2327              :                                 (errcode(ERRCODE_EXTERNAL_ROUTINE_EXCEPTION),
    2328              :                                  errmsg("%s", strip_trailing_ws(sv2cstr(ERRSV)))));
    2329            0 :         }
    2330              : 
    2331            0 :         retval = newSVsv(POPs);
    2332              : 
    2333            0 :         PUTBACK;
    2334            0 :         FREETMPS;
    2335            0 :         LEAVE;
    2336              : 
    2337            0 :         return retval;
    2338            0 : }
    2339              : 
    2340              : 
    2341              : static void
    2342            0 : plperl_call_perl_event_trigger_func(plperl_proc_desc *desc,
    2343              :                                                                         FunctionCallInfo fcinfo,
    2344              :                                                                         SV *td)
    2345              : {
    2346            0 :         dTHX;
    2347            0 :         dSP;
    2348            0 :         SV                 *retval,
    2349              :                            *TDsv;
    2350            0 :         int                     count;
    2351              : 
    2352            0 :         ENTER;
    2353            0 :         SAVETMPS;
    2354              : 
    2355            0 :         TDsv = get_sv("main::_TD", 0);
    2356            0 :         if (!TDsv)
    2357            0 :                 ereport(ERROR,
    2358              :                                 (errcode(ERRCODE_EXTERNAL_ROUTINE_EXCEPTION),
    2359              :                                  errmsg("couldn't fetch $_TD")));
    2360              : 
    2361            0 :         save_item(TDsv);                        /* local $_TD */
    2362            0 :         sv_setsv(TDsv, td);
    2363              : 
    2364            0 :         PUSHMARK(sp);
    2365            0 :         PUTBACK;
    2366              : 
    2367              :         /* Do NOT use G_KEEPERR here */
    2368            0 :         count = call_sv(desc->reference, G_SCALAR | G_EVAL);
    2369              : 
    2370            0 :         SPAGAIN;
    2371              : 
    2372            0 :         if (count != 1)
    2373              :         {
    2374            0 :                 PUTBACK;
    2375            0 :                 FREETMPS;
    2376            0 :                 LEAVE;
    2377            0 :                 ereport(ERROR,
    2378              :                                 (errcode(ERRCODE_EXTERNAL_ROUTINE_EXCEPTION),
    2379              :                                  errmsg("didn't get a return item from trigger function")));
    2380            0 :         }
    2381              : 
    2382            0 :         if (SvTRUE(ERRSV))
    2383              :         {
    2384            0 :                 (void) POPs;
    2385            0 :                 PUTBACK;
    2386            0 :                 FREETMPS;
    2387            0 :                 LEAVE;
    2388              :                 /* XXX need to find a way to determine a better errcode here */
    2389            0 :                 ereport(ERROR,
    2390              :                                 (errcode(ERRCODE_EXTERNAL_ROUTINE_EXCEPTION),
    2391              :                                  errmsg("%s", strip_trailing_ws(sv2cstr(ERRSV)))));
    2392            0 :         }
    2393              : 
    2394            0 :         retval = newSVsv(POPs);
    2395            0 :         (void) retval;                          /* silence compiler warning */
    2396              : 
    2397            0 :         PUTBACK;
    2398            0 :         FREETMPS;
    2399            0 :         LEAVE;
    2400            0 : }
    2401              : 
    2402              : static Datum
    2403            0 : plperl_func_handler(PG_FUNCTION_ARGS)
    2404              : {
    2405            0 :         bool            nonatomic;
    2406            0 :         plperl_proc_desc *prodesc;
    2407            0 :         SV                 *perlret;
    2408            0 :         Datum           retval = 0;
    2409            0 :         ReturnSetInfo *rsi;
    2410            0 :         ErrorContextCallback pl_error_context;
    2411              : 
    2412            0 :         nonatomic = fcinfo->context &&
    2413            0 :                 IsA(fcinfo->context, CallContext) &&
    2414            0 :                 !castNode(CallContext, fcinfo->context)->atomic;
    2415              : 
    2416            0 :         SPI_connect_ext(nonatomic ? SPI_OPT_NONATOMIC : 0);
    2417              : 
    2418            0 :         prodesc = compile_plperl_function(fcinfo->flinfo->fn_oid, false, false);
    2419            0 :         current_call_data->prodesc = prodesc;
    2420            0 :         increment_prodesc_refcount(prodesc);
    2421              : 
    2422              :         /* Set a callback for error reporting */
    2423            0 :         pl_error_context.callback = plperl_exec_callback;
    2424            0 :         pl_error_context.previous = error_context_stack;
    2425            0 :         pl_error_context.arg = prodesc->proname;
    2426            0 :         error_context_stack = &pl_error_context;
    2427              : 
    2428            0 :         rsi = (ReturnSetInfo *) fcinfo->resultinfo;
    2429              : 
    2430            0 :         if (prodesc->fn_retisset)
    2431              :         {
    2432              :                 /* Check context before allowing the call to go through */
    2433            0 :                 if (!rsi || !IsA(rsi, ReturnSetInfo))
    2434            0 :                         ereport(ERROR,
    2435              :                                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    2436              :                                          errmsg("set-valued function called in context that cannot accept a set")));
    2437              : 
    2438            0 :                 if (!(rsi->allowedModes & SFRM_Materialize))
    2439            0 :                         ereport(ERROR,
    2440              :                                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    2441              :                                          errmsg("materialize mode required, but it is not allowed in this context")));
    2442            0 :         }
    2443              : 
    2444            0 :         activate_interpreter(prodesc->interp);
    2445              : 
    2446            0 :         perlret = plperl_call_perl_func(prodesc, fcinfo);
    2447              : 
    2448              :         /************************************************************
    2449              :          * Disconnect from SPI manager and then create the return
    2450              :          * values datum (if the input function does a palloc for it
    2451              :          * this must not be allocated in the SPI memory context
    2452              :          * because SPI_finish would free it).
    2453              :          ************************************************************/
    2454            0 :         if (SPI_finish() != SPI_OK_FINISH)
    2455            0 :                 elog(ERROR, "SPI_finish() failed");
    2456              : 
    2457            0 :         if (prodesc->fn_retisset)
    2458              :         {
    2459            0 :                 SV                 *sav;
    2460              : 
    2461              :                 /*
    2462              :                  * If the Perl function returned an arrayref, we pretend that it
    2463              :                  * called return_next() for each element of the array, to handle old
    2464              :                  * SRFs that didn't know about return_next(). Any other sort of return
    2465              :                  * value is an error, except undef which means return an empty set.
    2466              :                  */
    2467            0 :                 sav = get_perl_array_ref(perlret);
    2468            0 :                 if (sav)
    2469              :                 {
    2470            0 :                         dTHX;
    2471            0 :                         int                     i = 0;
    2472            0 :                         SV                **svp = 0;
    2473            0 :                         AV                 *rav = (AV *) SvRV(sav);
    2474              : 
    2475            0 :                         while ((svp = av_fetch(rav, i, FALSE)) != NULL)
    2476              :                         {
    2477            0 :                                 plperl_return_next_internal(*svp);
    2478            0 :                                 i++;
    2479              :                         }
    2480            0 :                 }
    2481            0 :                 else if (SvOK(perlret))
    2482              :                 {
    2483            0 :                         ereport(ERROR,
    2484              :                                         (errcode(ERRCODE_DATATYPE_MISMATCH),
    2485              :                                          errmsg("set-returning PL/Perl function must return "
    2486              :                                                         "reference to array or use return_next")));
    2487            0 :                 }
    2488              : 
    2489            0 :                 rsi->returnMode = SFRM_Materialize;
    2490            0 :                 if (current_call_data->tuple_store)
    2491              :                 {
    2492            0 :                         rsi->setResult = current_call_data->tuple_store;
    2493            0 :                         rsi->setDesc = current_call_data->ret_tdesc;
    2494            0 :                 }
    2495            0 :                 retval = (Datum) 0;
    2496            0 :         }
    2497            0 :         else if (prodesc->result_oid)
    2498              :         {
    2499            0 :                 retval = plperl_sv_to_datum(perlret,
    2500            0 :                                                                         prodesc->result_oid,
    2501              :                                                                         -1,
    2502            0 :                                                                         fcinfo,
    2503            0 :                                                                         &prodesc->result_in_func,
    2504            0 :                                                                         prodesc->result_typioparam,
    2505            0 :                                                                         &fcinfo->isnull);
    2506              : 
    2507            0 :                 if (fcinfo->isnull && rsi && IsA(rsi, ReturnSetInfo))
    2508            0 :                         rsi->isDone = ExprEndResult;
    2509            0 :         }
    2510              : 
    2511              :         /* Restore the previous error callback */
    2512            0 :         error_context_stack = pl_error_context.previous;
    2513              : 
    2514            0 :         SvREFCNT_dec_current(perlret);
    2515              : 
    2516            0 :         return retval;
    2517            0 : }
    2518              : 
    2519              : 
    2520              : static Datum
    2521            0 : plperl_trigger_handler(PG_FUNCTION_ARGS)
    2522              : {
    2523            0 :         plperl_proc_desc *prodesc;
    2524            0 :         SV                 *perlret;
    2525            0 :         Datum           retval;
    2526            0 :         SV                 *svTD;
    2527            0 :         HV                 *hvTD;
    2528            0 :         ErrorContextCallback pl_error_context;
    2529            0 :         TriggerData *tdata;
    2530            0 :         int                     rc PG_USED_FOR_ASSERTS_ONLY;
    2531              : 
    2532              :         /* Connect to SPI manager */
    2533            0 :         SPI_connect();
    2534              : 
    2535              :         /* Make transition tables visible to this SPI connection */
    2536            0 :         tdata = (TriggerData *) fcinfo->context;
    2537            0 :         rc = SPI_register_trigger_data(tdata);
    2538            0 :         Assert(rc >= 0);
    2539              : 
    2540              :         /* Find or compile the function */
    2541            0 :         prodesc = compile_plperl_function(fcinfo->flinfo->fn_oid, true, false);
    2542            0 :         current_call_data->prodesc = prodesc;
    2543            0 :         increment_prodesc_refcount(prodesc);
    2544              : 
    2545              :         /* Set a callback for error reporting */
    2546            0 :         pl_error_context.callback = plperl_exec_callback;
    2547            0 :         pl_error_context.previous = error_context_stack;
    2548            0 :         pl_error_context.arg = prodesc->proname;
    2549            0 :         error_context_stack = &pl_error_context;
    2550              : 
    2551            0 :         activate_interpreter(prodesc->interp);
    2552              : 
    2553            0 :         svTD = plperl_trigger_build_args(fcinfo);
    2554            0 :         perlret = plperl_call_perl_trigger_func(prodesc, fcinfo, svTD);
    2555            0 :         hvTD = (HV *) SvRV(svTD);
    2556              : 
    2557              :         /************************************************************
    2558              :         * Disconnect from SPI manager and then create the return
    2559              :         * values datum (if the input function does a palloc for it
    2560              :         * this must not be allocated in the SPI memory context
    2561              :         * because SPI_finish would free it).
    2562              :         ************************************************************/
    2563            0 :         if (SPI_finish() != SPI_OK_FINISH)
    2564            0 :                 elog(ERROR, "SPI_finish() failed");
    2565              : 
    2566            0 :         if (perlret == NULL || !SvOK(perlret))
    2567              :         {
    2568              :                 /* undef result means go ahead with original tuple */
    2569            0 :                 TriggerData *trigdata = ((TriggerData *) fcinfo->context);
    2570              : 
    2571            0 :                 if (TRIGGER_FIRED_BY_INSERT(trigdata->tg_event))
    2572            0 :                         retval = PointerGetDatum(trigdata->tg_trigtuple);
    2573            0 :                 else if (TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event))
    2574            0 :                         retval = PointerGetDatum(trigdata->tg_newtuple);
    2575            0 :                 else if (TRIGGER_FIRED_BY_DELETE(trigdata->tg_event))
    2576            0 :                         retval = PointerGetDatum(trigdata->tg_trigtuple);
    2577            0 :                 else if (TRIGGER_FIRED_BY_TRUNCATE(trigdata->tg_event))
    2578            0 :                         retval = PointerGetDatum(trigdata->tg_trigtuple);
    2579              :                 else
    2580            0 :                         retval = (Datum) 0; /* can this happen? */
    2581            0 :         }
    2582              :         else
    2583              :         {
    2584            0 :                 HeapTuple       trv;
    2585            0 :                 char       *tmp;
    2586              : 
    2587            0 :                 tmp = sv2cstr(perlret);
    2588              : 
    2589            0 :                 if (pg_strcasecmp(tmp, "SKIP") == 0)
    2590            0 :                         trv = NULL;
    2591            0 :                 else if (pg_strcasecmp(tmp, "MODIFY") == 0)
    2592              :                 {
    2593            0 :                         TriggerData *trigdata = (TriggerData *) fcinfo->context;
    2594              : 
    2595            0 :                         if (TRIGGER_FIRED_BY_INSERT(trigdata->tg_event))
    2596            0 :                                 trv = plperl_modify_tuple(hvTD, trigdata,
    2597            0 :                                                                                   trigdata->tg_trigtuple);
    2598            0 :                         else if (TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event))
    2599            0 :                                 trv = plperl_modify_tuple(hvTD, trigdata,
    2600            0 :                                                                                   trigdata->tg_newtuple);
    2601              :                         else
    2602              :                         {
    2603            0 :                                 ereport(WARNING,
    2604              :                                                 (errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED),
    2605              :                                                  errmsg("ignoring modified row in DELETE trigger")));
    2606            0 :                                 trv = NULL;
    2607              :                         }
    2608            0 :                 }
    2609              :                 else
    2610              :                 {
    2611            0 :                         ereport(ERROR,
    2612              :                                         (errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED),
    2613              :                                          errmsg("result of PL/Perl trigger function must be undef, "
    2614              :                                                         "\"SKIP\", or \"MODIFY\"")));
    2615            0 :                         trv = NULL;
    2616              :                 }
    2617            0 :                 retval = PointerGetDatum(trv);
    2618            0 :                 pfree(tmp);
    2619            0 :         }
    2620              : 
    2621              :         /* Restore the previous error callback */
    2622            0 :         error_context_stack = pl_error_context.previous;
    2623              : 
    2624            0 :         SvREFCNT_dec_current(svTD);
    2625            0 :         if (perlret)
    2626            0 :                 SvREFCNT_dec_current(perlret);
    2627              : 
    2628            0 :         return retval;
    2629            0 : }
    2630              : 
    2631              : 
    2632              : static void
    2633            0 : plperl_event_trigger_handler(PG_FUNCTION_ARGS)
    2634              : {
    2635            0 :         plperl_proc_desc *prodesc;
    2636            0 :         SV                 *svTD;
    2637            0 :         ErrorContextCallback pl_error_context;
    2638              : 
    2639              :         /* Connect to SPI manager */
    2640            0 :         SPI_connect();
    2641              : 
    2642              :         /* Find or compile the function */
    2643            0 :         prodesc = compile_plperl_function(fcinfo->flinfo->fn_oid, false, true);
    2644            0 :         current_call_data->prodesc = prodesc;
    2645            0 :         increment_prodesc_refcount(prodesc);
    2646              : 
    2647              :         /* Set a callback for error reporting */
    2648            0 :         pl_error_context.callback = plperl_exec_callback;
    2649            0 :         pl_error_context.previous = error_context_stack;
    2650            0 :         pl_error_context.arg = prodesc->proname;
    2651            0 :         error_context_stack = &pl_error_context;
    2652              : 
    2653            0 :         activate_interpreter(prodesc->interp);
    2654              : 
    2655            0 :         svTD = plperl_event_trigger_build_args(fcinfo);
    2656            0 :         plperl_call_perl_event_trigger_func(prodesc, fcinfo, svTD);
    2657              : 
    2658            0 :         if (SPI_finish() != SPI_OK_FINISH)
    2659            0 :                 elog(ERROR, "SPI_finish() failed");
    2660              : 
    2661              :         /* Restore the previous error callback */
    2662            0 :         error_context_stack = pl_error_context.previous;
    2663              : 
    2664            0 :         SvREFCNT_dec_current(svTD);
    2665            0 : }
    2666              : 
    2667              : 
    2668              : static bool
    2669            0 : validate_plperl_function(plperl_proc_ptr *proc_ptr, HeapTuple procTup)
    2670              : {
    2671            0 :         if (proc_ptr && proc_ptr->proc_ptr)
    2672              :         {
    2673            0 :                 plperl_proc_desc *prodesc = proc_ptr->proc_ptr;
    2674            0 :                 bool            uptodate;
    2675              : 
    2676              :                 /************************************************************
    2677              :                  * If it's present, must check whether it's still up to date.
    2678              :                  * This is needed because CREATE OR REPLACE FUNCTION can modify the
    2679              :                  * function's pg_proc entry without changing its OID.
    2680              :                  ************************************************************/
    2681            0 :                 uptodate = (prodesc->fn_xmin == HeapTupleHeaderGetRawXmin(procTup->t_data) &&
    2682            0 :                                         ItemPointerEquals(&prodesc->fn_tid, &procTup->t_self));
    2683              : 
    2684            0 :                 if (uptodate)
    2685            0 :                         return true;
    2686              : 
    2687              :                 /* Otherwise, unlink the obsoleted entry from the hashtable ... */
    2688            0 :                 proc_ptr->proc_ptr = NULL;
    2689              :                 /* ... and release the corresponding refcount, probably deleting it */
    2690            0 :                 decrement_prodesc_refcount(prodesc);
    2691            0 :         }
    2692              : 
    2693            0 :         return false;
    2694            0 : }
    2695              : 
    2696              : 
    2697              : static void
    2698            0 : free_plperl_function(plperl_proc_desc *prodesc)
    2699              : {
    2700            0 :         Assert(prodesc->fn_refcount == 0);
    2701              :         /* Release CODE reference, if we have one, from the appropriate interp */
    2702            0 :         if (prodesc->reference)
    2703              :         {
    2704            0 :                 plperl_interp_desc *oldinterp = plperl_active_interp;
    2705              : 
    2706            0 :                 activate_interpreter(prodesc->interp);
    2707            0 :                 SvREFCNT_dec_current(prodesc->reference);
    2708            0 :                 activate_interpreter(oldinterp);
    2709            0 :         }
    2710              :         /* Release all PG-owned data for this proc */
    2711            0 :         MemoryContextDelete(prodesc->fn_cxt);
    2712            0 : }
    2713              : 
    2714              : 
    2715              : static plperl_proc_desc *
    2716            0 : compile_plperl_function(Oid fn_oid, bool is_trigger, bool is_event_trigger)
    2717              : {
    2718            0 :         HeapTuple       procTup;
    2719            0 :         Form_pg_proc procStruct;
    2720            0 :         plperl_proc_key proc_key;
    2721            0 :         plperl_proc_ptr *proc_ptr;
    2722            0 :         plperl_proc_desc *volatile prodesc = NULL;
    2723            0 :         volatile MemoryContext proc_cxt = NULL;
    2724            0 :         plperl_interp_desc *oldinterp = plperl_active_interp;
    2725            0 :         ErrorContextCallback plperl_error_context;
    2726              : 
    2727              :         /* We'll need the pg_proc tuple in any case... */
    2728            0 :         procTup = SearchSysCache1(PROCOID, ObjectIdGetDatum(fn_oid));
    2729            0 :         if (!HeapTupleIsValid(procTup))
    2730            0 :                 elog(ERROR, "cache lookup failed for function %u", fn_oid);
    2731            0 :         procStruct = (Form_pg_proc) GETSTRUCT(procTup);
    2732              : 
    2733              :         /*
    2734              :          * Try to find function in plperl_proc_hash.  The reason for this
    2735              :          * overcomplicated-seeming lookup procedure is that we don't know whether
    2736              :          * it's plperl or plperlu, and don't want to spend a lookup in pg_language
    2737              :          * to find out.
    2738              :          */
    2739            0 :         proc_key.proc_id = fn_oid;
    2740            0 :         proc_key.is_trigger = is_trigger;
    2741            0 :         proc_key.user_id = GetUserId();
    2742            0 :         proc_ptr = hash_search(plperl_proc_hash, &proc_key,
    2743              :                                                    HASH_FIND, NULL);
    2744            0 :         if (validate_plperl_function(proc_ptr, procTup))
    2745              :         {
    2746              :                 /* Found valid plperl entry */
    2747            0 :                 ReleaseSysCache(procTup);
    2748            0 :                 return proc_ptr->proc_ptr;
    2749              :         }
    2750              : 
    2751              :         /* If not found or obsolete, maybe it's plperlu */
    2752            0 :         proc_key.user_id = InvalidOid;
    2753            0 :         proc_ptr = hash_search(plperl_proc_hash, &proc_key,
    2754              :                                                    HASH_FIND, NULL);
    2755            0 :         if (validate_plperl_function(proc_ptr, procTup))
    2756              :         {
    2757              :                 /* Found valid plperlu entry */
    2758            0 :                 ReleaseSysCache(procTup);
    2759            0 :                 return proc_ptr->proc_ptr;
    2760              :         }
    2761              : 
    2762              :         /************************************************************
    2763              :          * If we haven't found it in the hashtable, we analyze
    2764              :          * the function's arguments and return type and store
    2765              :          * the in-/out-functions in the prodesc block,
    2766              :          * then we load the procedure into the Perl interpreter,
    2767              :          * and last we create a new hashtable entry for it.
    2768              :          ************************************************************/
    2769              : 
    2770              :         /* Set a callback for reporting compilation errors */
    2771            0 :         plperl_error_context.callback = plperl_compile_callback;
    2772            0 :         plperl_error_context.previous = error_context_stack;
    2773            0 :         plperl_error_context.arg = NameStr(procStruct->proname);
    2774            0 :         error_context_stack = &plperl_error_context;
    2775              : 
    2776            0 :         PG_TRY();
    2777              :         {
    2778            0 :                 HeapTuple       langTup;
    2779            0 :                 HeapTuple       typeTup;
    2780            0 :                 Form_pg_language langStruct;
    2781            0 :                 Form_pg_type typeStruct;
    2782            0 :                 Datum           protrftypes_datum;
    2783            0 :                 Datum           prosrcdatum;
    2784            0 :                 bool            isnull;
    2785            0 :                 char       *proc_source;
    2786            0 :                 MemoryContext oldcontext;
    2787              : 
    2788              :                 /************************************************************
    2789              :                  * Allocate a context that will hold all PG data for the procedure.
    2790              :                  ************************************************************/
    2791            0 :                 proc_cxt = AllocSetContextCreate(TopMemoryContext,
    2792              :                                                                                  "PL/Perl function",
    2793              :                                                                                  ALLOCSET_SMALL_SIZES);
    2794              : 
    2795              :                 /************************************************************
    2796              :                  * Allocate and fill a new procedure description block.
    2797              :                  * struct prodesc and subsidiary data must all live in proc_cxt.
    2798              :                  ************************************************************/
    2799            0 :                 oldcontext = MemoryContextSwitchTo(proc_cxt);
    2800            0 :                 prodesc = palloc0_object(plperl_proc_desc);
    2801            0 :                 prodesc->proname = pstrdup(NameStr(procStruct->proname));
    2802            0 :                 MemoryContextSetIdentifier(proc_cxt, prodesc->proname);
    2803            0 :                 prodesc->fn_cxt = proc_cxt;
    2804            0 :                 prodesc->fn_refcount = 0;
    2805            0 :                 prodesc->fn_xmin = HeapTupleHeaderGetRawXmin(procTup->t_data);
    2806            0 :                 prodesc->fn_tid = procTup->t_self;
    2807            0 :                 prodesc->nargs = procStruct->pronargs;
    2808            0 :                 prodesc->arg_out_func = (FmgrInfo *) palloc0(prodesc->nargs * sizeof(FmgrInfo));
    2809            0 :                 prodesc->arg_is_rowtype = (bool *) palloc0(prodesc->nargs * sizeof(bool));
    2810            0 :                 prodesc->arg_arraytype = (Oid *) palloc0(prodesc->nargs * sizeof(Oid));
    2811            0 :                 MemoryContextSwitchTo(oldcontext);
    2812              : 
    2813              :                 /* Remember if function is STABLE/IMMUTABLE */
    2814            0 :                 prodesc->fn_readonly =
    2815            0 :                         (procStruct->provolatile != PROVOLATILE_VOLATILE);
    2816              : 
    2817              :                 /* Fetch protrftypes */
    2818            0 :                 protrftypes_datum = SysCacheGetAttr(PROCOID, procTup,
    2819              :                                                                                         Anum_pg_proc_protrftypes, &isnull);
    2820            0 :                 MemoryContextSwitchTo(proc_cxt);
    2821            0 :                 prodesc->trftypes = isnull ? NIL : oid_array_to_list(protrftypes_datum);
    2822            0 :                 MemoryContextSwitchTo(oldcontext);
    2823              : 
    2824              :                 /************************************************************
    2825              :                  * Lookup the pg_language tuple by Oid
    2826              :                  ************************************************************/
    2827            0 :                 langTup = SearchSysCache1(LANGOID,
    2828            0 :                                                                   ObjectIdGetDatum(procStruct->prolang));
    2829            0 :                 if (!HeapTupleIsValid(langTup))
    2830            0 :                         elog(ERROR, "cache lookup failed for language %u",
    2831              :                                  procStruct->prolang);
    2832            0 :                 langStruct = (Form_pg_language) GETSTRUCT(langTup);
    2833            0 :                 prodesc->lang_oid = langStruct->oid;
    2834            0 :                 prodesc->lanpltrusted = langStruct->lanpltrusted;
    2835            0 :                 ReleaseSysCache(langTup);
    2836              : 
    2837              :                 /************************************************************
    2838              :                  * Get the required information for input conversion of the
    2839              :                  * return value.
    2840              :                  ************************************************************/
    2841            0 :                 if (!is_trigger && !is_event_trigger)
    2842              :                 {
    2843            0 :                         Oid                     rettype = procStruct->prorettype;
    2844              : 
    2845            0 :                         typeTup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(rettype));
    2846            0 :                         if (!HeapTupleIsValid(typeTup))
    2847            0 :                                 elog(ERROR, "cache lookup failed for type %u", rettype);
    2848            0 :                         typeStruct = (Form_pg_type) GETSTRUCT(typeTup);
    2849              : 
    2850              :                         /* Disallow pseudotype result, except VOID or RECORD */
    2851            0 :                         if (typeStruct->typtype == TYPTYPE_PSEUDO)
    2852              :                         {
    2853            0 :                                 if (rettype == VOIDOID ||
    2854            0 :                                         rettype == RECORDOID)
    2855              :                                          /* okay */ ;
    2856            0 :                                 else if (rettype == TRIGGEROID ||
    2857            0 :                                                  rettype == EVENT_TRIGGEROID)
    2858            0 :                                         ereport(ERROR,
    2859              :                                                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    2860              :                                                          errmsg("trigger functions can only be called "
    2861              :                                                                         "as triggers")));
    2862              :                                 else
    2863            0 :                                         ereport(ERROR,
    2864              :                                                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    2865              :                                                          errmsg("PL/Perl functions cannot return type %s",
    2866              :                                                                         format_type_be(rettype))));
    2867            0 :                         }
    2868              : 
    2869            0 :                         prodesc->result_oid = rettype;
    2870            0 :                         prodesc->fn_retisset = procStruct->proretset;
    2871            0 :                         prodesc->fn_retistuple = type_is_rowtype(rettype);
    2872            0 :                         prodesc->fn_retisarray = IsTrueArrayType(typeStruct);
    2873              : 
    2874            0 :                         fmgr_info_cxt(typeStruct->typinput,
    2875            0 :                                                   &(prodesc->result_in_func),
    2876            0 :                                                   proc_cxt);
    2877            0 :                         prodesc->result_typioparam = getTypeIOParam(typeTup);
    2878              : 
    2879            0 :                         ReleaseSysCache(typeTup);
    2880            0 :                 }
    2881              : 
    2882              :                 /************************************************************
    2883              :                  * Get the required information for output conversion
    2884              :                  * of all procedure arguments
    2885              :                  ************************************************************/
    2886            0 :                 if (!is_trigger && !is_event_trigger)
    2887              :                 {
    2888            0 :                         int                     i;
    2889              : 
    2890            0 :                         for (i = 0; i < prodesc->nargs; i++)
    2891              :                         {
    2892            0 :                                 Oid                     argtype = procStruct->proargtypes.values[i];
    2893              : 
    2894            0 :                                 typeTup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(argtype));
    2895            0 :                                 if (!HeapTupleIsValid(typeTup))
    2896            0 :                                         elog(ERROR, "cache lookup failed for type %u", argtype);
    2897            0 :                                 typeStruct = (Form_pg_type) GETSTRUCT(typeTup);
    2898              : 
    2899              :                                 /* Disallow pseudotype argument, except RECORD */
    2900            0 :                                 if (typeStruct->typtype == TYPTYPE_PSEUDO &&
    2901            0 :                                         argtype != RECORDOID)
    2902            0 :                                         ereport(ERROR,
    2903              :                                                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    2904              :                                                          errmsg("PL/Perl functions cannot accept type %s",
    2905              :                                                                         format_type_be(argtype))));
    2906              : 
    2907            0 :                                 if (type_is_rowtype(argtype))
    2908            0 :                                         prodesc->arg_is_rowtype[i] = true;
    2909              :                                 else
    2910              :                                 {
    2911            0 :                                         prodesc->arg_is_rowtype[i] = false;
    2912            0 :                                         fmgr_info_cxt(typeStruct->typoutput,
    2913            0 :                                                                   &(prodesc->arg_out_func[i]),
    2914            0 :                                                                   proc_cxt);
    2915              :                                 }
    2916              : 
    2917              :                                 /* Identify array-type arguments */
    2918            0 :                                 if (IsTrueArrayType(typeStruct))
    2919            0 :                                         prodesc->arg_arraytype[i] = argtype;
    2920              :                                 else
    2921            0 :                                         prodesc->arg_arraytype[i] = InvalidOid;
    2922              : 
    2923            0 :                                 ReleaseSysCache(typeTup);
    2924            0 :                         }
    2925            0 :                 }
    2926              : 
    2927              :                 /************************************************************
    2928              :                  * create the text of the anonymous subroutine.
    2929              :                  * we do not use a named subroutine so that we can call directly
    2930              :                  * through the reference.
    2931              :                  ************************************************************/
    2932            0 :                 prosrcdatum = SysCacheGetAttrNotNull(PROCOID, procTup,
    2933              :                                                                                          Anum_pg_proc_prosrc);
    2934            0 :                 proc_source = TextDatumGetCString(prosrcdatum);
    2935              : 
    2936              :                 /************************************************************
    2937              :                  * Create the procedure in the appropriate interpreter
    2938              :                  ************************************************************/
    2939              : 
    2940            0 :                 select_perl_context(prodesc->lanpltrusted);
    2941              : 
    2942            0 :                 prodesc->interp = plperl_active_interp;
    2943              : 
    2944            0 :                 plperl_create_sub(prodesc, proc_source, fn_oid);
    2945              : 
    2946            0 :                 activate_interpreter(oldinterp);
    2947              : 
    2948            0 :                 pfree(proc_source);
    2949              : 
    2950            0 :                 if (!prodesc->reference)     /* can this happen? */
    2951            0 :                         elog(ERROR, "could not create PL/Perl internal procedure");
    2952              : 
    2953              :                 /************************************************************
    2954              :                  * OK, link the procedure into the correct hashtable entry.
    2955              :                  * Note we assume that the hashtable entry either doesn't exist yet,
    2956              :                  * or we already cleared its proc_ptr during the validation attempts
    2957              :                  * above.  So no need to decrement an old refcount here.
    2958              :                  ************************************************************/
    2959            0 :                 proc_key.user_id = prodesc->lanpltrusted ? GetUserId() : InvalidOid;
    2960              : 
    2961            0 :                 proc_ptr = hash_search(plperl_proc_hash, &proc_key,
    2962              :                                                            HASH_ENTER, NULL);
    2963              :                 /* We assume these two steps can't throw an error: */
    2964            0 :                 proc_ptr->proc_ptr = prodesc;
    2965            0 :                 increment_prodesc_refcount(prodesc);
    2966            0 :         }
    2967            0 :         PG_CATCH();
    2968              :         {
    2969              :                 /*
    2970              :                  * If we got as far as creating a reference, we should be able to use
    2971              :                  * free_plperl_function() to clean up.  If not, then at most we have
    2972              :                  * some PG memory resources in proc_cxt, which we can just delete.
    2973              :                  */
    2974            0 :                 if (prodesc && prodesc->reference)
    2975            0 :                         free_plperl_function(prodesc);
    2976            0 :                 else if (proc_cxt)
    2977            0 :                         MemoryContextDelete(proc_cxt);
    2978              : 
    2979              :                 /* Be sure to restore the previous interpreter, too, for luck */
    2980            0 :                 activate_interpreter(oldinterp);
    2981              : 
    2982            0 :                 PG_RE_THROW();
    2983              :         }
    2984            0 :         PG_END_TRY();
    2985              : 
    2986              :         /* restore previous error callback */
    2987            0 :         error_context_stack = plperl_error_context.previous;
    2988              : 
    2989            0 :         ReleaseSysCache(procTup);
    2990              : 
    2991            0 :         return prodesc;
    2992            0 : }
    2993              : 
    2994              : /* Build a hash from a given composite/row datum */
    2995              : static SV  *
    2996            0 : plperl_hash_from_datum(Datum attr)
    2997              : {
    2998            0 :         HeapTupleHeader td;
    2999            0 :         Oid                     tupType;
    3000            0 :         int32           tupTypmod;
    3001            0 :         TupleDesc       tupdesc;
    3002            0 :         HeapTupleData tmptup;
    3003            0 :         SV                 *sv;
    3004              : 
    3005            0 :         td = DatumGetHeapTupleHeader(attr);
    3006              : 
    3007              :         /* Extract rowtype info and find a tupdesc */
    3008            0 :         tupType = HeapTupleHeaderGetTypeId(td);
    3009            0 :         tupTypmod = HeapTupleHeaderGetTypMod(td);
    3010            0 :         tupdesc = lookup_rowtype_tupdesc(tupType, tupTypmod);
    3011              : 
    3012              :         /* Build a temporary HeapTuple control structure */
    3013            0 :         tmptup.t_len = HeapTupleHeaderGetDatumLength(td);
    3014            0 :         tmptup.t_data = td;
    3015              : 
    3016            0 :         sv = plperl_hash_from_tuple(&tmptup, tupdesc, true);
    3017            0 :         ReleaseTupleDesc(tupdesc);
    3018              : 
    3019            0 :         return sv;
    3020            0 : }
    3021              : 
    3022              : /* Build a hash from all attributes of a given tuple. */
    3023              : static SV  *
    3024            0 : plperl_hash_from_tuple(HeapTuple tuple, TupleDesc tupdesc, bool include_generated)
    3025              : {
    3026            0 :         dTHX;
    3027            0 :         HV                 *hv;
    3028            0 :         int                     i;
    3029              : 
    3030              :         /* since this function recurses, it could be driven to stack overflow */
    3031            0 :         check_stack_depth();
    3032              : 
    3033            0 :         hv = newHV();
    3034            0 :         hv_ksplit(hv, tupdesc->natts);       /* pre-grow the hash */
    3035              : 
    3036            0 :         for (i = 0; i < tupdesc->natts; i++)
    3037              :         {
    3038            0 :                 Datum           attr;
    3039            0 :                 bool            isnull,
    3040              :                                         typisvarlena;
    3041            0 :                 char       *attname;
    3042            0 :                 Oid                     typoutput;
    3043            0 :                 Form_pg_attribute att = TupleDescAttr(tupdesc, i);
    3044              : 
    3045            0 :                 if (att->attisdropped)
    3046            0 :                         continue;
    3047              : 
    3048            0 :                 if (att->attgenerated)
    3049              :                 {
    3050              :                         /* don't include unless requested */
    3051            0 :                         if (!include_generated)
    3052            0 :                                 continue;
    3053              :                         /* never include virtual columns */
    3054            0 :                         if (att->attgenerated == ATTRIBUTE_GENERATED_VIRTUAL)
    3055            0 :                                 continue;
    3056            0 :                 }
    3057              : 
    3058            0 :                 attname = NameStr(att->attname);
    3059            0 :                 attr = heap_getattr(tuple, i + 1, tupdesc, &isnull);
    3060              : 
    3061            0 :                 if (isnull)
    3062              :                 {
    3063              :                         /*
    3064              :                          * Store (attname => undef) and move on.  Note we can't use
    3065              :                          * &PL_sv_undef here; see "AVs, HVs and undefined values" in
    3066              :                          * perlguts for an explanation.
    3067              :                          */
    3068            0 :                         hv_store_string(hv, attname, newSV(0));
    3069            0 :                         continue;
    3070              :                 }
    3071              : 
    3072            0 :                 if (type_is_rowtype(att->atttypid))
    3073              :                 {
    3074            0 :                         SV                 *sv = plperl_hash_from_datum(attr);
    3075              : 
    3076            0 :                         hv_store_string(hv, attname, sv);
    3077            0 :                 }
    3078              :                 else
    3079              :                 {
    3080            0 :                         SV                 *sv;
    3081            0 :                         Oid                     funcid;
    3082              : 
    3083            0 :                         if (OidIsValid(get_base_element_type(att->atttypid)))
    3084            0 :                                 sv = plperl_ref_from_pg_array(attr, att->atttypid);
    3085            0 :                         else if ((funcid = get_transform_fromsql(att->atttypid, current_call_data->prodesc->lang_oid, current_call_data->prodesc->trftypes)))
    3086            0 :                                 sv = (SV *) DatumGetPointer(OidFunctionCall1(funcid, attr));
    3087              :                         else
    3088              :                         {
    3089            0 :                                 char       *outputstr;
    3090              : 
    3091              :                                 /* XXX should have a way to cache these lookups */
    3092            0 :                                 getTypeOutputInfo(att->atttypid, &typoutput, &typisvarlena);
    3093              : 
    3094            0 :                                 outputstr = OidOutputFunctionCall(typoutput, attr);
    3095            0 :                                 sv = cstr2sv(outputstr);
    3096            0 :                                 pfree(outputstr);
    3097            0 :                         }
    3098              : 
    3099            0 :                         hv_store_string(hv, attname, sv);
    3100            0 :                 }
    3101            0 :         }
    3102            0 :         return newRV_noinc((SV *) hv);
    3103            0 : }
    3104              : 
    3105              : 
    3106              : static void
    3107            0 : check_spi_usage_allowed(void)
    3108              : {
    3109              :         /* see comment in plperl_fini() */
    3110            0 :         if (plperl_ending)
    3111              :         {
    3112              :                 /* simple croak as we don't want to involve PostgreSQL code */
    3113            0 :                 croak("SPI functions can not be used in END blocks");
    3114              :         }
    3115              : 
    3116              :         /*
    3117              :          * Disallow SPI usage if we're not executing a fully-compiled plperl
    3118              :          * function.  It might seem impossible to get here in that case, but there
    3119              :          * are cases where Perl will try to execute code during compilation.  If
    3120              :          * we proceed we are likely to crash trying to dereference the prodesc
    3121              :          * pointer.  Working around that might be possible, but it seems unwise
    3122              :          * because it'd allow code execution to happen while validating a
    3123              :          * function, which is undesirable.
    3124              :          */
    3125            0 :         if (current_call_data == NULL || current_call_data->prodesc == NULL)
    3126              :         {
    3127              :                 /* simple croak as we don't want to involve PostgreSQL code */
    3128            0 :                 croak("SPI functions can not be used during function compilation");
    3129              :         }
    3130            0 : }
    3131              : 
    3132              : 
    3133              : HV *
    3134            0 : plperl_spi_exec(char *query, int limit)
    3135              : {
    3136            0 :         HV                 *ret_hv;
    3137              : 
    3138              :         /*
    3139              :          * Execute the query inside a sub-transaction, so we can cope with errors
    3140              :          * sanely
    3141              :          */
    3142            0 :         MemoryContext oldcontext = CurrentMemoryContext;
    3143            0 :         ResourceOwner oldowner = CurrentResourceOwner;
    3144              : 
    3145            0 :         check_spi_usage_allowed();
    3146              : 
    3147            0 :         BeginInternalSubTransaction(NULL);
    3148              :         /* Want to run inside function's memory context */
    3149            0 :         MemoryContextSwitchTo(oldcontext);
    3150              : 
    3151            0 :         PG_TRY();
    3152              :         {
    3153            0 :                 int                     spi_rv;
    3154              : 
    3155            0 :                 pg_verifymbstr(query, strlen(query), false);
    3156              : 
    3157            0 :                 spi_rv = SPI_execute(query, current_call_data->prodesc->fn_readonly,
    3158            0 :                                                          limit);
    3159            0 :                 ret_hv = plperl_spi_execute_fetch_result(SPI_tuptable, SPI_processed,
    3160            0 :                                                                                                  spi_rv);
    3161              : 
    3162              :                 /* Commit the inner transaction, return to outer xact context */
    3163            0 :                 ReleaseCurrentSubTransaction();
    3164            0 :                 MemoryContextSwitchTo(oldcontext);
    3165            0 :                 CurrentResourceOwner = oldowner;
    3166            0 :         }
    3167            0 :         PG_CATCH();
    3168              :         {
    3169            0 :                 ErrorData  *edata;
    3170              : 
    3171              :                 /* Save error info */
    3172            0 :                 MemoryContextSwitchTo(oldcontext);
    3173            0 :                 edata = CopyErrorData();
    3174            0 :                 FlushErrorState();
    3175              : 
    3176              :                 /* Abort the inner transaction */
    3177            0 :                 RollbackAndReleaseCurrentSubTransaction();
    3178            0 :                 MemoryContextSwitchTo(oldcontext);
    3179            0 :                 CurrentResourceOwner = oldowner;
    3180              : 
    3181              :                 /* Punt the error to Perl */
    3182            0 :                 croak_cstr(edata->message);
    3183              : 
    3184              :                 /* Can't get here, but keep compiler quiet */
    3185            0 :                 return NULL;
    3186            0 :         }
    3187            0 :         PG_END_TRY();
    3188              : 
    3189            0 :         return ret_hv;
    3190            0 : }
    3191              : 
    3192              : 
    3193              : static HV  *
    3194            0 : plperl_spi_execute_fetch_result(SPITupleTable *tuptable, uint64 processed,
    3195              :                                                                 int status)
    3196              : {
    3197            0 :         dTHX;
    3198            0 :         HV                 *result;
    3199              : 
    3200            0 :         check_spi_usage_allowed();
    3201              : 
    3202            0 :         result = newHV();
    3203              : 
    3204            0 :         hv_store_string(result, "status",
    3205            0 :                                         cstr2sv(SPI_result_code_string(status)));
    3206            0 :         hv_store_string(result, "processed",
    3207            0 :                                         (processed > (uint64) UV_MAX) ?
    3208            0 :                                         newSVnv((NV) processed) :
    3209            0 :                                         newSVuv((UV) processed));
    3210              : 
    3211            0 :         if (status > 0 && tuptable)
    3212              :         {
    3213            0 :                 AV                 *rows;
    3214            0 :                 SV                 *row;
    3215            0 :                 uint64          i;
    3216              : 
    3217              :                 /* Prevent overflow in call to av_extend() */
    3218            0 :                 if (processed > (uint64) AV_SIZE_MAX)
    3219            0 :                         ereport(ERROR,
    3220              :                                         (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
    3221              :                                          errmsg("query result has too many rows to fit in a Perl array")));
    3222              : 
    3223            0 :                 rows = newAV();
    3224            0 :                 av_extend(rows, processed);
    3225            0 :                 for (i = 0; i < processed; i++)
    3226              :                 {
    3227            0 :                         row = plperl_hash_from_tuple(tuptable->vals[i], tuptable->tupdesc, true);
    3228            0 :                         av_push(rows, row);
    3229            0 :                 }
    3230            0 :                 hv_store_string(result, "rows",
    3231            0 :                                                 newRV_noinc((SV *) rows));
    3232            0 :         }
    3233              : 
    3234            0 :         SPI_freetuptable(tuptable);
    3235              : 
    3236            0 :         return result;
    3237            0 : }
    3238              : 
    3239              : 
    3240              : /*
    3241              :  * plperl_return_next catches any error and converts it to a Perl error.
    3242              :  * We assume (perhaps without adequate justification) that we need not abort
    3243              :  * the current transaction if the Perl code traps the error.
    3244              :  */
    3245              : void
    3246            0 : plperl_return_next(SV *sv)
    3247              : {
    3248            0 :         MemoryContext oldcontext = CurrentMemoryContext;
    3249              : 
    3250            0 :         check_spi_usage_allowed();
    3251              : 
    3252            0 :         PG_TRY();
    3253              :         {
    3254            0 :                 plperl_return_next_internal(sv);
    3255              :         }
    3256            0 :         PG_CATCH();
    3257              :         {
    3258            0 :                 ErrorData  *edata;
    3259              : 
    3260              :                 /* Must reset elog.c's state */
    3261            0 :                 MemoryContextSwitchTo(oldcontext);
    3262            0 :                 edata = CopyErrorData();
    3263            0 :                 FlushErrorState();
    3264              : 
    3265              :                 /* Punt the error to Perl */
    3266            0 :                 croak_cstr(edata->message);
    3267            0 :         }
    3268            0 :         PG_END_TRY();
    3269            0 : }
    3270              : 
    3271              : /*
    3272              :  * plperl_return_next_internal reports any errors in Postgres fashion
    3273              :  * (via ereport).
    3274              :  */
    3275              : static void
    3276            0 : plperl_return_next_internal(SV *sv)
    3277              : {
    3278            0 :         plperl_proc_desc *prodesc;
    3279            0 :         FunctionCallInfo fcinfo;
    3280            0 :         ReturnSetInfo *rsi;
    3281            0 :         MemoryContext old_cxt;
    3282              : 
    3283            0 :         if (!sv)
    3284            0 :                 return;
    3285              : 
    3286            0 :         prodesc = current_call_data->prodesc;
    3287            0 :         fcinfo = current_call_data->fcinfo;
    3288            0 :         rsi = (ReturnSetInfo *) fcinfo->resultinfo;
    3289              : 
    3290            0 :         if (!prodesc->fn_retisset)
    3291            0 :                 ereport(ERROR,
    3292              :                                 (errcode(ERRCODE_SYNTAX_ERROR),
    3293              :                                  errmsg("cannot use return_next in a non-SETOF function")));
    3294              : 
    3295            0 :         if (!current_call_data->ret_tdesc)
    3296              :         {
    3297            0 :                 TupleDesc       tupdesc;
    3298              : 
    3299            0 :                 Assert(!current_call_data->tuple_store);
    3300              : 
    3301              :                 /*
    3302              :                  * This is the first call to return_next in the current PL/Perl
    3303              :                  * function call, so identify the output tuple type and create a
    3304              :                  * tuplestore to hold the result rows.
    3305              :                  */
    3306            0 :                 if (prodesc->fn_retistuple)
    3307              :                 {
    3308            0 :                         TypeFuncClass funcclass;
    3309            0 :                         Oid                     typid;
    3310              : 
    3311            0 :                         funcclass = get_call_result_type(fcinfo, &typid, &tupdesc);
    3312            0 :                         if (funcclass != TYPEFUNC_COMPOSITE &&
    3313            0 :                                 funcclass != TYPEFUNC_COMPOSITE_DOMAIN)
    3314            0 :                                 ereport(ERROR,
    3315              :                                                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    3316              :                                                  errmsg("function returning record called in context "
    3317              :                                                                 "that cannot accept type record")));
    3318              :                         /* if domain-over-composite, remember the domain's type OID */
    3319            0 :                         if (funcclass == TYPEFUNC_COMPOSITE_DOMAIN)
    3320            0 :                                 current_call_data->cdomain_oid = typid;
    3321            0 :                 }
    3322              :                 else
    3323              :                 {
    3324            0 :                         tupdesc = rsi->expectedDesc;
    3325              :                         /* Protect assumption below that we return exactly one column */
    3326            0 :                         if (tupdesc == NULL || tupdesc->natts != 1)
    3327            0 :                                 elog(ERROR, "expected single-column result descriptor for non-composite SETOF result");
    3328              :                 }
    3329              : 
    3330              :                 /*
    3331              :                  * Make sure the tuple_store and ret_tdesc are sufficiently
    3332              :                  * long-lived.
    3333              :                  */
    3334            0 :                 old_cxt = MemoryContextSwitchTo(rsi->econtext->ecxt_per_query_memory);
    3335              : 
    3336            0 :                 current_call_data->ret_tdesc = CreateTupleDescCopy(tupdesc);
    3337            0 :                 current_call_data->tuple_store =
    3338            0 :                         tuplestore_begin_heap(rsi->allowedModes & SFRM_Materialize_Random,
    3339            0 :                                                                   false, work_mem);
    3340              : 
    3341            0 :                 MemoryContextSwitchTo(old_cxt);
    3342            0 :         }
    3343              : 
    3344              :         /*
    3345              :          * Producing the tuple we want to return requires making plenty of
    3346              :          * palloc() allocations that are not cleaned up. Since this function can
    3347              :          * be called many times before the current memory context is reset, we
    3348              :          * need to do those allocations in a temporary context.
    3349              :          */
    3350            0 :         if (!current_call_data->tmp_cxt)
    3351              :         {
    3352            0 :                 current_call_data->tmp_cxt =
    3353            0 :                         AllocSetContextCreate(CurrentMemoryContext,
    3354              :                                                                   "PL/Perl return_next temporary cxt",
    3355              :                                                                   ALLOCSET_DEFAULT_SIZES);
    3356            0 :         }
    3357              : 
    3358            0 :         old_cxt = MemoryContextSwitchTo(current_call_data->tmp_cxt);
    3359              : 
    3360            0 :         if (prodesc->fn_retistuple)
    3361              :         {
    3362            0 :                 HeapTuple       tuple;
    3363              : 
    3364            0 :                 if (!(SvOK(sv) && SvROK(sv) && SvTYPE(SvRV(sv)) == SVt_PVHV))
    3365            0 :                         ereport(ERROR,
    3366              :                                         (errcode(ERRCODE_DATATYPE_MISMATCH),
    3367              :                                          errmsg("SETOF-composite-returning PL/Perl function "
    3368              :                                                         "must call return_next with reference to hash")));
    3369              : 
    3370            0 :                 tuple = plperl_build_tuple_result((HV *) SvRV(sv),
    3371            0 :                                                                                   current_call_data->ret_tdesc);
    3372              : 
    3373            0 :                 if (OidIsValid(current_call_data->cdomain_oid))
    3374            0 :                         domain_check(HeapTupleGetDatum(tuple), false,
    3375            0 :                                                  current_call_data->cdomain_oid,
    3376            0 :                                                  &current_call_data->cdomain_info,
    3377            0 :                                                  rsi->econtext->ecxt_per_query_memory);
    3378              : 
    3379            0 :                 tuplestore_puttuple(current_call_data->tuple_store, tuple);
    3380            0 :         }
    3381            0 :         else if (prodesc->result_oid)
    3382              :         {
    3383            0 :                 Datum           ret[1];
    3384            0 :                 bool            isNull[1];
    3385              : 
    3386            0 :                 ret[0] = plperl_sv_to_datum(sv,
    3387            0 :                                                                         prodesc->result_oid,
    3388              :                                                                         -1,
    3389            0 :                                                                         fcinfo,
    3390            0 :                                                                         &prodesc->result_in_func,
    3391            0 :                                                                         prodesc->result_typioparam,
    3392            0 :                                                                         &isNull[0]);
    3393              : 
    3394            0 :                 tuplestore_putvalues(current_call_data->tuple_store,
    3395            0 :                                                          current_call_data->ret_tdesc,
    3396            0 :                                                          ret, isNull);
    3397            0 :         }
    3398              : 
    3399            0 :         MemoryContextSwitchTo(old_cxt);
    3400            0 :         MemoryContextReset(current_call_data->tmp_cxt);
    3401            0 : }
    3402              : 
    3403              : 
    3404              : SV *
    3405            0 : plperl_spi_query(char *query)
    3406              : {
    3407            0 :         SV                 *cursor;
    3408              : 
    3409              :         /*
    3410              :          * Execute the query inside a sub-transaction, so we can cope with errors
    3411              :          * sanely
    3412              :          */
    3413            0 :         MemoryContext oldcontext = CurrentMemoryContext;
    3414            0 :         ResourceOwner oldowner = CurrentResourceOwner;
    3415              : 
    3416            0 :         check_spi_usage_allowed();
    3417              : 
    3418            0 :         BeginInternalSubTransaction(NULL);
    3419              :         /* Want to run inside function's memory context */
    3420            0 :         MemoryContextSwitchTo(oldcontext);
    3421              : 
    3422            0 :         PG_TRY();
    3423              :         {
    3424            0 :                 SPIPlanPtr      plan;
    3425            0 :                 Portal          portal;
    3426              : 
    3427              :                 /* Make sure the query is validly encoded */
    3428            0 :                 pg_verifymbstr(query, strlen(query), false);
    3429              : 
    3430              :                 /* Create a cursor for the query */
    3431            0 :                 plan = SPI_prepare(query, 0, NULL);
    3432            0 :                 if (plan == NULL)
    3433            0 :                         elog(ERROR, "SPI_prepare() failed:%s",
    3434              :                                  SPI_result_code_string(SPI_result));
    3435              : 
    3436            0 :                 portal = SPI_cursor_open(NULL, plan, NULL, NULL, false);
    3437            0 :                 SPI_freeplan(plan);
    3438            0 :                 if (portal == NULL)
    3439            0 :                         elog(ERROR, "SPI_cursor_open() failed:%s",
    3440              :                                  SPI_result_code_string(SPI_result));
    3441            0 :                 cursor = cstr2sv(portal->name);
    3442              : 
    3443            0 :                 PinPortal(portal);
    3444              : 
    3445              :                 /* Commit the inner transaction, return to outer xact context */
    3446            0 :                 ReleaseCurrentSubTransaction();
    3447            0 :                 MemoryContextSwitchTo(oldcontext);
    3448            0 :                 CurrentResourceOwner = oldowner;
    3449            0 :         }
    3450            0 :         PG_CATCH();
    3451              :         {
    3452            0 :                 ErrorData  *edata;
    3453              : 
    3454              :                 /* Save error info */
    3455            0 :                 MemoryContextSwitchTo(oldcontext);
    3456            0 :                 edata = CopyErrorData();
    3457            0 :                 FlushErrorState();
    3458              : 
    3459              :                 /* Abort the inner transaction */
    3460            0 :                 RollbackAndReleaseCurrentSubTransaction();
    3461            0 :                 MemoryContextSwitchTo(oldcontext);
    3462            0 :                 CurrentResourceOwner = oldowner;
    3463              : 
    3464              :                 /* Punt the error to Perl */
    3465            0 :                 croak_cstr(edata->message);
    3466              : 
    3467              :                 /* Can't get here, but keep compiler quiet */
    3468            0 :                 return NULL;
    3469            0 :         }
    3470            0 :         PG_END_TRY();
    3471              : 
    3472            0 :         return cursor;
    3473            0 : }
    3474              : 
    3475              : 
    3476              : SV *
    3477            0 : plperl_spi_fetchrow(char *cursor)
    3478              : {
    3479            0 :         SV                 *row;
    3480              : 
    3481              :         /*
    3482              :          * Execute the FETCH inside a sub-transaction, so we can cope with errors
    3483              :          * sanely
    3484              :          */
    3485            0 :         MemoryContext oldcontext = CurrentMemoryContext;
    3486            0 :         ResourceOwner oldowner = CurrentResourceOwner;
    3487              : 
    3488            0 :         check_spi_usage_allowed();
    3489              : 
    3490            0 :         BeginInternalSubTransaction(NULL);
    3491              :         /* Want to run inside function's memory context */
    3492            0 :         MemoryContextSwitchTo(oldcontext);
    3493              : 
    3494            0 :         PG_TRY();
    3495              :         {
    3496            0 :                 dTHX;
    3497            0 :                 Portal          p = SPI_cursor_find(cursor);
    3498              : 
    3499            0 :                 if (!p)
    3500              :                 {
    3501            0 :                         row = &PL_sv_undef;
    3502            0 :                 }
    3503              :                 else
    3504              :                 {
    3505            0 :                         SPI_cursor_fetch(p, true, 1);
    3506            0 :                         if (SPI_processed == 0)
    3507              :                         {
    3508            0 :                                 UnpinPortal(p);
    3509            0 :                                 SPI_cursor_close(p);
    3510            0 :                                 row = &PL_sv_undef;
    3511            0 :                         }
    3512              :                         else
    3513              :                         {
    3514            0 :                                 row = plperl_hash_from_tuple(SPI_tuptable->vals[0],
    3515            0 :                                                                                          SPI_tuptable->tupdesc,
    3516              :                                                                                          true);
    3517              :                         }
    3518            0 :                         SPI_freetuptable(SPI_tuptable);
    3519              :                 }
    3520              : 
    3521              :                 /* Commit the inner transaction, return to outer xact context */
    3522            0 :                 ReleaseCurrentSubTransaction();
    3523            0 :                 MemoryContextSwitchTo(oldcontext);
    3524            0 :                 CurrentResourceOwner = oldowner;
    3525            0 :         }
    3526            0 :         PG_CATCH();
    3527              :         {
    3528            0 :                 ErrorData  *edata;
    3529              : 
    3530              :                 /* Save error info */
    3531            0 :                 MemoryContextSwitchTo(oldcontext);
    3532            0 :                 edata = CopyErrorData();
    3533            0 :                 FlushErrorState();
    3534              : 
    3535              :                 /* Abort the inner transaction */
    3536            0 :                 RollbackAndReleaseCurrentSubTransaction();
    3537            0 :                 MemoryContextSwitchTo(oldcontext);
    3538            0 :                 CurrentResourceOwner = oldowner;
    3539              : 
    3540              :                 /* Punt the error to Perl */
    3541            0 :                 croak_cstr(edata->message);
    3542              : 
    3543              :                 /* Can't get here, but keep compiler quiet */
    3544            0 :                 return NULL;
    3545            0 :         }
    3546            0 :         PG_END_TRY();
    3547              : 
    3548            0 :         return row;
    3549            0 : }
    3550              : 
    3551              : void
    3552            0 : plperl_spi_cursor_close(char *cursor)
    3553              : {
    3554            0 :         Portal          p;
    3555              : 
    3556            0 :         check_spi_usage_allowed();
    3557              : 
    3558            0 :         p = SPI_cursor_find(cursor);
    3559              : 
    3560            0 :         if (p)
    3561              :         {
    3562            0 :                 UnpinPortal(p);
    3563            0 :                 SPI_cursor_close(p);
    3564            0 :         }
    3565            0 : }
    3566              : 
    3567              : SV *
    3568            0 : plperl_spi_prepare(char *query, int argc, SV **argv)
    3569              : {
    3570            0 :         volatile SPIPlanPtr plan = NULL;
    3571            0 :         volatile MemoryContext plan_cxt = NULL;
    3572            0 :         plperl_query_desc *volatile qdesc = NULL;
    3573            0 :         plperl_query_entry *volatile hash_entry = NULL;
    3574            0 :         MemoryContext oldcontext = CurrentMemoryContext;
    3575            0 :         ResourceOwner oldowner = CurrentResourceOwner;
    3576            0 :         MemoryContext work_cxt;
    3577            0 :         bool            found;
    3578            0 :         int                     i;
    3579              : 
    3580            0 :         check_spi_usage_allowed();
    3581              : 
    3582            0 :         BeginInternalSubTransaction(NULL);
    3583            0 :         MemoryContextSwitchTo(oldcontext);
    3584              : 
    3585            0 :         PG_TRY();
    3586              :         {
    3587            0 :                 CHECK_FOR_INTERRUPTS();
    3588              : 
    3589              :                 /************************************************************
    3590              :                  * Allocate the new querydesc structure
    3591              :                  *
    3592              :                  * The qdesc struct, as well as all its subsidiary data, lives in its
    3593              :                  * plan_cxt.  But note that the SPIPlan does not.
    3594              :                  ************************************************************/
    3595            0 :                 plan_cxt = AllocSetContextCreate(TopMemoryContext,
    3596              :                                                                                  "PL/Perl spi_prepare query",
    3597              :                                                                                  ALLOCSET_SMALL_SIZES);
    3598            0 :                 MemoryContextSwitchTo(plan_cxt);
    3599            0 :                 qdesc = palloc0_object(plperl_query_desc);
    3600            0 :                 snprintf(qdesc->qname, sizeof(qdesc->qname), "%p", qdesc);
    3601            0 :                 qdesc->plan_cxt = plan_cxt;
    3602            0 :                 qdesc->nargs = argc;
    3603            0 :                 qdesc->argtypes = (Oid *) palloc(argc * sizeof(Oid));
    3604            0 :                 qdesc->arginfuncs = (FmgrInfo *) palloc(argc * sizeof(FmgrInfo));
    3605            0 :                 qdesc->argtypioparams = (Oid *) palloc(argc * sizeof(Oid));
    3606            0 :                 MemoryContextSwitchTo(oldcontext);
    3607              : 
    3608              :                 /************************************************************
    3609              :                  * Do the following work in a short-lived context so that we don't
    3610              :                  * leak a lot of memory in the PL/Perl function's SPI Proc context.
    3611              :                  ************************************************************/
    3612            0 :                 work_cxt = AllocSetContextCreate(CurrentMemoryContext,
    3613              :                                                                                  "PL/Perl spi_prepare workspace",
    3614              :                                                                                  ALLOCSET_DEFAULT_SIZES);
    3615            0 :                 MemoryContextSwitchTo(work_cxt);
    3616              : 
    3617              :                 /************************************************************
    3618              :                  * Resolve argument type names and then look them up by oid
    3619              :                  * in the system cache, and remember the required information
    3620              :                  * for input conversion.
    3621              :                  ************************************************************/
    3622            0 :                 for (i = 0; i < argc; i++)
    3623              :                 {
    3624            0 :                         Oid                     typId,
    3625              :                                                 typInput,
    3626              :                                                 typIOParam;
    3627            0 :                         int32           typmod;
    3628            0 :                         char       *typstr;
    3629              : 
    3630            0 :                         typstr = sv2cstr(argv[i]);
    3631            0 :                         (void) parseTypeString(typstr, &typId, &typmod, NULL);
    3632            0 :                         pfree(typstr);
    3633              : 
    3634            0 :                         getTypeInputInfo(typId, &typInput, &typIOParam);
    3635              : 
    3636            0 :                         qdesc->argtypes[i] = typId;
    3637            0 :                         fmgr_info_cxt(typInput, &(qdesc->arginfuncs[i]), plan_cxt);
    3638            0 :                         qdesc->argtypioparams[i] = typIOParam;
    3639            0 :                 }
    3640              : 
    3641              :                 /* Make sure the query is validly encoded */
    3642            0 :                 pg_verifymbstr(query, strlen(query), false);
    3643              : 
    3644              :                 /************************************************************
    3645              :                  * Prepare the plan and check for errors
    3646              :                  ************************************************************/
    3647            0 :                 plan = SPI_prepare(query, argc, qdesc->argtypes);
    3648              : 
    3649            0 :                 if (plan == NULL)
    3650            0 :                         elog(ERROR, "SPI_prepare() failed:%s",
    3651              :                                  SPI_result_code_string(SPI_result));
    3652              : 
    3653              :                 /************************************************************
    3654              :                  * Save the plan into permanent memory (right now it's in the
    3655              :                  * SPI procCxt, which will go away at function end).
    3656              :                  ************************************************************/
    3657            0 :                 if (SPI_keepplan(plan))
    3658            0 :                         elog(ERROR, "SPI_keepplan() failed");
    3659            0 :                 qdesc->plan = plan;
    3660              : 
    3661              :                 /************************************************************
    3662              :                  * Insert a hashtable entry for the plan.
    3663              :                  ************************************************************/
    3664            0 :                 hash_entry = hash_search(plperl_active_interp->query_hash,
    3665            0 :                                                                  qdesc->qname,
    3666              :                                                                  HASH_ENTER, &found);
    3667            0 :                 hash_entry->query_data = qdesc;
    3668              : 
    3669              :                 /* Get rid of workspace */
    3670            0 :                 MemoryContextDelete(work_cxt);
    3671              : 
    3672              :                 /* Commit the inner transaction, return to outer xact context */
    3673            0 :                 ReleaseCurrentSubTransaction();
    3674            0 :                 MemoryContextSwitchTo(oldcontext);
    3675            0 :                 CurrentResourceOwner = oldowner;
    3676              :         }
    3677            0 :         PG_CATCH();
    3678              :         {
    3679            0 :                 ErrorData  *edata;
    3680              : 
    3681              :                 /* Save error info */
    3682            0 :                 MemoryContextSwitchTo(oldcontext);
    3683            0 :                 edata = CopyErrorData();
    3684            0 :                 FlushErrorState();
    3685              : 
    3686              :                 /* Drop anything we managed to allocate */
    3687            0 :                 if (hash_entry)
    3688            0 :                         hash_search(plperl_active_interp->query_hash,
    3689            0 :                                                 qdesc->qname,
    3690              :                                                 HASH_REMOVE, NULL);
    3691            0 :                 if (plan_cxt)
    3692            0 :                         MemoryContextDelete(plan_cxt);
    3693            0 :                 if (plan)
    3694            0 :                         SPI_freeplan(plan);
    3695              : 
    3696              :                 /* Abort the inner transaction */
    3697            0 :                 RollbackAndReleaseCurrentSubTransaction();
    3698            0 :                 MemoryContextSwitchTo(oldcontext);
    3699            0 :                 CurrentResourceOwner = oldowner;
    3700              : 
    3701              :                 /* Punt the error to Perl */
    3702            0 :                 croak_cstr(edata->message);
    3703              : 
    3704              :                 /* Can't get here, but keep compiler quiet */
    3705            0 :                 return NULL;
    3706            0 :         }
    3707            0 :         PG_END_TRY();
    3708              : 
    3709              :         /************************************************************
    3710              :          * Return the query's hash key to the caller.
    3711              :          ************************************************************/
    3712            0 :         return cstr2sv(qdesc->qname);
    3713            0 : }
    3714              : 
    3715              : HV *
    3716            0 : plperl_spi_exec_prepared(char *query, HV *attr, int argc, SV **argv)
    3717              : {
    3718            0 :         HV                 *ret_hv;
    3719            0 :         SV                **sv;
    3720            0 :         int                     i,
    3721              :                                 limit,
    3722              :                                 spi_rv;
    3723            0 :         char       *nulls;
    3724            0 :         Datum      *argvalues;
    3725            0 :         plperl_query_desc *qdesc;
    3726            0 :         plperl_query_entry *hash_entry;
    3727              : 
    3728              :         /*
    3729              :          * Execute the query inside a sub-transaction, so we can cope with errors
    3730              :          * sanely
    3731              :          */
    3732            0 :         MemoryContext oldcontext = CurrentMemoryContext;
    3733            0 :         ResourceOwner oldowner = CurrentResourceOwner;
    3734              : 
    3735            0 :         check_spi_usage_allowed();
    3736              : 
    3737            0 :         BeginInternalSubTransaction(NULL);
    3738              :         /* Want to run inside function's memory context */
    3739            0 :         MemoryContextSwitchTo(oldcontext);
    3740              : 
    3741            0 :         PG_TRY();
    3742              :         {
    3743            0 :                 dTHX;
    3744              : 
    3745              :                 /************************************************************
    3746              :                  * Fetch the saved plan descriptor, see if it's o.k.
    3747              :                  ************************************************************/
    3748            0 :                 hash_entry = hash_search(plperl_active_interp->query_hash, query,
    3749              :                                                                  HASH_FIND, NULL);
    3750            0 :                 if (hash_entry == NULL)
    3751            0 :                         elog(ERROR, "spi_exec_prepared: Invalid prepared query passed");
    3752              : 
    3753            0 :                 qdesc = hash_entry->query_data;
    3754            0 :                 if (qdesc == NULL)
    3755            0 :                         elog(ERROR, "spi_exec_prepared: plperl query_hash value vanished");
    3756              : 
    3757            0 :                 if (qdesc->nargs != argc)
    3758            0 :                         elog(ERROR, "spi_exec_prepared: expected %d argument(s), %d passed",
    3759              :                                  qdesc->nargs, argc);
    3760              : 
    3761              :                 /************************************************************
    3762              :                  * Parse eventual attributes
    3763              :                  ************************************************************/
    3764            0 :                 limit = 0;
    3765            0 :                 if (attr != NULL)
    3766              :                 {
    3767            0 :                         sv = hv_fetch_string(attr, "limit");
    3768            0 :                         if (sv && *sv && SvIOK(*sv))
    3769            0 :                                 limit = SvIV(*sv);
    3770            0 :                 }
    3771              :                 /************************************************************
    3772              :                  * Set up arguments
    3773              :                  ************************************************************/
    3774            0 :                 if (argc > 0)
    3775              :                 {
    3776            0 :                         nulls = (char *) palloc(argc);
    3777            0 :                         argvalues = (Datum *) palloc(argc * sizeof(Datum));
    3778            0 :                 }
    3779              :                 else
    3780              :                 {
    3781            0 :                         nulls = NULL;
    3782            0 :                         argvalues = NULL;
    3783              :                 }
    3784              : 
    3785            0 :                 for (i = 0; i < argc; i++)
    3786              :                 {
    3787            0 :                         bool            isnull;
    3788              : 
    3789            0 :                         argvalues[i] = plperl_sv_to_datum(argv[i],
    3790            0 :                                                                                           qdesc->argtypes[i],
    3791              :                                                                                           -1,
    3792              :                                                                                           NULL,
    3793            0 :                                                                                           &qdesc->arginfuncs[i],
    3794            0 :                                                                                           qdesc->argtypioparams[i],
    3795              :                                                                                           &isnull);
    3796            0 :                         nulls[i] = isnull ? 'n' : ' ';
    3797            0 :                 }
    3798              : 
    3799              :                 /************************************************************
    3800              :                  * go
    3801              :                  ************************************************************/
    3802            0 :                 spi_rv = SPI_execute_plan(qdesc->plan, argvalues, nulls,
    3803            0 :                                                                   current_call_data->prodesc->fn_readonly, limit);
    3804            0 :                 ret_hv = plperl_spi_execute_fetch_result(SPI_tuptable, SPI_processed,
    3805            0 :                                                                                                  spi_rv);
    3806            0 :                 if (argc > 0)
    3807              :                 {
    3808            0 :                         pfree(argvalues);
    3809            0 :                         pfree(nulls);
    3810            0 :                 }
    3811              : 
    3812              :                 /* Commit the inner transaction, return to outer xact context */
    3813            0 :                 ReleaseCurrentSubTransaction();
    3814            0 :                 MemoryContextSwitchTo(oldcontext);
    3815            0 :                 CurrentResourceOwner = oldowner;
    3816            0 :         }
    3817            0 :         PG_CATCH();
    3818              :         {
    3819            0 :                 ErrorData  *edata;
    3820              : 
    3821              :                 /* Save error info */
    3822            0 :                 MemoryContextSwitchTo(oldcontext);
    3823            0 :                 edata = CopyErrorData();
    3824            0 :                 FlushErrorState();
    3825              : 
    3826              :                 /* Abort the inner transaction */
    3827            0 :                 RollbackAndReleaseCurrentSubTransaction();
    3828            0 :                 MemoryContextSwitchTo(oldcontext);
    3829            0 :                 CurrentResourceOwner = oldowner;
    3830              : 
    3831              :                 /* Punt the error to Perl */
    3832            0 :                 croak_cstr(edata->message);
    3833              : 
    3834              :                 /* Can't get here, but keep compiler quiet */
    3835            0 :                 return NULL;
    3836            0 :         }
    3837            0 :         PG_END_TRY();
    3838              : 
    3839            0 :         return ret_hv;
    3840            0 : }
    3841              : 
    3842              : SV *
    3843            0 : plperl_spi_query_prepared(char *query, int argc, SV **argv)
    3844              : {
    3845            0 :         int                     i;
    3846            0 :         char       *nulls;
    3847            0 :         Datum      *argvalues;
    3848            0 :         plperl_query_desc *qdesc;
    3849            0 :         plperl_query_entry *hash_entry;
    3850            0 :         SV                 *cursor;
    3851            0 :         Portal          portal = NULL;
    3852              : 
    3853              :         /*
    3854              :          * Execute the query inside a sub-transaction, so we can cope with errors
    3855              :          * sanely
    3856              :          */
    3857            0 :         MemoryContext oldcontext = CurrentMemoryContext;
    3858            0 :         ResourceOwner oldowner = CurrentResourceOwner;
    3859              : 
    3860            0 :         check_spi_usage_allowed();
    3861              : 
    3862            0 :         BeginInternalSubTransaction(NULL);
    3863              :         /* Want to run inside function's memory context */
    3864            0 :         MemoryContextSwitchTo(oldcontext);
    3865              : 
    3866            0 :         PG_TRY();
    3867              :         {
    3868              :                 /************************************************************
    3869              :                  * Fetch the saved plan descriptor, see if it's o.k.
    3870              :                  ************************************************************/
    3871            0 :                 hash_entry = hash_search(plperl_active_interp->query_hash, query,
    3872              :                                                                  HASH_FIND, NULL);
    3873            0 :                 if (hash_entry == NULL)
    3874            0 :                         elog(ERROR, "spi_query_prepared: Invalid prepared query passed");
    3875              : 
    3876            0 :                 qdesc = hash_entry->query_data;
    3877            0 :                 if (qdesc == NULL)
    3878            0 :                         elog(ERROR, "spi_query_prepared: plperl query_hash value vanished");
    3879              : 
    3880            0 :                 if (qdesc->nargs != argc)
    3881            0 :                         elog(ERROR, "spi_query_prepared: expected %d argument(s), %d passed",
    3882              :                                  qdesc->nargs, argc);
    3883              : 
    3884              :                 /************************************************************
    3885              :                  * Set up arguments
    3886              :                  ************************************************************/
    3887            0 :                 if (argc > 0)
    3888              :                 {
    3889            0 :                         nulls = (char *) palloc(argc);
    3890            0 :                         argvalues = (Datum *) palloc(argc * sizeof(Datum));
    3891            0 :                 }
    3892              :                 else
    3893              :                 {
    3894            0 :                         nulls = NULL;
    3895            0 :                         argvalues = NULL;
    3896              :                 }
    3897              : 
    3898            0 :                 for (i = 0; i < argc; i++)
    3899              :                 {
    3900            0 :                         bool            isnull;
    3901              : 
    3902            0 :                         argvalues[i] = plperl_sv_to_datum(argv[i],
    3903            0 :                                                                                           qdesc->argtypes[i],
    3904              :                                                                                           -1,
    3905              :                                                                                           NULL,
    3906            0 :                                                                                           &qdesc->arginfuncs[i],
    3907            0 :                                                                                           qdesc->argtypioparams[i],
    3908              :                                                                                           &isnull);
    3909            0 :                         nulls[i] = isnull ? 'n' : ' ';
    3910            0 :                 }
    3911              : 
    3912              :                 /************************************************************
    3913              :                  * go
    3914              :                  ************************************************************/
    3915            0 :                 portal = SPI_cursor_open(NULL, qdesc->plan, argvalues, nulls,
    3916            0 :                                                                  current_call_data->prodesc->fn_readonly);
    3917            0 :                 if (argc > 0)
    3918              :                 {
    3919            0 :                         pfree(argvalues);
    3920            0 :                         pfree(nulls);
    3921            0 :                 }
    3922            0 :                 if (portal == NULL)
    3923            0 :                         elog(ERROR, "SPI_cursor_open() failed:%s",
    3924              :                                  SPI_result_code_string(SPI_result));
    3925              : 
    3926            0 :                 cursor = cstr2sv(portal->name);
    3927              : 
    3928            0 :                 PinPortal(portal);
    3929              : 
    3930              :                 /* Commit the inner transaction, return to outer xact context */
    3931            0 :                 ReleaseCurrentSubTransaction();
    3932            0 :                 MemoryContextSwitchTo(oldcontext);
    3933            0 :                 CurrentResourceOwner = oldowner;
    3934              :         }
    3935            0 :         PG_CATCH();
    3936              :         {
    3937            0 :                 ErrorData  *edata;
    3938              : 
    3939              :                 /* Save error info */
    3940            0 :                 MemoryContextSwitchTo(oldcontext);
    3941            0 :                 edata = CopyErrorData();
    3942            0 :                 FlushErrorState();
    3943              : 
    3944              :                 /* Abort the inner transaction */
    3945            0 :                 RollbackAndReleaseCurrentSubTransaction();
    3946            0 :                 MemoryContextSwitchTo(oldcontext);
    3947            0 :                 CurrentResourceOwner = oldowner;
    3948              : 
    3949              :                 /* Punt the error to Perl */
    3950            0 :                 croak_cstr(edata->message);
    3951              : 
    3952              :                 /* Can't get here, but keep compiler quiet */
    3953            0 :                 return NULL;
    3954            0 :         }
    3955            0 :         PG_END_TRY();
    3956              : 
    3957            0 :         return cursor;
    3958            0 : }
    3959              : 
    3960              : void
    3961            0 : plperl_spi_freeplan(char *query)
    3962              : {
    3963            0 :         SPIPlanPtr      plan;
    3964            0 :         plperl_query_desc *qdesc;
    3965            0 :         plperl_query_entry *hash_entry;
    3966              : 
    3967            0 :         check_spi_usage_allowed();
    3968              : 
    3969            0 :         hash_entry = hash_search(plperl_active_interp->query_hash, query,
    3970              :                                                          HASH_FIND, NULL);
    3971            0 :         if (hash_entry == NULL)
    3972            0 :                 elog(ERROR, "spi_freeplan: Invalid prepared query passed");
    3973              : 
    3974            0 :         qdesc = hash_entry->query_data;
    3975            0 :         if (qdesc == NULL)
    3976            0 :                 elog(ERROR, "spi_freeplan: plperl query_hash value vanished");
    3977            0 :         plan = qdesc->plan;
    3978              : 
    3979              :         /*
    3980              :          * free all memory before SPI_freeplan, so if it dies, nothing will be
    3981              :          * left over
    3982              :          */
    3983            0 :         hash_search(plperl_active_interp->query_hash, query,
    3984              :                                 HASH_REMOVE, NULL);
    3985              : 
    3986            0 :         MemoryContextDelete(qdesc->plan_cxt);
    3987              : 
    3988            0 :         SPI_freeplan(plan);
    3989            0 : }
    3990              : 
    3991              : void
    3992            0 : plperl_spi_commit(void)
    3993              : {
    3994            0 :         MemoryContext oldcontext = CurrentMemoryContext;
    3995              : 
    3996            0 :         check_spi_usage_allowed();
    3997              : 
    3998            0 :         PG_TRY();
    3999              :         {
    4000            0 :                 SPI_commit();
    4001              :         }
    4002            0 :         PG_CATCH();
    4003              :         {
    4004            0 :                 ErrorData  *edata;
    4005              : 
    4006              :                 /* Save error info */
    4007            0 :                 MemoryContextSwitchTo(oldcontext);
    4008            0 :                 edata = CopyErrorData();
    4009            0 :                 FlushErrorState();
    4010              : 
    4011              :                 /* Punt the error to Perl */
    4012            0 :                 croak_cstr(edata->message);
    4013            0 :         }
    4014            0 :         PG_END_TRY();
    4015            0 : }
    4016              : 
    4017              : void
    4018            0 : plperl_spi_rollback(void)
    4019              : {
    4020            0 :         MemoryContext oldcontext = CurrentMemoryContext;
    4021              : 
    4022            0 :         check_spi_usage_allowed();
    4023              : 
    4024            0 :         PG_TRY();
    4025              :         {
    4026            0 :                 SPI_rollback();
    4027              :         }
    4028            0 :         PG_CATCH();
    4029              :         {
    4030            0 :                 ErrorData  *edata;
    4031              : 
    4032              :                 /* Save error info */
    4033            0 :                 MemoryContextSwitchTo(oldcontext);
    4034            0 :                 edata = CopyErrorData();
    4035            0 :                 FlushErrorState();
    4036              : 
    4037              :                 /* Punt the error to Perl */
    4038            0 :                 croak_cstr(edata->message);
    4039            0 :         }
    4040            0 :         PG_END_TRY();
    4041            0 : }
    4042              : 
    4043              : /*
    4044              :  * Implementation of plperl's elog() function
    4045              :  *
    4046              :  * If the error level is less than ERROR, we'll just emit the message and
    4047              :  * return.  When it is ERROR, elog() will longjmp, which we catch and
    4048              :  * turn into a Perl croak().  Note we are assuming that elog() can't have
    4049              :  * any internal failures that are so bad as to require a transaction abort.
    4050              :  *
    4051              :  * The main reason this is out-of-line is to avoid conflicts between XSUB.h
    4052              :  * and the PG_TRY macros.
    4053              :  */
    4054              : void
    4055            0 : plperl_util_elog(int level, SV *msg)
    4056              : {
    4057            0 :         MemoryContext oldcontext = CurrentMemoryContext;
    4058            0 :         char       *volatile cmsg = NULL;
    4059              : 
    4060              :         /*
    4061              :          * We intentionally omit check_spi_usage_allowed() here, as this seems
    4062              :          * safe to allow even in the contexts that that function rejects.
    4063              :          */
    4064              : 
    4065            0 :         PG_TRY();
    4066              :         {
    4067            0 :                 cmsg = sv2cstr(msg);
    4068            0 :                 elog(level, "%s", cmsg);
    4069            0 :                 pfree(cmsg);
    4070              :         }
    4071            0 :         PG_CATCH();
    4072              :         {
    4073            0 :                 ErrorData  *edata;
    4074              : 
    4075              :                 /* Must reset elog.c's state */
    4076            0 :                 MemoryContextSwitchTo(oldcontext);
    4077            0 :                 edata = CopyErrorData();
    4078            0 :                 FlushErrorState();
    4079              : 
    4080            0 :                 if (cmsg)
    4081            0 :                         pfree(cmsg);
    4082              : 
    4083              :                 /* Punt the error to Perl */
    4084            0 :                 croak_cstr(edata->message);
    4085            0 :         }
    4086            0 :         PG_END_TRY();
    4087            0 : }
    4088              : 
    4089              : /*
    4090              :  * Store an SV into a hash table under a key that is a string assumed to be
    4091              :  * in the current database's encoding.
    4092              :  */
    4093              : static SV **
    4094            0 : hv_store_string(HV *hv, const char *key, SV *val)
    4095              : {
    4096            0 :         dTHX;
    4097            0 :         int32           hlen;
    4098            0 :         char       *hkey;
    4099            0 :         SV                **ret;
    4100              : 
    4101            0 :         hkey = pg_server_to_any(key, strlen(key), PG_UTF8);
    4102              : 
    4103              :         /*
    4104              :          * hv_store() recognizes a negative klen parameter as meaning a UTF-8
    4105              :          * encoded key.
    4106              :          */
    4107            0 :         hlen = -(int) strlen(hkey);
    4108            0 :         ret = hv_store(hv, hkey, hlen, val, 0);
    4109              : 
    4110            0 :         if (hkey != key)
    4111            0 :                 pfree(hkey);
    4112              : 
    4113            0 :         return ret;
    4114            0 : }
    4115              : 
    4116              : /*
    4117              :  * Fetch an SV from a hash table under a key that is a string assumed to be
    4118              :  * in the current database's encoding.
    4119              :  */
    4120              : static SV **
    4121            0 : hv_fetch_string(HV *hv, const char *key)
    4122              : {
    4123            0 :         dTHX;
    4124            0 :         int32           hlen;
    4125            0 :         char       *hkey;
    4126            0 :         SV                **ret;
    4127              : 
    4128            0 :         hkey = pg_server_to_any(key, strlen(key), PG_UTF8);
    4129              : 
    4130              :         /* See notes in hv_store_string */
    4131            0 :         hlen = -(int) strlen(hkey);
    4132            0 :         ret = hv_fetch(hv, hkey, hlen, 0);
    4133              : 
    4134            0 :         if (hkey != key)
    4135            0 :                 pfree(hkey);
    4136              : 
    4137            0 :         return ret;
    4138            0 : }
    4139              : 
    4140              : /*
    4141              :  * Provide function name for PL/Perl execution errors
    4142              :  */
    4143              : static void
    4144            0 : plperl_exec_callback(void *arg)
    4145              : {
    4146            0 :         char       *procname = (char *) arg;
    4147              : 
    4148            0 :         if (procname)
    4149            0 :                 errcontext("PL/Perl function \"%s\"", procname);
    4150            0 : }
    4151              : 
    4152              : /*
    4153              :  * Provide function name for PL/Perl compilation errors
    4154              :  */
    4155              : static void
    4156            0 : plperl_compile_callback(void *arg)
    4157              : {
    4158            0 :         char       *procname = (char *) arg;
    4159              : 
    4160            0 :         if (procname)
    4161            0 :                 errcontext("compilation of PL/Perl function \"%s\"", procname);
    4162            0 : }
    4163              : 
    4164              : /*
    4165              :  * Provide error context for the inline handler
    4166              :  */
    4167              : static void
    4168            0 : plperl_inline_callback(void *arg)
    4169              : {
    4170            0 :         errcontext("PL/Perl anonymous code block");
    4171            0 : }
    4172              : 
    4173              : 
    4174              : /*
    4175              :  * Perl's own setlocale(), copied from POSIX.xs
    4176              :  * (needed because of the calls to new_*())
    4177              :  *
    4178              :  * Starting in 5.28, perl exposes Perl_setlocale to do so.
    4179              :  */
    4180              : #if defined(WIN32) && PERL_VERSION_LT(5, 28, 0)
    4181              : static char *
    4182              : setlocale_perl(int category, char *locale)
    4183              : {
    4184              :         dTHX;
    4185              :         char       *RETVAL = setlocale(category, locale);
    4186              : 
    4187              :         if (RETVAL)
    4188              :         {
    4189              : #ifdef USE_LOCALE_CTYPE
    4190              :                 if (category == LC_CTYPE
    4191              : #ifdef LC_ALL
    4192              :                         || category == LC_ALL
    4193              : #endif
    4194              :                         )
    4195              :                 {
    4196              :                         char       *newctype;
    4197              : 
    4198              : #ifdef LC_ALL
    4199              :                         if (category == LC_ALL)
    4200              :                                 newctype = setlocale(LC_CTYPE, NULL);
    4201              :                         else
    4202              : #endif
    4203              :                                 newctype = RETVAL;
    4204              :                         new_ctype(newctype);
    4205              :                 }
    4206              : #endif                                                  /* USE_LOCALE_CTYPE */
    4207              : #ifdef USE_LOCALE_COLLATE
    4208              :                 if (category == LC_COLLATE
    4209              : #ifdef LC_ALL
    4210              :                         || category == LC_ALL
    4211              : #endif
    4212              :                         )
    4213              :                 {
    4214              :                         char       *newcoll;
    4215              : 
    4216              : #ifdef LC_ALL
    4217              :                         if (category == LC_ALL)
    4218              :                                 newcoll = setlocale(LC_COLLATE, NULL);
    4219              :                         else
    4220              : #endif
    4221              :                                 newcoll = RETVAL;
    4222              :                         new_collate(newcoll);
    4223              :                 }
    4224              : #endif                                                  /* USE_LOCALE_COLLATE */
    4225              : 
    4226              : #ifdef USE_LOCALE_NUMERIC
    4227              :                 if (category == LC_NUMERIC
    4228              : #ifdef LC_ALL
    4229              :                         || category == LC_ALL
    4230              : #endif
    4231              :                         )
    4232              :                 {
    4233              :                         char       *newnum;
    4234              : 
    4235              : #ifdef LC_ALL
    4236              :                         if (category == LC_ALL)
    4237              :                                 newnum = setlocale(LC_NUMERIC, NULL);
    4238              :                         else
    4239              : #endif
    4240              :                                 newnum = RETVAL;
    4241              :                         new_numeric(newnum);
    4242              :                 }
    4243              : #endif                                                  /* USE_LOCALE_NUMERIC */
    4244              :         }
    4245              : 
    4246              :         return RETVAL;
    4247              : }
    4248              : #endif                                                  /* defined(WIN32) && PERL_VERSION_LT(5, 28, 0) */
        

Generated by: LCOV version 2.3.2-1