SQLite

Check-in [72bf73b2c1]
Login

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

Overview
Comment:Disallow temporary indices on persistent tables. (CVS 1122)
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 72bf73b2c1e3594aa85920e47fc345bba56c80d0
User & Date: drh 2003-11-27 00:48:58.000
Context
2003-12-04
13:44
Update change log and version in preparation for the 2.8.7 release. (CVS 1123) (check-in: 9e79ab6ce0 user: drh tags: trunk)
2003-11-27
00:48
Disallow temporary indices on persistent tables. (CVS 1122) (check-in: 72bf73b2c1 user: drh tags: trunk)
2003-11-25
23:48
Fix typos in file format documentation. Ticket #505. (CVS 1121) (check-in: 4eef93814f user: drh tags: trunk)
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/build.c.
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
**     DROP INDEX
**     creating ID lists
**     BEGIN TRANSACTION
**     COMMIT
**     ROLLBACK
**     PRAGMA
**
** $Id: build.c,v 1.160 2003/09/06 22:18:08 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>

/*
** This routine is called when a new SQL statement is beginning to
** be parsed.  Check to see if the schema for the database needs







|







19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
**     DROP INDEX
**     creating ID lists
**     BEGIN TRANSACTION
**     COMMIT
**     ROLLBACK
**     PRAGMA
**
** $Id: build.c,v 1.161 2003/11/27 00:48:58 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>

/*
** This routine is called when a new SQL statement is beginning to
** be parsed.  Check to see if the schema for the database needs
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
    zType = pTab->aCol[iCol].zType;
  }
  if( pParse->db->file_format>=1 && 
           zType && sqliteStrICmp(zType, "INTEGER")==0 ){
    pTab->iPKey = iCol;
    pTab->keyConf = onError;
  }else{
    sqliteCreateIndex(pParse, 0, 0, pList, onError, 0, 0, 0);
    pList = 0;
  }

primary_key_exit:
  sqliteIdListDelete(pList);
  return;
}







|







730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
    zType = pTab->aCol[iCol].zType;
  }
  if( pParse->db->file_format>=1 && 
           zType && sqliteStrICmp(zType, "INTEGER")==0 ){
    pTab->iPKey = iCol;
    pTab->keyConf = onError;
  }else{
    sqliteCreateIndex(pParse, 0, 0, pList, onError, 0, 0);
    pList = 0;
  }

primary_key_exit:
  sqliteIdListDelete(pList);
  return;
}
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549

1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
*/
void sqliteCreateIndex(
  Parse *pParse,   /* All information about this parse */
  Token *pName,    /* Name of the index.  May be NULL */
  SrcList *pTable, /* Name of the table to index.  Use pParse->pNewTable if 0 */
  IdList *pList,   /* A list of columns to be indexed */
  int onError,     /* OE_Abort, OE_Ignore, OE_Replace, or OE_None */
  int isTemp,      /* True if this is a temporary index */
  Token *pStart,   /* The CREATE token that begins a CREATE TABLE statement */
  Token *pEnd      /* The ")" that closes the CREATE INDEX statement */
){
  Table *pTab;     /* Table to be indexed */
  Index *pIndex;   /* The index to be created */
  char *zName = 0;
  int i, j;
  Token nullId;    /* Fake token for an empty ID list */
  DbFixer sFix;    /* For assigning database names to pTable */

  sqlite *db = pParse->db;

  if( pParse->nErr || sqlite_malloc_failed ) goto exit_create_index;
  if( !isTemp && pParse->initFlag 
     && sqliteFixInit(&sFix, pParse, pParse->iDb, "index", pName)
     && sqliteFixSrcList(&sFix, pTable)
  ){
    goto exit_create_index;
  }

  /*







<









>



|







1533
1534
1535
1536
1537
1538
1539

1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
*/
void sqliteCreateIndex(
  Parse *pParse,   /* All information about this parse */
  Token *pName,    /* Name of the index.  May be NULL */
  SrcList *pTable, /* Name of the table to index.  Use pParse->pNewTable if 0 */
  IdList *pList,   /* A list of columns to be indexed */
  int onError,     /* OE_Abort, OE_Ignore, OE_Replace, or OE_None */

  Token *pStart,   /* The CREATE token that begins a CREATE TABLE statement */
  Token *pEnd      /* The ")" that closes the CREATE INDEX statement */
){
  Table *pTab;     /* Table to be indexed */
  Index *pIndex;   /* The index to be created */
  char *zName = 0;
  int i, j;
  Token nullId;    /* Fake token for an empty ID list */
  DbFixer sFix;    /* For assigning database names to pTable */
  int isTemp;      /* True for a temporary index */
  sqlite *db = pParse->db;

  if( pParse->nErr || sqlite_malloc_failed ) goto exit_create_index;
  if( pParse->initFlag 
     && sqliteFixInit(&sFix, pParse, pParse->iDb, "index", pName)
     && sqliteFixSrcList(&sFix, pTable)
  ){
    goto exit_create_index;
  }

  /*
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
  if( pTab==0 || pParse->nErr ) goto exit_create_index;
  if( pTab->readOnly ){
    sqliteSetString(&pParse->zErrMsg, "table ", pTab->zName,
      " may not be indexed", 0);
    pParse->nErr++;
    goto exit_create_index;
  }
  if( !isTemp && pTab->iDb>=2 && pParse->initFlag==0 ){
    sqliteSetString(&pParse->zErrMsg, "table ", pTab->zName, 
      " may not have non-temporary indices added", 0);
    pParse->nErr++;
    goto exit_create_index;
  }
  if( pTab->pSelect ){
    sqliteSetString(&pParse->zErrMsg, "views may not be indexed", 0);
    pParse->nErr++;
    goto exit_create_index;
  }
  if( pTab->iDb==1 ){
    isTemp = 1;
  }

  /*
  ** Find the name of the index.  Make sure there is not already another
  ** index or table with the same name.  
  **
  ** Exception:  If we are reading the names of permanent indices from the
  ** sqlite_master table (because some other process changed the schema) and







|

|








<
|
<







1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588

1589

1590
1591
1592
1593
1594
1595
1596
  if( pTab==0 || pParse->nErr ) goto exit_create_index;
  if( pTab->readOnly ){
    sqliteSetString(&pParse->zErrMsg, "table ", pTab->zName,
      " may not be indexed", 0);
    pParse->nErr++;
    goto exit_create_index;
  }
  if( pTab->iDb>=2 && pParse->initFlag==0 ){
    sqliteSetString(&pParse->zErrMsg, "table ", pTab->zName, 
      " may not have indices added", 0);
    pParse->nErr++;
    goto exit_create_index;
  }
  if( pTab->pSelect ){
    sqliteSetString(&pParse->zErrMsg, "views may not be indexed", 0);
    pParse->nErr++;
    goto exit_create_index;
  }

  isTemp = pTab->iDb==1;


  /*
  ** Find the name of the index.  Make sure there is not already another
  ** index or table with the same name.  
  **
  ** Exception:  If we are reading the names of permanent indices from the
  ** sqlite_master table (because some other process changed the schema) and
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650

  /* Check for authorization to create an index.
  */
#ifndef SQLITE_OMIT_AUTHORIZATION
  {
    const char *zDb = db->aDb[pTab->iDb].zName;

    assert( isTemp==0 || isTemp==1 );
    assert( pTab->iDb==pParse->iDb || isTemp==1 );
    if( sqliteAuthCheck(pParse, SQLITE_INSERT, SCHEMA_TABLE(isTemp), 0, zDb) ){
      goto exit_create_index;
    }
    i = SQLITE_CREATE_INDEX;
    if( isTemp ) i = SQLITE_CREATE_TEMP_INDEX;
    if( sqliteAuthCheck(pParse, i, zName, pTab->zName, zDb) ){
      goto exit_create_index;







<
|







1633
1634
1635
1636
1637
1638
1639

1640
1641
1642
1643
1644
1645
1646
1647

  /* Check for authorization to create an index.
  */
#ifndef SQLITE_OMIT_AUTHORIZATION
  {
    const char *zDb = db->aDb[pTab->iDb].zName;


    assert( pTab->iDb==pParse->iDb || isTemp );
    if( sqliteAuthCheck(pParse, SQLITE_INSERT, SCHEMA_TABLE(isTemp), 0, zDb) ){
      goto exit_create_index;
    }
    i = SQLITE_CREATE_INDEX;
    if( isTemp ) i = SQLITE_CREATE_TEMP_INDEX;
    if( sqliteAuthCheck(pParse, i, zName, pTab->zName, zDb) ){
      goto exit_create_index;
Changes to src/parse.y.
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
**
*************************************************************************
** 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.103 2003/09/30 01:54:14 drh Exp $
*/
%token_prefix TK_
%token_type {Token}
%default_type {Token}
%extra_argument {Parse *pParse}
%syntax_error {
  if( pParse->zErrMsg==0 ){







|







10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
**
*************************************************************************
** 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.104 2003/11/27 00:48:58 drh Exp $
*/
%token_prefix TK_
%token_type {Token}
%default_type {Token}
%extra_argument {Parse *pParse}
%syntax_error {
  if( pParse->zErrMsg==0 ){
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187

// In addition to the type name, we also care about the primary key and
// UNIQUE constraints.
//
ccons ::= NULL onconf.
ccons ::= NOT NULL onconf(R).               {sqliteAddNotNull(pParse, R);}
ccons ::= PRIMARY KEY sortorder onconf(R).  {sqliteAddPrimaryKey(pParse,0,R);}
ccons ::= UNIQUE onconf(R).           {sqliteCreateIndex(pParse,0,0,0,R,0,0,0);}
ccons ::= CHECK LP expr RP onconf.
ccons ::= REFERENCES nm(T) idxlist_opt(TA) refargs(R).
                                {sqliteCreateForeignKey(pParse,0,&T,TA,R);}
ccons ::= defer_subclause(D).   {sqliteDeferForeignKey(pParse,D);}
ccons ::= COLLATE id(C).  {
   sqliteAddCollateType(pParse, sqliteCollateType(C.z, C.n));
}







|







173
174
175
176
177
178
179
180
181
182
183
184
185
186
187

// In addition to the type name, we also care about the primary key and
// UNIQUE constraints.
//
ccons ::= NULL onconf.
ccons ::= NOT NULL onconf(R).               {sqliteAddNotNull(pParse, R);}
ccons ::= PRIMARY KEY sortorder onconf(R).  {sqliteAddPrimaryKey(pParse,0,R);}
ccons ::= UNIQUE onconf(R).           {sqliteCreateIndex(pParse,0,0,0,R,0,0);}
ccons ::= CHECK LP expr RP onconf.
ccons ::= REFERENCES nm(T) idxlist_opt(TA) refargs(R).
                                {sqliteCreateForeignKey(pParse,0,&T,TA,R);}
ccons ::= defer_subclause(D).   {sqliteDeferForeignKey(pParse,D);}
ccons ::= COLLATE id(C).  {
   sqliteAddCollateType(pParse, sqliteCollateType(C.z, C.n));
}
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
conslist ::= conslist COMMA tcons.
conslist ::= conslist tcons.
conslist ::= tcons.
tcons ::= CONSTRAINT nm.
tcons ::= PRIMARY KEY LP idxlist(X) RP onconf(R).
                                             {sqliteAddPrimaryKey(pParse,X,R);}
tcons ::= UNIQUE LP idxlist(X) RP onconf(R).
                                     {sqliteCreateIndex(pParse,0,0,X,R,0,0,0);}
tcons ::= CHECK expr onconf.
tcons ::= FOREIGN KEY LP idxlist(FA) RP
          REFERENCES nm(T) idxlist_opt(TA) refargs(R) defer_subclause_opt(D). {
    sqliteCreateForeignKey(pParse, FA, &T, TA, R);
    sqliteDeferForeignKey(pParse, D);
}
%type defer_subclause_opt {int}







|







220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
conslist ::= conslist COMMA tcons.
conslist ::= conslist tcons.
conslist ::= tcons.
tcons ::= CONSTRAINT nm.
tcons ::= PRIMARY KEY LP idxlist(X) RP onconf(R).
                                             {sqliteAddPrimaryKey(pParse,X,R);}
tcons ::= UNIQUE LP idxlist(X) RP onconf(R).
                                       {sqliteCreateIndex(pParse,0,0,X,R,0,0);}
tcons ::= CHECK expr onconf.
tcons ::= FOREIGN KEY LP idxlist(FA) RP
          REFERENCES nm(T) idxlist_opt(TA) refargs(R) defer_subclause_opt(D). {
    sqliteCreateForeignKey(pParse, FA, &T, TA, R);
    sqliteDeferForeignKey(pParse, D);
}
%type defer_subclause_opt {int}
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
   {A = sqliteExprListAppend(X,Y,0);}
exprlist(A) ::= expritem(X).            {A = sqliteExprListAppend(0,X,0);}
expritem(A) ::= expr(X).                {A = X;}
expritem(A) ::= .                       {A = 0;}

///////////////////////////// The CREATE INDEX command ///////////////////////
//
cmd ::= CREATE(S) temp(T) uniqueflag(U) INDEX nm(X)
        ON nm(Y) dbnm(D) LP idxlist(Z) RP(E) onconf(R). {
  SrcList *pSrc = sqliteSrcListAppend(0, &Y, &D);
  if( U!=OE_None ) U = R;
  if( U==OE_Default) U = OE_Abort;
  sqliteCreateIndex(pParse, &X, pSrc, Z, U, T, &S, &E);
}

%type uniqueflag {int}
uniqueflag(A) ::= UNIQUE.  { A = OE_Abort; }
uniqueflag(A) ::= .        { A = OE_None; }

%type idxlist {IdList*}







|




|







697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
   {A = sqliteExprListAppend(X,Y,0);}
exprlist(A) ::= expritem(X).            {A = sqliteExprListAppend(0,X,0);}
expritem(A) ::= expr(X).                {A = X;}
expritem(A) ::= .                       {A = 0;}

///////////////////////////// The CREATE INDEX command ///////////////////////
//
cmd ::= CREATE(S) uniqueflag(U) INDEX nm(X)
        ON nm(Y) dbnm(D) LP idxlist(Z) RP(E) onconf(R). {
  SrcList *pSrc = sqliteSrcListAppend(0, &Y, &D);
  if( U!=OE_None ) U = R;
  if( U==OE_Default) U = OE_Abort;
  sqliteCreateIndex(pParse, &X, pSrc, Z, U, &S, &E);
}

%type uniqueflag {int}
uniqueflag(A) ::= UNIQUE.  { A = OE_Abort; }
uniqueflag(A) ::= .        { A = OE_None; }

%type idxlist {IdList*}
Changes to src/sqliteInt.h.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/*
** 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.
**
*************************************************************************
** Internal interface definitions for SQLite.
**
** @(#) $Id: sqliteInt.h,v 1.202 2003/11/11 23:30:36 drh Exp $
*/
#include "config.h"
#include "sqlite.h"
#include "hash.h"
#include "vdbe.h"
#include "parse.h"
#include "btree.h"













|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/*
** 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.
**
*************************************************************************
** Internal interface definitions for SQLite.
**
** @(#) $Id: sqliteInt.h,v 1.203 2003/11/27 00:48:58 drh Exp $
*/
#include "config.h"
#include "sqlite.h"
#include "hash.h"
#include "vdbe.h"
#include "parse.h"
#include "btree.h"
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
IdList *sqliteIdListAppend(IdList*, Token*);
int sqliteIdListIndex(IdList*,const char*);
SrcList *sqliteSrcListAppend(SrcList*, Token*, Token*);
void sqliteSrcListAddAlias(SrcList*, Token*);
void sqliteSrcListAssignCursors(Parse*, SrcList*);
void sqliteIdListDelete(IdList*);
void sqliteSrcListDelete(SrcList*);
void sqliteCreateIndex(Parse*,Token*,SrcList*,IdList*,int,int,Token*,Token*);
void sqliteDropIndex(Parse*, SrcList*);
void sqliteAddKeyType(Vdbe*, ExprList*);
void sqliteAddIdxKeyType(Vdbe*, Index*);
int sqliteSelect(Parse*, Select*, int, int, Select*, int, int*);
Select *sqliteSelectNew(ExprList*,SrcList*,Expr*,ExprList*,Expr*,ExprList*,
                        int,int,int);
void sqliteSelectDelete(Select*);







|







1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
IdList *sqliteIdListAppend(IdList*, Token*);
int sqliteIdListIndex(IdList*,const char*);
SrcList *sqliteSrcListAppend(SrcList*, Token*, Token*);
void sqliteSrcListAddAlias(SrcList*, Token*);
void sqliteSrcListAssignCursors(Parse*, SrcList*);
void sqliteIdListDelete(IdList*);
void sqliteSrcListDelete(SrcList*);
void sqliteCreateIndex(Parse*,Token*,SrcList*,IdList*,int,Token*,Token*);
void sqliteDropIndex(Parse*, SrcList*);
void sqliteAddKeyType(Vdbe*, ExprList*);
void sqliteAddIdxKeyType(Vdbe*, Index*);
int sqliteSelect(Parse*, Select*, int, int, Select*, int, int*);
Select *sqliteSelectNew(ExprList*,SrcList*,Expr*,ExprList*,Expr*,ExprList*,
                        int,int,int);
void sqliteSelectDelete(Select*);
Changes to test/auth.test.
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#    May you share freely, never taking more than you give.
#
#***********************************************************************
# This file implements regression tests for SQLite library.  The
# focus of this script is testing the ATTACH and DETACH commands
# and related functionality.
#
# $Id: auth.test,v 1.10 2003/06/06 19:00:42 drh Exp $
#

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

# disable this test if the SQLITE_OMIT_AUTHORIZATION macro is
# defined during compilation.







|







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#    May you share freely, never taking more than you give.
#
#***********************************************************************
# This file implements regression tests for SQLite library.  The
# focus of this script is testing the ATTACH and DETACH commands
# and related functionality.
#
# $Id: auth.test,v 1.11 2003/11/27 00:49:23 drh Exp $
#

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

# disable this test if the SQLITE_OMIT_AUTHORIZATION macro is
# defined during compilation.
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278





279
280
281
282
283
284
285
  }
  catchsql {INSERT INTO t2 VALUES(1,2,3)}
} {0 {}}
do_test auth-1.34 {
  execsql {SELECT * FROM t2}
} {1 2 3}

do_test auth-1.35 {
  proc auth {code arg1 arg2 arg3 arg4} {
    if {$code=="SQLITE_READ" && $arg1=="t2" && $arg2=="b"} {
      return SQLITE_DENY
    }
    return SQLITE_OK
  }
  catchsql {SELECT * FROM t2}
} {1 {access to t2.b is prohibited}}





do_test auth-1.36 {
  proc auth {code arg1 arg2 arg3 arg4} {
    if {$code=="SQLITE_READ" && $arg1=="t2" && $arg2=="b"} {
      return SQLITE_IGNORE
    }
    return SQLITE_OK
  }







|








>
>
>
>
>







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
  }
  catchsql {INSERT INTO t2 VALUES(1,2,3)}
} {0 {}}
do_test auth-1.34 {
  execsql {SELECT * FROM t2}
} {1 2 3}

do_test auth-1.35.1 {
  proc auth {code arg1 arg2 arg3 arg4} {
    if {$code=="SQLITE_READ" && $arg1=="t2" && $arg2=="b"} {
      return SQLITE_DENY
    }
    return SQLITE_OK
  }
  catchsql {SELECT * FROM t2}
} {1 {access to t2.b is prohibited}}
do_test auth-1.35.2 {
  execsql {ATTACH DATABASE 'test.db' AS two}
  catchsql {SELECT * FROM two.t2}
} {1 {access to two.t2.b is prohibited}}
execsql {DETACH DATABASE two}
do_test auth-1.36 {
  proc auth {code arg1 arg2 arg3 arg4} {
    if {$code=="SQLITE_READ" && $arg1=="t2" && $arg2=="b"} {
      return SQLITE_IGNORE
    }
    return SQLITE_OK
  }
Changes to test/trigger2.test.
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
	{CREATE TEMP TABLE tbl (a, b);} 
	{CREATE TABLE tbl (a, b);} 
	{CREATE TABLE tbl (a INTEGER PRIMARY KEY, b);} 
	{CREATE TEMPORARY TABLE tbl (a INTEGER PRIMARY KEY, b);} 
        {CREATE TABLE tbl (a, b PRIMARY KEY);} 
	{CREATE TABLE tbl (a, b); CREATE INDEX tbl_idx ON tbl(b);} 
	{CREATE TEMP TABLE tbl (a, b); CREATE INDEX tbl_idx ON tbl(b);} 
	{CREATE TABLE tbl (a, b); CREATE TEMP INDEX tbl_idx ON tbl(b);} 
} {
  incr ii
  catchsql { DROP INDEX tbl_idx; }
  catchsql {
    DROP TABLE rlog;
    DROP TABLE clog;
    DROP TABLE tbl;







<







56
57
58
59
60
61
62

63
64
65
66
67
68
69
	{CREATE TEMP TABLE tbl (a, b);} 
	{CREATE TABLE tbl (a, b);} 
	{CREATE TABLE tbl (a INTEGER PRIMARY KEY, b);} 
	{CREATE TEMPORARY TABLE tbl (a INTEGER PRIMARY KEY, b);} 
        {CREATE TABLE tbl (a, b PRIMARY KEY);} 
	{CREATE TABLE tbl (a, b); CREATE INDEX tbl_idx ON tbl(b);} 
	{CREATE TEMP TABLE tbl (a, b); CREATE INDEX tbl_idx ON tbl(b);} 

} {
  incr ii
  catchsql { DROP INDEX tbl_idx; }
  catchsql {
    DROP TABLE rlog;
    DROP TABLE clog;
    DROP TABLE tbl;