1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
|
/* this must be first: */
#include "postgres.h"
/* Defined by Perl */
#undef _
/* perl stuff */
/* stop perl from hijacking stdio and other stuff */
#ifdef WIN32
#define WIN32IO_IS_STDIO
#endif
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
#include "ppport.h"
#include "spi_internal.h"
/*
* 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
do_spi_elog(int level, char *message)
{
MemoryContext oldcontext = CurrentMemoryContext;
PG_TRY();
{
elog(level, "%s", message);
}
PG_CATCH();
{
ErrorData *edata;
/* Must reset elog.c's state */
MemoryContextSwitchTo(oldcontext);
edata = CopyErrorData();
FlushErrorState();
/* Punt the error to Perl */
croak("%s", edata->message);
}
PG_END_TRY();
}
/*
* 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("%s", edata->message);
}
PG_END_TRY();
}
MODULE = SPI PREFIX = spi_
PROTOTYPES: ENABLE
VERSIONCHECK: DISABLE
void
spi_elog(level, message)
int level
char* message
CODE:
if (level > ERROR) /* no PANIC allowed thanks */
level = ERROR;
if (level < DEBUG5)
level = DEBUG5;
do_spi_elog(level, message);
int
spi_DEBUG()
int
spi_LOG()
int
spi_INFO()
int
spi_NOTICE()
int
spi_WARNING()
int
spi_ERROR()
SV*
spi_spi_exec_query(query, ...)
char* query;
PREINIT:
HV *ret_hash;
int limit = 0;
CODE:
if (items > 2)
croak("Usage: spi_exec_query(query, limit) or spi_exec_query(query)");
if (items == 2)
limit = SvIV(ST(1));
ret_hash = plperl_spi_exec(query, limit);
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(query)
char *query;
CODE:
RETVAL = plperl_spi_query(query);
OUTPUT:
RETVAL
SV *
spi_spi_fetchrow(cursor)
char *cursor;
CODE:
RETVAL = plperl_spi_fetchrow(cursor);
OUTPUT:
RETVAL
BOOT:
items = 0; /* avoid 'unused variable' warning */
|