You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by hw...@apache.org on 2011/05/26 02:20:16 UTC

svn commit: r1127741 - in /subversion/trunk/subversion: include/private/svn_sqlite.h libsvn_subr/sqlite.c libsvn_wc/wc_db_util.c

Author: hwright
Date: Thu May 26 00:20:16 2011
New Revision: 1127741

URL: http://svn.apache.org/viewvc?rev=1127741&view=rev
Log:
Add wrappers for adding custom functions into SQLite.  This should allow these
functions to be implemented in the library in which they reside, while hiding
the sqlite implementation details.  This also provides such custom functions
access to pools, and allows them to return errors through the normal channels.

This change introduces those wrappers required by the sole existing custom
function.  Also, as this function is not currently used, this code may have
bugs.

* subversion/include/private/svn_sqlite.h
  (svn_sqlite__context_t, svn_sqlite__value_t): Forward declare these structs.
  (svn_sqlite__func_t): New.
  (svn_sqlite__create_scalar_function): New.
  (SVN_SQLITE__INTEGER, SVN_SQLITE__FLOAT, SVN_SQLITE__TEXT, SVN_SQLITE__BLOB,
   SVN_SQLITE__NULL): New.
  (svn_sqlite__value_type, svn_sqlite__value_text, svn_sqlite__result_null,
   svn_sqlite__result_int64): New.

* subversion/libsvn_subr/sqlite.c
  (svn_sqlite__context_t, svn_sqlite__value_t): New.
  (relpath_depth): Remove.
  (svn_sqlite__open): Don't add the relpath_depth custom function.
  (function_wrapper_baton_t, wrapped_func): New.
  (svn_sqlite__create_scalar_function): New.
  (svn_sqlite__value_type, svn_sqlite__value_text, svn_sqlite__result_null,
   svn_sqlite__result_int64): New.

* subversion/libsvn_wc/wc_db_util.c
  (relpath_depth): New.
  (svn_wc__db_util_open_db): Add the custom function.

Modified:
    subversion/trunk/subversion/include/private/svn_sqlite.h
    subversion/trunk/subversion/libsvn_subr/sqlite.c
    subversion/trunk/subversion/libsvn_wc/wc_db_util.c

Modified: subversion/trunk/subversion/include/private/svn_sqlite.h
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/include/private/svn_sqlite.h?rev=1127741&r1=1127740&r2=1127741&view=diff
==============================================================================
--- subversion/trunk/subversion/include/private/svn_sqlite.h (original)
+++ subversion/trunk/subversion/include/private/svn_sqlite.h Thu May 26 00:20:16 2011
@@ -39,6 +39,8 @@ extern "C" {
 
 typedef struct svn_sqlite__db_t svn_sqlite__db_t;
 typedef struct svn_sqlite__stmt_t svn_sqlite__stmt_t;
+typedef struct svn_sqlite__context_t svn_sqlite__context_t;
+typedef struct svn_sqlite__value_t svn_sqlite__value_t;
 
 typedef enum svn_sqlite__mode_e {
     svn_sqlite__mode_readonly,   /* open the database read-only */
@@ -46,6 +48,12 @@ typedef enum svn_sqlite__mode_e {
     svn_sqlite__mode_rwcreate    /* open/create the database read-write */
 } svn_sqlite__mode_t;
 
+/* The type used for callback functions. */
+typedef svn_error_t *(*svn_sqlite__func_t)(svn_sqlite__context_t *sctx,
+                                           int argc,
+                                           svn_sqlite__value_t *values[],
+                                           apr_pool_t *scatch_pool);
+
 
 /* Step the given statement; if it returns SQLITE_DONE, reset the statement.
    Otherwise, raise an SVN error.  */
@@ -122,6 +130,15 @@ svn_sqlite__open(svn_sqlite__db_t **db, 
 svn_error_t *
 svn_sqlite__close(svn_sqlite__db_t *db);
 
+/* Add a custom function to be used with this database connection.  The data
+   in BATON should live at least as long as the connection in DB. */
+svn_error_t *
+svn_sqlite__create_scalar_function(svn_sqlite__db_t *db,
+                                   const char *func_name,
+                                   int argc,
+                                   svn_sqlite__func_t func,
+                                   void *baton);
+
 /* Execute the (multiple) statements in the STATEMENTS[STMT_IDX] string.  */
 svn_error_t *
 svn_sqlite__exec_statements(svn_sqlite__db_t *db, int stmt_idx);
@@ -293,6 +310,33 @@ svn_sqlite__column_bytes(svn_sqlite__stm
 
 /* --------------------------------------------------------------------- */
 
+#define SVN_SQLITE__INTEGER  1
+#define SVN_SQLITE__FLOAT    2
+#define SVN_SQLITE__TEXT     3
+#define SVN_SQLITE__BLOB     4
+#define SVN_SQLITE__NULL     5
+
+/* */
+int
+svn_sqlite__value_type(svn_sqlite__value_t *val);
+
+/* */
+const char *
+svn_sqlite__value_text(svn_sqlite__value_t *val);
+
+
+/* --------------------------------------------------------------------- */
+
+/* */
+void
+svn_sqlite__result_null(svn_sqlite__context_t *sctx);
+
+void
+svn_sqlite__result_int64(svn_sqlite__context_t *sctx, apr_int64_t val);
+
+
+/* --------------------------------------------------------------------- */
+
 
 /* Error-handling wrapper around sqlite3_finalize. */
 svn_error_t *

Modified: subversion/trunk/subversion/libsvn_subr/sqlite.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_subr/sqlite.c?rev=1127741&r1=1127740&r2=1127741&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_subr/sqlite.c (original)
+++ subversion/trunk/subversion/libsvn_subr/sqlite.c Thu May 26 00:20:16 2011
@@ -94,6 +94,16 @@ struct svn_sqlite__stmt_t
   svn_boolean_t needs_reset;
 };
 
+struct svn_sqlite__context_t
+{
+  sqlite3_context *context;
+};
+
+struct svn_sqlite__value_t
+{
+  sqlite3_value *value;
+};
+
 
 /* Convert SQLite error codes to SVN. Evaluates X multiple times */
 #define SQLITE_ERROR_CODE(x) ((x) == SQLITE_READONLY       \
@@ -876,37 +886,6 @@ close_apr(void *data)
 }
 
 
-/* An SQLite application defined function that allows SQL queries to
-   use "relpath_depth(local_relpath)".  This has to be installed before
-   the statements are prepared, so before the first call to
-   svn_sqlite__get_statement.
-
-   Should we have a way of allowing the caller of svn_sqlite__open to
-   pass in an array of function pointers?  Would the caller have to
-   use the SQLite types or would we wrap them all? */
-static void relpath_depth(sqlite3_context *context, int argc, sqlite3_value **val)
-{
-  const unsigned char *path = NULL;
-  sqlite3_int64 depth;
-
-  if (argc == 1 && sqlite3_value_type(val[0]) == SQLITE_TEXT)
-    path = sqlite3_value_text(val[0]);
-  if (!path)
-    {
-      sqlite3_result_null(context);
-      return;
-    }
-
-  depth = *path ? 1 : 0;
-  while (*path)
-    {
-      if (*path == '/')
-        ++depth;
-      ++path;
-    }
-  sqlite3_result_int(context, depth);
-}
-
 svn_error_t *
 svn_sqlite__open(svn_sqlite__db_t **db, const char *path,
                  svn_sqlite__mode_t mode, const char * const statements[],
@@ -963,10 +942,6 @@ svn_sqlite__open(svn_sqlite__db_t **db, 
   if (upgrade_sql != NULL)
     SVN_ERR(check_format(*db, latest_schema, upgrade_sql, scratch_pool));
 
-  SQLITE_ERR(sqlite3_create_function((*db)->db3, "relpath_depth",
-                                     1, SQLITE_UTF8, NULL,
-                                     relpath_depth, NULL, NULL), *db);
-
   /* Store the provided statements. */
   if (statements)
     {
@@ -1191,3 +1166,88 @@ svn_sqlite__hotcopy(const char *src_path
 
   return SVN_NO_ERROR;
 }
+
+struct function_wrapper_baton_t
+{
+  svn_sqlite__func_t func;
+  void *baton;
+
+  apr_pool_t *scratch_pool;
+};
+
+static void
+wrapped_func(sqlite3_context *context,
+             int argc,
+             sqlite3_value *values[])
+{
+  struct function_wrapper_baton_t *fwb = sqlite3_user_data(context);
+  svn_sqlite__context_t sctx = { context };
+  svn_sqlite__value_t **local_vals =
+                            apr_palloc(fwb->scratch_pool,
+                                       sizeof(svn_sqlite__value_t *) * argc);
+  svn_error_t *err;
+  int i;
+
+  for (i = 0; i < argc; i++)
+    {
+      local_vals[i] = apr_palloc(fwb->scratch_pool, sizeof(*local_vals[i]));
+      local_vals[i]->value = values[i];
+    }
+
+  err = fwb->func(&sctx, argc, local_vals, fwb->scratch_pool);
+  svn_pool_clear(fwb->scratch_pool);
+
+  if (err)
+    {
+      char buf[256];
+      sqlite3_result_error(context,
+                           svn_err_best_message(err, buf, sizeof(buf)),
+                           -1);
+      svn_error_clear(err);
+    }
+}
+
+svn_error_t *
+svn_sqlite__create_scalar_function(svn_sqlite__db_t *db,
+                                   const char *func_name,
+                                   int argc,
+                                   svn_sqlite__func_t func,
+                                   void *baton)
+{
+  struct function_wrapper_baton_t *fwb = apr_pcalloc(db->state_pool,
+                                                     sizeof(*fwb));
+
+  fwb->scratch_pool = svn_pool_create(db->state_pool);
+  fwb->func = func;
+  fwb->baton = baton;
+  
+  SQLITE_ERR(sqlite3_create_function(db->db3, func_name, argc, SQLITE_ANY,
+                                     fwb, wrapped_func, NULL, NULL),
+             db);
+
+  return SVN_NO_ERROR;
+}
+
+int
+svn_sqlite__value_type(svn_sqlite__value_t *val)
+{
+  return sqlite3_value_type(val->value);
+}
+
+const char *
+svn_sqlite__value_text(svn_sqlite__value_t *val)
+{
+  return (const char *) sqlite3_value_text(val->value);
+}
+
+void
+svn_sqlite__result_null(svn_sqlite__context_t *sctx)
+{
+  sqlite3_result_null(sctx->context);
+}
+
+void
+svn_sqlite__result_int64(svn_sqlite__context_t *sctx, apr_int64_t val)
+{
+  sqlite3_result_int64(sctx->context, val);
+}

Modified: subversion/trunk/subversion/libsvn_wc/wc_db_util.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_wc/wc_db_util.c?rev=1127741&r1=1127740&r2=1127741&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_wc/wc_db_util.c (original)
+++ subversion/trunk/subversion/libsvn_wc/wc_db_util.c Thu May 26 00:20:16 2011
@@ -38,6 +38,7 @@
 #define SVN_WC__I_AM_WC_DB
 
 #include "svn_dirent_uri.h"
+#include "private/svn_sqlite.h"
 
 #include "wc.h"
 #include "adm_files.h"
@@ -75,6 +76,39 @@ svn_wc__db_util_fetch_wc_id(apr_int64_t 
 
 
 
+
+/* An SQLite application defined function that allows SQL queries to
+   use "relpath_depth(local_relpath)".  */
+static svn_error_t *
+relpath_depth(svn_sqlite__context_t *sctx,
+              int argc,
+              svn_sqlite__value_t *values[],
+              apr_pool_t *scratch_pool)
+{
+  const char *path = NULL;
+  apr_int64_t depth;
+
+  if (argc == 1 && svn_sqlite__value_type(values[0]) == SVN_SQLITE__TEXT)
+    path = svn_sqlite__value_text(values[0]);
+  if (!path)
+    {
+      svn_sqlite__result_null(sctx);
+      return SVN_NO_ERROR;
+    }
+
+  depth = *path ? 1 : 0;
+  while (*path)
+    {
+      if (*path == '/')
+        ++depth;
+      ++path;
+    }
+  svn_sqlite__result_int64(sctx, depth);
+
+  return SVN_NO_ERROR;
+}
+
+
 svn_error_t *
 svn_wc__db_util_open_db(svn_sqlite__db_t **sdb,
                         const char *dir_abspath,
@@ -86,10 +120,13 @@ svn_wc__db_util_open_db(svn_sqlite__db_t
   const char *sdb_abspath = svn_wc__adm_child(dir_abspath, sdb_fname,
                                               scratch_pool);
 
-  return svn_error_return(svn_sqlite__open(sdb, sdb_abspath,
-                                           smode, statements,
-                                           0, NULL,
-                                           result_pool, scratch_pool));
+  SVN_ERR(svn_sqlite__open(sdb, sdb_abspath, smode, statements,
+                           0, NULL, result_pool, scratch_pool));
+
+  SVN_ERR(svn_sqlite__create_scalar_function(*sdb, "relpath_depth", 1,
+                                             relpath_depth, NULL));
+
+  return SVN_NO_ERROR;
 }