mirror of
https://github.com/postgres/postgres.git
synced 2025-09-11 00:12:06 +03:00
We were passing error message texts to croak() verbatim, which turns out
not to work if the text contains non-ASCII characters; Perl mangles their
encoding, as reported in bug #13638 from Michal Leinweber. To fix, convert
the text into a UTF8-encoded SV first.
It's hard to test this without risking failures in different database
encodings; but we can follow the lead of plpython, which is already
assuming that no-break space (U+00A0) has an equivalent in all encodings
we care about running the regression tests in (cf commit 2dfa15de5
).
Back-patch to 9.1. The code is quite different in 9.0, and anyway it seems
too risky to put something like this into 9.0's final minor release.
Alex Hunsaker, with suggestions from Tim Bunce and Tom Lane
186 lines
3.5 KiB
Plaintext
186 lines
3.5 KiB
Plaintext
/**********************************************************************
|
|
* PostgreSQL::InServer::SPI
|
|
*
|
|
* SPI interface for plperl.
|
|
*
|
|
* src/pl/plperl/SPI.xs
|
|
*
|
|
**********************************************************************/
|
|
|
|
/* this must be first: */
|
|
#include "postgres.h"
|
|
#include "mb/pg_wchar.h" /* for GetDatabaseEncoding */
|
|
|
|
/* Defined by Perl */
|
|
#undef _
|
|
|
|
/* perl stuff */
|
|
#include "plperl.h"
|
|
#include "plperl_helpers.h"
|
|
|
|
|
|
/*
|
|
* Interface routine to catch ereports and punt them to Perl
|
|
*/
|
|
static void
|
|
do_plperl_return_next(SV *sv)
|
|
{
|
|
MemoryContext oldcontext = CurrentMemoryContext;
|
|
|
|
PG_TRY();
|
|
{
|
|
plperl_return_next(sv);
|
|
}
|
|
PG_CATCH();
|
|
{
|
|
ErrorData *edata;
|
|
|
|
/* Must reset elog.c's state */
|
|
MemoryContextSwitchTo(oldcontext);
|
|
edata = CopyErrorData();
|
|
FlushErrorState();
|
|
|
|
/* Punt the error to Perl */
|
|
croak_cstr(edata->message);
|
|
}
|
|
PG_END_TRY();
|
|
}
|
|
|
|
|
|
MODULE = PostgreSQL::InServer::SPI PREFIX = spi_
|
|
|
|
PROTOTYPES: ENABLE
|
|
VERSIONCHECK: DISABLE
|
|
|
|
SV*
|
|
spi_spi_exec_query(sv, ...)
|
|
SV* sv;
|
|
PREINIT:
|
|
HV *ret_hash;
|
|
int limit = 0;
|
|
char *query;
|
|
CODE:
|
|
if (items > 2)
|
|
croak("Usage: spi_exec_query(query, limit) "
|
|
"or spi_exec_query(query)");
|
|
if (items == 2)
|
|
limit = SvIV(ST(1));
|
|
query = sv2cstr(sv);
|
|
ret_hash = plperl_spi_exec(query, limit);
|
|
pfree(query);
|
|
RETVAL = newRV_noinc((SV*) ret_hash);
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
void
|
|
spi_return_next(rv)
|
|
SV *rv;
|
|
CODE:
|
|
do_plperl_return_next(rv);
|
|
|
|
SV *
|
|
spi_spi_query(sv)
|
|
SV *sv;
|
|
CODE:
|
|
char* query = sv2cstr(sv);
|
|
RETVAL = plperl_spi_query(query);
|
|
pfree(query);
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
SV *
|
|
spi_spi_fetchrow(sv)
|
|
SV* sv;
|
|
CODE:
|
|
char* cursor = sv2cstr(sv);
|
|
RETVAL = plperl_spi_fetchrow(cursor);
|
|
pfree(cursor);
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
SV*
|
|
spi_spi_prepare(sv, ...)
|
|
SV* sv;
|
|
CODE:
|
|
int i;
|
|
SV** argv;
|
|
char* query = sv2cstr(sv);
|
|
if (items < 1)
|
|
Perl_croak(aTHX_ "Usage: spi_prepare(query, ...)");
|
|
argv = ( SV**) palloc(( items - 1) * sizeof(SV*));
|
|
for ( i = 1; i < items; i++)
|
|
argv[i - 1] = ST(i);
|
|
RETVAL = plperl_spi_prepare(query, items - 1, argv);
|
|
pfree( argv);
|
|
pfree(query);
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
SV*
|
|
spi_spi_exec_prepared(sv, ...)
|
|
SV* sv;
|
|
PREINIT:
|
|
HV *ret_hash;
|
|
CODE:
|
|
HV *attr = NULL;
|
|
int i, offset = 1, argc;
|
|
SV ** argv;
|
|
char *query = sv2cstr(sv);
|
|
if ( items < 1)
|
|
Perl_croak(aTHX_ "Usage: spi_exec_prepared(query, [\\%%attr,] "
|
|
"[\\@bind_values])");
|
|
if ( items > 1 && SvROK( ST( 1)) && SvTYPE( SvRV( ST( 1))) == SVt_PVHV)
|
|
{
|
|
attr = ( HV*) SvRV(ST(1));
|
|
offset++;
|
|
}
|
|
argc = items - offset;
|
|
argv = ( SV**) palloc( argc * sizeof(SV*));
|
|
for ( i = 0; offset < items; offset++, i++)
|
|
argv[i] = ST(offset);
|
|
ret_hash = plperl_spi_exec_prepared(query, attr, argc, argv);
|
|
RETVAL = newRV_noinc((SV*)ret_hash);
|
|
pfree( argv);
|
|
pfree(query);
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
SV*
|
|
spi_spi_query_prepared(sv, ...)
|
|
SV * sv;
|
|
CODE:
|
|
int i;
|
|
SV ** argv;
|
|
char *query = sv2cstr(sv);
|
|
if ( items < 1)
|
|
Perl_croak(aTHX_ "Usage: spi_query_prepared(query, "
|
|
"[\\@bind_values])");
|
|
argv = ( SV**) palloc(( items - 1) * sizeof(SV*));
|
|
for ( i = 1; i < items; i++)
|
|
argv[i - 1] = ST(i);
|
|
RETVAL = plperl_spi_query_prepared(query, items - 1, argv);
|
|
pfree( argv);
|
|
pfree(query);
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
void
|
|
spi_spi_freeplan(sv)
|
|
SV *sv;
|
|
CODE:
|
|
char *query = sv2cstr(sv);
|
|
plperl_spi_freeplan(query);
|
|
pfree(query);
|
|
|
|
void
|
|
spi_spi_cursor_close(sv)
|
|
SV *sv;
|
|
CODE:
|
|
char *cursor = sv2cstr(sv);
|
|
plperl_spi_cursor_close(cursor);
|
|
pfree(cursor);
|
|
|
|
|
|
BOOT:
|
|
items = 0; /* avoid 'unused variable' warning */
|