-C Handle\ssome\sof\sthe\sIO\serror\sconditions\sthat\smay\soccur\sin\sa\sshared-cache\scontext.\s(CVS\s2980)
-D 2006-01-20T10:55:05
+C Fix\sand\stest\sthe\sprocessing\sof\ssqlite3_result_error()\swithing\saggregate\nfunctions.\s\sAllow\serrors\sto\scome\sfrom\sthe\sstep\sfunction\s(a\snew\ncapability).\s\sTicket\s#1632.\s(CVS\s2981)
+D 2006-01-20T15:45:36
F Makefile.in ab3ffd8d469cef4477257169b82810030a6bb967
F Makefile.linux-gcc aee18d8a05546dcf1888bd4547e442008a49a092
F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028
F src/sqliteInt.h 7ddd6141a57748363fe42119f165d06260996aa3
F src/table.c 486dcfce532685b53b5a2b5da8bba0ded6fb2316
F src/tclsqlite.c d650bea0248fc0a310ddc2cb94273a3a5021fddf
-F src/test1.c 44e8f194ee7d95e25dc421b10ced2ec9d89632a0
+F src/test1.c bcdd1978cb4f576611917948728acd09ede9c85d
F src/test2.c ca74a1d8aeb7d9606e8f6b762c5daf85c1a3f92b
F src/test3.c 86e99724ee898b119ed575ef9f98618afe7e5e5d
F src/test4.c 6633cb7b4a7429e938804a34f688d118c8b7f8e1
F src/utf.c 5ab8ca05d4e9ec81174b010f01ab12a232f0087d
F src/util.c 14f1f842caede231c8f72308c40d8e1f1cbec59e
F src/vacuum.c 3865673cc66acd0717ecd517f6b8fdb2a5e7924b
-F src/vdbe.c 2a3d5ea76ab166bd77de9e3a7dbeb4a9354a1603
+F src/vdbe.c 9eceb866b8197d25d07f700e16b1a50638d4bd6e
F src/vdbe.h 8729a4ee16ff9aeab2af9667df3cf300ff978e13
-F src/vdbeInt.h 5451cf71f229e366ac543607c0a17f36e5737ea9
+F src/vdbeInt.h eb3f86ab08ef11635bc78eb88c3ff13f923c233b
F src/vdbeapi.c b5a3eacce266a657cdc0fc740b60ba480fb88649
F src/vdbeaux.c d9a757ed4e3eefc54408226cb781694059fe2b39
F src/vdbefifo.c 9efb94c8c3f4c979ebd0028219483f88e57584f5
-F src/vdbemem.c 53f25c5c537e4ded24549d6c8537e65d4efc42d1
+F src/vdbemem.c 2034e93b32c14bda6e306bb54e3a8e930b963027
F src/where.c 5215507b232e718606e0014f999912d53de32a70
F tclinstaller.tcl 046e3624671962dc50f0481d7c25b38ef803eb42
+F test/aggerror.test b2223511ec37fcdeca023b5a261900f18261aad8
F test/all.test 5df90d015ca63fcef2a4b62c24f7316b66c4bfd4
F test/alter.test d2569ed639946be29cfcae9117942b4a6d01f719
F test/alter2.test cc0b8832e4e98605dbc26910efd4bb89abe59cb2
F test/expr.test a513aceb5d89042232e0d07ac5a1591965cf3963
F test/fkey1.test 153004438d51e6769fb1ce165f6313972d6263ce
F test/format4.test 9f31d41d4f926cab97b2ebe6be00a6ab12dece87
-F test/func.test a7119afcc16abdf24b24486684fb888279008f75
+F test/func.test 337888172c054c2de1aa3bacad6115522943dc2c
F test/hook.test 7e7645fd9a033f79cce8fdff151e32715e7ec50a
F test/in.test cead6165aebbe0d451bb2263a307173acfeb6240
F test/index.test c478459611ded74745fee57f99f424da8a5f5fbd
F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0
F www/version3.tcl a99cf5f6d8bd4d5537584a2b342f0fb9fa601d8b
F www/whentouse.tcl 97e2b5cd296f7d8057e11f44427dea8a4c2db513
-P 0208e4221a2d90b5ae0755061c345d3351a30da8
-R 1b27118630fddde079e3c9acefda5965
-U danielk1977
-Z 68c504492dfd4d0600ae3c8ff35cbb3d
+P 97491d4eb5fc24d8f5cc7605db844359ecc6a818
+R 0ac1c3b7951d8503eabc2e4f37bf1aac
+U drh
+Z 64f4b8a9886c6294a59c365b44cd61fd
-97491d4eb5fc24d8f5cc7605db844359ecc6a818
\ No newline at end of file
+fd4a6bb1ac94d085dda247799c0a5c64aaeec046
\ No newline at end of file
** is not included in the SQLite library. It is used for automated
** testing of the SQLite library.
**
-** $Id: test1.c,v 1.200 2006/01/20 10:55:05 danielk1977 Exp $
+** $Id: test1.c,v 1.201 2006/01/20 15:45:36 drh Exp $
*/
#include "sqliteInt.h"
#include "tcl.h"
/*
** Routines to implement the x_count() aggregate function.
+**
+** x_count() counts the number of non-null arguments. But there are
+** some twists for testing purposes.
+**
+** If the argument to x_count() is 40 then a UTF-8 error is reported
+** on the step function. If x_count(41) is seen, then a UTF-16 error
+** is reported on the step function. If the total count is 42, then
+** a UTF-8 error is reported on the finalize function.
*/
typedef struct CountCtx CountCtx;
struct CountCtx {
if( (argc==0 || SQLITE_NULL!=sqlite3_value_type(argv[0]) ) && p ){
p->n++;
}
+ if( argc>0 ){
+ int v = sqlite3_value_int(argv[0]);
+ if( v==40 ){
+ sqlite3_result_error(context, "value of 40 handed to x_count", -1);
+ }else if( v==41 ){
+ const char zUtf16ErrMsg[] = { 0, 0x61, 0, 0x62, 0, 0x63, 0, 0, 0};
+ sqlite3_result_error16(context, &zUtf16ErrMsg[1-SQLITE_BIGENDIAN], -1);
+ }
+ }
}
static void countFinalize(sqlite3_context *context){
CountCtx *p;
p = sqlite3_aggregate_context(context, sizeof(*p));
- sqlite3_result_int(context, p ? p->n : 0);
+ if( p ){
+ if( p->n==42 ){
+ sqlite3_result_error(context, "x_count totals to 42", -1);
+ }else{
+ sqlite3_result_int(context, p ? p->n : 0);
+ }
+ }
}
/*
**
** The original motivation for this routine was to be able to call the
** sqlite3_create_aggregate function while a query is in progress in order
-** to test the SQLITE_MISUSE detection logic.
+** to test the SQLITE_MISUSE detection logic. See misuse.test.
+**
+** This routine was later extended to test the use of sqlite3_result_error()
+** within aggregate functions.
*/
static int test_create_aggregate(
void *NotUsed,
** in this file for details. If in doubt, do not deviate from existing
** commenting and indentation practices when changing or adding code.
**
-** $Id: vdbe.c,v 1.533 2006/01/18 18:22:43 danielk1977 Exp $
+** $Id: vdbe.c,v 1.534 2006/01/20 15:45:36 drh Exp $
*/
#include "sqliteInt.h"
#include "os.h"
pOp->p3type = P3_VDBEFUNC;
}
+ /* If the function returned an error, throw an exception */
+ if( ctx.isError ){
+ sqlite3SetString(&p->zErrMsg, sqlite3_value_text(&ctx.s), (char*)0);
+ rc = SQLITE_ERROR;
+ }
+
/* Copy the result of the function to the top of the stack */
sqlite3VdbeChangeEncoding(&ctx.s, encoding);
pTos++;
pTos->flags = 0;
sqlite3VdbeMemMove(pTos, &ctx.s);
-
- /* If the function returned an error, throw an exception */
- if( ctx.isError ){
- if( !(pTos->flags&MEM_Str) ){
- sqlite3SetString(&p->zErrMsg, "user function error", (char*)0);
- }else{
- sqlite3SetString(&p->zErrMsg, sqlite3_value_text(pTos), (char*)0);
- sqlite3VdbeChangeEncoding(pTos, encoding);
- }
- rc = SQLITE_ERROR;
- }
break;
}
assert( pOp->p1>=0 && pOp->p1<p->nMem );
ctx.pMem = pMem = &p->aMem[pOp->p1];
pMem->n++;
+ ctx.s.flags = MEM_Null;
+ ctx.s.z = 0;
+ ctx.s.xDel = 0;
ctx.isError = 0;
ctx.pColl = 0;
if( ctx.pFunc->needCollSeq ){
(ctx.pFunc->xStep)(&ctx, n, apVal);
popStack(&pTos, n);
if( ctx.isError ){
+ sqlite3SetString(&p->zErrMsg, sqlite3_value_text(&ctx.s), (char*)0);
rc = SQLITE_ERROR;
}
+ sqlite3VdbeMemRelease(&ctx.s);
break;
}
assert( pOp->p1>=0 && pOp->p1<p->nMem );
pMem = &p->aMem[pOp->p1];
assert( (pMem->flags & ~(MEM_Null|MEM_Agg))==0 );
- sqlite3VdbeMemFinalize(pMem, (FuncDef*)pOp->p3);
+ rc = sqlite3VdbeMemFinalize(pMem, (FuncDef*)pOp->p3);
+ if( rc==SQLITE_ERROR ){
+ sqlite3SetString(&p->zErrMsg, sqlite3_value_text(pMem), (char*)0);
+ }
break;
}
int sqlite3VdbeMemNumerify(Mem*);
int sqlite3VdbeMemFromBtree(BtCursor*,int,int,int,Mem*);
void sqlite3VdbeMemRelease(Mem *p);
-void sqlite3VdbeMemFinalize(Mem*, FuncDef*);
+int sqlite3VdbeMemFinalize(Mem*, FuncDef*);
#ifndef NDEBUG
void sqlite3VdbeMemSanity(Mem*, u8);
int sqlite3VdbeOpcodeNoPush(u8);
** Memory cell pMem contains the context of an aggregate function.
** This routine calls the finalize method for that function. The
** result of the aggregate is stored back into pMem.
+**
+** Return SQLITE_ERROR if the finalizer reports an error. SQLITE_OK
+** otherwise.
*/
-void sqlite3VdbeMemFinalize(Mem *pMem, FuncDef *pFunc){
+int sqlite3VdbeMemFinalize(Mem *pMem, FuncDef *pFunc){
+ int rc = SQLITE_OK;
if( pFunc && pFunc->xFinalize ){
sqlite3_context ctx;
assert( (pMem->flags & MEM_Null)!=0 || pFunc==*(FuncDef**)&pMem->i );
ctx.s.z = pMem->zShort;
ctx.pMem = pMem;
ctx.pFunc = pFunc;
+ ctx.isError = 0;
pFunc->xFinalize(&ctx);
if( pMem->z && pMem->z!=pMem->zShort ){
sqliteFree( pMem->z );
if( pMem->flags & MEM_Short ){
pMem->z = pMem->zShort;
}
+ if( ctx.isError ){
+ rc = SQLITE_ERROR;
+ }
}
+ return rc;
}
/*
--- /dev/null
+# 2006 January 20
+#
+# 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.
+#
+# This file implements tests for calling sqlite3_result_error()
+# from within an aggregate function implementation.
+#
+# $Id: aggerror.test,v 1.1 2006/01/20 15:45:37 drh Exp $
+
+set testdir [file dirname $argv0]
+source $testdir/tester.tcl
+
+
+# Add the x_count aggregate function to the database handle.
+# x_count will error out if its input is 40 or 41 or if its
+# final results is 42. Make sure that such errors are handled
+# appropriately.
+#
+do_test aggfunc-1.1 {
+ set DB [sqlite3_connection_pointer db]
+ sqlite3_create_aggregate $DB
+ execsql {
+ CREATE TABLE t1(a);
+ INSERT INTO t1 VALUES(1);
+ INSERT INTO t1 VALUES(2);
+ INSERT INTO t1 SELECT a+2 FROM t1;
+ INSERT INTO t1 SELECT a+4 FROM t1;
+ INSERT INTO t1 SELECT a+8 FROM t1;
+ INSERT INTO t1 SELECT a+16 FROM t1;
+ INSERT INTO t1 SELECT a+32 FROM t1 ORDER BY a LIMIT 7;
+ SELECT x_count(*) FROM t1;
+ }
+} {39}
+do_test aggfunc-1.2 {
+ execsql {
+ INSERT INTO t1 VALUES(40);
+ SELECT x_count(*) FROM t1;
+ }
+} {40}
+do_test aggfunc-1.3 {
+ catchsql {
+ SELECT x_count(a) FROM t1;
+ }
+} {1 {value of 40 handed to x_count}}
+do_test aggfunc-1.4 {
+ execsql {
+ UPDATE t1 SET a=41 WHERE a=40
+ }
+ catchsql {
+ SELECT x_count(a) FROM t1;
+ }
+} {1 abc}
+do_test aggfunc-1.5 {
+ execsql {
+ SELECT x_count(*) FROM t1
+ }
+} 40
+do_test aggfunc-1.6 {
+ execsql {
+ INSERT INTO t1 VALUES(40);
+ INSERT INTO t1 VALUES(42);
+ }
+ catchsql {
+ SELECT x_count(*) FROM t1;
+ }
+} {1 {x_count totals to 42}}
+
+finish_test
# This file implements regression tests for SQLite library. The
# focus of this file is testing built-in functions.
#
-# $Id: func.test,v 1.43 2006/01/03 00:33:50 drh Exp $
+# $Id: func.test,v 1.44 2006/01/20 15:45:37 drh Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
catchsql {
select test_error(NULL);
}
-} {1 {user function error}}
+} {1 {}}
# Test the quote function for BLOB and NULL values.
do_test func-16.1 {