--- apr_dbd_mysql.c.orig	2006-05-22 11:32:45.000000000 +1000
+++ apr_dbd_mysql.c	2006-05-22 11:48:11.000000000 +1000
@@ -40,10 +40,26 @@
  * Alternatively, if you have an alternative home for this driver,
  * and an active developer community, I'm open to offers.
  */
+	     
 
+/*      Changes to handling of prepared statements: Alex Dubov <oakad@yahoo.com> 2006-02-23
+ *
+ *      1. Make dbd_mysql_prepare accept type specifiers (see below)
+ *      2. Parameters bind array is now part of the apr_dbd_prepared_t
+ *      3. Return types are honored (no automatic conversion to strings)
+ *      4. struct blob_t* is returned for blobs (types handled by fetch_result_bin)
+ *        - other string types are handled by fetch_result_str, which always adds terminating \0
+ *      5. Removed mysql_stmt_close call-back registration - mysql_close removes all statements
+ *        - I had this problem with stand-alone apr app (glibc double free exception)
+ *
+ *     Additional changes: Alex Dubov <oakad@yahoo.com> 2006-04-20
+ *
+ *	1. Make all function return mysql_errno/mysql_stmt_errno (much more informative)
+ *      2. Remove buggy mysql_stmt_fetch_column (not needed - wrong hanling of large BIGINTs)
+ *      3. Add handling of unsigned types (prevents unnecessary "data truncated" errors)
+ */
 
 #include "apu.h"
-#include "apu_version.h"
 
 #if APU_HAVE_MYSQL
 
@@ -57,10 +73,10 @@
 
 #include "apr_dbd_internal.h"
 
-#define FIELDSIZE 1048575
 
 struct apr_dbd_prepared_t {
     MYSQL_STMT* stmt;
+    MYSQL_BIND* bind;
 };
 
 struct apr_dbd_transaction_t {
@@ -84,6 +100,11 @@
     apr_dbd_results_t *res;
 };
 
+struct blob_t {
+    unsigned long length;
+    char data[];
+};
+
 static int dbd_mysql_select(apr_pool_t *pool, apr_dbd_t *sql,
                             apr_dbd_results_t **results,
                             const char *query, int seek)
@@ -111,7 +132,10 @@
                                       (void*)mysql_free_result,
                                       apr_pool_cleanup_null);
         }
+    } else {
+	ret = mysql_errno(sql->conn);
     }
+    
     if (sql->trans) {
         sql->trans->errnum = ret;
     }
@@ -131,7 +155,7 @@
 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;
 
     if (res->statement) {
@@ -140,7 +164,13 @@
                 mysql_stmt_data_seek(res->statement, (my_ulonglong)rownum);
             }
         }
-        ret = mysql_stmt_fetch(res->statement);
+        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) {
+	    ret = 0; /* bad luck - get_entry will deal with this */
+	}
     }
     else {
         if (res->random) {
@@ -148,10 +178,9 @@
                 mysql_data_seek(res->res, (my_ulonglong) rownum);
             }
         }
