diff options
Diffstat (limited to 'subversion/include/private/svn_sqlite.h')
-rw-r--r-- | subversion/include/private/svn_sqlite.h | 519 |
1 files changed, 519 insertions, 0 deletions
diff --git a/subversion/include/private/svn_sqlite.h b/subversion/include/private/svn_sqlite.h new file mode 100644 index 0000000..c1d640b --- /dev/null +++ b/subversion/include/private/svn_sqlite.h @@ -0,0 +1,519 @@ +/* svn_sqlite.h + * + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + */ + + +#ifndef SVN_SQLITE_H +#define SVN_SQLITE_H + +#include <apr_pools.h> + +#include "svn_types.h" +#include "svn_checksum.h" +#include "svn_error.h" + +#include "private/svn_token.h" /* for svn_token_map_t */ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +/* Because the SQLite code can be inlined into libsvn_subre/sqlite.c, + we define accessors to its compile-time and run-time version + numbers here. */ + +/* Return the value that SQLITE_VERSION had at compile time. */ +const char *svn_sqlite__compiled_version(void); + +/* Return the value of sqlite3_libversion() at run time. */ +const char *svn_sqlite__runtime_version(void); + + +typedef struct svn_sqlite__db_t svn_sqlite__db_t; +typedef struct svn_sqlite__stmt_t svn_sqlite__stmt_t; +typedef struct svn_sqlite__context_t svn_sqlite__context_t; +typedef struct svn_sqlite__value_t svn_sqlite__value_t; + +typedef enum svn_sqlite__mode_e { + svn_sqlite__mode_readonly, /* open the database read-only */ + svn_sqlite__mode_readwrite, /* open the database read-write */ + svn_sqlite__mode_rwcreate /* open/create the database read-write */ +} svn_sqlite__mode_t; + +/* The type used for callback functions. */ +typedef svn_error_t *(*svn_sqlite__func_t)(svn_sqlite__context_t *sctx, + int argc, + svn_sqlite__value_t *values[], + apr_pool_t *scatch_pool); + + +/* Step the given statement; if it returns SQLITE_DONE, reset the statement. + Otherwise, raise an SVN error. */ +svn_error_t * +svn_sqlite__step_done(svn_sqlite__stmt_t *stmt); + +/* Step the given statement; raise an SVN error (and reset the + statement) if it doesn't return SQLITE_ROW. */ +svn_error_t * +svn_sqlite__step_row(svn_sqlite__stmt_t *stmt); + +/* Step the given statement; raise an SVN error (and reset the + statement) if it doesn't return SQLITE_DONE or SQLITE_ROW. Set + *GOT_ROW to true iff it got SQLITE_ROW. +*/ +svn_error_t * +svn_sqlite__step(svn_boolean_t *got_row, svn_sqlite__stmt_t *stmt); + +/* Perform an insert as given by the prepared and bound STMT, and set + *ROW_ID to the id of the inserted row if ROW_ID is non-NULL. + STMT will be reset prior to returning. */ +svn_error_t * +svn_sqlite__insert(apr_int64_t *row_id, svn_sqlite__stmt_t *stmt); + +/* Perform an update/delete and then return the number of affected rows. + If AFFECTED_ROWS is not NULL, then set *AFFECTED_ROWS to the + number of rows changed. + STMT will be reset prior to returning. */ +svn_error_t * +svn_sqlite__update(int *affected_rows, svn_sqlite__stmt_t *stmt); + +/* Return in *VERSION the version of the schema in DB. Use SCRATCH_POOL + for temporary allocations. */ +svn_error_t * +svn_sqlite__read_schema_version(int *version, + svn_sqlite__db_t *db, + apr_pool_t *scratch_pool); + + + +/* Open a connection in *DB to the database at PATH. Validate the schema, + creating/upgrading to LATEST_SCHEMA if needed using the instructions + in UPGRADE_SQL. The resulting DB is allocated in RESULT_POOL, and any + temporary allocations are made in SCRATCH_POOL. + + STATEMENTS is an array of strings which may eventually be executed, the + last element of which should be NULL. These strings and the array itself + are not duplicated internally, and should have a lifetime at least as long + as RESULT_POOL. + STATEMENTS itself may be NULL, in which case it has no impact. + See svn_sqlite__get_statement() for how these strings are used. + + The statements will be finalized and the SQLite database will be closed + when RESULT_POOL is cleaned up. */ +svn_error_t * +svn_sqlite__open(svn_sqlite__db_t **db, const char *repos_path, + svn_sqlite__mode_t mode, const char * const statements[], + int latest_schema, const char * const *upgrade_sql, + apr_pool_t *result_pool, apr_pool_t *scratch_pool); + +/* Explicitly close the connection in DB. */ +svn_error_t * +svn_sqlite__close(svn_sqlite__db_t *db); + +/* Add a custom function to be used with this database connection. The data + in BATON should live at least as long as the connection in DB. */ +svn_error_t * +svn_sqlite__create_scalar_function(svn_sqlite__db_t *db, + const char *func_name, + int argc, + svn_sqlite__func_t func, + void *baton); + +/* Execute the (multiple) statements in the STATEMENTS[STMT_IDX] string. */ +svn_error_t * +svn_sqlite__exec_statements(svn_sqlite__db_t *db, int stmt_idx); + +/* Return the statement in *STMT which has been prepared from the + STATEMENTS[STMT_IDX] string, where STATEMENTS is the array that was + passed to svn_sqlite__open(). This statement is allocated in the same + pool as the DB, and will be cleaned up when DB is closed. */ +svn_error_t * +svn_sqlite__get_statement(svn_sqlite__stmt_t **stmt, svn_sqlite__db_t *db, + int stmt_idx); + + +/* --------------------------------------------------------------------- + + BINDING VALUES + +*/ + +/* Bind values to SQL parameters in STMT, according to FMT. FMT may contain: + + Spec Argument type Item type + ---- ----------------- --------- + n <none, absent> Column assignment skip + d int Number + L apr_int64_t Number + i apr_int64_t Number (deprecated format spec) + s const char * String + b const void * Blob data + apr_size_t Blob length + r svn_revnum_t Revision number + t const svn_token_map_t * Token mapping table + int Token value + + Each character in FMT maps to one SQL parameter, and one or two function + parameters, in the order they appear. +*/ +svn_error_t * +svn_sqlite__bindf(svn_sqlite__stmt_t *stmt, const char *fmt, ...); + +/* Error-handling wrapper around sqlite3_bind_int. */ +svn_error_t * +svn_sqlite__bind_int(svn_sqlite__stmt_t *stmt, int slot, int val); + +/* Error-handling wrapper around sqlite3_bind_int64. */ +svn_error_t * +svn_sqlite__bind_int64(svn_sqlite__stmt_t *stmt, int slot, + apr_int64_t val); + +/* Error-handling wrapper around sqlite3_bind_text. VAL cannot contain + zero bytes; we always pass SQLITE_TRANSIENT. */ +svn_error_t * +svn_sqlite__bind_text(svn_sqlite__stmt_t *stmt, int slot, + const char *val); + +/* Error-handling wrapper around sqlite3_bind_blob. */ +svn_error_t * +svn_sqlite__bind_blob(svn_sqlite__stmt_t *stmt, + int slot, + const void *val, + apr_size_t len); + +/* Look up VALUE in MAP, and bind the resulting token word at SLOT. */ +svn_error_t * +svn_sqlite__bind_token(svn_sqlite__stmt_t *stmt, + int slot, + const svn_token_map_t *map, + int value); + +/* Bind the value to SLOT, unless SVN_IS_VALID_REVNUM(value) is false, + in which case it binds NULL. */ +svn_error_t * +svn_sqlite__bind_revnum(svn_sqlite__stmt_t *stmt, int slot, + svn_revnum_t value); + +/* Bind a set of properties to the given slot. If PROPS is NULL, then no + binding will occur. PROPS will be stored as a serialized skel. */ +svn_error_t * +svn_sqlite__bind_properties(svn_sqlite__stmt_t *stmt, + int slot, + const apr_hash_t *props, + apr_pool_t *scratch_pool); + +/* Bind a set of inherited properties to the given slot. If INHERITED_PROPS + is NULL, then no binding will occur. INHERITED_PROPS will be stored as a + serialized skel. */ +svn_error_t * +svn_sqlite__bind_iprops(svn_sqlite__stmt_t *stmt, + int slot, + const apr_array_header_t *inherited_props, + apr_pool_t *scratch_pool); + +/* Bind a checksum's value to the given slot. If CHECKSUM is NULL, then no + binding will occur. */ +svn_error_t * +svn_sqlite__bind_checksum(svn_sqlite__stmt_t *stmt, + int slot, + const svn_checksum_t *checksum, + apr_pool_t *scratch_pool); + + +/* --------------------------------------------------------------------- + + FETCHING VALUES + +*/ + +/* Wrapper around sqlite3_column_blob and sqlite3_column_bytes. The return + value will be NULL if the column is null. + + If RESULT_POOL is not NULL, allocate the return value (if any) in it. + If RESULT_POOL is NULL, the return value will be valid until an + invocation of svn_sqlite__column_* performs a data type conversion (as + described in the SQLite documentation) or the statement is stepped or + reset or finalized. */ +const void * +svn_sqlite__column_blob(svn_sqlite__stmt_t *stmt, int column, + apr_size_t *len, apr_pool_t *result_pool); + +/* Wrapper around sqlite3_column_text. If the column is null, then the + return value will be NULL. + + If RESULT_POOL is not NULL, allocate the return value (if any) in it. + If RESULT_POOL is NULL, the return value will be valid until an + invocation of svn_sqlite__column_* performs a data type conversion (as + described in the SQLite documentation) or the statement is stepped or + reset or finalized. */ +const char * +svn_sqlite__column_text(svn_sqlite__stmt_t *stmt, int column, + apr_pool_t *result_pool); + +/* Wrapper around sqlite3_column_int64. If the column is null, then the + return value will be SVN_INVALID_REVNUM. */ +svn_revnum_t +svn_sqlite__column_revnum(svn_sqlite__stmt_t *stmt, int column); + +/* Wrapper around sqlite3_column_int64. If the column is null, then the + return value will be FALSE. */ +svn_boolean_t +svn_sqlite__column_boolean(svn_sqlite__stmt_t *stmt, int column); + +/* Wrapper around sqlite3_column_int. If the column is null, then the + return value will be 0. */ +int +svn_sqlite__column_int(svn_sqlite__stmt_t *stmt, int column); + +/* Wrapper around sqlite3_column_int64. If the column is null, then the + return value will be 0. */ +apr_int64_t +svn_sqlite__column_int64(svn_sqlite__stmt_t *stmt, int column); + +/* Fetch the word at COLUMN, look it up in the MAP, and return its value. + MALFUNCTION is thrown if the column is null or contains an unknown word. */ +int +svn_sqlite__column_token(svn_sqlite__stmt_t *stmt, + int column, + const svn_token_map_t *map); + +/* Fetch the word at COLUMN, look it up in the MAP, and return its value. + Returns NULL_VAL if the column is null. MALFUNCTION is thrown if the + column contains an unknown word. */ +int +svn_sqlite__column_token_null(svn_sqlite__stmt_t *stmt, + int column, + const svn_token_map_t *map, + int null_val); + +/* Return the column as a hash of const char * => const svn_string_t *. + If the column is null, then set *PROPS to NULL. The + results will be allocated in RESULT_POOL, and any temporary allocations + will be made in SCRATCH_POOL. */ +svn_error_t * +svn_sqlite__column_properties(apr_hash_t **props, + svn_sqlite__stmt_t *stmt, + int column, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool); + +/* Return the column as an array of depth-first ordered array of + svn_prop_inherited_item_t * structures. If the column is null, then + set *IPROPS to NULL. The results will be allocated in RESULT_POOL, + and any temporary allocations will be made in SCRATCH_POOL. */ +svn_error_t * +svn_sqlite__column_iprops(apr_array_header_t **iprops, + svn_sqlite__stmt_t *stmt, + int column, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool); + +/* Return the column as a checksum. If the column is null, then NULL will + be stored into *CHECKSUM. The result will be allocated in RESULT_POOL. */ +svn_error_t * +svn_sqlite__column_checksum(const svn_checksum_t **checksum, + svn_sqlite__stmt_t *stmt, + int column, + apr_pool_t *result_pool); + +/* Return TRUE if the result of selecting the column is null, + FALSE otherwise */ +svn_boolean_t +svn_sqlite__column_is_null(svn_sqlite__stmt_t *stmt, int column); + +/* Return the number of bytes the column uses in a text or blob representation. + 0 for NULL columns. */ +int +svn_sqlite__column_bytes(svn_sqlite__stmt_t *stmt, int column); + + +/* --------------------------------------------------------------------- */ + +#define SVN_SQLITE__INTEGER 1 +#define SVN_SQLITE__FLOAT 2 +#define SVN_SQLITE__TEXT 3 +#define SVN_SQLITE__BLOB 4 +#define SVN_SQLITE__NULL 5 + +/* */ +int +svn_sqlite__value_type(svn_sqlite__value_t *val); + +/* */ +const char * +svn_sqlite__value_text(svn_sqlite__value_t *val); + + +/* --------------------------------------------------------------------- */ + +/* */ +void +svn_sqlite__result_null(svn_sqlite__context_t *sctx); + +void +svn_sqlite__result_int64(svn_sqlite__context_t *sctx, apr_int64_t val); + + +/* --------------------------------------------------------------------- */ + + +/* Error-handling wrapper around sqlite3_finalize. */ +svn_error_t * +svn_sqlite__finalize(svn_sqlite__stmt_t *stmt); + +/* Reset STMT by calling sqlite3_reset(), and also clear any bindings to it. + + Note: svn_sqlite__get_statement() calls this function automatically if + the requested statement has been used and has not yet been reset. */ +svn_error_t * +svn_sqlite__reset(svn_sqlite__stmt_t *stmt); + + +/* Begin a transaction in DB. */ +svn_error_t * +svn_sqlite__begin_transaction(svn_sqlite__db_t *db); + +/* Like svn_sqlite__begin_transaction(), but takes out a 'RESERVED' lock + immediately, instead of using the default deferred locking scheme. */ +svn_error_t * +svn_sqlite__begin_immediate_transaction(svn_sqlite__db_t *db); + +/* Begin a savepoint in DB. */ +svn_error_t * +svn_sqlite__begin_savepoint(svn_sqlite__db_t *db); + +/* Commit the current transaction in DB if ERR is SVN_NO_ERROR, otherwise + * roll back the transaction. Return a composition of ERR and any error + * that may occur during the commit or roll-back. */ +svn_error_t * +svn_sqlite__finish_transaction(svn_sqlite__db_t *db, + svn_error_t *err); + +/* Release the current savepoint in DB if EXPR is SVN_NO_ERROR, otherwise + * roll back to the savepoint and then release it. Return a composition of + * ERR and any error that may occur during the release or roll-back. */ +svn_error_t * +svn_sqlite__finish_savepoint(svn_sqlite__db_t *db, + svn_error_t *err); + +/* Evaluate the expression EXPR within a transaction. + * + * Begin a transaction in DB; evaluate the expression EXPR, which would + * typically be a function call that does some work in DB; finally commit + * the transaction if EXPR evaluated to SVN_NO_ERROR, otherwise roll back + * the transaction. + */ +#define SVN_SQLITE__WITH_TXN(expr, db) \ + do { \ + svn_sqlite__db_t *svn_sqlite__db = (db); \ + svn_error_t *svn_sqlite__err; \ + \ + SVN_ERR(svn_sqlite__begin_transaction(svn_sqlite__db)); \ + svn_sqlite__err = (expr); \ + SVN_ERR(svn_sqlite__finish_transaction(svn_sqlite__db, svn_sqlite__err)); \ + } while (0) + +/* Callback function to for use with svn_sqlite__with_transaction(). */ +typedef svn_error_t *(*svn_sqlite__transaction_callback_t)( + void *baton, svn_sqlite__db_t *db, apr_pool_t *scratch_pool); + +/* Helper function to handle SQLite transactions. All the work done inside + CB_FUNC will be wrapped in an SQLite transaction, which will be committed + if CB_FUNC does not return an error. If any error is returned from CB_FUNC, + the transaction will be rolled back. DB and CB_BATON will be passed to + CB_FUNC. SCRATCH_POOL will be passed to the callback (NULL is valid). */ +svn_error_t * +svn_sqlite__with_transaction(svn_sqlite__db_t *db, + svn_sqlite__transaction_callback_t cb_func, + void *cb_baton, apr_pool_t *scratch_pool); + +/* Like SVN_SQLITE__WITH_TXN(), but takes out a 'RESERVED' lock + immediately, instead of using the default deferred locking scheme. */ +#define SVN_SQLITE__WITH_IMMEDIATE_TXN(expr, db) \ + do { \ + svn_sqlite__db_t *svn_sqlite__db = (db); \ + svn_error_t *svn_sqlite__err; \ + \ + SVN_ERR(svn_sqlite__begin_immediate_transaction(svn_sqlite__db)); \ + svn_sqlite__err = (expr); \ + SVN_ERR(svn_sqlite__finish_transaction(svn_sqlite__db, svn_sqlite__err)); \ + } while (0) + +/* Like svn_sqlite__with_transaction(), but takes out a 'RESERVED' lock + immediately, instead of using the default deferred locking scheme. */ +svn_error_t * +svn_sqlite__with_immediate_transaction(svn_sqlite__db_t *db, + svn_sqlite__transaction_callback_t cb_func, + void *cb_baton, + apr_pool_t *scratch_pool); + +/* Evaluate the expression EXPR within a 'savepoint'. Savepoints can be + * nested. + * + * Begin a savepoint in DB; evaluate the expression EXPR, which would + * typically be a function call that does some work in DB; finally release + * the savepoint if EXPR evaluated to SVN_NO_ERROR, otherwise roll back + * to the savepoint and then release it. + */ +#define SVN_SQLITE__WITH_LOCK(expr, db) \ + do { \ + svn_sqlite__db_t *svn_sqlite__db = (db); \ + svn_error_t *svn_sqlite__err; \ + \ + SVN_ERR(svn_sqlite__begin_savepoint(svn_sqlite__db)); \ + svn_sqlite__err = (expr); \ + SVN_ERR(svn_sqlite__finish_savepoint(svn_sqlite__db, svn_sqlite__err)); \ + } while (0) + +/* Helper function to handle several SQLite operations inside a shared lock. + This callback is similar to svn_sqlite__with_transaction(), but can be + nested (even with a transaction). + + Using this function as a wrapper around a group of operations can give a + *huge* performance boost as the shared-read lock will be shared over + multiple statements, instead of being reobtained every time, which may + require disk and/or network io, depending on SQLite's locking strategy. + + SCRATCH_POOL will be passed to the callback (NULL is valid). + + ### Since we now require SQLite >= 3.6.18, this function has the effect of + always behaving like a defered transaction. Can it be combined with + svn_sqlite__with_transaction()? + */ +svn_error_t * +svn_sqlite__with_lock(svn_sqlite__db_t *db, + svn_sqlite__transaction_callback_t cb_func, + void *cb_baton, + apr_pool_t *scratch_pool); + + +/* Hotcopy an SQLite database from SRC_PATH to DST_PATH. */ +svn_error_t * +svn_sqlite__hotcopy(const char *src_path, + const char *dst_path, + apr_pool_t *scratch_pool); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* SVN_SQLITE_H */ |