pgpool2.git / summary / log / commit / refs
commit ac1d371a6c70b567b45157bd14100b34ee577fd5
Author: Tatsuo Ishii <ishii at sraoss.co.jp>
Date: Tue Jan 26 09:53:28 2010 +0000
Teach do_query to support V2 protocol. This will solve the problem
with pgpool-II 2.3 user who are experiencing error while using V2
dirvers (for example unixODBC). See [Pgpool-general] Bug report
pgpool-II-2.3.1 plus ODBC submitted on Tue, 12 Jan 2010 12:46:35 -0500
for this kind of use case.
Patch contributed by Toshihiro Kitagawa.
pool.h | 4 +-
pool_lobj.c | 2 +-
pool_process_query.c | 238 ++++++++++++++++++++++++++++++++++++++------------
pool_relcache.c | 2 +-
pool_timestamp.c | 2 +-
test/timestamp/main.c | 2 +-
6 files changed, 186 insertions(+), 64 deletions(-)
diff --git a/pool.h b/pool.h
index ee3b57398..39ba503fe 100644
--- a/pool.h
+++ b/pool.h
@@ -620,7 +620,7 @@ extern POOL_STATUS OneNode_do_command(POOL_CONNECTION *frontend, POOL_CONNECTION
extern POOL_CONNECTION_POOL_SLOT *make_persistent_db_connection(
char *hostname, int port, char *dbname, char *user, char *password);
-extern POOL_STATUS do_query(POOL_CONNECTION *backend, char *query, POOL_SELECT_RESULT **result);
+extern POOL_STATUS do_query(POOL_CONNECTION *backend, char *query, POOL_SELECT_RESULT **result, int major);
/* define pool_system.c */
extern POOL_CONNECTION_POOL_SLOT *pool_system_db_connection(void);
@@ -671,7 +671,7 @@ void per_node_statement_log(POOL_CONNECTION_POOL *backend, int node_id, char *qu
POOL_STATUS pool_extract_error_message(POOL_CONNECTION *backend, int major, bool unread, char **message);
POOL_STATUS do_command(POOL_CONNECTION *frontend, POOL_CONNECTION *backend,
char *query, int protoMajor, int pid, int key, int no_ready_for_query);
-POOL_STATUS do_query(POOL_CONNECTION *backend, char *query, POOL_SELECT_RESULT **result);
+POOL_STATUS do_query(POOL_CONNECTION *backend, char *query, POOL_SELECT_RESULT **result, int major);
void free_select_result(POOL_SELECT_RESULT *result);
/* pool_relcache.c */
diff --git a/pool_lobj.c b/pool_lobj.c
index ed9340668..ab12b0154 100644
--- a/pool_lobj.c
+++ b/pool_lobj.c
@@ -177,7 +177,7 @@ char *pool_rewrite_lo_creat(char kind, char *packet, int packet_len,
/* get max lobj id */
per_node_statement_log(backend, MASTER_NODE_ID, GET_MAX_LOBJ_KEY);
- status = do_query(MASTER(backend), GET_MAX_LOBJ_KEY, &result);
+ status = do_query(MASTER(backend), GET_MAX_LOBJ_KEY, &result, MAJOR(backend));
if (status == POOL_END)
{
pool_error("pool_rewrite_lo_creat: do_query failed");
diff --git a/pool_process_query.c b/pool_process_query.c
index ba108b209..90dee408f 100644
--- a/pool_process_query.c
+++ b/pool_process_query.c
@@ -2759,18 +2759,18 @@ void free_select_result(POOL_SELECT_RESULT *result)
}
/*
- * Send a SELECT to one DB node. This function works for V3 only.
+ * Send a SELECT to one DB node.
*/
-POOL_STATUS do_query(POOL_CONNECTION *backend, char *query, POOL_SELECT_RESULT **result)
+POOL_STATUS do_query(POOL_CONNECTION *backend, char *query, POOL_SELECT_RESULT **result, int major)
{
#define DO_QUERY_ALLOC_NUM 1024 /* memory allocation unit for POOL_SELECT_RESULT */
int i;
int len;
char kind;
- char *packet;
- char *p;
- short num_fields;
+ char *packet = NULL;
+ char *p = NULL;
+ short num_fields = 0;
int num_data;
int intval;
short shortval;
@@ -2779,6 +2779,10 @@ POOL_STATUS do_query(POOL_CONNECTION *backend, char *query, POOL_SELECT_RESULT *
RowDesc *rowdesc;
AttrInfo *attrinfo;
+ int nbytes;
+ static char nullmap[8192];
+ unsigned char mask = 0;
+
res = malloc(sizeof(*res));
if (!res)
{
@@ -2813,7 +2817,7 @@ POOL_STATUS do_query(POOL_CONNECTION *backend, char *query, POOL_SELECT_RESULT *
}
/* send a query to the backend */
- if (send_simplequery_message(backend, strlen(query) + 1, query, PROTO_MAJOR_V3) != POOL_CONTINUE)
+ if (send_simplequery_message(backend, strlen(query) + 1, query, major) != POOL_CONTINUE)
{
return POOL_END;
}
@@ -2836,17 +2840,32 @@ POOL_STATUS do_query(POOL_CONNECTION *backend, char *query, POOL_SELECT_RESULT *
pool_debug("do_query: kind: %c", kind);
- if (pool_read(backend, &len, sizeof(len)) < 0)
+ if (major == PROTO_MAJOR_V3)
{
- pool_error("do_query: error while reading message length");
- return POOL_END;
+ if (pool_read(backend, &len, sizeof(len)) < 0)
+ {
+ pool_error("do_query: error while reading message length");
+ return POOL_END;
+ }
+ len = ntohl(len) - 4;
+ packet = pool_read2(backend, len);
+ if (packet == NULL)
+ {
+ pool_error("do_query: error while reading rest of message");
+ return POOL_END;
+ }
}
- len = ntohl(len) - 4;
- packet = pool_read2(backend, len);
- if (packet == NULL)
+ else
{
- pool_error("do_query: error while reading rest of message");
- return POOL_END;
+ mask = 0;
+ if (kind == 'C' || kind == 'E' || kind == 'N' || kind == 'P')
+ {
+ if (pool_read_string(backend, &len, 0) == NULL)
+ {
+ pool_error("do_query: error while reading string of message type %c", kind);
+ return POOL_END;
+ }
+ }
}
switch (kind)
@@ -2856,8 +2875,20 @@ POOL_STATUS do_query(POOL_CONNECTION *backend, char *query, POOL_SELECT_RESULT *
break;
case 'T': /* Row Description */
- p = packet;
- memcpy(&shortval, p, sizeof(short));
+ if (major == PROTO_MAJOR_V3)
+ {
+ p = packet;
+ memcpy(&shortval, p, sizeof(short));
+ p += sizeof(num_fields);
+ }
+ else
+ {
+ if (pool_read(backend, &shortval, sizeof(short)) < 0)
+ {
+ pool_error("do_query: error while reading number of fields");
+ return POOL_END;
+ }
+ }
num_fields = ntohs(shortval); /* number of fields */
pool_debug("num_fileds: %d", num_fields);
@@ -2872,36 +2903,66 @@ POOL_STATUS do_query(POOL_CONNECTION *backend, char *query, POOL_SELECT_RESULT *
}
rowdesc->attrinfo = attrinfo;
- p += sizeof(num_fields);
-
/* extract attribute info */
for (i = 0;i<num_fields;i++)
{
- len = strlen(p) + 1;
- attrinfo->attrname = malloc(len);
- if (!attrinfo->attrname)
+ if (major == PROTO_MAJOR_V3)
+ {
+ len = strlen(p) + 1;
+ attrinfo->attrname = malloc(len);
+ if (!attrinfo->attrname)
+ {
+ pool_error("do_query: malloc failed");
+ return POOL_ERROR;
+ }
+ memcpy(attrinfo->attrname, p, len);
+ p += len;
+ memcpy(&intval, p, sizeof(int));
+ attrinfo->oid = htonl(intval);
+ p += sizeof(int);
+ memcpy(&shortval, p, sizeof(short));
+ attrinfo->attrnumber = htons(shortval);
+ p += sizeof(short);
+ memcpy(&intval, p, sizeof(int));
+ attrinfo->typeoid = htonl(intval);
+ p += sizeof(int);
+ memcpy(&shortval, p, sizeof(short));
+ attrinfo->size = htons(shortval);
+ p += sizeof(short);
+ memcpy(&intval, p, sizeof(int));
+ attrinfo->mod = htonl(intval);
+ p += sizeof(int);
+ p += sizeof(short); /* skip format code since we use "text" anyway */
+ }
+ else
{
- pool_error("do_query: malloc failed");
- return POOL_ERROR;
+ p = pool_read_string(backend, &len, 0);
+ attrinfo->attrname = malloc(len);
+ if (!attrinfo->attrname)
+ {
+ pool_error("do_query: malloc failed");
+ return POOL_ERROR;
+ }
+ memcpy(attrinfo->attrname, p, len);
+ if (pool_read(backend, &intval, sizeof(int)) < 0)
+ {
+ pool_error("do_query: error while reading type oid");
+ return POOL_END;
+ }
+ attrinfo->typeoid = ntohl(intval);
+ if (pool_read(backend, &shortval, sizeof(short)) < 0)
+ {
+ pool_error("do_query: error while reading type size");
+ return POOL_END;
+ }
+ attrinfo->size = ntohs(shortval);
+ if (pool_read(backend, &intval, sizeof(int)) < 0)
+ {
+ pool_error("do_query: error while reading type modifier");
+ return POOL_END;
+ }
+ attrinfo->mod = ntohl(intval);
}
- memcpy(attrinfo->attrname, p, len);
- p += len;
- memcpy(&intval, p, sizeof(int));
- attrinfo->oid = htonl(intval);
- p += sizeof(int);
- memcpy(&shortval, p, sizeof(short));
- attrinfo->attrnumber = htons(shortval);
- p += sizeof(short);
- memcpy(&intval, p, sizeof(int));
- attrinfo->typeoid = htonl(intval);
- p += sizeof(int);
- memcpy(&shortval, p, sizeof(short));
- attrinfo->size = htons(shortval);
- p += sizeof(short);
- memcpy(&intval, p, sizeof(int));
- attrinfo->mod = htonl(intval);
- p += sizeof(int);
- p += sizeof(short); /* skip format code since we use "text" anyway */
attrinfo++;
}
@@ -2909,36 +2970,97 @@ POOL_STATUS do_query(POOL_CONNECTION *backend, char *query, POOL_SELECT_RESULT *
break;
case 'D': /* data row */
- p = packet;
-
- memcpy(&shortval, p, sizeof(short));
- num_fields = htons(shortval);
- p += sizeof(short);
+ if (major == PROTO_MAJOR_V3)
+ {
+ p = packet;
+ memcpy(&shortval, p, sizeof(short));
+ num_fields = htons(shortval);
+ p += sizeof(short);
+ }
if (num_fields > 0)
{
+ if (major == PROTO_MAJOR_V2)
+ {
+ nbytes = (num_fields + 7)/8;
+
+ if (nbytes <= 0)
+ {
+ pool_error("do_query: error while reading null bitmap");
+ return POOL_END;
+ }
+
+ pool_read(backend, nullmap, nbytes);
+ }
+
res->numrows++;
for (i=0;i<num_fields;i++)
{
- memcpy(&intval, p, sizeof(int));
- len = htonl(intval);
- p += sizeof(int);
+ if (major == PROTO_MAJOR_V3)
+ {
+ memcpy(&intval, p, sizeof(int));
+ len = htonl(intval);
+ p += sizeof(int);
- res->nullflags[num_data] = len;
+ res->nullflags[num_data] = len;
- if (len > 0) /* NOT NULL? */
+ if (len > 0) /* NOT NULL? */
+ {
+ res->data[num_data] = malloc(len + 1);
+ if (!res->data[num_data])
+ {
+ pool_error("do_query: malloc failed");
+ return POOL_ERROR;
+ }
+ memcpy(res->data[num_data], p, len);
+ *(res->data[num_data] + len) = '\0';
+
+ p += len;
+ }
+ }
+ else
{
- res->data[num_data] = malloc(len + 1);
- if (!res->data[num_data])
+ if (mask == 0)
+ mask = 0x80;
+
+ /* NOT NULL? */
+ if (mask & nullmap[i/8])
{
- pool_error("do_query: malloc failed");
- return POOL_ERROR;
+ /* field size */
+ if (pool_read(backend, &len, sizeof(int)) < 0)
+ {
+ pool_error("do_query: error while reading field size");
+ return POOL_END;
+ }
+ len = ntohl(len) - 4;
+
+ res->nullflags[num_data] = len;
+
+ if (len > 0)
+ {
+ p = pool_read2(backend, len);
+ res->data[num_data] = malloc(len + 1);
+ if (!res->data[num_data])
+ {
+ pool_error("do_query: malloc failed");
+ return POOL_ERROR;
+ }
+ memcpy(res->data[num_data], p, len);
+ *(res->data[num_data] + len) = '\0';
+ if (res->data[num_data] == NULL)
+ {
+ pool_error("do_query: error while reading field data");
+ return POOL_END;
+ }
+ }
+ }
+ else
+ {
+ res->nullflags[num_data] = -1;
}
- memcpy(res->data[num_data], p, len);
- *(res->data[num_data] + len) = '\0';
- p += len;
+ mask >>= 1;
}
num_data++;
diff --git a/pool_relcache.c b/pool_relcache.c
index c521e5ac0..bdf089032 100644
--- a/pool_relcache.c
+++ b/pool_relcache.c
@@ -142,7 +142,7 @@ void *pool_search_relcache(POOL_RELCACHE *relcache, POOL_CONNECTION_POOL *backen
per_node_statement_log(backend, MASTER_NODE_ID, query);
- if (do_query(MASTER(backend), query, &res) != POOL_CONTINUE)
+ if (do_query(MASTER(backend), query, &res, MAJOR(backend)) != POOL_CONTINUE)
{
pool_error("pool_search_relcache: do_query failed");
if (res)
diff --git a/pool_timestamp.c b/pool_timestamp.c
index c68970aa4..5557efa09 100644
--- a/pool_timestamp.c
+++ b/pool_timestamp.c
@@ -265,7 +265,7 @@ get_current_timestamp(POOL_CONNECTION_POOL *backend)
POOL_STATUS status;
static char timestamp[32];
- status = do_query(MASTER(backend), "SELECT now()", &res);
+ status = do_query(MASTER(backend), "SELECT now()", &res, MAJOR(backend));
if (status != POOL_CONTINUE)
{
pool_error("get_current_timestamp: do_query faild");
diff --git a/test/timestamp/main.c b/test/timestamp/main.c
index d784e5e71..eb03619d1 100644
--- a/test/timestamp/main.c
+++ b/test/timestamp/main.c
@@ -56,7 +56,7 @@ pool_search_relcache(POOL_RELCACHE *relcache, POOL_CONNECTION_POOL *backend, cha
}
POOL_STATUS
-do_query(POOL_CONNECTION *backend, char *query, POOL_SELECT_RESULT **result) {
+do_query(POOL_CONNECTION *backend, char *query, POOL_SELECT_RESULT **result, int major) {
static POOL_SELECT_RESULT res;
static char *data[1] = {
"2009-01-01 23:59:59.123456+09"
[parent: f3eb92d20308]