drh | ac442f4 | 2018-01-03 01:28:46 +0000 | [diff] [blame] | 1 | # 2018-01-02 |
| 2 | # |
| 3 | # The author disclaims copyright to this source code. In place of |
| 4 | # a legal notice, here is a blessing: |
| 5 | # |
| 6 | # May you do good and not evil. |
| 7 | # May you find forgiveness for yourself and forgive others. |
| 8 | # May you share freely, never taking more than you give. |
| 9 | # |
| 10 | #*********************************************************************** |
| 11 | # This file implements regression tests for SQLite library. The |
| 12 | # focus of this file is the "memdb" VFS |
| 13 | # |
| 14 | |
| 15 | set testdir [file dirname $argv0] |
| 16 | source $testdir/tester.tcl |
| 17 | set testprefix memdb1 |
| 18 | do_not_use_codec |
| 19 | |
drh | 9c6396e | 2018-03-06 21:43:19 +0000 | [diff] [blame] | 20 | ifcapable !deserialize { |
drh | ac442f4 | 2018-01-03 01:28:46 +0000 | [diff] [blame] | 21 | finish_test |
| 22 | return |
| 23 | } |
| 24 | |
| 25 | # Create a MEMDB and populate it with some dummy data. |
| 26 | # Then extract the database into the $::db1 variable. |
| 27 | # Verify that the size of $::db1 is the same as the size of |
| 28 | # the database. |
| 29 | # |
drh | ac442f4 | 2018-01-03 01:28:46 +0000 | [diff] [blame] | 30 | unset -nocomplain db1 |
| 31 | unset -nocomplain sz1 |
| 32 | unset -nocomplain pgsz |
| 33 | do_test 100 { |
| 34 | db eval { |
| 35 | CREATE TABLE t1(a,b); |
| 36 | INSERT INTO t1 VALUES(1,2); |
| 37 | } |
| 38 | set ::pgsz [db one {PRAGMA page_size}] |
| 39 | set ::sz1 [expr {$::pgsz*[db one {PRAGMA page_count}]}] |
drh | cb7d541 | 2018-01-03 16:49:52 +0000 | [diff] [blame] | 40 | set ::db1 [db serialize] |
drh | ac442f4 | 2018-01-03 01:28:46 +0000 | [diff] [blame] | 41 | expr {[string length $::db1]==$::sz1} |
| 42 | } 1 |
drh | cb7d541 | 2018-01-03 16:49:52 +0000 | [diff] [blame] | 43 | set fd [open db1.db wb] |
| 44 | puts -nonewline $fd $db1 |
| 45 | close $fd |
drh | ac442f4 | 2018-01-03 01:28:46 +0000 | [diff] [blame] | 46 | |
| 47 | # Create a new MEMDB and initialize it to the content of $::db1 |
| 48 | # Verify that the content is the same. |
| 49 | # |
| 50 | db close |
drh | 3ec8665 | 2018-01-03 19:03:31 +0000 | [diff] [blame] | 51 | sqlite3 db |
| 52 | db deserialize $db1 |
drh | ac442f4 | 2018-01-03 01:28:46 +0000 | [diff] [blame] | 53 | do_execsql_test 110 { |
| 54 | SELECT * FROM t1; |
| 55 | } {1 2} |
| 56 | |
drh | a5bb435 | 2018-01-03 23:40:02 +0000 | [diff] [blame] | 57 | # What happens when we try to VACUUM a MEMDB database? |
| 58 | # |
| 59 | do_execsql_test 120 { |
dan | d88690b | 2018-03-29 11:02:19 +0000 | [diff] [blame] | 60 | PRAGMA auto_vacuum = off; |
drh | a5bb435 | 2018-01-03 23:40:02 +0000 | [diff] [blame] | 61 | VACUUM; |
| 62 | } {} |
| 63 | do_execsql_test 130 { |
| 64 | CREATE TABLE t2(x, y); |
| 65 | WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<100) |
| 66 | INSERT INTO t2(x, y) SELECT x, randomblob(1000) FROM c; |
| 67 | DROP TABLE t2; |
| 68 | PRAGMA page_count; |
| 69 | } {116} |
| 70 | do_execsql_test 140 { |
| 71 | VACUUM; |
| 72 | PRAGMA page_count; |
| 73 | } {2} |
| 74 | |
drh | 6ca6448 | 2019-01-22 16:06:20 +0000 | [diff] [blame] | 75 | do_test 150 { |
| 76 | catch {db deserialize -unknown 1 $db1} msg |
| 77 | set msg |
| 78 | } {unknown option: -unknown} |
| 79 | do_test 151 { |
| 80 | db deserialize -readonly 1 $db1 |
| 81 | db eval {SELECT * FROM t1} |
| 82 | } {1 2} |
| 83 | do_test 152 { |
| 84 | catchsql {INSERT INTO t1 VALUES(3,4);} |
| 85 | } {1 {attempt to write a readonly database}} |
| 86 | |
| 87 | breakpoint |
| 88 | do_test 160 { |
| 89 | db deserialize -maxsize 32768 $db1 |
| 90 | db eval {SELECT * FROM t1} |
| 91 | } {1 2} |
| 92 | do_test 161 { |
| 93 | db eval {INSERT INTO t1 VALUES(3,4); SELECT * FROM t1} |
| 94 | } {1 2 3 4} |
| 95 | do_test 162 { |
| 96 | catchsql {INSERT INTO t1 VALUES(5,randomblob(100000))} |
| 97 | } {1 {database or disk is full}} |
| 98 | |
| 99 | |
drh | a5bb435 | 2018-01-03 23:40:02 +0000 | [diff] [blame] | 100 | # Build a largish on-disk database and serialize it. Verify that the |
| 101 | # serialization works. |
| 102 | # |
| 103 | db close |
| 104 | forcedelete test.db |
| 105 | sqlite3 db test.db |
| 106 | do_execsql_test 200 { |
| 107 | CREATE TABLE t3(x, y); |
| 108 | WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<400) |
| 109 | INSERT INTO t3(x, y) SELECT x, randomblob(1000) FROM c; |
| 110 | PRAGMA quick_check; |
| 111 | } {ok} |
| 112 | set fd [open test.db rb] |
| 113 | unset -nocomplain direct |
| 114 | set direct [read $fd] |
| 115 | close $fd |
| 116 | do_test 210 { |
| 117 | string length [db serialize] |
| 118 | } [string length $direct] |
| 119 | do_test 220 { |
| 120 | db eval {ATTACH ':memory:' AS aux1} |
| 121 | db deserialize aux1 $::direct |
| 122 | db eval { |
| 123 | SELECT x, y FROM main.t3 EXCEPT SELECT x, y FROM aux1.t3; |
| 124 | } |
| 125 | } {} |
| 126 | unset -nocomplain direct |
| 127 | |
| 128 | # Do the same with a :memory: database. |
| 129 | # |
| 130 | db close |
| 131 | sqlite3 db :memory: |
| 132 | do_execsql_test 300 { |
| 133 | CREATE TABLE t3(x, y); |
| 134 | WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<400) |
| 135 | INSERT INTO t3(x, y) SELECT x, randomblob(1000) FROM c; |
| 136 | PRAGMA quick_check; |
| 137 | } {ok} |
| 138 | do_test 310 { |
| 139 | db eval {ATTACH ':memory:' AS aux1} |
| 140 | db deserialize aux1 [db serialize main] |
| 141 | db eval { |
| 142 | SELECT x, y FROM main.t3 EXCEPT SELECT x, y FROM aux1.t3; |
| 143 | } |
| 144 | } {} |
| 145 | |
| 146 | # Deserialize an empty database |
| 147 | # |
| 148 | db close |
| 149 | sqlite3 db |
| 150 | db deserialize {} |
| 151 | do_execsql_test 400 { |
| 152 | PRAGMA integrity_check; |
| 153 | } {ok} |
| 154 | do_execsql_test 410 { |
| 155 | CREATE TABLE t4(a,b); |
| 156 | INSERT INTO t4 VALUES('hello','world!'); |
| 157 | PRAGMA integrity_check; |
| 158 | SELECT * FROM t4; |
| 159 | } {ok hello world!} |
drh | d5e7fff | 2021-04-05 13:41:42 +0000 | [diff] [blame] | 160 | do_execsql_test 420 { |
| 161 | PRAGMA journal_mode=TRUNCATE; |
| 162 | PRAGMA journal_mode=OFF; |
| 163 | PRAGMA journal_mode=DELETE; |
| 164 | PRAGMA journal_mode=WAL; |
| 165 | PRAGMA journal_mode=PERSIST; |
| 166 | PRAGMA journal_mode=MEMORY; |
| 167 | PRAGMA journal_mode=OFF; |
| 168 | PRAGMA journal_mode=DELETE; |
| 169 | } {truncate off delete delete persist memory off delete} |
drh | a5bb435 | 2018-01-03 23:40:02 +0000 | [diff] [blame] | 170 | |
| 171 | # Deserialize something that is not a database. |
| 172 | # |
| 173 | db close |
| 174 | sqlite3 db |
| 175 | do_test 500 { |
| 176 | set rc [catch {db deserialize not-a-database} msg] |
| 177 | lappend rc $msg |
| 178 | } {0 {}} |
| 179 | do_catchsql_test 510 { |
| 180 | PRAGMA integrity_check; |
| 181 | } {1 {file is not a database}} |
| 182 | |
| 183 | # Abuse the serialize and deserialize commands. Make sure errors are caught. |
| 184 | # |
| 185 | do_test 600 { |
| 186 | set rc [catch {db deserialize} msg] |
| 187 | lappend rc $msg |
| 188 | } {1 {wrong # args: should be "db deserialize ?DATABASE? VALUE"}} |
| 189 | do_test 610 { |
| 190 | set rc [catch {db deserialize a b c} msg] |
| 191 | lappend rc $msg |
drh | 6ca6448 | 2019-01-22 16:06:20 +0000 | [diff] [blame] | 192 | } {1 {unknown option: a}} |
drh | a5bb435 | 2018-01-03 23:40:02 +0000 | [diff] [blame] | 193 | do_test 620 { |
| 194 | set rc [catch {db serialize a b} msg] |
| 195 | lappend rc $msg |
| 196 | } {1 {wrong # args: should be "db serialize ?DATABASE?"}} |
drh | ac442f4 | 2018-01-03 01:28:46 +0000 | [diff] [blame] | 197 | |
dan | fcb0242 | 2019-03-13 11:40:30 +0000 | [diff] [blame] | 198 | #------------------------------------------------------------------------- |
dan | 150dfbd | 2019-04-12 12:10:03 +0000 | [diff] [blame] | 199 | ifcapable vtab { |
| 200 | reset_db |
| 201 | do_execsql_test 700 { |
| 202 | CREATE TABLE t1(a, b); |
| 203 | PRAGMA schema_version = 0; |
dan | fcb0242 | 2019-03-13 11:40:30 +0000 | [diff] [blame] | 204 | } |
dan | 150dfbd | 2019-04-12 12:10:03 +0000 | [diff] [blame] | 205 | do_test 710 { |
| 206 | set ser [db serialize main] |
| 207 | db close |
| 208 | sqlite3 db |
| 209 | db deserialize main $ser |
| 210 | catchsql { |
| 211 | CREATE VIRTUAL TABLE t1 USING rtree(id, a, b, c, d); |
| 212 | } |
| 213 | } {1 {table t1 already exists}} |
| 214 | } |
dan | fcb0242 | 2019-03-13 11:40:30 +0000 | [diff] [blame] | 215 | |
drh | ac442f4 | 2018-01-03 01:28:46 +0000 | [diff] [blame] | 216 | finish_test |