/ Check-in [836b59d0]
Login

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

Overview
Comment:Added support for CASE expressions - patches from Dan Kennedy. (CVS 437)
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 836b59d057c3fb4087b138c9bfbc03392ddfb89d
User & Date: drh 2002-03-24 13:13:28
Context
2002-03-26
03:11
Update the change log. (CVS 438) check-in: 9637b9aa user: drh tags: trunk
2002-03-24
13:13
Added support for CASE expressions - patches from Dan Kennedy. (CVS 437) check-in: 836b59d0 user: drh tags: trunk
2002-03-23
01:00
Version 2.4.3 (CVS 440) check-in: 99d6764e user: drh tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to VERSION.

     1         -2.4.3
            1  +2.4.4

Changes to src/expr.c.

     8      8   **    May you find forgiveness for yourself and forgive others.
     9      9   **    May you share freely, never taking more than you give.
    10     10   **
    11     11   *************************************************************************
    12     12   ** This file contains routines used for analyzing expressions and
    13     13   ** for generating VDBE code that evaluates expressions in SQLite.
    14     14   **
    15         -** $Id: expr.c,v 1.56 2002/03/13 18:54:07 drh Exp $
           15  +** $Id: expr.c,v 1.57 2002/03/24 13:13:29 drh Exp $
    16     16   */
    17     17   #include "sqliteInt.h"
    18     18   
    19     19   
    20     20   /*
    21     21   ** Construct a new expression node and return a pointer to it.  Memory
    22     22   ** for this node is obtained from sqliteMalloc().  The calling function
................................................................................
   873    873         sqliteVdbeResolveLabel(v, lbl);
   874    874         break;
   875    875       }
   876    876       case TK_AS: {
   877    877         sqliteExprCode(pParse, pExpr->pLeft);
   878    878         break;
   879    879       }
          880  +    case TK_CASE: {
          881  +      int expr_end_label;
          882  +      int next_when_label;
          883  +      int i;
          884  +
          885  +      assert(pExpr->pList);
          886  +      assert((pExpr->pList->nExpr % 2) == 0);
          887  +      assert(pExpr->pList->nExpr > 0);
          888  +      expr_end_label = sqliteVdbeMakeLabel(pParse->pVdbe);
          889  +      if( pExpr->pLeft ){
          890  +        sqliteExprCode(pParse, pExpr->pLeft);
          891  +      }
          892  +      for(i=0; i<pExpr->pList->nExpr; i=i+2){
          893  +        if( i!=0 ){
          894  +          sqliteVdbeResolveLabel(pParse->pVdbe, next_when_label);
          895  +        }
          896  +        next_when_label = sqliteVdbeMakeLabel(pParse->pVdbe);
          897  +        if( pExpr->pLeft ){
          898  +          sqliteVdbeAddOp(pParse->pVdbe, OP_Dup, 0, 1);
          899  +          sqliteExprCode(pParse, pExpr->pList->a[i].pExpr);
          900  +          sqliteVdbeAddOp(pParse->pVdbe, OP_Ne, 0, next_when_label);
          901  +        }else{
          902  +          sqliteExprIfFalse(pParse, pExpr->pList->a[i].pExpr, next_when_label);
          903  +        }
          904  +        if( pExpr->pLeft ){
          905  +          sqliteVdbeAddOp(pParse->pVdbe, OP_Pop, 1, 0);
          906  +        }
          907  +        sqliteExprCode(pParse, pExpr->pList->a[i+1].pExpr);
          908  +        sqliteVdbeAddOp(pParse->pVdbe, OP_Goto, 0, expr_end_label);
          909  +      }
          910  +      sqliteVdbeResolveLabel(pParse->pVdbe, next_when_label);
          911  +      if( pExpr->pLeft ){
          912  +        sqliteVdbeAddOp(pParse->pVdbe, OP_Pop, 1, 0);
          913  +      }
          914  +      if( pExpr->pRight ){
          915  +        sqliteExprCode(pParse, pExpr->pRight);
          916  +      }else{
          917  +        sqliteVdbeAddOp(pParse->pVdbe, OP_String, 0, 0);
          918  +      }
          919  +      sqliteVdbeResolveLabel(pParse->pVdbe, expr_end_label);
          920  +    }
          921  +    break;
   880    922     }
   881         -  return;
   882    923   }
   883    924   
   884    925   /*
   885    926   ** Generate code for a boolean expression such that a jump is made
   886    927   ** to the label "dest" if the expression is true but execution
   887    928   ** continues straight thru if the expression is false.
   888    929   */

