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]