/ Check-in [67f8af37]
Login

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

Overview
Comment:file format change (CVS 120)
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 67f8af377c8a92ac155f55afc75e9957bec4e787
User & Date: drh 2000-08-02 12:26:29
Context
2000-08-02
12:37
file format change (CVS 121) check-in: 4110936f user: drh tags: trunk
12:26
file format change (CVS 120) check-in: 67f8af37 user: drh tags: trunk
2000-08-01
09:56
fix parser stack overflow (CVS 119) check-in: bffca90f user: drh tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/dbbe.c.

26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
...
625
626
627
628
629
630
631

632
633
634
635
636
637
638
** sqlite and the code that does the actually reading and writing
** of information to the disk.
**
** This file uses GDBM as the database backend.  It should be
** relatively simple to convert to a different database such
** as NDBM, SDBM, or BerkeleyDB.
**
** $Id: dbbe.c,v 1.17 2000/07/31 13:38:26 drh Exp $
*/
#include "sqliteInt.h"
#include <gdbm.h>
#include <sys/stat.h>
#include <unistd.h>
#include <ctype.h>
#include <time.h>
................................................................................
  if( pCursr->pFile==0 || pCursr->pFile->dbf==0 ) return 1;
  pRc4 = &pCursr->pBe->rc4;
  while( go ){
    iKey = 0;
    for(i=0; i<4; i++){
      iKey = (iKey<<8) + rc4byte(pRc4);
    }

    key.dptr = (char*)&iKey;
    key.dsize = 4;
    go = gdbm_exists(pCursr->pFile->dbf, key);
  }
  return iKey;
}   








|







 







>







26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
...
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
** sqlite and the code that does the actually reading and writing
** of information to the disk.
**
** This file uses GDBM as the database backend.  It should be
** relatively simple to convert to a different database such
** as NDBM, SDBM, or BerkeleyDB.
**
** $Id: dbbe.c,v 1.18 2000/08/02 12:26:29 drh Exp $
*/
#include "sqliteInt.h"
#include <gdbm.h>
#include <sys/stat.h>
#include <unistd.h>
#include <ctype.h>
#include <time.h>
................................................................................
  if( pCursr->pFile==0 || pCursr->pFile->dbf==0 ) return 1;
  pRc4 = &pCursr->pBe->rc4;
  while( go ){
    iKey = 0;
    for(i=0; i<4; i++){
      iKey = (iKey<<8) + rc4byte(pRc4);
    }
    if( iKey==0 ) continue;
    key.dptr = (char*)&iKey;
    key.dsize = 4;
    go = gdbm_exists(pCursr->pFile->dbf, key);
  }
  return iKey;
}   

Changes to src/sqliteInt.h.

