/ Check-in [5f0e803e]
Login

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

Overview
Comment:Fix test cases so that they work with the new EXPLAIN QUERY PLAN output format. Only some of the cases have been fixed. This is an incremental check-in.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | rework-EQP
Files: files | file ages | folders
SHA3-256: 5f0e803e33aa557865d5fc830d9202d628de9a94c9757058ca48f1a560702cd3
User & Date: drh 2018-05-02 18:00:17
Context
2018-05-02
19:42
More test case updates. Tests are all running now. check-in: dab5e529 user: drh tags: rework-EQP
18:00
Fix test cases so that they work with the new EXPLAIN QUERY PLAN output format. Only some of the cases have been fixed. This is an incremental check-in. check-in: 5f0e803e user: drh tags: rework-EQP
16:13
Improved EQP output for recursive CTEs and multi-value VALUES clauses. check-in: f2f52554 user: drh tags: rework-EQP
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to ext/fts5/test/fts5plan.test.

25
26
27
28
29
30
31

32
33
34
35
36
37
38

39
40
41
42
43
44
45

46
47
48
49
50
51
52

53
54
55
56
57
58
59
60
61
62
63
64
65
66
  CREATE TABLE t1(x, y);
  CREATE VIRTUAL TABLE f1 USING fts5(ff);
}

do_eqp_test 1.1 {
  SELECT * FROM t1, f1 WHERE f1 MATCH t1.x
} {

  0 0 0 {SCAN TABLE t1} 
  0 1 1 {SCAN TABLE f1 VIRTUAL TABLE INDEX 65537:}
}

do_eqp_test 1.2 {
  SELECT * FROM t1, f1 WHERE f1 > t1.x
} {

  0 0 1 {SCAN TABLE f1 VIRTUAL TABLE INDEX 0:}
  0 1 0 {SCAN TABLE t1} 
}

do_eqp_test 1.3 {
  SELECT * FROM f1 WHERE f1 MATCH ? ORDER BY ff
} {

  0 0 0 {SCAN TABLE f1 VIRTUAL TABLE INDEX 65537:}
  0 0 0 {USE TEMP B-TREE FOR ORDER BY}
}

do_eqp_test 1.4 {
  SELECT * FROM f1 ORDER BY rank
} {

  0 0 0 {SCAN TABLE f1 VIRTUAL TABLE INDEX 0:}
  0 0 0 {USE TEMP B-TREE FOR ORDER BY}
}

do_eqp_test 1.5 {
  SELECT * FROM f1 WHERE rank MATCH ?
} {
  0 0 0 {SCAN TABLE f1 VIRTUAL TABLE INDEX 2:}
}




finish_test







>
|
|





>
|
|





>
|
|





>
|
|




<
|
|
<
<
<
<

25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62

63
64




65
  CREATE TABLE t1(x, y);
  CREATE VIRTUAL TABLE f1 USING fts5(ff);
}

do_eqp_test 1.1 {
  SELECT * FROM t1, f1 WHERE f1 MATCH t1.x
} {
  QUERY PLAN
  |--SCAN TABLE t1
  `--SCAN TABLE f1 VIRTUAL TABLE INDEX 65537:
}

do_eqp_test 1.2 {
  SELECT * FROM t1, f1 WHERE f1 > t1.x
} {
  QUERY PLAN
  |--SCAN TABLE f1 VIRTUAL TABLE INDEX 0:
  `--SCAN TABLE t1
}

do_eqp_test 1.3 {
  SELECT * FROM f1 WHERE f1 MATCH ? ORDER BY ff
} {
  QUERY PLAN
  |--SCAN TABLE f1 VIRTUAL TABLE INDEX 65537:
  `--USE TEMP B-TREE FOR ORDER BY
}

do_eqp_test 1.4 {
  SELECT * FROM f1 ORDER BY rank
} {
  QUERY PLAN
  |--SCAN TABLE f1 VIRTUAL TABLE INDEX 0:
  `--USE TEMP B-TREE FOR ORDER BY
}

do_eqp_test 1.5 {
  SELECT * FROM f1 WHERE rank MATCH ?

} {SCAN TABLE f1 VIRTUAL TABLE INDEX 2:





finish_test

Changes to src/where.c.

4588
4589
4590
4591
4592
4593
4594
4595
4596
4597
4598
4599
4600
4601
4602
  /* Special case: No FROM clause
  */
  if( nTabList==0 ){
    if( pOrderBy ) pWInfo->nOBSat = pOrderBy->nExpr;
    if( wctrlFlags & WHERE_WANT_DISTINCT ){
      pWInfo->eDistinct = WHERE_DISTINCT_UNIQUE;
    }
    ExplainQueryPlan((pParse, 0, "SCAN CONSTANT ROW"));
  }else{
    /* Assign a bit from the bitmask to every term in the FROM clause.
    **
    ** The N-th term of the FROM clause is assigned a bitmask of 1<<N.
    **
    ** The rule of the previous sentence ensures thta if X is the bitmask for
    ** a table T, then X-1 is the bitmask for all other tables to the left of T.







|







4588
4589
4590
4591
4592
4593
4594
4595
4596
4597
4598
4599
4600
4601
4602
  /* Special case: No FROM clause
  */
  if( nTabList==0 ){
    if( pOrderBy ) pWInfo->nOBSat = pOrderBy->nExpr;
    if( wctrlFlags & WHERE_WANT_DISTINCT ){
      pWInfo->eDistinct = WHERE_DISTINCT_UNIQUE;
    }
    /* ExplainQueryPlan((pParse, 0, "SCAN CONSTANT ROW")); */
  }else{
    /* Assign a bit from the bitmask to every term in the FROM clause.
    **
    ** The N-th term of the FROM clause is assigned a bitmask of 1<<N.
    **
    ** The rule of the previous sentence ensures thta if X is the bitmask for
    ** a table T, then X-1 is the bitmask for all other tables to the left of T.

Changes to test/analyzeA.test.

132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
...
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
  do_execsql_test 1.$tn.2.1 { SELECT count(*) FROM t1 WHERE b=31 } 1
  do_execsql_test 1.$tn.2.2 { SELECT count(*) FROM t1 WHERE c=0  } 49
  do_execsql_test 1.$tn.2.3 { SELECT count(*) FROM t1 WHERE b=125  } 49
  do_execsql_test 1.$tn.2.4 { SELECT count(*) FROM t1 WHERE c=16  } 1

  do_eqp_test 1.$tn.2.5 {
    SELECT * FROM t1 WHERE b = 31 AND c = 0;
  } {0 0 0 {SEARCH TABLE t1 USING INDEX t1b (b=?)}}
  do_eqp_test 1.$tn.2.6 {
    SELECT * FROM t1 WHERE b = 125 AND c = 16;
  } {0 0 0 {SEARCH TABLE t1 USING INDEX t1c (c=?)}}

  do_execsql_test 1.$tn.3.1 { 
    SELECT count(*) FROM t1 WHERE b BETWEEN 0 AND 50
  } {6}
  do_execsql_test 1.$tn.3.2 { 
    SELECT count(*) FROM t1 WHERE c BETWEEN 0 AND 50
  } {90}
................................................................................
  } {90}
  do_execsql_test 1.$tn.3.4 { 
    SELECT count(*) FROM t1 WHERE c BETWEEN 75 AND 125
  } {6}

  do_eqp_test 1.$tn.3.5 {
    SELECT * FROM t1 WHERE b BETWEEN 0 AND 50 AND c BETWEEN 0 AND 50
  } {0 0 0 {SEARCH TABLE t1 USING INDEX t1b (b>? AND b<?)}}

  do_eqp_test 1.$tn.3.6 {
    SELECT * FROM t1 WHERE b BETWEEN 75 AND 125 AND c BETWEEN 75 AND 125
  } {0 0 0 {SEARCH TABLE t1 USING INDEX t1c (c>? AND c<?)}}

  do_eqp_test 1.$tn.3.7 {
    SELECT * FROM t1 WHERE b BETWEEN +0 AND +50 AND c BETWEEN +0 AND +50
  } {0 0 0 {SEARCH TABLE t1 USING INDEX t1b (b>? AND b<?)}}

  do_eqp_test 1.$tn.3.8 {
    SELECT * FROM t1
     WHERE b BETWEEN cast('0' AS int) AND cast('50.0' AS real)
       AND c BETWEEN cast('0' AS numeric) AND cast('50.0' AS real)
  } {0 0 0 {SEARCH TABLE t1 USING INDEX t1b (b>? AND b<?)}}

  do_eqp_test 1.$tn.3.9 {
    SELECT * FROM t1 WHERE b BETWEEN +75 AND +125 AND c BETWEEN +75 AND +125
  } {0 0 0 {SEARCH TABLE t1 USING INDEX t1c (c>? AND c<?)}}

  do_eqp_test 1.$tn.3.10 {
    SELECT * FROM t1
     WHERE b BETWEEN cast('75' AS int) AND cast('125.0' AS real)
       AND c BETWEEN cast('75' AS numeric) AND cast('125.0' AS real)
  } {0 0 0 {SEARCH TABLE t1 USING INDEX t1c (c>? AND c<?)}}
}

finish_test







|


|







 







|



|



|





|



|





|



132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
...
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
  do_execsql_test 1.$tn.2.1 { SELECT count(*) FROM t1 WHERE b=31 } 1
  do_execsql_test 1.$tn.2.2 { SELECT count(*) FROM t1 WHERE c=0  } 49
  do_execsql_test 1.$tn.2.3 { SELECT count(*) FROM t1 WHERE b=125  } 49
  do_execsql_test 1.$tn.2.4 { SELECT count(*) FROM t1 WHERE c=16  } 1

  do_eqp_test 1.$tn.2.5 {
    SELECT * FROM t1 WHERE b = 31 AND c = 0;
  } {SEARCH TABLE t1 USING INDEX t1b (b=?)}
  do_eqp_test 1.$tn.2.6 {
    SELECT * FROM t1 WHERE b = 125 AND c = 16;
  } {SEARCH TABLE t1 USING INDEX t1c (c=?)}

  do_execsql_test 1.$tn.3.1 { 
    SELECT count(*) FROM t1 WHERE b BETWEEN 0 AND 50
  } {6}
  do_execsql_test 1.$tn.3.2 { 
    SELECT count(*) FROM t1 WHERE c BETWEEN 0 AND 50
  } {90}
................................................................................
  } {90}
  do_execsql_test 1.$tn.3.4 { 
    SELECT count(*) FROM t1 WHERE c BETWEEN 75 AND 125
  } {6}

  do_eqp_test 1.$tn.3.5 {
    SELECT * FROM t1 WHERE b BETWEEN 0 AND 50 AND c BETWEEN 0 AND 50
  } {SEARCH TABLE t1 USING INDEX t1b (b>? AND b<?)}

  do_eqp_test 1.$tn.3.6 {
    SELECT * FROM t1 WHERE b BETWEEN 75 AND 125 AND c BETWEEN 75 AND 125
  } {SEARCH TABLE t1 USING INDEX t1c (c>? AND c<?)}

  do_eqp_test 1.$tn.3.7 {
    SELECT * FROM t1 WHERE b BETWEEN +0 AND +50 AND c BETWEEN +0 AND +50
  } {SEARCH TABLE t1 USING INDEX t1b (b>? AND b<?)}

  do_eqp_test 1.$tn.3.8 {
    SELECT * FROM t1
     WHERE b BETWEEN cast('0' AS int) AND cast('50.0' AS real)
       AND c BETWEEN cast('0' AS numeric) AND cast('50.0' AS real)
  } {SEARCH TABLE t1 USING INDEX t1b (b>? AND b<?)}

  do_eqp_test 1.$tn.3.9 {
    SELECT * FROM t1 WHERE b BETWEEN +75 AND +125 AND c BETWEEN +75 AND +125
  } {SEARCH TABLE t1 USING INDEX t1c (c>? AND c<?)}

  do_eqp_test 1.$tn.3.10 {
    SELECT * FROM t1
     WHERE b BETWEEN cast('75' AS int) AND cast('125.0' AS real)
       AND c BETWEEN cast('75' AS numeric) AND cast('125.0' AS real)
  } {SEARCH TABLE t1 USING INDEX t1c (c>? AND c<?)}
}

finish_test

Changes to test/analyzeD.test.

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
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
} {}

# With full ANALYZE data, SQLite sees that c=150 (5 rows) is better than
# a=3001 (7 rows).
#
do_eqp_test 1.2 {
  SELECT * FROM t1 WHERE a=3001 AND c=150;
} {
  0 0 0 {SEARCH TABLE t1 USING INDEX t1_c (c=?)}
}

do_test 1.3 {
  execsql { DELETE FROM sqlite_stat1 }
  db close
  sqlite3 db test.db
} {}

................................................................................
# Without stat1, because 3001 is larger than all samples in the stat4
# table, SQLite thinks that a=3001 matches just 1 row. So it (incorrectly)
# chooses it over the c=150 index (5 rows). Even with stat1 data, things
# worked this way before commit [e6f7f97dbc].
#
do_eqp_test 1.4 {
  SELECT * FROM t1 WHERE a=3001 AND c=150;
} {
  0 0 0 {SEARCH TABLE t1 USING INDEX t1_ab (a=?)}
}

do_test 1.5 {
  execsql { 
    UPDATE t1 SET a=13 WHERE a = 3001;
    ANALYZE;
  }
} {}

do_eqp_test 1.6 {
  SELECT * FROM t1 WHERE a=13 AND c=150;
} {
  0 0 0 {SEARCH TABLE t1 USING INDEX t1_c (c=?)}
}

do_test 1.7 {
  execsql { DELETE FROM sqlite_stat1 }
  db close
  sqlite3 db test.db
} {}

# Same test as 1.4, except this time the 7 rows that match the a=? condition 
# do not feature larger values than all rows in the stat4 table. So SQLite
# gets this right, even without stat1 data.
do_eqp_test 1.8 {
  SELECT * FROM t1 WHERE a=13 AND c=150;
} {
  0 0 0 {SEARCH TABLE t1 USING INDEX t1_c (c=?)}
}

finish_test







<
|
<







 







<
|
<










<
|
<












<
|
|
<

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
84
85
86
87
88
89
90
91

92

93
94
95
96
97
98
99
100
101
102
103
104

105
106

107
} {}

# With full ANALYZE data, SQLite sees that c=150 (5 rows) is better than
# a=3001 (7 rows).
#
do_eqp_test 1.2 {
  SELECT * FROM t1 WHERE a=3001 AND c=150;

} {SEARCH TABLE t1 USING INDEX t1_c (c=?)}


do_test 1.3 {
  execsql { DELETE FROM sqlite_stat1 }
  db close
  sqlite3 db test.db
} {}

................................................................................
# Without stat1, because 3001 is larger than all samples in the stat4
# table, SQLite thinks that a=3001 matches just 1 row. So it (incorrectly)
# chooses it over the c=150 index (5 rows). Even with stat1 data, things
# worked this way before commit [e6f7f97dbc].
#
do_eqp_test 1.4 {
  SELECT * FROM t1 WHERE a=3001 AND c=150;

} {SEARCH TABLE t1 USING INDEX t1_ab (a=?)}


do_test 1.5 {
  execsql { 
    UPDATE t1 SET a=13 WHERE a = 3001;
    ANALYZE;
  }
} {}

do_eqp_test 1.6 {
  SELECT * FROM t1 WHERE a=13 AND c=150;

} {SEARCH TABLE t1 USING INDEX t1_c (c=?)}


do_test 1.7 {
  execsql { DELETE FROM sqlite_stat1 }
  db close
  sqlite3 db test.db
} {}

# Same test as 1.4, except this time the 7 rows that match the a=? condition 
# do not feature larger values than all rows in the stat4 table. So SQLite
# gets this right, even without stat1 data.
do_eqp_test 1.8 {
  SELECT * FROM t1 WHERE a=13 AND c=150;

} {SEARCH TABLE t1 USING INDEX t1_c (c=?)}


finish_test

Changes to test/analyzeF.test.

58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
..
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102

  9  "x = str('19') AND y = str('4')" {t1y (y=?)}
  10 "x = str('4') AND y = str('19')" {t1y (y=?)}

  11 "x = nullif('19', 0) AND y = nullif('4', 0)" {t1y (y=?)}
  12 "x = nullif('4', 0) AND y = nullif('19', 0)" {t1y (y=?)}
} {
  set res "0 0 0 {SEARCH TABLE t1 USING INDEX $idx}"
  do_eqp_test 1.$tn "SELECT * FROM t1 WHERE $where" $res
}

# Test that functions that do not exist - "func()" - do not cause an error.
#
do_catchsql_test 2.1 {
  SELECT * FROM t1 WHERE x = substr('145', 2, 1) AND y = func(1, 2, 3)
................................................................................
foreach {tn where idx} {
  1 "x = det4() AND y = det19()"     {t1x (x=?)}
  2 "x = det19() AND y = det4()"     {t1y (y=?)}

  3 "x = nondet4() AND y = nondet19()"     {t1y (y=?)}
  4 "x = nondet19() AND y = nondet4()"     {t1y (y=?)}
} {
  set res "0 0 0 {SEARCH TABLE t1 USING INDEX $idx}"
  do_eqp_test 3.$tn "SELECT * FROM t1 WHERE $where" $res
}


execsql { DELETE FROM t1 }

proc throw_error {err} { error $err }







|







 







|







58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
..
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102

  9  "x = str('19') AND y = str('4')" {t1y (y=?)}
  10 "x = str('4') AND y = str('19')" {t1y (y=?)}

  11 "x = nullif('19', 0) AND y = nullif('4', 0)" {t1y (y=?)}
  12 "x = nullif('4', 0) AND y = nullif('19', 0)" {t1y (y=?)}
} {
  set res "SEARCH TABLE t1 USING INDEX $idx"
  do_eqp_test 1.$tn "SELECT * FROM t1 WHERE $where" $res
}

# Test that functions that do not exist - "func()" - do not cause an error.
#
do_catchsql_test 2.1 {
  SELECT * FROM t1 WHERE x = substr('145', 2, 1) AND y = func(1, 2, 3)
................................................................................
foreach {tn where idx} {
  1 "x = det4() AND y = det19()"     {t1x (x=?)}
  2 "x = det19() AND y = det4()"     {t1y (y=?)}

  3 "x = nondet4() AND y = nondet19()"     {t1y (y=?)}
  4 "x = nondet19() AND y = nondet4()"     {t1y (y=?)}
} {
  set res "SEARCH TABLE t1 USING INDEX $idx"
  do_eqp_test 3.$tn "SELECT * FROM t1 WHERE $where" $res
}


execsql { DELETE FROM t1 }

proc throw_error {err} { error $err }

Changes to test/autoindex3.test.

80
81
82
83
84
85
86

87
88
89
90
91
92
# on the basis that the real index "uab" must be better than the automatic
# index. This is not right - a skip-scan is not necessarily better than an
# automatic index scan.
#
do_eqp_test 220 {
  select count(*) from u, v where u.b = v.b and v.e > 34;
} {

  0 0 1 {SEARCH TABLE v USING INDEX ve (e>?)} 
  0 1 0 {SEARCH TABLE u USING AUTOMATIC COVERING INDEX (b=?)}
}


finish_test







>
|
|




80
81
82
83
84
85
86
87
88
89
90
91
92
93
# on the basis that the real index "uab" must be better than the automatic
# index. This is not right - a skip-scan is not necessarily better than an
# automatic index scan.
#
do_eqp_test 220 {
  select count(*) from u, v where u.b = v.b and v.e > 34;
} {
  QUERY PLAN
  |--SEARCH TABLE v USING INDEX ve (e>?)
  `--SEARCH TABLE u USING AUTOMATIC COVERING INDEX (b=?)
}


finish_test

Changes to test/bestindex1.test.

47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
...
140
141
142
143
144
145
146

147
148
149
150

151
152
153
154

155
156
157
158
159
160
161
162
163
164
165
166
167
168

do_execsql_test 1.0 {
  CREATE VIRTUAL TABLE x1 USING tcl(vtab_command);
} {}

do_eqp_test 1.1 {
  SELECT * FROM x1 WHERE a = 'abc'
} {
  0 0 0 {SCAN TABLE x1 VIRTUAL TABLE INDEX 555:eq!}
}

do_eqp_test 1.2 {
  SELECT * FROM x1 WHERE a IN ('abc', 'def');
} {
  0 0 0 {SCAN TABLE x1 VIRTUAL TABLE INDEX 555:eq!}
}

#-------------------------------------------------------------------------
#
reset_db
register_tcl_module db

# Parameter $mode may be one of:
................................................................................
  do_execsql_test 2.2.$mode.4 {SELECT rowid FROM t1 WHERE a='two'} {2} 

  do_execsql_test 2.2.$mode.5 {
    SELECT rowid FROM t1 WHERE a IN ('one', 'four') ORDER BY +rowid
  } {1 4} 

  set plan(use) {

    0 0 0 {SCAN TABLE t1 VIRTUAL TABLE INDEX 0:SELECT * FROM t1x WHERE a='%1%'}
    0 0 0 {USE TEMP B-TREE FOR ORDER BY}
  }
  set plan(omit) {

    0 0 0 {SCAN TABLE t1 VIRTUAL TABLE INDEX 0:SELECT * FROM t1x WHERE a='%1%'}
    0 0 0 {USE TEMP B-TREE FOR ORDER BY}
  }
  set plan(use2) {

    0 0 0 {SCAN TABLE t1 VIRTUAL TABLE INDEX 0:SELECT * FROM t1x}
    0 0 0 {USE TEMP B-TREE FOR ORDER BY}
  }

  do_eqp_test 2.2.$mode.6 { 
    SELECT rowid FROM t1 WHERE a IN ('one', 'four') ORDER BY +rowid
  } $plan($mode)
}

# 2016-04-09.
# Demonstrate a register overwrite problem when using two virtual
# tables where the outer loop uses the IN operator.
#
set G(collist) [list PrimaryKey flagA columnA]







<
|
<



<
|
<







 







>
|
|


>
|
|


>
|
|




|







47
48
49
50
51
52
53

54

55
56
57

58

59
60
61
62
63
64
65
...
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167

do_execsql_test 1.0 {
  CREATE VIRTUAL TABLE x1 USING tcl(vtab_command);
} {}

do_eqp_test 1.1 {
  SELECT * FROM x1 WHERE a = 'abc'

} {SCAN TABLE x1 VIRTUAL TABLE INDEX 555:eq!}


do_eqp_test 1.2 {
  SELECT * FROM x1 WHERE a IN ('abc', 'def');

} {SCAN TABLE x1 VIRTUAL TABLE INDEX 555:eq!}


#-------------------------------------------------------------------------
#
reset_db
register_tcl_module db

# Parameter $mode may be one of:
................................................................................
  do_execsql_test 2.2.$mode.4 {SELECT rowid FROM t1 WHERE a='two'} {2} 

  do_execsql_test 2.2.$mode.5 {
    SELECT rowid FROM t1 WHERE a IN ('one', 'four') ORDER BY +rowid
  } {1 4} 

  set plan(use) {
    QUERY PLAN
    |--SCAN TABLE t1 VIRTUAL TABLE INDEX 0:SELECT * FROM t1x WHERE a='%1%'
    `--USE TEMP B-TREE FOR ORDER BY
  }
  set plan(omit) {
    QUERY PLAN
    |--SCAN TABLE t1 VIRTUAL TABLE INDEX 0:SELECT * FROM t1x WHERE a='%1%'
    `--USE TEMP B-TREE FOR ORDER BY
  }
  set plan(use2) {
    QUERY PLAN
    |--SCAN TABLE t1 VIRTUAL TABLE INDEX 0:SELECT * FROM t1x
    `--USE TEMP B-TREE FOR ORDER BY
  }

  do_eqp_test 2.2.$mode.6 { 
    SELECT rowid FROM t1 WHERE a IN ('one', 'four') ORDER BY +rowid
  } [string map {"\n  " "\n"} $plan($mode)]
}

# 2016-04-09.
# Demonstrate a register overwrite problem when using two virtual
# tables where the outer loop uses the IN operator.
#
set G(collist) [list PrimaryKey flagA columnA]

Changes to test/bestindex2.test.

85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107

108
109
110
111
112
113
114

115
116
117
118
119
120
121
122

123
124
125
126
127
128
129
130
131
132
133
134

135
136
137
138
139
140
141
  CREATE VIRTUAL TABLE t1 USING tcl("vtab_cmd t1 {a b}");
  CREATE VIRTUAL TABLE t2 USING tcl("vtab_cmd t2 {c d}");
  CREATE VIRTUAL TABLE t3 USING tcl("vtab_cmd t3 {e f}");
}

do_eqp_test 1.1 {
  SELECT * FROM t1 WHERE a='abc'
} {
  0 0 0 {SCAN TABLE t1 VIRTUAL TABLE INDEX 0:indexed(a=?)}
}
do_eqp_test 1.2 {
  SELECT * FROM t1 WHERE a='abc' AND b='def'
} {
  0 0 0 {SCAN TABLE t1 VIRTUAL TABLE INDEX 0:indexed(a=? AND b=?)}
}
do_eqp_test 1.3 {
  SELECT * FROM t1 WHERE a='abc' AND a='def'
} {
  0 0 0 {SCAN TABLE t1 VIRTUAL TABLE INDEX 0:indexed(a=?)}
}
do_eqp_test 1.4 {
  SELECT * FROM t1,t2 WHERE c=a
} {

  0 0 0 {SCAN TABLE t1 VIRTUAL TABLE INDEX 0:} 
  0 1 1 {SCAN TABLE t2 VIRTUAL TABLE INDEX 0:indexed(c=?)}
}

do_eqp_test 1.5 {
  SELECT * FROM t1, t2 CROSS JOIN t3 WHERE t2.c = +t1.b AND t3.e=t2.d
} {

  0 0 0 {SCAN TABLE t1 VIRTUAL TABLE INDEX 0:} 
  0 1 1 {SCAN TABLE t2 VIRTUAL TABLE INDEX 0:indexed(c=?)} 
  0 2 2 {SCAN TABLE t3 VIRTUAL TABLE INDEX 0:indexed(e=?)}
}

do_eqp_test 1.6 {
  SELECT * FROM t1, t2, t3 WHERE t2.c = +t1.b AND t3.e = t2.d
} {

  0 0 0 {SCAN TABLE t1 VIRTUAL TABLE INDEX 0:} 
  0 1 1 {SCAN TABLE t2 VIRTUAL TABLE INDEX 0:indexed(c=?)} 
  0 2 2 {SCAN TABLE t3 VIRTUAL TABLE INDEX 0:indexed(e=?)}
}

do_execsql_test 1.7.1 {
  CREATE TABLE x1(a, b);
}
do_eqp_test 1.7.2 {
  SELECT * FROM x1 CROSS JOIN t1, t2, t3 
    WHERE t1.a = t2.c AND t1.b = t3.e
} {

  0 0 0 {SCAN TABLE x1} 
  0 1 1 {SCAN TABLE t1 VIRTUAL TABLE INDEX 0:}
  0 2 2 {SCAN TABLE t2 VIRTUAL TABLE INDEX 0:indexed(c=?)} 
  0 3 3 {SCAN TABLE t3 VIRTUAL TABLE INDEX 0:indexed(e=?)}
}

finish_test







<
|
|


<
|
|


<
|
|



>
|
|





>
|
|
|





>
|
|
|









>
|
|
|
|



85
86
87
88
89
90
91

92
93
94
95

96
97
98
99

100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
  CREATE VIRTUAL TABLE t1 USING tcl("vtab_cmd t1 {a b}");
  CREATE VIRTUAL TABLE t2 USING tcl("vtab_cmd t2 {c d}");
  CREATE VIRTUAL TABLE t3 USING tcl("vtab_cmd t3 {e f}");
}

do_eqp_test 1.1 {
  SELECT * FROM t1 WHERE a='abc'

} {SCAN TABLE t1 VIRTUAL TABLE INDEX 0:indexed(a=?)}

do_eqp_test 1.2 {
  SELECT * FROM t1 WHERE a='abc' AND b='def'

} {SCAN TABLE t1 VIRTUAL TABLE INDEX 0:indexed(a=? AND b=?)}

do_eqp_test 1.3 {
  SELECT * FROM t1 WHERE a='abc' AND a='def'

} {SCAN TABLE t1 VIRTUAL TABLE INDEX 0:indexed(a=?)}

do_eqp_test 1.4 {
  SELECT * FROM t1,t2 WHERE c=a
} {
  QUERY PLAN
  |--SCAN TABLE t1 VIRTUAL TABLE INDEX 0:
  `--SCAN TABLE t2 VIRTUAL TABLE INDEX 0:indexed(c=?)
}

do_eqp_test 1.5 {
  SELECT * FROM t1, t2 CROSS JOIN t3 WHERE t2.c = +t1.b AND t3.e=t2.d
} {
  QUERY PLAN
  |--SCAN TABLE t1 VIRTUAL TABLE INDEX 0:
  |--SCAN TABLE t2 VIRTUAL TABLE INDEX 0:indexed(c=?)
  `--SCAN TABLE t3 VIRTUAL TABLE INDEX 0:indexed(e=?)
}

do_eqp_test 1.6 {
  SELECT * FROM t1, t2, t3 WHERE t2.c = +t1.b AND t3.e = t2.d
} {
  QUERY PLAN
  |--SCAN TABLE t1 VIRTUAL TABLE INDEX 0:
  |--SCAN TABLE t2 VIRTUAL TABLE INDEX 0:indexed(c=?)
  `--SCAN TABLE t3 VIRTUAL TABLE INDEX 0:indexed(e=?)
}

do_execsql_test 1.7.1 {
  CREATE TABLE x1(a, b);
}
do_eqp_test 1.7.2 {
  SELECT * FROM x1 CROSS JOIN t1, t2, t3 
    WHERE t1.a = t2.c AND t1.b = t3.e
} {
  QUERY PLAN
  |--SCAN TABLE x1
  |--SCAN TABLE t1 VIRTUAL TABLE INDEX 0:
  |--SCAN TABLE t2 VIRTUAL TABLE INDEX 0:indexed(c=?)
  `--SCAN TABLE t3 VIRTUAL TABLE INDEX 0:indexed(e=?)
}

finish_test

Changes to test/bestindex3.test.

75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94

95
96
97
98
99
100
101

102
103
104
105
106
107
108
109
110
...
144
145
146
147
148
149
150

151
152
153
154
155
156
157
158
159

do_execsql_test 1.0 {
  CREATE VIRTUAL TABLE t1 USING tcl("vtab_cmd 0");
}

do_eqp_test 1.1 {
  SELECT * FROM t1 WHERE a LIKE 'abc';
} {
  0 0 0 {SCAN TABLE t1 VIRTUAL TABLE INDEX 0:a LIKE ?}
}

do_eqp_test 1.2 {
  SELECT * FROM t1 WHERE a = 'abc';
} {
  0 0 0 {SCAN TABLE t1 VIRTUAL TABLE INDEX 0:a EQ ?}
}

do_eqp_test 1.3 {
  SELECT * FROM t1 WHERE a = 'abc' OR b = 'def';
} {

  0 0 0 {SCAN TABLE t1 VIRTUAL TABLE INDEX 0:a EQ ?}
  0 0 0 {SCAN TABLE t1 VIRTUAL TABLE INDEX 0:b EQ ?}
}

do_eqp_test 1.4 {
  SELECT * FROM t1 WHERE a LIKE 'abc%' OR b = 'def';
} {

  0 0 0 {SCAN TABLE t1 VIRTUAL TABLE INDEX 0:a LIKE ?}
  0 0 0 {SCAN TABLE t1 VIRTUAL TABLE INDEX 0:b EQ ?}
}

do_execsql_test 1.5 {
  CREATE TABLE ttt(a, b, c);

  INSERT INTO ttt VALUES(1, 'two',   'three');
  INSERT INTO ttt VALUES(2, 'one',   'two');
................................................................................
    CREATE INDEX t2x ON t2(x COLLATE nocase);
    CREATE INDEX t2y ON t2(y);
  }

  do_eqp_test 2.2 {
    SELECT * FROM t2 WHERE x LIKE 'abc%' OR y = 'def'
  } {

    0 0 0 {SEARCH TABLE t2 USING INDEX t2x (x>? AND x<?)}
    0 0 0 {SEARCH TABLE t2 USING INDEX t2y (y=?)}
  }
}

#-------------------------------------------------------------------------
# Test that any PRIMARY KEY within a sqlite3_decl_vtab() CREATE TABLE 
# statement is currently ignored.
#







<
|
<



<
|
<




>
|
|





>
|
|







 







>
|
|







75
76
77
78
79
80
81

82

83
84
85

86

87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
...
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158

do_execsql_test 1.0 {
  CREATE VIRTUAL TABLE t1 USING tcl("vtab_cmd 0");
}

do_eqp_test 1.1 {
  SELECT * FROM t1 WHERE a LIKE 'abc';

} {SCAN TABLE t1 VIRTUAL TABLE INDEX 0:a LIKE ?}


do_eqp_test 1.2 {
  SELECT * FROM t1 WHERE a = 'abc';

} {SCAN TABLE t1 VIRTUAL TABLE INDEX 0:a EQ ?}


do_eqp_test 1.3 {
  SELECT * FROM t1 WHERE a = 'abc' OR b = 'def';
} {
  QUERY PLAN
  |--SCAN TABLE t1 VIRTUAL TABLE INDEX 0:a EQ ?
  `--SCAN TABLE t1 VIRTUAL TABLE INDEX 0:b EQ ?
}

do_eqp_test 1.4 {
  SELECT * FROM t1 WHERE a LIKE 'abc%' OR b = 'def';
} {
  QUERY PLAN
  |--SCAN TABLE t1 VIRTUAL TABLE INDEX 0:a LIKE ?
  `--SCAN TABLE t1 VIRTUAL TABLE INDEX 0:b EQ ?
}

do_execsql_test 1.5 {
  CREATE TABLE ttt(a, b, c);

  INSERT INTO ttt VALUES(1, 'two',   'three');
  INSERT INTO ttt VALUES(2, 'one',   'two');
................................................................................
    CREATE INDEX t2x ON t2(x COLLATE nocase);
    CREATE INDEX t2y ON t2(y);
  }

  do_eqp_test 2.2 {
    SELECT * FROM t2 WHERE x LIKE 'abc%' OR y = 'def'
  } {
  QUERY PLAN
  |--SEARCH TABLE t2 USING INDEX t2x (x>? AND x<?)
  `--SEARCH TABLE t2 USING INDEX t2y (y=?)
  }
}

#-------------------------------------------------------------------------
# Test that any PRIMARY KEY within a sqlite3_decl_vtab() CREATE TABLE 
# statement is currently ignored.
#

Changes to test/bigmmap.test.

88
89
90
91
92
93
94
95

96
97
98
99
100
101
102
103
104
      ORDER BY b, c;
    " {}
    
    do_eqp_test 2.$i.$t.3 "
      SELECT * FROM t$t AS o WHERE 
        NOT EXISTS( SELECT * FROM t$t AS i WHERE a=o.a AND +b=o.b AND +c=o.c )
      ORDER BY b, c;
    " "

      0 0 0 {SCAN TABLE t$t AS o USING COVERING INDEX sqlite_autoindex_t${t}_1}
      0 0 0 {EXECUTE CORRELATED SCALAR SUBQUERY 1}
      1 0 0 {SEARCH TABLE t$t AS i USING INTEGER PRIMARY KEY (rowid=?)}
    "
  }
}

finish_test








|
>
|
|
|
|




<
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104

      ORDER BY b, c;
    " {}
    
    do_eqp_test 2.$i.$t.3 "
      SELECT * FROM t$t AS o WHERE 
        NOT EXISTS( SELECT * FROM t$t AS i WHERE a=o.a AND +b=o.b AND +c=o.c )
      ORDER BY b, c;
    " [string map {"\n    " "\n"} "
      QUERY PLAN
      |--SCAN TABLE t$t AS o USING COVERING INDEX sqlite_autoindex_t${t}_1
      `--CORRELATED SCALAR SUBQUERY
         `--SEARCH TABLE t$t AS i USING INTEGER PRIMARY KEY (rowid=?)
    "]
  }
}

finish_test

Changes to test/cost.test.

20
21
22
23
24
25
26

27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
..
53
54
55
56
57
58
59

60
61
62
63
64
65
66
67
68
69
70
..
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102

103
104
105
106
107
108
109

110
111
112
113
114
115
116
117
118
119
120
121
122
123
124

125
126
127
128
129
130
131
132
133
134
...
141
142
143
144
145
146
147

148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
...
190
191
192
193
194
195
196

197
198
199
200
201
202
203
204
205
206
207
...
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
  CREATE TABLE t4(c, d, e);
  CREATE UNIQUE INDEX i3 ON t3(b);
  CREATE UNIQUE INDEX i4 ON t4(c, d);
}
do_eqp_test 1.2 {
  SELECT e FROM t3, t4 WHERE b=c ORDER BY b, d;
} {

  0 0 0 {SCAN TABLE t3 USING COVERING INDEX i3} 
  0 1 1 {SEARCH TABLE t4 USING INDEX i4 (c=?)}
}


do_execsql_test 2.1 {
  CREATE TABLE t1(a, b);
  CREATE INDEX i1 ON t1(a);
}

# It is better to use an index for ORDER BY than sort externally, even 
# if the index is a non-covering index.
do_eqp_test 2.2 {
  SELECT * FROM t1 ORDER BY a;
} {
  0 0 0 {SCAN TABLE t1 USING INDEX i1}
}

do_execsql_test 3.1 {
  CREATE TABLE t5(a INTEGER PRIMARY KEY,b,c,d,e,f,g);
  CREATE INDEX t5b ON t5(b);
  CREATE INDEX t5c ON t5(c);
  CREATE INDEX t5d ON t5(d);
  CREATE INDEX t5e ON t5(e);
................................................................................
}

do_eqp_test 3.2 {
  SELECT a FROM t5 
  WHERE b IS NULL OR c IS NULL OR d IS NULL 
  ORDER BY a;
} {

  0 0 0 {SEARCH TABLE t5 USING INDEX t5b (b=?)} 
  0 0 0 {SEARCH TABLE t5 USING INDEX t5c (c=?)} 
  0 0 0 {SEARCH TABLE t5 USING INDEX t5d (d=?)} 
  0 0 0 {USE TEMP B-TREE FOR ORDER BY}
}

#-------------------------------------------------------------------------
# If there is no likelihood() or stat3 data, SQLite assumes that a closed
# range scan (e.g. one constrained by "col BETWEEN ? AND ?" constraint)
# visits 1/64 of the rows in a table.
#
................................................................................
do_execsql_test 4.1 {
  CREATE TABLE t1(a, b);
  CREATE INDEX i1 ON t1(a);
  CREATE INDEX i2 ON t1(b);
}
do_eqp_test 4.2 {
  SELECT * FROM t1 WHERE likelihood(a=?, 0.014) AND b BETWEEN ? AND ?;
} {
  0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a=?)}
}
do_eqp_test 4.3 {
  SELECT * FROM t1 WHERE likelihood(a=?, 0.016) AND b BETWEEN ? AND ?;
} {
  0 0 0 {SEARCH TABLE t1 USING INDEX i2 (b>? AND b<?)}
}


#-------------------------------------------------------------------------
#
reset_db
do_execsql_test 5.1 {
  CREATE TABLE t2(x, y);
  CREATE INDEX t2i1 ON t2(x);
}

do_eqp_test 5.2 {
  SELECT * FROM t2 ORDER BY x, y;
} {

  0 0 0 {SCAN TABLE t2 USING INDEX t2i1} 
  0 0 0 {USE TEMP B-TREE FOR RIGHT PART OF ORDER BY}
}

do_eqp_test 5.3 {
  SELECT * FROM t2 WHERE x BETWEEN ? AND ? ORDER BY rowid;
} {

  0 0 0 {SEARCH TABLE t2 USING INDEX t2i1 (x>? AND x<?)} 
  0 0 0 {USE TEMP B-TREE FOR ORDER BY}
}

# where7.test, where8.test:
#
do_execsql_test 6.1 {
  CREATE TABLE t3(a INTEGER PRIMARY KEY, b, c);
  CREATE INDEX t3i1 ON t3(b);
  CREATE INDEX t3i2 ON t3(c);
}

do_eqp_test 6.2 {
  SELECT a FROM t3 WHERE (b BETWEEN 2 AND 4) OR c=100 ORDER BY a
} {

  0 0 0 {SEARCH TABLE t3 USING INDEX t3i1 (b>? AND b<?)} 
  0 0 0 {SEARCH TABLE t3 USING INDEX t3i2 (c=?)}
  0 0 0 {USE TEMP B-TREE FOR ORDER BY}
}

#-------------------------------------------------------------------------
#
reset_db
do_execsql_test 7.1 {
  CREATE TABLE t1(a INTEGER PRIMARY KEY,b,c,d,e,f,g);
................................................................................
}

do_eqp_test 7.2 {
  SELECT a FROM t1
     WHERE (b>=950 AND b<=1010) OR (b IS NULL AND c NOT NULL)
  ORDER BY a
} {

  0 0 0 {SEARCH TABLE t1 USING INDEX t1b (b>? AND b<?)} 
  0 0 0 {SEARCH TABLE t1 USING INDEX t1b (b=?)} 
  0 0 0 {USE TEMP B-TREE FOR ORDER BY}
}

do_eqp_test 7.3 {
  SELECT rowid FROM t1
  WHERE (+b IS NULL AND c NOT NULL AND d NOT NULL)
        OR (b NOT NULL AND c IS NULL AND d NOT NULL)
        OR (b NOT NULL AND c NOT NULL AND d IS NULL)
} {
  0 0 0 {SCAN TABLE t1}
}

do_eqp_test 7.4 {
  SELECT rowid FROM t1 WHERE (+b IS NULL AND c NOT NULL) OR c IS NULL
} {
  0 0 0 {SCAN TABLE t1}
}

#-------------------------------------------------------------------------
#
reset_db
do_execsql_test 8.1 {
  CREATE TABLE composer(
    cid INTEGER PRIMARY KEY,
................................................................................
do_eqp_test 8.2 {
  SELECT DISTINCT aname
    FROM album, composer, track
   WHERE cname LIKE '%bach%'
     AND unlikely(composer.cid=track.cid)
     AND unlikely(album.aid=track.aid);
} {

  0 0 2 {SCAN TABLE track} 
  0 1 0 {SEARCH TABLE album USING INTEGER PRIMARY KEY (rowid=?)}
  0 2 1 {SEARCH TABLE composer USING INTEGER PRIMARY KEY (rowid=?)}
  0 0 0 {USE TEMP B-TREE FOR DISTINCT}
}

#-------------------------------------------------------------------------
#
do_execsql_test 9.1 {
  CREATE TABLE t1(
    a,b,c,d,e, f,g,h,i,j,
................................................................................
      execsql { INSERT INTO t6 VALUES($i%4, 'xyz', $i%8) }
    }
    execsql ANALYZE
  } {}

  do_eqp_test 10.3 {
    SELECT rowid FROM t6 WHERE a=0 AND c=0
  } {
    0 0 0 {SEARCH TABLE t6 USING INDEX t6i2 (c=?)}
  }

  do_eqp_test 10.4 {
    SELECT rowid FROM t6 WHERE a=0 AND b='xyz' AND c=0
  } {
    0 0 0 {SEARCH TABLE t6 USING INDEX t6i2 (c=?)}
  }

  do_eqp_test 10.5 {
    SELECT rowid FROM t6 WHERE likelihood(a=0, 0.1) AND c=0
  } {
    0 0 0 {SEARCH TABLE t6 USING INDEX t6i1 (a=?)}
  }

  do_eqp_test 10.6 {
    SELECT rowid FROM t6 WHERE likelihood(a=0, 0.1) AND b='xyz' AND c=0
  } {
    0 0 0 {SEARCH TABLE t6 USING INDEX t6i1 (a=? AND b=?)}
  }
}

finish_test







>
|
|












<
|
<







 







>
|
|
|
|







 







<
|
|


<
|
<













>
|
|





>
|
|













>
|
|
|







 







>
|
|
|







<
|
<



<
|
<







 







>
|
|
|
|







 







<
|
<



<
|
<



<
|
<



<
|
<



20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41

42

43
44
45
46
47
48
49
..
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
..
75
76
77
78
79
80
81

82
83
84
85

86

87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
...
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158

159

160
161
162

163

164
165
166
167
168
169
170
...
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
...
257
258
259
260
261
262
263

264

265
266
267

268

269
270
271

272

273
274
275

276

277
278
279
  CREATE TABLE t4(c, d, e);
  CREATE UNIQUE INDEX i3 ON t3(b);
  CREATE UNIQUE INDEX i4 ON t4(c, d);
}
do_eqp_test 1.2 {
  SELECT e FROM t3, t4 WHERE b=c ORDER BY b, d;
} {
  QUERY PLAN
  |--SCAN TABLE t3 USING COVERING INDEX i3
  `--SEARCH TABLE t4 USING INDEX i4 (c=?)
}


do_execsql_test 2.1 {
  CREATE TABLE t1(a, b);
  CREATE INDEX i1 ON t1(a);
}

# It is better to use an index for ORDER BY than sort externally, even 
# if the index is a non-covering index.
do_eqp_test 2.2 {
  SELECT * FROM t1 ORDER BY a;

} {SCAN TABLE t1 USING INDEX i1}


do_execsql_test 3.1 {
  CREATE TABLE t5(a INTEGER PRIMARY KEY,b,c,d,e,f,g);
  CREATE INDEX t5b ON t5(b);
  CREATE INDEX t5c ON t5(c);
  CREATE INDEX t5d ON t5(d);
  CREATE INDEX t5e ON t5(e);
................................................................................
}

do_eqp_test 3.2 {
  SELECT a FROM t5 
  WHERE b IS NULL OR c IS NULL OR d IS NULL 
  ORDER BY a;
} {
  QUERY PLAN
  |--SEARCH TABLE t5 USING INDEX t5b (b=?)
  |--SEARCH TABLE t5 USING INDEX t5c (c=?)
  |--SEARCH TABLE t5 USING INDEX t5d (d=?)
  `--USE TEMP B-TREE FOR ORDER BY
}

#-------------------------------------------------------------------------
# If there is no likelihood() or stat3 data, SQLite assumes that a closed
# range scan (e.g. one constrained by "col BETWEEN ? AND ?" constraint)
# visits 1/64 of the rows in a table.
#
................................................................................
do_execsql_test 4.1 {
  CREATE TABLE t1(a, b);
  CREATE INDEX i1 ON t1(a);
  CREATE INDEX i2 ON t1(b);
}
do_eqp_test 4.2 {
  SELECT * FROM t1 WHERE likelihood(a=?, 0.014) AND b BETWEEN ? AND ?;

} {SEARCH TABLE t1 USING INDEX i1 (a=?)}

do_eqp_test 4.3 {
  SELECT * FROM t1 WHERE likelihood(a=?, 0.016) AND b BETWEEN ? AND ?;

} {SEARCH TABLE t1 USING INDEX i2 (b>? AND b<?)}



#-------------------------------------------------------------------------
#
reset_db
do_execsql_test 5.1 {
  CREATE TABLE t2(x, y);
  CREATE INDEX t2i1 ON t2(x);
}

do_eqp_test 5.2 {
  SELECT * FROM t2 ORDER BY x, y;
} {
  QUERY PLAN
  |--SCAN TABLE t2 USING INDEX t2i1
  `--USE TEMP B-TREE FOR RIGHT PART OF ORDER BY
}

do_eqp_test 5.3 {
  SELECT * FROM t2 WHERE x BETWEEN ? AND ? ORDER BY rowid;
} {
  QUERY PLAN
  |--SEARCH TABLE t2 USING INDEX t2i1 (x>? AND x<?)
  `--USE TEMP B-TREE FOR ORDER BY
}

# where7.test, where8.test:
#
do_execsql_test 6.1 {
  CREATE TABLE t3(a INTEGER PRIMARY KEY, b, c);
  CREATE INDEX t3i1 ON t3(b);
  CREATE INDEX t3i2 ON t3(c);
}

do_eqp_test 6.2 {
  SELECT a FROM t3 WHERE (b BETWEEN 2 AND 4) OR c=100 ORDER BY a
} {
  QUERY PLAN
  |--SEARCH TABLE t3 USING INDEX t3i1 (b>? AND b<?)
  |--SEARCH TABLE t3 USING INDEX t3i2 (c=?)
  `--USE TEMP B-TREE FOR ORDER BY
}

#-------------------------------------------------------------------------
#
reset_db
do_execsql_test 7.1 {
  CREATE TABLE t1(a INTEGER PRIMARY KEY,b,c,d,e,f,g);
................................................................................
}

do_eqp_test 7.2 {
  SELECT a FROM t1
     WHERE (b>=950 AND b<=1010) OR (b IS NULL AND c NOT NULL)
  ORDER BY a
} {
  QUERY PLAN
  |--SEARCH TABLE t1 USING INDEX t1b (b>? AND b<?)
  |--SEARCH TABLE t1 USING INDEX t1b (b=?)
  `--USE TEMP B-TREE FOR ORDER BY
}

do_eqp_test 7.3 {
  SELECT rowid FROM t1
  WHERE (+b IS NULL AND c NOT NULL AND d NOT NULL)
        OR (b NOT NULL AND c IS NULL AND d NOT NULL)
        OR (b NOT NULL AND c NOT NULL AND d IS NULL)

} {SCAN TABLE t1}


do_eqp_test 7.4 {
  SELECT rowid FROM t1 WHERE (+b IS NULL AND c NOT NULL) OR c IS NULL

} {SCAN TABLE t1}


#-------------------------------------------------------------------------
#
reset_db
do_execsql_test 8.1 {
  CREATE TABLE composer(
    cid INTEGER PRIMARY KEY,
................................................................................
do_eqp_test 8.2 {
  SELECT DISTINCT aname
    FROM album, composer, track
   WHERE cname LIKE '%bach%'
     AND unlikely(composer.cid=track.cid)
     AND unlikely(album.aid=track.aid);
} {
  QUERY PLAN
  |--SCAN TABLE track
  |--SEARCH TABLE album USING INTEGER PRIMARY KEY (rowid=?)
  |--SEARCH TABLE composer USING INTEGER PRIMARY KEY (rowid=?)
  `--USE TEMP B-TREE FOR DISTINCT
}

#-------------------------------------------------------------------------
#
do_execsql_test 9.1 {
  CREATE TABLE t1(
    a,b,c,d,e, f,g,h,i,j,
................................................................................
      execsql { INSERT INTO t6 VALUES($i%4, 'xyz', $i%8) }
    }
    execsql ANALYZE
  } {}

  do_eqp_test 10.3 {
    SELECT rowid FROM t6 WHERE a=0 AND c=0

  } {SEARCH TABLE t6 USING INDEX t6i2 (c=?)}


  do_eqp_test 10.4 {
    SELECT rowid FROM t6 WHERE a=0 AND b='xyz' AND c=0

  } {SEARCH TABLE t6 USING INDEX t6i2 (c=?)}


  do_eqp_test 10.5 {
    SELECT rowid FROM t6 WHERE likelihood(a=0, 0.1) AND c=0

  } {SEARCH TABLE t6 USING INDEX t6i1 (a=?)}


  do_eqp_test 10.6 {
    SELECT rowid FROM t6 WHERE likelihood(a=0, 0.1) AND b='xyz' AND c=0

  } {SEARCH TABLE t6 USING INDEX t6i1 (a=? AND b=?)}

}

finish_test

Changes to test/coveridxscan.test.

105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124

  CREATE TABLE t2(i INTEGER PRIMARY KEY, $cols);
  CREATE INDEX i2 ON t2($cols);
"

do_eqp_test 5.1.1 {
  SELECT * FROM t1 ORDER BY c1, c2;
} {
  0 0 0 {SCAN TABLE t1 USING COVERING INDEX i1}
}

do_eqp_test 5.1.2 {
  SELECT * FROM t2 ORDER BY c1, c2;
} {
  0 0 0 {SCAN TABLE t2 USING COVERING INDEX i2}
}



finish_test







<
|
<



<
|
<
<



105
106
107
108
109
110
111

112

113
114
115

116


117
118
119

  CREATE TABLE t2(i INTEGER PRIMARY KEY, $cols);
  CREATE INDEX i2 ON t2($cols);
"

do_eqp_test 5.1.1 {
  SELECT * FROM t1 ORDER BY c1, c2;

} {SCAN TABLE t1 USING COVERING INDEX i1}


do_eqp_test 5.1.2 {
  SELECT * FROM t2 ORDER BY c1, c2;

} {SCAN TABLE t2 USING COVERING INDEX i2}




finish_test

Changes to test/fts3join.test.

92
93
94
95
96
97
98


99
100
101
102
103
104

do_eqp_test 4.2 {
  SELECT * FROM t4 LEFT JOIN (
      SELECT docid, * FROM ft4 WHERE ft4 MATCH ?
  ) AS rr ON t4.rowid=rr.docid 
  WHERE t4.y = ?;
} {


  1 0 0 {SCAN TABLE ft4 VIRTUAL TABLE INDEX 3:} 
  0 0 0 {SCAN TABLE t4}
  0 1 1 {SEARCH SUBQUERY 1 AS rr USING AUTOMATIC COVERING INDEX (docid=?)}
}

finish_test







>
>
|
|
|



92
93
94
95
96
97
98
99
100
101
102
103
104
105
106

do_eqp_test 4.2 {
  SELECT * FROM t4 LEFT JOIN (
      SELECT docid, * FROM ft4 WHERE ft4 MATCH ?
  ) AS rr ON t4.rowid=rr.docid 
  WHERE t4.y = ?;
} {
  QUERY PLAN
  |--MATERIALIZE xxxxxx
  |  `--SCAN TABLE ft4 VIRTUAL TABLE INDEX 3:
  |--SCAN TABLE t4
  `--SEARCH SUBQUERY xxxxxx AS rr USING AUTOMATIC COVERING INDEX (docid=?)
}

finish_test

Changes to test/fts3query.test.

114
115
116
117
118
119
120

121
122
123
124
125
126

127
128
129
130
131
132

133
134
135
136
137
138

139
140
141
142
143
144
145
146
147
    CREATE VIRTUAL TABLE ft USING fts3(title);
    CREATE TABLE bt(title);
  }
} {}
do_eqp_test fts3query-4.2 {
  SELECT t1.number FROM t1, ft WHERE t1.number=ft.rowid ORDER BY t1.date
} {

  0 0 0 {SCAN TABLE t1 USING COVERING INDEX i1} 
  0 1 1 {SCAN TABLE ft VIRTUAL TABLE INDEX 1:}
}
do_eqp_test fts3query-4.3 {
  SELECT t1.number FROM ft, t1 WHERE t1.number=ft.rowid ORDER BY t1.date
} {

  0 0 1 {SCAN TABLE t1 USING COVERING INDEX i1} 
  0 1 0 {SCAN TABLE ft VIRTUAL TABLE INDEX 1:}
}
do_eqp_test fts3query-4.4 {
  SELECT t1.number FROM t1, bt WHERE t1.number=bt.rowid ORDER BY t1.date
} {

  0 0 0 {SCAN TABLE t1 USING COVERING INDEX i1} 
  0 1 1 {SEARCH TABLE bt USING INTEGER PRIMARY KEY (rowid=?)}
}
do_eqp_test fts3query-4.5 {
  SELECT t1.number FROM bt, t1 WHERE t1.number=bt.rowid ORDER BY t1.date
} {

  0 0 1 {SCAN TABLE t1 USING COVERING INDEX i1} 
  0 1 0 {SEARCH TABLE bt USING INTEGER PRIMARY KEY (rowid=?)}
}


# Test that calling matchinfo() with the wrong number of arguments, or with
# an invalid argument returns an error.
#
do_execsql_test 5.1 {







>
|
|




>
|
|




>
|
|




>
|
|







114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
    CREATE VIRTUAL TABLE ft USING fts3(title);
    CREATE TABLE bt(title);
  }
} {}
do_eqp_test fts3query-4.2 {
  SELECT t1.number FROM t1, ft WHERE t1.number=ft.rowid ORDER BY t1.date
} {
  QUERY PLAN
  |--SCAN TABLE t1 USING COVERING INDEX i1
  `--SCAN TABLE ft VIRTUAL TABLE INDEX 1:
}
do_eqp_test fts3query-4.3 {
  SELECT t1.number FROM ft, t1 WHERE t1.number=ft.rowid ORDER BY t1.date
} {
  QUERY PLAN
  |--SCAN TABLE t1 USING COVERING INDEX i1
  `--SCAN TABLE ft VIRTUAL TABLE INDEX 1:
}
do_eqp_test fts3query-4.4 {
  SELECT t1.number FROM t1, bt WHERE t1.number=bt.rowid ORDER BY t1.date
} {
  QUERY PLAN
  |--SCAN TABLE t1 USING COVERING INDEX i1
  `--SEARCH TABLE bt USING INTEGER PRIMARY KEY (rowid=?)
}
do_eqp_test fts3query-4.5 {
  SELECT t1.number FROM bt, t1 WHERE t1.number=bt.rowid ORDER BY t1.date
} {
  QUERY PLAN
  |--SCAN TABLE t1 USING COVERING INDEX i1
  `--SEARCH TABLE bt USING INTEGER PRIMARY KEY (rowid=?)
}


# Test that calling matchinfo() with the wrong number of arguments, or with
# an invalid argument returns an error.
#
do_execsql_test 5.1 {

Changes to test/index6.test.

314
315
316
317
318
319
320

321
322
323
324
325
326
327
328
329
  INSERT INTO t8b VALUES('value', 3);
  INSERT INTO t8b VALUES('dummy', 4);
} {}

do_eqp_test index6-8.1 {
  SELECT * FROM t8a LEFT JOIN t8b ON (x = 'value' AND y = a)
} {

  0 0 0 {SCAN TABLE t8a} 
  0 1 1 {SEARCH TABLE t8b USING INDEX i8c (y=?)}
}

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







>
|
|







314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
  INSERT INTO t8b VALUES('value', 3);
  INSERT INTO t8b VALUES('dummy', 4);
} {}

do_eqp_test index6-8.1 {
  SELECT * FROM t8a LEFT JOIN t8b ON (x = 'value' AND y = a)
} {
  QUERY PLAN
  |--SCAN TABLE t8a
  `--SEARCH TABLE t8b USING INDEX i8c (y=?)
}

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

Changes to test/index7.test.

317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
  INSERT INTO t4 VALUES('def', 'xyz');
  SELECT * FROM v4 WHERE d='xyz' AND c='def'
} {
  def xyz
}
do_eqp_test index7-6.4 {
  SELECT * FROM v4 WHERE d='xyz' AND c='def'
} {
  0 0 0 {SEARCH TABLE t4 USING INDEX i4 (c=?)}
}
do_catchsql_test index7-6.5 {
  CREATE INDEX t5a ON t5(a) WHERE a=#1;
} {1 {near "#1": syntax error}}


finish_test







<
|
|






317
318
319
320
321
322
323

324
325
326
327
328
329
330
331
  INSERT INTO t4 VALUES('def', 'xyz');
  SELECT * FROM v4 WHERE d='xyz' AND c='def'
} {
  def xyz
}
do_eqp_test index7-6.4 {
  SELECT * FROM v4 WHERE d='xyz' AND c='def'

} {SEARCH TABLE t4 USING INDEX i4 (c=?)}

do_catchsql_test index7-6.5 {
  CREATE INDEX t5a ON t5(a) WHERE a=#1;
} {1 {near "#1": syntax error}}


finish_test

Changes to test/indexedby.test.

36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51

52
53
54
55
56
57
58
59
60
...
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169

170
171
172
173
174
175

176
177
178
179
180
181
182
183
184
...
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
...
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
...
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
...
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
#
proc EQP {sql} {
  uplevel "execsql {EXPLAIN QUERY PLAN $sql}"
}

# These tests are to check that "EXPLAIN QUERY PLAN" is working as expected.
#
do_execsql_test indexedby-1.2 {
  EXPLAIN QUERY PLAN select * from t1 WHERE a = 10; 
} {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a=?)}}
do_execsql_test indexedby-1.3 {
  EXPLAIN QUERY PLAN select * from t1 ; 
} {0 0 0 {SCAN TABLE t1}}
do_execsql_test indexedby-1.4 {
  EXPLAIN QUERY PLAN select * from t1, t2 WHERE c = 10; 
} {

  0 0 1 {SEARCH TABLE t2 USING INDEX i3 (c=?)} 
  0 1 0 {SCAN TABLE t1}
}

# Parser tests. Test that an INDEXED BY or NOT INDEX clause can be 
# attached to a table in the FROM clause, but not to a sub-select or
# SQL view. Also test that specifying an index that does not exist or
# is attached to a different table is detected as an error.
#
................................................................................
#
# EVIDENCE-OF: R-37002-28871 The "NOT INDEXED" clause specifies that no
# index shall be used when accessing the preceding table, including
# implied indices create by UNIQUE and PRIMARY KEY constraints. However,
# the rowid can still be used to look up entries even when "NOT INDEXED"
# is specified.
#
do_execsql_test indexedby-3.1 {
  EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a = 'one' AND b = 'two'
} {/SEARCH TABLE t1 USING INDEX/}
do_execsql_test indexedby-3.1.1 {
  EXPLAIN QUERY PLAN SELECT * FROM t1 NOT INDEXED WHERE a = 'one' AND b = 'two'
} {0 0 0 {SCAN TABLE t1}}
do_execsql_test indexedby-3.1.2 {
  EXPLAIN QUERY PLAN SELECT * FROM t1 NOT INDEXED WHERE rowid=1
} {/SEARCH TABLE t1 USING INTEGER PRIMARY KEY .rowid=/}


do_execsql_test indexedby-3.2 {
  EXPLAIN QUERY PLAN 
  SELECT * FROM t1 INDEXED BY i1 WHERE a = 'one' AND b = 'two'
} {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a=?)}}
do_execsql_test indexedby-3.3 {
  EXPLAIN QUERY PLAN 
  SELECT * FROM t1 INDEXED BY i2 WHERE a = 'one' AND b = 'two'
} {0 0 0 {SEARCH TABLE t1 USING INDEX i2 (b=?)}}
do_test indexedby-3.4 {
  catchsql { SELECT * FROM t1 INDEXED BY i2 WHERE a = 'one' }
} {1 {no query solution}}
do_test indexedby-3.5 {
  catchsql { SELECT * FROM t1 INDEXED BY i2 ORDER BY a }
} {1 {no query solution}}
do_test indexedby-3.6 {
  catchsql { SELECT * FROM t1 INDEXED BY i1 WHERE a = 'one' }
} {0 {}}
do_test indexedby-3.7 {
  catchsql { SELECT * FROM t1 INDEXED BY i1 ORDER BY a }
} {0 {}}

do_execsql_test indexedby-3.8 {
  EXPLAIN QUERY PLAN 
  SELECT * FROM t3 INDEXED BY sqlite_autoindex_t3_1 ORDER BY e 
} {0 0 0 {SCAN TABLE t3 USING INDEX sqlite_autoindex_t3_1}}
do_execsql_test indexedby-3.9 {
  EXPLAIN QUERY PLAN 
  SELECT * FROM t3 INDEXED BY sqlite_autoindex_t3_1 WHERE e = 10 
} {0 0 0 {SEARCH TABLE t3 USING INDEX sqlite_autoindex_t3_1 (e=?)}}
do_test indexedby-3.10 {
  catchsql { SELECT * FROM t3 INDEXED BY sqlite_autoindex_t3_1 WHERE f = 10 }
} {1 {no query solution}}
do_test indexedby-3.11 {
  catchsql { SELECT * FROM t3 INDEXED BY sqlite_autoindex_t3_2 WHERE f = 10 }
} {1 {no such index: sqlite_autoindex_t3_2}}

# Tests for multiple table cases.
#
do_execsql_test indexedby-4.1 {
  EXPLAIN QUERY PLAN SELECT * FROM t1, t2 WHERE a = c 
} {

  0 0 0 {SCAN TABLE t1} 
  0 1 1 {SEARCH TABLE t2 USING INDEX i3 (c=?)}
}
do_execsql_test indexedby-4.2 {
  EXPLAIN QUERY PLAN SELECT * FROM t1 INDEXED BY i1, t2 WHERE a = c 
} {

  0 0 1 {SCAN TABLE t2} 
  0 1 0 {SEARCH TABLE t1 USING INDEX i1 (a=?)}
}
do_test indexedby-4.3 {
  catchsql {
    SELECT * FROM t1 INDEXED BY i1, t2 INDEXED BY i3 WHERE a=c
  }
} {1 {no query solution}}
do_test indexedby-4.4 {
................................................................................
# Test embedding an INDEXED BY in a CREATE VIEW statement. This block
# also tests that nothing bad happens if an index refered to by
# a CREATE VIEW statement is dropped and recreated.
#
do_execsql_test indexedby-5.1 {
  CREATE VIEW v2 AS SELECT * FROM t1 INDEXED BY i1 WHERE a > 5;
  EXPLAIN QUERY PLAN SELECT * FROM v2 
} {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a>?)}}
do_execsql_test indexedby-5.2 {
  EXPLAIN QUERY PLAN SELECT * FROM v2 WHERE b = 10 
} {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a>?)}}
do_test indexedby-5.3 {
  execsql { DROP INDEX i1 }
  catchsql { SELECT * FROM v2 }
} {1 {no such index: i1}}
do_test indexedby-5.4 {
  # Recreate index i1 in such a way as it cannot be used by the view query.
  execsql { CREATE INDEX i1 ON t1(b) }
................................................................................
  # be used by the query.
  execsql { DROP INDEX i1 ; CREATE INDEX i1 ON t1(a) }
  catchsql { SELECT * FROM v2 }
} {0 {}}

# Test that "NOT INDEXED" may use the rowid index, but not others.
# 
do_execsql_test indexedby-6.1 {
  EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE b = 10 ORDER BY rowid 
} {0 0 0 {SEARCH TABLE t1 USING INDEX i2 (b=?)}}
do_execsql_test indexedby-6.2 {
  EXPLAIN QUERY PLAN SELECT * FROM t1 NOT INDEXED WHERE b = 10 ORDER BY rowid 
} {0 0 0 {SCAN TABLE t1}}

# EVIDENCE-OF: R-40297-14464 The INDEXED BY phrase forces the SQLite
# query planner to use a particular named index on a DELETE, SELECT, or
# UPDATE statement.
#
# Test that "INDEXED BY" can be used in a DELETE statement.
# 
do_execsql_test indexedby-7.1 {
  EXPLAIN QUERY PLAN DELETE FROM t1 WHERE a = 5 
} {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a=?)}}
do_execsql_test indexedby-7.2 {
  EXPLAIN QUERY PLAN DELETE FROM t1 NOT INDEXED WHERE a = 5 
} {0 0 0 {SCAN TABLE t1}}
do_execsql_test indexedby-7.3 {
  EXPLAIN QUERY PLAN DELETE FROM t1 INDEXED BY i1 WHERE a = 5 
} {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a=?)}}
do_execsql_test indexedby-7.4 {
  EXPLAIN QUERY PLAN DELETE FROM t1 INDEXED BY i1 WHERE a = 5 AND b = 10
} {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a=?)}}
do_execsql_test indexedby-7.5 {
  EXPLAIN QUERY PLAN DELETE FROM t1 INDEXED BY i2 WHERE a = 5 AND b = 10
} {0 0 0 {SEARCH TABLE t1 USING INDEX i2 (b=?)}}
do_test indexedby-7.6 {
  catchsql { DELETE FROM t1 INDEXED BY i2 WHERE a = 5}
} {1 {no query solution}}

# Test that "INDEXED BY" can be used in an UPDATE statement.
# 
do_execsql_test indexedby-8.1 {
  EXPLAIN QUERY PLAN UPDATE t1 SET rowid=rowid+1 WHERE a = 5 
} {0 0 0 {SEARCH TABLE t1 USING COVERING INDEX i1 (a=?)}}
do_execsql_test indexedby-8.2 {
  EXPLAIN QUERY PLAN UPDATE t1 NOT INDEXED SET rowid=rowid+1 WHERE a = 5 
} {0 0 0 {SCAN TABLE t1}}
do_execsql_test indexedby-8.3 {
  EXPLAIN QUERY PLAN UPDATE t1 INDEXED BY i1 SET rowid=rowid+1 WHERE a = 5 
} {0 0 0 {SEARCH TABLE t1 USING COVERING INDEX i1 (a=?)}}
do_execsql_test indexedby-8.4 {
  EXPLAIN QUERY PLAN 
  UPDATE t1 INDEXED BY i1 SET rowid=rowid+1 WHERE a = 5 AND b = 10
} {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a=?)}}
do_execsql_test indexedby-8.5 {
  EXPLAIN QUERY PLAN 
  UPDATE t1 INDEXED BY i2 SET rowid=rowid+1 WHERE a = 5 AND b = 10
} {0 0 0 {SEARCH TABLE t1 USING INDEX i2 (b=?)}}
do_test indexedby-8.6 {
  catchsql { UPDATE t1 INDEXED BY i2 SET rowid=rowid+1 WHERE a = 5}
} {1 {no query solution}}

# Test that bug #3560 is fixed.
#
do_test indexedby-9.1 {
................................................................................
  SELECT a,b,rowid FROM x1 INDEXED BY x1i WHERE a=1 AND b=1 AND rowid='3';
} {1 1 3}
do_execsql_test 11.4 {
  SELECT a,b,rowid FROM x1 INDEXED BY x1i WHERE a=1 AND b=1 AND rowid='3.0';
} {1 1 3}
do_eqp_test 11.5 {
  SELECT a,b,rowid FROM x1 INDEXED BY x1i WHERE a=1 AND b=1 AND rowid='3.0';
} {0 0 0 {SEARCH TABLE x1 USING COVERING INDEX x1i (a=? AND b=? AND rowid=?)}}

do_execsql_test 11.6 {
  CREATE TABLE x2(c INTEGER PRIMARY KEY, a, b TEXT);
  CREATE INDEX x2i ON x2(a, b);
  INSERT INTO x2 VALUES(1, 1, 1);
  INSERT INTO x2 VALUES(2, 1, 1);
  INSERT INTO x2 VALUES(3, 1, 1);
................................................................................
  SELECT a,b,c FROM x2 INDEXED BY x2i WHERE a=1 AND b=1 AND c='3';
} {1 1 3}
do_execsql_test 11.9 {
  SELECT a,b,c FROM x2 INDEXED BY x2i WHERE a=1 AND b=1 AND c='3.0';
} {1 1 3}
do_eqp_test 11.10 {
  SELECT a,b,c FROM x2 INDEXED BY x2i WHERE a=1 AND b=1 AND c='3.0';
} {0 0 0 {SEARCH TABLE x2 USING COVERING INDEX x2i (a=? AND b=? AND rowid=?)}}

#-------------------------------------------------------------------------
# Check INDEXED BY works (throws an exception) with partial indexes that 
# cannot be used.
do_execsql_test 12.1 {
  CREATE TABLE o1(x INTEGER PRIMARY KEY, y, z);
  CREATE INDEX p1 ON o1(z);







|
|
|
|
|
|
|
|

>
|
|







 







|
|

|
|
|
|
|



|
<

|
|
<

|













|
<

|
|
<

|









|
|

>
|
|

|
|

>
|
|







 







|


|







 







|
|
|
|
|
|







|
|
|
|
|
|
|
|
|
|
|
|
|
|
|






|
|
|
|
|
|
|
|
|
|
<

|
|
<

|







 







|







 







|







36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
...
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130

131
132
133

134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149

150
151
152

153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
...
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
...
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261

262
263
264

265
266
267
268
269
270
271
272
273
...
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
...
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
#
proc EQP {sql} {
  uplevel "execsql {EXPLAIN QUERY PLAN $sql}"
}

# These tests are to check that "EXPLAIN QUERY PLAN" is working as expected.
#
do_eqp_test indexedby-1.2 {
  select * from t1 WHERE a = 10; 
} {SEARCH TABLE t1 USING INDEX i1 (a=?)}
do_eqp_test indexedby-1.3 {
  select * from t1 ; 
} {SCAN TABLE t1}
do_eqp_test indexedby-1.4 {
  select * from t1, t2 WHERE c = 10; 
} {
  QUERY PLAN
  |--SEARCH TABLE t2 USING INDEX i3 (c=?)
  `--SCAN TABLE t1
}

# Parser tests. Test that an INDEXED BY or NOT INDEX clause can be 
# attached to a table in the FROM clause, but not to a sub-select or
# SQL view. Also test that specifying an index that does not exist or
# is attached to a different table is detected as an error.
#
................................................................................
#
# EVIDENCE-OF: R-37002-28871 The "NOT INDEXED" clause specifies that no
# index shall be used when accessing the preceding table, including
# implied indices create by UNIQUE and PRIMARY KEY constraints. However,
# the rowid can still be used to look up entries even when "NOT INDEXED"
# is specified.
#
do_eqp_test indexedby-3.1 {
  SELECT * FROM t1 WHERE a = 'one' AND b = 'two'
} {/SEARCH TABLE t1 USING INDEX/}
do_eqp_test indexedby-3.1.1 {
  SELECT * FROM t1 NOT INDEXED WHERE a = 'one' AND b = 'two'
} {SCAN TABLE t1}
do_eqp_test indexedby-3.1.2 {
  SELECT * FROM t1 NOT INDEXED WHERE rowid=1
} {/SEARCH TABLE t1 USING INTEGER PRIMARY KEY .rowid=/}


do_eqp_test indexedby-3.2 {

  SELECT * FROM t1 INDEXED BY i1 WHERE a = 'one' AND b = 'two'
} {SEARCH TABLE t1 USING INDEX i1 (a=?)}
do_eqp_test indexedby-3.3 {

  SELECT * FROM t1 INDEXED BY i2 WHERE a = 'one' AND b = 'two'
} {SEARCH TABLE t1 USING INDEX i2 (b=?)}
do_test indexedby-3.4 {
  catchsql { SELECT * FROM t1 INDEXED BY i2 WHERE a = 'one' }
} {1 {no query solution}}
do_test indexedby-3.5 {
  catchsql { SELECT * FROM t1 INDEXED BY i2 ORDER BY a }
} {1 {no query solution}}
do_test indexedby-3.6 {
  catchsql { SELECT * FROM t1 INDEXED BY i1 WHERE a = 'one' }
} {0 {}}
do_test indexedby-3.7 {
  catchsql { SELECT * FROM t1 INDEXED BY i1 ORDER BY a }
} {0 {}}

do_eqp_test indexedby-3.8 {

  SELECT * FROM t3 INDEXED BY sqlite_autoindex_t3_1 ORDER BY e 
} {SCAN TABLE t3 USING INDEX sqlite_autoindex_t3_1}
do_eqp_test indexedby-3.9 {

  SELECT * FROM t3 INDEXED BY sqlite_autoindex_t3_1 WHERE e = 10 
} {SEARCH TABLE t3 USING INDEX sqlite_autoindex_t3_1 (e=?)}
do_test indexedby-3.10 {
  catchsql { SELECT * FROM t3 INDEXED BY sqlite_autoindex_t3_1 WHERE f = 10 }
} {1 {no query solution}}
do_test indexedby-3.11 {
  catchsql { SELECT * FROM t3 INDEXED BY sqlite_autoindex_t3_2 WHERE f = 10 }
} {1 {no such index: sqlite_autoindex_t3_2}}

# Tests for multiple table cases.
#
do_eqp_test indexedby-4.1 {
  SELECT * FROM t1, t2 WHERE a = c 
} {
  QUERY PLAN
  |--SCAN TABLE t1
  `--SEARCH TABLE t2 USING INDEX i3 (c=?)
}
do_eqp_test indexedby-4.2 {
  SELECT * FROM t1 INDEXED BY i1, t2 WHERE a = c 
} {
  QUERY PLAN
  |--SCAN TABLE t2
  `--SEARCH TABLE t1 USING INDEX i1 (a=?)
}
do_test indexedby-4.3 {
  catchsql {
    SELECT * FROM t1 INDEXED BY i1, t2 INDEXED BY i3 WHERE a=c
  }
} {1 {no query solution}}
do_test indexedby-4.4 {
................................................................................
# Test embedding an INDEXED BY in a CREATE VIEW statement. This block
# also tests that nothing bad happens if an index refered to by
# a CREATE VIEW statement is dropped and recreated.
#
do_execsql_test indexedby-5.1 {
  CREATE VIEW v2 AS SELECT * FROM t1 INDEXED BY i1 WHERE a > 5;
  EXPLAIN QUERY PLAN SELECT * FROM v2 
} {/*SEARCH TABLE t1 USING INDEX i1 (a>?)*/}
do_execsql_test indexedby-5.2 {
  EXPLAIN QUERY PLAN SELECT * FROM v2 WHERE b = 10 
} {/*SEARCH TABLE t1 USING INDEX i1 (a>?)*/}
do_test indexedby-5.3 {
  execsql { DROP INDEX i1 }
  catchsql { SELECT * FROM v2 }
} {1 {no such index: i1}}
do_test indexedby-5.4 {
  # Recreate index i1 in such a way as it cannot be used by the view query.
  execsql { CREATE INDEX i1 ON t1(b) }
................................................................................
  # be used by the query.
  execsql { DROP INDEX i1 ; CREATE INDEX i1 ON t1(a) }
  catchsql { SELECT * FROM v2 }
} {0 {}}

# Test that "NOT INDEXED" may use the rowid index, but not others.
# 
do_eqp_test indexedby-6.1 {
  SELECT * FROM t1 WHERE b = 10 ORDER BY rowid 
} {SEARCH TABLE t1 USING INDEX i2 (b=?)}
do_eqp_test indexedby-6.2 {
  SELECT * FROM t1 NOT INDEXED WHERE b = 10 ORDER BY rowid 
} {SCAN TABLE t1}

# EVIDENCE-OF: R-40297-14464 The INDEXED BY phrase forces the SQLite
# query planner to use a particular named index on a DELETE, SELECT, or
# UPDATE statement.
#
# Test that "INDEXED BY" can be used in a DELETE statement.
# 
do_eqp_test indexedby-7.1 {
  DELETE FROM t1 WHERE a = 5 
} {SEARCH TABLE t1 USING INDEX i1 (a=?)}
do_eqp_test indexedby-7.2 {
  DELETE FROM t1 NOT INDEXED WHERE a = 5 
} {SCAN TABLE t1}
do_eqp_test indexedby-7.3 {
  DELETE FROM t1 INDEXED BY i1 WHERE a = 5 
} {SEARCH TABLE t1 USING INDEX i1 (a=?)}
do_eqp_test indexedby-7.4 {
  DELETE FROM t1 INDEXED BY i1 WHERE a = 5 AND b = 10
} {SEARCH TABLE t1 USING INDEX i1 (a=?)}
do_eqp_test indexedby-7.5 {
  DELETE FROM t1 INDEXED BY i2 WHERE a = 5 AND b = 10
} {SEARCH TABLE t1 USING INDEX i2 (b=?)}
do_test indexedby-7.6 {
  catchsql { DELETE FROM t1 INDEXED BY i2 WHERE a = 5}
} {1 {no query solution}}

# Test that "INDEXED BY" can be used in an UPDATE statement.
# 
do_eqp_test indexedby-8.1 {
  UPDATE t1 SET rowid=rowid+1 WHERE a = 5 
} {SEARCH TABLE t1 USING COVERING INDEX i1 (a=?)}
do_eqp_test indexedby-8.2 {
  UPDATE t1 NOT INDEXED SET rowid=rowid+1 WHERE a = 5 
} {SCAN TABLE t1}
do_eqp_test indexedby-8.3 {
  UPDATE t1 INDEXED BY i1 SET rowid=rowid+1 WHERE a = 5 
} {SEARCH TABLE t1 USING COVERING INDEX i1 (a=?)}
do_eqp_test indexedby-8.4 {

  UPDATE t1 INDEXED BY i1 SET rowid=rowid+1 WHERE a = 5 AND b = 10
} {SEARCH TABLE t1 USING INDEX i1 (a=?)}
do_eqp_test indexedby-8.5 {

  UPDATE t1 INDEXED BY i2 SET rowid=rowid+1 WHERE a = 5 AND b = 10
} {SEARCH TABLE t1 USING INDEX i2 (b=?)}
do_test indexedby-8.6 {
  catchsql { UPDATE t1 INDEXED BY i2 SET rowid=rowid+1 WHERE a = 5}
} {1 {no query solution}}

# Test that bug #3560 is fixed.
#
do_test indexedby-9.1 {
................................................................................
  SELECT a,b,rowid FROM x1 INDEXED BY x1i WHERE a=1 AND b=1 AND rowid='3';
} {1 1 3}
do_execsql_test 11.4 {
  SELECT a,b,rowid FROM x1 INDEXED BY x1i WHERE a=1 AND b=1 AND rowid='3.0';
} {1 1 3}
do_eqp_test 11.5 {
  SELECT a,b,rowid FROM x1 INDEXED BY x1i WHERE a=1 AND b=1 AND rowid='3.0';
} {SEARCH TABLE x1 USING COVERING INDEX x1i (a=? AND b=? AND rowid=?)}

do_execsql_test 11.6 {
  CREATE TABLE x2(c INTEGER PRIMARY KEY, a, b TEXT);
  CREATE INDEX x2i ON x2(a, b);
  INSERT INTO x2 VALUES(1, 1, 1);
  INSERT INTO x2 VALUES(2, 1, 1);
  INSERT INTO x2 VALUES(3, 1, 1);
................................................................................
  SELECT a,b,c FROM x2 INDEXED BY x2i WHERE a=1 AND b=1 AND c='3';
} {1 1 3}
do_execsql_test 11.9 {
  SELECT a,b,c FROM x2 INDEXED BY x2i WHERE a=1 AND b=1 AND c='3.0';
} {1 1 3}
do_eqp_test 11.10 {
  SELECT a,b,c FROM x2 INDEXED BY x2i WHERE a=1 AND b=1 AND c='3.0';
} {SEARCH TABLE x2 USING COVERING INDEX x2i (a=? AND b=? AND rowid=?)}

#-------------------------------------------------------------------------
# Check INDEXED BY works (throws an exception) with partial indexes that 
# cannot be used.
do_execsql_test 12.1 {
  CREATE TABLE o1(x INTEGER PRIMARY KEY, y, z);
  CREATE INDEX p1 ON o1(z);

Changes to test/indexexpr2.test.

87
88
89
90
91
92
93
94

95
96
97
98
99
100
101
102
103
104
105
106
107
108

109
110
111
112
113
114
115
116
117
118

ifcapable json1 {
  do_eqp_test 3.3.1 {
    SELECT json_extract(x, '$.b') FROM t2 
    WHERE json_extract(x, '$.b') IS NOT NULL AND json_extract(x, '$.a') IS NULL 
    GROUP BY json_extract(x, '$.b') COLLATE nocase
    ORDER BY json_extract(x, '$.b') COLLATE nocase;
  } {

    0 0 0 {SCAN TABLE t2} 
    0 0 0 {USE TEMP B-TREE FOR GROUP BY}
  }
  
  do_execsql_test 3.3.2 {
    CREATE INDEX i3 ON t3(json_extract(x, '$.a'), json_extract(x, '$.b'));
  } {}
  
  do_eqp_test 3.3.3 {
    SELECT json_extract(x, '$.b') FROM t3 
    WHERE json_extract(x, '$.b') IS NOT NULL AND json_extract(x, '$.a') IS NULL 
    GROUP BY json_extract(x, '$.b') COLLATE nocase
    ORDER BY json_extract(x, '$.b') COLLATE nocase;
  } {

    0 0 0 {SEARCH TABLE t3 USING INDEX i3 (<expr>=?)} 
    0 0 0 {USE TEMP B-TREE FOR GROUP BY}
  }
}

do_execsql_test 3.4.0 {
  CREATE TABLE t4(a, b);
  INSERT INTO t4 VALUES('.ABC', 1);
  INSERT INTO t4 VALUES('.abc', 2);
  INSERT INTO t4 VALUES('.ABC', 3);







|
>
|
|
|










|
>
|
|
|







87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120

ifcapable json1 {
  do_eqp_test 3.3.1 {
    SELECT json_extract(x, '$.b') FROM t2 
    WHERE json_extract(x, '$.b') IS NOT NULL AND json_extract(x, '$.a') IS NULL 
    GROUP BY json_extract(x, '$.b') COLLATE nocase
    ORDER BY json_extract(x, '$.b') COLLATE nocase;
  } [string map {"\n  " \n} {
    QUERY PLAN
    |--SCAN TABLE t2
    `--USE TEMP B-TREE FOR GROUP BY
  }]
  
  do_execsql_test 3.3.2 {
    CREATE INDEX i3 ON t3(json_extract(x, '$.a'), json_extract(x, '$.b'));
  } {}
  
  do_eqp_test 3.3.3 {
    SELECT json_extract(x, '$.b') FROM t3 
    WHERE json_extract(x, '$.b') IS NOT NULL AND json_extract(x, '$.a') IS NULL 
    GROUP BY json_extract(x, '$.b') COLLATE nocase
    ORDER BY json_extract(x, '$.b') COLLATE nocase;
  } [string map {"\n  " \n} {
    QUERY PLAN
    |--SEARCH TABLE t3 USING INDEX i3 (<expr>=?)
    `--USE TEMP B-TREE FOR GROUP BY
  }]
}

do_execsql_test 3.4.0 {
  CREATE TABLE t4(a, b);
  INSERT INTO t4 VALUES('.ABC', 1);
  INSERT INTO t4 VALUES('.abc', 2);
  INSERT INTO t4 VALUES('.ABC', 3);

Changes to test/join2.test.

108
109
110
111
112
113
114

115
116
117
118
119
120
121

122
123
124
125
126
127
128
129
130
...
154
155
156
157
158
159
160

161
162
163
164
165
166
167

168
169
170
171
172
173
174
175
176
...
199
200
201
202
203
204
205

206
207
208
209
210
211
212

213
214
215
216
217
218
219
220
221
...
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
  CREATE TABLE t3_1(k3 PRIMARY KEY, v3) WITHOUT ROWID;
  CREATE TABLE t3_2(v3, k3 PRIMARY KEY) WITHOUT ROWID;
}

do_eqp_test 3.1 {
  SELECT v2 FROM t1 LEFT JOIN t2 USING (k2) LEFT JOIN t3_1 USING (k3);
} {

  0 0 0 {SCAN TABLE t1} 
  0 1 1 {SEARCH TABLE t2 USING INTEGER PRIMARY KEY (rowid=?)}
}

do_eqp_test 3.2 {
  SELECT v2 FROM t1 LEFT JOIN t2 USING (k2) LEFT JOIN t3_2 USING (k3);
} {

  0 0 0 {SCAN TABLE t1} 
  0 1 1 {SEARCH TABLE t2 USING INTEGER PRIMARY KEY (rowid=?)}
}

#-------------------------------------------------------------------------
# Test that tables other than the rightmost can be omitted from a
# LEFT JOIN query.
#
do_execsql_test 4.0 {
................................................................................
do_execsql_test 4.1.4 {
  SELECT v1, v3 FROM c1 LEFT JOIN c2 LEFT JOIN c3 ON (c3.k=v1+1);
} {2 v3 2 v3 1112 {} 1112 {}}

do_eqp_test 4.1.5 {
  SELECT v1, v3 FROM c1 LEFT JOIN c2 ON (c2.k=v1) LEFT JOIN c3 ON (c3.k=v2);
} {

  0 0 0 {SCAN TABLE c1} 
  0 1 1 {SEARCH TABLE c2 USING INTEGER PRIMARY KEY (rowid=?)}
  0 2 2 {SEARCH TABLE c3 USING INTEGER PRIMARY KEY (rowid=?)}
}
do_eqp_test 4.1.6 {
  SELECT v1, v3 FROM c1 LEFT JOIN c2 ON (c2.k=v1) LEFT JOIN c3 ON (c3.k=v1+1);
} {

  0 0 0 {SCAN TABLE c1} 
  0 1 2 {SEARCH TABLE c3 USING INTEGER PRIMARY KEY (rowid=?)}
}

do_execsql_test 4.2.0 {
  DROP TABLE c1;
  DROP TABLE c2;
  DROP TABLE c3;
  CREATE TABLE c1(k UNIQUE, v1);
................................................................................
do_execsql_test 4.2.4 {
  SELECT v1, v3 FROM c1 LEFT JOIN c2 LEFT JOIN c3 ON (c3.k=v1+1);
} {2 v3 2 v3 1112 {} 1112 {}}

do_eqp_test 4.2.5 {
  SELECT v1, v3 FROM c1 LEFT JOIN c2 ON (c2.k=v1) LEFT JOIN c3 ON (c3.k=v2);
} {

  0 0 0 {SCAN TABLE c1} 
  0 1 1 {SEARCH TABLE c2 USING INDEX sqlite_autoindex_c2_1 (k=?)}
  0 2 2 {SEARCH TABLE c3 USING INDEX sqlite_autoindex_c3_1 (k=?)}
}
do_eqp_test 4.2.6 {
  SELECT v1, v3 FROM c1 LEFT JOIN c2 ON (c2.k=v1) LEFT JOIN c3 ON (c3.k=v1+1);
} {

  0 0 0 {SCAN TABLE c1} 
  0 1 2 {SEARCH TABLE c3 USING INDEX sqlite_autoindex_c3_1 (k=?)}
}

# 2017-11-23 (Thanksgiving day)
# OSSFuzz found an assertion fault in the new LEFT JOIN eliminator code.
#
do_execsql_test 4.3.0 {
  DROP TABLE IF EXISTS t1;
................................................................................
  CREATE TABLE s1 (a INTEGER PRIMARY KEY);
  CREATE TABLE s2 (a INTEGER PRIMARY KEY);
  CREATE TABLE s3 (a INTEGER);
  CREATE UNIQUE INDEX ndx on s3(a);
}
do_eqp_test 5.1 {
  SELECT s1.a FROM s1 left join s2 using (a);
} {
  0 0 0 {SCAN TABLE s1}
}
do_eqp_test 5.2 {
  SELECT s1.a FROM s1 left join s3 using (a);
} {
  0 0 0 {SCAN TABLE s1}
}

do_execsql_test 6.0 {
  CREATE TABLE u1(a INTEGER PRIMARY KEY, b, c);
  CREATE TABLE u2(a INTEGER PRIMARY KEY, b, c);
  CREATE INDEX u1ab ON u1(b, c);
}
do_eqp_test 6.1 {
  SELECT u2.* FROM u2 LEFT JOIN u1 ON( u1.a=u2.a AND u1.b=u2.b AND u1.c=u2.c );
} {
  0 0 0 {SCAN TABLE u2}
}

db close
sqlite3 db :memory:
do_execsql_test 7.0 {
  CREATE TABLE t1(a,b);  INSERT INTO t1 VALUES(1,2),(3,4),(5,6);
  CREATE TABLE t2(c,d);  INSERT INTO t2 VALUES(2,4),(3,6);
  CREATE TABLE t3(x);    INSERT INTO t3 VALUES(9);







>
|
|





>
|
|







 







>
|
|
|




>
|
|







 







>
|
|
|




>
|
|







 







<
|
|


<
|
<








<
|
<







108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
...
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
...
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
...
247
248
249
250
251
252
253

254
255
256
257

258

259
260
261
262
263
264
265
266

267

268
269
270
271
272
273
274
  CREATE TABLE t3_1(k3 PRIMARY KEY, v3) WITHOUT ROWID;
  CREATE TABLE t3_2(v3, k3 PRIMARY KEY) WITHOUT ROWID;
}

do_eqp_test 3.1 {
  SELECT v2 FROM t1 LEFT JOIN t2 USING (k2) LEFT JOIN t3_1 USING (k3);
} {
  QUERY PLAN
  |--SCAN TABLE t1
  `--SEARCH TABLE t2 USING INTEGER PRIMARY KEY (rowid=?)
}

do_eqp_test 3.2 {
  SELECT v2 FROM t1 LEFT JOIN t2 USING (k2) LEFT JOIN t3_2 USING (k3);
} {
  QUERY PLAN
  |--SCAN TABLE t1
  `--SEARCH TABLE t2 USING INTEGER PRIMARY KEY (rowid=?)
}

#-------------------------------------------------------------------------
# Test that tables other than the rightmost can be omitted from a
# LEFT JOIN query.
#
do_execsql_test 4.0 {
................................................................................
do_execsql_test 4.1.4 {
  SELECT v1, v3 FROM c1 LEFT JOIN c2 LEFT JOIN c3 ON (c3.k=v1+1);
} {2 v3 2 v3 1112 {} 1112 {}}

do_eqp_test 4.1.5 {
  SELECT v1, v3 FROM c1 LEFT JOIN c2 ON (c2.k=v1) LEFT JOIN c3 ON (c3.k=v2);
} {
  QUERY PLAN
  |--SCAN TABLE c1
  |--SEARCH TABLE c2 USING INTEGER PRIMARY KEY (rowid=?)
  `--SEARCH TABLE c3 USING INTEGER PRIMARY KEY (rowid=?)
}
do_eqp_test 4.1.6 {
  SELECT v1, v3 FROM c1 LEFT JOIN c2 ON (c2.k=v1) LEFT JOIN c3 ON (c3.k=v1+1);
} {
  QUERY PLAN
  |--SCAN TABLE c1
  `--SEARCH TABLE c3 USING INTEGER PRIMARY KEY (rowid=?)
}

do_execsql_test 4.2.0 {
  DROP TABLE c1;
  DROP TABLE c2;
  DROP TABLE c3;
  CREATE TABLE c1(k UNIQUE, v1);
................................................................................
do_execsql_test 4.2.4 {
  SELECT v1, v3 FROM c1 LEFT JOIN c2 LEFT JOIN c3 ON (c3.k=v1+1);
} {2 v3 2 v3 1112 {} 1112 {}}

do_eqp_test 4.2.5 {
  SELECT v1, v3 FROM c1 LEFT JOIN c2 ON (c2.k=v1) LEFT JOIN c3 ON (c3.k=v2);
} {
  QUERY PLAN
  |--SCAN TABLE c1
  |--SEARCH TABLE c2 USING INDEX sqlite_autoindex_c2_1 (k=?)
  `--SEARCH TABLE c3 USING INDEX sqlite_autoindex_c3_1 (k=?)
}
do_eqp_test 4.2.6 {
  SELECT v1, v3 FROM c1 LEFT JOIN c2 ON (c2.k=v1) LEFT JOIN c3 ON (c3.k=v1+1);
} {
  QUERY PLAN
  |--SCAN TABLE c1
  `--SEARCH TABLE c3 USING INDEX sqlite_autoindex_c3_1 (k=?)
}

# 2017-11-23 (Thanksgiving day)
# OSSFuzz found an assertion fault in the new LEFT JOIN eliminator code.
#
do_execsql_test 4.3.0 {
  DROP TABLE IF EXISTS t1;
................................................................................
  CREATE TABLE s1 (a INTEGER PRIMARY KEY);
  CREATE TABLE s2 (a INTEGER PRIMARY KEY);
  CREATE TABLE s3 (a INTEGER);
  CREATE UNIQUE INDEX ndx on s3(a);
}
do_eqp_test 5.1 {
  SELECT s1.a FROM s1 left join s2 using (a);

} {SCAN TABLE s1}

do_eqp_test 5.2 {
  SELECT s1.a FROM s1 left join s3 using (a);

} {SCAN TABLE s1}


do_execsql_test 6.0 {
  CREATE TABLE u1(a INTEGER PRIMARY KEY, b, c);
  CREATE TABLE u2(a INTEGER PRIMARY KEY, b, c);
  CREATE INDEX u1ab ON u1(b, c);
}
do_eqp_test 6.1 {
  SELECT u2.* FROM u2 LEFT JOIN u1 ON( u1.a=u2.a AND u1.b=u2.b AND u1.c=u2.c );

} {SCAN TABLE u2}


db close
sqlite3 db :memory:
do_execsql_test 7.0 {
  CREATE TABLE t1(a,b);  INSERT INTO t1 VALUES(1,2),(3,4),(5,6);
  CREATE TABLE t2(c,d);  INSERT INTO t2 VALUES(2,4),(3,6);
  CREATE TABLE t3(x);    INSERT INTO t3 VALUES(9);

Changes to test/join5.test.

260
261
262
263
264
265
266

267
268
269
270
271
272
273
274
275
276
...
281
282
283
284
285
286
287

288
289
290
291
292
293
}

do_eqp_test 7.2 {
  SELECT * FROM t1 LEFT JOIN t2 ON (
    t2.x = t1.x AND (t2.y=? OR (t2.y=? AND t2.z IS NOT NULL))
  );
} {

  0 0 0 {SCAN TABLE t1} 
  0 1 1 {SEARCH TABLE t2 USING INDEX t2xy (x=? AND y=?)} 
  0 1 1 {SEARCH TABLE t2 USING INDEX t2xy (x=? AND y=?)}
}

do_execsql_test 7.3 {
  CREATE TABLE t3(x);

  CREATE TABLE t4(x, y, z);
  CREATE INDEX t4xy ON t4(x, y);
................................................................................

  ANALYZE;
}

do_eqp_test 7.4 {
  SELECT * FROM t3 LEFT JOIN t4 ON (t4.x = t3.x) WHERE (t4.y = ? OR t4.z = ?);
} {

  0 0 0 {SCAN TABLE t3} 
  0 1 1 {SEARCH TABLE t4 USING INDEX t4xz (x=?)}
} 

finish_test








>
|
|
|







 







>
|
|



<
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
...
282
283
284
285
286
287
288
289
290
291
292
293
294

}

do_eqp_test 7.2 {
  SELECT * FROM t1 LEFT JOIN t2 ON (
    t2.x = t1.x AND (t2.y=? OR (t2.y=? AND t2.z IS NOT NULL))
  );
} {
  QUERY PLAN
  |--SCAN TABLE t1
  |--SEARCH TABLE t2 USING INDEX t2xy (x=? AND y=?)
  `--SEARCH TABLE t2 USING INDEX t2xy (x=? AND y=?)
}

do_execsql_test 7.3 {
  CREATE TABLE t3(x);

  CREATE TABLE t4(x, y, z);
  CREATE INDEX t4xy ON t4(x, y);
................................................................................

  ANALYZE;
}

do_eqp_test 7.4 {
  SELECT * FROM t3 LEFT JOIN t4 ON (t4.x = t3.x) WHERE (t4.y = ? OR t4.z = ?);
} {
  QUERY PLAN
  |--SCAN TABLE t3
  `--SEARCH TABLE t4 USING INDEX t4xz (x=?)
} 

finish_test

Changes to test/mallocK.test.

117
118
119
120
121
122
123
124

125
126
127
128
129
130
131
132
133
134

  SELECT 'x' > '.';
} {1}

ifcapable stat4 {
  do_eqp_test 6.1 {
    SELECT DISTINCT c FROM t3 WHERE b BETWEEN '.xx..' AND '.xxxx';
  } {

    0 0 0 {SEARCH TABLE t3 USING INDEX i3 (ANY(a) AND b>? AND b<?)} 
    0 0 0 {USE TEMP B-TREE FOR DISTINCT}
  }
}

do_faultsim_test 6 -faults oom* -body {
  db cache flush
  db eval { SELECT DISTINCT c FROM t3 WHERE b BETWEEN '.xx..' AND '.xxxx' }
} -test {
  faultsim_test_result {0 {12 13 14 15}} 







|
>
|
|
|







117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135

  SELECT 'x' > '.';
} {1}

ifcapable stat4 {
  do_eqp_test 6.1 {
    SELECT DISTINCT c FROM t3 WHERE b BETWEEN '.xx..' AND '.xxxx';
  } [string map {"\n  " \n} {
    QUERY PLAN
    |--SEARCH TABLE t3 USING INDEX i3 (ANY(a) AND b>? AND b<?)
    `--USE TEMP B-TREE FOR DISTINCT
  }]
}

do_faultsim_test 6 -faults oom* -body {
  db cache flush
  db eval { SELECT DISTINCT c FROM t3 WHERE b BETWEEN '.xx..' AND '.xxxx' }
} -test {
  faultsim_test_result {0 {12 13 14 15}} 

Changes to test/orderby1.test.

508
509
510
511
512
513
514

515
516
517
518
519
520
521
522
523
  CREATE TABLE t1(a, b);
  CREATE INDEX i1 ON t1(a);
}

do_eqp_test 8.1 {
  SELECT * FROM t1 ORDER BY a, b;
} {

  0 0 0 {SCAN TABLE t1 USING INDEX i1} 
  0 0 0 {USE TEMP B-TREE FOR RIGHT PART OF ORDER BY}
}

do_execsql_test 8.2 {
  WITH cnt(i) AS (
    SELECT 1 UNION ALL SELECT i+1 FROM cnt WHERE i<10000
  )
  INSERT INTO t1 SELECT i%2, randomblob(500) FROM cnt;







>
|
|







508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
  CREATE TABLE t1(a, b);
  CREATE INDEX i1 ON t1(a);
}

do_eqp_test 8.1 {
  SELECT * FROM t1 ORDER BY a, b;
} {
  QUERY PLAN
  |--SCAN TABLE t1 USING INDEX i1
  `--USE TEMP B-TREE FOR RIGHT PART OF ORDER BY
}

do_execsql_test 8.2 {
  WITH cnt(i) AS (
    SELECT 1 UNION ALL SELECT i+1 FROM cnt WHERE i<10000
  )
  INSERT INTO t1 SELECT i%2, randomblob(500) FROM cnt;

Changes to test/rollback2.test.

97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
...
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
}

#--------------------------------------------------------------------
# Try with some index scans
#
do_eqp_test 3.1 {
  SELECT i FROM t1 WHERE (i%2)==0 ORDER BY h DESC;
} {0 0 0 {SCAN TABLE t1 USING INDEX i1}}
do_rollback_test 3.2 -setup {
  BEGIN;
    DELETE FROM t1 WHERE (i%2)==1;
} -select {
  SELECT i FROM t1 WHERE (i%2)==0 ORDER BY h DESC;
} -result {
  40 38 36 34 32 30 28 26 24 22 20 18 16 14 12 10  8  6  4  2
................................................................................
# Now with some index scans that feature overflow keys.
#
set leader [string repeat "abcdefghij" 70]
do_execsql_test 4.1 { UPDATE t1 SET h = $leader || h; }

do_eqp_test 4.2 {
  SELECT i FROM t1 WHERE (i%2)==0 ORDER BY h ASC;
} {0 0 0 {SCAN TABLE t1 USING INDEX i1}}
do_rollback_test 4.3 -setup {
  BEGIN;
    DELETE FROM t1 WHERE (i%2)==1;
} -select {
  SELECT i FROM t1 WHERE (i%2)==0 ORDER BY h ASC;
} -result {
  2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32 34 36 38 40







|







 







|







97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
...
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
}

#--------------------------------------------------------------------
# Try with some index scans
#
do_eqp_test 3.1 {
  SELECT i FROM t1 WHERE (i%2)==0 ORDER BY h DESC;
} {SCAN TABLE t1 USING INDEX i1}
do_rollback_test 3.2 -setup {
  BEGIN;
    DELETE FROM t1 WHERE (i%2)==1;
} -select {
  SELECT i FROM t1 WHERE (i%2)==0 ORDER BY h DESC;
} -result {
  40 38 36 34 32 30 28 26 24 22 20 18 16 14 12 10  8  6  4  2
................................................................................
# Now with some index scans that feature overflow keys.
#
set leader [string repeat "abcdefghij" 70]
do_execsql_test 4.1 { UPDATE t1 SET h = $leader || h; }

do_eqp_test 4.2 {
  SELECT i FROM t1 WHERE (i%2)==0 ORDER BY h ASC;
} {SCAN TABLE t1 USING INDEX i1}
do_rollback_test 4.3 -setup {
  BEGIN;
    DELETE FROM t1 WHERE (i%2)==1;
} -select {
  SELECT i FROM t1 WHERE (i%2)==0 ORDER BY h ASC;
} -result {
  2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32 34 36 38 40

Changes to test/rowvalue.test.

171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
  INSERT INTO xy VALUES(3, 3, 3);
  INSERT INTO xy VALUES(4, 4, 4);
}


foreach {tn sql res eqp} {
  1 "SELECT * FROM xy WHERE (i, j) IS (2, 2)" {2 2 2} 
    "0 0 0 {SEARCH TABLE xy USING INTEGER PRIMARY KEY (rowid=?)}"

  2 "SELECT * FROM xy WHERE (k, j) < (2, 3)" {1 1 1 2 2 2}
    "0 0 0 {SCAN TABLE xy}"

  3 "SELECT * FROM xy WHERE (i, j) < (2, 3)" {1 1 1 2 2 2}
    "0 0 0 {SEARCH TABLE xy USING INTEGER PRIMARY KEY (rowid<?)}"

  4 "SELECT * FROM xy WHERE (i, j) > (2, 1)" {2 2 2 3 3 3 4 4 4}
    "0 0 0 {SEARCH TABLE xy USING INTEGER PRIMARY KEY (rowid>?)}"

  5 "SELECT * FROM xy WHERE (i, j) > ('2', 1)" {2 2 2 3 3 3 4 4 4}
    "0 0 0 {SEARCH TABLE xy USING INTEGER PRIMARY KEY (rowid>?)}"

} {
  do_eqp_test 7.$tn.1 $sql $eqp
  do_execsql_test 7.$tn.2 $sql $res
}

do_execsql_test 8.0 {







|


|


|


|


|







171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
  INSERT INTO xy VALUES(3, 3, 3);
  INSERT INTO xy VALUES(4, 4, 4);
}


foreach {tn sql res eqp} {
  1 "SELECT * FROM xy WHERE (i, j) IS (2, 2)" {2 2 2} 
    "SEARCH TABLE xy USING INTEGER PRIMARY KEY (rowid=?)"

  2 "SELECT * FROM xy WHERE (k, j) < (2, 3)" {1 1 1 2 2 2}
    "SCAN TABLE xy"

  3 "SELECT * FROM xy WHERE (i, j) < (2, 3)" {1 1 1 2 2 2}
    "SEARCH TABLE xy USING INTEGER PRIMARY KEY (rowid<?)"

  4 "SELECT * FROM xy WHERE (i, j) > (2, 1)" {2 2 2 3 3 3 4 4 4}
    "SEARCH TABLE xy USING INTEGER PRIMARY KEY (rowid>?)"

  5 "SELECT * FROM xy WHERE (i, j) > ('2', 1)" {2 2 2 3 3 3 4 4 4}
    "SEARCH TABLE xy USING INTEGER PRIMARY KEY (rowid>?)"

} {
  do_eqp_test 7.$tn.1 $sql $eqp
  do_execsql_test 7.$tn.2 $sql $res
}

do_execsql_test 8.0 {

Changes to test/rowvalue4.test.

180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
...
230
231
232
233
234
235
236

237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
    INSERT INTO c1(c, d) SELECT a, b FROM c1;

    CREATE INDEX c1ab ON c1(a, b);
    CREATE INDEX c1cd ON c1(c, d);
    ANALYZE;
  }

  do_eqp_test 3.1.1 { SELECT * FROM c1 WHERE a=1 AND c=2 } {
    0 0 0 {SEARCH TABLE c1 USING INDEX c1cd (c=?)}
  }
  do_eqp_test 3.1.2 { SELECT * FROM c1 WHERE a=1 AND b>'d' AND c=2 } {
    0 0 0 {SEARCH TABLE c1 USING INDEX c1cd (c=?)}
  }
  do_eqp_test 3.1.3 { SELECT * FROM c1 WHERE a=1 AND b>'l' AND c=2 } {
    0 0 0 {SEARCH TABLE c1 USING INDEX c1ab (a=? AND b>?)}
  }

  do_eqp_test 3.2.1 { SELECT * FROM c1 WHERE a=1 AND c>1 } {
    0 0 0 {SEARCH TABLE c1 USING INDEX c1cd (c>?)}
  }
  do_eqp_test 3.2.2 { SELECT * FROM c1 WHERE a=1 AND c>0 } {
    0 0 0 {SEARCH TABLE c1 USING INDEX c1ab (a=?)}
  }
  do_eqp_test 3.2.3 { SELECT * FROM c1 WHERE a=1 AND c>=1 } {
    0 0 0 {SEARCH TABLE c1 USING INDEX c1ab (a=?)}
  }
  do_eqp_test 3.2.4 { SELECT * FROM c1 WHERE a=1 AND (c, d)>(1, 'c') } {
    0 0 0 {SEARCH TABLE c1 USING INDEX c1ab (a=?)}
  }
  do_eqp_test 3.2.5 { SELECT * FROM c1 WHERE a=1 AND (c, d)>(1, 'o') } {
    0 0 0 {SEARCH TABLE c1 USING INDEX c1cd ((c,d)>(?,?))}
  }
  do_eqp_test 3.2.6 { SELECT * FROM c1 WHERE a=1 AND (c, +b)>(1, 'c') } {
    0 0 0 {SEARCH TABLE c1 USING INDEX c1ab (a=?)}
  }
}

#------------------------------------------------------------------------

do_execsql_test 5.0 {
  CREATE TABLE d1(x, y);
  CREATE TABLE d2(a, b, c);
................................................................................
}

do_eqp_test 5.1 {
  SELECT * FROM d2 WHERE 
    (a, b) IN (SELECT x, y FROM d1) AND
    (c) IN (SELECT y FROM d1)
} {

  0 0 0 {SEARCH TABLE d2 USING INDEX d2ab (a=? AND b=?)}
  0 0 0 {EXECUTE LIST SUBQUERY 1} 
  1 0 0 {SCAN TABLE d1}
  0 0 0 {EXECUTE LIST SUBQUERY 2} 
  2 0 0 {SCAN TABLE d1}
}

do_execsql_test 6.0 {
  CREATE TABLE e1(a, b, c, d, e);
  CREATE INDEX e1ab ON e1(a, b);
  CREATE INDEX e1cde ON e1(c, d, e);
}

do_eqp_test 6.1 {
  SELECT * FROM e1 WHERE (a, b) > (?, ?)
} {
  0 0 0 {SEARCH TABLE e1 USING INDEX e1ab ((a,b)>(?,?))}
}
do_eqp_test 6.2 {
  SELECT * FROM e1 WHERE (a, b) < (?, ?)
} {
  0 0 0 {SEARCH TABLE e1 USING INDEX e1ab ((a,b)<(?,?))}
}
do_eqp_test 6.3 {
  SELECT * FROM e1 WHERE c = ? AND (d, e) > (?, ?)
} {
  0 0 0 {SEARCH TABLE e1 USING INDEX e1cde (c=? AND (d,e)>(?,?))}
}
do_eqp_test 6.4 {
  SELECT * FROM e1 WHERE c = ? AND (d, e) < (?, ?)
} {
  0 0 0 {SEARCH TABLE e1 USING INDEX e1cde (c=? AND (d,e)<(?,?))}
}

do_eqp_test 6.5 {
  SELECT * FROM e1 WHERE (d, e) BETWEEN (?, ?) AND (?, ?) AND c = ?
} {
  0 0 0 
  {SEARCH TABLE e1 USING INDEX e1cde (c=? AND (d,e)>(?,?) AND (d,e)<(?,?))}
}

#-------------------------------------------------------------------------

do_execsql_test 7.1 {
  CREATE TABLE f1(a, b, c);
  CREATE INDEX f1ab ON f1(a, b);
}







|
|
|
|
|
|
|
|
|
<
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|







 







>
|
|
|
|
|










<
|
|


<
|
|


<
|
|


<
|
<



<
<
|
<







180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195

196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
...
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251

252
253
254
255

256
257
258
259

260
261
262
263

264

265
266
267


268

269
270
271
272
273
274
275
    INSERT INTO c1(c, d) SELECT a, b FROM c1;

    CREATE INDEX c1ab ON c1(a, b);
    CREATE INDEX c1cd ON c1(c, d);
    ANALYZE;
  }

  do_eqp_test 3.1.1 { SELECT * FROM c1 WHERE a=1 AND c=2 } \
     {SEARCH TABLE c1 USING INDEX c1cd (c=?)}

  do_eqp_test 3.1.2 { SELECT * FROM c1 WHERE a=1 AND b>'d' AND c=2 } \
     {SEARCH TABLE c1 USING INDEX c1cd (c=?)}

  do_eqp_test 3.1.3 { SELECT * FROM c1 WHERE a=1 AND b>'l' AND c=2 } \
     {SEARCH TABLE c1 USING INDEX c1ab (a=? AND b>?)}


  do_eqp_test 3.2.1 { SELECT * FROM c1 WHERE a=1 AND c>1 } \
     {SEARCH TABLE c1 USING INDEX c1cd (c>?)}

  do_eqp_test 3.2.2 { SELECT * FROM c1 WHERE a=1 AND c>0 } \
     {SEARCH TABLE c1 USING INDEX c1ab (a=?)}

  do_eqp_test 3.2.3 { SELECT * FROM c1 WHERE a=1 AND c>=1 } \
     {SEARCH TABLE c1 USING INDEX c1ab (a=?)}

  do_eqp_test 3.2.4 { SELECT * FROM c1 WHERE a=1 AND (c, d)>(1, 'c') } \
     {SEARCH TABLE c1 USING INDEX c1ab (a=?)}

  do_eqp_test 3.2.5 { SELECT * FROM c1 WHERE a=1 AND (c, d)>(1, 'o') } \
     {SEARCH TABLE c1 USING INDEX c1cd ((c,d)>(?,?))}

  do_eqp_test 3.2.6 { SELECT * FROM c1 WHERE a=1 AND (c, +b)>(1, 'c') } \
     {SEARCH TABLE c1 USING INDEX c1ab (a=?)}

}

#------------------------------------------------------------------------

do_execsql_test 5.0 {
  CREATE TABLE d1(x, y);
  CREATE TABLE d2(a, b, c);
................................................................................
}

do_eqp_test 5.1 {
  SELECT * FROM d2 WHERE 
    (a, b) IN (SELECT x, y FROM d1) AND
    (c) IN (SELECT y FROM d1)
} {
  QUERY PLAN
  |--SEARCH TABLE d2 USING INDEX d2ab (a=? AND b=?)
  |--LIST SUBQUERY
  |  `--SCAN TABLE d1
  `--LIST SUBQUERY
     `--SCAN TABLE d1
}

do_execsql_test 6.0 {
  CREATE TABLE e1(a, b, c, d, e);
  CREATE INDEX e1ab ON e1(a, b);
  CREATE INDEX e1cde ON e1(c, d, e);
}

do_eqp_test 6.1 {
  SELECT * FROM e1 WHERE (a, b) > (?, ?)

} {SEARCH TABLE e1 USING INDEX e1ab ((a,b)>(?,?))}

do_eqp_test 6.2 {
  SELECT * FROM e1 WHERE (a, b) < (?, ?)

} {SEARCH TABLE e1 USING INDEX e1ab ((a,b)<(?,?))}

do_eqp_test 6.3 {
  SELECT * FROM e1 WHERE c = ? AND (d, e) > (?, ?)

} {SEARCH TABLE e1 USING INDEX e1cde (c=? AND (d,e)>(?,?))}

do_eqp_test 6.4 {
  SELECT * FROM e1 WHERE c = ? AND (d, e) < (?, ?)

} {SEARCH TABLE e1 USING INDEX e1cde (c=? AND (d,e)<(?,?))}


do_eqp_test 6.5 {
  SELECT * FROM e1 WHERE (d, e) BETWEEN (?, ?) AND (?, ?) AND c = ?


} {SEARCH TABLE e1 USING INDEX e1cde (c=? AND (d,e)>(?,?) AND (d,e)<(?,?))}


#-------------------------------------------------------------------------

do_execsql_test 7.1 {
  CREATE TABLE f1(a, b, c);
  CREATE INDEX f1ab ON f1(a, b);
}

Changes to test/scanstatus.test.

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
350
351
...
352
353
354
355
356
357
358

359
360
361
362
363
364
365
366
367
do_scanstatus_test 5.2.2 { 
  nLoop 1 nVisit 2 nEst 2.0 zName sqlite_autoindex_t1_1
  zExplain {SEARCH TABLE t1 USING COVERING INDEX sqlite_autoindex_t1_1 (a=?)}
}

do_eqp_test 5.3.1 {
  SELECT count(*) FROM t2 WHERE y = 'j';
} {0 0 0 {SEARCH TABLE t2 USING COVERING INDEX t2xy (ANY(x) AND y=?)}}
do_execsql_test 5.3.2 {
  SELECT count(*) FROM t2 WHERE y = 'j';
} {19}
do_scanstatus_test 5.3.3 { 
  nLoop 1 nVisit 19 nEst 56.0 zName t2xy zExplain
  {SEARCH TABLE t2 USING COVERING INDEX t2xy (ANY(x) AND y=?)}
}

do_eqp_test 5.4.1 {
  SELECT count(*) FROM t1, t2 WHERE y = c;
} {

  0 0 0 {SCAN TABLE t1 USING COVERING INDEX t1bc}
  0 1 1 {SEARCH TABLE t2 USING COVERING INDEX t2xy (ANY(x) AND y=?)}
}
do_execsql_test 5.4.2 {
  SELECT count(*) FROM t1, t2 WHERE y = c;
} {200}
do_scanstatus_test 5.4.3 { 
  nLoop 1 nVisit 10 nEst 10.0 zName t1bc 
  zExplain {SCAN TABLE t1 USING COVERING INDEX t1bc}
................................................................................
  nLoop 10 nVisit 200 nEst 56.0 zName t2xy 
  zExplain {SEARCH TABLE t2 USING COVERING INDEX t2xy (ANY(x) AND y=?)}
}

do_eqp_test 5.5.1 {
  SELECT count(*) FROM t1, t3 WHERE y = c;
} {

  0 0 1 {SCAN TABLE t3} 
  0 1 0 {SEARCH TABLE t1 USING AUTOMATIC COVERING INDEX (c=?)}
}
do_execsql_test 5.5.2 {
  SELECT count(*) FROM t1, t3 WHERE y = c;
} {200}
do_scanstatus_test 5.5.3 { 
  nLoop 1 nVisit 501 nEst 480.0 zName t3 zExplain {SCAN TABLE t3}
  nLoop 501 nVisit 200 nEst 20.0 zName auto-index zExplain







|











>
|
|







 







>
|
|







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
350
351
352
...
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
do_scanstatus_test 5.2.2 { 
  nLoop 1 nVisit 2 nEst 2.0 zName sqlite_autoindex_t1_1
  zExplain {SEARCH TABLE t1 USING COVERING INDEX sqlite_autoindex_t1_1 (a=?)}
}

do_eqp_test 5.3.1 {
  SELECT count(*) FROM t2 WHERE y = 'j';
} {SEARCH TABLE t2 USING COVERING INDEX t2xy (ANY(x) AND y=?)}
do_execsql_test 5.3.2 {
  SELECT count(*) FROM t2 WHERE y = 'j';
} {19}
do_scanstatus_test 5.3.3 { 
  nLoop 1 nVisit 19 nEst 56.0 zName t2xy zExplain
  {SEARCH TABLE t2 USING COVERING INDEX t2xy (ANY(x) AND y=?)}
}

do_eqp_test 5.4.1 {
  SELECT count(*) FROM t1, t2 WHERE y = c;
} {
  QUERY PLAN
  |--SCAN TABLE t1 USING COVERING INDEX t1bc
  `--SEARCH TABLE t2 USING COVERING INDEX t2xy (ANY(x) AND y=?)
}
do_execsql_test 5.4.2 {
  SELECT count(*) FROM t1, t2 WHERE y = c;
} {200}
do_scanstatus_test 5.4.3 { 
  nLoop 1 nVisit 10 nEst 10.0 zName t1bc 
  zExplain {SCAN TABLE t1 USING COVERING INDEX t1bc}
................................................................................
  nLoop 10 nVisit 200 nEst 56.0 zName t2xy 
  zExplain {SEARCH TABLE t2 USING COVERING INDEX t2xy (ANY(x) AND y=?)}
}

do_eqp_test 5.5.1 {
  SELECT count(*) FROM t1, t3 WHERE y = c;
} {
  QUERY PLAN
  |--SCAN TABLE t3
  `--SEARCH TABLE t1 USING AUTOMATIC COVERING INDEX (c=?)
}
do_execsql_test 5.5.2 {
  SELECT count(*) FROM t1, t3 WHERE y = c;
} {200}
do_scanstatus_test 5.5.3 { 
  nLoop 1 nVisit 501 nEst 480.0 zName t3 zExplain {SCAN TABLE t3}
  nLoop 501 nVisit 200 nEst 20.0 zName auto-index zExplain

Changes to test/selectA.test.

1332
1333
1334
1335
1336
1337
1338



1339
1340

1341
1342
1343
1344
1345
1346
1347
1348
1349
1350

do_eqp_test 4.1.2 {
  SELECT c, d FROM t5 
  UNION ALL
  SELECT a, b FROM t4 WHERE f()==f()
  ORDER BY 1,2
} {



  1 0 0 {SCAN TABLE t5 USING INDEX i2} 
  1 0 0 {USE TEMP B-TREE FOR RIGHT PART OF ORDER BY}

  2 0 0 {SCAN TABLE t4 USING INDEX i1} 
  2 0 0 {USE TEMP B-TREE FOR RIGHT PART OF ORDER BY}
  0 0 0 {COMPOUND SUBQUERIES 1 AND 2 (UNION ALL)}
}

do_execsql_test 4.1.3 {
  SELECT c, d FROM t5 
  UNION ALL
  SELECT a, b FROM t4 WHERE f()==f()
  ORDER BY 1,2







>
>
>
|
|
>
|
|
<







1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346

1347
1348
1349
1350
1351
1352
1353

do_eqp_test 4.1.2 {
  SELECT c, d FROM t5 
  UNION ALL
  SELECT a, b FROM t4 WHERE f()==f()
  ORDER BY 1,2
} {
  QUERY PLAN
  `--MERGE (UNION ALL)
     |--LEFT
     |  |--SCAN TABLE t5 USING INDEX i2
     |  `--USE TEMP B-TREE FOR RIGHT PART OF ORDER BY
     `--RIGHT
        |--SCAN TABLE t4 USING INDEX i1
        `--USE TEMP B-TREE FOR RIGHT PART OF ORDER BY

}

do_execsql_test 4.1.3 {
  SELECT c, d FROM t5 
  UNION ALL
  SELECT a, b FROM t4 WHERE f()==f()
  ORDER BY 1,2

Changes to test/skipscan2.test.

195
196
197
198
199
200
201
202
203
204
205
  for {set i 0} {$i < 1000} {incr i} {
    execsql { INSERT INTO t3 VALUES($i%2, $i, 'xyz') }
  }
  execsql { ANALYZE }
} {}
do_eqp_test skipscan2-3.3eqp {
  SELECT * FROM t3 WHERE b=42;
} {0 0 0 {SEARCH TABLE t3 USING PRIMARY KEY (ANY(a) AND b=?)}}


finish_test







|



195
196
197
198
199
200
201
202
203
204
205
  for {set i 0} {$i < 1000} {incr i} {
    execsql { INSERT INTO t3 VALUES($i%2, $i, 'xyz') }
  }
  execsql { ANALYZE }
} {}
do_eqp_test skipscan2-3.3eqp {
  SELECT * FROM t3 WHERE b=42;
} {SEARCH TABLE t3 USING PRIMARY KEY (ANY(a) AND b=?)}


finish_test

Changes to test/skipscan6.test.

175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
  t3 t3_ba   {100 20 1 1}
}

# Use index "t3_a", as (a=?) is expected to match only a single row.
#
do_eqp_test 3.1 {
  SELECT * FROM t3 WHERE a = ? AND c = ?
} {
  0 0 0 {SEARCH TABLE t3 USING INDEX t3_a (a=?)}
}

# The same query on table t2. This should use index "t2_a", for the
# same reason. At one point though, it was mistakenly using a skip-scan.
#
do_eqp_test 3.2 {
  SELECT * FROM t2 WHERE a = ? AND c = ?
} {
  0 0 0 {SEARCH TABLE t2 USING INDEX t2_a (a=?)}
}

finish_test




finish_test







<
|
<






<
|
|
<

<
<
<
<
<
175
176
177
178
179
180
181

182

183
184
185
186
187
188

189
190

191





  t3 t3_ba   {100 20 1 1}
}

# Use index "t3_a", as (a=?) is expected to match only a single row.
#
do_eqp_test 3.1 {
  SELECT * FROM t3 WHERE a = ? AND c = ?

} {SEARCH TABLE t3 USING INDEX t3_a (a=?)}


# The same query on table t2. This should use index "t2_a", for the
# same reason. At one point though, it was mistakenly using a skip-scan.
#
do_eqp_test 3.2 {
  SELECT * FROM t2 WHERE a = ? AND c = ?

} {SEARCH TABLE t2 USING INDEX t2_a (a=?)}


finish_test





Changes to test/tkt-385a5b56b9.test.

30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53

do_execsql_test 2.0 {
  CREATE TABLE t2(x, y NOT NULL);
  CREATE UNIQUE INDEX t2x ON t2(x);
  CREATE UNIQUE INDEX t2y ON t2(y);
}

do_eqp_test 2.1 { SELECT DISTINCT x FROM t2 } {
  0 0 0 {SCAN TABLE t2 USING COVERING INDEX t2x}
}

do_eqp_test 2.2 { SELECT DISTINCT y FROM t2 } {
  0 0 0 {SCAN TABLE t2 USING COVERING INDEX t2y}
}

do_eqp_test 2.3 { SELECT DISTINCT x, y FROM t2 WHERE y=10 } {
  0 0 0 {SEARCH TABLE t2 USING INDEX t2y (y=?)}
}

do_eqp_test 2.4 { SELECT DISTINCT x, y FROM t2 WHERE x=10 } {
  0 0 0 {SEARCH TABLE t2 USING INDEX t2x (x=?)}
}

finish_test







|
|
|
<
|
|
|
<
|
|
|
<
|
|
|


30
31
32
33
34
35
36
37
38
39

40
41
42

43
44
45

46
47
48
49
50

do_execsql_test 2.0 {
  CREATE TABLE t2(x, y NOT NULL);
  CREATE UNIQUE INDEX t2x ON t2(x);
  CREATE UNIQUE INDEX t2y ON t2(y);
}

do_eqp_test 2.1 { SELECT DISTINCT x FROM t2 } \
  {SCAN TABLE t2 USING COVERING INDEX t2x}


do_eqp_test 2.2 { SELECT DISTINCT y FROM t2 } \
  {SCAN TABLE t2 USING COVERING INDEX t2y}


do_eqp_test 2.3 { SELECT DISTINCT x, y FROM t2 WHERE y=10 } \
  {SEARCH TABLE t2 USING INDEX t2y (y=?)}


do_eqp_test 2.4 { SELECT DISTINCT x, y FROM t2 WHERE x=10 } \
  {SEARCH TABLE t2 USING INDEX t2x (x=?)}


finish_test

Changes to test/tkt-b75a9ca6b0.test.

28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
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
  INSERT INTO t1 VALUES (3, 1);
}

do_execsql_test 1.1 {
  CREATE INDEX i1 ON t1(x, y);
} 

set idxscan {0 0 0 {SCAN TABLE t1 USING COVERING INDEX i1}}
set tblscan {0 0 0 {SCAN TABLE t1}}
set grpsort {0 0 0 {USE TEMP B-TREE FOR GROUP BY}}
set sort    {0 0 0 {USE TEMP B-TREE FOR ORDER BY}}

foreach {tn q res eqp} [subst -nocommands {
  1 "SELECT * FROM t1 GROUP BY x, y ORDER BY x,y"
  {1 3  2 2  3 1} {$idxscan}

  2 "SELECT * FROM t1 GROUP BY x, y ORDER BY x"
  {1 3  2 2  3 1} {$idxscan $sort}

  3 "SELECT * FROM t1 GROUP BY y, x ORDER BY y, x"
  {3 1  2 2  1 3} {$idxscan $sort}
  
  4 "SELECT * FROM t1 GROUP BY x ORDER BY x"
  {1 3  2 2  3 1} {$idxscan}

  5 "SELECT * FROM t1 GROUP BY y ORDER BY y"
  {3 1  2 2  1 3} {$tblscan $grpsort}

  6 "SELECT * FROM t1 GROUP BY y ORDER BY x"
  {1 3  2 2  3 1} {$tblscan $grpsort $sort}

  7 "SELECT * FROM t1 GROUP BY x, y ORDER BY x, y DESC"
  {1 3  2 2  3 1} {$idxscan $sort}

  8 "SELECT * FROM t1 GROUP BY x, y ORDER BY x DESC, y DESC"
  {3 1  2 2  1 3} {$idxscan $sort}

  9 "SELECT * FROM t1 GROUP BY x, y ORDER BY x ASC, y ASC"
  {1 3  2 2  3 1} {$idxscan}

  10 "SELECT * FROM t1 GROUP BY x, y ORDER BY x COLLATE nocase, y"
  {1 3  2 2  3 1} {$idxscan $sort}

}] {
  do_execsql_test 1.$tn.1 $q $res
  do_eqp_test     1.$tn.2 $q $eqp
}


finish_test







|
|
|
|






|


|





|


|


|


|





|








28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
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
  INSERT INTO t1 VALUES (3, 1);
}

do_execsql_test 1.1 {
  CREATE INDEX i1 ON t1(x, y);
} 

set idxscan {SCAN TABLE t1 USING COVERING INDEX i1}
set tblscan {SCAN TABLE t1}
set grpsort {USE TEMP B-TREE FOR GROUP BY}
set sort    {USE TEMP B-TREE FOR ORDER BY}

foreach {tn q res eqp} [subst -nocommands {
  1 "SELECT * FROM t1 GROUP BY x, y ORDER BY x,y"
  {1 3  2 2  3 1} {$idxscan}

  2 "SELECT * FROM t1 GROUP BY x, y ORDER BY x"
  {1 3  2 2  3 1} {$idxscan*$sort}

  3 "SELECT * FROM t1 GROUP BY y, x ORDER BY y, x"
  {3 1  2 2  1 3} {$idxscan*$sort}
  
  4 "SELECT * FROM t1 GROUP BY x ORDER BY x"
  {1 3  2 2  3 1} {$idxscan}

  5 "SELECT * FROM t1 GROUP BY y ORDER BY y"
  {3 1  2 2  1 3} {$tblscan*$grpsort}

  6 "SELECT * FROM t1 GROUP BY y ORDER BY x"
  {1 3  2 2  3 1} {$tblscan*$grpsort*$sort}

  7 "SELECT * FROM t1 GROUP BY x, y ORDER BY x, y DESC"
  {1 3  2 2  3 1} {$idxscan*$sort}

  8 "SELECT * FROM t1 GROUP BY x, y ORDER BY x DESC, y DESC"
  {3 1  2 2  1 3} {$idxscan*$sort}

  9 "SELECT * FROM t1 GROUP BY x, y ORDER BY x ASC, y ASC"
  {1 3  2 2  3 1} {$idxscan}

  10 "SELECT * FROM t1 GROUP BY x, y ORDER BY x COLLATE nocase, y"
  {1 3  2 2  3 1} {$idxscan*$sort}

}] {
  do_execsql_test 1.$tn.1 $q $res
  do_eqp_test     1.$tn.2 $q $eqp
}


finish_test

Changes to test/tpch01.test.

161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
...
183
184
185
186
187
188
189


190





191

192
                               and p_type = 'LARGE PLATED STEEL'
               ) as all_nations
       group by
               o_year
       order by
               o_year;}]
  set ::eqpres
} {/0 0 0 {SEARCH TABLE part USING INDEX bootleg_pti .P_TYPE=..} 0 1 2 {SEARCH TABLE lineitem USING INDEX lpki2 .L_PARTKEY=..}.*/}
do_test tpch01-1.1b {
  set ::eqpres
} {/.* customer .* nation AS n1 .*/}
do_test tpch01-1.1c {
  set ::eqpres
} {/.* supplier .* nation AS n2 .*/}

................................................................................
    c_custkey = o_custkey    and l_orderkey = o_orderkey
    and o_orderdate >=  '1994-08-01'    and o_orderdate < date('1994-08-01', '+3 month')
    and l_returnflag = 'R'    and c_nationkey = n_nationkey
group by
    c_custkey,    c_name,    c_acctbal,    c_phone,    n_name, c_address,    c_comment
order by
    revenue desc;


} {0 0 1 {SEARCH TABLE orders USING INDEX odi (O_ORDERDATE>? AND O_ORDERDATE<?)} 0 1 0 {SEARCH TABLE customer USING INDEX cpki (C_CUSTKEY=?)} 0 2 3 {SEARCH TABLE nation USING INDEX npki (N_NATIONKEY=?)} 0 3 2 {SEARCH TABLE lineitem USING INDEX lpki (L_ORDERKEY=?)} 0 0 0 {USE TEMP B-TREE FOR GROUP BY} 0 0 0 {USE TEMP B-TREE FOR ORDER BY}}







finish_test







|







 







>
>
|
>
>
>
>
>
|
>

161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
...
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
                               and p_type = 'LARGE PLATED STEEL'
               ) as all_nations
       group by
               o_year
       order by
               o_year;}]
  set ::eqpres
} {/*SEARCH TABLE part USING INDEX bootleg_pti *SEARCH TABLE lineitem USING INDEX lpki2*/}
do_test tpch01-1.1b {
  set ::eqpres
} {/.* customer .* nation AS n1 .*/}
do_test tpch01-1.1c {
  set ::eqpres
} {/.* supplier .* nation AS n2 .*/}

................................................................................
    c_custkey = o_custkey    and l_orderkey = o_orderkey
    and o_orderdate >=  '1994-08-01'    and o_orderdate < date('1994-08-01', '+3 month')
    and l_returnflag = 'R'    and c_nationkey = n_nationkey
group by
    c_custkey,    c_name,    c_acctbal,    c_phone,    n_name, c_address,    c_comment
order by
    revenue desc;
} {
  QUERY PLAN
  |--SEARCH TABLE orders USING INDEX odi (O_ORDERDATE>? AND O_ORDERDATE<?)
  |--SEARCH TABLE customer USING INDEX cpki (C_CUSTKEY=?)
  |--SEARCH TABLE nation USING INDEX npki (N_NATIONKEY=?)
  |--SEARCH TABLE lineitem USING INDEX lpki (L_ORDERKEY=?)
  |--USE TEMP B-TREE FOR GROUP BY
  `--USE TEMP B-TREE FOR ORDER BY
}

finish_test

Changes to test/unordered.test.

36
37
38
39
40
41
42
43
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
  if {$idxmode == "unordered"} {
    execsql { UPDATE sqlite_stat1 SET stat = stat || ' unordered' }
  }
  db close
  sqlite3 db test.db
  foreach {tn sql r(ordered) r(unordered)} {
    1   "SELECT * FROM t1 ORDER BY a"
        {0 0 0 {SCAN TABLE t1 USING INDEX i1}}
        {0 0 0 {SCAN TABLE t1} 0 0 0 {USE TEMP B-TREE FOR ORDER BY}}
    2   "SELECT * FROM t1 WHERE a > 100"
        {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a>?)}}
        {0 0 0 {SCAN TABLE t1}}
    3   "SELECT * FROM t1 WHERE a = ? ORDER BY rowid"
        {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a=?)}}
        {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a=?)} 
         0 0 0 {USE TEMP B-TREE FOR ORDER BY}}
    4   "SELECT max(a) FROM t1"
        {0 0 0 {SEARCH TABLE t1 USING COVERING INDEX i1}}
        {0 0 0 {SEARCH TABLE t1}}
    5   "SELECT group_concat(b) FROM t1 GROUP BY a"
        {0 0 0 {SCAN TABLE t1 USING INDEX i1}}
        {0 0 0 {SCAN TABLE t1} 0 0 0 {USE TEMP B-TREE FOR GROUP BY}}

    6   "SELECT * FROM t1 WHERE a = ?"
        {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a=?)}}
        {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a=?)}}
    7   "SELECT count(*) FROM t1"
        {0 0 0 {SCAN TABLE t1 USING COVERING INDEX i1}}
        {0 0 0 {SCAN TABLE t1}}
  } {
    do_eqp_test 1.$idxmode.$tn $sql $r($idxmode)
  }
}

finish_test







|
|

|
|

|
|
<

|
|

|
|


|
|

|
|






36
37
38
39
40
41
42
43
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
  if {$idxmode == "unordered"} {
    execsql { UPDATE sqlite_stat1 SET stat = stat || ' unordered' }
  }
  db close
  sqlite3 db test.db
  foreach {tn sql r(ordered) r(unordered)} {
    1   "SELECT * FROM t1 ORDER BY a"
        {SCAN TABLE t1 USING INDEX i1}
        {SCAN TABLE t1*USE TEMP B-TREE FOR ORDER BY}
    2   "SELECT * FROM t1 WHERE a > 100"
        {SEARCH TABLE t1 USING INDEX i1 (a>?)}
        {SCAN TABLE t1}
    3   "SELECT * FROM t1 WHERE a = ? ORDER BY rowid"
        {SEARCH TABLE t1 USING INDEX i1 (a=?)}
        {SEARCH TABLE t1 USING INDEX i1 (a=?)*USE TEMP B-TREE FOR ORDER BY}

    4   "SELECT max(a) FROM t1"
        {SEARCH TABLE t1 USING COVERING INDEX i1}
        {SEARCH TABLE t1}
    5   "SELECT group_concat(b) FROM t1 GROUP BY a"
        {SCAN TABLE t1 USING INDEX i1}
        {SCAN TABLE t1*USE TEMP B-TREE FOR GROUP BY}

    6   "SELECT * FROM t1 WHERE a = ?"
        {SEARCH TABLE t1 USING INDEX i1 (a=?)}
        {SEARCH TABLE t1 USING INDEX i1 (a=?)}
    7   "SELECT count(*) FROM t1"
        {SCAN TABLE t1 USING COVERING INDEX i1}
        {SCAN TABLE t1}
  } {
    do_eqp_test 1.$idxmode.$tn $sql $r($idxmode)
  }
}

finish_test

Changes to test/where7.test.

23337
23338
23339
23340
23341
23342
23343
23344
23345
23346
23347
23348
23349
23350
23351
23352
23353

23354
23355
23356
23357
23358
23359
23360
      c2 INTEGER,
      c4 INTEGER,
      FOREIGN KEY (c8) REFERENCES t301(c8)
  );
  CREATE INDEX t302_c3 on t302(c3);
  CREATE INDEX t302_c8_c3 on t302(c8, c3);
  CREATE INDEX t302_c5 on t302(c5);
  
  EXPLAIN QUERY PLAN
  SELECT t302.c1 
    FROM t302 JOIN t301 ON t302.c8 = +t301.c8
    WHERE t302.c2 = 19571
      AND t302.c3 > 1287603136
      AND (t301.c4 = 1407449685622784
           OR t301.c8 = 1407424651264000)
   ORDER BY t302.c5 LIMIT 200;
} {

  0 0 1 {SEARCH TABLE t301 USING COVERING INDEX t301_c4 (c4=?)} 
  0 0 1 {SEARCH TABLE t301 USING INTEGER PRIMARY KEY (rowid=?)} 
  0 1 0 {SEARCH TABLE t302 USING INDEX t302_c8_c3 (c8=? AND c3>?)} 
  0 0 0 {USE TEMP B-TREE FOR ORDER BY}
}

finish_test







|
|








>
|
|
|
|



23337
23338
23339
23340
23341
23342
23343
23344
23345
23346
23347
23348
23349
23350
23351
23352
23353
23354
23355
23356
23357
23358
23359
23360
23361
      c2 INTEGER,
      c4 INTEGER,
      FOREIGN KEY (c8) REFERENCES t301(c8)
  );
  CREATE INDEX t302_c3 on t302(c3);
  CREATE INDEX t302_c8_c3 on t302(c8, c3);
  CREATE INDEX t302_c5 on t302(c5);
}
do_eqp_test where7-3.2 {
  SELECT t302.c1 
    FROM t302 JOIN t301 ON t302.c8 = +t301.c8
    WHERE t302.c2 = 19571
      AND t302.c3 > 1287603136
      AND (t301.c4 = 1407449685622784
           OR t301.c8 = 1407424651264000)
   ORDER BY t302.c5 LIMIT 200;
} {
  QUERY PLAN
  |--SEARCH TABLE t301 USING COVERING INDEX t301_c4 (c4=?)
  |--SEARCH TABLE t301 USING INTEGER PRIMARY KEY (rowid=?)
  |--SEARCH TABLE t302 USING INDEX t302_c8_c3 (c8=? AND c3>?)
  `--USE TEMP B-TREE FOR ORDER BY
}

finish_test

Changes to test/where9.test.

353
354
355
356
357
358
359
360
361
362
363

364
365
366
367
368
369
370
371
372
373

374
375
376
377
378
379
380
381
382
383
384
385
...
442
443
444
445
446
447
448
449
450
451
452
453
454
455

456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
     WHERE t1.a=t3.y OR t1.b=t3.y*11 OR (t1.c=27027 AND round(t1.d)==80)
    ORDER BY 1, 2, 3
  }
} {1 80 2 1 80 28 1 80 54 1 80 80 2 80 2 2 80 28 2 80 54 2 80 80 scan 1 sort 1}


ifcapable explain {
  do_execsql_test where9-3.1 {
    EXPLAIN QUERY PLAN
    SELECT t2.a FROM t1, t2
    WHERE t1.a=80 AND ((t1.c=t2.c AND t1.d=t2.d) OR t1.f=t2.f)

  } {
    0 0 0 {SEARCH TABLE t1 USING INTEGER PRIMARY KEY (rowid=?)} 
    0 1 1 {SEARCH TABLE t2 USING INDEX t2d (d=?)} 
    0 1 1 {SEARCH TABLE t2 USING COVERING INDEX t2f (f=?)}
  }
  do_execsql_test where9-3.2 {
    EXPLAIN QUERY PLAN
    SELECT coalesce(t2.a,9999)
    FROM t1 LEFT JOIN t2 ON (t1.c+1=t2.c AND t1.d=t2.d) OR (t1.f||'x')=t2.f
    WHERE t1.a=80

  } {
    0 0 0 {SEARCH TABLE t1 USING INTEGER PRIMARY KEY (rowid=?)} 
    0 1 1 {SEARCH TABLE t2 USING INDEX t2d (d=?)} 
    0 1 1 {SEARCH TABLE t2 USING COVERING INDEX t2f (f=?)}
  }
} 

# Make sure that INDEXED BY and multi-index OR clauses play well with
# one another.
#
do_test where9-4.1 {
  count_steps {
................................................................................
    SELECT a FROM t1 INDEXED BY t1d
     WHERE b>1000
       AND (c=31031 OR d IS NULL)
     ORDER BY +a
  }
} {1 {no query solution}}

ifcapable explain {
  # The (c=31031 OR d IS NULL) clause is preferred over b>1000 because
  # the former is an equality test which is expected to return fewer rows.
  #
  do_execsql_test where9-5.1 {
    EXPLAIN QUERY PLAN SELECT a FROM t1 WHERE b>1000 AND (c=31031 OR d IS NULL)
  } {

    0 0 0 {SEARCH TABLE t1 USING INDEX t1c (c=?)} 
    0 0 0 {SEARCH TABLE t1 USING INDEX t1d (d=?)}
  }

  # In contrast, b=1000 is preferred over any OR-clause.
  #
  do_execsql_test where9-5.2 {
    EXPLAIN QUERY PLAN SELECT a FROM t1 WHERE b=1000 AND (c=31031 OR d IS NULL)
  } {
    0 0 0 {SEARCH TABLE t1 USING INDEX t1b (b=?)}
  }

  # Likewise, inequalities in an AND are preferred over inequalities in
  # an OR.
  #
  do_execsql_test where9-5.3 {
    EXPLAIN QUERY PLAN SELECT a FROM t1 WHERE b>1000 AND (c>=31031 OR d IS NULL)
  } {
    0 0 0 {SEARCH TABLE t1 USING INDEX t1b (b>?)}
  }
}

############################################################################
# Make sure OR-clauses work correctly on UPDATE and DELETE statements.

do_test where9-6.2.1 {
  db eval {SELECT count(*) FROM t1 UNION ALL SELECT a FROM t1 WHERE a>=85}
} {99 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99}







|
<


>
|
|
|
|
|
|
<



>
|
|
|
|
|







 







<
|
|
|
|
|
|
>
|
|
|

|
|
|
|
<
|
|
<
|
|
|
|
|
<
|
<
<







353
354
355
356
357
358
359
360

361
362
363
364
365
366
367
368
369

370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
...
442
443
444
445
446
447
448

449
450
451
452
453
454
455
456
457
458
459
460
461
462
463

464
465

466
467
468
469
470

471


472
473
474
475
476
477
478
     WHERE t1.a=t3.y OR t1.b=t3.y*11 OR (t1.c=27027 AND round(t1.d)==80)
    ORDER BY 1, 2, 3
  }
} {1 80 2 1 80 28 1 80 54 1 80 80 2 80 2 2 80 28 2 80 54 2 80 80 scan 1 sort 1}


ifcapable explain {
  do_eqp_test where9-3.1 {

    SELECT t2.a FROM t1, t2
    WHERE t1.a=80 AND ((t1.c=t2.c AND t1.d=t2.d) OR t1.f=t2.f)
  } [string map {"\n  " \n} {
    QUERY PLAN
    |--SEARCH TABLE t1 USING INTEGER PRIMARY KEY (rowid=?)
    |--SEARCH TABLE t2 USING INDEX t2d (d=?)
    `--SEARCH TABLE t2 USING COVERING INDEX t2f (f=?)
  }]
  do_eqp_test where9-3.2 {

    SELECT coalesce(t2.a,9999)
    FROM t1 LEFT JOIN t2 ON (t1.c+1=t2.c AND t1.d=t2.d) OR (t1.f||'x')=t2.f
    WHERE t1.a=80
  } [string map {"\n  " \n} {
    QUERY PLAN
    |--SEARCH TABLE t1 USING INTEGER PRIMARY KEY (rowid=?)
    |--SEARCH TABLE t2 USING INDEX t2d (d=?)
    `--SEARCH TABLE t2 USING COVERING INDEX t2f (f=?)
  }]
} 

# Make sure that INDEXED BY and multi-index OR clauses play well with
# one another.
#
do_test where9-4.1 {
  count_steps {
................................................................................
    SELECT a FROM t1 INDEXED BY t1d
     WHERE b>1000
       AND (c=31031 OR d IS NULL)
     ORDER BY +a
  }
} {1 {no query solution}}


# The (c=31031 OR d IS NULL) clause is preferred over b>1000 because
# the former is an equality test which is expected to return fewer rows.
#
do_eqp_test where9-5.1 {
  SELECT a FROM t1 WHERE b>1000 AND (c=31031 OR d IS NULL)
} {
  QUERY PLAN
  |--SEARCH TABLE t1 USING INDEX t1c (c=?)
  `--SEARCH TABLE t1 USING INDEX t1d (d=?)
}

# In contrast, b=1000 is preferred over any OR-clause.
#
do_eqp_test where9-5.2 {
  SELECT a FROM t1 WHERE b=1000 AND (c=31031 OR d IS NULL)

} {SEARCH TABLE t1 USING INDEX t1b (b=?)}


# Likewise, inequalities in an AND are preferred over inequalities in
# an OR.
#
do_eqp_test where9-5.3 {
  SELECT a FROM t1 WHERE b>1000 AND (c>=31031 OR d IS NULL)

} {SEARCH TABLE t1 USING INDEX t1b (b>?)}



############################################################################
# Make sure OR-clauses work correctly on UPDATE and DELETE statements.

do_test where9-6.2.1 {
  db eval {SELECT count(*) FROM t1 UNION ALL SELECT a FROM t1 WHERE a>=85}
} {99 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99}

Changes to test/whereG.test.

62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
...
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
} {}
do_eqp_test whereG-1.1 {
  SELECT DISTINCT aname
    FROM album, composer, track
   WHERE unlikely(cname LIKE '%bach%')
     AND composer.cid=track.cid
     AND album.aid=track.aid;
} {/.*composer.*track.*album.*/}
do_execsql_test whereG-1.2 {
  SELECT DISTINCT aname
    FROM album, composer, track
   WHERE unlikely(cname LIKE '%bach%')
     AND composer.cid=track.cid
     AND album.aid=track.aid;
} {{Mass in B Minor, BWV 232}}
................................................................................

do_execsql_test 5.1 {
  CREATE TABLE t1(a, b, c);
  CREATE INDEX i1 ON t1(a, b);
}
do_eqp_test 5.1.2 {
  SELECT * FROM t1 WHERE a>?
} {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a>?)}}
do_eqp_test 5.1.3 {
  SELECT * FROM t1 WHERE likelihood(a>?, 0.9)
} {0 0 0 {SCAN TABLE t1}}
do_eqp_test 5.1.4 {
  SELECT * FROM t1 WHERE likely(a>?)
} {0 0 0 {SCAN TABLE t1}}

do_test 5.2 {
  for {set i 0} {$i < 100} {incr i} {
    execsql { INSERT INTO t1 VALUES('abc', $i, $i); }
  }
  execsql { INSERT INTO t1 SELECT 'def', b, c FROM t1; }
  execsql { ANALYZE }
} {}
do_eqp_test 5.2.2 {
  SELECT * FROM t1 WHERE likelihood(b>?, 0.01)
} {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (ANY(a) AND b>?)}}
do_eqp_test 5.2.3 {
  SELECT * FROM t1 WHERE likelihood(b>?, 0.9)
} {0 0 0 {SCAN TABLE t1}}
do_eqp_test 5.2.4 {
  SELECT * FROM t1 WHERE likely(b>?)
} {0 0 0 {SCAN TABLE t1}}

do_eqp_test 5.3.1 {
  SELECT * FROM t1 WHERE a=?
} {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a=?)}}
do_eqp_test 5.3.2 {
  SELECT * FROM t1 WHERE likelihood(a=?, 0.9)
} {0 0 0 {SCAN TABLE t1}}
do_eqp_test 5.3.3 {
  SELECT * FROM t1 WHERE likely(a=?)
} {0 0 0 {SCAN TABLE t1}}

# 2015-06-18
# Ticket [https://www.sqlite.org/see/tktview/472f0742a1868fb58862bc588ed70]
#
do_execsql_test 6.0 {
  DROP TABLE IF EXISTS t1;
  CREATE TABLE t1(i int, x, y, z);







|







 







|


|


|










|


|


|



|


|


|







62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
...
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
} {}
do_eqp_test whereG-1.1 {
  SELECT DISTINCT aname
    FROM album, composer, track
   WHERE unlikely(cname LIKE '%bach%')
     AND composer.cid=track.cid
     AND album.aid=track.aid;
} {composer*track*album}
do_execsql_test whereG-1.2 {
  SELECT DISTINCT aname
    FROM album, composer, track
   WHERE unlikely(cname LIKE '%bach%')
     AND composer.cid=track.cid
     AND album.aid=track.aid;
} {{Mass in B Minor, BWV 232}}
................................................................................

do_execsql_test 5.1 {
  CREATE TABLE t1(a, b, c);
  CREATE INDEX i1 ON t1(a, b);
}
do_eqp_test 5.1.2 {
  SELECT * FROM t1 WHERE a>?
} {SEARCH TABLE t1 USING INDEX i1 (a>?)}
do_eqp_test 5.1.3 {
  SELECT * FROM t1 WHERE likelihood(a>?, 0.9)
} {SCAN TABLE t1}
do_eqp_test 5.1.4 {
  SELECT * FROM t1 WHERE likely(a>?)
} {SCAN TABLE t1}

do_test 5.2 {
  for {set i 0} {$i < 100} {incr i} {
    execsql { INSERT INTO t1 VALUES('abc', $i, $i); }
  }
  execsql { INSERT INTO t1 SELECT 'def', b, c FROM t1; }
  execsql { ANALYZE }
} {}
do_eqp_test 5.2.2 {
  SELECT * FROM t1 WHERE likelihood(b>?, 0.01)
} {SEARCH TABLE t1 USING INDEX i1 (ANY(a) AND b>?)}
do_eqp_test 5.2.3 {
  SELECT * FROM t1 WHERE likelihood(b>?, 0.9)
} {SCAN TABLE t1}
do_eqp_test 5.2.4 {
  SELECT * FROM t1 WHERE likely(b>?)
} {SCAN TABLE t1}

do_eqp_test 5.3.1 {
  SELECT * FROM t1 WHERE a=?
} {SEARCH TABLE t1 USING INDEX i1 (a=?)}
do_eqp_test 5.3.2 {
  SELECT * FROM t1 WHERE likelihood(a=?, 0.9)
} {SCAN TABLE t1}
do_eqp_test 5.3.3 {
  SELECT * FROM t1 WHERE likely(a=?)
} {SCAN TABLE t1}

# 2015-06-18
# Ticket [https://www.sqlite.org/see/tktview/472f0742a1868fb58862bc588ed70]
#
do_execsql_test 6.0 {
  DROP TABLE IF EXISTS t1;
  CREATE TABLE t1(i int, x, y, z);

Changes to test/whereI.test.

25
26
27
28
29
30
31

32
33
34
35
36
37
38
39
40
..
53
54
55
56
57
58
59

60
61
62
63
64
65
66
67
68
  CREATE INDEX i1 ON t1(b);
  CREATE INDEX i2 ON t1(c);
}

do_eqp_test 1.1 {
  SELECT a FROM t1 WHERE b='b' OR c='x'
} {

  0 0 0 {SEARCH TABLE t1 USING INDEX i1 (b=?)} 
  0 0 0 {SEARCH TABLE t1 USING INDEX i2 (c=?)}
}

do_execsql_test 1.2 {
  SELECT a FROM t1 WHERE b='b' OR c='x'
} {2 3}

do_execsql_test 1.3 {
................................................................................
  CREATE INDEX i3 ON t2(b);
  CREATE INDEX i4 ON t2(c);
}

do_eqp_test 2.1 {
  SELECT a FROM t2 WHERE b='b' OR c='x'
} {

  0 0 0 {SEARCH TABLE t2 USING INDEX i3 (b=?)} 
  0 0 0 {SEARCH TABLE t2 USING INDEX i4 (c=?)}
}

do_execsql_test 2.2 {
  SELECT a FROM t2 WHERE b='b' OR c='x'
} {ii iii}

do_execsql_test 2.3 {







>
|
|







 







>
|
|







25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
..
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
  CREATE INDEX i1 ON t1(b);
  CREATE INDEX i2 ON t1(c);
}

do_eqp_test 1.1 {
  SELECT a FROM t1 WHERE b='b' OR c='x'
} {
  QUERY PLAN
  |--SEARCH TABLE t1 USING INDEX i1 (b=?)
  `--SEARCH TABLE t1 USING INDEX i2 (c=?)
}

do_execsql_test 1.2 {
  SELECT a FROM t1 WHERE b='b' OR c='x'
} {2 3}

do_execsql_test 1.3 {
................................................................................
  CREATE INDEX i3 ON t2(b);
  CREATE INDEX i4 ON t2(c);
}

do_eqp_test 2.1 {
  SELECT a FROM t2 WHERE b='b' OR c='x'
} {
  QUERY PLAN
  |--SEARCH TABLE t2 USING INDEX i3 (b=?)
  `--SEARCH TABLE t2 USING INDEX i4 (c=?)
}

do_execsql_test 2.2 {
  SELECT a FROM t2 WHERE b='b' OR c='x'
} {ii iii}

do_execsql_test 2.3 {

Changes to test/whereJ.test.

398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424

# This one should use index "idx_c".
do_eqp_test 3.4 {
  SELECT * FROM t1 WHERE 
    a = 4 AND b BETWEEN 20 AND 80           -- Matches 80 rows
      AND
    c BETWEEN 150 AND 160                   -- Matches 10 rows
} {
  0 0 0 {SEARCH TABLE t1 USING INDEX idx_c (c>? AND c<?)}
}

# This one should use index "idx_ab".
do_eqp_test 3.5 {
  SELECT * FROM t1 WHERE 
    a = 5 AND b BETWEEN 20 AND 80           -- Matches 1 row
      AND
    c BETWEEN 150 AND 160                   -- Matches 10 rows
} {
  0 0 0 {SEARCH TABLE t1 USING INDEX idx_ab (a=? AND b>? AND b<?)}
}

###########################################################################################

# Reset the database and setup for a test case derived from actual SQLite users
#
db close
sqlite3 db test.db







<
|
<







<
|
<







398
399
400
401
402
403
404

405

406
407
408
409
410
411
412

413

414
415
416
417
418
419
420

# This one should use index "idx_c".
do_eqp_test 3.4 {
  SELECT * FROM t1 WHERE 
    a = 4 AND b BETWEEN 20 AND 80           -- Matches 80 rows
      AND
    c BETWEEN 150 AND 160                   -- Matches 10 rows

} {SEARCH TABLE t1 USING INDEX idx_c (c>? AND c<?)}


# This one should use index "idx_ab".
do_eqp_test 3.5 {
  SELECT * FROM t1 WHERE 
    a = 5 AND b BETWEEN 20 AND 80           -- Matches 1 row
      AND
    c BETWEEN 150 AND 160                   -- Matches 10 rows

} {SEARCH TABLE t1 USING INDEX idx_ab (a=? AND b>? AND b<?)}


###########################################################################################

# Reset the database and setup for a test case derived from actual SQLite users
#
db close
sqlite3 db test.db

Changes to test/with1.test.

988
989
990
991
992
993
994
995
996
997
998


999
1000
1001
1002
1003



1004


1005
1006
1007
1008
1009
1010
1011
    FROM xyz ORDER BY 1
  )
  SELECT 1 FROM xyz;
} 1

# EXPLAIN QUERY PLAN on a self-join of a CTE
#
do_execsql_test 19.1 {
  DROP TABLE IF EXISTS t1;
  CREATE TABLE t1(x);
  EXPLAIN QUERY PLAN


  WITH
    x1(a) AS (values(100))
  INSERT INTO t1(x)
    SELECT * FROM (WITH x2(y) AS (SELECT * FROM x1) SELECT y+a FROM x1, x2);
  SELECT * FROM t1;



} {0 0 0 {SCAN SUBQUERY 1} 0 1 1 {SCAN SUBQUERY 1}}



# 2017-10-28.
# See check-in https://sqlite.org/src/info/0926df095faf72c2
# Tried to optimize co-routine processing by changing a Copy opcode
# into SCopy.  But OSSFuzz found two (similar) cases where that optimization
# does not work.
#







|


<
>
>





>
>
>
|
>
>







988
989
990
991
992
993
994
995
996
997

998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
    FROM xyz ORDER BY 1
  )
  SELECT 1 FROM xyz;
} 1

# EXPLAIN QUERY PLAN on a self-join of a CTE
#
do_execsql_test 19.1a {
  DROP TABLE IF EXISTS t1;
  CREATE TABLE t1(x);

}
do_eqp_test 19.1b {
  WITH
    x1(a) AS (values(100))
  INSERT INTO t1(x)
    SELECT * FROM (WITH x2(y) AS (SELECT * FROM x1) SELECT y+a FROM x1, x2);
  SELECT * FROM t1;
} {
  QUERY PLAN
  |--MATERIALIZE xxxxxx
  |--SCAN SUBQUERY xxxxxx
  `--SCAN SUBQUERY xxxxxx
}

# 2017-10-28.
# See check-in https://sqlite.org/src/info/0926df095faf72c2
# Tried to optimize co-routine processing by changing a Copy opcode
# into SCopy.  But OSSFuzz found two (similar) cases where that optimization
# does not work.
#

Changes to test/with3.test.

75
76
77
78
79
80
81
82




83
84
85
86
87
88
89
90
91
92




93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110



111
112

113
114
115

116
117
118
119
120
    ANALYZE;

  }

  do_eqp_test 3.1.2 {
    WITH cnt(i) AS ( SELECT 1 UNION ALL SELECT i+1 FROM cnt LIMIT 1)
    SELECT * FROM cnt, y1 WHERE i=a
  } {




    3 0 0 {SCAN TABLE cnt} 
    1 0 0 {COMPOUND SUBQUERIES 0 AND 0 (UNION ALL)}
    0 0 0 {SCAN SUBQUERY 1} 
    0 1 1 {SEARCH TABLE y1 USING INDEX y1a (a=?)}
  }

  do_eqp_test 3.1.3 {
    WITH cnt(i) AS ( SELECT 1 UNION ALL SELECT i+1 FROM cnt LIMIT 1000000)
    SELECT * FROM cnt, y1 WHERE i=a
  } {




    3 0 0 {SCAN TABLE cnt} 
    1 0 0 {COMPOUND SUBQUERIES 0 AND 0 (UNION ALL)}
    0 0 1 {SCAN TABLE y1} 
    0 1 0 {SEARCH SUBQUERY 1 USING AUTOMATIC COVERING INDEX (i=?)}
  }
}

do_execsql_test 3.2.1 {
  CREATE TABLE w1(pk INTEGER PRIMARY KEY, x INTEGER);
  CREATE TABLE w2(pk INTEGER PRIMARY KEY);
}

do_eqp_test 3.2.2 {
  WITH RECURSIVE c(w,id) AS (SELECT 0, (SELECT pk FROM w2 LIMIT 1)
     UNION ALL SELECT c.w + 1, x FROM w1, c LIMIT 1)
     SELECT * FROM c, w2, w1
     WHERE c.id=w2.pk AND c.id=w1.pk;
} {



  2 0 0 {EXECUTE SCALAR SUBQUERY 3} 
  3 0 0 {SCAN TABLE w2} 

  4 0 0 {SCAN TABLE w1}
  4 1 1 {SCAN TABLE c} 
  1 0 0 {COMPOUND SUBQUERIES 0 AND 0 (UNION ALL)} 0 0 0 {SCAN SUBQUERY 1}

  0 1 1 {SEARCH TABLE w2 USING INTEGER PRIMARY KEY (rowid=?)} 
  0 2 2 {SEARCH TABLE w1 USING INTEGER PRIMARY KEY (rowid=?)}
}

finish_test







|
>
>
>
>
|
<
|
|
|




|
>
>
>
>
|
<
|
|
|













>
>
>
|
|
>
|
|
<
>
|
|



75
76
77
78
79
80
81
82
83
84
85
86
87

88
89
90
91
92
93
94
95
96
97
98
99
100

101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124

125
126
127
128
129
130
    ANALYZE;

  }

  do_eqp_test 3.1.2 {
    WITH cnt(i) AS ( SELECT 1 UNION ALL SELECT i+1 FROM cnt LIMIT 1)
    SELECT * FROM cnt, y1 WHERE i=a
  } [string map {"\n  " \n} {
    QUERY PLAN
    |--MATERIALIZE xxxxxx
    |  |--SETUP
    |  `--RECURSIVE STEP
    |     `--SCAN TABLE cnt

    |--SCAN SUBQUERY xxxxxx
    `--SEARCH TABLE y1 USING INDEX y1a (a=?)
  }]

  do_eqp_test 3.1.3 {
    WITH cnt(i) AS ( SELECT 1 UNION ALL SELECT i+1 FROM cnt LIMIT 1000000)
    SELECT * FROM cnt, y1 WHERE i=a
  } [string map {"\n  " \n} {
    QUERY PLAN
    |--MATERIALIZE xxxxxx
    |  |--SETUP
    |  `--RECURSIVE STEP
    |     `--SCAN TABLE cnt

    |--SCAN TABLE y1
    `--SEARCH SUBQUERY xxxxxx USING AUTOMATIC COVERING INDEX (i=?)
  }]
}

do_execsql_test 3.2.1 {
  CREATE TABLE w1(pk INTEGER PRIMARY KEY, x INTEGER);
  CREATE TABLE w2(pk INTEGER PRIMARY KEY);
}

do_eqp_test 3.2.2 {
  WITH RECURSIVE c(w,id) AS (SELECT 0, (SELECT pk FROM w2 LIMIT 1)
     UNION ALL SELECT c.w + 1, x FROM w1, c LIMIT 1)
     SELECT * FROM c, w2, w1
     WHERE c.id=w2.pk AND c.id=w1.pk;
} {
  QUERY PLAN
  |--MATERIALIZE xxxxxx
  |  |--SETUP
  |  |  `--SCALAR SUBQUERY
  |  |     `--SCAN TABLE w2
  |  `--RECURSIVE STEP
  |     |--SCAN TABLE w1
  |     `--SCAN TABLE c

  |--SCAN SUBQUERY xxxxxx
  |--SEARCH TABLE w2 USING INTEGER PRIMARY KEY (rowid=?)
  `--SEARCH TABLE w1 USING INTEGER PRIMARY KEY (rowid=?)
}

finish_test

Changes to test/without_rowid1.test.

234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
...
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
  INSERT INTO t45 VALUES(5, 'two', 'x');
  INSERT INTO t45 VALUES(7, 'two', 'x');
  INSERT INTO t45 VALUES(9, 'two', 'x');
}

do_eqp_test 5.1 {
  SELECT * FROM t45 WHERE b=? AND a>?
} {/*USING INDEX i45 (b=? AND a>?)*/}

do_execsql_test 5.2 {
  SELECT * FROM t45 WHERE b='two' AND a>4
} {5 two x 7 two x 9 two x}

do_execsql_test 5.3 {
  SELECT * FROM t45 WHERE b='one' AND a<8
................................................................................
  WITH r(x) AS (
    SELECT 1 UNION ALL SELECT x+1 FROM r WHERE x<100
  )
  INSERT INTO t46 SELECT x / 20, x % 20, x % 10, x FROM r;
}

set queries {
  1    2    "c = 5 AND a = 1"          {/*i46 (c=? AND a=?)*/}
  2    6    "c = 4 AND a < 3"          {/*i46 (c=? AND a<?)*/}
  3    4    "c = 2 AND a >= 3"         {/*i46 (c=? AND a>?)*/}
  4    1    "c = 2 AND a = 1 AND b<10" {/*i46 (c=? AND a=? AND b<?)*/}
  5    1    "c = 0 AND a = 0 AND b>5"  {/*i46 (c=? AND a=? AND b>?)*/}
}

foreach {tn cnt where eqp} $queries {
  do_execsql_test 5.5.$tn.1 "SELECT count(*) FROM t46 WHERE $where" $cnt
}

do_execsql_test 5.6 {







|







 







|
|
|
|
|







234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
...
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
  INSERT INTO t45 VALUES(5, 'two', 'x');
  INSERT INTO t45 VALUES(7, 'two', 'x');
  INSERT INTO t45 VALUES(9, 'two', 'x');
}

do_eqp_test 5.1 {
  SELECT * FROM t45 WHERE b=? AND a>?
} {USING INDEX i45 (b=? AND a>?)}

do_execsql_test 5.2 {
  SELECT * FROM t45 WHERE b='two' AND a>4
} {5 two x 7 two x 9 two x}

do_execsql_test 5.3 {
  SELECT * FROM t45 WHERE b='one' AND a<8
................................................................................
  WITH r(x) AS (
    SELECT 1 UNION ALL SELECT x+1 FROM r WHERE x<100
  )
  INSERT INTO t46 SELECT x / 20, x % 20, x % 10, x FROM r;
}

set queries {
  1    2    "c = 5 AND a = 1"          {i46 (c=? AND a=?)}
  2    6    "c = 4 AND a < 3"          {i46 (c=? AND a<?)}
  3    4    "c = 2 AND a >= 3"         {i46 (c=? AND a>?)}
  4    1    "c = 2 AND a = 1 AND b<10" {i46 (c=? AND a=? AND b<?)}
  5    1    "c = 0 AND a = 0 AND b>5"  {i46 (c=? AND a=? AND b>?)}
}

foreach {tn cnt where eqp} $queries {
  do_execsql_test 5.5.$tn.1 "SELECT count(*) FROM t46 WHERE $where" $cnt
}

do_execsql_test 5.6 {