diff --git a/manifest b/manifest index fcc64deb1a..daa7d4f11d 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Version\s1.0.3\s(CVS\s497) -D 2000-08-22T18:30:00 +C Added\slength()\sand\ssubstr()\sfunctions\s(CVS\s143) +D 2000-08-28T15:51:44 F COPYRIGHT 74a8a6531a42e124df07ab5599aad63870fa0bd4 F Makefile.in 036bce328b963f48dbaadbec8cc4144a1fd9e50a F README 51f6a4e7408b34afa5bc1c0485f61b6a4efb6958 @@ -11,7 +11,7 @@ F src/build.c 4d90e9e94750ca80249fc7958c617021d8bb7a50 F src/dbbe.c 226daaf8c095ceb4aff48cad188dad90643f9867 F src/dbbe.h 6337132f904e72ecb28b07390021c241397e4cbf F src/delete.c 4d491eaf61b515516749c7ed68fa3b2ee8a09065 -F src/expr.c 2fa63f086707176d09092e71832f9bbdc6a8ac85 +F src/expr.c e8e350d7baa33bd9ed8701c159eaba5e912e0adb F src/insert.c f146f149ad2422a1dc3bfa7a1651a25940f98958 F src/main.c 9a89579b40e498920f86e89878f52185457b9c2c F src/parse.y 5d199034de5d29ebedb42c1c51f34db4df40cbe5 @@ -19,13 +19,13 @@ F src/select.c d382e96c2221d08367cc87976f2b574537c9de97 F src/shell.c 061186b1a4f0884037d067f0f102ec5d382119b5 F src/shell.tcl 27ecbd63dd88396ad16d81ab44f73e6c0ea9d20e F src/sqlite.h.in d341439fc1432c7d7014bcff5f7b6e914571232c -F src/sqliteInt.h f6d1e139b3bfa4ceff2136684e19d76b53178ec0 +F src/sqliteInt.h b65fdecac7281aafb4c9ff3e79ea1b5546478385 F src/tclsqlite.c 89dc4ba2b521f3e919d6d7aaa4cc1c2aba8e16f3 F src/tokenize.c 097bec5843d4a0fb4509e036fee93bac080c5e73 F src/update.c 51b9ef7434b15e31096155da920302e9db0d27fc F src/util.c b75b33e6bd5d47898bb7ed9fdd0dea4fe7c19b00 -F src/vdbe.c bdedf21230581f0cf73a2dcd8fe23f30cf30ebe6 -F src/vdbe.h 6c5653241633c583549c2d8097394ab52550eb63 +F src/vdbe.c a2372aebfcf2a5ed4530cd956a8cdbb595c67991 +F src/vdbe.h 6413cd0165ac62b0839fe3e077cb7c9f0b736295 F src/where.c 3dfad2ffd0aa994d5eceac88852f7189c8d1d3c8 F test/all.test 0950c135cab7e60c07bd745ccfad1476211e5bd7 F test/copy.test b77a1214bd7756f2849d5c4fa6e715c0ff0c34eb @@ -70,7 +70,7 @@ F www/mingw.tcl fc5f4ba9d336b6e8c97347cc6496d6162461ef60 F www/opcode.tcl cb3a1abf8b7b9be9f3a228d097d6bf8b742c2b6f F www/sqlite.tcl cb0d23d8f061a80543928755ec7775da6e4f362f F www/vdbe.tcl bcbfc33bcdd0ebad95eab31286adb9e1bc289520 -P f255ea6d4bb085a869485c14b4c96af13ca826fa -R d941b15d38d95642a66b6ff4bba2c454 +P d35a1f8b37333e2df86c22c2dbd766132b4931b2 +R 33478b7323acb1d67e1ce4b66b8bba30 U drh -Z cbdf4324aa4508ca2f8e72c3acf62235 +Z a1f7d622d82864a914f4580098647f78 diff --git a/manifest.uuid b/manifest.uuid index 75314479ac..8b147137cd 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -d35a1f8b37333e2df86c22c2dbd766132b4931b2 \ No newline at end of file +0eef538f3de66fede7c88f8be8c3458d84107c3f \ No newline at end of file diff --git a/src/expr.c b/src/expr.c index c94fd247a4..55774f24b4 100644 --- a/src/expr.c +++ b/src/expr.c @@ -24,7 +24,7 @@ ** This file contains routines used for analyzing expressions and ** for generating VDBE code that evaluates expressions. ** -** $Id: expr.c,v 1.18 2000/06/21 13:59:11 drh Exp $ +** $Id: expr.c,v 1.19 2000/08/28 15:51:44 drh Exp $ */ #include "sqliteInt.h" @@ -323,6 +323,8 @@ int sqliteFuncId(Token *pToken){ { "sum", 3, FN_Sum }, { "avg", 3, FN_Avg }, { "fcnt", 4, FN_Fcnt }, /* Used for testing only */ + { "length", 6, FN_Length}, + { "substr", 6, FN_Substr}, }; int i; for(i=0; i1; + break; + } + case FN_Substr: { + too_few_args = n<3; + too_many_args = n>3; + break; + } /* The "fcnt(*)" function always returns the number of fetch ** operations that have occurred so far while processing the ** SQL statement. This information can be used by test procedures @@ -392,6 +404,7 @@ int sqliteExprCheck(Parse *pParse, Expr *pExpr, int allowAgg, int *pIsAgg){ n = 0; break; } + default: break; } if( no_such_func ){ @@ -574,15 +587,37 @@ void sqliteExprCode(Parse *pParse, Expr *pExpr){ int op; int i; ExprList *pList = pExpr->pList; - if( id==FN_Fcnt ){ - sqliteVdbeAddOp(v, OP_Fcnt, 0, 0, 0, 0); - break; - } - op = id==FN_Min ? OP_Min : OP_Max; - for(i=0; inExpr; i++){ - sqliteExprCode(pParse, pList->a[i].pExpr); - if( i>0 ){ - sqliteVdbeAddOp(v, op, 0, 0, 0, 0); + switch( id ){ + case FN_Fcnt: { + sqliteVdbeAddOp(v, OP_Fcnt, 0, 0, 0, 0); + break; + } + case FN_Min: + case FN_Max: { + op = id==FN_Min ? OP_Min : OP_Max; + for(i=0; inExpr; i++){ + sqliteExprCode(pParse, pList->a[i].pExpr); + if( i>0 ){ + sqliteVdbeAddOp(v, op, 0, 0, 0, 0); + } + } + break; + } + case FN_Length: { + sqliteExprCode(pParse, pList->a[0].pExpr); + sqliteVdbeAddOp(v, OP_Strlen, 0, 0, 0, 0); + break; + } + case FN_Substr: { + for(i=0; inExpr; i++){ + sqliteExprCode(pParse, pList->a[i].pExpr); + } + sqliteVdbeAddOp(v, OP_Substr, 0, 0, 0, 0); + break; + } + default: { + /* Can't happen! */ + break; } } break; diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 3e497f3b4f..092feb5b67 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -23,7 +23,7 @@ ************************************************************************* ** Internal interface definitions for SQLite. ** -** @(#) $Id: sqliteInt.h,v 1.29 2000/08/02 13:47:42 drh Exp $ +** @(#) $Id: sqliteInt.h,v 1.30 2000/08/28 15:51:44 drh Exp $ */ #include "sqlite.h" #include "dbbe.h" @@ -99,6 +99,8 @@ int sqlite_iMallocFail; /* Fail sqliteMalloc() after this many calls */ #define FN_Sum 4 #define FN_Avg 5 #define FN_Fcnt 6 +#define FN_Length 7 +#define FN_Substr 8 /* ** Forward references to structures diff --git a/src/vdbe.c b/src/vdbe.c index 4850506855..d258beaa5e 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -41,7 +41,7 @@ ** But other routines are also provided to help in building up ** a program instruction by instruction. ** -** $Id: vdbe.c,v 1.38 2000/08/02 12:26:29 drh Exp $ +** $Id: vdbe.c,v 1.39 2000/08/28 15:51:44 drh Exp $ */ #include "sqliteInt.h" #include @@ -788,6 +788,7 @@ static char *zOpName[] = { 0, "Lt", "Le", "Gt", "Ge", "IsNull", "NotNull", "Negative", "And", "Or", "Not", "Concat", "Noop", + "Strlen", "Substr", }; /* @@ -3130,6 +3131,91 @@ int sqliteVdbeExec( break; } + /* Opcode: Length * * * + ** + ** Interpret the top of the stack as a string. Replace the top of + ** stack with an integer which is the length of the string. + */ + case OP_Strlen: { + int tos = p->tos; + int len; + if( tos<0 ) goto not_enough_stack; + Stringify(p, tos); + len = p->aStack[tos].n-1; + PopStack(p, 1); + p->tos++; + p->aStack[tos].i = len; + p->aStack[tos].flags = STK_Int; + break; + } + + /* Opcode: Substr P1 P2 * + ** + ** This operation pops between 1 and 3 elements from the stack and + ** pushes back a single element. The bottom-most element popped from + ** the stack is a string and the element pushed back is also a string. + ** The other two elements popped are integers. The integers are taken + ** from the stack only if P1 and/or P2 are 0. When P1 or P2 are + ** not zero, the value of the operand is used rather than the integer + ** from the stack. In the sequel, we will use P1 and P2 to describe + ** the two integers, even if those integers are really taken from the + ** stack. + ** + ** The string pushed back onto the stack is a substring of the string + ** that was popped. There are P2 characters in the substring. The + ** first character of the substring is the P1-th character of the + ** original string where the left-most character is 1 (not 0). If P1 + ** is negative, then counting begins at the right instead of at the + ** left. + */ + case OP_Substr: { + int cnt; + int start; + int n; + char *z; + + if( pOp->p2==0 ){ + if( p->tos<0 ) goto not_enough_stack; + Integerify(p, p->tos); + cnt = p->aStack[p->tos].i; + PopStack(p, 1); + }else{ + cnt = pOp->p2; + } + if( pOp->p1==0 ){ + if( p->tos<0 ) goto not_enough_stack; + Integerify(p, p->tos); + start = p->aStack[p->tos].i; + PopStack(p, 1); + }else{ + start = pOp->p1; + } + if( p->tos<0 ) goto not_enough_stack; + Stringify(p, p->tos); + n = p->aStack[p->tos].n - 1; + if( start<0 ){ + start += n; + if( start<0 ){ + cnt += start; + start = 0; + } + } + if( cnt<0 ) cnt = 0; + if( cnt > n ){ + cnt = n; + } + z = sqliteMalloc( cnt+1 ); + if( z==0 ) goto no_mem; + strncpy(z, p->zStack[p->tos], cnt); + z[cnt] = 0; + PopStack(p, 1); + p->tos++; + p->zStack[p->tos] = z; + p->aStack[p->tos].n = cnt + 1; + p->aStack[p->tos].flags = STK_Str|STK_Dyn; + break; + } + /* An other opcode is illegal... */ default: { diff --git a/src/vdbe.h b/src/vdbe.h index bf80b1849b..d349b5dc85 100644 --- a/src/vdbe.h +++ b/src/vdbe.h @@ -27,7 +27,7 @@ ** or VDBE. The VDBE implements an abstract machine that runs a ** simple program to access and modify the underlying database. ** -** $Id: vdbe.h,v 1.11 2000/07/28 14:32:50 drh Exp $ +** $Id: vdbe.h,v 1.12 2000/08/28 15:51:45 drh Exp $ */ #ifndef _SQLITE_VDBE_H_ #define _SQLITE_VDBE_H_ @@ -173,7 +173,10 @@ typedef struct VdbeOp VdbeOp; #define OP_Concat 87 #define OP_Noop 88 -#define OP_MAX 88 +#define OP_Strlen 89 +#define OP_Substr 90 + +#define OP_MAX 90 /* ** Prototypes for the VDBE interface. See comments on the implementation