⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 insert.c

📁 sqlite 嵌入式数据库的源码
💻 C
📖 第 1 页 / 共 3 页
字号:
** The code generated by this routine pushes additional entries onto** the stack which are the keys for new index entries for the new record.** The order of index keys is the same as the order of the indices on** the pTable->pIndex list.  A key is only created for index i if ** aIdxUsed!=0 and aIdxUsed[i]!=0.**** 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 "base".  All indices of pTab must also have open** read/write cursors with cursor number base+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 aIdxUsed[i]==0.**** If the isUpdate flag is true, it means that the "base" cursor is** 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 sqlite3GenerateConstraintChecks(  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 rowidChng,      /* 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=0, jumpInst2;  int contAddr;  int hasTwoRowids = (isUpdate && rowidChng);  v = sqlite3GetVdbe(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( onError==OE_Default ){      onError = OE_Abort;    }    if( onError==OE_Replace && pTab->aCol[i].pDflt==0 ){      onError = OE_Abort;    }    sqlite3VdbeAddOp(v, OP_Dup, nCol-1-i, 1);    addr = sqlite3VdbeAddOp(v, OP_NotNull, 1, 0);    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;        sqlite3VdbeAddOp(v, OP_Halt, SQLITE_CONSTRAINT, onError);        sqlite3SetString(&zMsg, pTab->zName, ".", pTab->aCol[i].zName,                        " may not be NULL", (char*)0);        sqlite3VdbeChangeP3(v, -1, zMsg, P3_DYNAMIC);        break;      }      case OE_Ignore: {        sqlite3VdbeAddOp(v, OP_Pop, nCol+1+hasTwoRowids, 0);        sqlite3VdbeAddOp(v, OP_Goto, 0, ignoreDest);        break;      }      case OE_Replace: {        sqlite3ExprCode(pParse, pTab->aCol[i].pDflt);        sqlite3VdbeAddOp(v, OP_Push, nCol-i, 0);        break;      }    }    sqlite3VdbeChangeP2(v, addr, sqlite3VdbeCurrentAddr(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( rowidChng ){    onError = pTab->keyConf;    if( overrideError!=OE_Default ){      onError = overrideError;    }else if( onError==OE_Default ){      onError = OE_Abort;    }        if( isUpdate ){      sqlite3VdbeAddOp(v, OP_Dup, nCol+1, 1);      sqlite3VdbeAddOp(v, OP_Dup, nCol+1, 1);      jumpInst1 = sqlite3VdbeAddOp(v, OP_Eq, 0, 0);    }    sqlite3VdbeAddOp(v, OP_Dup, nCol, 1);    jumpInst2 = sqlite3VdbeAddOp(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: {        sqlite3VdbeOp3(v, OP_Halt, SQLITE_CONSTRAINT, onError,                         "PRIMARY KEY must be unique", P3_STATIC);        break;      }      case OE_Replace: {        sqlite3GenerateRowIndexDelete(pParse->db, v, pTab, base, 0);        if( isUpdate ){          sqlite3VdbeAddOp(v, OP_Dup, nCol+hasTwoRowids, 1);          sqlite3VdbeAddOp(v, OP_MoveGe, base, 0);        }        seenReplace = 1;        break;      }      case OE_Ignore: {        assert( seenReplace==0 );        sqlite3VdbeAddOp(v, OP_Pop, nCol+1+hasTwoRowids, 0);        sqlite3VdbeAddOp(v, OP_Goto, 0, ignoreDest);        break;      }    }    contAddr = sqlite3VdbeCurrentAddr(v);    sqlite3VdbeChangeP2(v, jumpInst2, contAddr);    if( isUpdate ){      sqlite3VdbeChangeP2(v, jumpInst1, contAddr);      sqlite3VdbeAddOp(v, OP_Dup, nCol+1, 1);      sqlite3VdbeAddOp(v, OP_MoveGe, 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 */    sqlite3VdbeAddOp(v, OP_Dup, nCol+extra, 1);    for(i=0; i<pIdx->nColumn; i++){      int idx = pIdx->aiColumn[i];      if( idx==pTab->iPKey ){        sqlite3VdbeAddOp(v, OP_Dup, i+extra+nCol+1, 1);      }else{        sqlite3VdbeAddOp(v, OP_Dup, i+extra+nCol-idx, 1);      }    }    jumpInst1 = sqlite3VdbeAddOp(v, OP_MakeRecord, pIdx->nColumn, (1<<24));    sqlite3IndexAffinityStr(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( 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 */    sqlite3VdbeAddOp(v, OP_Dup, extra+nCol+1+hasTwoRowids, 1);    jumpInst2 = sqlite3VdbeAddOp(v, OP_IsUnique, base+iCur+1, 0);    /* 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];        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");        sqlite3VdbeOp3(v, OP_Halt, SQLITE_CONSTRAINT, onError, zErrMsg, 0);        break;      }      case OE_Ignore: {        assert( seenReplace==0 );        sqlite3VdbeAddOp(v, OP_Pop, nCol+extra+3+hasTwoRowids, 0);        sqlite3VdbeAddOp(v, OP_Goto, 0, ignoreDest);        break;      }      case OE_Replace: {        sqlite3GenerateRowDelete(pParse->db, v, pTab, base, 0);        if( isUpdate ){          sqlite3VdbeAddOp(v, OP_Dup, nCol+extra+1+hasTwoRowids, 1);          sqlite3VdbeAddOp(v, OP_MoveGe, base, 0);        }        seenReplace = 1;        break;      }    }    contAddr = sqlite3VdbeCurrentAddr(v);    assert( contAddr<(1<<24) );#if NULL_DISTINCT_FOR_UNIQUE    sqlite3VdbeChangeP2(v, jumpInst1, contAddr | (1<<24));#endif    sqlite3VdbeChangeP2(v, jumpInst2, contAddr);  }}/*** This routine generates code to finish the INSERT or UPDATE operation** that was started by a prior call to sqlite3GenerateConstraintChecks.** The stack must contain keys for all active indices followed by data** and the rowid 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 sqlite3GenerateConstraintChecks.*/void sqlite3CompleteInsertion(  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 rowidChng,      /* 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;  int pik_flags;  v = sqlite3GetVdbe(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;    sqlite3VdbeAddOp(v, OP_IdxInsert, base+i+1, 0);  }  sqlite3VdbeAddOp(v, OP_MakeRecord, pTab->nCol, 0);  sqlite3TableAffinityStr(v, pTab);#ifndef SQLITE_OMIT_TRIGGER  if( newIdx>=0 ){    sqlite3VdbeAddOp(v, OP_Dup, 1, 0);    sqlite3VdbeAddOp(v, OP_Dup, 1, 0);    sqlite3VdbeAddOp(v, OP_Insert, newIdx, 0);  }#endif  if( pParse->nested ){    pik_flags = 0;  }else{    pik_flags = (OPFLAG_NCHANGE|(isUpdate?0:OPFLAG_LASTROWID));  }  sqlite3VdbeAddOp(v, OP_Insert, base, pik_flags);    if( isUpdate && rowidChng ){    sqlite3VdbeAddOp(v, OP_Pop, 1, 0);  }}/*** Generate code that will open 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.*/void sqlite3OpenTableAndIndices(  Parse *pParse,   /* Parsing context */  Table *pTab,     /* Table to be opened */  int base,        /* Cursor number assigned to the table */  int op           /* OP_OpenRead or OP_OpenWrite */){  int i;  Index *pIdx;  Vdbe *v = sqlite3GetVdbe(pParse);  assert( v!=0 );  sqlite3VdbeAddOp(v, OP_Integer, pTab->iDb, 0);  sqlite3VdbeAddOp(v, op, base, pTab->tnum);  VdbeComment((v, "# %s", pTab->zName));  sqlite3VdbeAddOp(v, OP_SetNumColumns, base, pTab->nCol);  for(i=1, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){    sqlite3VdbeAddOp(v, OP_Integer, pIdx->iDb, 0);    sqlite3VdbeOp3(v, op, i+base, pIdx->tnum,                   (char*)&pIdx->keyInfo, P3_KEYINFO);  }  if( pParse->nTab<=base+i ){    pParse->nTab = base+i;  }}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -