]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Move the tointeger() and toreal() functions out of core and make them into
authordrh <drh@noemail.net>
Mon, 14 Oct 2013 21:14:42 +0000 (21:14 +0000)
committerdrh <drh@noemail.net>
Mon, 14 Oct 2013 21:14:42 +0000 (21:14 +0000)
a run-time loadable extension.

FossilOrigin-Name: 9f66dd7e3790c04f0ab724419f5381bd21f9ebad

Makefile.in
Makefile.msc
ext/misc/totype.c [new file with mode: 0644]
main.mk
manifest
manifest.uuid
src/func.c
src/test1.c
test/func4.test

index 91cac6ed374dc0f2f292a1bdbbde0e5f6b9be821..f01cae05e7b2dcf3ebcc965eccedb800c4b05f32 100644 (file)
@@ -396,6 +396,7 @@ TESTSRC += \
   $(TOP)/ext/misc/percentile.c \
   $(TOP)/ext/misc/regexp.c \
   $(TOP)/ext/misc/spellfix.c \
+  $(TOP)/ext/misc/totype.c \
   $(TOP)/ext/misc/wholenumber.c
 
 # Source code to the library files needed by the test fixture
index f50b31b418afd0371a0f330e3d39140a58fc050d..b9aeea334b8b02f226a6ca33124e6cdac05f43dc 100644 (file)
@@ -782,6 +782,7 @@ TESTEXT = \
   $(TOP)\ext\misc\percentile.c \
   $(TOP)\ext\misc\regexp.c \
   $(TOP)\ext\misc\spellfix.c \
+  $(TOP)\ext\misc\totype.c \
   $(TOP)\ext\misc\wholenumber.c
 
 
