/ Check-in [a55842cf]
Login
SQLite training in Houston TX on 2019-11-05 (details)
Part of the 2019 Tcl Conference

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Move the test for an (illegal) scalar sub-query that returns more than one column to earlier in SELECT processing in order to avoid an assert() that can happen later on.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: a55842cfb56b659c88832dce9ce7bafb50258211
User & Date: dan 2010-09-02 19:01:16
Context
2010-09-03
03:32
Fix a discrepancy between the documented behavior of SQLITE_DBCONFIG_LOOKASIDE and what it actually does. Also add evidence marks on the DBCONFIG_LOOKASIDE implementation. check-in: f483be44 user: drh tags: trunk
2010-09-02
19:01
Move the test for an (illegal) scalar sub-query that returns more than one column to earlier in SELECT processing in order to avoid an assert() that can happen later on. check-in: a55842cf user: dan tags: trunk
18:13
Fix an off-by-one error in the scratch memory allocator. check-in: 5a959160 user: drh tags: trunk
Changes
Hide Diffs Unified Diffs Show Whitespace Changes Patch

Changes to src/select.c.

3621
3622
3623
3624
3625
3626
3627









3628
3629
3630
3631
3632
3633
3634
....
3693
3694
3695
3696
3697
3698
3699
3700
3701
3702
3703
3704
3705
3706
3707
3708
3709
3710
3711
3712
3713
3714
3715
  isAgg = (p->selFlags & SF_Aggregate)!=0;
  assert( pEList!=0 );

  /* Begin generating code.
  */
  v = sqlite3GetVdbe(pParse);
  if( v==0 ) goto select_end;










  /* Generate code for all sub-queries in the FROM clause
  */
#if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW)
  for(i=0; !p->pPrior && i<pTabList->nSrc; i++){
    struct SrcList_item *pItem = &pTabList->a[i];
    SelectDest dest;
................................................................................
      if( mxSelect && cnt>mxSelect ){
        sqlite3ErrorMsg(pParse, "too many terms in compound SELECT");
        return 1;
      }
    }
    return multiSelect(pParse, p, pDest);
  }
#endif

  /* If writing to memory or generating a set
  ** only a single column may be output.
  */
#ifndef SQLITE_OMIT_SUBQUERY
  if( checkForMultiColumnSelectError(pParse, pDest, pEList->nExpr) ){
    goto select_end;
  }
#endif

  /* If possible, rewrite the query to use GROUP BY instead of DISTINCT.
  ** GROUP BY might use an index, DISTINCT never does.
  */
  assert( p->pGroupBy==0 || (p->selFlags & SF_Aggregate)!=0 );
  if( (p->selFlags & (SF_Distinct|SF_Aggregate))==SF_Distinct ){







>
>
>
>
>
>
>
>
>







 







<
<
<
<
<
<
<
<
<







3621
3622
3623
3624
3625
3626
3627
3628
3629
3630
3631
3632
3633
3634
3635
3636
3637
3638
3639
3640
3641
3642
3643
....
3702
3703
3704
3705
3706
3707
3708









3709
3710
3711
3712
3713
3714
3715
  isAgg = (p->selFlags & SF_Aggregate)!=0;
  assert( pEList!=0 );

  /* Begin generating code.
  */
  v = sqlite3GetVdbe(pParse);
  if( v==0 ) goto select_end;

  /* If writing to memory or generating a set
  ** only a single column may be output.
  */
#ifndef SQLITE_OMIT_SUBQUERY
  if( checkForMultiColumnSelectError(pParse, pDest, pEList->nExpr) ){
    goto select_end;
  }
#endif

  /* Generate code for all sub-queries in the FROM clause
  */
#if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW)
  for(i=0; !p->pPrior && i<pTabList->nSrc; i++){
    struct SrcList_item *pItem = &pTabList->a[i];
    SelectDest dest;
................................................................................
      if( mxSelect && cnt>mxSelect ){
        sqlite3ErrorMsg(pParse, "too many terms in compound SELECT");
        return 1;
      }
    }
    return multiSelect(pParse, p, pDest);
  }









