diff options
author | dan <dan@noemail.net> | 2016-06-21 10:34:41 +0000 |
---|---|---|
committer | dan <dan@noemail.net> | 2016-06-21 10:34:41 +0000 |
commit | 9c987a833cf767c7d07c071c25b353623e60ad2a (patch) | |
tree | e05bfc53455b19ac47d2ba740aad815c2e7aefef /tool/sqldiff.c | |
parent | ee84b0f6906f809771bbf35405a31281a3258d74 (diff) | |
download | sqlite-9c987a833cf767c7d07c071c25b353623e60ad2a.tar.gz sqlite-9c987a833cf767c7d07c071c25b353623e60ad2a.zip |
Update the sqldiff utility so that if the --vtab switch is specified "rtree", "fts3", "fts4" and "fts5" tables are diff'd directly and the underlying real database tables ignored. Without this switch, all virtual tables are ignored and the diff is performed on the underlying real tables.
FossilOrigin-Name: 5d0a9d4c45730e47576bc77373fa7075a74051a5
Diffstat (limited to 'tool/sqldiff.c')
-rw-r--r-- | tool/sqldiff.c | 152 |
1 files changed, 144 insertions, 8 deletions
diff --git a/tool/sqldiff.c b/tool/sqldiff.c index 319acafdb..4a5389c60 100644 --- a/tool/sqldiff.c +++ b/tool/sqldiff.c @@ -33,6 +33,7 @@ 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; @@ -1736,6 +1737,144 @@ end_changeset_one_table: } /* +** 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<pEnd ){ + if( *p==q ){ + p++; + if( *p!=q ) break; + } + if( pOut<pEnd ) *pOut++ = *p; + p++; + } + }else{ + while( *p && *p!=' ' && *p!='(' ){ + if( pOut<pEnd ) *pOut++ = *p; + p++; + } + } + + *pOut = '\0'; + return p; +} + +/* +** This function is the implementation of SQL scalar function "module_name": +** +** module_name(SQL) +** +** The only argument should be an SQL statement of the type that may appear +** in the sqlite_master table. If the statement is a "CREATE VIRTUAL TABLE" +** statement, then the value returned is the name of the module that it +** uses. Otherwise, if the statement is not a CVT, NULL is returned. +*/ +static void module_name_func( + sqlite3_context *pCtx, + int nVal, sqlite3_value **apVal +){ + const char *zSql; + char zToken[32]; + + assert( nVal==1 ); + zSql = (const char*)sqlite3_value_text(apVal[0]); + + zSql = gobble_token(zSql, zToken, sizeof(zToken)); + if( zSql==0 || sqlite3_stricmp(zToken, "create") ) return; + zSql = gobble_token(zSql, zToken, sizeof(zToken)); + if( zSql==0 || sqlite3_stricmp(zToken, "virtual") ) return; + zSql = gobble_token(zSql, zToken, sizeof(zToken)); + if( zSql==0 || sqlite3_stricmp(zToken, "table") ) return; + zSql = gobble_token(zSql, zToken, sizeof(zToken)); + if( zSql==0 ) return; + zSql = gobble_token(zSql, zToken, sizeof(zToken)); + if( zSql==0 || sqlite3_stricmp(zToken, "using") ) return; + zSql = gobble_token(zSql, zToken, sizeof(zToken)); + + sqlite3_result_text(pCtx, zToken, -1, SQLITE_TRANSIENT); +} + +/* +** Return the text of an SQL statement that itself returns the list of +** tables to process within the database. +*/ +const char *all_tables_sql(){ + if( g.bHandleVtab ){ + int rc; + + rc = sqlite3_exec(g.db, + "CREATE TEMP TABLE tblmap(module, postfix);" + "INSERT INTO temp.tblmap VALUES" + "('fts3', '_content'), ('fts3', '_segments'), ('fts3', '_segdir')," + + "('fts4', '_content'), ('fts4', '_segments'), ('fts4', '_segdir')," + "('fts4', '_docsize'), ('fts4', '_stat')," + + "('fts5', '_data'), ('fts5', '_idx'), ('fts5', '_content')," + "('fts5', '_docsize'), ('fts5', '_config')," + + "('rtree', '_node'), ('rtree', '_rowid'), ('rtree', '_parent');" + , 0, 0, 0 + ); + assert( rc==SQLITE_OK ); + + rc = sqlite3_create_function( + g.db, "module_name", 1, SQLITE_UTF8, 0, module_name_func, 0, 0 + ); + assert( rc==SQLITE_OK ); + + return + "SELECT name FROM main.sqlite_master\n" + " WHERE type='table' AND (\n" + " module_name(sql) IS NULL OR \n" + " module_name(sql) IN (SELECT module FROM temp.tblmap)\n" + " ) AND name NOT IN (\n" + " SELECT a.name || b.postfix \n" + "FROM main.sqlite_master AS a, temp.tblmap AS b \n" + "WHERE module_name(a.sql) = b.module\n" + " )\n" + "UNION \n" + "SELECT name FROM aux.sqlite_master\n" + " WHERE type='table' AND (\n" + " module_name(sql) IS NULL OR \n" + " module_name(sql) IN (SELECT module FROM temp.tblmap)\n" + " ) AND name NOT IN (\n" + " SELECT a.name || b.postfix \n" + "FROM aux.sqlite_master AS a, temp.tblmap AS b \n" + "WHERE module_name(a.sql) = b.module\n" + " )\n" + " ORDER BY name"; + }else{ + return + "SELECT name FROM main.sqlite_master\n" + " WHERE type='table' AND sql NOT LIKE 'CREATE VIRTUAL%%'\n" + " UNION\n" + "SELECT name FROM aux.sqlite_master\n" + " WHERE type='table' AND sql NOT LIKE 'CREATE VIRTUAL%%'\n" + " ORDER BY name"; + } +} + +/* ** Print sketchy documentation for this utility program */ static void showHelp(void){ @@ -1751,6 +1890,7 @@ static void showHelp(void){ " --summary Show only a summary of the differences\n" " --table TAB Show only differences in table TAB\n" " --transaction Show SQL output inside a transaction\n" +" --vtab Handle fts3, fts4, fts5 and rtree tables\n" ); } @@ -1821,6 +1961,9 @@ int main(int argc, char **argv){ if( strcmp(z,"transaction")==0 ){ useTransaction = 1; }else + if( strcmp(z,"vtab")==0 ){ + g.bHandleVtab = 1; + }else { cmdlineError("unknown option: %s", argv[i]); } @@ -1875,14 +2018,7 @@ int main(int argc, char **argv){ xDiff(zTab, out); }else{ /* Handle tables one by one */ - pStmt = db_prepare( - "SELECT name FROM main.sqlite_master\n" - " WHERE type='table' AND sql NOT LIKE 'CREATE VIRTUAL%%'\n" - " UNION\n" - "SELECT name FROM aux.sqlite_master\n" - " WHERE type='table' AND sql NOT LIKE 'CREATE VIRTUAL%%'\n" - " ORDER BY name" - ); + pStmt = db_prepare( all_tables_sql() ); while( SQLITE_ROW==sqlite3_step(pStmt) ){ xDiff((const char*)sqlite3_column_text(pStmt,0), out); } |