OLD | NEW |
1 /* | 1 /* |
2 ** 2015-04-06 | 2 ** 2015-04-06 |
3 ** | 3 ** |
4 ** The author disclaims copyright to this source code. In place of | 4 ** The author disclaims copyright to this source code. In place of |
5 ** a legal notice, here is a blessing: | 5 ** a legal notice, here is a blessing: |
6 ** | 6 ** |
7 ** May you do good and not evil. | 7 ** May you do good and not evil. |
8 ** May you find forgiveness for yourself and forgive others. | 8 ** May you find forgiveness for yourself and forgive others. |
9 ** May you share freely, never taking more than you give. | 9 ** May you share freely, never taking more than you give. |
10 ** | 10 ** |
(...skipping 15 matching lines...) Expand all Loading... |
26 #include <assert.h> | 26 #include <assert.h> |
27 #include "sqlite3.h" | 27 #include "sqlite3.h" |
28 | 28 |
29 /* | 29 /* |
30 ** All global variables are gathered into the "g" singleton. | 30 ** All global variables are gathered into the "g" singleton. |
31 */ | 31 */ |
32 struct GlobalVars { | 32 struct GlobalVars { |
33 const char *zArgv0; /* Name of program */ | 33 const char *zArgv0; /* Name of program */ |
34 int bSchemaOnly; /* Only show schema differences */ | 34 int bSchemaOnly; /* Only show schema differences */ |
35 int bSchemaPK; /* Use the schema-defined PK, not the true PK */ | 35 int bSchemaPK; /* Use the schema-defined PK, not the true PK */ |
| 36 int bHandleVtab; /* Handle fts3, fts4, fts5 and rtree vtabs */ |
36 unsigned fDebug; /* Debug flags */ | 37 unsigned fDebug; /* Debug flags */ |
37 sqlite3 *db; /* The database connection */ | 38 sqlite3 *db; /* The database connection */ |
38 } g; | 39 } g; |
39 | 40 |
40 /* | 41 /* |
41 ** Allowed values for g.fDebug | 42 ** Allowed values for g.fDebug |
42 */ | 43 */ |
43 #define DEBUG_COLUMN_NAMES 0x000001 | 44 #define DEBUG_COLUMN_NAMES 0x000001 |
44 #define DEBUG_DIFF_SQL 0x000002 | 45 #define DEBUG_DIFF_SQL 0x000002 |
45 | 46 |
(...skipping 349 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
395 const unsigned char *zBlob = sqlite3_value_blob(X); | 396 const unsigned char *zBlob = sqlite3_value_blob(X); |
396 int nBlob = sqlite3_value_bytes(X); | 397 int nBlob = sqlite3_value_bytes(X); |
397 if( zBlob ){ | 398 if( zBlob ){ |
398 int i; | 399 int i; |
399 fprintf(out, "x'"); | 400 fprintf(out, "x'"); |
400 for(i=0; i<nBlob; i++){ | 401 for(i=0; i<nBlob; i++){ |
401 fprintf(out, "%02x", zBlob[i]); | 402 fprintf(out, "%02x", zBlob[i]); |
402 } | 403 } |
403 fprintf(out, "'"); | 404 fprintf(out, "'"); |
404 }else{ | 405 }else{ |
405 fprintf(out, "NULL"); | 406 /* Could be an OOM, could be a zero-byte blob */ |
| 407 fprintf(out, "X''"); |
406 } | 408 } |
407 break; | 409 break; |
408 } | 410 } |
409 case SQLITE_TEXT: { | 411 case SQLITE_TEXT: { |
410 const unsigned char *zArg = sqlite3_value_text(X); | 412 const unsigned char *zArg = sqlite3_value_text(X); |
411 int i, j; | 413 int i, j; |
412 | 414 |
413 if( zArg==0 ){ | 415 if( zArg==0 ){ |
414 fprintf(out, "NULL"); | 416 fprintf(out, "NULL"); |
415 }else{ | 417 }else{ |
(...skipping 260 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
676 zTab, zTab); | 678 zTab, zTab); |
677 while( SQLITE_ROW==sqlite3_step(pStmt) ){ | 679 while( SQLITE_ROW==sqlite3_step(pStmt) ){ |
678 char *z = safeId((const char*)sqlite3_column_text(pStmt,0)); | 680 char *z = safeId((const char*)sqlite3_column_text(pStmt,0)); |
679 fprintf(out, "DROP INDEX %s;\n", z); | 681 fprintf(out, "DROP INDEX %s;\n", z); |
680 sqlite3_free(z); | 682 sqlite3_free(z); |
681 } | 683 } |
682 sqlite3_finalize(pStmt); | 684 sqlite3_finalize(pStmt); |
683 | 685 |
684 /* Run the query and output differences */ | 686 /* Run the query and output differences */ |
685 if( !g.bSchemaOnly ){ | 687 if( !g.bSchemaOnly ){ |
686 pStmt = db_prepare(sql.z); | 688 pStmt = db_prepare("%s", sql.z); |
687 while( SQLITE_ROW==sqlite3_step(pStmt) ){ | 689 while( SQLITE_ROW==sqlite3_step(pStmt) ){ |
688 int iType = sqlite3_column_int(pStmt, nPk); | 690 int iType = sqlite3_column_int(pStmt, nPk); |
689 if( iType==1 || iType==2 ){ | 691 if( iType==1 || iType==2 ){ |
690 if( iType==1 ){ /* Change the content of a row */ | 692 if( iType==1 ){ /* Change the content of a row */ |
691 fprintf(out, "UPDATE %s", zId); | 693 fprintf(out, "UPDATE %s", zId); |
692 zSep = " SET"; | 694 zSep = " SET"; |
693 for(i=nPk+1; i<nQ; i+=2){ | 695 for(i=nPk+1; i<nQ; i+=2){ |
694 if( sqlite3_column_int(pStmt,i)==0 ) continue; | 696 if( sqlite3_column_int(pStmt,i)==0 ) continue; |
695 fprintf(out, "%s %s=", zSep, az2[(i+nPk-1)/2]); | 697 fprintf(out, "%s %s=", zSep, az2[(i+nPk-1)/2]); |
696 zSep = ","; | 698 zSep = ","; |
(...skipping 290 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
987 ** chance of ever doing a copy command. Just output a single | 989 ** chance of ever doing a copy command. Just output a single |
988 ** literal segment for the entire target and exit. | 990 ** literal segment for the entire target and exit. |
989 */ | 991 */ |
990 if( lenSrc<=NHASH ){ | 992 if( lenSrc<=NHASH ){ |
991 putInt(lenOut, &zDelta); | 993 putInt(lenOut, &zDelta); |
992 *(zDelta++) = ':'; | 994 *(zDelta++) = ':'; |
993 memcpy(zDelta, zOut, lenOut); | 995 memcpy(zDelta, zOut, lenOut); |
994 zDelta += lenOut; | 996 zDelta += lenOut; |
995 putInt(checksum(zOut, lenOut), &zDelta); | 997 putInt(checksum(zOut, lenOut), &zDelta); |
996 *(zDelta++) = ';'; | 998 *(zDelta++) = ';'; |
997 return zDelta - zOrigDelta; | 999 return (int)(zDelta - zOrigDelta); |
998 } | 1000 } |
999 | 1001 |
1000 /* Compute the hash table used to locate matching sections in the | 1002 /* Compute the hash table used to locate matching sections in the |
1001 ** source file. | 1003 ** source file. |
1002 */ | 1004 */ |
1003 nHash = lenSrc/NHASH; | 1005 nHash = lenSrc/NHASH; |
1004 collide = sqlite3_malloc( nHash*2*sizeof(int) ); | 1006 collide = sqlite3_malloc( nHash*2*sizeof(int) ); |
1005 landmark = &collide[nHash]; | 1007 landmark = &collide[nHash]; |
1006 memset(landmark, -1, nHash*sizeof(int)); | 1008 memset(landmark, -1, nHash*sizeof(int)); |
1007 memset(collide, -1, nHash*sizeof(int)); | 1009 memset(collide, -1, nHash*sizeof(int)); |
(...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1134 if( base<lenOut ){ | 1136 if( base<lenOut ){ |
1135 putInt(lenOut-base, &zDelta); | 1137 putInt(lenOut-base, &zDelta); |
1136 *(zDelta++) = ':'; | 1138 *(zDelta++) = ':'; |
1137 memcpy(zDelta, &zOut[base], lenOut-base); | 1139 memcpy(zDelta, &zOut[base], lenOut-base); |
1138 zDelta += lenOut-base; | 1140 zDelta += lenOut-base; |
1139 } | 1141 } |
1140 /* Output the final checksum record. */ | 1142 /* Output the final checksum record. */ |
1141 putInt(checksum(zOut, lenOut), &zDelta); | 1143 putInt(checksum(zOut, lenOut), &zDelta); |
1142 *(zDelta++) = ';'; | 1144 *(zDelta++) = ';'; |
1143 sqlite3_free(collide); | 1145 sqlite3_free(collide); |
1144 return zDelta - zOrigDelta; | 1146 return (int)(zDelta - zOrigDelta); |
1145 } | 1147 } |
1146 | 1148 |
1147 /* | 1149 /* |
1148 ** End of code copied from fossil. | 1150 ** End of code copied from fossil. |
1149 **************************************************************************/ | 1151 **************************************************************************/ |
1150 | 1152 |
1151 static void strPrintfArray( | 1153 static void strPrintfArray( |
1152 Str *pStr, /* String object to append to */ | 1154 Str *pStr, /* String object to append to */ |
1153 const char *zSep, /* Separator string */ | 1155 const char *zSep, /* Separator string */ |
1154 const char *zFmt, /* Format for each entry */ | 1156 const char *zFmt, /* Format for each entry */ |
(...skipping 16 matching lines...) Expand all Loading... |
1171 int i; | 1173 int i; |
1172 | 1174 |
1173 /* First the newly inserted rows: **/ | 1175 /* First the newly inserted rows: **/ |
1174 strPrintf(pSql, "SELECT "); | 1176 strPrintf(pSql, "SELECT "); |
1175 strPrintfArray(pSql, ", ", "%s", azCol, -1); | 1177 strPrintfArray(pSql, ", ", "%s", azCol, -1); |
1176 strPrintf(pSql, ", 0, "); /* Set ota_control to 0 for an insert */ | 1178 strPrintf(pSql, ", 0, "); /* Set ota_control to 0 for an insert */ |
1177 strPrintfArray(pSql, ", ", "NULL", azCol, -1); | 1179 strPrintfArray(pSql, ", ", "NULL", azCol, -1); |
1178 strPrintf(pSql, " FROM aux.%Q AS n WHERE NOT EXISTS (\n", zTab); | 1180 strPrintf(pSql, " FROM aux.%Q AS n WHERE NOT EXISTS (\n", zTab); |
1179 strPrintf(pSql, " SELECT 1 FROM ", zTab); | 1181 strPrintf(pSql, " SELECT 1 FROM ", zTab); |
1180 strPrintf(pSql, " main.%Q AS o WHERE ", zTab); | 1182 strPrintf(pSql, " main.%Q AS o WHERE ", zTab); |
1181 strPrintfArray(pSql, " AND ", "(n.%Q IS o.%Q)", azCol, nPK); | 1183 strPrintfArray(pSql, " AND ", "(n.%Q = o.%Q)", azCol, nPK); |
1182 strPrintf(pSql, "\n)"); | 1184 strPrintf(pSql, "\n) AND "); |
| 1185 strPrintfArray(pSql, " AND ", "(n.%Q IS NOT NULL)", azCol, nPK); |
1183 | 1186 |
1184 /* Deleted rows: */ | 1187 /* Deleted rows: */ |
1185 strPrintf(pSql, "\nUNION ALL\nSELECT "); | 1188 strPrintf(pSql, "\nUNION ALL\nSELECT "); |
1186 strPrintfArray(pSql, ", ", "%s", azCol, nPK); | 1189 strPrintfArray(pSql, ", ", "%s", azCol, nPK); |
1187 if( azCol[nPK] ){ | 1190 if( azCol[nPK] ){ |
1188 strPrintf(pSql, ", "); | 1191 strPrintf(pSql, ", "); |
1189 strPrintfArray(pSql, ", ", "NULL", &azCol[nPK], -1); | 1192 strPrintfArray(pSql, ", ", "NULL", &azCol[nPK], -1); |
1190 } | 1193 } |
1191 strPrintf(pSql, ", 1, "); /* Set ota_control to 1 for a delete */ | 1194 strPrintf(pSql, ", 1, "); /* Set ota_control to 1 for a delete */ |
1192 strPrintfArray(pSql, ", ", "NULL", azCol, -1); | 1195 strPrintfArray(pSql, ", ", "NULL", azCol, -1); |
1193 strPrintf(pSql, " FROM main.%Q AS n WHERE NOT EXISTS (\n", zTab); | 1196 strPrintf(pSql, " FROM main.%Q AS n WHERE NOT EXISTS (\n", zTab); |
1194 strPrintf(pSql, " SELECT 1 FROM ", zTab); | 1197 strPrintf(pSql, " SELECT 1 FROM ", zTab); |
1195 strPrintf(pSql, " aux.%Q AS o WHERE ", zTab); | 1198 strPrintf(pSql, " aux.%Q AS o WHERE ", zTab); |
1196 strPrintfArray(pSql, " AND ", "(n.%Q IS o.%Q)", azCol, nPK); | 1199 strPrintfArray(pSql, " AND ", "(n.%Q = o.%Q)", azCol, nPK); |
1197 strPrintf(pSql, "\n) "); | 1200 strPrintf(pSql, "\n) AND "); |
| 1201 strPrintfArray(pSql, " AND ", "(n.%Q IS NOT NULL)", azCol, nPK); |
1198 | 1202 |
1199 /* Updated rows. If all table columns are part of the primary key, there | 1203 /* Updated rows. If all table columns are part of the primary key, there |
1200 ** can be no updates. In this case this part of the compound SELECT can | 1204 ** can be no updates. In this case this part of the compound SELECT can |
1201 ** be omitted altogether. */ | 1205 ** be omitted altogether. */ |
1202 if( azCol[nPK] ){ | 1206 if( azCol[nPK] ){ |
1203 strPrintf(pSql, "\nUNION ALL\nSELECT "); | 1207 strPrintf(pSql, "\nUNION ALL\nSELECT "); |
1204 strPrintfArray(pSql, ", ", "n.%s", azCol, nPK); | 1208 strPrintfArray(pSql, ", ", "n.%s", azCol, nPK); |
1205 strPrintf(pSql, ",\n"); | 1209 strPrintf(pSql, ",\n"); |
1206 strPrintfArray(pSql, " ,\n", | 1210 strPrintfArray(pSql, " ,\n", |
1207 " CASE WHEN n.%s IS o.%s THEN NULL ELSE n.%s END", &azCol[nPK], -1 | 1211 " CASE WHEN n.%s IS o.%s THEN NULL ELSE n.%s END", &azCol[nPK], -1 |
(...skipping 10 matching lines...) Expand all Loading... |
1218 " CASE WHEN n.%s IS o.%s THEN '.' ELSE 'x' END", &azCol[nPK], -1 | 1222 " CASE WHEN n.%s IS o.%s THEN '.' ELSE 'x' END", &azCol[nPK], -1 |
1219 ); | 1223 ); |
1220 strPrintf(pSql, "\nAS ota_control, "); | 1224 strPrintf(pSql, "\nAS ota_control, "); |
1221 strPrintfArray(pSql, ", ", "NULL", azCol, nPK); | 1225 strPrintfArray(pSql, ", ", "NULL", azCol, nPK); |
1222 strPrintf(pSql, ",\n"); | 1226 strPrintf(pSql, ",\n"); |
1223 strPrintfArray(pSql, " ,\n", | 1227 strPrintfArray(pSql, " ,\n", |
1224 " CASE WHEN n.%s IS o.%s THEN NULL ELSE o.%s END", &azCol[nPK], -1 | 1228 " CASE WHEN n.%s IS o.%s THEN NULL ELSE o.%s END", &azCol[nPK], -1 |
1225 ); | 1229 ); |
1226 | 1230 |
1227 strPrintf(pSql, "\nFROM main.%Q AS o, aux.%Q AS n\nWHERE ", zTab, zTab); | 1231 strPrintf(pSql, "\nFROM main.%Q AS o, aux.%Q AS n\nWHERE ", zTab, zTab); |
1228 strPrintfArray(pSql, " AND ", "(n.%Q IS o.%Q)", azCol, nPK); | 1232 strPrintfArray(pSql, " AND ", "(n.%Q = o.%Q)", azCol, nPK); |
1229 strPrintf(pSql, " AND ota_control LIKE '%%x%%'"); | 1233 strPrintf(pSql, " AND ota_control LIKE '%%x%%'"); |
1230 } | 1234 } |
1231 | 1235 |
1232 /* Now add an ORDER BY clause to sort everything by PK. */ | 1236 /* Now add an ORDER BY clause to sort everything by PK. */ |
1233 strPrintf(pSql, "\nORDER BY "); | 1237 strPrintf(pSql, "\nORDER BY "); |
1234 for(i=1; i<=nPK; i++) strPrintf(pSql, "%s%d", ((i>1)?", ":""), i); | 1238 for(i=1; i<=nPK; i++) strPrintf(pSql, "%s%d", ((i>1)?", ":""), i); |
1235 } | 1239 } |
1236 | 1240 |
1237 static void rbudiff_one_table(const char *zTab, FILE *out){ | 1241 static void rbudiff_one_table(const char *zTab, FILE *out){ |
1238 int bOtaRowid; /* True to use an ota_rowid column */ | 1242 int bOtaRowid; /* True to use an ota_rowid column */ |
1239 int nPK; /* Number of primary key columns in table */ | 1243 int nPK; /* Number of primary key columns in table */ |
1240 char **azCol; /* NULL terminated array of col names */ | 1244 char **azCol; /* NULL terminated array of col names */ |
1241 int i; | 1245 int i; |
1242 int nCol; | 1246 int nCol; |
1243 Str ct = {0, 0, 0}; /* The "CREATE TABLE data_xxx" statement */ | 1247 Str ct = {0, 0, 0}; /* The "CREATE TABLE data_xxx" statement */ |
1244 Str sql = {0, 0, 0}; /* Query to find differences */ | 1248 Str sql = {0, 0, 0}; /* Query to find differences */ |
1245 Str insert = {0, 0, 0}; /* First part of output INSERT statement */ | 1249 Str insert = {0, 0, 0}; /* First part of output INSERT statement */ |
1246 sqlite3_stmt *pStmt = 0; | 1250 sqlite3_stmt *pStmt = 0; |
| 1251 int nRow = 0; /* Total rows in data_xxx table */ |
1247 | 1252 |
1248 /* --rbu mode must use real primary keys. */ | 1253 /* --rbu mode must use real primary keys. */ |
1249 g.bSchemaPK = 1; | 1254 g.bSchemaPK = 1; |
1250 | 1255 |
1251 /* Check that the schemas of the two tables match. Exit early otherwise. */ | 1256 /* Check that the schemas of the two tables match. Exit early otherwise. */ |
1252 checkSchemasMatch(zTab); | 1257 checkSchemasMatch(zTab); |
1253 | 1258 |
1254 /* Grab the column names and PK details for the table(s). If no usable PK | 1259 /* Grab the column names and PK details for the table(s). If no usable PK |
1255 ** columns are found, bail out early. */ | 1260 ** columns are found, bail out early. */ |
1256 azCol = columnNames("main", zTab, &nPK, &bOtaRowid); | 1261 azCol = columnNames("main", zTab, &nPK, &bOtaRowid); |
(...skipping 25 matching lines...) Expand all Loading... |
1282 /* If this is the first row output, print out the CREATE TABLE | 1287 /* If this is the first row output, print out the CREATE TABLE |
1283 ** statement first. And then set ct.z to NULL so that it is not | 1288 ** statement first. And then set ct.z to NULL so that it is not |
1284 ** printed again. */ | 1289 ** printed again. */ |
1285 if( ct.z ){ | 1290 if( ct.z ){ |
1286 fprintf(out, "%s\n", ct.z); | 1291 fprintf(out, "%s\n", ct.z); |
1287 strFree(&ct); | 1292 strFree(&ct); |
1288 } | 1293 } |
1289 | 1294 |
1290 /* Output the first part of the INSERT statement */ | 1295 /* Output the first part of the INSERT statement */ |
1291 fprintf(out, "%s", insert.z); | 1296 fprintf(out, "%s", insert.z); |
| 1297 nRow++; |
1292 | 1298 |
1293 if( sqlite3_column_type(pStmt, nCol)==SQLITE_INTEGER ){ | 1299 if( sqlite3_column_type(pStmt, nCol)==SQLITE_INTEGER ){ |
1294 for(i=0; i<=nCol; i++){ | 1300 for(i=0; i<=nCol; i++){ |
1295 if( i>0 ) fprintf(out, ", "); | 1301 if( i>0 ) fprintf(out, ", "); |
1296 printQuoted(out, sqlite3_column_value(pStmt, i)); | 1302 printQuoted(out, sqlite3_column_value(pStmt, i)); |
1297 } | 1303 } |
1298 }else{ | 1304 }else{ |
1299 char *zOtaControl; | 1305 char *zOtaControl; |
1300 int nOtaControl = sqlite3_column_bytes(pStmt, nCol); | 1306 int nOtaControl = sqlite3_column_bytes(pStmt, nCol); |
1301 | 1307 |
1302 zOtaControl = (char*)sqlite3_malloc(nOtaControl); | 1308 zOtaControl = (char*)sqlite3_malloc(nOtaControl+1); |
1303 memcpy(zOtaControl, sqlite3_column_text(pStmt, nCol), nOtaControl+1); | 1309 memcpy(zOtaControl, sqlite3_column_text(pStmt, nCol), nOtaControl+1); |
1304 | 1310 |
1305 for(i=0; i<nCol; i++){ | 1311 for(i=0; i<nCol; i++){ |
1306 int bDone = 0; | 1312 int bDone = 0; |
1307 if( i>=nPK | 1313 if( i>=nPK |
1308 && sqlite3_column_type(pStmt, i)==SQLITE_BLOB | 1314 && sqlite3_column_type(pStmt, i)==SQLITE_BLOB |
1309 && sqlite3_column_type(pStmt, nCol+1+i)==SQLITE_BLOB | 1315 && sqlite3_column_type(pStmt, nCol+1+i)==SQLITE_BLOB |
1310 ){ | 1316 ){ |
1311 const char *aSrc = sqlite3_column_blob(pStmt, nCol+1+i); | 1317 const char *aSrc = sqlite3_column_blob(pStmt, nCol+1+i); |
1312 int nSrc = sqlite3_column_bytes(pStmt, nCol+1+i); | 1318 int nSrc = sqlite3_column_bytes(pStmt, nCol+1+i); |
(...skipping 22 matching lines...) Expand all Loading... |
1335 } | 1341 } |
1336 fprintf(out, "'%s'", zOtaControl); | 1342 fprintf(out, "'%s'", zOtaControl); |
1337 sqlite3_free(zOtaControl); | 1343 sqlite3_free(zOtaControl); |
1338 } | 1344 } |
1339 | 1345 |
1340 /* And the closing bracket of the insert statement */ | 1346 /* And the closing bracket of the insert statement */ |
1341 fprintf(out, ");\n"); | 1347 fprintf(out, ");\n"); |
1342 } | 1348 } |
1343 | 1349 |
1344 sqlite3_finalize(pStmt); | 1350 sqlite3_finalize(pStmt); |
| 1351 if( nRow>0 ){ |
| 1352 Str cnt = {0, 0, 0}; |
| 1353 strPrintf(&cnt, "INSERT INTO rbu_count VALUES('data_%q', %d);", zTab, nRow); |
| 1354 fprintf(out, "%s\n", cnt.z); |
| 1355 strFree(&cnt); |
| 1356 } |
1345 | 1357 |
1346 strFree(&ct); | 1358 strFree(&ct); |
1347 strFree(&sql); | 1359 strFree(&sql); |
1348 strFree(&insert); | 1360 strFree(&insert); |
1349 } | 1361 } |
1350 | 1362 |
1351 /* | 1363 /* |
1352 ** Display a summary of differences between two versions of the same | 1364 ** Display a summary of differences between two versions of the same |
1353 ** table table. | 1365 ** table table. |
1354 ** | 1366 ** |
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1445 zSep = " AND"; | 1457 zSep = " AND"; |
1446 } | 1458 } |
1447 strPrintf(&sql, ")\n ORDER BY 1;\n"); | 1459 strPrintf(&sql, ")\n ORDER BY 1;\n"); |
1448 | 1460 |
1449 if( (g.fDebug & DEBUG_DIFF_SQL)!=0 ){ | 1461 if( (g.fDebug & DEBUG_DIFF_SQL)!=0 ){ |
1450 printf("SQL for %s:\n%s\n", zId, sql.z); | 1462 printf("SQL for %s:\n%s\n", zId, sql.z); |
1451 goto end_summarize_one_table; | 1463 goto end_summarize_one_table; |
1452 } | 1464 } |
1453 | 1465 |
1454 /* Run the query and output difference summary */ | 1466 /* Run the query and output difference summary */ |
1455 pStmt = db_prepare(sql.z); | 1467 pStmt = db_prepare("%s", sql.z); |
1456 nUpdate = 0; | 1468 nUpdate = 0; |
1457 nInsert = 0; | 1469 nInsert = 0; |
1458 nDelete = 0; | 1470 nDelete = 0; |
1459 nUnchanged = 0; | 1471 nUnchanged = 0; |
1460 while( SQLITE_ROW==sqlite3_step(pStmt) ){ | 1472 while( SQLITE_ROW==sqlite3_step(pStmt) ){ |
1461 switch( sqlite3_column_int(pStmt,0) ){ | 1473 switch( sqlite3_column_int(pStmt,0) ){ |
1462 case 1: | 1474 case 1: |
1463 nUpdate = sqlite3_column_int64(pStmt,2); | 1475 nUpdate = sqlite3_column_int64(pStmt,2); |
1464 nUnchanged = sqlite3_column_int64(pStmt,1) - nUpdate; | 1476 nUnchanged = sqlite3_column_int64(pStmt,1) - nUpdate; |
1465 break; | 1477 break; |
(...skipping 255 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1721 sqlite3_finalize(pStmt); | 1733 sqlite3_finalize(pStmt); |
1722 | 1734 |
1723 end_changeset_one_table: | 1735 end_changeset_one_table: |
1724 while( nCol>0 ) sqlite3_free(azCol[--nCol]); | 1736 while( nCol>0 ) sqlite3_free(azCol[--nCol]); |
1725 sqlite3_free(azCol); | 1737 sqlite3_free(azCol); |
1726 sqlite3_free(aiPk); | 1738 sqlite3_free(aiPk); |
1727 sqlite3_free(zId); | 1739 sqlite3_free(zId); |
1728 } | 1740 } |
1729 | 1741 |
1730 /* | 1742 /* |
| 1743 ** Extract the next SQL keyword or quoted string from buffer zIn and copy it |
| 1744 ** (or a prefix of it if it will not fit) into buffer zBuf, size nBuf bytes. |
| 1745 ** Return a pointer to the character within zIn immediately following |
| 1746 ** the token or quoted string just extracted. |
| 1747 */ |
| 1748 const char *gobble_token(const char *zIn, char *zBuf, int nBuf){ |
| 1749 const char *p = zIn; |
| 1750 char *pOut = zBuf; |
| 1751 char *pEnd = &pOut[nBuf-1]; |
| 1752 char q = 0; /* quote character, if any */ |
| 1753 |
| 1754 if( p==0 ) return 0; |
| 1755 while( *p==' ' ) p++; |
| 1756 switch( *p ){ |
| 1757 case '"': q = '"'; break; |
| 1758 case '\'': q = '\''; break; |
| 1759 case '`': q = '`'; break; |
| 1760 case '[': q = ']'; break; |
| 1761 } |
| 1762 |
| 1763 if( q ){ |
| 1764 p++; |
| 1765 while( *p && pOut<pEnd ){ |
| 1766 if( *p==q ){ |
| 1767 p++; |
| 1768 if( *p!=q ) break; |
| 1769 } |
| 1770 if( pOut<pEnd ) *pOut++ = *p; |
| 1771 p++; |
| 1772 } |
| 1773 }else{ |
| 1774 while( *p && *p!=' ' && *p!='(' ){ |
| 1775 if( pOut<pEnd ) *pOut++ = *p; |
| 1776 p++; |
| 1777 } |
| 1778 } |
| 1779 |
| 1780 *pOut = '\0'; |
| 1781 return p; |
| 1782 } |
| 1783 |
| 1784 /* |
| 1785 ** This function is the implementation of SQL scalar function "module_name": |
| 1786 ** |
| 1787 ** module_name(SQL) |
| 1788 ** |
| 1789 ** The only argument should be an SQL statement of the type that may appear |
| 1790 ** in the sqlite_master table. If the statement is a "CREATE VIRTUAL TABLE" |
| 1791 ** statement, then the value returned is the name of the module that it |
| 1792 ** uses. Otherwise, if the statement is not a CVT, NULL is returned. |
| 1793 */ |
| 1794 static void module_name_func( |
| 1795 sqlite3_context *pCtx, |
| 1796 int nVal, sqlite3_value **apVal |
| 1797 ){ |
| 1798 const char *zSql; |
| 1799 char zToken[32]; |
| 1800 |
| 1801 assert( nVal==1 ); |
| 1802 zSql = (const char*)sqlite3_value_text(apVal[0]); |
| 1803 |
| 1804 zSql = gobble_token(zSql, zToken, sizeof(zToken)); |
| 1805 if( zSql==0 || sqlite3_stricmp(zToken, "create") ) return; |
| 1806 zSql = gobble_token(zSql, zToken, sizeof(zToken)); |
| 1807 if( zSql==0 || sqlite3_stricmp(zToken, "virtual") ) return; |
| 1808 zSql = gobble_token(zSql, zToken, sizeof(zToken)); |
| 1809 if( zSql==0 || sqlite3_stricmp(zToken, "table") ) return; |
| 1810 zSql = gobble_token(zSql, zToken, sizeof(zToken)); |
| 1811 if( zSql==0 ) return; |
| 1812 zSql = gobble_token(zSql, zToken, sizeof(zToken)); |
| 1813 if( zSql==0 || sqlite3_stricmp(zToken, "using") ) return; |
| 1814 zSql = gobble_token(zSql, zToken, sizeof(zToken)); |
| 1815 |
| 1816 sqlite3_result_text(pCtx, zToken, -1, SQLITE_TRANSIENT); |
| 1817 } |
| 1818 |
| 1819 /* |
| 1820 ** Return the text of an SQL statement that itself returns the list of |
| 1821 ** tables to process within the database. |
| 1822 */ |
| 1823 const char *all_tables_sql(){ |
| 1824 if( g.bHandleVtab ){ |
| 1825 int rc; |
| 1826 |
| 1827 rc = sqlite3_exec(g.db, |
| 1828 "CREATE TEMP TABLE tblmap(module COLLATE nocase, postfix);" |
| 1829 "INSERT INTO temp.tblmap VALUES" |
| 1830 "('fts3', '_content'), ('fts3', '_segments'), ('fts3', '_segdir')," |
| 1831 |
| 1832 "('fts4', '_content'), ('fts4', '_segments'), ('fts4', '_segdir')," |
| 1833 "('fts4', '_docsize'), ('fts4', '_stat')," |
| 1834 |
| 1835 "('fts5', '_data'), ('fts5', '_idx'), ('fts5', '_content')," |
| 1836 "('fts5', '_docsize'), ('fts5', '_config')," |
| 1837 |
| 1838 "('rtree', '_node'), ('rtree', '_rowid'), ('rtree', '_parent');" |
| 1839 , 0, 0, 0 |
| 1840 ); |
| 1841 assert( rc==SQLITE_OK ); |
| 1842 |
| 1843 rc = sqlite3_create_function( |
| 1844 g.db, "module_name", 1, SQLITE_UTF8, 0, module_name_func, 0, 0 |
| 1845 ); |
| 1846 assert( rc==SQLITE_OK ); |
| 1847 |
| 1848 return |
| 1849 "SELECT name FROM main.sqlite_master\n" |
| 1850 " WHERE type='table' AND (\n" |
| 1851 " module_name(sql) IS NULL OR \n" |
| 1852 " module_name(sql) IN (SELECT module FROM temp.tblmap)\n" |
| 1853 " ) AND name NOT IN (\n" |
| 1854 " SELECT a.name || b.postfix \n" |
| 1855 "FROM main.sqlite_master AS a, temp.tblmap AS b \n" |
| 1856 "WHERE module_name(a.sql) = b.module\n" |
| 1857 " )\n" |
| 1858 "UNION \n" |
| 1859 "SELECT name FROM aux.sqlite_master\n" |
| 1860 " WHERE type='table' AND (\n" |
| 1861 " module_name(sql) IS NULL OR \n" |
| 1862 " module_name(sql) IN (SELECT module FROM temp.tblmap)\n" |
| 1863 " ) AND name NOT IN (\n" |
| 1864 " SELECT a.name || b.postfix \n" |
| 1865 "FROM aux.sqlite_master AS a, temp.tblmap AS b \n" |
| 1866 "WHERE module_name(a.sql) = b.module\n" |
| 1867 " )\n" |
| 1868 " ORDER BY name"; |
| 1869 }else{ |
| 1870 return |
| 1871 "SELECT name FROM main.sqlite_master\n" |
| 1872 " WHERE type='table' AND sql NOT LIKE 'CREATE VIRTUAL%%'\n" |
| 1873 " UNION\n" |
| 1874 "SELECT name FROM aux.sqlite_master\n" |
| 1875 " WHERE type='table' AND sql NOT LIKE 'CREATE VIRTUAL%%'\n" |
| 1876 " ORDER BY name"; |
| 1877 } |
| 1878 } |
| 1879 |
| 1880 /* |
1731 ** Print sketchy documentation for this utility program | 1881 ** Print sketchy documentation for this utility program |
1732 */ | 1882 */ |
1733 static void showHelp(void){ | 1883 static void showHelp(void){ |
1734 printf("Usage: %s [options] DB1 DB2\n", g.zArgv0); | 1884 printf("Usage: %s [options] DB1 DB2\n", g.zArgv0); |
1735 printf( | 1885 printf( |
1736 "Output SQL text that would transform DB1 into DB2.\n" | 1886 "Output SQL text that would transform DB1 into DB2.\n" |
1737 "Options:\n" | 1887 "Options:\n" |
1738 " --changeset FILE Write a CHANGESET into FILE\n" | 1888 " --changeset FILE Write a CHANGESET into FILE\n" |
1739 " -L|--lib LIBRARY Load an SQLite extension library\n" | 1889 " -L|--lib LIBRARY Load an SQLite extension library\n" |
1740 " --primarykey Use schema-defined PRIMARY KEYs\n" | 1890 " --primarykey Use schema-defined PRIMARY KEYs\n" |
1741 " --rbu Output SQL to create/populate RBU table(s)\n" | 1891 " --rbu Output SQL to create/populate RBU table(s)\n" |
1742 " --schema Show only differences in the schema\n" | 1892 " --schema Show only differences in the schema\n" |
1743 " --summary Show only a summary of the differences\n" | 1893 " --summary Show only a summary of the differences\n" |
1744 " --table TAB Show only differences in table TAB\n" | 1894 " --table TAB Show only differences in table TAB\n" |
1745 " --transaction Show SQL output inside a transaction\n" | 1895 " --transaction Show SQL output inside a transaction\n" |
| 1896 " --vtab Handle fts3, fts4, fts5 and rtree tables\n" |
1746 ); | 1897 ); |
1747 } | 1898 } |
1748 | 1899 |
1749 int main(int argc, char **argv){ | 1900 int main(int argc, char **argv){ |
1750 const char *zDb1 = 0; | 1901 const char *zDb1 = 0; |
1751 const char *zDb2 = 0; | 1902 const char *zDb2 = 0; |
1752 int i; | 1903 int i; |
1753 int rc; | 1904 int rc; |
1754 char *zErrMsg = 0; | 1905 char *zErrMsg = 0; |
1755 char *zSql; | 1906 char *zSql; |
1756 sqlite3_stmt *pStmt; | 1907 sqlite3_stmt *pStmt; |
1757 char *zTab = 0; | 1908 char *zTab = 0; |
1758 FILE *out = stdout; | 1909 FILE *out = stdout; |
1759 void (*xDiff)(const char*,FILE*) = diff_one_table; | 1910 void (*xDiff)(const char*,FILE*) = diff_one_table; |
| 1911 #ifndef SQLITE_OMIT_LOAD_EXTENSION |
1760 int nExt = 0; | 1912 int nExt = 0; |
1761 char **azExt = 0; | 1913 char **azExt = 0; |
| 1914 #endif |
1762 int useTransaction = 0; | 1915 int useTransaction = 0; |
1763 int neverUseTransaction = 0; | 1916 int neverUseTransaction = 0; |
1764 | 1917 |
1765 g.zArgv0 = argv[0]; | 1918 g.zArgv0 = argv[0]; |
1766 sqlite3_config(SQLITE_CONFIG_SINGLETHREAD); | 1919 sqlite3_config(SQLITE_CONFIG_SINGLETHREAD); |
1767 for(i=1; i<argc; i++){ | 1920 for(i=1; i<argc; i++){ |
1768 const char *z = argv[i]; | 1921 const char *z = argv[i]; |
1769 if( z[0]=='-' ){ | 1922 if( z[0]=='-' ){ |
1770 z++; | 1923 z++; |
1771 if( z[0]=='-' ) z++; | 1924 if( z[0]=='-' ) z++; |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1804 if( strcmp(z,"summary")==0 ){ | 1957 if( strcmp(z,"summary")==0 ){ |
1805 xDiff = summarize_one_table; | 1958 xDiff = summarize_one_table; |
1806 }else | 1959 }else |
1807 if( strcmp(z,"table")==0 ){ | 1960 if( strcmp(z,"table")==0 ){ |
1808 if( i==argc-1 ) cmdlineError("missing argument to %s", argv[i]); | 1961 if( i==argc-1 ) cmdlineError("missing argument to %s", argv[i]); |
1809 zTab = argv[++i]; | 1962 zTab = argv[++i]; |
1810 }else | 1963 }else |
1811 if( strcmp(z,"transaction")==0 ){ | 1964 if( strcmp(z,"transaction")==0 ){ |
1812 useTransaction = 1; | 1965 useTransaction = 1; |
1813 }else | 1966 }else |
| 1967 if( strcmp(z,"vtab")==0 ){ |
| 1968 g.bHandleVtab = 1; |
| 1969 }else |
1814 { | 1970 { |
1815 cmdlineError("unknown option: %s", argv[i]); | 1971 cmdlineError("unknown option: %s", argv[i]); |
1816 } | 1972 } |
1817 }else if( zDb1==0 ){ | 1973 }else if( zDb1==0 ){ |
1818 zDb1 = argv[i]; | 1974 zDb1 = argv[i]; |
1819 }else if( zDb2==0 ){ | 1975 }else if( zDb2==0 ){ |
1820 zDb2 = argv[i]; | 1976 zDb2 = argv[i]; |
1821 }else{ | 1977 }else{ |
1822 cmdlineError("unknown argument: %s", argv[i]); | 1978 cmdlineError("unknown argument: %s", argv[i]); |
1823 } | 1979 } |
(...skipping 10 matching lines...) Expand all Loading... |
1834 cmdlineError("\"%s\" does not appear to be a valid SQLite database", zDb1); | 1990 cmdlineError("\"%s\" does not appear to be a valid SQLite database", zDb1); |
1835 } | 1991 } |
1836 #ifndef SQLITE_OMIT_LOAD_EXTENSION | 1992 #ifndef SQLITE_OMIT_LOAD_EXTENSION |
1837 sqlite3_enable_load_extension(g.db, 1); | 1993 sqlite3_enable_load_extension(g.db, 1); |
1838 for(i=0; i<nExt; i++){ | 1994 for(i=0; i<nExt; i++){ |
1839 rc = sqlite3_load_extension(g.db, azExt[i], 0, &zErrMsg); | 1995 rc = sqlite3_load_extension(g.db, azExt[i], 0, &zErrMsg); |
1840 if( rc || zErrMsg ){ | 1996 if( rc || zErrMsg ){ |
1841 cmdlineError("error loading %s: %s", azExt[i], zErrMsg); | 1997 cmdlineError("error loading %s: %s", azExt[i], zErrMsg); |
1842 } | 1998 } |
1843 } | 1999 } |
| 2000 free(azExt); |
1844 #endif | 2001 #endif |
1845 free(azExt); | |
1846 zSql = sqlite3_mprintf("ATTACH %Q as aux;", zDb2); | 2002 zSql = sqlite3_mprintf("ATTACH %Q as aux;", zDb2); |
1847 rc = sqlite3_exec(g.db, zSql, 0, 0, &zErrMsg); | 2003 rc = sqlite3_exec(g.db, zSql, 0, 0, &zErrMsg); |
1848 if( rc || zErrMsg ){ | 2004 if( rc || zErrMsg ){ |
1849 cmdlineError("cannot attach database \"%s\"", zDb2); | 2005 cmdlineError("cannot attach database \"%s\"", zDb2); |
1850 } | 2006 } |
1851 rc = sqlite3_exec(g.db, "SELECT * FROM aux.sqlite_master", 0, 0, &zErrMsg); | 2007 rc = sqlite3_exec(g.db, "SELECT * FROM aux.sqlite_master", 0, 0, &zErrMsg); |
1852 if( rc || zErrMsg ){ | 2008 if( rc || zErrMsg ){ |
1853 cmdlineError("\"%s\" does not appear to be a valid SQLite database", zDb2); | 2009 cmdlineError("\"%s\" does not appear to be a valid SQLite database", zDb2); |
1854 } | 2010 } |
1855 | 2011 |
1856 if( neverUseTransaction ) useTransaction = 0; | 2012 if( neverUseTransaction ) useTransaction = 0; |
1857 if( useTransaction ) printf("BEGIN TRANSACTION;\n"); | 2013 if( useTransaction ) fprintf(out, "BEGIN TRANSACTION;\n"); |
| 2014 if( xDiff==rbudiff_one_table ){ |
| 2015 fprintf(out, "CREATE TABLE IF NOT EXISTS rbu_count" |
| 2016 "(tbl TEXT PRIMARY KEY COLLATE NOCASE, cnt INTEGER) " |
| 2017 "WITHOUT ROWID;\n" |
| 2018 ); |
| 2019 } |
1858 if( zTab ){ | 2020 if( zTab ){ |
1859 xDiff(zTab, out); | 2021 xDiff(zTab, out); |
1860 }else{ | 2022 }else{ |
1861 /* Handle tables one by one */ | 2023 /* Handle tables one by one */ |
1862 pStmt = db_prepare( | 2024 pStmt = db_prepare("%s", all_tables_sql() ); |
1863 "SELECT name FROM main.sqlite_master\n" | |
1864 " WHERE type='table' AND sql NOT LIKE 'CREATE VIRTUAL%%'\n" | |
1865 " UNION\n" | |
1866 "SELECT name FROM aux.sqlite_master\n" | |
1867 " WHERE type='table' AND sql NOT LIKE 'CREATE VIRTUAL%%'\n" | |
1868 " ORDER BY name" | |
1869 ); | |
1870 while( SQLITE_ROW==sqlite3_step(pStmt) ){ | 2025 while( SQLITE_ROW==sqlite3_step(pStmt) ){ |
1871 xDiff((const char*)sqlite3_column_text(pStmt,0), out); | 2026 xDiff((const char*)sqlite3_column_text(pStmt,0), out); |
1872 } | 2027 } |
1873 sqlite3_finalize(pStmt); | 2028 sqlite3_finalize(pStmt); |
1874 } | 2029 } |
1875 if( useTransaction ) printf("COMMIT;\n"); | 2030 if( useTransaction ) printf("COMMIT;\n"); |
1876 | 2031 |
1877 /* TBD: Handle trigger differences */ | 2032 /* TBD: Handle trigger differences */ |
1878 /* TBD: Handle view differences */ | 2033 /* TBD: Handle view differences */ |
1879 sqlite3_close(g.db); | 2034 sqlite3_close(g.db); |
1880 return 0; | 2035 return 0; |
1881 } | 2036 } |
OLD | NEW |