SQLite

Check-in [d3f3acb77f]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Modify the sqlite shell program so that the ".dump" command does not give up if it encounters an SQLITE_CORRUPT error. It tries to keep going in order to extract as much information as it can from the corrupt database. (CVS 1919)
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: d3f3acb77f4e9f597af5afac565916b9c5e1c5d6
User & Date: drh 2004-08-30 01:54:05.000
Context
2004-08-30
14:22
Remove the \001 character that lemon inserts automatically in its output file. The need for this character has expired and it creates confusion for users. Ticket #877 (CVS 1920) (check-in: acfc59186a user: drh tags: trunk)
01:54
Modify the sqlite shell program so that the ".dump" command does not give up if it encounters an SQLITE_CORRUPT error. It tries to keep going in order to extract as much information as it can from the corrupt database. (CVS 1919) (check-in: d3f3acb77f user: drh tags: trunk)
2004-08-29
23:42
Change the name of the global variable to sqlite3_temp_directory to avoid a naming conflict with version 2.8. (CVS 1918) (check-in: 431f7436a6 user: drh tags: trunk)
Changes
Unified Diff Show Whitespace Changes Patch
Changes to src/shell.c.
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** This file contains code to implement the "sqlite" command line
** utility for accessing SQLite databases.
**
** $Id: shell.c,v 1.111 2004/08/14 18:18:44 drh Exp $
*/
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <assert.h>
#include "sqlite3.h"
#include <ctype.h>







|







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** This file contains code to implement the "sqlite" command line
** utility for accessing SQLite databases.
**
** $Id: shell.c,v 1.112 2004/08/30 01:54:05 drh Exp $
*/
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <assert.h>
#include "sqlite3.h"
#include <ctype.h>
551
552
553
554
555
556
557





















558
559
560
561
562
563
564
  }else{
    memcpy(&zIn[nIn], zAppend, nAppend);
    zIn[len-1] = '\0';
  }

  return zIn;
}






















/*
** This is a different callback routine used for dumping the database.
** Each row received by this callback consists of a table name,
** the table type ("index" or "table") and SQL to create the table.
** This routine should print text sufficient to recreate the table.
*/







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
  }else{
    memcpy(&zIn[nIn], zAppend, nAppend);
    zIn[len-1] = '\0';
  }

  return zIn;
}


/*
** Execute a query statement that has a single result column.  Print
** that result column on a line by itself with a semicolon terminator.
*/
static int run_table_dump_query(FILE *out, sqlite3 *db, const char *zSelect){
  sqlite3_stmt *pSelect;
  int rc;
  rc = sqlite3_prepare(db, zSelect, -1, &pSelect, 0);
  if( rc!=SQLITE_OK || !pSelect ){
    return rc;
  }
  rc = sqlite3_step(pSelect);
  while( rc==SQLITE_ROW ){
    fprintf(out, "%s;\n", sqlite3_column_text(pSelect, 0));
    rc = sqlite3_step(pSelect);
  }
  return sqlite3_finalize(pSelect);
}


/*
** This is a different callback routine used for dumping the database.
** Each row received by this callback consists of a table name,
** the table type ("index" or "table") and SQL to create the table.
** This routine should print text sufficient to recreate the table.
*/
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
  zType = azArg[1];
  zSql = azArg[2];
  
  fprintf(p->out, "%s;\n", zSql);

  if( strcmp(zType, "table")==0 ){
    sqlite3_stmt *pTableInfo = 0;
    sqlite3_stmt *pSelect = 0;
    char *zSelect = 0;
    char *zTableInfo = 0;
    char *zTmp = 0;
   
    zTableInfo = appendText(zTableInfo, "PRAGMA table_info(", 0);
    zTableInfo = appendText(zTableInfo, zTable, '"');
    zTableInfo = appendText(zTableInfo, ");", 0);







<







595
596
597
598
599
600
601

602
603
604
605
606
607
608
  zType = azArg[1];
  zSql = azArg[2];
  
  fprintf(p->out, "%s;\n", zSql);

  if( strcmp(zType, "table")==0 ){
    sqlite3_stmt *pTableInfo = 0;

    char *zSelect = 0;
    char *zTableInfo = 0;
    char *zTmp = 0;
   
    zTableInfo = appendText(zTableInfo, "PRAGMA table_info(", 0);
    zTableInfo = appendText(zTableInfo, zTable, '"');
    zTableInfo = appendText(zTableInfo, ");", 0);
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636

637























638
639
640
641
642
643
644
645
646
    if( rc!=SQLITE_OK ){
      if( zSelect ) free(zSelect);
      return 1;
    }
    zSelect = appendText(zSelect, "|| ')' FROM  ", 0);
    zSelect = appendText(zSelect, zTable, '"');

    rc = sqlite3_prepare(p->db, zSelect, -1, &pSelect, 0);
    if( zSelect ) free(zSelect);
    if( rc!=SQLITE_OK || !pSelect ){
      return 1;
    }

    rc = sqlite3_step(pSelect);
    while( rc==SQLITE_ROW ){
      fprintf(p->out, "%s;\n", sqlite3_column_text(pSelect, 0));
      rc = sqlite3_step(pSelect);
    }
    rc = sqlite3_finalize(pSelect);
    if( rc!=SQLITE_OK ){
      return 1;
    }
  }

























  return 0;
}

/*
** Text of a help message
*/
static char zHelp[] =
  ".databases             List names and files of attached databases\n"
  ".dump ?TABLE? ...      Dump the database in an SQL text format\n"







<
<
<
<
<
|
<
|
|
|

|




>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|








634
635
636
637
638
639
640





641

642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
    if( rc!=SQLITE_OK ){
      if( zSelect ) free(zSelect);
      return 1;
    }
    zSelect = appendText(zSelect, "|| ')' FROM  ", 0);
    zSelect = appendText(zSelect, zTable, '"');






    rc = run_table_dump_query(p->out, p->db, zSelect);

    if( rc==SQLITE_CORRUPT ){
      zSelect = appendText(zSelect, " ORDER BY rowid DESC", 0);
      rc = run_table_dump_query(p->out, p->db, zSelect);
    }
    if( zSelect ) free(zSelect);
    if( rc!=SQLITE_OK ){
      return 1;
    }
  }
  return 0;
}

/*
** Run zQuery.  Update dump_callback() as the callback routine.
** If we get a SQLITE_CORRUPT error, rerun the query after appending
** "ORDER BY rowid DESC" to the end.
*/
static int run_schema_dump_query(
  struct callback_data *p, 
  const char *zQuery,
  char **pzErrMsg
){
  int rc;
  rc = sqlite3_exec(p->db, zQuery, dump_callback, p, pzErrMsg);
  if( rc==SQLITE_CORRUPT ){
    char *zQ2;
    int len = strlen(zQuery);
    if( pzErrMsg ) sqlite3_free(*pzErrMsg);
    zQ2 = malloc( len+100 );
    if( zQ2==0 ) return rc;
    sprintf(zQ2, "%s ORDER BY rowid DESC", zQuery);
    rc = sqlite3_exec(p->db, zQ2, dump_callback, p, pzErrMsg);
    free(zQ2);
  }
  return rc;
}

/*
** Text of a help message
*/
static char zHelp[] =
  ".databases             List names and files of attached databases\n"
  ".dump ?TABLE? ...      Dump the database in an SQL text format\n"
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
  }else

  if( c=='d' && strncmp(azArg[0], "dump", n)==0 ){
    char *zErrMsg = 0;
    open_db(p);
    fprintf(p->out, "BEGIN TRANSACTION;\n");
    if( nArg==1 ){
      sqlite3_exec(p->db,
        "SELECT name, type, sql FROM sqlite_master "
        "WHERE type!='meta' AND sql NOT NULL "
        "ORDER BY substr(type,2,1), name",
        dump_callback, p, &zErrMsg


      );
    }else{
      int i;
      for(i=1; i<nArg && zErrMsg==0; i++){
        zShellStatic = azArg[i];
        sqlite3_exec(p->db,
          "SELECT name, type, sql FROM sqlite_master "
          "WHERE tbl_name LIKE shellstatic() AND type!='meta' AND sql NOT NULL "
          "ORDER BY substr(type,2,1), name",
          dump_callback, p, &zErrMsg
        );



        zShellStatic = 0;
      }
    }
    if( zErrMsg ){
      fprintf(stderr,"Error: %s\n", zErrMsg);
      sqlite3_free(zErrMsg);
    }else{







|

|
|
|
>
>



|

|

|
|
|
<
>
>
>







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
  }else

  if( c=='d' && strncmp(azArg[0], "dump", n)==0 ){
    char *zErrMsg = 0;
    open_db(p);
    fprintf(p->out, "BEGIN TRANSACTION;\n");
    if( nArg==1 ){
      run_schema_dump_query(p, 
        "SELECT name, type, sql FROM sqlite_master "
        "WHERE sql NOT NULL AND type=='table'", 0
      );
      run_schema_dump_query(p, 
        "SELECT name, type, sql FROM sqlite_master "
        "WHERE sql NOT NULL AND type!='table' AND type!='meta'", 0
      );
    }else{
      int i;
      for(i=1; i<nArg; i++){
        zShellStatic = azArg[i];
        run_schema_dump_query(p,
          "SELECT name, type, sql FROM sqlite_master "
          "WHERE tbl_name LIKE shellstatic() AND type=='table'"
          "  AND sql NOT NULL", 0);
        run_schema_dump_query(p,

          "SELECT name, type, sql FROM sqlite_master "
          "WHERE tbl_name LIKE shellstatic() AND type!='table'"
          "  AND type!='meta' AND sql NOT NULL", 0);
        zShellStatic = 0;
      }
    }
    if( zErrMsg ){
      fprintf(stderr,"Error: %s\n", zErrMsg);
      sqlite3_free(zErrMsg);
    }else{