| # 2018-01-02 |
| # |
| # The author disclaims copyright to this source code. In place of |
| # a legal notice, here is a blessing: |
| # |
| # May you do good and not evil. |
| # May you find forgiveness for yourself and forgive others. |
| # May you share freely, never taking more than you give. |
| # |
| #*********************************************************************** |
| # This file implements regression tests for SQLite library. The |
| # focus of this file is the "memdb" VFS |
| # |
| |
| set testdir [file dirname $argv0] |
| source $testdir/tester.tcl |
| set testprefix memdb1 |
| do_not_use_codec |
| |
| ifcapable !deserialize { |
| finish_test |
| return |
| } |
| |
| # Create a MEMDB and populate it with some dummy data. |
| # Then extract the database into the $::db1 variable. |
| # Verify that the size of $::db1 is the same as the size of |
| # the database. |
| # |
| unset -nocomplain db1 |
| unset -nocomplain sz1 |
| unset -nocomplain pgsz |
| do_test 100 { |
| db eval { |
| CREATE TABLE t1(a,b); |
| INSERT INTO t1 VALUES(1,2); |
| } |
| set ::pgsz [db one {PRAGMA page_size}] |
| set ::sz1 [expr {$::pgsz*[db one {PRAGMA page_count}]}] |
| set ::db1 [db serialize] |
| expr {[string length $::db1]==$::sz1} |
| } 1 |
| set fd [open db1.db wb] |
| puts -nonewline $fd $db1 |
| close $fd |
| |
| # Create a new MEMDB and initialize it to the content of $::db1 |
| # Verify that the content is the same. |
| # |
| db close |
| sqlite3 db |
| db deserialize $db1 |
| do_execsql_test 110 { |
| SELECT * FROM t1; |
| } {1 2} |
| |
| # What happens when we try to VACUUM a MEMDB database? |
| # |
| do_execsql_test 120 { |
| PRAGMA auto_vacuum = off; |
| VACUUM; |
| } {} |
| do_execsql_test 130 { |
| CREATE TABLE t2(x, y); |
| WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<100) |
| INSERT INTO t2(x, y) SELECT x, randomblob(1000) FROM c; |
| DROP TABLE t2; |
| PRAGMA page_count; |
| } {116} |
| do_execsql_test 140 { |
| VACUUM; |
| PRAGMA page_count; |
| } {2} |
| |
| do_test 150 { |
| catch {db deserialize -unknown 1 $db1} msg |
| set msg |
| } {unknown option: -unknown} |
| do_test 151 { |
| db deserialize -readonly 1 $db1 |
| db eval {SELECT * FROM t1} |
| } {1 2} |
| do_test 152 { |
| catchsql {INSERT INTO t1 VALUES(3,4);} |
| } {1 {attempt to write a readonly database}} |
| |
| breakpoint |
| do_test 160 { |
| db deserialize -maxsize 32768 $db1 |
| db eval {SELECT * FROM t1} |
| } {1 2} |
| do_test 161 { |
| db eval {INSERT INTO t1 VALUES(3,4); SELECT * FROM t1} |
| } {1 2 3 4} |
| do_test 162 { |
| catchsql {INSERT INTO t1 VALUES(5,randomblob(100000))} |
| } {1 {database or disk is full}} |
| |
| |
| # Build a largish on-disk database and serialize it. Verify that the |
| # serialization works. |
| # |
| db close |
| forcedelete test.db |
| sqlite3 db test.db |
| do_execsql_test 200 { |
| CREATE TABLE t3(x, y); |
| WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<400) |
| INSERT INTO t3(x, y) SELECT x, randomblob(1000) FROM c; |
| PRAGMA quick_check; |
| } {ok} |
| set fd [open test.db rb] |
| unset -nocomplain direct |
| set direct [read $fd] |
| close $fd |
| do_test 210 { |
| string length [db serialize] |
| } [string length $direct] |
| do_test 220 { |
| db eval {ATTACH ':memory:' AS aux1} |
| db deserialize aux1 $::direct |
| db eval { |
| SELECT x, y FROM main.t3 EXCEPT SELECT x, y FROM aux1.t3; |
| } |
| } {} |
| unset -nocomplain direct |
| |
| # Do the same with a :memory: database. |
| # |
| db close |
| sqlite3 db :memory: |
| do_execsql_test 300 { |
| CREATE TABLE t3(x, y); |
| WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<400) |
| INSERT INTO t3(x, y) SELECT x, randomblob(1000) FROM c; |
| PRAGMA quick_check; |
| } {ok} |
| do_test 310 { |
| db eval {ATTACH ':memory:' AS aux1} |
| db deserialize aux1 [db serialize main] |
| db eval { |
| SELECT x, y FROM main.t3 EXCEPT SELECT x, y FROM aux1.t3; |
| } |
| } {} |
| |
| # Deserialize an empty database |
| # |
| db close |
| sqlite3 db |
| db deserialize {} |
| do_execsql_test 400 { |
| PRAGMA integrity_check; |
| } {ok} |
| do_execsql_test 410 { |
| CREATE TABLE t4(a,b); |
| INSERT INTO t4 VALUES('hello','world!'); |
| PRAGMA integrity_check; |
| SELECT * FROM t4; |
| } {ok hello world!} |
| do_execsql_test 420 { |
| PRAGMA journal_mode=TRUNCATE; |
| PRAGMA journal_mode=OFF; |
| PRAGMA journal_mode=DELETE; |
| PRAGMA journal_mode=WAL; |
| PRAGMA journal_mode=PERSIST; |
| PRAGMA journal_mode=MEMORY; |
| PRAGMA journal_mode=OFF; |
| PRAGMA journal_mode=DELETE; |
| } {truncate off delete delete persist memory off delete} |
| |
| # Deserialize something that is not a database. |
| # |
| db close |
| sqlite3 db |
| do_test 500 { |
| set rc [catch {db deserialize not-a-database} msg] |
| lappend rc $msg |
| } {0 {}} |
| do_catchsql_test 510 { |
| PRAGMA integrity_check; |
| } {1 {file is not a database}} |
| |
| # Abuse the serialize and deserialize commands. Make sure errors are caught. |
| # |
| do_test 600 { |
| set rc [catch {db deserialize} msg] |
| lappend rc $msg |
| } {1 {wrong # args: should be "db deserialize ?DATABASE? VALUE"}} |
| do_test 610 { |
| set rc [catch {db deserialize a b c} msg] |
| lappend rc $msg |
| } {1 {unknown option: a}} |
| do_test 620 { |
| set rc [catch {db serialize a b} msg] |
| lappend rc $msg |
| } {1 {wrong # args: should be "db serialize ?DATABASE?"}} |
| |
| # 2021-07-19 https://sqlite.org/forum/forumpost/e1cbb5f450b98aa6 |
| # The TEMP database cannot participate in serialization or |
| # deserialization. |
| # |
| reset_db |
| do_test 650 { |
| db eval { |
| CREATE TEMP TABLE t0(a); |
| CREATE TABLE t1(x); |
| WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<1000) |
| INSERT INTO t1(x) SELECT random() FROM c; |
| } |
| set rc [catch {db deserialize temp [db serialize main]} err] |
| lappend rc err |
| } {1 err} |
| |
| #------------------------------------------------------------------------- |
| ifcapable vtab { |
| reset_db |
| do_execsql_test 700 { |
| CREATE TABLE t1(a, b); |
| PRAGMA schema_version = 0; |
| } |
| do_test 710 { |
| set ser [db serialize main] |
| db close |
| sqlite3 db |
| db deserialize main $ser |
| catchsql { |
| CREATE VIRTUAL TABLE t1 USING rtree(id, a, b, c, d); |
| } |
| } {1 {table t1 already exists}} |
| } |
| |
| |
| #------------------------------------------------------------------------- |
| # dbsqlfuzz 0a13dfb474d4f2f11a48a2ea57075c96fb456dd7 |
| # |
| if {[wal_is_capable]} { |
| reset_db |
| do_execsql_test 800 { |
| PRAGMA auto_vacuum = 0; |
| PRAGMA page_size = 8192; |
| PRAGMA journal_mode = wal; |
| CREATE TABLE t1(x, y); |
| INSERT INTO t1 VALUES(1, 2); |
| CREATE TABLE t2(x, y); |
| } {wal} |
| db close |
| |
| set fd [open test.db] |
| fconfigure $fd -translation binary -encoding binary |
| set data [read $fd [expr 20*1024]] |
| |
| sqlite3 db "" |
| db deserialize $data |
| |
| do_execsql_test 810 { |
| PRAGMA locking_mode = exclusive; |
| SELECT * FROM t1 |
| } {exclusive 1 2} |
| |
| do_execsql_test 820 { |
| INSERT INTO t1 VALUES(3, 4); |
| SELECT * FROM t1; |
| } {1 2 3 4} |
| |
| do_catchsql_test 830 { |
| PRAGMA wal_checkpoint; |
| } {1 {database disk image is malformed}} |
| } |
| |
| finish_test |