Quoting Bojan Smojver <[EMAIL PROTECTED]>:

And here is the patch that does exactly that. I'll follow this up with
another e-mail where I'll include some other, related stuff. This is
due to list size restrictions.

As promised...

--
Bojan
Index: apr_dbd_mysql.c
===================================================================
--- apr_dbd_mysql.c	(revision 51)
+++ apr_dbd_mysql.c	(working copy)
@@ -54,6 +54,7 @@
 #endif
 
 #include "apr_strings.h"
+#include "apr_buckets.h"
 
 #include "apr_dbd_internal.h"
 
@@ -62,6 +63,10 @@
 
 struct apr_dbd_prepared_t {
     MYSQL_STMT* stmt;
+#if APU_MAJOR_VERSION >= 2 || (APU_MAJOR_VERSION == 1 && APU_MINOR_VERSION >= 3)
+    int nargs;
+    apr_dbd_type_e *types;
+#endif
 };
 
 struct apr_dbd_transaction_t {
@@ -83,12 +88,156 @@
     MYSQL_RES *res;
     MYSQL_STMT *statement;
     MYSQL_BIND *bind;
+#if APU_MAJOR_VERSION >= 2 || (APU_MAJOR_VERSION == 1 && APU_MINOR_VERSION >= 3)
+    apr_pool_t *pool;
+#endif
 };
 struct apr_dbd_row_t {
     MYSQL_ROW row;
     apr_dbd_results_t *res;
+#if APU_MAJOR_VERSION >= 2 || (APU_MAJOR_VERSION == 1 && APU_MINOR_VERSION >= 3)
+    unsigned long *len;
+#endif
 };
 
+#if APU_MAJOR_VERSION >= 2 || (APU_MAJOR_VERSION == 1 && APU_MINOR_VERSION >= 3)
+/* MySQL specific bucket for BLOB types */
+typedef struct apr_bucket_blob apr_bucket_blob;
+/**
+ * A bucket referring to a MySQL BLOB
+ */
+struct apr_bucket_blob {
+    /** Number of buckets using this memory */
+    apr_bucket_refcount  refcount;
+    /** The row this bucket refers to */
+    const apr_dbd_row_t *row;
+    /** The column this bucket refers to */
+    int col;
+    /** The pool into which any needed structures should
+     *  be created while reading from this bucket */
+    apr_pool_t *readpool;
+};
+
+static void blob_bucket_destroy(void *data);
+static apr_status_t blob_bucket_read(apr_bucket *e, const char **str,
+                                     apr_size_t *len, apr_read_type_e block);
+static apr_bucket *apr_bucket_blob_make(apr_bucket *b,
+                                        const apr_dbd_row_t *row, int col,
+                                        apr_off_t offset, apr_size_t len,
+                                        apr_pool_t *p);
+static apr_bucket *apr_bucket_blob_create(const apr_dbd_row_t *row, int col,
+                                          apr_off_t offset,
+                                          apr_size_t len, apr_pool_t *p,
+                                          apr_bucket_alloc_t *list);
+
+const apr_bucket_type_t apr_bucket_type_blob = {
+    "BLOB", 5, APR_BUCKET_DATA,
+    blob_bucket_destroy,
+    blob_bucket_read,
+    apr_bucket_setaside_notimpl,
+    apr_bucket_shared_split,
+    apr_bucket_shared_copy
+};
+
+static void blob_bucket_destroy(void *data)
+{
+    apr_bucket_blob *f = data;
+
+    if (apr_bucket_shared_destroy(f)) {
+        /* no need to destroy database objects here; it will get
+         * done automatically when the pool gets cleaned up */
+        apr_bucket_free(f);
+    }
+}
+
+static apr_status_t blob_bucket_read(apr_bucket *e, const char **str,
+                                     apr_size_t *len, apr_read_type_e block)
+{
+    apr_bucket_blob *a = e->data;
+    const apr_dbd_row_t *row = a->row;
+    apr_dbd_results_t *res = row->res;
+    int col = a->col;
+    apr_bucket *b = NULL;
+    int rv;
+    apr_size_t blength = e->length;  /* bytes remaining in file past offset */
+    apr_off_t boffset = e->start;
+    MYSQL_BIND *bind = &res->bind[col];
+
+    *str = NULL;  /* in case we die prematurely */
+
+    /* fetch from offset if not at the beginning */
+    if (boffset > 0) {
+        rv = mysql_stmt_fetch_column(res->statement, bind, col, boffset);
+        if (rv != 0) {
+            return APR_EGENERAL;
+        }
+    }
+    blength -= blength > bind->buffer_length ? bind->buffer_length : blength;
+    *len = e->length - blength;
+    *str = bind->buffer;
+
+    /* allocate new buffer, since we used this one for the bucket */
+    bind->buffer = apr_palloc(res->pool, bind->buffer_length);
+
+    /*
+     * Change the current bucket to refer to what we read,
+     * even if we read nothing because we hit EOF.
+     */
+    apr_bucket_pool_make(e, *str, *len, res->pool);
+
+    /* If we have more to read from the field, then create another bucket */
+    if (blength > 0) {
+        /* for efficiency, we can just build a new apr_bucket struct
+         * to wrap around the existing blob bucket */
+        b = apr_bucket_alloc(sizeof(*b), e->list);
+        b->start  = boffset + *len;
+        b->length = blength;
+        b->data   = a;
+        b->type   = &apr_bucket_type_blob;
+        b->free   = apr_bucket_free;
+        b->list   = e->list;
+        APR_BUCKET_INSERT_AFTER(e, b);
+    }
+    else {
+        blob_bucket_destroy(a);
+    }
+
+    return APR_SUCCESS;
+}
+
+static apr_bucket *apr_bucket_blob_make(apr_bucket *b,
+                                        const apr_dbd_row_t *row, int col,
+                                        apr_off_t offset, apr_size_t len,
+                                        apr_pool_t *p)
+{
+    apr_bucket_blob *f;
+
+    f = apr_bucket_alloc(sizeof(*f), b->list);
+    f->row = row;
+    f->col = col;
+    f->readpool = p;
+
+    b = apr_bucket_shared_make(b, f, offset, len);
+    b->type = &apr_bucket_type_blob;
+
+    return b;
+}
+
+static apr_bucket *apr_bucket_blob_create(const apr_dbd_row_t *row, int col,
+                                          apr_off_t offset,
+                                          apr_size_t len, apr_pool_t *p,
+                                          apr_bucket_alloc_t *list)
+{
+    apr_bucket *b = apr_bucket_alloc(sizeof(*b), list);
+
+    APR_BUCKET_INIT(b);
+    b->free = apr_bucket_free;
+    b->list = list;
+    return apr_bucket_blob_make(b, row, col, offset, len, p);
+}
+
+#endif
+
 static apr_status_t free_result(void *data)
 {
     mysql_free_result(data);
@@ -112,6 +261,9 @@
             }
             (*results)->random = seek;
             (*results)->statement = NULL;
+#if APU_MAJOR_VERSION >= 2 || (APU_MAJOR_VERSION == 1 && APU_MINOR_VERSION >= 3)
+            (*results)->pool = pool;
+#endif
             if (seek) {
                 (*results)->res = mysql_store_result(sql->conn);
             }
@@ -145,6 +297,7 @@
     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)
 {
@@ -187,6 +340,9 @@
         }
         (*row)->row = r;
         (*row)->res = res;
+#if APU_MAJOR_VERSION >= 2 || (APU_MAJOR_VERSION == 1 && APU_MINOR_VERSION >= 3)
+        (*row)->len = mysql_fetch_lengths(res->res);
+#endif
     }
     else {
         apr_pool_cleanup_run(pool, res->res, free_result);
@@ -221,6 +377,7 @@
     return 0;
 }
 #else
+
 static const char *dbd_mysql_get_entry(const apr_dbd_row_t *row, int n)
 {
     MYSQL_BIND *bind;
@@ -239,13 +396,166 @@
     else {
         return row->row[n];
     }
+    return NULL;
+}
+#endif
+
+#if APU_MAJOR_VERSION >= 2 || (APU_MAJOR_VERSION == 1 && APU_MINOR_VERSION >= 3)
+static apr_status_t dbd_mysql_datum_get(const apr_dbd_row_t *row, int n,
+                                        apr_dbd_type_e type, void *data)
+{
+    if (row->res->statement) {
+        MYSQL_BIND *bind = &row->res->bind[n];
+        unsigned long len = *bind->length;
+
+        if (mysql_stmt_fetch_column(row->res->statement, bind, n, 0) != 0) {
+            return APR_EGENERAL;
+        }
+
+        if (*bind->is_null) {
+            return APR_ENOENT;
+        }
+
+        switch (type) {
+        case APR_DBD_TYPE_TINY:
+            *(char*)data = atoi(bind->buffer);
+            break;
+        case APR_DBD_TYPE_UTINY:
+            *(unsigned char*)data = atoi(bind->buffer);
+            break;
+        case APR_DBD_TYPE_SHORT:
+            *(short*)data = atoi(bind->buffer);
+            break;
+        case APR_DBD_TYPE_USHORT:
+            *(unsigned short*)data = atoi(bind->buffer);
+            break;
+        case APR_DBD_TYPE_INT:
+            *(int*)data = atoi(bind->buffer);
+            break;
+        case APR_DBD_TYPE_UINT:
+            *(unsigned int*)data = atoi(bind->buffer);
+            break;
+        case APR_DBD_TYPE_LONG:
+            *(long*)data = atol(bind->buffer);
+            break;
+        case APR_DBD_TYPE_ULONG:
+            *(unsigned long*)data = atol(bind->buffer);
+            break;
+        case APR_DBD_TYPE_LONGLONG:
+            *(apr_int64_t*)data = apr_atoi64(bind->buffer);
+            break;
+        case APR_DBD_TYPE_ULONGLONG:
+            *(apr_uint64_t*)data = apr_atoi64(bind->buffer);
+            break;
+        case APR_DBD_TYPE_FLOAT:
+            *(float*)data = atof(bind->buffer);
+            break;
+        case APR_DBD_TYPE_DOUBLE:
+            *(double*)data = atof(bind->buffer);
+            break;
+        case APR_DBD_TYPE_STRING:
+        case APR_DBD_TYPE_TEXT:
+        case APR_DBD_TYPE_TIME:
+        case APR_DBD_TYPE_DATE:
+        case APR_DBD_TYPE_DATETIME:
+        case APR_DBD_TYPE_TIMESTAMP:
+        case APR_DBD_TYPE_ZTIMESTAMP:
+            *(char**)data = bind->buffer;
+            break;
+        case APR_DBD_TYPE_BLOB:
+            {
+            apr_bucket *e;
+            apr_bucket_brigade *b = (apr_bucket_brigade*)data;
+
+            e = apr_bucket_blob_create(row, n, 0, len,
+                                       row->res->pool, b->bucket_alloc);
+            APR_BRIGADE_INSERT_TAIL(b, e);
+            }
+            break;
+        case APR_DBD_TYPE_NULL:
+            *(void**)data = NULL;
+            break;
+        default:
+            return APR_EGENERAL;
+        }
+    }
+    else {
+        if (row->row[n] == NULL) {
+            return APR_ENOENT;
+        }
+
+        switch (type) {
+        case APR_DBD_TYPE_TINY:
+            *(char*)data = atoi(row->row[n]);
+            break;
+        case APR_DBD_TYPE_UTINY:
+            *(unsigned char*)data = atoi(row->row[n]);
+            break;
+        case APR_DBD_TYPE_SHORT:
+            *(short*)data = atoi(row->row[n]);
+            break;
+        case APR_DBD_TYPE_USHORT:
+            *(unsigned short*)data = atoi(row->row[n]);
+            break;
+        case APR_DBD_TYPE_INT:
+            *(int*)data = atoi(row->row[n]);
+            break;
+        case APR_DBD_TYPE_UINT:
+            *(unsigned int*)data = atoi(row->row[n]);
+            break;
+        case APR_DBD_TYPE_LONG:
+            *(long*)data = atol(row->row[n]);
+            break;
+        case APR_DBD_TYPE_ULONG:
+            *(unsigned long*)data = atol(row->row[n]);
+            break;
+        case APR_DBD_TYPE_LONGLONG:
+            *(apr_int64_t*)data = apr_atoi64(row->row[n]);
+            break;
+        case APR_DBD_TYPE_ULONGLONG:
+            *(apr_uint64_t*)data = apr_atoi64(row->row[n]);
+            break;
+        case APR_DBD_TYPE_FLOAT:
+            *(float*)data = atof(row->row[n]);
+            break;
+        case APR_DBD_TYPE_DOUBLE:
+            *(double*)data = atof(row->row[n]);
+            break;
+        case APR_DBD_TYPE_STRING:
+        case APR_DBD_TYPE_TEXT:
+        case APR_DBD_TYPE_TIME:
+        case APR_DBD_TYPE_DATE:
+        case APR_DBD_TYPE_DATETIME:
+        case APR_DBD_TYPE_TIMESTAMP:
+        case APR_DBD_TYPE_ZTIMESTAMP:
+            *(char**)data = row->row[n];
+            break;
+        case APR_DBD_TYPE_BLOB:
+            {
+            apr_bucket *e;
+            apr_bucket_brigade *b = (apr_bucket_brigade*)data;
+
+            e = apr_bucket_pool_create(row->row[n], row->len[n],
+                                       row->res->pool, b->bucket_alloc);
+            APR_BRIGADE_INSERT_TAIL(b, e);
+            }
+            break;
+        case APR_DBD_TYPE_NULL:
+            *(void**)data = NULL;
+            break;
+        default:
+            return APR_EGENERAL;
+        }
+    }
     return 0;
 }
 #endif
