Fossil SCM

Add the .clone command to "fossil sqlite3". Taken from SQLite trunk.

jan.nijtmans 2014-02-07 08:58 trunk
Commit 90bd20308b5705caa687acb2aab1f62a6c77a4bb
1 file changed +218
+218
--- src/shell.c
+++ src/shell.c
@@ -1541,10 +1541,11 @@
15411541
** Text of a help message
15421542
*/
15431543
static char zHelp[] =
15441544
".backup ?DB? FILE Backup DB (default \"main\") to FILE\n"
15451545
".bail ON|OFF Stop after hitting an error. Default OFF\n"
1546
+ ".clone NEWDB Clone data into NEWDB from the existing database\n"
15461547
".databases List names and files of attached databases\n"
15471548
".dump ?TABLE? ... Dump the database in an SQL text format\n"
15481549
" If TABLE specified, only dump tables matching\n"
15491550
" LIKE pattern TABLE.\n"
15501551
".echo ON|OFF Turn command echo on or off\n"
@@ -1893,10 +1894,223 @@
18931894
p->cTerm = c;
18941895
}
18951896
if( p->z ) p->z[p->n] = 0;
18961897
return p->z;
18971898
}
1899
+
1900
+/*
1901
+** Try to transfer data for table zTable. If an error is seen while
1902
+** moving forward, try to go backwards. The backwards movement won't
1903
+** work for WITHOUT ROWID tables.
1904
+*/
1905
+static void tryToCloneData(
1906
+ struct callback_data *p,
1907
+ sqlite3 *newDb,
1908
+ const char *zTable
1909
+){
1910
+ sqlite3_stmt *pQuery = 0;
1911
+ sqlite3_stmt *pInsert = 0;
1912
+ char *zQuery = 0;
1913
+ char *zInsert = 0;
1914
+ int rc;
1915
+ int i, j, n;
1916
+ int nTable = (int)strlen(zTable);
1917
+ int k = 0;
1918
+ int cnt = 0;
1919
+ const int spinRate = 10000;
1920
+
1921
+ zQuery = sqlite3_mprintf("SELECT * FROM \"%w\"", zTable);
1922
+ rc = sqlite3_prepare_v2(p->db, zQuery, -1, &pQuery, 0);
1923
+ if( rc ){
1924
+ fprintf(stderr, "Error %d: %s on [%s]\n",
1925
+ sqlite3_extended_errcode(p->db), sqlite3_errmsg(p->db),
1926
+ zQuery);
1927
+ goto end_data_xfer;
1928
+ }
1929
+ n = sqlite3_column_count(pQuery);
1930
+ zInsert = sqlite3_malloc(200 + nTable + n*3);
1931
+ if( zInsert==0 ){
1932
+ fprintf(stderr, "out of memory\n");
1933
+ goto end_data_xfer;
1934
+ }
1935
+ sqlite3_snprintf(200+nTable,zInsert,
1936
+ "INSERT OR IGNORE INTO \"%s\" VALUES(?", zTable);
1937
+ i = (int)strlen(zInsert);
1938
+ for(j=1; j<n; j++){
1939
+ memcpy(zInsert+i, ",?", 2);
1940
+ i += 2;
1941
+ }
1942
+ memcpy(zInsert+i, ");", 3);
1943
+ rc = sqlite3_prepare_v2(newDb, zInsert, -1, &pInsert, 0);
1944
+ if( rc ){
1945
+ fprintf(stderr, "Error %d: %s on [%s]\n",
1946
+ sqlite3_extended_errcode(newDb), sqlite3_errmsg(newDb),
1947
+ zQuery);
1948
+ goto end_data_xfer;
1949
+ }
1950
+ for(k=0; k<2; k++){
1951
+ while( (rc = sqlite3_step(pQuery))==SQLITE_ROW ){
1952
+ for(i=0; i<n; i++){
1953
+ switch( sqlite3_column_type(pQuery, i) ){
1954
+ case SQLITE_NULL: {
1955
+ sqlite3_bind_null(pInsert, i+1);
1956
+ break;
1957
+ }
1958
+ case SQLITE_INTEGER: {
1959
+ sqlite3_bind_int64(pInsert, i+1, sqlite3_column_int64(pQuery,i));
1960
+ break;
1961
+ }
1962
+ case SQLITE_FLOAT: {
1963
+ sqlite3_bind_double(pInsert, i+1, sqlite3_column_double(pQuery,i));
1964
+ break;
1965
+ }
1966
+ case SQLITE_TEXT: {
1967
+ sqlite3_bind_text(pInsert, i+1,
1968
+ (const char*)sqlite3_column_text(pQuery,i),
1969
+ -1, SQLITE_STATIC);
1970
+ break;
1971
+ }
1972
+ case SQLITE_BLOB: {
1973
+ sqlite3_bind_blob(pInsert, i+1, sqlite3_column_blob(pQuery,i),
1974
+ sqlite3_column_bytes(pQuery,i),
1975
+ SQLITE_STATIC);
1976
+ break;
1977
+ }
1978
+ }
1979
+ } /* End for */
1980
+ rc = sqlite3_step(pInsert);
1981
+ if( rc!=SQLITE_OK && rc!=SQLITE_ROW && rc!=SQLITE_DONE ){
1982
+ fprintf(stderr, "Error %d: %s\n", sqlite3_extended_errcode(newDb),
1983
+ sqlite3_errmsg(newDb));
1984
+ }
1985
+ sqlite3_reset(pInsert);
1986
+ cnt++;
1987
+ if( (cnt%spinRate)==0 ){
1988
+ printf("%c\b", "|/-\\"[(cnt/spinRate)%4]);
1989
+ fflush(stdout);
1990
+ }
1991
+ } /* End while */
1992
+ if( rc==SQLITE_DONE ) break;
1993
+ sqlite3_finalize(pQuery);
1994
+ sqlite3_free(zQuery);
1995
+ zQuery = sqlite3_mprintf("SELECT * FROM \"%w\" ORDER BY rowid DESC;",
1996
+ zTable);
1997
+ rc = sqlite3_prepare_v2(p->db, zQuery, -1, &pQuery, 0);
1998
+ if( rc ){
1999
+ fprintf(stderr, "Warning: cannot step \"%s\" backwards", zTable);
2000
+ break;
2001
+ }
2002
+ } /* End for(k=0...) */
2003
+
2004
+end_data_xfer:
2005
+ sqlite3_finalize(pQuery);
2006
+ sqlite3_finalize(pInsert);
2007
+ sqlite3_free(zQuery);
2008
+ sqlite3_free(zInsert);
2009
+}
2010
+
2011
+
2012
+/*
2013
+** Try to transfer all rows of the schema that match zWhere. For
2014
+** each row, invoke xForEach() on the object defined by that row.
2015
+** If an error is encountered while moving forward through the
2016
+** sqlite_master table, try again moving backwards.
2017
+*/
2018
+static void tryToCloneSchema(
2019
+ struct callback_data *p,
2020
+ sqlite3 *newDb,
2021
+ const char *zWhere,
2022
+ void (*xForEach)(struct callback_data*,sqlite3*,const char*)
2023
+){
2024
+ sqlite3_stmt *pQuery = 0;
2025
+ char *zQuery = 0;
2026
+ int rc;
2027
+ const unsigned char *zName;
2028
+ const unsigned char *zSql;
2029
+ char *zErrMsg = 0;
2030
+
2031
+ zQuery = sqlite3_mprintf("SELECT name, sql FROM sqlite_master"
2032
+ " WHERE %s", zWhere);
2033
+ rc = sqlite3_prepare_v2(p->db, zQuery, -1, &pQuery, 0);
2034
+ if( rc ){
2035
+ fprintf(stderr, "Error: (%d) %s on [%s]\n",
2036
+ sqlite3_extended_errcode(p->db), sqlite3_errmsg(p->db),
2037
+ zQuery);
2038
+ goto end_schema_xfer;
2039
+ }
2040
+ while( (rc = sqlite3_step(pQuery))==SQLITE_ROW ){
2041
+ zName = sqlite3_column_text(pQuery, 0);
2042
+ zSql = sqlite3_column_text(pQuery, 1);
2043
+ printf("%s... ", zName); fflush(stdout);
2044
+ sqlite3_exec(newDb, (const char*)zSql, 0, 0, &zErrMsg);
2045
+ if( zErrMsg ){
2046
+ fprintf(stderr, "Error: %s\nSQL: [%s]\n", zErrMsg, zSql);
2047
+ sqlite3_free(zErrMsg);
2048
+ zErrMsg = 0;
2049
+ }
2050
+ if( xForEach ){
2051
+ xForEach(p, newDb, (const char*)zName);
2052
+ }
2053
+ printf("done\n");
2054
+ }
2055
+ if( rc!=SQLITE_DONE ){
2056
+ sqlite3_finalize(pQuery);
2057
+ sqlite3_free(zQuery);
2058
+ zQuery = sqlite3_mprintf("SELECT name, sql FROM sqlite_master"
2059
+ " WHERE %s ORDER BY rowid DESC", zWhere);
2060
+ rc = sqlite3_prepare_v2(p->db, zQuery, -1, &pQuery, 0);
2061
+ if( rc ){
2062
+ fprintf(stderr, "Error: (%d) %s on [%s]\n",
2063
+ sqlite3_extended_errcode(p->db), sqlite3_errmsg(p->db),
2064
+ zQuery);
2065
+ goto end_schema_xfer;
2066
+ }
2067
+ while( (rc = sqlite3_step(pQuery))==SQLITE_ROW ){
2068
+ zName = sqlite3_column_text(pQuery, 0);
2069
+ zSql = sqlite3_column_text(pQuery, 1);
2070
+ printf("%s... ", zName); fflush(stdout);
2071
+ sqlite3_exec(newDb, (const char*)zSql, 0, 0, &zErrMsg);
2072
+ if( zErrMsg ){
2073
+ fprintf(stderr, "Error: %s\nSQL: [%s]\n", zErrMsg, zSql);
2074
+ sqlite3_free(zErrMsg);
2075
+ zErrMsg = 0;
2076
+ }
2077
+ if( xForEach ){
2078
+ xForEach(p, newDb, (const char*)zName);
2079
+ }
2080
+ printf("done\n");
2081
+ }
2082
+ }
2083
+end_schema_xfer:
2084
+ sqlite3_finalize(pQuery);
2085
+ sqlite3_free(zQuery);
2086
+}
2087
+
2088
+/*
2089
+** Open a new database file named "zNewDb". Try to recover as much information
2090
+** as possible out of the main database (which might be corrupt) and write it
2091
+** into zNewDb.
2092
+*/
2093
+static void tryToClone(struct callback_data *p, const char *zNewDb){
2094
+ int rc;
2095
+ sqlite3 *newDb = 0;
2096
+ if( access(zNewDb,0)==0 ){
2097
+ fprintf(stderr, "File \"%s\" already exists.\n", zNewDb);
2098
+ return;
2099
+ }
2100
+ rc = sqlite3_open(zNewDb, &newDb);
2101
+ if( rc ){
2102
+ fprintf(stderr, "Cannot create output database: %s\n",
2103
+ sqlite3_errmsg(newDb));
2104
+ }else{
2105
+ sqlite3_exec(newDb, "BEGIN EXCLUSIVE;", 0, 0, 0);
2106
+ tryToCloneSchema(p, newDb, "type='table'", tryToCloneData);
2107
+ tryToCloneSchema(p, newDb, "type!='table'", 0);
2108
+ sqlite3_exec(newDb, "COMMIT;", 0, 0, 0);
2109
+ }
2110
+ sqlite3_close(newDb);
2111
+}
18982112
18992113
/*
19002114
** If an input line begins with "." then invoke this routine to
19012115
** process that line.
19022116
**
@@ -2000,10 +2214,14 @@
20002214
** routine named test_breakpoint().
20012215
*/
20022216
if( c=='b' && n>=3 && strncmp(azArg[0], "breakpoint", n)==0 ){
20032217
test_breakpoint();
20042218
}else
2219
+
2220
+ if( c=='c' && strncmp(azArg[0], "clone", n)==0 && nArg>1 && nArg<3 ){
2221
+ tryToClone(p, azArg[1]);
2222
+ }else
20052223
20062224
if( c=='d' && n>1 && strncmp(azArg[0], "databases", n)==0 && nArg==1 ){
20072225
struct callback_data data;
20082226
char *zErrMsg = 0;
20092227
open_db(p, 0);
20102228
--- src/shell.c
+++ src/shell.c
@@ -1541,10 +1541,11 @@
1541 ** Text of a help message
1542 */
1543 static char zHelp[] =
1544 ".backup ?DB? FILE Backup DB (default \"main\") to FILE\n"
1545 ".bail ON|OFF Stop after hitting an error. Default OFF\n"
 
1546 ".databases List names and files of attached databases\n"
1547 ".dump ?TABLE? ... Dump the database in an SQL text format\n"
1548 " If TABLE specified, only dump tables matching\n"
1549 " LIKE pattern TABLE.\n"
1550 ".echo ON|OFF Turn command echo on or off\n"
@@ -1893,10 +1894,223 @@
1893 p->cTerm = c;
1894 }
1895 if( p->z ) p->z[p->n] = 0;
1896 return p->z;
1897 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1898
1899 /*
1900 ** If an input line begins with "." then invoke this routine to
1901 ** process that line.
1902 **
@@ -2000,10 +2214,14 @@
2000 ** routine named test_breakpoint().
2001 */
2002 if( c=='b' && n>=3 && strncmp(azArg[0], "breakpoint", n)==0 ){
2003 test_breakpoint();
2004 }else
 
 
 
 
2005
2006 if( c=='d' && n>1 && strncmp(azArg[0], "databases", n)==0 && nArg==1 ){
2007 struct callback_data data;
2008 char *zErrMsg = 0;
2009 open_db(p, 0);
2010
--- src/shell.c
+++ src/shell.c
@@ -1541,10 +1541,11 @@
1541 ** Text of a help message
1542 */
1543 static char zHelp[] =
1544 ".backup ?DB? FILE Backup DB (default \"main\") to FILE\n"
1545 ".bail ON|OFF Stop after hitting an error. Default OFF\n"
1546 ".clone NEWDB Clone data into NEWDB from the existing database\n"
1547 ".databases List names and files of attached databases\n"
1548 ".dump ?TABLE? ... Dump the database in an SQL text format\n"
1549 " If TABLE specified, only dump tables matching\n"
1550 " LIKE pattern TABLE.\n"
1551 ".echo ON|OFF Turn command echo on or off\n"
@@ -1893,10 +1894,223 @@
1894 p->cTerm = c;
1895 }
1896 if( p->z ) p->z[p->n] = 0;
1897 return p->z;
1898 }
1899
1900 /*
1901 ** Try to transfer data for table zTable. If an error is seen while
1902 ** moving forward, try to go backwards. The backwards movement won't
1903 ** work for WITHOUT ROWID tables.
1904 */
1905 static void tryToCloneData(
1906 struct callback_data *p,
1907 sqlite3 *newDb,
1908 const char *zTable
1909 ){
1910 sqlite3_stmt *pQuery = 0;
1911 sqlite3_stmt *pInsert = 0;
1912 char *zQuery = 0;
1913 char *zInsert = 0;
1914 int rc;
1915 int i, j, n;
1916 int nTable = (int)strlen(zTable);
1917 int k = 0;
1918 int cnt = 0;
1919 const int spinRate = 10000;
1920
1921 zQuery = sqlite3_mprintf("SELECT * FROM \"%w\"", zTable);
1922 rc = sqlite3_prepare_v2(p->db, zQuery, -1, &pQuery, 0);
1923 if( rc ){
1924 fprintf(stderr, "Error %d: %s on [%s]\n",
1925 sqlite3_extended_errcode(p->db), sqlite3_errmsg(p->db),
1926 zQuery);
1927 goto end_data_xfer;
1928 }
1929 n = sqlite3_column_count(pQuery);
1930 zInsert = sqlite3_malloc(200 + nTable + n*3);
1931 if( zInsert==0 ){
1932 fprintf(stderr, "out of memory\n");
1933 goto end_data_xfer;
1934 }
1935 sqlite3_snprintf(200+nTable,zInsert,
1936 "INSERT OR IGNORE INTO \"%s\" VALUES(?", zTable);
1937 i = (int)strlen(zInsert);
1938 for(j=1; j<n; j++){
1939 memcpy(zInsert+i, ",?", 2);
1940 i += 2;
1941 }
1942 memcpy(zInsert+i, ");", 3);
1943 rc = sqlite3_prepare_v2(newDb, zInsert, -1, &pInsert, 0);
1944 if( rc ){
1945 fprintf(stderr, "Error %d: %s on [%s]\n",
1946 sqlite3_extended_errcode(newDb), sqlite3_errmsg(newDb),
1947 zQuery);
1948 goto end_data_xfer;
1949 }
1950 for(k=0; k<2; k++){
1951 while( (rc = sqlite3_step(pQuery))==SQLITE_ROW ){
1952 for(i=0; i<n; i++){
1953 switch( sqlite3_column_type(pQuery, i) ){
1954 case SQLITE_NULL: {
1955 sqlite3_bind_null(pInsert, i+1);
1956 break;
1957 }
1958 case SQLITE_INTEGER: {
1959 sqlite3_bind_int64(pInsert, i+1, sqlite3_column_int64(pQuery,i));
1960 break;
1961 }
1962 case SQLITE_FLOAT: {
1963 sqlite3_bind_double(pInsert, i+1, sqlite3_column_double(pQuery,i));
1964 break;
1965 }
1966 case SQLITE_TEXT: {
1967 sqlite3_bind_text(pInsert, i+1,
1968 (const char*)sqlite3_column_text(pQuery,i),
1969 -1, SQLITE_STATIC);
1970 break;
1971 }
1972 case SQLITE_BLOB: {
1973 sqlite3_bind_blob(pInsert, i+1, sqlite3_column_blob(pQuery,i),
1974 sqlite3_column_bytes(pQuery,i),
1975 SQLITE_STATIC);
1976 break;
1977 }
1978 }
1979 } /* End for */
1980 rc = sqlite3_step(pInsert);
1981 if( rc!=SQLITE_OK && rc!=SQLITE_ROW && rc!=SQLITE_DONE ){
1982 fprintf(stderr, "Error %d: %s\n", sqlite3_extended_errcode(newDb),
1983 sqlite3_errmsg(newDb));
1984 }
1985 sqlite3_reset(pInsert);
1986 cnt++;
1987 if( (cnt%spinRate)==0 ){
1988 printf("%c\b", "|/-\\"[(cnt/spinRate)%4]);
1989 fflush(stdout);
1990 }
1991 } /* End while */
1992 if( rc==SQLITE_DONE ) break;
1993 sqlite3_finalize(pQuery);
1994 sqlite3_free(zQuery);
1995 zQuery = sqlite3_mprintf("SELECT * FROM \"%w\" ORDER BY rowid DESC;",
1996 zTable);
1997 rc = sqlite3_prepare_v2(p->db, zQuery, -1, &pQuery, 0);
1998 if( rc ){
1999 fprintf(stderr, "Warning: cannot step \"%s\" backwards", zTable);
2000 break;
2001 }
2002 } /* End for(k=0...) */
2003
2004 end_data_xfer:
2005 sqlite3_finalize(pQuery);
2006 sqlite3_finalize(pInsert);
2007 sqlite3_free(zQuery);
2008 sqlite3_free(zInsert);
2009 }
2010
2011
2012 /*
2013 ** Try to transfer all rows of the schema that match zWhere. For
2014 ** each row, invoke xForEach() on the object defined by that row.
2015 ** If an error is encountered while moving forward through the
2016 ** sqlite_master table, try again moving backwards.
2017 */
2018 static void tryToCloneSchema(
2019 struct callback_data *p,
2020 sqlite3 *newDb,
2021 const char *zWhere,
2022 void (*xForEach)(struct callback_data*,sqlite3*,const char*)
2023 ){
2024 sqlite3_stmt *pQuery = 0;
2025 char *zQuery = 0;
2026 int rc;
2027 const unsigned char *zName;
2028 const unsigned char *zSql;
2029 char *zErrMsg = 0;
2030
2031 zQuery = sqlite3_mprintf("SELECT name, sql FROM sqlite_master"
2032 " WHERE %s", zWhere);
2033 rc = sqlite3_prepare_v2(p->db, zQuery, -1, &pQuery, 0);
2034 if( rc ){
2035 fprintf(stderr, "Error: (%d) %s on [%s]\n",
2036 sqlite3_extended_errcode(p->db), sqlite3_errmsg(p->db),
2037 zQuery);
2038 goto end_schema_xfer;
2039 }
2040 while( (rc = sqlite3_step(pQuery))==SQLITE_ROW ){
2041 zName = sqlite3_column_text(pQuery, 0);
2042 zSql = sqlite3_column_text(pQuery, 1);
2043 printf("%s... ", zName); fflush(stdout);
2044 sqlite3_exec(newDb, (const char*)zSql, 0, 0, &zErrMsg);
2045 if( zErrMsg ){
2046 fprintf(stderr, "Error: %s\nSQL: [%s]\n", zErrMsg, zSql);
2047 sqlite3_free(zErrMsg);
2048 zErrMsg = 0;
2049 }
2050 if( xForEach ){
2051 xForEach(p, newDb, (const char*)zName);
2052 }
2053 printf("done\n");
2054 }
2055 if( rc!=SQLITE_DONE ){
2056 sqlite3_finalize(pQuery);
2057 sqlite3_free(zQuery);
2058 zQuery = sqlite3_mprintf("SELECT name, sql FROM sqlite_master"
2059 " WHERE %s ORDER BY rowid DESC", zWhere);
2060 rc = sqlite3_prepare_v2(p->db, zQuery, -1, &pQuery, 0);
2061 if( rc ){
2062 fprintf(stderr, "Error: (%d) %s on [%s]\n",
2063 sqlite3_extended_errcode(p->db), sqlite3_errmsg(p->db),
2064 zQuery);
2065 goto end_schema_xfer;
2066 }
2067 while( (rc = sqlite3_step(pQuery))==SQLITE_ROW ){
2068 zName = sqlite3_column_text(pQuery, 0);
2069 zSql = sqlite3_column_text(pQuery, 1);
2070 printf("%s... ", zName); fflush(stdout);
2071 sqlite3_exec(newDb, (const char*)zSql, 0, 0, &zErrMsg);
2072 if( zErrMsg ){
2073 fprintf(stderr, "Error: %s\nSQL: [%s]\n", zErrMsg, zSql);
2074 sqlite3_free(zErrMsg);
2075 zErrMsg = 0;
2076 }
2077 if( xForEach ){
2078 xForEach(p, newDb, (const char*)zName);
2079 }
2080 printf("done\n");
2081 }
2082 }
2083 end_schema_xfer:
2084 sqlite3_finalize(pQuery);
2085 sqlite3_free(zQuery);
2086 }
2087
2088 /*
2089 ** Open a new database file named "zNewDb". Try to recover as much information
2090 ** as possible out of the main database (which might be corrupt) and write it
2091 ** into zNewDb.
2092 */
2093 static void tryToClone(struct callback_data *p, const char *zNewDb){
2094 int rc;
2095 sqlite3 *newDb = 0;
2096 if( access(zNewDb,0)==0 ){
2097 fprintf(stderr, "File \"%s\" already exists.\n", zNewDb);
2098 return;
2099 }
2100 rc = sqlite3_open(zNewDb, &newDb);
2101 if( rc ){
2102 fprintf(stderr, "Cannot create output database: %s\n",
2103 sqlite3_errmsg(newDb));
2104 }else{
2105 sqlite3_exec(newDb, "BEGIN EXCLUSIVE;", 0, 0, 0);
2106 tryToCloneSchema(p, newDb, "type='table'", tryToCloneData);
2107 tryToCloneSchema(p, newDb, "type!='table'", 0);
2108 sqlite3_exec(newDb, "COMMIT;", 0, 0, 0);
2109 }
2110 sqlite3_close(newDb);
2111 }
2112
2113 /*
2114 ** If an input line begins with "." then invoke this routine to
2115 ** process that line.
2116 **
@@ -2000,10 +2214,14 @@
2214 ** routine named test_breakpoint().
2215 */
2216 if( c=='b' && n>=3 && strncmp(azArg[0], "breakpoint", n)==0 ){
2217 test_breakpoint();
2218 }else
2219
2220 if( c=='c' && strncmp(azArg[0], "clone", n)==0 && nArg>1 && nArg<3 ){
2221 tryToClone(p, azArg[1]);
2222 }else
2223
2224 if( c=='d' && n>1 && strncmp(azArg[0], "databases", n)==0 && nArg==1 ){
2225 struct callback_data data;
2226 char *zErrMsg = 0;
2227 open_db(p, 0);
2228

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button