Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Changes In Branch reuse-schema Excluding Merge-Ins
This is equivalent to a diff from 4484ec6d26 to e556f3d381
2024-04-06
| ||
17:37 | Improvements to the accurancy of the fuzzinvariants.c testing module when SQLITE_ALLOW_ROWID_IN_VIEW is defined and the test query involves rowids. (check-in: c6e873d4db user: drh tags: trunk) | |
2024-04-05
| ||
20:01 | Experimental enhancement in which expressions of the form "expr IN table" can be pushed down into subexpressions. (check-in: 2cbd7838fd user: drh tags: pushdown-IN-table) | |
15:04 | Merge all recent trunk enhancements into the reuse-schema branch. (Leaf check-in: e556f3d381 user: drh tags: reuse-schema) | |
14:50 | Merge the latest trunk enhancements into the wal2 branch. (check-in: a8a8a2db9b user: drh tags: wal2) | |
14:46 | Merge the latest trunk enhancements into the begin-concurrent branch. (check-in: 4ff8334241 user: drh tags: begin-concurrent) | |
14:13 | Check-in a9657c87c53c1922 is wrong: the IndexedExpr.bMaybeNullRow flag is required for virtual columns if they are part of an outer join. Add a test case to prove it. (check-in: 083b0f7e77 user: drh tags: branch-3.44) | |
14:06 | Fix obscure issues associated with SQLITE_ALLOW_ROWID_IN_VIEW and indexes on virtual columns in a RIGHT JOIN. (check-in: 4b3a253fc7 user: drh tags: branch-3.45) | |
13:56 | Check-in [a9657c87c53c1922] is wrong: the IndexedExpr.bMaybeNullRow flag is required for virtual columns if they are part of an outer join. Add a test case (derived from dbsqlfuzz b9e65e2f110df998f1306571fae7af6c01e4d92b) to prove it. (check-in: 4484ec6d26 user: drh tags: trunk) | |
11:23 | When compiling with SQLITE_ALLOW_ROWID_IN_VIEW, if the RETURNING clause of an UPDATE of a view specifies a rowid, then return NULL for the value of that rowid. dbsqlfuzz 7863696e9e5ec10b29bcf5ab2681cd6c82a78a4a. (check-in: c7896e8885 user: drh tags: trunk) | |
2024-03-26
| ||
10:48 | Merge all recent trunk enhancements into the reuse-schema branch. (check-in: e469b02205 user: drh tags: reuse-schema) | |
2022-10-20
| ||
16:12 | Only enable the bMaybeNullRow flag on IndexedExpr for an index on an expression, not on a virtual column. But do enable it for the right operand of a right join. (check-in: a9657c87c5 user: drh tags: trunk) | |
Changes to Makefile.in.
︙ | ︙ | |||
398 399 400 401 402 403 404 405 406 407 408 409 410 411 | $(TOP)/src/test_mutex.c \ $(TOP)/src/test_onefile.c \ $(TOP)/src/test_osinst.c \ $(TOP)/src/test_pcache.c \ $(TOP)/src/test_quota.c \ $(TOP)/src/test_rtree.c \ $(TOP)/src/test_schema.c \ $(TOP)/src/test_superlock.c \ $(TOP)/src/test_syscall.c \ $(TOP)/src/test_tclsh.c \ $(TOP)/src/test_tclvar.c \ $(TOP)/src/test_thread.c \ $(TOP)/src/test_vdbecov.c \ $(TOP)/src/test_vfs.c \ | > | 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 | $(TOP)/src/test_mutex.c \ $(TOP)/src/test_onefile.c \ $(TOP)/src/test_osinst.c \ $(TOP)/src/test_pcache.c \ $(TOP)/src/test_quota.c \ $(TOP)/src/test_rtree.c \ $(TOP)/src/test_schema.c \ $(TOP)/src/test_schemapool.c \ $(TOP)/src/test_superlock.c \ $(TOP)/src/test_syscall.c \ $(TOP)/src/test_tclsh.c \ $(TOP)/src/test_tclvar.c \ $(TOP)/src/test_thread.c \ $(TOP)/src/test_vdbecov.c \ $(TOP)/src/test_vfs.c \ |
︙ | ︙ | |||
465 466 467 468 469 470 471 472 473 474 475 476 477 478 | # TESTSRC2 = \ $(TOP)/src/attach.c \ $(TOP)/src/backup.c \ $(TOP)/src/bitvec.c \ $(TOP)/src/btree.c \ $(TOP)/src/build.c \ $(TOP)/src/ctime.c \ $(TOP)/src/date.c \ $(TOP)/src/dbpage.c \ $(TOP)/src/dbstat.c \ $(TOP)/src/expr.c \ $(TOP)/src/func.c \ $(TOP)/src/global.c \ | > | 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 | # TESTSRC2 = \ $(TOP)/src/attach.c \ $(TOP)/src/backup.c \ $(TOP)/src/bitvec.c \ $(TOP)/src/btree.c \ $(TOP)/src/build.c \ $(TOP)/src/callback.c \ $(TOP)/src/ctime.c \ $(TOP)/src/date.c \ $(TOP)/src/dbpage.c \ $(TOP)/src/dbstat.c \ $(TOP)/src/expr.c \ $(TOP)/src/func.c \ $(TOP)/src/global.c \ |
︙ | ︙ |
Changes to Makefile.msc.
︙ | ︙ | |||
1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 | $(TOP)\src\test_mutex.c \ $(TOP)\src\test_onefile.c \ $(TOP)\src\test_osinst.c \ $(TOP)\src\test_pcache.c \ $(TOP)\src\test_quota.c \ $(TOP)\src\test_rtree.c \ $(TOP)\src\test_schema.c \ $(TOP)\src\test_superlock.c \ $(TOP)\src\test_syscall.c \ $(TOP)\src\test_tclsh.c \ $(TOP)\src\test_tclvar.c \ $(TOP)\src\test_thread.c \ $(TOP)\src\test_vdbecov.c \ $(TOP)\src\test_vfs.c \ | > | 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 | $(TOP)\src\test_mutex.c \ $(TOP)\src\test_onefile.c \ $(TOP)\src\test_osinst.c \ $(TOP)\src\test_pcache.c \ $(TOP)\src\test_quota.c \ $(TOP)\src\test_rtree.c \ $(TOP)\src\test_schema.c \ $(TOP)\src\test_schemapool.c \ $(TOP)\src\test_superlock.c \ $(TOP)\src\test_syscall.c \ $(TOP)\src\test_tclsh.c \ $(TOP)\src\test_tclvar.c \ $(TOP)\src\test_thread.c \ $(TOP)\src\test_vdbecov.c \ $(TOP)\src\test_vfs.c \ |
︙ | ︙ |
Added doc/shared_schema.md.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 | Shared-Schema Mode Notes ======================== The [reuse-schema](/timeline?r=reuse-schema) branch contains changes to allow SQLite connections to share schemas between database connections within the same process in order to save memory. Schemas may be shared between multiple databases attached to the same or distinct connection handles. Compile with -DSQLITE\_ENABLE\_SHARED\_SCHEMA in order to enable the shared-schema enhancement. Enabling the shared-schema enhancement causes approximately a 0.1% increase in CPU cycles consumed and about a 3000-byte increase in the size of the library, even if shared-schema is never used. Assuming the compile-time requirements are satisfied, the shared-schema feature is engaged by opening the database connection using the sqlite3_open_v2() API with the SQLITE_OPEN_SHARED_SCHEMA flag specified. The main database and any attached databases will then share an in-memory Schema object with any other database opened within the process for which: * the contents of the sqlite_master table, including all object names, SQL statements and root pages are identical, and * have the same values for the schema-cookie. Temp databases (those populated with "CREATE TEMP TABLE" and similar statements) never share schemas. Connections opened with the SQLITE_OPEN_SHARED_SCHEMA flag specified may not modify any database schema except that belonging to the temp database in anyway. This includes creating or dropping database objects, vacuuming the database, or running ANALYZE when the sqlite_stat\[14\] tables do not exist. For SQLITE_OPEN_SHARED_SCHEMA connections, the SQLITE_DBSTATUS_SCHEMA_USED sqlite3_db_status() verb distributes the memory used for a shared schema object evenly between all database connections that share it. ## The ".shared-schema" Command The shell tool on this branch contains a special dot-command to help with managing databases. The ".shared-schema" dot-command can be used to test whether or not two databases are similar enough to share in-memory schemas, and to fix minor problems that prevent them from doing so. To test if two or more database are compatible, one database is opened directly using the shell tool and the following command issued: .shared-schema check <database-1> [<database-2>]... where <database-1> etc. are replaced with the names of database files on disk. For each database specified on the command line, a single line of output is produced. If the database can share an in-memory schema with the main database opened by the shell tool, the output is of the form: <database> is compatible Otherwise, if the database cannot share a schema with the main db, the output is of the form: <database> is NOT compatible (<reason>) where <reason> indicates the cause of the incompatibility. <reason> is always one of the following. <ul> <li> <b>objects</b> - the databases contain a different set schema objects (tables, indexes, views and triggers). <li> <b>SQL</b> - the databases contain the same set of objects, but the SQL statements used to create them were not the same. <li> <b>root pages</b> - the databases contain the same set of objects created by the same SQL statements, but the root pages are not the same. <li> <b>order of sqlite_master rows</b> - the databases contain the same set of objects created by the same SQL statements with the same root pages, but the order of the rows in the sqlite_master tables are different. <li> <b>schema cookie</b> - the database schemas are compatible, but the schema cookie values ("PRAGMA schema_version") are different. </ul> The final three problems in the list above can be fixed using the .shared-schema command. To modify such a database so that it can share a schema with the main database, the following shell command is used: .shared-schema fix <database-1> [<database-2>]... If a database can be modified so that it may share a schema with the main database opened by the shell tool, output is as follows: Fixing <database>... <database> is compatible If a database does not require modification, or cannot be modified such that it can share a schema with the main database, the output of "fix" is identical to that of the "check" command. ## Implementation Notes A single Schema object is never used by more than one database simultaneously, regardless of whether or not those databases are attached to the same or different database handles. Instead, a pool of schema objects is maintained for each unique sqlite_master-contents/schema-cookie combination opened within the process. Each time database schemas are required by a connection, for example as part of an sqlite3_prepare\*(), sqlite3_blob_open() or sqlite3_blob_open() call, it obtains the minimum number of schemas required from the various schema-pools, returning them at the end of the call. This means that a single schema-pool only ever contains more than one copy of the schema if: * Two threads require schemas from the same pool at the same time, or * A single sqlite3_prepare\*() call requires schemas for two or more attached databases that use the same schema-pool. The size of a schema-pool never shrinks. Each schema pool always maintains a number of schema objects equal to the highwater mark of schema objects simultaneously required by clients. This approach is preferred to allowing multiple databases to use the same Schema object simultaneously for three reasons: * The Schema object is not completely read-only. For example, the Index.zIdxAff string is allocated lazily. * Throughout the statement compiler, SQLite uses variables like Table.pSchema and Index.pSchema with the sqlite3SchemaToIndex() routine in order to determine which attached database a Table or Index object resides in. This mechanism does not work if the same Schema may be used by two or more attached databases. * It may be easier to modify this approach in order to allow SQLITE_OPEN_SHARED_SCHEMA connections to modify database schemas, should that be required. SQLITE_OPEN_SHARED_SCHEMA connections do not store their virtual-table handles in the Table.pVTable list of each table. This would not work, as (a) there is no guarantee that a connection will be assigned the same Schema object each time it requests one from a schema-pool and (b) a single Schema (and therefore Table) object may correspond to tables in two or more databases attached to a single connection. Instead, all virtual-table handles associated with a single database are stored in a linked-list headed at Db.pVTable. |
Added ext/wasm/EXPORTED_FUNCTIONS.fiddle.
> > > > > > > | 1 2 3 4 5 6 7 | _fiddle_exec _fiddle_interrupt _fiddle_experiment _fiddle_the_db _fiddle_db_arg _fiddle_db_filename _fiddle_reset_db |
Deleted ext/wasm/EXPORTED_FUNCTIONS.fiddle.in.
|
| < < < < < < < < < < |
Changes to ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-api.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < | < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 | _sqlite3_bind_blob _sqlite3_bind_double _sqlite3_bind_int _sqlite3_bind_int64 _sqlite3_bind_null _sqlite3_bind_parameter_count _sqlite3_bind_parameter_index _sqlite3_bind_text _sqlite3_changes _sqlite3_changes64 _sqlite3_clear_bindings _sqlite3_close_v2 _sqlite3_column_blob _sqlite3_column_bytes _sqlite3_column_count _sqlite3_column_count _sqlite3_column_double _sqlite3_column_int _sqlite3_column_int64 _sqlite3_column_name _sqlite3_column_text _sqlite3_column_type _sqlite3_compileoption_get _sqlite3_compileoption_used _sqlite3_create_function_v2 _sqlite3_data_count _sqlite3_db_filename _sqlite3_db_name _sqlite3_errmsg _sqlite3_error_offset _sqlite3_errstr _sqlite3_exec _sqlite3_expanded_sql _sqlite3_extended_errcode _sqlite3_extended_result_codes _sqlite3_finalize _sqlite3_initialize _sqlite3_interrupt _sqlite3_libversion _sqlite3_libversion_number _sqlite3_open _sqlite3_open_v2 _sqlite3_prepare_v2 _sqlite3_prepare_v3 _sqlite3_reset _sqlite3_result_blob _sqlite3_result_double _sqlite3_result_error _sqlite3_result_error_code _sqlite3_result_error_nomem _sqlite3_result_error_toobig _sqlite3_result_int _sqlite3_result_null _sqlite3_result_text _sqlite3_sourceid _sqlite3_sql _sqlite3_step _sqlite3_strglob _sqlite3_strlike _sqlite3_total_changes _sqlite3_total_changes64 _sqlite3_value_blob _sqlite3_value_bytes _sqlite3_value_double _sqlite3_value_text _sqlite3_value_type _sqlite3_vfs_find _sqlite3_vfs_register _sqlite3_wasm_db_error _sqlite3_wasm_enum_json _malloc _free |
Changes to ext/wasm/api/sqlite3-worker1-promiser.c-pp.js.
|
| < | 1 2 3 4 5 6 7 | /* 2022-08-24 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. |
︙ | ︙ | |||
38 39 40 41 42 43 44 | config option may alternately be a function, in which case this function re-assigns this property with the result of calling that function, enabling delayed instantiation of a Worker. - `onready` (optional, but...): this callback is called with no arguments when the worker fires its initial 'sqlite3-api'/'worker1-ready' message, which it does when | | | | < < < < | 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | config option may alternately be a function, in which case this function re-assigns this property with the result of calling that function, enabling delayed instantiation of a Worker. - `onready` (optional, but...): this callback is called with no arguments when the worker fires its initial 'sqlite3-api'/'worker1-ready' message, which it does when sqlite3.initWorker1API() completes its initialization. This is the simplest way to tell the worker to kick off work at the earliest opportunity. - `onunhandled` (optional): a callback which gets passed the message event object for any worker.onmessage() events which are not handled by this proxy. Ideally that "should" never happen, as this proxy aims to handle all known message types. - `generateMessageId` (optional): a function which, when passed an |
︙ | ︙ | |||
115 116 117 118 119 120 121 | columnNames: array} Where `typeString` is an internally-synthesized message type string used temporarily for worker message dispatching. It can be ignored by all client code except that which tests this API. The `row` property contains the row result in the form implied by the `rowMode` option (defaulting to `'array'`). The `rowNumber` is a | | < < < < < < < < < | | 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 | columnNames: array} Where `typeString` is an internally-synthesized message type string used temporarily for worker message dispatching. It can be ignored by all client code except that which tests this API. The `row` property contains the row result in the form implied by the `rowMode` option (defaulting to `'array'`). The `rowNumber` is a 1-based integer value incremented by 1 on each call into th callback. At the end of the result set, the same event is fired with (row=undefined, rowNumber=null) to indicate that the end of the result set has been reached. Note that the rows arrive via worker-posted messages, with all the implications of that. */ self.sqlite3Worker1Promiser = function callee(config = callee.defaultConfig){ // Inspired by: https://stackoverflow.com/a/52439530 if(1===arguments.length && 'function'===typeof arguments[0]){ const f = config; config = Object.assign(Object.create(null), callee.defaultConfig); config.onready = f; }else{ config = Object.assign(Object.create(null), callee.defaultConfig, config); |
︙ | ︙ | |||
156 157 158 159 160 161 162 | const genMsgId = config.generateMessageId || function(msg){ return msg.type+'#'+(idTypeMap[msg.type] = (idTypeMap[msg.type]||0) + 1); }; const toss = (...args)=>{throw new Error(args.join(' '))}; if(!config.worker) config.worker = callee.defaultConfig.worker; if('function'===typeof config.worker) config.worker = config.worker(); let dbId; | < | | | 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 | const genMsgId = config.generateMessageId || function(msg){ return msg.type+'#'+(idTypeMap[msg.type] = (idTypeMap[msg.type]||0) + 1); }; const toss = (...args)=>{throw new Error(args.join(' '))}; if(!config.worker) config.worker = callee.defaultConfig.worker; if('function'===typeof config.worker) config.worker = config.worker(); let dbId; config.worker.onmessage = function(ev){ ev = ev.data; debug('worker1.onmessage',ev); let msgHandler = handlerMap[ev.messageId]; if(!msgHandler){ if(ev && 'sqlite3-api'===ev.type && 'worker1-ready'===ev.result) { /*fired one time when the Worker1 API initializes*/ if(config.onready) config.onready(); return; } msgHandler = handlerMap[ev.type] /* check for exec per-row callback */; if(msgHandler && msgHandler.onrow){ msgHandler.onrow(ev); return; } if(config.onunhandled) config.onunhandled(arguments[0]); else err("sqlite3Worker1Promiser() unhandled worker message:",ev); return; } delete handlerMap[ev.messageId]; switch(ev.type){ case 'error': |
︙ | ︙ | |||
193 194 195 196 197 198 199 | break; default: break; } try {msgHandler.resolve(ev)} catch(e){msgHandler.reject(e)} }/*worker.onmessage()*/; | | | | | < > | | 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 | break; default: break; } try {msgHandler.resolve(ev)} catch(e){msgHandler.reject(e)} }/*worker.onmessage()*/; return function(/*(msgType, msgArgs) || (msgEnvelope)*/){ let msg; if(1===arguments.length){ msg = arguments[0]; }else if(2===arguments.length){ msg = { type: arguments[0], args: arguments[1] }; }else{ toss("Invalid arugments for sqlite3Worker1Promiser()-created factory."); } if(!msg.dbId) msg.dbId = dbId; msg.messageId = genMsgId(msg); msg.departureTime = performance.now(); const proxy = Object.create(null); proxy.message = msg; let rowCallbackId /* message handler ID for exec on-row callback proxy */; if('exec'===msg.type && msg.args){ if('function'===typeof msg.args.callback){ |
︙ | ︙ | |||
247 248 249 250 251 252 253 | debug("Posting",msg.type,"message to Worker dbId="+(dbId||'default')+':',msg); config.worker.postMessage(msg); }); if(rowCallbackId) p = p.finally(()=>delete handlerMap[rowCallbackId]); return p; }; }/*sqlite3Worker1Promiser()*/; | < | | | < < | | | | < < | | | < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 | debug("Posting",msg.type,"message to Worker dbId="+(dbId||'default')+':',msg); config.worker.postMessage(msg); }); if(rowCallbackId) p = p.finally(()=>delete handlerMap[rowCallbackId]); return p; }; }/*sqlite3Worker1Promiser()*/; self.sqlite3Worker1Promiser.defaultConfig = { worker: function(){ //#if target=es6-bundler-friendly return new Worker("sqlite3-worker1.js"); //#else let theJs = "sqlite3-worker1.js"; if(this.currentScript){ const src = this.currentScript.src.split('/'); src.pop(); theJs = src.join('/')+'/' + theJs; //sqlite3.config.warn("promiser currentScript, theJs =",this.currentScript,theJs); }else{ //sqlite3.config.warn("promiser self.location =",self.location); const urlParams = new URL(self.location.href).searchParams; if(urlParams.has('sqlite3.dir')){ theJs = urlParams.get('sqlite3.dir') + '/' + theJs; } } return new Worker(theJs + self.location.search); //#endif }.bind({ currentScript: self?.document?.currentScript }), onerror: (...args)=>console.error('worker1 promiser error',...args) }; |
Added ext/wasm/fiddle/fiddle.html.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 | <!doctype html> <html lang="en-us"> <head> <meta charset="utf-8"> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <title>SQLite3 Fiddle</title> <link rel="shortcut icon" href="data:image/x-icon;," type="image/x-icon"> <!-- to add a togglable terminal-style view, uncomment the following two lines and ensure that these files are on the web server. --> <!--script src="jqterm/jqterm-bundle.min.js"></script> <link rel="stylesheet" href="jqterm/jquery.terminal.min.css"/--> <link rel="stylesheet" href="emscripten.css"/> <style> /* The following styles are for app-level use. */ :root { --sqlite-blue: #044a64; --textarea-color1: #044a64; --textarea-color2: white; } textarea { font-family: monospace; flex: 1 1 auto; background-color: var(--textarea-color1); color: var(--textarea-color2); } textarea#input { color: var(--textarea-color1); background-color: var(--textarea-color2); } header { display: flex; justify-content: space-between; align-items: center; background-color: var(--sqlite-blue); color: white; font-size: 120%; font-weight: bold; border-radius: 0.25em; padding: 0.2em 0.5em; } header > .powered-by { font-size: 80%; } header a, header a:visited, header a:hover { color: inherit; } #main-wrapper { display: flex; flex-direction: column-reverse; flex: 1 1 auto; margin: 0.5em 0; overflow: hidden; } #main-wrapper.side-by-side { flex-direction: row; } #main-wrapper.side-by-side > fieldset { margin-left: 0.25em; margin-right: 0.25em; } #main-wrapper:not(.side-by-side) > fieldset { margin-bottom: 0.25em; } #main-wrapper.swapio { flex-direction: column; } #main-wrapper.side-by-side.swapio { flex-direction: row-reverse; } .zone-wrapper{ display: flex; margin: 0; flex: 1 1 0%; border-radius: 0.5em; min-width: inherit/*important: resolves inability to scroll fieldset child element!*/; padding: 0.35em 0 0 0; } .zone-wrapper textarea { border-radius: 0.5em; flex: 1 1 auto; /*min/max width resolve an inexplicable margin on the RHS. The -1em is for the padding, else we overlap the parent boundaries.*/ /*min-width: calc(100% - 1em); max-width: calc(100% - 1em); padding: 0 0.5em;*/ } .zone-wrapper.input { flex: 10 1 auto; } .zone-wrapper.output { flex: 20 1 auto; } .zone-wrapper > div { display:flex; flex: 1 1 0%; } .zone-wrapper.output {} .button-bar { display: flex; flex-wrap: wrap; align-items: center; align-content: space-between; justify-content: flex-start; } .button-bar > * { margin: 0.05em 0.5em 0.05em 0; flex: 0 1 auto; align-self: auto; } label[for] { cursor: pointer; } .error { color: red; background-color: yellow; } .hidden, .initially-hidden { position: absolute !important; opacity: 0 !important; pointer-events: none !important; display: none !important; } fieldset { border-radius: 0.5em; border: 1px inset; padding: 0.25em; } fieldset.options { font-size: 80%; margin-top: 0.5em; } fieldset:not(.options) > legend { font-size: 80%; } fieldset.options > div { display: flex; flex-wrap: wrap; } fieldset button { font-size: inherit; } fieldset.collapsible > legend > .fieldset-toggle::after { content: " [hide]"; position: relative; } fieldset.collapsible.collapsed > legend > .fieldset-toggle::after { content: " [show]"; position: relative; } span.labeled-input { padding: 0.25em; margin: 0.05em 0.25em; border-radius: 0.25em; white-space: nowrap; background: #0002; display: flex; align-items: center; } span.labeled-input > *:nth-child(2) { margin-left: 0.3em; } .center { text-align: center; } body.terminal-mode { max-height: calc(100% - 2em); display: flex; flex-direction: column; align-items: stretch; } #view-terminal {} .app-view { flex: 20 1 auto; } #view-split { display: flex; flex-direction: column-reverse; } </style> </head> <body> <header id='titlebar'> <span>SQLite3 Fiddle</span> <span class='powered-by'>Powered by <a href='https://sqlite.org'>SQLite3</a></span> </header> <!-- emscripten bits --> <figure id="module-spinner"> <div class="spinner"></div> <div class='center'><strong>Initializing app...</strong></div> <div class='center'> On a slow internet connection this may take a moment. If this message displays for "a long time", intialization may have failed and the JavaScript console may contain clues as to why. </div> </figure> <div class="emscripten" id="module-status">Downloading...</div> <div class="emscripten"> <progress value="0" max="100" id="module-progress" hidden='1'></progress> </div><!-- /emscripten bits --> <div id='view-terminal' class='app-view hidden initially-hidden'> This is a placeholder for a terminal-like view which is not in the default build. </div> <div id='view-split' class='app-view initially-hidden'> <fieldset class='options collapsible'> <legend><button class='fieldset-toggle'>Options</button></legend> <div class=''> <span class='labeled-input'> <input type='checkbox' id='opt-cb-sbs' data-csstgt='#main-wrapper' data-cssclass='side-by-side' data-config='sideBySide'> <label for='opt-cb-sbs'>Side-by-side</label> </span> <span class='labeled-input'> <input type='checkbox' id='opt-cb-swapio' data-csstgt='#main-wrapper' data-cssclass='swapio' data-config='swapInOut'> <label for='opt-cb-swapio'>Swap in/out</label> </span> <span class='labeled-input'> <input type='checkbox' id='opt-cb-autoscroll' data-config='autoScrollOutput'> <label for='opt-cb-autoscroll'>Auto-scroll output</label> </span> <span class='labeled-input'> <input type='checkbox' id='opt-cb-autoclear' data-config='autoClearOutput'> <label for='opt-cb-autoclear'>Auto-clear output</label> </span> <span class='labeled-input'> <input type='file' id='load-db' class='hidden'/> <button id='btn-load-db'>Load DB...</button> </span> <span class='labeled-input'> <button id='btn-export'>Download DB</button> </span> <span class='labeled-input'> <button id='btn-reset'>Reset DB</button> </span> </div> </fieldset><!-- .options --> <div id='main-wrapper' class=''> <fieldset class='zone-wrapper input'> <legend><div class='button-bar'> <button id='btn-shell-exec'>Run</button> <button id='btn-clear'>Clear Input</button> <!--button data-cmd='.help'>Help</button--> <select id='select-examples'></select> </div></legend> <div><textarea id="input" placeholder="Shell input. Ctrl-enter/shift-enter runs it."> -- ================================================== -- Use ctrl-enter or shift-enter to execute sqlite3 -- shell commands and SQL. -- If a subset of the text is currently selected, -- only that part is executed. -- ================================================== .nullvalue NULL .headers on </textarea></div> </fieldset> <fieldset class='zone-wrapper output'> <legend><div class='button-bar'> <button id='btn-clear-output'>Clear Output</button> <button id='btn-interrupt' class='hidden' disabled>Interrupt</button> <!-- interruption cannot work in the current configuration because we cannot send an interrupt message when work is currently underway. At that point the Worker is tied up and will not receive the message. --> </div></legend> <div><textarea id="output" readonly placeholder="Shell output."></textarea></div> </fieldset> </div> </div> <!-- #view-split --> <!-- Maintenance notes: ... TODO... currently being refactored... --> <script src="fiddle.js"></script> </body> </html> |
Deleted ext/wasm/fiddle/index.html.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to main.mk.
︙ | ︙ | |||
321 322 323 324 325 326 327 328 329 330 331 332 333 334 | $(TOP)/src/test_mutex.c \ $(TOP)/src/test_onefile.c \ $(TOP)/src/test_osinst.c \ $(TOP)/src/test_pcache.c \ $(TOP)/src/test_quota.c \ $(TOP)/src/test_rtree.c \ $(TOP)/src/test_schema.c \ $(TOP)/src/test_sqllog.c \ $(TOP)/src/test_superlock.c \ $(TOP)/src/test_syscall.c \ $(TOP)/src/test_tclsh.c \ $(TOP)/src/test_tclvar.c \ $(TOP)/src/test_thread.c \ $(TOP)/src/test_vdbecov.c \ | > | 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 | $(TOP)/src/test_mutex.c \ $(TOP)/src/test_onefile.c \ $(TOP)/src/test_osinst.c \ $(TOP)/src/test_pcache.c \ $(TOP)/src/test_quota.c \ $(TOP)/src/test_rtree.c \ $(TOP)/src/test_schema.c \ $(TOP)/src/test_schemapool.c \ $(TOP)/src/test_sqllog.c \ $(TOP)/src/test_superlock.c \ $(TOP)/src/test_syscall.c \ $(TOP)/src/test_tclsh.c \ $(TOP)/src/test_tclvar.c \ $(TOP)/src/test_thread.c \ $(TOP)/src/test_vdbecov.c \ |
︙ | ︙ | |||
382 383 384 385 386 387 388 389 390 391 392 393 394 395 | #TESTSRC += $(TOP)/ext/fts3/fts3_tokenizer.c TESTSRC2 = \ $(TOP)/src/attach.c \ $(TOP)/src/backup.c \ $(TOP)/src/btree.c \ $(TOP)/src/build.c \ $(TOP)/src/date.c \ $(TOP)/src/dbpage.c \ $(TOP)/src/dbstat.c \ $(TOP)/src/expr.c \ $(TOP)/src/func.c \ $(TOP)/src/global.c \ $(TOP)/src/insert.c \ | > | 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 | #TESTSRC += $(TOP)/ext/fts3/fts3_tokenizer.c TESTSRC2 = \ $(TOP)/src/attach.c \ $(TOP)/src/backup.c \ $(TOP)/src/btree.c \ $(TOP)/src/build.c \ $(TOP)/src/callback.c \ $(TOP)/src/date.c \ $(TOP)/src/dbpage.c \ $(TOP)/src/dbstat.c \ $(TOP)/src/expr.c \ $(TOP)/src/func.c \ $(TOP)/src/global.c \ $(TOP)/src/insert.c \ |
︙ | ︙ |
Changes to src/alter.c.
︙ | ︙ | |||
108 109 110 111 112 113 114 | ** Generate code to reload the schema for database iDb. And, if iDb!=1, for ** the temp database as well. */ static void renameReloadSchema(Parse *pParse, int iDb, u16 p5){ Vdbe *v = pParse->pVdbe; if( v ){ sqlite3ChangeCookie(pParse, iDb); | | | | 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 | ** Generate code to reload the schema for database iDb. And, if iDb!=1, for ** the temp database as well. */ static void renameReloadSchema(Parse *pParse, int iDb, u16 p5){ Vdbe *v = pParse->pVdbe; if( v ){ sqlite3ChangeCookie(pParse, iDb); sqlite3VdbeAddParseSchemaOp(pParse, iDb, 0, p5); if( iDb!=1 ) sqlite3VdbeAddParseSchemaOp(pParse, 1, 0, p5); } } /* ** Generate code to implement the "ALTER TABLE xxx RENAME TO yyy" ** command. */ |
︙ | ︙ |
Changes to src/analyze.c.
︙ | ︙ | |||
208 209 210 211 212 213 214 215 216 217 218 219 220 221 | aCreateTbl[i] = 0; if( (pStat = sqlite3FindTable(db, zTab, pDb->zDbSName))==0 ){ if( i<nToOpen ){ /* The sqlite_statN table does not exist. Create it. Note that a ** side-effect of the CREATE TABLE statement is to leave the rootpage ** of the new table in register pParse->regRoot. This is important ** because the OpenWrite opcode below will be needing it. */ sqlite3NestedParse(pParse, "CREATE TABLE %Q.%s(%s)", pDb->zDbSName, zTab, aTable[i].zCols ); aRoot[i] = (u32)pParse->regRoot; aCreateTbl[i] = OPFLAG_P2ISREG; } }else{ | > | 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 | aCreateTbl[i] = 0; if( (pStat = sqlite3FindTable(db, zTab, pDb->zDbSName))==0 ){ if( i<nToOpen ){ /* The sqlite_statN table does not exist. Create it. Note that a ** side-effect of the CREATE TABLE statement is to leave the rootpage ** of the new table in register pParse->regRoot. This is important ** because the OpenWrite opcode below will be needing it. */ sqlite3SchemaWritable(pParse, iDb); sqlite3NestedParse(pParse, "CREATE TABLE %Q.%s(%s)", pDb->zDbSName, zTab, aTable[i].zCols ); aRoot[i] = (u32)pParse->regRoot; aCreateTbl[i] = OPFLAG_P2ISREG; } }else{ |
︙ | ︙ |
Changes to src/attach.c.
︙ | ︙ | |||
214 215 216 217 218 219 220 | /* If the file was opened successfully, read the schema for the new database. ** If this fails, or if opening the file failed, then close the file and ** remove the entry from the db->aDb[] array. i.e. put everything back the ** way we found it. */ if( rc==SQLITE_OK ){ | < | > < | | > | 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 | /* If the file was opened successfully, read the schema for the new database. ** If this fails, or if opening the file failed, then close the file and ** remove the entry from the db->aDb[] array. i.e. put everything back the ** way we found it. */ if( rc==SQLITE_OK ){ db->init.iDb = 0; db->mDbFlags &= ~(DBFLAG_SchemaKnownOk); if( !IsSharedSchema(db) && !REOPEN_AS_MEMDB(db) ){ sqlite3BtreeEnterAll(db); rc = sqlite3Init(db, &zErrDyn); sqlite3BtreeLeaveAll(db); assert( zErrDyn==0 || rc!=SQLITE_OK ); } } #ifdef SQLITE_USER_AUTHENTICATION if( rc==SQLITE_OK && !REOPEN_AS_MEMDB(db) ){ u8 newAuth = 0; rc = sqlite3UserAuthCheckLogin(db, zName, &newAuth); if( newAuth<db->auth.authLevel ){ rc = SQLITE_AUTH_USER; |
︙ | ︙ | |||
321 322 323 324 325 326 327 328 329 330 331 332 333 334 | Trigger *pTrig = (Trigger*)sqliteHashData(pEntry); if( pTrig->pTabSchema==pDb->pSchema ){ pTrig->pTabSchema = pTrig->pSchema; } pEntry = sqliteHashNext(pEntry); } sqlite3BtreeClose(pDb->pBt); pDb->pBt = 0; pDb->pSchema = 0; sqlite3CollapseDatabaseArray(db); return; detach_error: | > | 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 | Trigger *pTrig = (Trigger*)sqliteHashData(pEntry); if( pTrig->pTabSchema==pDb->pSchema ){ pTrig->pTabSchema = pTrig->pSchema; } pEntry = sqliteHashNext(pEntry); } (void)sqlite3SchemaDisconnect(db, i, 0); sqlite3BtreeClose(pDb->pBt); pDb->pBt = 0; pDb->pSchema = 0; sqlite3CollapseDatabaseArray(db); return; detach_error: |
︙ | ︙ | |||
350 351 352 353 354 355 356 | ){ int rc; NameContext sName; Vdbe *v; sqlite3* db = pParse->db; int regArgs; | > | > | 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 | ){ int rc; NameContext sName; Vdbe *v; sqlite3* db = pParse->db; int regArgs; if( (db->mDbFlags & DBFLAG_EncodingFixed)==0 ){ if( SQLITE_OK!=sqlite3ReadSchema(pParse) ) goto attach_end; } if( pParse->nErr ) goto attach_end; memset(&sName, 0, sizeof(NameContext)); sName.pParse = pParse; if( SQLITE_OK!=resolveAttachExpr(&sName, pFilename) || |
︙ | ︙ |
Changes to src/build.c.
︙ | ︙ | |||
334 335 336 337 338 339 340 341 342 343 344 345 346 347 | ** list of users and their access credentials. */ int sqlite3UserAuthTable(const char *zTable){ return sqlite3_stricmp(zTable, "sqlite_user")==0; } #endif /* ** Locate the in-memory structure that describes a particular database ** table given the name of that table and (optionally) the name of the ** database containing the table. Return NULL if not found. ** ** If zDatabase is 0, all databases are searched for the table and the ** first matching table is returned. (No checking for duplicate table | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 | ** list of users and their access credentials. */ int sqlite3UserAuthTable(const char *zTable){ return sqlite3_stricmp(zTable, "sqlite_user")==0; } #endif #ifdef SQLITE_ENABLE_SHARED_SCHEMA /* ** If this database connection was opened with the SQLITE_OPEN_SHARED_SCHEMA ** flag specified, then ensure that the database schema for database iDb ** is loaded. Either by obtaining a Schema object from the schema-pool, or ** by reading the contents of the sqlite_master table. Unless it is NULL, ** the location indicated by parameter pbUnload is set to 1 if a shared-schema ** is loaded. ** ** If the database handle was not opened with SQLITE_OPEN_SHARED_SCHEMA, or ** if the schema for database iDb is already loaded, this function is a no-op. ** ** SQLITE_OK is returned if successful, or an SQLite error code otherwise. If ** an error code is returned, (*pzErr) may be set to point to a buffer ** containing an error message. It is the responsibility of the caller to ** eventually free this buffer using sqlite3_free(). */ int sqlite3SchemaLoad(sqlite3 *db, int iDb, int *pbUnload, char **pzErr){ int rc = SQLITE_OK; if( IsSharedSchema(db) && DbHasProperty(db, iDb, DB_SchemaLoaded)==0 && (db->init.busy==0 || (iDb!=1 && db->init.iDb==1)) ){ struct sqlite3InitInfo sv = db->init; memset(&db->init, 0, sizeof(struct sqlite3InitInfo)); rc = sqlite3InitOne(db, iDb, pzErr, 0); db->init = sv; if( pbUnload && rc==SQLITE_OK && iDb!=1 ) *pbUnload = 1; } return rc; } #endif /* ** Locate the in-memory structure that describes a particular database ** table given the name of that table and (optionally) the name of the ** database containing the table. Return NULL if not found. ** ** If zDatabase is 0, all databases are searched for the table and the ** first matching table is returned. (No checking for duplicate table |
︙ | ︙ | |||
359 360 361 362 363 364 365 | #if SQLITE_USER_AUTHENTICATION /* Only the admin user is allowed to know that the sqlite_user table ** exists */ if( db->auth.authLevel<UAUTH_Admin && sqlite3UserAuthTable(zName)!=0 ){ return 0; } #endif | | | | < < < < | | > > | > > | | | | < | < < < | | < < > > > > | < | > | < < < < < < < < < < < | | < > < | < < | | | < < | | 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 | #if SQLITE_USER_AUTHENTICATION /* Only the admin user is allowed to know that the sqlite_user table ** exists */ if( db->auth.authLevel<UAUTH_Admin && sqlite3UserAuthTable(zName)!=0 ){ return 0; } #endif while(1){ for(i=OMIT_TEMPDB; i<db->nDb; i++){ int j = (i<2) ? i^1 : i; /* Search TEMP before MAIN */ if( zDatabase==0 || sqlite3DbIsNamed(db, j, zDatabase) ){ int bUnload = 0; assert( sqlite3SchemaMutexHeld(db, j, 0) ); if( IsSharedSchema(db) ){ Parse *pParse = db->pParse; if( pParse && pParse->nErr==0 ){ pParse->rc = sqlite3SchemaLoad(db, j, &bUnload, &pParse->zErrMsg); if( pParse->rc ) pParse->nErr++; } } p = sqlite3HashFind(&db->aDb[j].pSchema->tblHash, zName); if( p ) return p; if( bUnload ){ sqlite3SchemaRelease(db, j); } } } /* Not found. If the name we were looking for was temp.sqlite_master ** then change the name to sqlite_temp_master and try again. */ if( sqlite3StrICmp(zName, PREFERRED_SCHEMA_TABLE)==0 ){ zName = LEGACY_SCHEMA_TABLE; continue; } if( sqlite3StrICmp(zName, PREFERRED_TEMP_SCHEMA_TABLE)==0 ){ zName = LEGACY_TEMP_SCHEMA_TABLE; continue; } if( sqlite3StrICmp(zName, LEGACY_SCHEMA_TABLE)!=0 ) break; if( sqlite3_stricmp(zDatabase, db->aDb[1].zDbSName)!=0 ) break; zName = LEGACY_TEMP_SCHEMA_TABLE; } return 0; } /* ** Locate the in-memory structure that describes a particular database ** table given the name of that table and (optionally) the name of the ** database containing the table. Return NULL if not found. Also leave an ** error message in pParse->zErrMsg. |
︙ | ︙ | |||
436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 | ){ Table *p; sqlite3 *db = pParse->db; /* Read the database schema. If an error occurs, leave an error message ** and code in pParse and return NULL. */ if( (db->mDbFlags & DBFLAG_SchemaKnownOk)==0 && SQLITE_OK!=sqlite3ReadSchema(pParse) ){ return 0; } p = sqlite3FindTable(db, zName, zDbase); if( p==0 ){ #ifndef SQLITE_OMIT_VIRTUALTABLE /* If zName is the not the name of a table in the schema created using ** CREATE, then check to see if it is the name of an virtual table that ** can be an eponymous virtual table. */ if( (pParse->prepFlags & SQLITE_PREPARE_NO_VTAB)==0 && db->init.busy==0 ){ Module *pMod = (Module*)sqlite3HashFind(&db->aModule, zName); if( pMod==0 && sqlite3_strnicmp(zName, "pragma_", 7)==0 ){ pMod = sqlite3PragmaVtabRegister(db, zName); } | > > > > > > > > | | > > > > | > | < < | 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 | ){ Table *p; sqlite3 *db = pParse->db; /* Read the database schema. If an error occurs, leave an error message ** and code in pParse and return NULL. */ if( (db->mDbFlags & DBFLAG_SchemaKnownOk)==0 && !IsSharedSchema(db) && SQLITE_OK!=sqlite3ReadSchema(pParse) ){ return 0; } p = sqlite3FindTable(db, zName, zDbase); if( p==0 ){ #ifndef SQLITE_OMIT_VIRTUALTABLE /* If zName is the not the name of a table in the schema created using ** CREATE, then check to see if it is the name of an virtual table that ** can be an eponymous virtual table. */ if( (pParse->prepFlags & SQLITE_PREPARE_NO_VTAB)==0 && db->init.busy==0 ){ Module *pMod = (Module*)sqlite3HashFind(&db->aModule, zName); if( pMod==0 && sqlite3_strnicmp(zName, "pragma_", 7)==0 ){ pMod = sqlite3PragmaVtabRegister(db, zName); } if( pMod ){ if( IsSharedSchema(db) && pParse->nErr==0 ){ int bDummy = 0; pParse->rc = sqlite3SchemaLoad(db, 0, &bDummy, &pParse->zErrMsg); if( pParse->rc ) pParse->nErr++; (void)bDummy; } if( sqlite3VtabEponymousTableInit(pParse, pMod) ){ Table *pEpoTab = pMod->pEpoTab; if( pEpoTab ){ assert( IsSharedSchema(db)||pEpoTab->pSchema==db->aDb[0].pSchema ); pEpoTab->pSchema = db->aDb[0].pSchema; /* For SHARED_SCHEMA mode */ } return pEpoTab; } } } #endif if( flags & LOCATE_NOERR ) return 0; pParse->checkSchema = 1; }else if( IsVirtual(p) && (pParse->prepFlags & SQLITE_PREPARE_NO_VTAB)!=0 ){ p = 0; } if( p==0 && (!IsSharedSchema(db) || pParse->nErr==0) ){ const char *zMsg = flags & LOCATE_VIEW ? "no such view" : "no such table"; if( zDbase ){ sqlite3ErrorMsg(pParse, "%s: %s.%s", zMsg, zDbase, zName); }else{ sqlite3ErrorMsg(pParse, "%s: %s", zMsg, zName); } } return p; } /* ** Locate the table identified by *p. |
︙ | ︙ | |||
641 642 643 644 645 646 647 | if( iDb>=0 ){ assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); DbSetProperty(db, iDb, DB_ResetWanted); DbSetProperty(db, 1, DB_ResetWanted); db->mDbFlags &= ~DBFLAG_SchemaKnownOk; } | < | | | > | 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 | if( iDb>=0 ){ assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); DbSetProperty(db, iDb, DB_ResetWanted); DbSetProperty(db, 1, DB_ResetWanted); db->mDbFlags &= ~DBFLAG_SchemaKnownOk; } if( db->nSchemaLock==0 ){ for(i=0; i<db->nDb; i++){ if( DbHasProperty(db, i, DB_ResetWanted) ){ sqlite3SchemaClearOrDisconnect(db, i); } } } } /* ** Erase all schema information from all attached databases (including ** "main" and "temp") for a single database connection. */ void sqlite3ResetAllSchemasOfConnection(sqlite3 *db){ int i; sqlite3BtreeEnterAll(db); for(i=0; i<db->nDb; i=(i?i+1:2)){ Db *pDb = &db->aDb[i]; if( pDb->pSchema ){ if( db->nSchemaLock==0 ){ sqlite3SchemaClearOrDisconnect(db, i); }else{ DbSetProperty(db, i, DB_ResetWanted); } } } sqlite3SchemaClear(db->aDb[1].pSchema); db->mDbFlags &= ~(DBFLAG_SchemaChange|DBFLAG_SchemaKnownOk); sqlite3VtabUnlockList(db); sqlite3BtreeLeaveAll(db); if( db->nSchemaLock==0 ){ sqlite3CollapseDatabaseArray(db); } } |
︙ | ︙ | |||
1278 1279 1280 1281 1282 1283 1284 | ** it does. The exception is if the statement being parsed was passed ** to an sqlite3_declare_vtab() call. In that case only the column names ** and types will be used, so there is no need to test for namespace ** collisions. */ if( !IN_SPECIAL_PARSE ){ char *zDb = db->aDb[iDb].zDbSName; | | | 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 | ** it does. The exception is if the statement being parsed was passed ** to an sqlite3_declare_vtab() call. In that case only the column names ** and types will be used, so there is no need to test for namespace ** collisions. */ if( !IN_SPECIAL_PARSE ){ char *zDb = db->aDb[iDb].zDbSName; if( !IsSharedSchema(db) && SQLITE_OK!=sqlite3ReadSchema(pParse) ){ goto begin_table_error; } pTable = sqlite3FindTable(db, zName, zDb); if( pTable ){ if( !noErr ){ sqlite3ErrorMsg(pParse, "%s %T already exists", (IsView(pTable)? "view" : "table"), pName); |
︙ | ︙ | |||
2913 2914 2915 2916 2917 2918 2919 | pDb->zDbSName ); } } #endif /* Reparse everything to update our internal data structures */ | | | 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952 2953 | pDb->zDbSName ); } } #endif /* Reparse everything to update our internal data structures */ sqlite3VdbeAddParseSchemaOp(pParse, iDb, sqlite3MPrintf(db, "tbl_name='%q' AND type!='trigger'", p->zName),0); /* Test for cycles in generated columns and illegal expressions ** in CHECK constraints and in DEFAULT clauses. */ if( p->tabFlags & TF_HasGenerated ){ sqlite3VdbeAddOp4(v, OP_SqlExec, 0x0001, 0, 0, sqlite3MPrintf(db, "SELECT*FROM\"%w\".\"%w\"", |
︙ | ︙ | |||
3485 3486 3487 3488 3489 3490 3491 | int iDb; if( db->mallocFailed ){ goto exit_drop_table; } assert( pParse->nErr==0 ); assert( pName->nSrc==1 ); | | > | 3511 3512 3513 3514 3515 3516 3517 3518 3519 3520 3521 3522 3523 3524 3525 3526 3527 3528 3529 3530 3531 3532 3533 3534 3535 3536 3537 3538 3539 3540 | int iDb; if( db->mallocFailed ){ goto exit_drop_table; } assert( pParse->nErr==0 ); assert( pName->nSrc==1 ); if( !IsSharedSchema(db) && sqlite3ReadSchema(pParse) ) goto exit_drop_table; if( noErr ) db->suppressErr++; assert( isView==0 || isView==LOCATE_VIEW ); pTab = sqlite3LocateTableItem(pParse, isView, &pName->a[0]); if( noErr ) db->suppressErr--; if( pTab==0 ){ if( noErr ){ sqlite3CodeVerifyNamedSchema(pParse, pName->a[0].zDatabase); sqlite3ForceNotReadOnly(pParse); } goto exit_drop_table; } iDb = sqlite3SchemaToIndex(db, pTab->pSchema); assert( iDb>=0 && iDb<db->nDb ); sqlite3SchemaWritable(pParse, iDb); /* If pTab is a virtual table, call ViewGetColumnNames() to ensure ** it is initialized. */ if( IsVirtual(pTab) && sqlite3ViewGetColumnNames(pParse, pTab) ){ goto exit_drop_table; } |
︙ | ︙ | |||
3954 3955 3956 3957 3958 3959 3960 | if( pParse->nErr ){ goto exit_create_index; } assert( db->mallocFailed==0 ); if( IN_DECLARE_VTAB && idxType!=SQLITE_IDXTYPE_PRIMARYKEY ){ goto exit_create_index; } | | | 3981 3982 3983 3984 3985 3986 3987 3988 3989 3990 3991 3992 3993 3994 3995 | if( pParse->nErr ){ goto exit_create_index; } assert( db->mallocFailed==0 ); if( IN_DECLARE_VTAB && idxType!=SQLITE_IDXTYPE_PRIMARYKEY ){ goto exit_create_index; } if( !IsSharedSchema(db) && SQLITE_OK!=sqlite3ReadSchema(pParse) ){ goto exit_create_index; } if( sqlite3HasExplicitNulls(pParse, pList) ){ goto exit_create_index; } /* |
︙ | ︙ | |||
4454 4455 4456 4457 4458 4459 4460 | /* Fill the index with data and reparse the schema. Code an OP_Expire ** to invalidate all pre-compiled statements. */ if( pTblName ){ sqlite3RefillIndex(pParse, pIndex, iMem); sqlite3ChangeCookie(pParse, iDb); | | | 4481 4482 4483 4484 4485 4486 4487 4488 4489 4490 4491 4492 4493 4494 4495 | /* Fill the index with data and reparse the schema. Code an OP_Expire ** to invalidate all pre-compiled statements. */ if( pTblName ){ sqlite3RefillIndex(pParse, pIndex, iMem); sqlite3ChangeCookie(pParse, iDb); sqlite3VdbeAddParseSchemaOp(pParse, iDb, sqlite3MPrintf(db, "name='%q' AND type='index'", pIndex->zName), 0); sqlite3VdbeAddOp2(v, OP_Expire, 0, 1); } sqlite3VdbeJumpHere(v, (int)pIndex->tnum); } } |
︙ | ︙ | |||
4604 4605 4606 4607 4608 4609 4610 4611 4612 4613 4614 4615 4616 4617 | } if( pIndex->idxType!=SQLITE_IDXTYPE_APPDEF ){ sqlite3ErrorMsg(pParse, "index associated with UNIQUE " "or PRIMARY KEY constraint cannot be dropped", 0); goto exit_drop_index; } iDb = sqlite3SchemaToIndex(db, pIndex->pSchema); #ifndef SQLITE_OMIT_AUTHORIZATION { int code = SQLITE_DROP_INDEX; Table *pTab = pIndex->pTable; const char *zDb = db->aDb[iDb].zDbSName; const char *zTab = SCHEMA_TABLE(iDb); if( sqlite3AuthCheck(pParse, SQLITE_DELETE, zTab, 0, zDb) ){ | > | 4631 4632 4633 4634 4635 4636 4637 4638 4639 4640 4641 4642 4643 4644 4645 | } if( pIndex->idxType!=SQLITE_IDXTYPE_APPDEF ){ sqlite3ErrorMsg(pParse, "index associated with UNIQUE " "or PRIMARY KEY constraint cannot be dropped", 0); goto exit_drop_index; } iDb = sqlite3SchemaToIndex(db, pIndex->pSchema); sqlite3SchemaWritable(pParse, iDb); #ifndef SQLITE_OMIT_AUTHORIZATION { int code = SQLITE_DROP_INDEX; Table *pTab = pIndex->pTable; const char *zDb = db->aDb[iDb].zDbSName; const char *zTab = SCHEMA_TABLE(iDb); if( sqlite3AuthCheck(pParse, SQLITE_DELETE, zTab, 0, zDb) ){ |
︙ | ︙ |
Changes to src/callback.c.
︙ | ︙ | |||
12 13 14 15 16 17 18 19 20 21 22 23 24 25 | ** ** This file contains functions used to access the internal hash tables ** of user defined functions and collation sequences. */ #include "sqliteInt.h" /* ** Invoke the 'collation needed' callback to request a collation sequence ** in the encoding enc of name zName, length nName. */ static void callCollNeeded(sqlite3 *db, int enc, const char *zName){ assert( !db->xCollNeeded || !db->xCollNeeded16 ); if( db->xCollNeeded ){ | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 | ** ** This file contains functions used to access the internal hash tables ** of user defined functions and collation sequences. */ #include "sqliteInt.h" /* ** Connections opened with the SQLITE_OPEN_SHARED_SCHEMA flag specified ** may use SchemaPool objects for any database that is not the temp db ** (iDb==1). For such databases (type "struct Db") there are three states ** the Schema/SchemaPool object may be in. ** ** 1) pSPool==0, pSchema points to an empty object allocated by ** sqlite3_malloc(). DB_SchemaLoaded flag is clear. ** ** 2) pSPool!=0, pSchema points to a populated object owned by the ** SchemaPool. DB_SchemaLoaded flag is set. ** ** 3) pSPool!=0, pSchema points to the SchemaPool's static object ** (SchemaPool.sSchema). */ struct SchemaPool { int nRef; /* Number of pointers to this object */ int nDelete; /* Schema objects deleted by ReleaseAll() */ u64 cksum; /* Checksum for this Schema contents */ Schema *pSchema; /* Linked list of Schema objects */ Schema sSchema; /* The single dummy schema object */ SchemaPool *pNext; /* Next element in schemaPoolList */ }; #ifdef SQLITE_ENABLE_SHARED_SCHEMA #ifdef SQLITE_DEBUG static void assert_schema_state_ok(sqlite3 *db){ if( IsSharedSchema(db) && db->eOpenState!=SQLITE_STATE_ZOMBIE ){ int i; for(i=0; i<db->nDb; i++){ if( i!=1 ){ Db *pDb = &db->aDb[i]; Btree *pBt = pDb->pBt; if( pBt==0 ) continue; assert( sqlite3BtreeSchema(pBt, 0, 0)==0 ); assert( pDb->pSchema ); if( pDb->pSPool ){ if( DbHasProperty(db, i, DB_SchemaLoaded)==0 ){ assert( pDb->pSchema->tblHash.count==0 ); assert( pDb->pSchema==&pDb->pSPool->sSchema ); }else{ assert( pDb->pSchema!=&pDb->pSPool->sSchema ); } }else{ assert( DbHasProperty(db, i, DB_SchemaLoaded)==0 ); assert( pDb->pSchema->tblHash.count==0 ); assert( pDb->pSchema!=&pDb->pSPool->sSchema ); } } } } } #else # define assert_schema_state_ok(x) #endif #endif /* ifdef SQLITE_ENABLE_SHARED_SCHEMA */ /* ** Invoke the 'collation needed' callback to request a collation sequence ** in the encoding enc of name zName, length nName. */ static void callCollNeeded(sqlite3 *db, int enc, const char *zName){ assert( !db->xCollNeeded || !db->xCollNeeded16 ); if( db->xCollNeeded ){ |
︙ | ︙ | |||
513 514 515 516 517 518 519 | if( pSchema->schemaFlags & DB_SchemaLoaded ){ pSchema->iGeneration++; } pSchema->schemaFlags &= ~(DB_SchemaLoaded|DB_ResetWanted); } /* | > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > | | | | | 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 | if( pSchema->schemaFlags & DB_SchemaLoaded ){ pSchema->iGeneration++; } pSchema->schemaFlags &= ~(DB_SchemaLoaded|DB_ResetWanted); } /* ** If this database was opened with the SQLITE_OPEN_SHARED_SCHEMA flag ** and iDb!=1, then disconnect from the schema-pool associated with ** database iDb. Otherwise, clear the Schema object belonging to ** database iDb. ** ** If an OOM error occurs while disconnecting from a schema-pool, ** the db->mallocFailed flag is set. */ void sqlite3SchemaClearOrDisconnect(sqlite3 *db, int iDb){ Db *pDb = &db->aDb[iDb]; #ifdef SQLITE_ENABLE_SHARED_SCHEMA if( IsSharedSchema(db) && iDb!=1 && pDb->pSPool ){ sqlite3SchemaDisconnect(db, iDb, 1); }else #endif { sqlite3SchemaClear(pDb->pSchema); } } #ifdef SQLITE_ENABLE_SHARED_SCHEMA /* ** Global linked list of SchemaPool objects. Read and write access must ** be protected by the SQLITE_MUTEX_STATIC_MASTER mutex. */ static SchemaPool *SQLITE_WSD schemaPoolList = 0; #ifdef SQLITE_TEST /* ** Return a pointer to the head of the linked list of SchemaPool objects. ** This is used by the virtual table in file test_schemapool.c. */ SchemaPool *sqlite3SchemaPoolList(void){ return schemaPoolList; } #endif /* ** Database handle db was opened with the SHARED_SCHEMA flag, and database ** iDb is currently connected to a schema-pool. When this function is called, ** (*pnByte) is set to nInit plus the amount of memory used to store a ** single instance of the Schema objects managed by the schema-pool. ** This function adjusts (*pnByte) sot hat it is set to nInit plus ** (nSchema/nRef) of the amount of memory used by a single Schema object, ** where nSchema is the number of Schema objects allocated by this pool, ** and nRef is the number of connections to the schema-pool. */ void sqlite3SchemaAdjustUsed(sqlite3 *db, int iDb, int nInit, int *pnByte){ SchemaPool *pSPool = db->aDb[iDb].pSPool; int nSchema = 0; Schema *p; sqlite3_mutex_enter( sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER) ); for(p=pSPool->pSchema; p; p=p->pNext){ nSchema++; } *pnByte = nInit + ((*pnByte - nInit) * nSchema) / pSPool->nRef; sqlite3_mutex_leave( sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER) ); } /* ** Check that the schema of db iDb is writable (either because it is the ** temp db schema or because the db handle was opened without ** SQLITE_OPEN_SHARED_SCHEMA). If so, do nothing. Otherwise, leave an ** error in the Parse object. */ void sqlite3SchemaWritable(Parse *pParse, int iDb){ if( iDb!=1 && IsSharedSchema(pParse->db) && IN_DECLARE_VTAB==0 ){ sqlite3ErrorMsg(pParse, "attempt to modify read-only schema"); } } /* ** The schema object passed as the only argument was allocated using ** sqlite3_malloc() and then populated using the usual mechanism. This ** function frees both the Schema object and its contents. */ static void schemaDelete(Schema *pSchema){ sqlite3SchemaClear((void*)pSchema); sqlite3_free(pSchema); } /* ** When this function is called, the database connection Db must be ** using a schema-pool (Db.pSPool!=0) and must currently have Db.pSchema ** set to point to a populated schema object checked out from the ** schema-pool. It is also assumed that the STATIC_MASTER mutex is held. ** This function returns the Schema object to the schema-pool and sets ** Db.pSchema to point to the schema-pool's static, empty, Schema object. */ static void schemaRelease(sqlite3 *db, Db *pDb){ Schema *pRelease = pDb->pSchema; SchemaPool *pSPool = pDb->pSPool; assert( pDb->pSchema->iGeneration==pSPool->sSchema.iGeneration ); pDb->pSchema = &pSPool->sSchema; assert( pDb->pSPool && pRelease ); assert( pRelease->schemaFlags & DB_SchemaLoaded ); assert( (pDb->pSchema->schemaFlags & DB_SchemaLoaded)==0 ); assert( sqlite3_mutex_held(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER)) ); /* If the DBFLAG_FreeSchema flag is set and the database connection holds ** at least one other copy of the schema being released, delete it instead ** of returning it to the schema-pool. */ if( db->mDbFlags & DBFLAG_FreeSchema ){ int i; for(i=0; i<db->nDb; i++){ Db *p = &db->aDb[i]; if( p!=pDb && p->pSchema!=&pSPool->sSchema && pDb->pSPool==p->pSPool ){ pSPool->nDelete++; schemaDelete(pRelease); return; } } } pRelease->pNext = pDb->pSPool->pSchema; pDb->pSPool->pSchema = pRelease; } /* ** The schema for database iDb of database handle db, which was opened ** with SQLITE_OPEN_SHARED_SCHEMA, has just been parsed. This function either ** finds a matching SchemaPool object on the global list (schemaPoolList) or ** else allocates a new one and sets the Db.pSPool variable accordingly. ** ** SQLITE_OK is returned if no error occurs, or an SQLite error code ** (SQLITE_NOMEM) otherwise. */ int sqlite3SchemaConnect(sqlite3 *db, int iDb, u64 cksum){ Schema *pSchema = db->aDb[iDb].pSchema; SchemaPool *p; assert( pSchema && iDb!=1 && db->aDb[iDb].pSPool==0 ); sqlite3_mutex_enter( sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER) ); /* Search for a matching SchemaPool object */ for(p=schemaPoolList; p; p=p->pNext){ if( p->cksum==cksum && p->sSchema.schema_cookie==pSchema->schema_cookie ){ break; } } if( !p ){ /* No SchemaPool object found. Allocate a new one. */ p = (SchemaPool*)sqlite3_malloc(sizeof(SchemaPool)); if( p ){ memset(p, 0, sizeof(SchemaPool)); p->cksum = cksum; p->pNext = schemaPoolList; schemaPoolList = p; p->sSchema.schema_cookie = pSchema->schema_cookie; p->sSchema.iGeneration = pSchema->iGeneration; p->sSchema.file_format = pSchema->file_format; p->sSchema.enc = pSchema->enc; p->sSchema.cache_size = pSchema->cache_size; } } if( p ) p->nRef++; /* If the SchemaPool contains one or more free schemas at the moment, ** delete one of them. */ if( p && p->pSchema ){ Schema *pDel = p->pSchema; p->pSchema = pDel->pNext; schemaDelete(pDel); } sqlite3_mutex_leave( sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER) ); db->aDb[iDb].pSPool = p; return (p ? SQLITE_OK : SQLITE_NOMEM); } /* ** If parameter iDb is 1 (the temp db), or if connection handle db was not ** opened with the SQLITE_OPEN_SHARED_SCHEMA flag, this function is a no-op. ** Otherwise, it disconnects from the schema-pool associated with database ** iDb, assuming it is connected. ** ** If parameter bNew is true, then Db.pSchema is set to point to a new, empty, ** Schema object obtained from sqlite3_malloc(). Or, if bNew is false, then ** Db.pSchema is set to NULL before returning. ** ** If the bNew parameter is true, then this function may allocate memory. ** If the allocation attempt fails, then SQLITE_NOMEM is returned and the ** schema-pool is not disconnected from. Or, if no OOM error occurs, ** SQLITE_OK is returned. */ int sqlite3SchemaDisconnect(sqlite3 *db, int iDb, int bNew){ int rc = SQLITE_OK; if( IsSharedSchema(db) ){ Db *pDb = &db->aDb[iDb]; SchemaPool *pSPool = pDb->pSPool; assert_schema_state_ok(db); assert( pDb->pSchema ); if( pSPool==0 ){ assert( pDb->pVTable==0 ); assert( bNew==0 ); schemaDelete(pDb->pSchema); pDb->pSchema = 0; }else{ VTable *p; VTable *pNext; for(p=pDb->pVTable; p; p=pNext){ pNext = p->pNext; sqlite3VtabUnlock(p); } pDb->pVTable = 0; sqlite3_mutex_enter( sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER) ); if( DbHasProperty(db, iDb, DB_SchemaLoaded) ){ schemaRelease(db, pDb); } if( bNew ){ Schema *pNew = sqlite3SchemaGet(db, 0); if( pNew==0 ){ rc = SQLITE_NOMEM; }else{ pDb->pSchema = pNew; } } if( rc==SQLITE_OK ){ assert( pSPool->nRef>=1 ); pDb->pSPool = 0; pSPool->nRef--; if( pSPool->nRef<=0 ){ SchemaPool **pp; while( pSPool->pSchema ){ Schema *pNext = pSPool->pSchema->pNext; schemaDelete(pSPool->pSchema); pSPool->pSchema = pNext; } for(pp=&schemaPoolList; (*pp)!=pSPool; pp=&((*pp)->pNext)); *pp = pSPool->pNext; sqlite3_free(pSPool); } } sqlite3_mutex_leave( sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER) ); } } return rc; } /* ** Extract and return a pointer to a schema object from the SchemaPool passed ** as the only argument, if one is available. If one is not available, return ** NULL. */ Schema *sqlite3SchemaExtract(SchemaPool *pSPool){ Schema *pRet = 0; sqlite3_mutex_enter( sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER) ); if( pSPool->pSchema ){ pRet = pSPool->pSchema; pSPool->pSchema = pRet->pNext; pRet->pNext = 0; } sqlite3_mutex_leave( sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER) ); return pRet; } /* ** Return all sharable schemas held by database handle db back to their ** respective schema-pools. Db.pSchema variables are left pointing to ** the static, empty, Schema object owned by each schema-pool. */ void sqlite3SchemaReleaseAll(sqlite3 *db){ int i; assert_schema_state_ok(db); sqlite3_mutex_enter( sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER) ); for(i=0; i<db->nDb; i++){ if( i!=1 ){ Db *pDb = &db->aDb[i]; if( pDb->pSPool && DbHasProperty(db,i,DB_SchemaLoaded) ){ schemaRelease(db, pDb); } } } db->mDbFlags &= ~DBFLAG_FreeSchema; sqlite3_mutex_leave( sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER) ); } /* ** Release any sharable schema held by connection iDb of database handle ** db. Db.pSchema is left pointing to the static, empty, Schema object ** owned by the schema-pool. */ void sqlite3SchemaRelease(sqlite3 *db, int iDb){ Db *pDb = &db->aDb[iDb]; assert( iDb!=1 ); assert_schema_state_ok(db); sqlite3_mutex_enter( sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER) ); schemaRelease(db, pDb); sqlite3_mutex_leave( sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER) ); } #endif /* ifdef SQLITE_ENABLE_SHARED_SCHEMA */ /* ** In most cases, this function finds and returns the schema associated ** with BTree handle pBt, creating a new one if necessary. However, if ** the database handle was opened with the SQLITE_OPEN_SHARED_SCHEMA flag ** specified, a new, empty, Schema object in memory obtained by ** sqlite3_malloc() is always returned. */ Schema *sqlite3SchemaGet(sqlite3 *db, Btree *pBt){ Schema *p; if( pBt && IsSharedSchema(db)==0 ){ p = (Schema*)sqlite3BtreeSchema(pBt, sizeof(Schema), sqlite3SchemaClear); }else{ p = (Schema*)sqlite3DbMallocZero(0, sizeof(Schema)); } if( !p ){ sqlite3OomFault(db); }else if ( 0==p->file_format ){ sqlite3HashInit(&p->tblHash); sqlite3HashInit(&p->idxHash); sqlite3HashInit(&p->trigHash); sqlite3HashInit(&p->fkeyHash); p->enc = SQLITE_UTF8; } return p; } |
Changes to src/main.c.
︙ | ︙ | |||
1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 | Schema *pSchema = db->aDb[i].pSchema; if( pSchema ){ for(p=sqliteHashFirst(&pSchema->tblHash); p; p=sqliteHashNext(p)){ Table *pTab = (Table *)sqliteHashData(p); if( IsVirtual(pTab) ) sqlite3VtabDisconnect(db, pTab); } } } for(p=sqliteHashFirst(&db->aModule); p; p=sqliteHashNext(p)){ Module *pMod = (Module *)sqliteHashData(p); if( pMod->pEpoTab ){ sqlite3VtabDisconnect(db, pMod->pEpoTab); } } | > > > > > > > > > > > | 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 | Schema *pSchema = db->aDb[i].pSchema; if( pSchema ){ for(p=sqliteHashFirst(&pSchema->tblHash); p; p=sqliteHashNext(p)){ Table *pTab = (Table *)sqliteHashData(p); if( IsVirtual(pTab) ) sqlite3VtabDisconnect(db, pTab); } } #ifdef SQLITE_ENABLE_SHARED_SCHEMA if( IsSharedSchema(db) && i!=1 ){ VTable *pVTable; VTable *pNext; for(pVTable=db->aDb[i].pVTable; pVTable; pVTable=pNext){ pNext = pVTable->pNext; sqlite3VtabUnlock(pVTable); } db->aDb[i].pVTable = 0; } #endif /* ifdef SQLITE_ENABLE_SHARED_SCHEMA */ } for(p=sqliteHashFirst(&db->aModule); p; p=sqliteHashNext(p)){ Module *pMod = (Module *)sqliteHashData(p); if( pMod->pEpoTab ){ sqlite3VtabDisconnect(db, pMod->pEpoTab); } } |
︙ | ︙ | |||
1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 | /* Close all database connections */ for(j=0; j<db->nDb; j++){ struct Db *pDb = &db->aDb[j]; if( pDb->pBt ){ sqlite3BtreeClose(pDb->pBt); pDb->pBt = 0; if( j!=1 ){ pDb->pSchema = 0; } } } /* Clear the TEMP schema separately and last */ if( db->aDb[1].pSchema ){ sqlite3SchemaClear(db->aDb[1].pSchema); | > | 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 | /* Close all database connections */ for(j=0; j<db->nDb; j++){ struct Db *pDb = &db->aDb[j]; if( pDb->pBt ){ sqlite3BtreeClose(pDb->pBt); pDb->pBt = 0; if( j!=1 ){ (void)sqlite3SchemaDisconnect(db, j, 0); pDb->pSchema = 0; } } } /* Clear the TEMP schema separately and last */ if( db->aDb[1].pSchema ){ sqlite3SchemaClear(db->aDb[1].pSchema); |
︙ | ︙ | |||
3931 3932 3933 3934 3935 3936 3937 | const char *zColumnName, /* Column name */ char const **pzDataType, /* OUTPUT: Declared data type */ char const **pzCollSeq, /* OUTPUT: Collation sequence name */ int *pNotNull, /* OUTPUT: True if NOT NULL constraint exists */ int *pPrimaryKey, /* OUTPUT: True if column part of PK */ int *pAutoinc /* OUTPUT: True if column is auto-increment */ ){ | | | > > | < < > > > > > > > | > > > > > > > > | 3943 3944 3945 3946 3947 3948 3949 3950 3951 3952 3953 3954 3955 3956 3957 3958 3959 3960 3961 3962 3963 3964 3965 3966 3967 3968 3969 3970 3971 3972 3973 3974 3975 3976 3977 3978 3979 3980 3981 3982 3983 3984 3985 3986 3987 3988 3989 3990 3991 3992 3993 3994 3995 3996 3997 3998 3999 | const char *zColumnName, /* Column name */ char const **pzDataType, /* OUTPUT: Declared data type */ char const **pzCollSeq, /* OUTPUT: Collation sequence name */ int *pNotNull, /* OUTPUT: True if NOT NULL constraint exists */ int *pPrimaryKey, /* OUTPUT: True if column part of PK */ int *pAutoinc /* OUTPUT: True if column is auto-increment */ ){ int rc = SQLITE_OK; char *zErrMsg = 0; Table *pTab = 0; Column *pCol = 0; int iCol = 0; char const *zDataType = 0; char const *zCollSeq = 0; int notnull = 0; int primarykey = 0; int autoinc = 0; int bUnlock; #ifdef SQLITE_ENABLE_API_ARMOR if( !sqlite3SafetyCheckOk(db) || zTableName==0 ){ return SQLITE_MISUSE_BKPT; } #endif /* Ensure the database schema has been loaded */ sqlite3_mutex_enter(db->mutex); bUnlock = sqlite3LockReusableSchema(db); sqlite3BtreeEnterAll(db); if( IsSharedSchema(db)==0 ){ rc = sqlite3Init(db, &zErrMsg); } /* Locate the table in question */ if( rc==SQLITE_OK ){ #ifdef SQLITE_ENABLE_SHARED_SCHEMA Parse sParse; /* Fake Parse object for FindTable */ Parse *pSaved = db->pParse; memset(&sParse, 0, sizeof(sParse)); db->pParse = &sParse; #endif pTab = sqlite3FindTable(db, zTableName, zDbName); #ifdef SQLITE_ENABLE_SHARED_SCHEMA sqlite3_free(sParse.zErrMsg); rc = sParse.rc; db->pParse = pSaved; #endif } if( SQLITE_OK!=rc ) goto error_out; if( !pTab || IsView(pTab) ){ pTab = 0; goto error_out; } /* Find the column for which info is requested */ if( zColumnName==0 ){ |
︙ | ︙ | |||
4031 4032 4033 4034 4035 4036 4037 4038 4039 4040 4041 4042 4043 4044 | zErrMsg = sqlite3MPrintf(db, "no such table column: %s.%s", zTableName, zColumnName); rc = SQLITE_ERROR; } sqlite3ErrorWithMsg(db, rc, (zErrMsg?"%s":0), zErrMsg); sqlite3DbFree(db, zErrMsg); rc = sqlite3ApiExit(db, rc); sqlite3_mutex_leave(db->mutex); return rc; } /* ** Sleep for a little while. Return the amount of time slept. */ | > | 4058 4059 4060 4061 4062 4063 4064 4065 4066 4067 4068 4069 4070 4071 4072 | zErrMsg = sqlite3MPrintf(db, "no such table column: %s.%s", zTableName, zColumnName); rc = SQLITE_ERROR; } sqlite3ErrorWithMsg(db, rc, (zErrMsg?"%s":0), zErrMsg); sqlite3DbFree(db, zErrMsg); rc = sqlite3ApiExit(db, rc); sqlite3UnlockReusableSchema(db, bUnlock); sqlite3_mutex_leave(db->mutex); return rc; } /* ** Sleep for a little while. Return the amount of time slept. */ |
︙ | ︙ |
Changes to src/pragma.c.
︙ | ︙ | |||
500 501 502 503 504 505 506 | /* IMP: R-43042-22504 No error messages are generated if an ** unknown pragma is issued. */ goto pragma_out; } /* Make sure the database schema is loaded if the pragma requires that */ if( (pPragma->mPragFlg & PragFlg_NeedSchema)!=0 ){ | > > > > > | > | 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 | /* IMP: R-43042-22504 No error messages are generated if an ** unknown pragma is issued. */ goto pragma_out; } /* Make sure the database schema is loaded if the pragma requires that */ if( (pPragma->mPragFlg & PragFlg_NeedSchema)!=0 ){ if( IsSharedSchema(db) && (zDb || (pPragma->mPragFlg & PragFlg_OneSchema)) ){ assert( iDb>=0 && iDb<db->nDb ); pParse->rc = sqlite3SchemaLoad(db, iDb, 0, &pParse->zErrMsg); if( pParse->rc ) goto pragma_out; }else{ if( sqlite3ReadSchema(pParse) ) goto pragma_out; } } /* Register the result column names for pragmas that return results */ if( (pPragma->mPragFlg & PragFlg_NoColumns)==0 && ((pPragma->mPragFlg & PragFlg_NoColumns1)==0 || zRight==0) ){ setPragmaResultColumnNames(v, pPragma); |
︙ | ︙ | |||
2291 2292 2293 2294 2295 2296 2297 | ** the schema-version is potentially dangerous and may lead to program ** crashes or database corruption. Use with caution! ** ** The user-version is not used internally by SQLite. It may be used by ** applications for any purpose. */ case PragTyp_HEADER_VALUE: { | | > | | 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 | ** the schema-version is potentially dangerous and may lead to program ** crashes or database corruption. Use with caution! ** ** The user-version is not used internally by SQLite. It may be used by ** applications for any purpose. */ case PragTyp_HEADER_VALUE: { int iCookie; /* Which cookie to read or write */ iCookie = pPragma->iArg & PRAGMA_HEADER_VALUE_MASK; sqlite3VdbeUsesBtree(v, iDb); if( zRight && (pPragma->iArg & PRAGMA_HEADER_VALUE_READONLY)==0 ){ /* Write the specified cookie value */ static const VdbeOpList setCookie[] = { { OP_Transaction, 0, 1, 0}, /* 0 */ { OP_SetCookie, 0, 0, 0}, /* 1 */ }; VdbeOp *aOp; sqlite3VdbeVerifyNoMallocRequired(v, ArraySize(setCookie)); |
︙ | ︙ |
Changes to src/pragma.h.
︙ | ︙ | |||
52 53 54 55 56 57 58 | #define PragTyp_LOCK_STATUS 44 #define PragTyp_STATS 45 /* Property flags associated with various pragma. */ #define PragFlg_NeedSchema 0x01 /* Force schema load before running */ #define PragFlg_NoColumns 0x02 /* OP_ResultRow called with zero columns */ #define PragFlg_NoColumns1 0x04 /* zero columns if RHS argument is present */ | | > > > > > > > | 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 | #define PragTyp_LOCK_STATUS 44 #define PragTyp_STATS 45 /* Property flags associated with various pragma. */ #define PragFlg_NeedSchema 0x01 /* Force schema load before running */ #define PragFlg_NoColumns 0x02 /* OP_ResultRow called with zero columns */ #define PragFlg_NoColumns1 0x04 /* zero columns if RHS argument is present */ #define PragFlg_OneSchema 0x08 /* Only a single schema required */ #define PragFlg_Result0 0x10 /* Acts as query when no argument */ #define PragFlg_Result1 0x20 /* Acts as query when has one argument */ #define PragFlg_SchemaOpt 0x40 /* Schema restricts name search if present */ #define PragFlg_SchemaReq 0x80 /* Schema required - "main" is default */ /* For PragTyp_HEADER_VALUE pragmas the Pragma.iArg value is set ** to the index of the header field to access (always 10 or less). ** Ored with HEADER_VALUE_READONLY if the field is read only. */ #define PRAGMA_HEADER_VALUE_READONLY 0x0100 #define PRAGMA_HEADER_VALUE_MASK 0x00FF /* Names of columns for pragmas that return multi-column result ** or that return single-column results where the name of the ** result column is different from the name of the pragma */ static const char *const pragCName[] = { /* 0 */ "id", /* Used by: foreign_key_list */ |
︙ | ︙ | |||
158 159 160 161 162 163 164 | /* ePragFlg: */ PragFlg_NoColumns1|PragFlg_Result0, /* ColNames: */ 0, 0, /* iArg: */ BTREE_APPLICATION_ID }, #endif #if !defined(SQLITE_OMIT_AUTOVACUUM) {/* zName: */ "auto_vacuum", /* ePragTyp: */ PragTyp_AUTO_VACUUM, | | | | 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 | /* ePragFlg: */ PragFlg_NoColumns1|PragFlg_Result0, /* ColNames: */ 0, 0, /* iArg: */ BTREE_APPLICATION_ID }, #endif #if !defined(SQLITE_OMIT_AUTOVACUUM) {/* zName: */ "auto_vacuum", /* ePragTyp: */ PragTyp_AUTO_VACUUM, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq|PragFlg_NoColumns1|PragFlg_OneSchema, /* ColNames: */ 0, 0, /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_FLAG_PRAGMAS) #if !defined(SQLITE_OMIT_AUTOMATIC_INDEX) {/* zName: */ "automatic_index", /* ePragTyp: */ PragTyp_FLAG, /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, /* ColNames: */ 0, 0, /* iArg: */ SQLITE_AutoIndex }, #endif #endif {/* zName: */ "busy_timeout", /* ePragTyp: */ PragTyp_BUSY_TIMEOUT, /* ePragFlg: */ PragFlg_Result0, /* ColNames: */ 56, 1, /* iArg: */ 0 }, #if !defined(SQLITE_OMIT_PAGER_PRAGMAS) {/* zName: */ "cache_size", /* ePragTyp: */ PragTyp_CACHE_SIZE, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq|PragFlg_NoColumns1|PragFlg_OneSchema, /* ColNames: */ 0, 0, /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_FLAG_PRAGMAS) {/* zName: */ "cache_spill", /* ePragTyp: */ PragTyp_CACHE_SPILL, /* ePragFlg: */ PragFlg_Result0|PragFlg_SchemaReq|PragFlg_NoColumns1, |
︙ | ︙ | |||
240 241 242 243 244 245 246 | /* ePragFlg: */ PragFlg_NoColumns1, /* ColNames: */ 0, 0, /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS) {/* zName: */ "data_version", /* ePragTyp: */ PragTyp_HEADER_VALUE, | | | | | 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 | /* ePragFlg: */ PragFlg_NoColumns1, /* ColNames: */ 0, 0, /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS) {/* zName: */ "data_version", /* ePragTyp: */ PragTyp_HEADER_VALUE, /* ePragFlg: */ PragFlg_Result0, /* ColNames: */ 0, 0, /* iArg: */ BTREE_DATA_VERSION|PRAGMA_HEADER_VALUE_READONLY }, #endif #if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS) {/* zName: */ "database_list", /* ePragTyp: */ PragTyp_DATABASE_LIST, /* ePragFlg: */ PragFlg_Result0, /* ColNames: */ 47, 3, /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_PAGER_PRAGMAS) && !defined(SQLITE_OMIT_DEPRECATED) {/* zName: */ "default_cache_size", /* ePragTyp: */ PragTyp_DEFAULT_CACHE_SIZE, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq|PragFlg_NoColumns1|PragFlg_OneSchema, /* ColNames: */ 55, 1, /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_FLAG_PRAGMAS) #if !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER) {/* zName: */ "defer_foreign_keys", /* ePragTyp: */ PragTyp_FLAG, |
︙ | ︙ | |||
291 292 293 294 295 296 297 | /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_Result1|PragFlg_SchemaOpt, /* ColNames: */ 43, 4, /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_FOREIGN_KEY) {/* zName: */ "foreign_key_list", /* ePragTyp: */ PragTyp_FOREIGN_KEY_LIST, | | | | | 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 | /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_Result1|PragFlg_SchemaOpt, /* ColNames: */ 43, 4, /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_FOREIGN_KEY) {/* zName: */ "foreign_key_list", /* ePragTyp: */ PragTyp_FOREIGN_KEY_LIST, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt|PragFlg_OneSchema, /* ColNames: */ 0, 8, /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_FLAG_PRAGMAS) #if !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER) {/* zName: */ "foreign_keys", /* ePragTyp: */ PragTyp_FLAG, /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, /* ColNames: */ 0, 0, /* iArg: */ SQLITE_ForeignKeys }, #endif #endif #if !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS) {/* zName: */ "freelist_count", /* ePragTyp: */ PragTyp_HEADER_VALUE, /* ePragFlg: */ PragFlg_Result0, /* ColNames: */ 0, 0, /* iArg: */ BTREE_FREE_PAGE_COUNT|PRAGMA_HEADER_VALUE_READONLY }, #endif #if !defined(SQLITE_OMIT_FLAG_PRAGMAS) {/* zName: */ "full_column_names", /* ePragTyp: */ PragTyp_FLAG, /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, /* ColNames: */ 0, 0, /* iArg: */ SQLITE_FullColNames }, |
︙ | ︙ | |||
349 350 351 352 353 354 355 | /* ColNames: */ 0, 0, /* iArg: */ SQLITE_IgnoreChecks }, #endif #endif #if !defined(SQLITE_OMIT_AUTOVACUUM) {/* zName: */ "incremental_vacuum", /* ePragTyp: */ PragTyp_INCREMENTAL_VACUUM, | | | 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 | /* ColNames: */ 0, 0, /* iArg: */ SQLITE_IgnoreChecks }, #endif #endif #if !defined(SQLITE_OMIT_AUTOVACUUM) {/* zName: */ "incremental_vacuum", /* ePragTyp: */ PragTyp_INCREMENTAL_VACUUM, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_NoColumns|PragFlg_OneSchema, /* ColNames: */ 0, 0, /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS) {/* zName: */ "index_info", /* ePragTyp: */ PragTyp_INDEX_INFO, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt, |
︙ | ︙ | |||
380 381 382 383 384 385 386 | /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_Result1|PragFlg_SchemaOpt, /* ColNames: */ 0, 0, /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_PAGER_PRAGMAS) {/* zName: */ "journal_mode", /* ePragTyp: */ PragTyp_JOURNAL_MODE, | | | 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 | /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_Result1|PragFlg_SchemaOpt, /* ColNames: */ 0, 0, /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_PAGER_PRAGMAS) {/* zName: */ "journal_mode", /* ePragTyp: */ PragTyp_JOURNAL_MODE, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq|PragFlg_OneSchema, /* ColNames: */ 0, 0, /* iArg: */ 0 }, {/* zName: */ "journal_size_limit", /* ePragTyp: */ PragTyp_JOURNAL_SIZE_LIMIT, /* ePragFlg: */ PragFlg_Result0|PragFlg_SchemaReq, /* ColNames: */ 0, 0, /* iArg: */ 0 }, |
︙ | ︙ | |||
418 419 420 421 422 423 424 | {/* zName: */ "locking_mode", /* ePragTyp: */ PragTyp_LOCKING_MODE, /* ePragFlg: */ PragFlg_Result0|PragFlg_SchemaReq, /* ColNames: */ 0, 0, /* iArg: */ 0 }, {/* zName: */ "max_page_count", /* ePragTyp: */ PragTyp_PAGE_COUNT, | | | 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 | {/* zName: */ "locking_mode", /* ePragTyp: */ PragTyp_LOCKING_MODE, /* ePragFlg: */ PragFlg_Result0|PragFlg_SchemaReq, /* ColNames: */ 0, 0, /* iArg: */ 0 }, {/* zName: */ "max_page_count", /* ePragTyp: */ PragTyp_PAGE_COUNT, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq|PragFlg_OneSchema, /* ColNames: */ 0, 0, /* iArg: */ 0 }, {/* zName: */ "mmap_size", /* ePragTyp: */ PragTyp_MMAP_SIZE, /* ePragFlg: */ 0, /* ColNames: */ 0, 0, /* iArg: */ 0 }, |
︙ | ︙ | |||
446 447 448 449 450 451 452 | /* ePragTyp: */ PragTyp_OPTIMIZE, /* ePragFlg: */ PragFlg_Result1|PragFlg_NeedSchema, /* ColNames: */ 0, 0, /* iArg: */ 0 }, #if !defined(SQLITE_OMIT_PAGER_PRAGMAS) {/* zName: */ "page_count", /* ePragTyp: */ PragTyp_PAGE_COUNT, | | | 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 | /* ePragTyp: */ PragTyp_OPTIMIZE, /* ePragFlg: */ PragFlg_Result1|PragFlg_NeedSchema, /* ColNames: */ 0, 0, /* iArg: */ 0 }, #if !defined(SQLITE_OMIT_PAGER_PRAGMAS) {/* zName: */ "page_count", /* ePragTyp: */ PragTyp_PAGE_COUNT, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq|PragFlg_OneSchema, /* ColNames: */ 0, 0, /* iArg: */ 0 }, {/* zName: */ "page_size", /* ePragTyp: */ PragTyp_PAGE_SIZE, /* ePragFlg: */ PragFlg_Result0|PragFlg_SchemaReq|PragFlg_NoColumns1, /* ColNames: */ 0, 0, /* iArg: */ 0 }, |
︙ | ︙ | |||
545 546 547 548 549 550 551 | /* ColNames: */ 0, 0, /* iArg: */ SQLITE_SqlTrace }, #endif #endif #if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS) && defined(SQLITE_DEBUG) {/* zName: */ "stats", /* ePragTyp: */ PragTyp_STATS, | | | | 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 | /* ColNames: */ 0, 0, /* iArg: */ SQLITE_SqlTrace }, #endif #endif #if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS) && defined(SQLITE_DEBUG) {/* zName: */ "stats", /* ePragTyp: */ PragTyp_STATS, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq|PragFlg_OneSchema, /* ColNames: */ 33, 5, /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_PAGER_PRAGMAS) {/* zName: */ "synchronous", /* ePragTyp: */ PragTyp_SYNCHRONOUS, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq|PragFlg_NoColumns1|PragFlg_OneSchema, /* ColNames: */ 0, 0, /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS) {/* zName: */ "table_info", /* ePragTyp: */ PragTyp_TABLE_INFO, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt, |
︙ | ︙ | |||
641 642 643 644 645 646 647 | {/* zName: */ "wal_autocheckpoint", /* ePragTyp: */ PragTyp_WAL_AUTOCHECKPOINT, /* ePragFlg: */ 0, /* ColNames: */ 0, 0, /* iArg: */ 0 }, {/* zName: */ "wal_checkpoint", /* ePragTyp: */ PragTyp_WAL_CHECKPOINT, | | | 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 | {/* zName: */ "wal_autocheckpoint", /* ePragTyp: */ PragTyp_WAL_AUTOCHECKPOINT, /* ePragFlg: */ 0, /* ColNames: */ 0, 0, /* iArg: */ 0 }, {/* zName: */ "wal_checkpoint", /* ePragTyp: */ PragTyp_WAL_CHECKPOINT, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_OneSchema, /* ColNames: */ 50, 3, /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_FLAG_PRAGMAS) {/* zName: */ "writable_schema", /* ePragTyp: */ PragTyp_FLAG, /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, /* ColNames: */ 0, 0, /* iArg: */ SQLITE_WriteSchema|SQLITE_NoSchemaError }, #endif }; /* Number of pragmas: 68 on by default, 78 total. */ |
Changes to src/prepare.c.
︙ | ︙ | |||
39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 | "error in %s %s after %s: %s", azObj[0], azObj[1], azAlterType[(pData->mInitFlags&INITFLAG_AlterMask)-1], zExtra ); pData->rc = SQLITE_ERROR; }else if( db->flags & SQLITE_WriteSchema ){ pData->rc = SQLITE_CORRUPT_BKPT; }else{ char *z; const char *zObj = azObj[1] ? azObj[1] : "?"; z = sqlite3MPrintf(db, "malformed database schema (%s)", zObj); if( zExtra && zExtra[0] ) z = sqlite3MPrintf(db, "%z - %s", z, zExtra); *pData->pzErrMsg = z; pData->rc = SQLITE_CORRUPT_BKPT; } } /* ** Check to see if any sibling index (another index on the same table) ** of pIndex has the same root page number, and if it does, return true. ** This would indicate a corrupt schema. */ int sqlite3IndexHasDuplicateRootPage(Index *pIndex){ Index *p; for(p=pIndex->pTable->pIndex; p; p=p->pNext){ if( p->tnum==pIndex->tnum && p!=pIndex ) return 1; } return 0; } /* forward declaration */ static int sqlite3Prepare( sqlite3 *db, /* Database handle. */ const char *zSql, /* UTF-8 encoded SQL statement. */ int nBytes, /* Length of zSql in bytes. */ u32 prepFlags, /* Zero or more SQLITE_PREPARE_* flags */ Vdbe *pReprepare, /* VM being reprepared */ sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */ const char **pzTail /* OUT: End of parsed string */ | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 | "error in %s %s after %s: %s", azObj[0], azObj[1], azAlterType[(pData->mInitFlags&INITFLAG_AlterMask)-1], zExtra ); pData->rc = SQLITE_ERROR; }else if( db->flags & SQLITE_WriteSchema ){ pData->rc = SQLITE_CORRUPT_BKPT; }else if( IsSharedSchema(db) && 0==sqlite3StrNICmp(zExtra, "malformed database schema", 17) ){ pData->rc = SQLITE_CORRUPT_BKPT; *pData->pzErrMsg = sqlite3DbStrDup(db, zExtra); }else{ char *z; const char *zObj = azObj[1] ? azObj[1] : "?"; z = sqlite3MPrintf(db, "malformed database schema (%s)", zObj); if( zExtra && zExtra[0] ) z = sqlite3MPrintf(db, "%z - %s", z, zExtra); *pData->pzErrMsg = z; pData->rc = SQLITE_CORRUPT_BKPT; } } #ifdef SQLITE_ENABLE_SHARED_SCHEMA /* ** Update the Schema.cksum checksum to account for the database object ** specified by the three arguments following the first. */ static void schemaUpdateChecksum( InitData *pData, /* Schema parse context */ const char *zName, /* Name of new database object */ const char *zRoot, /* Root page of new database object */ const char *zSql /* SQL used to create new database object */ ){ int i; u64 cksum = pData->cksum; if( zName ){ for(i=0; zName[i]; i++) cksum += (cksum<<3) + zName[i]; } if( zRoot ) for(i=0; zRoot[i]; i++) cksum += (cksum<<3) + zRoot[i]; if( zSql ) for(i=0; zSql[i]; i++) cksum += (cksum<<3) + zSql[i]; pData->cksum = cksum; } #endif /* ifdef SQLITE_ENABLE_SHARED_SCHEMA */ /* ** Check to see if any sibling index (another index on the same table) ** of pIndex has the same root page number, and if it does, return true. ** This would indicate a corrupt schema. */ int sqlite3IndexHasDuplicateRootPage(Index *pIndex){ Index *p; for(p=pIndex->pTable->pIndex; p; p=p->pNext){ if( p->tnum==pIndex->tnum && p!=pIndex ) return 1; } return 0; } /* forward declaration */ static int sqlite3Prepare( sqlite3 *db, /* Database handle. */ const char *zSql, /* UTF-8 encoded SQL statement. */ int nBytes, /* Length of zSql in bytes. */ u32 prepFlags, /* Zero or more SQLITE_PREPARE_* flags */ Vdbe *pReprepare, /* VM being reprepared */ sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */ const char **pzTail /* OUT: End of parsed string */ ); static int sqlite3LockAndPrepare( sqlite3 *db, /* Database handle. */ const char *zSql, /* UTF-8 encoded SQL statement. */ int nBytes, /* Length of zSql in bytes. */ u32 prepFlags, /* Zero or more SQLITE_PREPARE_* flags */ Vdbe *pReprepare, /* VM being reprepared */ sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */ const char **pzTail /* OUT: End of parsed string */ |
︙ | ︙ | |||
137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 | if( sqlite3Config.bExtraSchemaChecks ){ corruptSchema(pData, argv, "invalid rootpage"); } } db->init.orphanTrigger = 0; db->init.azInit = (const char**)argv; pStmt = 0; TESTONLY(rcp = ) sqlite3Prepare(db, argv[4], -1, 0, 0, &pStmt, 0); rc = db->errCode; assert( (rc&0xFF)==(rcp&0xFF) ); db->init.iDb = saved_iDb; /* assert( saved_iDb==0 || (db->mDbFlags & DBFLAG_Vacuum)!=0 ); */ if( SQLITE_OK!=rc ){ if( db->init.orphanTrigger ){ assert( iDb==1 ); }else{ if( rc > pData->rc ) pData->rc = rc; if( rc==SQLITE_NOMEM ){ sqlite3OomFault(db); | > > > > | > > > > | 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 | if( sqlite3Config.bExtraSchemaChecks ){ corruptSchema(pData, argv, "invalid rootpage"); } } db->init.orphanTrigger = 0; db->init.azInit = (const char**)argv; pStmt = 0; #ifdef SQLITE_ENABLE_SHARED_SCHEMA TESTONLY(rcp = ) sqlite3LockAndPrepare(db, argv[4], -1, 0, 0, &pStmt, 0); #else TESTONLY(rcp = ) sqlite3Prepare(db, argv[4], -1, 0, 0, &pStmt, 0); #endif rc = db->errCode; assert( (rc&0xFF)==(rcp&0xFF) ); db->init.iDb = saved_iDb; /* assert( saved_iDb==0 || (db->mDbFlags & DBFLAG_Vacuum)!=0 ); */ if( SQLITE_OK!=rc ){ if( db->init.orphanTrigger ){ assert( iDb==1 ); }else{ if( rc > pData->rc ) pData->rc = rc; if( rc==SQLITE_NOMEM ){ sqlite3OomFault(db); }else if( rc!=SQLITE_INTERRUPT && (rc&0xFF)!=SQLITE_LOCKED #ifdef SQLITE_ENABLE_SHARED_SCHEMA && (rc&0xFF)!=SQLITE_IOERR #endif ){ corruptSchema(pData, argv, sqlite3_errmsg(db)); } } } db->init.azInit = sqlite3StdType; /* Any array of string ptrs will do */ sqlite3_finalize(pStmt); }else if( argv[1]==0 || (argv[4]!=0 && argv[4][0]!=0) ){ |
︙ | ︙ | |||
180 181 182 183 184 185 186 187 188 189 190 191 192 193 | || sqlite3IndexHasDuplicateRootPage(pIndex) ){ if( sqlite3Config.bExtraSchemaChecks ){ corruptSchema(pData, argv, "invalid rootpage"); } } } return 0; } /* ** Attempt to read the database schema and initialize internal ** data structures for a single database file. The index of the ** database file is given by iDb. iDb==0 is used for the main | > > > > > > | 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 | || sqlite3IndexHasDuplicateRootPage(pIndex) ){ if( sqlite3Config.bExtraSchemaChecks ){ corruptSchema(pData, argv, "invalid rootpage"); } } } #ifdef SQLITE_ENABLE_SHARED_SCHEMA if( IsSharedSchema(db) && iDb!=1 ){ schemaUpdateChecksum(pData, argv[0], argv[1], argv[2]); } #endif return 0; } /* ** Attempt to read the database schema and initialize internal ** data structures for a single database file. The index of the ** database file is given by iDb. iDb==0 is used for the main |
︙ | ︙ | |||
207 208 209 210 211 212 213 | InitData initData; const char *zSchemaTabName; int openedTransaction = 0; int mask = ((db->mDbFlags & DBFLAG_EncodingFixed) | ~DBFLAG_EncodingFixed); assert( (db->mDbFlags & DBFLAG_SchemaKnownOk)==0 ); assert( iDb>=0 && iDb<db->nDb ); | | > > > > > > > > > > > > > > > > > > | 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 | InitData initData; const char *zSchemaTabName; int openedTransaction = 0; int mask = ((db->mDbFlags & DBFLAG_EncodingFixed) | ~DBFLAG_EncodingFixed); assert( (db->mDbFlags & DBFLAG_SchemaKnownOk)==0 ); assert( iDb>=0 && iDb<db->nDb ); assert( db->aDb[iDb].pSchema || (IsSharedSchema(db) && iDb!=1) ); assert( sqlite3_mutex_held(db->mutex) ); assert( iDb==1 || sqlite3BtreeHoldsMutex(db->aDb[iDb].pBt) ); pDb = &db->aDb[iDb]; #ifdef SQLITE_ENABLE_SHARED_SCHEMA assert( pDb->pSPool==0 || IsSharedSchema(db) ); if( pDb->pSPool ){ /* See if there is a free schema object in the schema-pool. If not, ** disconnect from said schema pool and continue. This function will ** connect to a (possibly different) schema-pool before returning. */ Schema *pNew = sqlite3SchemaExtract(pDb->pSPool); if( pNew ){ pDb->pSchema = pNew; return SQLITE_OK; } rc = sqlite3SchemaDisconnect(db, iDb, 1); if( rc!=SQLITE_OK ) goto error_out; assert( pDb->pSchema && pDb->pSPool==0 ); } #endif db->init.busy = 1; /* Construct the in-memory representation schema tables (sqlite_schema or ** sqlite_temp_schema) by invoking the parser directly. The appropriate ** table name will be inserted automatically by the parser so we can just ** use the abbreviation "x" here. The parser will also automatically tag |
︙ | ︙ | |||
231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 | azArg[5] = 0; initData.db = db; initData.iDb = iDb; initData.rc = SQLITE_OK; initData.pzErrMsg = pzErrMsg; initData.mInitFlags = mFlags; initData.nInitRow = 0; initData.mxPage = 0; sqlite3InitCallback(&initData, 5, (char **)azArg, 0); db->mDbFlags &= mask; if( initData.rc ){ rc = initData.rc; goto error_out; } /* Create a cursor to hold the database open */ | > < | 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 | azArg[5] = 0; initData.db = db; initData.iDb = iDb; initData.rc = SQLITE_OK; initData.pzErrMsg = pzErrMsg; initData.mInitFlags = mFlags; initData.nInitRow = 0; initData.cksum = 0; initData.mxPage = 0; sqlite3InitCallback(&initData, 5, (char **)azArg, 0); db->mDbFlags &= mask; if( initData.rc ){ rc = initData.rc; goto error_out; } /* Create a cursor to hold the database open */ if( pDb->pBt==0 ){ assert( iDb==1 ); DbSetProperty(db, 1, DB_SchemaLoaded); rc = SQLITE_OK; goto error_out; } |
︙ | ︙ | |||
406 407 408 409 410 411 412 413 414 415 416 417 418 419 | ** ** The primary purpose of this is to allow access to the sqlite_schema ** table even when its contents have been corrupted. */ DbSetProperty(db, iDb, DB_SchemaLoaded); rc = SQLITE_OK; } /* Jump here for an error that occurs after successfully allocating ** curMain and calling sqlite3BtreeEnter(). For an error that occurs ** before that point, jump to error_out. */ initone_error_out: if( openedTransaction ){ | > > > > | 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 | ** ** The primary purpose of this is to allow access to the sqlite_schema ** table even when its contents have been corrupted. */ DbSetProperty(db, iDb, DB_SchemaLoaded); rc = SQLITE_OK; } if( rc==SQLITE_OK && iDb!=1 && IsSharedSchema(db) ){ rc = sqlite3SchemaConnect(db, iDb, initData.cksum); } /* Jump here for an error that occurs after successfully allocating ** curMain and calling sqlite3BtreeEnter(). For an error that occurs ** before that point, jump to error_out. */ initone_error_out: if( openedTransaction ){ |
︙ | ︙ | |||
428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 | } sqlite3ResetOneSchema(db, iDb); } db->init.busy = 0; return rc; } /* ** Initialize all database files - the main database file, the file ** used to store temporary tables, and any additional database files ** created using ATTACH statements. Return a success code. If an ** error occurs, write an error message into *pzErrMsg. ** ** After a database is initialized, the DB_SchemaLoaded bit is set ** bit is set in the flags field of the Db structure. */ int sqlite3Init(sqlite3 *db, char **pzErrMsg){ | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > < | < | > | > | | 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 | } sqlite3ResetOneSchema(db, iDb); } db->init.busy = 0; return rc; } #ifdef SQLITE_ENABLE_SHARED_SCHEMA /* ** If this is a SHARED_SCHEMA connection and the DBFLAG_SchemaInUse flag ** is not currently set, set it and return non-zero. Otherwise, return 0. */ int sqlite3LockReusableSchema(sqlite3 *db){ if( IsSharedSchema(db) && (db->mDbFlags & DBFLAG_SchemaInuse)==0 ){ db->mDbFlags |= DBFLAG_SchemaInuse; return 1; } return 0; } #endif /* ifdef SQLITE_ENABLE_SHARED_SCHEMA */ #ifdef SQLITE_ENABLE_SHARED_SCHEMA /* ** This function is a no-op for non-SHARED_SCHEMA connections, or if bRelease ** is zero. Otherwise, clear the DBFLAG_SchemaInuse flag and release all ** schema references currently held. */ void sqlite3UnlockReusableSchema(sqlite3 *db, int bRelease){ if( bRelease ){ db->mDbFlags &= ~DBFLAG_SchemaInuse; sqlite3SchemaReleaseAll(db); } } #endif /* ifdef SQLITE_ENABLE_SHARED_SCHEMA */ /* ** Initialize all database files - the main database file, the file ** used to store temporary tables, and any additional database files ** created using ATTACH statements. Return a success code. If an ** error occurs, write an error message into *pzErrMsg. ** ** After a database is initialized, the DB_SchemaLoaded bit is set ** bit is set in the flags field of the Db structure. */ int sqlite3Init(sqlite3 *db, char **pzErrMsg){ int rc = SQLITE_OK; int bReleaseSchema; int i; int commit_internal = !(db->mDbFlags&DBFLAG_SchemaChange); bReleaseSchema = sqlite3LockReusableSchema(db); assert( sqlite3_mutex_held(db->mutex) ); assert( sqlite3BtreeHoldsMutex(db->aDb[0].pBt) ); assert( db->init.busy==0 ); ENC(db) = SCHEMA_ENC(db); assert( db->nDb>0 ); /* Do the main schema first */ if( !DbHasProperty(db, 0, DB_SchemaLoaded) ){ rc = sqlite3InitOne(db, 0, pzErrMsg, 0); } /* All other schemas after the main schema. The "temp" schema must be last */ for(i=db->nDb-1; rc==SQLITE_OK && i>0; i--){ assert( i==1 || sqlite3BtreeHoldsMutex(db->aDb[i].pBt) ); if( !DbHasProperty(db, i, DB_SchemaLoaded) ){ rc = sqlite3InitOne(db, i, pzErrMsg, 0); } } if( rc==SQLITE_OK && commit_internal ){ sqlite3CommitInternalChanges(db); } sqlite3UnlockReusableSchema(db, bReleaseSchema); return rc; } /* ** This routine is a no-op if the database schema is already initialized. ** Otherwise, the schema is loaded. An error code is returned. */ int sqlite3ReadSchema(Parse *pParse){ int rc = SQLITE_OK; sqlite3 *db = pParse->db; assert( sqlite3_mutex_held(db->mutex) ); if( !db->init.busy ){ db->mDbFlags |= DBFLAG_FreeSchema; /* For sharable-schema mode */ rc = sqlite3Init(db, &pParse->zErrMsg); if( rc!=SQLITE_OK ){ pParse->rc = rc; pParse->nErr++; }else if( db->noSharedCache && !IsSharedSchema(db) ){ db->mDbFlags |= DBFLAG_SchemaKnownOk; } } return rc; } |
︙ | ︙ | |||
503 504 505 506 507 508 509 510 511 512 513 514 515 516 | assert( pParse->checkSchema ); assert( sqlite3_mutex_held(db->mutex) ); for(iDb=0; iDb<db->nDb; iDb++){ int openedTransaction = 0; /* True if a transaction is opened */ Btree *pBt = db->aDb[iDb].pBt; /* Btree database to read cookie from */ if( pBt==0 ) continue; /* If there is not already a read-only (or read-write) transaction opened ** on the b-tree database, open one now. If a transaction is opened, it ** will be closed immediately after reading the meta-value. */ if( sqlite3BtreeTxnState(pBt)==SQLITE_TXN_NONE ){ rc = sqlite3BtreeBeginTrans(pBt, 0, 0); if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ){ | > > > > | 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 | assert( pParse->checkSchema ); assert( sqlite3_mutex_held(db->mutex) ); for(iDb=0; iDb<db->nDb; iDb++){ int openedTransaction = 0; /* True if a transaction is opened */ Btree *pBt = db->aDb[iDb].pBt; /* Btree database to read cookie from */ if( pBt==0 ) continue; #ifdef SQLITE_ENABLE_SHARED_SCHEMA if( IsSharedSchema(db) && iDb!=1 && db->aDb[iDb].pSPool==0 ) continue; #endif /* If there is not already a read-only (or read-write) transaction opened ** on the b-tree database, open one now. If a transaction is opened, it ** will be closed immediately after reading the meta-value. */ if( sqlite3BtreeTxnState(pBt)==SQLITE_TXN_NONE ){ rc = sqlite3BtreeBeginTrans(pBt, 0, 0); if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ){ |
︙ | ︙ | |||
840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 | u32 prepFlags, /* Zero or more SQLITE_PREPARE_* flags */ Vdbe *pOld, /* VM being reprepared */ sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */ const char **pzTail /* OUT: End of parsed string */ ){ int rc; int cnt = 0; #ifdef SQLITE_ENABLE_API_ARMOR if( ppStmt==0 ) return SQLITE_MISUSE_BKPT; #endif *ppStmt = 0; if( !sqlite3SafetyCheckOk(db)||zSql==0 ){ return SQLITE_MISUSE_BKPT; } sqlite3_mutex_enter(db->mutex); sqlite3BtreeEnterAll(db); do{ /* Make multiple attempts to compile the SQL, until it either succeeds ** or encounters a permanent error. A schema problem after one schema ** reset is considered a permanent error. */ rc = sqlite3Prepare(db, zSql, nBytes, prepFlags, pOld, ppStmt, pzTail); assert( rc==SQLITE_OK || *ppStmt==0 ); if( rc==SQLITE_OK || db->mallocFailed ) break; }while( (rc==SQLITE_ERROR_RETRY && (cnt++)<SQLITE_MAX_PREPARE_RETRY) || (rc==SQLITE_SCHEMA && (sqlite3ResetOneSchema(db,-1), cnt++)==0) ); sqlite3BtreeLeaveAll(db); rc = sqlite3ApiExit(db, rc); assert( (rc&db->errMask)==rc ); db->busyHandler.nBusy = 0; sqlite3_mutex_leave(db->mutex); assert( rc==SQLITE_OK || (*ppStmt)==0 ); return rc; } | > > > > > > | 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 | u32 prepFlags, /* Zero or more SQLITE_PREPARE_* flags */ Vdbe *pOld, /* VM being reprepared */ sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */ const char **pzTail /* OUT: End of parsed string */ ){ int rc; int cnt = 0; int bReleaseSchema = 0; #ifdef SQLITE_ENABLE_API_ARMOR if( ppStmt==0 ) return SQLITE_MISUSE_BKPT; #endif *ppStmt = 0; if( !sqlite3SafetyCheckOk(db)||zSql==0 ){ return SQLITE_MISUSE_BKPT; } sqlite3_mutex_enter(db->mutex); bReleaseSchema = sqlite3LockReusableSchema(db); sqlite3BtreeEnterAll(db); do{ /* Make multiple attempts to compile the SQL, until it either succeeds ** or encounters a permanent error. A schema problem after one schema ** reset is considered a permanent error. */ rc = sqlite3Prepare(db, zSql, nBytes, prepFlags, pOld, ppStmt, pzTail); assert( rc==SQLITE_OK || *ppStmt==0 ); if( rc==SQLITE_OK || db->mallocFailed ) break; }while( (rc==SQLITE_ERROR_RETRY && (cnt++)<SQLITE_MAX_PREPARE_RETRY) || (rc==SQLITE_SCHEMA && (sqlite3ResetOneSchema(db,-1), cnt++)==0) ); sqlite3BtreeLeaveAll(db); sqlite3UnlockReusableSchema(db, bReleaseSchema); rc = sqlite3ApiExit(db, rc); assert( (rc&db->errMask)==rc ); db->busyHandler.nBusy = 0; sqlite3_mutex_leave(db->mutex); assert( rc==SQLITE_OK || (*ppStmt)==0 ); return rc; } |
︙ | ︙ |
Changes to src/shell.c.in.
︙ | ︙ | |||
1380 1381 1382 1383 1384 1385 1386 | #define AUTOEQP_off 0 /* Automatic EXPLAIN QUERY PLAN is off */ #define AUTOEQP_on 1 /* Automatic EQP is on */ #define AUTOEQP_trigger 2 /* On and also show plans for triggers */ #define AUTOEQP_full 3 /* Show full EXPLAIN */ /* Allowed values for ShellState.openMode */ | | | | | | | | > | 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 | #define AUTOEQP_off 0 /* Automatic EXPLAIN QUERY PLAN is off */ #define AUTOEQP_on 1 /* Automatic EQP is on */ #define AUTOEQP_trigger 2 /* On and also show plans for triggers */ #define AUTOEQP_full 3 /* Show full EXPLAIN */ /* Allowed values for ShellState.openMode */ #define SHELL_OPEN_UNSPEC 0 /* No open-mode specified */ #define SHELL_OPEN_NORMAL 1 /* Normal database file */ #define SHELL_OPEN_APPENDVFS 2 /* Use appendvfs */ #define SHELL_OPEN_ZIPFILE 3 /* Use the zipfile virtual table */ #define SHELL_OPEN_READONLY 4 /* Open a normal database read-only */ #define SHELL_OPEN_DESERIALIZE 5 /* Open using sqlite3_deserialize() */ #define SHELL_OPEN_HEXDB 6 /* Use "dbtotxt" output as data source */ #define SHELL_OPEN_SHAREDSCHEMA 7 /* Open for schema reuse */ /* Allowed values for ShellState.eTraceType */ #define SHELL_TRACE_PLAIN 0 /* Show input SQL text */ #define SHELL_TRACE_EXPANDED 1 /* Show expanded SQL text */ #define SHELL_TRACE_NORMALIZED 2 /* Show normalized SQL text */ |
︙ | ︙ | |||
4879 4880 4881 4882 4883 4884 4885 4886 4887 4888 4889 4890 4891 4892 | " Options:", " --schema Also hash the sqlite_schema table", " --sha3-224 Use the sha3-224 algorithm", " --sha3-256 Use the sha3-256 algorithm (default)", " --sha3-384 Use the sha3-384 algorithm", " --sha3-512 Use the sha3-512 algorithm", " Any other argument is a LIKE pattern for tables to hash", #if !defined(SQLITE_NOHAVE_SYSTEM) && !defined(SQLITE_SHELL_FIDDLE) ".shell CMD ARGS... Run CMD ARGS... in a system shell", #endif ".show Show the current values for various settings", ".stats ?ARG? Show stats or turn stats on or off", " off Turn off automatic stat display", " on Turn on automatic stat display", | > > > > > > | 4880 4881 4882 4883 4884 4885 4886 4887 4888 4889 4890 4891 4892 4893 4894 4895 4896 4897 4898 4899 | " Options:", " --schema Also hash the sqlite_schema table", " --sha3-224 Use the sha3-224 algorithm", " --sha3-256 Use the sha3-256 algorithm (default)", " --sha3-384 Use the sha3-384 algorithm", " --sha3-512 Use the sha3-512 algorithm", " Any other argument is a LIKE pattern for tables to hash", #if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_ENABLE_DBPAGE_VTAB) ".shared-schema CMD DB1 DB2 ...", " Commands:", " check Determine if DB1, DB2, etc have identical schemas", " fix Attempt to make DB1, DB2, etc compatible", #endif #if !defined(SQLITE_NOHAVE_SYSTEM) && !defined(SQLITE_SHELL_FIDDLE) ".shell CMD ARGS... Run CMD ARGS... in a system shell", #endif ".show Show the current values for various settings", ".stats ?ARG? Show stats or turn stats on or off", " off Turn off automatic stat display", " on Turn on automatic stat display", |
︙ | ︙ | |||
5321 5322 5323 5324 5325 5326 5327 5328 5329 5330 5331 5332 5333 5334 | sqlite3_open(":memory:", &p->db); break; } case SHELL_OPEN_READONLY: { sqlite3_open_v2(zDbFilename, &p->db, SQLITE_OPEN_READONLY|p->openFlags, 0); break; } case SHELL_OPEN_UNSPEC: case SHELL_OPEN_NORMAL: { sqlite3_open_v2(zDbFilename, &p->db, SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|p->openFlags, 0); break; } | > > > > > | 5328 5329 5330 5331 5332 5333 5334 5335 5336 5337 5338 5339 5340 5341 5342 5343 5344 5345 5346 | sqlite3_open(":memory:", &p->db); break; } case SHELL_OPEN_READONLY: { sqlite3_open_v2(zDbFilename, &p->db, SQLITE_OPEN_READONLY|p->openFlags, 0); break; } case SHELL_OPEN_SHAREDSCHEMA: { sqlite3_open_v2(p->pAuxDb->zDbFilename, &p->db, SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|SQLITE_OPEN_SHARED_SCHEMA,0); break; } case SHELL_OPEN_UNSPEC: case SHELL_OPEN_NORMAL: { sqlite3_open_v2(zDbFilename, &p->db, SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|p->openFlags, 0); break; } |
︙ | ︙ | |||
7572 7573 7574 7575 7576 7577 7578 7579 | sqlite3_free(cmd.zSrcTable); return rc; } /* End of the ".archive" or ".ar" command logic *******************************************************************************/ #endif /* !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_HAVE_ZLIB) */ | > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 7584 7585 7586 7587 7588 7589 7590 7591 7592 7593 7594 7595 7596 7597 7598 7599 7600 7601 7602 7603 7604 7605 7606 7607 7608 7609 7610 7611 7612 7613 7614 7615 7616 7617 7618 7619 7620 7621 7622 7623 7624 7625 7626 7627 7628 7629 7630 7631 7632 7633 7634 7635 7636 7637 7638 7639 7640 7641 7642 7643 7644 7645 7646 7647 7648 7649 7650 7651 7652 7653 7654 7655 7656 7657 7658 7659 7660 7661 7662 7663 7664 7665 7666 7667 7668 7669 7670 7671 7672 7673 7674 7675 7676 7677 7678 7679 7680 7681 7682 7683 7684 7685 7686 7687 7688 7689 7690 7691 7692 7693 7694 7695 7696 7697 7698 7699 7700 7701 7702 7703 7704 7705 7706 7707 7708 7709 7710 7711 7712 7713 7714 7715 7716 7717 7718 7719 7720 7721 7722 7723 7724 7725 7726 7727 7728 7729 7730 7731 7732 7733 7734 7735 7736 7737 7738 7739 7740 7741 7742 7743 7744 7745 7746 7747 7748 7749 7750 7751 7752 7753 7754 7755 7756 7757 7758 7759 7760 7761 7762 7763 7764 7765 7766 7767 7768 7769 7770 7771 7772 7773 7774 7775 7776 7777 7778 7779 7780 7781 7782 7783 7784 7785 7786 7787 7788 7789 7790 7791 7792 7793 7794 7795 7796 7797 7798 7799 7800 7801 7802 7803 7804 7805 7806 7807 7808 7809 7810 7811 7812 7813 7814 7815 7816 7817 7818 7819 7820 7821 7822 7823 7824 7825 7826 7827 7828 7829 7830 7831 7832 7833 7834 7835 7836 7837 7838 7839 7840 7841 7842 7843 7844 7845 7846 7847 7848 7849 7850 7851 7852 7853 7854 7855 7856 7857 7858 7859 7860 7861 7862 7863 7864 7865 7866 7867 7868 7869 | sqlite3_free(cmd.zSrcTable); return rc; } /* End of the ".archive" or ".ar" command logic *******************************************************************************/ #endif /* !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_HAVE_ZLIB) */ /* ** If (*pRc) is not SQLITE_OK when this function is called, it is a no-op. ** Otherwise, the SQL statement or statements in zSql are executed using ** database connection db and the error code written to *pRc before ** this function returns. */ static void shellExec(sqlite3 *db, int *pRc, const char *zSql){ int rc = *pRc; if( rc==SQLITE_OK ){ char *zErr = 0; rc = sqlite3_exec(db, zSql, 0, 0, &zErr); if( rc!=SQLITE_OK ){ sputf(stderr, "SQL error: %s\n", zErr); } sqlite3_free(zErr); *pRc = rc; } } /* ** Like shellExec(), except that zFmt is a printf() style format string. */ static void shellExecPrintf(sqlite3 *db, int *pRc, const char *zFmt, ...){ char *z = 0; if( *pRc==SQLITE_OK ){ va_list ap; va_start(ap, zFmt); z = sqlite3_vmprintf(zFmt, ap); va_end(ap); if( z==0 ){ *pRc = SQLITE_NOMEM; }else{ shellExec(db, pRc, z); } sqlite3_free(z); } } static int sharedSchemaFix(ShellState *pState, const char *zDb){ int rc = SQLITE_OK; i64 iLast = 0; int iCookie = 0; int iAutoVacuum = 0; sqlite3_stmt *pStmt = 0; shellExecPrintf(pState->db, &rc, "ATTACH '%q' AS _shared_schema_tmp", zDb); shellExecPrintf(pState->db, &rc, "PRAGMA writable_schema = 1"); shellExecPrintf(pState->db, &rc, "BEGIN"); shellPreparePrintf(pState->db, &rc, &pStmt, "SELECT max(rowid) FROM _shared_schema_tmp.sqlite_master" ); sqlite3_step(pStmt); iLast = sqlite3_column_int64(pStmt, 0); shellFinalize(&rc, pStmt); shellPreparePrintf(pState->db, &rc, &pStmt, "INSERT INTO _shared_schema_tmp.sqlite_master SELECT " " type, name, tbl_name, (" " SELECT rootpage FROM _shared_schema_tmp.sqlite_master WHERE " " type IS o.type AND name IS o.name AND rowid<=?" " ), sql FROM main.sqlite_master AS o" ); sqlite3_bind_int64(pStmt, 1, iLast); sqlite3_step(pStmt); shellFinalize(&rc, pStmt); shellExecPrintf(pState->db, &rc, "DELETE FROM _shared_schema_tmp.sqlite_master WHERE rowid<=%lld", iLast ); shellExecPrintf(pState->db, &rc, "COMMIT"); sqlite3_exec(pState->db, "PRAGMA writable_schema = 0", 0, 0, 0); /* Copy the auto-vacuum setting from main to the target db */ shellPreparePrintf(pState->db, &rc, &pStmt, "PRAGMA main.auto_vacuum"); sqlite3_step(pStmt); iAutoVacuum = sqlite3_column_int(pStmt, 0); shellFinalize(&rc, pStmt); shellExecPrintf(pState->db, &rc, "PRAGMA _shared_schema_tmp.auto_vacuum = %d", iAutoVacuum ); /* Vacuum the db in order to standardize the rootpage numbers. */ shellExecPrintf(pState->db, &rc, "VACUUM _shared_schema_tmp"); /* Set the schema-cookie value to the same as database "main" */ shellPreparePrintf(pState->db, &rc, &pStmt, "PRAGMA main.schema_version"); sqlite3_step(pStmt); iCookie = sqlite3_column_int(pStmt, 0); shellFinalize(&rc, pStmt); shellExecPrintf(pState->db, &rc, "PRAGMA _shared_schema_tmp.schema_version = %d", iCookie ); sqlite3_exec(pState->db, "DETACH _shared_schema_tmp", 0, 0, 0); return rc; } static int sharedSchemaCheck(ShellState *pState, const char *zDb, int *peFix){ int rc = SQLITE_OK; int bFailed = 0; sqlite3_stmt *pStmt = 0; if( peFix ) *peFix = 0; shellExecPrintf(pState->db, &rc, "ATTACH '%q' AS _shared_schema_tmp", zDb); /* Check if this database has the same set of objects as the current db */ shellPreparePrintf(pState->db, &rc, &pStmt, "SELECT type, name FROM _shared_schema_tmp.sqlite_master AS o " "WHERE NOT EXISTS (" " SELECT 1 FROM main.sqlite_master " " WHERE name IS o.name AND type IS o.type" ")" " UNION ALL " "SELECT type, name FROM main.sqlite_master AS o " "WHERE NOT EXISTS (" " SELECT 1 FROM _shared_schema_tmp.sqlite_master " " WHERE name IS o.name AND type IS o.type" ")" ); if( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){ sputf(pState->out, "%s is NOT compatible (objects)\n", zDb); bFailed = 1; } shellFinalize(&rc, pStmt); /* Check if this database has the same set of SQL statements as the ** current db. */ if( bFailed==0 ){ shellPreparePrintf(pState->db, &rc, &pStmt, "SELECT 1 FROM _shared_schema_tmp.sqlite_master AS o " "WHERE sql IS NOT (" " SELECT sql FROM main.sqlite_master " " WHERE name IS o.name AND type IS o.type" ")" ); if( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){ sputf(pState->out, "%s is NOT compatible (SQL)\n", zDb); bFailed = 1; } shellFinalize(&rc, pStmt); } /* Check if this database has the same set of root pages as the current ** db. */ if( bFailed==0 ){ shellPreparePrintf(pState->db, &rc, &pStmt, "SELECT 1 FROM _shared_schema_tmp.sqlite_master AS o " "WHERE rootpage IS NOT (" " SELECT rootpage FROM main.sqlite_master " " WHERE name IS o.name AND type IS o.type" ")" ); if( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){ if( peFix==0 ){ sputf(pState->out, "%s is NOT compatible (root pages)\n", zDb); } bFailed = 1; if( peFix ) *peFix = 1; } shellFinalize(&rc, pStmt); } if( bFailed==0 ){ shellPreparePrintf(pState->db, &rc, &pStmt, "SELECT 1 WHERE (" " SELECT group_concat(rootpage || '.' || name || '.' || sql, '.') " " FROM _shared_schema_tmp.sqlite_master" ") IS NOT (" " SELECT group_concat(rootpage || '.' || name || '.' || sql, '.') " " FROM main.sqlite_master" ")" ); if( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){ if( peFix==0 ){ sputf(pState->out, "%s is NOT compatible (order of sqlite_master rows)\n", zDb ); } bFailed = 1; if( peFix ) *peFix = 2; } shellFinalize(&rc, pStmt); } if( bFailed==0 ){ int iMain = -1; int iNew = +1; shellPreparePrintf(pState->db, &rc, &pStmt, "PRAGMA main.schema_version" ); if( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){ iMain = sqlite3_column_int(pStmt, 0); } shellFinalize(&rc, pStmt); shellPreparePrintf(pState->db, &rc, &pStmt, "PRAGMA _shared_schema_tmp.schema_version" ); if( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){ iNew = sqlite3_column_int(pStmt, 0); } shellFinalize(&rc, pStmt); if( rc==SQLITE_OK && iMain!=iNew ){ if( peFix==0 ){ sputf(pState->out, "%s is NOT compatible (schema cookie)\n", zDb ); } bFailed = 1; if( peFix ) *peFix = 3; } } if( rc==SQLITE_OK && bFailed==0 ){ sputf(pState->out, "%s is compatible\n", zDb); } sqlite3_exec(pState->db, "DETACH _shared_schema_tmp", 0, 0, 0); return rc; } /* ** .shared-schema check|fix DB1 DB2... */ static int sharedSchemaDotCommand( ShellState *pState, /* Current shell tool state */ char **azArg, /* Array of arguments passed to dot command */ int nArg /* Number of entries in azArg[] */ ){ int rc = SQLITE_OK; int bFix = 0; /* Fix databases if possible */ int n1; int i; if( nArg<3 ){ goto shared_schema_usage; } n1 = (int)strlen(azArg[1]); if( n1>0 && n1<=3 && memcmp("fix", azArg[1], n1)==0 ){ bFix = 1; }else if( n1==0 || n1>5 || memcmp("check", azArg[1], n1) ){ goto shared_schema_usage; } for(i=2; rc==SQLITE_OK && i<nArg; i++){ int eFix = 0; rc = sharedSchemaCheck(pState, azArg[i], bFix ? &eFix : 0); if( rc==SQLITE_OK && bFix && eFix ){ sputf(pState->out, "Fixing %s... ", azArg[i]); fflush(pState->out); rc = sharedSchemaFix(pState, azArg[i]); if( rc==SQLITE_OK ){ rc = sharedSchemaCheck(pState, azArg[i], &eFix); if( rc==SQLITE_OK && eFix ){ sputf(pState->out, "VACUUMing main... "); fflush(pState->out); rc = sqlite3_exec(pState->db, "VACUUM main", 0, 0, 0); if( rc==SQLITE_OK ){ rc = sharedSchemaCheck(pState, azArg[i], 0); } } } } } return rc; shared_schema_usage: sputf(stderr, "usage: .shared-schema check|fix DB1 DB2...\n"); return SQLITE_ERROR; } #if SQLITE_SHELL_HAVE_RECOVER /* ** This function is used as a callback by the recover extension. Simply ** print the supplied SQL statement to stdout. */ static int recoverSqlCb(void *pCtx, const char *zSql){ ShellState *pState = (ShellState*)pCtx; sputf(pState->out, "%s;\n", zSql); |
︙ | ︙ | |||
10641 10642 10643 10644 10645 10646 10647 10648 10649 10650 10651 10652 10653 10654 | } if( rc ) eputz(".sha3sum failed.\n"); sqlite3_free(zRevText); } #endif /* !defined(*_OMIT_SCHEMA_PRAGMAS) && !defined(*_OMIT_VIRTUALTABLE) */ sqlite3_free(zSql); }else #if !defined(SQLITE_NOHAVE_SYSTEM) && !defined(SQLITE_SHELL_FIDDLE) if( c=='s' && (cli_strncmp(azArg[0], "shell", n)==0 || cli_strncmp(azArg[0],"system",n)==0) ){ char *zCmd; | > > > > > > > | 10922 10923 10924 10925 10926 10927 10928 10929 10930 10931 10932 10933 10934 10935 10936 10937 10938 10939 10940 10941 10942 | } if( rc ) eputz(".sha3sum failed.\n"); sqlite3_free(zRevText); } #endif /* !defined(*_OMIT_SCHEMA_PRAGMAS) && !defined(*_OMIT_VIRTUALTABLE) */ sqlite3_free(zSql); }else #if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_ENABLE_DBPAGE_VTAB) if( c=='s' && strncmp(azArg[0], "shared-schema", n)==0 ){ open_db(p, 0); sharedSchemaDotCommand(p, azArg, nArg); }else #endif #if !defined(SQLITE_NOHAVE_SYSTEM) && !defined(SQLITE_SHELL_FIDDLE) if( c=='s' && (cli_strncmp(azArg[0], "shell", n)==0 || cli_strncmp(azArg[0],"system",n)==0) ){ char *zCmd; |
︙ | ︙ | |||
12435 12436 12437 12438 12439 12440 12441 12442 12443 12444 12445 12446 12447 12448 | }else if( cli_strcmp(z,"-deserialize")==0 ){ data.openMode = SHELL_OPEN_DESERIALIZE; }else if( cli_strcmp(z,"-maxsize")==0 && i+1<argc ){ data.szMax = integerValue(argv[++i]); #endif }else if( cli_strcmp(z,"-readonly")==0 ){ data.openMode = SHELL_OPEN_READONLY; }else if( cli_strcmp(z,"-nofollow")==0 ){ data.openFlags = SQLITE_OPEN_NOFOLLOW; #if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_HAVE_ZLIB) }else if( cli_strncmp(z, "-A",2)==0 ){ /* All remaining command-line arguments are passed to the ".archive" ** command, so ignore them */ break; | > > | 12723 12724 12725 12726 12727 12728 12729 12730 12731 12732 12733 12734 12735 12736 12737 12738 | }else if( cli_strcmp(z,"-deserialize")==0 ){ data.openMode = SHELL_OPEN_DESERIALIZE; }else if( cli_strcmp(z,"-maxsize")==0 && i+1<argc ){ data.szMax = integerValue(argv[++i]); #endif }else if( cli_strcmp(z,"-readonly")==0 ){ data.openMode = SHELL_OPEN_READONLY; }else if( strcmp(z,"-sharedschema")==0 ){ data.openMode = SHELL_OPEN_SHAREDSCHEMA; }else if( cli_strcmp(z,"-nofollow")==0 ){ data.openFlags = SQLITE_OPEN_NOFOLLOW; #if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_HAVE_ZLIB) }else if( cli_strncmp(z, "-A",2)==0 ){ /* All remaining command-line arguments are passed to the ".archive" ** command, so ignore them */ break; |
︙ | ︙ | |||
12565 12566 12567 12568 12569 12570 12571 12572 12573 12574 12575 12576 12577 12578 | }else if( cli_strcmp(z,"-deserialize")==0 ){ data.openMode = SHELL_OPEN_DESERIALIZE; }else if( cli_strcmp(z,"-maxsize")==0 && i+1<argc ){ data.szMax = integerValue(argv[++i]); #endif }else if( cli_strcmp(z,"-readonly")==0 ){ data.openMode = SHELL_OPEN_READONLY; }else if( cli_strcmp(z,"-nofollow")==0 ){ data.openFlags |= SQLITE_OPEN_NOFOLLOW; }else if( cli_strcmp(z,"-ascii")==0 ){ data.mode = MODE_Ascii; sqlite3_snprintf(sizeof(data.colSeparator), data.colSeparator,SEP_Unit); sqlite3_snprintf(sizeof(data.rowSeparator), data.rowSeparator,SEP_Record); }else if( cli_strcmp(z,"-tabs")==0 ){ | > > | 12855 12856 12857 12858 12859 12860 12861 12862 12863 12864 12865 12866 12867 12868 12869 12870 | }else if( cli_strcmp(z,"-deserialize")==0 ){ data.openMode = SHELL_OPEN_DESERIALIZE; }else if( cli_strcmp(z,"-maxsize")==0 && i+1<argc ){ data.szMax = integerValue(argv[++i]); #endif }else if( cli_strcmp(z,"-readonly")==0 ){ data.openMode = SHELL_OPEN_READONLY; }else if( strcmp(z,"-sharedschema")==0 ){ data.openMode = SHELL_OPEN_SHAREDSCHEMA; }else if( cli_strcmp(z,"-nofollow")==0 ){ data.openFlags |= SQLITE_OPEN_NOFOLLOW; }else if( cli_strcmp(z,"-ascii")==0 ){ data.mode = MODE_Ascii; sqlite3_snprintf(sizeof(data.colSeparator), data.colSeparator,SEP_Unit); sqlite3_snprintf(sizeof(data.rowSeparator), data.rowSeparator,SEP_Record); }else if( cli_strcmp(z,"-tabs")==0 ){ |
︙ | ︙ |
Changes to src/sqlite.h.in.
︙ | ︙ | |||
612 613 614 615 616 617 618 619 620 | #define SQLITE_OPEN_SHAREDCACHE 0x00020000 /* Ok for sqlite3_open_v2() */ #define SQLITE_OPEN_PRIVATECACHE 0x00040000 /* Ok for sqlite3_open_v2() */ #define SQLITE_OPEN_WAL 0x00080000 /* VFS only */ #define SQLITE_OPEN_NOFOLLOW 0x01000000 /* Ok for sqlite3_open_v2() */ #define SQLITE_OPEN_EXRESCODE 0x02000000 /* Extended result codes */ /* Reserved: 0x00F00000 */ /* Legacy compatibility: */ #define SQLITE_OPEN_MASTER_JOURNAL 0x00004000 /* VFS only */ | > > < | 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 | #define SQLITE_OPEN_SHAREDCACHE 0x00020000 /* Ok for sqlite3_open_v2() */ #define SQLITE_OPEN_PRIVATECACHE 0x00040000 /* Ok for sqlite3_open_v2() */ #define SQLITE_OPEN_WAL 0x00080000 /* VFS only */ #define SQLITE_OPEN_NOFOLLOW 0x01000000 /* Ok for sqlite3_open_v2() */ #define SQLITE_OPEN_EXRESCODE 0x02000000 /* Extended result codes */ /* Reserved: 0x00F00000 */ #define SQLITE_OPEN_SHARED_SCHEMA 0x01000000 /* Ok for sqlite3_open_v2() */ /* Legacy compatibility: */ #define SQLITE_OPEN_MASTER_JOURNAL 0x00004000 /* VFS only */ /* ** CAPI3REF: Device Characteristics ** ** The xDeviceCharacteristics method of the [sqlite3_io_methods] ** object returns an integer which is a vector of these ** bit values expressing I/O characteristics of the mass storage |
︙ | ︙ |
Changes to src/sqliteInt.h.
︙ | ︙ | |||
1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 | typedef struct Column Column; typedef struct Cte Cte; typedef struct CteUse CteUse; typedef struct Db Db; typedef struct DbClientData DbClientData; typedef struct DbFixer DbFixer; typedef struct Schema Schema; typedef struct Expr Expr; typedef struct ExprList ExprList; typedef struct FKey FKey; typedef struct FpDecode FpDecode; typedef struct FuncDestructor FuncDestructor; typedef struct FuncDef FuncDef; typedef struct FuncDefHash FuncDefHash; | > | 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 | typedef struct Column Column; typedef struct Cte Cte; typedef struct CteUse CteUse; typedef struct Db Db; typedef struct DbClientData DbClientData; typedef struct DbFixer DbFixer; typedef struct Schema Schema; typedef struct SchemaPool SchemaPool; typedef struct Expr Expr; typedef struct ExprList ExprList; typedef struct FKey FKey; typedef struct FpDecode FpDecode; typedef struct FuncDestructor FuncDestructor; typedef struct FuncDef FuncDef; typedef struct FuncDefHash FuncDefHash; |
︙ | ︙ | |||
1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 | */ struct Db { char *zDbSName; /* Name of this database. (schema name, not filename) */ Btree *pBt; /* The B*Tree structure for this database file */ u8 safety_level; /* How aggressive at syncing data to disk */ u8 bSyncSet; /* True if "PRAGMA synchronous=N" has been run */ Schema *pSchema; /* Pointer to database schema (possibly shared) */ }; /* ** An instance of the following structure stores a database schema. ** ** Most Schema objects are associated with a Btree. The exception is ** the Schema for the TEMP database (sqlite3.aDb[1]) which is free-standing. | > > > > | 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 | */ struct Db { char *zDbSName; /* Name of this database. (schema name, not filename) */ Btree *pBt; /* The B*Tree structure for this database file */ u8 safety_level; /* How aggressive at syncing data to disk */ u8 bSyncSet; /* True if "PRAGMA synchronous=N" has been run */ Schema *pSchema; /* Pointer to database schema (possibly shared) */ #ifdef SQLITE_ENABLE_SHARED_SCHEMA SchemaPool *pSPool; /* For REUSE_SCHEMA mode */ VTable *pVTable; /* List of all VTable objects (REUSE_SCHEMA mode only) */ #endif }; /* ** An instance of the following structure stores a database schema. ** ** Most Schema objects are associated with a Btree. The exception is ** the Schema for the TEMP database (sqlite3.aDb[1]) which is free-standing. |
︙ | ︙ | |||
1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 | Hash trigHash; /* All triggers indexed by name */ Hash fkeyHash; /* All foreign keys by referenced table name */ Table *pSeqTab; /* The sqlite_sequence table used by AUTOINCREMENT */ u8 file_format; /* Schema format version for this file */ u8 enc; /* Text encoding used by this database */ u16 schemaFlags; /* Flags associated with this schema */ int cache_size; /* Number of pages to use in the cache */ }; /* ** These macros can be used to test, set, or clear bits in the ** Db.pSchema->flags field. */ #define DbHasProperty(D,I,P) (((D)->aDb[I].pSchema->schemaFlags&(P))==(P)) | > > > | 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 | Hash trigHash; /* All triggers indexed by name */ Hash fkeyHash; /* All foreign keys by referenced table name */ Table *pSeqTab; /* The sqlite_sequence table used by AUTOINCREMENT */ u8 file_format; /* Schema format version for this file */ u8 enc; /* Text encoding used by this database */ u16 schemaFlags; /* Flags associated with this schema */ int cache_size; /* Number of pages to use in the cache */ #ifdef SQLITE_ENABLE_SHARED_SCHEMA Schema *pNext; /* Next Schema object SchemaPool (REUSE_SCHEMA) */ #endif }; /* ** These macros can be used to test, set, or clear bits in the ** Db.pSchema->flags field. */ #define DbHasProperty(D,I,P) (((D)->aDb[I].pSchema->schemaFlags&(P))==(P)) |
︙ | ︙ | |||
1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 | sqlite3 *pNextBlocked; /* Next in list of all blocked connections */ #endif #ifdef SQLITE_USER_AUTHENTICATION sqlite3_userauth auth; /* User authentication information */ #endif }; /* ** A macro to discover the encoding of a database. */ #define SCHEMA_ENC(db) ((db)->aDb[0].pSchema->enc) #define ENC(db) ((db)->enc) /* | > > > > > > | 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 | sqlite3 *pNextBlocked; /* Next in list of all blocked connections */ #endif #ifdef SQLITE_USER_AUTHENTICATION sqlite3_userauth auth; /* User authentication information */ #endif }; #ifdef SQLITE_ENABLE_SHARED_SCHEMA # define IsSharedSchema(db) (((db)->openFlags & SQLITE_OPEN_SHARED_SCHEMA)!=0) #else # define IsSharedSchema(db) 0 #endif /* ** A macro to discover the encoding of a database. */ #define SCHEMA_ENC(db) ((db)->aDb[0].pSchema->enc) #define ENC(db) ((db)->enc) /* |
︙ | ︙ | |||
1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 | #define DBFLAG_PreferBuiltin 0x0002 /* Preference to built-in funcs */ #define DBFLAG_Vacuum 0x0004 /* Currently in a VACUUM */ #define DBFLAG_VacuumInto 0x0008 /* Currently running VACUUM INTO */ #define DBFLAG_SchemaKnownOk 0x0010 /* Schema is known to be valid */ #define DBFLAG_InternalFunc 0x0020 /* Allow use of internal functions */ #define DBFLAG_EncodingFixed 0x0040 /* No longer possible to change enc. */ /* ** Bits of the sqlite3.dbOptFlags field that are used by the ** sqlite3_test_control(SQLITE_TESTCTRL_OPTIMIZATIONS,...) interface to ** selectively disable various optimizations. */ #define SQLITE_QueryFlattener 0x00000001 /* Query flattening */ #define SQLITE_WindowFunc 0x00000002 /* Use xInverse for window functions */ | > > > | 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 | #define DBFLAG_PreferBuiltin 0x0002 /* Preference to built-in funcs */ #define DBFLAG_Vacuum 0x0004 /* Currently in a VACUUM */ #define DBFLAG_VacuumInto 0x0008 /* Currently running VACUUM INTO */ #define DBFLAG_SchemaKnownOk 0x0010 /* Schema is known to be valid */ #define DBFLAG_InternalFunc 0x0020 /* Allow use of internal functions */ #define DBFLAG_EncodingFixed 0x0040 /* No longer possible to change enc. */ #define DBFLAG_SchemaInuse 0x0080 /* Do not release sharable schemas */ #define DBFLAG_FreeSchema 0x0100 /* Free extra shared schemas on release */ /* ** Bits of the sqlite3.dbOptFlags field that are used by the ** sqlite3_test_control(SQLITE_TESTCTRL_OPTIMIZATIONS,...) interface to ** selectively disable various optimizations. */ #define SQLITE_QueryFlattener 0x00000001 /* Query flattening */ #define SQLITE_WindowFunc 0x00000002 /* Use xInverse for window functions */ |
︙ | ︙ | |||
2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 | sqlite3_vtab *pVtab; /* Pointer to vtab instance */ int nRef; /* Number of pointers to this structure */ u8 bConstraint; /* True if constraints are supported */ u8 bAllSchemas; /* True if might use any attached schema */ u8 eVtabRisk; /* Riskiness of allowing hacker access */ int iSavepoint; /* Depth of the SAVEPOINT stack */ VTable *pNext; /* Next in linked list (see above) */ }; /* Allowed values for VTable.eVtabRisk */ #define SQLITE_VTABRISK_Low 0 #define SQLITE_VTABRISK_Normal 1 #define SQLITE_VTABRISK_High 2 | > > > | 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 | sqlite3_vtab *pVtab; /* Pointer to vtab instance */ int nRef; /* Number of pointers to this structure */ u8 bConstraint; /* True if constraints are supported */ u8 bAllSchemas; /* True if might use any attached schema */ u8 eVtabRisk; /* Riskiness of allowing hacker access */ int iSavepoint; /* Depth of the SAVEPOINT stack */ VTable *pNext; /* Next in linked list (see above) */ #ifdef SQLITE_ENABLE_SHARED_SCHEMA char *zName; /* Table name (REUSE_SCHEMA mode) */ #endif }; /* Allowed values for VTable.eVtabRisk */ #define SQLITE_VTABRISK_Low 0 #define SQLITE_VTABRISK_Normal 1 #define SQLITE_VTABRISK_High 2 |
︙ | ︙ | |||
4029 4030 4031 4032 4033 4034 4035 4036 4037 4038 4039 4040 4041 4042 | Expr *pWhen; /* The WHEN clause of the expression (may be NULL) */ IdList *pColumns; /* If this is an UPDATE OF <column-list> trigger, the <column-list> is stored here */ Schema *pSchema; /* Schema containing the trigger */ Schema *pTabSchema; /* Schema containing the table */ TriggerStep *step_list; /* Link list of trigger program steps */ Trigger *pNext; /* Next trigger associated with the table */ }; /* ** A trigger is either a BEFORE or an AFTER trigger. The following constants ** determine which. ** ** If there are multiple triggers, you might of some BEFORE and some AFTER. | > > > | 4049 4050 4051 4052 4053 4054 4055 4056 4057 4058 4059 4060 4061 4062 4063 4064 4065 | Expr *pWhen; /* The WHEN clause of the expression (may be NULL) */ IdList *pColumns; /* If this is an UPDATE OF <column-list> trigger, the <column-list> is stored here */ Schema *pSchema; /* Schema containing the trigger */ Schema *pTabSchema; /* Schema containing the table */ TriggerStep *step_list; /* Link list of trigger program steps */ Trigger *pNext; /* Next trigger associated with the table */ #ifdef SQLITE_ENABLE_SHARED_SCHEMA char *zTabSchema; /* Temp triggers in IsSharedSchema() dbs only */ #endif }; /* ** A trigger is either a BEFORE or an AFTER trigger. The following constants ** determine which. ** ** If there are multiple triggers, you might of some BEFORE and some AFTER. |
︙ | ︙ | |||
4168 4169 4170 4171 4172 4173 4174 4175 4176 4177 4178 4179 4180 4181 | typedef struct { sqlite3 *db; /* The database being initialized */ char **pzErrMsg; /* Error message stored here */ int iDb; /* 0 for main database. 1 for TEMP, 2.. for ATTACHed */ int rc; /* Result code stored here */ u32 mInitFlags; /* Flags controlling error messages */ u32 nInitRow; /* Number of rows processed */ Pgno mxPage; /* Maximum page number. 0 for no limit. */ } InitData; /* ** Allowed values for mInitFlags */ #define INITFLAG_AlterMask 0x0003 /* Types of ALTER */ | > | 4191 4192 4193 4194 4195 4196 4197 4198 4199 4200 4201 4202 4203 4204 4205 | typedef struct { sqlite3 *db; /* The database being initialized */ char **pzErrMsg; /* Error message stored here */ int iDb; /* 0 for main database. 1 for TEMP, 2.. for ATTACHed */ int rc; /* Result code stored here */ u32 mInitFlags; /* Flags controlling error messages */ u32 nInitRow; /* Number of rows processed */ u64 cksum; /* Schema checksum for REUSE_SCHEMA mode */ Pgno mxPage; /* Maximum page number. 0 for no limit. */ } InitData; /* ** Allowed values for mInitFlags */ #define INITFLAG_AlterMask 0x0003 /* Types of ALTER */ |
︙ | ︙ | |||
5389 5390 5391 5392 5393 5394 5395 5396 5397 5398 5399 5400 5401 5402 | int sqlite3FindDbName(sqlite3 *, const char *); int sqlite3AnalysisLoad(sqlite3*,int iDB); void sqlite3DeleteIndexSamples(sqlite3*,Index*); void sqlite3DefaultRowEst(Index*); void sqlite3RegisterLikeFunctions(sqlite3*, int); int sqlite3IsLikeFunction(sqlite3*,Expr*,int*,char*); void sqlite3SchemaClear(void *); Schema *sqlite3SchemaGet(sqlite3 *, Btree *); int sqlite3SchemaToIndex(sqlite3 *db, Schema *); KeyInfo *sqlite3KeyInfoAlloc(sqlite3*,int,int); void sqlite3KeyInfoUnref(KeyInfo*); KeyInfo *sqlite3KeyInfoRef(KeyInfo*); KeyInfo *sqlite3KeyInfoOfIndex(Parse*, Index*); KeyInfo *sqlite3KeyInfoFromExprList(Parse*, ExprList*, int, int); | > > > > > > > > > > > > > > > > > > > > > > > | 5413 5414 5415 5416 5417 5418 5419 5420 5421 5422 5423 5424 5425 5426 5427 5428 5429 5430 5431 5432 5433 5434 5435 5436 5437 5438 5439 5440 5441 5442 5443 5444 5445 5446 5447 5448 5449 | int sqlite3FindDbName(sqlite3 *, const char *); int sqlite3AnalysisLoad(sqlite3*,int iDB); void sqlite3DeleteIndexSamples(sqlite3*,Index*); void sqlite3DefaultRowEst(Index*); void sqlite3RegisterLikeFunctions(sqlite3*, int); int sqlite3IsLikeFunction(sqlite3*,Expr*,int*,char*); void sqlite3SchemaClear(void *); void sqlite3SchemaClearOrDisconnect(sqlite3*, int); #ifdef SQLITE_ENABLE_SHARED_SCHEMA int sqlite3SchemaConnect(sqlite3*, int, u64); int sqlite3SchemaDisconnect(sqlite3 *, int, int); Schema *sqlite3SchemaExtract(SchemaPool*); int sqlite3SchemaLoad(sqlite3*, int, int*, char**); void sqlite3SchemaReleaseAll(sqlite3*); void sqlite3SchemaRelease(sqlite3*, int); void sqlite3SchemaAdjustUsed(sqlite3*, int, int, int*); void sqlite3SchemaWritable(Parse*, int); void sqlite3UnlockReusableSchema(sqlite3 *db, int bRelease); int sqlite3LockReusableSchema(sqlite3 *db); #else # define sqlite3SchemaWritable(x,y) # define sqlite3UnlockReusableSchema(x,y) (void)(y) # define sqlite3LockReusableSchema(x) 0 # define sqlite3SchemaDisconnect(x,y,z) SQLITE_OK # define sqlite3SchemaLoad(w,x,y,z) SQLITE_OK # define sqlite3SchemaRelease(y,z) # define sqlite3SchemaConnect(x,y,z) SQLITE_OK #endif Schema *sqlite3SchemaGet(sqlite3 *, Btree *); int sqlite3SchemaToIndex(sqlite3 *db, Schema *); KeyInfo *sqlite3KeyInfoAlloc(sqlite3*,int,int); void sqlite3KeyInfoUnref(KeyInfo*); KeyInfo *sqlite3KeyInfoRef(KeyInfo*); KeyInfo *sqlite3KeyInfoOfIndex(Parse*, Index*); KeyInfo *sqlite3KeyInfoFromExprList(Parse*, ExprList*, int, int); |
︙ | ︙ |
Changes to src/status.c.
︙ | ︙ | |||
284 285 286 287 288 289 290 291 292 293 294 295 296 | ** *pCurrent gets an accurate estimate of the amount of memory used ** to store the schema for all databases (main, temp, and any ATTACHed ** databases. *pHighwater is set to zero. */ case SQLITE_DBSTATUS_SCHEMA_USED: { int i; /* Used to iterate through schemas */ int nByte = 0; /* Used to accumulate return value */ sqlite3BtreeEnterAll(db); db->pnBytesFreed = &nByte; assert( db->lookaside.pEnd==db->lookaside.pTrueEnd ); db->lookaside.pEnd = db->lookaside.pStart; for(i=0; i<db->nDb; i++){ | > > > > > > > > > > > > > | | 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 | ** *pCurrent gets an accurate estimate of the amount of memory used ** to store the schema for all databases (main, temp, and any ATTACHed ** databases. *pHighwater is set to zero. */ case SQLITE_DBSTATUS_SCHEMA_USED: { int i; /* Used to iterate through schemas */ int nByte = 0; /* Used to accumulate return value */ int bReleaseSchema; sqlite3BtreeEnterAll(db); bReleaseSchema = sqlite3LockReusableSchema(db); db->pnBytesFreed = &nByte; assert( db->lookaside.pEnd==db->lookaside.pTrueEnd ); db->lookaside.pEnd = db->lookaside.pStart; for(i=0; i<db->nDb; i++){ Schema *pSchema; #ifdef SQLITE_ENABLE_SHARED_SCHEMA int bUnload = 0; int nUsed = nByte; if( db->aDb[i].pSPool ){ char *zDummy = 0; rc = sqlite3SchemaLoad(db, i, &bUnload, &zDummy); sqlite3_free(zDummy); if( rc ) break; } #endif /* ifdef SQLITE_ENABLE_SHARED_SCHEMA */ pSchema = db->aDb[i].pSchema; if( ALWAYS(pSchema!=0) ){ HashElem *p; nByte += sqlite3GlobalConfig.m.xRoundup(sizeof(HashElem)) * ( pSchema->tblHash.count + pSchema->trigHash.count + pSchema->idxHash.count |
︙ | ︙ | |||
312 313 314 315 316 317 318 | for(p=sqliteHashFirst(&pSchema->trigHash); p; p=sqliteHashNext(p)){ sqlite3DeleteTrigger(db, (Trigger*)sqliteHashData(p)); } for(p=sqliteHashFirst(&pSchema->tblHash); p; p=sqliteHashNext(p)){ sqlite3DeleteTable(db, (Table *)sqliteHashData(p)); } } | > > > > | > > > | 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 | for(p=sqliteHashFirst(&pSchema->trigHash); p; p=sqliteHashNext(p)){ sqlite3DeleteTrigger(db, (Trigger*)sqliteHashData(p)); } for(p=sqliteHashFirst(&pSchema->tblHash); p; p=sqliteHashNext(p)){ sqlite3DeleteTable(db, (Table *)sqliteHashData(p)); } } #ifdef SQLITE_ENABLE_SHARED_SCHEMA if( db->aDb[i].pSPool ){ if( bUnload ) sqlite3SchemaRelease(db, i); sqlite3SchemaAdjustUsed(db, i, nUsed, &nByte); } #endif /* ifdef SQLITE_ENABLE_SHARED_SCHEMA */ } sqlite3UnlockReusableSchema(db, bReleaseSchema); db->pnBytesFreed = 0; db->lookaside.pEnd = db->lookaside.pTrueEnd; sqlite3BtreeLeaveAll(db); *pHighwater = 0; *pCurrent = nByte; break; |
︙ | ︙ |
Changes to src/tclsqlite.c.
︙ | ︙ | |||
3723 3724 3725 3726 3727 3728 3729 3730 3731 3732 3733 3734 3735 3736 | Tcl_Interp *interp, Tcl_Obj *const*objv ){ Tcl_WrongNumArgs(interp, 1, objv, "HANDLE ?FILENAME? ?-vfs VFSNAME? ?-readonly BOOLEAN? ?-create BOOLEAN?" " ?-nofollow BOOLEAN?" " ?-nomutex BOOLEAN? ?-fullmutex BOOLEAN? ?-uri BOOLEAN?" ); return TCL_ERROR; } /* ** sqlite3 DBNAME FILENAME ?-vfs VFSNAME? ?-key KEY? ?-readonly BOOLEAN? ** ?-create BOOLEAN? ?-nomutex BOOLEAN? | > > > | 3723 3724 3725 3726 3727 3728 3729 3730 3731 3732 3733 3734 3735 3736 3737 3738 3739 | Tcl_Interp *interp, Tcl_Obj *const*objv ){ Tcl_WrongNumArgs(interp, 1, objv, "HANDLE ?FILENAME? ?-vfs VFSNAME? ?-readonly BOOLEAN? ?-create BOOLEAN?" " ?-nofollow BOOLEAN?" " ?-nomutex BOOLEAN? ?-fullmutex BOOLEAN? ?-uri BOOLEAN?" #ifdef SQLITE_ENABLE_SHARED_SCHEMA " ?-shared-schema BOOLEAN?" #endif ); return TCL_ERROR; } /* ** sqlite3 DBNAME FILENAME ?-vfs VFSNAME? ?-key KEY? ?-readonly BOOLEAN? ** ?-create BOOLEAN? ?-nomutex BOOLEAN? |
︙ | ︙ | |||
3854 3855 3856 3857 3858 3859 3860 3861 3862 3863 3864 3865 3866 3867 | int b; if( Tcl_GetBooleanFromObj(interp, objv[i], &b) ) return TCL_ERROR; if( b ){ flags |= SQLITE_OPEN_URI; }else{ flags &= ~SQLITE_OPEN_URI; } }else if( strcmp(zArg, "-translatefilename")==0 ){ if( Tcl_GetBooleanFromObj(interp, objv[i], &bTranslateFileName) ){ return TCL_ERROR; } }else{ Tcl_AppendResult(interp, "unknown option: ", zArg, (char*)0); return TCL_ERROR; | > > > > > > > > > > | 3857 3858 3859 3860 3861 3862 3863 3864 3865 3866 3867 3868 3869 3870 3871 3872 3873 3874 3875 3876 3877 3878 3879 3880 | int b; if( Tcl_GetBooleanFromObj(interp, objv[i], &b) ) return TCL_ERROR; if( b ){ flags |= SQLITE_OPEN_URI; }else{ flags &= ~SQLITE_OPEN_URI; } #ifdef SQLITE_ENABLE_SHARED_SCHEMA }else if( strcmp(zArg, "-shared-schema")==0 ){ int b; if( Tcl_GetBooleanFromObj(interp, objv[i], &b) ) return TCL_ERROR; if( b ){ flags |= SQLITE_OPEN_SHARED_SCHEMA; }else{ flags &= ~SQLITE_OPEN_SHARED_SCHEMA; } #endif /* ifdef SQLITE_ENABLE_SHARED_SCHEMA */ }else if( strcmp(zArg, "-translatefilename")==0 ){ if( Tcl_GetBooleanFromObj(interp, objv[i], &bTranslateFileName) ){ return TCL_ERROR; } }else{ Tcl_AppendResult(interp, "unknown option: ", zArg, (char*)0); return TCL_ERROR; |
︙ | ︙ |
Changes to src/test_config.c.
︙ | ︙ | |||
774 775 776 777 778 779 780 781 782 783 784 785 786 787 | #endif #ifdef SQLITE_OMIT_WINDOWFUNC Tcl_SetVar2(interp, "sqlite_options", "windowfunc", "0", TCL_GLOBAL_ONLY); #else Tcl_SetVar2(interp, "sqlite_options", "windowfunc", "1", TCL_GLOBAL_ONLY); #endif #define LINKVAR(x) { \ static const int cv_ ## x = SQLITE_ ## x; \ Tcl_LinkVar(interp, "SQLITE_" #x, (char *)&(cv_ ## x), \ TCL_LINK_INT | TCL_LINK_READ_ONLY); } LINKVAR( MAX_LENGTH ); | > > > > > > | 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 | #endif #ifdef SQLITE_OMIT_WINDOWFUNC Tcl_SetVar2(interp, "sqlite_options", "windowfunc", "0", TCL_GLOBAL_ONLY); #else Tcl_SetVar2(interp, "sqlite_options", "windowfunc", "1", TCL_GLOBAL_ONLY); #endif #ifdef SQLITE_ENABLE_SHARED_SCHEMA Tcl_SetVar2(interp, "sqlite_options", "sharedschema", "1", TCL_GLOBAL_ONLY); #else Tcl_SetVar2(interp, "sqlite_options", "sharedschema", "0", TCL_GLOBAL_ONLY); #endif #define LINKVAR(x) { \ static const int cv_ ## x = SQLITE_ ## x; \ Tcl_LinkVar(interp, "SQLITE_" #x, (char *)&(cv_ ## x), \ TCL_LINK_INT | TCL_LINK_READ_ONLY); } LINKVAR( MAX_LENGTH ); |
︙ | ︙ |
Added src/test_schemapool.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 | /* ** 2006 June 10 ** ** 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. ** ************************************************************************* ** Code for testing the virtual table interfaces. This code ** is not included in the SQLite library. It is used for automated ** testing of the SQLite library. */ /* ** None of this works unless we have virtual tables. */ #if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_TEST) #include <tcl.h> #ifdef SQLITE_ENABLE_SHARED_SCHEMA #include "sqliteInt.h" /* The code in this file defines a sqlite3 virtual-table module with ** the following schema. */ #define SCHEMAPOOL_SCHEMA \ "CREATE TABLE x(" \ " cksum INTEGER, " \ " nref INTEGER, " \ " nschema INTEGER, " \ " ndelete INTEGER " \ ")" #define SCHEMAPOOL_NFIELD 4 typedef struct schemapool_vtab schemapool_vtab; typedef struct schemapool_cursor schemapool_cursor; /* A schema table object */ struct schemapool_vtab { sqlite3_vtab base; }; /* A schema table cursor object */ struct schemapool_cursor { sqlite3_vtab_cursor base; sqlite3_int64 *aData; int iRow; int nRow; }; /* ** Table destructor for the schema module. */ static int schemaPoolDestroy(sqlite3_vtab *pVtab){ sqlite3_free(pVtab); return 0; } /* ** Table constructor for the schema module. */ static int schemaPoolCreate( sqlite3 *db, void *pAux, int argc, const char *const*argv, sqlite3_vtab **ppVtab, char **pzErr ){ int rc = SQLITE_NOMEM; schemapool_vtab *pVtab = sqlite3_malloc(sizeof(schemapool_vtab)); if( pVtab ){ memset(pVtab, 0, sizeof(schemapool_vtab)); rc = sqlite3_declare_vtab(db, SCHEMAPOOL_SCHEMA); if( rc!=SQLITE_OK ){ sqlite3_free(pVtab); pVtab = 0; } } *ppVtab = (sqlite3_vtab *)pVtab; return rc; } /* ** Open a new cursor on the schema table. */ static int schemaPoolOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){ int rc = SQLITE_NOMEM; schemapool_cursor *pCur; pCur = sqlite3_malloc(sizeof(schemapool_cursor)); if( pCur ){ memset(pCur, 0, sizeof(schemapool_cursor)); *ppCursor = (sqlite3_vtab_cursor*)pCur; rc = SQLITE_OK; } return rc; } /* ** Close a schema table cursor. */ static int schemaPoolClose(sqlite3_vtab_cursor *cur){ schemapool_cursor *pCur = (schemapool_cursor*)cur; sqlite3_free(pCur->aData); sqlite3_free(pCur); return SQLITE_OK; } /* ** Retrieve a column of data. */ static int schemaPoolColumn(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int i){ schemapool_cursor *pCur = (schemapool_cursor*)cur; assert( i==0 || i==1 || i==2 || i==3 ); sqlite3_result_int64(ctx, pCur->aData[pCur->iRow*SCHEMAPOOL_NFIELD + i]); return SQLITE_OK; } /* ** Retrieve the current rowid. */ static int schemaPoolRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){ schemapool_cursor *pCur = (schemapool_cursor*)cur; *pRowid = pCur->iRow + 1; return SQLITE_OK; } static int schemaPoolEof(sqlite3_vtab_cursor *cur){ schemapool_cursor *pCur = (schemapool_cursor*)cur; return pCur->iRow>=pCur->nRow; } /* ** Advance the cursor to the next row. */ static int schemaPoolNext(sqlite3_vtab_cursor *cur){ schemapool_cursor *pCur = (schemapool_cursor*)cur; pCur->iRow++; return SQLITE_OK; } struct SchemaPool { int nRef; /* Number of pointers to this object */ int nDelete; /* Schema objects deleted by ReleaseAll() */ u64 cksum; /* Checksum for this Schema contents */ Schema *pSchema; /* Linked list of Schema objects */ Schema sSchema; /* The single dummy schema object */ SchemaPool *pNext; /* Next element in schemaPoolList */ }; extern SchemaPool *sqlite3SchemaPoolList(void); /* ** Reset a schemaPool table cursor. */ static int schemaPoolFilter( sqlite3_vtab_cursor *pVtabCursor, int idxNum, const char *idxStr, int argc, sqlite3_value **argv ){ SchemaPool *pSPool; schemapool_cursor *pCur = (schemapool_cursor*)pVtabCursor; sqlite3_free(pCur->aData); pCur->aData = 0; pCur->nRow = 0; pCur->iRow = 0; for(pSPool = sqlite3SchemaPoolList(); pSPool; pSPool=pSPool->pNext){ pCur->nRow++; } if( pCur->nRow ){ int iRow = 0; int nByte = SCHEMAPOOL_NFIELD * pCur->nRow * sizeof(i64); pCur->aData = (i64*)sqlite3_malloc(nByte); if( pCur->aData==0 ) return SQLITE_NOMEM; for(pSPool = sqlite3SchemaPoolList(); pSPool; pSPool=pSPool->pNext){ Schema *p; i64 nSchema = 0; for(p=pSPool->pSchema; p; p=p->pNext){ nSchema++; } pCur->aData[0 + iRow*SCHEMAPOOL_NFIELD] = pSPool->cksum; pCur->aData[1 + iRow*SCHEMAPOOL_NFIELD] = (i64)pSPool->nRef; pCur->aData[2 + iRow*SCHEMAPOOL_NFIELD] = nSchema; pCur->aData[3 + iRow*SCHEMAPOOL_NFIELD] = (i64)pSPool->nDelete; iRow++; } } return SQLITE_OK; } /* ** Analyse the WHERE condition. */ static int schemaPoolBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){ return SQLITE_OK; } /* ** A virtual table module that merely echos method calls into TCL ** variables. */ static sqlite3_module schemaPoolModule = { 0, /* iVersion */ schemaPoolCreate, schemaPoolCreate, schemaPoolBestIndex, schemaPoolDestroy, schemaPoolDestroy, schemaPoolOpen, /* xOpen - open a cursor */ schemaPoolClose, /* xClose - close a cursor */ schemaPoolFilter, /* xFilter - configure scan constraints */ schemaPoolNext, /* xNext - advance a cursor */ schemaPoolEof, /* xEof */ schemaPoolColumn, /* xColumn - read data */ schemaPoolRowid, /* xRowid - read data */ 0, /* xUpdate */ 0, /* xBegin */ 0, /* xSync */ 0, /* xCommit */ 0, /* xRollback */ 0, /* xFindMethod */ 0, /* xRename */ }; /* ** Decode a pointer to an sqlite3 object. */ extern int getDbPointer(Tcl_Interp *interp, const char *zA, sqlite3 **ppDb); /* ** Register the schema virtual table module. */ static int SQLITE_TCLAPI register_schemapool_module( ClientData clientData, /* Not used */ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int objc, /* Number of arguments */ Tcl_Obj *CONST objv[] /* Command arguments */ ){ sqlite3 *db; if( objc!=2 ){ Tcl_WrongNumArgs(interp, 1, objv, "DB"); return TCL_ERROR; } if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; #ifndef SQLITE_OMIT_VIRTUALTABLE sqlite3_create_module(db, "schemapool", &schemaPoolModule, 0); #endif return TCL_OK; } #endif /* ifdef SQLITE_ENABLE_SHARED_SCHEMA */ #endif /* !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_TEST) */ /* ** Register commands with the TCL interpreter. */ int Sqlitetestschemapool_Init(Tcl_Interp *interp){ #ifdef SQLITE_ENABLE_SHARED_SCHEMA static struct { char *zName; Tcl_ObjCmdProc *xProc; void *clientData; } aObjCmd[] = { { "register_schemapool_module", register_schemapool_module, 0 }, }; int i; for(i=0; i<sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++){ Tcl_CreateObjCommand(interp, aObjCmd[i].zName, aObjCmd[i].xProc, aObjCmd[i].clientData, 0); } #endif /* ifdef SQLITE_ENABLE_SHARED_SCHEMA */ return TCL_OK; } |
Changes to src/test_tclsh.c.
︙ | ︙ | |||
72 73 74 75 76 77 78 79 80 81 82 83 84 85 | extern int Sqlitetest_demovfs_Init(Tcl_Interp *); extern int Sqlitetest_func_Init(Tcl_Interp*); extern int Sqlitetest_hexio_Init(Tcl_Interp*); extern int Sqlitetest_init_Init(Tcl_Interp*); extern int Sqlitetest_malloc_Init(Tcl_Interp*); extern int Sqlitetest_mutex_Init(Tcl_Interp*); extern int Sqlitetestschema_Init(Tcl_Interp*); extern int Sqlitetestsse_Init(Tcl_Interp*); extern int Sqlitetesttclvar_Init(Tcl_Interp*); extern int Sqlitetestfs_Init(Tcl_Interp*); extern int SqlitetestThread_Init(Tcl_Interp*); extern int SqlitetestOnefile_Init(); extern int SqlitetestOsinst_Init(Tcl_Interp*); extern int Sqlitetestbackup_Init(Tcl_Interp*); | > | 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 | extern int Sqlitetest_demovfs_Init(Tcl_Interp *); extern int Sqlitetest_func_Init(Tcl_Interp*); extern int Sqlitetest_hexio_Init(Tcl_Interp*); extern int Sqlitetest_init_Init(Tcl_Interp*); extern int Sqlitetest_malloc_Init(Tcl_Interp*); extern int Sqlitetest_mutex_Init(Tcl_Interp*); extern int Sqlitetestschema_Init(Tcl_Interp*); extern int Sqlitetestschemapool_Init(Tcl_Interp*); extern int Sqlitetestsse_Init(Tcl_Interp*); extern int Sqlitetesttclvar_Init(Tcl_Interp*); extern int Sqlitetestfs_Init(Tcl_Interp*); extern int SqlitetestThread_Init(Tcl_Interp*); extern int SqlitetestOnefile_Init(); extern int SqlitetestOsinst_Init(Tcl_Interp*); extern int Sqlitetestbackup_Init(Tcl_Interp*); |
︙ | ︙ | |||
144 145 146 147 148 149 150 151 152 153 154 155 156 157 | Sqlitetest_demovfs_Init(interp); Sqlitetest_func_Init(interp); Sqlitetest_hexio_Init(interp); Sqlitetest_init_Init(interp); Sqlitetest_malloc_Init(interp); Sqlitetest_mutex_Init(interp); Sqlitetestschema_Init(interp); Sqlitetesttclvar_Init(interp); Sqlitetestfs_Init(interp); SqlitetestThread_Init(interp); SqlitetestOnefile_Init(); SqlitetestOsinst_Init(interp); Sqlitetestbackup_Init(interp); Sqlitetestintarray_Init(interp); | > | 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 | Sqlitetest_demovfs_Init(interp); Sqlitetest_func_Init(interp); Sqlitetest_hexio_Init(interp); Sqlitetest_init_Init(interp); Sqlitetest_malloc_Init(interp); Sqlitetest_mutex_Init(interp); Sqlitetestschema_Init(interp); Sqlitetestschemapool_Init(interp); Sqlitetesttclvar_Init(interp); Sqlitetestfs_Init(interp); SqlitetestThread_Init(interp); SqlitetestOnefile_Init(); SqlitetestOsinst_Init(interp); Sqlitetestbackup_Init(interp); Sqlitetestintarray_Init(interp); |
︙ | ︙ |
Changes to src/trigger.c.
︙ | ︙ | |||
47 48 49 50 51 52 53 54 55 56 57 58 59 60 | ** that fire off of pTab. The list will include any TEMP triggers on ** pTab as well as the triggers lised in pTab->pTrigger. */ Trigger *sqlite3TriggerList(Parse *pParse, Table *pTab){ Schema *pTmpSchema; /* Schema of the pTab table */ Trigger *pList; /* List of triggers to return */ HashElem *p; /* Loop variable for TEMP triggers */ assert( pParse->disableTriggers==0 ); pTmpSchema = pParse->db->aDb[1].pSchema; p = sqliteHashFirst(&pTmpSchema->trigHash); pList = pTab->pTrigger; while( p ){ Trigger *pTrig = (Trigger *)sqliteHashData(p); | > > > > > > > > > > > > > > > > > > | > > > | | 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 | ** that fire off of pTab. The list will include any TEMP triggers on ** pTab as well as the triggers lised in pTab->pTrigger. */ Trigger *sqlite3TriggerList(Parse *pParse, Table *pTab){ Schema *pTmpSchema; /* Schema of the pTab table */ Trigger *pList; /* List of triggers to return */ HashElem *p; /* Loop variable for TEMP triggers */ #ifdef SQLITE_ENABLE_SHARED_SCHEMA char *zSchema = 0; sqlite3 *db = pParse->db; if( IsSharedSchema(db) ){ zSchema = db->aDb[sqlite3SchemaToIndex(db, pTab->pSchema)].zDbSName; } #endif assert( pParse->disableTriggers==0 ); pTmpSchema = pParse->db->aDb[1].pSchema; p = sqliteHashFirst(&pTmpSchema->trigHash); pList = pTab->pTrigger; while( p ){ Trigger *pTrig = (Trigger *)sqliteHashData(p); int bSchemaMatch; #ifdef SQLITE_ENABLE_SHARED_SCHEMA if( zSchema ){ /* Shared-schema */ bSchemaMatch = (0==sqlite3StrICmp(pTrig->zTabSchema, zSchema)); }else #endif { /* Non-shared-schema */ bSchemaMatch = (pTrig->pTabSchema==pTab->pSchema); } if( bSchemaMatch && pTrig->table && 0==sqlite3StrICmp(pTrig->table, pTab->zName) && (pTrig->pTabSchema!=pTmpSchema || pTrig->bReturning) ){ pTrig->pNext = pList; pList = pTrig; }else if( pTrig->op==TK_RETURNING ){ #ifndef SQLITE_OMIT_VIRTUALTABLE assert( pParse->db->pVtabCtx==0 ); #endif assert( pParse->bReturning ); assert( &(pParse->u1.pReturning->retTrig) == pTrig ); pTrig->table = pTab->zName; pTrig->pTabSchema = pTab->pSchema; pTrig->pNext = pList; pList = pTrig; } |
︙ | ︙ | |||
259 260 261 262 263 264 265 266 267 268 269 270 271 272 | /* Build the Trigger object */ pTrigger = (Trigger*)sqlite3DbMallocZero(db, sizeof(Trigger)); if( pTrigger==0 ) goto trigger_cleanup; pTrigger->zName = zName; zName = 0; pTrigger->table = sqlite3DbStrDup(db, pTableName->a[0].zName); pTrigger->pSchema = db->aDb[iDb].pSchema; pTrigger->pTabSchema = pTab->pSchema; pTrigger->op = (u8)op; pTrigger->tr_tm = tr_tm==TK_BEFORE ? TRIGGER_BEFORE : TRIGGER_AFTER; if( IN_RENAME_OBJECT ){ sqlite3RenameTokenRemap(pParse, pTrigger->table, pTableName->a[0].zName); pTrigger->pWhen = pWhen; | > > > > > > | 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 | /* Build the Trigger object */ pTrigger = (Trigger*)sqlite3DbMallocZero(db, sizeof(Trigger)); if( pTrigger==0 ) goto trigger_cleanup; pTrigger->zName = zName; zName = 0; pTrigger->table = sqlite3DbStrDup(db, pTableName->a[0].zName); #ifdef SQLITE_ENABLE_SHARED_SCHEMA if( IsSharedSchema(db) && iDb==1 ){ int iTabDb = sqlite3SchemaToIndex(db, pTab->pSchema); pTrigger->zTabSchema = sqlite3DbStrDup(db, db->aDb[iTabDb].zDbSName); } #endif /* ifdef SQLITE_ENABLE_SHARED_SCHEMA */ pTrigger->pSchema = db->aDb[iDb].pSchema; pTrigger->pTabSchema = pTab->pSchema; pTrigger->op = (u8)op; pTrigger->tr_tm = tr_tm==TK_BEFORE ? TRIGGER_BEFORE : TRIGGER_AFTER; if( IN_RENAME_OBJECT ){ sqlite3RenameTokenRemap(pParse, pTrigger->table, pTableName->a[0].zName); pTrigger->pWhen = pWhen; |
︙ | ︙ | |||
382 383 384 385 386 387 388 | sqlite3NestedParse(pParse, "INSERT INTO %Q." LEGACY_SCHEMA_TABLE " VALUES('trigger',%Q,%Q,0,'CREATE TRIGGER %q')", db->aDb[iDb].zDbSName, zName, pTrig->table, z); sqlite3DbFree(db, z); sqlite3ChangeCookie(pParse, iDb); | | | 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 | sqlite3NestedParse(pParse, "INSERT INTO %Q." LEGACY_SCHEMA_TABLE " VALUES('trigger',%Q,%Q,0,'CREATE TRIGGER %q')", db->aDb[iDb].zDbSName, zName, pTrig->table, z); sqlite3DbFree(db, z); sqlite3ChangeCookie(pParse, iDb); sqlite3VdbeAddParseSchemaOp(pParse, iDb, sqlite3MPrintf(db, "type='trigger' AND name='%q'", zName), 0); } if( db->init.busy ){ Trigger *pLink = pTrig; Hash *pHash = &db->aDb[iDb].pSchema->trigHash; assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); |
︙ | ︙ | |||
601 602 603 604 605 606 607 608 609 610 611 612 613 614 | ** Recursively delete a Trigger structure */ void sqlite3DeleteTrigger(sqlite3 *db, Trigger *pTrigger){ if( pTrigger==0 || pTrigger->bReturning ) return; sqlite3DeleteTriggerStep(db, pTrigger->step_list); sqlite3DbFree(db, pTrigger->zName); sqlite3DbFree(db, pTrigger->table); sqlite3ExprDelete(db, pTrigger->pWhen); sqlite3IdListDelete(db, pTrigger->pColumns); sqlite3DbFree(db, pTrigger); } /* ** This function is called to drop a trigger from the database schema. | > > > | 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 | ** Recursively delete a Trigger structure */ void sqlite3DeleteTrigger(sqlite3 *db, Trigger *pTrigger){ if( pTrigger==0 || pTrigger->bReturning ) return; sqlite3DeleteTriggerStep(db, pTrigger->step_list); sqlite3DbFree(db, pTrigger->zName); sqlite3DbFree(db, pTrigger->table); #ifdef SQLITE_ENABLE_SHARED_SCHEMA sqlite3DbFree(db, pTrigger->zTabSchema); #endif sqlite3ExprDelete(db, pTrigger->pWhen); sqlite3IdListDelete(db, pTrigger->pColumns); sqlite3DbFree(db, pTrigger); } /* ** This function is called to drop a trigger from the database schema. |
︙ | ︙ | |||
672 673 674 675 676 677 678 679 680 681 682 683 684 685 | Table *pTable; Vdbe *v; sqlite3 *db = pParse->db; int iDb; iDb = sqlite3SchemaToIndex(pParse->db, pTrigger->pSchema); assert( iDb>=0 && iDb<db->nDb ); pTable = tableOfTrigger(pTrigger); assert( (pTable && pTable->pSchema==pTrigger->pSchema) || iDb==1 ); #ifndef SQLITE_OMIT_AUTHORIZATION if( pTable ){ int code = SQLITE_DROP_TRIGGER; const char *zDb = db->aDb[iDb].zDbSName; const char *zTab = SCHEMA_TABLE(iDb); | > | 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 | Table *pTable; Vdbe *v; sqlite3 *db = pParse->db; int iDb; iDb = sqlite3SchemaToIndex(pParse->db, pTrigger->pSchema); assert( iDb>=0 && iDb<db->nDb ); sqlite3SchemaWritable(pParse, iDb); pTable = tableOfTrigger(pTrigger); assert( (pTable && pTable->pSchema==pTrigger->pSchema) || iDb==1 ); #ifndef SQLITE_OMIT_AUTHORIZATION if( pTable ){ int code = SQLITE_DROP_TRIGGER; const char *zDb = db->aDb[iDb].zDbSName; const char *zTab = SCHEMA_TABLE(iDb); |
︙ | ︙ | |||
1171 1172 1173 1174 1175 1176 1177 | Expr *pWhen = 0; /* Duplicate of trigger WHEN expression */ Vdbe *v; /* Temporary VM */ NameContext sNC; /* Name context for sub-vdbe */ SubProgram *pProgram = 0; /* Sub-vdbe for trigger program */ int iEndTrigger = 0; /* Label to jump to if WHEN is false */ Parse sSubParse; /* Parse context for sub-vdbe */ | | > > | 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 | Expr *pWhen = 0; /* Duplicate of trigger WHEN expression */ Vdbe *v; /* Temporary VM */ NameContext sNC; /* Name context for sub-vdbe */ SubProgram *pProgram = 0; /* Sub-vdbe for trigger program */ int iEndTrigger = 0; /* Label to jump to if WHEN is false */ Parse sSubParse; /* Parse context for sub-vdbe */ assert( pTrigger->zName==0 || IsSharedSchema(pParse->db) || pTab==tableOfTrigger(pTrigger) ); assert( pTop->pVdbe ); /* Allocate the TriggerPrg and SubProgram objects. To ensure that they ** are freed if an error occurs, link them into the Parse.pTriggerPrg ** list of the top-level Parse object sooner rather than later. */ pPrg = sqlite3DbMallocZero(db, sizeof(TriggerPrg)); if( !pPrg ) return 0; |
︙ | ︙ | |||
1278 1279 1280 1281 1282 1283 1284 | Trigger *pTrigger, /* Trigger to code */ Table *pTab, /* The table trigger pTrigger is attached to */ int orconf /* ON CONFLICT algorithm. */ ){ Parse *pRoot = sqlite3ParseToplevel(pParse); TriggerPrg *pPrg; | | > > | 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 | Trigger *pTrigger, /* Trigger to code */ Table *pTab, /* The table trigger pTrigger is attached to */ int orconf /* ON CONFLICT algorithm. */ ){ Parse *pRoot = sqlite3ParseToplevel(pParse); TriggerPrg *pPrg; assert( pTrigger->zName==0 || IsSharedSchema(pParse->db) || pTab==tableOfTrigger(pTrigger) ); /* It may be that this trigger has already been coded (or is in the ** process of being coded). If this is the case, then an entry with ** a matching TriggerPrg.pTrigger field will be present somewhere ** in the Parse.pTriggerPrg list. Search for such an entry. */ for(pPrg=pRoot->pTriggerPrg; pPrg && (pPrg->pTrigger!=pTrigger || pPrg->orconf!=orconf); |
︙ | ︙ |
Changes to src/vacuum.c.
︙ | ︙ | |||
121 122 123 124 125 126 127 128 129 130 131 132 133 134 | ** legacy applications. */ iDb = sqlite3FindDb(pParse->db, pNm); if( iDb<0 ) iDb = 0; #endif } if( iDb!=1 ){ int iIntoReg = 0; if( pInto && sqlite3ResolveSelfReference(pParse,0,0,pInto,0)==0 ){ iIntoReg = ++pParse->nMem; sqlite3ExprCode(pParse, pInto, iIntoReg); } sqlite3VdbeAddOp2(v, OP_Vacuum, iDb, iIntoReg); sqlite3VdbeUsesBtree(v, iDb); } | > | 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 | ** legacy applications. */ iDb = sqlite3FindDb(pParse->db, pNm); if( iDb<0 ) iDb = 0; #endif } if( iDb!=1 ){ int iIntoReg = 0; sqlite3SchemaWritable(pParse, iDb); if( pInto && sqlite3ResolveSelfReference(pParse,0,0,pInto,0)==0 ){ iIntoReg = ++pParse->nMem; sqlite3ExprCode(pParse, pInto, iIntoReg); } sqlite3VdbeAddOp2(v, OP_Vacuum, iDb, iIntoReg); sqlite3VdbeUsesBtree(v, iDb); } |
︙ | ︙ |
Changes to src/vdbe.c.
︙ | ︙ | |||
4071 4072 4073 4074 4075 4076 4077 | } } assert( pOp->p5==0 || pOp->p4type==P4_INT32 ); if( rc==SQLITE_OK && pOp->p5 && (iMeta!=pOp->p3 || pDb->pSchema->iGeneration!=pOp->p4.i) ){ | < < < < < < < > > > > > > > | 4071 4072 4073 4074 4075 4076 4077 4078 4079 4080 4081 4082 4083 4084 4085 4086 4087 4088 4089 4090 4091 4092 4093 4094 4095 4096 4097 4098 4099 4100 4101 4102 4103 4104 4105 4106 4107 | } } assert( pOp->p5==0 || pOp->p4type==P4_INT32 ); if( rc==SQLITE_OK && pOp->p5 && (iMeta!=pOp->p3 || pDb->pSchema->iGeneration!=pOp->p4.i) ){ /* If the schema-cookie from the database file matches the cookie ** stored with the in-memory representation of the schema, do ** not reload the schema from the database file. ** ** If virtual-tables are in use, this is not just an optimization. ** Often, v-tables store their data in other SQLite tables, which ** are queried from within xNext() and other v-table methods using ** prepared queries. If such a query is out-of-date, we do not want to ** discard the database schema, as the user code implementing the ** v-table would have to be ready for the sqlite3_vtab structure itself ** to be invalidated whenever sqlite3_step() is called from within ** a v-table method. */ if( db->aDb[pOp->p1].pSchema->schema_cookie!=iMeta ){ sqlite3ResetOneSchema(db, pOp->p1); } /* ** IMPLEMENTATION-OF: R-03189-51135 As each SQL statement runs, the schema ** version is checked to ensure that the schema has not changed since the ** SQL statement was prepared. */ sqlite3DbFree(db, p->zErrMsg); p->zErrMsg = sqlite3DbStrDup(db, "database schema has changed"); p->expired = 1; rc = SQLITE_SCHEMA; /* Set changeCntOn to 0 to prevent the value returned by sqlite3_changes() ** from being modified in sqlite3VdbeHalt(). If this statement is ** reprepared, changeCntOn will be set again. */ p->changeCntOn = 0; |
︙ | ︙ |
Changes to src/vdbe.h.
︙ | ︙ | |||
225 226 227 228 229 230 231 | # define sqlite3ExplainBreakpoint(A,B) /*no-op*/ #endif #if defined(SQLITE_DEBUG) && !defined(SQLITE_OMIT_EXPLAIN) void sqlite3ExplainBreakpoint(const char*,const char*); #else # define sqlite3ExplainBreakpoint(A,B) /*no-op*/ #endif | | | 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 | # define sqlite3ExplainBreakpoint(A,B) /*no-op*/ #endif #if defined(SQLITE_DEBUG) && !defined(SQLITE_OMIT_EXPLAIN) void sqlite3ExplainBreakpoint(const char*,const char*); #else # define sqlite3ExplainBreakpoint(A,B) /*no-op*/ #endif void sqlite3VdbeAddParseSchemaOp(Parse*,int,char*,u16); void sqlite3VdbeChangeOpcode(Vdbe*, int addr, u8); void sqlite3VdbeChangeP1(Vdbe*, int addr, int P1); void sqlite3VdbeChangeP2(Vdbe*, int addr, int P2); void sqlite3VdbeChangeP3(Vdbe*, int addr, int P3); void sqlite3VdbeChangeP5(Vdbe*, u16 P5); void sqlite3VdbeTypeofColumn(Vdbe*, int); void sqlite3VdbeJumpHere(Vdbe*, int addr); |
︙ | ︙ |
Changes to src/vdbeaux.c.
︙ | ︙ | |||
557 558 559 560 561 562 563 | ** Add an OP_ParseSchema opcode. This routine is broken out from ** sqlite3VdbeAddOp4() since it needs to also needs to mark all btrees ** as having been used. ** ** The zWhere string must have been obtained from sqlite3_malloc(). ** This routine will take ownership of the allocated memory. */ | | > > | 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 | ** Add an OP_ParseSchema opcode. This routine is broken out from ** sqlite3VdbeAddOp4() since it needs to also needs to mark all btrees ** as having been used. ** ** The zWhere string must have been obtained from sqlite3_malloc(). ** This routine will take ownership of the allocated memory. */ void sqlite3VdbeAddParseSchemaOp(Parse *pParse, int iDb, char *zWhere, u16 p5){ Vdbe *p = pParse->pVdbe; int j; sqlite3SchemaWritable(pParse, iDb); sqlite3VdbeAddOp4(p, OP_ParseSchema, iDb, 0, 0, zWhere, P4_DYNAMIC); sqlite3VdbeChangeP5(p, p5); for(j=0; j<p->db->nDb; j++) sqlite3VdbeUsesBtree(p, j); sqlite3MayAbort(p->pParse); } /* Insert the end of a co-routine |
︙ | ︙ |
Changes to src/vdbeblob.c.
︙ | ︙ | |||
130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 | int nAttempt = 0; int iCol; /* Index of zColumn in row-record */ int rc = SQLITE_OK; char *zErr = 0; Table *pTab; Incrblob *pBlob = 0; Parse sParse; #ifdef SQLITE_ENABLE_API_ARMOR if( ppBlob==0 ){ return SQLITE_MISUSE_BKPT; } #endif *ppBlob = 0; #ifdef SQLITE_ENABLE_API_ARMOR if( !sqlite3SafetyCheckOk(db) || zTable==0 || zColumn==0 ){ return SQLITE_MISUSE_BKPT; } #endif wrFlag = !!wrFlag; /* wrFlag = (wrFlag ? 1 : 0); */ sqlite3_mutex_enter(db->mutex); pBlob = (Incrblob *)sqlite3DbMallocZero(db, sizeof(Incrblob)); while(1){ sqlite3ParseObjectInit(&sParse,db); if( !pBlob ) goto blob_open_out; sqlite3DbFree(db, zErr); zErr = 0; | > > | 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 | int nAttempt = 0; int iCol; /* Index of zColumn in row-record */ int rc = SQLITE_OK; char *zErr = 0; Table *pTab; Incrblob *pBlob = 0; Parse sParse; int bUnlock; /* True to unlock reusable schemas before returning */ #ifdef SQLITE_ENABLE_API_ARMOR if( ppBlob==0 ){ return SQLITE_MISUSE_BKPT; } #endif *ppBlob = 0; #ifdef SQLITE_ENABLE_API_ARMOR if( !sqlite3SafetyCheckOk(db) || zTable==0 || zColumn==0 ){ return SQLITE_MISUSE_BKPT; } #endif wrFlag = !!wrFlag; /* wrFlag = (wrFlag ? 1 : 0); */ sqlite3_mutex_enter(db->mutex); bUnlock = sqlite3LockReusableSchema(db); pBlob = (Incrblob *)sqlite3DbMallocZero(db, sizeof(Incrblob)); while(1){ sqlite3ParseObjectInit(&sParse,db); if( !pBlob ) goto blob_open_out; sqlite3DbFree(db, zErr); zErr = 0; |
︙ | ︙ | |||
331 332 333 334 335 336 337 338 339 340 341 342 343 344 | } rc = blobSeekToRow(pBlob, iRow, &zErr); if( (++nAttempt)>=SQLITE_MAX_SCHEMA_RETRY || rc!=SQLITE_SCHEMA ) break; sqlite3ParseObjectReset(&sParse); } blob_open_out: if( rc==SQLITE_OK && db->mallocFailed==0 ){ *ppBlob = (sqlite3_blob *)pBlob; }else{ if( pBlob && pBlob->pStmt ) sqlite3VdbeFinalize((Vdbe *)pBlob->pStmt); sqlite3DbFree(db, pBlob); } sqlite3ErrorWithMsg(db, rc, (zErr ? "%s" : (char*)0), zErr); | > | 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 | } rc = blobSeekToRow(pBlob, iRow, &zErr); if( (++nAttempt)>=SQLITE_MAX_SCHEMA_RETRY || rc!=SQLITE_SCHEMA ) break; sqlite3ParseObjectReset(&sParse); } blob_open_out: sqlite3UnlockReusableSchema(db, bUnlock); if( rc==SQLITE_OK && db->mallocFailed==0 ){ *ppBlob = (sqlite3_blob *)pBlob; }else{ if( pBlob && pBlob->pStmt ) sqlite3VdbeFinalize((Vdbe *)pBlob->pStmt); sqlite3DbFree(db, pBlob); } sqlite3ErrorWithMsg(db, rc, (zErr ? "%s" : (char*)0), zErr); |
︙ | ︙ |
Changes to src/vtab.c.
︙ | ︙ | |||
188 189 190 191 192 193 194 195 196 197 198 199 200 201 | ** pTab is a pointer to a Table structure representing a virtual-table. ** Return a pointer to the VTable object used by connection db to access ** this virtual-table, if one has been created, or NULL otherwise. */ VTable *sqlite3GetVTable(sqlite3 *db, Table *pTab){ VTable *pVtab; assert( IsVirtual(pTab) ); for(pVtab=pTab->u.vtab.p; pVtab && pVtab->db!=db; pVtab=pVtab->pNext); return pVtab; } /* ** Decrement the ref-count on a virtual table object. When the ref-count ** reaches zero, call the xDisconnect() method to delete the object. | > > > > > > > > > > > > > > > > > > | 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 | ** pTab is a pointer to a Table structure representing a virtual-table. ** Return a pointer to the VTable object used by connection db to access ** this virtual-table, if one has been created, or NULL otherwise. */ VTable *sqlite3GetVTable(sqlite3 *db, Table *pTab){ VTable *pVtab; assert( IsVirtual(pTab) ); #ifdef SQLITE_ENABLE_SHARED_SCHEMA if( IsSharedSchema(db) ){ int iDb = sqlite3SchemaToIndex(db, pTab->pSchema); if( iDb!=1 ){ VTable **pp; for(pp=&db->aDb[iDb].pVTable; *pp; pp=&(*pp)->pNext){ if( sqlite3StrICmp(pTab->zName, (*pp)->zName)==0 ) break; } pVtab = *pp; if( pVtab && pTab->nCol<=0 ){ *pp = pVtab->pNext; sqlite3VtabUnlock(pVtab); pVtab = 0; } return pVtab; } } #endif /* ifdef SQLITE_ENABLE_SHARED_SCHEMA */ for(pVtab=pTab->u.vtab.p; pVtab && pVtab->db!=db; pVtab=pVtab->pNext); return pVtab; } /* ** Decrement the ref-count on a virtual table object. When the ref-count ** reaches zero, call the xDisconnect() method to delete the object. |
︙ | ︙ | |||
495 496 497 498 499 500 501 | pParse->regRowid ); v = sqlite3GetVdbe(pParse); sqlite3ChangeCookie(pParse, iDb); sqlite3VdbeAddOp0(v, OP_Expire); zWhere = sqlite3MPrintf(db, "name=%Q AND sql=%Q", pTab->zName, zStmt); | | | 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 | pParse->regRowid ); v = sqlite3GetVdbe(pParse); sqlite3ChangeCookie(pParse, iDb); sqlite3VdbeAddOp0(v, OP_Expire); zWhere = sqlite3MPrintf(db, "name=%Q AND sql=%Q", pTab->zName, zStmt); sqlite3VdbeAddParseSchemaOp(pParse, iDb, zWhere, 0); sqlite3DbFree(db, zStmt); iReg = ++pParse->nMem; sqlite3VdbeLoadString(v, iReg, pTab->zName); sqlite3VdbeAddOp2(v, OP_VCreate, iDb, iReg); }else{ /* If we are rereading the sqlite_schema table create the in-memory |
︙ | ︙ | |||
565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 | int rc; const char *const*azArg; int nArg = pTab->u.vtab.nArg; char *zErr = 0; char *zModuleName; int iDb; VtabCtx *pCtx; assert( IsVirtual(pTab) ); azArg = (const char *const*)pTab->u.vtab.azArg; /* Check that the virtual-table is not already being initialized */ for(pCtx=db->pVtabCtx; pCtx; pCtx=pCtx->pPrior){ if( pCtx->pTab==pTab ){ *pzErr = sqlite3MPrintf(db, "vtable constructor called recursively: %s", pTab->zName ); return SQLITE_LOCKED; } } zModuleName = sqlite3DbStrDup(db, pTab->zName); if( !zModuleName ){ return SQLITE_NOMEM_BKPT; } | > | > > > > > > > > | 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 | int rc; const char *const*azArg; int nArg = pTab->u.vtab.nArg; char *zErr = 0; char *zModuleName; int iDb; VtabCtx *pCtx; int nByte; /* Bytes of space to allocate */ assert( IsVirtual(pTab) ); azArg = (const char *const*)pTab->u.vtab.azArg; /* Check that the virtual-table is not already being initialized */ for(pCtx=db->pVtabCtx; pCtx; pCtx=pCtx->pPrior){ if( pCtx->pTab==pTab ){ *pzErr = sqlite3MPrintf(db, "vtable constructor called recursively: %s", pTab->zName ); return SQLITE_LOCKED; } } zModuleName = sqlite3DbStrDup(db, pTab->zName); if( !zModuleName ){ return SQLITE_NOMEM_BKPT; } nByte = sizeof(VTable); #ifdef SQLITE_ENABLE_SHARED_SCHEMA nByte += sqlite3Strlen30(pTab->zName) + 1; #endif pVTable = (VTable*)sqlite3MallocZero(nByte); if( !pVTable ){ sqlite3OomFault(db); sqlite3DbFree(db, zModuleName); return SQLITE_NOMEM_BKPT; } pVTable->db = db; pVTable->pMod = pMod; #ifdef SQLITE_ENABLE_SHARED_SCHEMA pVTable->zName = (char*)&pVTable[1]; memcpy(pVTable->zName, pTab->zName, nByte-sizeof(VTable)); #endif pVTable->eVtabRisk = SQLITE_VTABRISK_Normal; iDb = sqlite3SchemaToIndex(db, pTab->pSchema); pTab->u.vtab.azArg[1] = db->aDb[iDb].zDbSName; /* Invoke the virtual table constructor */ assert( &db->pVtabCtx ); |
︙ | ︙ | |||
638 639 640 641 642 643 644 | *pzErr = sqlite3MPrintf(db, zFormat, zModuleName); sqlite3VtabUnlock(pVTable); rc = SQLITE_ERROR; }else{ int iCol; u16 oooHidden = 0; /* If everything went according to plan, link the new VTable structure | | > > | | | > > > > > > > > | | > | 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 | *pzErr = sqlite3MPrintf(db, zFormat, zModuleName); sqlite3VtabUnlock(pVTable); rc = SQLITE_ERROR; }else{ int iCol; u16 oooHidden = 0; /* If everything went according to plan, link the new VTable structure ** into the linked list headed by pTab->u.vtab.p. Or, if this is a ** reusable schema, into the linked list headed by Db.pVTable. ** ** Then loop through the columns of the table to see if any of them ** contain the token "hidden". If so, set the Column COLFLAG_HIDDEN flag ** and remove the token from the type string. */ #ifdef SQLITE_ENABLE_SHARED_SCHEMA if( IsSharedSchema(db) && iDb!=1 ){ pVTable->pNext = db->aDb[iDb].pVTable; db->aDb[iDb].pVTable = pVTable; }else #endif /* ifdef SQLITE_ENABLE_SHARED_SCHEMA */ { assert( IsVirtual(pTab) ); pVTable->pNext = pTab->u.vtab.p; pTab->u.vtab.p = pVTable; } for(iCol=0; iCol<pTab->nCol; iCol++){ char *zType = sqlite3ColumnType(&pTab->aCol[iCol], ""); int nType; int i = 0; nType = sqlite3Strlen30(zType); for(i=0; i<nType; i++){ |
︙ | ︙ | |||
698 699 700 701 702 703 704 705 706 707 708 709 710 711 | const char *zMod; Module *pMod; int rc; assert( pTab ); assert( IsVirtual(pTab) ); if( sqlite3GetVTable(db, pTab) ){ return SQLITE_OK; } /* Locate the required virtual table module */ zMod = pTab->u.vtab.azArg[0]; pMod = (Module*)sqlite3HashFind(&db->aModule, zMod); | > | 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 | const char *zMod; Module *pMod; int rc; assert( pTab ); assert( IsVirtual(pTab) ); if( sqlite3GetVTable(db, pTab) ){ assert( !IsVirtual(pTab) || pTab->nCol>0 ); return SQLITE_OK; } /* Locate the required virtual table module */ zMod = pTab->u.vtab.azArg[0]; pMod = (Module*)sqlite3HashFind(&db->aModule, zMod); |
︙ | ︙ |
Changes to src/where.c.
︙ | ︙ | |||
1512 1513 1514 1515 1516 1517 1518 | sqlite3OomFault(pParse->db); }else if( !pVtab->zErrMsg ){ sqlite3ErrorMsg(pParse, "%s", sqlite3ErrStr(rc)); }else{ sqlite3ErrorMsg(pParse, "%s", pVtab->zErrMsg); } } | | | 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 | sqlite3OomFault(pParse->db); }else if( !pVtab->zErrMsg ){ sqlite3ErrorMsg(pParse, "%s", sqlite3ErrStr(rc)); }else{ sqlite3ErrorMsg(pParse, "%s", pVtab->zErrMsg); } } if( pTab->u.vtab.p && pTab->u.vtab.p->bAllSchemas ){ sqlite3VtabUsesAllSchemas(pParse); } sqlite3_free(pVtab->zErrMsg); pVtab->zErrMsg = 0; return rc; } #endif /* !defined(SQLITE_OMIT_VIRTUALTABLE) */ |
︙ | ︙ |
Added test/reuse1.test.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 | # 2017 August 9 # # 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. # #*********************************************************************** # # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix reuse1 ifcapable !sharedschema { finish_test return } forcedelete test.db2 sqlite3 db2 test.db2 do_execsql_test 1.0 { CREATE TABLE t1(x INTEGER PRIMARY KEY, y UNIQUE, z); CREATE INDEX i1 ON t1(z); PRAGMA schema_version; } {2} do_execsql_test -db db2 1.1 { CREATE TABLE t1(x INTEGER PRIMARY KEY, y UNIQUE, z); CREATE INDEX i1 ON t1(z); PRAGMA schema_version; } {2} do_test 1.2 { db close db2 close sqlite3 db2 test.db2 -shared-schema 1 sqlite3 db test.db -shared-schema 1 } {} do_execsql_test -db db2 1.3.1 { INSERT INTO t1 VALUES(1, 2, 3); INSERT INTO t1 VALUES(4, 5, 6); } do_execsql_test 1.3.2 { SELECT * FROM t1; PRAGMA integrity_check; } {ok} do_execsql_test -db db2 1.3.3 { SELECT * FROM t1; PRAGMA integrity_check; } {1 2 3 4 5 6 ok} sqlite3 db3 test.db2 do_execsql_test -db db3 1.4.1 { ALTER TABLE t1 ADD COLUMN a; } do_execsql_test -db db2 1.4.2 { SELECT * FROM t1; } {1 2 3 {} 4 5 6 {}} do_execsql_test 1.4.3 { SELECT * FROM t1; } {} db3 close sqlite3 db3 test.db do_execsql_test -db db3 1.5.0 { CREATE TRIGGER tr1 AFTER INSERT ON t1 BEGIN SELECT 1, 2, 3; END; } # Check that the schema cannot be modified if the db was opened with # SQLITE_OPEN_REUSE_SCHEMA. # foreach {tn sql} { 1 { CREATE TABLE t2(x, y) } 2 { CREATE INDEX i2 ON t1(z) } 3 { CREATE VIEW v2 AS SELECT * FROM t2 } 4 { ALTER TABLE t1 RENAME TO t3 } 5 { ALTER TABLE t1 ADD COLUMN xyz } 6 { VACUUM } 7 { DROP INDEX i1 } 8 { DROP TABLE t1 } 9 { DROP TRIGGER tr1 } 10 { ANALYZE } 11 { ALTER TABLE t1 RENAME z TO zzz } } { do_catchsql_test 1.5.$tn $sql {1 {attempt to modify read-only schema}} } #------------------------------------------------------------------------- # reset_db forcedelete test.db2 ifcapable fts5 { do_execsql_test 2.0 { CREATE VIRTUAL TABLE ft USING fts5(a); INSERT INTO ft VALUES('one'), ('two'), ('three'); ATTACH 'test.db2' AS aux; CREATE VIRTUAL TABLE aux.ft USING fts5(a); INSERT INTO aux.ft VALUES('aux1'), ('aux2'), ('aux3'); } db close sqlite3 db test.db -shared-schema 1 do_execsql_test 2.1 { ATTACH 'test.db2' AS aux; SELECT * FROM main.ft; } {one two three} breakpoint do_execsql_test 2.2 { SELECT * FROM aux.ft; } {aux1 aux2 aux3} do_execsql_test 2.2 { SELECT * FROM aux.ft_content; } {1 aux1 2 aux2 3 aux3} } #------------------------------------------------------------------------- # reset_db forcedelete test.db2 do_execsql_test 3.0 { CREATE TABLE t1(a PRIMARY KEY, b, c); CREATE VIEW v1 AS SELECT * FROM t1; CREATE TRIGGER v1_ins INSTEAD OF INSERT ON v1 BEGIN INSERT INTO t1 VALUES(new.a, new.b, new.c); END; CREATE TRIGGER v1_del INSTEAD OF DELETE ON v1 BEGIN DELETE FROM t1 WHERE a=old.a; END; CREATE TRIGGER v1_up INSTEAD OF UPDATE ON v1 BEGIN UPDATE t1 SET a=new.a, b=new.b, c=new.c WHERE a=old.a; END; } forcecopy test.db test.db2 do_test 3.1 { sqlite3 db2 test.db2 execsql { INSERT INTO t1 VALUES(1, 2, 3) } db execsql { INSERT INTO t1 VALUES(4, 5, 6) } db2 db2 close execsql { ATTACH 'test.db2' AS aux; } } {} do_execsql_test 3.2 { SELECT * FROM main.v1; } {1 2 3} do_execsql_test 3.3 { SELECT * FROM aux.v1; } {4 5 6} db close sqlite3 db test.db -shared-schema 1 do_execsql_test 3.4 { ATTACH 'test.db2' AS aux } {} do_execsql_test 3.5 { SELECT * FROM main.v1 } {1 2 3} do_execsql_test 3.6 { SELECT * FROM aux.v1 } {4 5 6} do_execsql_test 3.7.1 { INSERT INTO aux.t1 VALUES(8, 9, 10); } do_execsql_test 3.7.2 { SELECT * FROM main.v1 } {1 2 3} do_execsql_test 3.7.3 { SELECT * FROM aux.v1 } {4 5 6 8 9 10} do_execsql_test 3.8.1 { DELETE FROM aux.t1 WHERE b=5 } do_execsql_test 3.8.2 { SELECT * FROM main.v1 } {1 2 3} do_execsql_test 3.8.3 { SELECT * FROM aux.v1 } {8 9 10} do_execsql_test 3.9.1 { UPDATE aux.t1 SET b='abc' } do_execsql_test 3.9.2 { SELECT * FROM main.v1 } {1 2 3} do_execsql_test 3.9.3 { SELECT * FROM aux.v1 } {8 abc 10} do_execsql_test 3.10.1 { INSERT INTO aux.v1 VALUES(11, 12, 13) } do_execsql_test 3.10.2 { SELECT * FROM main.v1 } {1 2 3} do_execsql_test 3.10.3 { SELECT * FROM aux.v1 } {8 abc 10 11 12 13} do_execsql_test 3.11.1 { DELETE FROM aux.v1 WHERE b='abc' } do_execsql_test 3.11.2 { SELECT * FROM main.v1 } {1 2 3} do_execsql_test 3.11.3 { SELECT * FROM aux.v1 } {11 12 13} do_execsql_test 3.12.1 { UPDATE aux.v1 SET b='def' } do_execsql_test 3.12.2 { SELECT * FROM main.v1 } {1 2 3} do_execsql_test 3.12.3 { SELECT * FROM aux.v1 } {11 def 13} do_execsql_test 3.13.1 { CREATE TEMP TRIGGER xyz AFTER INSERT ON aux.t1 BEGIN INSERT INTO v1 VALUES(new.a, new.b, new.c); END } do_execsql_test 3.13.2 { INSERT INTO aux.v1 VALUES('x', 'y', 'z'); } do_execsql_test 3.13.3 { SELECT * FROM v1; } {1 2 3 x y z} #------------------------------------------------------------------------- # reset_db forcedelete test.db2 do_execsql_test 4.0 { CREATE TABLE t1(a PRIMARY KEY, b, c UNIQUE); CREATE TABLE del(a, b, c); CREATE TRIGGER tr1 AFTER DELETE ON t1 BEGIN INSERT INTO del VALUES(old.a, old.b, old.c); END; } forcecopy test.db test.db2 db close sqlite3 db test.db -shared-schema 1 execsql { ATTACH 'test.db2' AS aux; PRAGMA recursive_triggers = 1; } do_execsql_test 4.1 { INSERT INTO main.t1 VALUES(1, 2, 3); INSERT INTO aux.t1 VALUES(4, 5, 6); } do_execsql_test 4.2.1 { INSERT OR REPLACE INTO aux.t1 VALUES('a', 'b', 6); SELECT * FROM aux.t1; } {a b 6} do_execsql_test 4.2.2 { SELECT * FROM aux.del } {4 5 6} do_execsql_test 4.2.3 { SELECT * FROM main.del } {} do_execsql_test 4.3.1 { INSERT INTO aux.t1 VALUES('x', 'y', 'z'); UPDATE OR REPLACE aux.t1 SET c='z' WHERE a='a'; } {} do_execsql_test 4.3.2 { SELECT * FROM aux.del } {4 5 6 x y z} do_execsql_test 4.3.3 { SELECT * FROM main.del } {} #------------------------------------------------------------------------- # reset_db do_execsql_test 5.0 { CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c); CREATE TABLE t2(a INTEGER PRIMARY KEY, b, c); CREATE INDEX i1 ON t1(b); INSERT INTO t1 VALUES(1, 2, 3), (4, 5, 6); ANALYZE; PRAGMA writable_schema = 1; DELETE FROM sqlite_stat1; } db close forcecopy test.db test.db2 sqlite3 db test.db -shared-schema 1 execsql { ATTACH 'test.db2' AS aux } foreach {tn sql} { 1 { CREATE TABLE t3(x) } 2 { DROP TABLE t2 } 3 { CREATE INDEX i2 ON t2(b) } 4 { DROP INDEX i1 } 5 { ALTER TABLE t1 ADD COLUMN d } 6 { ALTER TABLE t1 RENAME TO t3 } 7 { ALTER TABLE t1 RENAME c TO d } } { do_catchsql_test 5.1.$tn $sql {1 {attempt to modify read-only schema}} } do_execsql_test 5.2.1 { ANALYZE aux.t1 } {} do_execsql_test 5.2.2 { SELECT * FROM aux.sqlite_stat1 } {t1 i1 {2 1}} do_execsql_test 5.2.3 { SELECT * FROM main.sqlite_stat1 } {} do_test 5.3.0 { sqlite3 db2 test.db2 db2 eval { PRAGMA writable_schema = 1; DELETE FROM sqlite_stat1; } } {} do_execsql_test 5.3.1 { SELECT * FROM aux.sqlite_stat1 } {} do_execsql_test 5.3.2 { ANALYZE aux } {} do_execsql_test 5.3.3 { SELECT * FROM aux.sqlite_stat1 } {t1 i1 {2 1}} do_execsql_test 5.3.4 { SELECT * FROM main.sqlite_stat1 } {} #------------------------------------------------------------------------- # Attempting to run ANALYZE when the required sqlite_statXX functions # are missing is an error (because it would modify the database schema). # reset_db do_execsql_test 5.4 { CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c); CREATE TABLE t2(a INTEGER PRIMARY KEY, b, c); CREATE INDEX i1 ON t1(b); INSERT INTO t1 VALUES(1, 2, 3), (4, 5, 6); } db close sqlite3 db test.db -shared-schema 1 foreach {tn sql} { 1 { ANALYZE } 2 { ANALYZE t1 } 3 { ANALYZE i1 } 4 { ANALYZE main } 5 { ANALYZE main.t1 } 6 { ANALYZE main.i1 } } { do_catchsql_test 5.4.$tn $sql {1 {attempt to modify read-only schema}} } #------------------------------------------------------------------------- # reset_db do_execsql_test 6.0 { CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c); CREATE VIEW v1 AS SELECT * FROM t1; } db close forcecopy test.db test.db2 sqlite3 db test.db -shared-schema 1 execsql { ATTACH 'test.db2' AS aux } do_execsql_test 6.1 { INSERT INTO main.t1(a) VALUES(1), (2), (3); INSERT INTO aux.t1(a) VALUES(4), (5), (6); CREATE TEMP TABLE t2(i,t); INSERT INTO t2 VALUES(2, 'two'), (5, 'five'); } do_execsql_test 6.2 { SELECT t FROM t2 WHERE i IN (SELECT a FROM aux.t1) } {five} do_execsql_test 6.3 { SELECT t FROM t2 WHERE i IN (SELECT a FROM aux.v1) } {five} #------------------------------------------------------------------------- # reset_db do_execsql_test 7.0 { CREATE TABLE p1(a PRIMARY KEY, b); CREATE TABLE p2(a PRIMARY KEY, b); CREATE TABLE c1(x REFERENCES p1 ON UPDATE CASCADE ON DELETE CASCADE); } db close forcecopy test.db test.db2 sqlite3 db test.db -shared-schema 1 execsql { ATTACH 'test.db2' AS aux } do_execsql_test 7.1 { INSERT INTO aux.p1 VALUES(1, 'one'); INSERT INTO aux.p1 VALUES(2, 'two'); PRAGMA foreign_keys = on; } do_execsql_test 7.2 { INSERT INTO aux.c1 VALUES(2); } do_execsql_test 7.3.1 { PRAGMA foreign_keys = off; INSERT INTO main.p2 SELECT * FROM aux.p1; } do_execsql_test 7.3.2 { SELECT * FROM main.p2; } {1 one 2 two} do_execsql_test 7.3.3 { INSERT INTO aux.p2 VALUES(1, 2); } do_execsql_test 7.3.4 { SELECT main.p2.a FROM main.p2, aux.p2; } {1 2} do_execsql_test 7.3.5 { SELECT * FROM main.p2, aux.p2; } {1 one 1 2 2 two 1 2} do_execsql_test 7.4 { SELECT count(*) FROM aux.p2; } {1} finish_test |
Added test/reuse2.test.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 | # 2017 August 9 # # 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. # #*********************************************************************** # # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix reuse2 ifcapable !sharedschema { finish_test return } do_execsql_test 1.0 { CREATE TABLE t1(x INTEGER PRIMARY KEY, y UNIQUE, z); CREATE INDEX i1 ON t1(z); PRAGMA schema_version; } {2} do_test 1.2 { catch { db close } catch { db2 close } sqlite3 db2 test.db -shared-schema 1 sqlite3 db test.db -shared-schema 1 } {} do_execsql_test -db db2 1.3.1 { INSERT INTO t1 VALUES(1, 2, 3); } do_execsql_test -db db2 1.3.2 { INSERT INTO t1 VALUES(4, 5, 6); } do_execsql_test 1.3.3 { SELECT * FROM t1; } {1 2 3 4 5 6} #-------------------------------------------------------------------------- reset_db ifcapable fts5 { do_execsql_test 2.0 { CREATE VIRTUAL TABLE ft USING fts5(c); INSERT INTO ft VALUES('one two three'); } db close sqlite3 db test.db -shared-schema 1 do_execsql_test 2.1 { SELECT * FROM ft } {{one two three}} } #-------------------------------------------------------------------------- reset_db do_execsql_test 3.0 { CREATE TABLE t1(x INTEGER PRIMARY KEY, y UNIQUE, z); CREATE INDEX i1 ON t1(z); PRAGMA schema_version; } {2} do_test 3.1 { sqlite3 db1 test.db -shared-schema 1 sqlite3 db2 test.db -shared-schema 1 } {} do_execsql_test -db db1 3.2.1 { SELECT * FROM t1 } do_execsql_test -db db2 3.2.2 { SELECT * FROM t1 } register_schemapool_module db do_execsql_test 3.3 { SELECT 'nref=' || nRef, 'nschema=' || nSchema, 'ndelete=' || nDelete FROM schemapool; } {nref=2 nschema=1 ndelete=0} sqlite3 db3 test.db -shared-schema 1 register_schemapool_module db3 do_execsql_test 3.5 { SELECT 'nref=' || nRef, 'nschema=' || nSchema, 'ndelete=' || nDelete FROM schemapool; } {nref=2 nschema=1 ndelete=0} do_execsql_test -db db3 3.6 { SELECT * FROM t1; SELECT 'nref=' || nRef, 'nschema=' || nSchema, 'ndelete=' || nDelete FROM schemapool; } {nref=3 nschema=1 ndelete=0} do_execsql_test 3.7 { CREATE TABLE t2(x); } do_execsql_test 3.8 { SELECT 'nref=' || nRef, 'nschema=' || nSchema, 'ndelete=' || nDelete FROM schemapool; } {nref=3 nschema=1 ndelete=0} do_execsql_test -db db1 3.9.1 { SELECT * FROM t1 } do_execsql_test 3.9.2 { SELECT 'nref=' || nRef, 'nschema=' || nSchema, 'ndelete=' || nDelete FROM schemapool; } {nref=1 nschema=1 ndelete=0 nref=2 nschema=1 ndelete=0} do_execsql_test -db db2 3.10.1 { SELECT * FROM t1 } do_execsql_test 3.10.2 { SELECT 'nref=' || nRef, 'nschema=' || nSchema, 'ndelete=' || nDelete FROM schemapool ORDER BY 1; } {nref=1 nschema=1 ndelete=0 nref=2 nschema=1 ndelete=0} do_execsql_test -db db3 3.11.1 { SELECT * FROM t1 } do_execsql_test 3.11.2 { SELECT 'nref=' || nRef, 'nschema=' || nSchema, 'ndelete=' || nDelete FROM schemapool; } {nref=3 nschema=1 ndelete=0} #-------------------------------------------------------------------------- catch {db1 close} catch {db2 close} catch {db3 close} reset_db do_execsql_test 4.0.1 { CREATE TABLE x1(a, b, c); CREATE INDEX x1a ON x1(a); CREATE INDEX x1b ON x1(b); } do_test 4.0.2 { db close for {set i 1} {$i < 6} {incr i} { forcedelete test.db${i}-journal test.db${i}-wal test.db${i}-wal2 forcecopy test.db test.db${i} } sqlite3 db test.db sqlite3 db2 test.db -shared-schema 1 } {} register_schemapool_module db do_execsql_test 4.0.3 { SELECT 'nref=' || nRef, 'nschema=' || nSchema, 'ndelete=' || nDelete FROM schemapool; } {} do_test 4.1.1 { execsql { ATTACH 'test.db1' AS db1; ATTACH 'test.db2' AS db2; ATTACH 'test.db3' AS db3; ATTACH 'test.db4' AS db4; ATTACH 'test.db5' AS db5; } db2 } {} do_execsql_test 4.1.2 { SELECT 'nref=' || nRef, 'nschema=' || nSchema, 'ndelete=' || nDelete FROM schemapool; } {nref=1 nschema=1 ndelete=0} do_execsql_test -db db2 4.1.3 { SELECT * FROM db3.x1 } do_execsql_test 4.1.4 { SELECT 'nref=' || nRef, 'nschema=' || nSchema, 'ndelete=' || nDelete FROM schemapool; } {nref=2 nschema=1 ndelete=0} do_execsql_test -db db2 4.1.5 { SELECT * FROM db2.x1 } do_execsql_test 4.1.6 { SELECT 'nref=' || nRef, 'nschema=' || nSchema, 'ndelete=' || nDelete FROM schemapool; } {nref=3 nschema=1 ndelete=0} do_execsql_test -db db2 4.1.7 { SELECT * FROM x1 } do_execsql_test 4.1.8 { SELECT 'nref=' || nRef, 'nschema=' || nSchema, 'ndelete=' || nDelete FROM schemapool; } {nref=3 nschema=1 ndelete=0} do_test 4.2.1 { catchsql { SELECT * FROM abc } db2 } {1 {no such table: abc}} do_execsql_test 4.2.2 { SELECT 'nref=' || nRef, 'nschema=' || nSchema, 'ndelete=' || nDelete FROM schemapool; } {nref=6 nschema=1 ndelete=0} register_schemapool_module db2 do_execsql_test -db db2 4.3.1 { INSERT INTO x1 VALUES(1, 2, 3); INSERT INTO db1.x1 VALUES(4, 5, 6); INSERT INTO db2.x1 VALUES(7, 8, 9); INSERT INTO db3.x1 VALUES(10, 11, 12); INSERT INTO db4.x1 VALUES(13, 14, 15); INSERT INTO db5.x1 VALUES(16, 17, 18); SELECT 'nref=' || nRef, 'nschema=' || nSchema, 'ndelete=' || nDelete FROM schemapool; } {nref=6 nschema=1 ndelete=0} do_execsql_test -db db2 4.3.2 { SELECT * FROM db5.x1; SELECT * FROM db4.x1; SELECT * FROM db3.x1; SELECT * FROM db2.x1; SELECT * FROM db1.x1; SELECT * FROM x1; SELECT 'nref=' || nRef, 'nschema=' || nSchema, 'ndelete=' || nDelete FROM schemapool; } { 16 17 18 13 14 15 10 11 12 7 8 9 4 5 6 1 2 3 nref=6 nschema=1 ndelete=0 } do_execsql_test -db db2 4.3.3 { UPDATE x1 SET a=a+10; UPDATE db5.x1 SET a=a+10; SELECT 'nref=' || nRef, 'nschema=' || nSchema, 'ndelete=' || nDelete FROM schemapool; } { nref=6 nschema=1 ndelete=0 } do_execsql_test -db db2 4.3.4 { SELECT * FROM db5.x1; SELECT * FROM db4.x1; SELECT * FROM db3.x1; SELECT * FROM db2.x1; SELECT * FROM db1.x1; SELECT * FROM x1; SELECT 'nref=' || nRef, 'nschema=' || nSchema, 'ndelete=' || nDelete FROM schemapool; } { 26 17 18 13 14 15 10 11 12 7 8 9 4 5 6 11 2 3 nref=6 nschema=1 ndelete=0 } do_execsql_test -db db2 4.3.5 { DELETE FROM db3.x1; DELETE FROM x1; SELECT 'nref=' || nRef, 'nschema=' || nSchema, 'ndelete=' || nDelete FROM schemapool; } { nref=6 nschema=1 ndelete=0 } do_execsql_test -db db2 4.3.6 { SELECT * FROM db5.x1; SELECT * FROM db4.x1; SELECT * FROM db3.x1; SELECT * FROM db2.x1; SELECT * FROM db1.x1; SELECT * FROM x1; SELECT 'nref=' || nRef, 'nschema=' || nSchema, 'ndelete=' || nDelete FROM schemapool; } { 26 17 18 13 14 15 7 8 9 4 5 6 nref=6 nschema=1 ndelete=0 } do_execsql_test -db db2 4.3.6 { SELECT * FROM db5.x1, db4.x1, db1.x1; SELECT 'nref=' || nRef, 'nschema=' || nSchema, 'ndelete=' || nDelete FROM schemapool; } {26 17 18 13 14 15 4 5 6 nref=6 nschema=3 ndelete=0} #-------------------------------------------------------------------------- # Test the incremental-blob API with REUSE_SCHEMA connections. # catch {db1 close} catch {db2 close} catch {db3 close} reset_db do_execsql_test 5.0.1 { CREATE TABLE bbb(a INTEGER PRIMARY KEY, b); } db close do_test 5.0.2 { sqlite3 db2 test.db -shared-schema 1 register_schemapool_module db2 for {set i 1} {$i<6} {incr i} { forcedelete test.db${i}-journal test.db${i}-wal test.db${i}-wal2 forcecopy test.db test.db${i} sqlite3 db test.db${i} db eval { INSERT INTO bbb VALUES(123, 'database_' || $i) } db close db2 eval "ATTACH 'test.db${i}' AS db${i}" } execsql { SELECT 'nref=' || nRef, 'nschema=' || nSchema, 'ndelete=' || nDelete FROM schemapool; } db2 } {nref=6 nschema=1 ndelete=0} do_test 5.1.1 { set res [list] for {set i 1} {$i<6} {incr i} { set chan [db2 incrblob db${i} bbb b 123] lappend res [gets $chan] close $chan } set res } {database_1 database_2 database_3 database_4 database_5} do_execsql_test -db db2 5.1.2 { SELECT 'nref=' || nRef, 'nschema=' || nSchema, 'ndelete=' || nDelete FROM schemapool; } {nref=6 nschema=1 ndelete=0} do_test 5.2.1 { sqlite3_table_column_metadata db2 main bbb a } {INTEGER BINARY 0 1 0} do_test 5.2.2 { sqlite3_table_column_metadata db2 main bbb b } {{} BINARY 0 0 0} do_execsql_test -db db2 5.2.3 { SELECT 'nref=' || nRef, 'nschema=' || nSchema, 'ndelete=' || nDelete FROM schemapool; } {nref=6 nschema=1 ndelete=0} do_execsql_test -db db2 5.2.4 { PRAGMA integrity_check; SELECT 'nref=' || nRef, 'nschema=' || nSchema, 'ndelete=' || nDelete FROM schemapool; } {ok nref=6 nschema=1 ndelete=5} finish_test |
Added test/reuse3.test.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 | # 2019 February 12 # # 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. # #*********************************************************************** # # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix reuse3 ifcapable !sharedschema { finish_test return } do_execsql_test 1.0 { CREATE TABLE t1(x INTEGER PRIMARY KEY, y UNIQUE, z); CREATE INDEX i1 ON t1(z); CREATE TABLE t2(a); } {} db close sqlite3 db test.db -shared-schema 1 do_execsql_test 1.1 { CREATE TEMP VIEW v1 AS SELECT * FROM t1; SELECT * FROM v1; } do_execsql_test 1.2 { CREATE TEMP TRIGGER tr1 AFTER INSERT ON t1 BEGIN INSERT INTO t2 VALUES(new.x); END; } do_execsql_test 1.3 { INSERT INTO t1 VALUES(1, 2, 3); } do_execsql_test 1.4 { SELECT * FROM t2 } {1} do_execsql_test 1.5 { SELECT * FROM v1 } {1 2 3} do_execsql_test 1.6 { BEGIN; DROP TRIGGER tr1; ROLLBACK; } do_execsql_test 1.7 { SELECT * FROM v1 } {1 2 3} do_execsql_test 1.8 { INSERT INTO t1 VALUES(4, 5, 6); SELECT * FROM t2 } {1 4} do_execsql_test 1.9 { SELECT * FROM v1 } {1 2 3 4 5 6} #------------------------------------------------------------------------- # Test error messages when parsing the schema with a REUSE_SCHEMA # connection. reset_db do_execsql_test 2.0 { CREATE TABLE x1(a, b, c); CREATE TABLE y1(d, e, f); PRAGMA writable_schema = 1; UPDATE sqlite_master SET sql = 'CREATE TBL y1(d, e, f)' WHERE name = 'y1'; } db close sqlite3 db test.db -shared-schema 1 do_catchsql_test 2.1 { SELECT * FROM x1; } {1 {malformed database schema (y1) - near "TBL": syntax error}} do_catchsql_test 2.2 { SELECT * FROM x1; } {1 {malformed database schema (y1) - near "TBL": syntax error}} #------------------------------------------------------------------------- reset_db do_execsql_test 3.0 { CREATE TABLE x1(a, b, c); CREATE INDEX i1 ON x1(a, b, c); CREATE TRIGGER tr1 AFTER INSERT ON x1 BEGIN SELECT 1, 2, 3, 4, 5; END; INSERT INTO x1 VALUES(1, 2, 3); } sqlite3 db1 test.db -shared-schema 1 do_test 3.1 { execsql { SELECT * FROM x1 } db1 set N [lindex [sqlite3_db_status db1 SCHEMA_USED 0] 1] expr $N==$N } 1 sqlite3 db2 test.db -shared-schema 1 do_test 3.2 { execsql { SELECT * FROM x1 } db2 set N2 [lindex [sqlite3_db_status db2 SCHEMA_USED 0] 1] expr $N2>($N/2) && $N2<($N/2)+400 } 1 sqlite3 db3 test.db -shared-schema 1 sqlite3 db4 test.db -shared-schema 1 do_test 3.3 { execsql { SELECT * FROM x1 } db3 execsql { SELECT * FROM x1 } db4 set N4 [lindex [sqlite3_db_status db2 SCHEMA_USED 0] 1] set M [expr 2*($N-$N2)] set {} {} } {} do_test 3.3.1 { expr {(($M / 4) + $N-$M)} } "#/$N4/" catch { db1 close } catch { db2 close } catch { db3 close } catch { db4 close } #------------------------------------------------------------------------- # 4.1 Test the REINDEX command. # 4.2 Test CREATE TEMP ... commands. # reset_db do_execsql_test 4.1.0 { CREATE TABLE x1(a, b, c); CREATE INDEX x1a ON x1(a); CREATE INDEX x1b ON x1(b); CREATE INDEX x1c ON x1(c); } db close sqlite3 db test.db -shared-schema 1 do_execsql_test 4.1.1 { REINDEX x1; REINDEX x1a; REINDEX x1b; REINDEX x1c; REINDEX; } do_test 4.1.2 { for {set i 1} {$i < 5} {incr i} { forcedelete test.db${i} test.db${i}-wal test.db${i}-journal forcecopy test.db test.db${i} execsql "ATTACH 'test.db${i}' AS db${i}" } register_schemapool_module db set {} {} execsql { SELECT 'nref=' || nRef, 'nschema=' || nSchema, 'ndelete=' || nDelete FROM schemapool } } {nref=5 nschema=1 ndelete=0} do_execsql_test 4.1.3 { REINDEX x1; REINDEX x1a; REINDEX x1b; REINDEX x1c; REINDEX db1.x1a; REINDEX db2.x1b; REINDEX db3.x1c; } do_execsql_test 4.1.4 { SELECT 'nref=' || nRef, 'nschema=' || nSchema, 'ndelete=' || nDelete FROM schemapool } {nref=5 nschema=1 ndelete=28} #------------------------------------------------------------------------- db close sqlite3 db test.db -shared-schema 1 register_schemapool_module db do_execsql_test 4.2.0 { ATTACH 'test.db1' AS db1; ATTACH 'test.db2' AS db2; ATTACH 'test.db3' AS db3; ATTACH 'test.db4' AS db4; SELECT * FROM db1.x1; SELECT * FROM db2.x1; SELECT * FROM db3.x1; SELECT * FROM db4.x1; } do_execsql_test 4.2.1 { SELECT 'nref=' || nRef, 'nschema=' || nSchema, 'ndelete=' || nDelete FROM schemapool; } {nref=5 nschema=1 ndelete=0} do_execsql_test 4.2.2 { CREATE TEMP TABLE t1(a, b, c); SELECT 'nref=' || nRef, 'nschema=' || nSchema, 'ndelete=' || nDelete FROM schemapool; } {nref=5 nschema=1 ndelete=0} do_execsql_test 4.2.3 { CREATE INDEX t1a ON t1(a); SELECT 'nref=' || nRef, 'nschema=' || nSchema, 'ndelete=' || nDelete FROM schemapool; } {nref=5 nschema=1 ndelete=0} do_execsql_test 4.2.4 { CREATE TRIGGER tr1 AFTER INSERT ON t1 BEGIN SELECT 1,2,3,4; END; SELECT 'nref=' || nRef, 'nschema=' || nSchema, 'ndelete=' || nDelete FROM schemapool; } {nref=5 nschema=1 ndelete=0} do_execsql_test 4.2.5 { DROP TABLE t1; SELECT 'nref=' || nRef, 'nschema=' || nSchema, 'ndelete=' || nDelete FROM schemapool; } {nref=5 nschema=1 ndelete=0} do_execsql_test 4.2.6 { CREATE TEMP TRIGGER tr1 AFTER INSERT ON db2.x1 BEGIN SELECT 1,2,3,4; END; SELECT 'nref=' || nRef, 'nschema=' || nSchema, 'ndelete=' || nDelete FROM schemapool; } {nref=5 nschema=1 ndelete=0} do_execsql_test 4.2.7 { DROP TRIGGER tr1; SELECT 'nref=' || nRef, 'nschema=' || nSchema, 'ndelete=' || nDelete FROM schemapool; } {nref=5 nschema=1 ndelete=4} #-------------------------------------------------------------------------- reset_db do_execsql_test 5.0 { CREATE TABLE t1(a, b); CREATE TABLE t2(a, b); CREATE TABLE t3(a, b); } sqlite3 db2 test.db -shared-schema 1 register_schemapool_module db2 do_execsql_test 5.1 { PRAGMA writable_schema = 1; UPDATE sqlite_master SET sql='CREATE TABLE t3 a,b' WHERE name = 't3'; } do_test 5.2 { catchsql { SELECT * FROM t1 } db2 } {1 {malformed database schema (t3) - near "a": syntax error}} do_test 5.3 { catchsql { SELECT nref,nschema FROM schemapool } db2 } {1 {malformed database schema (t3) - near "a": syntax error}} do_execsql_test 5.4 { PRAGMA writable_schema = 1; UPDATE sqlite_master SET sql='CREATE TABLE t3(a,b)' WHERE name = 't3'; } do_test 5.5 { catchsql { SELECT nref,nschema FROM schemapool } db2 } {0 {1 1}} db2 close db close do_test 5.6.1 { forcedelete test.db2 test.db2-wal test.db2-journal forcecopy test.db test.db2 sqlite3 db test.db sqlite3 db2 test.db -shared-schema 1 sqlite3 db3 test.db2 -shared-schema 1 register_schemapool_module db } {} do_execsql_test -db db2 5.6.2 { SELECT * FROM t1 } do_execsql_test -db db3 5.6.3 { SELECT * FROM t1 } do_execsql_test 5.6.4 { SELECT 'nref=' || nRef, 'nschema=' || nSchema FROM schemapool; CREATE TABLE t4(x); DROP TABLE t4; } {nref=2 nschema=1} do_execsql_test -db db2 5.6.5 { SELECT * FROM t1 } do_execsql_test -db db3 5.6.6 { SELECT * FROM t1 } do_execsql_test 5.6.7 { SELECT 'nref=' || nRef, 'nschema=' || nSchema FROM schemapool; ATTACH 'test.db2' AS db2; CREATE TABLE db2.t4(x); DROP TABLE db2.t4; } {nref=1 nschema=1 nref=1 nschema=1} do_execsql_test -db db2 5.6.8 { SELECT * FROM t1 } do_execsql_test -db db3 5.6.9 { SELECT * FROM t1 } do_execsql_test 5.6.10 { SELECT 'nref=' || nRef, 'nschema=' || nSchema FROM schemapool; } {nref=2 nschema=1} #------------------------------------------------------------------------- reset_db do_execsql_test 6.0 { CREATE TABLE t1(a, b); CREATE TABLE t2(a, b); CREATE TABLE t3(a, b); } do_test 6.1 { db close sqlite3 db test.db -shared-schema 1 for {set i 1} {$i < 5} {incr i} { set base "test.db$i" set nm "aux$i" forcedelete $base $base-wal $base-journal forcecopy test.db $base execsql "ATTACH '$base' AS $nm" } } {} do_test 6.2 { set N1 [lindex [sqlite3_db_status db SCHEMA_USED 0] 1] set N2 [lindex [sqlite3_db_status db SCHEMA_USED 0] 1] expr {$N1>0 && $N2>0 && $N1==$N2} } {1} do_test 6.3 { execsql { SELECT * FROM main.t1 } set N1 [lindex [sqlite3_db_status db SCHEMA_USED 0] 1] set N2 [lindex [sqlite3_db_status db SCHEMA_USED 0] 1] expr {$N1>0 && $N2>0 && $N1==$N2} } {1} do_test 6.4 { execsql { SELECT * FROM aux1.t1 } set N3 [lindex [sqlite3_db_status db SCHEMA_USED 0] 1] set N4 [lindex [sqlite3_db_status db SCHEMA_USED 0] 1] list $N3 $N4 } "#/$N1 $N1/" finish_test |
Added test/reuse4.test.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 | # 2019 February 12 # # 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. # #*********************************************************************** # # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix reuse4 ifcapable !sharedschema { finish_test return } foreach {tn sharedschema} { 1 0 2 1 } { reset_db do_execsql_test 1.$tn.0 { CREATE TABLE x1(a, b); CREATE INDEX x1a ON x1(a); CREATE INDEX x1b ON x1(b); CREATE TABLE x2(a, b); } db close do_test 1.$tn.1 { for {set i 1} {$i<4} {incr i} { forcedelete test.db$i test.db$i-journal test.db$i-wal forcecopy test.db test.db$i } sqlite3 db test.db -shared-schema $sharedschema for {set i 1} {$i<4} {incr i} { execsql " ATTACH 'test.db$i' AS db$i " } } {} do_execsql_test 1.$tn.2 { WITH s(i) AS ( SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<10 ) INSERT INTO x1 SELECT i, i FROM s; INSERT INTO db3.x2 SELECT * FROM x1; INSERT INTO db2.x1 SELECT * FROM db3.x2; CREATE TEMP TRIGGER tr1 AFTER INSERT ON db2.x2 BEGIN INSERT INTO x1 VALUES(new.a, new.b); END; INSERT INTO db2.x2 SELECT * FROM x1 WHERE a%2; DELETE FROM x1 WHERE a<3; INSERT INTO db3.x1 SELECT * FROM db2.x2; DETACH db3; ATTACH 'test.db3' AS db3; UPDATE db3.x1 SET a=a-10 WHERE b NOT IN (SELECT b FROM db2.x2); CREATE TEMP TABLE x1(a, b); INSERT INTO db2.x2 VALUES(50, 60), (60, 70), (80, 90); ALTER TABLE x1 RENAME TO x2; ALTER TABLE x2 ADD COLUMN c; ALTER TABLE x2 RENAME a TO aaa; DELETE FROM x1 WHERE b>8; UPDATE db3.x2 SET b=b*10; BEGIN; CREATE TEMP TABLE x5(x); INSERT INTO x5 VALUES(1); ROLLBACK; INSERT INTO main.x2 VALUES(123, 456); } integrity_check 1.$tn.3 do_execsql_test 1.$tn.4 { SELECT * FROM main.x1; SELECT 'xxx'; SELECT * FROM main.x2; SELECT 'xxx'; SELECT * FROM temp.x2; SELECT 'xxx'; SELECT * FROM db1.x1; SELECT 'xxx'; SELECT * FROM db1.x2; SELECT 'xxx'; SELECT * FROM db2.x1; SELECT 'xxx'; SELECT * FROM db2.x2; SELECT 'xxx'; SELECT * FROM db3.x1; SELECT 'xxx'; SELECT * FROM db3.x2; SELECT 'xxx'; } { 3 3 4 4 5 5 6 6 7 7 8 8 3 3 5 5 7 7 xxx 123 456 xxx 50 60 {} 60 70 {} 80 90 {} xxx xxx xxx 1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9 10 10 xxx 1 1 3 3 5 5 7 7 9 9 50 60 60 70 80 90 xxx 1 1 3 3 5 5 7 7 9 9 xxx 1 10 2 20 3 30 4 40 5 50 6 60 7 70 8 80 9 90 10 100 xxx } do_test 1.$tn.5.1 { sqlite3 db2 test.db db2 eval { CREATE TABLE x3(x) } } {} do_execsql_test 1.$tn.5.2 { SELECT * FROM main.x1; SELECT 'xxx'; SELECT * FROM main.x2; SELECT 'xxx'; SELECT * FROM main.x3; SELECT 'xxx'; } { 3 3 4 4 5 5 6 6 7 7 8 8 3 3 5 5 7 7 xxx 123 456 xxx xxx } } #------------------------------------------------------------------------- # Test some PRAGMA statements with shared-schema connections. # reset_db do_execsql_test 2.0 { CREATE TABLE t1(a, b, c); CREATE INDEX t1abc ON t1(a, b, c); } foreach {tn pragma nSchema nDelete} { 1 "PRAGMA synchronous = OFF" 1 0 2 "PRAGMA cache_size = 200" 1 0 3 "PRAGMA aux2.integrity_check" 1 0 4 "PRAGMA integrity_check" 1 5 5 "PRAGMA index_info=t1abc" 1 5 6 "PRAGMA aux3.index_info=t1abc" 1 0 7 "PRAGMA journal_mode" 1 0 8 "PRAGMA aux2.wal_checkpoint" 1 0 9 "PRAGMA wal_checkpoint" 1 0 } { do_test 2.$tn.1 { catch { db close } catch { db2 close } for {set i 1} {$i < 6} {incr i} { forcedelete "test.db$i" "test.db${i}-wal" "test.db${i}-journal" forcecopy test.db test.db$i } sqlite3 db2 test.db -shared-schema 1 for {set i 1} {$i < 6} {incr i} { execsql "ATTACH 'test.db$i' AS aux$i" db2 } } {} sqlite3 db test.db register_schemapool_module db do_test 2.$tn.2 { execsql $pragma db2 execsql { SELECT 'nschema='||nschema, 'ndelete='||nDelete FROM schemapool } } "nschema=$nSchema ndelete=$nDelete" do_test 2.$tn.3 { execsql { SELECT * FROM main.t1,aux1.t1,aux2.t1,aux3.t1,aux4.t1,aux5.t1 } db2 execsql { SELECT 'nschema=' || nschema, 'nref=' || nref FROM schemapool } } "nschema=6 nref=6" } finish_test |
Added test/reuse5.test.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 | # 2019 February 26 # # 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. # #*********************************************************************** # # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix reuse5 set CLI [test_find_cli] ifcapable !sharedschema { finish_test return } do_execsql_test 1.0 { CREATE TABLE t1(x, y); CREATE TABLE t2(a, b, c); CREATE INDEX t1x ON t1(x); CREATE INDEX t1y ON t1(y); CREATE VIEW v1 AS SELECT * FROM t2; } foreach {tn sql out1 out2} { 1 { CREATE TABLE t1(x, y); CREATE TABLE t2(a, b, c); CREATE INDEX t1x ON t1(x); CREATE INDEX t1y ON t1(y); CREATE VIEW v1 AS SELECT * FROM t2; } { test.db2 is compatible } {} 2 { CREATE TABLE t1(x, y); CREATE TABLE t2(a, b, c); CREATE INDEX t1x ON t1(x); CREATE INDEX t1y ON t1(y); CREATE VIEW v1 AS SELECT * FROM t2; CREATE TABLE x1(x); DROP TABLE x1; } { test.db2 is NOT compatible (schema cookie) } { Fixing test.db2... test.db2 is compatible } 3 { CREATE TABLE t1(x, y); CREATE TABLE t2(a, b, c); CREATE INDEX t1y ON t1(y); CREATE VIEW v1 AS SELECT * FROM t2; } { test.db2 is NOT compatible (objects) } {} 4 { CREATE TABLE t1(x, y); CREATE TABLE t2(a, b, c); CREATE INDEX t1x ON t1(X); CREATE INDEX t1y ON t1(y); CREATE VIEW v1 AS SELECT * FROM t2; } { test.db2 is NOT compatible (SQL) } {} 5 { CREATE TABLE t1(x, y); CREATE TABLE t2(a, b, c); CREATE INDEX t1y ON t1(y); CREATE INDEX t1x ON t1(x); CREATE VIEW v1 AS SELECT * FROM t2; } { test.db2 is NOT compatible (root pages) } { Fixing test.db2... test.db2 is compatible } 6 { CREATE TABLE t1(x, y); CREATE TABLE t2(a, b, c); CREATE INDEX t1x ON t1(x); CREATE INDEX t1y ON t1(y); CREATE VIEW v1 AS SELECT * FROM t2; DROP INDEX t1x; CREATE INDEX t1x ON t1(x); } { test.db2 is NOT compatible (order of sqlite_master rows) } { Fixing test.db2... test.db2 is compatible } } { forcedelete test.db2 sqlite3 db2 test.db2 db2 eval $sql db2 close if {$out2==""} {set out2 $out1} do_test 1.$tn.1 { catchcmd test.db ".shared-schema check test.db2" } [list 0 [string trim $out1]] do_test 1.$tn.2 { catchcmd test.db ".shared-schema fix test.db2" } [list 0 [string trim $out2]] do_test 1.$tn.3 { catchcmd test.db2 "PRAGMA integrity_check" } [list 0 ok] } finish_test |
Added test/reuse6.test.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 | # 2019 February 26 # # 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. # #*********************************************************************** # # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix reuse6 ifcapable !sharedschema { finish_test return } do_execsql_test 1.0 { CREATE TABLE t1(x, y); CREATE TABLE t2(a, b, c); CREATE INDEX t1x ON t1(x); CREATE INDEX t1y ON t1(y); CREATE VIEW v1 AS SELECT * FROM t2; INSERT INTO t1 VALUES(1, 2), (3, 4), (5, 6); INSERT INTO t2 VALUES('a', 'b', 'c'), ('d', 'e', 'f'), ('g', 'h', 'i'); ATTACH 'test.db2' AS aux; CREATE TABLE t3(i, ii); INSERT INTO t3 VALUES(10, 20); } sqlite3 db1 test.db -shared-schema 1 sqlite3 db2 test.db -shared-schema 1 do_execsql_test -db db1 1.1 { ATTACH 'test.db2' AS aux; } do_test 1.2 { execsql {SELECT * FROM t3} db1 } {10 20} do_execsql_test -db db2 1.3 { ATTACH 'test.db2' AS aux; } do_test 1.3 { execsql {SELECT * FROM t3} db1 } {10 20} do_execsql_test -db db2 1.5 { SELECT * FROM t3; } {10 20} do_test 1.6 { execsql {SELECT * FROM t3} db1 } {10 20} db1 close db2 close #------------------------------------------------------------------------- reset_db forcedelete test.db2 forcedelete test.db3 do_execsql_test 2.0 { CREATE TABLE t1(x, y); ATTACH 'test.db2' AS aux2; CREATE TABLE aux2.t2(x, y); ATTACH 'test.db3' AS aux3; CREATE TABLE aux3.t3(x, y); } sqlite3 db1 test.db -shared-schema 1 do_execsql_test -db db1 2.1 { ATTACH 'test.db2' AS aux2; ATTACH 'test.db3' AS aux3; } do_test 2.2.1 { catchsql { SELECT * FROM aux2.nosuchtable } db1 } {1 {no such table: aux2.nosuchtable}} do_test 2.2.2 { sqlite3_errcode db1 } {SQLITE_ERROR} db1 close #------------------------------------------------------------------------- reset_db forcedelete test.db2 ifcapable fts5 { do_execsql_test 3.0 { CREATE VIRTUAL TABLE ft USING fts5(a, b); ATTACH 'test.db2' AS aux; CREATE TABLE aux.t1(x, y, z); } sqlite3 db1 test.db -shared-schema 1 do_execsql_test -db db1 3.1 { ATTACH 'test.db2' AS aux; } do_execsql_test -db db1 3.2 { SELECT * FROM main.ft, aux.t1; } db1 close } #------------------------------------------------------------------------- reset_db forcedelete test.db2 ifcapable fts5 { do_execsql_test 4.0 { CREATE VIRTUAL TABLE ft USING fts5(a, b); } forcecopy test.db test.db2 sqlite3 db1 test.db -shared-schema 1 do_execsql_test -db db1 4.1 { ATTACH 'test.db2' AS aux; SELECT * FROM main.ft; SELECT * FROM aux.ft; } do_execsql_test -db db1 4.2 { SELECT * FROM main.ft, aux.ft } } finish_test |
Added test/reusefault.test.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 | # 2019 February 12 # # 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. # #*********************************************************************** # # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix reusefault ifcapable !sharedschema { finish_test return } do_execsql_test 1.0 { PRAGMA cache_size = 10; CREATE TABLE t1(a UNIQUE, b UNIQUE); INSERT INTO t1 VALUES(1, 2), (3, 4); } faultsim_save_and_close do_faultsim_test 1.1 -prep { faultsim_restore sqlite3 db test.db -shared-schema 1 } -body { execsql { SELECT * FROM t1 } } -test { faultsim_test_result {0 {1 2 3 4}} } do_faultsim_test 1.2 -prep { faultsim_restore sqlite3 db test.db -shared-schema 1 execsql { SELECT * FROM t1 } sqlite3 db2 test.db db2 eval {CREATE TABLE a(a)} db2 close } -body { execsql { SELECT * FROM t1 } } -test { faultsim_test_result {0 {1 2 3 4}} } finish_test |
Changes to test/shell9.test.
︙ | ︙ | |||
68 69 70 71 72 73 74 | # Check testdump.txt cannot be processed if the initial db is not empty. # reset_db do_execsql_test 1.2.1 { CREATE TABLE t4(hello); } db close | > | | | | 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 | # Check testdump.txt cannot be processed if the initial db is not empty. # reset_db do_execsql_test 1.2.1 { CREATE TABLE t4(hello); } db close # This works ok on the reuse-schema branch # do_test 1.2.2 { # catchcmd test.db ".read testdump.txt" # } {1 {Parse error near line 5: table sqlite_master may not be modified}} # Check testdump.txt cannot be processed if the db is in safe mode # do_test 1.3.1 { forcedelete test.db catchsafecmd test.db ".read testdump.txt" } {1 {line 1: cannot run .read in safe mode}} |
︙ | ︙ |
Changes to test/tclsqlite.test.
︙ | ︙ | |||
22 23 24 25 26 27 28 29 30 31 32 33 34 35 | set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix tcl # Check the error messages generated by tclsqlite # set r "sqlite_orig HANDLE ?FILENAME? ?-vfs VFSNAME? ?-readonly BOOLEAN? ?-create BOOLEAN? ?-nofollow BOOLEAN? ?-nomutex BOOLEAN? ?-fullmutex BOOLEAN? ?-uri BOOLEAN?" if {[sqlite3 -has-codec]} { append r " ?-key CODECKEY?" } do_test tcl-1.1 { set v [catch {sqlite3 -bogus} msg] regsub {really_sqlite3} $msg {sqlite3} msg lappend v $msg | > > > | 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix tcl # Check the error messages generated by tclsqlite # set r "sqlite_orig HANDLE ?FILENAME? ?-vfs VFSNAME? ?-readonly BOOLEAN? ?-create BOOLEAN? ?-nofollow BOOLEAN? ?-nomutex BOOLEAN? ?-fullmutex BOOLEAN? ?-uri BOOLEAN?" ifcapable sharedschema { append r " ?-shared-schema BOOLEAN?" } if {[sqlite3 -has-codec]} { append r " ?-key CODECKEY?" } do_test tcl-1.1 { set v [catch {sqlite3 -bogus} msg] regsub {really_sqlite3} $msg {sqlite3} msg lappend v $msg |
︙ | ︙ |
Changes to test/tester.tcl.
︙ | ︙ | |||
876 877 878 879 880 881 882 | } proc catchcmd {db {cmd ""}} { global CLI set out [open cmds.txt w] puts $out $cmd close $out | | | 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 | } proc catchcmd {db {cmd ""}} { global CLI set out [open cmds.txt w] puts $out $cmd close $out set line "exec $CLI --unsafe-testing $db < cmds.txt" set rc [catch { eval $line } msg] list $rc $msg } proc catchsafecmd {db {cmd ""}} { global CLI set out [open cmds.txt w] puts $out $cmd |
︙ | ︙ |
Changes to test/testrunner.tcl.
︙ | ︙ | |||
898 899 900 901 902 903 904 | foreach c $clist { add_tcl_jobs "" $c $patternlist } } mdevtest { set config_set { | | > | | 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 | foreach c $clist { add_tcl_jobs "" $c $patternlist } } mdevtest { set config_set { ReuseSchema-O0 ReuseSchema-Debug All-Debug } add_devtest_jobs $config_set [lrange $patternlist 1 end] } sdevtest { set config_set { ReuseSchema-Sanitize All-Debug } add_devtest_jobs $config_set [lrange $patternlist 1 end] } release { set patternlist [lrange $patternlist 1 end] |
︙ | ︙ |
Changes to test/testrunner_data.tcl.
︙ | ︙ | |||
100 101 102 103 104 105 106 107 108 109 110 111 112 113 | set build(All-O0) { -O0 --enable-all } set build(All-Sanitize) { -DSQLITE_OMIT_LOOKASIDE=1 --enable-all -fsanitize=address,undefined -fno-sanitize-recover=undefined } set build(Sanitize) { CC=clang -fsanitize=address,undefined -fno-sanitize-recover=undefined -DSQLITE_ENABLE_STAT4 -DSQLITE_OMIT_LOOKASIDE=1 -DCONFIG_SLOWDOWN_FACTOR=5.0 -DSQLITE_ENABLE_RBU | > > > > > > > > > > > > | 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 | set build(All-O0) { -O0 --enable-all } set build(All-Sanitize) { -DSQLITE_OMIT_LOOKASIDE=1 --enable-all -fsanitize=address,undefined -fno-sanitize-recover=undefined } set build(ReuseSchema-Debug) { --enable-debug --enable-all -DSQLITE_ENABLE_SHARED_SCHEMA } set build(ReuseSchema-O0) { -O0 --enable-all -DSQLITE_ENABLE_SHARED_SCHEMA } set build(ReuseSchema-Sanitize) { -DSQLITE_OMIT_LOOKASIDE=1 -DSQLITE_ENABLE_SHARED_SCHEMA --enable-all -fsanitize=address,undefined -fno-sanitize-recover=undefined } set build(Sanitize) { CC=clang -fsanitize=address,undefined -fno-sanitize-recover=undefined -DSQLITE_ENABLE_STAT4 -DSQLITE_OMIT_LOOKASIDE=1 -DCONFIG_SLOWDOWN_FACTOR=5.0 -DSQLITE_ENABLE_RBU |
︙ | ︙ |
Changes to test/threadtest3.c.
︙ | ︙ | |||
34 35 36 37 38 39 40 | /* ** The "Set Error Line" macro. */ #define SEL(e) ((e)->iLine = ((e)->rc ? (e)->iLine : __LINE__)) /* Database functions */ | | | 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | /* ** The "Set Error Line" macro. */ #define SEL(e) ((e)->iLine = ((e)->rc ? (e)->iLine : __LINE__)) /* Database functions */ #define opendb(w,x,y,z,f) (SEL(w), opendb_x(w,x,y,z,f)) #define closedb(y,z) (SEL(y), closedb_x(y,z)) /* Functions to execute SQL */ #define sql_script(x,y,z) (SEL(x), sql_script_x(x,y,z)) #define integrity_check(x,y) (SEL(x), integrity_check_x(x,y)) #define execsql_i64(x,y,...) (SEL(x), execsql_i64_x(x,y,__VA_ARGS__)) #define execsql_text(x,y,z,...) (SEL(x), execsql_text_x(x,y,z,__VA_ARGS__)) |
︙ | ︙ | |||
541 542 543 544 545 546 547 | return 1; } static void opendb_x( Error *pErr, /* IN/OUT: Error code */ Sqlite *pDb, /* OUT: Database handle */ const char *zFile, /* Database file name */ | | > > | > | 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 | return 1; } static void opendb_x( Error *pErr, /* IN/OUT: Error code */ Sqlite *pDb, /* OUT: Database handle */ const char *zFile, /* Database file name */ int bDelete, /* True to delete db file before opening */ int flags ){ if( pErr->rc==SQLITE_OK ){ int rc; if( flags==0 ){ flags = SQLITE_OPEN_CREATE | SQLITE_OPEN_READWRITE | SQLITE_OPEN_URI; } if( bDelete ) unlink(zFile); rc = sqlite3_open_v2(zFile, &pDb->db, flags, 0); if( rc ){ sqlite_error(pErr, pDb, "open"); sqlite3_close(pDb->db); pDb->db = 0; }else{ |
︙ | ︙ | |||
981 982 983 984 985 986 987 | #define WALTHREAD3_NTHREAD 6 static char *walthread1_thread(int iTid, void *pArg){ Error err = {0}; /* Error code and message */ Sqlite db = {0}; /* SQLite database connection */ int nIter = 0; /* Iterations so far */ | | | 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 | #define WALTHREAD3_NTHREAD 6 static char *walthread1_thread(int iTid, void *pArg){ Error err = {0}; /* Error code and message */ Sqlite db = {0}; /* SQLite database connection */ int nIter = 0; /* Iterations so far */ opendb(&err, &db, "test.db", 0, 0); while( !timetostop(&err) ){ const char *azSql[] = { "SELECT md5sum(x) FROM t1 WHERE rowid != (SELECT max(rowid) FROM t1)", "SELECT x FROM t1 WHERE rowid = (SELECT max(rowid) FROM t1)", }; char *z1, *z2, *z3; |
︙ | ︙ | |||
1020 1021 1022 1023 1024 1025 1026 | } static char *walthread1_ckpt_thread(int iTid, void *pArg){ Error err = {0}; /* Error code and message */ Sqlite db = {0}; /* SQLite database connection */ int nCkpt = 0; /* Checkpoints so far */ | | | | 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 | } static char *walthread1_ckpt_thread(int iTid, void *pArg){ Error err = {0}; /* Error code and message */ Sqlite db = {0}; /* SQLite database connection */ int nCkpt = 0; /* Checkpoints so far */ opendb(&err, &db, "test.db", 0, 0); while( !timetostop(&err) ){ sqlite3_sleep(500); execsql(&err, &db, "PRAGMA wal_checkpoint"); if( err.rc==SQLITE_OK ) nCkpt++; clear_error(&err, SQLITE_BUSY); } closedb(&err, &db); print_and_free_err(&err); return sqlite3_mprintf("%d checkpoints", nCkpt); } static void walthread1(int nMs){ Error err = {0}; /* Error code and message */ Sqlite db = {0}; /* SQLite database connection */ Threadset threads = {0}; /* Test threads */ int i; /* Iterator variable */ opendb(&err, &db, "test.db", 1, 0); sql_script(&err, &db, "PRAGMA journal_mode = WAL;" "CREATE TABLE t1(x PRIMARY KEY);" "INSERT INTO t1 VALUES(randomblob(100));" "INSERT INTO t1 VALUES(randomblob(100));" "INSERT INTO t1 SELECT md5sum(x) FROM t1;" ); |
︙ | ︙ | |||
1072 1073 1074 1075 1076 1077 1078 | const char *zJournal = "PRAGMA journal_mode = WAL"; if( iArg ){ zJournal = "PRAGMA journal_mode = DELETE"; } while( !timetostop(&err) ){ int journal_exists = 0; int wal_exists = 0; | | | 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 | const char *zJournal = "PRAGMA journal_mode = WAL"; if( iArg ){ zJournal = "PRAGMA journal_mode = DELETE"; } while( !timetostop(&err) ){ int journal_exists = 0; int wal_exists = 0; opendb(&err, &db, "test.db", 0, 0); sql_script(&err, &db, zJournal); clear_error(&err, SQLITE_BUSY); sql_script(&err, &db, "BEGIN"); sql_script(&err, &db, "INSERT INTO t1 VALUES(NULL, randomblob(100))"); journal_exists = (filesize(&err, "test.db-journal") >= 0); |
︙ | ︙ | |||
1102 1103 1104 1105 1106 1107 1108 | } static void walthread2(int nMs){ Error err = {0}; Sqlite db = {0}; Threadset threads = {0}; | | | | 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 | } static void walthread2(int nMs){ Error err = {0}; Sqlite db = {0}; Threadset threads = {0}; opendb(&err, &db, "test.db", 1, 0); sql_script(&err, &db, "CREATE TABLE t1(x INTEGER PRIMARY KEY, y UNIQUE)"); closedb(&err, &db); setstoptime(&err, nMs); launch_thread(&err, &threads, walthread2_thread, 0); launch_thread(&err, &threads, walthread2_thread, 0); launch_thread(&err, &threads, walthread2_thread, (void*)1); launch_thread(&err, &threads, walthread2_thread, (void*)1); join_all_threads(&err, &threads); print_and_free_err(&err); } static char *walthread3_thread(int iTid, void *pArg){ Error err = {0}; /* Error code and message */ Sqlite db = {0}; /* SQLite database connection */ i64 iNextWrite; /* Next value this thread will write */ int iArg = PTR2INT(pArg); opendb(&err, &db, "test.db", 0, 0); sql_script(&err, &db, "PRAGMA wal_autocheckpoint = 10"); iNextWrite = iArg+1; while( 1 ){ i64 sum1; i64 sum2; int stop = 0; /* True to stop executing (test timed out) */ |
︙ | ︙ | |||
1159 1160 1161 1162 1163 1164 1165 | static void walthread3(int nMs){ Error err = {0}; Sqlite db = {0}; Threadset threads = {0}; int i; | | | 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 | static void walthread3(int nMs){ Error err = {0}; Sqlite db = {0}; Threadset threads = {0}; int i; opendb(&err, &db, "test.db", 1, 0); sql_script(&err, &db, "PRAGMA journal_mode = WAL;" "CREATE TABLE t1(cnt PRIMARY KEY, sum1, sum2);" "CREATE INDEX i1 ON t1(sum1);" "CREATE INDEX i2 ON t1(sum2);" "INSERT INTO t1 VALUES(0, 0, 0);" ); |
︙ | ︙ | |||
1182 1183 1184 1185 1186 1187 1188 | print_and_free_err(&err); } static char *walthread4_reader_thread(int iTid, void *pArg){ Error err = {0}; /* Error code and message */ Sqlite db = {0}; /* SQLite database connection */ | | | | | | | 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 | print_and_free_err(&err); } static char *walthread4_reader_thread(int iTid, void *pArg){ Error err = {0}; /* Error code and message */ Sqlite db = {0}; /* SQLite database connection */ opendb(&err, &db, "test.db", 0, 0); while( !timetostop(&err) ){ integrity_check(&err, &db); } closedb(&err, &db); print_and_free_err(&err); return 0; } static char *walthread4_writer_thread(int iTid, void *pArg){ Error err = {0}; /* Error code and message */ Sqlite db = {0}; /* SQLite database connection */ i64 iRow = 1; opendb(&err, &db, "test.db", 0, 0); sql_script(&err, &db, "PRAGMA wal_autocheckpoint = 15;"); while( !timetostop(&err) ){ execsql_i64( &err, &db, "REPLACE INTO t1 VALUES(:iRow, randomblob(300))", &iRow ); iRow++; if( iRow==10 ) iRow = 0; } closedb(&err, &db); print_and_free_err(&err); return 0; } static void walthread4(int nMs){ Error err = {0}; Sqlite db = {0}; Threadset threads = {0}; opendb(&err, &db, "test.db", 1, 0); sql_script(&err, &db, "PRAGMA journal_mode = WAL;" "CREATE TABLE t1(a INTEGER PRIMARY KEY, b UNIQUE);" ); closedb(&err, &db); setstoptime(&err, nMs); launch_thread(&err, &threads, walthread4_reader_thread, 0); launch_thread(&err, &threads, walthread4_writer_thread, 0); join_all_threads(&err, &threads); print_and_free_err(&err); } static char *walthread5_thread(int iTid, void *pArg){ Error err = {0}; /* Error code and message */ Sqlite db = {0}; /* SQLite database connection */ i64 nRow; opendb(&err, &db, "test.db", 0, 0); nRow = execsql_i64(&err, &db, "SELECT count(*) FROM t1"); closedb(&err, &db); if( nRow!=65536 ) test_error(&err, "Bad row count: %d", (int)nRow); print_and_free_err(&err); return 0; } static void walthread5(int nMs){ Error err = {0}; Sqlite db = {0}; Threadset threads = {0}; opendb(&err, &db, "test.db", 1, 0); sql_script(&err, &db, "PRAGMA wal_autocheckpoint = 0;" "PRAGMA page_size = 1024;" "PRAGMA journal_mode = WAL;" "CREATE TABLE t1(x);" "BEGIN;" "INSERT INTO t1 VALUES(randomblob(900));" |
︙ | ︙ | |||
1341 1342 1343 1344 1345 1346 1347 | sql_script(pErr, pDb, "COMMIT"); } static void cgt_pager_1(int nMs){ void (*xSub)(Error *, Sqlite *); Error err = {0}; Sqlite db = {0}; | | | 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 | sql_script(pErr, pDb, "COMMIT"); } static void cgt_pager_1(int nMs){ void (*xSub)(Error *, Sqlite *); Error err = {0}; Sqlite db = {0}; opendb(&err, &db, "test.db", 1, 0); sql_script(&err, &db, "PRAGMA cache_size = 2000;" "PRAGMA page_size = 1024;" "CREATE TABLE t1(a INTEGER PRIMARY KEY, b BLOB);" ); xSub = cgt_pager_1_populate; xSub(&err, &db); |
︙ | ︙ | |||
1370 1371 1372 1373 1374 1375 1376 | static char *dynamic_triggers_1(int iTid, void *pArg){ Error err = {0}; /* Error code and message */ Sqlite db = {0}; /* SQLite database connection */ int nDrop = 0; int nCreate = 0; | | | 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 | static char *dynamic_triggers_1(int iTid, void *pArg){ Error err = {0}; /* Error code and message */ Sqlite db = {0}; /* SQLite database connection */ int nDrop = 0; int nCreate = 0; opendb(&err, &db, "test.db", 0, 0); while( !timetostop(&err) ){ int i; for(i=1; i<9; i++){ char *zSql = sqlite3_mprintf( "CREATE TRIGGER itr%d BEFORE INSERT ON t%d BEGIN " "INSERT INTO t%d VALUES(new.x, new.y);" |
︙ | ︙ | |||
1423 1424 1425 1426 1427 1428 1429 | static char *dynamic_triggers_2(int iTid, void *pArg){ Error err = {0}; /* Error code and message */ Sqlite db = {0}; /* SQLite database connection */ i64 iVal = 0; int nInsert = 0; int nDelete = 0; | | | 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 | static char *dynamic_triggers_2(int iTid, void *pArg){ Error err = {0}; /* Error code and message */ Sqlite db = {0}; /* SQLite database connection */ i64 iVal = 0; int nInsert = 0; int nDelete = 0; opendb(&err, &db, "test.db", 0, 0); while( !timetostop(&err) ){ do { iVal = (iVal+1)%100; execsql(&err, &db, "INSERT INTO t1 VALUES(:iX, :iY+1)", &iVal, &iVal); nInsert++; } while( iVal ); |
︙ | ︙ | |||
1448 1449 1450 1451 1452 1453 1454 | } static void dynamic_triggers(int nMs){ Error err = {0}; Sqlite db = {0}; Threadset threads = {0}; | | | 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 | } static void dynamic_triggers(int nMs){ Error err = {0}; Sqlite db = {0}; Threadset threads = {0}; opendb(&err, &db, "test.db", 1, 0); sql_script(&err, &db, "PRAGMA page_size = 1024;" "PRAGMA journal_mode = WAL;" "CREATE TABLE t1(x, y);" "CREATE TABLE t2(x, y);" "CREATE TABLE t3(x, y);" "CREATE TABLE t4(x, y);" |
︙ | ︙ | |||
1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 | #include "tt3_checkpoint.c" #include "tt3_index.c" #include "tt3_lookaside1.c" #include "tt3_vacuum.c" #include "tt3_stress.c" #include "tt3_shared.c" int main(int argc, char **argv){ struct ThreadTest { void (*xTest)(int); /* Routine for running this test */ const char *zTest; /* Name of this test */ int nMs; /* How long to run this test, in milliseconds */ | > | 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 | #include "tt3_checkpoint.c" #include "tt3_index.c" #include "tt3_lookaside1.c" #include "tt3_vacuum.c" #include "tt3_stress.c" #include "tt3_reuseschema.c" #include "tt3_shared.c" int main(int argc, char **argv){ struct ThreadTest { void (*xTest)(int); /* Routine for running this test */ const char *zTest; /* Name of this test */ int nMs; /* How long to run this test, in milliseconds */ |
︙ | ︙ | |||
1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 | { checkpoint_starvation_2, "checkpoint_starvation_2", 10000 }, { create_drop_index_1, "create_drop_index_1", 10000 }, { lookaside1, "lookaside1", 10000 }, { vacuum1, "vacuum1", 10000 }, { stress1, "stress1", 10000 }, { stress2, "stress2", 60000 }, { shared1, "shared1", 10000 }, }; static char *substArgv[] = { 0, "*", 0 }; int i, iArg; int nTestfound = 0; sqlite3_config(SQLITE_CONFIG_MULTITHREAD); | > | 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 | { checkpoint_starvation_2, "checkpoint_starvation_2", 10000 }, { create_drop_index_1, "create_drop_index_1", 10000 }, { lookaside1, "lookaside1", 10000 }, { vacuum1, "vacuum1", 10000 }, { stress1, "stress1", 10000 }, { stress2, "stress2", 60000 }, { reuse_schema_1, "reuse_schema_1", 20000 }, { shared1, "shared1", 10000 }, }; static char *substArgv[] = { 0, "*", 0 }; int i, iArg; int nTestfound = 0; sqlite3_config(SQLITE_CONFIG_MULTITHREAD); |
︙ | ︙ |
Changes to test/tt3_checkpoint.c.
︙ | ︙ | |||
66 67 68 69 70 71 72 | return SQLITE_OK; } static char *checkpoint_starvation_reader(int iTid, void *pArg){ Error err = {0}; Sqlite db = {0}; | | | 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 | return SQLITE_OK; } static char *checkpoint_starvation_reader(int iTid, void *pArg){ Error err = {0}; Sqlite db = {0}; opendb(&err, &db, "test.db", 0, 0); while( !timetostop(&err) ){ i64 iCount1, iCount2; sql_script(&err, &db, "BEGIN"); iCount1 = execsql_i64(&err, &db, "SELECT count(x) FROM t1"); sqlite3_sleep(CHECKPOINT_STARVATION_READMS); iCount2 = execsql_i64(&err, &db, "SELECT count(x) FROM t1"); sql_script(&err, &db, "COMMIT"); |
︙ | ︙ | |||
92 93 94 95 96 97 98 | static void checkpoint_starvation_main(int nMs, CheckpointStarvationCtx *p){ Error err = {0}; Sqlite db = {0}; Threadset threads = {0}; int nInsert = 0; int i; | | | 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 | static void checkpoint_starvation_main(int nMs, CheckpointStarvationCtx *p){ Error err = {0}; Sqlite db = {0}; Threadset threads = {0}; int nInsert = 0; int i; opendb(&err, &db, "test.db", 1, 0); sql_script(&err, &db, "PRAGMA page_size = 1024;" "PRAGMA journal_mode = WAL;" "CREATE TABLE t1(x);" ); setstoptime(&err, nMs); |
︙ | ︙ |
Changes to test/tt3_index.c.
︙ | ︙ | |||
15 16 17 18 19 20 21 | static char *create_drop_index_thread(int iTid, void *pArg){ Error err = {0}; /* Error code and message */ Sqlite db = {0}; /* SQLite database connection */ while( !timetostop(&err) ){ | | | 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | static char *create_drop_index_thread(int iTid, void *pArg){ Error err = {0}; /* Error code and message */ Sqlite db = {0}; /* SQLite database connection */ while( !timetostop(&err) ){ opendb(&err, &db, "test.db", 0, 0); sql_script(&err, &db, "DROP INDEX IF EXISTS i1;" "DROP INDEX IF EXISTS i2;" "DROP INDEX IF EXISTS i3;" "DROP INDEX IF EXISTS i4;" |
︙ | ︙ | |||
47 48 49 50 51 52 53 | } static void create_drop_index_1(int nMs){ Error err = {0}; Sqlite db = {0}; Threadset threads = {0}; | | | 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 | } static void create_drop_index_1(int nMs){ Error err = {0}; Sqlite db = {0}; Threadset threads = {0}; opendb(&err, &db, "test.db", 1, 0); sql_script(&err, &db, "CREATE TABLE t11(a, b, c, d);" "WITH data(x) AS (SELECT 1 UNION ALL SELECT x+1 FROM data WHERE x<100) " "INSERT INTO t11 SELECT x,x,x,x FROM data;" ); closedb(&err, &db); |
︙ | ︙ |
Changes to test/tt3_lookaside1.c.
︙ | ︙ | |||
18 19 20 21 22 23 24 | ** that is suspected to exist at time of writing. */ static char *lookaside1_thread_reader(int iTid, void *pArg){ Error err = {0}; /* Error code and message */ Sqlite db = {0}; /* SQLite database connection */ | | | 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | ** that is suspected to exist at time of writing. */ static char *lookaside1_thread_reader(int iTid, void *pArg){ Error err = {0}; /* Error code and message */ Sqlite db = {0}; /* SQLite database connection */ opendb(&err, &db, "test.db", 0, 0); while( !timetostop(&err) ){ sqlite3_stmt *pStmt = 0; int rc; sqlite3_prepare_v2(db.db, "SELECT 1 FROM t1", -1, &pStmt, 0); while( sqlite3_step(pStmt)==SQLITE_ROW ){ |
︙ | ︙ | |||
43 44 45 46 47 48 49 | return sqlite3_mprintf("ok"); } static char *lookaside1_thread_writer(int iTid, void *pArg){ Error err = {0}; /* Error code and message */ Sqlite db = {0}; /* SQLite database connection */ | | | | 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 | return sqlite3_mprintf("ok"); } static char *lookaside1_thread_writer(int iTid, void *pArg){ Error err = {0}; /* Error code and message */ Sqlite db = {0}; /* SQLite database connection */ opendb(&err, &db, "test.db", 0, 0); do{ sql_script(&err, &db, "BEGIN;" "UPDATE t3 SET i=i+1 WHERE x=1;" "ROLLBACK;" ); }while( !timetostop(&err) ); closedb(&err, &db); print_and_free_err(&err); return sqlite3_mprintf("ok"); } static void lookaside1(int nMs){ Error err = {0}; Sqlite db = {0}; Threadset threads = {0}; opendb(&err, &db, "test.db", 1, 0); sql_script(&err, &db, "CREATE TABLE t1(x PRIMARY KEY) WITHOUT ROWID;" "WITH data(x,y) AS (" " SELECT 1, quote(randomblob(750)) UNION ALL " " SELECT x*2, y||y FROM data WHERE x<5) " "INSERT INTO t1 SELECT y FROM data;" |
︙ | ︙ |
Added test/tt3_reuseschema.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 | /* ** 2014 December 9 ** ** 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. ** ************************************************************************* ** ** reuse_schema_1 */ static char *reuse_schema_thread(int iTid, void *pArg){ Error err = {0}; /* Error code and message */ Sqlite db = {0}; /* SQLite database connection */ int iRep = 0; while( !timetostop(&err) ){ int f = SQLITE_OPEN_READWRITE|SQLITE_OPEN_SHARED_SCHEMA; opendb(&err, &db, "test.db", 0, f); execsql_i64(&err, &db, "SELECT count(*) FROM t1"); sql_script(&err, &db, "ATTACH 'test.db2' AS aux"); execsql_i64(&err, &db, "SELECT count(*) FROM t1"); closedb(&err, &db); iRep++; } print_and_free_err(&err); return sqlite3_mprintf("%d", iRep); } static void reuse_schema_1(int nMs){ Error err = {0}; Sqlite db = {0}; Threadset threads = {0}; opendb(&err, &db, "test.db", 1, 0); sql_script(&err, &db, "CREATE TABLE t1(a, b, c, d);" "WITH data(x) AS (SELECT 1 UNION ALL SELECT x+1 FROM data WHERE x<100) " "INSERT INTO t1 SELECT x,x,x,x FROM data;" ); closedb(&err, &db); opendb(&err, &db, "test.db2", 1, 0); sql_script(&err, &db, #ifdef SQLITE_ENABLE_FTS5 "CREATE VIRTUAL TABLE t2 USING fts5(a, b, c, d);" #else "CREATE TABLE t2(a, b, c, d);" #endif "WITH data(x) AS (SELECT 1 UNION ALL SELECT x+1 FROM data WHERE x<100) " "INSERT INTO t2 SELECT x*2,x*2,x*2,x*2 FROM data;" ); closedb(&err, &db); setstoptime(&err, nMs); launch_thread(&err, &threads, reuse_schema_thread, 0); launch_thread(&err, &threads, reuse_schema_thread, 0); launch_thread(&err, &threads, reuse_schema_thread, 0); launch_thread(&err, &threads, reuse_schema_thread, 0); launch_thread(&err, &threads, reuse_schema_thread, 0); join_all_threads(&err, &threads); sqlite3_enable_shared_cache(0); print_and_free_err(&err); } |
Changes to test/tt3_stress.c.
︙ | ︙ | |||
17 18 19 20 21 22 23 | /* ** Thread 1. CREATE and DROP a table. */ static char *stress_thread_1(int iTid, void *pArg){ Error err = {0}; /* Error code and message */ Sqlite db = {0}; /* SQLite database connection */ | | | | | 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 | /* ** Thread 1. CREATE and DROP a table. */ static char *stress_thread_1(int iTid, void *pArg){ Error err = {0}; /* Error code and message */ Sqlite db = {0}; /* SQLite database connection */ opendb(&err, &db, "test.db", 0, 0); while( !timetostop(&err) ){ sql_script(&err, &db, "CREATE TABLE IF NOT EXISTS t1(a PRIMARY KEY, b)"); clear_error(&err, SQLITE_LOCKED); sql_script(&err, &db, "DROP TABLE IF EXISTS t1"); clear_error(&err, SQLITE_LOCKED); } closedb(&err, &db); print_and_free_err(&err); return sqlite3_mprintf("ok"); } /* ** Thread 2. Open and close database connections. */ static char *stress_thread_2(int iTid, void *pArg){ Error err = {0}; /* Error code and message */ Sqlite db = {0}; /* SQLite database connection */ while( !timetostop(&err) ){ opendb(&err, &db, "test.db", 0, 0); sql_script(&err, &db, "SELECT * FROM sqlite_schema;"); clear_error(&err, SQLITE_LOCKED); closedb(&err, &db); } print_and_free_err(&err); return sqlite3_mprintf("ok"); } /* ** Thread 3. Attempt many small SELECT statements. */ static char *stress_thread_3(int iTid, void *pArg){ Error err = {0}; /* Error code and message */ Sqlite db = {0}; /* SQLite database connection */ int i1 = 0; int i2 = 0; opendb(&err, &db, "test.db", 0, 0); while( !timetostop(&err) ){ sql_script(&err, &db, "SELECT * FROM t1 ORDER BY a;"); i1++; if( err.rc ) i2++; clear_error(&err, SQLITE_LOCKED); clear_error(&err, SQLITE_ERROR); } |
︙ | ︙ | |||
78 79 80 81 82 83 84 | static char *stress_thread_4(int iTid, void *pArg){ Error err = {0}; /* Error code and message */ Sqlite db = {0}; /* SQLite database connection */ int i1 = 0; int i2 = 0; int iArg = PTR2INT(pArg); | | | | 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 | static char *stress_thread_4(int iTid, void *pArg){ Error err = {0}; /* Error code and message */ Sqlite db = {0}; /* SQLite database connection */ int i1 = 0; int i2 = 0; int iArg = PTR2INT(pArg); opendb(&err, &db, "test.db", 0, 0); while( !timetostop(&err) ){ if( iArg ){ closedb(&err, &db); opendb(&err, &db, "test.db", 0, 0); } sql_script(&err, &db, "WITH loop(i) AS (SELECT 1 UNION ALL SELECT i+1 FROM loop LIMIT 200) " "INSERT INTO t1 VALUES(randomblob(60), randomblob(60));" ); i1++; if( err.rc ) i2++; |
︙ | ︙ | |||
109 110 111 112 113 114 115 | Error err = {0}; /* Error code and message */ Sqlite db = {0}; /* SQLite database connection */ int iArg = PTR2INT(pArg); int i1 = 0; int i2 = 0; | | | | 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 | Error err = {0}; /* Error code and message */ Sqlite db = {0}; /* SQLite database connection */ int iArg = PTR2INT(pArg); int i1 = 0; int i2 = 0; opendb(&err, &db, "test.db", 0, 0); while( !timetostop(&err) ){ i64 i = (i1 % 4); if( iArg ){ closedb(&err, &db); opendb(&err, &db, "test.db", 0, 0); } execsql(&err, &db, "DELETE FROM t1 WHERE (rowid % 4)==:i", &i); i1++; if( err.rc ) i2++; clear_error(&err, SQLITE_LOCKED); } closedb(&err, &db); |
︙ | ︙ | |||
261 262 263 264 265 266 267 | } static char *stress2_workload19(int iTid, void *pArg){ Error err = {0}; /* Error code and message */ Sqlite db = {0}; /* SQLite database connection */ const char *zDb = (const char*)pArg; while( !timetostop(&err) ){ | | | 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 | } static char *stress2_workload19(int iTid, void *pArg){ Error err = {0}; /* Error code and message */ Sqlite db = {0}; /* SQLite database connection */ const char *zDb = (const char*)pArg; while( !timetostop(&err) ){ opendb(&err, &db, zDb, 0, 0); sql_script(&err, &db, "SELECT * FROM sqlite_schema;"); clear_error(&err, SQLITE_LOCKED); closedb(&err, &db); } print_and_free_err(&err); return sqlite3_mprintf("ok"); } |
︙ | ︙ | |||
286 287 288 289 290 291 292 | Error err = {0}; /* Error code and message */ Sqlite db = {0}; /* SQLite database connection */ int i1 = 0; int i2 = 0; while( !timetostop(&err) ){ int cnt; | | | 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 | Error err = {0}; /* Error code and message */ Sqlite db = {0}; /* SQLite database connection */ int i1 = 0; int i2 = 0; while( !timetostop(&err) ){ int cnt; opendb(&err, &db, pCtx->zDb, 0, 0); for(cnt=0; err.rc==SQLITE_OK && cnt<STRESS2_TABCNT; cnt++){ pCtx->xProc(&err, &db, i1); i2 += (err.rc==SQLITE_OK); clear_error(&err, SQLITE_LOCKED); i1++; } closedb(&err, &db); |
︙ | ︙ | |||
338 339 340 341 342 343 344 | int i; Error err = {0}; Sqlite db = {0}; Threadset threads = {0}; /* To make sure the db file is empty before commencing */ | | | 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 | int i; Error err = {0}; Sqlite db = {0}; Threadset threads = {0}; /* To make sure the db file is empty before commencing */ opendb(&err, &db, zDb, 1, 0); sql_script(&err, &db, "CREATE TABLE IF NOT EXISTS t0(x PRIMARY KEY, y, z);" "CREATE INDEX IF NOT EXISTS i0 ON t0(y);" ); closedb(&err, &db); setstoptime(&err, nMs); |
︙ | ︙ |
Changes to test/tt3_vacuum.c.
︙ | ︙ | |||
21 22 23 24 25 26 27 | static char *vacuum1_thread_writer(int iTid, void *pArg){ Error err = {0}; /* Error code and message */ Sqlite db = {0}; /* SQLite database connection */ i64 i = 0; | | | 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | static char *vacuum1_thread_writer(int iTid, void *pArg){ Error err = {0}; /* Error code and message */ Sqlite db = {0}; /* SQLite database connection */ i64 i = 0; opendb(&err, &db, "test.db", 0, 0); while( !timetostop(&err) ){ i++; /* Insert lots of rows. Then delete some. */ execsql(&err, &db, "WITH loop(i) AS (SELECT 1 UNION ALL SELECT i+1 FROM loop WHERE i<100) " "INSERT INTO t1 SELECT randomblob(50), randomblob(2500) FROM loop" |
︙ | ︙ | |||
48 49 50 51 52 53 54 | print_and_free_err(&err); return sqlite3_mprintf("ok"); } static char *vacuum1_thread_vacuumer(int iTid, void *pArg){ Error err = {0}; /* Error code and message */ Sqlite db = {0}; /* SQLite database connection */ | | | | 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 | print_and_free_err(&err); return sqlite3_mprintf("ok"); } static char *vacuum1_thread_vacuumer(int iTid, void *pArg){ Error err = {0}; /* Error code and message */ Sqlite db = {0}; /* SQLite database connection */ opendb(&err, &db, "test.db", 0, 0); do{ sql_script(&err, &db, "VACUUM"); clear_error(&err, SQLITE_LOCKED); }while( !timetostop(&err) ); closedb(&err, &db); print_and_free_err(&err); return sqlite3_mprintf("ok"); } static void vacuum1(int nMs){ Error err = {0}; Sqlite db = {0}; Threadset threads = {0}; opendb(&err, &db, "test.db", 1, 0); sql_script(&err, &db, "CREATE TABLE t1(x PRIMARY KEY, y BLOB);" "CREATE INDEX i1 ON t1(y);" ); closedb(&err, &db); setstoptime(&err, nMs); |
︙ | ︙ |
Changes to tool/mkpragmatab.tcl.
︙ | ︙ | |||
16 17 18 19 20 21 22 | # tclsh tool/mkpragmatab.tcl ;# <--- Results to src/pragma.h # # tclsh tool/mkpragmatab.tcl /dev/tty ;# <-- results to terminal # # Flag meanings: set flagMeaning(NeedSchema) {Force schema load before running} | | | 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | # tclsh tool/mkpragmatab.tcl ;# <--- Results to src/pragma.h # # tclsh tool/mkpragmatab.tcl /dev/tty ;# <-- results to terminal # # Flag meanings: set flagMeaning(NeedSchema) {Force schema load before running} set flagMeaning(OneSchema) {Only a single schema required} set flagMeaning(Result0) {Acts as query when no argument} set flagMeaning(Result1) {Acts as query when has one argument} set flagMeaning(SchemaReq) {Schema required - "main" is default} set flagMeaning(SchemaOpt) {Schema restricts name search if present} set flagMeaning(NoColumns) {OP_ResultRow called with zero columns} set flagMeaning(NoColumns1) {zero columns if RHS argument is present} |
︙ | ︙ | |||
154 155 156 157 158 159 160 | IF: !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER) NAME: cell_size_check TYPE: FLAG ARG: SQLITE_CellSizeCk NAME: default_cache_size | | | | | | | | | | 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 | IF: !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER) NAME: cell_size_check TYPE: FLAG ARG: SQLITE_CellSizeCk NAME: default_cache_size FLAG: NeedSchema Result0 SchemaReq NoColumns1 OneSchema COLS: cache_size IF: !defined(SQLITE_OMIT_PAGER_PRAGMAS) && !defined(SQLITE_OMIT_DEPRECATED) NAME: page_size FLAG: Result0 SchemaReq NoColumns1 IF: !defined(SQLITE_OMIT_PAGER_PRAGMAS) NAME: secure_delete FLAG: Result0 IF: !defined(SQLITE_OMIT_PAGER_PRAGMAS) NAME: page_count FLAG: NeedSchema Result0 SchemaReq OneSchema IF: !defined(SQLITE_OMIT_PAGER_PRAGMAS) NAME: max_page_count TYPE: PAGE_COUNT FLAG: NeedSchema Result0 SchemaReq OneSchema IF: !defined(SQLITE_OMIT_PAGER_PRAGMAS) NAME: locking_mode FLAG: Result0 SchemaReq IF: !defined(SQLITE_OMIT_PAGER_PRAGMAS) NAME: journal_mode FLAG: NeedSchema Result0 SchemaReq OneSchema IF: !defined(SQLITE_OMIT_PAGER_PRAGMAS) NAME: journal_size_limit FLAG: Result0 SchemaReq IF: !defined(SQLITE_OMIT_PAGER_PRAGMAS) NAME: cache_size FLAG: NeedSchema Result0 SchemaReq NoColumns1 OneSchema IF: !defined(SQLITE_OMIT_PAGER_PRAGMAS) NAME: mmap_size IF: !defined(SQLITE_OMIT_PAGER_PRAGMAS) NAME: auto_vacuum FLAG: NeedSchema Result0 SchemaReq NoColumns1 OneSchema IF: !defined(SQLITE_OMIT_AUTOVACUUM) NAME: incremental_vacuum FLAG: NeedSchema NoColumns OneSchema IF: !defined(SQLITE_OMIT_AUTOVACUUM) NAME: temp_store FLAG: Result0 NoColumns1 IF: !defined(SQLITE_OMIT_PAGER_PRAGMAS) NAME: temp_store_directory FLAG: NoColumns1 IF: !defined(SQLITE_OMIT_PAGER_PRAGMAS) NAME: data_store_directory FLAG: NoColumns1 IF: !defined(SQLITE_OMIT_PAGER_PRAGMAS) && SQLITE_OS_WIN NAME: lock_proxy_file FLAG: NoColumns1 IF: !defined(SQLITE_OMIT_PAGER_PRAGMAS) && SQLITE_ENABLE_LOCKING_STYLE NAME: synchronous FLAG: NeedSchema Result0 SchemaReq NoColumns1 OneSchema IF: !defined(SQLITE_OMIT_PAGER_PRAGMAS) NAME: table_info FLAG: NeedSchema Result1 SchemaOpt ARG: 0 COLS: cid name type notnull dflt_value pk IF: !defined(SQLITE_OMIT_SCHEMA_PRAGMAS) |
︙ | ︙ | |||
242 243 244 245 246 247 248 | NAME: table_list TYPE: TABLE_LIST FLAG: NeedSchema Result1 COLS: schema name type ncol wr strict IF: !defined(SQLITE_OMIT_SCHEMA_PRAGMAS) NAME: stats | | | 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 | NAME: table_list TYPE: TABLE_LIST FLAG: NeedSchema Result1 COLS: schema name type ncol wr strict IF: !defined(SQLITE_OMIT_SCHEMA_PRAGMAS) NAME: stats FLAG: NeedSchema Result0 SchemaReq OneSchema COLS: tbl idx wdth hght flgs IF: !defined(SQLITE_OMIT_SCHEMA_PRAGMAS) && defined(SQLITE_DEBUG) NAME: index_info TYPE: INDEX_INFO ARG: 0 FLAG: NeedSchema Result1 SchemaOpt |
︙ | ︙ | |||
294 295 296 297 298 299 300 | NAME: collation_list FLAG: Result0 COLS: seq name IF: !defined(SQLITE_OMIT_SCHEMA_PRAGMAS) NAME: foreign_key_list | | | 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 | NAME: collation_list FLAG: Result0 COLS: seq name IF: !defined(SQLITE_OMIT_SCHEMA_PRAGMAS) NAME: foreign_key_list FLAG: NeedSchema Result1 SchemaOpt OneSchema COLS: id seq table from to on_update on_delete match IF: !defined(SQLITE_OMIT_FOREIGN_KEY) NAME: foreign_key_check FLAG: NeedSchema Result0 Result1 SchemaOpt COLS: table rowid parent fkid IF: !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER) |
︙ | ︙ | |||
340 341 342 343 344 345 346 | TYPE: HEADER_VALUE ARG: BTREE_USER_VERSION FLAG: NoColumns1 Result0 IF: !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS) NAME: data_version TYPE: HEADER_VALUE | | | | | | | 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 | TYPE: HEADER_VALUE ARG: BTREE_USER_VERSION FLAG: NoColumns1 Result0 IF: !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS) NAME: data_version TYPE: HEADER_VALUE ARG: BTREE_DATA_VERSION|PRAGMA_HEADER_VALUE_READONLY FLAG: Result0 IF: !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS) NAME: freelist_count TYPE: HEADER_VALUE ARG: BTREE_FREE_PAGE_COUNT|PRAGMA_HEADER_VALUE_READONLY FLAG: Result0 IF: !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS) NAME: application_id TYPE: HEADER_VALUE ARG: BTREE_APPLICATION_ID FLAG: NoColumns1 Result0 IF: !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS) NAME: compile_options FLAG: Result0 IF: !defined(SQLITE_OMIT_COMPILEOPTION_DIAGS) NAME: wal_checkpoint FLAG: NeedSchema OneSchema COLS: busy log checkpointed IF: !defined(SQLITE_OMIT_WAL) NAME: wal_autocheckpoint IF: !defined(SQLITE_OMIT_WAL) NAME: shrink_memory |
︙ | ︙ | |||
523 524 525 526 527 528 529 530 531 532 533 534 535 536 | puts $fd "\n/* Property flags associated with various pragma. */" set fv 1 foreach f [lsort [array names allflags]] { puts $fd [format {#define PragFlg_%-10s 0x%02x /* %s */} \ $f $fv $flagMeaning($f)] set fv [expr {$fv*2}] } # Sort the column lists so that longer column lists occur first # proc colscmp {a b} { return [expr {[llength $b] - [llength $a]}] } set cols_list [lsort -command colscmp $cols_list] | > > > > > > | 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 | puts $fd "\n/* Property flags associated with various pragma. */" set fv 1 foreach f [lsort [array names allflags]] { puts $fd [format {#define PragFlg_%-10s 0x%02x /* %s */} \ $f $fv $flagMeaning($f)] set fv [expr {$fv*2}] } puts $fd "\n/* For PragTyp_HEADER_VALUE pragmas the Pragma.iArg value is set" puts $fd "** to the index of the header field to access (always 10 or less)." puts $fd "** Ored with HEADER_VALUE_READONLY if the field is read only. */" puts $fd "#define PRAGMA_HEADER_VALUE_READONLY 0x0100" puts $fd "#define PRAGMA_HEADER_VALUE_MASK 0x00FF\n" # Sort the column lists so that longer column lists occur first # proc colscmp {a b} { return [expr {[llength $b] - [llength $a]}] } set cols_list [lsort -command colscmp $cols_list] |
︙ | ︙ |