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

📄 insert.c

📁 嵌入式数据系统软件!
💻 C
📖 第 1 页 / 共 4 页
字号:
/*** 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.**** $Id: insert.c,v 1.197 2007/12/14 16:11:09 drh Exp $*/#include "sqliteInt.h"/*** Set P3 of the most recently inserted opcode to a column affinity** string for 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*/void sqlite3IndexAffinityStr(Vdbe *v, Index *pIdx){  if( !pIdx->zColAff ){    /* 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);    pIdx->zColAff = (char *)sqlite3DbMallocZero(db, pIdx->nColumn+1);    if( !pIdx->zColAff ){      return;    }    for(n=0; n<pIdx->nColumn; n++){      pIdx->zColAff[n] = pTab->aCol[pIdx->aiColumn[n]].affinity;    }    pIdx->zColAff[pIdx->nColumn] = '\0';  }   sqlite3VdbeChangeP3(v, -1, pIdx->zColAff, 0);}/*** Set P3 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*/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 ){    char *zColAff;    int i;    sqlite3 *db = sqlite3VdbeDb(v);    zColAff = (char *)sqlite3DbMallocZero(db, pTab->nCol+1);    if( !zColAff ){      return;    }    for(i=0; i<pTab->nCol; i++){      zColAff[i] = pTab->aCol[i].affinity;    }    zColAff[pTab->nCol] = '\0';    pTab->zColAff = zColAff;  }  sqlite3VdbeChangeP3(v, -1, pTab->zColAff, 0);}/*** 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 <iDb, pTab> SELECT ..." can ** run without using temporary table for the results of the SELECT. */static int readsTable(Vdbe *v, int iStartAddr, int iDb, Table *pTab){  int i;  int iEnd = sqlite3VdbeCurrentAddr(v);  for(i=iStartAddr; i<iEnd; i++){    VdbeOp *pOp = sqlite3VdbeGetOp(v, i);    assert( pOp!=0 );    if( pOp->opcode==OP_OpenRead ){      VdbeOp *pPrior = &pOp[-1];      int tnum = pOp->p2;      assert( i>iStartAddr );      assert( pPrior->opcode==OP_Integer );      if( pPrior->p1==iDb ){        Index *pIndex;        if( tnum==pTab->tnum ){          return 1;        }        for(pIndex=pTab->pIndex; pIndex; pIndex=pIndex->pNext){          if( tnum==pIndex->tnum ){            return 1;          }        }      }    }#ifndef SQLITE_OMIT_VIRTUALTABLE    if( pOp->opcode==OP_VOpen && pOp->p3==(const char*)pTab->pVtab ){      assert( pOp->p3!=0 );      assert( pOp->p3type==P3_VTAB );      return 1;    }#endif  }  return 0;}#ifndef SQLITE_OMIT_AUTOINCREMENT/*** Write out code to initialize the autoincrement logic.  This code** looks up the current autoincrement value in the sqlite_sequence** table and stores that value in a memory cell.  Code generated by** autoIncStep() will keep that memory cell holding the largest** rowid value.  Code generated by autoIncEnd() will write the new** largest value of the counter back into the sqlite_sequence table.**** This routine returns the index of the mem[] cell that contains** the maximum rowid counter.**** Two memory cells are allocated.  The next memory cell after the** one returned holds the rowid in sqlite_sequence where we will** write back the revised maximum rowid.*/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;  if( pTab->autoInc ){    Vdbe *v = pParse->pVdbe;    Db *pDb = &pParse->db->aDb[iDb];    int iCur = pParse->nTab;    int addr;    assert( v );    addr = sqlite3VdbeCurrentAddr(v);    memId = pParse->nMem+1;    pParse->nMem += 2;    sqlite3OpenTable(pParse, iCur, iDb, pDb->pSchema->pSeqTab, OP_OpenRead);    sqlite3VdbeAddOp(v, OP_Rewind, iCur, addr+13);    sqlite3VdbeAddOp(v, OP_Column, iCur, 0);    sqlite3VdbeOp3(v, OP_String8, 0, 0, pTab->zName, 0);    sqlite3VdbeAddOp(v, OP_Ne, 0x100, addr+12);    sqlite3VdbeAddOp(v, OP_Rowid, iCur, 0);    sqlite3VdbeAddOp(v, OP_MemStore, memId-1, 1);    sqlite3VdbeAddOp(v, OP_Column, iCur, 1);    sqlite3VdbeAddOp(v, OP_MemStore, memId, 1);    sqlite3VdbeAddOp(v, OP_Goto, 0, addr+13);    sqlite3VdbeAddOp(v, OP_Next, iCur, addr+4);    sqlite3VdbeAddOp(v, OP_Close, iCur, 0);  }  return memId;}/*** 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.*/static void autoIncStep(Parse *pParse, int memId){  if( memId>0 ){    sqlite3VdbeAddOp(pParse->pVdbe, OP_MemMax, memId, 0);  }}/*** After doing one or more inserts, the maximum rowid is stored** in mem[memId].  Generate code to write this value back into the** the sqlite_sequence table.*/static void autoIncEnd(  Parse *pParse,     /* The parsing context */  int iDb,           /* Index of the database holding pTab */  Table *pTab,       /* Table we are inserting into */  int memId          /* Memory cell holding the maximum rowid */){  if( pTab->autoInc ){    int iCur = pParse->nTab;    Vdbe *v = pParse->pVdbe;    Db *pDb = &pParse->db->aDb[iDb];    int addr;    assert( v );    addr = sqlite3VdbeCurrentAddr(v);    sqlite3OpenTable(pParse, iCur, iDb, pDb->pSchema->pSeqTab, OP_OpenWrite);    sqlite3VdbeAddOp(v, OP_MemLoad, memId-1, 0);    sqlite3VdbeAddOp(v, OP_NotNull, -1, addr+7);    sqlite3VdbeAddOp(v, OP_Pop, 1, 0);    sqlite3VdbeAddOp(v, OP_NewRowid, iCur, 0);    sqlite3VdbeOp3(v, OP_String8, 0, 0, pTab->zName, 0);    sqlite3VdbeAddOp(v, OP_MemLoad, memId, 0);    sqlite3VdbeAddOp(v, OP_MakeRecord, 2, 0);    sqlite3VdbeAddOp(v, OP_Insert, iCur, OPFLAG_APPEND);    sqlite3VdbeAddOp(v, OP_Close, iCur, 0);  }}#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)# define autoIncEnd(A,B,C,D)#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.  The template looks like this:****         open write cursor to <table> and its indices**         puts VALUES clause expressions onto the stack**         write the resulting record into <table>**         cleanup**** The three remaining templates assume the statement is of the form****   INSERT INTO <table> SELECT ...**** If the SELECT clause is of the restricted form "SELECT * FROM <table2>" -** 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 <table2> and <table1> are distinct tables but have identical** schemas, including all the same indices, then a special optimization** is invoked that copies raw records from <table2> over to <table1>.** See the xferOptimization() function for the implementation of this** template.  This is the second template.****         open a write cursor to <table>**         open read cursor on <table2>**         transfer all records in <table2> over to <table>**         close cursors**         foreach index on <table>**           open a write cursor on the <table> index**           open a read cursor on the corresponding <table2> index**           transfer all records from the read to the write cursors**           close cursors**         end foreach**** The third template is for when the second template does not apply** and the SELECT clause does not read from <table> at any time.** The generated code follows this template:****         goto B**      A: setup for the SELECT**         loop over the rows in the SELECT**           gosub C**         end loop**         cleanup after the SELECT**         goto D**      B: open write cursor to <table> and its indices**         goto A**      C: insert the select result into <table>**         return**      D: cleanup**** The fourth 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:****         goto B**      A: setup for the SELECT**         loop over the tables in the SELECT**           gosub C**         end loop**         cleanup after the SELECT**         goto D**      C: insert the select result into the intermediate table**         return**      B: open a cursor to an intermediate table**         goto A**      D: open write cursor to <table> and its indices**         loop over the intermediate table**           transfer values form intermediate table into <table>**         end the loop**         cleanup*/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 */){  Table *pTab;          /* The table to insert into */  char *zTab;           /* Name of the table into which we are inserting */  const char *zDb;      /* Name of the database holding this table */  int i, j, idx;        /* 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 base = 0;         /* VDBE Cursor number for pTab */  int iCont=0,iBreak=0; /* Beginning and end of the loop over srcTab */  sqlite3 *db;          /* The main database structure */  int keyColumn = -1;   /* Column that is the INTEGER PRIMARY KEY */  int endOfLoop;        /* Label for the end of the insertion loop */  int useTempTable = 0; /* Store SELECT results in intermediate table */  int srcTab = 0;       /* Data comes from this temporary cursor if >=0 */  int iSelectLoop = 0;  /* Address of code that implements the SELECT */  int iCleanup = 0;     /* Address of the cleanup code */  int iInsertBlock = 0; /* Address of the subroutine used to insert data */  int iCntMem = 0;      /* Memory cell used for the row counter */  int newIdx = -1;      /* Cursor for the NEW table */  Db *pDb;              /* The database containing table being inserted into */  int counterMem = 0;   /* Memory cell holding AUTOINCREMENT counter */  int appendFlag = 0;   /* True if the insert is likely to be an append */  int iDb;  int nHidden = 0;#ifndef SQLITE_OMIT_TRIGGER  int isView;                 /* True if attempting to insert into a view */  int triggers_exist = 0;     /* True if there are FOR EACH ROW triggers */#endif  db = pParse->db;  if( pParse->nErr || db->mallocFailed ){    goto insert_cleanup;  }  /* Locate the table into which we will be inserting new information.  */  assert( pTabList->nSrc==1 );  zTab = pTabList->a[0].zName;  if( zTab==0 ) goto insert_cleanup;  pTab = sqlite3SrcListLookup(pParse, pTabList);  if( pTab==0 ){    goto insert_cleanup;  }  iDb = sqlite3SchemaToIndex(db, pTab->pSchema);  assert( iDb<db->nDb );  pDb = &db->aDb[iDb];  zDb = pDb->zName;  if( sqlite3AuthCheck(pParse, SQLITE_INSERT, pTab->zName, 0, zDb) ){    goto insert_cleanup;  }  /* Figure out if we have any triggers and if the table being  ** inserted into is a view  */#ifndef SQLITE_OMIT_TRIGGER  triggers_exist = sqlite3TriggersExist(pParse, pTab, TK_INSERT, 0);  isView = pTab->pSelect!=0;

⌨️ 快捷键说明

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