From 7e18c259fed73572745907c1b9c63fe098ee0515 Mon Sep 17 00:00:00 2001 From: danielk1977 Date: Tue, 25 May 2004 11:47:24 +0000 Subject: [PATCH] Use the new API for returning values and errors from user functions. (CVS 1453) FossilOrigin-Name: 4eccae03b4a7f37804fea30416579787c3584bb2 --- manifest | 28 ++--- manifest.uuid | 2 +- src/date.c | 12 +- src/func.c | 85 +++++++------ src/md5.c | 2 +- src/sqlite.h.in | 124 +++++++++++++----- src/tclsqlite.c | 6 +- src/test1.c | 20 +-- src/vdbe.c | 117 +++++++++++++++-- src/vdbeInt.h | 42 ++++++- src/vdbeaux.c | 328 +++++++++++++++++++++++++++++++++--------------- 11 files changed, 549 insertions(+), 217 deletions(-) diff --git a/manifest b/manifest index b063368968..c898089ade 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\smanifest\stype\saware\sversions\sof\sthe\smin()\sand\smax()\saggregates.\s(CVS\s1452) -D 2004-05-25T01:13:21 +C Use\sthe\snew\sAPI\sfor\sreturning\svalues\sand\serrors\sfrom\suser\sfunctions.\s(CVS\s1453) +D 2004-05-25T11:47:25 F Makefile.in ab7b0d5118e2da97bac66be8684a1034e3500f5a F Makefile.linux-gcc b86a99c493a5bfb402d1d9178dcdc4bd4b32f906 F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd @@ -28,16 +28,16 @@ F src/btree.c 51dfa34da5f42762b228d7360cf3273ee403bce8 F src/btree.h b65140b5ae891f30d2a39e64b9f0343225553545 F src/build.c 35cbeb439b49cca5eb5e8a1de010a5194f4523e8 F src/copy.c 4d2038602fd0549d80c59bda27d96f13ea9b5e29 -F src/date.c 64fd7169c7d599ec8eaa99121d59e27ddf3d783d +F src/date.c b754dc0e1a84b408de0ccc727c792d46ccb66a69 F src/delete.c 2e1dda38345416a1ea1c0a6468589a7472334dac F src/encode.c a876af473d1d636faa3dca51c7571f2e007eea37 F src/expr.c 5b283e68bd6df365b7c2ad10bd04cc54c2b4b07c -F src/func.c 7eb4356a9e3155d6783d84fc5d6b324031877572 +F src/func.c c811d2b77f1f1d88db759cbd60b382463f5a3ae3 F src/hash.c 440c2f8cb373ee1b4e13a0988489c7cd95d55b6f F src/hash.h 762d95f1e567664d1eafc1687de755626be962fb F src/insert.c e510d62d23b4de4d901e7ccbbe7833b7fb3b9570 F src/main.c 8279e1160810410bb9ad6608f87b0140db5b1ce0 -F src/md5.c 84c69162ad4c9b8399b522a259c09e256edaf88a +F src/md5.c 8344ab774bed1bcf2f2fd4e130cc48536f37c414 F src/os.h ab42f4a7c4c716f26b988e759b6e12085a3bfc67 F src/os_common.h 744286a27de55c52f1b18921e8d17abbf7fafc0f F src/os_mac.c b823874690615ace0dd520d3ad1fe8bfd864b7e0 @@ -54,11 +54,11 @@ F src/printf.c ef750e8e2398ca7e8b58be991075f08c6a7f0e53 F src/random.c eff68e3f257e05e81eae6c4d50a51eb88beb4ff3 F src/select.c 7d77a8bed7eeac23216d42fc1be006fb4352fcdc F src/shell.c ed4d237b3e52a0a42512bfcc53530e46de20c28f -F src/sqlite.h.in 3dfba192557c211779fdd48fd25b437b339eabcd +F src/sqlite.h.in 5c9a7d2a4c438da8389382a4ecf145cad73a9238 F src/sqliteInt.h 3ba18f1bbe85c69db1b4882ba899681b0bbac2ae F src/table.c af14284fa36c8d41f6829e3f2819dce07d3e2de2 -F src/tclsqlite.c c8b511645f98051f41b5e0d6c3a99feeed9aeeec -F src/test1.c 045cdd926a8157cd24c6112c2743236063f1bf3e +F src/tclsqlite.c 0c0600409dfc297ef026ca9c8dbdf8754e54d0c4 +F src/test1.c ae2886e9c130f0dcd49f78bd78ffa37c2cb2e7d0 F src/test2.c 6195a1ca2c8d0d2d93644e86da3289b403486872 F src/test3.c 5e4a6d596f982f6f47a5f9f75ede9b4a3b739968 F src/test4.c b9947c319a5c023c10c1e953e6610abd571c2283 @@ -69,10 +69,10 @@ F src/update.c 1a5e9182596f3ea8c7a141e308a3d2a7e5689fee F src/utf.c 1d38da85bffb928fb0d9f301e7db913a6df486ce F src/util.c 4c0adcbc9ce6678dd046931253e45d623c6d279f F src/vacuum.c 8734f89742f246abd91dbd3e087fc153bddbfbad -F src/vdbe.c 11bb4758ae692888ee2a2566be9e0119b489dff3 +F src/vdbe.c bf205ee831161cffc924c71307e24eb61b237230 F src/vdbe.h 391d5642a83af686f35c228fcd36cb4456d68f44 -F src/vdbeInt.h 4dfeaaf7ca34859553d62f391bfb6b6fe4be425e -F src/vdbeaux.c 588e7df730b5d3f6cbe1f44203c91b7be0042ce5 +F src/vdbeInt.h a9a105b9232d7305b41ab36eadd0355079ff01c3 +F src/vdbeaux.c dc4fdfce9cad48d47328d7733df2ee975da6c0a0 F src/where.c efe5d25fe18cd7381722457898cd863e84097a0c F test/all.test 569a92a8ee88f5300c057cc4a8f50fbbc69a3242 F test/attach.test cb9b884344e6cfa5e165965d5b1adea679a24c83 @@ -202,7 +202,7 @@ F www/sqlite.tcl 3c83b08cf9f18aa2d69453ff441a36c40e431604 F www/tclsqlite.tcl b9271d44dcf147a93c98f8ecf28c927307abd6da F www/vdbe.tcl 9b9095d4495f37697fd1935d10e14c6015e80aa1 F www/whentouse.tcl a8335bce47cc2fddb07f19052cb0cb4d9129a8e4 -P 5c28ed5e9b5a3ecb3081ce0c5c9450d6ae8dc77d -R 8308cdc960f78d11f007d3b61876bd79 +P b77c268ebebd5401c3f519a72cfb81438207368c +R 4e71bf50ae3412040cd39e61cbbbc2a7 U danielk1977 -Z 39c12ff09c771deaa84ed1f3b56e6995 +Z c2a413dbfbef432d165e1d1b259db6f9 diff --git a/manifest.uuid b/manifest.uuid index 6cd8c84786..5a8f300f1c 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -b77c268ebebd5401c3f519a72cfb81438207368c \ No newline at end of file +4eccae03b4a7f37804fea30416579787c3584bb2 \ No newline at end of file diff --git a/src/date.c b/src/date.c index 21589bd107..27a05876bf 100644 --- a/src/date.c +++ b/src/date.c @@ -16,7 +16,7 @@ ** sqlite3RegisterDateTimeFunctions() found at the bottom of the file. ** All other code has file scope. ** -** $Id: date.c,v 1.21 2004/05/24 12:39:02 danielk1977 Exp $ +** $Id: date.c,v 1.22 2004/05/25 11:47:25 danielk1977 Exp $ ** ** NOTES: ** @@ -668,7 +668,7 @@ static void juliandayFunc(sqlite_func *context, int argc, sqlite3_value **argv){ DateTime x; if( isDate(argc, argv, &x)==0 ){ computeJD(&x); - sqlite3_set_result_double(context, x.rJD); + sqlite3_result_double(context, x.rJD); } } @@ -684,7 +684,7 @@ static void datetimeFunc(sqlite_func *context, int argc, sqlite3_value **argv){ computeYMD_HMS(&x); sprintf(zBuf, "%04d-%02d-%02d %02d:%02d:%02d",x.Y, x.M, x.D, x.h, x.m, (int)(x.s)); - sqlite3_set_result_string(context, zBuf, -1); + sqlite3_result_text(context, zBuf, -1, 1); } } @@ -699,7 +699,7 @@ static void timeFunc(sqlite_func *context, int argc, sqlite3_value **argv){ char zBuf[100]; computeHMS(&x); sprintf(zBuf, "%02d:%02d:%02d", x.h, x.m, (int)x.s); - sqlite3_set_result_string(context, zBuf, -1); + sqlite3_result_text(context, zBuf, -1, 1); } } @@ -714,7 +714,7 @@ static void dateFunc(sqlite_func *context, int argc, sqlite3_value **argv){ char zBuf[100]; computeYMD(&x); sprintf(zBuf, "%04d-%02d-%02d", x.Y, x.M, x.D); - sqlite3_set_result_string(context, zBuf, -1); + sqlite3_result_text(context, zBuf, -1, 1); } } @@ -834,7 +834,7 @@ static void strftimeFunc(sqlite_func *context, int argc, sqlite3_value **argv){ } } z[j] = 0; - sqlite3_set_result_string(context, z, -1); + sqlite3_result_text(context, z, -1, 1); if( z!=zBuf ){ sqliteFree(z); } diff --git a/src/func.c b/src/func.c index 23386b467f..cf230489ea 100644 --- a/src/func.c +++ b/src/func.c @@ -16,7 +16,7 @@ ** sqliteRegisterBuildinFunctions() found at the bottom of the file. ** All other code has file scope. ** -** $Id: func.c,v 1.53 2004/05/25 01:13:21 danielk1977 Exp $ +** $Id: func.c,v 1.54 2004/05/25 11:47:25 danielk1977 Exp $ */ #include #include @@ -53,7 +53,7 @@ static void minmaxFunc(sqlite_func *context, int argc, sqlite3_value **argv){ zBest = zArg; } } - sqlite3_set_result_string(context, zBest, -1); + sqlite3_result_text(context, zBest, -1, 1); } /* @@ -69,7 +69,7 @@ static void typeofFunc(sqlite_func *context, int argc, sqlite3_value **argv){ case SQLITE3_FLOAT: z = "real" ; break; case SQLITE3_BLOB: z = "blob" ; break; } - sqlite3_set_result_string(context, z, -1); + sqlite3_result_text(context, z, -1, 0); } /* @@ -87,7 +87,7 @@ static void lengthFunc(sqlite_func *context, int argc, sqlite3_value **argv){ #else len = strlen(z); #endif - sqlite3_set_result_int(context, len); + sqlite3_result_int32(context, len); } /* @@ -99,7 +99,7 @@ static void absFunc(sqlite_func *context, int argc, sqlite3_value **argv){ z = sqlite3_value_data(argv[0]); if( z==0 ) return; if( z[0]=='-' && isdigit(z[1]) ) z++; - sqlite3_set_result_string(context, z, -1); + sqlite3_result_text(context, z, -1, 1); } /* @@ -145,7 +145,7 @@ static void substrFunc(sqlite_func *context, int argc, sqlite3_value **argv){ while( z[i] && (z[i]&0xc0)==0x80 ){ i++; p2++; } #endif if( p2<0 ) p2 = 0; - sqlite3_set_result_string(context, &z[p1], p2); + sqlite3_result_text(context, &z[p1], p2, 1); } /* @@ -165,7 +165,7 @@ static void roundFunc(sqlite_func *context, int argc, sqlite3_value **argv){ if( SQLITE3_NULL==sqlite3_value_type(argv[0]) ) return; r = sqlite3_value_float(argv[0]); sprintf(zBuf,"%.*f",n,r); - sqlite3_set_result_string(context, zBuf, -1); + sqlite3_result_text(context, zBuf, -1, 1); } /* @@ -174,22 +174,28 @@ static void roundFunc(sqlite_func *context, int argc, sqlite3_value **argv){ static void upperFunc(sqlite_func *context, int argc, sqlite3_value **argv){ char *z; int i; - if( argc<1 ) return; - z = sqlite3_set_result_string(context, sqlite3_value_data(argv[0]), -1); + if( argc<1 || SQLITE3_NULL==sqlite3_value_type(argv[0]) ) return; + z = sqliteMalloc(sqlite3_value_bytes(argv[0])); if( z==0 ) return; + strcpy(z, sqlite3_value_data(argv[0])); for(i=0; z[i]; i++){ if( islower(z[i]) ) z[i] = toupper(z[i]); } + sqlite3_result_text(context, z, -1, 1); + sqliteFree(z); } static void lowerFunc(sqlite_func *context, int argc, sqlite3_value **argv){ char *z; int i; - if( argc<1 ) return; - z = sqlite3_set_result_string(context, sqlite3_value_data(argv[0]), -1); + if( argc<1 || SQLITE3_NULL==sqlite3_value_type(argv[0]) ) return; + z = sqliteMalloc(sqlite3_value_bytes(argv[0])); if( z==0 ) return; + strcpy(z, sqlite3_value_data(argv[0])); for(i=0; z[i]; i++){ if( isupper(z[i]) ) z[i] = tolower(z[i]); } + sqlite3_result_text(context, z, -1, 1); + sqliteFree(z); } /* @@ -201,7 +207,7 @@ static void ifnullFunc(sqlite_func *context, int argc, sqlite3_value **argv){ int i; for(i=0; isum : 0.0); + sqlite3_result_double(context, p ? p->sum : 0.0); } static void avgFinalize(sqlite_func *context){ SumCtx *p; p = sqlite3_aggregate_context(context, sizeof(*p)); if( p && p->cnt>0 ){ - sqlite3_set_result_double(context, p->sum/(double)p->cnt); + sqlite3_result_double(context, p->sum/(double)p->cnt); } } @@ -527,7 +533,7 @@ static void countStep(sqlite_func *context, int argc, sqlite3_value **argv){ static void countFinalize(sqlite_func *context){ CountCtx *p; p = sqlite3_aggregate_context(context, sizeof(*p)); - sqlite3_set_result_int(context, p ? p->n : 0); + sqlite3_result_int32(context, p ? p->n : 0); } /* @@ -552,13 +558,21 @@ static void minmaxStep(sqlite_func *context, int argc, sqlite3_value **argv){ if( SQLITE3_NULL==sqlite3_value_type(argv[0]) ) return; if( pBest->flags ){ + /* This step function is used for both the min() and max() aggregates, + ** the only difference between the two being that the sense of the + ** comparison is inverted. For the max() aggregate, the + ** sqlite3_user_data() function returns (void *)-1. For min() it + ** returns (void *)db, where db is the sqlite3* database pointer. + ** Therefore the next statement sets variable 'max' to 1 for the max() + ** aggregate, or 0 for min(). + */ max = ((sqlite3_user_data(context)==(void *)-1)?1:0); cmp = sqlite3MemCompare(pBest, pArg, 0); if( (max && cmp<0) || (!max && cmp>0) ){ - sqlite3MemCopy(pBest, pArg); + sqlite3VdbeMemCopy(pBest, pArg); } }else{ - sqlite3MemCopy(pBest, pArg); + sqlite3VdbeMemCopy(pBest, pArg); } } static void minMaxFinalize(sqlite_func *context){ @@ -568,15 +582,14 @@ static void minMaxFinalize(sqlite_func *context){ if( pRes->flags ){ switch( sqlite3_value_type(pRes) ){ case SQLITE3_INTEGER: - sqlite3_set_result_int(context, sqlite3_value_int(pRes)); + sqlite3_result_int32(context, sqlite3_value_int(pRes)); break; case SQLITE3_FLOAT: - sqlite3_set_result_double(context, sqlite3_value_float(pRes)); + sqlite3_result_double(context, sqlite3_value_float(pRes)); case SQLITE3_TEXT: case SQLITE3_BLOB: - sqlite3_set_result_string(context, - sqlite3_value_data(pRes), - sqlite3_value_bytes(pRes)); + sqlite3_result_text(context, + sqlite3_value_data(pRes), sqlite3_value_bytes(pRes), 1); break; case SQLITE3_NULL: default: diff --git a/src/md5.c b/src/md5.c index 0d0f3f4794..77f3d49945 100644 --- a/src/md5.c +++ b/src/md5.c @@ -379,7 +379,7 @@ static void md5finalize(sqlite_func *context){ p = sqlite3_aggregate_context(context, sizeof(*p)); MD5Final(digest,p); DigestToBase16(digest, zBuf); - sqlite3_set_result_string(context, zBuf, strlen(zBuf)); + sqlite3_result_text(context, zBuf, -1, 1); } void Md5_Register(sqlite *db){ sqlite3_create_aggregate(db, "md5sum", -1, md5step, md5finalize, 0); diff --git a/src/sqlite.h.in b/src/sqlite.h.in index ab696c6804..1df7ef43b9 100644 --- a/src/sqlite.h.in +++ b/src/sqlite.h.in @@ -12,7 +12,7 @@ ** This header file defines the interface that the SQLite library ** presents to client programs. ** -** @(#) $Id: sqlite.h.in,v 1.74 2004/05/24 23:48:27 danielk1977 Exp $ +** @(#) $Id: sqlite.h.in,v 1.75 2004/05/25 11:47:26 danielk1977 Exp $ */ #ifndef _SQLITE_H_ #define _SQLITE_H_ @@ -464,36 +464,6 @@ int sqlite3_function_type( #define SQLITE_TEXT (-2) #define SQLITE_ARGS (-3) -/* -** 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 xFinialize(). -** The second parameter to these routines is the result to be returned. -** A NULL can be passed as the second parameter to sqlite3_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. -** -** The sqlite3_set_result_string() function allocates a buffer to hold the -** result and returns a pointer to this buffer. The calling routine -** (that is, the implmentation of a user function) can alter the content -** of this buffer if desired. -*/ -char *sqlite3_set_result_string(sqlite_func*,const char*,int); -void sqlite3_set_result_int(sqlite_func*,int); -void sqlite3_set_result_double(sqlite_func*,double); -void sqlite3_set_result_error(sqlite_func*,const char*,int); - -/* -** The pUserData parameter to the sqlite3_create_function() and -** sqlite3_create_aggregate() routines used to register user functions -** is available to the implementation of the function using this -** call. -*/ -void *sqlite3_user_data(sqlite_func*); - /* ** Aggregate functions use the following routine to allocate ** a structure for storing their state. The first time this routine @@ -1412,6 +1382,98 @@ long long int sqlite3_value_int(sqlite3_value*); */ double sqlite3_value_float(sqlite3_value*); +typedef sqlite_func sqlite3_context; + +void *sqlite3_get_context(sqlite3_context*, int nbyte); + +/* +** The pUserData parameter to the sqlite3_create_function() and +** sqlite3_create_aggregate() routines used to register user functions +** is available to the implementation of the function using this +** call. +*/ +void *sqlite3_user_data(sqlite3_context*); + +/* +** The following three functions may be called from within a user-defined +** function callback or a user-defined aggregate finalizer callback. The +** result of the user-defined function or aggregate is set to the value of +** the second parameter. Any value previously set as the return value via +** an sqlite3_result_*() call is overwritten. +** +** The first parameter to each of these routines must be a copy of the +** sqlite3_context* pointer passed to the user-defined function or +** aggregate finalizer function. +*/ +void sqlite3_result_int32(sqlite3_context*, int); +void sqlite3_result_int64(sqlite3_context*, long long int); +void sqlite3_result_double(sqlite3_context*, double); + +/* +** This function may be called from within a user-defined function callback +** or a user-defined aggregate finalizer callback. The result of the +** user-defined function or aggregate is set to NULL. Any value previously +** set as the return value via an sqlite3_result_*() call is overwritten. +** +** The parameter to this routine must be a copy of the sqlite3_context* +** pointer passed to the user-defined function or aggregate finalizer +** function. +*/ +void sqlite3_result_null(sqlite3_context*); + +/* +** The following two functions may be called from within a user-defined or +** a user-defined aggregate finalizer callback to return a text value. +** The second parameter is a pointer to the string, encoded in UTF-8 +** for sqlite3_result_text() and UTF-16 (machine byte order) for +** sqlite3_result_text16(). +** +** If the third parameter, n, is positive, it is the number of bytes (not +** characters) in the string data. A negative n value indicates that the +** string may be read up to the nul terminator character. +** +** If the fourth parameter is non-zero, then a copy is made of the string. +** Otherwise, SQLite stores a pointer to the original string data. +** +** The first parameter to this routine must be a copy of the +** sqlite3_context* pointer passed to the user-defined function or +** aggregate finalizer function. +*/ +void sqlite3_result_text(sqlite3_context*, const char*, int n, int eCopy); +void sqlite3_result_text16(sqlite3_context*, const void*, int n, int eCopy); + +/* +** The following function may be called from within a user-defined or a +** user-defined aggregate finalizer callback to return a blob value. The +** second parameter is a pointer to the blob of data. The third parameter +** is the number of bytes of data in the blob. +** +** If the fourth parameter is non-zero, then a copy is made of the blob. +** Otherwise, SQLite stores a pointer to the original blob data. +** +** The first parameter to this routine must be a copy of the +** sqlite3_context* pointer passed to the user-defined function or +** aggregate finalizer function. +*/ +void sqlite3_result_blob(sqlite3_context*, const void*, int n, int eCopy); + +/* +** These routines are used from within a user-defined or a user-defined +** aggregate finalizer callback to return an error. The second parameter +** is a pointer to a string describing the error, or NULL if no explanation +** is provided. +** +** The string should be encoded in UTF-8 for sqlite3_result_error() and +** UTF-16 (machine byte order) for sqlite3_result_error16(). +** +** If not negative, the third parameter is the number of bytes (not +** characters) in the string passed as the second argument. If the third +** parameter is negative, then the string is read up to the first nul +** terminator character. +*/ +void sqlite3_result_error(sqlite3_context*, const char*, int); +void sqlite3_result_error16(sqlite3_context*, const void*, int); + #ifdef __cplusplus } /* End of the 'extern "C"' block */ #endif diff --git a/src/tclsqlite.c b/src/tclsqlite.c index cf60288cff..a2b4983bdd 100644 --- a/src/tclsqlite.c +++ b/src/tclsqlite.c @@ -11,7 +11,7 @@ ************************************************************************* ** A TCL Interface to SQLite ** -** $Id: tclsqlite.c,v 1.67 2004/05/24 12:39:02 danielk1977 Exp $ +** $Id: tclsqlite.c,v 1.68 2004/05/25 11:47:26 danielk1977 Exp $ */ #ifndef NO_TCL /* Omit this whole file if TCL is unavailable */ @@ -396,9 +396,9 @@ static void tclSqlFunc(sqlite_func *context, int argc, sqlite3_value **argv){ } rc = Tcl_Eval(p->interp, Tcl_DStringValue(&cmd)); if( rc ){ - sqlite3_set_result_error(context, Tcl_GetStringResult(p->interp), -1); + sqlite3_result_error(context, Tcl_GetStringResult(p->interp), -1); }else{ - sqlite3_set_result_string(context, Tcl_GetStringResult(p->interp), -1); + sqlite3_result_text(context, Tcl_GetStringResult(p->interp), -1, 1); } } #ifndef SQLITE_OMIT_AUTHORIZATION diff --git a/src/test1.c b/src/test1.c index 57016e320b..1691187138 100644 --- a/src/test1.c +++ b/src/test1.c @@ -13,7 +13,7 @@ ** is not included in the SQLite library. It is used for automated ** testing of the SQLite library. ** -** $Id: test1.c,v 1.49 2004/05/24 23:48:27 danielk1977 Exp $ +** $Id: test1.c,v 1.50 2004/05/25 11:47:26 danielk1977 Exp $ */ #include "sqliteInt.h" #include "tcl.h" @@ -311,7 +311,7 @@ static void ifnullFunc(sqlite_func *context, int argc, sqlite3_value **argv){ int i; for(i=0; in : 0); + sqlite3_result_int32(context, p ? p->n : 0); } /* @@ -658,19 +658,19 @@ static void testFunc(sqlite_func *context, int argc, sqlite3_value **argv){ const char *zArg0 = sqlite3_value_data(argv[0]); const char *zArg1 = sqlite3_value_data(argv[1]); if( zArg0==0 ){ - sqlite3_set_result_error(context, "first argument to test function " + sqlite3_result_error(context, "first argument to test function " "may not be NULL", -1); }else if( sqlite3StrICmp(zArg0,"string")==0 ){ - sqlite3_set_result_string(context, zArg1, -1); + sqlite3_result_text(context, zArg1, -1, 1); }else if( zArg1==0 ){ - sqlite3_set_result_error(context, "2nd argument may not be NULL if the " + sqlite3_result_error(context, "2nd argument may not be NULL if the " "first argument is not \"string\"", -1); }else if( sqlite3StrICmp(zArg0,"int")==0 ){ - sqlite3_set_result_int(context, atoi(zArg1)); + sqlite3_result_int32(context, atoi(zArg1)); }else if( sqlite3StrICmp(zArg0,"double")==0 ){ - sqlite3_set_result_double(context, sqlite3AtoF(zArg1, 0)); + sqlite3_result_double(context, sqlite3AtoF(zArg1, 0)); }else{ - sqlite3_set_result_error(context,"first argument should be one of: " + sqlite3_result_error(context,"first argument should be one of: " "string int double", -1); } argc -= 2; diff --git a/src/vdbe.c b/src/vdbe.c index 14cb55035a..aa4645bc89 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -43,7 +43,7 @@ ** 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.327 2004/05/24 23:48:27 danielk1977 Exp $ +** $Id: vdbe.c,v 1.328 2004/05/25 11:47:26 danielk1977 Exp $ */ #include "sqliteInt.h" #include "os.h" @@ -69,14 +69,109 @@ int sqlite3_search_count = 0; */ int sqlite3_interrupt_count = 0; +/* +** This macro takes a single parameter, a pointer to a Mem structure. +** It returns the string encoding for the Mem structure, one of TEXT_Utf8 +** TEXT_Utf16le or TEXT_Utf16be. +*/ +#define MemEnc(p) ( \ + p->flags&MEM_Utf16le?TEXT_Utf16le: \ + (p->flags&MEM_Utf16le?TEXT_Utf16be:TEXT_Utf8) ) + +/* +** The following macros each take one parameter, a pointer to a Mem +** structure. The value returned is non-zero if the value stored in +** the Mem structure is of or can be losslessly converted to the +** type implicit in the macro name. +** +** MemIsNull # NULL values +** MemIsInt # Ints and reals and strings that can be converted to ints. +** MemIsReal # Reals, ints and strings that look like numbers +** MemIsStr # Strings, reals and ints. +** MemIsBlob # Blobs. +** +** These macros do not alter the contents of the Mem structure. +*/ +#define MemIsNull(p) ((p)->flags&Mem_Null) +#define MemIsBlob(p) ((p)->flags&Mem_Blob) +#define MemIsStr(p) ((p)->flags&(MEM_Int|MEM_Real|MEM_Str)) +#define MemIsInt(p) ((p)->flags&MEM_Int || hardMemIsInt(p)) +#define MemIsReal(p) ((p)->flags&(MEM_Int|MEM_Real) || hardMemIsReal(p)) +static int hardMemIsInt(Mem *p){ + assert( !(p->flags&(MEM_Int|MEM_Real)) ); + if( p->flags&MEM_Str ){ + int realnum = 0; + if( sqlite3IsNumber(p->z, &realnum, MemEnc(p)) && !realnum ){ + return 1; + } + } + return 0; +} +static int hardMemIsReal(Mem *p){ + assert( !(p->flags&(MEM_Int|MEM_Real)) ); + if( p->flags&MEM_Str && sqlite3IsNumber(p->z, 0, MemEnc(p)) ){ + return 1; + } + return 0; +} + +/* +** The following two macros each take one parameter, a pointer to a Mem +** structure. They return the value stored in the Mem structure coerced +** to a 64-bit integer or real, respectively. +** +** MemInt +** MemReal +** +** These macros do not alter the contents of the Mem structure, although +** they may cache the integer or real value cast of the value. +*/ +#define MemInt(p) (((p)->flags&MEM_Int)?(p)->i:hardMemInt(p)) +#define MemReal(p) (((p)->flags&MEM_Real)?(p)->i:hardMemReal(p)) +static i64 hardMemInt(Mem *p){ + assert( !(p->flags&MEM_Int) ); + if( !MemIsInt(p) ) return 0; + + if( p->flags&MEM_Real ){ + p->i = p->r; + }else{ + assert( p->flags&MEM_Str ); + sqlite3atoi64(p->z, &(p->i), MemEnc(p)); + } + p->flags |= MEM_Int; + return p->i; +} +static double hardMemReal(Mem *p){ + assert( !(p->flags&MEM_Real) ); + if( !MemIsReal(p) ) return 0.0; + + if( p->flags&MEM_Int ){ + p->r = p->i; + }else{ + assert( p->flags&MEM_Str ); + /* p->r = sqlite3AtoF(p->z, 0, MemEnc(p)); */ + p->r = sqlite3AtoF(p->z, 0); + } + p->flags |= MEM_Real; + return p->r; +} + + #if 0 /* -** NulTermify -** Stringify -** Integerify -** Realify -** SetEncoding -** Release +** MemStr(Mem *pMem) +** MemBlob(Mem *pMem) +** MemBloblen(Mem *pMem) +** +** MemType(Mem *pMem) +** +** MemSetBlob +** MemSetStr +** +** MemSetEnc +** MemSetType +** +** MemCopy */ struct MemRecord { char *zData; /* Serialized record */ @@ -2012,6 +2107,7 @@ case OP_Callback: { for(i=0; ip1; i++){ Mem *pVal = &pTos[0-i]; SetEncodingFlags(pVal, db->enc); + MemNulTerminate(pVal); } p->resOnStack = 1; @@ -2274,14 +2370,14 @@ case OP_Function: { (*ctx.pFunc->xFunc)(&ctx, n, apVal); if( sqlite3SafetyOn(db) ) goto abort_due_to_misuse; popStack(&pTos, n); + + /* Copy the result of the function to the top of the stack */ pTos++; *pTos = ctx.s; - if( pTos->flags & MEM_Str ){ - pTos->flags |= MEM_Term; - } if( pTos->flags & MEM_Short ){ pTos->z = pTos->zShort; } + /* If the function returned an error, throw an exception */ if( ctx.isError ){ sqlite3SetString(&p->zErrMsg, (pTos->flags & MEM_Str)!=0 ? pTos->z : "user function error", (char*)0); @@ -2289,7 +2385,6 @@ case OP_Function: { } if( pTos->flags&MEM_Str ){ - SetEncodingFlags(pTos, TEXT_Utf8); SetEncoding(pTos, encToFlags(db->enc)|MEM_Term); } diff --git a/src/vdbeInt.h b/src/vdbeInt.h index 679a6c33d0..0061046877 100644 --- a/src/vdbeInt.h +++ b/src/vdbeInt.h @@ -117,8 +117,15 @@ struct Sorter { #define NBFS 32 /* -** A single level of the stack or a single memory cell -** is an instance of the following structure. +** Internally, the vdbe manipulates nearly all SQL values as Mem +** structures. Each Mem struct may cache multiple representations (string, +** integer etc.) of the same value. A value (and therefore Mem structure) +** has the following properties: +** +** Each value has a manifest type. The manifest type of the value stored +** in a Mem struct is returned by the MemType(Mem*) macro. The type is +** one of SQLITE3_NULL, SQLITE3_INTEGER, SQLITE3_REAL, SQLITE3_TEXT or +** SQLITE3_BLOB. */ struct Mem { i64 i; /* Integer value */ @@ -130,6 +137,33 @@ struct Mem { }; typedef struct Mem Mem; +/* +** The following three macros are used to set the value and manifest type +** stored by a Mem structure. +** +** MemSetNull - Set the value to NULL. +** MemSetInt - Set the value to an integer. +** MemSetReal - Set the value to a real. +** MemSetStr - Set the value to a string. +*/ +#define MemSetNull(p) sqlite3VdbeMemSetNull(p) +#define MemSetInt(p,v) sqlite3VdbeMemSetInt(p,v) +#define MemSetReal(p,v) sqlite3VdbeMemSetReal(p,v) +#define MemSetStr(p,z,n,enc,eCopy) sqlite3VdbeMemSetStr(p,z,n,enc,eCopy) + +/* +** This macro is used to ensure a string stored in a Mem struct is NULL +** terminated. When used on an object that is not a string or is a nul +** terminated string this is a no-op. When used on a non-nul-terminated +** string a nul terminator character is appended. +** +** Non-zero is returned if a malloc() fails. +*/ +#define MemNulTerminate(p) ( \ + ((p)->flags&MEM_Str) && \ + !((p)->flags&MEM_Term) && \ + sqlite3VdbeMemNulTerminate(p) ) + /* ** Allowed values for Mem.flags. ** @@ -147,7 +181,6 @@ typedef struct Mem Mem; #define MEM_Int 0x0004 /* Value is an integer */ #define MEM_Real 0x0008 /* Value is a real number */ #define MEM_Blob 0x0010 /* Value is a BLOB */ -#define MEM_Struct 0x0020 /* Value is some kind of struct */ #define MEM_Term 0x0200 /* String has a nul terminator character */ @@ -361,9 +394,10 @@ int sqlite2BtreeKeyCompare(BtCursor *, const void *, int, int, int *); int sqlite3VdbeIdxKeyCompare(Cursor*, int , const unsigned char*, int*); int sqlite3VdbeIdxRowid(BtCursor *, i64 *); int sqlite3MemCompare(const Mem*, const Mem*, const CollSeq*); -int sqlite3MemCopy(Mem*, const Mem*); int sqlite3VdbeKeyCompare(void*,int,const void*,int, const void*); int sqlite3VdbeRowCompare(void*,int,const void*,int, const void*); int sqlite3VdbeExec(Vdbe*); int sqlite3VdbeList(Vdbe*); int sqlite3VdbeSetEncoding(Mem *, u8); +int sqlite3VdbeMemCopy(Mem*, const Mem*); +int sqlite3VdbeMemNulTerminate(Mem *); diff --git a/src/vdbeaux.c b/src/vdbeaux.c index 8d02b91713..6ff1d6791e 100644 --- a/src/vdbeaux.c +++ b/src/vdbeaux.c @@ -424,83 +424,11 @@ VdbeOp *sqlite3VdbeGetOp(Vdbe *p, int addr){ return &p->aOp[addr]; } -/* -** The following group or routines are employed by installable functions -** to return their results. -** -** The sqlite3_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 an ephemeral string. -** -** sqlite3_set_result_error() works like sqlite3_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 sqlite3_set_result_int() and sqlite3_set_result_double() set the return -** value of the user function to an integer or a double. -** -** These routines are defined here in vdbe.c because they depend on knowing -** the internals of the sqlite_func structure which is only defined in -** this source file. -*/ -char *sqlite3_set_result_string(sqlite_func *p, const char *zResult, int n){ - assert( !p->isStep ); - if( p->s.flags & MEM_Dyn ){ - sqliteFree(p->s.z); - } - if( zResult==0 ){ - p->s.flags = MEM_Null; - n = 0; - p->s.z = 0; - p->s.n = 0; - }else{ - if( n<0 ) n = strlen(zResult); - if( ns.zShort, zResult, n); - p->s.zShort[n] = 0; - p->s.flags = MEM_Utf8 | MEM_Str | MEM_Short; - p->s.z = p->s.zShort; - }else{ - p->s.z = sqliteMallocRaw( n+1 ); - if( p->s.z ){ - memcpy(p->s.z, zResult, n); - p->s.z[n] = 0; - } - p->s.flags = MEM_Utf8 | MEM_Str | MEM_Dyn; - } - p->s.n = n+1; - } - return p->s.z; -} -void sqlite3_set_result_int(sqlite_func *p, int iResult){ - assert( !p->isStep ); - if( p->s.flags & MEM_Dyn ){ - sqliteFree(p->s.z); - } - p->s.i = iResult; - p->s.flags = MEM_Int; -} -void sqlite3_set_result_double(sqlite_func *p, double rResult){ - assert( !p->isStep ); - if( p->s.flags & MEM_Dyn ){ - sqliteFree(p->s.z); - } - p->s.r = rResult; - p->s.flags = MEM_Real; -} -void sqlite3_set_result_error(sqlite_func *p, const char *zMsg, int n){ - assert( !p->isStep ); - sqlite3_set_result_string(p, zMsg, n); - p->isError = 1; -} - /* ** Extract the user data from a sqlite_func structure and return a ** pointer to it. */ -void *sqlite3_user_data(sqlite_func *p){ +void *sqlite3_user_data(sqlite3_context *p){ assert( p && p->pFunc ); return p->pFunc->pUserData; } @@ -1461,33 +1389,6 @@ int sqlite3MemCompare(const Mem *pMem1, const Mem *pMem2, const CollSeq *pColl){ return rc; } -/* -** Copy the contents of memory cell pFrom into pTo. -*/ -int sqlite3MemCopy(Mem *pTo, const Mem *pFrom){ - if( pTo->flags&MEM_Dyn ){ - sqliteFree(pTo->z); - } - - memcpy(pTo, pFrom, sizeof(*pFrom)); - if( pTo->flags&MEM_Short ){ - pTo->z = pTo->zShort; - } - else if( pTo->flags&(MEM_Ephem|MEM_Dyn) ){ - pTo->flags = pTo->flags&(~(MEM_Static|MEM_Ephem|MEM_Short|MEM_Dyn)); - if( pTo->n>NBFS ){ - pTo->z = sqliteMalloc(pTo->n); - if( !pTo->z ) return SQLITE_NOMEM; - pTo->flags |= MEM_Dyn; - }else{ - pTo->z = pTo->zShort; - pTo->flags |= MEM_Short; - } - memcpy(pTo->z, pFrom->z, pTo->n); - } - return SQLITE_OK; -} - /* ** The following is the comparison function for (non-integer) ** keys in the btrees. This function returns negative, zero, or @@ -1753,3 +1654,230 @@ int sqlite3VdbeIdxKeyCompare( } return SQLITE_OK; } + +/* +** Parameter "enc" is one of TEXT_Utf8, TEXT_Utf16le or TEXT_Utf16be. +** Return the corresponding MEM_Utf* value. +*/ +static int encToFlags(u8 enc){ + switch( enc ){ + case TEXT_Utf8: return MEM_Utf8; + case TEXT_Utf16be: return MEM_Utf16be; + case TEXT_Utf16le: return MEM_Utf16le; + } + assert(0); +} +static u8 flagsToEnc(int flags){ + switch( flags&(MEM_Utf8|MEM_Utf16be|MEM_Utf16le) ){ + case MEM_Utf8: return TEXT_Utf8; + case MEM_Utf16le: return TEXT_Utf16le; + case MEM_Utf16be: return TEXT_Utf16be; + } + return 0; +} + +/* +** Delete any previous value and set the value stored in *pMem to NULL. +*/ +void sqlite3VdbeMemSetNull(Mem *pMem){ + if( pMem->flags&MEM_Dyn ){ + sqliteFree(pMem->z); + } + pMem->flags = MEM_Null; +} + +/* +** Delete any previous value and set the value stored in *pMem to val, +** manifest type INTEGER. +*/ +void sqlite3VdbeMemSetInt(Mem *pMem, i64 val){ + MemSetNull(pMem); + pMem->i = val; + pMem->flags = MEM_Int; +} + +/* +** Delete any previous value and set the value stored in *pMem to val, +** manifest type REAL. +*/ +void sqlite3VdbeMemSetReal(Mem *pMem, double val){ + MemSetNull(pMem); + pMem->r = val; + pMem->flags = MEM_Real; +} + +/* +** Copy the contents of memory cell pFrom into pTo. +*/ +int sqlite3VdbeMemCopy(Mem *pTo, const Mem *pFrom){ + if( pTo->flags&MEM_Dyn ){ + sqliteFree(pTo->z); + } + + memcpy(pTo, pFrom, sizeof(*pFrom)); + if( pTo->flags&MEM_Short ){ + pTo->z = pTo->zShort; + } + else if( pTo->flags&(MEM_Ephem|MEM_Dyn) ){ + pTo->flags = pTo->flags&(~(MEM_Static|MEM_Ephem|MEM_Short|MEM_Dyn)); + if( pTo->n>NBFS ){ + pTo->z = sqliteMalloc(pTo->n); + if( !pTo->z ) return SQLITE_NOMEM; + pTo->flags |= MEM_Dyn; + }else{ + pTo->z = pTo->zShort; + pTo->flags |= MEM_Short; + } + memcpy(pTo->z, pFrom->z, pTo->n); + } + return SQLITE_OK; +} + +int sqlite3VdbeMemSetStr( + Mem *pMem, /* Memory cell to set to string value */ + const char *z, /* String pointer */ + int n, /* Bytes in string, or negative */ + u8 enc, /* Encoding of z */ + int eCopy /* True if this function should make a copy of z */ +){ + Mem tmp; + + if( !z ){ + /* If z is NULL, just set *pMem to contain NULL. */ + MemSetNull(pMem); + return SQLITE_OK; + } + + tmp.z = (char *)z; + if( eCopy ){ + tmp.flags = MEM_Ephem|MEM_Str; + }else{ + tmp.flags = MEM_Static|MEM_Str; + } + tmp.flags |= encToFlags(enc); + tmp.n = n; + switch( enc ){ + case 0: + tmp.flags |= MEM_Blob; + break; + + case TEXT_Utf8: + tmp.flags |= MEM_Utf8; + if( n<0 ) tmp.n = strlen(z)+1; + tmp.flags |= ((tmp.z[tmp.n-1])?0:MEM_Term); + break; + + case TEXT_Utf16le: + case TEXT_Utf16be: + tmp.flags |= (enc==TEXT_Utf16le?MEM_Utf16le:MEM_Utf16be); + if( n<0 ) tmp.n = sqlite3utf16ByteLen(z,-1)+1; + tmp.flags |= ((tmp.z[tmp.n-1]||tmp.z[tmp.n-2])?0:MEM_Term); + break; + + default: + assert(0); + } + return sqlite3VdbeMemCopy(pMem, &tmp); +} + +int sqlite3VdbeMemNulTerminate(Mem *pMem){ + int nulTermLen; + int f = pMem->flags; + + assert( pMem->flags&MEM_Str && !pMem->flags&MEM_Term ); + assert( flagsToEnc(pMem->flags) ); + + nulTermLen = (flagsToEnc(f)==TEXT_Utf8?1:2); + + if( pMem->n+nulTermLen<=NBFS ){ + /* If the string plus the nul terminator will fit in the Mem.zShort + ** buffer, and it is not already stored there, copy it there. + */ + if( !(f&MEM_Short) ){ + memcpy(pMem->z, pMem->zShort, pMem->n); + if( f&MEM_Dyn ){ + sqliteFree(pMem->z); + } + pMem->z = pMem->zShort; + pMem->flags &= ~(MEM_Static|MEM_Ephem|MEM_Dyn); + pMem->flags |= MEM_Short; + } + }else{ + /* Otherwise we have to malloc for memory. If the string is already + ** dynamic, use sqliteRealloc(). Otherwise sqliteMalloc() enough + ** space for the string and the nul terminator, and copy the string + ** data there. + */ + if( f&MEM_Dyn ){ + pMem->z = (char *)sqliteRealloc(pMem->z, pMem->n+nulTermLen); + if( !pMem->z ){ + return SQLITE_NOMEM; + } + }else{ + char *z = (char *)sqliteMalloc(pMem->n+nulTermLen); + memcpy(z, pMem->z, pMem->n); + pMem->z = z; + pMem->flags &= ~(MEM_Static|MEM_Ephem|MEM_Short); + pMem->flags |= MEM_Dyn; + } + } + + /* pMem->z now points at the string data, with enough space at the end + ** to insert the nul nul terminator. pMem->n has not yet been updated. + */ + memcpy(&pMem->z[pMem->n], "\0\0", nulTermLen); + pMem->n += nulTermLen; + pMem->flags |= MEM_Term; +} + +/* +** The following nine routines, named sqlite3_result_*(), are used to +** return values or errors from user-defined functions and aggregate +** operations. They are commented in the header file sqlite.h (sqlite.h.in) +*/ +void sqlite3_result_int32(sqlite3_context *pCtx, int iVal){ + MemSetInt(&pCtx->s, iVal); +} +void sqlite3_result_int64(sqlite3_context *pCtx, i64 iVal){ + MemSetInt(&pCtx->s, iVal); +} +void sqlite3_result_double(sqlite3_context *pCtx, double rVal){ + MemSetReal(&pCtx->s, rVal); +} +void sqlite3_result_null(sqlite3_context *pCtx){ + MemSetNull(&pCtx->s); +} +void sqlite3_result_text( + sqlite3_context *pCtx, + const char *z, + int n, + int eCopy +){ + MemSetStr(&pCtx->s, z, n, TEXT_Utf8, eCopy); +} +void sqlite3_result_text16( + sqlite3_context *pCtx, + const void *z, + int n, + int eCopy +){ + MemSetStr(&pCtx->s, z, n, TEXT_Utf16, eCopy); +} +void sqlite3_result_blob( + sqlite3_context *pCtx, + const void *z, + int n, + int eCopy +){ + assert( n>0 ); + MemSetStr(&pCtx->s, z, n, 0, eCopy); +} +void sqlite3_result_error(sqlite3_context *pCtx, const char *z, int n){ + pCtx->isError = 1; + MemSetStr(&pCtx->s, z, n, TEXT_Utf8, 1); +} +void sqlite3_result_error16(sqlite3_context *pCtx, const void *z, int n){ + pCtx->isError = 1; + MemSetStr(&pCtx->s, z, n, TEXT_Utf16, 1); +} +