/ Check-in [b3656a5c]
Login

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

Overview
Comment:Working on a bug: Dropping and recreating a table within a transaction causes an assertion failure. (CVS 342)
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1:b3656a5cfef91c89de2cbb9790087d0d53c03e6f
User & Date: drh 2002-01-09 03:19:59
Context
2002-01-09
13:30
Continued work on the DROP/CREATE problem. (CVS 343) check-in: 0a3aa99e user: drh tags: trunk
03:19
Working on a bug: Dropping and recreating a table within a transaction causes an assertion failure. (CVS 342) check-in: b3656a5c user: drh tags: trunk
2002-01-07
19:58
Added a manpage from A. Rottmann. (CVS 341) check-in: 7deb6224 user: drh tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to Makefile.in.

299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314




doc:	$(DOC)
	mkdir -p doc
	mv $(DOC) doc

install:	sqlite libsqlite.la sqlite.h
	$(LIBTOOL) $(INSTALL) libsqlite.la $(prefix)/lib
	$(LIBTOOL) $(INSTALL) sqlite $(prefix)/bin
	$(INSTALL) sqlite.h $(prefix)/include

clean:	
	rm -f *.lo *.la *.o sqlite libsqlite.la sqlite.h
	rm -rf .libs .deps
	rm -f lemon lempar.c parse.* sqlite*.tar.gz
	rm -f $(PUBLISH)
	rm -f *.da *.bb *.bbg gmon.out
	rm -f testfixture test.db











|



|




>
>
>
>
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
doc:	$(DOC)
	mkdir -p doc
	mv $(DOC) doc

install:	sqlite libsqlite.la sqlite.h
	$(LIBTOOL) $(INSTALL) libsqlite.la $(prefix)/lib
	$(LIBTOOL) $(INSTALL) sqlite $(prefix)/bin
	$(INSTALL) -m 0644 sqlite.h $(prefix)/include

clean:	
	rm -f *.lo *.la *.o sqlite libsqlite.la sqlite.h
	rm -rf .libs .deps 
	rm -f lemon lempar.c parse.* sqlite*.tar.gz
	rm -f $(PUBLISH)
	rm -f *.da *.bb *.bbg gmon.out
	rm -f testfixture test.db
	rm -rf doc

distclean:	clean
	rm -f config.log config.status

Changes to src/build.c.

21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
...
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
...
187
188
189
190
191
192
193





















194
195
196
197
198
199
200
...
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
...
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
...
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
...
772
773
774
775
776
777
778
779


780
781
782
783
784
785
786
787
788
789
790
791
792
793
....
1062
1063
1064
1065
1066
1067
1068
1069

1070
1071
1072
1073
1074
1075
1076
....
1119
1120
1121
1122
1123
1124
1125
1126

1127


1128
1129
1130

1131
1132
1133
1134
1135
1136
1137
**     COPY
**     VACUUM
**     BEGIN TRANSACTION
**     COMMIT
**     ROLLBACK
**     PRAGMA
**
** $Id: build.c,v 1.61 2001/12/22 14:49:25 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 
................................................................................
/*
** Locate the in-memory structure that describes 
** a particular database table given the name
** of that table.  Return NULL if not found.
*/
Table *sqliteFindTable(sqlite *db, char *zName){
  Table *p = sqliteHashFind(&db->tblHash, zName, strlen(zName)+1);
  return (p==0 || p->isDelete) ? 0 : p;
}

/*
** Locate the in-memory structure that describes 
** a particular index given the name of that index.
** Return NULL if not found.
*/
Index *sqliteFindIndex(sqlite *db, char *zName){
  Index *p = sqliteHashFind(&db->idxHash, zName, strlen(zName)+1);
  return (p==0 || p->isDelete) ? 0 : p;
}

/*
** Remove the given index from the index hash table, and free
** its memory structures.
**
** The index is removed from the database hash table if db!=NULL.
** But the index is not unlinked from the Table that it indexes.
** Unlinking from the Table must be done by the calling function.
*/
static void sqliteDeleteIndex(sqlite *db, Index *pIndex){
  if( pIndex->zName && db ){

    sqliteHashInsert(&db->idxHash, pIndex->zName, strlen(pIndex->zName)+1, 0);


  }
  sqliteFree(pIndex);
}

/*
** Unlink the given index from its table, then remove
** the index from the index hash table and free its memory
** structures.
*/
................................................................................
    for(p=pIndex->pTable->pIndex; p && p->pNext!=pIndex; p=p->pNext){}
    if( p && p->pNext==pIndex ){
      p->pNext = pIndex->pNext;
    }
  }
  sqliteDeleteIndex(db, pIndex);
}






















