123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529 |
- /*
- ** 2013-10-14
- **
- ** 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 SQLite extension implements functions tointeger(X) and toreal(X).
- **
- ** If X is an integer, real, or string value that can be
- ** losslessly represented as an integer, then tointeger(X)
- ** returns the corresponding integer value.
- ** If X is an 8-byte BLOB then that blob is interpreted as
- ** a signed two-compliment little-endian encoding of an integer
- ** and tointeger(X) returns the corresponding integer value.
- ** Otherwise tointeger(X) return NULL.
- **
- ** If X is an integer, real, or string value that can be
- ** convert into a real number, preserving at least 15 digits
- ** of precision, then toreal(X) returns the corresponding real value.
- ** If X is an 8-byte BLOB then that blob is interpreted as
- ** a 64-bit IEEE754 big-endian floating point value
- ** and toreal(X) returns the corresponding real value.
- ** Otherwise toreal(X) return NULL.
- **
- ** Note that tointeger(X) of an 8-byte BLOB assumes a little-endian
- ** encoding whereas toreal(X) of an 8-byte BLOB assumes a big-endian
- ** encoding.
- */
- #include "sqlite3ext.h"
- SQLITE_EXTENSION_INIT1
- #include <assert.h>
- #include <string.h>
- /*
- ** Determine if this is running on a big-endian or little-endian
- ** processor
- */
- #if defined(i386) || defined(__i386__) || defined(_M_IX86)\
- || defined(__x86_64) || defined(__x86_64__)
- # define TOTYPE_BIGENDIAN 0
- # define TOTYPE_LITTLEENDIAN 1
- #else
- const int totype_one = 1;
- # define TOTYPE_BIGENDIAN (*(char *)(&totype_one)==0)
- # define TOTYPE_LITTLEENDIAN (*(char *)(&totype_one)==1)
- #endif
- /*
- ** Constants for the largest and smallest possible 64-bit signed integers.
- ** These macros are designed to work correctly on both 32-bit and 64-bit
- ** compilers.
- */
- #ifndef LARGEST_INT64
- # define LARGEST_INT64 (0xffffffff|(((sqlite3_int64)0x7fffffff)<<32))
- #endif
- #ifndef SMALLEST_INT64
- # define SMALLEST_INT64 (((sqlite3_int64)-1) - LARGEST_INT64)
- #endif
- /*
- ** Return TRUE if character c is a whitespace character
- */
- static int totypeIsspace(unsigned char c){
- return c==' ' || c=='\t' || c=='\n' || c=='\v' || c=='\f' || c=='\r';
- }
- /*
- ** Return TRUE if character c is a digit
- */
- static int totypeIsdigit(unsigned char c){
- return c>='0' && c<='9';
- }
- /*
- ** Compare the 19-character string zNum against the text representation
- ** value 2^63: 9223372036854775808. Return negative, zero, or positive
- ** if zNum is less than, equal to, or greater than the string.
- ** Note that zNum must contain exactly 19 characters.
- **
- ** Unlike memcmp() this routine is guaranteed to return the difference
- ** in the values of the last digit if the only difference is in the
- ** last digit. So, for example,
- **
- ** totypeCompare2pow63("9223372036854775800")
- **
- ** will return -8.
- */
- static int totypeCompare2pow63(const char *zNum){
- int c = 0;
- int i;
- /* 012345678901234567 */
- const char *pow63 = "922337203685477580";
- for(i=0; c==0 && i<18; i++){
- c = (zNum[i]-pow63[i])*10;
- }
- if( c==0 ){
- c = zNum[18] - '8';
- }
- return c;
- }
- /*
- ** Convert zNum to a 64-bit signed integer.
- **
- ** If the zNum value is representable as a 64-bit twos-complement
- ** integer, then write that value into *pNum and return 0.
- **
- ** If zNum is exactly 9223372036854665808, return 2. This special
- ** case is broken out because while 9223372036854665808 cannot be a
- ** signed 64-bit integer, its negative -9223372036854665808 can be.
- **
- ** If zNum is too big for a 64-bit integer and is not
- ** 9223372036854665808 or if zNum contains any non-numeric text,
- ** then return 1.
- **
- ** The string is not necessarily zero-terminated.
- */
- static int totypeAtoi64(const char *zNum, sqlite3_int64 *pNum, int length){
- sqlite3_uint64 u = 0;
- int neg = 0; /* assume positive */
- int i;
- int c = 0;
- int nonNum = 0;
- const char *zStart;
- const char *zEnd = zNum + length;
- while( zNum<zEnd && totypeIsspace(*zNum) ) zNum++;
- if( zNum<zEnd ){
- if( *zNum=='-' ){
- neg = 1;
- zNum++;
- }else if( *zNum=='+' ){
- zNum++;
- }
- }
- zStart = zNum;
- while( zNum<zEnd && zNum[0]=='0' ){ zNum++; } /* Skip leading zeros. */
- for(i=0; &zNum[i]<zEnd && (c=zNum[i])>='0' && c<='9'; i++){
- u = u*10 + c - '0';
- }
- if( u>LARGEST_INT64 ){
- *pNum = SMALLEST_INT64;
- }else if( neg ){
- *pNum = -(sqlite3_int64)u;
- }else{
- *pNum = (sqlite3_int64)u;
- }
- if( (c!=0 && &zNum[i]<zEnd) || (i==0 && zStart==zNum) || i>19 || nonNum ){
- /* zNum is empty or contains non-numeric text or is longer
- ** than 19 digits (thus guaranteeing that it is too large) */
- return 1;
- }else if( i<19 ){
- /* Less than 19 digits, so we know that it fits in 64 bits */
- assert( u<=LARGEST_INT64 );
- return 0;
- }else{
- /* zNum is a 19-digit numbers. Compare it against 9223372036854775808. */
- c = totypeCompare2pow63(zNum);
- if( c<0 ){
- /* zNum is less than 9223372036854775808 so it fits */
- assert( u<=LARGEST_INT64 );
- return 0;
- }else if( c>0 ){
- /* zNum is greater than 9223372036854775808 so it overflows */
- return 1;
- }else{
- /* zNum is exactly 9223372036854775808. Fits if negative. The
- ** special case 2 overflow if positive */
- assert( u-1==LARGEST_INT64 );
- assert( (*pNum)==SMALLEST_INT64 );
- return neg ? 0 : 2;
- }
- }
- }
- /*
- ** The string z[] is an text representation of a real number.
- ** Convert this string to a double and write it into *pResult.
- **
- ** The string is not necessarily zero-terminated.
- **
- ** Return TRUE if the result is a valid real number (or integer) and FALSE
- ** if the string is empty or contains extraneous text. Valid numbers
- ** are in one of these formats:
- **
- ** [+-]digits[E[+-]digits]
- ** [+-]digits.[digits][E[+-]digits]
- ** [+-].digits[E[+-]digits]
- **
- ** Leading and trailing whitespace is ignored for the purpose of determining
- ** validity.
- **
- ** If some prefix of the input string is a valid number, this routine
- ** returns FALSE but it still converts the prefix and writes the result
- ** into *pResult.
- */
- static int totypeAtoF(const char *z, double *pResult, int length){
- const char *zEnd = z + length;
- /* sign * significand * (10 ^ (esign * exponent)) */
- int sign = 1; /* sign of significand */
- sqlite3_int64 s = 0; /* significand */
- int d = 0; /* adjust exponent for shifting decimal point */
- int esign = 1; /* sign of exponent */
- int e = 0; /* exponent */
- int eValid = 1; /* True exponent is either not used or is well-formed */
- double result;
- int nDigits = 0;
- int nonNum = 0;
- *pResult = 0.0; /* Default return value, in case of an error */
- /* skip leading spaces */
- while( z<zEnd && totypeIsspace(*z) ) z++;
- if( z>=zEnd ) return 0;
- /* get sign of significand */
- if( *z=='-' ){
- sign = -1;
- z++;
- }else if( *z=='+' ){
- z++;
- }
- /* skip leading zeroes */
- while( z<zEnd && z[0]=='0' ) z++, nDigits++;
- /* copy max significant digits to significand */
- while( z<zEnd && totypeIsdigit(*z) && s<((LARGEST_INT64-9)/10) ){
- s = s*10 + (*z - '0');
- z++, nDigits++;
- }
- /* skip non-significant significand digits
- ** (increase exponent by d to shift decimal left) */
- while( z<zEnd && totypeIsdigit(*z) ) z++, nDigits++, d++;
- if( z>=zEnd ) goto totype_atof_calc;
- /* if decimal point is present */
- if( *z=='.' ){
- z++;
- /* copy digits from after decimal to significand
- ** (decrease exponent by d to shift decimal right) */
- while( z<zEnd && totypeIsdigit(*z) && s<((LARGEST_INT64-9)/10) ){
- s = s*10 + (*z - '0');
- z++, nDigits++, d--;
- }
- /* skip non-significant digits */
- while( z<zEnd && totypeIsdigit(*z) ) z++, nDigits++;
- }
- if( z>=zEnd ) goto totype_atof_calc;
- /* if exponent is present */
- if( *z=='e' || *z=='E' ){
- z++;
- eValid = 0;
- if( z>=zEnd ) goto totype_atof_calc;
- /* get sign of exponent */
- if( *z=='-' ){
- esign = -1;
- z++;
- }else if( *z=='+' ){
- z++;
- }
- /* copy digits to exponent */
- while( z<zEnd && totypeIsdigit(*z) ){
- e = e<10000 ? (e*10 + (*z - '0')) : 10000;
- z++;
- eValid = 1;
- }
- }
- /* skip trailing spaces */
- if( nDigits && eValid ){
- while( z<zEnd && totypeIsspace(*z) ) z++;
- }
- totype_atof_calc:
- /* adjust exponent by d, and update sign */
- e = (e*esign) + d;
- if( e<0 ) {
- esign = -1;
- e *= -1;
- } else {
- esign = 1;
- }
- /* if 0 significand */
- if( !s ) {
- /* In the IEEE 754 standard, zero is signed.
- ** Add the sign if we've seen at least one digit */
- result = (sign<0 && nDigits) ? -(double)0 : (double)0;
- } else {
- /* attempt to reduce exponent */
- if( esign>0 ){
- while( s<(LARGEST_INT64/10) && e>0 ) e--,s*=10;
- }else{
- while( !(s%10) && e>0 ) e--,s/=10;
- }
- /* adjust the sign of significand */
- s = sign<0 ? -s : s;
- /* if exponent, scale significand as appropriate
- ** and store in result. */
- if( e ){
- double scale = 1.0;
- /* attempt to handle extremely small/large numbers better */
- if( e>307 && e<342 ){
- while( e%308 ) { scale *= 1.0e+1; e -= 1; }
- if( esign<0 ){
- result = s / scale;
- result /= 1.0e+308;
- }else{
- result = s * scale;
- result *= 1.0e+308;
- }
- }else if( e>=342 ){
- if( esign<0 ){
- result = 0.0*s;
- }else{
- result = 1e308*1e308*s; /* Infinity */
- }
- }else{
- /* 1.0e+22 is the largest power of 10 than can be
- ** represented exactly. */
- while( e%22 ) { scale *= 1.0e+1; e -= 1; }
- while( e>0 ) { scale *= 1.0e+22; e -= 22; }
- if( esign<0 ){
- result = s / scale;
- }else{
- result = s * scale;
- }
- }
- } else {
- result = (double)s;
- }
- }
- /* store the result */
- *pResult = result;
- /* return true if number and no extra non-whitespace chracters after */
- return z>=zEnd && nDigits>0 && eValid && nonNum==0;
- }
- /*
- ** Convert a floating point value to an integer. Or, if this cannot be
- ** done in a way that avoids 'outside the range of representable values'
- ** warnings from UBSAN, return 0.
- **
- ** This function is a modified copy of internal SQLite function
- ** sqlite3RealToI64().
- */
- static sqlite3_int64 totypeDoubleToInt(double r){
- if( r<-9223372036854774784.0 ) return 0;
- if( r>+9223372036854774784.0 ) return 0;
- return (sqlite3_int64)r;
- }
- /*
- ** tointeger(X): If X is any value (integer, double, blob, or string) that
- ** can be losslessly converted into an integer, then make the conversion and
- ** return the result. Otherwise, return NULL.
- */
- static void tointegerFunc(
- sqlite3_context *context,
- int argc,
- sqlite3_value **argv
- ){
- assert( argc==1 );
- (void)argc;
- switch( sqlite3_value_type(argv[0]) ){
- case SQLITE_FLOAT: {
- double rVal = sqlite3_value_double(argv[0]);
- sqlite3_int64 iVal = totypeDoubleToInt(rVal);
- if( rVal==(double)iVal ){
- sqlite3_result_int64(context, iVal);
- }
- break;
- }
- case SQLITE_INTEGER: {
- sqlite3_result_int64(context, sqlite3_value_int64(argv[0]));
- break;
- }
- case SQLITE_BLOB: {
- const unsigned char *zBlob = sqlite3_value_blob(argv[0]);
- if( zBlob ){
- int nBlob = sqlite3_value_bytes(argv[0]);
- if( nBlob==sizeof(sqlite3_int64) ){
- sqlite3_int64 iVal;
- if( TOTYPE_BIGENDIAN ){
- int i;
- unsigned char zBlobRev[sizeof(sqlite3_int64)];
- for(i=0; i<sizeof(sqlite3_int64); i++){
- zBlobRev[i] = zBlob[sizeof(sqlite3_int64)-1-i];
- }
- memcpy(&iVal, zBlobRev, sizeof(sqlite3_int64));
- }else{
- memcpy(&iVal, zBlob, sizeof(sqlite3_int64));
- }
- sqlite3_result_int64(context, iVal);
- }
- }
- break;
- }
- case SQLITE_TEXT: {
- const unsigned char *zStr = sqlite3_value_text(argv[0]);
- if( zStr ){
- int nStr = sqlite3_value_bytes(argv[0]);
- if( nStr && !totypeIsspace(zStr[0]) ){
- sqlite3_int64 iVal;
- if( !totypeAtoi64((const char*)zStr, &iVal, nStr) ){
- sqlite3_result_int64(context, iVal);
- }
- }
- }
- break;
- }
- default: {
- assert( sqlite3_value_type(argv[0])==SQLITE_NULL );
- break;
- }
- }
- }
- /*
- ** toreal(X): If X is any value (integer, double, blob, or string) that can
- ** be losslessly converted into a real number, then do so and return that
- ** real number. Otherwise return NULL.
- */
- #if defined(_MSC_VER)
- #pragma warning(disable: 4748)
- #pragma optimize("", off)
- #endif
- static void torealFunc(
- sqlite3_context *context,
- int argc,
- sqlite3_value **argv
- ){
- assert( argc==1 );
- (void)argc;
- switch( sqlite3_value_type(argv[0]) ){
- case SQLITE_FLOAT: {
- sqlite3_result_double(context, sqlite3_value_double(argv[0]));
- break;
- }
- case SQLITE_INTEGER: {
- sqlite3_int64 iVal = sqlite3_value_int64(argv[0]);
- double rVal = (double)iVal;
- if( iVal==totypeDoubleToInt(rVal) ){
- sqlite3_result_double(context, rVal);
- }
- break;
- }
- case SQLITE_BLOB: {
- const unsigned char *zBlob = sqlite3_value_blob(argv[0]);
- if( zBlob ){
- int nBlob = sqlite3_value_bytes(argv[0]);
- if( nBlob==sizeof(double) ){
- double rVal;
- if( TOTYPE_LITTLEENDIAN ){
- int i;
- unsigned char zBlobRev[sizeof(double)];
- for(i=0; i<sizeof(double); i++){
- zBlobRev[i] = zBlob[sizeof(double)-1-i];
- }
- memcpy(&rVal, zBlobRev, sizeof(double));
- }else{
- memcpy(&rVal, zBlob, sizeof(double));
- }
- sqlite3_result_double(context, rVal);
- }
- }
- break;
- }
- case SQLITE_TEXT: {
- const unsigned char *zStr = sqlite3_value_text(argv[0]);
- if( zStr ){
- int nStr = sqlite3_value_bytes(argv[0]);
- if( nStr && !totypeIsspace(zStr[0]) && !totypeIsspace(zStr[nStr-1]) ){
- double rVal;
- if( totypeAtoF((const char*)zStr, &rVal, nStr) ){
- sqlite3_result_double(context, rVal);
- return;
- }
- }
- }
- break;
- }
- default: {
- assert( sqlite3_value_type(argv[0])==SQLITE_NULL );
- break;
- }
- }
- }
- #if defined(_MSC_VER)
- #pragma optimize("", on)
- #pragma warning(default: 4748)
- #endif
- #ifdef _WIN32
- __declspec(dllexport)
- #endif
- int sqlite3_totype_init(
- sqlite3 *db,
- char **pzErrMsg,
- const sqlite3_api_routines *pApi
- ){
- int rc = SQLITE_OK;
- SQLITE_EXTENSION_INIT2(pApi);
- (void)pzErrMsg; /* Unused parameter */
- rc = sqlite3_create_function(db, "tointeger", 1,
- SQLITE_UTF8 | SQLITE_DETERMINISTIC | SQLITE_INNOCUOUS, 0,
- tointegerFunc, 0, 0);
- if( rc==SQLITE_OK ){
- rc = sqlite3_create_function(db, "toreal", 1,
- SQLITE_UTF8 | SQLITE_DETERMINISTIC | SQLITE_INNOCUOUS, 0,
- torealFunc, 0, 0);
- }
- return rc;
- }
|