/ Check-in [236a54d2]
Login

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

Overview
Comment:Added support for the INTEGER PRIMARY KEY column type. (CVS 333)
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1:236a54d289e858a1e0505a20d907a2a40c01b521
User & Date: drh 2001-12-21 14:30:43
Context
2001-12-22
14:49
Bug fixing in the new integer primary key code. (CVS 334) check-in: 29cab124 user: drh tags: trunk
2001-12-21
14:30
Added support for the INTEGER PRIMARY KEY column type. (CVS 333) check-in: 236a54d2 user: drh tags: trunk
2001-12-16
20:05
Added the ability to say things like "SELECT rowid, * FROM table1;" (CVS 332) check-in: ffbdd43f user: drh tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to VERSION.

1
2.1.8
|
1
2.2.0

Changes to src/build.c.

21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
...
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
...
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
...
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
...
529
530
531
532
533
534
535


















































536
537
538
539
540
541
542
...
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
**     COPY
**     VACUUM
**     BEGIN TRANSACTION
**     COMMIT
**     ROLLBACK
**     PRAGMA
**
** $Id: build.c,v 1.59 2001/12/15 02:35:59 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>

/*
** This routine is called after a single SQL statement has been
** parsed and we want to execute the VDBE code to implement 
................................................................................
  }
  for(pElem=sqliteHashFirst(&toDelete); pElem; pElem=sqliteHashNext(pElem)){
    Table *pTable = sqliteHashData(pElem);
    sqliteUnlinkAndDeleteTable(db, pTable);
  }
  sqliteHashClear(&toDelete);
  for(pElem=sqliteHashFirst(&db->idxHash); pElem; pElem=sqliteHashNext(pElem)){
    Table *pIndex = sqliteHashData(pElem);
    if( pIndex->isDelete ){
      sqliteHashInsert(&toDelete, pIndex, 0, pIndex);
    }else{
      pIndex->isCommit = 1;
    }
  }
  for(pElem=sqliteHashFirst(&toDelete); pElem; pElem=sqliteHashNext(pElem)){
................................................................................
  }
  for(pElem=sqliteHashFirst(&toDelete); pElem; pElem=sqliteHashNext(pElem)){
    Table *pTable = sqliteHashData(pElem);
    sqliteUnlinkAndDeleteTable(db, pTable);
  }
  sqliteHashClear(&toDelete);
  for(pElem=sqliteHashFirst(&db->idxHash); pElem; pElem=sqliteHashNext(pElem)){
    Table *pIndex = sqliteHashData(pElem);
    if( !pIndex->isCommit ){
      sqliteHashInsert(&toDelete, pIndex, 0, pIndex);
    }else{
      pIndex->isDelete = 0;
    }
  }
  for(pElem=sqliteHashFirst(&toDelete); pElem; pElem=sqliteHashNext(pElem)){
................................................................................
  if( pTable==0 ){
    sqliteFree(zName);
    return;
  }
  pTable->zName = zName;
  pTable->nCol = 0;
  pTable->aCol = 0;

  pTable->pIndex = 0;
  pTable->isTemp = isTemp;
  if( pParse->pNewTable ) sqliteDeleteTable(db, pParse->pNewTable);
  pParse->pNewTable = pTable;
  if( !pParse->initFlag && (v = sqliteGetVdbe(pParse))!=0 ){
    if( (db->flags & SQLITE_InTrans)==0 ){
      sqliteVdbeAddOp(v, OP_Transaction, 0, 0);
      sqliteVdbeAddOp(v, OP_VerifyCookie, db->schema_cookie, 0);
      pParse->schemaVerified = 1;
    }
    if( !isTemp ){

      sqliteVdbeAddOp(v, OP_OpenWrite, 0, 2);
      sqliteVdbeChangeP3(v, -1, MASTER_NAME, P3_STATIC);
    }
  }
}

/*
................................................................................
  if( minusFlag ){
    sqliteSetNString(pz, "-", 1, pVal->z, pVal->n, 0);
  }else{
    sqliteSetNString(pz, pVal->z, pVal->n, 0);
  }
  sqliteDequote(*pz);
}



















































/*
** Come up with a new random value for the schema cookie.  Make sure
** the new value is different from the old.
**
** The schema cookie is used to determine when the schema for the
** database changes.  After each schema change, the cookie value
................................................................................
      " may not have new indices added", 0);
    pParse->nErr++;
    goto exit_create_index;
  }

  /* If this index is created while re-reading the schema from sqlite_master
  ** but the table associated with this index is a temporary table, it can
  ** only mean that the table this index is really associated with is one 
  ** whose name is hidden behind a temporary table with the same name.
  ** Since its table has been suppressed, we need to also suppress the
  ** index.
  */
  if( pParse->initFlag && pTab->isTemp ){
    goto exit_create_index;
  }








|







 







|







 







|







 







>











>







 







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







 







|
|







21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
...
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
...
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
...
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
...
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
...
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
**     COPY
**     VACUUM
**     BEGIN TRANSACTION
**     COMMIT
**     ROLLBACK
**     PRAGMA
**
** $Id: build.c,v 1.60 2001/12/21 14:30:43 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>

/*
** This routine is called after a single SQL statement has been
** parsed and we want to execute the VDBE code to implement 
................................................................................
  }
  for(pElem=sqliteHashFirst(&toDelete); pElem; pElem=sqliteHashNext(pElem)){
    Table *pTable = sqliteHashData(pElem);
    sqliteUnlinkAndDeleteTable(db, pTable);
  }
  sqliteHashClear(&toDelete);
  for(pElem=sqliteHashFirst(&db->idxHash); pElem; pElem=sqliteHashNext(pElem)){
    Index *pIndex = sqliteHashData(pElem);
    if( pIndex->isDelete ){
      sqliteHashInsert(&toDelete, pIndex, 0, pIndex);
    }else{
      pIndex->isCommit = 1;
    }
  }
  for(pElem=sqliteHashFirst(&toDelete); pElem; pElem=sqliteHashNext(pElem)){
................................................................................
  }
  for(pElem=sqliteHashFirst(&toDelete); pElem; pElem=sqliteHashNext(pElem)){
    Table *pTable = sqliteHashData(pElem);
    sqliteUnlinkAndDeleteTable(db, pTable);
  }
  sqliteHashClear(&toDelete);
  for(pElem=sqliteHashFirst(&db->idxHash); pElem; pElem=sqliteHashNext(pElem)){
    Index *pIndex = sqliteHashData(pElem);
    if( !pIndex->isCommit ){
      sqliteHashInsert(&toDelete, pIndex, 0, pIndex);
    }else{
      pIndex->isDelete = 0;
    }
  }
  for(pElem=sqliteHashFirst(&toDelete); pElem; pElem=sqliteHashNext(pElem)){
................................................................................
  if( pTable==0 ){
    sqliteFree(zName);
    return;
  }
  pTable->zName = zName;
  pTable->nCol = 0;
  pTable->aCol = 0;
  pTable->iPKey = -1;
  pTable->pIndex = 0;
  pTable->isTemp = isTemp;
  if( pParse->pNewTable ) sqliteDeleteTable(db, pParse->pNewTable);
  pParse->pNewTable = pTable;
  if( !pParse->initFlag && (v = sqliteGetVdbe(pParse))!=0 ){
    if( (db->flags & SQLITE_InTrans)==0 ){
      sqliteVdbeAddOp(v, OP_Transaction, 0, 0);
      sqliteVdbeAddOp(v, OP_VerifyCookie, db->schema_cookie, 0);
      pParse->schemaVerified = 1;
    }
    if( !isTemp ){
      sqliteVdbeAddOp(v, OP_SetCookie, db->file_format, 1);
      sqliteVdbeAddOp(v, OP_OpenWrite, 0, 2);
      sqliteVdbeChangeP3(v, -1, MASTER_NAME, P3_STATIC);
    }
  }
}

/*
................................................................................
  if( minusFlag ){
    sqliteSetNString(pz, "-", 1, pVal->z, pVal->n, 0);
  }else{
    sqliteSetNString(pz, pVal->z, pVal->n, 0);
  }
  sqliteDequote(*pz);
}

/*
** Designate the PRIMARY KEY for the table.  pList is a list of names 
** of columns that form the primary key.  If pList is NULL, then the
** most recently added column of the table is the primary key.
**
** A table can have at most one primary key.  If the table already has
** a primary key (and this is the second primary key) then create an
** error.
**
** If the PRIMARY KEY is on a single column whose datatype is INTEGER,
** then we will try to use that column as the row id.  (Exception:
** For backwards compatibility with older databases, do not do this
** if the file format version number is less than 1.)  Set the Table.iPKey
** field of the table under construction to be the index of the
** INTEGER PRIMARY KEY column.  Table.iPKey is set to -1 if there is
** no INTEGER PRIMARY KEY.
**
** If the key is not an INTEGER PRIMARY KEY, then create a unique
** index for the key.  No index is created for INTEGER PRIMARY KEYs.
*/
void sqliteAddPrimaryKey(Parse *pParse, IdList *pList){
  Table *pTab = pParse->pNewTable;
  char *zType = 0;
  int iCol = -1;
  if( pTab==0 ) return;
  if( pTab->hasPrimKey ){
    sqliteSetString(&pParse->zErrMsg, "table \"", pTab->zName, 
        "\" has more than one primary key", 0);
    pParse->nErr++;
    return;
  }
  pTab->hasPrimKey = 1;
  if( pList==0 ){
    iCol = pTab->nCol - 1;
  }else if( pList->nId==1 ){
    for(iCol=0; iCol<pTab->nCol; iCol++){
      if( sqliteStrICmp(pList->a[0].zName, pTab->aCol[iCol].zName)==0 ) break;
    }
  }
  if( iCol>=0 && iCol<pTab->nCol ){
    zType = pTab->aCol[iCol].zType;
  }
  if( pParse->db->file_format>=1 && 
           zType && sqliteStrICmp(zType, "INTEGER")==0 ){
    pTab->iPKey = iCol;
  }else{
    sqliteCreateIndex(pParse, 0, 0, pList, 1, 0, 0);
  }
}

