Pg: Skip query preparation when we can
This commit is contained in:
parent
4686097d00
commit
0734bc4991
4 changed files with 33 additions and 28 deletions
14
FU.xs
14
FU.xs
|
|
@ -380,16 +380,12 @@ void prepare_time(fupg_st *st)
|
|||
ST(0) = !st->prepared ? &PL_sv_undef : sv_2mortal(newSVnv(st->preptime));
|
||||
|
||||
void get_cache(fupg_st *st)
|
||||
ALIAS:
|
||||
FU::Pg::st::get_text_params = FUPG_TEXT_PARAMS
|
||||
FU::Pg::st::get_text_results = FUPG_TEXT_RESULTS
|
||||
CODE:
|
||||
ST(0) = st->stflags & FUPG_CACHE ? &PL_sv_yes : &PL_sv_no;
|
||||
|
||||
void get_text_params(fupg_st *st)
|
||||
CODE:
|
||||
ST(0) = st->stflags & FUPG_TEXT_PARAMS ? &PL_sv_yes : &PL_sv_no;
|
||||
|
||||
void get_text_results(fupg_st *st)
|
||||
CODE:
|
||||
ST(0) = st->stflags & FUPG_TEXT_RESULTS ? &PL_sv_yes : &PL_sv_no;
|
||||
if (!ix) ix = FUPG_CACHE;
|
||||
ST(0) = st->stflags & ix ? &PL_sv_yes : &PL_sv_no;
|
||||
|
||||
void DESTROY(fupg_st *st)
|
||||
CODE:
|
||||
|
|
|
|||
4
FU/Pg.pm
4
FU/Pg.pm
|
|
@ -371,7 +371,9 @@ parameter in the given C<$sql> string. Example:
|
|||
# $oids = []
|
||||
|
||||
This method can be called before the query has been executed, but will then
|
||||
trigger a prepare operation.
|
||||
trigger a prepare operation. An empty array is also returned if the query has
|
||||
already been executed without a separate preparation step; this happens if
|
||||
prepared statement caching is disabled and C<text_params> is enabled.
|
||||
|
||||
=item $st->columns
|
||||
|
||||
|
|
|
|||
21
c/pgst.c
21
c/pgst.c
|
|
@ -271,10 +271,13 @@ static void fupg_st_execute(pTHX_ fupg_st *st) {
|
|||
* results in a streaming fashion without breaking API compat. */
|
||||
if (st->result) fu_confess("Invalid attempt to execute statement multiple times");
|
||||
|
||||
/* TODO: prepare can be skipped when prepared statement caching is disabled and (text-format queries or no bind params) */
|
||||
/* Whether we can do a direct call or need to prepare first */
|
||||
int direct = !st->describe && (st->nbind == 0 || st->stflags & FUPG_TEXT_PARAMS) && !(st->stflags & FUPG_CACHE);
|
||||
if (!direct) {
|
||||
fupg_st_prepare(aTHX_ st);
|
||||
if (PQnparams(st->describe) != st->nbind)
|
||||
fu_confess("Statement expects %d bind parameters but %d were given", PQnparams(st->describe), st->nbind);
|
||||
}
|
||||
int refresh_done = 0;
|
||||
fupg_params_setup(aTHX_ st, &refresh_done);
|
||||
|
||||
|
|
@ -290,13 +293,17 @@ static void fupg_st_execute(pTHX_ fupg_st *st) {
|
|||
* improvement */
|
||||
struct timespec t_start;
|
||||
clock_gettime(CLOCK_MONOTONIC, &t_start);
|
||||
PGresult *r = PQexecPrepared(st->conn->conn,
|
||||
st->name,
|
||||
st->nbind,
|
||||
PGresult *r = direct ? PQexecParams(st->conn->conn,
|
||||
st->query, st->nbind, NULL,
|
||||
(const char * const *)st->param_values,
|
||||
st->param_lengths,
|
||||
st->param_formats,
|
||||
st->stflags & FUPG_TEXT_RESULTS ? 0 : 1);
|
||||
st->param_lengths, st->param_formats,
|
||||
st->stflags & FUPG_TEXT_RESULTS ? 0 : 1
|
||||
) : PQexecPrepared(st->conn->conn,
|
||||
st->name, st->nbind,
|
||||
(const char * const *)st->param_values,
|
||||
st->param_lengths, st->param_formats,
|
||||
st->stflags & FUPG_TEXT_RESULTS ? 0 : 1
|
||||
);
|
||||
struct timespec t_end;
|
||||
clock_gettime(CLOCK_MONOTONIC, &t_end);
|
||||
st->exectime = fu_timediff(&t_end, &t_start);
|
||||
|
|
|
|||
|
|
@ -73,10 +73,10 @@ subtest '$st prepare & exec', sub {
|
|||
is $conn->exec('SELECT 1 FROM pg_prepared_statements'), 0;
|
||||
|
||||
ok !eval { $conn->q('SELECT 1', 1)->exec; 1 };
|
||||
like $@, qr/Statement expects 0 bind parameters but 1 were given/;
|
||||
like $@, qr/bind message supplies 1 parameters, but prepared statement/;
|
||||
|
||||
ok !eval { $conn->q('SELECT $1')->exec; 1 };
|
||||
like $@, qr/Statement expects 1 bind parameters but 0 were given/;
|
||||
like $@, qr/bind message supplies 0 parameters, but prepared statement/;
|
||||
|
||||
# prepare + describe won't let us detect empty queries, hmm...
|
||||
is_deeply $conn->q('')->param_types, [];
|
||||
|
|
@ -88,7 +88,7 @@ subtest '$st prepare & exec', sub {
|
|||
is $conn->q('SET client_encoding=utf8')->exec, undef;
|
||||
|
||||
ok !eval { $conn->q('select 1; select 2')->exec; 1 };
|
||||
okerr ERROR => prepare => qr/cannot insert multiple commands into a prepared statement/;
|
||||
okerr ERROR => exec => qr/cannot insert multiple commands into a prepared statement/;
|
||||
|
||||
# Interleaved
|
||||
{
|
||||
|
|
@ -400,7 +400,7 @@ subtest 'Tracing', sub {
|
|||
my @log;
|
||||
$conn->query_trace(sub($st) { push @log, $st });
|
||||
|
||||
is_deeply $conn->q('SELECT 1 AS a, $1 AS b', 123)->rowa, [ 1, 123 ];
|
||||
is_deeply $conn->q('SELECT 1 AS a, $1 AS b', 123)->text_params(0)->rowa, [ 1, 123 ];
|
||||
is scalar @log, 1;
|
||||
my $st = shift @log;
|
||||
is ref $st, 'FU::Pg::st';
|
||||
|
|
@ -412,8 +412,8 @@ subtest 'Tracing', sub {
|
|||
ok $st->exec_time > 0 && $st->exec_time < 1;
|
||||
ok $st->prepare_time > 0 && $st->prepare_time < 1;
|
||||
ok !$st->get_cache;
|
||||
ok $st->text_params;
|
||||
ok $st->text_results;
|
||||
ok !$st->get_text_params;
|
||||
ok $st->get_text_results;
|
||||
|
||||
$conn->exec('SET client_encoding=UTF8');
|
||||
is scalar @log, 1;
|
||||
|
|
@ -427,8 +427,8 @@ subtest 'Tracing', sub {
|
|||
ok $st->exec_time > 0 && $st->exec_time < 1;
|
||||
ok !defined $st->prepare_time;
|
||||
ok !$st->get_cache;
|
||||
ok $st->text_params;
|
||||
ok $st->text_results;
|
||||
ok $st->get_text_params;
|
||||
ok $st->get_text_results;
|
||||
|
||||
$conn->query_trace(undef);
|
||||
$conn->exec('SELECT 1');
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue