2010-01-20 02:08:21 +01:00
|
|
|
/**********************************************************************
|
|
|
|
* PostgreSQL::InServer::Util
|
|
|
|
*
|
2010-09-20 22:08:53 +02:00
|
|
|
* src/pl/plperl/Util.xs
|
2010-01-20 02:08:21 +01:00
|
|
|
*
|
|
|
|
* Defines plperl interfaces for general-purpose utilities.
|
|
|
|
* This module is bootstrapped as soon as an interpreter is initialized.
|
|
|
|
* Currently doesn't define a PACKAGE= so all subs are in main:: to avoid
|
|
|
|
* the need for explicit importing.
|
|
|
|
*
|
|
|
|
**********************************************************************/
|
|
|
|
|
|
|
|
/* this must be first: */
|
|
|
|
#include "postgres.h"
|
|
|
|
#include "fmgr.h"
|
|
|
|
#include "utils/builtins.h"
|
|
|
|
#include "utils/bytea.h" /* for byteain & byteaout */
|
|
|
|
#include "mb/pg_wchar.h" /* for GetDatabaseEncoding */
|
|
|
|
/* Defined by Perl */
|
|
|
|
#undef _
|
|
|
|
|
|
|
|
/* perl stuff */
|
|
|
|
#include "plperl.h"
|
2011-02-06 23:29:26 +01:00
|
|
|
#include "plperl_helpers.h"
|
2010-01-20 02:08:21 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Implementation of plperl's elog() function
|
|
|
|
*
|
|
|
|
* If the error level is less than ERROR, we'll just emit the message and
|
|
|
|
* return. When it is ERROR, elog() will longjmp, which we catch and
|
|
|
|
* turn into a Perl croak(). Note we are assuming that elog() can't have
|
|
|
|
* any internal failures that are so bad as to require a transaction abort.
|
|
|
|
*
|
|
|
|
* This is out-of-line to suppress "might be clobbered by longjmp" warnings.
|
|
|
|
*/
|
|
|
|
static void
|
2011-02-06 23:29:26 +01:00
|
|
|
do_util_elog(int level, SV *msg)
|
2010-01-20 02:08:21 +01:00
|
|
|
{
|
2011-03-07 03:15:48 +01:00
|
|
|
MemoryContext oldcontext = CurrentMemoryContext;
|
|
|
|
char * volatile cmsg = NULL;
|
2010-01-20 02:08:21 +01:00
|
|
|
|
2011-03-07 03:15:48 +01:00
|
|
|
PG_TRY();
|
|
|
|
{
|
2011-02-06 23:29:26 +01:00
|
|
|
cmsg = sv2cstr(msg);
|
2011-03-07 03:15:48 +01:00
|
|
|
elog(level, "%s", cmsg);
|
2011-02-06 23:29:26 +01:00
|
|
|
pfree(cmsg);
|
2011-03-07 03:15:48 +01:00
|
|
|
}
|
|
|
|
PG_CATCH();
|
|
|
|
{
|
|
|
|
ErrorData *edata;
|
2010-01-20 02:08:21 +01:00
|
|
|
|
2011-03-07 03:15:48 +01:00
|
|
|
/* Must reset elog.c's state */
|
|
|
|
MemoryContextSwitchTo(oldcontext);
|
|
|
|
edata = CopyErrorData();
|
|
|
|
FlushErrorState();
|
2010-01-20 02:08:21 +01:00
|
|
|
|
2011-02-06 23:29:26 +01:00
|
|
|
if (cmsg)
|
|
|
|
pfree(cmsg);
|
|
|
|
|
2011-03-07 03:15:48 +01:00
|
|
|
/* Punt the error to Perl */
|
2015-09-29 16:52:22 +02:00
|
|
|
croak_cstr(edata->message);
|
2011-03-07 03:15:48 +01:00
|
|
|
}
|
|
|
|
PG_END_TRY();
|
2010-01-20 02:08:21 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static text *
|
|
|
|
sv2text(SV *sv)
|
|
|
|
{
|
2011-03-07 03:15:48 +01:00
|
|
|
char *str = sv2cstr(sv);
|
2012-07-09 23:36:29 +02:00
|
|
|
text *text;
|
2011-03-07 03:15:48 +01:00
|
|
|
|
2012-07-09 23:36:29 +02:00
|
|
|
text = cstring_to_text(str);
|
|
|
|
pfree(str);
|
|
|
|
return text;
|
2010-01-20 02:08:21 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
MODULE = PostgreSQL::InServer::Util PREFIX = util_
|
|
|
|
|
|
|
|
PROTOTYPES: ENABLE
|
|
|
|
VERSIONCHECK: DISABLE
|
|
|
|
|
|
|
|
int
|
|
|
|
_aliased_constants()
|
|
|
|
PROTOTYPE:
|
|
|
|
ALIAS:
|
|
|
|
DEBUG = DEBUG2
|
|
|
|
LOG = LOG
|
|
|
|
INFO = INFO
|
|
|
|
NOTICE = NOTICE
|
|
|
|
WARNING = WARNING
|
|
|
|
ERROR = ERROR
|
|
|
|
CODE:
|
|
|
|
/* uses the ALIAS value as the return value */
|
|
|
|
RETVAL = ix;
|
|
|
|
OUTPUT:
|
|
|
|
RETVAL
|
|
|
|
|
|
|
|
|
|
|
|
void
|
2011-02-06 23:29:26 +01:00
|
|
|
util_elog(level, msg)
|
2010-01-20 02:08:21 +01:00
|
|
|
int level
|
2011-02-06 23:29:26 +01:00
|
|
|
SV *msg
|
2010-01-20 02:08:21 +01:00
|
|
|
CODE:
|
|
|
|
if (level > ERROR) /* no PANIC allowed thanks */
|
|
|
|
level = ERROR;
|
|
|
|
if (level < DEBUG5)
|
|
|
|
level = DEBUG5;
|
2011-02-06 23:29:26 +01:00
|
|
|
do_util_elog(level, msg);
|
2010-01-20 02:08:21 +01:00
|
|
|
|
|
|
|
SV *
|
|
|
|
util_quote_literal(sv)
|
|
|
|
SV *sv
|
|
|
|
CODE:
|
|
|
|
if (!sv || !SvOK(sv)) {
|
|
|
|
RETVAL = &PL_sv_undef;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
text *arg = sv2text(sv);
|
2012-07-09 23:36:29 +02:00
|
|
|
text *quoted = DatumGetTextP(DirectFunctionCall1(quote_literal, PointerGetDatum(arg)));
|
|
|
|
char *str;
|
|
|
|
|
|
|
|
pfree(arg);
|
|
|
|
str = text_to_cstring(quoted);
|
2011-02-06 23:29:26 +01:00
|
|
|
RETVAL = cstr2sv(str);
|
|
|
|
pfree(str);
|
2010-01-20 02:08:21 +01:00
|
|
|
}
|
|
|
|
OUTPUT:
|
|
|
|
RETVAL
|
|
|
|
|
|
|
|
SV *
|
|
|
|
util_quote_nullable(sv)
|
|
|
|
SV *sv
|
|
|
|
CODE:
|
2010-11-23 21:27:50 +01:00
|
|
|
if (!sv || !SvOK(sv))
|
2010-01-20 02:08:21 +01:00
|
|
|
{
|
2011-02-06 23:29:26 +01:00
|
|
|
RETVAL = cstr2sv("NULL");
|
2010-01-20 02:08:21 +01:00
|
|
|
}
|
2010-11-23 21:27:50 +01:00
|
|
|
else
|
2010-01-20 02:08:21 +01:00
|
|
|
{
|
|
|
|
text *arg = sv2text(sv);
|
2012-07-09 23:36:29 +02:00
|
|
|
text *quoted = DatumGetTextP(DirectFunctionCall1(quote_nullable, PointerGetDatum(arg)));
|
|
|
|
char *str;
|
|
|
|
|
|
|
|
pfree(arg);
|
|
|
|
str = text_to_cstring(quoted);
|
2011-02-06 23:29:26 +01:00
|
|
|
RETVAL = cstr2sv(str);
|
|
|
|
pfree(str);
|
2010-01-20 02:08:21 +01:00
|
|
|
}
|
|
|
|
OUTPUT:
|
|
|
|
RETVAL
|
|
|
|
|
|
|
|
SV *
|
|
|
|
util_quote_ident(sv)
|
|
|
|
SV *sv
|
|
|
|
PREINIT:
|
|
|
|
text *arg;
|
2012-07-09 23:36:29 +02:00
|
|
|
text *quoted;
|
2011-02-06 23:29:26 +01:00
|
|
|
char *str;
|
2010-01-20 02:08:21 +01:00
|
|
|
CODE:
|
|
|
|
arg = sv2text(sv);
|
2012-07-09 23:36:29 +02:00
|
|
|
quoted = DatumGetTextP(DirectFunctionCall1(quote_ident, PointerGetDatum(arg)));
|
|
|
|
|
|
|
|
pfree(arg);
|
|
|
|
str = text_to_cstring(quoted);
|
2011-02-06 23:29:26 +01:00
|
|
|
RETVAL = cstr2sv(str);
|
|
|
|
pfree(str);
|
2010-01-20 02:08:21 +01:00
|
|
|
OUTPUT:
|
|
|
|
RETVAL
|
|
|
|
|
|
|
|
SV *
|
|
|
|
util_decode_bytea(sv)
|
|
|
|
SV *sv
|
|
|
|
PREINIT:
|
|
|
|
char *arg;
|
|
|
|
text *ret;
|
|
|
|
CODE:
|
2011-02-06 23:29:26 +01:00
|
|
|
arg = SvPVbyte_nolen(sv);
|
2010-01-20 02:08:21 +01:00
|
|
|
ret = DatumGetTextP(DirectFunctionCall1(byteain, PointerGetDatum(arg)));
|
2011-02-06 23:29:26 +01:00
|
|
|
/* not cstr2sv because this is raw bytes not utf8'able */
|
2010-01-20 02:08:21 +01:00
|
|
|
RETVAL = newSVpvn(VARDATA(ret), (VARSIZE(ret) - VARHDRSZ));
|
|
|
|
OUTPUT:
|
|
|
|
RETVAL
|
|
|
|
|
|
|
|
SV *
|
|
|
|
util_encode_bytea(sv)
|
|
|
|
SV *sv
|
|
|
|
PREINIT:
|
|
|
|
text *arg;
|
|
|
|
char *ret;
|
2011-02-06 23:29:26 +01:00
|
|
|
STRLEN len;
|
2010-01-20 02:08:21 +01:00
|
|
|
CODE:
|
2011-02-06 23:29:26 +01:00
|
|
|
/* not sv2text because this is raw bytes not utf8'able */
|
|
|
|
ret = SvPVbyte(sv, len);
|
|
|
|
arg = cstring_to_text_with_len(ret, len);
|
2010-01-20 02:08:21 +01:00
|
|
|
ret = DatumGetCString(DirectFunctionCall1(byteaout, PointerGetDatum(arg)));
|
2011-02-06 23:29:26 +01:00
|
|
|
RETVAL = cstr2sv(ret);
|
2010-01-20 02:08:21 +01:00
|
|
|
OUTPUT:
|
|
|
|
RETVAL
|
|
|
|
|
|
|
|
SV *
|
|
|
|
looks_like_number(sv)
|
|
|
|
SV *sv
|
|
|
|
CODE:
|
|
|
|
if (!SvOK(sv))
|
|
|
|
RETVAL = &PL_sv_undef;
|
|
|
|
else if ( looks_like_number(sv) )
|
|
|
|
RETVAL = &PL_sv_yes;
|
|
|
|
else
|
|
|
|
RETVAL = &PL_sv_no;
|
|
|
|
OUTPUT:
|
|
|
|
RETVAL
|
|
|
|
|
2011-02-18 02:11:50 +01:00
|
|
|
SV *
|
|
|
|
encode_typed_literal(sv, typname)
|
|
|
|
SV *sv
|
|
|
|
char *typname;
|
|
|
|
PREINIT:
|
|
|
|
char *outstr;
|
|
|
|
CODE:
|
|
|
|
outstr = plperl_sv_to_literal(sv, typname);
|
|
|
|
if (outstr == NULL)
|
|
|
|
RETVAL = &PL_sv_undef;
|
|
|
|
else
|
|
|
|
RETVAL = cstr2sv(outstr);
|
|
|
|
OUTPUT:
|
|
|
|
RETVAL
|
2010-01-20 02:08:21 +01:00
|
|
|
|
|
|
|
BOOT:
|
|
|
|
items = 0; /* avoid 'unused variable' warning */
|