apr-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From bo...@apache.org
Subject svn commit: r508700 [2/2] - in /apr/apr-util/trunk: CHANGES STATUS dbd/apr_dbd.c dbd/apr_dbd_oracle.c dbd/apr_dbd_pgsql.c dbd/apr_dbd_sqlite2.c dbd/apr_dbd_sqlite3.c include/apr_dbd.h include/private/apr_dbd_internal.h
Date Sat, 17 Feb 2007 02:50:18 GMT
Modified: apr/apr-util/trunk/dbd/apr_dbd_pgsql.c
URL: http://svn.apache.org/viewvc/apr/apr-util/trunk/dbd/apr_dbd_pgsql.c?view=diff&rev=508700&r1=508699&r2=508700
==============================================================================
--- apr/apr-util/trunk/dbd/apr_dbd_pgsql.c (original)
+++ apr/apr-util/trunk/dbd/apr_dbd_pgsql.c Fri Feb 16 18:50:17 2007
@@ -31,11 +31,10 @@
 
 #include "apr_strings.h"
 #include "apr_time.h"
+#include "apr_buckets.h"
 
 #include "apr_dbd_internal.h"
 
-#define QUERY_MAX_ARGS 40
-
 struct apr_dbd_transaction_t {
     int mode;
     int errnum;
@@ -54,6 +53,7 @@
     size_t ntuples;
     size_t sz;
     size_t index;
+    apr_pool_t *pool;
 };
 
 struct apr_dbd_row_t {
@@ -65,6 +65,8 @@
     const char *name;
     int prepared;
     int nargs;
+    int nvals;
+    apr_dbd_type_e *types;
 };
 
 #define dbd_pgsql_is_success(x) (((x) == PGRES_EMPTY_QUERY) \
@@ -152,6 +154,7 @@
         (*results)->ntuples = PQntuples(res);
         (*results)->sz = PQnfields(res);
         (*results)->random = seek;
+        (*results)->pool = pool;
         apr_pool_cleanup_register(pool, res, clear_result,
                                   apr_pool_cleanup_null);
     }
@@ -208,6 +211,7 @@
         }
         (*results)->random = seek;
         (*results)->handle = sql->conn;
+        (*results)->pool = pool;
     }
     return 0;
 }
@@ -286,6 +290,81 @@
     return PQgetvalue(row->res->res, row->n, n);
 }
 
+static apr_status_t dbd_pgsql_datum_get(const apr_dbd_row_t *row, int n,
+                                        apr_dbd_type_e type, void *data)
+{
+    if (PQgetisnull(row->res->res, row->n, n)) {
+        return APR_ENOENT;
+    }
+
+    switch (type) {
+    case APR_DBD_TYPE_TINY:
+        *(char*)data = atoi(PQgetvalue(row->res->res, row->n, n));
+        break;
+    case APR_DBD_TYPE_UTINY:
+        *(unsigned char*)data = atoi(PQgetvalue(row->res->res, row->n, n));
+        break;
+    case APR_DBD_TYPE_SHORT:
+        *(short*)data = atoi(PQgetvalue(row->res->res, row->n, n));
+        break;
+    case APR_DBD_TYPE_USHORT:
+        *(unsigned short*)data = atoi(PQgetvalue(row->res->res, row->n, n));
+        break;
+    case APR_DBD_TYPE_INT:
+        *(int*)data = atoi(PQgetvalue(row->res->res, row->n, n));
+        break;
+    case APR_DBD_TYPE_UINT:
+        *(unsigned int*)data = atoi(PQgetvalue(row->res->res, row->n, n));
+        break;
+    case APR_DBD_TYPE_LONG:
+        *(long*)data = atol(PQgetvalue(row->res->res, row->n, n));
+        break;
+    case APR_DBD_TYPE_ULONG:
+        *(unsigned long*)data = atol(PQgetvalue(row->res->res, row->n, n));
+        break;
+    case APR_DBD_TYPE_LONGLONG:
+        *(apr_int64_t*)data = apr_atoi64(PQgetvalue(row->res->res, row->n, n));
+        break;
+    case APR_DBD_TYPE_ULONGLONG:
+        *(apr_uint64_t*)data = apr_atoi64(PQgetvalue(row->res->res, row->n, n));
+        break;
+    case APR_DBD_TYPE_FLOAT:
+        *(float*)data = atof(PQgetvalue(row->res->res, row->n, n));
+        break;
+    case APR_DBD_TYPE_DOUBLE:
+        *(double*)data = atof(PQgetvalue(row->res->res, row->n, 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 = PQgetvalue(row->res->res, row->n, n);
+        break;
+    case APR_DBD_TYPE_BLOB:
+    case APR_DBD_TYPE_CLOB:
+        {
+        apr_bucket *e;
+        apr_bucket_brigade *b = (apr_bucket_brigade*)data;
+
+        e = apr_bucket_pool_create(PQgetvalue(row->res->res, row->n, n),
+                                   PQgetlength(row->res->res, row->n, 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 APR_SUCCESS;
+}
+
 static const char *dbd_pgsql_error(apr_dbd_t *sql, int n)
 {
     return PQerrorMessage(sql->conn);
@@ -377,78 +456,88 @@
 
 static int dbd_pgsql_prepare(apr_pool_t *pool, apr_dbd_t *sql,
                              const char *query, const char *label,
+                             int nargs, int nvals, apr_dbd_type_e *types,
                              apr_dbd_prepared_t **statement)
 {
     char *sqlcmd;
     char *sqlptr;
-    size_t length;
+    size_t length, qlen;
     size_t i = 0;
-    const char *args[QUERY_MAX_ARGS];
+    const char **args;
     size_t alen;
     int ret;
     PGresult *res;
-    char *pgquery;
-    char *pgptr;
 
     if (!*statement) {
         *statement = apr_palloc(pool, sizeof(apr_dbd_prepared_t));
     }
-    (*statement)->nargs = 0;
-    /* Translate from apr_dbd to native query format */
-    for (sqlptr = (char*)query; *sqlptr; ++sqlptr) {
-        if (sqlptr[0] == '%') {
-            if (isalpha(sqlptr[1])) {
-                ++(*statement)->nargs;
-            }
-            else if (sqlptr[1] == '%') {
-                ++sqlptr;
-            }
-        }
-    }
-    length = strlen(query) + 1;
-    if ((*statement)->nargs > 8) {
-        length += (*statement)->nargs - 8;
-    }
-    pgptr = pgquery = apr_palloc(pool, length) ;
-
-    for (sqlptr = (char*)query; *sqlptr; ++sqlptr) {
-        if ((sqlptr[0] == '%') && isalpha(sqlptr[1])) {
-            *pgptr++ = '$';
-            if (i < 9) {
-                *pgptr++ = '1' + i;
-            }
-            else {
-                *pgptr++ = '0' + ((i+1)/10);
-                *pgptr++ = '0' + ((i+1)%10);
-            }
-            switch (*++sqlptr) {
-            case 'd':
-                args[i] = "integer";
-                break;
-            case 's':
-                args[i] = "varchar";
-                break;
-            default:
-                args[i] = "varchar";
-                break;
-            }
-            length += 1 + strlen(args[i]);
-            ++i;
-        }
-        else if ((sqlptr[0] == '%') && (sqlptr[1] == '%')) {
-            /* reduce %% to % */
-            *pgptr++ = *sqlptr++;
-        }
-        else {
-            *pgptr++ = *sqlptr;
+    (*statement)->nargs = nargs;
+    (*statement)->nvals = nvals;
+    (*statement)->types = types;
+
+    args = apr_palloc(pool, nargs * sizeof(*args));
+
+    qlen = strlen(query);
+    length = qlen + 1;
+
+    for (i = 0; i < nargs; i++) {
+        switch (types[i]) {
+        case APR_DBD_TYPE_TINY: 
+        case APR_DBD_TYPE_UTINY: 
+        case APR_DBD_TYPE_SHORT: 
+        case APR_DBD_TYPE_USHORT:
+            args[i] = "smallint";
+            break;
+        case APR_DBD_TYPE_INT: 
+        case APR_DBD_TYPE_UINT:
+            args[i] = "integer";
+            break;
+        case APR_DBD_TYPE_LONG: 
+        case APR_DBD_TYPE_ULONG:   
+        case APR_DBD_TYPE_LONGLONG: 
+        case APR_DBD_TYPE_ULONGLONG:
+            args[i] = "bigint";
+            break;
+        case APR_DBD_TYPE_FLOAT:
+            args[i] = "real";
+            break;
+        case APR_DBD_TYPE_DOUBLE:
+            args[i] = "double precision";
+            break;
+        case APR_DBD_TYPE_TEXT:
+            args[i] = "text";
+            break;
+        case APR_DBD_TYPE_TIME:
+            args[i] = "time";
+            break;
+        case APR_DBD_TYPE_DATE:
+            args[i] = "date";
+            break;
+        case APR_DBD_TYPE_DATETIME:
+        case APR_DBD_TYPE_TIMESTAMP:
+            args[i] = "timestamp";
+            break;
+        case APR_DBD_TYPE_ZTIMESTAMP:
+            args[i] = "timestamp with time zone";
+            break;
+        case APR_DBD_TYPE_BLOB:
+        case APR_DBD_TYPE_CLOB:
+            args[i] = "bytea";
+            break;
+        case APR_DBD_TYPE_NULL:
+            args[i] = "varchar"; /* XXX Eh? */
+            break;
+        default:
+            args[i] = "varchar";
+            break;
         }
+        length += 1 + strlen(args[i]);
     }
-    *pgptr = 0;
 
     if (!label) {
         /* don't really prepare; use in execParams instead */
         (*statement)->prepared = 0;
-        (*statement)->name = apr_pstrdup(pool, pgquery);
+        (*statement)->name = apr_pstrdup(pool, query);
         return 0;
     }
     (*statement)->name = apr_pstrdup(pool, label);
@@ -462,10 +551,10 @@
     length = strlen(label);
     memcpy(sqlptr, label, length);
     sqlptr += length;
-    if ((*statement)->nargs > 0) {
+    if (nargs > 0) {
         memcpy(sqlptr, " (",2);
         sqlptr += 2;
-        for (i=0; i < (*statement)->nargs; ++i) {
+        for (i=0; i < nargs; ++i) {
             alen = strlen(args[i]);
             memcpy(sqlptr, args[i], alen);
             sqlptr += alen;
@@ -475,8 +564,8 @@
     }
     memcpy(sqlptr, " AS ", 4);
     sqlptr += 4;
-    memcpy(sqlptr, pgquery, strlen(pgquery));
-    sqlptr += strlen(pgquery);
+    memcpy(sqlptr, query, qlen);
+    sqlptr += qlen;
     *sqlptr = 0;
 
     res = PQexec(sql->conn, sqlcmd);
@@ -496,17 +585,14 @@
     return ret;
 }
 
-static int dbd_pgsql_pquery(apr_pool_t *pool, apr_dbd_t *sql,
-                            int *nrows, apr_dbd_prepared_t *statement,
-                            int nargs, const char **values)
+static int dbd_pgsql_pquery_internal(apr_pool_t *pool, apr_dbd_t *sql,
+                                     int *nrows, apr_dbd_prepared_t *statement,
+                                     const char **values,
+                                     const int *len, const int *fmt)
 {
     int ret;
     PGresult *res;
 
-    if (sql->trans && sql->trans->errnum) {
-        return sql->trans->errnum;
-    }
-
     if (TXN_IGNORE_ERRORS(sql->trans)) {
         PGresult *res = PQexec(sql->conn, "SAVEPOINT APR_DBD_TXN_SP");
         if (res) {
@@ -522,12 +608,12 @@
     }
 
     if (statement->prepared) {
-        res = PQexecPrepared(sql->conn, statement->name, nargs, values, 0, 0,
-                             0);
+        res = PQexecPrepared(sql->conn, statement->name, statement->nargs,
+                             values, len, fmt, 0);
     }
     else {
-        res = PQexecParams(sql->conn, statement->name, nargs, 0, values, 0, 0,
-                           0);
+        res = PQexecParams(sql->conn, statement->name, statement->nargs, 0,
+                           values, len, fmt, 0);
     }
     if (res) {
         ret = PQresultStatus(res);
@@ -580,6 +666,58 @@
     return ret;
 }
 
+static void dbd_pgsql_bind(apr_dbd_prepared_t *statement,
+                           const char **values,
+                           const char **val, int *len, int *fmt)
+{
+    int i, j;
+
+    for (i = 0, j = 0; i < statement->nargs; i++, j++) {
+        if (values[j] == NULL) {
+            val[i] = NULL;
+        }
+        else {
+            switch (statement->types[i]) {
+            case APR_DBD_TYPE_BLOB:
+            case APR_DBD_TYPE_CLOB:
+                val[i] = (char *)values[j];
+                len[i] = atoi(values[++j]);
+                fmt[i] = 1;
+
+                /* skip table and column */
+                j += 2;
+                break;
+            default:
+                val[i] = values[j];
+                break;
+            }
+        }
+    }
+
+    return;
+}
+
+static int dbd_pgsql_pquery(apr_pool_t *pool, apr_dbd_t *sql,
+                            int *nrows, apr_dbd_prepared_t *statement,
+                            const char **values)
+{
+    int *len, *fmt;
+    const char **val;
+
+    if (sql->trans && sql->trans->errnum) {
+        return sql->trans->errnum;
+    }
+
+    val = apr_palloc(pool, sizeof(*val) * statement->nargs);
+    len = apr_pcalloc(pool, sizeof(*len) * statement->nargs);
+    fmt = apr_pcalloc(pool, sizeof(*fmt) * statement->nargs);
+
+    dbd_pgsql_bind(statement, values, val, len, fmt);
+
+    return dbd_pgsql_pquery_internal(pool, sql, nrows, statement,
+                                     val, len, fmt);
+}
+
 static int dbd_pgsql_pvquery(apr_pool_t *pool, apr_dbd_t *sql,
                              int *nrows, apr_dbd_prepared_t *statement,
                              va_list args)
@@ -591,29 +729,25 @@
         return sql->trans->errnum;
     }
 
-    values = apr_palloc(pool, sizeof(*values) * statement->nargs);
+    values = apr_palloc(pool, sizeof(*values) * statement->nvals);
 
-    for (i = 0; i < statement->nargs; i++) {
-        values[i] = apr_pstrdup(pool, va_arg(args, const char*));
+    for (i = 0; i < statement->nvals; i++) {
+        values[i] = va_arg(args, const char*);
     }
 
-    return dbd_pgsql_pquery(pool, sql, nrows, statement,
-                            statement->nargs, values);
+    return dbd_pgsql_pquery(pool, sql, nrows, statement, values);
 }
 
-static int dbd_pgsql_pselect(apr_pool_t *pool, apr_dbd_t *sql,
-                             apr_dbd_results_t **results,
-                             apr_dbd_prepared_t *statement,
-                             int seek, int nargs, const char **values)
+static int dbd_pgsql_pselect_internal(apr_pool_t *pool, apr_dbd_t *sql,
+                                      apr_dbd_results_t **results,
+                                      apr_dbd_prepared_t *statement,
+                                      int seek, const char **values,
+                                      const int *len, const int *fmt)
 {
     PGresult *res;
     int rv;
     int ret = 0;
 
-    if (sql->trans && sql->trans->errnum) {
-        return sql->trans->errnum;
-    }
-
     if (seek) { /* synchronous query */
         if (TXN_IGNORE_ERRORS(sql->trans)) {
             PGresult *res = PQexec(sql->conn, "SAVEPOINT APR_DBD_TXN_SP");
@@ -630,12 +764,12 @@
             }
         }
         if (statement->prepared) {
-            res = PQexecPrepared(sql->conn, statement->name, nargs, values, 0,
-                                 0, 0);
+            res = PQexecPrepared(sql->conn, statement->name, statement->nargs,
+                                 values, len, fmt, 0);
         }
         else {
-            res = PQexecParams(sql->conn, statement->name, nargs, 0, values, 0,
-                               0, 0);
+            res = PQexecParams(sql->conn, statement->name, statement->nargs, 0,
+                               values, len, fmt, 0);
         }
         if (res) {
             ret = PQresultStatus(res);
@@ -692,6 +826,7 @@
         (*results)->ntuples = PQntuples(res);
         (*results)->sz = PQnfields(res);
         (*results)->random = seek;
+        (*results)->pool = pool;
         apr_pool_cleanup_register(pool, res, clear_result,
                                   apr_pool_cleanup_null);
     }
@@ -711,12 +846,12 @@
             }
         }
         if (statement->prepared) {
-            rv = PQsendQueryPrepared(sql->conn, statement->name, nargs, values,
-                                     0, 0, 0);
+            rv = PQsendQueryPrepared(sql->conn, statement->name,
+                                     statement->nargs, values, len, fmt, 0);
         }
         else {
-            rv = PQsendQueryParams(sql->conn, statement->name, nargs, 0,
-                                   values, 0, 0, 0);
+            rv = PQsendQueryParams(sql->conn, statement->name,
+                                   statement->nargs, 0, values, len, fmt, 0);
         }
         if (rv == 0) {
             if (TXN_IGNORE_ERRORS(sql->trans)) {
@@ -759,11 +894,34 @@
         }
         (*results)->random = seek;
         (*results)->handle = sql->conn;
+        (*results)->pool = pool;
     }
 
     return ret;
 }
 
+static int dbd_pgsql_pselect(apr_pool_t *pool, apr_dbd_t *sql,
+                             apr_dbd_results_t **results,
+                             apr_dbd_prepared_t *statement,
+                             int seek, const char **values)
+{
+    int *len, *fmt;
+    const char **val;
+
+    if (sql->trans && sql->trans->errnum) {
+        return sql->trans->errnum;
+    }
+
+    val = apr_palloc(pool, sizeof(*val) * statement->nargs);
+    len = apr_pcalloc(pool, sizeof(*len) * statement->nargs);
+    fmt = apr_pcalloc(pool, sizeof(*fmt) * statement->nargs);
+
+    dbd_pgsql_bind(statement, values, val, len, fmt);
+
+    return dbd_pgsql_pselect_internal(pool, sql, results, statement,
+                                      seek, val, len, fmt);
+}
+
 static int dbd_pgsql_pvselect(apr_pool_t *pool, apr_dbd_t *sql,
                               apr_dbd_results_t **results,
                               apr_dbd_prepared_t *statement,
@@ -776,14 +934,174 @@
         return sql->trans->errnum;
     }
 
-    values = apr_palloc(pool, sizeof(*values) * statement->nargs);
+    values = apr_palloc(pool, sizeof(*values) * statement->nvals);
+
+    for (i = 0; i < statement->nvals; i++) {
+        values[i] = va_arg(args, const char*);
+    }
+
+    return dbd_pgsql_pselect(pool, sql, results, statement, seek, values);
+}
+
+static void dbd_pgsql_bbind(apr_pool_t *pool, apr_dbd_prepared_t * statement,
+                            const void **values,
+                            const char **val, int *len, int *fmt)
+{
+    int i, j;
+    apr_dbd_type_e type;
+
+    for (i = 0, j = 0; i < statement->nargs; i++, j++) {
+        type = (values[j] == NULL ? APR_DBD_TYPE_NULL : statement->types[i]);
+
+        switch (type) {
+        case APR_DBD_TYPE_TINY:
+            val[i] = apr_itoa(pool, *(char*)values[j]);
+            break;
+        case APR_DBD_TYPE_UTINY:
+            val[i] = apr_itoa(pool, *(unsigned char*)values[j]);
+            break;
+        case APR_DBD_TYPE_SHORT:
+            val[i] = apr_itoa(pool, *(short*)values[j]);
+            break;
+        case APR_DBD_TYPE_USHORT:
+            val[i] = apr_itoa(pool, *(unsigned short*)values[j]);
+            break;
+        case APR_DBD_TYPE_INT:
+            val[i] = apr_itoa(pool, *(int*)values[j]);
+            break;
+        case APR_DBD_TYPE_UINT:
+            val[i] = apr_itoa(pool, *(unsigned int*)values[j]);
+            break;
+        case APR_DBD_TYPE_LONG:
+            val[i] = apr_ltoa(pool, *(long*)values[j]);
+            break;
+        case APR_DBD_TYPE_ULONG:
+            val[i] = apr_ltoa(pool, *(unsigned long*)values[j]);
+            break;
+        case APR_DBD_TYPE_LONGLONG:
+            val[i] = apr_psprintf(pool, "%" APR_INT64_T_FMT,
+                                  *(apr_int64_t*)values[j]);
+            break;
+        case APR_DBD_TYPE_ULONGLONG:
+            val[i] = apr_psprintf(pool, "%" APR_UINT64_T_FMT,
+                                  *(apr_uint64_t*)values[j]);
+            break;
+        case APR_DBD_TYPE_FLOAT:
+            val[i] = apr_psprintf(pool, "%f", *(float*)values[j]);
+            break;
+        case APR_DBD_TYPE_DOUBLE:
+            val[i] = apr_psprintf(pool, "%lf", *(double*)values[j]);
+            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:
+            val[i] = values[j];
+            break;
+        case APR_DBD_TYPE_BLOB:
+        case APR_DBD_TYPE_CLOB:
+            val[i] = (char*)values[j];
+            len[i] = *(apr_size_t*)values[++j];
+            fmt[i] = 1;
+
+            /* skip table and column */
+            j += 2;
+            break;
+        case APR_DBD_TYPE_NULL:
+        default:
+            val[i] = NULL;
+            break;
+        }
+    }
+
+    return;
+}
+
+static int dbd_pgsql_pbquery(apr_pool_t * pool, apr_dbd_t * sql,
+                             int *nrows, apr_dbd_prepared_t * statement,
+                             const void **values)
+{
+    int *len, *fmt;
+    const char **val;
+
+    if (sql->trans && sql->trans->errnum) {
+        return sql->trans->errnum;
+    }
+
+    val = apr_palloc(pool, sizeof(*val) * statement->nargs);
+    len = apr_pcalloc(pool, sizeof(*len) * statement->nargs);
+    fmt = apr_pcalloc(pool, sizeof(*fmt) * statement->nargs);
+
+    dbd_pgsql_bbind(pool, statement, values, val, len, fmt);
+
+    return dbd_pgsql_pquery_internal(pool, sql, nrows, statement,
+                                     val, len, fmt);
+}
+
+static int dbd_pgsql_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->nvals);
+
+    for (i = 0; i < statement->nvals; i++) {
+        values[i] = va_arg(args, const void*);
+    }
+
+    return dbd_pgsql_pbquery(pool, sql, nrows, statement, values);
+}
+
+static int dbd_pgsql_pbselect(apr_pool_t * pool, apr_dbd_t * sql,
+                              apr_dbd_results_t ** results,
+                              apr_dbd_prepared_t * statement,
+                              int seek, const void **values)
+{
+    int *len, *fmt;
+    const char **val;
+
+    if (sql->trans && sql->trans->errnum) {
+        return sql->trans->errnum;
+    }
+
+    val = apr_palloc(pool, sizeof(*val) * statement->nargs);
+    len = apr_pcalloc(pool, sizeof(*len) * statement->nargs);
+    fmt = apr_pcalloc(pool, sizeof(*fmt) * statement->nargs);
+
+    dbd_pgsql_bbind(pool, statement, values, val, len, fmt);
+
+    return dbd_pgsql_pselect_internal(pool, sql, results, statement,
+                                      seek, val, len, fmt);
+}
+
+static int dbd_pgsql_pvbselect(apr_pool_t * pool, apr_dbd_t * sql,
+                               apr_dbd_results_t ** results,
+                               apr_dbd_prepared_t * statement, int seek,
+                               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->nvals);
 
-    for (i = 0; i < statement->nargs; i++) {
-        values[i] = apr_pstrdup(pool, va_arg(args, const char*));
+    for (i = 0; i < statement->nvals; i++) {
+        values[i] = va_arg(args, const void*);
     }
 
-    return dbd_pgsql_pselect(pool, sql, results, statement,
-                             seek, statement->nargs, values) ;
+    return dbd_pgsql_pbselect(pool, sql, results, statement, seek, values);
 }
 
 static int dbd_pgsql_start_transaction(apr_pool_t *pool, apr_dbd_t *handle,
@@ -949,6 +1267,12 @@
     dbd_pgsql_pselect,
     dbd_pgsql_get_name,
     dbd_pgsql_transaction_mode_get,
-    dbd_pgsql_transaction_mode_set
+    dbd_pgsql_transaction_mode_set,
+    "$%d",
+    dbd_pgsql_pvbquery,
+    dbd_pgsql_pvbselect,
+    dbd_pgsql_pbquery,
+    dbd_pgsql_pbselect,
+    dbd_pgsql_datum_get
 };
 #endif

Modified: apr/apr-util/trunk/dbd/apr_dbd_sqlite2.c
URL: http://svn.apache.org/viewvc/apr/apr-util/trunk/dbd/apr_dbd_sqlite2.c?view=diff&rev=508700&r1=508699&r2=508700
==============================================================================
--- apr/apr-util/trunk/dbd/apr_dbd_sqlite2.c (original)
+++ apr/apr-util/trunk/dbd/apr_dbd_sqlite2.c Fri Feb 16 18:50:17 2007
@@ -25,6 +25,7 @@
 
 #include "apr_strings.h"
 #include "apr_time.h"
+#include "apr_buckets.h"
 
 #include "apr_dbd_internal.h"
 
@@ -47,6 +48,7 @@
     size_t ntuples;
     size_t sz;
     size_t index;
+    apr_pool_t *pool;
 };
 
 struct apr_dbd_row_t {
@@ -101,6 +103,7 @@
         (*results)->ntuples = tuples;
         (*results)->sz = fields;
         (*results)->random = seek;
+        (*results)->pool = pool;
 
         if (tuples > 0)
             apr_pool_cleanup_register(pool, result, free_table,
@@ -187,6 +190,84 @@
     return row->data[n];
 }
 
+static apr_status_t dbd_sqlite_datum_get(const apr_dbd_row_t *row, int n,
+                                         apr_dbd_type_e type, void *data)
+{
+    if ((n < 0) || (n >= row->res->sz)) {
+      return APR_EGENERAL;
+    }
+
+    if (row->data[n] == NULL) {
+        return APR_ENOENT;
+    }
+
+    switch (type) {
+    case APR_DBD_TYPE_TINY:
+        *(char*)data = atoi(row->data[n]);
+        break;
+    case APR_DBD_TYPE_UTINY:
+        *(unsigned char*)data = atoi(row->data[n]);
+        break;
+    case APR_DBD_TYPE_SHORT:
+        *(short*)data = atoi(row->data[n]);
+        break;
+    case APR_DBD_TYPE_USHORT:
+        *(unsigned short*)data = atoi(row->data[n]);
+        break;
+    case APR_DBD_TYPE_INT:
+        *(int*)data = atoi(row->data[n]);
+        break;
+    case APR_DBD_TYPE_UINT:
+        *(unsigned int*)data = atoi(row->data[n]);
+        break;
+    case APR_DBD_TYPE_LONG:
+        *(long*)data = atol(row->data[n]);
+        break;
+    case APR_DBD_TYPE_ULONG:
+        *(unsigned long*)data = atol(row->data[n]);
+        break;
+    case APR_DBD_TYPE_LONGLONG:
+        *(apr_int64_t*)data = apr_atoi64(row->data[n]);
+        break;
+    case APR_DBD_TYPE_ULONGLONG:
+        *(apr_uint64_t*)data = apr_atoi64(row->data[n]);
+        break;
+    case APR_DBD_TYPE_FLOAT:
+        *(float*)data = atof(row->data[n]);
+        break;
+    case APR_DBD_TYPE_DOUBLE:
+        *(double*)data = atof(row->data[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->data[n];
+        break;
+    case APR_DBD_TYPE_BLOB:
+    case APR_DBD_TYPE_CLOB:
+        {
+        apr_bucket *e;
+        apr_bucket_brigade *b = (apr_bucket_brigade*)data;
+
+        e = apr_bucket_pool_create(row->data[n],strlen(row->data[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 APR_SUCCESS;
+}
+
 static const char *dbd_sqlite_error(apr_dbd_t * sql, int n)
 {
     return sql->errmsg;
@@ -240,6 +321,7 @@
 
 static int dbd_sqlite_prepare(apr_pool_t * pool, apr_dbd_t * sql,
                               const char *query, const char *label,
+                              int nargs, int nvals, apr_dbd_type_e *types,
                               apr_dbd_prepared_t ** statement)
 {
     return APR_ENOTIMPL;
@@ -247,7 +329,7 @@
 
 static int dbd_sqlite_pquery(apr_pool_t * pool, apr_dbd_t * sql,
                              int *nrows, apr_dbd_prepared_t * statement,
-                             int nargs, const char **values)
+                             const char **values)
 {
     return APR_ENOTIMPL;
 }
@@ -262,7 +344,7 @@
 static int dbd_sqlite_pselect(apr_pool_t * pool, apr_dbd_t * sql,
                               apr_dbd_results_t ** results,
                               apr_dbd_prepared_t * statement,
-                              int seek, int nargs, const char **values)
+                              int seek, const char **values)
 {
     return APR_ENOTIMPL;
 }
@@ -275,6 +357,36 @@
     return APR_ENOTIMPL;
 }
 
+static int dbd_sqlite_pbquery(apr_pool_t * pool, apr_dbd_t * sql,
+                              int *nrows, apr_dbd_prepared_t * statement,
+                              const void **values)
+{
+    return APR_ENOTIMPL;
+}
+
+static int dbd_sqlite_pvbquery(apr_pool_t * pool, apr_dbd_t * sql,
+                               int *nrows, apr_dbd_prepared_t * statement,
+                               va_list args)
+{
+    return APR_ENOTIMPL;
+}
+
+static int dbd_sqlite_pbselect(apr_pool_t * pool, apr_dbd_t * sql,
+                               apr_dbd_results_t ** results,
+                               apr_dbd_prepared_t * statement,
+                               int seek, const void **values)
+{
+    return APR_ENOTIMPL;
+}
+
+static int dbd_sqlite_pvbselect(apr_pool_t * pool, apr_dbd_t * sql,
+                                apr_dbd_results_t ** results,
+                                apr_dbd_prepared_t * statement, int seek,
+                                va_list args)
+{
+    return APR_ENOTIMPL;
+}
+
 static int dbd_sqlite_start_transaction(apr_pool_t * pool, apr_dbd_t * handle,
                                         apr_dbd_transaction_t ** trans)
 {
@@ -424,6 +536,12 @@
     dbd_sqlite_pselect,
     dbd_sqlite_get_name,
     dbd_sqlite_transaction_mode_get,
-    dbd_sqlite_transaction_mode_set
+    dbd_sqlite_transaction_mode_set,
+    NULL,
+    dbd_sqlite_pvbquery,
+    dbd_sqlite_pvbselect,
+    dbd_sqlite_pbquery,
+    dbd_sqlite_pbselect,
+    dbd_sqlite_datum_get
 };
 #endif

Modified: apr/apr-util/trunk/dbd/apr_dbd_sqlite3.c
URL: http://svn.apache.org/viewvc/apr/apr-util/trunk/dbd/apr_dbd_sqlite3.c?view=diff&rev=508700&r1=508699&r2=508700
==============================================================================
--- apr/apr-util/trunk/dbd/apr_dbd_sqlite3.c (original)
+++ apr/apr-util/trunk/dbd/apr_dbd_sqlite3.c Fri Feb 16 18:50:17 2007
@@ -25,6 +25,7 @@
 
 #include "apr_strings.h"
 #include "apr_time.h"
+#include "apr_buckets.h"
 
 #include "apr_dbd_internal.h"
 
@@ -67,21 +68,25 @@
     size_t sz;
     int tuples;
     char **col_names;
+    apr_pool_t *pool;
 };
 
 struct apr_dbd_prepared_t {
     sqlite3_stmt *stmt;
     apr_dbd_prepared_t *next;
+    int nargs;
+    int nvals;
+    apr_dbd_type_e *types;
 };
 
-#define dbd_sqlite3_is_success(x) (((x) == SQLITE_DONE ) \
-		|| ((x) == SQLITE_OK ))
+#define dbd_sqlite3_is_success(x) (((x) == SQLITE_DONE) || ((x) == SQLITE_OK))
 
-static int dbd_sqlite3_select(apr_pool_t * pool, apr_dbd_t * sql, apr_dbd_results_t ** results, const char *query, int seek)
+static int dbd_sqlite3_select_internal(apr_pool_t *pool,
+                                       apr_dbd_t *sql,
+                                       apr_dbd_results_t **results,
+                                       sqlite3_stmt *stmt, int seek)
 {
-    sqlite3_stmt *stmt = NULL;
-    const char *tail = NULL;
-    int i, ret, retry_count = 0;
+    int i, ret, retry_count = 0, column_count;
     size_t num_tuples = 0;
     int increment = 0;
     apr_dbd_row_t *row = NULL;
@@ -89,6 +94,97 @@
     apr_dbd_column_t *column;
     char *hold = NULL;
 
+    column_count = sqlite3_column_count(stmt);
+    if (!*results) {
+        *results = apr_pcalloc(pool, sizeof(apr_dbd_results_t));
+    }
+    (*results)->stmt = stmt;
+    (*results)->sz = column_count;
+    (*results)->random = seek;
+    (*results)->next_row = 0;
+    (*results)->tuples = 0;
+    (*results)->col_names = apr_pcalloc(pool, column_count * sizeof(char *));
+    (*results)->pool = pool;
+    do {
+        ret = sqlite3_step(stmt);
+        if (ret == SQLITE_BUSY) {
+            if (retry_count++ > MAX_RETRY_COUNT) {
+                ret = SQLITE_ERROR;
+            } else {
+                apr_dbd_mutex_unlock();
+                apr_sleep(MAX_RETRY_SLEEP);
+                apr_dbd_mutex_lock();
+            }
+        } else if (ret == SQLITE_ROW) {
+            int length;
+            apr_dbd_column_t *col;
+            row = apr_palloc(pool, sizeof(apr_dbd_row_t));
+            row->res = *results;
+            increment = sizeof(apr_dbd_column_t *);
+            length = increment * (*results)->sz;
+            row->columns = apr_palloc(pool, length);
+            row->columnCount = column_count;
+            for (i = 0; i < (*results)->sz; i++) {
+                column = apr_palloc(pool, sizeof(apr_dbd_column_t));
+                row->columns[i] = column;
+                /* copy column name once only */
+                if ((*results)->col_names[i] == NULL) {
+                    (*results)->col_names[i] =
+                        apr_pstrdup(pool, sqlite3_column_name(stmt, i));
+                }
+                column->name = (*results)->col_names[i];
+                column->size = sqlite3_column_bytes(stmt, i);
+                column->type = sqlite3_column_type(stmt, i);
+                column->value = NULL;
+                switch (column->type) {
+                case SQLITE_FLOAT:
+                case SQLITE_INTEGER:
+                case SQLITE_TEXT:
+                    hold = (char *) sqlite3_column_text(stmt, i);
+                    if (hold) {
+                        column->value = apr_pstrmemdup(pool, hold,
+                                                       column->size);
+                    }
+                    break;
+                case SQLITE_BLOB:
+                    hold = (char *) sqlite3_column_blob(stmt, i);
+                    if (hold) {
+                        column->value = apr_pstrmemdup(pool, hold,
+                                                       column->size);
+                    }
+                    break;
+                case SQLITE_NULL:
+                    break;
+                }
+                col = row->columns[i];
+            }
+            row->rownum = num_tuples++;
+            row->next_row = 0;
+            (*results)->tuples = num_tuples;
+            if ((*results)->next_row == 0) {
+                (*results)->next_row = row;
+            }
+            if (lastrow != 0) {
+                lastrow->next_row = row;
+            }
+            lastrow = row;
+        }
+    } while (ret == SQLITE_ROW || ret == SQLITE_BUSY);
+
+    if (dbd_sqlite3_is_success(ret)) {
+        ret = 0;
+    }
+    return ret;
+}
+
+static int dbd_sqlite3_select(apr_pool_t *pool, apr_dbd_t *sql,
+                              apr_dbd_results_t **results, const char *query,
+                              int seek)
+{
+    sqlite3_stmt *stmt = NULL;
+    const char *tail = NULL;
+    int ret;
+
     if (sql->trans && sql->trans->errnum) {
         return sql->trans->errnum;
     }
@@ -96,87 +192,11 @@
     apr_dbd_mutex_lock();
 
     ret = sqlite3_prepare(sql->conn, query, strlen(query), &stmt, &tail);
-    if (!dbd_sqlite3_is_success(ret)) {
-        apr_dbd_mutex_unlock();
-        return ret;
-    } else {
-        int column_count;
-        column_count = sqlite3_column_count(stmt);
-        if (!*results) {
-            *results = apr_pcalloc(pool, sizeof(apr_dbd_results_t));
-        }
-        (*results)->stmt = stmt;
-        (*results)->sz = column_count;
-        (*results)->random = seek;
-        (*results)->next_row = 0;
-        (*results)->tuples = 0;
-        (*results)->col_names = apr_pcalloc(pool,
-                                            column_count * sizeof(char *));
-        do {
-            ret = sqlite3_step(stmt);
-            if (ret == SQLITE_BUSY) {
-                if (retry_count++ > MAX_RETRY_COUNT) {
-                    ret = SQLITE_ERROR;
-                } else {
-                    apr_dbd_mutex_unlock();
-                    apr_sleep(MAX_RETRY_SLEEP);
-                    apr_dbd_mutex_lock();
-                }
-            } else if (ret == SQLITE_ROW) {
-                int length;
-                apr_dbd_column_t *col;
-                row = apr_palloc(pool, sizeof(apr_dbd_row_t));
-                row->res = *results;
-                increment = sizeof(apr_dbd_column_t *);
-                length = increment * (*results)->sz;
-                row->columns = apr_palloc(pool, length);
-                row->columnCount = column_count;
-                for (i = 0; i < (*results)->sz; i++) {
-                    column = apr_palloc(pool, sizeof(apr_dbd_column_t));
-                    row->columns[i] = column;
-                    /* copy column name once only */
-                    if ((*results)->col_names[i] == NULL) {
-                      (*results)->col_names[i] =
-                          apr_pstrdup(pool, sqlite3_column_name(stmt, i));
-                    }
-                    column->name = (*results)->col_names[i];
-                    column->size = sqlite3_column_bytes(stmt, i);
-                    column->type = sqlite3_column_type(stmt, i);
-                    column->value = NULL;
-                    switch (column->type) {
-                    case SQLITE_FLOAT:
-                    case SQLITE_INTEGER:
-                    case SQLITE_TEXT:
-                        hold = NULL;
-                        hold = (char *) sqlite3_column_text(stmt, i);
-                        if (hold) {
-                            column->value = apr_palloc(pool, column->size + 1);
-                            strncpy(column->value, hold, column->size + 1);
-                        }
-                        break;
-                    case SQLITE_BLOB:
-                        break;
-                    case SQLITE_NULL:
-                        break;
-                    }
-                    col = row->columns[i];
-                }
-                row->rownum = num_tuples++;
-                row->next_row = 0;
-                (*results)->tuples = num_tuples;
-                if ((*results)->next_row == 0) {
-                    (*results)->next_row = row;
-                }
-                if (lastrow != 0) {
-                    lastrow->next_row = row;
-                }
-                lastrow = row;
-            } else if (ret == SQLITE_DONE) {
-                ret = SQLITE_OK;
-            }
-        } while (ret == SQLITE_ROW || ret == SQLITE_BUSY);
+    if (dbd_sqlite3_is_success(ret)) {
+        ret = dbd_sqlite3_select_internal(pool, sql, results, stmt, seek);
     }
-    ret = sqlite3_finalize(stmt);
+    sqlite3_finalize(stmt);
+
     apr_dbd_mutex_unlock();
 
     if (TXN_NOTICE_ERRORS(sql->trans)) {
@@ -233,11 +253,113 @@
     return value;
 }
 
+static apr_status_t dbd_sqlite3_datum_get(const apr_dbd_row_t *row, int n,
+                                          apr_dbd_type_e type, void *data)
+{
+    if ((n < 0) || (n >= row->res->sz)) {
+      return APR_EGENERAL;
+    }
+
+    if (row->columns[n]->type == SQLITE_NULL) {
+        return APR_ENOENT;
+    }
+
+    switch (type) {
+    case APR_DBD_TYPE_TINY:
+        *(char*)data = atoi(row->columns[n]->value);
+        break;
+    case APR_DBD_TYPE_UTINY:
+        *(unsigned char*)data = atoi(row->columns[n]->value);
+        break;
+    case APR_DBD_TYPE_SHORT:
+        *(short*)data = atoi(row->columns[n]->value);
+        break;
+    case APR_DBD_TYPE_USHORT:
+        *(unsigned short*)data = atoi(row->columns[n]->value);
+        break;
+    case APR_DBD_TYPE_INT:
+        *(int*)data = atoi(row->columns[n]->value);
+        break;
+    case APR_DBD_TYPE_UINT:
+        *(unsigned int*)data = atoi(row->columns[n]->value);
+        break;
+    case APR_DBD_TYPE_LONG:
+        *(long*)data = atol(row->columns[n]->value);
+        break;
+    case APR_DBD_TYPE_ULONG:
+        *(unsigned long*)data = atol(row->columns[n]->value);
+        break;
+    case APR_DBD_TYPE_LONGLONG:
+        *(apr_int64_t*)data = apr_atoi64(row->columns[n]->value);
+        break;
+    case APR_DBD_TYPE_ULONGLONG:
+        *(apr_uint64_t*)data = apr_atoi64(row->columns[n]->value);
+        break;
+    case APR_DBD_TYPE_FLOAT:
+        *(float*)data = atof(row->columns[n]->value);
+        break;
+    case APR_DBD_TYPE_DOUBLE:
+        *(double*)data = atof(row->columns[n]->value);
+        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->columns[n]->value;
+        break;
+    case APR_DBD_TYPE_BLOB:
+    case APR_DBD_TYPE_CLOB:
+        {
+        apr_bucket *e;
+        apr_bucket_brigade *b = (apr_bucket_brigade*)data;
+
+        e = apr_bucket_pool_create(row->columns[n]->value,
+                                   row->columns[n]->size,
+                                   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 APR_SUCCESS;
+}
+
 static const char *dbd_sqlite3_error(apr_dbd_t *sql, int n)
 {
     return sqlite3_errmsg(sql->conn);
 }
 
+static int dbd_sqlite3_query_internal(apr_dbd_t *sql, sqlite3_stmt *stmt,
+                                      int *nrows)
+{
+    int ret = -1, retry_count = 0;
+
+    while(retry_count++ <= MAX_RETRY_COUNT) {
+        ret = sqlite3_step(stmt);
+        if (ret != SQLITE_BUSY)
+            break;
+
+        apr_dbd_mutex_unlock();
+        apr_sleep(MAX_RETRY_SLEEP);
+        apr_dbd_mutex_lock();
+    }
+
+    *nrows = sqlite3_changes(sql->conn);
+
+    if (dbd_sqlite3_is_success(ret)) {
+        ret = 0;
+    }
+    return ret;
+}
+
 static int dbd_sqlite3_query(apr_dbd_t *sql, int *nrows, const char *query)
 {
     sqlite3_stmt *stmt = NULL;
@@ -252,34 +374,21 @@
     apr_dbd_mutex_lock();
 
     do {
-        int retry_count = 0;
-
         ret = sqlite3_prepare(sql->conn, query, length, &stmt, &tail);
         if (ret != SQLITE_OK) {
             sqlite3_finalize(stmt);
             break;
         }
 
-        while(retry_count++ <= MAX_RETRY_COUNT) {
-            ret = sqlite3_step(stmt);
-            if (ret != SQLITE_BUSY)
-                break;
-
-            apr_dbd_mutex_unlock();
-            apr_sleep(MAX_RETRY_SLEEP);
-            apr_dbd_mutex_lock();
-        }
+        ret = dbd_sqlite3_query_internal(sql, stmt, nrows);
 
-        *nrows = sqlite3_changes(sql->conn);
         sqlite3_finalize(stmt);
         length -= (tail - query);
         query = tail;
     } while (length > 0);
 
-    if (dbd_sqlite3_is_success(ret)) {
-        ret = 0;
-    }
     apr_dbd_mutex_unlock();
+
     if (TXN_NOTICE_ERRORS(sql->trans)) {
         sql->trans->errnum = ret;
     }
@@ -303,42 +412,25 @@
 
 static int dbd_sqlite3_prepare(apr_pool_t *pool, apr_dbd_t *sql,
                                const char *query, const char *label,
+                               int nargs, int nvals, apr_dbd_type_e *types,
                                apr_dbd_prepared_t **statement)
 {
     sqlite3_stmt *stmt;
-    char *p, *slquery = apr_pstrdup(pool, query);
-    const char *tail = NULL, *q;
+    const char *tail = NULL;
     int ret;
 
-    for (p = slquery, 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;
-        }
-    }
-    *p = 0;
-
     apr_dbd_mutex_lock();
 
-    ret = sqlite3_prepare(sql->conn, slquery, strlen(query), &stmt, &tail);
+    ret = sqlite3_prepare(sql->conn, query, strlen(query), &stmt, &tail);
     if (ret == SQLITE_OK) {
         apr_dbd_prepared_t *prep; 
 
         prep = apr_pcalloc(sql->pool, sizeof(*prep));
         prep->stmt = stmt;
         prep->next = sql->prep;
+        prep->nargs = nargs;
+        prep->nvals = nvals;
+        prep->types = types;
 
         /* link new statement to the handle */
         sql->prep = prep;
@@ -353,12 +445,46 @@
     return ret;
 }
 
+static void dbd_sqlite3_bind(apr_dbd_prepared_t *statement, const char **values)
+{
+    sqlite3_stmt *stmt = statement->stmt;
+    int i, j;
+
+    for (i = 0, j = 0; i < statement->nargs; i++, j++) {
+        if (values[j] == NULL) {
+            sqlite3_bind_null(stmt, i + 1);
+        }
+        else {
+            switch (statement->types[i]) {
+            case APR_DBD_TYPE_BLOB:
+            case APR_DBD_TYPE_CLOB:
+                {
+                char *data = (char *)values[j];
+                int size = atoi((char*)values[++j]);
+
+                /* skip table and column */
+                j += 2;
+
+                sqlite3_bind_blob(stmt, i + 1, data, size, SQLITE_STATIC);
+                }
+                break;
+            default:
+                sqlite3_bind_text(stmt, i + 1, values[j],
+                                  strlen(values[j]), SQLITE_STATIC);
+                break;
+            }
+        }
+    }
+
+    return;
+}
+
 static int dbd_sqlite3_pquery(apr_pool_t *pool, apr_dbd_t *sql,
                               int *nrows, apr_dbd_prepared_t *statement,
-                              int nargs, const char **values)
+                              const char **values)
 {
     sqlite3_stmt *stmt = statement->stmt;
-    int ret = -1, retry_count = 0, i;
+    int ret = -1;
 
     if (sql->trans && sql->trans->errnum) {
         return sql->trans->errnum;
@@ -368,34 +494,18 @@
 
     ret = sqlite3_reset(stmt);
     if (ret == SQLITE_OK) {
-        for (i=0; i < nargs; i++) {
-            sqlite3_bind_text(stmt, i + 1, values[i], strlen(values[i]),
-                              SQLITE_STATIC);
-        }
-
-        while(retry_count++ <= MAX_RETRY_COUNT) {
-            ret = sqlite3_step(stmt);
-            if (ret != SQLITE_BUSY)
-                break;
-
-            apr_dbd_mutex_unlock();
-            apr_sleep(MAX_RETRY_SLEEP);
-            apr_dbd_mutex_lock();
-        }
+        dbd_sqlite3_bind(statement, values);
 
-        *nrows = sqlite3_changes(sql->conn);
+        ret = dbd_sqlite3_query_internal(sql, stmt, nrows);
 
         sqlite3_reset(stmt);
     }
 
-    if (dbd_sqlite3_is_success(ret)) {
-        ret = 0;
-    }
     apr_dbd_mutex_unlock();
+
     if (TXN_NOTICE_ERRORS(sql->trans)) {
         sql->trans->errnum = ret;
     }
-
     return ret;
 }
 
@@ -403,35 +513,28 @@
                                apr_dbd_prepared_t *statement, va_list args)
 {
     const char **values;
-    int i, nargs;
+    int i;
 
     if (sql->trans && sql->trans->errnum) {
         return sql->trans->errnum;
     }
 
-    nargs = sqlite3_bind_parameter_count(statement->stmt);
-    values = apr_palloc(pool, sizeof(*values) * nargs);
+    values = apr_palloc(pool, sizeof(*values) * statement->nvals);
 
-    for (i = 0; i < nargs; i++) {
-        values[i] = apr_pstrdup(pool, va_arg(args, const char*));
+    for (i = 0; i < statement->nvals; i++) {
+        values[i] = va_arg(args, const char*);
     }
 
-    return dbd_sqlite3_pquery(pool, sql, nrows, statement, nargs, values);
+    return dbd_sqlite3_pquery(pool, sql, nrows, statement, values);
 }
 
 static int dbd_sqlite3_pselect(apr_pool_t *pool, apr_dbd_t *sql,
                                apr_dbd_results_t **results,
                                apr_dbd_prepared_t *statement, int seek,
-                               int nargs, const char **values)
+                               const char **values)
 {
     sqlite3_stmt *stmt = statement->stmt;
-    int i, ret, retry_count = 0;
-    size_t num_tuples = 0;
-    int increment = 0;
-    apr_dbd_row_t *row = NULL;
-    apr_dbd_row_t *lastrow = NULL;
-    apr_dbd_column_t *column;
-    char *hold = NULL;
+    int ret;
 
     if (sql->trans && sql->trans->errnum) {
         return sql->trans->errnum;
@@ -441,90 +544,13 @@
 
     ret = sqlite3_reset(stmt);
     if (ret == SQLITE_OK) {
-        int column_count;
+        dbd_sqlite3_bind(statement, values);
 
-        for (i=0; i < nargs; i++) {
-            sqlite3_bind_text(stmt, i + 1, values[i], strlen(values[i]),
-                              SQLITE_STATIC);
-        }
-
-        column_count = sqlite3_column_count(stmt);
-        if (!*results) {
-            *results = apr_pcalloc(pool, sizeof(apr_dbd_results_t));
-        }
-        (*results)->stmt = stmt;
-        (*results)->sz = column_count;
-        (*results)->random = seek;
-        (*results)->next_row = 0;
-        (*results)->tuples = 0;
-        (*results)->col_names = apr_pcalloc(pool,
-                                            column_count * sizeof(char *));
-        do {
-            ret = sqlite3_step(stmt);
-            if (ret == SQLITE_BUSY) {
-                if (retry_count++ > MAX_RETRY_COUNT) {
-                    ret = SQLITE_ERROR;
-                } else {
-                    apr_dbd_mutex_unlock();
-                    apr_sleep(MAX_RETRY_SLEEP);
-                    apr_dbd_mutex_lock();
-                }
-            } else if (ret == SQLITE_ROW) {
-                int length;
-                apr_dbd_column_t *col;
-                row = apr_palloc(pool, sizeof(apr_dbd_row_t));
-                row->res = *results;
-                increment = sizeof(apr_dbd_column_t *);
-                length = increment * (*results)->sz;
-                row->columns = apr_palloc(pool, length);
-                row->columnCount = column_count;
-                for (i = 0; i < (*results)->sz; i++) {
-                    column = apr_palloc(pool, sizeof(apr_dbd_column_t));
-                    row->columns[i] = column;
-                    /* copy column name once only */
-                    if ((*results)->col_names[i] == NULL) {
-                      (*results)->col_names[i] =
-                          apr_pstrdup(pool, sqlite3_column_name(stmt, i));
-                    }
-                    column->name = (*results)->col_names[i];
-                    column->size = sqlite3_column_bytes(stmt, i);
-                    column->type = sqlite3_column_type(stmt, i);
-                    column->value = NULL;
-                    switch (column->type) {
-                    case SQLITE_FLOAT:
-                    case SQLITE_INTEGER:
-                    case SQLITE_TEXT:
-                        hold = NULL;
-                        hold = (char *) sqlite3_column_text(stmt, i);
-                        if (hold) {
-                            column->value = apr_palloc(pool, column->size + 1);
-                            strncpy(column->value, hold, column->size + 1);
-                        }
-                        break;
-                    case SQLITE_BLOB:
-                        break;
-                    case SQLITE_NULL:
-                        break;
-                    }
-                    col = row->columns[i];
-                }
-                row->rownum = num_tuples++;
-                row->next_row = 0;
-                (*results)->tuples = num_tuples;
-                if ((*results)->next_row == 0) {
-                    (*results)->next_row = row;
-                }
-                if (lastrow != 0) {
-                    lastrow->next_row = row;
-                }
-                lastrow = row;
-            } else if (ret == SQLITE_DONE) {
-                ret = SQLITE_OK;
-            }
-        } while (ret == SQLITE_ROW || ret == SQLITE_BUSY);
+        ret = dbd_sqlite3_select_internal(pool, sql, results, stmt, seek);
 
         sqlite3_reset(stmt);
     }
+
     apr_dbd_mutex_unlock();
 
     if (TXN_NOTICE_ERRORS(sql->trans)) {
@@ -539,21 +565,200 @@
                                 va_list args)
 {
     const char **values;
-    int i, nargs;
+    int i;
+
+    if (sql->trans && sql->trans->errnum) {
+        return sql->trans->errnum;
+    }
+
+    values = apr_palloc(pool, sizeof(*values) * statement->nvals);
+
+    for (i = 0; i < statement->nvals; i++) {
+        values[i] = va_arg(args, const char*);
+    }
+
+    return dbd_sqlite3_pselect(pool, sql, results, statement, seek, values);
+}
+
+static void dbd_sqlite3_bbind(apr_dbd_prepared_t * statement,
+                              const void **values)
+{
+    sqlite3_stmt *stmt = statement->stmt;
+    int i, j;
+    apr_dbd_type_e type;
+
+    for (i = 0, j = 0; i < statement->nargs; i++, j++) {
+        type = (values[j] == NULL ? APR_DBD_TYPE_NULL : statement->types[i]);
+
+        switch (type) {
+        case APR_DBD_TYPE_TINY:
+            sqlite3_bind_int(stmt, i + 1, *(char*)values[j]);
+            break;
+        case APR_DBD_TYPE_UTINY:
+            sqlite3_bind_int(stmt, i + 1, *(unsigned char*)values[j]);
+            break;
+        case APR_DBD_TYPE_SHORT:
+            sqlite3_bind_int(stmt, i + 1, *(short*)values[j]);
+            break;
+        case APR_DBD_TYPE_USHORT:
+            sqlite3_bind_int(stmt, i + 1, *(unsigned short*)values[j]);
+            break;
+        case APR_DBD_TYPE_INT:
+            sqlite3_bind_int(stmt, i + 1, *(int*)values[j]);
+            break;
+        case APR_DBD_TYPE_UINT:
+            sqlite3_bind_int(stmt, i + 1, *(unsigned int*)values[j]);
+            break;
+        case APR_DBD_TYPE_LONG:
+            sqlite3_bind_int64(stmt, i + 1, *(long*)values[j]);
+            break;
+        case APR_DBD_TYPE_ULONG:
+            sqlite3_bind_int64(stmt, i + 1, *(unsigned long*)values[j]);
+            break;
+        case APR_DBD_TYPE_LONGLONG:
+            sqlite3_bind_int64(stmt, i + 1, *(apr_int64_t*)values[j]);
+            break;
+        case APR_DBD_TYPE_ULONGLONG:
+            sqlite3_bind_int64(stmt, i + 1, *(apr_uint64_t*)values[j]);
+            break;
+        case APR_DBD_TYPE_FLOAT:
+            sqlite3_bind_double(stmt, i + 1, *(float*)values[j]);
+            break;
+        case APR_DBD_TYPE_DOUBLE:
+            sqlite3_bind_double(stmt, i + 1, *(double*)values[j]);
+            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:
+            sqlite3_bind_text(stmt, i + 1, values[j], strlen(values[j]),
+                              SQLITE_STATIC);
+            break;
+        case APR_DBD_TYPE_BLOB:
+        case APR_DBD_TYPE_CLOB:
+            {
+            char *data = (char*)values[j];
+            apr_size_t size = *(apr_size_t*)values[++j];
+
+            sqlite3_bind_blob(stmt, i + 1, data, size, SQLITE_STATIC);
+
+            /* skip table and column */
+            j += 2;
+            }
+            break;
+        case APR_DBD_TYPE_NULL:
+        default:
+            sqlite3_bind_null(stmt, i + 1);
+            break;
+        }
+    }
+
+    return;
+}
+
+static int dbd_sqlite3_pbquery(apr_pool_t * pool, apr_dbd_t * sql,
+                               int *nrows, apr_dbd_prepared_t * statement,
+                               const void **values)
+{
+    sqlite3_stmt *stmt = statement->stmt;
+    int ret = -1;
+
+    if (sql->trans && sql->trans->errnum) {
+        return sql->trans->errnum;
+    }
+
+    apr_dbd_mutex_lock();
+
+    ret = sqlite3_reset(stmt);
+    if (ret == SQLITE_OK) {
+        dbd_sqlite3_bbind(statement, values);
+
+        ret = dbd_sqlite3_query_internal(sql, stmt, nrows);
+
+        sqlite3_reset(stmt);
+    }
+
+    apr_dbd_mutex_unlock();
+
+    if (TXN_NOTICE_ERRORS(sql->trans)) {
+        sql->trans->errnum = ret;
+    }
+    return ret;
+}
+
+static int dbd_sqlite3_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->nvals);
+
+    for (i = 0; i < statement->nvals; i++) {
+        values[i] = va_arg(args, const void*);
+    }
+
+    return dbd_sqlite3_pbquery(pool, sql, nrows, statement, values);
+}
+
+static int dbd_sqlite3_pbselect(apr_pool_t * pool, apr_dbd_t * sql,
+                                apr_dbd_results_t ** results,
+                                apr_dbd_prepared_t * statement,
+                                int seek, const void **values)
+{
+    sqlite3_stmt *stmt = statement->stmt;
+    int ret;
+
+    if (sql->trans && sql->trans->errnum) {
+        return sql->trans->errnum;
+    }
+
+    apr_dbd_mutex_lock();
+
+    ret = sqlite3_reset(stmt);
+    if (ret == SQLITE_OK) {
+        dbd_sqlite3_bbind(statement, values);
+
+        ret = dbd_sqlite3_select_internal(pool, sql, results, stmt, seek);
+
+        sqlite3_reset(stmt);
+    }
+
+    apr_dbd_mutex_unlock();
+
+    if (TXN_NOTICE_ERRORS(sql->trans)) {
+        sql->trans->errnum = ret;
+    }
+    return ret;
+}
+
+static int dbd_sqlite3_pvbselect(apr_pool_t * pool, apr_dbd_t * sql,
+                                 apr_dbd_results_t ** results,
+                                 apr_dbd_prepared_t * statement, int seek,
+                                 va_list args)
+{
+    const void **values;
+    int i;
 
     if (sql->trans && sql->trans->errnum) {
         return sql->trans->errnum;
     }
 
-    nargs = sqlite3_bind_parameter_count(statement->stmt);
-    values = apr_palloc(pool, sizeof(*values) * nargs);
+    values = apr_palloc(pool, sizeof(*values) * statement->nvals);
 
-    for (i = 0; i < nargs; i++) {
-        values[i] = apr_pstrdup(pool, va_arg(args, const char*));
+    for (i = 0; i < statement->nvals; i++) {
+        values[i] = va_arg(args, const void*);
     }
 
-    return dbd_sqlite3_pselect(pool, sql, results, statement,
-                               seek, nargs, values);
+    return dbd_sqlite3_pbselect(pool, sql, results, statement, seek, values);
 }
 
 static int dbd_sqlite3_start_transaction(apr_pool_t *pool,
@@ -696,6 +901,12 @@
     dbd_sqlite3_pselect,
     dbd_sqlite3_get_name,
     dbd_sqlite3_transaction_mode_get,
-    dbd_sqlite3_transaction_mode_set
+    dbd_sqlite3_transaction_mode_set,
+    "?",
+    dbd_sqlite3_pvbquery,
+    dbd_sqlite3_pvbselect,
+    dbd_sqlite3_pbquery,
+    dbd_sqlite3_pbselect,
+    dbd_sqlite3_datum_get
 };
 #endif

Modified: apr/apr-util/trunk/include/apr_dbd.h
URL: http://svn.apache.org/viewvc/apr/apr-util/trunk/include/apr_dbd.h?view=diff&rev=508700&r1=508699&r2=508700
==============================================================================
--- apr/apr-util/trunk/include/apr_dbd.h (original)
+++ apr/apr-util/trunk/include/apr_dbd.h Fri Feb 16 18:50:17 2007
@@ -38,6 +38,46 @@
  * @{
  */
 
+/**
+ * Mapping of C to SQL types, used for prepared statements.
+ * @remarks
+ * For apr_dbd_p[v]query/select functions, in and out parameters are always
+ * const char * (i.e. regular nul terminated strings). LOB types are passed
+ * with four (4) arguments: payload, length, table and column, all as const
+ * char *, where table and column are reserved for future use by Oracle.
+ * @remarks
+ * For apr_dbd_p[v]bquery/select functions, in and out parameters are
+ * described next to each enumeration constant and are generally native binary
+ * types or some APR data type. LOB types are passed with four (4) arguments:
+ * payload (char*), length (apr_size_t*), table (char*) and column (char*).
+ * Table and column are reserved for future use by Oracle.
+ */
+typedef enum {
+    APR_DBD_TYPE_NONE,
+    APR_DBD_TYPE_TINY,       /**< \%hhd : in, out: char* */
+    APR_DBD_TYPE_UTINY,      /**< \%hhu : in, out: unsigned char* */
+    APR_DBD_TYPE_SHORT,      /**< \%hd  : in, out: short* */
+    APR_DBD_TYPE_USHORT,     /**< \%hu  : in, out: unsigned short* */
+    APR_DBD_TYPE_INT,        /**< \%d   : in, out: int* */
+    APR_DBD_TYPE_UINT,       /**< \%u   : in, out: unsigned int* */
+    APR_DBD_TYPE_LONG,       /**< \%ld  : in, out: long* */
+    APR_DBD_TYPE_ULONG,      /**< \%lu  : in, out: unsigned long* */
+    APR_DBD_TYPE_LONGLONG,   /**< \%lld : in, out: apr_int64_t* */
+    APR_DBD_TYPE_ULONGLONG,  /**< \%llu : in, out: apr_uint64_t* */
+    APR_DBD_TYPE_FLOAT,      /**< \%f   : in, out: float* */
+    APR_DBD_TYPE_DOUBLE,     /**< \%lf  : in, out: double* */
+    APR_DBD_TYPE_STRING,     /**< \%s   : in: char*, out: char** */
+    APR_DBD_TYPE_TEXT,       /**< \%pDt : in: char*, out: char** */
+    APR_DBD_TYPE_TIME,       /**< \%pDi : in: char*, out: char** */
+    APR_DBD_TYPE_DATE,       /**< \%pDd : in: char*, out: char** */
+    APR_DBD_TYPE_DATETIME,   /**< \%pDa : in: char*, out: char** */
+    APR_DBD_TYPE_TIMESTAMP,  /**< \%pDs : in: char*, out: char** */
+    APR_DBD_TYPE_ZTIMESTAMP, /**< \%pDz : in: char*, out: char** */
+    APR_DBD_TYPE_BLOB,       /**< \%pDb : in: char* apr_size_t* char* char*, out: apr_bucket_brigade* */
+    APR_DBD_TYPE_CLOB,       /**< \%pDc : in: char* apr_size_t* char* char*, out: apr_bucket_brigade* */
+    APR_DBD_TYPE_NULL        /**< \%pDn : in: void*, out: void** */
+} apr_dbd_type_e;
+
 /* These are opaque structs.  Instantiation is up to each backend */
 typedef struct apr_dbd_driver_t apr_dbd_driver_t;
 typedef struct apr_dbd_t apr_dbd_t;
@@ -316,12 +356,22 @@
  *                 (eg within a Request in httpd)
  *  @param statement - statement to prepare.  May point to null on entry.
  *  @return 0 for success or error code
- *  @remarks To specify parameters of the prepared query, use %s in place of
- *  database specific parameter syntax (e.g. for PostgreSQL, this would be $1,
- *  $2, for SQLite3 this would be ? etc.). For instance: "SELECT name FROM
- *  customers WHERE name=%s" would be a query that this function understands.
- *  Some drivers may support different data types using printf-like format:
- *  for example %d (e.g. PostgreSQL) or %f for numeric data.
+ *  @remarks To specify parameters of the prepared query, use \%s, \%d etc.
+ *  (see below for full list) in place of database specific parameter syntax
+ *  (e.g.  for PostgreSQL, this would be $1, $2, for SQLite3 this would be ?
+ *  etc.).  For instance: "SELECT name FROM customers WHERE name=%s" would be
+ *  a query that this function understands.
+ *  @remarks Here is the full list of format specifiers that this function
+ *  understands and what they map to in SQL: \%hhd (TINY INT), \%hhu (UNSIGNED
+ *  TINY INT), \%hd (SHORT), \%hu (UNSIGNED SHORT), \%d (INT), \%u (UNSIGNED
+ *  INT), \%ld (LONG), \%lu (UNSIGNED LONG), \%lld (LONG LONG), \%llu
+ *  (UNSIGNED LONG LONG), \%f (FLOAT, REAL), \%lf (DOUBLE PRECISION), \%s
+ *  (VARCHAR), \%pDt (TEXT), \%pDi (TIME), \%pDd (DATE), \%pDa (SQL:
+ *  DATETIME), \%pDs (TIMESTAMP), \%pDz (TIMESTAMP WITH TIME ZONE), \%pDb
+ *  (BLOB), \%pDc (CLOB) and \%pDn (NULL). Not all databases have support for
+ *  all these types, so the underlying driver will attempt the "best match"
+ *  where possible.  A \% followed by any letter not in the above list will be
+ *  interpreted as VARCHAR (i.e. \%s).
  */
 APU_DECLARE(int) apr_dbd_prepare(const apr_dbd_driver_t *driver, apr_pool_t *pool,
                                  apr_dbd_t *handle, const char *query,
@@ -336,7 +386,7 @@
  *  @param handle - the connection
  *  @param nrows - number of rows affected.
  *  @param statement - the prepared statement to execute
- *  @param nargs - number of args to prepared statement
+ *  @param nargs - ignored (for backward compatibility only)
  *  @param args - args to prepared statement
  *  @return 0 for success or error code
  */
@@ -353,7 +403,7 @@
  *  @param res - pointer to query results.  May point to NULL on entry
  *  @param statement - the prepared statement to execute
  *  @param random - Whether to support random-access to results
- *  @param nargs - number of args to prepared statement
+ *  @param nargs - ignored (for backward compatibility only)
  *  @param args - args to prepared statement
  *  @return 0 for success or error code
  */
@@ -391,6 +441,83 @@
                                   apr_dbd_t *handle, apr_dbd_results_t **res,
                                   apr_dbd_prepared_t *statement, int random,
                                   ...);
+
+/** apr_dbd_pbquery: query using a prepared statement + binary args
+ *
+ *  @param driver - the driver
+ *  @param pool - working pool
+ *  @param handle - the connection
+ *  @param nrows - number of rows affected.
+ *  @param statement - the prepared statement to execute
+ *  @param args - binary args to prepared statement
+ *  @return 0 for success or error code
+ */
+APU_DECLARE(int) apr_dbd_pbquery(const apr_dbd_driver_t *driver,
+                                 apr_pool_t *pool, apr_dbd_t *handle,
+                                 int *nrows, apr_dbd_prepared_t *statement,
+                                 const void **args);
+
+/** apr_dbd_pbselect: select using a prepared statement + binary args
+ *
+ *  @param driver - the driver
+ *  @param pool - working pool
+ *  @param handle - the connection
+ *  @param res - pointer to query results.  May point to NULL on entry
+ *  @param statement - the prepared statement to execute
+ *  @param random - Whether to support random-access to results
+ *  @param args - binary args to prepared statement
+ *  @return 0 for success or error code
+ */
+APU_DECLARE(int) apr_dbd_pbselect(const apr_dbd_driver_t *driver,
+                                  apr_pool_t *pool,
+                                  apr_dbd_t *handle, apr_dbd_results_t **res,
+                                  apr_dbd_prepared_t *statement, int random,
+                                  const void **args);
+
+/** apr_dbd_pvbquery: query using a prepared statement + binary args
+ *
+ *  @param driver - the driver
+ *  @param pool - working pool
+ *  @param handle - the connection
+ *  @param nrows - number of rows affected.
+ *  @param statement - the prepared statement to execute
+ *  @param ... - varargs list of binary args
+ *  @return 0 for success or error code
+ */
+APU_DECLARE(int) apr_dbd_pvbquery(const apr_dbd_driver_t *driver,
+                                  apr_pool_t *pool,
+                                  apr_dbd_t *handle, int *nrows,
+                                  apr_dbd_prepared_t *statement, ...);
+
+/** apr_dbd_pvbselect: select using a prepared statement + binary args
+ *
+ *  @param driver - the driver
+ *  @param pool - working pool
+ *  @param handle - the connection
+ *  @param res - pointer to query results.  May point to NULL on entry
+ *  @param statement - the prepared statement to execute
+ *  @param random - Whether to support random-access to results
+ *  @param ... - varargs list of binary args
+ *  @return 0 for success or error code
+ */
+APU_DECLARE(int) apr_dbd_pvbselect(const apr_dbd_driver_t *driver,
+                                   apr_pool_t *pool,
+                                   apr_dbd_t *handle, apr_dbd_results_t **res,
+                                   apr_dbd_prepared_t *statement, int random,
+                                   ...);
+
+/** apr_dbd_datum_get: get a binary entry from a row
+ *
+ *  @param driver - the driver
+ *  @param row - row pointer
+ *  @param col - entry number
+ *  @param type - type of data to get
+ *  @param data - pointer to data, allocated by the caller
+ *  @return APR_SUCCESS on success, APR_ENOENT if data is NULL or APR_EGENERAL
+ */
+APU_DECLARE(apr_status_t) apr_dbd_datum_get(const apr_dbd_driver_t *driver,
+                                            apr_dbd_row_t *row, int col,
+                                            apr_dbd_type_e type, void *data);
 
 /** @} */
 

Modified: apr/apr-util/trunk/include/private/apr_dbd_internal.h
URL: http://svn.apache.org/viewvc/apr/apr-util/trunk/include/private/apr_dbd_internal.h?view=diff&rev=508700&r1=508699&r2=508700
==============================================================================
--- apr/apr-util/trunk/include/private/apr_dbd_internal.h (original)
+++ apr/apr-util/trunk/include/private/apr_dbd_internal.h Fri Feb 16 18:50:17 2007
@@ -196,11 +196,15 @@
      *  @param label - A label for the prepared statement.
      *                 use NULL for temporary prepared statements
      *                 (eg within a Request in httpd)
+     *  @param nargs - number of parameters in the query
+     *  @param nvals - number of values passed in p[b]query/select
+     *  @param types - pointer to an array with types of parameters
      *  @param statement - statement to prepare.  May point to null on entry.
      *  @return 0 for success or error code
      */
     int (*prepare)(apr_pool_t *pool, apr_dbd_t *handle, const char *query,
-                   const char *label, apr_dbd_prepared_t **statement);
+                   const char *label, int nargs, int nvals,
+                   apr_dbd_type_e *types, apr_dbd_prepared_t **statement);
 
     /** pvquery: query using a prepared statement + args
      *
@@ -234,13 +238,11 @@
      *  @param handle - the connection
      *  @param nrows - number of rows affected.
      *  @param statement - the prepared statement to execute
-     *  @param nargs - number of args to prepared statement
      *  @param args - args to prepared statement
      *  @return 0 for success or error code
      */
     int (*pquery)(apr_pool_t *pool, apr_dbd_t *handle, int *nrows,
-                  apr_dbd_prepared_t *statement, int nargs,
-                  const char **args);
+                  apr_dbd_prepared_t *statement, const char **args);
 
     /** pselect: select using a prepared statement + args
      *
@@ -249,13 +251,12 @@
      *  @param res - pointer to query results.  May point to NULL on entry
      *  @param statement - the prepared statement to execute
      *  @param random - Whether to support random-access to results
-     *  @param nargs - number of args to prepared statement
      *  @param args - args to prepared statement
      *  @return 0 for success or error code
      */
     int (*pselect)(apr_pool_t *pool, apr_dbd_t *handle,
                    apr_dbd_results_t **res, apr_dbd_prepared_t *statement,
-                   int random, int nargs, const char **args);
+                   int random, const char **args);
 
   
     /** get_name: get a column title from a result set
@@ -280,6 +281,72 @@
      *  @return the mode of transaction in force after the call
      */
     int (*transaction_mode_set)(apr_dbd_transaction_t *trans, int mode);
+
+    /** format of prepared statement parameters */
+    const char *pformat;
+
+    /** pvbquery: query using a prepared statement + binary args
+     *
+     *  @param pool - working pool
+     *  @param handle - the connection
+     *  @param nrows - number of rows affected.
+     *  @param statement - the prepared statement to execute
+     *  @param args - binary args to prepared statement
+     *  @return 0 for success or error code
+     */
+    int (*pvbquery)(apr_pool_t *pool, apr_dbd_t *handle, int *nrows,
+                    apr_dbd_prepared_t *statement, va_list args);
+
+    /** pvbselect: select using a prepared statement + binary args
+     *
+     *  @param pool - working pool
+     *  @param handle - the connection
+     *  @param res - pointer to query results.  May point to NULL on entry
+     *  @param statement - the prepared statement to execute
+     *  @param random - Whether to support random-access to results
+     *  @param args - binary args to prepared statement
+     *  @return 0 for success or error code
+     */
+    int (*pvbselect)(apr_pool_t *pool, apr_dbd_t *handle,
+                     apr_dbd_results_t **res,
+                     apr_dbd_prepared_t *statement, int random, va_list args);
+
+    /** pbquery: query using a prepared statement + binary args
+     *
+     *  @param pool - working pool
+     *  @param handle - the connection
+     *  @param nrows - number of rows affected.
+     *  @param statement - the prepared statement to execute
+     *  @param args - binary args to prepared statement
+     *  @return 0 for success or error code
+     */
+    int (*pbquery)(apr_pool_t *pool, apr_dbd_t *handle, int *nrows,
+                   apr_dbd_prepared_t *statement,const void **args);
+
+    /** pbselect: select using a prepared statement + binary args
+     *
+     *  @param pool - working pool
+     *  @param handle - the connection
+     *  @param res - pointer to query results.  May point to NULL on entry
+     *  @param statement - the prepared statement to execute
+     *  @param random - Whether to support random-access to results
+     *  @param args - binary args to prepared statement
+     *  @return 0 for success or error code
+     */
+    int (*pbselect)(apr_pool_t *pool, apr_dbd_t *handle,
+                    apr_dbd_results_t **res, apr_dbd_prepared_t *statement,
+                    int random, const void **args);
+  
+    /** datum_get: get a binary entry from a row
+     *
+     *  @param row - row pointer
+     *  @param col - entry number
+     *  @param type - type of data to get
+     *  @param data - pointer to data, allocated by the caller
+     *  @return APR_SUCCESS, an error code on error or if col is out of bounds
+     */
+    apr_status_t (*datum_get)(const apr_dbd_row_t *row, int col,
+                              apr_dbd_type_e type, void *data);
 };
 
 /* Export mutex lock/unlock for drivers that need it */



Mime
View raw message