+
 static const char *dbd_mysql_error(apr_dbd_t *sql, int n)
 {
     return mysql_error(sql->conn);
 }
+
 static int dbd_mysql_query(apr_dbd_t *sql, int *nrows, const char *query)
 {
     int ret;
@@ -266,6 +576,7 @@
     }
     return ret;
 }
+
 static const char *dbd_mysql_escape(apr_pool_t *pool, const char *arg,
                                     apr_dbd_t *sql)
 {
@@ -274,16 +585,486 @@
     mysql_real_escape_string(sql->conn, ret, arg, len);
     return ret;
 }
+
 static apr_status_t stmt_close(void *data)
 {
     mysql_stmt_close(data);
     return APR_SUCCESS;
 }
+
+#if APU_MAJOR_VERSION >= 2 || (APU_MAJOR_VERSION == 1 && APU_MINOR_VERSION >= 3)
 static int dbd_mysql_prepare(apr_pool_t *pool, apr_dbd_t *sql,
                              const char *query, const char *label,
+                             int nargs, apr_dbd_type_e *types,
                              apr_dbd_prepared_t **statement)
 {
     /* Translate from apr_dbd to native query format */
+    int ret;
+
+    if (!*statement) {
+        *statement = apr_palloc(pool, sizeof(apr_dbd_prepared_t));
+    }
+    (*statement)->stmt = mysql_stmt_init(sql->conn);
+
+    if ((*statement)->stmt) {
+        apr_pool_cleanup_register(pool, (*statement)->stmt,
+                                  stmt_close, apr_pool_cleanup_null);
+        ret = mysql_stmt_prepare((*statement)->stmt, query, strlen(query));
+
+        if (ret != 0) {
+            ret = mysql_stmt_errno((*statement)->stmt);
+        }
+
+        (*statement)->nargs = nargs;
+        (*statement)->types = types;
+
+        return ret;
+    }
+
+    return CR_OUT_OF_MEMORY;
+}
+
+static void dbd_mysql_bind(apr_dbd_prepared_t *statement,
+                           int nargs, const char **values, MYSQL_BIND *bind)
+{
+    int i, j;
+    my_bool is_null = FALSE;
+
+    for (i = 0; i < nargs; i++) {
+        bind[i].length = &bind[i].buffer_length;
+        bind[i].is_null = &is_null;
+        bind[i].is_unsigned = 0;
+
+        if (values[i] == NULL) {
+            bind[i].buffer_type = MYSQL_TYPE_NULL;
+        }
+        else {
+            if (statement->types[i] == APR_DBD_TYPE_BLOB) {
+                char *data = (char*)values[i];
+
+                /* encoding: length:table:column:payload */
+                for (j = 0; j < 3; j++) {
+                    data = strchr(data, ':');
+                    data++;
+                }
+
+                bind[i].buffer_type = MYSQL_TYPE_LONG_BLOB;
+                bind[i].buffer = data;
+                bind[i].buffer_length = atoi(values[i]);
+            }
+            else {
+                bind[i].buffer_type = MYSQL_TYPE_VAR_STRING;
+                bind[i].buffer = (void*)values[i];
+                bind[i].buffer_length = strlen(values[i]);
+            }
+        }
+    }
+
+    return;
+}
+
+static int dbd_mysql_pquery_internal(apr_pool_t *pool, apr_dbd_t *sql,
+                                     int *nrows, apr_dbd_prepared_t *statement,
+                                     MYSQL_BIND *bind)
+{
+    int ret;
+
+    ret = mysql_stmt_bind_param(statement->stmt, bind);
+    if (ret != 0) {
+        *nrows = 0;
+        ret = mysql_stmt_errno(statement->stmt);
+    }
+    else {
+        ret = mysql_stmt_execute(statement->stmt);
+        if (ret != 0) {
+            ret = mysql_stmt_errno(statement->stmt);
+        }
+        *nrows = mysql_stmt_affected_rows(statement->stmt);
+    }
+
+    return ret;
+}
+
+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;
+    int ret;
+
+    if (sql->trans && sql->trans->errnum) {
+        return sql->trans->errnum;
+    }
+
+    bind = apr_palloc(pool, nargs * sizeof(MYSQL_BIND));
+
+    dbd_mysql_bind(statement, nargs, values, bind);
+
+    ret = dbd_mysql_pquery_internal(pool, sql, nrows, statement, bind);
+
+    if (TXN_NOTICE_ERRORS(sql->trans)) {
+        sql->trans->errnum = ret;
+    }
+    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)
+{
+    const char **values;
+    int i;
+
+    if (sql->trans && sql->trans->errnum) {
+        return sql->trans->errnum;
+    }
+
+    values = apr_palloc(pool, sizeof(*values) * statement->nargs);
+
+    for (i = 0; i < statement->nargs; i++) {
+        values[i] = va_arg(args, const char*);
+    }
+
+    return dbd_mysql_pquery(pool, sql, nrows, statement,
+                            statement->nargs, values);
+}
+
+static int dbd_mysql_pselect_internal(apr_pool_t *pool, apr_dbd_t *sql,
+                                      apr_dbd_results_t **res,
+                                      apr_dbd_prepared_t *statement,
+                                      int random, MYSQL_BIND *bind)
+{
+    int nfields, i;
+    my_bool *is_nullr;
+#if MYSQL_VERSION_ID >= 50000
+    my_bool *error;
+#endif
+    int ret;
+    unsigned long *length, maxlen;
+
+    ret = mysql_stmt_bind_param(statement->stmt, bind);
+    if (ret == 0) {
+        ret = mysql_stmt_execute(statement->stmt);
+        if (!ret) {
+            if (!*res) {
+                *res = apr_pcalloc(pool, sizeof(apr_dbd_results_t));
+            }
+            (*res)->random = random;
+            (*res)->statement = statement->stmt;
+            (*res)->res = mysql_stmt_result_metadata(statement->stmt);
+            (*res)->pool = pool;
+            apr_pool_cleanup_register(pool, (*res)->res,
+                                      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));
+                for ( i = 0; i < nfields; ++i ) {
+                    maxlen = (*res)->res->fields[i].length < sql->fldsz ?
+                             (*res)->res->fields[i].length : sql->fldsz;
+                    if ((*res)->res->fields[i].type == MYSQL_TYPE_BLOB) {
+                        (*res)->bind[i].buffer_type = MYSQL_TYPE_LONG_BLOB;
+                    }
+                    else {
+                        (*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
+                }
+            }
+            ret = mysql_stmt_bind_result(statement->stmt, (*res)->bind);
+            if (!ret) {
+                ret = mysql_stmt_store_result(statement->stmt);
+            }
+        }
+    }
+    if (ret != 0) {
+        ret = mysql_stmt_errno(statement->stmt);
+    }
+
+    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 ret;
+    MYSQL_BIND *bind;
+
+    if (sql->trans && sql->trans->errnum) {
+        return sql->trans->errnum;
+    }
+
+    bind = apr_palloc(pool, nargs * sizeof(MYSQL_BIND));
+
+    dbd_mysql_bind(statement, nargs, args, bind);
+
+    ret = dbd_mysql_pselect_internal(pool, sql,  res, statement, random, bind);
+
+    if (TXN_NOTICE_ERRORS(sql->trans)) {
+        sql->trans->errnum = ret;
+    }
+    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)
+{
+    const char **values;
+    int i;
+
+    if (sql->trans && sql->trans->errnum) {
+        return sql->trans->errnum;
+    }
+
+    values = apr_palloc(pool, sizeof(*values) * statement->nargs);
+
+    for (i = 0; i < statement->nargs; i++) {
+        values[i] = va_arg(args, const char*);
+    }
+
+    return dbd_mysql_pselect(pool, sql, res, statement, random,
+                             statement->nargs, values);
+}
+
+static void dbd_mysql_bbind(apr_pool_t *pool, apr_dbd_prepared_t *statement,
+                            int nargs, const void **values, MYSQL_BIND *bind)
+{
+    void *arg;
+    int i;
+    my_bool is_null = FALSE;
+    apr_dbd_type_e type;
+
+    for (i = 0; i < nargs; i++) {
+        arg = (void *)values[i];
+
+        bind[i].length = &bind[i].buffer_length;
+        bind[i].is_null = &is_null;
+
+        type = (values[i] == NULL ? APR_DBD_TYPE_NULL : statement->types[i]);
+        switch (type) {
+        case APR_DBD_TYPE_TINY:
+            bind[i].buffer = arg;
+            bind[i].buffer_type = MYSQL_TYPE_TINY;
+            bind[i].is_unsigned = 0;
+            break;
+        case APR_DBD_TYPE_UTINY:
+            bind[i].buffer = arg;
+            bind[i].buffer_type = MYSQL_TYPE_TINY;
+            bind[i].is_unsigned = 1;
+            break;
+        case APR_DBD_TYPE_SHORT:
+            bind[i].buffer = arg;
+            bind[i].buffer_type = MYSQL_TYPE_SHORT;
+            bind[i].is_unsigned = 0;
+            break;
+        case APR_DBD_TYPE_USHORT:
+            bind[i].buffer = arg;
+            bind[i].buffer_type = MYSQL_TYPE_SHORT;
+            bind[i].is_unsigned = 1;
+            break;
+        case APR_DBD_TYPE_INT:
+            bind[i].buffer = arg;
+            bind[i].buffer_type = MYSQL_TYPE_LONG;
+            bind[i].is_unsigned = 0;
+            break;
+        case APR_DBD_TYPE_UINT:
+            bind[i].buffer = arg;
+            bind[i].buffer_type = MYSQL_TYPE_LONG;
+            bind[i].is_unsigned = 1;
+            break;
+        case APR_DBD_TYPE_LONG:
+            if (sizeof(int) == sizeof(long)) {
+                bind[i].buffer = arg;
+            }
+            else {
+                bind[i].buffer = apr_palloc(pool, sizeof(int));
+                *(int*)bind[i].buffer = *(long*)arg;
+            }
+            bind[i].buffer_type = MYSQL_TYPE_LONG;
+            bind[i].is_unsigned = 0;
+            break;
+        case APR_DBD_TYPE_ULONG:
+            if (sizeof(unsigned int) == sizeof(unsigned long)) {
+                bind[i].buffer = arg;
+            }
+            else {
+                bind[i].buffer = apr_palloc(pool, sizeof(unsigned int));
+                *(unsigned int*)bind[i].buffer = *(unsigned long*)arg;
+            }
+            bind[i].buffer_type = MYSQL_TYPE_LONG;
+            bind[i].is_unsigned = 1;
+            break;
+        case APR_DBD_TYPE_LONGLONG:
+            if (sizeof(long long) == sizeof(apr_int64_t)) {
+                bind[i].buffer = arg;
+            }
+            else {
+                bind[i].buffer = apr_palloc(pool, sizeof(long long));
+                *(long long*)bind[i].buffer = *(apr_int64_t*)arg;
+            }
+            bind[i].buffer_type = MYSQL_TYPE_LONGLONG;
+            bind[i].is_unsigned = 0;
+            break;
+        case APR_DBD_TYPE_ULONGLONG:
+            if (sizeof(unsigned long long) == sizeof(apr_uint64_t)) {
+                bind[i].buffer = arg;
+            }
+            else {
+                bind[i].buffer = apr_palloc(pool, sizeof(unsigned long long));
+                *(unsigned long long*)bind[i].buffer = *(apr_uint64_t*)arg;
+            }
+            bind[i].buffer_type = MYSQL_TYPE_LONGLONG;
+            bind[i].is_unsigned = 1;
+            break;
+        case APR_DBD_TYPE_FLOAT:
+            bind[i].buffer = arg;
+            bind[i].buffer_type = MYSQL_TYPE_FLOAT;
+            bind[i].is_unsigned = 0;
+            break;
+        case APR_DBD_TYPE_DOUBLE:
+            bind[i].buffer = arg;
+            bind[i].buffer_type = MYSQL_TYPE_DOUBLE;
+            bind[i].is_unsigned = 0;
+            break;
+        case APR_DBD_TYPE_STRING:
+        case APR_DBD_TYPE_TEXT:
+        case APR_DBD_TYPE_TIME:
+        case APR_DBD_TYPE_DATE:
+        case APR_DBD_TYPE_DATETIME:
+        case APR_DBD_TYPE_TIMESTAMP:
+        case APR_DBD_TYPE_ZTIMESTAMP:
+            bind[i].buffer = arg;
+            bind[i].buffer_type = MYSQL_TYPE_VAR_STRING;
+            bind[i].is_unsigned = 0;
+            bind[i].buffer_length = strlen((const char *)arg);
+            break;
+        case APR_DBD_TYPE_BLOB:
+            {
+            apr_dbd_blob_t *blob = (void *)arg;
+
+            bind[i].buffer = (void *)blob->data;
+            bind[i].buffer_type = MYSQL_TYPE_LONG_BLOB;
+            bind[i].is_unsigned = 0;
+            bind[i].buffer_length = blob->size;
+            }
+            break;
+        case APR_DBD_TYPE_NULL:
+        default:
+            bind[i].buffer_type = MYSQL_TYPE_NULL;
+            break;
+        }
+    }
+
+    return;
+}
+
+static int dbd_mysql_pbquery(apr_pool_t *pool, apr_dbd_t *sql,
+                             int *nrows, apr_dbd_prepared_t *statement,
+                             int nargs, const void **values)
+{
+    MYSQL_BIND *bind;
+    int ret;
+
+    if (sql->trans && sql->trans->errnum) {
+        return sql->trans->errnum;
+    }
+
+    bind = apr_palloc(pool, nargs * sizeof(MYSQL_BIND));
+
+    dbd_mysql_bbind(pool, statement, nargs, values, bind);
+
+    ret = dbd_mysql_pquery_internal(pool, sql, nrows, statement, bind);
+
+    if (TXN_NOTICE_ERRORS(sql->trans)) {
+        sql->trans->errnum = ret;
+    }
+    return ret;
+}
+
+static int dbd_mysql_pvbquery(apr_pool_t *pool, apr_dbd_t *sql, int *nrows,
+                              apr_dbd_prepared_t *statement, va_list args)
+{
+    const void **values;
+    int i;
+
+    if (sql->trans && sql->trans->errnum) {
+        return sql->trans->errnum;
+    }
+
+    values = apr_palloc(pool, sizeof(*values) * statement->nargs);
+
+    for (i = 0; i < statement->nargs; i++) {
+        values[i] = va_arg(args, void*);
+    }
+
+    return dbd_mysql_pbquery(pool, sql, nrows, statement,
+                             statement->nargs, values);
+}
+
+static int dbd_mysql_pbselect(apr_pool_t *pool, apr_dbd_t *sql,
+                              apr_dbd_results_t **res,
+                              apr_dbd_prepared_t *statement, int random,
+                              int nargs, const void **args)
+{
+    int ret;
+    MYSQL_BIND *bind;
+
+    if (sql->trans && sql->trans->errnum) {
+        return sql->trans->errnum;
+    }
+
+    bind = apr_palloc(pool, nargs * sizeof(MYSQL_BIND));
+
+    dbd_mysql_bbind(pool, statement, nargs, args, bind);
+
+    ret = dbd_mysql_pselect_internal(pool, sql,  res, statement, random, bind);
+
+    if (TXN_NOTICE_ERRORS(sql->trans)) {
+        sql->trans->errnum = ret;
+    }
+    return ret;
+}
+
+static int dbd_mysql_pvbselect(apr_pool_t *pool, apr_dbd_t *sql,
+                               apr_dbd_results_t **res,
+                               apr_dbd_prepared_t *statement, int random,
+                               va_list args)
+{
+    const void **values;
+    int i;
+
+    if (sql->trans && sql->trans->errnum) {
+        return sql->trans->errnum;
+    }
+
+    values = apr_palloc(pool, sizeof(*values) * statement->nargs);
+
+    for (i = 0; i < statement->nargs; i++) {
+        values[i] = va_arg(args, void*);
+    }
+
+    return dbd_mysql_pbselect(pool, sql, res, statement, random,
+                              statement->nargs, values);
+}
+#else
+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;
@@ -326,6 +1107,7 @@
 
     return CR_OUT_OF_MEMORY;
 }
+
 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)
@@ -364,15 +1146,12 @@
         }
         *nrows = mysql_stmt_affected_rows(statement->stmt);
     }
-#if APU_MAJOR_VERSION >= 2 || (APU_MAJOR_VERSION == 1 && APU_MINOR_VERSION >= 3)
-    if (TXN_NOTICE_ERRORS(sql->trans)) {
-#else
     if (sql->trans) {
-#endif
         sql->trans->errnum = ret;
     }
     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)
 {
@@ -411,15 +1190,12 @@
         }
         *nrows = mysql_stmt_affected_rows(statement->stmt);
     }
-#if APU_MAJOR_VERSION >= 2 || (APU_MAJOR_VERSION == 1 && APU_MINOR_VERSION >= 3)
-    if (TXN_NOTICE_ERRORS(sql->trans)) {
-#else
     if (sql->trans) {
-#endif
         sql->trans->errnum = ret;
     }
     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,
@@ -496,15 +1272,12 @@
     if (ret != 0) {
         ret = mysql_stmt_errno(statement->stmt);
     }
-#if APU_MAJOR_VERSION >= 2 || (APU_MAJOR_VERSION == 1 && APU_MINOR_VERSION >= 3)
-    if (TXN_NOTICE_ERRORS(sql->trans)) {
-#else
     if (sql->trans) {
-#endif
         sql->trans->errnum = ret;
     }
     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,
@@ -582,15 +1355,13 @@
     if (ret != 0) {
         ret = mysql_stmt_errno(statement->stmt);
     }
-#if APU_MAJOR_VERSION >= 2 || (APU_MAJOR_VERSION == 1 && APU_MINOR_VERSION >= 3)
-    if (TXN_NOTICE_ERRORS(sql->trans)) {
-#else
     if (sql->trans) {
-#endif
         sql->trans->errnum = ret;
     }
     return ret;
 }
+#endif
+
 static int dbd_mysql_end_transaction(apr_dbd_transaction_t *trans)
 {
     int ret = -1;
@@ -616,6 +1387,7 @@
  * underlying DB supports them within MySQL.  Unfortunately
  * it fails silently with the default InnoDB.
  */
+
 static int dbd_mysql_transaction(apr_pool_t *pool, apr_dbd_t *handle,
                                  apr_dbd_transaction_t **trans)
 {
@@ -631,6 +1403,7 @@
     handle->trans = *trans;
     return (*trans)->errnum;
 }
+
 #if APU_MAJOR_VERSION >= 2 || (APU_MAJOR_VERSION == 1 && APU_MINOR_VERSION >= 3)
 static int dbd_mysql_transaction_mode_get(apr_dbd_transaction_t *trans)
 {
@@ -649,6 +1422,7 @@
     return trans->mode = (mode & TXN_MODE_BITS);
 }
 #endif
+
 static apr_dbd_t *dbd_mysql_open(apr_pool_t *pool, const char *params)
 {
     static const char *const delims = " \r\n\t;|,";
@@ -701,7 +1475,7 @@
         ++key;
         for (value = ptr+1; isspace(*value); ++value);
         vlen = strcspn(value, delims);
-        for (i=0; fields[i].field != NULL; ++i) {
+        for (i = 0; fields[i].field != NULL; i++) {
             if (!strncasecmp(fields[i].field, key, klen)) {
                 fields[i].value = apr_pstrndup(pool, value, vlen);
                 break;
@@ -736,25 +1510,30 @@
 
     return sql;
 }
+
 static apr_status_t dbd_mysql_close(apr_dbd_t *handle)
 {
     mysql_close(handle->conn);
     return APR_SUCCESS;
 }
+
 static apr_status_t dbd_mysql_check_conn(apr_pool_t *pool,
                                          apr_dbd_t *handle)
 {
     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)
 {
     return mysql_select_db(handle->conn, name);
 }
+
 static void *dbd_mysql_native(apr_dbd_t *handle)
 {
     return handle->conn;
 }
+
 static int dbd_mysql_num_cols(apr_dbd_results_t *res)
 {
     if (res->statement) {
@@ -764,6 +1543,7 @@
         return mysql_num_fields(res->res);
     }
 }
+
 static int dbd_mysql_num_tuples(apr_dbd_results_t *res)
 {
     if (res->random) {
@@ -778,11 +1558,13 @@
         return -1;
     }
 }
+
 static apr_status_t thread_end(void *data)
 {
     mysql_thread_end();
     return APR_SUCCESS;
 }
+
 static void dbd_mysql_init(apr_pool_t *pool)
 {
     my_init();
@@ -816,9 +1598,14 @@
     ,
     dbd_mysql_get_name,
     dbd_mysql_transaction_mode_get,
-    dbd_mysql_transaction_mode_set
+    dbd_mysql_transaction_mode_set,
+    "?",
+    dbd_mysql_pvbquery,
+    dbd_mysql_pvbselect,
+    dbd_mysql_pbquery,
+    dbd_mysql_pbselect,
+    dbd_mysql_datum_get
 #endif
 };
 
 #endif
-

Attachment: build.sh
Description: application/shellscript

#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <stdarg.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>

#include <apr.h>
#include <apr_pools.h>
#include <apr_strings.h>
#include <apr_time.h>
#include <apr_dbd.h>
#include <apr_buckets.h>

#define NARGS     21
#define BLOB_SIZE 100000

int main(int argc,char **argv){
  apr_pool_t *pool;
  const char *drivers[][2] = {{"pgsql","dbname=test"},
                              {"mysql","dbname=test,fldsz=8000"},
                              {"sqlite2","./test2.db"},
                              {"sqlite3","./test3.db"},
                              {NULL,NULL}};
  size_t i,j;
  int nrows, has_prepare;
  const apr_dbd_driver_t *driver;
  apr_dbd_t *sql;
  apr_dbd_prepared_t *stmt;
  apr_dbd_results_t *res;
  apr_dbd_row_t *row;
  apr_status_t rv,rv2[NARGS];
  char d_tiny,d_tiny2;
  unsigned char d_utiny,d_utiny2;
  short d_short,d_short2;
  unsigned short d_ushort,d_ushort2;
  int d_int,d_int2;
  unsigned int d_uint,d_uint2;
  long d_long,d_long2;
  unsigned long d_ulong,d_ulong2;
  apr_int64_t d_longlong,d_longlong2;
  apr_uint64_t d_ulonglong,d_ulonglong2;
  float d_float,d_float2;
  double d_double,d_double2;
  char *d_string,*d_text,*d_time,*d_date,*d_datetime,*d_timestamp,*d_ztimestamp,
       *d_string2,*d_text2,*d_time2,*d_date2,*d_datetime2,*d_timestamp2,
       *d_ztimestamp2,*d_null2,*buf,*query;
  apr_dbd_blob_t *d_blob;
  apr_bucket_alloc_t *balloc;
  apr_bucket_brigade *d_blob2;
  apr_off_t blen;
  apr_size_t blen2;
  const char *args[NARGS];
  const void *vargs[NARGS];
  char *data;
  int correct;

  apr_initialize();
  apr_pool_create(&pool,NULL);

  apr_dbd_init(pool);

  balloc=apr_bucket_alloc_create(pool);

  for(i=0;drivers[i][0];i++){
    driver=NULL;
    rv=apr_dbd_get_driver(pool,drivers[i][0],&driver);
    if(rv == APR_SUCCESS){
      sql=NULL;
      rv=apr_dbd_open(driver,pool,drivers[i][1],&sql);
      if(rv == APR_SUCCESS){
        stmt=NULL;
        res=NULL;
        row=NULL;

        printf("driver[%u]: name=%s, conn=%s, loaded=%p\n",i,drivers[i][0],
                                                           drivers[i][1],sql);
        rv=apr_dbd_query(driver,sql,&nrows,"delete from test");
        if(rv != APR_SUCCESS)
          continue;

        printf("table cleared, rows affected=%d\n",nrows);

        rv=apr_dbd_prepare(driver,pool,sql,
                           "insert into test values("
                           "%hhd, %hhu, %hd, %hu, %d, %u, %ld, %lu, "
                           "%lld, %llu, %f, %lf, %s, "
                           "%pDt, %pDi, %pDd, %pDa, %pDs, %pDz, %pDb, %pDn)",
                           "apu_dbd_insert",&stmt);
        switch(rv){
        case APR_ENOTIMPL:
          has_prepare=0;
          break;
        case APR_SUCCESS:
          has_prepare=1;
          break;
        default:
          continue;
        }

        printf("prepared statement=%p\n",stmt);

        d_tiny=-1;
        d_utiny=1;
        d_short=-2;
        d_ushort=2;
        d_int=-3;
        d_uint=3;
        d_long=-4;
        d_ulong=4;
        d_longlong=-5;
        d_ulonglong=5;
        d_float=6;
        d_double=7;
        d_string="string";
        d_text="text";
        d_time="11:22";
        d_date="2006-08-29";
        d_datetime="2006-08-29 11:22";
        d_timestamp="2006-08-29 11:22";
        d_ztimestamp="2006-08-29 11:22";
        data=apr_palloc(pool,BLOB_SIZE+1);
        memset((void*)data,'b',BLOB_SIZE);
        ((char*)(data))[BLOB_SIZE]='\0';
        d_blob=apr_dbd_blob_create(pool,data,BLOB_SIZE,NULL,NULL);

        args[0]=apr_psprintf(pool,"%hd",d_tiny);
        args[1]=apr_psprintf(pool,"%hu",d_utiny);
        args[2]=apr_psprintf(pool,"%hd",d_short);
        args[3]=apr_psprintf(pool,"%hu",d_ushort);
        args[4]=apr_psprintf(pool,"%d",d_int);
        args[5]=apr_psprintf(pool,"%u",d_uint);
        args[6]=apr_psprintf(pool,"%ld",d_long);
        args[7]=apr_psprintf(pool,"%lu",d_ulong);
        args[8]=apr_psprintf(pool,"%" APR_INT64_T_FMT,d_longlong);
        args[9]=apr_psprintf(pool,"%" APR_UINT64_T_FMT,d_ulonglong);
        args[10]=apr_psprintf(pool,"%f",d_float);
        args[11]=apr_psprintf(pool,"%lf",d_double);
        args[12]=d_string;
        args[13]=d_text;
        args[14]=d_time;
        args[15]=d_date;
        args[16]=d_datetime;
        args[17]=d_timestamp;
        args[18]=d_ztimestamp;
        args[19]=apr_psprintf(pool,"%" APR_SIZE_T_FMT ":::%s",
                              apr_dbd_blob_size_get(d_blob),
                              apr_dbd_blob_data_get(d_blob));
        args[20]=NULL;

        for(j=0;j<NARGS;j++)
          printf("args[%u]=%.60s\n",j,args[j]);

        if(has_prepare){
          rv=apr_dbd_pquery(driver,pool,sql,&nrows,stmt,NARGS,args);
          if(rv != APR_SUCCESS)
            continue;
        } else{
          query="";
          query=apr_pstrcat(pool,"insert into test values('",
                            args[0],"','",
                            args[1],"','",
                            args[2],"','",
                            args[3],"','",
                            args[4],"','",
                            args[5],"','",
                            args[6],"','",
                            args[7],"','",
                            args[8],"','",
                            args[9],"','",
                            args[10],"','",
                            args[11],"','",
                            args[12],"','",
                            args[13],"','",
                            args[14],"','",
                            args[16],"','",
                            args[16],"','",
                            args[17],"','",
                            args[18],"','",
                            apr_dbd_blob_data_get(d_blob),"',NULL)",NULL);
          rv=apr_dbd_query(driver,sql,&nrows,query);
          if(rv != APR_SUCCESS)
            continue;
        }

        printf("query status=%d\n",rv);

        vargs[0]=&d_tiny;
        vargs[1]=&d_utiny;
        vargs[2]=&d_short;
        vargs[3]=&d_ushort;
        vargs[4]=&d_int;
        vargs[5]=&d_uint;
        vargs[6]=&d_long;
        vargs[7]=&d_ulong;
        vargs[8]=&d_longlong;
        vargs[9]=&d_ulonglong;
        vargs[10]=&d_float;
        vargs[11]=&d_double;
        vargs[12]=d_string;
        vargs[13]=d_text;
        vargs[14]=d_time;
        vargs[15]=d_date;
        vargs[16]=d_datetime;
        vargs[17]=d_timestamp;
        vargs[18]=d_ztimestamp;
        vargs[19]=d_blob;
        vargs[20]=NULL;

        if(has_prepare){
          rv=apr_dbd_pbquery(driver,pool,sql,&nrows,stmt,NARGS,vargs);
          if(rv != APR_SUCCESS)
            continue;
        } else{
          rv=apr_dbd_query(driver,sql,&nrows,query);
          if(rv != APR_SUCCESS)
            continue;
        }

        printf("query status=%d\n",rv);

        if(has_prepare){
          rv=apr_dbd_prepare(driver,pool,sql,"select * from test",
                             "apu_dbd_select",&stmt);
          if(rv != APR_SUCCESS)
            continue;

          printf("prepared statement=%p\n",stmt);

          res=NULL;
          rv = apr_dbd_pbselect(driver,pool,sql,&res,stmt,0,0,NULL);
          if(rv != APR_SUCCESS)
            continue;
        } else{
          rv=apr_dbd_select(driver,pool,sql,&res,"select * from test",0);
          if(rv != APR_SUCCESS)
            continue;
        }

        printf("result=%p\n",res);

        while(!apr_dbd_get_row(driver,pool,res,&row,-1)){
          d_blob2=apr_brigade_create(pool,balloc);

          rv2[0]=apr_dbd_datum_get(driver,row,0,APR_DBD_TYPE_TINY,&d_tiny2); 
          rv2[1]=apr_dbd_datum_get(driver,row,1,APR_DBD_TYPE_UTINY,&d_utiny2); 
          rv2[2]=apr_dbd_datum_get(driver,row,2,APR_DBD_TYPE_SHORT,&d_short2); 
          rv2[3]=apr_dbd_datum_get(driver,row,3,APR_DBD_TYPE_USHORT,&d_ushort2); 
          rv2[4]=apr_dbd_datum_get(driver,row,4,APR_DBD_TYPE_INT,&d_int2); 
          rv2[5]=apr_dbd_datum_get(driver,row,5,APR_DBD_TYPE_UINT,&d_uint2); 
          rv2[6]=apr_dbd_datum_get(driver,row,6,APR_DBD_TYPE_LONG,&d_long2); 
          rv2[7]=apr_dbd_datum_get(driver,row,7,APR_DBD_TYPE_ULONG,&d_ulong2); 
          rv2[8]=apr_dbd_datum_get(driver,row,8,APR_DBD_TYPE_LONGLONG,&d_longlong2); 
          rv2[9]=apr_dbd_datum_get(driver,row,9,APR_DBD_TYPE_ULONGLONG,&d_ulonglong2); 
          rv2[10]=apr_dbd_datum_get(driver,row,10,APR_DBD_TYPE_FLOAT,&d_float2); 
          rv2[11]=apr_dbd_datum_get(driver,row,11,APR_DBD_TYPE_DOUBLE,&d_double2); 
          rv2[12]=apr_dbd_datum_get(driver,row,12,APR_DBD_TYPE_STRING,&d_string2); 
          rv2[13]=apr_dbd_datum_get(driver,row,13,APR_DBD_TYPE_TEXT,&d_text2); 
          rv2[14]=apr_dbd_datum_get(driver,row,14,APR_DBD_TYPE_TIME,&d_time2); 
          rv2[15]=apr_dbd_datum_get(driver,row,15,APR_DBD_TYPE_DATE,&d_date2); 
          rv2[16]=apr_dbd_datum_get(driver,row,16,APR_DBD_TYPE_DATETIME,&d_datetime2); 
          rv2[17]=apr_dbd_datum_get(driver,row,17,APR_DBD_TYPE_TIMESTAMP,&d_timestamp2); 
          rv2[18]=apr_dbd_datum_get(driver,row,18,APR_DBD_TYPE_ZTIMESTAMP,&d_ztimestamp2); 
          rv2[19]=apr_dbd_datum_get(driver,row,19,APR_DBD_TYPE_BLOB,d_blob2); 
          rv2[20]=apr_dbd_datum_get(driver,row,20,APR_DBD_TYPE_NULL,&d_null2); 

          for(j=0;j<NARGS;j++){
            switch(rv2[j]){
            case APR_ENOENT:
              printf("value[%d] is NULL\n",j);
              break;
            case APR_EGENERAL:
              printf("error fetching value[%d]\n",j);
              break;
            }
          }

          printf("%hhd %hhu %hd %hu %d %u %ld %lu "
                 "%" APR_INT64_T_FMT " %" APR_UINT64_T_FMT " %f %lf "
                 "%s %s %s %s %s %s %s %p %p\n",
                 d_tiny2,d_utiny2,d_short2,d_ushort2,d_int2,d_uint2,
                 d_long2,d_ulong2,d_longlong2,d_ulonglong2,d_float2,d_double2,
                 d_string2,d_text2,d_time2,d_date2,d_datetime2,d_timestamp2,
                 d_ztimestamp2,d_blob2,d_null2);

          apr_brigade_length(d_blob2,1,&blen);
          blen2=blen;
          buf=NULL;
          apr_brigade_pflatten(d_blob2,&buf,&blen2,pool);

          correct=1;
          for(j=0;j<blen;j++)
            if(buf[j]!='b'){
              correct=0;
              break;
            }

          printf("blob=%.*s, length=%"
                 APR_OFF_T_FMT ", correct=%d\n",40,buf,blen,correct);

          apr_brigade_destroy(d_blob2);
        }
      }
    }
  }

  apr_terminate();
  return 0;
}

Reply via email to