/ Check-in [1df8cbbe]
Login

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

Overview
Comment:Merge trunk fixes.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | view-optimization
Files: files | file ages | folders
SHA1: 1df8cbbea66f303029737752f37cf2a6db98fcd4
User & Date: drh 2015-06-11 17:58:27
Context
2015-06-11
17:58
Merge trunk fixes. Leaf check-in: 1df8cbbe user: drh tags: view-optimization
14:19
Remove stray outputs from the test suite. check-in: afc6db9b user: drh tags: trunk
2015-06-10
20:00
Merge enhancements from trunk. check-in: 0e23a079 user: drh tags: view-optimization
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to Makefile.msc.

1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
	.\testfixture.exe $(TOP)\test\permutations.test queryplanner $(TESTOPTS)

fuzztest:	fuzzcheck.exe
	.\fuzzcheck.exe $(FUZZDATA)

# Minimal testing that runs in less than 3 minutes (on a fast machine)
#
quicktest:	.\testfixture.exe
	.\testfixture.exe $(TOP)\test\extraquick.test $(TESTOPTS)

# This is the common case.  Run many tests that do not take too long,
# including fuzzcheck, sqlite3_analyzer, and sqldiff tests.
#
test:	$(TESTPROGS) fuzztest
	.\testfixture.exe $(TOP)\test\veryquick.test $(TESTOPTS)







|







1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
	.\testfixture.exe $(TOP)\test\permutations.test queryplanner $(TESTOPTS)

fuzztest:	fuzzcheck.exe
	.\fuzzcheck.exe $(FUZZDATA)

# Minimal testing that runs in less than 3 minutes (on a fast machine)
#
quicktest:	testfixture.exe
	.\testfixture.exe $(TOP)\test\extraquick.test $(TESTOPTS)

# This is the common case.  Run many tests that do not take too long,
# including fuzzcheck, sqlite3_analyzer, and sqldiff tests.
#
test:	$(TESTPROGS) fuzztest
	.\testfixture.exe $(TOP)\test\veryquick.test $(TESTOPTS)

Changes to src/delete.c.

794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
  int nCol;

  if( piPartIdxLabel ){
    if( pIdx->pPartIdxWhere ){
      *piPartIdxLabel = sqlite3VdbeMakeLabel(v);
      pParse->iPartIdxTab = iDataCur;
      sqlite3ExprCachePush(pParse);
      sqlite3ExprIfFalse(pParse, pIdx->pPartIdxWhere, *piPartIdxLabel, 
                         SQLITE_JUMPIFNULL);
    }else{
      *piPartIdxLabel = 0;
    }
  }
  nCol = (prefixOnly && pIdx->uniqNotNull) ? pIdx->nKeyCol : pIdx->nColumn;
  regBase = sqlite3GetTempRange(pParse, nCol);
  if( pPrior && (regBase!=regPrior || pPrior->pPartIdxWhere) ) pPrior = 0;







|
|







794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
  int nCol;

  if( piPartIdxLabel ){
    if( pIdx->pPartIdxWhere ){
      *piPartIdxLabel = sqlite3VdbeMakeLabel(v);
      pParse->iPartIdxTab = iDataCur;
      sqlite3ExprCachePush(pParse);
      sqlite3ExprIfFalseDup(pParse, pIdx->pPartIdxWhere, *piPartIdxLabel, 
                            SQLITE_JUMPIFNULL);
    }else{
      *piPartIdxLabel = 0;
    }
  }
  nCol = (prefixOnly && pIdx->uniqNotNull) ? pIdx->nKeyCol : pIdx->nColumn;
  regBase = sqlite3GetTempRange(pParse, nCol);
  if( pPrior && (regBase!=regPrior || pPrior->pPartIdxWhere) ) pPrior = 0;

Changes to src/expr.c.

3697
3698
3699
3700
3701
3702
3703















3704
3705
3706
3707
3708
3709
3710
      }
      break;
    }
  }
  sqlite3ReleaseTempReg(pParse, regFree1);
  sqlite3ReleaseTempReg(pParse, regFree2);
}
















