On Fri, 2007-10-19 at 15:05 +1000, Bojan Smojver wrote:

> Yeah, that's been the problem of the 1.2 API. In 1.3, we cannot do it
> with the same function (API/ABI backward compatibility), but we can
> introduce another function (e.g. apr_dbd_open_ex()) that does return an
> error.

Perhaps something like this (compiles but untested)...

-- 
Bojan
Index: include/apr_dbd.h
===================================================================
--- include/apr_dbd.h	(revision 586254)
+++ include/apr_dbd.h	(working copy)
@@ -105,6 +105,42 @@
 APU_DECLARE(apr_status_t) apr_dbd_get_driver(apr_pool_t *pool, const char *name,
                                              const apr_dbd_driver_t **driver);
 
+/** apr_dbd_open_ex: open a connection to a backend
+ *
+ *  @param pool - working pool
+ *  @param params - arguments to driver (implementation-dependent)
+ *  @param handle - pointer to handle to return
+ *  @param driver - driver struct.
+ *  @param error - descriptive error.
+ *  @return APR_SUCCESS for success
+ *  @return APR_EGENERAL if driver exists but connection failed
+ *  @remarks PostgreSQL: the params is passed directly to the PQconnectdb()
+ *  function (check PostgreSQL documentation for more details on the syntax).
+ *  @remarks SQLite2: the params is split on a colon, with the first part used
+ *  as the filename and second part converted to an integer and used as file
+ *  mode.
+ *  @remarks SQLite3: the params is passed directly to the sqlite3_open()
+ *  function as a filename to be opened (check SQLite3 documentation for more
+ *  details).
+ *  @remarks Oracle: the params can have "user", "pass", "dbname" and "server"
+ *  keys, each followed by an equal sign and a value. Such key/value pairs can
+ *  be delimited by space, CR, LF, tab, semicolon, vertical bar or comma.
+ *  @remarks MySQL: the params can have "host", "port", "user", "pass",
+ *  "dbname", "sock", "flags" "fldsz" and "group" keys, each followed by an
+ *  equal sign and a value. Such key/value pairs can be delimited by space,
+ *  CR, LF, tab, semicolon, vertical bar or comma. For now, "flags" can only
+ *  recognise CLIENT_FOUND_ROWS (check MySQL manual for details). The value
+ *  associated with "fldsz" determines maximum amount of memory (in bytes) for
+ *  each of the fields in the result set of prepared statements. By default,
+ *  this value is 1 MB. The value associated with "group" determines which
+ *  group from configuration file to use (see MYSQL_READ_DEFAULT_GROUP option
+ *  of mysql_options() in MySQL manual).
+ */
+APU_DECLARE(apr_status_t) apr_dbd_open_ex(const apr_dbd_driver_t *driver,
+                                          apr_pool_t *pool, const char *params,
+                                          apr_dbd_t **handle,
+                                          const char **error);
+
 /** apr_dbd_open: open a connection to a backend
  *
  *  @param pool - working pool
Index: include/private/apr_dbd_internal.h
===================================================================
--- include/private/apr_dbd_internal.h	(revision 586254)
+++ include/private/apr_dbd_internal.h	(working copy)
@@ -62,10 +62,12 @@
      *  a lifetime other than a request
      *
      *  @param pool - a pool to use for error messages (if any).
-     *  @param s - server rec managing the underlying connection/pool.
+     *  @param params - connection parameters.
+     *  @param error - descriptive error.
      *  @return database handle, or NULL on error.
      */
-    apr_dbd_t *(*open)(apr_pool_t *pool, const char *params);
+    apr_dbd_t *(*open)(apr_pool_t *pool, const char *params,
+                       const char **error);
 
     /** check_conn: check status of a database connection
      *
Index: dbd/apr_dbd_sqlite2.c
===================================================================
--- dbd/apr_dbd_sqlite2.c	(revision 586254)
+++ dbd/apr_dbd_sqlite2.c	(working copy)
@@ -446,8 +446,15 @@
     return trans->mode = (mode & TXN_MODE_BITS);
 }
 
-static apr_dbd_t *dbd_sqlite_open(apr_pool_t * pool, const char *params_)
+static apr_status_t error_free(void *data)
 {
+    free(data);
+    return APR_SUCCESS;
+}
+
+static apr_dbd_t *dbd_sqlite_open(apr_pool_t * pool, const char *params_,
+                                  const char **error)
+{
     apr_dbd_t *sql;
     sqlite *conn = NULL;
     char *perm;
@@ -465,8 +472,20 @@
             iperms = atoi(perm);
     }
 
-    conn = sqlite_open(params, iperms, NULL);
+    if (error) {
+        *error = NULL;
 
+        conn = sqlite_open(params, iperms, (char **)error);
+
+        if (*error) {
+            apr_pool_cleanup_register(pool, *error, error_free,
+                                      apr_pool_cleanup_null);
+        }
+    }
+    else {
+        conn = sqlite_open(params, iperms, NULL);
+    }
+
     sql = apr_pcalloc(pool, sizeof(*sql));
     sql->conn = conn;
 
Index: dbd/apr_dbd_sqlite3.c
===================================================================
--- dbd/apr_dbd_sqlite3.c	(revision 586254)
+++ dbd/apr_dbd_sqlite3.c	(working copy)
@@ -814,7 +814,8 @@
     return trans->mode = (mode & TXN_MODE_BITS);
 }
 
-static apr_dbd_t *dbd_sqlite3_open(apr_pool_t *pool, const char *params)
+static apr_dbd_t *dbd_sqlite3_open(apr_pool_t *pool, const char *params,
+                                   const char **error)
 {
     apr_dbd_t *sql = NULL;
     sqlite3 *conn = NULL;
@@ -823,6 +824,9 @@
         return NULL;
     sqlres = sqlite3_open(params, &conn);
     if (sqlres != SQLITE_OK) {
+        if (error) {
+            *error = apr_pstrdup(pool, sqlite3_errmsg(conn));
+        }
         sqlite3_close(conn);
         return NULL;
     }
Index: dbd/apr_dbd_oracle.c
===================================================================
--- dbd/apr_dbd_oracle.c	(revision 586254)
+++ dbd/apr_dbd_oracle.c	(working copy)
@@ -437,10 +437,11 @@
 #endif
 }
 
-static apr_dbd_t *dbd_oracle_open(apr_pool_t *pool, const char *params)
+static apr_dbd_t *dbd_oracle_open(apr_pool_t *pool, const char *params,
+                                  const char **error)
 {
     apr_dbd_t *ret = apr_pcalloc(pool, sizeof(apr_dbd_t));
-    int_errorcode;
+    int errorcode;
 
     char *BLANK = "";
     struct {
@@ -519,6 +520,9 @@
         printf("OPEN ERROR %d (alloc svr): %s\n", ret->status, ret->buf);
         break;
 #else
+        *error = apr_pcalloc(pool, 200);
+        OCIErrorGet(ret->err, 1, NULL, &errorcode, (unsigned char*)(*error),
+                    200, OCI_HTYPE_ERROR);
         return NULL;
 #endif
     case OCI_SUCCESS:
@@ -535,6 +539,9 @@
         printf("OPEN ERROR %d (alloc svc): %s\n", ret->status, ret->buf);
         break;
 #else
+        *error = apr_pcalloc(pool, 200);
+        OCIErrorGet(ret->err, 1, NULL, &errorcode, (unsigned char*)(*error),
+                    200, OCI_HTYPE_ERROR);
         return NULL;
 #endif
     case OCI_SUCCESS:
@@ -555,6 +562,9 @@
         printf("OPEN ERROR: %s\n", ret->buf);
         break;
 #else
+        *error = apr_pcalloc(pool, 200);
+        OCIErrorGet(ret->err, 1, NULL, &errorcode, (unsigned char*)(*error),
+                    200, OCI_HTYPE_ERROR);
         return NULL;
 #endif
     case OCI_SUCCESS:
@@ -571,6 +581,9 @@
         printf("OPEN ERROR %d (server attach): %s\n", ret->status, ret->buf);
         break;
 #else
+        *error = apr_pcalloc(pool, 200);
+        OCIErrorGet(ret->err, 1, NULL, &errorcode, (unsigned char*)(*error),
+                    200, OCI_HTYPE_ERROR);
         return NULL;
 #endif
     case OCI_SUCCESS:
@@ -586,6 +599,9 @@
         printf("OPEN ERROR %d (attr set): %s\n", ret->status, ret->buf);
         break;
 #else
+        *error = apr_pcalloc(pool, 200);
+        OCIErrorGet(ret->err, 1, NULL, &errorcode, (unsigned char*)(*error),
+                    200, OCI_HTYPE_ERROR);
         return NULL;
 #endif
     case OCI_SUCCESS:
@@ -601,6 +617,9 @@
         printf("OPEN ERROR %d (alloc auth): %s\n", ret->status, ret->buf);
         break;
 #else
+        *error = apr_pcalloc(pool, 200);
+        OCIErrorGet(ret->err, 1, NULL, &errorcode, (unsigned char*)(*error),
+                    200, OCI_HTYPE_ERROR);
         return NULL;
 #endif
     case OCI_SUCCESS:
@@ -616,6 +635,9 @@
         printf("OPEN ERROR %d (attr username): %s\n", ret->status, ret->buf);
         break;
 #else
+        *error = apr_pcalloc(pool, 200);
+        OCIErrorGet(ret->err, 1, NULL, &errorcode, (unsigned char*)(*error),
+                    200, OCI_HTYPE_ERROR);
         return NULL;
 #endif
     case OCI_SUCCESS:
@@ -631,6 +653,9 @@
         printf("OPEN ERROR %d (attr password): %s\n", ret->status, ret->buf);
         break;
 #else
+        *error = apr_pcalloc(pool, 200);
+        OCIErrorGet(ret->err, 1, NULL, &errorcode, (unsigned char*)(*error),
+                    200, OCI_HTYPE_ERROR);
         return NULL;
 #endif
     case OCI_SUCCESS:
@@ -646,6 +671,9 @@
         printf("OPEN ERROR %d (session begin): %s\n", ret->status, ret->buf);
         break;
 #else
+        *error = apr_pcalloc(pool, 200);
+        OCIErrorGet(ret->err, 1, NULL, &errorcode, (unsigned char*)(*error),
+                    200, OCI_HTYPE_ERROR);
         return NULL;
 #endif
     case OCI_SUCCESS:
@@ -660,6 +688,9 @@
                     sizeof(ret->buf), OCI_HTYPE_ERROR);
         printf("OPEN ERROR %d (attr session): %s\n", ret->status, ret->buf);
 #else
+        *error = apr_pcalloc(pool, 200);
+        OCIErrorGet(ret->err, 1, NULL, &errorcode, (unsigned char*)(*error),
+                    200, OCI_HTYPE_ERROR);
         return NULL;
 #endif
         break;
Index: dbd/apr_dbd_mysql.c
===================================================================
--- dbd/apr_dbd_mysql.c	(revision 586254)
+++ dbd/apr_dbd_mysql.c	(working copy)
@@ -1064,7 +1064,8 @@
     return trans->mode = (mode & TXN_MODE_BITS);
 }
 
-static apr_dbd_t *dbd_mysql_open(apr_pool_t *pool, const char *params)
+static apr_dbd_t *dbd_mysql_open(apr_pool_t *pool, const char *params,
+                                 const char **error)
 {
     static const char *const delims = " \r\n\t;|,";
     const char *ptr;
@@ -1155,6 +1156,9 @@
                                    fields[5].value, flags);
 
     if(real_conn == NULL) {
+        if (error) {
+            *error = apr_pstrdup(pool, mysql_error(sql->conn));
+        }
         mysql_close(sql->conn);
         return NULL;
     }
Index: dbd/apr_dbd_pgsql.c
===================================================================
--- dbd/apr_dbd_pgsql.c	(revision 586254)
+++ dbd/apr_dbd_pgsql.c	(working copy)
@@ -1176,7 +1176,8 @@
     return trans->mode = (mode & TXN_MODE_BITS);
 }
 
-static apr_dbd_t *dbd_pgsql_open(apr_pool_t *pool, const char *params)
+static apr_dbd_t *dbd_pgsql_open(apr_pool_t *pool, const char *params,
+                                 const char **error)
 {
     apr_dbd_t *sql;
     
@@ -1187,6 +1188,9 @@
      * liable to segfault, so just close it out now.  it would be nice
      * if we could give an indication of why we failed to connect... */
     if (PQstatus(conn) != CONNECTION_OK) {
+        if (error) {
+            *error = apr_pstrdup(pool, PQerrorMessage(conn));
+        }
         PQfinish(conn);
         return NULL;
     }