19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
...
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
** Author contact information:
**   drh@hwaci.com
**   http://www.hwaci.com/drh/
**
*************************************************************************
** Internal interface definitions for SQLite.
**
** @(#) $Id: sqliteInt.h,v 1.27 2000/07/29 13:06:59 drh Exp $
*/
#include "sqlite.h"
#include "dbbe.h"
#include "vdbe.h"
#include "parse.h"
#include <gdbm.h>
#include <stdio.h>
................................................................................
/*
** Each database is an instance of the following structure
*/
struct sqlite {
  Dbbe *pBe;                 /* The backend driver */
  int flags;                 /* Miscellanous flags */
  void *pBusyArg;            /* 1st Argument to the busy callback */
  int (*xBusyCallback)(void *,const char*,int);
  Table *apTblHash[N_HASH];  /* All tables of the database */
  Index *apIdxHash[N_HASH];  /* All indices of the database */
};

/*
** Possible values for the sqlite.flags.
*/







|







 







|







19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
...
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
** Author contact information:
**   drh@hwaci.com
**   http://www.hwaci.com/drh/
**
*************************************************************************
** Internal interface definitions for SQLite.
**
** @(#) $Id: sqliteInt.h,v 1.28 2000/08/02 12:26:29 drh Exp $
*/
#include "sqlite.h"
#include "dbbe.h"
#include "vdbe.h"
#include "parse.h"
#include <gdbm.h>
#include <stdio.h>
................................................................................
/*
** Each database is an instance of the following structure
*/
struct sqlite {
  Dbbe *pBe;                 /* The backend driver */
  int flags;                 /* Miscellanous flags */
  void *pBusyArg;            /* 1st Argument to the busy callback */
  int (*xBusyCallback)(void *,const char*,int);  /* The busy callback */
  Table *apTblHash[N_HASH];  /* All tables of the database */
  Index *apIdxHash[N_HASH];  /* All indices of the database */
};

/*
** Possible values for the sqlite.flags.
*/

Changes to src/vdbe.c.

37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
....
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148






2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
....
2189
2190
2191
2192
2193
2194
2195


2196

2197
2198

2199
2200
2201
2202
2203




















2204
2205
2206
2207
2208
2209
2210
....
2225
2226
2227
2228
2229
2230
2231
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
** inplicit conversion from one type to the other occurs as necessary.
** 
** Most of the code in this file is taken up by the sqliteVdbeExec()
** function which does the work of interpreting a VDBE program.
** But other routines are also provided to help in building up
** a program instruction by instruction.
**
** $Id: vdbe.c,v 1.37 2000/07/30 20:04:43 drh Exp $
*/
#include "sqliteInt.h"
#include <unistd.h>

/*
** SQL is translated into a sequence of instructions to be
** executed by a virtual machine.  Each instruction is an instance
................................................................................
        DbbeCursor *pCrsr;

        if( NeedStack(p, p->tos) ) goto no_mem;
        p->zStack[tos] = 0;
        if( i>=0 && i<p->nCursor && (pCrsr = p->aCsr[i].pCursor)!=0 ){
          int *aIdx;
          int nIdx;
          int j;
          nIdx = sqliteDbbeDataLength(pCrsr)/sizeof(int);
          aIdx = (int*)sqliteDbbeReadData(pCrsr, 0);






          for(j=p->aCsr[i].index; j<nIdx; j++){
            if( aIdx[j]!=0 ){
              p->aStack[tos].i = aIdx[j];
              p->aStack[tos].flags = STK_Int;
              break;
            }
          }
          if( j>=nIdx ){
            j = -1;
            pc = pOp->p2 - 1;
            PopStack(p, 1);
          }
          p->aCsr[i].index = j+1;
        }
        break;
................................................................................
            /* Create a new record for this index */
            sqliteDbbePut(pCrsr, p->aStack[tos].n, p->zStack[tos],
                          sizeof(int), (char*)&newVal);
          }else{
            /* Extend the existing record */
            int nIdx;
            int *aIdx;


            nIdx = sqliteDbbeDataLength(pCrsr)/sizeof(int);

            aIdx = sqliteMalloc( sizeof(int)*(nIdx+1) );
            if( aIdx==0 ) goto no_mem;

            sqliteDbbeCopyData(pCrsr, 0, nIdx*sizeof(int), (char*)aIdx);
            aIdx[nIdx] = newVal;
            sqliteDbbePut(pCrsr, p->aStack[tos].n, p->zStack[tos],
                          sizeof(int)*(nIdx+1), (char*)aIdx);
            sqliteFree(aIdx);




















          }
        }
        PopStack(p, 2);
        break;
      }

      /* Opcode: DeleteIdx P1 * *
................................................................................
        int tos = p->tos;
        int nos = tos - 1;
        DbbeCursor *pCrsr;
        if( nos<0 ) goto not_enough_stack;
        if( i>=0 && i<p->nCursor && (pCrsr = p->aCsr[i].pCursor)!=0 ){
          int *aIdx;
          int nIdx;
          int j;
          int r;
          int oldVal;
          Integerify(p, nos);
          oldVal = p->aStack[nos].i;
          if( Stringify(p, tos) ) goto no_mem;
          r = sqliteDbbeFetch(pCrsr, p->aStack[tos].n, p->zStack[tos]);
          if( r==0 ) break;
          nIdx = sqliteDbbeDataLength(pCrsr)/sizeof(int);
          aIdx = (int*)sqliteDbbeReadData(pCrsr, 0);
          for(j=0; j<nIdx && aIdx[j]!=oldVal; j++){}
          if( j>=nIdx ) break;
          aIdx[j] = aIdx[nIdx-1];
          if( nIdx==1 ){
            sqliteDbbeDelete(pCrsr, p->aStack[tos].n, p->zStack[tos]);
          }else{









            sqliteDbbePut(pCrsr, p->aStack[tos].n, p->zStack[tos], 
                          sizeof(int)*(nIdx-1), (char*)aIdx);
          }
        }
        PopStack(p, 2);
        break;
      }

      /* Opcode: Destroy * * P3







|







 







|


>
>
>
>
>
>
|






|







 







>
>

>
|
|
>
|
|
|
|
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







 







|









|
<
<
<


>
>
>
>
>
>
>
>
>

|







37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
....
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
....
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240
....
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272



2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
** inplicit conversion from one type to the other occurs as necessary.
** 
** Most of the code in this file is taken up by the sqliteVdbeExec()
** function which does the work of interpreting a VDBE program.
** But other routines are also provided to help in building up
** a program instruction by instruction.
**
** $Id: vdbe.c,v 1.38 2000/08/02 12:26:29 drh Exp $
*/
#include "sqliteInt.h"
#include <unistd.h>

/*
** SQL is translated into a sequence of instructions to be
** executed by a virtual machine.  Each instruction is an instance
................................................................................
        DbbeCursor *pCrsr;

        if( NeedStack(p, p->tos) ) goto no_mem;
        p->zStack[tos] = 0;
        if( i>=0 && i<p->nCursor && (pCrsr = p->aCsr[i].pCursor)!=0 ){
          int *aIdx;
          int nIdx;
          int j, k;
          nIdx = sqliteDbbeDataLength(pCrsr)/sizeof(int);
          aIdx = (int*)sqliteDbbeReadData(pCrsr, 0);
          if( nIdx>1 ){
            k = *(aIdx++);
            if( k>nIdx-1 ) k = nIdx-1;
          }else{
            k = nIdx;
          }
          for(j=p->aCsr[i].index; j<k; j++){
            if( aIdx[j]!=0 ){
              p->aStack[tos].i = aIdx[j];
              p->aStack[tos].flags = STK_Int;
              break;
            }
          }
          if( j>=k ){
            j = -1;
            pc = pOp->p2 - 1;
            PopStack(p, 1);
          }
          p->aCsr[i].index = j+1;
        }
        break;
................................................................................
            /* Create a new record for this index */
            sqliteDbbePut(pCrsr, p->aStack[tos].n, p->zStack[tos],
                          sizeof(int), (char*)&newVal);
          }else{
            /* Extend the existing record */
            int nIdx;
            int *aIdx;
            int k;
            
            nIdx = sqliteDbbeDataLength(pCrsr)/sizeof(int);
            if( nIdx==1 ){
              aIdx = sqliteMalloc( sizeof(int)*4 );
              if( aIdx==0 ) goto no_mem;
              aIdx[0] = 2;
              sqliteDbbeCopyData(pCrsr, 0, sizeof(int), (char*)&aIdx[1]);
              aIdx[2] = newVal;
              sqliteDbbePut(pCrsr, p->aStack[tos].n, p->zStack[tos],
                    sizeof(int)*4, (char*)aIdx);
              sqliteFree(aIdx);
            }else{
              aIdx = (int*)sqliteDbbeReadData(pCrsr, 0);
              k = aIdx[0];
              if( k<nIdx-1 ){
                aIdx[k+1] = newVal;
                aIdx[0]++;
                sqliteDbbePut(pCrsr, p->aStack[tos].n, p->zStack[tos],
                    sizeof(int)*nIdx, (char*)aIdx);
              }else{
                nIdx *= 2;
                aIdx = sqliteMalloc( sizeof(int)*nIdx );
                if( aIdx==0 ) goto no_mem;
                sqliteDbbeCopyData(pCrsr, 0, sizeof(int)*(k+1), (char*)aIdx);
                aIdx[k+1] = newVal;
                aIdx[0]++;
                sqliteDbbePut(pCrsr, p->aStack[tos].n, p->zStack[tos],
                      sizeof(int)*nIdx, (char*)aIdx);
                sqliteFree(aIdx);
              }
            }              
          }
        }
        PopStack(p, 2);
        break;
      }

      /* Opcode: DeleteIdx P1 * *
................................................................................
        int tos = p->tos;
        int nos = tos - 1;
        DbbeCursor *pCrsr;
        if( nos<0 ) goto not_enough_stack;
        if( i>=0 && i<p->nCursor && (pCrsr = p->aCsr[i].pCursor)!=0 ){
          int *aIdx;
          int nIdx;
          int j, k;
          int r;
          int oldVal;
          Integerify(p, nos);
          oldVal = p->aStack[nos].i;
          if( Stringify(p, tos) ) goto no_mem;
          r = sqliteDbbeFetch(pCrsr, p->aStack[tos].n, p->zStack[tos]);
          if( r==0 ) break;
          nIdx = sqliteDbbeDataLength(pCrsr)/sizeof(int);
          aIdx = (int*)sqliteDbbeReadData(pCrsr, 0);
          if( (nIdx==1 && aIdx[0]==oldVal) || (aIdx[0]==1 && aIdx[1]==oldVal) ){



            sqliteDbbeDelete(pCrsr, p->aStack[tos].n, p->zStack[tos]);
          }else{
            k = aIdx[0];
            for(j=1; j<=k && aIdx[j]!=oldVal; j++){}
            if( j>k ) break;
            aIdx[j] = aIdx[k];
            aIdx[k] = 0;
            aIdx[0]--;
            if( aIdx[0]*3 + 1 < nIdx ){
              nIdx /= 2;
            }
            sqliteDbbePut(pCrsr, p->aStack[tos].n, p->zStack[tos], 
                          sizeof(int)*nIdx, (char*)aIdx);
          }
        }
        PopStack(p, 2);
        break;
      }

      /* Opcode: Destroy * * P3

Changes to test/index.test.

19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
...
277
278
279
280
281
282
283
284
285
286
287
288
289














290


























291
#   drh@hwaci.com
#   http://www.hwaci.com/drh/
#
#***********************************************************************
# This file implements regression tests for SQLite library.  The
# focus of this file is testing the CREATE INDEX statement.
#
# $Id: index.test,v 1.5 2000/06/17 13:12:40 drh Exp $

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

# Create a basic index and verify it is added to sqlite_master
#
do_test index-1.1 {
................................................................................
} {4}
do_test index-10.2 {
  execsql {
    DELETE FROM t1 WHERE b=12;
    SELECT b FROM t1 WHERE a=1 ORDER BY b;
  }
} {2}
do_test index-10.2 {
  execsql {
    DELETE FROM t1 WHERE b=2;
    SELECT b FROM t1 WHERE a=1 ORDER BY b;
  }
} {}









































finish_test







|







 







|





>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>

19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
...
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
#   drh@hwaci.com
#   http://www.hwaci.com/drh/
#
#***********************************************************************
# This file implements regression tests for SQLite library.  The
# focus of this file is testing the CREATE INDEX statement.
#
# $Id: index.test,v 1.6 2000/08/02 12:26:30 drh Exp $

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

# Create a basic index and verify it is added to sqlite_master
#
do_test index-1.1 {
................................................................................
} {4}
do_test index-10.2 {
  execsql {
    DELETE FROM t1 WHERE b=12;
    SELECT b FROM t1 WHERE a=1 ORDER BY b;
  }
} {2}
do_test index-10.3 {
  execsql {
    DELETE FROM t1 WHERE b=2;
    SELECT b FROM t1 WHERE a=1 ORDER BY b;
  }
} {}
do_test index-10.4 {
  execsql {
    DELETE FROM t1;
    INSERT INTO t1 VALUES (1,1);
    INSERT INTO t1 VALUES (1,2);
    INSERT INTO t1 VALUES (1,3);
    INSERT INTO t1 VALUES (1,4);
    INSERT INTO t1 VALUES (1,5);
    INSERT INTO t1 VALUES (1,6);
    INSERT INTO t1 VALUES (1,7);
    INSERT INTO t1 VALUES (1,8);
    INSERT INTO t1 VALUES (1,9);
    INSERT INTO t1 VALUES (2,0);
    SELECT b FROM t1 WHERE a=1 ORDER BY b;
  }
} {1 2 3 4 5 6 7 8 9}
do_test index-10.5 {
  execsql {
    DELETE FROM t1 WHERE b IN (2, 4, 6, 8);
    SELECT b FROM t1 WHERE a=1 ORDER BY b;
  }
} {1 3 5 7 9}
do_test index-10.6 {
  execsql {
    DELETE FROM t1 WHERE b>2;
    SELECT b FROM t1 WHERE a=1 ORDER BY b;
  }
} {1}
do_test index-10.7 {
  execsql {
    DELETE FROM t1 WHERE b=1;
    SELECT b FROM t1 WHERE a=1 ORDER BY b;
  }
} {}
do_test index-10.8 {
  execsql {
    SELECT b FROM t1 ORDER BY b;
  }
} {0}


finish_test

Changes to www/changes.tcl.

12
13
14
15
16
17
18







19
20
21
22
23
24
25
}


proc chng {date desc} {
  puts "<DT><B>$date</B></DT>"
  puts "<DD><P><UL>$desc</UL></P></DD>"
}








chng {2000 Aug 1} {
<li>The parser's stack was overflowing on a very long UPDATE statement.
    This is now fixed.</li>
}

chng {2000 July 31} {







>
>
>
>
>
>
>







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


proc chng {date desc} {
  puts "<DT><B>$date</B></DT>"
  puts "<DD><P><UL>$desc</UL></P></DD>"
}

chng {2000 Aug 2} {
<li>The file format for indices was changed slightly in order to work
    around an inefficiency that can sometimes come up with GDBM when
    there are large indices having many entries with the same key.
    <font color="red">** Incompatible Change **</font></li>
}

chng {2000 Aug 1} {
<li>The parser's stack was overflowing on a very long UPDATE statement.
    This is now fixed.</li>
}

chng {2000 July 31} {

Changes to www/fileformat.tcl.

1
2
3
4
5
6
7
8
9
10
11
...
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
...
147
148
149
150
151
152
153
154





155
156
157
158
159
160
161
...
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209





210
211
212
213
214
215
216
217
218
#
# Run this Tcl script to generate the fileformat.html file.
#
set rcsid {$Id: fileformat.tcl,v 1.2 2000/06/23 17:02:09 drh Exp $}

puts {<html>
<head>
  <title>The SQLite file format</title>
</head>
<body bgcolor=white>
<h1 align=center>
................................................................................
$ (((rm -rf ex1)))
$ (((sqlite ex1)))
sqlite> (((create table t1(a int, b text, c text);)))
sqlite> (((insert into t1 values(10,NULL,'hello!');)))
sqlite> (((insert into t1 values(-11,'this is','a test');)))
sqlite> (((.exit)))
$ (((gdbmdump ex1/t1.tbl)))
key  : 223100ae                                      "1..
data : 0c000000 10000000 18000000 2d313100 74686973  ............-11.this
       20697300 61207465 737400                       is.a test.

key  : a840e996                                      .@..
data : 0c000000 00000000 0f000000 31300068 656c6c6f  ............10.hello
       2100                                          !.

$
}

puts {
................................................................................

<p>Each SQL index is also represented using a single GDBM file.
There is one entry in the GDBM file for each unique SQL key in the
table that is being indexed.  The GDBM key is an
arbitrary length null-terminated string which is SQL key that
is used by the index.  The data is a list of integers that correspond
to GDBM keys of entries in data table that have the corresponding
SQL key.</p>






<p>To illustrate, we will create an index on the example table
shown above, and add a new entry to this table that has a duplicate
SQL key.</p>
}

Code {
................................................................................

<p>Now let's look at a dump of the index file.</p>
}

Code {
$ (((gdbmdump ex1/i1.tbl)))
key  : 313000                                        10.
data : a840e996 c19e3119                             .@....1.

key  : 2d313100                                      -11.
data : 223100ae                                      "1..

$
}

puts {
<p>The GDBM file for the index contains only two records because
the <b>t1</b> table contains only two distinct values for
column <b>a</b>.  You can see that the GDBM keys for each record
are just the text values for <b>a</b> columns of table <b>t1</b>.
The data for each record of the index is a list of integers
where each integer is the GDBM key for an entry in the <b>t1</b>
table that has the corresponding value for the <b>a</b> column.</p>





}

puts {
<p><hr /></p>
<p><a href="index.html"><img src="/goback.jpg" border=0 />
Back to the SQLite Home Page</a>
</p>

</body></html>}



|







 







|



|







 







|
>
>
>
>
>







 







|


|












>
>
>
>
>









1
2
3
4
5
6
7
8
9
10
11
...
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
...
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
...
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
#
# Run this Tcl script to generate the fileformat.html file.
#
set rcsid {$Id: fileformat.tcl,v 1.3 2000/08/02 12:26:30 drh Exp $}

puts {<html>
<head>
  <title>The SQLite file format</title>
</head>
<body bgcolor=white>
<h1 align=center>
................................................................................
$ (((rm -rf ex1)))
$ (((sqlite ex1)))
sqlite> (((create table t1(a int, b text, c text);)))
sqlite> (((insert into t1 values(10,NULL,'hello!');)))
sqlite> (((insert into t1 values(-11,'this is','a test');)))
sqlite> (((.exit)))
$ (((gdbmdump ex1/t1.tbl)))
key  : 6d1a6e03                                      m.n.
data : 0c000000 10000000 18000000 2d313100 74686973  ............-11.this
       20697300 61207465 737400                       is.a test.

key  : 6d3f90e2                                      m?..
data : 0c000000 00000000 0f000000 31300068 656c6c6f  ............10.hello
       2100                                          !.

$
}

puts {
................................................................................

<p>Each SQL index is also represented using a single GDBM file.
There is one entry in the GDBM file for each unique SQL key in the
table that is being indexed.  The GDBM key is an
arbitrary length null-terminated string which is SQL key that
is used by the index.  The data is a list of integers that correspond
to GDBM keys of entries in data table that have the corresponding
SQL key.  If the data record of the index is exactly 4 bytes in size,
then the data represents a single integer key.  If the data is greater
than 4 bytes in size, then the first 4 bytes form an integer that
tells us how many keys are in the data.  The index data record is
always sized to be a power of 2.  Unused slots at the end of the
index data record are filled with zero.</p>

<p>To illustrate, we will create an index on the example table
shown above, and add a new entry to this table that has a duplicate
SQL key.</p>
}

Code {
................................................................................

<p>Now let's look at a dump of the index file.</p>
}

Code {
$ (((gdbmdump ex1/i1.tbl)))
key  : 313000                                        10.
data : 02000000 45b4f724 6d3f90e2 00000000           ....E..$m?......

key  : 2d313100                                      -11.
data : 6d1a6e03                                      m.n.

$
}

puts {
<p>The GDBM file for the index contains only two records because
the <b>t1</b> table contains only two distinct values for
column <b>a</b>.  You can see that the GDBM keys for each record
are just the text values for <b>a</b> columns of table <b>t1</b>.
The data for each record of the index is a list of integers
where each integer is the GDBM key for an entry in the <b>t1</b>
table that has the corresponding value for the <b>a</b> column.</p>
The index entry for -11 contains only a single entry and is 4
bytes in size.  The index entry for 10 is 16 bytes in size but
contains only 2 entries.  The first integer is the number of
entires.  The two integer keys follow.  The last 4 bytes unused
and are set to zero.
}

puts {
<p><hr /></p>
<p><a href="index.html"><img src="/goback.jpg" border=0 />
Back to the SQLite Home Page</a>
</p>

</body></html>}

Changes to www/index.tcl.

1
2
3
4
5
6
7
8
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
#
# Run this TCL script to generate HTML for the index.html file.
#
set rcsid {$Id: index.tcl,v 1.22 2000/08/01 09:56:27 drh Exp $}

puts {<html>
<head><title>SQLite: An SQL Database Engine Built Atop GDBM</title></head>
<body bgcolor=white>
<h1 align=center>SQLite: An SQL Database Engine Built Atop
<a href="http://www.gnu.org/software/gdbm/gdbm.html">GDBM</a></h1>
<p align=center>}
puts "This page was last modified on [lrange $rcsid 3 4] GMT<br>"
puts "The SQLite source code was last modifed on [exec cat last_change] GMT"
puts {</p>}

if 0 {
puts {
<h2>News</h2>
<p>
The SQLite code base is being called "beta" only because it is
relatively new.  It appears to be stable and usable.
Most of the SQL language is now implemented and working.  
The regression test suite
provides good coverage, according to
<a href="http://gcc.gnu.org/onlinedocs/gcov_1.html">gcov</a>.
There are currently no known errors in the code.</p>

<p>If you find bugs or missing features, please submit a comment
to the <a href="#mailinglist">SQLite mailing list</a>.</p>
}
}

puts {<h2>Introduction</h2>

<p>SQLite is an SQL database engine built on top of the
<a href="http://www.gnu.org/software/gdbm/gdbm.html">GDBM library</a>.
SQLite includes a standalone command-line
access program (<a href="sqlite.html">sqlite</a>)
and a C library (<a href="c_interface.html">libsqlite.a</a>)
that can be linked
with a C/C++ program to provide SQL database access without
an separate RDBMS.</p>




















<h2>Features</h2>

<p><ul>
<li>Implements most of SQL92.</li>
<li>A database is just a directory of GDBM files.</li>
<li>Unlimited length records.</li>
<li>Import and export data from 



|











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











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







1
2
3
4
5
6
7
8
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
#
# Run this TCL script to generate HTML for the index.html file.
#
set rcsid {$Id: index.tcl,v 1.23 2000/08/02 12:26:30 drh Exp $}

puts {<html>
<head><title>SQLite: An SQL Database Engine Built Atop GDBM</title></head>
<body bgcolor=white>
<h1 align=center>SQLite: An SQL Database Engine Built Atop
<a href="http://www.gnu.org/software/gdbm/gdbm.html">GDBM</a></h1>
<p align=center>}
puts "This page was last modified on [lrange $rcsid 3 4] GMT<br>"
puts "The SQLite source code was last modifed on [exec cat last_change] GMT"
puts {</p>}


















puts {<h2>Introduction</h2>

<p>SQLite is an SQL database engine built on top of the
<a href="http://www.gnu.org/software/gdbm/gdbm.html">GDBM library</a>.
SQLite includes a standalone command-line
access program (<a href="sqlite.html">sqlite</a>)
and a C library (<a href="c_interface.html">libsqlite.a</a>)
that can be linked
with a C/C++ program to provide SQL database access without
an separate RDBMS.</p>

<h2>Important News Flash!</h2>
<p>
The SQLite file format was changed in an incompatible way on
Aug 2, 2000.  If you are updated the library and have databases
built using the old version of the library, you should save your
old databases into an ASCII fileformat then reimport those
database using the new library.  For example, if you change the
name of the old <b>sqlite</b> utility to "old-sqlite" and
change the name of the old database directory to "old-db", then
you can reconstruct the database as follows:</p>

<blockquote><pre>
echo .dump | old-sqlite old-db | sqlite db
</pre></blockquote>

<p>This file format change was made to work around a potential 
inefficiency in GDBM that comes up when large indices are created 
on tables where many entries in the table have the same key.</p>

<h2>Features</h2>

<p><ul>
<li>Implements most of SQL92.</li>
<li>A database is just a directory of GDBM files.</li>
<li>Unlimited length records.</li>
<li>Import and export data from