|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#include "sqlite3ext.h" |
|
|
SQLITE_EXTENSION_INIT1 |
|
|
#include <assert.h> |
|
|
#include <string.h> |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#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 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#ifndef LARGEST_INT64 |
|
|
# define LARGEST_INT64 (0xffffffff|(((sqlite3_int64)0x7fffffff)<<32)) |
|
|
#endif |
|
|
|
|
|
#ifndef SMALLEST_INT64 |
|
|
# define SMALLEST_INT64 (((sqlite3_int64)-1) - LARGEST_INT64) |
|
|
#endif |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int totypeIsspace(unsigned char c){ |
|
|
return c==' ' || c=='\t' || c=='\n' || c=='\v' || c=='\f' || c=='\r'; |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int totypeIsdigit(unsigned char c){ |
|
|
return c>='0' && c<='9'; |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int totypeCompare2pow63(const char *zNum){ |
|
|
int c = 0; |
|
|
int i; |
|
|
|
|
|
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; |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int totypeAtoi64(const char *zNum, sqlite3_int64 *pNum, int length){ |
|
|
sqlite3_uint64 u = 0; |
|
|
int neg = 0; |
|
|
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++; } |
|
|
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 ){ |
|
|
|
|
|
|
|
|
return 1; |
|
|
}else if( i<19 ){ |
|
|
|
|
|
assert( u<=LARGEST_INT64 ); |
|
|
return 0; |
|
|
}else{ |
|
|
|
|
|
c = totypeCompare2pow63(zNum); |
|
|
if( c<0 ){ |
|
|
|
|
|
assert( u<=LARGEST_INT64 ); |
|
|
return 0; |
|
|
}else if( c>0 ){ |
|
|
|
|
|
return 1; |
|
|
}else{ |
|
|
|
|
|
|
|
|
assert( u-1==LARGEST_INT64 ); |
|
|
assert( (*pNum)==SMALLEST_INT64 ); |
|
|
return neg ? 0 : 2; |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int totypeAtoF(const char *z, double *pResult, int length){ |
|
|
const char *zEnd = z + length; |
|
|
|
|
|
int sign = 1; |
|
|
sqlite3_int64 s = 0; |
|
|
int d = 0; |
|
|
int esign = 1; |
|
|
int e = 0; |
|
|
int eValid = 1; |
|
|
double result; |
|
|
int nDigits = 0; |
|
|
int nonNum = 0; |
|
|
|
|
|
*pResult = 0.0; |
|
|
|
|
|
|
|
|
while( z<zEnd && totypeIsspace(*z) ) z++; |
|
|
if( z>=zEnd ) return 0; |
|
|
|
|
|
|
|
|
if( *z=='-' ){ |
|
|
sign = -1; |
|
|
z++; |
|
|
}else if( *z=='+' ){ |
|
|
z++; |
|
|
} |
|
|
|
|
|
|
|
|
while( z<zEnd && z[0]=='0' ) z++, nDigits++; |
|
|
|
|
|
|
|
|
while( z<zEnd && totypeIsdigit(*z) && s<((LARGEST_INT64-9)/10) ){ |
|
|
s = s*10 + (*z - '0'); |
|
|
z++, nDigits++; |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
while( z<zEnd && totypeIsdigit(*z) ) z++, nDigits++, d++; |
|
|
if( z>=zEnd ) goto totype_atof_calc; |
|
|
|
|
|
|
|
|
if( *z=='.' ){ |
|
|
z++; |
|
|
|
|
|
|
|
|
while( z<zEnd && totypeIsdigit(*z) && s<((LARGEST_INT64-9)/10) ){ |
|
|
s = s*10 + (*z - '0'); |
|
|
z++, nDigits++, d--; |
|
|
} |
|
|
|
|
|
while( z<zEnd && totypeIsdigit(*z) ) z++, nDigits++; |
|
|
} |
|
|
if( z>=zEnd ) goto totype_atof_calc; |
|
|
|
|
|
|
|
|
if( *z=='e' || *z=='E' ){ |
|
|
z++; |
|
|
eValid = 0; |
|
|
if( z>=zEnd ) goto totype_atof_calc; |
|
|
|
|
|
if( *z=='-' ){ |
|
|
esign = -1; |
|
|
z++; |
|
|
}else if( *z=='+' ){ |
|
|
z++; |
|
|
} |
|
|
|
|
|
while( z<zEnd && totypeIsdigit(*z) ){ |
|
|
e = e<10000 ? (e*10 + (*z - '0')) : 10000; |
|
|
z++; |
|
|
eValid = 1; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
if( nDigits && eValid ){ |
|
|
while( z<zEnd && totypeIsspace(*z) ) z++; |
|
|
} |
|
|
|
|
|
totype_atof_calc: |
|
|
|
|
|
e = (e*esign) + d; |
|
|
if( e<0 ) { |
|
|
esign = -1; |
|
|
e *= -1; |
|
|
} else { |
|
|
esign = 1; |
|
|
} |
|
|
|
|
|
|
|
|
if( !s ) { |
|
|
|
|
|
|
|
|
result = (sign<0 && nDigits) ? -(double)0 : (double)0; |
|
|
} else { |
|
|
|
|
|
if( esign>0 ){ |
|
|
while( s<(LARGEST_INT64/10) && e>0 ) e--,s*=10; |
|
|
}else{ |
|
|
while( !(s%10) && e>0 ) e--,s/=10; |
|
|
} |
|
|
|
|
|
|
|
|
s = sign<0 ? -s : s; |
|
|
|
|
|
|
|
|
|
|
|
if( e ){ |
|
|
double scale = 1.0; |
|
|
|
|
|
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; |
|
|
} |
|
|
}else{ |
|
|
|
|
|
|
|
|
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; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
*pResult = result; |
|
|
|
|
|
|
|
|
return z>=zEnd && nDigits>0 && eValid && nonNum==0; |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static sqlite3_int64 totypeDoubleToInt(double r){ |
|
|
if( r<-9223372036854774784.0 ) return 0; |
|
|
if( r>+9223372036854774784.0 ) return 0; |
|
|
return (sqlite3_int64)r; |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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; |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#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; |
|
|
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; |
|
|
} |
|
|
|