In the command-line client, forbid
[svn.git] / subversion / libsvn_fs_util / sqlite-util.c
blobde9278deb34fc016aa5e03c222edfe19aae246ac
1 /* sqlite-util.c
3 * ====================================================================
4 * Copyright (c) 2007 CollabNet. All rights reserved.
6 * This software is licensed as described in the file COPYING, which
7 * you should have received as part of this distribution. The terms
8 * are also available at http://subversion.tigris.org/license-1.html.
9 * If newer versions of this license are posted there, you may use a
10 * newer version instead, at your option.
12 * This software consists of voluntary contributions made by many
13 * individuals. For exact contribution history, see the revision
14 * history and logs, available at http://subversion.tigris.org/.
15 * ====================================================================
18 #include <stdlib.h>
19 #include <stdio.h>
20 #include <string.h>
21 #include <ctype.h>
22 #include <assert.h>
24 #include <apr_general.h>
25 #include <apr_pools.h>
27 #include <sqlite3.h>
29 #include "svn_types.h"
30 #include "svn_fs.h"
31 #include "svn_path.h"
32 #include "svn_mergeinfo.h"
33 #include "svn_pools.h"
35 #include "private/svn_fs_sqlite.h"
36 #include "../libsvn_fs/fs-loader.h"
37 #include "svn_private_config.h"
39 #include "sqlite-util.h"
41 #ifdef SQLITE3_DEBUG
42 /* An sqlite query execution callback. */
43 static void
44 sqlite_tracer(void *data, const char *sql)
46 /* sqlite3 *db = data; */
47 fprintf(stderr, "SQLITE SQL is \"%s\"\n", sql);
49 #endif
51 struct svn_fs__sqlite_stmt_t
53 sqlite3_stmt *s3stmt;
54 sqlite3 *db;
57 /* Convert SQLite error codes to SVN */
58 #define SQLITE_ERROR_CODE(x) ((x) == SQLITE_READONLY ? \
59 SVN_ERR_FS_SQLITE_READONLY \
60 : SVN_ERR_FS_SQLITE_ERROR )
62 /* SQLITE->SVN quick error wrap, much like SVN_ERR. */
63 #define SQLITE_ERR(x, db) do \
64 { \
65 int sqlite_err__temp = (x); \
66 if (sqlite_err__temp != SQLITE_OK) \
67 return svn_error_create(SQLITE_ERROR_CODE(sqlite_err__temp), \
68 NULL, sqlite3_errmsg((db))); \
69 } while (0)
72 svn_error_t *
73 svn_fs__sqlite_exec(sqlite3 *db, const char *sql)
75 char *err_msg;
76 svn_error_t *err;
77 int sqlite_err = sqlite3_exec(db, sql, NULL, NULL, &err_msg);
78 if (sqlite_err != SQLITE_OK)
80 err = svn_error_create(SQLITE_ERROR_CODE(sqlite_err), NULL,
81 err_msg);
82 sqlite3_free(err_msg);
83 return err;
85 return SVN_NO_ERROR;
88 svn_error_t *
89 svn_fs__sqlite_prepare(svn_fs__sqlite_stmt_t **stmt, sqlite3 *db,
90 const char *text, apr_pool_t *pool)
92 svn_fs__sqlite_stmt_t *s = apr_palloc(pool, sizeof(*s));
93 s->db = db;
94 SQLITE_ERR(sqlite3_prepare(db, text, -1, &(s->s3stmt), NULL), db);
95 *stmt = s;
96 return SVN_NO_ERROR;
99 static svn_error_t *
100 step_with_expectation(svn_fs__sqlite_stmt_t* stmt,
101 svn_boolean_t expecting_row)
103 svn_boolean_t got_row;
104 SVN_ERR(svn_fs__sqlite_step(&got_row, stmt));
105 if ((got_row && !expecting_row)
107 (!got_row && expecting_row))
108 return svn_error_create(SVN_ERR_FS_SQLITE_ERROR, NULL,
109 expecting_row
110 ? _("Expected database row missing")
111 : _("Extra database row found"));
113 return SVN_NO_ERROR;
116 svn_error_t *
117 svn_fs__sqlite_step_done(svn_fs__sqlite_stmt_t *stmt)
119 return step_with_expectation(stmt, FALSE);
122 svn_error_t *
123 svn_fs__sqlite_step_row(svn_fs__sqlite_stmt_t *stmt)
125 return step_with_expectation(stmt, TRUE);
128 svn_error_t *
129 svn_fs__sqlite_step(svn_boolean_t *got_row, svn_fs__sqlite_stmt_t *stmt)
131 int sqlite_result = sqlite3_step(stmt->s3stmt);
132 if (sqlite_result != SQLITE_DONE && sqlite_result != SQLITE_ROW)
134 /* Extract the real error value with finalize. */
135 SVN_ERR(svn_fs__sqlite_finalize(stmt));
136 /* This really should have thrown an error! */
137 abort();
140 *got_row = (sqlite_result == SQLITE_ROW);
142 return SVN_NO_ERROR;
145 svn_error_t *
146 svn_fs__sqlite_bind_int64(svn_fs__sqlite_stmt_t *stmt,
147 int slot,
148 sqlite_int64 val)
150 SQLITE_ERR(sqlite3_bind_int64(stmt->s3stmt, slot, val), stmt->db);
151 return SVN_NO_ERROR;
154 svn_error_t *
155 svn_fs__sqlite_bind_text(svn_fs__sqlite_stmt_t *stmt,
156 int slot,
157 const char *val)
159 SQLITE_ERR(sqlite3_bind_text(stmt->s3stmt, slot, val, -1, SQLITE_TRANSIENT),
160 stmt->db);
161 return SVN_NO_ERROR;
164 const char *
165 svn_fs__sqlite_column_text(svn_fs__sqlite_stmt_t *stmt, int column)
167 return (const char *) sqlite3_column_text(stmt->s3stmt, column);
170 svn_revnum_t
171 svn_fs__sqlite_column_revnum(svn_fs__sqlite_stmt_t *stmt, int column)
173 return (svn_revnum_t) sqlite3_column_int64(stmt->s3stmt, column);
176 svn_boolean_t
177 svn_fs__sqlite_column_boolean(svn_fs__sqlite_stmt_t *stmt, int column)
179 return (sqlite3_column_int64(stmt->s3stmt, column) == 0
180 ? FALSE : TRUE);
184 svn_fs__sqlite_column_int(svn_fs__sqlite_stmt_t *stmt, int column)
186 return sqlite3_column_int(stmt->s3stmt, column);
189 svn_error_t *
190 svn_fs__sqlite_finalize(svn_fs__sqlite_stmt_t *stmt)
192 SQLITE_ERR(sqlite3_finalize(stmt->s3stmt), stmt->db);
193 return SVN_NO_ERROR;
196 svn_error_t *
197 svn_fs__sqlite_reset(svn_fs__sqlite_stmt_t *stmt)
199 SQLITE_ERR(sqlite3_reset(stmt->s3stmt), stmt->db);
200 return SVN_NO_ERROR;
203 /* Time (in milliseconds) to wait for sqlite locks before giving up. */
204 #define BUSY_TIMEOUT 10000
206 static const char *schema_create_sql[] = {
207 NULL, /* An empty database is format 0 */
209 /* USER_VERSION 1 */
210 "PRAGMA auto_vacuum = 1;"
211 APR_EOL_STR
212 "CREATE TABLE mergeinfo (revision INTEGER NOT NULL, mergedfrom TEXT NOT "
213 "NULL, mergedto TEXT NOT NULL, mergedrevstart INTEGER NOT NULL, "
214 "mergedrevend INTEGER NOT NULL, inheritable INTEGER NOT NULL);"
215 APR_EOL_STR
216 "CREATE INDEX mi_mergedfrom_idx ON mergeinfo (mergedfrom);"
217 APR_EOL_STR
218 "CREATE INDEX mi_mergedto_idx ON mergeinfo (mergedto);"
219 APR_EOL_STR
220 "CREATE INDEX mi_revision_idx ON mergeinfo (revision);"
221 APR_EOL_STR
222 "CREATE TABLE mergeinfo_changed (revision INTEGER NOT NULL, path TEXT "
223 "NOT NULL);"
224 APR_EOL_STR
225 "CREATE UNIQUE INDEX mi_c_revpath_idx ON mergeinfo_changed (revision, path);"
226 APR_EOL_STR
227 "CREATE INDEX mi_c_path_idx ON mergeinfo_changed (path);"
228 APR_EOL_STR
229 "CREATE INDEX mi_c_revision_idx ON mergeinfo_changed (revision);"
230 APR_EOL_STR,
232 /* USER_VERSION 2 */
233 "CREATE TABLE node_origins (node_id TEXT NOT NULL, node_rev_id TEXT NOT "
234 "NULL);"
235 APR_EOL_STR
236 "CREATE UNIQUE INDEX no_ni_idx ON node_origins (node_id);"
237 APR_EOL_STR
240 static const int latest_schema_format =
241 sizeof(schema_create_sql)/sizeof(schema_create_sql[0]) - 1;
244 static svn_error_t *
245 upgrade_format(sqlite3 *db, int current_format, apr_pool_t *pool)
247 apr_pool_t *iterpool = svn_pool_create(pool);
249 while (current_format < latest_schema_format)
251 const char *pragma_cmd;
253 svn_pool_clear(iterpool);
255 /* Go to the next format */
256 current_format++;
258 /* Run the upgrade SQL */
259 SVN_ERR(svn_fs__sqlite_exec(db, schema_create_sql[current_format]));
261 /* Update the user version pragma */
262 pragma_cmd = apr_psprintf(iterpool,
263 "PRAGMA user_version = %d;",
264 current_format);
265 SVN_ERR(svn_fs__sqlite_exec(db, pragma_cmd));
268 svn_pool_destroy(iterpool);
270 return SVN_NO_ERROR;
274 /* Check the schema format of the database, upgrading it if necessary.
275 Return SVN_ERR_FS_UNSUPPORTED_FORMAT if the schema format is too new, or
276 SVN_ERR_FS_SQLITE_ERROR if an sqlite error occurs during
277 validation. Return SVN_NO_ERROR if everything is okay. */
278 static svn_error_t *
279 check_format(sqlite3 *db, apr_pool_t *pool)
281 svn_fs__sqlite_stmt_t *stmt;
282 int schema_format;
284 SVN_ERR(svn_fs__sqlite_prepare(&stmt, db, "PRAGMA user_version;", pool));
285 SVN_ERR(svn_fs__sqlite_step_row(stmt));
287 /* Validate that the schema exists as expected and that the
288 schema and repository versions match. */
289 schema_format = svn_fs__sqlite_column_int(stmt, 0);
291 SVN_ERR(svn_fs__sqlite_finalize(stmt));
293 if (schema_format == latest_schema_format)
294 return SVN_NO_ERROR;
295 else if (schema_format < latest_schema_format)
296 return upgrade_format(db, schema_format, pool);
297 else
298 return svn_error_createf(SVN_ERR_FS_UNSUPPORTED_FORMAT, NULL,
299 _("Index schema format %d not "
300 "recognized"), schema_format);
303 /* If possible, verify that SQLite was compiled in a thread-safe
304 manner. */
305 static svn_error_t *
306 init_sqlite(apr_pool_t *pool)
308 svn_boolean_t is_threadsafe = TRUE;
310 /* SQLite 3.5 allows verification of its thread-safety at runtime.
311 Older versions are simply expected to have been configured with
312 --enable-threadsafe, which compiles with -DSQLITE_THREADSAFE=1
313 (or -DTHREADSAFE, for older versions). */
314 #ifdef SVN_HAVE_SQLITE_THREADSAFE_PREDICATE
315 /* sqlite3_threadsafe() was available at Subversion 'configure'-time. */
316 is_threadsafe = sqlite3_threadsafe();
317 #endif /* SVN_HAVE_SQLITE_THREADSAFE_PREDICATE */
319 if (! is_threadsafe)
320 return svn_error_create(SVN_ERR_FS_SQLITE_ERROR, NULL,
321 _("SQLite is required to be compiled and run in "
322 "thread-safe mode"));
323 return SVN_NO_ERROR;
326 svn_error_t *
327 svn_fs__sqlite_open(sqlite3 **db, const char *repos_path, apr_pool_t *pool)
329 const char *db_path;
330 static svn_boolean_t sqlite_initialized = FALSE;
332 if (! sqlite_initialized)
334 /* There is a potential initialization race condition here, but
335 it currently isn't worth guarding against (e.g. with a mutex). */
336 SVN_ERR(init_sqlite(pool));
337 sqlite_initialized = TRUE;
340 db_path = svn_path_join(repos_path, SVN_FS__SQLITE_DB_NAME, pool);
342 /* Open the database. */
343 SQLITE_ERR(sqlite3_open(db_path, db), *db);
344 /* Retry until timeout when database is busy. */
345 SQLITE_ERR(sqlite3_busy_timeout(*db, BUSY_TIMEOUT), *db);
346 #ifdef SQLITE3_DEBUG
347 sqlite3_trace(*db, sqlite_tracer, *db);
348 #endif
350 SVN_ERR(svn_fs__sqlite_exec(*db, "PRAGMA case_sensitive_like=on;"));
352 /* Validate the schema, upgrading if necessary. */
353 return check_format(*db, pool);
356 svn_error_t *
357 svn_fs__sqlite_close(sqlite3 *db, svn_error_t *err)
359 int result = sqlite3_close(db);
360 /* If there's a pre-existing error, return it. */
361 /* ### If the connection close also fails, say something about it as well? */
362 SVN_ERR(err);
363 SQLITE_ERR(result, db);
364 return SVN_NO_ERROR;
368 /* Create an sqlite DB for our mergeinfo index under PATH. Use POOL
369 for temporary allocations. */
370 svn_error_t *
371 svn_fs__sqlite_create_index(const char *path, apr_pool_t *pool)
373 sqlite3 *db;
374 /* Opening the database will create it + schema if it's not already there. */
375 SVN_ERR(svn_fs__sqlite_open(&db, path, pool));
376 return svn_fs__sqlite_close(db, SVN_NO_ERROR);