/ Check-in [3ca31cc3]
Login

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

Overview
Comment:Minor cleanup in checkindex.c. Add progress displays when checking a single index in the top-level TCL script for sqlite3_checker.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | checkindex
Files: files | file ages | folders
SHA3-256:3ca31cc3ffe1cce4a9961d29801eebd47f0093d1b53d0ea63386338a1d434fd3
User & Date: drh 2017-11-01 13:09:02
Context
2017-11-01
18:05
Move the test scripts for checkfreelist and checkindex over into the ext/repair/test directory. Run them now using the sqlite3_checker utility with the --test option. Some tests are currently failing due to an incomplete port. This is an incremental check-in. check-in: 17f8d5e1 user: drh tags: checkindex
13:09
Minor cleanup in checkindex.c. Add progress displays when checking a single index in the top-level TCL script for sqlite3_checker. check-in: 3ca31cc3 user: drh tags: checkindex
01:05
When sqlite3_checker finds a problem, show the row key as part of the error message, not the row index number. check-in: 6ffe917d user: drh tags: checkindex
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to ext/repair/checkindex.c.

38
39
40
41
42
43
44

45
46
47
48
49
50
51
..
89
90
91
92
93
94
95




96
97
98
99
100
101
102
...
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
...
189
190
191
192
193
194
195

196
197
198
199
200
201
202
...
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
struct CidxTable {
  sqlite3_vtab base;              /* Base class.  Must be first */
  sqlite3 *db;
};

struct CidxCursor {
  sqlite3_vtab_cursor base;       /* Base class.  Must be first */

  sqlite3_stmt *pStmt;
};

typedef struct CidxColumn CidxColumn;
struct CidxColumn {
  char *zExpr;                    /* Text for indexed expression */
  int bDesc;                      /* True for DESC columns, otherwise false */
................................................................................
  int argc, const char *const*argv,
  sqlite3_vtab **ppVtab,
  char **pzErr
){
  int rc = SQLITE_OK;
  CidxTable *pRet;





  rc = sqlite3_declare_vtab(db,
      "CREATE TABLE xyz("
      " errmsg TEXT, current_key TEXT,"
      " index_name HIDDEN, after_key HIDDEN"
      ")"
  );
  pRet = cidxMalloc(&rc, sizeof(CidxTable));
................................................................................
  int i;

  for(i=0; i<pInfo->nConstraint; i++){
    struct sqlite3_index_constraint *p = &pInfo->aConstraint[i];
    if( p->usable==0 ) continue;
    if( p->op!=SQLITE_INDEX_CONSTRAINT_EQ ) continue;

    if( p->iColumn==2 ){
      iIdxName = i;
    }
    if( p->iColumn==3 ){
      iAfterKey = i;
    }
  }

  if( iIdxName<0 ){
    pInfo->estimatedCost = 1000000000.0;
  }else{
................................................................................
    rc = sqlite3_finalize(pCsr->pStmt);
    pCsr->pStmt = 0;
    if( rc!=SQLITE_OK ){
      sqlite3 *db = ((CidxTable*)pCsr->base.pVtab)->db;
      cidxCursorError(pCsr, "Cursor error: %s", sqlite3_errmsg(db));
    }
  }else{

    rc = SQLITE_OK;
  }
  return rc;
}

/* We have reached EOF if previous sqlite3_step() returned
** anything other than SQLITE_ROW;
................................................................................
    sqlite3_free(azAfter);
  }

  if( pCsr->pStmt ){
    assert( rc==SQLITE_OK );
    rc = cidxNext(pCursor);
  }

  return rc;
}

/* 
** Return a column value.
*/
static int cidxColumn(
  sqlite3_vtab_cursor *pCursor, 
  sqlite3_context *ctx, 
  int iCol
){
  CidxCursor *pCsr = (CidxCursor*)pCursor;
  assert( iCol==0 || iCol==1 );
  if( iCol==0 ){
    const char *zVal = 0;
    if( sqlite3_column_type(pCsr->pStmt, 0)==SQLITE_INTEGER ){
      if( sqlite3_column_int(pCsr->pStmt, 0)==0 ){
        zVal = "row data mismatch";
      }
    }else{
      zVal = "row missing";
    }
    sqlite3_result_text(ctx, zVal, -1, SQLITE_STATIC);
  }else{
    sqlite3_result_value(ctx, sqlite3_column_value(pCsr->pStmt, 1));
  }
  return SQLITE_OK;
}