/*
** Remove the memory data structures associated with the given
** Table.  No changes are made to disk by this routine.
**
** This routine just deletes the data structure.  It does not unlink
** the table data structure from the hash table.  But it does destroy
................................................................................
  sqliteFree(pTable->zName);
  sqliteFree(pTable->aCol);
  sqliteFree(pTable);
}

/*
** Unlink the given table from the hash tables and the delete the
** table structure and all its indices.
*/
static void sqliteUnlinkAndDeleteTable(sqlite *db, Table *pTable){
  if( pTable->zName && db ){

    sqliteHashInsert(&db->tblHash, pTable->zName, strlen(pTable->zName)+1, 0);


  }
  sqliteDeleteTable(db, pTable);


























}

/*
** Check all Tables and Indexes in the internal hash table and commit
** any additions or deletions to those hash tables.
**
** When executing CREATE TABLE and CREATE INDEX statements, the Table
** and Index structures are created and added to the hash tables, but
** the "isCommit" field is not set.  This routine sets those fields.
** When executing DROP TABLE and DROP INDEX, the "isDelete" fields of
** Table and Index structures is set but the structures are not unlinked
** from the hash tables nor deallocated.  This routine handles that
** deallocation. 
**
** See also: sqliteRollbackInternalChanges()
*/
void sqliteCommitInternalChanges(sqlite *db){
  Hash toDelete;
  HashElem *pElem;
  if( (db->flags & SQLITE_InternChanges)==0 ) return;
  sqliteHashInit(&toDelete, SQLITE_HASH_POINTER, 0);
  db->schema_cookie = db->next_cookie;
  for(pElem=sqliteHashFirst(&db->tblHash); pElem; pElem=sqliteHashNext(pElem)){
    Table *pTable = sqliteHashData(pElem);
    if( pTable->isDelete ){
      sqliteHashInsert(&toDelete, pTable, 0, pTable);
    }else{
      pTable->isCommit = 1;
    }
  }
  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)){
    Index *pIndex = sqliteHashData(pElem);
    sqliteUnlinkAndDeleteIndex(db, pIndex);
  }
  sqliteHashClear(&toDelete);
  db->flags &= ~SQLITE_InternChanges;
}

/*
** This routine runs when one or more CREATE TABLE, CREATE INDEX,
** DROP TABLE, or DROP INDEX statements gets rolled back.  The
** additions or deletions of Table and Index structures in the
................................................................................
  if( (db->flags & SQLITE_InternChanges)==0 ) return;
  sqliteHashInit(&toDelete, SQLITE_HASH_POINTER, 0);
  db->next_cookie = db->schema_cookie;
  for(pElem=sqliteHashFirst(&db->tblHash); pElem; pElem=sqliteHashNext(pElem)){
    Table *pTable = sqliteHashData(pElem);
    if( !pTable->isCommit ){
      sqliteHashInsert(&toDelete, pTable, 0, pTable);
    }else{
      pTable->isDelete = 0;
    }
  }
  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)){
    Index *pIndex = sqliteHashData(pElem);
    sqliteUnlinkAndDeleteIndex(db, pIndex);
  }
  sqliteHashClear(&toDelete);








  db->flags &= ~SQLITE_InternChanges;
}

/*
** Construct the name of a user table or index from a token.
**
** Space to hold the name is obtained from sqliteMalloc() and must
................................................................................
  /* Add the table to the in-memory representation of the database.
  */
  assert( pParse->nameClash==0 || pParse->initFlag==1 );
  if( pParse->explain==0 && pParse->nameClash==0 ){
    Table *pOld;
    pOld = sqliteHashInsert(&db->tblHash, p->zName, strlen(p->zName)+1, p);
    if( pOld ){
      assert( p==pOld );  /* Malloc must have failed */
      return;
    }
    pParse->pNewTable = 0;
    db->nTable++;
    db->flags |= SQLITE_InternChanges;
  }

................................................................................
      sqliteVdbeAddOp(v, OP_Destroy, pIdx->tnum, pTable->isTemp);
    }
    if( (db->flags & SQLITE_InTrans)==0 ){
      sqliteVdbeAddOp(v, OP_Commit, 0, 0);
    }
  }

  /* Mark the in-memory Table structure as being deleted.  The actually


  ** deletion occurs inside of sqliteCommitInternalChanges().
  **
  ** Exception: if the SQL statement began with the EXPLAIN keyword,
  ** then no changes should be made.
  */
  if( !pParse->explain ){
    pTable->isDelete = 1;
    db->flags |= SQLITE_InternChanges;
  }
}

/*
** Create a new index for an SQL table.  pIndex is the name of the index 
** and pTable is the name of the table that is to be indexed.  Both will 
................................................................................
exit_create_index:
  sqliteIdListDelete(pList);
  sqliteFree(zName);
  return;
}

/*
** This routine will drop an existing named index.

*/
void sqliteDropIndex(Parse *pParse, Token *pName){
  Index *pIndex;
  char *zName;
  Vdbe *v;
  sqlite *db = pParse->db;

................................................................................
    }
    sqliteVdbeAddOp(v, OP_Destroy, pIndex->tnum, pTab->isTemp);
    if( (db->flags & SQLITE_InTrans)==0 ){
      sqliteVdbeAddOp(v, OP_Commit, 0, 0);
    }
  }

  /* Mark the internal Index structure for deletion by the

  ** sqliteCommitInternalChanges routine.


  */
  if( !pParse->explain ){
    pIndex->isDelete = 1;

    db->flags |= SQLITE_InternChanges;
  }
}

/*
** Add a new element to the end of an expression list.  If pList is
** initially NULL, then create a new expression list.







|







 







|









|






|



|
|
>
|
>
>

|







 







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







 







|

|
|
>
|
>
>

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









|
|
|
<




<


<



<
<
<
|
|
<
|

|

|


<
<
<
|
|
<
|



|







 







<
<







>
>
>
>
>
>
>




<
<







>
>
>
>
>
>
>
>







 







|







 







|
>
>
|





|







 







|
>







 







|
>
|
>
>


<
>







21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
...
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
...
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
...
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
...
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
...
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
...
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
....
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
....
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188

1189
1190
1191
1192
1193
1194
1195
1196
**     COPY
**     VACUUM
**     BEGIN TRANSACTION
**     COMMIT
**     ROLLBACK
**     PRAGMA
**
** $Id: build.c,v 1.62 2002/01/09 03:20:00 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 
................................................................................
/*
** Locate the in-memory structure that describes 
** a particular database table given the name
** of that table.  Return NULL if not found.
*/
Table *sqliteFindTable(sqlite *db, char *zName){
  Table *p = sqliteHashFind(&db->tblHash, zName, strlen(zName)+1);
  return p;
}

/*
** Locate the in-memory structure that describes 
** a particular index given the name of that index.
** Return NULL if not found.
*/
Index *sqliteFindIndex(sqlite *db, char *zName){
  Index *p = sqliteHashFind(&db->idxHash, zName, strlen(zName)+1);
  return p;
}

/*
** Remove the given index from the index hash table, and free
** its memory structures.
**
** The index is removed from the database hash tables if db!=NULL.
** But the index is not unlinked from the Table that it indexes.
** Unlinking from the Table must be done by the calling function.
*/
static void sqliteDeleteIndex(sqlite *db, Index *p){
  if( p->zName && db ){
    Index *pOld;
    pOld = sqliteHashInsert(&db->idxHash, p->zName, strlen(p->zName)+1, 0);
    assert( pOld==0 || pOld==p );
    sqliteHashInsert(&db->idxDrop, p, 0, 0);
  }
  sqliteFree(p);
}

/*
** Unlink the given index from its table, then remove
** the index from the index hash table and free its memory
** structures.
*/
................................................................................
    for(p=pIndex->pTable->pIndex; p && p->pNext!=pIndex; p=p->pNext){}
    if( p && p->pNext==pIndex ){
      p->pNext = pIndex->pNext;
    }
  }
  sqliteDeleteIndex(db, pIndex);
}

/*
** Move the given index to the pending DROP INDEX queue if it has
** been committed.  If this index was never committed, then just
** delete it.
**
** Indices on the pending drop queue are deleted when a COMMIT is
** executed.  If a ROLLBACK occurs, the indices are moved back into
** the main index hash table.
*/
void sqlitePendingDropIndex(sqlite *db, Index *p){
  if( !p->isCommit ){
    sqliteUnlinkAndDeleteIndex(db, p);
  }else{
    Index *pOld;
    pOld = sqliteHashInsert(&db->idxHash, p->zName, strlen(p->zName)+1, 0);
    assert( pOld==p );
    sqliteHashInsert(&db->idxDrop, p, 0, p);
    p->isDropped = 1;
  }
}

/*
** Remove the memory data structures associated with the given
** Table.  No changes are made to disk by this routine.
**
** This routine just deletes the data structure.  It does not unlink
** the table data structure from the hash table.  But it does destroy
................................................................................
  sqliteFree(pTable->zName);
  sqliteFree(pTable->aCol);
  sqliteFree(pTable);
}

/*
** Unlink the given table from the hash tables and the delete the
** table structure with all its indices.
*/
static void sqliteUnlinkAndDeleteTable(sqlite *db, Table *p){
  if( p->zName && db ){
    Table *pOld;
    pOld = sqliteHashInsert(&db->tblHash, p->zName, strlen(p->zName)+1, 0);
    assert( pOld==0 || pOld==p );
    sqliteHashInsert(&db->tblDrop, p, 0, 0);
  }
  sqliteDeleteTable(db, p);
}

/*
** Move the given table to the pending DROP TABLE queue if it has
** been committed.  If this table was never committed, then just
** delete it.  Do the same for all its indices.
**
** Table on the drop queue are not actually deleted until a COMMIT
** statement is executed.  If a ROLLBACK occurs instead of a COMMIT,
** then the tables on the drop queue are moved back into the main
** hash table.
*/
void sqlitePendingDropTable(sqlite *db, Table *pTbl){
  if( !pTbl->isCommit ){
    sqliteUnlinkAndDeleteTable(db, pTbl);
  }else{
    Table *pOld;
    Index *pIndex, *pNext;
    pOld = sqliteHashInsert(&db->tblHash, pTbl->zName, strlen(pTbl->zName)+1,0);
    assert( pOld==pTbl );
    sqliteHashInsert(&db->tblDrop, pTbl, 0, pTbl);
    for(pIndex = pTbl->pIndex; pIndex; pIndex=pNext){
      pNext = pIndex->pNext;
      sqlitePendingDropIndex(db, pIndex);
    }
  }
}

/*
** Check all Tables and Indexes in the internal hash table and commit
** any additions or deletions to those hash tables.
**
** When executing CREATE TABLE and CREATE INDEX statements, the Table
** and Index structures are created and added to the hash tables, but
** the "isCommit" field is not set.  This routine sets those fields.
** When executing DROP TABLE and DROP INDEX, the table or index structures
** are moved out of tblHash and idxHash into tblDrop and idxDrop.  This
** routine deletes the structure in tblDrop and idxDrop.

**
** See also: sqliteRollbackInternalChanges()
*/
void sqliteCommitInternalChanges(sqlite *db){

  HashElem *pElem;
  if( (db->flags & SQLITE_InternChanges)==0 ) return;

  db->schema_cookie = db->next_cookie;
  for(pElem=sqliteHashFirst(&db->tblHash); pElem; pElem=sqliteHashNext(pElem)){
    Table *pTable = sqliteHashData(pElem);



    pTable->isCommit = 1;
  }

  for(pElem=sqliteHashFirst(&db->tblDrop); pElem; pElem=sqliteHashNext(pElem)){
    Table *pTable = sqliteHashData(pElem);
    sqliteDeleteTable(db, pTable);
  }
  sqliteHashClear(&db->tblDrop);
  for(pElem=sqliteHashFirst(&db->idxHash); pElem; pElem=sqliteHashNext(pElem)){
    Index *pIndex = sqliteHashData(pElem);



    pIndex->isCommit = 1;
  }

  while( (pElem=sqliteHashFirst(&db->idxDrop))!=0 ){
    Index *pIndex = sqliteHashData(pElem);
    sqliteUnlinkAndDeleteIndex(db, pIndex);
  }
  sqliteHashClear(&db->idxDrop);
  db->flags &= ~SQLITE_InternChanges;
}

/*
** This routine runs when one or more CREATE TABLE, CREATE INDEX,
** DROP TABLE, or DROP INDEX statements gets rolled back.  The
** additions or deletions of Table and Index structures in the
................................................................................
  if( (db->flags & SQLITE_InternChanges)==0 ) return;
  sqliteHashInit(&toDelete, SQLITE_HASH_POINTER, 0);
  db->next_cookie = db->schema_cookie;
  for(pElem=sqliteHashFirst(&db->tblHash); pElem; pElem=sqliteHashNext(pElem)){
    Table *pTable = sqliteHashData(pElem);
    if( !pTable->isCommit ){
      sqliteHashInsert(&toDelete, pTable, 0, pTable);


    }
  }
  for(pElem=sqliteHashFirst(&toDelete); pElem; pElem=sqliteHashNext(pElem)){
    Table *pTable = sqliteHashData(pElem);
    sqliteUnlinkAndDeleteTable(db, pTable);
  }
  sqliteHashClear(&toDelete);
  for(pElem=sqliteHashFirst(&db->tblDrop); pElem; pElem=sqliteHashNext(pElem)){
    Table *pOld, *p = sqliteHashData(pElem);
    assert( p->isCommit );
    pOld = sqliteHashInsert(&db->tblHash, p->zName, strlen(p->zName)+1, p);
    assert( pOld==0 || pOld==p );
  }
  sqliteHashClear(&db->tblDrop);
  for(pElem=sqliteHashFirst(&db->idxHash); pElem; pElem=sqliteHashNext(pElem)){
    Index *pIndex = sqliteHashData(pElem);
    if( !pIndex->isCommit ){
      sqliteHashInsert(&toDelete, pIndex, 0, pIndex);


    }
  }
  for(pElem=sqliteHashFirst(&toDelete); pElem; pElem=sqliteHashNext(pElem)){
    Index *pIndex = sqliteHashData(pElem);
    sqliteUnlinkAndDeleteIndex(db, pIndex);
  }
  sqliteHashClear(&toDelete);
  for(pElem=sqliteHashFirst(&db->idxDrop); pElem; pElem=sqliteHashNext(pElem)){
    Index *pOld, *p = sqliteHashData(pElem);
    assert( p->isCommit );
    p->isDropped = 0;
    pOld = sqliteHashInsert(&db->idxHash, p->zName, strlen(p->zName)+1, p);
    assert( pOld==0 || pOld==p );
  }
  sqliteHashClear(&db->idxDrop);
  db->flags &= ~SQLITE_InternChanges;
}

/*
** Construct the name of a user table or index from a token.
**
** Space to hold the name is obtained from sqliteMalloc() and must
................................................................................
  /* Add the table to the in-memory representation of the database.
  */
  assert( pParse->nameClash==0 || pParse->initFlag==1 );
  if( pParse->explain==0 && pParse->nameClash==0 ){
    Table *pOld;
    pOld = sqliteHashInsert(&db->tblHash, p->zName, strlen(p->zName)+1, p);
    if( pOld ){
      assert( p==pOld );  /* Malloc must have failed inside HashInsert() */
      return;
    }
    pParse->pNewTable = 0;
    db->nTable++;
    db->flags |= SQLITE_InternChanges;
  }

................................................................................
      sqliteVdbeAddOp(v, OP_Destroy, pIdx->tnum, pTable->isTemp);
    }
    if( (db->flags & SQLITE_InTrans)==0 ){
      sqliteVdbeAddOp(v, OP_Commit, 0, 0);
    }
  }

  /* Move the table (and all its indices) to the pending DROP queue.
  ** Or, if the table was never committed, just delete it.  If the table
  ** has been committed and is placed on the pending DROP queue, then the
  ** delete will occur when sqliteCommitInternalChanges() executes.
  **
  ** Exception: if the SQL statement began with the EXPLAIN keyword,
  ** then no changes should be made.
  */
  if( !pParse->explain ){
    sqlitePendingDropTable(db, pTable);
    db->flags |= SQLITE_InternChanges;
  }
}

/*
** Create a new index for an SQL table.  pIndex is the name of the index 
** and pTable is the name of the table that is to be indexed.  Both will 
................................................................................
exit_create_index:
  sqliteIdListDelete(pList);
  sqliteFree(zName);
  return;
}

/*
** This routine will drop an existing named index.  This routine
** implements the DROP INDEX statement.
*/
void sqliteDropIndex(Parse *pParse, Token *pName){
  Index *pIndex;
  char *zName;
  Vdbe *v;
  sqlite *db = pParse->db;

................................................................................
    }
    sqliteVdbeAddOp(v, OP_Destroy, pIndex->tnum, pTab->isTemp);
    if( (db->flags & SQLITE_InTrans)==0 ){
      sqliteVdbeAddOp(v, OP_Commit, 0, 0);
    }
  }

  /* Move the index onto the pending DROP queue.  Or, if the index was
  ** never committed, just delete it.  Indices on the pending DROP queue
  ** get deleted by sqliteCommitInternalChanges() when the user executes
  ** a COMMIT.  Or if a rollback occurs, the elements of the DROP queue
  ** are moved back into the main hash table.
  */
  if( !pParse->explain ){

    sqlitePendingDropIndex(db, pIndex);
    db->flags |= SQLITE_InternChanges;
  }
}