/*
** Come up with a new random value for the schema cookie.  Make sure
** the new value is different from the old.
**
** The schema cookie is used to determine when the schema for the
** database changes.  After each schema change, the cookie value
................................................................................
      " may not have new indices added", 0);
    pParse->nErr++;
    goto exit_create_index;
  }

  /* If this index is created while re-reading the schema from sqlite_master
  ** but the table associated with this index is a temporary table, it can
  ** only mean that the table that this index is really associated with is
  ** one whose name is hidden behind a temporary table with the same name.
  ** Since its table has been suppressed, we need to also suppress the
  ** index.
  */
  if( pParse->initFlag && pTab->isTemp ){
    goto exit_create_index;
  }

Changes to src/delete.c.

8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
...
153
154
155
156
157
158
159




160

161
162
163
164
165
166
167
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** This file contains C code routines that are called by the parser
** to handle DELETE FROM statements.
**
** $Id: delete.c,v 1.21 2001/11/07 16:48:27 drh Exp $
*/
#include "sqliteInt.h"

/*
** Process a DELETE FROM statement.
*/
void sqliteDeleteFrom(
................................................................................
    addr = sqliteVdbeAddOp(v, OP_ListRead, 0, end);
    sqliteVdbeAddOp(v, OP_MoveTo, base, 0);
    if( pTab->pIndex ){
      for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
        int j;
        sqliteVdbeAddOp(v, OP_Recno, base, 0);
        for(j=0; j<pIdx->nColumn; j++){




          sqliteVdbeAddOp(v, OP_Column, base, pIdx->aiColumn[j]);

        }
        sqliteVdbeAddOp(v, OP_MakeIdxKey, pIdx->nColumn, 0);
        sqliteVdbeAddOp(v, OP_IdxDelete, base+i, 0);
      }
    }
    sqliteVdbeAddOp(v, OP_Delete, base, 0);
    sqliteVdbeAddOp(v, OP_Goto, 0, addr);







|







 







>
>
>
>
|
>







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
...
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** This file contains C code routines that are called by the parser
** to handle DELETE FROM statements.
**
** $Id: delete.c,v 1.22 2001/12/21 14:30:43 drh Exp $
*/
#include "sqliteInt.h"

/*
** Process a DELETE FROM statement.
*/
void sqliteDeleteFrom(
................................................................................
    addr = sqliteVdbeAddOp(v, OP_ListRead, 0, end);
    sqliteVdbeAddOp(v, OP_MoveTo, base, 0);
    if( pTab->pIndex ){
      for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
        int j;
        sqliteVdbeAddOp(v, OP_Recno, base, 0);
        for(j=0; j<pIdx->nColumn; j++){
          int idx = pIdx->aiColumn[j];
          if( idx==pTab->iPKey ){
            sqliteVdbeAddOp(v, OP_Dup, j, 0);
          }else{
            sqliteVdbeAddOp(v, OP_Column, base, idx);
          }
        }
        sqliteVdbeAddOp(v, OP_MakeIdxKey, pIdx->nColumn, 0);
        sqliteVdbeAddOp(v, OP_IdxDelete, base+i, 0);
      }
    }
    sqliteVdbeAddOp(v, OP_Delete, base, 0);
    sqliteVdbeAddOp(v, OP_Goto, 0, addr);

Changes to src/expr.c.

8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
...
123
124
125
126
127
128
129




130

131
132
133
134
135
136
137
...
186
187
188
189
190
191
192




193

194
195
196
197
198
199
200
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** This file contains routines used for analyzing expressions and
** for generating VDBE code that evaluates expressions in SQLite.
**
** $Id: expr.c,v 1.34 2001/11/24 00:31:46 drh Exp $
*/
#include "sqliteInt.h"

/*
** Walk an expression tree.  Return 1 if the expression is constant
** and 0 if it involves variables.
*/
................................................................................
        int j;
        Table *pTab = pTabList->a[i].pTab;
        if( pTab==0 ) continue;
        for(j=0; j<pTab->nCol; j++){
          if( sqliteStrICmp(pTab->aCol[j].zName, z)==0 ){
            cnt++;
            pExpr->iTable = i + pParse->nTab;




            pExpr->iColumn = j;

          }
        }
      }
      if( cnt==0 && sqliteIsRowid(z) ){
        pExpr->iColumn = -1;
        pExpr->iTable = pParse->nTab;
        cnt = 1 + (pTabList->nId>1);
................................................................................
        }
        if( sqliteStrICmp(zTab, zLeft)!=0 ) continue;
        if( 0==(cntTab++) ) pExpr->iTable = i + pParse->nTab;
        for(j=0; j<pTab->nCol; j++){
          if( sqliteStrICmp(pTab->aCol[j].zName, zRight)==0 ){
            cnt++;
            pExpr->iTable = i + pParse->nTab;




            pExpr->iColumn = j;

          }
        }
      }
      if( cnt==0 && cntTab==1 && sqliteIsRowid(zRight) ){
        cnt = 1;
        pExpr->iColumn = -1;
      }







|







 







>
>
>
>
|
>







 







>
>
>
>
|
>







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
...
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
...
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** This file contains routines used for analyzing expressions and
** for generating VDBE code that evaluates expressions in SQLite.
**
** $Id: expr.c,v 1.35 2001/12/21 14:30:43 drh Exp $
*/
#include "sqliteInt.h"

/*
** Walk an expression tree.  Return 1 if the expression is constant
** and 0 if it involves variables.
*/
................................................................................
        int j;
        Table *pTab = pTabList->a[i].pTab;
        if( pTab==0 ) continue;
        for(j=0; j<pTab->nCol; j++){
          if( sqliteStrICmp(pTab->aCol[j].zName, z)==0 ){
            cnt++;
            pExpr->iTable = i + pParse->nTab;
            if( j==pTab->iPKey ){
              /* Substitute the record number for the INTEGER PRIMARY KEY */
              pExpr->iColumn = -1;
            }else{
              pExpr->iColumn = j;
            }
          }
        }
      }
      if( cnt==0 && sqliteIsRowid(z) ){
        pExpr->iColumn = -1;
        pExpr->iTable = pParse->nTab;
        cnt = 1 + (pTabList->nId>1);
................................................................................
        }
        if( sqliteStrICmp(zTab, zLeft)!=0 ) continue;
        if( 0==(cntTab++) ) pExpr->iTable = i + pParse->nTab;
        for(j=0; j<pTab->nCol; j++){
          if( sqliteStrICmp(pTab->aCol[j].zName, zRight)==0 ){
            cnt++;
            pExpr->iTable = i + pParse->nTab;
            if( j==pTab->iPKey ){
              /* Substitute the record number for the INTEGER PRIMARY KEY */
              pExpr->iColumn = -1;
            }else{
              pExpr->iColumn = j;
            }
          }
        }
      }
      if( cnt==0 && cntTab==1 && sqliteIsRowid(zRight) ){
        cnt = 1;
        pExpr->iColumn = -1;
      }

Changes to src/insert.c.

8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
..
45
46
47
48
49
50
51

52
53
54
55
56
57
58
...
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
...
174
175
176
177
178
179
180
181



182








183





184
185
186




187








188
189
190
191
192
193
194
...
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
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** This file contains C code routines that are called by the parser
** to handle INSERT statements in SQLite.
**
** $Id: insert.c,v 1.26 2001/11/07 16:48:27 drh Exp $
*/
#include "sqliteInt.h"

/*
** This routine is call to handle SQL of the following forms:
**
**    insert into TABLE (IDLIST) values(EXPRLIST)
................................................................................
  Index *pIdx;          /* For looping over indices of the table */
  int srcTab;           /* Date comes from this temporary cursor if >=0 */
  int nColumn;          /* Number of columns in the data */
  int base;             /* First available cursor */
  int iCont, iBreak;    /* Beginning and end of the loop over srcTab */
  sqlite *db;           /* The main database structure */
  int openOp;           /* Opcode used to open cursors */


  if( pParse->nErr || sqlite_malloc_failed ) goto insert_cleanup;
  db = pParse->db;

  /* Locate the table into which we will be inserting new information.
  */
  zTab = sqliteTableNameFromToken(pTableName);
................................................................................
    for(i=0; i<pColumn->nId; i++){
      pColumn->a[i].idx = -1;
    }
    for(i=0; i<pColumn->nId; i++){
      for(j=0; j<pTab->nCol; j++){
        if( sqliteStrICmp(pColumn->a[i].zName, pTab->aCol[j].zName)==0 ){
          pColumn->a[i].idx = j;



          break;
        }
      }
      if( j>=pTab->nCol ){
        sqliteSetString(&pParse->zErrMsg, "table ", pTab->zName,
           " has no column named ", pColumn->a[i].zName, 0);
        pParse->nErr++;
        goto insert_cleanup;
      }
    }
  }








  /* Open cursors into the table that is received the new data and
  ** all indices of that table.
  */
  base = pParse->nTab;
  openOp = pTab->isTemp ? OP_OpenWrAux : OP_OpenWrite;
  sqliteVdbeAddOp(v, openOp, base, pTab->tnum);
................................................................................
      sqliteVdbeAddOp(v, OP_Integer, 0, 0);  /* Initialize the row count */
    }
    iBreak = sqliteVdbeMakeLabel(v);
    sqliteVdbeAddOp(v, OP_Rewind, srcTab, iBreak);
    iCont = sqliteVdbeCurrentAddr(v);
  }

  /* Create a new entry in the table and fill it with data.



  */








  sqliteVdbeAddOp(v, OP_NewRecno, base, 0);





  if( pTab->pIndex ){
    sqliteVdbeAddOp(v, OP_Dup, 0, 0);
  }




  for(i=0; i<pTab->nCol; i++){








    if( pColumn==0 ){
      j = i;
    }else{
      for(j=0; j<pColumn->nId; j++){
        if( pColumn->a[j].idx==i ) break;
      }
    }
................................................................................
      sqliteVdbeChangeP3(v, -1, pTab->aCol[i].zDflt, P3_STATIC);
    }else if( srcTab>=0 ){
      sqliteVdbeAddOp(v, OP_Column, srcTab, i); 
    }else{
      sqliteExprCode(pParse, pList->a[j].pExpr);
    }
  }



  sqliteVdbeAddOp(v, OP_MakeRecord, pTab->nCol, 0);
  sqliteVdbeAddOp(v, OP_Put, base, 0);
  

  /* Create appropriate entries for the new data row in all indices
  ** of the table.
  */
  for(idx=1, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, idx++){
    if( pIdx->pNext ){
      sqliteVdbeAddOp(v, OP_Dup, 0, 0);
    }
    for(i=0; i<pIdx->nColumn; i++){
      int idx = pIdx->aiColumn[i];





      if( pColumn==0 ){
        j = idx;
      }else{
        for(j=0; j<pColumn->nId; j++){
          if( pColumn->a[j].idx==idx ) break;
        }
      }







|







 







>







 







>
>
>











>
>
>
>
>
>
>







 







|
>
>
>

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



>
>
>
>

>
>
>
>
>
>
>
>







 







>
>
>

|

<









>
>
>
>
>







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
..
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
...
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
...
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
...
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
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** This file contains C code routines that are called by the parser
** to handle INSERT statements in SQLite.
**
** $Id: insert.c,v 1.27 2001/12/21 14:30:43 drh Exp $
*/
#include "sqliteInt.h"

/*
** This routine is call to handle SQL of the following forms:
**
**    insert into TABLE (IDLIST) values(EXPRLIST)
................................................................................
  Index *pIdx;          /* For looping over indices of the table */
  int srcTab;           /* Date comes from this temporary cursor if >=0 */
  int nColumn;          /* Number of columns in the data */
  int base;             /* First available cursor */
  int iCont, iBreak;    /* Beginning and end of the loop over srcTab */
  sqlite *db;           /* The main database structure */
  int openOp;           /* Opcode used to open cursors */
  int keyColumn = -1;   /* Column that is the INTEGER PRIMARY KEY */

  if( pParse->nErr || sqlite_malloc_failed ) goto insert_cleanup;
  db = pParse->db;

  /* Locate the table into which we will be inserting new information.
  */
  zTab = sqliteTableNameFromToken(pTableName);
................................................................................
    for(i=0; i<pColumn->nId; i++){
      pColumn->a[i].idx = -1;
    }
    for(i=0; i<pColumn->nId; i++){
      for(j=0; j<pTab->nCol; j++){
        if( sqliteStrICmp(pColumn->a[i].zName, pTab->aCol[j].zName)==0 ){
          pColumn->a[i].idx = j;
          if( j==pTab->iPKey ){
            keyColumn = j;
          }
          break;
        }
      }
      if( j>=pTab->nCol ){
        sqliteSetString(&pParse->zErrMsg, "table ", pTab->zName,
           " has no column named ", pColumn->a[i].zName, 0);
        pParse->nErr++;
        goto insert_cleanup;
      }
    }
  }

  /* If there is not IDLIST term but the table has an integer primary
  ** key, the set the keyColumn variable to the primary key column.
  */
  if( pColumn==0 ){
    keyColumn = pTab->iPKey;
  }

  /* Open cursors into the table that is received the new data and
  ** all indices of that table.
  */
  base = pParse->nTab;
  openOp = pTab->isTemp ? OP_OpenWrAux : OP_OpenWrite;
  sqliteVdbeAddOp(v, openOp, base, pTab->tnum);
................................................................................
      sqliteVdbeAddOp(v, OP_Integer, 0, 0);  /* Initialize the row count */
    }
    iBreak = sqliteVdbeMakeLabel(v);
    sqliteVdbeAddOp(v, OP_Rewind, srcTab, iBreak);
    iCont = sqliteVdbeCurrentAddr(v);
  }

  /* Push the record number for the new entry onto the stack.  The
  ** record number is a randomly generate integer created by NewRecno
  ** except when the table has an INTEGER PRIMARY KEY column, in which
  ** case the record number is the same as that column.
  */
  if( keyColumn>=0 ){
    if( srcTab>=0 ){
      sqliteVdbeAddOp(v, OP_Column, srcTab, keyColumn);
    }else{
      sqliteExprCode(pParse, pList->a[keyColumn].pExpr);
    }
    sqliteVdbeAddOp(v, OP_AddImm, 0, 0);  /* Make sure ROWID is an integer */
  }else{
    sqliteVdbeAddOp(v, OP_NewRecno, base, 0);
  }

  /* If there are indices, we'll need this record number again, so make
  ** a copy.
  */
  if( pTab->pIndex ){
    sqliteVdbeAddOp(v, OP_Dup, 0, 0);
  }

  /* Push onto the stack data for all columns of the new entry, beginning
  ** with the first column.
  */
  for(i=0; i<pTab->nCol; i++){
    if( i==pTab->iPKey ){
      /* The value of the INTEGER PRIMARY KEY column is always a NULL.
      ** Whenever this column is used, the record number will be substituted
      ** in its place, so there is no point it it taking up space in
      ** the data record. */
      sqliteVdbeAddOp(v, OP_String, 0, 0);
      continue;
    }
    if( pColumn==0 ){
      j = i;
    }else{
      for(j=0; j<pColumn->nId; j++){
        if( pColumn->a[j].idx==i ) break;
      }
    }
................................................................................
      sqliteVdbeChangeP3(v, -1, pTab->aCol[i].zDflt, P3_STATIC);
    }else if( srcTab>=0 ){
      sqliteVdbeAddOp(v, OP_Column, srcTab, i); 
    }else{
      sqliteExprCode(pParse, pList->a[j].pExpr);
    }
  }

  /* Create the new record and put it into the database.
  */
  sqliteVdbeAddOp(v, OP_MakeRecord, pTab->nCol, 0);
  sqliteVdbeAddOp(v, OP_Put, base, keyColumn>=0);
  

  /* Create appropriate entries for the new data row in all indices
  ** of the table.
  */
  for(idx=1, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, idx++){
    if( pIdx->pNext ){
      sqliteVdbeAddOp(v, OP_Dup, 0, 0);
    }
    for(i=0; i<pIdx->nColumn; i++){
      int idx = pIdx->aiColumn[i];
      if( idx==pTab->iPKey ){
        /* Copy the record number in place of the INTEGER PRIMARY KEY column */
        sqliteVdbeAddOp(v, OP_Dup, i, 0);
        continue;
      }
      if( pColumn==0 ){
        j = idx;
      }else{
        for(j=0; j<pColumn->nId; j++){
          if( pColumn->a[j].idx==idx ) break;
        }
      }

Changes to src/main.c.

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
..
38
39
40
41
42
43
44
45
46
47
48



49
50
51
52
53
54
55
56
57
58
...
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
...
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
**
*************************************************************************
** 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.51 2001/12/05 00:21:20 drh Exp $
*/
#include "sqliteInt.h"
#include "os.h"

/*
** This is the callback routine for the code that initializes the
** database.  See sqliteInit() below for additional information.
**
** Each callback contains the following information:
**
**     argv[0] = "meta" or "table" or "index"
**     argv[1] = table or index name or meta statement type.
**     argv[2] = root page number for table or index.  NULL for meta.
**     argv[3] = SQL create statement for the table or index
**
*/
static int sqliteOpenCb(void *pDb, int argc, char **argv, char **azColName){
  sqlite *db = (sqlite*)pDb;
................................................................................

  /* TODO: Do some validity checks on all fields.  In particular,
  ** make sure fields do not contain NULLs. Otherwise we might core
  ** when attempting to initialize from a corrupt database file. */

  assert( argc==4 );
  switch( argv[0][0] ){
    case 'm': {  /* Meta information */
      if( strcmp(argv[1],"file-format")==0 ){
        db->file_format = atoi(argv[3]);
      }else if( strcmp(argv[1],"schema-cookie")==0 ){



        db->schema_cookie = atoi(argv[3]);
        db->next_cookie = db->schema_cookie;
      }
      break;
    }
    case 'i':
    case 't': {  /* CREATE TABLE  and CREATE INDEX statements */
      if( argv[3] && argv[3][0] ){
        /* Call the parser to process a CREATE TABLE or CREATE INDEX statement.
        ** But because sParse.initFlag is set to 1, no VDBE code is generated
................................................................................
  ** 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, 2,  0},
    { OP_Rewind,   0, 31, 0},
    { OP_Column,   0, 0,  0},           /* 2 */
    { OP_String,   0, 0,  "meta"},
    { OP_Ne,       0, 10, 0},
    { OP_Column,   0, 0,  0},
    { OP_Column,   0, 1,  0},
    { OP_Column,   0, 3,  0},
    { OP_Column,   0, 4,  0},

    { OP_Callback, 4, 0,  0},
    { OP_Next,     0, 2,  0},           /* 10 */
    { OP_Rewind,   0, 31, 0},           /* 11 */
    { OP_Column,   0, 0,  0},           /* 12 */
    { OP_String,   0, 0,  "table"},
    { OP_Ne,       0, 20, 0},
    { OP_Column,   0, 0,  0},
    { OP_Column,   0, 1,  0},
    { OP_Column,   0, 3,  0},
    { OP_Column,   0, 4,  0},
    { OP_Callback, 4, 0,  0},
    { OP_Next,     0, 12, 0},           /* 20 */
    { OP_Rewind,   0, 31, 0},           /* 21 */
    { OP_Column,   0, 0,  0},           /* 22 */
    { OP_String,   0, 0,  "index"},
    { OP_Ne,       0, 30, 0},
    { OP_Column,   0, 0,  0},
    { OP_Column,   0, 1,  0},
    { OP_Column,   0, 3,  0},
    { OP_Column,   0, 4,  0},
    { OP_Callback, 4, 0,  0},
    { OP_Next,     0, 22, 0},           /* 30 */
    { OP_String,   0, 0,  "meta"},      /* 31 */
    { OP_String,   0, 0,  "schema-cookie"},
    { OP_String,   0, 0,  0},
    { OP_ReadCookie,0,0,  0},
    { OP_Callback, 4, 0,  0},
    { OP_Close,    0, 0,  0},
    { OP_Halt,     0, 0,  0},
  };

  /* Create a virtual machine to run the initialization program.  Run
  ** the program.  Then delete the virtual machine.
  */
  vdbe = sqliteVdbeCreate(db);
  if( vdbe==0 ){
................................................................................
    sqliteSetString(pzErrMsg, "out of memory", 0);
    return SQLITE_NOMEM;
  }
  sqliteVdbeAddOpList(vdbe, sizeof(initProg)/sizeof(initProg[0]), initProg);
  rc = sqliteVdbeExec(vdbe, sqliteOpenCb, db, pzErrMsg, 
                      db->pBusyArg, db->xBusyCallback);
  sqliteVdbeDelete(vdbe);



  if( rc==SQLITE_OK && db->file_format>1 && db->nTable>0 ){
    sqliteSetString(pzErrMsg, "unsupported file format", 0);
    rc = SQLITE_ERROR;
  }
  if( rc==SQLITE_OK ){
    Table *pTab;
    char *azArg[6];
    azArg[0] = "table";
................................................................................
      }
    }
    sqliteFree(db);
    sqliteStrRealloc(pzErrMsg);
    return 0;
  }

  /* Assume file format 1 unless the database says otherwise */
  db->file_format = 1;

  /* Attempt to read the schema */
  rc = sqliteInit(db, pzErrMsg);
  if( sqlite_malloc_failed ){
    sqlite_close(db);
    goto no_mem_on_open;
  }else if( rc!=SQLITE_OK && rc!=SQLITE_BUSY ){
    sqlite_close(db);







|










|







 







|
<
|
<
>
>
>
|
|
<







 







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







 







>
>
>
|







 







<
<
<







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
..
38
39
40
41
42
43
44
45

46

47
48
49
50
51

52
53
54
55
56
57
58
...
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
...
276
277
278
279
280
281
282



283
284
285
286
287
288
289
**
*************************************************************************
** 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.52 2001/12/21 14:30:43 drh Exp $
*/
#include "sqliteInt.h"
#include "os.h"

/*
** This is the callback routine for the code that initializes the
** database.  See sqliteInit() below for additional information.
**
** Each callback contains the following information:
**
**     argv[0] = "file-format" or "schema-cookie" or "table" or "index"
**     argv[1] = table or index name or meta statement type.
**     argv[2] = root page number for table or index.  NULL for meta.
**     argv[3] = SQL create statement for the table or index
**
*/
static int sqliteOpenCb(void *pDb, int argc, char **argv, char **azColName){
  sqlite *db = (sqlite*)pDb;
................................................................................

  /* TODO: Do some validity checks on all fields.  In particular,
  ** make sure fields do not contain NULLs. Otherwise we might core
  ** when attempting to initialize from a corrupt database file. */

  assert( argc==4 );
  switch( argv[0][0] ){
    case 'f': {  /* File format */

      db->file_format = atoi(argv[3]);

      break;
    }
    case 's': { /* Schema cookie */
      db->schema_cookie = atoi(argv[3]);
      db->next_cookie = db->schema_cookie;

      break;
    }
    case 'i':
    case 't': {  /* CREATE TABLE  and CREATE INDEX statements */
      if( argv[3] && argv[3][0] ){
        /* Call the parser to process a CREATE TABLE or CREATE INDEX statement.
        ** But because sParse.initFlag is set to 1, no VDBE code is generated
................................................................................
  ** 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, 2,  0},
    { OP_String,     0, 0,  "file-format"},
    { OP_String,     0, 0,  0},
    { OP_String,     0, 0,  0},
    { OP_ReadCookie, 0, 1,  0},
    { OP_Callback,   4, 0,  0},
    { OP_String,     0, 0,  "schema_cookie"},
    { OP_String,     0, 0,  0},
    { OP_String,     0, 0,  0},
    { OP_ReadCookie, 0, 0,  0},
    { OP_Callback,   4, 0,  0},

    { OP_Rewind,     0, 31, 0},
    { OP_Column,     0, 0,  0},           /* 12 */
    { OP_String,     0, 0,  "table"},
    { OP_Ne,         0, 20, 0},
    { OP_Column,     0, 0,  0},
    { OP_Column,     0, 1,  0},
    { OP_Column,     0, 3,  0},
    { OP_Column,     0, 4,  0},
    { OP_Callback,   4, 0,  0},
    { OP_Next,       0, 12, 0},           /* 20 */
    { OP_Rewind,     0, 31, 0},           /* 21 */
    { OP_Column,     0, 0,  0},           /* 22 */
    { OP_String,     0, 0,  "index"},
    { OP_Ne,         0, 30, 0},
    { OP_Column,     0, 0,  0},
    { OP_Column,     0, 1,  0},
    { OP_Column,     0, 3,  0},
    { OP_Column,     0, 4,  0},
    { OP_Callback,   4, 0,  0},
    { OP_Next,       0, 22, 0},           /* 30 */





    { OP_Close,      0, 0,  0},           /* 31 */
    { OP_Halt,       0, 0,  0},
  };

  /* Create a virtual machine to run the initialization program.  Run
  ** the program.  Then delete the virtual machine.
  */
  vdbe = sqliteVdbeCreate(db);
  if( vdbe==0 ){
................................................................................
    sqliteSetString(pzErrMsg, "out of memory", 0);
    return SQLITE_NOMEM;
  }
  sqliteVdbeAddOpList(vdbe, sizeof(initProg)/sizeof(initProg[0]), initProg);
  rc = sqliteVdbeExec(vdbe, sqliteOpenCb, db, pzErrMsg, 
                      db->pBusyArg, db->xBusyCallback);
  sqliteVdbeDelete(vdbe);
  if( rc==SQLITE_OK && db->nTable==0 ){
    db->file_format = FILE_FORMAT;
  }
  if( rc==SQLITE_OK && db->file_format>FILE_FORMAT ){
    sqliteSetString(pzErrMsg, "unsupported file format", 0);
    rc = SQLITE_ERROR;
  }
  if( rc==SQLITE_OK ){
    Table *pTab;
    char *azArg[6];
    azArg[0] = "table";
................................................................................
      }
    }
    sqliteFree(db);
    sqliteStrRealloc(pzErrMsg);
    return 0;
  }




  /* Attempt to read the schema */
  rc = sqliteInit(db, pzErrMsg);
  if( sqlite_malloc_failed ){
    sqlite_close(db);
    goto no_mem_on_open;
  }else if( rc!=SQLITE_OK && rc!=SQLITE_BUSY ){
    sqlite_close(db);

Changes to src/parse.y.

10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
...
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
**
*************************************************************************
** This file contains SQLite's grammar for SQL.  Process this file
** using the lemon parser generator to generate C code that runs
** the parser.  Lemon will also generate a header file containing
** numeric codes for all of the tokens.
**
** @(#) $Id: parse.y,v 1.39 2001/12/16 20:05:06 drh Exp $
*/
%token_prefix TK_
%token_type {Token}
%default_type {Token}
%extra_argument {Parse *pParse}
%syntax_error {
  sqliteSetString(&pParse->zErrMsg,"syntax error",0);
................................................................................
carg ::= DEFAULT MINUS FLOAT(X).     {sqliteAddDefaultValue(pParse,&X,1);}
carg ::= DEFAULT NULL. 

// In addition to the type name, we also care about the primary key and
// UNIQUE constraints.
//
ccons ::= NOT NULL.                  {sqliteAddNotNull(pParse);}
ccons ::= PRIMARY KEY sortorder.     {sqliteCreateIndex(pParse,0,0,0,1,0,0);}
ccons ::= UNIQUE.                    {sqliteCreateIndex(pParse,0,0,0,1,0,0);}
ccons ::= CHECK LP expr RP.

// For the time being, the only constraint we care about is the primary
// key and UNIQUE.  Both create indices.
//
conslist_opt ::= .
conslist_opt ::= COMMA conslist.
conslist ::= conslist COMMA tcons.
conslist ::= conslist tcons.
conslist ::= tcons.
tcons ::= CONSTRAINT ids.
tcons ::= PRIMARY KEY LP idxlist(X) RP. {sqliteCreateIndex(pParse,0,0,X,1,0,0);}
tcons ::= UNIQUE LP idxlist(X) RP.      {sqliteCreateIndex(pParse,0,0,X,1,0,0);}
tcons ::= CHECK expr.

////////////////////////// The DROP TABLE /////////////////////////////////////
//
cmd ::= DROP TABLE ids(X).          {sqliteDropTable(pParse,&X);}








|







 







|












|







10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
...
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
**
*************************************************************************
** This file contains SQLite's grammar for SQL.  Process this file
** using the lemon parser generator to generate C code that runs
** the parser.  Lemon will also generate a header file containing
** numeric codes for all of the tokens.
**
** @(#) $Id: parse.y,v 1.40 2001/12/21 14:30:43 drh Exp $
*/
%token_prefix TK_
%token_type {Token}
%default_type {Token}
%extra_argument {Parse *pParse}
%syntax_error {
  sqliteSetString(&pParse->zErrMsg,"syntax error",0);
................................................................................
carg ::= DEFAULT MINUS FLOAT(X).     {sqliteAddDefaultValue(pParse,&X,1);}
carg ::= DEFAULT NULL. 

// In addition to the type name, we also care about the primary key and
// UNIQUE constraints.
//
ccons ::= NOT NULL.                  {sqliteAddNotNull(pParse);}
ccons ::= PRIMARY KEY sortorder.     {sqliteAddPrimaryKey(pParse, 0);}
ccons ::= UNIQUE.                    {sqliteCreateIndex(pParse,0,0,0,1,0,0);}
ccons ::= CHECK LP expr RP.

// For the time being, the only constraint we care about is the primary
// key and UNIQUE.  Both create indices.
//
conslist_opt ::= .
conslist_opt ::= COMMA conslist.
conslist ::= conslist COMMA tcons.
conslist ::= conslist tcons.
conslist ::= tcons.
tcons ::= CONSTRAINT ids.
tcons ::= PRIMARY KEY LP idxlist(X) RP. {sqliteAddPrimaryKey(pParse,X);}
tcons ::= UNIQUE LP idxlist(X) RP.      {sqliteCreateIndex(pParse,0,0,X,1,0,0);}
tcons ::= CHECK expr.

////////////////////////// The DROP TABLE /////////////////////////////////////
//
cmd ::= DROP TABLE ids(X).          {sqliteDropTable(pParse,&X);}

Changes to src/sqliteInt.h.

7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
..
26
27
28
29
30
31
32





33
34
35
36
37
38
39
...
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
**    May you do good and not evil.
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** Internal interface definitions for SQLite.
**
** @(#) $Id: sqliteInt.h,v 1.72 2001/12/05 00:21:20 drh Exp $
*/
#include "sqlite.h"
#include "hash.h"
#include "vdbe.h"
#include "parse.h"
#include "btree.h"
#include <stdio.h>
................................................................................
/*
** The maximum number of in-memory pages to use for the main database
** table and for temporary tables.
*/
#define MAX_PAGES   100
#define TEMP_PAGES   25






/*
** Integers of known sizes.  These typedefs might change for architectures
** where the sizes very.  Preprocessor macros are available so that the
** types can be conveniently redefined at compile-type.  Like this:
**
**         cc '-DUINTPTR_TYPE=long long int' ...
*/
................................................................................
** information about each column of an SQL table is held in an instance
** of this structure.
*/
struct Column {
  char *zName;     /* Name of this column */
  char *zDflt;     /* Default value of this column */
  char *zType;     /* Data type for this column */
  int notNull;     /* True if there is a NOT NULL constraint */

};

/*
** Each SQL table is represented in memory by
** an instance of the following structure.
*/
struct Table {
  char *zName;     /* Name of the table */
  int nCol;        /* Number of columns in this table */
  Column *aCol;    /* Information about each column */

  Index *pIndex;   /* List of SQL indexes on this table. */
  int tnum;        /* Page containing root for this table */
  u8 readOnly;     /* True if this table should not be written by the user */
  u8 isCommit;     /* True if creation of this table has been committed */
  u8 isDelete;     /* True if this table is being deleted */
  u8 isTemp;       /* True if stored in db->pBeTemp instead of db->pBe */

};

/*
** Each SQL index is represented in memory by an
** instance of the following structure.
**
** The columns of the table that are to be indexed are described







|







 







>
>
>
>
>







 







|
>










>






>







7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
..
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
...
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
**    May you do good and not evil.
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** Internal interface definitions for SQLite.
**
** @(#) $Id: sqliteInt.h,v 1.73 2001/12/21 14:30:43 drh Exp $
*/
#include "sqlite.h"
#include "hash.h"
#include "vdbe.h"
#include "parse.h"
#include "btree.h"
#include <stdio.h>
................................................................................
/*
** The maximum number of in-memory pages to use for the main database
** table and for temporary tables.
*/
#define MAX_PAGES   100
#define TEMP_PAGES   25

/*
** File format version number
*/
#define FILE_FORMAT 1

/*
** Integers of known sizes.  These typedefs might change for architectures
** where the sizes very.  Preprocessor macros are available so that the
** types can be conveniently redefined at compile-type.  Like this:
**
**         cc '-DUINTPTR_TYPE=long long int' ...
*/
................................................................................
** information about each column of an SQL table is held in an instance
** of this structure.
*/
struct Column {
  char *zName;     /* Name of this column */
  char *zDflt;     /* Default value of this column */
  char *zType;     /* Data type for this column */
  u8 notNull;      /* True if there is a NOT NULL constraint */
  u8 isPrimKey;    /* True if this column is an INTEGER PRIMARY KEY */
};

/*
** Each SQL table is represented in memory by
** an instance of the following structure.
*/
struct Table {
  char *zName;     /* Name of the table */
  int nCol;        /* Number of columns in this table */
  Column *aCol;    /* Information about each column */
  int iPKey;       /* Use this column as the record-number for each row */
  Index *pIndex;   /* List of SQL indexes on this table. */
  int tnum;        /* Page containing root for this table */
  u8 readOnly;     /* True if this table should not be written by the user */
  u8 isCommit;     /* True if creation of this table has been committed */
  u8 isDelete;     /* True if this table is being deleted */
  u8 isTemp;       /* True if stored in db->pBeTemp instead of db->pBe */
  u8 hasPrimKey;   /* True if there exists a primary key */
};

/*
** Each SQL index is represented in memory by an
** instance of the following structure.
**
** The columns of the table that are to be indexed are described

Changes to src/update.c.

8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
..
36
37
38
39
40
41
42


43
44
45
46
47
48
49
..
85
86
87
88
89
90
91

92
93
94
95
96
97
98
99
100




101
102
103
104
105
106
107
...
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
...
171
172
173
174
175
176
177

178
179
180
181
182
183
184
...
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
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** This file contains C code routines that are called by the parser
** to handle UPDATE statements.
**
** $Id: update.c,v 1.22 2001/11/21 02:21:12 drh Exp $
*/
#include "sqliteInt.h"

/*
** Process an UPDATE statement.
*/
void sqliteUpdate(
................................................................................
  int base;              /* Index of first available table cursor */
  sqlite *db;            /* The database structure */
  Index **apIdx = 0;     /* An array of indices that need updating too */
  int *aXRef = 0;        /* aXRef[i] is the index in pChanges->a[] of the
                         ** an expression for the i-th column of the table.
                         ** aXRef[i]==-1 if the i-th column is not changed. */
  int openOp;            /* Opcode used to open tables */



  if( pParse->nErr || sqlite_malloc_failed ) goto update_cleanup;
  db = pParse->db;

  /* Locate the table which we want to update.  This table has to be
  ** put in an IdList structure because some of the subroutines we
  ** will be calling are designed to work with multiple tables and expect
................................................................................
    if( sqliteExprResolveIds(pParse, pTabList, pWhere) ){
      goto update_cleanup;
    }
    if( sqliteExprCheck(pParse, pWhere, 0, 0) ){
      goto update_cleanup;
    }
  }

  for(i=0; i<pChanges->nExpr; i++){
    if( sqliteExprResolveIds(pParse, pTabList, pChanges->a[i].pExpr) ){
      goto update_cleanup;
    }
    if( sqliteExprCheck(pParse, pChanges->a[i].pExpr, 0, 0) ){
      goto update_cleanup;
    }
    for(j=0; j<pTab->nCol; j++){
      if( sqliteStrICmp(pTab->aCol[j].zName, pChanges->a[i].zName)==0 ){




        aXRef[j] = i;
        break;
      }
    }
    if( j>=pTab->nCol ){
      sqliteSetString(&pParse->zErrMsg, "no such column: ", 
         pChanges->a[i].zName, 0);
................................................................................
  }

  /* Allocate memory for the array apIdx[] and fill it with pointers to every
  ** index that needs to be updated.  Indices only need updating if their
  ** key includes one of the columns named in pChanges.
  */
  for(nIdx=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){



    for(i=0; i<pIdx->nColumn; i++){
      if( aXRef[pIdx->aiColumn[i]]>=0 ) break;

    }
    if( i<pIdx->nColumn ) nIdx++;
  }
  if( nIdx>0 ){
    apIdx = sqliteMalloc( sizeof(Index*) * nIdx );
    if( apIdx==0 ) goto update_cleanup;
  }
  for(nIdx=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){



    for(i=0; i<pIdx->nColumn; i++){
      if( aXRef[pIdx->aiColumn[i]]>=0 ) break;

    }
    if( i<pIdx->nColumn ) apIdx[nIdx++] = pIdx;
  }

  /* Begin generating code.
  */
  v = sqliteGetVdbe(pParse);
................................................................................
    sqliteVdbeAddOp(v, openOp, base+i+1, apIdx[i]->tnum);
  }

  /* 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.

  */
  end = sqliteVdbeMakeLabel(v);
  addr = sqliteVdbeAddOp(v, OP_ListRead, 0, end);
  sqliteVdbeAddOp(v, OP_Dup, 0, 0);
  sqliteVdbeAddOp(v, OP_MoveTo, base, 0);

  /* Delete the old indices for the current record.
................................................................................
    pIdx = apIdx[i];
    for(j=0; j<pIdx->nColumn; j++){
      sqliteVdbeAddOp(v, OP_Column, base, pIdx->aiColumn[j]);
    }
    sqliteVdbeAddOp(v, OP_MakeIdxKey, pIdx->nColumn, 0);
    sqliteVdbeAddOp(v, OP_IdxDelete, base+i+1, 0);
  }










  /* Compute new data for this record.  
  */
  for(i=0; i<pTab->nCol; i++){




    j = aXRef[i];
    if( j<0 ){
      sqliteVdbeAddOp(v, OP_Column, base, i);
    }else{
      sqliteExprCode(pParse, pChanges->a[j].pExpr);
    }
  }







  /* Insert new index entries that correspond to the new data
  */
  for(i=0; i<nIdx; i++){
    sqliteVdbeAddOp(v, OP_Dup, pTab->nCol, 0); /* The KEY */
    pIdx = apIdx[i];
    for(j=0; j<pIdx->nColumn; j++){




      sqliteVdbeAddOp(v, OP_Dup, j+pTab->nCol-pIdx->aiColumn[j], 0);

    }
    sqliteVdbeAddOp(v, OP_MakeIdxKey, pIdx->nColumn, 0);
    sqliteVdbeAddOp(v, OP_IdxPut, base+i+1, pIdx->isUnique);
  }

  /* Write the new data back into the database.
  */







|







 







>
>







 







>









>
>
>
>







 







>
>
>
|
|
>








>
>
>
|
|
>







 







>







 







>
>
>
>
>
>
>
>
>




>
>
>
>







>
>
>
>
>
>







>
>
>
>
|
>







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
..
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
..
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
...
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
...
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
...
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
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** This file contains C code routines that are called by the parser
** to handle UPDATE statements.
**
** $Id: update.c,v 1.23 2001/12/21 14:30:43 drh Exp $
*/
#include "sqliteInt.h"

/*
** Process an UPDATE statement.
*/
void sqliteUpdate(
................................................................................
  int base;              /* Index of first available table cursor */
  sqlite *db;            /* The database structure */
  Index **apIdx = 0;     /* An array of indices that need updating too */
  int *aXRef = 0;        /* aXRef[i] is the index in pChanges->a[] of the
                         ** an expression for the i-th column of the table.
                         ** aXRef[i]==-1 if the i-th column is not changed. */
  int openOp;            /* Opcode used to open tables */
  int chngRecno;         /* True if the record number is being changed */
  Expr *pRecnoExpr;      /* Expression defining the new record number */

  if( pParse->nErr || sqlite_malloc_failed ) goto update_cleanup;
  db = pParse->db;

  /* Locate the table which we want to update.  This table has to be
  ** put in an IdList structure because some of the subroutines we
  ** will be calling are designed to work with multiple tables and expect
................................................................................
    if( sqliteExprResolveIds(pParse, pTabList, pWhere) ){
      goto update_cleanup;
    }
    if( sqliteExprCheck(pParse, pWhere, 0, 0) ){
      goto update_cleanup;
    }
  }
  chngRecno = 0;
  for(i=0; i<pChanges->nExpr; i++){
    if( sqliteExprResolveIds(pParse, pTabList, pChanges->a[i].pExpr) ){
      goto update_cleanup;
    }
    if( sqliteExprCheck(pParse, pChanges->a[i].pExpr, 0, 0) ){
      goto update_cleanup;
    }
    for(j=0; j<pTab->nCol; j++){
      if( sqliteStrICmp(pTab->aCol[j].zName, pChanges->a[i].zName)==0 ){
        if( i==pTab->iPKey ){
          chngRecno = 1;
          pRecnoExpr = pChanges->a[i].pExpr;
        }
        aXRef[j] = i;
        break;
      }
    }
    if( j>=pTab->nCol ){
      sqliteSetString(&pParse->zErrMsg, "no such column: ", 
         pChanges->a[i].zName, 0);
................................................................................
  }

  /* Allocate memory for the array apIdx[] and fill it with pointers to every
  ** index that needs to be updated.  Indices only need updating if their
  ** key includes one of the columns named in pChanges.
  */
  for(nIdx=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
    if( chngRecno ){
      i = 0;
    }else {
      for(i=0; i<pIdx->nColumn; i++){
        if( aXRef[pIdx->aiColumn[i]]>=0 ) break;
      }
    }
    if( i<pIdx->nColumn ) nIdx++;
  }
  if( nIdx>0 ){
    apIdx = sqliteMalloc( sizeof(Index*) * nIdx );
    if( apIdx==0 ) goto update_cleanup;
  }
  for(nIdx=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
    if( chngRecno ){
      i = 0;
    }else{
      for(i=0; i<pIdx->nColumn; i++){
        if( aXRef[pIdx->aiColumn[i]]>=0 ) break;
      }
    }
    if( i<pIdx->nColumn ) apIdx[nIdx++] = pIdx;
  }

  /* Begin generating code.
  */
  v = sqliteGetVdbe(pParse);
................................................................................
    sqliteVdbeAddOp(v, openOp, base+i+1, apIdx[i]->tnum);
  }

  /* 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.
  ** So make the cursor point at the old record.
  */
  end = sqliteVdbeMakeLabel(v);
  addr = sqliteVdbeAddOp(v, OP_ListRead, 0, end);
  sqliteVdbeAddOp(v, OP_Dup, 0, 0);
  sqliteVdbeAddOp(v, OP_MoveTo, base, 0);

  /* Delete the old indices for the current record.
................................................................................
    pIdx = apIdx[i];
    for(j=0; j<pIdx->nColumn; j++){
      sqliteVdbeAddOp(v, OP_Column, base, pIdx->aiColumn[j]);
    }
    sqliteVdbeAddOp(v, OP_MakeIdxKey, pIdx->nColumn, 0);
    sqliteVdbeAddOp(v, OP_IdxDelete, base+i+1, 0);
  }

  /* If changing the record number, remove the old record number
  ** from the top of the stack and replace it with the new one.
  */
  if( chngRecno ){
    sqliteVdbeAddOp(v, OP_Pop, 1, 0);
    sqliteExprCode(pParse, pRecnoExpr);
    sqliteVdbeAddOp(v, OP_AddImm, 0, 0);
  }

  /* Compute new data for this record.  
  */
  for(i=0; i<pTab->nCol; i++){
    if( i==pTab->iPKey ){
      sqliteVdbeAddOp(v, OP_Dup, i, 0);
      continue;
    }
    j = aXRef[i];
    if( j<0 ){
      sqliteVdbeAddOp(v, OP_Column, base, i);
    }else{
      sqliteExprCode(pParse, pChanges->a[j].pExpr);
    }
  }

  /* If changing the record number, delete the hold record.
  */
  if( chngRecno ){
    sqliteVdbeAddOp(v, OP_Delete, 0, 0);
  }

  /* Insert new index entries that correspond to the new data
  */
  for(i=0; i<nIdx; i++){
    sqliteVdbeAddOp(v, OP_Dup, pTab->nCol, 0); /* The KEY */
    pIdx = apIdx[i];
    for(j=0; j<pIdx->nColumn; j++){
      int idx = pIdx->aiColumn[j];
      if( idx==pTab->iPKey ){
        sqliteVdbeAddOp(v, OP_Dup, j, 0);
      }else{
        sqliteVdbeAddOp(v, OP_Dup, j+pTab->nCol-idx, 0);
      }
    }
    sqliteVdbeAddOp(v, OP_MakeIdxKey, pIdx->nColumn, 0);
    sqliteVdbeAddOp(v, OP_IdxPut, base+i+1, pIdx->isUnique);
  }

  /* Write the new data back into the database.
  */

Changes to src/vdbe.c.

26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
....
1650
1651
1652
1653
1654
1655
1656
1657



1658
1659
1660
1661
1662
1663
1664
....
2265
2266
2267
2268
2269
2270
2271
2272
2273

2274
2275
2276
2277
2278
2279




2280
2281
2282
2283
2284
2285
2286
2287

2288
2289
2290
2291
2292
2293
2294
2295
2296

2297
2298


2299
2300
2301
2302
2303
2304
2305
2306
2307

2308
2309
2310
2311
2312
2313
2314
2315
2316
2317
2318


2319
2320
2321
2322
2323
2324
2325
2326
2327
2328
2329
2330

2331
2332
2333
2334
2335
2336
2337
2338
2339
....
2609
2610
2611
2612
2613
2614
2615
2616
2617
2618
2619
2620
2621
2622
2623
....
2662
2663
2664
2665
2666
2667
2668
2669
2670
2671
2672
2673
2674
2675



2676
2677
2678
2679
2680
2681
2682
....
2686
2687
2688
2689
2690
2691
2692










2693
2694
2695
2696
2697
2698
2699
** 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.100 2001/11/13 19:35:15 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>

/*
** The following global variable is incremented every time a cursor
** moves, either by the OP_MoveTo or the OP_Next opcode.  The test
................................................................................
  aStack[nos].i = a;
  aStack[nos].flags = STK_Int;
  break;
}

/* Opcode: AddImm  P1 * *
** 
** Add the value P1 to whatever is on top of the stack.



*/
case OP_AddImm: {
  int tos = p->tos;
  VERIFY( if( tos<0 ) goto not_enough_stack; )
  Integerify(p, tos);
  aStack[tos].i += pOp->p1;
  break;
................................................................................
    sqliteBtreeRollback(db->pBeTemp);
  }
  rc = sqliteBtreeRollback(pBt);
  sqliteRollbackInternalChanges(db);
  break;
}

/* Opcode: ReadCookie * * *
**

** Read the schema cookie from the database file and push it onto the
** stack.  The schema cookie is an integer that is used like a version
** number for the database schema.  Everytime the schema changes, the
** cookie changes to a new random value.  This opcode is used during
** initialization to read the initial cookie value so that subsequent
** database accesses can verify that the cookie has not changed.




**
** There must be a read-lock on the database (either a transaction
** must be started or there must be an open cursor) before
** executing this instruction.
*/
case OP_ReadCookie: {
  int i = ++p->tos;
  int aMeta[SQLITE_N_BTREE_META];

  VERIFY( if( NeedStack(p, p->tos) ) goto no_mem; )
  rc = sqliteBtreeGetMeta(pBt, aMeta);
  aStack[i].i = aMeta[1];
  aStack[i].flags = STK_Int;
  break;
}

/* Opcode: SetCookie P1 * *
**

** This operation changes the value of the schema cookie on the database.
** The new value is P1.


**
** The schema cookie changes its value whenever the database schema changes.
** That way, other processes can recognize when the schema has changed
** and reread it.
**
** A transaction must be started before executing this opcode.
*/
case OP_SetCookie: {
  int aMeta[SQLITE_N_BTREE_META];

  rc = sqliteBtreeGetMeta(pBt, aMeta);
  if( rc==SQLITE_OK ){
    aMeta[1] = pOp->p1;
    rc = sqliteBtreeUpdateMeta(pBt, aMeta);
  }
  break;
}

/* Opcode: VerifyCookie P1 * *
**
** Check the current value of the schema cookie and make sure it is


** equal to P1.  If it is not, abort with an SQLITE_SCHEMA error.
**
** The cookie changes its value whenever the database schema changes.
** This operation is used to detect when that the cookie has changed
** and that the current process needs to reread the schema.
**
** Either a transaction needs to have been started or an OP_Open needs
** to be executed (to establish a read lock) before this opcode is
** invoked.
*/
case OP_VerifyCookie: {
  int aMeta[SQLITE_N_BTREE_META];

  rc = sqliteBtreeGetMeta(pBt, aMeta);
  if( rc==SQLITE_OK && aMeta[1]!=pOp->p1 ){
    sqliteSetString(pzErrMsg, "database schema has changed", 0);
    rc = SQLITE_SCHEMA;
  }
  break;
}

/* Opcode: Open P1 P2 P3
................................................................................
  break;
}

/* Opcode: NewRecno P1 * *
**
** Get a new integer record number used as the key to a table.
** The record number is not previously used as a key in the database
** table that cursor P1 points to.  The new record number pushed 
** onto the stack.
*/
case OP_NewRecno: {
  int i = pOp->p1;
  int v = 0;
  Cursor *pC;
  if( VERIFY( i<0 || i>=p->nCursor || ) (pC = &p->aCsr[i])->pCursor==0 ){
................................................................................
  VERIFY( NeedStack(p, p->tos+1); )
  p->tos++;
  aStack[p->tos].i = v;
  aStack[p->tos].flags = STK_Int;
  break;
}

/* Opcode: Put P1 * *
**
** Write an entry into the database file P1.  A new entry is
** created if it doesn't already exist or the data for an existing
** entry is overwritten.  The data is the value on the top of the
** stack.  The key is the next value down on the stack.  The stack
** is popped twice by this instruction.



*/
case OP_Put: {
  int tos = p->tos;
  int nos = p->tos-1;
  int i = pOp->p1;
  VERIFY( if( nos<0 ) goto not_enough_stack; )
  if( VERIFY( i>=0 && i<p->nCursor && ) p->aCsr[i].pCursor!=0 ){
................................................................................
      if( Stringify(p, nos) ) goto no_mem;
      nKey = aStack[nos].n;
      zKey = zStack[nos];
    }else{
      nKey = sizeof(int);
      iKey = bigEndian(aStack[nos].i);
      zKey = (char*)&iKey;










    }
    rc = sqliteBtreeInsert(p->aCsr[i].pCursor, zKey, nKey,
                        zStack[tos], aStack[tos].n);
  }
  POPSTACK;
  POPSTACK;
  break;







|







 







|
>
>
>







 







|

>
|





>
>
>
>








>


|




|

>
|
|
>
>









>


|





|

|
>
>
|











>

|







 







|







 







|






>
>
>







 







>
>
>
>
>
>
>
>
>
>







26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
....
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
....
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
2317
2318
2319
2320
2321
2322
2323
2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
....
2625
2626
2627
2628
2629
2630
2631
2632
2633
2634
2635
2636
2637
2638
2639
....
2678
2679
2680
2681
2682
2683
2684
2685
2686
2687
2688
2689
2690
2691
2692
2693
2694
2695
2696
2697
2698
2699
2700
2701
....
2705
2706
2707
2708
2709
2710
2711
2712
2713
2714
2715
2716
2717
2718
2719
2720
2721
2722
2723
2724
2725
2726
2727
2728
** 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.101 2001/12/21 14:30:43 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>

/*
** The following global variable is incremented every time a cursor
** moves, either by the OP_MoveTo or the OP_Next opcode.  The test
................................................................................
  aStack[nos].i = a;
  aStack[nos].flags = STK_Int;
  break;
}

/* Opcode: AddImm  P1 * *
** 
** Add the value P1 to whatever is on top of the stack.  The result
** is always an integer.
**
** To force the top of the stack to be an integer, just add 0.
*/
case OP_AddImm: {
  int tos = p->tos;
  VERIFY( if( tos<0 ) goto not_enough_stack; )
  Integerify(p, tos);
  aStack[tos].i += pOp->p1;
  break;
................................................................................
    sqliteBtreeRollback(db->pBeTemp);
  }
  rc = sqliteBtreeRollback(pBt);
  sqliteRollbackInternalChanges(db);
  break;
}

/* Opcode: ReadCookie * P2 *
**
** When P2==0, 
** read the schema cookie from the database file and push it onto the
** stack.  The schema cookie is an integer that is used like a version
** number for the database schema.  Everytime the schema changes, the
** cookie changes to a new random value.  This opcode is used during
** initialization to read the initial cookie value so that subsequent
** database accesses can verify that the cookie has not changed.
**
** If P2>0, then read global database parameter number P2.  There is
** a small fixed number of global database parameters.  P2==1 is the
** database version number.  Other parameters are currently unused.
**
** There must be a read-lock on the database (either a transaction
** must be started or there must be an open cursor) before
** executing this instruction.
*/
case OP_ReadCookie: {
  int i = ++p->tos;
  int aMeta[SQLITE_N_BTREE_META];
  assert( pOp->p2<SQLITE_N_BTREE_META );
  VERIFY( if( NeedStack(p, p->tos) ) goto no_mem; )
  rc = sqliteBtreeGetMeta(pBt, aMeta);
  aStack[i].i = aMeta[1+pOp->p2];
  aStack[i].flags = STK_Int;
  break;
}

/* Opcode: SetCookie P1 P2 *
**
** When P2==0,
** this operation changes the value of the schema cookie on the database.
** The new value is P1.  When P2>0, the value of global database parameter
** number P2 is changed.  See ReadCookie for more information about
** global database parametes.
**
** The schema cookie changes its value whenever the database schema changes.
** That way, other processes can recognize when the schema has changed
** and reread it.
**
** A transaction must be started before executing this opcode.
*/
case OP_SetCookie: {
  int aMeta[SQLITE_N_BTREE_META];
  assert( pOp->p2<SQLITE_N_BTREE_META );
  rc = sqliteBtreeGetMeta(pBt, aMeta);
  if( rc==SQLITE_OK ){
    aMeta[1+pOp->p2] = pOp->p1;
    rc = sqliteBtreeUpdateMeta(pBt, aMeta);
  }
  break;
}

/* Opcode: VerifyCookie P1 P2 *
**
** Check the value of global database parameter number P2 and make
** sure it is equal to P1.  P2==0 is the schema cookie.  P1==1 is
** the database version.  If the values do not match, abort with
** an SQLITE_SCHEMA error.
**
** The cookie changes its value whenever the database schema changes.
** This operation is used to detect when that the cookie has changed
** and that the current process needs to reread the schema.
**
** Either a transaction needs to have been started or an OP_Open needs
** to be executed (to establish a read lock) before this opcode is
** invoked.
*/
case OP_VerifyCookie: {
  int aMeta[SQLITE_N_BTREE_META];
  assert( pOp->p2<SQLITE_N_BTREE_META );
  rc = sqliteBtreeGetMeta(pBt, aMeta);
  if( rc==SQLITE_OK && aMeta[1+pOp->p2]!=pOp->p1 ){
    sqliteSetString(pzErrMsg, "database schema has changed", 0);
    rc = SQLITE_SCHEMA;
  }
  break;
}

/* Opcode: Open P1 P2 P3
................................................................................
  break;
}

/* Opcode: NewRecno P1 * *
**
** Get a new integer record number used as the key to a table.
** The record number is not previously used as a key in the database
** table that cursor P1 points to.  The new record number is pushed 
** onto the stack.
*/
case OP_NewRecno: {
  int i = pOp->p1;
  int v = 0;
  Cursor *pC;
  if( VERIFY( i<0 || i>=p->nCursor || ) (pC = &p->aCsr[i])->pCursor==0 ){
................................................................................
  VERIFY( NeedStack(p, p->tos+1); )
  p->tos++;
  aStack[p->tos].i = v;
  aStack[p->tos].flags = STK_Int;
  break;
}

/* Opcode: Put P1 P2 *
**
** Write an entry into the database file P1.  A new entry is
** created if it doesn't already exist or the data for an existing
** entry is overwritten.  The data is the value on the top of the
** stack.  The key is the next value down on the stack.  The stack
** is popped twice by this instruction.
**
** If P2==1 then overwriting is prohibited.  If a prior entry with
** the same key exists, an SQLITE_CONSTRAINT exception is raised.
*/
case OP_Put: {
  int tos = p->tos;
  int nos = p->tos-1;
  int i = pOp->p1;
  VERIFY( if( nos<0 ) goto not_enough_stack; )
  if( VERIFY( i>=0 && i<p->nCursor && ) p->aCsr[i].pCursor!=0 ){
................................................................................
      if( Stringify(p, nos) ) goto no_mem;
      nKey = aStack[nos].n;
      zKey = zStack[nos];
    }else{
      nKey = sizeof(int);
      iKey = bigEndian(aStack[nos].i);
      zKey = (char*)&iKey;
    }
    if( pOp->p2 ){
      int res;
      rc = sqliteBtreeMoveto(p->aCsr[i].pCursor, zKey, nKey, &res);
      if( res==0 && rc==SQLITE_OK ){
        rc = SQLITE_CONSTRAINT;
      }
      if( rc!=SQLITE_OK ){
        goto abort_due_to_error;
      }
    }
    rc = sqliteBtreeInsert(p->aCsr[i].pCursor, zKey, nKey,
                        zStack[tos], aStack[tos].n);
  }
  POPSTACK;
  POPSTACK;
  break;

Added test/intpkey.test.



























































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
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
# 2001 September 15
#
# The author disclaims copyright to this source code.  In place of
# a legal notice, here is a blessing:
#
#    May you do good and not evil.
#    May you find forgiveness for yourself and forgive others.
#    May you share freely, never taking more than you give.
#
#***********************************************************************
# This file implements regression tests for SQLite library.
#
# This file implements tests for the special processing associated
# with INTEGER PRIMARY KEY columns.
#
# $Id: intpkey.test,v 1.1 2001/12/21 14:30:44 drh Exp $

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

# Create a table with a primary key and a datatype other than
# integer
#
do_test intpkey-1.0 {
  execsql {
    CREATE TABLE t1(a TEXT PRIMARY KEY, b, c);
  }
} {}

# There should be an index associated with the primary key
#
do_test intpkey-1.1 {
  execsql {
    SELECT name FROM sqlite_master
    WHERE type='index' AND tbl_name='t1';
  }
} {{(t1 autoindex 1)}}

# Now create a table with an integer primary key and verify that
# there is no associated index.
#
do_test intpkey-1.2 {
  execsql {
    DROP TABLE t1;
    CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c);
    SELECT name FROM sqlite_master
      WHERE type='index' AND tbl_name='t1';
  }
} {}

# Insert some records into the new table.  Specify the primary key
# and verify that the key is used as the record number.
#
do_test intpkey-1.3 {
  execsql {
    INSERT INTO t1 VALUES(5,'hello','world');
  }
} {}
do_test intpkey-1.4 {
  execsql {
    SELECT * FROM t1;
  }
} {5 hello world}
do_test intpkey-1.5 {
  execsql {
    SELECT rowid, * FROM t1;
  }
} {5 5 hello world}

# Attempting to insert a duplicate primary key should give a constraint
# failure.
#
do_test intpkey-1.6 {
  set r [catch {execsql {
     INSERT INTO t1 VALUES(5,'second','entry');
  }} msg]
  lappend r $msg
} {1 {constraint failed}}
do_test intpkey-1.7 {
  execsql {
    SELECT rowid, * FROM t1;
  }
} {5 5 hello world}
do_test intpkey-1.8 {
  set r [catch {execsql {
     INSERT INTO t1 VALUES(6,'second','entry');
  }} msg]
  lappend r $msg
} {0 {}}
do_test intpkey-1.9 {
  execsql {
    SELECT rowid, * FROM t1;
  }
} {5 5 hello world 6 6 second entry}

# A ROWID is automatically generated for new records that do not specify
# the integer primary key.
#
do_test intpkey-1.10 {
  execsql {
    INSERT INTO t1(b,c) VALUES('one','two');
    SELECT b FROM t1 ORDER BY b;
  }
} {hello one second}

# Try to change the ROWID for the new entry.
#
do_test intpkey-1.11 {
  execsql {
    UPDATE t1 SET a=7 WHERE b='one';
    SELECT * FROM t1;
  }
} {5 hello world 6 second entry 7 one two}

# Make sure SELECT statements are able to use the primary key column
# as an index.
#
do_test intpkey-1.12 {
  execsql {
    SELECT * FROM t1 WHERE a==7;
  }
} {7 one two}


finish_test

Changes to test/unique.test.

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
#    May you share freely, never taking more than you give.
#
#***********************************************************************
# This file implements regression tests for SQLite library.  The
# focus of this file is testing the CREATE UNIQUE INDEX statement,
# and primary keys, and the UNIQUE constraint on table columns
#
# $Id: unique.test,v 1.2 2001/09/27 23:57:06 drh Exp $

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

# Try to create a table with two primary keys.
# (This is allowed in SQLite even that it is not valid SQL)
#
................................................................................
do_test unique-1.1 {
  catchsql {
    CREATE TABLE t1(
       a int PRIMARY KEY,
       b int PRIMARY KEY,
       c text
    );









  }
} {0 {}}
do_test unique-1.2 {
  catchsql {
    INSERT INTO t1(a,b,c) VALUES(1,2,3)
  }
} {0 {}}







|







 







>
>
>
>
>
>
>
>
>







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
#    May you share freely, never taking more than you give.
#
#***********************************************************************
# This file implements regression tests for SQLite library.  The
# focus of this file is testing the CREATE UNIQUE INDEX statement,
# and primary keys, and the UNIQUE constraint on table columns
#
# $Id: unique.test,v 1.3 2001/12/21 14:30:44 drh Exp $

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

# Try to create a table with two primary keys.
# (This is allowed in SQLite even that it is not valid SQL)
#
................................................................................
do_test unique-1.1 {
  catchsql {
    CREATE TABLE t1(
       a int PRIMARY KEY,
       b int PRIMARY KEY,
       c text
    );
  }
} {1 {table "t1" has more than one primary key}}
do_test unique-1.1b {
  catchsql {
    CREATE TABLE t1(
       a int PRIMARY KEY,
       b int UNIQUE,
       c text
    );
  }
} {0 {}}
do_test unique-1.2 {
  catchsql {
    INSERT INTO t1(a,b,c) VALUES(1,2,3)
  }
} {0 {}}