From 5708d2deacccde4c3d6a5de48b74c9bb7cae8aee Mon Sep 17 00:00:00 2001 From: drh Date: Wed, 22 Jun 2005 10:53:59 +0000 Subject: [PATCH] Add built-in functions numeric(), text(), and blob() that coerce types. Ticket #1287. (CVS 2524) FossilOrigin-Name: affb0fa2e8c5ff497838ba3c2994cdb1f6f50c68 --- manifest | 16 +++--- manifest.uuid | 2 +- src/func.c | 92 +++++++++++++++++++++++++++++++++- src/vdbeapi.c | 2 +- test/func.test | 133 ++++++++++++++++++++++++++++++++++++++++++++++++- 5 files changed, 232 insertions(+), 13 deletions(-) diff --git a/manifest b/manifest index 519fcc2e73..c2a3bda225 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Allow\sparameters\sto\sbe\sintroduced\sby\scharacters\s':',\s'$'\sand\s'#'.\s\sThis\nis\san\sexperimental\schange.\s(CVS\s2523) -D 2005-06-22T08:48:06 +C Add\sbuilt-in\sfunctions\snumeric(),\stext(),\sand\sblob()\sthat\scoerce\stypes.\r\nTicket\s#1287.\s(CVS\s2524) +D 2005-06-22T10:53:59 F Makefile.in 64a6635ef44a98325e0cffe8d67669920a3dad47 F Makefile.linux-gcc 06be33b2a9ad4f005a5f42b22c4a19dab3cbb5c7 F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028 @@ -38,7 +38,7 @@ F src/date.c 2134ef4388256e8247405178df8a61bd60dc180a F src/delete.c 4b68127f55971c7fb459146e0b6cf3bd70cfffe9 F src/experimental.c 50c1e3b34f752f4ac10c36f287db095c2b61766d F src/expr.c 4d6e26da200e0d08233df52fd8d07916d24a6926 -F src/func.c f208d71f741d47b63277530939f552815af8ce35 +F src/func.c 301b81af2e831b2e929f0ba252739c32a0c756e5 F src/hash.c 2b1b13f7400e179631c83a1be0c664608c8f021f F src/hash.h 1b0c445e1c89ff2aaad9b4605ba61375af001e84 F src/insert.c 8c0868a975fe37366ed92e1b976853be96284607 @@ -80,7 +80,7 @@ F src/vacuum.c 829d9e1a6d7c094b80e0899686670932eafd768c F src/vdbe.c 4745b575d9f23a960da0ce8334f99b98ea855265 F src/vdbe.h 75e466d84d362b0c4498978a9d6b1e6bd32ecf3b F src/vdbeInt.h 4312faf41630a6c215924b6c7c2f39ebb1af8ffb -F src/vdbeapi.c 3f858d2236df0d127249a6a166e0e25b5de650ed +F src/vdbeapi.c 5025a9163107e0a4964212d16e1c4defa13dc5c2 F src/vdbeaux.c 38332d91887817a2146f46b58fff2a8a88ed0278 F src/vdbemem.c 48a64ae95a9edc6e8d940300dad15d70d1670398 F src/where.c 3a9a2258ab3364655e9ea215ad5ae7bf41813f54 @@ -132,7 +132,7 @@ F test/enc2.test d1ab077b84f4d3099246915422b1ab6b81481e0a F test/enc3.test f6a5f0b7b7f3a88f030d3143729b87cd5c86d837 F test/expr.test 54d9d1cc05eb731fa62daa70f2d7163f8a03c54d F test/fkey1.test 81bb13caaa78f58d7d191d7f535529f7c91d821a -F test/func.test 7d2d8489bede4495feca427c5efc7b7a2f3b1e94 +F test/func.test f5f9f2bd3f1121ae82eb4d6b3f48b8c52f597895 F test/hook.test f8605cde4c77b2c6a4a73723bf6c507796a64dda F test/in.test ed134f8d477a6280297ced1646de83cccf8f196d F test/index.test 51e01a0928b4b61228917ddd8c6c0e2466547f6f @@ -281,7 +281,7 @@ F www/tclsqlite.tcl 425be741b8ae664f55cb1ef2371aab0a75109cf9 F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0 F www/version3.tcl a99cf5f6d8bd4d5537584a2b342f0fb9fa601d8b F www/whentouse.tcl 528299b8316726dbcc5548e9aa0648c8b1bd055b -P 60f752ed1817e6710c13c2ce393c3bf51dae76ad -R 0728a1fdbaca12bf5f29cdb10e76a914 +P f3427a139c3bd4faf9134ec6290b3eb829c0a19f +R 71ae20ec723bd0f4ef99d2a15e3563f6 U drh -Z 6446212b902f4acbac0e5ce1e2a10f05 +Z 9f6943b255fa6f70bc55d3e3a0442f66 diff --git a/manifest.uuid b/manifest.uuid index 9c51dfed70..31646f2545 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -f3427a139c3bd4faf9134ec6290b3eb829c0a19f \ No newline at end of file +affb0fa2e8c5ff497838ba3c2994cdb1f6f50c68 \ No newline at end of file diff --git a/src/func.c b/src/func.c index e1b2195e89..d13ba437cb 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.98 2005/05/24 12:01:02 danielk1977 Exp $ +** $Id: func.c,v 1.99 2005/06/22 10:53:59 drh Exp $ */ #include "sqliteInt.h" #include @@ -78,6 +78,93 @@ static void typeofFunc( sqlite3_result_text(context, z, -1, SQLITE_STATIC); } +/* +** Convert the argument to a numeric type. +*/ +static void numericFunc( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + const char *z = 0; + switch( sqlite3_value_type(argv[0]) ){ + case SQLITE_NULL: { + sqlite3_result_int(context, 0); + break; + } + case SQLITE_INTEGER: + case SQLITE_FLOAT: { + sqlite3_result_value(context, argv[0]); + break; + } + case SQLITE_TEXT: + case SQLITE_BLOB: { + z = sqlite3_value_text(argv[0]); + while( *z && *z!='.' ){ z++; } + if( *z ){ + sqlite3_result_double(context, sqlite3_value_double(argv[0])); + }else{ + sqlite3_result_int64(context, sqlite3_value_int64(argv[0])); + } + break; + } + } +} + +/* +** Convert the argument to TEXT +*/ +static void textFunc( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + switch( sqlite3_value_type(argv[0]) ){ + case SQLITE_NULL: { + sqlite3_result_text(context, "", 0, SQLITE_STATIC); + break; + } + case SQLITE_BLOB: + case SQLITE_INTEGER: + case SQLITE_FLOAT: { + sqlite3_result_text(context, sqlite3_value_text(argv[0]), + sqlite3_value_bytes(argv[0]), SQLITE_TRANSIENT); + break; + } + case SQLITE_TEXT: { + sqlite3_result_value(context, argv[0]); + break; + } + } +} + +/* +** Convert the argument to TEXT +*/ +static void blobFunc( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + switch( sqlite3_value_type(argv[0]) ){ + case SQLITE_NULL: { + sqlite3_result_blob(context, "", 0, SQLITE_STATIC); + break; + } + case SQLITE_TEXT: + case SQLITE_INTEGER: + case SQLITE_FLOAT: { + sqlite3_result_blob(context, sqlite3_value_text(argv[0]), + sqlite3_value_bytes(argv[0]), SQLITE_TRANSIENT); + break; + } + case SQLITE_BLOB: { + sqlite3_result_value(context, argv[0]); + break; + } + } +} + /* ** Implementation of the length() function */ @@ -971,6 +1058,9 @@ void sqlite3RegisterBuiltinFunctions(sqlite3 *db){ { "last_insert_rowid", 0, 1, SQLITE_UTF8, 0, last_insert_rowid }, { "changes", 0, 1, SQLITE_UTF8, 0, changes }, { "total_changes", 0, 1, SQLITE_UTF8, 0, total_changes }, + { "text", 1, 0, SQLITE_UTF8, 0, textFunc }, + { "numeric", 1, 0, SQLITE_UTF8, 0, numericFunc }, + { "blob", 1, 0, SQLITE_UTF8, 0, blobFunc }, #ifdef SQLITE_SOUNDEX { "soundex", 1, 0, SQLITE_UTF8, 0, soundexFunc}, #endif diff --git a/src/vdbeapi.c b/src/vdbeapi.c index f07bc88992..99da1c30bc 100644 --- a/src/vdbeapi.c +++ b/src/vdbeapi.c @@ -84,7 +84,7 @@ void sqlite3_result_blob( int n, void (*xDel)(void *) ){ - assert( n>0 ); + assert( n>=0 ); sqlite3VdbeMemSetStr(&pCtx->s, z, n, 0, xDel); } void sqlite3_result_double(sqlite3_context *pCtx, double rVal){ diff --git a/test/func.test b/test/func.test index feed0d03b1..ab8b6f6df7 100644 --- a/test/func.test +++ b/test/func.test @@ -11,7 +11,7 @@ # This file implements regression tests for SQLite library. The # focus of this file is testing built-in functions. # -# $Id: func.test,v 1.34 2005/03/29 03:11:00 danielk1977 Exp $ +# $Id: func.test,v 1.35 2005/06/22 10:53:59 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl @@ -485,5 +485,134 @@ do_test func-16.1 { } } {X'616263' NULL} -finish_test +# Tests for the blob(), text() and numeric() built-ins +# +do_test func-17.1 { + execsql {SELECT x'616263'} +} abc +do_test func-17.2 { + execsql {SELECT typeof(x'616263')} +} blob +do_test func-17.3 { + execsql {SELECT text(x'616263')} +} abc +do_test func-17.4 { + execsql {SELECT typeof(text(x'616263'))} +} text +do_test func-17.5 { + execsql {SELECT numeric(x'616263')} +} 0 +do_test func-17.6 { + execsql {SELECT typeof(numeric(x'616263'))} +} integer +do_test func-17.7 { + execsql {SELECT blob(x'616263')} +} abc +do_test func-17.8 { + execsql {SELECT typeof(blob(x'616263'))} +} blob +do_test func-17.11 { + execsql {SELECT null} +} {{}} +do_test func-17.12 { + execsql {SELECT typeof(NULL)} +} null +do_test func-17.13 { + execsql {SELECT text(NULL)} +} {{}} +do_test func-17.14 { + execsql {SELECT typeof(text(NULL))} +} text +do_test func-17.15 { + execsql {SELECT numeric(NULL)} +} 0 +do_test func-17.16 { + execsql {SELECT typeof(numeric(NULL))} +} integer +do_test func-17.17 { + execsql {SELECT blob(NULL)} +} {{}} +do_test func-17.18 { + execsql {SELECT typeof(blob(NULL))} +} blob +do_test func-17.21 { + execsql {SELECT 123} +} {123} +do_test func-17.22 { + execsql {SELECT typeof(123)} +} integer +do_test func-17.23 { + execsql {SELECT text(123)} +} {123} +do_test func-17.24 { + execsql {SELECT typeof(text(123))} +} text +do_test func-17.25 { + execsql {SELECT numeric(123)} +} 123 +do_test func-17.26 { + execsql {SELECT typeof(numeric(123))} +} integer +do_test func-17.27 { + execsql {SELECT blob(123)} +} {123} +do_test func-17.28 { + execsql {SELECT typeof(blob(123))} +} blob +do_test func-17.31 { + execsql {SELECT 123.456} +} {123.456} +do_test func-17.32 { + execsql {SELECT typeof(123.456)} +} real +do_test func-17.33 { + execsql {SELECT text(123.456)} +} {123.456} +do_test func-17.34 { + execsql {SELECT typeof(text(123.456))} +} text +do_test func-17.35 { + execsql {SELECT numeric(123.456)} +} 123.456 +do_test func-17.36 { + execsql {SELECT typeof(numeric(123.456))} +} real +do_test func-17.37 { + execsql {SELECT blob(123.456)} +} {123.456} +do_test func-17.38 { + execsql {SELECT typeof(blob(123.456))} +} blob +do_test func-17.41 { + execsql {SELECT '123abc'} +} {123abc} +do_test func-17.42 { + execsql {SELECT typeof('123abc')} +} text +do_test func-17.43 { + execsql {SELECT text('123abc')} +} {123abc} +do_test func-17.44 { + execsql {SELECT typeof(text('123abc'))} +} text +do_test func-17.45 { + execsql {SELECT numeric('123abc')} +} 123 +do_test func-17.46 { + execsql {SELECT typeof(numeric('123abc'))} +} integer +do_test func-17.47 { + execsql {SELECT blob('123abc')} +} {123abc} +do_test func-17.48 { + execsql {SELECT typeof(blob('123abc'))} +} blob +do_test func-17.49 { + execsql {SELECT numeric('123.5abc')} +} 123.5 +do_test func-17.49b { + execsql {SELECT typeof(numeric('123.5abc'))} +} real + +finish_test