#endif

  /* If possible, rewrite the query to use GROUP BY instead of DISTINCT.
  ** GROUP BY might use an index, DISTINCT never does.
  */
  assert( p->pGroupBy==0 || (p->selFlags & SF_Aggregate)!=0 );
  if( (p->selFlags & (SF_Distinct|SF_Aggregate))==SF_Distinct ){

Changes to test/e_expr.test.

1725
1726
1727
1728
1729
1730
1731


1732
1733
1734
1735











1736


































1737
1738
1739
  2 { EXISTS (SELECT NULL FROM t1) }  { EXISTS (SELECT 'bread' FROM t1) }
} {
  set res [db one "SELECT $e1"]
  do_expr_test e_expr-34.5.${tn}a $e1 integer $res
  do_expr_test e_expr-34.5.${tn}b $e2 integer $res
}





#-------------------------------------------------------------------------
# Test statements related to the IN and NOT IN operators.











#



































finish_test








>
>
|

<
<
>
>
>
>
>
>
>
>
>
>
>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>



1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735


1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
  2 { EXISTS (SELECT NULL FROM t1) }  { EXISTS (SELECT 'bread' FROM t1) }
} {
  set res [db one "SELECT $e1"]
  do_expr_test e_expr-34.5.${tn}a $e1 integer $res
  do_expr_test e_expr-34.5.${tn}b $e2 integer $res
}

#-------------------------------------------------------------------------
# Test statements related to scalar sub-queries.
#



catch { db close }
file delete -force test.db
sqlite3 db test.db
do_test e_expr-35.0 {
  execsql {
    CREATE TABLE t2(a, b);
    INSERT INTO t2 VALUES('one', 'two');
    INSERT INTO t2 VALUES('three', NULL);
    INSERT INTO t2 VALUES(4, 5.0);
  }
} {}

# EVIDENCE-OF: R-00980-39256 A SELECT statement enclosed in parentheses
# may appear as a scalar quantity.
#
# EVIDENCE-OF: R-56294-03966 All types of SELECT statement, including
# aggregate and compound SELECT queries (queries with keywords like
# UNION or EXCEPT) are allowed as scalar subqueries.
#
do_expr_test e_expr-35.1.1 { (SELECT 35)   } integer 35
do_expr_test e_expr-35.1.2 { (SELECT NULL) } null {}

do_expr_test e_expr-35.1.3 { (SELECT count(*) FROM t2) } integer 3
do_expr_test e_expr-35.1.4 { (SELECT 4 FROM t2) } integer 4

do_expr_test e_expr-35.1.5 { 
  (SELECT b FROM t2 UNION SELECT a+1 FROM t2)
} null {}
do_expr_test e_expr-35.1.6 { 
  (SELECT a FROM t2 UNION SELECT COALESCE(b, 55) FROM t2 ORDER BY 1)
} integer 4

# EVIDENCE-OF: R-46899-53765 A SELECT used as a scalar quantity must
# return a result set with a single column.
#
set M {only a single result allowed for a SELECT that is part of an expression}
foreach {tn sql} {
  1     { SELECT (SELECT * FROM t2 UNION SELECT a+1, b+1 FROM t2) }
  2     { SELECT (SELECT * FROM t2 UNION SELECT a+1, b+1 FROM t2 ORDER BY 1) }
  3     { SELECT (SELECT 1, 2) }
  4     { SELECT (SELECT NULL, NULL, NULL) }
  5     { SELECT (SELECT * FROM t2) }
  6     { SELECT (SELECT * FROM (SELECT 1, 2, 3)) }
} {
  do_catchsql_test e_expr-35.2.$tn $sql [list 1 $M]
}

finish_test

Changes to test/in.test.

400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433





























