using System; using System.Diagnostics; using System.Text; using Pgno = System.UInt32; using u8 = System.Byte; using u32 = 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 parser ** to handle INSERT statements in SQLite. ************************************************************************* ** 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: 2011-06-23 19:49:22 4374b7e83ea0a3fbc3691f9c0c936272862f32f2 ** ************************************************************************* */ //#include "sqliteInt.h" /* ** Generate code that will open a table for reading. */ static void sqlite3OpenTable( Parse p, /* Generate code into this VDBE */ int iCur, /* The cursor number of the table */ int iDb, /* The database index in sqlite3.aDb[] */ Table pTab, /* The table to be opened */ int opcode /* OP_OpenRead or OP_OpenWrite */ ) { Vdbe v; if ( IsVirtual( pTab ) ) return; v = sqlite3GetVdbe( p ); Debug.Assert( opcode == OP_OpenWrite || opcode == OP_OpenRead ); sqlite3TableLock( p, iDb, pTab.tnum, ( opcode == OP_OpenWrite ) ? (byte)1 : (byte)0, pTab.zName ); sqlite3VdbeAddOp3( v, opcode, iCur, pTab.tnum, iDb ); sqlite3VdbeChangeP4( v, -1, ( pTab.nCol ), P4_INT32 );//SQLITE_INT_TO_PTR( pTab.nCol ), P4_INT32 ); VdbeComment( v, "%s", pTab.zName ); } /* ** Return a pointer to the column affinity string associated with index ** pIdx. A column affinity string has one character for each column in ** the table, according to the affinity of the column: ** ** Character Column affinity ** ------------------------------ ** 'a' TEXT ** 'b' NONE ** 'c' NUMERIC ** 'd' INTEGER ** 'e' REAL ** ** An extra 'b' is appended to the end of the string to cover the ** rowid that appears as the last column in every index. ** ** Memory for the buffer containing the column index affinity string ** is managed along with the rest of the Index structure. It will be ** released when sqlite3DeleteIndex() is called. */ static string sqlite3IndexAffinityStr( Vdbe v, Index pIdx ) { if ( pIdx.zColAff == null || pIdx.zColAff[0] == '\0' ) { /* The first time a column affinity string for a particular index is ** required, it is allocated and populated here. It is then stored as ** a member of the Index structure for subsequent use. ** ** The column affinity string will eventually be deleted by ** sqliteDeleteIndex() when the Index structure itself is cleaned ** up. */ int n; Table pTab = pIdx.pTable; ////sqlite3 db = sqlite3VdbeDb( v ); StringBuilder pIdx_zColAff = new StringBuilder( pIdx.nColumn + 2 );// (char )sqlite3DbMallocRaw(0, pIdx->nColumn+2); // if ( pIdx_zColAff == null ) // { // db.mallocFailed = 1; // return null; // } for ( n = 0; n < pIdx.nColumn; n++ ) { pIdx_zColAff.Append( pTab.aCol[pIdx.aiColumn[n]].affinity ); } pIdx_zColAff.Append( SQLITE_AFF_NONE ); pIdx_zColAff.Append( '\0' ); pIdx.zColAff = pIdx_zColAff.ToString(); } return pIdx.zColAff; } /* ** Set P4 of the most recently inserted opcode to a column affinity ** string for table pTab. A column affinity string has one character ** for each column indexed by the index, according to the affinity of the ** column: ** ** Character Column affinity ** ------------------------------ ** 'a' TEXT ** 'b' NONE ** 'c' NUMERIC ** 'd' INTEGER ** 'e' REAL */ static void sqlite3TableAffinityStr( Vdbe v, Table pTab ) { /* The first time a column affinity string for a particular table ** is required, it is allocated and populated here. It is then ** stored as a member of the Table structure for subsequent use. ** ** The column affinity string will eventually be deleted by ** sqlite3DeleteTable() when the Table structure itself is cleaned up. */ if ( pTab.zColAff == null ) { StringBuilder zColAff; int i; ////sqlite3 db = sqlite3VdbeDb( v ); zColAff = new StringBuilder( pTab.nCol + 1 );// (char)sqlite3DbMallocRaw(0, pTab->nCol+1); if ( zColAff == null ) { //// db.mallocFailed = 1; return; } for ( i = 0; i < pTab.nCol; i++ ) { zColAff.Append( pTab.aCol[i].affinity ); } //zColAff.Append( '\0' ); pTab.zColAff = zColAff.ToString(); } sqlite3VdbeChangeP4( v, -1, pTab.zColAff, P4_TRANSIENT ); } /* ** Return non-zero if the table pTab in database iDb or any of its indices ** have been opened at any point in the VDBE program beginning at location ** iStartAddr throught the end of the program. This is used to see if ** a statement of the form "INSERT INTO SELECT ..." can ** run without using temporary table for the results of the SELECT. */ static bool readsTable( Parse p, int iStartAddr, int iDb, Table pTab ) { Vdbe v = sqlite3GetVdbe( p ); int i; int iEnd = sqlite3VdbeCurrentAddr( v ); #if !SQLITE_OMIT_VIRTUALTABLE VTable pVTab = IsVirtual( pTab ) ? sqlite3GetVTable( p.db, pTab ) : null; #endif for ( i = iStartAddr; i < iEnd; i++ ) { VdbeOp pOp = sqlite3VdbeGetOp( v, i ); Debug.Assert( pOp != null ); if ( pOp.opcode == OP_OpenRead && pOp.p3 == iDb ) { Index pIndex; int tnum = pOp.p2; if ( tnum == pTab.tnum ) { return true; } for ( pIndex = pTab.pIndex; pIndex != null; pIndex = pIndex.pNext ) { if ( tnum == pIndex.tnum ) { return true; } } } #if !SQLITE_OMIT_VIRTUALTABLE if ( pOp.opcode == OP_VOpen && pOp.p4.pVtab == pVTab ) { Debug.Assert( pOp.p4.pVtab != null ); Debug.Assert( pOp.p4type == P4_VTAB ); return true; } #endif } return false; } #if !SQLITE_OMIT_AUTOINCREMENT /* ** Locate or create an AutoincInfo structure associated with table pTab ** which is in database iDb. Return the register number for the register ** that holds the maximum rowid. ** ** There is at most one AutoincInfo structure per table even if the ** same table is autoincremented multiple times due to inserts within ** triggers. A new AutoincInfo structure is created if this is the ** first use of table pTab. On 2nd and subsequent uses, the original ** AutoincInfo structure is used. ** ** Three memory locations are allocated: ** ** (1) Register to hold the name of the pTab table. ** (2) Register to hold the maximum ROWID of pTab. ** (3) Register to hold the rowid in sqlite_sequence of pTab ** ** The 2nd register is the one that is returned. That is all the ** insert routine needs to know about. */ static int autoIncBegin( Parse pParse, /* Parsing context */ int iDb, /* Index of the database holding pTab */ Table pTab /* The table we are writing to */ ) { int memId = 0; /* Register holding maximum rowid */ if ( ( pTab.tabFlags & TF_Autoincrement ) != 0 ) { Parse pToplevel = sqlite3ParseToplevel( pParse ); AutoincInfo pInfo; pInfo = pToplevel.pAinc; while ( pInfo != null && pInfo.pTab != pTab ) { pInfo = pInfo.pNext; } if ( pInfo == null ) { pInfo = new AutoincInfo();//sqlite3DbMallocRaw(pParse.db, sizeof(*pInfo)); //if( pInfo==0 ) return 0; pInfo.pNext = pToplevel.pAinc; pToplevel.pAinc = pInfo; pInfo.pTab = pTab; pInfo.iDb = iDb; pToplevel.nMem++; /* Register to hold name of table */ pInfo.regCtr = ++pToplevel.nMem; /* Max rowid register */ pToplevel.nMem++; /* Rowid in sqlite_sequence */ } memId = pInfo.regCtr; } return memId; } /* ** This routine generates code that will initialize all of the ** register used by the autoincrement tracker. */ static void sqlite3AutoincrementBegin( Parse pParse ) { AutoincInfo p; /* Information about an AUTOINCREMENT */ sqlite3 db = pParse.db; /* The database connection */ Db pDb; /* Database only autoinc table */ int memId; /* Register holding max rowid */ int addr; /* A VDBE address */ Vdbe v = pParse.pVdbe; /* VDBE under construction */ /* This routine is never called during trigger-generation. It is ** only called from the top-level */ Debug.Assert( pParse.pTriggerTab == null ); Debug.Assert( pParse == sqlite3ParseToplevel( pParse ) ); Debug.Assert( v != null ); /* We failed long ago if this is not so */ for ( p = pParse.pAinc; p != null; p = p.pNext ) { pDb = db.aDb[p.iDb]; memId = p.regCtr; Debug.Assert( sqlite3SchemaMutexHeld( db, 0, pDb.pSchema ) ); sqlite3OpenTable( pParse, 0, p.iDb, pDb.pSchema.pSeqTab, OP_OpenRead ); addr = sqlite3VdbeCurrentAddr( v ); sqlite3VdbeAddOp4( v, OP_String8, 0, memId - 1, 0, p.pTab.zName, 0 ); sqlite3VdbeAddOp2( v, OP_Rewind, 0, addr + 9 ); sqlite3VdbeAddOp3( v, OP_Column, 0, 0, memId ); sqlite3VdbeAddOp3( v, OP_Ne, memId - 1, addr + 7, memId ); sqlite3VdbeChangeP5( v, SQLITE_JUMPIFNULL ); sqlite3VdbeAddOp2( v, OP_Rowid, 0, memId + 1 ); sqlite3VdbeAddOp3( v, OP_Column, 0, 1, memId ); sqlite3VdbeAddOp2( v, OP_Goto, 0, addr + 9 ); sqlite3VdbeAddOp2( v, OP_Next, 0, addr + 2 ); sqlite3VdbeAddOp2( v, OP_Integer, 0, memId ); sqlite3VdbeAddOp0( v, OP_Close ); } } /* ** Update the maximum rowid for an autoincrement calculation. ** ** This routine should be called when the top of the stack holds a ** new rowid that is about to be inserted. If that new rowid is ** larger than the maximum rowid in the memId memory cell, then the ** memory cell is updated. The stack is unchanged. */ static void autoIncStep( Parse pParse, int memId, int regRowid ) { if ( memId > 0 ) { sqlite3VdbeAddOp2( pParse.pVdbe, OP_MemMax, memId, regRowid ); } } /* ** This routine generates the code needed to write autoincrement ** maximum rowid values back into the sqlite_sequence register. ** Every statement that might do an INSERT into an autoincrement ** table (either directly or through triggers) needs to call this ** routine just before the "exit" code. */ static void sqlite3AutoincrementEnd( Parse pParse ) { AutoincInfo p; Vdbe v = pParse.pVdbe; sqlite3 db = pParse.db; Debug.Assert( v != null ); for ( p = pParse.pAinc; p != null; p = p.pNext ) { Db pDb = db.aDb[p.iDb]; int j1, j2, j3, j4, j5; int iRec; int memId = p.regCtr; iRec = sqlite3GetTempReg( pParse ); Debug.Assert( sqlite3SchemaMutexHeld( db, 0, pDb.pSchema ) ); sqlite3OpenTable( pParse, 0, p.iDb, pDb.pSchema.pSeqTab, OP_OpenWrite ); j1 = sqlite3VdbeAddOp1( v, OP_NotNull, memId + 1 ); j2 = sqlite3VdbeAddOp0( v, OP_Rewind ); j3 = sqlite3VdbeAddOp3( v, OP_Column, 0, 0, iRec ); j4 = sqlite3VdbeAddOp3( v, OP_Eq, memId - 1, 0, iRec ); sqlite3VdbeAddOp2( v, OP_Next, 0, j3 ); sqlite3VdbeJumpHere( v, j2 ); sqlite3VdbeAddOp2( v, OP_NewRowid, 0, memId + 1 ); j5 = sqlite3VdbeAddOp0( v, OP_Goto ); sqlite3VdbeJumpHere( v, j4 ); sqlite3VdbeAddOp2( v, OP_Rowid, 0, memId + 1 ); sqlite3VdbeJumpHere( v, j1 ); sqlite3VdbeJumpHere( v, j5 ); sqlite3VdbeAddOp3( v, OP_MakeRecord, memId - 1, 2, iRec ); sqlite3VdbeAddOp3( v, OP_Insert, 0, iRec, memId + 1 ); sqlite3VdbeChangeP5( v, OPFLAG_APPEND ); sqlite3VdbeAddOp0( v, OP_Close ); sqlite3ReleaseTempReg( pParse, iRec ); } } #else /* ** If SQLITE_OMIT_AUTOINCREMENT is defined, then the three routines ** above are all no-ops */ //# define autoIncBegin(A,B,C) (0) //# define autoIncStep(A,B,C) #endif // * SQLITE_OMIT_AUTOINCREMENT */ /* Forward declaration */ //static int xferOptimization( // Parse pParse, /* Parser context */ // Table pDest, /* The table we are inserting into */ // Select pSelect, /* A SELECT statement to use as the data source */ // int onError, /* How to handle constraint errors */ // int iDbDest /* The database of pDest */ //); /* ** This routine is call to handle SQL of the following forms: ** ** insert into TABLE (IDLIST) values(EXPRLIST) ** insert into TABLE (IDLIST) select ** ** The IDLIST following the table name is always optional. If omitted, ** then a list of all columns for the table is substituted. The IDLIST ** appears in the pColumn parameter. pColumn is NULL if IDLIST is omitted. ** ** The pList parameter holds EXPRLIST in the first form of the INSERT ** statement above, and pSelect is NULL. For the second form, pList is ** NULL and pSelect is a pointer to the select statement used to generate ** data for the insert. ** ** The code generated follows one of four templates. For a simple ** select with data coming from a VALUES clause, the code executes ** once straight down through. Pseudo-code follows (we call this ** the "1st template"): ** ** open write cursor to and its indices ** puts VALUES clause expressions onto the stack ** write the resulting record into
** cleanup ** ** The three remaining templates assume the statement is of the form ** ** INSERT INTO
SELECT ... ** ** If the SELECT clause is of the restricted form "SELECT * FROM " - ** in other words if the SELECT pulls all columns from a single table ** and there is no WHERE or LIMIT or GROUP BY or ORDER BY clauses, and ** if and are distinct tables but have identical ** schemas, including all the same indices, then a special optimization ** is invoked that copies raw records from over to . ** See the xferOptimization() function for the implementation of this ** template. This is the 2nd template. ** ** open a write cursor to
** open read cursor on ** transfer all records in over to
** close cursors ** foreach index on
** open a write cursor on the
index ** open a read cursor on the corresponding index ** transfer all records from the read to the write cursors ** close cursors ** end foreach ** ** The 3rd template is for when the second template does not apply ** and the SELECT clause does not read from
at any time. ** The generated code follows this template: ** ** EOF <- 0 ** X <- A ** goto B ** A: setup for the SELECT ** loop over the rows in the SELECT ** load values into registers R..R+n ** yield X ** end loop ** cleanup after the SELECT ** EOF <- 1 ** yield X ** goto A ** B: open write cursor to
and its indices ** C: yield X ** if EOF goto D ** insert the select result into
from R..R+n ** goto C ** D: cleanup ** ** The 4th template is used if the insert statement takes its ** values from a SELECT but the data is being inserted into a table ** that is also read as part of the SELECT. In the third form, ** we have to use a intermediate table to store the results of ** the select. The template is like this: ** ** EOF <- 0 ** X <- A ** goto B ** A: setup for the SELECT ** loop over the tables in the SELECT ** load value into register R..R+n ** yield X ** end loop ** cleanup after the SELECT ** EOF <- 1 ** yield X ** halt-error ** B: open temp table ** L: yield X ** if EOF goto M ** insert row from R..R+n into temp table ** goto L ** M: open write cursor to
and its indices ** rewind temp table ** C: loop over rows of intermediate table ** transfer values form intermediate table into
** end loop ** D: cleanup */ // OVERLOADS, so I don't need to rewrite parse.c static void sqlite3Insert( Parse pParse, SrcList pTabList, int null_3, int null_4, IdList pColumn, int onError ) { sqlite3Insert( pParse, pTabList, null, null, pColumn, onError ); } static void sqlite3Insert( Parse pParse, SrcList pTabList, int null_3, Select pSelect, IdList pColumn, int onError ) { sqlite3Insert( pParse, pTabList, null, pSelect, pColumn, onError ); } static void sqlite3Insert( Parse pParse, SrcList pTabList, ExprList pList, int null_4, IdList pColumn, int onError ) { sqlite3Insert( pParse, pTabList, pList, null, pColumn, onError ); } static void sqlite3Insert( Parse pParse, /* Parser context */ SrcList pTabList, /* Name of table into which we are inserting */ ExprList pList, /* List of values to be inserted */ Select pSelect, /* A SELECT statement to use as the data source */ IdList pColumn, /* Column names corresponding to IDLIST. */ int onError /* How to handle constraint errors */ ) { sqlite3 db; /* The main database structure */ Table pTab; /* The table to insert into. aka TABLE */ string zTab; /* Name of the table into which we are inserting */ int i = 0; int j = 0; int idx = 0; /* Loop counters */ Vdbe v; /* Generate code into this virtual machine */ Index pIdx; /* For looping over indices of the table */ int nColumn; /* Number of columns in the data */ int nHidden = 0; /* Number of hidden columns if TABLE is virtual */ int baseCur = 0; /* VDBE VdbeCursor number for pTab */ int keyColumn = -1; /* Column that is the INTEGER PRIMARY KEY */ int endOfLoop = 0; /* Label for the end of the insertion loop */ bool useTempTable = false; /* Store SELECT results in intermediate table */ int srcTab = 0; /* Data comes from this temporary cursor if >=0 */ int addrInsTop = 0; /* Jump to label "D" */ int addrCont = 0; /* Top of insert loop. Label "C" in templates 3 and 4 */ int addrSelect = 0; /* Address of coroutine that implements the SELECT */ SelectDest dest; /* Destination for SELECT on rhs of INSERT */ int iDb; /* Index of database holding TABLE */ bool appendFlag = false; /* True if the insert is likely to be an append */ /* Register allocations */ int regFromSelect = 0; /* Base register for data coming from SELECT */ int regAutoinc = 0; /* Register holding the AUTOINCREMENT counter */ int regRowCount = 0; /* Memory cell used for the row counter */ int regIns; /* Block of regs holding rowid+data being inserted */ int regRowid; /* registers holding insert rowid */ int regData; /* register holding first column to insert */ int regEof = 0; /* Register recording end of SELECT data */ int[] aRegIdx = null; /* One register allocated to each index */ #if !SQLITE_OMIT_TRIGGER bool isView = false; /* True if attempting to insert into a view */ Trigger pTrigger; /* List of triggers on pTab, if required */ int tmask = 0; /* Mask of trigger times */ #endif db = pParse.db; dest = new SelectDest();// memset( &dest, 0, sizeof( dest ) ); if ( pParse.nErr != 0 /*|| db.mallocFailed != 0 */ ) { goto insert_cleanup; } /* Locate the table into which we will be inserting new information. */ Debug.Assert( pTabList.nSrc == 1 ); zTab = pTabList.a[0].zName; if ( NEVER( zTab == null ) ) goto insert_cleanup; pTab = sqlite3SrcListLookup( pParse, pTabList ); if ( pTab == null ) { goto insert_cleanup; } iDb = sqlite3SchemaToIndex( db, pTab.pSchema ); Debug.Assert( iDb < db.nDb ); #if !SQLITE_OMIT_AUTHORIZATION Db pDb; /* The database containing table being inserted into */ pDb = db.aDb[iDb]; string zDb; /* Name of the database holding this table */ zDb = pDb.zName; if( sqlite3AuthCheck(pParse, SQLITE_INSERT, pTab.zName, 0, zDb) ){ goto insert_cleanup; } #endif /* Figure out if we have any triggers and if the table being ** inserted into is a view */ #if !SQLITE_OMIT_TRIGGER pTrigger = sqlite3TriggersExist( pParse, pTab, TK_INSERT, null, out tmask ); isView = pTab.pSelect != null; #else Trigger pTrigger = null; //# define pTrigger 0 int tmask = 0; //# define tmask 0 bool isView = false; #endif #if SQLITE_OMIT_VIEW //# undef isView isView = false; #endif #if !SQLITE_OMIT_TRIGGER Debug.Assert( ( pTrigger != null && tmask != 0 ) || ( pTrigger == null && tmask == 0 ) ); #endif #if !SQLITE_OMIT_VIEW /* If pTab is really a view, make sure it has been initialized. ** ViewGetColumnNames() is a no-op if pTab is not a view (or virtual ** module table). */ if ( sqlite3ViewGetColumnNames( pParse, pTab ) != -0 ) { goto insert_cleanup; } #endif /* Ensure that: * (a) the table is not read-only, * (b) that if it is a view then ON INSERT triggers exist */ if ( sqlite3IsReadOnly( pParse, pTab, tmask ) ) { goto insert_cleanup; } /* Allocate a VDBE */ v = sqlite3GetVdbe( pParse ); if ( v == null ) goto insert_cleanup; if ( pParse.nested == 0 ) sqlite3VdbeCountChanges( v ); sqlite3BeginWriteOperation( pParse, ( pSelect != null || pTrigger != null ) ? 1 : 0, iDb ); #if !SQLITE_OMIT_XFER_OPT /* If the statement is of the form ** ** INSERT INTO SELECT * FROM ; ** ** Then special optimizations can be applied that make the transfer ** very fast and which reduce fragmentation of indices. ** ** This is the 2nd template. */ if ( pColumn == null && xferOptimization( pParse, pTab, pSelect, onError, iDb ) != 0 ) { Debug.Assert( null == pTrigger ); Debug.Assert( pList == null ); goto insert_end; } #endif // * SQLITE_OMIT_XFER_OPT */ /* If this is an AUTOINCREMENT table, look up the sequence number in the ** sqlite_sequence table and store it in memory cell regAutoinc. */ regAutoinc = autoIncBegin( pParse, iDb, pTab ); /* Figure out how many columns of data are supplied. If the data ** is coming from a SELECT statement, then generate a co-routine that ** produces a single row of the SELECT on each invocation. The ** co-routine is the common header to the 3rd and 4th templates. */ if ( pSelect != null ) { /* Data is coming from a SELECT. Generate code to implement that SELECT ** as a co-routine. The code is common to both the 3rd and 4th ** templates: ** ** EOF <- 0 ** X <- A ** goto B ** A: setup for the SELECT ** loop over the tables in the SELECT ** load value into register R..R+n ** yield X ** end loop ** cleanup after the SELECT ** EOF <- 1 ** yield X ** halt-error ** ** On each invocation of the co-routine, it puts a single row of the ** SELECT result into registers dest.iMem...dest.iMem+dest.nMem-1. ** (These output registers are allocated by sqlite3Select().) When ** the SELECT completes, it sets the EOF flag stored in regEof. */ int rc = 0, j1; regEof = ++pParse.nMem; sqlite3VdbeAddOp2( v, OP_Integer, 0, regEof ); /* EOF <- 0 */ #if SQLITE_DEBUG VdbeComment( v, "SELECT eof flag" ); #endif sqlite3SelectDestInit( dest, SRT_Coroutine, ++pParse.nMem ); addrSelect = sqlite3VdbeCurrentAddr( v ) + 2; sqlite3VdbeAddOp2( v, OP_Integer, addrSelect - 1, dest.iParm ); j1 = sqlite3VdbeAddOp2( v, OP_Goto, 0, 0 ); #if SQLITE_DEBUG VdbeComment( v, "Jump over SELECT coroutine" ); #endif /* Resolve the expressions in the SELECT statement and execute it. */ rc = sqlite3Select( pParse, pSelect, ref dest ); Debug.Assert( pParse.nErr == 0 || rc != 0 ); if ( rc != 0 || NEVER( pParse.nErr != 0 ) /*|| db.mallocFailed != 0 */ ) { goto insert_cleanup; } sqlite3VdbeAddOp2( v, OP_Integer, 1, regEof ); /* EOF <- 1 */ sqlite3VdbeAddOp1( v, OP_Yield, dest.iParm ); /* yield X */ sqlite3VdbeAddOp2( v, OP_Halt, SQLITE_INTERNAL, OE_Abort ); #if SQLITE_DEBUG VdbeComment( v, "End of SELECT coroutine" ); #endif sqlite3VdbeJumpHere( v, j1 ); /* label B: */ regFromSelect = dest.iMem; Debug.Assert( pSelect.pEList != null ); nColumn = pSelect.pEList.nExpr; Debug.Assert( dest.nMem == nColumn ); /* Set useTempTable to TRUE if the result of the SELECT statement ** should be written into a temporary table (template 4). Set to ** FALSE if each* row of the SELECT can be written directly into ** the destination table (template 3). ** ** A temp table must be used if the table being updated is also one ** of the tables being read by the SELECT statement. Also use a ** temp table in the case of row triggers. */ if ( pTrigger != null || readsTable( pParse, addrSelect, iDb, pTab ) ) { useTempTable = true; } if ( useTempTable ) { /* Invoke the coroutine to extract information from the SELECT ** and add it to a transient table srcTab. The code generated ** here is from the 4th template: ** ** B: open temp table ** L: yield X ** if EOF goto M ** insert row from R..R+n into temp table ** goto L ** M: ... */ int regRec; /* Register to hold packed record */ int regTempRowid; /* Register to hold temp table ROWID */ int addrTop; /* Label "L" */ int addrIf; /* Address of jump to M */ srcTab = pParse.nTab++; regRec = sqlite3GetTempReg( pParse ); regTempRowid = sqlite3GetTempReg( pParse ); sqlite3VdbeAddOp2( v, OP_OpenEphemeral, srcTab, nColumn ); addrTop = sqlite3VdbeAddOp1( v, OP_Yield, dest.iParm ); addrIf = sqlite3VdbeAddOp1( v, OP_If, regEof ); sqlite3VdbeAddOp3( v, OP_MakeRecord, regFromSelect, nColumn, regRec ); sqlite3VdbeAddOp2( v, OP_NewRowid, srcTab, regTempRowid ); sqlite3VdbeAddOp3( v, OP_Insert, srcTab, regRec, regTempRowid ); sqlite3VdbeAddOp2( v, OP_Goto, 0, addrTop ); sqlite3VdbeJumpHere( v, addrIf ); sqlite3ReleaseTempReg( pParse, regRec ); sqlite3ReleaseTempReg( pParse, regTempRowid ); } } else { /* This is the case if the data for the INSERT is coming from a VALUES ** clause */ NameContext sNC; sNC = new NameContext();// memset( &sNC, 0, sNC ).Length; sNC.pParse = pParse; srcTab = -1; Debug.Assert( !useTempTable ); nColumn = pList != null ? pList.nExpr : 0; for ( i = 0; i < nColumn; i++ ) { if ( sqlite3ResolveExprNames( sNC, ref pList.a[i].pExpr ) != 0 ) { goto insert_cleanup; } } } /* Make sure the number of columns in the source data matches the number ** of columns to be inserted into the table. */ if ( IsVirtual( pTab ) ) { for ( i = 0; i < pTab.nCol; i++ ) { nHidden += ( IsHiddenColumn( pTab.aCol[i] ) ? 1 : 0 ); } } if ( pColumn == null && nColumn != 0 && nColumn != ( pTab.nCol - nHidden ) ) { sqlite3ErrorMsg( pParse, "table %S has %d columns but %d values were supplied", pTabList, 0, pTab.nCol - nHidden, nColumn ); goto insert_cleanup; } if ( pColumn != null && nColumn != pColumn.nId ) { sqlite3ErrorMsg( pParse, "%d values for %d columns", nColumn, pColumn.nId ); goto insert_cleanup; } /* If the INSERT statement included an IDLIST term, then make sure ** all elements of the IDLIST really are columns of the table and ** remember the column indices. ** ** If the table has an INTEGER PRIMARY KEY column and that column ** is named in the IDLIST, then record in the keyColumn variable ** the index into IDLIST of the primary key column. keyColumn is ** the index of the primary key as it appears in IDLIST, not as ** is appears in the original table. (The index of the primary ** key in the original table is pTab.iPKey.) */ if ( pColumn != null ) { for ( i = 0; i < pColumn.nId; i++ ) { pColumn.a[i].idx = -1; } for ( i = 0; i < pColumn.nId; i++ ) { for ( j = 0; j < pTab.nCol; j++ ) { if ( pColumn.a[i].zName.Equals( pTab.aCol[j].zName ,StringComparison.OrdinalIgnoreCase ) ) { pColumn.a[i].idx = j; if ( j == pTab.iPKey ) { keyColumn = i; } break; } } if ( j >= pTab.nCol ) { if ( sqlite3IsRowid( pColumn.a[i].zName ) ) { keyColumn = i; } else { sqlite3ErrorMsg( pParse, "table %S has no column named %s", pTabList, 0, pColumn.a[i].zName ); pParse.checkSchema = 1; goto insert_cleanup; } } } } /* If there is no IDLIST term but the table has an integer primary ** key, the set the keyColumn variable to the primary key column index ** in the original table definition. */ if ( pColumn == null && nColumn > 0 ) { keyColumn = pTab.iPKey; } /* Initialize the count of rows to be inserted */ if ( ( db.flags & SQLITE_CountRows ) != 0 ) { regRowCount = ++pParse.nMem; sqlite3VdbeAddOp2( v, OP_Integer, 0, regRowCount ); } /* If this is not a view, open the table and and all indices */ if ( !isView ) { int nIdx; baseCur = pParse.nTab; nIdx = sqlite3OpenTableAndIndices( pParse, pTab, baseCur, OP_OpenWrite ); aRegIdx = new int[nIdx + 1];// sqlite3DbMallocRaw( db, sizeof( int ) * ( nIdx + 1 ) ); if ( aRegIdx == null ) { goto insert_cleanup; } for ( i = 0; i < nIdx; i++ ) { aRegIdx[i] = ++pParse.nMem; } } /* This is the top of the main insertion loop */ if ( useTempTable ) { /* This block codes the top of loop only. The complete loop is the ** following pseudocode (template 4): ** ** rewind temp table ** C: loop over rows of intermediate table ** transfer values form intermediate table into
** end loop ** D: ... */ addrInsTop = sqlite3VdbeAddOp1( v, OP_Rewind, srcTab ); addrCont = sqlite3VdbeCurrentAddr( v ); } else if ( pSelect != null ) { /* This block codes the top of loop only. The complete loop is the ** following pseudocode (template 3): ** ** C: yield X ** if EOF goto D ** insert the select result into
from R..R+n ** goto C ** D: ... */ addrCont = sqlite3VdbeAddOp1( v, OP_Yield, dest.iParm ); addrInsTop = sqlite3VdbeAddOp1( v, OP_If, regEof ); } /* Allocate registers for holding the rowid of the new row, ** the content of the new row, and the assemblied row record. */ regRowid = regIns = pParse.nMem + 1; pParse.nMem += pTab.nCol + 1; if ( IsVirtual( pTab ) ) { regRowid++; pParse.nMem++; } regData = regRowid + 1; /* Run the BEFORE and INSTEAD OF triggers, if there are any */ endOfLoop = sqlite3VdbeMakeLabel( v ); #if !SQLITE_OMIT_TRIGGER if ( ( tmask & TRIGGER_BEFORE ) != 0 ) { int regCols = sqlite3GetTempRange( pParse, pTab.nCol + 1 ); /* build the NEW.* reference row. Note that if there is an INTEGER ** PRIMARY KEY into which a NULL is being inserted, that NULL will be ** translated into a unique ID for the row. But on a BEFORE trigger, ** we do not know what the unique ID will be (because the insert has ** not happened yet) so we substitute a rowid of -1 */ if ( keyColumn < 0 ) { sqlite3VdbeAddOp2( v, OP_Integer, -1, regCols ); } else { int j1; if ( useTempTable ) { sqlite3VdbeAddOp3( v, OP_Column, srcTab, keyColumn, regCols ); } else { Debug.Assert( pSelect == null ); /* Otherwise useTempTable is true */ sqlite3ExprCode( pParse, pList.a[keyColumn].pExpr, regCols ); } j1 = sqlite3VdbeAddOp1( v, OP_NotNull, regCols ); sqlite3VdbeAddOp2( v, OP_Integer, -1, regCols ); sqlite3VdbeJumpHere( v, j1 ); sqlite3VdbeAddOp1( v, OP_MustBeInt, regCols ); } /* Cannot have triggers on a virtual table. If it were possible, ** this block would have to account for hidden column. */ Debug.Assert( !IsVirtual( pTab ) ); /* Create the new column data */ for ( i = 0; i < pTab.nCol; i++ ) { if ( pColumn == null ) { j = i; } else { for ( j = 0; j < pColumn.nId; j++ ) { if ( pColumn.a[j].idx == i ) break; } } if ( ( !useTempTable && null == pList ) || ( pColumn != null && j >= pColumn.nId ) ) { sqlite3ExprCode( pParse, pTab.aCol[i].pDflt, regCols + i + 1 ); } else if ( useTempTable ) { sqlite3VdbeAddOp3( v, OP_Column, srcTab, j, regCols + i + 1 ); } else { Debug.Assert( pSelect == null ); /* Otherwise useTempTable is true */ sqlite3ExprCodeAndCache( pParse, pList.a[j].pExpr, regCols + i + 1 ); } } /* If this is an INSERT on a view with an INSTEAD OF INSERT trigger, ** do not attempt any conversions before assembling the record. ** If this is a real table, attempt conversions as required by the ** table column affinities. */ if ( !isView ) { sqlite3VdbeAddOp2( v, OP_Affinity, regCols + 1, pTab.nCol ); sqlite3TableAffinityStr( v, pTab ); } /* Fire BEFORE or INSTEAD OF triggers */ sqlite3CodeRowTrigger( pParse, pTrigger, TK_INSERT, null, TRIGGER_BEFORE, pTab, regCols - pTab.nCol - 1, onError, endOfLoop ); sqlite3ReleaseTempRange( pParse, regCols, pTab.nCol + 1 ); } #endif /* Push the record number for the new entry onto the stack. The ** record number is a randomly generate integer created by NewRowid ** except when the table has an INTEGER PRIMARY KEY column, in which ** case the record number is the same as that column. */ if ( !isView ) { if ( IsVirtual( pTab ) ) { /* The row that the VUpdate opcode will delete: none */ sqlite3VdbeAddOp2( v, OP_Null, 0, regIns ); } if ( keyColumn >= 0 ) { if ( useTempTable ) { sqlite3VdbeAddOp3( v, OP_Column, srcTab, keyColumn, regRowid ); } else if ( pSelect != null ) { sqlite3VdbeAddOp2( v, OP_SCopy, regFromSelect + keyColumn, regRowid ); } else { VdbeOp pOp; sqlite3ExprCode( pParse, pList.a[keyColumn].pExpr, regRowid ); pOp = sqlite3VdbeGetOp( v, -1 ); if ( ALWAYS( pOp != null ) && pOp.opcode == OP_Null && !IsVirtual( pTab ) ) { appendFlag = true; pOp.opcode = OP_NewRowid; pOp.p1 = baseCur; pOp.p2 = regRowid; pOp.p3 = regAutoinc; } } /* If the PRIMARY KEY expression is NULL, then use OP_NewRowid ** to generate a unique primary key value. */ if ( !appendFlag ) { int j1; if ( !IsVirtual( pTab ) ) { j1 = sqlite3VdbeAddOp1( v, OP_NotNull, regRowid ); sqlite3VdbeAddOp3( v, OP_NewRowid, baseCur, regRowid, regAutoinc ); sqlite3VdbeJumpHere( v, j1 ); } else { j1 = sqlite3VdbeCurrentAddr( v ); sqlite3VdbeAddOp2( v, OP_IsNull, regRowid, j1 + 2 ); } sqlite3VdbeAddOp1( v, OP_MustBeInt, regRowid ); } } else if ( IsVirtual( pTab ) ) { sqlite3VdbeAddOp2( v, OP_Null, 0, regRowid ); } else { sqlite3VdbeAddOp3( v, OP_NewRowid, baseCur, regRowid, regAutoinc ); appendFlag = true; } autoIncStep( pParse, regAutoinc, regRowid ); /* Push onto the stack, data for all columns of the new entry, beginning ** with the first column. */ nHidden = 0; for ( i = 0; i < pTab.nCol; i++ ) { int iRegStore = regRowid + 1 + i; if ( i == pTab.iPKey ) { /* The value of the INTEGER PRIMARY KEY column is always a NULL. ** Whenever this column is read, the record number will be substituted ** in its place. So will fill this column with a NULL to avoid ** taking up data space with information that will never be used. */ sqlite3VdbeAddOp2( v, OP_Null, 0, iRegStore ); continue; } if ( pColumn == null ) { if ( IsHiddenColumn( pTab.aCol[i] ) ) { Debug.Assert( IsVirtual( pTab ) ); j = -1; nHidden++; } else { j = i - nHidden; } } else { for ( j = 0; j < pColumn.nId; j++ ) { if ( pColumn.a[j].idx == i ) break; } } if ( j < 0 || nColumn == 0 || ( pColumn != null && j >= pColumn.nId ) ) { sqlite3ExprCode( pParse, pTab.aCol[i].pDflt, iRegStore ); } else if ( useTempTable ) { sqlite3VdbeAddOp3( v, OP_Column, srcTab, j, iRegStore ); } else if ( pSelect != null ) { sqlite3VdbeAddOp2( v, OP_SCopy, regFromSelect + j, iRegStore ); } else { sqlite3ExprCode( pParse, pList.a[j].pExpr, iRegStore ); } } /* Generate code to check constraints and generate index keys and ** do the insertion. */ #if !SQLITE_OMIT_VIRTUALTABLE if ( IsVirtual( pTab ) ) { VTable pVTab = sqlite3GetVTable( db, pTab ); sqlite3VtabMakeWritable( pParse, pTab ); sqlite3VdbeAddOp4( v, OP_VUpdate, 1, pTab.nCol + 2, regIns, pVTab, P4_VTAB ); sqlite3VdbeChangeP5( v, (byte)( onError == OE_Default ? OE_Abort : onError ) ); sqlite3MayAbort( pParse ); } else #endif { int isReplace = 0; /* Set to true if constraints may cause a replace */ sqlite3GenerateConstraintChecks( pParse, pTab, baseCur, regIns, aRegIdx, keyColumn >= 0 ? 1 : 0, false, onError, endOfLoop, out isReplace ); sqlite3FkCheck( pParse, pTab, 0, regIns ); sqlite3CompleteInsertion( pParse, pTab, baseCur, regIns, aRegIdx, false, appendFlag, isReplace == 0 ); } } /* Update the count of rows that are inserted */ if ( ( db.flags & SQLITE_CountRows ) != 0 ) { sqlite3VdbeAddOp2( v, OP_AddImm, regRowCount, 1 ); } #if !SQLITE_OMIT_TRIGGER if ( pTrigger != null ) { /* Code AFTER triggers */ sqlite3CodeRowTrigger( pParse, pTrigger, TK_INSERT, null, TRIGGER_AFTER, pTab, regData - 2 - pTab.nCol, onError, endOfLoop ); } #endif /* The bottom of the main insertion loop, if the data source ** is a SELECT statement. */ sqlite3VdbeResolveLabel( v, endOfLoop ); if ( useTempTable ) { sqlite3VdbeAddOp2( v, OP_Next, srcTab, addrCont ); sqlite3VdbeJumpHere( v, addrInsTop ); sqlite3VdbeAddOp1( v, OP_Close, srcTab ); } else if ( pSelect != null ) { sqlite3VdbeAddOp2( v, OP_Goto, 0, addrCont ); sqlite3VdbeJumpHere( v, addrInsTop ); } if ( !IsVirtual( pTab ) && !isView ) { /* Close all tables opened */ sqlite3VdbeAddOp1( v, OP_Close, baseCur ); for ( idx = 1, pIdx = pTab.pIndex; pIdx != null; pIdx = pIdx.pNext, idx++ ) { sqlite3VdbeAddOp1( v, OP_Close, idx + baseCur ); } } insert_end: /* Update the sqlite_sequence table by storing the content of the ** maximum rowid counter values recorded while inserting into ** autoincrement tables. */ if ( pParse.nested == 0 && pParse.pTriggerTab == null ) { sqlite3AutoincrementEnd( pParse ); } /* ** Return the number of rows inserted. If this routine is ** generating code because of a call to sqlite3NestedParse(), do not ** invoke the callback function. */ if ( ( db.flags & SQLITE_CountRows ) != 0 && 0 == pParse.nested && null == pParse.pTriggerTab ) { sqlite3VdbeAddOp2( v, OP_ResultRow, regRowCount, 1 ); sqlite3VdbeSetNumCols( v, 1 ); sqlite3VdbeSetColName( v, 0, COLNAME_NAME, "rows inserted", SQLITE_STATIC ); } insert_cleanup: sqlite3SrcListDelete( db, ref pTabList ); sqlite3ExprListDelete( db, ref pList ); sqlite3SelectDelete( db, ref pSelect ); sqlite3IdListDelete( db, ref pColumn ); sqlite3DbFree( db, ref aRegIdx ); } /* Make sure "isView" and other macros defined above are undefined. Otherwise ** thely may interfere with compilation of other functions in this file ** (or in another file, if this file becomes part of the amalgamation). */ //#if isView // #undef isView //#endif //#if pTrigger // #undef pTrigger //#endif //#if tmask // #undef tmask //#endif /* ** Generate code to do constraint checks prior to an INSERT or an UPDATE. ** ** The input is a range of consecutive registers as follows: ** ** 1. The rowid of the row after the update. ** ** 2. The data in the first column of the entry after the update. ** ** i. Data from middle columns... ** ** N. The data in the last column of the entry after the update. ** ** The regRowid parameter is the index of the register containing (1). ** ** If isUpdate is true and rowidChng is non-zero, then rowidChng contains ** the address of a register containing the rowid before the update takes ** place. isUpdate is true for UPDATEs and false for INSERTs. If isUpdate ** is false, indicating an INSERT statement, then a non-zero rowidChng ** indicates that the rowid was explicitly specified as part of the ** INSERT statement. If rowidChng is false, it means that the rowid is ** computed automatically in an insert or that the rowid value is not ** modified by an update. ** ** The code generated by this routine store new index entries into ** registers identified by aRegIdx[]. No index entry is created for ** indices where aRegIdx[i]==0. The order of indices in aRegIdx[] is ** the same as the order of indices on the linked list of indices ** attached to the table. ** ** This routine also generates code to check constraints. NOT NULL, ** CHECK, and UNIQUE constraints are all checked. If a constraint fails, ** then the appropriate action is performed. There are five possible ** actions: ROLLBACK, ABORT, FAIL, REPLACE, and IGNORE. ** ** Constraint type Action What Happens ** --------------- ---------- ---------------------------------------- ** any ROLLBACK The current transaction is rolled back and ** sqlite3_exec() returns immediately with a ** return code of SQLITE_CONSTRAINT. ** ** any ABORT Back out changes from the current command ** only (do not do a complete rollback) then ** cause sqlite3_exec() to return immediately ** with SQLITE_CONSTRAINT. ** ** any FAIL Sqlite_exec() returns immediately with a ** return code of SQLITE_CONSTRAINT. The ** transaction is not rolled back and any ** prior changes are retained. ** ** any IGNORE The record number and data is popped from ** the stack and there is an immediate jump ** to label ignoreDest. ** ** NOT NULL REPLACE The NULL value is replace by the default ** value for that column. If the default value ** is NULL, the action is the same as ABORT. ** ** UNIQUE REPLACE The other row that conflicts with the row ** being inserted is removed. ** ** CHECK REPLACE Illegal. The results in an exception. ** ** Which action to take is determined by the overrideError parameter. ** Or if overrideError==OE_Default, then the pParse.onError parameter ** is used. Or if pParse.onError==OE_Default then the onError value ** for the constraint is used. ** ** The calling routine must open a read/write cursor for pTab with ** cursor number "baseCur". All indices of pTab must also have open ** read/write cursors with cursor number baseCur+i for the i-th cursor. ** Except, if there is no possibility of a REPLACE action then ** cursors do not need to be open for indices where aRegIdx[i]==0. */ static void sqlite3GenerateConstraintChecks( Parse pParse, /* The parser context */ Table pTab, /* the table into which we are inserting */ int baseCur, /* Index of a read/write cursor pointing at pTab */ int regRowid, /* Index of the range of input registers */ int[] aRegIdx, /* Register used by each index. 0 for unused indices */ int rowidChng, /* True if the rowid might collide with existing entry */ bool isUpdate, /* True for UPDATE, False for INSERT */ int overrideError, /* Override onError to this if not OE_Default */ int ignoreDest, /* Jump to this label on an OE_Ignore resolution */ out int pbMayReplace /* OUT: Set to true if constraint may cause a replace */ ) { int i; /* loop counter */ Vdbe v; /* VDBE under constrution */ int nCol; /* Number of columns */ int onError; /* Conflict resolution strategy */ int j1; /* Addresss of jump instruction */ int j2 = 0, j3; /* Addresses of jump instructions */ int regData; /* Register containing first data column */ int iCur; /* Table cursor number */ Index pIdx; /* Pointer to one of the indices */ bool seenReplace = false; /* True if REPLACE is used to resolve INT PK conflict */ int regOldRowid = ( rowidChng != 0 && isUpdate ) ? rowidChng : regRowid; v = sqlite3GetVdbe( pParse ); Debug.Assert( v != null ); Debug.Assert( pTab.pSelect == null ); /* This table is not a VIEW */ nCol = pTab.nCol; regData = regRowid + 1; /* Test all NOT NULL constraints. */ for ( i = 0; i < nCol; i++ ) { if ( i == pTab.iPKey ) { continue; } onError = pTab.aCol[i].notNull; if ( onError == OE_None ) continue; if ( overrideError != OE_Default ) { onError = overrideError; } else if ( onError == OE_Default ) { onError = OE_Abort; } if ( onError == OE_Replace && pTab.aCol[i].pDflt == null ) { onError = OE_Abort; } Debug.Assert( onError == OE_Rollback || onError == OE_Abort || onError == OE_Fail || onError == OE_Ignore || onError == OE_Replace ); switch ( onError ) { case OE_Abort: { sqlite3MayAbort( pParse ); goto case OE_Fail; } case OE_Rollback: case OE_Fail: { string zMsg; sqlite3VdbeAddOp3( v, OP_HaltIfNull, SQLITE_CONSTRAINT, onError, regData + i ); zMsg = sqlite3MPrintf( pParse.db, "%s.%s may not be NULL", pTab.zName, pTab.aCol[i].zName ); sqlite3VdbeChangeP4( v, -1, zMsg, P4_DYNAMIC ); break; } case OE_Ignore: { sqlite3VdbeAddOp2( v, OP_IsNull, regData + i, ignoreDest ); break; } default: { Debug.Assert( onError == OE_Replace ); j1 = sqlite3VdbeAddOp1( v, OP_NotNull, regData + i ); sqlite3ExprCode( pParse, pTab.aCol[i].pDflt, regData + i ); sqlite3VdbeJumpHere( v, j1 ); break; } } } /* Test all CHECK constraints */ #if !SQLITE_OMIT_CHECK if ( pTab.pCheck != null && ( pParse.db.flags & SQLITE_IgnoreChecks ) == 0 ) { int allOk = sqlite3VdbeMakeLabel( v ); pParse.ckBase = regData; sqlite3ExprIfTrue( pParse, pTab.pCheck, allOk, SQLITE_JUMPIFNULL ); onError = overrideError != OE_Default ? overrideError : OE_Abort; if ( onError == OE_Ignore ) { sqlite3VdbeAddOp2( v, OP_Goto, 0, ignoreDest ); } else { if ( onError == OE_Replace ) onError = OE_Abort; /* IMP: R-15569-63625 */ sqlite3HaltConstraint( pParse, onError, (string)null, 0 ); } sqlite3VdbeResolveLabel( v, allOk ); } #endif // * !SQLITE_OMIT_CHECK) */ /* If we have an INTEGER PRIMARY KEY, make sure the primary key ** of the new record does not previously exist. Except, if this ** is an UPDATE and the primary key is not changing, that is OK. */ if ( rowidChng != 0 ) { onError = pTab.keyConf; if ( overrideError != OE_Default ) { onError = overrideError; } else if ( onError == OE_Default ) { onError = OE_Abort; } if ( isUpdate ) { j2 = sqlite3VdbeAddOp3( v, OP_Eq, regRowid, 0, rowidChng ); } j3 = sqlite3VdbeAddOp3( v, OP_NotExists, baseCur, 0, regRowid ); switch ( onError ) { default: { onError = OE_Abort; /* Fall thru into the next case */ } goto case OE_Rollback; case OE_Rollback: case OE_Abort: case OE_Fail: { sqlite3HaltConstraint( pParse, onError, "PRIMARY KEY must be unique", P4_STATIC ); break; } case OE_Replace: { /* If there are DELETE triggers on this table and the ** recursive-triggers flag is set, call GenerateRowDelete() to ** remove the conflicting row from the the table. This will fire ** the triggers and remove both the table and index b-tree entries. ** ** Otherwise, if there are no triggers or the recursive-triggers ** flag is not set, but the table has one or more indexes, call ** GenerateRowIndexDelete(). This removes the index b-tree entries ** only. The table b-tree entry will be replaced by the new entry ** when it is inserted. ** ** If either GenerateRowDelete() or GenerateRowIndexDelete() is called, ** also invoke MultiWrite() to indicate that this VDBE may require ** statement rollback (if the statement is aborted after the delete ** takes place). Earlier versions called sqlite3MultiWrite() regardless, ** but being more selective here allows statements like: ** ** REPLACE INTO t(rowid) VALUES($newrowid) ** ** to run without a statement journal if there are no indexes on the ** table. */ Trigger pTrigger = null; if ( ( pParse.db.flags & SQLITE_RecTriggers ) != 0 ) { int iDummy; pTrigger = sqlite3TriggersExist( pParse, pTab, TK_DELETE, null, out iDummy ); } if ( pTrigger != null || sqlite3FkRequired( pParse, pTab, null, 0 ) != 0 ) { sqlite3MultiWrite( pParse ); sqlite3GenerateRowDelete( pParse, pTab, baseCur, regRowid, 0, pTrigger, OE_Replace ); } else if ( pTab.pIndex != null ) { sqlite3MultiWrite( pParse ); sqlite3GenerateRowIndexDelete( pParse, pTab, baseCur, 0 ); } seenReplace = true; break; } case OE_Ignore: { Debug.Assert( !seenReplace ); sqlite3VdbeAddOp2( v, OP_Goto, 0, ignoreDest ); break; } } sqlite3VdbeJumpHere( v, j3 ); if ( isUpdate ) { sqlite3VdbeJumpHere( v, j2 ); } } /* Test all UNIQUE constraints by creating entries for each UNIQUE ** index and making sure that duplicate entries do not already exist. ** Add the new records to the indices as we go. */ for ( iCur = 0, pIdx = pTab.pIndex; pIdx != null; pIdx = pIdx.pNext, iCur++ ) { int regIdx; int regR; if ( aRegIdx[iCur] == 0 ) continue; /* Skip unused indices */ /* Create a key for accessing the index entry */ regIdx = sqlite3GetTempRange( pParse, pIdx.nColumn + 1 ); for ( i = 0; i < pIdx.nColumn; i++ ) { int idx = pIdx.aiColumn[i]; if ( idx == pTab.iPKey ) { sqlite3VdbeAddOp2( v, OP_SCopy, regRowid, regIdx + i ); } else { sqlite3VdbeAddOp2( v, OP_SCopy, regData + idx, regIdx + i ); } } sqlite3VdbeAddOp2( v, OP_SCopy, regRowid, regIdx + i ); sqlite3VdbeAddOp3( v, OP_MakeRecord, regIdx, pIdx.nColumn + 1, aRegIdx[iCur] ); sqlite3VdbeChangeP4( v, -1, sqlite3IndexAffinityStr( v, pIdx ), P4_TRANSIENT ); sqlite3ExprCacheAffinityChange( pParse, regIdx, pIdx.nColumn + 1 ); /* Find out what action to take in case there is an indexing conflict */ onError = pIdx.onError; if ( onError == OE_None ) { sqlite3ReleaseTempRange( pParse, regIdx, pIdx.nColumn + 1 ); continue; /* pIdx is not a UNIQUE index */ } if ( overrideError != OE_Default ) { onError = overrideError; } else if ( onError == OE_Default ) { onError = OE_Abort; } if ( seenReplace ) { if ( onError == OE_Ignore ) onError = OE_Replace; else if ( onError == OE_Fail ) onError = OE_Abort; } /* Check to see if the new index entry will be unique */ regR = sqlite3GetTempReg( pParse ); sqlite3VdbeAddOp2( v, OP_SCopy, regOldRowid, regR ); j3 = sqlite3VdbeAddOp4( v, OP_IsUnique, baseCur + iCur + 1, 0, regR, regIdx,//regR, SQLITE_INT_TO_PTR(regIdx), P4_INT32 ); sqlite3ReleaseTempRange( pParse, regIdx, pIdx.nColumn + 1 ); /* Generate code that executes if the new index entry is not unique */ Debug.Assert( onError == OE_Rollback || onError == OE_Abort || onError == OE_Fail || onError == OE_Ignore || onError == OE_Replace ); switch ( onError ) { case OE_Rollback: case OE_Abort: case OE_Fail: { int j; StrAccum errMsg = new StrAccum( 200 ); string zSep; string zErr; sqlite3StrAccumInit( errMsg, null, 0, 200 ); errMsg.db = pParse.db; zSep = pIdx.nColumn > 1 ? "columns " : "column "; for ( j = 0; j < pIdx.nColumn; j++ ) { string zCol = pTab.aCol[pIdx.aiColumn[j]].zName; sqlite3StrAccumAppend( errMsg, zSep, -1 ); zSep = ", "; sqlite3StrAccumAppend( errMsg, zCol, -1 ); } sqlite3StrAccumAppend( errMsg, pIdx.nColumn > 1 ? " are not unique" : " is not unique", -1 ); zErr = sqlite3StrAccumFinish( errMsg ); sqlite3HaltConstraint( pParse, onError, zErr, 0 ); sqlite3DbFree( errMsg.db, ref zErr ); break; } case OE_Ignore: { Debug.Assert( !seenReplace ); sqlite3VdbeAddOp2( v, OP_Goto, 0, ignoreDest ); break; } default: { Trigger pTrigger = null; Debug.Assert( onError == OE_Replace ); sqlite3MultiWrite( pParse ); if ( ( pParse.db.flags & SQLITE_RecTriggers ) != 0 ) { int iDummy; pTrigger = sqlite3TriggersExist( pParse, pTab, TK_DELETE, null, out iDummy ); } sqlite3GenerateRowDelete( pParse, pTab, baseCur, regR, 0, pTrigger, OE_Replace ); seenReplace = true; break; } } sqlite3VdbeJumpHere( v, j3 ); sqlite3ReleaseTempReg( pParse, regR ); } //if ( pbMayReplace ) { pbMayReplace = seenReplace ? 1 : 0; } } /* ** This routine generates code to finish the INSERT or UPDATE operation ** that was started by a prior call to sqlite3GenerateConstraintChecks. ** A consecutive range of registers starting at regRowid contains the ** rowid and the content to be inserted. ** ** The arguments to this routine should be the same as the first six ** arguments to sqlite3GenerateConstraintChecks. */ static void sqlite3CompleteInsertion( Parse pParse, /* The parser context */ Table pTab, /* the table into which we are inserting */ int baseCur, /* Index of a read/write cursor pointing at pTab */ int regRowid, /* Range of content */ int[] aRegIdx, /* Register used by each index. 0 for unused indices */ bool isUpdate, /* True for UPDATE, False for INSERT */ bool appendBias, /* True if this is likely to be an append */ bool useSeekResult /* True to set the USESEEKRESULT flag on OP_[Idx]Insert */ ) { int i; Vdbe v; int nIdx; Index pIdx; u8 pik_flags; int regData; int regRec; v = sqlite3GetVdbe( pParse ); Debug.Assert( v != null ); Debug.Assert( pTab.pSelect == null ); /* This table is not a VIEW */ for ( nIdx = 0, pIdx = pTab.pIndex; pIdx != null; pIdx = pIdx.pNext, nIdx++ ) { } for ( i = nIdx - 1; i >= 0; i-- ) { if ( aRegIdx[i] == 0 ) continue; sqlite3VdbeAddOp2( v, OP_IdxInsert, baseCur + i + 1, aRegIdx[i] ); if ( useSeekResult ) { sqlite3VdbeChangeP5( v, OPFLAG_USESEEKRESULT ); } } regData = regRowid + 1; regRec = sqlite3GetTempReg( pParse ); sqlite3VdbeAddOp3( v, OP_MakeRecord, regData, pTab.nCol, regRec ); sqlite3TableAffinityStr( v, pTab ); sqlite3ExprCacheAffinityChange( pParse, regData, pTab.nCol ); if ( pParse.nested != 0 ) { pik_flags = 0; } else { pik_flags = OPFLAG_NCHANGE; pik_flags |= ( isUpdate ? OPFLAG_ISUPDATE : OPFLAG_LASTROWID ); } if ( appendBias ) { pik_flags |= OPFLAG_APPEND; } if ( useSeekResult ) { pik_flags |= OPFLAG_USESEEKRESULT; } sqlite3VdbeAddOp3( v, OP_Insert, baseCur, regRec, regRowid ); if ( pParse.nested == 0 ) { sqlite3VdbeChangeP4( v, -1, pTab.zName, P4_TRANSIENT ); } sqlite3VdbeChangeP5( v, pik_flags ); } /* ** Generate code that will open cursors for a table and for all ** indices of that table. The "baseCur" parameter is the cursor number used ** for the table. Indices are opened on subsequent cursors. ** ** Return the number of indices on the table. */ static int sqlite3OpenTableAndIndices( Parse pParse, /* Parsing context */ Table pTab, /* Table to be opened */ int baseCur, /* VdbeCursor number assigned to the table */ int op /* OP_OpenRead or OP_OpenWrite */ ) { int i; int iDb; Index pIdx; Vdbe v; if ( IsVirtual( pTab ) ) return 0; iDb = sqlite3SchemaToIndex( pParse.db, pTab.pSchema ); v = sqlite3GetVdbe( pParse ); Debug.Assert( v != null ); sqlite3OpenTable( pParse, baseCur, iDb, pTab, op ); for ( i = 1, pIdx = pTab.pIndex; pIdx != null; pIdx = pIdx.pNext, i++ ) { KeyInfo pKey = sqlite3IndexKeyinfo( pParse, pIdx ); Debug.Assert( pIdx.pSchema == pTab.pSchema ); sqlite3VdbeAddOp4( v, op, i + baseCur, pIdx.tnum, iDb, pKey, P4_KEYINFO_HANDOFF ); #if SQLITE_DEBUG VdbeComment( v, "%s", pIdx.zName ); #endif } if ( pParse.nTab < baseCur + i ) { pParse.nTab = baseCur + i; } return i - 1; } #if SQLITE_TEST /* ** The following global variable is incremented whenever the ** transfer optimization is used. This is used for testing ** purposes only - to make sure the transfer optimization really ** is happening when it is suppose to. */ #if !TCLSH static int sqlite3_xferopt_count = 0; #else static tcl.lang.Var.SQLITE3_GETSET sqlite3_xferopt_count = new tcl.lang.Var.SQLITE3_GETSET( "sqlite3_xferopt_count" ); #endif #endif // * SQLITE_TEST */ #if !SQLITE_OMIT_XFER_OPT /* ** Check to collation names to see if they are compatible. */ static bool xferCompatibleCollation( string z1, string z2 ) { if ( z1 == null ) { return z2 == null; } if ( z2 == null ) { return false; } return z1.Equals( z2 ,StringComparison.OrdinalIgnoreCase ) ; } /* ** Check to see if index pSrc is compatible as a source of data ** for index pDest in an insert transfer optimization. The rules ** for a compatible index: ** ** * The index is over the same set of columns ** * The same DESC and ASC markings occurs on all columns ** * The same onError processing (OE_Abort, OE_Ignore, etc) ** * The same collating sequence on each column */ static bool xferCompatibleIndex( Index pDest, Index pSrc ) { int i; Debug.Assert( pDest != null && pSrc != null ); Debug.Assert( pDest.pTable != pSrc.pTable ); if ( pDest.nColumn != pSrc.nColumn ) { return false; /* Different number of columns */ } if ( pDest.onError != pSrc.onError ) { return false; /* Different conflict resolution strategies */ } for ( i = 0; i < pSrc.nColumn; i++ ) { if ( pSrc.aiColumn[i] != pDest.aiColumn[i] ) { return false; /* Different columns indexed */ } if ( pSrc.aSortOrder[i] != pDest.aSortOrder[i] ) { return false; /* Different sort orders */ } if ( !xferCompatibleCollation( pSrc.azColl[i], pDest.azColl[i] ) ) { return false; /* Different collating sequences */ } } /* If no test above fails then the indices must be compatible */ return true; } /* ** Attempt the transfer optimization on INSERTs of the form ** ** INSERT INTO tab1 SELECT * FROM tab2; ** ** This optimization is only attempted if ** ** (1) tab1 and tab2 have identical schemas including all the ** same indices and constraints ** ** (2) tab1 and tab2 are different tables ** ** (3) There must be no triggers on tab1 ** ** (4) The result set of the SELECT statement is "*" ** ** (5) The SELECT statement has no WHERE, HAVING, ORDER BY, GROUP BY, ** or LIMIT clause. ** ** (6) The SELECT statement is a simple (not a compound) select that ** contains only tab2 in its FROM clause ** ** This method for implementing the INSERT transfers raw records from ** tab2 over to tab1. The columns are not decoded. Raw records from ** the indices of tab2 are transfered to tab1 as well. In so doing, ** the resulting tab1 has much less fragmentation. ** ** This routine returns TRUE if the optimization is attempted. If any ** of the conditions above fail so that the optimization should not ** be attempted, then this routine returns FALSE. */ static int xferOptimization( Parse pParse, /* Parser context */ Table pDest, /* The table we are inserting into */ Select pSelect, /* A SELECT statement to use as the data source */ int onError, /* How to handle constraint errors */ int iDbDest /* The database of pDest */ ) { ExprList pEList; /* The result set of the SELECT */ Table pSrc; /* The table in the FROM clause of SELECT */ Index pSrcIdx, pDestIdx; /* Source and destination indices */ SrcList_item pItem; /* An element of pSelect.pSrc */ int i; /* Loop counter */ int iDbSrc; /* The database of pSrc */ int iSrc, iDest; /* Cursors from source and destination */ int addr1, addr2; /* Loop addresses */ int emptyDestTest; /* Address of test for empty pDest */ int emptySrcTest; /* Address of test for empty pSrc */ Vdbe v; /* The VDBE we are building */ KeyInfo pKey; /* Key information for an index */ int regAutoinc; /* Memory register used by AUTOINC */ bool destHasUniqueIdx = false; /* True if pDest has a UNIQUE index */ int regData, regRowid; /* Registers holding data and rowid */ if ( pSelect == null ) { return 0; /* Must be of the form INSERT INTO ... SELECT ... */ } #if !SQLITE_OMIT_TRIGGER if ( sqlite3TriggerList( pParse, pDest ) != null ) { return 0; /* tab1 must not have triggers */ } #endif if ( ( pDest.tabFlags & TF_Virtual ) != 0 ) { return 0; /* tab1 must not be a virtual table */ } if ( onError == OE_Default ) { onError = OE_Abort; } if ( onError != OE_Abort && onError != OE_Rollback ) { return 0; /* Cannot do OR REPLACE or OR IGNORE or OR FAIL */ } Debug.Assert( pSelect.pSrc != null ); /* allocated even if there is no FROM clause */ if ( pSelect.pSrc.nSrc != 1 ) { return 0; /* FROM clause must have exactly one term */ } if ( pSelect.pSrc.a[0].pSelect != null ) { return 0; /* FROM clause cannot contain a subquery */ } if ( pSelect.pWhere != null ) { return 0; /* SELECT may not have a WHERE clause */ } if ( pSelect.pOrderBy != null ) { return 0; /* SELECT may not have an ORDER BY clause */ } /* Do not need to test for a HAVING clause. If HAVING is present but ** there is no ORDER BY, we will get an error. */ if ( pSelect.pGroupBy != null ) { return 0; /* SELECT may not have a GROUP BY clause */ } if ( pSelect.pLimit != null ) { return 0; /* SELECT may not have a LIMIT clause */ } Debug.Assert( pSelect.pOffset == null ); /* Must be so if pLimit==0 */ if ( pSelect.pPrior != null ) { return 0; /* SELECT may not be a compound query */ } if ( ( pSelect.selFlags & SF_Distinct ) != 0 ) { return 0; /* SELECT may not be DISTINCT */ } pEList = pSelect.pEList; Debug.Assert( pEList != null ); if ( pEList.nExpr != 1 ) { return 0; /* The result set must have exactly one column */ } Debug.Assert( pEList.a[0].pExpr != null ); if ( pEList.a[0].pExpr.op != TK_ALL ) { return 0; /* The result set must be the special operator "*" */ } /* At this point we have established that the statement is of the ** correct syntactic form to participate in this optimization. Now ** we have to check the semantics. */ pItem = pSelect.pSrc.a[0]; pSrc = sqlite3LocateTable( pParse, 0, pItem.zName, pItem.zDatabase ); if ( pSrc == null ) { return 0; /* FROM clause does not contain a real table */ } if ( pSrc == pDest ) { return 0; /* tab1 and tab2 may not be the same table */ } if ( ( pSrc.tabFlags & TF_Virtual ) != 0 ) { return 0; /* tab2 must not be a virtual table */ } if ( pSrc.pSelect != null ) { return 0; /* tab2 may not be a view */ } if ( pDest.nCol != pSrc.nCol ) { return 0; /* Number of columns must be the same in tab1 and tab2 */ } if ( pDest.iPKey != pSrc.iPKey ) { return 0; /* Both tables must have the same INTEGER PRIMARY KEY */ } for ( i = 0; i < pDest.nCol; i++ ) { if ( pDest.aCol[i].affinity != pSrc.aCol[i].affinity ) { return 0; /* Affinity must be the same on all columns */ } if ( !xferCompatibleCollation( pDest.aCol[i].zColl, pSrc.aCol[i].zColl ) ) { return 0; /* Collating sequence must be the same on all columns */ } if ( pDest.aCol[i].notNull != 0 && pSrc.aCol[i].notNull == 0 ) { return 0; /* tab2 must be NOT NULL if tab1 is */ } } for ( pDestIdx = pDest.pIndex; pDestIdx != null; pDestIdx = pDestIdx.pNext ) { if ( pDestIdx.onError != OE_None ) { destHasUniqueIdx = true; } for ( pSrcIdx = pSrc.pIndex; pSrcIdx != null; pSrcIdx = pSrcIdx.pNext ) { if ( xferCompatibleIndex( pDestIdx, pSrcIdx ) ) break; } if ( pSrcIdx == null ) { return 0; /* pDestIdx has no corresponding index in pSrc */ } } #if !SQLITE_OMIT_CHECK if ( pDest.pCheck != null && 0 != sqlite3ExprCompare( pSrc.pCheck, pDest.pCheck ) ) { return 0; /* Tables have different CHECK constraints. Ticket #2252 */ } #endif #if !SQLITE_OMIT_FOREIGN_KEY /* Disallow the transfer optimization if the destination table constains ** any foreign key constraints. This is more restrictive than necessary. ** But the main beneficiary of the transfer optimization is the VACUUM ** command, and the VACUUM command disables foreign key constraints. So ** the extra complication to make this rule less restrictive is probably ** not worth the effort. Ticket [6284df89debdfa61db8073e062908af0c9b6118e] */ if ( ( pParse.db.flags & SQLITE_ForeignKeys ) != 0 && pDest.pFKey != null ) { return 0; } #endif /* If we get this far, it means either: ** ** * We can always do the transfer if the table contains an ** an integer primary key ** ** * We can conditionally do the transfer if the destination ** table is empty. */ #if SQLITE_TEST #if !TCLSH sqlite3_xferopt_count++; #else sqlite3_xferopt_count.iValue++; #endif #endif iDbSrc = sqlite3SchemaToIndex( pParse.db, pSrc.pSchema ); v = sqlite3GetVdbe( pParse ); sqlite3CodeVerifySchema( pParse, iDbSrc ); iSrc = pParse.nTab++; iDest = pParse.nTab++; regAutoinc = autoIncBegin( pParse, iDbDest, pDest ); sqlite3OpenTable( pParse, iDest, iDbDest, pDest, OP_OpenWrite ); if ( ( pDest.iPKey < 0 && pDest.pIndex != null ) || destHasUniqueIdx ) { /* If tables do not have an INTEGER PRIMARY KEY and there ** are indices to be copied and the destination is not empty, ** we have to disallow the transfer optimization because the ** the rowids might change which will mess up indexing. ** ** Or if the destination has a UNIQUE index and is not empty, ** we also disallow the transfer optimization because we cannot ** insure that all entries in the union of DEST and SRC will be ** unique. */ addr1 = sqlite3VdbeAddOp2( v, OP_Rewind, iDest, 0 ); emptyDestTest = sqlite3VdbeAddOp2( v, OP_Goto, 0, 0 ); sqlite3VdbeJumpHere( v, addr1 ); } else { emptyDestTest = 0; } sqlite3OpenTable( pParse, iSrc, iDbSrc, pSrc, OP_OpenRead ); emptySrcTest = sqlite3VdbeAddOp2( v, OP_Rewind, iSrc, 0 ); regData = sqlite3GetTempReg( pParse ); regRowid = sqlite3GetTempReg( pParse ); if ( pDest.iPKey >= 0 ) { addr1 = sqlite3VdbeAddOp2( v, OP_Rowid, iSrc, regRowid ); addr2 = sqlite3VdbeAddOp3( v, OP_NotExists, iDest, 0, regRowid ); sqlite3HaltConstraint( pParse, onError, "PRIMARY KEY must be unique", P4_STATIC ); sqlite3VdbeJumpHere( v, addr2 ); autoIncStep( pParse, regAutoinc, regRowid ); } else if ( pDest.pIndex == null ) { addr1 = sqlite3VdbeAddOp2( v, OP_NewRowid, iDest, regRowid ); } else { addr1 = sqlite3VdbeAddOp2( v, OP_Rowid, iSrc, regRowid ); Debug.Assert( ( pDest.tabFlags & TF_Autoincrement ) == 0 ); } sqlite3VdbeAddOp2( v, OP_RowData, iSrc, regData ); sqlite3VdbeAddOp3( v, OP_Insert, iDest, regData, regRowid ); sqlite3VdbeChangeP5( v, OPFLAG_NCHANGE | OPFLAG_LASTROWID | OPFLAG_APPEND ); sqlite3VdbeChangeP4( v, -1, pDest.zName, 0 ); sqlite3VdbeAddOp2( v, OP_Next, iSrc, addr1 ); for ( pDestIdx = pDest.pIndex; pDestIdx != null; pDestIdx = pDestIdx.pNext ) { for ( pSrcIdx = pSrc.pIndex; pSrcIdx != null; pSrcIdx = pSrcIdx.pNext ) { if ( xferCompatibleIndex( pDestIdx, pSrcIdx ) ) break; } Debug.Assert( pSrcIdx != null ); sqlite3VdbeAddOp2( v, OP_Close, iSrc, 0 ); sqlite3VdbeAddOp2( v, OP_Close, iDest, 0 ); pKey = sqlite3IndexKeyinfo( pParse, pSrcIdx ); sqlite3VdbeAddOp4( v, OP_OpenRead, iSrc, pSrcIdx.tnum, iDbSrc, pKey, P4_KEYINFO_HANDOFF ); #if SQLITE_DEBUG VdbeComment( v, "%s", pSrcIdx.zName ); #endif pKey = sqlite3IndexKeyinfo( pParse, pDestIdx ); sqlite3VdbeAddOp4( v, OP_OpenWrite, iDest, pDestIdx.tnum, iDbDest, pKey, P4_KEYINFO_HANDOFF ); #if SQLITE_DEBUG VdbeComment( v, "%s", pDestIdx.zName ); #endif addr1 = sqlite3VdbeAddOp2( v, OP_Rewind, iSrc, 0 ); sqlite3VdbeAddOp2( v, OP_RowKey, iSrc, regData ); sqlite3VdbeAddOp3( v, OP_IdxInsert, iDest, regData, 1 ); sqlite3VdbeAddOp2( v, OP_Next, iSrc, addr1 + 1 ); sqlite3VdbeJumpHere( v, addr1 ); } sqlite3VdbeJumpHere( v, emptySrcTest ); sqlite3ReleaseTempReg( pParse, regRowid ); sqlite3ReleaseTempReg( pParse, regData ); sqlite3VdbeAddOp2( v, OP_Close, iSrc, 0 ); sqlite3VdbeAddOp2( v, OP_Close, iDest, 0 ); if ( emptyDestTest != 0 ) { sqlite3VdbeAddOp2( v, OP_Halt, SQLITE_OK, 0 ); sqlite3VdbeJumpHere( v, emptyDestTest ); sqlite3VdbeAddOp2( v, OP_Close, iDest, 0 ); return 0; } else { return 1; } } #endif // * SQLITE_OMIT_XFER_OPT */ } }