SQLite4
Check-in [ba34125233]
Not logged in

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Change various things to use sqlite4_num instead of double.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | sqlite4-num
Files: files | file ages | folders
SHA1: ba341252335cbe112540a59564c4a59a58b1955b
User & Date: dan 2013-05-30 18:26:49
Context
2013-05-30
19:01
Use the same code to encode keys for rowid indexes as regular indexes. check-in: 9265ac66c8 user: dan tags: sqlite4-num
18:26
Change various things to use sqlite4_num instead of double. check-in: ba34125233 user: dan tags: sqlite4-num
2013-05-29
18:52
Further progress on this. src4.test is now passing again. check-in: 9cf2ab46f5 user: dan tags: sqlite4-num
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/vdbe.c.

1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
....
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
** has REAL affinity.  Such column values may still be stored as
** integers, for space efficiency, but after extraction we want them
** to have only a real value.
*/
case OP_RealAffinity: {                  /* in1 */
  pIn1 = &aMem[pOp->p1];
  if( pIn1->flags & MEM_Int ){
    sqlite4VdbeMemRealify(pIn1);
  }
  break;
}
#endif

#ifndef SQLITE4_OMIT_CAST
/* Opcode: ToText P1 * * * *
................................................................................
case OP_If:                 /* jump, in1 */
case OP_IfNot: {            /* jump, in1 */
  int c;
  pIn1 = &aMem[pOp->p1];
  if( pIn1->flags & MEM_Null ){
    c = pOp->p3;
  }else{
#ifdef SQLITE4_OMIT_FLOATING_POINT
    c = sqlite4VdbeIntValue(pIn1)!=0;
#else
    c = sqlite4VdbeRealValue(pIn1)!=0.0;
#endif
    if( pOp->opcode==OP_IfNot ) c = !c;
  }
  if( c ){
    pc = pOp->p2-1;
  }
  break;
}







|







 







<
|
<
<
<







1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
....
2038
2039
2040
2041
2042
2043
2044

2045



2046
2047
2048
2049
2050
2051
2052
** has REAL affinity.  Such column values may still be stored as
** integers, for space efficiency, but after extraction we want them
** to have only a real value.
*/
case OP_RealAffinity: {                  /* in1 */
  pIn1 = &aMem[pOp->p1];
  if( pIn1->flags & MEM_Int ){
    MemSetTypeFlag(pIn1, MEM_Real);
  }
  break;
}
#endif

#ifndef SQLITE4_OMIT_CAST
/* Opcode: ToText P1 * * * *
................................................................................
case OP_If:                 /* jump, in1 */
case OP_IfNot: {            /* jump, in1 */
  int c;
  pIn1 = &aMem[pOp->p1];
  if( pIn1->flags & MEM_Null ){
    c = pOp->p3;
  }else{

    c = sqlite4VdbeNumValue(pIn1).m!=0;



    if( pOp->opcode==OP_IfNot ) c = !c;
  }
  if( c ){
    pc = pOp->p2-1;
  }
  break;
}

Changes to src/vdbeInt.h.

407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
int sqlite4VdbeMemMakeWriteable(Mem*);
int sqlite4VdbeMemStringify(Mem*, int);
i64 sqlite4VdbeIntValue(Mem*);
int sqlite4VdbeMemIntegerify(Mem*);
double sqlite4VdbeRealValue(Mem*);
sqlite4_num sqlite4VdbeNumValue(Mem *);
void sqlite4VdbeIntegerAffinity(Mem*);
int sqlite4VdbeMemRealify(Mem*);
int sqlite4VdbeMemNumerify(Mem*);
void sqlite4VdbeMemSetRowSet(Mem *pMem);

void sqlite4VdbeMemRelease(Mem *p);
void sqlite4VdbeMemReleaseExternal(Mem *p);
#define VdbeMemRelease(X)  \
  if((X)->flags&(MEM_Agg|MEM_Dyn|MEM_RowSet|MEM_Frame)) \







<







407
408
409
410
411
412
413

