On Friday 2014-05-02 00:55, Jan Engelhardt wrote:
>On Friday 2014-05-02 00:15, Markus Hoenicka wrote:
>>Am 2014-05-01 18:50, schrieb Jan Engelhardt:
>>> I have identified another bug and prepared a patch for
>>> dbd_mysql/dbd_msql. The purpose of result->currowidx was not totally
>>> clear-cut, so I am posting this patch for potential comments.
>>
>>[...] was designed to avoid an expensive call to mysql_data_seek()
>>in *every single* iteration of stepping through a result set. There
>>are data in the mailing list archives which show that MySQL is
>>slowed down abysmally [...]. It would be great if we could find a
>>way to synchronize result->currowidx with the DBD row pointer in a
>>cheaper way.

Indeed, I found that libmysql uses a singly-linked list. That is truly
abysmal, already from a design point.
I have this new patch, for libdbi this time. Looks better?

====
dbi: resolve bogus seeking into dbd

I have a query result that, when iteratively seeked with
dbi_result_next_row() and read with dbi_result_get_string(), yields
these 15 values (1-based row indices shown in parentheses):

        B-W(1) BAY(2) BER(3) BRE(4) HAM(5) HES(6) M-V(7) NDS(8)
        NRW(9) RLP(10) SAR(11) SAC(12) S-A(13) S-H(14) THU(15)

Now, when using dbi_result_seek_row() to seek to arbitrary rows
(given in parentheses), dbi_result_get_string() can return incorrect
values. In particular, I have observed:

        B-W(1) S-H(14) B-W(1) THU(2)

What happens:

* row 1 is not already present, dbd_goto_row(1) is executed,
  the row data retrieved, and result->currowidx set to 1
* row 14 is not already present, a goto_row(14) is executed,
  the row data retrieved, and result->currowidx set to 14
* row 1 is already present, result->currowidx set to 1
* row 2 is not already present, dbd_goto_row(2) is NOT executed,
  because of rowidx == currowidx + 1 [2 == 2].
  So the next mysql row fetched is row 15, rather than 2.

result->currowidx is a high-level pointer that always gets updated.
But we do need to track the pointer that the DBD has, as well.

After applying this patch, the seeked results correctly yield:

        B-W(1) S-H(14) B-W(1) BAY(2)
---
 include/dbi/dbi-dev.h | 7 +++++++
 src/dbd_helper.c      | 1 +
 src/dbi_result.c      | 5 ++---
 3 files changed, 10 insertions(+), 3 deletions(-)

diff --git a/include/dbi/dbi-dev.h b/include/dbi/dbi-dev.h
index 0e21005..175cd7e 100644
--- a/include/dbi/dbi-dev.h
+++ b/include/dbi/dbi-dev.h
@@ -71,7 +71,14 @@ typedef struct dbi_result_s {
 
        enum { NOTHING_RETURNED, ROWS_RETURNED } result_state;
        dbi_row_t **rows; /* array of filled rows, elements set to NULL if not 
fetched yet */
+
+       /* Current row pointer index (1-based) for DBI. */
        unsigned long long currowidx;
+       /*
+        * Current row pointer index (1-based) that is synchronized to what
+        * the current pointer inside the DBD.
+        */
+       unsigned long long dbd_currowidx;
 } dbi_result_t;
 
 typedef struct _field_binding_s {
diff --git a/src/dbd_helper.c b/src/dbd_helper.c
index 0c03408..d0a9360 100644
--- a/src/dbd_helper.c
+++ b/src/dbd_helper.c
@@ -78,6 +78,7 @@ dbi_result_t *_dbd_result_create(dbi_conn_t *conn, void 
*handle, unsigned long l
        result->field_types = NULL;
        result->field_attribs = NULL;
        result->result_state = (numrows_matched > 0) ? ROWS_RETURNED : 
NOTHING_RETURNED;
+       /* result->rows[0] is intentionally unused; rows are in [1..n] */
        result->rows = calloc(numrows_matched+1, sizeof(dbi_row_t *));
        result->currowidx = 0;
 
diff --git a/src/dbi_result.c b/src/dbi_result.c
index 751e490..59e64d9 100644
--- a/src/dbi_result.c
+++ b/src/dbi_result.c
@@ -108,7 +108,7 @@ int dbi_result_seek_row(dbi_result Result, unsigned long 
long rowidx) {
   }
        
   /* row is one-based for the user, but zero-based to the dbd conn */
-  retval = RESULT->conn->driver->functions->goto_row(RESULT, rowidx-1, 
RESULT->currowidx-1);
+  retval = RESULT->conn->driver->functions->goto_row(RESULT, rowidx-1, 
RESULT->dbd_currowidx-1);
   if (retval == -1) {
     _error_handler(RESULT->conn, DBI_ERROR_DBD);
     return 0;
@@ -120,6 +120,7 @@ int dbi_result_seek_row(dbi_result Result, unsigned long 
long rowidx) {
   }
 
   RESULT->currowidx = rowidx;
+  RESULT->dbd_currowidx = rowidx;
   _activate_bindings(RESULT);
   return retval;
 }
@@ -1789,8 +1790,6 @@ static unsigned int _find_field(dbi_result_t *result, 
const char *fieldname, dbi
 }
 
 static int _is_row_fetched(dbi_result_t *result, unsigned long long row) {
-  /* Bull patch reported by Tom Lane */
-  /*  if (!result->rows || (row >= result->numrows_matched)) return -1; */
   if (!result->rows || (row > result->numrows_matched)) return -1;
   return !(result->rows[row] == NULL);
 }
-- 
# Created with git-export-patch

------------------------------------------------------------------------------
"Accelerate Dev Cycles with Automated Cross-Browser Testing - For FREE
Instantly run your Selenium tests across 300+ browser/OS combos.  Get 
unparalleled scalability from the best Selenium testing platform available.
Simple to use. Nothing to install. Get started now for free."
http://p.sf.net/sfu/SauceLabs
_______________________________________________
Libdbi-drivers-devel mailing list
Libdbi-drivers-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/libdbi-drivers-devel

Reply via email to