Use a vdbe memory cell to allocate the space required for vdbe cursors. (CVS 4912)
FossilOrigin-Name: 047153648155654b0cd70b811935209d2e21776c
This commit is contained in:
+4
-4
@@ -11,7 +11,7 @@
|
||||
*************************************************************************
|
||||
** This file contains code associated with the ANALYZE command.
|
||||
**
|
||||
** @(#) $Id: analyze.c,v 1.41 2008/01/25 15:04:49 drh Exp $
|
||||
** @(#) $Id: analyze.c,v 1.42 2008/03/25 09:47:35 danielk1977 Exp $
|
||||
*/
|
||||
#ifndef SQLITE_OMIT_ANALYZE
|
||||
#include "sqliteInt.h"
|
||||
@@ -74,9 +74,9 @@ static void openStatTable(
|
||||
if( !createStat1 ){
|
||||
sqlite3TableLock(pParse, iDb, iRootPage, 1, "sqlite_stat1");
|
||||
}
|
||||
sqlite3VdbeAddOp2(v, OP_SetNumColumns, 0, 3);
|
||||
sqlite3VdbeAddOp3(v, OP_OpenWrite, iStatCur, iRootPage, iDb);
|
||||
sqlite3VdbeChangeP5(v, createStat1);
|
||||
sqlite3VdbeAddOp2(v, OP_SetNumColumns, iStatCur, 3);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -130,17 +130,17 @@ static void analyzeOneTable(
|
||||
/* Open a cursor to the index to be analyzed
|
||||
*/
|
||||
assert( iDb==sqlite3SchemaToIndex(pParse->db, pIdx->pSchema) );
|
||||
nCol = pIdx->nColumn;
|
||||
sqlite3VdbeAddOp2(v, OP_SetNumColumns, 0, nCol+1);
|
||||
sqlite3VdbeAddOp4(v, OP_OpenRead, iIdxCur, pIdx->tnum, iDb,
|
||||
(char *)pKey, P4_KEYINFO_HANDOFF);
|
||||
VdbeComment((v, "%s", pIdx->zName));
|
||||
nCol = pIdx->nColumn;
|
||||
regFields = iMem+nCol*2;
|
||||
regTemp = regRowid = regCol = regFields+3;
|
||||
regRec = regCol+1;
|
||||
if( regRec>pParse->nMem ){
|
||||
pParse->nMem = regRec;
|
||||
}
|
||||
sqlite3VdbeAddOp2(v, OP_SetNumColumns, iIdxCur, nCol+1);
|
||||
|
||||
/* Memory cells are used as follows:
|
||||
**
|
||||
|
||||
+34
-38
@@ -9,7 +9,7 @@
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
*************************************************************************
|
||||
** $Id: btree.c,v 1.443 2008/03/25 00:22:21 drh Exp $
|
||||
** $Id: btree.c,v 1.444 2008/03/25 09:47:35 danielk1977 Exp $
|
||||
**
|
||||
** This file implements a external (disk-based) database using BTrees.
|
||||
** See the header comment on "btreeInt.h" for additional information.
|
||||
@@ -2677,18 +2677,16 @@ int sqlite3BtreeRollbackStmt(Btree *p){
|
||||
** will not work correctly.
|
||||
*/
|
||||
static int btreeCursor(
|
||||
Btree *p, /* The btree */
|
||||
int iTable, /* Root page of table to open */
|
||||
int wrFlag, /* 1 to write. 0 read-only */
|
||||
struct KeyInfo *pKeyInfo, /* First arg to comparison function */
|
||||
BtCursor **ppCur /* Write new cursor here */
|
||||
Btree *p, /* The btree */
|
||||
int iTable, /* Root page of table to open */
|
||||
int wrFlag, /* 1 to write. 0 read-only */
|
||||
struct KeyInfo *pKeyInfo, /* First arg to comparison function */
|
||||
BtCursor *pCur /* Space for new cursor */
|
||||
){
|
||||
int rc;
|
||||
BtCursor *pCur;
|
||||
BtShared *pBt = p->pBt;
|
||||
|
||||
assert( sqlite3BtreeHoldsMutex(p) );
|
||||
*ppCur = 0;
|
||||
if( wrFlag ){
|
||||
if( pBt->readOnly ){
|
||||
return SQLITE_READONLY;
|
||||
@@ -2707,11 +2705,6 @@ static int btreeCursor(
|
||||
return SQLITE_READONLY;
|
||||
}
|
||||
}
|
||||
pCur = sqlite3MallocZero( sizeof(*pCur) );
|
||||
if( pCur==0 ){
|
||||
rc = SQLITE_NOMEM;
|
||||
goto create_cursor_exception;
|
||||
}
|
||||
pCur->pgnoRoot = (Pgno)iTable;
|
||||
if( iTable==1 && sqlite3PagerPagecount(pBt->pPager)==0 ){
|
||||
rc = SQLITE_EMPTY;
|
||||
@@ -2736,32 +2729,34 @@ static int btreeCursor(
|
||||
}
|
||||
pBt->pCursor = pCur;
|
||||
pCur->eState = CURSOR_INVALID;
|
||||
*ppCur = pCur;
|
||||
|
||||
return SQLITE_OK;
|
||||
|
||||
create_cursor_exception:
|
||||
if( pCur ){
|
||||
releasePage(pCur->pPage);
|
||||
sqlite3_free(pCur);
|
||||
}
|
||||
unlockBtreeIfUnused(pBt);
|
||||
return rc;
|
||||
}
|
||||
int sqlite3BtreeCursor(
|
||||
Btree *p, /* The btree */
|
||||
int iTable, /* Root page of table to open */
|
||||
int wrFlag, /* 1 to write. 0 read-only */
|
||||
struct KeyInfo *pKeyInfo, /* First arg to xCompare() */
|
||||
BtCursor **ppCur /* Write new cursor here */
|
||||
Btree *p, /* The btree */
|
||||
int iTable, /* Root page of table to open */
|
||||
int wrFlag, /* 1 to write. 0 read-only */
|
||||
struct KeyInfo *pKeyInfo, /* First arg to xCompare() */
|
||||
BtCursor *pCur /* Write new cursor here */
|
||||
){
|
||||
int rc;
|
||||
sqlite3BtreeEnter(p);
|
||||
p->pBt->db = p->db;
|
||||
rc = btreeCursor(p, iTable, wrFlag, pKeyInfo, ppCur);
|
||||
rc = btreeCursor(p, iTable, wrFlag, pKeyInfo, pCur);
|
||||
sqlite3BtreeLeave(p);
|
||||
return rc;
|
||||
}
|
||||
int sqlite3BtreeCursorSize(){
|
||||
return sizeof(BtCursor);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
@@ -2769,25 +2764,26 @@ int sqlite3BtreeCursor(
|
||||
** when the last cursor is closed.
|
||||
*/
|
||||
int sqlite3BtreeCloseCursor(BtCursor *pCur){
|
||||
BtShared *pBt = pCur->pBt;
|
||||
Btree *pBtree = pCur->pBtree;
|
||||
|
||||
sqlite3BtreeEnter(pBtree);
|
||||
pBt->db = pBtree->db;
|
||||
clearCursorPosition(pCur);
|
||||
if( pCur->pPrev ){
|
||||
pCur->pPrev->pNext = pCur->pNext;
|
||||
}else{
|
||||
pBt->pCursor = pCur->pNext;
|
||||
if( pBtree ){
|
||||
BtShared *pBt = pCur->pBt;
|
||||
sqlite3BtreeEnter(pBtree);
|
||||
pBt->db = pBtree->db;
|
||||
clearCursorPosition(pCur);
|
||||
if( pCur->pPrev ){
|
||||
pCur->pPrev->pNext = pCur->pNext;
|
||||
}else{
|
||||
pBt->pCursor = pCur->pNext;
|
||||
}
|
||||
if( pCur->pNext ){
|
||||
pCur->pNext->pPrev = pCur->pPrev;
|
||||
}
|
||||
releasePage(pCur->pPage);
|
||||
unlockBtreeIfUnused(pBt);
|
||||
invalidateOverflowCache(pCur);
|
||||
/* sqlite3_free(pCur); */
|
||||
sqlite3BtreeLeave(pBtree);
|
||||
}
|
||||
if( pCur->pNext ){
|
||||
pCur->pNext->pPrev = pCur->pPrev;
|
||||
}
|
||||
releasePage(pCur->pPage);
|
||||
unlockBtreeIfUnused(pBt);
|
||||
invalidateOverflowCache(pCur);
|
||||
sqlite3_free(pCur);
|
||||
sqlite3BtreeLeave(pBtree);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
|
||||
+7
-6
@@ -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.95 2008/03/25 00:22:21 drh Exp $
|
||||
** @(#) $Id: btree.h,v 1.96 2008/03/25 09:47:35 danielk1977 Exp $
|
||||
*/
|
||||
#ifndef _BTREE_H_
|
||||
#define _BTREE_H_
|
||||
@@ -128,12 +128,13 @@ int sqlite3BtreeUpdateMeta(Btree*, int idx, u32 value);
|
||||
void sqlite3BtreeTripAllCursors(Btree*, int);
|
||||
|
||||
int sqlite3BtreeCursor(
|
||||
Btree*, /* BTree containing table to open */
|
||||
int iTable, /* Index of root page */
|
||||
int wrFlag, /* 1 for writing. 0 for read-only */
|
||||
struct KeyInfo*, /* First argument to compare function */
|
||||
BtCursor **ppCursor /* Returned cursor */
|
||||
Btree*, /* BTree containing table to open */
|
||||
int iTable, /* Index of root page */
|
||||
int wrFlag, /* 1 for writing. 0 for read-only */
|
||||
struct KeyInfo*, /* First argument to compare function */
|
||||
BtCursor *pCursor /* Space to write cursor structure */
|
||||
);
|
||||
int sqlite3BtreeCursorSize();
|
||||
|
||||
int sqlite3BtreeCloseCursor(BtCursor*);
|
||||
int sqlite3BtreeMoveto(BtCursor*,const void *pKey,i64 nKey,int bias,int *pRes);
|
||||
|
||||
+2
-2
@@ -22,7 +22,7 @@
|
||||
** COMMIT
|
||||
** ROLLBACK
|
||||
**
|
||||
** $Id: build.c,v 1.475 2008/03/20 14:03:29 drh Exp $
|
||||
** $Id: build.c,v 1.476 2008/03/25 09:47:35 danielk1977 Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include <ctype.h>
|
||||
@@ -608,8 +608,8 @@ char *sqlite3NameFromToken(sqlite3 *db, Token *pName){
|
||||
void sqlite3OpenMasterTable(Parse *p, int iDb){
|
||||
Vdbe *v = sqlite3GetVdbe(p);
|
||||
sqlite3TableLock(p, iDb, MASTER_ROOT, 1, SCHEMA_TABLE(iDb));
|
||||
sqlite3VdbeAddOp2(v, OP_SetNumColumns, 0, 5);/* sqlite_master has 5 columns */
|
||||
sqlite3VdbeAddOp3(v, OP_OpenWrite, 0, MASTER_ROOT, iDb);
|
||||
sqlite3VdbeAddOp2(v, OP_SetNumColumns, 0, 5); /* sqlite_master has 5 columns */
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
+3
-3
@@ -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.162 2008/03/19 20:42:14 drh Exp $
|
||||
** $Id: delete.c,v 1.163 2008/03/25 09:47:35 danielk1977 Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
|
||||
@@ -75,9 +75,9 @@ void sqlite3OpenTable(
|
||||
v = sqlite3GetVdbe(p);
|
||||
assert( opcode==OP_OpenWrite || opcode==OP_OpenRead );
|
||||
sqlite3TableLock(p, iDb, pTab->tnum, (opcode==OP_OpenWrite), pTab->zName);
|
||||
sqlite3VdbeAddOp2(v, OP_SetNumColumns, 0, pTab->nCol);
|
||||
sqlite3VdbeAddOp3(v, opcode, iCur, pTab->tnum, iDb);
|
||||
VdbeComment((v, "%s", pTab->zName));
|
||||
sqlite3VdbeAddOp2(v, OP_SetNumColumns, iCur, pTab->nCol);
|
||||
}
|
||||
|
||||
|
||||
@@ -322,8 +322,8 @@ void sqlite3DeleteFrom(
|
||||
/* Open the pseudo-table used to store OLD if there are triggers.
|
||||
*/
|
||||
if( triggers_exist ){
|
||||
sqlite3VdbeAddOp2(v, OP_SetNumColumns, 0, pTab->nCol);
|
||||
sqlite3VdbeAddOp1(v, OP_OpenPseudo, oldIdx);
|
||||
sqlite3VdbeAddOp2(v, OP_SetNumColumns, oldIdx, pTab->nCol);
|
||||
}
|
||||
|
||||
/* Delete every item whose key was written to the list during the
|
||||
|
||||
+3
-4
@@ -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.356 2008/03/20 16:30:18 drh Exp $
|
||||
** $Id: expr.c,v 1.357 2008/03/25 09:47:35 danielk1977 Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include <ctype.h>
|
||||
@@ -1639,11 +1639,11 @@ int sqlite3FindInIndex(Parse *pParse, Expr *pX, int mustBeUnique){
|
||||
iAddr = sqlite3VdbeAddOp1(v, OP_If, iMem);
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, 1, iMem);
|
||||
|
||||
sqlite3VdbeAddOp2(v, OP_SetNumColumns, 0, pIdx->nColumn);
|
||||
sqlite3VdbeAddOp4(v, OP_OpenRead, iTab, pIdx->tnum, iDb,
|
||||
pKey,P4_KEYINFO_HANDOFF);
|
||||
VdbeComment((v, "%s", pIdx->zName));
|
||||
eType = IN_INDEX_INDEX;
|
||||
sqlite3VdbeAddOp2(v, OP_SetNumColumns, iTab, pIdx->nColumn);
|
||||
|
||||
sqlite3VdbeJumpHere(v, iAddr);
|
||||
}
|
||||
@@ -1719,10 +1719,9 @@ void sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){
|
||||
** is used.
|
||||
*/
|
||||
pExpr->iTable = pParse->nTab++;
|
||||
addr = sqlite3VdbeAddOp1(v, OP_OpenEphemeral, pExpr->iTable);
|
||||
addr = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pExpr->iTable, 1);
|
||||
memset(&keyInfo, 0, sizeof(keyInfo));
|
||||
keyInfo.nField = 1;
|
||||
sqlite3VdbeAddOp2(v, OP_SetNumColumns, pExpr->iTable, 1);
|
||||
|
||||
if( pExpr->pSelect ){
|
||||
/* Case 1: expr IN (SELECT ...)
|
||||
|
||||
+3
-4
@@ -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.232 2008/03/19 20:42:14 drh Exp $
|
||||
** $Id: insert.c,v 1.233 2008/03/25 09:47:35 danielk1977 Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
|
||||
@@ -537,8 +537,7 @@ void sqlite3Insert(
|
||||
** back up and execute the SELECT code above.
|
||||
*/
|
||||
sqlite3VdbeJumpHere(v, iInitCode);
|
||||
sqlite3VdbeAddOp2(v, OP_OpenEphemeral, srcTab, 0);
|
||||
sqlite3VdbeAddOp2(v, OP_SetNumColumns, srcTab, nColumn);
|
||||
sqlite3VdbeAddOp2(v, OP_OpenEphemeral, srcTab, nColumn);
|
||||
sqlite3VdbeAddOp2(v, OP_Goto, 0, iSelectLoop);
|
||||
sqlite3VdbeResolveLabel(v, iCleanup);
|
||||
}else{
|
||||
@@ -629,8 +628,8 @@ void sqlite3Insert(
|
||||
/* Open the temp table for FOR EACH ROW triggers
|
||||
*/
|
||||
if( triggers_exist ){
|
||||
sqlite3VdbeAddOp2(v, OP_SetNumColumns, 0, pTab->nCol);
|
||||
sqlite3VdbeAddOp2(v, OP_OpenPseudo, newIdx, 0);
|
||||
sqlite3VdbeAddOp2(v, OP_SetNumColumns, newIdx, pTab->nCol);
|
||||
}
|
||||
|
||||
/* Initialize the count of rows to be inserted
|
||||
|
||||
+44
-28
@@ -13,7 +13,7 @@
|
||||
** interface, and routines that contribute to loading the database schema
|
||||
** from disk.
|
||||
**
|
||||
** $Id: prepare.c,v 1.81 2008/03/25 00:22:21 drh Exp $
|
||||
** $Id: prepare.c,v 1.82 2008/03/25 09:47:35 danielk1977 Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include <ctype.h>
|
||||
@@ -207,12 +207,16 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
|
||||
}
|
||||
return SQLITE_OK;
|
||||
}
|
||||
curMain = sqlite3MallocZero(sqlite3BtreeCursorSize());
|
||||
if( !curMain ){
|
||||
rc = SQLITE_NOMEM;
|
||||
goto error_out;
|
||||
}
|
||||
sqlite3BtreeEnter(pDb->pBt);
|
||||
rc = sqlite3BtreeCursor(pDb->pBt, MASTER_ROOT, 0, 0, &curMain);
|
||||
rc = sqlite3BtreeCursor(pDb->pBt, MASTER_ROOT, 0, 0, curMain);
|
||||
if( rc!=SQLITE_OK && rc!=SQLITE_EMPTY ){
|
||||
sqlite3SetString(pzErrMsg, sqlite3ErrStr(rc), (char*)0);
|
||||
sqlite3BtreeLeave(pDb->pBt);
|
||||
goto error_out;
|
||||
goto leave_error_out;
|
||||
}
|
||||
|
||||
/* Get the database meta information.
|
||||
@@ -239,9 +243,7 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
|
||||
}
|
||||
if( rc ){
|
||||
sqlite3SetString(pzErrMsg, sqlite3ErrStr(rc), (char*)0);
|
||||
sqlite3BtreeCloseCursor(curMain);
|
||||
sqlite3BtreeLeave(pDb->pBt);
|
||||
goto error_out;
|
||||
goto leave_error_out;
|
||||
}
|
||||
}else{
|
||||
memset(meta, 0, sizeof(meta));
|
||||
@@ -261,11 +263,10 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
|
||||
}else{
|
||||
/* If opening an attached database, the encoding much match ENC(db) */
|
||||
if( meta[4]!=ENC(db) ){
|
||||
sqlite3BtreeCloseCursor(curMain);
|
||||
sqlite3SetString(pzErrMsg, "attached databases must use the same"
|
||||
" text encoding as main database", (char*)0);
|
||||
sqlite3BtreeLeave(pDb->pBt);
|
||||
return SQLITE_ERROR;
|
||||
rc = SQLITE_ERROR;
|
||||
goto leave_error_out;
|
||||
}
|
||||
}
|
||||
}else{
|
||||
@@ -290,10 +291,9 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
|
||||
pDb->pSchema->file_format = 1;
|
||||
}
|
||||
if( pDb->pSchema->file_format>SQLITE_MAX_FILE_FORMAT ){
|
||||
sqlite3BtreeCloseCursor(curMain);
|
||||
sqlite3SetString(pzErrMsg, "unsupported file format", (char*)0);
|
||||
sqlite3BtreeLeave(pDb->pBt);
|
||||
return SQLITE_ERROR;
|
||||
rc = SQLITE_ERROR;
|
||||
goto leave_error_out;
|
||||
}
|
||||
|
||||
/* Ticket #2804: When we open a database in the newer file format,
|
||||
@@ -336,7 +336,6 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
|
||||
sqlite3AnalysisLoad(db, iDb);
|
||||
}
|
||||
#endif
|
||||
sqlite3BtreeCloseCursor(curMain);
|
||||
}
|
||||
if( db->mallocFailed ){
|
||||
/* sqlite3SetString(pzErrMsg, "out of memory", (char*)0); */
|
||||
@@ -355,6 +354,14 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
|
||||
DbSetProperty(db, iDb, DB_SchemaLoaded);
|
||||
rc = SQLITE_OK;
|
||||
}
|
||||
|
||||
/* Jump here for an error that occurs after successfully allocating
|
||||
** curMain and calling sqlite3BtreeEnter(). For an error that occurs
|
||||
** before that point, jump to error_out.
|
||||
*/
|
||||
leave_error_out:
|
||||
sqlite3BtreeCloseCursor(curMain);
|
||||
sqlite3_free(curMain);
|
||||
sqlite3BtreeLeave(pDb->pBt);
|
||||
|
||||
error_out:
|
||||
@@ -441,23 +448,32 @@ static int schemaIsValid(sqlite3 *db){
|
||||
int cookie;
|
||||
int allOk = 1;
|
||||
|
||||
assert( sqlite3_mutex_held(db->mutex) );
|
||||
for(iDb=0; allOk && iDb<db->nDb; iDb++){
|
||||
Btree *pBt;
|
||||
pBt = db->aDb[iDb].pBt;
|
||||
if( pBt==0 ) continue;
|
||||
rc = sqlite3BtreeCursor(pBt, MASTER_ROOT, 0, 0, &curTemp);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3BtreeGetMeta(pBt, 1, (u32 *)&cookie);
|
||||
if( rc==SQLITE_OK && cookie!=db->aDb[iDb].pSchema->schema_cookie ){
|
||||
allOk = 0;
|
||||
curTemp = (BtCursor *)sqlite3_malloc(sqlite3BtreeCursorSize());
|
||||
if( curTemp ){
|
||||
assert( sqlite3_mutex_held(db->mutex) );
|
||||
for(iDb=0; allOk && iDb<db->nDb; iDb++){
|
||||
Btree *pBt;
|
||||
pBt = db->aDb[iDb].pBt;
|
||||
if( pBt==0 ) continue;
|
||||
memset(curTemp, 0, sqlite3BtreeCursorSize());
|
||||
rc = sqlite3BtreeCursor(pBt, MASTER_ROOT, 0, 0, curTemp);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3BtreeGetMeta(pBt, 1, (u32 *)&cookie);
|
||||
if( rc==SQLITE_OK && cookie!=db->aDb[iDb].pSchema->schema_cookie ){
|
||||
allOk = 0;
|
||||
}
|
||||
sqlite3BtreeCloseCursor(curTemp);
|
||||
}
|
||||
if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ){
|
||||
db->mallocFailed = 1;
|
||||
}
|
||||
sqlite3BtreeCloseCursor(curTemp);
|
||||
}
|
||||
if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ){
|
||||
db->mallocFailed = 1;
|
||||
}
|
||||
sqlite3_free(curTemp);
|
||||
}else{
|
||||
allOk = 0;
|
||||
db->mallocFailed = 1;
|
||||
}
|
||||
|
||||
return allOk;
|
||||
}
|
||||
|
||||
|
||||
+5
-6
@@ -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.417 2008/03/22 01:07:18 drh Exp $
|
||||
** $Id: select.c,v 1.418 2008/03/25 09:47:35 danielk1977 Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
|
||||
@@ -789,8 +789,8 @@ static void generateSortTail(
|
||||
iTab = pOrderBy->iECursor;
|
||||
if( eDest==SRT_Callback || eDest==SRT_Subroutine ){
|
||||
pseudoTab = pParse->nTab++;
|
||||
sqlite3VdbeAddOp2(v, OP_SetNumColumns, 0, nColumn);
|
||||
sqlite3VdbeAddOp2(v, OP_OpenPseudo, pseudoTab, 0);
|
||||
sqlite3VdbeAddOp2(v, OP_SetNumColumns, pseudoTab, nColumn);
|
||||
}
|
||||
addr = 1 + sqlite3VdbeAddOp2(v, OP_Sort, iTab, brk);
|
||||
codeOffset(v, p, cont);
|
||||
@@ -3316,10 +3316,9 @@ int sqlite3Select(
|
||||
*/
|
||||
sAggInfo.sortingIdx = pParse->nTab++;
|
||||
pKeyInfo = keyInfoFromExprList(pParse, pGroupBy);
|
||||
addrSortingIdx =
|
||||
sqlite3VdbeAddOp4(v, OP_OpenEphemeral, sAggInfo.sortingIdx,
|
||||
sAggInfo.nSortingColumn, 0,
|
||||
(char*)pKeyInfo, P4_KEYINFO_HANDOFF);
|
||||
addrSortingIdx = sqlite3VdbeAddOp4(v, OP_OpenEphemeral,
|
||||
sAggInfo.sortingIdx, sAggInfo.nSortingColumn,
|
||||
0, (char*)pKeyInfo, P4_KEYINFO_HANDOFF);
|
||||
|
||||
/* Initialize memory locations used by GROUP BY aggregate processing
|
||||
*/
|
||||
|
||||
+6
-2
@@ -13,7 +13,7 @@
|
||||
** is not included in the SQLite library. It is used for automated
|
||||
** testing of the SQLite library.
|
||||
**
|
||||
** $Id: test3.c,v 1.92 2008/03/25 00:22:21 drh Exp $
|
||||
** $Id: test3.c,v 1.93 2008/03/25 09:47:35 danielk1977 Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include "btreeInt.h"
|
||||
@@ -711,10 +711,13 @@ static int btree_cursor(
|
||||
pBt = sqlite3TextToPtr(argv[1]);
|
||||
if( Tcl_GetInt(interp, argv[2], &iTable) ) return TCL_ERROR;
|
||||
if( Tcl_GetBoolean(interp, argv[3], &wrFlag) ) return TCL_ERROR;
|
||||
pCur = (BtCursor *)ckalloc(sqlite3BtreeCursorSize());
|
||||
memset(pCur, 0, sqlite3BtreeCursorSize());
|
||||
sqlite3BtreeEnter(pBt);
|
||||
rc = sqlite3BtreeCursor(pBt, iTable, wrFlag, 0, &pCur);
|
||||
rc = sqlite3BtreeCursor(pBt, iTable, wrFlag, 0, pCur);
|
||||
sqlite3BtreeLeave(pBt);
|
||||
if( rc ){
|
||||
ckfree((char *)pCur);
|
||||
Tcl_AppendResult(interp, errorName(rc), 0);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
@@ -748,6 +751,7 @@ static int btree_close_cursor(
|
||||
sqlite3BtreeEnter(pBt);
|
||||
rc = sqlite3BtreeCloseCursor(pCur);
|
||||
sqlite3BtreeLeave(pBt);
|
||||
ckfree((char *)pCur);
|
||||
if( rc ){
|
||||
Tcl_AppendResult(interp, errorName(rc), 0);
|
||||
return TCL_ERROR;
|
||||
|
||||
+2
-2
@@ -13,7 +13,7 @@
|
||||
** This file contains code used to implement test interfaces to the
|
||||
** memory allocation subsystem.
|
||||
**
|
||||
** $Id: test_malloc.c,v 1.18 2008/03/21 14:22:44 danielk1977 Exp $
|
||||
** $Id: test_malloc.c,v 1.19 2008/03/25 09:47:35 danielk1977 Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include "tcl.h"
|
||||
@@ -507,7 +507,7 @@ static int test_memdebug_settitle(
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
#define MALLOC_LOG_FRAMES 5
|
||||
#define MALLOC_LOG_FRAMES 10
|
||||
static Tcl_HashTable aMallocLog;
|
||||
static int mallocLogEnabled = 0;
|
||||
|
||||
|
||||
+3
-3
@@ -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.172 2008/03/19 20:42:14 drh Exp $
|
||||
** $Id: update.c,v 1.173 2008/03/25 09:47:35 danielk1977 Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
|
||||
@@ -302,10 +302,10 @@ void sqlite3Update(
|
||||
|
||||
/* Create pseudo-tables for NEW and OLD
|
||||
*/
|
||||
sqlite3VdbeAddOp2(v, OP_SetNumColumns, 0, pTab->nCol);
|
||||
sqlite3VdbeAddOp2(v, OP_OpenPseudo, oldIdx, 0);
|
||||
sqlite3VdbeAddOp2(v, OP_SetNumColumns, oldIdx, pTab->nCol);
|
||||
sqlite3VdbeAddOp2(v, OP_SetNumColumns, 0, pTab->nCol);
|
||||
sqlite3VdbeAddOp2(v, OP_OpenPseudo, newIdx, 0);
|
||||
sqlite3VdbeAddOp2(v, OP_SetNumColumns, newIdx, pTab->nCol);
|
||||
|
||||
iGoto = sqlite3VdbeAddOp2(v, OP_Goto, 0, 0);
|
||||
addr = sqlite3VdbeMakeLabel(v);
|
||||
|
||||
+78
-32
@@ -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.716 2008/03/25 00:22:21 drh Exp $
|
||||
** $Id: vdbe.c,v 1.717 2008/03/25 09:47:35 danielk1977 Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include <ctype.h>
|
||||
@@ -208,15 +208,66 @@ int sqlite3VdbeOpcodeHasProperty(int opcode, int mask){
|
||||
** Allocate cursor number iCur. Return a pointer to it. Return NULL
|
||||
** if we run out of memory.
|
||||
*/
|
||||
static Cursor *allocateCursor(Vdbe *p, int iCur, int iDb){
|
||||
Cursor *pCx;
|
||||
static Cursor *allocateCursor(
|
||||
Vdbe *p,
|
||||
int iCur,
|
||||
Op *pOp,
|
||||
int iDb,
|
||||
int isBtreeCursor
|
||||
){
|
||||
/* Find the memory cell that will be used to store the blob of memory
|
||||
** required for this Cursor structure. It is convenient to use a
|
||||
** vdbe memory cell to manage the memory allocation required for a
|
||||
** Cursor structure for the following reasons:
|
||||
**
|
||||
** * Sometimes cursor numbers are used for a couple of different
|
||||
** purposes in a vdbe program. The different uses might require
|
||||
** different sized allocations. Memory cells provide growable
|
||||
** allocations.
|
||||
**
|
||||
** * When using ENABLE_MEMORY_MANAGEMENT, memory cell buffers can
|
||||
** be freed lazily via the sqlite3_release_memory() API. This
|
||||
** minimizes the number of malloc calls made by the system.
|
||||
**
|
||||
** Memory cells for cursors are allocated at the top of the address
|
||||
** space. Memory cell (p->nMem) corresponds to cursor 0. Space for
|
||||
** cursor 1 is managed by memory cell (p->nMem-1), etc.
|
||||
*/
|
||||
Mem *pMem = &p->aMem[p->nMem-iCur];
|
||||
|
||||
Cursor *pCx = 0;
|
||||
/* If the opcode of pOp is OP_SetNumColumns, then pOp->p2 contains
|
||||
** the number of fields in the records contained in the table or
|
||||
** index being opened. Use this to reserve space for the
|
||||
** Cursor.aType[] array.
|
||||
*/
|
||||
int nField = 0;
|
||||
if( pOp->opcode==OP_SetNumColumns || pOp->opcode==OP_OpenEphemeral ){
|
||||
nField = pOp->p2;
|
||||
}
|
||||
|
||||
|
||||
int nByte =
|
||||
sizeof(Cursor) +
|
||||
(isBtreeCursor?sqlite3BtreeCursorSize():0) +
|
||||
2*nField*sizeof(u32);
|
||||
|
||||
assert( iCur<p->nCursor );
|
||||
if( p->apCsr[iCur] ){
|
||||
sqlite3VdbeFreeCursor(p, p->apCsr[iCur]);
|
||||
p->apCsr[iCur] = 0;
|
||||
}
|
||||
p->apCsr[iCur] = pCx = sqlite3MallocZero( sizeof(Cursor) );
|
||||
if( pCx ){
|
||||
if( SQLITE_OK==sqlite3VdbeMemGrow(pMem, nByte, 0) ){
|
||||
p->apCsr[iCur] = pCx = (Cursor *)pMem->z;
|
||||
memset(pMem->z, 0, nByte);
|
||||
pCx->iDb = iDb;
|
||||
pCx->nField = nField;
|
||||
if( nField ){
|
||||
pCx->aType = (u32 *)&pMem->z[sizeof(Cursor)];
|
||||
}
|
||||
if( isBtreeCursor ){
|
||||
pCx->pCursor = (BtCursor *)&pMem->z[sizeof(Cursor)+2*nField*sizeof(u32)];
|
||||
}
|
||||
}
|
||||
return pCx;
|
||||
}
|
||||
@@ -1773,22 +1824,23 @@ case OP_NotNull: { /* same as TK_NOTNULL, jump, in1 */
|
||||
break;
|
||||
}
|
||||
|
||||
/* Opcode: SetNumColumns P1 P2 * * *
|
||||
/* Opcode: SetNumColumns * P2 * * *
|
||||
**
|
||||
** Before the OP_Column opcode can be executed on a cursor, this
|
||||
** opcode must be called to set the number of fields in the table.
|
||||
** This opcode sets the number of columns for the cursor opened by the
|
||||
** following instruction to P2.
|
||||
**
|
||||
** This opcode sets the number of columns for cursor P1 to P2.
|
||||
** An OP_SetNumColumns is only useful if it occurs immediately before
|
||||
** one of the following opcodes:
|
||||
**
|
||||
** If OP_KeyAsData is to be applied to cursor P1, it must be executed
|
||||
** before this op-code.
|
||||
** OpenRead
|
||||
** OpenWrite
|
||||
** OpenPseudo
|
||||
**
|
||||
** If the OP_Column opcode is to be executed on a cursor, then
|
||||
** this opcode must be present immediately before the opcode that
|
||||
** opens the cursor.
|
||||
*/
|
||||
case OP_SetNumColumns: {
|
||||
Cursor *pC;
|
||||
assert( (pOp->p1)<p->nCursor );
|
||||
assert( p->apCsr[pOp->p1]!=0 );
|
||||
pC = p->apCsr[pOp->p1];
|
||||
pC->nField = pOp->p2;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1893,8 +1945,8 @@ case OP_Column: {
|
||||
/* Read and parse the table header. Store the results of the parse
|
||||
** into the record header cache fields of the cursor.
|
||||
*/
|
||||
aType = pC->aType;
|
||||
if( pC->cacheStatus==p->cacheCtr ){
|
||||
aType = pC->aType;
|
||||
aOffset = pC->aOffset;
|
||||
}else{
|
||||
u8 *zIdx; /* Index into header */
|
||||
@@ -1903,13 +1955,7 @@ case OP_Column: {
|
||||
int szHdrSz; /* Size of the header size field at start of record */
|
||||
int avail; /* Number of bytes of available data */
|
||||
|
||||
aType = pC->aType;
|
||||
if( aType==0 ){
|
||||
pC->aType = aType = sqlite3DbMallocRaw(db, 2*nField*sizeof(aType) );
|
||||
}
|
||||
if( aType==0 ){
|
||||
goto no_mem;
|
||||
}
|
||||
assert(aType);
|
||||
pC->aOffset = aOffset = &aType[nField];
|
||||
pC->payloadSize = payloadSize;
|
||||
pC->cacheStatus = p->cacheCtr;
|
||||
@@ -2515,10 +2561,10 @@ case OP_OpenWrite: {
|
||||
assert( p2>=2 );
|
||||
}
|
||||
assert( i>=0 );
|
||||
pCur = allocateCursor(p, i, iDb);
|
||||
pCur = allocateCursor(p, i, &pOp[-1], iDb, 1);
|
||||
if( pCur==0 ) goto no_mem;
|
||||
pCur->nullRow = 1;
|
||||
rc = sqlite3BtreeCursor(pX, p2, wrFlag, pOp->p4.p, &pCur->pCursor);
|
||||
rc = sqlite3BtreeCursor(pX, p2, wrFlag, pOp->p4.p, pCur->pCursor);
|
||||
if( pOp->p4type==P4_KEYINFO ){
|
||||
pCur->pKeyInfo = pOp->p4.pKeyInfo;
|
||||
pCur->pIncrKey = &pCur->pKeyInfo->incrKey;
|
||||
@@ -2561,6 +2607,7 @@ case OP_OpenWrite: {
|
||||
case SQLITE_EMPTY: {
|
||||
pCur->isTable = pOp->p4type!=P4_KEYINFO;
|
||||
pCur->isIndex = !pCur->isTable;
|
||||
pCur->pCursor = 0;
|
||||
rc = SQLITE_OK;
|
||||
break;
|
||||
}
|
||||
@@ -2600,7 +2647,7 @@ case OP_OpenEphemeral: {
|
||||
SQLITE_OPEN_TRANSIENT_DB;
|
||||
|
||||
assert( i>=0 );
|
||||
pCx = allocateCursor(p, i, -1);
|
||||
pCx = allocateCursor(p, i, pOp, -1, 1);
|
||||
if( pCx==0 ) goto no_mem;
|
||||
pCx->nullRow = 1;
|
||||
rc = sqlite3BtreeFactory(db, 0, 1, SQLITE_DEFAULT_TEMP_CACHE_SIZE, openFlags,
|
||||
@@ -2621,19 +2668,18 @@ case OP_OpenEphemeral: {
|
||||
if( rc==SQLITE_OK ){
|
||||
assert( pgno==MASTER_ROOT+1 );
|
||||
rc = sqlite3BtreeCursor(pCx->pBt, pgno, 1,
|
||||
(KeyInfo*)pOp->p4.z, &pCx->pCursor);
|
||||
(KeyInfo*)pOp->p4.z, pCx->pCursor);
|
||||
pCx->pKeyInfo = pOp->p4.pKeyInfo;
|
||||
pCx->pKeyInfo->enc = ENC(p->db);
|
||||
pCx->pIncrKey = &pCx->pKeyInfo->incrKey;
|
||||
}
|
||||
pCx->isTable = 0;
|
||||
}else{
|
||||
rc = sqlite3BtreeCursor(pCx->pBt, MASTER_ROOT, 1, 0, &pCx->pCursor);
|
||||
rc = sqlite3BtreeCursor(pCx->pBt, MASTER_ROOT, 1, 0, pCx->pCursor);
|
||||
pCx->isTable = 1;
|
||||
pCx->pIncrKey = &pCx->bogusIncrKey;
|
||||
}
|
||||
}
|
||||
pCx->nField = pOp->p2;
|
||||
pCx->isIndex = !pCx->isTable;
|
||||
break;
|
||||
}
|
||||
@@ -2654,7 +2700,7 @@ case OP_OpenPseudo: {
|
||||
int i = pOp->p1;
|
||||
Cursor *pCx;
|
||||
assert( i>=0 );
|
||||
pCx = allocateCursor(p, i, -1);
|
||||
pCx = allocateCursor(p, i, &pOp[-1], -1, 0);
|
||||
if( pCx==0 ) goto no_mem;
|
||||
pCx->nullRow = 1;
|
||||
pCx->pseudoTable = 1;
|
||||
@@ -4390,7 +4436,7 @@ case OP_VOpen: {
|
||||
pVtabCursor->pVtab = pVtab;
|
||||
|
||||
/* Initialise vdbe cursor object */
|
||||
pCur = allocateCursor(p, pOp->p1, -1);
|
||||
pCur = allocateCursor(p, pOp->p1, &pOp[-1], -1, 0);
|
||||
if( pCur ){
|
||||
pCur->pVtabCursor = pVtabCursor;
|
||||
pCur->pModule = pVtabCursor->pVtab->pModule;
|
||||
|
||||
+17
-4
@@ -958,6 +958,17 @@ void sqlite3VdbeMakeReady(
|
||||
*/
|
||||
p->magic = VDBE_MAGIC_RUN;
|
||||
|
||||
/* For each cursor required, also allocate a memory cell. Memory
|
||||
** cells (nMem+1-nCursor)..nMem, inclusive, will never be used by
|
||||
** the vdbe program. Instead they are used to allocate space for
|
||||
** Cursor/BtCursor structures. The blob of memory associated with
|
||||
** cursor 0 is stored in memory cell nMem. Memory cell (nMem-1)
|
||||
** stores the blob of memory associated with cursor 1, etc.
|
||||
**
|
||||
** See also: allocateCursor().
|
||||
*/
|
||||
nMem += nCursor;
|
||||
|
||||
/*
|
||||
** Allocation space for registers.
|
||||
*/
|
||||
@@ -1026,8 +1037,8 @@ void sqlite3VdbeMakeReady(
|
||||
}
|
||||
|
||||
/*
|
||||
** Close a VDBE cursor and release all the resources that cursor happens
|
||||
** to hold.
|
||||
** Close a VDBE cursor and release all the resources that cursor
|
||||
** happens to hold.
|
||||
*/
|
||||
void sqlite3VdbeFreeCursor(Vdbe *p, Cursor *pCx){
|
||||
if( pCx==0 ){
|
||||
@@ -1051,8 +1062,9 @@ void sqlite3VdbeFreeCursor(Vdbe *p, Cursor *pCx){
|
||||
}
|
||||
#endif
|
||||
sqlite3_free(pCx->pData);
|
||||
sqlite3_free(pCx->aType);
|
||||
sqlite3_free(pCx);
|
||||
memset(pCx, 0, sizeof(Cursor));
|
||||
/* sqlite3_free(pCx->aType); */
|
||||
/* sqlite3_free(pCx); */
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1084,6 +1096,7 @@ static void Cleanup(Vdbe *p){
|
||||
for(i=1; i<=p->nMem; i++){
|
||||
MemSetTypeFlag(&p->aMem[i], MEM_Null);
|
||||
}
|
||||
|
||||
releaseMemArray(&p->aMem[1], p->nMem);
|
||||
sqlite3VdbeFifoClear(&p->sFifo);
|
||||
if( p->contextStack ){
|
||||
|
||||
+14
-13
@@ -12,7 +12,7 @@
|
||||
**
|
||||
** This file contains code used to implement incremental BLOB I/O.
|
||||
**
|
||||
** $Id: vdbeblob.c,v 1.20 2008/01/25 15:04:50 drh Exp $
|
||||
** $Id: vdbeblob.c,v 1.21 2008/03/25 09:47:35 danielk1977 Exp $
|
||||
*/
|
||||
|
||||
#include "sqliteInt.h"
|
||||
@@ -70,16 +70,17 @@ int sqlite3_blob_open(
|
||||
/* One of the following two instructions is replaced by an
|
||||
** OP_Noop before exection.
|
||||
*/
|
||||
{OP_OpenRead, 0, 0, 0}, /* 2: Open cursor 0 for reading */
|
||||
{OP_OpenWrite, 0, 0, 0}, /* 3: Open cursor 0 for read/write */
|
||||
{OP_SetNumColumns, 0, 0, 0}, /* 2: Num cols for cursor */
|
||||
{OP_OpenRead, 0, 0, 0}, /* 3: Open cursor 0 for reading */
|
||||
{OP_SetNumColumns, 0, 0, 0}, /* 4: Num cols for cursor */
|
||||
{OP_OpenWrite, 0, 0, 0}, /* 5: Open cursor 0 for read/write */
|
||||
|
||||
{OP_Variable, 1, 1, 0}, /* 5: Push the rowid to the stack */
|
||||
{OP_NotExists, 0, 10, 1}, /* 6: Seek the cursor */
|
||||
{OP_Column, 0, 0, 1}, /* 7 */
|
||||
{OP_ResultRow, 1, 0, 0}, /* 8 */
|
||||
{OP_Close, 0, 0, 0}, /* 9 */
|
||||
{OP_Halt, 0, 0, 0}, /* 10 */
|
||||
{OP_Variable, 1, 1, 0}, /* 6: Push the rowid to the stack */
|
||||
{OP_NotExists, 0, 10, 1}, /* 7: Seek the cursor */
|
||||
{OP_Column, 0, 0, 1}, /* 8 */
|
||||
{OP_ResultRow, 1, 0, 0}, /* 9 */
|
||||
{OP_Close, 0, 0, 0}, /* 10 */
|
||||
{OP_Halt, 0, 0, 0}, /* 11 */
|
||||
};
|
||||
|
||||
Vdbe *v = 0;
|
||||
@@ -168,9 +169,9 @@ int sqlite3_blob_open(
|
||||
/* Remove either the OP_OpenWrite or OpenRead. Set the P2
|
||||
** parameter of the other to pTab->tnum.
|
||||
*/
|
||||
sqlite3VdbeChangeToNoop(v, (flags ? 2 : 3), 1);
|
||||
sqlite3VdbeChangeP2(v, (flags ? 3 : 2), pTab->tnum);
|
||||
sqlite3VdbeChangeP3(v, (flags ? 3 : 2), iDb);
|
||||
sqlite3VdbeChangeToNoop(v, (flags ? 3 : 5), 1);
|
||||
sqlite3VdbeChangeP2(v, (flags ? 5 : 3), pTab->tnum);
|
||||
sqlite3VdbeChangeP3(v, (flags ? 5 : 3), iDb);
|
||||
|
||||
/* Configure the OP_SetNumColumns. Configure the cursor to
|
||||
** think that the table has one more column than it really
|
||||
@@ -179,7 +180,7 @@ int sqlite3_blob_open(
|
||||
** we can invoke OP_Column to fill in the vdbe cursors type
|
||||
** and offset cache without causing any IO.
|
||||
*/
|
||||
sqlite3VdbeChangeP2(v, 4, pTab->nCol+1);
|
||||
sqlite3VdbeChangeP2(v, flags ? 4 : 2, pTab->nCol+1);
|
||||
if( !db->mallocFailed ){
|
||||
sqlite3VdbeMakeReady(v, 1, 1, 1, 0);
|
||||
}
|
||||
|
||||
+3
-3
@@ -16,7 +16,7 @@
|
||||
** so is applicable. Because this module is responsible for selecting
|
||||
** indices, you might also think of this module as the "query optimizer".
|
||||
**
|
||||
** $Id: where.c,v 1.290 2008/03/17 17:08:33 drh Exp $
|
||||
** $Id: where.c,v 1.291 2008/03/25 09:47:35 danielk1977 Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
|
||||
@@ -2223,7 +2223,7 @@ WhereInfo *sqlite3WhereBegin(
|
||||
Bitmask b = pTabItem->colUsed;
|
||||
int n = 0;
|
||||
for(; b; b=b>>1, n++){}
|
||||
sqlite3VdbeChangeP2(v, sqlite3VdbeCurrentAddr(v)-1, n);
|
||||
sqlite3VdbeChangeP2(v, sqlite3VdbeCurrentAddr(v)-2, n);
|
||||
assert( n<=pTab->nCol );
|
||||
}
|
||||
}else{
|
||||
@@ -2233,10 +2233,10 @@ WhereInfo *sqlite3WhereBegin(
|
||||
if( (pIx = pLevel->pIdx)!=0 ){
|
||||
KeyInfo *pKey = sqlite3IndexKeyinfo(pParse, pIx);
|
||||
assert( pIx->pSchema==pTab->pSchema );
|
||||
sqlite3VdbeAddOp2(v, OP_SetNumColumns, 0, pIx->nColumn+1);
|
||||
sqlite3VdbeAddOp4(v, OP_OpenRead, iIdxCur, pIx->tnum, iDb,
|
||||
(char*)pKey, P4_KEYINFO_HANDOFF);
|
||||
VdbeComment((v, "%s", pIx->zName));
|
||||
sqlite3VdbeAddOp2(v, OP_SetNumColumns, iIdxCur, pIx->nColumn+1);
|
||||
}
|
||||
sqlite3CodeVerifySchema(pParse, iDb);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user