pg: Pipeline prepare + describeprepared
This commit is contained in:
parent
7b76d94719
commit
b6517cf05a
2 changed files with 43 additions and 14 deletions
10
c/libpq.h
10
c/libpq.h
|
|
@ -40,11 +40,12 @@ typedef enum { PQTRANS_IDLE, PQTRANS_ACTIVE, PQTRANS_INTRANS, PQTRANS_INERROR, P
|
|||
X(PQclosePrepared, PGresult *, PGconn *, const char *) \
|
||||
X(PQcmdTuples, char *, PGresult *) \
|
||||
X(PQconnectdb, PGconn *, const char *) \
|
||||
X(PQdescribePrepared, PGresult *, PGconn *, const char *) \
|
||||
X(PQenterPipelineMode, int, PGconn *) \
|
||||
X(PQerrorMessage, char *, const PGconn *) \
|
||||
X(PQexec, PGresult *, PGconn *, const char *) \
|
||||
X(PQexecParams, PGresult *, PGconn *, const char *, int, const Oid *, const char * const *, const int *, const int *, int) \
|
||||
X(PQexecPrepared, PGresult *, PGconn *, const char *, int, const char * const *, const int *, const int *, int) \
|
||||
X(PQexitPipelineMode, int, PGconn *conn) \
|
||||
X(PQfinish, void, PGconn *) \
|
||||
X(PQfmod, int, const PGresult *, int) \
|
||||
X(PQfname, char *, const PGresult *, int) \
|
||||
|
|
@ -52,18 +53,21 @@ typedef enum { PQTRANS_IDLE, PQTRANS_ACTIVE, PQTRANS_INTRANS, PQTRANS_INERROR, P
|
|||
X(PQftype, Oid, const PGresult *, int) \
|
||||
X(PQgetisnull, int, const PGresult *, int, int) \
|
||||
X(PQgetlength, int, const PGresult *, int, int) \
|
||||
X(PQgetResult, PGresult *, PGconn *) \
|
||||
X(PQgetvalue, char *, const PGresult *, int, int) \
|
||||
X(PQlibVersion, int, void) \
|
||||
X(PQnfields, int, const PGresult *) \
|
||||
X(PQnparams, int, const PGresult *) \
|
||||
X(PQntuples, int, const PGresult *) \
|
||||
X(PQparamtype, Oid, const PGresult *, int) \
|
||||
X(PQprepare, PGresult *, PGconn *, const char *, const char *, int, const Oid *) \
|
||||
X(PQpipelineSync, int, PGconn *) \
|
||||
X(PQresStatus, char *, ExecStatusType) \
|
||||
X(PQresultErrorField, char *, const PGresult *, int) \
|
||||
X(PQresultErrorMessage, char *, const PGresult *res) \
|
||||
X(PQresultErrorMessage, char *, const PGresult *) \
|
||||
X(PQresultStatus, ExecStatusType, const PGresult *) \
|
||||
X(PQresultVerboseErrorMessage, char *, const PGresult *, PGVerbosity, PGContextVisibility) \
|
||||
X(PQsendDescribePrepared, int, PGconn *, const char *) \
|
||||
X(PQsendPrepare, int, PGconn *, const char *, const char *, int, const Oid *) \
|
||||
X(PQserverVersion, int, const PGconn *) \
|
||||
X(PQstatus, ConnStatusType, const PGconn *) \
|
||||
X(PQtrace, void, PGconn *, FILE *) \
|
||||
|
|
|
|||
47
c/pgconn.c
47
c/pgconn.c
|
|
@ -261,6 +261,9 @@ static void fupg_txn_destroy(pTHX_ fupg_txn *t) {
|
|||
/* XXX: It feels a bit wasteful to load *all* types; even on an empty database
|
||||
* that's ~55k of data, but it's easier and (potentially) faster than fetching
|
||||
* each type seperately as we encounter them.
|
||||
* Perhaps an easier optimization is to filter out all table-based composites
|
||||
* and their array types by default, I've never seen anyone use those types for
|
||||
* I/O and that would shrink the data by nearly a factor 5.
|
||||
*/
|
||||
static void fupg_refresh_types(pTHX_ fupg_conn *c) {
|
||||
safefree(c->types);
|
||||
|
|
@ -354,19 +357,41 @@ static void fupg_st_prepare(pTHX_ fupg_st *st) {
|
|||
|
||||
snprintf(st->name, sizeof(st->name), "fupg%"UVuf, ++st->conn->prep_counter);
|
||||
|
||||
/* TODO: Pipeline these two commands, no need for two round-trips with the server */
|
||||
PGresult *r = PQprepare(st->conn->conn, st->name, st->query, 0, NULL);
|
||||
if (!r) fupg_conn_croak(st->conn , "prepare");
|
||||
if (PQresultStatus(r) != PGRES_COMMAND_OK)
|
||||
fupg_result_croak(r, "prepare", st->query);
|
||||
PQclear(r);
|
||||
/* Send prepare + describe in a pipeline to avoid a double round-trip with the server */
|
||||
PQenterPipelineMode(st->conn->conn);
|
||||
PQsendPrepare(st->conn->conn, st->name, st->query, 0, NULL);
|
||||
PQsendDescribePrepared(st->conn->conn, st->name);
|
||||
PQpipelineSync(st->conn->conn);
|
||||
PGresult *prep = PQgetResult(st->conn->conn); PQgetResult(st->conn->conn); /* NULL */
|
||||
PGresult *desc = PQgetResult(st->conn->conn); PQgetResult(st->conn->conn); /* NULL */
|
||||
PGresult *sync = PQgetResult(st->conn->conn);
|
||||
PQexitPipelineMode(st->conn->conn);
|
||||
|
||||
if (!prep) {
|
||||
PQclear(desc); PQclear(sync);
|
||||
fupg_conn_croak(st->conn , "prepare");
|
||||
}
|
||||
if (PQresultStatus(prep) != PGRES_COMMAND_OK) {
|
||||
PQclear(desc); PQclear(sync);
|
||||
fupg_result_croak(prep, "prepare", st->query);
|
||||
}
|
||||
PQclear(prep);
|
||||
st->prepared = 1;
|
||||
|
||||
r = PQdescribePrepared(st->conn->conn, st->name);
|
||||
if (!r) fupg_conn_croak(st->conn , "prepare");
|
||||
if (PQresultStatus(r) != PGRES_COMMAND_OK)
|
||||
fupg_result_croak(r, "prepare", st->query);
|
||||
st->describe = r;
|
||||
if (!desc) {
|
||||
PQclear(sync);
|
||||
fupg_conn_croak(st->conn , "prepare");
|
||||
}
|
||||
if (PQresultStatus(desc) != PGRES_COMMAND_OK) {
|
||||
PQclear(sync);
|
||||
fupg_result_croak(desc, "prepare", st->query);
|
||||
}
|
||||
st->describe = desc;
|
||||
|
||||
if (!sync) fupg_conn_croak(st->conn , "prepare");
|
||||
if (PQresultStatus(sync) != PGRES_PIPELINE_SYNC)
|
||||
fupg_result_croak(sync, "prepare", st->query);
|
||||
PQclear(sync);
|
||||
}
|
||||
|
||||
static SV *fupg_st_params(pTHX_ fupg_st *st) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue