Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | The new function code passes regression tests. (CVS 403) |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
b00cf110b1cc671b7200a5ce8b9e704f |
User & Date: | drh 2002-02-28 03:04:48.000 |
Context
2002-02-28
| ||
03:14 | Change the IFNULL and NVL functions to COALESCE. Change MIN and MAX so that they require at least one argument. (CVS 404) (check-in: 7d86749d4a user: drh tags: trunk) | |
03:04 | The new function code passes regression tests. (CVS 403) (check-in: b00cf110b1 user: drh tags: trunk) | |
01:46 | Fix the coredump. There are still problems in the test suite though. (CVS 402) (check-in: 6af10cc53a user: drh tags: trunk) | |
Changes
Changes to src/expr.c.
︙ | ︙ | |||
8 9 10 11 12 13 14 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains routines used for analyzing expressions and ** for generating VDBE code that evaluates expressions in SQLite. ** | | | 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains routines used for analyzing expressions and ** for generating VDBE code that evaluates expressions in SQLite. ** ** $Id: expr.c,v 1.51 2002/02/28 03:04:48 drh Exp $ */ #include "sqliteInt.h" /* ** Construct a new expression node and return a pointer to it. Memory ** for this node is obtained from sqliteMalloc(). The calling function |
︙ | ︙ | |||
648 649 650 651 652 653 654 | int n = pExpr->pList ? pExpr->pList->nExpr : 0; int no_such_func = 0; int wrong_num_args = 0; int is_agg = 0; int i; FuncDef *pDef; | | > | 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 | int n = pExpr->pList ? pExpr->pList->nExpr : 0; int no_such_func = 0; int wrong_num_args = 0; int is_agg = 0; int i; FuncDef *pDef; pDef = sqliteFindFunction(pParse->db, pExpr->token.z, pExpr->token.n, n, 0); if( pDef==0 ){ pDef = sqliteFindFunction(pParse->db, pExpr->token.z, pExpr->token.n, -1, 0); if( pDef==0 ){ no_such_func = 1; }else{ wrong_num_args = 1; |
︙ | ︙ | |||
850 851 852 853 854 855 856 857 858 | case TK_AGG_FUNCTION: { sqliteVdbeAddOp(v, OP_AggGet, 0, pExpr->iAgg); break; } case TK_FUNCTION: { int i; ExprList *pList = pExpr->pList; FuncDef *pDef; pDef = sqliteFindFunction(pParse->db, | > | | | | 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 | case TK_AGG_FUNCTION: { sqliteVdbeAddOp(v, OP_AggGet, 0, pExpr->iAgg); break; } case TK_FUNCTION: { int i; ExprList *pList = pExpr->pList; int nExpr = pList ? pList->nExpr : 0; FuncDef *pDef; pDef = sqliteFindFunction(pParse->db, pExpr->token.z, pExpr->token.n, nExpr, 0); assert( pDef!=0 ); for(i=0; i<nExpr; i++){ sqliteExprCode(pParse, pList->a[i].pExpr); } sqliteVdbeAddOp(v, OP_Function, nExpr, 0); sqliteVdbeChangeP3(v, -1, (char*)pDef, P3_POINTER); break; } case TK_SELECT: { sqliteVdbeAddOp(v, OP_MemLoad, pExpr->iColumn, 0); break; } |
︙ | ︙ | |||
1242 1243 1244 1245 1246 1247 1248 | if( p && !createFlag && p->xFunc==0 && p->xStep==0 ){ return 0; } if( p==0 && pMaybe ){ assert( createFlag==0 ); return pMaybe; } | | < | 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 | 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)))!=0 ){ p->nArg = nArg; p->pNext = pFirst; sqliteHashInsert(&db->aFunc, zName, nName, (void*)p); } return p; } |
Changes to src/func.c.
︙ | ︙ | |||
12 13 14 15 16 17 18 | ** This file contains the C functions that implement various SQL ** functions of SQLite. ** ** There is only one exported symbol in this file - the function ** sqliteRegisterBuildinFunctions() found at the bottom of the file. ** All other code has file scope. ** | | > > | 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 | ** This file contains the C functions that implement various SQL ** functions of SQLite. ** ** There is only one exported symbol in this file - the function ** sqliteRegisterBuildinFunctions() found at the bottom of the file. ** All other code has file scope. ** ** $Id: func.c,v 1.9 2002/02/28 03:04:48 drh Exp $ */ #include <ctype.h> #include <math.h> #include <stdlib.h> #include <assert.h> #include "sqliteInt.h" /* ** Implementation of the non-aggregate min() and max() functions */ static void minFunc(sqlite_func *context, int argc, const char **argv){ const char *zBest; int i; if( argc==0 ) return; zBest = argv[0]; for(i=1; i<argc; i++){ if( sqliteCompare(argv[i], zBest)<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]; for(i=1; i<argc; i++){ if( sqliteCompare(argv[i], zBest)>0 ){ zBest = argv[i]; } } sqlite_set_result_string(context, zBest, -1); |
︙ | ︙ | |||
101 102 103 104 105 106 107 | p2 = atoi(argv[2]?argv[2]:0); #ifdef SQLITE_UTF8 for(len=0, z2=z; *z2; z2++){ if( (0xc0&*z)!=0x80 ) len++; } #else len = strlen(z); #endif if( p1<0 ){ | | | 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 | p2 = atoi(argv[2]?argv[2]:0); #ifdef SQLITE_UTF8 for(len=0, z2=z; *z2; z2++){ if( (0xc0&*z)!=0x80 ) len++; } #else len = strlen(z); #endif if( p1<0 ){ p1 += len; }else if( p1>0 ){ p1--; } if( p1+p2>len ){ p2 = len-p1; } #ifdef SQLITE_UTF8 |
︙ | ︙ | |||
197 198 199 200 201 202 203 | if( p==0 ) return; x = argv[0] ? atof(argv[0]) : 0.0; p->sum += x; } static void sumFinalize(sqlite_func *context){ SumCtx *p; p = sqlite_aggregate_context(context, sizeof(*p)); | < | < | 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 | if( p==0 ) return; x = argv[0] ? atof(argv[0]) : 0.0; p->sum += x; } static void sumFinalize(sqlite_func *context){ SumCtx *p; p = sqlite_aggregate_context(context, sizeof(*p)); sqlite_set_result_double(context, p ? p->sum : 0.0); } static void avgFinalize(sqlite_func *context){ SumCtx *p; double rN; p = sqlite_aggregate_context(context, sizeof(*p)); rN = sqlite_aggregate_count(context); if( p && rN>0.0 ){ |
︙ | ︙ |
Changes to src/vdbe.c.
︙ | ︙ | |||
26 27 28 29 30 31 32 | ** type to the other occurs as necessary. ** ** Most of the code in this file is taken up by the sqliteVdbeExec() ** function which does the work of interpreting a VDBE program. ** But other routines are also provided to help in building up ** a program instruction by instruction. ** | | | 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | ** type to the other occurs as necessary. ** ** Most of the code in this file is taken up by the sqliteVdbeExec() ** function which does the work of interpreting a VDBE program. ** But other routines are also provided to help in building up ** a program instruction by instruction. ** ** $Id: vdbe.c,v 1.128 2002/02/28 03:04:48 drh Exp $ */ #include "sqliteInt.h" #include <ctype.h> /* ** The following global variable is incremented every time a cursor ** moves, either by the OP_MoveTo or the OP_Next opcode. The test |
︙ | ︙ | |||
548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 | 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; } } | > > < | 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 | if( p->s.flags & STK_Dyn ){ sqliteFree(p->z); } if( zResult==0 ){ p->s.flags = STK_Null; n = 0; p->z = 0; p->s.n = 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+1; } return p->z; } void sqlite_set_result_int(sqlite_func *p, int iResult){ assert( !p->isStep ); if( p->s.flags & STK_Dyn ){ sqliteFree(p->z); } |
︙ | ︙ | |||
1874 1875 1876 1877 1878 1879 1880 | ** See also: AggFunc */ case OP_Function: { int n, i; sqlite_func ctx; n = pOp->p1; | | | 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 | ** See also: AggFunc */ case OP_Function: { int n, i; sqlite_func ctx; 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; } } ctx.pFunc = (FuncDef*)pOp->p3; |
︙ | ︙ |
Changes to test/func.test.
1 2 3 4 5 6 7 8 9 10 11 12 13 | # 2001 September 15 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # This file implements regression tests for SQLite library. The # focus of this file is testing built-in functions. # | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | # 2001 September 15 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # This file implements regression tests for SQLite library. The # focus of this file is testing built-in functions. # # $Id: func.test,v 1.8 2002/02/28 03:04:48 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl # Create a table to work with. # do_test func-0.0 { |
︙ | ︙ | |||
30 31 32 33 34 35 36 | # do_test func-1.0 { execsql {SELECT length(t1) FROM tbl1 ORDER BY t1} } {4 2 7 8 4} do_test func-1.1 { set r [catch {execsql {SELECT length(*) FROM tbl1 ORDER BY t1}} msg] lappend r $msg | | | | 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | # do_test func-1.0 { execsql {SELECT length(t1) FROM tbl1 ORDER BY t1} } {4 2 7 8 4} do_test func-1.1 { set r [catch {execsql {SELECT length(*) FROM tbl1 ORDER BY t1}} msg] lappend r $msg } {1 {wrong number of arguments to function length()}} do_test func-1.2 { set r [catch {execsql {SELECT length(t1,5) FROM tbl1 ORDER BY t1}} msg] lappend r $msg } {1 {wrong number of arguments to function length()}} do_test func-1.3 { execsql {SELECT length(t1), count(*) FROM tbl1 GROUP BY length(t1) ORDER BY length(t1)} } {2 1 4 2 7 1 8 1} # Check out the substr() function # |
︙ | ︙ | |||
127 128 129 130 131 132 133 | execsql { CREATE TABLE t1(a,b,c); INSERT INTO t1 VALUES(1,2,3); INSERT INTO t1 VALUES(2,1.2345678901234,-12345.67890); INSERT INTO t1 VALUES(3,-2,-5); } catchsql {SELECT abs(a,b) FROM t1} | | | | | | | 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 | execsql { CREATE TABLE t1(a,b,c); INSERT INTO t1 VALUES(1,2,3); INSERT INTO t1 VALUES(2,1.2345678901234,-12345.67890); INSERT INTO t1 VALUES(3,-2,-5); } catchsql {SELECT abs(a,b) FROM t1} } {1 {wrong number of arguments to function abs()}} do_test func-4.2 { catchsql {SELECT abs() FROM t1} } {1 {wrong number of arguments to function abs()}} do_test func-4.3 { catchsql {SELECT abs(b) FROM t1 ORDER BY a} } {0 {2 1.2345678901234 2}} do_test func-4.4 { catchsql {SELECT abs(c) FROM t1 ORDER BY a} } {0 {3 12345.67890 5}} do_test func-4.5 { catchsql {SELECT round(a,b,c) FROM t1} } {1 {wrong number of arguments to function round()}} do_test func-4.6 { catchsql {SELECT round(b,2) FROM t1 ORDER BY b} } {0 {-2.00 1.23 2.00}} do_test func-4.7 { catchsql {SELECT round(b,0) FROM t1 ORDER BY a} } {0 {2 1 -2}} do_test func-4.8 { catchsql {SELECT round(c) FROM t1 ORDER BY a} } {0 {3 -12346 -5}} do_test func-4.9 { catchsql {SELECT round(c,a) FROM t1 ORDER BY a} } {0 {3.0 -12345.68 -5.000}} do_test func-4.10 { catchsql {SELECT 'x' || round(c,a) || 'y' FROM t1 ORDER BY a} } {0 {x3.0y x-12345.68y x-5.000y}} do_test func-4.11 { catchsql {SELECT round() FROM t1 ORDER BY a} } {1 {wrong number of arguments to function round()}} finish_test |
Changes to test/select1.test.
1 2 3 4 5 6 7 8 9 10 11 12 13 | # 2001 September 15 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # This file implements regression tests for SQLite library. The # focus of this file is testing the SELECT statement. # | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | # 2001 September 15 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # This file implements regression tests for SQLite library. The # focus of this file is testing the SELECT statement. # # $Id: select1.test,v 1.20 2002/02/28 03:04:48 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl # Try to select on a non-existant table. # do_test select1-1.1 { |
︙ | ︙ | |||
103 104 105 106 107 108 109 | execsql {INSERT INTO test1 VALUES(33,44)} # Error messges from sqliteExprCheck # do_test select1-2.1 { set v [catch {execsql {SELECT count(f1,f2) FROM test1}} msg] lappend v $msg | | | | | | | 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 | execsql {INSERT INTO test1 VALUES(33,44)} # Error messges from sqliteExprCheck # do_test select1-2.1 { set v [catch {execsql {SELECT count(f1,f2) FROM test1}} msg] lappend v $msg } {1 {wrong number of arguments to function count()}} do_test select1-2.2 { set v [catch {execsql {SELECT count(f1) FROM test1}} msg] lappend v $msg } {0 2} do_test select1-2.3 { set v [catch {execsql {SELECT Count() FROM test1}} msg] lappend v $msg } {0 2} do_test select1-2.4 { set v [catch {execsql {SELECT COUNT(*) FROM test1}} msg] lappend v $msg } {0 2} do_test select1-2.5 { set v [catch {execsql {SELECT COUNT(*)+1 FROM test1}} msg] lappend v $msg } {0 3} do_test select1-2.6 { set v [catch {execsql {SELECT min(*) FROM test1}} msg] lappend v $msg } {0 {{} {}}} do_test select1-2.7 { set v [catch {execsql {SELECT Min(f1) FROM test1}} msg] lappend v $msg } {0 11} do_test select1-2.8 { set v [catch {execsql {SELECT MIN(f1,f2) FROM test1}} msg] lappend v [lsort $msg] } {0 {11 33}} do_test select1-2.9 { set v [catch {execsql {SELECT MAX(*) FROM test1}} msg] lappend v $msg } {0 {{} {}}} do_test select1-2.10 { set v [catch {execsql {SELECT Max(f1) FROM test1}} msg] lappend v $msg } {0 33} do_test select1-2.11 { set v [catch {execsql {SELECT max(f1,f2) FROM test1}} msg] lappend v [lsort $msg] } {0 {22 44}} do_test select1-2.12 { set v [catch {execsql {SELECT MAX(f1,f2)+1 FROM test1}} msg] lappend v [lsort $msg] } {0 {23 45}} do_test select1-2.13 { set v [catch {execsql {SELECT MAX(f1)+1 FROM test1}} msg] lappend v $msg } {0 34} do_test select1-2.14 { set v [catch {execsql {SELECT SUM(*) FROM test1}} msg] lappend v $msg } {1 {wrong number of arguments to function SUM()}} do_test select1-2.15 { set v [catch {execsql {SELECT Sum(f1) FROM test1}} msg] lappend v $msg } {0 44} do_test select1-2.16 { set v [catch {execsql {SELECT sum(f1,f2) FROM test1}} msg] lappend v $msg } {1 {wrong number of arguments to function sum()}} do_test select1-2.17 { set v [catch {execsql {SELECT SUM(f1)+1 FROM test1}} msg] lappend v $msg } {0 45} do_test select1-2.18 { set v [catch {execsql {SELECT XYZZY(f1) FROM test1}} msg] lappend v $msg |
︙ | ︙ | |||
218 219 220 221 222 223 224 | do_test select1-3.8 { set v [catch {execsql {SELECT f1 FROM test1 WHERE max(f1,f2)!=11}} msg] lappend v [lsort $msg] } {0 {11 33}} do_test select1-3.9 { set v [catch {execsql {SELECT f1 FROM test1 WHERE count(f1,f2)!=11}} msg] lappend v $msg | | | 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 | do_test select1-3.8 { set v [catch {execsql {SELECT f1 FROM test1 WHERE max(f1,f2)!=11}} msg] lappend v [lsort $msg] } {0 {11 33}} do_test select1-3.9 { set v [catch {execsql {SELECT f1 FROM test1 WHERE count(f1,f2)!=11}} msg] lappend v $msg } {1 {wrong number of arguments to function count()}} # ORDER BY expressions # do_test select1-4.1 { set v [catch {execsql {SELECT f1 FROM test1 ORDER BY f1}} msg] lappend v $msg } {0 {11 33}} |
︙ | ︙ | |||
428 429 430 431 432 433 434 | } } {11 33} do_test select1-8.4 { execsql { SELECT f1/(f1-11), min(f1/(f1-11),5), max(f1/(f1-33),6) FROM test1 ORDER BY f1 } | | | 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 | } } {11 33} do_test select1-8.4 { execsql { SELECT f1/(f1-11), min(f1/(f1-11),5), max(f1/(f1-33),6) FROM test1 ORDER BY f1 } } {{} {} 6 1.5 1.5 6} do_test select1-8.5 { execsql { SELECT min(1,2,3), -max(1,2,3) FROM test1 ORDER BY f1 } } {1 -3 1 -3} |
︙ | ︙ |