From 61d2f915e3429cbbc52bb2a8292b87449853a7da Mon Sep 17 00:00:00 2001 From: drh Date: Mon, 18 Jun 2012 14:23:06 +0000 Subject: [PATCH] Add the ieee754() SQL function that interprets a blob as a big-endian double. Arrange for the quote() SQL function to emit ieee754() functions in its output so that floating-point values in the database are exactly preserved by a ".dump" command in the shell. FossilOrigin-Name: 87597e988fc6aad00e1326c152830a0938d30457 --- manifest | 15 +++++++----- manifest.uuid | 2 +- src/func.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 75 insertions(+), 8 deletions(-) diff --git a/manifest b/manifest index 1043803b95..b55e0e3b9c 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C In\sLemon,\swhen\scomparing\sthe\soutput\sto\sthe\s*.h\sfile\sto\ssee\sif\sit\shas\schanged,\nmake\ssure\sthat\sthe\sproposed\snew\soutput\sand\sthe\spreexisting\soutput\sare\sthe\nsame\ssize\sbefore\sdeciding\sthat\sthey\sare\sthe\ssame. -D 2012-06-16T15:26:31.082 +C Add\sthe\sieee754()\sSQL\sfunction\sthat\sinterprets\sa\sblob\sas\sa\sbig-endian\sdouble.\nArrange\sfor\sthe\squote()\sSQL\sfunction\sto\semit\sieee754()\sfunctions\sin\sits\soutput\nso\sthat\sfloating-point\svalues\sin\sthe\sdatabase\sare\sexactly\spreserved\sby\sa\n".dump"\scommand\sin\sthe\sshell. +D 2012-06-18T14:23:06.889 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in d17fddaa4e81f93a7c9c7c0808aacb3fc95f79f4 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -135,7 +135,7 @@ F src/delete.c 4c20ea4f6213b3bc1c6a510586864b679946e05e F src/expr.c 06a7733d19dc725dc46ba51afd9feadb4b85d991 F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb F src/fkey.c 657212460bf5cfd3ae607d12ea62092844c227b5 -F src/func.c c6b3c94320253a35bda43fb69cc292618e3285d6 +F src/func.c fab8831959557d4668decd4114da5686c5919d42 F src/global.c 4cfdca5cb0edd33c4d021baec4ede958cb2c793b F src/hash.c 458488dcc159c301b8e7686280ab209f1fb915af F src/hash.h 2894c932d84d9f892d4b4023a75e501f83050970 @@ -1005,7 +1005,10 @@ F tool/tostr.awk e75472c2f98dd76e06b8c9c1367f4ab07e122d06 F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 -P f5b5a13f7394dc143aa136f1d4faba6839eaa6dc -R 1f8bdd1a411e91223aef9522ba34a3e6 +P 0c2fb18d25217ada7e75dcab8b342bbc632875d8 +R a69dd6288fa77a5b1431e7d5145e0a60 +T *branch * ieee754-func +T *sym-ieee754-func * +T -sym-trunk * U drh -Z 53f96406b6eec20edfa4ee33fc7d7346 +Z f2065a600167b98e49c11fee712be824 diff --git a/manifest.uuid b/manifest.uuid index 0425283c18..913bcd0275 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -0c2fb18d25217ada7e75dcab8b342bbc632875d8 \ No newline at end of file +87597e988fc6aad00e1326c152830a0938d30457 \ No newline at end of file diff --git a/src/func.c b/src/func.c index 6ffc7184b0..137ed36114 100644 --- a/src/func.c +++ b/src/func.c @@ -841,6 +841,44 @@ static void compileoptiongetFunc( } #endif /* SQLITE_OMIT_COMPILEOPTION_DIAGS */ +/* +** 64-bit byte swap on little-endian platforms. No-op on bigenidan. +*/ +static void byteSwap64(unsigned char *x){ + if( !SQLITE_BIGENDIAN ){ + unsigned char c; + int i; + for(i=0; i<4; i++){ + c = x[i]; + x[i] = x[7-i]; + x[7-i] = c; + } + } +} + +/* +** The ieee754() function converts a blob into a REAL. The blob must be +** an big-endian ieee754 floating point number. +** +** Any argument other than an 8-byte blob returns NULL. +*/ +static void ieee754Func( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + assert( argc==1 ); + UNUSED_PARAMETER(argc); + if( sqlite3_value_type(argv[0])==SQLITE_BLOB + && sqlite3_value_bytes(argv[0])==8 + ){ + double r; + memcpy(&r, sqlite3_value_blob(argv[0]), 8); + byteSwap64((unsigned char*)&r); + sqlite3_result_double(context, r); + } +} + /* Array for converting from half-bytes (nybbles) into ASCII hex ** digits. */ static const char hexdigits[] = { @@ -863,8 +901,31 @@ static void quoteFunc(sqlite3_context *context, int argc, sqlite3_value **argv){ assert( argc==1 ); UNUSED_PARAMETER(argc); switch( sqlite3_value_type(argv[0]) ){ - case SQLITE_INTEGER: case SQLITE_FLOAT: { + union { + double r; + unsigned char x[8]; + } v; + sqlite3_int64 vi; + int i; + char zAns[30]; + v.r = sqlite3_value_double(argv[0]); + vi = (sqlite3_int64)v.r; + if( v.r==(double)vi ){ + sqlite3_result_value(context, argv[0]); + }else{ + byteSwap64(v.x); + /* 0123456789 123456789 12345678 */ + memcpy(zAns, "ieee754(X'----------------')", 29); + for(i=0; i<8; i++){ + zAns[10+i*2] = hexdigits[v.x[i]>>4]; + zAns[11+i*2] = hexdigits[v.x[i]&0xf]; + } + sqlite3_result_text(context, zAns, 28, SQLITE_TRANSIENT); + } + break; + } + case SQLITE_INTEGER: { sqlite3_result_value(context, argv[0]); break; } @@ -1568,6 +1629,9 @@ void sqlite3RegisterGlobalFunctions(void){ FUNCTION(sqlite_compileoption_used,1, 0, 0, compileoptionusedFunc ), FUNCTION(sqlite_compileoption_get, 1, 0, 0, compileoptiongetFunc ), #endif /* SQLITE_OMIT_COMPILEOPTION_DIAGS */ +#ifndef SQLITE_OMIT_FLOATING_POINT + FUNCTION(ieee754, 1, 0, 0, ieee754Func ), +#endif FUNCTION(quote, 1, 0, 0, quoteFunc ), FUNCTION(last_insert_rowid, 0, 0, 0, last_insert_rowid), FUNCTION(changes, 0, 0, 0, changes ), -- 2.39.5