📄 insert.c
字号:
** initially pointing to an entry that is being updated. The isUpdate** flag causes extra code to be generated so that the "base" cursor** is still pointing at the same entry after the routine returns.** Without the isUpdate flag, the "base" cursor might be moved.*/void sqliteGenerateConstraintChecks( Parse *pParse, /* The parser context */ Table *pTab, /* the table into which we are inserting */ int base, /* Index of a read/write cursor pointing at pTab */ char *aIdxUsed, /* Which indices are used. NULL means all are used */ int recnoChng, /* True if the record number will change */ 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 addr; int extra; int iCur; Index *pIdx; int seenReplace = 0; int jumpInst1, jumpInst2; int contAddr; int hasTwoRecnos = (isUpdate && recnoChng); v = sqliteGetVdbe(pParse); assert( v!=0 ); assert( pTab->pSelect==0 ); /* This table is not a VIEW */ nCol = pTab->nCol; /* 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( pParse->db->onError!=OE_Default ){ onError = pParse->db->onError; }else if( onError==OE_Default ){ onError = OE_Abort; } if( onError==OE_Replace && pTab->aCol[i].zDflt==0 ){ onError = OE_Abort; } sqliteVdbeAddOp(v, OP_Dup, nCol-1-i, 1); addr = sqliteVdbeAddOp(v, OP_NotNull, 1, 0); switch( onError ){ case OE_Rollback: case OE_Abort: case OE_Fail: { char *zMsg = 0; sqliteVdbeAddOp(v, OP_Halt, SQLITE_CONSTRAINT, onError); sqliteSetString(&zMsg, pTab->zName, ".", pTab->aCol[i].zName, " may not be NULL", (char*)0); sqliteVdbeChangeP3(v, -1, zMsg, P3_DYNAMIC); break; } case OE_Ignore: { sqliteVdbeAddOp(v, OP_Pop, nCol+1+hasTwoRecnos, 0); sqliteVdbeAddOp(v, OP_Goto, 0, ignoreDest); break; } case OE_Replace: { sqliteVdbeOp3(v, OP_String, 0, 0, pTab->aCol[i].zDflt, P3_STATIC); sqliteVdbeAddOp(v, OP_Push, nCol-i, 0); break; } default: assert(0); } sqliteVdbeChangeP2(v, addr, sqliteVdbeCurrentAddr(v)); } /* Test all CHECK constraints */ /**** TBD ****/ /* 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( recnoChng ){ onError = pTab->keyConf; if( overrideError!=OE_Default ){ onError = overrideError; }else if( pParse->db->onError!=OE_Default ){ onError = pParse->db->onError; }else if( onError==OE_Default ){ onError = OE_Abort; } if( isUpdate ){ sqliteVdbeAddOp(v, OP_Dup, nCol+1, 1); sqliteVdbeAddOp(v, OP_Dup, nCol+1, 1); jumpInst1 = sqliteVdbeAddOp(v, OP_Eq, 0, 0); } sqliteVdbeAddOp(v, OP_Dup, nCol, 1); jumpInst2 = sqliteVdbeAddOp(v, OP_NotExists, base, 0); switch( onError ){ default: { onError = OE_Abort; /* Fall thru into the next case */ } case OE_Rollback: case OE_Abort: case OE_Fail: { sqliteVdbeOp3(v, OP_Halt, SQLITE_CONSTRAINT, onError, "PRIMARY KEY must be unique", P3_STATIC); break; } case OE_Replace: { sqliteGenerateRowIndexDelete(pParse->db, v, pTab, base, 0); if( isUpdate ){ sqliteVdbeAddOp(v, OP_Dup, nCol+hasTwoRecnos, 1); sqliteVdbeAddOp(v, OP_MoveTo, base, 0); } seenReplace = 1; break; } case OE_Ignore: { assert( seenReplace==0 ); sqliteVdbeAddOp(v, OP_Pop, nCol+1+hasTwoRecnos, 0); sqliteVdbeAddOp(v, OP_Goto, 0, ignoreDest); break; } } contAddr = sqliteVdbeCurrentAddr(v); sqliteVdbeChangeP2(v, jumpInst2, contAddr); if( isUpdate ){ sqliteVdbeChangeP2(v, jumpInst1, contAddr); sqliteVdbeAddOp(v, OP_Dup, nCol+1, 1); sqliteVdbeAddOp(v, OP_MoveTo, base, 0); } } /* 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. */ extra = -1; for(iCur=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, iCur++){ if( aIdxUsed && aIdxUsed[iCur]==0 ) continue; /* Skip unused indices */ extra++; /* Create a key for accessing the index entry */ sqliteVdbeAddOp(v, OP_Dup, nCol+extra, 1); for(i=0; i<pIdx->nColumn; i++){ int idx = pIdx->aiColumn[i]; if( idx==pTab->iPKey ){ sqliteVdbeAddOp(v, OP_Dup, i+extra+nCol+1, 1); }else{ sqliteVdbeAddOp(v, OP_Dup, i+extra+nCol-idx, 1); } } jumpInst1 = sqliteVdbeAddOp(v, OP_MakeIdxKey, pIdx->nColumn, 0); if( pParse->db->file_format>=4 ) sqliteAddIdxKeyType(v, pIdx); /* 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( pParse->db->onError!=OE_Default ){ onError = pParse->db->onError; }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 */ sqliteVdbeAddOp(v, OP_Dup, extra+nCol+1+hasTwoRecnos, 1); jumpInst2 = sqliteVdbeAddOp(v, OP_IsUnique, base+iCur+1, 0); /* Generate code that executes if the new index entry is not unique */ switch( onError ){ case OE_Rollback: case OE_Abort: case OE_Fail: { int j, n1, n2; char zErrMsg[200]; strcpy(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 ){ strcpy(&zErrMsg[n1], ", "); n1 += 2; } if( n1+n2>sizeof(zErrMsg)-30 ){ strcpy(&zErrMsg[n1], "..."); n1 += 3; break; }else{ strcpy(&zErrMsg[n1], zCol); n1 += n2; } } strcpy(&zErrMsg[n1], pIdx->nColumn>1 ? " are not unique" : " is not unique"); sqliteVdbeOp3(v, OP_Halt, SQLITE_CONSTRAINT, onError, zErrMsg, 0); break; } case OE_Ignore: { assert( seenReplace==0 ); sqliteVdbeAddOp(v, OP_Pop, nCol+extra+3+hasTwoRecnos, 0); sqliteVdbeAddOp(v, OP_Goto, 0, ignoreDest); break; } case OE_Replace: { sqliteGenerateRowDelete(pParse->db, v, pTab, base, 0); if( isUpdate ){ sqliteVdbeAddOp(v, OP_Dup, nCol+extra+1+hasTwoRecnos, 1); sqliteVdbeAddOp(v, OP_MoveTo, base, 0); } seenReplace = 1; break; } default: assert(0); } contAddr = sqliteVdbeCurrentAddr(v);#if NULL_DISTINCT_FOR_UNIQUE sqliteVdbeChangeP2(v, jumpInst1, contAddr);#endif sqliteVdbeChangeP2(v, jumpInst2, contAddr); }}/*** This routine generates code to finish the INSERT or UPDATE operation** that was started by a prior call to sqliteGenerateConstraintChecks.** The stack must contain keys for all active indices followed by data** and the recno for the new entry. This routine creates the new** entries in all indices and in the main table.**** The arguments to this routine should be the same as the first six** arguments to sqliteGenerateConstraintChecks.*/void sqliteCompleteInsertion( Parse *pParse, /* The parser context */ Table *pTab, /* the table into which we are inserting */ int base, /* Index of a read/write cursor pointing at pTab */ char *aIdxUsed, /* Which indices are used. NULL means all are used */ int recnoChng, /* True if the record number will change */ int isUpdate, /* True for UPDATE, False for INSERT */ int newIdx /* Index of NEW table for triggers. -1 if none */){ int i; Vdbe *v; int nIdx; Index *pIdx; v = sqliteGetVdbe(pParse); assert( v!=0 ); assert( pTab->pSelect==0 ); /* This table is not a VIEW */ for(nIdx=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, nIdx++){} for(i=nIdx-1; i>=0; i--){ if( aIdxUsed && aIdxUsed[i]==0 ) continue; sqliteVdbeAddOp(v, OP_IdxPut, base+i+1, 0); } sqliteVdbeAddOp(v, OP_MakeRecord, pTab->nCol, 0); if( newIdx>=0 ){ sqliteVdbeAddOp(v, OP_Dup, 1, 0); sqliteVdbeAddOp(v, OP_Dup, 1, 0); sqliteVdbeAddOp(v, OP_PutIntKey, newIdx, 0); } sqliteVdbeAddOp(v, OP_PutIntKey, base, (pParse->trigStack?0:OPFLAG_NCHANGE) | (isUpdate?0:OPFLAG_LASTROWID) | OPFLAG_CSCHANGE); if( isUpdate && recnoChng ){ sqliteVdbeAddOp(v, OP_Pop, 1, 0); }}/*** Generate code that will open write cursors for a table and for all** indices of that table. The "base" parameter is the cursor number used** for the table. Indices are opened on subsequent cursors.**** Return the total number of cursors opened. This is always at least** 1 (for the main table) plus more for each cursor.*/int sqliteOpenTableAndIndices(Parse *pParse, Table *pTab, int base){ int i; Index *pIdx; Vdbe *v = sqliteGetVdbe(pParse); assert( v!=0 ); sqliteVdbeAddOp(v, OP_Integer, pTab->iDb, 0); sqliteVdbeOp3(v, OP_OpenWrite, base, pTab->tnum, pTab->zName, P3_STATIC); for(i=1, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){ sqliteVdbeAddOp(v, OP_Integer, pIdx->iDb, 0); sqliteVdbeOp3(v, OP_OpenWrite, i+base, pIdx->tnum, pIdx->zName, P3_STATIC); } return i;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -