mirror of
https://github.com/sqlite/sqlite.git
synced 2025-08-08 14:02:16 +03:00
An attempt to delete a single row using a WHERE clause that specifies
the rowid would result in an error if the rowid did not exist. This problem has been resolved. (CVS 338) FossilOrigin-Name: 011be9a9d2632d261489005d97c69b0a0bc5a108
This commit is contained in:
37
src/btree.c
37
src/btree.c
@@ -9,7 +9,7 @@
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
*************************************************************************
|
||||
** $Id: btree.c,v 1.45 2001/12/15 14:22:19 drh Exp $
|
||||
** $Id: btree.c,v 1.46 2002/01/04 03:09:29 drh Exp $
|
||||
**
|
||||
** This file implements a external (disk-based) database using BTrees.
|
||||
** For a detailed discussion of BTrees, refer to
|
||||
@@ -728,6 +728,7 @@ static int newDatabase(Btree *pBt){
|
||||
** unless a transaction is started first:
|
||||
**
|
||||
** sqliteBtreeCreateTable()
|
||||
** sqliteBtreeCreateIndex()
|
||||
** sqliteBtreeClearTable()
|
||||
** sqliteBtreeDropTable()
|
||||
** sqliteBtreeInsert()
|
||||
@@ -2227,8 +2228,13 @@ int sqliteBtreeDelete(BtCursor *pCur){
|
||||
}
|
||||
|
||||
/*
|
||||
** Create a new BTree in the same file. Write into *piTable the index
|
||||
** of the root page of the new table.
|
||||
** Create a new BTree table. Write into *piTable the page
|
||||
** number for the root page of the new table.
|
||||
**
|
||||
** In the current implementation, BTree tables and BTree indices are the
|
||||
** the same. But in the future, we may change this so that BTree tables
|
||||
** are restricted to having a 4-byte integer key and arbitrary data and
|
||||
** BTree indices are restricted to having an arbitrary key and no data.
|
||||
*/
|
||||
int sqliteBtreeCreateTable(Btree *pBt, int *piTable){
|
||||
MemPage *pRoot;
|
||||
@@ -2246,6 +2252,31 @@ int sqliteBtreeCreateTable(Btree *pBt, int *piTable){
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Create a new BTree index. Write into *piTable the page
|
||||
** number for the root page of the new index.
|
||||
**
|
||||
** In the current implementation, BTree tables and BTree indices are the
|
||||
** the same. But in the future, we may change this so that BTree tables
|
||||
** are restricted to having a 4-byte integer key and arbitrary data and
|
||||
** BTree indices are restricted to having an arbitrary key and no data.
|
||||
*/
|
||||
int sqliteBtreeCreateIndex(Btree *pBt, int *piIndex){
|
||||
MemPage *pRoot;
|
||||
Pgno pgnoRoot;
|
||||
int rc;
|
||||
if( !pBt->inTrans ){
|
||||
return SQLITE_ERROR; /* Must start a transaction first */
|
||||
}
|
||||
rc = allocatePage(pBt, &pRoot, &pgnoRoot);
|
||||
if( rc ) return rc;
|
||||
assert( sqlitepager_iswriteable(pRoot) );
|
||||
zeroPage(pRoot);
|
||||
sqlitepager_unref(pRoot);
|
||||
*piIndex = (int)pgnoRoot;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Erase the given database page and all its children. Return
|
||||
** the page to the freelist.
|
||||
|
@@ -13,7 +13,7 @@
|
||||
** subsystem. See comments in the source code for a detailed description
|
||||
** of what each interface routine does.
|
||||
**
|
||||
** @(#) $Id: btree.h,v 1.18 2001/12/15 14:22:19 drh Exp $
|
||||
** @(#) $Id: btree.h,v 1.19 2002/01/04 03:09:30 drh Exp $
|
||||
*/
|
||||
#ifndef _BTREE_H_
|
||||
#define _BTREE_H_
|
||||
@@ -30,6 +30,7 @@ int sqliteBtreeCommit(Btree*);
|
||||
int sqliteBtreeRollback(Btree*);
|
||||
|
||||
int sqliteBtreeCreateTable(Btree*, int*);
|
||||
int sqliteBtreeCreateIndex(Btree*, int*);
|
||||
int sqliteBtreeDropTable(Btree*, int);
|
||||
int sqliteBtreeClearTable(Btree*, int);
|
||||
|
||||
|
@@ -12,7 +12,7 @@
|
||||
** This file contains routines used for analyzing expressions and
|
||||
** for generating VDBE code that evaluates expressions in SQLite.
|
||||
**
|
||||
** $Id: expr.c,v 1.35 2001/12/21 14:30:43 drh Exp $
|
||||
** $Id: expr.c,v 1.36 2002/01/04 03:09:30 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
|
||||
@@ -244,7 +244,7 @@ int sqliteExprResolveIds(Parse *pParse, IdList *pTabList, Expr *pExpr){
|
||||
** table. The cursor number of the temporary table has already
|
||||
** been put in iTable by sqliteExprResolveInSelect().
|
||||
*/
|
||||
sqliteVdbeAddOp(v, OP_OpenTemp, pExpr->iTable, 0);
|
||||
sqliteVdbeAddOp(v, OP_OpenTemp, pExpr->iTable, 1);
|
||||
if( sqliteSelect(pParse, pExpr->pSelect, SRT_Set, pExpr->iTable) );
|
||||
}else if( pExpr->pList ){
|
||||
/* Case 2: expr IN (exprlist)
|
||||
|
@@ -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.30 2001/12/31 02:48:51 drh Exp $
|
||||
** $Id: insert.c,v 1.31 2002/01/04 03:09:30 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
|
||||
@@ -84,7 +84,7 @@ void sqliteInsert(
|
||||
}
|
||||
|
||||
/* Figure out how many columns of data are supplied. If the data
|
||||
** is comming from a SELECT statement, then this step has to generate
|
||||
** is coming from a SELECT statement, then this step has to generate
|
||||
** all the code to implement the SELECT statement and leave the data
|
||||
** in a temporary table. If data is coming from an expression list,
|
||||
** then we just have to count the number of expressions.
|
||||
|
10
src/select.c
10
src/select.c
@@ -12,7 +12,7 @@
|
||||
** This file contains C code routines that are called by the parser
|
||||
** to handle SELECT statements in SQLite.
|
||||
**
|
||||
** $Id: select.c,v 1.52 2001/12/31 02:48:51 drh Exp $
|
||||
** $Id: select.c,v 1.53 2002/01/04 03:09:30 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
|
||||
@@ -546,7 +546,7 @@ static int multiSelect(Parse *pParse, Select *p, int eDest, int iParm){
|
||||
return 1;
|
||||
}
|
||||
if( p->op!=TK_ALL ){
|
||||
sqliteVdbeAddOp(v, OP_OpenTemp, unionTab, 0);
|
||||
sqliteVdbeAddOp(v, OP_OpenTemp, unionTab, 1);
|
||||
sqliteVdbeAddOp(v, OP_KeyAsData, unionTab, 1);
|
||||
}else{
|
||||
sqliteVdbeAddOp(v, OP_OpenTemp, unionTab, 0);
|
||||
@@ -608,7 +608,7 @@ static int multiSelect(Parse *pParse, Select *p, int eDest, int iParm){
|
||||
if( p->pOrderBy && matchOrderbyToColumn(pParse,p,p->pOrderBy,tab1,1) ){
|
||||
return 1;
|
||||
}
|
||||
sqliteVdbeAddOp(v, OP_OpenTemp, tab1, 0);
|
||||
sqliteVdbeAddOp(v, OP_OpenTemp, tab1, 1);
|
||||
sqliteVdbeAddOp(v, OP_KeyAsData, tab1, 1);
|
||||
|
||||
/* Code the SELECTs to our left into temporary table "tab1".
|
||||
@@ -618,7 +618,7 @@ static int multiSelect(Parse *pParse, Select *p, int eDest, int iParm){
|
||||
|
||||
/* Code the current SELECT into temporary table "tab2"
|
||||
*/
|
||||
sqliteVdbeAddOp(v, OP_OpenTemp, tab2, 0);
|
||||
sqliteVdbeAddOp(v, OP_OpenTemp, tab2, 1);
|
||||
sqliteVdbeAddOp(v, OP_KeyAsData, tab2, 1);
|
||||
p->pPrior = 0;
|
||||
rc = sqliteSelect(pParse, p, SRT_Union, tab2);
|
||||
@@ -932,7 +932,7 @@ int sqliteSelect(
|
||||
/* Begin the database scan
|
||||
*/
|
||||
if( isDistinct ){
|
||||
sqliteVdbeAddOp(v, OP_OpenTemp, distinct, 0);
|
||||
sqliteVdbeAddOp(v, OP_OpenTemp, distinct, 1);
|
||||
}
|
||||
pWInfo = sqliteWhereBegin(pParse, pTabList, pWhere, 0);
|
||||
if( pWInfo==0 ) return 1;
|
||||
|
45
src/vdbe.c
45
src/vdbe.c
@@ -30,7 +30,7 @@
|
||||
** But other routines are also provided to help in building up
|
||||
** a program instruction by instruction.
|
||||
**
|
||||
** $Id: vdbe.c,v 1.103 2001/12/31 02:48:51 drh Exp $
|
||||
** $Id: vdbe.c,v 1.104 2002/01/04 03:09:30 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include <ctype.h>
|
||||
@@ -2537,12 +2537,16 @@ case OP_Open: {
|
||||
break;
|
||||
}
|
||||
|
||||
/* Opcode: OpenTemp P1 * *
|
||||
/* Opcode: OpenTemp P1 P2 *
|
||||
**
|
||||
** Open a new cursor that points to a table in a temporary database
|
||||
** file. The temporary file is opened read/write even if the main
|
||||
** database is read-only. The temporary file is deleted when the
|
||||
** cursor is closed.
|
||||
** Open a new cursor that points to a table or index in a temporary
|
||||
** database file. The temporary file is opened read/write even if
|
||||
** the main database is read-only. The temporary file is deleted
|
||||
** when the cursor is closed.
|
||||
**
|
||||
** The cursor points to a BTree table if P2==0 and to a BTree index
|
||||
** if P2==1. A BTree table must have an integer key and can have arbitrary
|
||||
** data. A BTree index has no data but can have an arbitrary key.
|
||||
**
|
||||
** This opcode is used for tables that exist for the duration of a single
|
||||
** SQL statement only. Tables created using CREATE TEMPORARY TABLE
|
||||
@@ -2570,10 +2574,18 @@ case OP_OpenTemp: {
|
||||
memset(pCx, 0, sizeof(*pCx));
|
||||
rc = sqliteBtreeOpen(0, 0, TEMP_PAGES, &pCx->pBt);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqliteBtreeCursor(pCx->pBt, 2, 1, &pCx->pCursor);
|
||||
rc = sqliteBtreeBeginTrans(pCx->pBt);
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqliteBtreeBeginTrans(pCx->pBt);
|
||||
if( pOp->p2 ){
|
||||
int pgno;
|
||||
rc = sqliteBtreeCreateIndex(pCx->pBt, &pgno);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqliteBtreeCursor(pCx->pBt, pgno, 1, &pCx->pCursor);
|
||||
}
|
||||
}else{
|
||||
rc = sqliteBtreeCursor(pCx->pBt, 2, 1, &pCx->pCursor);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -3224,14 +3236,19 @@ case OP_Clear: {
|
||||
** number into the parser's internal data structures that describe the
|
||||
** new table.
|
||||
**
|
||||
** The difference between a table and an index is this: A table must
|
||||
** have a 4-byte integer key and can have arbitrary data. An index
|
||||
** has an arbitrary key but no data.
|
||||
**
|
||||
** See also: CreateIndex
|
||||
*/
|
||||
/* Opcode: CreateIndex * P2 P3
|
||||
**
|
||||
** This instruction does exactly the same thing as CreateTable. It
|
||||
** has a different name for historical reasons.
|
||||
** Allocate a new index in the main database file if P2==0 or in the
|
||||
** auxiliary database file if P2==1. Push the page number of the
|
||||
** root page of the new index onto the stack.
|
||||
**
|
||||
** See also: CreateTable
|
||||
** See documentation on OP_CreateTable for additional information.
|
||||
*/
|
||||
case OP_CreateIndex:
|
||||
case OP_CreateTable: {
|
||||
@@ -3239,7 +3256,11 @@ case OP_CreateTable: {
|
||||
int pgno;
|
||||
VERIFY( if( NeedStack(p, p->tos) ) goto no_mem; )
|
||||
assert( pOp->p3!=0 && pOp->p3type==P3_POINTER );
|
||||
rc = sqliteBtreeCreateTable(pOp->p2 ? db->pBeTemp : pBt, &pgno);
|
||||
if( pOp->opcode==OP_CreateTable ){
|
||||
rc = sqliteBtreeCreateTable(pOp->p2 ? db->pBeTemp : pBt, &pgno);
|
||||
}else{
|
||||
rc = sqliteBtreeCreateIndex(pOp->p2 ? db->pBeTemp : pBt, &pgno);
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
aStack[i].i = pgno;
|
||||
aStack[i].flags = STK_Int;
|
||||
|
@@ -13,7 +13,7 @@
|
||||
** the WHERE clause of SQL statements. Also found here are subroutines
|
||||
** to generate VDBE code to evaluate expressions.
|
||||
**
|
||||
** $Id: where.c,v 1.29 2001/12/22 14:49:26 drh Exp $
|
||||
** $Id: where.c,v 1.30 2002/01/04 03:09:30 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
|
||||
@@ -439,6 +439,7 @@ WhereInfo *sqliteWhereBegin(
|
||||
sqliteVdbeAddOp(v, OP_MustBeInt, 0, brk);
|
||||
if( i==pTabList->nId-1 && pushKey ){
|
||||
haveKey = 1;
|
||||
sqliteVdbeAddOp(v, OP_Distinct, base+idx, brk);
|
||||
}else{
|
||||
sqliteVdbeAddOp(v, OP_NotFound, base+idx, brk);
|
||||
haveKey = 0;
|
||||
|
Reference in New Issue
Block a user