414
415
416
417
418
419
420
int sqlite4VdbeMemMakeWriteable(Mem*);
int sqlite4VdbeMemStringify(Mem*, int);
i64 sqlite4VdbeIntValue(Mem*);
int sqlite4VdbeMemIntegerify(Mem*);
double sqlite4VdbeRealValue(Mem*);
sqlite4_num sqlite4VdbeNumValue(Mem *);
void sqlite4VdbeIntegerAffinity(Mem*);

int sqlite4VdbeMemNumerify(Mem*);
void sqlite4VdbeMemSetRowSet(Mem *pMem);

void sqlite4VdbeMemRelease(Mem *p);
void sqlite4VdbeMemReleaseExternal(Mem *p);
#define VdbeMemRelease(X)  \
  if((X)->flags&(MEM_Agg|MEM_Dyn|MEM_RowSet|MEM_Frame)) \

Changes to src/vdbecodec.c.

132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
...
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
...
527
528
529
530
531
532
533









534
535
536
537
538
539
540
...
546
547
548
549
550
551
552

553
554
555
556
557
558
559
...
565
566
567
568
569
570
571

572
573
574
575
576


577
578
579
580

581
582
583
584
585
586
587













588











589


590
591
592






593





594
595

596
597









598
599
600

601
602
603
604
605
606
607
...
848
849
850
851
852
853
854


855
856
857
858
859
860
861
      num.m = x;
      num.e = (e >> 2);
      if( e & 0x02 ) num.e = -1 * num.e;
      if( e & 0x01 ) num.sign = 1;
      pOut->u.num = num;
      MemSetTypeFlag(pOut, MEM_Real);

#if 0
      double r = (double)x;
      if( e&1 ) r = -r;
      if( e&2 ){
        e = -(e>>2);
        if( e==0 ){
          r *= 1e+300*1e+300;
        }else{
          while( e<=-10 ){ r /= 1.0e10; e += 10; }
          while( e<0 ){ r /= 10.0; e++; }
        }
      }else{
        e = e>>2;
        while( e>=10 ){ r *= 1.0e10; e -= 10; }
        while( e>0 ){ r *= 10.0; e--; }
      }
      sqlite4VdbeMemSetDouble(pOut, r);
#endif

    }else if( cclass==0 ){
      if( size==0 ){
        sqlite4VdbeMemSetStr(pOut, "", 0, SQLITE4_UTF8, SQLITE4_TRANSIENT, 0);
      }else if( p->a[ofst]>0x02 ){
        sqlite4VdbeMemSetStr(pOut, (char*)(p->a+ofst), size, 
                             SQLITE4_UTF8, SQLITE4_TRANSIENT, 0);
      }else{
................................................................................
      n = significantBytes(i1);
      aOut[nOut++] = n+2;
      nPayload += n;
      aAux[i].n = n;
    }else if( flags & MEM_Real ){
      sqlite4_num *p = &aIn[i].u.num;
      int e;

      assert( p->sign==0 || p->sign==1 );
      if( p->e<0 ){
        e = (p->e*-4) + 2 + p->sign;
      }else{
        e = (p->e*4) + p->sign;
      }


#if 0
      sqlite4_num_to_double(aIn[i].u.num, &r);
      if( sqlite4IsNaN(r) ){
        m = 0;
        e = 2;
      }else if( sqlite4IsInf(r)!=0 ){
        m = 1;
        e = 2 + (sqlite4IsInf(r)<0);
      }else{
        if( r<0 ){ r = -r; sign = 1; }
        while( r<1.0e+19 && r!=(sqlite4_uint64)r ){
          e--;
          r *= 10.0;
        }
        while( r>1.8e+19 ){
          e++;
          r /= 10.0;
        }
        m = r;
        if( e<0 ){
          e = (-e*4) + 2 + sign;
        }else{
          e = e*4 + sign;
        }
      }
#endif

      n = sqlite4PutVarint64(aAux[i].z, (sqlite4_uint64)e);
      n += sqlite4PutVarint64(aAux[i].z+n, p->m);
      aAux[i].n = n;
      aOut[nOut++] = n+9;
      nPayload += n;
    }else if( flags & MEM_Str ){
      n = aIn[i].n;
................................................................................
    p->aOut[p->nOut++] = 2*d + 1;
    r -= d;
  }
  p->aOut[p->nOut-1] &= 0xfe;
  return e;
}