/*
** Do a deep comparison of two expression trees.  Return 0 if the two
** expressions are completely identical.  Return 1 if they differ only
** by a COLLATE operator at the top level.  Return 2 if there are differences
** other than the top-level COLLATE operator.
**







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







3697
3698
3699
3700
3701
3702
3703
3704
3705
3706
3707
3708
3709
3710
3711
3712
3713
3714
3715
3716
3717
3718
3719
3720
3721
3722
3723
3724
3725
      }
      break;
    }
  }
  sqlite3ReleaseTempReg(pParse, regFree1);
  sqlite3ReleaseTempReg(pParse, regFree2);
}

/*
** Like sqlite3ExprIfFalse() except that a copy is made of pExpr before
** code generation, and that copy is deleted after code generation. This
** ensures that the original pExpr is unchanged.
*/
void sqlite3ExprIfFalseDup(Parse *pParse, Expr *pExpr, int dest,int jumpIfNull){
  sqlite3 *db = pParse->db;
  Expr *pCopy = sqlite3ExprDup(db, pExpr, 0);
  if( db->mallocFailed==0 ){
    sqlite3ExprIfFalse(pParse, pCopy, dest, jumpIfNull);
  }
  sqlite3ExprDelete(db, pCopy);
}


/*
** Do a deep comparison of two expression trees.  Return 0 if the two
** expressions are completely identical.  Return 1 if they differ only
** by a COLLATE operator at the top level.  Return 2 if there are differences
** other than the top-level COLLATE operator.
**

Changes to src/insert.c.

1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
    iThisCur = iIdxCur+ix;
    addrUniqueOk = sqlite3VdbeMakeLabel(v);

    /* Skip partial indices for which the WHERE clause is not true */
    if( pIdx->pPartIdxWhere ){
      sqlite3VdbeAddOp2(v, OP_Null, 0, aRegIdx[ix]);
      pParse->ckBase = regNewData+1;
      sqlite3ExprIfFalse(pParse, pIdx->pPartIdxWhere, addrUniqueOk,
                         SQLITE_JUMPIFNULL);
      pParse->ckBase = 0;
    }

    /* Create a record for this index entry as it should appear after
    ** the insert or update.  Store that record in the aRegIdx[ix] register
    */
    regIdx = sqlite3GetTempRange(pParse, pIdx->nColumn);







|
|







1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
    iThisCur = iIdxCur+ix;
    addrUniqueOk = sqlite3VdbeMakeLabel(v);

    /* Skip partial indices for which the WHERE clause is not true */
    if( pIdx->pPartIdxWhere ){
      sqlite3VdbeAddOp2(v, OP_Null, 0, aRegIdx[ix]);
      pParse->ckBase = regNewData+1;
      sqlite3ExprIfFalseDup(pParse, pIdx->pPartIdxWhere, addrUniqueOk,
                            SQLITE_JUMPIFNULL);
      pParse->ckBase = 0;
    }

    /* Create a record for this index entry as it should appear after
    ** the insert or update.  Store that record in the aRegIdx[ix] register
    */
    regIdx = sqlite3GetTempRange(pParse, pIdx->nColumn);

Changes to src/sqliteInt.h.

3325
3326
3327
3328
3329
3330
3331

3332
3333
3334
3335
3336
3337
3338
int sqlite3ExprCodeTarget(Parse*, Expr*, int);
void sqlite3ExprCodeAndCache(Parse*, Expr*, int);
int sqlite3ExprCodeExprList(Parse*, ExprList*, int, u8);
#define SQLITE_ECEL_DUP      0x01  /* Deep, not shallow copies */
#define SQLITE_ECEL_FACTOR   0x02  /* Factor out constant terms */
void sqlite3ExprIfTrue(Parse*, Expr*, int, int);
void sqlite3ExprIfFalse(Parse*, Expr*, int, int);

Table *sqlite3FindTable(sqlite3*,const char*, const char*);
Table *sqlite3LocateTable(Parse*,int isView,const char*, const char*);
Table *sqlite3LocateTableItem(Parse*,int isView,struct SrcList_item *);
Index *sqlite3FindIndex(sqlite3*,const char*, const char*);
void sqlite3UnlinkAndDeleteTable(sqlite3*,int,const char*);
void sqlite3UnlinkAndDeleteIndex(sqlite3*,int,const char*);
void sqlite3Vacuum(Parse*);







>







