From 75e2b81732d1683323b0e15a7622d14e2ca71122 Mon Sep 17 00:00:00 2001 From: Heikki Linnakangas Date: Wed, 24 Apr 2013 18:35:54 +0300 Subject: [PATCH] Fix bug with VARCHAR(5) parameter and UseServerSidePrepare=0 If you passed a VARCHAR parameter with column_size 5 to SQLPrepare, and you had UseServerSideprepare=0 and BoolsAsChar=1, the code describes the parameters before running the query, so that it can check if the parameter is a boolean. That produced a bogus extra empty result set to the caller in subsequent SQLExecute(). This fixes the two regression test failures. Patch by Hiroshi Inoue, with minor copy-editing by me. --- columninfo.c | 1 + columninfo.h | 2 ++ docs/release.html | 3 +++ execute.c | 6 ++--- pgtypes.c | 4 ++-- qresult.c | 42 ++++++++++++++++++++++++++------- qresult.h | 1 + statement.c | 60 +++++++++++++++++++++++++++++++++++++---------- 8 files changed, 92 insertions(+), 27 deletions(-) diff --git a/columninfo.c b/columninfo.c index db45b48..fed75e9 100644 --- a/columninfo.c +++ b/columninfo.c @@ -30,6 +30,7 @@ CI_Constructor() if (rv) { + rv->refcount = 0; rv->num_fields = 0; rv->coli_array = NULL; } diff --git a/columninfo.h b/columninfo.h index 9ac110f..72c6e13 100644 --- a/columninfo.h +++ b/columninfo.h @@ -13,6 +13,8 @@ struct ColumnInfoClass_ { + UInt4 refcount; /* reference count. A ColumnInfo can be shared by + * several qresults. */ Int2 num_fields; struct srvr_info { diff --git a/docs/release.html b/docs/release.html index 87251e9..9c5aa16 100644 --- a/docs/release.html +++ b/docs/release.html @@ -28,6 +28,9 @@ using the patch provided by Michael Kocherov.
This was caused by unintentional multiple evaluation of macro arguments.
8.) Move psqlodbc website's main page, FAQ, and howto pages to a separate git repository. They are no longer included in psqldbc release tarballs.
+9.) Fix bug with binding a 5-bytes long string as VARCHAR parameter, with + UseServerSidePrepare=0 and BoolsAsChar=1. That combination produced an + extra empty result set on execution.

psqlODBC 09.01.0200