Index: dbd/apr_dbd.c
===================================================================
--- dbd/apr_dbd.c	(revision 586254)
+++ dbd/apr_dbd.c	(working copy)
@@ -183,22 +183,33 @@
 
     return rv;
 }
-APU_DECLARE(apr_status_t) apr_dbd_open(const apr_dbd_driver_t *driver,
-                                       apr_pool_t *pool, const char *params,
-                                       apr_dbd_t **handle)
+APU_DECLARE(apr_status_t) apr_dbd_open_ex(const apr_dbd_driver_t *driver,
+                                          apr_pool_t *pool, const char *params,
+                                          apr_dbd_t **handle,
+                                          const char **error)
 {
     apr_status_t rv;
-    *handle = (driver->open)(pool, params);
+    *handle = (driver->open)(pool, params, error);
     if (*handle == NULL) {
         return APR_EGENERAL;
     }
     rv = apr_dbd_check_conn(driver, pool, *handle);
     if ((rv != APR_SUCCESS) && (rv != APR_ENOTIMPL)) {
+        /* XXX: rv is APR error code, but apr_dbd_error() takes int! */
+        if (error) {
+            *error = apr_dbd_error(driver, *handle, rv);
+        }
         apr_dbd_close(driver, *handle);
         return APR_EGENERAL;
     }
     return APR_SUCCESS;
 }
+APU_DECLARE(apr_status_t) apr_dbd_open(const apr_dbd_driver_t *driver,
+                                       apr_pool_t *pool, const char *params,
+                                       apr_dbd_t **handle)
+{
+    return apr_dbd_open_ex(driver,pool,params,handle,NULL);
+}
 APU_DECLARE(int) apr_dbd_transaction_start(const apr_dbd_driver_t *driver,
                                            apr_pool_t *pool, apr_dbd_t *handle,
                                            apr_dbd_transaction_t **trans)

Reply via email to