3325
3326
3327
3328
3329
3330
3331
3332
3333
3334
3335
3336
3337
3338
3339
int sqlite3ExprCodeTarget(Parse*, Expr*, int);
void sqlite3ExprCodeAndCache(Parse*, Expr*, int);
int sqlite3ExprCodeExprList(Parse*, ExprList*, int, u8);
#define SQLITE_ECEL_DUP      0x01  /* Deep, not shallow copies */
#define SQLITE_ECEL_FACTOR   0x02  /* Factor out constant terms */
void sqlite3ExprIfTrue(Parse*, Expr*, int, int);
void sqlite3ExprIfFalse(Parse*, Expr*, int, int);
void sqlite3ExprIfFalseDup(Parse*, Expr*, int, int);
Table *sqlite3FindTable(sqlite3*,const char*, const char*);
Table *sqlite3LocateTable(Parse*,int isView,const char*, const char*);
Table *sqlite3LocateTableItem(Parse*,int isView,struct SrcList_item *);
Index *sqlite3FindIndex(sqlite3*,const char*, const char*);
void sqlite3UnlinkAndDeleteTable(sqlite3*,int,const char*);
void sqlite3UnlinkAndDeleteIndex(sqlite3*,int,const char*);
void sqlite3Vacuum(Parse*);

Changes to test/e_walauto.test.

167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
  } 0

  # EVIDENCE-OF: R-33080-59193 Checkpoints initiated by this mechanism 
  # are PASSIVE.
  #
  set ::busy_callback_count 0
  proc busy_callback {args} {
  puts Hello
    incr ::busy_callback_count
    return 0
  }
  do_test 1.$tn.12.1 {
    sqlite3_wal_checkpoint_v2 db truncate
    autocheckpoint db 100 
    db busy busy_callback







<







167
168
169
170
171
172
173

174
175
176
177
178
179
180
  } 0

  # EVIDENCE-OF: R-33080-59193 Checkpoints initiated by this mechanism 
  # are PASSIVE.
  #
  set ::busy_callback_count 0
  proc busy_callback {args} {

    incr ::busy_callback_count
    return 0
  }
  do_test 1.$tn.12.1 {
    sqlite3_wal_checkpoint_v2 db truncate
    autocheckpoint db 100 
    db busy busy_callback

Changes to test/filectrl.test.

35
36
37
38
39
40
41
42
43
44
45
46
47
  db close
  sqlite3 db test_control_lockproxy.db
  file_control_lockproxy_test db [get_pwd]
} {}
do_test filectrl-1.6 {
  sqlite3 db test.db
  set fn [file_control_tempfilename db]
  puts -nonewline \[$fn\]
  set fn
} {/etilqs_/}
db close
forcedelete .test_control_lockproxy.db-conch test.proxy
finish_test







<





35
36
37
38
39
40
41

42
43
44
45
46
  db close
  sqlite3 db test_control_lockproxy.db
  file_control_lockproxy_test db [get_pwd]
} {}
do_test filectrl-1.6 {
  sqlite3 db test.db
  set fn [file_control_tempfilename db]

  set fn
} {/etilqs_/}
db close
forcedelete .test_control_lockproxy.db-conch test.proxy
finish_test

Changes to test/fts3d.test.

209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
    SELECT OFFSETS(t1) FROM t1
     WHERE t1 MATCH 'this OR that OR was OR a OR is OR test' ORDER BY docid;
  }
} [list {0 0 0 4 0 4 5 2 0 3 8 1 0 5 10 4} \
        {0 1 0 4 0 2 5 3 0 3 9 1 0 5 11 4} \
        {0 0 0 4 0 4 5 2 0 3 8 1 0 5 10 4}]

puts [db eval {SELECT c FROM t1 } ]
check_terms_all fts3d-4.1      {a four is test that this was}
check_doclist_all fts3d-4.1.1  a {[1 0[2]] [2 0[2]] [3 0[2]]}
check_doclist_all fts3d-4.1.2  four {}
check_doclist_all fts3d-4.1.3  is {[1 0[1]] [3 0[1]]}
#check_doclist_all fts3d-4.1.4  one {}
check_doclist_all fts3d-4.1.5  test {[1 0[3]] [2 0[3]] [3 0[3]]}
check_doclist_all fts3d-4.1.6  that {[2 0[0]]}







|







209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
    SELECT OFFSETS(t1) FROM t1
     WHERE t1 MATCH 'this OR that OR was OR a OR is OR test' ORDER BY docid;
  }
} [list {0 0 0 4 0 4 5 2 0 3 8 1 0 5 10 4} \
        {0 1 0 4 0 2 5 3 0 3 9 1 0 5 11 4} \
        {0 0 0 4 0 4 5 2 0 3 8 1 0 5 10 4}]