/*
** Add a new element to the end of an expression list.  If pList is
** initially NULL, then create a new expression list.

Changes to src/main.c.

10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
...
264
265
266
267
268
269
270


271
272
273
274
275
276
277
...
314
315
316
317
318
319
320


321
322
323
324
325
326
327
**
*************************************************************************
** 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.53 2002/01/06 17:07:40 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.
................................................................................

  /* Allocate the sqlite data structure */
  db = sqliteMalloc( sizeof(sqlite) );
  if( pzErrMsg ) *pzErrMsg = 0;
  if( db==0 ) goto no_mem_on_open;
  sqliteHashInit(&db->tblHash, SQLITE_HASH_STRING, 0);
  sqliteHashInit(&db->idxHash, SQLITE_HASH_STRING, 0);


  db->nextRowid = sqliteRandomInteger();
  
  /* Open the backend database driver */
  rc = sqliteBtreeOpen(zFilename, mode, MAX_PAGES, &db->pBe);
  if( rc!=SQLITE_OK ){
    switch( rc ){
      default: {
................................................................................
** This routine erases the stored schema.  This erasure occurs because
** either the database is being closed or because some other process
** changed the schema and this process needs to reread it.
*/
static void clearHashTable(sqlite *db, int preserveTemps){
  HashElem *pElem;
  Hash temp1;


  temp1 = db->tblHash;
  sqliteHashInit(&db->tblHash, SQLITE_HASH_STRING, 0);
  sqliteHashClear(&db->idxHash);
  for(pElem=sqliteHashFirst(&temp1); pElem; pElem=sqliteHashNext(pElem)){
    Table *pTab = sqliteHashData(pElem);
    if( preserveTemps && pTab->isTemp ){
      Index *pIdx;







|







 







>
>







 







>
>







10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
...
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
...
316
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.54 2002/01/09 03:20:00 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.
................................................................................

  /* Allocate the sqlite data structure */
  db = sqliteMalloc( sizeof(sqlite) );
  if( pzErrMsg ) *pzErrMsg = 0;
  if( db==0 ) goto no_mem_on_open;
  sqliteHashInit(&db->tblHash, SQLITE_HASH_STRING, 0);
  sqliteHashInit(&db->idxHash, SQLITE_HASH_STRING, 0);
  sqliteHashInit(&db->tblDrop, SQLITE_HASH_POINTER, 0);
  sqliteHashInit(&db->idxDrop, SQLITE_HASH_POINTER, 0);
  db->nextRowid = sqliteRandomInteger();
  
  /* Open the backend database driver */
  rc = sqliteBtreeOpen(zFilename, mode, MAX_PAGES, &db->pBe);
  if( rc!=SQLITE_OK ){
    switch( rc ){
      default: {
................................................................................
** This routine erases the stored schema.  This erasure occurs because
** either the database is being closed or because some other process
** changed the schema and this process needs to reread it.
*/
static void clearHashTable(sqlite *db, int preserveTemps){
  HashElem *pElem;
  Hash temp1;
  assert( sqliteHashFirst(&db->tblDrop)==0 ); /* There can not be uncommitted */
  assert( sqliteHashFirst(&db->idxDrop)==0 ); /*   DROP TABLEs or DROP INDEXs */
  temp1 = db->tblHash;
  sqliteHashInit(&db->tblHash, SQLITE_HASH_STRING, 0);
  sqliteHashClear(&db->idxHash);
  for(pElem=sqliteHashFirst(&temp1); pElem; pElem=sqliteHashNext(pElem)){
    Table *pTab = sqliteHashData(pElem);
    if( preserveTemps && pTab->isTemp ){
      Index *pIdx;

Changes to src/sqliteInt.h.

7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
...
175
176
177
178
179
180
181


182
183
184
185
186
187
188
...
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
...
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
**    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.75 2002/01/06 17:07:40 drh Exp $
*/
#include "sqlite.h"
#include "hash.h"
#include "vdbe.h"
#include "parse.h"
#include "btree.h"
#include <stdio.h>
................................................................................
  int schema_cookie;            /* Magic number that changes with the schema */
  int next_cookie;              /* Value of schema_cookie after commit */
  int nTable;                   /* Number of tables in the database */
  void *pBusyArg;               /* 1st Argument to the busy callback */
  int (*xBusyCallback)(void *,const char*,int);  /* The busy callback */
  Hash tblHash;                 /* All tables indexed by name */
  Hash idxHash;                 /* All (named) indices indexed by name */


  int nextRowid;                /* Next generated rowID */
};

/*
** Possible values for the sqlite.flags.
*/
#define SQLITE_VdbeTrace      0x00000001  /* True to trace VDBE execution */
................................................................................
  int nCol;        /* Number of columns in this table */
  Column *aCol;    /* Information about each column */
  int iPKey;       /* If not less then 0, use aCol[iPKey] as the primary key */
  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.
................................................................................
  char *zName;     /* Name of this index */
  int nColumn;     /* Number of columns in the table used by this index */
  int *aiColumn;   /* Which columns are used by this index.  1st is 0 */
  Table *pTable;   /* The SQL table being indexed */
  int tnum;        /* Page containing root of this index in database file */
  u8 isUnique;     /* True if keys must all be unique */
  u8 isCommit;     /* True if creation of this index has been committed */
  u8 isDelete;     /* True if deletion of this index has not been comitted */
  Index *pNext;    /* The next index associated with the same table */
};

/*
** Each token coming out of the lexer is an instance of
** this structure.
*/







|







 







>
>







 







<







 







|







7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
...
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
...
226
227
228
229
230
231
232

233
234
235
236
237
238
239
...
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
**    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.76 2002/01/09 03:20:00 drh Exp $
*/
#include "sqlite.h"
#include "hash.h"
#include "vdbe.h"
#include "parse.h"
#include "btree.h"
#include <stdio.h>
................................................................................
  int schema_cookie;            /* Magic number that changes with the schema */
  int next_cookie;              /* Value of schema_cookie after commit */
  int nTable;                   /* Number of tables in the database */
  void *pBusyArg;               /* 1st Argument to the busy callback */
  int (*xBusyCallback)(void *,const char*,int);  /* The busy callback */
  Hash tblHash;                 /* All tables indexed by name */
  Hash idxHash;                 /* All (named) indices indexed by name */
  Hash tblDrop;                 /* Uncommitted DROP TABLEs */
  Hash idxDrop;                 /* Uncommitted DROP INDEXs */
  int nextRowid;                /* Next generated rowID */
};

/*
** Possible values for the sqlite.flags.
*/
#define SQLITE_VdbeTrace      0x00000001  /* True to trace VDBE execution */
................................................................................
  int nCol;        /* Number of columns in this table */
  Column *aCol;    /* Information about each column */
  int iPKey;       /* If not less then 0, use aCol[iPKey] as the primary key */
  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 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.
................................................................................
  char *zName;     /* Name of this index */
  int nColumn;     /* Number of columns in the table used by this index */
  int *aiColumn;   /* Which columns are used by this index.  1st is 0 */
  Table *pTable;   /* The SQL table being indexed */
  int tnum;        /* Page containing root of this index in database file */
  u8 isUnique;     /* True if keys must all be unique */
  u8 isCommit;     /* True if creation of this index has been committed */
  u8 isDropped;    /* True if a DROP INDEX has executed on this index */
  Index *pNext;    /* The next index associated with the same table */
};

/*
** Each token coming out of the lexer is an instance of
** this structure.
*/

Changes to src/where.c.

9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
...
298
299
300
301
302
303
304

305
306
307
308
309
310
311
**    May you share freely, never taking more than you give.
**
*************************************************************************
** 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.31 2002/01/06 17:07:41 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.
................................................................................
    */
    for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
      int eqMask = 0;  /* Index columns covered by an x=... constraint */
      int ltMask = 0;  /* Index columns covered by an x<... constraint */
      int gtMask = 0;  /* Index columns covered by an x>... constraing */
      int nEq, m, score;


      if( pIdx->nColumn>32 ) continue;  /* Ignore indices too many columns */
      for(j=0; j<nExpr; j++){
        if( aExpr[j].idxLeft==idx 
             && (aExpr[j].prereqRight & loopMask)==aExpr[j].prereqRight ){
          int iColumn = aExpr[j].p->pLeft->iColumn;
          int k;
          for(k=0; k<pIdx->nColumn; k++){







|







 







>







9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
...
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
**    May you share freely, never taking more than you give.
**
*************************************************************************
** 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.32 2002/01/09 03:20:00 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.
................................................................................
    */
    for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
      int eqMask = 0;  /* Index columns covered by an x=... constraint */
      int ltMask = 0;  /* Index columns covered by an x<... constraint */
      int gtMask = 0;  /* Index columns covered by an x>... constraing */
      int nEq, m, score;

      if( pIdx->isDropped ) continue;   /* Ignore dropped indices */
      if( pIdx->nColumn>32 ) continue;  /* Ignore indices too many columns */
      for(j=0; j<nExpr; j++){
        if( aExpr[j].idxLeft==idx 
             && (aExpr[j].prereqRight & loopMask)==aExpr[j].prereqRight ){
          int iColumn = aExpr[j].p->pLeft->iColumn;
          int k;
          for(k=0; k<pIdx->nColumn; k++){

Changes to test/trans.test.

7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
...
401
402
403
404
405
406
407
408





























































































































409
#    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.  The
# focus of this script is database locks.
#
# $Id: trans.test,v 1.7 2001/09/24 03:12:41 drh Exp $


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


# Create several tables to work with.
................................................................................
  }
} {i2x i2y t1 t2}
do_test trans-5.23 {
  execsql {
    SELECT * FROM t2;
  }
} {1 2 3}






























































































































finish_test







|







 








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

7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
...
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
#    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.  The
# focus of this script is database locks.
#
# $Id: trans.test,v 1.8 2002/01/09 03:20:00 drh Exp $


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


# Create several tables to work with.
................................................................................
  }
} {i2x i2y t1 t2}
do_test trans-5.23 {
  execsql {
    SELECT * FROM t2;
  }
} {1 2 3}

# Try to DROP and CREATE tables and indices with the same name
# within a transaction.  Make sure ROLLBACK works.
#
do_test trans-6.1 {
  execsql2 {
    INSERT INTO t1 VALUES(1,2,3);
    BEGIN TRANSACTION;
    DROP TABLE t1;
    CREATE TABLE t1(p,q,r);
    ROLLBACK;
    SELECT * FROM t1;
  }
} {a 1 b 2 c 3}
do_test trans-6.2 {
  execsql2 {
    INSERT INTO t1 VALUES(1,2,3);
    BEGIN TRANSACTION;
    DROP TABLE t1;
    CREATE TABLE t1(p,q,r);
    COMMIT;
    SELECT * FROM t1;
  }
} {}
do_test trans-6.3 {
  execsql2 {
    INSERT INTO t1 VALUES(1,2,3);
    SELECT * FROM t1;
  }
} {p 1 q 2 r 3}
do_test trans-6.4 {
  execsql2 {
    BEGIN TRANSACTION;
    DROP TABLE t1;
    CREATE TABLE t1(a,b,c);
    INSERT INTO t1 VALUES(4,5,6);
    SELECT * FROM t1;
    DROP TABLE t1;
  }
} {a 4 b 5 c 6}
do_test trans-6.5 {
  execsql2 {
    ROLLBACK;
    SELECT * FROM t1;
  }
} {p 1 q 2 r 3}
do_test trans-6.6 {
  execsql2 {
    BEGIN TRANSACTION;
    DROP TABLE t1;
    CREATE TABLE t1(a,b,c);
    INSERT INTO t1 VALUES(4,5,6);
    SELECT * FROM t1;
    DROP TABLE t1;
  }
} {a 4 b 5 c 6}
do_test trans-6.7 {
  catchsql {
    COMMIT;
    SELECT * FROM t1;
  }
} {1 {no such table: t1}}

do_test trans-6.8 {
  execsql {
    CREATE TABLE t1(a integer primary key,b,c);
    INSERT INTO t1 VALUES(1,-2,-3);
    INSERT INTO t1 VALUES(4,-5,-6);
    SELECT * FROM t1;
  }
} {1 -2 -3 4 -5 -6}
do_test trans-6.9 {
  execsql {
    CREATE INDEX i1 ON t1(b);
    SELECT * FROM t1 WHERE b<1;
  }
} {4 -5 -6 1 -2 -3}
do_test trans-6.10 {
  execsql {
    BEGIN TRANSACTION;
    DROP INDEX i1;
    SELECT * FROM t1 WHERE b<1;
    ROLLBACK;
  }
} {1 -2 -3 4 -5 -6}
do_test trans-6.11 {
  execsql {
    SELECT * FROM t1 WHERE b<1;
  }
} {4 -5 -6 1 -2 -3}
do_test trans-6.12 {
  execsql {
    BEGIN TRANSACTION;
    DROP TABLE t1;
    ROLLBACK;
    SELECT * FROM t1 WHERE b<1;
  }
} {4 -5 -6 1 -2 -3}

do_test trans-6.13 {
  execsql {
    BEGIN TRANSACTION;
    DROP INDEX i1;
    CREATE INDEX i1 ON t1(c);
    SELECT * FROM t1 WHERE b<1;
  }
} {1 -2 -3 4 -5 -6}
do_test trans-6.14 {
  execsql {
    SELECT * FROM t1 WHERE c<1;
  }
} {4 -5 -6 1 -2 -3}
do_test trans-6.15 {
  execsql {
    ROLLBACK;
    SELECT * FROM t1 WHERE b<1;
  }
} {4 -5 -6 1 -2 -3}
do_test trans-6.16 {
  execsql {
    SELECT * FROM t1 WHERE c<1;
  }
} {1 -2 -3 4 -5 -6}



finish_test

Changes to www/changes.tcl.

13
14
15
16
17
18
19
20
21
22
23
24



25
26
27
28
29
30
31


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

chng {2002 Jan 4 (2.2.1)} {
<li>Bug fix: An attempt to delete a single row of a table with a WHERE
    clause of "ROWID=x" when no such rowid exists was causing an error.</li>
<li>Bug fix: Passing in a NULL as the 3rd parameter to <b>sqlite_open()</b>
    would sometimes cause a coredump.</li>



}

chng {2001 Dec 22 (2.2.0)} {
<li>Columns of type INTEGER PRIMARY KEY are actually used as the primary
    key in underlying B-Tree representation of the table.</li>
<li>Several obscure, unrelated bugs were found and fixed while 
    implemented the integer primary key change of the previous bullet.</li>







|




>
>
>







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


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

chng {2002 Jan 8 (2.2.1)} {
<li>Bug fix: An attempt to delete a single row of a table with a WHERE
    clause of "ROWID=x" when no such rowid exists was causing an error.</li>
<li>Bug fix: Passing in a NULL as the 3rd parameter to <b>sqlite_open()</b>
    would sometimes cause a coredump.</li>
<li>Bug fix: DROP TABLE followed by a CREATE TABLE with the same name all
    within a single transaction was causing a coredump.</li>
<li>Makefile updates from A. Rottmann</li>
}

chng {2001 Dec 22 (2.2.0)} {
<li>Columns of type INTEGER PRIMARY KEY are actually used as the primary
    key in underlying B-Tree representation of the table.</li>
<li>Several obscure, unrelated bugs were found and fixed while 
    implemented the integer primary key change of the previous bullet.</li>