000001 # 2010 September 24
000002 #
000003 # The author disclaims copyright to this source code. In place of
000004 # a legal notice, here is a blessing:
000005 #
000006 # May you do good and not evil.
000007 # May you find forgiveness for yourself and forgive others.
000008 # May you share freely, never taking more than you give.
000009 #
000010 #***********************************************************************
000011 #
000012 # This file implements tests to verify that the "testable statements" in
000013 # the lang_select.html document are correct.
000014 #
000015
000016 set testdir [file dirname $argv0]
000017 source $testdir/tester.tcl
000018
000019 #-------------------------------------------------------------------------
000020 # te_* commands:
000021 #
000022 #
000023 # te_read_sql DB SELECT-STATEMENT
000024 # te_read_tbl DB TABLENAME
000025 #
000026 # These two commands are used to read a dataset from the database. A dataset
000027 # consists of N rows of M named columns of values each, where each value has a
000028 # type (null, integer, real, text or blob) and a value within the types domain.
000029 # The tcl format for a "dataset" is a list of two elements:
000030 #
000031 # * A list of the column names.
000032 # * A list of data rows. Each row is itself a list, where each element is
000033 # the contents of a column of the row. Each of these is a list of two
000034 # elements, the type name and the actual value.
000035 #
000036 # For example, the contents of table [t1] as a dataset is:
000037 #
000038 # CREATE TABLE t1(a, b);
000039 # INSERT INTO t1 VALUES('abc', NULL);
000040 # INSERT INTO t1 VALUES(43.1, 22);
000041 #
000042 # {a b} {{{TEXT abc} {NULL {}}} {{REAL 43.1} {INTEGER 22}}}
000043 #
000044 # The [te_read_tbl] command returns a dataset read from a table. The
000045 # [te_read_sql] returns the dataset that results from executing a SELECT
000046 # command.
000047 #
000048 #
000049 # te_tbljoin ?SWITCHES? LHS-TABLE RHS-TABLE
000050 # te_join ?SWITCHES? LHS-DATASET RHS-DATASET
000051 #
000052 # This command joins the two datasets and returns the resulting dataset. If
000053 # there are no switches specified, then the results is the cartesian product
000054 # of the two inputs. The [te_tbljoin] command reads the left and right-hand
000055 # datasets from the specified tables. The [te_join] command is passed the
000056 # datasets directly.
000057 #
000058 # Optional switches are as follows:
000059 #
000060 # -on SCRIPT
000061 # -using COLUMN-LIST
000062 # -left
000063 #
000064 # The -on option specifies a tcl script that is executed for each row in the
000065 # cartesian product of the two datasets. The script has 4 arguments appended
000066 # to it, in the following order:
000067 #
000068 # * The list of column-names from the left-hand dataset.
000069 # * A single row from the left-hand dataset (one "data row" list as
000070 # described above.
000071 # * The list of column-names from the right-hand dataset.
000072 # * A single row from the right-hand dataset.
000073 #
000074 # The script must return a boolean value - true if the combination of rows
000075 # should be included in the output dataset, or false otherwise.
000076 #
000077 # The -using option specifies a list of the columns from the right-hand
000078 # dataset that should be omitted from the output dataset.
000079 #
000080 # If the -left option is present, the join is done LEFT JOIN style.
000081 # Specifically, an extra row is inserted if after the -on script is run there
000082 # exist rows in the left-hand dataset that have no corresponding rows in
000083 # the output. See the implementation for more specific comments.
000084 #
000085 #
000086 # te_equals ?SWITCHES? COLNAME1 COLNAME2 <-on script args>
000087 #
000088 # The only supported switch is "-nocase". If it is present, then text values
000089 # are compared in a case-independent fashion. Otherwise, they are compared
000090 # as if using the SQLite BINARY collation sequence.
000091 #
000092 #
000093 # te_and ONSCRIPT1 ONSCRIPT2...
000094 #
000095 #
000096
000097
000098 #
000099 # te_read_tbl DB TABLENAME
000100 # te_read_sql DB SELECT-STATEMENT
000101 #
000102 # These two procs are used to extract datasets from the database, either
000103 # by reading the contents of a named table (te_read_tbl), or by executing
000104 # a SELECT statement (t3_read_sql).
000105 #
000106 # See the comment above, describing "te_* commands", for details of the
000107 # return values.
000108 #
000109 proc te_read_tbl {db tbl} {
000110 te_read_sql $db "SELECT * FROM '$tbl'"
000111 }
000112 proc te_read_sql {db sql} {
000113 set S [sqlite3_prepare_v2 $db $sql -1 DUMMY]
000114
000115 set cols [list]
000116 for {set i 0} {$i < [sqlite3_column_count $S]} {incr i} {
000117 lappend cols [sqlite3_column_name $S $i]
000118 }
000119
000120 set rows [list]
000121 while {[sqlite3_step $S] == "SQLITE_ROW"} {
000122 set r [list]
000123 for {set i 0} {$i < [sqlite3_column_count $S]} {incr i} {
000124 lappend r [list [sqlite3_column_type $S $i] [sqlite3_column_text $S $i]]
000125 }
000126 lappend rows $r
000127 }
000128 sqlite3_finalize $S
000129
000130 return [list $cols $rows]
000131 }
000132
000133 #-------
000134 # Usage: te_join <table-data1> <table-data2> <join spec>...
000135 #
000136 # Where a join-spec is an optional list of arguments as follows:
000137 #
000138 # ?-left?
000139 # ?-using colname-list?
000140 # ?-on on-expr-proc?
000141 #
000142 proc te_join {data1 data2 args} {
000143
000144 set testproc ""
000145 set usinglist [list]
000146 set isleft 0
000147 for {set i 0} {$i < [llength $args]} {incr i} {
000148 set a [lindex $args $i]
000149 switch -- $a {
000150 -on { set testproc [lindex $args [incr i]] }
000151 -using { set usinglist [lindex $args [incr i]] }
000152 -left { set isleft 1 }
000153 default {
000154 error "Unknown argument: $a"
000155 }
000156 }
000157 }
000158
000159 set c1 [lindex $data1 0]
000160 set c2 [lindex $data2 0]
000161 set omitlist [list]
000162 set nullrowlist [list]
000163 set cret $c1
000164
000165 set cidx 0
000166 foreach col $c2 {
000167 set idx [lsearch $usinglist $col]
000168 if {$idx>=0} {lappend omitlist $cidx}
000169 if {$idx<0} {
000170 lappend nullrowlist {NULL {}}
000171 lappend cret $col
000172 }
000173 incr cidx
000174 }
000175 set omitlist [lsort -integer -decreasing $omitlist]
000176
000177
000178 set rret [list]
000179 foreach r1 [lindex $data1 1] {
000180 set one 0
000181 foreach r2 [lindex $data2 1] {
000182 set ok 1
000183 if {$testproc != ""} {
000184 set ok [eval $testproc [list $c1 $r1 $c2 $r2]]
000185 }
000186 if {$ok} {
000187 set one 1
000188 foreach idx $omitlist {set r2 [lreplace $r2 $idx $idx]}
000189 lappend rret [concat $r1 $r2]
000190 }
000191 }
000192
000193 if {$isleft && $one==0} {
000194 lappend rret [concat $r1 $nullrowlist]
000195 }
000196 }
000197
000198 list $cret $rret
000199 }
000200
000201 proc te_tbljoin {db t1 t2 args} {
000202 te_join [te_read_tbl $db $t1] [te_read_tbl $db $t2] {*}$args
000203 }
000204
000205 proc te_apply_affinity {affinity typevar valvar} {
000206 upvar $typevar type
000207 upvar $valvar val
000208
000209 switch -- $affinity {
000210 integer {
000211 if {[string is double $val]} { set type REAL }
000212 if {[string is wideinteger $val]} { set type INTEGER }
000213 if {$type == "REAL" && int($val)==$val} {
000214 set type INTEGER
000215 set val [expr {int($val)}]
000216 }
000217 }
000218 text {
000219 set type TEXT
000220 }
000221 none { }
000222
000223 default { error "invalid affinity: $affinity" }
000224 }
000225 }
000226
000227 #----------
000228 # te_equals ?SWITCHES? c1 c2 cols1 row1 cols2 row2
000229 #
000230 proc te_equals {args} {
000231
000232 if {[llength $args]<6} {error "invalid arguments to te_equals"}
000233 foreach {c1 c2 cols1 row1 cols2 row2} [lrange $args end-5 end] break
000234
000235 set nocase 0
000236 set affinity none
000237
000238 for {set i 0} {$i < ([llength $args]-6)} {incr i} {
000239 set a [lindex $args $i]
000240 switch -- $a {
000241 -nocase {
000242 set nocase 1
000243 }
000244 -affinity {
000245 set affinity [string tolower [lindex $args [incr i]]]
000246 }
000247 default {
000248 error "invalid arguments to te_equals"
000249 }
000250 }
000251 }
000252
000253 set idx2 [if {[string is integer $c2]} { set c2 } else { lsearch $cols2 $c2 }]
000254 set idx1 [if {[string is integer $c1]} { set c1 } else { lsearch $cols1 $c1 }]
000255
000256 set t1 [lindex $row1 $idx1 0]
000257 set t2 [lindex $row2 $idx2 0]
000258 set v1 [lindex $row1 $idx1 1]
000259 set v2 [lindex $row2 $idx2 1]
000260
000261 te_apply_affinity $affinity t1 v1
000262 te_apply_affinity $affinity t2 v2
000263
000264 if {$t1 == "NULL" || $t2 == "NULL"} { return 0 }
000265 if {$nocase && $t1 == "TEXT"} { set v1 [string tolower $v1] }
000266 if {$nocase && $t2 == "TEXT"} { set v2 [string tolower $v2] }
000267
000268
000269 set res [expr {$t1 == $t2 && [string equal $v1 $v2]}]
000270 return $res
000271 }
000272
000273 proc te_false {args} { return 0 }
000274 proc te_true {args} { return 1 }
000275
000276 proc te_and {args} {
000277 foreach a [lrange $args 0 end-4] {
000278 set res [eval $a [lrange $args end-3 end]]
000279 if {$res == 0} {return 0}
000280 }
000281 return 1
000282 }
000283
000284
000285 proc te_dataset_eq {testname got expected} {
000286 uplevel #0 [list do_test $testname [list set {} $got] $expected]
000287 }
000288 proc te_dataset_eq_unordered {testname got expected} {
000289 lset got 1 [lsort [lindex $got 1]]
000290 lset expected 1 [lsort [lindex $expected 1]]
000291 te_dataset_eq $testname $got $expected
000292 }
000293
000294 proc te_dataset_ne {testname got unexpected} {
000295 uplevel #0 [list do_test $testname [list string equal $got $unexpected] 0]
000296 }
000297 proc te_dataset_ne_unordered {testname got unexpected} {
000298 lset got 1 [lsort [lindex $got 1]]
000299 lset unexpected 1 [lsort [lindex $unexpected 1]]
000300 te_dataset_ne $testname $got $unexpected
000301 }
000302
000303
000304 #-------------------------------------------------------------------------
000305 #
000306 proc test_join {tn sqljoin tbljoinargs} {
000307 set sql [te_read_sql db "SELECT * FROM $sqljoin"]
000308 set te [te_tbljoin db {*}$tbljoinargs]
000309 te_dataset_eq_unordered $tn $sql $te
000310 }
000311
000312 drop_all_tables
000313 do_execsql_test e_select-2.0 {
000314 CREATE TABLE t1(a, b);
000315 CREATE TABLE t2(a, b);
000316 CREATE TABLE t3(b COLLATE nocase);
000317
000318 INSERT INTO t1 VALUES(2, 'B');
000319 INSERT INTO t1 VALUES(1, 'A');
000320 INSERT INTO t1 VALUES(4, 'D');
000321 INSERT INTO t1 VALUES(NULL, NULL);
000322 INSERT INTO t1 VALUES(3, NULL);
000323
000324 INSERT INTO t2 VALUES(1, 'A');
000325 INSERT INTO t2 VALUES(2, NULL);
000326 INSERT INTO t2 VALUES(5, 'E');
000327 INSERT INTO t2 VALUES(NULL, NULL);
000328 INSERT INTO t2 VALUES(3, 'C');
000329
000330 INSERT INTO t3 VALUES('a');
000331 INSERT INTO t3 VALUES('c');
000332 INSERT INTO t3 VALUES('b');
000333 } {}
000334
000335 foreach {tn indexes} {
000336 e_select-2.1.1 { }
000337 e_select-2.1.2 { CREATE INDEX i1 ON t1(a) }
000338 e_select-2.1.3 { CREATE INDEX i1 ON t2(a) }
000339 e_select-2.1.4 { CREATE INDEX i1 ON t3(b) }
000340 } {
000341
000342 catchsql { DROP INDEX i1 }
000343 catchsql { DROP INDEX i2 }
000344 catchsql { DROP INDEX i3 }
000345 execsql $indexes
000346
000347 # EVIDENCE-OF: R-49872-03192 If the join-operator is "CROSS JOIN",
000348 # "INNER JOIN", "JOIN" or a comma (",") and there is no ON or USING
000349 # clause, then the result of the join is simply the cartesian product of
000350 # the left and right-hand datasets.
000351 #
000352 # EVIDENCE-OF: R-46256-57243 There is no difference between the "INNER
000353 # JOIN", "JOIN" and "," join operators.
000354 #
000355 # EVIDENCE-OF: R-25071-21202 The "CROSS JOIN" join operator produces the
000356 # same result as the "INNER JOIN", "JOIN" and "," operators
000357 #
000358 test_join $tn.1.1 "t1, t2" {t1 t2}
000359 test_join $tn.1.2 "t1 INNER JOIN t2" {t1 t2}
000360 test_join $tn.1.3 "t1 CROSS JOIN t2" {t1 t2}
000361 test_join $tn.1.4 "t1 JOIN t2" {t1 t2}
000362 test_join $tn.1.5 "t2, t3" {t2 t3}
000363 test_join $tn.1.6 "t2 INNER JOIN t3" {t2 t3}
000364 test_join $tn.1.7 "t2 CROSS JOIN t3" {t2 t3}
000365 test_join $tn.1.8 "t2 JOIN t3" {t2 t3}
000366 test_join $tn.1.9 "t2, t2 AS x" {t2 t2}
000367 test_join $tn.1.10 "t2 INNER JOIN t2 AS x" {t2 t2}
000368 test_join $tn.1.11 "t2 CROSS JOIN t2 AS x" {t2 t2}
000369 test_join $tn.1.12 "t2 JOIN t2 AS x" {t2 t2}
000370
000371 # EVIDENCE-OF: R-38465-03616 If there is an ON clause then the ON
000372 # expression is evaluated for each row of the cartesian product as a
000373 # boolean expression. Only rows for which the expression evaluates to
000374 # true are included from the dataset.
000375 #
000376 test_join $tn.2.1 "t1, t2 ON (t1.a=t2.a)" {t1 t2 -on {te_equals a a}}
000377 test_join $tn.2.2 "t2, t1 ON (t1.a=t2.a)" {t2 t1 -on {te_equals a a}}
000378 test_join $tn.2.3 "t2, t1 ON (1)" {t2 t1 -on te_true}
000379 test_join $tn.2.4 "t2, t1 ON (NULL)" {t2 t1 -on te_false}
000380 test_join $tn.2.5 "t2, t1 ON (1.1-1.1)" {t2 t1 -on te_false}
000381 test_join $tn.2.6 "t1, t2 ON (1.1-1.0)" {t1 t2 -on te_true}
000382
000383
000384 test_join $tn.3 "t1 LEFT JOIN t2 ON (t1.a=t2.a)" {t1 t2 -left -on {te_equals a a}}
000385 test_join $tn.4 "t1 LEFT JOIN t2 USING (a)" {
000386 t1 t2 -left -using a -on {te_equals a a}
000387 }
000388 test_join $tn.5 "t1 CROSS JOIN t2 USING(b, a)" {
000389 t1 t2 -using {a b} -on {te_and {te_equals a a} {te_equals b b}}
000390 }
000391 test_join $tn.6 "t1 NATURAL JOIN t2" {
000392 t1 t2 -using {a b} -on {te_and {te_equals a a} {te_equals b b}}
000393 }
000394 test_join $tn.7 "t1 NATURAL INNER JOIN t2" {
000395 t1 t2 -using {a b} -on {te_and {te_equals a a} {te_equals b b}}
000396 }
000397 test_join $tn.8 "t1 NATURAL CROSS JOIN t2" {
000398 t1 t2 -using {a b} -on {te_and {te_equals a a} {te_equals b b}}
000399 }
000400 test_join $tn.9 "t1 NATURAL INNER JOIN t2" {
000401 t1 t2 -using {a b} -on {te_and {te_equals a a} {te_equals b b}}
000402 }
000403 test_join $tn.10 "t1 NATURAL LEFT JOIN t2" {
000404 t1 t2 -left -using {a b} -on {te_and {te_equals a a} {te_equals b b}}
000405 }
000406 test_join $tn.11 "t1 NATURAL LEFT OUTER JOIN t2" {
000407 t1 t2 -left -using {a b} -on {te_and {te_equals a a} {te_equals b b}}
000408 }
000409 test_join $tn.12 "t2 NATURAL JOIN t1" {
000410 t2 t1 -using {a b} -on {te_and {te_equals a a} {te_equals b b}}
000411 }
000412 test_join $tn.13 "t2 NATURAL INNER JOIN t1" {
000413 t2 t1 -using {a b} -on {te_and {te_equals a a} {te_equals b b}}
000414 }
000415 test_join $tn.14 "t2 NATURAL CROSS JOIN t1" {
000416 t2 t1 -using {a b} -on {te_and {te_equals a a} {te_equals b b}}
000417 }
000418 test_join $tn.15 "t2 NATURAL INNER JOIN t1" {
000419 t2 t1 -using {a b} -on {te_and {te_equals a a} {te_equals b b}}
000420 }
000421 test_join $tn.16 "t2 NATURAL LEFT JOIN t1" {
000422 t2 t1 -left -using {a b} -on {te_and {te_equals a a} {te_equals b b}}
000423 }
000424 test_join $tn.17 "t2 NATURAL LEFT OUTER JOIN t1" {
000425 t2 t1 -left -using {a b} -on {te_and {te_equals a a} {te_equals b b}}
000426 }
000427 test_join $tn.18 "t1 LEFT JOIN t2 USING (b)" {
000428 t1 t2 -left -using b -on {te_equals b b}
000429 }
000430 test_join $tn.19 "t1 JOIN t3 USING(b)" {t1 t3 -using b -on {te_equals b b}}
000431 test_join $tn.20 "t3 JOIN t1 USING(b)" {
000432 t3 t1 -using b -on {te_equals -nocase b b}
000433 }
000434 test_join $tn.21 "t1 NATURAL JOIN t3" {
000435 t1 t3 -using b -on {te_equals b b}
000436 }
000437 test_join $tn.22 "t3 NATURAL JOIN t1" {
000438 t3 t1 -using b -on {te_equals -nocase b b}
000439 }
000440 test_join $tn.23 "t1 NATURAL LEFT JOIN t3" {
000441 t1 t3 -left -using b -on {te_equals b b}
000442 }
000443 test_join $tn.24 "t3 NATURAL LEFT JOIN t1" {
000444 t3 t1 -left -using b -on {te_equals -nocase b b}
000445 }
000446 test_join $tn.25 "t1 LEFT JOIN t3 ON (t3.b=t1.b)" {
000447 t1 t3 -left -on {te_equals -nocase b b}
000448 }
000449 test_join $tn.26 "t1 LEFT JOIN t3 ON (t1.b=t3.b)" {
000450 t1 t3 -left -on {te_equals b b}
000451 }
000452 test_join $tn.27 "t1 JOIN t3 ON (t1.b=t3.b)" { t1 t3 -on {te_equals b b} }
000453
000454 # EVIDENCE-OF: R-28760-53843 When more than two tables are joined
000455 # together as part of a FROM clause, the join operations are processed
000456 # in order from left to right. In other words, the FROM clause (A
000457 # join-op-1 B join-op-2 C) is computed as ((A join-op-1 B) join-op-2 C).
000458 #
000459 # Tests 28a and 28b show that the statement above is true for this case.
000460 # Test 28c shows that if the parenthesis force a different order of
000461 # evaluation the result is different. Test 28d verifies that the result
000462 # of the query with the parenthesis forcing a different order of evaluation
000463 # is as calculated by the [te_*] procs.
000464 #
000465 set t3_natural_left_join_t2 [
000466 te_tbljoin db t3 t2 -left -using {b} -on {te_equals -nocase b b}
000467 ]
000468 set t1 [te_read_tbl db t1]
000469 te_dataset_eq_unordered $tn.28a [
000470 te_read_sql db "SELECT * FROM t3 NATURAL LEFT JOIN t2 NATURAL JOIN t1"
000471 ] [te_join $t3_natural_left_join_t2 $t1 \
000472 -using {a b} -on {te_and {te_equals a a} {te_equals -nocase b b}} \
000473 ]
000474
000475 te_dataset_eq_unordered $tn.28b [
000476 te_read_sql db "SELECT * FROM (t3 NATURAL LEFT JOIN t2) NATURAL JOIN t1"
000477 ] [te_join $t3_natural_left_join_t2 $t1 \
000478 -using {a b} -on {te_and {te_equals a a} {te_equals -nocase b b}} \
000479 ]
000480
000481 te_dataset_ne_unordered $tn.28c [
000482 te_read_sql db "SELECT * FROM (t3 NATURAL LEFT JOIN t2) NATURAL JOIN t1"
000483 ] [
000484 te_read_sql db "SELECT * FROM t3 NATURAL LEFT JOIN (t2 NATURAL JOIN t1)"
000485 ]
000486
000487 set t2_natural_join_t1 [te_tbljoin db t2 t1 -using {a b} \
000488 -using {a b} -on {te_and {te_equals a a} {te_equals -nocase b b}} \
000489 ]
000490 set t3 [te_read_tbl db t3]
000491 te_dataset_eq_unordered $tn.28d [
000492 te_read_sql db "SELECT * FROM t3 NATURAL LEFT JOIN (t2 NATURAL JOIN t1)"
000493 ] [te_join $t3 $t2_natural_join_t1 \
000494 -left -using {b} -on {te_equals -nocase b b} \
000495 ]
000496 }
000497
000498 do_execsql_test e_select-2.2.0 {
000499 CREATE TABLE t4(x TEXT COLLATE nocase);
000500 CREATE TABLE t5(y INTEGER, z TEXT COLLATE binary);
000501
000502 INSERT INTO t4 VALUES('2.0');
000503 INSERT INTO t4 VALUES('TWO');
000504 INSERT INTO t5 VALUES(2, 'two');
000505 } {}
000506
000507 # EVIDENCE-OF: R-59237-46742 A subquery specified in the
000508 # table-or-subquery following the FROM clause in a simple SELECT
000509 # statement is handled as if it was a table containing the data returned
000510 # by executing the subquery statement.
000511 #
000512 # EVIDENCE-OF: R-27438-53558 Each column of the subquery has the
000513 # collation sequence and affinity of the corresponding expression in the
000514 # subquery statement.
000515 #
000516 foreach {tn subselect select spec} {
000517 1 "SELECT * FROM t2" "SELECT * FROM t1 JOIN %ss%"
000518 {t1 %ss%}
000519
000520 2 "SELECT * FROM t2" "SELECT * FROM t1 JOIN %ss% AS x ON (t1.a=x.a)"
000521 {t1 %ss% -on {te_equals 0 0}}
000522
000523 3 "SELECT * FROM t2" "SELECT * FROM %ss% AS x JOIN t1 ON (t1.a=x.a)"
000524 {%ss% t1 -on {te_equals 0 0}}
000525
000526 4 "SELECT * FROM t1, t2" "SELECT * FROM %ss% AS x JOIN t3"
000527 {%ss% t3}
000528
000529 5 "SELECT * FROM t1, t2" "SELECT * FROM %ss% NATURAL JOIN t3"
000530 {%ss% t3 -using b -on {te_equals 1 0}}
000531
000532 6 "SELECT * FROM t1, t2" "SELECT * FROM t3 NATURAL JOIN %ss%"
000533 {t3 %ss% -using b -on {te_equals -nocase 0 1}}
000534
000535 7 "SELECT * FROM t1, t2" "SELECT * FROM t3 NATURAL LEFT JOIN %ss%"
000536 {t3 %ss% -left -using b -on {te_equals -nocase 0 1}}
000537
000538 8 "SELECT count(*) AS y FROM t4" "SELECT * FROM t5, %ss% USING (y)"
000539 {t5 %ss% -using y -on {te_equals -affinity text 0 0}}
000540
000541 9 "SELECT count(*) AS y FROM t4" "SELECT * FROM %ss%, t5 USING (y)"
000542 {%ss% t5 -using y -on {te_equals -affinity text 0 0}}
000543
000544 10 "SELECT x AS y FROM t4" "SELECT * FROM %ss% JOIN t5 USING (y)"
000545 {%ss% t5 -using y -on {te_equals -nocase -affinity integer 0 0}}
000546
000547 11 "SELECT x AS y FROM t4" "SELECT * FROM t5 JOIN %ss% USING (y)"
000548 {t5 %ss% -using y -on {te_equals -nocase -affinity integer 0 0}}
000549
000550 12 "SELECT y AS x FROM t5" "SELECT * FROM %ss% JOIN t4 USING (x)"
000551 {%ss% t4 -using x -on {te_equals -nocase -affinity integer 0 0}}
000552
000553 13 "SELECT y AS x FROM t5" "SELECT * FROM t4 JOIN %ss% USING (x)"
000554 {t4 %ss% -using x -on {te_equals -nocase -affinity integer 0 0}}
000555
000556 14 "SELECT +y AS x FROM t5" "SELECT * FROM %ss% JOIN t4 USING (x)"
000557 {%ss% t4 -using x -on {te_equals -nocase -affinity text 0 0}}
000558
000559 15 "SELECT +y AS x FROM t5" "SELECT * FROM t4 JOIN %ss% USING (x)"
000560 {t4 %ss% -using x -on {te_equals -nocase -affinity text 0 0}}
000561 } {
000562
000563 # Create a temporary table named %ss% containing the data returned by
000564 # the sub-select. Then have the [te_tbljoin] proc use this table to
000565 # compute the expected results of the $select query. Drop the temporary
000566 # table before continuing.
000567 #
000568 execsql "CREATE TEMP TABLE '%ss%' AS $subselect"
000569 set te [eval te_tbljoin db $spec]
000570 execsql "DROP TABLE '%ss%'"
000571
000572 # Check that the actual data returned by the $select query is the same
000573 # as the expected data calculated using [te_tbljoin] above.
000574 #
000575 te_dataset_eq_unordered e_select-2.2.1.$tn [
000576 te_read_sql db [string map [list %ss% "($subselect)"] $select]
000577 ] $te
000578 }
000579
000580 finish_test