mirror of
https://github.com/sqlite/sqlite.git
synced 2025-11-18 10:21:03 +03:00
Some modifications to insert.c to work without using the stack. (CVS 4678)
FossilOrigin-Name: d9ac6beef538376d0ea0a1daa95cf1dfe36143cf
This commit is contained in:
10
src/delete.c
10
src/delete.c
@@ -12,7 +12,7 @@
|
||||
** This file contains C code routines that are called by the parser
|
||||
** in order to generate code for DELETE FROM statements.
|
||||
**
|
||||
** $Id: delete.c,v 1.146 2008/01/04 13:57:26 danielk1977 Exp $
|
||||
** $Id: delete.c,v 1.147 2008/01/04 19:10:29 danielk1977 Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
|
||||
@@ -91,6 +91,14 @@ int sqlite3StackToReg(Parse *p, int nVal){
|
||||
}
|
||||
return iRet;
|
||||
}
|
||||
void sqlite3RegToStack(Parse *p, int iReg, int nVal){
|
||||
int i;
|
||||
Vdbe *v = sqlite3GetVdbe(p);
|
||||
assert(v);
|
||||
for(i=0; i<nVal; i++){
|
||||
sqlite3VdbeAddOp2(v, OP_MemLoad, iReg+i, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Generate code that will open a table for reading.
|
||||
|
||||
56
src/insert.c
56
src/insert.c
@@ -12,7 +12,7 @@
|
||||
** This file contains C code routines that are called by the parser
|
||||
** to handle INSERT statements in SQLite.
|
||||
**
|
||||
** $Id: insert.c,v 1.209 2008/01/04 13:24:29 danielk1977 Exp $
|
||||
** $Id: insert.c,v 1.210 2008/01/04 19:10:29 danielk1977 Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
|
||||
@@ -189,9 +189,9 @@ static int autoIncBegin(
|
||||
** 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){
|
||||
static void autoIncStep(Parse *pParse, int memId, int iRowid){
|
||||
if( memId>0 ){
|
||||
sqlite3VdbeAddOp2(pParse->pVdbe, OP_MemMax, memId, 0);
|
||||
sqlite3VdbeAddOp2(pParse->pVdbe, OP_MemMax, memId, iRowid);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -231,7 +231,7 @@ static void autoIncEnd(
|
||||
** above are all no-ops
|
||||
*/
|
||||
# define autoIncBegin(A,B,C) (0)
|
||||
# define autoIncStep(A,B)
|
||||
# define autoIncStep(A,B,C)
|
||||
# define autoIncEnd(A,B,C,D)
|
||||
#endif /* SQLITE_OMIT_AUTOINCREMENT */
|
||||
|
||||
@@ -716,15 +716,21 @@ void sqlite3Insert(
|
||||
** case the record number is the same as that column.
|
||||
*/
|
||||
if( !isView ){
|
||||
int iReg = pParse->nMem+1;
|
||||
int iRowid = iReg+(IsVirtual(pTab)?1:0);
|
||||
pParse->nMem += pTab->nCol + (IsVirtual(pTab)?2:1);
|
||||
|
||||
if( IsVirtual(pTab) ){
|
||||
/* The row that the VUpdate opcode will delete: none */
|
||||
sqlite3VdbeAddOp2(v, OP_Null, 0, 0);
|
||||
/* The row that the VUpdate opcode will delete: none */
|
||||
sqlite3VdbeAddOp2(v, OP_MemNull, 0, iReg);
|
||||
}
|
||||
if( keyColumn>=0 ){
|
||||
if( useTempTable ){
|
||||
sqlite3VdbeAddOp2(v, OP_Column, srcTab, keyColumn);
|
||||
sqlite3VdbeAddOp3(v, OP_Column, srcTab, keyColumn, iRowid);
|
||||
}else if( pSelect ){
|
||||
sqlite3VdbeAddOp2(v, OP_Dup, nColumn - keyColumn - 1, 1);
|
||||
sqlite3VdbeAddOp3(v, OP_Dup, nColumn - keyColumn - 1, 1, iRowid);
|
||||
/* TODO: Avoid this use of the stack. */
|
||||
sqlite3VdbeAddOp2(v, OP_MemStore, iRowid, 1);
|
||||
}else{
|
||||
VdbeOp *pOp;
|
||||
sqlite3ExprCode(pParse, pList->a[keyColumn].pExpr, 0);
|
||||
@@ -734,36 +740,42 @@ void sqlite3Insert(
|
||||
pOp->opcode = OP_NewRowid;
|
||||
pOp->p1 = base;
|
||||
pOp->p2 = counterMem;
|
||||
pOp->p3 = iRowid;
|
||||
}else{
|
||||
/* TODO: Avoid this use of the stack. */
|
||||
sqlite3VdbeAddOp2(v, OP_MemStore, iRowid, 1);
|
||||
}
|
||||
}
|
||||
/* If the PRIMARY KEY expression is NULL, then use OP_NewRowid
|
||||
** to generate a unique primary key value.
|
||||
*/
|
||||
if( !appendFlag ){
|
||||
sqlite3VdbeAddOp2(v, OP_NotNull, -1, sqlite3VdbeCurrentAddr(v)+3);
|
||||
sqlite3VdbeAddOp2(v, OP_Pop, 1, 0);
|
||||
sqlite3VdbeAddOp2(v, OP_NewRowid, base, counterMem);
|
||||
sqlite3VdbeAddOp2(v, OP_MustBeInt, 0, 0);
|
||||
sqlite3VdbeAddOp2(v, OP_IfMemNull, iRowid, sqlite3VdbeCurrentAddr(v)+2);
|
||||
sqlite3VdbeAddOp2(v, OP_Goto, -1, sqlite3VdbeCurrentAddr(v)+2);
|
||||
sqlite3VdbeAddOp3(v, OP_NewRowid, base, counterMem, iRowid);
|
||||
sqlite3VdbeAddOp3(v, OP_MustBeInt, 0, 0, iRowid);
|
||||
}
|
||||
}else if( IsVirtual(pTab) ){
|
||||
sqlite3VdbeAddOp2(v, OP_Null, 0, 0);
|
||||
sqlite3VdbeAddOp2(v, OP_MemNull, 0, iRowid);
|
||||
}else{
|
||||
sqlite3VdbeAddOp2(v, OP_NewRowid, base, counterMem);
|
||||
sqlite3VdbeAddOp2(v, OP_MemStore, iRowid, 1);
|
||||
appendFlag = 1;
|
||||
}
|
||||
autoIncStep(pParse, counterMem);
|
||||
autoIncStep(pParse, counterMem, iRowid);
|
||||
|
||||
/* Push onto the stack, data for all columns of the new entry, beginning
|
||||
** with the first column.
|
||||
*/
|
||||
nHidden = 0;
|
||||
for(i=0; i<pTab->nCol; i++){
|
||||
int iRegStore = iRowid+1+i;
|
||||
if( i==pTab->iPKey ){
|
||||
/* The value of the INTEGER PRIMARY KEY column is always a NULL.
|
||||
** Whenever this column is read, the record number will be substituted
|
||||
** in its place. So will fill this column with a NULL to avoid
|
||||
** taking up data space with information that will never be used. */
|
||||
sqlite3VdbeAddOp2(v, OP_Null, 0, 0);
|
||||
sqlite3VdbeAddOp2(v, OP_MemNull, 0, iRegStore);
|
||||
continue;
|
||||
}
|
||||
if( pColumn==0 ){
|
||||
@@ -780,13 +792,15 @@ void sqlite3Insert(
|
||||
}
|
||||
}
|
||||
if( j<0 || nColumn==0 || (pColumn && j>=pColumn->nId) ){
|
||||
sqlite3ExprCode(pParse, pTab->aCol[i].pDflt, 0);
|
||||
sqlite3ExprCode(pParse, pTab->aCol[i].pDflt, iRegStore);
|
||||
}else if( useTempTable ){
|
||||
sqlite3VdbeAddOp2(v, OP_Column, srcTab, j);
|
||||
sqlite3VdbeAddOp3(v, OP_Column, srcTab, j, iRegStore);
|
||||
}else if( pSelect ){
|
||||
sqlite3VdbeAddOp2(v, OP_Dup, i+nColumn-j+IsVirtual(pTab), 1);
|
||||
sqlite3VdbeAddOp2(v, OP_Dup, nColumn-j-1, 1);
|
||||
/* TODO: Avoid this use of the stack */
|
||||
sqlite3VdbeAddOp2(v, OP_MemStore, iRegStore, 1);
|
||||
}else{
|
||||
sqlite3ExprCode(pParse, pList->a[j].pExpr, 0);
|
||||
sqlite3ExprCode(pParse, pList->a[j].pExpr, iRegStore);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -795,13 +809,13 @@ void sqlite3Insert(
|
||||
*/
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
if( IsVirtual(pTab) ){
|
||||
int iReg = sqlite3StackToReg(pParse, pTab->nCol+2);
|
||||
pParse->pVirtualLock = pTab;
|
||||
sqlite3VdbeAddOp4(v, OP_VUpdate, 1, pTab->nCol+2, iReg,
|
||||
(const char*)pTab->pVtab, P4_VTAB);
|
||||
}else
|
||||
#endif
|
||||
{
|
||||
sqlite3RegToStack(pParse, iReg, pTab->nCol+1);
|
||||
sqlite3GenerateConstraintChecks(pParse, pTab, base, 0, keyColumn>=0,
|
||||
0, onError, endOfLoop);
|
||||
sqlite3CompleteInsertion(pParse, pTab, base, 0,0,0,
|
||||
@@ -1557,7 +1571,7 @@ static int xferOptimization(
|
||||
sqlite3VdbeAddOp4(v, OP_Halt, SQLITE_CONSTRAINT, onError, 0,
|
||||
"PRIMARY KEY must be unique", P4_STATIC);
|
||||
sqlite3VdbeJumpHere(v, addr2);
|
||||
autoIncStep(pParse, counterMem);
|
||||
autoIncStep(pParse, counterMem, 0);
|
||||
}else if( pDest->pIndex==0 ){
|
||||
addr1 = sqlite3VdbeAddOp2(v, OP_NewRowid, iDest, 0);
|
||||
}else{
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
*************************************************************************
|
||||
** Internal interface definitions for SQLite.
|
||||
**
|
||||
** @(#) $Id: sqliteInt.h,v 1.637 2008/01/04 13:24:29 danielk1977 Exp $
|
||||
** @(#) $Id: sqliteInt.h,v 1.638 2008/01/04 19:10:29 danielk1977 Exp $
|
||||
*/
|
||||
#ifndef _SQLITEINT_H_
|
||||
#define _SQLITEINT_H_
|
||||
@@ -1919,6 +1919,7 @@ char *sqlite3StrAccumFinish(StrAccum*);
|
||||
void sqlite3StrAccumReset(StrAccum*);
|
||||
void sqlite3CodeInsert(Parse *, int, u8);
|
||||
int sqlite3StackToReg(Parse *, int);
|
||||
void sqlite3RegToStack(Parse *, int, int);
|
||||
|
||||
/*
|
||||
** The interface to the LEMON-generated parser
|
||||
|
||||
26
src/update.c
26
src/update.c
@@ -12,7 +12,7 @@
|
||||
** This file contains C code routines that are called by the parser
|
||||
** to handle UPDATE statements.
|
||||
**
|
||||
** $Id: update.c,v 1.156 2008/01/04 13:57:26 danielk1977 Exp $
|
||||
** $Id: update.c,v 1.157 2008/01/04 19:10:29 danielk1977 Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
|
||||
@@ -592,7 +592,9 @@ static void updateVirtualTable(
|
||||
int ephemTab; /* Table holding the result of the SELECT */
|
||||
int i; /* Loop counter */
|
||||
int addr; /* Address of top of loop */
|
||||
int iReg; /* First register in set passed to OP_VUpdate */
|
||||
sqlite3 *db = pParse->db; /* Database connection */
|
||||
const char *pVtab = (const char*)pTab->pVtab;
|
||||
SelectDest dest = {SRT_Table, 0, 0};
|
||||
|
||||
/* Construct the SELECT statement that will find the new values for
|
||||
@@ -627,26 +629,18 @@ static void updateVirtualTable(
|
||||
dest.iParm = ephemTab;
|
||||
sqlite3Select(pParse, pSelect, &dest, 0, 0, 0, 0);
|
||||
|
||||
/*
|
||||
** Generate code to scan the ephemeral table and call VDelete and
|
||||
** VInsert
|
||||
*/
|
||||
/* Generate code to scan the ephemeral table and call VUpdate. */
|
||||
iReg = ++pParse->nMem;
|
||||
pParse->nMem += pTab->nCol+1;
|
||||
sqlite3VdbeAddOp2(v, OP_Rewind, ephemTab, 0);
|
||||
addr = sqlite3VdbeCurrentAddr(v);
|
||||
sqlite3VdbeAddOp2(v, OP_Column, ephemTab, 0);
|
||||
if( pRowid ){
|
||||
sqlite3VdbeAddOp2(v, OP_Column, ephemTab, 1);
|
||||
}else{
|
||||
sqlite3VdbeAddOp2(v, OP_Dup, 0, 0);
|
||||
}
|
||||
sqlite3VdbeAddOp3(v, OP_Column, ephemTab, 0, iReg);
|
||||
sqlite3VdbeAddOp3(v, OP_Column, ephemTab, (pRowid?1:0), iReg+1);
|
||||
for(i=0; i<pTab->nCol; i++){
|
||||
sqlite3VdbeAddOp2(v, OP_Column, ephemTab, i+1+(pRowid!=0));
|
||||
sqlite3VdbeAddOp3(v, OP_Column, ephemTab, i+1+(pRowid!=0), iReg+2+i);
|
||||
}
|
||||
pParse->pVirtualLock = pTab;
|
||||
sqlite3VdbeAddOp4(v, OP_VUpdate, 0, pTab->nCol+2,
|
||||
sqlite3StackToReg(pParse, pTab->nCol+2),
|
||||
(const char*)pTab->pVtab, P4_VTAB
|
||||
);
|
||||
sqlite3VdbeAddOp4(v, OP_VUpdate, 0, pTab->nCol+2, iReg, pVtab, P4_VTAB);
|
||||
sqlite3VdbeAddOp2(v, OP_Next, ephemTab, addr);
|
||||
sqlite3VdbeJumpHere(v, addr-1);
|
||||
sqlite3VdbeAddOp2(v, OP_Close, ephemTab, 0);
|
||||
|
||||
52
src/vdbe.c
52
src/vdbe.c
@@ -43,7 +43,7 @@
|
||||
** in this file for details. If in doubt, do not deviate from existing
|
||||
** commenting and indentation practices when changing or adding code.
|
||||
**
|
||||
** $Id: vdbe.c,v 1.677 2008/01/04 16:50:09 drh Exp $
|
||||
** $Id: vdbe.c,v 1.678 2008/01/04 19:10:29 danielk1977 Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include <ctype.h>
|
||||
@@ -591,6 +591,7 @@ int sqlite3VdbeExec(
|
||||
if( sqlite3VdbeOpcodeHasProperty(pOp->opcode, OPFLG_PUSH) ){
|
||||
pStackLimit++;
|
||||
}
|
||||
assert( pTos>=&p->aStack[-1] && pTos<=pStackLimit );
|
||||
#endif
|
||||
|
||||
switch( pOp->opcode ){
|
||||
@@ -1526,7 +1527,7 @@ case OP_ForceInt: { /* no-push, jump */
|
||||
break;
|
||||
}
|
||||
|
||||
/* Opcode: MustBeInt P1 P2 *
|
||||
/* Opcode: MustBeInt P1 P2 P3
|
||||
**
|
||||
** Force the top of the stack to be an integer. If the top of the
|
||||
** stack is not an integer and cannot be converted into an integer
|
||||
@@ -1536,21 +1537,26 @@ case OP_ForceInt: { /* no-push, jump */
|
||||
** If the top of the stack is not an integer and P2 is not zero and
|
||||
** P1 is 1, then the stack is popped. In all other cases, the depth
|
||||
** of the stack is unchanged.
|
||||
**
|
||||
** If P3 is not zero, then act on the value in register P3 instead
|
||||
** of using the stack.
|
||||
*/
|
||||
case OP_MustBeInt: { /* no-push, jump */
|
||||
assert( pTos>=p->aStack );
|
||||
applyAffinity(pTos, SQLITE_AFF_NUMERIC, encoding);
|
||||
if( (pTos->flags & MEM_Int)==0 ){
|
||||
Mem *pMem = ((pOp->p3==0)?pTos:&p->aMem[pOp->p3]);
|
||||
assert( pOp->p3 || pTos>=p->aStack );
|
||||
assert( pOp->p3>=0 && pOp->p3<=p->nMem );
|
||||
applyAffinity(pMem, SQLITE_AFF_NUMERIC, encoding);
|
||||
if( (pMem->flags & MEM_Int)==0 ){
|
||||
if( pOp->p2==0 ){
|
||||
rc = SQLITE_MISMATCH;
|
||||
goto abort_due_to_error;
|
||||
}else{
|
||||
}else if( pMem==pTos ){
|
||||
if( pOp->p1 ) popStack(&pTos, 1);
|
||||
pc = pOp->p2 - 1;
|
||||
}
|
||||
}else{
|
||||
Release(pTos);
|
||||
pTos->flags = MEM_Int;
|
||||
Release(pMem);
|
||||
pMem->flags = MEM_Int;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -3438,12 +3444,12 @@ case OP_Sequence: {
|
||||
}
|
||||
|
||||
|
||||
/* Opcode: NewRowid P1 P2 *
|
||||
/* Opcode: NewRowid P1 P2 P3
|
||||
**
|
||||
** Get a new integer record number (a.k.a "rowid") used as the key to a table.
|
||||
** The record number is not previously used as a key in the database
|
||||
** table that cursor P1 points to. The new record number is pushed
|
||||
** onto the stack.
|
||||
** onto the stack if P3 is 0 or written to memory cell P3 otherwise.
|
||||
**
|
||||
** If P2>0 then P2 is a memory cell that holds the largest previously
|
||||
** generated record number. No new record numbers are allowed to be less
|
||||
@@ -3587,9 +3593,13 @@ case OP_NewRowid: {
|
||||
pC->deferredMoveto = 0;
|
||||
pC->cacheStatus = CACHE_STALE;
|
||||
}
|
||||
pTos++;
|
||||
pTos->u.i = v;
|
||||
pTos->flags = MEM_Int;
|
||||
if( pOp->p3 ){
|
||||
sqlite3VdbeMemSetInt64(&p->aMem[pOp->p3], v);
|
||||
}else{
|
||||
pTos++;
|
||||
pTos->u.i = v;
|
||||
pTos->flags = MEM_Int;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -4662,10 +4672,11 @@ case OP_MemLoad: {
|
||||
}
|
||||
|
||||
#ifndef SQLITE_OMIT_AUTOINCREMENT
|
||||
/* Opcode: MemMax P1 * *
|
||||
/* Opcode: MemMax P1 P2 *
|
||||
**
|
||||
** Set the value of memory cell P1 to the maximum of its current value
|
||||
** and the value on the top of the stack. The stack is unchanged.
|
||||
** and the value in cell P2, or the value on the top of the stack if P2
|
||||
** is zero. The stack is unchanged in either case.
|
||||
**
|
||||
** This instruction throws an error if the memory cell is not initially
|
||||
** an integer.
|
||||
@@ -4673,13 +4684,14 @@ case OP_MemLoad: {
|
||||
case OP_MemMax: { /* no-push */
|
||||
int i = pOp->p1;
|
||||
Mem *pMem;
|
||||
assert( pTos>=p->aStack );
|
||||
Mem *pNew = (pOp->p2?(&p->aMem[pOp->p2]):pTos);
|
||||
assert( pOp->p2 || pTos>=p->aStack );
|
||||
assert( i>0 && i<=p->nMem );
|
||||
pMem = &p->aMem[i];
|
||||
sqlite3VdbeMemIntegerify(pMem);
|
||||
sqlite3VdbeMemIntegerify(pTos);
|
||||
if( pMem->u.i<pTos->u.i){
|
||||
pMem->u.i = pTos->u.i;
|
||||
sqlite3VdbeMemIntegerify(pNew);
|
||||
if( pMem->u.i<pNew->u.i){
|
||||
pMem->u.i = pNew->u.i;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -5352,7 +5364,7 @@ default: {
|
||||
}
|
||||
|
||||
/* Make sure the stack limit was not exceeded */
|
||||
assert( pTos<=pStackLimit );
|
||||
assert( pTos>=&p->aStack[-1] && pTos<=pStackLimit );
|
||||
|
||||
#ifdef VDBE_PROFILE
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user