-C Fix\sthe\sreturn\stype\sof\ssqliteRunVacuum.\s\sTicket\s#627.\s(CVS\s1271)
-D 2004-02-25T02:33:35
+C Min()\sand\smax()\sfunctions\shonor\sthe\sdistinction\sbetween\sTEXT\sand\sNUMERIC\ndata.\s\sTicket\s#623.\s\stypeof()\sis\snow\sa\suser\sfunction.\s\sSome\stests\sare\nnow\sfailing\sdue\sto\sticket\s#521.\s(CVS\s1272)
+D 2004-02-25T13:47:31
F Makefile.in cfd75c46b335881999333a9e4b982fa8491f200b
F Makefile.linux-gcc b86a99c493a5bfb402d1d9178dcdc4bd4b32f906
F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd
F src/btree.h 41cb3ff6ebc3f6da2d0a074e39ff8c7a2287469f
F src/btree_rb.c 32b2cb4285c0fbd53b89de021637b63d52257e54
F src/build.c c8ab8b467d9a64254b0d4d42083f6313b3a980d1
-F src/copy.c e4dc49e7e1661818c72852e348d0cb0ef2b42bc1
+F src/copy.c 750e13828c3e4a293123e36aaa7cf0f22466248a
F src/date.c 3025642cee50d5c41aef4a22cbc41aa7e543c922
F src/delete.c 82001c74882319f94dab5f6b92a27311b31092ae
F src/encode.c 9e70ea1e4e746f23f18180949e94f1bb1c2220d3
-F src/expr.c 61b71ce2e93b0faca39db9e9c06e9a089d25a04f
-F src/func.c a2265f29e6a286203c9dfeb835d9a50439617805
+F src/expr.c 95ea5d47d11b5085aaeeb77d60b17c2cba13383a
+F src/func.c 424256b469717367f3939725a36a6f3c3d7b5f60
F src/hash.c 9b56ef3b291e25168f630d5643a4264ec011c70e
F src/hash.h 3247573ab95b9dd90bcca0307a75d9a16da1ccc7
F src/insert.c c0485ee2d1b99322894e2d1e0b576fd05ed75616
-F src/main.c 0f77633b37540fabd45e68c5137f32f4cd99470a
+F src/main.c af984c8dbfe769fb88fb0ac70e5f813e50800c1b
F src/md5.c fe4f9c9c6f71dfc26af8da63e4d04489b1430565
F src/os.c f5fc4954725b2fcd852979f2746085fe8ca27710
F src/os.h 250a3789be609adfee5c5aa20137ce8683276f24
F src/pragma.c 621d319580e9e23712ec232e8be1786cdae06b36
F src/printf.c f201a5a316afc474d29d51e07501536e8998194d
F src/random.c 775913e0b7fbd6295d21f12a7bd35b46387c44b2
-F src/select.c 902000034e44817e2822d72870c15eff842dea9e
+F src/select.c a8b0f9bfe92001d2399d33832bd6ec57ba492ae7
F src/shell.c b19e750ffcccf49b626f4b6fefe89c1dbae47e82
-F src/sqlite.h.in 64f016cd5ce190643a0f47760188fdf4e0b2227e
-F src/sqliteInt.h 1ef4dcb7a5525c91e3d338f9435c84930c11aeb2
+F src/sqlite.h.in 8a83091fbbbd73d30a9743310ed0089e3f1fda0f
+F src/sqliteInt.h 235ce244b62bb26cc9ab394fb7a0724dd4e65c83
F src/table.c d845cb101b5afc1f7fea083c99e3d2fa7998d895
F src/tclsqlite.c b84dafe3a8532ff534c36e96bd38880e4b9cedf3
F src/test1.c 9aa62b89d420e6763b5e7ae89a47f6cf87370477
F test/malloc.test 2cfcffb7c858640e01e6520ee1cd54ca57d98e80
F test/memdb.test 6ece25c7c0e6500199d3662607a3edca081abb2a
F test/memleak.test 4d5d374c8ea1fc5ac634aed58cac1047848ce65e
-F test/minmax.test 6680b8d79b9b6e026a476ebfb91f310f7774568e
+F test/minmax.test d7da9183013ac814a5b032b3542f9caf4c88af42
F test/misc1.test 0b98d493b0cf55cb5f53e1f3df8107c166eecb5a
F test/misc2.test 10c2ce26407d37411b96273e552d5095393732be
F test/misc3.test bd371567b6fec7c1d7fe42a172a551226d271dd2
F www/tclsqlite.tcl b9271d44dcf147a93c98f8ecf28c927307abd6da
F www/vdbe.tcl 9b9095d4495f37697fd1935d10e14c6015e80aa1
F www/whentouse.tcl a8335bce47cc2fddb07f19052cb0cb4d9129a8e4
-P 114b72f8608b8e08fad863a1446fb1ef59610efd
-R e0dfbd5e11231f51ee512fc59088c2fb
+P 9c9f4a867a4ea708847cbb0839b7279eb33ecd7c
+R 5415532acf52c246928d5fc32e241eec
U drh
-Z ea543ed6ac4d345acdce58082a3273de
+Z 719381690dd478a52c92cb1074f23dac
** This file contains routines used for analyzing expressions and
** for generating VDBE code that evaluates expressions in SQLite.
**
-** $Id: expr.c,v 1.111 2004/02/22 20:05:01 drh Exp $
+** $Id: expr.c,v 1.112 2004/02/25 13:47:31 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>
case TK_FUNCTION: {
int n = pExpr->pList ? pExpr->pList->nExpr : 0; /* Number of arguments */
int no_such_func = 0; /* True if no such function exists */
- int is_type_of = 0; /* True if is the special TypeOf() function */
int wrong_num_args = 0; /* True if wrong number of arguments */
int is_agg = 0; /* True if is an aggregate function */
int i;
if( pDef==0 ){
pDef = sqliteFindFunction(pParse->db, zId, nId, -1, 0);
if( pDef==0 ){
- if( n==1 && nId==6 && sqliteStrNICmp(zId, "typeof", 6)==0 ){
- is_type_of = 1;
- }else {
- no_such_func = 1;
- }
+ no_such_func = 1;
}else{
wrong_num_args = 1;
}
allowAgg && !is_agg, pIsAgg);
}
if( pDef==0 ){
- if( is_type_of ){
- pExpr->op = TK_STRING;
- if( sqliteExprType(pExpr->pList->a[0].pExpr)==SQLITE_SO_NUM ){
- pExpr->token.z = "numeric";
- pExpr->token.n = 7;
- }else{
- pExpr->token.z = "text";
- pExpr->token.n = 4;
- }
- }
+ /* Already reported an error */
}else if( pDef->dataType>=0 ){
if( pDef->dataType<n ){
pExpr->dataType =
case TK_GLOB:
case TK_LIKE:
case TK_FUNCTION: {
- int i;
ExprList *pList = pExpr->pList;
int nExpr = pList ? pList->nExpr : 0;
FuncDef *pDef;
getFunctionName(pExpr, &zId, &nId);
pDef = sqliteFindFunction(pParse->db, zId, nId, nExpr, 0);
assert( pDef!=0 );
- for(i=0; i<nExpr; i++){
- sqliteExprCode(pParse, pList->a[i].pExpr);
- }
+ nExpr = sqliteExprCodeExprList(pParse, pList, pDef->includeTypes);
sqliteVdbeOp3(v, OP_Function, nExpr, 0, (char*)pDef, P3_POINTER);
break;
}
}
}
+/*
+** Generate code that pushes the value of every element of the given
+** expression list onto the stack. If the includeTypes flag is true,
+** then also push a string that is the datatype of each element onto
+** the stack after the value.
+**
+** Return the number of elements pushed onto the stack.
+*/
+int sqliteExprCodeExprList(
+ Parse *pParse, /* Parsing context */
+ ExprList *pList, /* The expression list to be coded */
+ int includeTypes /* TRUE to put datatypes on the stack too */
+){
+ struct ExprList_item *pItem;
+ int i, n;
+ Vdbe *v;
+ if( pList==0 ) return 0;
+ v = sqliteGetVdbe(pParse);
+ n = pList->nExpr;
+ for(pItem=pList->a, i=0; i<n; i++, pItem++){
+ sqliteExprCode(pParse, pItem->pExpr);
+ if( includeTypes ){
+ sqliteVdbeOp3(v, OP_String, 0, 0,
+ sqliteExprType(pItem->pExpr)==SQLITE_SO_NUM ? "numeric" : "text",
+ P3_STATIC);
+ }
+ }
+ return includeTypes ? n*2 : n;
+}
+
/*
** Generate code for a boolean expression such that a jump is made
** to the label "dest" if the expression is true but execution
** sqliteRegisterBuildinFunctions() found at the bottom of the file.
** All other code has file scope.
**
-** $Id: func.c,v 1.41 2004/02/22 17:49:34 drh Exp $
+** $Id: func.c,v 1.42 2004/02/25 13:47:32 drh Exp $
*/
#include <ctype.h>
#include <math.h>
/*
** Implementation of the non-aggregate min() and max() functions
*/
-static void minFunc(sqlite_func *context, int argc, const char **argv){
+static void minmaxFunc(sqlite_func *context, int argc, const char **argv){
const char *zBest;
int i;
+ int (*xCompare)(const char*, const char*);
+ int mask; /* 0 for min() or 0xffffffff for max() */
if( argc==0 ) return;
+ mask = (int)sqlite_user_data(context);
zBest = argv[0];
if( zBest==0 ) return;
- for(i=1; i<argc; i++){
+ if( argv[1][0]=='n' ){
+ xCompare = sqliteCompare;
+ }else{
+ xCompare = strcmp;
+ }
+ for(i=2; i<argc; i+=2){
if( argv[i]==0 ) return;
- if( sqliteCompare(argv[i], zBest)<0 ){
+ if( (xCompare(argv[i], zBest)^mask)<0 ){
zBest = argv[i];
}
}
sqlite_set_result_string(context, zBest, -1);
}
-static void maxFunc(sqlite_func *context, int argc, const char **argv){
- const char *zBest;
- int i;
- if( argc==0 ) return;
- zBest = argv[0];
- if( zBest==0 ) return;
- for(i=1; i<argc; i++){
- if( argv[i]==0 ) return;
- if( sqliteCompare(argv[i], zBest)>0 ){
- zBest = argv[i];
- }
- }
- sqlite_set_result_string(context, zBest, -1);
+/*
+** Return the type of the argument.
+*/
+static void typeofFunc(sqlite_func *context, int argc, const char **argv){
+ assert( argc==2 );
+ sqlite_set_result_string(context, argv[1], -1);
}
/*
/*
** Routines to implement min() and max() aggregate functions.
*/
-static void minStep(sqlite_func *context, int argc, const char **argv){
+static void minmaxStep(sqlite_func *context, int argc, const char **argv){
MinMaxCtx *p;
- p = sqlite_aggregate_context(context, sizeof(*p));
- if( p==0 || argc<1 || argv[0]==0 ) return;
- if( p->z==0 || sqliteCompare(argv[0],p->z)<0 ){
- int len;
- if( !p->zBuf[0] ){
- sqliteFree(p->z);
- }
- len = strlen(argv[0]);
- if( len < sizeof(p->zBuf)-1 ){
- p->z = &p->zBuf[1];
- p->zBuf[0] = 1;
- }else{
- p->z = sqliteMalloc( len+1 );
- p->zBuf[0] = 0;
- if( p->z==0 ) return;
- }
- strcpy(p->z, argv[0]);
+ int (*xCompare)(const char*, const char*);
+ int mask; /* 0 for min() or 0xffffffff for max() */
+
+ assert( argc==2 );
+ if( argv[1][0]=='n' ){
+ xCompare = sqliteCompare;
+ }else{
+ xCompare = strcmp;
}
-}
-static void maxStep(sqlite_func *context, int argc, const char **argv){
- MinMaxCtx *p;
+ mask = (int)sqlite_user_data(context);
p = sqlite_aggregate_context(context, sizeof(*p));
if( p==0 || argc<1 || argv[0]==0 ) return;
- if( p->z==0 || sqliteCompare(argv[0],p->z)>0 ){
+ if( p->z==0 || (xCompare(argv[0],p->z)^mask)<0 ){
int len;
if( !p->zBuf[0] ){
sqliteFree(p->z);
void sqliteRegisterBuiltinFunctions(sqlite *db){
static struct {
char *zName;
- int nArg;
- int dataType;
+ signed char nArg;
+ signed char dataType;
+ u8 argType; /* 0: none. 1: db 2: (-1) */
void (*xFunc)(sqlite_func*,int,const char**);
} aFuncs[] = {
- { "min", -1, SQLITE_ARGS, minFunc },
- { "min", 0, 0, 0 },
- { "max", -1, SQLITE_ARGS, maxFunc },
- { "max", 0, 0, 0 },
- { "length", 1, SQLITE_NUMERIC, lengthFunc },
- { "substr", 3, SQLITE_TEXT, substrFunc },
- { "abs", 1, SQLITE_NUMERIC, absFunc },
- { "round", 1, SQLITE_NUMERIC, roundFunc },
- { "round", 2, SQLITE_NUMERIC, roundFunc },
- { "upper", 1, SQLITE_TEXT, upperFunc },
- { "lower", 1, SQLITE_TEXT, lowerFunc },
- { "coalesce", -1, SQLITE_ARGS, ifnullFunc },
- { "coalesce", 0, 0, 0 },
- { "coalesce", 1, 0, 0 },
- { "ifnull", 2, SQLITE_ARGS, ifnullFunc },
- { "random", -1, SQLITE_NUMERIC, randomFunc },
- { "like", 2, SQLITE_NUMERIC, likeFunc },
- { "glob", 2, SQLITE_NUMERIC, globFunc },
- { "nullif", 2, SQLITE_ARGS, nullifFunc },
- { "sqlite_version",0,SQLITE_TEXT, versionFunc},
- { "quote", 1, SQLITE_ARGS, quoteFunc },
+ { "min", -1, SQLITE_ARGS, 0, minmaxFunc },
+ { "min", 0, 0, 0, 0 },
+ { "max", -1, SQLITE_ARGS, 2, minmaxFunc },
+ { "max", 0, 0, 2, 0 },
+ { "typeof", 1, SQLITE_TEXT, 0, typeofFunc },
+ { "length", 1, SQLITE_NUMERIC, 0, lengthFunc },
+ { "substr", 3, SQLITE_TEXT, 0, substrFunc },
+ { "abs", 1, SQLITE_NUMERIC, 0, absFunc },
+ { "round", 1, SQLITE_NUMERIC, 0, roundFunc },
+ { "round", 2, SQLITE_NUMERIC, 0, roundFunc },
+ { "upper", 1, SQLITE_TEXT, 0, upperFunc },
+ { "lower", 1, SQLITE_TEXT, 0, lowerFunc },
+ { "coalesce", -1, SQLITE_ARGS, 0, ifnullFunc },
+ { "coalesce", 0, 0, 0, 0 },
+ { "coalesce", 1, 0, 0, 0 },
+ { "ifnull", 2, SQLITE_ARGS, 0, ifnullFunc },
+ { "random", -1, SQLITE_NUMERIC, 0, randomFunc },
+ { "like", 2, SQLITE_NUMERIC, 0, likeFunc },
+ { "glob", 2, SQLITE_NUMERIC, 0, globFunc },
+ { "nullif", 2, SQLITE_ARGS, 0, nullifFunc },
+ { "sqlite_version",0,SQLITE_TEXT, 0, versionFunc},
+ { "quote", 1, SQLITE_ARGS, 0, quoteFunc },
+ { "last_insert_rowid", 0, SQLITE_NUMERIC, 1, last_insert_rowid },
+ { "change_count", 0, SQLITE_NUMERIC, 1, change_count },
+ { "last_statement_change_count",
+ 0, SQLITE_NUMERIC, 1, last_statement_change_count },
#ifdef SQLITE_SOUNDEX
- { "soundex", 1, SQLITE_TEXT, soundexFunc},
+ { "soundex", 1, SQLITE_TEXT, 0, soundexFunc},
#endif
#ifdef SQLITE_TEST
- { "randstr", 2, SQLITE_TEXT, randStr },
+ { "randstr", 2, SQLITE_TEXT, 0, randStr },
#endif
};
static struct {
char *zName;
- int nArg;
- int dataType;
+ signed char nArg;
+ signed char dataType;
+ u8 argType;
void (*xStep)(sqlite_func*,int,const char**);
void (*xFinalize)(sqlite_func*);
} aAggs[] = {
- { "min", 1, 0, minStep, minMaxFinalize },
- { "max", 1, 0, maxStep, minMaxFinalize },
- { "sum", 1, SQLITE_NUMERIC, sumStep, sumFinalize },
- { "avg", 1, SQLITE_NUMERIC, sumStep, avgFinalize },
- { "count", 0, SQLITE_NUMERIC, countStep, countFinalize },
- { "count", 1, SQLITE_NUMERIC, countStep, countFinalize },
+ { "min", 1, 0, 0, minmaxStep, minMaxFinalize },
+ { "max", 1, 0, 2, minmaxStep, minMaxFinalize },
+ { "sum", 1, SQLITE_NUMERIC, 0, sumStep, sumFinalize },
+ { "avg", 1, SQLITE_NUMERIC, 0, sumStep, avgFinalize },
+ { "count", 0, SQLITE_NUMERIC, 0, countStep, countFinalize },
+ { "count", 1, SQLITE_NUMERIC, 0, countStep, countFinalize },
#if 0
- { "stddev", 1, SQLITE_NUMERIC, stdDevStep, stdDevFinalize },
+ { "stddev", 1, SQLITE_NUMERIC, 0, stdDevStep, stdDevFinalize },
#endif
};
+ static const char *azTypeFuncs[] = { "min", "max", "typeof" };
int i;
for(i=0; i<sizeof(aFuncs)/sizeof(aFuncs[0]); i++){
+ void *pArg = aFuncs[i].argType==2 ? (void*)(-1) : db;
sqlite_create_function(db, aFuncs[i].zName,
- aFuncs[i].nArg, aFuncs[i].xFunc, 0);
+ aFuncs[i].nArg, aFuncs[i].xFunc, pArg);
if( aFuncs[i].xFunc ){
sqlite_function_type(db, aFuncs[i].zName, aFuncs[i].dataType);
}
}
- sqlite_create_function(db, "last_insert_rowid", 0,
- last_insert_rowid, db);
- sqlite_function_type(db, "last_insert_rowid", SQLITE_NUMERIC);
- sqlite_create_function(db, "change_count", 0, change_count, db);
- sqlite_function_type(db, "change_count", SQLITE_NUMERIC);
- sqlite_create_function(db, "last_statement_change_count", 0,
- last_statement_change_count, db);
- sqlite_function_type(db, "last_statement_change_count", SQLITE_NUMERIC);
-
for(i=0; i<sizeof(aAggs)/sizeof(aAggs[0]); i++){
+ void *pArg = aAggs[i].argType==2 ? (void*)(-1) : db;
sqlite_create_aggregate(db, aAggs[i].zName,
- aAggs[i].nArg, aAggs[i].xStep, aAggs[i].xFinalize, 0);
+ aAggs[i].nArg, aAggs[i].xStep, aAggs[i].xFinalize, pArg);
sqlite_function_type(db, aAggs[i].zName, aAggs[i].dataType);
}
+ for(i=0; i<sizeof(azTypeFuncs)/sizeof(azTypeFuncs[0]); i++){
+ int n = strlen(azTypeFuncs[i]);
+ FuncDef *p = sqliteHashFind(&db->aFunc, azTypeFuncs[i], n);
+ while( p ){
+ p->includeTypes = 1;
+ p = p->pNext;
+ }
+ }
sqliteRegisterDateTimeFunctions(db);
}