diff --git a/ext/misc/totype.c b/ext/misc/totype.c
new file mode 100644 (file)
index 0000000..e7288d5
--- /dev/null
@@ -0,0 +1,503 @@
+/*
+** 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 SQLITE_BIGENDIAN    0
+# define SQLITE_LITTLEENDIAN 1
+#else
+  const int totype_one = 1;
+# define SQLITE_BIGENDIAN    (*(char *)(&totype_one)==0)
+# define SQLITE_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.
+*/
+#define LARGEST_INT64  (0xffffffff|(((sqlite3_int64)0x7fffffff)<<32))
+#define SMALLEST_INT64 (((sqlite3_int64)-1) - LARGEST_INT64)
+
+/*
+** Return TRUE if character c is a whitespace character
+*/
+static int totypeIsspace(unsigned char c){
+  return c==' ' || c=='\t' || c=='\n' || 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", 1)
+**
+** 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.
+*/
+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 z[] is length bytes in length (bytes, not characters) and
+** uses the encoding enc.  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;
+}
+
+/*
+** 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 = (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( SQLITE_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 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( SQLITE_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)
+#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, 0,
+                               tointegerFunc, 0, 0);
+  if( rc==SQLITE_OK ){
+    rc = sqlite3_create_function(db, "toreal", 1, SQLITE_UTF8, 0,
+                                 torealFunc, 0, 0);
+  }
+  return rc;
+}
diff --git a/main.mk b/main.mk
index fd30019833a6c7bba53995935a17fa9b4b931c24..9eb384d9054398778d68bbe40ac279b7879ce065 100644 (file)
--- a/main.mk
+++ b/main.mk
@@ -279,6 +279,7 @@ TESTSRC += \
   $(TOP)/ext/misc/percentile.c \
   $(TOP)/ext/misc/regexp.c \
   $(TOP)/ext/misc/spellfix.c \
+  $(TOP)/ext/misc/totype.c \
   $(TOP)/ext/misc/wholenumber.c \
   $(TOP)/ext/misc/vfslog.c
 
index 811db3a0b0846aa9c3755d0d76ef288e67cdd0a0..e6ab42acd18cccd923e38f66a156e0e1efb97c1b 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,9 +1,9 @@
-C Fix\sa\scrash\sin\sFTS\sincremental\sphrase\sprocessing\sthat\scan\soccur\sif\sthe\ssecond\sor\ssubsequent\stoken\sis\smuch\smore\scommon\sin\sthe\sdataset\sthan\sthe\sfirst.
-D 2013-10-14T20:30:51.215
+C Move\sthe\stointeger()\sand\storeal()\sfunctions\sout\sof\score\sand\smake\sthem\sinto\na\srun-time\sloadable\sextension.
+D 2013-10-14T21:14:42.543
 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
-F Makefile.in e2d28ec95bd17ab4f3b6ee40b7102e9d7a0857b9
+F Makefile.in 0522b53cdc1fcfc18f3a98e0246add129136c654
 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
-F Makefile.msc d72be28ba13ec3986ac5791a6549036a84dc5903
+F Makefile.msc ec5d662ed5a15ff819928c0495017af13910d7b6
 F Makefile.vxworks db21ed42a01d5740e656b16f92cb5d8d5e5dd315
 F README cd04a36fbc7ea56932a4052d7d0b7f09f27c33d6
 F VERSION a8d1f6839521130dc73c5408cdd24bcfd791df34
@@ -115,6 +115,7 @@ F ext/misc/percentile.c bcbee3c061b884eccb80e21651daaae8e1e43c63
 F ext/misc/regexp.c af92cdaa5058fcec1451e49becc7ba44dba023dc
 F ext/misc/rot13.c 1ac6f95f99b575907b9b09c81a349114cf9be45a
 F ext/misc/spellfix.c 5e1d547e9a2aed13897fa91bac924333f62fd2d9
+F ext/misc/totype.c 368c089adfeabfe3de5fd4b8c581df53743cf6c0
 F ext/misc/vfslog.c 1abb192d8d4bd323adbddec0c024580496b51b7a
 F ext/misc/vtshim.c babb0dc2bf116029e3e7c9a618b8a1377045303e
 F ext/misc/wholenumber.c 784b12543d60702ebdd47da936e278aa03076212
@@ -140,7 +141,7 @@ F ext/rtree/viewrtree.tcl eea6224b3553599ae665b239bd827e182b466024
 F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x
 F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8
 F magic.txt 814d3de5ec227817ff2ad26cbc73159c968a2a58
-F main.mk 2e01504061f618db804812143a9e9ec45a66ae70
+F main.mk c6a433cb334bbb019625c137ab5d5e7568b47cff
 F mkdll.sh 7d09b23c05d56532e9d44a50868eb4b12ff4f74a
 F mkextu.sh 416f9b7089d80e5590a29692c9d9280a10dbad9f
 F mkextw.sh d2a981497b404d6498f5ff3e3b1f3816bdfcb338
@@ -176,7 +177,7 @@ F src/delete.c 45788c5e48734f2af4acd75a876466e5b9838e34
 F src/expr.c e7338ccffdc391c53ba2d51c5eb6a2f5299e040e
 F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb
 F src/fkey.c 5dc10cbaa355753903cd2a64da040f948997ebf8
-F src/func.c 5fb4103cc5fd2920696e0a263e6a56a2844ab35d
+F src/func.c 2c47b65e6e00e3e9374942f28254faf8adafe398
 F src/global.c 5caf4deab621abb45b4c607aad1bd21c20aac759
 F src/hash.c ac3470bbf1ca4ae4e306a8ecb0fdf1731810ffe4
 F src/hash.h 8890a25af81fb85a9ad7790d32eedab4b994da22
@@ -227,7 +228,7 @@ F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d
 F src/status.c 7ac05a5c7017d0b9f0b4bcd701228b784f987158
 F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e
 F src/tclsqlite.c 3b5f3716e320480659239abe887164521c575d83
-F src/test1.c 26226cfd2b6dc3f77d2eb27f07ffcf236b4e728b
+F src/test1.c 5757066e503a8ed51313cb3a5d9bcdcced2991a9
 F src/test2.c 7355101c085304b90024f2261e056cdff13c6c35
 F src/test3.c 1c0e5d6f080b8e33c1ce8b3078e7013fdbcd560c
 F src/test4.c 9b32d22f5f150abe23c1830e2057c4037c45b3df
@@ -569,7 +570,7 @@ F test/full.test 6b3c8fb43c6beab6b95438c1675374b95fab245d
 F test/func.test c7e80a44eebac8604397eb2ad83d0d5d9d541237
 F test/func2.test 772d66227e4e6684b86053302e2d74a2500e1e0f
 F test/func3.test dbccee9133cfef1473c59ec07b5f0262b9d72f9a
-F test/func4.test 142490571f2e7ee6c3c5a65f24cad3f8342c02a2
+F test/func4.test cb3f888a1cafad195a1f8d396875bdb11dc4faf9
 F test/fuzz-oss1.test 4912e528ec9cf2f42134456933659d371c9e0d74
 F test/fuzz.test 77fd50afc12847af50fcf1941679d90adebadde6
 F test/fuzz2.test 207d0f9d06db3eaf47a6b7bfc835b8e2fc397167
@@ -1124,7 +1125,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381
 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
 F tool/warnings.sh d1a6de74685f360ab718efda6265994b99bbea01
 F tool/win/sqlite.vsix 030f3eeaf2cb811a3692ab9c14d021a75ce41fff
-P a0f7cbc068416cf55b86056f2ce7ee505c6cc3ea
-R 5f9ee33bea159851b0bd3b4df54def2b
-U dan
-Z 1fee4cc09a93b480a53b5d3c883e606f
+P 0bf438fc30582a08fddfc3cec49366ee17ae2abe
+R ade7979aa97b3511bc21cfd9a8979ec2
+U drh
+Z 602799c8fb404ec8c5a4601c8b4e8f8d
index f84250b290b094bd0d385f84ae48744f3ca21611..a52f12edb6733beb4643d24bffae4090cca4d4d4 100644 (file)
@@ -1 +1 @@
-0bf438fc30582a08fddfc3cec49366ee17ae2abe
\ No newline at end of file
+9f66dd7e3790c04f0ab724419f5381bd21f9ebad
\ No newline at end of file
index 73b6c3bb284813ba3520346e1b15464510c1ace2..e2ab68f0303c8a03eec2377e660c864b25d75cfe 100644 (file)
@@ -965,145 +965,6 @@ static void quoteFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
   }
 }
 
-/*
-** 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 );
-  UNUSED_PARAMETER(argc);
-  switch( sqlite3_value_type(argv[0]) ){
-    case SQLITE_FLOAT: {
-      double rVal = sqlite3_value_double(argv[0]);
-      i64 iVal = (i64)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(i64) ){
-          i64 iVal;
-          if( SQLITE_BIGENDIAN ){
-            int i;
-            unsigned char *zBlobRev = contextMalloc(context, nBlob);
-            if( !zBlobRev ) break;
-            for(i=0; i<nBlob; i++) zBlobRev[i] = zBlob[nBlob-1-i];
-            memcpy(&iVal, zBlobRev, sizeof(i64));
-            sqlite3_free(zBlobRev);
-          }else{
-            memcpy(&iVal, zBlob, sizeof(i64));
-          }
-          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 && !sqlite3Isspace(zStr[0]) ){
-          i64 iVal;
-          if( !sqlite3Atoi64((const char*)zStr, &iVal, nStr, SQLITE_UTF8) ){
-            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 optimize("", off)
-#endif
-static void torealFunc(
-  sqlite3_context *context,
-  int argc,
-  sqlite3_value **argv
-){
-  assert( argc==1 );
-  UNUSED_PARAMETER(argc);
-  switch( sqlite3_value_type(argv[0]) ){
-    case SQLITE_FLOAT: {
-      sqlite3_result_double(context, sqlite3_value_double(argv[0]));
-      break;
-    }
-    case SQLITE_INTEGER: {
-      i64 iVal = sqlite3_value_int64(argv[0]);
-      double rVal = (double)iVal;
-      if( iVal==(i64)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( SQLITE_LITTLEENDIAN ){
-            int i;
-            unsigned char *zBlobRev = contextMalloc(context, nBlob);
-            if( !zBlobRev ) break;
-            for(i=0; i<nBlob; i++) zBlobRev[i] = zBlob[nBlob-1-i];
-            memcpy(&rVal, zBlobRev, sizeof(double));
-            sqlite3_free(zBlobRev);
-          }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 && !sqlite3Isspace(zStr[0]) && !sqlite3Isspace(zStr[nStr-1]) ){
-          double rVal;
-          if( sqlite3AtoF((const char*)zStr, &rVal, nStr, SQLITE_UTF8) ){
-            sqlite3_result_double(context, rVal);
-            return;
-          }
-        }
-      }
-      break;
-    }
-    default: {
-      assert( sqlite3_value_type(argv[0])==SQLITE_NULL );
-      break;
-    }
-  }
-}
-#if defined(_MSC_VER)
-#pragma optimize("", on)
-#endif
-
 /*
 ** The unicode() function.  Return the integer unicode code-point value
 ** for the first character of the input string. 
@@ -1814,8 +1675,6 @@ void sqlite3RegisterGlobalFunctions(void){
     FUNCTION(sqlite_compileoption_get, 1, 0, 0, compileoptiongetFunc  ),
 #endif /* SQLITE_OMIT_COMPILEOPTION_DIAGS */
     FUNCTION(quote,              1, 0, 0, quoteFunc        ),
