1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-10-24 09:53:10 +03:00

Added TRIM, LTRIM, and RTRIM functions. (CVS 3698)

FossilOrigin-Name: 6fe13eeade4fc7099fbda1e6520640927c08debc
This commit is contained in:
drh
2007-03-17 17:52:42 +00:00
parent 26b6d90d74
commit 309b338673
4 changed files with 141 additions and 40 deletions

View File

@@ -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 ){