159 lines
4.9 KiB
Diff
159 lines
4.9 KiB
Diff
Subject: [PATCH] In defensive mode, do not allow shadow tables to be renamed
|
|
using ALTER TABLE and do not allow shadow tables to be dropped.
|
|
|
|
diff --git a/src/alter.c b/src/alter.c
|
|
index 0fa24c0..707472a 100644
|
|
--- a/src/alter.c
|
|
+++ b/src/alter.c
|
|
@@ -28,9 +28,16 @@
|
|
**
|
|
** Or, if zName is not a system table, zero is returned.
|
|
*/
|
|
-static int isSystemTable(Parse *pParse, const char *zName){
|
|
- if( 0==sqlite3StrNICmp(zName, "sqlite_", 7) ){
|
|
- sqlite3ErrorMsg(pParse, "table %s may not be altered", zName);
|
|
+static int isAlterableTable(Parse *pParse, Table *pTab){
|
|
+ if( 0==sqlite3StrNICmp(pTab->zName, "sqlite_", 7)
|
|
+#ifndef SQLITE_OMIT_VIRTUALTABLE
|
|
+ || ( (pTab->tabFlags & TF_Shadow)
|
|
+ && (pParse->db->flags & SQLITE_Defensive)
|
|
+ && pParse->db->nVdbeExec==0
|
|
+ )
|
|
+#endif
|
|
+ ){
|
|
+ sqlite3ErrorMsg(pParse, "table %s may not be altered", pTab->zName);
|
|
return 1;
|
|
}
|
|
return 0;
|
|
@@ -129,7 +136,7 @@ void sqlite3AlterRenameTable(
|
|
/* Make sure it is not a system table being altered, or a reserved name
|
|
** that the table is being renamed to.
|
|
*/
|
|
- if( SQLITE_OK!=isSystemTable(pParse, pTab->zName) ){
|
|
+ if( SQLITE_OK!=isAlterableTable(pParse, pTab) ){
|
|
goto exit_rename_table;
|
|
}
|
|
if( SQLITE_OK!=sqlite3CheckObjectName(pParse, zName) ){ goto
|
|
@@ -427,7 +434,7 @@ void sqlite3AlterBeginAddColumn(Parse *pParse, SrcList *pSrc){
|
|
sqlite3ErrorMsg(pParse, "Cannot add a column to a view");
|
|
goto exit_begin_add_column;
|
|
}
|
|
- if( SQLITE_OK!=isSystemTable(pParse, pTab->zName) ){
|
|
+ if( SQLITE_OK!=isAlterableTable(pParse, pTab) ){
|
|
goto exit_begin_add_column;
|
|
}
|
|
|
|
@@ -529,7 +536,7 @@ void sqlite3AlterRenameColumn(
|
|
if( !pTab ) goto exit_rename_column;
|
|
|
|
/* Cannot alter a system table */
|
|
- if( SQLITE_OK!=isSystemTable(pParse, pTab->zName) ) goto exit_rename_column;
|
|
+ if( SQLITE_OK!=isAlterableTable(pParse, pTab) ) goto exit_rename_column;
|
|
if( SQLITE_OK!=isRealTable(pParse, pTab) ) goto exit_rename_column;
|
|
|
|
/* Which schema holds the table to be altered */
|
|
diff --git a/src/build.c b/src/build.c
|
|
index 1dc2614..3412670 100644
|
|
--- a/src/build.c
|
|
+++ b/src/build.c
|
|
@@ -2661,6 +2661,22 @@ void sqlite3CodeDropTable(Parse *pParse, Table *pTab, int iDb, int isView){
|
|
sqliteViewResetAll(db, iDb);
|
|
}
|
|
|
|
+/*
|
|
+** Return true if it is not allowed to drop the given table
|
|
+*/
|
|
+static int tableMayNotBeDropped(Parse *pParse, Table *pTab){
|
|
+ if( sqlite3StrNICmp(pTab->zName, "sqlite_", 7)==0 ){
|
|
+ if( sqlite3StrNICmp(pTab->zName+7, "stat", 4)==0 ) return 0;
|
|
+ if( sqlite3StrNICmp(pTab->zName+7, "parameters", 10)==0 ) return 0;
|
|
+ return 1;
|
|
+ }
|
|
+ if( pTab->tabFlags & TF_Shadow ){
|
|
+ sqlite3 *db = pParse->db;
|
|
+ if( (db->flags & SQLITE_Defensive)!=0 && db->nVdbeExec==0 ) return 1;
|
|
+ }
|
|
+ return 0;
|
|
+}
|
|
+
|
|
/*
|
|
** This routine is called to do the work of a DROP TABLE statement.
|
|
** pName is the name of the table to be dropped.
|
|
@@ -2730,8 +2746,7 @@ void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView, int noErr){
|
|
}
|
|
}
|
|
#endif
|
|
- if( sqlite3StrNICmp(pTab->zName, "sqlite_", 7)==0
|
|
- && sqlite3StrNICmp(pTab->zName, "sqlite_stat", 11)!=0 ){
|
|
+ if( tableMayNotBeDropped(pParse, pTab) ){
|
|
sqlite3ErrorMsg(pParse, "table %s may not be dropped", pTab->zName);
|
|
goto exit_drop_table;
|
|
}
|
|
diff --git a/test/altertab.test b/test/altertab.test
|
|
index a364207..891b081 100644
|
|
--- a/test/altertab.test
|
|
+++ b/test/altertab.test
|
|
@@ -505,5 +505,62 @@ do_execsql_test 15.5 {
|
|
SELECT sql FROM sqlite_master WHERE name = 'y';
|
|
} {{CREATE VIEW y AS SELECT f2 AS f1 FROM x}}
|
|
|
|
+#-------------------------------------------------------------------------
|
|
+# Test that it is not possible to rename a shadow table in DEFENSIVE mode.
|
|
+#
|
|
+ifcapable fts3 {
|
|
+ proc vtab_command {method args} {
|
|
+ switch -- $method {
|
|
+ xConnect {
|
|
+ if {[info exists ::vtab_connect_sql]} {
|
|
+ execsql $::vtab_connect_sql
|
|
+ }
|
|
+ return "CREATE TABLE t1(a, b, c)"
|
|
+ }
|
|
+
|
|
+ xBestIndex {
|
|
+ set clist [lindex $args 0]
|
|
+ if {[llength $clist]!=1} { error "unexpected constraint list" }
|
|
+ catch { array unset C }
|
|
+ array set C [lindex $clist 0]
|
|
+ if {$C(usable)} {
|
|
+ return "omit 0 cost 0 rows 1 idxnum 555 idxstr eq!"
|
|
+ } else {
|
|
+ return "cost 1000000 rows 0 idxnum 0 idxstr scan..."
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return {}
|
|
+ }
|
|
+
|
|
+ register_tcl_module db
|
|
+
|
|
+ sqlite3_db_config db DEFENSIVE 1
|
|
+
|
|
+ do_execsql_test 16.0 {
|
|
+ CREATE VIRTUAL TABLE y1 USING fts3;
|
|
+ }
|
|
+
|
|
+ do_catchsql_test 16.10 {
|
|
+ INSERT INTO y1_segments VALUES(1, X'1234567890');
|
|
+ } {1 {table y1_segments may not be modified}}
|
|
+
|
|
+ do_catchsql_test 16.20 {
|
|
+ ALTER TABLE y1_segments RENAME TO abc;
|
|
+ } {1 {table y1_segments may not be altered}}
|
|
+
|
|
+ do_catchsql_test 16.21 {
|
|
+ DROP TABLE y1_segments;
|
|
+ } {1 {table y1_segments may not be dropped}}
|
|
+
|
|
+ do_execsql_test 16.30 {
|
|
+ ALTER TABLE y1 RENAME TO z1;
|
|
+ }
|
|
+
|
|
+ do_execsql_test 16.40 {
|
|
+ SELECT * FROM z1_segments;
|
|
+ }
|
|
+}
|
|
|
|
finish_test
|