/*
** Encode a single column of the key
*/
static int encodeOneKeyValue(
  KeyEncoder *p,    /* Key encoder context */
  Mem *pMem,        /* Value to be encoded */
................................................................................
  int i, e;
  int n;
  int iStart = p->nOut;
  if( flags & MEM_Null ){
    if( enlargeEncoderAllocation(p, 1) ) return SQLITE4_NOMEM;
    p->aOut[p->nOut++] = 0x05;   /* NULL */
  }else

  if( flags & MEM_Int ){
    sqlite4_int64 v;
    sqlite4_num_to_int64(pMem->u.num, &v);
    if( enlargeEncoderAllocation(p, 11) ) return SQLITE4_NOMEM;
    if( v==0 ){
      p->aOut[p->nOut++] = 0x15;  /* Numeric zero */
    }else if( v<0 ){
................................................................................
    }else{
      i = p->nOut;
      p->aOut[p->nOut++] = 0x22;  /* Large positive number */
      e = encodeIntKey((sqlite4_uint64)v, p);
      if( e<=10 ) p->aOut[i] = 0x17+e;
    }
  }else

  if( flags & MEM_Real ){
    double r;
    sqlite4_num_to_double(pMem->u.num, &r);
    if( enlargeEncoderAllocation(p, 16) ) return SQLITE4_NOMEM;
    if( r==0.0 ){


      p->aOut[p->nOut++] = 0x15;  /* Numeric zero */
    }else if( sqlite4IsNaN(r) ){
      p->aOut[p->nOut++] = 0x06;  /* NaN */
    }else if( (n = sqlite4IsInf(r))!=0 ){

      p->aOut[p->nOut++] = n<0 ? 0x07 : 0x23;  /* Neg and Pos infinity */
    }else if( r<=-1.0 ){
      p->aOut[p->nOut++] = 0x08;  /* Large negative values */
      i = p->nOut;
      e = encodeLargeFloatKey(-r, p);
      if( e<=10 ) p->aOut[i-1] = 0x13-e;
      while( i<p->nOut ) p->aOut[i++] ^= 0xff;













    }else if( r<0.0 ){











      p->aOut[p->nOut++] = 0x14;  /* Small negative values */


      i = p->nOut;
      encodeSmallFloatKey(-r, p);
      while( i<p->nOut ) p->aOut[i++] ^= 0xff;






    }else if( r<1.0 ){





      p->aOut[p->nOut++] = 0x16;  /* Small positive values */
      encodeSmallFloatKey(r, p);

    }else{
      i = p->nOut;









      p->aOut[p->nOut++] = 0x22;  /* Large positive values */
      e = encodeLargeFloatKey(r, p);
      if( e<=10 ) p->aOut[i] = 0x17+e;

    }
  }else
  if( flags & MEM_Str ){
    Mem *pEnc;                    /* Pointer to memory cell in correct enc. */
    Mem sMem;                     /* Value converted to different encoding */
    int enc;                      /* Required encoding */

................................................................................
  }
  m = 0;
  i = 1;
  do{
    m = m*100 + aKey[i]/2;
    e--;
  }while( aKey[i++] & 1 );


  if( isNeg ){
    *pVal = -m;
  }else{
    *pVal = m;
  }
  return m==0 ? 0 : i;
}







<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







 







<






<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







 







>
>
>
>
>
>
>
>
>







 







>







 







>
|
<
|

<
>
>

|

<
>
|
|
<
|
|
|
|
>
>
>
>
>
>
>
>
>
>
>
>
>
|
>
>
>
>
>
>
>
>
>
>
>
|
>
>
|
<
<
>
>
>
>
>
>
|
>
>
>
>
>
|
<
>
|
|
>
>
>
>
>
>
>
>
>
|
<
<
>







 







>
>







132
133
134
135
136
137
138



















139
140
141
142
143
144
145
...
227
228
229
230
231
232
233

234
235
236
237
238
239





























240
241
242
243
244
245
246
...
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
...
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
...
526
527
528
529
530
531
532
533
534

535
536

537
538
539
540
541

542
543
544

545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577


578
579
580
581
582
583
584
585
586
587
588
589
590

591
592
593
594
595
596
597
598
599
600
601
602
603


604
605
606
607
608
609
610
611
...
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
      num.m = x;
      num.e = (e >> 2);
      if( e & 0x02 ) num.e = -1 * num.e;
      if( e & 0x01 ) num.sign = 1;
      pOut->u.num = num;
      MemSetTypeFlag(pOut, MEM_Real);




















    }else if( cclass==0 ){
      if( size==0 ){
        sqlite4VdbeMemSetStr(pOut, "", 0, SQLITE4_UTF8, SQLITE4_TRANSIENT, 0);
      }else if( p->a[ofst]>0x02 ){
        sqlite4VdbeMemSetStr(pOut, (char*)(p->a+ofst), size, 
                             SQLITE4_UTF8, SQLITE4_TRANSIENT, 0);
      }else{
................................................................................
      n = significantBytes(i1);
      aOut[nOut++] = n+2;
      nPayload += n;
      aAux[i].n = n;
    }else if( flags & MEM_Real ){
      sqlite4_num *p = &aIn[i].u.num;
      int e;

      assert( p->sign==0 || p->sign==1 );
      if( p->e<0 ){
        e = (p->e*-4) + 2 + p->sign;
      }else{
        e = (p->e*4) + p->sign;
      }





























      n = sqlite4PutVarint64(aAux[i].z, (sqlite4_uint64)e);
      n += sqlite4PutVarint64(aAux[i].z+n, p->m);
      aAux[i].n = n;
      aOut[nOut++] = n+9;
      nPayload += n;
    }else if( flags & MEM_Str ){
      n = aIn[i].n;
................................................................................
    p->aOut[p->nOut++] = 2*d + 1;
    r -= d;
  }
  p->aOut[p->nOut-1] &= 0xfe;
  return e;
}

static void putVarint64(KeyEncoder *p, sqlite4_uint64 v, int bInvert){
  unsigned char *z = &p->aOut[p->nOut];
  int n = sqlite4PutVarint64(z, v);
  if( bInvert ){
    int i;
    for(i=0; i<n; i++) z[i] = ~z[i];
  }
  p->nOut += n;
}

/*
** Encode a single column of the key
*/
static int encodeOneKeyValue(
  KeyEncoder *p,    /* Key encoder context */
  Mem *pMem,        /* Value to be encoded */
................................................................................
  int i, e;
  int n;
  int iStart = p->nOut;
  if( flags & MEM_Null ){
    if( enlargeEncoderAllocation(p, 1) ) return SQLITE4_NOMEM;
    p->aOut[p->nOut++] = 0x05;   /* NULL */
  }else
#if 0
  if( flags & MEM_Int ){
    sqlite4_int64 v;
    sqlite4_num_to_int64(pMem->u.num, &v);
    if( enlargeEncoderAllocation(p, 11) ) return SQLITE4_NOMEM;
    if( v==0 ){
      p->aOut[p->nOut++] = 0x15;  /* Numeric zero */
    }else if( v<0 ){
................................................................................
    }else{
      i = p->nOut;
      p->aOut[p->nOut++] = 0x22;  /* Large positive number */
      e = encodeIntKey((sqlite4_uint64)v, p);
      if( e<=10 ) p->aOut[i] = 0x17+e;
    }
  }else
#endif
  if( flags & (MEM_Real|MEM_Int) ){

    sqlite4_num num = pMem->u.num;
    if( enlargeEncoderAllocation(p, 16) ) return SQLITE4_NOMEM;


    if( num.m==0 ){
      p->aOut[p->nOut++] = 0x15;  /* Numeric zero */
    }else if( sqlite4_num_isnan(num) ){
      p->aOut[p->nOut++] = 0x06;  /* NaN */

    }else if( sqlite4_num_isinf(num) ){
      p->aOut[p->nOut++] = num.sign ? 0x07 : 0x23;  /* Neg and Pos infinity */
    }else{

      int e;
      u64 m;
      int iDigit = 0;
      u8 aDigit[12];

      while( (num.m % 10)==0 ){
        num.e++;
        num.m = num.m / 10;
      }
      m = num.m;
      e = num.e;

      if( num.e % 2 ){
        aDigit[0] = 10 * (m % 10);
        m = m / 10;
        e--;
        iDigit = 1;
      }else{
        iDigit = 0;
      }

      while( m ){
        aDigit[iDigit++] = (m % 100);
        m = m / 100;
      }
      e = (iDigit + (e/2));

      if( e>11 ){                 /* Large value */
        if( num.sign==0 ){
          p->aOut[p->nOut++] = 0x22;
          putVarint64(p, e, 0);
        }else{
          p->aOut[p->nOut++] = 0x08;


          putVarint64(p, e, 1);
        }
      }
      else if( e>=0 ){            /* Medium value */
        if( num.sign==0 ){
          p->aOut[p->nOut++] = 0x17+e;
        }else{
          p->aOut[p->nOut++] = 0x13-e;
        }
      }
      else{                       /* Small value */
        if( num.sign==0 ){
          p->aOut[p->nOut++] = 0x16;

          putVarint64(p, -1*e, 1);
        }else{
          p->aOut[p->nOut++] = 0x14;
          putVarint64(p, -1*e, 0);
        }
      }

      /* Write M to the output. */
      while( (iDigit--)>0 ){
        u8 d = aDigit[iDigit]*2;
        if( iDigit!=0 ) d |= 0x01;
        if( num.sign ) d = ~d;
        p->aOut[p->nOut++] = d;


      }
    }
  }else
  if( flags & MEM_Str ){
    Mem *pEnc;                    /* Pointer to memory cell in correct enc. */
    Mem sMem;                     /* Value converted to different encoding */
    int enc;                      /* Required encoding */

................................................................................
  }
  m = 0;
  i = 1;
  do{
    m = m*100 + aKey[i]/2;
    e--;
  }while( aKey[i++] & 1 );
  while( (e--)>0 ){ m = m*100; }

  if( isNeg ){
    *pVal = -m;
  }else{
    *pVal = m;
  }
  return m==0 ? 0 : i;
}

Changes to src/vdbemem.c.

334
335
336
337
338
339
340

341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
...
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
/*
** Return the best representation of pMem that we can get into a
** double.  If pMem is already a double or an integer, return its
** value.  If it is a string or blob, try to convert it to a double.
** If it is a NULL, return 0.0.
*/
double sqlite4VdbeRealValue(Mem *pMem){

  assert( pMem->db==0 || sqlite4_mutex_held(pMem->db->mutex) );
  assert( EIGHT_BYTE_ALIGNMENT(pMem) );
  if( pMem->flags & (MEM_Real|MEM_Int) ){
    double r;
    sqlite4_num_to_double(pMem->u.num, &r);
    return r;
  }else if( pMem->flags & (MEM_Str|MEM_Blob) ){
    /* (double)0 In case of SQLITE4_OMIT_FLOATING_POINT... */
    double val = (double)0;
    sqlite4AtoF(pMem->z, &val, pMem->n, pMem->enc);
    return val;
  }else{
    /* (double)0 In case of SQLITE4_OMIT_FLOATING_POINT... */
    return (double)0;
  }
}

/*
** Extract and return a numeric value from memory cell pMem. This call
** does not modify the contents or flags of *pMem in any way.
*/
sqlite4_num sqlite4VdbeNumValue(Mem *pMem){
................................................................................
    }
  }

  MemSetTypeFlag(pMem, MEM_Int);
  return SQLITE4_OK;
}

/*
** Convert pMem so that it is of type MEM_Real.
** Invalidate any prior representations.
*/
int sqlite4VdbeMemRealify(Mem *pMem){
  assert( pMem->db==0 || sqlite4_mutex_held(pMem->db->mutex) );
  assert( EIGHT_BYTE_ALIGNMENT(pMem) );

  pMem->u.num = sqlite4_num_from_double(sqlite4VdbeRealValue(pMem));
  MemSetTypeFlag(pMem, MEM_Real);
  return SQLITE4_OK;
}

/*
** Convert pMem so that it has types MEM_Real or MEM_Int or both.
** Invalidate any prior representations.
**
** Every effort is made to force the conversion, even if the input
** is a string that does not look completely like a number.  Convert
** as much of the string as we can and ignore the rest.







>


<
<
|
|
<
<
<
<
<
<
<
<
<







 







<
<
<
<
<
<
<
<
<
<
<
<
<







334
335
336
337
338
339
340
341
342
343


344
345









346
347
348
349
350
351
352
...
415
416
417
418
419
420
421













422
423
424
425
426
427
428
/*
** Return the best representation of pMem that we can get into a
** double.  If pMem is already a double or an integer, return its
** value.  If it is a string or blob, try to convert it to a double.
** If it is a NULL, return 0.0.
*/
double sqlite4VdbeRealValue(Mem *pMem){
  double rVal = 0.0;
  assert( pMem->db==0 || sqlite4_mutex_held(pMem->db->mutex) );
  assert( EIGHT_BYTE_ALIGNMENT(pMem) );


  sqlite4_num_to_double(sqlite4VdbeNumValue(pMem), &rVal);
  return rVal;









}

/*
** Extract and return a numeric value from memory cell pMem. This call
** does not modify the contents or flags of *pMem in any way.
*/
sqlite4_num sqlite4VdbeNumValue(Mem *pMem){
................................................................................
    }
  }

  MemSetTypeFlag(pMem, MEM_Int);
  return SQLITE4_OK;
}














/*
** Convert pMem so that it has types MEM_Real or MEM_Int or both.
** Invalidate any prior representations.
**
** Every effort is made to force the conversion, even if the input
** is a string that does not look completely like a number.  Convert
** as much of the string as we can and ignore the rest.

Changes to test/simple.test.

1500
1501
1502
1503
1504
1505
1506
1507



























1508
1509
do_execsql_test 76.4 {
  CREATE TABLE t2(a REAL, str);
}
do_execsql_test 76.5 {
  INSERT INTO t2 VALUES(0.0012345, '');
}
do_execsql_test 76.6 { SELECT cast(a AS TEXT) FROM t2 } {0.0012345}




























finish_test









>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>


1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
do_execsql_test 76.4 {
  CREATE TABLE t2(a REAL, str);
}
do_execsql_test 76.5 {
  INSERT INTO t2 VALUES(0.0012345, '');
}
do_execsql_test 76.6 { SELECT cast(a AS TEXT) FROM t2 } {0.0012345}

#-------------------------------------------------------------------------
# Integer keys.
#
reset_db
do_execsql_test 77.1 { CREATE TABLE t1(x) }
do_test 77.2 {
  for {set i 0} {$i < 99} {incr i} {
    execsql { INSERT INTO t1 VALUES(NULL) }
  }
} {}
do_execsql_test 77.3 { INSERT INTO t1 VALUES(NULL) }
do_execsql_test 77.4 { INSERT INTO t1 VALUES(NULL) }

#-------------------------------------------------------------------------
#
reset_db
do_test 78.1 {
  execsql {
    CREATE TABLE t1 (id INTEGER PRIMARY KEY, v);
    INSERT INTO t1 VALUES(42, 3);
  }
} {}

do_execsql_test 78.2 {
    SELECT id, v FROM t1 WHERE id>1.5;
} {42 3}

finish_test