2000-01-20 06:08:58 +01:00
|
|
|
/**********************************************************************
|
|
|
|
* plperl.c - perl as a procedural language for PostgreSQL
|
|
|
|
*
|
|
|
|
* IDENTIFICATION
|
|
|
|
*
|
|
|
|
* This software is copyrighted by Mark Hollomon
|
At 2005-05-21 20:18:50 +0530, ams@oryx.com wrote:
>
> > The second issue is where plperl returns a large result set.
I have attached the following seven patches to address this problem:
1. Trivial. Replaces some errant spaces with tabs.
2. Trivial. Fixes the spelling of Jan's name, and gets rid of many
inane, useless, annoying, and often misleading comments. Here's
a sample: "plperl_init_all() - Initialize all".
(I have tried to add some useful comments here and there, and will
continue to do so now and again.)
3. Trivial. Splits up some long lines.
4. Converts SRFs in PL/Perl to use a Tuplestore and SFRM_Materialize
to return the result set, based on the PL/PgSQL model.
There are two major consequences: result sets will spill to disk when
they can no longer fit in work_mem; and "select foo_srf()" no longer
works. (I didn't lose sleep over the latter, since that form is not
valid in PL/PgSQL, and it's not documented in PL/Perl.)
5. Trivial, but important. Fixes use of "undef" instead of undef. This
would cause empty functions to fail in bizarre ways. I suspect that
there's still another (old) bug here. I'll investigate further.
6. Moves the majority of (4) out into a new plperl_return_next()
function, to make it possible to expose the functionality to
Perl; cleans up some of the code besides.
7. Add an spi_return_next function for use in Perl code.
If you want to apply the patches and try them out, 8-composite.diff is
what you should use. (Note: my patches depend upon Andrew's use-strict
and %_SHARED patches being applied.)
Here's something to try:
create or replace function foo() returns setof record as $$
$i = 0;
for ("World", "PostgreSQL", "PL/Perl") {
spi_return_next({f1=>++$i, f2=>'Hello', f3=>$_});
}
return;
$$ language plperl;
select * from foo() as (f1 integer, f2 text, f3 text);
(Many thanks to Andrews Dunstan and Supernews for their help.)
Abhijit Menon-Sen
2005-06-04 22:33:06 +02:00
|
|
|
* but is shameless cribbed from pltcl.c by Jan Wieck.
|
2000-01-20 06:08:58 +01:00
|
|
|
*
|
|
|
|
* The author hereby grants permission to use, copy, modify,
|
|
|
|
* distribute, and license this software and its documentation
|
|
|
|
* for any purpose, provided that existing copyright notices are
|
|
|
|
* retained in all copies and that this notice is included
|
|
|
|
* verbatim in any distributions. No written agreement, license,
|
|
|
|
* or royalty fee is required for any of the authorized uses.
|
|
|
|
* Modifications to this software may be copyrighted by their
|
|
|
|
* author and need not follow the licensing terms described
|
|
|
|
* here, provided that the new terms are clearly indicated on
|
|
|
|
* the first page of each file where they apply.
|
|
|
|
*
|
|
|
|
* IN NO EVENT SHALL THE AUTHOR OR DISTRIBUTORS BE LIABLE TO ANY
|
|
|
|
* PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR
|
|
|
|
* CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF THIS
|
|
|
|
* SOFTWARE, ITS DOCUMENTATION, OR ANY DERIVATIVES THEREOF, EVEN
|
|
|
|
* IF THE AUTHOR HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
|
|
|
* DAMAGE.
|
|
|
|
*
|
|
|
|
* THE AUTHOR AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY
|
|
|
|
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
|
|
* WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
|
|
|
* PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON
|
|
|
|
* AN "AS IS" BASIS, AND THE AUTHOR AND DISTRIBUTORS HAVE NO
|
|
|
|
* OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
|
|
|
|
* ENHANCEMENTS, OR MODIFICATIONS.
|
|
|
|
*
|
2000-05-28 19:56:29 +02:00
|
|
|
* IDENTIFICATION
|
2005-08-12 23:26:32 +02:00
|
|
|
* $PostgreSQL: pgsql/src/pl/plperl/plperl.c,v 1.89 2005/08/12 21:26:32 tgl Exp $
|
2000-05-28 19:56:29 +02:00
|
|
|
*
|
2000-01-20 06:08:58 +01:00
|
|
|
**********************************************************************/
|
|
|
|
|
2001-10-20 00:43:49 +02:00
|
|
|
#include "postgres.h"
|
2005-02-22 05:43:23 +01:00
|
|
|
/* Defined by Perl */
|
2005-02-23 05:34:21 +01:00
|
|
|
#undef _
|
2000-01-20 06:08:58 +01:00
|
|
|
|
|
|
|
/* system stuff */
|
2004-11-20 20:07:40 +01:00
|
|
|
#include <ctype.h>
|
2000-01-20 06:08:58 +01:00
|
|
|
#include <fcntl.h>
|
2004-07-31 02:45:57 +02:00
|
|
|
#include <unistd.h>
|
2000-01-20 06:08:58 +01:00
|
|
|
|
|
|
|
/* postgreSQL stuff */
|
2004-04-01 23:28:47 +02:00
|
|
|
#include "commands/trigger.h"
|
|
|
|
#include "executor/spi.h"
|
2004-11-23 01:21:24 +01:00
|
|
|
#include "funcapi.h"
|
2004-09-13 22:10:13 +02:00
|
|
|
#include "utils/lsyscache.h"
|
2005-05-06 19:24:55 +02:00
|
|
|
#include "utils/memutils.h"
|
2004-04-01 23:28:47 +02:00
|
|
|
#include "utils/typcache.h"
|
At 2005-05-21 20:18:50 +0530, ams@oryx.com wrote:
>
> > The second issue is where plperl returns a large result set.
I have attached the following seven patches to address this problem:
1. Trivial. Replaces some errant spaces with tabs.
2. Trivial. Fixes the spelling of Jan's name, and gets rid of many
inane, useless, annoying, and often misleading comments. Here's
a sample: "plperl_init_all() - Initialize all".
(I have tried to add some useful comments here and there, and will
continue to do so now and again.)
3. Trivial. Splits up some long lines.
4. Converts SRFs in PL/Perl to use a Tuplestore and SFRM_Materialize
to return the result set, based on the PL/PgSQL model.
There are two major consequences: result sets will spill to disk when
they can no longer fit in work_mem; and "select foo_srf()" no longer
works. (I didn't lose sleep over the latter, since that form is not
valid in PL/PgSQL, and it's not documented in PL/Perl.)
5. Trivial, but important. Fixes use of "undef" instead of undef. This
would cause empty functions to fail in bizarre ways. I suspect that
there's still another (old) bug here. I'll investigate further.
6. Moves the majority of (4) out into a new plperl_return_next()
function, to make it possible to expose the functionality to
Perl; cleans up some of the code besides.
7. Add an spi_return_next function for use in Perl code.
If you want to apply the patches and try them out, 8-composite.diff is
what you should use. (Note: my patches depend upon Andrew's use-strict
and %_SHARED patches being applied.)
Here's something to try:
create or replace function foo() returns setof record as $$
$i = 0;
for ("World", "PostgreSQL", "PL/Perl") {
spi_return_next({f1=>++$i, f2=>'Hello', f3=>$_});
}
return;
$$ language plperl;
select * from foo() as (f1 integer, f2 text, f3 text);
(Many thanks to Andrews Dunstan and Supernews for their help.)
Abhijit Menon-Sen
2005-06-04 22:33:06 +02:00
|
|
|
#include "miscadmin.h"
|
2005-06-15 02:35:16 +02:00
|
|
|
#include "mb/pg_wchar.h"
|
2000-01-20 06:08:58 +01:00
|
|
|
|
|
|
|
/* perl stuff */
|
2000-05-29 23:25:07 +02:00
|
|
|
#include "EXTERN.h"
|
|
|
|
#include "perl.h"
|
2002-01-24 22:40:44 +01:00
|
|
|
#include "XSUB.h"
|
2000-10-24 19:01:06 +02:00
|
|
|
#include "ppport.h"
|
2005-07-10 18:13:13 +02:00
|
|
|
#include "spi_internal.h"
|
2000-01-20 06:08:58 +01:00
|
|
|
|
2002-01-24 22:40:44 +01:00
|
|
|
/* just in case these symbols aren't provided */
|
|
|
|
#ifndef pTHX_
|
|
|
|
#define pTHX_
|
|
|
|
#define pTHX void
|
|
|
|
#endif
|
|
|
|
|
2000-01-20 06:08:58 +01:00
|
|
|
|
|
|
|
/**********************************************************************
|
|
|
|
* The information we cache about loaded procedures
|
|
|
|
**********************************************************************/
|
|
|
|
typedef struct plperl_proc_desc
|
|
|
|
{
|
|
|
|
char *proname;
|
2001-10-20 00:43:49 +02:00
|
|
|
TransactionId fn_xmin;
|
|
|
|
CommandId fn_cmin;
|
2004-09-13 22:10:13 +02:00
|
|
|
bool fn_readonly;
|
2001-10-20 00:43:49 +02:00
|
|
|
bool lanpltrusted;
|
2004-07-01 22:50:22 +02:00
|
|
|
bool fn_retistuple; /* true, if function returns tuple */
|
2004-08-29 07:07:03 +02:00
|
|
|
bool fn_retisset; /* true, if function returns set */
|
2005-07-10 17:32:47 +02:00
|
|
|
bool fn_retisarray; /* true if function returns array */
|
2004-11-22 21:31:53 +01:00
|
|
|
Oid result_oid; /* Oid of result type */
|
|
|
|
FmgrInfo result_in_func; /* I/O function and arg for result type */
|
2004-06-06 02:41:28 +02:00
|
|
|
Oid result_typioparam;
|
2000-01-20 06:08:58 +01:00
|
|
|
int nargs;
|
|
|
|
FmgrInfo arg_out_func[FUNC_MAX_ARGS];
|
2004-04-01 23:28:47 +02:00
|
|
|
bool arg_is_rowtype[FUNC_MAX_ARGS];
|
2000-04-12 19:17:23 +02:00
|
|
|
SV *reference;
|
2004-08-30 04:54:42 +02:00
|
|
|
} plperl_proc_desc;
|
2000-01-20 06:08:58 +01:00
|
|
|
|
|
|
|
|
|
|
|
/**********************************************************************
|
|
|
|
* Global data
|
|
|
|
**********************************************************************/
|
|
|
|
static int plperl_firstcall = 1;
|
The attached patch, which incorporates the previous one sent and
currently unapplied regarding spi_internal.c, makes some additional
fixes relating to return types, and also contains the fix for
preventing the use of insecure versions of Safe.pm.
There is one remaing return case that does not appear to work, namely
return of a composite directly in a select, i.e. if foo returns some
composite type, 'select * from foo()' works but 'select foo()' doesn't.
We will either fix that or document it as a limitation.
The function plperl_func_handler is a mess - I will try to get it
cleaned up (and split up) in a subsequent patch, time permitting.
Also, reiterating previous advice - this changes slightly the API for
spi_exec_query - the returned object has either 2 or 3 members: 'status'
(string) and 'proceesed' (int,- number of rows) and, if rows are
returned, 'rows' (array of tuple hashes).
Andrew Dunstan
2004-07-12 16:31:04 +02:00
|
|
|
static bool plperl_safe_init_done = false;
|
Well, after persuading cvsup and cvs that it _is_ possible to have local
modifiable repositories, I have a clean untrusted plperl patch to offer
you :)
Highlights:
* There's one perl interpreter used for both trusted and untrusted
procedures. I do think its unnecessary to keep two perl
interpreters around. If someone can break out from trusted "Safe" perl
mode, well, they can do what they want already. If someone disagrees, I
can change this.
* Opcode is not statically loaded anymore. Instead, we load Dynaloader,
which then can grab Opcode (and anything else you can 'use') on its own.
* Checked to work on FreeBSD 4.3 + perl 5.5.3 , OpenBSD 2.8 + perl5.6.1,
RedHat 6.2 + perl 5.5.3
* Uses ExtUtils::Embed to find what options are necessary to link with
perl shared libraries
* createlang is also updated, it can create untrusted perl using 'plperlu'
* Example script (assuming you have Mail::Sendmail installed):
create function foo() returns text as '
use Mail::Sendmail;
%mail = ( To => q(you@yourname.com),
From => q(me@here.com),
Message => "This is a very short message"
);
sendmail(%mail) or die $Mail::Sendmail::error;
return "OK. Log says:\n", $Mail::Sendmail::log;
' language 'plperlu';
Alex Pilosov
2001-06-18 23:40:06 +02:00
|
|
|
static PerlInterpreter *plperl_interp = NULL;
|
2000-04-12 19:17:23 +02:00
|
|
|
static HV *plperl_proc_hash = NULL;
|
|
|
|
|
At 2005-05-21 20:18:50 +0530, ams@oryx.com wrote:
>
> > The second issue is where plperl returns a large result set.
I have attached the following seven patches to address this problem:
1. Trivial. Replaces some errant spaces with tabs.
2. Trivial. Fixes the spelling of Jan's name, and gets rid of many
inane, useless, annoying, and often misleading comments. Here's
a sample: "plperl_init_all() - Initialize all".
(I have tried to add some useful comments here and there, and will
continue to do so now and again.)
3. Trivial. Splits up some long lines.
4. Converts SRFs in PL/Perl to use a Tuplestore and SFRM_Materialize
to return the result set, based on the PL/PgSQL model.
There are two major consequences: result sets will spill to disk when
they can no longer fit in work_mem; and "select foo_srf()" no longer
works. (I didn't lose sleep over the latter, since that form is not
valid in PL/PgSQL, and it's not documented in PL/Perl.)
5. Trivial, but important. Fixes use of "undef" instead of undef. This
would cause empty functions to fail in bizarre ways. I suspect that
there's still another (old) bug here. I'll investigate further.
6. Moves the majority of (4) out into a new plperl_return_next()
function, to make it possible to expose the functionality to
Perl; cleans up some of the code besides.
7. Add an spi_return_next function for use in Perl code.
If you want to apply the patches and try them out, 8-composite.diff is
what you should use. (Note: my patches depend upon Andrew's use-strict
and %_SHARED patches being applied.)
Here's something to try:
create or replace function foo() returns setof record as $$
$i = 0;
for ("World", "PostgreSQL", "PL/Perl") {
spi_return_next({f1=>++$i, f2=>'Hello', f3=>$_});
}
return;
$$ language plperl;
select * from foo() as (f1 integer, f2 text, f3 text);
(Many thanks to Andrews Dunstan and Supernews for their help.)
Abhijit Menon-Sen
2005-06-04 22:33:06 +02:00
|
|
|
static bool plperl_use_strict = false;
|
|
|
|
|
2005-07-12 03:16:22 +02:00
|
|
|
/* these are saved and restored by plperl_call_handler */
|
2004-09-13 22:10:13 +02:00
|
|
|
static plperl_proc_desc *plperl_current_prodesc = NULL;
|
2005-07-12 03:16:22 +02:00
|
|
|
static FunctionCallInfo plperl_current_caller_info;
|
|
|
|
static Tuplestorestate *plperl_current_tuple_store;
|
|
|
|
static TupleDesc plperl_current_tuple_desc;
|
2004-09-13 22:10:13 +02:00
|
|
|
|
2000-01-20 06:08:58 +01:00
|
|
|
/**********************************************************************
|
|
|
|
* Forward declarations
|
|
|
|
**********************************************************************/
|
|
|
|
static void plperl_init_all(void);
|
Well, after persuading cvsup and cvs that it _is_ possible to have local
modifiable repositories, I have a clean untrusted plperl patch to offer
you :)
Highlights:
* There's one perl interpreter used for both trusted and untrusted
procedures. I do think its unnecessary to keep two perl
interpreters around. If someone can break out from trusted "Safe" perl
mode, well, they can do what they want already. If someone disagrees, I
can change this.
* Opcode is not statically loaded anymore. Instead, we load Dynaloader,
which then can grab Opcode (and anything else you can 'use') on its own.
* Checked to work on FreeBSD 4.3 + perl 5.5.3 , OpenBSD 2.8 + perl5.6.1,
RedHat 6.2 + perl 5.5.3
* Uses ExtUtils::Embed to find what options are necessary to link with
perl shared libraries
* createlang is also updated, it can create untrusted perl using 'plperlu'
* Example script (assuming you have Mail::Sendmail installed):
create function foo() returns text as '
use Mail::Sendmail;
%mail = ( To => q(you@yourname.com),
From => q(me@here.com),
Message => "This is a very short message"
);
sendmail(%mail) or die $Mail::Sendmail::error;
return "OK. Log says:\n", $Mail::Sendmail::log;
' language 'plperlu';
Alex Pilosov
2001-06-18 23:40:06 +02:00
|
|
|
static void plperl_init_interp(void);
|
2000-01-20 06:08:58 +01:00
|
|
|
|
2001-03-22 05:01:46 +01:00
|
|
|
Datum plperl_call_handler(PG_FUNCTION_ARGS);
|
2005-06-22 18:45:51 +02:00
|
|
|
Datum plperl_validator(PG_FUNCTION_ARGS);
|
2003-07-31 20:36:46 +02:00
|
|
|
void plperl_init(void);
|
2000-01-20 06:08:58 +01:00
|
|
|
|
2004-11-17 22:23:36 +01:00
|
|
|
HV *plperl_spi_exec(char *query, int limit);
|
2005-07-10 17:19:43 +02:00
|
|
|
SV *plperl_spi_query(char *);
|
2004-11-17 22:23:36 +01:00
|
|
|
|
2000-05-28 19:56:29 +02:00
|
|
|
static Datum plperl_func_handler(PG_FUNCTION_ARGS);
|
2000-01-20 06:08:58 +01:00
|
|
|
|
2004-07-01 22:50:22 +02:00
|
|
|
static Datum plperl_trigger_handler(PG_FUNCTION_ARGS);
|
2001-10-20 00:43:49 +02:00
|
|
|
static plperl_proc_desc *compile_plperl_function(Oid fn_oid, bool is_trigger);
|
|
|
|
|
2004-11-23 01:21:24 +01:00
|
|
|
static SV *plperl_hash_from_tuple(HeapTuple tuple, TupleDesc tupdesc);
|
2002-01-24 22:40:44 +01:00
|
|
|
static void plperl_init_shared_libs(pTHX);
|
2004-09-13 22:10:13 +02:00
|
|
|
static HV *plperl_spi_execute_fetch_result(SPITupleTable *, int, int);
|
2000-01-20 06:08:58 +01:00
|
|
|
|
At 2005-05-21 20:18:50 +0530, ams@oryx.com wrote:
>
> > The second issue is where plperl returns a large result set.
I have attached the following seven patches to address this problem:
1. Trivial. Replaces some errant spaces with tabs.
2. Trivial. Fixes the spelling of Jan's name, and gets rid of many
inane, useless, annoying, and often misleading comments. Here's
a sample: "plperl_init_all() - Initialize all".
(I have tried to add some useful comments here and there, and will
continue to do so now and again.)
3. Trivial. Splits up some long lines.
4. Converts SRFs in PL/Perl to use a Tuplestore and SFRM_Materialize
to return the result set, based on the PL/PgSQL model.
There are two major consequences: result sets will spill to disk when
they can no longer fit in work_mem; and "select foo_srf()" no longer
works. (I didn't lose sleep over the latter, since that form is not
valid in PL/PgSQL, and it's not documented in PL/Perl.)
5. Trivial, but important. Fixes use of "undef" instead of undef. This
would cause empty functions to fail in bizarre ways. I suspect that
there's still another (old) bug here. I'll investigate further.
6. Moves the majority of (4) out into a new plperl_return_next()
function, to make it possible to expose the functionality to
Perl; cleans up some of the code besides.
7. Add an spi_return_next function for use in Perl code.
If you want to apply the patches and try them out, 8-composite.diff is
what you should use. (Note: my patches depend upon Andrew's use-strict
and %_SHARED patches being applied.)
Here's something to try:
create or replace function foo() returns setof record as $$
$i = 0;
for ("World", "PostgreSQL", "PL/Perl") {
spi_return_next({f1=>++$i, f2=>'Hello', f3=>$_});
}
return;
$$ language plperl;
select * from foo() as (f1 integer, f2 text, f3 text);
(Many thanks to Andrews Dunstan and Supernews for their help.)
Abhijit Menon-Sen
2005-06-04 22:33:06 +02:00
|
|
|
void plperl_return_next(SV *);
|
2000-01-20 06:08:58 +01:00
|
|
|
|
2001-06-01 20:17:44 +02:00
|
|
|
/*
|
|
|
|
* This routine is a crock, and so is everyplace that calls it. The problem
|
|
|
|
* is that the cached form of plperl functions/queries is allocated permanently
|
|
|
|
* (mostly via malloc()) and never released until backend exit. Subsidiary
|
|
|
|
* data structures such as fmgr info records therefore must live forever
|
|
|
|
* as well. A better implementation would store all this stuff in a per-
|
|
|
|
* function memory context that could be reclaimed at need. In the meantime,
|
2001-10-07 01:21:45 +02:00
|
|
|
* fmgr_info_cxt must be called specifying TopMemoryContext so that whatever
|
|
|
|
* it might allocate, and whatever the eventual function might allocate using
|
|
|
|
* fn_mcxt, will live forever too.
|
2001-06-01 20:17:44 +02:00
|
|
|
*/
|
|
|
|
static void
|
|
|
|
perm_fmgr_info(Oid functionId, FmgrInfo *finfo)
|
|
|
|
{
|
2001-10-07 01:21:45 +02:00
|
|
|
fmgr_info_cxt(functionId, finfo, TopMemoryContext);
|
2001-06-01 20:17:44 +02:00
|
|
|
}
|
|
|
|
|
At 2005-05-21 20:18:50 +0530, ams@oryx.com wrote:
>
> > The second issue is where plperl returns a large result set.
I have attached the following seven patches to address this problem:
1. Trivial. Replaces some errant spaces with tabs.
2. Trivial. Fixes the spelling of Jan's name, and gets rid of many
inane, useless, annoying, and often misleading comments. Here's
a sample: "plperl_init_all() - Initialize all".
(I have tried to add some useful comments here and there, and will
continue to do so now and again.)
3. Trivial. Splits up some long lines.
4. Converts SRFs in PL/Perl to use a Tuplestore and SFRM_Materialize
to return the result set, based on the PL/PgSQL model.
There are two major consequences: result sets will spill to disk when
they can no longer fit in work_mem; and "select foo_srf()" no longer
works. (I didn't lose sleep over the latter, since that form is not
valid in PL/PgSQL, and it's not documented in PL/Perl.)
5. Trivial, but important. Fixes use of "undef" instead of undef. This
would cause empty functions to fail in bizarre ways. I suspect that
there's still another (old) bug here. I'll investigate further.
6. Moves the majority of (4) out into a new plperl_return_next()
function, to make it possible to expose the functionality to
Perl; cleans up some of the code besides.
7. Add an spi_return_next function for use in Perl code.
If you want to apply the patches and try them out, 8-composite.diff is
what you should use. (Note: my patches depend upon Andrew's use-strict
and %_SHARED patches being applied.)
Here's something to try:
create or replace function foo() returns setof record as $$
$i = 0;
for ("World", "PostgreSQL", "PL/Perl") {
spi_return_next({f1=>++$i, f2=>'Hello', f3=>$_});
}
return;
$$ language plperl;
select * from foo() as (f1 integer, f2 text, f3 text);
(Many thanks to Andrews Dunstan and Supernews for their help.)
Abhijit Menon-Sen
2005-06-04 22:33:06 +02:00
|
|
|
|
|
|
|
/* Perform initialization during postmaster startup. */
|
|
|
|
|
2003-07-31 20:36:46 +02:00
|
|
|
void
|
|
|
|
plperl_init(void)
|
2000-01-20 06:08:58 +01:00
|
|
|
{
|
|
|
|
if (!plperl_firstcall)
|
|
|
|
return;
|
|
|
|
|
At 2005-05-21 20:18:50 +0530, ams@oryx.com wrote:
>
> > The second issue is where plperl returns a large result set.
I have attached the following seven patches to address this problem:
1. Trivial. Replaces some errant spaces with tabs.
2. Trivial. Fixes the spelling of Jan's name, and gets rid of many
inane, useless, annoying, and often misleading comments. Here's
a sample: "plperl_init_all() - Initialize all".
(I have tried to add some useful comments here and there, and will
continue to do so now and again.)
3. Trivial. Splits up some long lines.
4. Converts SRFs in PL/Perl to use a Tuplestore and SFRM_Materialize
to return the result set, based on the PL/PgSQL model.
There are two major consequences: result sets will spill to disk when
they can no longer fit in work_mem; and "select foo_srf()" no longer
works. (I didn't lose sleep over the latter, since that form is not
valid in PL/PgSQL, and it's not documented in PL/Perl.)
5. Trivial, but important. Fixes use of "undef" instead of undef. This
would cause empty functions to fail in bizarre ways. I suspect that
there's still another (old) bug here. I'll investigate further.
6. Moves the majority of (4) out into a new plperl_return_next()
function, to make it possible to expose the functionality to
Perl; cleans up some of the code besides.
7. Add an spi_return_next function for use in Perl code.
If you want to apply the patches and try them out, 8-composite.diff is
what you should use. (Note: my patches depend upon Andrew's use-strict
and %_SHARED patches being applied.)
Here's something to try:
create or replace function foo() returns setof record as $$
$i = 0;
for ("World", "PostgreSQL", "PL/Perl") {
spi_return_next({f1=>++$i, f2=>'Hello', f3=>$_});
}
return;
$$ language plperl;
select * from foo() as (f1 integer, f2 text, f3 text);
(Many thanks to Andrews Dunstan and Supernews for their help.)
Abhijit Menon-Sen
2005-06-04 22:33:06 +02:00
|
|
|
DefineCustomBoolVariable(
|
|
|
|
"plperl.use_strict",
|
|
|
|
"If true, will compile trusted and untrusted perl code in strict mode",
|
|
|
|
NULL,
|
|
|
|
&plperl_use_strict,
|
|
|
|
PGC_USERSET,
|
|
|
|
NULL, NULL);
|
|
|
|
|
|
|
|
EmitWarningsOnPlaceholders("plperl");
|
2000-01-20 06:08:58 +01:00
|
|
|
|
At 2005-05-21 20:18:50 +0530, ams@oryx.com wrote:
>
> > The second issue is where plperl returns a large result set.
I have attached the following seven patches to address this problem:
1. Trivial. Replaces some errant spaces with tabs.
2. Trivial. Fixes the spelling of Jan's name, and gets rid of many
inane, useless, annoying, and often misleading comments. Here's
a sample: "plperl_init_all() - Initialize all".
(I have tried to add some useful comments here and there, and will
continue to do so now and again.)
3. Trivial. Splits up some long lines.
4. Converts SRFs in PL/Perl to use a Tuplestore and SFRM_Materialize
to return the result set, based on the PL/PgSQL model.
There are two major consequences: result sets will spill to disk when
they can no longer fit in work_mem; and "select foo_srf()" no longer
works. (I didn't lose sleep over the latter, since that form is not
valid in PL/PgSQL, and it's not documented in PL/Perl.)
5. Trivial, but important. Fixes use of "undef" instead of undef. This
would cause empty functions to fail in bizarre ways. I suspect that
there's still another (old) bug here. I'll investigate further.
6. Moves the majority of (4) out into a new plperl_return_next()
function, to make it possible to expose the functionality to
Perl; cleans up some of the code besides.
7. Add an spi_return_next function for use in Perl code.
If you want to apply the patches and try them out, 8-composite.diff is
what you should use. (Note: my patches depend upon Andrew's use-strict
and %_SHARED patches being applied.)
Here's something to try:
create or replace function foo() returns setof record as $$
$i = 0;
for ("World", "PostgreSQL", "PL/Perl") {
spi_return_next({f1=>++$i, f2=>'Hello', f3=>$_});
}
return;
$$ language plperl;
select * from foo() as (f1 integer, f2 text, f3 text);
(Many thanks to Andrews Dunstan and Supernews for their help.)
Abhijit Menon-Sen
2005-06-04 22:33:06 +02:00
|
|
|
plperl_init_interp();
|
2000-01-20 06:08:58 +01:00
|
|
|
plperl_firstcall = 0;
|
|
|
|
}
|
|
|
|
|
At 2005-05-21 20:18:50 +0530, ams@oryx.com wrote:
>
> > The second issue is where plperl returns a large result set.
I have attached the following seven patches to address this problem:
1. Trivial. Replaces some errant spaces with tabs.
2. Trivial. Fixes the spelling of Jan's name, and gets rid of many
inane, useless, annoying, and often misleading comments. Here's
a sample: "plperl_init_all() - Initialize all".
(I have tried to add some useful comments here and there, and will
continue to do so now and again.)
3. Trivial. Splits up some long lines.
4. Converts SRFs in PL/Perl to use a Tuplestore and SFRM_Materialize
to return the result set, based on the PL/PgSQL model.
There are two major consequences: result sets will spill to disk when
they can no longer fit in work_mem; and "select foo_srf()" no longer
works. (I didn't lose sleep over the latter, since that form is not
valid in PL/PgSQL, and it's not documented in PL/Perl.)
5. Trivial, but important. Fixes use of "undef" instead of undef. This
would cause empty functions to fail in bizarre ways. I suspect that
there's still another (old) bug here. I'll investigate further.
6. Moves the majority of (4) out into a new plperl_return_next()
function, to make it possible to expose the functionality to
Perl; cleans up some of the code besides.
7. Add an spi_return_next function for use in Perl code.
If you want to apply the patches and try them out, 8-composite.diff is
what you should use. (Note: my patches depend upon Andrew's use-strict
and %_SHARED patches being applied.)
Here's something to try:
create or replace function foo() returns setof record as $$
$i = 0;
for ("World", "PostgreSQL", "PL/Perl") {
spi_return_next({f1=>++$i, f2=>'Hello', f3=>$_});
}
return;
$$ language plperl;
select * from foo() as (f1 integer, f2 text, f3 text);
(Many thanks to Andrews Dunstan and Supernews for their help.)
Abhijit Menon-Sen
2005-06-04 22:33:06 +02:00
|
|
|
|
|
|
|
/* Perform initialization during backend startup. */
|
|
|
|
|
2003-07-31 20:36:46 +02:00
|
|
|
static void
|
|
|
|
plperl_init_all(void)
|
|
|
|
{
|
|
|
|
if (plperl_firstcall)
|
|
|
|
plperl_init();
|
|
|
|
|
At 2005-05-21 20:18:50 +0530, ams@oryx.com wrote:
>
> > The second issue is where plperl returns a large result set.
I have attached the following seven patches to address this problem:
1. Trivial. Replaces some errant spaces with tabs.
2. Trivial. Fixes the spelling of Jan's name, and gets rid of many
inane, useless, annoying, and often misleading comments. Here's
a sample: "plperl_init_all() - Initialize all".
(I have tried to add some useful comments here and there, and will
continue to do so now and again.)
3. Trivial. Splits up some long lines.
4. Converts SRFs in PL/Perl to use a Tuplestore and SFRM_Materialize
to return the result set, based on the PL/PgSQL model.
There are two major consequences: result sets will spill to disk when
they can no longer fit in work_mem; and "select foo_srf()" no longer
works. (I didn't lose sleep over the latter, since that form is not
valid in PL/PgSQL, and it's not documented in PL/Perl.)
5. Trivial, but important. Fixes use of "undef" instead of undef. This
would cause empty functions to fail in bizarre ways. I suspect that
there's still another (old) bug here. I'll investigate further.
6. Moves the majority of (4) out into a new plperl_return_next()
function, to make it possible to expose the functionality to
Perl; cleans up some of the code besides.
7. Add an spi_return_next function for use in Perl code.
If you want to apply the patches and try them out, 8-composite.diff is
what you should use. (Note: my patches depend upon Andrew's use-strict
and %_SHARED patches being applied.)
Here's something to try:
create or replace function foo() returns setof record as $$
$i = 0;
for ("World", "PostgreSQL", "PL/Perl") {
spi_return_next({f1=>++$i, f2=>'Hello', f3=>$_});
}
return;
$$ language plperl;
select * from foo() as (f1 integer, f2 text, f3 text);
(Many thanks to Andrews Dunstan and Supernews for their help.)
Abhijit Menon-Sen
2005-06-04 22:33:06 +02:00
|
|
|
/* We don't need to do anything yet when a new backend starts. */
|
2003-07-31 20:36:46 +02:00
|
|
|
}
|
|
|
|
|
2000-01-20 06:08:58 +01:00
|
|
|
|
|
|
|
static void
|
Well, after persuading cvsup and cvs that it _is_ possible to have local
modifiable repositories, I have a clean untrusted plperl patch to offer
you :)
Highlights:
* There's one perl interpreter used for both trusted and untrusted
procedures. I do think its unnecessary to keep two perl
interpreters around. If someone can break out from trusted "Safe" perl
mode, well, they can do what they want already. If someone disagrees, I
can change this.
* Opcode is not statically loaded anymore. Instead, we load Dynaloader,
which then can grab Opcode (and anything else you can 'use') on its own.
* Checked to work on FreeBSD 4.3 + perl 5.5.3 , OpenBSD 2.8 + perl5.6.1,
RedHat 6.2 + perl 5.5.3
* Uses ExtUtils::Embed to find what options are necessary to link with
perl shared libraries
* createlang is also updated, it can create untrusted perl using 'plperlu'
* Example script (assuming you have Mail::Sendmail installed):
create function foo() returns text as '
use Mail::Sendmail;
%mail = ( To => q(you@yourname.com),
From => q(me@here.com),
Message => "This is a very short message"
);
sendmail(%mail) or die $Mail::Sendmail::error;
return "OK. Log says:\n", $Mail::Sendmail::log;
' language 'plperlu';
Alex Pilosov
2001-06-18 23:40:06 +02:00
|
|
|
plperl_init_interp(void)
|
2000-01-20 06:08:58 +01:00
|
|
|
{
|
At 2005-05-21 20:18:50 +0530, ams@oryx.com wrote:
>
> > The second issue is where plperl returns a large result set.
I have attached the following seven patches to address this problem:
1. Trivial. Replaces some errant spaces with tabs.
2. Trivial. Fixes the spelling of Jan's name, and gets rid of many
inane, useless, annoying, and often misleading comments. Here's
a sample: "plperl_init_all() - Initialize all".
(I have tried to add some useful comments here and there, and will
continue to do so now and again.)
3. Trivial. Splits up some long lines.
4. Converts SRFs in PL/Perl to use a Tuplestore and SFRM_Materialize
to return the result set, based on the PL/PgSQL model.
There are two major consequences: result sets will spill to disk when
they can no longer fit in work_mem; and "select foo_srf()" no longer
works. (I didn't lose sleep over the latter, since that form is not
valid in PL/PgSQL, and it's not documented in PL/Perl.)
5. Trivial, but important. Fixes use of "undef" instead of undef. This
would cause empty functions to fail in bizarre ways. I suspect that
there's still another (old) bug here. I'll investigate further.
6. Moves the majority of (4) out into a new plperl_return_next()
function, to make it possible to expose the functionality to
Perl; cleans up some of the code besides.
7. Add an spi_return_next function for use in Perl code.
If you want to apply the patches and try them out, 8-composite.diff is
what you should use. (Note: my patches depend upon Andrew's use-strict
and %_SHARED patches being applied.)
Here's something to try:
create or replace function foo() returns setof record as $$
$i = 0;
for ("World", "PostgreSQL", "PL/Perl") {
spi_return_next({f1=>++$i, f2=>'Hello', f3=>$_});
}
return;
$$ language plperl;
select * from foo() as (f1 integer, f2 text, f3 text);
(Many thanks to Andrews Dunstan and Supernews for their help.)
Abhijit Menon-Sen
2005-06-04 22:33:06 +02:00
|
|
|
static char *loose_embedding[3] = {
|
2001-03-22 05:01:46 +01:00
|
|
|
"", "-e",
|
At 2005-05-21 20:18:50 +0530, ams@oryx.com wrote:
>
> > The second issue is where plperl returns a large result set.
I have attached the following seven patches to address this problem:
1. Trivial. Replaces some errant spaces with tabs.
2. Trivial. Fixes the spelling of Jan's name, and gets rid of many
inane, useless, annoying, and often misleading comments. Here's
a sample: "plperl_init_all() - Initialize all".
(I have tried to add some useful comments here and there, and will
continue to do so now and again.)
3. Trivial. Splits up some long lines.
4. Converts SRFs in PL/Perl to use a Tuplestore and SFRM_Materialize
to return the result set, based on the PL/PgSQL model.
There are two major consequences: result sets will spill to disk when
they can no longer fit in work_mem; and "select foo_srf()" no longer
works. (I didn't lose sleep over the latter, since that form is not
valid in PL/PgSQL, and it's not documented in PL/Perl.)
5. Trivial, but important. Fixes use of "undef" instead of undef. This
would cause empty functions to fail in bizarre ways. I suspect that
there's still another (old) bug here. I'll investigate further.
6. Moves the majority of (4) out into a new plperl_return_next()
function, to make it possible to expose the functionality to
Perl; cleans up some of the code besides.
7. Add an spi_return_next function for use in Perl code.
If you want to apply the patches and try them out, 8-composite.diff is
what you should use. (Note: my patches depend upon Andrew's use-strict
and %_SHARED patches being applied.)
Here's something to try:
create or replace function foo() returns setof record as $$
$i = 0;
for ("World", "PostgreSQL", "PL/Perl") {
spi_return_next({f1=>++$i, f2=>'Hello', f3=>$_});
}
return;
$$ language plperl;
select * from foo() as (f1 integer, f2 text, f3 text);
(Many thanks to Andrews Dunstan and Supernews for their help.)
Abhijit Menon-Sen
2005-06-04 22:33:06 +02:00
|
|
|
/* all one string follows (no commas please) */
|
The attached patch, which incorporates the previous one sent and
currently unapplied regarding spi_internal.c, makes some additional
fixes relating to return types, and also contains the fix for
preventing the use of insecure versions of Safe.pm.
There is one remaing return case that does not appear to work, namely
return of a composite directly in a select, i.e. if foo returns some
composite type, 'select * from foo()' works but 'select foo()' doesn't.
We will either fix that or document it as a limitation.
The function plperl_func_handler is a mess - I will try to get it
cleaned up (and split up) in a subsequent patch, time permitting.
Also, reiterating previous advice - this changes slightly the API for
spi_exec_query - the returned object has either 2 or 3 members: 'status'
(string) and 'proceesed' (int,- number of rows) and, if rows are
returned, 'rows' (array of tuple hashes).
Andrew Dunstan
2004-07-12 16:31:04 +02:00
|
|
|
"SPI::bootstrap(); use vars qw(%_SHARED);"
|
2005-07-07 00:33:39 +02:00
|
|
|
"sub ::plperl_warn { my $msg = shift; &elog(&NOTICE, $msg); } "
|
|
|
|
"$SIG{__WARN__} = \\&::plperl_warn; "
|
2004-07-01 22:50:22 +02:00
|
|
|
"sub ::mkunsafefunc {return eval(qq[ sub { $_[0] $_[1] } ]); }"
|
2005-07-10 17:32:47 +02:00
|
|
|
"sub ::_plperl_to_pg_array"
|
|
|
|
"{"
|
|
|
|
" my $arg = shift; ref $arg eq 'ARRAY' || return $arg; "
|
|
|
|
" my $res = ''; my $first = 1; "
|
|
|
|
" foreach my $elem (@$arg) "
|
|
|
|
" { "
|
|
|
|
" $res .= ', ' unless $first; $first = undef; "
|
|
|
|
" if (ref $elem) "
|
|
|
|
" { "
|
|
|
|
" $res .= _plperl_to_pg_array($elem); "
|
|
|
|
" } "
|
|
|
|
" else "
|
|
|
|
" { "
|
|
|
|
" my $str = qq($elem); "
|
|
|
|
" $str =~ s/([\"\\\\])/\\\\$1/g; "
|
|
|
|
" $res .= qq(\"$str\"); "
|
|
|
|
" } "
|
|
|
|
" } "
|
|
|
|
" return qq({$res}); "
|
|
|
|
"} "
|
2001-03-22 05:01:46 +01:00
|
|
|
};
|
2000-01-20 06:08:58 +01:00
|
|
|
|
2005-07-10 17:32:47 +02:00
|
|
|
|
At 2005-05-21 20:18:50 +0530, ams@oryx.com wrote:
>
> > The second issue is where plperl returns a large result set.
I have attached the following seven patches to address this problem:
1. Trivial. Replaces some errant spaces with tabs.
2. Trivial. Fixes the spelling of Jan's name, and gets rid of many
inane, useless, annoying, and often misleading comments. Here's
a sample: "plperl_init_all() - Initialize all".
(I have tried to add some useful comments here and there, and will
continue to do so now and again.)
3. Trivial. Splits up some long lines.
4. Converts SRFs in PL/Perl to use a Tuplestore and SFRM_Materialize
to return the result set, based on the PL/PgSQL model.
There are two major consequences: result sets will spill to disk when
they can no longer fit in work_mem; and "select foo_srf()" no longer
works. (I didn't lose sleep over the latter, since that form is not
valid in PL/PgSQL, and it's not documented in PL/Perl.)
5. Trivial, but important. Fixes use of "undef" instead of undef. This
would cause empty functions to fail in bizarre ways. I suspect that
there's still another (old) bug here. I'll investigate further.
6. Moves the majority of (4) out into a new plperl_return_next()
function, to make it possible to expose the functionality to
Perl; cleans up some of the code besides.
7. Add an spi_return_next function for use in Perl code.
If you want to apply the patches and try them out, 8-composite.diff is
what you should use. (Note: my patches depend upon Andrew's use-strict
and %_SHARED patches being applied.)
Here's something to try:
create or replace function foo() returns setof record as $$
$i = 0;
for ("World", "PostgreSQL", "PL/Perl") {
spi_return_next({f1=>++$i, f2=>'Hello', f3=>$_});
}
return;
$$ language plperl;
select * from foo() as (f1 integer, f2 text, f3 text);
(Many thanks to Andrews Dunstan and Supernews for their help.)
Abhijit Menon-Sen
2005-06-04 22:33:06 +02:00
|
|
|
static char *strict_embedding[3] = {
|
|
|
|
"", "-e",
|
|
|
|
/* all one string follows (no commas please) */
|
|
|
|
"SPI::bootstrap(); use vars qw(%_SHARED);"
|
2005-07-07 00:33:39 +02:00
|
|
|
"sub ::plperl_warn { my $msg = shift; &elog(&NOTICE, $msg); } "
|
|
|
|
"$SIG{__WARN__} = \\&::plperl_warn; "
|
At 2005-05-21 20:18:50 +0530, ams@oryx.com wrote:
>
> > The second issue is where plperl returns a large result set.
I have attached the following seven patches to address this problem:
1. Trivial. Replaces some errant spaces with tabs.
2. Trivial. Fixes the spelling of Jan's name, and gets rid of many
inane, useless, annoying, and often misleading comments. Here's
a sample: "plperl_init_all() - Initialize all".
(I have tried to add some useful comments here and there, and will
continue to do so now and again.)
3. Trivial. Splits up some long lines.
4. Converts SRFs in PL/Perl to use a Tuplestore and SFRM_Materialize
to return the result set, based on the PL/PgSQL model.
There are two major consequences: result sets will spill to disk when
they can no longer fit in work_mem; and "select foo_srf()" no longer
works. (I didn't lose sleep over the latter, since that form is not
valid in PL/PgSQL, and it's not documented in PL/Perl.)
5. Trivial, but important. Fixes use of "undef" instead of undef. This
would cause empty functions to fail in bizarre ways. I suspect that
there's still another (old) bug here. I'll investigate further.
6. Moves the majority of (4) out into a new plperl_return_next()
function, to make it possible to expose the functionality to
Perl; cleans up some of the code besides.
7. Add an spi_return_next function for use in Perl code.
If you want to apply the patches and try them out, 8-composite.diff is
what you should use. (Note: my patches depend upon Andrew's use-strict
and %_SHARED patches being applied.)
Here's something to try:
create or replace function foo() returns setof record as $$
$i = 0;
for ("World", "PostgreSQL", "PL/Perl") {
spi_return_next({f1=>++$i, f2=>'Hello', f3=>$_});
}
return;
$$ language plperl;
select * from foo() as (f1 integer, f2 text, f3 text);
(Many thanks to Andrews Dunstan and Supernews for their help.)
Abhijit Menon-Sen
2005-06-04 22:33:06 +02:00
|
|
|
"sub ::mkunsafefunc {return eval("
|
|
|
|
"qq[ sub { use strict; $_[0] $_[1] } ]); }"
|
|
|
|
};
|
|
|
|
|
Well, after persuading cvsup and cvs that it _is_ possible to have local
modifiable repositories, I have a clean untrusted plperl patch to offer
you :)
Highlights:
* There's one perl interpreter used for both trusted and untrusted
procedures. I do think its unnecessary to keep two perl
interpreters around. If someone can break out from trusted "Safe" perl
mode, well, they can do what they want already. If someone disagrees, I
can change this.
* Opcode is not statically loaded anymore. Instead, we load Dynaloader,
which then can grab Opcode (and anything else you can 'use') on its own.
* Checked to work on FreeBSD 4.3 + perl 5.5.3 , OpenBSD 2.8 + perl5.6.1,
RedHat 6.2 + perl 5.5.3
* Uses ExtUtils::Embed to find what options are necessary to link with
perl shared libraries
* createlang is also updated, it can create untrusted perl using 'plperlu'
* Example script (assuming you have Mail::Sendmail installed):
create function foo() returns text as '
use Mail::Sendmail;
%mail = ( To => q(you@yourname.com),
From => q(me@here.com),
Message => "This is a very short message"
);
sendmail(%mail) or die $Mail::Sendmail::error;
return "OK. Log says:\n", $Mail::Sendmail::log;
' language 'plperlu';
Alex Pilosov
2001-06-18 23:40:06 +02:00
|
|
|
plperl_interp = perl_alloc();
|
|
|
|
if (!plperl_interp)
|
2004-11-29 21:11:06 +01:00
|
|
|
elog(ERROR, "could not allocate Perl interpreter");
|
2000-01-20 06:08:58 +01:00
|
|
|
|
Well, after persuading cvsup and cvs that it _is_ possible to have local
modifiable repositories, I have a clean untrusted plperl patch to offer
you :)
Highlights:
* There's one perl interpreter used for both trusted and untrusted
procedures. I do think its unnecessary to keep two perl
interpreters around. If someone can break out from trusted "Safe" perl
mode, well, they can do what they want already. If someone disagrees, I
can change this.
* Opcode is not statically loaded anymore. Instead, we load Dynaloader,
which then can grab Opcode (and anything else you can 'use') on its own.
* Checked to work on FreeBSD 4.3 + perl 5.5.3 , OpenBSD 2.8 + perl5.6.1,
RedHat 6.2 + perl 5.5.3
* Uses ExtUtils::Embed to find what options are necessary to link with
perl shared libraries
* createlang is also updated, it can create untrusted perl using 'plperlu'
* Example script (assuming you have Mail::Sendmail installed):
create function foo() returns text as '
use Mail::Sendmail;
%mail = ( To => q(you@yourname.com),
From => q(me@here.com),
Message => "This is a very short message"
);
sendmail(%mail) or die $Mail::Sendmail::error;
return "OK. Log says:\n", $Mail::Sendmail::log;
' language 'plperlu';
Alex Pilosov
2001-06-18 23:40:06 +02:00
|
|
|
perl_construct(plperl_interp);
|
At 2005-05-21 20:18:50 +0530, ams@oryx.com wrote:
>
> > The second issue is where plperl returns a large result set.
I have attached the following seven patches to address this problem:
1. Trivial. Replaces some errant spaces with tabs.
2. Trivial. Fixes the spelling of Jan's name, and gets rid of many
inane, useless, annoying, and often misleading comments. Here's
a sample: "plperl_init_all() - Initialize all".
(I have tried to add some useful comments here and there, and will
continue to do so now and again.)
3. Trivial. Splits up some long lines.
4. Converts SRFs in PL/Perl to use a Tuplestore and SFRM_Materialize
to return the result set, based on the PL/PgSQL model.
There are two major consequences: result sets will spill to disk when
they can no longer fit in work_mem; and "select foo_srf()" no longer
works. (I didn't lose sleep over the latter, since that form is not
valid in PL/PgSQL, and it's not documented in PL/Perl.)
5. Trivial, but important. Fixes use of "undef" instead of undef. This
would cause empty functions to fail in bizarre ways. I suspect that
there's still another (old) bug here. I'll investigate further.
6. Moves the majority of (4) out into a new plperl_return_next()
function, to make it possible to expose the functionality to
Perl; cleans up some of the code besides.
7. Add an spi_return_next function for use in Perl code.
If you want to apply the patches and try them out, 8-composite.diff is
what you should use. (Note: my patches depend upon Andrew's use-strict
and %_SHARED patches being applied.)
Here's something to try:
create or replace function foo() returns setof record as $$
$i = 0;
for ("World", "PostgreSQL", "PL/Perl") {
spi_return_next({f1=>++$i, f2=>'Hello', f3=>$_});
}
return;
$$ language plperl;
select * from foo() as (f1 integer, f2 text, f3 text);
(Many thanks to Andrews Dunstan and Supernews for their help.)
Abhijit Menon-Sen
2005-06-04 22:33:06 +02:00
|
|
|
perl_parse(plperl_interp, plperl_init_shared_libs, 3 ,
|
|
|
|
(plperl_use_strict ? strict_embedding : loose_embedding), NULL);
|
Well, after persuading cvsup and cvs that it _is_ possible to have local
modifiable repositories, I have a clean untrusted plperl patch to offer
you :)
Highlights:
* There's one perl interpreter used for both trusted and untrusted
procedures. I do think its unnecessary to keep two perl
interpreters around. If someone can break out from trusted "Safe" perl
mode, well, they can do what they want already. If someone disagrees, I
can change this.
* Opcode is not statically loaded anymore. Instead, we load Dynaloader,
which then can grab Opcode (and anything else you can 'use') on its own.
* Checked to work on FreeBSD 4.3 + perl 5.5.3 , OpenBSD 2.8 + perl5.6.1,
RedHat 6.2 + perl 5.5.3
* Uses ExtUtils::Embed to find what options are necessary to link with
perl shared libraries
* createlang is also updated, it can create untrusted perl using 'plperlu'
* Example script (assuming you have Mail::Sendmail installed):
create function foo() returns text as '
use Mail::Sendmail;
%mail = ( To => q(you@yourname.com),
From => q(me@here.com),
Message => "This is a very short message"
);
sendmail(%mail) or die $Mail::Sendmail::error;
return "OK. Log says:\n", $Mail::Sendmail::log;
' language 'plperlu';
Alex Pilosov
2001-06-18 23:40:06 +02:00
|
|
|
perl_run(plperl_interp);
|
2000-01-20 06:08:58 +01:00
|
|
|
|
2000-04-12 19:17:23 +02:00
|
|
|
plperl_proc_hash = newHV();
|
2000-01-20 06:08:58 +01:00
|
|
|
}
|
|
|
|
|
The attached patch, which incorporates the previous one sent and
currently unapplied regarding spi_internal.c, makes some additional
fixes relating to return types, and also contains the fix for
preventing the use of insecure versions of Safe.pm.
There is one remaing return case that does not appear to work, namely
return of a composite directly in a select, i.e. if foo returns some
composite type, 'select * from foo()' works but 'select foo()' doesn't.
We will either fix that or document it as a limitation.
The function plperl_func_handler is a mess - I will try to get it
cleaned up (and split up) in a subsequent patch, time permitting.
Also, reiterating previous advice - this changes slightly the API for
spi_exec_query - the returned object has either 2 or 3 members: 'status'
(string) and 'proceesed' (int,- number of rows) and, if rows are
returned, 'rows' (array of tuple hashes).
Andrew Dunstan
2004-07-12 16:31:04 +02:00
|
|
|
|
|
|
|
static void
|
|
|
|
plperl_safe_init(void)
|
|
|
|
{
|
2004-08-29 07:07:03 +02:00
|
|
|
static char *safe_module =
|
|
|
|
"require Safe; $Safe::VERSION";
|
The attached patch, which incorporates the previous one sent and
currently unapplied regarding spi_internal.c, makes some additional
fixes relating to return types, and also contains the fix for
preventing the use of insecure versions of Safe.pm.
There is one remaing return case that does not appear to work, namely
return of a composite directly in a select, i.e. if foo returns some
composite type, 'select * from foo()' works but 'select foo()' doesn't.
We will either fix that or document it as a limitation.
The function plperl_func_handler is a mess - I will try to get it
cleaned up (and split up) in a subsequent patch, time permitting.
Also, reiterating previous advice - this changes slightly the API for
spi_exec_query - the returned object has either 2 or 3 members: 'status'
(string) and 'proceesed' (int,- number of rows) and, if rows are
returned, 'rows' (array of tuple hashes).
Andrew Dunstan
2004-07-12 16:31:04 +02:00
|
|
|
|
At 2005-05-21 20:18:50 +0530, ams@oryx.com wrote:
>
> > The second issue is where plperl returns a large result set.
I have attached the following seven patches to address this problem:
1. Trivial. Replaces some errant spaces with tabs.
2. Trivial. Fixes the spelling of Jan's name, and gets rid of many
inane, useless, annoying, and often misleading comments. Here's
a sample: "plperl_init_all() - Initialize all".
(I have tried to add some useful comments here and there, and will
continue to do so now and again.)
3. Trivial. Splits up some long lines.
4. Converts SRFs in PL/Perl to use a Tuplestore and SFRM_Materialize
to return the result set, based on the PL/PgSQL model.
There are two major consequences: result sets will spill to disk when
they can no longer fit in work_mem; and "select foo_srf()" no longer
works. (I didn't lose sleep over the latter, since that form is not
valid in PL/PgSQL, and it's not documented in PL/Perl.)
5. Trivial, but important. Fixes use of "undef" instead of undef. This
would cause empty functions to fail in bizarre ways. I suspect that
there's still another (old) bug here. I'll investigate further.
6. Moves the majority of (4) out into a new plperl_return_next()
function, to make it possible to expose the functionality to
Perl; cleans up some of the code besides.
7. Add an spi_return_next function for use in Perl code.
If you want to apply the patches and try them out, 8-composite.diff is
what you should use. (Note: my patches depend upon Andrew's use-strict
and %_SHARED patches being applied.)
Here's something to try:
create or replace function foo() returns setof record as $$
$i = 0;
for ("World", "PostgreSQL", "PL/Perl") {
spi_return_next({f1=>++$i, f2=>'Hello', f3=>$_});
}
return;
$$ language plperl;
select * from foo() as (f1 integer, f2 text, f3 text);
(Many thanks to Andrews Dunstan and Supernews for their help.)
Abhijit Menon-Sen
2005-06-04 22:33:06 +02:00
|
|
|
static char *common_safe_ok =
|
2004-08-29 07:07:03 +02:00
|
|
|
"use vars qw($PLContainer); $PLContainer = new Safe('PLPerl');"
|
2004-11-16 23:05:22 +01:00
|
|
|
"$PLContainer->permit_only(':default');"
|
|
|
|
"$PLContainer->permit(qw[:base_math !:base_io sort time]);"
|
2005-06-05 05:16:42 +02:00
|
|
|
"$PLContainer->share(qw[&elog &spi_exec_query &return_next "
|
2005-07-10 17:19:43 +02:00
|
|
|
"&spi_query &spi_fetchrow "
|
2005-07-10 17:32:47 +02:00
|
|
|
"&_plperl_to_pg_array "
|
At 2005-05-21 20:18:50 +0530, ams@oryx.com wrote:
>
> > The second issue is where plperl returns a large result set.
I have attached the following seven patches to address this problem:
1. Trivial. Replaces some errant spaces with tabs.
2. Trivial. Fixes the spelling of Jan's name, and gets rid of many
inane, useless, annoying, and often misleading comments. Here's
a sample: "plperl_init_all() - Initialize all".
(I have tried to add some useful comments here and there, and will
continue to do so now and again.)
3. Trivial. Splits up some long lines.
4. Converts SRFs in PL/Perl to use a Tuplestore and SFRM_Materialize
to return the result set, based on the PL/PgSQL model.
There are two major consequences: result sets will spill to disk when
they can no longer fit in work_mem; and "select foo_srf()" no longer
works. (I didn't lose sleep over the latter, since that form is not
valid in PL/PgSQL, and it's not documented in PL/Perl.)
5. Trivial, but important. Fixes use of "undef" instead of undef. This
would cause empty functions to fail in bizarre ways. I suspect that
there's still another (old) bug here. I'll investigate further.
6. Moves the majority of (4) out into a new plperl_return_next()
function, to make it possible to expose the functionality to
Perl; cleans up some of the code besides.
7. Add an spi_return_next function for use in Perl code.
If you want to apply the patches and try them out, 8-composite.diff is
what you should use. (Note: my patches depend upon Andrew's use-strict
and %_SHARED patches being applied.)
Here's something to try:
create or replace function foo() returns setof record as $$
$i = 0;
for ("World", "PostgreSQL", "PL/Perl") {
spi_return_next({f1=>++$i, f2=>'Hello', f3=>$_});
}
return;
$$ language plperl;
select * from foo() as (f1 integer, f2 text, f3 text);
(Many thanks to Andrews Dunstan and Supernews for their help.)
Abhijit Menon-Sen
2005-06-04 22:33:06 +02:00
|
|
|
"&DEBUG &LOG &INFO &NOTICE &WARNING &ERROR %_SHARED ]);"
|
2004-08-29 07:07:03 +02:00
|
|
|
;
|
The attached patch, which incorporates the previous one sent and
currently unapplied regarding spi_internal.c, makes some additional
fixes relating to return types, and also contains the fix for
preventing the use of insecure versions of Safe.pm.
There is one remaing return case that does not appear to work, namely
return of a composite directly in a select, i.e. if foo returns some
composite type, 'select * from foo()' works but 'select foo()' doesn't.
We will either fix that or document it as a limitation.
The function plperl_func_handler is a mess - I will try to get it
cleaned up (and split up) in a subsequent patch, time permitting.
Also, reiterating previous advice - this changes slightly the API for
spi_exec_query - the returned object has either 2 or 3 members: 'status'
(string) and 'proceesed' (int,- number of rows) and, if rows are
returned, 'rows' (array of tuple hashes).
Andrew Dunstan
2004-07-12 16:31:04 +02:00
|
|
|
|
At 2005-05-21 20:18:50 +0530, ams@oryx.com wrote:
>
> > The second issue is where plperl returns a large result set.
I have attached the following seven patches to address this problem:
1. Trivial. Replaces some errant spaces with tabs.
2. Trivial. Fixes the spelling of Jan's name, and gets rid of many
inane, useless, annoying, and often misleading comments. Here's
a sample: "plperl_init_all() - Initialize all".
(I have tried to add some useful comments here and there, and will
continue to do so now and again.)
3. Trivial. Splits up some long lines.
4. Converts SRFs in PL/Perl to use a Tuplestore and SFRM_Materialize
to return the result set, based on the PL/PgSQL model.
There are two major consequences: result sets will spill to disk when
they can no longer fit in work_mem; and "select foo_srf()" no longer
works. (I didn't lose sleep over the latter, since that form is not
valid in PL/PgSQL, and it's not documented in PL/Perl.)
5. Trivial, but important. Fixes use of "undef" instead of undef. This
would cause empty functions to fail in bizarre ways. I suspect that
there's still another (old) bug here. I'll investigate further.
6. Moves the majority of (4) out into a new plperl_return_next()
function, to make it possible to expose the functionality to
Perl; cleans up some of the code besides.
7. Add an spi_return_next function for use in Perl code.
If you want to apply the patches and try them out, 8-composite.diff is
what you should use. (Note: my patches depend upon Andrew's use-strict
and %_SHARED patches being applied.)
Here's something to try:
create or replace function foo() returns setof record as $$
$i = 0;
for ("World", "PostgreSQL", "PL/Perl") {
spi_return_next({f1=>++$i, f2=>'Hello', f3=>$_});
}
return;
$$ language plperl;
select * from foo() as (f1 integer, f2 text, f3 text);
(Many thanks to Andrews Dunstan and Supernews for their help.)
Abhijit Menon-Sen
2005-06-04 22:33:06 +02:00
|
|
|
static char * strict_safe_ok =
|
|
|
|
"$PLContainer->permit('require');$PLContainer->reval('use strict;');"
|
|
|
|
"$PLContainer->deny('require');"
|
|
|
|
"sub ::mksafefunc { return $PLContainer->reval(qq[ "
|
|
|
|
" sub { BEGIN { strict->import(); } $_[0] $_[1]}]); }"
|
|
|
|
;
|
|
|
|
|
|
|
|
static char * loose_safe_ok =
|
|
|
|
"sub ::mksafefunc { return $PLContainer->reval(qq[ "
|
|
|
|
" sub { $_[0] $_[1]}]); }"
|
|
|
|
;
|
|
|
|
|
2004-08-29 07:07:03 +02:00
|
|
|
static char *safe_bad =
|
|
|
|
"use vars qw($PLContainer); $PLContainer = new Safe('PLPerl');"
|
2004-11-16 23:05:22 +01:00
|
|
|
"$PLContainer->permit_only(':default');"
|
|
|
|
"$PLContainer->share(qw[&elog &ERROR ]);"
|
2004-08-29 07:07:03 +02:00
|
|
|
"sub ::mksafefunc { return $PLContainer->reval(qq[sub { "
|
2004-11-29 21:11:06 +01:00
|
|
|
"elog(ERROR,'trusted Perl functions disabled - "
|
At 2005-05-21 20:18:50 +0530, ams@oryx.com wrote:
>
> > The second issue is where plperl returns a large result set.
I have attached the following seven patches to address this problem:
1. Trivial. Replaces some errant spaces with tabs.
2. Trivial. Fixes the spelling of Jan's name, and gets rid of many
inane, useless, annoying, and often misleading comments. Here's
a sample: "plperl_init_all() - Initialize all".
(I have tried to add some useful comments here and there, and will
continue to do so now and again.)
3. Trivial. Splits up some long lines.
4. Converts SRFs in PL/Perl to use a Tuplestore and SFRM_Materialize
to return the result set, based on the PL/PgSQL model.
There are two major consequences: result sets will spill to disk when
they can no longer fit in work_mem; and "select foo_srf()" no longer
works. (I didn't lose sleep over the latter, since that form is not
valid in PL/PgSQL, and it's not documented in PL/Perl.)
5. Trivial, but important. Fixes use of "undef" instead of undef. This
would cause empty functions to fail in bizarre ways. I suspect that
there's still another (old) bug here. I'll investigate further.
6. Moves the majority of (4) out into a new plperl_return_next()
function, to make it possible to expose the functionality to
Perl; cleans up some of the code besides.
7. Add an spi_return_next function for use in Perl code.
If you want to apply the patches and try them out, 8-composite.diff is
what you should use. (Note: my patches depend upon Andrew's use-strict
and %_SHARED patches being applied.)
Here's something to try:
create or replace function foo() returns setof record as $$
$i = 0;
for ("World", "PostgreSQL", "PL/Perl") {
spi_return_next({f1=>++$i, f2=>'Hello', f3=>$_});
}
return;
$$ language plperl;
select * from foo() as (f1 integer, f2 text, f3 text);
(Many thanks to Andrews Dunstan and Supernews for their help.)
Abhijit Menon-Sen
2005-06-04 22:33:06 +02:00
|
|
|
"please upgrade Perl Safe module to version 2.09 or later');}]); }"
|
2004-08-29 07:07:03 +02:00
|
|
|
;
|
The attached patch, which incorporates the previous one sent and
currently unapplied regarding spi_internal.c, makes some additional
fixes relating to return types, and also contains the fix for
preventing the use of insecure versions of Safe.pm.
There is one remaing return case that does not appear to work, namely
return of a composite directly in a select, i.e. if foo returns some
composite type, 'select * from foo()' works but 'select foo()' doesn't.
We will either fix that or document it as a limitation.
The function plperl_func_handler is a mess - I will try to get it
cleaned up (and split up) in a subsequent patch, time permitting.
Also, reiterating previous advice - this changes slightly the API for
spi_exec_query - the returned object has either 2 or 3 members: 'status'
(string) and 'proceesed' (int,- number of rows) and, if rows are
returned, 'rows' (array of tuple hashes).
Andrew Dunstan
2004-07-12 16:31:04 +02:00
|
|
|
|
2004-08-29 07:07:03 +02:00
|
|
|
SV *res;
|
2004-11-24 19:47:38 +01:00
|
|
|
double safe_version;
|
The attached patch, which incorporates the previous one sent and
currently unapplied regarding spi_internal.c, makes some additional
fixes relating to return types, and also contains the fix for
preventing the use of insecure versions of Safe.pm.
There is one remaing return case that does not appear to work, namely
return of a composite directly in a select, i.e. if foo returns some
composite type, 'select * from foo()' works but 'select foo()' doesn't.
We will either fix that or document it as a limitation.
The function plperl_func_handler is a mess - I will try to get it
cleaned up (and split up) in a subsequent patch, time permitting.
Also, reiterating previous advice - this changes slightly the API for
spi_exec_query - the returned object has either 2 or 3 members: 'status'
(string) and 'proceesed' (int,- number of rows) and, if rows are
returned, 'rows' (array of tuple hashes).
Andrew Dunstan
2004-07-12 16:31:04 +02:00
|
|
|
|
2004-08-29 07:07:03 +02:00
|
|
|
res = eval_pv(safe_module, FALSE); /* TRUE = croak if failure */
|
The attached patch, which incorporates the previous one sent and
currently unapplied regarding spi_internal.c, makes some additional
fixes relating to return types, and also contains the fix for
preventing the use of insecure versions of Safe.pm.
There is one remaing return case that does not appear to work, namely
return of a composite directly in a select, i.e. if foo returns some
composite type, 'select * from foo()' works but 'select foo()' doesn't.
We will either fix that or document it as a limitation.
The function plperl_func_handler is a mess - I will try to get it
cleaned up (and split up) in a subsequent patch, time permitting.
Also, reiterating previous advice - this changes slightly the API for
spi_exec_query - the returned object has either 2 or 3 members: 'status'
(string) and 'proceesed' (int,- number of rows) and, if rows are
returned, 'rows' (array of tuple hashes).
Andrew Dunstan
2004-07-12 16:31:04 +02:00
|
|
|
|
|
|
|
safe_version = SvNV(res);
|
|
|
|
|
2004-11-24 19:47:38 +01:00
|
|
|
/*
|
|
|
|
* We actually want to reject safe_version < 2.09, but it's risky to
|
|
|
|
* assume that floating-point comparisons are exact, so use a slightly
|
|
|
|
* smaller comparison value.
|
|
|
|
*/
|
At 2005-05-21 20:18:50 +0530, ams@oryx.com wrote:
>
> > The second issue is where plperl returns a large result set.
I have attached the following seven patches to address this problem:
1. Trivial. Replaces some errant spaces with tabs.
2. Trivial. Fixes the spelling of Jan's name, and gets rid of many
inane, useless, annoying, and often misleading comments. Here's
a sample: "plperl_init_all() - Initialize all".
(I have tried to add some useful comments here and there, and will
continue to do so now and again.)
3. Trivial. Splits up some long lines.
4. Converts SRFs in PL/Perl to use a Tuplestore and SFRM_Materialize
to return the result set, based on the PL/PgSQL model.
There are two major consequences: result sets will spill to disk when
they can no longer fit in work_mem; and "select foo_srf()" no longer
works. (I didn't lose sleep over the latter, since that form is not
valid in PL/PgSQL, and it's not documented in PL/Perl.)
5. Trivial, but important. Fixes use of "undef" instead of undef. This
would cause empty functions to fail in bizarre ways. I suspect that
there's still another (old) bug here. I'll investigate further.
6. Moves the majority of (4) out into a new plperl_return_next()
function, to make it possible to expose the functionality to
Perl; cleans up some of the code besides.
7. Add an spi_return_next function for use in Perl code.
If you want to apply the patches and try them out, 8-composite.diff is
what you should use. (Note: my patches depend upon Andrew's use-strict
and %_SHARED patches being applied.)
Here's something to try:
create or replace function foo() returns setof record as $$
$i = 0;
for ("World", "PostgreSQL", "PL/Perl") {
spi_return_next({f1=>++$i, f2=>'Hello', f3=>$_});
}
return;
$$ language plperl;
select * from foo() as (f1 integer, f2 text, f3 text);
(Many thanks to Andrews Dunstan and Supernews for their help.)
Abhijit Menon-Sen
2005-06-04 22:33:06 +02:00
|
|
|
if (safe_version < 2.0899 )
|
|
|
|
{
|
|
|
|
/* not safe, so disallow all trusted funcs */
|
|
|
|
eval_pv(safe_bad, FALSE);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
eval_pv(common_safe_ok, FALSE);
|
|
|
|
eval_pv((plperl_use_strict ? strict_safe_ok : loose_safe_ok), FALSE);
|
|
|
|
}
|
The attached patch, which incorporates the previous one sent and
currently unapplied regarding spi_internal.c, makes some additional
fixes relating to return types, and also contains the fix for
preventing the use of insecure versions of Safe.pm.
There is one remaing return case that does not appear to work, namely
return of a composite directly in a select, i.e. if foo returns some
composite type, 'select * from foo()' works but 'select foo()' doesn't.
We will either fix that or document it as a limitation.
The function plperl_func_handler is a mess - I will try to get it
cleaned up (and split up) in a subsequent patch, time permitting.
Also, reiterating previous advice - this changes slightly the API for
spi_exec_query - the returned object has either 2 or 3 members: 'status'
(string) and 'proceesed' (int,- number of rows) and, if rows are
returned, 'rows' (array of tuple hashes).
Andrew Dunstan
2004-07-12 16:31:04 +02:00
|
|
|
|
|
|
|
plperl_safe_init_done = true;
|
|
|
|
}
|
|
|
|
|
2004-07-01 22:50:22 +02:00
|
|
|
|
2004-11-20 20:07:40 +01:00
|
|
|
/*
|
|
|
|
* Perl likes to put a newline after its error messages; clean up such
|
|
|
|
*/
|
|
|
|
static char *
|
|
|
|
strip_trailing_ws(const char *msg)
|
|
|
|
{
|
|
|
|
char *res = pstrdup(msg);
|
|
|
|
int len = strlen(res);
|
|
|
|
|
|
|
|
while (len > 0 && isspace((unsigned char) res[len-1]))
|
|
|
|
res[--len] = '\0';
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
At 2005-05-21 20:18:50 +0530, ams@oryx.com wrote:
>
> > The second issue is where plperl returns a large result set.
I have attached the following seven patches to address this problem:
1. Trivial. Replaces some errant spaces with tabs.
2. Trivial. Fixes the spelling of Jan's name, and gets rid of many
inane, useless, annoying, and often misleading comments. Here's
a sample: "plperl_init_all() - Initialize all".
(I have tried to add some useful comments here and there, and will
continue to do so now and again.)
3. Trivial. Splits up some long lines.
4. Converts SRFs in PL/Perl to use a Tuplestore and SFRM_Materialize
to return the result set, based on the PL/PgSQL model.
There are two major consequences: result sets will spill to disk when
they can no longer fit in work_mem; and "select foo_srf()" no longer
works. (I didn't lose sleep over the latter, since that form is not
valid in PL/PgSQL, and it's not documented in PL/Perl.)
5. Trivial, but important. Fixes use of "undef" instead of undef. This
would cause empty functions to fail in bizarre ways. I suspect that
there's still another (old) bug here. I'll investigate further.
6. Moves the majority of (4) out into a new plperl_return_next()
function, to make it possible to expose the functionality to
Perl; cleans up some of the code besides.
7. Add an spi_return_next function for use in Perl code.
If you want to apply the patches and try them out, 8-composite.diff is
what you should use. (Note: my patches depend upon Andrew's use-strict
and %_SHARED patches being applied.)
Here's something to try:
create or replace function foo() returns setof record as $$
$i = 0;
for ("World", "PostgreSQL", "PL/Perl") {
spi_return_next({f1=>++$i, f2=>'Hello', f3=>$_});
}
return;
$$ language plperl;
select * from foo() as (f1 integer, f2 text, f3 text);
(Many thanks to Andrews Dunstan and Supernews for their help.)
Abhijit Menon-Sen
2005-06-04 22:33:06 +02:00
|
|
|
/* Build a tuple from a hash. */
|
|
|
|
|
2004-11-23 01:21:24 +01:00
|
|
|
static HeapTuple
|
|
|
|
plperl_build_tuple_result(HV *perlhash, AttInMetadata *attinmeta)
|
2004-10-15 19:08:26 +02:00
|
|
|
{
|
2004-11-23 01:21:24 +01:00
|
|
|
TupleDesc td = attinmeta->tupdesc;
|
|
|
|
char **values;
|
|
|
|
SV *val;
|
|
|
|
char *key;
|
|
|
|
I32 klen;
|
|
|
|
HeapTuple tup;
|
2004-10-15 19:08:26 +02:00
|
|
|
|
2004-11-23 01:21:24 +01:00
|
|
|
values = (char **) palloc0(td->natts * sizeof(char *));
|
2004-10-15 19:08:26 +02:00
|
|
|
|
2004-11-23 01:21:24 +01:00
|
|
|
hv_iterinit(perlhash);
|
|
|
|
while ((val = hv_iternextsv(perlhash, &key, &klen)))
|
|
|
|
{
|
At 2005-05-21 20:18:50 +0530, ams@oryx.com wrote:
>
> > The second issue is where plperl returns a large result set.
I have attached the following seven patches to address this problem:
1. Trivial. Replaces some errant spaces with tabs.
2. Trivial. Fixes the spelling of Jan's name, and gets rid of many
inane, useless, annoying, and often misleading comments. Here's
a sample: "plperl_init_all() - Initialize all".
(I have tried to add some useful comments here and there, and will
continue to do so now and again.)
3. Trivial. Splits up some long lines.
4. Converts SRFs in PL/Perl to use a Tuplestore and SFRM_Materialize
to return the result set, based on the PL/PgSQL model.
There are two major consequences: result sets will spill to disk when
they can no longer fit in work_mem; and "select foo_srf()" no longer
works. (I didn't lose sleep over the latter, since that form is not
valid in PL/PgSQL, and it's not documented in PL/Perl.)
5. Trivial, but important. Fixes use of "undef" instead of undef. This
would cause empty functions to fail in bizarre ways. I suspect that
there's still another (old) bug here. I'll investigate further.
6. Moves the majority of (4) out into a new plperl_return_next()
function, to make it possible to expose the functionality to
Perl; cleans up some of the code besides.
7. Add an spi_return_next function for use in Perl code.
If you want to apply the patches and try them out, 8-composite.diff is
what you should use. (Note: my patches depend upon Andrew's use-strict
and %_SHARED patches being applied.)
Here's something to try:
create or replace function foo() returns setof record as $$
$i = 0;
for ("World", "PostgreSQL", "PL/Perl") {
spi_return_next({f1=>++$i, f2=>'Hello', f3=>$_});
}
return;
$$ language plperl;
select * from foo() as (f1 integer, f2 text, f3 text);
(Many thanks to Andrews Dunstan and Supernews for their help.)
Abhijit Menon-Sen
2005-06-04 22:33:06 +02:00
|
|
|
int attn = SPI_fnumber(td, key);
|
2004-07-01 22:50:22 +02:00
|
|
|
|
2004-11-23 01:21:24 +01:00
|
|
|
if (attn <= 0 || td->attrs[attn - 1]->attisdropped)
|
2004-11-29 21:11:06 +01:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_UNDEFINED_COLUMN),
|
|
|
|
errmsg("Perl hash contains nonexistent column \"%s\"",
|
|
|
|
key)));
|
2005-01-11 07:08:45 +01:00
|
|
|
if (SvOK(val) && SvTYPE(val) != SVt_NULL)
|
2004-11-23 01:21:24 +01:00
|
|
|
values[attn - 1] = SvPV(val, PL_na);
|
2004-10-15 19:08:26 +02:00
|
|
|
}
|
2004-11-23 01:21:24 +01:00
|
|
|
hv_iterinit(perlhash);
|
|
|
|
|
|
|
|
tup = BuildTupleFromCStrings(attinmeta, values);
|
|
|
|
pfree(values);
|
|
|
|
return tup;
|
2004-07-01 22:50:22 +02:00
|
|
|
}
|
|
|
|
|
2005-07-10 17:32:47 +02:00
|
|
|
/*
|
|
|
|
* convert perl array to postgres string representation
|
|
|
|
*/
|
|
|
|
static SV*
|
|
|
|
plperl_convert_to_pg_array(SV *src)
|
|
|
|
{
|
|
|
|
SV* rv;
|
|
|
|
int count;
|
|
|
|
dSP ;
|
|
|
|
|
|
|
|
PUSHMARK(SP) ;
|
|
|
|
XPUSHs(src);
|
|
|
|
PUTBACK ;
|
|
|
|
|
|
|
|
count = call_pv("_plperl_to_pg_array", G_SCALAR);
|
|
|
|
|
|
|
|
SPAGAIN ;
|
|
|
|
|
|
|
|
if (count != 1)
|
|
|
|
croak("Big trouble\n") ;
|
|
|
|
|
|
|
|
rv = POPs;
|
|
|
|
|
|
|
|
PUTBACK ;
|
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
2004-10-15 19:08:26 +02:00
|
|
|
|
At 2005-05-21 20:18:50 +0530, ams@oryx.com wrote:
>
> > The second issue is where plperl returns a large result set.
I have attached the following seven patches to address this problem:
1. Trivial. Replaces some errant spaces with tabs.
2. Trivial. Fixes the spelling of Jan's name, and gets rid of many
inane, useless, annoying, and often misleading comments. Here's
a sample: "plperl_init_all() - Initialize all".
(I have tried to add some useful comments here and there, and will
continue to do so now and again.)
3. Trivial. Splits up some long lines.
4. Converts SRFs in PL/Perl to use a Tuplestore and SFRM_Materialize
to return the result set, based on the PL/PgSQL model.
There are two major consequences: result sets will spill to disk when
they can no longer fit in work_mem; and "select foo_srf()" no longer
works. (I didn't lose sleep over the latter, since that form is not
valid in PL/PgSQL, and it's not documented in PL/Perl.)
5. Trivial, but important. Fixes use of "undef" instead of undef. This
would cause empty functions to fail in bizarre ways. I suspect that
there's still another (old) bug here. I'll investigate further.
6. Moves the majority of (4) out into a new plperl_return_next()
function, to make it possible to expose the functionality to
Perl; cleans up some of the code besides.
7. Add an spi_return_next function for use in Perl code.
If you want to apply the patches and try them out, 8-composite.diff is
what you should use. (Note: my patches depend upon Andrew's use-strict
and %_SHARED patches being applied.)
Here's something to try:
create or replace function foo() returns setof record as $$
$i = 0;
for ("World", "PostgreSQL", "PL/Perl") {
spi_return_next({f1=>++$i, f2=>'Hello', f3=>$_});
}
return;
$$ language plperl;
select * from foo() as (f1 integer, f2 text, f3 text);
(Many thanks to Andrews Dunstan and Supernews for their help.)
Abhijit Menon-Sen
2005-06-04 22:33:06 +02:00
|
|
|
/* Set up the arguments for a trigger call. */
|
|
|
|
|
2004-07-01 22:50:22 +02:00
|
|
|
static SV *
|
|
|
|
plperl_trigger_build_args(FunctionCallInfo fcinfo)
|
|
|
|
{
|
|
|
|
TriggerData *tdata;
|
|
|
|
TupleDesc tupdesc;
|
2004-11-23 01:21:24 +01:00
|
|
|
int i;
|
2004-10-15 19:08:26 +02:00
|
|
|
char *level;
|
|
|
|
char *event;
|
|
|
|
char *relid;
|
|
|
|
char *when;
|
|
|
|
HV *hv;
|
2004-07-01 22:50:22 +02:00
|
|
|
|
2004-10-15 19:08:26 +02:00
|
|
|
hv = newHV();
|
2004-07-01 22:50:22 +02:00
|
|
|
|
|
|
|
tdata = (TriggerData *) fcinfo->context;
|
|
|
|
tupdesc = tdata->tg_relation->rd_att;
|
|
|
|
|
2004-10-15 19:08:26 +02:00
|
|
|
relid = DatumGetCString(
|
2004-11-23 01:21:24 +01:00
|
|
|
DirectFunctionCall1(oidout,
|
|
|
|
ObjectIdGetDatum(tdata->tg_relation->rd_id)
|
2004-10-15 19:08:26 +02:00
|
|
|
)
|
|
|
|
);
|
|
|
|
|
|
|
|
hv_store(hv, "name", 4, newSVpv(tdata->tg_trigger->tgname, 0), 0);
|
|
|
|
hv_store(hv, "relid", 5, newSVpv(relid, 0), 0);
|
2004-07-01 22:50:22 +02:00
|
|
|
|
|
|
|
if (TRIGGER_FIRED_BY_INSERT(tdata->tg_event))
|
|
|
|
{
|
2004-10-15 19:08:26 +02:00
|
|
|
event = "INSERT";
|
2005-01-14 17:25:42 +01:00
|
|
|
if (TRIGGER_FIRED_FOR_ROW(tdata->tg_event))
|
|
|
|
hv_store(hv, "new", 3,
|
|
|
|
plperl_hash_from_tuple(tdata->tg_trigtuple, tupdesc),
|
|
|
|
0);
|
2004-07-01 22:50:22 +02:00
|
|
|
}
|
|
|
|
else if (TRIGGER_FIRED_BY_DELETE(tdata->tg_event))
|
|
|
|
{
|
2004-10-15 19:08:26 +02:00
|
|
|
event = "DELETE";
|
2005-01-14 17:25:42 +01:00
|
|
|
if (TRIGGER_FIRED_FOR_ROW(tdata->tg_event))
|
|
|
|
hv_store(hv, "old", 3,
|
|
|
|
plperl_hash_from_tuple(tdata->tg_trigtuple, tupdesc),
|
|
|
|
0);
|
2004-07-01 22:50:22 +02:00
|
|
|
}
|
|
|
|
else if (TRIGGER_FIRED_BY_UPDATE(tdata->tg_event))
|
|
|
|
{
|
2004-10-15 19:08:26 +02:00
|
|
|
event = "UPDATE";
|
2005-01-14 17:25:42 +01:00
|
|
|
if (TRIGGER_FIRED_FOR_ROW(tdata->tg_event))
|
|
|
|
{
|
|
|
|
hv_store(hv, "old", 3,
|
|
|
|
plperl_hash_from_tuple(tdata->tg_trigtuple, tupdesc),
|
|
|
|
0);
|
|
|
|
hv_store(hv, "new", 3,
|
|
|
|
plperl_hash_from_tuple(tdata->tg_newtuple, tupdesc),
|
|
|
|
0);
|
|
|
|
}
|
2004-10-15 19:08:26 +02:00
|
|
|
}
|
2005-01-14 17:25:42 +01:00
|
|
|
else
|
2004-10-15 19:08:26 +02:00
|
|
|
event = "UNKNOWN";
|
2004-07-01 22:50:22 +02:00
|
|
|
|
2004-10-15 19:08:26 +02:00
|
|
|
hv_store(hv, "event", 5, newSVpv(event, 0), 0);
|
|
|
|
hv_store(hv, "argc", 4, newSViv(tdata->tg_trigger->tgnargs), 0);
|
2004-07-01 22:50:22 +02:00
|
|
|
|
2005-01-14 17:25:42 +01:00
|
|
|
if (tdata->tg_trigger->tgnargs > 0)
|
2004-07-01 22:50:22 +02:00
|
|
|
{
|
2004-10-15 19:08:26 +02:00
|
|
|
AV *av = newAV();
|
|
|
|
for (i=0; i < tdata->tg_trigger->tgnargs; i++)
|
|
|
|
av_push(av, newSVpv(tdata->tg_trigger->tgargs[i], 0));
|
2004-11-23 01:21:24 +01:00
|
|
|
hv_store(hv, "args", 4, newRV_noinc((SV *)av), 0);
|
2004-07-01 22:50:22 +02:00
|
|
|
}
|
2004-10-15 19:08:26 +02:00
|
|
|
|
|
|
|
hv_store(hv, "relname", 7,
|
|
|
|
newSVpv(SPI_getrelname(tdata->tg_relation), 0), 0);
|
2004-07-01 22:50:22 +02:00
|
|
|
|
|
|
|
if (TRIGGER_FIRED_BEFORE(tdata->tg_event))
|
2004-10-15 19:08:26 +02:00
|
|
|
when = "BEFORE";
|
2004-07-01 22:50:22 +02:00
|
|
|
else if (TRIGGER_FIRED_AFTER(tdata->tg_event))
|
2004-10-15 19:08:26 +02:00
|
|
|
when = "AFTER";
|
2004-07-01 22:50:22 +02:00
|
|
|
else
|
2004-10-15 19:08:26 +02:00
|
|
|
when = "UNKNOWN";
|
|
|
|
hv_store(hv, "when", 4, newSVpv(when, 0), 0);
|
2004-07-01 22:50:22 +02:00
|
|
|
|
|
|
|
if (TRIGGER_FIRED_FOR_ROW(tdata->tg_event))
|
2004-10-15 19:08:26 +02:00
|
|
|
level = "ROW";
|
2004-07-01 22:50:22 +02:00
|
|
|
else if (TRIGGER_FIRED_FOR_STATEMENT(tdata->tg_event))
|
2004-10-15 19:08:26 +02:00
|
|
|
level = "STATEMENT";
|
2004-07-01 22:50:22 +02:00
|
|
|
else
|
2004-10-15 19:08:26 +02:00
|
|
|
level = "UNKNOWN";
|
|
|
|
hv_store(hv, "level", 5, newSVpv(level, 0), 0);
|
2004-07-01 22:50:22 +02:00
|
|
|
|
2004-11-23 01:21:24 +01:00
|
|
|
return newRV_noinc((SV*)hv);
|
2004-07-01 22:50:22 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
At 2005-05-21 20:18:50 +0530, ams@oryx.com wrote:
>
> > The second issue is where plperl returns a large result set.
I have attached the following seven patches to address this problem:
1. Trivial. Replaces some errant spaces with tabs.
2. Trivial. Fixes the spelling of Jan's name, and gets rid of many
inane, useless, annoying, and often misleading comments. Here's
a sample: "plperl_init_all() - Initialize all".
(I have tried to add some useful comments here and there, and will
continue to do so now and again.)
3. Trivial. Splits up some long lines.
4. Converts SRFs in PL/Perl to use a Tuplestore and SFRM_Materialize
to return the result set, based on the PL/PgSQL model.
There are two major consequences: result sets will spill to disk when
they can no longer fit in work_mem; and "select foo_srf()" no longer
works. (I didn't lose sleep over the latter, since that form is not
valid in PL/PgSQL, and it's not documented in PL/Perl.)
5. Trivial, but important. Fixes use of "undef" instead of undef. This
would cause empty functions to fail in bizarre ways. I suspect that
there's still another (old) bug here. I'll investigate further.
6. Moves the majority of (4) out into a new plperl_return_next()
function, to make it possible to expose the functionality to
Perl; cleans up some of the code besides.
7. Add an spi_return_next function for use in Perl code.
If you want to apply the patches and try them out, 8-composite.diff is
what you should use. (Note: my patches depend upon Andrew's use-strict
and %_SHARED patches being applied.)
Here's something to try:
create or replace function foo() returns setof record as $$
$i = 0;
for ("World", "PostgreSQL", "PL/Perl") {
spi_return_next({f1=>++$i, f2=>'Hello', f3=>$_});
}
return;
$$ language plperl;
select * from foo() as (f1 integer, f2 text, f3 text);
(Many thanks to Andrews Dunstan and Supernews for their help.)
Abhijit Menon-Sen
2005-06-04 22:33:06 +02:00
|
|
|
/* Set up the new tuple returned from a trigger. */
|
2004-11-22 21:31:53 +01:00
|
|
|
|
2004-07-01 22:50:22 +02:00
|
|
|
static HeapTuple
|
2004-11-23 01:21:24 +01:00
|
|
|
plperl_modify_tuple(HV *hvTD, TriggerData *tdata, HeapTuple otup)
|
2004-07-01 22:50:22 +02:00
|
|
|
{
|
|
|
|
SV **svp;
|
|
|
|
HV *hvNew;
|
|
|
|
HeapTuple rtup;
|
2004-11-23 01:21:24 +01:00
|
|
|
SV *val;
|
|
|
|
char *key;
|
|
|
|
I32 klen;
|
|
|
|
int slotsused;
|
|
|
|
int *modattrs;
|
|
|
|
Datum *modvalues;
|
|
|
|
char *modnulls;
|
|
|
|
|
2004-07-01 22:50:22 +02:00
|
|
|
TupleDesc tupdesc;
|
|
|
|
|
|
|
|
tupdesc = tdata->tg_relation->rd_att;
|
|
|
|
|
|
|
|
svp = hv_fetch(hvTD, "new", 3, FALSE);
|
2004-11-23 01:21:24 +01:00
|
|
|
if (!svp)
|
2004-11-29 21:11:06 +01:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_UNDEFINED_COLUMN),
|
|
|
|
errmsg("$_TD->{new} does not exist")));
|
2005-01-11 07:08:45 +01:00
|
|
|
if (!SvOK(*svp) || SvTYPE(*svp) != SVt_RV || SvTYPE(SvRV(*svp)) != SVt_PVHV)
|
2004-11-29 21:11:06 +01:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DATATYPE_MISMATCH),
|
|
|
|
errmsg("$_TD->{new} is not a hash reference")));
|
2004-07-01 22:50:22 +02:00
|
|
|
hvNew = (HV *) SvRV(*svp);
|
|
|
|
|
2004-11-23 01:21:24 +01:00
|
|
|
modattrs = palloc(tupdesc->natts * sizeof(int));
|
|
|
|
modvalues = palloc(tupdesc->natts * sizeof(Datum));
|
|
|
|
modnulls = palloc(tupdesc->natts * sizeof(char));
|
|
|
|
slotsused = 0;
|
2004-07-01 22:50:22 +02:00
|
|
|
|
2004-11-23 01:21:24 +01:00
|
|
|
hv_iterinit(hvNew);
|
|
|
|
while ((val = hv_iternextsv(hvNew, &key, &klen)))
|
2004-07-01 22:50:22 +02:00
|
|
|
{
|
2004-11-23 01:21:24 +01:00
|
|
|
int attn = SPI_fnumber(tupdesc, key);
|
2004-07-01 22:50:22 +02:00
|
|
|
|
2004-11-23 01:21:24 +01:00
|
|
|
if (attn <= 0 || tupdesc->attrs[attn - 1]->attisdropped)
|
2004-11-29 21:11:06 +01:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_UNDEFINED_COLUMN),
|
|
|
|
errmsg("Perl hash contains nonexistent column \"%s\"",
|
|
|
|
key)));
|
2005-01-11 07:08:45 +01:00
|
|
|
if (SvOK(val) && SvTYPE(val) != SVt_NULL)
|
2004-07-01 22:50:22 +02:00
|
|
|
{
|
2004-11-23 01:21:24 +01:00
|
|
|
Oid typinput;
|
|
|
|
Oid typioparam;
|
|
|
|
FmgrInfo finfo;
|
|
|
|
|
|
|
|
/* XXX would be better to cache these lookups */
|
|
|
|
getTypeInputInfo(tupdesc->attrs[attn - 1]->atttypid,
|
|
|
|
&typinput, &typioparam);
|
|
|
|
fmgr_info(typinput, &finfo);
|
|
|
|
modvalues[slotsused] = FunctionCall3(&finfo,
|
|
|
|
CStringGetDatum(SvPV(val, PL_na)),
|
|
|
|
ObjectIdGetDatum(typioparam),
|
|
|
|
Int32GetDatum(tupdesc->attrs[attn - 1]->atttypmod));
|
|
|
|
modnulls[slotsused] = ' ';
|
2004-07-01 22:50:22 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2004-11-23 01:21:24 +01:00
|
|
|
modvalues[slotsused] = (Datum) 0;
|
|
|
|
modnulls[slotsused] = 'n';
|
2004-07-01 22:50:22 +02:00
|
|
|
}
|
2004-11-23 01:21:24 +01:00
|
|
|
modattrs[slotsused] = attn;
|
|
|
|
slotsused++;
|
2004-07-01 22:50:22 +02:00
|
|
|
}
|
2004-11-23 01:21:24 +01:00
|
|
|
hv_iterinit(hvNew);
|
|
|
|
|
|
|
|
rtup = SPI_modifytuple(tdata->tg_relation, otup, slotsused,
|
|
|
|
modattrs, modvalues, modnulls);
|
2004-07-01 22:50:22 +02:00
|
|
|
|
|
|
|
pfree(modattrs);
|
|
|
|
pfree(modvalues);
|
|
|
|
pfree(modnulls);
|
2004-11-23 01:21:24 +01:00
|
|
|
|
2004-07-01 22:50:22 +02:00
|
|
|
if (rtup == NULL)
|
2004-11-29 21:11:06 +01:00
|
|
|
elog(ERROR, "SPI_modifytuple failed: %s",
|
2004-11-23 01:21:24 +01:00
|
|
|
SPI_result_code_string(SPI_result));
|
2004-07-01 22:50:22 +02:00
|
|
|
|
|
|
|
return rtup;
|
|
|
|
}
|
2000-01-20 06:08:58 +01:00
|
|
|
|
At 2005-05-21 20:18:50 +0530, ams@oryx.com wrote:
>
> > The second issue is where plperl returns a large result set.
I have attached the following seven patches to address this problem:
1. Trivial. Replaces some errant spaces with tabs.
2. Trivial. Fixes the spelling of Jan's name, and gets rid of many
inane, useless, annoying, and often misleading comments. Here's
a sample: "plperl_init_all() - Initialize all".
(I have tried to add some useful comments here and there, and will
continue to do so now and again.)
3. Trivial. Splits up some long lines.
4. Converts SRFs in PL/Perl to use a Tuplestore and SFRM_Materialize
to return the result set, based on the PL/PgSQL model.
There are two major consequences: result sets will spill to disk when
they can no longer fit in work_mem; and "select foo_srf()" no longer
works. (I didn't lose sleep over the latter, since that form is not
valid in PL/PgSQL, and it's not documented in PL/Perl.)
5. Trivial, but important. Fixes use of "undef" instead of undef. This
would cause empty functions to fail in bizarre ways. I suspect that
there's still another (old) bug here. I'll investigate further.
6. Moves the majority of (4) out into a new plperl_return_next()
function, to make it possible to expose the functionality to
Perl; cleans up some of the code besides.
7. Add an spi_return_next function for use in Perl code.
If you want to apply the patches and try them out, 8-composite.diff is
what you should use. (Note: my patches depend upon Andrew's use-strict
and %_SHARED patches being applied.)
Here's something to try:
create or replace function foo() returns setof record as $$
$i = 0;
for ("World", "PostgreSQL", "PL/Perl") {
spi_return_next({f1=>++$i, f2=>'Hello', f3=>$_});
}
return;
$$ language plperl;
select * from foo() as (f1 integer, f2 text, f3 text);
(Many thanks to Andrews Dunstan and Supernews for their help.)
Abhijit Menon-Sen
2005-06-04 22:33:06 +02:00
|
|
|
|
2005-06-22 18:45:51 +02:00
|
|
|
/*
|
|
|
|
* This is the only externally-visible part of the plperl call interface.
|
At 2005-05-21 20:18:50 +0530, ams@oryx.com wrote:
>
> > The second issue is where plperl returns a large result set.
I have attached the following seven patches to address this problem:
1. Trivial. Replaces some errant spaces with tabs.
2. Trivial. Fixes the spelling of Jan's name, and gets rid of many
inane, useless, annoying, and often misleading comments. Here's
a sample: "plperl_init_all() - Initialize all".
(I have tried to add some useful comments here and there, and will
continue to do so now and again.)
3. Trivial. Splits up some long lines.
4. Converts SRFs in PL/Perl to use a Tuplestore and SFRM_Materialize
to return the result set, based on the PL/PgSQL model.
There are two major consequences: result sets will spill to disk when
they can no longer fit in work_mem; and "select foo_srf()" no longer
works. (I didn't lose sleep over the latter, since that form is not
valid in PL/PgSQL, and it's not documented in PL/Perl.)
5. Trivial, but important. Fixes use of "undef" instead of undef. This
would cause empty functions to fail in bizarre ways. I suspect that
there's still another (old) bug here. I'll investigate further.
6. Moves the majority of (4) out into a new plperl_return_next()
function, to make it possible to expose the functionality to
Perl; cleans up some of the code besides.
7. Add an spi_return_next function for use in Perl code.
If you want to apply the patches and try them out, 8-composite.diff is
what you should use. (Note: my patches depend upon Andrew's use-strict
and %_SHARED patches being applied.)
Here's something to try:
create or replace function foo() returns setof record as $$
$i = 0;
for ("World", "PostgreSQL", "PL/Perl") {
spi_return_next({f1=>++$i, f2=>'Hello', f3=>$_});
}
return;
$$ language plperl;
select * from foo() as (f1 integer, f2 text, f3 text);
(Many thanks to Andrews Dunstan and Supernews for their help.)
Abhijit Menon-Sen
2005-06-04 22:33:06 +02:00
|
|
|
* The Postgres function and trigger managers call it to execute a
|
2005-06-22 18:45:51 +02:00
|
|
|
* perl function.
|
|
|
|
*/
|
2000-11-20 21:36:57 +01:00
|
|
|
PG_FUNCTION_INFO_V1(plperl_call_handler);
|
2000-01-20 06:08:58 +01:00
|
|
|
|
|
|
|
Datum
|
2000-05-28 19:56:29 +02:00
|
|
|
plperl_call_handler(PG_FUNCTION_ARGS)
|
2000-01-20 06:08:58 +01:00
|
|
|
{
|
At 2005-05-21 20:18:50 +0530, ams@oryx.com wrote:
>
> > The second issue is where plperl returns a large result set.
I have attached the following seven patches to address this problem:
1. Trivial. Replaces some errant spaces with tabs.
2. Trivial. Fixes the spelling of Jan's name, and gets rid of many
inane, useless, annoying, and often misleading comments. Here's
a sample: "plperl_init_all() - Initialize all".
(I have tried to add some useful comments here and there, and will
continue to do so now and again.)
3. Trivial. Splits up some long lines.
4. Converts SRFs in PL/Perl to use a Tuplestore and SFRM_Materialize
to return the result set, based on the PL/PgSQL model.
There are two major consequences: result sets will spill to disk when
they can no longer fit in work_mem; and "select foo_srf()" no longer
works. (I didn't lose sleep over the latter, since that form is not
valid in PL/PgSQL, and it's not documented in PL/Perl.)
5. Trivial, but important. Fixes use of "undef" instead of undef. This
would cause empty functions to fail in bizarre ways. I suspect that
there's still another (old) bug here. I'll investigate further.
6. Moves the majority of (4) out into a new plperl_return_next()
function, to make it possible to expose the functionality to
Perl; cleans up some of the code besides.
7. Add an spi_return_next function for use in Perl code.
If you want to apply the patches and try them out, 8-composite.diff is
what you should use. (Note: my patches depend upon Andrew's use-strict
and %_SHARED patches being applied.)
Here's something to try:
create or replace function foo() returns setof record as $$
$i = 0;
for ("World", "PostgreSQL", "PL/Perl") {
spi_return_next({f1=>++$i, f2=>'Hello', f3=>$_});
}
return;
$$ language plperl;
select * from foo() as (f1 integer, f2 text, f3 text);
(Many thanks to Andrews Dunstan and Supernews for their help.)
Abhijit Menon-Sen
2005-06-04 22:33:06 +02:00
|
|
|
Datum retval;
|
2004-09-13 22:10:13 +02:00
|
|
|
plperl_proc_desc *save_prodesc;
|
2005-07-12 03:16:22 +02:00
|
|
|
FunctionCallInfo save_caller_info;
|
|
|
|
Tuplestorestate *save_tuple_store;
|
|
|
|
TupleDesc save_tuple_desc;
|
2000-01-20 06:08:58 +01:00
|
|
|
|
2003-07-31 20:36:46 +02:00
|
|
|
plperl_init_all();
|
2000-01-20 06:08:58 +01:00
|
|
|
|
2004-09-13 22:10:13 +02:00
|
|
|
save_prodesc = plperl_current_prodesc;
|
2005-07-12 03:16:22 +02:00
|
|
|
save_caller_info = plperl_current_caller_info;
|
|
|
|
save_tuple_store = plperl_current_tuple_store;
|
|
|
|
save_tuple_desc = plperl_current_tuple_desc;
|
2000-01-20 06:08:58 +01:00
|
|
|
|
2004-09-13 22:10:13 +02:00
|
|
|
PG_TRY();
|
|
|
|
{
|
|
|
|
if (CALLED_AS_TRIGGER(fcinfo))
|
|
|
|
retval = PointerGetDatum(plperl_trigger_handler(fcinfo));
|
|
|
|
else
|
|
|
|
retval = plperl_func_handler(fcinfo);
|
|
|
|
}
|
|
|
|
PG_CATCH();
|
|
|
|
{
|
|
|
|
plperl_current_prodesc = save_prodesc;
|
2005-07-12 03:16:22 +02:00
|
|
|
plperl_current_caller_info = save_caller_info;
|
|
|
|
plperl_current_tuple_store = save_tuple_store;
|
|
|
|
plperl_current_tuple_desc = save_tuple_desc;
|
2004-09-13 22:10:13 +02:00
|
|
|
PG_RE_THROW();
|
|
|
|
}
|
|
|
|
PG_END_TRY();
|
|
|
|
|
|
|
|
plperl_current_prodesc = save_prodesc;
|
2005-07-12 03:16:22 +02:00
|
|
|
plperl_current_caller_info = save_caller_info;
|
|
|
|
plperl_current_tuple_store = save_tuple_store;
|
|
|
|
plperl_current_tuple_desc = save_tuple_desc;
|
2000-01-20 06:08:58 +01:00
|
|
|
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
2005-06-22 18:45:51 +02:00
|
|
|
/*
|
|
|
|
* This is the other externally visible function - it is called when CREATE
|
|
|
|
* FUNCTION is issued to validate the function being created/replaced.
|
|
|
|
*/
|
|
|
|
PG_FUNCTION_INFO_V1(plperl_validator);
|
|
|
|
|
|
|
|
Datum
|
|
|
|
plperl_validator(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
Oid funcoid = PG_GETARG_OID(0);
|
|
|
|
HeapTuple tuple;
|
|
|
|
Form_pg_proc proc;
|
|
|
|
bool istrigger = false;
|
|
|
|
plperl_proc_desc *prodesc;
|
|
|
|
|
|
|
|
plperl_init_all();
|
|
|
|
|
|
|
|
/* Get the new function's pg_proc entry */
|
|
|
|
tuple = SearchSysCache(PROCOID,
|
|
|
|
ObjectIdGetDatum(funcoid),
|
|
|
|
0, 0, 0);
|
|
|
|
if (!HeapTupleIsValid(tuple))
|
|
|
|
elog(ERROR, "cache lookup failed for function %u", funcoid);
|
|
|
|
proc = (Form_pg_proc) GETSTRUCT(tuple);
|
|
|
|
|
|
|
|
/* we assume OPAQUE with no arguments means a trigger */
|
|
|
|
if (proc->prorettype == TRIGGEROID ||
|
|
|
|
(proc->prorettype == OPAQUEOID && proc->pronargs == 0))
|
|
|
|
istrigger = true;
|
|
|
|
|
|
|
|
ReleaseSysCache(tuple);
|
|
|
|
|
|
|
|
prodesc = compile_plperl_function(funcoid, istrigger);
|
|
|
|
|
|
|
|
/* the result of a validator is ignored */
|
|
|
|
PG_RETURN_VOID();
|
|
|
|
}
|
|
|
|
|
2000-01-20 06:08:58 +01:00
|
|
|
|
At 2005-05-21 20:18:50 +0530, ams@oryx.com wrote:
>
> > The second issue is where plperl returns a large result set.
I have attached the following seven patches to address this problem:
1. Trivial. Replaces some errant spaces with tabs.
2. Trivial. Fixes the spelling of Jan's name, and gets rid of many
inane, useless, annoying, and often misleading comments. Here's
a sample: "plperl_init_all() - Initialize all".
(I have tried to add some useful comments here and there, and will
continue to do so now and again.)
3. Trivial. Splits up some long lines.
4. Converts SRFs in PL/Perl to use a Tuplestore and SFRM_Materialize
to return the result set, based on the PL/PgSQL model.
There are two major consequences: result sets will spill to disk when
they can no longer fit in work_mem; and "select foo_srf()" no longer
works. (I didn't lose sleep over the latter, since that form is not
valid in PL/PgSQL, and it's not documented in PL/Perl.)
5. Trivial, but important. Fixes use of "undef" instead of undef. This
would cause empty functions to fail in bizarre ways. I suspect that
there's still another (old) bug here. I'll investigate further.
6. Moves the majority of (4) out into a new plperl_return_next()
function, to make it possible to expose the functionality to
Perl; cleans up some of the code besides.
7. Add an spi_return_next function for use in Perl code.
If you want to apply the patches and try them out, 8-composite.diff is
what you should use. (Note: my patches depend upon Andrew's use-strict
and %_SHARED patches being applied.)
Here's something to try:
create or replace function foo() returns setof record as $$
$i = 0;
for ("World", "PostgreSQL", "PL/Perl") {
spi_return_next({f1=>++$i, f2=>'Hello', f3=>$_});
}
return;
$$ language plperl;
select * from foo() as (f1 integer, f2 text, f3 text);
(Many thanks to Andrews Dunstan and Supernews for their help.)
Abhijit Menon-Sen
2005-06-04 22:33:06 +02:00
|
|
|
/* Uses mksafefunc/mkunsafefunc to create an anonymous sub whose text is
|
|
|
|
* supplied in s, and returns a reference to the closure. */
|
|
|
|
|
2003-08-04 02:43:34 +02:00
|
|
|
static SV *
|
Well, after persuading cvsup and cvs that it _is_ possible to have local
modifiable repositories, I have a clean untrusted plperl patch to offer
you :)
Highlights:
* There's one perl interpreter used for both trusted and untrusted
procedures. I do think its unnecessary to keep two perl
interpreters around. If someone can break out from trusted "Safe" perl
mode, well, they can do what they want already. If someone disagrees, I
can change this.
* Opcode is not statically loaded anymore. Instead, we load Dynaloader,
which then can grab Opcode (and anything else you can 'use') on its own.
* Checked to work on FreeBSD 4.3 + perl 5.5.3 , OpenBSD 2.8 + perl5.6.1,
RedHat 6.2 + perl 5.5.3
* Uses ExtUtils::Embed to find what options are necessary to link with
perl shared libraries
* createlang is also updated, it can create untrusted perl using 'plperlu'
* Example script (assuming you have Mail::Sendmail installed):
create function foo() returns text as '
use Mail::Sendmail;
%mail = ( To => q(you@yourname.com),
From => q(me@here.com),
Message => "This is a very short message"
);
sendmail(%mail) or die $Mail::Sendmail::error;
return "OK. Log says:\n", $Mail::Sendmail::log;
' language 'plperlu';
Alex Pilosov
2001-06-18 23:40:06 +02:00
|
|
|
plperl_create_sub(char *s, bool trusted)
|
2000-04-12 19:17:23 +02:00
|
|
|
{
|
2000-01-20 06:08:58 +01:00
|
|
|
dSP;
|
2003-04-20 23:15:34 +02:00
|
|
|
SV *subref;
|
2001-03-22 05:01:46 +01:00
|
|
|
int count;
|
2000-01-20 06:08:58 +01:00
|
|
|
|
2004-08-29 07:07:03 +02:00
|
|
|
if (trusted && !plperl_safe_init_done)
|
2004-11-18 22:35:42 +01:00
|
|
|
{
|
The attached patch, which incorporates the previous one sent and
currently unapplied regarding spi_internal.c, makes some additional
fixes relating to return types, and also contains the fix for
preventing the use of insecure versions of Safe.pm.
There is one remaing return case that does not appear to work, namely
return of a composite directly in a select, i.e. if foo returns some
composite type, 'select * from foo()' works but 'select foo()' doesn't.
We will either fix that or document it as a limitation.
The function plperl_func_handler is a mess - I will try to get it
cleaned up (and split up) in a subsequent patch, time permitting.
Also, reiterating previous advice - this changes slightly the API for
spi_exec_query - the returned object has either 2 or 3 members: 'status'
(string) and 'proceesed' (int,- number of rows) and, if rows are
returned, 'rows' (array of tuple hashes).
Andrew Dunstan
2004-07-12 16:31:04 +02:00
|
|
|
plperl_safe_init();
|
2004-11-18 22:35:42 +01:00
|
|
|
SPAGAIN;
|
|
|
|
}
|
The attached patch, which incorporates the previous one sent and
currently unapplied regarding spi_internal.c, makes some additional
fixes relating to return types, and also contains the fix for
preventing the use of insecure versions of Safe.pm.
There is one remaing return case that does not appear to work, namely
return of a composite directly in a select, i.e. if foo returns some
composite type, 'select * from foo()' works but 'select foo()' doesn't.
We will either fix that or document it as a limitation.
The function plperl_func_handler is a mess - I will try to get it
cleaned up (and split up) in a subsequent patch, time permitting.
Also, reiterating previous advice - this changes slightly the API for
spi_exec_query - the returned object has either 2 or 3 members: 'status'
(string) and 'proceesed' (int,- number of rows) and, if rows are
returned, 'rows' (array of tuple hashes).
Andrew Dunstan
2004-07-12 16:31:04 +02:00
|
|
|
|
2000-01-20 06:08:58 +01:00
|
|
|
ENTER;
|
|
|
|
SAVETMPS;
|
|
|
|
PUSHMARK(SP);
|
2004-07-01 22:50:22 +02:00
|
|
|
XPUSHs(sv_2mortal(newSVpv("my $_TD=$_[0]; shift;", 0)));
|
2001-03-22 05:01:46 +01:00
|
|
|
XPUSHs(sv_2mortal(newSVpv(s, 0)));
|
2000-04-18 17:04:02 +02:00
|
|
|
PUTBACK;
|
2003-08-04 02:43:34 +02:00
|
|
|
|
2003-04-20 23:15:34 +02:00
|
|
|
/*
|
|
|
|
* G_KEEPERR seems to be needed here, else we don't recognize compile
|
2003-08-04 02:43:34 +02:00
|
|
|
* errors properly. Perhaps it's because there's another level of
|
|
|
|
* eval inside mksafefunc?
|
2003-04-20 23:15:34 +02:00
|
|
|
*/
|
2001-10-25 07:50:21 +02:00
|
|
|
count = perl_call_pv((trusted ? "mksafefunc" : "mkunsafefunc"),
|
|
|
|
G_SCALAR | G_EVAL | G_KEEPERR);
|
2000-01-20 06:08:58 +01:00
|
|
|
SPAGAIN;
|
|
|
|
|
2003-04-20 23:15:34 +02:00
|
|
|
if (count != 1)
|
|
|
|
{
|
|
|
|
PUTBACK;
|
|
|
|
FREETMPS;
|
|
|
|
LEAVE;
|
2003-07-26 01:37:31 +02:00
|
|
|
elog(ERROR, "didn't get a return item from mksafefunc");
|
2003-04-20 23:15:34 +02:00
|
|
|
}
|
|
|
|
|
2000-09-12 06:28:30 +02:00
|
|
|
if (SvTRUE(ERRSV))
|
2000-04-12 19:17:23 +02:00
|
|
|
{
|
2004-11-17 22:23:36 +01:00
|
|
|
(void) POPs;
|
2000-01-20 06:08:58 +01:00
|
|
|
PUTBACK;
|
|
|
|
FREETMPS;
|
|
|
|
LEAVE;
|
2004-11-29 21:11:06 +01:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_SYNTAX_ERROR),
|
|
|
|
errmsg("creation of Perl function failed: %s",
|
|
|
|
strip_trailing_ws(SvPV(ERRSV, PL_na)))));
|
2000-01-20 06:08:58 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2000-04-12 19:17:23 +02:00
|
|
|
* need to make a deep copy of the return. it comes off the stack as a
|
|
|
|
* temporary.
|
2000-01-20 06:08:58 +01:00
|
|
|
*/
|
|
|
|
subref = newSVsv(POPs);
|
|
|
|
|
2005-06-22 18:45:51 +02:00
|
|
|
if (!SvROK(subref) || SvTYPE(SvRV(subref)) != SVt_PVCV)
|
2000-04-12 19:17:23 +02:00
|
|
|
{
|
2000-01-20 06:08:58 +01:00
|
|
|
PUTBACK;
|
|
|
|
FREETMPS;
|
|
|
|
LEAVE;
|
2000-04-12 19:17:23 +02:00
|
|
|
|
2000-01-20 06:08:58 +01:00
|
|
|
/*
|
|
|
|
* subref is our responsibility because it is not mortal
|
|
|
|
*/
|
|
|
|
SvREFCNT_dec(subref);
|
2003-07-26 01:37:31 +02:00
|
|
|
elog(ERROR, "didn't get a code ref");
|
2000-01-20 06:08:58 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
PUTBACK;
|
|
|
|
FREETMPS;
|
|
|
|
LEAVE;
|
2003-04-20 23:15:34 +02:00
|
|
|
|
2000-01-20 06:08:58 +01:00
|
|
|
return subref;
|
|
|
|
}
|
|
|
|
|
At 2005-05-21 20:18:50 +0530, ams@oryx.com wrote:
>
> > The second issue is where plperl returns a large result set.
I have attached the following seven patches to address this problem:
1. Trivial. Replaces some errant spaces with tabs.
2. Trivial. Fixes the spelling of Jan's name, and gets rid of many
inane, useless, annoying, and often misleading comments. Here's
a sample: "plperl_init_all() - Initialize all".
(I have tried to add some useful comments here and there, and will
continue to do so now and again.)
3. Trivial. Splits up some long lines.
4. Converts SRFs in PL/Perl to use a Tuplestore and SFRM_Materialize
to return the result set, based on the PL/PgSQL model.
There are two major consequences: result sets will spill to disk when
they can no longer fit in work_mem; and "select foo_srf()" no longer
works. (I didn't lose sleep over the latter, since that form is not
valid in PL/PgSQL, and it's not documented in PL/Perl.)
5. Trivial, but important. Fixes use of "undef" instead of undef. This
would cause empty functions to fail in bizarre ways. I suspect that
there's still another (old) bug here. I'll investigate further.
6. Moves the majority of (4) out into a new plperl_return_next()
function, to make it possible to expose the functionality to
Perl; cleans up some of the code besides.
7. Add an spi_return_next function for use in Perl code.
If you want to apply the patches and try them out, 8-composite.diff is
what you should use. (Note: my patches depend upon Andrew's use-strict
and %_SHARED patches being applied.)
Here's something to try:
create or replace function foo() returns setof record as $$
$i = 0;
for ("World", "PostgreSQL", "PL/Perl") {
spi_return_next({f1=>++$i, f2=>'Hello', f3=>$_});
}
return;
$$ language plperl;
select * from foo() as (f1 integer, f2 text, f3 text);
(Many thanks to Andrews Dunstan and Supernews for their help.)
Abhijit Menon-Sen
2005-06-04 22:33:06 +02:00
|
|
|
|
2000-01-20 06:08:58 +01:00
|
|
|
/**********************************************************************
|
2000-04-12 19:17:23 +02:00
|
|
|
* plperl_init_shared_libs() -
|
2000-01-20 06:08:58 +01:00
|
|
|
*
|
|
|
|
* We cannot use the DynaLoader directly to get at the Opcode
|
|
|
|
* module (used by Safe.pm). So, we link Opcode into ourselves
|
|
|
|
* and do the initialization behind perl's back.
|
2000-04-12 19:17:23 +02:00
|
|
|
*
|
2000-01-20 06:08:58 +01:00
|
|
|
**********************************************************************/
|
|
|
|
|
2004-08-30 04:54:42 +02:00
|
|
|
EXTERN_C void boot_DynaLoader(pTHX_ CV *cv);
|
|
|
|
EXTERN_C void boot_SPI(pTHX_ CV *cv);
|
2000-01-20 06:08:58 +01:00
|
|
|
|
2000-02-19 19:58:37 +01:00
|
|
|
static void
|
2002-01-24 22:40:44 +01:00
|
|
|
plperl_init_shared_libs(pTHX)
|
2000-01-20 06:08:58 +01:00
|
|
|
{
|
2000-04-12 19:17:23 +02:00
|
|
|
char *file = __FILE__;
|
|
|
|
|
2001-10-25 07:50:21 +02:00
|
|
|
newXS("DynaLoader::boot_DynaLoader", boot_DynaLoader, file);
|
2000-01-29 02:58:50 +01:00
|
|
|
newXS("SPI::bootstrap", boot_SPI, file);
|
2000-01-20 06:08:58 +01:00
|
|
|
}
|
|
|
|
|
At 2005-05-21 20:18:50 +0530, ams@oryx.com wrote:
>
> > The second issue is where plperl returns a large result set.
I have attached the following seven patches to address this problem:
1. Trivial. Replaces some errant spaces with tabs.
2. Trivial. Fixes the spelling of Jan's name, and gets rid of many
inane, useless, annoying, and often misleading comments. Here's
a sample: "plperl_init_all() - Initialize all".
(I have tried to add some useful comments here and there, and will
continue to do so now and again.)
3. Trivial. Splits up some long lines.
4. Converts SRFs in PL/Perl to use a Tuplestore and SFRM_Materialize
to return the result set, based on the PL/PgSQL model.
There are two major consequences: result sets will spill to disk when
they can no longer fit in work_mem; and "select foo_srf()" no longer
works. (I didn't lose sleep over the latter, since that form is not
valid in PL/PgSQL, and it's not documented in PL/Perl.)
5. Trivial, but important. Fixes use of "undef" instead of undef. This
would cause empty functions to fail in bizarre ways. I suspect that
there's still another (old) bug here. I'll investigate further.
6. Moves the majority of (4) out into a new plperl_return_next()
function, to make it possible to expose the functionality to
Perl; cleans up some of the code besides.
7. Add an spi_return_next function for use in Perl code.
If you want to apply the patches and try them out, 8-composite.diff is
what you should use. (Note: my patches depend upon Andrew's use-strict
and %_SHARED patches being applied.)
Here's something to try:
create or replace function foo() returns setof record as $$
$i = 0;
for ("World", "PostgreSQL", "PL/Perl") {
spi_return_next({f1=>++$i, f2=>'Hello', f3=>$_});
}
return;
$$ language plperl;
select * from foo() as (f1 integer, f2 text, f3 text);
(Many thanks to Andrews Dunstan and Supernews for their help.)
Abhijit Menon-Sen
2005-06-04 22:33:06 +02:00
|
|
|
|
2003-08-04 02:43:34 +02:00
|
|
|
static SV *
|
2004-08-30 04:54:42 +02:00
|
|
|
plperl_call_perl_func(plperl_proc_desc *desc, FunctionCallInfo fcinfo)
|
2000-01-20 06:08:58 +01:00
|
|
|
{
|
|
|
|
dSP;
|
2000-04-12 19:17:23 +02:00
|
|
|
SV *retval;
|
|
|
|
int i;
|
|
|
|
int count;
|
2005-06-15 02:35:16 +02:00
|
|
|
SV *sv;
|
2000-01-20 06:08:58 +01:00
|
|
|
|
|
|
|
ENTER;
|
|
|
|
SAVETMPS;
|
|
|
|
|
2003-04-20 23:15:34 +02:00
|
|
|
PUSHMARK(SP);
|
2004-11-23 01:21:24 +01:00
|
|
|
|
At 2005-05-21 20:18:50 +0530, ams@oryx.com wrote:
>
> > The second issue is where plperl returns a large result set.
I have attached the following seven patches to address this problem:
1. Trivial. Replaces some errant spaces with tabs.
2. Trivial. Fixes the spelling of Jan's name, and gets rid of many
inane, useless, annoying, and often misleading comments. Here's
a sample: "plperl_init_all() - Initialize all".
(I have tried to add some useful comments here and there, and will
continue to do so now and again.)
3. Trivial. Splits up some long lines.
4. Converts SRFs in PL/Perl to use a Tuplestore and SFRM_Materialize
to return the result set, based on the PL/PgSQL model.
There are two major consequences: result sets will spill to disk when
they can no longer fit in work_mem; and "select foo_srf()" no longer
works. (I didn't lose sleep over the latter, since that form is not
valid in PL/PgSQL, and it's not documented in PL/Perl.)
5. Trivial, but important. Fixes use of "undef" instead of undef. This
would cause empty functions to fail in bizarre ways. I suspect that
there's still another (old) bug here. I'll investigate further.
6. Moves the majority of (4) out into a new plperl_return_next()
function, to make it possible to expose the functionality to
Perl; cleans up some of the code besides.
7. Add an spi_return_next function for use in Perl code.
If you want to apply the patches and try them out, 8-composite.diff is
what you should use. (Note: my patches depend upon Andrew's use-strict
and %_SHARED patches being applied.)
Here's something to try:
create or replace function foo() returns setof record as $$
$i = 0;
for ("World", "PostgreSQL", "PL/Perl") {
spi_return_next({f1=>++$i, f2=>'Hello', f3=>$_});
}
return;
$$ language plperl;
select * from foo() as (f1 integer, f2 text, f3 text);
(Many thanks to Andrews Dunstan and Supernews for their help.)
Abhijit Menon-Sen
2005-06-04 22:33:06 +02:00
|
|
|
XPUSHs(&PL_sv_undef); /* no trigger data */
|
2004-11-23 01:21:24 +01:00
|
|
|
|
2000-04-12 19:17:23 +02:00
|
|
|
for (i = 0; i < desc->nargs; i++)
|
|
|
|
{
|
2004-11-18 22:35:42 +01:00
|
|
|
if (fcinfo->argnull[i])
|
|
|
|
XPUSHs(&PL_sv_undef);
|
|
|
|
else if (desc->arg_is_rowtype[i])
|
2000-04-12 19:17:23 +02:00
|
|
|
{
|
2004-11-18 22:35:42 +01:00
|
|
|
HeapTupleHeader td;
|
|
|
|
Oid tupType;
|
|
|
|
int32 tupTypmod;
|
|
|
|
TupleDesc tupdesc;
|
|
|
|
HeapTupleData tmptup;
|
|
|
|
SV *hashref;
|
|
|
|
|
|
|
|
td = DatumGetHeapTupleHeader(fcinfo->arg[i]);
|
|
|
|
/* Extract rowtype info and find a tupdesc */
|
|
|
|
tupType = HeapTupleHeaderGetTypeId(td);
|
|
|
|
tupTypmod = HeapTupleHeaderGetTypMod(td);
|
|
|
|
tupdesc = lookup_rowtype_tupdesc(tupType, tupTypmod);
|
|
|
|
/* Build a temporary HeapTuple control structure */
|
|
|
|
tmptup.t_len = HeapTupleHeaderGetDatumLength(td);
|
|
|
|
tmptup.t_data = td;
|
|
|
|
|
2004-11-23 01:21:24 +01:00
|
|
|
hashref = plperl_hash_from_tuple(&tmptup, tupdesc);
|
|
|
|
XPUSHs(sv_2mortal(hashref));
|
2000-04-12 19:17:23 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2004-11-18 22:35:42 +01:00
|
|
|
char *tmp;
|
|
|
|
|
2005-05-01 20:56:19 +02:00
|
|
|
tmp = DatumGetCString(FunctionCall1(&(desc->arg_out_func[i]),
|
|
|
|
fcinfo->arg[i]));
|
2005-06-15 02:35:16 +02:00
|
|
|
sv = newSVpv(tmp, 0);
|
|
|
|
#if PERL_BCDVERSION >= 0x5006000L
|
|
|
|
if (GetDatabaseEncoding() == PG_UTF8) SvUTF8_on(sv);
|
|
|
|
#endif
|
|
|
|
XPUSHs(sv_2mortal(sv));
|
2004-11-18 22:35:42 +01:00
|
|
|
pfree(tmp);
|
2000-01-20 06:08:58 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
PUTBACK;
|
2003-04-20 23:15:34 +02:00
|
|
|
|
|
|
|
/* Do NOT use G_KEEPERR here */
|
|
|
|
count = perl_call_sv(desc->reference, G_SCALAR | G_EVAL);
|
2000-01-20 06:08:58 +01:00
|
|
|
|
|
|
|
SPAGAIN;
|
|
|
|
|
2000-04-12 19:17:23 +02:00
|
|
|
if (count != 1)
|
|
|
|
{
|
|
|
|
PUTBACK;
|
|
|
|
FREETMPS;
|
2000-01-20 06:08:58 +01:00
|
|
|
LEAVE;
|
2003-07-26 01:37:31 +02:00
|
|
|
elog(ERROR, "didn't get a return item from function");
|
2000-01-20 06:08:58 +01:00
|
|
|
}
|
|
|
|
|
2000-09-12 06:28:30 +02:00
|
|
|
if (SvTRUE(ERRSV))
|
2000-04-12 19:17:23 +02:00
|
|
|
{
|
2004-11-17 22:23:36 +01:00
|
|
|
(void) POPs;
|
2000-04-12 19:17:23 +02:00
|
|
|
PUTBACK;
|
|
|
|
FREETMPS;
|
2000-01-20 06:08:58 +01:00
|
|
|
LEAVE;
|
2004-11-29 21:11:06 +01:00
|
|
|
/* XXX need to find a way to assign an errcode here */
|
|
|
|
ereport(ERROR,
|
|
|
|
(errmsg("error from Perl function: %s",
|
|
|
|
strip_trailing_ws(SvPV(ERRSV, PL_na)))));
|
2000-01-20 06:08:58 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
retval = newSVsv(POPs);
|
|
|
|
|
2000-04-12 19:17:23 +02:00
|
|
|
PUTBACK;
|
|
|
|
FREETMPS;
|
|
|
|
LEAVE;
|
2000-01-20 06:08:58 +01:00
|
|
|
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
At 2005-05-21 20:18:50 +0530, ams@oryx.com wrote:
>
> > The second issue is where plperl returns a large result set.
I have attached the following seven patches to address this problem:
1. Trivial. Replaces some errant spaces with tabs.
2. Trivial. Fixes the spelling of Jan's name, and gets rid of many
inane, useless, annoying, and often misleading comments. Here's
a sample: "plperl_init_all() - Initialize all".
(I have tried to add some useful comments here and there, and will
continue to do so now and again.)
3. Trivial. Splits up some long lines.
4. Converts SRFs in PL/Perl to use a Tuplestore and SFRM_Materialize
to return the result set, based on the PL/PgSQL model.
There are two major consequences: result sets will spill to disk when
they can no longer fit in work_mem; and "select foo_srf()" no longer
works. (I didn't lose sleep over the latter, since that form is not
valid in PL/PgSQL, and it's not documented in PL/Perl.)
5. Trivial, but important. Fixes use of "undef" instead of undef. This
would cause empty functions to fail in bizarre ways. I suspect that
there's still another (old) bug here. I'll investigate further.
6. Moves the majority of (4) out into a new plperl_return_next()
function, to make it possible to expose the functionality to
Perl; cleans up some of the code besides.
7. Add an spi_return_next function for use in Perl code.
If you want to apply the patches and try them out, 8-composite.diff is
what you should use. (Note: my patches depend upon Andrew's use-strict
and %_SHARED patches being applied.)
Here's something to try:
create or replace function foo() returns setof record as $$
$i = 0;
for ("World", "PostgreSQL", "PL/Perl") {
spi_return_next({f1=>++$i, f2=>'Hello', f3=>$_});
}
return;
$$ language plperl;
select * from foo() as (f1 integer, f2 text, f3 text);
(Many thanks to Andrews Dunstan and Supernews for their help.)
Abhijit Menon-Sen
2005-06-04 22:33:06 +02:00
|
|
|
|
2004-07-01 22:50:22 +02:00
|
|
|
static SV *
|
2004-11-23 01:21:24 +01:00
|
|
|
plperl_call_perl_trigger_func(plperl_proc_desc *desc, FunctionCallInfo fcinfo,
|
|
|
|
SV *td)
|
2004-07-01 22:50:22 +02:00
|
|
|
{
|
|
|
|
dSP;
|
|
|
|
SV *retval;
|
2004-11-18 22:35:42 +01:00
|
|
|
Trigger *tg_trigger;
|
2004-07-01 22:50:22 +02:00
|
|
|
int i;
|
|
|
|
int count;
|
|
|
|
|
|
|
|
ENTER;
|
|
|
|
SAVETMPS;
|
|
|
|
|
|
|
|
PUSHMARK(sp);
|
2004-11-23 01:21:24 +01:00
|
|
|
|
2004-07-01 22:50:22 +02:00
|
|
|
XPUSHs(td);
|
2004-11-23 01:21:24 +01:00
|
|
|
|
2004-11-18 22:35:42 +01:00
|
|
|
tg_trigger = ((TriggerData *) fcinfo->context)->tg_trigger;
|
|
|
|
for (i = 0; i < tg_trigger->tgnargs; i++)
|
|
|
|
XPUSHs(sv_2mortal(newSVpv(tg_trigger->tgargs[i], 0)));
|
2004-07-01 22:50:22 +02:00
|
|
|
PUTBACK;
|
|
|
|
|
2004-11-23 01:21:24 +01:00
|
|
|
/* Do NOT use G_KEEPERR here */
|
|
|
|
count = perl_call_sv(desc->reference, G_SCALAR | G_EVAL);
|
2004-07-01 22:50:22 +02:00
|
|
|
|
|
|
|
SPAGAIN;
|
|
|
|
|
|
|
|
if (count != 1)
|
|
|
|
{
|
|
|
|
PUTBACK;
|
|
|
|
FREETMPS;
|
|
|
|
LEAVE;
|
2004-11-20 20:07:40 +01:00
|
|
|
elog(ERROR, "didn't get a return item from trigger function");
|
2004-07-01 22:50:22 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (SvTRUE(ERRSV))
|
|
|
|
{
|
2004-11-17 22:23:36 +01:00
|
|
|
(void) POPs;
|
2004-07-01 22:50:22 +02:00
|
|
|
PUTBACK;
|
|
|
|
FREETMPS;
|
|
|
|
LEAVE;
|
2004-11-29 21:11:06 +01:00
|
|
|
/* XXX need to find a way to assign an errcode here */
|
|
|
|
ereport(ERROR,
|
|
|
|
(errmsg("error from Perl trigger function: %s",
|
|
|
|
strip_trailing_ws(SvPV(ERRSV, PL_na)))));
|
2004-07-01 22:50:22 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
retval = newSVsv(POPs);
|
|
|
|
|
|
|
|
PUTBACK;
|
|
|
|
FREETMPS;
|
|
|
|
LEAVE;
|
|
|
|
|
|
|
|
return retval;
|
|
|
|
}
|
2003-04-20 23:15:34 +02:00
|
|
|
|
At 2005-05-21 20:18:50 +0530, ams@oryx.com wrote:
>
> > The second issue is where plperl returns a large result set.
I have attached the following seven patches to address this problem:
1. Trivial. Replaces some errant spaces with tabs.
2. Trivial. Fixes the spelling of Jan's name, and gets rid of many
inane, useless, annoying, and often misleading comments. Here's
a sample: "plperl_init_all() - Initialize all".
(I have tried to add some useful comments here and there, and will
continue to do so now and again.)
3. Trivial. Splits up some long lines.
4. Converts SRFs in PL/Perl to use a Tuplestore and SFRM_Materialize
to return the result set, based on the PL/PgSQL model.
There are two major consequences: result sets will spill to disk when
they can no longer fit in work_mem; and "select foo_srf()" no longer
works. (I didn't lose sleep over the latter, since that form is not
valid in PL/PgSQL, and it's not documented in PL/Perl.)
5. Trivial, but important. Fixes use of "undef" instead of undef. This
would cause empty functions to fail in bizarre ways. I suspect that
there's still another (old) bug here. I'll investigate further.
6. Moves the majority of (4) out into a new plperl_return_next()
function, to make it possible to expose the functionality to
Perl; cleans up some of the code besides.
7. Add an spi_return_next function for use in Perl code.
If you want to apply the patches and try them out, 8-composite.diff is
what you should use. (Note: my patches depend upon Andrew's use-strict
and %_SHARED patches being applied.)
Here's something to try:
create or replace function foo() returns setof record as $$
$i = 0;
for ("World", "PostgreSQL", "PL/Perl") {
spi_return_next({f1=>++$i, f2=>'Hello', f3=>$_});
}
return;
$$ language plperl;
select * from foo() as (f1 integer, f2 text, f3 text);
(Many thanks to Andrews Dunstan and Supernews for their help.)
Abhijit Menon-Sen
2005-06-04 22:33:06 +02:00
|
|
|
|
2000-01-20 06:08:58 +01:00
|
|
|
static Datum
|
2000-05-28 19:56:29 +02:00
|
|
|
plperl_func_handler(PG_FUNCTION_ARGS)
|
2000-01-20 06:08:58 +01:00
|
|
|
{
|
|
|
|
plperl_proc_desc *prodesc;
|
2000-04-12 19:17:23 +02:00
|
|
|
SV *perlret;
|
|
|
|
Datum retval;
|
At 2005-05-21 20:18:50 +0530, ams@oryx.com wrote:
>
> > The second issue is where plperl returns a large result set.
I have attached the following seven patches to address this problem:
1. Trivial. Replaces some errant spaces with tabs.
2. Trivial. Fixes the spelling of Jan's name, and gets rid of many
inane, useless, annoying, and often misleading comments. Here's
a sample: "plperl_init_all() - Initialize all".
(I have tried to add some useful comments here and there, and will
continue to do so now and again.)
3. Trivial. Splits up some long lines.
4. Converts SRFs in PL/Perl to use a Tuplestore and SFRM_Materialize
to return the result set, based on the PL/PgSQL model.
There are two major consequences: result sets will spill to disk when
they can no longer fit in work_mem; and "select foo_srf()" no longer
works. (I didn't lose sleep over the latter, since that form is not
valid in PL/PgSQL, and it's not documented in PL/Perl.)
5. Trivial, but important. Fixes use of "undef" instead of undef. This
would cause empty functions to fail in bizarre ways. I suspect that
there's still another (old) bug here. I'll investigate further.
6. Moves the majority of (4) out into a new plperl_return_next()
function, to make it possible to expose the functionality to
Perl; cleans up some of the code besides.
7. Add an spi_return_next function for use in Perl code.
If you want to apply the patches and try them out, 8-composite.diff is
what you should use. (Note: my patches depend upon Andrew's use-strict
and %_SHARED patches being applied.)
Here's something to try:
create or replace function foo() returns setof record as $$
$i = 0;
for ("World", "PostgreSQL", "PL/Perl") {
spi_return_next({f1=>++$i, f2=>'Hello', f3=>$_});
}
return;
$$ language plperl;
select * from foo() as (f1 integer, f2 text, f3 text);
(Many thanks to Andrews Dunstan and Supernews for their help.)
Abhijit Menon-Sen
2005-06-04 22:33:06 +02:00
|
|
|
ReturnSetInfo *rsi;
|
2005-08-12 23:09:34 +02:00
|
|
|
SV* array_ret = NULL;
|
2000-01-20 06:08:58 +01:00
|
|
|
|
2004-11-22 21:31:53 +01:00
|
|
|
if (SPI_connect() != SPI_OK_CONNECT)
|
|
|
|
elog(ERROR, "could not connect to SPI manager");
|
|
|
|
|
2001-10-20 00:43:49 +02:00
|
|
|
prodesc = compile_plperl_function(fcinfo->flinfo->fn_oid, false);
|
2004-09-13 22:10:13 +02:00
|
|
|
|
|
|
|
plperl_current_prodesc = prodesc;
|
2005-07-12 03:16:22 +02:00
|
|
|
plperl_current_caller_info = fcinfo;
|
|
|
|
plperl_current_tuple_store = 0;
|
|
|
|
plperl_current_tuple_desc = 0;
|
2004-09-13 22:10:13 +02:00
|
|
|
|
2005-08-12 23:09:34 +02:00
|
|
|
rsi = (ReturnSetInfo *)fcinfo->resultinfo;
|
|
|
|
|
2005-08-12 23:26:32 +02:00
|
|
|
if (prodesc->fn_retisset)
|
2005-08-12 22:48:03 +02:00
|
|
|
{
|
2005-08-12 23:26:32 +02:00
|
|
|
/* Check context before allowing the call to go through */
|
|
|
|
if (!rsi || !IsA(rsi, ReturnSetInfo) ||
|
|
|
|
(rsi->allowedModes & SFRM_Materialize) == 0 ||
|
|
|
|
rsi->expectedDesc == NULL)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
|
|
|
errmsg("set-valued function called in context that "
|
|
|
|
"cannot accept a set")));
|
2005-08-12 22:48:03 +02:00
|
|
|
}
|
|
|
|
|
At 2005-05-21 20:18:50 +0530, ams@oryx.com wrote:
>
> > The second issue is where plperl returns a large result set.
I have attached the following seven patches to address this problem:
1. Trivial. Replaces some errant spaces with tabs.
2. Trivial. Fixes the spelling of Jan's name, and gets rid of many
inane, useless, annoying, and often misleading comments. Here's
a sample: "plperl_init_all() - Initialize all".
(I have tried to add some useful comments here and there, and will
continue to do so now and again.)
3. Trivial. Splits up some long lines.
4. Converts SRFs in PL/Perl to use a Tuplestore and SFRM_Materialize
to return the result set, based on the PL/PgSQL model.
There are two major consequences: result sets will spill to disk when
they can no longer fit in work_mem; and "select foo_srf()" no longer
works. (I didn't lose sleep over the latter, since that form is not
valid in PL/PgSQL, and it's not documented in PL/Perl.)
5. Trivial, but important. Fixes use of "undef" instead of undef. This
would cause empty functions to fail in bizarre ways. I suspect that
there's still another (old) bug here. I'll investigate further.
6. Moves the majority of (4) out into a new plperl_return_next()
function, to make it possible to expose the functionality to
Perl; cleans up some of the code besides.
7. Add an spi_return_next function for use in Perl code.
If you want to apply the patches and try them out, 8-composite.diff is
what you should use. (Note: my patches depend upon Andrew's use-strict
and %_SHARED patches being applied.)
Here's something to try:
create or replace function foo() returns setof record as $$
$i = 0;
for ("World", "PostgreSQL", "PL/Perl") {
spi_return_next({f1=>++$i, f2=>'Hello', f3=>$_});
}
return;
$$ language plperl;
select * from foo() as (f1 integer, f2 text, f3 text);
(Many thanks to Andrews Dunstan and Supernews for their help.)
Abhijit Menon-Sen
2005-06-04 22:33:06 +02:00
|
|
|
perlret = plperl_call_perl_func(prodesc, fcinfo);
|
2000-01-20 06:08:58 +01:00
|
|
|
|
|
|
|
/************************************************************
|
|
|
|
* Disconnect from SPI manager and then create the return
|
|
|
|
* values datum (if the input function does a palloc for it
|
|
|
|
* this must not be allocated in the SPI memory context
|
|
|
|
* because SPI_finish would free it).
|
|
|
|
************************************************************/
|
|
|
|
if (SPI_finish() != SPI_OK_FINISH)
|
2003-07-26 01:37:31 +02:00
|
|
|
elog(ERROR, "SPI_finish() failed");
|
2000-01-20 06:08:58 +01:00
|
|
|
|
2005-08-12 23:26:32 +02:00
|
|
|
if (prodesc->fn_retisset)
|
2005-07-10 17:32:47 +02:00
|
|
|
{
|
2005-08-12 23:26:32 +02:00
|
|
|
/*
|
|
|
|
* If the Perl function returned an arrayref, we pretend that it
|
At 2005-05-21 20:18:50 +0530, ams@oryx.com wrote:
>
> > The second issue is where plperl returns a large result set.
I have attached the following seven patches to address this problem:
1. Trivial. Replaces some errant spaces with tabs.
2. Trivial. Fixes the spelling of Jan's name, and gets rid of many
inane, useless, annoying, and often misleading comments. Here's
a sample: "plperl_init_all() - Initialize all".
(I have tried to add some useful comments here and there, and will
continue to do so now and again.)
3. Trivial. Splits up some long lines.
4. Converts SRFs in PL/Perl to use a Tuplestore and SFRM_Materialize
to return the result set, based on the PL/PgSQL model.
There are two major consequences: result sets will spill to disk when
they can no longer fit in work_mem; and "select foo_srf()" no longer
works. (I didn't lose sleep over the latter, since that form is not
valid in PL/PgSQL, and it's not documented in PL/Perl.)
5. Trivial, but important. Fixes use of "undef" instead of undef. This
would cause empty functions to fail in bizarre ways. I suspect that
there's still another (old) bug here. I'll investigate further.
6. Moves the majority of (4) out into a new plperl_return_next()
function, to make it possible to expose the functionality to
Perl; cleans up some of the code besides.
7. Add an spi_return_next function for use in Perl code.
If you want to apply the patches and try them out, 8-composite.diff is
what you should use. (Note: my patches depend upon Andrew's use-strict
and %_SHARED patches being applied.)
Here's something to try:
create or replace function foo() returns setof record as $$
$i = 0;
for ("World", "PostgreSQL", "PL/Perl") {
spi_return_next({f1=>++$i, f2=>'Hello', f3=>$_});
}
return;
$$ language plperl;
select * from foo() as (f1 integer, f2 text, f3 text);
(Many thanks to Andrews Dunstan and Supernews for their help.)
Abhijit Menon-Sen
2005-06-04 22:33:06 +02:00
|
|
|
* called return_next() for each element of the array, to handle
|
|
|
|
* old SRFs that didn't know about return_next(). Any other sort
|
2005-08-12 23:26:32 +02:00
|
|
|
* of return value is an error.
|
|
|
|
*/
|
At 2005-05-21 20:18:50 +0530, ams@oryx.com wrote:
>
> > The second issue is where plperl returns a large result set.
I have attached the following seven patches to address this problem:
1. Trivial. Replaces some errant spaces with tabs.
2. Trivial. Fixes the spelling of Jan's name, and gets rid of many
inane, useless, annoying, and often misleading comments. Here's
a sample: "plperl_init_all() - Initialize all".
(I have tried to add some useful comments here and there, and will
continue to do so now and again.)
3. Trivial. Splits up some long lines.
4. Converts SRFs in PL/Perl to use a Tuplestore and SFRM_Materialize
to return the result set, based on the PL/PgSQL model.
There are two major consequences: result sets will spill to disk when
they can no longer fit in work_mem; and "select foo_srf()" no longer
works. (I didn't lose sleep over the latter, since that form is not
valid in PL/PgSQL, and it's not documented in PL/Perl.)
5. Trivial, but important. Fixes use of "undef" instead of undef. This
would cause empty functions to fail in bizarre ways. I suspect that
there's still another (old) bug here. I'll investigate further.
6. Moves the majority of (4) out into a new plperl_return_next()
function, to make it possible to expose the functionality to
Perl; cleans up some of the code besides.
7. Add an spi_return_next function for use in Perl code.
If you want to apply the patches and try them out, 8-composite.diff is
what you should use. (Note: my patches depend upon Andrew's use-strict
and %_SHARED patches being applied.)
Here's something to try:
create or replace function foo() returns setof record as $$
$i = 0;
for ("World", "PostgreSQL", "PL/Perl") {
spi_return_next({f1=>++$i, f2=>'Hello', f3=>$_});
}
return;
$$ language plperl;
select * from foo() as (f1 integer, f2 text, f3 text);
(Many thanks to Andrews Dunstan and Supernews for their help.)
Abhijit Menon-Sen
2005-06-04 22:33:06 +02:00
|
|
|
if (SvTYPE(perlret) == SVt_RV &&
|
|
|
|
SvTYPE(SvRV(perlret)) == SVt_PVAV)
|
2004-07-01 22:50:22 +02:00
|
|
|
{
|
At 2005-05-21 20:18:50 +0530, ams@oryx.com wrote:
>
> > The second issue is where plperl returns a large result set.
I have attached the following seven patches to address this problem:
1. Trivial. Replaces some errant spaces with tabs.
2. Trivial. Fixes the spelling of Jan's name, and gets rid of many
inane, useless, annoying, and often misleading comments. Here's
a sample: "plperl_init_all() - Initialize all".
(I have tried to add some useful comments here and there, and will
continue to do so now and again.)
3. Trivial. Splits up some long lines.
4. Converts SRFs in PL/Perl to use a Tuplestore and SFRM_Materialize
to return the result set, based on the PL/PgSQL model.
There are two major consequences: result sets will spill to disk when
they can no longer fit in work_mem; and "select foo_srf()" no longer
works. (I didn't lose sleep over the latter, since that form is not
valid in PL/PgSQL, and it's not documented in PL/Perl.)
5. Trivial, but important. Fixes use of "undef" instead of undef. This
would cause empty functions to fail in bizarre ways. I suspect that
there's still another (old) bug here. I'll investigate further.
6. Moves the majority of (4) out into a new plperl_return_next()
function, to make it possible to expose the functionality to
Perl; cleans up some of the code besides.
7. Add an spi_return_next function for use in Perl code.
If you want to apply the patches and try them out, 8-composite.diff is
what you should use. (Note: my patches depend upon Andrew's use-strict
and %_SHARED patches being applied.)
Here's something to try:
create or replace function foo() returns setof record as $$
$i = 0;
for ("World", "PostgreSQL", "PL/Perl") {
spi_return_next({f1=>++$i, f2=>'Hello', f3=>$_});
}
return;
$$ language plperl;
select * from foo() as (f1 integer, f2 text, f3 text);
(Many thanks to Andrews Dunstan and Supernews for their help.)
Abhijit Menon-Sen
2005-06-04 22:33:06 +02:00
|
|
|
int i = 0;
|
|
|
|
SV **svp = 0;
|
|
|
|
AV *rav = (AV *)SvRV(perlret);
|
2005-07-10 17:32:47 +02:00
|
|
|
while ((svp = av_fetch(rav, i, FALSE)) != NULL)
|
|
|
|
{
|
At 2005-05-21 20:18:50 +0530, ams@oryx.com wrote:
>
> > The second issue is where plperl returns a large result set.
I have attached the following seven patches to address this problem:
1. Trivial. Replaces some errant spaces with tabs.
2. Trivial. Fixes the spelling of Jan's name, and gets rid of many
inane, useless, annoying, and often misleading comments. Here's
a sample: "plperl_init_all() - Initialize all".
(I have tried to add some useful comments here and there, and will
continue to do so now and again.)
3. Trivial. Splits up some long lines.
4. Converts SRFs in PL/Perl to use a Tuplestore and SFRM_Materialize
to return the result set, based on the PL/PgSQL model.
There are two major consequences: result sets will spill to disk when
they can no longer fit in work_mem; and "select foo_srf()" no longer
works. (I didn't lose sleep over the latter, since that form is not
valid in PL/PgSQL, and it's not documented in PL/Perl.)
5. Trivial, but important. Fixes use of "undef" instead of undef. This
would cause empty functions to fail in bizarre ways. I suspect that
there's still another (old) bug here. I'll investigate further.
6. Moves the majority of (4) out into a new plperl_return_next()
function, to make it possible to expose the functionality to
Perl; cleans up some of the code besides.
7. Add an spi_return_next function for use in Perl code.
If you want to apply the patches and try them out, 8-composite.diff is
what you should use. (Note: my patches depend upon Andrew's use-strict
and %_SHARED patches being applied.)
Here's something to try:
create or replace function foo() returns setof record as $$
$i = 0;
for ("World", "PostgreSQL", "PL/Perl") {
spi_return_next({f1=>++$i, f2=>'Hello', f3=>$_});
}
return;
$$ language plperl;
select * from foo() as (f1 integer, f2 text, f3 text);
(Many thanks to Andrews Dunstan and Supernews for their help.)
Abhijit Menon-Sen
2005-06-04 22:33:06 +02:00
|
|
|
plperl_return_next(*svp);
|
|
|
|
i++;
|
|
|
|
}
|
2004-07-01 22:50:22 +02:00
|
|
|
}
|
At 2005-05-21 20:18:50 +0530, ams@oryx.com wrote:
>
> > The second issue is where plperl returns a large result set.
I have attached the following seven patches to address this problem:
1. Trivial. Replaces some errant spaces with tabs.
2. Trivial. Fixes the spelling of Jan's name, and gets rid of many
inane, useless, annoying, and often misleading comments. Here's
a sample: "plperl_init_all() - Initialize all".
(I have tried to add some useful comments here and there, and will
continue to do so now and again.)
3. Trivial. Splits up some long lines.
4. Converts SRFs in PL/Perl to use a Tuplestore and SFRM_Materialize
to return the result set, based on the PL/PgSQL model.
There are two major consequences: result sets will spill to disk when
they can no longer fit in work_mem; and "select foo_srf()" no longer
works. (I didn't lose sleep over the latter, since that form is not
valid in PL/PgSQL, and it's not documented in PL/Perl.)
5. Trivial, but important. Fixes use of "undef" instead of undef. This
would cause empty functions to fail in bizarre ways. I suspect that
there's still another (old) bug here. I'll investigate further.
6. Moves the majority of (4) out into a new plperl_return_next()
function, to make it possible to expose the functionality to
Perl; cleans up some of the code besides.
7. Add an spi_return_next function for use in Perl code.
If you want to apply the patches and try them out, 8-composite.diff is
what you should use. (Note: my patches depend upon Andrew's use-strict
and %_SHARED patches being applied.)
Here's something to try:
create or replace function foo() returns setof record as $$
$i = 0;
for ("World", "PostgreSQL", "PL/Perl") {
spi_return_next({f1=>++$i, f2=>'Hello', f3=>$_});
}
return;
$$ language plperl;
select * from foo() as (f1 integer, f2 text, f3 text);
(Many thanks to Andrews Dunstan and Supernews for their help.)
Abhijit Menon-Sen
2005-06-04 22:33:06 +02:00
|
|
|
else if (SvTYPE(perlret) != SVt_NULL)
|
2004-07-01 22:50:22 +02:00
|
|
|
{
|
2004-11-29 21:11:06 +01:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DATATYPE_MISMATCH),
|
At 2005-05-21 20:18:50 +0530, ams@oryx.com wrote:
>
> > The second issue is where plperl returns a large result set.
I have attached the following seven patches to address this problem:
1. Trivial. Replaces some errant spaces with tabs.
2. Trivial. Fixes the spelling of Jan's name, and gets rid of many
inane, useless, annoying, and often misleading comments. Here's
a sample: "plperl_init_all() - Initialize all".
(I have tried to add some useful comments here and there, and will
continue to do so now and again.)
3. Trivial. Splits up some long lines.
4. Converts SRFs in PL/Perl to use a Tuplestore and SFRM_Materialize
to return the result set, based on the PL/PgSQL model.
There are two major consequences: result sets will spill to disk when
they can no longer fit in work_mem; and "select foo_srf()" no longer
works. (I didn't lose sleep over the latter, since that form is not
valid in PL/PgSQL, and it's not documented in PL/Perl.)
5. Trivial, but important. Fixes use of "undef" instead of undef. This
would cause empty functions to fail in bizarre ways. I suspect that
there's still another (old) bug here. I'll investigate further.
6. Moves the majority of (4) out into a new plperl_return_next()
function, to make it possible to expose the functionality to
Perl; cleans up some of the code besides.
7. Add an spi_return_next function for use in Perl code.
If you want to apply the patches and try them out, 8-composite.diff is
what you should use. (Note: my patches depend upon Andrew's use-strict
and %_SHARED patches being applied.)
Here's something to try:
create or replace function foo() returns setof record as $$
$i = 0;
for ("World", "PostgreSQL", "PL/Perl") {
spi_return_next({f1=>++$i, f2=>'Hello', f3=>$_});
}
return;
$$ language plperl;
select * from foo() as (f1 integer, f2 text, f3 text);
(Many thanks to Andrews Dunstan and Supernews for their help.)
Abhijit Menon-Sen
2005-06-04 22:33:06 +02:00
|
|
|
errmsg("set-returning Perl function must return "
|
|
|
|
"reference to array or use return_next")));
|
The attached patch, which incorporates the previous one sent and
currently unapplied regarding spi_internal.c, makes some additional
fixes relating to return types, and also contains the fix for
preventing the use of insecure versions of Safe.pm.
There is one remaing return case that does not appear to work, namely
return of a composite directly in a select, i.e. if foo returns some
composite type, 'select * from foo()' works but 'select foo()' doesn't.
We will either fix that or document it as a limitation.
The function plperl_func_handler is a mess - I will try to get it
cleaned up (and split up) in a subsequent patch, time permitting.
Also, reiterating previous advice - this changes slightly the API for
spi_exec_query - the returned object has either 2 or 3 members: 'status'
(string) and 'proceesed' (int,- number of rows) and, if rows are
returned, 'rows' (array of tuple hashes).
Andrew Dunstan
2004-07-12 16:31:04 +02:00
|
|
|
}
|
2004-08-29 07:07:03 +02:00
|
|
|
|
At 2005-05-21 20:18:50 +0530, ams@oryx.com wrote:
>
> > The second issue is where plperl returns a large result set.
I have attached the following seven patches to address this problem:
1. Trivial. Replaces some errant spaces with tabs.
2. Trivial. Fixes the spelling of Jan's name, and gets rid of many
inane, useless, annoying, and often misleading comments. Here's
a sample: "plperl_init_all() - Initialize all".
(I have tried to add some useful comments here and there, and will
continue to do so now and again.)
3. Trivial. Splits up some long lines.
4. Converts SRFs in PL/Perl to use a Tuplestore and SFRM_Materialize
to return the result set, based on the PL/PgSQL model.
There are two major consequences: result sets will spill to disk when
they can no longer fit in work_mem; and "select foo_srf()" no longer
works. (I didn't lose sleep over the latter, since that form is not
valid in PL/PgSQL, and it's not documented in PL/Perl.)
5. Trivial, but important. Fixes use of "undef" instead of undef. This
would cause empty functions to fail in bizarre ways. I suspect that
there's still another (old) bug here. I'll investigate further.
6. Moves the majority of (4) out into a new plperl_return_next()
function, to make it possible to expose the functionality to
Perl; cleans up some of the code besides.
7. Add an spi_return_next function for use in Perl code.
If you want to apply the patches and try them out, 8-composite.diff is
what you should use. (Note: my patches depend upon Andrew's use-strict
and %_SHARED patches being applied.)
Here's something to try:
create or replace function foo() returns setof record as $$
$i = 0;
for ("World", "PostgreSQL", "PL/Perl") {
spi_return_next({f1=>++$i, f2=>'Hello', f3=>$_});
}
return;
$$ language plperl;
select * from foo() as (f1 integer, f2 text, f3 text);
(Many thanks to Andrews Dunstan and Supernews for their help.)
Abhijit Menon-Sen
2005-06-04 22:33:06 +02:00
|
|
|
rsi->returnMode = SFRM_Materialize;
|
2005-07-12 03:16:22 +02:00
|
|
|
if (plperl_current_tuple_store)
|
2005-07-10 17:32:47 +02:00
|
|
|
{
|
2005-07-12 03:16:22 +02:00
|
|
|
rsi->setResult = plperl_current_tuple_store;
|
|
|
|
rsi->setDesc = plperl_current_tuple_desc;
|
The attached patch, which incorporates the previous one sent and
currently unapplied regarding spi_internal.c, makes some additional
fixes relating to return types, and also contains the fix for
preventing the use of insecure versions of Safe.pm.
There is one remaing return case that does not appear to work, namely
return of a composite directly in a select, i.e. if foo returns some
composite type, 'select * from foo()' works but 'select foo()' doesn't.
We will either fix that or document it as a limitation.
The function plperl_func_handler is a mess - I will try to get it
cleaned up (and split up) in a subsequent patch, time permitting.
Also, reiterating previous advice - this changes slightly the API for
spi_exec_query - the returned object has either 2 or 3 members: 'status'
(string) and 'proceesed' (int,- number of rows) and, if rows are
returned, 'rows' (array of tuple hashes).
Andrew Dunstan
2004-07-12 16:31:04 +02:00
|
|
|
}
|
At 2005-05-21 20:18:50 +0530, ams@oryx.com wrote:
>
> > The second issue is where plperl returns a large result set.
I have attached the following seven patches to address this problem:
1. Trivial. Replaces some errant spaces with tabs.
2. Trivial. Fixes the spelling of Jan's name, and gets rid of many
inane, useless, annoying, and often misleading comments. Here's
a sample: "plperl_init_all() - Initialize all".
(I have tried to add some useful comments here and there, and will
continue to do so now and again.)
3. Trivial. Splits up some long lines.
4. Converts SRFs in PL/Perl to use a Tuplestore and SFRM_Materialize
to return the result set, based on the PL/PgSQL model.
There are two major consequences: result sets will spill to disk when
they can no longer fit in work_mem; and "select foo_srf()" no longer
works. (I didn't lose sleep over the latter, since that form is not
valid in PL/PgSQL, and it's not documented in PL/Perl.)
5. Trivial, but important. Fixes use of "undef" instead of undef. This
would cause empty functions to fail in bizarre ways. I suspect that
there's still another (old) bug here. I'll investigate further.
6. Moves the majority of (4) out into a new plperl_return_next()
function, to make it possible to expose the functionality to
Perl; cleans up some of the code besides.
7. Add an spi_return_next function for use in Perl code.
If you want to apply the patches and try them out, 8-composite.diff is
what you should use. (Note: my patches depend upon Andrew's use-strict
and %_SHARED patches being applied.)
Here's something to try:
create or replace function foo() returns setof record as $$
$i = 0;
for ("World", "PostgreSQL", "PL/Perl") {
spi_return_next({f1=>++$i, f2=>'Hello', f3=>$_});
}
return;
$$ language plperl;
select * from foo() as (f1 integer, f2 text, f3 text);
(Many thanks to Andrews Dunstan and Supernews for their help.)
Abhijit Menon-Sen
2005-06-04 22:33:06 +02:00
|
|
|
retval = (Datum)0;
|
|
|
|
}
|
|
|
|
else if (SvTYPE(perlret) == SVt_NULL)
|
|
|
|
{
|
|
|
|
/* Return NULL if Perl code returned undef */
|
|
|
|
if (rsi && IsA(rsi, ReturnSetInfo))
|
|
|
|
rsi->isDone = ExprEndResult;
|
|
|
|
fcinfo->isnull = true;
|
|
|
|
retval = (Datum)0;
|
2004-08-29 07:07:03 +02:00
|
|
|
}
|
2004-11-22 21:31:53 +01:00
|
|
|
else if (prodesc->fn_retistuple)
|
2000-05-28 19:56:29 +02:00
|
|
|
{
|
At 2005-05-21 20:18:50 +0530, ams@oryx.com wrote:
>
> > The second issue is where plperl returns a large result set.
I have attached the following seven patches to address this problem:
1. Trivial. Replaces some errant spaces with tabs.
2. Trivial. Fixes the spelling of Jan's name, and gets rid of many
inane, useless, annoying, and often misleading comments. Here's
a sample: "plperl_init_all() - Initialize all".
(I have tried to add some useful comments here and there, and will
continue to do so now and again.)
3. Trivial. Splits up some long lines.
4. Converts SRFs in PL/Perl to use a Tuplestore and SFRM_Materialize
to return the result set, based on the PL/PgSQL model.
There are two major consequences: result sets will spill to disk when
they can no longer fit in work_mem; and "select foo_srf()" no longer
works. (I didn't lose sleep over the latter, since that form is not
valid in PL/PgSQL, and it's not documented in PL/Perl.)
5. Trivial, but important. Fixes use of "undef" instead of undef. This
would cause empty functions to fail in bizarre ways. I suspect that
there's still another (old) bug here. I'll investigate further.
6. Moves the majority of (4) out into a new plperl_return_next()
function, to make it possible to expose the functionality to
Perl; cleans up some of the code besides.
7. Add an spi_return_next function for use in Perl code.
If you want to apply the patches and try them out, 8-composite.diff is
what you should use. (Note: my patches depend upon Andrew's use-strict
and %_SHARED patches being applied.)
Here's something to try:
create or replace function foo() returns setof record as $$
$i = 0;
for ("World", "PostgreSQL", "PL/Perl") {
spi_return_next({f1=>++$i, f2=>'Hello', f3=>$_});
}
return;
$$ language plperl;
select * from foo() as (f1 integer, f2 text, f3 text);
(Many thanks to Andrews Dunstan and Supernews for their help.)
Abhijit Menon-Sen
2005-06-04 22:33:06 +02:00
|
|
|
/* Return a perl hash converted to a Datum */
|
|
|
|
TupleDesc td;
|
2004-11-22 21:31:53 +01:00
|
|
|
AttInMetadata *attinmeta;
|
At 2005-05-21 20:18:50 +0530, ams@oryx.com wrote:
>
> > The second issue is where plperl returns a large result set.
I have attached the following seven patches to address this problem:
1. Trivial. Replaces some errant spaces with tabs.
2. Trivial. Fixes the spelling of Jan's name, and gets rid of many
inane, useless, annoying, and often misleading comments. Here's
a sample: "plperl_init_all() - Initialize all".
(I have tried to add some useful comments here and there, and will
continue to do so now and again.)
3. Trivial. Splits up some long lines.
4. Converts SRFs in PL/Perl to use a Tuplestore and SFRM_Materialize
to return the result set, based on the PL/PgSQL model.
There are two major consequences: result sets will spill to disk when
they can no longer fit in work_mem; and "select foo_srf()" no longer
works. (I didn't lose sleep over the latter, since that form is not
valid in PL/PgSQL, and it's not documented in PL/Perl.)
5. Trivial, but important. Fixes use of "undef" instead of undef. This
would cause empty functions to fail in bizarre ways. I suspect that
there's still another (old) bug here. I'll investigate further.
6. Moves the majority of (4) out into a new plperl_return_next()
function, to make it possible to expose the functionality to
Perl; cleans up some of the code besides.
7. Add an spi_return_next function for use in Perl code.
If you want to apply the patches and try them out, 8-composite.diff is
what you should use. (Note: my patches depend upon Andrew's use-strict
and %_SHARED patches being applied.)
Here's something to try:
create or replace function foo() returns setof record as $$
$i = 0;
for ("World", "PostgreSQL", "PL/Perl") {
spi_return_next({f1=>++$i, f2=>'Hello', f3=>$_});
}
return;
$$ language plperl;
select * from foo() as (f1 integer, f2 text, f3 text);
(Many thanks to Andrews Dunstan and Supernews for their help.)
Abhijit Menon-Sen
2005-06-04 22:33:06 +02:00
|
|
|
HeapTuple tup;
|
2004-11-22 21:31:53 +01:00
|
|
|
|
At 2005-05-21 20:18:50 +0530, ams@oryx.com wrote:
>
> > The second issue is where plperl returns a large result set.
I have attached the following seven patches to address this problem:
1. Trivial. Replaces some errant spaces with tabs.
2. Trivial. Fixes the spelling of Jan's name, and gets rid of many
inane, useless, annoying, and often misleading comments. Here's
a sample: "plperl_init_all() - Initialize all".
(I have tried to add some useful comments here and there, and will
continue to do so now and again.)
3. Trivial. Splits up some long lines.
4. Converts SRFs in PL/Perl to use a Tuplestore and SFRM_Materialize
to return the result set, based on the PL/PgSQL model.
There are two major consequences: result sets will spill to disk when
they can no longer fit in work_mem; and "select foo_srf()" no longer
works. (I didn't lose sleep over the latter, since that form is not
valid in PL/PgSQL, and it's not documented in PL/Perl.)
5. Trivial, but important. Fixes use of "undef" instead of undef. This
would cause empty functions to fail in bizarre ways. I suspect that
there's still another (old) bug here. I'll investigate further.
6. Moves the majority of (4) out into a new plperl_return_next()
function, to make it possible to expose the functionality to
Perl; cleans up some of the code besides.
7. Add an spi_return_next function for use in Perl code.
If you want to apply the patches and try them out, 8-composite.diff is
what you should use. (Note: my patches depend upon Andrew's use-strict
and %_SHARED patches being applied.)
Here's something to try:
create or replace function foo() returns setof record as $$
$i = 0;
for ("World", "PostgreSQL", "PL/Perl") {
spi_return_next({f1=>++$i, f2=>'Hello', f3=>$_});
}
return;
$$ language plperl;
select * from foo() as (f1 integer, f2 text, f3 text);
(Many thanks to Andrews Dunstan and Supernews for their help.)
Abhijit Menon-Sen
2005-06-04 22:33:06 +02:00
|
|
|
if (!SvOK(perlret) || SvTYPE(perlret) != SVt_RV ||
|
|
|
|
SvTYPE(SvRV(perlret)) != SVt_PVHV)
|
|
|
|
{
|
2004-11-29 21:11:06 +01:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DATATYPE_MISMATCH),
|
At 2005-05-21 20:18:50 +0530, ams@oryx.com wrote:
>
> > The second issue is where plperl returns a large result set.
I have attached the following seven patches to address this problem:
1. Trivial. Replaces some errant spaces with tabs.
2. Trivial. Fixes the spelling of Jan's name, and gets rid of many
inane, useless, annoying, and often misleading comments. Here's
a sample: "plperl_init_all() - Initialize all".
(I have tried to add some useful comments here and there, and will
continue to do so now and again.)
3. Trivial. Splits up some long lines.
4. Converts SRFs in PL/Perl to use a Tuplestore and SFRM_Materialize
to return the result set, based on the PL/PgSQL model.
There are two major consequences: result sets will spill to disk when
they can no longer fit in work_mem; and "select foo_srf()" no longer
works. (I didn't lose sleep over the latter, since that form is not
valid in PL/PgSQL, and it's not documented in PL/Perl.)
5. Trivial, but important. Fixes use of "undef" instead of undef. This
would cause empty functions to fail in bizarre ways. I suspect that
there's still another (old) bug here. I'll investigate further.
6. Moves the majority of (4) out into a new plperl_return_next()
function, to make it possible to expose the functionality to
Perl; cleans up some of the code besides.
7. Add an spi_return_next function for use in Perl code.
If you want to apply the patches and try them out, 8-composite.diff is
what you should use. (Note: my patches depend upon Andrew's use-strict
and %_SHARED patches being applied.)
Here's something to try:
create or replace function foo() returns setof record as $$
$i = 0;
for ("World", "PostgreSQL", "PL/Perl") {
spi_return_next({f1=>++$i, f2=>'Hello', f3=>$_});
}
return;
$$ language plperl;
select * from foo() as (f1 integer, f2 text, f3 text);
(Many thanks to Andrews Dunstan and Supernews for their help.)
Abhijit Menon-Sen
2005-06-04 22:33:06 +02:00
|
|
|
errmsg("composite-returning Perl function "
|
|
|
|
"must return reference to hash")));
|
|
|
|
}
|
2004-11-23 01:21:24 +01:00
|
|
|
|
At 2005-05-21 20:18:50 +0530, ams@oryx.com wrote:
>
> > The second issue is where plperl returns a large result set.
I have attached the following seven patches to address this problem:
1. Trivial. Replaces some errant spaces with tabs.
2. Trivial. Fixes the spelling of Jan's name, and gets rid of many
inane, useless, annoying, and often misleading comments. Here's
a sample: "plperl_init_all() - Initialize all".
(I have tried to add some useful comments here and there, and will
continue to do so now and again.)
3. Trivial. Splits up some long lines.
4. Converts SRFs in PL/Perl to use a Tuplestore and SFRM_Materialize
to return the result set, based on the PL/PgSQL model.
There are two major consequences: result sets will spill to disk when
they can no longer fit in work_mem; and "select foo_srf()" no longer
works. (I didn't lose sleep over the latter, since that form is not
valid in PL/PgSQL, and it's not documented in PL/Perl.)
5. Trivial, but important. Fixes use of "undef" instead of undef. This
would cause empty functions to fail in bizarre ways. I suspect that
there's still another (old) bug here. I'll investigate further.
6. Moves the majority of (4) out into a new plperl_return_next()
function, to make it possible to expose the functionality to
Perl; cleans up some of the code besides.
7. Add an spi_return_next function for use in Perl code.
If you want to apply the patches and try them out, 8-composite.diff is
what you should use. (Note: my patches depend upon Andrew's use-strict
and %_SHARED patches being applied.)
Here's something to try:
create or replace function foo() returns setof record as $$
$i = 0;
for ("World", "PostgreSQL", "PL/Perl") {
spi_return_next({f1=>++$i, f2=>'Hello', f3=>$_});
}
return;
$$ language plperl;
select * from foo() as (f1 integer, f2 text, f3 text);
(Many thanks to Andrews Dunstan and Supernews for their help.)
Abhijit Menon-Sen
2005-06-04 22:33:06 +02:00
|
|
|
/* XXX should cache the attinmeta data instead of recomputing */
|
|
|
|
if (get_call_result_type(fcinfo, NULL, &td) != TYPEFUNC_COMPOSITE)
|
|
|
|
{
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
|
|
|
errmsg("function returning record called in context "
|
|
|
|
"that cannot accept type record")));
|
|
|
|
}
|
2004-11-22 21:31:53 +01:00
|
|
|
|
At 2005-05-21 20:18:50 +0530, ams@oryx.com wrote:
>
> > The second issue is where plperl returns a large result set.
I have attached the following seven patches to address this problem:
1. Trivial. Replaces some errant spaces with tabs.
2. Trivial. Fixes the spelling of Jan's name, and gets rid of many
inane, useless, annoying, and often misleading comments. Here's
a sample: "plperl_init_all() - Initialize all".
(I have tried to add some useful comments here and there, and will
continue to do so now and again.)
3. Trivial. Splits up some long lines.
4. Converts SRFs in PL/Perl to use a Tuplestore and SFRM_Materialize
to return the result set, based on the PL/PgSQL model.
There are two major consequences: result sets will spill to disk when
they can no longer fit in work_mem; and "select foo_srf()" no longer
works. (I didn't lose sleep over the latter, since that form is not
valid in PL/PgSQL, and it's not documented in PL/Perl.)
5. Trivial, but important. Fixes use of "undef" instead of undef. This
would cause empty functions to fail in bizarre ways. I suspect that
there's still another (old) bug here. I'll investigate further.
6. Moves the majority of (4) out into a new plperl_return_next()
function, to make it possible to expose the functionality to
Perl; cleans up some of the code besides.
7. Add an spi_return_next function for use in Perl code.
If you want to apply the patches and try them out, 8-composite.diff is
what you should use. (Note: my patches depend upon Andrew's use-strict
and %_SHARED patches being applied.)
Here's something to try:
create or replace function foo() returns setof record as $$
$i = 0;
for ("World", "PostgreSQL", "PL/Perl") {
spi_return_next({f1=>++$i, f2=>'Hello', f3=>$_});
}
return;
$$ language plperl;
select * from foo() as (f1 integer, f2 text, f3 text);
(Many thanks to Andrews Dunstan and Supernews for their help.)
Abhijit Menon-Sen
2005-06-04 22:33:06 +02:00
|
|
|
attinmeta = TupleDescGetAttInMetadata(td);
|
|
|
|
tup = plperl_build_tuple_result((HV *)SvRV(perlret), attinmeta);
|
2004-11-22 21:31:53 +01:00
|
|
|
retval = HeapTupleGetDatum(tup);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2005-07-10 17:32:47 +02:00
|
|
|
/* Return a perl string converted to a Datum */
|
|
|
|
char *val;
|
|
|
|
|
2005-07-12 22:35:42 +02:00
|
|
|
if (prodesc->fn_retisarray && SvROK(perlret) &&
|
|
|
|
SvTYPE(SvRV(perlret)) == SVt_PVAV)
|
2005-07-10 17:32:47 +02:00
|
|
|
{
|
|
|
|
array_ret = plperl_convert_to_pg_array(perlret);
|
|
|
|
SvREFCNT_dec(perlret);
|
|
|
|
perlret = array_ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
val = SvPV(perlret, PL_na);
|
|
|
|
|
2004-11-22 21:31:53 +01:00
|
|
|
retval = FunctionCall3(&prodesc->result_in_func,
|
|
|
|
CStringGetDatum(val),
|
|
|
|
ObjectIdGetDatum(prodesc->result_typioparam),
|
|
|
|
Int32GetDatum(-1));
|
2000-05-28 19:56:29 +02:00
|
|
|
}
|
2000-01-20 06:08:58 +01:00
|
|
|
|
2005-07-12 03:16:22 +02:00
|
|
|
if (array_ret == NULL)
|
|
|
|
SvREFCNT_dec(perlret);
|
|
|
|
|
2000-01-20 06:08:58 +01:00
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
At 2005-05-21 20:18:50 +0530, ams@oryx.com wrote:
>
> > The second issue is where plperl returns a large result set.
I have attached the following seven patches to address this problem:
1. Trivial. Replaces some errant spaces with tabs.
2. Trivial. Fixes the spelling of Jan's name, and gets rid of many
inane, useless, annoying, and often misleading comments. Here's
a sample: "plperl_init_all() - Initialize all".
(I have tried to add some useful comments here and there, and will
continue to do so now and again.)
3. Trivial. Splits up some long lines.
4. Converts SRFs in PL/Perl to use a Tuplestore and SFRM_Materialize
to return the result set, based on the PL/PgSQL model.
There are two major consequences: result sets will spill to disk when
they can no longer fit in work_mem; and "select foo_srf()" no longer
works. (I didn't lose sleep over the latter, since that form is not
valid in PL/PgSQL, and it's not documented in PL/Perl.)
5. Trivial, but important. Fixes use of "undef" instead of undef. This
would cause empty functions to fail in bizarre ways. I suspect that
there's still another (old) bug here. I'll investigate further.
6. Moves the majority of (4) out into a new plperl_return_next()
function, to make it possible to expose the functionality to
Perl; cleans up some of the code besides.
7. Add an spi_return_next function for use in Perl code.
If you want to apply the patches and try them out, 8-composite.diff is
what you should use. (Note: my patches depend upon Andrew's use-strict
and %_SHARED patches being applied.)
Here's something to try:
create or replace function foo() returns setof record as $$
$i = 0;
for ("World", "PostgreSQL", "PL/Perl") {
spi_return_next({f1=>++$i, f2=>'Hello', f3=>$_});
}
return;
$$ language plperl;
select * from foo() as (f1 integer, f2 text, f3 text);
(Many thanks to Andrews Dunstan and Supernews for their help.)
Abhijit Menon-Sen
2005-06-04 22:33:06 +02:00
|
|
|
|
2004-07-01 22:50:22 +02:00
|
|
|
static Datum
|
|
|
|
plperl_trigger_handler(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
plperl_proc_desc *prodesc;
|
|
|
|
SV *perlret;
|
|
|
|
Datum retval;
|
|
|
|
SV *svTD;
|
|
|
|
HV *hvTD;
|
|
|
|
|
2004-11-22 21:31:53 +01:00
|
|
|
/* Connect to SPI manager */
|
|
|
|
if (SPI_connect() != SPI_OK_CONNECT)
|
|
|
|
elog(ERROR, "could not connect to SPI manager");
|
|
|
|
|
2004-07-01 22:50:22 +02:00
|
|
|
/* Find or compile the function */
|
|
|
|
prodesc = compile_plperl_function(fcinfo->flinfo->fn_oid, true);
|
|
|
|
|
2004-09-13 22:10:13 +02:00
|
|
|
plperl_current_prodesc = prodesc;
|
|
|
|
|
2004-07-01 22:50:22 +02:00
|
|
|
svTD = plperl_trigger_build_args(fcinfo);
|
|
|
|
perlret = plperl_call_perl_trigger_func(prodesc, fcinfo, svTD);
|
At 2005-05-21 20:18:50 +0530, ams@oryx.com wrote:
>
> > The second issue is where plperl returns a large result set.
I have attached the following seven patches to address this problem:
1. Trivial. Replaces some errant spaces with tabs.
2. Trivial. Fixes the spelling of Jan's name, and gets rid of many
inane, useless, annoying, and often misleading comments. Here's
a sample: "plperl_init_all() - Initialize all".
(I have tried to add some useful comments here and there, and will
continue to do so now and again.)
3. Trivial. Splits up some long lines.
4. Converts SRFs in PL/Perl to use a Tuplestore and SFRM_Materialize
to return the result set, based on the PL/PgSQL model.
There are two major consequences: result sets will spill to disk when
they can no longer fit in work_mem; and "select foo_srf()" no longer
works. (I didn't lose sleep over the latter, since that form is not
valid in PL/PgSQL, and it's not documented in PL/Perl.)
5. Trivial, but important. Fixes use of "undef" instead of undef. This
would cause empty functions to fail in bizarre ways. I suspect that
there's still another (old) bug here. I'll investigate further.
6. Moves the majority of (4) out into a new plperl_return_next()
function, to make it possible to expose the functionality to
Perl; cleans up some of the code besides.
7. Add an spi_return_next function for use in Perl code.
If you want to apply the patches and try them out, 8-composite.diff is
what you should use. (Note: my patches depend upon Andrew's use-strict
and %_SHARED patches being applied.)
Here's something to try:
create or replace function foo() returns setof record as $$
$i = 0;
for ("World", "PostgreSQL", "PL/Perl") {
spi_return_next({f1=>++$i, f2=>'Hello', f3=>$_});
}
return;
$$ language plperl;
select * from foo() as (f1 integer, f2 text, f3 text);
(Many thanks to Andrews Dunstan and Supernews for their help.)
Abhijit Menon-Sen
2005-06-04 22:33:06 +02:00
|
|
|
hvTD = (HV *) SvRV(svTD);
|
2004-07-01 22:50:22 +02:00
|
|
|
|
|
|
|
/************************************************************
|
|
|
|
* Disconnect from SPI manager and then create the return
|
|
|
|
* values datum (if the input function does a palloc for it
|
|
|
|
* this must not be allocated in the SPI memory context
|
|
|
|
* because SPI_finish would free it).
|
|
|
|
************************************************************/
|
|
|
|
if (SPI_finish() != SPI_OK_FINISH)
|
2004-11-29 21:11:06 +01:00
|
|
|
elog(ERROR, "SPI_finish() failed");
|
2004-07-01 22:50:22 +02:00
|
|
|
|
2004-11-23 01:21:24 +01:00
|
|
|
if (!(perlret && SvOK(perlret) && SvTYPE(perlret) != SVt_NULL))
|
2004-07-01 22:50:22 +02:00
|
|
|
{
|
2004-11-23 01:21:24 +01:00
|
|
|
/* undef result means go ahead with original tuple */
|
2004-07-01 22:50:22 +02:00
|
|
|
TriggerData *trigdata = ((TriggerData *) fcinfo->context);
|
|
|
|
|
|
|
|
if (TRIGGER_FIRED_BY_INSERT(trigdata->tg_event))
|
|
|
|
retval = (Datum) trigdata->tg_trigtuple;
|
|
|
|
else if (TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event))
|
|
|
|
retval = (Datum) trigdata->tg_newtuple;
|
|
|
|
else if (TRIGGER_FIRED_BY_DELETE(trigdata->tg_event))
|
|
|
|
retval = (Datum) trigdata->tg_trigtuple;
|
2004-11-17 22:23:36 +01:00
|
|
|
else
|
|
|
|
retval = (Datum) 0; /* can this happen? */
|
2004-07-01 22:50:22 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2004-11-23 01:21:24 +01:00
|
|
|
HeapTuple trv;
|
|
|
|
char *tmp;
|
2004-07-01 22:50:22 +02:00
|
|
|
|
2004-11-23 01:21:24 +01:00
|
|
|
tmp = SvPV(perlret, PL_na);
|
2004-07-01 22:50:22 +02:00
|
|
|
|
2004-11-23 01:21:24 +01:00
|
|
|
if (pg_strcasecmp(tmp, "SKIP") == 0)
|
|
|
|
trv = NULL;
|
|
|
|
else if (pg_strcasecmp(tmp, "MODIFY") == 0)
|
|
|
|
{
|
|
|
|
TriggerData *trigdata = (TriggerData *) fcinfo->context;
|
|
|
|
|
|
|
|
if (TRIGGER_FIRED_BY_INSERT(trigdata->tg_event))
|
|
|
|
trv = plperl_modify_tuple(hvTD, trigdata,
|
|
|
|
trigdata->tg_trigtuple);
|
|
|
|
else if (TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event))
|
|
|
|
trv = plperl_modify_tuple(hvTD, trigdata,
|
|
|
|
trigdata->tg_newtuple);
|
2004-07-01 22:50:22 +02:00
|
|
|
else
|
|
|
|
{
|
2004-11-29 21:11:06 +01:00
|
|
|
ereport(WARNING,
|
|
|
|
(errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED),
|
|
|
|
errmsg("ignoring modified tuple in DELETE trigger")));
|
2004-07-01 22:50:22 +02:00
|
|
|
trv = NULL;
|
|
|
|
}
|
|
|
|
}
|
2004-11-17 22:23:36 +01:00
|
|
|
else
|
2004-11-23 01:21:24 +01:00
|
|
|
{
|
2004-11-29 21:11:06 +01:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED),
|
At 2005-05-21 20:18:50 +0530, ams@oryx.com wrote:
>
> > The second issue is where plperl returns a large result set.
I have attached the following seven patches to address this problem:
1. Trivial. Replaces some errant spaces with tabs.
2. Trivial. Fixes the spelling of Jan's name, and gets rid of many
inane, useless, annoying, and often misleading comments. Here's
a sample: "plperl_init_all() - Initialize all".
(I have tried to add some useful comments here and there, and will
continue to do so now and again.)
3. Trivial. Splits up some long lines.
4. Converts SRFs in PL/Perl to use a Tuplestore and SFRM_Materialize
to return the result set, based on the PL/PgSQL model.
There are two major consequences: result sets will spill to disk when
they can no longer fit in work_mem; and "select foo_srf()" no longer
works. (I didn't lose sleep over the latter, since that form is not
valid in PL/PgSQL, and it's not documented in PL/Perl.)
5. Trivial, but important. Fixes use of "undef" instead of undef. This
would cause empty functions to fail in bizarre ways. I suspect that
there's still another (old) bug here. I'll investigate further.
6. Moves the majority of (4) out into a new plperl_return_next()
function, to make it possible to expose the functionality to
Perl; cleans up some of the code besides.
7. Add an spi_return_next function for use in Perl code.
If you want to apply the patches and try them out, 8-composite.diff is
what you should use. (Note: my patches depend upon Andrew's use-strict
and %_SHARED patches being applied.)
Here's something to try:
create or replace function foo() returns setof record as $$
$i = 0;
for ("World", "PostgreSQL", "PL/Perl") {
spi_return_next({f1=>++$i, f2=>'Hello', f3=>$_});
}
return;
$$ language plperl;
select * from foo() as (f1 integer, f2 text, f3 text);
(Many thanks to Andrews Dunstan and Supernews for their help.)
Abhijit Menon-Sen
2005-06-04 22:33:06 +02:00
|
|
|
errmsg("result of Perl trigger function must be undef, "
|
|
|
|
"\"SKIP\" or \"MODIFY\"")));
|
2004-11-23 01:21:24 +01:00
|
|
|
trv = NULL;
|
|
|
|
}
|
|
|
|
retval = PointerGetDatum(trv);
|
2004-07-01 22:50:22 +02:00
|
|
|
}
|
|
|
|
|
2004-11-23 01:21:24 +01:00
|
|
|
SvREFCNT_dec(svTD);
|
|
|
|
if (perlret)
|
|
|
|
SvREFCNT_dec(perlret);
|
2004-07-01 22:50:22 +02:00
|
|
|
|
|
|
|
return retval;
|
|
|
|
}
|
2000-01-20 06:08:58 +01:00
|
|
|
|
At 2005-05-21 20:18:50 +0530, ams@oryx.com wrote:
>
> > The second issue is where plperl returns a large result set.
I have attached the following seven patches to address this problem:
1. Trivial. Replaces some errant spaces with tabs.
2. Trivial. Fixes the spelling of Jan's name, and gets rid of many
inane, useless, annoying, and often misleading comments. Here's
a sample: "plperl_init_all() - Initialize all".
(I have tried to add some useful comments here and there, and will
continue to do so now and again.)
3. Trivial. Splits up some long lines.
4. Converts SRFs in PL/Perl to use a Tuplestore and SFRM_Materialize
to return the result set, based on the PL/PgSQL model.
There are two major consequences: result sets will spill to disk when
they can no longer fit in work_mem; and "select foo_srf()" no longer
works. (I didn't lose sleep over the latter, since that form is not
valid in PL/PgSQL, and it's not documented in PL/Perl.)
5. Trivial, but important. Fixes use of "undef" instead of undef. This
would cause empty functions to fail in bizarre ways. I suspect that
there's still another (old) bug here. I'll investigate further.
6. Moves the majority of (4) out into a new plperl_return_next()
function, to make it possible to expose the functionality to
Perl; cleans up some of the code besides.
7. Add an spi_return_next function for use in Perl code.
If you want to apply the patches and try them out, 8-composite.diff is
what you should use. (Note: my patches depend upon Andrew's use-strict
and %_SHARED patches being applied.)
Here's something to try:
create or replace function foo() returns setof record as $$
$i = 0;
for ("World", "PostgreSQL", "PL/Perl") {
spi_return_next({f1=>++$i, f2=>'Hello', f3=>$_});
}
return;
$$ language plperl;
select * from foo() as (f1 integer, f2 text, f3 text);
(Many thanks to Andrews Dunstan and Supernews for their help.)
Abhijit Menon-Sen
2005-06-04 22:33:06 +02:00
|
|
|
|
2001-10-20 00:43:49 +02:00
|
|
|
static plperl_proc_desc *
|
|
|
|
compile_plperl_function(Oid fn_oid, bool is_trigger)
|
2000-01-20 06:08:58 +01:00
|
|
|
{
|
2001-10-20 00:43:49 +02:00
|
|
|
HeapTuple procTup;
|
|
|
|
Form_pg_proc procStruct;
|
|
|
|
char internal_proname[64];
|
|
|
|
int proname_len;
|
|
|
|
plperl_proc_desc *prodesc = NULL;
|
2000-01-20 06:08:58 +01:00
|
|
|
int i;
|
2004-10-15 19:08:26 +02:00
|
|
|
SV **svp;
|
2000-01-20 06:08:58 +01:00
|
|
|
|
2001-10-20 00:43:49 +02:00
|
|
|
/* We'll need the pg_proc tuple in any case... */
|
|
|
|
procTup = SearchSysCache(PROCOID,
|
|
|
|
ObjectIdGetDatum(fn_oid),
|
|
|
|
0, 0, 0);
|
|
|
|
if (!HeapTupleIsValid(procTup))
|
2003-07-26 01:37:31 +02:00
|
|
|
elog(ERROR, "cache lookup failed for function %u", fn_oid);
|
2001-10-20 00:43:49 +02:00
|
|
|
procStruct = (Form_pg_proc) GETSTRUCT(procTup);
|
2000-01-20 06:08:58 +01:00
|
|
|
|
|
|
|
/************************************************************
|
|
|
|
* Build our internal proc name from the functions Oid
|
|
|
|
************************************************************/
|
2001-10-20 00:43:49 +02:00
|
|
|
if (!is_trigger)
|
|
|
|
sprintf(internal_proname, "__PLPerl_proc_%u", fn_oid);
|
|
|
|
else
|
|
|
|
sprintf(internal_proname, "__PLPerl_proc_%u_trigger", fn_oid);
|
2004-07-01 22:50:22 +02:00
|
|
|
|
2001-10-20 00:43:49 +02:00
|
|
|
proname_len = strlen(internal_proname);
|
2000-01-20 06:08:58 +01:00
|
|
|
|
|
|
|
/************************************************************
|
|
|
|
* Lookup the internal proc name in the hashtable
|
|
|
|
************************************************************/
|
2004-10-15 19:08:26 +02:00
|
|
|
svp = hv_fetch(plperl_proc_hash, internal_proname, proname_len, FALSE);
|
|
|
|
if (svp)
|
2000-01-20 06:08:58 +01:00
|
|
|
{
|
2001-10-20 00:43:49 +02:00
|
|
|
bool uptodate;
|
|
|
|
|
2004-10-15 19:08:26 +02:00
|
|
|
prodesc = (plperl_proc_desc *) SvIV(*svp);
|
2001-10-20 00:43:49 +02:00
|
|
|
|
2000-01-20 06:08:58 +01:00
|
|
|
/************************************************************
|
2001-10-20 00:43:49 +02:00
|
|
|
* If it's present, must check whether it's still up to date.
|
|
|
|
* This is needed because CREATE OR REPLACE FUNCTION can modify the
|
|
|
|
* function's pg_proc entry without changing its OID.
|
2000-01-20 06:08:58 +01:00
|
|
|
************************************************************/
|
2002-06-15 21:54:24 +02:00
|
|
|
uptodate = (prodesc->fn_xmin == HeapTupleHeaderGetXmin(procTup->t_data) &&
|
2002-09-04 22:31:48 +02:00
|
|
|
prodesc->fn_cmin == HeapTupleHeaderGetCmin(procTup->t_data));
|
2001-10-20 00:43:49 +02:00
|
|
|
|
|
|
|
if (!uptodate)
|
|
|
|
{
|
|
|
|
/* need we delete old entry? */
|
|
|
|
prodesc = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/************************************************************
|
|
|
|
* If we haven't found it in the hashtable, we analyze
|
|
|
|
* the functions arguments and returntype and store
|
|
|
|
* the in-/out-functions in the prodesc block and create
|
|
|
|
* a new hashtable entry for it.
|
|
|
|
*
|
|
|
|
* Then we load the procedure into the Perl interpreter.
|
|
|
|
************************************************************/
|
|
|
|
if (prodesc == NULL)
|
|
|
|
{
|
|
|
|
HeapTuple langTup;
|
|
|
|
HeapTuple typeTup;
|
|
|
|
Form_pg_language langStruct;
|
|
|
|
Form_pg_type typeStruct;
|
2004-01-07 00:55:19 +01:00
|
|
|
Datum prosrcdatum;
|
|
|
|
bool isnull;
|
2000-01-20 06:08:58 +01:00
|
|
|
char *proc_source;
|
|
|
|
|
|
|
|
/************************************************************
|
|
|
|
* Allocate a new procedure description block
|
|
|
|
************************************************************/
|
|
|
|
prodesc = (plperl_proc_desc *) malloc(sizeof(plperl_proc_desc));
|
2001-10-20 00:43:49 +02:00
|
|
|
if (prodesc == NULL)
|
2003-07-26 01:37:31 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_OUT_OF_MEMORY),
|
|
|
|
errmsg("out of memory")));
|
2001-10-20 00:43:49 +02:00
|
|
|
MemSet(prodesc, 0, sizeof(plperl_proc_desc));
|
|
|
|
prodesc->proname = strdup(internal_proname);
|
2002-06-15 21:54:24 +02:00
|
|
|
prodesc->fn_xmin = HeapTupleHeaderGetXmin(procTup->t_data);
|
|
|
|
prodesc->fn_cmin = HeapTupleHeaderGetCmin(procTup->t_data);
|
2000-01-20 06:08:58 +01:00
|
|
|
|
2004-09-13 22:10:13 +02:00
|
|
|
/* Remember if function is STABLE/IMMUTABLE */
|
|
|
|
prodesc->fn_readonly =
|
|
|
|
(procStruct->provolatile != PROVOLATILE_VOLATILE);
|
|
|
|
|
2000-01-20 06:08:58 +01:00
|
|
|
/************************************************************
|
2001-10-20 00:43:49 +02:00
|
|
|
* Lookup the pg_language tuple by Oid
|
2000-01-20 06:08:58 +01:00
|
|
|
************************************************************/
|
2001-10-20 00:43:49 +02:00
|
|
|
langTup = SearchSysCache(LANGOID,
|
|
|
|
ObjectIdGetDatum(procStruct->prolang),
|
2000-11-16 23:30:52 +01:00
|
|
|
0, 0, 0);
|
2001-10-20 00:43:49 +02:00
|
|
|
if (!HeapTupleIsValid(langTup))
|
2000-01-20 06:08:58 +01:00
|
|
|
{
|
|
|
|
free(prodesc->proname);
|
|
|
|
free(prodesc);
|
2003-07-26 01:37:31 +02:00
|
|
|
elog(ERROR, "cache lookup failed for language %u",
|
2001-10-20 00:43:49 +02:00
|
|
|
procStruct->prolang);
|
2000-01-20 06:08:58 +01:00
|
|
|
}
|
2001-10-20 00:43:49 +02:00
|
|
|
langStruct = (Form_pg_language) GETSTRUCT(langTup);
|
|
|
|
prodesc->lanpltrusted = langStruct->lanpltrusted;
|
|
|
|
ReleaseSysCache(langTup);
|
2000-01-20 06:08:58 +01:00
|
|
|
|
|
|
|
/************************************************************
|
2001-10-20 00:43:49 +02:00
|
|
|
* Get the required information for input conversion of the
|
|
|
|
* return value.
|
2000-01-20 06:08:58 +01:00
|
|
|
************************************************************/
|
2001-10-20 00:43:49 +02:00
|
|
|
if (!is_trigger)
|
|
|
|
{
|
|
|
|
typeTup = SearchSysCache(TYPEOID,
|
2001-10-25 07:50:21 +02:00
|
|
|
ObjectIdGetDatum(procStruct->prorettype),
|
2001-10-20 00:43:49 +02:00
|
|
|
0, 0, 0);
|
|
|
|
if (!HeapTupleIsValid(typeTup))
|
|
|
|
{
|
|
|
|
free(prodesc->proname);
|
|
|
|
free(prodesc);
|
2003-07-26 01:37:31 +02:00
|
|
|
elog(ERROR, "cache lookup failed for type %u",
|
2002-08-22 02:01:51 +02:00
|
|
|
procStruct->prorettype);
|
2001-10-20 00:43:49 +02:00
|
|
|
}
|
|
|
|
typeStruct = (Form_pg_type) GETSTRUCT(typeTup);
|
|
|
|
|
2004-07-01 22:50:22 +02:00
|
|
|
/* Disallow pseudotype result, except VOID or RECORD */
|
2002-08-22 02:01:51 +02:00
|
|
|
if (typeStruct->typtype == 'p')
|
|
|
|
{
|
2004-07-01 22:50:22 +02:00
|
|
|
if (procStruct->prorettype == VOIDOID ||
|
|
|
|
procStruct->prorettype == RECORDOID)
|
2002-09-04 22:31:48 +02:00
|
|
|
/* okay */ ;
|
2002-09-21 20:39:26 +02:00
|
|
|
else if (procStruct->prorettype == TRIGGEROID)
|
2002-08-22 02:01:51 +02:00
|
|
|
{
|
|
|
|
free(prodesc->proname);
|
|
|
|
free(prodesc);
|
2003-07-26 01:37:31 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
At 2005-05-21 20:18:50 +0530, ams@oryx.com wrote:
>
> > The second issue is where plperl returns a large result set.
I have attached the following seven patches to address this problem:
1. Trivial. Replaces some errant spaces with tabs.
2. Trivial. Fixes the spelling of Jan's name, and gets rid of many
inane, useless, annoying, and often misleading comments. Here's
a sample: "plperl_init_all() - Initialize all".
(I have tried to add some useful comments here and there, and will
continue to do so now and again.)
3. Trivial. Splits up some long lines.
4. Converts SRFs in PL/Perl to use a Tuplestore and SFRM_Materialize
to return the result set, based on the PL/PgSQL model.
There are two major consequences: result sets will spill to disk when
they can no longer fit in work_mem; and "select foo_srf()" no longer
works. (I didn't lose sleep over the latter, since that form is not
valid in PL/PgSQL, and it's not documented in PL/Perl.)
5. Trivial, but important. Fixes use of "undef" instead of undef. This
would cause empty functions to fail in bizarre ways. I suspect that
there's still another (old) bug here. I'll investigate further.
6. Moves the majority of (4) out into a new plperl_return_next()
function, to make it possible to expose the functionality to
Perl; cleans up some of the code besides.
7. Add an spi_return_next function for use in Perl code.
If you want to apply the patches and try them out, 8-composite.diff is
what you should use. (Note: my patches depend upon Andrew's use-strict
and %_SHARED patches being applied.)
Here's something to try:
create or replace function foo() returns setof record as $$
$i = 0;
for ("World", "PostgreSQL", "PL/Perl") {
spi_return_next({f1=>++$i, f2=>'Hello', f3=>$_});
}
return;
$$ language plperl;
select * from foo() as (f1 integer, f2 text, f3 text);
(Many thanks to Andrews Dunstan and Supernews for their help.)
Abhijit Menon-Sen
2005-06-04 22:33:06 +02:00
|
|
|
errmsg("trigger functions may only be called "
|
|
|
|
"as triggers")));
|
2002-08-22 02:01:51 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
free(prodesc->proname);
|
|
|
|
free(prodesc);
|
2003-07-26 01:37:31 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
2003-08-04 02:43:34 +02:00
|
|
|
errmsg("plperl functions cannot return type %s",
|
|
|
|
format_type_be(procStruct->prorettype))));
|
2002-08-22 02:01:51 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-11-22 21:31:53 +01:00
|
|
|
prodesc->result_oid = procStruct->prorettype;
|
|
|
|
prodesc->fn_retisset = procStruct->proretset;
|
|
|
|
prodesc->fn_retistuple = (typeStruct->typtype == 'c' ||
|
|
|
|
procStruct->prorettype == RECORDOID);
|
2001-10-20 00:43:49 +02:00
|
|
|
|
2005-07-10 17:32:47 +02:00
|
|
|
prodesc->fn_retisarray =
|
|
|
|
(typeStruct->typlen == -1 && typeStruct->typelem) ;
|
|
|
|
|
2001-10-20 00:43:49 +02:00
|
|
|
perm_fmgr_info(typeStruct->typinput, &(prodesc->result_in_func));
|
2004-06-06 02:41:28 +02:00
|
|
|
prodesc->result_typioparam = getTypeIOParam(typeTup);
|
2001-10-20 00:43:49 +02:00
|
|
|
|
|
|
|
ReleaseSysCache(typeTup);
|
|
|
|
}
|
2000-01-20 06:08:58 +01:00
|
|
|
|
|
|
|
/************************************************************
|
2001-10-20 00:43:49 +02:00
|
|
|
* Get the required information for output conversion
|
|
|
|
* of all procedure arguments
|
2000-01-20 06:08:58 +01:00
|
|
|
************************************************************/
|
2001-10-20 00:43:49 +02:00
|
|
|
if (!is_trigger)
|
|
|
|
{
|
|
|
|
prodesc->nargs = procStruct->pronargs;
|
|
|
|
for (i = 0; i < prodesc->nargs; i++)
|
|
|
|
{
|
|
|
|
typeTup = SearchSysCache(TYPEOID,
|
2005-03-29 02:17:27 +02:00
|
|
|
ObjectIdGetDatum(procStruct->proargtypes.values[i]),
|
2001-10-20 00:43:49 +02:00
|
|
|
0, 0, 0);
|
|
|
|
if (!HeapTupleIsValid(typeTup))
|
|
|
|
{
|
|
|
|
free(prodesc->proname);
|
|
|
|
free(prodesc);
|
2003-07-26 01:37:31 +02:00
|
|
|
elog(ERROR, "cache lookup failed for type %u",
|
2005-03-29 02:17:27 +02:00
|
|
|
procStruct->proargtypes.values[i]);
|
2001-10-20 00:43:49 +02:00
|
|
|
}
|
|
|
|
typeStruct = (Form_pg_type) GETSTRUCT(typeTup);
|
|
|
|
|
2002-08-22 02:01:51 +02:00
|
|
|
/* Disallow pseudotype argument */
|
|
|
|
if (typeStruct->typtype == 'p')
|
|
|
|
{
|
|
|
|
free(prodesc->proname);
|
|
|
|
free(prodesc);
|
2003-07-26 01:37:31 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
2003-08-04 02:43:34 +02:00
|
|
|
errmsg("plperl functions cannot take type %s",
|
2005-03-29 02:17:27 +02:00
|
|
|
format_type_be(procStruct->proargtypes.values[i]))));
|
2002-08-22 02:01:51 +02:00
|
|
|
}
|
|
|
|
|
2004-04-01 23:28:47 +02:00
|
|
|
if (typeStruct->typtype == 'c')
|
|
|
|
prodesc->arg_is_rowtype[i] = true;
|
2001-10-20 00:43:49 +02:00
|
|
|
else
|
2004-04-01 23:28:47 +02:00
|
|
|
{
|
|
|
|
prodesc->arg_is_rowtype[i] = false;
|
|
|
|
perm_fmgr_info(typeStruct->typoutput,
|
|
|
|
&(prodesc->arg_out_func[i]));
|
|
|
|
}
|
2001-10-20 00:43:49 +02:00
|
|
|
|
|
|
|
ReleaseSysCache(typeTup);
|
|
|
|
}
|
|
|
|
}
|
2000-01-20 06:08:58 +01:00
|
|
|
|
2001-10-20 00:43:49 +02:00
|
|
|
/************************************************************
|
|
|
|
* create the text of the anonymous subroutine.
|
|
|
|
* we do not use a named subroutine so that we can call directly
|
|
|
|
* through the reference.
|
|
|
|
************************************************************/
|
2004-01-07 00:55:19 +01:00
|
|
|
prosrcdatum = SysCacheGetAttr(PROCOID, procTup,
|
|
|
|
Anum_pg_proc_prosrc, &isnull);
|
|
|
|
if (isnull)
|
|
|
|
elog(ERROR, "null prosrc");
|
2000-07-06 01:12:09 +02:00
|
|
|
proc_source = DatumGetCString(DirectFunctionCall1(textout,
|
2004-01-07 00:55:19 +01:00
|
|
|
prosrcdatum));
|
2000-01-20 06:08:58 +01:00
|
|
|
|
|
|
|
/************************************************************
|
2001-10-20 00:43:49 +02:00
|
|
|
* Create the procedure in the interpreter
|
2000-01-20 06:08:58 +01:00
|
|
|
************************************************************/
|
2001-10-20 00:43:49 +02:00
|
|
|
prodesc->reference = plperl_create_sub(proc_source, prodesc->lanpltrusted);
|
|
|
|
pfree(proc_source);
|
2004-11-29 21:11:06 +01:00
|
|
|
if (!prodesc->reference) /* can this happen? */
|
2000-01-20 06:08:58 +01:00
|
|
|
{
|
|
|
|
free(prodesc->proname);
|
|
|
|
free(prodesc);
|
2003-07-26 01:37:31 +02:00
|
|
|
elog(ERROR, "could not create internal procedure \"%s\"",
|
2001-10-20 00:43:49 +02:00
|
|
|
internal_proname);
|
2000-01-20 06:08:58 +01:00
|
|
|
}
|
|
|
|
|
2001-10-20 00:43:49 +02:00
|
|
|
hv_store(plperl_proc_hash, internal_proname, proname_len,
|
|
|
|
newSViv((IV) prodesc), 0);
|
2000-01-20 06:08:58 +01:00
|
|
|
}
|
|
|
|
|
2001-10-20 00:43:49 +02:00
|
|
|
ReleaseSysCache(procTup);
|
2000-01-20 06:08:58 +01:00
|
|
|
|
2001-10-20 00:43:49 +02:00
|
|
|
return prodesc;
|
|
|
|
}
|
2000-01-20 06:08:58 +01:00
|
|
|
|
|
|
|
|
At 2005-05-21 20:18:50 +0530, ams@oryx.com wrote:
>
> > The second issue is where plperl returns a large result set.
I have attached the following seven patches to address this problem:
1. Trivial. Replaces some errant spaces with tabs.
2. Trivial. Fixes the spelling of Jan's name, and gets rid of many
inane, useless, annoying, and often misleading comments. Here's
a sample: "plperl_init_all() - Initialize all".
(I have tried to add some useful comments here and there, and will
continue to do so now and again.)
3. Trivial. Splits up some long lines.
4. Converts SRFs in PL/Perl to use a Tuplestore and SFRM_Materialize
to return the result set, based on the PL/PgSQL model.
There are two major consequences: result sets will spill to disk when
they can no longer fit in work_mem; and "select foo_srf()" no longer
works. (I didn't lose sleep over the latter, since that form is not
valid in PL/PgSQL, and it's not documented in PL/Perl.)
5. Trivial, but important. Fixes use of "undef" instead of undef. This
would cause empty functions to fail in bizarre ways. I suspect that
there's still another (old) bug here. I'll investigate further.
6. Moves the majority of (4) out into a new plperl_return_next()
function, to make it possible to expose the functionality to
Perl; cleans up some of the code besides.
7. Add an spi_return_next function for use in Perl code.
If you want to apply the patches and try them out, 8-composite.diff is
what you should use. (Note: my patches depend upon Andrew's use-strict
and %_SHARED patches being applied.)
Here's something to try:
create or replace function foo() returns setof record as $$
$i = 0;
for ("World", "PostgreSQL", "PL/Perl") {
spi_return_next({f1=>++$i, f2=>'Hello', f3=>$_});
}
return;
$$ language plperl;
select * from foo() as (f1 integer, f2 text, f3 text);
(Many thanks to Andrews Dunstan and Supernews for their help.)
Abhijit Menon-Sen
2005-06-04 22:33:06 +02:00
|
|
|
/* Build a hash from all attributes of a given tuple. */
|
|
|
|
|
2003-08-04 02:43:34 +02:00
|
|
|
static SV *
|
2004-11-23 01:21:24 +01:00
|
|
|
plperl_hash_from_tuple(HeapTuple tuple, TupleDesc tupdesc)
|
2000-01-20 06:08:58 +01:00
|
|
|
{
|
2004-10-15 19:08:26 +02:00
|
|
|
HV *hv;
|
2004-11-23 01:21:24 +01:00
|
|
|
int i;
|
2000-01-20 06:08:58 +01:00
|
|
|
|
2004-10-15 19:08:26 +02:00
|
|
|
hv = newHV();
|
2000-01-20 06:08:58 +01:00
|
|
|
|
|
|
|
for (i = 0; i < tupdesc->natts; i++)
|
|
|
|
{
|
2004-11-23 01:21:24 +01:00
|
|
|
Datum attr;
|
|
|
|
bool isnull;
|
|
|
|
char *attname;
|
|
|
|
char *outputstr;
|
|
|
|
Oid typoutput;
|
|
|
|
bool typisvarlena;
|
|
|
|
int namelen;
|
2005-06-15 02:35:16 +02:00
|
|
|
SV *sv;
|
2004-11-23 01:21:24 +01:00
|
|
|
|
2003-09-04 17:16:39 +02:00
|
|
|
if (tupdesc->attrs[i]->attisdropped)
|
|
|
|
continue;
|
|
|
|
|
2004-11-23 01:21:24 +01:00
|
|
|
attname = NameStr(tupdesc->attrs[i]->attname);
|
2004-10-15 19:08:26 +02:00
|
|
|
namelen = strlen(attname);
|
2000-01-20 06:08:58 +01:00
|
|
|
attr = heap_getattr(tuple, i + 1, tupdesc, &isnull);
|
|
|
|
|
2004-10-15 19:08:26 +02:00
|
|
|
if (isnull) {
|
|
|
|
/* Store (attname => undef) and move on. */
|
|
|
|
hv_store(hv, attname, namelen, newSV(0), 0);
|
2001-10-20 00:43:49 +02:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2004-11-23 01:21:24 +01:00
|
|
|
/* XXX should have a way to cache these lookups */
|
2000-01-20 06:08:58 +01:00
|
|
|
|
2004-11-23 01:21:24 +01:00
|
|
|
getTypeOutputInfo(tupdesc->attrs[i]->atttypid,
|
2005-05-01 20:56:19 +02:00
|
|
|
&typoutput, &typisvarlena);
|
2000-01-20 06:08:58 +01:00
|
|
|
|
2005-07-03 23:56:16 +02:00
|
|
|
outputstr = DatumGetCString(OidFunctionCall1(typoutput, attr));
|
2004-10-15 19:08:26 +02:00
|
|
|
|
2005-06-15 02:35:16 +02:00
|
|
|
sv = newSVpv(outputstr, 0);
|
|
|
|
#if PERL_BCDVERSION >= 0x5006000L
|
2005-07-03 23:56:16 +02:00
|
|
|
if (GetDatabaseEncoding() == PG_UTF8)
|
|
|
|
SvUTF8_on(sv);
|
2005-06-15 02:35:16 +02:00
|
|
|
#endif
|
|
|
|
hv_store(hv, attname, namelen, sv, 0);
|
2005-07-03 23:56:16 +02:00
|
|
|
|
|
|
|
pfree(outputstr);
|
2000-01-20 06:08:58 +01:00
|
|
|
}
|
2001-10-20 00:43:49 +02:00
|
|
|
|
2004-11-23 01:21:24 +01:00
|
|
|
return newRV_noinc((SV *) hv);
|
2000-01-20 06:08:58 +01:00
|
|
|
}
|
2004-09-13 22:10:13 +02:00
|
|
|
|
|
|
|
|
|
|
|
HV *
|
|
|
|
plperl_spi_exec(char *query, int limit)
|
|
|
|
{
|
|
|
|
HV *ret_hv;
|
|
|
|
|
2004-11-21 22:17:07 +01:00
|
|
|
/*
|
|
|
|
* Execute the query inside a sub-transaction, so we can cope with
|
|
|
|
* errors sanely
|
|
|
|
*/
|
|
|
|
MemoryContext oldcontext = CurrentMemoryContext;
|
|
|
|
ResourceOwner oldowner = CurrentResourceOwner;
|
|
|
|
|
|
|
|
BeginInternalSubTransaction(NULL);
|
|
|
|
/* Want to run inside function's memory context */
|
|
|
|
MemoryContextSwitchTo(oldcontext);
|
|
|
|
|
|
|
|
PG_TRY();
|
|
|
|
{
|
|
|
|
int spi_rv;
|
|
|
|
|
|
|
|
spi_rv = SPI_execute(query, plperl_current_prodesc->fn_readonly,
|
|
|
|
limit);
|
|
|
|
ret_hv = plperl_spi_execute_fetch_result(SPI_tuptable, SPI_processed,
|
|
|
|
spi_rv);
|
|
|
|
|
|
|
|
/* Commit the inner transaction, return to outer xact context */
|
|
|
|
ReleaseCurrentSubTransaction();
|
|
|
|
MemoryContextSwitchTo(oldcontext);
|
|
|
|
CurrentResourceOwner = oldowner;
|
|
|
|
/*
|
|
|
|
* AtEOSubXact_SPI() should not have popped any SPI context,
|
|
|
|
* but just in case it did, make sure we remain connected.
|
|
|
|
*/
|
|
|
|
SPI_restore_connection();
|
|
|
|
}
|
|
|
|
PG_CATCH();
|
|
|
|
{
|
|
|
|
ErrorData *edata;
|
|
|
|
|
|
|
|
/* Save error info */
|
|
|
|
MemoryContextSwitchTo(oldcontext);
|
|
|
|
edata = CopyErrorData();
|
|
|
|
FlushErrorState();
|
|
|
|
|
|
|
|
/* Abort the inner transaction */
|
|
|
|
RollbackAndReleaseCurrentSubTransaction();
|
|
|
|
MemoryContextSwitchTo(oldcontext);
|
|
|
|
CurrentResourceOwner = oldowner;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If AtEOSubXact_SPI() popped any SPI context of the subxact,
|
|
|
|
* it will have left us in a disconnected state. We need this
|
|
|
|
* hack to return to connected state.
|
|
|
|
*/
|
|
|
|
SPI_restore_connection();
|
|
|
|
|
|
|
|
/* Punt the error to Perl */
|
|
|
|
croak("%s", edata->message);
|
|
|
|
|
|
|
|
/* Can't get here, but keep compiler quiet */
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
PG_END_TRY();
|
2004-09-13 22:10:13 +02:00
|
|
|
|
|
|
|
return ret_hv;
|
|
|
|
}
|
|
|
|
|
At 2005-05-21 20:18:50 +0530, ams@oryx.com wrote:
>
> > The second issue is where plperl returns a large result set.
I have attached the following seven patches to address this problem:
1. Trivial. Replaces some errant spaces with tabs.
2. Trivial. Fixes the spelling of Jan's name, and gets rid of many
inane, useless, annoying, and often misleading comments. Here's
a sample: "plperl_init_all() - Initialize all".
(I have tried to add some useful comments here and there, and will
continue to do so now and again.)
3. Trivial. Splits up some long lines.
4. Converts SRFs in PL/Perl to use a Tuplestore and SFRM_Materialize
to return the result set, based on the PL/PgSQL model.
There are two major consequences: result sets will spill to disk when
they can no longer fit in work_mem; and "select foo_srf()" no longer
works. (I didn't lose sleep over the latter, since that form is not
valid in PL/PgSQL, and it's not documented in PL/Perl.)
5. Trivial, but important. Fixes use of "undef" instead of undef. This
would cause empty functions to fail in bizarre ways. I suspect that
there's still another (old) bug here. I'll investigate further.
6. Moves the majority of (4) out into a new plperl_return_next()
function, to make it possible to expose the functionality to
Perl; cleans up some of the code besides.
7. Add an spi_return_next function for use in Perl code.
If you want to apply the patches and try them out, 8-composite.diff is
what you should use. (Note: my patches depend upon Andrew's use-strict
and %_SHARED patches being applied.)
Here's something to try:
create or replace function foo() returns setof record as $$
$i = 0;
for ("World", "PostgreSQL", "PL/Perl") {
spi_return_next({f1=>++$i, f2=>'Hello', f3=>$_});
}
return;
$$ language plperl;
select * from foo() as (f1 integer, f2 text, f3 text);
(Many thanks to Andrews Dunstan and Supernews for their help.)
Abhijit Menon-Sen
2005-06-04 22:33:06 +02:00
|
|
|
|
2004-09-13 22:10:13 +02:00
|
|
|
static HV *
|
2004-11-21 22:17:07 +01:00
|
|
|
plperl_spi_execute_fetch_result(SPITupleTable *tuptable, int processed,
|
|
|
|
int status)
|
2004-09-13 22:10:13 +02:00
|
|
|
{
|
|
|
|
HV *result;
|
|
|
|
|
|
|
|
result = newHV();
|
|
|
|
|
|
|
|
hv_store(result, "status", strlen("status"),
|
|
|
|
newSVpv((char *) SPI_result_code_string(status), 0), 0);
|
|
|
|
hv_store(result, "processed", strlen("processed"),
|
|
|
|
newSViv(processed), 0);
|
|
|
|
|
|
|
|
if (status == SPI_OK_SELECT)
|
|
|
|
{
|
2004-11-21 22:17:07 +01:00
|
|
|
AV *rows;
|
2004-11-23 01:21:24 +01:00
|
|
|
SV *row;
|
2004-11-21 22:17:07 +01:00
|
|
|
int i;
|
2004-09-13 22:10:13 +02:00
|
|
|
|
2004-11-21 22:17:07 +01:00
|
|
|
rows = newAV();
|
|
|
|
for (i = 0; i < processed; i++)
|
|
|
|
{
|
|
|
|
row = plperl_hash_from_tuple(tuptable->vals[i], tuptable->tupdesc);
|
2004-11-23 01:21:24 +01:00
|
|
|
av_push(rows, row);
|
2004-09-13 22:10:13 +02:00
|
|
|
}
|
2004-11-21 22:17:07 +01:00
|
|
|
hv_store(result, "rows", strlen("rows"),
|
|
|
|
newRV_noinc((SV *) rows), 0);
|
2004-09-13 22:10:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
SPI_freetuptable(tuptable);
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
At 2005-05-21 20:18:50 +0530, ams@oryx.com wrote:
>
> > The second issue is where plperl returns a large result set.
I have attached the following seven patches to address this problem:
1. Trivial. Replaces some errant spaces with tabs.
2. Trivial. Fixes the spelling of Jan's name, and gets rid of many
inane, useless, annoying, and often misleading comments. Here's
a sample: "plperl_init_all() - Initialize all".
(I have tried to add some useful comments here and there, and will
continue to do so now and again.)
3. Trivial. Splits up some long lines.
4. Converts SRFs in PL/Perl to use a Tuplestore and SFRM_Materialize
to return the result set, based on the PL/PgSQL model.
There are two major consequences: result sets will spill to disk when
they can no longer fit in work_mem; and "select foo_srf()" no longer
works. (I didn't lose sleep over the latter, since that form is not
valid in PL/PgSQL, and it's not documented in PL/Perl.)
5. Trivial, but important. Fixes use of "undef" instead of undef. This
would cause empty functions to fail in bizarre ways. I suspect that
there's still another (old) bug here. I'll investigate further.
6. Moves the majority of (4) out into a new plperl_return_next()
function, to make it possible to expose the functionality to
Perl; cleans up some of the code besides.
7. Add an spi_return_next function for use in Perl code.
If you want to apply the patches and try them out, 8-composite.diff is
what you should use. (Note: my patches depend upon Andrew's use-strict
and %_SHARED patches being applied.)
Here's something to try:
create or replace function foo() returns setof record as $$
$i = 0;
for ("World", "PostgreSQL", "PL/Perl") {
spi_return_next({f1=>++$i, f2=>'Hello', f3=>$_});
}
return;
$$ language plperl;
select * from foo() as (f1 integer, f2 text, f3 text);
(Many thanks to Andrews Dunstan and Supernews for their help.)
Abhijit Menon-Sen
2005-06-04 22:33:06 +02:00
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
plperl_return_next(SV *sv)
|
|
|
|
{
|
|
|
|
plperl_proc_desc *prodesc = plperl_current_prodesc;
|
2005-07-12 03:16:22 +02:00
|
|
|
FunctionCallInfo fcinfo = plperl_current_caller_info;
|
At 2005-05-21 20:18:50 +0530, ams@oryx.com wrote:
>
> > The second issue is where plperl returns a large result set.
I have attached the following seven patches to address this problem:
1. Trivial. Replaces some errant spaces with tabs.
2. Trivial. Fixes the spelling of Jan's name, and gets rid of many
inane, useless, annoying, and often misleading comments. Here's
a sample: "plperl_init_all() - Initialize all".
(I have tried to add some useful comments here and there, and will
continue to do so now and again.)
3. Trivial. Splits up some long lines.
4. Converts SRFs in PL/Perl to use a Tuplestore and SFRM_Materialize
to return the result set, based on the PL/PgSQL model.
There are two major consequences: result sets will spill to disk when
they can no longer fit in work_mem; and "select foo_srf()" no longer
works. (I didn't lose sleep over the latter, since that form is not
valid in PL/PgSQL, and it's not documented in PL/Perl.)
5. Trivial, but important. Fixes use of "undef" instead of undef. This
would cause empty functions to fail in bizarre ways. I suspect that
there's still another (old) bug here. I'll investigate further.
6. Moves the majority of (4) out into a new plperl_return_next()
function, to make it possible to expose the functionality to
Perl; cleans up some of the code besides.
7. Add an spi_return_next function for use in Perl code.
If you want to apply the patches and try them out, 8-composite.diff is
what you should use. (Note: my patches depend upon Andrew's use-strict
and %_SHARED patches being applied.)
Here's something to try:
create or replace function foo() returns setof record as $$
$i = 0;
for ("World", "PostgreSQL", "PL/Perl") {
spi_return_next({f1=>++$i, f2=>'Hello', f3=>$_});
}
return;
$$ language plperl;
select * from foo() as (f1 integer, f2 text, f3 text);
(Many thanks to Andrews Dunstan and Supernews for their help.)
Abhijit Menon-Sen
2005-06-04 22:33:06 +02:00
|
|
|
ReturnSetInfo *rsi = (ReturnSetInfo *)fcinfo->resultinfo;
|
|
|
|
MemoryContext cxt;
|
|
|
|
HeapTuple tuple;
|
|
|
|
TupleDesc tupdesc;
|
|
|
|
|
|
|
|
if (!sv)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (!prodesc->fn_retisset)
|
|
|
|
{
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_SYNTAX_ERROR),
|
|
|
|
errmsg("cannot use return_next in a non-SETOF function")));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (prodesc->fn_retistuple &&
|
|
|
|
!(SvOK(sv) && SvTYPE(sv) == SVt_RV && SvTYPE(SvRV(sv)) == SVt_PVHV))
|
|
|
|
{
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DATATYPE_MISMATCH),
|
|
|
|
errmsg("setof-composite-returning Perl function "
|
|
|
|
"must call return_next with reference to hash")));
|
|
|
|
}
|
|
|
|
|
|
|
|
cxt = MemoryContextSwitchTo(rsi->econtext->ecxt_per_query_memory);
|
|
|
|
|
2005-07-12 03:16:22 +02:00
|
|
|
if (!plperl_current_tuple_store)
|
|
|
|
plperl_current_tuple_store =
|
|
|
|
tuplestore_begin_heap(true, false, work_mem);
|
At 2005-05-21 20:18:50 +0530, ams@oryx.com wrote:
>
> > The second issue is where plperl returns a large result set.
I have attached the following seven patches to address this problem:
1. Trivial. Replaces some errant spaces with tabs.
2. Trivial. Fixes the spelling of Jan's name, and gets rid of many
inane, useless, annoying, and often misleading comments. Here's
a sample: "plperl_init_all() - Initialize all".
(I have tried to add some useful comments here and there, and will
continue to do so now and again.)
3. Trivial. Splits up some long lines.
4. Converts SRFs in PL/Perl to use a Tuplestore and SFRM_Materialize
to return the result set, based on the PL/PgSQL model.
There are two major consequences: result sets will spill to disk when
they can no longer fit in work_mem; and "select foo_srf()" no longer
works. (I didn't lose sleep over the latter, since that form is not
valid in PL/PgSQL, and it's not documented in PL/Perl.)
5. Trivial, but important. Fixes use of "undef" instead of undef. This
would cause empty functions to fail in bizarre ways. I suspect that
there's still another (old) bug here. I'll investigate further.
6. Moves the majority of (4) out into a new plperl_return_next()
function, to make it possible to expose the functionality to
Perl; cleans up some of the code besides.
7. Add an spi_return_next function for use in Perl code.
If you want to apply the patches and try them out, 8-composite.diff is
what you should use. (Note: my patches depend upon Andrew's use-strict
and %_SHARED patches being applied.)
Here's something to try:
create or replace function foo() returns setof record as $$
$i = 0;
for ("World", "PostgreSQL", "PL/Perl") {
spi_return_next({f1=>++$i, f2=>'Hello', f3=>$_});
}
return;
$$ language plperl;
select * from foo() as (f1 integer, f2 text, f3 text);
(Many thanks to Andrews Dunstan and Supernews for their help.)
Abhijit Menon-Sen
2005-06-04 22:33:06 +02:00
|
|
|
|
|
|
|
if (prodesc->fn_retistuple)
|
|
|
|
{
|
|
|
|
TypeFuncClass rettype;
|
|
|
|
AttInMetadata *attinmeta;
|
|
|
|
|
|
|
|
rettype = get_call_result_type(fcinfo, NULL, &tupdesc);
|
|
|
|
tupdesc = CreateTupleDescCopy(tupdesc);
|
|
|
|
attinmeta = TupleDescGetAttInMetadata(tupdesc);
|
|
|
|
tuple = plperl_build_tuple_result((HV *)SvRV(sv), attinmeta);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Datum ret;
|
|
|
|
bool isNull;
|
|
|
|
|
|
|
|
tupdesc = CreateTupleDescCopy(rsi->expectedDesc);
|
|
|
|
|
|
|
|
if (SvOK(sv) && SvTYPE(sv) != SVt_NULL)
|
|
|
|
{
|
|
|
|
char *val = SvPV(sv, PL_na);
|
|
|
|
ret = FunctionCall3(&prodesc->result_in_func,
|
|
|
|
PointerGetDatum(val),
|
|
|
|
ObjectIdGetDatum(prodesc->result_typioparam),
|
|
|
|
Int32GetDatum(-1));
|
|
|
|
isNull = false;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
ret = (Datum)0;
|
|
|
|
isNull = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
tuple = heap_form_tuple(tupdesc, &ret, &isNull);
|
|
|
|
}
|
|
|
|
|
2005-07-12 03:16:22 +02:00
|
|
|
if (!plperl_current_tuple_desc)
|
|
|
|
plperl_current_tuple_desc = tupdesc;
|
At 2005-05-21 20:18:50 +0530, ams@oryx.com wrote:
>
> > The second issue is where plperl returns a large result set.
I have attached the following seven patches to address this problem:
1. Trivial. Replaces some errant spaces with tabs.
2. Trivial. Fixes the spelling of Jan's name, and gets rid of many
inane, useless, annoying, and often misleading comments. Here's
a sample: "plperl_init_all() - Initialize all".
(I have tried to add some useful comments here and there, and will
continue to do so now and again.)
3. Trivial. Splits up some long lines.
4. Converts SRFs in PL/Perl to use a Tuplestore and SFRM_Materialize
to return the result set, based on the PL/PgSQL model.
There are two major consequences: result sets will spill to disk when
they can no longer fit in work_mem; and "select foo_srf()" no longer
works. (I didn't lose sleep over the latter, since that form is not
valid in PL/PgSQL, and it's not documented in PL/Perl.)
5. Trivial, but important. Fixes use of "undef" instead of undef. This
would cause empty functions to fail in bizarre ways. I suspect that
there's still another (old) bug here. I'll investigate further.
6. Moves the majority of (4) out into a new plperl_return_next()
function, to make it possible to expose the functionality to
Perl; cleans up some of the code besides.
7. Add an spi_return_next function for use in Perl code.
If you want to apply the patches and try them out, 8-composite.diff is
what you should use. (Note: my patches depend upon Andrew's use-strict
and %_SHARED patches being applied.)
Here's something to try:
create or replace function foo() returns setof record as $$
$i = 0;
for ("World", "PostgreSQL", "PL/Perl") {
spi_return_next({f1=>++$i, f2=>'Hello', f3=>$_});
}
return;
$$ language plperl;
select * from foo() as (f1 integer, f2 text, f3 text);
(Many thanks to Andrews Dunstan and Supernews for their help.)
Abhijit Menon-Sen
2005-06-04 22:33:06 +02:00
|
|
|
|
2005-07-12 03:16:22 +02:00
|
|
|
tuplestore_puttuple(plperl_current_tuple_store, tuple);
|
At 2005-05-21 20:18:50 +0530, ams@oryx.com wrote:
>
> > The second issue is where plperl returns a large result set.
I have attached the following seven patches to address this problem:
1. Trivial. Replaces some errant spaces with tabs.
2. Trivial. Fixes the spelling of Jan's name, and gets rid of many
inane, useless, annoying, and often misleading comments. Here's
a sample: "plperl_init_all() - Initialize all".
(I have tried to add some useful comments here and there, and will
continue to do so now and again.)
3. Trivial. Splits up some long lines.
4. Converts SRFs in PL/Perl to use a Tuplestore and SFRM_Materialize
to return the result set, based on the PL/PgSQL model.
There are two major consequences: result sets will spill to disk when
they can no longer fit in work_mem; and "select foo_srf()" no longer
works. (I didn't lose sleep over the latter, since that form is not
valid in PL/PgSQL, and it's not documented in PL/Perl.)
5. Trivial, but important. Fixes use of "undef" instead of undef. This
would cause empty functions to fail in bizarre ways. I suspect that
there's still another (old) bug here. I'll investigate further.
6. Moves the majority of (4) out into a new plperl_return_next()
function, to make it possible to expose the functionality to
Perl; cleans up some of the code besides.
7. Add an spi_return_next function for use in Perl code.
If you want to apply the patches and try them out, 8-composite.diff is
what you should use. (Note: my patches depend upon Andrew's use-strict
and %_SHARED patches being applied.)
Here's something to try:
create or replace function foo() returns setof record as $$
$i = 0;
for ("World", "PostgreSQL", "PL/Perl") {
spi_return_next({f1=>++$i, f2=>'Hello', f3=>$_});
}
return;
$$ language plperl;
select * from foo() as (f1 integer, f2 text, f3 text);
(Many thanks to Andrews Dunstan and Supernews for their help.)
Abhijit Menon-Sen
2005-06-04 22:33:06 +02:00
|
|
|
heap_freetuple(tuple);
|
|
|
|
MemoryContextSwitchTo(cxt);
|
|
|
|
}
|
2005-07-10 17:19:43 +02:00
|
|
|
|
|
|
|
|
|
|
|
SV *
|
|
|
|
plperl_spi_query(char *query)
|
|
|
|
{
|
|
|
|
SV *cursor;
|
|
|
|
|
|
|
|
MemoryContext oldcontext = CurrentMemoryContext;
|
|
|
|
ResourceOwner oldowner = CurrentResourceOwner;
|
|
|
|
|
|
|
|
BeginInternalSubTransaction(NULL);
|
|
|
|
MemoryContextSwitchTo(oldcontext);
|
|
|
|
|
|
|
|
PG_TRY();
|
|
|
|
{
|
|
|
|
void *plan;
|
|
|
|
Portal portal = NULL;
|
|
|
|
|
|
|
|
plan = SPI_prepare(query, 0, NULL);
|
|
|
|
if (plan)
|
|
|
|
portal = SPI_cursor_open(NULL, plan, NULL, NULL, false);
|
|
|
|
if (portal)
|
|
|
|
cursor = newSVpv(portal->name, 0);
|
|
|
|
else
|
|
|
|
cursor = newSV(0);
|
|
|
|
|
|
|
|
ReleaseCurrentSubTransaction();
|
|
|
|
MemoryContextSwitchTo(oldcontext);
|
|
|
|
CurrentResourceOwner = oldowner;
|
|
|
|
SPI_restore_connection();
|
|
|
|
}
|
|
|
|
PG_CATCH();
|
|
|
|
{
|
|
|
|
ErrorData *edata;
|
|
|
|
|
|
|
|
MemoryContextSwitchTo(oldcontext);
|
|
|
|
edata = CopyErrorData();
|
|
|
|
FlushErrorState();
|
|
|
|
|
|
|
|
RollbackAndReleaseCurrentSubTransaction();
|
|
|
|
MemoryContextSwitchTo(oldcontext);
|
|
|
|
CurrentResourceOwner = oldowner;
|
|
|
|
|
|
|
|
SPI_restore_connection();
|
|
|
|
croak("%s", edata->message);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
PG_END_TRY();
|
|
|
|
|
|
|
|
return cursor;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
SV *
|
|
|
|
plperl_spi_fetchrow(char *cursor)
|
|
|
|
{
|
|
|
|
SV *row = newSV(0);
|
|
|
|
Portal p = SPI_cursor_find(cursor);
|
|
|
|
|
|
|
|
if (!p)
|
|
|
|
return row;
|
|
|
|
|
|
|
|
SPI_cursor_fetch(p, true, 1);
|
|
|
|
if (SPI_processed == 0) {
|
|
|
|
SPI_cursor_close(p);
|
|
|
|
return row;
|
|
|
|
}
|
|
|
|
|
|
|
|
row = plperl_hash_from_tuple(SPI_tuptable->vals[0],
|
|
|
|
SPI_tuptable->tupdesc);
|
|
|
|
SPI_freetuptable(SPI_tuptable);
|
|
|
|
|
|
|
|
return row;
|
|
|
|
}
|