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