Skip to content

Commit 0acf2e7

Browse files
committed
improves sqlcipher_export to resolve sqlcipher#310
1 parent 9dd168c commit 0acf2e7

File tree

2 files changed

+60
-20
lines changed

2 files changed

+60
-20
lines changed

src/crypto.c

Lines changed: 23 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1016,8 +1016,9 @@ static int sqlcipher_execExecSql(sqlite3 *db, char **pzErrMsg, const char *zSql)
10161016
void sqlcipher_exportFunc(sqlite3_context *context, int argc, sqlite3_value **argv) {
10171017
sqlite3 *db = sqlite3_context_db_handle(context);
10181018
const char* targetDb, *sourceDb;
1019-
1020-
int saved_flags = db->flags; /* Saved value of the db->flags */
1019+
int targetDb_idx = 0;
1020+
u64 saved_flags = db->flags; /* Saved value of the db->flags */
1021+
u32 saved_mDbFlags = db->mDbFlags; /* Saved value of the db->mDbFlags */
10211022
int saved_nChange = db->nChange; /* Saved value of db->nChange */
10221023
int saved_nTotalChange = db->nTotalChange; /* Saved value of db->nTotalChange */
10231024
u8 saved_mTrace = db->mTrace; /* Saved value of db->mTrace */
@@ -1035,36 +1036,46 @@ void sqlcipher_exportFunc(sqlite3_context *context, int argc, sqlite3_value **ar
10351036
targetDb = (const char*) sqlite3_value_text(argv[0]);
10361037
sourceDb = (argc == 2) ? (char *) sqlite3_value_text(argv[1]) : "main";
10371038

1039+
/* if the name of the target is not main, but the index returned is zero
1040+
there is a mismatch and we should not proceed */
1041+
targetDb_idx = sqlcipher_find_db_index(db, targetDb);
1042+
if(targetDb_idx == 0 && sqlite3StrICmp("main", targetDb) != 0) {
1043+
rc = SQLITE_ERROR;
1044+
pzErrMsg = sqlite3_mprintf("unknown database %s", targetDb);
1045+
goto end_of_export;
1046+
}
1047+
db->init.iDb = targetDb_idx;
1048+
10381049
db->flags |= SQLITE_WriteSchema | SQLITE_IgnoreChecks;
10391050
db->mDbFlags |= DBFLAG_PreferBuiltin | DBFLAG_Vacuum;
1040-
db->flags &= ~(SQLITE_ForeignKeys | SQLITE_ReverseOrder);
1051+
db->flags &= ~(u64)(SQLITE_ForeignKeys | SQLITE_ReverseOrder | SQLITE_Defensive | SQLITE_CountRows);
10411052
db->xTrace = 0;
10421053
db->mTrace = 0;
10431054

10441055
/* Query the schema of the main database. Create a mirror schema
10451056
** in the temporary database.
10461057
*/
10471058
zSql = sqlite3_mprintf(
1048-
"SELECT 'CREATE TABLE %s.' || substr(sql,14) "
1059+
"SELECT sql "
10491060
" FROM %s.sqlite_master WHERE type='table' AND name!='sqlite_sequence'"
10501061
" AND rootpage>0"
1051-
, targetDb, sourceDb);
1062+
, sourceDb);
10521063
rc = (zSql == NULL) ? SQLITE_NOMEM : sqlcipher_execExecSql(db, &pzErrMsg, zSql);
10531064
if( rc!=SQLITE_OK ) goto end_of_export;
10541065
sqlite3_free(zSql);
10551066

10561067
zSql = sqlite3_mprintf(
1057-
"SELECT 'CREATE INDEX %s.' || substr(sql,14)"
1068+
"SELECT sql "
10581069
" FROM %s.sqlite_master WHERE sql LIKE 'CREATE INDEX %%' "
1059-
, targetDb, sourceDb);
1070+
, sourceDb);
10601071
rc = (zSql == NULL) ? SQLITE_NOMEM : sqlcipher_execExecSql(db, &pzErrMsg, zSql);
10611072
if( rc!=SQLITE_OK ) goto end_of_export;
10621073
sqlite3_free(zSql);
10631074

