/ Check-in [c6ffb7ec]
Login

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

Overview
Comment:continued progress toward version 2.0 (CVS 177)
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1:c6ffb7ec6acb596907ead8992dfad94e18e83866
User & Date: drh 2001-01-15 22:51:09
Context
2001-01-15
22:51
continued progress toward version 2.0 (CVS 1710) check-in: a60af40a user: drh tags: trunk
22:51
continued progress toward version 2.0 (CVS 177) check-in: c6ffb7ec user: drh tags: trunk
2001-01-13
14:34
Changes to the DBBE. Moving toward having many more backend driver choices. (CVS 176) check-in: c0730217 user: drh tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/build.c.

29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
...
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
...
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
...
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
...
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
...
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
...
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
**     DROP TABLE
**     CREATE INDEX
**     DROP INDEX
**     creating expressions and ID lists
**     COPY
**     VACUUM
**
** $Id: build.c,v 1.24 2000/10/16 22:06:42 drh Exp $
*/
#include "sqliteInt.h"

/*
** This routine is called after a single SQL statement has been
** parsed and we want to execute the VDBE code to implement 
** that statement.  Prior action routines should have already
................................................................................
    pParse->db->nTable++;
  }

  /* If not initializing, then create the table on disk.
  */
  if( !pParse->initFlag ){
    static VdbeOp addTable[] = {
      { OP_Open,        0, 1, MASTER_NAME },
      { OP_New,         0, 0, 0},
      { OP_String,      0, 0, "table"     },
      { OP_String,      0, 0, 0},            /* 3 */
      { OP_String,      0, 0, 0},            /* 4 */
      { OP_String,      0, 0, 0},            /* 5 */
      { OP_MakeRecord,  4, 0, 0},
      { OP_Put,         0, 0, 0},
................................................................................

  /* Generate code to remove the table from the master table
  ** on disk.
  */
  v = sqliteGetVdbe(pParse);
  if( v ){
    static VdbeOp dropTable[] = {
      { OP_Open,       0, 1,        MASTER_NAME },
      { OP_ListOpen,   0, 0,        0},
      { OP_String,     0, 0,        0}, /* 2 */
      { OP_Next,       0, ADDR(10), 0}, /* 3 */
      { OP_Dup,        0, 0,        0},
      { OP_Field,      0, 2,        0},
      { OP_Ne,         0, ADDR(3),  0},
      { OP_Key,        0, 0,        0},
................................................................................
  ** command.  The initFlag is 1 when a database is opened and 
  ** CREATE INDEX statements are read out of the master table.  In
  ** the latter case the index already exists on disk, which is why
  ** we don't want to recreate it.
  */
  if( pParse->initFlag==0 ){
    static VdbeOp addTable[] = {
      { OP_Open,        2, 1, MASTER_NAME},
      { OP_New,         2, 0, 0},
      { OP_String,      0, 0, "index"},
      { OP_String,      0, 0, 0},  /* 3 */
      { OP_String,      0, 0, 0},  /* 4 */
      { OP_String,      0, 0, 0},  /* 5 */
      { OP_MakeRecord,  4, 0, 0},
      { OP_Put,         2, 0, 0},
................................................................................
    int n;
    Vdbe *v = pParse->pVdbe;
    int lbl1, lbl2;
    int i;

    v = sqliteGetVdbe(pParse);
    if( v==0 ) goto exit_create_index;
    sqliteVdbeAddOp(v, OP_Open, 0, 0, pTab->zName, 0);
    sqliteVdbeAddOp(v, OP_Open, 1, 1, pIndex->zName, 0);
    if( pStart && pEnd ){
      int base;
      n = (int)pEnd->z - (int)pStart->z + 1;
      base = sqliteVdbeAddOpList(v, ArraySize(addTable), addTable);
      sqliteVdbeChangeP3(v, base+3, pIndex->zName, 0);
      sqliteVdbeChangeP3(v, base+4, pTab->zName, 0);
      sqliteVdbeChangeP3(v, base+5, pStart->z, n);
................................................................................
    return;
  }

  /* Generate code to remove the index and from the master table */
  v = sqliteGetVdbe(pParse);
  if( v ){
    static VdbeOp dropIndex[] = {
      { OP_Open,       0, 1,       MASTER_NAME},
      { OP_ListOpen,   0, 0,       0},
      { OP_String,     0, 0,       0}, /* 2 */
      { OP_Next,       0, ADDR(9), 0}, /* 3 */
      { OP_Dup,        0, 0,       0},
      { OP_Field,      0, 1,       0},
      { OP_Ne,         0, ADDR(3), 0},
      { OP_Key,        0, 0,       0},
................................................................................
    goto copy_cleanup;
  }
  v = sqliteGetVdbe(pParse);
  if( v ){
    addr = sqliteVdbeAddOp(v, OP_FileOpen, 0, 0, 0, 0);
    sqliteVdbeChangeP3(v, addr, pFilename->z, pFilename->n);
    sqliteVdbeDequoteP3(v, addr);
    sqliteVdbeAddOp(v, OP_Open, 0, 1, pTab->zName, 0);
    for(i=1, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
      sqliteVdbeAddOp(v, OP_Open, i, 1, pIdx->zName, 0);
    }
    end = sqliteVdbeMakeLabel(v);
    addr = sqliteVdbeAddOp(v, OP_FileRead, pTab->nCol, end, 0, 0);
    if( pDelimiter ){
      sqliteVdbeChangeP3(v, addr, pDelimiter->z, pDelimiter->n);
      sqliteVdbeDequoteP3(v, addr);
    }else{







|







 







|







 







|







 







|







 







|
|







 







|







 







|

|







29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
...
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
...
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
...
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
...
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
...
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
...
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
**     DROP TABLE
**     CREATE INDEX
**     DROP INDEX
**     creating expressions and ID lists
**     COPY
**     VACUUM
**
** $Id: build.c,v 1.25 2001/01/15 22:51:09 drh Exp $
*/
#include "sqliteInt.h"

/*
** This routine is called after a single SQL statement has been
** parsed and we want to execute the VDBE code to implement 
** that statement.  Prior action routines should have already
................................................................................
    pParse->db->nTable++;
  }

  /* If not initializing, then create the table on disk.
  */
  if( !pParse->initFlag ){
    static VdbeOp addTable[] = {
      { OP_OpenTbl,     0, 1, MASTER_NAME },
      { OP_New,         0, 0, 0},
      { OP_String,      0, 0, "table"     },
      { OP_String,      0, 0, 0},            /* 3 */
      { OP_String,      0, 0, 0},            /* 4 */
      { OP_String,      0, 0, 0},            /* 5 */
      { OP_MakeRecord,  4, 0, 0},
      { OP_Put,         0, 0, 0},
................................................................................

  /* Generate code to remove the table from the master table
  ** on disk.
  */
  v = sqliteGetVdbe(pParse);
  if( v ){
    static VdbeOp dropTable[] = {
      { OP_OpenTbl,    0, 1,        MASTER_NAME },
      { OP_ListOpen,   0, 0,        0},
      { OP_String,     0, 0,        0}, /* 2 */
      { OP_Next,       0, ADDR(10), 0}, /* 3 */
      { OP_Dup,        0, 0,        0},
      { OP_Field,      0, 2,        0},
      { OP_Ne,         0, ADDR(3),  0},
      { OP_Key,        0, 0,        0},
................................................................................
  ** command.  The initFlag is 1 when a database is opened and 
  ** CREATE INDEX statements are read out of the master table.  In
  ** the latter case the index already exists on disk, which is why
  ** we don't want to recreate it.
  */
  if( pParse->initFlag==0 ){
    static VdbeOp addTable[] = {
      { OP_OpenTbl,     2, 1, MASTER_NAME},
      { OP_New,         2, 0, 0},
      { OP_String,      0, 0, "index"},
      { OP_String,      0, 0, 0},  /* 3 */
      { OP_String,      0, 0, 0},  /* 4 */
      { OP_String,      0, 0, 0},  /* 5 */
      { OP_MakeRecord,  4, 0, 0},
      { OP_Put,         2, 0, 0},
................................................................................
    int n;
    Vdbe *v = pParse->pVdbe;
    int lbl1, lbl2;
    int i;

    v = sqliteGetVdbe(pParse);
    if( v==0 ) goto exit_create_index;
    sqliteVdbeAddOp(v, OP_OpenTbl, 0, 0, pTab->zName, 0);
    sqliteVdbeAddOp(v, OP_OpenIdx, 1, 1, pIndex->zName, 0);
    if( pStart && pEnd ){
      int base;
      n = (int)pEnd->z - (int)pStart->z + 1;
      base = sqliteVdbeAddOpList(v, ArraySize(addTable), addTable);
      sqliteVdbeChangeP3(v, base+3, pIndex->zName, 0);
      sqliteVdbeChangeP3(v, base+4, pTab->zName, 0);
      sqliteVdbeChangeP3(v, base+5, pStart->z, n);
................................................................................
    return;
  }

  /* Generate code to remove the index and from the master table */
  v = sqliteGetVdbe(pParse);
  if( v ){
    static VdbeOp dropIndex[] = {
      { OP_OpenTbl,      0, 1,       MASTER_NAME},
      { OP_ListOpen,   0, 0,       0},
      { OP_String,     0, 0,       0}, /* 2 */
      { OP_Next,       0, ADDR(9), 0}, /* 3 */
      { OP_Dup,        0, 0,       0},
      { OP_Field,      0, 1,       0},
      { OP_Ne,         0, ADDR(3), 0},
      { OP_Key,        0, 0,       0},
................................................................................
    goto copy_cleanup;
  }
  v = sqliteGetVdbe(pParse);
  if( v ){
    addr = sqliteVdbeAddOp(v, OP_FileOpen, 0, 0, 0, 0);
    sqliteVdbeChangeP3(v, addr, pFilename->z, pFilename->n);
    sqliteVdbeDequoteP3(v, addr);
    sqliteVdbeAddOp(v, OP_OpenTbl, 0, 1, pTab->zName, 0);
    for(i=1, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
      sqliteVdbeAddOp(v, OP_OpenIdx, i, 1, pIdx->zName, 0);
    }
    end = sqliteVdbeMakeLabel(v);
    addr = sqliteVdbeAddOp(v, OP_FileRead, pTab->nCol, end, 0, 0);
    if( pDelimiter ){
      sqliteVdbeChangeP3(v, addr, pDelimiter->z, pDelimiter->n);
      sqliteVdbeDequoteP3(v, addr);
    }else{

Added src/db.h.











































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
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
53
/*
** Copyright (c) 2001 D. Richard Hipp
**
** This program is free software; you can redistribute it and/or
** modify it under the terms of the GNU General Public
** License as published by the Free Software Foundation; either
** version 2 of the License, or (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
** General Public License for more details.
** 
** You should have received a copy of the GNU General Public
** License along with this library; if not, write to the
** Free Software Foundation, Inc., 59 Temple Place - Suite 330,
** Boston, MA  02111-1307, USA.
**
** Author contact information:
**   drh@hwaci.com
**   http://www.hwaci.com/drh/
**
*************************************************************************
** $Id: db.h,v 1.1 2001/01/15 22:51:10 drh Exp $
*/

typedef struct Db Db;
typedef struct DbCursor DbCursor;

int sqliteDbOpen(const char *filename, Db**);
int sqliteDbClose(Db*);
int sqliteDbBeginTransaction(Db*);
int sqliteDbCommit(Db*);
int sqliteDbRollback(Db*);

int sqliteDbCreateTable(Db*, int *pPgno);
int sqliteDbDropTable(Db*, int pgno);

int sqliteDbCursorOpen(Db*, int pgno, DbCursor**);
int sqliteDbCursorClose(DbCursor*);

int sqliteDbCursorMoveTo(DbCursor*, int key);
int sqliteDbCursorFirst(DbCursor*);
int sqliteDbCursorNext(DbCursor*);
int sqliteDbCursorDelete(DbCursor*);
int sqliteDbCursorDatasize(DbCursor*);
int sqliteDbCursorRead(DbCursor*, int amt, int offset, char *buf);
int sqliteDbCursorInsert(DbCursor*, int key, int nData, char *pData);

int sqliteDbCursorMoveToIdx(DbCursor*, int nKey, char *pKey);
int sqliteDbCursorKeysize(DbCursor*);
int sqliteDbCursorReadKey(DbCursor*, int amt, int offset, char *buf);
int sqliteDbCursorInsertIdx(DbCursor*, int nKey, char *pKey, int nData, char*);

Changes to src/dbbe.c.

26
27
28
29
30
31
32
33
34
35

36
37
38
39
40
41
42
..
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
..
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
...
145
146
147
148
149
150
151



















































** 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.22 2001/01/13 14:34:06 drh Exp $
*/
#include "sqliteInt.h"


/*
** This routine opens a new database.  It looks at the first
** few characters of the database name to try to determine what
** kind of database to open.  If the first characters are "gdbm:",
** then it uses the GDBM driver.  If the first few characters are
** "memory:" then it uses the in-memory driver.  If there is no
................................................................................
/*
** Open a temporary file.  The file should be deleted when closed.
**
** Note that we can't use the old Unix trick of opening the file
** and then immediately unlinking the file.  That works great
** under Unix, but fails when we try to port to Windows.
*/
int sqliteDbbeOpenTempFile(Dbbe *pBe, FILE **ppFile){
  char *zFile;         /* Full name of the temporary file */
  char zBuf[50];       /* Base name of the temporary file */
  int i;               /* Loop counter */
  int limit;           /* Prevent an infinite loop */
  int rc = SQLITE_OK;  /* Value returned by this function */
  char *zDir;          /* Directory to hold the file */

  for(i=0; i<pBe->nTemp; i++){
    if( pBe->apTemp[i]==0 ) break;
  }
  if( i>=pBe->nTemp ){
    pBe->nTemp++;
    pBe->apTemp = sqliteRealloc(pBe->apTemp, pBe->nTemp*sizeof(FILE*) );
................................................................................
  }
  if( pBe->apTemp==0 ){
    *ppFile = 0;
    return SQLITE_NOMEM;
  }
  limit = 4;
  zFile = 0;
  zDir = pBe->zDir;
  if( zDir==0 ){
    zDir = "./";
  }
  do{
    sqliteRandomName(zBuf, "/_temp_file_");
    sqliteFree(zFile);
    zFile = 0;
    sqliteSetString(&zFile, zDir, zBuf, 0);
  }while( access(zFile,0)==0 && limit-- >= 0 );
  *ppFile = pBe->apTemp[i] = fopen(zFile, "w+");
................................................................................
      pBe->azTemp[i] = 0;
      break;
    }
  }
  sqliteFree(pBe->azTemp);
  sqliteFree(pBe->apTemp);
}


























































|


>







 







|





<







 







<
<
<
<







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
..
67
68
69
70
71
72
73
74
75
76
77
78
79

80
81
82
83
84
85
86
..
88
89
90
91
92
93
94




95
96
97
98
99
100
101
...
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
** 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.23 2001/01/15 22:51:10 drh Exp $
*/
#include "sqliteInt.h"
#include <unistd.h>

/*
** This routine opens a new database.  It looks at the first
** few characters of the database name to try to determine what
** kind of database to open.  If the first characters are "gdbm:",
** then it uses the GDBM driver.  If the first few characters are
** "memory:" then it uses the in-memory driver.  If there is no
................................................................................
/*
** Open a temporary file.  The file should be deleted when closed.
**
** Note that we can't use the old Unix trick of opening the file
** and then immediately unlinking the file.  That works great
** under Unix, but fails when we try to port to Windows.
*/
int sqliteDbbeOpenTempFile(const char *zDir, Dbbe *pBe, FILE **ppFile){
  char *zFile;         /* Full name of the temporary file */
  char zBuf[50];       /* Base name of the temporary file */
  int i;               /* Loop counter */
  int limit;           /* Prevent an infinite loop */
  int rc = SQLITE_OK;  /* Value returned by this function */


  for(i=0; i<pBe->nTemp; i++){
    if( pBe->apTemp[i]==0 ) break;
  }
  if( i>=pBe->nTemp ){
    pBe->nTemp++;
    pBe->apTemp = sqliteRealloc(pBe->apTemp, pBe->nTemp*sizeof(FILE*) );
................................................................................
  }
  if( pBe->apTemp==0 ){
    *ppFile = 0;
    return SQLITE_NOMEM;
  }
  limit = 4;
  zFile = 0;




  do{
    sqliteRandomName(zBuf, "/_temp_file_");
    sqliteFree(zFile);
    zFile = 0;
    sqliteSetString(&zFile, zDir, zBuf, 0);
  }while( access(zFile,0)==0 && limit-- >= 0 );
  *ppFile = pBe->apTemp[i] = fopen(zFile, "w+");
................................................................................
      pBe->azTemp[i] = 0;
      break;
    }
  }
  sqliteFree(pBe->azTemp);
  sqliteFree(pBe->apTemp);
}

/*
** Translate the name of an SQL table (or index) into the name 
** of a file that holds the key/data pairs for that table or
** index.  Space to hold the filename is obtained from
** sqliteMalloc() and must be freed by the calling function.
**
** zDir is the name of the directory in which the file should
** be located.  zSuffix is the filename extension to use for
** the file.
*/
char *sqliteDbbeNameToFile(
  const char *zDir,      /* Directory containing the file */
  const char *zTable,    /* Name of the SQL table that the file contains */
  const char *zSuffix    /* Suffix for the file.  Includes the "." */
){
  char *zFile = 0;
  int i, k, c;
  int nChar = 0;

  for(i=0; (c = zTable[i])!=0; i++){
    if( !isalnum(c) && c!='_' ){
      nChar += 3;
    }else{
      nChar ++;
    }
  }
  nChar += strlen(zDir) + strlen(zSuffix) + 2;
  zFile = sqliteMalloc( nChar );
  if( zFile==0 ) return 0;
  for(i=0; (c = zDir[i])!=0; i++){
    zFile[i] = c;
  }
  zFile[i++] = '/';
  for(k=0; (c = zTable[k])!=0; k++){
    if( isupper(c) ){
      zFile[i++] = tolower(c);
    }else if( isalnum(c) || c=='_' ){
      zFile[i++] = c;
    }else{
      zFile[i++] = '~';
      zFile[i++] = "0123456789abcdef"[c & 0xf];
      zFile[i++] = "0123456789abcdef"[(c>>8)&0xf];
    }
  }
  for(k=0; (c = zSuffix[k])!=0; k++){
    zFile[i++] = c;
  }
  zFile[i] = 0;
  return zFile;
}

Changes to src/dbbe.h.

24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
..
76
77
78
79
80
81
82





83
84
85
86
87

88
89
90
91
92
93
94
...
160
161
162
163
164
165
166
167
168
169
170
171
172
173
** This file defines the interface to the database backend (Dbbe).
**
** The database backend is designed to be as general as possible
** so that it can easily be replaced by a different backend.
** This library was originally designed to support the following
** backends: GDBM, NDBM, SDBM, Berkeley DB.
**
** $Id: dbbe.h,v 1.9 2001/01/13 14:34:06 drh Exp $
*/
#ifndef _SQLITE_DBBE_H_
#define _SQLITE_DBBE_H_
#include <stdio.h>

/*
** The database backend supports two opaque structures.  A Dbbe is
................................................................................
  void (*Close)(Dbbe*);

  /* Open a cursor into particular file of a previously opened database.
  ** Create the file if it doesn't already exist and writeable!=0.  zName
  ** is the base name of the file to be opened.  This routine will add
  ** an appropriate path and extension to the filename to locate the 
  ** actual file.





  **
  ** If zName is 0 or "", then a temporary file is created that
  ** will be deleted when closed.
  */
  int (*OpenCursor)(Dbbe*, const char *zName, int writeable, DbbeCursor**);


  /* Delete a table from the database */
  void (*DropTable)(Dbbe*, const char *zTableName);

  /* Reorganize a table to speed access or reduce its disk usage */
  int (*ReorganizeTable)(Dbbe*, const char *zTableName);

................................................................................
** pointers in the Dbbe.x field) is intended to be visible to
** the backend drivers only.  Users should not access or modify
** this structure in any way other than the read the method pointers
** in Dbbe.x.
*/
struct Dbbe {
  struct DbbeMethods *x; /* Backend-specific methods for database access */
  char *zDir;            /* The directory containing the database file(s) */
  int nTemp;             /* Number of temporary files created */
  FILE **apTemp;         /* Space to hold temporary file pointers */
  char **azTemp;         /* Names of the temporary files */
};

#endif /* defined(_SQLITE_DBBE_H_) */







|







 







>
>
>
>
>




|
>







 







<






24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
..
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
...
166
167
168
169
170
171
172

173
174
175
176
177
178
** This file defines the interface to the database backend (Dbbe).
**
** The database backend is designed to be as general as possible
** so that it can easily be replaced by a different backend.
** This library was originally designed to support the following
** backends: GDBM, NDBM, SDBM, Berkeley DB.
**
** $Id: dbbe.h,v 1.10 2001/01/15 22:51:10 drh Exp $
*/
#ifndef _SQLITE_DBBE_H_
#define _SQLITE_DBBE_H_
#include <stdio.h>

/*
** The database backend supports two opaque structures.  A Dbbe is
................................................................................
  void (*Close)(Dbbe*);

  /* Open a cursor into particular file of a previously opened database.
  ** Create the file if it doesn't already exist and writeable!=0.  zName
  ** is the base name of the file to be opened.  This routine will add
  ** an appropriate path and extension to the filename to locate the 
  ** actual file.
  **
  ** The keyType parameter is TRUE if this table will only be accessed
  ** using integer keys.  This parameter allows the database backend to
  ** use a faster algorithm for the special case of integer keys, if it
  ** wants to.
  **
  ** If zName is 0 or "", then a temporary file is created that
  ** will be deleted when closed.
  */
  int (*OpenCursor)(Dbbe*, const char *zName, int writeable, 
                    int intKeyOnly, DbbeCursor**);

  /* Delete a table from the database */
  void (*DropTable)(Dbbe*, const char *zTableName);

  /* Reorganize a table to speed access or reduce its disk usage */
  int (*ReorganizeTable)(Dbbe*, const char *zTableName);

................................................................................
** pointers in the Dbbe.x field) is intended to be visible to
** the backend drivers only.  Users should not access or modify
** this structure in any way other than the read the method pointers
** in Dbbe.x.
*/
struct Dbbe {
  struct DbbeMethods *x; /* Backend-specific methods for database access */

  int nTemp;             /* Number of temporary files created */
  FILE **apTemp;         /* Space to hold temporary file pointers */
  char **azTemp;         /* Names of the temporary files */
};

#endif /* defined(_SQLITE_DBBE_H_) */

Changes to src/dbbegdbm.c.

26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
..
62
63
64
65
66
67
68

69
70
71
72
73
74
75
..
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
...
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
...
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
...
168
169
170
171
172
173
174

175
176
177
178
179
180
181
...
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
...
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
...
507
508
509
510
511
512
513
514
515





516
517
518
519
520
521
522
...
538
539
540
541
542
543
544









545
546
547
548
549
550
551
...
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
...
619
620
621
622
623
624
625
626
627
628
629
630
631
** 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: dbbegdbm.c,v 1.2 2001/01/13 14:34:06 drh Exp $
*/
#include "sqliteInt.h"
#include <gdbm.h>
#include <sys/stat.h>
#include <unistd.h>
#include <ctype.h>
#include <time.h>
................................................................................
** database driver.  This is a subclass of the Dbbe structure.
*/
typedef struct Dbbex Dbbex;
struct Dbbex {
  Dbbe dbbe;         /* The base class */
  int write;         /* True for write permission */
  BeFile *pOpen;     /* List of open files */

};

/*
** An cursor into a database file is an instance of the following structure.
** There can only be a single BeFile structure for each disk file, but
** there can be multiple DbbeCursor structures.  Each DbbeCursor represents
** a cursor pointing to a particular part of the open BeFile.  The
................................................................................
  datum key;         /* Most recently used key */
  datum data;        /* Most recent data */
  int needRewind;    /* Next key should be the first */
  int readPending;   /* The fetch hasn't actually been done yet */
};

/*
**
*/
struct DbbeList {
  FILE *pOut;
  Dbbe *pDbbe;
};
/*
** The "mkdir()" function only takes one argument under Windows.
*/
#if OS_WIN
# define mkdir(A,B) mkdir(A)
#endif

/*
................................................................................

/*
** Completely shutdown the given database.  Close all files.  Free all memory.
*/
static void sqliteGdbmClose(Dbbe *pDbbe){
  Dbbex *pBe = (Dbbex*)pDbbe;
  BeFile *pFile, *pNext;
  int i;
  for(pFile=pBe->pOpen; pFile; pFile=pNext){
    pNext = pFile->pNext;
    gdbm_close(pFile->dbf);
    memset(pFile, 0, sizeof(*pFile));   
    sqliteFree(pFile);
  }
  sqliteDbbeCloseAllTempFiles(pDbbe);
................................................................................
** of a file that holds the key/data pairs for that table or
** index.  Space to hold the filename is obtained from
** sqliteMalloc() and must be freed by the calling function.
*/
static char *sqliteFileOfTable(Dbbex *pBe, const char *zTable){
  char *zFile = 0;
  int i;
  sqliteSetString(&zFile, pBe->dbbe.zDir, "/", zTable, ".tbl", 0);
  if( zFile==0 ) return 0;
  for(i=strlen(pBe->dbbe.zDir)+1; zFile[i]; i++){
    int c = zFile[i];
    if( isupper(c) ){
      zFile[i] = tolower(c);
    }else if( !isalnum(c) && c!='-' && c!='_' && c!='.' ){
      zFile[i] = '+';
    }
  }
................................................................................
** a cursor to that temporary file is opened.  The temporary file
** will be deleted from the disk when it is closed.
*/
static int sqliteGdbmOpenCursor(
  Dbbe *pDbbe,            /* The database the table belongs to */
  const char *zTable,     /* The SQL name of the file to be opened */
  int writeable,          /* True to open for writing */

  DbbeCursor **ppCursr    /* Write the resulting table pointer here */
){
  char *zFile;            /* Name of the table file */
  DbbeCursor *pCursr;     /* The new table cursor */
  BeFile *pFile;          /* The underlying data file for this table */
  int rc = SQLITE_OK;     /* Return value */
  int rw_mask;            /* Permissions mask for opening a table */
................................................................................
/*
** Reorganize a table to reduce search times and disk usage.
*/
static int sqliteGdbmReorganizeTable(Dbbe *pBe, const char *zTable){
  DbbeCursor *pCrsr;
  int rc;

  rc = sqliteGdbmOpenCursor(pBe, zTable, 1, &pCrsr);
  if( rc!=SQLITE_OK ){
    return rc;
  }
  if( pCrsr && pCrsr->pFile && pCrsr->pFile->dbf ){
    gdbm_reorganize(pCrsr->pFile->dbf);
  }
  if( pCrsr ){
................................................................................
/*
** Get a new integer key.
*/
static int sqliteGdbmNew(DbbeCursor *pCursr){
  int iKey;
  datum key;
  int go = 1;
  int i;

  if( pCursr->pFile==0 || pCursr->pFile->dbf==0 ) return 1;
  while( go ){
    iKey = sqliteRandomInteger();
    if( iKey==0 ) continue;
    key.dptr = (char*)&iKey;
    key.dsize = 4;
................................................................................
  return iKey;
}   

/*
** Write an entry into the table.  Overwrite any prior entry with the
** same key.
*/
static int
sqliteGdbmPut(DbbeCursor *pCursr, int nKey,char *pKey,int nData,char *pData){





  datum data, key;
  int rc;
  if( pCursr->pFile==0 || pCursr->pFile->dbf==0 ) return SQLITE_ERROR;
  data.dsize = nData;
  data.dptr = pData;
  key.dsize = nKey;
  key.dptr = pKey;
................................................................................
  if( pCursr->pFile==0 || pCursr->pFile->dbf==0 ) return SQLITE_ERROR;
  key.dsize = nKey;
  key.dptr = pKey;
  rc = gdbm_delete(pCursr->pFile->dbf, key);
  if( rc ) rc = SQLITE_ERROR;
  return rc;
}










/*
** This variable contains pointers to all of the access methods
** used to implement the GDBM backend.
*/
static struct DbbeMethods gdbmMethods = {
  /* n         Close */   sqliteGdbmClose,
................................................................................
  /*       KeyLength */   sqliteGdbmKeyLength,
  /*      DataLength */   sqliteGdbmDataLength,
  /*         NextKey */   sqliteGdbmNextKey,
  /*          Rewind */   sqliteGdbmRewind,
  /*             New */   sqliteGdbmNew,
  /*             Put */   sqliteGdbmPut,
  /*          Delete */   sqliteGdbmDelete,
  /*    OpenTempFile */   sqliteDbbeOpenTempFile,
  /*   CloseTempFile */   sqliteDbbeCloseTempFile
};


/*
** This routine opens a new database.  For the GDBM driver
** implemented here, the database name is the name of the directory
................................................................................
  sqliteFree(zMaster);
  pNew = sqliteMalloc(sizeof(Dbbex) + strlen(zName) + 1);
  if( pNew==0 ){
    sqliteSetString(pzErrMsg, "out of memory", 0);
    return 0;
  }
  pNew->dbbe.x = &gdbmMethods;
  pNew->dbbe.zDir = (char*)&pNew[1];
  strcpy(pNew->dbbe.zDir, zName);
  pNew->write = writeFlag;
  pNew->pOpen = 0;
  return &pNew->dbbe;
}







|







 







>







 







<
<
<
<
<
<
<







 







<







 







|

|







 







>







 







|







 







<







 







|
|
>
>
>
>
>







 







>
>
>
>
>
>
>
>
>







 







|







 







|
|




26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
..
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
..
83
84
85
86
87
88
89







90
91
92
93
94
95
96
...
100
101
102
103
104
105
106

107
108
109
110
111
112
113
...
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
...
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
...
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
...
484
485
486
487
488
489
490

491
492
493
494
495
496
497
...
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
...
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
...
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
...
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: dbbegdbm.c,v 1.3 2001/01/15 22:51:10 drh Exp $
*/
#include "sqliteInt.h"
#include <gdbm.h>
#include <sys/stat.h>
#include <unistd.h>
#include <ctype.h>
#include <time.h>
................................................................................
** database driver.  This is a subclass of the Dbbe structure.
*/
typedef struct Dbbex Dbbex;
struct Dbbex {
  Dbbe dbbe;         /* The base class */
  int write;         /* True for write permission */
  BeFile *pOpen;     /* List of open files */
  char *zDir;        /* Directory hold the database */
};

/*
** An cursor into a database file is an instance of the following structure.
** There can only be a single BeFile structure for each disk file, but
** there can be multiple DbbeCursor structures.  Each DbbeCursor represents
** a cursor pointing to a particular part of the open BeFile.  The
................................................................................
  datum key;         /* Most recently used key */
  datum data;        /* Most recent data */
  int needRewind;    /* Next key should be the first */
  int readPending;   /* The fetch hasn't actually been done yet */
};

/*







** The "mkdir()" function only takes one argument under Windows.
*/
#if OS_WIN
# define mkdir(A,B) mkdir(A)
#endif

/*
................................................................................

/*
** Completely shutdown the given database.  Close all files.  Free all memory.
*/
static void sqliteGdbmClose(Dbbe *pDbbe){
  Dbbex *pBe = (Dbbex*)pDbbe;
  BeFile *pFile, *pNext;

  for(pFile=pBe->pOpen; pFile; pFile=pNext){
    pNext = pFile->pNext;
    gdbm_close(pFile->dbf);
    memset(pFile, 0, sizeof(*pFile));   
    sqliteFree(pFile);
  }
  sqliteDbbeCloseAllTempFiles(pDbbe);
................................................................................
** of a file that holds the key/data pairs for that table or
** index.  Space to hold the filename is obtained from
** sqliteMalloc() and must be freed by the calling function.
*/
static char *sqliteFileOfTable(Dbbex *pBe, const char *zTable){
  char *zFile = 0;
  int i;
  sqliteSetString(&zFile, pBe->zDir, "/", zTable, ".tbl", 0);
  if( zFile==0 ) return 0;
  for(i=strlen(pBe->zDir)+1; zFile[i]; i++){
    int c = zFile[i];
    if( isupper(c) ){
      zFile[i] = tolower(c);
    }else if( !isalnum(c) && c!='-' && c!='_' && c!='.' ){
      zFile[i] = '+';
    }
  }
................................................................................
** a cursor to that temporary file is opened.  The temporary file
** will be deleted from the disk when it is closed.
*/
static int sqliteGdbmOpenCursor(
  Dbbe *pDbbe,            /* The database the table belongs to */
  const char *zTable,     /* The SQL name of the file to be opened */
  int writeable,          /* True to open for writing */
  int intKeyOnly,         /* True if only integer keys are used */
  DbbeCursor **ppCursr    /* Write the resulting table pointer here */
){
  char *zFile;            /* Name of the table file */
  DbbeCursor *pCursr;     /* The new table cursor */
  BeFile *pFile;          /* The underlying data file for this table */
  int rc = SQLITE_OK;     /* Return value */
  int rw_mask;            /* Permissions mask for opening a table */
................................................................................
/*
** Reorganize a table to reduce search times and disk usage.
*/
static int sqliteGdbmReorganizeTable(Dbbe *pBe, const char *zTable){
  DbbeCursor *pCrsr;
  int rc;

  rc = sqliteGdbmOpenCursor(pBe, zTable, 1, 0, &pCrsr);
  if( rc!=SQLITE_OK ){
    return rc;
  }
  if( pCrsr && pCrsr->pFile && pCrsr->pFile->dbf ){
    gdbm_reorganize(pCrsr->pFile->dbf);
  }
  if( pCrsr ){
................................................................................
/*
** Get a new integer key.
*/
static int sqliteGdbmNew(DbbeCursor *pCursr){
  int iKey;
  datum key;
  int go = 1;


  if( pCursr->pFile==0 || pCursr->pFile->dbf==0 ) return 1;
  while( go ){
    iKey = sqliteRandomInteger();
    if( iKey==0 ) continue;
    key.dptr = (char*)&iKey;
    key.dsize = 4;
................................................................................
  return iKey;
}   

/*
** Write an entry into the table.  Overwrite any prior entry with the
** same key.
*/
static int sqliteGdbmPut(
  DbbeCursor *pCursr,  /* Write to the database associated with this cursor */
  int nKey,            /* Number of bytes in the key */
  char *pKey,          /* The data for the key */
  int nData,           /* Number of bytes of data */
  char *pData          /* The data */
){
  datum data, key;
  int rc;
  if( pCursr->pFile==0 || pCursr->pFile->dbf==0 ) return SQLITE_ERROR;
  data.dsize = nData;
  data.dptr = pData;
  key.dsize = nKey;
  key.dptr = pKey;
................................................................................
  if( pCursr->pFile==0 || pCursr->pFile->dbf==0 ) return SQLITE_ERROR;
  key.dsize = nKey;
  key.dptr = pKey;
  rc = gdbm_delete(pCursr->pFile->dbf, key);
  if( rc ) rc = SQLITE_ERROR;
  return rc;
}

/*
** Open a temporary file.  The file is located in the same directory
** as the rest of the database.
*/
static int sqliteGdbmOpenTempFile(Dbbe *pDbbe, FILE **ppFile){
  Dbbex *pBe = (Dbbex*)pDbbe;
  return sqliteDbbeOpenTempFile(pBe->zDir, pDbbe, ppFile);
}

/*
** This variable contains pointers to all of the access methods
** used to implement the GDBM backend.
*/
static struct DbbeMethods gdbmMethods = {
  /* n         Close */   sqliteGdbmClose,
................................................................................
  /*       KeyLength */   sqliteGdbmKeyLength,
  /*      DataLength */   sqliteGdbmDataLength,
  /*         NextKey */   sqliteGdbmNextKey,
  /*          Rewind */   sqliteGdbmRewind,
  /*             New */   sqliteGdbmNew,
  /*             Put */   sqliteGdbmPut,
  /*          Delete */   sqliteGdbmDelete,
  /*    OpenTempFile */   sqliteGdbmOpenTempFile,
  /*   CloseTempFile */   sqliteDbbeCloseTempFile
};


/*
** This routine opens a new database.  For the GDBM driver
** implemented here, the database name is the name of the directory
................................................................................
  sqliteFree(zMaster);
  pNew = sqliteMalloc(sizeof(Dbbex) + strlen(zName) + 1);
  if( pNew==0 ){
    sqliteSetString(pzErrMsg, "out of memory", 0);
    return 0;
  }
  pNew->dbbe.x = &gdbmMethods;
  pNew->zDir = (char*)&pNew[1];
  strcpy(pNew->zDir, zName);
  pNew->write = writeFlag;
  pNew->pOpen = 0;
  return &pNew->dbbe;
}

Changes to src/dbbemem.c.

24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
...
335
336
337
338
339
340
341

342
343
344
345
346
347
348
...
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
...
448
449
450
451
452
453
454

455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
...
490
491
492
493
494
495
496

497
498

499
500
501
502
503
504
505
...
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
...
561
562
563
564
565
566
567

568
569
570
571
572
573
574
...
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
...
677
678
679
680
681
682
683
684
685



686
687
688
689
690
691

692
693
694
695
696
697
698
...
707
708
709
710
711
712
713




















714
715
716
717
718
719
720
...
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
...
759
760
761
762
763
764
765
766
767
768
** This file contains code to implement the database backend (DBBE)
** for sqlite.  The database backend is the interface between
** sqlite and the code that does the actually reading and writing
** of information to the disk.
**
** This file uses an in-memory hash table as the database backend. 
**
** $Id: dbbemem.c,v 1.6 2001/01/13 14:34:06 drh Exp $
*/
#include "sqliteInt.h"
#include <sys/stat.h>
#include <unistd.h>
#include <ctype.h>
#include <time.h>

................................................................................
** for a self-join, for example) then two DbbeCursor structures are
** created but there is only a single MTable structure.
*/
typedef struct MTable MTable;
struct MTable {
  char *zName;            /* Name of the table */
  int delOnClose;         /* Delete when closing */

  Array data;             /* The data in this stable */
};

/*
** The following structure contains all information used by GDBM
** database driver.  This is a subclass of the Dbbe structure.
*/
................................................................................
}

/*
** Completely shutdown the given database.  Close all files.  Free all memory.
*/
static void sqliteMemClose(Dbbe *pDbbe){
  Dbbex *pBe = (Dbbex*)pDbbe;
  MTable *pTble, *pNext;
  int i;
  ArrayElem *j, *k;
  for(j=ArrayFirst(&pBe->tables); j; j=ArrayNext(j)){
    pTble = ArrayData(j);
    deleteMTable(pTble);
  }
  ArrayClear(&pBe->tables);
  sqliteDbbeCloseAllTempFiles(pDbbe);
  memset(pBe, 0, sizeof(*pBe));
................................................................................
** a cursor to that temporary file is opened.  The temporary file
** will be deleted from the disk when it is closed.
*/
static int sqliteMemOpenCursor(
  Dbbe *pDbbe,            /* The database the table belongs to */
  const char *zTable,     /* The SQL name of the file to be opened */
  int writeable,          /* True to open for writing */

  DbbeCursor **ppCursr    /* Write the resulting table pointer here */
){
  DbbeCursor *pCursr;     /* The new table cursor */
  char *zName;            /* Canonical table name */
  MTable *pTble;          /* The underlying data file for this table */
  int rc = SQLITE_OK;     /* Return value */
  int rw_mask;            /* Permissions mask for opening a table */
  int mode;               /* Mode for opening a table */
  Dbbex *pBe = (Dbbex*)pDbbe;

  *ppCursr = 0;
  pCursr = sqliteMalloc( sizeof(*pCursr) );
  if( pCursr==0 ) return SQLITE_NOMEM;
  if( zTable ){
    Datum key;
................................................................................
      ins_key.p = zName;
      ins_key.n = strlen(zName);
      ArrayInsert(&pBe->tables, ins_key, ins_data);
    }else{
      pTble->zName = 0;
      pTble->delOnClose = 1;
    }

    ArrayInit(&pTble->data);
  }else{

    sqliteFree(zName);
  }
  pCursr->pBe = pBe;
  pCursr->pTble = pTble;
  pCursr->needRewind = 1;
  *ppCursr = pCursr;
  return rc;
................................................................................
** Drop a table from the database.  The file on the disk that corresponds
** to this table is deleted.
*/
static void sqliteMemDropTable(Dbbe *pDbbe, const char *zTable){
  char *zName;            /* Name of the table file */
  Datum key, data;
  MTable *pTble;
  ArrayElem *i;
  Dbbex *pBe = (Dbbex*)pDbbe;

  zName = sqliteNameOfTable(zTable);
  key.p = zName;
  key.n = strlen(zName);
  pTble = ArrayFind(&pBe->tables, key).p;
  if( pTble ){
................................................................................
** Fetch a single record from an open cursor.  Return 1 on success
** and 0 on failure.
*/
static int sqliteMemFetch(DbbeCursor *pCursr, int nKey, char *pKey){
  Datum key;
  key.n = nKey;
  key.p = pKey;

  pCursr->elem = ArrayFindElement(&pCursr->pTble->data, key);
  return pCursr->elem!=0;
}

/*
** Return 1 if the given key is already in the table.  Return 0
** if it is not.
................................................................................
/*
** Get a new integer key.
*/
static int sqliteMemNew(DbbeCursor *pCursr){
  int iKey;
  Datum key;
  int go = 1;
  int i;

  while( go ){
    iKey = sqliteRandomInteger();
    if( iKey==0 ) continue;
    key.p = (char*)&iKey;
    key.n = 4;
    go = ArrayFindElement(&pCursr->pTble->data, key)!=0;
................................................................................
  return iKey;
}   

/*
** Write an entry into the table.  Overwrite any prior entry with the
** same key.
*/
static int
sqliteMemPut(DbbeCursor *pCursr, int nKey,char *pKey, int nData, char *pData){



  Datum data, key;
  data.n = nData;
  data.p = sqliteMalloc( data.n );
  memcpy(data.p, pData, data.n);
  key.n = nKey;
  key.p = pKey;

  data = ArrayInsert(&pCursr->pTble->data, key, data);
  if( data.p ){
    sqliteFree(data.p);
  }
  return SQLITE_OK;
}

................................................................................
  data.n = 0;
  data = ArrayInsert(&pCursr->pTble->data, key, data);
  if( data.p ){
    sqliteFree(data.p);
  }
  return SQLITE_OK;
}





















/*
** This variable contains pointers to all of the access methods
** used to implement the MEMORY backend.
*/
static struct DbbeMethods memoryMethods = {
  /* n         Close */   sqliteMemClose,
................................................................................
  /*       KeyLength */   sqliteMemKeyLength,
  /*      DataLength */   sqliteMemDataLength,
  /*         NextKey */   sqliteMemNextKey,
  /*          Rewind */   sqliteMemRewind,
  /*             New */   sqliteMemNew,
  /*             Put */   sqliteMemPut,
  /*          Delete */   sqliteMemDelete,
  /*    OpenTempFile */   sqliteDbbeOpenTempFile,
  /*   CloseTempFile */   sqliteDbbeCloseTempFile
};

/*
** This routine opens a new database.  For the GDBM driver
** implemented here, the database name is the name of the directory
** containing all the files of the database.
................................................................................
  pNew = sqliteMalloc( sizeof(*pNew) );
  if( pNew==0 ){
    sqliteSetString(pzErrMsg, "out of memory", 0);
    return 0;
  }
  ArrayInit(&pNew->tables);
  pNew->dbbe.x = &memoryMethods;
  pNew->dbbe.zDir = 0;
  return &pNew->dbbe;
}







|







 







>







 







|
<
|







 







>






<
<







 







>


>







 







<







 







>







 







<







 







|
|
>
>
>






>







 







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







 







|







 







<


24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
...
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
...
388
389
390
391
392
393
394
395

396
397
398
399
400
401
402
403
...
448
449
450
451
452
453
454
455
456
457
458
459
460
461


462
463
464
465
466
467
468
...
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
...
510
511
512
513
514
515
516

517
518
519
520
521
522
523
...
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
...
662
663
664
665
666
667
668

669
670
671
672
673
674
675
...
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
...
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
...
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
...
783
784
785
786
787
788
789

790
791
** This file contains code to implement the database backend (DBBE)
** for sqlite.  The database backend is the interface between
** sqlite and the code that does the actually reading and writing
** of information to the disk.
**
** This file uses an in-memory hash table as the database backend. 
**
** $Id: dbbemem.c,v 1.7 2001/01/15 22:51:10 drh Exp $
*/
#include "sqliteInt.h"
#include <sys/stat.h>
#include <unistd.h>
#include <ctype.h>
#include <time.h>

................................................................................
** for a self-join, for example) then two DbbeCursor structures are
** created but there is only a single MTable structure.
*/
typedef struct MTable MTable;
struct MTable {
  char *zName;            /* Name of the table */
  int delOnClose;         /* Delete when closing */
  int intKeyOnly;         /* Use only integer keys on this table */
  Array data;             /* The data in this stable */
};

/*
** The following structure contains all information used by GDBM
** database driver.  This is a subclass of the Dbbe structure.
*/
................................................................................
}

/*
** Completely shutdown the given database.  Close all files.  Free all memory.
*/
static void sqliteMemClose(Dbbe *pDbbe){
  Dbbex *pBe = (Dbbex*)pDbbe;
  MTable *pTble;

  ArrayElem *j;
  for(j=ArrayFirst(&pBe->tables); j; j=ArrayNext(j)){
    pTble = ArrayData(j);
    deleteMTable(pTble);
  }
  ArrayClear(&pBe->tables);
  sqliteDbbeCloseAllTempFiles(pDbbe);
  memset(pBe, 0, sizeof(*pBe));
................................................................................
** a cursor to that temporary file is opened.  The temporary file
** will be deleted from the disk when it is closed.
*/
static int sqliteMemOpenCursor(
  Dbbe *pDbbe,            /* The database the table belongs to */
  const char *zTable,     /* The SQL name of the file to be opened */
  int writeable,          /* True to open for writing */
  int intKeyOnly,         /* True if only integer keys are used */
  DbbeCursor **ppCursr    /* Write the resulting table pointer here */
){
  DbbeCursor *pCursr;     /* The new table cursor */
  char *zName;            /* Canonical table name */
  MTable *pTble;          /* The underlying data file for this table */
  int rc = SQLITE_OK;     /* Return value */


  Dbbex *pBe = (Dbbex*)pDbbe;

  *ppCursr = 0;
  pCursr = sqliteMalloc( sizeof(*pCursr) );
  if( pCursr==0 ) return SQLITE_NOMEM;
  if( zTable ){
    Datum key;
................................................................................
      ins_key.p = zName;
      ins_key.n = strlen(zName);
      ArrayInsert(&pBe->tables, ins_key, ins_data);
    }else{
      pTble->zName = 0;
      pTble->delOnClose = 1;
    }
    pTble->intKeyOnly = intKeyOnly;
    ArrayInit(&pTble->data);
  }else{
    assert( pTble->intKeyOnly==intKeyOnly );
    sqliteFree(zName);
  }
  pCursr->pBe = pBe;
  pCursr->pTble = pTble;
  pCursr->needRewind = 1;
  *ppCursr = pCursr;
  return rc;
................................................................................
** Drop a table from the database.  The file on the disk that corresponds
** to this table is deleted.
*/
static void sqliteMemDropTable(Dbbe *pDbbe, const char *zTable){
  char *zName;            /* Name of the table file */
  Datum key, data;
  MTable *pTble;

  Dbbex *pBe = (Dbbex*)pDbbe;

  zName = sqliteNameOfTable(zTable);
  key.p = zName;
  key.n = strlen(zName);
  pTble = ArrayFind(&pBe->tables, key).p;
  if( pTble ){
................................................................................
** Fetch a single record from an open cursor.  Return 1 on success
** and 0 on failure.
*/
static int sqliteMemFetch(DbbeCursor *pCursr, int nKey, char *pKey){
  Datum key;
  key.n = nKey;
  key.p = pKey;
  assert( nKey==4 || pCursr->pTble->intKeyOnly==0 );
  pCursr->elem = ArrayFindElement(&pCursr->pTble->data, key);
  return pCursr->elem!=0;
}

/*
** Return 1 if the given key is already in the table.  Return 0
** if it is not.
................................................................................
/*
** Get a new integer key.
*/
static int sqliteMemNew(DbbeCursor *pCursr){
  int iKey;
  Datum key;
  int go = 1;


  while( go ){
    iKey = sqliteRandomInteger();
    if( iKey==0 ) continue;
    key.p = (char*)&iKey;
    key.n = 4;
    go = ArrayFindElement(&pCursr->pTble->data, key)!=0;
................................................................................
  return iKey;
}   

/*
** Write an entry into the table.  Overwrite any prior entry with the
** same key.
*/
static int sqliteMemPut(
  DbbeCursor *pCursr,       /* Write new entry into this database table */
  int nKey, char *pKey,     /* The key of the new entry */
  int nData, char *pData    /* The data of the new entry */
){
  Datum data, key;
  data.n = nData;
  data.p = sqliteMalloc( data.n );
  memcpy(data.p, pData, data.n);
  key.n = nKey;
  key.p = pKey;
  assert( nKey==4 || pCursr->pTble->intKeyOnly==0 );
  data = ArrayInsert(&pCursr->pTble->data, key, data);
  if( data.p ){
    sqliteFree(data.p);
  }
  return SQLITE_OK;
}

................................................................................
  data.n = 0;
  data = ArrayInsert(&pCursr->pTble->data, key, data);
  if( data.p ){
    sqliteFree(data.p);
  }
  return SQLITE_OK;
}

/*
** Open a temporary file.  The file is located in the current working
** directory.
*/
static int sqliteMemOpenTempFile(Dbbe *pDbbe, FILE **ppFile){
  const char *zTemps[] = { "/usr/tmp", "/var/tmp", "/tmp", "/temp", 0};
  const char *zDir;
  int i;
  struct stat statbuf;
  for(i=0; zTemps[i]; i++){
    zDir = zTemps[i];
    if( stat("/usr/tmp", &statbuf)==0 && S_ISDIR(statbuf.st_mode) 
      && access("/usr/tmp", W_OK|X_OK)==0 ){
        break;
    }
  }
  if( zDir==0 ) zDir = ".";
  return sqliteDbbeOpenTempFile(zDir, pDbbe, ppFile);
}

/*
** This variable contains pointers to all of the access methods
** used to implement the MEMORY backend.
*/
static struct DbbeMethods memoryMethods = {
  /* n         Close */   sqliteMemClose,
................................................................................
  /*       KeyLength */   sqliteMemKeyLength,
  /*      DataLength */   sqliteMemDataLength,
  /*         NextKey */   sqliteMemNextKey,
  /*          Rewind */   sqliteMemRewind,
  /*             New */   sqliteMemNew,
  /*             Put */   sqliteMemPut,
  /*          Delete */   sqliteMemDelete,
  /*    OpenTempFile */   sqliteMemOpenTempFile,
  /*   CloseTempFile */   sqliteDbbeCloseTempFile
};

/*
** This routine opens a new database.  For the GDBM driver
** implemented here, the database name is the name of the directory
** containing all the files of the database.
................................................................................
  pNew = sqliteMalloc( sizeof(*pNew) );
  if( pNew==0 ){
    sqliteSetString(pzErrMsg, "out of memory", 0);
    return 0;
  }
  ArrayInit(&pNew->tables);
  pNew->dbbe.x = &memoryMethods;

  return &pNew->dbbe;
}

Changes to src/delete.c.

20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
...
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
**   drh@hwaci.com
**   http://www.hwaci.com/drh/
**
*************************************************************************
** This file contains C code routines that are called by the parser
** to handle DELETE FROM statements.
**
** $Id: delete.c,v 1.6 2000/06/21 13:59:11 drh Exp $
*/
#include "sqliteInt.h"

/*
** Process a DELETE FROM statement.
*/
void sqliteDeleteFrom(
................................................................................

  /* Delete every item whose key was written to the list during the
  ** database scan.  We have to delete items after the scan is complete
  ** because deleting an item can change the scan order.
  */
  base = pParse->nTab;
  sqliteVdbeAddOp(v, OP_ListRewind, 0, 0, 0, 0);
  sqliteVdbeAddOp(v, OP_Open, base, 1, pTab->zName, 0);
  for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
    sqliteVdbeAddOp(v, OP_Open, base+i, 1, pIdx->zName, 0);
  }
  end = sqliteVdbeMakeLabel(v);
  addr = sqliteVdbeAddOp(v, OP_ListRead, 0, end, 0, 0);
  if( pTab->pIndex ){
    sqliteVdbeAddOp(v, OP_Dup, 0, 0, 0, 0);
    sqliteVdbeAddOp(v, OP_Fetch, base, 0, 0, 0);
    for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){







|







 







|

|







20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
...
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
**   drh@hwaci.com
**   http://www.hwaci.com/drh/
**
*************************************************************************
** This file contains C code routines that are called by the parser
** to handle DELETE FROM statements.
**
** $Id: delete.c,v 1.7 2001/01/15 22:51:10 drh Exp $
*/
#include "sqliteInt.h"

/*
** Process a DELETE FROM statement.
*/
void sqliteDeleteFrom(
................................................................................

  /* Delete every item whose key was written to the list during the
  ** database scan.  We have to delete items after the scan is complete
  ** because deleting an item can change the scan order.
  */
  base = pParse->nTab;
  sqliteVdbeAddOp(v, OP_ListRewind, 0, 0, 0, 0);
  sqliteVdbeAddOp(v, OP_OpenTbl, base, 1, pTab->zName, 0);
  for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
    sqliteVdbeAddOp(v, OP_OpenIdx, base+i, 1, pIdx->zName, 0);
  }
  end = sqliteVdbeMakeLabel(v);
  addr = sqliteVdbeAddOp(v, OP_ListRead, 0, end, 0, 0);
  if( pTab->pIndex ){
    sqliteVdbeAddOp(v, OP_Dup, 0, 0, 0, 0);
    sqliteVdbeAddOp(v, OP_Fetch, base, 0, 0, 0);
    for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){

Changes to src/expr.c.

20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
...
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
**   drh@hwaci.com
**   http://www.hwaci.com/drh/
**
*************************************************************************
** This file contains routines used for analyzing expressions and
** for generating VDBE code that evaluates expressions.
**
** $Id: expr.c,v 1.20 2000/11/28 20:47:18 drh Exp $
*/
#include "sqliteInt.h"

/*
** Walk an expression tree.  Return 1 if the expression is constant
** and 0 if it involves variables.
*/
................................................................................
      if( pExpr->pSelect ){
        /* Case 1:     expr IN (SELECT ...)
        **
        ** Generate code to write the results of the select into a temporary
        ** table.  The cursor number of the temporary table has already
        ** been put in iTable by sqliteExprResolveInSelect().
        */
        sqliteVdbeAddOp(v, OP_Open, pExpr->iTable, 1, 0, 0);
        if( sqliteSelect(pParse, pExpr->pSelect, SRT_Set, pExpr->iTable) );
      }else if( pExpr->pList ){
        /* Case 2:     expr IN (exprlist)
        **
        ** Create a set to put the exprlist values in.  The Set id is stored
        ** in iTable.
        */







|







 







|







20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
...
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
**   drh@hwaci.com
**   http://www.hwaci.com/drh/
**
*************************************************************************
** This file contains routines used for analyzing expressions and
** for generating VDBE code that evaluates expressions.
**
** $Id: expr.c,v 1.21 2001/01/15 22:51:10 drh Exp $
*/
#include "sqliteInt.h"

/*
** Walk an expression tree.  Return 1 if the expression is constant
** and 0 if it involves variables.
*/
................................................................................
      if( pExpr->pSelect ){
        /* Case 1:     expr IN (SELECT ...)
        **
        ** Generate code to write the results of the select into a temporary
        ** table.  The cursor number of the temporary table has already
        ** been put in iTable by sqliteExprResolveInSelect().
        */
        sqliteVdbeAddOp(v, OP_OpenIdx, pExpr->iTable, 1, 0, 0);
        if( sqliteSelect(pParse, pExpr->pSelect, SRT_Set, pExpr->iTable) );
      }else if( pExpr->pList ){
        /* Case 2:     expr IN (exprlist)
        **
        ** Create a set to put the exprlist values in.  The Set id is stored
        ** in iTable.
        */

Changes to src/insert.c.

20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
..
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
...
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
**   drh@hwaci.com
**   http://www.hwaci.com/drh/
**
*************************************************************************
** This file contains C code routines that are called by the parser
** to handle INSERT statements.
**
** $Id: insert.c,v 1.11 2000/06/21 13:59:12 drh Exp $
*/
#include "sqliteInt.h"

/*
** This routine is call to handle SQL of the following forms:
**
**    insert into TABLE (IDLIST) values(EXPRLIST)
................................................................................
  ** all the code to implement the SELECT statement and leave the data
  ** in a temporary table.  If data is coming from an expression list,
  ** then we just have to count the number of expressions.
  */
  if( pSelect ){
    int rc;
    srcTab = pParse->nTab++;
    sqliteVdbeAddOp(v, OP_Open, srcTab, 1, 0, 0);
    rc = sqliteSelect(pParse, pSelect, SRT_Table, srcTab);
    if( rc ) goto insert_cleanup;
    assert( pSelect->pEList );
    nColumn = pSelect->pEList->nExpr;
  }else{
    srcTab = -1;
    assert( pList );
................................................................................
    }
  }

  /* Open cursors into the table that is received the new data and
  ** all indices of that table.
  */
  base = pParse->nTab;
  sqliteVdbeAddOp(v, OP_Open, base, 1, pTab->zName, 0);
  for(idx=1, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, idx++){
    sqliteVdbeAddOp(v, OP_Open, idx+base, 1, pIdx->zName, 0);
  }

  /* If the data source is a SELECT statement, then we have to create
  ** a loop because there might be multiple rows of data.  If the data
  ** source is an expression list, then exactly one row will be inserted
  ** and the loop is not used.
  */







|







 







|







 







|

|







20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
..
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
...
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
**   drh@hwaci.com
**   http://www.hwaci.com/drh/
**
*************************************************************************
** This file contains C code routines that are called by the parser
** to handle INSERT statements.
**
** $Id: insert.c,v 1.12 2001/01/15 22:51:11 drh Exp $
*/
#include "sqliteInt.h"

/*
** This routine is call to handle SQL of the following forms:
**
**    insert into TABLE (IDLIST) values(EXPRLIST)
................................................................................
  ** all the code to implement the SELECT statement and leave the data
  ** in a temporary table.  If data is coming from an expression list,
  ** then we just have to count the number of expressions.
  */
  if( pSelect ){
    int rc;
    srcTab = pParse->nTab++;
    sqliteVdbeAddOp(v, OP_OpenTbl, srcTab, 1, 0, 0);
    rc = sqliteSelect(pParse, pSelect, SRT_Table, srcTab);
    if( rc ) goto insert_cleanup;
    assert( pSelect->pEList );
    nColumn = pSelect->pEList->nExpr;
  }else{
    srcTab = -1;
    assert( pList );
................................................................................
    }
  }

  /* Open cursors into the table that is received the new data and
  ** all indices of that table.
  */
  base = pParse->nTab;
  sqliteVdbeAddOp(v, OP_OpenTbl, base, 1, pTab->zName, 0);
  for(idx=1, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, idx++){
    sqliteVdbeAddOp(v, OP_OpenIdx, idx+base, 1, pIdx->zName, 0);
  }

  /* If the data source is a SELECT statement, then we have to create
  ** a loop because there might be multiple rows of data.  If the data
  ** source is an expression list, then exactly one row will be inserted
  ** and the loop is not used.
  */

Changes to src/main.c.

22
23
24
25
26
27
28
29
30
31

32
33
34
35
36
37
38
...
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
...
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
**
*************************************************************************
** Main file for the SQLite library.  The routines in this file
** implement the programmer interface to the library.  Routines in
** other files are for internal use by SQLite and should not be
** accessed by users of the library.
**
** $Id: main.c,v 1.23 2001/01/13 14:34:06 drh Exp $
*/
#include "sqliteInt.h"


/*
** This is the callback routine for the code that initializes the
** database.  Each callback contains text of a CREATE TABLE or
** CREATE INDEX statement that must be parsed to yield the internal
** structures that describe the tables.
**
................................................................................
  ** The following program invokes its callback on the SQL for each
  ** table then goes back and invokes the callback on the
  ** SQL for each index.  The callback will invoke the
  ** parser to build the internal representation of the
  ** database scheme.
  */
  static VdbeOp initProg[] = {
    { OP_Open,     0, 0,  MASTER_NAME},
    { OP_Next,     0, 9,  0},           /* 1 */
    { OP_Field,    0, 0,  0},
    { OP_String,   0, 0,  "meta"},
    { OP_Ne,       0, 1,  0},
    { OP_Field,    0, 0,  0},
    { OP_Field,    0, 3,  0},
    { OP_Callback, 2, 0,  0},
................................................................................
  sqlite *db,                 /* The database on which the SQL executes */
  char *zSql,                 /* The SQL to be executed */
  sqlite_callback xCallback,  /* Invoke this callback routine */
  void *pArg,                 /* First argument to xCallback() */
  char **pzErrMsg             /* Write error messages here */
){
  Parse sParse;
  int rc;

  if( pzErrMsg ) *pzErrMsg = 0;
  if( (db->flags & SQLITE_Initialized)==0 ){
    int rc = sqliteInit(db, pzErrMsg);
    if( rc!=SQLITE_OK ) return rc;
  }
  memset(&sParse, 0, sizeof(sParse));







|


>







 







|







 







<







22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
...
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
...
318
319
320
321
322
323
324

325
326
327
328
329
330
331
**
*************************************************************************
** Main file for the SQLite library.  The routines in this file
** implement the programmer interface to the library.  Routines in
** other files are for internal use by SQLite and should not be
** accessed by users of the library.
**
** $Id: main.c,v 1.24 2001/01/15 22:51:11 drh Exp $
*/
#include "sqliteInt.h"
#include <unistd.h>

/*
** This is the callback routine for the code that initializes the
** database.  Each callback contains text of a CREATE TABLE or
** CREATE INDEX statement that must be parsed to yield the internal
** structures that describe the tables.
**
................................................................................
  ** The following program invokes its callback on the SQL for each
  ** table then goes back and invokes the callback on the
  ** SQL for each index.  The callback will invoke the
  ** parser to build the internal representation of the
  ** database scheme.
  */
  static VdbeOp initProg[] = {
    { OP_OpenTbl,    0, 0,  MASTER_NAME},
    { OP_Next,     0, 9,  0},           /* 1 */
    { OP_Field,    0, 0,  0},
    { OP_String,   0, 0,  "meta"},
    { OP_Ne,       0, 1,  0},
    { OP_Field,    0, 0,  0},
    { OP_Field,    0, 3,  0},
    { OP_Callback, 2, 0,  0},
................................................................................
  sqlite *db,                 /* The database on which the SQL executes */
  char *zSql,                 /* The SQL to be executed */
  sqlite_callback xCallback,  /* Invoke this callback routine */
  void *pArg,                 /* First argument to xCallback() */
  char **pzErrMsg             /* Write error messages here */
){
  Parse sParse;


  if( pzErrMsg ) *pzErrMsg = 0;
  if( (db->flags & SQLITE_Initialized)==0 ){
    int rc = sqliteInit(db, pzErrMsg);
    if( rc!=SQLITE_OK ) return rc;
  }
  memset(&sParse, 0, sizeof(sParse));

Added src/pg.c.



























































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
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
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
120
121
122
123
124
125
126
127
128
129
130
131
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
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
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
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
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
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
332
333
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
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
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
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
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
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
/*
** Copyright (c) 2001 D. Richard Hipp
**
** This program is free software; you can redistribute it and/or
** modify it under the terms of the GNU General Public
** License as published by the Free Software Foundation; either
** version 2 of the License, or (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
** General Public License for more details.
** 
** You should have received a copy of the GNU General Public
** License along with this library; if not, write to the
** Free Software Foundation, Inc., 59 Temple Place - Suite 330,
** Boston, MA  02111-1307, USA.
**
** Author contact information:
**   drh@hwaci.com
**   http://www.hwaci.com/drh/
**
*************************************************************************
** $Id: pg.c,v 1.1 2001/01/15 22:51:11 drh Exp $
*/
#include <assert.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include "sqliteInt.h"
#include "pg.h"

/*
** Uncomment the following for a debug trace
*/
#if 1
# define TRACE(X)  printf X; fflush(stdout);
#endif  

#ifndef SQLITE_IOERR
# define SQLITE_IOERR SQLITE_ERROR
#endif

/*
** Hash table sizes
*/
#define J_HASH_SIZE  127  /* Size of the journal page hash table */
#define PG_HASH_SIZE 349  /* Size of the database page hash table */

/*
** Forward declaration of structure
*/
typedef struct Pghdr Pghdr;

/*
** All information about a single paging file is contained in an
** instance of the following structure.
*/
struct Pgr {
  int fdMain;                    /* The main database file */
  char *zMain;                   /* Name of the database file */
  int fdJournal;                 /* The journal file */
  char *zJournal;                /* Name of the journal file */
  int nMemPg;                    /* Number of memory-resident pages */
  int nJPg;                      /* Number of pages in the journal */
  int nDbPg;                     /* Number of pages in the database */
  int nRefPg;                    /* Number of pages currently in use */
  Pghdr *pLru, *pMru;            /* Least and most recently used mem-page */
  Pghdr *pJidx;                  /* List of journal index pages */
  Pghdr *pAll;                   /* All pages, except journal index pages */
  u32 aJHash[J_HASH_SIZE];       /* Journal page hash table */
  Pghdr *aPgHash[PG_HASH_SIZE];  /* Mem-page hash table */
};

/*
** Each memory-resident page of the paging file has a header which
** is an instance of the following structure.
*/
struct Pghdr {
  Pgr *p;            /* Pointer back to the Pgr structure */
  int nRef;          /* Number of references to this page */
  int isDirty;       /* TRUE if needs to be written to disk */
  u32 dbpgno;        /* Page number in the database file */
  u32 jpgno;         /* Page number in the journal file */
  Pghdr *pNx;        /* Next page on a list of them all */
  Pghdr *pLru;       /* Less recently used pages */
  Pghdr *pMru;       /* More recently used pages */
  Pghdr *pNxHash;    /* Next with same dbpgno hash */
  Pghdr *pPvHash;    /* Previous with the same dbpgno hash */
};

/*
** For a memory-resident page, the page data comes immediately after
** the page header.  The following macros can be used to change a 
** pointer to a page header into a pointer to the data, or vice
** versa.
*/
#define PG_TO_DATA(X)  ((void*)&(X)[1])
#define DATA_TO_PG(X)  (&((Pghdr*)(X))[-1])

/*
** The number of in-memory pages that we accumulate before trying
** to reuse older pages when new ones are requested.
*/
#define MX_MEM_PAGE  100

/*
** The number of journal data pages that come between consecutive 
** journal index pages.
*/
#define N_J_DATAPAGE  (SQLITE_PAGE_SIZE/(2*sizeof(u32)))

/*
** An index page in the journal consists of an array of N_J_DATAPAGE
** of the following structures.  There is one instance of the following
** structure for each of the N_J_DATAPAGE data pages that follow the
** index.
**
** Let the journal page number that a JidxEntry describes be J.  Then
** the JidxEntry.dbpgno field is the page of the database file that
** corresponds to the J page in the journal.  The JidxEntry.next_jpgno
** field hold the number of another journal page that contains
** a database file page with the same hash as JidxEntry.dbpgno.
**
** All information is written to the journal index in big-endian
** notation.
*/
typedef struct JidxEntry JidxEntry;
struct JidxEntry {
  char dbpgno[sizeof(u32)];        /* Database page number for this entry */
  char next_jpgno[sizeof(u32)];    /* Next entry with same hash on dbpgno */
};

/*
** Read a page from a file into memory.  Return SQLITE_OK if successful.
** The "pgno" parameter tells where in the file to read the page.
** The first page is 1.  Files do not contain a page 0 since a page
** number of 0 is used to indicate "no such page".
*/
static int sqlitePgRead(int fd, char *zBuf, u32 pgno){
  int got = 0;
  int amt;

  assert( pgno>0 );
  assert( fd>=0 );
  lseek(fd, SEEK_SET, (pgno-1)*SQLITE_PAGE_SIZE);
  while( got<SQLITE_PAGE_SIZE ){
    amt = read(fd, &zBuf[got], SQLITE_PAGE_SIZE - got);
    if( amt<=0 ){
      memset(&zBuf[got], 0, SQLITE_PAGE_SIZE - got);
      return amt==0 ? SQLITE_OK : SQLITE_IOERR;
    }
    got += amt;
  }
  return SQLITE_OK;
}

/*
** Read a page from a file into memory.  Return SQLITE_OK if successful.
** The "pgno" parameter tells where in the file to write the page.
** The first page is 1.  Files do not contain a page 0 since a page
** number of 0 is used to indicate "no such page".
*/
static int sqlitePgWrite(int fd, char *zBuf, u32 pgno){
  int done = 0;
  int amt;

  assert( pgno>0 );
  assert( fd>=0 );
  lseek(fd, SEEK_SET, (pgno-1)*SQLITE_PAGE_SIZE);
  while( done<SQLITE_PAGE_SIZE ){
    amt = write(fd, &zBuf[done], SQLITE_PAGE_SIZE - done);
    if( amt<=0 ) return SQLITE_IOERR;
    done += amt;
  }
  return SQLITE_OK;
}

/*
** Turn four bytes into an integer.  The first byte is always the
** most significant 8 bits.
*/
static u32 sqlitePgGetInt(const char *p){
  return ((p[0]&0xff)<<24) | ((p[1]&0xff)<<16) | ((p[2]&0xff)<<8) | (p[3]&0xff);
}

/*
** Turn an integer into 4 bytes.  The first byte is always the
** most significant 8 bits.
*/
static void sqlitePgPutInt(u32 v, char *p){
  p[3] = v & 0xff;
  v >>= 8;
  p[2] = v & 0xff;
  v >>= 8;
  p[1] = v & 0xff;
  v >>= 8;
  p[0] = v & 0xff;
}

/*
** Check the hash table for an in-memory page.  Return a pointer to
** the page header if found.  Return NULL if the page is not in memory.
*/
static Pghdr *sqlitePgFind(Pgr *p, u32 pgno){
  int h;
  Pghdr *pPg;

  if( pgno==0 ) return 0;
  h = pgno % PG_HASH_SIZE;
  for(pPg = p->aPgHash[h]; pPg; pPg=pPg->pNxHash){
    if( pPg->dbpgno==pgno ) return pPg;
  }
  TRACE(("PG: data page %u is %#x\n", pgno, (u32)pPg));
  return 0;
}

/*
** Locate and return an index page from the journal.
**
** The first page of a journal is the primary index.  Additional
** index pages are called secondary indices.  Index pages appear
** in the journal as often as needed.  (If SQLITE_PAGE_SIZE==1024,
** then there are 1024/sizeof(int)*2 = 128 database between each
** pair of index pages.)  Journal index pages are not hashed and
** do no appear on the Pgr.pAll list.  Index pages are on the
** Pgr.pJidx list only.  Index pages have Pghdr.dbpgno==0.
**
** If the requested index page is not already in memory, then a
** new memory page is created to hold the index.
**
** This routine will return a NULL pointer if we run out of memory.
*/
static Pghdr *sqlitePgFindJidx(Pgr *p, u32 pgno){
  Pghdr *pPg;

  assert( pgno % (N_J_DATAPAGE+1) == 1 );
  for(pPg=p->pJidx; pPg; pPg=pPg->pNx){
    if( pPg->jpgno==pgno ){
      TRACE(("PG: found j-index %u at %#x\n", pgno, (u32)pPg));
      return pPg;
    }
  }
  pPg = sqliteMalloc( sizeof(Pghdr)+SQLITE_PAGE_SIZE );
  if( pPg==0 ) return 0;
  pPg->jpgno = pgno;
  pPg->pNx = p->pJidx;
  p->pJidx = pPg;
  sqlitePgRead(p->fdJournal, PG_TO_DATA(pPg), pgno);
  TRACE(("PG: create j-index %u at %#x\n", pgno, (u32)pPg));
  return pPg;
}

/*
** Look in the journal to see if the given database page is stored
** in the journal.  If it is, return its journal page number.  If
** not, return 0.
*/
static u32 sqlitePgJournalPageNumber(Pgr *p, u32 dbpgno){
  u32 jpgno;
  
  assert( dbpgno>0 );
  jpgno = p->aJHash[dbpgno % J_HASH_SIZE];
  while( jpgno!=0 ){
    int idx_num;     /* Which journal index describes page jpgno */
    int ipgno;       /* Page number for the journal index */
    int idx_slot;    /* Which entry in index idx_num describes jpgno */
    Pghdr *pIdxPg;   /* The index page for jpgno */
    JidxEntry *aIdx; /* The data for the index page */

    idx_num = (jpgno - 1)/(N_J_DATAPAGE + 1);
    idx_slot = (jpgno - 1) % (N_J_DATAPAGE + 1) - 2;
    ipgno = idx_num * (N_J_DATAPAGE + 1) + 1;
    if( ipgno>p->nJPg ){
      jpgno = 0;
      break;
    }
    pIdxPg = sqlitePgFindJidx(p, ipgno);
    assert( pIdxPg!=0 );
    aIdx = PG_TO_DATA(pIdxPg);
    if( dbpgno==sqlitePgGetInt(aIdx[idx_slot].dbpgno) ){
      break;
    }
    jpgno = sqlitePgGetInt(aIdx[idx_slot].next_jpgno);
  }
  return jpgno;
}

/*
** Make a page not dirty by writing it to the journal.
*/
static int sqlitePgMakeClean(Pghdr *pPg){
  Pgr *p = pPg->p;
  int rc;

  assert( pPg->isDirty );
  assert( p->fdJournal>=0 );
  if( pPg->jpgno==0 ){
    int jpgno;       /* A newly allocate page in the journal */
    int idx_num;     /* Which journal index describes page jpgno */
    int idx_slot;    /* Which entry in index idx_num describes jpgno */
    Pghdr *pIdxPg;   /* The index page for jpgno */
    JidxEntry *aIdx; /* The data for the index page */
    int h;           /* The hash value for pPg->dbpgno */

    jpgno = p->nJPg + 1;
    if( jpgno % (N_J_DATAPAGE + 1) == 1 ){
      jpgno++;
    }
    idx_num = (jpgno - 1)/(N_J_DATAPAGE + 1);
    idx_slot = (jpgno - 1) % (N_J_DATAPAGE + 1) - 2;
    pIdxPg = sqlitePgFindJidx(p, idx_num * (N_J_DATAPAGE + 1) + 1);
    assert( pIdxPg!=0 );
    aIdx = PG_TO_DATA(pIdxPg);
    sqlitePgPutInt(pPg->dbpgno, aIdx[idx_slot].dbpgno);
    h = pPg->dbpgno % J_HASH_SIZE;
    sqlitePgPutInt(p->aJHash[h], aIdx[idx_slot].next_jpgno);
    p->aJHash[h] = jpgno;
    p->nJPg = jpgno;
    pPg->jpgno = jpgno;
    TRACE(("PG: assign d-page %u to j-page %u\n", jpgno, pPg->dbpgno));
  }
  rc = sqlitePgWrite(p->fdJournal, PG_TO_DATA(pPg), pPg->jpgno);
  if( rc==SQLITE_OK ){
    pPg->isDirty = 0;
  }
  return rc;
}

/*
** Find the number of pages in the given file by measuring the size
** of the file.  Return 0 if there is any problem.
*/
static int sqlitePgPageCount(int fd){
  struct stat statbuf;
  if( fstat(fd, &statbuf)!=0 ) return 0;
  return statbuf.st_size/SQLITE_PAGE_SIZE;
}

/*
** This routine reads the journal and transfers pages from the
** journal to the database.
*/
static int sqlitePgJournalPlayback(Pgr *p){
  Pghdr *pPg;
  JidxEntry *aIdx;
  int nJpg;
  int jpgno = 1;
  int i;
  int dbpgno;
  int rc;
  char idx[SQLITE_PAGE_SIZE];
  char pgbuf[SQLITE_PAGE_SIZE];
  
  assert( p->fdJournal>=0 );
  nJpg = sqlitePgPageCount(p->fdJournal);
  while( jpgno<=nJpg ){
    if( !sqlitePgRead(p->fdJournal, idx, jpgno++) ) break;
    aIdx = (JidxEntry*)idx;
    for(i=0; i<N_J_DATAPAGE; i++){
      dbpgno = sqlitePgGetInt(&idx[i]);
      if( dbpgno==0 ){
        jpgno = nJpg+1;
        break;
      }
      pPg = sqlitePgFind(p, dbpgno);
      if( pPg ){
        rc = sqlitePgWrite(p->fdMain, PG_TO_DATA(pPg), dbpgno);
        TRACE(("PG: commit j-page %u to d-page %u from memory\n",jpgno,dbpgno));
      }else{
        rc = sqlitePgRead(p->fdJournal, pgbuf, jpgno);
        if( rc!=SQLITE_OK ){
          return rc;
        }
        rc = sqlitePgWrite(p->fdMain, pgbuf, dbpgno);
        TRACE(("PG: commit j-page %u to d-page %u from disk\n",jpgno,dbpgno));
      }
      jpgno++;
      if( rc!=SQLITE_OK ){
        return rc;
      }
    }
  }
  TRACE(("PG: commit complete. deleting the journal.\n"));
  fsync(p->fdMain);
  close(p->fdJournal);
  p->fdJournal = -1;
  unlink(p->zJournal);
  for(pPg=p->pAll; pPg; pPg=pPg->pNx){
    pPg->isDirty = 0;
    pPg->jpgno = 0;
  }
  while( (pPg = p->pJidx)!=0 ){
    p->pAll = pPg->pNx;
    sqliteFree(pPg);
  }
  return SQLITE_OK;
}

/*
** Remove the given page from the LRU list.
*/
static void sqlitePgUnlinkLru(Pghdr *pPg){
  Pgr *p = pPg->p;
  if( pPg->pLru ){
    pPg->pLru->pMru = pPg->pLru;
  }
  if( pPg->pMru ){
    pPg->pMru->pLru = pPg->pMru;
  }
  if( p->pLru==pPg ){
    p->pLru = pPg->pLru;
  }
  if( p->pMru==pPg ){
    p->pMru = pPg->pMru;
  }
  pPg->pLru = pPg->pMru = 0;
}

/*
** Open the database file and make *ppPgr pointer to a structure describing it.
** Return SQLITE_OK on success or an error code if there is a failure.
**
** If there was an unfinished commit, complete it before returnning.
*/
int sqlitePgOpen(const char *zFilename, Pgr **ppPgr){
  Pgr *p;
  int n;

  n = strlen(zFilename);
  p = sqliteMalloc( sizeof(*p) + n*2 + 4 );
  if( p==0 ){
    *ppPgr = 0;
    return SQLITE_NOMEM;
  }
  p->zMain = (char*)&p[1];
  strcpy(p->zMain, zFilename);
  p->zJournal = &p->zMain[n+1];
  strcpy(p->zJournal, p->zMain);
  p->zJournal[n] = '~';
  p->zJournal[n+1] = 0;
  p->fdJournal = -1;
  p->fdMain = open(p->zMain, O_CREAT|O_RDWR, 0600);
  if( p->fdMain<0 ){
    *ppPgr = 0;
    sqliteFree(p);
    return SQLITE_PERM;
  }
  p->nDbPg = sqlitePgPageCount(p->fdMain);
  if( access(p->zJournal, R_OK)==0 ){
    sqlitePgJournalPlayback(p);
  }
  *ppPgr = p;
  return SQLITE_OK;
}

/*
** Close the database file.  Any outstanding transactions are abandoned.
*/
int sqlitePgClose(Pgr *p){
  Pghdr *pPg;

  if( p->fdMain ) close(p->fdMain);
  if( p->fdJournal ) close(p->fdJournal);
  unlink(p->zJournal);
  while( (pPg = p->pAll)!=0 ){
    p->pAll = pPg->pNx;
    sqliteFree(pPg);
  }
  while( (pPg = p->pJidx)!=0 ){
    p->pAll = pPg->pNx;
    sqliteFree(pPg);
  }
  sqliteFree(p);
  return SQLITE_OK;
}

/*
** Begin a new transaction.  Return SQLITE_OK on success or an error
** code if something goes wrong.
*/
int sqlitePgBeginTransaction(Pgr *p){
  assert( p->fdJournal<0 );
  if( p->nRefPg>0 ){
     /* release the read lock */
  }
  /* write lock the database */
  p->fdJournal = open(p->zJournal, O_CREAT|O_EXCL|O_RDWR, 0600);
  if( p->fdJournal<0 ){
    return SQLITE_PERM;
  }
  p->nJPg = 0;
  TRACE(("PG: begin transaction\n"));
  return SQLITE_OK;
}

/*
** Commit the current transaction.  Return SQLITE_OK or an error code.
*/
int sqlitePgCommit(Pgr *p){
  Pghdr *pPrimaryIdx = 0;
  Pghdr *pPg;
  int rc;

  for(pPg=p->pAll; pPg; pPg=pPg->pNx){
    if( pPg->isDirty ){
      rc = sqlitePgMakeClean(pPg);
      if( rc!=SQLITE_OK ){
        return rc;
      }
    }
  }
  for(pPg=p->pJidx; pPg; pPg=pPg->pNx){
    if( pPg->jpgno==1 ){
      pPrimaryIdx = pPg;
    }else{
      TRACE(("PG: writing j-index %u\n", pPg->jpgno));
      rc = sqlitePgMakeClean(pPg);
      if( rc!=SQLITE_OK ){
        return rc;
      }
    }
  }
  assert( pPrimaryIdx!=0 );
  fsync(p->fdJournal);
  TRACE(("PG: writing j-index %u\n", pPrimaryIdx->jpgno));
  rc = sqlitePgMakeClean(pPrimaryIdx);
  if( rc!=SQLITE_OK ){
    return rc;
  }
  fsync(p->fdJournal);
  rc = sqlitePgJournalPlayback(p);
  if( rc!=SQLITE_OK ){
    return rc;
  }
  /* remove write lock from database */
  if( p->nRefPg>0 ){
    /* acquire read lock on database */
  }
  return SQLITE_OK;
}

/*
** Abandon the current transaction.
*/
int sqlitePgRollback(Pgr *p){
  Pghdr *pPg;

  TRACE(("PG: begin rollback\n"));
  for(pPg=p->pAll; pPg; pPg=pPg->pNx){
    if( pPg->isDirty || pPg->jpgno!=0 ){
      pPg->isDirty = 0;
      pPg->jpgno = 0;
      if( pPg->nRef>0 ){
        TRACE(("PG: reloading d-page %u\n", pPg->dbpgno));
        sqlitePgRead(p->fdMain, PG_TO_DATA(pPg), pPg->dbpgno);
      }else{
        sqlitePgUnlinkLru(pPg);
      }
    }
  }
  close(p->fdJournal);
  p->fdJournal = -1;
  unlink(p->zJournal);
  while( (pPg = p->pJidx)!=0 ){
    p->pAll = pPg->pNx;
    sqliteFree(pPg);
  }
  p->nDbPg = sqlitePgPageCount(p->fdMain);
  /* remove write lock from database */
  if( p->nRefPg>0 ){
    /* acquire read lock on database */
  }
  return SQLITE_OK;
}

/*
** Get a page from the database.  Return a pointer to the data for that
** page.
**
** A NULL pointer will be returned if we run out of memory.
*/
int sqlitePgGet(Pgr *p, u32 pgno, void **ppData){
  Pghdr *pPg;
  int h;

  pPg = sqlitePgFind(p, pgno);
  if( pPg ){
    pPg->nRef++;
    if( pPg->nRef==1 ){
      sqlitePgUnlinkLru(pPg);
      TRACE(("PG: d-page %u pulled from cache\n", pgno));
    }
    p->nRefPg++;
    if( p->nRefPg==1 ){
      /* Acquire a read lock */
    }
    *ppData = PG_TO_DATA(pPg);
    return SQLITE_OK;
  }
  if( p->nMemPg<MX_MEM_PAGE || p->pLru==0 ){
    pPg = sqliteMalloc( sizeof(Pghdr) + SQLITE_PAGE_SIZE );
    if( pPg==0 ) return SQLITE_NOMEM;
    p->nMemPg++;
    pPg->pNx = p->pAll;
    p->pAll = pPg;
    pPg->p = p;
    TRACE(("PG: new page %d created.\n", p->nMemPg));
  }else{
    int rc;
    pPg = p->pLru;
    if( pPg->isDirty ){
      rc = sqlitePgMakeClean(pPg);
      if( rc!=SQLITE_OK ) return rc;
    }
    sqlitePgUnlinkLru(pPg);
    h = pPg->dbpgno % PG_HASH_SIZE;
    if( pPg->pPvHash ){
      pPg->pPvHash->pNxHash = pPg->pNxHash;
    }else{
      assert( p->aPgHash[h]==pPg );
      p->aPgHash[h] = pPg->pNxHash;
    }
    if( pPg->pNxHash ){
      pPg->pNxHash->pPvHash = pPg->pPvHash;
    }
    TRACE(("PG: recycling d-page %u to d-page %u\n", pPg->dbpgno, pgno));
  }
  pPg->dbpgno = pgno;
  if( pgno>p->nDbPg ){
    p->nDbPg = pgno;
  }
  h = pgno % PG_HASH_SIZE;
  pPg->pPvHash = 0;
  pPg->pNxHash = p->aPgHash[h];
  if( pPg->pNxHash ){
    pPg->pNxHash->pPvHash = pPg;
  }
  p->aPgHash[h] = pPg;
  pPg->jpgno = sqlitePgJournalPageNumber(p, pgno);
  if( pPg->jpgno!=0 ){
    TRACE(("PG: reading d-page %u content from j-page %u\n", pgno, pPg->jpgno));
    sqlitePgRead(p->fdJournal, PG_TO_DATA(pPg), pPg->jpgno);
  }else{
    TRACE(("PG: reading d-page %u from database\n", pgno));
    sqlitePgRead(p->fdMain, PG_TO_DATA(pPg), pPg->dbpgno);
  }
  pPg->isDirty = 0;
  pPg->nRef = 1;
  p->nRefPg++;
  if( p->nRefPg==1 ){
    /* Acquire a read lock */
  }
  *ppData = PG_TO_DATA(pPg);
  return SQLITE_OK;
}

/*
** Release a reference to a database data page.
*/
int sqlitePgUnref(void *pData){
  Pghdr *pPg = DATA_TO_PG(pData);
  pPg->nRef--;
  assert( pPg->nRef>=0 );
  if( pPg->nRef==0 ){
    Pgr *p = pPg->p;
    pPg->pMru = 0;
    pPg->pLru = p->pLru;
    p->pLru = pPg;
    TRACE(("PG: d-page %u is unused\n", pPg->dbpgno));
    p->nRefPg--;
    if( p->nRefPg==0 ){
      /* Release the read lock */
    }
  }
  return SQLITE_OK;
}

/*
** The database page in the argument has been modified.  Write it back
** to the database file on the next commit.
*/
int sqlitePgTouch(void *pD){
  Pghdr *pPg = DATA_TO_PG(pD);
  assert( pPg->p->fdJournal>=0 );
  if( pPg->isDirty==0 ){
    pPg->isDirty = 1;
    TRACE(("PG: d-page %u is dirty\n", pPg->dbpgno));
  }
  return SQLITE_OK;
}

/*
** Return the number of the first unused page at the end of the
** database file.
*/
int sqlitePgAlloc(Pgr *p, int *pPgno){
  *pPgno = p->nDbPg;
  return SQLITE_OK;
}

Added src/pg.h.























































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
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
/*
** Copyright (c) 2001 D. Richard Hipp
**
** This program is free software; you can redistribute it and/or
** modify it under the terms of the GNU General Public
** License as published by the Free Software Foundation; either
** version 2 of the License, or (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
** General Public License for more details.
** 
** You should have received a copy of the GNU General Public
** License along with this library; if not, write to the
** Free Software Foundation, Inc., 59 Temple Place - Suite 330,
** Boston, MA  02111-1307, USA.
**
** Author contact information:
**   drh@hwaci.com
**   http://www.hwaci.com/drh/
**
*************************************************************************
** $Id: pg.h,v 1.1 2001/01/15 22:51:11 drh Exp $
*/

typedef struct Pgr Pgr;
#define SQLITE_PAGE_SIZE 1024

/*
** The paging system deals with 32-bit integers.
*/
typedef unsigned int u32;

int sqlitePgOpen(const char *filename, Pgr **pp);
int sqlitePgClose(Pgr*);
int sqlitePgBeginTransaction(Pgr*);
int sqlitePgCommit(Pgr*);
int sqlitePgRollback(Pgr*);
int sqlitePgGet(Pgr*, u32 pgno, void **);
int sqlitePgUnref(void*);
int sqlitePgTouch(void*);
int sqlitePgAlloc(Pgr*, int*);

Changes to src/select.c.

20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
...
485
486
487
488
489
490
491
492
493

494


495
496
497
498
499
500
501
...
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
...
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
**   drh@hwaci.com
**   http://www.hwaci.com/drh/
**
*************************************************************************
** This file contains C code routines that are called by the parser
** to handle SELECT statements.
**
** $Id: select.c,v 1.27 2000/10/16 22:06:42 drh Exp $
*/
#include "sqliteInt.h"

/*
** Allocate a new Select structure and return a pointer to that
** structure.
*/
................................................................................
        ** intermediate results.
        */
        unionTab = pParse->nTab++;
        if( p->pOrderBy 
        && matchOrderbyToColumn(pParse, p, p->pOrderBy, unionTab, 1) ){
          return 1;
        }
        sqliteVdbeAddOp(v, OP_Open, unionTab, 1, 0, 0);
        if( p->op!=TK_ALL ){

          sqliteVdbeAddOp(v, OP_KeyAsData, unionTab, 1, 0, 0);


        }
      }

      /* Code the SELECT statements to our left
      */
      rc = sqliteSelect(pParse, pPrior, priorOp, unionTab);
      if( rc ) return rc;
................................................................................
      ** by allocating the tables we will need.
      */
      tab1 = pParse->nTab++;
      tab2 = pParse->nTab++;
      if( p->pOrderBy && matchOrderbyToColumn(pParse,p,p->pOrderBy,tab1,1) ){
        return 1;
      }
      sqliteVdbeAddOp(v, OP_Open, tab1, 1, 0, 0);
      sqliteVdbeAddOp(v, OP_KeyAsData, tab1, 1, 0, 0);

      /* Code the SELECTs to our left into temporary table "tab1".
      */
      rc = sqliteSelect(pParse, pPrior, SRT_Union, tab1);
      if( rc ) return rc;

      /* Code the current SELECT into temporary table "tab2"
      */
      sqliteVdbeAddOp(v, OP_Open, tab2, 1, 0, 0);
      sqliteVdbeAddOp(v, OP_KeyAsData, tab2, 1, 0, 0);
      p->pPrior = 0;
      rc = sqliteSelect(pParse, p, SRT_Union, tab2);
      p->pPrior = pPrior;
      if( rc ) return rc;

      /* Generate code to take the intersection of the two temporary
................................................................................
    sqliteVdbeAddOp(v, OP_Null, 0, 0, 0, 0);
    sqliteVdbeAddOp(v, OP_MemStore, iParm, 0, 0, 0);
  }

  /* Begin the database scan
  */
  if( isDistinct ){
    sqliteVdbeAddOp(v, OP_Open, distinct, 1, 0, 0);
  }
  pWInfo = sqliteWhereBegin(pParse, pTabList, pWhere, 0);
  if( pWInfo==0 ) return 1;

  /* Use the standard inner loop if we are not dealing with
  ** aggregates
  */







|







 







<

>

>
>







 







|









|







 







|







20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
...
485
486
487
488
489
490
491

492
493
494
495
496
497
498
499
500
501
502
503
...
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
...
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
**   drh@hwaci.com
**   http://www.hwaci.com/drh/
**
*************************************************************************
** This file contains C code routines that are called by the parser
** to handle SELECT statements.
**
** $Id: select.c,v 1.28 2001/01/15 22:51:11 drh Exp $
*/
#include "sqliteInt.h"

/*
** Allocate a new Select structure and return a pointer to that
** structure.
*/
................................................................................
        ** intermediate results.
        */
        unionTab = pParse->nTab++;
        if( p->pOrderBy 
        && matchOrderbyToColumn(pParse, p, p->pOrderBy, unionTab, 1) ){
          return 1;
        }

        if( p->op!=TK_ALL ){
          sqliteVdbeAddOp(v, OP_OpenIdx, unionTab, 1, 0, 0);
          sqliteVdbeAddOp(v, OP_KeyAsData, unionTab, 1, 0, 0);
        }else{
          sqliteVdbeAddOp(v, OP_OpenTbl, unionTab, 1, 0, 0);
        }
      }

      /* Code the SELECT statements to our left
      */
      rc = sqliteSelect(pParse, pPrior, priorOp, unionTab);
      if( rc ) return rc;
................................................................................
      ** by allocating the tables we will need.
      */
      tab1 = pParse->nTab++;
      tab2 = pParse->nTab++;
      if( p->pOrderBy && matchOrderbyToColumn(pParse,p,p->pOrderBy,tab1,1) ){
        return 1;
      }
      sqliteVdbeAddOp(v, OP_OpenIdx, tab1, 1, 0, 0);
      sqliteVdbeAddOp(v, OP_KeyAsData, tab1, 1, 0, 0);

      /* Code the SELECTs to our left into temporary table "tab1".
      */
      rc = sqliteSelect(pParse, pPrior, SRT_Union, tab1);
      if( rc ) return rc;

      /* Code the current SELECT into temporary table "tab2"
      */
      sqliteVdbeAddOp(v, OP_OpenIdx, tab2, 1, 0, 0);
      sqliteVdbeAddOp(v, OP_KeyAsData, tab2, 1, 0, 0);
      p->pPrior = 0;
      rc = sqliteSelect(pParse, p, SRT_Union, tab2);
      p->pPrior = pPrior;
      if( rc ) return rc;

      /* Generate code to take the intersection of the two temporary
................................................................................
    sqliteVdbeAddOp(v, OP_Null, 0, 0, 0, 0);
    sqliteVdbeAddOp(v, OP_MemStore, iParm, 0, 0, 0);
  }

  /* Begin the database scan
  */
  if( isDistinct ){
    sqliteVdbeAddOp(v, OP_OpenIdx, distinct, 1, 0, 0);
  }
  pWInfo = sqliteWhereBegin(pParse, pTabList, pWhere, 0);
  if( pWInfo==0 ) return 1;

  /* Use the standard inner loop if we are not dealing with
  ** aggregates
  */

Changes to src/sqlite.h.in.

20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
...
134
135
136
137
138
139
140

141
142
143
144
145
146
147
**   drh@hwaci.com
**   http://www.hwaci.com/drh/
**
*************************************************************************
** This header file defines the interface that the sqlite library
** presents to client programs.
**
** @(#) $Id: sqlite.h.in,v 1.7 2000/11/28 20:47:20 drh Exp $
*/
#ifndef _SQLITE_H_
#define _SQLITE_H_
#include <stdarg.h>     /* Needed for the definition of va_list */

/*
** The version of the SQLite library.
................................................................................
#define SQLITE_INTERNAL  2    /* An internal logic error in SQLite */
#define SQLITE_PERM      3    /* Access permission denied */
#define SQLITE_ABORT     4    /* Callback routine requested an abort */
#define SQLITE_BUSY      5    /* One or more database files are locked */
#define SQLITE_NOMEM     6    /* A malloc() failed */
#define SQLITE_READONLY  7    /* Attempt to write a readonly database */
#define SQLITE_INTERRUPT 8    /* Operation terminated by sqlite_interrupt() */


/* This function causes any pending database operation to abort and
** return at its earliest opportunity.  This routine is typically
** called in response to a user action such as pressing "Cancel"
** or Ctrl-C where the user wants a long query operation to halt
** immediately.
*/







|







 







>







20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
...
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
**   drh@hwaci.com
**   http://www.hwaci.com/drh/
**
*************************************************************************
** This header file defines the interface that the sqlite library
** presents to client programs.
**
** @(#) $Id: sqlite.h.in,v 1.8 2001/01/15 22:51:11 drh Exp $
*/
#ifndef _SQLITE_H_
#define _SQLITE_H_
#include <stdarg.h>     /* Needed for the definition of va_list */

/*
** The version of the SQLite library.
................................................................................
#define SQLITE_INTERNAL  2    /* An internal logic error in SQLite */
#define SQLITE_PERM      3    /* Access permission denied */
#define SQLITE_ABORT     4    /* Callback routine requested an abort */
#define SQLITE_BUSY      5    /* One or more database files are locked */
#define SQLITE_NOMEM     6    /* A malloc() failed */
#define SQLITE_READONLY  7    /* Attempt to write a readonly database */
#define SQLITE_INTERRUPT 8    /* Operation terminated by sqlite_interrupt() */
#define SQLITE_IOERR     9    /* Disk full or other I/O error */

/* This function causes any pending database operation to abort and
** return at its earliest opportunity.  This routine is typically
** called in response to a user action such as pressing "Cancel"
** or Ctrl-C where the user wants a long query operation to halt
** immediately.
*/

Changes to src/sqliteInt.h.

19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
...
418
419
420
421
422
423
424
425
426


** Author contact information:
**   drh@hwaci.com
**   http://www.hwaci.com/drh/
**
*************************************************************************
** Internal interface definitions for SQLite.
**
** @(#) $Id: sqliteInt.h,v 1.34 2001/01/13 14:34:07 drh Exp $
*/
#include "sqlite.h"
#include "dbbe.h"
#include "vdbe.h"
#include "parse.h"
#include <gdbm.h>
#include <stdio.h>
................................................................................
void sqliteExprResolveInSelect(Parse*, Expr*);
int sqliteExprAnalyzeAggregates(Parse*, Expr*);
void sqliteParseInfoReset(Parse*);
Vdbe *sqliteGetVdbe(Parse*);
int sqliteRandomByte(void);
int sqliteRandomInteger(void);
void sqliteRandomName(char*,char*);
int sqliteDbbeOpenTempFile(Dbbe*, FILE**);
void sqliteDbbeCloseTempFile(Dbbe*, FILE*);









|







 







|

>
>
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
...
418
419
420
421
422
423
424
425
426
427
428
** Author contact information:
**   drh@hwaci.com
**   http://www.hwaci.com/drh/
**
*************************************************************************
** Internal interface definitions for SQLite.
**
** @(#) $Id: sqliteInt.h,v 1.35 2001/01/15 22:51:11 drh Exp $
*/
#include "sqlite.h"
#include "dbbe.h"
#include "vdbe.h"
#include "parse.h"
#include <gdbm.h>
#include <stdio.h>
................................................................................
void sqliteExprResolveInSelect(Parse*, Expr*);
int sqliteExprAnalyzeAggregates(Parse*, Expr*);
void sqliteParseInfoReset(Parse*);
Vdbe *sqliteGetVdbe(Parse*);
int sqliteRandomByte(void);
int sqliteRandomInteger(void);
void sqliteRandomName(char*,char*);
int sqliteDbbeOpenTempFile(const char*, Dbbe*, FILE**);
void sqliteDbbeCloseTempFile(Dbbe*, FILE*);
void sqliteDbbeCloseAllTempFiles(Dbbe*);
char *sqliteDbbeNameToFile(const char*,const char*,const char*);

Changes to src/update.c.

20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
...
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
**   drh@hwaci.com
**   http://www.hwaci.com/drh/
**
*************************************************************************
** This file contains C code routines that are called by the parser
** to handle UPDATE statements.
**
** $Id: update.c,v 1.8 2000/06/21 13:59:12 drh Exp $
*/
#include "sqliteInt.h"

/*
** Process an UPDATE statement.
*/
void sqliteUpdate(
................................................................................
  sqliteWhereEnd(pWInfo);

  /* Rewind the list of records that need to be updated and
  ** open every index that needs updating.
  */
  sqliteVdbeAddOp(v, OP_ListRewind, 0, 0, 0, 0);
  base = pParse->nTab;
  sqliteVdbeAddOp(v, OP_Open, base, 1, pTab->zName, 0);
  for(i=0; i<nIdx; i++){
    sqliteVdbeAddOp(v, OP_Open, base+i+1, 1, apIdx[i]->zName, 0);
  }

  /* Loop over every record that needs updating.  We have to load
  ** the old data for each record to be updated because some columns
  ** might not change and we will need to copy the old value.
  ** Also, the old data is needed to delete the old index entires.
  */







|







 







|

|







20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
...
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
**   drh@hwaci.com
**   http://www.hwaci.com/drh/
**
*************************************************************************
** This file contains C code routines that are called by the parser
** to handle UPDATE statements.
**
** $Id: update.c,v 1.9 2001/01/15 22:51:11 drh Exp $
*/
#include "sqliteInt.h"

/*
** Process an UPDATE statement.
*/
void sqliteUpdate(
................................................................................
  sqliteWhereEnd(pWInfo);

  /* Rewind the list of records that need to be updated and
  ** open every index that needs updating.
  */
  sqliteVdbeAddOp(v, OP_ListRewind, 0, 0, 0, 0);
  base = pParse->nTab;
  sqliteVdbeAddOp(v, OP_OpenTbl, base, 1, pTab->zName, 0);
  for(i=0; i<nIdx; i++){
    sqliteVdbeAddOp(v, OP_OpenIdx, base+i+1, 1, apIdx[i]->zName, 0);
  }

  /* Loop over every record that needs updating.  We have to load
  ** the old data for each record to be updated because some columns
  ** might not change and we will need to copy the old value.
  ** Also, the old data is needed to delete the old index entires.
  */

Changes to src/vdbe.c.

37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
...
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
....
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
....
1794
1795
1796
1797
1798
1799
1800







1801












1802

1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816

1817
1818
1819
1820
1821
1822
1823
** 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.50 2001/01/13 14:34:07 drh Exp $
*/
#include "sqliteInt.h"
#include <unistd.h>
#include <ctype.h>

/*
** SQL is translated into a sequence of instructions to be
................................................................................
**
** If any of the numeric OP_ values for opcodes defined in sqliteVdbe.h
** change, be sure to change this array to match.  You can use the
** "opNames.awk" awk script which is part of the source tree to regenerate
** this array, then copy and paste it into this file, if you want.
*/
static char *zOpName[] = { 0,
  "Open",           "Close",          "Fetch",          "Fcnt",
  "New",            "Put",            "Distinct",       "Found",
  "NotFound",       "Delete",         "Field",          "KeyAsData",
  "Key",            "Rewind",         "Next",           "Destroy",
  "Reorganize",     "ResetIdx",       "NextIdx",        "PutIdx",
  "DeleteIdx",      "MemLoad",        "MemStore",       "ListOpen",
  "ListWrite",      "ListRewind",     "ListRead",       "ListClose",
  "SortOpen",       "SortPut",        "SortMakeRec",    "SortMakeKey",
  "Sort",           "SortNext",       "SortKey",        "SortCallback",
  "SortClose",      "FileOpen",       "FileRead",       "FileField",
  "FileClose",      "AggReset",       "AggFocus",       "AggIncr",
  "AggNext",        "AggSet",         "AggGet",         "SetInsert",
  "SetFound",       "SetNotFound",    "SetClear",       "MakeRecord",
  "MakeKey",        "Goto",           "If",             "Halt",
  "ColumnCount",    "ColumnName",     "Callback",       "Integer",
  "String",         "Null",           "Pop",            "Dup",
  "Pull",           "Add",            "AddImm",         "Subtract",
  "Multiply",       "Divide",         "Min",            "Max",
  "Like",           "Glob",           "Eq",             "Ne",
  "Lt",             "Le",             "Gt",             "Ge",
  "IsNull",         "NotNull",        "Negative",       "And",
  "Or",             "Not",            "Concat",         "Noop",
  "Strlen",         "Substr",       
};

/*
** Given the name of an opcode, return its number.  Return 0 if
** there is no match.
**
** This routine is used for testing and debugging.
................................................................................
        p->tos++;
        aStack[p->tos].n = nByte;
        aStack[p->tos].flags = STK_Str|STK_Dyn;
        zStack[p->tos] = zNewKey;
        break;
      }

      /* Opcode: Open P1 P2 P3
      **
      ** Open a new cursor for the database file named P3.  Give the
      ** cursor an identifier P1.  The P1 values need not be
      ** contiguous but all P1 values should be small integers.  It is
      ** an error for P1 to be negative.
      **
      ** Open readonly if P2==0 and for reading and writing if P2!=0.
................................................................................
      ** If there is already another cursor opened with identifier P1,
      ** then the old cursor is closed first.  All cursors are
      ** automatically closed when the VDBE finishes execution.
      **
      ** If P3 is null or an empty string, a temporary database file
      ** is created.  This temporary database file is automatically 
      ** deleted when the cursor is closed.







      */












      case OP_Open: {

        int busy = 0;
        int i = pOp->p1;
        VERIFY( if( i<0 ) goto bad_instruction; )
        if( i>=p->nCursor ){
          int j;
          p->aCsr = sqliteRealloc( p->aCsr, (i+1)*sizeof(Cursor) );
          if( p->aCsr==0 ){ p->nCursor = 0; goto no_mem; }
          for(j=p->nCursor; j<=i; j++) p->aCsr[j].pCursor = 0;
          p->nCursor = i+1;
        }else if( p->aCsr[i].pCursor ){
          pBex->CloseCursor(p->aCsr[i].pCursor);
        }
        do {
          rc = pBex->OpenCursor(pBe,pOp->p3,pOp->p2,&p->aCsr[i].pCursor);

          switch( rc ){
            case SQLITE_BUSY: {
              if( xBusy==0 || (*xBusy)(pBusyArg, pOp->p3, ++busy)==0 ){
                sqliteSetString(pzErrMsg,"table ", pOp->p3, " is locked", 0);
                busy = 0;
              }
              break;







|







 







|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|







 







|







 







>
>
>
>
>
>
>

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













|
>







37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
...
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
....
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
....
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
** 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.51 2001/01/15 22:51:12 drh Exp $
*/
#include "sqliteInt.h"
#include <unistd.h>
#include <ctype.h>

/*
** SQL is translated into a sequence of instructions to be
................................................................................
**
** If any of the numeric OP_ values for opcodes defined in sqliteVdbe.h
** change, be sure to change this array to match.  You can use the
** "opNames.awk" awk script which is part of the source tree to regenerate
** this array, then copy and paste it into this file, if you want.
*/
static char *zOpName[] = { 0,
  "OpenIdx",        "OpenTbl",        "Close",          "Fetch",
  "Fcnt",           "New",            "Put",            "Distinct",
  "Found",          "NotFound",       "Delete",         "Field",
  "KeyAsData",      "Key",            "Rewind",         "Next",
  "Destroy",        "Reorganize",     "ResetIdx",       "NextIdx",
  "PutIdx",         "DeleteIdx",      "MemLoad",        "MemStore",
  "ListOpen",       "ListWrite",      "ListRewind",     "ListRead",
  "ListClose",      "SortOpen",       "SortPut",        "SortMakeRec",
  "SortMakeKey",    "Sort",           "SortNext",       "SortKey",
  "SortCallback",   "SortClose",      "FileOpen",       "FileRead",
  "FileField",      "FileClose",      "AggReset",       "AggFocus",
  "AggIncr",        "AggNext",        "AggSet",         "AggGet",
  "SetInsert",      "SetFound",       "SetNotFound",    "SetClear",
  "MakeRecord",     "MakeKey",        "Goto",           "If",
  "Halt",           "ColumnCount",    "ColumnName",     "Callback",
  "Integer",        "String",         "Null",           "Pop",
  "Dup",            "Pull",           "Add",            "AddImm",
  "Subtract",       "Multiply",       "Divide",         "Min",
  "Max",            "Like",           "Glob",           "Eq",
  "Ne",             "Lt",             "Le",             "Gt",
  "Ge",             "IsNull",         "NotNull",        "Negative",
  "And",            "Or",             "Not",            "Concat",
  "Noop",           "Strlen",         "Substr",       
};

/*
** Given the name of an opcode, return its number.  Return 0 if
** there is no match.
**
** This routine is used for testing and debugging.
................................................................................
        p->tos++;
        aStack[p->tos].n = nByte;
        aStack[p->tos].flags = STK_Str|STK_Dyn;
        zStack[p->tos] = zNewKey;
        break;
      }

      /* Opcode: OpenIdx P1 P2 P3
      **
      ** Open a new cursor for the database file named P3.  Give the
      ** cursor an identifier P1.  The P1 values need not be
      ** contiguous but all P1 values should be small integers.  It is
      ** an error for P1 to be negative.
      **
      ** Open readonly if P2==0 and for reading and writing if P2!=0.
................................................................................
      ** If there is already another cursor opened with identifier P1,
      ** then the old cursor is closed first.  All cursors are
      ** automatically closed when the VDBE finishes execution.
      **
      ** If P3 is null or an empty string, a temporary database file
      ** is created.  This temporary database file is automatically 
      ** deleted when the cursor is closed.
      **
      ** The database file opened must be able to map arbitrary length
      ** keys into arbitrary data.  A similar opcode, OpenTbl, opens
      ** a database file that maps integer keys into arbitrary length
      ** data.  This opcode opens database files used as
      ** SQL indices and OpenTbl opens database files used for SQL
      ** tables.
      */
      /* Opcode: OpenTbl P1 P2 P3
      **
      ** This works just like the OpenIdx operation except that the database
      ** file that is opened is one that will only accept integers as
      ** keys.  Some database backends are able to operate more efficiently
      ** if keys are always integers.  So if SQLite knows in advance that
      ** all keys will be integers, it uses this opcode rather than Open
      ** in order to give the backend an opportunity to run faster.
      **
      ** This opcode opens database files used for storing SQL tables.
      ** The OpenIdx opcode opens files used for SQL indices.
      */
      case OP_OpenIdx: 
      case OP_OpenTbl: {
        int busy = 0;
        int i = pOp->p1;
        VERIFY( if( i<0 ) goto bad_instruction; )
        if( i>=p->nCursor ){
          int j;
          p->aCsr = sqliteRealloc( p->aCsr, (i+1)*sizeof(Cursor) );
          if( p->aCsr==0 ){ p->nCursor = 0; goto no_mem; }
          for(j=p->nCursor; j<=i; j++) p->aCsr[j].pCursor = 0;
          p->nCursor = i+1;
        }else if( p->aCsr[i].pCursor ){
          pBex->CloseCursor(p->aCsr[i].pCursor);
        }
        do {
          rc = pBex->OpenCursor(pBe,pOp->p3, pOp->p2,
                                pOp->opcode==OP_OpenTbl, &p->aCsr[i].pCursor);
          switch( rc ){
            case SQLITE_BUSY: {
              if( xBusy==0 || (*xBusy)(pBusyArg, pOp->p3, ++busy)==0 ){
                sqliteSetString(pzErrMsg,"table ", pOp->p3, " is locked", 0);
                busy = 0;
              }
              break;

Changes to src/vdbe.h.

23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
..
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
120
121
122
123
124
125
126
127
128
129
130
131
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
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
*************************************************************************
** Header file for the Virtual DataBase Engine (VDBE)
**
** This header defines the interface to the virtual database engine
** or VDBE.  The VDBE implements an abstract machine that runs a
** simple program to access and modify the underlying database.
**
** $Id: vdbe.h,v 1.14 2000/10/16 22:06:43 drh Exp $
*/
#ifndef _SQLITE_VDBE_H_
#define _SQLITE_VDBE_H_
#include <stdio.h>

/*
** A single VDBE is an opaque structure named "Vdbe".  Only routines
................................................................................
** If any of the values changes or if opcodes are added or removed,
** be sure to also update the zOpName[] array in sqliteVdbe.c to
** mirror the change.
**
** The source tree contains an AWK script named renumberOps.awk that
** can be used to renumber these opcodes when new opcodes are inserted.
*/
#define OP_Open                1

#define OP_Close               2
#define OP_Fetch               3
#define OP_Fcnt                4
#define OP_New                 5
#define OP_Put                 6
#define OP_Distinct            7
#define OP_Found               8
#define OP_NotFound            9
#define OP_Delete             10
#define OP_Field              11
#define OP_KeyAsData          12
#define OP_Key                13
#define OP_Rewind             14
#define OP_Next               15

#define OP_Destroy            16
#define OP_Reorganize         17

#define OP_ResetIdx           18
#define OP_NextIdx            19
#define OP_PutIdx             20
#define OP_DeleteIdx          21

#define OP_MemLoad            22
#define OP_MemStore           23

#define OP_ListOpen           24
#define OP_ListWrite          25
#define OP_ListRewind         26
#define OP_ListRead           27
#define OP_ListClose          28

#define OP_SortOpen           29
#define OP_SortPut            30
#define OP_SortMakeRec        31
#define OP_SortMakeKey        32
#define OP_Sort               33
#define OP_SortNext           34
#define OP_SortKey            35
#define OP_SortCallback       36
#define OP_SortClose          37

#define OP_FileOpen           38
#define OP_FileRead           39
#define OP_FileField          40
#define OP_FileClose          41

#define OP_AggReset           42
#define OP_AggFocus           43
#define OP_AggIncr            44
#define OP_AggNext            45
#define OP_AggSet             46
#define OP_AggGet             47

#define OP_SetInsert          48
#define OP_SetFound           49
#define OP_SetNotFound        50
#define OP_SetClear           51

#define OP_MakeRecord         52
#define OP_MakeKey            53

#define OP_Goto               54
#define OP_If                 55
#define OP_Halt               56

#define OP_ColumnCount        57
#define OP_ColumnName         58
#define OP_Callback           59

#define OP_Integer            60
#define OP_String             61
#define OP_Null               62
#define OP_Pop                63
#define OP_Dup                64
#define OP_Pull               65

#define OP_Add                66
#define OP_AddImm             67
#define OP_Subtract           68
#define OP_Multiply           69
#define OP_Divide             70
#define OP_Min                71
#define OP_Max                72
#define OP_Like               73
#define OP_Glob               74
#define OP_Eq                 75
#define OP_Ne                 76
#define OP_Lt                 77
#define OP_Le                 78
#define OP_Gt                 79
#define OP_Ge                 80
#define OP_IsNull             81
#define OP_NotNull            82
#define OP_Negative           83
#define OP_And                84
#define OP_Or                 85
#define OP_Not                86
#define OP_Concat             87
#define OP_Noop               88

#define OP_Strlen             89
#define OP_Substr             90

#define OP_MAX                90

/*
** Prototypes for the VDBE interface.  See comments on the implementation
** for a description of what each of these routines does.
*/
Vdbe *sqliteVdbeCreate(sqlite*);
int sqliteVdbeAddOp(Vdbe*,int,int,int,const char*,int);







|







 







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

|
|

|
|
|
|

|
|

|
|
|
|
|

|
|
|
|
|
|
|
|
|

|
|
|
|

|
|
|
|
|
|

|
|
|
|

|
|

|
|
|

|
|
|

|
|
|
|
|
|

|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|

|
|

|







23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
..
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
120
121
122
123
124
125
126
127
128
129
130
131
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
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
*************************************************************************
** Header file for the Virtual DataBase Engine (VDBE)
**
** This header defines the interface to the virtual database engine
** or VDBE.  The VDBE implements an abstract machine that runs a
** simple program to access and modify the underlying database.
**
** $Id: vdbe.h,v 1.15 2001/01/15 22:51:12 drh Exp $
*/
#ifndef _SQLITE_VDBE_H_
#define _SQLITE_VDBE_H_
#include <stdio.h>

/*
** A single VDBE is an opaque structure named "Vdbe".  Only routines
................................................................................
** If any of the values changes or if opcodes are added or removed,
** be sure to also update the zOpName[] array in sqliteVdbe.c to
** mirror the change.
**
** The source tree contains an AWK script named renumberOps.awk that
** can be used to renumber these opcodes when new opcodes are inserted.
*/
#define OP_OpenIdx             1
#define OP_OpenTbl             2
#define OP_Close               3
#define OP_Fetch               4
#define OP_Fcnt                5
#define OP_New                 6
#define OP_Put                 7
#define OP_Distinct            8
#define OP_Found               9
#define OP_NotFound           10
#define OP_Delete             11
#define OP_Field              12
#define OP_KeyAsData          13
#define OP_Key                14
#define OP_Rewind             15
#define OP_Next               16

#define OP_Destroy            17
#define OP_Reorganize         18

#define OP_ResetIdx           19
#define OP_NextIdx            20
#define OP_PutIdx             21
#define OP_DeleteIdx          22

#define OP_MemLoad            23
#define OP_MemStore           24

#define OP_ListOpen           25
#define OP_ListWrite          26
#define OP_ListRewind         27
#define OP_ListRead           28
#define OP_ListClose          29

#define OP_SortOpen           30
#define OP_SortPut            31
#define OP_SortMakeRec        32
#define OP_SortMakeKey        33
#define OP_Sort               34
#define OP_SortNext           35
#define OP_SortKey            36
#define OP_SortCallback       37
#define OP_SortClose          38

#define OP_FileOpen           39
#define OP_FileRead           40
#define OP_FileField          41
#define OP_FileClose          42

#define OP_AggReset           43
#define OP_AggFocus           44
#define OP_AggIncr            45
#define OP_AggNext            46
#define OP_AggSet             47
#define OP_AggGet             48

#define OP_SetInsert          49
#define OP_SetFound           50
#define OP_SetNotFound        51
#define OP_SetClear           52

#define OP_MakeRecord         53
#define OP_MakeKey            54

#define OP_Goto               55
#define OP_If                 56
#define OP_Halt               57

#define OP_ColumnCount        58
#define OP_ColumnName         59
#define OP_Callback           60

#define OP_Integer            61
#define OP_String             62
#define OP_Null               63
#define OP_Pop                64
#define OP_Dup                65
#define OP_Pull               66

#define OP_Add                67
#define OP_AddImm             68
#define OP_Subtract           69
#define OP_Multiply           70
#define OP_Divide             71
#define OP_Min                72
#define OP_Max                73
#define OP_Like               74
#define OP_Glob               75
#define OP_Eq                 76
#define OP_Ne                 77
#define OP_Lt                 78
#define OP_Le                 79
#define OP_Gt                 80
#define OP_Ge                 81
#define OP_IsNull             82
#define OP_NotNull            83
#define OP_Negative           84
#define OP_And                85
#define OP_Or                 86
#define OP_Not                87
#define OP_Concat             88
#define OP_Noop               89

#define OP_Strlen             90
#define OP_Substr             91

#define OP_MAX                91

/*
** Prototypes for the VDBE interface.  See comments on the implementation
** for a description of what each of these routines does.
*/
Vdbe *sqliteVdbeCreate(sqlite*);
int sqliteVdbeAddOp(Vdbe*,int,int,int,const char*,int);

Changes to src/where.c.

21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
...
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
**   http://www.hwaci.com/drh/
**
*************************************************************************
** This module contains C code that generates VDBE code used to process
** the WHERE clause of SQL statements.  Also found here are subroutines
** to generate VDBE code to evaluate expressions.
**
** $Id: where.c,v 1.9 2000/08/22 18:29:34 drh Exp $
*/
#include "sqliteInt.h"

/*
** The query generator uses an array of instances of this structure to
** help it analyze the subexpressions of the WHERE clause.  Each WHERE
** clause subexpression is separated from the others by an AND operator.
................................................................................
    aIdx[i] = pBestIdx;
    loopMask |= 1<<idx;
  }

  /* Open all tables in the pTabList and all indices in aIdx[].
  */
  for(i=0; i<pTabList->nId; i++){
    sqliteVdbeAddOp(v, OP_Open, base+i, 0, pTabList->a[i].pTab->zName, 0);
    if( i<ARRAYSIZE(aIdx) && aIdx[i]!=0 ){
      sqliteVdbeAddOp(v, OP_Open, base+pTabList->nId+i, 0, aIdx[i]->zName, 0);
    }
  }
  memcpy(pWInfo->aIdx, aIdx, sizeof(aIdx));

  /* Generate the code to do the search
  */
  pWInfo->iBreak = brk = sqliteVdbeMakeLabel(v);







|







 







|

|







21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
...
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
**   http://www.hwaci.com/drh/
**
*************************************************************************
** This module contains C code that generates VDBE code used to process
** the WHERE clause of SQL statements.  Also found here are subroutines
** to generate VDBE code to evaluate expressions.
**
** $Id: where.c,v 1.10 2001/01/15 22:51:12 drh Exp $
*/
#include "sqliteInt.h"

/*
** The query generator uses an array of instances of this structure to
** help it analyze the subexpressions of the WHERE clause.  Each WHERE
** clause subexpression is separated from the others by an AND operator.
................................................................................
    aIdx[i] = pBestIdx;
    loopMask |= 1<<idx;
  }

  /* Open all tables in the pTabList and all indices in aIdx[].
  */
  for(i=0; i<pTabList->nId; i++){
    sqliteVdbeAddOp(v, OP_OpenTbl, base+i, 0, pTabList->a[i].pTab->zName, 0);
    if( i<ARRAYSIZE(aIdx) && aIdx[i]!=0 ){
      sqliteVdbeAddOp(v, OP_OpenIdx, base+pTabList->nId+i, 0, aIdx[i]->zName,0);
    }
  }
  memcpy(pWInfo->aIdx, aIdx, sizeof(aIdx));

  /* Generate the code to do the search
  */
  pWInfo->iBreak = brk = sqliteVdbeMakeLabel(v);