/* Return the ROWID for the sqlite_btreeinfo table */
static int cidxRowid(sqlite3_vtab_cursor *pCursor, sqlite_int64 *pRowid){







>







 







>
>
>
>







 







|


|







 







>







 







>












|
|









|







38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
..
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
...
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
...
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
...
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
struct CidxTable {
  sqlite3_vtab base;              /* Base class.  Must be first */
  sqlite3 *db;
};

struct CidxCursor {
  sqlite3_vtab_cursor base;       /* Base class.  Must be first */
  sqlite3_int64 iRowid;
  sqlite3_stmt *pStmt;
};

typedef struct CidxColumn CidxColumn;
struct CidxColumn {
  char *zExpr;                    /* Text for indexed expression */
  int bDesc;                      /* True for DESC columns, otherwise false */
................................................................................
  int argc, const char *const*argv,
  sqlite3_vtab **ppVtab,
  char **pzErr
){
  int rc = SQLITE_OK;
  CidxTable *pRet;

#define IIC_ERRMSG        0
#define IIC_CURRENT_KEY   1
#define IIC_INDEX_NAME    2
#define IIC_AFTER_KEY     3
  rc = sqlite3_declare_vtab(db,
      "CREATE TABLE xyz("
      " errmsg TEXT, current_key TEXT,"
      " index_name HIDDEN, after_key HIDDEN"
      ")"
  );
  pRet = cidxMalloc(&rc, sizeof(CidxTable));
................................................................................
  int i;

  for(i=0; i<pInfo->nConstraint; i++){
    struct sqlite3_index_constraint *p = &pInfo->aConstraint[i];
    if( p->usable==0 ) continue;
    if( p->op!=SQLITE_INDEX_CONSTRAINT_EQ ) continue;

    if( p->iColumn==IIC_INDEX_NAME ){
      iIdxName = i;
    }
    if( p->iColumn==IIC_AFTER_KEY ){
      iAfterKey = i;
    }
  }

  if( iIdxName<0 ){
    pInfo->estimatedCost = 1000000000.0;
  }else{
................................................................................
    rc = sqlite3_finalize(pCsr->pStmt);
    pCsr->pStmt = 0;
    if( rc!=SQLITE_OK ){
      sqlite3 *db = ((CidxTable*)pCsr->base.pVtab)->db;
      cidxCursorError(pCsr, "Cursor error: %s", sqlite3_errmsg(db));
    }
  }else{
    pCsr->iRowid++;
    rc = SQLITE_OK;
  }
  return rc;
}

/* We have reached EOF if previous sqlite3_step() returned
** anything other than SQLITE_ROW;
................................................................................
    sqlite3_free(azAfter);
  }

  if( pCsr->pStmt ){
    assert( rc==SQLITE_OK );
    rc = cidxNext(pCursor);
  }
  pCsr->iRowid = 1;
  return rc;
}

/* 
** Return a column value.
*/
static int cidxColumn(
  sqlite3_vtab_cursor *pCursor, 
  sqlite3_context *ctx, 
  int iCol
){
  CidxCursor *pCsr = (CidxCursor*)pCursor;
  assert( iCol>=IIC_ERRMSG && iCol<=IIC_AFTER_KEY );
  if( iCol==IIC_ERRMSG ){
    const char *zVal = 0;
    if( sqlite3_column_type(pCsr->pStmt, 0)==SQLITE_INTEGER ){
      if( sqlite3_column_int(pCsr->pStmt, 0)==0 ){
        zVal = "row data mismatch";
      }
    }else{
      zVal = "row missing";
    }
    sqlite3_result_text(ctx, zVal, -1, SQLITE_STATIC);
  }else if( iCol==IIC_CURRENT_KEY ){
    sqlite3_result_value(ctx, sqlite3_column_value(pCsr->pStmt, 1));
  }
  return SQLITE_OK;
}

/* Return the ROWID for the sqlite_btreeinfo table */
static int cidxRowid(sqlite3_vtab_cursor *pCursor, sqlite_int64 *pRowid){

Changes to ext/repair/sqlite3_checker.tcl.

44
45
46
47
48
49
50



51

52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67





68
69
70
71
72
73

74
75
76
77
78
79
80
...
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117

# Do an incremental integrity check of a single index
#
proc check_index {idxname batchsize} {
  set i 0
  set more 1
  set nerr 0



  puts -nonewline "$idxname: "

  while {$more} {
    set more 0
    db eval {SELECT errmsg, current_key AS key
               FROM incremental_index_check($idxname)
              WHERE after_key=$key
              LIMIT $batchsize} {
      set more 1
      if {$errmsg!=""} {
        if {$nerr>0} {
           puts -nonewline "$idxname: "
        }
        incr nerr
        puts "key($key): $errmsg"
      }
      incr i
    }





  }
  if {$nerr==0} {
    puts "$i entries, ok"
  } else {
    puts "$idxname: $nerr errors out of $i entries"
  }

}

# Print a usage message on standard error, then quit.
#
proc usage {} {
  set argv0 [file rootname [file tail [info nameofexecutable]]]
  puts stderr "Usage: $argv0 OPTIONS database-filename"
................................................................................

set file_to_analyze {}
append argv {}
set bFreelistCheck 0
set bSummary 0
set zIndex {}
set zTable {}
set batchsize 100
set bAll 1
set argc [llength $argv]
for {set i 0} {$i<$argc} {incr i} {
  set arg [lindex $argv $i]
  if {[regexp {^-+tclsh$} $arg]} {
    tclsh
    exit 0







>
>
>
|
>








<
<
<

|



>
>
>
>
>
|
<
<
<
<

>







 







|







44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63



64
65
66
67
68
69
70
71
72
73
74




75
76
77
78
79
80
81
82
83
...
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120

# Do an incremental integrity check of a single index
#
proc check_index {idxname batchsize} {
  set i 0
  set more 1
  set nerr 0
  set pct 00.0
  set max [db one {SELECT nEntry FROM sqlite_btreeinfo('main')
                    WHERE name=$idxname}]
  puts -nonewline "$idxname: $i of $max rows ($pct%)\r"
  flush stdout
  while {$more} {
    set more 0
    db eval {SELECT errmsg, current_key AS key
               FROM incremental_index_check($idxname)
              WHERE after_key=$key
              LIMIT $batchsize} {
      set more 1
      if {$errmsg!=""} {



        incr nerr
        puts "$idxname: key($key): $errmsg"
      }
      incr i
    }
    set x [format {%.1f} [expr {($i*100.0)/$max}]]
    if {$x!=$pct} {
      puts -nonewline "$idxname: $i of $max rows ($pct%)\r"
      flush stdout
      set pct $x
    }




  }
  puts "$idxname: $nerr errors out of $i entries"
}

# Print a usage message on standard error, then quit.
#
proc usage {} {
  set argv0 [file rootname [file tail [info nameofexecutable]]]
  puts stderr "Usage: $argv0 OPTIONS database-filename"
................................................................................

set file_to_analyze {}
append argv {}
set bFreelistCheck 0
set bSummary 0
set zIndex {}
set zTable {}
set batchsize 1000
set bAll 1
set argc [llength $argv]
for {set i 0} {$i<$argc} {incr i} {
  set arg [lindex $argv $i]
  if {[regexp {^-+tclsh$} $arg]} {
    tclsh
    exit 0