Index: ext/rbu/rbudiff.test ================================================================== --- ext/rbu/rbudiff.test +++ ext/rbu/rbudiff.test @@ -22,10 +22,14 @@ db close proc get_rbudiff_sql {db1 db2} { exec $::PROG --rbu $db1 $db2 } + +proc get_vtab_rbudiff_sql {db1 db2} { + exec $::PROG --vtab --rbu $db1 $db2 +} proc step_rbu {target rbu} { while 1 { sqlite3rbu rbu $target $rbu set rc [rbu step] @@ -41,10 +45,15 @@ sqlite3 rbudb rbu.db rbudb eval $sql rbudb close step_rbu $target rbu.db } + +proc sqlesc {id} { + set ret "'[string map {' ''} $id]'" + set ret +} # The only argument is the output of an [sqldiff -rbu] run. This command # tests that the contents of the rbu_count table is correct. An exception # is thrown if it is not. # @@ -52,11 +61,11 @@ sqlite3 tmpdb "" tmpdb eval $sql tmpdb eval { SELECT name FROM sqlite_master WHERE name LIKE 'data%' AND type='table' } { - set a [tmpdb eval "SELECT count(*) FROM $name"] + set a [tmpdb eval "SELECT count(*) FROM [sqlesc $name]"] set b [tmpdb eval {SELECT cnt FROM rbu_count WHERE tbl = $name}] if {$a != $b} { tmpdb close error "rbu_count error - tbl = $name" } @@ -69,13 +78,15 @@ set txt "" sqlite3 dbtmp $db1 foreach tbl [dbtmp eval {SELECT name FROM sqlite_master WHERE type='table'}] { set cols [list] - dbtmp eval "PRAGMA table_info = $tbl" { lappend cols "quote( $name )" } + dbtmp eval "PRAGMA table_info = [sqlesc $tbl]" { + lappend cols "quote( $name )" + } append txt [dbtmp eval \ - "SELECT [join $cols {||'.'||}] FROM $tbl ORDER BY 1" + "SELECT [join $cols {||'.'||}] FROM [sqlesc $tbl] ORDER BY 1" ] } dbtmp close md5 $txt @@ -155,9 +166,61 @@ do_test 1.$tn.4 { set sql [get_rbudiff_sql test.db test.db2] apply_rbudiff $sql test.db } {SQLITE_DONE} do_test 1.$tn.5 { rbudiff_cksum test.db } [rbudiff_cksum test.db2] +} + +#------------------------------------------------------------------------- +# Test that if the --vtab switch is present, [sqldiff] handles virtual +# table types fts[345] and rtree correctly. +# +ifcapable fts3&&fts5&&rtree { + +foreach {tn init mod} { + 1 { + CREATE VIRTUAL TABLE t1 USING fts5(c); + INSERT INTO t1 VALUES('a b c'); + INSERT INTO t1 VALUES('a b c'); + } { + DELETE FROM t1 WHERE rowid = 1; + INSERT INTO t1 VALUES('a b c'); + } + + 2 { + CREATE VIRTUAL TABLE "x y" USING 'rtree'(id, x1, x2); + INSERT INTO "x y" VALUES(1, 2, 3); + INSERT INTO "x y" VALUES(2, 4, 6); + } { + DELETE FROM "x y" WHERE rowid = 1; + INSERT INTO "x y" VALUES(3, 6, 9); + } + + 3 { + CREATE VIRTUAL TABLE 'x''y' USING fts3; + INSERT INTO 'x''y' VALUES('one two three'); + INSERT INTO 'x''y' VALUES('four five six'); + } { + DELETE FROM 'x''y' WHERE rowid = 1; + INSERT INTO 'x''y' VALUES('one two three'); + } + +} { + + forcedelete test.db test.db2 + sqlite3 db test.db + db eval "$init" + sqlite3 db test.db2 + db eval "$init ; $mod" + db close + + do_test 2.$tn.1 { + set sql [get_vtab_rbudiff_sql test.db test.db2] + apply_rbudiff $sql test.db + } {SQLITE_DONE} + do_test 2.$tn.2 { rbudiff_cksum test.db } [rbudiff_cksum test.db2] +} + } finish_test Index: tool/sqldiff.c ================================================================== --- tool/sqldiff.c +++ tool/sqldiff.c @@ -31,10 +31,11 @@ */ struct GlobalVars { const char *zArgv0; /* Name of program */ int bSchemaOnly; /* Only show schema differences */ int bSchemaPK; /* Use the schema-defined PK, not the true PK */ + int bHandleVtab; /* Handle fts3, fts4, fts5 and rtree vtabs */ unsigned fDebug; /* Debug flags */ sqlite3 *db; /* The database connection */ } g; /* @@ -1732,10 +1733,148 @@ while( nCol>0 ) sqlite3_free(azCol[--nCol]); sqlite3_free(azCol); sqlite3_free(aiPk); sqlite3_free(zId); } + +/* +** Extract the next SQL keyword or quoted string from buffer zIn and copy it +** (or a prefix of it if it will not fit) into buffer zBuf, size nBuf bytes. +** Return a pointer to the character within zIn immediately following +** the token or quoted string just extracted. +*/ +const char *gobble_token(const char *zIn, char *zBuf, int nBuf){ + const char *p = zIn; + char *pOut = zBuf; + char *pEnd = &pOut[nBuf-1]; + char q = 0; /* quote character, if any */ + + if( p==0 ) return 0; + while( *p==' ' ) p++; + switch( *p ){ + case '"': q = '"'; break; + case '\'': q = '\''; break; + case '`': q = '`'; break; + case '[': q = ']'; break; + } + + if( q ){ + p++; + while( *p && pOut