diff options
author | drh <drh@noemail.net> | 2007-03-17 17:52:42 +0000 |
---|---|---|
committer | drh <drh@noemail.net> | 2007-03-17 17:52:42 +0000 |
commit | 309b3386735610c693dafab7d3f68aeba9bd0048 (patch) | |
tree | 301ee3db744fb6029e3c79f3d242ab5145475634 /src | |
parent | 26b6d90d747f9315cc1602506b0984368ef4636c (diff) | |
download | sqlite-309b3386735610c693dafab7d3f68aeba9bd0048.tar.gz sqlite-309b3386735610c693dafab7d3f68aeba9bd0048.zip |
Added TRIM, LTRIM, and RTRIM functions. (CVS 3698)
FossilOrigin-Name: 6fe13eeade4fc7099fbda1e6520640927c08debc
Diffstat (limited to 'src')
-rw-r--r-- | src/func.c | 111 |
1 files changed, 82 insertions, 29 deletions
diff --git a/src/func.c b/src/func.c index cfd377eeb..7850e22a1 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 <ctype.h> @@ -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<sizeof(aFuncs)/sizeof(aFuncs[0]); i++){ - void *pArg = 0; - switch( aFuncs[i].argType ){ - case 1: pArg = db; break; - case 2: pArg = (void *)(-1); break; + void *pArg; + u8 argType = aFuncs[i].argType; + if( argType==0xff ){ + pArg = db; + }else{ + pArg = (void*)(int)argType; } sqlite3CreateFunc(db, aFuncs[i].zName, aFuncs[i].nArg, aFuncs[i].eTextRep, pArg, aFuncs[i].xFunc, 0, 0); @@ -1199,11 +1256,7 @@ void sqlite3RegisterBuiltinFunctions(sqlite3 *db){ sqlite3AttachFunctions(db); #endif for(i=0; i<sizeof(aAggs)/sizeof(aAggs[0]); i++){ - void *pArg = 0; - switch( aAggs[i].argType ){ - case 1: pArg = db; break; - case 2: pArg = (void *)(-1); break; - } + void *pArg = (void*)(int)aAggs[i].argType; sqlite3CreateFunc(db, aAggs[i].zName, aAggs[i].nArg, SQLITE_UTF8, pArg, 0, aAggs[i].xStep, aAggs[i].xFinalize); if( aAggs[i].needCollSeq ){ |