gitlab.com/CoiaPrant/sqlite3@v1.19.1/testdata/tcl/e_select2.test (about)

     1  # 2010 September 24
     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  # This file implements tests to verify that the "testable statements" in 
    13  # the lang_select.html document are correct.
    14  #
    15  
    16  set testdir [file dirname $argv0]
    17  source $testdir/tester.tcl
    18  
    19  #-------------------------------------------------------------------------
    20  # te_* commands:
    21  #
    22  #
    23  #   te_read_sql DB SELECT-STATEMENT
    24  #   te_read_tbl DB TABLENAME
    25  #
    26  # These two commands are used to read a dataset from the database. A dataset
    27  # consists of N rows of M named columns of values each, where each value has a
    28  # type (null, integer, real, text or blob) and a value within the types domain.
    29  # The tcl format for a "dataset" is a list of two elements:
    30  #
    31  #   * A list of the column names.
    32  #   * A list of data rows. Each row is itself a list, where each element is
    33  #     the contents of a column of the row. Each of these is a list of two
    34  #     elements, the type name and the actual value.
    35  #
    36  # For example, the contents of table [t1] as a dataset is:
    37  #
    38  #   CREATE TABLE t1(a, b);
    39  #   INSERT INTO t1 VALUES('abc', NULL);
    40  #   INSERT INTO t1 VALUES(43.1, 22);
    41  #
    42  #   {a b} {{{TEXT abc} {NULL {}}} {{REAL 43.1} {INTEGER 22}}}
    43  #
    44  # The [te_read_tbl] command returns a dataset read from a table. The
    45  # [te_read_sql] returns the dataset that results from executing a SELECT
    46  # command.
    47  #
    48  #
    49  #   te_tbljoin ?SWITCHES? LHS-TABLE RHS-TABLE
    50  #   te_join ?SWITCHES? LHS-DATASET RHS-DATASET
    51  #
    52  # This command joins the two datasets and returns the resulting dataset. If 
    53  # there are no switches specified, then the results is the cartesian product
    54  # of the two inputs.  The [te_tbljoin] command reads the left and right-hand
    55  # datasets from the specified tables. The [te_join] command is passed the
    56  # datasets directly.
    57  #
    58  # Optional switches are as follows:
    59  #
    60  #   -on SCRIPT
    61  #   -using COLUMN-LIST
    62  #   -left
    63  #
    64  # The -on option specifies a tcl script that is executed for each row in the
    65  # cartesian product of the two datasets. The script has 4 arguments appended
    66  # to it, in the following order:
    67  #
    68  #   * The list of column-names from the left-hand dataset.
    69  #   * A single row from the left-hand dataset (one "data row" list as 
    70  #     described above.
    71  #   * The list of column-names from the right-hand dataset.
    72  #   * A single row from the right-hand dataset.
    73  #
    74  # The script must return a boolean value - true if the combination of rows
    75  # should be included in the output dataset, or false otherwise.
    76  #
    77  # The -using option specifies a list of the columns from the right-hand
    78  # dataset that should be omitted from the output dataset.
    79  #
    80  # If the -left option is present, the join is done LEFT JOIN style. 
    81  # Specifically, an extra row is inserted if after the -on script is run there
    82  # exist rows in the left-hand dataset that have no corresponding rows in
    83  # the output. See the implementation for more specific comments.
    84  #
    85  #
    86  #   te_equals ?SWITCHES? COLNAME1 COLNAME2 <-on script args>
    87  #
    88  # The only supported switch is "-nocase". If it is present, then text values
    89  # are compared in a case-independent fashion. Otherwise, they are compared
    90  # as if using the SQLite BINARY collation sequence.
    91  #
    92  #
    93  #   te_and ONSCRIPT1 ONSCRIPT2...
    94  #
    95  #
    96  
    97  
    98  #
    99  #   te_read_tbl DB TABLENAME
   100  #   te_read_sql DB SELECT-STATEMENT
   101  #
   102  # These two procs are used to extract datasets from the database, either
   103  # by reading the contents of a named table (te_read_tbl), or by executing
   104  # a SELECT statement (t3_read_sql).  
   105  #
   106  # See the comment above, describing "te_* commands", for details of the
   107  # return values.
   108  #
   109  proc te_read_tbl {db tbl} {
   110   te_read_sql $db "SELECT * FROM '$tbl'"
   111  }
   112  proc te_read_sql {db sql} {
   113    set S [sqlite3_prepare_v2 $db $sql -1 DUMMY]
   114  
   115    set cols [list]
   116    for {set i 0} {$i < [sqlite3_column_count $S]} {incr i} {
   117      lappend cols [sqlite3_column_name $S $i]
   118    }
   119  
   120    set rows [list]
   121    while {[sqlite3_step $S] == "SQLITE_ROW"} {
   122      set r [list]
   123      for {set i 0} {$i < [sqlite3_column_count $S]} {incr i} {
   124        lappend r [list [sqlite3_column_type $S $i] [sqlite3_column_text $S $i]]
   125      }
   126      lappend rows $r
   127    }
   128    sqlite3_finalize $S
   129  
   130    return [list $cols $rows]
   131  }
   132  
   133  #-------
   134  # Usage:   te_join <table-data1> <table-data2> <join spec>...
   135  #
   136  # Where a join-spec is an optional list of arguments as follows:
   137  #
   138  #   ?-left?
   139  #   ?-using colname-list?
   140  #   ?-on on-expr-proc?
   141  #
   142  proc te_join {data1 data2 args} {
   143  
   144    set testproc ""
   145    set usinglist [list]
   146    set isleft 0
   147    for {set i 0} {$i < [llength $args]} {incr i} {
   148      set a [lindex $args $i]
   149      switch -- $a {
   150        -on     { set testproc [lindex $args [incr i]] }
   151        -using  { set usinglist [lindex $args [incr i]] }
   152        -left   { set isleft 1 }
   153        default {
   154          error "Unknown argument: $a"
   155        }
   156      }
   157    }
   158  
   159    set c1 [lindex $data1 0]
   160    set c2 [lindex $data2 0]
   161    set omitlist [list]
   162    set nullrowlist [list]
   163    set cret $c1
   164  
   165    set cidx 0
   166    foreach col $c2 {
   167      set idx [lsearch $usinglist $col]
   168      if {$idx>=0} {lappend omitlist $cidx}
   169      if {$idx<0} {
   170        lappend nullrowlist {NULL {}}
   171        lappend cret $col
   172      }
   173      incr cidx
   174    }
   175    set omitlist [lsort -integer -decreasing $omitlist]
   176  
   177  
   178    set rret [list]
   179    foreach r1 [lindex $data1 1] {
   180      set one 0
   181      foreach r2 [lindex $data2 1] {
   182        set ok 1
   183        if {$testproc != ""} {
   184          set ok [eval $testproc [list $c1 $r1 $c2 $r2]]
   185        }
   186        if {$ok} {
   187          set one 1
   188          foreach idx $omitlist {set r2 [lreplace $r2 $idx $idx]}
   189          lappend rret [concat $r1 $r2]
   190        }
   191      }
   192  
   193      if {$isleft && $one==0} {
   194        lappend rret [concat $r1 $nullrowlist]
   195      }
   196    }
   197    
   198    list $cret $rret
   199  }
   200  
   201  proc te_tbljoin {db t1 t2 args} {
   202    te_join [te_read_tbl $db $t1] [te_read_tbl $db $t2] {*}$args
   203  }
   204  
   205  proc te_apply_affinity {affinity typevar valvar} {
   206    upvar $typevar type
   207    upvar $valvar val
   208  
   209    switch -- $affinity {
   210      integer {
   211        if {[string is double $val]} { set type REAL }
   212        if {[string is wideinteger $val]} { set type INTEGER }
   213        if {$type == "REAL" && int($val)==$val} { 
   214          set type INTEGER 
   215          set val [expr {int($val)}]
   216        }
   217      }
   218      text {
   219        set type TEXT
   220      }
   221      none { }
   222  
   223      default { error "invalid affinity: $affinity" }
   224    }
   225  }
   226  
   227  #----------
   228  # te_equals ?SWITCHES? c1 c2 cols1 row1 cols2 row2
   229  #
   230  proc te_equals {args} {
   231  
   232    if {[llength $args]<6} {error "invalid arguments to te_equals"}
   233    foreach {c1 c2 cols1 row1 cols2 row2} [lrange $args end-5 end] break
   234  
   235    set nocase 0
   236    set affinity none
   237  
   238    for {set i 0} {$i < ([llength $args]-6)} {incr i} {
   239      set a [lindex $args $i]
   240      switch -- $a {
   241        -nocase {
   242          set nocase 1
   243        }
   244        -affinity {
   245          set affinity [string tolower [lindex $args [incr i]]]
   246        }
   247        default {
   248          error "invalid arguments to te_equals"
   249        }
   250      }
   251    }
   252  
   253    set idx2 [if {[string is integer $c2]} { set c2 } else { lsearch $cols2 $c2 }]
   254    set idx1 [if {[string is integer $c1]} { set c1 } else { lsearch $cols1 $c1 }]
   255  
   256    set t1 [lindex $row1 $idx1 0]
   257    set t2 [lindex $row2 $idx2 0]
   258    set v1 [lindex $row1 $idx1 1]
   259    set v2 [lindex $row2 $idx2 1]
   260  
   261    te_apply_affinity $affinity t1 v1
   262    te_apply_affinity $affinity t2 v2
   263  
   264    if {$t1 == "NULL" || $t2 == "NULL"} { return 0 }
   265    if {$nocase && $t1 == "TEXT"} { set v1 [string tolower $v1] }
   266    if {$nocase && $t2 == "TEXT"} { set v2 [string tolower $v2] }
   267  
   268  
   269    set res [expr {$t1 == $t2 && [string equal $v1 $v2]}]
   270    return $res
   271  }
   272  
   273  proc te_false {args} { return 0 }
   274  proc te_true  {args} { return 1 }
   275  
   276  proc te_and {args} {
   277    foreach a [lrange $args 0 end-4] {
   278      set res [eval $a [lrange $args end-3 end]]
   279      if {$res == 0} {return 0}
   280    }
   281    return 1
   282  }
   283  
   284  
   285  proc te_dataset_eq {testname got expected} {
   286    uplevel #0 [list do_test $testname [list set {} $got] $expected]
   287  }
   288  proc te_dataset_eq_unordered {testname got expected} {
   289    lset got      1 [lsort [lindex $got 1]]
   290    lset expected 1 [lsort [lindex $expected 1]]
   291    te_dataset_eq $testname $got $expected
   292  }
   293  
   294  proc te_dataset_ne {testname got unexpected} {
   295    uplevel #0 [list do_test $testname [list string equal $got $unexpected] 0]
   296  }
   297  proc te_dataset_ne_unordered {testname got unexpected} {
   298    lset got      1 [lsort [lindex $got 1]]
   299    lset unexpected 1 [lsort [lindex $unexpected 1]]
   300    te_dataset_ne $testname $got $unexpected
   301  }
   302  
   303  
   304  #-------------------------------------------------------------------------
   305  #
   306  proc test_join {tn sqljoin tbljoinargs} {
   307    set sql [te_read_sql db "SELECT * FROM $sqljoin"]
   308    set te  [te_tbljoin db {*}$tbljoinargs]
   309    te_dataset_eq_unordered $tn $sql $te
   310  }
   311  
   312  drop_all_tables
   313  do_execsql_test e_select-2.0 {
   314    CREATE TABLE t1(a, b);
   315    CREATE TABLE t2(a, b);
   316    CREATE TABLE t3(b COLLATE nocase);
   317  
   318    INSERT INTO t1 VALUES(2, 'B');
   319    INSERT INTO t1 VALUES(1, 'A');
   320    INSERT INTO t1 VALUES(4, 'D');
   321    INSERT INTO t1 VALUES(NULL, NULL);
   322    INSERT INTO t1 VALUES(3, NULL);
   323  
   324    INSERT INTO t2 VALUES(1, 'A');
   325    INSERT INTO t2 VALUES(2, NULL);
   326    INSERT INTO t2 VALUES(5, 'E');
   327    INSERT INTO t2 VALUES(NULL, NULL);
   328    INSERT INTO t2 VALUES(3, 'C');
   329  
   330    INSERT INTO t3 VALUES('a');
   331    INSERT INTO t3 VALUES('c');
   332    INSERT INTO t3 VALUES('b');
   333  } {}
   334  
   335  foreach {tn indexes} {
   336    e_select-2.1.1 { }
   337    e_select-2.1.2 { CREATE INDEX i1 ON t1(a) }
   338    e_select-2.1.3 { CREATE INDEX i1 ON t2(a) }
   339    e_select-2.1.4 { CREATE INDEX i1 ON t3(b) }
   340  } {
   341  
   342    catchsql { DROP INDEX i1 }
   343    catchsql { DROP INDEX i2 }
   344    catchsql { DROP INDEX i3 }
   345    execsql $indexes
   346  
   347    # EVIDENCE-OF: R-49872-03192 If the join-operator is "CROSS JOIN",
   348    # "INNER JOIN", "JOIN" or a comma (",") and there is no ON or USING
   349    # clause, then the result of the join is simply the cartesian product of
   350    # the left and right-hand datasets.
   351    #
   352    # EVIDENCE-OF: R-46256-57243 There is no difference between the "INNER
   353    # JOIN", "JOIN" and "," join operators.
   354    #
   355    # EVIDENCE-OF: R-25071-21202 The "CROSS JOIN" join operator produces the
   356    # same result as the "INNER JOIN", "JOIN" and "," operators
   357    #
   358    test_join $tn.1.1  "t1, t2"                {t1 t2}
   359    test_join $tn.1.2  "t1 INNER JOIN t2"      {t1 t2}
   360    test_join $tn.1.3  "t1 CROSS JOIN t2"      {t1 t2}
   361    test_join $tn.1.4  "t1 JOIN t2"            {t1 t2}
   362    test_join $tn.1.5  "t2, t3"                {t2 t3}
   363    test_join $tn.1.6  "t2 INNER JOIN t3"      {t2 t3}
   364    test_join $tn.1.7  "t2 CROSS JOIN t3"      {t2 t3}
   365    test_join $tn.1.8  "t2 JOIN t3"            {t2 t3}
   366    test_join $tn.1.9  "t2, t2 AS x"           {t2 t2}
   367    test_join $tn.1.10 "t2 INNER JOIN t2 AS x" {t2 t2}
   368    test_join $tn.1.11 "t2 CROSS JOIN t2 AS x" {t2 t2}
   369    test_join $tn.1.12 "t2 JOIN t2 AS x"       {t2 t2}
   370  
   371    # EVIDENCE-OF: R-38465-03616 If there is an ON clause then the ON
   372    # expression is evaluated for each row of the cartesian product as a
   373    # boolean expression. Only rows for which the expression evaluates to
   374    # true are included from the dataset.
   375    #
   376    test_join $tn.2.1  "t1, t2 ON (t1.a=t2.a)"  {t1 t2 -on {te_equals a a}}
   377    test_join $tn.2.2  "t2, t1 ON (t1.a=t2.a)"  {t2 t1 -on {te_equals a a}}
   378    test_join $tn.2.3  "t2, t1 ON (1)"          {t2 t1 -on te_true}
   379    test_join $tn.2.4  "t2, t1 ON (NULL)"       {t2 t1 -on te_false}
   380    test_join $tn.2.5  "t2, t1 ON (1.1-1.1)"    {t2 t1 -on te_false}
   381    test_join $tn.2.6  "t1, t2 ON (1.1-1.0)"    {t1 t2 -on te_true}
   382  
   383  
   384    test_join $tn.3 "t1 LEFT JOIN t2 ON (t1.a=t2.a)" {t1 t2 -left -on {te_equals a a}}
   385    test_join $tn.4 "t1 LEFT JOIN t2 USING (a)" {
   386      t1 t2 -left -using a -on {te_equals a a}
   387    }
   388    test_join $tn.5 "t1 CROSS JOIN t2 USING(b, a)" {
   389      t1 t2 -using {a b} -on {te_and {te_equals a a} {te_equals b b}}
   390    }
   391    test_join $tn.6 "t1 NATURAL JOIN t2" {
   392      t1 t2 -using {a b} -on {te_and {te_equals a a} {te_equals b b}}
   393    }
   394    test_join $tn.7 "t1 NATURAL INNER JOIN t2" {
   395      t1 t2 -using {a b} -on {te_and {te_equals a a} {te_equals b b}}
   396    }
   397    test_join $tn.8 "t1 NATURAL CROSS JOIN t2" {
   398      t1 t2 -using {a b} -on {te_and {te_equals a a} {te_equals b b}}
   399    }
   400    test_join $tn.9 "t1 NATURAL INNER JOIN t2" {
   401      t1 t2 -using {a b} -on {te_and {te_equals a a} {te_equals b b}}
   402    }
   403    test_join $tn.10 "t1 NATURAL LEFT JOIN t2" {
   404      t1 t2 -left -using {a b} -on {te_and {te_equals a a} {te_equals b b}}
   405    }
   406    test_join $tn.11 "t1 NATURAL LEFT OUTER JOIN t2" {
   407      t1 t2 -left -using {a b} -on {te_and {te_equals a a} {te_equals b b}}
   408    }
   409    test_join $tn.12 "t2 NATURAL JOIN t1" {
   410      t2 t1 -using {a b} -on {te_and {te_equals a a} {te_equals b b}}
   411    }
   412    test_join $tn.13 "t2 NATURAL INNER JOIN t1" {
   413      t2 t1 -using {a b} -on {te_and {te_equals a a} {te_equals b b}}
   414    }
   415    test_join $tn.14 "t2 NATURAL CROSS JOIN t1" {
   416      t2 t1 -using {a b} -on {te_and {te_equals a a} {te_equals b b}}
   417    }
   418    test_join $tn.15 "t2 NATURAL INNER JOIN t1" {
   419      t2 t1 -using {a b} -on {te_and {te_equals a a} {te_equals b b}}
   420    }
   421    test_join $tn.16 "t2 NATURAL LEFT JOIN t1" {
   422      t2 t1 -left -using {a b} -on {te_and {te_equals a a} {te_equals b b}}
   423    }
   424    test_join $tn.17 "t2 NATURAL LEFT OUTER JOIN t1" {
   425      t2 t1 -left -using {a b} -on {te_and {te_equals a a} {te_equals b b}}
   426    }
   427    test_join $tn.18 "t1 LEFT JOIN t2 USING (b)" {
   428      t1 t2 -left -using b -on {te_equals b b}
   429    }
   430    test_join $tn.19 "t1 JOIN t3 USING(b)" {t1 t3 -using b -on {te_equals b b}}
   431    test_join $tn.20 "t3 JOIN t1 USING(b)" {
   432      t3 t1 -using b -on {te_equals -nocase b b}
   433    }
   434    test_join $tn.21 "t1 NATURAL JOIN t3"  {
   435      t1 t3 -using b -on {te_equals b b}
   436    }
   437    test_join $tn.22 "t3 NATURAL JOIN t1"  {
   438      t3 t1 -using b -on {te_equals -nocase b b}
   439    }
   440    test_join $tn.23 "t1 NATURAL LEFT JOIN t3" {
   441      t1 t3 -left -using b -on {te_equals b b}
   442    }
   443    test_join $tn.24 "t3 NATURAL LEFT JOIN t1" {
   444      t3 t1 -left -using b -on {te_equals -nocase b b}
   445    }
   446    test_join $tn.25 "t1 LEFT JOIN t3 ON (t3.b=t1.b)" {
   447      t1 t3 -left -on {te_equals -nocase b b}
   448    }
   449    test_join $tn.26 "t1 LEFT JOIN t3 ON (t1.b=t3.b)" {
   450      t1 t3 -left -on {te_equals b b}
   451    }
   452    test_join $tn.27 "t1 JOIN t3 ON (t1.b=t3.b)" { t1 t3 -on {te_equals b b} }
   453  
   454    # EVIDENCE-OF: R-28760-53843 When more than two tables are joined
   455    # together as part of a FROM clause, the join operations are processed
   456    # in order from left to right. In other words, the FROM clause (A
   457    # join-op-1 B join-op-2 C) is computed as ((A join-op-1 B) join-op-2 C).
   458    #
   459    #   Tests 28a and 28b show that the statement above is true for this case.
   460    #   Test 28c shows that if the parenthesis force a different order of
   461    #   evaluation the result is different. Test 28d verifies that the result
   462    #   of the query with the parenthesis forcing a different order of evaluation
   463    #   is as calculated by the [te_*] procs.
   464    #
   465    set t3_natural_left_join_t2 [
   466      te_tbljoin db t3 t2 -left -using {b} -on {te_equals -nocase b b}
   467    ]
   468    set t1 [te_read_tbl db t1]
   469    te_dataset_eq_unordered $tn.28a [
   470      te_read_sql db "SELECT * FROM t3 NATURAL LEFT JOIN t2 NATURAL JOIN t1"
   471    ] [te_join $t3_natural_left_join_t2 $t1                                \
   472        -using {a b} -on {te_and {te_equals a a} {te_equals -nocase b b}}  \
   473    ]
   474  
   475    te_dataset_eq_unordered $tn.28b [
   476      te_read_sql db "SELECT * FROM (t3 NATURAL LEFT JOIN t2) NATURAL JOIN t1"
   477    ] [te_join $t3_natural_left_join_t2 $t1                                \
   478        -using {a b} -on {te_and {te_equals a a} {te_equals -nocase b b}}  \
   479    ]
   480  
   481    te_dataset_ne_unordered $tn.28c [
   482      te_read_sql db "SELECT * FROM (t3 NATURAL LEFT JOIN t2) NATURAL JOIN t1"
   483    ] [
   484      te_read_sql db "SELECT * FROM t3 NATURAL LEFT JOIN (t2 NATURAL JOIN t1)"
   485    ]
   486  
   487    set t2_natural_join_t1 [te_tbljoin db t2 t1 -using {a b}                 \
   488          -using {a b} -on {te_and {te_equals a a} {te_equals -nocase b b}}  \
   489    ]
   490    set t3 [te_read_tbl db t3]
   491    te_dataset_eq_unordered $tn.28d [
   492      te_read_sql db "SELECT * FROM t3 NATURAL LEFT JOIN (t2 NATURAL JOIN t1)"
   493    ] [te_join $t3 $t2_natural_join_t1                                       \
   494        -left -using {b} -on {te_equals -nocase b b}                         \
   495    ]
   496  }
   497  
   498  do_execsql_test e_select-2.2.0 {
   499    CREATE TABLE t4(x TEXT COLLATE nocase);
   500    CREATE TABLE t5(y INTEGER, z TEXT COLLATE binary);
   501  
   502    INSERT INTO t4 VALUES('2.0');
   503    INSERT INTO t4 VALUES('TWO');
   504    INSERT INTO t5 VALUES(2, 'two');
   505  } {}
   506  
   507  # EVIDENCE-OF: R-59237-46742 A subquery specified in the
   508  # table-or-subquery following the FROM clause in a simple SELECT
   509  # statement is handled as if it was a table containing the data returned
   510  # by executing the subquery statement.
   511  #
   512  # EVIDENCE-OF: R-27438-53558 Each column of the subquery has the
   513  # collation sequence and affinity of the corresponding expression in the
   514  # subquery statement.
   515  #
   516  foreach {tn subselect select spec} {
   517    1   "SELECT * FROM t2"   "SELECT * FROM t1 JOIN %ss%" 
   518        {t1 %ss%}
   519  
   520    2   "SELECT * FROM t2"   "SELECT * FROM t1 JOIN %ss% AS x ON (t1.a=x.a)" 
   521        {t1 %ss% -on {te_equals 0 0}}
   522  
   523    3   "SELECT * FROM t2"   "SELECT * FROM %ss% AS x JOIN t1 ON (t1.a=x.a)" 
   524        {%ss% t1 -on {te_equals 0 0}}
   525  
   526    4   "SELECT * FROM t1, t2" "SELECT * FROM %ss% AS x JOIN t3"
   527        {%ss% t3}
   528  
   529    5   "SELECT * FROM t1, t2" "SELECT * FROM %ss% NATURAL JOIN t3"
   530        {%ss% t3 -using b -on {te_equals 1 0}}
   531  
   532    6   "SELECT * FROM t1, t2" "SELECT * FROM t3 NATURAL JOIN %ss%"
   533        {t3 %ss% -using b -on {te_equals -nocase 0 1}}
   534  
   535    7   "SELECT * FROM t1, t2" "SELECT * FROM t3 NATURAL LEFT JOIN %ss%"
   536        {t3 %ss% -left -using b -on {te_equals -nocase 0 1}}
   537  
   538    8   "SELECT count(*) AS y FROM t4"   "SELECT * FROM t5, %ss% USING (y)"
   539        {t5 %ss% -using y -on {te_equals -affinity text 0 0}}
   540  
   541    9   "SELECT count(*) AS y FROM t4"   "SELECT * FROM %ss%, t5 USING (y)"
   542        {%ss% t5 -using y -on {te_equals -affinity text 0 0}}
   543  
   544    10  "SELECT x AS y FROM t4"   "SELECT * FROM %ss% JOIN t5 USING (y)"
   545        {%ss% t5 -using y -on {te_equals -nocase -affinity integer 0 0}}
   546  
   547    11  "SELECT x AS y FROM t4"   "SELECT * FROM t5 JOIN %ss% USING (y)"
   548        {t5 %ss% -using y -on {te_equals -nocase -affinity integer 0 0}}
   549  
   550    12  "SELECT y AS x FROM t5"   "SELECT * FROM %ss% JOIN t4 USING (x)"
   551        {%ss% t4 -using x -on {te_equals -nocase -affinity integer 0 0}}
   552  
   553    13  "SELECT y AS x FROM t5"   "SELECT * FROM t4 JOIN %ss% USING (x)"
   554        {t4 %ss% -using x -on {te_equals -nocase -affinity integer 0 0}}
   555  
   556    14  "SELECT +y AS x FROM t5"   "SELECT * FROM %ss% JOIN t4 USING (x)"
   557        {%ss% t4 -using x -on {te_equals -nocase -affinity text 0 0}}
   558  
   559    15  "SELECT +y AS x FROM t5"   "SELECT * FROM t4 JOIN %ss% USING (x)"
   560        {t4 %ss% -using x -on {te_equals -nocase -affinity text 0 0}}
   561  } {
   562  
   563    # Create a temporary table named %ss% containing the data returned by
   564    # the sub-select. Then have the [te_tbljoin] proc use this table to
   565    # compute the expected results of the $select query. Drop the temporary
   566    # table before continuing.
   567    #
   568    execsql "CREATE TEMP TABLE '%ss%' AS $subselect"
   569    set te [eval te_tbljoin db $spec]
   570    execsql "DROP TABLE '%ss%'"
   571  
   572    # Check that the actual data returned by the $select query is the same
   573    # as the expected data calculated using [te_tbljoin] above.
   574    #
   575    te_dataset_eq_unordered e_select-2.2.1.$tn [
   576      te_read_sql db [string map [list %ss% "($subselect)"] $select]
   577    ] $te
   578  }
   579  
   580  finish_test