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