17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate ** 2001 September 15
37c478bd9Sstevel@tonic-gate **
47c478bd9Sstevel@tonic-gate ** The author disclaims copyright to this source code. In place of
57c478bd9Sstevel@tonic-gate ** a legal notice, here is a blessing:
67c478bd9Sstevel@tonic-gate **
77c478bd9Sstevel@tonic-gate ** May you do good and not evil.
87c478bd9Sstevel@tonic-gate ** May you find forgiveness for yourself and forgive others.
97c478bd9Sstevel@tonic-gate ** May you share freely, never taking more than you give.
107c478bd9Sstevel@tonic-gate **
117c478bd9Sstevel@tonic-gate *************************************************************************
127c478bd9Sstevel@tonic-gate ** This file contains C code routines that are called by the SQLite parser
137c478bd9Sstevel@tonic-gate ** when syntax rules are reduced. The routines in this file handle the
147c478bd9Sstevel@tonic-gate ** following kinds of SQL syntax:
157c478bd9Sstevel@tonic-gate **
167c478bd9Sstevel@tonic-gate ** CREATE TABLE
177c478bd9Sstevel@tonic-gate ** DROP TABLE
187c478bd9Sstevel@tonic-gate ** CREATE INDEX
197c478bd9Sstevel@tonic-gate ** DROP INDEX
207c478bd9Sstevel@tonic-gate ** creating ID lists
217c478bd9Sstevel@tonic-gate ** BEGIN TRANSACTION
227c478bd9Sstevel@tonic-gate ** COMMIT
237c478bd9Sstevel@tonic-gate ** ROLLBACK
247c478bd9Sstevel@tonic-gate ** PRAGMA
257c478bd9Sstevel@tonic-gate **
267c478bd9Sstevel@tonic-gate ** $Id: build.c,v 1.176.2.2 2004/07/20 00:50:30 drh Exp $
277c478bd9Sstevel@tonic-gate */
287c478bd9Sstevel@tonic-gate #include "sqliteInt.h"
297c478bd9Sstevel@tonic-gate #include <ctype.h>
307c478bd9Sstevel@tonic-gate
317c478bd9Sstevel@tonic-gate /*
327c478bd9Sstevel@tonic-gate ** This routine is called when a new SQL statement is beginning to
337c478bd9Sstevel@tonic-gate ** be parsed. Check to see if the schema for the database needs
347c478bd9Sstevel@tonic-gate ** to be read from the SQLITE_MASTER and SQLITE_TEMP_MASTER tables.
357c478bd9Sstevel@tonic-gate ** If it does, then read it.
367c478bd9Sstevel@tonic-gate */
sqliteBeginParse(Parse * pParse,int explainFlag)377c478bd9Sstevel@tonic-gate void sqliteBeginParse(Parse *pParse, int explainFlag){
387c478bd9Sstevel@tonic-gate sqlite *db = pParse->db;
397c478bd9Sstevel@tonic-gate int i;
407c478bd9Sstevel@tonic-gate pParse->explain = explainFlag;
417c478bd9Sstevel@tonic-gate if((db->flags & SQLITE_Initialized)==0 && db->init.busy==0 ){
427c478bd9Sstevel@tonic-gate int rc = sqliteInit(db, &pParse->zErrMsg);
437c478bd9Sstevel@tonic-gate if( rc!=SQLITE_OK ){
447c478bd9Sstevel@tonic-gate pParse->rc = rc;
457c478bd9Sstevel@tonic-gate pParse->nErr++;
467c478bd9Sstevel@tonic-gate }
477c478bd9Sstevel@tonic-gate }
487c478bd9Sstevel@tonic-gate for(i=0; i<db->nDb; i++){
497c478bd9Sstevel@tonic-gate DbClearProperty(db, i, DB_Locked);
507c478bd9Sstevel@tonic-gate if( !db->aDb[i].inTrans ){
517c478bd9Sstevel@tonic-gate DbClearProperty(db, i, DB_Cookie);
527c478bd9Sstevel@tonic-gate }
537c478bd9Sstevel@tonic-gate }
547c478bd9Sstevel@tonic-gate pParse->nVar = 0;
557c478bd9Sstevel@tonic-gate }
567c478bd9Sstevel@tonic-gate
577c478bd9Sstevel@tonic-gate /*
587c478bd9Sstevel@tonic-gate ** This routine is called after a single SQL statement has been
59*1da57d55SToomas Soome ** parsed and we want to execute the VDBE code to implement
607c478bd9Sstevel@tonic-gate ** that statement. Prior action routines should have already
617c478bd9Sstevel@tonic-gate ** constructed VDBE code to do the work of the SQL statement.
627c478bd9Sstevel@tonic-gate ** This routine just has to execute the VDBE code.
637c478bd9Sstevel@tonic-gate **
647c478bd9Sstevel@tonic-gate ** Note that if an error occurred, it might be the case that
657c478bd9Sstevel@tonic-gate ** no VDBE code was generated.
667c478bd9Sstevel@tonic-gate */
sqliteExec(Parse * pParse)677c478bd9Sstevel@tonic-gate void sqliteExec(Parse *pParse){
687c478bd9Sstevel@tonic-gate sqlite *db = pParse->db;
697c478bd9Sstevel@tonic-gate Vdbe *v = pParse->pVdbe;
707c478bd9Sstevel@tonic-gate
717c478bd9Sstevel@tonic-gate if( v==0 && (v = sqliteGetVdbe(pParse))!=0 ){
727c478bd9Sstevel@tonic-gate sqliteVdbeAddOp(v, OP_Halt, 0, 0);
737c478bd9Sstevel@tonic-gate }
747c478bd9Sstevel@tonic-gate if( sqlite_malloc_failed ) return;
757c478bd9Sstevel@tonic-gate if( v && pParse->nErr==0 ){
767c478bd9Sstevel@tonic-gate FILE *trace = (db->flags & SQLITE_VdbeTrace)!=0 ? stdout : 0;
777c478bd9Sstevel@tonic-gate sqliteVdbeTrace(v, trace);
787c478bd9Sstevel@tonic-gate sqliteVdbeMakeReady(v, pParse->nVar, pParse->explain);
797c478bd9Sstevel@tonic-gate pParse->rc = pParse->nErr ? SQLITE_ERROR : SQLITE_DONE;
807c478bd9Sstevel@tonic-gate pParse->colNamesSet = 0;
817c478bd9Sstevel@tonic-gate }else if( pParse->rc==SQLITE_OK ){
827c478bd9Sstevel@tonic-gate pParse->rc = SQLITE_ERROR;
837c478bd9Sstevel@tonic-gate }
847c478bd9Sstevel@tonic-gate pParse->nTab = 0;
857c478bd9Sstevel@tonic-gate pParse->nMem = 0;
867c478bd9Sstevel@tonic-gate pParse->nSet = 0;
877c478bd9Sstevel@tonic-gate pParse->nAgg = 0;
887c478bd9Sstevel@tonic-gate pParse->nVar = 0;
897c478bd9Sstevel@tonic-gate }
907c478bd9Sstevel@tonic-gate
917c478bd9Sstevel@tonic-gate /*
92*1da57d55SToomas Soome ** Locate the in-memory structure that describes
937c478bd9Sstevel@tonic-gate ** a particular database table given the name
947c478bd9Sstevel@tonic-gate ** of that table and (optionally) the name of the database
957c478bd9Sstevel@tonic-gate ** containing the table. Return NULL if not found.
967c478bd9Sstevel@tonic-gate **
977c478bd9Sstevel@tonic-gate ** If zDatabase is 0, all databases are searched for the
987c478bd9Sstevel@tonic-gate ** table and the first matching table is returned. (No checking
997c478bd9Sstevel@tonic-gate ** for duplicate table names is done.) The search order is
1007c478bd9Sstevel@tonic-gate ** TEMP first, then MAIN, then any auxiliary databases added
1017c478bd9Sstevel@tonic-gate ** using the ATTACH command.
1027c478bd9Sstevel@tonic-gate **
1037c478bd9Sstevel@tonic-gate ** See also sqliteLocateTable().
1047c478bd9Sstevel@tonic-gate */
sqliteFindTable(sqlite * db,const char * zName,const char * zDatabase)1057c478bd9Sstevel@tonic-gate Table *sqliteFindTable(sqlite *db, const char *zName, const char *zDatabase){
1067c478bd9Sstevel@tonic-gate Table *p = 0;
1077c478bd9Sstevel@tonic-gate int i;
1087c478bd9Sstevel@tonic-gate for(i=0; i<db->nDb; i++){
1097c478bd9Sstevel@tonic-gate int j = (i<2) ? i^1 : i; /* Search TEMP before MAIN */
1107c478bd9Sstevel@tonic-gate if( zDatabase!=0 && sqliteStrICmp(zDatabase, db->aDb[j].zName) ) continue;
1117c478bd9Sstevel@tonic-gate p = sqliteHashFind(&db->aDb[j].tblHash, zName, strlen(zName)+1);
1127c478bd9Sstevel@tonic-gate if( p ) break;
1137c478bd9Sstevel@tonic-gate }
1147c478bd9Sstevel@tonic-gate return p;
1157c478bd9Sstevel@tonic-gate }
1167c478bd9Sstevel@tonic-gate
1177c478bd9Sstevel@tonic-gate /*
118*1da57d55SToomas Soome ** Locate the in-memory structure that describes
1197c478bd9Sstevel@tonic-gate ** a particular database table given the name
1207c478bd9Sstevel@tonic-gate ** of that table and (optionally) the name of the database
1217c478bd9Sstevel@tonic-gate ** containing the table. Return NULL if not found.
1227c478bd9Sstevel@tonic-gate ** Also leave an error message in pParse->zErrMsg.
1237c478bd9Sstevel@tonic-gate **
1247c478bd9Sstevel@tonic-gate ** The difference between this routine and sqliteFindTable()
1257c478bd9Sstevel@tonic-gate ** is that this routine leaves an error message in pParse->zErrMsg
1267c478bd9Sstevel@tonic-gate ** where sqliteFindTable() does not.
1277c478bd9Sstevel@tonic-gate */
sqliteLocateTable(Parse * pParse,const char * zName,const char * zDbase)1287c478bd9Sstevel@tonic-gate Table *sqliteLocateTable(Parse *pParse, const char *zName, const char *zDbase){
1297c478bd9Sstevel@tonic-gate Table *p;
1307c478bd9Sstevel@tonic-gate
1317c478bd9Sstevel@tonic-gate p = sqliteFindTable(pParse->db, zName, zDbase);
1327c478bd9Sstevel@tonic-gate if( p==0 ){
1337c478bd9Sstevel@tonic-gate if( zDbase ){
1347c478bd9Sstevel@tonic-gate sqliteErrorMsg(pParse, "no such table: %s.%s", zDbase, zName);
1357c478bd9Sstevel@tonic-gate }else if( sqliteFindTable(pParse->db, zName, 0)!=0 ){
1367c478bd9Sstevel@tonic-gate sqliteErrorMsg(pParse, "table \"%s\" is not in database \"%s\"",
1377c478bd9Sstevel@tonic-gate zName, zDbase);
1387c478bd9Sstevel@tonic-gate }else{
1397c478bd9Sstevel@tonic-gate sqliteErrorMsg(pParse, "no such table: %s", zName);
1407c478bd9Sstevel@tonic-gate }
1417c478bd9Sstevel@tonic-gate }
1427c478bd9Sstevel@tonic-gate return p;
1437c478bd9Sstevel@tonic-gate }
1447c478bd9Sstevel@tonic-gate
1457c478bd9Sstevel@tonic-gate /*
146*1da57d55SToomas Soome ** Locate the in-memory structure that describes
1477c478bd9Sstevel@tonic-gate ** a particular index given the name of that index
1487c478bd9Sstevel@tonic-gate ** and the name of the database that contains the index.
1497c478bd9Sstevel@tonic-gate ** Return NULL if not found.
1507c478bd9Sstevel@tonic-gate **
1517c478bd9Sstevel@tonic-gate ** If zDatabase is 0, all databases are searched for the
1527c478bd9Sstevel@tonic-gate ** table and the first matching index is returned. (No checking
1537c478bd9Sstevel@tonic-gate ** for duplicate index names is done.) The search order is
1547c478bd9Sstevel@tonic-gate ** TEMP first, then MAIN, then any auxiliary databases added
1557c478bd9Sstevel@tonic-gate ** using the ATTACH command.
1567c478bd9Sstevel@tonic-gate */
sqliteFindIndex(sqlite * db,const char * zName,const char * zDb)1577c478bd9Sstevel@tonic-gate Index *sqliteFindIndex(sqlite *db, const char *zName, const char *zDb){
1587c478bd9Sstevel@tonic-gate Index *p = 0;
1597c478bd9Sstevel@tonic-gate int i;
1607c478bd9Sstevel@tonic-gate for(i=0; i<db->nDb; i++){
1617c478bd9Sstevel@tonic-gate int j = (i<2) ? i^1 : i; /* Search TEMP before MAIN */
1627c478bd9Sstevel@tonic-gate if( zDb && sqliteStrICmp(zDb, db->aDb[j].zName) ) continue;
1637c478bd9Sstevel@tonic-gate p = sqliteHashFind(&db->aDb[j].idxHash, zName, strlen(zName)+1);
1647c478bd9Sstevel@tonic-gate if( p ) break;
1657c478bd9Sstevel@tonic-gate }
1667c478bd9Sstevel@tonic-gate return p;
1677c478bd9Sstevel@tonic-gate }
1687c478bd9Sstevel@tonic-gate
1697c478bd9Sstevel@tonic-gate /*
1707c478bd9Sstevel@tonic-gate ** Remove the given index from the index hash table, and free
1717c478bd9Sstevel@tonic-gate ** its memory structures.
1727c478bd9Sstevel@tonic-gate **
1737c478bd9Sstevel@tonic-gate ** The index is removed from the database hash tables but
1747c478bd9Sstevel@tonic-gate ** it is not unlinked from the Table that it indexes.
1757c478bd9Sstevel@tonic-gate ** Unlinking from the Table must be done by the calling function.
1767c478bd9Sstevel@tonic-gate */
sqliteDeleteIndex(sqlite * db,Index * p)1777c478bd9Sstevel@tonic-gate static void sqliteDeleteIndex(sqlite *db, Index *p){
1787c478bd9Sstevel@tonic-gate Index *pOld;
1797c478bd9Sstevel@tonic-gate
1807c478bd9Sstevel@tonic-gate assert( db!=0 && p->zName!=0 );
1817c478bd9Sstevel@tonic-gate pOld = sqliteHashInsert(&db->aDb[p->iDb].idxHash, p->zName,
1827c478bd9Sstevel@tonic-gate strlen(p->zName)+1, 0);
1837c478bd9Sstevel@tonic-gate if( pOld!=0 && pOld!=p ){
1847c478bd9Sstevel@tonic-gate sqliteHashInsert(&db->aDb[p->iDb].idxHash, pOld->zName,
1857c478bd9Sstevel@tonic-gate strlen(pOld->zName)+1, pOld);
1867c478bd9Sstevel@tonic-gate }
1877c478bd9Sstevel@tonic-gate sqliteFree(p);
1887c478bd9Sstevel@tonic-gate }
1897c478bd9Sstevel@tonic-gate
1907c478bd9Sstevel@tonic-gate /*
1917c478bd9Sstevel@tonic-gate ** Unlink the given index from its table, then remove
1927c478bd9Sstevel@tonic-gate ** the index from the index hash table and free its memory
1937c478bd9Sstevel@tonic-gate ** structures.
1947c478bd9Sstevel@tonic-gate */
sqliteUnlinkAndDeleteIndex(sqlite * db,Index * pIndex)1957c478bd9Sstevel@tonic-gate void sqliteUnlinkAndDeleteIndex(sqlite *db, Index *pIndex){
1967c478bd9Sstevel@tonic-gate if( pIndex->pTable->pIndex==pIndex ){
1977c478bd9Sstevel@tonic-gate pIndex->pTable->pIndex = pIndex->pNext;
1987c478bd9Sstevel@tonic-gate }else{
1997c478bd9Sstevel@tonic-gate Index *p;
2007c478bd9Sstevel@tonic-gate for(p=pIndex->pTable->pIndex; p && p->pNext!=pIndex; p=p->pNext){}
2017c478bd9Sstevel@tonic-gate if( p && p->pNext==pIndex ){
2027c478bd9Sstevel@tonic-gate p->pNext = pIndex->pNext;
2037c478bd9Sstevel@tonic-gate }
2047c478bd9Sstevel@tonic-gate }
2057c478bd9Sstevel@tonic-gate sqliteDeleteIndex(db, pIndex);
2067c478bd9Sstevel@tonic-gate }
2077c478bd9Sstevel@tonic-gate
2087c478bd9Sstevel@tonic-gate /*
2097c478bd9Sstevel@tonic-gate ** Erase all schema information from the in-memory hash tables of
2107c478bd9Sstevel@tonic-gate ** database connection. This routine is called to reclaim memory
2117c478bd9Sstevel@tonic-gate ** before the connection closes. It is also called during a rollback
2127c478bd9Sstevel@tonic-gate ** if there were schema changes during the transaction.
2137c478bd9Sstevel@tonic-gate **
2147c478bd9Sstevel@tonic-gate ** If iDb<=0 then reset the internal schema tables for all database
2157c478bd9Sstevel@tonic-gate ** files. If iDb>=2 then reset the internal schema for only the
2167c478bd9Sstevel@tonic-gate ** single file indicated.
2177c478bd9Sstevel@tonic-gate */
sqliteResetInternalSchema(sqlite * db,int iDb)2187c478bd9Sstevel@tonic-gate void sqliteResetInternalSchema(sqlite *db, int iDb){
2197c478bd9Sstevel@tonic-gate HashElem *pElem;
2207c478bd9Sstevel@tonic-gate Hash temp1;
2217c478bd9Sstevel@tonic-gate Hash temp2;
2227c478bd9Sstevel@tonic-gate int i, j;
2237c478bd9Sstevel@tonic-gate
2247c478bd9Sstevel@tonic-gate assert( iDb>=0 && iDb<db->nDb );
2257c478bd9Sstevel@tonic-gate db->flags &= ~SQLITE_Initialized;
2267c478bd9Sstevel@tonic-gate for(i=iDb; i<db->nDb; i++){
2277c478bd9Sstevel@tonic-gate Db *pDb = &db->aDb[i];
2287c478bd9Sstevel@tonic-gate temp1 = pDb->tblHash;
2297c478bd9Sstevel@tonic-gate temp2 = pDb->trigHash;
2307c478bd9Sstevel@tonic-gate sqliteHashInit(&pDb->trigHash, SQLITE_HASH_STRING, 0);
2317c478bd9Sstevel@tonic-gate sqliteHashClear(&pDb->aFKey);
2327c478bd9Sstevel@tonic-gate sqliteHashClear(&pDb->idxHash);
2337c478bd9Sstevel@tonic-gate for(pElem=sqliteHashFirst(&temp2); pElem; pElem=sqliteHashNext(pElem)){
2347c478bd9Sstevel@tonic-gate Trigger *pTrigger = sqliteHashData(pElem);
2357c478bd9Sstevel@tonic-gate sqliteDeleteTrigger(pTrigger);
2367c478bd9Sstevel@tonic-gate }
2377c478bd9Sstevel@tonic-gate sqliteHashClear(&temp2);
2387c478bd9Sstevel@tonic-gate sqliteHashInit(&pDb->tblHash, SQLITE_HASH_STRING, 0);
2397c478bd9Sstevel@tonic-gate for(pElem=sqliteHashFirst(&temp1); pElem; pElem=sqliteHashNext(pElem)){
2407c478bd9Sstevel@tonic-gate Table *pTab = sqliteHashData(pElem);
2417c478bd9Sstevel@tonic-gate sqliteDeleteTable(db, pTab);
2427c478bd9Sstevel@tonic-gate }
2437c478bd9Sstevel@tonic-gate sqliteHashClear(&temp1);
2447c478bd9Sstevel@tonic-gate DbClearProperty(db, i, DB_SchemaLoaded);
2457c478bd9Sstevel@tonic-gate if( iDb>0 ) return;
2467c478bd9Sstevel@tonic-gate }
2477c478bd9Sstevel@tonic-gate assert( iDb==0 );
2487c478bd9Sstevel@tonic-gate db->flags &= ~SQLITE_InternChanges;
2497c478bd9Sstevel@tonic-gate
2507c478bd9Sstevel@tonic-gate /* If one or more of the auxiliary database files has been closed,
2517c478bd9Sstevel@tonic-gate ** then remove then from the auxiliary database list. We take the
2527c478bd9Sstevel@tonic-gate ** opportunity to do this here since we have just deleted all of the
2537c478bd9Sstevel@tonic-gate ** schema hash tables and therefore do not have to make any changes
2547c478bd9Sstevel@tonic-gate ** to any of those tables.
2557c478bd9Sstevel@tonic-gate */
2567c478bd9Sstevel@tonic-gate for(i=0; i<db->nDb; i++){
2577c478bd9Sstevel@tonic-gate struct Db *pDb = &db->aDb[i];
2587c478bd9Sstevel@tonic-gate if( pDb->pBt==0 ){
2597c478bd9Sstevel@tonic-gate if( pDb->pAux && pDb->xFreeAux ) pDb->xFreeAux(pDb->pAux);
2607c478bd9Sstevel@tonic-gate pDb->pAux = 0;
2617c478bd9Sstevel@tonic-gate }
2627c478bd9Sstevel@tonic-gate }
2637c478bd9Sstevel@tonic-gate for(i=j=2; i<db->nDb; i++){
2647c478bd9Sstevel@tonic-gate struct Db *pDb = &db->aDb[i];
2657c478bd9Sstevel@tonic-gate if( pDb->pBt==0 ){
2667c478bd9Sstevel@tonic-gate sqliteFree(pDb->zName);
2677c478bd9Sstevel@tonic-gate pDb->zName = 0;
2687c478bd9Sstevel@tonic-gate continue;
2697c478bd9Sstevel@tonic-gate }
2707c478bd9Sstevel@tonic-gate if( j<i ){
2717c478bd9Sstevel@tonic-gate db->aDb[j] = db->aDb[i];
2727c478bd9Sstevel@tonic-gate }
2737c478bd9Sstevel@tonic-gate j++;
2747c478bd9Sstevel@tonic-gate }
2757c478bd9Sstevel@tonic-gate memset(&db->aDb[j], 0, (db->nDb-j)*sizeof(db->aDb[j]));
2767c478bd9Sstevel@tonic-gate db->nDb = j;
2777c478bd9Sstevel@tonic-gate if( db->nDb<=2 && db->aDb!=db->aDbStatic ){
2787c478bd9Sstevel@tonic-gate memcpy(db->aDbStatic, db->aDb, 2*sizeof(db->aDb[0]));
2797c478bd9Sstevel@tonic-gate sqliteFree(db->aDb);
2807c478bd9Sstevel@tonic-gate db->aDb = db->aDbStatic;
2817c478bd9Sstevel@tonic-gate }
2827c478bd9Sstevel@tonic-gate }
2837c478bd9Sstevel@tonic-gate
2847c478bd9Sstevel@tonic-gate /*
2857c478bd9Sstevel@tonic-gate ** This routine is called whenever a rollback occurs. If there were
2867c478bd9Sstevel@tonic-gate ** schema changes during the transaction, then we have to reset the
2877c478bd9Sstevel@tonic-gate ** internal hash tables and reload them from disk.
2887c478bd9Sstevel@tonic-gate */
sqliteRollbackInternalChanges(sqlite * db)2897c478bd9Sstevel@tonic-gate void sqliteRollbackInternalChanges(sqlite *db){
2907c478bd9Sstevel@tonic-gate if( db->flags & SQLITE_InternChanges ){
2917c478bd9Sstevel@tonic-gate sqliteResetInternalSchema(db, 0);
2927c478bd9Sstevel@tonic-gate }
2937c478bd9Sstevel@tonic-gate }
2947c478bd9Sstevel@tonic-gate
2957c478bd9Sstevel@tonic-gate /*
2967c478bd9Sstevel@tonic-gate ** This routine is called when a commit occurs.
2977c478bd9Sstevel@tonic-gate */
sqliteCommitInternalChanges(sqlite * db)2987c478bd9Sstevel@tonic-gate void sqliteCommitInternalChanges(sqlite *db){
2997c478bd9Sstevel@tonic-gate db->aDb[0].schema_cookie = db->next_cookie;
3007c478bd9Sstevel@tonic-gate db->flags &= ~SQLITE_InternChanges;
3017c478bd9Sstevel@tonic-gate }
3027c478bd9Sstevel@tonic-gate
3037c478bd9Sstevel@tonic-gate /*
3047c478bd9Sstevel@tonic-gate ** Remove the memory data structures associated with the given
3057c478bd9Sstevel@tonic-gate ** Table. No changes are made to disk by this routine.
3067c478bd9Sstevel@tonic-gate **
3077c478bd9Sstevel@tonic-gate ** This routine just deletes the data structure. It does not unlink
3087c478bd9Sstevel@tonic-gate ** the table data structure from the hash table. Nor does it remove
3097c478bd9Sstevel@tonic-gate ** foreign keys from the sqlite.aFKey hash table. But it does destroy
310*1da57d55SToomas Soome ** memory structures of the indices and foreign keys associated with
3117c478bd9Sstevel@tonic-gate ** the table.
3127c478bd9Sstevel@tonic-gate **
3137c478bd9Sstevel@tonic-gate ** Indices associated with the table are unlinked from the "db"
3147c478bd9Sstevel@tonic-gate ** data structure if db!=NULL. If db==NULL, indices attached to
3157c478bd9Sstevel@tonic-gate ** the table are deleted, but it is assumed they have already been
3167c478bd9Sstevel@tonic-gate ** unlinked.
3177c478bd9Sstevel@tonic-gate */
sqliteDeleteTable(sqlite * db,Table * pTable)3187c478bd9Sstevel@tonic-gate void sqliteDeleteTable(sqlite *db, Table *pTable){
3197c478bd9Sstevel@tonic-gate int i;
3207c478bd9Sstevel@tonic-gate Index *pIndex, *pNext;
3217c478bd9Sstevel@tonic-gate FKey *pFKey, *pNextFKey;
3227c478bd9Sstevel@tonic-gate
3237c478bd9Sstevel@tonic-gate if( pTable==0 ) return;
3247c478bd9Sstevel@tonic-gate
3257c478bd9Sstevel@tonic-gate /* Delete all indices associated with this table
3267c478bd9Sstevel@tonic-gate */
3277c478bd9Sstevel@tonic-gate for(pIndex = pTable->pIndex; pIndex; pIndex=pNext){
3287c478bd9Sstevel@tonic-gate pNext = pIndex->pNext;
3297c478bd9Sstevel@tonic-gate assert( pIndex->iDb==pTable->iDb || (pTable->iDb==0 && pIndex->iDb==1) );
3307c478bd9Sstevel@tonic-gate sqliteDeleteIndex(db, pIndex);
3317c478bd9Sstevel@tonic-gate }
3327c478bd9Sstevel@tonic-gate
3337c478bd9Sstevel@tonic-gate /* Delete all foreign keys associated with this table. The keys
334*1da57d55SToomas Soome ** should have already been unlinked from the db->aFKey hash table
3357c478bd9Sstevel@tonic-gate */
3367c478bd9Sstevel@tonic-gate for(pFKey=pTable->pFKey; pFKey; pFKey=pNextFKey){
3377c478bd9Sstevel@tonic-gate pNextFKey = pFKey->pNextFrom;
3387c478bd9Sstevel@tonic-gate assert( pTable->iDb<db->nDb );
3397c478bd9Sstevel@tonic-gate assert( sqliteHashFind(&db->aDb[pTable->iDb].aFKey,
3407c478bd9Sstevel@tonic-gate pFKey->zTo, strlen(pFKey->zTo)+1)!=pFKey );
3417c478bd9Sstevel@tonic-gate sqliteFree(pFKey);
3427c478bd9Sstevel@tonic-gate }
3437c478bd9Sstevel@tonic-gate
3447c478bd9Sstevel@tonic-gate /* Delete the Table structure itself.
3457c478bd9Sstevel@tonic-gate */
3467c478bd9Sstevel@tonic-gate for(i=0; i<pTable->nCol; i++){
3477c478bd9Sstevel@tonic-gate sqliteFree(pTable->aCol[i].zName);
3487c478bd9Sstevel@tonic-gate sqliteFree(pTable->aCol[i].zDflt);
3497c478bd9Sstevel@tonic-gate sqliteFree(pTable->aCol[i].zType);
3507c478bd9Sstevel@tonic-gate }
3517c478bd9Sstevel@tonic-gate sqliteFree(pTable->zName);
3527c478bd9Sstevel@tonic-gate sqliteFree(pTable->aCol);
3537c478bd9Sstevel@tonic-gate sqliteSelectDelete(pTable->pSelect);
3547c478bd9Sstevel@tonic-gate sqliteFree(pTable);
3557c478bd9Sstevel@tonic-gate }
3567c478bd9Sstevel@tonic-gate
3577c478bd9Sstevel@tonic-gate /*
3587c478bd9Sstevel@tonic-gate ** Unlink the given table from the hash tables and the delete the
3597c478bd9Sstevel@tonic-gate ** table structure with all its indices and foreign keys.
3607c478bd9Sstevel@tonic-gate */
sqliteUnlinkAndDeleteTable(sqlite * db,Table * p)3617c478bd9Sstevel@tonic-gate static void sqliteUnlinkAndDeleteTable(sqlite *db, Table *p){
3627c478bd9Sstevel@tonic-gate Table *pOld;
3637c478bd9Sstevel@tonic-gate FKey *pF1, *pF2;
3647c478bd9Sstevel@tonic-gate int i = p->iDb;
3657c478bd9Sstevel@tonic-gate assert( db!=0 );
3667c478bd9Sstevel@tonic-gate pOld = sqliteHashInsert(&db->aDb[i].tblHash, p->zName, strlen(p->zName)+1, 0);
3677c478bd9Sstevel@tonic-gate assert( pOld==0 || pOld==p );
3687c478bd9Sstevel@tonic-gate for(pF1=p->pFKey; pF1; pF1=pF1->pNextFrom){
3697c478bd9Sstevel@tonic-gate int nTo = strlen(pF1->zTo) + 1;
3707c478bd9Sstevel@tonic-gate pF2 = sqliteHashFind(&db->aDb[i].aFKey, pF1->zTo, nTo);
3717c478bd9Sstevel@tonic-gate if( pF2==pF1 ){
3727c478bd9Sstevel@tonic-gate sqliteHashInsert(&db->aDb[i].aFKey, pF1->zTo, nTo, pF1->pNextTo);
3737c478bd9Sstevel@tonic-gate }else{
3747c478bd9Sstevel@tonic-gate while( pF2 && pF2->pNextTo!=pF1 ){ pF2=pF2->pNextTo; }
3757c478bd9Sstevel@tonic-gate if( pF2 ){
3767c478bd9Sstevel@tonic-gate pF2->pNextTo = pF1->pNextTo;
3777c478bd9Sstevel@tonic-gate }
3787c478bd9Sstevel@tonic-gate }
3797c478bd9Sstevel@tonic-gate }
3807c478bd9Sstevel@tonic-gate sqliteDeleteTable(db, p);
3817c478bd9Sstevel@tonic-gate }
3827c478bd9Sstevel@tonic-gate
3837c478bd9Sstevel@tonic-gate /*
3847c478bd9Sstevel@tonic-gate ** Construct the name of a user table or index from a token.
3857c478bd9Sstevel@tonic-gate **
3867c478bd9Sstevel@tonic-gate ** Space to hold the name is obtained from sqliteMalloc() and must
3877c478bd9Sstevel@tonic-gate ** be freed by the calling function.
3887c478bd9Sstevel@tonic-gate */
sqliteTableNameFromToken(Token * pName)3897c478bd9Sstevel@tonic-gate char *sqliteTableNameFromToken(Token *pName){
3907c478bd9Sstevel@tonic-gate char *zName = sqliteStrNDup(pName->z, pName->n);
3917c478bd9Sstevel@tonic-gate sqliteDequote(zName);
3927c478bd9Sstevel@tonic-gate return zName;
3937c478bd9Sstevel@tonic-gate }
3947c478bd9Sstevel@tonic-gate
3957c478bd9Sstevel@tonic-gate /*
3967c478bd9Sstevel@tonic-gate ** Generate code to open the appropriate master table. The table
397*1da57d55SToomas Soome ** opened will be SQLITE_MASTER for persistent tables and
3987c478bd9Sstevel@tonic-gate ** SQLITE_TEMP_MASTER for temporary tables. The table is opened
3997c478bd9Sstevel@tonic-gate ** on cursor 0.
4007c478bd9Sstevel@tonic-gate */
sqliteOpenMasterTable(Vdbe * v,int isTemp)4017c478bd9Sstevel@tonic-gate void sqliteOpenMasterTable(Vdbe *v, int isTemp){
4027c478bd9Sstevel@tonic-gate sqliteVdbeAddOp(v, OP_Integer, isTemp, 0);
4037c478bd9Sstevel@tonic-gate sqliteVdbeAddOp(v, OP_OpenWrite, 0, 2);
4047c478bd9Sstevel@tonic-gate }
4057c478bd9Sstevel@tonic-gate
4067c478bd9Sstevel@tonic-gate /*
4077c478bd9Sstevel@tonic-gate ** Begin constructing a new table representation in memory. This is
4087c478bd9Sstevel@tonic-gate ** the first of several action routines that get called in response
4097c478bd9Sstevel@tonic-gate ** to a CREATE TABLE statement. In particular, this routine is called
4107c478bd9Sstevel@tonic-gate ** after seeing tokens "CREATE" and "TABLE" and the table name. The
4117c478bd9Sstevel@tonic-gate ** pStart token is the CREATE and pName is the table name. The isTemp
4127c478bd9Sstevel@tonic-gate ** flag is true if the table should be stored in the auxiliary database
4137c478bd9Sstevel@tonic-gate ** file instead of in the main database file. This is normally the case
4147c478bd9Sstevel@tonic-gate ** when the "TEMP" or "TEMPORARY" keyword occurs in between
4157c478bd9Sstevel@tonic-gate ** CREATE and TABLE.
4167c478bd9Sstevel@tonic-gate **
4177c478bd9Sstevel@tonic-gate ** The new table record is initialized and put in pParse->pNewTable.
4187c478bd9Sstevel@tonic-gate ** As more of the CREATE TABLE statement is parsed, additional action
4197c478bd9Sstevel@tonic-gate ** routines will be called to add more information to this record.
4207c478bd9Sstevel@tonic-gate ** At the end of the CREATE TABLE statement, the sqliteEndTable() routine
4217c478bd9Sstevel@tonic-gate ** is called to complete the construction of the new table record.
4227c478bd9Sstevel@tonic-gate */
sqliteStartTable(Parse * pParse,Token * pStart,Token * pName,int isTemp,int isView)4237c478bd9Sstevel@tonic-gate void sqliteStartTable(
4247c478bd9Sstevel@tonic-gate Parse *pParse, /* Parser context */
4257c478bd9Sstevel@tonic-gate Token *pStart, /* The "CREATE" token */
4267c478bd9Sstevel@tonic-gate Token *pName, /* Name of table or view to create */
4277c478bd9Sstevel@tonic-gate int isTemp, /* True if this is a TEMP table */
4287c478bd9Sstevel@tonic-gate int isView /* True if this is a VIEW */
4297c478bd9Sstevel@tonic-gate ){
4307c478bd9Sstevel@tonic-gate Table *pTable;
4317c478bd9Sstevel@tonic-gate Index *pIdx;
4327c478bd9Sstevel@tonic-gate char *zName;
4337c478bd9Sstevel@tonic-gate sqlite *db = pParse->db;
4347c478bd9Sstevel@tonic-gate Vdbe *v;
4357c478bd9Sstevel@tonic-gate int iDb;
4367c478bd9Sstevel@tonic-gate
4377c478bd9Sstevel@tonic-gate pParse->sFirstToken = *pStart;
4387c478bd9Sstevel@tonic-gate zName = sqliteTableNameFromToken(pName);
4397c478bd9Sstevel@tonic-gate if( zName==0 ) return;
4407c478bd9Sstevel@tonic-gate if( db->init.iDb==1 ) isTemp = 1;
4417c478bd9Sstevel@tonic-gate #ifndef SQLITE_OMIT_AUTHORIZATION
4427c478bd9Sstevel@tonic-gate assert( (isTemp & 1)==isTemp );
4437c478bd9Sstevel@tonic-gate {
4447c478bd9Sstevel@tonic-gate int code;
4457c478bd9Sstevel@tonic-gate char *zDb = isTemp ? "temp" : "main";
4467c478bd9Sstevel@tonic-gate if( sqliteAuthCheck(pParse, SQLITE_INSERT, SCHEMA_TABLE(isTemp), 0, zDb) ){
4477c478bd9Sstevel@tonic-gate sqliteFree(zName);
4487c478bd9Sstevel@tonic-gate return;
4497c478bd9Sstevel@tonic-gate }
4507c478bd9Sstevel@tonic-gate if( isView ){
4517c478bd9Sstevel@tonic-gate if( isTemp ){
4527c478bd9Sstevel@tonic-gate code = SQLITE_CREATE_TEMP_VIEW;
4537c478bd9Sstevel@tonic-gate }else{
4547c478bd9Sstevel@tonic-gate code = SQLITE_CREATE_VIEW;
4557c478bd9Sstevel@tonic-gate }
4567c478bd9Sstevel@tonic-gate }else{
4577c478bd9Sstevel@tonic-gate if( isTemp ){
4587c478bd9Sstevel@tonic-gate code = SQLITE_CREATE_TEMP_TABLE;
4597c478bd9Sstevel@tonic-gate }else{
4607c478bd9Sstevel@tonic-gate code = SQLITE_CREATE_TABLE;
4617c478bd9Sstevel@tonic-gate }
4627c478bd9Sstevel@tonic-gate }
4637c478bd9Sstevel@tonic-gate if( sqliteAuthCheck(pParse, code, zName, 0, zDb) ){
4647c478bd9Sstevel@tonic-gate sqliteFree(zName);
4657c478bd9Sstevel@tonic-gate return;
4667c478bd9Sstevel@tonic-gate }
4677c478bd9Sstevel@tonic-gate }
4687c478bd9Sstevel@tonic-gate #endif
469*1da57d55SToomas Soome
4707c478bd9Sstevel@tonic-gate
4717c478bd9Sstevel@tonic-gate /* Before trying to create a temporary table, make sure the Btree for
4727c478bd9Sstevel@tonic-gate ** holding temporary tables is open.
4737c478bd9Sstevel@tonic-gate */
4747c478bd9Sstevel@tonic-gate if( isTemp && db->aDb[1].pBt==0 && !pParse->explain ){
4757c478bd9Sstevel@tonic-gate int rc = sqliteBtreeFactory(db, 0, 0, MAX_PAGES, &db->aDb[1].pBt);
4767c478bd9Sstevel@tonic-gate if( rc!=SQLITE_OK ){
4777c478bd9Sstevel@tonic-gate sqliteErrorMsg(pParse, "unable to open a temporary database "
4787c478bd9Sstevel@tonic-gate "file for storing temporary tables");
4797c478bd9Sstevel@tonic-gate pParse->nErr++;
4807c478bd9Sstevel@tonic-gate return;
4817c478bd9Sstevel@tonic-gate }
4827c478bd9Sstevel@tonic-gate if( db->flags & SQLITE_InTrans ){
4837c478bd9Sstevel@tonic-gate rc = sqliteBtreeBeginTrans(db->aDb[1].pBt);
4847c478bd9Sstevel@tonic-gate if( rc!=SQLITE_OK ){
4857c478bd9Sstevel@tonic-gate sqliteErrorMsg(pParse, "unable to get a write lock on "
4867c478bd9Sstevel@tonic-gate "the temporary database file");
4877c478bd9Sstevel@tonic-gate return;
4887c478bd9Sstevel@tonic-gate }
4897c478bd9Sstevel@tonic-gate }
4907c478bd9Sstevel@tonic-gate }
4917c478bd9Sstevel@tonic-gate
4927c478bd9Sstevel@tonic-gate /* Make sure the new table name does not collide with an existing
4937c478bd9Sstevel@tonic-gate ** index or table name. Issue an error message if it does.
4947c478bd9Sstevel@tonic-gate **
4957c478bd9Sstevel@tonic-gate ** If we are re-reading the sqlite_master table because of a schema
4967c478bd9Sstevel@tonic-gate ** change and a new permanent table is found whose name collides with
4977c478bd9Sstevel@tonic-gate ** an existing temporary table, that is not an error.
4987c478bd9Sstevel@tonic-gate */
4997c478bd9Sstevel@tonic-gate pTable = sqliteFindTable(db, zName, 0);
5007c478bd9Sstevel@tonic-gate iDb = isTemp ? 1 : db->init.iDb;
5017c478bd9Sstevel@tonic-gate if( pTable!=0 && (pTable->iDb==iDb || !db->init.busy) ){
5027c478bd9Sstevel@tonic-gate sqliteErrorMsg(pParse, "table %T already exists", pName);
5037c478bd9Sstevel@tonic-gate sqliteFree(zName);
5047c478bd9Sstevel@tonic-gate return;
5057c478bd9Sstevel@tonic-gate }
5067c478bd9Sstevel@tonic-gate if( (pIdx = sqliteFindIndex(db, zName, 0))!=0 &&
5077c478bd9Sstevel@tonic-gate (pIdx->iDb==0 || !db->init.busy) ){
5087c478bd9Sstevel@tonic-gate sqliteErrorMsg(pParse, "there is already an index named %s", zName);
5097c478bd9Sstevel@tonic-gate sqliteFree(zName);
5107c478bd9Sstevel@tonic-gate return;
5117c478bd9Sstevel@tonic-gate }
5127c478bd9Sstevel@tonic-gate pTable = sqliteMalloc( sizeof(Table) );
5137c478bd9Sstevel@tonic-gate if( pTable==0 ){
5147c478bd9Sstevel@tonic-gate sqliteFree(zName);
5157c478bd9Sstevel@tonic-gate return;
5167c478bd9Sstevel@tonic-gate }
5177c478bd9Sstevel@tonic-gate pTable->zName = zName;
5187c478bd9Sstevel@tonic-gate pTable->nCol = 0;
5197c478bd9Sstevel@tonic-gate pTable->aCol = 0;
5207c478bd9Sstevel@tonic-gate pTable->iPKey = -1;
5217c478bd9Sstevel@tonic-gate pTable->pIndex = 0;
5227c478bd9Sstevel@tonic-gate pTable->iDb = iDb;
5237c478bd9Sstevel@tonic-gate if( pParse->pNewTable ) sqliteDeleteTable(db, pParse->pNewTable);
5247c478bd9Sstevel@tonic-gate pParse->pNewTable = pTable;
5257c478bd9Sstevel@tonic-gate
5267c478bd9Sstevel@tonic-gate /* Begin generating the code that will insert the table record into
5277c478bd9Sstevel@tonic-gate ** the SQLITE_MASTER table. Note in particular that we must go ahead
5287c478bd9Sstevel@tonic-gate ** and allocate the record number for the table entry now. Before any
5297c478bd9Sstevel@tonic-gate ** PRIMARY KEY or UNIQUE keywords are parsed. Those keywords will cause
530*1da57d55SToomas Soome ** indices to be created and the table record must come before the
5317c478bd9Sstevel@tonic-gate ** indices. Hence, the record number for the table must be allocated
5327c478bd9Sstevel@tonic-gate ** now.
5337c478bd9Sstevel@tonic-gate */
5347c478bd9Sstevel@tonic-gate if( !db->init.busy && (v = sqliteGetVdbe(pParse))!=0 ){
5357c478bd9Sstevel@tonic-gate sqliteBeginWriteOperation(pParse, 0, isTemp);
5367c478bd9Sstevel@tonic-gate if( !isTemp ){
5377c478bd9Sstevel@tonic-gate sqliteVdbeAddOp(v, OP_Integer, db->file_format, 0);
5387c478bd9Sstevel@tonic-gate sqliteVdbeAddOp(v, OP_SetCookie, 0, 1);
5397c478bd9Sstevel@tonic-gate }
5407c478bd9Sstevel@tonic-gate sqliteOpenMasterTable(v, isTemp);
5417c478bd9Sstevel@tonic-gate sqliteVdbeAddOp(v, OP_NewRecno, 0, 0);
5427c478bd9Sstevel@tonic-gate sqliteVdbeAddOp(v, OP_Dup, 0, 0);
5437c478bd9Sstevel@tonic-gate sqliteVdbeAddOp(v, OP_String, 0, 0);
5447c478bd9Sstevel@tonic-gate sqliteVdbeAddOp(v, OP_PutIntKey, 0, 0);
5457c478bd9Sstevel@tonic-gate }
5467c478bd9Sstevel@tonic-gate }
5477c478bd9Sstevel@tonic-gate
5487c478bd9Sstevel@tonic-gate /*
5497c478bd9Sstevel@tonic-gate ** Add a new column to the table currently being constructed.
5507c478bd9Sstevel@tonic-gate **
5517c478bd9Sstevel@tonic-gate ** The parser calls this routine once for each column declaration
5527c478bd9Sstevel@tonic-gate ** in a CREATE TABLE statement. sqliteStartTable() gets called
5537c478bd9Sstevel@tonic-gate ** first to get things going. Then this routine is called for each
5547c478bd9Sstevel@tonic-gate ** column.
5557c478bd9Sstevel@tonic-gate */
sqliteAddColumn(Parse * pParse,Token * pName)5567c478bd9Sstevel@tonic-gate void sqliteAddColumn(Parse *pParse, Token *pName){
5577c478bd9Sstevel@tonic-gate Table *p;
5587c478bd9Sstevel@tonic-gate int i;
5597c478bd9Sstevel@tonic-gate char *z = 0;
5607c478bd9Sstevel@tonic-gate Column *pCol;
5617c478bd9Sstevel@tonic-gate if( (p = pParse->pNewTable)==0 ) return;
5627c478bd9Sstevel@tonic-gate sqliteSetNString(&z, pName->z, pName->n, 0);
5637c478bd9Sstevel@tonic-gate if( z==0 ) return;
5647c478bd9Sstevel@tonic-gate sqliteDequote(z);
5657c478bd9Sstevel@tonic-gate for(i=0; i<p->nCol; i++){
5667c478bd9Sstevel@tonic-gate if( sqliteStrICmp(z, p->aCol[i].zName)==0 ){
5677c478bd9Sstevel@tonic-gate sqliteErrorMsg(pParse, "duplicate column name: %s", z);
5687c478bd9Sstevel@tonic-gate sqliteFree(z);
5697c478bd9Sstevel@tonic-gate return;
5707c478bd9Sstevel@tonic-gate }
5717c478bd9Sstevel@tonic-gate }
5727c478bd9Sstevel@tonic-gate if( (p->nCol & 0x7)==0 ){
5737c478bd9Sstevel@tonic-gate Column *aNew;
5747c478bd9Sstevel@tonic-gate aNew = sqliteRealloc( p->aCol, (p->nCol+8)*sizeof(p->aCol[0]));
5757c478bd9Sstevel@tonic-gate if( aNew==0 ) return;
5767c478bd9Sstevel@tonic-gate p->aCol = aNew;
5777c478bd9Sstevel@tonic-gate }
5787c478bd9Sstevel@tonic-gate pCol = &p->aCol[p->nCol];
5797c478bd9Sstevel@tonic-gate memset(pCol, 0, sizeof(p->aCol[0]));
5807c478bd9Sstevel@tonic-gate pCol->zName = z;
5817c478bd9Sstevel@tonic-gate pCol->sortOrder = SQLITE_SO_NUM;
5827c478bd9Sstevel@tonic-gate p->nCol++;
5837c478bd9Sstevel@tonic-gate }
5847c478bd9Sstevel@tonic-gate
5857c478bd9Sstevel@tonic-gate /*
5867c478bd9Sstevel@tonic-gate ** This routine is called by the parser while in the middle of
5877c478bd9Sstevel@tonic-gate ** parsing a CREATE TABLE statement. A "NOT NULL" constraint has
5887c478bd9Sstevel@tonic-gate ** been seen on a column. This routine sets the notNull flag on
5897c478bd9Sstevel@tonic-gate ** the column currently under construction.
5907c478bd9Sstevel@tonic-gate */
sqliteAddNotNull(Parse * pParse,int onError)5917c478bd9Sstevel@tonic-gate void sqliteAddNotNull(Parse *pParse, int onError){
5927c478bd9Sstevel@tonic-gate Table *p;
5937c478bd9Sstevel@tonic-gate int i;
5947c478bd9Sstevel@tonic-gate if( (p = pParse->pNewTable)==0 ) return;
5957c478bd9Sstevel@tonic-gate i = p->nCol-1;
5967c478bd9Sstevel@tonic-gate if( i>=0 ) p->aCol[i].notNull = onError;
5977c478bd9Sstevel@tonic-gate }
5987c478bd9Sstevel@tonic-gate
5997c478bd9Sstevel@tonic-gate /*
6007c478bd9Sstevel@tonic-gate ** This routine is called by the parser while in the middle of
6017c478bd9Sstevel@tonic-gate ** parsing a CREATE TABLE statement. The pFirst token is the first
6027c478bd9Sstevel@tonic-gate ** token in the sequence of tokens that describe the type of the
6037c478bd9Sstevel@tonic-gate ** column currently under construction. pLast is the last token
6047c478bd9Sstevel@tonic-gate ** in the sequence. Use this information to construct a string
6057c478bd9Sstevel@tonic-gate ** that contains the typename of the column and store that string
6067c478bd9Sstevel@tonic-gate ** in zType.
607*1da57d55SToomas Soome */
sqliteAddColumnType(Parse * pParse,Token * pFirst,Token * pLast)6087c478bd9Sstevel@tonic-gate void sqliteAddColumnType(Parse *pParse, Token *pFirst, Token *pLast){
6097c478bd9Sstevel@tonic-gate Table *p;
6107c478bd9Sstevel@tonic-gate int i, j;
6117c478bd9Sstevel@tonic-gate int n;
6127c478bd9Sstevel@tonic-gate char *z, **pz;
6137c478bd9Sstevel@tonic-gate Column *pCol;
6147c478bd9Sstevel@tonic-gate if( (p = pParse->pNewTable)==0 ) return;
6157c478bd9Sstevel@tonic-gate i = p->nCol-1;
6167c478bd9Sstevel@tonic-gate if( i<0 ) return;
6177c478bd9Sstevel@tonic-gate pCol = &p->aCol[i];
6187c478bd9Sstevel@tonic-gate pz = &pCol->zType;
6197c478bd9Sstevel@tonic-gate n = pLast->n + Addr(pLast->z) - Addr(pFirst->z);
6207c478bd9Sstevel@tonic-gate sqliteSetNString(pz, pFirst->z, n, 0);
6217c478bd9Sstevel@tonic-gate z = *pz;
6227c478bd9Sstevel@tonic-gate if( z==0 ) return;
6237c478bd9Sstevel@tonic-gate for(i=j=0; z[i]; i++){
6247c478bd9Sstevel@tonic-gate int c = z[i];
6257c478bd9Sstevel@tonic-gate if( isspace(c) ) continue;
6267c478bd9Sstevel@tonic-gate z[j++] = c;
6277c478bd9Sstevel@tonic-gate }
6287c478bd9Sstevel@tonic-gate z[j] = 0;
6297c478bd9Sstevel@tonic-gate if( pParse->db->file_format>=4 ){
6307c478bd9Sstevel@tonic-gate pCol->sortOrder = sqliteCollateType(z, n);
6317c478bd9Sstevel@tonic-gate }else{
6327c478bd9Sstevel@tonic-gate pCol->sortOrder = SQLITE_SO_NUM;
6337c478bd9Sstevel@tonic-gate }
6347c478bd9Sstevel@tonic-gate }
6357c478bd9Sstevel@tonic-gate
6367c478bd9Sstevel@tonic-gate /*
6377c478bd9Sstevel@tonic-gate ** The given token is the default value for the last column added to
6387c478bd9Sstevel@tonic-gate ** the table currently under construction. If "minusFlag" is true, it
6397c478bd9Sstevel@tonic-gate ** means the value token was preceded by a minus sign.
6407c478bd9Sstevel@tonic-gate **
6417c478bd9Sstevel@tonic-gate ** This routine is called by the parser while in the middle of
6427c478bd9Sstevel@tonic-gate ** parsing a CREATE TABLE statement.
6437c478bd9Sstevel@tonic-gate */
sqliteAddDefaultValue(Parse * pParse,Token * pVal,int minusFlag)6447c478bd9Sstevel@tonic-gate void sqliteAddDefaultValue(Parse *pParse, Token *pVal, int minusFlag){
6457c478bd9Sstevel@tonic-gate Table *p;
6467c478bd9Sstevel@tonic-gate int i;
6477c478bd9Sstevel@tonic-gate char **pz;
6487c478bd9Sstevel@tonic-gate if( (p = pParse->pNewTable)==0 ) return;
6497c478bd9Sstevel@tonic-gate i = p->nCol-1;
6507c478bd9Sstevel@tonic-gate if( i<0 ) return;
6517c478bd9Sstevel@tonic-gate pz = &p->aCol[i].zDflt;
6527c478bd9Sstevel@tonic-gate if( minusFlag ){
6537c478bd9Sstevel@tonic-gate sqliteSetNString(pz, "-", 1, pVal->z, pVal->n, 0);
6547c478bd9Sstevel@tonic-gate }else{
6557c478bd9Sstevel@tonic-gate sqliteSetNString(pz, pVal->z, pVal->n, 0);
6567c478bd9Sstevel@tonic-gate }
6577c478bd9Sstevel@tonic-gate sqliteDequote(*pz);
6587c478bd9Sstevel@tonic-gate }
6597c478bd9Sstevel@tonic-gate
6607c478bd9Sstevel@tonic-gate /*
661*1da57d55SToomas Soome ** Designate the PRIMARY KEY for the table. pList is a list of names
6627c478bd9Sstevel@tonic-gate ** of columns that form the primary key. If pList is NULL, then the
6637c478bd9Sstevel@tonic-gate ** most recently added column of the table is the primary key.
6647c478bd9Sstevel@tonic-gate **
6657c478bd9Sstevel@tonic-gate ** A table can have at most one primary key. If the table already has
6667c478bd9Sstevel@tonic-gate ** a primary key (and this is the second primary key) then create an
6677c478bd9Sstevel@tonic-gate ** error.
6687c478bd9Sstevel@tonic-gate **
6697c478bd9Sstevel@tonic-gate ** If the PRIMARY KEY is on a single column whose datatype is INTEGER,
6707c478bd9Sstevel@tonic-gate ** then we will try to use that column as the row id. (Exception:
6717c478bd9Sstevel@tonic-gate ** For backwards compatibility with older databases, do not do this
6727c478bd9Sstevel@tonic-gate ** if the file format version number is less than 1.) Set the Table.iPKey
6737c478bd9Sstevel@tonic-gate ** field of the table under construction to be the index of the
6747c478bd9Sstevel@tonic-gate ** INTEGER PRIMARY KEY column. Table.iPKey is set to -1 if there is
6757c478bd9Sstevel@tonic-gate ** no INTEGER PRIMARY KEY.
6767c478bd9Sstevel@tonic-gate **
6777c478bd9Sstevel@tonic-gate ** If the key is not an INTEGER PRIMARY KEY, then create a unique
6787c478bd9Sstevel@tonic-gate ** index for the key. No index is created for INTEGER PRIMARY KEYs.
6797c478bd9Sstevel@tonic-gate */
sqliteAddPrimaryKey(Parse * pParse,IdList * pList,int onError)6807c478bd9Sstevel@tonic-gate void sqliteAddPrimaryKey(Parse *pParse, IdList *pList, int onError){
6817c478bd9Sstevel@tonic-gate Table *pTab = pParse->pNewTable;
6827c478bd9Sstevel@tonic-gate char *zType = 0;
6837c478bd9Sstevel@tonic-gate int iCol = -1, i;
6847c478bd9Sstevel@tonic-gate if( pTab==0 ) goto primary_key_exit;
6857c478bd9Sstevel@tonic-gate if( pTab->hasPrimKey ){
686*1da57d55SToomas Soome sqliteErrorMsg(pParse,
6877c478bd9Sstevel@tonic-gate "table \"%s\" has more than one primary key", pTab->zName);
6887c478bd9Sstevel@tonic-gate goto primary_key_exit;
6897c478bd9Sstevel@tonic-gate }
6907c478bd9Sstevel@tonic-gate pTab->hasPrimKey = 1;
6917c478bd9Sstevel@tonic-gate if( pList==0 ){
6927c478bd9Sstevel@tonic-gate iCol = pTab->nCol - 1;
6937c478bd9Sstevel@tonic-gate pTab->aCol[iCol].isPrimKey = 1;
6947c478bd9Sstevel@tonic-gate }else{
6957c478bd9Sstevel@tonic-gate for(i=0; i<pList->nId; i++){
6967c478bd9Sstevel@tonic-gate for(iCol=0; iCol<pTab->nCol; iCol++){
6977c478bd9Sstevel@tonic-gate if( sqliteStrICmp(pList->a[i].zName, pTab->aCol[iCol].zName)==0 ) break;
6987c478bd9Sstevel@tonic-gate }
6997c478bd9Sstevel@tonic-gate if( iCol<pTab->nCol ) pTab->aCol[iCol].isPrimKey = 1;
7007c478bd9Sstevel@tonic-gate }
7017c478bd9Sstevel@tonic-gate if( pList->nId>1 ) iCol = -1;
7027c478bd9Sstevel@tonic-gate }
7037c478bd9Sstevel@tonic-gate if( iCol>=0 && iCol<pTab->nCol ){
7047c478bd9Sstevel@tonic-gate zType = pTab->aCol[iCol].zType;
7057c478bd9Sstevel@tonic-gate }
706*1da57d55SToomas Soome if( pParse->db->file_format>=1 &&
7077c478bd9Sstevel@tonic-gate zType && sqliteStrICmp(zType, "INTEGER")==0 ){
7087c478bd9Sstevel@tonic-gate pTab->iPKey = iCol;
7097c478bd9Sstevel@tonic-gate pTab->keyConf = onError;
7107c478bd9Sstevel@tonic-gate }else{
7117c478bd9Sstevel@tonic-gate sqliteCreateIndex(pParse, 0, 0, pList, onError, 0, 0);
7127c478bd9Sstevel@tonic-gate pList = 0;
7137c478bd9Sstevel@tonic-gate }
7147c478bd9Sstevel@tonic-gate
7157c478bd9Sstevel@tonic-gate primary_key_exit:
7167c478bd9Sstevel@tonic-gate sqliteIdListDelete(pList);
7177c478bd9Sstevel@tonic-gate return;
7187c478bd9Sstevel@tonic-gate }
7197c478bd9Sstevel@tonic-gate
7207c478bd9Sstevel@tonic-gate /*
7217c478bd9Sstevel@tonic-gate ** Return the appropriate collating type given a type name.
7227c478bd9Sstevel@tonic-gate **
7237c478bd9Sstevel@tonic-gate ** The collation type is text (SQLITE_SO_TEXT) if the type
7247c478bd9Sstevel@tonic-gate ** name contains the character stream "text" or "blob" or
7257c478bd9Sstevel@tonic-gate ** "clob". Any other type name is collated as numeric
7267c478bd9Sstevel@tonic-gate ** (SQLITE_SO_NUM).
7277c478bd9Sstevel@tonic-gate */
sqliteCollateType(const char * zType,int nType)7287c478bd9Sstevel@tonic-gate int sqliteCollateType(const char *zType, int nType){
7297c478bd9Sstevel@tonic-gate int i;
7307c478bd9Sstevel@tonic-gate for(i=0; i<nType-3; i++){
7317c478bd9Sstevel@tonic-gate int c = *(zType++) | 0x60;
7327c478bd9Sstevel@tonic-gate if( (c=='b' || c=='c') && sqliteStrNICmp(zType, "lob", 3)==0 ){
7337c478bd9Sstevel@tonic-gate return SQLITE_SO_TEXT;
7347c478bd9Sstevel@tonic-gate }
7357c478bd9Sstevel@tonic-gate if( c=='c' && sqliteStrNICmp(zType, "har", 3)==0 ){
7367c478bd9Sstevel@tonic-gate return SQLITE_SO_TEXT;
7377c478bd9Sstevel@tonic-gate }
7387c478bd9Sstevel@tonic-gate if( c=='t' && sqliteStrNICmp(zType, "ext", 3)==0 ){
7397c478bd9Sstevel@tonic-gate return SQLITE_SO_TEXT;
7407c478bd9Sstevel@tonic-gate }
7417c478bd9Sstevel@tonic-gate }
7427c478bd9Sstevel@tonic-gate return SQLITE_SO_NUM;
7437c478bd9Sstevel@tonic-gate }
7447c478bd9Sstevel@tonic-gate
7457c478bd9Sstevel@tonic-gate /*
7467c478bd9Sstevel@tonic-gate ** This routine is called by the parser while in the middle of
7477c478bd9Sstevel@tonic-gate ** parsing a CREATE TABLE statement. A "COLLATE" clause has
7487c478bd9Sstevel@tonic-gate ** been seen on a column. This routine sets the Column.sortOrder on
7497c478bd9Sstevel@tonic-gate ** the column currently under construction.
7507c478bd9Sstevel@tonic-gate */
sqliteAddCollateType(Parse * pParse,int collType)7517c478bd9Sstevel@tonic-gate void sqliteAddCollateType(Parse *pParse, int collType){
7527c478bd9Sstevel@tonic-gate Table *p;
7537c478bd9Sstevel@tonic-gate int i;
7547c478bd9Sstevel@tonic-gate if( (p = pParse->pNewTable)==0 ) return;
7557c478bd9Sstevel@tonic-gate i = p->nCol-1;
7567c478bd9Sstevel@tonic-gate if( i>=0 ) p->aCol[i].sortOrder = collType;
7577c478bd9Sstevel@tonic-gate }
7587c478bd9Sstevel@tonic-gate
7597c478bd9Sstevel@tonic-gate /*
7607c478bd9Sstevel@tonic-gate ** Come up with a new random value for the schema cookie. Make sure
7617c478bd9Sstevel@tonic-gate ** the new value is different from the old.
7627c478bd9Sstevel@tonic-gate **
7637c478bd9Sstevel@tonic-gate ** The schema cookie is used to determine when the schema for the
7647c478bd9Sstevel@tonic-gate ** database changes. After each schema change, the cookie value
7657c478bd9Sstevel@tonic-gate ** changes. When a process first reads the schema it records the
7667c478bd9Sstevel@tonic-gate ** cookie. Thereafter, whenever it goes to access the database,
7677c478bd9Sstevel@tonic-gate ** it checks the cookie to make sure the schema has not changed
7687c478bd9Sstevel@tonic-gate ** since it was last read.
7697c478bd9Sstevel@tonic-gate **
7707c478bd9Sstevel@tonic-gate ** This plan is not completely bullet-proof. It is possible for
7717c478bd9Sstevel@tonic-gate ** the schema to change multiple times and for the cookie to be
7727c478bd9Sstevel@tonic-gate ** set back to prior value. But schema changes are infrequent
7737c478bd9Sstevel@tonic-gate ** and the probability of hitting the same cookie value is only
7747c478bd9Sstevel@tonic-gate ** 1 chance in 2^32. So we're safe enough.
7757c478bd9Sstevel@tonic-gate */
sqliteChangeCookie(sqlite * db,Vdbe * v)7767c478bd9Sstevel@tonic-gate void sqliteChangeCookie(sqlite *db, Vdbe *v){
7777c478bd9Sstevel@tonic-gate if( db->next_cookie==db->aDb[0].schema_cookie ){
7787c478bd9Sstevel@tonic-gate unsigned char r;
7797c478bd9Sstevel@tonic-gate sqliteRandomness(1, &r);
7807c478bd9Sstevel@tonic-gate db->next_cookie = db->aDb[0].schema_cookie + r + 1;
7817c478bd9Sstevel@tonic-gate db->flags |= SQLITE_InternChanges;
7827c478bd9Sstevel@tonic-gate sqliteVdbeAddOp(v, OP_Integer, db->next_cookie, 0);
7837c478bd9Sstevel@tonic-gate sqliteVdbeAddOp(v, OP_SetCookie, 0, 0);
7847c478bd9Sstevel@tonic-gate }
7857c478bd9Sstevel@tonic-gate }
7867c478bd9Sstevel@tonic-gate
7877c478bd9Sstevel@tonic-gate /*
7887c478bd9Sstevel@tonic-gate ** Measure the number of characters needed to output the given
7897c478bd9Sstevel@tonic-gate ** identifier. The number returned includes any quotes used
7907c478bd9Sstevel@tonic-gate ** but does not include the null terminator.
7917c478bd9Sstevel@tonic-gate */
identLength(const char * z)7927c478bd9Sstevel@tonic-gate static int identLength(const char *z){
7937c478bd9Sstevel@tonic-gate int n;
7947c478bd9Sstevel@tonic-gate int needQuote = 0;
7957c478bd9Sstevel@tonic-gate for(n=0; *z; n++, z++){
7967c478bd9Sstevel@tonic-gate if( *z=='\'' ){ n++; needQuote=1; }
7977c478bd9Sstevel@tonic-gate }
7987c478bd9Sstevel@tonic-gate return n + needQuote*2;
7997c478bd9Sstevel@tonic-gate }
8007c478bd9Sstevel@tonic-gate
8017c478bd9Sstevel@tonic-gate /*
8027c478bd9Sstevel@tonic-gate ** Write an identifier onto the end of the given string. Add
8037c478bd9Sstevel@tonic-gate ** quote characters as needed.
8047c478bd9Sstevel@tonic-gate */
identPut(char * z,int * pIdx,char * zIdent)8057c478bd9Sstevel@tonic-gate static void identPut(char *z, int *pIdx, char *zIdent){
8067c478bd9Sstevel@tonic-gate int i, j, needQuote;
8077c478bd9Sstevel@tonic-gate i = *pIdx;
8087c478bd9Sstevel@tonic-gate for(j=0; zIdent[j]; j++){
8097c478bd9Sstevel@tonic-gate if( !isalnum(zIdent[j]) && zIdent[j]!='_' ) break;
8107c478bd9Sstevel@tonic-gate }
8117c478bd9Sstevel@tonic-gate needQuote = zIdent[j]!=0 || isdigit(zIdent[0])
8127c478bd9Sstevel@tonic-gate || sqliteKeywordCode(zIdent, j)!=TK_ID;
8137c478bd9Sstevel@tonic-gate if( needQuote ) z[i++] = '\'';
8147c478bd9Sstevel@tonic-gate for(j=0; zIdent[j]; j++){
8157c478bd9Sstevel@tonic-gate z[i++] = zIdent[j];
8167c478bd9Sstevel@tonic-gate if( zIdent[j]=='\'' ) z[i++] = '\'';
8177c478bd9Sstevel@tonic-gate }
8187c478bd9Sstevel@tonic-gate if( needQuote ) z[i++] = '\'';
8197c478bd9Sstevel@tonic-gate z[i] = 0;
8207c478bd9Sstevel@tonic-gate *pIdx = i;
8217c478bd9Sstevel@tonic-gate }
8227c478bd9Sstevel@tonic-gate
8237c478bd9Sstevel@tonic-gate /*
8247c478bd9Sstevel@tonic-gate ** Generate a CREATE TABLE statement appropriate for the given
8257c478bd9Sstevel@tonic-gate ** table. Memory to hold the text of the statement is obtained
8267c478bd9Sstevel@tonic-gate ** from sqliteMalloc() and must be freed by the calling function.
8277c478bd9Sstevel@tonic-gate */
createTableStmt(Table * p)8287c478bd9Sstevel@tonic-gate static char *createTableStmt(Table *p){
8297c478bd9Sstevel@tonic-gate int i, k, n;
8307c478bd9Sstevel@tonic-gate char *zStmt;
8317c478bd9Sstevel@tonic-gate char *zSep, *zSep2, *zEnd;
8327c478bd9Sstevel@tonic-gate n = 0;
8337c478bd9Sstevel@tonic-gate for(i=0; i<p->nCol; i++){
8347c478bd9Sstevel@tonic-gate n += identLength(p->aCol[i].zName);
8357c478bd9Sstevel@tonic-gate }
8367c478bd9Sstevel@tonic-gate n += identLength(p->zName);
8377c478bd9Sstevel@tonic-gate if( n<40 ){
8387c478bd9Sstevel@tonic-gate zSep = "";
8397c478bd9Sstevel@tonic-gate zSep2 = ",";
8407c478bd9Sstevel@tonic-gate zEnd = ")";
8417c478bd9Sstevel@tonic-gate }else{
8427c478bd9Sstevel@tonic-gate zSep = "\n ";
8437c478bd9Sstevel@tonic-gate zSep2 = ",\n ";
8447c478bd9Sstevel@tonic-gate zEnd = "\n)";
8457c478bd9Sstevel@tonic-gate }
8467c478bd9Sstevel@tonic-gate n += 35 + 6*p->nCol;
8477c478bd9Sstevel@tonic-gate zStmt = sqliteMallocRaw( n );
8487c478bd9Sstevel@tonic-gate if( zStmt==0 ) return 0;
8497c478bd9Sstevel@tonic-gate strcpy(zStmt, p->iDb==1 ? "CREATE TEMP TABLE " : "CREATE TABLE ");
8507c478bd9Sstevel@tonic-gate k = strlen(zStmt);
8517c478bd9Sstevel@tonic-gate identPut(zStmt, &k, p->zName);
8527c478bd9Sstevel@tonic-gate zStmt[k++] = '(';
8537c478bd9Sstevel@tonic-gate for(i=0; i<p->nCol; i++){
8547c478bd9Sstevel@tonic-gate strcpy(&zStmt[k], zSep);
8557c478bd9Sstevel@tonic-gate k += strlen(&zStmt[k]);
8567c478bd9Sstevel@tonic-gate zSep = zSep2;
8577c478bd9Sstevel@tonic-gate identPut(zStmt, &k, p->aCol[i].zName);
8587c478bd9Sstevel@tonic-gate }
8597c478bd9Sstevel@tonic-gate strcpy(&zStmt[k], zEnd);
8607c478bd9Sstevel@tonic-gate return zStmt;
8617c478bd9Sstevel@tonic-gate }
8627c478bd9Sstevel@tonic-gate
8637c478bd9Sstevel@tonic-gate /*
8647c478bd9Sstevel@tonic-gate ** This routine is called to report the final ")" that terminates
8657c478bd9Sstevel@tonic-gate ** a CREATE TABLE statement.
8667c478bd9Sstevel@tonic-gate **
8677c478bd9Sstevel@tonic-gate ** The table structure that other action routines have been building
8687c478bd9Sstevel@tonic-gate ** is added to the internal hash tables, assuming no errors have
8697c478bd9Sstevel@tonic-gate ** occurred.
8707c478bd9Sstevel@tonic-gate **
8717c478bd9Sstevel@tonic-gate ** An entry for the table is made in the master table on disk, unless
8727c478bd9Sstevel@tonic-gate ** this is a temporary table or db->init.busy==1. When db->init.busy==1
8737c478bd9Sstevel@tonic-gate ** it means we are reading the sqlite_master table because we just
8747c478bd9Sstevel@tonic-gate ** connected to the database or because the sqlite_master table has
8757c478bd9Sstevel@tonic-gate ** recently changes, so the entry for this table already exists in
8767c478bd9Sstevel@tonic-gate ** the sqlite_master table. We do not want to create it again.
8777c478bd9Sstevel@tonic-gate **
8787c478bd9Sstevel@tonic-gate ** If the pSelect argument is not NULL, it means that this routine
879*1da57d55SToomas Soome ** was called to create a table generated from a
8807c478bd9Sstevel@tonic-gate ** "CREATE TABLE ... AS SELECT ..." statement. The column names of
8817c478bd9Sstevel@tonic-gate ** the new table will match the result set of the SELECT.
8827c478bd9Sstevel@tonic-gate */
sqliteEndTable(Parse * pParse,Token * pEnd,Select * pSelect)8837c478bd9Sstevel@tonic-gate void sqliteEndTable(Parse *pParse, Token *pEnd, Select *pSelect){
8847c478bd9Sstevel@tonic-gate Table *p;
8857c478bd9Sstevel@tonic-gate sqlite *db = pParse->db;
8867c478bd9Sstevel@tonic-gate
8877c478bd9Sstevel@tonic-gate if( (pEnd==0 && pSelect==0) || pParse->nErr || sqlite_malloc_failed ) return;
8887c478bd9Sstevel@tonic-gate p = pParse->pNewTable;
8897c478bd9Sstevel@tonic-gate if( p==0 ) return;
8907c478bd9Sstevel@tonic-gate
8917c478bd9Sstevel@tonic-gate /* If the table is generated from a SELECT, then construct the
8927c478bd9Sstevel@tonic-gate ** list of columns and the text of the table.
8937c478bd9Sstevel@tonic-gate */
8947c478bd9Sstevel@tonic-gate if( pSelect ){
8957c478bd9Sstevel@tonic-gate Table *pSelTab = sqliteResultSetOfSelect(pParse, 0, pSelect);
8967c478bd9Sstevel@tonic-gate if( pSelTab==0 ) return;
8977c478bd9Sstevel@tonic-gate assert( p->aCol==0 );
8987c478bd9Sstevel@tonic-gate p->nCol = pSelTab->nCol;
8997c478bd9Sstevel@tonic-gate p->aCol = pSelTab->aCol;
9007c478bd9Sstevel@tonic-gate pSelTab->nCol = 0;
9017c478bd9Sstevel@tonic-gate pSelTab->aCol = 0;
9027c478bd9Sstevel@tonic-gate sqliteDeleteTable(0, pSelTab);
9037c478bd9Sstevel@tonic-gate }
9047c478bd9Sstevel@tonic-gate
9057c478bd9Sstevel@tonic-gate /* If the db->init.busy is 1 it means we are reading the SQL off the
9067c478bd9Sstevel@tonic-gate ** "sqlite_master" or "sqlite_temp_master" table on the disk.
9077c478bd9Sstevel@tonic-gate ** So do not write to the disk again. Extract the root page number
9087c478bd9Sstevel@tonic-gate ** for the table from the db->init.newTnum field. (The page number
9097c478bd9Sstevel@tonic-gate ** should have been put there by the sqliteOpenCb routine.)
9107c478bd9Sstevel@tonic-gate */
9117c478bd9Sstevel@tonic-gate if( db->init.busy ){
9127c478bd9Sstevel@tonic-gate p->tnum = db->init.newTnum;
9137c478bd9Sstevel@tonic-gate }
9147c478bd9Sstevel@tonic-gate
9157c478bd9Sstevel@tonic-gate /* If not initializing, then create a record for the new table
9167c478bd9Sstevel@tonic-gate ** in the SQLITE_MASTER table of the database. The record number
9177c478bd9Sstevel@tonic-gate ** for the new table entry should already be on the stack.
9187c478bd9Sstevel@tonic-gate **
9197c478bd9Sstevel@tonic-gate ** If this is a TEMPORARY table, write the entry into the auxiliary
9207c478bd9Sstevel@tonic-gate ** file instead of into the main database file.
9217c478bd9Sstevel@tonic-gate */
9227c478bd9Sstevel@tonic-gate if( !db->init.busy ){
9237c478bd9Sstevel@tonic-gate int n;
9247c478bd9Sstevel@tonic-gate Vdbe *v;
9257c478bd9Sstevel@tonic-gate
9267c478bd9Sstevel@tonic-gate v = sqliteGetVdbe(pParse);
9277c478bd9Sstevel@tonic-gate if( v==0 ) return;
9287c478bd9Sstevel@tonic-gate if( p->pSelect==0 ){
9297c478bd9Sstevel@tonic-gate /* A regular table */
9307c478bd9Sstevel@tonic-gate sqliteVdbeOp3(v, OP_CreateTable, 0, p->iDb, (char*)&p->tnum, P3_POINTER);
9317c478bd9Sstevel@tonic-gate }else{
9327c478bd9Sstevel@tonic-gate /* A view */
9337c478bd9Sstevel@tonic-gate sqliteVdbeAddOp(v, OP_Integer, 0, 0);
9347c478bd9Sstevel@tonic-gate }
9357c478bd9Sstevel@tonic-gate p->tnum = 0;
9367c478bd9Sstevel@tonic-gate sqliteVdbeAddOp(v, OP_Pull, 1, 0);
9377c478bd9Sstevel@tonic-gate sqliteVdbeOp3(v, OP_String, 0, 0, p->pSelect==0?"table":"view", P3_STATIC);
9387c478bd9Sstevel@tonic-gate sqliteVdbeOp3(v, OP_String, 0, 0, p->zName, 0);
9397c478bd9Sstevel@tonic-gate sqliteVdbeOp3(v, OP_String, 0, 0, p->zName, 0);
9407c478bd9Sstevel@tonic-gate sqliteVdbeAddOp(v, OP_Dup, 4, 0);
9417c478bd9Sstevel@tonic-gate sqliteVdbeAddOp(v, OP_String, 0, 0);
9427c478bd9Sstevel@tonic-gate if( pSelect ){
9437c478bd9Sstevel@tonic-gate char *z = createTableStmt(p);
9447c478bd9Sstevel@tonic-gate n = z ? strlen(z) : 0;
9457c478bd9Sstevel@tonic-gate sqliteVdbeChangeP3(v, -1, z, n);
9467c478bd9Sstevel@tonic-gate sqliteFree(z);
9477c478bd9Sstevel@tonic-gate }else{
9487c478bd9Sstevel@tonic-gate assert( pEnd!=0 );
9497c478bd9Sstevel@tonic-gate n = Addr(pEnd->z) - Addr(pParse->sFirstToken.z) + 1;
9507c478bd9Sstevel@tonic-gate sqliteVdbeChangeP3(v, -1, pParse->sFirstToken.z, n);
9517c478bd9Sstevel@tonic-gate }
9527c478bd9Sstevel@tonic-gate sqliteVdbeAddOp(v, OP_MakeRecord, 5, 0);
9537c478bd9Sstevel@tonic-gate sqliteVdbeAddOp(v, OP_PutIntKey, 0, 0);
9547c478bd9Sstevel@tonic-gate if( !p->iDb ){
9557c478bd9Sstevel@tonic-gate sqliteChangeCookie(db, v);
9567c478bd9Sstevel@tonic-gate }
9577c478bd9Sstevel@tonic-gate sqliteVdbeAddOp(v, OP_Close, 0, 0);
9587c478bd9Sstevel@tonic-gate if( pSelect ){
9597c478bd9Sstevel@tonic-gate sqliteVdbeAddOp(v, OP_Integer, p->iDb, 0);
9607c478bd9Sstevel@tonic-gate sqliteVdbeAddOp(v, OP_OpenWrite, 1, 0);
9617c478bd9Sstevel@tonic-gate pParse->nTab = 2;
9627c478bd9Sstevel@tonic-gate sqliteSelect(pParse, pSelect, SRT_Table, 1, 0, 0, 0);
9637c478bd9Sstevel@tonic-gate }
9647c478bd9Sstevel@tonic-gate sqliteEndWriteOperation(pParse);
9657c478bd9Sstevel@tonic-gate }
9667c478bd9Sstevel@tonic-gate
9677c478bd9Sstevel@tonic-gate /* Add the table to the in-memory representation of the database.
9687c478bd9Sstevel@tonic-gate */
9697c478bd9Sstevel@tonic-gate if( pParse->explain==0 && pParse->nErr==0 ){
9707c478bd9Sstevel@tonic-gate Table *pOld;
9717c478bd9Sstevel@tonic-gate FKey *pFKey;
972*1da57d55SToomas Soome pOld = sqliteHashInsert(&db->aDb[p->iDb].tblHash,
9737c478bd9Sstevel@tonic-gate p->zName, strlen(p->zName)+1, p);
9747c478bd9Sstevel@tonic-gate if( pOld ){
9757c478bd9Sstevel@tonic-gate assert( p==pOld ); /* Malloc must have failed inside HashInsert() */
9767c478bd9Sstevel@tonic-gate return;
9777c478bd9Sstevel@tonic-gate }
9787c478bd9Sstevel@tonic-gate for(pFKey=p->pFKey; pFKey; pFKey=pFKey->pNextFrom){
9797c478bd9Sstevel@tonic-gate int nTo = strlen(pFKey->zTo) + 1;
9807c478bd9Sstevel@tonic-gate pFKey->pNextTo = sqliteHashFind(&db->aDb[p->iDb].aFKey, pFKey->zTo, nTo);
9817c478bd9Sstevel@tonic-gate sqliteHashInsert(&db->aDb[p->iDb].aFKey, pFKey->zTo, nTo, pFKey);
9827c478bd9Sstevel@tonic-gate }
9837c478bd9Sstevel@tonic-gate pParse->pNewTable = 0;
9847c478bd9Sstevel@tonic-gate db->nTable++;
9857c478bd9Sstevel@tonic-gate db->flags |= SQLITE_InternChanges;
9867c478bd9Sstevel@tonic-gate }
9877c478bd9Sstevel@tonic-gate }
9887c478bd9Sstevel@tonic-gate
9897c478bd9Sstevel@tonic-gate /*
9907c478bd9Sstevel@tonic-gate ** The parser calls this routine in order to create a new VIEW
9917c478bd9Sstevel@tonic-gate */
sqliteCreateView(Parse * pParse,Token * pBegin,Token * pName,Select * pSelect,int isTemp)9927c478bd9Sstevel@tonic-gate void sqliteCreateView(
9937c478bd9Sstevel@tonic-gate Parse *pParse, /* The parsing context */
9947c478bd9Sstevel@tonic-gate Token *pBegin, /* The CREATE token that begins the statement */
9957c478bd9Sstevel@tonic-gate Token *pName, /* The token that holds the name of the view */
9967c478bd9Sstevel@tonic-gate Select *pSelect, /* A SELECT statement that will become the new view */
9977c478bd9Sstevel@tonic-gate int isTemp /* TRUE for a TEMPORARY view */
9987c478bd9Sstevel@tonic-gate ){
9997c478bd9Sstevel@tonic-gate Table *p;
10007c478bd9Sstevel@tonic-gate int n;
10017c478bd9Sstevel@tonic-gate const char *z;
10027c478bd9Sstevel@tonic-gate Token sEnd;
10037c478bd9Sstevel@tonic-gate DbFixer sFix;
10047c478bd9Sstevel@tonic-gate
10057c478bd9Sstevel@tonic-gate sqliteStartTable(pParse, pBegin, pName, isTemp, 1);
10067c478bd9Sstevel@tonic-gate p = pParse->pNewTable;
10077c478bd9Sstevel@tonic-gate if( p==0 || pParse->nErr ){
10087c478bd9Sstevel@tonic-gate sqliteSelectDelete(pSelect);
10097c478bd9Sstevel@tonic-gate return;
10107c478bd9Sstevel@tonic-gate }
10117c478bd9Sstevel@tonic-gate if( sqliteFixInit(&sFix, pParse, p->iDb, "view", pName)
10127c478bd9Sstevel@tonic-gate && sqliteFixSelect(&sFix, pSelect)
10137c478bd9Sstevel@tonic-gate ){
10147c478bd9Sstevel@tonic-gate sqliteSelectDelete(pSelect);
10157c478bd9Sstevel@tonic-gate return;
10167c478bd9Sstevel@tonic-gate }
10177c478bd9Sstevel@tonic-gate
10187c478bd9Sstevel@tonic-gate /* Make a copy of the entire SELECT statement that defines the view.
10197c478bd9Sstevel@tonic-gate ** This will force all the Expr.token.z values to be dynamically
10207c478bd9Sstevel@tonic-gate ** allocated rather than point to the input string - which means that
10217c478bd9Sstevel@tonic-gate ** they will persist after the current sqlite_exec() call returns.
10227c478bd9Sstevel@tonic-gate */
10237c478bd9Sstevel@tonic-gate p->pSelect = sqliteSelectDup(pSelect);
10247c478bd9Sstevel@tonic-gate sqliteSelectDelete(pSelect);
10257c478bd9Sstevel@tonic-gate if( !pParse->db->init.busy ){
10267c478bd9Sstevel@tonic-gate sqliteViewGetColumnNames(pParse, p);
10277c478bd9Sstevel@tonic-gate }
10287c478bd9Sstevel@tonic-gate
10297c478bd9Sstevel@tonic-gate /* Locate the end of the CREATE VIEW statement. Make sEnd point to
10307c478bd9Sstevel@tonic-gate ** the end.
10317c478bd9Sstevel@tonic-gate */
10327c478bd9Sstevel@tonic-gate sEnd = pParse->sLastToken;
10337c478bd9Sstevel@tonic-gate if( sEnd.z[0]!=0 && sEnd.z[0]!=';' ){
10347c478bd9Sstevel@tonic-gate sEnd.z += sEnd.n;
10357c478bd9Sstevel@tonic-gate }
10367c478bd9Sstevel@tonic-gate sEnd.n = 0;
10377c478bd9Sstevel@tonic-gate n = sEnd.z - pBegin->z;
10387c478bd9Sstevel@tonic-gate z = pBegin->z;
10397c478bd9Sstevel@tonic-gate while( n>0 && (z[n-1]==';' || isspace(z[n-1])) ){ n--; }
10407c478bd9Sstevel@tonic-gate sEnd.z = &z[n-1];
10417c478bd9Sstevel@tonic-gate sEnd.n = 1;
10427c478bd9Sstevel@tonic-gate
10437c478bd9Sstevel@tonic-gate /* Use sqliteEndTable() to add the view to the SQLITE_MASTER table */
10447c478bd9Sstevel@tonic-gate sqliteEndTable(pParse, &sEnd, 0);
10457c478bd9Sstevel@tonic-gate return;
10467c478bd9Sstevel@tonic-gate }
10477c478bd9Sstevel@tonic-gate
10487c478bd9Sstevel@tonic-gate /*
10497c478bd9Sstevel@tonic-gate ** The Table structure pTable is really a VIEW. Fill in the names of
10507c478bd9Sstevel@tonic-gate ** the columns of the view in the pTable structure. Return the number
10517c478bd9Sstevel@tonic-gate ** of errors. If an error is seen leave an error message in pParse->zErrMsg.
10527c478bd9Sstevel@tonic-gate */
sqliteViewGetColumnNames(Parse * pParse,Table * pTable)10537c478bd9Sstevel@tonic-gate int sqliteViewGetColumnNames(Parse *pParse, Table *pTable){
10547c478bd9Sstevel@tonic-gate ExprList *pEList;
10557c478bd9Sstevel@tonic-gate Select *pSel;
10567c478bd9Sstevel@tonic-gate Table *pSelTab;
10577c478bd9Sstevel@tonic-gate int nErr = 0;
10587c478bd9Sstevel@tonic-gate
10597c478bd9Sstevel@tonic-gate assert( pTable );
10607c478bd9Sstevel@tonic-gate
10617c478bd9Sstevel@tonic-gate /* A positive nCol means the columns names for this view are
10627c478bd9Sstevel@tonic-gate ** already known.
10637c478bd9Sstevel@tonic-gate */
10647c478bd9Sstevel@tonic-gate if( pTable->nCol>0 ) return 0;
10657c478bd9Sstevel@tonic-gate
10667c478bd9Sstevel@tonic-gate /* A negative nCol is a special marker meaning that we are currently
10677c478bd9Sstevel@tonic-gate ** trying to compute the column names. If we enter this routine with
10687c478bd9Sstevel@tonic-gate ** a negative nCol, it means two or more views form a loop, like this:
10697c478bd9Sstevel@tonic-gate **
10707c478bd9Sstevel@tonic-gate ** CREATE VIEW one AS SELECT * FROM two;
10717c478bd9Sstevel@tonic-gate ** CREATE VIEW two AS SELECT * FROM one;
10727c478bd9Sstevel@tonic-gate **
10737c478bd9Sstevel@tonic-gate ** Actually, this error is caught previously and so the following test
10747c478bd9Sstevel@tonic-gate ** should always fail. But we will leave it in place just to be safe.
10757c478bd9Sstevel@tonic-gate */
10767c478bd9Sstevel@tonic-gate if( pTable->nCol<0 ){
10777c478bd9Sstevel@tonic-gate sqliteErrorMsg(pParse, "view %s is circularly defined", pTable->zName);
10787c478bd9Sstevel@tonic-gate return 1;
10797c478bd9Sstevel@tonic-gate }
10807c478bd9Sstevel@tonic-gate
10817c478bd9Sstevel@tonic-gate /* If we get this far, it means we need to compute the table names.
10827c478bd9Sstevel@tonic-gate */
10837c478bd9Sstevel@tonic-gate assert( pTable->pSelect ); /* If nCol==0, then pTable must be a VIEW */
10847c478bd9Sstevel@tonic-gate pSel = pTable->pSelect;
10857c478bd9Sstevel@tonic-gate
10867c478bd9Sstevel@tonic-gate /* Note that the call to sqliteResultSetOfSelect() will expand any
10877c478bd9Sstevel@tonic-gate ** "*" elements in this list. But we will need to restore the list
10887c478bd9Sstevel@tonic-gate ** back to its original configuration afterwards, so we save a copy of
10897c478bd9Sstevel@tonic-gate ** the original in pEList.
10907c478bd9Sstevel@tonic-gate */
10917c478bd9Sstevel@tonic-gate pEList = pSel->pEList;
10927c478bd9Sstevel@tonic-gate pSel->pEList = sqliteExprListDup(pEList);
10937c478bd9Sstevel@tonic-gate if( pSel->pEList==0 ){
10947c478bd9Sstevel@tonic-gate pSel->pEList = pEList;
10957c478bd9Sstevel@tonic-gate return 1; /* Malloc failed */
10967c478bd9Sstevel@tonic-gate }
10977c478bd9Sstevel@tonic-gate pTable->nCol = -1;
10987c478bd9Sstevel@tonic-gate pSelTab = sqliteResultSetOfSelect(pParse, 0, pSel);
10997c478bd9Sstevel@tonic-gate if( pSelTab ){
11007c478bd9Sstevel@tonic-gate assert( pTable->aCol==0 );
11017c478bd9Sstevel@tonic-gate pTable->nCol = pSelTab->nCol;
11027c478bd9Sstevel@tonic-gate pTable->aCol = pSelTab->aCol;
11037c478bd9Sstevel@tonic-gate pSelTab->nCol = 0;
11047c478bd9Sstevel@tonic-gate pSelTab->aCol = 0;
11057c478bd9Sstevel@tonic-gate sqliteDeleteTable(0, pSelTab);
11067c478bd9Sstevel@tonic-gate DbSetProperty(pParse->db, pTable->iDb, DB_UnresetViews);
11077c478bd9Sstevel@tonic-gate }else{
11087c478bd9Sstevel@tonic-gate pTable->nCol = 0;
11097c478bd9Sstevel@tonic-gate nErr++;
11107c478bd9Sstevel@tonic-gate }
11117c478bd9Sstevel@tonic-gate sqliteSelectUnbind(pSel);
11127c478bd9Sstevel@tonic-gate sqliteExprListDelete(pSel->pEList);
11137c478bd9Sstevel@tonic-gate pSel->pEList = pEList;
1114*1da57d55SToomas Soome return nErr;
11157c478bd9Sstevel@tonic-gate }
11167c478bd9Sstevel@tonic-gate
11177c478bd9Sstevel@tonic-gate /*
11187c478bd9Sstevel@tonic-gate ** Clear the column names from the VIEW pTable.
11197c478bd9Sstevel@tonic-gate **
11207c478bd9Sstevel@tonic-gate ** This routine is called whenever any other table or view is modified.
11217c478bd9Sstevel@tonic-gate ** The view passed into this routine might depend directly or indirectly
11227c478bd9Sstevel@tonic-gate ** on the modified or deleted table so we need to clear the old column
11237c478bd9Sstevel@tonic-gate ** names so that they will be recomputed.
11247c478bd9Sstevel@tonic-gate */
sqliteViewResetColumnNames(Table * pTable)11257c478bd9Sstevel@tonic-gate static void sqliteViewResetColumnNames(Table *pTable){
11267c478bd9Sstevel@tonic-gate int i;
11277c478bd9Sstevel@tonic-gate Column *pCol;
11287c478bd9Sstevel@tonic-gate assert( pTable!=0 && pTable->pSelect!=0 );
11297c478bd9Sstevel@tonic-gate for(i=0, pCol=pTable->aCol; i<pTable->nCol; i++, pCol++){
11307c478bd9Sstevel@tonic-gate sqliteFree(pCol->zName);
11317c478bd9Sstevel@tonic-gate sqliteFree(pCol->zDflt);
11327c478bd9Sstevel@tonic-gate sqliteFree(pCol->zType);
11337c478bd9Sstevel@tonic-gate }
11347c478bd9Sstevel@tonic-gate sqliteFree(pTable->aCol);
11357c478bd9Sstevel@tonic-gate pTable->aCol = 0;
11367c478bd9Sstevel@tonic-gate pTable->nCol = 0;
11377c478bd9Sstevel@tonic-gate }
11387c478bd9Sstevel@tonic-gate
11397c478bd9Sstevel@tonic-gate /*
11407c478bd9Sstevel@tonic-gate ** Clear the column names from every VIEW in database idx.
11417c478bd9Sstevel@tonic-gate */
sqliteViewResetAll(sqlite * db,int idx)11427c478bd9Sstevel@tonic-gate static void sqliteViewResetAll(sqlite *db, int idx){
11437c478bd9Sstevel@tonic-gate HashElem *i;
11447c478bd9Sstevel@tonic-gate if( !DbHasProperty(db, idx, DB_UnresetViews) ) return;
11457c478bd9Sstevel@tonic-gate for(i=sqliteHashFirst(&db->aDb[idx].tblHash); i; i=sqliteHashNext(i)){
11467c478bd9Sstevel@tonic-gate Table *pTab = sqliteHashData(i);
11477c478bd9Sstevel@tonic-gate if( pTab->pSelect ){
11487c478bd9Sstevel@tonic-gate sqliteViewResetColumnNames(pTab);
11497c478bd9Sstevel@tonic-gate }
11507c478bd9Sstevel@tonic-gate }
11517c478bd9Sstevel@tonic-gate DbClearProperty(db, idx, DB_UnresetViews);
11527c478bd9Sstevel@tonic-gate }
11537c478bd9Sstevel@tonic-gate
11547c478bd9Sstevel@tonic-gate /*
11557c478bd9Sstevel@tonic-gate ** Given a token, look up a table with that name. If not found, leave
11567c478bd9Sstevel@tonic-gate ** an error for the parser to find and return NULL.
11577c478bd9Sstevel@tonic-gate */
sqliteTableFromToken(Parse * pParse,Token * pTok)11587c478bd9Sstevel@tonic-gate Table *sqliteTableFromToken(Parse *pParse, Token *pTok){
11597c478bd9Sstevel@tonic-gate char *zName;
11607c478bd9Sstevel@tonic-gate Table *pTab;
11617c478bd9Sstevel@tonic-gate zName = sqliteTableNameFromToken(pTok);
11627c478bd9Sstevel@tonic-gate if( zName==0 ) return 0;
11637c478bd9Sstevel@tonic-gate pTab = sqliteFindTable(pParse->db, zName, 0);
11647c478bd9Sstevel@tonic-gate sqliteFree(zName);
11657c478bd9Sstevel@tonic-gate if( pTab==0 ){
11667c478bd9Sstevel@tonic-gate sqliteErrorMsg(pParse, "no such table: %T", pTok);
11677c478bd9Sstevel@tonic-gate }
11687c478bd9Sstevel@tonic-gate return pTab;
11697c478bd9Sstevel@tonic-gate }
11707c478bd9Sstevel@tonic-gate
11717c478bd9Sstevel@tonic-gate /*
11727c478bd9Sstevel@tonic-gate ** This routine is called to do the work of a DROP TABLE statement.
11737c478bd9Sstevel@tonic-gate ** pName is the name of the table to be dropped.
11747c478bd9Sstevel@tonic-gate */
sqliteDropTable(Parse * pParse,Token * pName,int isView)11757c478bd9Sstevel@tonic-gate void sqliteDropTable(Parse *pParse, Token *pName, int isView){
11767c478bd9Sstevel@tonic-gate Table *pTable;
11777c478bd9Sstevel@tonic-gate Vdbe *v;
11787c478bd9Sstevel@tonic-gate int base;
11797c478bd9Sstevel@tonic-gate sqlite *db = pParse->db;
11807c478bd9Sstevel@tonic-gate int iDb;
11817c478bd9Sstevel@tonic-gate
11827c478bd9Sstevel@tonic-gate if( pParse->nErr || sqlite_malloc_failed ) return;
11837c478bd9Sstevel@tonic-gate pTable = sqliteTableFromToken(pParse, pName);
11847c478bd9Sstevel@tonic-gate if( pTable==0 ) return;
11857c478bd9Sstevel@tonic-gate iDb = pTable->iDb;
11867c478bd9Sstevel@tonic-gate assert( iDb>=0 && iDb<db->nDb );
11877c478bd9Sstevel@tonic-gate #ifndef SQLITE_OMIT_AUTHORIZATION
11887c478bd9Sstevel@tonic-gate {
11897c478bd9Sstevel@tonic-gate int code;
11907c478bd9Sstevel@tonic-gate const char *zTab = SCHEMA_TABLE(pTable->iDb);
11917c478bd9Sstevel@tonic-gate const char *zDb = db->aDb[pTable->iDb].zName;
11927c478bd9Sstevel@tonic-gate if( sqliteAuthCheck(pParse, SQLITE_DELETE, zTab, 0, zDb)){
11937c478bd9Sstevel@tonic-gate return;
11947c478bd9Sstevel@tonic-gate }
11957c478bd9Sstevel@tonic-gate if( isView ){
11967c478bd9Sstevel@tonic-gate if( iDb==1 ){
11977c478bd9Sstevel@tonic-gate code = SQLITE_DROP_TEMP_VIEW;
11987c478bd9Sstevel@tonic-gate }else{
11997c478bd9Sstevel@tonic-gate code = SQLITE_DROP_VIEW;
12007c478bd9Sstevel@tonic-gate }
12017c478bd9Sstevel@tonic-gate }else{
12027c478bd9Sstevel@tonic-gate if( iDb==1 ){
12037c478bd9Sstevel@tonic-gate code = SQLITE_DROP_TEMP_TABLE;
12047c478bd9Sstevel@tonic-gate }else{
12057c478bd9Sstevel@tonic-gate code = SQLITE_DROP_TABLE;
12067c478bd9Sstevel@tonic-gate }
12077c478bd9Sstevel@tonic-gate }
12087c478bd9Sstevel@tonic-gate if( sqliteAuthCheck(pParse, code, pTable->zName, 0, zDb) ){
12097c478bd9Sstevel@tonic-gate return;
12107c478bd9Sstevel@tonic-gate }
12117c478bd9Sstevel@tonic-gate if( sqliteAuthCheck(pParse, SQLITE_DELETE, pTable->zName, 0, zDb) ){
12127c478bd9Sstevel@tonic-gate return;
12137c478bd9Sstevel@tonic-gate }
12147c478bd9Sstevel@tonic-gate }
12157c478bd9Sstevel@tonic-gate #endif
12167c478bd9Sstevel@tonic-gate if( pTable->readOnly ){
12177c478bd9Sstevel@tonic-gate sqliteErrorMsg(pParse, "table %s may not be dropped", pTable->zName);
12187c478bd9Sstevel@tonic-gate pParse->nErr++;
12197c478bd9Sstevel@tonic-gate return;
12207c478bd9Sstevel@tonic-gate }
12217c478bd9Sstevel@tonic-gate if( isView && pTable->pSelect==0 ){
12227c478bd9Sstevel@tonic-gate sqliteErrorMsg(pParse, "use DROP TABLE to delete table %s", pTable->zName);
12237c478bd9Sstevel@tonic-gate return;
12247c478bd9Sstevel@tonic-gate }
12257c478bd9Sstevel@tonic-gate if( !isView && pTable->pSelect ){
12267c478bd9Sstevel@tonic-gate sqliteErrorMsg(pParse, "use DROP VIEW to delete view %s", pTable->zName);
12277c478bd9Sstevel@tonic-gate return;
12287c478bd9Sstevel@tonic-gate }
12297c478bd9Sstevel@tonic-gate
12307c478bd9Sstevel@tonic-gate /* Generate code to remove the table from the master table
12317c478bd9Sstevel@tonic-gate ** on disk.
12327c478bd9Sstevel@tonic-gate */
12337c478bd9Sstevel@tonic-gate v = sqliteGetVdbe(pParse);
12347c478bd9Sstevel@tonic-gate if( v ){
12357c478bd9Sstevel@tonic-gate static VdbeOpList dropTable[] = {
12367c478bd9Sstevel@tonic-gate { OP_Rewind, 0, ADDR(8), 0},
12377c478bd9Sstevel@tonic-gate { OP_String, 0, 0, 0}, /* 1 */
12387c478bd9Sstevel@tonic-gate { OP_MemStore, 1, 1, 0},
12397c478bd9Sstevel@tonic-gate { OP_MemLoad, 1, 0, 0}, /* 3 */
12407c478bd9Sstevel@tonic-gate { OP_Column, 0, 2, 0},
12417c478bd9Sstevel@tonic-gate { OP_Ne, 0, ADDR(7), 0},
12427c478bd9Sstevel@tonic-gate { OP_Delete, 0, 0, 0},
12437c478bd9Sstevel@tonic-gate { OP_Next, 0, ADDR(3), 0}, /* 7 */
12447c478bd9Sstevel@tonic-gate };
12457c478bd9Sstevel@tonic-gate Index *pIdx;
12467c478bd9Sstevel@tonic-gate Trigger *pTrigger;
12477c478bd9Sstevel@tonic-gate sqliteBeginWriteOperation(pParse, 0, pTable->iDb);
12487c478bd9Sstevel@tonic-gate
12497c478bd9Sstevel@tonic-gate /* Drop all triggers associated with the table being dropped */
12507c478bd9Sstevel@tonic-gate pTrigger = pTable->pTrigger;
12517c478bd9Sstevel@tonic-gate while( pTrigger ){
12527c478bd9Sstevel@tonic-gate assert( pTrigger->iDb==pTable->iDb || pTrigger->iDb==1 );
12537c478bd9Sstevel@tonic-gate sqliteDropTriggerPtr(pParse, pTrigger, 1);
12547c478bd9Sstevel@tonic-gate if( pParse->explain ){
12557c478bd9Sstevel@tonic-gate pTrigger = pTrigger->pNext;
12567c478bd9Sstevel@tonic-gate }else{
12577c478bd9Sstevel@tonic-gate pTrigger = pTable->pTrigger;
12587c478bd9Sstevel@tonic-gate }
12597c478bd9Sstevel@tonic-gate }
12607c478bd9Sstevel@tonic-gate
12617c478bd9Sstevel@tonic-gate /* Drop all SQLITE_MASTER entries that refer to the table */
12627c478bd9Sstevel@tonic-gate sqliteOpenMasterTable(v, pTable->iDb);
12637c478bd9Sstevel@tonic-gate base = sqliteVdbeAddOpList(v, ArraySize(dropTable), dropTable);
12647c478bd9Sstevel@tonic-gate sqliteVdbeChangeP3(v, base+1, pTable->zName, 0);
12657c478bd9Sstevel@tonic-gate
12667c478bd9Sstevel@tonic-gate /* Drop all SQLITE_TEMP_MASTER entries that refer to the table */
12677c478bd9Sstevel@tonic-gate if( pTable->iDb!=1 ){
12687c478bd9Sstevel@tonic-gate sqliteOpenMasterTable(v, 1);
12697c478bd9Sstevel@tonic-gate base = sqliteVdbeAddOpList(v, ArraySize(dropTable), dropTable);
12707c478bd9Sstevel@tonic-gate sqliteVdbeChangeP3(v, base+1, pTable->zName, 0);
12717c478bd9Sstevel@tonic-gate }
12727c478bd9Sstevel@tonic-gate
12737c478bd9Sstevel@tonic-gate if( pTable->iDb==0 ){
12747c478bd9Sstevel@tonic-gate sqliteChangeCookie(db, v);
12757c478bd9Sstevel@tonic-gate }
12767c478bd9Sstevel@tonic-gate sqliteVdbeAddOp(v, OP_Close, 0, 0);
12777c478bd9Sstevel@tonic-gate if( !isView ){
12787c478bd9Sstevel@tonic-gate sqliteVdbeAddOp(v, OP_Destroy, pTable->tnum, pTable->iDb);
12797c478bd9Sstevel@tonic-gate for(pIdx=pTable->pIndex; pIdx; pIdx=pIdx->pNext){
12807c478bd9Sstevel@tonic-gate sqliteVdbeAddOp(v, OP_Destroy, pIdx->tnum, pIdx->iDb);
12817c478bd9Sstevel@tonic-gate }
12827c478bd9Sstevel@tonic-gate }
12837c478bd9Sstevel@tonic-gate sqliteEndWriteOperation(pParse);
12847c478bd9Sstevel@tonic-gate }
12857c478bd9Sstevel@tonic-gate
12867c478bd9Sstevel@tonic-gate /* Delete the in-memory description of the table.
12877c478bd9Sstevel@tonic-gate **
12887c478bd9Sstevel@tonic-gate ** Exception: if the SQL statement began with the EXPLAIN keyword,
12897c478bd9Sstevel@tonic-gate ** then no changes should be made.
12907c478bd9Sstevel@tonic-gate */
12917c478bd9Sstevel@tonic-gate if( !pParse->explain ){
12927c478bd9Sstevel@tonic-gate sqliteUnlinkAndDeleteTable(db, pTable);
12937c478bd9Sstevel@tonic-gate db->flags |= SQLITE_InternChanges;
12947c478bd9Sstevel@tonic-gate }
12957c478bd9Sstevel@tonic-gate sqliteViewResetAll(db, iDb);
12967c478bd9Sstevel@tonic-gate }
12977c478bd9Sstevel@tonic-gate
12987c478bd9Sstevel@tonic-gate /*
12997c478bd9Sstevel@tonic-gate ** This routine constructs a P3 string suitable for an OP_MakeIdxKey
13007c478bd9Sstevel@tonic-gate ** opcode and adds that P3 string to the most recently inserted instruction
13017c478bd9Sstevel@tonic-gate ** in the virtual machine. The P3 string consists of a single character
13027c478bd9Sstevel@tonic-gate ** for each column in the index pIdx of table pTab. If the column uses
13037c478bd9Sstevel@tonic-gate ** a numeric sort order, then the P3 string character corresponding to
13047c478bd9Sstevel@tonic-gate ** that column is 'n'. If the column uses a text sort order, then the
13057c478bd9Sstevel@tonic-gate ** P3 string is 't'. See the OP_MakeIdxKey opcode documentation for
13067c478bd9Sstevel@tonic-gate ** additional information. See also the sqliteAddKeyType() routine.
13077c478bd9Sstevel@tonic-gate */
sqliteAddIdxKeyType(Vdbe * v,Index * pIdx)13087c478bd9Sstevel@tonic-gate void sqliteAddIdxKeyType(Vdbe *v, Index *pIdx){
13097c478bd9Sstevel@tonic-gate char *zType;
13107c478bd9Sstevel@tonic-gate Table *pTab;
13117c478bd9Sstevel@tonic-gate int i, n;
13127c478bd9Sstevel@tonic-gate assert( pIdx!=0 && pIdx->pTable!=0 );
13137c478bd9Sstevel@tonic-gate pTab = pIdx->pTable;
13147c478bd9Sstevel@tonic-gate n = pIdx->nColumn;
13157c478bd9Sstevel@tonic-gate zType = sqliteMallocRaw( n+1 );
13167c478bd9Sstevel@tonic-gate if( zType==0 ) return;
13177c478bd9Sstevel@tonic-gate for(i=0; i<n; i++){
13187c478bd9Sstevel@tonic-gate int iCol = pIdx->aiColumn[i];
13197c478bd9Sstevel@tonic-gate assert( iCol>=0 && iCol<pTab->nCol );
13207c478bd9Sstevel@tonic-gate if( (pTab->aCol[iCol].sortOrder & SQLITE_SO_TYPEMASK)==SQLITE_SO_TEXT ){
13217c478bd9Sstevel@tonic-gate zType[i] = 't';
13227c478bd9Sstevel@tonic-gate }else{
13237c478bd9Sstevel@tonic-gate zType[i] = 'n';
13247c478bd9Sstevel@tonic-gate }
13257c478bd9Sstevel@tonic-gate }
13267c478bd9Sstevel@tonic-gate zType[n] = 0;
13277c478bd9Sstevel@tonic-gate sqliteVdbeChangeP3(v, -1, zType, n);
13287c478bd9Sstevel@tonic-gate sqliteFree(zType);
13297c478bd9Sstevel@tonic-gate }
13307c478bd9Sstevel@tonic-gate
13317c478bd9Sstevel@tonic-gate /*
13327c478bd9Sstevel@tonic-gate ** This routine is called to create a new foreign key on the table
13337c478bd9Sstevel@tonic-gate ** currently under construction. pFromCol determines which columns
13347c478bd9Sstevel@tonic-gate ** in the current table point to the foreign key. If pFromCol==0 then
13357c478bd9Sstevel@tonic-gate ** connect the key to the last column inserted. pTo is the name of
13367c478bd9Sstevel@tonic-gate ** the table referred to. pToCol is a list of tables in the other
13377c478bd9Sstevel@tonic-gate ** pTo table that the foreign key points to. flags contains all
13387c478bd9Sstevel@tonic-gate ** information about the conflict resolution algorithms specified
13397c478bd9Sstevel@tonic-gate ** in the ON DELETE, ON UPDATE and ON INSERT clauses.
13407c478bd9Sstevel@tonic-gate **
13417c478bd9Sstevel@tonic-gate ** An FKey structure is created and added to the table currently
13427c478bd9Sstevel@tonic-gate ** under construction in the pParse->pNewTable field. The new FKey
13437c478bd9Sstevel@tonic-gate ** is not linked into db->aFKey at this point - that does not happen
13447c478bd9Sstevel@tonic-gate ** until sqliteEndTable().
13457c478bd9Sstevel@tonic-gate **
13467c478bd9Sstevel@tonic-gate ** The foreign key is set for IMMEDIATE processing. A subsequent call
13477c478bd9Sstevel@tonic-gate ** to sqliteDeferForeignKey() might change this to DEFERRED.
13487c478bd9Sstevel@tonic-gate */
sqliteCreateForeignKey(Parse * pParse,IdList * pFromCol,Token * pTo,IdList * pToCol,int flags)13497c478bd9Sstevel@tonic-gate void sqliteCreateForeignKey(
13507c478bd9Sstevel@tonic-gate Parse *pParse, /* Parsing context */
13517c478bd9Sstevel@tonic-gate IdList *pFromCol, /* Columns in this table that point to other table */
13527c478bd9Sstevel@tonic-gate Token *pTo, /* Name of the other table */
13537c478bd9Sstevel@tonic-gate IdList *pToCol, /* Columns in the other table */
13547c478bd9Sstevel@tonic-gate int flags /* Conflict resolution algorithms. */
13557c478bd9Sstevel@tonic-gate ){
13567c478bd9Sstevel@tonic-gate Table *p = pParse->pNewTable;
13577c478bd9Sstevel@tonic-gate int nByte;
13587c478bd9Sstevel@tonic-gate int i;
13597c478bd9Sstevel@tonic-gate int nCol;
13607c478bd9Sstevel@tonic-gate char *z;
13617c478bd9Sstevel@tonic-gate FKey *pFKey = 0;
13627c478bd9Sstevel@tonic-gate
13637c478bd9Sstevel@tonic-gate assert( pTo!=0 );
13647c478bd9Sstevel@tonic-gate if( p==0 || pParse->nErr ) goto fk_end;
13657c478bd9Sstevel@tonic-gate if( pFromCol==0 ){
13667c478bd9Sstevel@tonic-gate int iCol = p->nCol-1;
13677c478bd9Sstevel@tonic-gate if( iCol<0 ) goto fk_end;
13687c478bd9Sstevel@tonic-gate if( pToCol && pToCol->nId!=1 ){
13697c478bd9Sstevel@tonic-gate sqliteErrorMsg(pParse, "foreign key on %s"
13707c478bd9Sstevel@tonic-gate " should reference only one column of table %T",
13717c478bd9Sstevel@tonic-gate p->aCol[iCol].zName, pTo);
13727c478bd9Sstevel@tonic-gate goto fk_end;
13737c478bd9Sstevel@tonic-gate }
13747c478bd9Sstevel@tonic-gate nCol = 1;
13757c478bd9Sstevel@tonic-gate }else if( pToCol && pToCol->nId!=pFromCol->nId ){
13767c478bd9Sstevel@tonic-gate sqliteErrorMsg(pParse,
13777c478bd9Sstevel@tonic-gate "number of columns in foreign key does not match the number of "
13787c478bd9Sstevel@tonic-gate "columns in the referenced table");
13797c478bd9Sstevel@tonic-gate goto fk_end;
13807c478bd9Sstevel@tonic-gate }else{
13817c478bd9Sstevel@tonic-gate nCol = pFromCol->nId;
13827c478bd9Sstevel@tonic-gate }
13837c478bd9Sstevel@tonic-gate nByte = sizeof(*pFKey) + nCol*sizeof(pFKey->aCol[0]) + pTo->n + 1;
13847c478bd9Sstevel@tonic-gate if( pToCol ){
13857c478bd9Sstevel@tonic-gate for(i=0; i<pToCol->nId; i++){
13867c478bd9Sstevel@tonic-gate nByte += strlen(pToCol->a[i].zName) + 1;
13877c478bd9Sstevel@tonic-gate }
13887c478bd9Sstevel@tonic-gate }
13897c478bd9Sstevel@tonic-gate pFKey = sqliteMalloc( nByte );
13907c478bd9Sstevel@tonic-gate if( pFKey==0 ) goto fk_end;
13917c478bd9Sstevel@tonic-gate pFKey->pFrom = p;
13927c478bd9Sstevel@tonic-gate pFKey->pNextFrom = p->pFKey;
13937c478bd9Sstevel@tonic-gate z = (char*)&pFKey[1];
13947c478bd9Sstevel@tonic-gate pFKey->aCol = (struct sColMap*)z;
13957c478bd9Sstevel@tonic-gate z += sizeof(struct sColMap)*nCol;
13967c478bd9Sstevel@tonic-gate pFKey->zTo = z;
13977c478bd9Sstevel@tonic-gate memcpy(z, pTo->z, pTo->n);
13987c478bd9Sstevel@tonic-gate z[pTo->n] = 0;
13997c478bd9Sstevel@tonic-gate z += pTo->n+1;
14007c478bd9Sstevel@tonic-gate pFKey->pNextTo = 0;
14017c478bd9Sstevel@tonic-gate pFKey->nCol = nCol;
14027c478bd9Sstevel@tonic-gate if( pFromCol==0 ){
14037c478bd9Sstevel@tonic-gate pFKey->aCol[0].iFrom = p->nCol-1;
14047c478bd9Sstevel@tonic-gate }else{
14057c478bd9Sstevel@tonic-gate for(i=0; i<nCol; i++){
14067c478bd9Sstevel@tonic-gate int j;
14077c478bd9Sstevel@tonic-gate for(j=0; j<p->nCol; j++){
14087c478bd9Sstevel@tonic-gate if( sqliteStrICmp(p->aCol[j].zName, pFromCol->a[i].zName)==0 ){
14097c478bd9Sstevel@tonic-gate pFKey->aCol[i].iFrom = j;
14107c478bd9Sstevel@tonic-gate break;
14117c478bd9Sstevel@tonic-gate }
14127c478bd9Sstevel@tonic-gate }
14137c478bd9Sstevel@tonic-gate if( j>=p->nCol ){
1414*1da57d55SToomas Soome sqliteErrorMsg(pParse,
1415*1da57d55SToomas Soome "unknown column \"%s\" in foreign key definition",
14167c478bd9Sstevel@tonic-gate pFromCol->a[i].zName);
14177c478bd9Sstevel@tonic-gate goto fk_end;
14187c478bd9Sstevel@tonic-gate }
14197c478bd9Sstevel@tonic-gate }
14207c478bd9Sstevel@tonic-gate }
14217c478bd9Sstevel@tonic-gate if( pToCol ){
14227c478bd9Sstevel@tonic-gate for(i=0; i<nCol; i++){
14237c478bd9Sstevel@tonic-gate int n = strlen(pToCol->a[i].zName);
14247c478bd9Sstevel@tonic-gate pFKey->aCol[i].zCol = z;
14257c478bd9Sstevel@tonic-gate memcpy(z, pToCol->a[i].zName, n);
14267c478bd9Sstevel@tonic-gate z[n] = 0;
14277c478bd9Sstevel@tonic-gate z += n+1;
14287c478bd9Sstevel@tonic-gate }
14297c478bd9Sstevel@tonic-gate }
14307c478bd9Sstevel@tonic-gate pFKey->isDeferred = 0;
14317c478bd9Sstevel@tonic-gate pFKey->deleteConf = flags & 0xff;
14327c478bd9Sstevel@tonic-gate pFKey->updateConf = (flags >> 8 ) & 0xff;
14337c478bd9Sstevel@tonic-gate pFKey->insertConf = (flags >> 16 ) & 0xff;
14347c478bd9Sstevel@tonic-gate
14357c478bd9Sstevel@tonic-gate /* Link the foreign key to the table as the last step.
14367c478bd9Sstevel@tonic-gate */
14377c478bd9Sstevel@tonic-gate p->pFKey = pFKey;
14387c478bd9Sstevel@tonic-gate pFKey = 0;
14397c478bd9Sstevel@tonic-gate
14407c478bd9Sstevel@tonic-gate fk_end:
14417c478bd9Sstevel@tonic-gate sqliteFree(pFKey);
14427c478bd9Sstevel@tonic-gate sqliteIdListDelete(pFromCol);
14437c478bd9Sstevel@tonic-gate sqliteIdListDelete(pToCol);
14447c478bd9Sstevel@tonic-gate }
14457c478bd9Sstevel@tonic-gate
14467c478bd9Sstevel@tonic-gate /*
14477c478bd9Sstevel@tonic-gate ** This routine is called when an INITIALLY IMMEDIATE or INITIALLY DEFERRED
14487c478bd9Sstevel@tonic-gate ** clause is seen as part of a foreign key definition. The isDeferred
14497c478bd9Sstevel@tonic-gate ** parameter is 1 for INITIALLY DEFERRED and 0 for INITIALLY IMMEDIATE.
14507c478bd9Sstevel@tonic-gate ** The behavior of the most recently created foreign key is adjusted
14517c478bd9Sstevel@tonic-gate ** accordingly.
14527c478bd9Sstevel@tonic-gate */
sqliteDeferForeignKey(Parse * pParse,int isDeferred)14537c478bd9Sstevel@tonic-gate void sqliteDeferForeignKey(Parse *pParse, int isDeferred){
14547c478bd9Sstevel@tonic-gate Table *pTab;
14557c478bd9Sstevel@tonic-gate FKey *pFKey;
14567c478bd9Sstevel@tonic-gate if( (pTab = pParse->pNewTable)==0 || (pFKey = pTab->pFKey)==0 ) return;
14577c478bd9Sstevel@tonic-gate pFKey->isDeferred = isDeferred;
14587c478bd9Sstevel@tonic-gate }
14597c478bd9Sstevel@tonic-gate
14607c478bd9Sstevel@tonic-gate /*
1461*1da57d55SToomas Soome ** Create a new index for an SQL table. pIndex is the name of the index
1462*1da57d55SToomas Soome ** and pTable is the name of the table that is to be indexed. Both will
14637c478bd9Sstevel@tonic-gate ** be NULL for a primary key or an index that is created to satisfy a
14647c478bd9Sstevel@tonic-gate ** UNIQUE constraint. If pTable and pIndex are NULL, use pParse->pNewTable
14657c478bd9Sstevel@tonic-gate ** as the table to be indexed. pParse->pNewTable is a table that is
14667c478bd9Sstevel@tonic-gate ** currently being constructed by a CREATE TABLE statement.
14677c478bd9Sstevel@tonic-gate **
14687c478bd9Sstevel@tonic-gate ** pList is a list of columns to be indexed. pList will be NULL if this
14697c478bd9Sstevel@tonic-gate ** is a primary key or unique-constraint on the most recent column added
1470*1da57d55SToomas Soome ** to the table currently under construction.
14717c478bd9Sstevel@tonic-gate */
sqliteCreateIndex(Parse * pParse,Token * pName,SrcList * pTable,IdList * pList,int onError,Token * pStart,Token * pEnd)14727c478bd9Sstevel@tonic-gate void sqliteCreateIndex(
14737c478bd9Sstevel@tonic-gate Parse *pParse, /* All information about this parse */
14747c478bd9Sstevel@tonic-gate Token *pName, /* Name of the index. May be NULL */
14757c478bd9Sstevel@tonic-gate SrcList *pTable, /* Name of the table to index. Use pParse->pNewTable if 0 */
14767c478bd9Sstevel@tonic-gate IdList *pList, /* A list of columns to be indexed */
14777c478bd9Sstevel@tonic-gate int onError, /* OE_Abort, OE_Ignore, OE_Replace, or OE_None */
14787c478bd9Sstevel@tonic-gate Token *pStart, /* The CREATE token that begins a CREATE TABLE statement */
14797c478bd9Sstevel@tonic-gate Token *pEnd /* The ")" that closes the CREATE INDEX statement */
14807c478bd9Sstevel@tonic-gate ){
14817c478bd9Sstevel@tonic-gate Table *pTab; /* Table to be indexed */
14827c478bd9Sstevel@tonic-gate Index *pIndex; /* The index to be created */
14837c478bd9Sstevel@tonic-gate char *zName = 0;
14847c478bd9Sstevel@tonic-gate int i, j;
14857c478bd9Sstevel@tonic-gate Token nullId; /* Fake token for an empty ID list */
14867c478bd9Sstevel@tonic-gate DbFixer sFix; /* For assigning database names to pTable */
14877c478bd9Sstevel@tonic-gate int isTemp; /* True for a temporary index */
14887c478bd9Sstevel@tonic-gate sqlite *db = pParse->db;
14897c478bd9Sstevel@tonic-gate
14907c478bd9Sstevel@tonic-gate if( pParse->nErr || sqlite_malloc_failed ) goto exit_create_index;
1491*1da57d55SToomas Soome if( db->init.busy
14927c478bd9Sstevel@tonic-gate && sqliteFixInit(&sFix, pParse, db->init.iDb, "index", pName)
14937c478bd9Sstevel@tonic-gate && sqliteFixSrcList(&sFix, pTable)
14947c478bd9Sstevel@tonic-gate ){
14957c478bd9Sstevel@tonic-gate goto exit_create_index;
14967c478bd9Sstevel@tonic-gate }
14977c478bd9Sstevel@tonic-gate
14987c478bd9Sstevel@tonic-gate /*
14997c478bd9Sstevel@tonic-gate ** Find the table that is to be indexed. Return early if not found.
15007c478bd9Sstevel@tonic-gate */
15017c478bd9Sstevel@tonic-gate if( pTable!=0 ){
15027c478bd9Sstevel@tonic-gate assert( pName!=0 );
15037c478bd9Sstevel@tonic-gate assert( pTable->nSrc==1 );
15047c478bd9Sstevel@tonic-gate pTab = sqliteSrcListLookup(pParse, pTable);
15057c478bd9Sstevel@tonic-gate }else{
15067c478bd9Sstevel@tonic-gate assert( pName==0 );
15077c478bd9Sstevel@tonic-gate pTab = pParse->pNewTable;
15087c478bd9Sstevel@tonic-gate }
15097c478bd9Sstevel@tonic-gate if( pTab==0 || pParse->nErr ) goto exit_create_index;
15107c478bd9Sstevel@tonic-gate if( pTab->readOnly ){
15117c478bd9Sstevel@tonic-gate sqliteErrorMsg(pParse, "table %s may not be indexed", pTab->zName);
15127c478bd9Sstevel@tonic-gate goto exit_create_index;
15137c478bd9Sstevel@tonic-gate }
15147c478bd9Sstevel@tonic-gate if( pTab->iDb>=2 && db->init.busy==0 ){
15157c478bd9Sstevel@tonic-gate sqliteErrorMsg(pParse, "table %s may not have indices added", pTab->zName);
15167c478bd9Sstevel@tonic-gate goto exit_create_index;
15177c478bd9Sstevel@tonic-gate }
15187c478bd9Sstevel@tonic-gate if( pTab->pSelect ){
15197c478bd9Sstevel@tonic-gate sqliteErrorMsg(pParse, "views may not be indexed");
15207c478bd9Sstevel@tonic-gate goto exit_create_index;
15217c478bd9Sstevel@tonic-gate }
15227c478bd9Sstevel@tonic-gate isTemp = pTab->iDb==1;
15237c478bd9Sstevel@tonic-gate
15247c478bd9Sstevel@tonic-gate /*
15257c478bd9Sstevel@tonic-gate ** Find the name of the index. Make sure there is not already another
1526*1da57d55SToomas Soome ** index or table with the same name.
15277c478bd9Sstevel@tonic-gate **
15287c478bd9Sstevel@tonic-gate ** Exception: If we are reading the names of permanent indices from the
15297c478bd9Sstevel@tonic-gate ** sqlite_master table (because some other process changed the schema) and
15307c478bd9Sstevel@tonic-gate ** one of the index names collides with the name of a temporary table or
15317c478bd9Sstevel@tonic-gate ** index, then we will continue to process this index.
15327c478bd9Sstevel@tonic-gate **
15337c478bd9Sstevel@tonic-gate ** If pName==0 it means that we are
15347c478bd9Sstevel@tonic-gate ** dealing with a primary key or UNIQUE constraint. We have to invent our
15357c478bd9Sstevel@tonic-gate ** own name.
15367c478bd9Sstevel@tonic-gate */
15377c478bd9Sstevel@tonic-gate if( pName && !db->init.busy ){
15387c478bd9Sstevel@tonic-gate Index *pISameName; /* Another index with the same name */
15397c478bd9Sstevel@tonic-gate Table *pTSameName; /* A table with same name as the index */
15407c478bd9Sstevel@tonic-gate zName = sqliteTableNameFromToken(pName);
15417c478bd9Sstevel@tonic-gate if( zName==0 ) goto exit_create_index;
15427c478bd9Sstevel@tonic-gate if( (pISameName = sqliteFindIndex(db, zName, 0))!=0 ){
15437c478bd9Sstevel@tonic-gate sqliteErrorMsg(pParse, "index %s already exists", zName);
15447c478bd9Sstevel@tonic-gate goto exit_create_index;
15457c478bd9Sstevel@tonic-gate }
15467c478bd9Sstevel@tonic-gate if( (pTSameName = sqliteFindTable(db, zName, 0))!=0 ){
15477c478bd9Sstevel@tonic-gate sqliteErrorMsg(pParse, "there is already a table named %s", zName);
15487c478bd9Sstevel@tonic-gate goto exit_create_index;
15497c478bd9Sstevel@tonic-gate }
15507c478bd9Sstevel@tonic-gate }else if( pName==0 ){
15517c478bd9Sstevel@tonic-gate char zBuf[30];
15527c478bd9Sstevel@tonic-gate int n;
15537c478bd9Sstevel@tonic-gate Index *pLoop;
15547c478bd9Sstevel@tonic-gate for(pLoop=pTab->pIndex, n=1; pLoop; pLoop=pLoop->pNext, n++){}
15557c478bd9Sstevel@tonic-gate sprintf(zBuf,"%d)",n);
15567c478bd9Sstevel@tonic-gate zName = 0;
15577c478bd9Sstevel@tonic-gate sqliteSetString(&zName, "(", pTab->zName, " autoindex ", zBuf, (char*)0);
15587c478bd9Sstevel@tonic-gate if( zName==0 ) goto exit_create_index;
15597c478bd9Sstevel@tonic-gate }else{
15607c478bd9Sstevel@tonic-gate zName = sqliteStrNDup(pName->z, pName->n);
15617c478bd9Sstevel@tonic-gate }
15627c478bd9Sstevel@tonic-gate
15637c478bd9Sstevel@tonic-gate /* Check for authorization to create an index.
15647c478bd9Sstevel@tonic-gate */
15657c478bd9Sstevel@tonic-gate #ifndef SQLITE_OMIT_AUTHORIZATION
15667c478bd9Sstevel@tonic-gate {
15677c478bd9Sstevel@tonic-gate const char *zDb = db->aDb[pTab->iDb].zName;
15687c478bd9Sstevel@tonic-gate
15697c478bd9Sstevel@tonic-gate assert( pTab->iDb==db->init.iDb || isTemp );
15707c478bd9Sstevel@tonic-gate if( sqliteAuthCheck(pParse, SQLITE_INSERT, SCHEMA_TABLE(isTemp), 0, zDb) ){
15717c478bd9Sstevel@tonic-gate goto exit_create_index;
15727c478bd9Sstevel@tonic-gate }
15737c478bd9Sstevel@tonic-gate i = SQLITE_CREATE_INDEX;
15747c478bd9Sstevel@tonic-gate if( isTemp ) i = SQLITE_CREATE_TEMP_INDEX;
15757c478bd9Sstevel@tonic-gate if( sqliteAuthCheck(pParse, i, zName, pTab->zName, zDb) ){
15767c478bd9Sstevel@tonic-gate goto exit_create_index;
15777c478bd9Sstevel@tonic-gate }
15787c478bd9Sstevel@tonic-gate }
15797c478bd9Sstevel@tonic-gate #endif
15807c478bd9Sstevel@tonic-gate
15817c478bd9Sstevel@tonic-gate /* If pList==0, it means this routine was called to make a primary
15827c478bd9Sstevel@tonic-gate ** key out of the last column added to the table under construction.
15837c478bd9Sstevel@tonic-gate ** So create a fake list to simulate this.
15847c478bd9Sstevel@tonic-gate */
15857c478bd9Sstevel@tonic-gate if( pList==0 ){
15867c478bd9Sstevel@tonic-gate nullId.z = pTab->aCol[pTab->nCol-1].zName;
15877c478bd9Sstevel@tonic-gate nullId.n = strlen(nullId.z);
15887c478bd9Sstevel@tonic-gate pList = sqliteIdListAppend(0, &nullId);
15897c478bd9Sstevel@tonic-gate if( pList==0 ) goto exit_create_index;
15907c478bd9Sstevel@tonic-gate }
15917c478bd9Sstevel@tonic-gate
1592*1da57d55SToomas Soome /*
1593*1da57d55SToomas Soome ** Allocate the index structure.
15947c478bd9Sstevel@tonic-gate */
15957c478bd9Sstevel@tonic-gate pIndex = sqliteMalloc( sizeof(Index) + strlen(zName) + 1 +
15967c478bd9Sstevel@tonic-gate sizeof(int)*pList->nId );
15977c478bd9Sstevel@tonic-gate if( pIndex==0 ) goto exit_create_index;
15987c478bd9Sstevel@tonic-gate pIndex->aiColumn = (int*)&pIndex[1];
15997c478bd9Sstevel@tonic-gate pIndex->zName = (char*)&pIndex->aiColumn[pList->nId];
16007c478bd9Sstevel@tonic-gate strcpy(pIndex->zName, zName);
16017c478bd9Sstevel@tonic-gate pIndex->pTable = pTab;
16027c478bd9Sstevel@tonic-gate pIndex->nColumn = pList->nId;
16037c478bd9Sstevel@tonic-gate pIndex->onError = onError;
16047c478bd9Sstevel@tonic-gate pIndex->autoIndex = pName==0;
16057c478bd9Sstevel@tonic-gate pIndex->iDb = isTemp ? 1 : db->init.iDb;
16067c478bd9Sstevel@tonic-gate
16077c478bd9Sstevel@tonic-gate /* Scan the names of the columns of the table to be indexed and
16087c478bd9Sstevel@tonic-gate ** load the column indices into the Index structure. Report an error
16097c478bd9Sstevel@tonic-gate ** if any column is not found.
16107c478bd9Sstevel@tonic-gate */
16117c478bd9Sstevel@tonic-gate for(i=0; i<pList->nId; i++){
16127c478bd9Sstevel@tonic-gate for(j=0; j<pTab->nCol; j++){
16137c478bd9Sstevel@tonic-gate if( sqliteStrICmp(pList->a[i].zName, pTab->aCol[j].zName)==0 ) break;
16147c478bd9Sstevel@tonic-gate }
16157c478bd9Sstevel@tonic-gate if( j>=pTab->nCol ){
16167c478bd9Sstevel@tonic-gate sqliteErrorMsg(pParse, "table %s has no column named %s",
16177c478bd9Sstevel@tonic-gate pTab->zName, pList->a[i].zName);
16187c478bd9Sstevel@tonic-gate sqliteFree(pIndex);
16197c478bd9Sstevel@tonic-gate goto exit_create_index;
16207c478bd9Sstevel@tonic-gate }
16217c478bd9Sstevel@tonic-gate pIndex->aiColumn[i] = j;
16227c478bd9Sstevel@tonic-gate }
16237c478bd9Sstevel@tonic-gate
16247c478bd9Sstevel@tonic-gate /* Link the new Index structure to its table and to the other
1625*1da57d55SToomas Soome ** in-memory database structures.
16267c478bd9Sstevel@tonic-gate */
16277c478bd9Sstevel@tonic-gate if( !pParse->explain ){
16287c478bd9Sstevel@tonic-gate Index *p;
1629*1da57d55SToomas Soome p = sqliteHashInsert(&db->aDb[pIndex->iDb].idxHash,
16307c478bd9Sstevel@tonic-gate pIndex->zName, strlen(pIndex->zName)+1, pIndex);
16317c478bd9Sstevel@tonic-gate if( p ){
16327c478bd9Sstevel@tonic-gate assert( p==pIndex ); /* Malloc must have failed */
16337c478bd9Sstevel@tonic-gate sqliteFree(pIndex);
16347c478bd9Sstevel@tonic-gate goto exit_create_index;
16357c478bd9Sstevel@tonic-gate }
16367c478bd9Sstevel@tonic-gate db->flags |= SQLITE_InternChanges;
16377c478bd9Sstevel@tonic-gate }
16387c478bd9Sstevel@tonic-gate
16397c478bd9Sstevel@tonic-gate /* When adding an index to the list of indices for a table, make
16407c478bd9Sstevel@tonic-gate ** sure all indices labeled OE_Replace come after all those labeled
16417c478bd9Sstevel@tonic-gate ** OE_Ignore. This is necessary for the correct operation of UPDATE
16427c478bd9Sstevel@tonic-gate ** and INSERT.
16437c478bd9Sstevel@tonic-gate */
16447c478bd9Sstevel@tonic-gate if( onError!=OE_Replace || pTab->pIndex==0
16457c478bd9Sstevel@tonic-gate || pTab->pIndex->onError==OE_Replace){
16467c478bd9Sstevel@tonic-gate pIndex->pNext = pTab->pIndex;
16477c478bd9Sstevel@tonic-gate pTab->pIndex = pIndex;
16487c478bd9Sstevel@tonic-gate }else{
16497c478bd9Sstevel@tonic-gate Index *pOther = pTab->pIndex;
16507c478bd9Sstevel@tonic-gate while( pOther->pNext && pOther->pNext->onError!=OE_Replace ){
16517c478bd9Sstevel@tonic-gate pOther = pOther->pNext;
16527c478bd9Sstevel@tonic-gate }
16537c478bd9Sstevel@tonic-gate pIndex->pNext = pOther->pNext;
16547c478bd9Sstevel@tonic-gate pOther->pNext = pIndex;
16557c478bd9Sstevel@tonic-gate }
16567c478bd9Sstevel@tonic-gate
16577c478bd9Sstevel@tonic-gate /* If the db->init.busy is 1 it means we are reading the SQL off the
16587c478bd9Sstevel@tonic-gate ** "sqlite_master" table on the disk. So do not write to the disk
16597c478bd9Sstevel@tonic-gate ** again. Extract the table number from the db->init.newTnum field.
16607c478bd9Sstevel@tonic-gate */
16617c478bd9Sstevel@tonic-gate if( db->init.busy && pTable!=0 ){
16627c478bd9Sstevel@tonic-gate pIndex->tnum = db->init.newTnum;
16637c478bd9Sstevel@tonic-gate }
16647c478bd9Sstevel@tonic-gate
16657c478bd9Sstevel@tonic-gate /* If the db->init.busy is 0 then create the index on disk. This
16667c478bd9Sstevel@tonic-gate ** involves writing the index into the master table and filling in the
16677c478bd9Sstevel@tonic-gate ** index with the current table contents.
16687c478bd9Sstevel@tonic-gate **
1669*1da57d55SToomas Soome ** The db->init.busy is 0 when the user first enters a CREATE INDEX
1670*1da57d55SToomas Soome ** command. db->init.busy is 1 when a database is opened and
16717c478bd9Sstevel@tonic-gate ** CREATE INDEX statements are read out of the master table. In
16727c478bd9Sstevel@tonic-gate ** the latter case the index already exists on disk, which is why
16737c478bd9Sstevel@tonic-gate ** we don't want to recreate it.
16747c478bd9Sstevel@tonic-gate **
16757c478bd9Sstevel@tonic-gate ** If pTable==0 it means this index is generated as a primary key
16767c478bd9Sstevel@tonic-gate ** or UNIQUE constraint of a CREATE TABLE statement. Since the table
16777c478bd9Sstevel@tonic-gate ** has just been created, it contains no data and the index initialization
16787c478bd9Sstevel@tonic-gate ** step can be skipped.
16797c478bd9Sstevel@tonic-gate */
16807c478bd9Sstevel@tonic-gate else if( db->init.busy==0 ){
16817c478bd9Sstevel@tonic-gate int n;
16827c478bd9Sstevel@tonic-gate Vdbe *v;
16837c478bd9Sstevel@tonic-gate int lbl1, lbl2;
16847c478bd9Sstevel@tonic-gate int i;
16857c478bd9Sstevel@tonic-gate int addr;
16867c478bd9Sstevel@tonic-gate
16877c478bd9Sstevel@tonic-gate v = sqliteGetVdbe(pParse);
16887c478bd9Sstevel@tonic-gate if( v==0 ) goto exit_create_index;
16897c478bd9Sstevel@tonic-gate if( pTable!=0 ){
16907c478bd9Sstevel@tonic-gate sqliteBeginWriteOperation(pParse, 0, isTemp);
16917c478bd9Sstevel@tonic-gate sqliteOpenMasterTable(v, isTemp);
16927c478bd9Sstevel@tonic-gate }
16937c478bd9Sstevel@tonic-gate sqliteVdbeAddOp(v, OP_NewRecno, 0, 0);
16947c478bd9Sstevel@tonic-gate sqliteVdbeOp3(v, OP_String, 0, 0, "index", P3_STATIC);
16957c478bd9Sstevel@tonic-gate sqliteVdbeOp3(v, OP_String, 0, 0, pIndex->zName, 0);
16967c478bd9Sstevel@tonic-gate sqliteVdbeOp3(v, OP_String, 0, 0, pTab->zName, 0);
16977c478bd9Sstevel@tonic-gate sqliteVdbeOp3(v, OP_CreateIndex, 0, isTemp,(char*)&pIndex->tnum,P3_POINTER);
16987c478bd9Sstevel@tonic-gate pIndex->tnum = 0;
16997c478bd9Sstevel@tonic-gate if( pTable ){
17007c478bd9Sstevel@tonic-gate sqliteVdbeCode(v,
17017c478bd9Sstevel@tonic-gate OP_Dup, 0, 0,
17027c478bd9Sstevel@tonic-gate OP_Integer, isTemp, 0,
17037c478bd9Sstevel@tonic-gate OP_OpenWrite, 1, 0,
17047c478bd9Sstevel@tonic-gate 0);
17057c478bd9Sstevel@tonic-gate }
17067c478bd9Sstevel@tonic-gate addr = sqliteVdbeAddOp(v, OP_String, 0, 0);
17077c478bd9Sstevel@tonic-gate if( pStart && pEnd ){
17087c478bd9Sstevel@tonic-gate n = Addr(pEnd->z) - Addr(pStart->z) + 1;
17097c478bd9Sstevel@tonic-gate sqliteVdbeChangeP3(v, addr, pStart->z, n);
17107c478bd9Sstevel@tonic-gate }
17117c478bd9Sstevel@tonic-gate sqliteVdbeAddOp(v, OP_MakeRecord, 5, 0);
17127c478bd9Sstevel@tonic-gate sqliteVdbeAddOp(v, OP_PutIntKey, 0, 0);
17137c478bd9Sstevel@tonic-gate if( pTable ){
17147c478bd9Sstevel@tonic-gate sqliteVdbeAddOp(v, OP_Integer, pTab->iDb, 0);
17157c478bd9Sstevel@tonic-gate sqliteVdbeOp3(v, OP_OpenRead, 2, pTab->tnum, pTab->zName, 0);
17167c478bd9Sstevel@tonic-gate lbl2 = sqliteVdbeMakeLabel(v);
17177c478bd9Sstevel@tonic-gate sqliteVdbeAddOp(v, OP_Rewind, 2, lbl2);
17187c478bd9Sstevel@tonic-gate lbl1 = sqliteVdbeAddOp(v, OP_Recno, 2, 0);
17197c478bd9Sstevel@tonic-gate for(i=0; i<pIndex->nColumn; i++){
17207c478bd9Sstevel@tonic-gate int iCol = pIndex->aiColumn[i];
17217c478bd9Sstevel@tonic-gate if( pTab->iPKey==iCol ){
17227c478bd9Sstevel@tonic-gate sqliteVdbeAddOp(v, OP_Dup, i, 0);
17237c478bd9Sstevel@tonic-gate }else{
17247c478bd9Sstevel@tonic-gate sqliteVdbeAddOp(v, OP_Column, 2, iCol);
17257c478bd9Sstevel@tonic-gate }
17267c478bd9Sstevel@tonic-gate }
17277c478bd9Sstevel@tonic-gate sqliteVdbeAddOp(v, OP_MakeIdxKey, pIndex->nColumn, 0);
17287c478bd9Sstevel@tonic-gate if( db->file_format>=4 ) sqliteAddIdxKeyType(v, pIndex);
17297c478bd9Sstevel@tonic-gate sqliteVdbeOp3(v, OP_IdxPut, 1, pIndex->onError!=OE_None,
17307c478bd9Sstevel@tonic-gate "indexed columns are not unique", P3_STATIC);
17317c478bd9Sstevel@tonic-gate sqliteVdbeAddOp(v, OP_Next, 2, lbl1);
17327c478bd9Sstevel@tonic-gate sqliteVdbeResolveLabel(v, lbl2);
17337c478bd9Sstevel@tonic-gate sqliteVdbeAddOp(v, OP_Close, 2, 0);
17347c478bd9Sstevel@tonic-gate sqliteVdbeAddOp(v, OP_Close, 1, 0);
17357c478bd9Sstevel@tonic-gate }
17367c478bd9Sstevel@tonic-gate if( pTable!=0 ){
17377c478bd9Sstevel@tonic-gate if( !isTemp ){
17387c478bd9Sstevel@tonic-gate sqliteChangeCookie(db, v);
17397c478bd9Sstevel@tonic-gate }
17407c478bd9Sstevel@tonic-gate sqliteVdbeAddOp(v, OP_Close, 0, 0);
17417c478bd9Sstevel@tonic-gate sqliteEndWriteOperation(pParse);
17427c478bd9Sstevel@tonic-gate }
17437c478bd9Sstevel@tonic-gate }
17447c478bd9Sstevel@tonic-gate
17457c478bd9Sstevel@tonic-gate /* Clean up before exiting */
17467c478bd9Sstevel@tonic-gate exit_create_index:
17477c478bd9Sstevel@tonic-gate sqliteIdListDelete(pList);
17487c478bd9Sstevel@tonic-gate sqliteSrcListDelete(pTable);
17497c478bd9Sstevel@tonic-gate sqliteFree(zName);
17507c478bd9Sstevel@tonic-gate return;
17517c478bd9Sstevel@tonic-gate }
17527c478bd9Sstevel@tonic-gate
17537c478bd9Sstevel@tonic-gate /*
17547c478bd9Sstevel@tonic-gate ** This routine will drop an existing named index. This routine
17557c478bd9Sstevel@tonic-gate ** implements the DROP INDEX statement.
17567c478bd9Sstevel@tonic-gate */
sqliteDropIndex(Parse * pParse,SrcList * pName)17577c478bd9Sstevel@tonic-gate void sqliteDropIndex(Parse *pParse, SrcList *pName){
17587c478bd9Sstevel@tonic-gate Index *pIndex;
17597c478bd9Sstevel@tonic-gate Vdbe *v;
17607c478bd9Sstevel@tonic-gate sqlite *db = pParse->db;
17617c478bd9Sstevel@tonic-gate
17627c478bd9Sstevel@tonic-gate if( pParse->nErr || sqlite_malloc_failed ) return;
17637c478bd9Sstevel@tonic-gate assert( pName->nSrc==1 );
17647c478bd9Sstevel@tonic-gate pIndex = sqliteFindIndex(db, pName->a[0].zName, pName->a[0].zDatabase);
17657c478bd9Sstevel@tonic-gate if( pIndex==0 ){
17667c478bd9Sstevel@tonic-gate sqliteErrorMsg(pParse, "no such index: %S", pName, 0);
17677c478bd9Sstevel@tonic-gate goto exit_drop_index;
17687c478bd9Sstevel@tonic-gate }
17697c478bd9Sstevel@tonic-gate if( pIndex->autoIndex ){
17707c478bd9Sstevel@tonic-gate sqliteErrorMsg(pParse, "index associated with UNIQUE "
17717c478bd9Sstevel@tonic-gate "or PRIMARY KEY constraint cannot be dropped", 0);
17727c478bd9Sstevel@tonic-gate goto exit_drop_index;
17737c478bd9Sstevel@tonic-gate }
17747c478bd9Sstevel@tonic-gate if( pIndex->iDb>1 ){
17757c478bd9Sstevel@tonic-gate sqliteErrorMsg(pParse, "cannot alter schema of attached "
17767c478bd9Sstevel@tonic-gate "databases", 0);
17777c478bd9Sstevel@tonic-gate goto exit_drop_index;
17787c478bd9Sstevel@tonic-gate }
17797c478bd9Sstevel@tonic-gate #ifndef SQLITE_OMIT_AUTHORIZATION
17807c478bd9Sstevel@tonic-gate {
17817c478bd9Sstevel@tonic-gate int code = SQLITE_DROP_INDEX;
17827c478bd9Sstevel@tonic-gate Table *pTab = pIndex->pTable;
17837c478bd9Sstevel@tonic-gate const char *zDb = db->aDb[pIndex->iDb].zName;
17847c478bd9Sstevel@tonic-gate const char *zTab = SCHEMA_TABLE(pIndex->iDb);
17857c478bd9Sstevel@tonic-gate if( sqliteAuthCheck(pParse, SQLITE_DELETE, zTab, 0, zDb) ){
17867c478bd9Sstevel@tonic-gate goto exit_drop_index;
17877c478bd9Sstevel@tonic-gate }
17887c478bd9Sstevel@tonic-gate if( pIndex->iDb ) code = SQLITE_DROP_TEMP_INDEX;
17897c478bd9Sstevel@tonic-gate if( sqliteAuthCheck(pParse, code, pIndex->zName, pTab->zName, zDb) ){
17907c478bd9Sstevel@tonic-gate goto exit_drop_index;
17917c478bd9Sstevel@tonic-gate }
17927c478bd9Sstevel@tonic-gate }
17937c478bd9Sstevel@tonic-gate #endif
17947c478bd9Sstevel@tonic-gate
17957c478bd9Sstevel@tonic-gate /* Generate code to remove the index and from the master table */
17967c478bd9Sstevel@tonic-gate v = sqliteGetVdbe(pParse);
17977c478bd9Sstevel@tonic-gate if( v ){
17987c478bd9Sstevel@tonic-gate static VdbeOpList dropIndex[] = {
1799*1da57d55SToomas Soome { OP_Rewind, 0, ADDR(9), 0},
18007c478bd9Sstevel@tonic-gate { OP_String, 0, 0, 0}, /* 1 */
18017c478bd9Sstevel@tonic-gate { OP_MemStore, 1, 1, 0},
18027c478bd9Sstevel@tonic-gate { OP_MemLoad, 1, 0, 0}, /* 3 */
18037c478bd9Sstevel@tonic-gate { OP_Column, 0, 1, 0},
18047c478bd9Sstevel@tonic-gate { OP_Eq, 0, ADDR(8), 0},
18057c478bd9Sstevel@tonic-gate { OP_Next, 0, ADDR(3), 0},
18067c478bd9Sstevel@tonic-gate { OP_Goto, 0, ADDR(9), 0},
18077c478bd9Sstevel@tonic-gate { OP_Delete, 0, 0, 0}, /* 8 */
18087c478bd9Sstevel@tonic-gate };
18097c478bd9Sstevel@tonic-gate int base;
18107c478bd9Sstevel@tonic-gate
18117c478bd9Sstevel@tonic-gate sqliteBeginWriteOperation(pParse, 0, pIndex->iDb);
18127c478bd9Sstevel@tonic-gate sqliteOpenMasterTable(v, pIndex->iDb);
18137c478bd9Sstevel@tonic-gate base = sqliteVdbeAddOpList(v, ArraySize(dropIndex), dropIndex);
18147c478bd9Sstevel@tonic-gate sqliteVdbeChangeP3(v, base+1, pIndex->zName, 0);
18157c478bd9Sstevel@tonic-gate if( pIndex->iDb==0 ){
18167c478bd9Sstevel@tonic-gate sqliteChangeCookie(db, v);
18177c478bd9Sstevel@tonic-gate }
18187c478bd9Sstevel@tonic-gate sqliteVdbeAddOp(v, OP_Close, 0, 0);
18197c478bd9Sstevel@tonic-gate sqliteVdbeAddOp(v, OP_Destroy, pIndex->tnum, pIndex->iDb);
18207c478bd9Sstevel@tonic-gate sqliteEndWriteOperation(pParse);
18217c478bd9Sstevel@tonic-gate }
18227c478bd9Sstevel@tonic-gate
18237c478bd9Sstevel@tonic-gate /* Delete the in-memory description of this index.
18247c478bd9Sstevel@tonic-gate */
18257c478bd9Sstevel@tonic-gate if( !pParse->explain ){
18267c478bd9Sstevel@tonic-gate sqliteUnlinkAndDeleteIndex(db, pIndex);
18277c478bd9Sstevel@tonic-gate db->flags |= SQLITE_InternChanges;
18287c478bd9Sstevel@tonic-gate }
18297c478bd9Sstevel@tonic-gate
18307c478bd9Sstevel@tonic-gate exit_drop_index:
18317c478bd9Sstevel@tonic-gate sqliteSrcListDelete(pName);
18327c478bd9Sstevel@tonic-gate }
18337c478bd9Sstevel@tonic-gate
18347c478bd9Sstevel@tonic-gate /*
18357c478bd9Sstevel@tonic-gate ** Append a new element to the given IdList. Create a new IdList if
18367c478bd9Sstevel@tonic-gate ** need be.
18377c478bd9Sstevel@tonic-gate **
18387c478bd9Sstevel@tonic-gate ** A new IdList is returned, or NULL if malloc() fails.
18397c478bd9Sstevel@tonic-gate */
sqliteIdListAppend(IdList * pList,Token * pToken)18407c478bd9Sstevel@tonic-gate IdList *sqliteIdListAppend(IdList *pList, Token *pToken){
18417c478bd9Sstevel@tonic-gate if( pList==0 ){
18427c478bd9Sstevel@tonic-gate pList = sqliteMalloc( sizeof(IdList) );
18437c478bd9Sstevel@tonic-gate if( pList==0 ) return 0;
18447c478bd9Sstevel@tonic-gate pList->nAlloc = 0;
18457c478bd9Sstevel@tonic-gate }
18467c478bd9Sstevel@tonic-gate if( pList->nId>=pList->nAlloc ){
18477c478bd9Sstevel@tonic-gate struct IdList_item *a;
18487c478bd9Sstevel@tonic-gate pList->nAlloc = pList->nAlloc*2 + 5;
18497c478bd9Sstevel@tonic-gate a = sqliteRealloc(pList->a, pList->nAlloc*sizeof(pList->a[0]) );
18507c478bd9Sstevel@tonic-gate if( a==0 ){
18517c478bd9Sstevel@tonic-gate sqliteIdListDelete(pList);
18527c478bd9Sstevel@tonic-gate return 0;
18537c478bd9Sstevel@tonic-gate }
18547c478bd9Sstevel@tonic-gate pList->a = a;
18557c478bd9Sstevel@tonic-gate }
18567c478bd9Sstevel@tonic-gate memset(&pList->a[pList->nId], 0, sizeof(pList->a[0]));
18577c478bd9Sstevel@tonic-gate if( pToken ){
18587c478bd9Sstevel@tonic-gate char **pz = &pList->a[pList->nId].zName;
18597c478bd9Sstevel@tonic-gate sqliteSetNString(pz, pToken->z, pToken->n, 0);
18607c478bd9Sstevel@tonic-gate if( *pz==0 ){
18617c478bd9Sstevel@tonic-gate sqliteIdListDelete(pList);
18627c478bd9Sstevel@tonic-gate return 0;
18637c478bd9Sstevel@tonic-gate }else{
18647c478bd9Sstevel@tonic-gate sqliteDequote(*pz);
18657c478bd9Sstevel@tonic-gate }
18667c478bd9Sstevel@tonic-gate }
18677c478bd9Sstevel@tonic-gate pList->nId++;
18687c478bd9Sstevel@tonic-gate return pList;
18697c478bd9Sstevel@tonic-gate }
18707c478bd9Sstevel@tonic-gate
18717c478bd9Sstevel@tonic-gate /*
18727c478bd9Sstevel@tonic-gate ** Append a new table name to the given SrcList. Create a new SrcList if
18737c478bd9Sstevel@tonic-gate ** need be. A new entry is created in the SrcList even if pToken is NULL.
18747c478bd9Sstevel@tonic-gate **
18757c478bd9Sstevel@tonic-gate ** A new SrcList is returned, or NULL if malloc() fails.
18767c478bd9Sstevel@tonic-gate **
18777c478bd9Sstevel@tonic-gate ** If pDatabase is not null, it means that the table has an optional
18787c478bd9Sstevel@tonic-gate ** database name prefix. Like this: "database.table". The pDatabase
18797c478bd9Sstevel@tonic-gate ** points to the table name and the pTable points to the database name.
18807c478bd9Sstevel@tonic-gate ** The SrcList.a[].zName field is filled with the table name which might
1881*1da57d55SToomas Soome ** come from pTable (if pDatabase is NULL) or from pDatabase.
18827c478bd9Sstevel@tonic-gate ** SrcList.a[].zDatabase is filled with the database name from pTable,
18837c478bd9Sstevel@tonic-gate ** or with NULL if no database is specified.
18847c478bd9Sstevel@tonic-gate **
18857c478bd9Sstevel@tonic-gate ** In other words, if call like this:
18867c478bd9Sstevel@tonic-gate **
18877c478bd9Sstevel@tonic-gate ** sqliteSrcListAppend(A,B,0);
18887c478bd9Sstevel@tonic-gate **
18897c478bd9Sstevel@tonic-gate ** Then B is a table name and the database name is unspecified. If called
18907c478bd9Sstevel@tonic-gate ** like this:
18917c478bd9Sstevel@tonic-gate **
18927c478bd9Sstevel@tonic-gate ** sqliteSrcListAppend(A,B,C);
18937c478bd9Sstevel@tonic-gate **
18947c478bd9Sstevel@tonic-gate ** Then C is the table name and B is the database name.
18957c478bd9Sstevel@tonic-gate */
sqliteSrcListAppend(SrcList * pList,Token * pTable,Token * pDatabase)18967c478bd9Sstevel@tonic-gate SrcList *sqliteSrcListAppend(SrcList *pList, Token *pTable, Token *pDatabase){
18977c478bd9Sstevel@tonic-gate if( pList==0 ){
18987c478bd9Sstevel@tonic-gate pList = sqliteMalloc( sizeof(SrcList) );
18997c478bd9Sstevel@tonic-gate if( pList==0 ) return 0;
19007c478bd9Sstevel@tonic-gate pList->nAlloc = 1;
19017c478bd9Sstevel@tonic-gate }
19027c478bd9Sstevel@tonic-gate if( pList->nSrc>=pList->nAlloc ){
19037c478bd9Sstevel@tonic-gate SrcList *pNew;
19047c478bd9Sstevel@tonic-gate pList->nAlloc *= 2;
19057c478bd9Sstevel@tonic-gate pNew = sqliteRealloc(pList,
19067c478bd9Sstevel@tonic-gate sizeof(*pList) + (pList->nAlloc-1)*sizeof(pList->a[0]) );
19077c478bd9Sstevel@tonic-gate if( pNew==0 ){
19087c478bd9Sstevel@tonic-gate sqliteSrcListDelete(pList);
19097c478bd9Sstevel@tonic-gate return 0;
19107c478bd9Sstevel@tonic-gate }
19117c478bd9Sstevel@tonic-gate pList = pNew;
19127c478bd9Sstevel@tonic-gate }
19137c478bd9Sstevel@tonic-gate memset(&pList->a[pList->nSrc], 0, sizeof(pList->a[0]));
19147c478bd9Sstevel@tonic-gate if( pDatabase && pDatabase->z==0 ){
19157c478bd9Sstevel@tonic-gate pDatabase = 0;
19167c478bd9Sstevel@tonic-gate }
19177c478bd9Sstevel@tonic-gate if( pDatabase && pTable ){
19187c478bd9Sstevel@tonic-gate Token *pTemp = pDatabase;
19197c478bd9Sstevel@tonic-gate pDatabase = pTable;
19207c478bd9Sstevel@tonic-gate pTable = pTemp;
19217c478bd9Sstevel@tonic-gate }
19227c478bd9Sstevel@tonic-gate if( pTable ){
19237c478bd9Sstevel@tonic-gate char **pz = &pList->a[pList->nSrc].zName;
19247c478bd9Sstevel@tonic-gate sqliteSetNString(pz, pTable->z, pTable->n, 0);
19257c478bd9Sstevel@tonic-gate if( *pz==0 ){
19267c478bd9Sstevel@tonic-gate sqliteSrcListDelete(pList);
19277c478bd9Sstevel@tonic-gate return 0;
19287c478bd9Sstevel@tonic-gate }else{
19297c478bd9Sstevel@tonic-gate sqliteDequote(*pz);
19307c478bd9Sstevel@tonic-gate }
19317c478bd9Sstevel@tonic-gate }
19327c478bd9Sstevel@tonic-gate if( pDatabase ){
19337c478bd9Sstevel@tonic-gate char **pz = &pList->a[pList->nSrc].zDatabase;
19347c478bd9Sstevel@tonic-gate sqliteSetNString(pz, pDatabase->z, pDatabase->n, 0);
19357c478bd9Sstevel@tonic-gate if( *pz==0 ){
19367c478bd9Sstevel@tonic-gate sqliteSrcListDelete(pList);
19377c478bd9Sstevel@tonic-gate return 0;
19387c478bd9Sstevel@tonic-gate }else{
19397c478bd9Sstevel@tonic-gate sqliteDequote(*pz);
19407c478bd9Sstevel@tonic-gate }
19417c478bd9Sstevel@tonic-gate }
19427c478bd9Sstevel@tonic-gate pList->a[pList->nSrc].iCursor = -1;
19437c478bd9Sstevel@tonic-gate pList->nSrc++;
19447c478bd9Sstevel@tonic-gate return pList;
19457c478bd9Sstevel@tonic-gate }
19467c478bd9Sstevel@tonic-gate
19477c478bd9Sstevel@tonic-gate /*
19487c478bd9Sstevel@tonic-gate ** Assign cursors to all tables in a SrcList
19497c478bd9Sstevel@tonic-gate */
sqliteSrcListAssignCursors(Parse * pParse,SrcList * pList)19507c478bd9Sstevel@tonic-gate void sqliteSrcListAssignCursors(Parse *pParse, SrcList *pList){
19517c478bd9Sstevel@tonic-gate int i;
19527c478bd9Sstevel@tonic-gate for(i=0; i<pList->nSrc; i++){
19537c478bd9Sstevel@tonic-gate if( pList->a[i].iCursor<0 ){
19547c478bd9Sstevel@tonic-gate pList->a[i].iCursor = pParse->nTab++;
19557c478bd9Sstevel@tonic-gate }
19567c478bd9Sstevel@tonic-gate }
19577c478bd9Sstevel@tonic-gate }
19587c478bd9Sstevel@tonic-gate
19597c478bd9Sstevel@tonic-gate /*
19607c478bd9Sstevel@tonic-gate ** Add an alias to the last identifier on the given identifier list.
19617c478bd9Sstevel@tonic-gate */
sqliteSrcListAddAlias(SrcList * pList,Token * pToken)19627c478bd9Sstevel@tonic-gate void sqliteSrcListAddAlias(SrcList *pList, Token *pToken){
19637c478bd9Sstevel@tonic-gate if( pList && pList->nSrc>0 ){
19647c478bd9Sstevel@tonic-gate int i = pList->nSrc - 1;
19657c478bd9Sstevel@tonic-gate sqliteSetNString(&pList->a[i].zAlias, pToken->z, pToken->n, 0);
19667c478bd9Sstevel@tonic-gate sqliteDequote(pList->a[i].zAlias);
19677c478bd9Sstevel@tonic-gate }
19687c478bd9Sstevel@tonic-gate }
19697c478bd9Sstevel@tonic-gate
19707c478bd9Sstevel@tonic-gate /*
19717c478bd9Sstevel@tonic-gate ** Delete an IdList.
19727c478bd9Sstevel@tonic-gate */
sqliteIdListDelete(IdList * pList)19737c478bd9Sstevel@tonic-gate void sqliteIdListDelete(IdList *pList){
19747c478bd9Sstevel@tonic-gate int i;
19757c478bd9Sstevel@tonic-gate if( pList==0 ) return;
19767c478bd9Sstevel@tonic-gate for(i=0; i<pList->nId; i++){
19777c478bd9Sstevel@tonic-gate sqliteFree(pList->a[i].zName);
19787c478bd9Sstevel@tonic-gate }
19797c478bd9Sstevel@tonic-gate sqliteFree(pList->a);
19807c478bd9Sstevel@tonic-gate sqliteFree(pList);
19817c478bd9Sstevel@tonic-gate }
19827c478bd9Sstevel@tonic-gate
19837c478bd9Sstevel@tonic-gate /*
19847c478bd9Sstevel@tonic-gate ** Return the index in pList of the identifier named zId. Return -1
19857c478bd9Sstevel@tonic-gate ** if not found.
19867c478bd9Sstevel@tonic-gate */
sqliteIdListIndex(IdList * pList,const char * zName)19877c478bd9Sstevel@tonic-gate int sqliteIdListIndex(IdList *pList, const char *zName){
19887c478bd9Sstevel@tonic-gate int i;
19897c478bd9Sstevel@tonic-gate if( pList==0 ) return -1;
19907c478bd9Sstevel@tonic-gate for(i=0; i<pList->nId; i++){
19917c478bd9Sstevel@tonic-gate if( sqliteStrICmp(pList->a[i].zName, zName)==0 ) return i;
19927c478bd9Sstevel@tonic-gate }
19937c478bd9Sstevel@tonic-gate return -1;
19947c478bd9Sstevel@tonic-gate }
19957c478bd9Sstevel@tonic-gate
19967c478bd9Sstevel@tonic-gate /*
19977c478bd9Sstevel@tonic-gate ** Delete an entire SrcList including all its substructure.
19987c478bd9Sstevel@tonic-gate */
sqliteSrcListDelete(SrcList * pList)19997c478bd9Sstevel@tonic-gate void sqliteSrcListDelete(SrcList *pList){
20007c478bd9Sstevel@tonic-gate int i;
20017c478bd9Sstevel@tonic-gate if( pList==0 ) return;
20027c478bd9Sstevel@tonic-gate for(i=0; i<pList->nSrc; i++){
20037c478bd9Sstevel@tonic-gate sqliteFree(pList->a[i].zDatabase);
20047c478bd9Sstevel@tonic-gate sqliteFree(pList->a[i].zName);
20057c478bd9Sstevel@tonic-gate sqliteFree(pList->a[i].zAlias);
20067c478bd9Sstevel@tonic-gate if( pList->a[i].pTab && pList->a[i].pTab->isTransient ){
20077c478bd9Sstevel@tonic-gate sqliteDeleteTable(0, pList->a[i].pTab);
20087c478bd9Sstevel@tonic-gate }
20097c478bd9Sstevel@tonic-gate sqliteSelectDelete(pList->a[i].pSelect);
20107c478bd9Sstevel@tonic-gate sqliteExprDelete(pList->a[i].pOn);
20117c478bd9Sstevel@tonic-gate sqliteIdListDelete(pList->a[i].pUsing);
20127c478bd9Sstevel@tonic-gate }
20137c478bd9Sstevel@tonic-gate sqliteFree(pList);
20147c478bd9Sstevel@tonic-gate }
20157c478bd9Sstevel@tonic-gate
20167c478bd9Sstevel@tonic-gate /*
20177c478bd9Sstevel@tonic-gate ** Begin a transaction
20187c478bd9Sstevel@tonic-gate */
sqliteBeginTransaction(Parse * pParse,int onError)20197c478bd9Sstevel@tonic-gate void sqliteBeginTransaction(Parse *pParse, int onError){
20207c478bd9Sstevel@tonic-gate sqlite *db;
20217c478bd9Sstevel@tonic-gate
20227c478bd9Sstevel@tonic-gate if( pParse==0 || (db=pParse->db)==0 || db->aDb[0].pBt==0 ) return;
20237c478bd9Sstevel@tonic-gate if( pParse->nErr || sqlite_malloc_failed ) return;
20247c478bd9Sstevel@tonic-gate if( sqliteAuthCheck(pParse, SQLITE_TRANSACTION, "BEGIN", 0, 0) ) return;
20257c478bd9Sstevel@tonic-gate if( db->flags & SQLITE_InTrans ){
20267c478bd9Sstevel@tonic-gate sqliteErrorMsg(pParse, "cannot start a transaction within a transaction");
20277c478bd9Sstevel@tonic-gate return;
20287c478bd9Sstevel@tonic-gate }
20297c478bd9Sstevel@tonic-gate sqliteBeginWriteOperation(pParse, 0, 0);
20307c478bd9Sstevel@tonic-gate if( !pParse->explain ){
20317c478bd9Sstevel@tonic-gate db->flags |= SQLITE_InTrans;
20327c478bd9Sstevel@tonic-gate db->onError = onError;
20337c478bd9Sstevel@tonic-gate }
20347c478bd9Sstevel@tonic-gate }
20357c478bd9Sstevel@tonic-gate
20367c478bd9Sstevel@tonic-gate /*
20377c478bd9Sstevel@tonic-gate ** Commit a transaction
20387c478bd9Sstevel@tonic-gate */
sqliteCommitTransaction(Parse * pParse)20397c478bd9Sstevel@tonic-gate void sqliteCommitTransaction(Parse *pParse){
20407c478bd9Sstevel@tonic-gate sqlite *db;
20417c478bd9Sstevel@tonic-gate
20427c478bd9Sstevel@tonic-gate if( pParse==0 || (db=pParse->db)==0 || db->aDb[0].pBt==0 ) return;
20437c478bd9Sstevel@tonic-gate if( pParse->nErr || sqlite_malloc_failed ) return;
20447c478bd9Sstevel@tonic-gate if( sqliteAuthCheck(pParse, SQLITE_TRANSACTION, "COMMIT", 0, 0) ) return;
20457c478bd9Sstevel@tonic-gate if( (db->flags & SQLITE_InTrans)==0 ){
20467c478bd9Sstevel@tonic-gate sqliteErrorMsg(pParse, "cannot commit - no transaction is active");
20477c478bd9Sstevel@tonic-gate return;
20487c478bd9Sstevel@tonic-gate }
20497c478bd9Sstevel@tonic-gate if( !pParse->explain ){
20507c478bd9Sstevel@tonic-gate db->flags &= ~SQLITE_InTrans;
20517c478bd9Sstevel@tonic-gate }
20527c478bd9Sstevel@tonic-gate sqliteEndWriteOperation(pParse);
20537c478bd9Sstevel@tonic-gate if( !pParse->explain ){
20547c478bd9Sstevel@tonic-gate db->onError = OE_Default;
20557c478bd9Sstevel@tonic-gate }
20567c478bd9Sstevel@tonic-gate }
20577c478bd9Sstevel@tonic-gate
20587c478bd9Sstevel@tonic-gate /*
20597c478bd9Sstevel@tonic-gate ** Rollback a transaction
20607c478bd9Sstevel@tonic-gate */
sqliteRollbackTransaction(Parse * pParse)20617c478bd9Sstevel@tonic-gate void sqliteRollbackTransaction(Parse *pParse){
20627c478bd9Sstevel@tonic-gate sqlite *db;
20637c478bd9Sstevel@tonic-gate Vdbe *v;
20647c478bd9Sstevel@tonic-gate
20657c478bd9Sstevel@tonic-gate if( pParse==0 || (db=pParse->db)==0 || db->aDb[0].pBt==0 ) return;
20667c478bd9Sstevel@tonic-gate if( pParse->nErr || sqlite_malloc_failed ) return;
20677c478bd9Sstevel@tonic-gate if( sqliteAuthCheck(pParse, SQLITE_TRANSACTION, "ROLLBACK", 0, 0) ) return;
20687c478bd9Sstevel@tonic-gate if( (db->flags & SQLITE_InTrans)==0 ){
20697c478bd9Sstevel@tonic-gate sqliteErrorMsg(pParse, "cannot rollback - no transaction is active");
2070*1da57d55SToomas Soome return;
20717c478bd9Sstevel@tonic-gate }
20727c478bd9Sstevel@tonic-gate v = sqliteGetVdbe(pParse);
20737c478bd9Sstevel@tonic-gate if( v ){
20747c478bd9Sstevel@tonic-gate sqliteVdbeAddOp(v, OP_Rollback, 0, 0);
20757c478bd9Sstevel@tonic-gate }
20767c478bd9Sstevel@tonic-gate if( !pParse->explain ){
20777c478bd9Sstevel@tonic-gate db->flags &= ~SQLITE_InTrans;
20787c478bd9Sstevel@tonic-gate db->onError = OE_Default;
20797c478bd9Sstevel@tonic-gate }
20807c478bd9Sstevel@tonic-gate }
20817c478bd9Sstevel@tonic-gate
20827c478bd9Sstevel@tonic-gate /*
20837c478bd9Sstevel@tonic-gate ** Generate VDBE code that will verify the schema cookie for all
20847c478bd9Sstevel@tonic-gate ** named database files.
20857c478bd9Sstevel@tonic-gate */
sqliteCodeVerifySchema(Parse * pParse,int iDb)20867c478bd9Sstevel@tonic-gate void sqliteCodeVerifySchema(Parse *pParse, int iDb){
20877c478bd9Sstevel@tonic-gate sqlite *db = pParse->db;
20887c478bd9Sstevel@tonic-gate Vdbe *v = sqliteGetVdbe(pParse);
20897c478bd9Sstevel@tonic-gate assert( iDb>=0 && iDb<db->nDb );
20907c478bd9Sstevel@tonic-gate assert( db->aDb[iDb].pBt!=0 );
20917c478bd9Sstevel@tonic-gate if( iDb!=1 && !DbHasProperty(db, iDb, DB_Cookie) ){
20927c478bd9Sstevel@tonic-gate sqliteVdbeAddOp(v, OP_VerifyCookie, iDb, db->aDb[iDb].schema_cookie);
20937c478bd9Sstevel@tonic-gate DbSetProperty(db, iDb, DB_Cookie);
20947c478bd9Sstevel@tonic-gate }
20957c478bd9Sstevel@tonic-gate }
20967c478bd9Sstevel@tonic-gate
20977c478bd9Sstevel@tonic-gate /*
20987c478bd9Sstevel@tonic-gate ** Generate VDBE code that prepares for doing an operation that
20997c478bd9Sstevel@tonic-gate ** might change the database.
21007c478bd9Sstevel@tonic-gate **
21017c478bd9Sstevel@tonic-gate ** This routine starts a new transaction if we are not already within
21027c478bd9Sstevel@tonic-gate ** a transaction. If we are already within a transaction, then a checkpoint
21037c478bd9Sstevel@tonic-gate ** is set if the setCheckpoint parameter is true. A checkpoint should
21047c478bd9Sstevel@tonic-gate ** be set for operations that might fail (due to a constraint) part of
21057c478bd9Sstevel@tonic-gate ** the way through and which will need to undo some writes without having to
21067c478bd9Sstevel@tonic-gate ** rollback the whole transaction. For operations where all constraints
21077c478bd9Sstevel@tonic-gate ** can be checked before any changes are made to the database, it is never
21087c478bd9Sstevel@tonic-gate ** necessary to undo a write and the checkpoint should not be set.
21097c478bd9Sstevel@tonic-gate **
21107c478bd9Sstevel@tonic-gate ** Only database iDb and the temp database are made writable by this call.
21117c478bd9Sstevel@tonic-gate ** If iDb==0, then the main and temp databases are made writable. If
21127c478bd9Sstevel@tonic-gate ** iDb==1 then only the temp database is made writable. If iDb>1 then the
21137c478bd9Sstevel@tonic-gate ** specified auxiliary database and the temp database are made writable.
21147c478bd9Sstevel@tonic-gate */
sqliteBeginWriteOperation(Parse * pParse,int setCheckpoint,int iDb)21157c478bd9Sstevel@tonic-gate void sqliteBeginWriteOperation(Parse *pParse, int setCheckpoint, int iDb){
21167c478bd9Sstevel@tonic-gate Vdbe *v;
21177c478bd9Sstevel@tonic-gate sqlite *db = pParse->db;
21187c478bd9Sstevel@tonic-gate if( DbHasProperty(db, iDb, DB_Locked) ) return;
21197c478bd9Sstevel@tonic-gate v = sqliteGetVdbe(pParse);
21207c478bd9Sstevel@tonic-gate if( v==0 ) return;
21217c478bd9Sstevel@tonic-gate if( !db->aDb[iDb].inTrans ){
21227c478bd9Sstevel@tonic-gate sqliteVdbeAddOp(v, OP_Transaction, iDb, 0);
21237c478bd9Sstevel@tonic-gate DbSetProperty(db, iDb, DB_Locked);
21247c478bd9Sstevel@tonic-gate sqliteCodeVerifySchema(pParse, iDb);
21257c478bd9Sstevel@tonic-gate if( iDb!=1 ){
21267c478bd9Sstevel@tonic-gate sqliteBeginWriteOperation(pParse, setCheckpoint, 1);
21277c478bd9Sstevel@tonic-gate }
21287c478bd9Sstevel@tonic-gate }else if( setCheckpoint ){
21297c478bd9Sstevel@tonic-gate sqliteVdbeAddOp(v, OP_Checkpoint, iDb, 0);
21307c478bd9Sstevel@tonic-gate DbSetProperty(db, iDb, DB_Locked);
21317c478bd9Sstevel@tonic-gate }
21327c478bd9Sstevel@tonic-gate }
21337c478bd9Sstevel@tonic-gate
21347c478bd9Sstevel@tonic-gate /*
21357c478bd9Sstevel@tonic-gate ** Generate code that concludes an operation that may have changed
21367c478bd9Sstevel@tonic-gate ** the database. If a statement transaction was started, then emit
21377c478bd9Sstevel@tonic-gate ** an OP_Commit that will cause the changes to be committed to disk.
21387c478bd9Sstevel@tonic-gate **
21397c478bd9Sstevel@tonic-gate ** Note that checkpoints are automatically committed at the end of
2140*1da57d55SToomas Soome ** a statement. Note also that there can be multiple calls to
21417c478bd9Sstevel@tonic-gate ** sqliteBeginWriteOperation() but there should only be a single
21427c478bd9Sstevel@tonic-gate ** call to sqliteEndWriteOperation() at the conclusion of the statement.
21437c478bd9Sstevel@tonic-gate */
sqliteEndWriteOperation(Parse * pParse)21447c478bd9Sstevel@tonic-gate void sqliteEndWriteOperation(Parse *pParse){
21457c478bd9Sstevel@tonic-gate Vdbe *v;
21467c478bd9Sstevel@tonic-gate sqlite *db = pParse->db;
21477c478bd9Sstevel@tonic-gate if( pParse->trigStack ) return; /* if this is in a trigger */
21487c478bd9Sstevel@tonic-gate v = sqliteGetVdbe(pParse);
21497c478bd9Sstevel@tonic-gate if( v==0 ) return;
21507c478bd9Sstevel@tonic-gate if( db->flags & SQLITE_InTrans ){
21517c478bd9Sstevel@tonic-gate /* A BEGIN has executed. Do not commit until we see an explicit
21527c478bd9Sstevel@tonic-gate ** COMMIT statement. */
21537c478bd9Sstevel@tonic-gate }else{
21547c478bd9Sstevel@tonic-gate sqliteVdbeAddOp(v, OP_Commit, 0, 0);
21557c478bd9Sstevel@tonic-gate }
21567c478bd9Sstevel@tonic-gate }
2157