aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authordrh <drh@noemail.net>2004-10-04 13:19:23 +0000
committerdrh <drh@noemail.net>2004-10-04 13:19:23 +0000
commitf2bc013c7011580ae976e5d7a978863b3f84a52d (patch)
tree8fdf6922f04914830682242910be66e9d5a58b26 /src
parent9c105bb990007c678ca28e63b764f8d0b557d5f9 (diff)
downloadsqlite-f2bc013c7011580ae976e5d7a978863b3f84a52d.tar.gz
sqlite-f2bc013c7011580ae976e5d7a978863b3f84a52d.zip
Save about 800 bytes of code space by aligning TK_ and OP_ constants so that
we do not have to translate between them. (CVS 1998) FossilOrigin-Name: 4c817e3f293a9c1365e632f7dc13ae440263332a
Diffstat (limited to 'src')
-rw-r--r--src/expr.c137
-rw-r--r--src/parse.y12
-rw-r--r--src/sqliteInt.h4
-rw-r--r--src/vdbe.c90
4 files changed, 125 insertions, 118 deletions
diff --git a/src/expr.c b/src/expr.c
index a07fdcd00..75167579b 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.165 2004/09/25 13:12:15 drh Exp $
+** $Id: expr.c,v 1.166 2004/10/04 13:19:24 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>
@@ -1180,41 +1180,19 @@ static void codeInteger(Vdbe *v, const char *z, int n){
/*
** Generate code into the current Vdbe to evaluate the given
** expression and leave the result on the top of stack.
+**
+** This code depends on the fact that certain token values (ex: TK_EQ)
+** are the same as opcode values (ex: OP_Eq) that implement the corresponding
+** operation. Special comments in vdbe.c and the mkopcodeh.awk script in
+** the make process cause these values to align. Assert()s in the code
+** below verify that the numbers are aligned correctly.
*/
void sqlite3ExprCode(Parse *pParse, Expr *pExpr){
Vdbe *v = pParse->pVdbe;
int op;
if( v==0 || pExpr==0 ) return;
- switch( pExpr->op ){
- case TK_PLUS: op = OP_Add; break;
- case TK_MINUS: op = OP_Subtract; break;
- case TK_STAR: op = OP_Multiply; break;
- case TK_SLASH: op = OP_Divide; break;
- case TK_AND: op = OP_And; break;
- case TK_OR: op = OP_Or; break;
- case TK_LT: op = OP_Lt; break;
- case TK_LE: op = OP_Le; break;
- case TK_GT: op = OP_Gt; break;
- case TK_GE: op = OP_Ge; break;
- case TK_NE: op = OP_Ne; break;
- case TK_EQ: op = OP_Eq; break;
- case TK_ISNULL: op = OP_IsNull; break;
- case TK_NOTNULL: op = OP_NotNull; break;
- case TK_NOT: op = OP_Not; break;
- case TK_UMINUS: op = OP_Negative; break;
- case TK_BITAND: op = OP_BitAnd; break;
- case TK_BITOR: op = OP_BitOr; break;
- case TK_BITNOT: op = OP_BitNot; break;
- case TK_LSHIFT: op = OP_ShiftLeft; break;
- case TK_RSHIFT: op = OP_ShiftRight; break;
- case TK_REM: op = OP_Remainder; break;
- case TK_FLOAT: op = OP_Real; break;
- case TK_STRING: op = OP_String8; break;
- case TK_BLOB: op = OP_HexBlob; break;
- case TK_CONCAT: op = OP_Concat; break;
- default: op = 0; break;
- }
- switch( pExpr->op ){
+ op = pExpr->op;
+ switch( op ){
case TK_COLUMN: {
if( pParse->useAgg ){
sqlite3VdbeAddOp(v, OP_AggGet, 0, pExpr->iAgg);
@@ -1236,11 +1214,14 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){
}
case TK_FLOAT:
case TK_STRING: {
+ assert( TK_FLOAT==OP_Real );
+ assert( TK_STRING==OP_String8 );
sqlite3VdbeOp3(v, op, 0, 0, pExpr->token.z, pExpr->token.n);
sqlite3VdbeDequoteP3(v, -1);
break;
}
case TK_BLOB: {
+ assert( TK_BLOB==OP_HexBlob );
sqlite3VdbeOp3(v, op, 0, 0, pExpr->token.z+1, pExpr->token.n-1);
sqlite3VdbeDequoteP3(v, -1);
break;
@@ -1262,6 +1243,12 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){
case TK_GE:
case TK_NE:
case TK_EQ: {
+ assert( TK_LT==OP_Lt );
+ assert( TK_LE==OP_Le );
+ assert( TK_GT==OP_Gt );
+ assert( TK_GE==OP_Ge );
+ assert( TK_EQ==OP_Eq );
+ assert( TK_NE==OP_Ne );
sqlite3ExprCode(pParse, pExpr->pLeft);
sqlite3ExprCode(pParse, pExpr->pRight);
codeCompare(pParse, pExpr->pLeft, pExpr->pRight, op, 0, 0);
@@ -1279,6 +1266,17 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){
case TK_LSHIFT:
case TK_RSHIFT:
case TK_CONCAT: {
+ assert( TK_AND==OP_And );
+ assert( TK_OR==OP_Or );
+ assert( TK_PLUS==OP_Add );
+ assert( TK_MINUS==OP_Subtract );
+ assert( TK_REM==OP_Remainder );
+ assert( TK_BITAND==OP_BitAnd );
+ assert( TK_BITOR==OP_BitOr );
+ assert( TK_SLASH==OP_Divide );
+ assert( TK_LSHIFT==OP_ShiftLeft );
+ assert( TK_RSHIFT==OP_ShiftRight );
+ assert( TK_CONCAT==OP_Concat );
sqlite3ExprCode(pParse, pExpr->pLeft);
sqlite3ExprCode(pParse, pExpr->pRight);
sqlite3VdbeAddOp(v, op, 0, 0);
@@ -1303,6 +1301,8 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){
}
case TK_BITNOT:
case TK_NOT: {
+ assert( TK_BITNOT==OP_BitNot );
+ assert( TK_NOT==OP_Not );
sqlite3ExprCode(pParse, pExpr->pLeft);
sqlite3VdbeAddOp(v, op, 0, 0);
break;
@@ -1310,13 +1310,15 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){
case TK_ISNULL:
case TK_NOTNULL: {
int dest;
+ assert( TK_ISNULL==OP_IsNull );
+ assert( TK_NOTNULL==OP_NotNull );
sqlite3VdbeAddOp(v, OP_Integer, 1, 0);
sqlite3ExprCode(pParse, pExpr->pLeft);
dest = sqlite3VdbeCurrentAddr(v) + 2;
sqlite3VdbeAddOp(v, op, 1, dest);
sqlite3VdbeAddOp(v, OP_AddImm, -1, 0);
+ break;
}
- break;
case TK_AGG_FUNCTION: {
sqlite3VdbeAddOp(v, OP_AggGet, 0, pExpr->iAgg);
break;
@@ -1503,23 +1505,19 @@ int sqlite3ExprCodeExprList(
**
** If the expression evaluates to NULL (neither true nor false), then
** take the jump if the jumpIfNull flag is true.
+**
+** This code depends on the fact that certain token values (ex: TK_EQ)
+** are the same as opcode values (ex: OP_Eq) that implement the corresponding
+** operation. Special comments in vdbe.c and the mkopcodeh.awk script in
+** the make process cause these values to align. Assert()s in the code
+** below verify that the numbers are aligned correctly.
*/
void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
Vdbe *v = pParse->pVdbe;
int op = 0;
if( v==0 || pExpr==0 ) return;
- switch( pExpr->op ){
- case TK_LT: op = OP_Lt; break;
- case TK_LE: op = OP_Le; break;
- case TK_GT: op = OP_Gt; break;
- case TK_GE: op = OP_Ge; break;
- case TK_NE: op = OP_Ne; break;
- case TK_EQ: op = OP_Eq; break;
- case TK_ISNULL: op = OP_IsNull; break;
- case TK_NOTNULL: op = OP_NotNull; break;
- default: break;
- }
- switch( pExpr->op ){
+ op = pExpr->op;
+ switch( op ){
case TK_AND: {
int d2 = sqlite3VdbeMakeLabel(v);
sqlite3ExprIfFalse(pParse, pExpr->pLeft, d2, !jumpIfNull);
@@ -1542,6 +1540,12 @@ void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
case TK_GE:
case TK_NE:
case TK_EQ: {
+ assert( TK_LT==OP_Lt );
+ assert( TK_LE==OP_Le );
+ assert( TK_GT==OP_Gt );
+ assert( TK_GE==OP_Ge );
+ assert( TK_EQ==OP_Eq );
+ assert( TK_NE==OP_Ne );
sqlite3ExprCode(pParse, pExpr->pLeft);
sqlite3ExprCode(pParse, pExpr->pRight);
codeCompare(pParse, pExpr->pLeft, pExpr->pRight, op, dest, jumpIfNull);
@@ -1549,6 +1553,8 @@ void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
}
case TK_ISNULL:
case TK_NOTNULL: {
+ assert( TK_ISNULL==OP_IsNull );
+ assert( TK_NOTNULL==OP_NotNull );
sqlite3ExprCode(pParse, pExpr->pLeft);
sqlite3VdbeAddOp(v, op, 1, dest);
break;
@@ -1597,17 +1603,38 @@ void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
Vdbe *v = pParse->pVdbe;
int op = 0;
if( v==0 || pExpr==0 ) return;
- switch( pExpr->op ){
- case TK_LT: op = OP_Ge; break;
- case TK_LE: op = OP_Gt; break;
- case TK_GT: op = OP_Le; break;
- case TK_GE: op = OP_Lt; break;
- case TK_NE: op = OP_Eq; break;
- case TK_EQ: op = OP_Ne; break;
- case TK_ISNULL: op = OP_NotNull; break;
- case TK_NOTNULL: op = OP_IsNull; break;
- default: break;
- }
+
+ /* The value of pExpr->op and op are related as follows:
+ **
+ ** pExpr->op op
+ ** --------- ----------
+ ** TK_ISNULL OP_NotNull
+ ** TK_NOTNULL OP_IsNull
+ ** TK_NE OP_Eq
+ ** TK_EQ OP_Ne
+ ** TK_GT OP_Le
+ ** TK_LE OP_Gt
+ ** TK_GE OP_Lt
+ ** TK_LT OP_Ge
+ **
+ ** For other values of pExpr->op, op is undefined and unused.
+ ** The value of TK_ and OP_ constants are arranged such that we
+ ** can compute the mapping above using the following expression.
+ ** Assert()s verify that the computation is correct.
+ */
+ op = ((pExpr->op+(TK_ISNULL&1))^1)-(TK_ISNULL&1);
+
+ /* Verify correct alignment of TK_ and OP_ constants
+ */
+ assert( pExpr->op!=TK_ISNULL || op==OP_NotNull );
+ assert( pExpr->op!=TK_NOTNULL || op==OP_IsNull );
+ assert( pExpr->op!=TK_NE || op==OP_Eq );
+ assert( pExpr->op!=TK_EQ || op==OP_Ne );
+ assert( pExpr->op!=TK_LT || op==OP_Ge );
+ assert( pExpr->op!=TK_LE || op==OP_Gt );
+ assert( pExpr->op!=TK_GT || op==OP_Le );
+ assert( pExpr->op!=TK_GE || op==OP_Lt );
+
switch( pExpr->op ){
case TK_AND: {
sqlite3ExprIfFalse(pParse, pExpr->pLeft, dest, jumpIfNull);
diff --git a/src/parse.y b/src/parse.y
index 8d42dfd47..5999e2146 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.139 2004/09/30 14:22:47 drh Exp $
+** @(#) $Id: parse.y,v 1.140 2004/10/04 13:19:24 drh Exp $
*/
%token_prefix TK_
%token_type {Token}
@@ -137,11 +137,17 @@ id(A) ::= ID(X). {A = X;}
// causes them to be assigned integer values that are close together,
// which keeps parser tables smaller.
//
+// The token values assigned to these symbols is determined by the order
+// in which lemon first sees them. It must be the case that ISNULL/NOTNULL,
+// NE/EQ, GT/LE, and GE/LT are separated by only a single value. See
+// the sqlite3ExprIfFalse() routine for additional information on this
+// constraint.
+//
%left OR.
%left AND.
%right NOT.
-%left ISNULL NOTNULL IS LIKE GLOB BETWEEN IN NE EQ.
-%left GT GE LT LE.
+%left IS LIKE GLOB BETWEEN IN ISNULL NOTNULL NE EQ.
+%left GT LE GE LT.
%left BITAND BITOR LSHIFT RSHIFT.
%left PLUS MINUS.
%left STAR SLASH REM.
diff --git a/src/sqliteInt.h b/src/sqliteInt.h
index e8946f256..7b4c4fc0e 100644
--- a/src/sqliteInt.h
+++ b/src/sqliteInt.h
@@ -11,7 +11,7 @@
*************************************************************************
** Internal interface definitions for SQLite.
**
-** @(#) $Id: sqliteInt.h,v 1.325 2004/10/01 02:00:31 drh Exp $
+** @(#) $Id: sqliteInt.h,v 1.326 2004/10/04 13:19:24 drh Exp $
*/
#ifndef _SQLITEINT_H_
#define _SQLITEINT_H_
@@ -767,9 +767,9 @@ struct Token {
struct Expr {
u8 op; /* Operation performed by this node */
char affinity; /* The affinity of the column or 0 if not a column */
- CollSeq *pColl; /* The collation type of the column or 0 */
u8 iDb; /* Database referenced by this expression */
u8 flags; /* Various flags. See below */
+ CollSeq *pColl; /* The collation type of the column or 0 */
Expr *pLeft, *pRight; /* Left and right subnodes */
ExprList *pList; /* A list of expressions used as function arguments
** or in "<expr> IN (<expr-list)" */
diff --git a/src/vdbe.c b/src/vdbe.c
index 5ec829464..327460ca2 100644
--- a/src/vdbe.c
+++ b/src/vdbe.c
@@ -43,7 +43,7 @@
** in this file for details. If in doubt, do not deviate from existing
** commenting and indentation practices when changing or adding code.
**
-** $Id: vdbe.c,v 1.415 2004/09/19 00:50:21 drh Exp $
+** $Id: vdbe.c,v 1.416 2004/10/04 13:19:24 drh Exp $
*/
#include "sqliteInt.h"
#include "os.h"
@@ -184,32 +184,6 @@ static int AggInsert(Agg *p, char *zKey, int nKey){
}
/*
-** Store a pointer to the AggElem currently in focus in *ppElem. Return
-** SQLITE_OK if successful, otherwise an error-code.
-*/
-static int AggInFocus(Agg *p, AggElem **ppElem){
- int rc;
- int res;
-
- if( p->pCurrent ){
- *ppElem = p->pCurrent;
- return SQLITE_OK;
- }
-
- rc = sqlite3BtreeFirst(p->pCsr, &res);
- if( rc!=SQLITE_OK ){
- return rc;
- }
- if( res!=0 ){
- rc = AggInsert(p,"",1);
- *ppElem = p->pCurrent;
- }else{
- rc = sqlite3BtreeData(p->pCsr, 0, 4, (char *)ppElem);
- }
- return rc;
-}
-
-/*
** Pop the stack N times.
*/
static void popStack(Mem **ppTos, int N){
@@ -559,7 +533,9 @@ int sqlite3VdbeExec(
** file looking for lines that begin with "case OP_". The opcodes.h files
** will be filled with #defines that give unique integer values to each
** opcode and the opcodes.c file is filled with an array of strings where
-** each string is the symbolic name for the corresponding opcode.
+** each string is the symbolic name for the corresponding opcode. If the
+** case statement is followed by a comment of the form "/# same as ... #/"
+** that comment is used to determine the particular value of the opcode.
**
** Documentation about VDBE opcodes is generated by scanning this file
** for lines of that contain "Opcode:". That line and all subsequent
@@ -677,7 +653,7 @@ case OP_Integer: {
**
** The string value P3 is converted to a real and pushed on to the stack.
*/
-case OP_Real: {
+case OP_Real: { /* same as TK_FLOAT */
pTos++;
pTos->flags = MEM_Str|MEM_Static|MEM_Term;
pTos->z = pOp->p3;
@@ -694,7 +670,7 @@ case OP_Real: {
** P3 points to a nul terminated UTF-8 string. This opcode is transformed
** into an OP_String before it is executed for the first time.
*/
-case OP_String8: {
+case OP_String8: { /* same as TK_STRING */
pOp->opcode = OP_String;
if( db->enc!=SQLITE_UTF8 && pOp->p3 ){
@@ -745,7 +721,7 @@ case OP_String: {
** The first time this instruction executes, in transforms itself into a
** 'Blob' opcode with a binary blob as P3.
*/
-case OP_HexBlob: {
+case OP_HexBlob: { /* same as TK_BLOB */
pOp->opcode = OP_Blob;
pOp->p1 = strlen(pOp->p3)/2;
if( pOp->p1 ){
@@ -922,7 +898,7 @@ case OP_Callback: {
** When P1==1, this routine makes a copy of the top stack element
** into memory obtained from sqliteMalloc().
*/
-case OP_Concat: {
+case OP_Concat: { /* same as TK_CONCAT */
char *zNew;
int nByte;
int nField;
@@ -1030,11 +1006,11 @@ case OP_Concat: {
** function before the division. Division by zero returns NULL.
** If either operand is NULL, the result is NULL.
*/
-case OP_Add:
-case OP_Subtract:
-case OP_Multiply:
-case OP_Divide:
-case OP_Remainder: {
+case OP_Add: /* same as TK_PLUS */
+case OP_Subtract: /* same as TK_MINUS */
+case OP_Multiply: /* same as TK_STAR */
+case OP_Divide: /* same as TK_SLASH */
+case OP_Remainder: { /* same as TK_REM */
Mem *pNos = &pTos[-1];
assert( pNos>=p->aStack );
if( ((pTos->flags | pNos->flags) & MEM_Null)!=0 ){
@@ -1233,10 +1209,10 @@ case OP_Function: {
** right by N bits where N is the top element on the stack.
** If either operand is NULL, the result is NULL.
*/
-case OP_BitAnd:
-case OP_BitOr:
-case OP_ShiftLeft:
-case OP_ShiftRight: {
+case OP_BitAnd: /* same as TK_BITAND */
+case OP_BitOr: /* same as TK_BITOR */
+case OP_ShiftLeft: /* same as TK_LSHIFT */
+case OP_ShiftRight: { /* same as TK_RSHIFT */
Mem *pNos = &pTos[-1];
int a, b;
@@ -1398,12 +1374,12 @@ case OP_MustBeInt: {
** the 2nd element down on the stack is greater than or equal to the
** top of the stack. See the Eq opcode for additional information.
*/
-case OP_Eq:
-case OP_Ne:
-case OP_Lt:
-case OP_Le:
-case OP_Gt:
-case OP_Ge: {
+case OP_Eq: /* same as TK_EQ */
+case OP_Ne: /* same as TK_NE */
+case OP_Lt: /* same as TK_LT */
+case OP_Le: /* same as TK_LE */
+case OP_Gt: /* same as TK_GT */
+case OP_Ge: { /* same as TK_GE */
Mem *pNos;
int flags;
int res;
@@ -1469,8 +1445,8 @@ case OP_Ge: {
** two values and push the resulting boolean value back onto the
** stack.
*/
-case OP_And:
-case OP_Or: {
+case OP_And: /* same as TK_AND */
+case OP_Or: { /* same as TK_OR */
Mem *pNos = &pTos[-1];
int v1, v2; /* 0==TRUE, 1==FALSE, 2==UNKNOWN or NULL */
@@ -1517,7 +1493,7 @@ case OP_Or: {
** with its absolute value. If the top of the stack is NULL
** its value is unchanged.
*/
-case OP_Negative:
+case OP_Negative: /* same as TK_UMINUS */
case OP_AbsValue: {
assert( pTos>=p->aStack );
if( pTos->flags & MEM_Real ){
@@ -1550,7 +1526,7 @@ case OP_AbsValue: {
** with its complement. If the top of the stack is NULL its value
** is unchanged.
*/
-case OP_Not: {
+case OP_Not: { /* same as TK_NOT */
assert( pTos>=p->aStack );
if( pTos->flags & MEM_Null ) break; /* Do nothing to NULLs */
Integerify(pTos);
@@ -1566,7 +1542,7 @@ case OP_Not: {
** with its ones-complement. If the top of the stack is NULL its
** value is unchanged.
*/
-case OP_BitNot: {
+case OP_BitNot: { /* same as TK_BITNOT */
assert( pTos>=p->aStack );
if( pTos->flags & MEM_Null ) break; /* Do nothing to NULLs */
Integerify(pTos);
@@ -1627,7 +1603,7 @@ case OP_IfNot: {
** to P2. Pop the stack P1 times if P1>0. If P1<0 leave the stack
** unchanged.
*/
-case OP_IsNull: {
+case OP_IsNull: { /* same as TK_ISNULL */
int i, cnt;
Mem *pTerm;
cnt = pOp->p1;
@@ -1650,7 +1626,7 @@ case OP_IsNull: {
** stack if P1 times if P1 is greater than zero. If P1 is less than
** zero then leave the stack unchanged.
*/
-case OP_NotNull: {
+case OP_NotNull: { /* same as TK_NOTNULL */
int i, cnt;
cnt = pOp->p1;
if( cnt<0 ) cnt = -cnt;
@@ -4241,8 +4217,7 @@ case OP_AggFocus: {
case OP_AggSet: {
AggElem *pFocus;
int i = pOp->p2;
- rc = AggInFocus(&p->agg, &pFocus);
- if( rc!=SQLITE_OK ) goto abort_due_to_error;
+ pFocus = p->agg.pCurrent;
assert( pTos>=p->aStack );
if( pFocus==0 ) goto no_mem;
assert( i>=0 && i<p->agg.nMem );
@@ -4260,8 +4235,7 @@ case OP_AggSet: {
case OP_AggGet: {
AggElem *pFocus;
int i = pOp->p2;
- rc = AggInFocus(&p->agg, &pFocus);
- if( rc!=SQLITE_OK ) goto abort_due_to_error;
+ pFocus = p->agg.pCurrent;
if( pFocus==0 ) goto no_mem;
assert( i>=0 && i<p->agg.nMem );
pTos++;