434
435
436
437
438
439
440
      SELECT a, b FROM t3 INTERSECT SELECT a, b FROM t2
    );
  }
} {1 {only a single result allowed for a SELECT that is part of an expression}}
do_test in-12.6 {
  catchsql {
    SELECT * FROM t2 WHERE a IN (
      SELECT a FROM t3 UNION ALL SELECT a, b FROM t2
    );
  }
} {1 {SELECTs to the left and right of UNION ALL do not have the same number of result columns}}
do_test in-12.7 {
  catchsql {
    SELECT * FROM t2 WHERE a IN (
      SELECT a FROM t3 UNION SELECT a, b FROM t2
    );
  }
} {1 {SELECTs to the left and right of UNION do not have the same number of result columns}}
do_test in-12.8 {
  catchsql {
    SELECT * FROM t2 WHERE a IN (
      SELECT a FROM t3 EXCEPT SELECT a, b FROM t2
    );
  }
} {1 {SELECTs to the left and right of EXCEPT do not have the same number of result columns}}
do_test in-12.9 {
  catchsql {
    SELECT * FROM t2 WHERE a IN (
      SELECT a FROM t3 INTERSECT SELECT a, b FROM t2
    );
  }
} {1 {SELECTs to the left and right of INTERSECT do not have the same number of result columns}}
}































#------------------------------------------------------------------------
# The following tests check that NULL is handled correctly when it 
# appears as part of a set of values on the right-hand side of an
# IN or NOT IN operator.
#
# When it appears in such a set, NULL is handled as an "unknown value".







|






|






|






|





>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
      SELECT a, b FROM t3 INTERSECT SELECT a, b FROM t2
    );
  }
} {1 {only a single result allowed for a SELECT that is part of an expression}}
do_test in-12.6 {
  catchsql {
    SELECT * FROM t2 WHERE a IN (
      SELECT a, b FROM t3 UNION ALL SELECT a FROM t2
    );
  }
} {1 {SELECTs to the left and right of UNION ALL do not have the same number of result columns}}
do_test in-12.7 {
  catchsql {
    SELECT * FROM t2 WHERE a IN (
      SELECT a, b FROM t3 UNION SELECT a FROM t2
    );
  }
} {1 {SELECTs to the left and right of UNION do not have the same number of result columns}}
do_test in-12.8 {
  catchsql {
    SELECT * FROM t2 WHERE a IN (
      SELECT a, b FROM t3 EXCEPT SELECT a FROM t2
    );
  }
} {1 {SELECTs to the left and right of EXCEPT do not have the same number of result columns}}
do_test in-12.9 {
  catchsql {
    SELECT * FROM t2 WHERE a IN (
      SELECT a, b FROM t3 INTERSECT SELECT a FROM t2
    );
  }
} {1 {SELECTs to the left and right of INTERSECT do not have the same number of result columns}}
}

do_test in-12.10 {
  catchsql {
    SELECT * FROM t2 WHERE a IN (
      SELECT a FROM t3 UNION ALL SELECT a, b FROM t2
    );
  }
} {1 {only a single result allowed for a SELECT that is part of an expression}}
do_test in-12.11 {
  catchsql {
    SELECT * FROM t2 WHERE a IN (
      SELECT a FROM t3 UNION SELECT a, b FROM t2
    );
  }
} {1 {only a single result allowed for a SELECT that is part of an expression}}
do_test in-12.12 {
  catchsql {
    SELECT * FROM t2 WHERE a IN (
      SELECT a FROM t3 EXCEPT SELECT a, b FROM t2
    );
  }
} {1 {only a single result allowed for a SELECT that is part of an expression}}
do_test in-12.13 {
  catchsql {
    SELECT * FROM t2 WHERE a IN (
      SELECT a FROM t3 INTERSECT SELECT a, b FROM t2
    );
  }
} {1 {only a single result allowed for a SELECT that is part of an expression}}


#------------------------------------------------------------------------
# The following tests check that NULL is handled correctly when it 
# appears as part of a set of values on the right-hand side of an
# IN or NOT IN operator.
#
# When it appears in such a set, NULL is handled as an "unknown value".