/ Check-in [83ab2501]
Login

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

Overview
Comment:More fixes and improvements to the zeroblob() mechanism. (CVS 3900)
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 83ab25014e890b1cc6ea08ca1ebeeee0078da466
User & Date: drh 2007-05-02 16:51:59
Context
2007-05-02
17:48
Combine the internal btree functions BtreePutData() and getPayload(). (CVS 3901) check-in: a100a530 user: danielk1977 tags: trunk
16:51
More fixes and improvements to the zeroblob() mechanism. (CVS 3900) check-in: 83ab2501 user: drh tags: trunk
16:48
Cache the location of overflow pages in cursors used for incremental blob IO. (CVS 3899) check-in: 349f1ea7 user: danielk1977 tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/test1.c.

9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
....
4345
4346
4347
4348
4349
4350
4351

4352
4353
4354
4355
4356
4357
4358
....
4538
4539
4540
4541
4542
4543
4544


4545
4546
4547
4548
4549
4550
4551
**    May you share freely, never taking more than you give.
**
*************************************************************************
** Code for testing all sorts of SQLite interfaces.  This code
** is not included in the SQLite library.  It is used for automated
** testing of the SQLite library.
**
** $Id: test1.c,v 1.241 2007/05/02 01:34:31 drh Exp $
*/
#include "sqliteInt.h"
#include "tcl.h"
#include "os.h"
#include <stdlib.h>
#include <string.h>

................................................................................
*/
int Sqlitetest1_Init(Tcl_Interp *interp){
  extern int sqlite3_search_count;
  extern int sqlite3_interrupt_count;
  extern int sqlite3_open_file_count;
  extern int sqlite3_sort_count;
  extern int sqlite3_current_time;

  static struct {
     char *zName;
     Tcl_CmdProc *xProc;
  } aCmd[] = {
     { "sqlite3_mprintf_int",           (Tcl_CmdProc*)sqlite3_mprintf_int    },
     { "sqlite3_mprintf_int64",         (Tcl_CmdProc*)sqlite3_mprintf_int64  },
     { "sqlite3_mprintf_str",           (Tcl_CmdProc*)sqlite3_mprintf_str    },
................................................................................
    Tcl_CreateObjCommand(interp, aObjCmd[i].zName, 
        aObjCmd[i].xProc, aObjCmd[i].clientData, 0);
  }
  Tcl_LinkVar(interp, "sqlite_search_count", 
      (char*)&sqlite3_search_count, TCL_LINK_INT);
  Tcl_LinkVar(interp, "sqlite_sort_count", 
      (char*)&sqlite3_sort_count, TCL_LINK_INT);


  Tcl_LinkVar(interp, "sqlite_like_count", 
      (char*)&sqlite3_like_count, TCL_LINK_INT);
  Tcl_LinkVar(interp, "sqlite_interrupt_count", 
      (char*)&sqlite3_interrupt_count, TCL_LINK_INT);
  Tcl_LinkVar(interp, "sqlite_open_file_count", 
      (char*)&sqlite3_open_file_count, TCL_LINK_INT);
  Tcl_LinkVar(interp, "sqlite_current_time", 







|







 







>







 







>
>







9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
....
4345
4346
4347
4348
4349
4350
4351
4352
4353
4354
4355
4356
4357
4358
4359
....
4539
4540
4541
4542
4543
4544
4545
4546
4547
4548
4549
4550
4551
4552
4553
4554
**    May you share freely, never taking more than you give.
**
*************************************************************************
** Code for testing all sorts of SQLite interfaces.  This code
** is not included in the SQLite library.  It is used for automated
** testing of the SQLite library.
**
** $Id: test1.c,v 1.242 2007/05/02 16:51:59 drh Exp $
*/
#include "sqliteInt.h"
#include "tcl.h"
#include "os.h"
#include <stdlib.h>
#include <string.h>

................................................................................
*/
int Sqlitetest1_Init(Tcl_Interp *interp){
  extern int sqlite3_search_count;
  extern int sqlite3_interrupt_count;
  extern int sqlite3_open_file_count;
  extern int sqlite3_sort_count;
  extern int sqlite3_current_time;
  extern int sqlite3_max_blobsize;
  static struct {
     char *zName;
     Tcl_CmdProc *xProc;
  } aCmd[] = {
     { "sqlite3_mprintf_int",           (Tcl_CmdProc*)sqlite3_mprintf_int    },
     { "sqlite3_mprintf_int64",         (Tcl_CmdProc*)sqlite3_mprintf_int64  },
     { "sqlite3_mprintf_str",           (Tcl_CmdProc*)sqlite3_mprintf_str    },
................................................................................
    Tcl_CreateObjCommand(interp, aObjCmd[i].zName, 
        aObjCmd[i].xProc, aObjCmd[i].clientData, 0);
  }
  Tcl_LinkVar(interp, "sqlite_search_count", 
      (char*)&sqlite3_search_count, TCL_LINK_INT);
  Tcl_LinkVar(interp, "sqlite_sort_count", 
      (char*)&sqlite3_sort_count, TCL_LINK_INT);
  Tcl_LinkVar(interp, "sqlite3_max_blobsize", 
      (char*)&sqlite3_max_blobsize, TCL_LINK_INT);
  Tcl_LinkVar(interp, "sqlite_like_count", 
      (char*)&sqlite3_like_count, TCL_LINK_INT);
  Tcl_LinkVar(interp, "sqlite_interrupt_count", 
      (char*)&sqlite3_interrupt_count, TCL_LINK_INT);
  Tcl_LinkVar(interp, "sqlite_open_file_count", 
      (char*)&sqlite3_open_file_count, TCL_LINK_INT);
  Tcl_LinkVar(interp, "sqlite_current_time", 

Changes to src/vdbe.c.

39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
..
80
81
82
83
84
85
86











87
88
89
90
91
92
93
....
1629
1630
1631
1632
1633
1634
1635


1636
1637
1638
1639
1640
1641
1642
....
2219
2220
2221
2222
2223
2224
2225

2226
2227
2228
2229
2230
2231
2232
2233

2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
....
2873
2874
2875
2876
2877
2878
2879
2880
2881
2882
2883
2884
2885
2886
2887
....
2980
2981
2982
2983
2984
2985
2986

2987
2988
2989
2990
2991
2992
2993
....
3047
3048
3049
3050
3051
3052
3053

3054
3055
3056
3057
3058
3059
3060
....
3898
3899
3900
3901
3902
3903
3904
3905
3906
3907

3908
3909
3910
3911
3912
3913
3914
....
4977
4978
4979
4980
4981
4982
4983










4984
4985
4986
4987
4988
4989
4990
....
4994
4995
4996
4997
4998
4999
5000

5001
5002
5003
5004
5005
5006
5007
**
** Various scripts scan this source file in order to generate HTML
** documentation, headers files, or other derived files.  The formatting
** of the code in this file is, therefore, important.  See other comments
** in this file for details.  If in doubt, do not deviate from existing
** commenting and indentation practices when changing or adding code.
**
** $Id: vdbe.c,v 1.604 2007/05/02 13:30:27 drh Exp $
*/
#include "sqliteInt.h"
#include "os.h"
#include <ctype.h>
#include "vdbeInt.h"

/*
................................................................................
** has no function other than to help verify the correct operation of the
** library.
*/
#ifdef SQLITE_TEST
int sqlite3_sort_count = 0;
#endif












/*
** Release the memory associated with the given stack level.  This
** leaves the Mem.flags field in an inconsistent state.
*/
#define Release(P) if((P)->flags&MEM_Dyn){ sqlite3VdbeMemRelease(P); }

/*
................................................................................
  affinity = pOp->p1 & 0xFF;
  if( affinity ){
    applyAffinity(pNos, affinity, encoding);
    applyAffinity(pTos, affinity, encoding);
  }

  assert( pOp->p3type==P3_COLLSEQ || pOp->p3==0 );


  res = sqlite3MemCompare(pNos, pTos, (CollSeq*)pOp->p3);
  switch( pOp->opcode ){
    case OP_Eq:    res = res==0;     break;
    case OP_Ne:    res = res!=0;     break;
    case OP_Lt:    res = res<0;      break;
    case OP_Le:    res = res<=0;     break;
    case OP_Gt:    res = res>0;      break;
................................................................................
  containsNull = 0;
  file_format = p->minWriteFileFormat;

  /* Loop through the elements that will make up the record to figure
  ** out how much space is required for the new record.
  */
  for(pRec=pData0; pRec<=pTos; pRec++){

    if( zAffinity ){
      applyAffinity(pRec, zAffinity[pRec-pData0], encoding);
    }
    if( pRec->flags&MEM_Null ){
      containsNull = 1;
    }
    serial_type = sqlite3VdbeSerialType(pRec, file_format);
    nData += sqlite3VdbeSerialTypeLen(serial_type);

    nHdr += sqlite3VarintLen(serial_type);
    if( pRec->flags & MEM_Zero ){
      /* Only pure zero-filled BLOBs can be input to this Opcode.
      ** We do not allow blobs with a prefix and a zero-filled tail. */
      assert( pRec->n==0 );
      nZero += pRec->u.i;
    }else{
      nZero = 0;
    }
  }

  /* If we have to append a varint rowid to this record, set pRowid
  ** to the value of the rowid and increase nByte by the amount of space
  ** required to store it.
................................................................................
      if( rc!=SQLITE_OK ){
        goto abort_due_to_error;
      }
      pC->lastRowid = pTos->u.i;
      pC->rowidIsValid = res==0;
    }else{
      assert( pTos->flags & MEM_Blob );
      /* Stringify(pTos, encoding); */
      rc = sqlite3BtreeMoveto(pC->pCursor, pTos->z, pTos->n, 0, &res);
      if( rc!=SQLITE_OK ){
        goto abort_due_to_error;
      }
      pC->rowidIsValid = 0;
    }
    pC->deferredMoveto = 0;
................................................................................
  Cursor *pC;
  assert( pTos>=p->aStack );
  assert( i>=0 && i<p->nCursor );
  assert( p->apCsr[i]!=0 );
  if( (pC = p->apCsr[i])->pCursor!=0 ){
    int res, rx;
    assert( pC->isTable==0 );

    Stringify(pTos, encoding);
    rx = sqlite3BtreeMoveto(pC->pCursor, pTos->z, pTos->n, 0, &res);
    alreadyExists = rx==SQLITE_OK && res==0;
    pC->deferredMoveto = 0;
    pC->cacheStatus = CACHE_STALE;
  }
  if( pOp->opcode==OP_Found ){
................................................................................
    char *zKey;    /* The value of K */
    int nKey;      /* Number of bytes in K */
    int len;       /* Number of bytes in K without the rowid at the end */
    int szRowid;   /* Size of the rowid column at the end of zKey */

    /* Make sure K is a string and make zKey point to K
    */

    Stringify(pNos, encoding);
    zKey = pNos->z;
    nKey = pNos->n;

    szRowid = sqlite3VdbeIdxRowidLen((u8*)zKey);
    len = nKey-szRowid;

................................................................................

  assert( i>=0 && i<p->nCursor );
  assert( p->apCsr[i]!=0 );
  assert( pTos>=p->aStack );
  if( (pC = p->apCsr[i])->pCursor!=0 ){
    int res;
 
    assert( pTos->flags & MEM_Blob );  /* Created using OP_Make*Key */
    Stringify(pTos, encoding);
    assert( pC->deferredMoveto==0 );

    *pC->pIncrKey = pOp->p3!=0;
    assert( pOp->p3==0 || pOp->opcode!=OP_IdxGT );
    rc = sqlite3VdbeIdxKeyCompare(pC, pTos->n, (u8*)pTos->z, &res);
    *pC->pIncrKey = 0;
    if( rc!=SQLITE_OK ){
      break;
    }
................................................................................
      pOp->cnt++;
#if 0
        fprintf(stdout, "%10lld ", elapse);
        sqlite3VdbePrintOp(stdout, origPc, &p->aOp[origPc]);
#endif
    }
#endif











    /* The following code adds nothing to the actual functionality
    ** of the program.  It is only here for testing and debugging.
    ** On the other hand, it does burn CPU cycles every time through
    ** the evaluator loop.  So we can leave it out when NDEBUG is defined.
    */
#ifndef NDEBUG
................................................................................
    ** cell, so avoid calling MemSanity() in this case.
    */
    if( pTos>=p->aStack && pTos->flags ){
      sqlite3VdbeMemSanity(pTos);
    }
    assert( pc>=-1 && pc<p->nOp );
#ifdef SQLITE_DEBUG

    /* Code for tracing the vdbe stack. */
    if( p->trace && pTos>=p->aStack ){
      int i;
      fprintf(p->trace, "Stack:");
      for(i=0; i>-5 && &pTos[i]>=p->aStack; i--){
        if( pTos[i].flags & MEM_Null ){
          fprintf(p->trace, " NULL");







|







 







>
>
>
>
>
>
>
>
>
>
>







 







>
>







 







>







|
>






|







 







|







 







>







 







>







 







|
<

>







 







>
>
>
>
>
>
>
>
>
>







 







>







39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
..
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
....
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
....
2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
....
2888
2889
2890
2891
2892
2893
2894
2895
2896
2897
2898
2899
2900
2901
2902
....
2995
2996
2997
2998
2999
3000
3001
3002
3003
3004
3005
3006
3007
3008
3009
....
3063
3064
3065
3066
3067
3068
3069
3070
3071
3072
3073
3074
3075
3076
3077
....
3915
3916
3917
3918
3919
3920
3921
3922

3923
3924
3925
3926
3927
3928
3929
3930
3931
....
4994
4995
4996
4997
4998
4999
5000
5001
5002
5003
5004
5005
5006
5007
5008
5009
5010
5011
5012
5013
5014
5015
5016
5017
....
5021
5022
5023
5024
5025
5026
5027
5028
5029
5030
5031
5032
5033
5034
5035
**
** Various scripts scan this source file in order to generate HTML
** documentation, headers files, or other derived files.  The formatting
** of the code in this file is, therefore, important.  See other comments
** in this file for details.  If in doubt, do not deviate from existing
** commenting and indentation practices when changing or adding code.
**
** $Id: vdbe.c,v 1.605 2007/05/02 16:51:59 drh Exp $
*/
#include "sqliteInt.h"
#include "os.h"
#include <ctype.h>
#include "vdbeInt.h"

/*
................................................................................
** has no function other than to help verify the correct operation of the
** library.
*/
#ifdef SQLITE_TEST
int sqlite3_sort_count = 0;
#endif

/*
** The next global variable records the size of the largest MEM_Blob
** or MEM_Str that has appeared on the VDBE stack.  The test procedures
** use this information to make sure that the zero-blob functionality
** is working correctly.   This variable has no function other than to
** help verify the correct operation of the library.
*/
#ifdef SQLITE_TEST
int sqlite3_max_blobsize = 0;
#endif

/*
** Release the memory associated with the given stack level.  This
** leaves the Mem.flags field in an inconsistent state.
*/
#define Release(P) if((P)->flags&MEM_Dyn){ sqlite3VdbeMemRelease(P); }

/*
................................................................................
  affinity = pOp->p1 & 0xFF;
  if( affinity ){
    applyAffinity(pNos, affinity, encoding);
    applyAffinity(pTos, affinity, encoding);
  }

  assert( pOp->p3type==P3_COLLSEQ || pOp->p3==0 );
  sqlite3VdbeMemExpandBlob(pNos);
  sqlite3VdbeMemExpandBlob(pTos);
  res = sqlite3MemCompare(pNos, pTos, (CollSeq*)pOp->p3);
  switch( pOp->opcode ){
    case OP_Eq:    res = res==0;     break;
    case OP_Ne:    res = res!=0;     break;
    case OP_Lt:    res = res<0;      break;
    case OP_Le:    res = res<=0;     break;
    case OP_Gt:    res = res>0;      break;
................................................................................
  containsNull = 0;
  file_format = p->minWriteFileFormat;

  /* Loop through the elements that will make up the record to figure
  ** out how much space is required for the new record.
  */
  for(pRec=pData0; pRec<=pTos; pRec++){
    int len;
    if( zAffinity ){
      applyAffinity(pRec, zAffinity[pRec-pData0], encoding);
    }
    if( pRec->flags&MEM_Null ){
      containsNull = 1;
    }
    serial_type = sqlite3VdbeSerialType(pRec, file_format);
    len = sqlite3VdbeSerialTypeLen(serial_type);
    nData += len;
    nHdr += sqlite3VarintLen(serial_type);
    if( pRec->flags & MEM_Zero ){
      /* Only pure zero-filled BLOBs can be input to this Opcode.
      ** We do not allow blobs with a prefix and a zero-filled tail. */
      assert( pRec->n==0 );
      nZero += pRec->u.i;
    }else if( len ){
      nZero = 0;
    }
  }

  /* If we have to append a varint rowid to this record, set pRowid
  ** to the value of the rowid and increase nByte by the amount of space
  ** required to store it.
................................................................................
      if( rc!=SQLITE_OK ){
        goto abort_due_to_error;
      }
      pC->lastRowid = pTos->u.i;
      pC->rowidIsValid = res==0;
    }else{
      assert( pTos->flags & MEM_Blob );
      sqlite3VdbeMemExpandBlob(pTos);
      rc = sqlite3BtreeMoveto(pC->pCursor, pTos->z, pTos->n, 0, &res);
      if( rc!=SQLITE_OK ){
        goto abort_due_to_error;
      }
      pC->rowidIsValid = 0;
    }
    pC->deferredMoveto = 0;
................................................................................
  Cursor *pC;
  assert( pTos>=p->aStack );
  assert( i>=0 && i<p->nCursor );
  assert( p->apCsr[i]!=0 );
  if( (pC = p->apCsr[i])->pCursor!=0 ){
    int res, rx;
    assert( pC->isTable==0 );
    assert( pTos->flags & MEM_Blob );
    Stringify(pTos, encoding);
    rx = sqlite3BtreeMoveto(pC->pCursor, pTos->z, pTos->n, 0, &res);
    alreadyExists = rx==SQLITE_OK && res==0;
    pC->deferredMoveto = 0;
    pC->cacheStatus = CACHE_STALE;
  }
  if( pOp->opcode==OP_Found ){
................................................................................
    char *zKey;    /* The value of K */
    int nKey;      /* Number of bytes in K */
    int len;       /* Number of bytes in K without the rowid at the end */
    int szRowid;   /* Size of the rowid column at the end of zKey */

    /* Make sure K is a string and make zKey point to K
    */
    assert( pNos->flags & MEM_Blob );
    Stringify(pNos, encoding);
    zKey = pNos->z;
    nKey = pNos->n;

    szRowid = sqlite3VdbeIdxRowidLen((u8*)zKey);
    len = nKey-szRowid;

................................................................................

  assert( i>=0 && i<p->nCursor );
  assert( p->apCsr[i]!=0 );
  assert( pTos>=p->aStack );
  if( (pC = p->apCsr[i])->pCursor!=0 ){
    int res;
 
    assert( pTos->flags & MEM_Blob );  /* Created using OP_MakeRecord */

    assert( pC->deferredMoveto==0 );
    sqlite3VdbeMemExpandBlob(pTos);
    *pC->pIncrKey = pOp->p3!=0;
    assert( pOp->p3==0 || pOp->opcode!=OP_IdxGT );
    rc = sqlite3VdbeIdxKeyCompare(pC, pTos->n, (u8*)pTos->z, &res);
    *pC->pIncrKey = 0;
    if( rc!=SQLITE_OK ){
      break;
    }
................................................................................
      pOp->cnt++;
#if 0
        fprintf(stdout, "%10lld ", elapse);
        sqlite3VdbePrintOp(stdout, origPc, &p->aOp[origPc]);
#endif
    }
#endif

#ifdef SQLITE_TEST
    /* Keep track of the size of the largest BLOB or STR that has appeared
    ** on the top of the VDBE stack.
    */
    if( pTos>=p->aStack && (pTos->flags & (MEM_Blob|MEM_Str))!=0
         && pTos->n>sqlite3_max_blobsize ){
      sqlite3_max_blobsize = pTos->n;
    }
#endif

    /* The following code adds nothing to the actual functionality
    ** of the program.  It is only here for testing and debugging.
    ** On the other hand, it does burn CPU cycles every time through
    ** the evaluator loop.  So we can leave it out when NDEBUG is defined.
    */
#ifndef NDEBUG
................................................................................
    ** cell, so avoid calling MemSanity() in this case.
    */
    if( pTos>=p->aStack && pTos->flags ){
      sqlite3VdbeMemSanity(pTos);
    }
    assert( pc>=-1 && pc<p->nOp );
#ifdef SQLITE_DEBUG

    /* Code for tracing the vdbe stack. */
    if( p->trace && pTos>=p->aStack ){
      int i;
      fprintf(p->trace, "Stack:");
      for(i=0; i>-5 && &pTos[i]>=p->aStack; i--){
        if( pTos[i].flags & MEM_Null ){
          fprintf(p->trace, " NULL");

Changes to test/zeroblob.test.

9
10
11
12
13
14
15
16
17
18
19
20
21


22
23
24
25



26
27
28

29
30
31
32
33
34




35

36
37
38
39

40
41
42
43
44
45




46

47
48
49
50

51
52
53
54
55
56
57














































58
#
#***********************************************************************
# This file implements regression tests for SQLite library.  The
# focus of this file is testing of the zero-filled blob functionality
# including the sqlite3_bind_zeroblob(), sqlite3_result_zeroblob(),
# and the built-in zeroblob() SQL function.
#
# $Id: zeroblob.test,v 1.1 2007/05/02 13:30:27 drh Exp $

set testdir [file dirname $argv0]
source $testdir/tester.tcl

# Create the database


#
do_test zeroblob-1.1 {
  execsql {
    CREATE TABLE t1(a,b,c,d);



    INSERT INTO t1 VALUES(1,2,3,zeroblob(10000));
    SELECT count(*) FROM t1;
  }

} {1}
do_test zeroblob-1.2 {
  execsql {
    SELECT length(d) FROM t1
  }
} {10000}




do_test zeroblob-1.3 {

  execsql {
    INSERT INTO t1 VALUES(2,3,zeroblob(10000),4);
    SELECT count(*) FROM t1;
  }

} {2}
do_test zeroblob-1.4 {
  execsql {
    SELECT length(c), length(d) FROM t1
  }
} {1 10000 10000 1}




do_test zeroblob-1.5 {

  execsql {
    INSERT INTO t1 VALUES(3,4,zeroblob(10000),zeroblob(10000));
    SELECT count(*) FROM t1;
  }

} {3}
do_test zeroblob-1.6 {
  execsql {
    SELECT length(c), length(d) FROM t1
  }
} {1 10000 10000 1 10000 10000}















































finish_test







|




|
>
>




>
>
>
|
<

>
|





>
>
>
>

>

|
<

>
|





>
>
>
>

>

|
<

>
|






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

9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47

48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63

64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
#
#***********************************************************************
# This file implements regression tests for SQLite library.  The
# focus of this file is testing of the zero-filled blob functionality
# including the sqlite3_bind_zeroblob(), sqlite3_result_zeroblob(),
# and the built-in zeroblob() SQL function.
#
# $Id: zeroblob.test,v 1.2 2007/05/02 16:51:59 drh Exp $

set testdir [file dirname $argv0]
source $testdir/tester.tcl

# When zeroblob() is used for the last field of a column, then the
# content of the zeroblob is never instantiated on the VDBE stack.
# But it does get inserted into the database correctly.
#
do_test zeroblob-1.1 {
  execsql {
    CREATE TABLE t1(a,b,c,d);
  }
  set ::sqlite3_max_blobsize 0
  execsql {
    INSERT INTO t1 VALUES(2,3,4,zeroblob(10000));

  }
  set ::sqlite3_max_blobsize
} {10}
do_test zeroblob-1.2 {
  execsql {
    SELECT length(d) FROM t1
  }
} {10000}

# If a non-NULL column follows the zeroblob, then the content of
# the zeroblob must be instantiated.
#
do_test zeroblob-1.3 {
  set ::sqlite3_max_blobsize 0
  execsql {
    INSERT INTO t1 VALUES(3,4,zeroblob(10000),5);

  }
  set ::sqlite3_max_blobsize
} {10010}
do_test zeroblob-1.4 {
  execsql {
    SELECT length(c), length(d) FROM t1
  }
} {1 10000 10000 1}

# Multiple zeroblobs can appear at the end of record.  No instantiation
# of the blob content occurs on the stack.
#
do_test zeroblob-1.5 {
  set ::sqlite3_max_blobsize 0
  execsql {
    INSERT INTO t1 VALUES(4,5,zeroblob(10000),zeroblob(10000));

  }
  set ::sqlite3_max_blobsize
} {11}
do_test zeroblob-1.6 {
  execsql {
    SELECT length(c), length(d) FROM t1
  }
} {1 10000 10000 1 10000 10000}

# NULLs can follow the zeroblob() or be intermixed with zeroblobs and
# no instantiation of the zeroblobs occurs on the stack.
#
do_test zeroblob-1.7 {
  set ::sqlite3_max_blobsize 0
  execsql {
    INSERT INTO t1 VALUES(5,zeroblob(10000),NULL,zeroblob(10000));
  }
  set ::sqlite3_max_blobsize
} {10}
do_test zeroblob-1.8 {
  execsql {
    SELECT length(b), length(d) FROM t1 WHERE a=5
  }
} {10000 10000}

# Comparisons against zeroblobs work.
#
do_test zeroblob-2.1 {
  execsql {
    SELECT a FROM t1 WHERE b=zeroblob(10000)
  }
} {5}

# Comparisons against zeroblobs work even when indexed.
#
do_test zeroblob-2.2 {
  execsql {
    CREATE INDEX i1_1 ON t1(b);
    SELECT a FROM t1 WHERE b=zeroblob(10000);
  }
} {5}

# DISTINCT works for zeroblobs
#
do_test zeroblob-3.1 {
  execsql {
    SELECT count(DISTINCT a) FROM (
      SELECT x'00000000000000000000' AS a
      UNION ALL
      SELECT zeroblob(10) AS a
    )
  }
} {1}
  

finish_test