db eval {SELECT c FROM t1 }
check_terms_all fts3d-4.1      {a four is test that this was}
check_doclist_all fts3d-4.1.1  a {[1 0[2]] [2 0[2]] [3 0[2]]}
check_doclist_all fts3d-4.1.2  four {}
check_doclist_all fts3d-4.1.3  is {[1 0[1]] [3 0[1]]}
#check_doclist_all fts3d-4.1.4  one {}
check_doclist_all fts3d-4.1.5  test {[1 0[3]] [2 0[3]] [3 0[3]]}
check_doclist_all fts3d-4.1.6  that {[2 0[0]]}

Changes to test/fts4incr.test.

43
44
45
46
47
48
49

50

51
52
53
54
55
56
57
      MATCH '"land of canaan"' AND docid < 1030000 } 7
} {
  foreach s {0 1} {
    execsql "INSERT INTO t1(t1) VALUES('test-no-incr-doclist=$s')"
    do_execsql_test 2.$tn.$s $q $res
    set t($s) [lindex [time [list execsql $q] 100] 0]
  }

  puts "with optimization: $t(0)    without: $t(1)"

}

do_test 2.1 {
  execsql {
    CREATE VIRTUAL TABLE t2 USING fts4(order=DESC);
  }
  set num [list one two three four five six seven eight nine ten]







>
|
>







43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
      MATCH '"land of canaan"' AND docid < 1030000 } 7
} {
  foreach s {0 1} {
    execsql "INSERT INTO t1(t1) VALUES('test-no-incr-doclist=$s')"
    do_execsql_test 2.$tn.$s $q $res
    set t($s) [lindex [time [list execsql $q] 100] 0]
  }
  if {0} {
    puts "with optimization: $t(0)    without: $t(1)"
  }
}

do_test 2.1 {
  execsql {
    CREATE VIRTUAL TABLE t2 USING fts4(order=DESC);
  }
  set num [list one two three four five six seven eight nine ten]

Changes to test/index5.test.

63
64
65
66
67
68
69

70
71

72
73
74
75
76
77
78
    } elseif {$iNext==($iPrev-1)} { 
      incr nBackward 
    } else {
      incr nNoncont
    }
    set iPrev $iNext
  }

  puts -nonewline \
      " (forward=$nForward, back=$nBackward, noncontiguous=$nNoncont)"


  expr {$nForward > 2*($nBackward + $nNoncont)}
} {1}
db close
tvfs delete

finish_test







>
|
|
>







63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
    } elseif {$iNext==($iPrev-1)} { 
      incr nBackward 
    } else {
      incr nNoncont
    }
    set iPrev $iNext
  }
  if {0} {
    puts -nonewline \
        " (forward=$nForward, back=$nBackward, noncontiguous=$nNoncont)"
  }

  expr {$nForward > 2*($nBackward + $nNoncont)}
} {1}
db close
tvfs delete

finish_test

Changes to test/index6.test.

322
323
324
325
326
327
328
329



















330
do_execsql_test index6-8.2 {
  SELECT * FROM t8a LEFT JOIN t8b ON (x = 'value' AND y = a)
} {
  1 one value 1 
  2 two {} {} 
  3 three value 3
}




















finish_test








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

322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
do_execsql_test index6-8.2 {
  SELECT * FROM t8a LEFT JOIN t8b ON (x = 'value' AND y = a)
} {
  1 one value 1 
  2 two {} {} 
  3 three value 3
}

# 2015-06-11.  Assertion fault found by AFL
#
do_execsql_test index6-9.1 {
  CREATE TABLE t9(a int, b int, c int);
  CREATE INDEX t9ca ON t9(c,a) WHERE a in (10,12,20);
  INSERT INTO t9 VALUES(1,1,9),(10,2,35),(11,15,82),(20,19,5),(NULL,7,3);
  UPDATE t9 SET b=c WHERE a in (10,12,20);
  SELECT a,b,c,'|' FROM t9 ORDER BY a;
} {{} 7 3 | 1 1 9 | 10 35 35 | 11 15 82 | 20 5 5 |}
do_execsql_test index6-9.2 {
  DROP TABLE t9;
  CREATE TABLE t9(a int, b int, c int, PRIMARY KEY(a)) WITHOUT ROWID;
  CREATE INDEX t9ca ON t9(c,a) WHERE a in (10,12,20);
  INSERT INTO t9 VALUES(1,1,9),(10,2,35),(11,15,82),(20,19,5);
  UPDATE t9 SET b=c WHERE a in (10,12,20);
  SELECT a,b,c,'|' FROM t9 ORDER BY a;
} {1 1 9 | 10 35 35 | 11 15 82 | 20 5 5 |}


