Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit5d723d0

Browse files
committed
Prepared queries for PLPerl, plus fixing a small plperl memory leak. Patchand docs from Dmitry Karasik, slightly editorialised.
1 parentf2f5b05 commit5d723d0

File tree

6 files changed

+724
-20
lines changed

6 files changed

+724
-20
lines changed

‎doc/src/sgml/plperl.sgml

Lines changed: 68 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<!--
2-
$PostgreSQL: pgsql/doc/src/sgml/plperl.sgml,v 2.50 2006/03/01 06:30:32 neilc Exp $
2+
$PostgreSQL: pgsql/doc/src/sgml/plperl.sgml,v 2.51 2006/03/05 16:40:51 adunstan Exp $
33
-->
44

55
<chapter id="plperl">
@@ -296,7 +296,7 @@ BEGIN { strict->import(); }
296296
</para>
297297

298298
<para>
299-
PL/Perl providesthreeadditional Perl commands:
299+
PL/Perl provides additional Perl commands:
300300

301301
<variablelist>
302302
<varlistentry>
@@ -306,9 +306,13 @@ BEGIN { strict->import(); }
306306
</indexterm>
307307

308308
<term><literal><function>spi_exec_query</>(<replaceable>query</replaceable> [, <replaceable>max-rows</replaceable>])</literal></term>
309-
<term><literal><function>spi_exec_query</>(<replaceable>command</replaceable>)</literal></term>
310309
<term><literal><function>spi_query</>(<replaceable>command</replaceable>)</literal></term>
311-
<term><literal><function>spi_fetchrow</>(<replaceable>command</replaceable>)</literal></term>
310+
<term><literal><function>spi_fetchrow</>(<replaceable>cursor</replaceable>)</literal></term>
311+
<term><literal><function>spi_prepare</>(<replaceable>command</replaceable>, <replaceable>argument types</replaceable>)</literal></term>
312+
<term><literal><function>spi_exec_prepared</>(<replaceable>plan</replaceable>)</literal></term>
313+
<term><literal><function>spi_query_prepared</>(<replaceable>plan</replaceable> [, <replaceable>attributes</replaceable>], <replaceable>arguments</replaceable>)</literal></term>
314+
<term><literal><function>spi_cursor_close</>(<replaceable>cursor</replaceable>)</literal></term>
315+
<term><literal><function>spi_freeplan</>(<replaceable>plan</replaceable>)</literal></term>
312316

313317
<listitem>
314318
<para>
@@ -419,6 +423,66 @@ $$ LANGUAGE plperlu;
419423
SELECT * from lotsa_md5(500);
420424
</programlisting>
421425
</para>
426+
427+
<para>
428+
<literal>spi_prepare</literal>, <literal>spi_query_prepared</literal>, <literal>spi_exec_prepared</literal>,
429+
and <literal>spi_freeplan</literal> implement the same functionality but for prepared queries. Once
430+
a query plan is prepared by a call to <literal>spi_prepare</literal>, the plan can be used instead
431+
of the string query, either in <literal>spi_exec_prepared</literal>, where the result is the same as returned
432+
by <literal>spi_exec_query</literal>, or in <literal>spi_query_prepared</literal> which returns a cursor
433+
exactly as <literal>spi_query</literal> does, which can be later passed to <literal>spi_fetchrow</literal>.
434+
</para>
435+
436+
<para>
437+
The advantage of prepared queries is that is it possible to use one prepared plan for more
438+
than one query execution. After the plan is not needed anymore, it must be freed with
439+
<literal>spi_freeplan</literal>:
440+
</para>
441+
442+
<para>
443+
<programlisting>
444+
CREATE OR REPLACE FUNCTION init() RETURNS INTEGER AS $$
445+
$_SHARED{my_plan} = spi_prepare( 'SELECT (now() + $1)::date AS now', 'INTERVAL');
446+
$$ LANGUAGE plperl;
447+
448+
CREATE OR REPLACE FUNCTION add_time( INTERVAL ) RETURNS TEXT AS $$
449+
return spi_exec_prepared(
450+
$_SHARED{my_plan},
451+
$_[0],
452+
)->{rows}->[0]->{now};
453+
$$ LANGUAGE plperl;
454+
455+
CREATE OR REPLACE FUNCTION done() RETURNS INTEGER AS $$
456+
spi_freeplan( $_SHARED{my_plan});
457+
undef $_SHARED{my_plan};
458+
$$ LANGUAGE plperl;
459+
460+
SELECT init();
461+
SELECT add_time('1 day'), add_time('2 days'), add_time('3 days');
462+
SELECT done();
463+
464+
add_time | add_time | add_time
465+
------------+------------+------------
466+
2005-12-10 | 2005-12-11 | 2005-12-12
467+
</programlisting>
468+
</para>
469+
470+
<para>
471+
Note that the parameter subscript in <literal>spi_prepare</literal> is defined via
472+
$1, $2, $3, etc, so avoid declaring query strings in double quotes that might easily
473+
lead to hard-to-catch bugs.
474+
</para>
475+
476+
<para>
477+
<literal>spi_cursor_close</literal> can be used to abort sequence of
478+
<literal>spi_fetchrow</literal> calls. Normally, the call to
479+
<literal>spi_fetchrow</literal> that returns <literal>undef</literal> is
480+
the signal that there are no more rows to read. Also
481+
that call automatically frees the cursor associated with the query. If it is desired not
482+
to read all retuned rows, <literal>spi_cursor_close</literal> must be
483+
called to avoid memory leaks.
484+
</para>
485+
422486

423487
</listitem>
424488
</varlistentry>

‎src/pl/plperl/SPI.xs

Lines changed: 81 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,8 @@ spi_spi_exec_query(query, ...)
111111
intlimit=0;
112112
CODE:
113113
if (items>2)
114-
croak("Usage: spi_exec_query(query, limit) or spi_exec_query(query)");
114+
croak("Usage: spi_exec_query(query, limit) "
115+
"or spi_exec_query(query)");
115116
if (items==2)
116117
limit=SvIV(ST(1));
117118
ret_hash=plperl_spi_exec(query,limit);
@@ -141,5 +142,84 @@ spi_spi_fetchrow(cursor)
141142
OUTPUT:
142143
RETVAL
143144

145+
SV*
146+
spi_spi_prepare(query, ...)
147+
char*query;
148+
CODE:
149+
inti;
150+
SV**argv;
151+
if (items<1)
152+
Perl_croak(aTHX_"Usage: spi_prepare(query, ...)");
153+
argv= (SV**)palloc((items-1)*sizeof(SV*));
154+
if (argv==NULL)
155+
Perl_croak(aTHX_"spi_prepare: not enough memory");
156+
for (i=1;i<items;i++)
157+
argv[i-1]=ST(i);
158+
RETVAL=plperl_spi_prepare(query,items-1,argv);
159+
pfree(argv);
160+
OUTPUT:
161+
RETVAL
162+
163+
SV*
164+
spi_spi_exec_prepared(query, ...)
165+
char*query;
166+
PREINIT:
167+
HV*ret_hash;
168+
CODE:
169+
HV*attr=NULL;
170+
inti,offset=1,argc;
171+
SV**argv;
172+
if (items<1)
173+
Perl_croak(aTHX_"Usage: spi_exec_prepared(query, [\\%%attr,] "
174+
"[\\@bind_values])");
175+
if (items>1&&SvROK(ST(1))&&SvTYPE(SvRV(ST(1)))==SVt_PVHV)
176+
{
177+
attr= (HV*)SvRV(ST(1));
178+
offset++;
179+
}
180+
argc=items-offset;
181+
argv= (SV**)palloc(argc*sizeof(SV*));
182+
if (argv==NULL)
183+
Perl_croak(aTHX_"spi_exec_prepared: not enough memory");
184+
for (i=0;offset<items;offset++,i++)
185+
argv[i]=ST(offset);
186+
ret_hash=plperl_spi_exec_prepared(query,attr,argc,argv);
187+
RETVAL=newRV_noinc((SV*)ret_hash);
188+
pfree(argv);
189+
OUTPUT:
190+
RETVAL
191+
192+
SV*
193+
spi_spi_query_prepared(query, ...)
194+
char*query;
195+
CODE:
196+
inti;
197+
SV**argv;
198+
if (items<1)
199+
Perl_croak(aTHX_"Usage: spi_query_prepared(query, "
200+
"[\\@bind_values])");
201+
argv= (SV**)palloc((items-1)*sizeof(SV*));
202+
if (argv==NULL)
203+
Perl_croak(aTHX_"spi_query_prepared: not enough memory");
204+
for (i=1;i<items;i++)
205+
argv[i-1]=ST(i);
206+
RETVAL=plperl_spi_query_prepared(query,items-1,argv);
207+
pfree(argv);
208+
OUTPUT:
209+
RETVAL
210+
211+
void
212+
spi_spi_freeplan(query)
213+
char*query;
214+
CODE:
215+
plperl_spi_freeplan(query);
216+
217+
void
218+
spi_spi_cursor_close(cursor)
219+
char*cursor;
220+
CODE:
221+
plperl_spi_cursor_close(cursor);
222+
223+
144224
BOOT:
145225
items=0;/* avoid 'unused variable' warning */