-        r = mysql_fetch_row(res->res);
-        if (r == NULL) {
-            ret = 1;
-        }
+        if(!(r = mysql_fetch_row(res->res))) {
+    	    ret = -1;
+	}
     }
     if (ret == 0) {
         if (!*row) {
@@ -163,7 +192,6 @@
     else {
         mysql_free_result(res->res);
         apr_pool_cleanup_kill(pool, res->res, (void*)mysql_free_result);
-        ret = -1;
     }
     return ret;
 }
@@ -200,14 +228,20 @@
     MYSQL_BIND *bind;
     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) {
+        if (bind->is_null_value || bind->error_value) {
             return NULL;
         }
         else {
-            return bind->buffer;
+            if(bind->buffer_type == MYSQL_TYPE_TINY_BLOB 
+               || bind->buffer_type == MYSQL_TYPE_MEDIUM_BLOB
+               || bind->buffer_type == MYSQL_TYPE_LONG_BLOB
+               || bind->buffer_type == MYSQL_TYPE_BLOB
+               || bind->buffer_type == MYSQL_TYPE_BIT) {
+               /* Use optional length field - bind->length points to the real data size */
+               ((struct blob_t*)(bind->buffer - sizeof(struct blob_t)))->length = *(bind->length);
+               return bind->buffer - sizeof(struct blob_t);
+            }
+            else return bind->buffer;
         }
     }
     else {
@@ -226,7 +260,7 @@
     if (sql->trans && sql->trans->errnum) {
         return sql->trans->errnum;
     }
-    ret = mysql_query(sql->conn, query);
+    if((ret = mysql_query(sql->conn, query))) ret = mysql_errno(sql->conn);
     *nrows = mysql_affected_rows(sql->conn);
     if (sql->trans) {
         sql->trans->errnum = ret;
@@ -241,6 +275,7 @@
     mysql_real_escape_string(sql->conn, ret, arg, len);
     return ret;
 }
+
 static int dbd_mysql_prepare(apr_pool_t *pool, apr_dbd_t *sql,
                              const char *query, const char *label,
                              apr_dbd_prepared_t **statement)
@@ -248,72 +283,230 @@
     /* Translate from apr_dbd to native query format */
     char *myquery = apr_pstrdup(pool, query);
     char *p = myquery;
-    const char *q;
-    for (q = query; *q; ++q) {
-        if (q[0] == '%') {
-            if (isalpha(q[1])) {
-                *p++ = '?';
-                ++q;
-            }
-            else if (q[1] == '%') {
-                /* reduce %% to % */
+    const char *q = query;
+
+    const int bind_inc = 8;
+
+    int cnt, p_len = 0, nargs, ret = 0, bind_size = bind_inc, bind_pos = 0;
+
+    if (!*statement) {
+        *statement = apr_palloc(pool, sizeof(apr_dbd_prepared_t));
+    }
+
+    if(!((*statement)->bind = apr_pcalloc(pool, bind_size * sizeof(MYSQL_BIND)))) return 1;
+
+    /* Recognize following formats:
+     *    Format        | MySQL C type           | SQL type              | C type
+     * -----------------|------------------------|-----------------------|--------------
+     *    %hhd(u)       | MYSQL_TYPE_TINY        | TINYINT               | char
+     *    %hd(u)        | MYSQL_TYPE_SHORT       | SMALLINT              | short int
+     *    %ld(u), %d(u) | MYSQL_TYPE_LONG        | INT                   | int
+     *    %lld(u)       | MYSQL_TYPE_LONGLONG    | BIGINT                | long long int
+     *    %f            | MYSQL_TYPE_FLOAT       | FLOAT                 | float
+     *    %lf           | MYSQL_TYPE_DOUBLE      | DOUBLE                | double
+     *    %c            | MYSQL_TYPE_STRING      | CHAR/TEXT             | char*
+     *    %s            | MYSQL_TYPE_BLOB        | BLOB/BINARY           | struct blob_t*
+     * These are not supported currently:
+     *                  | MYSQL_TYPE_BIT
+     *                  | MYSQL_TYPE_TIME        | TIME                  | MYSQL_TIME
+     *                  | MYSQL_TYPE_DATE        | DATE                  | MYSQL_TIME
+     *                  | MYSQL_TYPE_DATETIME    | DATETIME              | MYSQL_TIME
+     *                  | MYSQL_TYPE_TIMESTAMP   | TIMESTAMP             | MYSQL_TIME
+     * These should work ok with MYSQL_TYPE_BLOB:
+     *                  | MYSQL_TYPE_VAR_STRING  | VARCHAR/VARBINARY     |
+     *                  | MYSQL_TYPE_TINY_BLOB   | TINYBLOB/TINYTEXT     |
+     *                  | MYSQL_TYPE_MEDIUM_BLOB | MEDIUMBLOB/MEDIUMTEXT |
+     *                  | MYSQL_TYPE_LONG_BLOB   | LONGBLOB/LONGTEXT     |
+     */
+    while(*q) {
+        if(q[0] != '%') {
+            *p++ = *q++;
+        }
+        else {
+	    q++;
+            if(q[0] == '%') {
                 *p++ = *q++;
             }
             else {
-                *p++ = *q;
+                if(q[0] == 'h') {
+                    if(q[1] == 'h') {
+                        p_len = 1;
+                        q += 2;
+                    }
+                    else {
+                        p_len = 2;
+                        q++;
+                    }
+                }
+                else if(q[0] == 'l') {
+                    if(q[1] == 'l') {
+                        p_len = 8;
+                        q += 2;
+                    }
+                    else {
+                        p_len = 4;
+                        q++;
+                    }
+                }
+
+                switch(q[0]) {
+                    case 'c':
+                        (*statement)->bind[bind_pos].buffer_type = MYSQL_TYPE_STRING;
+                        (*statement)->bind[bind_pos].is_unsigned = 0;
+                        break;
+                    case 'd':
+                        if(!p_len) p_len = 4;
+                        (*statement)->bind[bind_pos].buffer_type = 
+                            (p_len == 8) ? MYSQL_TYPE_LONGLONG : ((p_len == 4) ? MYSQL_TYPE_LONG
+                                : ((p_len == 2) ? MYSQL_TYPE_SHORT : ((p_len == 1) ? MYSQL_TYPE_TINY 
+                                    : MYSQL_TYPE_NULL)));
+                        (*statement)->bind[bind_pos].is_unsigned = 0;
+                        break;
+                    case 'f':
+                        (*statement)->bind[bind_pos].buffer_type = 
+                            (p_len == 4) ? MYSQL_TYPE_DOUBLE : ((p_len == 0) ? MYSQL_TYPE_FLOAT : MYSQL_TYPE_NULL);
+                        (*statement)->bind[bind_pos].is_unsigned = 0;
+                        break;
+                    case 's':
+                        (*statement)->bind[bind_pos].buffer_type = MYSQL_TYPE_BLOB;
+                        (*statement)->bind[bind_pos].is_unsigned = 0;
+                        break;
+                    case 'u':
+                        if(!p_len) p_len = 4;
+                        (*statement)->bind[bind_pos].buffer_type = 
+                            (p_len == 8) ? MYSQL_TYPE_LONGLONG : ((p_len == 4) ? MYSQL_TYPE_LONG
+                                : ((p_len == 2) ? MYSQL_TYPE_SHORT : ((p_len == 1) ? MYSQL_TYPE_TINY 
+                                    : MYSQL_TYPE_NULL)));
+                        (*statement)->bind[bind_pos].is_unsigned = 1;
+                        break;
+                    default:
+                        *p++ = *q++;
+                        p_len = 0;
+                        continue;
+                }
+                p_len = 0;
+                bind_pos++;
+                if(bind_pos == bind_size) {
+                    // it will be nice to have realloc here
+                    MYSQL_BIND* old_bind = (*statement)->bind;
+                    if(!((*statement)->bind = apr_pcalloc(pool, (bind_size + bind_inc) * sizeof(MYSQL_BIND)))) 
+                        return CR_OUT_OF_MEMORY;
+
+                    memcpy((*statement)->bind, old_bind, bind_size * sizeof(MYSQL_BIND));
+                    bind_size += bind_inc;
+                }
+                *p++ = '?'; q++;
             }
         }
-        else {
-            *p++ = *q;
-        }
-    } 
-    *p = 0;
-    if (!*statement) {
-        *statement = apr_palloc(pool, sizeof(apr_dbd_prepared_t));
     }
+
+    *p = 0;
+
     (*statement)->stmt = mysql_stmt_init(sql->conn);
 
-    if ((*statement)->stmt) {
-        apr_pool_cleanup_register(pool, (*statement)->stmt,
-                                  (void*)mysql_stmt_close,
-                                  apr_pool_cleanup_null);
-        return mysql_stmt_prepare((*statement)->stmt, myquery, strlen(myquery));
+    if(!(*statement)->stmt) ret = CR_OUT_OF_MEMORY;
+    else {
+        /* apr_pool_cleanup_register(pool, *statement, (void*)mysql_stmt_close,
+                                  apr_pool_cleanup_null); */
+        ret = mysql_stmt_prepare((*statement)->stmt, myquery, strlen(myquery));
+        if(!ret) {
+            nargs = mysql_stmt_param_count((*statement)->stmt);
+
+            if(nargs != bind_pos) ret = CR_INVALID_PARAMETER_NO; // SQL string probably has '?' characters we know nothing aboud
+        } else {
+	    ret = mysql_stmt_errno((*statement)->stmt);
+	}
     }
 
-    return APR_ENOMEM;
+    return ret;
+}
+
+static void bind_arg(MYSQL_BIND *bind, char *arg, my_bool* null_v)
+{
+    switch(bind->buffer_type) {
+        case MYSQL_TYPE_TINY:
+            bind->buffer = arg;
+            bind->buffer_length = 1;
+            break;
+        case MYSQL_TYPE_SHORT:
+            bind->buffer = arg;
+            bind->buffer_length = 2;
+            break;
+        case MYSQL_TYPE_LONG:
+            bind->buffer = arg;
+            bind->buffer_length = 4;
+            break;
+        case MYSQL_TYPE_LONGLONG:
+            bind->buffer = arg;
+            bind->buffer_length = 8;
+            break;
+        case MYSQL_TYPE_FLOAT:
+            bind->buffer = arg;
+            bind->buffer_length = 4;
+            break;
+        case MYSQL_TYPE_DOUBLE:
+            bind->buffer = arg;
+            bind->buffer_length = 8;
+            break;
+        case MYSQL_TYPE_STRING:
+            bind->buffer = arg;
+            bind->buffer_length = strlen(arg);
+            break;
+        case MYSQL_TYPE_BLOB:
+            bind->buffer = ((struct blob_t*)arg)->data;
+            bind->buffer_length = ((struct blob_t*)arg)->length;
+            break;
+        default:
+            bind->buffer_type = MYSQL_TYPE_NULL;
+            bind->buffer = 0;
+            bind->buffer_length = 0;
+            bind->length = 0;
+            bind->is_null = &null_v[1];
+        }
+
+        if(bind->buffer_type != MYSQL_TYPE_NULL) {
+
+            bind->length = &(bind->buffer_length);
+            bind->is_null = &null_v[0];
+        }
 }
 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 nqargs;
+    my_bool null_v[] = {FALSE, TRUE};
 
     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;
+    nqargs = mysql_stmt_param_count(statement->stmt);
+
+    for (i=0; i < nqargs; ++i) {
+	if(i < nargs) {
+            arg = (char*)values[i];
+        }
+        else {
+            statement->bind[i].buffer_type = MYSQL_TYPE_NULL;
+            arg = 0;
+        }
+        bind_arg(&statement->bind[i], arg, null_v);
     }
 
-    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);
     }
     else {
-        ret = mysql_stmt_execute(statement->stmt);
+        if((ret = mysql_stmt_execute(statement->stmt))) {
+	    ret = mysql_stmt_errno(statement->stmt);
+	}
+	
         *nrows = mysql_stmt_affected_rows(statement->stmt);
     }
     if (sql->trans) {
@@ -324,35 +517,33 @@
 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;
+    my_bool null_v[] = {FALSE, TRUE};
 
     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;
+        if(!(arg = va_arg(args, char*))) 
+            statement->bind[i].buffer_type = MYSQL_TYPE_NULL;
+
+        bind_arg(&statement->bind[i], arg, null_v);
     }
 
-    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);
     }
     else {
-        ret = mysql_stmt_execute(statement->stmt);
+        if((ret = mysql_stmt_execute(statement->stmt))) {
+	    ret = mysql_stmt_errno(statement->stmt);
+	}
         *nrows = mysql_stmt_affected_rows(statement->stmt);
     }
     if (sql->trans) {
@@ -368,33 +559,30 @@
     int i;
     int nfields;
     char *arg;
-    my_bool is_null = FALSE;
-    my_bool *is_nullr;
-#if MYSQL_VERSION_ID >= 50000
-    my_bool *error;
-#endif
+    my_bool null_v[] = {FALSE, TRUE};
     int ret;
-    unsigned long *length, maxlen;
-    MYSQL_BIND *bind;
+    int nqargs;
+    unsigned long *length;
+    char **data;
 
     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));