finish_test

Changes to test/progress.test.

160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
    CREATE TABLE abc(a, b, c);
    INSERT INTO abc VALUES(1, 2, 3);
    INSERT INTO abc VALUES(4, 5, 6);
    INSERT INTO abc VALUES(7, 8, 9);
  }

  set ::res [list]
  explain {SELECT a, b, c FROM abc} 
  db eval {SELECT a, b, c FROM abc} {
    lappend ::res $a $b $c
    db progress 5 "expr 1"
    catch {db eval {SELECT a, b, c FROM abc} { }} msg
    db progress 5 "expr 0"
    lappend ::res $msg
  }

  set ::res
} {1 2 3 interrupted 4 5 6 interrupted 7 8 9 interrupted}

finish_test







<












160
161
162
163
164
165
166

167
168
169
170
171
172
173
174
175
176
177
178
    CREATE TABLE abc(a, b, c);
    INSERT INTO abc VALUES(1, 2, 3);
    INSERT INTO abc VALUES(4, 5, 6);
    INSERT INTO abc VALUES(7, 8, 9);
  }

  set ::res [list]

  db eval {SELECT a, b, c FROM abc} {
    lappend ::res $a $b $c
    db progress 5 "expr 1"
    catch {db eval {SELECT a, b, c FROM abc} { }} msg
    db progress 5 "expr 0"
    lappend ::res $msg
  }

  set ::res
} {1 2 3 interrupted 4 5 6 interrupted 7 8 9 interrupted}

finish_test

Changes to test/select8.test.

28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
  INSERT INTO songs VALUES(6,'two',11);
}
set result [execsql {
  SELECT DISTINCT artist,sum(timesplayed) AS total      
  FROM songs      
  GROUP BY LOWER(artist)      
}]
puts result=$result
do_test select8-1.1 {
  execsql {
    SELECT DISTINCT artist,sum(timesplayed) AS total      
    FROM songs      
    GROUP BY LOWER(artist)      
    LIMIT 1 OFFSET 1
  }







<







28
29
30
31
32
33
34

35
36
37
38
39
40
41
  INSERT INTO songs VALUES(6,'two',11);
}
set result [execsql {
  SELECT DISTINCT artist,sum(timesplayed) AS total      
  FROM songs      
  GROUP BY LOWER(artist)      
}]

