using System; using System.Diagnostics; using System.Text; using u8 = System.Byte; 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. */ private 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. */ private 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 */ private 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. */ private 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. */ private 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. */ private 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. */ private 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. */ private 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 private static void sqlite3Insert(Parse pParse, SrcList pTabList, int null_3, int null_4, IdList pColumn, int onError) { sqlite3Insert(pParse, pTabList, null, null, pColumn, onError); } private static void sqlite3Insert(Parse pParse, SrcList pTabList, int null_3, Select pSelect, IdList pColumn, int onError) { sqlite3Insert(pParse, pTabList, null, pSelect, pColumn, onError); } private static void sqlite3Insert(Parse pParse, SrcList pTabList, ExprList pList, int null_4, IdList pColumn, int onError) { sqlite3Insert(pParse, pTabList, pList, null, pColumn, onError); } private 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 */ Db pDb; /* The database containing table being inserted into */ 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); pDb = db.aDb[iDb]; #if !SQLITE_OMIT_AUTHORIZATION 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. */ private 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. */ private 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. */ private 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. */ private 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 */ private 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. */ private 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 */ } }