Annotation of embedaddon/sqlite3/test/e_select2.test, revision 1.1

1.1     ! misho       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-46122-14930 If the join-op is "CROSS JOIN", "INNER
        !           348:   # JOIN", "JOIN" or a comma (",") and there is no ON or USING clause,
        !           349:   # then the result of the join is simply the cartesian product of the
        !           350:   # 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-07544-24155 The "CROSS JOIN" join operator produces the
        !           356:   # same data 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-22775-56496 If there is an ON clause specified, then
        !           372:   # the ON expression is evaluated for each row of the cartesian product
        !           373:   # as a boolean expression. All rows for which the expression evaluates
        !           374:   # to false are excluded 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-55824-40976 A sub-select specified in the join-source
        !           508: # following the FROM clause in a simple SELECT statement is handled as
        !           509: # if it was a table containing the data returned by executing the
        !           510: # sub-select statement.
        !           511: #
        !           512: # EVIDENCE-OF: R-42612-06757 Each column of the sub-select dataset
        !           513: # inherits the collation sequence and affinity of the corresponding
        !           514: # expression in the sub-select 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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>