mirror of
https://github.com/sqlite/sqlite.git
synced 2025-08-07 02:42:48 +03:00
Added support for user-defined normal functions. Support for user-defined
aggregates is pending. (CVS 390) FossilOrigin-Name: c490a1ff951c5d4a2de8e4f8d349189bfaef7f74
This commit is contained in:
32
manifest
32
manifest
@@ -1,5 +1,5 @@
|
|||||||
C Modify\slemon\sto\suse\smuch\sless\smemory\sfor\sits\sparser\stables.\s\sThis\sreduces\nthe\ssize\sof\sthe\slibrary\sby\s50K,\swhich\sis\simportant\sfor\san\sembedded\slibrary.\s(CVS\s389)
|
C Added\ssupport\sfor\suser-defined\snormal\sfunctions.\s\sSupport\sfor\suser-defined\naggregates\sis\spending.\s(CVS\s390)
|
||||||
D 2002-02-23T19:39:47
|
D 2002-02-23T23:45:45
|
||||||
F Makefile.in 9fa4277413bf1d9cf91365f07d4108d7d87ed2af
|
F Makefile.in 9fa4277413bf1d9cf91365f07d4108d7d87ed2af
|
||||||
F Makefile.template 3372d45f8853afdb70bd30cc6fb50a3cd9069834
|
F Makefile.template 3372d45f8853afdb70bd30cc6fb50a3cd9069834
|
||||||
F README a4c0ba11354ef6ba0776b400d057c59da47a4cc0
|
F README a4c0ba11354ef6ba0776b400d057c59da47a4cc0
|
||||||
@@ -23,11 +23,11 @@ F src/btree.c 495275fe14f3b718cf2f691dce979d4c0e1f8e5d
|
|||||||
F src/btree.h 8abeabfe6e0b1a990b64fa457592a6482f6674f3
|
F src/btree.h 8abeabfe6e0b1a990b64fa457592a6482f6674f3
|
||||||
F src/build.c 1da051784be0155ae579d47890db74f0186f9b9f
|
F src/build.c 1da051784be0155ae579d47890db74f0186f9b9f
|
||||||
F src/delete.c 950d8f9097361419f1963875f9943344b469cf02
|
F src/delete.c 950d8f9097361419f1963875f9943344b469cf02
|
||||||
F src/expr.c 6b641c43941094a5d1f7a96657d8a34d07188856
|
F src/expr.c 4f9db24c4e90585fd046703d4f91c10b453867fa
|
||||||
F src/hash.c 8f7c740ef2eaaa8decfa8751f2be30680b123e46
|
F src/hash.c cc259475e358baaf299b00a2c7370f2b03dda892
|
||||||
F src/hash.h d1ce47900c7325af5e41c4feb4855c4bf2b841e7
|
F src/hash.h dca065dda89d4575f3176e75e9a3dc0f4b4fb8b9
|
||||||
F src/insert.c 164d2d5e943268a8ff0594e1947599e04df0ce11
|
F src/insert.c 164d2d5e943268a8ff0594e1947599e04df0ce11
|
||||||
F src/main.c abc0732d4caa676ff8337f278b01f1f1b57538f5
|
F src/main.c 0fa2298ab8980cb446dc81086ce36f905f607f70
|
||||||
F src/md5.c 52f677bfc590e09f71d07d7e327bd59da738d07c
|
F src/md5.c 52f677bfc590e09f71d07d7e327bd59da738d07c
|
||||||
F src/os.c f6bc9b7ab530346bb7fef2ed39f2f1f214bc14ea
|
F src/os.c f6bc9b7ab530346bb7fef2ed39f2f1f214bc14ea
|
||||||
F src/os.h a17596ecc7f38a228b83ecdb661fb03ce44726d6
|
F src/os.h a17596ecc7f38a228b83ecdb661fb03ce44726d6
|
||||||
@@ -39,9 +39,9 @@ F src/random.c 19e8e00fe0df32a742f115773f57651be327cabe
|
|||||||
F src/select.c 61d4a739956aaeb124cdf12c34c66e99ae34212c
|
F src/select.c 61d4a739956aaeb124cdf12c34c66e99ae34212c
|
||||||
F src/shell.c cbf48bf0ca35c4e0d8a7d2a86f7724f52c525cd7
|
F src/shell.c cbf48bf0ca35c4e0d8a7d2a86f7724f52c525cd7
|
||||||
F src/shell.tcl 27ecbd63dd88396ad16d81ab44f73e6c0ea9d20e
|
F src/shell.tcl 27ecbd63dd88396ad16d81ab44f73e6c0ea9d20e
|
||||||
F src/sqlite.h.in f57074c84a2c112a5093ba7a9d9636aa9cacc87c
|
F src/sqlite.h.in f1421919a4437a377fb712b98835a224482e776e
|
||||||
F src/sqliteInt.h 81dcdf77391471443d53e4b96ac5e78a10e9df4b
|
F src/sqliteInt.h b089e9226fbb88b25810d2f52285929dcf6999c6
|
||||||
F src/table.c c89698bd5bb4b8d14722d6ee7e9be014c383d24a
|
F src/table.c 203a09d5d0009eeeb1f670370d52b4ce163a3b52
|
||||||
F src/tclsqlite.c b9cf346e95291cb4c4f1bf5ac1d77db6b8ad023d
|
F src/tclsqlite.c b9cf346e95291cb4c4f1bf5ac1d77db6b8ad023d
|
||||||
F src/test1.c 33efd350dca27c52c58c553c04fd3a6a51f13c1f
|
F src/test1.c 33efd350dca27c52c58c553c04fd3a6a51f13c1f
|
||||||
F src/test2.c d410dbd8a90faa466c3ab694fa0aa57f5a773aa6
|
F src/test2.c d410dbd8a90faa466c3ab694fa0aa57f5a773aa6
|
||||||
@@ -50,8 +50,8 @@ F src/threadtest.c 81f0598e0f031c1bd506af337fdc1b7e8dff263f
|
|||||||
F src/tokenize.c 4b5d30590a744b9bb5605a92d1f620ab2e7e75af
|
F src/tokenize.c 4b5d30590a744b9bb5605a92d1f620ab2e7e75af
|
||||||
F src/update.c 18971d265b0341574b7e3f73116e7947ddab0997
|
F src/update.c 18971d265b0341574b7e3f73116e7947ddab0997
|
||||||
F src/util.c f31f3d6198a0d1296a16f5a6ceec423a932cbbf6
|
F src/util.c f31f3d6198a0d1296a16f5a6ceec423a932cbbf6
|
||||||
F src/vdbe.c 44832d804e109248e9e2abd40daee5f8ac735450
|
F src/vdbe.c 7d4c6e2f4861bed0ef5abd5d39153bfd401e30ff
|
||||||
F src/vdbe.h 002bb8cf884034bea25a9fe901a9c5e9d29bc045
|
F src/vdbe.h c3be021687ab2eb8517052a24e1df7e7355f0d77
|
||||||
F src/where.c 664be01b0ce9ffaecbde609afbd4d8d3e5ed1585
|
F src/where.c 664be01b0ce9ffaecbde609afbd4d8d3e5ed1585
|
||||||
F test/all.test 7a8a8a7a579ed2bb4d8976d55402f21eacd58049
|
F test/all.test 7a8a8a7a579ed2bb4d8976d55402f21eacd58049
|
||||||
F test/bigrow.test 8ab252dba108f12ad64e337b0f2ff31a807ac578
|
F test/bigrow.test 8ab252dba108f12ad64e337b0f2ff31a807ac578
|
||||||
@@ -81,7 +81,7 @@ F test/printf.test 3cb415073754cb8ff076f26173143c3cd293a9da
|
|||||||
F test/quick.test 6f023c7a73fc413e6d65b7a1879c79764038dc05
|
F test/quick.test 6f023c7a73fc413e6d65b7a1879c79764038dc05
|
||||||
F test/quote.test 286db944717afa9a9bf829dd85e59185c65d5435
|
F test/quote.test 286db944717afa9a9bf829dd85e59185c65d5435
|
||||||
F test/rowid.test 4c55943300cddf73dd0f88d40a268cab14c83274
|
F test/rowid.test 4c55943300cddf73dd0f88d40a268cab14c83274
|
||||||
F test/select1.test fd2936aa907559153c78edf2740ea65eb9a614f5
|
F test/select1.test 7d5ae792d6dbfa2c1b6345a32b154b7ba8d24bbc
|
||||||
F test/select2.test ed2c1882857106b85478f54f67000e14966be4c4
|
F test/select2.test ed2c1882857106b85478f54f67000e14966be4c4
|
||||||
F test/select3.test 9469c332250a75a0ef1771fb5da62dc04ec77f18
|
F test/select3.test 9469c332250a75a0ef1771fb5da62dc04ec77f18
|
||||||
F test/select4.test 29a2ffb187f3d8b6ca42a0a6b619e9cabe12e228
|
F test/select4.test 29a2ffb187f3d8b6ca42a0a6b619e9cabe12e228
|
||||||
@@ -110,7 +110,7 @@ F www/arch.fig d5f9752a4dbf242e9cfffffd3f5762b6c63b3bcf
|
|||||||
F www/arch.png 82ef36db1143828a7abc88b1e308a5f55d4336f4
|
F www/arch.png 82ef36db1143828a7abc88b1e308a5f55d4336f4
|
||||||
F www/arch.tcl 72a0c80e9054cc7025a50928d28d9c75c02c2b8b
|
F www/arch.tcl 72a0c80e9054cc7025a50928d28d9c75c02c2b8b
|
||||||
F www/c_interface.tcl 63efc40f09e2f0d8fea43d174103248b160fdf0e
|
F www/c_interface.tcl 63efc40f09e2f0d8fea43d174103248b160fdf0e
|
||||||
F www/changes.tcl 4aee975940a59d43736cdd4cd352c51e1e6426ba
|
F www/changes.tcl 0c40569ef5c92af1fb211ea1f679113a44c60f19
|
||||||
F www/conflict.tcl 81dd21f9a679e60aae049e9dd8ab53d59570cda2
|
F www/conflict.tcl 81dd21f9a679e60aae049e9dd8ab53d59570cda2
|
||||||
F www/crosscompile.tcl 3622ebbe518927a3854a12de51344673eb2dd060
|
F www/crosscompile.tcl 3622ebbe518927a3854a12de51344673eb2dd060
|
||||||
F www/download.tcl a6d75b8b117cd33dcb090bef7e80d7556d28ebe0
|
F www/download.tcl a6d75b8b117cd33dcb090bef7e80d7556d28ebe0
|
||||||
@@ -125,7 +125,7 @@ F www/speed.tcl 83457b2bf6bb430900bd48ca3dd98264d9a916a5
|
|||||||
F www/sqlite.tcl 8b5884354cb615049aed83039f8dfe1552a44279
|
F www/sqlite.tcl 8b5884354cb615049aed83039f8dfe1552a44279
|
||||||
F www/tclsqlite.tcl 829b393d1ab187fd7a5e978631b3429318885c49
|
F www/tclsqlite.tcl 829b393d1ab187fd7a5e978631b3429318885c49
|
||||||
F www/vdbe.tcl 2013852c27a02a091d39a766bc87cff329f21218
|
F www/vdbe.tcl 2013852c27a02a091d39a766bc87cff329f21218
|
||||||
P 8da0ac9a8bb859377613dd18f4f423eb49c7338b
|
P 67a135a051e7c96ddbfe85976539b4b8372c7026
|
||||||
R a10568441a27cde980e4058838f315f0
|
R fa8d1484ff86c96c0829999f970d3d5e
|
||||||
U drh
|
U drh
|
||||||
Z 77767b7d4f55ba40f2761ab26d448e78
|
Z f2c150ed8d00dcdf045fbfc7cf498205
|
||||||
|
@@ -1 +1 @@
|
|||||||
67a135a051e7c96ddbfe85976539b4b8372c7026
|
c490a1ff951c5d4a2de8e4f8d349189bfaef7f74
|
94
src/expr.c
94
src/expr.c
@@ -12,7 +12,7 @@
|
|||||||
** This file contains routines used for analyzing expressions and
|
** This file contains routines used for analyzing expressions and
|
||||||
** for generating VDBE code that evaluates expressions in SQLite.
|
** for generating VDBE code that evaluates expressions in SQLite.
|
||||||
**
|
**
|
||||||
** $Id: expr.c,v 1.42 2002/02/23 02:32:10 drh Exp $
|
** $Id: expr.c,v 1.43 2002/02/23 23:45:45 drh Exp $
|
||||||
*/
|
*/
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
|
|
||||||
@@ -606,29 +606,40 @@ int sqliteExprCheck(Parse *pParse, Expr *pExpr, int allowAgg, int *pIsAgg){
|
|||||||
int no_such_func = 0;
|
int no_such_func = 0;
|
||||||
int too_many_args = 0;
|
int too_many_args = 0;
|
||||||
int too_few_args = 0;
|
int too_few_args = 0;
|
||||||
|
int wrong_num_args = 0;
|
||||||
int is_agg = 0;
|
int is_agg = 0;
|
||||||
int i;
|
int i;
|
||||||
pExpr->iColumn = id;
|
pExpr->iColumn = id;
|
||||||
switch( id ){
|
switch( id ){
|
||||||
case FN_Unknown: {
|
case FN_Unknown: {
|
||||||
|
UserFunc *pUser = sqliteFindUserFunction(pParse->db,
|
||||||
|
pExpr->token.z, pExpr->token.n, n, 0);
|
||||||
|
if( pUser==0 ){
|
||||||
|
pUser = sqliteFindUserFunction(pParse->db,
|
||||||
|
pExpr->token.z, pExpr->token.n, -1, 0);
|
||||||
|
if( pUser==0 ){
|
||||||
no_such_func = 1;
|
no_such_func = 1;
|
||||||
|
}else{
|
||||||
|
wrong_num_args = 1;
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
is_agg = pUser->xFunc==0;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case FN_Count: {
|
case FN_Count: {
|
||||||
no_such_func = !allowAgg;
|
|
||||||
too_many_args = n>1;
|
too_many_args = n>1;
|
||||||
is_agg = 1;
|
is_agg = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case FN_Max:
|
case FN_Max:
|
||||||
case FN_Min: {
|
case FN_Min: {
|
||||||
too_few_args = allowAgg ? n<1 : n<2;
|
too_few_args = n<1;
|
||||||
is_agg = n==1;
|
is_agg = n==1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case FN_Avg:
|
case FN_Avg:
|
||||||
case FN_Sum: {
|
case FN_Sum: {
|
||||||
no_such_func = !allowAgg;
|
|
||||||
too_many_args = n>1;
|
too_many_args = n>1;
|
||||||
too_few_args = n<1;
|
too_few_args = n<1;
|
||||||
is_agg = 1;
|
is_agg = 1;
|
||||||
@@ -652,7 +663,13 @@ int sqliteExprCheck(Parse *pParse, Expr *pExpr, int allowAgg, int *pIsAgg){
|
|||||||
}
|
}
|
||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
if( no_such_func ){
|
if( is_agg && !allowAgg ){
|
||||||
|
sqliteSetNString(&pParse->zErrMsg, "misuse of aggregate function ", -1,
|
||||||
|
pExpr->token.z, pExpr->token.n, "()", 2, 0);
|
||||||
|
pParse->nErr++;
|
||||||
|
nErr++;
|
||||||
|
is_agg = 0;
|
||||||
|
}else if( no_such_func ){
|
||||||
sqliteSetNString(&pParse->zErrMsg, "no such function: ", -1,
|
sqliteSetNString(&pParse->zErrMsg, "no such function: ", -1,
|
||||||
pExpr->token.z, pExpr->token.n, 0);
|
pExpr->token.z, pExpr->token.n, 0);
|
||||||
pParse->nErr++;
|
pParse->nErr++;
|
||||||
@@ -667,6 +684,12 @@ int sqliteExprCheck(Parse *pParse, Expr *pExpr, int allowAgg, int *pIsAgg){
|
|||||||
pExpr->token.z, pExpr->token.n, "()", 2, 0);
|
pExpr->token.z, pExpr->token.n, "()", 2, 0);
|
||||||
pParse->nErr++;
|
pParse->nErr++;
|
||||||
nErr++;
|
nErr++;
|
||||||
|
}else if( wrong_num_args ){
|
||||||
|
sqliteSetNString(&pParse->zErrMsg,
|
||||||
|
"wrong number of arguments to function ",-1,
|
||||||
|
pExpr->token.z, pExpr->token.n, "()", 2, 0);
|
||||||
|
pParse->nErr++;
|
||||||
|
nErr++;
|
||||||
}
|
}
|
||||||
if( is_agg ) pExpr->op = TK_AGG_FUNCTION;
|
if( is_agg ) pExpr->op = TK_AGG_FUNCTION;
|
||||||
if( is_agg && pIsAgg ) *pIsAgg = 1;
|
if( is_agg && pIsAgg ) *pIsAgg = 1;
|
||||||
@@ -886,6 +909,18 @@ void sqliteExprCode(Parse *pParse, Expr *pExpr){
|
|||||||
sqliteVdbeAddOp(v, OP_Substr, 0, 0);
|
sqliteVdbeAddOp(v, OP_Substr, 0, 0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case FN_Unknown: {
|
||||||
|
UserFunc *pUser;
|
||||||
|
pUser = sqliteFindUserFunction(pParse->db,
|
||||||
|
pExpr->token.z, pExpr->token.n, pList->nExpr, 0);
|
||||||
|
assert( pUser!=0 );
|
||||||
|
for(i=0; i<pList->nExpr; i++){
|
||||||
|
sqliteExprCode(pParse, pList->a[i].pExpr);
|
||||||
|
}
|
||||||
|
sqliteVdbeAddOp(v, OP_UserFunc, pList->nExpr, 0);
|
||||||
|
sqliteVdbeChangeP3(v, -1, (char*)pUser->xFunc, P3_POINTER);
|
||||||
|
break;
|
||||||
|
}
|
||||||
default: {
|
default: {
|
||||||
/* Can't happen! */
|
/* Can't happen! */
|
||||||
break;
|
break;
|
||||||
@@ -1245,3 +1280,52 @@ int sqliteExprAnalyzeAggregates(Parse *pParse, Expr *pExpr){
|
|||||||
}
|
}
|
||||||
return nErr;
|
return nErr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Locate a user function given a name and a number of arguments.
|
||||||
|
** Return a pointer to the UserFunc structure that defines that
|
||||||
|
** function, or return NULL if the function does not exist.
|
||||||
|
**
|
||||||
|
** If the createFlag argument is true, then a new (blank) UserFunc
|
||||||
|
** structure is created and liked into the "db" structure if a
|
||||||
|
** no matching function previously existed. When createFlag is true
|
||||||
|
** and the nArg parameter is -1, then only a function that accepts
|
||||||
|
** any number of arguments will be returned.
|
||||||
|
**
|
||||||
|
** If createFlag is false and nArg is -1, then the first valid
|
||||||
|
** function found is returned. A function is valid if either xFunc
|
||||||
|
** or xStep is non-zero.
|
||||||
|
*/
|
||||||
|
UserFunc *sqliteFindUserFunction(
|
||||||
|
sqlite *db, /* An open database */
|
||||||
|
const char *zName, /* Name of the function. Not null-terminated */
|
||||||
|
int nName, /* Number of characters in the name */
|
||||||
|
int nArg, /* Number of arguments. -1 means any number */
|
||||||
|
int createFlag /* Create new entry if true and does not otherwise exist */
|
||||||
|
){
|
||||||
|
UserFunc *pFirst, *p, *pMaybe;
|
||||||
|
pFirst = p = (UserFunc*)sqliteHashFind(&db->userFunc, zName, nName);
|
||||||
|
if( !createFlag && nArg<0 ){
|
||||||
|
while( p && p->xFunc==0 && p->xStep==0 ){ p = p->pNext; }
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
pMaybe = 0;
|
||||||
|
while( p && p->nArg!=nArg ){
|
||||||
|
if( p->nArg<0 && !createFlag && (p->xFunc || p->xStep) ) pMaybe = p;
|
||||||
|
p = p->pNext;
|
||||||
|
}
|
||||||
|
if( p && !createFlag && p->xFunc==0 && p->xStep==0 ){
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if( p==0 && pMaybe ){
|
||||||
|
assert( createFlag==0 );
|
||||||
|
return pMaybe;
|
||||||
|
}
|
||||||
|
if( p==0 && createFlag ){
|
||||||
|
p = sqliteMalloc( sizeof(*p) );
|
||||||
|
p->nArg = nArg;
|
||||||
|
p->pNext = pFirst;
|
||||||
|
sqliteHashInsert(&db->userFunc, zName, nName, (void*)p);
|
||||||
|
}
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
@@ -12,7 +12,7 @@
|
|||||||
** This is the implementation of generic hash-tables
|
** This is the implementation of generic hash-tables
|
||||||
** used in SQLite.
|
** used in SQLite.
|
||||||
**
|
**
|
||||||
** $Id: hash.c,v 1.6 2002/01/14 09:28:20 drh Exp $
|
** $Id: hash.c,v 1.7 2002/02/23 23:45:45 drh Exp $
|
||||||
*/
|
*/
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
@@ -286,7 +286,7 @@ void *sqliteHashFind(const Hash *pH, const void *pKey, int nKey){
|
|||||||
** If the "data" parameter to this function is NULL, then the
|
** If the "data" parameter to this function is NULL, then the
|
||||||
** element corresponding to "key" is removed from the hash table.
|
** element corresponding to "key" is removed from the hash table.
|
||||||
*/
|
*/
|
||||||
void *sqliteHashInsert(Hash *pH, void *pKey, int nKey, void *data){
|
void *sqliteHashInsert(Hash *pH, const void *pKey, int nKey, void *data){
|
||||||
int hraw; /* Raw hash value of the key */
|
int hraw; /* Raw hash value of the key */
|
||||||
int h; /* the hash of the key modulo hash table size */
|
int h; /* the hash of the key modulo hash table size */
|
||||||
HashElem *elem; /* Used to loop thru the element list */
|
HashElem *elem; /* Used to loop thru the element list */
|
||||||
@@ -320,7 +320,7 @@ void *sqliteHashInsert(Hash *pH, void *pKey, int nKey, void *data){
|
|||||||
}
|
}
|
||||||
memcpy((void*)new_elem->pKey, pKey, nKey);
|
memcpy((void*)new_elem->pKey, pKey, nKey);
|
||||||
}else{
|
}else{
|
||||||
new_elem->pKey = pKey;
|
new_elem->pKey = (const void*)pKey;
|
||||||
}
|
}
|
||||||
new_elem->nKey = nKey;
|
new_elem->nKey = nKey;
|
||||||
pH->count++;
|
pH->count++;
|
||||||
|
@@ -12,7 +12,7 @@
|
|||||||
** This is the header file for the generic hash-table implemenation
|
** This is the header file for the generic hash-table implemenation
|
||||||
** used in SQLite.
|
** used in SQLite.
|
||||||
**
|
**
|
||||||
** $Id: hash.h,v 1.3 2002/02/03 03:34:09 drh Exp $
|
** $Id: hash.h,v 1.4 2002/02/23 23:45:45 drh Exp $
|
||||||
*/
|
*/
|
||||||
#ifndef _SQLITE_HASH_H_
|
#ifndef _SQLITE_HASH_H_
|
||||||
#define _SQLITE_HASH_H_
|
#define _SQLITE_HASH_H_
|
||||||
@@ -79,7 +79,7 @@ struct HashElem {
|
|||||||
** Access routines. To delete, insert a NULL pointer.
|
** Access routines. To delete, insert a NULL pointer.
|
||||||
*/
|
*/
|
||||||
void sqliteHashInit(Hash*, int keytype, int copyKey);
|
void sqliteHashInit(Hash*, int keytype, int copyKey);
|
||||||
void *sqliteHashInsert(Hash*, void *pKey, int nKey, void *pData);
|
void *sqliteHashInsert(Hash*, const void *pKey, int nKey, void *pData);
|
||||||
void *sqliteHashFind(const Hash*, const void *pKey, int nKey);
|
void *sqliteHashFind(const Hash*, const void *pKey, int nKey);
|
||||||
void sqliteHashClear(Hash*);
|
void sqliteHashClear(Hash*);
|
||||||
|
|
||||||
|
83
src/main.c
83
src/main.c
@@ -14,8 +14,9 @@
|
|||||||
** other files are for internal use by SQLite and should not be
|
** other files are for internal use by SQLite and should not be
|
||||||
** accessed by users of the library.
|
** accessed by users of the library.
|
||||||
**
|
**
|
||||||
** $Id: main.c,v 1.61 2002/02/21 12:01:27 drh Exp $
|
** $Id: main.c,v 1.62 2002/02/23 23:45:45 drh Exp $
|
||||||
*/
|
*/
|
||||||
|
#include <ctype.h>
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
#include "os.h"
|
#include "os.h"
|
||||||
|
|
||||||
@@ -292,6 +293,30 @@ const char sqlite_encoding[] = "UTF-8";
|
|||||||
const char sqlite_encoding[] = "iso8859";
|
const char sqlite_encoding[] = "iso8859";
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Implementation of the upper() and lower() SQL functions.
|
||||||
|
*/
|
||||||
|
static void upperFunc(void *context, int argc, const char **argv){
|
||||||
|
char *z;
|
||||||
|
int i;
|
||||||
|
if( argc<1 || argv[0]==0 ) return;
|
||||||
|
z = sqlite_set_result_string(context, argv[0], -1);
|
||||||
|
if( z==0 ) return;
|
||||||
|
for(i=0; z[i]; i++){
|
||||||
|
if( islower(z[i]) ) z[i] = toupper(z[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static void lowerFunc(void *context, int argc, const char **argv){
|
||||||
|
char *z;
|
||||||
|
int i;
|
||||||
|
if( argc<1 || argv[0]==0 ) return;
|
||||||
|
z = sqlite_set_result_string(context, argv[0], -1);
|
||||||
|
if( z==0 ) return;
|
||||||
|
for(i=0; z[i]; i++){
|
||||||
|
if( isupper(z[i]) ) z[i] = tolower(z[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Open a new SQLite database. Construct an "sqlite" structure to define
|
** Open a new SQLite database. Construct an "sqlite" structure to define
|
||||||
** the state of this database and return a pointer to that structure.
|
** the state of this database and return a pointer to that structure.
|
||||||
@@ -313,6 +338,9 @@ sqlite *sqlite_open(const char *zFilename, int mode, char **pzErrMsg){
|
|||||||
sqliteHashInit(&db->idxHash, SQLITE_HASH_STRING, 0);
|
sqliteHashInit(&db->idxHash, SQLITE_HASH_STRING, 0);
|
||||||
sqliteHashInit(&db->tblDrop, SQLITE_HASH_POINTER, 0);
|
sqliteHashInit(&db->tblDrop, SQLITE_HASH_POINTER, 0);
|
||||||
sqliteHashInit(&db->idxDrop, SQLITE_HASH_POINTER, 0);
|
sqliteHashInit(&db->idxDrop, SQLITE_HASH_POINTER, 0);
|
||||||
|
sqliteHashInit(&db->userFunc, SQLITE_HASH_STRING, 1);
|
||||||
|
sqlite_create_function(db, "upper", 1, upperFunc);
|
||||||
|
sqlite_create_function(db, "lower", 1, lowerFunc);
|
||||||
db->onError = OE_Default;
|
db->onError = OE_Default;
|
||||||
db->priorNewRowid = 0;
|
db->priorNewRowid = 0;
|
||||||
|
|
||||||
@@ -408,11 +436,20 @@ int sqlite_last_insert_rowid(sqlite *db){
|
|||||||
** Close an existing SQLite database
|
** Close an existing SQLite database
|
||||||
*/
|
*/
|
||||||
void sqlite_close(sqlite *db){
|
void sqlite_close(sqlite *db){
|
||||||
|
HashElem *i;
|
||||||
sqliteBtreeClose(db->pBe);
|
sqliteBtreeClose(db->pBe);
|
||||||
clearHashTable(db, 0);
|
clearHashTable(db, 0);
|
||||||
if( db->pBeTemp ){
|
if( db->pBeTemp ){
|
||||||
sqliteBtreeClose(db->pBeTemp);
|
sqliteBtreeClose(db->pBeTemp);
|
||||||
}
|
}
|
||||||
|
for(i=sqliteHashFirst(&db->userFunc); i; i=sqliteHashNext(i)){
|
||||||
|
UserFunc *pFunc, *pNext;
|
||||||
|
for(pFunc = (UserFunc*)sqliteHashData(i); pFunc; pFunc=pNext){
|
||||||
|
pNext = pFunc->pNext;
|
||||||
|
sqliteFree(pFunc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sqliteHashClear(&db->userFunc);
|
||||||
sqliteFree(db);
|
sqliteFree(db);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -613,3 +650,47 @@ void sqlite_freemem(void *p){ free(p); }
|
|||||||
*/
|
*/
|
||||||
const char *sqlite_libversion(void){ return sqlite_version; }
|
const char *sqlite_libversion(void){ return sqlite_version; }
|
||||||
const char *sqlite_libencoding(void){ return sqlite_encoding; }
|
const char *sqlite_libencoding(void){ return sqlite_encoding; }
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Create new user-defined functions. The sqlite_create_function()
|
||||||
|
** routine creates a regular function and sqlite_create_aggregate()
|
||||||
|
** creates an aggregate function.
|
||||||
|
**
|
||||||
|
** Passing a NULL xFunc argument or NULL xStep and xFinalize arguments
|
||||||
|
** disables the function. Calling sqlite_create_function() with the
|
||||||
|
** same name and number of arguments as a prior call to
|
||||||
|
** sqlite_create_aggregate() disables the prior call to
|
||||||
|
** sqlite_create_aggregate(), and vice versa.
|
||||||
|
**
|
||||||
|
** If nArg is -1 it means that this function will accept any number
|
||||||
|
** of arguments, including 0.
|
||||||
|
*/
|
||||||
|
int sqlite_create_function(
|
||||||
|
sqlite *db, /* Add the function to this database connection */
|
||||||
|
const char *zName, /* Name of the function to add */
|
||||||
|
int nArg, /* Number of arguments */
|
||||||
|
void (*xFunc)(void*,int,const char**) /* Implementation of the function */
|
||||||
|
){
|
||||||
|
UserFunc *p;
|
||||||
|
if( db==0 || zName==0 ) return 1;
|
||||||
|
p = sqliteFindUserFunction(db, zName, strlen(zName), nArg, 1);
|
||||||
|
p->xFunc = xFunc;
|
||||||
|
p->xStep = 0;
|
||||||
|
p->xFinalize = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
int sqlite_create_aggregate(
|
||||||
|
sqlite *db, /* Add the function to this database connection */
|
||||||
|
const char *zName, /* Name of the function to add */
|
||||||
|
int nArg, /* Number of arguments */
|
||||||
|
void *(*xStep)(void*,int,const char**), /* The step function */
|
||||||
|
void (*xFinalize)(void*,void*) /* The finalizer */
|
||||||
|
){
|
||||||
|
UserFunc *p;
|
||||||
|
if( db==0 || zName==0 ) return 1;
|
||||||
|
p = sqliteFindUserFunction(db, zName, strlen(zName), nArg, 1);
|
||||||
|
p->xFunc = 0;
|
||||||
|
p->xStep = xStep;
|
||||||
|
p->xFinalize = xFinalize;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
@@ -12,7 +12,7 @@
|
|||||||
** This header file defines the interface that the SQLite library
|
** This header file defines the interface that the SQLite library
|
||||||
** presents to client programs.
|
** presents to client programs.
|
||||||
**
|
**
|
||||||
** @(#) $Id: sqlite.h.in,v 1.25 2002/01/16 21:00:27 drh Exp $
|
** @(#) $Id: sqlite.h.in,v 1.26 2002/02/23 23:45:45 drh Exp $
|
||||||
*/
|
*/
|
||||||
#ifndef _SQLITE_H_
|
#ifndef _SQLITE_H_
|
||||||
#define _SQLITE_H_
|
#define _SQLITE_H_
|
||||||
@@ -362,6 +362,41 @@ int sqlite_get_table_vprintf(
|
|||||||
va_list ap /* Arguments to the format string */
|
va_list ap /* Arguments to the format string */
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Use the following routines to create new user-defined functions. See
|
||||||
|
** the documentation for details.
|
||||||
|
*/
|
||||||
|
int sqlite_create_function(
|
||||||
|
sqlite*, /* Database where the new function is registered */
|
||||||
|
const char *zName, /* Name of the new function */
|
||||||
|
int nArg, /* Number of arguments. -1 means any number */
|
||||||
|
void (*xFunc)(void*,int,const char**) /* C code to implement the function */
|
||||||
|
);
|
||||||
|
int sqlite_create_aggregate(
|
||||||
|
sqlite*, /* Database where the new function is registered */
|
||||||
|
const char *zName, /* Name of the function */
|
||||||
|
int nArg, /* Number of arguments */
|
||||||
|
void *(*xStep)(void*,int,const char**), /* Called for each row */
|
||||||
|
void (*xFinalize)(void*,void*) /* Called once to get final result */
|
||||||
|
);
|
||||||
|
|
||||||
|
/*
|
||||||
|
** The user function implementations call one of the following four routines
|
||||||
|
** in order to return their results. The first parameter to each of these
|
||||||
|
** routines is a copy of the first argument to xFunc() or the second argument
|
||||||
|
** to xFinalize(). The second parameter to these routines is the result
|
||||||
|
** to be returned. A NULL can be passed as the second parameter to
|
||||||
|
** sqlite_set_result_string() in order to return a NULL result.
|
||||||
|
**
|
||||||
|
** The 3rd argument to _string and _error is the number of characters to
|
||||||
|
** take from the string. If this argument is negative, then all characters
|
||||||
|
** up to and including the first '\000' are used.
|
||||||
|
*/
|
||||||
|
char *sqlite_set_result_string(void*,const char*,int);
|
||||||
|
void sqlite_set_result_int(void*,int);
|
||||||
|
void sqlite_set_result_double(void*,double);
|
||||||
|
void sqlite_set_result_error(void*,const char*,int);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
} /* End of the 'extern "C"' block */
|
} /* End of the 'extern "C"' block */
|
||||||
#endif
|
#endif
|
||||||
|
@@ -11,7 +11,7 @@
|
|||||||
*************************************************************************
|
*************************************************************************
|
||||||
** Internal interface definitions for SQLite.
|
** Internal interface definitions for SQLite.
|
||||||
**
|
**
|
||||||
** @(#) $Id: sqliteInt.h,v 1.90 2002/02/23 02:32:10 drh Exp $
|
** @(#) $Id: sqliteInt.h,v 1.91 2002/02/23 23:45:45 drh Exp $
|
||||||
*/
|
*/
|
||||||
#include "sqlite.h"
|
#include "sqlite.h"
|
||||||
#include "hash.h"
|
#include "hash.h"
|
||||||
@@ -130,7 +130,7 @@ extern int sqlite_iMallocFail; /* Fail sqliteMalloc() after this many calls */
|
|||||||
/*
|
/*
|
||||||
** Integer identifiers for built-in SQL functions.
|
** Integer identifiers for built-in SQL functions.
|
||||||
*/
|
*/
|
||||||
#define FN_Unknown 0
|
#define FN_Unknown 0 /* Not a built-in. Might be user defined */
|
||||||
#define FN_Count 1
|
#define FN_Count 1
|
||||||
#define FN_Min 2
|
#define FN_Min 2
|
||||||
#define FN_Max 3
|
#define FN_Max 3
|
||||||
@@ -158,6 +158,7 @@ typedef struct WhereInfo WhereInfo;
|
|||||||
typedef struct WhereLevel WhereLevel;
|
typedef struct WhereLevel WhereLevel;
|
||||||
typedef struct Select Select;
|
typedef struct Select Select;
|
||||||
typedef struct AggExpr AggExpr;
|
typedef struct AggExpr AggExpr;
|
||||||
|
typedef struct UserFunc UserFunc;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Each database is an instance of the following structure
|
** Each database is an instance of the following structure
|
||||||
@@ -176,6 +177,7 @@ struct sqlite {
|
|||||||
Hash idxHash; /* All (named) indices indexed by name */
|
Hash idxHash; /* All (named) indices indexed by name */
|
||||||
Hash tblDrop; /* Uncommitted DROP TABLEs */
|
Hash tblDrop; /* Uncommitted DROP TABLEs */
|
||||||
Hash idxDrop; /* Uncommitted DROP INDEXs */
|
Hash idxDrop; /* Uncommitted DROP INDEXs */
|
||||||
|
Hash userFunc; /* User defined functions */
|
||||||
int lastRowid; /* ROWID of most recent insert */
|
int lastRowid; /* ROWID of most recent insert */
|
||||||
int priorNewRowid; /* Last randomly generated ROWID */
|
int priorNewRowid; /* Last randomly generated ROWID */
|
||||||
int onError; /* Default conflict algorithm */
|
int onError; /* Default conflict algorithm */
|
||||||
@@ -198,9 +200,18 @@ struct sqlite {
|
|||||||
#define SQLITE_ResultDetails 0x00000100 /* Details added to result set */
|
#define SQLITE_ResultDetails 0x00000100 /* Details added to result set */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Current file format version
|
** Each user-defined function is defined by an instance of the following
|
||||||
|
** structure. A pointer to this structure is stored in the sqlite.userFunc
|
||||||
|
** hash table. When multiple functions have the same name, the hash table
|
||||||
|
** points to a linked list of these structures.
|
||||||
*/
|
*/
|
||||||
#define SQLITE_FileFormat 2
|
struct UserFunc {
|
||||||
|
void (*xFunc)(void*,int,const char**); /* Regular function */
|
||||||
|
void *(*xStep)(void*,int,const char**); /* Aggregate function step */
|
||||||
|
void (*xFinalize)(void*,void*); /* Aggregate function finializer */
|
||||||
|
int nArg; /* Number of arguments */
|
||||||
|
UserFunc *pNext; /* Next function with same name */
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** information about each column of an SQL table is held in an instance
|
** information about each column of an SQL table is held in an instance
|
||||||
@@ -634,3 +645,4 @@ void sqliteEndWriteOperation(Parse*);
|
|||||||
void sqliteExprMoveStrings(Expr*, int);
|
void sqliteExprMoveStrings(Expr*, int);
|
||||||
void sqliteExprListMoveStrings(ExprList*, int);
|
void sqliteExprListMoveStrings(ExprList*, int);
|
||||||
void sqliteSelectMoveStrings(Select*, int);
|
void sqliteSelectMoveStrings(Select*, int);
|
||||||
|
UserFunc *sqliteFindUserFunction(sqlite*,const char*,int,int,int);
|
||||||
|
@@ -17,6 +17,7 @@
|
|||||||
** if they are not used.
|
** if they are not used.
|
||||||
*/
|
*/
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
#include "sqlite.h"
|
#include "sqlite.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
122
src/vdbe.c
122
src/vdbe.c
@@ -30,7 +30,7 @@
|
|||||||
** But other routines are also provided to help in building up
|
** But other routines are also provided to help in building up
|
||||||
** a program instruction by instruction.
|
** a program instruction by instruction.
|
||||||
**
|
**
|
||||||
** $Id: vdbe.c,v 1.121 2002/02/21 12:01:27 drh Exp $
|
** $Id: vdbe.c,v 1.122 2002/02/23 23:45:45 drh Exp $
|
||||||
*/
|
*/
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
@@ -138,6 +138,16 @@ typedef struct Mem Mem;
|
|||||||
#define STK_Dyn 0x0010 /* Need to call sqliteFree() on zStack[*] */
|
#define STK_Dyn 0x0010 /* Need to call sqliteFree() on zStack[*] */
|
||||||
#define STK_Static 0x0020 /* zStack[] points to a static string */
|
#define STK_Static 0x0020 /* zStack[] points to a static string */
|
||||||
|
|
||||||
|
/*
|
||||||
|
** The "context" argument for a user-defined function.
|
||||||
|
*/
|
||||||
|
struct UserFuncContext {
|
||||||
|
Stack s; /* Small string, integer, and floating point values go here */
|
||||||
|
char *z; /* Space for holding dynamic string results */
|
||||||
|
int isError; /* Set to true for an error */
|
||||||
|
};
|
||||||
|
typedef struct UserFuncContext UserFuncContext;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** An Agg structure describes an Aggregator. Each Agg consists of
|
** An Agg structure describes an Aggregator. Each Agg consists of
|
||||||
** zero or more Aggregator elements (AggElem). Each AggElem contains
|
** zero or more Aggregator elements (AggElem). Each AggElem contains
|
||||||
@@ -492,6 +502,73 @@ void sqliteVdbeCompressSpace(Vdbe *p, int addr){
|
|||||||
z[j] = 0;
|
z[j] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** The following group or routines are employed by user-defined functions
|
||||||
|
** to return their results.
|
||||||
|
**
|
||||||
|
** The sqlite_set_result_string() routine can be used to return a string
|
||||||
|
** value or to return a NULL. To return a NULL, pass in NULL for zResult.
|
||||||
|
** A copy is made of the string before this routine returns so it is safe
|
||||||
|
** to pass in a ephemeral string.
|
||||||
|
**
|
||||||
|
** sqlite_set_result_error() works like sqlite_set_result_string() except
|
||||||
|
** that it signals a fatal error. The string argument, if any, is the
|
||||||
|
** error message. If the argument is NULL a generic substitute error message
|
||||||
|
** is used.
|
||||||
|
**
|
||||||
|
** The sqlite_set_result_int() and sqlite_set_result_double() set the return
|
||||||
|
** value of the user function to an integer or a double.
|
||||||
|
*/
|
||||||
|
char *sqlite_set_result_string(void *context, const char *zResult, int n){
|
||||||
|
UserFuncContext *p = (UserFuncContext*)context;
|
||||||
|
if( p->s.flags & STK_Dyn ){
|
||||||
|
sqliteFree(p->z);
|
||||||
|
}
|
||||||
|
if( zResult==0 ){
|
||||||
|
p->s.flags = STK_Null;
|
||||||
|
n = 0;
|
||||||
|
p->z = 0;
|
||||||
|
}else{
|
||||||
|
if( n<0 ) n = strlen(zResult);
|
||||||
|
if( n<NBFS-1 ){
|
||||||
|
memcpy(p->s.z, zResult, n);
|
||||||
|
p->s.z[n] = 0;
|
||||||
|
p->s.flags = STK_Str;
|
||||||
|
p->z = p->s.z;
|
||||||
|
}else{
|
||||||
|
p->z = sqliteMalloc( n+1 );
|
||||||
|
if( p->z ){
|
||||||
|
memcpy(p->z, zResult, n);
|
||||||
|
p->z[n] = 0;
|
||||||
|
}
|
||||||
|
p->s.flags = STK_Str | STK_Dyn;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
p->s.n = n;
|
||||||
|
return p->z;
|
||||||
|
}
|
||||||
|
void sqlite_set_result_int(void *context, int iResult){
|
||||||
|
UserFuncContext *p = (UserFuncContext*)context;
|
||||||
|
if( p->s.flags & STK_Dyn ){
|
||||||
|
sqliteFree(p->z);
|
||||||
|
}
|
||||||
|
p->s.i = iResult;
|
||||||
|
p->s.flags = STK_Int;
|
||||||
|
}
|
||||||
|
void sqlite_set_result_double(void *context, double rResult){
|
||||||
|
UserFuncContext *p = (UserFuncContext*)context;
|
||||||
|
if( p->s.flags & STK_Dyn ){
|
||||||
|
sqliteFree(p->z);
|
||||||
|
}
|
||||||
|
p->s.r = rResult;
|
||||||
|
p->s.flags = STK_Real;
|
||||||
|
}
|
||||||
|
void sqlite_set_result_error(void *context, const char *zMsg, int n){
|
||||||
|
UserFuncContext *p = (UserFuncContext*)context;
|
||||||
|
sqlite_set_result_string(context, zMsg, n);
|
||||||
|
p->isError = 1;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Reset an Agg structure. Delete all its contents.
|
** Reset an Agg structure. Delete all its contents.
|
||||||
*/
|
*/
|
||||||
@@ -891,7 +968,7 @@ static char *zOpName[] = { 0,
|
|||||||
"Le", "Gt", "Ge", "IsNull",
|
"Le", "Gt", "Ge", "IsNull",
|
||||||
"NotNull", "Negative", "And", "Or",
|
"NotNull", "Negative", "And", "Or",
|
||||||
"Not", "Concat", "Noop", "Strlen",
|
"Not", "Concat", "Noop", "Strlen",
|
||||||
"Substr", "Limit",
|
"Substr", "UserFunc", "UserAgg", "Limit",
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -1694,6 +1771,47 @@ case OP_Max: {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Opcode: UserFunc P1 * P3
|
||||||
|
**
|
||||||
|
** Invoke a user function (P3 is a pointer to the function) with
|
||||||
|
** P1 string arguments taken from the stack. Pop all arguments from
|
||||||
|
** the stack and push back the result.
|
||||||
|
*/
|
||||||
|
case OP_UserFunc: {
|
||||||
|
int n, i;
|
||||||
|
UserFuncContext ctx;
|
||||||
|
void (*xFunc)(void*,int,const char**);
|
||||||
|
n = pOp->p1;
|
||||||
|
VERIFY( if( n<=0 ) goto bad_instruction; )
|
||||||
|
VERIFY( if( p->tos+1<n ) goto not_enough_stack; )
|
||||||
|
for(i=p->tos-n+1; i<=p->tos; i++){
|
||||||
|
if( (aStack[i].flags & STK_Null)==0 ){
|
||||||
|
if( Stringify(p, i) ) goto no_mem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
xFunc = (void(*)(void*,int,const char**))pOp->p3;
|
||||||
|
ctx.s.flags = STK_Null;
|
||||||
|
ctx.isError = 0;
|
||||||
|
xFunc((void*)&ctx, n, (const char**)&zStack[p->tos-n+1]);
|
||||||
|
PopStack(p, n);
|
||||||
|
VERIFY( NeedStack(p, p->tos+1); )
|
||||||
|
p->tos++;
|
||||||
|
aStack[p->tos] = ctx.s;
|
||||||
|
if( ctx.s.flags & STK_Dyn ){
|
||||||
|
zStack[p->tos] = ctx.z;
|
||||||
|
}else if( ctx.s.flags & STK_Str ){
|
||||||
|
zStack[p->tos] = aStack[p->tos].z;
|
||||||
|
}else{
|
||||||
|
zStack[p->tos] = 0;
|
||||||
|
}
|
||||||
|
if( ctx.isError ){
|
||||||
|
sqliteSetString(pzErrMsg,
|
||||||
|
zStack[p->tos] ? zStack[p->tos] : "user function error", 0);
|
||||||
|
rc = SQLITE_ERROR;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
/* Opcode: BitAnd * * *
|
/* Opcode: BitAnd * * *
|
||||||
**
|
**
|
||||||
** Pop the top two elements from the stack. Convert both elements
|
** Pop the top two elements from the stack. Convert both elements
|
||||||
|
@@ -15,7 +15,7 @@
|
|||||||
** or VDBE. The VDBE implements an abstract machine that runs a
|
** or VDBE. The VDBE implements an abstract machine that runs a
|
||||||
** simple program to access and modify the underlying database.
|
** simple program to access and modify the underlying database.
|
||||||
**
|
**
|
||||||
** $Id: vdbe.h,v 1.44 2002/02/21 12:01:28 drh Exp $
|
** $Id: vdbe.h,v 1.45 2002/02/23 23:45:46 drh Exp $
|
||||||
*/
|
*/
|
||||||
#ifndef _SQLITE_VDBE_H_
|
#ifndef _SQLITE_VDBE_H_
|
||||||
#define _SQLITE_VDBE_H_
|
#define _SQLITE_VDBE_H_
|
||||||
@@ -198,13 +198,14 @@ typedef struct VdbeOp VdbeOp;
|
|||||||
#define OP_Not 113
|
#define OP_Not 113
|
||||||
#define OP_Concat 114
|
#define OP_Concat 114
|
||||||
#define OP_Noop 115
|
#define OP_Noop 115
|
||||||
|
|
||||||
#define OP_Strlen 116
|
#define OP_Strlen 116
|
||||||
#define OP_Substr 117
|
#define OP_Substr 117
|
||||||
|
#define OP_UserFunc 118
|
||||||
|
#define OP_UserAgg 119
|
||||||
|
|
||||||
#define OP_Limit 118
|
#define OP_Limit 120
|
||||||
|
|
||||||
#define OP_MAX 118
|
#define OP_MAX 120
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Prototypes for the VDBE interface. See comments on the implementation
|
** Prototypes for the VDBE interface. See comments on the implementation
|
||||||
|
@@ -11,7 +11,7 @@
|
|||||||
# This file implements regression tests for SQLite library. The
|
# This file implements regression tests for SQLite library. The
|
||||||
# focus of this file is testing the SELECT statement.
|
# focus of this file is testing the SELECT statement.
|
||||||
#
|
#
|
||||||
# $Id: select1.test,v 1.18 2002/01/22 14:11:30 drh Exp $
|
# $Id: select1.test,v 1.19 2002/02/23 23:45:47 drh Exp $
|
||||||
|
|
||||||
set testdir [file dirname $argv0]
|
set testdir [file dirname $argv0]
|
||||||
source $testdir/tester.tcl
|
source $testdir/tester.tcl
|
||||||
@@ -183,7 +183,7 @@ do_test select1-2.19 {
|
|||||||
do_test select1-2.20 {
|
do_test select1-2.20 {
|
||||||
set v [catch {execsql {SELECT SUM(min(f1)) FROM test1}} msg]
|
set v [catch {execsql {SELECT SUM(min(f1)) FROM test1}} msg]
|
||||||
lappend v $msg
|
lappend v $msg
|
||||||
} {1 {too few arguments to function min()}}
|
} {1 {misuse of aggregate function min()}}
|
||||||
|
|
||||||
# WHERE clause expressions
|
# WHERE clause expressions
|
||||||
#
|
#
|
||||||
@@ -222,7 +222,7 @@ do_test select1-3.8 {
|
|||||||
do_test select1-3.9 {
|
do_test select1-3.9 {
|
||||||
set v [catch {execsql {SELECT f1 FROM test1 WHERE count(f1,f2)!=11}} msg]
|
set v [catch {execsql {SELECT f1 FROM test1 WHERE count(f1,f2)!=11}} msg]
|
||||||
lappend v $msg
|
lappend v $msg
|
||||||
} {1 {no such function: count}}
|
} {1 {misuse of aggregate function count()}}
|
||||||
|
|
||||||
# ORDER BY expressions
|
# ORDER BY expressions
|
||||||
#
|
#
|
||||||
@@ -241,7 +241,7 @@ do_test select1-4.3 {
|
|||||||
do_test select1-4.4 {
|
do_test select1-4.4 {
|
||||||
set v [catch {execsql {SELECT f1 FROM test1 ORDER BY min(f1)}} msg]
|
set v [catch {execsql {SELECT f1 FROM test1 ORDER BY min(f1)}} msg]
|
||||||
lappend v $msg
|
lappend v $msg
|
||||||
} {1 {too few arguments to function min()}}
|
} {1 {misuse of aggregate function min()}}
|
||||||
do_test select1-4.5 {
|
do_test select1-4.5 {
|
||||||
catchsql {
|
catchsql {
|
||||||
SELECT f1 FROM test1 ORDER BY 8.4;
|
SELECT f1 FROM test1 ORDER BY 8.4;
|
||||||
|
@@ -25,6 +25,9 @@ chng {2002 Feb * (2.3.4)} {
|
|||||||
<li>Automatically generated ROWIDs are now sequential.</li>
|
<li>Automatically generated ROWIDs are now sequential.</li>
|
||||||
<li>Do not allow dot-commands of the command-line shell to occur in the
|
<li>Do not allow dot-commands of the command-line shell to occur in the
|
||||||
middle of a real SQL command.</li>
|
middle of a real SQL command.</li>
|
||||||
|
<li>Modifications to the "lemon" parser generator so that the parser tables
|
||||||
|
are 4 times smaller.</li>
|
||||||
|
<li>Added support for user-defined functions implemented in C.</li>
|
||||||
}
|
}
|
||||||
|
|
||||||
chng {2002 Feb 18 (2.3.3)} {
|
chng {2002 Feb 18 (2.3.3)} {
|
||||||
|
Reference in New Issue
Block a user