+    nqargs = mysql_stmt_param_count(statement->stmt);
 
     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(i < nargs) {
+            arg = (char*)args[i];
+        }
+        else {
+            statement->bind[i].buffer_type = MYSQL_TYPE_NULL;
+            arg = 0;
+        }
+        bind_arg(&statement->bind[i], arg, null_v);
     }
 
-    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) {
@@ -402,7 +590,7 @@
                 *res = apr_pcalloc(pool, sizeof(apr_dbd_results_t));
                 if (!*res) {
                     while (!mysql_stmt_fetch(statement->stmt));
-                    return -1;
+                    return CR_OUT_OF_MEMORY;
                 }
             }
             (*res)->random = random;
@@ -412,34 +600,49 @@
                 (void*)mysql_free_result, apr_pool_cleanup_null);
             nfields = mysql_num_fields((*res)->res);
             if (!(*res)->bind) {
-                (*res)->bind = apr_palloc(pool, nfields*sizeof(MYSQL_BIND));
+                (*res)->bind = apr_pcalloc(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));
+		data = apr_pcalloc(pool, nfields*sizeof(char*));
+
                 for ( i = 0; i < nfields; ++i ) {
-                    maxlen = (*res)->res->fields[i].length < FIELDSIZE ?
-                             (*res)->res->fields[i].length : FIELDSIZE;
-                    (*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[i].buffer_type = (*res)->res->fields[i].type;
+                    (*res)->bind[i].buffer_length = (*res)->res->fields[i].length;
+                    (*res)->bind[i].length = &length[i]; length[i] = (*res)->res->fields[i].length;
+		    (*res)->bind[i].is_unsigned = ((*res)->res->fields[i].flags & UNSIGNED_FLAG) ? 1 : 0;
+                    /* Types handled by fetch_result_bin */
+                    if((*res)->bind[i].buffer_type == MYSQL_TYPE_TINY_BLOB 
+                       || (*res)->bind[i].buffer_type == MYSQL_TYPE_MEDIUM_BLOB
+                       || (*res)->bind[i].buffer_type == MYSQL_TYPE_LONG_BLOB
+                       || (*res)->bind[i].buffer_type == MYSQL_TYPE_BLOB
+                       || (*res)->bind[i].buffer_type == MYSQL_TYPE_BIT) {
+                        /* Make room for an optional length field */
+                        data[i] = apr_palloc(pool, sizeof(struct blob_t) + (*res)->bind[i].buffer_length);
+                        (*res)->bind[i].buffer = ((struct blob_t*)(data[i]))->data;
+                    }
+                    else {
+                        data[i] = apr_palloc(pool, (*res)->bind[i].buffer_length);
+                        (*res)->bind[i].buffer = data[i];
+                    }
+                    (*res)->bind[i].is_null = 0;
                 }
             }
             ret = mysql_stmt_bind_result(statement->stmt, (*res)->bind);
             if (!ret) {
                 ret = mysql_stmt_store_result(statement->stmt);
-            }
-        }
+            } else {
+		ret = mysql_stmt_errno(statement->stmt);
+	    }
+        } else {
+	    ret = mysql_stmt_errno(statement->stmt);
+	}
+    } else {
+	ret = mysql_stmt_errno(statement->stmt);
     }
+    
     if (sql->trans) {
         sql->trans->errnum = ret;
     }
+
     return ret;
 }
 static int dbd_mysql_pvselect(apr_pool_t *pool, apr_dbd_t *sql,
@@ -450,34 +653,26 @@
     int i;
     int nfields;
     char *arg;
-    my_bool is_null = FALSE;
-    my_bool *is_nullr;
-#if MYSQL_VERSION_ID >= 50000
-    my_bool *error;
-#endif
+    my_bool null_v[] = {FALSE, TRUE};
     int ret;
-    unsigned long *length, maxlen;
+    unsigned long *length;
+    char **data;
     int nargs;
-    MYSQL_BIND *bind;
 
     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;
+        if(!(arg = va_arg(args, char*))) 
+            statement->bind[i].buffer_type = MYSQL_TYPE_NULL;
+
+        bind_arg(&statement->bind[i], arg, null_v);
     }
 
-    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) {
@@ -485,7 +680,7 @@
                 *res = apr_pcalloc(pool, sizeof(apr_dbd_results_t));
                 if (!*res) {
                     while (!mysql_stmt_fetch(statement->stmt));
-                    return -1;
+                    return CR_OUT_OF_MEMORY;
                 }
             }
             (*res)->random = random;
@@ -495,31 +690,45 @@
                 (void*)mysql_free_result, apr_pool_cleanup_null);
             nfields = mysql_num_fields((*res)->res);
             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));
+                (*res)->bind = apr_pcalloc(pool, nfields*sizeof(MYSQL_BIND));
+                length = apr_pcalloc(pool, nfields * sizeof(unsigned long));
+		data = apr_pcalloc(pool, nfields*sizeof(char*));
+
                 for ( i = 0; i < nfields; ++i ) {
-                    maxlen = (*res)->res->fields[i].length < FIELDSIZE ?
-                             (*res)->res->fields[i].length : FIELDSIZE;
-                    (*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[i].buffer_type = (*res)->res->fields[i].type;
+                    (*res)->bind[i].buffer_length = (*res)->res->fields[i].length;
+                    (*res)->bind[i].length = &length[i]; length[i] = (*res)->res->fields[i].length;
+    		    (*res)->bind[i].is_unsigned = ((*res)->res->fields[i].flags & UNSIGNED_FLAG) ? 1 : 0;
+                    /* Types handled by fetch_result_bin */
+                    if((*res)->bind[i].buffer_type == MYSQL_TYPE_TINY_BLOB 
+                       || (*res)->bind[i].buffer_type == MYSQL_TYPE_MEDIUM_BLOB
+                       || (*res)->bind[i].buffer_type == MYSQL_TYPE_LONG_BLOB
+                       || (*res)->bind[i].buffer_type == MYSQL_TYPE_BLOB
+                       || (*res)->bind[i].buffer_type == MYSQL_TYPE_BIT) {
+                        /* Make room for an optional length field */
+                        data[i] = apr_palloc(pool, sizeof(struct blob_t) + (*res)->bind[i].buffer_length);
+                        (*res)->bind[i].buffer = ((struct blob_t*)(data[i]))->data;
+                    }
+                    else {
+                        data[i] = apr_palloc(pool, (*res)->bind[i].buffer_length);
+                        (*res)->bind[i].buffer = data[i];
+                    }
+                    (*res)->bind[i].is_null = 0;
                 }
             }
             ret = mysql_stmt_bind_result(statement->stmt, (*res)->bind);
             if (!ret) {
                 ret = mysql_stmt_store_result(statement->stmt);
-            }
-        }
+            } else {
+		ret = mysql_stmt_errno(statement->stmt);
+	    }
+        } else {
+	    ret = mysql_stmt_errno(statement->stmt);
+	}
+    } else {
+	ret = mysql_stmt_errno(statement->stmt);
     }
+    
     if (sql->trans) {
         sql->trans->errnum = ret;
     }
@@ -538,7 +747,6 @@
         }
     }
     ret |= mysql_autocommit(trans->handle->conn, 1);
-    trans->handle->trans = NULL;
     return ret;
 }
 /* Whether or not transactions work depends on whether the
@@ -617,7 +825,10 @@
     sql->conn = mysql_real_connect(sql->conn, fields[0].value,
                                    fields[1].value, fields[2].value,
                                    fields[3].value, port,
-                                   fields[5].value, CLIENT_FOUND_ROWS);
+                                   fields[5].value, 0);
+
+    if(!sql->conn) return 0; /* this is important */
+
     return sql;
 }
 static apr_status_t dbd_mysql_close(apr_dbd_t *handle)
@@ -628,13 +839,7 @@
 static apr_status_t dbd_mysql_check_conn(apr_pool_t *pool,
                                          apr_dbd_t *handle)
 {
-    return handle
-	? handle->conn
-	    ? mysql_ping(handle->conn)
-	        ? APR_EGENERAL
-		: APR_SUCCESS
-	    : APR_EGENERAL
-	: APR_EGENERAL;
+    return mysql_ping(handle->conn) ? APR_EGENERAL : APR_SUCCESS;
 }
 static int dbd_mysql_select_db(apr_pool_t *pool, apr_dbd_t* handle,
                                const char* name)
@@ -670,7 +875,8 @@
 }
 static void dbd_mysql_init(apr_pool_t *pool)
 {
-    my_init();
+    //my_init(); - called by mysql_init anyway
+
     /* FIXME: this is a guess; find out what it really does */ 
     apr_pool_cleanup_register(pool, NULL, apr_pool_cleanup_null,
                               (void*)mysql_thread_end);
@@ -697,10 +903,9 @@
     dbd_mysql_pvquery,
     dbd_mysql_pvselect,
     dbd_mysql_pquery,
-    dbd_mysql_pselect
+    dbd_mysql_pselect,
 #if APU_MAJOR_VERSION >= 2 || (APU_MAJOR_VERSION == 1 && APU_MINOR_VERSION >= 3)
-    ,
-    dbd_mysql_get_name
+    dbd_mysql_get_name,
 #endif
 };
 
