Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Add support for CREATE INDEX IF NOT EXISTS and DROP INDEX IF EXISTS. (CVS 2855) |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
551cdd6c309e75687abaeac5381b794c |
User & Date: | drh 2006-01-04 15:54:36.000 |
Context
2006-01-04
| ||
15:58 | Update document for CREATE INDEX IF NOT EXISTS and DROP INDEX IF EXISTS (CVS 2856) (check-in: 963ba8b8f3 user: drh tags: trunk) | |
15:54 | Add support for CREATE INDEX IF NOT EXISTS and DROP INDEX IF EXISTS. (CVS 2855) (check-in: 551cdd6c30 user: drh tags: trunk) | |
2006-01-03
| ||
15:16 | Always case 0 to (char*) on varargs functions. Otherwise there are problems on 64-bit machines. (CVS 2854) (check-in: 837dc77ff9 user: drh tags: trunk) | |
Changes
Changes to src/build.c.
︙ | ︙ | |||
18 19 20 21 22 23 24 | ** CREATE INDEX ** DROP INDEX ** creating ID lists ** BEGIN TRANSACTION ** COMMIT ** ROLLBACK ** | | | 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | ** CREATE INDEX ** DROP INDEX ** creating ID lists ** BEGIN TRANSACTION ** COMMIT ** ROLLBACK ** ** $Id: build.c,v 1.365 2006/01/04 15:54:36 drh Exp $ */ #include "sqliteInt.h" #include <ctype.h> /* ** This routine is called when a new SQL statement is beginning to ** be parsed. Initialize the pParse structure as needed. |
︙ | ︙ | |||
1052 1053 1054 1055 1056 1057 1058 | pTab->autoInc = autoInc; }else if( autoInc ){ #ifndef SQLITE_OMIT_AUTOINCREMENT sqlite3ErrorMsg(pParse, "AUTOINCREMENT is only allowed on an " "INTEGER PRIMARY KEY"); #endif }else{ | | | 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 | pTab->autoInc = autoInc; }else if( autoInc ){ #ifndef SQLITE_OMIT_AUTOINCREMENT sqlite3ErrorMsg(pParse, "AUTOINCREMENT is only allowed on an " "INTEGER PRIMARY KEY"); #endif }else{ sqlite3CreateIndex(pParse, 0, 0, 0, pList, onError, 0, 0, sortOrder, 0); pList = 0; } primary_key_exit: sqlite3ExprListDelete(pList); return; } |
︙ | ︙ | |||
2101 2102 2103 2104 2105 2106 2107 | Token *pName1, /* First part of index name. May be NULL */ Token *pName2, /* Second part of index name. May be NULL */ SrcList *pTblName, /* Table to index. Use pParse->pNewTable if 0 */ ExprList *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 */ | | > | 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 | Token *pName1, /* First part of index name. May be NULL */ Token *pName2, /* Second part of index name. May be NULL */ SrcList *pTblName, /* Table to index. Use pParse->pNewTable if 0 */ ExprList *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 */ int sortOrder, /* Sort order of primary key when pList==NULL */ int ifNotExist /* Omit error if index already exists */ ){ Table *pTab = 0; /* Table to be indexed */ Index *pIndex = 0; /* The index to be created */ char *zName = 0; /* Name of the index */ int nName; /* Number of characters in zName */ int i, j; Token nullId; /* Fake token for an empty ID list */ |
︙ | ︙ | |||
2195 2196 2197 2198 2199 2200 2201 | if( zName==0 ) goto exit_create_index; if( SQLITE_OK!=sqlite3CheckObjectName(pParse, zName) ){ goto exit_create_index; } if( !db->init.busy ){ if( SQLITE_OK!=sqlite3ReadSchema(pParse) ) goto exit_create_index; if( sqlite3FindIndex(db, zName, pDb->zName)!=0 ){ | > | > | 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 | if( zName==0 ) goto exit_create_index; if( SQLITE_OK!=sqlite3CheckObjectName(pParse, zName) ){ goto exit_create_index; } if( !db->init.busy ){ if( SQLITE_OK!=sqlite3ReadSchema(pParse) ) goto exit_create_index; if( sqlite3FindIndex(db, zName, pDb->zName)!=0 ){ if( !ifNotExist ){ sqlite3ErrorMsg(pParse, "index %s already exists", zName); } goto exit_create_index; } if( sqlite3FindTable(db, zName, 0)!=0 ){ sqlite3ErrorMsg(pParse, "there is already a table named %s", zName); goto exit_create_index; } } |
︙ | ︙ | |||
2521 2522 2523 2524 2525 2526 2527 | } } /* ** This routine will drop an existing named index. This routine ** implements the DROP INDEX statement. */ | | > | > | 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 | } } /* ** This routine will drop an existing named index. This routine ** implements the DROP INDEX statement. */ void sqlite3DropIndex(Parse *pParse, SrcList *pName, int ifExists){ Index *pIndex; Vdbe *v; sqlite3 *db = pParse->db; if( pParse->nErr || sqlite3Tsd()->mallocFailed ){ goto exit_drop_index; } assert( pName->nSrc==1 ); if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){ goto exit_drop_index; } pIndex = sqlite3FindIndex(db, pName->a[0].zName, pName->a[0].zDatabase); if( pIndex==0 ){ if( !ifExists ){ sqlite3ErrorMsg(pParse, "no such index: %S", pName, 0); } pParse->checkSchema = 1; goto exit_drop_index; } if( pIndex->autoIndex ){ sqlite3ErrorMsg(pParse, "index associated with UNIQUE " "or PRIMARY KEY constraint cannot be dropped", 0); goto exit_drop_index; |
︙ | ︙ |
Changes to src/parse.y.
︙ | ︙ | |||
10 11 12 13 14 15 16 | ** ************************************************************************* ** 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. ** | | | 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.191 2006/01/04 15:54:36 drh Exp $ */ // All token codes are small integers with #defines that begin with "TK_" %token_prefix TK_ // The type of the data attached to each token is Token. This is also the // default type for non-terminals. |
︙ | ︙ | |||
258 259 260 261 262 263 264 | // In addition to the type name, we also care about the primary key and // UNIQUE constraints. // ccons ::= NULL onconf. ccons ::= NOT NULL onconf(R). {sqlite3AddNotNull(pParse, R);} ccons ::= PRIMARY KEY sortorder(Z) onconf(R) autoinc(I). {sqlite3AddPrimaryKey(pParse,0,R,I,Z);} | | | 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 | // In addition to the type name, we also care about the primary key and // UNIQUE constraints. // ccons ::= NULL onconf. ccons ::= NOT NULL onconf(R). {sqlite3AddNotNull(pParse, R);} ccons ::= PRIMARY KEY sortorder(Z) onconf(R) autoinc(I). {sqlite3AddPrimaryKey(pParse,0,R,I,Z);} ccons ::= UNIQUE onconf(R). {sqlite3CreateIndex(pParse,0,0,0,0,R,0,0,0,0);} ccons ::= CHECK LP expr(X) RP. {sqlite3AddCheckConstraint(pParse,X);} ccons ::= REFERENCES nm(T) idxlist_opt(TA) refargs(R). {sqlite3CreateForeignKey(pParse,0,&T,TA,R);} ccons ::= defer_subclause(D). {sqlite3DeferForeignKey(pParse,D);} ccons ::= COLLATE id(C). {sqlite3AddCollateType(pParse, (char*)C.z, C.n);} // The optional AUTOINCREMENT keyword |
︙ | ︙ | |||
308 309 310 311 312 313 314 | conslist ::= conslist COMMA tcons. conslist ::= conslist tcons. conslist ::= tcons. tcons ::= CONSTRAINT nm. tcons ::= PRIMARY KEY LP idxlist(X) autoinc(I) RP onconf(R). {sqlite3AddPrimaryKey(pParse,X,R,I,0);} tcons ::= UNIQUE LP idxlist(X) RP onconf(R). | | | 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 | conslist ::= conslist COMMA tcons. conslist ::= conslist tcons. conslist ::= tcons. tcons ::= CONSTRAINT nm. tcons ::= PRIMARY KEY LP idxlist(X) autoinc(I) RP onconf(R). {sqlite3AddPrimaryKey(pParse,X,R,I,0);} tcons ::= UNIQUE LP idxlist(X) RP onconf(R). {sqlite3CreateIndex(pParse,0,0,0,X,R,0,0,0,0);} tcons ::= CHECK LP expr(E) RP onconf. {sqlite3AddCheckConstraint(pParse,E);} tcons ::= FOREIGN KEY LP idxlist(FA) RP REFERENCES nm(T) idxlist_opt(TA) refargs(R) defer_subclause_opt(D). { sqlite3CreateForeignKey(pParse, FA, &T, TA, R); sqlite3DeferForeignKey(pParse, D); } %type defer_subclause_opt {int} |
︙ | ︙ | |||
832 833 834 835 836 837 838 | {A = sqlite3ExprListAppend(X,Y,0);} exprlist(A) ::= expritem(X). {A = sqlite3ExprListAppend(0,X,0);} expritem(A) ::= expr(X). {A = X;} expritem(A) ::= . {A = 0;} ///////////////////////////// The CREATE INDEX command /////////////////////// // | | | | 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 | {A = sqlite3ExprListAppend(X,Y,0);} exprlist(A) ::= expritem(X). {A = sqlite3ExprListAppend(0,X,0);} expritem(A) ::= expr(X). {A = X;} expritem(A) ::= . {A = 0;} ///////////////////////////// The CREATE INDEX command /////////////////////// // cmd ::= CREATE(S) uniqueflag(U) INDEX ifnotexists(NE) nm(X) dbnm(D) ON nm(Y) LP idxlist(Z) RP(E) onconf(R). { if( U!=OE_None ) U = R; if( U==OE_Default) U = OE_Abort; sqlite3CreateIndex(pParse, &X, &D, sqlite3SrcListAppend(0,&Y,0), Z, U, &S, &E, SQLITE_SO_ASC, NE); } %type uniqueflag {int} uniqueflag(A) ::= UNIQUE. {A = OE_Abort;} uniqueflag(A) ::= . {A = OE_None;} %type idxlist {ExprList*} |
︙ | ︙ | |||
875 876 877 878 879 880 881 | if( A ) A->a[A->nExpr-1].sortOrder = Z; } idxitem(A) ::= nm(X). {A = X;} ///////////////////////////// The DROP INDEX command ///////////////////////// // | | | 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 | if( A ) A->a[A->nExpr-1].sortOrder = Z; } idxitem(A) ::= nm(X). {A = X;} ///////////////////////////// The DROP INDEX command ///////////////////////// // cmd ::= DROP INDEX ifexists(E) fullname(X). {sqlite3DropIndex(pParse, X, E);} ///////////////////////////// The VACUUM command ///////////////////////////// // cmd ::= VACUUM. {sqlite3Vacuum(pParse,0);} cmd ::= VACUUM nm. {sqlite3Vacuum(pParse,0);} ///////////////////////////// The PRAGMA command ///////////////////////////// |
︙ | ︙ |
Changes to src/prepare.c.
︙ | ︙ | |||
9 10 11 12 13 14 15 | ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains the implementation of the sqlite3_prepare() ** interface, and routines that contribute to loading the database schema ** from disk. ** | | | 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains the implementation of the sqlite3_prepare() ** interface, and routines that contribute to loading the database schema ** from disk. ** ** $Id: prepare.c,v 1.12 2006/01/04 15:54:36 drh Exp $ */ #include "sqliteInt.h" #include "os.h" #include <ctype.h> /* ** Fill the InitData structure with an error message that indicates |
︙ | ︙ | |||
429 430 431 432 433 434 435 | sParse.db = db; sqlite3RunParser(&sParse, zSql, &zErrMsg); if( sqlite3Tsd()->mallocFailed ){ sParse.rc = SQLITE_NOMEM; } if( sParse.rc==SQLITE_DONE ) sParse.rc = SQLITE_OK; | | | 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 | sParse.db = db; sqlite3RunParser(&sParse, zSql, &zErrMsg); if( sqlite3Tsd()->mallocFailed ){ sParse.rc = SQLITE_NOMEM; } if( sParse.rc==SQLITE_DONE ) sParse.rc = SQLITE_OK; if( sParse.checkSchema && !schemaIsValid(db) ){ sParse.rc = SQLITE_SCHEMA; } if( sParse.rc==SQLITE_SCHEMA ){ sqlite3ResetInternalSchema(db, 0); } if( pzTail ) *pzTail = sParse.zTail; rc = sParse.rc; |
︙ | ︙ |
Changes to src/sqliteInt.h.
1 2 3 4 5 6 7 8 9 10 11 12 13 | /* ** 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. ** | | | 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.447 2006/01/04 15:54:36 drh Exp $ */ #ifndef _SQLITEINT_H_ #define _SQLITEINT_H_ /* ** Many people are failing to set -DNDEBUG=1 when compiling SQLite. ** Setting NDEBUG makes the code smaller and run faster. So the following |
︙ | ︙ | |||
1512 1513 1514 1515 1516 1517 1518 | int sqlite3IdListIndex(IdList*,const char*); SrcList *sqlite3SrcListAppend(SrcList*, Token*, Token*); void sqlite3SrcListAddAlias(SrcList*, Token*); void sqlite3SrcListAssignCursors(Parse*, SrcList*); void sqlite3IdListDelete(IdList*); void sqlite3SrcListDelete(SrcList*); void sqlite3CreateIndex(Parse*,Token*,Token*,SrcList*,ExprList*,int,Token*, | | | | 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 | int sqlite3IdListIndex(IdList*,const char*); SrcList *sqlite3SrcListAppend(SrcList*, Token*, Token*); void sqlite3SrcListAddAlias(SrcList*, Token*); void sqlite3SrcListAssignCursors(Parse*, SrcList*); void sqlite3IdListDelete(IdList*); void sqlite3SrcListDelete(SrcList*); void sqlite3CreateIndex(Parse*,Token*,Token*,SrcList*,ExprList*,int,Token*, Token*, int, int); void sqlite3DropIndex(Parse*, SrcList*, int); void sqlite3AddKeyType(Vdbe*, ExprList*); void sqlite3AddIdxKeyType(Vdbe*, Index*); int sqlite3Select(Parse*, Select*, int, int, Select*, int, int*, char *aff); Select *sqlite3SelectNew(ExprList*,SrcList*,Expr*,ExprList*,Expr*,ExprList*, int,Expr*,Expr*); void sqlite3SelectDelete(Select*); void sqlite3SelectUnbind(Select*); |
︙ | ︙ |
Changes to test/index.test.
1 2 3 4 5 6 7 8 9 10 11 12 13 | # 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. The # focus of this file is testing the CREATE INDEX statement. # | | | 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. # #*********************************************************************** # This file implements regression tests for SQLite library. The # focus of this file is testing the CREATE INDEX statement. # # $Id: index.test,v 1.40 2006/01/04 15:54:37 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl # Create a basic index and verify it is added to sqlite_master # do_test index-1.1 { |
︙ | ︙ | |||
181 182 183 184 185 186 187 188 189 190 191 192 193 194 | execsql {CREATE INDEX index1 ON test1(f1)} set v [catch {execsql {CREATE INDEX index1 ON test2(g1)}} msg] lappend v $msg } {1 {index index1 already exists}} do_test index-6.1b { execsql {SELECT name FROM sqlite_master WHERE type!='meta' ORDER BY name} } {index1 test1 test2} do_test index-6.2 { set v [catch {execsql {CREATE INDEX test1 ON test2(g1)}} msg] lappend v $msg } {1 {there is already a table named test1}} do_test index-6.2b { execsql {SELECT name FROM sqlite_master WHERE type!='meta' ORDER BY name} } {index1 test1 test2} | > > > | 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 | execsql {CREATE INDEX index1 ON test1(f1)} set v [catch {execsql {CREATE INDEX index1 ON test2(g1)}} msg] lappend v $msg } {1 {index index1 already exists}} do_test index-6.1b { execsql {SELECT name FROM sqlite_master WHERE type!='meta' ORDER BY name} } {index1 test1 test2} do_test index-6.1c { catchsql {CREATE INDEX IF NOT EXISTS index1 ON test1(f1)} } {0 {}} do_test index-6.2 { set v [catch {execsql {CREATE INDEX test1 ON test2(g1)}} msg] lappend v $msg } {1 {there is already a table named test1}} do_test index-6.2b { execsql {SELECT name FROM sqlite_master WHERE type!='meta' ORDER BY name} } {index1 test1 test2} |
︙ | ︙ | |||
585 586 587 588 589 590 591 592 593 594 595 596 597 598 | } } {sqlite_autoindex_t7_1 sqlite_autoindex_t7_2 sqlite_autoindex_t7_3} do_test index-17.2 { catchsql { DROP INDEX sqlite_autoindex_t7_1; } } {1 {index associated with UNIQUE or PRIMARY KEY constraint cannot be dropped}} # The following tests ensure that it is not possible to explicitly name # a schema object with a name beginning with "sqlite_". Granted that is a # little outside the focus of this test scripts, but this has got to be # tested somewhere. do_test index-18.1 { catchsql { | > > > > > > > > > > > | 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 | } } {sqlite_autoindex_t7_1 sqlite_autoindex_t7_2 sqlite_autoindex_t7_3} do_test index-17.2 { catchsql { DROP INDEX sqlite_autoindex_t7_1; } } {1 {index associated with UNIQUE or PRIMARY KEY constraint cannot be dropped}} do_test index-17.3 { catchsql { DROP INDEX IF EXISTS sqlite_autoindex_t7_1; } } {1 {index associated with UNIQUE or PRIMARY KEY constraint cannot be dropped}} do_test index-17.4 { catchsql { DROP INDEX IF EXISTS no_such_index; } } {0 {}} # The following tests ensure that it is not possible to explicitly name # a schema object with a name beginning with "sqlite_". Granted that is a # little outside the focus of this test scripts, but this has got to be # tested somewhere. do_test index-18.1 { catchsql { |
︙ | ︙ |