# 2008 December 23
#
# The author disclaims copyright to this source code.  In place of
# a legal notice, here is a blessing:
#
#    May you do good and not evil.
#    May you find forgiveness for yourself and forgive others.
#    May you share freely, never taking more than you give.
#
#***********************************************************************
# This file implements regression tests for SQLite library. The focus
# is testing of where.c. More specifically, the focus is the optimization
# of WHERE clauses that feature the OR operator.
#
# $Id: where8.test,v 1.2 2008/12/30 12:00:12 danielk1977 Exp $

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

# Test organization:
#
#   where8-1.*: Tests to demonstrate simple cases work with a single table
#               in the FROM clause.
#
#   where8-2.*: Tests surrounding virtual tables and the OR optimization.
#
#   where8-3.*: Tests with more than one table in the FROM clause.
# 

proc execsql_status {sql {db db}} {
  set result [uplevel $db eval [list $sql]]
  concat $result [db status step] [db status sort]
}

proc execsql_status2 {sql {db db}} {
  set ::sqlite_search_count 0
  set result [uplevel [list execsql_status $sql $db]]
  concat $result $::sqlite_search_count
}

do_test where8-1.1 {
  execsql {
    CREATE TABLE t1(a, b, c);
    CREATE INDEX i1 ON t1(a);
    CREATE INDEX i2 ON t1(b);

    INSERT INTO t1 VALUES(1,  'one',   'I');
    INSERT INTO t1 VALUES(2,  'two',   'II');
    INSERT INTO t1 VALUES(3,  'three', 'III');
    INSERT INTO t1 VALUES(4,  'four',  'IV');
    INSERT INTO t1 VALUES(5,  'five',  'V');
    INSERT INTO t1 VALUES(6,  'six',   'VI');
    INSERT INTO t1 VALUES(7,  'seven', 'VII');
    INSERT INTO t1 VALUES(8,  'eight', 'VIII');
    INSERT INTO t1 VALUES(9,  'nine',  'IX');
    INSERT INTO t1 VALUES(10, 'ten',   'X');
  }
} {}

do_test where8-1.2 { 
  execsql_status2 { SELECT c FROM t1 WHERE a = 1 OR b = 'nine' }
} {I IX 0 0 6}

do_test where8-1.3 { 
  execsql_status2 { SELECT c FROM t1 WHERE a > 8 OR b = 'two' }
} {II IX X 0 0 6}

do_test where8-1.4 { 
  execsql_status2 { SELECT c FROM t1 WHERE a > 8 OR b GLOB 't*' }
} {II III IX X 0 0 9}

do_test where8-1.5 { 
  execsql_status2 { SELECT c FROM t1 WHERE a > 8 OR b GLOB 'f*' }
} {IV V IX X 0 0 9}

do_test where8-1.6 { 
  execsql_status { SELECT c FROM t1 WHERE a = 1 OR b = 'three' ORDER BY rowid }
} {I III 0 0}

do_test where8-1.7 { 
  execsql_status { SELECT c FROM t1 WHERE a = 1 OR b = 'three' ORDER BY a }
} {I III 0 1}

do_test where8-1.8 {
  # 18 searches. 9 on the index cursor and 9 on the table cursor.
  execsql_status2 { SELECT c FROM t1 WHERE a > 1 AND c LIKE 'I%' }
} {II III IV IX 0 0 18}

do_test where8-1.9 {
  execsql_status2 { SELECT c FROM t1 WHERE a >= 9 OR b <= 'eight' }
} {VIII IX X 0 0 6}

do_test where8-1.10 {
  execsql_status2 { 
    SELECT c FROM t1 WHERE (a >= 9 AND c != 'X') OR b <= 'eight' 
  }
} {VIII IX 0 0 7}

do_test where8-1.11 {
  execsql_status2 { 
    SELECT c FROM t1 WHERE (a >= 4 AND a <= 6) OR b = 'nine' 
  }
} {IV V VI IX 0 0 10}

do_test where8-1.12.1 {
  execsql_status2 { 
    SELECT c FROM t1 WHERE a IN(1, 2, 3) OR a = 5
  }
} {I II III V 0 0 14}

do_test where8-1.12.2 {
  execsql_status2 { 
    SELECT c FROM t1 WHERE +a IN(1, 2, 3) OR +a = 5
  }
} {I II III V 9 0 9}

do_test where8-1.13 {
  execsql_status2 {
    SELECT c FROM t1
    WHERE a = 2 OR b = 'three' OR a = 4 OR b = 'five' OR a = 6
    ORDER BY rowid
  }
} {II III IV V VI 0 0 15}
do_test where8-1.14 {
  execsql_status2 {
    SELECT c FROM t1
    WHERE 
      a = 2 OR b = 'three' OR a = 4 OR b = 'five' OR a = 6 OR
      b = 'seven' OR a = 8 OR b = 'nine' OR a = 10
    ORDER BY rowid
  }
} {II III IV V VI VII VIII IX X 0 0 26}

do_test where8-1.15 {
  execsql_status2 {
    SELECT c FROM t1 WHERE 
      a BETWEEN 2 AND 4 OR b = 'nine'
    ORDER BY rowid
  }
} {II III IV IX 0 0 10}



#--------------------------------------------------------------------------
# Tests where8-2.*: Virtual tables
# 

if 0 {
ifcapable vtab {
  # Register the 'echo' module used for testing virtual tables.
  #
  register_echo_module [sqlite3_connection_pointer db]

  do_test where8-2.1 {
    execsql {
      CREATE VIRTUAL TABLE e1 USING echo(t1);
      SELECT b FROM e1;
    }
  } {one two three four five six seven eight nine ten}

  do_test where8-2.2.1 {
    set echo_module ""
    execsql {
      SELECT c FROM e1 WHERE a=1 OR b='three';
    }
  } {I III}
  do_test where8-2.2.2 {
    set echo_module
  } {TODO: What should this be?}
}
}

#--------------------------------------------------------------------------
# Tests where8-3.*: Cases with multiple tables in the FROM clause.
# 
do_test where8-3.1 {
  execsql {
    CREATE TABLE t2(d, e, f);
    CREATE INDEX i3 ON t2(d);
    CREATE INDEX i4 ON t2(e);

    INSERT INTO t2 VALUES(1,  NULL,         'I');
    INSERT INTO t2 VALUES(2,  'four',       'IV');
    INSERT INTO t2 VALUES(3,  NULL,         'IX');
    INSERT INTO t2 VALUES(4,  'sixteen',    'XVI');
    INSERT INTO t2 VALUES(5,  NULL,         'XXV');
    INSERT INTO t2 VALUES(6,  'thirtysix',  'XXXVI');
    INSERT INTO t2 VALUES(7,  'fortynine',  'XLIX');
    INSERT INTO t2 VALUES(8,  'sixtyeight', 'LXIV');
    INSERT INTO t2 VALUES(9,  'eightyone',  'LXXXIX');
    INSERT INTO t2 VALUES(10, NULL,         'C');
  }
} {}

do_test where8-3.2 {
  execsql_status {
    SELECT a, d FROM t1, t2 WHERE b=e
  }
} {4 2 9 0}

do_test where8-3.3 {
  execsql_status {
    SELECT a, d FROM t1, t2 WHERE (a = 2 OR a = 3) AND d = 6
  }
} {2 6 3 6 0 0}

do_test where8-3.4 {
  execsql_status {
    SELECT a, d FROM t1, t2 WHERE (a = 2 OR a = 3) AND d = a
  }
} {2 2 3 3 0 0}

do_test where8-3.5 {
  execsql_status {
    SELECT a, d FROM t1, t2 WHERE (a = 2 OR a = 3) AND (d = a OR e = 'sixteen')
  }
} {2 2 2 4 3 3 3 4 0 0}

do_test where8-3.6 {
  # The first part of the WHERE clause in this query, (a=2 OR a=3) is
  # transformed into "a IN (2, 3)". This is why the sort is required.
  #
  execsql_status {
    SELECT a, d 
    FROM t1, t2 
    WHERE (a = 2 OR a = 3) AND (d = a OR e = 'sixteen')
    ORDER BY t1.rowid
  }
} {2 2 2 4 3 3 3 4 0 1}
do_test where8-3.7 {
  execsql_status {
    SELECT a, d 
    FROM t1, t2 
    WHERE a = 2 AND (d = a OR e = 'sixteen')
    ORDER BY t1.rowid
  }
} {2 2 2 4 0 0}
do_test where8-3.8 {
  execsql_status {
    SELECT a, d 
    FROM t1, t2 
    WHERE (a = 2 OR b = 'three') AND (d = a OR e = 'sixteen')
    ORDER BY t1.rowid
  }
} {2 2 2 4 3 3 3 4 0 0}

do_test where8-3.9 {
  # The "OR c = 'IX'" term forces a linear scan.
  execsql_status {
    SELECT a, d 
    FROM t1, t2 
    WHERE (a = 2 OR b = 'three' OR c = 'IX') AND (d = a OR e = 'sixteen')
    ORDER BY t1.rowid
  }
} {2 2 2 4 3 3 3 4 9 4 9 9 9 0}

do_test where8-3.10 {
  execsql_status {
    SELECT d FROM t2 WHERE e IS NULL OR e = 'four'
  }
} {1 2 3 5 10 0 0}

do_test where8-3.11 {
  execsql_status {
    SELECT a, d FROM t1, t2 WHERE (a=d OR b=e) AND a<5 ORDER BY a
  }
} {1 1 2 2 3 3 4 2 4 4 0 0}
do_test where8-3.12 {
  execsql_status {
    SELECT a, d FROM t1, t2 WHERE (a=d OR b=e) AND +a<5 ORDER BY a
  }
} {1 1 2 2 3 3 4 2 4 4 0 0}
do_test where8-3.13 {
  execsql_status {
    SELECT a, d FROM t1, t2 WHERE (a=d OR b=e) AND +a<5
  }
} {1 1 2 2 3 3 4 2 4 4 9 0}

do_test where8-3.14 {
  execsql_status {
    SELECT c FROM t1 WHERE a > (SELECT d FROM t2 WHERE e = b) OR a = 5
  }
} {IV V 9 0}

do_test where8-3.15 {
  execsql_status {
    SELECT c FROM t1, t2 WHERE a BETWEEN 1 AND 2 OR a = (
      SELECT sum(e IS NULL) FROM t2 AS inner WHERE t2.d>inner.d
    )
  }
} {I I I I I I I I I I II II II II II II II II II II III III III III III 99 0}

#-----------------------------------------------------------------------
# The following tests - where8-4.* - verify that adding or removing 
# indexes does not change the results returned by various queries.
#
do_test where8-4.1 {
  execsql {
    CREATE TABLE t3(a INTEGER, b REAL, c TEXT);
    CREATE TABLE t4(f INTEGER, g REAL, h TEXT);
  }
} {}

finish_test

