#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 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 = (sqlite3_int64)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==(sqlite3_int64)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;
}