Modify the sqlite3_stmt_readonly() interface so that it returns false for

CREATE TABLE IF NOT EXISTS statements even if the table already exists and
the statement is really a read-only no-op.  Likewise for DROP TABLE, 
CREATE INDEX, and DROP INDEX.  Update the documentation for
sqlite3_stmt_readonly() to reflect this new behavior.

FossilOrigin-Name: cf8eb465974e596a13df56f3efbc98e098e7b74de9af4fde9ad58312db9750e4
This commit is contained in:
drh 2021-05-13 18:24:22 +00:00
parent 756748ea86
commit 31da7be9f2
4 changed files with 40 additions and 9 deletions

View File

@ -1,5 +1,5 @@
C The\scontent\scolumns\sof\sthe\sindex-btree\sthat\simplements\sa\sWITHOUT\sROWID\ntable\sare\snot\sordered\sand\sso\sthe\squery\splanner\sshould\snot\sassume\sthey\nare\sordered.\s\sFix\sfor\sthe\sissue\sidentified\sby\n[forum:/forumpost/6c8960f545|forum\spost\s6c8960f545].
D 2021-05-13T13:43:40.565
C Modify\sthe\ssqlite3_stmt_readonly()\sinterface\sso\sthat\sit\sreturns\sfalse\sfor\nCREATE\sTABLE\sIF\sNOT\sEXISTS\sstatements\seven\sif\sthe\stable\salready\sexists\sand\nthe\sstatement\sis\sreally\sa\sread-only\sno-op.\s\sLikewise\sfor\sDROP\sTABLE,\s\nCREATE\sINDEX,\sand\sDROP\sINDEX.\s\sUpdate\sthe\sdocumentation\sfor\nsqlite3_stmt_readonly()\sto\sreflect\sthis\snew\sbehavior.
D 2021-05-13T18:24:22.567
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@ -487,7 +487,7 @@ F src/btmutex.c 8acc2f464ee76324bf13310df5692a262b801808984c1b79defb2503bbafadb6
F src/btree.c 5372d8bca3374145477e129be5ed6e907731e1d117c0dc1b524b536f1cc0e577
F src/btree.h 096cc53baa58be22b02c896d1cf933c38cfc6d65f9253c1367ece8cc88a24de5
F src/btreeInt.h 7bc15a24a02662409ebcd6aeaa1065522d14b7fda71573a2b0568b458f514ae0
F src/build.c bf4f76eb77ff0193ef826f9dbd0285e8b55fe8ecb24d1f6b14bf72b68df6a422
F src/build.c a7866beda66a7c8971e013674c7f659d19977d9ad51e11032479b1f754d1ef21
F src/callback.c d0b853dd413255d2e337b34545e54d888ea02f20da5ad0e63585b389624c4a6c
F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e
F src/ctime.c 2a322b9a3d75771fb4d99e0702851f4f68dda982507a0f798eefb0712969a410
@ -545,7 +545,7 @@ F src/resolve.c c38bbb89d7ba7a8673ec4f59b63e0980eb859c39ff2acc5df8b3d0f2dcd33115
F src/rowset.c ba9515a922af32abe1f7d39406b9d35730ed65efab9443dc5702693b60854c92
F src/select.c 57dbb27e0d0cb2438487c797365a4c17294d0df3c25c970ca87f123105f33ed0
F src/shell.c.in 1b32ba2918ede13b68df47c7b92b72ba0d06e68d384e78bb9d7456527271d400
F src/sqlite.h.in c0969405cc053220ebf81d487c5851007928e45e487237dd23435d13c25daab0
F src/sqlite.h.in 5c950066775ca9efdaa49077c05d38d0bef6418f3bd07d2dce0210f1d2f3c326
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
F src/sqlite3ext.h 61b38c073d5e1e96a3d45271b257aef27d0d13da2bea5347692ae579475cd95e
F src/sqliteInt.h 2b1cbc7f78346ac83ea962e5daf6a201e223cf1902e0cfde54f37cf3d82fcc24
@ -1913,7 +1913,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
P b2b0e23ba885f22c88b03492e42c3cd1cbd59289e452263951bb757a871699f0
R 764f06f91ab95ce9134e7e810a3df5f2
P c21bc5a2353e660f2acf5ed916921a4ee416910d0b3f2deb512a05c54138d1c0
R 2e9914ba2c75f0fbf85c89829a93e146
U drh
Z 2bf41f499ef008f771df581659494cf8
Z 708e967733b505d5e67438dc1caa81fb

