diff --git a/manifest b/manifest index 941ee16017..b1f1d545ec 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C NULL\svalues\sin\sa\srow\sof\sa\sunique\sindex\scause\sthe\srow\sto\sbe\sdistinct.\nTicket\s#1301.\s\sMore\stesting\sand\soptimization\sneeds\sto\sbe\sdone\son\sthis\nbefore\sclosing\sthe\sticket.\s(CVS\s2526) -D 2005-06-24T03:53:06 +C Remove\sthe\sblob(),\stext()\sand\snumeric()\sfunctions\sadded\sin\s(2524)\sand\r\nreplace\sthem\swith\sthe\sstandard\sCAST\soperator.\r\nTicket\s#1287.\s(CVS\s2527) +D 2005-06-25T18:42:14 F Makefile.in 64a6635ef44a98325e0cffe8d67669920a3dad47 F Makefile.linux-gcc 06be33b2a9ad4f005a5f42b22c4a19dab3cbb5c7 F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028 @@ -32,13 +32,13 @@ F src/attach.c 3615dbe960cbee4aa5ea300b8a213dad36527b0f F src/auth.c 18c5a0befe20f3a58a41e3ddd78f372faeeefe1f F src/btree.c a167f412cf5b269bffba925ac55a1c0a2f749e29 F src/btree.h 41a71ce027db9ddee72cb43df2316bbe3a1d92af -F src/build.c 3b64205934761976857ed3fe884854eb4c3b856a +F src/build.c f2f12fcb4455e247e6fabc46d7168eb42f7194df F src/callback.c 0910b611e0c158f107ee3ff86f8a371654971e2b -F src/date.c 2134ef4388256e8247405178df8a61bd60dc180a +F src/date.c 7444b0900a28da77e57e3337a636873cff0ae940 F src/delete.c 9bb19ede439cf325bc6d6f5995b6393fb85b5162 F src/experimental.c 50c1e3b34f752f4ac10c36f287db095c2b61766d -F src/expr.c 4d6e26da200e0d08233df52fd8d07916d24a6926 -F src/func.c 301b81af2e831b2e929f0ba252739c32a0c756e5 +F src/expr.c 8d4f5e3d06107e1932b534a45bea848aad6b8612 +F src/func.c cbdf7256400ac7d5f020d131261bb2bd41bb631f F src/hash.c 2b1b13f7400e179631c83a1be0c664608c8f021f F src/hash.h 1b0c445e1c89ff2aaad9b4605ba61375af001e84 F src/insert.c d61752504f8a67e28a3bd45288051a587ba899cd @@ -55,7 +55,7 @@ F src/os_win.c fe7b99cfcfb61d9bf54493ddf5857885a657fb89 F src/os_win.h 41a946bea10f61c158ce8645e7646b29d44f122b F src/pager.c 841a2cdddd4275de36cda26ed9dc54ae942660ce F src/pager.h 0d9153d6269d60d04af3dd84a0cc0a96253cf4a4 -F src/parse.y 72cd7553f05fbc7b63ea9476108d0da6237f2818 +F src/parse.y 562246a70c5e4a6bf1ed203119db0843bc926c11 F src/pragma.c dea86dad2f0e872b29632ae9fba526e539a4ddd8 F src/prepare.c d53602d2f8e097225ae7c76ec764ae68f759ba47 F src/printf.c 3d20b21cfecadacecac3fb7274e746cb81d3d357 @@ -63,10 +63,10 @@ F src/random.c 90adff4e73a3b249eb4f1fc2a6ff9cf78c7233a4 F src/select.c 28b752e58955c7920711fbdbfdcd369a2bd09448 F src/shell.c 25b3217d7c64e6497225439d261a253a23efff26 F src/sqlite.h.in e06d5774e9cfa5962376ae988300a9f114a3e3d7 -F src/sqliteInt.h c620e07e0c7e6e09d8623d165427f0f1f659aad5 +F src/sqliteInt.h 2135a5bab820af868bf308f51cdf1adbcb3a85b7 F src/table.c 25b3ff2b39b7d87e8d4a5da0713d68dfc06cbee9 F src/tclsqlite.c af0f002d9d6ab4f7f32b9bee5b57665946e76ad9 -F src/test1.c 5956d1c61b89d84c2b2ab01f065b1cd878917213 +F src/test1.c 96314a056763107646223779bcb2b987944944dd F src/test2.c 716c1809dba8e5be6093703e9cada99d627542dc F src/test3.c 683e1e3819152ffd35da2f201e507228921148d0 F src/test4.c 7c6b9fc33dd1f3f93c7f1ee6e5e6d016afa6c1df @@ -75,14 +75,14 @@ F src/tokenize.c 57ec9926612fb9e325b57a141303573bc20c79bf F src/trigger.c f51dec15921629591cb98bf2e350018e268b109a F src/update.c e96c7b342cd8903c672162f4cf84d2c737943347 F src/utf.c bda5eb85039ef16f2d17004c1e18c96e1ab0a80c -F src/util.c 1cdce9ae9fd17307e00848d63e3bc3300ca7c9fc +F src/util.c 54d5b4d56f0d14d4ff60881b145d1d3d664bb623 F src/vacuum.c 829d9e1a6d7c094b80e0899686670932eafd768c -F src/vdbe.c 5c1f7ccd6a75aa2cf211a9864ff511e15e86957c +F src/vdbe.c 56e892e351eb3ed634c3c239e4ad5c03aecfc2bf F src/vdbe.h 75e466d84d362b0c4498978a9d6b1e6bd32ecf3b F src/vdbeInt.h 4312faf41630a6c215924b6c7c2f39ebb1af8ffb F src/vdbeapi.c 5025a9163107e0a4964212d16e1c4defa13dc5c2 F src/vdbeaux.c 38332d91887817a2146f46b58fff2a8a88ed0278 -F src/vdbemem.c 48a64ae95a9edc6e8d940300dad15d70d1670398 +F src/vdbemem.c da8e8d6f29dd1323f782f000d7cd120027c9ff03 F src/where.c 3a9a2258ab3364655e9ea215ad5ae7bf41813f54 F tclinstaller.tcl 046e3624671962dc50f0481d7c25b38ef803eb42 F test/all.test 7f0988442ab811dfa41793b5b550f5828ce316f3 @@ -112,6 +112,7 @@ F test/btree7.test a6d3b842db22af97dd14b989e90a2fd96066b72f F test/capi2.test f897209386fb21cfdc9267595e0c667ebaca9164 F test/capi3.test 4d848cc55ad6e5f68cf2712716e9fc1fa55d7635 F test/capi3b.test 5b6a66f9f295f79f443b5d3f33187fa5ef6cf336 +F test/cast.test 5c5ebb3edadb04eb0bb172d0e48d52642480e004 F test/collate1.test f79736d2ebf5492167ee4d1f4ab4c09dda776b03 F test/collate2.test 224a632ba04907c049804b08162efd234aa7871f F test/collate3.test 51362bdfb43a72bd2b087d90b2623b0695538e7a @@ -132,7 +133,7 @@ F test/enc2.test d1ab077b84f4d3099246915422b1ab6b81481e0a F test/enc3.test f6a5f0b7b7f3a88f030d3143729b87cd5c86d837 F test/expr.test 54d9d1cc05eb731fa62daa70f2d7163f8a03c54d F test/fkey1.test 81bb13caaa78f58d7d191d7f535529f7c91d821a -F test/func.test f5f9f2bd3f1121ae82eb4d6b3f48b8c52f597895 +F test/func.test b062105b45cf8fb5b386ba137180c0f439eea0c9 F test/hook.test f8605cde4c77b2c6a4a73723bf6c507796a64dda F test/in.test ed134f8d477a6280297ced1646de83cccf8f196d F test/index.test 51e01a0928b4b61228917ddd8c6c0e2466547f6f @@ -225,7 +226,7 @@ F tool/lempar.c f0c30abcae762a7d1eb37cd88b2232ab8dd625fb F tool/memleak.awk 4e7690a51bf3ed757e611273d43fe3f65b510133 F tool/memleak2.awk 9cc20c8e8f3c675efac71ea0721ee6874a1566e8 F tool/memleak3.tcl 009da0ea82dc5893edca76cf1a21fb7260e9412e -F tool/mkkeywordhash.c 596389943f516bf6eaddd46659e7b87b16ea7c33 +F tool/mkkeywordhash.c e4ba5010348303b1dbab41326191e7f37f8a036f F tool/mkopts.tcl 66ac10d240cc6e86abd37dc908d50382f84ff46e x F tool/opcodeDoc.awk b3a2a3d5d3075b8bd90b7afe24283efdd586659c F tool/report1.txt 9eae07f26a8fc53889b45fc833a66a33daa22816 @@ -264,7 +265,7 @@ F www/faq.tcl 49f31a703f74c71ce66da646aaf18b07a5042672 F www/fileformat.tcl 900c95b9633abc3dcfc384d9ddd8eb4876793059 F www/formatchng.tcl 053ddb73646701353a5b1c9ca6274d5900739b45 F www/index.tcl 9527f4eed69739cf5f81b3d75e0478d1c84d0a8a -F www/lang.tcl 727b4769fbad2727b0f867acaeb8706d554edb35 +F www/lang.tcl be57d5f23a46b8afa3753b38f65ea22d26499b80 F www/lockingv3.tcl f59b19d6c8920a931f096699d6faaf61c05db55f F www/mingw.tcl d96b451568c5d28545fefe0c80bee3431c73f69c F www/nulls.tcl ec35193f92485b87b90a994a01d0171b58823fcf @@ -281,7 +282,7 @@ F www/tclsqlite.tcl 425be741b8ae664f55cb1ef2371aab0a75109cf9 F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0 F www/version3.tcl a99cf5f6d8bd4d5537584a2b342f0fb9fa601d8b F www/whentouse.tcl 528299b8316726dbcc5548e9aa0648c8b1bd055b -P bcf62dc7a1e8e7a3180138cf9b8944eb8fbd5490 -R fa67143595d3d7217f6f8facb2f20078 +P 06a71b162b032fc5b56d18919a784d4ee94dde7c +R 232a3463ca338974c39f0662b7bf2007 U drh -Z 382ef1453175c5aaab493342b42488e6 +Z 47d0af1509bc0a39043a3f760e0ac13b diff --git a/manifest.uuid b/manifest.uuid index d8b0fd2cd5..de827addf7 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -06a71b162b032fc5b56d18919a784d4ee94dde7c \ No newline at end of file +17631785f9ee8ab280c82677eb53886912e085bc \ No newline at end of file diff --git a/src/build.c b/src/build.c index e0a6e5953b..d9d5bb43ba 100644 --- a/src/build.c +++ b/src/build.c @@ -22,7 +22,7 @@ ** COMMIT ** ROLLBACK ** -** $Id: build.c,v 1.328 2005/06/24 03:53:06 drh Exp $ +** $Id: build.c,v 1.329 2005/06/25 18:42:14 drh Exp $ */ #include "sqliteInt.h" #include @@ -902,11 +902,11 @@ void sqlite3AddNotNull(Parse *pParse, int onError){ ** If none of the substrings in the above table are found, ** SQLITE_AFF_NUMERIC is returned. */ -static char sqlite3AffinityType(const char *zType, int nType){ +char sqlite3AffinityType(const Token *pType){ u32 h = 0; char aff = SQLITE_AFF_NUMERIC; - const unsigned char *zIn = zType; - const unsigned char *zEnd = (zIn+nType); + const unsigned char *zIn = pType->z; + const unsigned char *zEnd = &pType->z[pType->n]; while( zIn!=zEnd ){ h = (h<<8) + sqlite3UpperToLower[*zIn]; @@ -938,21 +938,17 @@ static char sqlite3AffinityType(const char *zType, int nType){ ** that contains the typename of the column and store that string ** in zType. */ -void sqlite3AddColumnType(Parse *pParse, Token *pFirst, Token *pLast){ +void sqlite3AddColumnType(Parse *pParse, Token *pType){ Table *p; - int i, j; - int n; - char *z; - const unsigned char *zIn; - + int i; Column *pCol; + if( (p = pParse->pNewTable)==0 ) return; i = p->nCol-1; if( i<0 ) return; pCol = &p->aCol[i]; - zIn = pFirst->z; - n = pLast->n + (pLast->z - zIn); assert( pCol->zType==0 ); +#if 0 z = pCol->zType = sqliteMallocRaw(n+1); if( z==0 ) return; for(i=j=0; iaffinity = sqlite3AffinityType(z, n); +#endif + pCol->zType = sqlite3NameFromToken(pType); + pCol->affinity = sqlite3AffinityType(pType); } /* diff --git a/src/date.c b/src/date.c index 5207569161..35c0bf64a8 100644 --- a/src/date.c +++ b/src/date.c @@ -16,7 +16,7 @@ ** sqlite3RegisterDateTimeFunctions() found at the bottom of the file. ** All other code has file scope. ** -** $Id: date.c,v 1.44 2005/03/21 00:43:44 drh Exp $ +** $Id: date.c,v 1.45 2005/06/25 18:42:14 drh Exp $ ** ** NOTES: ** @@ -124,11 +124,7 @@ static int getDigits(const char *zDate, ...){ ** Read text from z[] and convert into a floating point number. Return ** the number of digits converted. */ -static int getValue(const char *z, double *pR){ - const char *zEnd; - *pR = sqlite3AtoF(z, &zEnd); - return zEnd - z; -} +#define getValue sqlite3AtoF /* ** Parse a timezone extension on the end of a date-time. @@ -320,7 +316,7 @@ static int parseDateOrTime(const char *zDate, DateTime *p){ p->validJD = 1; return 0; }else if( sqlite3IsNumber(zDate, 0, SQLITE_UTF8) ){ - p->rJD = sqlite3AtoF(zDate, 0); + getValue(zDate, &p->rJD); p->validJD = 1; return 0; } diff --git a/src/expr.c b/src/expr.c index 4f21800e55..efac977660 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.207 2005/06/22 08:48:06 drh Exp $ +** $Id: expr.c,v 1.208 2005/06/25 18:42:14 drh Exp $ */ #include "sqliteInt.h" #include @@ -34,12 +34,18 @@ ** SELECT * FROM t1 WHERE (select a from t1); */ char sqlite3ExprAffinity(Expr *pExpr){ - if( pExpr->op==TK_AS ){ + int op = pExpr->op; + if( op==TK_AS ){ return sqlite3ExprAffinity(pExpr->pLeft); } - if( pExpr->op==TK_SELECT ){ + if( op==TK_SELECT ){ return sqlite3ExprAffinity(pExpr->pSelect->pEList->a[0].pExpr); } +#ifndef SQLITE_OMIT_CAST + if( op==TK_CAST ){ + return sqlite3AffinityType(&pExpr->token); + } +#endif return pExpr->affinity; } @@ -51,7 +57,7 @@ CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr){ CollSeq *pColl = 0; if( pExpr ){ pColl = pExpr->pColl; - if( pExpr->op==TK_AS && !pColl ){ + if( (pExpr->op==TK_AS || pExpr->op==TK_CAST) && !pColl ){ return sqlite3ExprCollSeq(pParse, pExpr->pLeft); } } @@ -1427,6 +1433,22 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){ sqlite3VdbeAddOp(v, OP_MemLoad, pExpr->iTable, 0); break; } +#ifndef SQLITE_OMIT_CAST + case TK_CAST: { + /* Expressions of the form: CAST(pLeft AS token) */ + int aff, op; + sqlite3ExprCode(pParse, pExpr->pLeft); + aff = sqlite3AffinityType(&pExpr->token); + switch( aff ){ + case SQLITE_AFF_INTEGER: op = OP_ToInt; break; + case SQLITE_AFF_NUMERIC: op = OP_ToNumeric; break; + case SQLITE_AFF_TEXT: op = OP_ToText; break; + case SQLITE_AFF_NONE: op = OP_ToBlob; break; + } + sqlite3VdbeAddOp(v, op, 0, 0); + break; + } +#endif /* SQLITE_OMIT_CAST */ case TK_LT: case TK_LE: case TK_GT: diff --git a/src/func.c b/src/func.c index d13ba437cb..7e8feadc0d 100644 --- a/src/func.c +++ b/src/func.c @@ -16,7 +16,7 @@ ** sqliteRegisterBuildinFunctions() found at the bottom of the file. ** All other code has file scope. ** -** $Id: func.c,v 1.99 2005/06/22 10:53:59 drh Exp $ +** $Id: func.c,v 1.100 2005/06/25 18:42:14 drh Exp $ */ #include "sqliteInt.h" #include @@ -78,92 +78,6 @@ static void typeofFunc( sqlite3_result_text(context, z, -1, SQLITE_STATIC); } -/* -** Convert the argument to a numeric type. -*/ -static void numericFunc( - sqlite3_context *context, - int argc, - sqlite3_value **argv -){ - const char *z = 0; - switch( sqlite3_value_type(argv[0]) ){ - case SQLITE_NULL: { - sqlite3_result_int(context, 0); - break; - } - case SQLITE_INTEGER: - case SQLITE_FLOAT: { - sqlite3_result_value(context, argv[0]); - break; - } - case SQLITE_TEXT: - case SQLITE_BLOB: { - z = sqlite3_value_text(argv[0]); - while( *z && *z!='.' ){ z++; } - if( *z ){ - sqlite3_result_double(context, sqlite3_value_double(argv[0])); - }else{ - sqlite3_result_int64(context, sqlite3_value_int64(argv[0])); - } - break; - } - } -} - -/* -** Convert the argument to TEXT -*/ -static void textFunc( - sqlite3_context *context, - int argc, - sqlite3_value **argv -){ - switch( sqlite3_value_type(argv[0]) ){ - case SQLITE_NULL: { - sqlite3_result_text(context, "", 0, SQLITE_STATIC); - break; - } - case SQLITE_BLOB: - case SQLITE_INTEGER: - case SQLITE_FLOAT: { - sqlite3_result_text(context, sqlite3_value_text(argv[0]), - sqlite3_value_bytes(argv[0]), SQLITE_TRANSIENT); - break; - } - case SQLITE_TEXT: { - sqlite3_result_value(context, argv[0]); - break; - } - } -} - -/* -** Convert the argument to TEXT -*/ -static void blobFunc( - sqlite3_context *context, - int argc, - sqlite3_value **argv -){ - switch( sqlite3_value_type(argv[0]) ){ - case SQLITE_NULL: { - sqlite3_result_blob(context, "", 0, SQLITE_STATIC); - break; - } - case SQLITE_TEXT: - case SQLITE_INTEGER: - case SQLITE_FLOAT: { - sqlite3_result_blob(context, sqlite3_value_text(argv[0]), - sqlite3_value_bytes(argv[0]), SQLITE_TRANSIENT); - break; - } - case SQLITE_BLOB: { - sqlite3_result_value(context, argv[0]); - break; - } - } -} /* ** Implementation of the length() function @@ -1058,9 +972,6 @@ void sqlite3RegisterBuiltinFunctions(sqlite3 *db){ { "last_insert_rowid", 0, 1, SQLITE_UTF8, 0, last_insert_rowid }, { "changes", 0, 1, SQLITE_UTF8, 0, changes }, { "total_changes", 0, 1, SQLITE_UTF8, 0, total_changes }, - { "text", 1, 0, SQLITE_UTF8, 0, textFunc }, - { "numeric", 1, 0, SQLITE_UTF8, 0, numericFunc }, - { "blob", 1, 0, SQLITE_UTF8, 0, blobFunc }, #ifdef SQLITE_SOUNDEX { "soundex", 1, 0, SQLITE_UTF8, 0, soundexFunc}, #endif diff --git a/src/parse.y b/src/parse.y index 1f7c8af333..bcb0014a33 100644 --- a/src/parse.y +++ b/src/parse.y @@ -14,12 +14,23 @@ ** the parser. Lemon will also generate a header file containing ** numeric codes for all of the tokens. ** -** @(#) $Id: parse.y,v 1.172 2005/05/23 17:26:51 drh Exp $ +** @(#) $Id: parse.y,v 1.173 2005/06/25 18:42:14 drh Exp $ */ + +// All token codes are small integers with #defines that begin with "TK_" %token_prefix TK_ + +// The type of the data attached to each token is Token. This is also the +// default type for non-terminals. +// %token_type {Token} %default_type {Token} + +// The generated parser function takes a 4th argument as follows: %extra_argument {Parse *pParse} + +// This code runs whenever there is a syntax error +// %syntax_error { if( pParse->zErrMsg==0 ){ if( TOKEN.z[0] ){ @@ -29,7 +40,14 @@ } } } + +// The name of the generated procedure that implements the parser +// is as follows: %name sqlite3Parser + +// The following text is included near the beginning of the C source +// code file that implements the parser. +// %include { #include "sqliteInt.h" #include "parse.h" @@ -126,9 +144,10 @@ create_table_args ::= AS select(S). { columnlist ::= columnlist COMMA column. columnlist ::= column. -// About the only information used for a column is the name of the -// column. The type is always just "text". But the code will accept -// an elaborate typename. Perhaps someday we'll do something with it. +// A "column" is a complete description of a single column in a +// CREATE TABLE statement. This includes the column name, its +// datatype, and other keywords such as PRIMARY KEY, UNIQUE, REFERENCES, +// NOT NULL and so forth. // column(A) ::= columnid(X) type carglist. { A.z = X.z; @@ -151,7 +170,7 @@ id(A) ::= ID(X). {A = X;} // This obviates the need for the "id" nonterminal. // %fallback ID - ABORT AFTER ASC ATTACH BEFORE BEGIN CASCADE CONFLICT + ABORT AFTER ASC ATTACH BEFORE BEGIN CASCADE CAST CONFLICT DATABASE DEFERRED DESC DETACH EACH END EXCLUSIVE EXPLAIN FAIL FOR IGNORE IMMEDIATE INITIALLY INSTEAD LIKE_KW MATCH KEY OF OFFSET PRAGMA RAISE REPLACE RESTRICT ROW STATEMENT @@ -198,17 +217,32 @@ nm(A) ::= ID(X). {A = X;} nm(A) ::= STRING(X). {A = X;} nm(A) ::= JOIN_KW(X). {A = X;} +// A typetoken is really one or more tokens that form a type name such +// as can be found after the column name in a CREATE TABLE statement. +// Multiple tokens are concatenated to form the value of the typetoken. +// +%type typetoken {Token} type ::= . -type ::= typename(X). {sqlite3AddColumnType(pParse,&X,&X);} -type ::= typename(X) LP signed RP(Y). {sqlite3AddColumnType(pParse,&X,&Y);} -type ::= typename(X) LP signed COMMA signed RP(Y). - {sqlite3AddColumnType(pParse,&X,&Y);} +type ::= typetoken(X). {sqlite3AddColumnType(pParse,&X);} +typetoken(A) ::= typename(X). {A = X;} +typetoken(A) ::= typename(X) LP signed RP(Y). { + A.z = X.z; + A.n = &Y.z[Y.n] - X.z; +} +typetoken(A) ::= typename(X) LP signed COMMA signed RP(Y). { + A.z = X.z; + A.n = &Y.z[Y.n] - X.z; +} %type typename {Token} typename(A) ::= ids(X). {A = X;} typename(A) ::= typename(X) ids(Y). {A.z=X.z; A.n=Y.n+(Y.z-X.z);} %type signed {int} signed(A) ::= plus_num(X). { A = atoi(X.z); } signed(A) ::= minus_num(X). { A = -atoi(X.z); } + +// "carglist" is a list of additional constraints that come after the +// column name and column type in a CREATE TABLE statement. +// carglist ::= carglist carg. carglist ::= . carg ::= CONSTRAINT nm ccons. @@ -619,6 +653,12 @@ expr(A) ::= VARIABLE(X). { Expr *pExpr = A = sqlite3Expr(TK_VARIABLE, 0, 0, pToken); sqlite3ExprAssignVarNumber(pParse, pExpr); } +%ifndef SQLITE_OMIT_CAST +expr(A) ::= CAST(X) LP expr(E) AS typetoken(T) RP(Y). { + A = sqlite3Expr(TK_CAST, E, 0, &T); + sqlite3ExprSpan(A,&X,&Y); +} +%endif // SQLITE_OMIT_CAST expr(A) ::= ID(X) LP exprlist(Y) RP(E). { A = sqlite3ExprFunction(Y, &X); sqlite3ExprSpan(A,&X,&E); diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 966090dc0e..cac864c430 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -11,7 +11,7 @@ ************************************************************************* ** Internal interface definitions for SQLite. ** -** @(#) $Id: sqliteInt.h,v 1.387 2005/06/12 21:35:52 drh Exp $ +** @(#) $Id: sqliteInt.h,v 1.388 2005/06/25 18:42:14 drh Exp $ */ #ifndef _SQLITEINT_H_ #define _SQLITEINT_H_ @@ -1369,7 +1369,7 @@ void sqlite3StartTable(Parse*,Token*,Token*,Token*,int,int); void sqlite3AddColumn(Parse*,Token*); void sqlite3AddNotNull(Parse*, int); void sqlite3AddPrimaryKey(Parse*, ExprList*, int, int); -void sqlite3AddColumnType(Parse*,Token*,Token*); +void sqlite3AddColumnType(Parse*,Token*); void sqlite3AddDefaultValue(Parse*,Expr*); void sqlite3AddCollateType(Parse*, const char*, int); void sqlite3EndTable(Parse*,Token*,Token*,Select*); @@ -1508,7 +1508,7 @@ int sqlite3FixSelect(DbFixer*, Select*); int sqlite3FixExpr(DbFixer*, Expr*); int sqlite3FixExprList(DbFixer*, ExprList*); int sqlite3FixTriggerStep(DbFixer*, TriggerStep*); -double sqlite3AtoF(const char *z, const char **); +int sqlite3AtoF(const char *z, double*); char *sqlite3_snprintf(int,char*,const char*,...); int sqlite3GetInt32(const char *, int*); int sqlite3FitsIn64Bits(const char *); @@ -1563,6 +1563,7 @@ void sqlite3AlterFinishAddColumn(Parse *, Token *); void sqlite3AlterBeginAddColumn(Parse *, SrcList *); const char *sqlite3TestErrorName(int); CollSeq *sqlite3GetCollSeq(sqlite3*, CollSeq *, const char *, int); +char sqlite3AffinityType(const Token*); #ifdef SQLITE_SSE #include "sseInt.h" diff --git a/src/test1.c b/src/test1.c index 73159910f2..dd7e06cd92 100644 --- a/src/test1.c +++ b/src/test1.c @@ -13,7 +13,7 @@ ** is not included in the SQLite library. It is used for automated ** testing of the SQLite library. ** -** $Id: test1.c,v 1.144 2005/06/12 22:01:43 drh Exp $ +** $Id: test1.c,v 1.145 2005/06/25 18:42:14 drh Exp $ */ #include "sqliteInt.h" #include "tcl.h" @@ -2794,6 +2794,12 @@ static void set_options(Tcl_Interp *interp){ Tcl_SetVar2(interp, "sqlite_options", "bloblit", "1", TCL_GLOBAL_ONLY); #endif +#ifdef SQLITE_OMIT_CAST + Tcl_SetVar2(interp, "sqlite_options", "cast", "0", TCL_GLOBAL_ONLY); +#else + Tcl_SetVar2(interp, "sqlite_options", "cast", "1", TCL_GLOBAL_ONLY); +#endif + #ifdef SQLITE_OMIT_COMPLETE Tcl_SetVar2(interp, "sqlite_options", "complete", "0", TCL_GLOBAL_ONLY); #else diff --git a/src/util.c b/src/util.c index 23794123ea..80fc41da26 100644 --- a/src/util.c +++ b/src/util.c @@ -14,7 +14,7 @@ ** This file contains functions for allocating memory, comparing ** strings, and stuff like that. ** -** $Id: util.c,v 1.137 2005/06/14 16:04:06 drh Exp $ +** $Id: util.c,v 1.138 2005/06/25 18:42:15 drh Exp $ */ #include "sqliteInt.h" #include @@ -565,8 +565,9 @@ int sqlite3IsNumber(const char *z, int *realnum, u8 enc){ ** of "." depending on how locale is set. But that would cause problems ** for SQL. So this routine always uses "." regardless of locale. */ -double sqlite3AtoF(const char *z, const char **pzEnd){ +int sqlite3AtoF(const char *z, double *pResult){ int sign = 1; + const char *zBegin = z; LONGDOUBLE_TYPE v1 = 0.0; if( *z=='-' ){ sign = -1; @@ -613,8 +614,8 @@ double sqlite3AtoF(const char *z, const char **pzEnd){ v1 *= scale; } } - if( pzEnd ) *pzEnd = z; - return sign<0 ? -v1 : v1; + *pResult = sign<0 ? -v1 : v1; + return z - zBegin; } /* diff --git a/src/vdbe.c b/src/vdbe.c index 4d0124153a..15305116c3 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.471 2005/06/24 03:53:06 drh Exp $ +** $Id: vdbe.c,v 1.472 2005/06/25 18:42:15 drh Exp $ */ #include "sqliteInt.h" #include "os.h" @@ -1379,6 +1379,94 @@ case OP_MustBeInt: { /* no-push */ break; } +#ifndef SQLITE_OMIT_CAST +/* Opcode: ToInt * * * +** +** Force the value on the top of the stack to be an integer. If +** The value is currently a real number, drop its fractional part. +** If the value is text or blob, try to convert it to an integer using the +** equivalent of atoi() and store 0 if no such conversion is possible. +** +** A NULL value is not changed by this routine. It remains NULL. +*/ +case OP_ToInt: { /* no-push */ + assert( pTos>=p->aStack ); + if( pTos->flags & MEM_Null ) break; + assert( MEM_Str==(MEM_Blob>>3) ); + pTos->flags |= (pTos->flags&MEM_Blob)>>3; + applyAffinity(pTos, SQLITE_AFF_INTEGER, db->enc); + sqlite3VdbeMemIntegerify(pTos); + break; +} + +/* Opcode: ToNumeric * * * +** +** Force the value on the top of the stack to be numeric (either an +** integer or a floating-point number. +** If the value is text or blob, try to convert it to an using the +** equivalent of atoi() or atof() and store 0 if no such conversion +** is possible. +** +** A NULL value is not changed by this routine. It remains NULL. +*/ +case OP_ToNumeric: { /* no-push */ + assert( pTos>=p->aStack ); + if( pTos->flags & MEM_Null ) break; + assert( MEM_Str==(MEM_Blob>>3) ); + pTos->flags |= (pTos->flags&MEM_Blob)>>3; + applyAffinity(pTos, SQLITE_AFF_NUMERIC, db->enc); + if( (pTos->flags & (MEM_Int|MEM_Real))==0 ){ + sqlite3VdbeMemRealify(pTos); + }else{ + sqlite3VdbeMemRelease(pTos); + } + assert( (pTos->flags & MEM_Dyn)==0 ); + pTos->flags &= (MEM_Int|MEM_Real); + break; +} + +/* Opcode: ToText * * * +** +** Force the value on the top of the stack to be text. +** If the value is numeric, convert it to an using the +** equivalent of printf(). Blob values are unchanged and +** are afterwards simply interpreted as text. +** +** A NULL value is not changed by this routine. It remains NULL. +*/ +case OP_ToText: { /* no-push */ + assert( pTos>=p->aStack ); + if( pTos->flags & MEM_Null ) break; + assert( MEM_Str==(MEM_Blob>>3) ); + pTos->flags |= (pTos->flags&MEM_Blob)>>3; + applyAffinity(pTos, SQLITE_AFF_TEXT, db->enc); + assert( pTos->flags & MEM_Str ); + pTos->flags &= ~(MEM_Int|MEM_Real|MEM_Blob); + break; +} + +/* Opcode: ToBlob * * * +** +** Force the value on the top of the stack to be a BLOB. +** If the value is numeric, convert it to a string first. +** Strings are simply reinterpreted as blobs with no change +** to the underlying data. +** +** A NULL value is not changed by this routine. It remains NULL. +*/ +case OP_ToBlob: { /* no-push */ + assert( pTos>=p->aStack ); + if( pTos->flags & MEM_Null ) break; + if( (pTos->flags & MEM_Blob)==0 ){ + applyAffinity(pTos, SQLITE_AFF_TEXT, db->enc); + assert( pTos->flags & MEM_Str ); + pTos->flags |= MEM_Blob; + } + pTos->flags &= ~(MEM_Int|MEM_Real|MEM_Str); + break; +} +#endif /* SQLITE_OMIT_CAST */ + /* Opcode: Eq P1 P2 P3 ** ** Pop the top two elements from the stack. If they are equal, then @@ -2154,6 +2242,7 @@ case OP_MakeRecord: { pTos->flags = MEM_Blob | MEM_Dyn; pTos->xDel = 0; } + pTos->enc = SQLITE_UTF8; /* In case the blob is ever converted to text */ /* If a NULL was encountered and jumpIfNull is non-zero, take the jump. */ if( jumpIfNull && containsNull ){ @@ -3289,6 +3378,7 @@ case OP_RowData: { }else{ pTos->flags = MEM_Null; } + pTos->enc = SQLITE_UTF8; /* In case the blob is ever cast to text */ break; } diff --git a/src/vdbemem.c b/src/vdbemem.c index f08671f249..37113b90d8 100644 --- a/src/vdbemem.c +++ b/src/vdbemem.c @@ -256,12 +256,14 @@ double sqlite3VdbeRealValue(Mem *pMem){ }else if( pMem->flags & MEM_Int ){ return (double)pMem->i; }else if( pMem->flags & (MEM_Str|MEM_Blob) ){ + double val = 0.0; if( sqlite3VdbeChangeEncoding(pMem, SQLITE_UTF8) || sqlite3VdbeMemNulTerminate(pMem) ){ return SQLITE_NOMEM; } assert( pMem->z ); - return sqlite3AtoF(pMem->z, 0); + sqlite3AtoF(pMem->z, &val); + return val; }else{ return 0.0; } @@ -406,6 +408,7 @@ int sqlite3VdbeMemSetStr( switch( enc ){ case 0: pMem->flags |= MEM_Blob; + pMem->enc = SQLITE_UTF8; break; case SQLITE_UTF8: diff --git a/test/cast.test b/test/cast.test new file mode 100644 index 0000000000..04a36c4d3a --- /dev/null +++ b/test/cast.test @@ -0,0 +1,184 @@ +# 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 the CAST operator. +# +# $Id: cast.test,v 1.1 2005/06/25 18:42:16 drh Exp $ + +set testdir [file dirname $argv0] +source $testdir/tester.tcl + +# Only run these tests if the build includes the CAST operator +ifcapable !cast { + finish_test + return +} + +# Tests for the CAST( AS blob), CAST( AS text) and CAST( AS numeric) built-ins +# +do_test cast-1.1 { + execsql {SELECT x'616263'} +} abc +do_test cast-1.2 { + execsql {SELECT typeof(x'616263')} +} blob +do_test cast-1.3 { + execsql {SELECT CAST(x'616263' AS text)} +} abc +do_test cast-1.4 { + execsql {SELECT typeof(CAST(x'616263' AS text))} +} text +do_test cast-1.5 { + execsql {SELECT CAST(x'616263' AS numeric)} +} 0.0 +do_test cast-1.6 { + execsql {SELECT typeof(CAST(x'616263' AS numeric))} +} real +do_test cast-1.7 { + execsql {SELECT CAST(x'616263' AS blob)} +} abc +do_test cast-1.8 { + execsql {SELECT typeof(CAST(x'616263' AS blob))} +} blob +do_test cast-1.9 { + execsql {SELECT CAST(x'616263' AS integer)} +} 0 +do_test cast-1.10 { + execsql {SELECT typeof(CAST(x'616263' AS integer))} +} integer +do_test cast-1.11 { + execsql {SELECT null} +} {{}} +do_test cast-1.12 { + execsql {SELECT typeof(NULL)} +} null +do_test cast-1.13 { + execsql {SELECT CAST(NULL AS text)} +} {{}} +do_test cast-1.14 { + execsql {SELECT typeof(CAST(NULL AS text))} +} null +do_test cast-1.15 { + execsql {SELECT CAST(NULL AS numeric)} +} {{}} +do_test cast-1.16 { + execsql {SELECT typeof(CAST(NULL AS numeric))} +} null +do_test cast-1.17 { + execsql {SELECT CAST(NULL AS blob)} +} {{}} +do_test cast-1.18 { + execsql {SELECT typeof(CAST(NULL AS blob))} +} null +do_test cast-1.19 { + execsql {SELECT CAST(NULL AS integer)} +} {{}} +do_test cast-1.20 { + execsql {SELECT typeof(CAST(NULL AS integer))} +} null +do_test cast-1.21 { + execsql {SELECT 123} +} {123} +do_test cast-1.22 { + execsql {SELECT typeof(123)} +} integer +do_test cast-1.23 { + execsql {SELECT CAST(123 AS text)} +} {123} +do_test cast-1.24 { + execsql {SELECT typeof(CAST(123 AS text))} +} text +do_test cast-1.25 { + execsql {SELECT CAST(123 AS numeric)} +} 123 +do_test cast-1.26 { + execsql {SELECT typeof(CAST(123 AS numeric))} +} integer +do_test cast-1.27 { + execsql {SELECT CAST(123 AS blob)} +} {123} +do_test cast-1.28 { + execsql {SELECT typeof(CAST(123 AS blob))} +} blob +do_test cast-1.29 { + execsql {SELECT CAST(123 AS integer)} +} {123} +do_test cast-1.30 { + execsql {SELECT typeof(CAST(123 AS integer))} +} integer +do_test cast-1.31 { + execsql {SELECT 123.456} +} {123.456} +do_test cast-1.32 { + execsql {SELECT typeof(123.456)} +} real +do_test cast-1.33 { + execsql {SELECT CAST(123.456 AS text)} +} {123.456} +do_test cast-1.34 { + execsql {SELECT typeof(CAST(123.456 AS text))} +} text +do_test cast-1.35 { + execsql {SELECT CAST(123.456 AS numeric)} +} 123.456 +do_test cast-1.36 { + execsql {SELECT typeof(CAST(123.456 AS numeric))} +} real +do_test cast-1.37 { + execsql {SELECT CAST(123.456 AS blob)} +} {123.456} +do_test cast-1.38 { + execsql {SELECT typeof(CAST(123.456 AS blob))} +} blob +do_test cast-1.39 { + execsql {SELECT CAST(123.456 AS integer)} +} {123} +do_test cast-1.38 { + execsql {SELECT typeof(CAST(123.456 AS integer))} +} integer +do_test cast-1.41 { + execsql {SELECT '123abc'} +} {123abc} +do_test cast-1.42 { + execsql {SELECT typeof('123abc')} +} text +do_test cast-1.43 { + execsql {SELECT CAST('123abc' AS text)} +} {123abc} +do_test cast-1.44 { + execsql {SELECT typeof(CAST('123abc' AS text))} +} text +do_test cast-1.45 { + execsql {SELECT CAST('123abc' AS numeric)} +} 123.0 +do_test cast-1.46 { + execsql {SELECT typeof(CAST('123abc' AS numeric))} +} real +do_test cast-1.47 { + execsql {SELECT CAST('123abc' AS blob)} +} {123abc} +do_test cast-1.48 { + execsql {SELECT typeof(CAST('123abc' AS blob))} +} blob +do_test cast-1.49 { + execsql {SELECT CAST('123abc' AS integer)} +} 123 +do_test cast-1.50 { + execsql {SELECT typeof(CAST('123abc' AS integer))} +} integer +do_test cast-1.51 { + execsql {SELECT CAST('123.5abc' AS numeric)} +} 123.5 +do_test cast-1.53 { + execsql {SELECT CAST('123.5abc' AS integer)} +} 123 + +finish_test diff --git a/test/func.test b/test/func.test index ab8b6f6df7..d8e5c3f09d 100644 --- a/test/func.test +++ b/test/func.test @@ -11,7 +11,7 @@ # This file implements regression tests for SQLite library. The # focus of this file is testing built-in functions. # -# $Id: func.test,v 1.35 2005/06/22 10:53:59 drh Exp $ +# $Id: func.test,v 1.36 2005/06/25 18:42:16 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl @@ -485,134 +485,6 @@ do_test func-16.1 { } } {X'616263' NULL} -# Tests for the blob(), text() and numeric() built-ins -# -do_test func-17.1 { - execsql {SELECT x'616263'} -} abc -do_test func-17.2 { - execsql {SELECT typeof(x'616263')} -} blob -do_test func-17.3 { - execsql {SELECT text(x'616263')} -} abc -do_test func-17.4 { - execsql {SELECT typeof(text(x'616263'))} -} text -do_test func-17.5 { - execsql {SELECT numeric(x'616263')} -} 0 -do_test func-17.6 { - execsql {SELECT typeof(numeric(x'616263'))} -} integer -do_test func-17.7 { - execsql {SELECT blob(x'616263')} -} abc -do_test func-17.8 { - execsql {SELECT typeof(blob(x'616263'))} -} blob -do_test func-17.11 { - execsql {SELECT null} -} {{}} -do_test func-17.12 { - execsql {SELECT typeof(NULL)} -} null -do_test func-17.13 { - execsql {SELECT text(NULL)} -} {{}} -do_test func-17.14 { - execsql {SELECT typeof(text(NULL))} -} text -do_test func-17.15 { - execsql {SELECT numeric(NULL)} -} 0 -do_test func-17.16 { - execsql {SELECT typeof(numeric(NULL))} -} integer -do_test func-17.17 { - execsql {SELECT blob(NULL)} -} {{}} -do_test func-17.18 { - execsql {SELECT typeof(blob(NULL))} -} blob -do_test func-17.21 { - execsql {SELECT 123} -} {123} -do_test func-17.22 { - execsql {SELECT typeof(123)} -} integer -do_test func-17.23 { - execsql {SELECT text(123)} -} {123} -do_test func-17.24 { - execsql {SELECT typeof(text(123))} -} text -do_test func-17.25 { - execsql {SELECT numeric(123)} -} 123 -do_test func-17.26 { - execsql {SELECT typeof(numeric(123))} -} integer -do_test func-17.27 { - execsql {SELECT blob(123)} -} {123} -do_test func-17.28 { - execsql {SELECT typeof(blob(123))} -} blob -do_test func-17.31 { - execsql {SELECT 123.456} -} {123.456} -do_test func-17.32 { - execsql {SELECT typeof(123.456)} -} real -do_test func-17.33 { - execsql {SELECT text(123.456)} -} {123.456} -do_test func-17.34 { - execsql {SELECT typeof(text(123.456))} -} text -do_test func-17.35 { - execsql {SELECT numeric(123.456)} -} 123.456 -do_test func-17.36 { - execsql {SELECT typeof(numeric(123.456))} -} real -do_test func-17.37 { - execsql {SELECT blob(123.456)} -} {123.456} -do_test func-17.38 { - execsql {SELECT typeof(blob(123.456))} -} blob -do_test func-17.41 { - execsql {SELECT '123abc'} -} {123abc} -do_test func-17.42 { - execsql {SELECT typeof('123abc')} -} text -do_test func-17.43 { - execsql {SELECT text('123abc')} -} {123abc} -do_test func-17.44 { - execsql {SELECT typeof(text('123abc'))} -} text -do_test func-17.45 { - execsql {SELECT numeric('123abc')} -} 123 -do_test func-17.46 { - execsql {SELECT typeof(numeric('123abc'))} -} integer -do_test func-17.47 { - execsql {SELECT blob('123abc')} -} {123abc} -do_test func-17.48 { - execsql {SELECT typeof(blob('123abc'))} -} blob -do_test func-17.49 { - execsql {SELECT numeric('123.5abc')} -} 123.5 -do_test func-17.49b { - execsql {SELECT typeof(numeric('123.5abc'))} -} real finish_test diff --git a/tool/mkkeywordhash.c b/tool/mkkeywordhash.c index 5d34257091..44cff22ce1 100644 --- a/tool/mkkeywordhash.c +++ b/tool/mkkeywordhash.c @@ -95,6 +95,11 @@ struct Keyword { #else # define VIEW 16384 #endif +#ifdef SQLITE_OMIT_CAST +# define CAST 0 +#else +# define CAST 32768 +#endif /* @@ -117,6 +122,7 @@ static Keyword aKeywordTable[] = { { "BY", "TK_BY", ALWAYS }, { "CASCADE", "TK_CASCADE", FKEY }, { "CASE", "TK_CASE", ALWAYS }, + { "CAST", "TK_CAST", CAST }, { "CHECK", "TK_CHECK", ALWAYS }, { "COLLATE", "TK_COLLATE", ALWAYS }, { "COLUMN", "TK_COLUMNKW", ALTER }, diff --git a/www/lang.tcl b/www/lang.tcl index 9a0b0e1982..2deac5439f 100644 --- a/www/lang.tcl +++ b/www/lang.tcl @@ -1,7 +1,7 @@ # # Run this Tcl script to generate the lang-*.html files. # -set rcsid {$Id: lang.tcl,v 1.90 2005/05/10 16:11:41 drh Exp $} +set rcsid {$Id: lang.tcl,v 1.91 2005/06/25 18:42:16 drh Exp $} source common.tcl if {[llength $argv]>0} { @@ -1099,7 +1099,7 @@ all arguments are NULL then NULL is returned. There must be at least sqlite3_create_function() interface can be used to override this function and thereby change the operation -of the GLOB operator. +of the GLOB operator.