1251881Speter/* sqlite.c
2251881Speter *
3251881Speter * ====================================================================
4251881Speter *    Licensed to the Apache Software Foundation (ASF) under one
5251881Speter *    or more contributor license agreements.  See the NOTICE file
6251881Speter *    distributed with this work for additional information
7251881Speter *    regarding copyright ownership.  The ASF licenses this file
8251881Speter *    to you under the Apache License, Version 2.0 (the
9251881Speter *    "License"); you may not use this file except in compliance
10251881Speter *    with the License.  You may obtain a copy of the License at
11251881Speter *
12251881Speter *      http://www.apache.org/licenses/LICENSE-2.0
13251881Speter *
14251881Speter *    Unless required by applicable law or agreed to in writing,
15251881Speter *    software distributed under the License is distributed on an
16251881Speter *    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17251881Speter *    KIND, either express or implied.  See the License for the
18251881Speter *    specific language governing permissions and limitations
19251881Speter *    under the License.
20251881Speter * ====================================================================
21251881Speter */
22251881Speter
23251881Speter#include <apr_pools.h>
24251881Speter
25251881Speter#include "svn_types.h"
26251881Speter#include "svn_error.h"
27251881Speter#include "svn_pools.h"
28251881Speter#include "svn_io.h"
29251881Speter#include "svn_dirent_uri.h"
30251881Speter#include "svn_checksum.h"
31251881Speter
32251881Speter#include "internal_statements.h"
33251881Speter
34251881Speter#include "private/svn_sqlite.h"
35251881Speter#include "svn_private_config.h"
36251881Speter#include "private/svn_dep_compat.h"
37251881Speter#include "private/svn_atomic.h"
38251881Speter#include "private/svn_skel.h"
39251881Speter#include "private/svn_token.h"
40251881Speter
41251881Speter#ifdef SQLITE3_DEBUG
42251881Speter#include "private/svn_debug.h"
43251881Speter#endif
44251881Speter
45251881Speter#ifdef SVN_SQLITE_INLINE
46251881Speter/* Import the sqlite3 API vtable from sqlite3wrapper.c */
47251881Speter#  define SQLITE_OMIT_DEPRECATED
48251881Speter#  include <sqlite3ext.h>
49251881Speterextern const sqlite3_api_routines *const svn_sqlite3__api_funcs;
50251881Speterextern int (*const svn_sqlite3__api_initialize)(void);
51251881Speterextern int (*const svn_sqlite3__api_config)(int, ...);
52251881Speter#  define sqlite3_api svn_sqlite3__api_funcs
53251881Speter#  define sqlite3_initialize svn_sqlite3__api_initialize
54251881Speter#  define sqlite3_config svn_sqlite3__api_config
55251881Speter#else
56251881Speter#  include <sqlite3.h>
57251881Speter#endif
58251881Speter
59251881Speter#if !SQLITE_VERSION_AT_LEAST(3,7,12)
60251881Speter#error SQLite is too old -- version 3.7.12 is the minimum required version
61251881Speter#endif
62251881Speter
63251881Speterconst char *
64251881Spetersvn_sqlite__compiled_version(void)
65251881Speter{
66251881Speter  static const char sqlite_version[] = SQLITE_VERSION;
67251881Speter  return sqlite_version;
68251881Speter}
69251881Speter
70251881Speterconst char *
71251881Spetersvn_sqlite__runtime_version(void)
72251881Speter{
73251881Speter  return sqlite3_libversion();
74251881Speter}
75251881Speter
76251881Speter
77251881SpeterINTERNAL_STATEMENTS_SQL_DECLARE_STATEMENTS(internal_statements);
78251881Speter
79251881Speter
80251881Speter#ifdef SQLITE3_DEBUG
81251881Speter/* An sqlite query execution callback. */
82251881Speterstatic void
83251881Spetersqlite_tracer(void *data, const char *sql)
84251881Speter{
85251881Speter  /*  sqlite3 *db3 = data; */
86251881Speter  SVN_DBG(("sql=\"%s\"\n", sql));
87251881Speter}
88251881Speter#endif
89251881Speter
90251881Speter#ifdef SQLITE3_PROFILE
91251881Speter/* An sqlite execution timing callback. */
92251881Speterstatic void
93251881Spetersqlite_profiler(void *data, const char *sql, sqlite3_uint64 duration)
94251881Speter{
95251881Speter  /*  sqlite3 *db3 = data; */
96251881Speter  SVN_DBG(("[%.3f] sql=\"%s\"\n", 1e-9 * duration, sql));
97251881Speter}
98251881Speter#endif
99251881Speter
100251881Speterstruct svn_sqlite__db_t
101251881Speter{
102251881Speter  sqlite3 *db3;
103251881Speter  const char * const *statement_strings;
104251881Speter  int nbr_statements;
105251881Speter  svn_sqlite__stmt_t **prepared_stmts;
106251881Speter  apr_pool_t *state_pool;
107251881Speter};
108251881Speter
109251881Speterstruct svn_sqlite__stmt_t
110251881Speter{
111251881Speter  sqlite3_stmt *s3stmt;
112251881Speter  svn_sqlite__db_t *db;
113251881Speter  svn_boolean_t needs_reset;
114251881Speter};
115251881Speter
116251881Speterstruct svn_sqlite__context_t
117251881Speter{
118251881Speter  sqlite3_context *context;
119251881Speter};
120251881Speter
121251881Speterstruct svn_sqlite__value_t
122251881Speter{
123251881Speter  sqlite3_value *value;
124251881Speter};
125251881Speter
126251881Speter
127251881Speter/* Convert SQLite error codes to SVN. Evaluates X multiple times */
128251881Speter#define SQLITE_ERROR_CODE(x) ((x) == SQLITE_READONLY            \
129251881Speter                              ? SVN_ERR_SQLITE_READONLY         \
130251881Speter                              : ((x) == SQLITE_BUSY             \
131251881Speter                                 ? SVN_ERR_SQLITE_BUSY          \
132251881Speter                                 : ((x) == SQLITE_CONSTRAINT    \
133251881Speter                                    ? SVN_ERR_SQLITE_CONSTRAINT \
134251881Speter                                    : SVN_ERR_SQLITE_ERROR)))
135251881Speter
136251881Speter
137251881Speter/* SQLITE->SVN quick error wrap, much like SVN_ERR. */
138251881Speter#define SQLITE_ERR(x, db) do                                     \
139251881Speter{                                                                \
140251881Speter  int sqlite_err__temp = (x);                                    \
141251881Speter  if (sqlite_err__temp != SQLITE_OK)                             \
142251881Speter    return svn_error_createf(SQLITE_ERROR_CODE(sqlite_err__temp), \
143253734Speter                             NULL, "sqlite[S%d]: %s",             \
144253734Speter                             sqlite_err__temp,                    \
145253734Speter                             sqlite3_errmsg((db)->db3));          \
146251881Speter} while (0)
147251881Speter
148251881Speter#define SQLITE_ERR_MSG(x, msg) do                                \
149251881Speter{                                                                \
150251881Speter  int sqlite_err__temp = (x);                                    \
151251881Speter  if (sqlite_err__temp != SQLITE_OK)                             \
152251881Speter    return svn_error_createf(SQLITE_ERROR_CODE(sqlite_err__temp), \
153253734Speter                             NULL, "sqlite[S%d]: %s",            \
154253734Speter                             sqlite_err__temp, msg);             \
155251881Speter} while (0)
156251881Speter
157251881Speter
158251881Speter/* Time (in milliseconds) to wait for sqlite locks before giving up. */
159251881Speter#define BUSY_TIMEOUT 10000
160251881Speter
161251881Speter
162251881Speter/* Convenience wrapper around exec_sql2(). */
163251881Speter#define exec_sql(db, sql) exec_sql2((db), (sql), SQLITE_OK)
164251881Speter
165251881Speter/* Run the statement SQL on DB, ignoring SQLITE_OK and IGNORED_ERR.
166251881Speter   (Note: the IGNORED_ERR parameter itself is not ignored.) */
167251881Speterstatic svn_error_t *
168251881Speterexec_sql2(svn_sqlite__db_t *db, const char *sql, int ignored_err)
169251881Speter{
170251881Speter  char *err_msg;
171251881Speter  int sqlite_err = sqlite3_exec(db->db3, sql, NULL, NULL, &err_msg);
172251881Speter
173251881Speter  if (sqlite_err != SQLITE_OK && sqlite_err != ignored_err)
174251881Speter    {
175251881Speter      svn_error_t *err = svn_error_createf(SQLITE_ERROR_CODE(sqlite_err), NULL,
176253734Speter                                           _("sqlite[S%d]: %s,"
177251881Speter                                             " executing statement '%s'"),
178253734Speter                                           sqlite_err, err_msg, sql);
179251881Speter      sqlite3_free(err_msg);
180251881Speter      return err;
181251881Speter    }
182251881Speter
183251881Speter  return SVN_NO_ERROR;
184251881Speter}
185251881Speter
186251881Speter
187251881Speterstatic svn_error_t *
188251881Speterprepare_statement(svn_sqlite__stmt_t **stmt, svn_sqlite__db_t *db,
189251881Speter                  const char *text, apr_pool_t *result_pool)
190251881Speter{
191251881Speter  *stmt = apr_palloc(result_pool, sizeof(**stmt));
192251881Speter  (*stmt)->db = db;
193251881Speter  (*stmt)->needs_reset = FALSE;
194251881Speter
195251881Speter  SQLITE_ERR(sqlite3_prepare_v2(db->db3, text, -1, &(*stmt)->s3stmt, NULL), db);
196251881Speter
197251881Speter  return SVN_NO_ERROR;
198251881Speter}
199251881Speter
200251881Speter
201251881Spetersvn_error_t *
202251881Spetersvn_sqlite__exec_statements(svn_sqlite__db_t *db, int stmt_idx)
203251881Speter{
204251881Speter  SVN_ERR_ASSERT(stmt_idx < db->nbr_statements);
205251881Speter
206251881Speter  return svn_error_trace(exec_sql(db, db->statement_strings[stmt_idx]));
207251881Speter}
208251881Speter
209251881Speter
210251881Spetersvn_error_t *
211251881Spetersvn_sqlite__get_statement(svn_sqlite__stmt_t **stmt, svn_sqlite__db_t *db,
212251881Speter                          int stmt_idx)
213251881Speter{
214251881Speter  SVN_ERR_ASSERT(stmt_idx < db->nbr_statements);
215251881Speter
216251881Speter  if (db->prepared_stmts[stmt_idx] == NULL)
217251881Speter    SVN_ERR(prepare_statement(&db->prepared_stmts[stmt_idx], db,
218251881Speter                              db->statement_strings[stmt_idx],
219251881Speter                              db->state_pool));
220251881Speter
221251881Speter  *stmt = db->prepared_stmts[stmt_idx];
222251881Speter
223251881Speter  if ((*stmt)->needs_reset)
224251881Speter    return svn_error_trace(svn_sqlite__reset(*stmt));
225251881Speter
226251881Speter  return SVN_NO_ERROR;
227251881Speter}
228251881Speter
229251881Speter/* Like svn_sqlite__get_statement but gets an internal statement.
230251881Speter
231251881Speter   All internal statements that use this api are executed with step_done(),
232251881Speter   so we don't need the fallback reset handling here or in the pool cleanup */
233251881Speterstatic svn_error_t *
234251881Speterget_internal_statement(svn_sqlite__stmt_t **stmt, svn_sqlite__db_t *db,
235251881Speter                       int stmt_idx)
236251881Speter{
237251881Speter  /* The internal statements are stored after the registered statements */
238251881Speter  int prep_idx = db->nbr_statements + stmt_idx;
239251881Speter  SVN_ERR_ASSERT(stmt_idx < STMT_INTERNAL_LAST);
240251881Speter
241251881Speter  if (db->prepared_stmts[prep_idx] == NULL)
242251881Speter    SVN_ERR(prepare_statement(&db->prepared_stmts[prep_idx], db,
243251881Speter                              internal_statements[stmt_idx],
244251881Speter                              db->state_pool));
245251881Speter
246251881Speter  *stmt = db->prepared_stmts[prep_idx];
247251881Speter
248251881Speter  return SVN_NO_ERROR;
249251881Speter}
250251881Speter
251251881Speter
252251881Speterstatic svn_error_t *
253251881Speterstep_with_expectation(svn_sqlite__stmt_t* stmt,
254251881Speter                      svn_boolean_t expecting_row)
255251881Speter{
256251881Speter  svn_boolean_t got_row;
257251881Speter
258251881Speter  SVN_ERR(svn_sqlite__step(&got_row, stmt));
259251881Speter  if ((got_row && !expecting_row)
260251881Speter      ||
261251881Speter      (!got_row && expecting_row))
262251881Speter    return svn_error_create(SVN_ERR_SQLITE_ERROR,
263251881Speter                            svn_sqlite__reset(stmt),
264251881Speter                            expecting_row
265251881Speter                              ? _("sqlite: Expected database row missing")
266251881Speter                              : _("sqlite: Extra database row found"));
267251881Speter
268251881Speter  return SVN_NO_ERROR;
269251881Speter}
270251881Speter
271251881Spetersvn_error_t *
272251881Spetersvn_sqlite__step_done(svn_sqlite__stmt_t *stmt)
273251881Speter{
274251881Speter  SVN_ERR(step_with_expectation(stmt, FALSE));
275251881Speter  return svn_error_trace(svn_sqlite__reset(stmt));
276251881Speter}
277251881Speter
278251881Spetersvn_error_t *
279251881Spetersvn_sqlite__step_row(svn_sqlite__stmt_t *stmt)
280251881Speter{
281251881Speter  return svn_error_trace(step_with_expectation(stmt, TRUE));
282251881Speter}
283251881Speter
284251881Speter
285251881Spetersvn_error_t *
286251881Spetersvn_sqlite__step(svn_boolean_t *got_row, svn_sqlite__stmt_t *stmt)
287251881Speter{
288251881Speter  int sqlite_result = sqlite3_step(stmt->s3stmt);
289251881Speter
290251881Speter  if (sqlite_result != SQLITE_DONE && sqlite_result != SQLITE_ROW)
291251881Speter    {
292251881Speter      svn_error_t *err1, *err2;
293251881Speter
294251881Speter      err1 = svn_error_createf(SQLITE_ERROR_CODE(sqlite_result), NULL,
295253734Speter                               "sqlite[S%d]: %s",
296253734Speter                               sqlite_result, sqlite3_errmsg(stmt->db->db3));
297251881Speter      err2 = svn_sqlite__reset(stmt);
298251881Speter      return svn_error_compose_create(err1, err2);
299251881Speter    }
300251881Speter
301251881Speter  *got_row = (sqlite_result == SQLITE_ROW);
302251881Speter  stmt->needs_reset = TRUE;
303251881Speter
304251881Speter  return SVN_NO_ERROR;
305251881Speter}
306251881Speter
307251881Spetersvn_error_t *
308251881Spetersvn_sqlite__insert(apr_int64_t *row_id, svn_sqlite__stmt_t *stmt)
309251881Speter{
310251881Speter  svn_boolean_t got_row;
311251881Speter
312251881Speter  SVN_ERR(svn_sqlite__step(&got_row, stmt));
313251881Speter  if (row_id)
314251881Speter    *row_id = sqlite3_last_insert_rowid(stmt->db->db3);
315251881Speter
316251881Speter  return svn_error_trace(svn_sqlite__reset(stmt));
317251881Speter}
318251881Speter
319251881Spetersvn_error_t *
320251881Spetersvn_sqlite__update(int *affected_rows, svn_sqlite__stmt_t *stmt)
321251881Speter{
322251881Speter  SVN_ERR(step_with_expectation(stmt, FALSE));
323251881Speter
324251881Speter  if (affected_rows)
325251881Speter    *affected_rows = sqlite3_changes(stmt->db->db3);
326251881Speter
327251881Speter  return svn_error_trace(svn_sqlite__reset(stmt));
328251881Speter}
329251881Speter
330251881Speter
331251881Speterstatic svn_error_t *
332251881Spetervbindf(svn_sqlite__stmt_t *stmt, const char *fmt, va_list ap)
333251881Speter{
334251881Speter  int count;
335251881Speter
336251881Speter  for (count = 1; *fmt; fmt++, count++)
337251881Speter    {
338251881Speter      const void *blob;
339251881Speter      apr_size_t blob_size;
340251881Speter      const svn_token_map_t *map;
341251881Speter
342251881Speter      switch (*fmt)
343251881Speter        {
344251881Speter          case 's':
345251881Speter            SVN_ERR(svn_sqlite__bind_text(stmt, count,
346251881Speter                                          va_arg(ap, const char *)));
347251881Speter            break;
348251881Speter
349251881Speter          case 'd':
350251881Speter            SVN_ERR(svn_sqlite__bind_int(stmt, count,
351251881Speter                                         va_arg(ap, int)));
352251881Speter            break;
353251881Speter
354251881Speter          case 'i':
355251881Speter          case 'L':
356251881Speter            SVN_ERR(svn_sqlite__bind_int64(stmt, count,
357251881Speter                                           va_arg(ap, apr_int64_t)));
358251881Speter            break;
359251881Speter
360251881Speter          case 'b':
361251881Speter            blob = va_arg(ap, const void *);
362251881Speter            blob_size = va_arg(ap, apr_size_t);
363251881Speter            SVN_ERR(svn_sqlite__bind_blob(stmt, count, blob, blob_size));
364251881Speter            break;
365251881Speter
366251881Speter          case 'r':
367251881Speter            SVN_ERR(svn_sqlite__bind_revnum(stmt, count,
368251881Speter                                            va_arg(ap, svn_revnum_t)));
369251881Speter            break;
370251881Speter
371251881Speter          case 't':
372251881Speter            map = va_arg(ap, const svn_token_map_t *);
373251881Speter            SVN_ERR(svn_sqlite__bind_token(stmt, count, map, va_arg(ap, int)));
374251881Speter            break;
375251881Speter
376251881Speter          case 'n':
377251881Speter            /* Skip this column: no binding */
378251881Speter            break;
379251881Speter
380251881Speter          default:
381251881Speter            SVN_ERR_MALFUNCTION();
382251881Speter        }
383251881Speter    }
384251881Speter
385251881Speter  return SVN_NO_ERROR;
386251881Speter}
387251881Speter
388251881Spetersvn_error_t *
389251881Spetersvn_sqlite__bindf(svn_sqlite__stmt_t *stmt, const char *fmt, ...)
390251881Speter{
391251881Speter  svn_error_t *err;
392251881Speter  va_list ap;
393251881Speter
394251881Speter  va_start(ap, fmt);
395251881Speter  err = vbindf(stmt, fmt, ap);
396251881Speter  va_end(ap);
397251881Speter  return svn_error_trace(err);
398251881Speter}
399251881Speter
400251881Spetersvn_error_t *
401251881Spetersvn_sqlite__bind_int(svn_sqlite__stmt_t *stmt,
402251881Speter                     int slot,
403251881Speter                     int val)
404251881Speter{
405251881Speter  SQLITE_ERR(sqlite3_bind_int(stmt->s3stmt, slot, val), stmt->db);
406251881Speter  return SVN_NO_ERROR;
407251881Speter}
408251881Speter
409251881Spetersvn_error_t *
410251881Spetersvn_sqlite__bind_int64(svn_sqlite__stmt_t *stmt,
411251881Speter                       int slot,
412251881Speter                       apr_int64_t val)
413251881Speter{
414251881Speter  SQLITE_ERR(sqlite3_bind_int64(stmt->s3stmt, slot, val), stmt->db);
415251881Speter  return SVN_NO_ERROR;
416251881Speter}
417251881Speter
418251881Spetersvn_error_t *
419251881Spetersvn_sqlite__bind_text(svn_sqlite__stmt_t *stmt,
420251881Speter                      int slot,
421251881Speter                      const char *val)
422251881Speter{
423251881Speter  SQLITE_ERR(sqlite3_bind_text(stmt->s3stmt, slot, val, -1, SQLITE_TRANSIENT),
424251881Speter             stmt->db);
425251881Speter  return SVN_NO_ERROR;
426251881Speter}
427251881Speter
428251881Spetersvn_error_t *
429251881Spetersvn_sqlite__bind_blob(svn_sqlite__stmt_t *stmt,
430251881Speter                      int slot,
431251881Speter                      const void *val,
432251881Speter                      apr_size_t len)
433251881Speter{
434251881Speter  SQLITE_ERR(sqlite3_bind_blob(stmt->s3stmt, slot, val, (int) len,
435251881Speter                               SQLITE_TRANSIENT),
436251881Speter             stmt->db);
437251881Speter  return SVN_NO_ERROR;
438251881Speter}
439251881Speter
440251881Spetersvn_error_t *
441251881Spetersvn_sqlite__bind_token(svn_sqlite__stmt_t *stmt,
442251881Speter                       int slot,
443251881Speter                       const svn_token_map_t *map,
444251881Speter                       int value)
445251881Speter{
446251881Speter  const char *word = svn_token__to_word(map, value);
447251881Speter
448251881Speter  SQLITE_ERR(sqlite3_bind_text(stmt->s3stmt, slot, word, -1, SQLITE_STATIC),
449251881Speter             stmt->db);
450251881Speter  return SVN_NO_ERROR;
451251881Speter}
452251881Speter
453251881Spetersvn_error_t *
454251881Spetersvn_sqlite__bind_revnum(svn_sqlite__stmt_t *stmt,
455251881Speter                        int slot,
456251881Speter                        svn_revnum_t value)
457251881Speter{
458251881Speter  if (SVN_IS_VALID_REVNUM(value))
459251881Speter    SQLITE_ERR(sqlite3_bind_int64(stmt->s3stmt, slot,
460251881Speter                                  (sqlite_int64)value), stmt->db);
461251881Speter  else
462251881Speter    SQLITE_ERR(sqlite3_bind_null(stmt->s3stmt, slot), stmt->db);
463251881Speter
464251881Speter  return SVN_NO_ERROR;
465251881Speter}
466251881Speter
467251881Spetersvn_error_t *
468251881Spetersvn_sqlite__bind_properties(svn_sqlite__stmt_t *stmt,
469251881Speter                            int slot,
470251881Speter                            const apr_hash_t *props,
471251881Speter                            apr_pool_t *scratch_pool)
472251881Speter{
473251881Speter  svn_skel_t *skel;
474251881Speter  svn_stringbuf_t *properties;
475251881Speter
476251881Speter  if (props == NULL)
477251881Speter    return svn_error_trace(svn_sqlite__bind_blob(stmt, slot, NULL, 0));
478251881Speter
479251881Speter  SVN_ERR(svn_skel__unparse_proplist(&skel, props, scratch_pool));
480251881Speter  properties = svn_skel__unparse(skel, scratch_pool);
481251881Speter  return svn_error_trace(svn_sqlite__bind_blob(stmt,
482251881Speter                                               slot,
483251881Speter                                               properties->data,
484251881Speter                                               properties->len));
485251881Speter}
486251881Speter
487251881Spetersvn_error_t *
488251881Spetersvn_sqlite__bind_iprops(svn_sqlite__stmt_t *stmt,
489251881Speter                        int slot,
490251881Speter                        const apr_array_header_t *inherited_props,
491251881Speter                        apr_pool_t *scratch_pool)
492251881Speter{
493251881Speter  svn_skel_t *skel;
494251881Speter  svn_stringbuf_t *properties;
495251881Speter
496251881Speter  if (inherited_props == NULL)
497251881Speter    return svn_error_trace(svn_sqlite__bind_blob(stmt, slot, NULL, 0));
498251881Speter
499251881Speter  SVN_ERR(svn_skel__unparse_iproplist(&skel, inherited_props,
500251881Speter                                      scratch_pool, scratch_pool));
501251881Speter  properties = svn_skel__unparse(skel, scratch_pool);
502251881Speter  return svn_error_trace(svn_sqlite__bind_blob(stmt,
503251881Speter                                               slot,
504251881Speter                                               properties->data,
505251881Speter                                               properties->len));
506251881Speter}
507251881Speter
508251881Spetersvn_error_t *
509251881Spetersvn_sqlite__bind_checksum(svn_sqlite__stmt_t *stmt,
510251881Speter                          int slot,
511251881Speter                          const svn_checksum_t *checksum,
512251881Speter                          apr_pool_t *scratch_pool)
513251881Speter{
514251881Speter  const char *csum_str;
515251881Speter
516251881Speter  if (checksum == NULL)
517251881Speter    csum_str = NULL;
518251881Speter  else
519251881Speter    csum_str = svn_checksum_serialize(checksum, scratch_pool, scratch_pool);
520251881Speter
521251881Speter  return svn_error_trace(svn_sqlite__bind_text(stmt, slot, csum_str));
522251881Speter}
523251881Speter
524251881Speter
525251881Speterconst void *
526251881Spetersvn_sqlite__column_blob(svn_sqlite__stmt_t *stmt, int column,
527251881Speter                        apr_size_t *len, apr_pool_t *result_pool)
528251881Speter{
529251881Speter  const void *val = sqlite3_column_blob(stmt->s3stmt, column);
530251881Speter  *len = sqlite3_column_bytes(stmt->s3stmt, column);
531251881Speter
532251881Speter  if (result_pool && val != NULL)
533251881Speter    val = apr_pmemdup(result_pool, val, *len);
534251881Speter
535251881Speter  return val;
536251881Speter}
537251881Speter
538251881Speterconst char *
539251881Spetersvn_sqlite__column_text(svn_sqlite__stmt_t *stmt, int column,
540251881Speter                        apr_pool_t *result_pool)
541251881Speter{
542251881Speter  /* cast from 'unsigned char' to regular 'char'  */
543251881Speter  const char *result = (const char *)sqlite3_column_text(stmt->s3stmt, column);
544251881Speter
545251881Speter  if (result_pool && result != NULL)
546251881Speter    result = apr_pstrdup(result_pool, result);
547251881Speter
548251881Speter  return result;
549251881Speter}
550251881Speter
551251881Spetersvn_revnum_t
552251881Spetersvn_sqlite__column_revnum(svn_sqlite__stmt_t *stmt, int column)
553251881Speter{
554251881Speter  if (svn_sqlite__column_is_null(stmt, column))
555251881Speter    return SVN_INVALID_REVNUM;
556251881Speter  return (svn_revnum_t) sqlite3_column_int64(stmt->s3stmt, column);
557251881Speter}
558251881Speter
559251881Spetersvn_boolean_t
560251881Spetersvn_sqlite__column_boolean(svn_sqlite__stmt_t *stmt, int column)
561251881Speter{
562251881Speter  return sqlite3_column_int64(stmt->s3stmt, column) != 0;
563251881Speter}
564251881Speter
565251881Speterint
566251881Spetersvn_sqlite__column_int(svn_sqlite__stmt_t *stmt, int column)
567251881Speter{
568251881Speter  return sqlite3_column_int(stmt->s3stmt, column);
569251881Speter}
570251881Speter
571251881Speterapr_int64_t
572251881Spetersvn_sqlite__column_int64(svn_sqlite__stmt_t *stmt, int column)
573251881Speter{
574251881Speter  return sqlite3_column_int64(stmt->s3stmt, column);
575251881Speter}
576251881Speter
577251881Speterint
578251881Spetersvn_sqlite__column_token(svn_sqlite__stmt_t *stmt,
579251881Speter                         int column,
580251881Speter                         const svn_token_map_t *map)
581251881Speter{
582251881Speter  /* cast from 'unsigned char' to regular 'char'  */
583251881Speter  const char *word = (const char *)sqlite3_column_text(stmt->s3stmt, column);
584251881Speter
585251881Speter  return svn_token__from_word_strict(map, word);
586251881Speter}
587251881Speter
588251881Speterint
589251881Spetersvn_sqlite__column_token_null(svn_sqlite__stmt_t *stmt,
590251881Speter                              int column,
591251881Speter                              const svn_token_map_t *map,
592251881Speter                              int null_val)
593251881Speter{
594251881Speter  /* cast from 'unsigned char' to regular 'char'  */
595251881Speter  const char *word = (const char *)sqlite3_column_text(stmt->s3stmt, column);
596251881Speter
597251881Speter  if (!word)
598251881Speter    return null_val;
599251881Speter
600251881Speter  return svn_token__from_word_strict(map, word);
601251881Speter}
602251881Speter
603251881Spetersvn_error_t *
604251881Spetersvn_sqlite__column_properties(apr_hash_t **props,
605251881Speter                              svn_sqlite__stmt_t *stmt,
606251881Speter                              int column,
607251881Speter                              apr_pool_t *result_pool,
608251881Speter                              apr_pool_t *scratch_pool)
609251881Speter{
610251881Speter  apr_size_t len;
611251881Speter  const void *val;
612251881Speter
613251881Speter  /* svn_skel__parse_proplist copies everything needed to result_pool */
614251881Speter  val = svn_sqlite__column_blob(stmt, column, &len, NULL);
615251881Speter  if (val == NULL)
616251881Speter    {
617251881Speter      *props = NULL;
618251881Speter      return SVN_NO_ERROR;
619251881Speter    }
620251881Speter
621251881Speter  SVN_ERR(svn_skel__parse_proplist(props,
622251881Speter                                   svn_skel__parse(val, len, scratch_pool),
623251881Speter                                   result_pool));
624251881Speter
625251881Speter  return SVN_NO_ERROR;
626251881Speter}
627251881Speter
628251881Spetersvn_error_t *
629251881Spetersvn_sqlite__column_iprops(apr_array_header_t **iprops,
630251881Speter                          svn_sqlite__stmt_t *stmt,
631251881Speter                          int column,
632251881Speter                          apr_pool_t *result_pool,
633251881Speter                          apr_pool_t *scratch_pool)
634251881Speter{
635251881Speter  apr_size_t len;
636251881Speter  const void *val;
637251881Speter
638251881Speter  /* svn_skel__parse_iprops copies everything needed to result_pool */
639251881Speter  val = svn_sqlite__column_blob(stmt, column, &len, NULL);
640251881Speter  if (val == NULL)
641251881Speter    {
642251881Speter      *iprops = NULL;
643251881Speter      return SVN_NO_ERROR;
644251881Speter    }
645251881Speter
646251881Speter  SVN_ERR(svn_skel__parse_iprops(iprops,
647251881Speter                                 svn_skel__parse(val, len, scratch_pool),
648251881Speter                                 result_pool));
649251881Speter
650251881Speter  return SVN_NO_ERROR;
651251881Speter}
652251881Speter
653251881Spetersvn_error_t *
654251881Spetersvn_sqlite__column_checksum(const svn_checksum_t **checksum,
655251881Speter                            svn_sqlite__stmt_t *stmt, int column,
656251881Speter                            apr_pool_t *result_pool)
657251881Speter{
658251881Speter  const char *digest = svn_sqlite__column_text(stmt, column, NULL);
659251881Speter
660251881Speter  if (digest == NULL)
661251881Speter    *checksum = NULL;
662251881Speter  else
663251881Speter    SVN_ERR(svn_checksum_deserialize(checksum, digest,
664251881Speter                                     result_pool, result_pool));
665251881Speter
666251881Speter  return SVN_NO_ERROR;
667251881Speter}
668251881Speter
669251881Spetersvn_boolean_t
670251881Spetersvn_sqlite__column_is_null(svn_sqlite__stmt_t *stmt, int column)
671251881Speter{
672251881Speter  return sqlite3_column_type(stmt->s3stmt, column) == SQLITE_NULL;
673251881Speter}
674251881Speter
675251881Speterint
676251881Spetersvn_sqlite__column_bytes(svn_sqlite__stmt_t *stmt, int column)
677251881Speter{
678251881Speter  return sqlite3_column_bytes(stmt->s3stmt, column);
679251881Speter}
680251881Speter
681251881Spetersvn_error_t *
682251881Spetersvn_sqlite__finalize(svn_sqlite__stmt_t *stmt)
683251881Speter{
684251881Speter  SQLITE_ERR(sqlite3_finalize(stmt->s3stmt), stmt->db);
685251881Speter  return SVN_NO_ERROR;
686251881Speter}
687251881Speter
688251881Spetersvn_error_t *
689251881Spetersvn_sqlite__reset(svn_sqlite__stmt_t *stmt)
690251881Speter{
691251881Speter  SQLITE_ERR(sqlite3_reset(stmt->s3stmt), stmt->db);
692251881Speter  SQLITE_ERR(sqlite3_clear_bindings(stmt->s3stmt), stmt->db);
693251881Speter  stmt->needs_reset = FALSE;
694251881Speter  return SVN_NO_ERROR;
695251881Speter}
696251881Speter
697251881Speter
698251881Spetersvn_error_t *
699251881Spetersvn_sqlite__read_schema_version(int *version,
700251881Speter                                svn_sqlite__db_t *db,
701251881Speter                                apr_pool_t *scratch_pool)
702251881Speter{
703251881Speter  svn_sqlite__stmt_t *stmt;
704251881Speter
705251881Speter  SVN_ERR(prepare_statement(&stmt, db, "PRAGMA user_version;", scratch_pool));
706251881Speter  SVN_ERR(svn_sqlite__step_row(stmt));
707251881Speter
708251881Speter  *version = svn_sqlite__column_int(stmt, 0);
709251881Speter
710251881Speter  return svn_error_trace(svn_sqlite__finalize(stmt));
711251881Speter}
712251881Speter
713251881Speter
714251881Speterstatic volatile svn_atomic_t sqlite_init_state = 0;
715251881Speter
716251881Speter/* If possible, verify that SQLite was compiled in a thread-safe
717251881Speter   manner. */
718251881Speter/* Don't call this function directly!  Use svn_atomic__init_once(). */
719251881Speterstatic svn_error_t *
720251881Speterinit_sqlite(void *baton, apr_pool_t *pool)
721251881Speter{
722251881Speter  if (sqlite3_libversion_number() < SVN_SQLITE_MIN_VERSION_NUMBER)
723251881Speter    {
724251881Speter      return svn_error_createf(
725251881Speter                    SVN_ERR_SQLITE_ERROR, NULL,
726251881Speter                    _("SQLite compiled for %s, but running with %s"),
727251881Speter                    SVN_SQLITE_MIN_VERSION, sqlite3_libversion());
728251881Speter    }
729251881Speter
730251881Speter#if APR_HAS_THREADS
731251881Speter
732251881Speter  /* SQLite 3.5 allows verification of its thread-safety at runtime.
733251881Speter     Older versions are simply expected to have been configured with
734251881Speter     --enable-threadsafe, which compiles with -DSQLITE_THREADSAFE=1
735251881Speter     (or -DTHREADSAFE, for older versions). */
736251881Speter  if (! sqlite3_threadsafe())
737251881Speter    return svn_error_create(SVN_ERR_SQLITE_ERROR, NULL,
738251881Speter                            _("SQLite is required to be compiled and run in "
739251881Speter                              "thread-safe mode"));
740251881Speter
741251881Speter  /* If SQLite has been already initialized, sqlite3_config() returns
742251881Speter     SQLITE_MISUSE. */
743251881Speter  {
744251881Speter    int err = sqlite3_config(SQLITE_CONFIG_MULTITHREAD);
745251881Speter    if (err != SQLITE_OK && err != SQLITE_MISUSE)
746251881Speter      return svn_error_createf(SQLITE_ERROR_CODE(err), NULL,
747253734Speter                               _("Could not configure SQLite [S%d]"), err);
748251881Speter  }
749251881Speter  SQLITE_ERR_MSG(sqlite3_initialize(), _("Could not initialize SQLite"));
750251881Speter
751251881Speter#endif /* APR_HAS_THRADS */
752251881Speter
753251881Speter  return SVN_NO_ERROR;
754251881Speter}
755251881Speter
756251881Speterstatic svn_error_t *
757251881Speterinternal_open(sqlite3 **db3, const char *path, svn_sqlite__mode_t mode,
758251881Speter              apr_pool_t *scratch_pool)
759251881Speter{
760251881Speter  {
761251881Speter    int flags;
762251881Speter
763251881Speter    if (mode == svn_sqlite__mode_readonly)
764251881Speter      flags = SQLITE_OPEN_READONLY;
765251881Speter    else if (mode == svn_sqlite__mode_readwrite)
766251881Speter      flags = SQLITE_OPEN_READWRITE;
767251881Speter    else if (mode == svn_sqlite__mode_rwcreate)
768251881Speter      flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE;
769251881Speter    else
770251881Speter      SVN_ERR_MALFUNCTION();
771251881Speter
772251881Speter    /* Turn off SQLite's mutexes. All svn objects are single-threaded,
773251881Speter       so we can already guarantee that our use of the SQLite handle
774251881Speter       will be serialized properly.
775251881Speter
776251881Speter       Note: in 3.6.x, we've already config'd SQLite into MULTITHREAD mode,
777251881Speter       so this is probably redundant, but if we are running in a process where
778251881Speter       somebody initialized SQLite before us it is needed anyway.  */
779251881Speter    flags |= SQLITE_OPEN_NOMUTEX;
780251881Speter
781251881Speter    /* Open the database. Note that a handle is returned, even when an error
782251881Speter       occurs (except for out-of-memory); thus, we can safely use it to
783251881Speter       extract an error message and construct an svn_error_t. */
784251881Speter    {
785251881Speter      /* We'd like to use SQLITE_ERR here, but we can't since it would
786251881Speter         just return an error and leave the database open.  So, we need to
787251881Speter         do this manually. */
788251881Speter      /* ### SQLITE_CANTOPEN */
789251881Speter      int err_code = sqlite3_open_v2(path, db3, flags, NULL);
790251881Speter      if (err_code != SQLITE_OK)
791251881Speter        {
792251881Speter          /* Save the error message before closing the SQLite handle. */
793251881Speter          char *msg = apr_pstrdup(scratch_pool, sqlite3_errmsg(*db3));
794251881Speter
795251881Speter          /* We don't catch the error here, since we care more about the open
796251881Speter             error than the close error at this point. */
797251881Speter          sqlite3_close(*db3);
798251881Speter
799251881Speter          SQLITE_ERR_MSG(err_code, msg);
800251881Speter        }
801251881Speter    }
802251881Speter  }
803251881Speter
804251881Speter  /* Retry until timeout when database is busy. */
805251881Speter  SQLITE_ERR_MSG(sqlite3_busy_timeout(*db3, BUSY_TIMEOUT),
806251881Speter                 sqlite3_errmsg(*db3));
807251881Speter
808251881Speter  return SVN_NO_ERROR;
809251881Speter}
810251881Speter
811251881Speter
812251881Speter/* APR cleanup function used to close the database when its pool is destroyed.
813251881Speter   DATA should be the svn_sqlite__db_t handle for the database. */
814251881Speterstatic apr_status_t
815251881Speterclose_apr(void *data)
816251881Speter{
817251881Speter  svn_sqlite__db_t *db = data;
818251881Speter  svn_error_t *err = SVN_NO_ERROR;
819251881Speter  apr_status_t result;
820251881Speter  int i;
821251881Speter
822251881Speter  /* Check to see if we've already closed this database. */
823251881Speter  if (db->db3 == NULL)
824251881Speter    return APR_SUCCESS;
825251881Speter
826251881Speter  /* Finalize any existing prepared statements. */
827251881Speter  for (i = 0; i < db->nbr_statements; i++)
828251881Speter    {
829251881Speter      if (db->prepared_stmts[i])
830251881Speter        {
831251881Speter          if (db->prepared_stmts[i]->needs_reset)
832251881Speter            {
833251881Speter#ifdef SVN_DEBUG
834251881Speter              const char *stmt_text = db->statement_strings[i];
835251881Speter              stmt_text = stmt_text; /* Provide value for debugger */
836251881Speter
837251881Speter              SVN_ERR_MALFUNCTION_NO_RETURN();
838251881Speter#else
839251881Speter              err = svn_error_compose_create(
840251881Speter                            err,
841251881Speter                            svn_sqlite__reset(db->prepared_stmts[i]));
842251881Speter#endif
843251881Speter            }
844251881Speter          err = svn_error_compose_create(
845251881Speter                        svn_sqlite__finalize(db->prepared_stmts[i]), err);
846251881Speter        }
847251881Speter    }
848251881Speter  /* And finalize any used internal statements */
849251881Speter  for (; i < db->nbr_statements + STMT_INTERNAL_LAST; i++)
850251881Speter    {
851251881Speter      if (db->prepared_stmts[i])
852251881Speter        {
853251881Speter          err = svn_error_compose_create(
854251881Speter                        svn_sqlite__finalize(db->prepared_stmts[i]), err);
855251881Speter        }
856251881Speter    }
857251881Speter
858251881Speter  result = sqlite3_close(db->db3);
859251881Speter
860251881Speter  /* If there's a pre-existing error, return it. */
861251881Speter  if (err)
862251881Speter    {
863251881Speter      result = err->apr_err;
864251881Speter      svn_error_clear(err);
865251881Speter      return result;
866251881Speter    }
867251881Speter
868251881Speter  if (result != SQLITE_OK)
869251881Speter    return SQLITE_ERROR_CODE(result); /* ### lossy */
870251881Speter
871251881Speter  db->db3 = NULL;
872251881Speter
873251881Speter  return APR_SUCCESS;
874251881Speter}
875251881Speter
876251881Speter
877251881Spetersvn_error_t *
878251881Spetersvn_sqlite__open(svn_sqlite__db_t **db, const char *path,
879251881Speter                 svn_sqlite__mode_t mode, const char * const statements[],
880251881Speter                 int unused1, const char * const *unused2,
881251881Speter                 apr_pool_t *result_pool, apr_pool_t *scratch_pool)
882251881Speter{
883251881Speter  SVN_ERR(svn_atomic__init_once(&sqlite_init_state,
884251881Speter                                init_sqlite, NULL, scratch_pool));
885251881Speter
886251881Speter  *db = apr_pcalloc(result_pool, sizeof(**db));
887251881Speter
888251881Speter  SVN_ERR(internal_open(&(*db)->db3, path, mode, scratch_pool));
889251881Speter
890251881Speter#ifdef SQLITE3_DEBUG
891251881Speter  sqlite3_trace((*db)->db3, sqlite_tracer, (*db)->db3);
892251881Speter#endif
893251881Speter#ifdef SQLITE3_PROFILE
894251881Speter  sqlite3_profile((*db)->db3, sqlite_profiler, (*db)->db3);
895251881Speter#endif
896251881Speter
897251881Speter  /* ### simplify this. remnants of some old SQLite compat code.  */
898251881Speter  {
899251881Speter    int ignored_err = SQLITE_OK;
900251881Speter
901251881Speter    SVN_ERR(exec_sql2(*db, "PRAGMA case_sensitive_like=1;", ignored_err));
902251881Speter  }
903251881Speter
904251881Speter  SVN_ERR(exec_sql(*db,
905251881Speter              /* Disable synchronization to disable the explicit disk flushes
906251881Speter                 that make Sqlite up to 50 times slower; especially on small
907251881Speter                 transactions.
908251881Speter
909251881Speter                 This removes some stability guarantees on specific hardware
910251881Speter                 and power failures, but still guarantees atomic commits on
911251881Speter                 application crashes. With our dependency on external data
912251881Speter                 like pristine files (Wc) and revision files (repository),
913251881Speter                 we can't keep up these additional guarantees anyway.
914251881Speter
915251881Speter                 ### Maybe switch to NORMAL(1) when we use larger transaction
916251881Speter                     scopes */
917251881Speter              "PRAGMA synchronous=OFF;"
918251881Speter              /* Enable recursive triggers so that a user trigger will fire
919251881Speter                 in the deletion phase of an INSERT OR REPLACE statement.
920251881Speter                 Requires SQLite >= 3.6.18  */
921251881Speter              "PRAGMA recursive_triggers=ON;"));
922251881Speter
923251881Speter#if defined(SVN_DEBUG)
924251881Speter  /* When running in debug mode, enable the checking of foreign key
925251881Speter     constraints.  This has possible performance implications, so we don't
926251881Speter     bother to do it for production...for now. */
927251881Speter  SVN_ERR(exec_sql(*db, "PRAGMA foreign_keys=ON;"));
928251881Speter#endif
929251881Speter
930251881Speter  /* Store temporary tables in RAM instead of in temporary files, but don't
931251881Speter     fail on this if this option is disabled in the sqlite compilation by
932251881Speter     setting SQLITE_TEMP_STORE to 0 (always to disk) */
933251881Speter  svn_error_clear(exec_sql(*db, "PRAGMA temp_store = MEMORY;"));
934251881Speter
935251881Speter  /* Store the provided statements. */
936251881Speter  if (statements)
937251881Speter    {
938251881Speter      (*db)->statement_strings = statements;
939251881Speter      (*db)->nbr_statements = 0;
940251881Speter      while (*statements != NULL)
941251881Speter        {
942251881Speter          statements++;
943251881Speter          (*db)->nbr_statements++;
944251881Speter        }
945251881Speter
946251881Speter      (*db)->prepared_stmts = apr_pcalloc(
947251881Speter                                  result_pool,
948251881Speter                                  ((*db)->nbr_statements + STMT_INTERNAL_LAST)
949251881Speter                                                * sizeof(svn_sqlite__stmt_t *));
950251881Speter    }
951251881Speter  else
952251881Speter    {
953251881Speter      (*db)->nbr_statements = 0;
954251881Speter      (*db)->prepared_stmts = apr_pcalloc(result_pool,
955251881Speter                                          (0 + STMT_INTERNAL_LAST)
956251881Speter                                                * sizeof(svn_sqlite__stmt_t *));
957251881Speter    }
958251881Speter
959251881Speter  (*db)->state_pool = result_pool;
960251881Speter  apr_pool_cleanup_register(result_pool, *db, close_apr, apr_pool_cleanup_null);
961251881Speter
962251881Speter  return SVN_NO_ERROR;
963251881Speter}
964251881Speter
965251881Spetersvn_error_t *
966251881Spetersvn_sqlite__close(svn_sqlite__db_t *db)
967251881Speter{
968251881Speter  apr_status_t result = apr_pool_cleanup_run(db->state_pool, db, close_apr);
969251881Speter
970251881Speter  if (result == APR_SUCCESS)
971251881Speter    return SVN_NO_ERROR;
972251881Speter
973251881Speter  return svn_error_wrap_apr(result, NULL);
974251881Speter}
975251881Speter
976251881Speterstatic svn_error_t *
977251881Speterreset_all_statements(svn_sqlite__db_t *db,
978251881Speter                     svn_error_t *error_to_wrap)
979251881Speter{
980251881Speter  int i;
981251881Speter  svn_error_t *err;
982251881Speter
983251881Speter  /* ### Should we reorder the errors in this specific case
984251881Speter     ### to avoid returning the normal error as top level error? */
985251881Speter
986251881Speter  err = svn_error_compose_create(error_to_wrap,
987251881Speter                   svn_error_create(SVN_ERR_SQLITE_RESETTING_FOR_ROLLBACK,
988251881Speter                                    NULL, NULL));
989251881Speter
990251881Speter  for (i = 0; i < db->nbr_statements; i++)
991251881Speter    if (db->prepared_stmts[i] && db->prepared_stmts[i]->needs_reset)
992251881Speter      err = svn_error_compose_create(err,
993251881Speter                                svn_sqlite__reset(db->prepared_stmts[i]));
994251881Speter
995251881Speter  return err;
996251881Speter}
997251881Speter
998251881Spetersvn_error_t *
999251881Spetersvn_sqlite__begin_transaction(svn_sqlite__db_t *db)
1000251881Speter{
1001251881Speter  svn_sqlite__stmt_t *stmt;
1002251881Speter
1003251881Speter  SVN_ERR(get_internal_statement(&stmt, db,
1004251881Speter                                 STMT_INTERNAL_BEGIN_TRANSACTION));
1005251881Speter  SVN_ERR(svn_sqlite__step_done(stmt));
1006251881Speter  return SVN_NO_ERROR;
1007251881Speter}
1008251881Speter
1009251881Spetersvn_error_t *
1010251881Spetersvn_sqlite__begin_immediate_transaction(svn_sqlite__db_t *db)
1011251881Speter{
1012251881Speter  svn_sqlite__stmt_t *stmt;
1013251881Speter
1014251881Speter  SVN_ERR(get_internal_statement(&stmt, db,
1015251881Speter                                 STMT_INTERNAL_BEGIN_IMMEDIATE_TRANSACTION));
1016251881Speter  SVN_ERR(svn_sqlite__step_done(stmt));
1017251881Speter  return SVN_NO_ERROR;
1018251881Speter}
1019251881Speter
1020251881Spetersvn_error_t *
1021251881Spetersvn_sqlite__begin_savepoint(svn_sqlite__db_t *db)
1022251881Speter{
1023251881Speter  svn_sqlite__stmt_t *stmt;
1024251881Speter
1025251881Speter  SVN_ERR(get_internal_statement(&stmt, db,
1026251881Speter                                 STMT_INTERNAL_SAVEPOINT_SVN));
1027251881Speter  SVN_ERR(svn_sqlite__step_done(stmt));
1028251881Speter  return SVN_NO_ERROR;
1029251881Speter}
1030251881Speter
1031251881Spetersvn_error_t *
1032251881Spetersvn_sqlite__finish_transaction(svn_sqlite__db_t *db,
1033251881Speter                               svn_error_t *err)
1034251881Speter{
1035251881Speter  svn_sqlite__stmt_t *stmt;
1036251881Speter
1037251881Speter  /* Commit or rollback the sqlite transaction. */
1038251881Speter  if (err)
1039251881Speter    {
1040251881Speter      svn_error_t *err2;
1041251881Speter
1042251881Speter      err2 = get_internal_statement(&stmt, db,
1043251881Speter                                    STMT_INTERNAL_ROLLBACK_TRANSACTION);
1044251881Speter      if (!err2)
1045251881Speter        err2 = svn_sqlite__step_done(stmt);
1046251881Speter
1047251881Speter      if (err2 && err2->apr_err == SVN_ERR_SQLITE_BUSY)
1048251881Speter        {
1049251881Speter          /* ### Houston, we have a problem!
1050251881Speter
1051251881Speter             We are trying to rollback but we can't because some
1052251881Speter             statements are still busy. This leaves the database
1053251881Speter             unusable for future transactions as the current transaction
1054251881Speter             is still open.
1055251881Speter
1056251881Speter             As we are returning the actual error as the most relevant
1057251881Speter             error in the chain, our caller might assume that it can
1058251881Speter             retry/compensate on this error (e.g. SVN_WC_LOCKED), while
1059251881Speter             in fact the SQLite database is unusable until the statements
1060251881Speter             started within this transaction are reset and the transaction
1061251881Speter             aborted.
1062251881Speter
1063251881Speter             We try to compensate by resetting all prepared but unreset
1064251881Speter             statements; but we leave the busy error in the chain anyway to
1065251881Speter             help diagnosing the original error and help in finding where
1066251881Speter             a reset statement is missing. */
1067251881Speter
1068251881Speter          err2 = reset_all_statements(db, err2);
1069251881Speter          err2 = svn_error_compose_create(
1070251881Speter                      svn_sqlite__step_done(stmt),
1071251881Speter                      err2);
1072251881Speter        }
1073251881Speter
1074251881Speter      return svn_error_compose_create(err,
1075251881Speter                                      err2);
1076251881Speter    }
1077251881Speter
1078251881Speter  SVN_ERR(get_internal_statement(&stmt, db, STMT_INTERNAL_COMMIT_TRANSACTION));
1079251881Speter  return svn_error_trace(svn_sqlite__step_done(stmt));
1080251881Speter}
1081251881Speter
1082251881Spetersvn_error_t *
1083251881Spetersvn_sqlite__finish_savepoint(svn_sqlite__db_t *db,
1084251881Speter                             svn_error_t *err)
1085251881Speter{
1086251881Speter  svn_sqlite__stmt_t *stmt;
1087251881Speter
1088251881Speter  if (err)
1089251881Speter    {
1090251881Speter      svn_error_t *err2;
1091251881Speter
1092251881Speter      err2 = get_internal_statement(&stmt, db,
1093251881Speter                                    STMT_INTERNAL_ROLLBACK_TO_SAVEPOINT_SVN);
1094251881Speter
1095251881Speter      if (!err2)
1096251881Speter        err2 = svn_sqlite__step_done(stmt);
1097251881Speter
1098251881Speter      if (err2 && err2->apr_err == SVN_ERR_SQLITE_BUSY)
1099251881Speter        {
1100251881Speter          /* Ok, we have a major problem. Some statement is still open, which
1101251881Speter             makes it impossible to release this savepoint.
1102251881Speter
1103251881Speter             ### See huge comment in svn_sqlite__finish_transaction for
1104251881Speter                 further details */
1105251881Speter
1106251881Speter          err2 = reset_all_statements(db, err2);
1107251881Speter          err2 = svn_error_compose_create(svn_sqlite__step_done(stmt), err2);
1108251881Speter        }
1109251881Speter
1110251881Speter      err = svn_error_compose_create(err, err2);
1111251881Speter      err2 = get_internal_statement(&stmt, db,
1112251881Speter                                    STMT_INTERNAL_RELEASE_SAVEPOINT_SVN);
1113251881Speter
1114251881Speter      if (!err2)
1115251881Speter        err2 = svn_sqlite__step_done(stmt);
1116251881Speter
1117251881Speter      return svn_error_trace(svn_error_compose_create(err, err2));
1118251881Speter    }
1119251881Speter
1120251881Speter  SVN_ERR(get_internal_statement(&stmt, db,
1121251881Speter                                 STMT_INTERNAL_RELEASE_SAVEPOINT_SVN));
1122251881Speter
1123251881Speter  return svn_error_trace(svn_sqlite__step_done(stmt));
1124251881Speter}
1125251881Speter
1126251881Spetersvn_error_t *
1127251881Spetersvn_sqlite__with_transaction(svn_sqlite__db_t *db,
1128251881Speter                             svn_sqlite__transaction_callback_t cb_func,
1129251881Speter                             void *cb_baton,
1130251881Speter                             apr_pool_t *scratch_pool /* NULL allowed */)
1131251881Speter{
1132251881Speter  SVN_SQLITE__WITH_TXN(cb_func(cb_baton, db, scratch_pool), db);
1133251881Speter  return SVN_NO_ERROR;
1134251881Speter}
1135251881Speter
1136251881Spetersvn_error_t *
1137251881Spetersvn_sqlite__with_immediate_transaction(
1138251881Speter  svn_sqlite__db_t *db,
1139251881Speter  svn_sqlite__transaction_callback_t cb_func,
1140251881Speter  void *cb_baton,
1141251881Speter  apr_pool_t *scratch_pool /* NULL allowed */)
1142251881Speter{
1143251881Speter  SVN_SQLITE__WITH_IMMEDIATE_TXN(cb_func(cb_baton, db, scratch_pool), db);
1144251881Speter  return SVN_NO_ERROR;
1145251881Speter}
1146251881Speter
1147251881Spetersvn_error_t *
1148251881Spetersvn_sqlite__with_lock(svn_sqlite__db_t *db,
1149251881Speter                      svn_sqlite__transaction_callback_t cb_func,
1150251881Speter                      void *cb_baton,
1151251881Speter                      apr_pool_t *scratch_pool /* NULL allowed */)
1152251881Speter{
1153251881Speter  SVN_SQLITE__WITH_LOCK(cb_func(cb_baton, db, scratch_pool), db);
1154251881Speter  return SVN_NO_ERROR;
1155251881Speter}
1156251881Speter
1157251881Spetersvn_error_t *
1158251881Spetersvn_sqlite__hotcopy(const char *src_path,
1159251881Speter                    const char *dst_path,
1160251881Speter                    apr_pool_t *scratch_pool)
1161251881Speter{
1162251881Speter  svn_sqlite__db_t *src_db;
1163251881Speter
1164251881Speter  SVN_ERR(svn_sqlite__open(&src_db, src_path, svn_sqlite__mode_readonly,
1165251881Speter                           NULL, 0, NULL,
1166251881Speter                           scratch_pool, scratch_pool));
1167251881Speter
1168251881Speter  {
1169251881Speter    svn_sqlite__db_t *dst_db;
1170251881Speter    sqlite3_backup *backup;
1171251881Speter    int rc1, rc2;
1172251881Speter
1173251881Speter    SVN_ERR(svn_sqlite__open(&dst_db, dst_path, svn_sqlite__mode_rwcreate,
1174251881Speter                             NULL, 0, NULL, scratch_pool, scratch_pool));
1175251881Speter    backup = sqlite3_backup_init(dst_db->db3, "main", src_db->db3, "main");
1176251881Speter    if (!backup)
1177251881Speter      return svn_error_createf(SVN_ERR_SQLITE_ERROR, NULL,
1178251881Speter                               _("SQLite hotcopy failed for %s"), src_path);
1179251881Speter    do
1180251881Speter      {
1181251881Speter        /* Pages are usually 1024 byte (SQLite docs). On my laptop
1182251881Speter           copying gets faster as the number of pages is increased up
1183251881Speter           to about 64, beyond that speed levels off.  Lets put the
1184251881Speter           number of pages an order of magnitude higher, this is still
1185251881Speter           likely to be a fraction of large databases. */
1186251881Speter        rc1 = sqlite3_backup_step(backup, 1024);
1187251881Speter
1188251881Speter        /* Should we sleep on SQLITE_OK?  That would make copying a
1189251881Speter           large database take much longer.  When we do sleep how,
1190251881Speter           long should we sleep?  Should the sleep get longer if we
1191251881Speter           keep getting BUSY/LOCKED?  I have no real reason for
1192251881Speter           choosing 25. */
1193251881Speter        if (rc1 == SQLITE_BUSY || rc1 == SQLITE_LOCKED)
1194251881Speter          sqlite3_sleep(25);
1195251881Speter      }
1196251881Speter    while (rc1 == SQLITE_OK || rc1 == SQLITE_BUSY || rc1 == SQLITE_LOCKED);
1197251881Speter    rc2 = sqlite3_backup_finish(backup);
1198251881Speter    if (rc1 != SQLITE_DONE)
1199251881Speter      SQLITE_ERR(rc1, dst_db);
1200251881Speter    SQLITE_ERR(rc2, dst_db);
1201251881Speter    SVN_ERR(svn_sqlite__close(dst_db));
1202251881Speter  }
1203251881Speter
1204251881Speter  SVN_ERR(svn_sqlite__close(src_db));
1205251881Speter
1206251881Speter  return SVN_NO_ERROR;
1207251881Speter}
1208251881Speter
1209251881Speterstruct function_wrapper_baton_t
1210251881Speter{
1211251881Speter  svn_sqlite__func_t func;
1212251881Speter  void *baton;
1213251881Speter
1214251881Speter  apr_pool_t *scratch_pool;
1215251881Speter};
1216251881Speter
1217251881Speterstatic void
1218251881Speterwrapped_func(sqlite3_context *context,
1219251881Speter             int argc,
1220251881Speter             sqlite3_value *values[])
1221251881Speter{
1222251881Speter  struct function_wrapper_baton_t *fwb = sqlite3_user_data(context);
1223251881Speter  svn_sqlite__context_t sctx;
1224251881Speter  svn_sqlite__value_t **local_vals =
1225251881Speter                            apr_palloc(fwb->scratch_pool,
1226251881Speter                                       sizeof(svn_sqlite__value_t *) * argc);
1227251881Speter  svn_error_t *err;
1228251881Speter  int i;
1229251881Speter
1230251881Speter  sctx.context = context;
1231251881Speter
1232251881Speter  for (i = 0; i < argc; i++)
1233251881Speter    {
1234251881Speter      local_vals[i] = apr_palloc(fwb->scratch_pool, sizeof(*local_vals[i]));
1235251881Speter      local_vals[i]->value = values[i];
1236251881Speter    }
1237251881Speter
1238251881Speter  err = fwb->func(&sctx, argc, local_vals, fwb->scratch_pool);
1239251881Speter  svn_pool_clear(fwb->scratch_pool);
1240251881Speter
1241251881Speter  if (err)
1242251881Speter    {
1243251881Speter      char buf[256];
1244251881Speter      sqlite3_result_error(context,
1245251881Speter                           svn_err_best_message(err, buf, sizeof(buf)),
1246251881Speter                           -1);
1247251881Speter      svn_error_clear(err);
1248251881Speter    }
1249251881Speter}
1250251881Speter
1251251881Spetersvn_error_t *
1252251881Spetersvn_sqlite__create_scalar_function(svn_sqlite__db_t *db,
1253251881Speter                                   const char *func_name,
1254251881Speter                                   int argc,
1255251881Speter                                   svn_sqlite__func_t func,
1256251881Speter                                   void *baton)
1257251881Speter{
1258251881Speter  struct function_wrapper_baton_t *fwb = apr_pcalloc(db->state_pool,
1259251881Speter                                                     sizeof(*fwb));
1260251881Speter
1261251881Speter  fwb->scratch_pool = svn_pool_create(db->state_pool);
1262251881Speter  fwb->func = func;
1263251881Speter  fwb->baton = baton;
1264251881Speter
1265251881Speter  SQLITE_ERR(sqlite3_create_function(db->db3, func_name, argc, SQLITE_ANY,
1266251881Speter                                     fwb, wrapped_func, NULL, NULL),
1267251881Speter             db);
1268251881Speter
1269251881Speter  return SVN_NO_ERROR;
1270251881Speter}
1271251881Speter
1272251881Speterint
1273251881Spetersvn_sqlite__value_type(svn_sqlite__value_t *val)
1274251881Speter{
1275251881Speter  return sqlite3_value_type(val->value);
1276251881Speter}
1277251881Speter
1278251881Speterconst char *
1279251881Spetersvn_sqlite__value_text(svn_sqlite__value_t *val)
1280251881Speter{
1281251881Speter  return (const char *) sqlite3_value_text(val->value);
1282251881Speter}
1283251881Speter
1284251881Spetervoid
1285251881Spetersvn_sqlite__result_null(svn_sqlite__context_t *sctx)
1286251881Speter{
1287251881Speter  sqlite3_result_null(sctx->context);
1288251881Speter}
1289251881Speter
1290251881Spetervoid
1291251881Spetersvn_sqlite__result_int64(svn_sqlite__context_t *sctx, apr_int64_t val)
1292251881Speter{
1293251881Speter  sqlite3_result_int64(sctx->context, val);
1294251881Speter}
1295