View File

@ -1 +1 @@
c21bc5a2353e660f2acf5ed916921a4ee416910d0b3f2deb512a05c54138d1c0
cf8eb465974e596a13df56f3efbc98e098e7b74de9af4fde9ad58312db9750e4

View File

@ -1048,6 +1048,22 @@ i16 sqlite3TableColumnToStorage(Table *pTab, i16 iCol){
}
#endif
/*
** Insert a single OP_JournalMode query opcode in order to force the
** prepared statement to return false for sqlite3_stmt_readonly(). This
** is used by CREATE TABLE IF NOT EXISTS and similar if the table already
** exists, so that the prepared statement for CREATE TABLE IF NOT EXISTS
** will return false for sqlite3_stmt_readonly() even if that statement
** is a read-only no-op.
*/
static void sqlite3ForceNotReadOnly(Parse *pParse){
int iReg = ++pParse->nMem;
Vdbe *v = sqlite3GetVdbe(pParse);
if( v ){
sqlite3VdbeAddOp3(v, OP_JournalMode, 0, iReg, PAGER_JOURNALMODE_QUERY);
}
}
/*
** Begin constructing a new table representation in memory. This is
** the first of several action routines that get called in response
@ -1147,6 +1163,7 @@ void sqlite3StartTable(
}else{
assert( !db->init.busy || CORRUPT_DB );
sqlite3CodeVerifySchema(pParse, iDb);
sqlite3ForceNotReadOnly(pParse);
}
goto begin_table_error;
}
@ -3197,7 +3214,10 @@ void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView, int noErr){
if( noErr ) db->suppressErr--;
if( pTab==0 ){
if( noErr ) sqlite3CodeVerifyNamedSchema(pParse, pName->a[0].zDatabase);
if( noErr ){
sqlite3CodeVerifyNamedSchema(pParse, pName->a[0].zDatabase);
sqlite3ForceNotReadOnly(pParse);
}
goto exit_drop_table;
}
iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
@ -3767,6 +3787,7 @@ void sqlite3CreateIndex(
}else{
assert( !db->init.busy );
sqlite3CodeVerifySchema(pParse, iDb);
sqlite3ForceNotReadOnly(pParse);
}
goto exit_create_index;
}
@ -4285,6 +4306,7 @@ void sqlite3DropIndex(Parse *pParse, SrcList *pName, int ifExists){
sqlite3ErrorMsg(pParse, "no such index: %S", pName->a);
}else{
sqlite3CodeVerifyNamedSchema(pParse, pName->a[0].zDatabase);
sqlite3ForceNotReadOnly(pParse);
}
pParse->checkSchema = 1;
goto exit_drop_index;

View File

@ -4198,6 +4198,15 @@ const char *sqlite3_normalized_sql(sqlite3_stmt *pStmt);
** [BEGIN] merely sets internal flags, but the [BEGIN|BEGIN IMMEDIATE] and
** [BEGIN|BEGIN EXCLUSIVE] commands do touch the database and so
** sqlite3_stmt_readonly() returns false for those commands.
**
** ^This routine returns false if there is any possibility that the
** statement might change the database file. ^A false return does
** not guarantee that the statement will change the database file.
** ^For example, an UPDATE statement might have a WHERE clause that
** makes it a no-op, but the sqlite3_stmt_readonly() result would still
** be false. ^Similarly, a CREATE TABLE IF NOT EXISTS statement is a
** read-only no-op if the table already exists, but
** sqlite3_stmt_readonly() still returns false for such a statement.
*/
int sqlite3_stmt_readonly(sqlite3_stmt *pStmt);