Fossil SCM

Take over latest shell.c, but without SQLITE_TESTCTRL_IMPOSTER support (included SQLite doesn't have that yet). Reason: add '.dbinfo' command to "fossil sqlite" [http://www.sqlite.org/src/info/0f65a7e2e09f801b|0f65a7e2e0] and fix bug in '.import' [http://www.sqlite.org/src/info/9c5bcad1f7d04c16|9c5bcad1]

jan.nijtmans 2015-02-13 09:00 UTC trunk
Commit d96488860f5a855908a33edd2018f8f3d3c0dde0
1 file changed +120 -5
+120 -5
--- src/shell.c
+++ src/shell.c
@@ -1742,10 +1742,11 @@
17421742
static char zHelp[] =
17431743
".backup ?DB? FILE Backup DB (default \"main\") to FILE\n"
17441744
".bail on|off Stop after hitting an error. Default OFF\n"
17451745
".clone NEWDB Clone data into NEWDB from the existing database\n"
17461746
".databases List names and files of attached databases\n"
1747
+ ".dbinfo ?DB? Show status information about the database\n"
17471748
".dump ?TABLE? ... Dump the database in an SQL text format\n"
17481749
" If TABLE specified, only dump tables matching\n"
17491750
" LIKE pattern TABLE.\n"
17501751
".echo on|off Turn command echo on or off\n"
17511752
".eqp on|off Enable or disable automatic EXPLAIN QUERY PLAN\n"
@@ -1754,12 +1755,12 @@
17541755
" With no args, it turns EXPLAIN on.\n"
17551756
".fullschema Show schema and the content of sqlite_stat tables\n"
17561757
".headers on|off Turn display of headers on or off\n"
17571758
".help Show this message\n"
17581759
".import FILE TABLE Import data from FILE into TABLE\n"
1759
- ".indices ?TABLE? Show names of all indices\n"
1760
- " If TABLE specified, only show indices for tables\n"
1760
+ ".indexes ?TABLE? Show names of all indexes\n"
1761
+ " If TABLE specified, only show indexes for tables\n"
17611762
" matching LIKE pattern TABLE.\n"
17621763
#ifdef SQLITE_ENABLE_IOTRACE
17631764
".iotrace FILE Enable I/O diagnostic logging to FILE\n"
17641765
#endif
17651766
#ifndef SQLITE_OMIT_LOAD_EXTENSION
@@ -2434,10 +2435,119 @@
24342435
output_file_close(p->out);
24352436
}
24362437
p->outfile[0] = 0;
24372438
p->out = stdout;
24382439
}
2440
+
2441
+/*
2442
+** Run an SQL command and return the single integer result.
2443
+*/
2444
+static int db_int(ShellState *p, const char *zSql){
2445
+ sqlite3_stmt *pStmt;
2446
+ int res = 0;
2447
+ sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
2448
+ if( pStmt && sqlite3_step(pStmt)==SQLITE_ROW ){
2449
+ res = sqlite3_column_int(pStmt,0);
2450
+ }
2451
+ sqlite3_finalize(pStmt);
2452
+ return res;
2453
+}
2454
+
2455
+/*
2456
+** Convert a 2-byte or 4-byte big-endian integer into a native integer
2457
+*/
2458
+unsigned int get2byteInt(unsigned char *a){
2459
+ return (a[0]<<8) + a[1];
2460
+}
2461
+unsigned int get4byteInt(unsigned char *a){
2462
+ return (a[0]<<24) + (a[1]<<16) + (a[2]<<8) + a[3];
2463
+}
2464
+
2465
+/*
2466
+** Implementation of the ".info" command.
2467
+**
2468
+** Return 1 on error, 2 to exit, and 0 otherwise.
2469
+*/
2470
+static int shell_dbinfo_command(ShellState *p, int nArg, char **azArg){
2471
+ static const struct { const char *zName; int ofst; } aField[] = {
2472
+ { "file change counter:", 24 },
2473
+ { "database page count:", 28 },
2474
+ { "freelist page count:", 36 },
2475
+ { "schema cookie:", 40 },
2476
+ { "schema format:", 44 },
2477
+ { "default cache size:", 48 },
2478
+ { "autovacuum top root:", 52 },
2479
+ { "incremental vacuum:", 64 },
2480
+ { "text encoding:", 56 },
2481
+ { "user version:", 60 },
2482
+ { "application id:", 68 },
2483
+ { "software version:", 96 },
2484
+ };
2485
+ static const struct { const char *zName; const char *zSql; } aQuery[] = {
2486
+ { "number of tables:",
2487
+ "SELECT count(*) FROM %s WHERE type='table'" },
2488
+ { "number of indexes:",
2489
+ "SELECT count(*) FROM %s WHERE type='index'" },
2490
+ { "number of triggers:",
2491
+ "SELECT count(*) FROM %s WHERE type='trigger'" },
2492
+ { "number of views:",
2493
+ "SELECT count(*) FROM %s WHERE type='view'" },
2494
+ { "schema size:",
2495
+ "SELECT total(length(sql)) FROM %s" },
2496
+ };
2497
+ sqlite3_file *pFile;
2498
+ int i;
2499
+ char *zSchemaTab;
2500
+ char *zDb = nArg>=2 ? azArg[1] : "main";
2501
+ unsigned char aHdr[100];
2502
+ open_db(p, 0);
2503
+ if( p->db==0 ) return 1;
2504
+ sqlite3_file_control(p->db, zDb, SQLITE_FCNTL_FILE_POINTER, &pFile);
2505
+ if( pFile==0 || pFile->pMethods==0 || pFile->pMethods->xRead==0 ){
2506
+ return 1;
2507
+ }
2508
+ i = pFile->pMethods->xRead(pFile, aHdr, 100, 0);
2509
+ if( i!=SQLITE_OK ){
2510
+ fprintf(stderr, "unable to read database header\n");
2511
+ return 1;
2512
+ }
2513
+ i = get2byteInt(aHdr+16);
2514
+ if( i==1 ) i = 65536;
2515
+ fprintf(p->out, "%-20s %d\n", "database page size:", i);
2516
+ fprintf(p->out, "%-20s %d\n", "write format:", aHdr[18]);
2517
+ fprintf(p->out, "%-20s %d\n", "read format:", aHdr[19]);
2518
+ fprintf(p->out, "%-20s %d\n", "reserved bytes:", aHdr[20]);
2519
+ for(i=0; i<sizeof(aField)/sizeof(aField[0]); i++){
2520
+ int ofst = aField[i].ofst;
2521
+ unsigned int val = get4byteInt(aHdr + ofst);
2522
+ fprintf(p->out, "%-20s %u", aField[i].zName, val);
2523
+ switch( ofst ){
2524
+ case 56: {
2525
+ if( val==1 ) fprintf(p->out, " (utf8)");
2526
+ if( val==2 ) fprintf(p->out, " (utf16le)");
2527
+ if( val==3 ) fprintf(p->out, " (utf16be)");
2528
+ }
2529
+ }
2530
+ fprintf(p->out, "\n");
2531
+ }
2532
+ if( zDb==0 ){
2533
+ zSchemaTab = sqlite3_mprintf("main.sqlite_master");
2534
+ }else if( strcmp(zDb,"temp")==0 ){
2535
+ zSchemaTab = sqlite3_mprintf("%s", "sqlite_temp_master");
2536
+ }else{
2537
+ zSchemaTab = sqlite3_mprintf("\"%w\".sqlite_master", zDb);
2538
+ }
2539
+ for(i=0; i<sizeof(aQuery)/sizeof(aQuery[0]); i++){
2540
+ char *zSql = sqlite3_mprintf(aQuery[i].zSql, zSchemaTab);
2541
+ int val = db_int(p, zSql);
2542
+ sqlite3_free(zSql);
2543
+ fprintf(p->out, "%-20s %d\n", aQuery[i].zName, val);
2544
+ }
2545
+ sqlite3_free(zSchemaTab);
2546
+ return 0;
2547
+}
2548
+
24392549
24402550
/*
24412551
** If an input line begins with "." then invoke this routine to
24422552
** process that line.
24432553
**
@@ -2576,10 +2686,14 @@
25762686
fprintf(stderr,"Error: %s\n", zErrMsg);
25772687
sqlite3_free(zErrMsg);
25782688
rc = 1;
25792689
}
25802690
}else
2691
+
2692
+ if( c=='d' && strncmp(azArg[0], "dbinfo", n)==0 ){
2693
+ rc = shell_dbinfo_command(p, nArg, azArg);
2694
+ }else
25812695
25822696
if( c=='d' && strncmp(azArg[0], "dump", n)==0 ){
25832697
open_db(p, 0);
25842698
/* When playing back a "dump", the content might appear in an order
25852699
** which causes immediate foreign key constraints to be violated.
@@ -2916,11 +3030,11 @@
29163030
sqlite3_bind_text(pStmt, i+1, z, -1, SQLITE_TRANSIENT);
29173031
if( i<nCol-1 && sCtx.cTerm!=sCtx.cColSep ){
29183032
fprintf(stderr, "%s:%d: expected %d columns but found %d - "
29193033
"filling the rest with NULL\n",
29203034
sCtx.zFile, startLine, nCol, i+1);
2921
- i++;
3035
+ i += 2;
29223036
while( i<=nCol ){ sqlite3_bind_null(pStmt, i); i++; }
29233037
}
29243038
}
29253039
if( sCtx.cTerm==sCtx.cColSep ){
29263040
do{
@@ -2945,11 +3059,12 @@
29453059
sqlite3_free(sCtx.z);
29463060
sqlite3_finalize(pStmt);
29473061
if( needCommit ) sqlite3_exec(db, "COMMIT", 0, 0, 0);
29483062
}else
29493063
2950
- if( c=='i' && strncmp(azArg[0], "indices", n)==0 ){
3064
+ if( c=='i' && (strncmp(azArg[0], "indices", n)==0
3065
+ || strncmp(azArg[0], "indexes", n)==0) ){
29513066
ShellState data;
29523067
char *zErrMsg = 0;
29533068
open_db(p, 0);
29543069
memcpy(&data, p, sizeof(data));
29553070
data.showHeader = 0;
@@ -2975,11 +3090,11 @@
29753090
"ORDER BY 1",
29763091
callback, &data, &zErrMsg
29773092
);
29783093
zShellStatic = 0;
29793094
}else{
2980
- fprintf(stderr, "Usage: .indices ?LIKE-PATTERN?\n");
3095
+ fprintf(stderr, "Usage: .indexes ?LIKE-PATTERN?\n");
29813096
rc = 1;
29823097
goto meta_command_exit;
29833098
}
29843099
if( zErrMsg ){
29853100
fprintf(stderr,"Error: %s\n", zErrMsg);
29863101
--- src/shell.c
+++ src/shell.c
@@ -1742,10 +1742,11 @@
1742 static char zHelp[] =
1743 ".backup ?DB? FILE Backup DB (default \"main\") to FILE\n"
1744 ".bail on|off Stop after hitting an error. Default OFF\n"
1745 ".clone NEWDB Clone data into NEWDB from the existing database\n"
1746 ".databases List names and files of attached databases\n"
 
1747 ".dump ?TABLE? ... Dump the database in an SQL text format\n"
1748 " If TABLE specified, only dump tables matching\n"
1749 " LIKE pattern TABLE.\n"
1750 ".echo on|off Turn command echo on or off\n"
1751 ".eqp on|off Enable or disable automatic EXPLAIN QUERY PLAN\n"
@@ -1754,12 +1755,12 @@
1754 " With no args, it turns EXPLAIN on.\n"
1755 ".fullschema Show schema and the content of sqlite_stat tables\n"
1756 ".headers on|off Turn display of headers on or off\n"
1757 ".help Show this message\n"
1758 ".import FILE TABLE Import data from FILE into TABLE\n"
1759 ".indices ?TABLE? Show names of all indices\n"
1760 " If TABLE specified, only show indices for tables\n"
1761 " matching LIKE pattern TABLE.\n"
1762 #ifdef SQLITE_ENABLE_IOTRACE
1763 ".iotrace FILE Enable I/O diagnostic logging to FILE\n"
1764 #endif
1765 #ifndef SQLITE_OMIT_LOAD_EXTENSION
@@ -2434,10 +2435,119 @@
2434 output_file_close(p->out);
2435 }
2436 p->outfile[0] = 0;
2437 p->out = stdout;
2438 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2439
2440 /*
2441 ** If an input line begins with "." then invoke this routine to
2442 ** process that line.
2443 **
@@ -2576,10 +2686,14 @@
2576 fprintf(stderr,"Error: %s\n", zErrMsg);
2577 sqlite3_free(zErrMsg);
2578 rc = 1;
2579 }
2580 }else
 
 
 
 
2581
2582 if( c=='d' && strncmp(azArg[0], "dump", n)==0 ){
2583 open_db(p, 0);
2584 /* When playing back a "dump", the content might appear in an order
2585 ** which causes immediate foreign key constraints to be violated.
@@ -2916,11 +3030,11 @@
2916 sqlite3_bind_text(pStmt, i+1, z, -1, SQLITE_TRANSIENT);
2917 if( i<nCol-1 && sCtx.cTerm!=sCtx.cColSep ){
2918 fprintf(stderr, "%s:%d: expected %d columns but found %d - "
2919 "filling the rest with NULL\n",
2920 sCtx.zFile, startLine, nCol, i+1);
2921 i++;
2922 while( i<=nCol ){ sqlite3_bind_null(pStmt, i); i++; }
2923 }
2924 }
2925 if( sCtx.cTerm==sCtx.cColSep ){
2926 do{
@@ -2945,11 +3059,12 @@
2945 sqlite3_free(sCtx.z);
2946 sqlite3_finalize(pStmt);
2947 if( needCommit ) sqlite3_exec(db, "COMMIT", 0, 0, 0);
2948 }else
2949
2950 if( c=='i' && strncmp(azArg[0], "indices", n)==0 ){
 
2951 ShellState data;
2952 char *zErrMsg = 0;
2953 open_db(p, 0);
2954 memcpy(&data, p, sizeof(data));
2955 data.showHeader = 0;
@@ -2975,11 +3090,11 @@
2975 "ORDER BY 1",
2976 callback, &data, &zErrMsg
2977 );
2978 zShellStatic = 0;
2979 }else{
2980 fprintf(stderr, "Usage: .indices ?LIKE-PATTERN?\n");
2981 rc = 1;
2982 goto meta_command_exit;
2983 }
2984 if( zErrMsg ){
2985 fprintf(stderr,"Error: %s\n", zErrMsg);
2986
--- src/shell.c
+++ src/shell.c
@@ -1742,10 +1742,11 @@
1742 static char zHelp[] =
1743 ".backup ?DB? FILE Backup DB (default \"main\") to FILE\n"
1744 ".bail on|off Stop after hitting an error. Default OFF\n"
1745 ".clone NEWDB Clone data into NEWDB from the existing database\n"
1746 ".databases List names and files of attached databases\n"
1747 ".dbinfo ?DB? Show status information about the database\n"
1748 ".dump ?TABLE? ... Dump the database in an SQL text format\n"
1749 " If TABLE specified, only dump tables matching\n"
1750 " LIKE pattern TABLE.\n"
1751 ".echo on|off Turn command echo on or off\n"
1752 ".eqp on|off Enable or disable automatic EXPLAIN QUERY PLAN\n"
@@ -1754,12 +1755,12 @@
1755 " With no args, it turns EXPLAIN on.\n"
1756 ".fullschema Show schema and the content of sqlite_stat tables\n"
1757 ".headers on|off Turn display of headers on or off\n"
1758 ".help Show this message\n"
1759 ".import FILE TABLE Import data from FILE into TABLE\n"
1760 ".indexes ?TABLE? Show names of all indexes\n"
1761 " If TABLE specified, only show indexes for tables\n"
1762 " matching LIKE pattern TABLE.\n"
1763 #ifdef SQLITE_ENABLE_IOTRACE
1764 ".iotrace FILE Enable I/O diagnostic logging to FILE\n"
1765 #endif
1766 #ifndef SQLITE_OMIT_LOAD_EXTENSION
@@ -2434,10 +2435,119 @@
2435 output_file_close(p->out);
2436 }
2437 p->outfile[0] = 0;
2438 p->out = stdout;
2439 }
2440
2441 /*
2442 ** Run an SQL command and return the single integer result.
2443 */
2444 static int db_int(ShellState *p, const char *zSql){
2445 sqlite3_stmt *pStmt;
2446 int res = 0;
2447 sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
2448 if( pStmt && sqlite3_step(pStmt)==SQLITE_ROW ){
2449 res = sqlite3_column_int(pStmt,0);
2450 }
2451 sqlite3_finalize(pStmt);
2452 return res;
2453 }
2454
2455 /*
2456 ** Convert a 2-byte or 4-byte big-endian integer into a native integer
2457 */
2458 unsigned int get2byteInt(unsigned char *a){
2459 return (a[0]<<8) + a[1];
2460 }
2461 unsigned int get4byteInt(unsigned char *a){
2462 return (a[0]<<24) + (a[1]<<16) + (a[2]<<8) + a[3];
2463 }
2464
2465 /*
2466 ** Implementation of the ".info" command.
2467 **
2468 ** Return 1 on error, 2 to exit, and 0 otherwise.
2469 */
2470 static int shell_dbinfo_command(ShellState *p, int nArg, char **azArg){
2471 static const struct { const char *zName; int ofst; } aField[] = {
2472 { "file change counter:", 24 },
2473 { "database page count:", 28 },
2474 { "freelist page count:", 36 },
2475 { "schema cookie:", 40 },
2476 { "schema format:", 44 },
2477 { "default cache size:", 48 },
2478 { "autovacuum top root:", 52 },
2479 { "incremental vacuum:", 64 },
2480 { "text encoding:", 56 },
2481 { "user version:", 60 },
2482 { "application id:", 68 },
2483 { "software version:", 96 },
2484 };
2485 static const struct { const char *zName; const char *zSql; } aQuery[] = {
2486 { "number of tables:",
2487 "SELECT count(*) FROM %s WHERE type='table'" },
2488 { "number of indexes:",
2489 "SELECT count(*) FROM %s WHERE type='index'" },
2490 { "number of triggers:",
2491 "SELECT count(*) FROM %s WHERE type='trigger'" },
2492 { "number of views:",
2493 "SELECT count(*) FROM %s WHERE type='view'" },
2494 { "schema size:",
2495 "SELECT total(length(sql)) FROM %s" },
2496 };
2497 sqlite3_file *pFile;
2498 int i;
2499 char *zSchemaTab;
2500 char *zDb = nArg>=2 ? azArg[1] : "main";
2501 unsigned char aHdr[100];
2502 open_db(p, 0);
2503 if( p->db==0 ) return 1;
2504 sqlite3_file_control(p->db, zDb, SQLITE_FCNTL_FILE_POINTER, &pFile);
2505 if( pFile==0 || pFile->pMethods==0 || pFile->pMethods->xRead==0 ){
2506 return 1;
2507 }
2508 i = pFile->pMethods->xRead(pFile, aHdr, 100, 0);
2509 if( i!=SQLITE_OK ){
2510 fprintf(stderr, "unable to read database header\n");
2511 return 1;
2512 }
2513 i = get2byteInt(aHdr+16);
2514 if( i==1 ) i = 65536;
2515 fprintf(p->out, "%-20s %d\n", "database page size:", i);
2516 fprintf(p->out, "%-20s %d\n", "write format:", aHdr[18]);
2517 fprintf(p->out, "%-20s %d\n", "read format:", aHdr[19]);
2518 fprintf(p->out, "%-20s %d\n", "reserved bytes:", aHdr[20]);
2519 for(i=0; i<sizeof(aField)/sizeof(aField[0]); i++){
2520 int ofst = aField[i].ofst;
2521 unsigned int val = get4byteInt(aHdr + ofst);
2522 fprintf(p->out, "%-20s %u", aField[i].zName, val);
2523 switch( ofst ){
2524 case 56: {
2525 if( val==1 ) fprintf(p->out, " (utf8)");
2526 if( val==2 ) fprintf(p->out, " (utf16le)");
2527 if( val==3 ) fprintf(p->out, " (utf16be)");
2528 }
2529 }
2530 fprintf(p->out, "\n");
2531 }
2532 if( zDb==0 ){
2533 zSchemaTab = sqlite3_mprintf("main.sqlite_master");
2534 }else if( strcmp(zDb,"temp")==0 ){
2535 zSchemaTab = sqlite3_mprintf("%s", "sqlite_temp_master");
2536 }else{
2537 zSchemaTab = sqlite3_mprintf("\"%w\".sqlite_master", zDb);
2538 }
2539 for(i=0; i<sizeof(aQuery)/sizeof(aQuery[0]); i++){
2540 char *zSql = sqlite3_mprintf(aQuery[i].zSql, zSchemaTab);
2541 int val = db_int(p, zSql);
2542 sqlite3_free(zSql);
2543 fprintf(p->out, "%-20s %d\n", aQuery[i].zName, val);
2544 }
2545 sqlite3_free(zSchemaTab);
2546 return 0;
2547 }
2548
2549
2550 /*
2551 ** If an input line begins with "." then invoke this routine to
2552 ** process that line.
2553 **
@@ -2576,10 +2686,14 @@
2686 fprintf(stderr,"Error: %s\n", zErrMsg);
2687 sqlite3_free(zErrMsg);
2688 rc = 1;
2689 }
2690 }else
2691
2692 if( c=='d' && strncmp(azArg[0], "dbinfo", n)==0 ){
2693 rc = shell_dbinfo_command(p, nArg, azArg);
2694 }else
2695
2696 if( c=='d' && strncmp(azArg[0], "dump", n)==0 ){
2697 open_db(p, 0);
2698 /* When playing back a "dump", the content might appear in an order
2699 ** which causes immediate foreign key constraints to be violated.
@@ -2916,11 +3030,11 @@
3030 sqlite3_bind_text(pStmt, i+1, z, -1, SQLITE_TRANSIENT);
3031 if( i<nCol-1 && sCtx.cTerm!=sCtx.cColSep ){
3032 fprintf(stderr, "%s:%d: expected %d columns but found %d - "
3033 "filling the rest with NULL\n",
3034 sCtx.zFile, startLine, nCol, i+1);
3035 i += 2;
3036 while( i<=nCol ){ sqlite3_bind_null(pStmt, i); i++; }
3037 }
3038 }
3039 if( sCtx.cTerm==sCtx.cColSep ){
3040 do{
@@ -2945,11 +3059,12 @@
3059 sqlite3_free(sCtx.z);
3060 sqlite3_finalize(pStmt);
3061 if( needCommit ) sqlite3_exec(db, "COMMIT", 0, 0, 0);
3062 }else
3063
3064 if( c=='i' && (strncmp(azArg[0], "indices", n)==0
3065 || strncmp(azArg[0], "indexes", n)==0) ){
3066 ShellState data;
3067 char *zErrMsg = 0;
3068 open_db(p, 0);
3069 memcpy(&data, p, sizeof(data));
3070 data.showHeader = 0;
@@ -2975,11 +3090,11 @@
3090 "ORDER BY 1",
3091 callback, &data, &zErrMsg
3092 );
3093 zShellStatic = 0;
3094 }else{
3095 fprintf(stderr, "Usage: .indexes ?LIKE-PATTERN?\n");
3096 rc = 1;
3097 goto meta_command_exit;
3098 }
3099 if( zErrMsg ){
3100 fprintf(stderr,"Error: %s\n", zErrMsg);
3101

Keyboard Shortcuts

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