-    FUNCTION(tointeger,          1, 0, 0, tointegerFunc    ),
-    FUNCTION(toreal,             1, 0, 0, torealFunc       ),
     FUNCTION(last_insert_rowid,  0, 0, 0, last_insert_rowid),
     FUNCTION(changes,            0, 0, 0, changes          ),
     FUNCTION(total_changes,      0, 0, 0, total_changes    ),
index b99efa7106eb58c6d95f09dee9fb1a5fe43b4566..d8a9e52d215059158567c4c5b6015810cb944f34 100644 (file)
@@ -6160,6 +6160,7 @@ static int tclLoadStaticExtensionCmd(
   extern int sqlite3_percentile_init(sqlite3*,char**,const sqlite3_api_routines*);
   extern int sqlite3_regexp_init(sqlite3*,char**,const sqlite3_api_routines*);
   extern int sqlite3_spellfix_init(sqlite3*,char**,const sqlite3_api_routines*);
+  extern int sqlite3_totype_init(sqlite3*,char**,const sqlite3_api_routines*);
   extern int sqlite3_wholenumber_init(sqlite3*,char**,const sqlite3_api_routines*);
   static const struct {
     const char *zExtName;
@@ -6173,6 +6174,7 @@ static int tclLoadStaticExtensionCmd(
     { "percentile",            sqlite3_percentile_init           },
     { "regexp",                sqlite3_regexp_init               },
     { "spellfix",              sqlite3_spellfix_init             },
+    { "totype",                sqlite3_totype_init               },
     { "wholenumber",           sqlite3_wholenumber_init          },
   };
   sqlite3 *db;
index 70acc655a2cac997899f0d431a6e71a216d02ee7..34a8be88400793ca117eeb3058633d6151cef6f7 100644 (file)
@@ -19,9 +19,10 @@ set testdir [file dirname $argv0]
 source $testdir/tester.tcl
 set saved_tcl_precision $tcl_precision
 set tcl_precision 0
+load_static_extension db totype
 
 set highPrecision(1) [expr \
-    {[memdbsql {SELECT tointeger(9223372036854775807 + 1);}] eq {{}}}]
+    {[db eval {SELECT tointeger(9223372036854775807 + 1);}] eq {{}}}]
 
 do_execsql_test func4-1.1 {
   SELECT tointeger(NULL);
@@ -195,7 +196,7 @@ do_execsql_test func4-1.55 {
 
 ifcapable floatingpoint {
   set highPrecision(2) [expr \
-      {[memdbsql {SELECT toreal(-9223372036854775808 + 1);}] eq {{}}}]
+      {[db eval {SELECT toreal(-9223372036854775808 + 1);}] eq {{}}}]
 
   do_execsql_test func4-2.1 {
     SELECT toreal(NULL);