mirror of
https://github.com/status-im/sqlcipher.git
synced 2025-02-22 16:58:14 +00:00
sqlcipher_export from attached database to main (2nd parameter specifies source)
This commit is contained in:
parent
867d0dafd5
commit
c566ead72a
44
src/crypto.c
44
src/crypto.c
@ -794,7 +794,8 @@ static int sqlcipher_execExecSql(sqlite3 *db, char **pzErrMsg, const char *zSql)
|
||||
*/
|
||||
void sqlcipher_exportFunc(sqlite3_context *context, int argc, sqlite3_value **argv) {
|
||||
sqlite3 *db = sqlite3_context_db_handle(context);
|
||||
const char* attachedDb = (const char*) sqlite3_value_text(argv[0]);
|
||||
const char* targetDb, *sourceDb;
|
||||
|
||||
int saved_flags; /* Saved value of the db->flags */
|
||||
int saved_nChange; /* Saved value of db->nChange */
|
||||
int saved_nTotalChange; /* Saved value of db->nTotalChange */
|
||||
@ -803,7 +804,16 @@ void sqlcipher_exportFunc(sqlite3_context *context, int argc, sqlite3_value **ar
|
||||
int rc = SQLITE_OK; /* Return code from service routines */
|
||||
char *zSql = NULL; /* SQL statements */
|
||||
char *pzErrMsg = NULL;
|
||||
|
||||
|
||||
if(argc != 1 && argc != 2) {
|
||||
rc = SQLITE_ERROR;
|
||||
pzErrMsg = sqlite3_mprintf("invalid number of arguments (%d) passed to sqlcipher_export", argc);
|
||||
goto end_of_export;
|
||||
}
|
||||
|
||||
targetDb = (const char*) sqlite3_value_text(argv[0]);
|
||||
sourceDb = (argc == 2) ? (char *) sqlite3_value_text(argv[1]) : "main";
|
||||
|
||||
saved_flags = db->flags;
|
||||
saved_nChange = db->nChange;
|
||||
saved_nTotalChange = db->nTotalChange;
|
||||
@ -820,25 +830,25 @@ void sqlcipher_exportFunc(sqlite3_context *context, int argc, sqlite3_value **ar
|
||||
*/
|
||||
zSql = sqlite3_mprintf(
|
||||
"SELECT 'CREATE TABLE %s.' || substr(sql,14) "
|
||||
" FROM sqlite_master WHERE type='table' AND name!='sqlite_sequence'"
|
||||
" FROM %s.sqlite_master WHERE type='table' AND name!='sqlite_sequence'"
|
||||
" AND rootpage>0"
|
||||
, attachedDb);
|
||||
, targetDb, sourceDb);
|
||||
rc = (zSql == NULL) ? SQLITE_NOMEM : sqlcipher_execExecSql(db, &pzErrMsg, zSql);
|
||||
if( rc!=SQLITE_OK ) goto end_of_export;
|
||||
sqlite3_free(zSql);
|
||||
|
||||
zSql = sqlite3_mprintf(
|
||||
"SELECT 'CREATE INDEX %s.' || substr(sql,14)"
|
||||
" FROM sqlite_master WHERE sql LIKE 'CREATE INDEX %%' "
|
||||
, attachedDb);
|
||||
" FROM %s.sqlite_master WHERE sql LIKE 'CREATE INDEX %%' "
|
||||
, targetDb, sourceDb);
|
||||
rc = (zSql == NULL) ? SQLITE_NOMEM : sqlcipher_execExecSql(db, &pzErrMsg, zSql);
|
||||
if( rc!=SQLITE_OK ) goto end_of_export;
|
||||
sqlite3_free(zSql);
|
||||
|
||||
zSql = sqlite3_mprintf(
|
||||
"SELECT 'CREATE UNIQUE INDEX %s.' || substr(sql,21) "
|
||||
" FROM sqlite_master WHERE sql LIKE 'CREATE UNIQUE INDEX %%'"
|
||||
, attachedDb);
|
||||
" FROM %s.sqlite_master WHERE sql LIKE 'CREATE UNIQUE INDEX %%'"
|
||||
, targetDb, sourceDb);
|
||||
rc = (zSql == NULL) ? SQLITE_NOMEM : sqlcipher_execExecSql(db, &pzErrMsg, zSql);
|
||||
if( rc!=SQLITE_OK ) goto end_of_export;
|
||||
sqlite3_free(zSql);
|
||||
@ -849,11 +859,11 @@ void sqlcipher_exportFunc(sqlite3_context *context, int argc, sqlite3_value **ar
|
||||
*/
|
||||
zSql = sqlite3_mprintf(
|
||||
"SELECT 'INSERT INTO %s.' || quote(name) "
|
||||
"|| ' SELECT * FROM main.' || quote(name) || ';'"
|
||||
"FROM main.sqlite_master "
|
||||
"|| ' SELECT * FROM %s.' || quote(name) || ';'"
|
||||
"FROM %s.sqlite_master "
|
||||
"WHERE type = 'table' AND name!='sqlite_sequence' "
|
||||
" AND rootpage>0"
|
||||
, attachedDb);
|
||||
, targetDb, sourceDb, sourceDb);
|
||||
rc = (zSql == NULL) ? SQLITE_NOMEM : sqlcipher_execExecSql(db, &pzErrMsg, zSql);
|
||||
if( rc!=SQLITE_OK ) goto end_of_export;
|
||||
sqlite3_free(zSql);
|
||||
@ -863,16 +873,16 @@ void sqlcipher_exportFunc(sqlite3_context *context, int argc, sqlite3_value **ar
|
||||
zSql = sqlite3_mprintf(
|
||||
"SELECT 'DELETE FROM %s.' || quote(name) || ';' "
|
||||
"FROM %s.sqlite_master WHERE name='sqlite_sequence' "
|
||||
, attachedDb, attachedDb);
|
||||
, targetDb, targetDb);
|
||||
rc = (zSql == NULL) ? SQLITE_NOMEM : sqlcipher_execExecSql(db, &pzErrMsg, zSql);
|
||||
if( rc!=SQLITE_OK ) goto end_of_export;
|
||||
sqlite3_free(zSql);
|
||||
|
||||
zSql = sqlite3_mprintf(
|
||||
"SELECT 'INSERT INTO %s.' || quote(name) "
|
||||
"|| ' SELECT * FROM main.' || quote(name) || ';' "
|
||||
"|| ' SELECT * FROM %s.' || quote(name) || ';' "
|
||||
"FROM %s.sqlite_master WHERE name=='sqlite_sequence';"
|
||||
, attachedDb, attachedDb);
|
||||
, targetDb, sourceDb, targetDb);
|
||||
rc = (zSql == NULL) ? SQLITE_NOMEM : sqlcipher_execExecSql(db, &pzErrMsg, zSql);
|
||||
if( rc!=SQLITE_OK ) goto end_of_export;
|
||||
sqlite3_free(zSql);
|
||||
@ -885,10 +895,10 @@ void sqlcipher_exportFunc(sqlite3_context *context, int argc, sqlite3_value **ar
|
||||
zSql = sqlite3_mprintf(
|
||||
"INSERT INTO %s.sqlite_master "
|
||||
" SELECT type, name, tbl_name, rootpage, sql"
|
||||
" FROM main.sqlite_master"
|
||||
" FROM %s.sqlite_master"
|
||||
" WHERE type='view' OR type='trigger'"
|
||||
" OR (type='table' AND rootpage=0)"
|
||||
, attachedDb);
|
||||
, targetDb, sourceDb);
|
||||
rc = (zSql == NULL) ? SQLITE_NOMEM : sqlcipher_execSql(db, &pzErrMsg, zSql);
|
||||
if( rc!=SQLITE_OK ) goto end_of_export;
|
||||
sqlite3_free(zSql);
|
||||
@ -901,7 +911,7 @@ end_of_export:
|
||||
db->xTrace = saved_xTrace;
|
||||
db->mTrace = saved_mTrace;
|
||||
|
||||
sqlite3_free(zSql);
|
||||
if(zSql) sqlite3_free(zSql);
|
||||
|
||||
if(rc) {
|
||||
if(pzErrMsg != NULL) {
|
||||
|
@ -1801,7 +1801,7 @@ void sqlite3RegisterPerConnectionBuiltinFunctions(sqlite3 *db){
|
||||
/* BEGIN SQLCIPHER */
|
||||
#ifdef SQLITE_HAS_CODEC
|
||||
#ifndef OMIT_EXPORT
|
||||
sqlite3CreateFunc(db, "sqlcipher_export", 1, SQLITE_TEXT, 0, sqlcipher_exportFunc, 0, 0, 0, 0, 0);
|
||||
sqlite3CreateFunc(db, "sqlcipher_export", -1, SQLITE_TEXT, 0, sqlcipher_exportFunc, 0, 0, 0, 0, 0);
|
||||
#endif
|
||||
#endif
|
||||
/* END SQLCIPHER */
|
||||
|
@ -1096,6 +1096,79 @@ db close
|
||||
file delete -force test.db
|
||||
file delete -force test2.db
|
||||
|
||||
# use the sqlcipher_export function
|
||||
# to copy a complicated attached database to the main database
|
||||
do_test export-attached-database {
|
||||
sqlite_orig db test.db
|
||||
|
||||
execsql {
|
||||
PRAGMA key = 'testkey';
|
||||
CREATE TABLE t1(a INTEGER PRIMARY KEY AUTOINCREMENT, b, c);
|
||||
CREATE UNIQUE INDEX b_idx ON t1(b);
|
||||
CREATE INDEX c_idx ON t1(c);
|
||||
|
||||
CREATE TABLE t2(b,c);
|
||||
CREATE TRIGGER t2_after_insert AFTER INSERT ON t2
|
||||
BEGIN
|
||||
INSERT INTO t1(b,c) VALUES (new.b, new.c);
|
||||
END;
|
||||
|
||||
CREATE VIEW v1 AS
|
||||
SELECT c FROM t1;
|
||||
|
||||
CREATE VIRTUAL TABLE fts USING fts5(a,b);
|
||||
|
||||
BEGIN;
|
||||
-- start with one known value
|
||||
INSERT INTO t2 VALUES(1000000,'value 1000000');
|
||||
}
|
||||
|
||||
for {set i 1} {$i<=999} {incr i} {
|
||||
set r [expr {int(rand()*500000)}]
|
||||
execsql "INSERT INTO t2 VALUES($i,'value $r');"
|
||||
}
|
||||
|
||||
execsql {
|
||||
INSERT INTO fts SELECT b,c FROM t1;
|
||||
COMMIT;
|
||||
}
|
||||
db close
|
||||
|
||||
sqlite_orig db test2.db
|
||||
execsql {
|
||||
PRAGMA key = 'testkey2';
|
||||
|
||||
CREATE TABLE t3(a INTEGER PRIMARY KEY AUTOINCREMENT, b, c);
|
||||
CREATE UNIQUE INDEX d_idx ON t3(b);
|
||||
INSERT INTO t3(b,c) VALUES ('one', 'two');
|
||||
|
||||
ATTACH DATABASE 'test.db' AS db KEY 'testkey';
|
||||
|
||||
SELECT sqlcipher_export('main', 'db');
|
||||
|
||||
DETACH DATABASE db;
|
||||
INSERT INTO t3(b,c) VALUES ('three', 'four');
|
||||
}
|
||||
db close
|
||||
|
||||
sqlite_orig db test2.db
|
||||
execsql {
|
||||
PRAGMA key = 'testkey2';
|
||||
SELECT count(*) FROM t1;
|
||||
SELECT count(*) FROM v1;
|
||||
SELECT count(*) FROM sqlite_sequence;
|
||||
SELECT seq FROM sqlite_sequence WHERE name = 't1';
|
||||
INSERT INTO t2 VALUES(10001, 'value 938383');
|
||||
SELECT count(*) FROM t1; -- verify the trigger worked
|
||||
SELECT seq FROM sqlite_sequence WHERE name = 't1'; -- verify that autoincrement worked
|
||||
SELECT a FROM fts WHERE b MATCH '1000000';
|
||||
SELECT count(*) FROM t3;
|
||||
}
|
||||
} {1000 1000 1 1000 1001 1001 1000000 2}
|
||||
db close
|
||||
file delete -force test.db
|
||||
file delete -force test2.db
|
||||
|
||||
# 1. create a database with WAL journal mode
|
||||
# 2. create table and insert operations should work
|
||||
# 3. close database, open it again
|
||||
|
Loading…
x
Reference in New Issue
Block a user