Index: src/expr.c ================================================================== --- src/expr.c +++ src/expr.c @@ -2073,21 +2073,28 @@ }else{ int c; i64 value; const char *z = pExpr->u.zToken; assert( z!=0 ); - c = sqlite3Atoi64(z, &value, sqlite3Strlen30(z), SQLITE_UTF8); + c = sqlite3DecOrHexToI64(z, &value); if( c==0 || (c==2 && negFlag) ){ char *zV; if( negFlag ){ value = c==2 ? SMALLEST_INT64 : -value; } zV = dup8bytes(v, (char*)&value); sqlite3VdbeAddOp4(v, OP_Int64, 0, iMem, 0, zV, P4_INT64); }else{ #ifdef SQLITE_OMIT_FLOATING_POINT sqlite3ErrorMsg(pParse, "oversized integer: %s%s", negFlag ? "-" : "", z); #else - codeReal(v, z, negFlag, iMem); +#ifndef SQLITE_OMIT_HEX_INTEGER + if( sqlite3_strnicmp(z,"0x",2)==0 ){ + sqlite3ErrorMsg(pParse, "hex literal too big: %s", z); + }else +#endif + { + codeReal(v, z, negFlag, iMem); + } #endif } } } Index: src/main.c ================================================================== --- src/main.c +++ src/main.c @@ -3407,11 +3407,11 @@ const char *zParam, /* URI parameter sought */ sqlite3_int64 bDflt /* return if parameter is missing */ ){ const char *z = sqlite3_uri_parameter(zFilename, zParam); sqlite3_int64 v; - if( z && sqlite3Atoi64(z, &v, sqlite3Strlen30(z), SQLITE_UTF8)==SQLITE_OK ){ + if( z && sqlite3DecOrHexToI64(z, &v)==SQLITE_OK ){ bDflt = v; } return bDflt; } Index: src/pragma.c ================================================================== --- src/pragma.c +++ src/pragma.c @@ -1046,11 +1046,11 @@ */ case PragTyp_JOURNAL_SIZE_LIMIT: { Pager *pPager = sqlite3BtreePager(pDb->pBt); i64 iLimit = -2; if( zRight ){ - sqlite3Atoi64(zRight, &iLimit, sqlite3Strlen30(zRight), SQLITE_UTF8); + sqlite3DecOrHexToI64(zRight, &iLimit); if( iLimit<-1 ) iLimit = -1; } iLimit = sqlite3PagerJournalSizeLimit(pPager, iLimit); returnSingleInt(pParse, "journal_size_limit", iLimit); break; @@ -1174,11 +1174,11 @@ sqlite3_int64 sz; #if SQLITE_MAX_MMAP_SIZE>0 assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); if( zRight ){ int ii; - sqlite3Atoi64(zRight, &sz, sqlite3Strlen30(zRight), SQLITE_UTF8); + sqlite3DecOrHexToI64(zRight, &sz); if( sz<0 ) sz = sqlite3GlobalConfig.szMmap; if( pId2->n==0 ) db->szMmap = sz; for(ii=db->nDb-1; ii>=0; ii--){ if( db->aDb[ii].pBt && (ii==iDb || pId2->n==0) ){ sqlite3BtreeSetMmapLimit(db->aDb[ii].pBt, sz); @@ -2217,11 +2217,11 @@ ** Call sqlite3_soft_heap_limit64(N). Return the result. If N is omitted, ** use -1. */ case PragTyp_SOFT_HEAP_LIMIT: { sqlite3_int64 N; - if( zRight && sqlite3Atoi64(zRight, &N, 1000000, SQLITE_UTF8)==SQLITE_OK ){ + if( zRight && sqlite3DecOrHexToI64(zRight, &N)==SQLITE_OK ){ sqlite3_soft_heap_limit64(N); } returnSingleInt(pParse, "soft_heap_limit", sqlite3_soft_heap_limit64(-1)); break; } Index: src/sqliteInt.h ================================================================== --- src/sqliteInt.h +++ src/sqliteInt.h @@ -3329,10 +3329,11 @@ void sqlite3TableAffinity(Vdbe*, Table*, int); char sqlite3CompareAffinity(Expr *pExpr, char aff2); int sqlite3IndexAffinityOk(Expr *pExpr, char idx_affinity); char sqlite3ExprAffinity(Expr *pExpr); int sqlite3Atoi64(const char*, i64*, int, u8); +int sqlite3DecOrHexToI64(const char*, i64*); void sqlite3Error(sqlite3*, int, const char*,...); void *sqlite3HexToBlob(sqlite3*, const char *z, int n); u8 sqlite3HexToInt(int h); int sqlite3TwoPartName(Parse *, Token *, Token *, Token **); Index: src/tokenize.c ================================================================== --- src/tokenize.c +++ src/tokenize.c @@ -268,10 +268,16 @@ testcase( z[0]=='0' ); testcase( z[0]=='1' ); testcase( z[0]=='2' ); testcase( z[0]=='3' ); testcase( z[0]=='4' ); testcase( z[0]=='5' ); testcase( z[0]=='6' ); testcase( z[0]=='7' ); testcase( z[0]=='8' ); testcase( z[0]=='9' ); *tokenType = TK_INTEGER; +#ifndef SQLITE_OMIT_HEX_INTEGER + if( z[0]=='0' && (z[1]=='x' || z[1]=='X') && sqlite3Isxdigit(z[2]) ){ + for(i=3; sqlite3Isxdigit(z[i]); i++){} + return i; + } +#endif for(i=0; sqlite3Isdigit(z[i]); i++){} #ifndef SQLITE_OMIT_FLOATING_POINT if( z[i]=='.' ){ i++; while( sqlite3Isdigit(z[i]) ){ i++; } Index: src/util.c ================================================================== --- src/util.c +++ src/util.c @@ -473,13 +473,13 @@ testcase( c==(+1) ); } return c; } - /* -** Convert zNum to a 64-bit signed integer. +** Convert zNum to a 64-bit signed integer. zNum must be decimal. This +** routine does *not* accept hexadecimal notation. ** ** 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 9223372036854775808, return 2. This special @@ -562,14 +562,48 @@ assert( u-1==LARGEST_INT64 ); return neg ? 0 : 2; } } } + +/* +** Transform a UTF-8 integer literal, in either decimal or hexadecimal, +** into a 64-bit signed integer. This routine accepts hexadecimal literals, +** whereas sqlite3Atoi64() does not. +** +** Returns: +** +** 0 Successful transformation. Fits in a 64-bit signed integer. +** 1 Integer too large for a 64-bit signed integer or is malformed +** 2 Special case of 9223372036854775808 +*/ +int sqlite3DecOrHexToI64(const char *z, i64 *pOut){ +#ifndef SQLITE_OMIT_HEX_INTEGER + if( z[0]=='0' + && (z[1]=='x' || z[1]=='X') + && sqlite3Isxdigit(z[2]) + ){ + u64 u = 0; + int i, k; + for(i=2; z[i]=='0'; i++){} + for(k=i; sqlite3Isxdigit(z[k]); k++){ + u = u*16 + sqlite3HexToInt(z[k]); + } + memcpy(pOut, &u, 8); + return (z[k]==0 && k-i<=16) ? 0 : 1; + }else +#endif /* SQLITE_OMIT_HEX_INTEGER */ + { + return sqlite3Atoi64(z, pOut, sqlite3Strlen30(z), SQLITE_UTF8); + } +} /* ** If zNum represents an integer that will fit in 32-bits, then set ** *pValue to that integer and return true. Otherwise return false. +** +** This routine accepts both decimal and hexadecimal notation for integers. ** ** Any non-numeric characters that following zNum are ignored. ** This is different from sqlite3Atoi64() which requires the ** input number to be zero-terminated. */ @@ -581,11 +615,29 @@ neg = 1; zNum++; }else if( zNum[0]=='+' ){ zNum++; } - while( zNum[0]=='0' ) zNum++; +#ifndef SQLITE_OMIT_HEX_INTEGER + else if( zNum[0]=='0' + && (zNum[1]=='x' || zNum[1]=='X') + && sqlite3Isxdigit(zNum[2]) + ){ + u32 u = 0; + zNum += 2; + while( zNum[0]=='0' ) zNum++; + for(i=0; sqlite3Isxdigit(zNum[i]) && i<8; i++){ + u = u*16 + sqlite3HexToInt(zNum[i]); + } + if( (u&0x80000000)==0 && sqlite3Isxdigit(zNum[i])==0 ){ + memcpy(pValue, &u, 4); + return 1; + }else{ + return 0; + } + } +#endif for(i=0; i<11 && (c = zNum[i] - '0')>=0 && c<=9; i++){ v = v*10 + c; } /* The longest decimal representation of a 32 bit integer is 10 digits: ADDED test/hexlit.test Index: test/hexlit.test ================================================================== --- /dev/null +++ test/hexlit.test @@ -0,0 +1,114 @@ +# 2014-07-23 +# +# 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 file implements tests for hexadecimal literals + + +set testdir [file dirname $argv0] +source $testdir/tester.tcl + +proc hexlit1 {tnum val ans} { + do_execsql_test hexlit-$tnum "SELECT $val" $ans +} + +hexlit1 100 0x0 0 +hexlit1 101 0x0000000000000000000000000000000000000000000001 1 +hexlit1 102 0x2 2 +hexlit1 103 0x4 4 +hexlit1 104 0x8 8 +hexlit1 105 0x00000000000000000000000000000000000000000000010 16 +hexlit1 103 0x20 32 +hexlit1 106 0x40 64 +hexlit1 107 0x80 128 +hexlit1 108 0x100 256 +hexlit1 109 0x200 512 +hexlit1 110 0X400 1024 +hexlit1 111 0x800 2048 +hexlit1 112 0x1000 4096 +hexlit1 113 0x2000 8192 +hexlit1 114 0x4000 16384 +hexlit1 115 0x8000 32768 +hexlit1 116 0x10000 65536 +hexlit1 117 0x20000 131072 +hexlit1 118 0x40000 262144 +hexlit1 119 0x80000 524288 +hexlit1 120 0x100000 1048576 +hexlit1 121 0x200000 2097152 +hexlit1 122 0x400000 4194304 +hexlit1 123 0x800000 8388608 +hexlit1 124 0x1000000 16777216 +hexlit1 125 0x2000000 33554432 +hexlit1 126 0x4000000 67108864 +hexlit1 127 0x8000000 134217728 +hexlit1 128 0x10000000 268435456 +hexlit1 129 0x20000000 536870912 +hexlit1 130 0x40000000 1073741824 +hexlit1 131 0x80000000 2147483648 +hexlit1 132 0x100000000 4294967296 +hexlit1 133 0x200000000 8589934592 +hexlit1 134 0x400000000 17179869184 +hexlit1 135 0x800000000 34359738368 +hexlit1 136 0x1000000000 68719476736 +hexlit1 137 0x2000000000 137438953472 +hexlit1 138 0x4000000000 274877906944 +hexlit1 139 0x8000000000 549755813888 +hexlit1 140 0x10000000000 1099511627776 +hexlit1 141 0x20000000000 2199023255552 +hexlit1 142 0x40000000000 4398046511104 +hexlit1 143 0x80000000000 8796093022208 +hexlit1 144 0x100000000000 17592186044416 +hexlit1 145 0x200000000000 35184372088832 +hexlit1 146 0x400000000000 70368744177664 +hexlit1 147 0x800000000000 140737488355328 +hexlit1 148 0x1000000000000 281474976710656 +hexlit1 149 0x2000000000000 562949953421312 +hexlit1 150 0x4000000000000 1125899906842624 +hexlit1 151 0x8000000000000 2251799813685248 +hexlit1 152 0x10000000000000 4503599627370496 +hexlit1 153 0x20000000000000 9007199254740992 +hexlit1 154 0x40000000000000 18014398509481984 +hexlit1 155 0x80000000000000 36028797018963968 +hexlit1 156 0x100000000000000 72057594037927936 +hexlit1 157 0x200000000000000 144115188075855872 +hexlit1 158 0x400000000000000 288230376151711744 +hexlit1 159 0x800000000000000 576460752303423488 +hexlit1 160 0X1000000000000000 1152921504606846976 +hexlit1 161 0x2000000000000000 2305843009213693952 +hexlit1 162 0X4000000000000000 4611686018427387904 +hexlit1 163 0x8000000000000000 -9223372036854775808 +hexlit1 164 0XFFFFFFFFFFFFFFFF -1 + +for {set n 1} {$n < 0x10} {incr n} { + hexlit1 200.$n.1 0X[format %03X $n] $n + hexlit1 200.$n.2 0x[format %03X $n] $n + hexlit1 200.$n.3 0X[format %03x $n] $n + hexlit1 200.$n.4 0x[format %03x $n] $n +} + +# String literals that look like hex do not get cast or coerced. +# +do_execsql_test hexlit-300 { + CREATE TABLE t1(x INT, y REAL); + INSERT INTO t1 VALUES('1234','4567'),('0x1234','0x4567'); + SELECT typeof(x), x, typeof(y), y, '#' FROM t1 ORDER BY rowid; +} {integer 1234 real 4567.0 # text 0x1234 text 0x4567 #} +do_execsql_test hexlit-301 { + SELECT CAST('0x1234' AS INTEGER); +} {0} + +# Oversized hex literals are rejected +# +do_catchsql_test hexlist-400 { + SELECT 0x10000000000000000; +} {1 {hex literal too big: 0x10000000000000000}} + + +finish_test