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

📄 insert.c

📁 sqlite数据库管理系统开放源码
💻 C
📖 第 1 页 / 共 3 页
字号:
/*** 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.94 2004/02/24 01:05:33 drh Exp $*/#include "sqliteInt.h"/*** 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 three 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**** If the statement is of the form****   INSERT INTO <table> SELECT ...**** And the SELECT clause does not read from <table> at any time, then** the generated code follows this template:****         goto B**      A: setup for the SELECT**         loop over the tables 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 third 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 sqliteInsert(  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;             /* VDBE Cursor number for pTab */  int iCont, iBreak;    /* Beginning and end of the loop over srcTab */  sqlite *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;     /* Store SELECT results in intermediate table */  int srcTab;           /* Data comes from this temporary cursor if >=0 */  int iSelectLoop;      /* Address of code that implements the SELECT */  int iCleanup;         /* Address of the cleanup code */  int iInsertBlock;     /* Address of the subroutine used to insert data */  int iCntMem;          /* Memory cell used for the row counter */  int isView;           /* True if attempting to insert into a view */  int row_triggers_exist = 0; /* True if there are FOR EACH ROW triggers */  int before_triggers;        /* True if there are BEFORE triggers */  int after_triggers;         /* True if there are AFTER triggers */  int newIdx = -1;            /* Cursor for the NEW table */  if( pParse->nErr || sqlite_malloc_failed ) goto insert_cleanup;  db = pParse->db;  /* 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 = sqliteSrcListLookup(pParse, pTabList);  if( pTab==0 ){    goto insert_cleanup;  }  assert( pTab->iDb<db->nDb );  zDb = db->aDb[pTab->iDb].zName;  if( sqliteAuthCheck(pParse, SQLITE_INSERT, pTab->zName, 0, zDb) ){    goto insert_cleanup;  }  /* Ensure that:  *  (a) the table is not read-only,   *  (b) that if it is a view then ON INSERT triggers exist  */  before_triggers = sqliteTriggersExist(pParse, pTab->pTrigger, TK_INSERT,                                        TK_BEFORE, TK_ROW, 0);  after_triggers = sqliteTriggersExist(pParse, pTab->pTrigger, TK_INSERT,                                       TK_AFTER, TK_ROW, 0);  row_triggers_exist = before_triggers || after_triggers;  isView = pTab->pSelect!=0;  if( sqliteIsReadOnly(pParse, pTab, before_triggers) ){    goto insert_cleanup;  }  if( pTab==0 ) goto insert_cleanup;  /* If pTab is really a view, make sure it has been initialized.  */  if( isView && sqliteViewGetColumnNames(pParse, pTab) ){    goto insert_cleanup;  }  /* Allocate a VDBE  */  v = sqliteGetVdbe(pParse);  if( v==0 ) goto insert_cleanup;  sqliteBeginWriteOperation(pParse, pSelect || row_triggers_exist, pTab->iDb);  /* if there are row triggers, allocate a temp table for new.* references. */  if( row_triggers_exist ){    newIdx = pParse->nTab++;  }  /* Figure out how many columns of data are supplied.  If the data  ** is coming from a SELECT statement, then this step also generates  ** all the code to implement the SELECT statement and invoke a subroutine  ** to process each row of the result. (Template 2.) If the SELECT  ** statement uses the the table that is being inserted into, then the  ** subroutine is also coded here.  That subroutine stores the SELECT  ** results in a temporary table. (Template 3.)  */  if( pSelect ){    /* Data is coming from a SELECT.  Generate code to implement that SELECT    */    int rc, iInitCode;    iInitCode = sqliteVdbeAddOp(v, OP_Goto, 0, 0);    iSelectLoop = sqliteVdbeCurrentAddr(v);    iInsertBlock = sqliteVdbeMakeLabel(v);    rc = sqliteSelect(pParse, pSelect, SRT_Subroutine, iInsertBlock, 0,0,0);    if( rc || pParse->nErr || sqlite_malloc_failed ) goto insert_cleanup;    iCleanup = sqliteVdbeMakeLabel(v);    sqliteVdbeAddOp(v, OP_Goto, 0, iCleanup);    assert( pSelect->pEList );    nColumn = pSelect->pEList->nExpr;    /* Set useTempTable to TRUE if the result of the SELECT statement    ** should be written into a temporary table.  Set to FALSE if each    ** row of the SELECT can be written directly into the result table.    **    ** A temp table must be used if the table being updated is also one    ** of the tables being read by the SELECT statement.  Also use a     ** temp table in the case of row triggers.    */    if( row_triggers_exist ){      useTempTable = 1;    }else{      int addr = sqliteVdbeFindOp(v, OP_OpenRead, pTab->tnum);      useTempTable = 0;      if( addr>0 ){        VdbeOp *pOp = sqliteVdbeGetOp(v, addr-2);        if( pOp->opcode==OP_Integer && pOp->p1==pTab->iDb ){          useTempTable = 1;        }      }    }    if( useTempTable ){      /* Generate the subroutine that SELECT calls to process each row of      ** the result.  Store the result in a temporary table      */      srcTab = pParse->nTab++;      sqliteVdbeResolveLabel(v, iInsertBlock);      sqliteVdbeAddOp(v, OP_MakeRecord, nColumn, 0);      sqliteVdbeAddOp(v, OP_NewRecno, srcTab, 0);      sqliteVdbeAddOp(v, OP_Pull, 1, 0);      sqliteVdbeAddOp(v, OP_PutIntKey, srcTab, 0);      sqliteVdbeAddOp(v, OP_Return, 0, 0);      /* The following code runs first because the GOTO at the very top      ** of the program jumps to it.  Create the temporary table, then jump      ** back up and execute the SELECT code above.      */      sqliteVdbeChangeP2(v, iInitCode, sqliteVdbeCurrentAddr(v));      sqliteVdbeAddOp(v, OP_OpenTemp, srcTab, 0);      sqliteVdbeAddOp(v, OP_Goto, 0, iSelectLoop);      sqliteVdbeResolveLabel(v, iCleanup);    }else{      sqliteVdbeChangeP2(v, iInitCode, sqliteVdbeCurrentAddr(v));    }  }else{    /* This is the case if the data for the INSERT is coming from a VALUES    ** clause    */    SrcList dummy;    assert( pList!=0 );    srcTab = -1;    useTempTable = 0;    assert( pList );    nColumn = pList->nExpr;    dummy.nSrc = 0;    for(i=0; i<nColumn; i++){      if( sqliteExprResolveIds(pParse, &dummy, 0, pList->a[i].pExpr) ){        goto insert_cleanup;      }      if( sqliteExprCheck(pParse, pList->a[i].pExpr, 0, 0) ){        goto insert_cleanup;      }    }  }  /* Make sure the number of columns in the source data matches the number  ** of columns to be inserted into the table.  */  if( pColumn==0 && nColumn!=pTab->nCol ){    sqliteErrorMsg(pParse,        "table %S has %d columns but %d values were supplied",       pTabList, 0, pTab->nCol, nColumn);    goto insert_cleanup;  }  if( pColumn!=0 && nColumn!=pColumn->nId ){    sqliteErrorMsg(pParse, "%d values for %d columns", nColumn, pColumn->nId);    goto insert_cleanup;  }  /* If the INSERT statement included an IDLIST term, then make sure  ** all elements of the IDLIST really are columns of the table and   ** remember the column indices.  **  ** If the table has an INTEGER PRIMARY KEY column and that column  ** is named in the IDLIST, then record in the keyColumn variable  ** the index into IDLIST of the primary key column.  keyColumn is  ** the index of the primary key as it appears in IDLIST, not as  ** is appears in the original table.  (The index of the primary  ** key in the original table is pTab->iPKey.)  */  if( pColumn ){    for(i=0; i<pColumn->nId; i++){      pColumn->a[i].idx = -1;    }    for(i=0; i<pColumn->nId; i++){      for(j=0; j<pTab->nCol; j++){        if( sqliteStrICmp(pColumn->a[i].zName, pTab->aCol[j].zName)==0 ){          pColumn->a[i].idx = j;          if( j==pTab->iPKey ){            keyColumn = i;          }          break;        }      }      if( j>=pTab->nCol ){        if( sqliteIsRowid(pColumn->a[i].zName) ){          keyColumn = i;        }else{          sqliteErrorMsg(pParse, "table %S has no column named %s",              pTabList, 0, pColumn->a[i].zName);          pParse->nErr++;          goto insert_cleanup;        }      }    }  }

⌨️ 快捷键说明

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