Compare commits
33 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a1016b4275 | |||
| f8be243fef | |||
| e6d7ae24e3 | |||
| aec0aa83a9 | |||
| 24b368da8d | |||
| 4cd3a59a79 | |||
| 07d76f7b95 | |||
| 1bfe92a691 | |||
| 48114d08cf | |||
| dd8b12a6c5 | |||
| 60f41362cf | |||
| 2ddfa6a360 | |||
| ec3e57fa92 | |||
| 500ca334bd | |||
| 0b1a1e8c37 | |||
| a75011a891 | |||
| cd88a74115 | |||
| 9ea7632cca | |||
| 7f5fe1faf3 | |||
| 8fbb335d9f | |||
| 60783f47b2 | |||
| d847c73153 | |||
| 12b198f1a2 | |||
| 502c618f01 | |||
| b9561384d0 | |||
| d2b9cdd592 | |||
| cc19bed8b1 | |||
| 077efc2730 | |||
| 7f9dcd664d | |||
| d6c671e626 | |||
| d4170ac0eb | |||
| 71aac8763f | |||
| b3d7f1c2db |
@@ -348,7 +348,7 @@ Or on windows:
|
||||
> nmake /f Makefile.msc verify-source
|
||||
|
||||
Using the makefile to verify source integrity is good for detecting
|
||||
accidental changes to the source tree, but malecious changes could be
|
||||
accidental changes to the source tree, but malicious changes could be
|
||||
hidden by also modifying the makefiles.
|
||||
|
||||
## Contacts
|
||||
|
||||
+345
-96
@@ -58,41 +58,24 @@ static void decimal_free(Decimal *p){
|
||||
}
|
||||
|
||||
/*
|
||||
** Allocate a new Decimal object. Initialize it to the number given
|
||||
** by the input string.
|
||||
** Allocate a new Decimal object initialized to the text in zIn[].
|
||||
** Return NULL if any kind of error occurs.
|
||||
*/
|
||||
static Decimal *decimal_new(
|
||||
sqlite3_context *pCtx,
|
||||
sqlite3_value *pIn,
|
||||
int nAlt,
|
||||
const unsigned char *zAlt
|
||||
){
|
||||
Decimal *p;
|
||||
int n, i;
|
||||
const unsigned char *zIn;
|
||||
static Decimal *decimalNewFromText(const char *zIn, int n){
|
||||
Decimal *p = 0;
|
||||
int i;
|
||||
int iExp = 0;
|
||||
|
||||
p = sqlite3_malloc( sizeof(*p) );
|
||||
if( p==0 ) goto new_no_mem;
|
||||
if( p==0 ) goto new_from_text_failed;
|
||||
p->sign = 0;
|
||||
p->oom = 0;
|
||||
p->isInit = 1;
|
||||
p->isNull = 0;
|
||||
p->nDigit = 0;
|
||||
p->nFrac = 0;
|
||||
if( zAlt ){
|
||||
n = nAlt,
|
||||
zIn = zAlt;
|
||||
}else{
|
||||
if( sqlite3_value_type(pIn)==SQLITE_NULL ){
|
||||
p->a = 0;
|
||||
p->isNull = 1;
|
||||
return p;
|
||||
}
|
||||
n = sqlite3_value_bytes(pIn);
|
||||
zIn = sqlite3_value_text(pIn);
|
||||
}
|
||||
p->a = sqlite3_malloc64( n+1 );
|
||||
if( p->a==0 ) goto new_no_mem;
|
||||
if( p->a==0 ) goto new_from_text_failed;
|
||||
for(i=0; isspace(zIn[i]); i++){}
|
||||
if( zIn[i]=='-' ){
|
||||
p->sign = 1;
|
||||
@@ -143,7 +126,7 @@ static Decimal *decimal_new(
|
||||
}
|
||||
if( iExp>0 ){
|
||||
p->a = sqlite3_realloc64(p->a, p->nDigit + iExp + 1 );
|
||||
if( p->a==0 ) goto new_no_mem;
|
||||
if( p->a==0 ) goto new_from_text_failed;
|
||||
memset(p->a+p->nDigit, 0, iExp);
|
||||
p->nDigit += iExp;
|
||||
}
|
||||
@@ -162,7 +145,7 @@ static Decimal *decimal_new(
|
||||
}
|
||||
if( iExp>0 ){
|
||||
p->a = sqlite3_realloc64(p->a, p->nDigit + iExp + 1 );
|
||||
if( p->a==0 ) goto new_no_mem;
|
||||
if( p->a==0 ) goto new_from_text_failed;
|
||||
memmove(p->a+iExp, p->a, p->nDigit);
|
||||
memset(p->a, 0, iExp);
|
||||
p->nDigit += iExp;
|
||||
@@ -171,7 +154,76 @@ static Decimal *decimal_new(
|
||||
}
|
||||
return p;
|
||||
|
||||
new_no_mem:
|
||||
new_from_text_failed:
|
||||
if( p ){
|
||||
if( p->a ) sqlite3_free(p->a);
|
||||
sqlite3_free(p);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Forward reference */
|
||||
static Decimal *decimalFromDouble(double);
|
||||
|
||||
/*
|
||||
** Allocate a new Decimal object from an sqlite3_value. Return a pointer
|
||||
** to the new object, or NULL if there is an error. If the pCtx argument
|
||||
** is not NULL, then errors are reported on it as well.
|
||||
**
|
||||
** If the pIn argument is SQLITE_TEXT or SQLITE_INTEGER, it is converted
|
||||
** directly into a Decimal. For SQLITE_FLOAT or for SQLITE_BLOB of length
|
||||
** 8 bytes, the resulting double value is expanded into its decimal equivalent.
|
||||
** If pIn is NULL or if it is a BLOB that is not exactly 8 bytes in length,
|
||||
** then NULL is returned.
|
||||
*/
|
||||
static Decimal *decimal_new(
|
||||
sqlite3_context *pCtx, /* Report error here, if not null */
|
||||
sqlite3_value *pIn, /* Construct the decimal object from this */
|
||||
int bTextOnly /* Always interpret pIn as text if true */
|
||||
){
|
||||
Decimal *p = 0;
|
||||
int eType = sqlite3_value_type(pIn);
|
||||
if( bTextOnly && (eType==SQLITE_FLOAT || eType==SQLITE_BLOB) ){
|
||||
eType = SQLITE_TEXT;
|
||||
}
|
||||
switch( eType ){
|
||||
case SQLITE_TEXT:
|
||||
case SQLITE_INTEGER: {
|
||||
const char *zIn = (const char*)sqlite3_value_text(pIn);
|
||||
int n = sqlite3_value_bytes(pIn);
|
||||
p = decimalNewFromText(zIn, n);
|
||||
if( p==0 ) goto new_failed;
|
||||
break;
|
||||
}
|
||||
|
||||
case SQLITE_FLOAT: {
|
||||
p = decimalFromDouble(sqlite3_value_double(pIn));
|
||||
break;
|
||||
}
|
||||
|
||||
case SQLITE_BLOB: {
|
||||
const unsigned char *x;
|
||||
unsigned int i;
|
||||
sqlite3_uint64 v = 0;
|
||||
double r;
|
||||
|
||||
if( sqlite3_value_bytes(pIn)!=sizeof(r) ) break;
|
||||
x = sqlite3_value_blob(pIn);
|
||||
for(i=0; i<sizeof(r); i++){
|
||||
v = (v<<8) | x[i];
|
||||
}
|
||||
memcpy(&r, &v, sizeof(r));
|
||||
p = decimalFromDouble(r);
|
||||
break;
|
||||
}
|
||||
|
||||
case SQLITE_NULL: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return p;
|
||||
|
||||
new_failed:
|
||||
if( pCtx ) sqlite3_result_error_nomem(pCtx);
|
||||
sqlite3_free(p);
|
||||
return 0;
|
||||
@@ -231,19 +283,64 @@ static void decimal_result(sqlite3_context *pCtx, Decimal *p){
|
||||
}
|
||||
|
||||
/*
|
||||
** SQL Function: decimal(X)
|
||||
**
|
||||
** Convert input X into decimal and then back into text
|
||||
** Make the given Decimal the result in an format similar to '%+#e'.
|
||||
** In other words, show exponential notation with leading and trailing
|
||||
** zeros omitted.
|
||||
*/
|
||||
static void decimalFunc(
|
||||
sqlite3_context *context,
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
Decimal *p = decimal_new(context, argv[0], 0, 0);
|
||||
UNUSED_PARAMETER(argc);
|
||||
decimal_result(context, p);
|
||||
decimal_free(p);
|
||||
static void decimal_result_sci(sqlite3_context *pCtx, Decimal *p){
|
||||
char *z; /* The output buffer */
|
||||
int i; /* Loop counter */
|
||||
int nZero; /* Number of leading zeros */
|
||||
int nDigit; /* Number of digits not counting trailing zeros */
|
||||
int nFrac; /* Digits to the right of the decimal point */
|
||||
int exp; /* Exponent value */
|
||||
signed char zero; /* Zero value */
|
||||
signed char *a; /* Array of digits */
|
||||
|
||||
if( p==0 || p->oom ){
|
||||
sqlite3_result_error_nomem(pCtx);
|
||||
return;
|
||||
}
|
||||
if( p->isNull ){
|
||||
sqlite3_result_null(pCtx);
|
||||
return;
|
||||
}
|
||||
for(nDigit=p->nDigit; nDigit>0 && p->a[nDigit-1]==0; nDigit--){}
|
||||
for(nZero=0; nZero<nDigit && p->a[nZero]==0; nZero++){}
|
||||
nFrac = p->nFrac + (nDigit - p->nDigit);
|
||||
nDigit -= nZero;
|
||||
z = sqlite3_malloc( nDigit+20 );
|
||||
if( z==0 ){
|
||||
sqlite3_result_error_nomem(pCtx);
|
||||
return;
|
||||
}
|
||||
if( nDigit==0 ){
|
||||
zero = 0;
|
||||
a = &zero;
|
||||
nDigit = 1;
|
||||
nFrac = 0;
|
||||
}else{
|
||||
a = &p->a[nZero];
|
||||
}
|
||||
if( p->sign && nDigit>0 ){
|
||||
z[0] = '-';
|
||||
}else{
|
||||
z[0] = '+';
|
||||
}
|
||||
z[1] = a[0]+'0';
|
||||
z[2] = '.';
|
||||
if( nDigit==1 ){
|
||||
z[3] = '0';
|
||||
i = 4;
|
||||
}else{
|
||||
for(i=1; i<nDigit; i++){
|
||||
z[2+i] = a[i]+'0';
|
||||
}
|
||||
i = nDigit+2;
|
||||
}
|
||||
exp = nDigit - nFrac - 1;
|
||||
sqlite3_snprintf(nDigit+20-i, &z[i], "e%+03d", exp);
|
||||
sqlite3_result_text(pCtx, z, -1, sqlite3_free);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -296,9 +393,9 @@ static void decimalCmpFunc(
|
||||
int rc;
|
||||
|
||||
UNUSED_PARAMETER(argc);
|
||||
pA = decimal_new(context, argv[0], 0, 0);
|
||||
pA = decimal_new(context, argv[0], 1);
|
||||
if( pA==0 || pA->isNull ) goto cmp_done;
|
||||
pB = decimal_new(context, argv[1], 0, 0);
|
||||
pB = decimal_new(context, argv[1], 1);
|
||||
if( pB==0 || pB->isNull ) goto cmp_done;
|
||||
rc = decimal_cmp(pA, pB);
|
||||
if( rc<0 ) rc = -1;
|
||||
@@ -338,7 +435,7 @@ static void decimal_expand(Decimal *p, int nDigit, int nFrac){
|
||||
}
|
||||
|
||||
/*
|
||||
** Add the value pB into pA.
|
||||
** Add the value pB into pA. A := A + B.
|
||||
**
|
||||
** Both pA and pB might become denormalized by this routine.
|
||||
*/
|
||||
@@ -407,6 +504,172 @@ static void decimal_add(Decimal *pA, Decimal *pB){
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Multiply A by B. A := A * B
|
||||
**
|
||||
** All significant digits after the decimal point are retained.
|
||||
** Trailing zeros after the decimal point are omitted as long as
|
||||
** the number of digits after the decimal point is no less than
|
||||
** either the number of digits in either input.
|
||||
*/
|
||||
static void decimalMul(Decimal *pA, Decimal *pB){
|
||||
signed char *acc = 0;
|
||||
int i, j, k;
|
||||
int minFrac;
|
||||
|
||||
if( pA==0 || pA->oom || pA->isNull
|
||||
|| pB==0 || pB->oom || pB->isNull
|
||||
){
|
||||
goto mul_end;
|
||||
}
|
||||
acc = sqlite3_malloc64( pA->nDigit + pB->nDigit + 2 );
|
||||
if( acc==0 ){
|
||||
pA->oom = 1;
|
||||
goto mul_end;
|
||||
}
|
||||
memset(acc, 0, pA->nDigit + pB->nDigit + 2);
|
||||
minFrac = pA->nFrac;
|
||||
if( pB->nFrac<minFrac ) minFrac = pB->nFrac;
|
||||
for(i=pA->nDigit-1; i>=0; i--){
|
||||
signed char f = pA->a[i];
|
||||
int carry = 0, x;
|
||||
for(j=pB->nDigit-1, k=i+j+3; j>=0; j--, k--){
|
||||
x = acc[k] + f*pB->a[j] + carry;
|
||||
acc[k] = x%10;
|
||||
carry = x/10;
|
||||
}
|
||||
x = acc[k] + carry;
|
||||
acc[k] = x%10;
|
||||
acc[k-1] += x/10;
|
||||
}
|
||||
sqlite3_free(pA->a);
|
||||
pA->a = acc;
|
||||
acc = 0;
|
||||
pA->nDigit += pB->nDigit + 2;
|
||||
pA->nFrac += pB->nFrac;
|
||||
pA->sign ^= pB->sign;
|
||||
while( pA->nFrac>minFrac && pA->a[pA->nDigit-1]==0 ){
|
||||
pA->nFrac--;
|
||||
pA->nDigit--;
|
||||
}
|
||||
|
||||
mul_end:
|
||||
sqlite3_free(acc);
|
||||
}
|
||||
|
||||
/*
|
||||
** Create a new Decimal object that contains an integer power of 2.
|
||||
*/
|
||||
static Decimal *decimalPow2(int N){
|
||||
Decimal *pA = 0; /* The result to be returned */
|
||||
Decimal *pX = 0; /* Multiplier */
|
||||
if( N<-20000 || N>20000 ) goto pow2_fault;
|
||||
pA = decimalNewFromText("1.0", 3);
|
||||
if( pA==0 || pA->oom ) goto pow2_fault;
|
||||
if( N==0 ) return pA;
|
||||
if( N>0 ){
|
||||
pX = decimalNewFromText("2.0", 3);
|
||||
}else{
|
||||
N = -N;
|
||||
pX = decimalNewFromText("0.5", 3);
|
||||
}
|
||||
if( pX==0 || pX->oom ) goto pow2_fault;
|
||||
while( 1 /* Exit by break */ ){
|
||||
if( N & 1 ){
|
||||
decimalMul(pA, pX);
|
||||
if( pA->oom ) goto pow2_fault;
|
||||
}
|
||||
N >>= 1;
|
||||
if( N==0 ) break;
|
||||
decimalMul(pX, pX);
|
||||
}
|
||||
decimal_free(pX);
|
||||
return pA;
|
||||
|
||||
pow2_fault:
|
||||
decimal_free(pA);
|
||||
decimal_free(pX);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Use an IEEE754 binary64 ("double") to generate a new Decimal object.
|
||||
*/
|
||||
static Decimal *decimalFromDouble(double r){
|
||||
sqlite3_int64 m, a;
|
||||
int e;
|
||||
int isNeg;
|
||||
Decimal *pA;
|
||||
Decimal *pX;
|
||||
char zNum[100];
|
||||
if( r<0.0 ){
|
||||
isNeg = 1;
|
||||
r = -r;
|
||||
}else{
|
||||
isNeg = 0;
|
||||
}
|
||||
memcpy(&a,&r,sizeof(a));
|
||||
if( a==0 ){
|
||||
e = 0;
|
||||
m = 0;
|
||||
}else{
|
||||
e = a>>52;
|
||||
m = a & ((((sqlite3_int64)1)<<52)-1);
|
||||
if( e==0 ){
|
||||
m <<= 1;
|
||||
}else{
|
||||
m |= ((sqlite3_int64)1)<<52;
|
||||
}
|
||||
while( e<1075 && m>0 && (m&1)==0 ){
|
||||
m >>= 1;
|
||||
e++;
|
||||
}
|
||||
if( isNeg ) m = -m;
|
||||
e = e - 1075;
|
||||
if( e>971 ){
|
||||
return 0; /* A NaN or an Infinity */
|
||||
}
|
||||
}
|
||||
|
||||
/* At this point m is the integer significand and e is the exponent */
|
||||
sqlite3_snprintf(sizeof(zNum), zNum, "%lld", m);
|
||||
pA = decimalNewFromText(zNum, (int)strlen(zNum));
|
||||
pX = decimalPow2(e);
|
||||
decimalMul(pA, pX);
|
||||
decimal_free(pX);
|
||||
return pA;
|
||||
}
|
||||
|
||||
/*
|
||||
** SQL Function: decimal(X)
|
||||
** OR: decimal_sci(X)
|
||||
**
|
||||
** Convert input X into decimal and then back into text.
|
||||
**
|
||||
** If X is originally a float, then a full decimal expansion of that floating
|
||||
** point value is done. Or if X is an 8-byte blob, it is interpreted
|
||||
** as a float and similarly expanded.
|
||||
**
|
||||
** The decimal_sci(X) function returns the result in scientific notation.
|
||||
** decimal(X) returns a complete decimal, without the e+NNN at the end.
|
||||
*/
|
||||
static void decimalFunc(
|
||||
sqlite3_context *context,
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
Decimal *p = decimal_new(context, argv[0], 0);
|
||||
UNUSED_PARAMETER(argc);
|
||||
if( p ){
|
||||
if( sqlite3_user_data(context)!=0 ){
|
||||
decimal_result_sci(context, p);
|
||||
}else{
|
||||
decimal_result(context, p);
|
||||
}
|
||||
decimal_free(p);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Compare text in decimal order.
|
||||
*/
|
||||
@@ -417,8 +680,8 @@ static int decimalCollFunc(
|
||||
){
|
||||
const unsigned char *zA = (const unsigned char*)pKey1;
|
||||
const unsigned char *zB = (const unsigned char*)pKey2;
|
||||
Decimal *pA = decimal_new(0, 0, nKey1, zA);
|
||||
Decimal *pB = decimal_new(0, 0, nKey2, zB);
|
||||
Decimal *pA = decimalNewFromText((const char*)zA, nKey1);
|
||||
Decimal *pB = decimalNewFromText((const char*)zB, nKey2);
|
||||
int rc;
|
||||
UNUSED_PARAMETER(notUsed);
|
||||
if( pA==0 || pB==0 ){
|
||||
@@ -443,8 +706,8 @@ static void decimalAddFunc(
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
Decimal *pA = decimal_new(context, argv[0], 0, 0);
|
||||
Decimal *pB = decimal_new(context, argv[1], 0, 0);
|
||||
Decimal *pA = decimal_new(context, argv[0], 1);
|
||||
Decimal *pB = decimal_new(context, argv[1], 1);
|
||||
UNUSED_PARAMETER(argc);
|
||||
decimal_add(pA, pB);
|
||||
decimal_result(context, pA);
|
||||
@@ -456,8 +719,8 @@ static void decimalSubFunc(
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
Decimal *pA = decimal_new(context, argv[0], 0, 0);
|
||||
Decimal *pB = decimal_new(context, argv[1], 0, 0);
|
||||
Decimal *pA = decimal_new(context, argv[0], 1);
|
||||
Decimal *pB = decimal_new(context, argv[1], 1);
|
||||
UNUSED_PARAMETER(argc);
|
||||
if( pB ){
|
||||
pB->sign = !pB->sign;
|
||||
@@ -495,7 +758,7 @@ static void decimalSumStep(
|
||||
p->nFrac = 0;
|
||||
}
|
||||
if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return;
|
||||
pArg = decimal_new(context, argv[0], 0, 0);
|
||||
pArg = decimal_new(context, argv[0], 1);
|
||||
decimal_add(p, pArg);
|
||||
decimal_free(pArg);
|
||||
}
|
||||
@@ -510,7 +773,7 @@ static void decimalSumInverse(
|
||||
p = sqlite3_aggregate_context(context, sizeof(*p));
|
||||
if( p==0 ) return;
|
||||
if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return;
|
||||
pArg = decimal_new(context, argv[0], 0, 0);
|
||||
pArg = decimal_new(context, argv[0], 1);
|
||||
if( pArg ) pArg->sign = !pArg->sign;
|
||||
decimal_add(p, pArg);
|
||||
decimal_free(pArg);
|
||||
@@ -531,66 +794,49 @@ static void decimalSumFinalize(sqlite3_context *context){
|
||||
** SQL Function: decimal_mul(X, Y)
|
||||
**
|
||||
** Return the product of X and Y.
|
||||
**
|
||||
** All significant digits after the decimal point are retained.
|
||||
** Trailing zeros after the decimal point are omitted as long as
|
||||
** the number of digits after the decimal point is no less than
|
||||
** either the number of digits in either input.
|
||||
*/
|
||||
static void decimalMulFunc(
|
||||
sqlite3_context *context,
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
Decimal *pA = decimal_new(context, argv[0], 0, 0);
|
||||
Decimal *pB = decimal_new(context, argv[1], 0, 0);
|
||||
signed char *acc = 0;
|
||||
int i, j, k;
|
||||
int minFrac;
|
||||
Decimal *pA = decimal_new(context, argv[0], 1);
|
||||
Decimal *pB = decimal_new(context, argv[1], 1);
|
||||
UNUSED_PARAMETER(argc);
|
||||
if( pA==0 || pA->oom || pA->isNull
|
||||
|| pB==0 || pB->oom || pB->isNull
|
||||
){
|
||||
goto mul_end;
|
||||
}
|
||||
acc = sqlite3_malloc64( pA->nDigit + pB->nDigit + 2 );
|
||||
if( acc==0 ){
|
||||
sqlite3_result_error_nomem(context);
|
||||
decimalMul(pA, pB);
|
||||
if( pA->oom ){
|
||||
goto mul_end;
|
||||
}
|
||||
memset(acc, 0, pA->nDigit + pB->nDigit + 2);
|
||||
minFrac = pA->nFrac;
|
||||
if( pB->nFrac<minFrac ) minFrac = pB->nFrac;
|
||||
for(i=pA->nDigit-1; i>=0; i--){
|
||||
signed char f = pA->a[i];
|
||||
int carry = 0, x;
|
||||
for(j=pB->nDigit-1, k=i+j+3; j>=0; j--, k--){
|
||||
x = acc[k] + f*pB->a[j] + carry;
|
||||
acc[k] = x%10;
|
||||
carry = x/10;
|
||||
}
|
||||
x = acc[k] + carry;
|
||||
acc[k] = x%10;
|
||||
acc[k-1] += x/10;
|
||||
}
|
||||
sqlite3_free(pA->a);
|
||||
pA->a = acc;
|
||||
acc = 0;
|
||||
pA->nDigit += pB->nDigit + 2;
|
||||
pA->nFrac += pB->nFrac;
|
||||
pA->sign ^= pB->sign;
|
||||
while( pA->nFrac>minFrac && pA->a[pA->nDigit-1]==0 ){
|
||||
pA->nFrac--;
|
||||
pA->nDigit--;
|
||||
}
|
||||
decimal_result(context, pA);
|
||||
|
||||
mul_end:
|
||||
sqlite3_free(acc);
|
||||
decimal_free(pA);
|
||||
decimal_free(pB);
|
||||
}
|
||||
|
||||
/*
|
||||
** SQL Function: decimal_pow2(N)
|
||||
**
|
||||
** Return the N-th power of 2. N must be an integer.
|
||||
*/
|
||||
static void decimalPow2Func(
|
||||
sqlite3_context *context,
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
UNUSED_PARAMETER(argc);
|
||||
if( sqlite3_value_type(argv[0])==SQLITE_INTEGER ){
|
||||
Decimal *pA = decimalPow2(sqlite3_value_int(argv[0]));
|
||||
decimal_result_sci(context, pA);
|
||||
decimal_free(pA);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
__declspec(dllexport)
|
||||
#endif
|
||||
@@ -603,13 +849,16 @@ int sqlite3_decimal_init(
|
||||
static const struct {
|
||||
const char *zFuncName;
|
||||
int nArg;
|
||||
int iArg;
|
||||
void (*xFunc)(sqlite3_context*,int,sqlite3_value**);
|
||||
} aFunc[] = {
|
||||
{ "decimal", 1, decimalFunc },
|
||||
{ "decimal_cmp", 2, decimalCmpFunc },
|
||||
{ "decimal_add", 2, decimalAddFunc },
|
||||
{ "decimal_sub", 2, decimalSubFunc },
|
||||
{ "decimal_mul", 2, decimalMulFunc },
|
||||
{ "decimal", 1, 0, decimalFunc },
|
||||
{ "decimal_sci", 1, 1, decimalFunc },
|
||||
{ "decimal_cmp", 2, 0, decimalCmpFunc },
|
||||
{ "decimal_add", 2, 0, decimalAddFunc },
|
||||
{ "decimal_sub", 2, 0, decimalSubFunc },
|
||||
{ "decimal_mul", 2, 0, decimalMulFunc },
|
||||
{ "decimal_pow2", 1, 0, decimalPow2Func },
|
||||
};
|
||||
unsigned int i;
|
||||
(void)pzErrMsg; /* Unused parameter */
|
||||
@@ -619,7 +868,7 @@ int sqlite3_decimal_init(
|
||||
for(i=0; i<(int)(sizeof(aFunc)/sizeof(aFunc[0])) && rc==SQLITE_OK; i++){
|
||||
rc = sqlite3_create_function(db, aFunc[i].zFuncName, aFunc[i].nArg,
|
||||
SQLITE_UTF8|SQLITE_INNOCUOUS|SQLITE_DETERMINISTIC,
|
||||
0, aFunc[i].xFunc, 0, 0);
|
||||
aFunc[i].iArg ? db : 0, aFunc[i].xFunc, 0, 0);
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3_create_window_function(db, "decimal_sum", 1,
|
||||
|
||||
@@ -174,7 +174,7 @@
|
||||
globalThis.WhWasmUtilInstaller = function(target){
|
||||
'use strict';
|
||||
if(undefined===target.bigIntEnabled){
|
||||
target.bigIntEnabled = !!self['BigInt64Array'];
|
||||
target.bigIntEnabled = !!globalThis['BigInt64Array'];
|
||||
}
|
||||
|
||||
/** Throws a new Error, the message of which is the concatenation of
|
||||
@@ -355,8 +355,8 @@ globalThis.WhWasmUtilInstaller = function(target){
|
||||
break;
|
||||
default:
|
||||
if(target.bigIntEnabled){
|
||||
if(n===self['BigUint64Array']) return c.HEAP64U;
|
||||
else if(n===self['BigInt64Array']) return c.HEAP64;
|
||||
if(n===globalThis['BigUint64Array']) return c.HEAP64U;
|
||||
else if(n===globalThis['BigInt64Array']) return c.HEAP64;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,9 +60,9 @@ globalThis.Jaccwabyt = function StructBinderFactory(config){
|
||||
memberPrefix = (config.memberPrefix || ""),
|
||||
memberSuffix = (config.memberSuffix || ""),
|
||||
bigIntEnabled = (undefined===config.bigIntEnabled
|
||||
? !!self['BigInt64Array'] : !!config.bigIntEnabled),
|
||||
BigInt = self['BigInt'],
|
||||
BigInt64Array = self['BigInt64Array'],
|
||||
? !!globalThis['BigInt64Array'] : !!config.bigIntEnabled),
|
||||
BigInt = globalThis['BigInt'],
|
||||
BigInt64Array = globalThis['BigInt64Array'],
|
||||
/* Undocumented (on purpose) config options: */
|
||||
ptrSizeof = config.ptrSizeof || 4,
|
||||
ptrIR = config.ptrIR || 'i32'
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
C Add\sthe\s--pcachetrace\soption\sto\sthe\sCLI.
|
||||
D 2023-06-21T14:11:25.888
|
||||
C Improve\sthe\soutput\swhen\s".scanstats\svm"\sis\senabled.
|
||||
D 2023-07-26T16:41:23.325
|
||||
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
|
||||
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
|
||||
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
|
||||
F Makefile.in 0f4cb3955aaff8a40ec3857ba1784bd98b69802e51eff979f874b65713b627b2
|
||||
F Makefile.linux-gcc f609543700659711fbd230eced1f01353117621dccae7b9fb70daa64236c5241
|
||||
F Makefile.msc 7248d860f71ab164b4cec3c415e6cc1bd9fee860c370d65bd8bb49e9572521e2
|
||||
F README.md 8ff80689b9cb9f6e9b842edf31a3358ff53bc538c351799e03dd3e5455e637e5
|
||||
F README.md c1c4218efcc4071a6e26db2b517fdbc1035696a29b370edd655faddbef02b224
|
||||
F VERSION c6366dc72582d3144ce87b013cc35fe48d62f6d07d5be0c9716ea33c862144aa
|
||||
F aclocal.m4 a5c22d164aff7ed549d53a90fa56d56955281f50
|
||||
F art/sqlite370.eps aa97a671332b432a54e1d74ff5e8775be34200c2
|
||||
@@ -287,7 +287,7 @@ F ext/misc/completion.c 6dafd7f4348eecc7be9e920d4b419d1fb2af75d938cd9c59a20cfe8b
|
||||
F ext/misc/compress.c 3354c77a7c8e86e07d849916000cdac451ed96500bfb5bd83b20eb61eee012c9
|
||||
F ext/misc/csv.c ca8d6dafc5469639de81937cb66ae2e6b358542aba94c4f791910d355a8e7f73
|
||||
F ext/misc/dbdump.c b8592f6f2da292c62991a13864a60d6c573c47a9cc58362131b9e6a64f823e01
|
||||
F ext/misc/decimal.c 57d85fa20a5a74d3b0dfc78ab7934ae6c9f5aa8eed915faa2b5246bec87ddc6d
|
||||
F ext/misc/decimal.c a61343b36672760e1d6d5b20a42cb52264db55bcd11d0a44e2e06e8ce23227e3
|
||||
F ext/misc/eval.c 04bc9aada78c888394204b4ed996ab834b99726fb59603b0ee3ed6e049755dc1
|
||||
F ext/misc/explain.c 0086fab288d4352ea638cf40ac382aad3b0dc5e845a1ea829a694c015fd970fe
|
||||
F ext/misc/fileio.c 4e7f7cd30de8df4820c552f14af3c9ca451c5ffe1f2e7bef34d598a12ebfb720
|
||||
@@ -513,7 +513,7 @@ F ext/wasm/c-pp.c 6d80d8569d85713effe8b0818a3cf51dc779e3f0bf8dc88771b8998552ee25
|
||||
F ext/wasm/common/SqliteTestUtil.js 7adaeffef757d8708418dc9190f72df22367b531831775804b31598b44f6aa51
|
||||
F ext/wasm/common/emscripten.css 11bd104b6c0d597c67d40cc8ecc0a60dae2b965151e3b6a37fa5708bac3acd15
|
||||
F ext/wasm/common/testing.css 0ff15602a3ab2bad8aef2c3bd120c7ee3fd1c2054ad2ace7e214187ae68d926f
|
||||
F ext/wasm/common/whwasmutil.js 749a1f81f85835e9a384e9706f2a955a7158f2b8cc9da33f41105cac7775a305
|
||||
F ext/wasm/common/whwasmutil.js 03407d7b61b817fd135c82401987e56688a45ee4d6b9c0eced160c0000d6e4c2
|
||||
F ext/wasm/demo-123-worker.html a0b58d9caef098a626a1a1db567076fca4245e8d60ba94557ede8684350a81ed
|
||||
F ext/wasm/demo-123.html 8c70a412ce386bd3796534257935eb1e3ea5c581e5d5aea0490b8232e570a508
|
||||
F ext/wasm/demo-123.js ebae30756585bca655b4ab2553ec9236a87c23ad24fc8652115dcedb06d28df6
|
||||
@@ -532,7 +532,7 @@ F ext/wasm/fiddle/fiddle.js 974b995119ac443685d7d94d3b3c58c6a36540e9eb3fed7069d5
|
||||
F ext/wasm/fiddle/index.html 5daf54e8f3d7777cbb1ca4f93affe28858dbfff25841cb4ab81d694efed28ec2
|
||||
F ext/wasm/index-dist.html 22379774f0ad4edcaaa8cf9c674c82e794cc557719a8addabed74eb8069d412e
|
||||
F ext/wasm/index.html dd900891844caebd9cadbddd704f66bd841d7c12fd69ce5af490e2c10fb49f45
|
||||
F ext/wasm/jaccwabyt/jaccwabyt.js 8287c0537fa0750414edbe75ce64668a81c8716df5ec4c3e6bb4f11bd1c36031
|
||||
F ext/wasm/jaccwabyt/jaccwabyt.js 1264710db3cfbcb6887d95665b7aeba60c1126eaef789ca4cf1a4a17d5bc7f54
|
||||
F ext/wasm/jaccwabyt/jaccwabyt.md 37911f00db12cbcca73aa1ed72594430365f30aafae2fa9c886961de74e5e0eb
|
||||
F ext/wasm/module-symbols.html 841de62fc198988b8330e238c260e70ec93028b096e1a1234db31b187a899d10
|
||||
F ext/wasm/scratchpad-wasmfs-main.html 20cf6f1a8f368e70d01e8c17200e3eaa90f1c8e1029186d836d14b83845fbe06
|
||||
@@ -576,7 +576,7 @@ F src/auth.c 19b7ccacae3dfba23fc6f1d0af68134fa216e9040e53b0681b4715445ea030b4
|
||||
F src/backup.c 5c97e8023aab1ce14a42387eb3ae00ba5a0644569e3476f38661fa6f824c3523
|
||||
F src/bitvec.c 9eac5f42c11914d5ef00a75605bb205e934f435c579687f985f1f8b0995c8645
|
||||
F src/btmutex.c 79a43670447eacc651519a429f6ece9fd638563cf95b469d6891185ddae2b522
|
||||
F src/btree.c 481666a3dd26b1cb16a9e9baaa3f6b17cab52a1d7a5836e5dcf5b45b85d4a51d
|
||||
F src/btree.c c0c93b6cb4dc133b528c1290bb4ad0f2414452f9a5758ff2b106af718874f39e
|
||||
F src/btree.h aa354b9bad4120af71e214666b35132712b8f2ec11869cb2315c52c81fad45cc
|
||||
F src/btreeInt.h 3b4eff7155c0cea6971dc51f62e3529934a15a6640ec607dd42a767e379cb3a9
|
||||
F src/build.c a8ae3b32d9aa9bbd2c0e97d7c0dd80def9fbca408425de1608f57ee6f47f45f4
|
||||
@@ -587,10 +587,10 @@ F src/date.c f73f203b3877cef866c60ab402aec2bf89597219b60635cf50cbe3c5e4533e94
|
||||
F src/dbpage.c f3eea5f7ec47e09ee7da40f42b25092ecbe961fc59566b8e5f705f34335b2387
|
||||
F src/dbstat.c ec92074baa61d883de58c945162d9e666c13cd7cf3a23bc38b4d1c4d0b2c2bef
|
||||
F src/delete.c cd5f5cd06ed0b6a882ec1a8c2a0d73b3cecb28479ad19e9931c4706c5e2182be
|
||||
F src/expr.c 36f6a47c8a2c20ec3c267a60fc598857876edd60af0cb40caf7b69b651fd73bf
|
||||
F src/expr.c 8d1656b65e26af3e34f78e947ac423f0d20c214ed25a67486e433bf16ca6b543
|
||||
F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007
|
||||
F src/fkey.c a7fcbf7e66d14dbb73cf49f31489ebf66d0e6006c62b95246924a3bae9f37b36
|
||||
F src/func.c 6303e1ccb80dbd0d9b52f902a01d3b105981486fdfd66f9e1ddfd74aaf3032fc
|
||||
F src/func.c 6b4804738b4d869f40625958b476a8f964d3df65b626e72a530d76051863cf32
|
||||
F src/global.c bd0892ade7289f6e20bff44c07d06371f2ff9b53cea359e7854b9b72f65adc30
|
||||
F src/hash.c 9ee4269fb1d6632a6fecfb9479c93a1f29271bddbbaf215dd60420bcb80c7220
|
||||
F src/hash.h 3340ab6e1d13e725571d7cee6d3e3135f0779a7d8e76a9ce0a85971fa3953c51
|
||||
@@ -633,21 +633,21 @@ F src/pcache1.c 602acb23c471bb8d557a6f0083cc2be641d6cafcafa19e481eba7ef4c9ca0f00
|
||||
F src/pragma.c 37b8fb02d090262280c86e1e2654bf59d8dbfbfe8dc6733f2b968a11374c095a
|
||||
F src/pragma.h e690a356c18e98414d2e870ea791c1be1545a714ba623719deb63f7f226d8bb7
|
||||
F src/prepare.c d6c4354f8ea0dc06962fbabc4b68c4471a45276a2918c929be00f9f537f69eb1
|
||||
F src/printf.c b9320cdbeca0b336c3f139fd36dd121e4167dd62b35fbe9ccaa9bab44c0af38d
|
||||
F src/printf.c a87473be34fa2acafa27692b8ae078275c7e23360956c93c07ff22f5d609cbd7
|
||||
F src/random.c 606b00941a1d7dd09c381d3279a058d771f406c5213c9932bbd93d5587be4b9c
|
||||
F src/resolve.c 37953a5f36c60bea413c3c04efcd433b6177009f508ef2ace0494728912fe2e9
|
||||
F src/rowset.c 8432130e6c344b3401a8874c3cb49fefe6873fec593294de077afea2dce5ec97
|
||||
F src/select.c 383b9dba12493c365ee2036bcadd73013b7c0f7d2afcda0c378317c335d60ac2
|
||||
F src/shell.c.in bdd1fdfc77a67651cdc5a158bc9107cf3c2cf3ddb62d7a4da06c6eaaa5e72037
|
||||
F src/select.c 3ab1186290a311a8ceed1286c0e286209f7fe97b2d02c7593258004ce295dd88
|
||||
F src/shell.c.in 921831fe4acca388f66472f6e4076c4531edf17b1b0a64d85843606f339d00d3
|
||||
F src/sqlite.h.in 3076d78836b6dac53b3ab0875fc8fd15bca8077aad4d33c85336e05af6aef8c7
|
||||
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
|
||||
F src/sqlite3ext.h da473ce2b3d0ae407a6300c4a164589b9a6bfdbec9462688a8593ff16f3bb6e4
|
||||
F src/sqliteInt.h 8974b60740b108269f51e833e85191be6bf9f06f317ee34a53b7ec215762cf8c
|
||||
F src/sqliteInt.h b677ba33397479f9a2fa1223fcd24b561cc8c77c7d073798f7b7118e15d69dbb
|
||||
F src/sqliteLimit.h 33b1c9baba578d34efe7dfdb43193b366111cdf41476b1e82699e14c11ee1fb6
|
||||
F src/status.c 160c445d7d28c984a0eae38c144f6419311ed3eace59b44ac6dafc20db4af749
|
||||
F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1
|
||||
F src/tclsqlite.c ecbc3c99c0d0c3ed122a913f143026c26d38d57f33e06bb71185dd5c1efe37cd
|
||||
F src/test1.c e6ab4a00671f052366a01bcb7fdf2e2f6bb4aa884cd01e738c5590dcf47a99ca
|
||||
F src/test1.c 64b8462099618a6243f63ba701eea8913046cd7377a7a77a7e3a0ada42219275
|
||||
F src/test2.c 827446e259a3b7ab949da1542953edda7b5117982576d3e6f1c24a0dd20a5cef
|
||||
F src/test3.c e5178558c41ff53236ae0271e9acb3d6885a94981d2eb939536ee6474598840e
|
||||
F src/test4.c 4533b76419e7feb41b40582554663ed3cd77aaa54e135cf76b3205098cd6e664
|
||||
@@ -705,18 +705,18 @@ F src/trigger.c ad6ab9452715fa9a8075442e15196022275b414b9141b566af8cdb7a1605f2b0
|
||||
F src/update.c 0aa36561167a7c40d01163238c297297962f31a15a8d742216b3c37cdf25f731
|
||||
F src/upsert.c 5303dc6c518fa7d4b280ec65170f465c7a70b7ac2b22491598f6d0b4875b3145
|
||||
F src/utf.c ee39565f0843775cc2c81135751ddd93eceb91a673ea2c57f61c76f288b041a0
|
||||
F src/util.c 6f9d2f278dcc8d41c618980cd3cfe88e1bafc0626209b917c6773d8202d29ef6
|
||||
F src/util.c 4264102045fdb36e9af3ff361e390a5f7a76342a2bd7069e55d8ad332026d6b5
|
||||
F src/vacuum.c 604fcdaebe76f3497c855afcbf91b8fa5046b32de3045bab89cc008d68e40104
|
||||
F src/vdbe.c 6c0de640ef3be08cf2992d588a7501aee0f1003027bc952a6916a35f6e33b4cf
|
||||
F src/vdbe.c 74282a947234513872a83b0bab1b8c644ece64b3e27b053ef17677c8ff9c81e0
|
||||
F src/vdbe.h 41485521f68e9437fdb7ec4a90f9d86ab294e9bb8281e33b235915e29122cfc0
|
||||
F src/vdbeInt.h 7bd49eef8f89c1a271fbf12d80a206bf56c876814c5fc6bee340f4e1907095ae
|
||||
F src/vdbeapi.c de9703f8705afc393cc2864669ce28cf9516983c8331d59aa2b978de01634365
|
||||
F src/vdbeaux.c 4d5e68a3850d0b193a692eca6442d7afe35252aaf29728a67adcb542ecabd9ce
|
||||
F src/vdbeaux.c b5e3f7e158518b4eca6f166ac43900640a3fe9735c710e12bfa119af21059339
|
||||
F src/vdbeblob.c 2516697b3ee8154eb8915f29466fb5d4f1ae39ee8b755ea909cefaf57ec5e2ce
|
||||
F src/vdbemem.c 710119a8e35e47813681c48703d65a80ba22792192de90bc51dc0d6366f2a79e
|
||||
F src/vdbemem.c aed58a560caab12540f7c14c43ee188636017814e21247a97902f78de2d43117
|
||||
F src/vdbesort.c 0d40dca073c94e158ead752ef4225f4fee22dee84145e8c00ca2309afb489015
|
||||
F src/vdbetrace.c fe0bc29ebd4e02c8bc5c1945f1d2e6be5927ec12c06d89b03ef2a4def34bf823
|
||||
F src/vdbevtab.c aae4bd769410eb7e1d02c42613eec961d514459b1c3c1c63cfc84e92a137daac
|
||||
F src/vdbevtab.c 57fa8f56478e5b5cb558cb425e7878515e0a105c54f96f1d1bbf4b9433529254
|
||||
F src/vtab.c 1ecf8c3745d29275688d583e12822fa984d421e0286b5ef50c137bc3bf6d7a64
|
||||
F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9
|
||||
F src/wal.c cbfeeb7415baa545efa244dd34bb5af4ae953a206fed720c6fa7f1ef763ec122
|
||||
@@ -724,7 +724,7 @@ F src/wal.h c3aa7825bfa2fe0d85bef2db94655f99870a285778baa36307c0a16da32b226a
|
||||
F src/walker.c 7c7ea0115345851c3da4e04e2e239a29983b61fb5b038b94eede6aba462640e2
|
||||
F src/where.c 2dc708cf8b6a691fb79f16bbc46567497ee6f991043318d421e294b2da114d93
|
||||
F src/whereInt.h c7d19902863beadec1d04e66aca39c0bcd60b74f05f0eaa7422c7005dfc5d51a
|
||||
F src/wherecode.c bff0bc56cb1a382de266c2db3a691135c18a4360b6ad5e069e5c415d57eb0c38
|
||||
F src/wherecode.c 5d77db30a2a3dd532492ae882de114edba2fae672622056b1c7fd61f5917a8f1
|
||||
F src/whereexpr.c dc5096eca5ed503999be3bdee8a90c51361289a678d396a220912e9cb73b3c00
|
||||
F src/window.c b7ad9cff3ce8ae6f8cc25e18e1a258426cb6bd2999aace6f5248d781b2a74098
|
||||
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
|
||||
@@ -939,7 +939,7 @@ F test/dbpage.test fce29035c7566fd7835ec0f19422cb4b9c6944ce0e1b936ff8452443f92e8
|
||||
F test/dbpagefault.test d9111a62f3601d3efc6841ace3940181937342d245f92a1cca6cba8206d4f58a
|
||||
F test/dbstatus.test 4a4221a883025ffd39696b3d1b3910b928fb097d77e671351acb35f3aed42759
|
||||
F test/dbstatus2.test f5fe0afed3fa45e57cfa70d1147606c20d2ba23feac78e9a172f2fe8ab5b78ef
|
||||
F test/decimal.test fcf403fd5585f47342234e153c4a4338cd737b8e0884ac66fc484df47dbcf1a7
|
||||
F test/decimal.test 18e7b4cb12e8d5c60d768b686ba52af3e1ca3ced4f870231f0476666fd9fab7e
|
||||
F test/default.test 9687cfb16717e4b8238c191697c98be88c0b16e568dd5368cd9284154097ef50
|
||||
F test/delete.test 2686e1c98d552ef37d79ad55b17b93fe96fad9737786917ce3839767f734c48f
|
||||
F test/delete2.test 3a03f2cca1f9a67ec469915cb8babd6485db43fa
|
||||
@@ -1107,7 +1107,7 @@ F test/fts4umlaut.test fcaca4471de7e78c9d1f7e8976e3e8704d7d8ad979d57a739d00f3f75
|
||||
F test/fts4unicode.test 82a9c16b68ba2f358a856226bb2ee02f81583797bc4744061c54401bf1a0f4c9
|
||||
F test/fts4upfrom.test f25835162c989dffd5e2ef91ec24c4848cc9973093e2d492d1c7b32afac1b49d
|
||||
F test/full.test 6b3c8fb43c6beab6b95438c1675374b95fab245d
|
||||
F test/func.test 4be8bed4be235e333f1e0ea31e32f5be3c9f456c30780363e7fcb15e3ff3e6bc
|
||||
F test/func.test f246a12169d1b0dbebcf70bb4ad0324b12e8fdbfbbbcc1c92379c7088014c602
|
||||
F test/func2.test 772d66227e4e6684b86053302e2d74a2500e1e0f
|
||||
F test/func3.test 600a632c305a88f3946d38f9a51efe145c989b2e13bd2b2a488db47fe76bab6a
|
||||
F test/func4.test 2285fb5792d593fef442358763f0fd9de806eda47dbc7a5934df57ffdc484c31
|
||||
@@ -1425,7 +1425,7 @@ F test/savepoint6.test f41279c5e137139fa5c21485773332c7adb98cd7
|
||||
F test/savepoint7.test cde525ea3075283eb950cdcdefe23ead4f700daa
|
||||
F test/savepointfault.test f044eac64b59f09746c7020ee261734de82bf9b2
|
||||
F test/scanstatus.test b249328caf4d317e71058006872b8012598a5fa045b30bf24a81eeff650ab49e
|
||||
F test/scanstatus2.test 9a00becb1d60d168944f8e2f3585d44d46123aa95c5c7c25563309e1f15f924d
|
||||
F test/scanstatus2.test d0434bc3b356fb9d948f3417846b2ed5bbc4bd4cc49bddb38ac86469f754bfb0
|
||||
F test/schema.test 5dd11c96ba64744de955315d2e4f8992e447533690153b93377dffb2a5ef5431
|
||||
F test/schema2.test 906408621ea881fdb496d878b1822572a34e32c5
|
||||
F test/schema3.test 8ed4ae66e082cdd8b1b1f22d8549e1e7a0db4527a8e6ee8b6193053ee1e5c9ce
|
||||
@@ -1469,7 +1469,7 @@ F test/sharedB.test 1a84863d7a2204e0d42f2e1606577c5e92e4473fa37ea0f5bdf829e4bf8e
|
||||
F test/shared_err.test 32634e404a3317eeb94abc7a099c556a346fdb8fb3858dbe222a4cbb8926a939
|
||||
F test/sharedlock.test 5ede3c37439067c43b0198f580fd374ebf15d304
|
||||
F test/shell1.test 300b77328aaafb9f3e7a53a26e4162fbf92181d92251d259ff105a2275ff998d
|
||||
F test/shell2.test 09a202f57e7cd99788537f763e0845796a173fcea06a0d199a08d69446fe1daf
|
||||
F test/shell2.test 35226c070a8c7f64fd016dfac2a0db2a40f709b3131f61daacd9dad61536c9cb
|
||||
F test/shell3.test 91febeac0412812bf6370abb8ed72700e32bf8f9878849414518f662dfd55e8a
|
||||
F test/shell4.test 9abd0c12a7e20a4c49e84d5be208d2124fa6c09e728f56f1f4bee0f02853935f
|
||||
F test/shell5.test c8b6c54f26ec537f8558273d7ed293ca3725ef42e6b12b8f151718628bd1473b
|
||||
@@ -2041,8 +2041,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
|
||||
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
|
||||
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
|
||||
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
|
||||
P f94f3021cde1d46373ee8fc8e5028d7507a937240c59cf0d0d19ab22acbd3c41
|
||||
R d23fbd106a98c76f065fa8c0590bcfbb
|
||||
U drh
|
||||
Z 6142bb2a618d1d23b62eb525e555db78
|
||||
P e727640fb5c17d23b8e27972065b4acbf169c9240298d3ff7aed092b727d052d
|
||||
R cd10daa978b5e0a84d84b4bb41300995
|
||||
U dan
|
||||
Z 2a26d9e4014ba821912c8a2a17121583
|
||||
# Remove this line to create a well-formed Fossil manifest.
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
61dfa92b44ad38a7aac76a09e167819ce5d0acace3e06ba9ed17b3264cc043c1
|
||||
7df08fd35e9d4bc471aa9fbc4c81d2ebcfd2be6c4c38143342b3d9d727c9df22
|
||||
+59
-50
@@ -2318,68 +2318,41 @@ Pgno sqlite3BtreeLastPage(Btree *p){
|
||||
|
||||
/*
|
||||
** Get a page from the pager and initialize it.
|
||||
**
|
||||
** If pCur!=0 then the page is being fetched as part of a moveToChild()
|
||||
** call. Do additional sanity checking on the page in this case.
|
||||
** And if the fetch fails, this routine must decrement pCur->iPage.
|
||||
**
|
||||
** The page is fetched as read-write unless pCur is not NULL and is
|
||||
** a read-only cursor.
|
||||
**
|
||||
** If an error occurs, then *ppPage is undefined. It
|
||||
** may remain unchanged, or it may be set to an invalid value.
|
||||
*/
|
||||
static int getAndInitPage(
|
||||
BtShared *pBt, /* The database file */
|
||||
Pgno pgno, /* Number of the page to get */
|
||||
MemPage **ppPage, /* Write the page pointer here */
|
||||
BtCursor *pCur, /* Cursor to receive the page, or NULL */
|
||||
int bReadOnly /* True for a read-only page */
|
||||
){
|
||||
int rc;
|
||||
DbPage *pDbPage;
|
||||
MemPage *pPage;
|
||||
assert( sqlite3_mutex_held(pBt->mutex) );
|
||||
assert( pCur==0 || ppPage==&pCur->pPage );
|
||||
assert( pCur==0 || bReadOnly==pCur->curPagerFlags );
|
||||
assert( pCur==0 || pCur->iPage>0 );
|
||||
|
||||
if( pgno>btreePagecount(pBt) ){
|
||||
rc = SQLITE_CORRUPT_BKPT;
|
||||
goto getAndInitPage_error1;
|
||||
*ppPage = 0;
|
||||
return SQLITE_CORRUPT_BKPT;
|
||||
}
|
||||
rc = sqlite3PagerGet(pBt->pPager, pgno, (DbPage**)&pDbPage, bReadOnly);
|
||||
if( rc ){
|
||||
goto getAndInitPage_error1;
|
||||
*ppPage = 0;
|
||||
return rc;
|
||||
}
|
||||
*ppPage = (MemPage*)sqlite3PagerGetExtra(pDbPage);
|
||||
if( (*ppPage)->isInit==0 ){
|
||||
pPage = (MemPage*)sqlite3PagerGetExtra(pDbPage);
|
||||
if( pPage->isInit==0 ){
|
||||
btreePageFromDbPage(pDbPage, pgno, pBt);
|
||||
rc = btreeInitPage(*ppPage);
|
||||
rc = btreeInitPage(pPage);
|
||||
if( rc!=SQLITE_OK ){
|
||||
goto getAndInitPage_error2;
|
||||
releasePage(pPage);
|
||||
*ppPage = 0;
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
assert( (*ppPage)->pgno==pgno || CORRUPT_DB );
|
||||
assert( (*ppPage)->aData==sqlite3PagerGetData(pDbPage) );
|
||||
|
||||
/* If obtaining a child page for a cursor, we must verify that the page is
|
||||
** compatible with the root page. */
|
||||
if( pCur && ((*ppPage)->nCell<1 || (*ppPage)->intKey!=pCur->curIntKey) ){
|
||||
rc = SQLITE_CORRUPT_PGNO(pgno);
|
||||
goto getAndInitPage_error2;
|
||||
}
|
||||
assert( pPage->pgno==pgno || CORRUPT_DB );
|
||||
assert( pPage->aData==sqlite3PagerGetData(pDbPage) );
|
||||
*ppPage = pPage;
|
||||
return SQLITE_OK;
|
||||
|
||||
getAndInitPage_error2:
|
||||
releasePage(*ppPage);
|
||||
getAndInitPage_error1:
|
||||
if( pCur ){
|
||||
pCur->iPage--;
|
||||
pCur->pPage = pCur->apPage[pCur->iPage];
|
||||
}
|
||||
testcase( pgno==0 );
|
||||
assert( pgno!=0 || rc!=SQLITE_OK );
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -5353,6 +5326,7 @@ const void *sqlite3BtreePayloadFetch(BtCursor *pCur, u32 *pAmt){
|
||||
** vice-versa).
|
||||
*/
|
||||
static int moveToChild(BtCursor *pCur, u32 newPgno){
|
||||
int rc;
|
||||
assert( cursorOwnsBtShared(pCur) );
|
||||
assert( pCur->eState==CURSOR_VALID );
|
||||
assert( pCur->iPage<BTCURSOR_MAX_DEPTH );
|
||||
@@ -5366,8 +5340,17 @@ static int moveToChild(BtCursor *pCur, u32 newPgno){
|
||||
pCur->apPage[pCur->iPage] = pCur->pPage;
|
||||
pCur->ix = 0;
|
||||
pCur->iPage++;
|
||||
return getAndInitPage(pCur->pBt, newPgno, &pCur->pPage, pCur,
|
||||
pCur->curPagerFlags);
|
||||
rc = getAndInitPage(pCur->pBt, newPgno, &pCur->pPage, pCur->curPagerFlags);
|
||||
if( rc==SQLITE_OK
|
||||
&& (pCur->pPage->nCell<1 || pCur->pPage->intKey!=pCur->curIntKey)
|
||||
){
|
||||
releasePage(pCur->pPage);
|
||||
rc = SQLITE_CORRUPT_PGNO(newPgno);
|
||||
}
|
||||
if( rc ){
|
||||
pCur->pPage = pCur->apPage[--pCur->iPage];
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
#ifdef SQLITE_DEBUG
|
||||
@@ -5474,7 +5457,7 @@ static int moveToRoot(BtCursor *pCur){
|
||||
sqlite3BtreeClearCursor(pCur);
|
||||
}
|
||||
rc = getAndInitPage(pCur->pBt, pCur->pgnoRoot, &pCur->pPage,
|
||||
0, pCur->curPagerFlags);
|
||||
pCur->curPagerFlags);
|
||||
if( rc!=SQLITE_OK ){
|
||||
pCur->eState = CURSOR_INVALID;
|
||||
return rc;
|
||||
@@ -6087,10 +6070,36 @@ bypass_moveto_root:
|
||||
}else{
|
||||
chldPg = get4byte(findCell(pPage, lwr));
|
||||
}
|
||||
pCur->ix = (u16)lwr;
|
||||
rc = moveToChild(pCur, chldPg);
|
||||
if( rc ) break;
|
||||
}
|
||||
|
||||
/* This block is similar to an in-lined version of:
|
||||
**
|
||||
** pCur->ix = (u16)lwr;
|
||||
** rc = moveToChild(pCur, chldPg);
|
||||
** if( rc ) break;
|
||||
*/
|
||||
pCur->info.nSize = 0;
|
||||
pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl);
|
||||
if( pCur->iPage>=(BTCURSOR_MAX_DEPTH-1) ){
|
||||
return SQLITE_CORRUPT_BKPT;
|
||||
}
|
||||
pCur->aiIdx[pCur->iPage] = (u16)lwr;
|
||||
pCur->apPage[pCur->iPage] = pCur->pPage;
|
||||
pCur->ix = 0;
|
||||
pCur->iPage++;
|
||||
rc = getAndInitPage(pCur->pBt, chldPg, &pCur->pPage, pCur->curPagerFlags);
|
||||
if( rc==SQLITE_OK
|
||||
&& (pCur->pPage->nCell<1 || pCur->pPage->intKey!=pCur->curIntKey)
|
||||
){
|
||||
releasePage(pCur->pPage);
|
||||
rc = SQLITE_CORRUPT_PGNO(chldPg);
|
||||
}
|
||||
if( rc ){
|
||||
pCur->pPage = pCur->apPage[--pCur->iPage];
|
||||
break;
|
||||
}
|
||||
/*
|
||||
***** End of in-lined moveToChild() call */
|
||||
}
|
||||
moveto_index_finish:
|
||||
pCur->info.nSize = 0;
|
||||
assert( (pCur->curFlags & BTCF_ValidOvfl)==0 );
|
||||
@@ -8144,7 +8153,7 @@ static int balance_nonroot(
|
||||
pgno = get4byte(pRight);
|
||||
while( 1 ){
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = getAndInitPage(pBt, pgno, &apOld[i], 0, 0);
|
||||
rc = getAndInitPage(pBt, pgno, &apOld[i], 0);
|
||||
}
|
||||
if( rc ){
|
||||
memset(apOld, 0, (i+1)*sizeof(MemPage*));
|
||||
@@ -10029,7 +10038,7 @@ static int clearDatabasePage(
|
||||
if( pgno>btreePagecount(pBt) ){
|
||||
return SQLITE_CORRUPT_BKPT;
|
||||
}
|
||||
rc = getAndInitPage(pBt, pgno, &pPage, 0, 0);
|
||||
rc = getAndInitPage(pBt, pgno, &pPage, 0);
|
||||
if( rc ) return rc;
|
||||
if( (pBt->openFlags & BTREE_SINGLE)==0
|
||||
&& sqlite3PagerPageRefcount(pPage->pDbPage) != (1 + (pgno==1))
|
||||
|
||||
+9
-6
@@ -4668,10 +4668,10 @@ expr_code_doover:
|
||||
r1 = sqlite3GetTempRange(pParse, nFarg);
|
||||
}
|
||||
|
||||
/* For length() and typeof() functions with a column argument,
|
||||
/* For length() and typeof() and octet_length() functions,
|
||||
** set the P5 parameter to the OP_Column opcode to OPFLAG_LENGTHARG
|
||||
** or OPFLAG_TYPEOFARG respectively, to avoid unnecessary data
|
||||
** loading.
|
||||
** or OPFLAG_TYPEOFARG or OPFLAG_BYTELENARG respectively, to avoid
|
||||
** unnecessary data loading.
|
||||
*/
|
||||
if( (pDef->funcFlags & (SQLITE_FUNC_LENGTH|SQLITE_FUNC_TYPEOF))!=0 ){
|
||||
u8 exprOp;
|
||||
@@ -4681,9 +4681,12 @@ expr_code_doover:
|
||||
if( exprOp==TK_COLUMN || exprOp==TK_AGG_COLUMN ){
|
||||
assert( SQLITE_FUNC_LENGTH==OPFLAG_LENGTHARG );
|
||||
assert( SQLITE_FUNC_TYPEOF==OPFLAG_TYPEOFARG );
|
||||
testcase( pDef->funcFlags & OPFLAG_LENGTHARG );
|
||||
pFarg->a[0].pExpr->op2 =
|
||||
pDef->funcFlags & (OPFLAG_LENGTHARG|OPFLAG_TYPEOFARG);
|
||||
assert( SQLITE_FUNC_BYTELEN==OPFLAG_BYTELENARG );
|
||||
assert( (OPFLAG_LENGTHARG|OPFLAG_TYPEOFARG)==OPFLAG_BYTELENARG );
|
||||
testcase( (pDef->funcFlags & OPFLAG_BYTELENARG)==OPFLAG_LENGTHARG );
|
||||
testcase( (pDef->funcFlags & OPFLAG_BYTELENARG)==OPFLAG_TYPEOFARG );
|
||||
testcase( (pDef->funcFlags & OPFLAG_BYTELENARG)==OPFLAG_BYTELENARG);
|
||||
pFarg->a[0].pExpr->op2 = pDef->funcFlags & OPFLAG_BYTELENARG;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+83
-23
@@ -149,6 +149,42 @@ static void lengthFunc(
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Implementation of the octet_length() function
|
||||
*/
|
||||
static void bytelengthFunc(
|
||||
sqlite3_context *context,
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
assert( argc==1 );
|
||||
UNUSED_PARAMETER(argc);
|
||||
switch( sqlite3_value_type(argv[0]) ){
|
||||
case SQLITE_BLOB: {
|
||||
sqlite3_result_int(context, sqlite3_value_bytes(argv[0]));
|
||||
break;
|
||||
}
|
||||
case SQLITE_INTEGER:
|
||||
case SQLITE_FLOAT: {
|
||||
i64 m = sqlite3_context_db_handle(context)->enc<=SQLITE_UTF8 ? 1 : 2;
|
||||
sqlite3_result_int64(context, sqlite3_value_bytes(argv[0])*m);
|
||||
break;
|
||||
}
|
||||
case SQLITE_TEXT: {
|
||||
if( sqlite3_value_encoding(argv[0])<=SQLITE_UTF8 ){
|
||||
sqlite3_result_int(context, sqlite3_value_bytes(argv[0]));
|
||||
}else{
|
||||
sqlite3_result_int(context, sqlite3_value_bytes16(argv[0]));
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
sqlite3_result_null(context);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Implementation of the abs() function.
|
||||
**
|
||||
@@ -1634,11 +1670,11 @@ static void loadExt(sqlite3_context *context, int argc, sqlite3_value **argv){
|
||||
*/
|
||||
typedef struct SumCtx SumCtx;
|
||||
struct SumCtx {
|
||||
double rSum; /* Floating point sum */
|
||||
i64 iSum; /* Integer sum */
|
||||
double rSum; /* Running sum as as a double */
|
||||
i64 iSum; /* Running sum as a signed integer */
|
||||
i64 cnt; /* Number of elements summed */
|
||||
u8 overflow; /* True if integer overflow seen */
|
||||
u8 approx; /* True if non-integer value was input to the sum */
|
||||
u8 approx; /* True if any non-integer value was input to the sum */
|
||||
u8 ovrfl; /* Integer overflow seen */
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -1660,15 +1696,26 @@ static void sumStep(sqlite3_context *context, int argc, sqlite3_value **argv){
|
||||
type = sqlite3_value_numeric_type(argv[0]);
|
||||
if( p && type!=SQLITE_NULL ){
|
||||
p->cnt++;
|
||||
if( type==SQLITE_INTEGER ){
|
||||
i64 v = sqlite3_value_int64(argv[0]);
|
||||
p->rSum += v;
|
||||
if( (p->approx|p->overflow)==0 && sqlite3AddInt64(&p->iSum, v) ){
|
||||
p->approx = p->overflow = 1;
|
||||
if( p->approx==0 ){
|
||||
if( type!=SQLITE_INTEGER ){
|
||||
p->rSum = (double)p->iSum;
|
||||
p->approx = 1;
|
||||
p->rSum += sqlite3_value_double(argv[0]);
|
||||
}else{
|
||||
i64 x = p->iSum;
|
||||
if( sqlite3AddInt64(&x, sqlite3_value_int64(argv[0]))==0 ){
|
||||
p->iSum = x;
|
||||
}else{
|
||||
p->ovrfl = 1;
|
||||
p->rSum = (double)p->iSum;
|
||||
p->approx = 1;
|
||||
p->rSum += sqlite3_value_double(argv[0]);
|
||||
}
|
||||
}
|
||||
}else{
|
||||
p->rSum += sqlite3_value_double(argv[0]);
|
||||
if( type!=SQLITE_INTEGER ) p->ovrfl = 0;
|
||||
p->approx = 1;
|
||||
p->rSum += sqlite3_value_double(argv[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1685,13 +1732,10 @@ static void sumInverse(sqlite3_context *context, int argc, sqlite3_value**argv){
|
||||
if( ALWAYS(p) && type!=SQLITE_NULL ){
|
||||
assert( p->cnt>0 );
|
||||
p->cnt--;
|
||||
assert( type==SQLITE_INTEGER || p->approx );
|
||||
if( type==SQLITE_INTEGER && p->approx==0 ){
|
||||
i64 v = sqlite3_value_int64(argv[0]);
|
||||
p->rSum -= v;
|
||||
p->iSum -= v;
|
||||
}else{
|
||||
if( p->approx ){
|
||||
p->rSum -= sqlite3_value_double(argv[0]);
|
||||
}else{
|
||||
p->iSum -= sqlite3_value_int64(argv[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1702,10 +1746,12 @@ static void sumFinalize(sqlite3_context *context){
|
||||
SumCtx *p;
|
||||
p = sqlite3_aggregate_context(context, 0);
|
||||
if( p && p->cnt>0 ){
|
||||
if( p->overflow ){
|
||||
sqlite3_result_error(context,"integer overflow",-1);
|
||||
}else if( p->approx ){
|
||||
sqlite3_result_double(context, p->rSum);
|
||||
if( p->approx ){
|
||||
if( p->ovrfl ){
|
||||
sqlite3_result_error(context,"integer overflow",-1);
|
||||
}else{
|
||||
sqlite3_result_double(context, p->rSum);
|
||||
}
|
||||
}else{
|
||||
sqlite3_result_int64(context, p->iSum);
|
||||
}
|
||||
@@ -1715,14 +1761,27 @@ static void avgFinalize(sqlite3_context *context){
|
||||
SumCtx *p;
|
||||
p = sqlite3_aggregate_context(context, 0);
|
||||
if( p && p->cnt>0 ){
|
||||
sqlite3_result_double(context, p->rSum/(double)p->cnt);
|
||||
double r;
|
||||
if( p->approx ){
|
||||
r = p->rSum;
|
||||
}else{
|
||||
r = sqlite3RealToI64(p->iSum);
|
||||
}
|
||||
sqlite3_result_double(context, r/(double)p->cnt);
|
||||
}
|
||||
}
|
||||
static void totalFinalize(sqlite3_context *context){
|
||||
SumCtx *p;
|
||||
double r = 0.0;
|
||||
p = sqlite3_aggregate_context(context, 0);
|
||||
/* (double)0 In case of SQLITE_OMIT_FLOATING_POINT... */
|
||||
sqlite3_result_double(context, p ? p->rSum : (double)0);
|
||||
if( p ){
|
||||
if( p->approx ){
|
||||
r = p->rSum;
|
||||
}else{
|
||||
r = sqlite3RealToI64(p->iSum);
|
||||
}
|
||||
}
|
||||
sqlite3_result_double(context, r);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2376,6 +2435,7 @@ void sqlite3RegisterBuiltinFunctions(void){
|
||||
FUNCTION2(typeof, 1, 0, 0, typeofFunc, SQLITE_FUNC_TYPEOF),
|
||||
FUNCTION2(subtype, 1, 0, 0, subtypeFunc, SQLITE_FUNC_TYPEOF),
|
||||
FUNCTION2(length, 1, 0, 0, lengthFunc, SQLITE_FUNC_LENGTH),
|
||||
FUNCTION2(octet_length, 1, 0, 0, bytelengthFunc,SQLITE_FUNC_BYTELEN),
|
||||
FUNCTION(instr, 2, 0, 0, instrFunc ),
|
||||
FUNCTION(printf, -1, 0, 0, printfFunc ),
|
||||
FUNCTION(format, -1, 0, 0, printfFunc ),
|
||||
|
||||
+7
-7
@@ -559,7 +559,7 @@ void sqlite3_str_vappendf(
|
||||
exp = 0;
|
||||
if( xtype==etGENERIC && precision>0 ) precision--;
|
||||
testcase( precision>0xfff );
|
||||
if( realvalue<1.0e+16
|
||||
if( realvalue<9.22e+18
|
||||
&& realvalue==(LONGDOUBLE_TYPE)(longvalue = (u64)realvalue)
|
||||
){
|
||||
/* Number is a pure integer that can be represented as u64 */
|
||||
@@ -598,13 +598,13 @@ void sqlite3_str_vappendf(
|
||||
|
||||
/* Normalize realvalue to within 10.0 > realvalue >= 1.0 */
|
||||
if( ALWAYS(realvalue>0.0) ){
|
||||
LONGDOUBLE_TYPE scale = 1.0;
|
||||
while( realvalue>=1e100*scale && exp<=350){ scale*=1e100;exp+=100;}
|
||||
while( realvalue>=1e10*scale && exp<=350 ){ scale*=1e10; exp+=10; }
|
||||
while( realvalue>=10.0*scale && exp<=350 ){ scale *= 10.0; exp++; }
|
||||
LONGDOUBLE_TYPE scale = 1.0L;
|
||||
while( realvalue>=1e100*scale && exp<=350){ scale*=1e100L;exp+=100;}
|
||||
while( realvalue>=1e10*scale && exp<=350 ){ scale*=1e10L; exp+=10; }
|
||||
while( realvalue>=10.0*scale && exp<=350 ){ scale*=10.0L; exp++; }
|
||||
realvalue /= scale;
|
||||
while( realvalue<1e-8 ){ realvalue *= 1e8; exp-=8; }
|
||||
while( realvalue<1.0 ){ realvalue *= 10.0; exp--; }
|
||||
while( realvalue<1e-8 ){ realvalue *= 1e8L; exp-=8; }
|
||||
while( realvalue<1.0 ){ realvalue *= 10.0L; exp--; }
|
||||
if( exp>350 ){
|
||||
if( flag_zeropad ){
|
||||
realvalue = 9.0;
|
||||
|
||||
+11
-2
@@ -8009,9 +8009,13 @@ int sqlite3Select(
|
||||
int nCol;
|
||||
int nGroupBy;
|
||||
|
||||
explainTempTable(pParse,
|
||||
#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
|
||||
int addrExp; /* Address of OP_Explain instruction */
|
||||
#endif
|
||||
ExplainQueryPlan2(addrExp, (pParse, 0, "USE TEMP B-TREE FOR %s",
|
||||
(sDistinct.isTnct && (p->selFlags&SF_Distinct)==0) ?
|
||||
"DISTINCT" : "GROUP BY");
|
||||
"DISTINCT" : "GROUP BY"
|
||||
));
|
||||
|
||||
groupBySort = 1;
|
||||
nGroupBy = pGroupBy->nExpr;
|
||||
@@ -8036,18 +8040,23 @@ int sqlite3Select(
|
||||
}
|
||||
pAggInfo->directMode = 0;
|
||||
regRecord = sqlite3GetTempReg(pParse);
|
||||
sqlite3VdbeScanStatusCounters(v, addrExp, 0, sqlite3VdbeCurrentAddr(v));
|
||||
sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase, nCol, regRecord);
|
||||
sqlite3VdbeAddOp2(v, OP_SorterInsert, pAggInfo->sortingIdx, regRecord);
|
||||
sqlite3VdbeScanStatusRange(v, addrExp, sqlite3VdbeCurrentAddr(v)-2, -1);
|
||||
sqlite3ReleaseTempReg(pParse, regRecord);
|
||||
sqlite3ReleaseTempRange(pParse, regBase, nCol);
|
||||
TREETRACE(0x2,pParse,p,("WhereEnd\n"));
|
||||
sqlite3WhereEnd(pWInfo);
|
||||
pAggInfo->sortingIdxPTab = sortPTab = pParse->nTab++;
|
||||
sortOut = sqlite3GetTempReg(pParse);
|
||||
sqlite3VdbeScanStatusCounters(v, addrExp, sqlite3VdbeCurrentAddr(v), 0);
|
||||
sqlite3VdbeAddOp3(v, OP_OpenPseudo, sortPTab, sortOut, nCol);
|
||||
sqlite3VdbeAddOp2(v, OP_SorterSort, pAggInfo->sortingIdx, addrEnd);
|
||||
VdbeComment((v, "GROUP BY sort")); VdbeCoverage(v);
|
||||
pAggInfo->useSortingIdx = 1;
|
||||
sqlite3VdbeScanStatusRange(v, addrExp, -1, sortPTab);
|
||||
sqlite3VdbeScanStatusRange(v, addrExp, -1, pAggInfo->sortingIdx);
|
||||
}
|
||||
|
||||
/* If there are entries in pAgggInfo->aFunc[] that contain subexpressions
|
||||
|
||||
+155
-76
@@ -1207,6 +1207,46 @@ static char *shellFakeSchema(
|
||||
return s.z;
|
||||
}
|
||||
|
||||
/*
|
||||
** SQL function: strtod(X)
|
||||
**
|
||||
** Use the C-library strtod() function to convert string X into a double.
|
||||
** Used for comparing the accuracy of SQLite's internal text-to-float conversion
|
||||
** routines against the C-library.
|
||||
*/
|
||||
static void shellStrtod(
|
||||
sqlite3_context *pCtx,
|
||||
int nVal,
|
||||
sqlite3_value **apVal
|
||||
){
|
||||
char *z = (char*)sqlite3_value_text(apVal[0]);
|
||||
UNUSED_PARAMETER(nVal);
|
||||
if( z==0 ) return;
|
||||
sqlite3_result_double(pCtx, strtod(z,0));
|
||||
}
|
||||
|
||||
/*
|
||||
** SQL function: dtostr(X)
|
||||
**
|
||||
** Use the C-library printf() function to convert real value X into a string.
|
||||
** Used for comparing the accuracy of SQLite's internal float-to-text conversion
|
||||
** routines against the C-library.
|
||||
*/
|
||||
static void shellDtostr(
|
||||
sqlite3_context *pCtx,
|
||||
int nVal,
|
||||
sqlite3_value **apVal
|
||||
){
|
||||
double r = sqlite3_value_double(apVal[0]);
|
||||
int n = nVal>=2 ? sqlite3_value_int(apVal[1]) : 26;
|
||||
char z[400];
|
||||
if( n<1 ) n = 1;
|
||||
if( n>350 ) n = 350;
|
||||
sprintf(z, "%#+.*e", n, r);
|
||||
sqlite3_result_text(pCtx, z, -1, SQLITE_TRANSIENT);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** SQL function: shell_module_schema(X)
|
||||
**
|
||||
@@ -1567,6 +1607,7 @@ static ShellState shellState;
|
||||
#define MODE_Box 16 /* Unicode box-drawing characters */
|
||||
#define MODE_Count 17 /* Output only a count of the rows of output */
|
||||
#define MODE_Off 18 /* No query output shown */
|
||||
#define MODE_ScanExp 19 /* Like MODE_Explain, but for ".scanstats vm" */
|
||||
|
||||
static const char *modeDescr[] = {
|
||||
"line",
|
||||
@@ -2480,38 +2521,58 @@ static int shell_callback(
|
||||
}
|
||||
break;
|
||||
}
|
||||
case MODE_ScanExp:
|
||||
case MODE_Explain: {
|
||||
static const int aExplainWidth[] = {4, 13, 4, 4, 4, 13, 2, 13};
|
||||
if( nArg>ArraySize(aExplainWidth) ){
|
||||
nArg = ArraySize(aExplainWidth);
|
||||
static const int aExplainWidth[] = {4, 13, 4, 4, 4, 13, 2, 13};
|
||||
static const int aExplainMap[] = {0, 1, 2, 3, 4, 5, 6, 7 };
|
||||
static const int aScanExpWidth[] = {4, 6, 6, 13, 4, 4, 4, 13, 2, 13};
|
||||
static const int aScanExpMap[] = {0, 9, 8, 1, 2, 3, 4, 5, 6, 7 };
|
||||
|
||||
const int *aWidth = aExplainWidth;
|
||||
const int *aMap = aExplainMap;
|
||||
int nWidth = ArraySize(aExplainWidth);
|
||||
int iIndent = 1;
|
||||
|
||||
if( p->cMode==MODE_ScanExp ){
|
||||
aWidth = aScanExpWidth;
|
||||
aMap = aScanExpMap;
|
||||
nWidth = ArraySize(aScanExpWidth);
|
||||
iIndent = 3;
|
||||
}
|
||||
if( nArg>nWidth ) nArg = nWidth;
|
||||
|
||||
/* If this is the first row seen, print out the headers */
|
||||
if( p->cnt++==0 ){
|
||||
for(i=0; i<nArg; i++){
|
||||
int w = aExplainWidth[i];
|
||||
utf8_width_print(p->out, w, azCol[i]);
|
||||
utf8_width_print(p->out, aWidth[i], azCol[ aMap[i] ]);
|
||||
fputs(i==nArg-1 ? "\n" : " ", p->out);
|
||||
}
|
||||
for(i=0; i<nArg; i++){
|
||||
int w = aExplainWidth[i];
|
||||
print_dashes(p->out, w);
|
||||
print_dashes(p->out, aWidth[i]);
|
||||
fputs(i==nArg-1 ? "\n" : " ", p->out);
|
||||
}
|
||||
}
|
||||
|
||||
/* If there is no data, exit early. */
|
||||
if( azArg==0 ) break;
|
||||
|
||||
for(i=0; i<nArg; i++){
|
||||
int w = aExplainWidth[i];
|
||||
const char *zSep = " ";
|
||||
int w = aWidth[i];
|
||||
const char *zVal = azArg[ aMap[i] ];
|
||||
if( i==nArg-1 ) w = 0;
|
||||
if( azArg[i] && strlenChar(azArg[i])>w ){
|
||||
w = strlenChar(azArg[i]);
|
||||
if( zVal && strlenChar(zVal)>w ){
|
||||
w = strlenChar(zVal);
|
||||
zSep = " ";
|
||||
}
|
||||
if( i==1 && p->aiIndent && p->pStmt ){
|
||||
if( i==iIndent && p->aiIndent && p->pStmt ){
|
||||
if( p->iIndent<p->nIndent ){
|
||||
utf8_printf(p->out, "%*.s", p->aiIndent[p->iIndent], "");
|
||||
}
|
||||
p->iIndent++;
|
||||
}
|
||||
utf8_width_print(p->out, w, azArg[i] ? azArg[i] : p->nullValue);
|
||||
fputs(i==nArg-1 ? "\n" : " ", p->out);
|
||||
utf8_width_print(p->out, w, zVal ? zVal : p->nullValue);
|
||||
fputs(i==nArg-1 ? "\n" : zSep, p->out);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -3292,17 +3353,11 @@ static int scanStatsHeight(sqlite3_stmt *p, int iEntry){
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Display scan stats.
|
||||
*/
|
||||
static void display_scanstats(
|
||||
#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
|
||||
static void display_explain_scanstats(
|
||||
sqlite3 *db, /* Database to query */
|
||||
ShellState *pArg /* Pointer to ShellState */
|
||||
){
|
||||
#ifndef SQLITE_ENABLE_STMT_SCANSTATUS
|
||||
UNUSED_PARAMETER(db);
|
||||
UNUSED_PARAMETER(pArg);
|
||||
#else
|
||||
static const int f = SQLITE_SCANSTAT_COMPLEX;
|
||||
sqlite3_stmt *p = pArg->pStmt;
|
||||
int ii = 0;
|
||||
@@ -3374,8 +3429,9 @@ static void display_scanstats(
|
||||
}
|
||||
|
||||
eqp_render(pArg, nTotal);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
** Parameter azArray points to a zero-terminated array of strings. zStr
|
||||
@@ -3413,8 +3469,6 @@ static int str_in_array(const char *zStr, const char **azArray){
|
||||
** and "Goto" by 2 spaces.
|
||||
*/
|
||||
static void explain_data_prepare(ShellState *p, sqlite3_stmt *pSql){
|
||||
const char *zSql; /* The text of the SQL statement */
|
||||
const char *z; /* Used to check if this is an EXPLAIN */
|
||||
int *abYield = 0; /* True if op is an OP_Yield */
|
||||
int nAlloc = 0; /* Allocated size of p->aiIndent[], abYield */
|
||||
int iOp; /* Index of operation in p->aiIndent[] */
|
||||
@@ -3425,65 +3479,45 @@ static void explain_data_prepare(ShellState *p, sqlite3_stmt *pSql){
|
||||
"Rewind", 0 };
|
||||
const char *azGoto[] = { "Goto", 0 };
|
||||
|
||||
/* Try to figure out if this is really an EXPLAIN statement. If this
|
||||
** cannot be verified, return early. */
|
||||
if( sqlite3_column_count(pSql)!=8 ){
|
||||
p->cMode = p->mode;
|
||||
return;
|
||||
}
|
||||
zSql = sqlite3_sql(pSql);
|
||||
if( zSql==0 ) return;
|
||||
for(z=zSql; *z==' ' || *z=='\t' || *z=='\n' || *z=='\f' || *z=='\r'; z++);
|
||||
if( sqlite3_strnicmp(z, "explain", 7) ){
|
||||
p->cMode = p->mode;
|
||||
return;
|
||||
}
|
||||
/* The caller guarantees that the leftmost 4 columns of the statement
|
||||
** passed to this function are equivalent to the leftmost 4 columns
|
||||
** of EXPLAIN statement output. In practice the statement may be
|
||||
** an EXPLAIN, or it may be a query on the bytecode() virtual table. */
|
||||
assert( sqlite3_column_count(pSql)>=4 );
|
||||
assert( 0==sqlite3_stricmp( sqlite3_column_name(pSql, 0), "addr" ) );
|
||||
assert( 0==sqlite3_stricmp( sqlite3_column_name(pSql, 1), "opcode" ) );
|
||||
assert( 0==sqlite3_stricmp( sqlite3_column_name(pSql, 2), "p1" ) );
|
||||
assert( 0==sqlite3_stricmp( sqlite3_column_name(pSql, 3), "p2" ) );
|
||||
|
||||
for(iOp=0; SQLITE_ROW==sqlite3_step(pSql); iOp++){
|
||||
int i;
|
||||
int iAddr = sqlite3_column_int(pSql, 0);
|
||||
const char *zOp = (const char*)sqlite3_column_text(pSql, 1);
|
||||
|
||||
/* Set p2 to the P2 field of the current opcode. Then, assuming that
|
||||
** p2 is an instruction address, set variable p2op to the index of that
|
||||
** instruction in the aiIndent[] array. p2 and p2op may be different if
|
||||
** the current instruction is part of a sub-program generated by an
|
||||
** SQL trigger or foreign key. */
|
||||
int p1 = sqlite3_column_int(pSql, 2);
|
||||
int p2 = sqlite3_column_int(pSql, 3);
|
||||
|
||||
/* Assuming that p2 is an instruction address, set variable p2op to the
|
||||
** index of that instruction in the aiIndent[] array. p2 and p2op may be
|
||||
** different if the current instruction is part of a sub-program generated
|
||||
** by an SQL trigger or foreign key. */
|
||||
int p2op = (p2 + (iOp-iAddr));
|
||||
|
||||
/* Grow the p->aiIndent array as required */
|
||||
if( iOp>=nAlloc ){
|
||||
if( iOp==0 ){
|
||||
/* Do further verification that this is explain output. Abort if
|
||||
** it is not */
|
||||
static const char *explainCols[] = {
|
||||
"addr", "opcode", "p1", "p2", "p3", "p4", "p5", "comment" };
|
||||
int jj;
|
||||
for(jj=0; jj<ArraySize(explainCols); jj++){
|
||||
if( cli_strcmp(sqlite3_column_name(pSql,jj),explainCols[jj])!=0 ){
|
||||
p->cMode = p->mode;
|
||||
sqlite3_reset(pSql);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
nAlloc += 100;
|
||||
p->aiIndent = (int*)sqlite3_realloc64(p->aiIndent, nAlloc*sizeof(int));
|
||||
shell_check_oom(p->aiIndent);
|
||||
abYield = (int*)sqlite3_realloc64(abYield, nAlloc*sizeof(int));
|
||||
shell_check_oom(abYield);
|
||||
}
|
||||
|
||||
abYield[iOp] = str_in_array(zOp, azYield);
|
||||
p->aiIndent[iOp] = 0;
|
||||
p->nIndent = iOp+1;
|
||||
|
||||
if( str_in_array(zOp, azNext) && p2op>0 ){
|
||||
for(i=p2op; i<iOp; i++) p->aiIndent[i] += 2;
|
||||
}
|
||||
if( str_in_array(zOp, azGoto) && p2op<p->nIndent
|
||||
&& (abYield[p2op] || sqlite3_column_int(pSql, 2))
|
||||
){
|
||||
if( str_in_array(zOp, azGoto) && p2op<iOp && (abYield[p2op] || p1) ){
|
||||
for(i=p2op; i<iOp; i++) p->aiIndent[i] += 2;
|
||||
}
|
||||
}
|
||||
@@ -3503,6 +3537,48 @@ static void explain_data_delete(ShellState *p){
|
||||
p->iIndent = 0;
|
||||
}
|
||||
|
||||
static void exec_prepared_stmt(ShellState*, sqlite3_stmt*);
|
||||
|
||||
/*
|
||||
** Display scan stats.
|
||||
*/
|
||||
static void display_scanstats(
|
||||
sqlite3 *db, /* Database to query */
|
||||
ShellState *pArg /* Pointer to ShellState */
|
||||
){
|
||||
#ifndef SQLITE_ENABLE_STMT_SCANSTATUS
|
||||
UNUSED_PARAMETER(db);
|
||||
UNUSED_PARAMETER(pArg);
|
||||
#else
|
||||
if( pArg->scanstatsOn==3 ){
|
||||
const char *zSql =
|
||||
" SELECT addr, opcode, p1, p2, p3, p4, p5, comment, nexec,"
|
||||
" round(ncycle*100.0 / (sum(ncycle) OVER ()), 2)||'%' AS cycles"
|
||||
" FROM bytecode(?)";
|
||||
|
||||
int rc = SQLITE_OK;
|
||||
sqlite3_stmt *pStmt = 0;
|
||||
rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0);
|
||||
if( rc==SQLITE_OK ){
|
||||
sqlite3_stmt *pSave = pArg->pStmt;
|
||||
pArg->pStmt = pStmt;
|
||||
sqlite3_bind_pointer(pStmt, 1, pSave, "stmt-pointer", 0);
|
||||
|
||||
pArg->cnt = 0;
|
||||
pArg->cMode = MODE_ScanExp;
|
||||
explain_data_prepare(pArg, pStmt);
|
||||
exec_prepared_stmt(pArg, pStmt);
|
||||
explain_data_delete(pArg);
|
||||
|
||||
sqlite3_finalize(pStmt);
|
||||
pArg->pStmt = pSave;
|
||||
}
|
||||
}else{
|
||||
display_explain_scanstats(db, pArg);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
** Disable and restore .wheretrace and .treetrace/.selecttrace settings.
|
||||
*/
|
||||
@@ -4322,6 +4398,7 @@ static int shell_exec(
|
||||
rc = sqlite3_prepare_v2(db, zEQP, -1, &pExplain, 0);
|
||||
if( rc==SQLITE_OK ){
|
||||
pArg->cMode = MODE_Explain;
|
||||
assert( sqlite3_stmt_isexplain(pExplain)==1 );
|
||||
explain_data_prepare(pArg, pExplain);
|
||||
exec_prepared_stmt(pArg, pExplain);
|
||||
explain_data_delete(pArg);
|
||||
@@ -4340,9 +4417,10 @@ static int shell_exec(
|
||||
}
|
||||
|
||||
if( pArg ){
|
||||
int bIsExplain = (sqlite3_stmt_isexplain(pStmt)==1);
|
||||
pArg->cMode = pArg->mode;
|
||||
if( pArg->autoExplain ){
|
||||
if( sqlite3_stmt_isexplain(pStmt)==1 ){
|
||||
if( bIsExplain ){
|
||||
pArg->cMode = MODE_Explain;
|
||||
}
|
||||
if( sqlite3_stmt_isexplain(pStmt)==2 ){
|
||||
@@ -4352,7 +4430,7 @@ static int shell_exec(
|
||||
|
||||
/* If the shell is currently in ".explain" mode, gather the extra
|
||||
** data required to add indents to the output.*/
|
||||
if( pArg->cMode==MODE_Explain ){
|
||||
if( pArg->cMode==MODE_Explain && bIsExplain ){
|
||||
explain_data_prepare(pArg, pStmt);
|
||||
}
|
||||
}
|
||||
@@ -5463,6 +5541,12 @@ static void open_db(ShellState *p, int openFlags){
|
||||
}
|
||||
#endif
|
||||
|
||||
sqlite3_create_function(p->db, "strtod", 1, SQLITE_UTF8, 0,
|
||||
shellStrtod, 0, 0);
|
||||
sqlite3_create_function(p->db, "dtostr", 1, SQLITE_UTF8, 0,
|
||||
shellDtostr, 0, 0);
|
||||
sqlite3_create_function(p->db, "dtostr", 2, SQLITE_UTF8, 0,
|
||||
shellDtostr, 0, 0);
|
||||
sqlite3_create_function(p->db, "shell_add_schema", 3, SQLITE_UTF8, 0,
|
||||
shellAddSchemaName, 0, 0);
|
||||
sqlite3_create_function(p->db, "shell_module_schema", 1, SQLITE_UTF8, 0,
|
||||
@@ -9887,6 +9971,9 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
|
||||
if( c=='s' && cli_strncmp(azArg[0], "scanstats", n)==0 ){
|
||||
if( nArg==2 ){
|
||||
if( cli_strcmp(azArg[1], "vm")==0 ){
|
||||
p->scanstatsOn = 3;
|
||||
}else
|
||||
if( cli_strcmp(azArg[1], "est")==0 ){
|
||||
p->scanstatsOn = 2;
|
||||
}else{
|
||||
@@ -10532,7 +10619,8 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
"with tabcols as materialized(\n"
|
||||
"select tname, cname\n"
|
||||
"from ("
|
||||
" select ss.tname as tname, ti.name as cname\n"
|
||||
" select printf('\"%%w\"',ss.tname) as tname,"
|
||||
" printf('\"%%w\"',ti.name) as cname\n"
|
||||
" from (%z) ss\n inner join pragma_table_info(tname) ti))\n"
|
||||
"select 'SELECT total(bad_text_count) AS bad_text_count\n"
|
||||
"FROM ('||group_concat(query, ' UNION ALL ')||')' as btc_query\n"
|
||||
@@ -10804,7 +10892,7 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
static const struct {
|
||||
const char *zCtrlName; /* Name of a test-control option */
|
||||
int ctrlCode; /* Integer code for that option */
|
||||
int unSafe; /* Not valid for --safe mode */
|
||||
int unSafe; /* Not valid unless --unsafe-testing */
|
||||
const char *zUsage; /* Usage notes */
|
||||
} aCtrl[] = {
|
||||
{"always", SQLITE_TESTCTRL_ALWAYS, 1, "BOOLEAN" },
|
||||
@@ -10837,12 +10925,6 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
int i, n2;
|
||||
const char *zCmd = 0;
|
||||
|
||||
if( !ShellHasFlag(p,SHFLG_TestingMode) ){
|
||||
utf8_printf(stderr, ".%s unavailable without --unsafe-testing\n",
|
||||
"testctrl");
|
||||
rc = 1;
|
||||
goto meta_command_exit;
|
||||
}
|
||||
open_db(p, 0);
|
||||
zCmd = nArg>=2 ? azArg[1] : "help";
|
||||
|
||||
@@ -10856,6 +10938,7 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
if( cli_strcmp(zCmd,"help")==0 ){
|
||||
utf8_printf(p->out, "Available test-controls:\n");
|
||||
for(i=0; i<ArraySize(aCtrl); i++){
|
||||
if( aCtrl[i].unSafe && !ShellHasFlag(p,SHFLG_TestingMode) ) continue;
|
||||
utf8_printf(p->out, " .testctrl %s %s\n",
|
||||
aCtrl[i].zCtrlName, aCtrl[i].zUsage);
|
||||
}
|
||||
@@ -10867,6 +10950,7 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
** of the option name, or a numerical value. */
|
||||
n2 = strlen30(zCmd);
|
||||
for(i=0; i<ArraySize(aCtrl); i++){
|
||||
if( aCtrl[i].unSafe && !ShellHasFlag(p,SHFLG_TestingMode) ) continue;
|
||||
if( cli_strncmp(zCmd, aCtrl[i].zCtrlName, n2)==0 ){
|
||||
if( testctrl<0 ){
|
||||
testctrl = aCtrl[i].ctrlCode;
|
||||
@@ -10882,11 +10966,6 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
if( testctrl<0 ){
|
||||
utf8_printf(stderr,"Error: unknown test-control: %s\n"
|
||||
"Use \".testctrl --help\" for help\n", zCmd);
|
||||
}else if( aCtrl[iCtrl].unSafe && p->bSafeMode ){
|
||||
utf8_printf(stderr,
|
||||
"line %d: \".testctrl %s\" may not be used in safe mode\n",
|
||||
p->lineno, aCtrl[iCtrl].zCtrlName);
|
||||
exit(1);
|
||||
}else{
|
||||
switch(testctrl){
|
||||
|
||||
|
||||
@@ -1234,6 +1234,7 @@ typedef struct Cte Cte;
|
||||
typedef struct CteUse CteUse;
|
||||
typedef struct Db Db;
|
||||
typedef struct DbFixer DbFixer;
|
||||
typedef struct DblDbl DblDbl;
|
||||
typedef struct Schema Schema;
|
||||
typedef struct Expr Expr;
|
||||
typedef struct ExprList ExprList;
|
||||
@@ -1930,6 +1931,7 @@ struct FuncDestructor {
|
||||
** SQLITE_FUNC_ANYORDER == NC_OrderAgg == SF_OrderByReqd
|
||||
** SQLITE_FUNC_LENGTH == OPFLAG_LENGTHARG
|
||||
** SQLITE_FUNC_TYPEOF == OPFLAG_TYPEOFARG
|
||||
** SQLITE_FUNC_BYTELEN == OPFLAG_BYTELENARG
|
||||
** SQLITE_FUNC_CONSTANT == SQLITE_DETERMINISTIC from the API
|
||||
** SQLITE_FUNC_DIRECT == SQLITE_DIRECTONLY from the API
|
||||
** SQLITE_FUNC_UNSAFE == SQLITE_INNOCUOUS -- opposite meanings!!!
|
||||
@@ -1948,6 +1950,7 @@ struct FuncDestructor {
|
||||
#define SQLITE_FUNC_NEEDCOLL 0x0020 /* sqlite3GetFuncCollSeq() might be called*/
|
||||
#define SQLITE_FUNC_LENGTH 0x0040 /* Built-in length() function */
|
||||
#define SQLITE_FUNC_TYPEOF 0x0080 /* Built-in typeof() function */
|
||||
#define SQLITE_FUNC_BYTELEN 0x00c0 /* Built-in octet_length() function */
|
||||
#define SQLITE_FUNC_COUNT 0x0100 /* Built-in count(*) aggregate */
|
||||
/* 0x0200 -- available for reuse */
|
||||
#define SQLITE_FUNC_UNLIKELY 0x0400 /* Built-in unlikely() function */
|
||||
@@ -3891,6 +3894,7 @@ struct AuthContext {
|
||||
#define OPFLAG_ISNOOP 0x40 /* OP_Delete does pre-update-hook only */
|
||||
#define OPFLAG_LENGTHARG 0x40 /* OP_Column only used for length() */
|
||||
#define OPFLAG_TYPEOFARG 0x80 /* OP_Column only used for typeof() */
|
||||
#define OPFLAG_BYTELENARG 0xc0 /* OP_Column only for octet_length() */
|
||||
#define OPFLAG_BULKCSR 0x01 /* OP_Open** used to open bulk cursor */
|
||||
#define OPFLAG_SEEKEQ 0x02 /* OP_Open** cursor uses EQ seek only */
|
||||
#define OPFLAG_FORDELETE 0x08 /* OP_Open should use BTREE_FORDELETE */
|
||||
@@ -5032,6 +5036,7 @@ int sqlite3FixSrcList(DbFixer*, SrcList*);
|
||||
int sqlite3FixSelect(DbFixer*, Select*);
|
||||
int sqlite3FixExpr(DbFixer*, Expr*);
|
||||
int sqlite3FixTriggerStep(DbFixer*, TriggerStep*);
|
||||
|
||||
int sqlite3RealSameAsInt(double,sqlite3_int64);
|
||||
i64 sqlite3RealToI64(double);
|
||||
int sqlite3Int64ToText(i64,char*);
|
||||
|
||||
+44
-1
@@ -2216,6 +2216,7 @@ static int SQLITE_TCLAPI test_stmt_scanstatus(
|
||||
int flags = 0;
|
||||
int iSelectId = 0;
|
||||
int iParentId = 0;
|
||||
int bDebug = 0;
|
||||
|
||||
if( objc==5 ){
|
||||
struct Flag {
|
||||
@@ -2223,6 +2224,7 @@ static int SQLITE_TCLAPI test_stmt_scanstatus(
|
||||
int flag;
|
||||
} aTbl[] = {
|
||||
{"complex", SQLITE_SCANSTAT_COMPLEX},
|
||||
{"debug", -1},
|
||||
{0, 0}
|
||||
};
|
||||
|
||||
@@ -2239,7 +2241,11 @@ static int SQLITE_TCLAPI test_stmt_scanstatus(
|
||||
interp, aFlag[ii], aTbl, sizeof(aTbl[0]), "flag", 0, &iVal
|
||||
);
|
||||
if( res ) return TCL_ERROR;
|
||||
flags |= aTbl[iVal].flag;
|
||||
if( aTbl[iVal].flag==-1 ){
|
||||
bDebug = 1;
|
||||
}else{
|
||||
flags |= aTbl[iVal].flag;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2253,6 +2259,13 @@ static int SQLITE_TCLAPI test_stmt_scanstatus(
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
if( bDebug && 0==(flags & SQLITE_SCANSTAT_COMPLEX) ){
|
||||
Tcl_SetObjResult(interp,
|
||||
Tcl_NewStringObj("may not specify debug without complex", -1)
|
||||
);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
if( idx<0 ){
|
||||
Tcl_Obj *pRet = Tcl_NewObj();
|
||||
res = sqlite3_stmt_scanstatus_v2(
|
||||
@@ -2299,6 +2312,36 @@ static int SQLITE_TCLAPI test_stmt_scanstatus(
|
||||
pStmt, idx, SQLITE_SCANSTAT_NCYCLE, flags, (void*)&nCycle);
|
||||
Tcl_ListObjAppendElement(0, pRet, Tcl_NewStringObj("nCycle", -1));
|
||||
Tcl_ListObjAppendElement(0, pRet, Tcl_NewWideIntObj(nCycle));
|
||||
|
||||
if( bDebug ){
|
||||
int ii;
|
||||
ScanStatus *pScan = &((Vdbe*)pStmt)->aScan[idx];
|
||||
Tcl_Obj *pRange = Tcl_NewObj();
|
||||
Tcl_Obj *pCsr = Tcl_NewObj();
|
||||
|
||||
Tcl_ListObjAppendElement(0, pRet, Tcl_NewStringObj("debug_loop", -1));
|
||||
Tcl_ListObjAppendElement(0, pRet, Tcl_NewIntObj(pScan->addrLoop));
|
||||
Tcl_ListObjAppendElement(0, pRet, Tcl_NewStringObj("debug_visit", -1));
|
||||
Tcl_ListObjAppendElement(0, pRet, Tcl_NewIntObj(pScan->addrVisit));
|
||||
Tcl_ListObjAppendElement(0, pRet, Tcl_NewStringObj("debug_explain",-1));
|
||||
Tcl_ListObjAppendElement(0, pRet, Tcl_NewIntObj(pScan->addrExplain));
|
||||
for(ii=0; ii<ArraySize(pScan->aAddrRange)/2; ii++){
|
||||
int iStart = pScan->aAddrRange[ii*2];
|
||||
int iEnd = pScan->aAddrRange[ii*2+1];
|
||||
if( iStart>0 ){
|
||||
Tcl_ListObjAppendElement(0, pRange, Tcl_NewIntObj(iStart));
|
||||
Tcl_ListObjAppendElement(0, pRange, Tcl_NewIntObj(iEnd));
|
||||
}else if( iStart<0 ){
|
||||
Tcl_ListObjAppendElement(0, pCsr, Tcl_NewIntObj(iEnd));
|
||||
}
|
||||
}
|
||||
|
||||
Tcl_ListObjAppendElement(0, pRet, Tcl_NewStringObj("debug_range", -1));
|
||||
Tcl_ListObjAppendElement(0, pRet, pRange);
|
||||
Tcl_ListObjAppendElement(0, pRet, Tcl_NewStringObj("debug_csr", -1));
|
||||
Tcl_ListObjAppendElement(0, pRet, pCsr);
|
||||
}
|
||||
|
||||
Tcl_SetObjResult(interp, pRet);
|
||||
}else{
|
||||
Tcl_ResetResult(interp);
|
||||
|
||||
+4
-4
@@ -468,7 +468,7 @@ int sqlite3AtoF(const char *z, double *pResult, int length, u8 enc){
|
||||
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;
|
||||
LONGDOUBLE_TYPE result;
|
||||
int nDigit = 0; /* Number of digits processed */
|
||||
int eType = 1; /* 1: pure integer, 2+: fractional -1 or less: bad UTF16 */
|
||||
|
||||
@@ -597,7 +597,7 @@ do_atof_calc:
|
||||
s = sign<0 ? -s : s;
|
||||
|
||||
if( e==0 ){ /*OPTIMIZATION-IF-TRUE*/
|
||||
result = (double)s;
|
||||
result = (LONGDOUBLE_TYPE)s;
|
||||
}else{
|
||||
/* attempt to handle extremely small/large numbers better */
|
||||
if( e>307 ){ /*OPTIMIZATION-IF-TRUE*/
|
||||
@@ -605,10 +605,10 @@ do_atof_calc:
|
||||
LONGDOUBLE_TYPE scale = sqlite3Pow10(e-308);
|
||||
if( esign<0 ){
|
||||
result = s / scale;
|
||||
result /= 1.0e+308;
|
||||
result /= 1.0e+308L;
|
||||
}else{
|
||||
result = s * scale;
|
||||
result *= 1.0e+308;
|
||||
result *= 1.0e+308L;
|
||||
}
|
||||
}else{ assert( e>=342 );
|
||||
if( esign<0 ){
|
||||
|
||||
+9
-5
@@ -3056,10 +3056,14 @@ op_column_restart:
|
||||
pDest->flags = aFlag[t&1];
|
||||
}
|
||||
}else{
|
||||
u8 p5;
|
||||
pDest->enc = encoding;
|
||||
/* This branch happens only when content is on overflow pages */
|
||||
if( ((pOp->p5 & (OPFLAG_LENGTHARG|OPFLAG_TYPEOFARG))!=0
|
||||
&& ((t>=12 && (t&1)==0) || (pOp->p5 & OPFLAG_TYPEOFARG)!=0))
|
||||
if( ((p5 = (pOp->p5 & OPFLAG_BYTELENARG))!=0
|
||||
&& (p5==OPFLAG_TYPEOFARG
|
||||
|| (t>=12 && ((t&1)==0 || p5==OPFLAG_BYTELENARG))
|
||||
)
|
||||
)
|
||||
|| (len = sqlite3VdbeSerialTypeLen(t))==0
|
||||
){
|
||||
/* Content is irrelevant for
|
||||
@@ -5847,7 +5851,7 @@ case OP_SorterCompare: {
|
||||
** parameter P3. Clearing the P3 column cache as part of this opcode saves
|
||||
** us from having to issue a separate NullRow instruction to clear that cache.
|
||||
*/
|
||||
case OP_SorterData: {
|
||||
case OP_SorterData: { /* ncycle */
|
||||
VdbeCursor *pC;
|
||||
|
||||
pOut = &aMem[pOp->p2];
|
||||
@@ -6122,8 +6126,8 @@ case OP_IfSmaller: { /* jump */
|
||||
** regression tests can determine whether or not the optimizer is
|
||||
** correctly optimizing out sorts.
|
||||
*/
|
||||
case OP_SorterSort: /* jump */
|
||||
case OP_Sort: { /* jump */
|
||||
case OP_SorterSort: /* jump ncycle */
|
||||
case OP_Sort: { /* jump ncycle */
|
||||
#ifdef SQLITE_TEST
|
||||
sqlite3_sort_count++;
|
||||
sqlite3_search_count--;
|
||||
|
||||
+3
-3
@@ -538,7 +538,7 @@ int sqlite3VdbeExplain(Parse *pParse, u8 bPush, const char *zFmt, ...){
|
||||
if( bPush){
|
||||
pParse->addrExplain = iThis;
|
||||
}
|
||||
sqlite3VdbeScanStatus(v, iThis, 0, 0, 0, 0);
|
||||
sqlite3VdbeScanStatus(v, iThis, -1, -1, 0, 0);
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
@@ -1250,8 +1250,8 @@ void sqlite3VdbeScanStatusCounters(
|
||||
pScan = 0;
|
||||
}
|
||||
if( pScan ){
|
||||
pScan->addrLoop = addrLoop;
|
||||
pScan->addrVisit = addrVisit;
|
||||
if( addrLoop>0 ) pScan->addrLoop = addrLoop;
|
||||
if( addrVisit>0 ) pScan->addrVisit = addrVisit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+2
-32
@@ -575,36 +575,6 @@ void sqlite3VdbeMemReleaseMalloc(Mem *p){
|
||||
if( p->szMalloc ) vdbeMemClear(p);
|
||||
}
|
||||
|
||||
/*
|
||||
** Convert a 64-bit IEEE double into a 64-bit signed integer.
|
||||
** If the double is out of range of a 64-bit signed integer then
|
||||
** return the closest available 64-bit signed integer.
|
||||
*/
|
||||
static SQLITE_NOINLINE i64 doubleToInt64(double r){
|
||||
#ifdef SQLITE_OMIT_FLOATING_POINT
|
||||
/* When floating-point is omitted, double and int64 are the same thing */
|
||||
return r;
|
||||
#else
|
||||
/*
|
||||
** Many compilers we encounter do not define constants for the
|
||||
** minimum and maximum 64-bit integers, or they define them
|
||||
** inconsistently. And many do not understand the "LL" notation.
|
||||
** So we define our own static constants here using nothing
|
||||
** larger than a 32-bit integer constant.
|
||||
*/
|
||||
static const i64 maxInt = LARGEST_INT64;
|
||||
static const i64 minInt = SMALLEST_INT64;
|
||||
|
||||
if( r<=(double)minInt ){
|
||||
return minInt;
|
||||
}else if( r>=(double)maxInt ){
|
||||
return maxInt;
|
||||
}else{
|
||||
return (i64)r;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
** Return some kind of integer value which is the best we can do
|
||||
** at representing the value that *pMem describes as an integer.
|
||||
@@ -631,7 +601,7 @@ i64 sqlite3VdbeIntValue(const Mem *pMem){
|
||||
testcase( flags & MEM_IntReal );
|
||||
return pMem->u.i;
|
||||
}else if( flags & MEM_Real ){
|
||||
return doubleToInt64(pMem->u.r);
|
||||
return sqlite3RealToI64(pMem->u.r);
|
||||
}else if( (flags & (MEM_Str|MEM_Blob))!=0 && pMem->z!=0 ){
|
||||
return memIntValue(pMem);
|
||||
}else{
|
||||
@@ -693,7 +663,7 @@ void sqlite3VdbeIntegerAffinity(Mem *pMem){
|
||||
if( pMem->flags & MEM_IntReal ){
|
||||
MemSetTypeFlag(pMem, MEM_Int);
|
||||
}else{
|
||||
i64 ix = doubleToInt64(pMem->u.r);
|
||||
i64 ix = sqlite3RealToI64(pMem->u.r);
|
||||
|
||||
/* Only mark the value as an integer if
|
||||
**
|
||||
|
||||
+23
-6
@@ -69,6 +69,8 @@ static int bytecodevtabConnect(
|
||||
"p5 INT,"
|
||||
"comment TEXT,"
|
||||
"subprog TEXT,"
|
||||
"nexec INT,"
|
||||
"ncycle INT,"
|
||||
"stmt HIDDEN"
|
||||
");",
|
||||
|
||||
@@ -231,7 +233,7 @@ static int bytecodevtabColumn(
|
||||
}
|
||||
}
|
||||
}
|
||||
i += 10;
|
||||
i += 20;
|
||||
}
|
||||
}
|
||||
switch( i ){
|
||||
@@ -281,16 +283,31 @@ static int bytecodevtabColumn(
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 10: /* tables_used.type */
|
||||
|
||||
#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
|
||||
case 9: /* nexec */
|
||||
sqlite3_result_int(ctx, pOp->nExec);
|
||||
break;
|
||||
case 10: /* ncycle */
|
||||
sqlite3_result_int(ctx, pOp->nCycle);
|
||||
break;
|
||||
#else
|
||||
case 9: /* nexec */
|
||||
case 10: /* ncycle */
|
||||
sqlite3_result_int(ctx, 0);
|
||||
break;
|
||||
#endif
|
||||
|
||||
case 20: /* tables_used.type */
|
||||
sqlite3_result_text(ctx, pCur->zType, -1, SQLITE_STATIC);
|
||||
break;
|
||||
case 11: /* tables_used.schema */
|
||||
case 21: /* tables_used.schema */
|
||||
sqlite3_result_text(ctx, pCur->zSchema, -1, SQLITE_STATIC);
|
||||
break;
|
||||
case 12: /* tables_used.name */
|
||||
case 22: /* tables_used.name */
|
||||
sqlite3_result_text(ctx, pCur->zName, -1, SQLITE_STATIC);
|
||||
break;
|
||||
case 13: /* tables_used.wr */
|
||||
case 23: /* tables_used.wr */
|
||||
sqlite3_result_int(ctx, pOp->opcode==OP_OpenWrite);
|
||||
break;
|
||||
}
|
||||
@@ -364,7 +381,7 @@ static int bytecodevtabBestIndex(
|
||||
int rc = SQLITE_CONSTRAINT;
|
||||
struct sqlite3_index_constraint *p;
|
||||
bytecodevtab *pVTab = (bytecodevtab*)tab;
|
||||
int iBaseCol = pVTab->bTablesUsed ? 4 : 8;
|
||||
int iBaseCol = pVTab->bTablesUsed ? 4 : 10;
|
||||
pIdxInfo->estimatedCost = (double)100;
|
||||
pIdxInfo->estimatedRows = 100;
|
||||
pIdxInfo->idxNum = 0;
|
||||
|
||||
@@ -315,6 +315,12 @@ void sqlite3WhereAddScanStatus(
|
||||
if( wsFlags & WHERE_INDEXED ){
|
||||
sqlite3VdbeScanStatusRange(v, addrExplain, -1, pLvl->iIdxCur);
|
||||
}
|
||||
}else{
|
||||
int addr = pSrclist->a[pLvl->iFrom].addrFillSub;
|
||||
VdbeOp *pOp = sqlite3VdbeGetOp(v, addr-1);
|
||||
assert( sqlite3VdbeDb(v)->mallocFailed || pOp->opcode==OP_InitCoroutine );
|
||||
assert( sqlite3VdbeDb(v)->mallocFailed || pOp->p2>addr );
|
||||
sqlite3VdbeScanStatusRange(v, addrExplain, addr, pOp->p2-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+16
-9
@@ -23,31 +23,34 @@ do_execsql_test 1000 {
|
||||
SELECT decimal(1);
|
||||
} {1}
|
||||
do_execsql_test 1010 {
|
||||
SELECT decimal(1.0);
|
||||
SELECT decimal('1.0');
|
||||
} {1.0}
|
||||
do_execsql_test 1020 {
|
||||
SELECT decimal(0001.0);
|
||||
SELECT decimal('0001.0');
|
||||
} {1.0}
|
||||
do_execsql_test 1030 {
|
||||
SELECT decimal(+0001.0);
|
||||
SELECT decimal('+0001.0');
|
||||
} {1.0}
|
||||
do_execsql_test 1040 {
|
||||
SELECT decimal(-0001.0);
|
||||
SELECT decimal('-0001.0');
|
||||
} {-1.0}
|
||||
do_execsql_test 1050 {
|
||||
SELECT decimal(1.0e72);
|
||||
SELECT decimal('1.0e72');
|
||||
} {1000000000000000000000000000000000000000000000000000000000000000000000000}
|
||||
# 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123
|
||||
do_execsql_test 1060 {
|
||||
SELECT decimal(1.0e-72);
|
||||
SELECT decimal('1.0e-72');
|
||||
} {0.0000000000000000000000000000000000000000000000000000000000000000000000010}
|
||||
# 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123
|
||||
do_execsql_test 1070 {
|
||||
SELECT decimal(-123e-4);
|
||||
SELECT decimal('-123e-4');
|
||||
} {-0.0123}
|
||||
do_execsql_test 1080 {
|
||||
SELECT decimal(+123e+4);
|
||||
} {1230000.0}
|
||||
SELECT decimal('+123e+4');
|
||||
} {1230000}
|
||||
do_execsql_test 1081 {
|
||||
SELECT decimal_sci('+123e+4');
|
||||
} {+1.23e+06}
|
||||
|
||||
|
||||
do_execsql_test 2000 {
|
||||
@@ -161,6 +164,10 @@ do_execsql_test 6010 {
|
||||
SELECT decimal_mul(ieee754_mantissa(c.n),pow2.v)
|
||||
FROM pow2, c WHERE pow2.x=ieee754_exponent(c.n);
|
||||
} {0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004940656458412465441765687928682213723650598026143247644255856825006755072702087518652998363616359923797965646954457177309266567103559397963987747960107818781263007131903114045278458171678489821036887186360569987307230500063874091535649843873124733972731696151400317153853980741262385655911710266585566867681870395603106249319452715914924553293054565444011274801297099995419319894090804165633245247571478690147267801593552386115501348035264934720193790268107107491703332226844753335720832431936092382893458368060106011506169809753078342277318329247904982524730776375927247874656084778203734469699533647017972677717585125660551199131504891101451037862738167250955837389733598993664809941164205702637090279242767544565229087538682506419718265533447265625}
|
||||
do_execsql_test 6011 {
|
||||
WITH c(n) AS (SELECT ieee754_from_blob(x'0000000000000001'))
|
||||
SELECT decimal(c.n) FROM c;
|
||||
} {0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004940656458412465441765687928682213723650598026143247644255856825006755072702087518652998363616359923797965646954457177309266567103559397963987747960107818781263007131903114045278458171678489821036887186360569987307230500063874091535649843873124733972731696151400317153853980741262385655911710266585566867681870395603106249319452715914924553293054565444011274801297099995419319894090804165633245247571478690147267801593552386115501348035264934720193790268107107491703332226844753335720832431936092382893458368060106011506169809753078342277318329247904982524730776375927247874656084778203734469699533647017972677717585125660551199131504891101451037862738167250955837389733598993664809941164205702637090279242767544565229087538682506419718265533447265625}
|
||||
do_execsql_test 6020 {
|
||||
WITH c(n) AS (SELECT ieee754_from_blob(x'7fefffffffffffff'))
|
||||
SELECT decimal_mul(ieee754_mantissa(c.n),pow2.v)
|
||||
|
||||
+46
-24
@@ -42,6 +42,9 @@ do_test func-0.1 {
|
||||
do_test func-1.0 {
|
||||
execsql {SELECT length(t1) FROM tbl1 ORDER BY t1}
|
||||
} {4 2 7 8 4}
|
||||
do_execsql_test func-1.0b {
|
||||
SELECT octet_length(t1) FROM tbl1 ORDER BY t1;
|
||||
} {4 2 7 8 4}
|
||||
do_test func-1.1 {
|
||||
set r [catch {execsql {SELECT length(*) FROM tbl1 ORDER BY t1}} msg]
|
||||
lappend r $msg
|
||||
@@ -57,9 +60,29 @@ do_test func-1.3 {
|
||||
do_test func-1.4 {
|
||||
execsql {SELECT coalesce(length(a),-1) FROM t2}
|
||||
} {1 -1 3 -1 5}
|
||||
do_execsql_test func-1.5 {
|
||||
SELECT octet_length(12345);
|
||||
} {5}
|
||||
db null NULL
|
||||
do_execsql_test func-1.6 {
|
||||
SELECT octet_length(NULL);
|
||||
} {NULL}
|
||||
do_execsql_test func-1.7 {
|
||||
SELECT octet_length(7.5);
|
||||
} {3}
|
||||
do_execsql_test func-1.8 {
|
||||
SELECT octet_length(x'30313233');
|
||||
} {4}
|
||||
do_execsql_test func-1.9 {
|
||||
WITH c(x) AS (VALUES(char(350,351,352,353,354)))
|
||||
SELECT length(x), octet_length(x) FROM c;
|
||||
} {5 10}
|
||||
|
||||
|
||||
|
||||
# Check out the substr() function
|
||||
#
|
||||
db null {}
|
||||
do_test func-2.0 {
|
||||
execsql {SELECT substr(t1,1,2) FROM tbl1 ORDER BY t1}
|
||||
} {fr is pr so th}
|
||||
@@ -839,30 +862,13 @@ do_test func-18.11 {
|
||||
}
|
||||
} integer
|
||||
ifcapable floatingpoint {
|
||||
do_test func-18.12 {
|
||||
catchsql {
|
||||
INSERT INTO t6 VALUES(1<<62);
|
||||
SELECT sum(x) - ((1<<62)*2.0+1) from t6;
|
||||
}
|
||||
do_catchsql_test func-18.12 {
|
||||
INSERT INTO t6 VALUES(1<<62);
|
||||
SELECT sum(x) - ((1<<62)*2.0+1) from t6;
|
||||
} {1 {integer overflow}}
|
||||
do_test func-18.13 {
|
||||
execsql {
|
||||
SELECT total(x) - ((1<<62)*2.0+1) FROM t6
|
||||
}
|
||||
} 0.0
|
||||
}
|
||||
ifcapable !floatingpoint {
|
||||
do_test func-18.12 {
|
||||
catchsql {
|
||||
INSERT INTO t6 VALUES(1<<62);
|
||||
SELECT sum(x) - ((1<<62)*2+1) from t6;
|
||||
}
|
||||
} {1 {integer overflow}}
|
||||
do_test func-18.13 {
|
||||
execsql {
|
||||
SELECT total(x) - ((1<<62)*2+1) FROM t6
|
||||
}
|
||||
} 0.0
|
||||
do_catchsql_test func-18.13 {
|
||||
SELECT total(x) - ((1<<62)*2.0+1) FROM t6
|
||||
} {0 0.0}
|
||||
}
|
||||
if {[working_64bit_int]} {
|
||||
do_test func-18.14 {
|
||||
@@ -1520,6 +1526,22 @@ do_execsql_test func-36.110 {
|
||||
SELECT 123 ->> 456
|
||||
} {123->>456}
|
||||
|
||||
|
||||
# 2023-06-26
|
||||
# Enhanced precision of SUM().
|
||||
#
|
||||
reset_db
|
||||
do_catchsql_test func-37.100 {
|
||||
WITH c(x) AS (VALUES(9223372036854775807),(9223372036854775807),
|
||||
(123),(-9223372036854775807),(-9223372036854775807))
|
||||
SELECT sum(x) FROM c;
|
||||
} {1 {integer overflow}}
|
||||
do_catchsql_test func-37.110 {
|
||||
WITH c(x) AS (VALUES(9223372036854775807),(1))
|
||||
SELECT sum(x) FROM c;
|
||||
} {1 {integer overflow}}
|
||||
do_catchsql_test func-37.120 {
|
||||
WITH c(x) AS (VALUES(9223372036854775807),(10000),(-10010))
|
||||
SELECT sum(x) FROM c;
|
||||
} {1 {integer overflow}}
|
||||
|
||||
finish_test
|
||||
|
||||
+65
-4
@@ -55,11 +55,12 @@ proc get_cycles {stmt} {
|
||||
dict get $r nCycle
|
||||
}
|
||||
|
||||
proc foreach_scan {varname stmt body} {
|
||||
proc foreach_scan {varname stmt body {debug 0}} {
|
||||
upvar $varname var
|
||||
|
||||
for {set ii 0} {1} {incr ii} {
|
||||
set r [sqlite3_stmt_scanstatus -flags complex $stmt $ii]
|
||||
set f "complex"
|
||||
if {$debug} { set f "complex debug" }
|
||||
set r [sqlite3_stmt_scanstatus -flags $f $stmt $ii]
|
||||
if {[llength $r]==0} break
|
||||
array set var $r
|
||||
uplevel $body
|
||||
@@ -102,6 +103,15 @@ proc puts_graph {sql} {
|
||||
puts [string trim [get_graph $stmt]]
|
||||
}
|
||||
|
||||
proc puts_debug_info {sql} {
|
||||
db eval $sql
|
||||
set stmt [db version -last-stmt-ptr]
|
||||
foreach_scan X $stmt {
|
||||
puts -nonewline "$X(debug_explain) $X(zExplain): "
|
||||
puts -nonewline "loop=$X(debug_loop) visit=$X(debug_visit) "
|
||||
puts "csr=$X(debug_csr) range=$X(debug_range)"
|
||||
} 1
|
||||
}
|
||||
|
||||
do_zexplain_test 0 1.1 {
|
||||
SELECT (SELECT a FROM t1 WHERE b=x) FROM t2 WHERE y=2
|
||||
@@ -235,7 +245,7 @@ do_graph_test 4.5 {
|
||||
QUERY (nCycle=nnn)
|
||||
--CO-ROUTINE v1
|
||||
----SCAN rt2 (nCycle=nnn)
|
||||
----USE TEMP B-TREE FOR GROUP BY
|
||||
----USE TEMP B-TREE FOR GROUP BY (nCycle=nnn)
|
||||
--SCAN rt1 (nCycle=nnn)
|
||||
--CREATE AUTOMATIC INDEX ON v1(x1, cnt) (nCycle=nnn)
|
||||
--BLOOM FILTER ON v1 (x1=?)
|
||||
@@ -270,6 +280,57 @@ ifcapable trace {
|
||||
} {{SCAN t1} {SCAN t1} {SCAN t1}}
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
sqlite3_db_config db STMT_SCANSTATUS 1
|
||||
|
||||
do_execsql_test 6.0 {
|
||||
CREATE TABLE t1(a, b);
|
||||
INSERT INTO t1 VALUES(1, 'one');
|
||||
INSERT INTO t1 VALUES(2, 'two');
|
||||
INSERT INTO t1 VALUES(3, 'three');
|
||||
INSERT INTO t1 VALUES(4, 'four');
|
||||
INSERT INTO t1 VALUES(5, 'five');
|
||||
INSERT INTO t1 VALUES(6, 'six');
|
||||
INSERT INTO t1 VALUES(7, 'seven');
|
||||
INSERT INTO t1 VALUES(8, 'eight');
|
||||
}
|
||||
|
||||
do_graph_test 6.1 {
|
||||
SELECT (a % 2), group_concat(b) FROM t1 GROUP BY 1
|
||||
} {
|
||||
QUERY (nCycle=nnn)
|
||||
--SCAN t1 (nCycle=nnn)
|
||||
--USE TEMP B-TREE FOR GROUP BY (nCycle=nnn)
|
||||
}
|
||||
|
||||
set sql {
|
||||
WITH xy(x, y) AS ( SELECT (a % 2), group_concat(b) FROM t1 GROUP BY 1)
|
||||
SELECT * FROM xy WHERE x=1
|
||||
}
|
||||
do_graph_test 6.2 $sql {
|
||||
QUERY (nCycle=nnn)
|
||||
--CO-ROUTINE xy
|
||||
----SCAN t1 (nCycle=nnn)
|
||||
----USE TEMP B-TREE FOR GROUP BY (nCycle=nnn)
|
||||
--SCAN xy (nCycle=nnn)
|
||||
}
|
||||
|
||||
do_graph_test 6.3 {
|
||||
WITH xy(x, y) AS ( SELECT (a % 2), group_concat(b) FROM t1 GROUP BY 1)
|
||||
SELECT * FROM xy, xy AS xy2
|
||||
} {
|
||||
QUERY (nCycle=nnn)
|
||||
--MATERIALIZE xy (nCycle=nnn)
|
||||
----SCAN t1 (nCycle=nnn)
|
||||
----USE TEMP B-TREE FOR GROUP BY (nCycle=nnn)
|
||||
--SCAN xy (nCycle=nnn)
|
||||
--SCAN xy2 (nCycle=nnn)
|
||||
}
|
||||
|
||||
#explain_i { SELECT (a % 2), group_concat(b) FROM t1 GROUP BY 1 }
|
||||
#puts_debug_info { SELECT (a % 2), group_concat(b) FROM t1 GROUP BY 1 }
|
||||
|
||||
finish_test
|
||||
|
||||
|
||||
|
||||
@@ -262,5 +262,14 @@ do_test shell2-1.4.11 {
|
||||
SELECT count(*) FROM t;}]]
|
||||
} {0 1}
|
||||
|
||||
# Bug from forum post 7cbe081746dd3803
|
||||
# Keywords as column names were producing an error message.
|
||||
do_test shell2-1.4.12 {
|
||||
set res [catchcmd :memory: [string trim {
|
||||
CREATE TABLE "group"("order" text);
|
||||
INSERT INTO "group" VALUES ('ABC');
|
||||
.sha3sum}]]
|
||||
} {0 ca08bc02b7e95c7df431a3a4b1cc0f8d8743914793473f55b5558e03}
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
Reference in New Issue
Block a user