Index: src/func.c ================================================================== --- src/func.c +++ src/func.c @@ -1120,21 +1120,21 @@ sqlite3_context *context, int argc, sqlite3_value **argv ){ i64 n; + int rc; sqlite3 *db = sqlite3_context_db_handle(context); assert( argc==1 ); UNUSED_PARAMETER(argc); n = sqlite3_value_int64(argv[0]); testcase( n==db->aLimit[SQLITE_LIMIT_LENGTH] ); testcase( n==db->aLimit[SQLITE_LIMIT_LENGTH]+1 ); - if( n>db->aLimit[SQLITE_LIMIT_LENGTH] ){ - sqlite3_result_error_toobig(context); - }else{ - if( n<0 ) n = 0; - sqlite3_result_zeroblob(context, (int)n); /* IMP: R-00293-64994 */ + if( n<0 ) n = 0; + rc = sqlite3_result_zeroblob64(context, n); /* IMP: R-00293-64994 */ + if( rc ){ + sqlite3_result_error_code(context, rc); } } /* ** The replace() function. Three arguments are all strings: call Index: src/sqlite.h.in ================================================================== --- src/sqlite.h.in +++ src/sqlite.h.in @@ -4532,12 +4532,12 @@ ** ^The sqlite3_result_blob() interface sets the result from ** an application-defined function to be the BLOB whose content is pointed ** to by the second parameter and which is N bytes long where N is the ** third parameter. ** -** ^The sqlite3_result_zeroblob() interfaces set the result of -** the application-defined function to be a BLOB containing all zero +** ^The sqlite3_result_zeroblob() and zeroblob64() interfaces set the result +** of the application-defined function to be a BLOB containing all zero ** bytes and N bytes in size, where N is the value of the 2nd parameter. ** ** ^The sqlite3_result_double() interface sets the result from ** an application-defined function to be a floating point value specified ** by its 2nd argument. @@ -4649,10 +4649,11 @@ void sqlite3_result_text16(sqlite3_context*, const void*, int, void(*)(void*)); void sqlite3_result_text16le(sqlite3_context*, const void*, int,void(*)(void*)); void sqlite3_result_text16be(sqlite3_context*, const void*, int,void(*)(void*)); void sqlite3_result_value(sqlite3_context*, sqlite3_value*); void sqlite3_result_zeroblob(sqlite3_context*, int n); +int sqlite3_result_zeroblob64(sqlite3_context*, sqlite3_uint64 n); /* ** CAPI3REF: Define New Collating Sequences ** METHOD: sqlite3 ** Index: src/sqlite3ext.h ================================================================== --- src/sqlite3ext.h +++ src/sqlite3ext.h @@ -268,10 +268,11 @@ void(*)(void*), unsigned char); int (*strglob)(const char*,const char*); /* Version 3.8.11 and later */ sqlite3_value *(*value_dup)(const sqlite3_value*); void (*value_free)(sqlite3_value*); + int (*result_zeroblob64)(sqlite3_context*,sqlite3_uint64); }; /* ** The following macros redefine the API routines so that they are ** redirected through the global sqlite3_api structure. @@ -501,10 +502,11 @@ #define sqlite3_result_text64 sqlite3_api->result_text64 #define sqlite3_strglob sqlite3_api->strglob /* Version 3.8.11 and later */ #define sqlite3_value_dup sqlite3_api->value_dup #define sqlite3_value_free sqlite3_api->value_free +#define sqlite3_result_zeroblob64 sqlite3_api->result_zeroblob64 #endif /* SQLITE_CORE */ #ifndef SQLITE_CORE /* This case when the file really is being compiled as a loadable ** extension */ Index: src/vdbeapi.c ================================================================== --- src/vdbeapi.c +++ src/vdbeapi.c @@ -160,11 +160,14 @@ ** structure. */ const void *sqlite3_value_blob(sqlite3_value *pVal){ Mem *p = (Mem*)pVal; if( p->flags & (MEM_Blob|MEM_Str) ){ - if( sqlite3VdbeMemExpandBlob(p)!=SQLITE_OK ) return 0; + if( sqlite3VdbeMemExpandBlob(p)!=SQLITE_OK ){ + assert( p->flags==MEM_Null && p->z==0 ); + return 0; + } p->flags |= MEM_Blob; return p->n ? p->z : 0; }else{ return sqlite3_value_text(pVal); } @@ -421,10 +424,19 @@ sqlite3VdbeMemCopy(pCtx->pOut, pValue); } void sqlite3_result_zeroblob(sqlite3_context *pCtx, int n){ assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); sqlite3VdbeMemSetZeroBlob(pCtx->pOut, n); +} +int sqlite3_result_zeroblob64(sqlite3_context *pCtx, u64 n){ + Mem *pOut = pCtx->pOut; + assert( sqlite3_mutex_held(pOut->db->mutex) ); + if( n>pOut->db->aLimit[SQLITE_LIMIT_LENGTH] ){ + return SQLITE_TOOBIG; + } + sqlite3VdbeMemSetZeroBlob(pCtx->pOut, (int)n); + return SQLITE_OK; } void sqlite3_result_error_code(sqlite3_context *pCtx, int errCode){ pCtx->isError = errCode; pCtx->fErrorOrAux = 1; #ifdef SQLITE_DEBUG Index: test/zeroblob.test ================================================================== --- test/zeroblob.test +++ test/zeroblob.test @@ -15,10 +15,11 @@ # # $Id: zeroblob.test,v 1.14 2009/07/14 02:33:02 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl +set testprefix zeroblob ifcapable !incrblob { finish_test return } @@ -265,8 +266,27 @@ CREATE TABLE t10(a,b,c); } catchsql {INSERT INTO t10 VALUES(zeroblob(1e9),zeroblob(1e9),zeroblob(1e9))} } {1 {string or blob too big}} +#------------------------------------------------------------------------- +## Test the zeroblob() function on its own with negative or oversized +## arguments. +## +do_execsql_test 11.0 { + SELECT length(zeroblob(-1444444444444444)); +} {0} +do_catchsql_test 11.1 { + SELECT zeroblob(1025 * 1024 * 1024); +} {1 {string or blob too big}} +do_catchsql_test 11.2 { + SELECT quote(zeroblob(1025 * 1024 * 1024)); +} {1 {string or blob too big}} +do_catchsql_test 11.3 { + SELECT quote(zeroblob(-1444444444444444)); +} {0 X''} +do_catchsql_test 11.4 { + SELECT quote(test_zeroblob(-1)); +} {0 X''} test_restore_config_pagecache finish_test