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));
|
ST(0) = !st->prepared ? &PL_sv_undef : sv_2mortal(newSVnv(st->preptime));
|
||||||
|
|
||||||
void get_cache(fupg_st *st)
|
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:
|
CODE:
|
||||||
ST(0) = st->stflags & FUPG_CACHE ? &PL_sv_yes : &PL_sv_no;
|
if (!ix) ix = FUPG_CACHE;
|
||||||
|
ST(0) = st->stflags & ix ? &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;
|
|
||||||
|
|
||||||
void DESTROY(fupg_st *st)
|
void DESTROY(fupg_st *st)
|
||||||
CODE:
|
CODE:
|
||||||
|
|
|
||||||
4
FU/Pg.pm
4
FU/Pg.pm
|
|
@ -371,7 +371,9 @@ parameter in the given C<$sql> string. Example:
|
||||||
# $oids = []
|
# $oids = []
|
||||||
|
|
||||||
This method can be called before the query has been executed, but will then
|
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
|
=item $st->columns
|
||||||
|
|
||||||
|
|
|
||||||
27
c/pgst.c
27
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. */
|
* results in a streaming fashion without breaking API compat. */
|
||||||
if (st->result) fu_confess("Invalid attempt to execute statement multiple times");
|
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 */
|
||||||
fupg_st_prepare(aTHX_ st);
|
int direct = !st->describe && (st->nbind == 0 || st->stflags & FUPG_TEXT_PARAMS) && !(st->stflags & FUPG_CACHE);
|
||||||
if (PQnparams(st->describe) != st->nbind)
|
if (!direct) {
|
||||||
fu_confess("Statement expects %d bind parameters but %d were given", PQnparams(st->describe), st->nbind);
|
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;
|
int refresh_done = 0;
|
||||||
fupg_params_setup(aTHX_ st, &refresh_done);
|
fupg_params_setup(aTHX_ st, &refresh_done);
|
||||||
|
|
||||||
|
|
@ -290,13 +293,17 @@ static void fupg_st_execute(pTHX_ fupg_st *st) {
|
||||||
* improvement */
|
* improvement */
|
||||||
struct timespec t_start;
|
struct timespec t_start;
|
||||||
clock_gettime(CLOCK_MONOTONIC, &t_start);
|
clock_gettime(CLOCK_MONOTONIC, &t_start);
|
||||||
PGresult *r = PQexecPrepared(st->conn->conn,
|
PGresult *r = direct ? PQexecParams(st->conn->conn,
|
||||||
st->name,
|
st->query, st->nbind, NULL,
|
||||||
st->nbind,
|
|
||||||
(const char * const *)st->param_values,
|
(const char * const *)st->param_values,
|
||||||
st->param_lengths,
|
st->param_lengths, st->param_formats,
|
||||||
st->param_formats,
|
st->stflags & FUPG_TEXT_RESULTS ? 0 : 1
|
||||||
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;
|
struct timespec t_end;
|
||||||
clock_gettime(CLOCK_MONOTONIC, &t_end);
|
clock_gettime(CLOCK_MONOTONIC, &t_end);
|
||||||
st->exectime = fu_timediff(&t_end, &t_start);
|
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;
|
is $conn->exec('SELECT 1 FROM pg_prepared_statements'), 0;
|
||||||
|
|
||||||
ok !eval { $conn->q('SELECT 1', 1)->exec; 1 };
|
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 };
|
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...
|
# prepare + describe won't let us detect empty queries, hmm...
|
||||||
is_deeply $conn->q('')->param_types, [];
|
is_deeply $conn->q('')->param_types, [];
|
||||||
|
|
@ -88,7 +88,7 @@ subtest '$st prepare & exec', sub {
|
||||||
is $conn->q('SET client_encoding=utf8')->exec, undef;
|
is $conn->q('SET client_encoding=utf8')->exec, undef;
|
||||||
|
|
||||||
ok !eval { $conn->q('select 1; select 2')->exec; 1 };
|
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
|
# Interleaved
|
||||||
{
|
{
|
||||||
|
|
@ -400,7 +400,7 @@ subtest 'Tracing', sub {
|
||||||
my @log;
|
my @log;
|
||||||
$conn->query_trace(sub($st) { push @log, $st });
|
$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;
|
is scalar @log, 1;
|
||||||
my $st = shift @log;
|
my $st = shift @log;
|
||||||
is ref $st, 'FU::Pg::st';
|
is ref $st, 'FU::Pg::st';
|
||||||
|
|
@ -412,8 +412,8 @@ subtest 'Tracing', sub {
|
||||||
ok $st->exec_time > 0 && $st->exec_time < 1;
|
ok $st->exec_time > 0 && $st->exec_time < 1;
|
||||||
ok $st->prepare_time > 0 && $st->prepare_time < 1;
|
ok $st->prepare_time > 0 && $st->prepare_time < 1;
|
||||||
ok !$st->get_cache;
|
ok !$st->get_cache;
|
||||||
ok $st->text_params;
|
ok !$st->get_text_params;
|
||||||
ok $st->text_results;
|
ok $st->get_text_results;
|
||||||
|
|
||||||
$conn->exec('SET client_encoding=UTF8');
|
$conn->exec('SET client_encoding=UTF8');
|
||||||
is scalar @log, 1;
|
is scalar @log, 1;
|
||||||
|
|
@ -427,8 +427,8 @@ subtest 'Tracing', sub {
|
||||||
ok $st->exec_time > 0 && $st->exec_time < 1;
|
ok $st->exec_time > 0 && $st->exec_time < 1;
|
||||||
ok !defined $st->prepare_time;
|
ok !defined $st->prepare_time;
|
||||||
ok !$st->get_cache;
|
ok !$st->get_cache;
|
||||||
ok $st->text_params;
|
ok $st->get_text_params;
|
||||||
ok $st->text_results;
|
ok $st->get_text_results;
|
||||||
|
|
||||||
$conn->query_trace(undef);
|
$conn->query_trace(undef);
|
||||||
$conn->exec('SELECT 1');
|
$conn->exec('SELECT 1');
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue