1
0

e_select2.test 19 KB

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