📄 insert.c
字号:
aRegIdx = sqlite3DbMallocRaw(db, sizeof(int)*(nIdx+1)); if( aRegIdx==0 ){ 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 <table> ** end loop ** D: ... */ addrInsTop = sqlite3VdbeAddOp1(v, OP_Rewind, srcTab); addrCont = sqlite3VdbeCurrentAddr(v); }else if( pSelect ){ /* 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 <table> 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. */ regRecord = ++pParse->nMem; 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( triggers_exist & TRIGGER_BEFORE ){ int regRowid; int regCols; int regRec; /* 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 */ regRowid = sqlite3GetTempReg(pParse); if( keyColumn<0 ){ sqlite3VdbeAddOp2(v, OP_Integer, -1, regRowid); }else if( useTempTable ){ sqlite3VdbeAddOp3(v, OP_Column, srcTab, keyColumn, regRowid); }else{ int j1; assert( pSelect==0 ); /* Otherwise useTempTable is true */ sqlite3ExprCode(pParse, pList->a[keyColumn].pExpr, regRowid); j1 = sqlite3VdbeAddOp1(v, OP_NotNull, regRowid); sqlite3VdbeAddOp2(v, OP_Integer, -1, regRowid); sqlite3VdbeJumpHere(v, j1); sqlite3VdbeAddOp1(v, OP_MustBeInt, regRowid); } /* Cannot have triggers on a virtual table. If it were possible, ** this block would have to account for hidden column. */ assert(!IsVirtual(pTab)); /* Create the new column data */ regCols = sqlite3GetTempRange(pParse, pTab->nCol); for(i=0; i<pTab->nCol; i++){ if( pColumn==0 ){ j = i; }else{ for(j=0; j<pColumn->nId; j++){ if( pColumn->a[j].idx==i ) break; } } if( pColumn && j>=pColumn->nId ){ sqlite3ExprCode(pParse, pTab->aCol[i].pDflt, regCols+i); }else if( useTempTable ){ sqlite3VdbeAddOp3(v, OP_Column, srcTab, j, regCols+i); }else{ assert( pSelect==0 ); /* Otherwise useTempTable is true */ sqlite3ExprCodeAndCache(pParse, pList->a[j].pExpr, regCols+i); } } regRec = sqlite3GetTempReg(pParse); sqlite3VdbeAddOp3(v, OP_MakeRecord, regCols, pTab->nCol, regRec); /* 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 ){ sqlite3TableAffinityStr(v, pTab); } sqlite3VdbeAddOp3(v, OP_Insert, newIdx, regRec, regRowid); sqlite3ReleaseTempReg(pParse, regRec); sqlite3ReleaseTempReg(pParse, regRowid); sqlite3ReleaseTempRange(pParse, regCols, pTab->nCol); /* Fire BEFORE or INSTEAD OF triggers */ if( sqlite3CodeRowTrigger(pParse, TK_INSERT, 0, TRIGGER_BEFORE, pTab, newIdx, -1, onError, endOfLoop, 0, 0) ){ goto insert_cleanup; } } /* 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 ){ sqlite3VdbeAddOp2(v, OP_SCopy, regFromSelect+keyColumn, regRowid); }else{ VdbeOp *pOp; sqlite3ExprCode(pParse, pList->a[keyColumn].pExpr, regRowid); pOp = sqlite3VdbeGetOp(v, sqlite3VdbeCurrentAddr(v) - 1); if( pOp && pOp->opcode==OP_Null && !IsVirtual(pTab) ){ appendFlag = 1; 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 = 1; } 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==0 ){ if( IsHiddenColumn(&pTab->aCol[i]) ){ 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 && j>=pColumn->nId) ){ sqlite3ExprCode(pParse, pTab->aCol[i].pDflt, iRegStore); }else if( useTempTable ){ sqlite3VdbeAddOp3(v, OP_Column, srcTab, j, iRegStore); }else if( pSelect ){ 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. */#ifndef SQLITE_OMIT_VIRTUALTABLE if( IsVirtual(pTab) ){ sqlite3VtabMakeWritable(pParse, pTab); sqlite3VdbeAddOp4(v, OP_VUpdate, 1, pTab->nCol+2, regIns, (const char*)pTab->pVtab, P4_VTAB); }else#endif { sqlite3GenerateConstraintChecks( pParse, pTab, baseCur, regIns, aRegIdx, keyColumn>=0, 0, onError, endOfLoop ); sqlite3CompleteInsertion( pParse, pTab, baseCur, regIns, aRegIdx, 0, (triggers_exist & TRIGGER_AFTER)!=0 ? newIdx : -1, appendFlag ); } } /* Update the count of rows that are inserted */ if( (db->flags & SQLITE_CountRows)!=0 ){ sqlite3VdbeAddOp2(v, OP_AddImm, regRowCount, 1); } if( triggers_exist ){ /* Code AFTER triggers */ if( sqlite3CodeRowTrigger(pParse, TK_INSERT, 0, TRIGGER_AFTER, pTab, newIdx, -1, onError, endOfLoop, 0, 0) ){ goto insert_cleanup; } } /* 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 ){ 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; pIdx=pIdx->pNext, idx++){ sqlite3VdbeAddOp1(v, OP_Close, idx+baseCur); } } /* Update the sqlite_sequence table by storing the content of the ** counter value in memory regAutoinc back into the sqlite_sequence ** table. */ autoIncEnd(pParse, iDb, pTab, regAutoinc); /* ** 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 && pParse->nested==0 && !pParse->trigStack ){ sqlite3VdbeAddOp2(v, OP_ResultRow, regRowCount, 1); sqlite3VdbeSetNumCols(v, 1); sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "rows inserted", SQLITE_STATIC); }insert_cleanup: sqlite3SrcListDelete(db, pTabList); sqlite3ExprListDelete(db, pList); sqlite3SelectDelete(db, pSelect); sqlite3IdListDelete(db, pColumn); sqlite3DbFree(db, aRegIdx);}/*** 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 to be updated before the update. This** value is omitted unless we are doing an UPDATE that involves a** change to the record number or writing to a virtual table.**** 2. The rowid of the row after the update.**** 3. 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 (2).**** The old rowid shown as entry (1) above is omitted unless both isUpdate** and rowidChng are 1. isUpdate is true for UPDATEs and false for** INSERTs. RowidChng means that the new rowid is explicitly specified by** the update or 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 the 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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -