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 6eb2939a60 to f98aa940b4
2025-05-07
| ||
17:13 | Fix a harmless warning about and oversize shift operation on malformed JSONB inputs. OSSFuzz 415850463. (check-in: cf8b55b3b6 user: drh tags: trunk) | |
2025-05-06
| ||
23:01 | Merge the latest trunk enhancements into the reuse-schema branch. (Leaf check-in: f98aa940b4 user: drh tags: reuse-schema) | |
21:38 | Merge the latest trunk changes into the wal2 branch. (Leaf check-in: b17f5beab8 user: drh tags: wal2) | |
21:26 | Merge all the latest trunk enhancements into the begin-concurrent branch. (Leaf check-in: 55a51ba58f user: drh tags: begin-concurrent) | |
17:56 | Add test cases for the NOT NULL/IS NULL optimization in CHECK constraints fix. (check-in: 6eb2939a60 user: dan tags: trunk) | |
17:53 | Fix a bug in the NOT NULL/IS NULL optimization of check-in [cb94350185f555c3] that can cause invalid data to be used for a column if that column has a CHECK constraint that includes the NOT NULL or IS NULL operator. Problem discovered by the Chromium fuzzer. Never seen in the wild, as far as anybody knows. (check-in: 2adaee9aa9 user: drh tags: trunk) | |
2025-04-21
| ||
13:08 | Merge all the latest trunk enhancements into the reuse-schema branch. (check-in: b3a526a887 user: drh tags: reuse-schema) | |
Changes to Makefile.msc.
︙ | ︙ | |||
1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 | $(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 \ | > | 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 | $(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 \ |
︙ | ︙ |
Changes to doc/lemon.html.
︙ | ︙ | |||
720 721 722 723 724 725 726 727 728 729 730 731 732 733 | <p><tt>%code</tt> is typically used to include some action routines or perhaps a tokenizer or even the "main()" function as part of the output file.</p> <p>There can be multiple <tt>%code</tt> directives. The arguments of all <tt>%code</tt> directives are concatenated.</p> <a id='default_destructor'></a> <h4>4.4.2 The <tt>%default_destructor</tt> directive</h4> <p>The <tt>%default_destructor</tt> directive specifies a destructor to use for non-terminals that do not have their own destructor specified by a separate <tt>%destructor</tt> directive. See the documentation | > > > > | 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 | <p><tt>%code</tt> is typically used to include some action routines or perhaps a tokenizer or even the "main()" function as part of the output file.</p> <p>There can be multiple <tt>%code</tt> directives. The arguments of all <tt>%code</tt> directives are concatenated.</p> <p>If the argument to <tt>%code</tt> is a filename within <tt><...></tt> then the content of the named file is inserted instead of the text of the argument itself. <a id='default_destructor'></a> <h4>4.4.2 The <tt>%default_destructor</tt> directive</h4> <p>The <tt>%default_destructor</tt> directive specifies a destructor to use for non-terminals that do not have their own destructor specified by a separate <tt>%destructor</tt> directive. See the documentation |
︙ | ︙ | |||
915 916 917 918 919 920 921 922 923 924 925 926 927 928 | <pre> %include {#include <unistd.h>} </pre> <p>This might be needed, for example, if some of the C actions in the grammar call functions that are prototyped in unistd.h.</p> <p>Use the <tt><a href="#pcode">%code</a></tt> directive to add code to the end of the generated parser.</p> <a id='pleft'></a> <h4>4.4.10 The <tt>%left</tt> directive</h4> | > > > > > | 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 | <pre> %include {#include <unistd.h>} </pre> <p>This might be needed, for example, if some of the C actions in the grammar call functions that are prototyped in unistd.h.</p> <p>If the argument to <tt>%include</tt> is a filename within <tt><...></tt> then the content of that file is inserted instead of the text of the argument itself. <p>Use the <tt><a href="#pcode">%code</a></tt> directive to add code to the end of the generated parser.</p> <a id='pleft'></a> <h4>4.4.10 The <tt>%left</tt> directive</h4> |
︙ | ︙ |
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.
|
| < < < < < < < < < < |
Added 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 |
Deleted ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-core.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
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) }; |
Changes to ext/wasm/demo-worker1-promiser.c-pp.js.
︙ | ︙ | |||
111 112 113 114 115 116 117 | const mustNotReach = ()=>toss("This is not supposed to be reached."); await wtest('exec',{ sql: ["create table t(a,b)", "insert into t(a,b) values(1,2),(3,4),(5,6)" ].join(';'), resultRows: [], columnNames: [], | < | < < | 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 | const mustNotReach = ()=>toss("This is not supposed to be reached."); await wtest('exec',{ sql: ["create table t(a,b)", "insert into t(a,b) values(1,2),(3,4),(5,6)" ].join(';'), resultRows: [], columnNames: [], countChanges: sqConfig.bigIntEnabled ? 64 : true }, function(ev){ ev = ev.result; T.assert(0===ev.resultRows.length) .assert(0===ev.columnNames.length) .assert(sqConfig.bigIntEnabled ? (3n===ev.changeCount) : (3===ev.changeCount)); }); await wtest('exec',{ sql: 'select a a, b b from t order by a', resultRows: [], columnNames: [], }, function(ev){ ev = ev.result; |
︙ | ︙ |
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.
︙ | ︙ | |||
761 762 763 764 765 766 767 768 769 770 771 772 773 774 | $(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 \ | > | 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 | $(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 \ |
︙ | ︙ | |||
828 829 830 831 832 833 834 835 836 837 838 839 840 841 | # TESTSRC2 = \ $(TOP)/src/attach.c \ $(TOP)/src/backup.c \ $(TOP)/src/bitvec.c \ $(TOP)/src/btree.c \ $(TOP)/src/build.c \ 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 \ | > > | 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 | # 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 \ 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 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 ); assert( pParse->isCreate || pParse->nErr ); aRoot[i] = (u32)pParse->u1.cr.regRoot; aCreateTbl[i] = OPFLAG_P2ISREG; } | > | 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 ); assert( pParse->isCreate || pParse->nErr ); aRoot[i] = (u32)pParse->u1.cr.regRoot; aCreateTbl[i] = OPFLAG_P2ISREG; } |
︙ | ︙ |
Changes to src/attach.c.
︙ | ︙ | |||
220 221 222 223 224 225 226 | /* 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 ){ | < | > < | | > | 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 | /* 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); #ifdef SQLITE_ENABLE_SETLK_TIMEOUT if( db->setlkFlags & SQLITE_SETLK_BLOCK_ON_CONNECT ){ int val = 1; sqlite3_file *fd = sqlite3PagerFile(sqlite3BtreePager(pNew->pBt)); sqlite3OsFileControlHint(fd, SQLITE_FCNTL_BLOCK_ON_CONNECT, &val); } #endif if( !IsSharedSchema(db) && !REOPEN_AS_MEMDB(db) ){ sqlite3BtreeEnterAll(db); rc = sqlite3Init(db, &zErrDyn); sqlite3BtreeLeaveAll(db); assert( zErrDyn==0 || rc!=SQLITE_OK ); } } if( rc ){ if( ALWAYS(!REOPEN_AS_MEMDB(db)) ){ int iDb = db->nDb - 1; assert( iDb>=2 ); if( db->aDb[iDb].pBt ){ sqlite3BtreeClose(db->aDb[iDb].pBt); |
︙ | ︙ | |||
325 326 327 328 329 330 331 332 333 334 335 336 337 338 | 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: | > | 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 | 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: |
︙ | ︙ | |||
354 355 356 357 358 359 360 | ){ int rc; NameContext sName; Vdbe *v; sqlite3* db = pParse->db; int regArgs; | > | > | 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 | ){ 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.
︙ | ︙ | |||
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 | sqlite3RunParser(pParse, zSql); db->mDbFlags = savedDbFlags; sqlite3DbFree(db, zSql); memcpy(PARSE_TAIL(pParse), saveBuf, PARSE_TAIL_SZ); pParse->nested--; } /* ** 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 ** names is done.) The search order is TEMP first, then MAIN, then any ** auxiliary databases added using the ATTACH command. ** ** See also sqlite3LocateTable(). */ Table *sqlite3FindTable(sqlite3 *db, const char *zName, const char *zDatabase){ Table *p = 0; int i; /* All mutexes are required for schema access. Make sure we hold them. */ assert( zDatabase!=0 || sqlite3BtreeHoldsAllMutexes(db) ); | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | < < < < | | > > | > > | | | | < | < < < | | < < > > > > | < | > | < < < < < < < < < < < | | < > < | < < | | | < < | | 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 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 | sqlite3RunParser(pParse, zSql); db->mDbFlags = savedDbFlags; sqlite3DbFree(db, zSql); memcpy(PARSE_TAIL(pParse), saveBuf, PARSE_TAIL_SZ); pParse->nested--; } #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 ** names is done.) The search order is TEMP first, then MAIN, then any ** auxiliary databases added using the ATTACH command. ** ** See also sqlite3LocateTable(). */ Table *sqlite3FindTable(sqlite3 *db, const char *zName, const char *zDatabase){ Table *p = 0; int i; /* All mutexes are required for schema access. Make sure we hold them. */ assert( zDatabase!=0 || sqlite3BtreeHoldsAllMutexes(db) ); 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. |
︙ | ︙ | |||
413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 | ){ 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); } | > > > > > > > > | | > > > > | > | < < | 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 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 | ){ 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. |
︙ | ︙ | |||
618 619 620 621 622 623 624 | if( iDb>=0 ){ assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); DbSetProperty(db, iDb, DB_ResetWanted); DbSetProperty(db, 1, DB_ResetWanted); db->mDbFlags &= ~DBFLAG_SchemaKnownOk; } | < | | | > | 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 | 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); } } |
︙ | ︙ | |||
1261 1262 1263 1264 1265 1266 1267 | ** 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; | | | 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 | ** 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); |
︙ | ︙ | |||
2911 2912 2913 2914 2915 2916 2917 | pDb->zDbSName ); } } #endif /* Reparse everything to update our internal data structures */ | | | 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 | 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\"", |
︙ | ︙ | |||
3483 3484 3485 3486 3487 3488 3489 | if( db->mallocFailed ){ goto exit_drop_table; } assert( pParse->nErr==0 ); assert( pName->nSrc==1 ); assert( pName->a[0].fg.fixedSchema==0 ); assert( pName->a[0].fg.isSubquery==0 ); | | > | 3509 3510 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 | if( db->mallocFailed ){ goto exit_drop_table; } assert( pParse->nErr==0 ); assert( pName->nSrc==1 ); assert( pName->a[0].fg.fixedSchema==0 ); assert( pName->a[0].fg.isSubquery==0 ); 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].u4.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; } /* |
︙ | ︙ | |||
4452 4453 4454 4455 4456 4457 4458 | /* 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); | | | 4479 4480 4481 4482 4483 4484 4485 4486 4487 4488 4489 4490 4491 4492 4493 | /* 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 ){ |
︙ | ︙ | |||
519 520 521 522 523 524 525 | if( pSchema->schemaFlags & DB_SchemaLoaded ){ pSchema->iGeneration++; } pSchema->schemaFlags &= ~(DB_SchemaLoaded|DB_ResetWanted); } /* | > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > | | | | | 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 900 901 902 903 904 905 | 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.
︙ | ︙ | |||
1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 | 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); } } | > > > > > > > > > > > | 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 | 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); } } |
︙ | ︙ | |||
1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 | /* 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); | > | 1397 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 ){ (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); |
︙ | ︙ | |||
3958 3959 3960 3961 3962 3963 3964 | 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 */ ){ | | | > > | < < > > > > > > > | > > > > > > > > | 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 4000 4001 4002 4003 4004 4005 4006 4007 4008 4009 4010 4011 4012 4013 4014 4015 4016 4017 4018 4019 4020 4021 4022 4023 4024 4025 4026 | 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 ){ |
︙ | ︙ | |||
4055 4056 4057 4058 4059 4060 4061 4062 4063 4064 4065 4066 4067 4068 | 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. */ | > | 4082 4083 4084 4085 4086 4087 4088 4089 4090 4091 4092 4093 4094 4095 4096 | 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/os_win.c.
︙ | ︙ | |||
5473 5474 5475 5476 5477 5478 5479 | /* If argument zPath is a NULL pointer, this function is required to open ** a temporary file. Use this buffer to store the file name in. */ char *zTmpname = 0; /* For temporary filename, if necessary. */ int rc = SQLITE_OK; /* Function Return Code */ #if !defined(NDEBUG) || SQLITE_OS_WINCE | | | 5473 5474 5475 5476 5477 5478 5479 5480 5481 5482 5483 5484 5485 5486 5487 | /* If argument zPath is a NULL pointer, this function is required to open ** a temporary file. Use this buffer to store the file name in. */ char *zTmpname = 0; /* For temporary filename, if necessary. */ int rc = SQLITE_OK; /* Function Return Code */ #if !defined(NDEBUG) || SQLITE_OS_WINCE int eType = flags&0x0FFF00; /* Type of file to open */ #endif int isExclusive = (flags & SQLITE_OPEN_EXCLUSIVE); int isDelete = (flags & SQLITE_OPEN_DELETEONCLOSE); int isCreate = (flags & SQLITE_OPEN_CREATE); int isReadonly = (flags & SQLITE_OPEN_READONLY); int isReadWrite = (flags & SQLITE_OPEN_READWRITE); |
︙ | ︙ |
Changes to src/pager.c.
︙ | ︙ | |||
5075 5076 5077 5078 5079 5080 5081 5082 5083 5084 5085 5086 5087 5088 | } p = zName - 4 - sizeof(Pager*); assert( EIGHT_BYTE_ALIGNMENT(p) ); pPager = *(Pager**)p; return pPager->fd; } /* ** This function is called after transitioning from PAGER_UNLOCK to ** PAGER_SHARED state. It tests if there is a hot journal present in ** the file-system for the given pager. A hot journal is one that ** needs to be played back. According to this function, a hot-journal ** file exists if the following criteria are met: | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 5075 5076 5077 5078 5079 5080 5081 5082 5083 5084 5085 5086 5087 5088 5089 5090 5091 5092 5093 5094 5095 5096 5097 5098 5099 5100 5101 5102 5103 5104 5105 5106 5107 5108 5109 5110 5111 5112 5113 5114 5115 5116 5117 5118 5119 5120 5121 5122 5123 5124 5125 5126 5127 5128 5129 5130 5131 5132 5133 5134 5135 5136 5137 5138 5139 5140 5141 5142 5143 5144 5145 5146 5147 5148 5149 5150 5151 5152 5153 5154 5155 5156 5157 5158 5159 5160 5161 5162 5163 5164 5165 5166 5167 5168 5169 5170 5171 5172 5173 5174 5175 5176 5177 5178 5179 5180 5181 5182 5183 5184 5185 5186 5187 5188 5189 5190 5191 5192 5193 5194 5195 5196 5197 | } p = zName - 4 - sizeof(Pager*); assert( EIGHT_BYTE_ALIGNMENT(p) ); pPager = *(Pager**)p; return pPager->fd; } #ifdef SQLITE_ENABLE_READONLY_WALJOURNAL /* ** This is used by a read-only database connection in cases where there ** is a hot journal which cannot be rolled back, but the hot journal was ** created by an aborted "PRAGMA journal_mode = wal" statement. In this ** case we can proceed, but must set bytes 18 and 19 of page 1 of the ** db file to indicate that this is not a wal mode database. */ static int getPageOneNoWal( Pager *pPager, /* The pager open on the database file */ Pgno pgno, /* Page number to fetch */ DbPage **ppPage, /* Write a pointer to the page here */ int flags /* PAGER_GET_XXX flags */ ){ int rc = SQLITE_OK; assert( pgno==1 ); assert( pPager->readOnly ); assert( !isOpen(pPager->jfd) ); rc = getPageNormal(pPager, pgno, ppPage, flags); if( rc==SQLITE_OK ){ int f = SQLITE_OPEN_READONLY|SQLITE_OPEN_MAIN_JOURNAL; u8 *aPg = (u8*)(*ppPage)->pData; u8 aHdr[28]; rc = sqlite3OsOpen(pPager->pVfs, pPager->zJournal, pPager->jfd, f, &f); if( rc==SQLITE_OK ){ rc = sqlite3OsRead(pPager->jfd, (void*)aHdr, sizeof(aHdr), 0); } if( rc==SQLITE_OK ){ u32 off = sqlite3Get4byte(&aHdr[20]); rc = sqlite3OsRead(pPager->jfd, (void*)aPg, pPager->pageSize, off+4); } sqlite3OsClose(pPager->jfd); } setGetterMethod(pPager); return rc; } #endif /* SQLITE_ENABLE_READONLY_WALJOURNAL */ /* ** This function is called after a potentially hot journal has been opened ** to inspect its contents and determine whether or not it really is a ** hot journal. The journal is not a hot journal in two cases: ** ** * The first byte of the journal is 0x00, or, ** ** * The connection is opened read-only, the journal consist of page 1 ** of the db only, and the contents of page 1 differs from the contents ** of the db only in bytes 18 and 19 (the wal mode setting). ** ** If the journal is not hot, then output variable (*pbHot) is set to 0 ** before this function returns. Otherwise, if the journal is hot, (*pbHot) ** is set to 1. */ static int checkHotJournal(Pager *pPager, int *pbHot){ char aHdr[28]; int rc = SQLITE_OK; *pbHot = 1; rc = sqlite3OsRead(pPager->jfd, (void *)aHdr, sizeof(aHdr), 0); if( rc==SQLITE_OK ){ if( aHdr[0]==0 ){ *pbHot = 0; } #ifdef SQLITE_ENABLE_READONLY_WALJOURNAL else if( pPager->readOnly ){ u32 nPg = sqlite3Get4byte(&aHdr[8]); u32 off = sqlite3Get4byte(&aHdr[20]); u32 pgsz = sqlite3Get4byte(&aHdr[24]); if( nPg==0xFFFFFFFF ){ i64 sz = 0; rc = sqlite3OsFileSize(pPager->jfd, &sz); nPg = ((sz-off) / pgsz); } if( nPg==1 ){ u8 *a1 = 0; a1 = sqlite3_malloc(pgsz*2); if( a1==0 ){ rc = SQLITE_NOMEM_BKPT; }else{ u8 *a2 = &a1[pgsz]; rc = sqlite3OsRead(pPager->jfd, a1, pgsz, off+4); if( rc==SQLITE_OK ){ rc = sqlite3OsRead(pPager->fd, a2, pgsz, 0); memcpy(&a2[18], &a1[18], 2); memcpy(&a2[24], &a1[24], 4); memcpy(&a2[92], &a1[92], 8); #ifdef SQLITE_ENABLE_ZIPVFS memcpy(&a2[176], &a1[176], 4); #endif } if( rc==SQLITE_OK && memcmp(a1, a2, pgsz)==0 ){ *pbHot = 0; pPager->xGet = getPageOneNoWal; } sqlite3_free(a1); } } } #endif /* SQLITE_ENABLE_READONLY_WALJOURNAL */ } if( rc==SQLITE_IOERR_SHORT_READ ){ rc = SQLITE_OK; } return rc; } /* ** This function is called after transitioning from PAGER_UNLOCK to ** PAGER_SHARED state. It tests if there is a hot journal present in ** the file-system for the given pager. A hot journal is one that ** needs to be played back. According to this function, a hot-journal ** file exists if the following criteria are met: |
︙ | ︙ | |||
5170 5171 5172 5173 5174 5175 5176 | ** it can be ignored. */ if( !jrnlOpen ){ int f = SQLITE_OPEN_READONLY|SQLITE_OPEN_MAIN_JOURNAL; rc = sqlite3OsOpen(pVfs, pPager->zJournal, pPager->jfd, f, &f); } if( rc==SQLITE_OK ){ | < < < | < < | 5279 5280 5281 5282 5283 5284 5285 5286 5287 5288 5289 5290 5291 5292 5293 5294 5295 5296 | ** it can be ignored. */ if( !jrnlOpen ){ int f = SQLITE_OPEN_READONLY|SQLITE_OPEN_MAIN_JOURNAL; rc = sqlite3OsOpen(pVfs, pPager->zJournal, pPager->jfd, f, &f); } if( rc==SQLITE_OK ){ rc = checkHotJournal(pPager, pExists); if( !jrnlOpen ){ sqlite3OsClose(pPager->jfd); } }else if( rc==SQLITE_CANTOPEN ){ /* If we cannot open the rollback journal file in order to see if ** it has a zero header, that might be due to an I/O error, or ** it might be due to the race condition described above and in ** ticket #3883. Either way, assume that the journal is hot. ** This might be a false positive. But if it is, then the ** automatic journal playback and recovery mechanism will deal |
︙ | ︙ | |||
5429 5430 5431 5432 5433 5434 5435 5436 5437 5438 5439 5440 5441 5442 | } failed: if( rc!=SQLITE_OK ){ assert( !MEMDB ); pager_unlock(pPager); assert( pPager->eState==PAGER_OPEN ); }else{ pPager->eState = PAGER_READER; pPager->hasHeldSharedLock = 1; } return rc; } | > > > > | 5533 5534 5535 5536 5537 5538 5539 5540 5541 5542 5543 5544 5545 5546 5547 5548 5549 5550 | } failed: if( rc!=SQLITE_OK ){ assert( !MEMDB ); pager_unlock(pPager); assert( pPager->eState==PAGER_OPEN ); #ifdef SQLITE_ENABLE_READONLY_WALJOURNAL testcase( pPager->xGet==getPageOneNoWal ); setGetterMethod(pPager); #endif /* SQLITE_ENABLE_READONLY_WALJOURNAL */ }else{ pPager->eState = PAGER_READER; pPager->hasHeldSharedLock = 1; } return rc; } |
︙ | ︙ | |||
5695 5696 5697 5698 5699 5700 5701 | ){ UNUSED_PARAMETER(pgno); UNUSED_PARAMETER(flags); assert( pPager->errCode!=SQLITE_OK ); *ppPage = 0; return pPager->errCode; } | < | 5803 5804 5805 5806 5807 5808 5809 5810 5811 5812 5813 5814 5815 5816 | ){ UNUSED_PARAMETER(pgno); UNUSED_PARAMETER(flags); assert( pPager->errCode!=SQLITE_OK ); *ppPage = 0; return pPager->errCode; } /* Dispatch all page fetch requests to the appropriate getter method. */ int sqlite3PagerGet( Pager *pPager, /* The pager open on the database file */ Pgno pgno, /* Page number to fetch */ DbPage **ppPage, /* Write a pointer to the page here */ |
︙ | ︙ | |||
7397 7398 7399 7400 7401 7402 7403 7404 7405 7406 7407 7408 7409 7410 | sqlite3OsDelete(pPager->pVfs, pPager->zJournal, 0); }else{ int rc = SQLITE_OK; int state = pPager->eState; assert( state==PAGER_OPEN || state==PAGER_READER ); if( state==PAGER_OPEN ){ rc = sqlite3PagerSharedLock(pPager); } if( pPager->eState==PAGER_READER ){ assert( rc==SQLITE_OK ); rc = pagerLockDb(pPager, RESERVED_LOCK); } if( rc==SQLITE_OK ){ sqlite3OsDelete(pPager->pVfs, pPager->zJournal, 0); | > > > > > > > > > | 7504 7505 7506 7507 7508 7509 7510 7511 7512 7513 7514 7515 7516 7517 7518 7519 7520 7521 7522 7523 7524 7525 7526 | sqlite3OsDelete(pPager->pVfs, pPager->zJournal, 0); }else{ int rc = SQLITE_OK; int state = pPager->eState; assert( state==PAGER_OPEN || state==PAGER_READER ); if( state==PAGER_OPEN ){ rc = sqlite3PagerSharedLock(pPager); #ifdef SQLITE_ENABLE_READONLY_WALJOURNAL /* If this is a read-only connection, and there is a hot-journal ** created by "PRAGMA journal_mode = wal" in the file-system, then ** the Pager.xGet method may have been set to getPageOneNoWal. Call ** setGetterMethod() here to ensure it is set properly. */ testcase( pPager->xGet==getPageOneNoWal ); setGetterMethod(pPager); #endif /* SQLITE_ENABLE_READONLY_WALJOURNAL */ } if( pPager->eState==PAGER_READER ){ assert( rc==SQLITE_OK ); rc = pagerLockDb(pPager, RESERVED_LOCK); } if( rc==SQLITE_OK ){ sqlite3OsDelete(pPager->pVfs, pPager->zJournal, 0); |
︙ | ︙ |
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); |
︙ | ︙ | |||
2290 2291 2292 2293 2294 2295 2296 | ** 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: { | | > | | 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 | ** 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/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; } |
︙ | ︙ | |||
399 400 401 402 403 404 405 406 407 408 409 410 411 412 | ** ** 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 ){ | > > > > | 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 | ** ** 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 ){ |
︙ | ︙ | |||
421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 | } 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){ | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > < | < | > | > | | 493 494 495 496 497 498 499 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 | } 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; } |
︙ | ︙ | |||
496 497 498 499 500 501 502 503 504 505 506 507 508 509 | 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 ){ | > > > > | 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 | 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 ){ |
︙ | ︙ | |||
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 | 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; } | > > > > > > | 948 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 | 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.
︙ | ︙ | |||
1520 1521 1522 1523 1524 1525 1526 | #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 */ | | | | | | | | > | 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 | #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 */ |
︙ | ︙ | |||
5283 5284 5285 5286 5287 5288 5289 5290 5291 5292 5293 5294 5295 5296 | " 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", | > > > > > > | 5284 5285 5286 5287 5288 5289 5290 5291 5292 5293 5294 5295 5296 5297 5298 5299 5300 5301 5302 5303 | " 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", |
︙ | ︙ | |||
5762 5763 5764 5765 5766 5767 5768 5769 5770 5771 5772 5773 5774 5775 | 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; } | > > > > > | 5769 5770 5771 5772 5773 5774 5775 5776 5777 5778 5779 5780 5781 5782 5783 5784 5785 5786 5787 | 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; } |
︙ | ︙ | |||
8155 8156 8157 8158 8159 8160 8161 8162 | sqlite3_free(cmd.zSrcTable); return rc; } /* End of the ".archive" or ".ar" command logic *******************************************************************************/ #endif /* !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_HAVE_ZLIB) */ | > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 8167 8168 8169 8170 8171 8172 8173 8174 8175 8176 8177 8178 8179 8180 8181 8182 8183 8184 8185 8186 8187 8188 8189 8190 8191 8192 8193 8194 8195 8196 8197 8198 8199 8200 8201 8202 8203 8204 8205 8206 8207 8208 8209 8210 8211 8212 8213 8214 8215 8216 8217 8218 8219 8220 8221 8222 8223 8224 8225 8226 8227 8228 8229 8230 8231 8232 8233 8234 8235 8236 8237 8238 8239 8240 8241 8242 8243 8244 8245 8246 8247 8248 8249 8250 8251 8252 8253 8254 8255 8256 8257 8258 8259 8260 8261 8262 8263 8264 8265 8266 8267 8268 8269 8270 8271 8272 8273 8274 8275 8276 8277 8278 8279 8280 8281 8282 8283 8284 8285 8286 8287 8288 8289 8290 8291 8292 8293 8294 8295 8296 8297 8298 8299 8300 8301 8302 8303 8304 8305 8306 8307 8308 8309 8310 8311 8312 8313 8314 8315 8316 8317 8318 8319 8320 8321 8322 8323 8324 8325 8326 8327 8328 8329 8330 8331 8332 8333 8334 8335 8336 8337 8338 8339 8340 8341 8342 8343 8344 8345 8346 8347 8348 8349 8350 8351 8352 8353 8354 8355 8356 8357 8358 8359 8360 8361 8362 8363 8364 8365 8366 8367 8368 8369 8370 8371 8372 8373 8374 8375 8376 8377 8378 8379 8380 8381 8382 8383 8384 8385 8386 8387 8388 8389 8390 8391 8392 8393 8394 8395 8396 8397 8398 8399 8400 8401 8402 8403 8404 8405 8406 8407 8408 8409 8410 8411 8412 8413 8414 8415 8416 8417 8418 8419 8420 8421 8422 8423 8424 8425 8426 8427 8428 8429 8430 8431 8432 8433 8434 8435 8436 8437 8438 8439 8440 8441 8442 8443 8444 8445 8446 8447 8448 8449 8450 8451 8452 | 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 ){ sqlite3_fprintf(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) ){ sqlite3_fprintf(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) ){ sqlite3_fprintf(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 ){ sqlite3_fprintf(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 ){ sqlite3_fprintf(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 ){ sqlite3_fprintf(pState->out, "%s is NOT compatible (schema cookie)\n", zDb ); } bFailed = 1; if( peFix ) *peFix = 3; } } if( rc==SQLITE_OK && bFailed==0 ){ sqlite3_fprintf(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 ){ sqlite3_fprintf(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 ){ sqlite3_fprintf(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: sqlite3_fprintf(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; sqlite3_fprintf(pState->out, "%s;\n", zSql); |
︙ | ︙ | |||
11347 11348 11349 11350 11351 11352 11353 11354 11355 11356 11357 11358 11359 11360 | } 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; | > > > > > > > | 11628 11629 11630 11631 11632 11633 11634 11635 11636 11637 11638 11639 11640 11641 11642 11643 11644 11645 11646 11647 11648 | } 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; |
︙ | ︙ | |||
13219 13220 13221 13222 13223 13224 13225 13226 13227 13228 13229 13230 13231 13232 | }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; | > > | 13507 13508 13509 13510 13511 13512 13513 13514 13515 13516 13517 13518 13519 13520 13521 13522 | }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; |
︙ | ︙ | |||
13375 13376 13377 13378 13379 13380 13381 13382 13383 13384 13385 13386 13387 13388 | }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 ){ | > > | 13665 13666 13667 13668 13669 13670 13671 13672 13673 13674 13675 13676 13677 13678 13679 13680 | }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.
︙ | ︙ | |||
1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 | 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; | > | 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 | 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; |
︙ | ︙ | |||
1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 | */ 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. | > > > > | 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 | */ 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. |
︙ | ︙ | |||
1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 | 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)) | > > > | 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 | 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)) |
︙ | ︙ | |||
1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 | sqlite3 *pUnlockConnection; /* Connection to watch for unlock */ void *pUnlockArg; /* Argument to xUnlockNotify */ void (*xUnlockNotify)(void **, int); /* Unlock notify callback */ sqlite3 *pNextBlocked; /* Next in list of all blocked connections */ #endif }; /* ** A macro to discover the encoding of a database. */ #define SCHEMA_ENC(db) ((db)->aDb[0].pSchema->enc) #define ENC(db) ((db)->enc) /* | > > > > > > | 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 | sqlite3 *pUnlockConnection; /* Connection to watch for unlock */ void *pUnlockArg; /* Argument to xUnlockNotify */ void (*xUnlockNotify)(void **, int); /* Unlock notify callback */ sqlite3 *pNextBlocked; /* Next in list of all blocked connections */ #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) /* |
︙ | ︙ | |||
1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 | #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 */ | > > > | 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 | #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 |
︙ | ︙ | |||
4096 4097 4098 4099 4100 4101 4102 4103 4104 4105 4106 4107 4108 4109 | 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. | > > > | 4116 4117 4118 4119 4120 4121 4122 4123 4124 4125 4126 4127 4128 4129 4130 4131 4132 | 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. |
︙ | ︙ | |||
4235 4236 4237 4238 4239 4240 4241 4242 4243 4244 4245 4246 4247 4248 | 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 */ | > | 4258 4259 4260 4261 4262 4263 4264 4265 4266 4267 4268 4269 4270 4271 4272 | 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 */ |
︙ | ︙ | |||
5460 5461 5462 5463 5464 5465 5466 5467 5468 5469 5470 5471 5472 5473 | 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); | > > > > > > > > > > > > > > > > > > > > > > > | 5484 5485 5486 5487 5488 5489 5490 5491 5492 5493 5494 5495 5496 5497 5498 5499 5500 5501 5502 5503 5504 5505 5506 5507 5508 5509 5510 5511 5512 5513 5514 5515 5516 5517 5518 5519 5520 | 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.
︙ | ︙ | |||
285 286 287 288 289 290 291 292 293 294 295 296 297 | ** *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++){ | > > > > > > > > > > > > > | | 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 | ** *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 |
︙ | ︙ | |||
313 314 315 316 317 318 319 | 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)); } } | > > > > | > > > | 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 | 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.
︙ | ︙ | |||
3778 3779 3780 3781 3782 3783 3784 3785 3786 3787 3788 3789 3790 3791 | 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? | > > > | 3778 3779 3780 3781 3782 3783 3784 3785 3786 3787 3788 3789 3790 3791 3792 3793 3794 | 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? |
︙ | ︙ | |||
3909 3910 3911 3912 3913 3914 3915 3916 3917 3918 3919 3920 3921 3922 | 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; | > > > > > > > > > > | 3912 3913 3914 3915 3916 3917 3918 3919 3920 3921 3922 3923 3924 3925 3926 3927 3928 3929 3930 3931 3932 3933 3934 3935 | 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.
︙ | ︙ | |||
564 565 566 567 568 569 570 571 572 573 574 575 576 577 | #endif #ifdef SQLITE_OMIT_PROGRESS_CALLBACK Tcl_SetVar2(interp, "sqlite_options", "progress", "0", TCL_GLOBAL_ONLY); #else Tcl_SetVar2(interp, "sqlite_options", "progress", "1", TCL_GLOBAL_ONLY); #endif #ifdef SQLITE_OMIT_REINDEX Tcl_SetVar2(interp, "sqlite_options", "reindex", "0", TCL_GLOBAL_ONLY); #else Tcl_SetVar2(interp, "sqlite_options", "reindex", "1", TCL_GLOBAL_ONLY); #endif | > > > > > > > > | 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 | #endif #ifdef SQLITE_OMIT_PROGRESS_CALLBACK Tcl_SetVar2(interp, "sqlite_options", "progress", "0", TCL_GLOBAL_ONLY); #else Tcl_SetVar2(interp, "sqlite_options", "progress", "1", TCL_GLOBAL_ONLY); #endif #ifdef SQLITE_ENABLE_READONLY_WALJOURNAL Tcl_SetVar2( interp, "sqlite_options", "readonly_waljournal", "1", TCL_GLOBAL_ONLY); #else Tcl_SetVar2( interp, "sqlite_options", "readonly_waljournal", "0", TCL_GLOBAL_ONLY); #endif #ifdef SQLITE_OMIT_REINDEX Tcl_SetVar2(interp, "sqlite_options", "reindex", "0", TCL_GLOBAL_ONLY); #else Tcl_SetVar2(interp, "sqlite_options", "reindex", "1", TCL_GLOBAL_ONLY); #endif |
︙ | ︙ | |||
782 783 784 785 786 787 788 789 790 791 792 793 794 795 | #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 #if !defined(SQLITE_ENABLE_SETLK_TIMEOUT) Tcl_SetVar2(interp, "sqlite_options", "setlk_timeout", "0", TCL_GLOBAL_ONLY); #else Tcl_SetVar2(interp, "sqlite_options", "setlk_timeout", STRINGVALUE(SQLITE_ENABLE_SETLK_TIMEOUT), TCL_GLOBAL_ONLY); #endif | > > > > > > > | 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 | #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 #if !defined(SQLITE_ENABLE_SETLK_TIMEOUT) Tcl_SetVar2(interp, "sqlite_options", "setlk_timeout", "0", TCL_GLOBAL_ONLY); #else Tcl_SetVar2(interp, "sqlite_options", "setlk_timeout", STRINGVALUE(SQLITE_ENABLE_SETLK_TIMEOUT), TCL_GLOBAL_ONLY); #endif |
︙ | ︙ |
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 | /* ** 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 "tclsqlite.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.
︙ | ︙ | |||
64 65 66 67 68 69 70 71 72 73 74 75 76 77 | 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*); | > | 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 | 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*); |
︙ | ︙ | |||
135 136 137 138 139 140 141 142 143 144 145 146 147 148 | 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); | > | 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 | 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->isCreate ); assert( &(pParse->u1.d.pReturning->retTrig) == pTrig ); pTrig->table = pTab->zName; pTrig->pTabSchema = pTab->pSchema; pTrig->pNext = pList; pList = pTrig; |
︙ | ︙ | |||
262 263 264 265 266 267 268 269 270 271 272 273 274 275 | /* 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; | > > > > > > | 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 | /* 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; |
︙ | ︙ | |||
385 386 387 388 389 390 391 | 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); | | | 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 | 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) ); |
︙ | ︙ | |||
604 605 606 607 608 609 610 611 612 613 614 615 616 617 | ** 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. | > > > | 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 | ** 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. |
︙ | ︙ | |||
676 677 678 679 680 681 682 683 684 685 686 687 688 689 | 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); | > | 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 | 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); |
︙ | ︙ | |||
1248 1249 1250 1251 1252 1253 1254 | 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 */ | | > > | 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 | 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; |
︙ | ︙ | |||
1357 1358 1359 1360 1361 1362 1363 | 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; | | > > | 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 | 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.
︙ | ︙ | |||
4104 4105 4106 4107 4108 4109 4110 | } } assert( pOp->p5==0 || pOp->p4type==P4_INT32 ); if( rc==SQLITE_OK && pOp->p5 && (iMeta!=pOp->p3 || pDb->pSchema->iGeneration!=pOp->p4.i) ){ | < < < < < < < > > > > > > > | 4104 4105 4106 4107 4108 4109 4110 4111 4112 4113 4114 4115 4116 4117 4118 4119 4120 4121 4122 4123 4124 4125 4126 4127 4128 4129 4130 4131 4132 4133 4134 4135 4136 4137 4138 4139 4140 | } } 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.
︙ | ︙ | |||
241 242 243 244 245 246 247 | # 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 | | | 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 | # 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.
︙ | ︙ | |||
555 556 557 558 559 560 561 | ** 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. */ | | > > | 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 | ** 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.
︙ | ︙ | |||
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 | int iCol; /* Index of zColumn in row-record */ int rc = SQLITE_OK; char *zErr = 0; Table *pTab; Incrblob *pBlob = 0; int iDb; 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; | > > | 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 | int iCol; /* Index of zColumn in row-record */ int rc = SQLITE_OK; char *zErr = 0; Table *pTab; Incrblob *pBlob = 0; int iDb; 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; |
︙ | ︙ | |||
335 336 337 338 339 340 341 342 343 344 345 346 347 348 | } 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); | > | 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 | } 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. |
︙ | ︙ | |||
496 497 498 499 500 501 502 | pParse->u1.cr.regRowid ); v = sqlite3GetVdbe(pParse); sqlite3ChangeCookie(pParse, iDb); sqlite3VdbeAddOp0(v, OP_Expire); zWhere = sqlite3MPrintf(db, "name=%Q AND sql=%Q", pTab->zName, zStmt); | | | 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 | pParse->u1.cr.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 |
︙ | ︙ | |||
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 | 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; } | > | > > > > > > > > | 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 | 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 ); |
︙ | ︙ | |||
639 640 641 642 643 644 645 | *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 | | > > | | | > > > > > > > > | | > | 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 | *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++){ |
︙ | ︙ | |||
699 700 701 702 703 704 705 706 707 708 709 710 711 712 | 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); | > | 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 | 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.
︙ | ︙ | |||
1680 1681 1682 1683 1684 1685 1686 | sqlite3OomFault(pParse->db); }else if( !pVtab->zErrMsg ){ sqlite3ErrorMsg(pParse, "%s", sqlite3ErrStr(rc)); }else{ sqlite3ErrorMsg(pParse, "%s", pVtab->zErrMsg); } } | | | 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 | 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) */ |
︙ | ︙ |
Changes to test/nolock.test.
︙ | ︙ | |||
12 13 14 15 16 17 18 19 20 21 22 23 24 25 | # This file implements regression tests for SQLite library. The # focus of this file is testing the nolock=1 and immutable=1 query # parameters and the SQLITE_IOCAP_IMMUTABLE device characteristic. # set testdir [file dirname $argv0] source $testdir/tester.tcl unset -nocomplain tvfs_calls proc tvfs_reset {} { global tvfs_calls array set tvfs_calls {xLock 0 xUnlock 0 xCheckReservedLock 0 xAccess 0} } proc tvfs_callback {op args} { | > | 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | # This file implements regression tests for SQLite library. The # focus of this file is testing the nolock=1 and immutable=1 query # parameters and the SQLITE_IOCAP_IMMUTABLE device characteristic. # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix nolock unset -nocomplain tvfs_calls proc tvfs_reset {} { global tvfs_calls array set tvfs_calls {xLock 0 xUnlock 0 xCheckReservedLock 0 xAccess 0} } proc tvfs_callback {op args} { |
︙ | ︙ | |||
213 214 215 216 217 218 219 220 | db close sqlite3 db file:test.db?nolock=1 -uri 1 set rc [catch {db eval {SELECT * FROM t1}} msg] lappend rc $msg } {1 {unable to open database file}} } finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | db close sqlite3 db file:test.db?nolock=1 -uri 1 set rc [catch {db eval {SELECT * FROM t1}} msg] lappend rc $msg } {1 {unable to open database file}} } #------------------------------------------------------------------------- reset_db do_execsql_test 5.0 { CREATE TABLE t1(x, y); CREATE TABLE t2(x, y); INSERT INTO t1 VALUES(1, 2), (3, 4), (5, 6); INSERT INTO t2 VALUES(1, 2), (3, 4), (5, 6); PRAGMA cache_size = 0; BEGIN; INSERT INTO t1 VALUES(7, 8); INSERT INTO t2 VALUES(7, 8); } do_test 5.1 { forcecopy test.db test.db2 forcecopy test.db-journal test.db2-journal sqlite3 db2 file:test.db2?immutable=0 -uri 1 -readonly 1 list [catch { db2 eval { SELECT * FROM t1; SELECT * FROM t2; } } msg] $msg } {1 {attempt to write a readonly database}} finish_test |
Added test/readonly2.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 | # 2024 October 30 # # 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. # #*********************************************************************** # # Test that readonly database connections may ignore a hot journal # created by an aborted "PRAGMA journal_mode = wal" statement. # set testdir [file dirname $argv0] source $testdir/tester.tcl ifcapable !readonly_waljournal { finish_test return } set ::testprefix readonly2 testvfs tvfs -default 1 tvfs script at_vfs_callback tvfs filter {xDelete} set ::delete_shall_fail 0 proc at_vfs_callback {method file z args} { if {$::delete_shall_fail} { return "SQLITE_IOERR" } return "SQLITE_OK" } reset_db do_execsql_test 1.0 { BEGIN; CREATE TABLE t1(a, b); INSERT INTO t1 VALUES(1, 2), (3, 4), (5, 6); COMMIT; } set ::delete_shall_fail 1 do_catchsql_test 1.1 { PRAGMA journal_mode = wal; } {1 {disk I/O error}} do_test 1.2 { file exists test.db-journal } 1 do_test 1.3 { sqlite3 db2 test.db -readonly 1 db2 eval { SELECT * FROM t1 } } {1 2 3 4 5 6} do_test 1.4 { file exists test.db-journal } 1 set ::delete_shall_fail 0 do_execsql_test 1.5 { SELECT * FROM t1 } {1 2 3 4 5 6} set ::delete_shall_fail 1 do_catchsql_test 1.6 { PRAGMA user_version = 444; } {1 {disk I/O error}} do_test 1.7 { file exists test.db-journal } 1 do_test 1.8 { list [catch { db2 eval { SELECT * FROM t1 } } msg] $msg } {1 {attempt to write a readonly database}} do_test 1.9 { file exists test.db-journal } 1 set ::delete_shall_fail 0 do_execsql_test 1.10 { SELECT * FROM t1 } {1 2 3 4 5 6} #--------------------------------------------------------- reset_db do_execsql_test 2.1 { CREATE TABLE t1(a, b); INSERT INTO t1 VALUES('abc', 'def'); } set ::delete_shall_fail 1 do_catchsql_test 2.2 { PRAGMA journal_mode = wal; } {1 {disk I/O error}} do_test 2.3 { sqlite3 db2 test.db -readonly 1 breakpoint db2 eval { PRAGMA journal_mode = persist; PRAGMA journal_mode = off; } } {persist off} do_test 2.4 { db2 eval { SELECT * FROM t1 } } {abc def} finish_test |
Added test/readonlyfault.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 | # 2024 October 30 # # 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 ifcapable !readonly_waljournal { finish_test return } set ::testprefix readonlyfault testvfs tvfs -default 1 tvfs script at_vfs_callback tvfs filter {xDelete} set ::delete_shall_fail 0 proc at_vfs_callback {method file z args} { if {$::delete_shall_fail} { return "SQLITE_IOERR" } return "SQLITE_OK" } reset_db do_execsql_test 1.0 { BEGIN; CREATE TABLE t1(a, b); INSERT INTO t1 VALUES(1, 2), (3, 4), (5, 6); COMMIT; } set ::delete_shall_fail 1 do_catchsql_test 1.1 { PRAGMA journal_mode = wal; } {1 {disk I/O error}} do_test 1.2 { file exists test.db-journal } 1 db_save_and_close # Injecting CANTOPEN errors doesn't work here. If such an error occurs # while trying to open a potentially hot journal to inspect its contents, # the error is ignored and the journal assumed to be hot. Leading to an # SQLITE_READONLY error. So only the other types of fault-injection are # tested here. # do_faultsim_test readonlyfault-1 -faults {oom* ioerr* inter* full*} -prep { catch { db close } db_restore sqlite3 db test.db -readonly 1 } -body { execsql { SELECT count(*), sum(a), sum(b) FROM t1 } } -test { faultsim_test_result {0 {3 9 12}} } finish_test |
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}} } #------------------------------------------------------------------------- # db2 close db3 close 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} #-------------------------------------------------------------------------- db2 close 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 356 | # 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} #------------------------------------------------------------------------- db2 close db3 close 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 174 | # 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 } { catch {db2 close} 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. # db2 close 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 55 56 | # 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 { catch {db close} 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 { catch {db close} catch {db2 close} 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.
︙ | ︙ | |||
828 829 830 831 832 833 834 | } proc catchcmd {db {cmd ""}} { global CLI set out [open cmds.txt w] puts $out $cmd close $out | | | 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 | } 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.
︙ | ︙ | |||
1298 1299 1300 1301 1302 1303 1304 | add_tcl_jobs "" $c $patternlist } } devtest - mdevtest { set config_set { | | > | | 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 | add_tcl_jobs "" $c $patternlist } } devtest - 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.
︙ | ︙ | |||
103 104 105 106 107 108 109 110 111 112 113 114 115 116 | 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 -DSQLITE_ENABLE_NORMALIZE -DCONFIG_SLOWDOWN_FACTOR=5.0 | > > > > > > > > > > > > | 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 | 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 -DSQLITE_ENABLE_NORMALIZE -DCONFIG_SLOWDOWN_FACTOR=5.0 |
︙ | ︙ | |||
482 483 484 485 486 487 488 | proc make_sh_script {srcdir opts cflags makeOpts configOpts} { set tcldir [::tcl::pkgconfig get libdir,install] set myopts "" if {[info exists ::env(OPTS)]} { append myopts "# From environment variable:\n" | | | | 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 | proc make_sh_script {srcdir opts cflags makeOpts configOpts} { set tcldir [::tcl::pkgconfig get libdir,install] set myopts "" if {[info exists ::env(OPTS)]} { append myopts "# From environment variable:\n" append myopts "OPTIONS=$::env(OPTS)\n\n" } foreach o [lsort $opts] { append myopts "OPTIONS=\"\$OPTS $o\"\n" } return [trimscript [subst -nocommands { set -e if [ "\$#" -ne 1 ] ; then echo "Usage: \$0 <target>" exit -1 |
︙ | ︙ |
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/lemon.c.
︙ | ︙ | |||
84 85 86 87 88 89 90 | ** This is not necessary. But compilers and getting increasingly ** fussy about memory leaks, even in command-line programs like Lemon ** where they do not matter. So this code is provided to hush the ** warnings. */ static void *lemon_malloc(size_t nByte){ MemChunk *p; | | | 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 | ** This is not necessary. But compilers and getting increasingly ** fussy about memory leaks, even in command-line programs like Lemon ** where they do not matter. So this code is provided to hush the ** warnings. */ static void *lemon_malloc(size_t nByte){ MemChunk *p; /* if( nByte<0 ) return 0; -- size_t is unsigned */ p = malloc( nByte + sizeof(MemChunk) ); if( p==0 ){ fprintf(stderr, "Out of memory. Failed to allocate %lld bytes.\n", (long long int)nByte); exit(1); } p->pNext = memChunkList; |
︙ | ︙ | |||
2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 | fprintf(errstream," -%s<string>%*s %s\n",op[i].label, (int)(max-lemonStrlen(op[i].label)-8),"",op[i].message); break; } } } /*********************** From the file "parse.c" ****************************/ /* ** Input file parser for the LEMON parser generator. */ /* The state of the parser */ enum e_state { INITIALIZE, | > > | 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 | fprintf(errstream," -%s<string>%*s %s\n",op[i].label, (int)(max-lemonStrlen(op[i].label)-8),"",op[i].message); break; } } } /*********************** From the file "parse.c" ****************************/ /* ** Input file parser for the LEMON parser generator. */ /* The state of the parser */ enum e_state { INITIALIZE, |
︙ | ︙ | |||
2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 | int insertLineMacro; /* Add #line before declaration insert */ int *decllinenoslot; /* Where to write declaration line number */ enum e_assoc declassoc; /* Assign this association to decl arguments */ int preccounter; /* Assign this precedence to decl arguments */ struct rule *firstrule; /* Pointer to first rule in the grammar */ struct rule *lastrule; /* Pointer to the most recently parsed rule */ }; /* Parse a single token */ static void parseonetoken(struct pstate *psp) { const char *x; x = Strsafe(psp->tokenstart); /* Save the token permanently */ #if 0 | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 | int insertLineMacro; /* Add #line before declaration insert */ int *decllinenoslot; /* Where to write declaration line number */ enum e_assoc declassoc; /* Assign this association to decl arguments */ int preccounter; /* Assign this precedence to decl arguments */ struct rule *firstrule; /* Pointer to first rule in the grammar */ struct rule *lastrule; /* Pointer to the most recently parsed rule */ }; /* ** input x[] is a filename enclosed in <...>. This routine strives ** to load the complete text of the named file into memory obtained ** from lemon_malloc() and return that text. The complete filename ** (without the enclosing <...>) is also written into memory obtained ** from lemon_malloc() and written back into *pzFN. ** ** Except, if any error occurs, the error message is set on psp and ** no memory is allocated and a NULL is returned. */ static char *load_file_content( struct pstate *psp, /* Parsing context */ const char *x, /* Filename enclosed in <....> */ char **pzFN /* Write true filename here */ ){ char *zContent; char *zFN; int nFN; FILE *in; int nAlloc; int nContent; *pzFN = 0; nFN = lemonStrlen(x); zFN = lemon_malloc( nFN ); memcpy(zFN, x+1, nFN-1); zFN[nFN-1] = 0; in = fopen(zFN, "rb"); if( in==0 ){ ErrorMsg(psp->filename,psp->tokenlineno, "Cannot read file \"%s\"", zFN); psp->errorcnt++; lemon_free(zFN); return 0; } *pzFN = zFN; nAlloc = 2000; zContent = lemon_malloc( nAlloc ); nContent = 0; while( nContent<nAlloc-1 ){ long got = fread(&zContent[nContent], 1, nAlloc-nContent-1, in); if( got<=0 ) break; nContent += got; if( nContent>=nAlloc-1 ){ nAlloc *= 2; zContent = lemon_realloc(zContent, nAlloc); } } zContent[nContent] = 0; fclose(in); return zContent; } /* Parse a single token */ static void parseonetoken(struct pstate *psp) { const char *x; x = Strsafe(psp->tokenstart); /* Save the token permanently */ #if 0 |
︙ | ︙ | |||
2742 2743 2744 2745 2746 2747 2748 | }else{ ErrorMsg(psp->filename,psp->tokenlineno, "Can't assign a precedence to \"%s\".",x); psp->errorcnt++; } break; case WAITING_FOR_DECL_ARG: | | > > | > > > > > > > > > > > > > | | > | > | | | | > > | 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 2853 2854 2855 2856 2857 2858 2859 2860 2861 2862 2863 2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 2881 2882 2883 | }else{ ErrorMsg(psp->filename,psp->tokenlineno, "Can't assign a precedence to \"%s\".",x); psp->errorcnt++; } break; case WAITING_FOR_DECL_ARG: if( x[0]=='{' || x[0]=='\"' || ISALNUM(x[0]) || (x[0]=='<' && psp->insertLineMacro) ){ const char *zOld, *zNew; char *zBuf; const char *z; int nOld, n, nLine = 0, nNew, nBack; int addLineMacro; char zLine[50]; char *zToFreeTxt = 0; char *zToFreeFN = 0; const char *zFN = psp->filename; int ln = psp->tokenlineno; if( x[0]=='<' ){ zToFreeTxt = load_file_content(psp,x,&zToFreeFN); if( psp->errorcnt ) break; zNew = zToFreeTxt; zFN = zToFreeFN; ln = 1; }else{ zNew = x; if( zNew[0]=='"' || zNew[0]=='{' ) zNew++; } nNew = lemonStrlen(zNew); if( *psp->declargslot ){ zOld = *psp->declargslot; }else{ zOld = ""; } nOld = lemonStrlen(zOld); n = nOld + nNew + 20; addLineMacro = !psp->gp->nolinenosflag && psp->insertLineMacro && psp->tokenlineno>1 && (psp->decllinenoslot==0 || psp->decllinenoslot[0]!=0); if( addLineMacro || x[0]=='<' ){ addLineMacro = 1; for(z=zFN, nBack=0; *z; z++){ if( *z=='\\' ) nBack++; } lemon_sprintf(zLine, "#line %d ", ln); nLine = lemonStrlen(zLine); n += nLine + lemonStrlen(zFN) + nBack; } *psp->declargslot = (char *) lemon_realloc(*psp->declargslot, n); zBuf = *psp->declargslot + nOld; if( addLineMacro ){ if( nOld && zBuf[-1]!='\n' ){ *(zBuf++) = '\n'; } memcpy(zBuf, zLine, nLine); zBuf += nLine; *(zBuf++) = '"'; for(z=zFN; *z; z++){ if( *z=='\\' ){ *(zBuf++) = '\\'; } *(zBuf++) = *z; } *(zBuf++) = '"'; *(zBuf++) = '\n'; } if( psp->decllinenoslot && psp->decllinenoslot[0]==0 ){ psp->decllinenoslot[0] = psp->tokenlineno; } memcpy(zBuf, zNew, nNew); zBuf += nNew; *zBuf = 0; psp->state = WAITING_FOR_DECL_OR_RULE; lemon_free(zToFreeTxt); lemon_free(zToFreeFN); }else{ ErrorMsg(psp->filename,psp->tokenlineno, "Illegal argument to %%%s: %s",psp->declkeyword,x); psp->errorcnt++; psp->state = RESYNC_AFTER_DECL_ERROR; } break; |
︙ | ︙ | |||
3159 3160 3161 3162 3163 3164 3165 3166 3167 3168 3169 3170 3171 3172 | } if( c==0 ){ ErrorMsg(ps.filename,startline, "String starting on this line is not terminated before " "the end of the file."); ps.errorcnt++; nextcp = cp; }else{ nextcp = cp+1; } }else if( c=='{' ){ /* A block of C code */ int level; cp++; for(level=1; (c= *cp)!=0 && (level>1 || c!='}'); cp++){ | > > > > > > > > > > > > | 3234 3235 3236 3237 3238 3239 3240 3241 3242 3243 3244 3245 3246 3247 3248 3249 3250 3251 3252 3253 3254 3255 3256 3257 3258 3259 | } if( c==0 ){ ErrorMsg(ps.filename,startline, "String starting on this line is not terminated before " "the end of the file."); ps.errorcnt++; nextcp = cp; }else{ nextcp = cp+1; } }else if( c=='<' ){ /* Pathname in <...> */ cp++; while( (c= *cp)!=0 && c!='>' && (c&0xfc)!=0 ){ cp++; } if( (c&0xfc)==0 ){ ErrorMsg(ps.filename,startline, c==0 ? "Unterminated filename" : "Control-character in filename"); ps.errorcnt++; nextcp = cp; }else{ nextcp = cp+1; } }else if( c=='{' ){ /* A block of C code */ int level; cp++; for(level=1; (c= *cp)!=0 && (level>1 || c!='}'); cp++){ |
︙ | ︙ |
Changes to tool/mkpragmatab.tcl.
︙ | ︙ | |||
16 17 18 19 20 21 22 | # tclsh tool/mkpragmatab.tcl ;# <--- Results to 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 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. # In the event of a tie, sort column lists lexicographically. # proc colscmp {a b} { set rc [expr {[llength $b] - [llength $a]}] if {$rc} {return $rc} | > > > > > > | 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. # In the event of a tie, sort column lists lexicographically. # proc colscmp {a b} { set rc [expr {[llength $b] - [llength $a]}] if {$rc} {return $rc} |
︙ | ︙ |