do_test select8-1.1 {
  execsql {
    SELECT DISTINCT artist,sum(timesplayed) AS total      
    FROM songs      
    GROUP BY LOWER(artist)      
    LIMIT 1 OFFSET 1
  }

Changes to test/shared4.test.

12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# Test the btree mutex protocol for shared cache mode.
#
# $Id: shared4.test,v 1.2 2008/08/04 03:51:24 danielk1977 Exp $

set testdir [file dirname $argv0]
source $testdir/tester.tcl
db close
puts hello

# This script is only valid if we are running shared-cache mode in a
# threadsafe-capable database engine.
#
ifcapable !shared_cache||!compound {
  finish_test
  return







<







12
13
14
15
16
17
18

19
20
21
22
23
24
25
# Test the btree mutex protocol for shared cache mode.
#
# $Id: shared4.test,v 1.2 2008/08/04 03:51:24 danielk1977 Exp $

set testdir [file dirname $argv0]
source $testdir/tester.tcl
db close


# This script is only valid if we are running shared-cache mode in a
# threadsafe-capable database engine.
#
ifcapable !shared_cache||!compound {
  finish_test
  return

Changes to test/tester.tcl.

1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
....
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
  lappend r $msg
  return $r
}

# Do an VDBE code dump on the SQL given
#
proc explain {sql {db db}} {
  puts ""
  puts "addr  opcode        p1      p2      p3      p4               p5  #"
  puts "----  ------------  ------  ------  ------  ---------------  --  -"
  $db eval "explain $sql" {} {
    puts [format {%-4d  %-12.12s  %-6d  %-6d  %-6d  % -17s %s  %s} \
      $addr $opcode $p1 $p2 $p3 $p4 $p5 $comment
    ]
  }
}

proc explain_i {sql {db db}} {
  puts ""
  puts "addr  opcode        p1      p2      p3      p4                p5  #"
  puts "----  ------------  ------  ------  ------  ----------------  --  -"


  # Set up colors for the different opcodes. Scheme is as follows:
  #
  #   Red:   Opcodes that write to a b-tree.
  #   Blue:  Opcodes that reposition or seek a cursor. 
  #   Green: The ResultRow opcode.
................................................................................
    if {$opcode == "Halt" && $comment == "End of coroutine"} {
      set linebreak([expr $addr+1]) 1
    }
  }

  $db eval "explain $sql" {} {
    if {[info exists linebreak($addr)]} {
      puts ""
    }
    set I [string repeat " " $x($addr)]

    set col ""
    catch { set col $color($opcode) }

    puts [format {%-4d  %s%s%-12.12s%s  %-6d  %-6d  %-6d  % -17s %s  %s} \
      $addr $I $col $opcode $D $p1 $p2 $p3 $p4 $p5 $comment
    ]
  }
  puts "----  ------------  ------  ------  ------  ----------------  --  -"
}

# Show the VDBE program for an SQL statement but omit the Trace
# opcode at the beginning.  This procedure can be used to prove
# that different SQL statements generate exactly the same VDBE code.
#
proc explain_no_trace {sql} {







|
|
|

|






|
|
|







 







|






|



|







1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
....
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
  lappend r $msg
  return $r
}

# Do an VDBE code dump on the SQL given
#
proc explain {sql {db db}} {
  output2 ""
  output2 "addr  opcode        p1      p2      p3      p4               p5  #"
  output2 "----  ------------  ------  ------  ------  ---------------  --  -"
  $db eval "explain $sql" {} {
    output2 [format {%-4d  %-12.12s  %-6d  %-6d  %-6d  % -17s %s  %s} \
      $addr $opcode $p1 $p2 $p3 $p4 $p5 $comment
    ]
  }
}

proc explain_i {sql {db db}} {
  output2 ""
  output2 "addr  opcode        p1      p2      p3      p4                p5  #"
  output2 "----  ------------  ------  ------  ------  ----------------  --  -"


  # Set up colors for the different opcodes. Scheme is as follows:
  #
  #   Red:   Opcodes that write to a b-tree.
  #   Blue:  Opcodes that reposition or seek a cursor. 
  #   Green: The ResultRow opcode.
................................................................................
    if {$opcode == "Halt" && $comment == "End of coroutine"} {
      set linebreak([expr $addr+1]) 1
    }
  }

  $db eval "explain $sql" {} {
    if {[info exists linebreak($addr)]} {
      output2 ""
    }
    set I [string repeat " " $x($addr)]

    set col ""
    catch { set col $color($opcode) }

    output2 [format {%-4d  %s%s%-12.12s%s  %-6d  %-6d  %-6d  % -17s %s  %s} \
      $addr $I $col $opcode $D $p1 $p2 $p3 $p4 $p5 $comment
    ]
  }
  output2 "----  ------------  ------  ------  ------  ----------------  --  -"
}

# Show the VDBE program for an SQL statement but omit the Trace
# opcode at the beginning.  This procedure can be used to prove
# that different SQL statements generate exactly the same VDBE code.
#
proc explain_no_trace {sql} {

Changes to test/vtab1.test.

52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
#----------------------------------------------------------------------
# Test cases vtab1.1.*
#

# We cannot create a virtual table if the module has not been registered.
#
do_test vtab1-1.1.1 {
  explain {
    CREATE VIRTUAL TABLE t1 USING echo;
  }
  catchsql {
    CREATE VIRTUAL TABLE t1 USING echo;
  }
} {1 {no such module: echo}}
do_test vtab1-1.1.2 {
  catchsql {
    CREATE VIRTUAL TABLE IF NOT EXISTS t1 USING echo;







<
<
<







52
53
54
55
56
57
58



59
60
61
62
63
64
65
#----------------------------------------------------------------------
# Test cases vtab1.1.*
#

# We cannot create a virtual table if the module has not been registered.
#
do_test vtab1-1.1.1 {



  catchsql {
    CREATE VIRTUAL TABLE t1 USING echo;
  }
} {1 {no such module: echo}}
do_test vtab1-1.1.2 {
  catchsql {
    CREATE VIRTUAL TABLE IF NOT EXISTS t1 USING echo;