Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Work toward adding the --changeset option to the sqldiff utility program. Changes are incomplete. This is an incremental check-in. |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | sqldiff-changeset |
Files: | files | file ages | folders |
SHA1: |
463e38d765f9d055b63792a8ea15c378 |
User & Date: | drh 2015-04-10 19:41:18.818 |
Context
2015-04-11
| ||
12:07 | First complete attempt to generate a working changeset. Still contains bugs. (check-in: 5611fa9bd5 user: drh tags: sqldiff-changeset) | |
2015-04-10
| ||
19:41 | Work toward adding the --changeset option to the sqldiff utility program. Changes are incomplete. This is an incremental check-in. (check-in: 463e38d765 user: drh tags: sqldiff-changeset) | |
16:05 | In sqlite3_declare_vtab(), avoid accessing the database structure until after the "api-armour" safety-check has completed and the db mutex has been obtained. (check-in: 860e4f8a94 user: dan tags: trunk) | |
Changes
Changes to tool/sqldiff.c.
︙ | ︙ | |||
709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 | end_diff_one_table: strFree(&sql); sqlite3_free(zId); namelistFree(az); namelistFree(az2); return; } /* ** Print sketchy documentation for this utility program */ static void showHelp(void){ printf("Usage: %s [options] DB1 DB2\n", g.zArgv0); printf( "Output SQL text that would transform DB1 into DB2.\n" "Options:\n" " --primarykey Use schema-defined PRIMARY KEYs\n" " --schema Show only differences in the schema\n" " --table TAB Show only differences in table TAB\n" ); } int main(int argc, char **argv){ const char *zDb1 = 0; const char *zDb2 = 0; int i; int rc; char *zErrMsg = 0; char *zSql; sqlite3_stmt *pStmt; char *zTab = 0; g.zArgv0 = argv[0]; for(i=1; i<argc; i++){ const char *z = argv[i]; if( z[0]=='-' ){ z++; if( z[0]=='-' ) z++; if( strcmp(z,"debug")==0 ){ g.fDebug = strtol(argv[++i], 0, 0); }else if( strcmp(z,"help")==0 ){ showHelp(); return 0; }else | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 | end_diff_one_table: strFree(&sql); sqlite3_free(zId); namelistFree(az); namelistFree(az2); return; } /* ** Generate a CHANGESET for all differences from main.zTab to aux.zTab. */ static void changeset_one_table(const char *zTab, FILE *out){ sqlite3_stmt *pStmt; /* SQL statment */ char *zId = safeId(zTab); /* Escaped name of the table */ char **azCol = 0; /* List of escaped column names */ int nCol = 0; /* Number of columns */ int *aiFlg = 0; /* 0 if column is not part of PK */ int *aiPk = 0; /* Column numbers for each PK column */ int nPk = 0; /* Number of PRIMARY KEY columns */ Str sql; /* SQL for the diff query */ int i; /* Loop counter */ const char *zSep; /* List separator */ pStmt = db_prepare( "SELECT A.sql=B.sql FROM main.sqlite_master A, aux.sqlite_master B" " WHERE A.name=%Q AND B.name=%Q", zTab, zTab ); if( SQLITE_ROW==sqlite3_step(pStmt) ){ if( sqlite3_column_int(pStmt,0)==0 ){ runtimeError("schema changes for table %s", safeId(zTab)); } }else{ runtimeError("table %s missing from one or both databases", safeId(zTab)); } sqlite3_finalize(pStmt); pStmt = db_prepare("PRAGMA main.table_info=%Q", zTab); while( SQLITE_ROW==sqlite3_step(pStmt) ){ nCol++; azCol = sqlite3_realloc(azCol, sizeof(char*)*nCol); if( azCol==0 ) runtimeError("out of memory"); aiFlg = sqlite3_realloc(aiFlg, sizeof(int)*nCol); if( aiFlg==0 ) runtimeError("out of memory"); azCol[nCol-1] = safeId((const char*)sqlite3_column_text(pStmt,1)); aiFlg[nCol-1] = i = sqlite3_column_int(pStmt,5); if( i>0 ){ if( i>nPk ){ nPk = i; aiPk = sqlite3_realloc(aiPk, sizeof(int)*nPk); if( aiPk==0 ) runtimeError("out of memory"); } aiPk[i-1] = nCol-1; } } sqlite3_finalize(pStmt); if( nPk==0 ) goto end_changeset_one_table; strInit(&sql); if( nCol>nPk ){ strPrintf(&sql, "SELECT 1"); /* Changes to non-PK columns */ for(i=0; i<nCol; i++) strPrintf(&sql, ", A.%s", azCol[i]); for(i=0; i<nCol; i++) strPrintf(&sql, ", B.%s", azCol[i]); strPrintf(&sql,"\n FROM main.%s A, aux.%s B\n", zId, zId); zSep = " WHERE"; for(i=0; i<nPk; i++){ strPrintf(&sql, "%s A.%s=B.%s", zSep, azCol[aiPk[i]], azCol[aiPk[i]]); zSep = " AND"; } zSep = "\n AND ("; for(i=0; i<nCol; i++){ if( aiFlg[i] ) continue; strPrintf(&sql, "%sA.%s IS NOT B.%s", zSep, azCol[i], azCol[i]); zSep = " OR\n "; } strPrintf(&sql,")\n UNION ALL\n"); } strPrintf(&sql, "SELECT 2"); /* Deleted rows */ for(i=0; i<nCol; i++) strPrintf(&sql, ", A.%s", azCol[i]); for(i=0; i<nCol; i++) strPrintf(&sql, ", 0"); strPrintf(&sql, " FROM main.%s A\n", zId); strPrintf(&sql, " WHERE NOT EXISTS(SELECT 1 FROM aux.%s B\n", zId); zSep = " WHERE"; for(i=0; i<nPk; i++){ strPrintf(&sql, "%s A.%s=B.%s", zSep, azCol[aiPk[i]], azCol[aiPk[i]]); zSep = " AND"; } strPrintf(&sql, ")\n UNION ALL\n"); strPrintf(&sql, "SELECT 3"); /* Inserted rows */ for(i=0; i<nCol; i++) strPrintf(&sql, ", 0"); for(i=0; i<nCol; i++) strPrintf(&sql, ", B.%s", azCol[i]); strPrintf(&sql, " FROM aux.%s B\n", zId); strPrintf(&sql, " WHERE NOT EXISTS(SELECT 1 FROM main.%s A\n", zId); zSep = " WHERE"; for(i=0; i<nPk; i++){ strPrintf(&sql, "%s A.%s=B.%s", zSep, azCol[aiPk[i]], azCol[aiPk[i]]); zSep = " AND"; } strPrintf(&sql, ")\n"); strPrintf(&sql, " ORDER BY"); zSep = " "; for(i=0; i<nPk; i++){ strPrintf(&sql, "%s %d", zSep, aiPk[i]+1); zSep = ","; } strPrintf(&sql, ";\n"); printf("for table %s:\n%s\n", zId, sql.z); strFree(&sql); end_changeset_one_table: while( nCol>0 ) sqlite3_free(azCol[--nCol]); sqlite3_free(azCol); sqlite3_free(aiPk); sqlite3_free(zId); } /* ** Print sketchy documentation for this utility program */ static void showHelp(void){ printf("Usage: %s [options] DB1 DB2\n", g.zArgv0); printf( "Output SQL text that would transform DB1 into DB2.\n" "Options:\n" " --changeset FILE Write a CHANGESET into FILE\n" " --primarykey Use schema-defined PRIMARY KEYs\n" " --schema Show only differences in the schema\n" " --table TAB Show only differences in table TAB\n" ); } int main(int argc, char **argv){ const char *zDb1 = 0; const char *zDb2 = 0; int i; int rc; char *zErrMsg = 0; char *zSql; sqlite3_stmt *pStmt; char *zTab = 0; FILE *out = 0; g.zArgv0 = argv[0]; for(i=1; i<argc; i++){ const char *z = argv[i]; if( z[0]=='-' ){ z++; if( z[0]=='-' ) z++; if( strcmp(z,"changeset")==0 ){ out = fopen(argv[++i], "wb"); if( out==0 ) cmdlineError("cannot open: %s", argv[i]); }else if( strcmp(z,"debug")==0 ){ g.fDebug = strtol(argv[++i], 0, 0); }else if( strcmp(z,"help")==0 ){ showHelp(); return 0; }else |
︙ | ︙ | |||
789 790 791 792 793 794 795 | } rc = sqlite3_exec(g.db, "SELECT * FROM aux.sqlite_master", 0, 0, &zErrMsg); if( rc || zErrMsg ){ cmdlineError("\"%s\" does not appear to be a valid SQLite database", zDb2); } if( zTab ){ | > > > | > | > > > > > | 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 | } rc = sqlite3_exec(g.db, "SELECT * FROM aux.sqlite_master", 0, 0, &zErrMsg); if( rc || zErrMsg ){ cmdlineError("\"%s\" does not appear to be a valid SQLite database", zDb2); } if( zTab ){ if( out ){ changeset_one_table(zTab, out); }else{ diff_one_table(zTab); } }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" ); while( SQLITE_ROW==sqlite3_step(pStmt) ){ const char *zTab = (const char*)sqlite3_column_text(pStmt,0); if( out ){ changeset_one_table(zTab, out); }else{ diff_one_table(zTab); } } sqlite3_finalize(pStmt); } /* TBD: Handle trigger differences */ /* TBD: Handle view differences */ sqlite3_close(g.db); return 0; } |