10641075
zSql = sqlite3_mprintf(
1065-
"SELECT 'CREATE UNIQUE INDEX %s.' || substr(sql,21) "
1076+
"SELECT sql "
10661077
" FROM %s.sqlite_master WHERE sql LIKE 'CREATE UNIQUE INDEX %%'"
1067-
, targetDb, sourceDb);
1078+
, sourceDb);
10681079
rc = (zSql == NULL) ? SQLITE_NOMEM : sqlcipher_execExecSql(db, &pzErrMsg, zSql);
10691080
if( rc!=SQLITE_OK ) goto end_of_export;
10701081
sqlite3_free(zSql);
@@ -1084,16 +1095,8 @@ void sqlcipher_exportFunc(sqlite3_context *context, int argc, sqlite3_value **ar
10841095
if( rc!=SQLITE_OK ) goto end_of_export;
10851096
sqlite3_free(zSql);
10861097

1087-
/* Copy over the sequence table
1098+
/* Copy over the contents of the sequence table
10881099
*/
1089-
zSql = sqlite3_mprintf(
1090-
"SELECT 'DELETE FROM %s.' || quote(name) || ';' "
1091-
"FROM %s.sqlite_master WHERE name='sqlite_sequence' "
1092-
, targetDb, targetDb);
1093-
rc = (zSql == NULL) ? SQLITE_NOMEM : sqlcipher_execExecSql(db, &pzErrMsg, zSql);
1094-
if( rc!=SQLITE_OK ) goto end_of_export;
1095-
sqlite3_free(zSql);
1096-
10971100
zSql = sqlite3_mprintf(
10981101
"SELECT 'INSERT INTO %s.' || quote(name) "
10991102
"|| ' SELECT * FROM %s.' || quote(name) || ';' "
@@ -1121,7 +1124,9 @@ void sqlcipher_exportFunc(sqlite3_context *context, int argc, sqlite3_value **ar
11211124

11221125
zSql = NULL;
11231126
end_of_export:
1127+
db->init.iDb = 0;
11241128
db->flags = saved_flags;
1129+
db->mDbFlags = saved_mDbFlags;
11251130
db->nChange = saved_nChange;
11261131
db->nTotalChange = saved_nTotalChange;
11271132
db->xTrace = saved_xTrace;

test/sqlcipher-compatibility.test

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,41 @@ db close
228228
file delete -force test.db
229229
file delete -force test2.db
230230

231+
do_test unencrypted-corrupt-to-encrypted-export {
232+
sqlite_orig db test.db
233+
234+
execsql {
235+
CREATE TABLE t1(a,b);
236+
INSERT INTO t1 VALUES (1,2);
237+
238+
PRAGMA writable_schema = ON;
239+
240+
UPDATE sqlite_master SET sql = 'CREATE TABLE IF NOT EXISTS t1(a,b)'
241+
WHERE tbl_name = 't1';
242+
243+
PRAGMA writable_schema = OFF;
244+
INSERT INTO t1 VALUES (3,4);
245+
246+
SELECT * FROM t1;
247+
248+
ATTACH DATABASE 'test2.db' AS test2 KEY 'testkey2';
249+
250+
SELECT sqlcipher_export('test2');
251+
}
252+
db close
253+
254+
sqlite_orig db test2.db
255+
execsql {
256+
PRAGMA key = 'testkey2';
257+
SELECT count(*) FROM sqlite_master;
258+
SELECT count(*) FROM t1;
259+
}
260+
} {1 2}
261+
db close
262+
file delete -force test.db
263+
file delete -force test2.db
264+
265+
231266
# create an encrypted database, attach an unencrypted database
232267
# with data in it, then import the data back into the encrypted DB
233268
# and verify
@@ -520,7 +555,7 @@ do_test export-attached-database {
520555
CREATE TABLE t3(a INTEGER PRIMARY KEY AUTOINCREMENT, b, c);
521556
CREATE UNIQUE INDEX d_idx ON t3(b);
522557
INSERT INTO t3(b,c) VALUES ('one', 'two');
523-
558+
524559
ATTACH DATABASE 'test.db' AS db KEY 'testkey';
525560

526561
SELECT sqlcipher_export('main', 'db');
@@ -543,7 +578,7 @@ do_test export-attached-database {
543578
SELECT a FROM fts WHERE b MATCH '1000000';
544579
SELECT count(*) FROM t3;
545580
}
546-
} {1000 1000 1 1000 1001 1001 1000000 2}
581+
} {1000 1000 2 1000 1001 1001 1000000 2}
547582
db close
548583
file delete -force test.db
549584
file delete -force test2.db

0 commit comments

Comments
 (0)