‎src/pl/plperl/expected/plperl.out

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -367,6 +367,20 @@ SELECT * from perl_spi_func();
367367
2
368368
(2 rows)
369369

370+
--
371+
-- Test spi_fetchrow abort
372+
--
373+
CREATE OR REPLACE FUNCTION perl_spi_func2() RETURNS INTEGER AS $$
374+
my $x = spi_query("select 1 as a union select 2 as a");
375+
spi_cursor_close( $x);
376+
return 0;
377+
$$ LANGUAGE plperl;
378+
SELECT * from perl_spi_func2();
379+
perl_spi_func2
380+
----------------
381+
0
382+
(1 row)
383+
370384
---
371385
--- Test recursion via SPI
372386
---
@@ -420,3 +434,37 @@ SELECT array_of_text();
420434
{{"a\"b",NULL,"c,d"},{"e\\f",NULL,g}}
421435
(1 row)
422436

437+
--
438+
-- Test spi_prepare/spi_exec_prepared/spi_freeplan
439+
--
440+
CREATE OR REPLACE FUNCTION perl_spi_prepared(INTEGER) RETURNS INTEGER AS $$
441+
my $x = spi_prepare('select $1 AS a', 'INT4');
442+
my $q = spi_exec_prepared( $x, $_[0] + 1);
443+
spi_freeplan($x);
444+
return $q->{rows}->[0]->{a};
445+
$$ LANGUAGE plperl;
446+
SELECT * from perl_spi_prepared(42);
447+
perl_spi_prepared
448+
-------------------
449+
43
450+
(1 row)
451+
452+
--
453+
-- Test spi_prepare/spi_query_prepared/spi_freeplan
454+
--
455+
CREATE OR REPLACE FUNCTION perl_spi_prepared_set(INTEGER, INTEGER) RETURNS SETOF INTEGER AS $$
456+
my $x = spi_prepare('SELECT $1 AS a union select $2 as a', 'INT4', 'INT4');
457+
my $q = spi_query_prepared( $x, 1+$_[0], 2+$_[1]);
458+
while (defined (my $y = spi_fetchrow($q))) {
459+
return_next $y->{a};
460+
}
461+
spi_freeplan($x);
462+
return;
463+
$$ LANGUAGE plperl;
464+
SELECT * from perl_spi_prepared_set(1,2);
465+
perl_spi_prepared_set
466+
-----------------------
467+
2
468+
4
469+
(2 rows)
470+

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp