github.com/jdgcs/sqlite3@v1.12.1-0.20210908114423-bc5f96e4dd51/testdata/tcl/eqp.test (about)

     1  # 2010 November 6
     2  #
     3  # The author disclaims copyright to this source code.  In place of
     4  # a legal notice, here is a blessing:
     5  #
     6  #    May you do good and not evil.
     7  #    May you find forgiveness for yourself and forgive others.
     8  #    May you share freely, never taking more than you give.
     9  #
    10  #***********************************************************************
    11  #
    12  
    13  set testdir [file dirname $argv0]
    14  source $testdir/tester.tcl
    15  
    16  ifcapable !compound {
    17    finish_test
    18    return
    19  }
    20  
    21  set testprefix eqp
    22  
    23  #-------------------------------------------------------------------------
    24  #
    25  # eqp-1.*:        Assorted tests.
    26  # eqp-2.*:        Tests for single select statements.
    27  # eqp-3.*:        Select statements that execute sub-selects.
    28  # eqp-4.*:        Compound select statements.
    29  # ...
    30  # eqp-7.*:        "SELECT count(*) FROM tbl" statements (VDBE code OP_Count).
    31  #
    32  
    33  proc det {args} { uplevel do_eqp_test $args }
    34  
    35  do_execsql_test 1.1 {
    36    CREATE TABLE t1(a INT, b INT, ex TEXT);
    37    CREATE INDEX i1 ON t1(a);
    38    CREATE INDEX i2 ON t1(b);
    39    CREATE TABLE t2(a INT, b INT, ex TEXT);
    40    CREATE TABLE t3(a INT, b INT, ex TEXT);
    41  }
    42  
    43  do_eqp_test 1.2 {
    44    SELECT * FROM t2, t1 WHERE t1.a=1 OR t1.b=2;
    45  } {
    46    QUERY PLAN
    47    |--MULTI-INDEX OR
    48    |  |--INDEX 1
    49    |  |  `--SEARCH t1 USING INDEX i1 (a=?)
    50    |  `--INDEX 2
    51    |     `--SEARCH t1 USING INDEX i2 (b=?)
    52    `--SCAN t2
    53  }
    54  do_eqp_test 1.3 {
    55    SELECT * FROM t2 CROSS JOIN t1 WHERE t1.a=1 OR t1.b=2;
    56  } {
    57    QUERY PLAN
    58    |--SCAN t2
    59    `--MULTI-INDEX OR
    60       |--INDEX 1
    61       |  `--SEARCH t1 USING INDEX i1 (a=?)
    62       `--INDEX 2
    63          `--SEARCH t1 USING INDEX i2 (b=?)
    64  }
    65  do_eqp_test 1.3 {
    66    SELECT a FROM t1 ORDER BY a
    67  } {
    68    QUERY PLAN
    69    `--SCAN t1 USING COVERING INDEX i1
    70  }
    71  do_eqp_test 1.4 {
    72    SELECT a FROM t1 ORDER BY +a
    73  } {
    74    QUERY PLAN
    75    |--SCAN t1 USING COVERING INDEX i1
    76    `--USE TEMP B-TREE FOR ORDER BY
    77  }
    78  do_eqp_test 1.5 {
    79    SELECT a FROM t1 WHERE a=4
    80  } {
    81    QUERY PLAN
    82    `--SEARCH t1 USING COVERING INDEX i1 (a=?)
    83  }
    84  do_eqp_test 1.6 {
    85    SELECT DISTINCT count(*) FROM t3 GROUP BY a;
    86  } {
    87    QUERY PLAN
    88    |--SCAN t3
    89    |--USE TEMP B-TREE FOR GROUP BY
    90    `--USE TEMP B-TREE FOR DISTINCT
    91  }
    92  
    93  do_eqp_test 1.7.1 {
    94    SELECT * FROM t3 JOIN (SELECT 1)
    95  } {
    96    QUERY PLAN
    97    |--MATERIALIZE SUBQUERY xxxxxx
    98    |  `--SCAN CONSTANT ROW
    99    |--SCAN SUBQUERY xxxxxx
   100    `--SCAN t3
   101  }
   102  do_eqp_test 1.7.2 {
   103    SELECT * FROM t3 JOIN (SELECT 1) AS v1
   104  } {
   105    QUERY PLAN
   106    |--MATERIALIZE v1
   107    |  `--SCAN CONSTANT ROW
   108    |--SCAN v1
   109    `--SCAN t3
   110  }
   111  do_eqp_test 1.7.3 {
   112    SELECT * FROM t3 AS xx JOIN (SELECT 1) AS yy
   113  } {
   114    QUERY PLAN
   115    |--MATERIALIZE yy
   116    |  `--SCAN CONSTANT ROW
   117    |--SCAN yy
   118    `--SCAN xx
   119  }
   120  
   121  
   122  do_eqp_test 1.8 {
   123    SELECT * FROM t3 JOIN (SELECT 1 UNION SELECT 2)
   124  } {
   125    QUERY PLAN
   126    |--MATERIALIZE SUBQUERY xxxxxx
   127    |  `--COMPOUND QUERY
   128    |     |--LEFT-MOST SUBQUERY
   129    |     |  `--SCAN CONSTANT ROW
   130    |     `--UNION USING TEMP B-TREE
   131    |        `--SCAN CONSTANT ROW
   132    |--SCAN SUBQUERY xxxxxx
   133    `--SCAN t3
   134  }
   135  do_eqp_test 1.9 {
   136    SELECT * FROM t3 JOIN (SELECT 1 EXCEPT SELECT a FROM t3 LIMIT 17) AS abc
   137  } {
   138    QUERY PLAN
   139    |--MATERIALIZE abc
   140    |  `--COMPOUND QUERY
   141    |     |--LEFT-MOST SUBQUERY
   142    |     |  `--SCAN CONSTANT ROW
   143    |     `--EXCEPT USING TEMP B-TREE
   144    |        `--SCAN t3
   145    |--SCAN abc
   146    `--SCAN t3
   147  }
   148  do_eqp_test 1.10 {
   149    SELECT * FROM t3 JOIN (SELECT 1 INTERSECT SELECT a FROM t3 LIMIT 17) AS abc
   150  } {
   151    QUERY PLAN
   152    |--MATERIALIZE abc
   153    |  `--COMPOUND QUERY
   154    |     |--LEFT-MOST SUBQUERY
   155    |     |  `--SCAN CONSTANT ROW
   156    |     `--INTERSECT USING TEMP B-TREE
   157    |        `--SCAN t3
   158    |--SCAN abc
   159    `--SCAN t3
   160  }
   161  
   162  do_eqp_test 1.11 {
   163    SELECT * FROM t3 JOIN (SELECT 1 UNION ALL SELECT a FROM t3 LIMIT 17) abc
   164  } {
   165    QUERY PLAN
   166    |--MATERIALIZE abc
   167    |  `--COMPOUND QUERY
   168    |     |--LEFT-MOST SUBQUERY
   169    |     |  `--SCAN CONSTANT ROW
   170    |     `--UNION ALL
   171    |        `--SCAN t3
   172    |--SCAN abc
   173    `--SCAN t3
   174  }
   175  
   176  #-------------------------------------------------------------------------
   177  # Test cases eqp-2.* - tests for single select statements.
   178  #
   179  drop_all_tables
   180  do_execsql_test 2.1 {
   181    CREATE TABLE t1(x INT, y INT, ex TEXT);
   182  
   183    CREATE TABLE t2(x INT, y INT, ex TEXT);
   184    CREATE INDEX t2i1 ON t2(x);
   185  }
   186  
   187  det 2.2.1 "SELECT DISTINCT min(x), max(x) FROM t1 GROUP BY x ORDER BY 1" {
   188    QUERY PLAN
   189    |--SCAN t1
   190    |--USE TEMP B-TREE FOR GROUP BY
   191    |--USE TEMP B-TREE FOR DISTINCT
   192    `--USE TEMP B-TREE FOR ORDER BY
   193  }
   194  det 2.2.2 "SELECT DISTINCT min(x), max(x) FROM t2 GROUP BY x ORDER BY 1" {
   195    QUERY PLAN
   196    |--SCAN t2 USING COVERING INDEX t2i1
   197    |--USE TEMP B-TREE FOR DISTINCT
   198    `--USE TEMP B-TREE FOR ORDER BY
   199  }
   200  det 2.2.3 "SELECT DISTINCT * FROM t1" {
   201    QUERY PLAN
   202    |--SCAN t1
   203    `--USE TEMP B-TREE FOR DISTINCT
   204  }
   205  det 2.2.4 "SELECT DISTINCT * FROM t1, t2" {
   206    QUERY PLAN
   207    |--SCAN t1
   208    |--SCAN t2
   209    `--USE TEMP B-TREE FOR DISTINCT
   210  }
   211  det 2.2.5 "SELECT DISTINCT * FROM t1, t2 ORDER BY t1.x" {
   212    QUERY PLAN
   213    |--SCAN t1
   214    |--SCAN t2
   215    |--USE TEMP B-TREE FOR DISTINCT
   216    `--USE TEMP B-TREE FOR ORDER BY
   217  }
   218  det 2.2.6 "SELECT DISTINCT t2.x FROM t1, t2 ORDER BY t2.x" {
   219    QUERY PLAN
   220    |--SCAN t2 USING COVERING INDEX t2i1
   221    `--SCAN t1
   222  }
   223  
   224  det 2.3.1 "SELECT max(x) FROM t2" {
   225    QUERY PLAN
   226    `--SEARCH t2 USING COVERING INDEX t2i1
   227  }
   228  det 2.3.2 "SELECT min(x) FROM t2" {
   229    QUERY PLAN
   230    `--SEARCH t2 USING COVERING INDEX t2i1
   231  }
   232  det 2.3.3 "SELECT min(x), max(x) FROM t2" {
   233    QUERY PLAN
   234    `--SCAN t2 USING COVERING INDEX t2i1
   235  }
   236  
   237  det 2.4.1 "SELECT * FROM t1 WHERE rowid=?" {
   238    QUERY PLAN
   239    `--SEARCH t1 USING INTEGER PRIMARY KEY (rowid=?)
   240  }
   241  
   242  
   243  
   244  #-------------------------------------------------------------------------
   245  # Test cases eqp-3.* - tests for select statements that use sub-selects.
   246  #
   247  do_eqp_test 3.1.1 {
   248    SELECT (SELECT x FROM t1 AS sub) FROM t1;
   249  } {
   250    QUERY PLAN
   251    |--SCAN t1
   252    `--SCALAR SUBQUERY xxxxxx
   253       `--SCAN sub
   254  }
   255  do_eqp_test 3.1.2 {
   256    SELECT * FROM t1 WHERE (SELECT x FROM t1 AS sub);
   257  } {
   258    QUERY PLAN
   259    |--SCAN t1
   260    `--SCALAR SUBQUERY xxxxxx
   261       `--SCAN sub
   262  }
   263  do_eqp_test 3.1.3 {
   264    SELECT * FROM t1 WHERE (SELECT x FROM t1 AS sub ORDER BY y);
   265  } {
   266    QUERY PLAN
   267    |--SCAN t1
   268    `--SCALAR SUBQUERY xxxxxx
   269       |--SCAN sub
   270       `--USE TEMP B-TREE FOR ORDER BY
   271  }
   272  do_eqp_test 3.1.4 {
   273    SELECT * FROM t1 WHERE (SELECT x FROM t2 ORDER BY x);
   274  } {
   275    QUERY PLAN
   276    |--SCAN t1
   277    `--SCALAR SUBQUERY xxxxxx
   278       `--SCAN t2 USING COVERING INDEX t2i1
   279  }
   280  
   281  det 3.2.1 {
   282    SELECT * FROM (SELECT * FROM t1 ORDER BY x LIMIT 10) ORDER BY y LIMIT 5
   283  } {
   284    QUERY PLAN
   285    |--CO-ROUTINE SUBQUERY xxxxxx
   286    |  |--SCAN t1
   287    |  `--USE TEMP B-TREE FOR ORDER BY
   288    |--SCAN SUBQUERY xxxxxx
   289    `--USE TEMP B-TREE FOR ORDER BY
   290  }
   291  det 3.2.2 {
   292    SELECT * FROM 
   293      (SELECT * FROM t1 ORDER BY x LIMIT 10) AS x1,
   294      (SELECT * FROM t2 ORDER BY x LIMIT 10) AS x2
   295    ORDER BY x2.y LIMIT 5
   296  } {
   297    QUERY PLAN
   298    |--MATERIALIZE x1
   299    |  |--SCAN t1
   300    |  `--USE TEMP B-TREE FOR ORDER BY
   301    |--MATERIALIZE x2
   302    |  `--SCAN t2 USING INDEX t2i1
   303    |--SCAN x1
   304    |--SCAN x2
   305    `--USE TEMP B-TREE FOR ORDER BY
   306  }
   307  
   308  det 3.3.1 {
   309    SELECT * FROM t1 WHERE y IN (SELECT y FROM t2)
   310  } {
   311    QUERY PLAN
   312    |--SCAN t1
   313    `--LIST SUBQUERY xxxxxx
   314       `--SCAN t2
   315  }
   316  det 3.3.2 {
   317    SELECT * FROM t1 WHERE y IN (SELECT y FROM t2 WHERE t1.x!=t2.x)
   318  } {
   319    QUERY PLAN
   320    |--SCAN t1
   321    `--CORRELATED LIST SUBQUERY xxxxxx
   322       `--SCAN t2
   323  }
   324  det 3.3.3 {
   325    SELECT * FROM t1 WHERE EXISTS (SELECT y FROM t2 WHERE t1.x!=t2.x)
   326  } {
   327    QUERY PLAN
   328    |--SCAN t1
   329    `--CORRELATED SCALAR SUBQUERY xxxxxx
   330       `--SCAN t2
   331  }
   332  
   333  #-------------------------------------------------------------------------
   334  # Test cases eqp-4.* - tests for composite select statements.
   335  #
   336  do_eqp_test 4.1.1 {
   337    SELECT * FROM t1 UNION ALL SELECT * FROM t2
   338  } {
   339    QUERY PLAN
   340    `--COMPOUND QUERY
   341       |--LEFT-MOST SUBQUERY
   342       |  `--SCAN t1
   343       `--UNION ALL
   344          `--SCAN t2
   345  }
   346  do_eqp_test 4.1.2 {
   347    SELECT * FROM t1 UNION ALL SELECT * FROM t2 ORDER BY 2
   348  } {
   349    QUERY PLAN
   350    `--MERGE (UNION ALL)
   351       |--LEFT
   352       |  |--SCAN t1
   353       |  `--USE TEMP B-TREE FOR ORDER BY
   354       `--RIGHT
   355          |--SCAN t2
   356          `--USE TEMP B-TREE FOR ORDER BY
   357  }
   358  do_eqp_test 4.1.3 {
   359    SELECT * FROM t1 UNION SELECT * FROM t2 ORDER BY 2
   360  } {
   361    QUERY PLAN
   362    `--MERGE (UNION)
   363       |--LEFT
   364       |  |--SCAN t1
   365       |  `--USE TEMP B-TREE FOR ORDER BY
   366       `--RIGHT
   367          |--SCAN t2
   368          `--USE TEMP B-TREE FOR ORDER BY
   369  }
   370  do_eqp_test 4.1.4 {
   371    SELECT * FROM t1 INTERSECT SELECT * FROM t2 ORDER BY 2
   372  } {
   373    QUERY PLAN
   374    `--MERGE (INTERSECT)
   375       |--LEFT
   376       |  |--SCAN t1
   377       |  `--USE TEMP B-TREE FOR ORDER BY
   378       `--RIGHT
   379          |--SCAN t2
   380          `--USE TEMP B-TREE FOR ORDER BY
   381  }
   382  do_eqp_test 4.1.5 {
   383    SELECT * FROM t1 EXCEPT SELECT * FROM t2 ORDER BY 2
   384  } {
   385    QUERY PLAN
   386    `--MERGE (EXCEPT)
   387       |--LEFT
   388       |  |--SCAN t1
   389       |  `--USE TEMP B-TREE FOR ORDER BY
   390       `--RIGHT
   391          |--SCAN t2
   392          `--USE TEMP B-TREE FOR ORDER BY
   393  }
   394  
   395  do_eqp_test 4.2.2 {
   396    SELECT * FROM t1 UNION ALL SELECT * FROM t2 ORDER BY 1
   397  } {
   398    QUERY PLAN
   399    `--MERGE (UNION ALL)
   400       |--LEFT
   401       |  |--SCAN t1
   402       |  `--USE TEMP B-TREE FOR ORDER BY
   403       `--RIGHT
   404          `--SCAN t2 USING INDEX t2i1
   405  }
   406  do_eqp_test 4.2.3 {
   407    SELECT * FROM t1 UNION SELECT * FROM t2 ORDER BY 1
   408  } {
   409    QUERY PLAN
   410    `--MERGE (UNION)
   411       |--LEFT
   412       |  |--SCAN t1
   413       |  `--USE TEMP B-TREE FOR ORDER BY
   414       `--RIGHT
   415          |--SCAN t2 USING INDEX t2i1
   416          `--USE TEMP B-TREE FOR RIGHT PART OF ORDER BY
   417  }
   418  do_eqp_test 4.2.4 {
   419    SELECT * FROM t1 INTERSECT SELECT * FROM t2 ORDER BY 1
   420  } {
   421    QUERY PLAN
   422    `--MERGE (INTERSECT)
   423       |--LEFT
   424       |  |--SCAN t1
   425       |  `--USE TEMP B-TREE FOR ORDER BY
   426       `--RIGHT
   427          |--SCAN t2 USING INDEX t2i1
   428          `--USE TEMP B-TREE FOR RIGHT PART OF ORDER BY
   429  }
   430  do_eqp_test 4.2.5 {
   431    SELECT * FROM t1 EXCEPT SELECT * FROM t2 ORDER BY 1
   432  } {
   433    QUERY PLAN
   434    `--MERGE (EXCEPT)
   435       |--LEFT
   436       |  |--SCAN t1
   437       |  `--USE TEMP B-TREE FOR ORDER BY
   438       `--RIGHT
   439          |--SCAN t2 USING INDEX t2i1
   440          `--USE TEMP B-TREE FOR RIGHT PART OF ORDER BY
   441  }
   442  
   443  do_eqp_test 4.3.1 {
   444    SELECT x FROM t1 UNION SELECT x FROM t2
   445  } {
   446    QUERY PLAN
   447    `--COMPOUND QUERY
   448       |--LEFT-MOST SUBQUERY
   449       |  `--SCAN t1
   450       `--UNION USING TEMP B-TREE
   451          `--SCAN t2 USING COVERING INDEX t2i1
   452  }
   453  
   454  do_eqp_test 4.3.2 {
   455    SELECT x FROM t1 UNION SELECT x FROM t2 UNION SELECT x FROM t1
   456  } {
   457    QUERY PLAN
   458    `--COMPOUND QUERY
   459       |--LEFT-MOST SUBQUERY
   460       |  `--SCAN t1
   461       |--UNION USING TEMP B-TREE
   462       |  `--SCAN t2 USING COVERING INDEX t2i1
   463       `--UNION USING TEMP B-TREE
   464          `--SCAN t1
   465  }
   466  do_eqp_test 4.3.3 {
   467    SELECT x FROM t1 UNION SELECT x FROM t2 UNION SELECT x FROM t1 ORDER BY 1
   468  } {
   469    QUERY PLAN
   470    `--MERGE (UNION)
   471       |--LEFT
   472       |  `--MERGE (UNION)
   473       |     |--LEFT
   474       |     |  |--SCAN t1
   475       |     |  `--USE TEMP B-TREE FOR ORDER BY
   476       |     `--RIGHT
   477       |        `--SCAN t2 USING COVERING INDEX t2i1
   478       `--RIGHT
   479          |--SCAN t1
   480          `--USE TEMP B-TREE FOR ORDER BY
   481  }
   482  
   483  if 0 {
   484  #-------------------------------------------------------------------------
   485  # This next block of tests verifies that the examples on the 
   486  # lang_explain.html page are correct.
   487  #
   488  drop_all_tables
   489  
   490  # XVIDENCE-OF: R-47779-47605 sqlite> EXPLAIN QUERY PLAN SELECT a, b
   491  # FROM t1 WHERE a=1;
   492  # 0|0|0|SCAN t1
   493  #
   494  do_execsql_test 5.1.0 { CREATE TABLE t1(a INT, b INT, ex TEXT) }
   495  det 5.1.1 "SELECT a, b FROM t1 WHERE a=1" {
   496    0 0 0 {SCAN t1}
   497  }
   498  
   499  # XVIDENCE-OF: R-55852-17599 sqlite> CREATE INDEX i1 ON t1(a);
   500  # sqlite> EXPLAIN QUERY PLAN SELECT a, b FROM t1 WHERE a=1;
   501  # 0|0|0|SEARCH t1 USING INDEX i1
   502  #
   503  do_execsql_test 5.2.0 { CREATE INDEX i1 ON t1(a) }
   504  det 5.2.1 "SELECT a, b FROM t1 WHERE a=1" {
   505    0 0 0 {SEARCH t1 USING INDEX i1 (a=?)}
   506  }
   507  
   508  # XVIDENCE-OF: R-21179-11011 sqlite> CREATE INDEX i2 ON t1(a, b);
   509  # sqlite> EXPLAIN QUERY PLAN SELECT a, b FROM t1 WHERE a=1;
   510  # 0|0|0|SEARCH t1 USING COVERING INDEX i2 (a=?)
   511  #
   512  do_execsql_test 5.3.0 { CREATE INDEX i2 ON t1(a, b) }
   513  det 5.3.1 "SELECT a, b FROM t1 WHERE a=1" {
   514    0 0 0 {SEARCH t1 USING COVERING INDEX i2 (a=?)}
   515  }
   516  
   517  # XVIDENCE-OF: R-09991-48941 sqlite> EXPLAIN QUERY PLAN
   518  # SELECT t1.*, t2.* FROM t1, t2 WHERE t1.a=1 AND t1.b>2;
   519  # 0|0|0|SEARCH t1 USING COVERING INDEX i2 (a=? AND b>?)
   520  # 0|1|1|SCAN t2
   521  #
   522  do_execsql_test 5.4.0 {CREATE TABLE t2(c INT, d INT, ex TEXT)}
   523  det 5.4.1 "SELECT t1.a, t2.c FROM t1, t2 WHERE t1.a=1 AND t1.b>2" {
   524    0 0 0 {SEARCH t1 USING COVERING INDEX i2 (a=? AND b>?)}
   525    0 1 1 {SCAN t2}
   526  }
   527  
   528  # XVIDENCE-OF: R-33626-61085 sqlite> EXPLAIN QUERY PLAN
   529  # SELECT t1.*, t2.* FROM t2, t1 WHERE t1.a=1 AND t1.b>2;
   530  # 0|0|1|SEARCH t1 USING COVERING INDEX i2 (a=? AND b>?)
   531  # 0|1|0|SCAN t2
   532  #
   533  det 5.5 "SELECT t1.a, t2.c FROM t2, t1 WHERE t1.a=1 AND t1.b>2" {
   534    0 0 1 {SEARCH t1 USING COVERING INDEX i2 (a=? AND b>?)}
   535    0 1 0 {SCAN t2}
   536  }
   537  
   538  # XVIDENCE-OF: R-04002-25654 sqlite> CREATE INDEX i3 ON t1(b);
   539  # sqlite> EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a=1 OR b=2;
   540  # 0|0|0|SEARCH t1 USING COVERING INDEX i2 (a=?)
   541  # 0|0|0|SEARCH t1 USING INDEX i3 (b=?)
   542  #
   543  do_execsql_test 5.5.0 {CREATE INDEX i3 ON t1(b)}
   544  det 5.6.1 "SELECT a, b FROM t1 WHERE a=1 OR b=2" {
   545    0 0 0 {SEARCH t1 USING COVERING INDEX i2 (a=?)}
   546    0 0 0 {SEARCH t1 USING INDEX i3 (b=?)}
   547  }
   548  
   549  # XVIDENCE-OF: R-24577-38891 sqlite> EXPLAIN QUERY PLAN
   550  # SELECT c, d FROM t2 ORDER BY c;
   551  # 0|0|0|SCAN t2
   552  # 0|0|0|USE TEMP B-TREE FOR ORDER BY
   553  #
   554  det 5.7 "SELECT c, d FROM t2 ORDER BY c" {
   555    0 0 0 {SCAN t2}
   556    0 0 0 {USE TEMP B-TREE FOR ORDER BY}
   557  }
   558  
   559  # XVIDENCE-OF: R-58157-12355 sqlite> CREATE INDEX i4 ON t2(c);
   560  # sqlite> EXPLAIN QUERY PLAN SELECT c, d FROM t2 ORDER BY c;
   561  # 0|0|0|SCAN t2 USING INDEX i4
   562  #
   563  do_execsql_test 5.8.0 {CREATE INDEX i4 ON t2(c)}
   564  det 5.8.1 "SELECT c, d FROM t2 ORDER BY c" {
   565    0 0 0 {SCAN t2 USING INDEX i4}
   566  }
   567  
   568  # XVIDENCE-OF: R-13931-10421 sqlite> EXPLAIN QUERY PLAN SELECT
   569  # (SELECT b FROM t1 WHERE a=0), (SELECT a FROM t1 WHERE b=t2.c) FROM t2;
   570  # 0|0|0|SCAN t2
   571  # 0|0|0|EXECUTE SCALAR SUBQUERY 1
   572  # 1|0|0|SEARCH t1 USING COVERING INDEX i2 (a=?)
   573  # 0|0|0|EXECUTE CORRELATED SCALAR SUBQUERY 2
   574  # 2|0|0|SEARCH t1 USING INDEX i3 (b=?)
   575  #
   576  det 5.9 {
   577    SELECT (SELECT b FROM t1 WHERE a=0), (SELECT a FROM t1 WHERE b=t2.c) FROM t2
   578  } {
   579    0 0 0 {SCAN t2 USING COVERING INDEX i4}
   580    0 0 0 {EXECUTE SCALAR SUBQUERY 1}
   581    1 0 0 {SEARCH t1 USING COVERING INDEX i2 (a=?)}
   582    0 0 0 {EXECUTE CORRELATED SCALAR SUBQUERY 2}
   583    2 0 0 {SEARCH t1 USING INDEX i3 (b=?)}
   584  }
   585  
   586  # XVIDENCE-OF: R-50892-45943 sqlite> EXPLAIN QUERY PLAN
   587  # SELECT count(*) FROM (SELECT max(b) AS x FROM t1 GROUP BY a) GROUP BY x;
   588  # 1|0|0|SCAN t1 USING COVERING INDEX i2
   589  # 0|0|0|SCAN SUBQUERY 1
   590  # 0|0|0|USE TEMP B-TREE FOR GROUP BY
   591  #
   592  det 5.10 {
   593    SELECT count(*) FROM (SELECT max(b) AS x FROM t1 GROUP BY a) GROUP BY x
   594  } {
   595    1 0 0 {SCAN t1 USING COVERING INDEX i2}
   596    0 0 0 {SCAN SUBQUERY 1}
   597    0 0 0 {USE TEMP B-TREE FOR GROUP BY}
   598  }
   599  
   600  # XVIDENCE-OF: R-46219-33846 sqlite> EXPLAIN QUERY PLAN
   601  # SELECT * FROM (SELECT * FROM t2 WHERE c=1), t1;
   602  # 0|0|0|SEARCH t2 USING INDEX i4 (c=?)
   603  # 0|1|1|SCAN t1
   604  #
   605  det 5.11 "SELECT a, b FROM (SELECT * FROM t2 WHERE c=1), t1" {
   606    0 0 0 {SEARCH t2 USING INDEX i4 (c=?)}
   607    0 1 1 {SCAN t1 USING COVERING INDEX i2}
   608  }
   609  
   610  # XVIDENCE-OF: R-37879-39987 sqlite> EXPLAIN QUERY PLAN
   611  # SELECT a FROM t1 UNION SELECT c FROM t2;
   612  # 1|0|0|SCAN t1
   613  # 2|0|0|SCAN t2
   614  # 0|0|0|COMPOUND SUBQUERIES 1 AND 2 USING TEMP B-TREE (UNION)
   615  #
   616  det 5.12 "SELECT a,b FROM t1 UNION SELECT c, 99 FROM t2" {
   617    1 0 0 {SCAN t1 USING COVERING INDEX i2}
   618    2 0 0 {SCAN t2 USING COVERING INDEX i4}
   619    0 0 0 {COMPOUND SUBQUERIES 1 AND 2 USING TEMP B-TREE (UNION)}
   620  }
   621  
   622  # XVIDENCE-OF: R-44864-63011 sqlite> EXPLAIN QUERY PLAN
   623  # SELECT a FROM t1 EXCEPT SELECT d FROM t2 ORDER BY 1;
   624  # 1|0|0|SCAN t1 USING COVERING INDEX i2
   625  # 2|0|0|SCAN t2 2|0|0|USE TEMP B-TREE FOR ORDER BY
   626  # 0|0|0|COMPOUND SUBQUERIES 1 AND 2 (EXCEPT)
   627  #
   628  det 5.13 "SELECT a FROM t1 EXCEPT SELECT d FROM t2 ORDER BY 1" {
   629    1 0 0 {SCAN t1 USING COVERING INDEX i1}
   630    2 0 0 {SCAN t2}
   631    2 0 0 {USE TEMP B-TREE FOR ORDER BY}
   632    0 0 0 {COMPOUND SUBQUERIES 1 AND 2 (EXCEPT)}
   633  }
   634  
   635  if {![nonzero_reserved_bytes]} {
   636    #-------------------------------------------------------------------------
   637    # The following tests - eqp-6.* - test that the example C code on 
   638    # documentation page eqp.html works. The C code is duplicated in test1.c
   639    # and wrapped in Tcl command [print_explain_query_plan] 
   640    #
   641    set boilerplate {
   642      proc explain_query_plan {db sql} {
   643        set stmt [sqlite3_prepare_v2 db $sql -1 DUMMY]
   644        print_explain_query_plan $stmt
   645        sqlite3_finalize $stmt
   646      }
   647      sqlite3 db test.db
   648      explain_query_plan db {%SQL%}
   649      db close
   650      exit
   651    }
   652    
   653    # Do a "Print Explain Query Plan" test.
   654    proc do_peqp_test {tn sql res} {
   655      set fd [open script.tcl w]
   656      puts $fd [string map [list %SQL% $sql] $::boilerplate]
   657      close $fd
   658    
   659      uplevel do_test $tn [list {
   660        set fd [open "|[info nameofexec] script.tcl"]
   661        set data [read $fd]
   662        close $fd
   663        set data
   664      }] [list $res]
   665    }
   666    
   667    do_peqp_test 6.1 {
   668      SELECT a, b FROM t1 EXCEPT SELECT d, 99 FROM t2 ORDER BY 1
   669    } [string trimleft {
   670  1 0 0 SCAN t1 USING COVERING INDEX i2
   671  2 0 0 SCAN t2
   672  2 0 0 USE TEMP B-TREE FOR ORDER BY
   673  0 0 0 COMPOUND SUBQUERIES 1 AND 2 (EXCEPT)
   674  }]
   675  }
   676  }
   677  
   678  #-------------------------------------------------------------------------
   679  # The following tests - eqp-7.* - test that queries that use the OP_Count
   680  # optimization return something sensible with EQP.
   681  #
   682  drop_all_tables
   683  
   684  do_execsql_test 7.0 {
   685    CREATE TABLE t1(a INT, b INT, ex CHAR(100));
   686    CREATE TABLE t2(a INT, b INT, ex CHAR(100));
   687    CREATE INDEX i1 ON t2(a);
   688  }
   689  
   690  det 7.1 "SELECT count(*) FROM t1" {
   691    QUERY PLAN
   692    `--SCAN t1
   693  }
   694  
   695  det 7.2 "SELECT count(*) FROM t2" {
   696    QUERY PLAN
   697    `--SCAN t2 USING COVERING INDEX i1
   698  }
   699  
   700  do_execsql_test 7.3 {
   701    INSERT INTO t1(a,b) VALUES(1, 2);
   702    INSERT INTO t1(a,b) VALUES(3, 4);
   703  
   704    INSERT INTO t2(a,b) VALUES(1, 2);
   705    INSERT INTO t2(a,b) VALUES(3, 4);
   706    INSERT INTO t2(a,b) VALUES(5, 6);
   707   
   708    ANALYZE;
   709  }
   710  
   711  db close
   712  sqlite3 db test.db
   713  
   714  det 7.4 "SELECT count(*) FROM t1" {
   715    QUERY PLAN
   716    `--SCAN t1
   717  }
   718  
   719  det 7.5 "SELECT count(*) FROM t2" {
   720    QUERY PLAN
   721    `--SCAN t2 USING COVERING INDEX i1
   722  }
   723  
   724  #-------------------------------------------------------------------------
   725  # The following tests - eqp-8.* - test that queries that use the OP_Count
   726  # optimization return something sensible with EQP.
   727  #
   728  drop_all_tables
   729  
   730  do_execsql_test 8.0 {
   731    CREATE TABLE t1(a, b, c, PRIMARY KEY(b, c)) WITHOUT ROWID;
   732    CREATE TABLE t2(a, b, c);
   733  }
   734  
   735  det 8.1.1 "SELECT * FROM t2" {
   736    QUERY PLAN
   737    `--SCAN t2
   738  }
   739  
   740  det 8.1.2 "SELECT * FROM t2 WHERE rowid=?" {
   741    QUERY PLAN
   742    `--SEARCH t2 USING INTEGER PRIMARY KEY (rowid=?)
   743  }
   744  
   745  det 8.1.3 "SELECT count(*) FROM t2" {
   746    QUERY PLAN
   747    `--SCAN t2
   748  }
   749  
   750  det 8.2.1 "SELECT * FROM t1" {
   751    QUERY PLAN
   752    `--SCAN t1
   753  }
   754  
   755  det 8.2.2 "SELECT * FROM t1 WHERE b=?" {
   756    QUERY PLAN
   757    `--SEARCH t1 USING PRIMARY KEY (b=?)
   758  }
   759  
   760  det 8.2.3 "SELECT * FROM t1 WHERE b=? AND c=?" {
   761    QUERY PLAN
   762    `--SEARCH t1 USING PRIMARY KEY (b=? AND c=?)
   763  }
   764  
   765  det 8.2.4 "SELECT count(*) FROM t1" {
   766    QUERY PLAN
   767    `--SCAN t1
   768  }
   769  
   770  # 2018-08-16:  While working on Fossil I discovered that EXPLAIN QUERY PLAN
   771  # did not describe IN operators implemented using a ROWID lookup.  These
   772  # test cases ensure that problem as been fixed.
   773  #
   774  do_execsql_test 9.0 {
   775    -- Schema from Fossil 2018-08-16
   776    CREATE TABLE forumpost(
   777      fpid INTEGER PRIMARY KEY,
   778      froot INT,
   779      fprev INT,
   780      firt INT,
   781      fmtime REAL
   782    );
   783    CREATE INDEX forumthread ON forumpost(froot,fmtime);
   784    CREATE TABLE blob(
   785      rid INTEGER PRIMARY KEY,
   786      rcvid INTEGER,
   787      size INTEGER,
   788      uuid TEXT UNIQUE NOT NULL,
   789      content BLOB,
   790      CHECK( length(uuid)>=40 AND rid>0 )
   791    );
   792    CREATE TABLE event(
   793      type TEXT,
   794      mtime DATETIME,
   795      objid INTEGER PRIMARY KEY,
   796      tagid INTEGER,
   797      uid INTEGER REFERENCES user,
   798      bgcolor TEXT,
   799      euser TEXT,
   800      user TEXT,
   801      ecomment TEXT,
   802      comment TEXT,
   803      brief TEXT,
   804      omtime DATETIME
   805    );
   806    CREATE INDEX event_i1 ON event(mtime);
   807    CREATE TABLE private(rid INTEGER PRIMARY KEY);
   808  }
   809  do_eqp_test 9.1 {
   810    WITH thread(age,duration,cnt,root,last) AS (
   811      SELECT
   812        julianday('now') - max(fmtime) AS age,
   813        max(fmtime) - min(fmtime) AS duration,
   814        sum(fprev IS NULL) AS msg_count,
   815        froot,
   816        (SELECT fpid FROM forumpost
   817          WHERE froot=x.froot
   818            AND fpid NOT IN private
   819          ORDER BY fmtime DESC LIMIT 1)
   820      FROM forumpost AS x
   821      WHERE fpid NOT IN private  --- Ensure this table mentioned in EQP output!
   822      GROUP BY froot
   823      ORDER BY 1 LIMIT 26 OFFSET 5
   824    )
   825    SELECT
   826      thread.age,
   827      thread.duration,
   828      thread.cnt,
   829      blob.uuid,
   830      substr(event.comment,instr(event.comment,':')+1)
   831    FROM thread, blob, event
   832    WHERE blob.rid=thread.last
   833      AND event.objid=thread.last
   834    ORDER BY 1;
   835  } {
   836    QUERY PLAN
   837    |--MATERIALIZE thread
   838    |  |--SCAN x USING INDEX forumthread
   839    |  |--USING ROWID SEARCH ON TABLE private FOR IN-OPERATOR
   840    |  |--CORRELATED SCALAR SUBQUERY xxxxxx
   841    |  |  |--SEARCH forumpost USING COVERING INDEX forumthread (froot=?)
   842    |  |  `--USING ROWID SEARCH ON TABLE private FOR IN-OPERATOR
   843    |  `--USE TEMP B-TREE FOR ORDER BY
   844    |--SCAN thread
   845    |--SEARCH blob USING INTEGER PRIMARY KEY (rowid=?)
   846    |--SEARCH event USING INTEGER PRIMARY KEY (rowid=?)
   847    `--USE TEMP B-TREE FOR ORDER BY
   848  }
   849  
   850  finish_test