/library/Library/WP7/SQLiteDriver/sqlite/build_c.cs
C# | 4331 lines | 3723 code | 86 blank | 522 comment | 288 complexity | e464bb4162b4f5b8e141695420744dce MD5 | raw file
Large files files are truncated, but you can click here to view the full file
- using System;
- using System.Diagnostics;
- using System.IO;
- using System.Text;
- using i16 = System.Int16;
- using u8 = System.Byte;
- using u16 = System.UInt16;
- using u32 = System.UInt32;
- using Pgno = System.UInt32;
- namespace Community.CsharpSqlite
- {
- public partial class Sqlite3
- {
- /*
- ** 2001 September 15
- **
- ** The author disclaims copyright to this source code. In place of
- ** a legal notice, here is a blessing:
- **
- ** May you do good and not evil.
- ** May you find forgiveness for yourself and forgive others.
- ** May you share freely, never taking more than you give.
- **
- *************************************************************************
- ** This file contains C code routines that are called by the SQLite parser
- ** when syntax rules are reduced. The routines in this file handle the
- ** following kinds of SQL syntax:
- **
- ** CREATE TABLE
- ** DROP TABLE
- ** CREATE INDEX
- ** DROP INDEX
- ** creating ID lists
- ** BEGIN TRANSACTION
- ** COMMIT
- ** ROLLBACK
- *************************************************************************
- ** Included in SQLite3 port to C#-SQLite; 2008 Noah B Hart
- ** C#-SQLite is an independent reimplementation of the SQLite software library
- **
- ** SQLITE_SOURCE_ID: 2010-12-07 20:14:09 a586a4deeb25330037a49df295b36aaf624d0f45
- **
- *************************************************************************
- */
- //#include "sqliteInt.h"
- /*
- ** This routine is called when a new SQL statement is beginning to
- ** be parsed. Initialize the pParse structure as needed.
- */
- static void sqlite3BeginParse( Parse pParse, int explainFlag )
- {
- pParse.explain = (byte)explainFlag;
- pParse.nVar = 0;
- }
- #if !SQLITE_OMIT_SHARED_CACHE
- /*
- ** The TableLock structure is only used by the sqlite3TableLock() and
- ** codeTableLocks() functions.
- */
- //struct TableLock {
- // int iDb; /* The database containing the table to be locked */
- // int iTab; /* The root page of the table to be locked */
- // u8 isWriteLock; /* True for write lock. False for a read lock */
- // string zName; /* Name of the table */
- //};
- public class TableLock
- {
- public int iDb; /* The database containing the table to be locked */
- public int iTab; /* The root page of the table to be locked */
- public u8 isWriteLock; /* True for write lock. False for a read lock */
- public string zName; /* Name of the table */
- }
- /*
- ** Record the fact that we want to lock a table at run-time.
- **
- ** The table to be locked has root page iTab and is found in database iDb.
- ** A read or a write lock can be taken depending on isWritelock.
- **
- ** This routine just records the fact that the lock is desired. The
- ** code to make the lock occur is generated by a later call to
- ** codeTableLocks() which occurs during sqlite3FinishCoding().
- */
- void sqlite3TableLock(
- Parse *pParse, /* Parsing context */
- int iDb, /* Index of the database containing the table to lock */
- int iTab, /* Root page number of the table to be locked */
- u8 isWriteLock, /* True for a write lock */
- const char *zName /* Name of the table to be locked */
- ){
- Parse *pToplevel = sqlite3ParseToplevel(pParse);
- int i;
- int nBytes;
- TableLock *p;
- assert( iDb>=0 );
- for(i=0; i<pToplevel->nTableLock; i++){
- p = &pToplevel->aTableLock[i];
- if( p->iDb==iDb && p->iTab==iTab ){
- p->isWriteLock = (p->isWriteLock || isWriteLock);
- return;
- }
- }
- nBytes = sizeof(TableLock) * (pToplevel->nTableLock+1);
- pToplevel->aTableLock =
- sqlite3DbReallocOrFree(pToplevel->db, pToplevel->aTableLock, nBytes);
- if( pToplevel->aTableLock ){
- p = &pToplevel->aTableLock[pToplevel->nTableLock++];
- p->iDb = iDb;
- p->iTab = iTab;
- p->isWriteLock = isWriteLock;
- p->zName = zName;
- }else{
- pToplevel->nTableLock = 0;
- pToplevel->db->mallocFailed = 1;
- }
- }
- /*
- ** Code an OP_TableLock instruction for each table locked by the
- ** statement (configured by calls to sqlite3TableLock()).
- */
- static void codeTableLocks( Parse pParse )
- {
- int i;
- Vdbe pVdbe;
- pVdbe = sqlite3GetVdbe( pParse );
- Debug.Assert( pVdbe != null ); /* sqlite3GetVdbe cannot fail: VDBE already allocated */
- for ( i = 0 ; i < pParse.nTableLock ; i++ )
- {
- TableLock p = pParse.aTableLock[i];
- int p1 = p.iDb;
- sqlite3VdbeAddOp4( pVdbe, OP_TableLock, p1, p.iTab, p.isWriteLock,
- p.zName, P4_STATIC );
- }
- }
- #else
- // #define codeTableLocks(x)
- static void codeTableLocks( Parse pParse )
- {
- }
- #endif
- /*
- ** This routine is called after a single SQL statement has been
- ** parsed and a VDBE program to execute that statement has been
- ** prepared. This routine puts the finishing touches on the
- ** VDBE program and resets the pParse structure for the next
- ** parse.
- **
- ** Note that if an error occurred, it might be the case that
- ** no VDBE code was generated.
- */
- static void sqlite3FinishCoding( Parse pParse )
- {
- sqlite3 db;
- Vdbe v;
- db = pParse.db;
- // if ( db.mallocFailed != 0 ) return;
- if ( pParse.nested != 0 )
- return;
- if ( pParse.nErr != 0 )
- return;
- /* Begin by generating some termination code at the end of the
- ** vdbe program
- */
- v = sqlite3GetVdbe( pParse );
- Debug.Assert( 0 == pParse.isMultiWrite
- || sqlite3VdbeAssertMayAbort( v, pParse.mayAbort ) != 0 );
- if ( v != null )
- {
- sqlite3VdbeAddOp0( v, OP_Halt );
- /* The cookie mask contains one bit for each database file open.
- ** (Bit 0 is for main, bit 1 is for temp, and so forth.) Bits are
- ** set for each database that is used. Generate code to start a
- ** transaction on each used database and to verify the schema cookie
- ** on each used database.
- */
- if ( pParse.cookieGoto > 0 )
- {
- u32 mask;
- int iDb;
- sqlite3VdbeJumpHere( v, pParse.cookieGoto - 1 );
- for ( iDb = 0, mask = 1; iDb < db.nDb; mask <<= 1, iDb++ )
- {
- if ( ( mask & pParse.cookieMask ) == 0 )
- continue;
- sqlite3VdbeUsesBtree( v, iDb );
- sqlite3VdbeAddOp2( v, OP_Transaction, iDb, ( mask & pParse.writeMask ) != 0 );
- if ( db.init.busy == 0 )
- {
- sqlite3VdbeAddOp2( v, OP_VerifyCookie, iDb, pParse.cookieValue[iDb] );
- }
- }
- #if !SQLITE_OMIT_VIRTUALTABLE
- {
- int i;
- for(i=0; i<pParse.nVtabLock; i++){
- char *vtab = (char *)sqlite3GetVTable(db, pParse->apVtabLock[i]);
- sqlite3VdbeAddOp4(v, OP_VBegin, 0, 0, 0, vtab, P4_VTAB);
- }
- pParse.nVtabLock = 0;
- }
- #endif
- /* Once all the cookies have been verified and transactions opened,
- ** obtain the required table-locks. This is a no-op unless the
- ** shared-cache feature is enabled.
- */
- codeTableLocks( pParse );
- /* Initialize any AUTOINCREMENT data structures required.
- */
- sqlite3AutoincrementBegin( pParse );
- /* Finally, jump back to the beginning of the executable code. */
- sqlite3VdbeAddOp2( v, OP_Goto, 0, pParse.cookieGoto );
- }
- }
- /* Get the VDBE program ready for execution
- */
- if ( v != null && ALWAYS( pParse.nErr == 0 ) /* && 0 == db.mallocFailed */ )
- {
- #if SQLITE_DEBUG
- TextWriter trace = ( db.flags & SQLITE_VdbeTrace ) != 0 ? Console.Out : null;
- sqlite3VdbeTrace( v, trace );
- #endif
- Debug.Assert( pParse.iCacheLevel == 0 ); /* Disables and re-enables match */
- /* A minimum of one cursor is required if autoincrement is used
- * See ticket [a696379c1f08866] */
- if ( pParse.pAinc != null && pParse.nTab == 0 )
- pParse.nTab = 1;
- sqlite3VdbeMakeReady( v, pParse.nVar, pParse.nMem,
- pParse.nTab, pParse.nMaxArg, pParse.explain,
- ( pParse.isMultiWrite != 0 && pParse.mayAbort != 0 ) ? 1 : 0 );
- pParse.rc = SQLITE_DONE;
- pParse.colNamesSet = 0;
- }
- else
- {
- pParse.rc = SQLITE_ERROR;
- }
- pParse.nTab = 0;
- pParse.nMem = 0;
- pParse.nSet = 0;
- pParse.nVar = 0;
- pParse.cookieMask = 0;
- pParse.cookieGoto = 0;
- }
- /*
- ** Run the parser and code generator recursively in order to generate
- ** code for the SQL statement given onto the end of the pParse context
- ** currently under construction. When the parser is run recursively
- ** this way, the final OP_Halt is not appended and other initialization
- ** and finalization steps are omitted because those are handling by the
- ** outermost parser.
- **
- ** Not everything is nestable. This facility is designed to permit
- ** INSERT, UPDATE, and DELETE operations against SQLITE_MASTER. Use
- ** care if you decide to try to use this routine for some other purposes.
- */
- static void sqlite3NestedParse( Parse pParse, string zFormat, params object[] ap )
- {
- string zSql; // char *zSql;
- string zErrMsg = "";// char* zErrMsg = 0;
- sqlite3 db = pParse.db;
- //# define SAVE_SZ (Parse.Length - offsetof(Parse,nVar))
- // char saveBuf[SAVE_SZ];
- if ( pParse.nErr != 0 )
- return;
- Debug.Assert( pParse.nested < 10 ); /* Nesting should only be of limited depth */
- // va_list ap;
- lock ( lock_va_list )
- {
- va_start( ap, zFormat );
- zSql = sqlite3VMPrintf( db, zFormat, ap );
- va_end( ref ap );
- }
- //if( zSql=="" ){
- // return; /* A malloc must have failed */
- //}
- lock ( nestingLock )
- {
- pParse.nested++;
- pParse.SaveMembers(); // memcpy(saveBuf, pParse.nVar, SAVE_SZ);
- pParse.ResetMembers(); // memset(pParse.nVar, 0, SAVE_SZ);
- sqlite3RunParser( pParse, zSql, ref zErrMsg );
- sqlite3DbFree( db, ref zErrMsg );
- sqlite3DbFree( db, ref zSql );
- pParse.RestoreMembers(); // memcpy(pParse.nVar, saveBuf, SAVE_SZ);
- pParse.nested--;
- }
- }
- static Object nestingLock = new Object();
- /*
- ** Locate the in-memory structure that describes a particular database
- ** table given the name of that table and (optionally) the name of the
- ** database containing the table. Return NULL if not found.
- **
- ** If zDatabase is 0, all databases are searched for the table and the
- ** first matching table is returned. (No checking for duplicate table
- ** names is done.) The search order is TEMP first, then MAIN, then any
- ** auxiliary databases added using the ATTACH command.
- **
- ** See also sqlite3LocateTable().
- */
- static Table sqlite3FindTable( sqlite3 db, string zName, string zDatabase )
- {
- Table p = null;
- int i;
- int nName;
- Debug.Assert( zName != null );
- nName = sqlite3Strlen30( zName );
- for ( i = OMIT_TEMPDB; i < db.nDb; i++ )
- {
- int j = ( i < 2 ) ? i ^ 1 : i; /* Search TEMP before MAIN */
- if ( zDatabase != null && !zDatabase.Equals( db.aDb[j].zName, StringComparison.InvariantCultureIgnoreCase ) )
- continue;
- p = sqlite3HashFind( db.aDb[j].pSchema.tblHash, zName, nName, (Table)null );
- if ( p != null )
- break;
- }
- return p;
- }
- /*
- ** Locate the in-memory structure that describes a particular database
- ** table given the name of that table and (optionally) the name of the
- ** database containing the table. Return NULL if not found. Also leave an
- ** error message in pParse.zErrMsg.
- **
- ** The difference between this routine and sqlite3FindTable() is that this
- ** routine leaves an error message in pParse.zErrMsg where
- ** sqlite3FindTable() does not.
- */
- static Table sqlite3LocateTable(
- Parse pParse, /* context in which to report errors */
- int isView, /* True if looking for a VIEW rather than a TABLE */
- string zName, /* Name of the table we are looking for */
- string zDbase /* Name of the database. Might be NULL */
- )
- {
- Table p;
- /* Read the database schema. If an error occurs, leave an error message
- ** and code in pParse and return NULL. */
- if ( SQLITE_OK != sqlite3ReadSchema( pParse ) )
- {
- return null;
- }
- p = sqlite3FindTable( pParse.db, zName, zDbase );
- if ( p == null )
- {
- string zMsg = isView != 0 ? "no such view" : "no such table";
- if ( zDbase != null )
- {
- sqlite3ErrorMsg( pParse, "%s: %s.%s", zMsg, zDbase, zName );
- }
- else
- {
- sqlite3ErrorMsg( pParse, "%s: %s", zMsg, zName );
- }
- pParse.checkSchema = 1;
- }
- return p;
- }
- /*
- ** Locate the in-memory structure that describes
- ** a particular index given the name of that index
- ** and the name of the database that contains the index.
- ** Return NULL if not found.
- **
- ** If zDatabase is 0, all databases are searched for the
- ** table and the first matching index is returned. (No checking
- ** for duplicate index names is done.) The search order is
- ** TEMP first, then MAIN, then any auxiliary databases added
- ** using the ATTACH command.
- */
- static Index sqlite3FindIndex( sqlite3 db, string zName, string zDb )
- {
- Index p = null;
- int i;
- int nName = sqlite3Strlen30( zName );
- for ( i = OMIT_TEMPDB; i < db.nDb; i++ )
- {
- int j = ( i < 2 ) ? i ^ 1 : i; /* Search TEMP before MAIN */
- Schema pSchema = db.aDb[j].pSchema;
- Debug.Assert( pSchema != null );
- if ( zDb != null && !zDb.Equals( db.aDb[j].zName, StringComparison.InvariantCultureIgnoreCase ) )
- continue;
- p = sqlite3HashFind( pSchema.idxHash, zName, nName, (Index)null );
- if ( p != null )
- break;
- }
- return p;
- }
- /*
- ** Reclaim the memory used by an index
- */
- static void freeIndex( sqlite3 db, ref Index p )
- {
- #if !SQLITE_OMIT_ANALYZE
- sqlite3DeleteIndexSamples( db, p );
- #endif
- sqlite3DbFree( db, ref p.zColAff );
- sqlite3DbFree( db, ref p );
- }
- /*
- ** For the index called zIdxName which is found in the database iDb,
- ** unlike that index from its Table then remove the index from
- ** the index hash table and free all memory structures associated
- ** with the index.
- */
- static void sqlite3UnlinkAndDeleteIndex( sqlite3 db, int iDb, string zIdxName )
- {
- Index pIndex;
- int len;
- Hash pHash = db.aDb[iDb].pSchema.idxHash;
- len = sqlite3Strlen30( zIdxName );
- pIndex = sqlite3HashInsert( ref pHash, zIdxName, len, (Index)null );
- if ( pIndex != null )
- {
- if ( pIndex.pTable.pIndex == pIndex )
- {
- pIndex.pTable.pIndex = pIndex.pNext;
- }
- else
- {
- Index p;
- /* Justification of ALWAYS(); The index must be on the list of
- ** indices. */
- p = pIndex.pTable.pIndex;
- while ( ALWAYS( p != null ) && p.pNext != pIndex )
- {
- p = p.pNext;
- }
- if ( ALWAYS( p != null && p.pNext == pIndex ) )
- {
- p.pNext = pIndex.pNext;
- }
- }
- freeIndex( db, ref pIndex );
- }
- db.flags |= SQLITE_InternChanges;
- }
- /*
- ** Erase all schema information from the in-memory hash tables of
- ** a single database. This routine is called to reclaim memory
- ** before the database closes. It is also called during a rollback
- ** if there were schema changes during the transaction or if a
- ** schema-cookie mismatch occurs.
- **
- ** If iDb==0 then reset the internal schema tables for all database
- ** files. If iDb>=1 then reset the internal schema for only the
- ** single file indicated.
- */
- static void sqlite3ResetInternalSchema( sqlite3 db, int iDb )
- {
- int i, j;
- Debug.Assert( iDb >= 0 && iDb < db.nDb );
- if ( iDb == 0 )
- {
- sqlite3BtreeEnterAll( db );
- }
- for ( i = iDb; i < db.nDb; i++ )
- {
- Db pDb = db.aDb[i];
- if ( pDb.pSchema != null )
- {
- Debug.Assert( i == 1 || ( pDb.pBt != null && sqlite3BtreeHoldsMutex( pDb.pBt ) ) );
- Debug.Assert( i == 1 || ( pDb.pBt != null ) );
- sqlite3SchemaFree( pDb.pSchema );
- }
- if ( iDb > 0 )
- return;
- }
- Debug.Assert( iDb == 0 );
- db.flags &= ~SQLITE_InternChanges;
- sqlite3VtabUnlockList( db );
- sqlite3BtreeLeaveAll( db );
- /* If one or more of the auxiliary database files has been closed,
- ** then remove them from the auxiliary database list. We take the
- ** opportunity to do this here since we have just deleted all of the
- ** schema hash tables and therefore do not have to make any changes
- ** to any of those tables.
- */
- for ( i = j = 2; i < db.nDb; i++ )
- {
- Db pDb = db.aDb[i];
- if ( pDb.pBt == null )
- {
- sqlite3DbFree( db, ref pDb.zName );
- continue;
- }
- if ( j < i )
- {
- db.aDb[j] = db.aDb[i];
- }
- j++;
- }
- if ( db.nDb != j )
- db.aDb[j] = new Db();//memset(db.aDb[j], 0, (db.nDb-j)*sizeof(db.aDb[j]));
- db.nDb = j;
- if ( db.nDb <= 2 && db.aDb != db.aDbStatic )
- {
- Array.Copy( db.aDb, db.aDbStatic, 2 );// memcpy(db.aDbStatic, db.aDb, 2*sizeof(db.aDb[0]));
- sqlite3DbFree( db, ref db.aDb );
- //db.aDb = db.aDbStatic;
- }
- }
- /*
- ** This routine is called when a commit occurs.
- */
- static void sqlite3CommitInternalChanges( sqlite3 db )
- {
- db.flags &= ~SQLITE_InternChanges;
- }
- /*
- ** Delete memory allocated for the column names of a table or view (the
- ** Table.aCol[] array).
- */
- static void sqliteDeleteColumnNames( sqlite3 db, Table pTable )
- {
- int i;
- Column pCol;
- Debug.Assert( pTable != null );
- for ( i = 0; i < pTable.nCol; i++ )
- {
- pCol = pTable.aCol[i];
- if ( pCol != null )
- {
- sqlite3DbFree( db, ref pCol.zName );
- sqlite3ExprDelete( db, ref pCol.pDflt );
- sqlite3DbFree( db, ref pCol.zDflt );
- sqlite3DbFree( db, ref pCol.zType );
- sqlite3DbFree( db, ref pCol.zColl );
- }
- }
- }
- /*
- ** Remove the memory data structures associated with the given
- ** Table. No changes are made to disk by this routine.
- **
- ** This routine just deletes the data structure. It does not unlink
- ** the table data structure from the hash table. But it does destroy
- ** memory structures of the indices and foreign keys associated with
- ** the table.
- */
- static void sqlite3DeleteTable( sqlite3 db, ref Table pTable )
- {
- Index pIndex;
- Index pNext;
- Debug.Assert( null == pTable || pTable.nRef > 0 );
- /* Do not delete the table until the reference count reaches zero. */
- if ( null == pTable )
- return;
- if ( (// ( !db || db->pnBytesFreed == 0 ) &&
- ( --pTable.nRef ) > 0 ) )
- return;
- /* Delete all indices associated with this table. */
- for ( pIndex = pTable.pIndex; pIndex != null; pIndex = pNext )
- {
- pNext = pIndex.pNext;
- Debug.Assert( pIndex.pSchema == pTable.pSchema );
- //if( null==db || db.pnBytesFreed==0 ){
- string zName = pIndex.zName;
- //
- #if !NDEBUG || SQLITE_COVERAGE_TEST
- // TESTONLY ( Index pOld = ) sqlite3HashInsert(
- //ref pIndex.pSchema.idxHash, zName, sqlite3Strlen30(zName), 0
- // );
- Index pOld = sqlite3HashInsert(
- ref pIndex.pSchema.idxHash, zName, sqlite3Strlen30( zName ), (Index)null
- );
- Debug.Assert( pOld == pIndex || pOld == null );
- #else
- // TESTONLY ( Index pOld = ) sqlite3HashInsert(
- //ref pIndex.pSchema.idxHash, zName, sqlite3Strlen30(zName), 0
- // );
- sqlite3HashInsert(
- ref pIndex.pSchema.idxHash, zName, sqlite3Strlen30(zName),(Index)null
- );
- #endif
- //}
- freeIndex( db, ref pIndex );
- }
- /* Delete any foreign keys attached to this table. */
- sqlite3FkDelete( db, pTable );
- /* Delete the Table structure itself.
- */
- sqliteDeleteColumnNames( db, pTable );
- sqlite3DbFree( db, ref pTable.zName );
- sqlite3DbFree( db, ref pTable.zColAff );
- sqlite3SelectDelete( db, ref pTable.pSelect );
- #if !SQLITE_OMIT_CHECK
- sqlite3ExprDelete( db, ref pTable.pCheck );
- #endif
- #if !SQLITE_OMIT_VIRTUALTABLE
- sqlite3VtabClear(db, pTable);
- #endif
- pTable = null;// sqlite3DbFree( db, ref pTable );
- }
- /*
- ** Unlink the given table from the hash tables and the delete the
- ** table structure with all its indices and foreign keys.
- */
- static void sqlite3UnlinkAndDeleteTable( sqlite3 db, int iDb, string zTabName )
- {
- Table p;
- Db pDb;
- Debug.Assert( db != null );
- Debug.Assert( iDb >= 0 && iDb < db.nDb );
- Debug.Assert( zTabName != null );
- testcase( zTabName.Length == 0 ); /* Zero-length table names are allowed */
- pDb = db.aDb[iDb];
- p = sqlite3HashInsert( ref pDb.pSchema.tblHash, zTabName,
- sqlite3Strlen30( zTabName ), (Table)null );
- sqlite3DeleteTable( db, ref p );
- db.flags |= SQLITE_InternChanges;
- }
- /*
- ** Given a token, return a string that consists of the text of that
- ** token. Space to hold the returned string
- ** is obtained from sqliteMalloc() and must be freed by the calling
- ** function.
- **
- ** Any quotation marks (ex: "name", 'name', [name], or `name`) that
- ** surround the body of the token are removed.
- **
- ** Tokens are often just pointers into the original SQL text and so
- ** are not \000 terminated and are not persistent. The returned string
- ** is \000 terminated and is persistent.
- */
- static string sqlite3NameFromToken( sqlite3 db, Token pName )
- {
- string zName;
- if ( pName != null && pName.z != null )
- {
- zName = pName.z.Substring( 0, pName.n );//sqlite3DbStrNDup(db, (char*)pName.z, pName.n);
- sqlite3Dequote( ref zName );
- }
- else
- {
- return null;
- }
- return zName;
- }
- /*
- ** Open the sqlite_master table stored in database number iDb for
- ** writing. The table is opened using cursor 0.
- */
- static void sqlite3OpenMasterTable( Parse p, int iDb )
- {
- Vdbe v = sqlite3GetVdbe( p );
- sqlite3TableLock( p, iDb, MASTER_ROOT, 1, SCHEMA_TABLE( iDb ) );
- sqlite3VdbeAddOp3( v, OP_OpenWrite, 0, MASTER_ROOT, iDb );
- sqlite3VdbeChangeP4( v, -1, (int)5, P4_INT32 ); /* 5 column table */
- if ( p.nTab == 0 )
- {
- p.nTab = 1;
- }
- }
- /*
- ** Parameter zName points to a nul-terminated buffer containing the name
- ** of a database ("main", "temp" or the name of an attached db). This
- ** function returns the index of the named database in db->aDb[], or
- ** -1 if the named db cannot be found.
- */
- static int sqlite3FindDbName( sqlite3 db, string zName )
- {
- int i = -1; /* Database number */
- if ( zName != null )
- {
- Db pDb;
- int n = sqlite3Strlen30( zName );
- for ( i = ( db.nDb - 1 ); i >= 0; i-- )
- {
- pDb = db.aDb[i];
- if ( ( OMIT_TEMPDB == 0 || i != 1 ) && n == sqlite3Strlen30( pDb.zName ) &&
- pDb.zName.Equals( zName, StringComparison.InvariantCultureIgnoreCase ) )
- {
- break;
- }
- }
- }
- return i;
- }
- /*
- ** The token *pName contains the name of a database (either "main" or
- ** "temp" or the name of an attached db). This routine returns the
- ** index of the named database in db->aDb[], or -1 if the named db
- ** does not exist.
- */
- static int sqlite3FindDb( sqlite3 db, Token pName )
- {
- int i; /* Database number */
- string zName; /* Name we are searching for */
- zName = sqlite3NameFromToken( db, pName );
- i = sqlite3FindDbName( db, zName );
- sqlite3DbFree( db, ref zName );
- return i;
- }
- /* The table or view or trigger name is passed to this routine via tokens
- ** pName1 and pName2. If the table name was fully qualified, for example:
- **
- ** CREATE TABLE xxx.yyy (...);
- **
- ** Then pName1 is set to "xxx" and pName2 "yyy". On the other hand if
- ** the table name is not fully qualified, i.e.:
- **
- ** CREATE TABLE yyy(...);
- **
- ** Then pName1 is set to "yyy" and pName2 is "".
- **
- ** This routine sets the ppUnqual pointer to point at the token (pName1 or
- ** pName2) that stores the unqualified table name. The index of the
- ** database "xxx" is returned.
- */
- static int sqlite3TwoPartName(
- Parse pParse, /* Parsing and code generating context */
- Token pName1, /* The "xxx" in the name "xxx.yyy" or "xxx" */
- Token pName2, /* The "yyy" in the name "xxx.yyy" */
- ref Token pUnqual /* Write the unqualified object name here */
- )
- {
- int iDb; /* Database holding the object */
- sqlite3 db = pParse.db;
- if ( ALWAYS( pName2 != null ) && pName2.n > 0 )
- {
- if ( db.init.busy != 0 )
- {
- sqlite3ErrorMsg( pParse, "corrupt database" );
- pParse.nErr++;
- return -1;
- }
- pUnqual = pName2;
- iDb = sqlite3FindDb( db, pName1 );
- if ( iDb < 0 )
- {
- sqlite3ErrorMsg( pParse, "unknown database %T", pName1 );
- pParse.nErr++;
- return -1;
- }
- }
- else
- {
- Debug.Assert( db.init.iDb == 0 || db.init.busy != 0 );
- iDb = db.init.iDb;
- pUnqual = pName1;
- }
- return iDb;
- }
- /*
- ** This routine is used to check if the UTF-8 string zName is a legal
- ** unqualified name for a new schema object (table, index, view or
- ** trigger). All names are legal except those that begin with the string
- ** "sqlite_" (in upper, lower or mixed case). This portion of the namespace
- ** is reserved for internal use.
- */
- static int sqlite3CheckObjectName( Parse pParse, string zName )
- {
- if ( 0 == pParse.db.init.busy && pParse.nested == 0
- && ( pParse.db.flags & SQLITE_WriteSchema ) == 0
- && zName.StartsWith( "sqlite_", System.StringComparison.InvariantCultureIgnoreCase ) )
- {
- sqlite3ErrorMsg( pParse, "object name reserved for internal use: %s", zName );
- return SQLITE_ERROR;
- }
- return SQLITE_OK;
- }
- /*
- ** Begin constructing a new table representation in memory. This is
- ** the first of several action routines that get called in response
- ** to a CREATE TABLE statement. In particular, this routine is called
- ** after seeing tokens "CREATE" and "TABLE" and the table name. The isTemp
- ** flag is true if the table should be stored in the auxiliary database
- ** file instead of in the main database file. This is normally the case
- ** when the "TEMP" or "TEMPORARY" keyword occurs in between
- ** CREATE and TABLE.
- **
- ** The new table record is initialized and put in pParse.pNewTable.
- ** As more of the CREATE TABLE statement is parsed, additional action
- ** routines will be called to add more information to this record.
- ** At the end of the CREATE TABLE statement, the sqlite3EndTable() routine
- ** is called to complete the construction of the new table record.
- */
- static void sqlite3StartTable(
- Parse pParse, /* Parser context */
- Token pName1, /* First part of the name of the table or view */
- Token pName2, /* Second part of the name of the table or view */
- int isTemp, /* True if this is a TEMP table */
- int isView, /* True if this is a VIEW */
- int isVirtual, /* True if this is a VIRTUAL table */
- int noErr /* Do nothing if table already exists */
- )
- {
- Table pTable;
- string zName = null; /* The name of the new table */
- sqlite3 db = pParse.db;
- Vdbe v;
- int iDb; /* Database number to create the table in */
- Token pName = new Token(); /* Unqualified name of the table to create */
- /* The table or view name to create is passed to this routine via tokens
- ** pName1 and pName2. If the table name was fully qualified, for example:
- **
- ** CREATE TABLE xxx.yyy (...);
- **
- ** Then pName1 is set to "xxx" and pName2 "yyy". On the other hand if
- ** the table name is not fully qualified, i.e.:
- **
- ** CREATE TABLE yyy(...);
- **
- ** Then pName1 is set to "yyy" and pName2 is "".
- **
- ** The call below sets the pName pointer to point at the token (pName1 or
- ** pName2) that stores the unqualified table name. The variable iDb is
- ** set to the index of the database that the table or view is to be
- ** created in.
- */
- iDb = sqlite3TwoPartName( pParse, pName1, pName2, ref pName );
- if ( iDb < 0 )
- return;
- if ( 0 == OMIT_TEMPDB && isTemp != 0 && pName2.n > 0 && iDb != 1 )
- {
- /* If creating a temp table, the name may not be qualified. Unless
- ** the database name is "temp" anyway. */
- sqlite3ErrorMsg( pParse, "temporary table name must be unqualified" );
- return;
- }
- if ( OMIT_TEMPDB == 0 && isTemp != 0 )
- iDb = 1;
- pParse.sNameToken = pName;
- zName = sqlite3NameFromToken( db, pName );
- if ( zName == null )
- return;
- if ( SQLITE_OK != sqlite3CheckObjectName( pParse, zName ) )
- {
- goto begin_table_error;
- }
- if ( db.init.iDb == 1 )
- isTemp = 1;
- #if !SQLITE_OMIT_AUTHORIZATION
- Debug.Assert( (isTemp & 1)==isTemp );
- {
- int code;
- char *zDb = db.aDb[iDb].zName;
- if( sqlite3AuthCheck(pParse, SQLITE_INSERT, SCHEMA_TABLE(isTemp), 0, zDb) ){
- goto begin_table_error;
- }
- if( isView ){
- if( OMIT_TEMPDB ==0&& isTemp ){
- code = SQLITE_CREATE_TEMP_VIEW;
- }else{
- code = SQLITE_CREATE_VIEW;
- }
- }else{
- if( OMIT_TEMPDB ==0&& isTemp ){
- code = SQLITE_CREATE_TEMP_TABLE;
- }else{
- code = SQLITE_CREATE_TABLE;
- }
- }
- if( !isVirtual && sqlite3AuthCheck(pParse, code, zName, 0, zDb) ){
- goto begin_table_error;
- }
- }
- #endif
- /* Make sure the new table name does not collide with an existing
- ** index or table name in the same database. Issue an error message if
- ** it does. The exception is if the statement being parsed was passed
- ** to an sqlite3_declare_vtab() call. In that case only the column names
- ** and types will be used, so there is no need to test for namespace
- ** collisions.
- */
- if ( !IN_DECLARE_VTAB )
- {
- String zDb = db.aDb[iDb].zName;
- if ( SQLITE_OK != sqlite3ReadSchema( pParse ) )
- {
- goto begin_table_error;
- }
- pTable = sqlite3FindTable( db, zName, zDb );
- if ( pTable != null )
- {
- if ( noErr == 0 )
- {
- sqlite3ErrorMsg( pParse, "table %T already exists", pName );
- }
- goto begin_table_error;
- }
- if ( sqlite3FindIndex( db, zName, zDb ) != null )
- {
- sqlite3ErrorMsg( pParse, "there is already an index named %s", zName );
- goto begin_table_error;
- }
- }
- pTable = new Table();// sqlite3DbMallocZero(db, Table).Length;
- if ( pTable == null )
- {
- // db.mallocFailed = 1;
- pParse.rc = SQLITE_NOMEM;
- pParse.nErr++;
- goto begin_table_error;
- }
- pTable.zName = zName;
- pTable.iPKey = -1;
- pTable.pSchema = db.aDb[iDb].pSchema;
- pTable.nRef = 1;
- pTable.nRowEst = 1000000;
- Debug.Assert( pParse.pNewTable == null );
- pParse.pNewTable = pTable;
- /* If this is the magic sqlite_sequence table used by autoincrement,
- ** then record a pointer to this table in the main database structure
- ** so that INSERT can find the table easily.
- */
- #if !SQLITE_OMIT_AUTOINCREMENT
- if ( pParse.nested == 0 && zName == "sqlite_sequence" )
- {
- pTable.pSchema.pSeqTab = pTable;
- }
- #endif
- /* Begin generating the code that will insert the table record into
- ** the SQLITE_MASTER table. Note in particular that we must go ahead
- ** and allocate the record number for the table entry now. Before any
- ** PRIMARY KEY or UNIQUE keywords are parsed. Those keywords will cause
- ** indices to be created and the table record must come before the
- ** indices. Hence, the record number for the table must be allocated
- ** now.
- */
- if ( 0 == db.init.busy && ( v = sqlite3GetVdbe( pParse ) ) != null )
- {
- int j1;
- int fileFormat;
- int reg1, reg2, reg3;
- sqlite3BeginWriteOperation( pParse, 0, iDb );
- if ( isVirtual != 0 )
- {
- sqlite3VdbeAddOp0( v, OP_VBegin );
- }
- /* If the file format and encoding in the database have not been set,
- ** set them now.
- */
- reg1 = pParse.regRowid = ++pParse.nMem;
- reg2 = pParse.regRoot = ++pParse.nMem;
- reg3 = ++pParse.nMem;
- sqlite3VdbeAddOp3( v, OP_ReadCookie, iDb, reg3, BTREE_FILE_FORMAT );
- sqlite3VdbeUsesBtree( v, iDb );
- j1 = sqlite3VdbeAddOp1( v, OP_If, reg3 );
- fileFormat = ( db.flags & SQLITE_LegacyFileFmt ) != 0 ?
- 1 : SQLITE_MAX_FILE_FORMAT;
- sqlite3VdbeAddOp2( v, OP_Integer, fileFormat, reg3 );
- sqlite3VdbeAddOp3( v, OP_SetCookie, iDb, BTREE_FILE_FORMAT, reg3 );
- sqlite3VdbeAddOp2( v, OP_Integer, ENC( db ), reg3 );
- sqlite3VdbeAddOp3( v, OP_SetCookie, iDb, BTREE_TEXT_ENCODING, reg3 );
- sqlite3VdbeJumpHere( v, j1 );
- /* This just creates a place-holder record in the sqlite_master table.
- ** The record created does not contain anything yet. It will be replaced
- ** by the real entry in code generated at sqlite3EndTable().
- **
- ** The rowid for the new entry is left in register pParse->regRowid.
- ** The root page number of the new table is left in reg pParse->regRoot.
- ** The rowid and root page number values are needed by the code that
- ** sqlite3EndTable will generate.
- */
- if ( isView != 0 || isVirtual != 0 )
- {
- sqlite3VdbeAddOp2( v, OP_Integer, 0, reg2 );
- }
- else
- {
- sqlite3VdbeAddOp2( v, OP_CreateTable, iDb, reg2 );
- }
- sqlite3OpenMasterTable( pParse, iDb );
- sqlite3VdbeAddOp2( v, OP_NewRowid, 0, reg1 );
- sqlite3VdbeAddOp2( v, OP_Null, 0, reg3 );
- sqlite3VdbeAddOp3( v, OP_Insert, 0, reg3, reg1 );
- sqlite3VdbeChangeP5( v, OPFLAG_APPEND );
- sqlite3VdbeAddOp0( v, OP_Close );
- }
- /* Normal (non-error) return. */
- return;
- /* If an error occurs, we jump here */
- begin_table_error:
- sqlite3DbFree( db, ref zName );
- return;
- }
- /*
- ** This macro is used to compare two strings in a case-insensitive manner.
- ** It is slightly faster than calling sqlite3StrICmp() directly, but
- ** produces larger code.
- **
- ** WARNING: This macro is not compatible with the strcmp() family. It
- ** returns true if the two strings are equal, otherwise false.
- */
- //#define STRICMP(x, y) (\
- //sqlite3UpperToLower[*(unsigned char *)(x)]== \
- //sqlite3UpperToLower[*(unsigned char *)(y)] \
- //&& sqlite3StrICmp((x)+1,(y)+1)==0 )
- /*
- ** Add a new column to the table currently being constructed.
- **
- ** The parser calls this routine once for each column declaration
- ** in a CREATE TABLE statement. sqlite3StartTable() gets called
- ** first to get things going. Then this routine is called for each
- ** column.
- */
- static void sqlite3AddColumn( Parse pParse, Token pName )
- {
- Table p;
- int i;
- string z;
- Column pCol;
- sqlite3 db = pParse.db;
- if ( ( p = pParse.pNewTable ) == null )
- return;
- #if SQLITE_MAX_COLUMN || !SQLITE_MAX_COLUMN
- if ( p.nCol + 1 > db.aLimit[SQLITE_LIMIT_COLUMN] )
- {
- sqlite3ErrorMsg( pParse, "too many columns on %s", p.zName );
- return;
- }
- #endif
- z = sqlite3NameFromToken( db, pName );
- if ( z == null )
- return;
- for ( i = 0; i < p.nCol; i++ )
- {
- if ( z.Equals( p.aCol[i].zName, StringComparison.InvariantCultureIgnoreCase ) )
- {//STRICMP(z, p.aCol[i].zName) ){
- sqlite3ErrorMsg( pParse, "duplicate column name: %s", z );
- sqlite3DbFree( db, ref z );
- return;
- }
- }
- if ( ( p.nCol & 0x7 ) == 0 )
- {
- //aNew = sqlite3DbRealloc(db,p.aCol,(p.nCol+8)*sizeof(p.aCol[0]));
- //if( aNew==0 ){
- // sqlite3DbFree(db,ref z);
- // return;
- //}
- Array.Resize( ref p.aCol, p.nCol + 8 );
- }
- p.aCol[p.nCol] = new Column();
- pCol = p.aCol[p.nCol];
- //memset(pCol, 0, sizeof(p.aCol[0]));
- pCol.zName = z;
- /* If there is no type specified, columns have the default affinity
- ** 'NONE'. If there is a type specified, then sqlite3AddColumnType() will
- ** be called next to set pCol.affinity correctly.
- */
- pCol.affinity = SQLITE_AFF_NONE;
- p.nCol++;
- }
- /*
- ** This routine is called by the parser while in the middle of
- ** parsing a CREATE TABLE statement. A "NOT NULL" constraint has
- ** been seen on a column. This routine sets the notNull flag on
- ** the column currently under construction.
- */
- static void sqlite3AddNotNull( Parse pParse, int onError )
- {
- Table p;
- p = pParse.pNewTable;
- if ( p == null || NEVER( p.nCol < 1 ) )
- return;
- p.aCol[p.nCol - 1].notNull = (u8)onError;
- }
- /*
- ** Scan the column type name zType (length nType) and return the
- ** associated affinity type.
- **
- ** This routine does a case-independent search of zType for the
- ** substrings in the following table. If one of the substrings is
- ** found, the corresponding affinity is returned. If zType contains
- ** more than one of the substrings, entries toward the top of
- ** the table take priority. For example, if zType is 'BLOBINT',
- ** SQLITE_AFF_INTEGER is returned.
- **
- ** Substring | Affinity
- ** --------------------------------
- ** 'INT' | SQLITE_AFF_INTEGER
- ** 'CHAR' | SQLITE_AFF_TEXT
- ** 'CLOB' | SQLITE_AFF_TEXT
- ** 'TEXT' | SQLITE_AFF_TEXT
- ** 'BLOB' | SQLITE_AFF_NONE
- ** 'REAL' | SQLITE_AFF_REAL
- ** 'FLOA' | SQLITE_AFF_REAL
- ** 'DOUB' | SQLITE_AFF_REAL
- **
- ** If none of the substrings in the above table are found,
- ** SQLITE_AFF_NUMERIC is returned.
- */
- static char sqlite3AffinityType( string zIn )
- {
- //u32 h = 0;
- //char aff = SQLITE_AFF_NUMERIC;
- zIn = zIn.ToLower();
- if ( zIn.Contains( "char" ) || zIn.Contains( "clob" ) || zIn.Contains( "text" ) )
- return SQLITE_AFF_TEXT;
- if ( zIn.Contains( "blob" ) )
- return SQLITE_AFF_NONE;
- if ( zIn.Contains( "doub" ) || zIn.Contains( "floa" ) || zIn.Contains( "real" ) )
- return SQLITE_AFF_REAL;
- if ( zIn.Contains( "int" ) )
- return SQLITE_AFF_INTEGER;
- return SQLITE_AFF_NUMERIC;
- // string zEnd = pType.z.Substring(pType.n);
- // while( zIn!=zEnd ){
- // h = (h<<8) + sqlite3UpperToLower[*zIn];
- // zIn++;
- // if( h==(('c'<<24)+('h'<<16)+('a'<<8)+'r') ){ /* CHAR */
- // aff = SQLITE_AFF_TEXT;
- // }else if( h==(('c'<<24)+('l'<<16)+('o'<<8)+'b') ){ /* CLOB */
- // aff = SQLITE_AFF_TEXT;
- // }else if( h==(('t'<<24)+('e'<<16)+('x'<<8)+'t') ){ /* TEXT */
- // aff = SQLITE_AFF_TEXT;
- // }else if( h==(('b'<<24)+('l'<<16)+('o'<<8)+'b') /* BLOB */
- // && (aff==SQLITE_AFF_NUMERIC || aff==SQLITE_AFF_REAL) ){
- // aff = SQLITE_AFF_NONE;
- //#if !SQLITE_OMIT_FLOATING_POINT
- // }else if( h==(('r'<<24)+('e'<<16)+('a'<<8)+'l') /* REAL */
- // && aff==SQLITE_AFF_NUMERIC ){
- // aff = SQLITE_AFF_REAL;
- // }else if( h==(('f'<<24)+('l'<<16)+('o'<<8)+'a') /* FLOA */
- // && aff==SQLITE_AFF_NUMERIC ){
- // aff = SQLITE_AFF_REAL;
- // }else if( h==(('d'<<24)+('o'<<16)+('u'<<8)+'b') /* DOUB */
- // && aff==SQLITE_AFF_NUMERIC ){
- // aff = SQLITE_AFF_REAL;
- //#endif
- // }else if( (h&0x00FFFFFF)==(('i'<<16)+('n'<<8)+'t') ){ /* INT */
- // aff = SQLITE_AFF_INTEGER;
- // break;
- // }
- // }
- // return aff;
- }
- /*
- ** This routine is called by the parser while in the middle of
- ** parsing a CREATE TABLE statement. The pFirst token is the first
- ** token in the sequence of tokens that describe the type of the
- ** column currently under construction. pLast is the last token
- ** in the sequence. Use this information to construct a string
- ** that contains the typename of the column and store that string
- ** in zType.
- */
- static void sqlite3AddColumnType( Parse pParse, Token pType )
- {
- Table p;
- Column pCol;
- p = pParse.pNewTable;
- if ( p == null || NEVER( p.nCol < 1 ) )
- return;
- pCol = p.aCol[p.nCol - 1];
- Debug.Assert( pCol.zType == null );
- pCol.zType = sqlite3NameFromToken( pParse.db, pType );
- pCol.affinity = sqlite3AffinityType( pCol.zType );
- }
- /*
- ** The expression is the default value for the most recently added column
- ** of the table currently under construction.
- **
- ** Default value expressions must be constant. Raise an exception if this
- ** is not the case.
- **
- ** This routine is called by the parser while in the middle of
- ** parsing a CREATE TABLE statement.
- */
- static void sqlite3AddDefaultValue( Parse pParse, ExprSpan pSpan )
- {
- Table p;
- Column pCol;
- sqlite3 db = pParse.db;
- p = pParse.pNewTable;
- if ( p != null )
- {
- pCol = ( p.aCol[p.nCol - 1] );
- if ( sqlite3ExprIsConstantOrFunction( pSpan.pExpr ) == 0 )
- {
- sqlite3ErrorMsg( pParse, "default value of column [%s] is not constant",
- pCol.zName );
- }
- else
- {
- /* A copy of pExpr is used instead of the original, as pExpr contains
- ** tokens that point to volatile memory. The 'span' of the expression
- ** is required by pragma table_info.
- */
- sqlite3ExprDelete( db, ref pCol.pDflt );
- pCol.pDflt = sqlite3ExprDup( db, pSpan.pExpr, EXPRDUP_REDUCE );
- sqlite3DbFree( db, ref pCol.zDflt );
- pCol.zDflt = pSpan.zStart.Substring( 0, pSpan.zStart.Length - pSpan.zEnd.Length );
- //sqlite3DbStrNDup( db, pSpan.zStart,
- // (int)( pSpan.zEnd.Length - pSpan.zStart.Length ) );
- }
- }
- sqlite3ExprDelete( db, ref pSpan.pExpr );
- }
- /*
- ** Designate the PRIMARY KEY for the table. pList is a list of names
- ** of columns that form the primary key. If pList is NULL, then the
- ** most recently added column of the table is the primary key.
- **
- ** A table can have at most one primary key. If the table already has
- ** a primary key (and this is the second primary key) then create an
- ** error.
- **
- ** If the PRIMARY KEY is on a single column whose datatype is INTEGER,
- ** then we will try to use that column as the rowid. Set the Table.iPKey
- ** field of the table under construction to be the index of the
- ** INTEGER PRIMARY KEY column. Table.iPKey is set to -1 if there is
- ** no INTEGER PRIMARY KEY.
- **
- ** If the key is not an INTEGER PRIMARY KEY, then create a unique
- ** index for the key. No index is created for INTEGER PRIMARY KEYs.
- */
- // OVERLOADS, so I don't need to rewrite parse.c
- static void sqlite3AddPrimaryKey( Parse pParse, int null_2, int onError, int autoInc, int sortOrder )
- {
- sqlite3AddPrimaryKey( pParse, null, onError, autoInc, sortOrder );
- }
- static void sqlite3AddPrimaryKey(
- Parse pParse, /* Parsing context */
- ExprList pList, /* List of field names to be indexed */
- int onError, /* What to do with a uniqueness conflict */
- int autoInc, /* True if the AUTOINCREMENT keyword is present */
- int sortOrder /* SQLITE_SO_ASC or SQLITE_SO_DESC */
- )
- {
- Table pTab = pParse.pNewTable;
- string zType = null;
- int iCol = -1, i;
- if ( pTab == null || IN_DECLARE_VTAB )
- goto primary_key_exit;
- if ( ( pTab.tabFlags & TF_HasPrimaryKey ) != 0 )
- {
- sqlite3ErrorMsg( pParse,
- "table \"%s\" has more than one primary key", pTab.zName );
- goto primary_key_exit;
- }
- pTab.tabFlags |= TF_HasPrimaryKey;
- if ( pList == null )
- {
- iCol = pTab.nCol - 1;
- pTab.aCol[iCol].isPrimKey = 1;
- }
- else
- {
- for ( i = 0; i < pList.nExpr; i++ )
- {
- for ( iCol = 0; iCol < pTab.nCol; iCol++ )
- {
- if ( pList.a[i].zName.Equals( pTab.aCol[iCol].zName, StringComparison.InvariantCultureIgnoreCase ) )
- {
- break;
- }
- }
- if ( iCol < pTab.nCol )
- {
- pTab.aCol[iCol].isPrimKey = 1;
- }
- }
- if ( pList.nExpr > 1 )
- iCol = -1;
- }
- if ( iCol >= 0 && iCol < pTab.nCol )
- {
- zType = pTab.aCol[iCol].zType;
- }
- if ( zType != null && zType.Equals( "INTEGER", StringComparison.InvariantCultureIgnoreCase )
- && sortOrder == SQLITE_SO_ASC )
- {
- pTab.iPKey = iCol;
- pTab.keyConf = (byte)onError;
- Debug.Assert( autoInc == 0 || autoInc == 1 );
- pTab.tabFlags |= (u8)( autoInc * TF_Autoincrement );
- }
- else if ( autoInc != 0 )
- {
- #if !SQLITE_OMIT_AUTOINCREMENT
- sqlite3ErrorMsg( pParse, "AUTOINCREMENT is only allowed on an " +
- "INTEGER PRIMARY KEY" );
- #endif
- }
- else
- {
- Index p;
- p = sqlite3CreateIndex( pParse, 0, 0, 0, pList, onError, 0, 0, sortOrder, 0 );
- if ( p != null )
- {
- p.autoIndex = 2;
- }
- pList = null;
- }
- primary_key_exit:
- sqlite3ExprListDelete( pParse.db, ref pList );
- return;
- }
- /*
- ** Add a new CHECK constraint to the table currently under construction.
- */
- static void sqlite3AddCheckConstraint(
- Parse pParse, /* Parsing context */
- Expr pCheckExpr /* The check expression */
- )
- {
- sqlite3 db = pParse.db;
- #if !SQLITE_OMIT_CHECK
- Table pTab = pParse.pNewTable;
- if ( pTab != null && !IN_DECLARE_VTAB )
- {
- pTab.pCheck = sqlite3ExprAnd( db, pTab.pCheck, pCheckExpr );
- }
- else
- #endif
- {
- sqlite3ExprDelete( db, ref pCheckExpr );
- }
- }
- /*
- ** Set the collation function of the most recently parsed table column
- ** to the CollSeq given.
- */
- static void sqlite3AddCollateType( Parse pParse, Token pToken )
- {
- Table p;
- int i;
- string zColl; /* Dequoted name of collation sequence */
- sqlite3 db;
- if ( ( p = pParse.pNewTable ) == null )
- return;
- i = p.nCol - 1;
- db = pParse.db;
- zColl = sqlite3NameFromToken( db, pToken );
- if ( zColl == null )
- return;
- if ( sqlite3LocateCollSeq( pParse, zColl ) != null )
- {
- Index pIdx;
- p.aCol[i].zColl = zColl;
- /* If the column is declared as "<name> PRIMARY KEY COLLATE <type>",
- ** then an index may have been created on this column before the
- ** collation type was added. Correct this if it is the case.
- */
- for ( pIdx = p.pIndex; pIdx != null; pIdx = pIdx.pNext )
- {
- Debug.Assert( pIdx.nColumn == 1 );
- if ( pIdx.aiColumn[0] == i )
- {
- pIdx.azColl[0] = p.aCol[i].zColl;
- }
- }
- }
- else
- {
- sqlite3DbFree( db, ref zColl );
- }
- }
- /*
- ** This function returns the collation sequence for database native text
- ** encoding identified by the string zName, length nName.
- **
- ** If the requested collation sequence is not available, or not available
- ** in the database native encoding, the collation factory is invoked to
- ** request it. If the collation factory does not supply such a sequence,
- ** and the sequence is available in another text encoding, then that is
- ** returned instead.
- **
- ** If no versions of the requested collations sequence are available, or
- ** another error occurs, NULL is returned and an error message written into
- ** pParse.
- **
- ** This routine is a wrapper around sqlite3FindCollSeq(). This routine
- ** invokes the collation factory if the named collation cannot be found
- ** and generates an error message.
- **
- ** See also: sqlite3FindCollSeq(), sqlite3GetCollSeq()
- */
- static CollSeq sqlite3LocateCollSeq( Parse pParse, string zName )
- {
- sqlite3 db = pParse.db;
- u8 enc = db.aDb[0].pSchema.enc;// ENC(db);
- u8 initbusy = db.init.busy;
- CollSeq pColl;
- pColl = sqlite3FindCollSeq( db, enc, zName, initbusy );
- if ( 0 == initbusy && ( pColl == null || pColl.xCmp == null ) )
- …
Large files files are truncated, but you can click here to view the full file