Changes to src/parse.y.

    10     10   **
    11     11   *************************************************************************
    12     12   ** This file contains SQLite's grammar for SQL.  Process this file
    13     13   ** using the lemon parser generator to generate C code that runs
    14     14   ** the parser.  Lemon will also generate a header file containing
    15     15   ** numeric codes for all of the tokens.
    16     16   **
    17         -** @(#) $Id: parse.y,v 1.57 2002/03/13 18:54:08 drh Exp $
           17  +** @(#) $Id: parse.y,v 1.58 2002/03/24 13:13:29 drh Exp $
    18     18   */
    19     19   %token_prefix TK_
    20     20   %token_type {Token}
    21     21   %default_type {Token}
    22     22   %extra_argument {Parse *pParse}
    23     23   %syntax_error {
    24     24     sqliteSetString(&pParse->zErrMsg,"syntax error",0);
................................................................................
   516    516   expr(A) ::= expr(X) NOT IN LP select(Y) RP(E).  {
   517    517     A = sqliteExpr(TK_IN, X, 0, 0);
   518    518     if( A ) A->pSelect = Y;
   519    519     A = sqliteExpr(TK_NOT, A, 0, 0);
   520    520     sqliteExprSpan(A,&X->span,&E);
   521    521   }
   522    522   
   523         -
          523  +/* CASE expressions */
          524  +expr(A) ::= CASE(C) case_operand(X) case_exprlist(Y) case_else(Z) END(E). {
          525  +  A = sqliteExpr(TK_CASE, X, Z, 0);
          526  +  if( A ) A->pList = Y;
          527  +  sqliteExprSpan(A, &C, &E);
          528  +}
          529  +%type case_exprlist {ExprList*}
          530  +%destructor case_exprlist {sqliteExprListDelete($$);}
          531  +case_exprlist(A) ::= case_exprlist(X) WHEN expr(Y) THEN expr(Z). {
          532  +  A = sqliteExprListAppend(X, Y, 0);
          533  +  A = sqliteExprListAppend(A, Z, 0);
          534  +}
          535  +case_exprlist(A) ::= WHEN expr(Y) THEN expr(Z). {
          536  +  A = sqliteExprListAppend(0, Y, 0);
          537  +  A = sqliteExprListAppend(A, Z, 0);
          538  +}
          539  +%type case_else {Expr*}
          540  +case_else(A) ::=  ELSE expr(X).         {A = X;}
          541  +case_else(A) ::=  .                     {A = 0;} 
          542  +%type case_operand {Expr*}
          543  +case_operand(A) ::= expr(X).            {A = X;} 
          544  +case_operand(A) ::= .                   {A = 0;} 
   524    545   
   525    546   %type exprlist {ExprList*}
   526    547   %destructor exprlist {sqliteExprListDelete($$);}
   527    548   %type expritem {Expr*}
   528    549   %destructor expritem {sqliteExprDelete($$);}
   529    550   
   530    551   exprlist(A) ::= exprlist(X) COMMA expritem(Y). 

Changes to src/tokenize.c.

    11     11   *************************************************************************
    12     12   ** An tokenizer for SQL
    13     13   **
    14     14   ** This file contains C code that splits an SQL input string up into
    15     15   ** individual tokens and sends those tokens one-by-one over to the
    16     16   ** parser for analysis.
    17     17   **
    18         -** $Id: tokenize.c,v 1.39 2002/03/13 18:54:08 drh Exp $
           18  +** $Id: tokenize.c,v 1.40 2002/03/24 13:13:29 drh Exp $
    19     19   */
    20     20   #include "sqliteInt.h"
    21     21   #include "os.h"
    22     22   #include <ctype.h>
    23     23   #include <stdlib.h>
    24     24   
    25     25   /*
................................................................................
    42     42     { "ALL",               0, TK_ALL,              0 },
    43     43     { "AND",               0, TK_AND,              0 },
    44     44     { "AS",                0, TK_AS,               0 },
    45     45     { "ASC",               0, TK_ASC,              0 },
    46     46     { "BEGIN",             0, TK_BEGIN,            0 },
    47     47     { "BETWEEN",           0, TK_BETWEEN,          0 },
    48     48     { "BY",                0, TK_BY,               0 },
           49  +  { "CASE",              0, TK_CASE,             0 },
    49     50     { "CHECK",             0, TK_CHECK,            0 },
    50     51     { "CLUSTER",           0, TK_CLUSTER,          0 },
    51     52     { "COMMIT",            0, TK_COMMIT,           0 },
    52     53     { "CONFLICT",          0, TK_CONFLICT,         0 },
    53     54     { "CONSTRAINT",        0, TK_CONSTRAINT,       0 },
    54     55     { "COPY",              0, TK_COPY,             0 },
    55     56     { "CREATE",            0, TK_CREATE,           0 },
................................................................................
    56     57     { "DEFAULT",           0, TK_DEFAULT,          0 },
    57     58     { "DELETE",            0, TK_DELETE,           0 },
    58     59     { "DELIMITERS",        0, TK_DELIMITERS,       0 },
    59     60     { "DESC",              0, TK_DESC,             0 },
    60     61     { "DISTINCT",          0, TK_DISTINCT,         0 },
    61     62     { "DROP",              0, TK_DROP,             0 },
    62     63     { "END",               0, TK_END,              0 },
           64  +  { "ELSE",              0, TK_ELSE,             0 },
    63     65     { "EXCEPT",            0, TK_EXCEPT,           0 },
    64     66     { "EXPLAIN",           0, TK_EXPLAIN,          0 },
    65     67     { "FAIL",              0, TK_FAIL,             0 },
    66     68     { "FROM",              0, TK_FROM,             0 },
    67     69     { "GLOB",              0, TK_GLOB,             0 },
    68     70     { "GROUP",             0, TK_GROUP,            0 },
    69     71     { "HAVING",            0, TK_HAVING,           0 },
................................................................................
    90     92     { "REPLACE",           0, TK_REPLACE,          0 },
    91     93     { "ROLLBACK",          0, TK_ROLLBACK,         0 },
    92     94     { "SELECT",            0, TK_SELECT,           0 },
    93     95     { "SET",               0, TK_SET,              0 },
    94     96     { "TABLE",             0, TK_TABLE,            0 },
    95     97     { "TEMP",              0, TK_TEMP,             0 },
    96     98     { "TEMPORARY",         0, TK_TEMP,             0 },
           99  +  { "THEN",              0, TK_THEN,             0 },
    97    100     { "TRANSACTION",       0, TK_TRANSACTION,      0 },
    98    101     { "UNION",             0, TK_UNION,            0 },
    99    102     { "UNIQUE",            0, TK_UNIQUE,           0 },
   100    103     { "UPDATE",            0, TK_UPDATE,           0 },
   101    104     { "USING",             0, TK_USING,            0 },
   102    105     { "VACUUM",            0, TK_VACUUM,           0 },
   103    106     { "VALUES",            0, TK_VALUES,           0 },
   104    107     { "VIEW",              0, TK_VIEW,             0 },
          108  +  { "WHEN",              0, TK_WHEN,             0 },
   105    109     { "WHERE",             0, TK_WHERE,            0 },
   106    110   };
   107    111   
   108    112   /*
   109    113   ** This is the hash table
   110    114   */
   111    115   #define KEY_HASH_SIZE 71

Changes to test/expr.test.

     7      7   #    May you find forgiveness for yourself and forgive others.
     8      8   #    May you share freely, never taking more than you give.
     9      9   #
    10     10   #***********************************************************************
    11     11   # This file implements regression tests for SQLite library.  The
    12     12   # focus of this file is testing expressions.
    13     13   #
    14         -# $Id: expr.test,v 1.18 2002/01/15 18:39:45 drh Exp $
           14  +# $Id: expr.test,v 1.19 2002/03/24 13:13:29 drh Exp $
    15     15   
    16     16   set testdir [file dirname $argv0]
    17     17   source $testdir/tester.tcl
    18     18   
    19     19   # Create a table to work with.
    20     20   #
    21     21   execsql {CREATE TABLE test1(i1 int, i2 int, r1 real, r2 real, t1 text, t2 text)}
................................................................................
   228    228   test_expr expr-6.19 {t1='abc', t2='a[]b]c'} {t1 GLOB t2} 1
   229    229   test_expr expr-6.20 {t1='abc', t2='a[^]b]c'} {t1 GLOB t2} 0
   230    230   test_expr expr-6.21 {t1='abcdefg', t2='a*[de]g'} {t1 GLOB t2} 0
   231    231   test_expr expr-6.22 {t1='abcdefg', t2='a*[^de]g'} {t1 GLOB t2} 1
   232    232   test_expr expr-6.23 {t1='abcdefg', t2='a*?g'} {t1 GLOB t2} 1
   233    233   test_expr expr-6.24 {t1='ac', t2='a*c'} {t1 GLOB t2} 1
   234    234   test_expr expr-6.25 {t1='ac', t2='a*?c'} {t1 GLOB t2} 0
          235  +
          236  +test_expr expr-case.1 {i1=1, i2=2} \
          237  +	{CASE WHEN i1 = i2 THEN 'eq' ELSE 'ne' END} ne
          238  +test_expr expr-case.2 {i1=2, i2=2} \
          239  +	{CASE WHEN i1 = i2 THEN 'eq' ELSE 'ne' END} eq
          240  +test_expr expr-case.3 {i1=2} \
          241  +	{CASE i1 WHEN 1 THEN 'one' WHEN 2 THEN 'two' ELSE 'error' END} two
          242  +test_expr expr-case.4 {i1=3} \
          243  +	{CASE i1 WHEN 1 THEN 'one' WHEN 2 THEN 'two' ELSE 'error' END} error
          244  +test_expr expr-case.5 {i1=3} \
          245  +	{CASE i1 WHEN 1 THEN 'one' WHEN 2 THEN 'two' END} {{}}
          246  +test_expr expr-case.6 {i1=7} \
          247  +	{ CASE WHEN i1 < 5 THEN 'low' 
          248  +	       WHEN i1 < 10 THEN 'medium' 
          249  +               WHEN i1 < 15 THEN 'high' ELSE 'error' END} medium
          250  +
   235    251   
   236    252   # These tests only work on versions of TCL that support Unicode
   237    253   #
   238    254   if {"\u1234"!="u1234" && [sqlite -encoding]=="UTF-8"} {
   239    255     test_expr expr-6.26 "t1='a\u0080c', t2='a?c'" {t1 GLOB t2} 1
   240    256     test_expr expr-6.27 "t1='a\u07ffc', t2='a?c'" {t1 GLOB t2} 1
   241    257     test_expr expr-6.28 "t1='a\u0800c', t2='a?c'" {t1 GLOB t2} 1