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 |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
836b59d057c3fb4087b138c9bfbc0339 |
User & Date: | drh 2002-03-24 13:13:28.000 |
Context
2002-03-26
| ||
03:11 | Update the change log. (CVS 438) (check-in: 9637b9aa5d user: drh tags: trunk) | |
2002-03-24
| ||
13:13 | Added support for CASE expressions - patches from Dan Kennedy. (CVS 437) (check-in: 836b59d057 user: drh tags: trunk) | |
2002-03-23
| ||
01:00 | Version 2.4.3 (CVS 440) (check-in: 99d6764e57 user: drh tags: trunk) | |
Changes
Changes to VERSION.
|
| | | 1 | 2.4.4 |
Changes to src/expr.c.
︙ | ︙ | |||
8 9 10 11 12 13 14 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains routines used for analyzing expressions and ** for generating VDBE code that evaluates expressions in SQLite. ** | | | 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains routines used for analyzing expressions and ** for generating VDBE code that evaluates expressions in SQLite. ** ** $Id: expr.c,v 1.57 2002/03/24 13:13:29 drh Exp $ */ #include "sqliteInt.h" /* ** Construct a new expression node and return a pointer to it. Memory ** for this node is obtained from sqliteMalloc(). The calling function |
︙ | ︙ | |||
873 874 875 876 877 878 879 | sqliteVdbeResolveLabel(v, lbl); break; } case TK_AS: { sqliteExprCode(pParse, pExpr->pLeft); break; } | > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > | 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 | sqliteVdbeResolveLabel(v, lbl); break; } case TK_AS: { sqliteExprCode(pParse, pExpr->pLeft); break; } case TK_CASE: { int expr_end_label; int next_when_label; int i; assert(pExpr->pList); assert((pExpr->pList->nExpr % 2) == 0); assert(pExpr->pList->nExpr > 0); expr_end_label = sqliteVdbeMakeLabel(pParse->pVdbe); if( pExpr->pLeft ){ sqliteExprCode(pParse, pExpr->pLeft); } for(i=0; i<pExpr->pList->nExpr; i=i+2){ if( i!=0 ){ sqliteVdbeResolveLabel(pParse->pVdbe, next_when_label); } next_when_label = sqliteVdbeMakeLabel(pParse->pVdbe); if( pExpr->pLeft ){ sqliteVdbeAddOp(pParse->pVdbe, OP_Dup, 0, 1); sqliteExprCode(pParse, pExpr->pList->a[i].pExpr); sqliteVdbeAddOp(pParse->pVdbe, OP_Ne, 0, next_when_label); }else{ sqliteExprIfFalse(pParse, pExpr->pList->a[i].pExpr, next_when_label); } if( pExpr->pLeft ){ sqliteVdbeAddOp(pParse->pVdbe, OP_Pop, 1, 0); } sqliteExprCode(pParse, pExpr->pList->a[i+1].pExpr); sqliteVdbeAddOp(pParse->pVdbe, OP_Goto, 0, expr_end_label); } sqliteVdbeResolveLabel(pParse->pVdbe, next_when_label); if( pExpr->pLeft ){ sqliteVdbeAddOp(pParse->pVdbe, OP_Pop, 1, 0); } if( pExpr->pRight ){ sqliteExprCode(pParse, pExpr->pRight); }else{ sqliteVdbeAddOp(pParse->pVdbe, OP_String, 0, 0); } sqliteVdbeResolveLabel(pParse->pVdbe, expr_end_label); } break; } } /* ** Generate code for a boolean expression such that a jump is made ** to the label "dest" if the expression is true but execution ** continues straight thru if the expression is false. */ |
︙ | ︙ |
Changes to src/parse.y.
︙ | ︙ | |||
10 11 12 13 14 15 16 | ** ************************************************************************* ** This file contains SQLite's grammar for SQL. Process this file ** using the lemon parser generator to generate C code that runs ** the parser. Lemon will also generate a header file containing ** numeric codes for all of the tokens. ** | | | 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | ** ************************************************************************* ** This file contains SQLite's grammar for SQL. Process this file ** using the lemon parser generator to generate C code that runs ** the parser. Lemon will also generate a header file containing ** numeric codes for all of the tokens. ** ** @(#) $Id: parse.y,v 1.58 2002/03/24 13:13:29 drh Exp $ */ %token_prefix TK_ %token_type {Token} %default_type {Token} %extra_argument {Parse *pParse} %syntax_error { sqliteSetString(&pParse->zErrMsg,"syntax error",0); |
︙ | ︙ | |||
516 517 518 519 520 521 522 | expr(A) ::= expr(X) NOT IN LP select(Y) RP(E). { A = sqliteExpr(TK_IN, X, 0, 0); if( A ) A->pSelect = Y; A = sqliteExpr(TK_NOT, A, 0, 0); sqliteExprSpan(A,&X->span,&E); } | > > > > > | > > > > > > > > > > > > > > > > | 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 | expr(A) ::= expr(X) NOT IN LP select(Y) RP(E). { A = sqliteExpr(TK_IN, X, 0, 0); if( A ) A->pSelect = Y; A = sqliteExpr(TK_NOT, A, 0, 0); sqliteExprSpan(A,&X->span,&E); } /* CASE expressions */ expr(A) ::= CASE(C) case_operand(X) case_exprlist(Y) case_else(Z) END(E). { A = sqliteExpr(TK_CASE, X, Z, 0); if( A ) A->pList = Y; sqliteExprSpan(A, &C, &E); } %type case_exprlist {ExprList*} %destructor case_exprlist {sqliteExprListDelete($$);} case_exprlist(A) ::= case_exprlist(X) WHEN expr(Y) THEN expr(Z). { A = sqliteExprListAppend(X, Y, 0); A = sqliteExprListAppend(A, Z, 0); } case_exprlist(A) ::= WHEN expr(Y) THEN expr(Z). { A = sqliteExprListAppend(0, Y, 0); A = sqliteExprListAppend(A, Z, 0); } %type case_else {Expr*} case_else(A) ::= ELSE expr(X). {A = X;} case_else(A) ::= . {A = 0;} %type case_operand {Expr*} case_operand(A) ::= expr(X). {A = X;} case_operand(A) ::= . {A = 0;} %type exprlist {ExprList*} %destructor exprlist {sqliteExprListDelete($$);} %type expritem {Expr*} %destructor expritem {sqliteExprDelete($$);} exprlist(A) ::= exprlist(X) COMMA expritem(Y). |
︙ | ︙ |
Changes to src/tokenize.c.
︙ | ︙ | |||
11 12 13 14 15 16 17 | ************************************************************************* ** An tokenizer for SQL ** ** This file contains C code that splits an SQL input string up into ** individual tokens and sends those tokens one-by-one over to the ** parser for analysis. ** | | | 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | ************************************************************************* ** An tokenizer for SQL ** ** This file contains C code that splits an SQL input string up into ** individual tokens and sends those tokens one-by-one over to the ** parser for analysis. ** ** $Id: tokenize.c,v 1.40 2002/03/24 13:13:29 drh Exp $ */ #include "sqliteInt.h" #include "os.h" #include <ctype.h> #include <stdlib.h> /* |
︙ | ︙ | |||
42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 | { "ALL", 0, TK_ALL, 0 }, { "AND", 0, TK_AND, 0 }, { "AS", 0, TK_AS, 0 }, { "ASC", 0, TK_ASC, 0 }, { "BEGIN", 0, TK_BEGIN, 0 }, { "BETWEEN", 0, TK_BETWEEN, 0 }, { "BY", 0, TK_BY, 0 }, { "CHECK", 0, TK_CHECK, 0 }, { "CLUSTER", 0, TK_CLUSTER, 0 }, { "COMMIT", 0, TK_COMMIT, 0 }, { "CONFLICT", 0, TK_CONFLICT, 0 }, { "CONSTRAINT", 0, TK_CONSTRAINT, 0 }, { "COPY", 0, TK_COPY, 0 }, { "CREATE", 0, TK_CREATE, 0 }, { "DEFAULT", 0, TK_DEFAULT, 0 }, { "DELETE", 0, TK_DELETE, 0 }, { "DELIMITERS", 0, TK_DELIMITERS, 0 }, { "DESC", 0, TK_DESC, 0 }, { "DISTINCT", 0, TK_DISTINCT, 0 }, { "DROP", 0, TK_DROP, 0 }, { "END", 0, TK_END, 0 }, { "EXCEPT", 0, TK_EXCEPT, 0 }, { "EXPLAIN", 0, TK_EXPLAIN, 0 }, { "FAIL", 0, TK_FAIL, 0 }, { "FROM", 0, TK_FROM, 0 }, { "GLOB", 0, TK_GLOB, 0 }, { "GROUP", 0, TK_GROUP, 0 }, { "HAVING", 0, TK_HAVING, 0 }, | > > | 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 | { "ALL", 0, TK_ALL, 0 }, { "AND", 0, TK_AND, 0 }, { "AS", 0, TK_AS, 0 }, { "ASC", 0, TK_ASC, 0 }, { "BEGIN", 0, TK_BEGIN, 0 }, { "BETWEEN", 0, TK_BETWEEN, 0 }, { "BY", 0, TK_BY, 0 }, { "CASE", 0, TK_CASE, 0 }, { "CHECK", 0, TK_CHECK, 0 }, { "CLUSTER", 0, TK_CLUSTER, 0 }, { "COMMIT", 0, TK_COMMIT, 0 }, { "CONFLICT", 0, TK_CONFLICT, 0 }, { "CONSTRAINT", 0, TK_CONSTRAINT, 0 }, { "COPY", 0, TK_COPY, 0 }, { "CREATE", 0, TK_CREATE, 0 }, { "DEFAULT", 0, TK_DEFAULT, 0 }, { "DELETE", 0, TK_DELETE, 0 }, { "DELIMITERS", 0, TK_DELIMITERS, 0 }, { "DESC", 0, TK_DESC, 0 }, { "DISTINCT", 0, TK_DISTINCT, 0 }, { "DROP", 0, TK_DROP, 0 }, { "END", 0, TK_END, 0 }, { "ELSE", 0, TK_ELSE, 0 }, { "EXCEPT", 0, TK_EXCEPT, 0 }, { "EXPLAIN", 0, TK_EXPLAIN, 0 }, { "FAIL", 0, TK_FAIL, 0 }, { "FROM", 0, TK_FROM, 0 }, { "GLOB", 0, TK_GLOB, 0 }, { "GROUP", 0, TK_GROUP, 0 }, { "HAVING", 0, TK_HAVING, 0 }, |
︙ | ︙ | |||
90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 | { "REPLACE", 0, TK_REPLACE, 0 }, { "ROLLBACK", 0, TK_ROLLBACK, 0 }, { "SELECT", 0, TK_SELECT, 0 }, { "SET", 0, TK_SET, 0 }, { "TABLE", 0, TK_TABLE, 0 }, { "TEMP", 0, TK_TEMP, 0 }, { "TEMPORARY", 0, TK_TEMP, 0 }, { "TRANSACTION", 0, TK_TRANSACTION, 0 }, { "UNION", 0, TK_UNION, 0 }, { "UNIQUE", 0, TK_UNIQUE, 0 }, { "UPDATE", 0, TK_UPDATE, 0 }, { "USING", 0, TK_USING, 0 }, { "VACUUM", 0, TK_VACUUM, 0 }, { "VALUES", 0, TK_VALUES, 0 }, { "VIEW", 0, TK_VIEW, 0 }, { "WHERE", 0, TK_WHERE, 0 }, }; /* ** This is the hash table */ #define KEY_HASH_SIZE 71 | > > | 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 | { "REPLACE", 0, TK_REPLACE, 0 }, { "ROLLBACK", 0, TK_ROLLBACK, 0 }, { "SELECT", 0, TK_SELECT, 0 }, { "SET", 0, TK_SET, 0 }, { "TABLE", 0, TK_TABLE, 0 }, { "TEMP", 0, TK_TEMP, 0 }, { "TEMPORARY", 0, TK_TEMP, 0 }, { "THEN", 0, TK_THEN, 0 }, { "TRANSACTION", 0, TK_TRANSACTION, 0 }, { "UNION", 0, TK_UNION, 0 }, { "UNIQUE", 0, TK_UNIQUE, 0 }, { "UPDATE", 0, TK_UPDATE, 0 }, { "USING", 0, TK_USING, 0 }, { "VACUUM", 0, TK_VACUUM, 0 }, { "VALUES", 0, TK_VALUES, 0 }, { "VIEW", 0, TK_VIEW, 0 }, { "WHEN", 0, TK_WHEN, 0 }, { "WHERE", 0, TK_WHERE, 0 }, }; /* ** This is the hash table */ #define KEY_HASH_SIZE 71 |
︙ | ︙ |
Changes to test/expr.test.
1 2 3 4 5 6 7 8 9 10 11 12 13 | # 2001 September 15 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # This file implements regression tests for SQLite library. The # focus of this file is testing expressions. # | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | # 2001 September 15 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # This file implements regression tests for SQLite library. The # focus of this file is testing expressions. # # $Id: expr.test,v 1.19 2002/03/24 13:13:29 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl # Create a table to work with. # execsql {CREATE TABLE test1(i1 int, i2 int, r1 real, r2 real, t1 text, t2 text)} |
︙ | ︙ | |||
228 229 230 231 232 233 234 235 236 237 238 239 240 241 | test_expr expr-6.19 {t1='abc', t2='a[]b]c'} {t1 GLOB t2} 1 test_expr expr-6.20 {t1='abc', t2='a[^]b]c'} {t1 GLOB t2} 0 test_expr expr-6.21 {t1='abcdefg', t2='a*[de]g'} {t1 GLOB t2} 0 test_expr expr-6.22 {t1='abcdefg', t2='a*[^de]g'} {t1 GLOB t2} 1 test_expr expr-6.23 {t1='abcdefg', t2='a*?g'} {t1 GLOB t2} 1 test_expr expr-6.24 {t1='ac', t2='a*c'} {t1 GLOB t2} 1 test_expr expr-6.25 {t1='ac', t2='a*?c'} {t1 GLOB t2} 0 # These tests only work on versions of TCL that support Unicode # if {"\u1234"!="u1234" && [sqlite -encoding]=="UTF-8"} { test_expr expr-6.26 "t1='a\u0080c', t2='a?c'" {t1 GLOB t2} 1 test_expr expr-6.27 "t1='a\u07ffc', t2='a?c'" {t1 GLOB t2} 1 test_expr expr-6.28 "t1='a\u0800c', t2='a?c'" {t1 GLOB t2} 1 | > > > > > > > > > > > > > > > > | 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 | test_expr expr-6.19 {t1='abc', t2='a[]b]c'} {t1 GLOB t2} 1 test_expr expr-6.20 {t1='abc', t2='a[^]b]c'} {t1 GLOB t2} 0 test_expr expr-6.21 {t1='abcdefg', t2='a*[de]g'} {t1 GLOB t2} 0 test_expr expr-6.22 {t1='abcdefg', t2='a*[^de]g'} {t1 GLOB t2} 1 test_expr expr-6.23 {t1='abcdefg', t2='a*?g'} {t1 GLOB t2} 1 test_expr expr-6.24 {t1='ac', t2='a*c'} {t1 GLOB t2} 1 test_expr expr-6.25 {t1='ac', t2='a*?c'} {t1 GLOB t2} 0 test_expr expr-case.1 {i1=1, i2=2} \ {CASE WHEN i1 = i2 THEN 'eq' ELSE 'ne' END} ne test_expr expr-case.2 {i1=2, i2=2} \ {CASE WHEN i1 = i2 THEN 'eq' ELSE 'ne' END} eq test_expr expr-case.3 {i1=2} \ {CASE i1 WHEN 1 THEN 'one' WHEN 2 THEN 'two' ELSE 'error' END} two test_expr expr-case.4 {i1=3} \ {CASE i1 WHEN 1 THEN 'one' WHEN 2 THEN 'two' ELSE 'error' END} error test_expr expr-case.5 {i1=3} \ {CASE i1 WHEN 1 THEN 'one' WHEN 2 THEN 'two' END} {{}} test_expr expr-case.6 {i1=7} \ { CASE WHEN i1 < 5 THEN 'low' WHEN i1 < 10 THEN 'medium' WHEN i1 < 15 THEN 'high' ELSE 'error' END} medium # These tests only work on versions of TCL that support Unicode # if {"\u1234"!="u1234" && [sqlite -encoding]=="UTF-8"} { test_expr expr-6.26 "t1='a\u0080c', t2='a?c'" {t1 GLOB t2} 1 test_expr expr-6.27 "t1='a\u07ffc', t2='a?c'" {t1 GLOB t2} 1 test_expr expr-6.28 "t1='a\u0800c', t2='a?c'" {t1 GLOB t2} 1 |
︙ | ︙ |