diff --git a/execute.c b/execute.c index c6c863f..ac99367 100644 --- a/execute.c +++ b/execute.c @@ -529,10 +529,8 @@ mylog("about to begin SC_execute\n"); if (kres = res->next, kres) { - if (kres->fields) - CI_Destructor(kres->fields); - kres->fields = res->fields; - res->fields = NULL; + QR_set_fields(kres, QR_get_fields(res)); + QR_set_fields(res, NULL); kres->num_fields = res->num_fields; res->next = NULL; SC_set_Result(stmt, kres); diff --git a/pgtypes.c b/pgtypes.c index b171c75..9970d17 100644 --- a/pgtypes.c +++ b/pgtypes.c @@ -1582,7 +1582,7 @@ getNumericDecimalDigits(const StatementClass *stmt, OID type, int col) return (atttypmod & 0xffff); if (stmt->catalog_result) { - flds = result->fields; + flds = QR_get_fields(result); if (flds) { int fsize = CI_get_fieldsize(flds, col); @@ -1626,7 +1626,7 @@ getNumericColumnSize(const StatementClass *stmt, OID type, int col) return (atttypmod >> 16) & 0xffff; if (stmt->catalog_result) { - flds = result->fields; + flds = QR_get_fields(result); if (flds) { int fsize = CI_get_fieldsize(flds, col); diff --git a/qresult.c b/qresult.c index 287e554..a30732c 100644 --- a/qresult.c +++ b/qresult.c @@ -38,7 +38,7 @@ QR_set_num_fields(QResultClass *self, int new_num_fields) if (!self) return; mylog("in QR_set_num_fields\n"); - CI_set_num_fields(self->fields, new_num_fields, allocrelatt); + CI_set_num_fields(QR_get_fields(self), new_num_fields, allocrelatt); mylog("exit QR_set_num_fields\n"); } @@ -133,6 +133,29 @@ QR_inc_rowstart_in_cache(QResultClass *self, SQLLEN base_inc) self->key_base = self->base; } +void +QR_set_fields(QResultClass *self, ColumnInfoClass *fields) +{ + ColumnInfoClass *curfields = QR_get_fields(self); + + if (curfields == fields) + return; + + /* + * Unlink the old columninfo from this result set, freeing it if this + * was the last reference. + */ + if (NULL != curfields) + { + if (curfields->refcount > 1) + curfields->refcount--; + else + CI_Destructor(curfields); + } + self->fields = fields; + if (NULL != fields) + fields->refcount++; +} /* * CLASS QResult @@ -147,15 +170,19 @@ QR_Constructor() if (rv != NULL) { + ColumnInfoClass *fields; + rv->rstatus = PORES_EMPTY_QUERY; rv->pstatus = 0; /* construct the column info */ - if (!(rv->fields = CI_Constructor())) + rv->fields = NULL; + if (fields = CI_Constructor(), NULL == fields) { free(rv); return NULL; } + QR_set_fields(rv, fields); rv->backend_tuples = NULL; rv->sqlstate[0] = '\0'; rv->message = NULL; @@ -249,11 +276,8 @@ QR_close_result(QResultClass *self, BOOL destroy) QR_set_cursor(self, NULL); /* Free up column info */ - if (destroy && self->fields) - { - CI_Destructor(self->fields); - self->fields = NULL; - } + if (destroy) + QR_set_fields(self, NULL); /* Free command info (this is from strdup()) */ if (self->command) @@ -572,7 +596,7 @@ QR_fetch_tuples(QResultClass *self, ConnectionClass *conn, const char *cursor, i if (CI_read_fields(QR_get_fields(self), QR_get_conn(self))) { QR_set_rstatus(self, PORES_FIELDS_OK); - self->num_fields = CI_get_num_fields(self->fields); + self->num_fields = CI_get_num_fields(QR_get_fields(self)); if (QR_haskeyset(self)) self->num_fields -= self->num_key_fields; } @@ -1567,7 +1591,7 @@ else bmp = bitmap[bitmap_pos]; } - flds = self->fields; + flds = QR_get_fields(self); for (field_lf = 0; field_lf < ci_num_fields; field_lf++) { diff --git a/qresult.h b/qresult.h index 5c0a39a..55b8ed8 100644 --- a/qresult.h +++ b/qresult.h @@ -235,6 +235,7 @@ void QR_set_notice(QResultClass *self, const char *msg); void QR_add_notice(QResultClass *self, const char *msg); void QR_set_num_fields(QResultClass *self, int new_num_fields); /* catalog functions' result only */ +void QR_set_fields(QResultClass *self, ColumnInfoClass *); void QR_set_num_cached_rows(QResultClass *, SQLLEN); void QR_set_rowstart_in_cache(QResultClass *, SQLLEN); diff --git a/statement.c b/statement.c index 7c0878e..dcfa905 100644 --- a/statement.c +++ b/statement.c @@ -1872,7 +1872,8 @@ SC_execute(StatementClass *self) { QResultClass *curres = SC_get_Curres(self); - if (NULL != curres) + if (NULL != curres && + curres->dataFilled) useCursor = (NULL != QR_get_cursor(curres)); } /* issue BEGIN ? */ @@ -1950,13 +1951,20 @@ SC_execute(StatementClass *self) #endif /* BYPASS_ONESHOT_PLAN_EXECUTION */ case NAMED_PARSE_REQUEST: use_extended_protocol = TRUE; + break; } } - if (!use_extended_protocol) + if (use_extended_protocol) + break; + /* fall through */ + case ONCE_DESCRIBED: + SC_forget_unnamed(self); { - SC_forget_unnamed(self); - SC_set_Result(self, NULL); /* discard the parsed information */ + QResultClass *pres = SC_get_Result(self); + if (NULL != pres && NULL == QR_get_command(pres)) + SC_set_Result(self, NULL); /* discard the parsed information */ } + break; } if (use_extended_protocol) { @@ -2140,10 +2148,8 @@ inolog("!!%p->SC_is_concat_pre=%x res=%p\n", self, self->miscinfo, res); { if (tres = res->next, tres) { - if (tres->fields) - CI_Destructor(tres->fields); - tres->fields = res->fields; - res->fields = NULL; + QR_set_fields(tres, QR_get_fields(res)); + QR_set_fields(res, NULL); tres->num_fields = res->num_fields; res->next = NULL; QR_Destructor(res); @@ -2413,7 +2419,7 @@ SC_log_error(const char *func, const char *desc, const StatementClass *self) if (res) { - qlog(" fields=%p, backend_tuples=%p, tupleField=%d, conn=%p\n", res->fields, res->backend_tuples, res->tupleField, res->conn); + qlog(" fields=%p, backend_tuples=%p, tupleField=%d, conn=%p\n", QR_get_fields(res), res->backend_tuples, res->tupleField, res->conn); qlog(" fetch_count=%d, num_total_rows=%d, num_fields=%d, cursor='%s'\n", res->fetch_number, QR_get_num_total_tuples(res), res->num_fields, nullcheck(QR_get_cursor(res))); qlog(" message='%s', command='%s', notice='%s'\n", nullcheck(QR_get_message(res)), nullcheck(res->command), nullcheck(res->notice)); qlog(" status=%d, inTuples=%d\n", QR_get_rstatus(res), QR_is_fetching_tuples(res)); @@ -2458,6 +2464,35 @@ RequestStart(StatementClass *stmt, ConnectionClass *conn, const char *func) return ret; } +/* + * Copies the column information from the first result set of 'self' to 'res'. + */ +static BOOL +ReflectColumnsInfo(StatementClass *self, QResultClass *res) +{ + QResultClass *pres; + + if (NOT_YET_PREPARED == self->prepared) + return FALSE; + if (res->num_fields > 0) + return FALSE; + pres = SC_get_Result(self); + if (pres != res && + pres->num_fields > 0) + { + QR_set_fields(res, QR_get_fields(pres)); + QR_set_conn(res, SC_get_conn(self)); + if (QR_haskeyset(pres)) + QR_set_haskeyset(res); + if (QR_is_withhold(pres)) + QR_set_withhold(res); + res->num_fields = pres->num_fields; + + return TRUE; + } + return FALSE; +} + BOOL SendBindRequest(StatementClass *stmt, const char *plan_name) { @@ -2628,7 +2663,7 @@ inolog("num_params=%d info=%d\n", stmt->num_params, num_p); int cidx; QR_set_rstatus(res, PORES_FIELDS_OK); - res->num_fields = CI_get_num_fields(res->fields); + res->num_fields = CI_get_num_fields(QR_get_fields(res)); if (QR_haskeyset(res)) res->num_fields -= res->num_key_fields; num_io_params = CountParameters(stmt, NULL, &dummy1, &dummy2); @@ -2645,8 +2680,8 @@ inolog("num_params=%d info=%d\n", stmt->num_params, num_p); if (SQL_PARAM_OUTPUT == paramType || SQL_PARAM_INPUT_OUTPUT == paramType) { -inolog("!![%d].PGType %u->%u\n", i, PIC_get_pgtype(ipdopts->parameters[i]), CI_get_oid(res->fields, cidx)); - PIC_set_pgtype(ipdopts->parameters[i], CI_get_oid(res->fields, cidx)); +inolog("!![%d].PGType %u->%u\n", i, PIC_get_pgtype(ipdopts->parameters[i]), CI_get_oid(QR_get_fields(res), cidx)); + PIC_set_pgtype(ipdopts->parameters[i], CI_get_oid(QR_get_fields(res), cidx)); cidx++; } } @@ -2669,6 +2704,7 @@ inolog("!![%d].PGType %u->%u\n", i, PIC_get_pgtype(ipdopts->parameters[i]), CI_g break; case 'B': /* Binary data */ case 'D': /* ASCII data */ + ReflectColumnsInfo(stmt, res); if (!QR_get_tupledata(res, id == 'B')) { loopend = TRUE; -- 2.39.5