diff --git a/manifest b/manifest index a20b20afb2..87e95a1b83 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C First\scut\sat\san\simplementation\sof\sthe\sREPLACE()\sfunction.\s\sWe\smight\syet\nmake\sthis\sa\scompile-time\soption\sor\smove\sit\sinto\sa\sseparate\ssource\sfile.\s(CVS\s3697) -D 2007-03-17T13:27:55 +C Added\sTRIM,\sLTRIM,\sand\sRTRIM\sfunctions.\s(CVS\s3698) +D 2007-03-17T17:52:42 F Makefile.in 1fe3d0b46e40fd684e1e61f8e8056cefed16de9f F Makefile.linux-gcc 2d8574d1ba75f129aba2019f0b959db380a90935 F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028 @@ -67,7 +67,7 @@ F src/date.c 393c73fc027597e008dcd81454544659e978b05c F src/delete.c 151d08386bf9c9e7f92f6b9106c71efec2def184 F src/experimental.c 1b2d1a6cd62ecc39610e97670332ca073c50792b F src/expr.c b5c65202c7ada4b1ec24f0f010bb73c92ab44e6d -F src/func.c 683c2d66a2ea386372f01afcd595bb1f026f1c12 +F src/func.c 94372fe3cf26b81d4dcdc15f98ff240c37c8c708 F src/hash.c 449f3d6620193aa557f5d86cbc5cc6b87702b185 F src/hash.h 1b3f7e2609141fd571f62199fc38687d262e9564 F src/insert.c 72cb64b698796f2005c0158e098124d9490868bb @@ -221,7 +221,7 @@ F test/fts2g.test c69a8ab43ec77d123976ba6cf9422d647ae63032 F test/fts2h.test 223af921323b409d4b5b18ff4e51619541b174bb F test/fts2i.test 1b22451d1f13f7c509baec620dc3a4a754885dd6 F test/fts2j.test f68d7611f76309bc8b94170f3740d9fbbc061d9b -F test/func.test 86c3322c9209be36354981354278553b3491393f +F test/func.test 019d706b2458dfdf239c74cc31143446de1ee44a F test/hook.test 7e7645fd9a033f79cce8fdff151e32715e7ec50a F test/in.test 369cb2aa1eab02296b4ec470732fe8c131260b1d F test/index.test e65df12bed94b2903ee89987115e1578687e9266 @@ -437,7 +437,7 @@ F www/tclsqlite.tcl bb0d1357328a42b1993d78573e587c6dcbc964b9 F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0 F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b F www/whentouse.tcl 97e2b5cd296f7d8057e11f44427dea8a4c2db513 -P b0f8203dbbf1036418a2dcc480f352f761826194 -R 1f5e4827e9584f1f16dd1e58366ed649 +P c2fe746ea782f84e850aaf3af7f5536b027a19a1 +R 56fe7aceb3f39a745b09a268ce41fa61 U drh -Z 93e91ca49be183cbbf3f15fa9aa6c1e3 +Z 1b019529be28ae82cd90d8e8442d2374 diff --git a/manifest.uuid b/manifest.uuid index cd8aadf2f9..87d238b0b0 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -c2fe746ea782f84e850aaf3af7f5536b027a19a1 \ No newline at end of file +6fe13eeade4fc7099fbda1e6520640927c08debc \ No newline at end of file diff --git a/src/func.c b/src/func.c index cfd377eeb7..7850e22a15 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.137 2007/03/17 13:27:55 drh Exp $ +** $Id: func.c,v 1.138 2007/03/17 17:52:42 drh Exp $ */ #include "sqliteInt.h" #include @@ -697,12 +697,12 @@ static void replaceFunc( sqlite3_value_type(argv[2])==SQLITE_NULL ){ return; } - nStr = sqlite3_value_bytes(argv[0]); zStr = sqlite3_value_text(argv[0]); - nPattern = sqlite3_value_bytes(argv[1]); + nStr = sqlite3_value_bytes(argv[0]); zPattern = sqlite3_value_text(argv[1]); - nRep = sqlite3_value_bytes(argv[2]); + nPattern = sqlite3_value_bytes(argv[1]); zRep = sqlite3_value_text(argv[2]); + nRep = sqlite3_value_bytes(argv[2]); if( nPattern>=nRep ){ nOut = nStr; }else{ @@ -727,6 +727,55 @@ static void replaceFunc( sqlite3_result_text(context, (char*)zOut, j, sqlite3_free); } +/* +** Implementation of the TRIM(), LTRIM(), and RTRIM() functions. +** The userdata is 0x1 for left trim, 0x2 for right trim, 0x3 for both. +*/ +static void trimFunc( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + const unsigned char *zIn; /* Input string */ + const unsigned char *zCharSet; /* Set of characters to trim */ + int nIn; /* Number of bytes in input */ + int flags; + int i; + unsigned char cFirst, cNext; + if( sqlite3_value_type(argv[0])==SQLITE_NULL ){ + return; + } + zIn = sqlite3_value_text(argv[0]); + nIn = sqlite3_value_bytes(argv[0]); + if( argc==1 ){ + static const unsigned char zSpace[] = " "; + zCharSet = zSpace; + }else if( sqlite3_value_type(argv[1])==SQLITE_NULL ){ + return; + }else{ + zCharSet = sqlite3_value_text(argv[1]); + } + cFirst = zCharSet[0]; + if( cFirst ){ + flags = (int)sqlite3_user_data(context); + if( flags & 1 ){ + for(; nIn>0; nIn--, zIn++){ + if( cFirst==zIn[0] ) continue; + for(i=1; zCharSet[i] && zCharSet[i]!=zIn[0]; i++){} + if( zCharSet[i]==0 ) break; + } + } + if( flags & 2 ){ + for(; nIn>0; nIn--){ + cNext = zIn[nIn-1]; + if( cFirst==cNext ) continue; + for(i=1; zCharSet[i] && zCharSet[i]!=cNext; i++){} + if( zCharSet[i]==0 ) break; + } + } + } + sqlite3_result_text(context, (char*)zIn, nIn, SQLITE_TRANSIENT); +} #ifdef SQLITE_SOUNDEX /* @@ -1079,7 +1128,7 @@ static void minmaxStep(sqlite3_context *context, int argc, sqlite3_value **argv) ** Therefore the next statement sets variable 'max' to 1 for the max() ** aggregate, or 0 for min(). */ - max = ((sqlite3_user_data(context)==(void *)-1)?1:0); + max = sqlite3_user_data(context)!=0; cmp = sqlite3MemCompare(pBest, pArg, pColl); if( (max && cmp<0) || (!max && cmp>0) ){ sqlite3VdbeMemCopy(pBest, pArg); @@ -1109,15 +1158,15 @@ void sqlite3RegisterBuiltinFunctions(sqlite3 *db){ static const struct { char *zName; signed char nArg; - u8 argType; /* 0: none. 1: db 2: (-1) */ + u8 argType; /* ff: db 1: 0, 2: 1, 3: 2,... N: N-1. */ u8 eTextRep; /* 1: UTF-16. 0: UTF-8 */ u8 needCollSeq; void (*xFunc)(sqlite3_context*,int,sqlite3_value **); } aFuncs[] = { { "min", -1, 0, SQLITE_UTF8, 1, minmaxFunc }, { "min", 0, 0, SQLITE_UTF8, 1, 0 }, - { "max", -1, 2, SQLITE_UTF8, 1, minmaxFunc }, - { "max", 0, 2, SQLITE_UTF8, 1, 0 }, + { "max", -1, 1, SQLITE_UTF8, 1, minmaxFunc }, + { "max", 0, 1, SQLITE_UTF8, 1, 0 }, { "typeof", 1, 0, SQLITE_UTF8, 0, typeofFunc }, { "length", 1, 0, SQLITE_UTF8, 0, lengthFunc }, { "substr", 3, 0, SQLITE_UTF8, 0, substrFunc }, @@ -1139,23 +1188,29 @@ void sqlite3RegisterBuiltinFunctions(sqlite3 *db){ { "nullif", 2, 0, SQLITE_UTF8, 1, nullifFunc }, { "sqlite_version", 0, 0, SQLITE_UTF8, 0, versionFunc}, { "quote", 1, 0, SQLITE_UTF8, 0, quoteFunc }, - { "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 }, + { "last_insert_rowid", 0, 0xff, SQLITE_UTF8, 0, last_insert_rowid }, + { "changes", 0, 0xff, SQLITE_UTF8, 0, changes }, + { "total_changes", 0, 0xff, SQLITE_UTF8, 0, total_changes }, { "replace", 3, 0, SQLITE_UTF8, 0, replaceFunc }, + { "ltrim", 1, 1, SQLITE_UTF8, 0, trimFunc }, + { "ltrim", 2, 1, SQLITE_UTF8, 0, trimFunc }, + { "rtrim", 1, 2, SQLITE_UTF8, 0, trimFunc }, + { "rtrim", 2, 2, SQLITE_UTF8, 0, trimFunc }, + { "trim", 1, 3, SQLITE_UTF8, 0, trimFunc }, + { "trim", 2, 3, SQLITE_UTF8, 0, trimFunc }, #ifdef SQLITE_SOUNDEX - { "soundex", 1, 0, SQLITE_UTF8, 0, soundexFunc}, + { "soundex", 1, 0, SQLITE_UTF8, 0, soundexFunc}, #endif #ifndef SQLITE_OMIT_LOAD_EXTENSION - { "load_extension", 1, 1, SQLITE_UTF8, 0, loadExt }, - { "load_extension", 2, 1, SQLITE_UTF8, 0, loadExt }, + { "load_extension", 1, 0xff, SQLITE_UTF8, 0, loadExt }, + { "load_extension", 2, 0xff, SQLITE_UTF8, 0, loadExt }, #endif #ifdef SQLITE_TEST - { "randstr", 2, 0, SQLITE_UTF8, 0, randStr }, - { "test_destructor", 1, 1, SQLITE_UTF8, 0, test_destructor}, - { "test_destructor_count", 0, 0, SQLITE_UTF8, 0, test_destructor_count}, - { "test_auxdata", -1, 0, SQLITE_UTF8, 0, test_auxdata}, - { "test_error", 1, 0, SQLITE_UTF8, 0, test_error}, + { "randstr", 2, 0, SQLITE_UTF8, 0, randStr }, + { "test_destructor", 1, 0xff, SQLITE_UTF8, 0, test_destructor}, + { "test_destructor_count", 0, 0, SQLITE_UTF8, 0, test_destructor_count}, + { "test_auxdata", -1, 0, SQLITE_UTF8, 0, test_auxdata}, + { "test_error", 1, 0, SQLITE_UTF8, 0, test_error}, #endif }; static const struct { @@ -1167,7 +1222,7 @@ void sqlite3RegisterBuiltinFunctions(sqlite3 *db){ void (*xFinalize)(sqlite3_context*); } aAggs[] = { { "min", 1, 0, 1, minmaxStep, minMaxFinalize }, - { "max", 1, 2, 1, minmaxStep, minMaxFinalize }, + { "max", 1, 1, 1, minmaxStep, minMaxFinalize }, { "sum", 1, 0, 0, sumStep, sumFinalize }, { "total", 1, 0, 0, sumStep, totalFinalize }, { "avg", 1, 0, 0, sumStep, avgFinalize }, @@ -1177,10 +1232,12 @@ void sqlite3RegisterBuiltinFunctions(sqlite3 *db){ int i; for(i=0; i