--- apr_dbd_mysql.c.orig	2006-07-03 13:42:03.000000000 +1000
+++ apr_dbd_mysql.c	2006-07-03 13:39:26.000000000 +1000
@@ -34,7 +34,24 @@
  *
  */
 
-
+/* 2006-06-28 Alex Dubov <oakad@yahoo.com> - changes
+ *
+ * 1. Use dbd_mysql_get_row with rownum == -1 to reset queries
+ * 2. Use mysql_stmt_store_result only when random == 1
+ * 3. Don't use MYSQL_RES with prepared statements
+ * 4. Use buckets for binary data
+ * 5. Format specifiers used:
+ *   %* - null
+ *   %b - bucket
+ *   %s - string
+ *   %c / %C - char / unsigned
+ *   %h / %H - short / unsigned
+ *   %d / %D - integer / unsigned
+ *   %q / %Q - quad / unsigned
+ *   %f / %F - float / double
+ * 6. Default field size lifted in safe manner
+ *
+ */
 #include "apu.h"
 
 #if APU_HAVE_MYSQL
@@ -45,6 +62,9 @@
 #include <ctype.h>
 #include <stdlib.h>
 
+#define HAVE_MYSQL_MYSQL_H 1
+#undef HAVE_MYSQL_H
+
 #ifdef HAVE_MYSQL_H
 #include <mysql.h>
 #include <errmsg.h>
@@ -54,14 +74,16 @@
 #endif
 
 #include "apr_strings.h"
+#include "apr_buckets.h"
 
 #include "apr_dbd_internal.h"
 
-/* default maximum field size 1 MB */
-#define FIELDSIZE 1048576
+/* unconditionally fetch up to 256 bytes - the rest by demand (through dbd_mysql_get_entry) */
+#define FIELDSIZE 256
 
 struct apr_dbd_prepared_t {
     MYSQL_STMT* stmt;
+    MYSQL_BIND* bind;
 };
 
 struct apr_dbd_transaction_t {
@@ -73,17 +95,23 @@
 };
 
 struct apr_dbd_t {
-    MYSQL* conn ;
-    apr_dbd_transaction_t* trans ;
-    unsigned long fldsz;
+    MYSQL *conn;
+    apr_dbd_transaction_t *trans;
 };
 
 struct apr_dbd_results_t {
     int random;
+    unsigned long nfields;
     MYSQL_RES *res;
     MYSQL_STMT *statement;
     MYSQL_BIND *bind;
+    char *data;
+    unsigned long *offset;
+    unsigned long *length;
+    apr_pool_t *pool;
+    apr_bucket_alloc_t *bucket_alloc;
 };
+
 struct apr_dbd_row_t {
     MYSQL_ROW row;
     apr_dbd_results_t *res;
@@ -110,6 +138,7 @@
             if (!*results) {
                 *results = apr_palloc(pool, sizeof(apr_dbd_results_t));
             }
+            (*results)->pool = pool;
             (*results)->random = seek;
             (*results)->statement = NULL;
             if (seek) {
@@ -119,12 +148,12 @@
                 (*results)->res = mysql_use_result(sql->conn);
             }
             apr_pool_cleanup_register(pool, (*results)->res,
-                                      free_result,apr_pool_cleanup_null);
+                                      free_result, apr_pool_cleanup_null);
         }
     } else {
         ret = mysql_errno(sql->conn);
     }
-    
+
 #if APU_MAJOR_VERSION >= 2 || (APU_MAJOR_VERSION == 1 && APU_MINOR_VERSION >= 3)
     if (TXN_NOTICE_ERRORS(sql->trans)) {
 #else
@@ -138,61 +167,68 @@
 #if APU_MAJOR_VERSION >= 2 || (APU_MAJOR_VERSION == 1 && APU_MINOR_VERSION >= 3)
 static const char *dbd_mysql_get_name(const apr_dbd_results_t *res, int n)
 {
-    if ((n < 0) || (n >= mysql_num_fields(res->res))) {
-        return NULL;
+    if(res->statement) {
+        if((n < 0) || (n >= mysql_stmt_field_count(res->statement))) return 0;
+        return res->statement->fields[n].name;
+    } else {
+        if ((n < 0) || (n >= mysql_num_fields(res->res))) return 0;
+        return mysql_fetch_fields(res->res)[n].name;
     }
-
-    return mysql_fetch_fields(res->res)[n].name;
 }
 #endif
+
 static int dbd_mysql_get_row(apr_pool_t *pool, apr_dbd_results_t *res,
                              apr_dbd_row_t **row, int rownum)
 {
-    MYSQL_ROW r = NULL;
+    MYSQL_ROW r;
     int ret = 0;
+    int cnt;
 
-    if (res->statement) {
+    if(res->statement) {
         if (res->random) {
             if (rownum >= 0) {
                 mysql_stmt_data_seek(res->statement, (my_ulonglong)rownum);
             }
         }
-        ret = mysql_stmt_fetch(res->statement);
-        switch (ret) {
-        case 1:
-            ret = mysql_stmt_errno(res->statement);
-            break;
-        case MYSQL_NO_DATA:
+
+        if(rownum == -1) {
+            mysql_stmt_free_result(res->statement);
             ret = -1;
-            break;
-        default:
-            ret = 0; /* bad luck - get_entry will deal with this */
-            break;
+        } else {
+            if(1 == (ret = mysql_stmt_fetch(res->statement))) {
+                ret = mysql_stmt_errno(res->statement);
+            } else if(ret == MYSQL_NO_DATA) {
+                    ret = -1;
+            } else if(ret == MYSQL_DATA_TRUNCATED) {
+                /* dbd_mysql_get_entry will deal with this */
+                ret = 0;
+            }
         }
-    }
-    else {
+    } else {
         if (res->random) {
             if (rownum >= 0) {
                 mysql_data_seek(res->res, (my_ulonglong) rownum);
             }
         }
-        r = mysql_fetch_row(res->res);
-        if (r == NULL) {
+        if(!(r = mysql_fetch_row(res->res))) {
             ret = -1;
         }
     }
     if (ret == 0) {
         if (!*row) {
-            *row = apr_palloc(pool, sizeof(apr_dbd_row_t));
+            *row = apr_palloc(res->pool, sizeof(apr_dbd_row_t));
         }
         (*row)->row = r;
         (*row)->res = res;
-    }
-    else {
-        apr_pool_cleanup_run(pool, res->res, free_result);
+    } else {
+        if(res->res) {
+            mysql_free_result(res->res);
+            apr_pool_cleanup_kill(pool, res->res, (void*)free_result);
+        }
     }
     return ret;
 }
+
 #if 0
 /* An improved API that was proposed but not followed up */
 static int dbd_mysql_get_entry(const apr_dbd_row_t *row, int n,
@@ -223,20 +259,40 @@
 #else
 static const char *dbd_mysql_get_entry(const apr_dbd_row_t *row, int n)
 {
-    MYSQL_BIND *bind;
+    char *data_out;
+    MYSQL_BIND arg_out = {0};
+
     if (row->res->statement) {
-        bind = &row->res->bind[n];
-        if (mysql_stmt_fetch_column(row->res->statement, bind, n, 0) != 0) {
-            return NULL;
-        }
-        if (*bind->is_null) {
-            return NULL;
+        if((n > row->res->nfields) || row->res->bind[n].is_null_value) return 0;
+        data_out = apr_palloc(row->res->pool, row->res->length[n]);
+
+        if(row->res->length[n] > FIELDSIZE) {
+            arg_out.buffer_type = row->res->bind[n].buffer_type;
+            arg_out.buffer = data_out + FIELDSIZE;
+            arg_out.buffer_length = row->res->length[n] - FIELDSIZE;
+            arg_out.length = &(row->res->length[n]);
+            arg_out.is_unsigned = row->res->bind[n].is_unsigned;
+
+            memcpy(data_out, row->res->data + row->res->offset[n], FIELDSIZE);
+
+            if(mysql_stmt_fetch_column(row->res->statement, &arg_out, n, FIELDSIZE))
+               return 0;
+        } else {
+            memcpy(data_out, row->res->data + row->res->offset[n], row->res->length[n]);
         }
-        else {
-            return bind->buffer;
+
+        if(row->res->statement->fields[n].flags & BLOB_FLAG) {
+            if(!(row->res->bucket_alloc))
+                row->res->bucket_alloc = apr_bucket_alloc_create(row->res->pool);
+
+            return (const char*)apr_bucket_pool_create(data_out, row->res->length[n],
+                row->res->pool, row->res->bucket_alloc);
+
+        } else {
+            return data_out;
         }
-    }
-    else {
+
+    } else {
         return row->row[n];
     }
     return 0;
@@ -279,40 +335,89 @@
     mysql_stmt_close(data);
     return APR_SUCCESS;
 }
+
 static int dbd_mysql_prepare(apr_pool_t *pool, apr_dbd_t *sql,
                              const char *query, const char *label,
                              apr_dbd_prepared_t **statement)
 {
-    /* Translate from apr_dbd to native query format */
-    char *myquery = apr_pstrdup(pool, query);
-    char *p = myquery;
-    const char *q;
-    int ret;
-    for (q = query; *q; ++q) {
-        if (q[0] == '%') {
-            if (isalpha(q[1])) {
-                *p++ = '?';
-                ++q;
-            }
-            else if (q[1] == '%') {
-                /* reduce %% to % */
-                *p++ = *q++;
-            }
-            else {
-                *p++ = *q;
-            }
-        }
-        else {
-            *p++ = *q;
+    const char *p = query;
+    int param_num = 0, char_out = 0, ret = 0;
+
+    while(p[0]) {
+        if(p[0] == '%' && p[1]) {
+            if(p[1] != '%') param_num++;
+            p++;
         }
-    } 
-    *p = 0;
+        char_out++;
+        p++;
+    }
+    char *myquery = apr_pcalloc(pool, char_out + 1);
     if (!*statement) {
         *statement = apr_palloc(pool, sizeof(apr_dbd_prepared_t));
     }
+    (*statement)->bind = apr_pcalloc(pool, param_num * sizeof(MYSQL_BIND));
+
+    p = query;
+    param_num = 0;
+    char_out = 0;
+    while(p[0]) {
+        if(p[0] == '%' && p[1]) {
+            p++;
+            if(p[1] == '%') {
+                myquery[char_out++] = '%';
+            } else {
+                myquery[char_out++] = '?';
+                switch(p[0]) {
+                    case '*':
+                        (*statement)->bind[param_num].buffer_type = MYSQL_TYPE_NULL;
+                        break;
+                    case 'b':
+                        (*statement)->bind[param_num].buffer_type = MYSQL_TYPE_BLOB;
+                        break;
+                    case 's':
+                        (*statement)->bind[param_num].buffer_type = MYSQL_TYPE_VAR_STRING;
+                        break;
+                    case 'C':
+                        (*statement)->bind[param_num].is_unsigned = 1;
+                    case 'c':
+                        (*statement)->bind[param_num].buffer_type = MYSQL_TYPE_TINY;
+                        break;
+                    case 'H':
+                        (*statement)->bind[param_num].is_unsigned = 1;
+                    case 'h':
+                        (*statement)->bind[param_num].buffer_type = MYSQL_TYPE_SHORT;
+                        break;
+                    case 'D':
+                        (*statement)->bind[param_num].is_unsigned = 1;
+                    case 'd':
+                        (*statement)->bind[param_num].buffer_type = MYSQL_TYPE_LONG;
+                        break;
+                    case 'Q':
+                        (*statement)->bind[param_num].is_unsigned = 1;
+                    case 'q':
+                        (*statement)->bind[param_num].buffer_type = MYSQL_TYPE_LONGLONG;
+                        break;
+                    case 'f':
+                        (*statement)->bind[param_num].buffer_type = MYSQL_TYPE_FLOAT;
+                        break;
+                    case 'F':
+                        (*statement)->bind[param_num].buffer_type = MYSQL_TYPE_DOUBLE;
+                        break;
+                    default: // assume string
+                        (*statement)->bind[param_num].buffer_type = MYSQL_TYPE_VAR_STRING;
+                        break;
+                }
+                param_num++;
+            }
+        } else {
+            myquery[char_out++] = p[0];
+        }
+        p++;
+    }
+
     (*statement)->stmt = mysql_stmt_init(sql->conn);
 
-    if ((*statement)->stmt) {
+    if(((*statement)->stmt)) {
         apr_pool_cleanup_register(pool, (*statement)->stmt,
                                   stmt_close, apr_pool_cleanup_null);
         ret = mysql_stmt_prepare((*statement)->stmt, myquery, strlen(myquery));
@@ -326,33 +431,81 @@
 
     return CR_OUT_OF_MEMORY;
 }
+
+static void mysql_bind_arg(MYSQL_BIND *bind, const char *arg)
+{
+    switch(bind->buffer_type) {
+        case MYSQL_TYPE_TINY:
+            bind->buffer = (char*)arg;
+            bind->buffer_length = 1;
+            break;
+        case MYSQL_TYPE_SHORT:
+            bind->buffer = (char*)arg;
+            bind->buffer_length = 2;
+            break;
+        case MYSQL_TYPE_LONG:
+            bind->buffer = (char*)arg;
+            bind->buffer_length = 4;
+            break;
+        case MYSQL_TYPE_LONGLONG:
+            bind->buffer = (char*)arg;
+            bind->buffer_length = 8;
+            break;
+        case MYSQL_TYPE_FLOAT:
+            bind->buffer = (char*)arg;
+            bind->buffer_length = 4;
+            break;
+        case MYSQL_TYPE_DOUBLE:
+            bind->buffer = (char*)arg;
+            bind->buffer_length = 8;
+            break;
+        case MYSQL_TYPE_VAR_STRING:
+            bind->buffer = (char*)arg;
+            bind->buffer_length = arg ? strlen(arg) : 0;
+            break;
+        case MYSQL_TYPE_TINY_BLOB:
+        case MYSQL_TYPE_BLOB:
+        case MYSQL_TYPE_MEDIUM_BLOB:
+        case MYSQL_TYPE_LONG_BLOB:
+            if(!arg || (APR_SUCCESS != apr_bucket_read((apr_bucket*)arg, (const char**)&(bind->buffer),
+                (apr_size_t*)&(bind->buffer_length), APR_BLOCK_READ))) {
+                bind->buffer = 0;
+                bind->buffer_length = 0;
+            }
+
+            if(bind->buffer_length < (1 << 8)) bind->buffer_type = MYSQL_TYPE_TINY_BLOB;
+            else if(bind->buffer_length < (1 << 16)) bind->buffer_type = MYSQL_TYPE_BLOB;
+            else if(bind->buffer_length < (1 << 24)) bind->buffer_type = MYSQL_TYPE_MEDIUM_BLOB;
+            else bind->buffer_type = MYSQL_TYPE_LONG_BLOB;
+            break;
+        }
+}
+
 static int dbd_mysql_pquery(apr_pool_t *pool, apr_dbd_t *sql,
                             int *nrows, apr_dbd_prepared_t *statement,
                             int nargs, const char **values)
 {
-    MYSQL_BIND *bind;
-    char *arg;
-    int ret;
-    int i;
-    my_bool is_null = FALSE;
+    int ret, cnt, my_arg = 0, my_nargs = mysql_stmt_param_count(statement->stmt);
+    my_bool is_null = 1; // only used for real nulls
 
     if (sql->trans && sql->trans->errnum) {
         return sql->trans->errnum;
     }
-    nargs = mysql_stmt_param_count(statement->stmt);
 
-    bind = apr_palloc(pool, nargs*sizeof(MYSQL_BIND));
-    for (i=0; i < nargs; ++i) {
-        arg = (char*)values[i];
-        bind[i].buffer_type = MYSQL_TYPE_VAR_STRING;
-        bind[i].buffer = arg;
-        bind[i].buffer_length = strlen(arg);
-        bind[i].length = &bind[i].buffer_length;
-        bind[i].is_null = &is_null;
-        bind[i].is_unsigned = 0;
+    if(my_nargs) {
+        for(cnt = 0; cnt < nargs; cnt++) {
+            while(statement->bind[my_arg].buffer_type == MYSQL_TYPE_NULL) { // skip const nulls
+                my_arg++;
+                if(my_arg > my_nargs) goto end_bind;
+            }
+            mysql_bind_arg(&(statement->bind[my_arg]), values[cnt]);
+            if(!(statement->bind[my_arg].buffer)) statement->bind[my_arg].is_null = &is_null;
+            else statement->bind[my_arg].is_null = 0;
+        }
     }
 
-    ret = mysql_stmt_bind_param(statement->stmt, bind);
+end_bind:
+    ret = mysql_stmt_bind_param(statement->stmt, statement->bind);
     if (ret != 0) {
         *nrows = 0;
         ret = mysql_stmt_errno(statement->stmt);
@@ -373,33 +526,27 @@
     }
     return ret;
 }
+
 static int dbd_mysql_pvquery(apr_pool_t *pool, apr_dbd_t *sql, int *nrows,
                              apr_dbd_prepared_t *statement, va_list args)
 {
-    MYSQL_BIND *bind;
-    char *arg;
-    int ret;
-    int nargs = 0;
-    int i;
-    my_bool is_null = FALSE;
+    int ret, my_arg = 0, my_nargs = mysql_stmt_param_count(statement->stmt);
+    my_bool is_null = 1; // only used for real nulls
 
     if (sql->trans && sql->trans->errnum) {
         return sql->trans->errnum;
     }
-    nargs = mysql_stmt_param_count(statement->stmt);
 
-    bind = apr_palloc(pool, nargs*sizeof(MYSQL_BIND));
-    for (i=0; i < nargs; ++i) {
-        arg = va_arg(args, char*);
-        bind[i].buffer_type = MYSQL_TYPE_VAR_STRING;
-        bind[i].buffer = arg;
-        bind[i].buffer_length = strlen(arg);
-        bind[i].length = &bind[i].buffer_length;
-        bind[i].is_null = &is_null;
-        bind[i].is_unsigned = 0;
+    while(my_arg < my_nargs) {
+        if(statement->bind[my_arg].buffer_type != MYSQL_TYPE_NULL) {
+            mysql_bind_arg(&(statement->bind[my_arg]), va_arg(args, char*));
+            if(!(statement->bind[my_arg].buffer)) statement->bind[my_arg].is_null = &is_null;
+            else statement->bind[my_arg].is_null = 0;
+        }
+        my_arg++;
     }
 
-    ret = mysql_stmt_bind_param(statement->stmt, bind);
+    ret = mysql_stmt_bind_param(statement->stmt, statement->bind);
     if (ret != 0) {
         *nrows = 0;
         ret = mysql_stmt_errno(statement->stmt);
@@ -420,75 +567,73 @@
     }
     return ret;
 }
+
 static int dbd_mysql_pselect(apr_pool_t *pool, apr_dbd_t *sql,
                              apr_dbd_results_t **res,
                              apr_dbd_prepared_t *statement, int random,
                              int nargs, const char **args)
 {
-    int i;
-    int nfields;
-    char *arg;
-    my_bool is_null = FALSE;
-    my_bool *is_nullr;
-#if MYSQL_VERSION_ID >= 50000
-    my_bool *error;
-#endif
-    int ret;
-    unsigned long *length, maxlen;
-    MYSQL_BIND *bind;
+    int ret, cnt, my_arg = 0, my_nargs = mysql_stmt_param_count(statement->stmt);
+    my_bool is_null = 1; // only used for real nulls
+    unsigned long *length;
+    unsigned long c_offset = 0;
 
     if (sql->trans && sql->trans->errnum) {
         return sql->trans->errnum;
     }
 
-    nargs = mysql_stmt_param_count(statement->stmt);
-    bind = apr_palloc(pool, nargs*sizeof(MYSQL_BIND));
-
-    for (i=0; i < nargs; ++i) {
-        arg = (char*)args[i];
-        bind[i].buffer_type = MYSQL_TYPE_VAR_STRING;
-        bind[i].buffer = arg;
-        bind[i].buffer_length = strlen(arg);
-        bind[i].length = &bind[i].buffer_length;
-        bind[i].is_null = &is_null;
-        bind[i].is_unsigned = 0;
+    if(my_nargs) {
+        for(cnt = 0; cnt < nargs; cnt++) {
+            while(statement->bind[my_arg].buffer_type == MYSQL_TYPE_NULL) { // skip const nulls
+                my_arg++;
+                if(my_arg > my_nargs) goto end_bind;
+            }
+            mysql_bind_arg(&(statement->bind[my_arg]), args[cnt]);
+            if(!(statement->bind[my_arg].buffer)) statement->bind[my_arg].is_null = &is_null;
+            else statement->bind[my_arg].is_null = 0;
+        }
     }
 
-    ret = mysql_stmt_bind_param(statement->stmt, bind);
+end_bind:
+    ret = mysql_stmt_bind_param(statement->stmt, statement->bind);
+
     if (ret == 0) {
         ret = mysql_stmt_execute(statement->stmt);
         if (!ret) {
             if (!*res) {
                 *res = apr_pcalloc(pool, sizeof(apr_dbd_results_t));
             }
+            (*res)->pool = pool;
             (*res)->random = random;
             (*res)->statement = statement->stmt;
-            (*res)->res = mysql_stmt_result_metadata(statement->stmt);
-            apr_pool_cleanup_register(pool, (*res)->res,
-                                      free_result, apr_pool_cleanup_null);
-            nfields = mysql_num_fields((*res)->res);
+            (*res)->nfields = mysql_stmt_field_count(statement->stmt);
+
             if (!(*res)->bind) {
-                (*res)->bind = apr_palloc(pool, nfields*sizeof(MYSQL_BIND));
-                length = apr_pcalloc(pool, nfields*sizeof(unsigned long));
-#if MYSQL_VERSION_ID >= 50000
-                error = apr_palloc(pool, nfields*sizeof(my_bool));
-#endif
-                is_nullr = apr_pcalloc(pool, nfields*sizeof(my_bool));
-                for ( i = 0; i < nfields; ++i ) {
-                    maxlen = (*res)->res->fields[i].length < sql->fldsz ?
-                             (*res)->res->fields[i].length : sql->fldsz;
-                    (*res)->bind[i].buffer_type = MYSQL_TYPE_VAR_STRING;
-                    (*res)->bind[i].buffer_length = maxlen;
-                    (*res)->bind[i].length = &length[i];
-                    (*res)->bind[i].buffer = apr_palloc(pool, maxlen);
-                    (*res)->bind[i].is_null = is_nullr+i;
-#if MYSQL_VERSION_ID >= 50000
-                    (*res)->bind[i].error = error+i;
-#endif
+                (*res)->bind = apr_pcalloc(pool, (*res)->nfields * sizeof(MYSQL_BIND));
+                (*res)->offset = apr_pcalloc(pool, (*res)->nfields * sizeof(unsigned long));
+                (*res)->length = apr_pcalloc(pool, (*res)->nfields * sizeof(unsigned long));
+
+                for(cnt = 0; cnt < (*res)->nfields; cnt++ ) {
+                        (*res)->bind[cnt].buffer_length
+                            = statement->stmt->fields[cnt].length > FIELDSIZE
+                                ? FIELDSIZE
+                                : statement->stmt->fields[cnt].length;
+
+                    (*res)->offset[cnt] = c_offset;
+                    c_offset += (*res)->bind[cnt].buffer_length;
+                }
+
+                (*res)->data = apr_palloc(pool, c_offset);
+
+                for ( cnt = 0; cnt < (*res)->nfields; cnt++ ) {
+                    (*res)->bind[cnt].buffer_type = statement->stmt->fields[cnt].type;
+                    (*res)->bind[cnt].buffer = (*res)->data + (*res)->offset[cnt];
+                    (*res)->bind[cnt].length = &((*res)->length[cnt]);
+                    (*res)->bind[cnt].is_unsigned = (statement->stmt->fields[cnt].flags & UNSIGNED_FLAG) ? 1 : 0;
                 }
             }
             ret = mysql_stmt_bind_result(statement->stmt, (*res)->bind);
-            if (!ret) {
+            if (!ret && random) {
                 ret = mysql_stmt_store_result(statement->stmt);
             }
         }
@@ -505,76 +650,69 @@
     }
     return ret;
 }
+
 static int dbd_mysql_pvselect(apr_pool_t *pool, apr_dbd_t *sql,
                               apr_dbd_results_t **res,
                               apr_dbd_prepared_t *statement, int random,
                               va_list args)
 {
-    int i;
-    int nfields;
-    char *arg;
-    my_bool is_null = FALSE;
-    my_bool *is_nullr;
-#if MYSQL_VERSION_ID >= 50000
-    my_bool *error;
-#endif
-    int ret;
-    unsigned long *length, maxlen;
-    int nargs;
-    MYSQL_BIND *bind;
+    int ret, cnt, my_arg = 0, my_nargs = mysql_stmt_param_count(statement->stmt);
+    my_bool is_null = 1; // only used for real nulls
+    unsigned long c_offset = 0;
 
     if (sql->trans && sql->trans->errnum) {
         return sql->trans->errnum;
     }
 
-    nargs = mysql_stmt_param_count(statement->stmt);
-    bind = apr_palloc(pool, nargs*sizeof(MYSQL_BIND));
-
-    for (i=0; i < nargs; ++i) {
-        arg = va_arg(args, char*);
-        bind[i].buffer_type = MYSQL_TYPE_VAR_STRING;
-        bind[i].buffer = arg;
-        bind[i].buffer_length = strlen(arg);
-        bind[i].length = &bind[i].buffer_length;
-        bind[i].is_null = &is_null;
-        bind[i].is_unsigned = 0;
+    while(my_arg < my_nargs) {
+        if(statement->bind[my_arg].buffer_type != MYSQL_TYPE_NULL) {
+            mysql_bind_arg(&(statement->bind[my_arg]), va_arg(args, char*));
+            if(!(statement->bind[my_arg].buffer)) statement->bind[my_arg].is_null = &is_null;
+            else statement->bind[my_arg].is_null = 0;
+        }
+        my_arg++;
     }
 
-    ret = mysql_stmt_bind_param(statement->stmt, bind);
+    ret = mysql_stmt_bind_param(statement->stmt, statement->bind);
+
     if (ret == 0) {
         ret = mysql_stmt_execute(statement->stmt);
         if (!ret) {
             if (!*res) {
                 *res = apr_pcalloc(pool, sizeof(apr_dbd_results_t));
             }
+            (*res)->pool = pool;
             (*res)->random = random;
             (*res)->statement = statement->stmt;
-            (*res)->res = mysql_stmt_result_metadata(statement->stmt);
-            apr_pool_cleanup_register(pool, (*res)->res,
-                                      free_result, apr_pool_cleanup_null);
-            nfields = mysql_num_fields((*res)->res);
+            (*res)->nfields = mysql_stmt_field_count(statement->stmt);
+
             if (!(*res)->bind) {
-                (*res)->bind = apr_palloc(pool, nfields*sizeof(MYSQL_BIND));
-                length = apr_pcalloc(pool, nfields*sizeof(unsigned long));
-#if MYSQL_VERSION_ID >= 50000
-                error = apr_palloc(pool, nfields*sizeof(my_bool));
-#endif
-                is_nullr = apr_pcalloc(pool, nfields*sizeof(my_bool));
-                for ( i = 0; i < nfields; ++i ) {
-                    maxlen = (*res)->res->fields[i].length < sql->fldsz ?
-                             (*res)->res->fields[i].length : sql->fldsz;
-                    (*res)->bind[i].buffer_type = MYSQL_TYPE_VAR_STRING;
-                    (*res)->bind[i].buffer_length = maxlen;
-                    (*res)->bind[i].length = &length[i];
-                    (*res)->bind[i].buffer = apr_palloc(pool, maxlen);
-                    (*res)->bind[i].is_null = is_nullr+i;
-#if MYSQL_VERSION_ID >= 50000
-                    (*res)->bind[i].error = error+i;
-#endif
+                (*res)->bind = apr_pcalloc(pool, (*res)->nfields * sizeof(MYSQL_BIND));
+                (*res)->offset = apr_pcalloc(pool, (*res)->nfields * sizeof(unsigned long));
+                (*res)->length = apr_pcalloc(pool, (*res)->nfields * sizeof(unsigned long));
+
+                for(cnt = 0; cnt < (*res)->nfields; cnt++ ) {
+                        (*res)->bind[cnt].buffer_length
+                            = statement->stmt->fields[cnt].length > FIELDSIZE
+                                ? FIELDSIZE
+                                : statement->stmt->fields[cnt].length;
+
+                    (*res)->offset[cnt] = c_offset;
+                    c_offset += (*res)->bind[cnt].buffer_length;
+                }
+
+                (*res)->data = apr_palloc(pool, c_offset);
+
+                for ( cnt = 0; cnt < (*res)->nfields; cnt++ ) {
+                    (*res)->bind[cnt].buffer_type = statement->stmt->fields[cnt].type;
+                    (*res)->bind[cnt].buffer = (*res)->data + (*res)->offset[cnt];
+                    (*res)->bind[cnt].length = &((*res)->length[cnt]);
+                    (*res)->bind[cnt].is_unsigned = (statement->stmt->fields[cnt].flags & UNSIGNED_FLAG) ? 1 : 0;
                 }
             }
+
             ret = mysql_stmt_bind_result(statement->stmt, (*res)->bind);
-            if (!ret) {
+            if (!ret && random) {
                 ret = mysql_stmt_store_result(statement->stmt);
             }
         }
@@ -591,6 +729,7 @@
     }
     return ret;
 }
+
 static int dbd_mysql_end_transaction(apr_dbd_transaction_t *trans)
 {
     int ret = -1;
@@ -675,12 +814,10 @@
         {"port", NULL},
         {"sock", NULL},
         {"flags", NULL},
-        {"fldsz", NULL},
         {NULL, NULL}
     };
     unsigned int port = 0;
     apr_dbd_t *sql = apr_pcalloc(pool, sizeof(apr_dbd_t));
-    sql->fldsz = FIELDSIZE;
     sql->conn = mysql_init(sql->conn);
     if ( sql->conn == NULL ) {
         return NULL;
@@ -716,10 +853,7 @@
         !strcmp(fields[6].value, "CLIENT_FOUND_ROWS")) {
         flags |= CLIENT_FOUND_ROWS; /* only option we know */
     }
-    if (fields[7].value != NULL) {
-        sql->fldsz = atol(fields[7].value);
-    }
-    
+
     real_conn = mysql_real_connect(sql->conn, fields[0].value,
                                    fields[1].value, fields[2].value,
                                    fields[3].value, port,
@@ -755,6 +889,7 @@
 {
     return handle->conn;
 }
+
 static int dbd_mysql_num_cols(apr_dbd_results_t *res)
 {
     if (res->statement) {
@@ -764,6 +899,7 @@
         return mysql_num_fields(res->res);
     }
 }
+
 static int dbd_mysql_num_tuples(apr_dbd_results_t *res)
 {
     if (res->random) {
