Compare commits
208 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| d376cec4e9 | |||
| 0131629cdc | |||
| 870ff768a8 | |||
| 707b713adc | |||
| 50bd28f6b3 | |||
| 53f51faef9 | |||
| 6a5049f531 | |||
| fa0539cbde | |||
| 10345cff80 | |||
| 2327537449 | |||
| dfb65ee643 | |||
| 1f0d31a7f1 | |||
| 6ed0e1f261 | |||
| 9be66d60b2 | |||
| 3a665b3f26 | |||
| 7fd8520e62 | |||
| 20f3236308 | |||
| 65705581f6 | |||
| 2dad06a161 | |||
| ed02a2d4e9 | |||
| ae2652721b | |||
| a9a4c7870e | |||
| a2c52fcaca | |||
| 2e7fcc4162 | |||
| cd2c56bfaa | |||
| acb294098c | |||
| 4c552e22b9 | |||
| 7d0c4438be | |||
| 68604e0057 | |||
| 623e7cddec | |||
| 77c79e9bc1 | |||
| 320b307a67 | |||
| 4bf6faea61 | |||
| a235056f38 | |||
| 7bf3736da3 | |||
| 49c9204073 | |||
| 20bd014b94 | |||
| 68a762bee8 | |||
| d338edb3c0 | |||
| 739a4244a6 | |||
| d6c13c345a | |||
| cac74b855d | |||
| 3878069543 | |||
| 7b9926a813 | |||
| b73f9a9d2d | |||
| f234d50e0e | |||
| d4275cbba1 | |||
| 9b625ceb55 | |||
| 7c897ff2d6 | |||
| 1d8366292e | |||
| 1640440b82 | |||
| bee05161af | |||
| 66e912f5ab | |||
| 9d6823b3fd | |||
| c0cbfe4441 | |||
| a8f9fb33fe | |||
| 37057de32c | |||
| 363f6247e9 | |||
| 1f086b6f37 | |||
| 78cfb05847 | |||
| 98c3b92ef3 | |||
| 1dc5be408c | |||
| 358078d2e0 | |||
| db8189008c | |||
| aed55d8919 | |||
| abe10b697d | |||
| 368e2de678 | |||
| d4b32efa3e | |||
| 9a5d7496e7 | |||
| 6a443c86e8 | |||
| 68df2e81c2 | |||
| eea0f7d194 | |||
| fc2d1f1b36 | |||
| 4465a0cd0b | |||
| 495e42cf5e | |||
| 7983d0f0b7 | |||
| 660e3fad0b | |||
| af313837d5 | |||
| 39ade05f33 | |||
| 1d373b4de6 | |||
| b928283248 | |||
| d4ff324e8a | |||
| fa98d0ea0d | |||
| 4484700648 | |||
| d046825cce | |||
| cee8c84dc9 | |||
| 41a871f0d2 | |||
| da60a1b0be | |||
| 1546d749e3 | |||
| bba8f23721 | |||
| 2ba1bb5b6f | |||
| b2ded7c318 | |||
| 9d04907363 | |||
| bd564771f6 | |||
| b7416ed80f | |||
| b963701038 | |||
| 63f94dfe9f | |||
| fd89e834b8 | |||
| 339fbb64be | |||
| 3fc9378b03 | |||
| bfab6fb822 | |||
| 371cc2491f | |||
| babfb2e536 | |||
| 1b0b429f23 | |||
| ea8f049012 | |||
| 356f24f0d3 | |||
| 6857efa5a8 | |||
| 4d55331f24 | |||
| 082f003903 | |||
| 017616e441 | |||
| 89f4e8c325 | |||
| 8af662c8d6 | |||
| ce3cc96805 | |||
| 7dd6817e58 | |||
| 2f35820fdc | |||
| 85aaf75855 | |||
| 36b4ffef75 | |||
| bd89471096 | |||
| 5422f18381 | |||
| 934eb637c2 | |||
| 8280fcc66f | |||
| 5a5f8b366b | |||
| 73d2d7938e | |||
| e805679133 | |||
| bb85a9053e | |||
| 19b2d07824 | |||
| 02d30805c8 | |||
| 6d78967393 | |||
| 006f49bc9b | |||
| 0a6e45f4d9 | |||
| 8e8c7ccc9b | |||
| c3c71c1451 | |||
| 5e87610fdf | |||
| d3698b7fe8 | |||
| 72d2de6eef | |||
| 0df48684bd | |||
| 106ab91fc8 | |||
| 806e04ab8f | |||
| eb888e2497 | |||
| d973196e30 | |||
| f6b6f46538 | |||
| f8f62070f8 | |||
| 73debcccd1 | |||
| 1430806e39 | |||
| 49c7657ac9 | |||
| e046ccb5f0 | |||
| 0b5d397cb4 | |||
| 2833522a9a | |||
| 06526fef2e | |||
| 7e0410951f | |||
| abbad7ef3c | |||
| cdfb4a29f4 | |||
| ce86700aa7 | |||
| 5593a4c26d | |||
| 88e7099875 | |||
| 28c156d6d6 | |||
| e2e8e9b16f | |||
| ff0e1d8d04 | |||
| 98c5bff6c8 | |||
| 3eadd64c0e | |||
| d32261e7a9 | |||
| 6847647dc4 | |||
| ae070eff74 | |||
| f4c01da150 | |||
| 0d46c528dd | |||
| 209f79234b | |||
| 22b16ac3d0 | |||
| 88a96c49f2 | |||
| 85a76ddc12 | |||
| 20a434abd3 | |||
| 9c2b284dbd | |||
| 74e020a164 | |||
| 94dba01337 | |||
| 239f69e204 | |||
| 05a094d4c5 | |||
| aec53fa5ba | |||
| a011145aae | |||
| 13af9ba7af | |||
| 6170a98cfa | |||
| d0932d5358 | |||
| 61155cb70b | |||
| d746d250f0 | |||
| 155a112b81 | |||
| a5150d4f05 | |||
| 64104062a7 | |||
| 1395c92f1f | |||
| 33a37f5ef0 | |||
| 9d65677e57 | |||
| 6758315c8e | |||
| 5944230305 | |||
| a72a438cd7 | |||
| d62150108a | |||
| 2ce6757bd4 | |||
| 33d1394e1a | |||
| 81fb4ef019 | |||
| d4e11dd78f | |||
| 5add6f25e2 | |||
| 30fdc47579 | |||
| 73e6f3adbd | |||
| 73b8e1f2d6 | |||
| 01d6eab9a5 | |||
| e54087db7b | |||
| d000f2286d | |||
| 8874678ecd | |||
| 8612853f70 | |||
| 62012c0b34 | |||
| 7d3159668c | |||
| d6af93a92c |
@@ -1616,6 +1616,7 @@ TESTSRC = \
|
||||
$(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 \
|
||||
|
||||
@@ -725,6 +725,10 @@ 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>
|
||||
|
||||
@@ -920,6 +924,11 @@ For example:</p>
|
||||
<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>
|
||||
|
||||
|
||||
@@ -0,0 +1,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.
|
||||
@@ -1,10 +1,7 @@
|
||||
_fiddle_exec
|
||||
_fiddle_interrupt
|
||||
_fiddle_experiment
|
||||
_fiddle_the_db
|
||||
_fiddle_db_arg
|
||||
_fiddle_db_filename
|
||||
_fiddle_exec
|
||||
_fiddle_experiment
|
||||
_fiddle_interrupt
|
||||
_fiddle_main
|
||||
_fiddle_reset_db
|
||||
_fiddle_db_handle
|
||||
_fiddle_db_vfs
|
||||
_fiddle_export_db
|
||||
@@ -0,0 +1,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
|
||||
@@ -1,155 +0,0 @@
|
||||
_malloc
|
||||
_free
|
||||
_realloc
|
||||
_sqlite3_aggregate_context
|
||||
_sqlite3_auto_extension
|
||||
_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_parameter_name
|
||||
_sqlite3_bind_pointer
|
||||
_sqlite3_bind_text
|
||||
_sqlite3_busy_handler
|
||||
_sqlite3_busy_timeout
|
||||
_sqlite3_cancel_auto_extension
|
||||
_sqlite3_changes
|
||||
_sqlite3_changes64
|
||||
_sqlite3_clear_bindings
|
||||
_sqlite3_close_v2
|
||||
_sqlite3_collation_needed
|
||||
_sqlite3_column_blob
|
||||
_sqlite3_column_bytes
|
||||
_sqlite3_column_count
|
||||
_sqlite3_column_decltype
|
||||
_sqlite3_column_double
|
||||
_sqlite3_column_int
|
||||
_sqlite3_column_int64
|
||||
_sqlite3_column_name
|
||||
_sqlite3_column_text
|
||||
_sqlite3_column_type
|
||||
_sqlite3_column_value
|
||||
_sqlite3_commit_hook
|
||||
_sqlite3_compileoption_get
|
||||
_sqlite3_compileoption_used
|
||||
_sqlite3_complete
|
||||
_sqlite3_context_db_handle
|
||||
_sqlite3_create_collation
|
||||
_sqlite3_create_collation_v2
|
||||
_sqlite3_create_function
|
||||
_sqlite3_create_function_v2
|
||||
_sqlite3_data_count
|
||||
_sqlite3_db_filename
|
||||
_sqlite3_db_handle
|
||||
_sqlite3_db_name
|
||||
_sqlite3_db_readonly
|
||||
_sqlite3_db_status
|
||||
_sqlite3_deserialize
|
||||
_sqlite3_errcode
|
||||
_sqlite3_errmsg
|
||||
_sqlite3_error_offset
|
||||
_sqlite3_errstr
|
||||
_sqlite3_exec
|
||||
_sqlite3_expanded_sql
|
||||
_sqlite3_extended_errcode
|
||||
_sqlite3_extended_result_codes
|
||||
_sqlite3_file_control
|
||||
_sqlite3_finalize
|
||||
_sqlite3_free
|
||||
_sqlite3_get_auxdata
|
||||
_sqlite3_get_autocommit
|
||||
_sqlite3_initialize
|
||||
_sqlite3_interrupt
|
||||
_sqlite3_is_interrupted
|
||||
_sqlite3_keyword_count
|
||||
_sqlite3_keyword_name
|
||||
_sqlite3_keyword_check
|
||||
_sqlite3_last_insert_rowid
|
||||
_sqlite3_libversion
|
||||
_sqlite3_libversion_number
|
||||
_sqlite3_limit
|
||||
_sqlite3_malloc
|
||||
_sqlite3_malloc64
|
||||
_sqlite3_msize
|
||||
_sqlite3_open
|
||||
_sqlite3_open_v2
|
||||
_sqlite3_overload_function
|
||||
_sqlite3_prepare_v2
|
||||
_sqlite3_prepare_v3
|
||||
_sqlite3_randomness
|
||||
_sqlite3_realloc
|
||||
_sqlite3_realloc64
|
||||
_sqlite3_reset
|
||||
_sqlite3_reset_auto_extension
|
||||
_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_int64
|
||||
_sqlite3_result_null
|
||||
_sqlite3_result_pointer
|
||||
_sqlite3_result_subtype
|
||||
_sqlite3_result_text
|
||||
_sqlite3_result_zeroblob
|
||||
_sqlite3_result_zeroblob64
|
||||
_sqlite3_rollback_hook
|
||||
_sqlite3_serialize
|
||||
_sqlite3_set_auxdata
|
||||
_sqlite3_set_last_insert_rowid
|
||||
_sqlite3_shutdown
|
||||
_sqlite3_sourceid
|
||||
_sqlite3_sql
|
||||
_sqlite3_status
|
||||
_sqlite3_status64
|
||||
_sqlite3_step
|
||||
_sqlite3_stmt_busy
|
||||
_sqlite3_stmt_explain
|
||||
_sqlite3_stmt_isexplain
|
||||
_sqlite3_stmt_readonly
|
||||
_sqlite3_stmt_status
|
||||
_sqlite3_strglob
|
||||
_sqlite3_stricmp
|
||||
_sqlite3_strlike
|
||||
_sqlite3_strnicmp
|
||||
_sqlite3_table_column_metadata
|
||||
_sqlite3_total_changes
|
||||
_sqlite3_total_changes64
|
||||
_sqlite3_trace_v2
|
||||
_sqlite3_txn_state
|
||||
_sqlite3_update_hook
|
||||
_sqlite3_uri_boolean
|
||||
_sqlite3_uri_int64
|
||||
_sqlite3_uri_key
|
||||
_sqlite3_uri_parameter
|
||||
_sqlite3_user_data
|
||||
_sqlite3_value_blob
|
||||
_sqlite3_value_bytes
|
||||
_sqlite3_value_double
|
||||
_sqlite3_value_dup
|
||||
_sqlite3_value_free
|
||||
_sqlite3_value_frombind
|
||||
_sqlite3_value_int
|
||||
_sqlite3_value_int64
|
||||
_sqlite3_value_nochange
|
||||
_sqlite3_value_numeric_type
|
||||
_sqlite3_value_pointer
|
||||
_sqlite3_value_subtype
|
||||
_sqlite3_value_text
|
||||
_sqlite3_value_type
|
||||
_sqlite3_vfs_find
|
||||
_sqlite3_vfs_register
|
||||
_sqlite3_vfs_unregister
|
||||
_sqlite3_vtab_collation
|
||||
_sqlite3_vtab_distinct
|
||||
_sqlite3_vtab_in
|
||||
_sqlite3_vtab_in_first
|
||||
_sqlite3_vtab_in_next
|
||||
_sqlite3_vtab_nochange
|
||||
_sqlite3_vtab_on_conflict
|
||||
_sqlite3_vtab_rhs_value
|
||||
@@ -1,4 +1,3 @@
|
||||
//#ifnot omit-oo1
|
||||
/*
|
||||
2022-08-24
|
||||
|
||||
@@ -42,13 +41,9 @@
|
||||
- `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, and the only way to know when the worker module has
|
||||
completed loading. The irony of using a callback for this, instead
|
||||
of returning a promise from sqlite3Worker1Promiser() is not lost on
|
||||
the developers: see sqlite3Worker1Promiser.v2() which uses a
|
||||
Promise instead.
|
||||
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
|
||||
@@ -119,7 +114,7 @@
|
||||
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 the
|
||||
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
|
||||
@@ -127,17 +122,8 @@
|
||||
the end of the result set has been reached. Note that the rows
|
||||
arrive via worker-posted messages, with all the implications
|
||||
of that.
|
||||
|
||||
Notable shortcomings:
|
||||
|
||||
- This API was not designed with ES6 modules in mind. Neither Firefox
|
||||
nor Safari support, as of March 2023, the {type:"module"} flag to the
|
||||
Worker constructor, so that particular usage is not something we're going
|
||||
to target for the time being:
|
||||
|
||||
https://developer.mozilla.org/en-US/docs/Web/API/Worker/Worker
|
||||
*/
|
||||
globalThis.sqlite3Worker1Promiser = function callee(config = callee.defaultConfig){
|
||||
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;
|
||||
@@ -160,7 +146,6 @@ globalThis.sqlite3Worker1Promiser = function callee(config = callee.defaultConfi
|
||||
if(!config.worker) config.worker = callee.defaultConfig.worker;
|
||||
if('function'===typeof config.worker) config.worker = config.worker();
|
||||
let dbId;
|
||||
let promiserFunc;
|
||||
config.worker.onmessage = function(ev){
|
||||
ev = ev.data;
|
||||
debug('worker1.onmessage',ev);
|
||||
@@ -168,14 +153,14 @@ globalThis.sqlite3Worker1Promiser = function callee(config = callee.defaultConfi
|
||||
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(promiserFunc);
|
||||
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;
|
||||
@@ -197,19 +182,19 @@ globalThis.sqlite3Worker1Promiser = function callee(config = callee.defaultConfi
|
||||
try {msgHandler.resolve(ev)}
|
||||
catch(e){msgHandler.reject(e)}
|
||||
}/*worker.onmessage()*/;
|
||||
return promiserFunc = function(/*(msgType, msgArgs) || (msgEnvelope)*/){
|
||||
return function(/*(msgType, msgArgs) || (msgEnvelope)*/){
|
||||
let msg;
|
||||
if(1===arguments.length){
|
||||
msg = arguments[0];
|
||||
}else if(2===arguments.length){
|
||||
msg = Object.create(null);
|
||||
msg.type = arguments[0];
|
||||
msg.args = arguments[1];
|
||||
msg.dbId = msg.args.dbId;
|
||||
msg = {
|
||||
type: arguments[0],
|
||||
args: arguments[1]
|
||||
};
|
||||
}else{
|
||||
toss("Invalid arguments for sqlite3Worker1Promiser()-created factory.");
|
||||
toss("Invalid arugments for sqlite3Worker1Promiser()-created factory.");
|
||||
}
|
||||
if(!msg.dbId && msg.type!=='open') msg.dbId = dbId;
|
||||
if(!msg.dbId) msg.dbId = dbId;
|
||||
msg.messageId = genMsgId(msg);
|
||||
msg.departureTime = performance.now();
|
||||
const proxy = Object.create(null);
|
||||
@@ -251,13 +236,10 @@ globalThis.sqlite3Worker1Promiser = function callee(config = callee.defaultConfi
|
||||
return p;
|
||||
};
|
||||
}/*sqlite3Worker1Promiser()*/;
|
||||
|
||||
globalThis.sqlite3Worker1Promiser.defaultConfig = {
|
||||
self.sqlite3Worker1Promiser.defaultConfig = {
|
||||
worker: function(){
|
||||
//#if target=es6-module
|
||||
return new Worker(new URL("sqlite3-worker1-bundler-friendly.mjs", import.meta.url),{
|
||||
type: 'module'
|
||||
});
|
||||
//#if target=es6-bundler-friendly
|
||||
return new Worker("sqlite3-worker1.js");
|
||||
//#else
|
||||
let theJs = "sqlite3-worker1.js";
|
||||
if(this.currentScript){
|
||||
@@ -265,82 +247,17 @@ globalThis.sqlite3Worker1Promiser.defaultConfig = {
|
||||
src.pop();
|
||||
theJs = src.join('/')+'/' + theJs;
|
||||
//sqlite3.config.warn("promiser currentScript, theJs =",this.currentScript,theJs);
|
||||
}else if(globalThis.location){
|
||||
//sqlite3.config.warn("promiser globalThis.location =",globalThis.location);
|
||||
const urlParams = new URL(globalThis.location.href).searchParams;
|
||||
}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 + globalThis.location.search);
|
||||
return new Worker(theJs + self.location.search);
|
||||
//#endif
|
||||
}
|
||||
//#ifnot target=es6-module
|
||||
.bind({
|
||||
currentScript: globalThis?.document?.currentScript
|
||||
})
|
||||
//#endif
|
||||
,
|
||||
}.bind({
|
||||
currentScript: self?.document?.currentScript
|
||||
}),
|
||||
onerror: (...args)=>console.error('worker1 promiser error',...args)
|
||||
}/*defaultConfig*/;
|
||||
|
||||
/**
|
||||
sqlite3Worker1Promiser.v2(), added in 3.46, works identically to
|
||||
sqlite3Worker1Promiser() except that it returns a Promise instead
|
||||
of relying an an onready callback in the config object. The Promise
|
||||
resolves to the same factory function which
|
||||
sqlite3Worker1Promiser() returns.
|
||||
|
||||
If config is-a function or is an object which contains an onready
|
||||
function, that function is replaced by a proxy which will resolve
|
||||
after calling the original function and will reject if that
|
||||
function throws.
|
||||
*/
|
||||
sqlite3Worker1Promiser.v2 = function(config){
|
||||
let oldFunc;
|
||||
if( 'function' == typeof config ){
|
||||
oldFunc = config;
|
||||
config = {};
|
||||
}else if('function'===typeof config?.onready){
|
||||
oldFunc = config.onready;
|
||||
delete config.onready;
|
||||
}
|
||||
const promiseProxy = Object.create(null);
|
||||
config = Object.assign((config || Object.create(null)),{
|
||||
onready: async function(func){
|
||||
try {
|
||||
if( oldFunc ) await oldFunc(func);
|
||||
promiseProxy.resolve(func);
|
||||
}
|
||||
catch(e){promiseProxy.reject(e)}
|
||||
}
|
||||
});
|
||||
const p = new Promise(function(resolve,reject){
|
||||
promiseProxy.resolve = resolve;
|
||||
promiseProxy.reject = reject;
|
||||
});
|
||||
try{
|
||||
this.original(config);
|
||||
}catch(e){
|
||||
promiseProxy.reject(e);
|
||||
}
|
||||
return p;
|
||||
}.bind({
|
||||
/* We do this because clients are
|
||||
recommended to delete globalThis.sqlite3Worker1Promiser. */
|
||||
original: sqlite3Worker1Promiser
|
||||
});
|
||||
|
||||
//#if target=es6-module
|
||||
/**
|
||||
When built as a module, we export sqlite3Worker1Promiser.v2()
|
||||
instead of sqlite3Worker1Promise() because (A) its interface is more
|
||||
conventional for ESM usage and (B) the ESM export option for this
|
||||
API did not exist until v2 was created, so there's no backwards
|
||||
incompatibility.
|
||||
*/
|
||||
export default sqlite3Worker1Promiser.v2;
|
||||
//#endif /* target=es6-module */
|
||||
//#else
|
||||
/* Built with the omit-oo1 flag. */
|
||||
//#endif ifnot omit-oo1
|
||||
};
|
||||
|
||||
@@ -115,7 +115,6 @@ delete globalThis.sqlite3Worker1Promiser;
|
||||
"insert into t(a,b) values(1,2),(3,4),(5,6)"
|
||||
].join(';'),
|
||||
resultRows: [], columnNames: [],
|
||||
lastInsertRowId: true,
|
||||
countChanges: sqConfig.bigIntEnabled ? 64 : true
|
||||
}, function(ev){
|
||||
ev = ev.result;
|
||||
@@ -123,9 +122,7 @@ delete globalThis.sqlite3Worker1Promiser;
|
||||
.assert(0===ev.columnNames.length)
|
||||
.assert(sqConfig.bigIntEnabled
|
||||
? (3n===ev.changeCount)
|
||||
: (3===ev.changeCount))
|
||||
.assert('bigint'===typeof ev.lastInsertRowId)
|
||||
.assert(ev.lastInsertRowId>=3);
|
||||
: (3===ev.changeCount));
|
||||
});
|
||||
|
||||
await wtest('exec',{
|
||||
|
||||
@@ -5,10 +5,11 @@
|
||||
<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 toggleable terminal-style view, uncomment the following
|
||||
<!-- 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 {
|
||||
@@ -170,31 +171,6 @@
|
||||
display: flex;
|
||||
flex-direction: column-reverse;
|
||||
}
|
||||
|
||||
/* emcscript-related styling, used during the module load/intialization processes... */
|
||||
.emscripten { padding-right: 0; margin-left: auto; margin-right: auto; display: block; }
|
||||
div.emscripten { text-align: center; }
|
||||
div.emscripten_border { border: 1px solid black; }
|
||||
#module-spinner { overflow: visible; }
|
||||
#module-spinner > * {
|
||||
margin-top: 1em;
|
||||
}
|
||||
.spinner {
|
||||
height: 50px;
|
||||
width: 50px;
|
||||
margin: 0px auto;
|
||||
animation: rotation 0.8s linear infinite;
|
||||
border-left: 10px solid rgb(0,150,240);
|
||||
border-right: 10px solid rgb(0,150,240);
|
||||
border-bottom: 10px solid rgb(0,150,240);
|
||||
border-top: 10px solid rgb(100,0,200);
|
||||
border-radius: 100%;
|
||||
background-color: rgb(200,100,250);
|
||||
}
|
||||
@keyframes rotation {
|
||||
from {transform: rotate(0deg);}
|
||||
to {transform: rotate(360deg);}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
@@ -297,6 +273,11 @@
|
||||
</fieldset>
|
||||
</div>
|
||||
</div> <!-- #view-split -->
|
||||
<!-- Maintenance notes:
|
||||
|
||||
... TODO... currently being refactored...
|
||||
|
||||
-->
|
||||
<script src="fiddle.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -725,6 +725,7 @@ TESTSRC = \
|
||||
$(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 \
|
||||
@@ -792,6 +793,8 @@ TESTSRC2 = \
|
||||
$(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 \
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
C Internal\sconfigure\sscript\scleanups.\sResolve\san\sas-yet-hypothetical\scorner\scase\sinvolving\sthe\s--dev\sflag\smixed\swith\scustom\sCFLAGS\scontaining\sSQLITE_ENABLE...\sor\sSQLITE_OMIT...\sflags.\sFix\san\sunrelated\sAPI\sdoc\stypo\sreported\sin\s[forum:606ea661df|forum\spost\s606ea661df].
|
||||
D 2025-03-03T14:15:13.905
|
||||
C Improvement\soutput\sfor\s".schema\s--indent"\sin\sthe\sCLI\swhen\sthe\sschema\scontains\npartial\sindexes\swith\slong\sand\scomplicated\sWHERE\sclauses.
|
||||
D 2025-03-05T16:30:36.389
|
||||
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
|
||||
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
|
||||
F LICENSE.md e108e1e69ae8e8a59e93c455654b8ac9356a11720d3345df2a4743e9590fb20d
|
||||
F Makefile.in 4ff9b301b59c66ef9d11c8d133cc62e09173bad4abc7d5eb801e45d5527f8fe6
|
||||
F Makefile.linux-generic bd3e3cacd369821a6241d4ea1967395c962dfe3057e38cb0a435cee0e8b789d0
|
||||
F Makefile.msc ef04498c7e227a0f459b105bb4952f26cc985d1d6340a367e62d5a79c4689dfb
|
||||
F Makefile.msc 40a852813c2c84efd579f34b881f9169020284ac80d3d56463b88158e2f1c00e
|
||||
F README.md a953c0cffd6e4f2501a306c00ee2b6e1e6630c25031e094629307fe99dd003d1
|
||||
F VERSION 001dea55eb8304ec9130b6b44a32d3fc349f279d45a7e224fc0730c3cb8e2372
|
||||
F art/icon-243x273.gif 9750b734f82fdb3dc43127753d5e6fbf3b62c9f4e136c2fbf573b2f57ea87af5
|
||||
@@ -59,8 +59,9 @@ F doc/compile-for-unix.md c9dce1ddd4bf0d25efccc5c63eb047e78c01ce06a6ff29c73e0a8a
|
||||
F doc/compile-for-windows.md 5141661e783c9ca9e3fd30e813345898712f5c311d71316f183db87038fa28a6
|
||||
F doc/json-enhancements.md e356fc834781f1f1aa22ee300027a270b2c960122468499bf347bb123ce1ea4f
|
||||
F doc/jsonb.md ede3238186e3a90bb79d20b2a6a06d0f9429a38e069e9da0efbad0f2ed48b924
|
||||
F doc/lemon.html 7504a6dc9b56dd376a046833ea9cc8b08def93f19bfad6eab9f1a365a4b5f49a
|
||||
F doc/lemon.html 6aa6b6a75890bc71a6ad2b94e0723c273818b8b5e43b591eb483a6db0838441f
|
||||
F doc/pager-invariants.txt 83aa3a4724b2d7970cc3f3461f0295c46d4fc19a835a5781cbb35cb52feb0577
|
||||
F doc/shared_schema.md 759fc374709fccf4e5d2d0cbd05f8fedd38fb022bdd8a6c5b5f492684c7023b9
|
||||
F doc/tcl-extension-testing.md 864875c3b672db79e7d42348dd726f9a4fbd852b1d8e5efcf09fe3d1ff6bf2a2
|
||||
F doc/testrunner.md 15583cf8c7d8a1c3378fd5d4319ca769a14c4d950a5df9b015d01d5be290dc69
|
||||
F doc/trusted-schema.md 33625008620e879c7bcfbbfa079587612c434fa094d338b08242288d358c3e8a
|
||||
@@ -618,7 +619,7 @@ F ext/session/sessionwor.test 6fd9a2256442cebde5b2284936ae9e0d54bde692d0f5fd009e
|
||||
F ext/session/sqlite3session.c 8011b9531c7dd8dce55226def022f3303ce40d0b45966877f2c35185f4b1c3fc
|
||||
F ext/session/sqlite3session.h aa5de3ec8ef0e5313e9f65dafd69e8ba292d170f07b57da9200c040068dab061
|
||||
F ext/session/test_session.c 12e0a2c15fd60f92da4bb29c697c9177ff0c0dbcdc5129a54c47e999f147937a
|
||||
F ext/wasm/EXPORTED_FUNCTIONS.fiddle.in 27450c8b8c70875a260aca55435ec927068b34cef801a96205adb81bdcefc65c
|
||||
F ext/wasm/EXPORTED_FUNCTIONS.fiddle 7fb73f7150ab79d83bb45a67d257553c905c78cd3d693101699243f36c5ae6c3
|
||||
F ext/wasm/GNUmakefile 24d7e6f446528fa67f5ade6c3c7d7e46e1ac52649d6264cbe24539c1dab608e1
|
||||
F ext/wasm/README-dist.txt f01081a850ce38a56706af6b481e3a7878e24e42b314cfcd4b129f0f8427066a
|
||||
F ext/wasm/README.md b89605f65661cf35bf034ff6d43e448cc169b8017fc105d498e33b81218b482c
|
||||
@@ -627,7 +628,7 @@ F ext/wasm/SQLTester/SQLTester.mjs 66e1adc3d79467b68e3e40614fd42c1a577c7e219ec09
|
||||
F ext/wasm/SQLTester/SQLTester.run.mjs 57f2adb33f43f2784abbf8026c1bfd049d8013af1998e7dcb8b50c89ffc332e0
|
||||
F ext/wasm/SQLTester/index.html 64f3435084c7d6139b08d1f2a713828a73f68de2ae6a3112cbb5980d991ba06f
|
||||
F ext/wasm/SQLTester/touint8array.c 2d5ece04ec1393a6a60c4bf96385bda5e1a10ad49f3038b96460fc5e5aa7e536
|
||||
F ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-core 2bcbbfe3b95c043ed6037e2708a2ee078d212dd1612c364f93588d8dc97300fe
|
||||
F ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-api c5eaceabb9e759aaae7d3101a4a3e542f96ab2c99d89a80ce20ec18c23115f33
|
||||
F ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-extras fe40d6d758646e38f8b15f709044951e10884214f5453d35502100179c388c13
|
||||
F ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-see fb29e62082a658f0d81102488414d422c393c4b20cc2f685b216bc566237957b
|
||||
F ext/wasm/api/EXPORTED_RUNTIME_METHODS.sqlite3-api 1ec3c73e7d66e95529c3c64ac3de2470b0e9e7fbf7a5b41261c367cf4f1b7287
|
||||
@@ -649,7 +650,7 @@ F ext/wasm/api/sqlite3-vfs-opfs-sahpool.c-pp.js 16d80af915bfd2529824b999b3044255
|
||||
F ext/wasm/api/sqlite3-vfs-opfs.c-pp.js 4ab0704ee198de7d1059eccedc7703c931510b588d10af0ee36ea5b3ebbac284
|
||||
F ext/wasm/api/sqlite3-vtab-helper.c-pp.js e809739d71e8b35dfe1b55d24d91f02d04239e6aef7ca1ea92a15a29e704f616
|
||||
F ext/wasm/api/sqlite3-wasm.c 6a4cd40267eaf08400895c5b9de39c56976c3b97b3c1bbe53fc2e80fa074e9c7
|
||||
F ext/wasm/api/sqlite3-worker1-promiser.c-pp.js bc65debfe43b81fc39fb25c40ad0cc1946bd82580fbf644351107b544d6177ee
|
||||
F ext/wasm/api/sqlite3-worker1-promiser.c-pp.js c5ac33e39f21a3481812d7333ca6e18853640d423a01960ca8dbc6e7c5c3c21c
|
||||
F ext/wasm/api/sqlite3-worker1.c-pp.js 5e8706c2c4af2a57fbcdc02f4e7ef79869971bc21bb8ede777687786ce1c92d5
|
||||
F ext/wasm/batch-runner-sahpool.html e9a38fdeb36a13eac7b50241dfe7ae066fe3f51f5c0b0151e7baee5fce0d07a7
|
||||
F ext/wasm/batch-runner-sahpool.js 54a3ac228e6c4703fe72fb65c897e19156263a51fe9b7e21d2834a45e876aabd
|
||||
@@ -667,15 +668,15 @@ F ext/wasm/demo-123.js c7b3cca50c55841c381a9ca4f9396e5bbdc6114273d0b10a43e378e32
|
||||
F ext/wasm/demo-jsstorage.html 409c4be4af5f207fb2877160724b91b33ea36a3cd8c204e8da1acb828ffe588e
|
||||
F ext/wasm/demo-jsstorage.js 42131ddfa18e817d0e39ac63745e9ea31553980a5ebd2222e04d4fac60c19837
|
||||
F ext/wasm/demo-worker1-promiser.c-pp.html 635cf90685805e21772a5f7a35d1ace80f98a9ef7c42ff04d7a125ddca7e5db8
|
||||
F ext/wasm/demo-worker1-promiser.c-pp.js af168699d3cab1c27ad2364ebe06cd49db300bdbf404e23b00d5742ed52816ba
|
||||
F ext/wasm/demo-worker1-promiser.c-pp.js fcc628cb42fcfaf07d250477801de1e6deb1e319d003976612a0db8d76b9fccc
|
||||
F ext/wasm/demo-worker1.html 2c178c1890a2beb5a5fecb1453e796d067a4b8d3d2a04d65ca2eb1ab2c68ef5d
|
||||
F ext/wasm/demo-worker1.js 08720227e98fa5b44761cf6e219269cee3e9dd0421d8d91459535da776950314
|
||||
F ext/wasm/dist.make 92ef4ffe33022a50f92d602acabad10bd8dd91759f3eb7df27fc6d7d37072b96
|
||||
F ext/wasm/example_extra_init.c 2347cd69d19d839ef4e5e77b7855103a7fe3ef2af86f2e8c95839afd8b05862f
|
||||
F ext/wasm/fiddle.make c6d7a3d6cc03bb5f21acb295c1233820d0dbf5c6a89b28dc2e093edcc001c45a
|
||||
F ext/wasm/fiddle/fiddle-worker.js 850e66fce39b89d59e161d1abac43a181a4caa89ddeea162765d660277cd84ce
|
||||
F ext/wasm/fiddle/fiddle.html 550c5aafce40bd218de9bf26192749f69f9b10bc379423ecd2e162bcef885c08
|
||||
F ext/wasm/fiddle/fiddle.js 2a2f27b4be2674f501fff61c4a09e44dcf2295731a26b5c28e439f3a573bd269
|
||||
F ext/wasm/fiddle/index.html 7fcfb221165183bef0e05d5af9ceb79b527e799b1708ab05de0ec0eaebd5b7bf
|
||||
F ext/wasm/index-dist.html 56132399702b15d70c474c3f1952541e25cb0922942868f70daf188f024b3730
|
||||
F ext/wasm/index.html bcaa00eca521b372a6a62c7e7b17a870b0fcdf3e418a5921df1fd61e5344080d
|
||||
F ext/wasm/jaccwabyt/jaccwabyt.js 6e4f26d0edb5c2e7d381b7eff1924832a040a12274afab2d1e1789027e9f6c5c
|
||||
@@ -705,7 +706,7 @@ F ext/wasm/tests/opfs/sahpool/sahpool-pausing.js f264925cfc82155de38cecb3d204c36
|
||||
F ext/wasm/tests/opfs/sahpool/sahpool-worker.js bd25a43fc2ab2d1bafd8f2854ad3943ef673f7c3be03e95ecf1612ff6e8e2a61
|
||||
F ext/wasm/wasmfs.make 68999f5bd8c489239592d59a420f8c627c99169bbd6fa16a404751f757b9f702
|
||||
F magic.txt 5ade0bc977aa135e79e3faaea894d5671b26107cc91e70783aa7dc83f22f3ba0
|
||||
F main.mk 8a75d3cc70549d2a876eab2666eb82832335a3539822359d612b56e355fdf344
|
||||
F main.mk 178381be0b2cdcb14f49af1e0b0b679b6626089df9da097563333a265c67db32
|
||||
F mptest/config01.test 3c6adcbc50b991866855f1977ff172eb6d901271
|
||||
F mptest/config02.test 4415dfe36c48785f751e16e32c20b077c28ae504
|
||||
F mptest/crash01.test 61e61469e257df0850df4293d7d4d6c2af301421
|
||||
@@ -715,9 +716,9 @@ F mptest/multiwrite01.test dab5c5f8f9534971efce679152c5146da265222d
|
||||
F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b
|
||||
F sqlite3.1 acdff36db796e2d00225b911d3047d580cd136547298435426ce9d40347973cc
|
||||
F sqlite3.pc.in 0977c03a4da7c4204bd60e784a0efb8d51a190448aba78a4e973fe7192bdaf03
|
||||
F src/alter.c 0d2122ade76617b7cca383428d0881a9821ef8ddaf9cce6ff91d69a215614b95
|
||||
F src/analyze.c 13895d4da6ac857d95d3291dc607d492eba3ea1cbc3bc04baaa0383fbc1bb3d4
|
||||
F src/attach.c 9af61b63b10ee702b1594ecd24fb8cea0839cfdb6addee52fba26fa879f5db9d
|
||||
F src/alter.c 4b855e10b66524fe39f3cc0fc19500593e0a0d7e9c77c17a5a8ad689356230e4
|
||||
F src/analyze.c b8662a13798064f01eef20d3f59e83f9f5b1860de131b526aec298180601f2de
|
||||
F src/attach.c 82a709d96b7043d9c9c52589e77ee5420415809d765405b0cc2f35894dd3fb13
|
||||
F src/auth.c 54ab9c6c5803b47c0d45b76ce27eff22a03b4b1f767c5945a3a4eb13aa4c78dc
|
||||
F src/backup.c 5c97e8023aab1ce14a42387eb3ae00ba5a0644569e3476f38661fa6f824c3523
|
||||
F src/bitvec.c 782cc29b42b47e7ec6348eb0aaf9ffe60063f498387e7249f458d445af4b53e9
|
||||
@@ -725,8 +726,8 @@ F src/btmutex.c 30dada73a819a1ef5b7583786370dce1842e12e1ad941e4d05ac29695528daea
|
||||
F src/btree.c 00fcee37947641f48d4b529d96143e74d056b7afa8f26d61292c90ee59c056b2
|
||||
F src/btree.h 18e5e7b2124c23426a283523e5f31a4bff029131b795bb82391f9d2f3136fc50
|
||||
F src/btreeInt.h 9c0f9ea5c9b5f4dcaea18111d43efe95f2ac276cd86d770dce10fd99ccc93886
|
||||
F src/build.c 20793695ef64d2d0c147501e37f344f828f09f16d346a987b516316186030996
|
||||
F src/callback.c acae8c8dddda41ee85cfdf19b926eefe830f371069f8aadca3aa39adf5b1c859
|
||||
F src/build.c 259abd6d09b8692553bfa7670ff807091af1219d44d3ee467e283b99656878e0
|
||||
F src/callback.c dd68d54c81989e9ba846464ffc5cc122ac83fe6686fabc6cf38d9e0f480c6879
|
||||
F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e
|
||||
F src/date.c 9db4d604e699a73e10b8e85a44db074a1f04c0591a77e2abfd77703f50dce1e9
|
||||
F src/dbpage.c 2e677acb658a29965e55398bbc61161cb7819da538057c8032adac7ab8e4a8c0
|
||||
@@ -745,7 +746,7 @@ F src/insert.c a5f0366266be993ebf533808f22cb7a788624805b55bc45424ceed3f48c54a16
|
||||
F src/json.c 81e2012796a0e139b18c50ee3444c8ef86a020ab360511882216f5b610657e0c
|
||||
F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa
|
||||
F src/loadext.c 7432c944ff197046d67a1207790a1b13eec4548c85a9457eb0896bb3641dfb36
|
||||
F src/main.c 5102588cbe7668d5ee19fd9945546e4f1fd99e41815432decf5dd29f01f55597
|
||||
F src/main.c 65ffb80350bf390245de6222bade5fcc69a4a93b8b70b880ec68b7776dd21ca0
|
||||
F src/malloc.c 410e570b30c26cc36e3372577df50f7a96ee3eed5b2b161c6b6b48773c650c5e
|
||||
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
|
||||
F src/mem1.c 3bb59158c38e05f6270e761a9f435bf19827a264c13d1631c58b84bdc96d73b2
|
||||
@@ -767,30 +768,30 @@ F src/os_common.h 6c0eb8dd40ef3e12fe585a13e709710267a258e2c8dd1c40b1948a1d14582e
|
||||
F src/os_kv.c 4d39e1f1c180b11162c6dc4aa8ad34053873a639bac6baae23272fc03349986a
|
||||
F src/os_setup.h 6011ad7af5db4e05155f385eb3a9b4470688de6f65d6166b8956e58a3d872107
|
||||
F src/os_unix.c 410185df4900817c218c0efdb8064b3481af88cb3f7cea7392f820b6eebc7889
|
||||
F src/os_win.c ab9912a2c1cb39a6429b8de919a5b63ad1c7775e511d748391c57bf9ad03bd29
|
||||
F src/os_win.c 18a345cad65013f625bc8e1d7efdea40e7be5462c7bc38e84ca5fa8b125cef5d
|
||||
F src/os_win.h 7b073010f1451abe501be30d12f6bc599824944a
|
||||
F src/pager.c 9fbb541b46125dfa8914827575e6bb4d15048caa008073b1709112d495d7983b
|
||||
F src/pager.c 9a40b9f6b1a4530905ac78914baba69e34f4f80ce86f53b010192df644adedc2
|
||||
F src/pager.h 6137149346e6c8a3ddc1eeb40aee46381e9bc8b0fcc6dda8a1efde993c2275b8
|
||||
F src/parse.y e426d7323311554c75b0aebc426d0fe3c88d9777ffefed236f343ad9e661dc4c
|
||||
F src/pcache.c 588cc3c5ccaaadde689ed35ce5c5c891a1f7b1f4d1f56f6cf0143b74d8ee6484
|
||||
F src/pcache.h 1497ce1b823cf00094bb0cf3bac37b345937e6f910890c626b16512316d3abf5
|
||||
F src/pcache1.c 78d4935e510f7bed0fdd1a3f742c0e663b36a795f9dc7411161dc22bdae1245e
|
||||
F src/pragma.c 30b535d0a66348df844ee36f890617b4cf45e9a22dcbc47ec3ca92909c50aaf1
|
||||
F src/prepare.c 1832be043fce7d489959aae6f994c452d023914714c4d5457beaed51c0f3d126
|
||||
F src/pragma.c 22c184ba97a2d5880aae074edbcf3f862a0198b9d8f5ef1ee7ee96d883858f88
|
||||
F src/prepare.c 64fb8aaf3c0ad0a5a12472bd7f5ec8d2e569f186c555e6ad4bf962d751e30325
|
||||
F src/printf.c 33fc0d7643c848a098afdcb6e1db6de12379d47084b1cd0912cfce1d09345e44
|
||||
F src/random.c 606b00941a1d7dd09c381d3279a058d771f406c5213c9932bbd93d5587be4b9c
|
||||
F src/resolve.c 626c24b258b111f75c22107aa5614ad89810df3026f5ca071116d3fe75925c75
|
||||
F src/rowset.c 8432130e6c344b3401a8874c3cb49fefe6873fec593294de077afea2dce5ec97
|
||||
F src/select.c a076f7db3a0fcbd9f710d7746cfc07e0b3baadee45eb3136bedc29c598ef8f1c
|
||||
F src/shell.c.in 6bb2abfb5cbeb5b017b8d0e94e39dd1efd101b22aca07a6734b155b6d4d03f62
|
||||
F src/sqlite.h.in 3db05f6603c78d9e6fe035e9e12bed4ca8140135d05ff092becc2cf7d7d1fefb
|
||||
F src/shell.c.in 5366b2a071d41784ce9bc87891c0d04cb469b122cdb632bafca3fad8d26a0b80
|
||||
F src/sqlite.h.in 7c58f9f9f7ed6d30d0783162f7d9f12ede11e833bac77b176aaa28aeca77bb12
|
||||
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
|
||||
F src/sqlite3ext.h 3f046c04ea3595d6bfda99b781926b17e672fd6d27da2ba6d8d8fc39981dcb54
|
||||
F src/sqliteInt.h 130217107c0425ab43d098c6eadf8aa2e1a037e26d79384127e2d950b27eec77
|
||||
F src/sqliteInt.h b6c47ecbe197adb620ce3d43415ff2d2519e53a5d634ec9c055ee193df72776c
|
||||
F src/sqliteLimit.h 6d817c28a8f19af95e6f4921933b7fbbca48a962bce0eb0ec81e8bb3ef38e68b
|
||||
F src/status.c 0e72e4f6be6ccfde2488eb63210297e75f569f3ce9920f6c3d77590ec6ce5ffd
|
||||
F src/status.c 9adeef15f9b2bd4a72ccd22b1f29e34dea6ca898baf420016332ba7e63f55539
|
||||
F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1
|
||||
F src/tclsqlite.c 5c1e367e26711044730c93d4b81312170918a8d1fe811f45be740ab48f7de8c1
|
||||
F src/tclsqlite.c 09d33ad9a35929f997d7152e9aa1d4d62757ce6e73d237dbe33f11261e4778ae
|
||||
F src/tclsqlite.h 65e2c761446e1c9fa0342b7d2612a703483643c8b6a316d12a65b745a4727395
|
||||
F src/test1.c ba7b93478a6a7a3f48ec5507f28bc662636ac5d9f9791700d3648a8e788f0bb2
|
||||
F src/test2.c 7ebc518e6735939d8979273a6f7b1d9b5702babf059f6ad62499f7f60a9eb9a3
|
||||
@@ -805,7 +806,7 @@ F src/test_backup.c bd901e3c116c7f3b3bbbd4aae4ce87d99b400c9cbb0a9e7b4610af451d97
|
||||
F src/test_bestindex.c 3401bee51665cbf7f9ed2552b5795452a8b86365e4c9ece745b54155a55670c6
|
||||
F src/test_blob.c bcdf6a6c22d0bcc13c41479d63692ef413add2a4d30e1e26b9f74ab85b9fb4d5
|
||||
F src/test_btree.c 28283787d32b8fa953eb77412ad0de2c9895260e4e5bd5a94b3c7411664f90d5
|
||||
F src/test_config.c 7f412406592794636d6226268e26d413850a9f799bc5f3c01afc2820b165fca8
|
||||
F src/test_config.c 8b48024b0f240f1824ba801b72048c9a6344109292ee33a8eb7339d1a3689956
|
||||
F src/test_delete.c e2fe07646dff6300b48d49b2fee2fe192ed389e834dd635e3b3bac0ce0bf9f8f
|
||||
F src/test_demovfs.c 3efa2adf4f21e10d95521721687d5ca047aea91fa62dd8cc22ac9e5a9c942383
|
||||
F src/test_devsym.c 649434ed34d0b03fbd5a6b42df80f0f9a7e53f94dd1710aad5dd8831e91c4e86
|
||||
@@ -829,10 +830,11 @@ F src/test_quota.c 744552848d9c5c5de3920d1c44b03d425a4123a223310567a199c7e0d3fe8
|
||||
F src/test_quota.h 2a8ad1952d1d2ca9af0ce0465e56e6c023b5e15d
|
||||
F src/test_rtree.c d844d746a3cc027247318b970025a927f14772339c991f40e7911583ea5ed0d9
|
||||
F src/test_schema.c b06d3ddc3edc173c143878f3edb869dd200d57d918ae2f38820534f9a5e3d7d9
|
||||
F src/test_schemapool.c fc6c14f7a20fcf4fb76e56c7ce3a3bc7056e105efeb11a6476172d5d576b920d
|
||||
F src/test_sqllog.c 540feaea7280cd5f926168aee9deb1065ae136d0bbbe7361e2ef3541783e187a
|
||||
F src/test_superlock.c 18355ca274746aa6909e3744163e5deb1196a85d5bc64b9cd377273cef626da7
|
||||
F src/test_syscall.c 9ad7ab39910c16d29411678d91b0d27a7a996a718df5ee93dcd635e846d0275c
|
||||
F src/test_tclsh.c c01706ac60bd3176754d3ccd37da74c6ad97c2e14489f8ed71b497c1c0ac0dd4
|
||||
F src/test_tclsh.c b2f529c87674301eb7ce168c6dd2d0a9030a0c75a0d88d85bcb0677195114249
|
||||
F src/test_tclvar.c ae873248a0188459b1c16ca7cc431265dacce524399e8b46725c2b3b7e048424
|
||||
F src/test_thread.c d7a8bcea7445f37cc2a1f7f81dd6059634f45e0c61bfe80182b02872fb0328bb
|
||||
F src/test_vdbecov.c 5c426d9cd2b351f5f9ceb30cabf8c64a63bfcad644c507e0bd9ce2f6ae1a3bf3
|
||||
@@ -844,28 +846,28 @@ F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
|
||||
F src/threads.c 4ae07fa022a3dc7c5beb373cf744a85d3c5c6c3c
|
||||
F src/tokenize.c 375a772e2342274f4bf73605a70633237da09deed00a9bf4c4816a56777ea7c9
|
||||
F src/treeview.c d85ce76e6d1498d781957c07cb234da6d77ce0ed2d196480d516f54dabc62279
|
||||
F src/trigger.c da3c25786870d8bf97cd46b493374c2375d1abaf20a9b0f5f8629a3f2f2ce383
|
||||
F src/trigger.c 24e5859e35eb5214ccea0da6924f0f90d41095091b0fc7247b6803e7d9a700f1
|
||||
F src/update.c 3e5e7ff66fa19ebe4d1b113d480639a24cc1175adbefabbd1a948a07f28e37cf
|
||||
F src/upsert.c 215328c3f91623c520ec8672c44323553f12caeb4f01b1090ebdca99fdf7b4f1
|
||||
F src/utf.c d4d55ca95106a2029ec1cdbd2497a34e69ea1d338f1a9d80ef15ebf4ff01690d
|
||||
F src/util.c 36fb1150062957280777655976f3f9a75db236cb8207a0770ceae8d5ec17fcd3
|
||||
F src/vacuum.c b763b6457bd058d2072ef9364832351fd8d11e8abf70cbb349657360f7d55c40
|
||||
F src/vdbe.c e7567bed441a53c4ceb48d2bdf3d1747677fc296a91e8d2a0fe8facdb9b890ce
|
||||
F src/vdbe.h 3d26d5c7660c5c7bd33ffb0d8784615072d8b23c81f8110870efe2631136bc89
|
||||
F src/vacuum.c 38577d6f45e10a984720b5219be09ca8649a0e600c2e5c11993900446caca609
|
||||
F src/vdbe.c dac8b4bf8e0a2451690aeb3a8384202e6498c8ec45477be0d0440b23fb52bce2
|
||||
F src/vdbe.h e56df3f84b08dfb60120796591af7d36fba8513a7df2605425189253f5a76d5f
|
||||
F src/vdbeInt.h 078b1c15b26587b54c1c1879d0d2f4dec812b9de4c337fed9faf73fbcc3bf091
|
||||
F src/vdbeapi.c cb8eb9e41a16f5fa3ce5b8f3910edfbba336d10156cfb7a79f92cf7bf443977b
|
||||
F src/vdbeaux.c d7ef1a0a7233589d789eda1ba9ffa4b0ea61fca9651e4f47fb4250d03d62bcaf
|
||||
F src/vdbeblob.c 9166b6eb7054e5da82e35255892fb1ed551355a4716452539e8e3ac14f25fbe3
|
||||
F src/vdbeaux.c 57b1ec1862d5d081294e3f266a20128837f21774215134b96a883b5d3cf8a70f
|
||||
F src/vdbeblob.c e14d9eca0cce3ec4fbef69cea8cc4caefb9f8d642cc4703123a56c43dfa470d3
|
||||
F src/vdbemem.c 571ae3116dbf840a62c4aaa6bc09d577dfef8ad4d3978cf37275bb5f9653217b
|
||||
F src/vdbesort.c f7ce6eb4c0e8b0273329d2f43b8b6e5ebe8f2d853fc323d5787dada702ea0b66
|
||||
F src/vdbetrace.c fe0bc29ebd4e02c8bc5c1945f1d2e6be5927ec12c06d89b03ef2a4def34bf823
|
||||
F src/vdbevtab.c fc46b9cbd759dc013f0b3724549cc0d71379183c667df3a5988f7e2f1bd485f3
|
||||
F src/vtab.c 828221bdbeaaa6d62126ee6d07fd4ec0d09dcaea846f87ad01944d8b7e548859
|
||||
F src/vtab.c 0c2567d6caa2f1df28362eedcd29a2fbc9f4d7a7ff6b13086cc23f4e6ab239c5
|
||||
F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9
|
||||
F src/wal.c 2c69a5f92270429db72d853691b0640c76c671d5b2465396dadb9d9873e1efce
|
||||
F src/wal.h ba252daaa94f889f4b2c17c027e823d9be47ce39da1d3799886bbd51f0490452
|
||||
F src/walker.c d5006d6b005e4ea7302ad390957a8d41ed83faa177e412f89bc5600a7462a014
|
||||
F src/where.c 12cca5dfbe96e2589f951c43c0720fc58e52611787c37d85a0d9c10376202e8b
|
||||
F src/where.c 4ef72b4d791fb1b6725d6fbebd17e5a9487105864c7828a7b0311136c08786ce
|
||||
F src/whereInt.h d20cddddb1d61b18d5cb1fcfa9b77fbeebbc4afe44d996e603452a23b3009ee1
|
||||
F src/wherecode.c 5baa06f0daae7d38aca1d4814030b82ad4f127fe6bad18f0644776a474f6088b
|
||||
F src/whereexpr.c 2415c8eee5ff89a8b709d7d83d71c1ff986cd720d0520057e1d8a5371339012a
|
||||
@@ -1485,7 +1487,7 @@ F test/mutex1.test 42cb5e244c3a77bb0ef2b967e06fa5e7ba7d32d90a9b20bed98f6f5ede185
|
||||
F test/mutex2.test bfeaeac2e73095b2ac32285d2756e3a65e681660
|
||||
F test/nan.test 73ea63ab43668313e2f8cc9ef9e9a966672c7934f3ce76926fbe991235d07d91
|
||||
F test/nockpt.test 8c43b25af63b0bd620cf1b003529e37b6f1dc53bd22690e96a1bd73f78dde53a
|
||||
F test/nolock.test f196cf8b8fbea4e2ca345140a2b3f3b0da45c76e
|
||||
F test/nolock.test 284c72c2b752cf3ffbfd224dfa868bd524e624d3ab5c5ef181fc49ad9df0b444
|
||||
F test/normalize.test f23b6c5926c59548635fcf39678ac613e726121e073dd902a3062fbb83903b72
|
||||
F test/notify1.test 669b2b743618efdc18ca4b02f45423d5d2304abf
|
||||
F test/notify2.test 2ecabaa1305083856b7c39cf32816b612740c161
|
||||
@@ -1558,6 +1560,8 @@ F test/randexpr1.test eda062a97e60f9c38ae8d806b03b0ddf23d796df
|
||||
F test/rbu.test 168573d353cd0fd10196b87b0caa322c144ef736
|
||||
F test/rdonly.test 64e2696c322e3538df0b1ed624e21f9a23ed9ff8
|
||||
F test/readonly.test 69a7ccec846cad2e000b3539d56360d02f327061dc5e41f7f9a3e01f19719952
|
||||
F test/readonly2.test 4f4c451adf06e314c3eeed5c5e01e5df8fa10fb3cd5f537a77a48ef50ed97b84
|
||||
F test/readonlyfault.test 2b9c98ed3ac47e3f3cb00db3850b4d7fc7c857be1502a7b74985fecf50837b1e
|
||||
F test/recover.test a163a156ea9f2beea63fa83c4dcd8dea6e57b8a569fc647155e3d2754eaac1b5
|
||||
F test/regexp1.test 8f2a8bc1569666e29a4cee6c1a666cd224eb6d50e2470d1dc1df995170f3e0f1
|
||||
F test/regexp2.test 55ed41da802b0e284ac7e2fe944be3948f93ff25abbca0361a609acfed1368b5
|
||||
@@ -1566,6 +1570,13 @@ F test/resetdb.test 54c06f18bc832ac6d6319e5ab23d5c8dd49fdbeec7c696d791682a8006bd
|
||||
F test/resolver01.test f4022acafda7f4d40eca94dbf16bc5fc4ac30ceb
|
||||
F test/returning1.test 212cd4111bb941a60abf608f20250db666c21eb1bc4d49217e96c87ff3ab9d1a
|
||||
F test/returningfault.test ae4c4b5e8745813287a359d9ccdb9d5c883c2e68afb18fb0767937d5de5692a4
|
||||
F test/reuse1.test b5359932592b25d2178cd1ce0cd837abb25b68aaf69c4812eb83efa490c2dd19
|
||||
F test/reuse2.test 4012db85142e2abe3d8a1186756a71ea6e7078091f7448ac2145ca7b8c18cc51
|
||||
F test/reuse3.test 890074bbfc31f71762d583ee23a22c647870b2c2e91eb1eb60c2b5a5d3d8986b
|
||||
F test/reuse4.test bf36ee3848534f64234f84389fe8f2289da353cc0535cfe62b9287e32786f755
|
||||
F test/reuse5.test bbe6cf7384ef90f134392edd93d626385ef0bf6f40eefc3d993535cd0861d83b
|
||||
F test/reuse6.test f4674f9967aee2a0b49c02832120b8b495291c0d87aae084c54e6c0cc18132fe
|
||||
F test/reusefault.test 545a21be1b80b8ccab02c3695137ab2bb1fc58ac78738b5bf33348a618ee3b2e
|
||||
F test/rollback.test 952c4d805bca96adc2be76f621ea22115fe40b330015af36fcc8028c8547fcee
|
||||
F test/rollback2.test 3f3a4e20401825017df7e7671e9f31b6de5fae5620c2b9b49917f52f8c160a8f
|
||||
F test/rollbackfault.test 0e646aeab8840c399cfbfa43daab46fd609cf04a
|
||||
@@ -1646,7 +1657,7 @@ F test/shell5.test 0e5f8ce08206b9998a778cfe1989e20e47839153c05af2da29198150172e2
|
||||
F test/shell6.test e3b883b61d4916b6906678a35f9d19054861123ad91b856461e0a456273bdbb8
|
||||
F test/shell7.test 43fd8e511c533bab5232e95c7b4be93b243451709e89582600d4b6e67693d5c3
|
||||
F test/shell8.test aea51ecbcd4494c746b096aeff51d841d04d5f0dc4b62eb42427f16109b87acd
|
||||
F test/shell9.test 8742a5b390cdcef6369f5aa223e415aa4255a4129ef249b177887dc635a87209
|
||||
F test/shell9.test 8030c6246e1ca474c65eb0e955324586bfbf3448289c99ca247fc7f62006ac2c
|
||||
F test/shellA.test 079c05c11947ade4ea8d51053d3abb687ec96a3dce6680d01838519b705190c5
|
||||
F test/shmlock.test 3dbf017d34ab0c60abe6a44e447d3552154bd0c87b41eaf5ceacd408dd13fda5
|
||||
F test/shortread1.test bb591ef20f0fd9ed26d0d12e80eee6d7ac8897a3
|
||||
@@ -1721,7 +1732,7 @@ F test/tabfunc01.test 7be82bd50c7ede7f01b2dd17cd1b84f352c516078222d0b067d858f081
|
||||
F test/table.test 7862a00b58b5541511a26757ea9c5c7c3f8298766e98aa099deec703d9c0a8e0
|
||||
F test/tableapi.test ecbcc29c4ab62c1912c3717c48ea5c5e59f7d64e4a91034e6148bd2b82f177f4
|
||||
F test/tableopts.test dba698ba97251017b7c80d738c198d39ab747930
|
||||
F test/tclsqlite.test ad0bbd92edabe64cc91d990a0748142fe5ab962d74ac71fa3bfa94d50d2f4c87
|
||||
F test/tclsqlite.test 350536a4233914aa437b6735e3e8e683e921a71ced8fa9fb5396057a04dbea33
|
||||
F test/tempdb.test 4cdaa23ddd8acb4d79cbb1b68ccdfd09b0537aaba909ca69a876157c2a2cbd08
|
||||
F test/tempdb2.test 353864e96fd3ae2f70773d0ffbf8b1fe48589b02c2ec05013b540879410c3440
|
||||
F test/tempfault.test 0c0d349c9a99bf5f374655742577f8712c647900
|
||||
@@ -1729,9 +1740,9 @@ F test/temptable.test d2c9b87a54147161bcd1822e30c1d1cd891e5b30
|
||||
F test/temptable2.test 76821347810ecc88203e6ef0dd6897b6036ac788e9dd3e6b04fd4d1631311a16
|
||||
F test/temptable3.test d11a0974e52b347e45ee54ef1923c91ed91e4637
|
||||
F test/temptrigger.test 38f0ca479b1822d3117069e014daabcaacefffcc
|
||||
F test/tester.tcl 2f900e8c912fbbaf381e69a92258fa6023ad0b4c8907e426bebbb4585da23c61
|
||||
F test/testrunner.tcl 0ffa67806e75aa2c186c63d7d00b16bb45adb91ed6560461fda6dbe3e18c885e x
|
||||
F test/testrunner_data.tcl 6d7e7824bb36278ea65c33f7da6dd3ca101fc7d6f7a765b807dce0aa68c52521
|
||||
F test/tester.tcl d067f95c685087f9e66efa2c4cefa5d99cd72ebeab2a7dceae89cba100ad61f7
|
||||
F test/testrunner.tcl fafc60461c165a6b53a879f090423eef7005d95f9692c7df798651b55e339fe6 x
|
||||
F test/testrunner_data.tcl 6aea1cb5865f005986037c9dad4dfe48a5281ec7aa214104e8ada3199332242b
|
||||
F test/thread001.test a0985c117eab62c0c65526e9fa5d1360dd1cac5b03bde223902763274ce21899
|
||||
F test/thread002.test c24c83408e35ba5a952a3638b7ac03ccdf1ce4409289c54a050ac4c5f1de7502
|
||||
F test/thread003.test ee4c9efc3b86a6a2767516a37bd64251272560a7
|
||||
@@ -1743,7 +1754,7 @@ F test/thread3.test a12656a56cdf67acb6a2ff7638826c6d6a645f79909d86df521045ad31cf
|
||||
F test/thread_common.tcl b3b19a769fe30ef5537cdfa60acd49b78f771301627720d1add2d3bac77d9039
|
||||
F test/threadtest1.c 6029d9c5567db28e6dc908a0c63099c3ba6c383b
|
||||
F test/threadtest2.c a70a8e94bef23339d34226eb9521015ef99f4df8
|
||||
F test/threadtest3.c 655bff6c0895ec03f014126aa65e808fac9aae8c5a7a7da58a510cbe8b43b781
|
||||
F test/threadtest3.c 25cb92accb4fa6d53e708d6006ed2db7a7533ef7b838ef1306455c6fe57e978a
|
||||
F test/threadtest4.c c1e67136ceb6c7ec8184e56ac61db28f96bd2925
|
||||
F test/threadtest5.c 9b4d782c58d8915d7e955ff8051f3d03628bda0d33b82971ea8c0f2f2808c421
|
||||
F test/time-wordcount.sh 8e0b0f8109367827ad5d58f5cc849705731e4b90
|
||||
@@ -1918,12 +1929,13 @@ F test/triggerF.test 5d76f0a8c428ff87a4d5ed52da06f6096a2c787a1e21b846111dfac4123
|
||||
F test/triggerG.test 2b816093c91ba73c733cfa8aedcc210ad819d72a98b1da30768a3c56505233e9
|
||||
F test/triggerupfrom.test d1f9e56090408115c522bee626cc33a2f3370f627a5e341d832589d72e3aa271
|
||||
F test/trustschema1.test d2996bb284859c99956ac706160eab9f086919da738d19bfef3ac431cce8fd47
|
||||
F test/tt3_checkpoint.c ac7ca661d739280c89d9c253897df64a59a49369bd1247207ac0f655b622579d
|
||||
F test/tt3_index.c 39eec10a35f57672225be4d182862152896dee4a
|
||||
F test/tt3_lookaside1.c 0377e202c3c2a50d688cb65ba203afeda6fafeb9
|
||||
F test/tt3_checkpoint.c 69214e2ce81bbbd3c1b82c31e103607fd2e6790818aef4792957fc9cc88d067e
|
||||
F test/tt3_index.c 95592839426dc85ce5a7a57b41be2cbf3c2ec3457b9cd841a06ed5877f712c7c
|
||||
F test/tt3_lookaside1.c 2ddd99bfffeef288f0786827ef68f912f6f47ce3d3184e62f05808d8e13b920e
|
||||
F test/tt3_reuseschema.c 4d52e141f89f009028d8ab0bd1f0697d0edffa94bafc1fff0f7ad4d9d9baa549
|
||||
F test/tt3_shared.c b37d22defc944a2ac4c91c927fd06c1d48cd51e2ce9d004fe868625bd2399f93
|
||||
F test/tt3_stress.c f9a769ca8b026ecc76ee93ca8c9700a5619f8e51c581107c4053ba6ac97f616f
|
||||
F test/tt3_vacuum.c 71b254cde1fc49d6c8c44efd54f4668f3e57d7b3a8f4601ade069f75a999ba39
|
||||
F test/tt3_stress.c 077e817ac1168443b075fedb44e92db84bb4dc5bd3b6fe1aba25c94ac280b231
|
||||
F test/tt3_vacuum.c 727bfda1299b18435eeba80dee8e6ff43462146d7c1e2096cc809f01db568391
|
||||
F test/types.test bf816ce73c7dfcfe26b700c19f97ef4050d194ff
|
||||
F test/types2.test 1aeb81976841a91eef292723649b5c4fe3bc3cac
|
||||
F test/types3.test c60e89c4d6babe44b23a2ea0090f3044e549403b20648b1c6bb65a69fea5f1ed
|
||||
@@ -2140,7 +2152,7 @@ F tool/genfkey.test b6afd7b825d797a1e1274f519ab5695373552ecad5cd373530c63533638a
|
||||
F tool/getlock.c f4c39b651370156cae979501a7b156bdba50e7ce
|
||||
F tool/index_usage.c f62a0c701b2c7ff2f3e21d206f093c123f222dbf07136a10ffd1ca15a5c706c5
|
||||
F tool/kvtest-speed.sh 4761a9c4b3530907562314d7757995787f7aef8f
|
||||
F tool/lemon.c f51a488369046cd4f4212d755a214a57673ded400cbeb01e298cbf63539e1d8c
|
||||
F tool/lemon.c 5f999ac3801e8b585149a5fd5c7c2bbdde3baca98985ebe68e1a41b8e19d19a4
|
||||
F tool/lempar.c bdffd3b233a4e4e78056c9c01fadd2bb3fe902435abde3bce3d769fdf0d5cca2
|
||||
F tool/libvers.c caafc3b689638a1d88d44bc5f526c2278760d9b9
|
||||
F tool/loadfts.c c3c64e4d5e90e8ba41159232c2189dba4be7b862
|
||||
@@ -2156,7 +2168,7 @@ F tool/mkmsvcmin.tcl d76c45efda1cce2d4005bcea7b8a22bb752e3256009f331120fb4fecb14
|
||||
F tool/mkopcodec.tcl 33d20791e191df43209b77d37f0ff0904620b28465cca6990cf8d60da61a07ef
|
||||
F tool/mkopcodeh.tcl 2b4e6967a670ef21bf53a164964c35c6163277d002a4c6f56fa231d68c88d023
|
||||
F tool/mkopts.tcl 680f785fdb09729fd9ac50632413da4eadbdf9071535e3f26d03795828ab07fa
|
||||
F tool/mkpragmatab.tcl 3801ce32f8c55fe63a3b279f231fb26c2c1a2ea9a09d2dd599239d87a609acec
|
||||
F tool/mkpragmatab.tcl 7650ca1297ef7530179c149db50311e9c533c6accd8df3505275529a10e82137
|
||||
F tool/mkshellc.tcl 9ce74de0fa904a2c56a96f8d8b5261246bacb0eaa8d7e184f9e18ff94145ebbc
|
||||
F tool/mksourceid.c 36aa8020014aed0836fd13c51d6dc9219b0df1761d6b5f58ff5b616211b079b9
|
||||
F tool/mkspeedsql.tcl a1a334d288f7adfe6e996f2e712becf076745c97
|
||||
@@ -2213,8 +2225,8 @@ F tool/version-info.c 3b36468a90faf1bbd59c65fd0eb66522d9f941eedd364fabccd7227350
|
||||
F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee87c1b31a7
|
||||
F tool/warnings.sh 49a486c5069de041aedcbde4de178293e0463ae9918ecad7539eedf0ec77a139
|
||||
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
|
||||
P acf9babf0efc346b26c8ac02c0bd973498bf1604b47fe320de14027f9b21ed33
|
||||
R 5182bad1c42928bd1b84d01963e58063
|
||||
U stephan
|
||||
Z df301f75cd724e3f3d22ab4620a14201
|
||||
P 52b97a7ad5d944e44240f624b30a76398d10ef945d8edc4b7d7b36ed2e515327
|
||||
R 8f505da43903c156f4ae84ef87ecfc5e
|
||||
U drh
|
||||
Z 684998f2296e83c5d595e837037d9498
|
||||
# Remove this line to create a well-formed Fossil manifest.
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
0554c00f32b7cc81d35340080df10ea6d66c9ff07fe749ea76cc523a4149b5c8
|
||||
94c6e8d97158fde5c8200206cf21e8acc9de8d1b4cbaf7db8d9c6a56ad6762e4
|
||||
|
||||
+2
-2
@@ -112,8 +112,8 @@ static void renameReloadSchema(Parse *pParse, int iDb, u16 p5){
|
||||
Vdbe *v = pParse->pVdbe;
|
||||
if( v ){
|
||||
sqlite3ChangeCookie(pParse, iDb);
|
||||
sqlite3VdbeAddParseSchemaOp(pParse->pVdbe, iDb, 0, p5);
|
||||
if( iDb!=1 ) sqlite3VdbeAddParseSchemaOp(pParse->pVdbe, 1, 0, p5);
|
||||
sqlite3VdbeAddParseSchemaOp(pParse, iDb, 0, p5);
|
||||
if( iDb!=1 ) sqlite3VdbeAddParseSchemaOp(pParse, 1, 0, p5);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -212,6 +212,7 @@ static void openStatTable(
|
||||
** 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
|
||||
);
|
||||
|
||||
+8
-5
@@ -224,7 +224,6 @@ static void attachFunc(
|
||||
** way we found it.
|
||||
*/
|
||||
if( rc==SQLITE_OK ){
|
||||
sqlite3BtreeEnterAll(db);
|
||||
db->init.iDb = 0;
|
||||
db->mDbFlags &= ~(DBFLAG_SchemaKnownOk);
|
||||
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
|
||||
@@ -234,11 +233,12 @@ static void attachFunc(
|
||||
sqlite3OsFileControlHint(fd, SQLITE_FCNTL_BLOCK_ON_CONNECT, &val);
|
||||
}
|
||||
#endif
|
||||
if( !REOPEN_AS_MEMDB(db) ){
|
||||
if( !IsSharedSchema(db) && !REOPEN_AS_MEMDB(db) ){
|
||||
sqlite3BtreeEnterAll(db);
|
||||
rc = sqlite3Init(db, &zErrDyn);
|
||||
sqlite3BtreeLeaveAll(db);
|
||||
assert( zErrDyn==0 || rc!=SQLITE_OK );
|
||||
}
|
||||
sqlite3BtreeLeaveAll(db);
|
||||
assert( zErrDyn==0 || rc!=SQLITE_OK );
|
||||
}
|
||||
if( rc ){
|
||||
if( ALWAYS(!REOPEN_AS_MEMDB(db)) ){
|
||||
@@ -329,6 +329,7 @@ static void detachFunc(
|
||||
pEntry = sqliteHashNext(pEntry);
|
||||
}
|
||||
|
||||
(void)sqlite3SchemaDisconnect(db, i, 0);
|
||||
sqlite3BtreeClose(pDb->pBt);
|
||||
pDb->pBt = 0;
|
||||
pDb->pSchema = 0;
|
||||
@@ -358,7 +359,9 @@ static void codeAttach(
|
||||
sqlite3* db = pParse->db;
|
||||
int regArgs;
|
||||
|
||||
if( SQLITE_OK!=sqlite3ReadSchema(pParse) ) goto attach_end;
|
||||
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));
|
||||
|
||||
+89
-61
@@ -322,6 +322,39 @@ void sqlite3NestedParse(Parse *pParse, const char *zFormat, ...){
|
||||
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
|
||||
@@ -340,59 +373,41 @@ Table *sqlite3FindTable(sqlite3 *db, const char *zName, const char *zDatabase){
|
||||
|
||||
/* All mutexes are required for schema access. Make sure we hold them. */
|
||||
assert( zDatabase!=0 || sqlite3BtreeHoldsAllMutexes(db) );
|
||||
if( zDatabase ){
|
||||
for(i=0; i<db->nDb; i++){
|
||||
if( sqlite3StrICmp(zDatabase, db->aDb[i].zDbSName)==0 ) break;
|
||||
}
|
||||
if( i>=db->nDb ){
|
||||
/* No match against the official names. But always match "main"
|
||||
** to schema 0 as a legacy fallback. */
|
||||
if( sqlite3StrICmp(zDatabase,"main")==0 ){
|
||||
i = 0;
|
||||
}else{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
p = sqlite3HashFind(&db->aDb[i].pSchema->tblHash, zName);
|
||||
if( p==0 && sqlite3StrNICmp(zName, "sqlite_", 7)==0 ){
|
||||
if( i==1 ){
|
||||
if( sqlite3StrICmp(zName+7, &PREFERRED_TEMP_SCHEMA_TABLE[7])==0
|
||||
|| sqlite3StrICmp(zName+7, &PREFERRED_SCHEMA_TABLE[7])==0
|
||||
|| sqlite3StrICmp(zName+7, &LEGACY_SCHEMA_TABLE[7])==0
|
||||
){
|
||||
p = sqlite3HashFind(&db->aDb[1].pSchema->tblHash,
|
||||
LEGACY_TEMP_SCHEMA_TABLE);
|
||||
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++;
|
||||
}
|
||||
}
|
||||
}else{
|
||||
if( sqlite3StrICmp(zName+7, &PREFERRED_SCHEMA_TABLE[7])==0 ){
|
||||
p = sqlite3HashFind(&db->aDb[i].pSchema->tblHash,
|
||||
LEGACY_SCHEMA_TABLE);
|
||||
p = sqlite3HashFind(&db->aDb[j].pSchema->tblHash, zName);
|
||||
if( p ) return p;
|
||||
if( bUnload ){
|
||||
sqlite3SchemaRelease(db, j);
|
||||
}
|
||||
}
|
||||
}
|
||||
}else{
|
||||
/* Match against TEMP first */
|
||||
p = sqlite3HashFind(&db->aDb[1].pSchema->tblHash, zName);
|
||||
if( p ) return p;
|
||||
/* The main database is second */
|
||||
p = sqlite3HashFind(&db->aDb[0].pSchema->tblHash, zName);
|
||||
if( p ) return p;
|
||||
/* Attached databases are in order of attachment */
|
||||
for(i=2; i<db->nDb; i++){
|
||||
assert( sqlite3SchemaMutexHeld(db, i, 0) );
|
||||
p = sqlite3HashFind(&db->aDb[i].pSchema->tblHash, zName);
|
||||
if( p ) break;
|
||||
/* 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( p==0 && sqlite3StrNICmp(zName, "sqlite_", 7)==0 ){
|
||||
if( sqlite3StrICmp(zName+7, &PREFERRED_SCHEMA_TABLE[7])==0 ){
|
||||
p = sqlite3HashFind(&db->aDb[0].pSchema->tblHash, LEGACY_SCHEMA_TABLE);
|
||||
}else if( sqlite3StrICmp(zName+7, &PREFERRED_TEMP_SCHEMA_TABLE[7])==0 ){
|
||||
p = sqlite3HashFind(&db->aDb[1].pSchema->tblHash,
|
||||
LEGACY_TEMP_SCHEMA_TABLE);
|
||||
}
|
||||
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 p;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -417,6 +432,7 @@ Table *sqlite3LocateTable(
|
||||
/* 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;
|
||||
@@ -433,9 +449,21 @@ Table *sqlite3LocateTable(
|
||||
if( pMod==0 && sqlite3_strnicmp(zName, "pragma_", 7)==0 ){
|
||||
pMod = sqlite3PragmaVtabRegister(db, zName);
|
||||
}
|
||||
if( pMod && sqlite3VtabEponymousTableInit(pParse, pMod) ){
|
||||
testcase( pMod->pEpoTab==0 );
|
||||
return pMod->pEpoTab;
|
||||
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
|
||||
@@ -445,15 +473,13 @@ Table *sqlite3LocateTable(
|
||||
p = 0;
|
||||
}
|
||||
|
||||
if( 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);
|
||||
}
|
||||
}else{
|
||||
assert( HasRowid(p) || p->iPKey<0 );
|
||||
}
|
||||
|
||||
return p;
|
||||
@@ -622,11 +648,10 @@ void sqlite3ResetOneSchema(sqlite3 *db, int iDb){
|
||||
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) ){
|
||||
sqlite3SchemaClear(db->aDb[i].pSchema);
|
||||
sqlite3SchemaClearOrDisconnect(db, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -639,16 +664,17 @@ void sqlite3ResetOneSchema(sqlite3 *db, int iDb){
|
||||
void sqlite3ResetAllSchemasOfConnection(sqlite3 *db){
|
||||
int i;
|
||||
sqlite3BtreeEnterAll(db);
|
||||
for(i=0; i<db->nDb; i++){
|
||||
for(i=0; i<db->nDb; i=(i?i+1:2)){
|
||||
Db *pDb = &db->aDb[i];
|
||||
if( pDb->pSchema ){
|
||||
if( db->nSchemaLock==0 ){
|
||||
sqlite3SchemaClear(pDb->pSchema);
|
||||
sqlite3SchemaClearOrDisconnect(db, i);
|
||||
}else{
|
||||
DbSetProperty(db, i, DB_ResetWanted);
|
||||
}
|
||||
}
|
||||
}
|
||||
sqlite3SchemaClear(db->aDb[1].pSchema);
|
||||
db->mDbFlags &= ~(DBFLAG_SchemaChange|DBFLAG_SchemaKnownOk);
|
||||
sqlite3VtabUnlockList(db);
|
||||
sqlite3BtreeLeaveAll(db);
|
||||
@@ -1265,7 +1291,7 @@ void sqlite3StartTable(
|
||||
*/
|
||||
if( !IN_SPECIAL_PARSE ){
|
||||
char *zDb = db->aDb[iDb].zDbSName;
|
||||
if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){
|
||||
if( !IsSharedSchema(db) && SQLITE_OK!=sqlite3ReadSchema(pParse) ){
|
||||
goto begin_table_error;
|
||||
}
|
||||
pTable = sqlite3FindTable(db, zName, zDb);
|
||||
@@ -2915,7 +2941,7 @@ void sqlite3EndTable(
|
||||
#endif
|
||||
|
||||
/* Reparse everything to update our internal data structures */
|
||||
sqlite3VdbeAddParseSchemaOp(v, iDb,
|
||||
sqlite3VdbeAddParseSchemaOp(pParse, iDb,
|
||||
sqlite3MPrintf(db, "tbl_name='%q' AND type!='trigger'", p->zName),0);
|
||||
|
||||
/* Test for cycles in generated columns and illegal expressions
|
||||
@@ -3487,7 +3513,7 @@ void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView, int noErr){
|
||||
assert( pName->nSrc==1 );
|
||||
assert( pName->a[0].fg.fixedSchema==0 );
|
||||
assert( pName->a[0].fg.isSubquery==0 );
|
||||
if( sqlite3ReadSchema(pParse) ) goto exit_drop_table;
|
||||
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]);
|
||||
@@ -3502,6 +3528,7 @@ void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView, int noErr){
|
||||
}
|
||||
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.
|
||||
@@ -3958,7 +3985,7 @@ void sqlite3CreateIndex(
|
||||
if( IN_DECLARE_VTAB && idxType!=SQLITE_IDXTYPE_PRIMARYKEY ){
|
||||
goto exit_create_index;
|
||||
}
|
||||
if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){
|
||||
if( !IsSharedSchema(db) && SQLITE_OK!=sqlite3ReadSchema(pParse) ){
|
||||
goto exit_create_index;
|
||||
}
|
||||
if( sqlite3HasExplicitNulls(pParse, pList) ){
|
||||
@@ -4455,7 +4482,7 @@ void sqlite3CreateIndex(
|
||||
if( pTblName ){
|
||||
sqlite3RefillIndex(pParse, pIndex, iMem);
|
||||
sqlite3ChangeCookie(pParse, iDb);
|
||||
sqlite3VdbeAddParseSchemaOp(v, iDb,
|
||||
sqlite3VdbeAddParseSchemaOp(pParse, iDb,
|
||||
sqlite3MPrintf(db, "name='%q' AND type='index'", pIndex->zName), 0);
|
||||
sqlite3VdbeAddOp2(v, OP_Expire, 0, 1);
|
||||
}
|
||||
@@ -4607,6 +4634,7 @@ void sqlite3DropIndex(Parse *pParse, SrcList *pName, int ifExists){
|
||||
goto exit_drop_index;
|
||||
}
|
||||
iDb = sqlite3SchemaToIndex(db, pIndex->pSchema);
|
||||
sqlite3SchemaWritable(pParse, iDb);
|
||||
#ifndef SQLITE_OMIT_AUTHORIZATION
|
||||
{
|
||||
int code = SQLITE_DROP_INDEX;
|
||||
|
||||
+365
-6
@@ -16,6 +16,63 @@
|
||||
|
||||
#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.
|
||||
@@ -523,15 +580,317 @@ void sqlite3SchemaClear(void *p){
|
||||
}
|
||||
|
||||
/*
|
||||
** Find and return the schema associated with a BTree. Create
|
||||
** a new one if necessary.
|
||||
** 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 ){
|
||||
p = (Schema *)sqlite3BtreeSchema(pBt, sizeof(Schema), sqlite3SchemaClear);
|
||||
Schema *p;
|
||||
if( pBt && IsSharedSchema(db)==0 ){
|
||||
p = (Schema*)sqlite3BtreeSchema(pBt, sizeof(Schema), sqlite3SchemaClear);
|
||||
}else{
|
||||
p = (Schema *)sqlite3DbMallocZero(0, sizeof(Schema));
|
||||
p = (Schema*)sqlite3DbMallocZero(0, sizeof(Schema));
|
||||
}
|
||||
if( !p ){
|
||||
sqlite3OomFault(db);
|
||||
|
||||
+34
-6
@@ -1214,6 +1214,17 @@ static void disconnectAllVtab(sqlite3 *db){
|
||||
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);
|
||||
@@ -1390,6 +1401,7 @@ void sqlite3LeaveMutexAndCloseZombie(sqlite3 *db){
|
||||
sqlite3BtreeClose(pDb->pBt);
|
||||
pDb->pBt = 0;
|
||||
if( j!=1 ){
|
||||
(void)sqlite3SchemaDisconnect(db, j, 0);
|
||||
pDb->pSchema = 0;
|
||||
}
|
||||
}
|
||||
@@ -3962,7 +3974,7 @@ int sqlite3_table_column_metadata(
|
||||
int *pPrimaryKey, /* OUTPUT: True if column part of PK */
|
||||
int *pAutoinc /* OUTPUT: True if column is auto-increment */
|
||||
){
|
||||
int rc;
|
||||
int rc = SQLITE_OK;
|
||||
char *zErrMsg = 0;
|
||||
Table *pTab = 0;
|
||||
Column *pCol = 0;
|
||||
@@ -3972,7 +3984,7 @@ int sqlite3_table_column_metadata(
|
||||
int notnull = 0;
|
||||
int primarykey = 0;
|
||||
int autoinc = 0;
|
||||
|
||||
int bUnlock;
|
||||
|
||||
#ifdef SQLITE_ENABLE_API_ARMOR
|
||||
if( !sqlite3SafetyCheckOk(db) || zTableName==0 ){
|
||||
@@ -3982,14 +3994,29 @@ int sqlite3_table_column_metadata(
|
||||
|
||||
/* Ensure the database schema has been loaded */
|
||||
sqlite3_mutex_enter(db->mutex);
|
||||
bUnlock = sqlite3LockReusableSchema(db);
|
||||
sqlite3BtreeEnterAll(db);
|
||||
rc = sqlite3Init(db, &zErrMsg);
|
||||
if( SQLITE_OK!=rc ){
|
||||
goto error_out;
|
||||
if( IsSharedSchema(db)==0 ){
|
||||
rc = sqlite3Init(db, &zErrMsg);
|
||||
}
|
||||
|
||||
/* Locate the table in question */
|
||||
pTab = sqlite3FindTable(db, zTableName, zDbName);
|
||||
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;
|
||||
@@ -4059,6 +4086,7 @@ error_out:
|
||||
sqlite3ErrorWithMsg(db, rc, (zErrMsg?"%s":0), zErrMsg);
|
||||
sqlite3DbFree(db, zErrMsg);
|
||||
rc = sqlite3ApiExit(db, rc);
|
||||
sqlite3UnlockReusableSchema(db, bUnlock);
|
||||
sqlite3_mutex_leave(db->mutex);
|
||||
return rc;
|
||||
}
|
||||
|
||||
+1
-1
@@ -5311,7 +5311,7 @@ static int winOpen(
|
||||
|
||||
int rc = SQLITE_OK; /* Function Return Code */
|
||||
#if !defined(NDEBUG) || SQLITE_OS_WINCE
|
||||
int eType = flags&0x0FFF00; /* Type of file to open */
|
||||
int eType = flags&0x0FFF00; /* Type of file to open */
|
||||
#endif
|
||||
|
||||
int isExclusive = (flags & SQLITE_OPEN_EXCLUSIVE);
|
||||
|
||||
+123
-7
@@ -5080,6 +5080,115 @@ sqlite3_file *sqlite3_database_file_object(const char *zName){
|
||||
}
|
||||
|
||||
|
||||
#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
|
||||
@@ -5174,15 +5283,10 @@ static int hasHotJournal(Pager *pPager, int *pExists){
|
||||
rc = sqlite3OsOpen(pVfs, pPager->zJournal, pPager->jfd, f, &f);
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
u8 first = 0;
|
||||
rc = sqlite3OsRead(pPager->jfd, (void *)&first, 1, 0);
|
||||
if( rc==SQLITE_IOERR_SHORT_READ ){
|
||||
rc = SQLITE_OK;
|
||||
}
|
||||
rc = checkHotJournal(pPager, pExists);
|
||||
if( !jrnlOpen ){
|
||||
sqlite3OsClose(pPager->jfd);
|
||||
}
|
||||
*pExists = (first!=0);
|
||||
}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
|
||||
@@ -5433,6 +5537,10 @@ int sqlite3PagerSharedLock(Pager *pPager){
|
||||
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;
|
||||
@@ -5700,7 +5808,6 @@ static int getPageError(
|
||||
return pPager->errCode;
|
||||
}
|
||||
|
||||
|
||||
/* Dispatch all page fetch requests to the appropriate getter method.
|
||||
*/
|
||||
int sqlite3PagerGet(
|
||||
@@ -7401,6 +7508,15 @@ int sqlite3PagerSetJournalMode(Pager *pPager, int eMode){
|
||||
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 );
|
||||
|
||||
+10
-3
@@ -504,7 +504,13 @@ void sqlite3Pragma(
|
||||
|
||||
/* Make sure the database schema is loaded if the pragma requires that */
|
||||
if( (pPragma->mPragFlg & PragFlg_NeedSchema)!=0 ){
|
||||
if( sqlite3ReadSchema(pParse) ) goto pragma_out;
|
||||
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 */
|
||||
@@ -2294,9 +2300,10 @@ void sqlite3Pragma(
|
||||
** applications for any purpose.
|
||||
*/
|
||||
case PragTyp_HEADER_VALUE: {
|
||||
int iCookie = pPragma->iArg; /* Which cookie to read or write */
|
||||
int iCookie; /* Which cookie to read or write */
|
||||
iCookie = pPragma->iArg & PRAGMA_HEADER_VALUE_MASK;
|
||||
sqlite3VdbeUsesBtree(v, iDb);
|
||||
if( zRight && (pPragma->mPragFlg & PragFlg_ReadOnly)==0 ){
|
||||
if( zRight && (pPragma->iArg & PRAGMA_HEADER_VALUE_READONLY)==0 ){
|
||||
/* Write the specified cookie value */
|
||||
static const VdbeOpList setCookie[] = {
|
||||
{ OP_Transaction, 0, 1, 0}, /* 0 */
|
||||
|
||||
+125
-10
@@ -43,6 +43,11 @@ static void corruptSchema(
|
||||
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] : "?";
|
||||
@@ -53,6 +58,28 @@ static void corruptSchema(
|
||||
}
|
||||
}
|
||||
|
||||
#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.
|
||||
@@ -76,6 +103,15 @@ static int sqlite3Prepare(
|
||||
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 */
|
||||
);
|
||||
|
||||
|
||||
/*
|
||||
@@ -141,7 +177,11 @@ int sqlite3InitCallback(void *pInit, int argc, char **argv, char **NotUsed){
|
||||
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;
|
||||
@@ -153,7 +193,11 @@ int sqlite3InitCallback(void *pInit, int argc, char **argv, char **NotUsed){
|
||||
if( rc > pData->rc ) pData->rc = rc;
|
||||
if( rc==SQLITE_NOMEM ){
|
||||
sqlite3OomFault(db);
|
||||
}else if( rc!=SQLITE_INTERRUPT && (rc&0xFF)!=SQLITE_LOCKED ){
|
||||
}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));
|
||||
}
|
||||
}
|
||||
@@ -184,6 +228,12 @@ int sqlite3InitCallback(void *pInit, int argc, char **argv, char **NotUsed){
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef SQLITE_ENABLE_SHARED_SCHEMA
|
||||
if( IsSharedSchema(db) && iDb!=1 ){
|
||||
schemaUpdateChecksum(pData, argv[0], argv[1], argv[2]);
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -211,10 +261,28 @@ int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg, u32 mFlags){
|
||||
|
||||
assert( (db->mDbFlags & DBFLAG_SchemaKnownOk)==0 );
|
||||
assert( iDb>=0 && iDb<db->nDb );
|
||||
assert( db->aDb[iDb].pSchema );
|
||||
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
|
||||
@@ -235,6 +303,7 @@ int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg, u32 mFlags){
|
||||
initData.pzErrMsg = pzErrMsg;
|
||||
initData.mInitFlags = mFlags;
|
||||
initData.nInitRow = 0;
|
||||
initData.cksum = 0;
|
||||
initData.mxPage = 0;
|
||||
sqlite3InitCallback(&initData, 5, (char **)azArg, 0);
|
||||
db->mDbFlags &= mask;
|
||||
@@ -245,7 +314,6 @@ int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg, u32 mFlags){
|
||||
|
||||
/* Create a cursor to hold the database open
|
||||
*/
|
||||
pDb = &db->aDb[iDb];
|
||||
if( pDb->pBt==0 ){
|
||||
assert( iDb==1 );
|
||||
DbSetProperty(db, 1, DB_SchemaLoaded);
|
||||
@@ -404,6 +472,10 @@ int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg, u32 mFlags){
|
||||
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.
|
||||
@@ -425,6 +497,35 @@ error_out:
|
||||
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
|
||||
@@ -435,8 +536,12 @@ error_out:
|
||||
** bit is set in the flags field of the Db structure.
|
||||
*/
|
||||
int sqlite3Init(sqlite3 *db, char **pzErrMsg){
|
||||
int i, rc;
|
||||
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) );
|
||||
@@ -446,20 +551,19 @@ int sqlite3Init(sqlite3 *db, char **pzErrMsg){
|
||||
/* Do the main schema first */
|
||||
if( !DbHasProperty(db, 0, DB_SchemaLoaded) ){
|
||||
rc = sqlite3InitOne(db, 0, pzErrMsg, 0);
|
||||
if( rc ) return rc;
|
||||
}
|
||||
/* All other schemas after the main schema. The "temp" schema must be last */
|
||||
for(i=db->nDb-1; i>0; i--){
|
||||
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 ) return rc;
|
||||
}
|
||||
}
|
||||
if( commit_internal ){
|
||||
if( rc==SQLITE_OK && commit_internal ){
|
||||
sqlite3CommitInternalChanges(db);
|
||||
}
|
||||
return SQLITE_OK;
|
||||
sqlite3UnlockReusableSchema(db, bReleaseSchema);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -471,11 +575,12 @@ int sqlite3ReadSchema(Parse *pParse){
|
||||
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 ){
|
||||
}else if( db->noSharedCache && !IsSharedSchema(db) ){
|
||||
db->mDbFlags |= DBFLAG_SchemaKnownOk;
|
||||
}
|
||||
}
|
||||
@@ -501,6 +606,10 @@ static void schemaIsValid(Parse *pParse){
|
||||
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. */
|
||||
@@ -843,6 +952,7 @@ static int sqlite3LockAndPrepare(
|
||||
){
|
||||
int rc;
|
||||
int cnt = 0;
|
||||
int bReleaseSchema = 0;
|
||||
|
||||
#ifdef SQLITE_ENABLE_API_ARMOR
|
||||
if( ppStmt==0 ) return SQLITE_MISUSE_BKPT;
|
||||
@@ -852,6 +962,7 @@ static int sqlite3LockAndPrepare(
|
||||
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
|
||||
@@ -862,7 +973,11 @@ static int sqlite3LockAndPrepare(
|
||||
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;
|
||||
|
||||
+317
-9
@@ -1528,13 +1528,14 @@ static ShellState shellState;
|
||||
|
||||
/* 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_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
|
||||
*/
|
||||
@@ -2741,6 +2742,8 @@ static int shell_callback(
|
||||
char cEnd = 0;
|
||||
char c;
|
||||
int nLine = 0;
|
||||
int isIndex;
|
||||
int isWhere = 0;
|
||||
assert( nArg==1 );
|
||||
if( azArg[0]==0 ) break;
|
||||
if( sqlite3_strlike("CREATE VIEW%", azArg[0], 0)==0
|
||||
@@ -2749,6 +2752,8 @@ static int shell_callback(
|
||||
sqlite3_fprintf(p->out, "%s;\n", azArg[0]);
|
||||
break;
|
||||
}
|
||||
isIndex = sqlite3_strlike("CREATE INDEX%", azArg[0], 0)==0
|
||||
|| sqlite3_strlike("CREATE UNIQUE INDEX%", azArg[0], 0)==0;
|
||||
z = sqlite3_mprintf("%s", azArg[0]);
|
||||
shell_check_oom(z);
|
||||
j = 0;
|
||||
@@ -2778,14 +2783,26 @@ static int shell_callback(
|
||||
nParen++;
|
||||
}else if( c==')' ){
|
||||
nParen--;
|
||||
if( nLine>0 && nParen==0 && j>0 ){
|
||||
if( nLine>0 && nParen==0 && j>0 && !isWhere ){
|
||||
printSchemaLineN(p->out, z, j, "\n");
|
||||
j = 0;
|
||||
}
|
||||
}else if( (c=='w' || c=='W')
|
||||
&& nParen==0 && isIndex
|
||||
&& sqlite3_strnicmp("WHERE",&z[i],5)==0
|
||||
&& !isalnum(z[i+5]) && z[i+5]!='_' ){
|
||||
isWhere = 1;
|
||||
}else if( isWhere && (c=='A' || c=='a')
|
||||
&& nParen==0
|
||||
&& sqlite3_strnicmp("AND",&z[i],3)==0
|
||||
&& !isalnum(z[i+3]) && z[i+3]!='_' ){
|
||||
printSchemaLineN(p->out, z, j, "\n ");
|
||||
j = 0;
|
||||
}
|
||||
z[j++] = c;
|
||||
if( nParen==1 && cEnd==0
|
||||
&& (c=='(' || c=='\n' || (c==',' && !wsToEol(z+i+1)))
|
||||
&& !isWhere
|
||||
){
|
||||
if( c=='\n' ) j--;
|
||||
printSchemaLineN(p->out, z, j, "\n ");
|
||||
@@ -5261,6 +5278,12 @@ static const char *(azHelp[]) = {
|
||||
" --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
|
||||
@@ -5708,6 +5731,11 @@ static void open_db(ShellState *p, int openFlags){
|
||||
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,
|
||||
@@ -8101,8 +8129,277 @@ end_ar_command:
|
||||
*******************************************************************************/
|
||||
#endif /* !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_HAVE_ZLIB) */
|
||||
|
||||
#if SQLITE_SHELL_HAVE_RECOVER
|
||||
/*
|
||||
** 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.
|
||||
@@ -11284,6 +11581,13 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
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
|
||||
@@ -13155,6 +13459,8 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
|
||||
#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)
|
||||
@@ -13311,6 +13617,8 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
|
||||
#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 ){
|
||||
|
||||
+2
-1
@@ -616,10 +616,11 @@ int sqlite3_exec(
|
||||
#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
|
||||
**
|
||||
|
||||
@@ -1321,6 +1321,7 @@ 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;
|
||||
@@ -1464,6 +1465,10 @@ struct Db {
|
||||
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
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -1495,6 +1500,9 @@ struct Schema {
|
||||
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
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -1790,6 +1798,12 @@ struct sqlite3 {
|
||||
#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.
|
||||
*/
|
||||
@@ -1876,6 +1890,9 @@ struct sqlite3 {
|
||||
#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
|
||||
@@ -2393,6 +2410,9 @@ struct VTable {
|
||||
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
|
||||
@@ -4066,6 +4086,9 @@ struct 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
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -4205,6 +4228,7 @@ typedef struct {
|
||||
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;
|
||||
|
||||
@@ -5422,6 +5446,29 @@ 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);
|
||||
|
||||
+21
-1
@@ -289,13 +289,26 @@ int sqlite3_db_status(
|
||||
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 = db->aDb[i].pSchema;
|
||||
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;
|
||||
|
||||
@@ -317,7 +330,14 @@ int sqlite3_db_status(
|
||||
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);
|
||||
|
||||
@@ -3772,6 +3772,9 @@ static int sqliteCmdUsage(
|
||||
"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;
|
||||
}
|
||||
@@ -3903,6 +3906,16 @@ static int SQLITE_TCLAPI DbMain(
|
||||
}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;
|
||||
|
||||
@@ -569,6 +569,14 @@ Tcl_SetVar2(interp, "sqlite_options", "mergesort", "1", TCL_GLOBAL_ONLY);
|
||||
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
|
||||
@@ -787,6 +795,13 @@ Tcl_SetVar2(interp, "sqlite_options", "mergesort", "1", TCL_GLOBAL_ONLY);
|
||||
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
|
||||
|
||||
@@ -0,0 +1,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;
|
||||
}
|
||||
@@ -68,6 +68,7 @@ const char *sqlite3TestInit(Tcl_Interp *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*);
|
||||
@@ -139,6 +140,7 @@ const char *sqlite3TestInit(Tcl_Interp *interp){
|
||||
Sqlitetest_malloc_Init(interp);
|
||||
Sqlitetest_mutex_Init(interp);
|
||||
Sqlitetestschema_Init(interp);
|
||||
Sqlitetestschemapool_Init(interp);
|
||||
Sqlitetesttclvar_Init(interp);
|
||||
Sqlitetestfs_Init(interp);
|
||||
SqlitetestThread_Init(interp);
|
||||
|
||||
+40
-5
@@ -52,13 +52,34 @@ Trigger *sqlite3TriggerList(Parse *pParse, Table *pTab){
|
||||
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);
|
||||
if( pTrig->pTabSchema==pTab->pSchema
|
||||
|
||||
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)
|
||||
@@ -68,7 +89,7 @@ Trigger *sqlite3TriggerList(Parse *pParse, Table *pTab){
|
||||
}else if( pTrig->op==TK_RETURNING ){
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
assert( pParse->db->pVtabCtx==0 );
|
||||
#endif
|
||||
#endif
|
||||
assert( pParse->bReturning );
|
||||
assert( !pParse->isCreate );
|
||||
assert( &(pParse->u1.d.pReturning->retTrig) == pTrig );
|
||||
@@ -266,6 +287,12 @@ void sqlite3BeginTrigger(
|
||||
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;
|
||||
@@ -389,7 +416,7 @@ void sqlite3FinishTrigger(
|
||||
pTrig->table, z);
|
||||
sqlite3DbFree(db, z);
|
||||
sqlite3ChangeCookie(pParse, iDb);
|
||||
sqlite3VdbeAddParseSchemaOp(v, iDb,
|
||||
sqlite3VdbeAddParseSchemaOp(pParse, iDb,
|
||||
sqlite3MPrintf(db, "type='trigger' AND name='%q'", zName), 0);
|
||||
}
|
||||
|
||||
@@ -608,6 +635,9 @@ void sqlite3DeleteTrigger(sqlite3 *db, Trigger *pTrigger){
|
||||
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);
|
||||
@@ -680,6 +710,7 @@ void sqlite3DropTriggerPtr(Parse *pParse, Trigger *pTrigger){
|
||||
|
||||
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
|
||||
@@ -1250,7 +1281,9 @@ static TriggerPrg *codeRowTrigger(
|
||||
int iEndTrigger = 0; /* Label to jump to if WHEN is false */
|
||||
Parse sSubParse; /* Parse context for sub-vdbe */
|
||||
|
||||
assert( pTrigger->zName==0 || pTab==tableOfTrigger(pTrigger) );
|
||||
assert( pTrigger->zName==0 || IsSharedSchema(pParse->db)
|
||||
|| pTab==tableOfTrigger(pTrigger)
|
||||
);
|
||||
assert( pTop->pVdbe );
|
||||
|
||||
/* Allocate the TriggerPrg and SubProgram objects. To ensure that they
|
||||
@@ -1359,7 +1392,9 @@ static TriggerPrg *getRowTrigger(
|
||||
Parse *pRoot = sqlite3ParseToplevel(pParse);
|
||||
TriggerPrg *pPrg;
|
||||
|
||||
assert( pTrigger->zName==0 || pTab==tableOfTrigger(pTrigger) );
|
||||
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
|
||||
|
||||
@@ -125,6 +125,7 @@ void sqlite3Vacuum(Parse *pParse, Token *pNm, Expr *pInto){
|
||||
}
|
||||
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);
|
||||
|
||||
+7
-7
@@ -4101,13 +4101,6 @@ case OP_Transaction: {
|
||||
&& pOp->p5
|
||||
&& (iMeta!=pOp->p3 || pDb->pSchema->iGeneration!=pOp->p4.i)
|
||||
){
|
||||
/*
|
||||
** 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");
|
||||
/* 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.
|
||||
@@ -4124,6 +4117,13 @@ case OP_Transaction: {
|
||||
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;
|
||||
|
||||
|
||||
+1
-1
@@ -245,7 +245,7 @@ VdbeOp *sqlite3VdbeAddOpList(Vdbe*, int nOp, VdbeOpList const *aOp,int iLineno);
|
||||
#else
|
||||
# define sqlite3ExplainBreakpoint(A,B) /*no-op*/
|
||||
#endif
|
||||
void sqlite3VdbeAddParseSchemaOp(Vdbe*, int, char*, u16);
|
||||
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);
|
||||
|
||||
+3
-1
@@ -561,8 +561,10 @@ void sqlite3VdbeExplainPop(Parse *pParse){
|
||||
** The zWhere string must have been obtained from sqlite3_malloc().
|
||||
** This routine will take ownership of the allocated memory.
|
||||
*/
|
||||
void sqlite3VdbeAddParseSchemaOp(Vdbe *p, int iDb, char *zWhere, u16 p5){
|
||||
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);
|
||||
|
||||
@@ -134,6 +134,7 @@ int sqlite3_blob_open(
|
||||
Table *pTab;
|
||||
Incrblob *pBlob = 0;
|
||||
Parse sParse;
|
||||
int bUnlock; /* True to unlock reusable schemas before returning */
|
||||
|
||||
#ifdef SQLITE_ENABLE_API_ARMOR
|
||||
if( ppBlob==0 ){
|
||||
@@ -150,6 +151,7 @@ int sqlite3_blob_open(
|
||||
|
||||
sqlite3_mutex_enter(db->mutex);
|
||||
|
||||
bUnlock = sqlite3LockReusableSchema(db);
|
||||
pBlob = (Incrblob *)sqlite3DbMallocZero(db, sizeof(Incrblob));
|
||||
while(1){
|
||||
sqlite3ParseObjectInit(&sParse,db);
|
||||
@@ -336,6 +338,7 @@ int sqlite3_blob_open(
|
||||
}
|
||||
|
||||
blob_open_out:
|
||||
sqlite3UnlockReusableSchema(db, bUnlock);
|
||||
if( rc==SQLITE_OK && db->mallocFailed==0 ){
|
||||
*ppBlob = (sqlite3_blob *)pBlob;
|
||||
}else{
|
||||
|
||||
+47
-8
@@ -192,6 +192,24 @@ void sqlite3VtabLock(VTable *pVTab){
|
||||
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;
|
||||
}
|
||||
@@ -500,7 +518,7 @@ void sqlite3VtabFinishParse(Parse *pParse, Token *pEnd){
|
||||
|
||||
sqlite3VdbeAddOp0(v, OP_Expire);
|
||||
zWhere = sqlite3MPrintf(db, "name=%Q AND sql=%Q", pTab->zName, zStmt);
|
||||
sqlite3VdbeAddParseSchemaOp(v, iDb, zWhere, 0);
|
||||
sqlite3VdbeAddParseSchemaOp(pParse, iDb, zWhere, 0);
|
||||
sqlite3DbFree(db, zStmt);
|
||||
|
||||
iReg = ++pParse->nMem;
|
||||
@@ -570,6 +588,7 @@ static int vtabCallConstructor(
|
||||
char *zModuleName;
|
||||
int iDb;
|
||||
VtabCtx *pCtx;
|
||||
int nByte; /* Bytes of space to allocate */
|
||||
|
||||
assert( IsVirtual(pTab) );
|
||||
azArg = (const char *const*)pTab->u.vtab.azArg;
|
||||
@@ -589,7 +608,11 @@ static int vtabCallConstructor(
|
||||
return SQLITE_NOMEM_BKPT;
|
||||
}
|
||||
|
||||
pVTable = sqlite3MallocZero(sizeof(VTable));
|
||||
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);
|
||||
@@ -597,6 +620,10 @@ static int vtabCallConstructor(
|
||||
}
|
||||
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);
|
||||
@@ -643,12 +670,23 @@ static int vtabCallConstructor(
|
||||
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. 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. */
|
||||
pVTable->pNext = pTab->u.vtab.p;
|
||||
pTab->u.vtab.p = pVTable;
|
||||
** 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], "");
|
||||
@@ -703,6 +741,7 @@ int sqlite3VtabCallConnect(Parse *pParse, Table *pTab){
|
||||
assert( pTab );
|
||||
assert( IsVirtual(pTab) );
|
||||
if( sqlite3GetVTable(db, pTab) ){
|
||||
assert( !IsVirtual(pTab) || pTab->nCol>0 );
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -1679,7 +1679,7 @@ static int vtabBestIndex(Parse *pParse, Table *pTab, sqlite3_index_info *p){
|
||||
sqlite3ErrorMsg(pParse, "%s", pVtab->zErrMsg);
|
||||
}
|
||||
}
|
||||
if( pTab->u.vtab.p->bAllSchemas ){
|
||||
if( pTab->u.vtab.p && pTab->u.vtab.p->bAllSchemas ){
|
||||
sqlite3VtabUsesAllSchemas(pParse);
|
||||
}
|
||||
sqlite3_free(pVtab->zErrMsg);
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set testprefix nolock
|
||||
|
||||
unset -nocomplain tvfs_calls
|
||||
proc tvfs_reset {} {
|
||||
@@ -217,4 +218,31 @@ if {[permutation]!="inmemory_journal"} {
|
||||
} {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
|
||||
|
||||
|
||||
@@ -0,0 +1,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
|
||||
|
||||
@@ -0,0 +1,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
|
||||
@@ -0,0 +1,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
|
||||
@@ -0,0 +1,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
|
||||
@@ -0,0 +1,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
|
||||
@@ -0,0 +1,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
|
||||
@@ -0,0 +1,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
|
||||
|
||||
@@ -0,0 +1,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
|
||||
|
||||
@@ -0,0 +1,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
|
||||
+4
-3
@@ -72,9 +72,10 @@ do_execsql_test 1.2.1 {
|
||||
CREATE TABLE t4(hello);
|
||||
}
|
||||
db close
|
||||
do_test 1.2.2 {
|
||||
catchcmd test.db ".read testdump.txt"
|
||||
} {1 {Parse error near line 5: table sqlite_master may not be modified}}
|
||||
# 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
|
||||
#
|
||||
|
||||
@@ -26,6 +26,9 @@ 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?"
|
||||
}
|
||||
|
||||
+1
-1
@@ -823,7 +823,7 @@ proc catchcmd {db {cmd ""}} {
|
||||
set out [open cmds.txt w]
|
||||
puts $out $cmd
|
||||
close $out
|
||||
set line "exec $CLI $db < cmds.txt"
|
||||
set line "exec $CLI --unsafe-testing $db < cmds.txt"
|
||||
set rc [catch { eval $line } msg]
|
||||
list $rc $msg
|
||||
}
|
||||
|
||||
+3
-2
@@ -1240,7 +1240,8 @@ proc add_jobs_from_cmdline {patternlist} {
|
||||
devtest -
|
||||
mdevtest {
|
||||
set config_set {
|
||||
All-O0
|
||||
ReuseSchema-O0
|
||||
ReuseSchema-Debug
|
||||
All-Debug
|
||||
}
|
||||
add_devtest_jobs $config_set [lrange $patternlist 1 end]
|
||||
@@ -1248,7 +1249,7 @@ proc add_jobs_from_cmdline {patternlist} {
|
||||
|
||||
sdevtest {
|
||||
set config_set {
|
||||
All-Sanitize
|
||||
ReuseSchema-Sanitize
|
||||
All-Debug
|
||||
}
|
||||
add_devtest_jobs $config_set [lrange $patternlist 1 end]
|
||||
|
||||
@@ -108,6 +108,18 @@ namespace eval trd {
|
||||
--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
|
||||
@@ -478,10 +490,10 @@ proc make_sh_script {srcdir opts cflags makeOpts configOpts} {
|
||||
set myopts ""
|
||||
if {[info exists ::env(OPTS)]} {
|
||||
append myopts "# From environment variable:\n"
|
||||
append myopts "OPTS=$::env(OPTS)\n\n"
|
||||
append myopts "OPTIONS=$::env(OPTS)\n\n"
|
||||
}
|
||||
foreach o [lsort $opts] {
|
||||
append myopts "OPTS=\"\$OPTS $o\"\n"
|
||||
append myopts "OPTIONS=\"\$OPTS $o\"\n"
|
||||
}
|
||||
|
||||
return [trimscript [subst -nocommands {
|
||||
|
||||
+24
-19
@@ -38,7 +38,7 @@
|
||||
#define SEL(e) ((e)->iLine = ((e)->rc ? (e)->iLine : __LINE__))
|
||||
|
||||
/* Database functions */
|
||||
#define opendb(w,x,y,z) (SEL(w), opendb_x(w,x,y,z))
|
||||
#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 */
|
||||
@@ -545,11 +545,14 @@ 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 bDelete, /* True to delete db file before opening */
|
||||
int flags
|
||||
){
|
||||
if( pErr->rc==SQLITE_OK ){
|
||||
int rc;
|
||||
int flags = SQLITE_OPEN_CREATE | SQLITE_OPEN_READWRITE | SQLITE_OPEN_URI;
|
||||
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 ){
|
||||
@@ -985,7 +988,7 @@ static char *walthread1_thread(int iTid, void *pArg){
|
||||
Sqlite db = {0}; /* SQLite database connection */
|
||||
int nIter = 0; /* Iterations so far */
|
||||
|
||||
opendb(&err, &db, "test.db", 0);
|
||||
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)",
|
||||
@@ -1024,7 +1027,7 @@ static char *walthread1_ckpt_thread(int iTid, void *pArg){
|
||||
Sqlite db = {0}; /* SQLite database connection */
|
||||
int nCkpt = 0; /* Checkpoints so far */
|
||||
|
||||
opendb(&err, &db, "test.db", 0);
|
||||
opendb(&err, &db, "test.db", 0, 0);
|
||||
while( !timetostop(&err) ){
|
||||
sqlite3_sleep(500);
|
||||
execsql(&err, &db, "PRAGMA wal_checkpoint");
|
||||
@@ -1043,7 +1046,7 @@ static void walthread1(int nMs){
|
||||
Threadset threads = {0}; /* Test threads */
|
||||
int i; /* Iterator variable */
|
||||
|
||||
opendb(&err, &db, "test.db", 1);
|
||||
opendb(&err, &db, "test.db", 1, 0);
|
||||
sql_script(&err, &db,
|
||||
"PRAGMA journal_mode = WAL;"
|
||||
"CREATE TABLE t1(x PRIMARY KEY);"
|
||||
@@ -1076,7 +1079,7 @@ static char *walthread2_thread(int iTid, void *pArg){
|
||||
int journal_exists = 0;
|
||||
int wal_exists = 0;
|
||||
|
||||
opendb(&err, &db, "test.db", 0);
|
||||
opendb(&err, &db, "test.db", 0, 0);
|
||||
|
||||
sql_script(&err, &db, zJournal);
|
||||
clear_error(&err, SQLITE_BUSY);
|
||||
@@ -1106,7 +1109,7 @@ static void walthread2(int nMs){
|
||||
Sqlite db = {0};
|
||||
Threadset threads = {0};
|
||||
|
||||
opendb(&err, &db, "test.db", 1);
|
||||
opendb(&err, &db, "test.db", 1, 0);
|
||||
sql_script(&err, &db, "CREATE TABLE t1(x INTEGER PRIMARY KEY, y UNIQUE)");
|
||||
closedb(&err, &db);
|
||||
|
||||
@@ -1126,7 +1129,7 @@ static char *walthread3_thread(int iTid, void *pArg){
|
||||
i64 iNextWrite; /* Next value this thread will write */
|
||||
int iArg = PTR2INT(pArg);
|
||||
|
||||
opendb(&err, &db, "test.db", 0);
|
||||
opendb(&err, &db, "test.db", 0, 0);
|
||||
sql_script(&err, &db, "PRAGMA wal_autocheckpoint = 10");
|
||||
|
||||
iNextWrite = iArg+1;
|
||||
@@ -1163,7 +1166,7 @@ static void walthread3(int nMs){
|
||||
Threadset threads = {0};
|
||||
int i;
|
||||
|
||||
opendb(&err, &db, "test.db", 1);
|
||||
opendb(&err, &db, "test.db", 1, 0);
|
||||
sql_script(&err, &db,
|
||||
"PRAGMA journal_mode = WAL;"
|
||||
"CREATE TABLE t1(cnt PRIMARY KEY, sum1, sum2);"
|
||||
@@ -1186,7 +1189,7 @@ 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);
|
||||
opendb(&err, &db, "test.db", 0, 0);
|
||||
while( !timetostop(&err) ){
|
||||
integrity_check(&err, &db);
|
||||
}
|
||||
@@ -1201,7 +1204,7 @@ static char *walthread4_writer_thread(int iTid, void *pArg){
|
||||
Sqlite db = {0}; /* SQLite database connection */
|
||||
i64 iRow = 1;
|
||||
|
||||
opendb(&err, &db, "test.db", 0);
|
||||
opendb(&err, &db, "test.db", 0, 0);
|
||||
sql_script(&err, &db, "PRAGMA wal_autocheckpoint = 15;");
|
||||
while( !timetostop(&err) ){
|
||||
execsql_i64(
|
||||
@@ -1221,7 +1224,7 @@ static void walthread4(int nMs){
|
||||
Sqlite db = {0};
|
||||
Threadset threads = {0};
|
||||
|
||||
opendb(&err, &db, "test.db", 1);
|
||||
opendb(&err, &db, "test.db", 1, 0);
|
||||
sql_script(&err, &db,
|
||||
"PRAGMA journal_mode = WAL;"
|
||||
"CREATE TABLE t1(a INTEGER PRIMARY KEY, b UNIQUE);"
|
||||
@@ -1241,7 +1244,7 @@ static char *walthread5_thread(int iTid, void *pArg){
|
||||
Sqlite db = {0}; /* SQLite database connection */
|
||||
i64 nRow;
|
||||
|
||||
opendb(&err, &db, "test.db", 0);
|
||||
opendb(&err, &db, "test.db", 0, 0);
|
||||
nRow = execsql_i64(&err, &db, "SELECT count(*) FROM t1");
|
||||
closedb(&err, &db);
|
||||
|
||||
@@ -1254,7 +1257,7 @@ static void walthread5(int nMs){
|
||||
Sqlite db = {0};
|
||||
Threadset threads = {0};
|
||||
|
||||
opendb(&err, &db, "test.db", 1);
|
||||
opendb(&err, &db, "test.db", 1, 0);
|
||||
sql_script(&err, &db,
|
||||
"PRAGMA wal_autocheckpoint = 0;"
|
||||
"PRAGMA page_size = 1024;"
|
||||
@@ -1345,7 +1348,7 @@ static void cgt_pager_1(int nMs){
|
||||
Error err = {0};
|
||||
Sqlite db = {0};
|
||||
|
||||
opendb(&err, &db, "test.db", 1);
|
||||
opendb(&err, &db, "test.db", 1, 0);
|
||||
sql_script(&err, &db,
|
||||
"PRAGMA cache_size = 2000;"
|
||||
"PRAGMA page_size = 1024;"
|
||||
@@ -1374,7 +1377,7 @@ static char *dynamic_triggers_1(int iTid, void *pArg){
|
||||
int nDrop = 0;
|
||||
int nCreate = 0;
|
||||
|
||||
opendb(&err, &db, "test.db", 0);
|
||||
opendb(&err, &db, "test.db", 0, 0);
|
||||
while( !timetostop(&err) ){
|
||||
int i;
|
||||
|
||||
@@ -1427,7 +1430,7 @@ static char *dynamic_triggers_2(int iTid, void *pArg){
|
||||
int nInsert = 0;
|
||||
int nDelete = 0;
|
||||
|
||||
opendb(&err, &db, "test.db", 0);
|
||||
opendb(&err, &db, "test.db", 0, 0);
|
||||
while( !timetostop(&err) ){
|
||||
do {
|
||||
iVal = (iVal+1)%100;
|
||||
@@ -1452,7 +1455,7 @@ static void dynamic_triggers(int nMs){
|
||||
Sqlite db = {0};
|
||||
Threadset threads = {0};
|
||||
|
||||
opendb(&err, &db, "test.db", 1);
|
||||
opendb(&err, &db, "test.db", 1, 0);
|
||||
sql_script(&err, &db,
|
||||
"PRAGMA page_size = 1024;"
|
||||
"PRAGMA journal_mode = WAL;"
|
||||
@@ -1492,6 +1495,7 @@ static void dynamic_triggers(int nMs){
|
||||
#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){
|
||||
@@ -1517,6 +1521,7 @@ int main(int argc, char **argv){
|
||||
{ vacuum1, "vacuum1", 10000 },
|
||||
{ stress1, "stress1", 10000 },
|
||||
{ stress2, "stress2", 60000 },
|
||||
{ reuse_schema_1, "reuse_schema_1", 20000 },
|
||||
{ shared1, "shared1", 10000 },
|
||||
};
|
||||
static char *substArgv[] = { 0, "*", 0 };
|
||||
|
||||
@@ -70,7 +70,7 @@ static char *checkpoint_starvation_reader(int iTid, void *pArg){
|
||||
Error err = {0};
|
||||
Sqlite db = {0};
|
||||
|
||||
opendb(&err, &db, "test.db", 0);
|
||||
opendb(&err, &db, "test.db", 0, 0);
|
||||
while( !timetostop(&err) ){
|
||||
i64 iCount1, iCount2;
|
||||
sql_script(&err, &db, "BEGIN");
|
||||
@@ -96,7 +96,7 @@ static void checkpoint_starvation_main(int nMs, CheckpointStarvationCtx *p){
|
||||
int nInsert = 0;
|
||||
int i;
|
||||
|
||||
opendb(&err, &db, "test.db", 1);
|
||||
opendb(&err, &db, "test.db", 1, 0);
|
||||
sql_script(&err, &db,
|
||||
"PRAGMA page_size = 1024;"
|
||||
"PRAGMA journal_mode = WAL;"
|
||||
|
||||
+2
-2
@@ -19,7 +19,7 @@ static char *create_drop_index_thread(int iTid, void *pArg){
|
||||
Sqlite db = {0}; /* SQLite database connection */
|
||||
|
||||
while( !timetostop(&err) ){
|
||||
opendb(&err, &db, "test.db", 0);
|
||||
opendb(&err, &db, "test.db", 0, 0);
|
||||
|
||||
sql_script(&err, &db,
|
||||
"DROP INDEX IF EXISTS i1;"
|
||||
@@ -51,7 +51,7 @@ static void create_drop_index_1(int nMs){
|
||||
Sqlite db = {0};
|
||||
Threadset threads = {0};
|
||||
|
||||
opendb(&err, &db, "test.db", 1);
|
||||
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) "
|
||||
|
||||
@@ -22,7 +22,7 @@ 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);
|
||||
opendb(&err, &db, "test.db", 0, 0);
|
||||
|
||||
while( !timetostop(&err) ){
|
||||
sqlite3_stmt *pStmt = 0;
|
||||
@@ -47,7 +47,7 @@ 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);
|
||||
opendb(&err, &db, "test.db", 0, 0);
|
||||
|
||||
do{
|
||||
sql_script(&err, &db,
|
||||
@@ -68,7 +68,7 @@ static void lookaside1(int nMs){
|
||||
Sqlite db = {0};
|
||||
Threadset threads = {0};
|
||||
|
||||
opendb(&err, &db, "test.db", 1);
|
||||
opendb(&err, &db, "test.db", 1, 0);
|
||||
sql_script(&err, &db,
|
||||
"CREATE TABLE t1(x PRIMARY KEY) WITHOUT ROWID;"
|
||||
"WITH data(x,y) AS ("
|
||||
|
||||
@@ -0,0 +1,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);
|
||||
}
|
||||
+10
-10
@@ -21,7 +21,7 @@ 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);
|
||||
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);
|
||||
@@ -40,7 +40,7 @@ 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);
|
||||
opendb(&err, &db, "test.db", 0, 0);
|
||||
sql_script(&err, &db, "SELECT * FROM sqlite_schema;");
|
||||
clear_error(&err, SQLITE_LOCKED);
|
||||
closedb(&err, &db);
|
||||
@@ -59,7 +59,7 @@ static char *stress_thread_3(int iTid, void *pArg){
|
||||
int i1 = 0;
|
||||
int i2 = 0;
|
||||
|
||||
opendb(&err, &db, "test.db", 0);
|
||||
opendb(&err, &db, "test.db", 0, 0);
|
||||
while( !timetostop(&err) ){
|
||||
sql_script(&err, &db, "SELECT * FROM t1 ORDER BY a;");
|
||||
i1++;
|
||||
@@ -82,11 +82,11 @@ static char *stress_thread_4(int iTid, void *pArg){
|
||||
int i2 = 0;
|
||||
int iArg = PTR2INT(pArg);
|
||||
|
||||
opendb(&err, &db, "test.db", 0);
|
||||
opendb(&err, &db, "test.db", 0, 0);
|
||||
while( !timetostop(&err) ){
|
||||
if( iArg ){
|
||||
closedb(&err, &db);
|
||||
opendb(&err, &db, "test.db", 0);
|
||||
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) "
|
||||
@@ -113,12 +113,12 @@ static char *stress_thread_5(int iTid, void *pArg){
|
||||
int i1 = 0;
|
||||
int i2 = 0;
|
||||
|
||||
opendb(&err, &db, "test.db", 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);
|
||||
opendb(&err, &db, "test.db", 0, 0);
|
||||
}
|
||||
execsql(&err, &db, "DELETE FROM t1 WHERE (rowid % 4)==:i", &i);
|
||||
i1++;
|
||||
@@ -265,7 +265,7 @@ static char *stress2_workload19(int iTid, void *pArg){
|
||||
Sqlite db = {0}; /* SQLite database connection */
|
||||
const char *zDb = (const char*)pArg;
|
||||
while( !timetostop(&err) ){
|
||||
opendb(&err, &db, zDb, 0);
|
||||
opendb(&err, &db, zDb, 0, 0);
|
||||
sql_script(&err, &db, "SELECT * FROM sqlite_schema;");
|
||||
clear_error(&err, SQLITE_LOCKED);
|
||||
closedb(&err, &db);
|
||||
@@ -290,7 +290,7 @@ static char *stress2_thread_wrapper(int iTid, void *pArg){
|
||||
|
||||
while( !timetostop(&err) ){
|
||||
int cnt;
|
||||
opendb(&err, &db, pCtx->zDb, 0);
|
||||
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);
|
||||
@@ -342,7 +342,7 @@ static void stress2(int nMs){
|
||||
Threadset threads = {0};
|
||||
|
||||
/* To make sure the db file is empty before commencing */
|
||||
opendb(&err, &db, zDb, 1);
|
||||
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);"
|
||||
|
||||
+3
-3
@@ -25,7 +25,7 @@ static char *vacuum1_thread_writer(int iTid, void *pArg){
|
||||
Sqlite db = {0}; /* SQLite database connection */
|
||||
i64 i = 0;
|
||||
|
||||
opendb(&err, &db, "test.db", 0);
|
||||
opendb(&err, &db, "test.db", 0, 0);
|
||||
while( !timetostop(&err) ){
|
||||
i++;
|
||||
|
||||
@@ -52,7 +52,7 @@ static char *vacuum1_thread_writer(int iTid, void *pArg){
|
||||
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);
|
||||
opendb(&err, &db, "test.db", 0, 0);
|
||||
|
||||
do{
|
||||
sql_script(&err, &db, "VACUUM");
|
||||
@@ -69,7 +69,7 @@ static void vacuum1(int nMs){
|
||||
Sqlite db = {0};
|
||||
Threadset threads = {0};
|
||||
|
||||
opendb(&err, &db, "test.db", 1);
|
||||
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);"
|
||||
|
||||
+97
-10
@@ -88,7 +88,7 @@ static MemChunk *memChunkList = 0;
|
||||
*/
|
||||
static void *lemon_malloc(size_t nByte){
|
||||
MemChunk *p;
|
||||
if( nByte<0 ) return 0;
|
||||
/* 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",
|
||||
@@ -2314,6 +2314,8 @@ void OptPrint(void){
|
||||
}
|
||||
}
|
||||
/*********************** From the file "parse.c" ****************************/
|
||||
|
||||
|
||||
/*
|
||||
** Input file parser for the LEMON parser generator.
|
||||
*/
|
||||
@@ -2369,6 +2371,60 @@ struct pstate {
|
||||
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)
|
||||
{
|
||||
@@ -2746,14 +2802,30 @@ static void parseonetoken(struct pstate *psp)
|
||||
}
|
||||
break;
|
||||
case WAITING_FOR_DECL_ARG:
|
||||
if( x[0]=='{' || x[0]=='\"' || ISALNUM(x[0]) ){
|
||||
if( x[0]=='{' || x[0]=='\"' || ISALNUM(x[0])
|
||||
|| (x[0]=='<' && psp->insertLineMacro)
|
||||
){
|
||||
const char *zOld, *zNew;
|
||||
char *zBuf, *z;
|
||||
char *zBuf;
|
||||
const char *z;
|
||||
int nOld, n, nLine = 0, nNew, nBack;
|
||||
int addLineMacro;
|
||||
char zLine[50];
|
||||
zNew = x;
|
||||
if( zNew[0]=='"' || zNew[0]=='{' ) zNew++;
|
||||
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;
|
||||
@@ -2766,13 +2838,14 @@ static void parseonetoken(struct pstate *psp)
|
||||
&& psp->insertLineMacro
|
||||
&& psp->tokenlineno>1
|
||||
&& (psp->decllinenoslot==0 || psp->decllinenoslot[0]!=0);
|
||||
if( addLineMacro ){
|
||||
for(z=psp->filename, nBack=0; *z; z++){
|
||||
if( addLineMacro || x[0]=='<' ){
|
||||
addLineMacro = 1;
|
||||
for(z=zFN, nBack=0; *z; z++){
|
||||
if( *z=='\\' ) nBack++;
|
||||
}
|
||||
lemon_sprintf(zLine, "#line %d ", psp->tokenlineno);
|
||||
lemon_sprintf(zLine, "#line %d ", ln);
|
||||
nLine = lemonStrlen(zLine);
|
||||
n += nLine + lemonStrlen(psp->filename) + nBack;
|
||||
n += nLine + lemonStrlen(zFN) + nBack;
|
||||
}
|
||||
*psp->declargslot = (char *) lemon_realloc(*psp->declargslot, n);
|
||||
zBuf = *psp->declargslot + nOld;
|
||||
@@ -2783,7 +2856,7 @@ static void parseonetoken(struct pstate *psp)
|
||||
memcpy(zBuf, zLine, nLine);
|
||||
zBuf += nLine;
|
||||
*(zBuf++) = '"';
|
||||
for(z=psp->filename; *z; z++){
|
||||
for(z=zFN; *z; z++){
|
||||
if( *z=='\\' ){
|
||||
*(zBuf++) = '\\';
|
||||
}
|
||||
@@ -2799,6 +2872,8 @@ static void parseonetoken(struct pstate *psp)
|
||||
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);
|
||||
@@ -3166,6 +3241,18 @@ void Parse(struct lemon *gp)
|
||||
}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++;
|
||||
|
||||
+22
-16
@@ -20,7 +20,7 @@
|
||||
|
||||
# Flag meanings:
|
||||
set flagMeaning(NeedSchema) {Force schema load before running}
|
||||
set flagMeaning(ReadOnly) {Read-only HEADER_VALUE}
|
||||
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}
|
||||
@@ -158,7 +158,7 @@ set pragma_def {
|
||||
ARG: SQLITE_CellSizeCk
|
||||
|
||||
NAME: default_cache_size
|
||||
FLAG: NeedSchema Result0 SchemaReq NoColumns1
|
||||
FLAG: NeedSchema Result0 SchemaReq NoColumns1 OneSchema
|
||||
COLS: cache_size
|
||||
IF: !defined(SQLITE_OMIT_PAGER_PRAGMAS) && !defined(SQLITE_OMIT_DEPRECATED)
|
||||
|
||||
@@ -171,12 +171,12 @@ set pragma_def {
|
||||
IF: !defined(SQLITE_OMIT_PAGER_PRAGMAS)
|
||||
|
||||
NAME: page_count
|
||||
FLAG: NeedSchema Result0 SchemaReq
|
||||
FLAG: NeedSchema Result0 SchemaReq OneSchema
|
||||
IF: !defined(SQLITE_OMIT_PAGER_PRAGMAS)
|
||||
|
||||
NAME: max_page_count
|
||||
TYPE: PAGE_COUNT
|
||||
FLAG: NeedSchema Result0 SchemaReq
|
||||
FLAG: NeedSchema Result0 SchemaReq OneSchema
|
||||
IF: !defined(SQLITE_OMIT_PAGER_PRAGMAS)
|
||||
|
||||
NAME: locking_mode
|
||||
@@ -184,7 +184,7 @@ set pragma_def {
|
||||
IF: !defined(SQLITE_OMIT_PAGER_PRAGMAS)
|
||||
|
||||
NAME: journal_mode
|
||||
FLAG: NeedSchema Result0 SchemaReq
|
||||
FLAG: NeedSchema Result0 SchemaReq OneSchema
|
||||
IF: !defined(SQLITE_OMIT_PAGER_PRAGMAS)
|
||||
|
||||
NAME: journal_size_limit
|
||||
@@ -192,18 +192,18 @@ set pragma_def {
|
||||
IF: !defined(SQLITE_OMIT_PAGER_PRAGMAS)
|
||||
|
||||
NAME: cache_size
|
||||
FLAG: NeedSchema Result0 SchemaReq NoColumns1
|
||||
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
|
||||
FLAG: NeedSchema Result0 SchemaReq NoColumns1 OneSchema
|
||||
IF: !defined(SQLITE_OMIT_AUTOVACUUM)
|
||||
|
||||
NAME: incremental_vacuum
|
||||
FLAG: NeedSchema NoColumns
|
||||
FLAG: NeedSchema NoColumns OneSchema
|
||||
IF: !defined(SQLITE_OMIT_AUTOVACUUM)
|
||||
|
||||
NAME: temp_store
|
||||
@@ -223,7 +223,7 @@ set pragma_def {
|
||||
IF: !defined(SQLITE_OMIT_PAGER_PRAGMAS) && SQLITE_ENABLE_LOCKING_STYLE
|
||||
|
||||
NAME: synchronous
|
||||
FLAG: NeedSchema Result0 SchemaReq NoColumns1
|
||||
FLAG: NeedSchema Result0 SchemaReq NoColumns1 OneSchema
|
||||
IF: !defined(SQLITE_OMIT_PAGER_PRAGMAS)
|
||||
|
||||
NAME: table_info
|
||||
@@ -246,7 +246,7 @@ set pragma_def {
|
||||
IF: !defined(SQLITE_OMIT_SCHEMA_PRAGMAS)
|
||||
|
||||
NAME: stats
|
||||
FLAG: NeedSchema Result0 SchemaReq
|
||||
FLAG: NeedSchema Result0 SchemaReq OneSchema
|
||||
COLS: tbl idx wdth hght flgs
|
||||
IF: !defined(SQLITE_OMIT_SCHEMA_PRAGMAS) && defined(SQLITE_DEBUG)
|
||||
|
||||
@@ -298,7 +298,7 @@ set pragma_def {
|
||||
IF: !defined(SQLITE_OMIT_SCHEMA_PRAGMAS)
|
||||
|
||||
NAME: foreign_key_list
|
||||
FLAG: NeedSchema Result1 SchemaOpt
|
||||
FLAG: NeedSchema Result1 SchemaOpt OneSchema
|
||||
COLS: id seq table from to on_update on_delete match
|
||||
IF: !defined(SQLITE_OMIT_FOREIGN_KEY)
|
||||
|
||||
@@ -344,14 +344,14 @@ set pragma_def {
|
||||
|
||||
NAME: data_version
|
||||
TYPE: HEADER_VALUE
|
||||
ARG: BTREE_DATA_VERSION
|
||||
FLAG: ReadOnly Result0
|
||||
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
|
||||
FLAG: ReadOnly Result0
|
||||
ARG: BTREE_FREE_PAGE_COUNT|PRAGMA_HEADER_VALUE_READONLY
|
||||
FLAG: Result0
|
||||
IF: !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS)
|
||||
|
||||
NAME: application_id
|
||||
@@ -365,7 +365,7 @@ set pragma_def {
|
||||
IF: !defined(SQLITE_OMIT_COMPILEOPTION_DIAGS)
|
||||
|
||||
NAME: wal_checkpoint
|
||||
FLAG: NeedSchema
|
||||
FLAG: NeedSchema OneSchema
|
||||
COLS: busy log checkpointed
|
||||
IF: !defined(SQLITE_OMIT_WAL)
|
||||
|
||||
@@ -528,6 +528,12 @@ foreach f [lsort [array names allflags]] {
|
||||
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.
|
||||
#
|
||||
|
||||
Reference in New Issue
Block a user