Fossil SCM
Update the SQLite command-line shell to the latest from the SQLite source tree.
Commit
862d7dbf59f55e2db4747942292b52c51c2338d8
Parent
399c0ddae480e57…
1 file changed
+55
-30
+55
-30
| --- src/shell.c | ||
| +++ src/shell.c | ||
| @@ -15,10 +15,21 @@ | ||
| 15 | 15 | #if (defined(_WIN32) || defined(WIN32)) && !defined(_CRT_SECURE_NO_WARNINGS) |
| 16 | 16 | /* This needs to come before any includes for MSVC compiler */ |
| 17 | 17 | #define _CRT_SECURE_NO_WARNINGS |
| 18 | 18 | #endif |
| 19 | 19 | |
| 20 | +/* | |
| 21 | +** Enable large-file support for fopen() and friends on unix. | |
| 22 | +*/ | |
| 23 | +#ifndef SQLITE_DISABLE_LFS | |
| 24 | +# define _LARGE_FILE 1 | |
| 25 | +# ifndef _FILE_OFFSET_BITS | |
| 26 | +# define _FILE_OFFSET_BITS 64 | |
| 27 | +# endif | |
| 28 | +# define _LARGEFILE_SOURCE 1 | |
| 29 | +#endif | |
| 30 | + | |
| 20 | 31 | #include <stdlib.h> |
| 21 | 32 | #include <string.h> |
| 22 | 33 | #include <stdio.h> |
| 23 | 34 | #include <assert.h> |
| 24 | 35 | #include "sqlite3.h" |
| @@ -58,11 +69,11 @@ | ||
| 58 | 69 | #define isatty(h) _isatty(h) |
| 59 | 70 | #define access(f,m) _access((f),(m)) |
| 60 | 71 | #else |
| 61 | 72 | /* Make sure isatty() has a prototype. |
| 62 | 73 | */ |
| 63 | -extern int isatty(); | |
| 74 | +extern int isatty(int); | |
| 64 | 75 | #endif |
| 65 | 76 | |
| 66 | 77 | #if defined(_WIN32_WCE) |
| 67 | 78 | /* Windows CE (arm-wince-mingw32ce-gcc) does not provide isatty() |
| 68 | 79 | * thus we always assume that we have a console. That can be |
| @@ -405,10 +416,11 @@ | ||
| 405 | 416 | sqlite3 *db; /* The database */ |
| 406 | 417 | int echoOn; /* True to echo input commands */ |
| 407 | 418 | int statsOn; /* True to display memory stats before each finalize */ |
| 408 | 419 | int cnt; /* Number of records displayed so far */ |
| 409 | 420 | FILE *out; /* Write results here */ |
| 421 | + int nErr; /* Number of errors seen */ | |
| 410 | 422 | int mode; /* An output mode setting */ |
| 411 | 423 | int writableSchema; /* True if PRAGMA writable_schema=ON */ |
| 412 | 424 | int showHeader; /* True to show column names in List or Column mode */ |
| 413 | 425 | char *zDestTable; /* Name of destination table when MODE_Insert */ |
| 414 | 426 | char separator[20]; /* Separator character for MODE_List */ |
| @@ -930,31 +942,37 @@ | ||
| 930 | 942 | ** |
| 931 | 943 | ** This is used, for example, to show the schema of the database by |
| 932 | 944 | ** querying the SQLITE_MASTER table. |
| 933 | 945 | */ |
| 934 | 946 | static int run_table_dump_query( |
| 935 | - FILE *out, /* Send output here */ | |
| 936 | - sqlite3 *db, /* Database to query */ | |
| 937 | - const char *zSelect, /* SELECT statement to extract content */ | |
| 938 | - const char *zFirstRow /* Print before first row, if not NULL */ | |
| 947 | + struct callback_data *p, /* Query context */ | |
| 948 | + const char *zSelect, /* SELECT statement to extract content */ | |
| 949 | + const char *zFirstRow /* Print before first row, if not NULL */ | |
| 939 | 950 | ){ |
| 940 | 951 | sqlite3_stmt *pSelect; |
| 941 | 952 | int rc; |
| 942 | - rc = sqlite3_prepare(db, zSelect, -1, &pSelect, 0); | |
| 953 | + rc = sqlite3_prepare(p->db, zSelect, -1, &pSelect, 0); | |
| 943 | 954 | if( rc!=SQLITE_OK || !pSelect ){ |
| 955 | + fprintf(p->out, "/**** ERROR: (%d) %s *****/\n", rc, sqlite3_errmsg(p->db)); | |
| 956 | + p->nErr++; | |
| 944 | 957 | return rc; |
| 945 | 958 | } |
| 946 | 959 | rc = sqlite3_step(pSelect); |
| 947 | 960 | while( rc==SQLITE_ROW ){ |
| 948 | 961 | if( zFirstRow ){ |
| 949 | - fprintf(out, "%s", zFirstRow); | |
| 962 | + fprintf(p->out, "%s", zFirstRow); | |
| 950 | 963 | zFirstRow = 0; |
| 951 | 964 | } |
| 952 | - fprintf(out, "%s;\n", sqlite3_column_text(pSelect, 0)); | |
| 965 | + fprintf(p->out, "%s;\n", sqlite3_column_text(pSelect, 0)); | |
| 953 | 966 | rc = sqlite3_step(pSelect); |
| 954 | 967 | } |
| 955 | - return sqlite3_finalize(pSelect); | |
| 968 | + rc = sqlite3_finalize(pSelect); | |
| 969 | + if( rc!=SQLITE_OK ){ | |
| 970 | + fprintf(p->out, "/**** ERROR: (%d) %s *****/\n", rc, sqlite3_errmsg(p->db)); | |
| 971 | + p->nErr++; | |
| 972 | + } | |
| 973 | + return rc; | |
| 956 | 974 | } |
| 957 | 975 | |
| 958 | 976 | /* |
| 959 | 977 | ** Allocate space and save off current error string. |
| 960 | 978 | */ |
| @@ -1276,14 +1294,14 @@ | ||
| 1276 | 1294 | return 1; |
| 1277 | 1295 | } |
| 1278 | 1296 | zSelect = appendText(zSelect, "|| ')' FROM ", 0); |
| 1279 | 1297 | zSelect = appendText(zSelect, zTable, '"'); |
| 1280 | 1298 | |
| 1281 | - rc = run_table_dump_query(p->out, p->db, zSelect, zPrepStmt); | |
| 1299 | + rc = run_table_dump_query(p, zSelect, zPrepStmt); | |
| 1282 | 1300 | if( rc==SQLITE_CORRUPT ){ |
| 1283 | 1301 | zSelect = appendText(zSelect, " ORDER BY rowid DESC", 0); |
| 1284 | - rc = run_table_dump_query(p->out, p->db, zSelect, 0); | |
| 1302 | + run_table_dump_query(p, zSelect, 0); | |
| 1285 | 1303 | } |
| 1286 | 1304 | if( zSelect ) free(zSelect); |
| 1287 | 1305 | } |
| 1288 | 1306 | return 0; |
| 1289 | 1307 | } |
| @@ -1295,23 +1313,34 @@ | ||
| 1295 | 1313 | ** If we get a SQLITE_CORRUPT error, rerun the query after appending |
| 1296 | 1314 | ** "ORDER BY rowid DESC" to the end. |
| 1297 | 1315 | */ |
| 1298 | 1316 | static int run_schema_dump_query( |
| 1299 | 1317 | struct callback_data *p, |
| 1300 | - const char *zQuery, | |
| 1301 | - char **pzErrMsg | |
| 1318 | + const char *zQuery | |
| 1302 | 1319 | ){ |
| 1303 | 1320 | int rc; |
| 1304 | - rc = sqlite3_exec(p->db, zQuery, dump_callback, p, pzErrMsg); | |
| 1321 | + char *zErr = 0; | |
| 1322 | + rc = sqlite3_exec(p->db, zQuery, dump_callback, p, &zErr); | |
| 1305 | 1323 | if( rc==SQLITE_CORRUPT ){ |
| 1306 | 1324 | char *zQ2; |
| 1307 | 1325 | int len = strlen30(zQuery); |
| 1308 | - if( pzErrMsg ) sqlite3_free(*pzErrMsg); | |
| 1326 | + fprintf(p->out, "/****** CORRUPTION ERROR *******/\n"); | |
| 1327 | + if( zErr ){ | |
| 1328 | + fprintf(p->out, "/****** %s ******/\n", zErr); | |
| 1329 | + sqlite3_free(zErr); | |
| 1330 | + zErr = 0; | |
| 1331 | + } | |
| 1309 | 1332 | zQ2 = malloc( len+100 ); |
| 1310 | 1333 | if( zQ2==0 ) return rc; |
| 1311 | 1334 | sqlite3_snprintf(sizeof(zQ2), zQ2, "%s ORDER BY rowid DESC", zQuery); |
| 1312 | - rc = sqlite3_exec(p->db, zQ2, dump_callback, p, pzErrMsg); | |
| 1335 | + rc = sqlite3_exec(p->db, zQ2, dump_callback, p, &zErr); | |
| 1336 | + if( rc ){ | |
| 1337 | + fprintf(p->out, "/****** ERROR: %s ******/\n", zErr); | |
| 1338 | + }else{ | |
| 1339 | + rc = SQLITE_CORRUPT; | |
| 1340 | + } | |
| 1341 | + sqlite3_free(zErr); | |
| 1313 | 1342 | free(zQ2); |
| 1314 | 1343 | } |
| 1315 | 1344 | return rc; |
| 1316 | 1345 | } |
| 1317 | 1346 | |
| @@ -1553,29 +1582,29 @@ | ||
| 1553 | 1582 | rc = 1; |
| 1554 | 1583 | } |
| 1555 | 1584 | }else |
| 1556 | 1585 | |
| 1557 | 1586 | if( c=='d' && strncmp(azArg[0], "dump", n)==0 && nArg<3 ){ |
| 1558 | - char *zErrMsg = 0; | |
| 1559 | 1587 | open_db(p); |
| 1560 | 1588 | /* When playing back a "dump", the content might appear in an order |
| 1561 | 1589 | ** which causes immediate foreign key constraints to be violated. |
| 1562 | 1590 | ** So disable foreign-key constraint enforcement to prevent problems. */ |
| 1563 | 1591 | fprintf(p->out, "PRAGMA foreign_keys=OFF;\n"); |
| 1564 | 1592 | fprintf(p->out, "BEGIN TRANSACTION;\n"); |
| 1565 | 1593 | p->writableSchema = 0; |
| 1566 | - sqlite3_exec(p->db, "PRAGMA writable_schema=ON", 0, 0, 0); | |
| 1594 | + sqlite3_exec(p->db, "SAVEPOINT dump; PRAGMA writable_schema=ON", 0, 0, 0); | |
| 1595 | + p->nErr = 0; | |
| 1567 | 1596 | if( nArg==1 ){ |
| 1568 | 1597 | run_schema_dump_query(p, |
| 1569 | 1598 | "SELECT name, type, sql FROM sqlite_master " |
| 1570 | - "WHERE sql NOT NULL AND type=='table' AND name!='sqlite_sequence'", 0 | |
| 1599 | + "WHERE sql NOT NULL AND type=='table' AND name!='sqlite_sequence'" | |
| 1571 | 1600 | ); |
| 1572 | 1601 | run_schema_dump_query(p, |
| 1573 | 1602 | "SELECT name, type, sql FROM sqlite_master " |
| 1574 | - "WHERE name=='sqlite_sequence'", 0 | |
| 1603 | + "WHERE name=='sqlite_sequence'" | |
| 1575 | 1604 | ); |
| 1576 | - run_table_dump_query(p->out, p->db, | |
| 1605 | + run_table_dump_query(p, | |
| 1577 | 1606 | "SELECT sql FROM sqlite_master " |
| 1578 | 1607 | "WHERE sql NOT NULL AND type IN ('index','trigger','view')", 0 |
| 1579 | 1608 | ); |
| 1580 | 1609 | }else{ |
| 1581 | 1610 | int i; |
| @@ -1582,12 +1611,12 @@ | ||
| 1582 | 1611 | for(i=1; i<nArg; i++){ |
| 1583 | 1612 | zShellStatic = azArg[i]; |
| 1584 | 1613 | run_schema_dump_query(p, |
| 1585 | 1614 | "SELECT name, type, sql FROM sqlite_master " |
| 1586 | 1615 | "WHERE tbl_name LIKE shellstatic() AND type=='table'" |
| 1587 | - " AND sql NOT NULL", 0); | |
| 1588 | - run_table_dump_query(p->out, p->db, | |
| 1616 | + " AND sql NOT NULL"); | |
| 1617 | + run_table_dump_query(p, | |
| 1589 | 1618 | "SELECT sql FROM sqlite_master " |
| 1590 | 1619 | "WHERE sql NOT NULL" |
| 1591 | 1620 | " AND type IN ('index','trigger','view')" |
| 1592 | 1621 | " AND tbl_name LIKE shellstatic()", 0 |
| 1593 | 1622 | ); |
| @@ -1596,17 +1625,13 @@ | ||
| 1596 | 1625 | } |
| 1597 | 1626 | if( p->writableSchema ){ |
| 1598 | 1627 | fprintf(p->out, "PRAGMA writable_schema=OFF;\n"); |
| 1599 | 1628 | p->writableSchema = 0; |
| 1600 | 1629 | } |
| 1601 | - sqlite3_exec(p->db, "PRAGMA writable_schema=OFF", 0, 0, 0); | |
| 1602 | - if( zErrMsg ){ | |
| 1603 | - fprintf(stderr,"Error: %s\n", zErrMsg); | |
| 1604 | - sqlite3_free(zErrMsg); | |
| 1605 | - }else{ | |
| 1606 | - fprintf(p->out, "COMMIT;\n"); | |
| 1607 | - } | |
| 1630 | + sqlite3_exec(p->db, "PRAGMA writable_schema=OFF;", 0, 0, 0); | |
| 1631 | + sqlite3_exec(p->db, "RELEASE dump;", 0, 0, 0); | |
| 1632 | + fprintf(p->out, p->nErr ? "ROLLBACK; -- due to errors\n" : "COMMIT;\n"); | |
| 1608 | 1633 | }else |
| 1609 | 1634 | |
| 1610 | 1635 | if( c=='e' && strncmp(azArg[0], "echo", n)==0 && nArg>1 && nArg<3 ){ |
| 1611 | 1636 | p->echoOn = booleanValue(azArg[1]); |
| 1612 | 1637 | }else |
| 1613 | 1638 |
| --- src/shell.c | |
| +++ src/shell.c | |
| @@ -15,10 +15,21 @@ | |
| 15 | #if (defined(_WIN32) || defined(WIN32)) && !defined(_CRT_SECURE_NO_WARNINGS) |
| 16 | /* This needs to come before any includes for MSVC compiler */ |
| 17 | #define _CRT_SECURE_NO_WARNINGS |
| 18 | #endif |
| 19 | |
| 20 | #include <stdlib.h> |
| 21 | #include <string.h> |
| 22 | #include <stdio.h> |
| 23 | #include <assert.h> |
| 24 | #include "sqlite3.h" |
| @@ -58,11 +69,11 @@ | |
| 58 | #define isatty(h) _isatty(h) |
| 59 | #define access(f,m) _access((f),(m)) |
| 60 | #else |
| 61 | /* Make sure isatty() has a prototype. |
| 62 | */ |
| 63 | extern int isatty(); |
| 64 | #endif |
| 65 | |
| 66 | #if defined(_WIN32_WCE) |
| 67 | /* Windows CE (arm-wince-mingw32ce-gcc) does not provide isatty() |
| 68 | * thus we always assume that we have a console. That can be |
| @@ -405,10 +416,11 @@ | |
| 405 | sqlite3 *db; /* The database */ |
| 406 | int echoOn; /* True to echo input commands */ |
| 407 | int statsOn; /* True to display memory stats before each finalize */ |
| 408 | int cnt; /* Number of records displayed so far */ |
| 409 | FILE *out; /* Write results here */ |
| 410 | int mode; /* An output mode setting */ |
| 411 | int writableSchema; /* True if PRAGMA writable_schema=ON */ |
| 412 | int showHeader; /* True to show column names in List or Column mode */ |
| 413 | char *zDestTable; /* Name of destination table when MODE_Insert */ |
| 414 | char separator[20]; /* Separator character for MODE_List */ |
| @@ -930,31 +942,37 @@ | |
| 930 | ** |
| 931 | ** This is used, for example, to show the schema of the database by |
| 932 | ** querying the SQLITE_MASTER table. |
| 933 | */ |
| 934 | static int run_table_dump_query( |
| 935 | FILE *out, /* Send output here */ |
| 936 | sqlite3 *db, /* Database to query */ |
| 937 | const char *zSelect, /* SELECT statement to extract content */ |
| 938 | const char *zFirstRow /* Print before first row, if not NULL */ |
| 939 | ){ |
| 940 | sqlite3_stmt *pSelect; |
| 941 | int rc; |
| 942 | rc = sqlite3_prepare(db, zSelect, -1, &pSelect, 0); |
| 943 | if( rc!=SQLITE_OK || !pSelect ){ |
| 944 | return rc; |
| 945 | } |
| 946 | rc = sqlite3_step(pSelect); |
| 947 | while( rc==SQLITE_ROW ){ |
| 948 | if( zFirstRow ){ |
| 949 | fprintf(out, "%s", zFirstRow); |
| 950 | zFirstRow = 0; |
| 951 | } |
| 952 | fprintf(out, "%s;\n", sqlite3_column_text(pSelect, 0)); |
| 953 | rc = sqlite3_step(pSelect); |
| 954 | } |
| 955 | return sqlite3_finalize(pSelect); |
| 956 | } |
| 957 | |
| 958 | /* |
| 959 | ** Allocate space and save off current error string. |
| 960 | */ |
| @@ -1276,14 +1294,14 @@ | |
| 1276 | return 1; |
| 1277 | } |
| 1278 | zSelect = appendText(zSelect, "|| ')' FROM ", 0); |
| 1279 | zSelect = appendText(zSelect, zTable, '"'); |
| 1280 | |
| 1281 | rc = run_table_dump_query(p->out, p->db, zSelect, zPrepStmt); |
| 1282 | if( rc==SQLITE_CORRUPT ){ |
| 1283 | zSelect = appendText(zSelect, " ORDER BY rowid DESC", 0); |
| 1284 | rc = run_table_dump_query(p->out, p->db, zSelect, 0); |
| 1285 | } |
| 1286 | if( zSelect ) free(zSelect); |
| 1287 | } |
| 1288 | return 0; |
| 1289 | } |
| @@ -1295,23 +1313,34 @@ | |
| 1295 | ** If we get a SQLITE_CORRUPT error, rerun the query after appending |
| 1296 | ** "ORDER BY rowid DESC" to the end. |
| 1297 | */ |
| 1298 | static int run_schema_dump_query( |
| 1299 | struct callback_data *p, |
| 1300 | const char *zQuery, |
| 1301 | char **pzErrMsg |
| 1302 | ){ |
| 1303 | int rc; |
| 1304 | rc = sqlite3_exec(p->db, zQuery, dump_callback, p, pzErrMsg); |
| 1305 | if( rc==SQLITE_CORRUPT ){ |
| 1306 | char *zQ2; |
| 1307 | int len = strlen30(zQuery); |
| 1308 | if( pzErrMsg ) sqlite3_free(*pzErrMsg); |
| 1309 | zQ2 = malloc( len+100 ); |
| 1310 | if( zQ2==0 ) return rc; |
| 1311 | sqlite3_snprintf(sizeof(zQ2), zQ2, "%s ORDER BY rowid DESC", zQuery); |
| 1312 | rc = sqlite3_exec(p->db, zQ2, dump_callback, p, pzErrMsg); |
| 1313 | free(zQ2); |
| 1314 | } |
| 1315 | return rc; |
| 1316 | } |
| 1317 | |
| @@ -1553,29 +1582,29 @@ | |
| 1553 | rc = 1; |
| 1554 | } |
| 1555 | }else |
| 1556 | |
| 1557 | if( c=='d' && strncmp(azArg[0], "dump", n)==0 && nArg<3 ){ |
| 1558 | char *zErrMsg = 0; |
| 1559 | open_db(p); |
| 1560 | /* When playing back a "dump", the content might appear in an order |
| 1561 | ** which causes immediate foreign key constraints to be violated. |
| 1562 | ** So disable foreign-key constraint enforcement to prevent problems. */ |
| 1563 | fprintf(p->out, "PRAGMA foreign_keys=OFF;\n"); |
| 1564 | fprintf(p->out, "BEGIN TRANSACTION;\n"); |
| 1565 | p->writableSchema = 0; |
| 1566 | sqlite3_exec(p->db, "PRAGMA writable_schema=ON", 0, 0, 0); |
| 1567 | if( nArg==1 ){ |
| 1568 | run_schema_dump_query(p, |
| 1569 | "SELECT name, type, sql FROM sqlite_master " |
| 1570 | "WHERE sql NOT NULL AND type=='table' AND name!='sqlite_sequence'", 0 |
| 1571 | ); |
| 1572 | run_schema_dump_query(p, |
| 1573 | "SELECT name, type, sql FROM sqlite_master " |
| 1574 | "WHERE name=='sqlite_sequence'", 0 |
| 1575 | ); |
| 1576 | run_table_dump_query(p->out, p->db, |
| 1577 | "SELECT sql FROM sqlite_master " |
| 1578 | "WHERE sql NOT NULL AND type IN ('index','trigger','view')", 0 |
| 1579 | ); |
| 1580 | }else{ |
| 1581 | int i; |
| @@ -1582,12 +1611,12 @@ | |
| 1582 | for(i=1; i<nArg; i++){ |
| 1583 | zShellStatic = azArg[i]; |
| 1584 | run_schema_dump_query(p, |
| 1585 | "SELECT name, type, sql FROM sqlite_master " |
| 1586 | "WHERE tbl_name LIKE shellstatic() AND type=='table'" |
| 1587 | " AND sql NOT NULL", 0); |
| 1588 | run_table_dump_query(p->out, p->db, |
| 1589 | "SELECT sql FROM sqlite_master " |
| 1590 | "WHERE sql NOT NULL" |
| 1591 | " AND type IN ('index','trigger','view')" |
| 1592 | " AND tbl_name LIKE shellstatic()", 0 |
| 1593 | ); |
| @@ -1596,17 +1625,13 @@ | |
| 1596 | } |
| 1597 | if( p->writableSchema ){ |
| 1598 | fprintf(p->out, "PRAGMA writable_schema=OFF;\n"); |
| 1599 | p->writableSchema = 0; |
| 1600 | } |
| 1601 | sqlite3_exec(p->db, "PRAGMA writable_schema=OFF", 0, 0, 0); |
| 1602 | if( zErrMsg ){ |
| 1603 | fprintf(stderr,"Error: %s\n", zErrMsg); |
| 1604 | sqlite3_free(zErrMsg); |
| 1605 | }else{ |
| 1606 | fprintf(p->out, "COMMIT;\n"); |
| 1607 | } |
| 1608 | }else |
| 1609 | |
| 1610 | if( c=='e' && strncmp(azArg[0], "echo", n)==0 && nArg>1 && nArg<3 ){ |
| 1611 | p->echoOn = booleanValue(azArg[1]); |
| 1612 | }else |
| 1613 |
| --- src/shell.c | |
| +++ src/shell.c | |
| @@ -15,10 +15,21 @@ | |
| 15 | #if (defined(_WIN32) || defined(WIN32)) && !defined(_CRT_SECURE_NO_WARNINGS) |
| 16 | /* This needs to come before any includes for MSVC compiler */ |
| 17 | #define _CRT_SECURE_NO_WARNINGS |
| 18 | #endif |
| 19 | |
| 20 | /* |
| 21 | ** Enable large-file support for fopen() and friends on unix. |
| 22 | */ |
| 23 | #ifndef SQLITE_DISABLE_LFS |
| 24 | # define _LARGE_FILE 1 |
| 25 | # ifndef _FILE_OFFSET_BITS |
| 26 | # define _FILE_OFFSET_BITS 64 |
| 27 | # endif |
| 28 | # define _LARGEFILE_SOURCE 1 |
| 29 | #endif |
| 30 | |
| 31 | #include <stdlib.h> |
| 32 | #include <string.h> |
| 33 | #include <stdio.h> |
| 34 | #include <assert.h> |
| 35 | #include "sqlite3.h" |
| @@ -58,11 +69,11 @@ | |
| 69 | #define isatty(h) _isatty(h) |
| 70 | #define access(f,m) _access((f),(m)) |
| 71 | #else |
| 72 | /* Make sure isatty() has a prototype. |
| 73 | */ |
| 74 | extern int isatty(int); |
| 75 | #endif |
| 76 | |
| 77 | #if defined(_WIN32_WCE) |
| 78 | /* Windows CE (arm-wince-mingw32ce-gcc) does not provide isatty() |
| 79 | * thus we always assume that we have a console. That can be |
| @@ -405,10 +416,11 @@ | |
| 416 | sqlite3 *db; /* The database */ |
| 417 | int echoOn; /* True to echo input commands */ |
| 418 | int statsOn; /* True to display memory stats before each finalize */ |
| 419 | int cnt; /* Number of records displayed so far */ |
| 420 | FILE *out; /* Write results here */ |
| 421 | int nErr; /* Number of errors seen */ |
| 422 | int mode; /* An output mode setting */ |
| 423 | int writableSchema; /* True if PRAGMA writable_schema=ON */ |
| 424 | int showHeader; /* True to show column names in List or Column mode */ |
| 425 | char *zDestTable; /* Name of destination table when MODE_Insert */ |
| 426 | char separator[20]; /* Separator character for MODE_List */ |
| @@ -930,31 +942,37 @@ | |
| 942 | ** |
| 943 | ** This is used, for example, to show the schema of the database by |
| 944 | ** querying the SQLITE_MASTER table. |
| 945 | */ |
| 946 | static int run_table_dump_query( |
| 947 | struct callback_data *p, /* Query context */ |
| 948 | const char *zSelect, /* SELECT statement to extract content */ |
| 949 | const char *zFirstRow /* Print before first row, if not NULL */ |
| 950 | ){ |
| 951 | sqlite3_stmt *pSelect; |
| 952 | int rc; |
| 953 | rc = sqlite3_prepare(p->db, zSelect, -1, &pSelect, 0); |
| 954 | if( rc!=SQLITE_OK || !pSelect ){ |
| 955 | fprintf(p->out, "/**** ERROR: (%d) %s *****/\n", rc, sqlite3_errmsg(p->db)); |
| 956 | p->nErr++; |
| 957 | return rc; |
| 958 | } |
| 959 | rc = sqlite3_step(pSelect); |
| 960 | while( rc==SQLITE_ROW ){ |
| 961 | if( zFirstRow ){ |
| 962 | fprintf(p->out, "%s", zFirstRow); |
| 963 | zFirstRow = 0; |
| 964 | } |
| 965 | fprintf(p->out, "%s;\n", sqlite3_column_text(pSelect, 0)); |
| 966 | rc = sqlite3_step(pSelect); |
| 967 | } |
| 968 | rc = sqlite3_finalize(pSelect); |
| 969 | if( rc!=SQLITE_OK ){ |
| 970 | fprintf(p->out, "/**** ERROR: (%d) %s *****/\n", rc, sqlite3_errmsg(p->db)); |
| 971 | p->nErr++; |
| 972 | } |
| 973 | return rc; |
| 974 | } |
| 975 | |
| 976 | /* |
| 977 | ** Allocate space and save off current error string. |
| 978 | */ |
| @@ -1276,14 +1294,14 @@ | |
| 1294 | return 1; |
| 1295 | } |
| 1296 | zSelect = appendText(zSelect, "|| ')' FROM ", 0); |
| 1297 | zSelect = appendText(zSelect, zTable, '"'); |
| 1298 | |
| 1299 | rc = run_table_dump_query(p, zSelect, zPrepStmt); |
| 1300 | if( rc==SQLITE_CORRUPT ){ |
| 1301 | zSelect = appendText(zSelect, " ORDER BY rowid DESC", 0); |
| 1302 | run_table_dump_query(p, zSelect, 0); |
| 1303 | } |
| 1304 | if( zSelect ) free(zSelect); |
| 1305 | } |
| 1306 | return 0; |
| 1307 | } |
| @@ -1295,23 +1313,34 @@ | |
| 1313 | ** If we get a SQLITE_CORRUPT error, rerun the query after appending |
| 1314 | ** "ORDER BY rowid DESC" to the end. |
| 1315 | */ |
| 1316 | static int run_schema_dump_query( |
| 1317 | struct callback_data *p, |
| 1318 | const char *zQuery |
| 1319 | ){ |
| 1320 | int rc; |
| 1321 | char *zErr = 0; |
| 1322 | rc = sqlite3_exec(p->db, zQuery, dump_callback, p, &zErr); |
| 1323 | if( rc==SQLITE_CORRUPT ){ |
| 1324 | char *zQ2; |
| 1325 | int len = strlen30(zQuery); |
| 1326 | fprintf(p->out, "/****** CORRUPTION ERROR *******/\n"); |
| 1327 | if( zErr ){ |
| 1328 | fprintf(p->out, "/****** %s ******/\n", zErr); |
| 1329 | sqlite3_free(zErr); |
| 1330 | zErr = 0; |
| 1331 | } |
| 1332 | zQ2 = malloc( len+100 ); |
| 1333 | if( zQ2==0 ) return rc; |
| 1334 | sqlite3_snprintf(sizeof(zQ2), zQ2, "%s ORDER BY rowid DESC", zQuery); |
| 1335 | rc = sqlite3_exec(p->db, zQ2, dump_callback, p, &zErr); |
| 1336 | if( rc ){ |
| 1337 | fprintf(p->out, "/****** ERROR: %s ******/\n", zErr); |
| 1338 | }else{ |
| 1339 | rc = SQLITE_CORRUPT; |
| 1340 | } |
| 1341 | sqlite3_free(zErr); |
| 1342 | free(zQ2); |
| 1343 | } |
| 1344 | return rc; |
| 1345 | } |
| 1346 | |
| @@ -1553,29 +1582,29 @@ | |
| 1582 | rc = 1; |
| 1583 | } |
| 1584 | }else |
| 1585 | |
| 1586 | if( c=='d' && strncmp(azArg[0], "dump", n)==0 && nArg<3 ){ |
| 1587 | open_db(p); |
| 1588 | /* When playing back a "dump", the content might appear in an order |
| 1589 | ** which causes immediate foreign key constraints to be violated. |
| 1590 | ** So disable foreign-key constraint enforcement to prevent problems. */ |
| 1591 | fprintf(p->out, "PRAGMA foreign_keys=OFF;\n"); |
| 1592 | fprintf(p->out, "BEGIN TRANSACTION;\n"); |
| 1593 | p->writableSchema = 0; |
| 1594 | sqlite3_exec(p->db, "SAVEPOINT dump; PRAGMA writable_schema=ON", 0, 0, 0); |
| 1595 | p->nErr = 0; |
| 1596 | if( nArg==1 ){ |
| 1597 | run_schema_dump_query(p, |
| 1598 | "SELECT name, type, sql FROM sqlite_master " |
| 1599 | "WHERE sql NOT NULL AND type=='table' AND name!='sqlite_sequence'" |
| 1600 | ); |
| 1601 | run_schema_dump_query(p, |
| 1602 | "SELECT name, type, sql FROM sqlite_master " |
| 1603 | "WHERE name=='sqlite_sequence'" |
| 1604 | ); |
| 1605 | run_table_dump_query(p, |
| 1606 | "SELECT sql FROM sqlite_master " |
| 1607 | "WHERE sql NOT NULL AND type IN ('index','trigger','view')", 0 |
| 1608 | ); |
| 1609 | }else{ |
| 1610 | int i; |
| @@ -1582,12 +1611,12 @@ | |
| 1611 | for(i=1; i<nArg; i++){ |
| 1612 | zShellStatic = azArg[i]; |
| 1613 | run_schema_dump_query(p, |
| 1614 | "SELECT name, type, sql FROM sqlite_master " |
| 1615 | "WHERE tbl_name LIKE shellstatic() AND type=='table'" |
| 1616 | " AND sql NOT NULL"); |
| 1617 | run_table_dump_query(p, |
| 1618 | "SELECT sql FROM sqlite_master " |
| 1619 | "WHERE sql NOT NULL" |
| 1620 | " AND type IN ('index','trigger','view')" |
| 1621 | " AND tbl_name LIKE shellstatic()", 0 |
| 1622 | ); |
| @@ -1596,17 +1625,13 @@ | |
| 1625 | } |
| 1626 | if( p->writableSchema ){ |
| 1627 | fprintf(p->out, "PRAGMA writable_schema=OFF;\n"); |
| 1628 | p->writableSchema = 0; |
| 1629 | } |
| 1630 | sqlite3_exec(p->db, "PRAGMA writable_schema=OFF;", 0, 0, 0); |
| 1631 | sqlite3_exec(p->db, "RELEASE dump;", 0, 0, 0); |
| 1632 | fprintf(p->out, p->nErr ? "ROLLBACK; -- due to errors\n" : "COMMIT;\n"); |
| 1633 | }else |
| 1634 | |
| 1635 | if( c=='e' && strncmp(azArg[0], "echo", n)==0 && nArg>1 && nArg<3 ){ |
| 1636 | p->echoOn = booleanValue(azArg[1]); |
| 1637 | }else |
| 1638 |