📄 insert.c
字号:
}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) ){ pParse->pVirtualLock = 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, 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 loop, if the data source is a SELECT statement */ sqlite3VdbeResolveLabel(v, endOfLoop); if( useTempTable ){ sqlite3VdbeAddOp2(v, OP_Next, srcTab, iCont); sqlite3VdbeResolveLabel(v, iBreak); sqlite3VdbeAddOp2(v, OP_Close, srcTab, 0); }else if( pSelect ){ sqlite3VdbeAddOp2(v, OP_Return, 0, 0); sqlite3VdbeResolveLabel(v, iCleanup); } if( !IsVirtual(pTab) && !isView ){ /* Close all tables opened */ sqlite3VdbeAddOp2(v, OP_Close, baseCur, 0); for(idx=1, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, idx++){ sqlite3VdbeAddOp2(v, OP_Close, idx+baseCur, 0); } } /* 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", P4_STATIC); }insert_cleanup: sqlite3SrcListDelete(pTabList); sqlite3ExprListDelete(pList); sqlite3SelectDelete(pSelect); sqlite3IdListDelete(pColumn); sqlite3_free(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** 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.*/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 */ int 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 */){ int i; Vdbe *v; int nCol; int onError; int j1, j2, j3; /* Addresses of jump instructions */ int regData; /* Register containing first data column */ int iCur; Index *pIdx; int seenReplace = 0; int hasTwoRowids = (isUpdate && rowidChng); v = sqlite3GetVdbe(pParse); assert( v!=0 ); assert( pTab->pSelect==0 ); /* 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==0 ){ onError = OE_Abort; } j1 = sqlite3VdbeAddOp1(v, OP_NotNull, regData+i); 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: { char *zMsg = 0; sqlite3VdbeAddOp2(v, OP_Halt, SQLITE_CONSTRAINT, onError); sqlite3SetString(&zMsg, pTab->zName, ".", pTab->aCol[i].zName, " may not be NULL", (char*)0); sqlite3VdbeChangeP4(v, -1, zMsg, P4_DYNAMIC); break; } case OE_Ignore: { sqlite3VdbeAddOp2(v, OP_Goto, 0, ignoreDest); break; } case OE_Replace: { sqlite3ExprCode(pParse, pTab->aCol[i].pDflt, regData+i); break; } } sqlite3VdbeJumpHere(v, j1); } /* Test all CHECK constraints */#ifndef SQLITE_OMIT_CHECK if( pTab->pCheck && (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{ sqlite3VdbeAddOp2(v, OP_Halt, SQLITE_CONSTRAINT, onError); } sqlite3VdbeResolveLabel(v, allOk); }#endif /* !defined(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 ){ onError = pTab->keyConf; if( overrideError!=OE_Default ){ onError = overrideError; }else if( onError==OE_Default ){ onError = OE_Abort; } if( onError!=OE_Replace || pTab->pIndex ){ if( isUpdate ){ j2 = sqlite3VdbeAddOp3(v, OP_Eq, regRowid, 0, regRowid-1); } j3 = sqlite3VdbeAddOp3(v, OP_NotExists, baseCur, 0, regRowid); switch( onError ){ default: { onError = OE_Abort; /* Fall thru into the next case */ } case OE_Rollback: case OE_Abort: case OE_Fail: { sqlite3VdbeAddOp4(v, OP_Halt, SQLITE_CONSTRAINT, onError, 0, "PRIMARY KEY must be unique", P4_STATIC); break; } case OE_Replace: { sqlite3GenerateRowIndexDelete(pParse, pTab, baseCur, 0); seenReplace = 1; break; } case OE_Ignore: { assert( seenReplace==0 ); 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; 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]); sqlite3IndexAffinityStr(v, pIdx); sqlite3ExprCacheAffinityChange(pParse, regIdx, pIdx->nColumn+1); sqlite3ReleaseTempRange(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 ) 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 */ j2 = sqlite3VdbeAddOp3(v, OP_IsNull, regIdx, 0, pIdx->nColumn); regR = sqlite3GetTempReg(pParse); sqlite3VdbeAddOp2(v, OP_SCopy, regRowid-hasTwoRowids, regR); j3 = sqlite3VdbeAddOp4(v, OP_IsUnique, baseCur+iCur+1, 0, regR, (char*)(sqlite3_intptr_t)aRegIdx[iCur], P4_INT32); /* Generate code that executes if the new index entry is not unique */ 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, n1, n2; char zErrMsg[200]; sqlite3_snprintf(sizeof(zErrMsg), zErrMsg, pIdx->nColumn>1 ? "columns " : "column "); n1 = strlen(zErrMsg); for(j=0; j<pIdx->nColumn && n1<sizeof(zErrMsg)-30; j++){ char *zCol = pTab->aCol[pIdx->aiColumn[j]].zName; n2 = strlen(zCol); if( j>0 ){ sqlite3_snprintf(sizeof(zErrMsg)-n1, &zErrMsg[n1], ", "); n1 += 2; } if( n1+n2>sizeof(zErrMsg)-30 ){ sqlite3_snprintf(sizeof(zErrMsg)-n1, &zErrMsg[n1], "..."); n1 += 3; break; }else{ sqlite3_snprintf(sizeof(zErrMsg)-n1, &zErrMsg[n1], "%s", zCol); n1 += n2; } } sqlite3_snprintf(sizeof(zErrMsg)-n1, &zErrMsg[n1], pIdx->nColumn>1 ? " are not unique" : " is not unique"); sqlite3VdbeAddOp4(v, OP_Halt, SQLITE_CONSTRAINT, onError, 0, zErrMsg,0); break; } case OE_Ignore: { assert( seenReplace==0 ); sqlite3VdbeAddOp2(v, OP_Goto, 0, ignoreDest); break; } case OE_Replace: { sqlite3GenerateRowDelete(pParse, pTab, baseCur, regR, 0); seenReplace = 1; break; } } sqlite3VdbeJumpHere(v, j2); sqlite3VdbeJumpHere(v, j3); sqlite3ReleaseTempReg(pParse, regR); }}/*** 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.**
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -