Added support for CASE expressions - patches from Dan Kennedy. (CVS 437)
FossilOrigin-Name: 836b59d057c3fb4087b138c9bfbc03392ddfb89d
diff --git a/src/expr.c b/src/expr.c
index 793a44e..5b0e732 100644
--- a/src/expr.c
+++ b/src/expr.c
@@ -12,7 +12,7 @@
** This file contains routines used for analyzing expressions and
** for generating VDBE code that evaluates expressions in SQLite.
**
-** $Id: expr.c,v 1.56 2002/03/13 18:54:07 drh Exp $
+** $Id: expr.c,v 1.57 2002/03/24 13:13:29 drh Exp $
*/
#include "sqliteInt.h"
@@ -877,8 +877,49 @@
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;
}
- return;
}
/*
diff --git a/src/parse.y b/src/parse.y
index ff24a58..2343d04 100644
--- a/src/parse.y
+++ b/src/parse.y
@@ -14,7 +14,7 @@
** the parser. Lemon will also generate a header file containing
** numeric codes for all of the tokens.
**
-** @(#) $Id: parse.y,v 1.57 2002/03/13 18:54:08 drh Exp $
+** @(#) $Id: parse.y,v 1.58 2002/03/24 13:13:29 drh Exp $
*/
%token_prefix TK_
%token_type {Token}
@@ -520,7 +520,28 @@
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($$);}
diff --git a/src/tokenize.c b/src/tokenize.c
index 5a541cf..84eaab7 100644
--- a/src/tokenize.c
+++ b/src/tokenize.c
@@ -15,7 +15,7 @@
** individual tokens and sends those tokens one-by-one over to the
** parser for analysis.
**
-** $Id: tokenize.c,v 1.39 2002/03/13 18:54:08 drh Exp $
+** $Id: tokenize.c,v 1.40 2002/03/24 13:13:29 drh Exp $
*/
#include "sqliteInt.h"
#include "os.h"
@@ -46,6 +46,7 @@
{ "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 },
@@ -60,6 +61,7 @@
{ "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 },
@@ -94,6 +96,7 @@
{ "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 },
@@ -102,6 +105,7 @@
{ "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 },
};