Committed by Greg Sabino Mullane <[email protected]>
Add new attribute, pg_switch_prepared, which controls when
we switch from using PQexecParams to PQexecPrepared. The default is 2,
meaning we do one round of PQexecParams, then switch to PQexecPrepared.
Mostly a proof of concept, alhough it seems to at least pass the tests. :)
---
.perlcriticrc | 2 +-
Pg.pm | 22 ++++
dbdimp.c | 404 ++++++++++++++++++++++++++++++----------------------------
dbdimp.h | 21 +--
4 files changed, 241 insertions(+), 208 deletions(-)
diff --git a/.perlcriticrc b/.perlcriticrc
index c1cbfdf..1b90e2a 100644
--- a/.perlcriticrc
+++ b/.perlcriticrc
@@ -2,7 +2,7 @@ verbose = 9
profile-strictness = quiet
[Documentation::PodSpelling]
-stop_words = ActiveKids AutoCommit boolean Bunce CachedKids ChildHandles
ChopBlanks CompatMode CursorName DBD DBI Datatype dbdpg dev enum ErrCount
FetchHashKeyName HandleError HandleSetErr InactiveDestroy LongReadLen
LongTruncOk Mergl Momjian Mullane NULLABLE OID ParamValues ParamTypes PgBouncer
pgend pglibpq pglogin pgprefix pgquote pgstart PGSERVICE PGSYSCONFDIR perl
Postgres PostgreSQL PrintError PrintWarn README RaiseError RowCache
RowCacheSize RowsInCache SQL SQLSTATE SSL STDIN STDERR STDOUT Sabino Savepoints
ShowErrorStatement TaintIn TaintOut TraceLevel UTF Username afterwards
arrayrefs attr autocommit backend bitmask bytea cancelled datatype dbd dbh
errstr fd filename getfd getline hashref largeobject len libpq lseg pgbuiltin
pgsql runtime savepoint savepoints schemas sslmode tablename tablespace
tablespaces tuple typename username varchar undef Perlish arrayref datatypes
bool func PID dr ReadOnly nullable hashrefs DSN onwards AutoInactiveDestroy
+stop_words = ActiveKids AutoCommit boolean Bunce CachedKids ChildHandles
ChopBlanks CompatMode CursorName DBD DBI Datatype dbdpg dev enum ErrCount
FetchHashKeyName HandleError HandleSetErr InactiveDestroy LongReadLen
LongTruncOk Mergl Momjian Mullane NULLABLE OID ParamValues ParamTypes PgBouncer
pgend pglibpq pglogin pgprefix pgquote pgstart PGSERVICE PGSYSCONFDIR perl
Postgres PostgreSQL PrintError PrintWarn README RaiseError RowCache
RowCacheSize RowsInCache SQL SQLSTATE SSL STDIN STDERR STDOUT Sabino Savepoints
ShowErrorStatement TaintIn TaintOut TraceLevel UTF Username afterwards
arrayrefs attr autocommit backend bitmask bytea cancelled datatype dbd dbh
errstr fd filename getfd getline hashref largeobject len libpq lseg pgbuiltin
pgsql runtime savepoint savepoints schemas sslmode tablename tablespace
tablespaces tuple typename username varchar undef Perlish arrayref datatypes
bool func PID dr ReadOnly nullable hashrefs DSN onwards AutoInactiveDestroy
PQexecParams PQexecP
repared
[-Bangs::ProhibitBitwiseOperators]
[-Bangs::ProhibitCommentedOutCode]
diff --git a/Pg.pm b/Pg.pm
index 09cc940..01d50ac 100644
--- a/Pg.pm
+++ b/Pg.pm
@@ -1685,6 +1685,7 @@ use 5.008001;
pg_server_version => undef,
pg_socket => undef,
pg_standard_conforming_strings => undef,
+ pg_switch_prepared => undef,
pg_user => undef,
};
}
@@ -1739,6 +1740,7 @@ use 5.008001;
pg_segments => undef,
pg_server_prepare => undef,
pg_size => undef,
+ pg_switch_prepared => undef,
pg_type => undef,
};
}
@@ -3184,6 +3186,16 @@ DBD::Pg specific attribute. Indicates if DBD::Pg should
attempt to use server-si
prepared statements. The default value, 1, indicates that prepared statements
should
be used whenever possible. See the section on the L</prepare> method for more
information.
+=head3 B<pg_switch_prepared> (integer)
+
+DBD::Pg specific attribute. Indicates when DBD::Pg will internally switch from
using
+PQexecParams to PQexecPrepared. In other words, when it will start using
server-side
+prepared statements (assuming all other requirements for them are met). The
default value,
+2, means that a prepared statement will be prepared and used the second and
subsequent
+time execute is called. To always use PQexecPrepared instead of PQexecParams,
set
+pg_switch_prepared to 1. Setting it to 0 will force DBD::Pg to use
PQexecPrepared always -
+this was the default behavior in versions older than 3.0.0.
+
=head3 B<pg_placeholder_dollaronly> (boolean)
DBD::Pg specific attribute. Defaults to false. When true, question marks
inside of statements
@@ -3841,6 +3853,16 @@ prepared statements for this statement handle. The
default value, 1, indicates t
statements should be used whenever possible. See the section on the
L</prepare> method for
more information.
+=head3 B<pg_switch_prepared> (integer)
+
+DBD::Pg specific attribute. Indicates when DBD::Pg will internally switch from
using
+PQexecParams to PQexecPrepared. In other words, when it will start using
server-side
+prepared statements (assuming all other requirements for them are met). The
default value,
+2, means that a prepared statement will be prepared and used the second and
subsequent
+time execute is called. To always use PQexecPrepared instead of PQexecParams,
set
+pg_switch_prepared to 1 (this was the default behavior in earlier versions).
+Setting pg_switch_prepared to 0 will force DBD::Pg to always use PQexecParams.
+
=head3 B<pg_placeholder_dollaronly> (boolean)
DBD::Pg specific attribute. Defaults to off. When true, question marks inside
of the query
diff --git a/dbdimp.c b/dbdimp.c
index 0c2b8fd..615b52a 100644
--- a/dbdimp.c
+++ b/dbdimp.c
@@ -233,17 +233,18 @@ int dbd_db_login6 (SV * dbh, imp_dbh_t * imp_dbh, char *
dbname, char * uid, cha
imp_dbh->pg_enable_utf8 = -1;
- imp_dbh->prepare_now = DBDPG_FALSE;
- imp_dbh->done_begin = DBDPG_FALSE;
- imp_dbh->dollaronly = DBDPG_FALSE;
- imp_dbh->expand_array = DBDPG_TRUE;
- imp_dbh->txn_read_only = DBDPG_FALSE;
- imp_dbh->pid_number = getpid();
- imp_dbh->prepare_number = 1;
- imp_dbh->copystate = 0;
- imp_dbh->pg_errorlevel = 1; /* Default */
- imp_dbh->async_status = 0;
- imp_dbh->async_sth = NULL;
+ imp_dbh->prepare_now = DBDPG_FALSE;
+ imp_dbh->done_begin = DBDPG_FALSE;
+ imp_dbh->dollaronly = DBDPG_FALSE;
+ imp_dbh->expand_array = DBDPG_TRUE;
+ imp_dbh->txn_read_only = DBDPG_FALSE;
+ imp_dbh->pid_number = getpid();
+ imp_dbh->prepare_number = 1;
+ imp_dbh->switch_prepared = 2;
+ imp_dbh->copystate = 0;
+ imp_dbh->pg_errorlevel = 1; /* Default */
+ imp_dbh->async_status = 0;
+ imp_dbh->async_sth = NULL;
/* If using server version 7.4, switch to "smart" */
imp_dbh->server_prepare = PGLIBVERSION >= 80000 ? 1 : 2;
@@ -1474,37 +1475,39 @@ int dbd_st_prepare (SV * sth, imp_sth_t * imp_sth, char
* statement, SV * attrib
croak ("Cannot prepare empty statement");
/* Set default values for this statement handle */
- imp_sth->placeholder_type = 0;
- imp_sth->numsegs = 0;
- imp_sth->numphs = 0;
- imp_sth->numbound = 0;
- imp_sth->cur_tuple = 0;
- imp_sth->rows = -1; /* per DBI spec */
- imp_sth->totalsize = 0;
- imp_sth->async_flag = 0;
- imp_sth->async_status = 0;
- imp_sth->prepare_name = NULL;
- imp_sth->firstword = NULL;
- imp_sth->result = NULL;
- imp_sth->type_info = NULL;
- imp_sth->seg = NULL;
- imp_sth->ph = NULL;
- imp_sth->PQvals = NULL;
- imp_sth->PQlens = NULL;
- imp_sth->PQfmts = NULL;
- imp_sth->PQoids = NULL;
- imp_sth->prepared_by_us = DBDPG_FALSE; /* Set to 1 when actually done
preparing */
- imp_sth->onetime = DBDPG_FALSE; /* Allow internal shortcut */
- imp_sth->direct = DBDPG_FALSE;
- imp_sth->is_dml = DBDPG_FALSE; /* Not preparable DML until
proved otherwise */
- imp_sth->has_binary = DBDPG_FALSE; /* Are any of the params
binary? */
- imp_sth->has_default = DBDPG_FALSE; /* Are any of the params
DEFAULT? */
- imp_sth->has_current = DBDPG_FALSE; /* Are any of the params
DEFAULT? */
- imp_sth->use_inout = DBDPG_FALSE; /* Are any of the placeholders
using inout? */
- imp_sth->all_bound = DBDPG_FALSE; /* Have all placeholders been
bound? */
+ imp_sth->placeholder_type = 0;
+ imp_sth->numsegs = 0;
+ imp_sth->numphs = 0;
+ imp_sth->numbound = 0;
+ imp_sth->cur_tuple = 0;
+ imp_sth->rows = -1; /* per DBI spec */
+ imp_sth->totalsize = 0;
+ imp_sth->async_flag = 0;
+ imp_sth->async_status = 0;
+ imp_sth->prepare_name = NULL;
+ imp_sth->firstword = NULL;
+ imp_sth->result = NULL;
+ imp_sth->type_info = NULL;
+ imp_sth->seg = NULL;
+ imp_sth->ph = NULL;
+ imp_sth->PQvals = NULL;
+ imp_sth->PQlens = NULL;
+ imp_sth->PQfmts = NULL;
+ imp_sth->PQoids = NULL;
+ imp_sth->prepared_by_us = DBDPG_FALSE; /* Set to 1 when actually
done preparing */
+ imp_sth->onetime = DBDPG_FALSE; /* Allow internal shortcut */
+ imp_sth->direct = DBDPG_FALSE;
+ imp_sth->is_dml = DBDPG_FALSE; /* Not preparable DML until
proved otherwise */
+ imp_sth->has_binary = DBDPG_FALSE; /* Are any of the params
binary? */
+ imp_sth->has_default = DBDPG_FALSE; /* Are any of the params
DEFAULT? */
+ imp_sth->has_current = DBDPG_FALSE; /* Are any of the params
DEFAULT? */
+ imp_sth->use_inout = DBDPG_FALSE; /* Are any of the
placeholders using inout? */
+ imp_sth->all_bound = DBDPG_FALSE; /* Have all placeholders been
bound? */
+ imp_sth->number_iterations = 0;
/* We inherit some preferences from the database handle */
imp_sth->server_prepare = imp_dbh->server_prepare;
+ imp_sth->switch_prepared = imp_dbh->switch_prepared;
imp_sth->prepare_now = imp_dbh->prepare_now;
imp_sth->dollaronly = imp_dbh->dollaronly;
@@ -2951,6 +2954,7 @@ int dbd_st_execute (SV * sth, imp_sth_t * imp_sth)
char * statement = NULL;
int num_fields;
int ret = -2;
+ int pqtype = 0;
long power_of_ten;
if (TSTART_slow) TRC(DBILOGFP, "%sBegin dbd_st_execute\n",
THEADER_slow);
@@ -3029,17 +3033,64 @@ int dbd_st_execute (SV * sth, imp_sth_t * imp_sth)
/*
Now, we need to build the statement to send to the backend
We are using one of PQexec, PQexecPrepared, or PQexecParams
- First, we figure out the size of the statement...
+ Let's figure out which we are going to use and set pqtype
+ 0= unknown
+ 1= PQexec
+ 2= PQexecParams
+ 3= PQexecPrepared
*/
- execsize = imp_sth->totalsize; /* Total of all segments */
+ if (TRACE4_slow) TRC(DBILOGFP,
+ "%sPQexec* decision: dml=%d direct=%d
server_prepare=%d numbound=%d numphs=%d default=%d current=%d\n",
+ THEADER_slow,
+ imp_sth->is_dml,
+ imp_sth->direct,
+ imp_sth->server_prepare,
+ imp_sth->numbound,
+ imp_sth->numphs,
+ imp_sth->has_default,
+ imp_sth->has_current);
- /* If using plain old PQexec, we need to quote each value ourselves */
+ /* We must use PQexec if:
+ 1. The statement is *not* DML (e.g. is DDL, which cannot be prepared)
+ 2. We have a DEFAULT parameter
+ 3. We have a CURRENT parameter
+ 4. pg_direct is true
+ 5. pg_server_prepare is false
+ 6. pg_server_prepare is 2, but all placeholders are not bound
+ */
if (!imp_sth->is_dml
|| imp_sth->has_default
|| imp_sth->has_current
- || 1 != imp_sth->server_prepare
- ) {
+ || imp_sth->direct
+ || !imp_sth->server_prepare
+ || (2==imp_sth->server_prepare && imp_sth->numbound !=
imp_sth->numphs)
+ )
+ pqtype = 1; /* PQexec */
+ else if (0==imp_sth->switch_prepared || imp_sth->number_iterations <
imp_sth->switch_prepared) {
+ pqtype = 2; /* PQexecParams */
+ }
+ else {
+ pqtype = 3; /* PQexecPrepared */
+ }
+
+ /* Increment our count */
+ imp_sth->number_iterations++;
+
+ /* We use the new server_side prepare style if:
+ 1. The statement is DML (DDL is not preparable)
+ 2. The attribute "pg_direct" is false
+ 3. The attribute "pg_server_prepare" is not 0
+ 4. The "onetime" attribute has not been set
+ 5. There are no DEFAULT or CURRENT values
+ 6a. The attribute "pg_server_prepare" is 1
+ OR
+ 6b. All placeholders are bound (and "pg_server_prepare" is 2)
+ */
+ execsize = imp_sth->totalsize; /* Total of all segments */
+
+ /* If using plain old PQexec, we need to quote each value ourselves */
+ if (1 == pqtype) {
for (currph=imp_sth->ph; NULL != currph; currph=currph->nextph)
{
if (currph->isdefault) {
Renew(currph->quoted, 8, char); /* freed in
dbd_st_destroy */
@@ -3074,7 +3125,7 @@ int dbd_st_execute (SV * sth, imp_sth_t * imp_sth)
}
}
else { /* We are using a server that can handle
PQexecParams/PQexecPrepared */
- /* Put all values into an array to pass to PQexecPrepared */
+ /* Put all values into an array to pass to one of the above */
if (NULL == imp_sth->PQvals) {
Newz(0, imp_sth->PQvals, (unsigned int)imp_sth->numphs,
const char *); /* freed in dbd_st_destroy */
}
@@ -3102,36 +3153,116 @@ int dbd_st_execute (SV * sth, imp_sth_t * imp_sth)
}
}
- /* We use the new server_side prepare style if:
- 1. The statement is DML (DDL is not preparable)
- 2. The attribute "pg_direct" is false
- 3. The attribute "pg_server_prepare" is not 0
- 4. The "onetime" attribute has not been set
- 5. There are no DEFAULT or CURRENT values
- 6a. The attribute "pg_server_prepare" is 1
- OR
- 6b. All placeholders are bound (and "pg_server_prepare" is 2)
- */
- if (TRACE4_slow) TRC(DBILOGFP,
- "%sPQexec* decision: dml=%d direct=%d
server_prepare=%d numbound=%d numphs=%d default=%d current=%d\n",
- THEADER_slow,
- imp_sth->is_dml,
- imp_sth->direct,
- imp_sth->server_prepare,
- imp_sth->numbound,
- imp_sth->numphs,
- imp_sth->has_default,
- imp_sth->has_current);
+ /* Run one of PQexec, PQexecParams, or PQexecPrepared */
+ if (1 == pqtype) { /* PQexec */
- if (imp_sth->is_dml
- && !imp_sth->direct
- && 0 != imp_sth->server_prepare
- && !imp_sth->has_default
- && !imp_sth->has_current
- && !imp_sth->onetime
- && (1 == imp_sth->server_prepare
- || (imp_sth->numbound == imp_sth->numphs))
- ){
+ if (TRACE5_slow) TRC(DBILOGFP, "%sPQexec\n", THEADER_slow);
+
+ /* Go through and quote each value, then turn into a giant
statement */
+ for (currseg=imp_sth->seg; NULL != currseg;
currseg=currseg->nextseg) {
+ if (currseg->placeholder!=0)
+ execsize += currseg->ph->quotedlen;
+ }
+
+ New(0, statement, execsize+1, char); /* freed below */
+ statement[0] = '\0';
+ for (currseg=imp_sth->seg; NULL != currseg;
currseg=currseg->nextseg) {
+ if (currseg->segment != NULL)
+ strcat(statement, currseg->segment);
+ if (currseg->placeholder!=0)
+ strcat(statement, currseg->ph->quoted);
+ }
+ statement[execsize] = '\0';
+
+ if (TRACE5_slow) TRC(DBILOGFP, "%sRunning %s with (%s)\n",
+ THEADER_slow,
imp_sth->async_flag & 1 ? "PQsendQuery" : "PQexec", statement);
+
+ if (TSQL)
+ TRC(DBILOGFP, "%s;\n\n", statement);
+
+ if (imp_sth->async_flag & PG_ASYNC) {
+ TRACE_PQSENDQUERY;
+ ret = PQsendQuery(imp_dbh->conn, statement);
+ }
+ else {
+ TRACE_PQEXEC;
+ imp_sth->result = PQexec(imp_dbh->conn, statement);
+ }
+
+ Safefree(statement);
+
+ }
+ else if (2 == pqtype) { /* PQexecParams */
+ if (TRACE5_slow) TRC(DBILOGFP, "%sPQexecParams\n",
THEADER_slow);
+
+ /* Figure out how big the statement plus placeholders will be */
+ for (currseg=imp_sth->seg; NULL != currseg;
currseg=currseg->nextseg) {
+ if (0==currseg->placeholder)
+ continue;
+ /* The parameter itself: dollar sign plus digit(s) */
+ power_of_ten = 10;
+ for (placeholder_digits=1; placeholder_digits<7;
placeholder_digits++, power_of_ten *= 10) {
+ if (currseg->placeholder < power_of_ten)
+ break;
+ }
+ if (placeholder_digits >= 7)
+ croak("Too many placeholders!");
+ execsize += placeholder_digits+1;
+ }
+
+ /* Create the statement */
+ New(0, statement, execsize+1, char); /* freed below */
+ statement[0] = '\0';
+ for (currseg=imp_sth->seg; NULL != currseg;
currseg=currseg->nextseg) {
+ if (currseg->segment != NULL)
+ strcat(statement, currseg->segment);
+ if (currseg->placeholder!=0)
+ sprintf(strchr(statement, '\0'), "$%d",
currseg->placeholder);
+ }
+ statement[execsize] = '\0';
+
+ /* Populate PQoids */
+ if (NULL == imp_sth->PQoids) {
+ Newz(0, imp_sth->PQoids, (unsigned int)imp_sth->numphs,
Oid);
+ }
+ for (x=0,currph=imp_sth->ph; NULL != currph;
currph=currph->nextph) {
+ imp_sth->PQoids[x++] = (currph->defaultval) ? 0 :
(Oid)currph->bind_type->type_id;
+ }
+
+ if (TRACE7_slow) {
+ for (x=0,currph=imp_sth->ph; NULL != currph;
currph=currph->nextph,x++) {
+ TRC(DBILOGFP, "%sPQexecParams item #%d\n",
THEADER_slow, (int)x);
+ TRC(DBILOGFP, "%s-> Type: (%d)\n",
THEADER_slow, imp_sth->PQoids[x]);
+ TRC(DBILOGFP, "%s-> Value: (%s)\n",
THEADER_slow, imp_sth->PQvals[x]);
+ TRC(DBILOGFP, "%s-> Length: (%d)\n",
THEADER_slow, imp_sth->PQlens ? imp_sth->PQlens[x] : 0);
+ TRC(DBILOGFP, "%s-> Format: (%d)\n",
THEADER_slow, imp_sth->PQfmts ? imp_sth->PQfmts[x] : 0);
+ }
+ }
+
+ if (TSQL) {
+ TRC(DBILOGFP, "EXECUTE %s (\n", statement);
+ for (x=0,currph=imp_sth->ph; NULL != currph;
currph=currph->nextph,x++) {
+ TRC(DBILOGFP, "$%d: %s\n", (int)x+1,
imp_sth->PQvals[x]);
+ }
+ TRC(DBILOGFP, ");\n\n");
+ }
+
+ if (TRACE5_slow) TRC(DBILOGFP, "%sRunning PQexecParams with
(%s)\n", THEADER_slow, statement);
+ if (imp_sth->async_flag & PG_ASYNC) {
+ TRACE_PQSENDQUERYPARAMS;
+ ret = PQsendQueryParams
+ (imp_dbh->conn, statement, imp_sth->numphs,
imp_sth->PQoids, imp_sth->PQvals, imp_sth->PQlens, imp_sth->PQfmts, 0);
+ }
+ else {
+ TRACE_PQEXECPARAMS;
+ imp_sth->result = PQexecParams
+ (imp_dbh->conn, statement, imp_sth->numphs,
imp_sth->PQoids, imp_sth->PQvals, imp_sth->PQlens, imp_sth->PQfmts, 0);
+ }
+
+ Safefree(statement);
+
+ }
+ else if (3 == pqtype) { /* PQexecPrepared */
if (TRACE4_slow) TRC(DBILOGFP, "%sPQexecPrepared\n",
THEADER_slow);
@@ -3182,131 +3313,8 @@ int dbd_st_execute (SV * sth, imp_sth_t * imp_sth)
(imp_dbh->conn, imp_sth->prepare_name,
imp_sth->numphs, imp_sth->PQvals, imp_sth->PQlens, imp_sth->PQfmts, 0);
}
} /* end new-style prepare */
- else {
- /* prepare via PQexec or PQexecParams */
-
-
- /* PQexecParams */
-
- if (imp_sth->is_dml
- && imp_sth->numphs
- && !imp_sth->has_default
- && !imp_sth->has_current
- && 1 == imp_sth->server_prepare
- ) {
-
- if (TRACE5_slow) TRC(DBILOGFP, "%sPQexecParams\n",
THEADER_slow);
-
- /* Figure out how big the statement plus placeholders
will be */
- for (currseg=imp_sth->seg; NULL != currseg;
currseg=currseg->nextseg) {
- if (0==currseg->placeholder)
- continue;
- /* The parameter itself: dollar sign plus
digit(s) */
- power_of_ten = 10;
- for (placeholder_digits=1;
placeholder_digits<7; placeholder_digits++, power_of_ten *= 10) {
- if (currseg->placeholder < power_of_ten)
- break;
- }
- if (placeholder_digits >= 7)
- croak("Too many placeholders!");
- execsize += placeholder_digits+1;
- }
-
- /* Create the statement */
- New(0, statement, execsize+1, char); /* freed below */
- statement[0] = '\0';
- for (currseg=imp_sth->seg; NULL != currseg;
currseg=currseg->nextseg) {
- if (currseg->segment != NULL)
- strcat(statement, currseg->segment);
- if (currseg->placeholder!=0)
- sprintf(strchr(statement, '\0'), "$%d",
currseg->placeholder);
- }
- statement[execsize] = '\0';
-
- /* Populate PQoids */
- if (NULL == imp_sth->PQoids) {
- Newz(0, imp_sth->PQoids, (unsigned
int)imp_sth->numphs, Oid);
- }
- for (x=0,currph=imp_sth->ph; NULL != currph;
currph=currph->nextph) {
- imp_sth->PQoids[x++] = (currph->defaultval) ? 0
: (Oid)currph->bind_type->type_id;
- }
-
- if (TRACE7_slow) {
- for (x=0,currph=imp_sth->ph; NULL != currph;
currph=currph->nextph,x++) {
- TRC(DBILOGFP, "%sPQexecParams item
#%d\n", THEADER_slow, (int)x);
- TRC(DBILOGFP, "%s-> Type: (%d)\n",
THEADER_slow, imp_sth->PQoids[x]);
- TRC(DBILOGFP, "%s-> Value: (%s)\n",
THEADER_slow, imp_sth->PQvals[x]);
- TRC(DBILOGFP, "%s-> Length: (%d)\n",
THEADER_slow, imp_sth->PQlens ? imp_sth->PQlens[x] : 0);
- TRC(DBILOGFP, "%s-> Format: (%d)\n",
THEADER_slow, imp_sth->PQfmts ? imp_sth->PQfmts[x] : 0);
- }
- }
-
- if (TSQL) {
- TRC(DBILOGFP, "EXECUTE %s (\n", statement);
- for (x=0,currph=imp_sth->ph; NULL != currph;
currph=currph->nextph,x++) {
- TRC(DBILOGFP, "$%d: %s\n", (int)x+1,
imp_sth->PQvals[x]);
- }
- TRC(DBILOGFP, ");\n\n");
- }
-
- if (TRACE5_slow) TRC(DBILOGFP, "%sRunning PQexecParams
with (%s)\n", THEADER_slow, statement);
- if (imp_sth->async_flag & PG_ASYNC) {
- TRACE_PQSENDQUERYPARAMS;
- ret = PQsendQueryParams
- (imp_dbh->conn, statement,
imp_sth->numphs, imp_sth->PQoids, imp_sth->PQvals, imp_sth->PQlens,
imp_sth->PQfmts, 0);
- }
- else {
- TRACE_PQEXECPARAMS;
- imp_sth->result = PQexecParams
- (imp_dbh->conn, statement,
imp_sth->numphs, imp_sth->PQoids, imp_sth->PQvals, imp_sth->PQlens,
imp_sth->PQfmts, 0);
- }
- }
-
- /* PQexec */
-
- else {
-
- if (TRACE5_slow) TRC(DBILOGFP, "%sPQexec\n",
THEADER_slow);
-
- /* Go through and quote each value, then turn into a
giant statement */
- for (currseg=imp_sth->seg; NULL != currseg;
currseg=currseg->nextseg) {
- if (currseg->placeholder!=0)
- execsize += currseg->ph->quotedlen;
- }
-
- New(0, statement, execsize+1, char); /* freed below */
- statement[0] = '\0';
- for (currseg=imp_sth->seg; NULL != currseg;
currseg=currseg->nextseg) {
- if (currseg->segment != NULL)
- strcat(statement, currseg->segment);
- if (currseg->placeholder!=0)
- strcat(statement, currseg->ph->quoted);
- }
- statement[execsize] = '\0';
-
- if (TRACE5_slow) TRC(DBILOGFP, "%sRunning %s with
(%s)\n",
- THEADER_slow,
imp_sth->async_flag & 1 ? "PQsendQuery" : "PQexec", statement);
-
- if (TSQL)
- TRC(DBILOGFP, "%s;\n\n", statement);
-
- if (imp_sth->async_flag & PG_ASYNC) {
- TRACE_PQSENDQUERY;
- ret = PQsendQuery(imp_dbh->conn, statement);
- }
- else {
- TRACE_PQEXEC;
- imp_sth->result = PQexec(imp_dbh->conn,
statement);
- }
-
- } /* end PQexec */
-
- Safefree(statement);
-
- } /* end non-prepared exec */
-
- /* Some form of PQexec/PQsendQuery has been run at this point */
+ /* Some form of PQexec* has been run at this point */
/* If running asynchronously, we don't stick around for the result */
if (imp_sth->async_flag & PG_ASYNC) {
diff --git a/dbdimp.h b/dbdimp.h
index a9e8081..22d55e7 100644
--- a/dbdimp.h
+++ b/dbdimp.h
@@ -23,6 +23,7 @@ struct imp_dbh_st {
int copystate; /* 0=none PGRES_COPY_IN PGRES_COPY_OUT */
int pg_errorlevel; /* PQsetErrorVerbosity. Set by user,
defaults to 1 */
int server_prepare; /* do we want to use PQexecPrepared? 0=no
1=yes 2=smart. Can be changed by user */
+ int switch_prepared; /* how many executes until we switch to
PQexecPrepared */
int async_status; /* 0=no async 1=async started -1=async has
been cancelled */
imp_sth_t *async_sth; /* current async statement handle */
@@ -75,15 +76,17 @@ typedef struct ph_st ph_t;
struct imp_sth_st {
dbih_stc_t com; /* MUST be first element in structure */
- int server_prepare; /* inherited from dbh. 3 states: 0=no 1=yes
2=smart */
- int placeholder_type; /* which style is being used 1=? 2=$1 3=:foo */
- int numsegs; /* how many segments this statement has */
- int numphs; /* how many placeholders this statement has */
- int numbound; /* how many placeholders were explicitly bound
by the client, not us */
- int cur_tuple; /* current tuple being fetched */
- int rows; /* number of affected rows */
- int async_flag; /* async? 0=no 1=async 2=cancel 4=wait */
- int async_status; /* 0=no async 1=async started -1=async has
been cancelled */
+ int server_prepare; /* inherited from dbh. 3 states: 0=no 1=yes
2=smart */
+ int switch_prepared; /* inherited from dbh */
+ int number_iterations; /* how many times has the statement been
executed? Used by switch_prepared */
+ int placeholder_type; /* which style is being used 1=? 2=$1 3=:foo
*/
+ int numsegs; /* how many segments this statement has */
+ int numphs; /* how many placeholders this statement has */
+ int numbound; /* how many placeholders were explicitly
bound by the client, not us */
+ int cur_tuple; /* current tuple being fetched */
+ int rows; /* number of affected rows */
+ int async_flag; /* async? 0=no 1=async 2=cancel 4=wait */
+ int async_status; /* 0=no async 1=async started -1=async has
been cancelled */
STRLEN totalsize; /* total string length of the statement (with
no placeholders)*/
--
1.8.4