mirror of
https://github.com/php/php-src.git
synced 2025-08-19 08:49:28 +02:00
Upgrade libsqlite 3 inside PDO sqlite to version 3.3.15
This commit is contained in:
parent
857f992cd3
commit
eb8d30f912
51 changed files with 5351 additions and 3624 deletions
|
@ -211,7 +211,7 @@ static void analyzeOneTable(
|
|||
}
|
||||
}
|
||||
sqlite3VdbeOp3(v, OP_MakeRecord, 3, 0, "aaa", 0);
|
||||
sqlite3VdbeAddOp(v, OP_Insert, iStatCur, 0);
|
||||
sqlite3VdbeAddOp(v, OP_Insert, iStatCur, OPFLAG_APPEND);
|
||||
sqlite3VdbeJumpHere(v, addr);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
*/
|
||||
#include "sqliteInt.h"
|
||||
|
||||
#ifndef SQLITE_OMIT_ATTACH
|
||||
/*
|
||||
** Resolve an expression that was part of an ATTACH or DETACH statement. This
|
||||
** is slightly different from resolving a normal SQL expression, because simple
|
||||
|
@ -133,13 +134,14 @@ static void attachFunc(
|
|||
"attached databases must use the same text encoding as main database");
|
||||
goto attach_error;
|
||||
}
|
||||
sqlite3PagerLockingMode(sqlite3BtreePager(aNew->pBt), db->dfltLockMode);
|
||||
}
|
||||
aNew->zName = sqliteStrDup(zName);
|
||||
aNew->safety_level = 3;
|
||||
|
||||
#if SQLITE_HAS_CODEC
|
||||
{
|
||||
extern int sqlite3CodecAttach(sqlite3*, int, void*, int);
|
||||
extern int sqlite3CodecAttach(sqlite3*, int, const void*, int);
|
||||
extern void sqlite3CodecGetKey(sqlite3*, int, void**, int*);
|
||||
int nKey;
|
||||
char *zKey;
|
||||
|
@ -188,7 +190,7 @@ static void attachFunc(
|
|||
sqlite3ResetInternalSchema(db, 0);
|
||||
db->nDb = iDb;
|
||||
if( rc==SQLITE_NOMEM ){
|
||||
if( !sqlite3MallocFailed() ) sqlite3FailedMalloc();
|
||||
sqlite3FailedMalloc();
|
||||
sqlite3_snprintf(sizeof(zErr),zErr, "out of memory");
|
||||
}else{
|
||||
sqlite3_snprintf(sizeof(zErr),zErr, "unable to open database: %s", zFile);
|
||||
|
@ -350,14 +352,17 @@ void sqlite3Detach(Parse *pParse, Expr *pDbname){
|
|||
void sqlite3Attach(Parse *pParse, Expr *p, Expr *pDbname, Expr *pKey){
|
||||
codeAttach(pParse, SQLITE_ATTACH, "sqlite_attach", 3, p, p, pDbname, pKey);
|
||||
}
|
||||
#endif /* SQLITE_OMIT_ATTACH */
|
||||
|
||||
/*
|
||||
** Register the functions sqlite_attach and sqlite_detach.
|
||||
*/
|
||||
void sqlite3AttachFunctions(sqlite3 *db){
|
||||
#ifndef SQLITE_OMIT_ATTACH
|
||||
static const int enc = SQLITE_UTF8;
|
||||
sqlite3CreateFunc(db, "sqlite_attach", 3, enc, db, attachFunc, 0, 0);
|
||||
sqlite3CreateFunc(db, "sqlite_detach", 1, enc, db, detachFunc, 0, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -67,6 +67,8 @@ int sqlite3BtreeGetReserve(Btree*);
|
|||
int sqlite3BtreeSetAutoVacuum(Btree *, int);
|
||||
int sqlite3BtreeGetAutoVacuum(Btree *);
|
||||
int sqlite3BtreeBeginTrans(Btree*,int);
|
||||
int sqlite3BtreeCommitPhaseOne(Btree*, const char *zMaster);
|
||||
int sqlite3BtreeCommitPhaseTwo(Btree*);
|
||||
int sqlite3BtreeCommit(Btree*);
|
||||
int sqlite3BtreeRollback(Btree*);
|
||||
int sqlite3BtreeBeginStmt(Btree*);
|
||||
|
@ -76,7 +78,6 @@ int sqlite3BtreeCreateTable(Btree*, int*, int flags);
|
|||
int sqlite3BtreeIsInTrans(Btree*);
|
||||
int sqlite3BtreeIsInStmt(Btree*);
|
||||
int sqlite3BtreeIsInReadTrans(Btree*);
|
||||
int sqlite3BtreeSync(Btree*, const char *zMaster);
|
||||
void *sqlite3BtreeSchema(Btree *, int, void(*)(void *));
|
||||
int sqlite3BtreeSchemaLocked(Btree *);
|
||||
int sqlite3BtreeLockTable(Btree *, int, u8);
|
||||
|
@ -114,10 +115,10 @@ void sqlite3BtreeSetCompare(
|
|||
);
|
||||
|
||||
int sqlite3BtreeCloseCursor(BtCursor*);
|
||||
int sqlite3BtreeMoveto(BtCursor*, const void *pKey, i64 nKey, int *pRes);
|
||||
int sqlite3BtreeMoveto(BtCursor*,const void *pKey,i64 nKey,int bias,int *pRes);
|
||||
int sqlite3BtreeDelete(BtCursor*);
|
||||
int sqlite3BtreeInsert(BtCursor*, const void *pKey, i64 nKey,
|
||||
const void *pData, int nData);
|
||||
const void *pData, int nData, int bias);
|
||||
int sqlite3BtreeFirst(BtCursor*, int *pRes);
|
||||
int sqlite3BtreeLast(BtCursor*, int *pRes);
|
||||
int sqlite3BtreeNext(BtCursor*, int *pRes);
|
||||
|
|
|
@ -82,7 +82,7 @@ void sqlite3TableLock(
|
|||
}
|
||||
|
||||
nBytes = sizeof(TableLock) * (pParse->nTableLock+1);
|
||||
sqliteReallocOrFree((void **)&pParse->aTableLock, nBytes);
|
||||
pParse->aTableLock = sqliteReallocOrFree(pParse->aTableLock, nBytes);
|
||||
if( pParse->aTableLock ){
|
||||
p = &pParse->aTableLock[pParse->nTableLock++];
|
||||
p->iDb = iDb;
|
||||
|
@ -442,17 +442,6 @@ void sqlite3ResetInternalSchema(sqlite3 *db, int iDb){
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** This routine is called whenever a rollback occurs. If there were
|
||||
** schema changes during the transaction, then we have to reset the
|
||||
** internal hash tables and reload them from disk.
|
||||
*/
|
||||
void sqlite3RollbackInternalChanges(sqlite3 *db){
|
||||
if( db->flags & SQLITE_InternChanges ){
|
||||
sqlite3ResetInternalSchema(db, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** This routine is called when a commit occurs.
|
||||
*/
|
||||
|
@ -887,7 +876,7 @@ void sqlite3StartTable(
|
|||
sqlite3VdbeAddOp(v, OP_NewRowid, 0, 0);
|
||||
sqlite3VdbeAddOp(v, OP_Dup, 0, 0);
|
||||
sqlite3VdbeAddOp(v, OP_Null, 0, 0);
|
||||
sqlite3VdbeAddOp(v, OP_Insert, 0, 0);
|
||||
sqlite3VdbeAddOp(v, OP_Insert, 0, OPFLAG_APPEND);
|
||||
sqlite3VdbeAddOp(v, OP_Close, 0, 0);
|
||||
sqlite3VdbeAddOp(v, OP_Pull, 1, 0);
|
||||
}
|
||||
|
@ -2357,17 +2346,17 @@ void sqlite3CreateIndex(
|
|||
}
|
||||
if( !db->init.busy ){
|
||||
if( SQLITE_OK!=sqlite3ReadSchema(pParse) ) goto exit_create_index;
|
||||
if( sqlite3FindIndex(db, zName, pDb->zName)!=0 ){
|
||||
if( !ifNotExist ){
|
||||
sqlite3ErrorMsg(pParse, "index %s already exists", zName);
|
||||
}
|
||||
goto exit_create_index;
|
||||
}
|
||||
if( sqlite3FindTable(db, zName, 0)!=0 ){
|
||||
sqlite3ErrorMsg(pParse, "there is already a table named %s", zName);
|
||||
goto exit_create_index;
|
||||
}
|
||||
}
|
||||
if( sqlite3FindIndex(db, zName, pDb->zName)!=0 ){
|
||||
if( !ifNotExist ){
|
||||
sqlite3ErrorMsg(pParse, "index %s already exists", zName);
|
||||
}
|
||||
goto exit_create_index;
|
||||
}
|
||||
}else{
|
||||
char zBuf[30];
|
||||
int n;
|
||||
|
@ -2783,44 +2772,46 @@ exit_drop_index:
|
|||
}
|
||||
|
||||
/*
|
||||
** ppArray points into a structure where there is an array pointer
|
||||
** followed by two integers. The first integer is the
|
||||
** number of elements in the structure array. The second integer
|
||||
** is the number of allocated slots in the array.
|
||||
** pArray is a pointer to an array of objects. Each object in the
|
||||
** array is szEntry bytes in size. This routine allocates a new
|
||||
** object on the end of the array.
|
||||
**
|
||||
** In other words, the structure looks something like this:
|
||||
** *pnEntry is the number of entries already in use. *pnAlloc is
|
||||
** the previously allocated size of the array. initSize is the
|
||||
** suggested initial array size allocation.
|
||||
**
|
||||
** struct Example1 {
|
||||
** struct subElem *aEntry;
|
||||
** int nEntry;
|
||||
** int nAlloc;
|
||||
** }
|
||||
** The index of the new entry is returned in *pIdx.
|
||||
**
|
||||
** The pnEntry parameter points to the equivalent of Example1.nEntry.
|
||||
**
|
||||
** This routine allocates a new slot in the array, zeros it out,
|
||||
** and returns its index. If malloc fails a negative number is returned.
|
||||
**
|
||||
** szEntry is the sizeof of a single array entry. initSize is the
|
||||
** number of array entries allocated on the initial allocation.
|
||||
** This routine returns a pointer to the array of objects. This
|
||||
** might be the same as the pArray parameter or it might be a different
|
||||
** pointer if the array was resized.
|
||||
*/
|
||||
int sqlite3ArrayAllocate(void **ppArray, int szEntry, int initSize){
|
||||
char *p;
|
||||
int *an = (int*)&ppArray[1];
|
||||
if( an[0]>=an[1] ){
|
||||
void *sqlite3ArrayAllocate(
|
||||
void *pArray, /* Array of objects. Might be reallocated */
|
||||
int szEntry, /* Size of each object in the array */
|
||||
int initSize, /* Suggested initial allocation, in elements */
|
||||
int *pnEntry, /* Number of objects currently in use */
|
||||
int *pnAlloc, /* Current size of the allocation, in elements */
|
||||
int *pIdx /* Write the index of a new slot here */
|
||||
){
|
||||
char *z;
|
||||
if( *pnEntry >= *pnAlloc ){
|
||||
void *pNew;
|
||||
int newSize;
|
||||
newSize = an[1]*2 + initSize;
|
||||
pNew = sqliteRealloc(*ppArray, newSize*szEntry);
|
||||
newSize = (*pnAlloc)*2 + initSize;
|
||||
pNew = sqliteRealloc(pArray, newSize*szEntry);
|
||||
if( pNew==0 ){
|
||||
return -1;
|
||||
*pIdx = -1;
|
||||
return pArray;
|
||||
}
|
||||
an[1] = newSize;
|
||||
*ppArray = pNew;
|
||||
*pnAlloc = newSize;
|
||||
pArray = pNew;
|
||||
}
|
||||
p = *ppArray;
|
||||
memset(&p[an[0]*szEntry], 0, szEntry);
|
||||
return an[0]++;
|
||||
z = (char*)pArray;
|
||||
memset(&z[*pnEntry * szEntry], 0, szEntry);
|
||||
*pIdx = *pnEntry;
|
||||
++*pnEntry;
|
||||
return pArray;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -2836,7 +2827,14 @@ IdList *sqlite3IdListAppend(IdList *pList, Token *pToken){
|
|||
if( pList==0 ) return 0;
|
||||
pList->nAlloc = 0;
|
||||
}
|
||||
i = sqlite3ArrayAllocate((void**)&pList->a, sizeof(pList->a[0]), 5);
|
||||
pList->a = sqlite3ArrayAllocate(
|
||||
pList->a,
|
||||
sizeof(pList->a[0]),
|
||||
5,
|
||||
&pList->nId,
|
||||
&pList->nAlloc,
|
||||
&i
|
||||
);
|
||||
if( i<0 ){
|
||||
sqlite3IdListDelete(pList);
|
||||
return 0;
|
||||
|
|
|
@ -565,7 +565,7 @@ static int parseModifier(const char *zMod, DateTime *p){
|
|||
case '8':
|
||||
case '9': {
|
||||
n = getValue(z, &r);
|
||||
if( n<=0 ) break;
|
||||
assert( n>=1 );
|
||||
if( z[n]==':' ){
|
||||
/* A modifier of the form (+|-)HH:MM:SS.FFF adds (or subtracts) the
|
||||
** specified number of hours, minutes, seconds, and fractional seconds
|
||||
|
@ -815,7 +815,7 @@ static void strftimeFunc(
|
|||
case 'f': {
|
||||
double s = x.s;
|
||||
if( s>59.999 ) s = 59.999;
|
||||
sqlite3_snprintf(7, &z[j],"%02.3f", s);
|
||||
sqlite3_snprintf(7, &z[j],"%06.3f", s);
|
||||
j += strlen(&z[j]);
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -131,7 +131,7 @@ static char comparisonAffinity(Expr *pExpr){
|
|||
aff = sqlite3CompareAffinity(pExpr->pSelect->pEList->a[0].pExpr, aff);
|
||||
}
|
||||
else if( !aff ){
|
||||
aff = SQLITE_AFF_NUMERIC;
|
||||
aff = SQLITE_AFF_NONE;
|
||||
}
|
||||
return aff;
|
||||
}
|
||||
|
@ -404,7 +404,7 @@ void sqlite3ExprAssignVarNumber(Parse *pParse, Expr *pExpr){
|
|||
pExpr->iTable = ++pParse->nVar;
|
||||
if( pParse->nVarExpr>=pParse->nVarExprAlloc-1 ){
|
||||
pParse->nVarExprAlloc += pParse->nVarExprAlloc + 10;
|
||||
sqliteReallocOrFree((void**)&pParse->apVarExpr,
|
||||
pParse->apVarExpr = sqliteReallocOrFree(pParse->apVarExpr,
|
||||
pParse->nVarExprAlloc*sizeof(pParse->apVarExpr[0]) );
|
||||
}
|
||||
if( !sqlite3MallocFailed() ){
|
||||
|
@ -1518,6 +1518,31 @@ static void codeInteger(Vdbe *v, const char *z, int n){
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Generate code that will extract the iColumn-th column from
|
||||
** table pTab and push that column value on the stack. There
|
||||
** is an open cursor to pTab in iTable. If iColumn<0 then
|
||||
** code is generated that extracts the rowid.
|
||||
*/
|
||||
void sqlite3ExprCodeGetColumn(Vdbe *v, Table *pTab, int iColumn, int iTable){
|
||||
if( iColumn<0 ){
|
||||
int op = (pTab && IsVirtual(pTab)) ? OP_VRowid : OP_Rowid;
|
||||
sqlite3VdbeAddOp(v, op, iTable, 0);
|
||||
}else if( pTab==0 ){
|
||||
sqlite3VdbeAddOp(v, OP_Column, iTable, iColumn);
|
||||
}else{
|
||||
int op = IsVirtual(pTab) ? OP_VColumn : OP_Column;
|
||||
sqlite3VdbeAddOp(v, op, iTable, iColumn);
|
||||
sqlite3ColumnDefault(v, pTab, iColumn);
|
||||
#ifndef SQLITE_OMIT_FLOATING_POINT
|
||||
if( pTab->aCol[iColumn].affinity==SQLITE_AFF_REAL ){
|
||||
sqlite3VdbeAddOp(v, OP_RealAffinity, 0, 0);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Generate code into the current Vdbe to evaluate the given
|
||||
** expression and leave the result on the top of stack.
|
||||
|
@ -1558,21 +1583,8 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){
|
|||
/* This only happens when coding check constraints */
|
||||
assert( pParse->ckOffset>0 );
|
||||
sqlite3VdbeAddOp(v, OP_Dup, pParse->ckOffset-pExpr->iColumn-1, 1);
|
||||
}else if( pExpr->iColumn>=0 ){
|
||||
Table *pTab = pExpr->pTab;
|
||||
int iCol = pExpr->iColumn;
|
||||
int op = (pTab && IsVirtual(pTab)) ? OP_VColumn : OP_Column;
|
||||
sqlite3VdbeAddOp(v, op, pExpr->iTable, iCol);
|
||||
sqlite3ColumnDefault(v, pTab, iCol);
|
||||
#ifndef SQLITE_OMIT_FLOATING_POINT
|
||||
if( pTab && pTab->aCol[iCol].affinity==SQLITE_AFF_REAL ){
|
||||
sqlite3VdbeAddOp(v, OP_RealAffinity, 0, 0);
|
||||
}
|
||||
#endif
|
||||
}else{
|
||||
Table *pTab = pExpr->pTab;
|
||||
int op = (pTab && IsVirtual(pTab)) ? OP_VRowid : OP_Rowid;
|
||||
sqlite3VdbeAddOp(v, op, pExpr->iTable, 0);
|
||||
sqlite3ExprCodeGetColumn(v, pExpr->pTab, pExpr->iColumn, pExpr->iTable);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -2175,6 +2187,16 @@ void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
|
|||
/*
|
||||
** Do a deep comparison of two expression trees. Return TRUE (non-zero)
|
||||
** if they are identical and return FALSE if they differ in any way.
|
||||
**
|
||||
** Sometimes this routine will return FALSE even if the two expressions
|
||||
** really are equivalent. If we cannot prove that the expressions are
|
||||
** identical, we return FALSE just to be safe. So if this routine
|
||||
** returns false, then you do not really know for certain if the two
|
||||
** expressions are the same. But if you get a TRUE return, then you
|
||||
** can be sure the expressions are the same. In the places where
|
||||
** this routine is used, it does not hurt to get an extra FALSE - that
|
||||
** just might result in some slightly slower code. But returning
|
||||
** an incorrect TRUE could lead to a malfunction.
|
||||
*/
|
||||
int sqlite3ExprCompare(Expr *pA, Expr *pB){
|
||||
int i;
|
||||
|
@ -2198,7 +2220,7 @@ int sqlite3ExprCompare(Expr *pA, Expr *pB){
|
|||
}
|
||||
if( pA->pSelect || pB->pSelect ) return 0;
|
||||
if( pA->iTable!=pB->iTable || pA->iColumn!=pB->iColumn ) return 0;
|
||||
if( pA->token.z ){
|
||||
if( pA->op!=TK_COLUMN && pA->token.z ){
|
||||
if( pB->token.z==0 ) return 0;
|
||||
if( pB->token.n!=pA->token.n ) return 0;
|
||||
if( sqlite3StrNICmp((char*)pA->token.z,(char*)pB->token.z,pB->token.n)!=0 ){
|
||||
|
@ -2215,10 +2237,14 @@ int sqlite3ExprCompare(Expr *pA, Expr *pB){
|
|||
*/
|
||||
static int addAggInfoColumn(AggInfo *pInfo){
|
||||
int i;
|
||||
i = sqlite3ArrayAllocate((void**)&pInfo->aCol, sizeof(pInfo->aCol[0]), 3);
|
||||
if( i<0 ){
|
||||
return -1;
|
||||
}
|
||||
pInfo->aCol = sqlite3ArrayAllocate(
|
||||
pInfo->aCol,
|
||||
sizeof(pInfo->aCol[0]),
|
||||
3,
|
||||
&pInfo->nColumn,
|
||||
&pInfo->nColumnAlloc,
|
||||
&i
|
||||
);
|
||||
return i;
|
||||
}
|
||||
|
||||
|
@ -2228,10 +2254,14 @@ static int addAggInfoColumn(AggInfo *pInfo){
|
|||
*/
|
||||
static int addAggInfoFunc(AggInfo *pInfo){
|
||||
int i;
|
||||
i = sqlite3ArrayAllocate((void**)&pInfo->aFunc, sizeof(pInfo->aFunc[0]), 2);
|
||||
if( i<0 ){
|
||||
return -1;
|
||||
}
|
||||
pInfo->aFunc = sqlite3ArrayAllocate(
|
||||
pInfo->aFunc,
|
||||
sizeof(pInfo->aFunc[0]),
|
||||
3,
|
||||
&pInfo->nFunc,
|
||||
&pInfo->nFuncAlloc,
|
||||
&i
|
||||
);
|
||||
return i;
|
||||
}
|
||||
|
||||
|
@ -2266,15 +2296,17 @@ static int analyzeAggregate(void *pArg, Expr *pExpr){
|
|||
** Make an entry for the column in pAggInfo->aCol[] if there
|
||||
** is not an entry there already.
|
||||
*/
|
||||
int k;
|
||||
pCol = pAggInfo->aCol;
|
||||
for(i=0; i<pAggInfo->nColumn; i++, pCol++){
|
||||
for(k=0; k<pAggInfo->nColumn; k++, pCol++){
|
||||
if( pCol->iTable==pExpr->iTable &&
|
||||
pCol->iColumn==pExpr->iColumn ){
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( i>=pAggInfo->nColumn && (i = addAggInfoColumn(pAggInfo))>=0 ){
|
||||
pCol = &pAggInfo->aCol[i];
|
||||
if( k>=pAggInfo->nColumn && (k = addAggInfoColumn(pAggInfo))>=0 ){
|
||||
pCol = &pAggInfo->aCol[k];
|
||||
pCol->pTab = pExpr->pTab;
|
||||
pCol->iTable = pExpr->iTable;
|
||||
pCol->iColumn = pExpr->iColumn;
|
||||
pCol->iMem = pParse->nMem++;
|
||||
|
@ -2305,7 +2337,7 @@ static int analyzeAggregate(void *pArg, Expr *pExpr){
|
|||
*/
|
||||
pExpr->pAggInfo = pAggInfo;
|
||||
pExpr->op = TK_AGG_COLUMN;
|
||||
pExpr->iAgg = i;
|
||||
pExpr->iAgg = k;
|
||||
break;
|
||||
} /* endif pExpr->iTable==pItem->iCursor */
|
||||
} /* end loop over pSrcList */
|
||||
|
|
|
@ -668,6 +668,114 @@ static void hexFunc(
|
|||
sqlite3_result_text(context, zHex, n*2, sqlite3_free);
|
||||
}
|
||||
|
||||
/*
|
||||
** The replace() function. Three arguments are all strings: call
|
||||
** them A, B, and C. The result is also a string which is derived
|
||||
** from A by replacing every occurance of B with C. The match
|
||||
** must be exact. Collating sequences are not used.
|
||||
*/
|
||||
static void replaceFunc(
|
||||
sqlite3_context *context,
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
const unsigned char *zStr; /* The input string A */
|
||||
const unsigned char *zPattern; /* The pattern string B */
|
||||
const unsigned char *zRep; /* The replacement string C */
|
||||
unsigned char *zOut; /* The output */
|
||||
int nStr; /* Size of zStr */
|
||||
int nPattern; /* Size of zPattern */
|
||||
int nRep; /* Size of zRep */
|
||||
int nOut; /* Maximum size of zOut */
|
||||
int loopLimit; /* Last zStr[] that might match zPattern[] */
|
||||
int i, j; /* Loop counters */
|
||||
|
||||
assert( argc==3 );
|
||||
if( sqlite3_value_type(argv[0])==SQLITE_NULL ||
|
||||
sqlite3_value_type(argv[1])==SQLITE_NULL ||
|
||||
sqlite3_value_type(argv[2])==SQLITE_NULL ){
|
||||
return;
|
||||
}
|
||||
zStr = sqlite3_value_text(argv[0]);
|
||||
nStr = sqlite3_value_bytes(argv[0]);
|
||||
zPattern = sqlite3_value_text(argv[1]);
|
||||
nPattern = sqlite3_value_bytes(argv[1]);
|
||||
zRep = sqlite3_value_text(argv[2]);
|
||||
nRep = sqlite3_value_bytes(argv[2]);
|
||||
if( nPattern>=nRep ){
|
||||
nOut = nStr;
|
||||
}else{
|
||||
nOut = (nStr/nPattern + 1)*nRep;
|
||||
}
|
||||
zOut = sqlite3_malloc(nOut+1);
|
||||
if( zOut==0 ) return;
|
||||
loopLimit = nStr - nPattern;
|
||||
for(i=j=0; i<=loopLimit; i++){
|
||||
if( zStr[i]!=zPattern[0] || memcmp(&zStr[i], zPattern, nPattern) ){
|
||||
zOut[j++] = zStr[i];
|
||||
}else{
|
||||
memcpy(&zOut[j], zRep, nRep);
|
||||
j += nRep;
|
||||
i += nPattern-1;
|
||||
}
|
||||
}
|
||||
memcpy(&zOut[j], &zStr[i], nStr-i);
|
||||
j += nStr - i;
|
||||
assert( j<=nOut );
|
||||
zOut[j] = 0;
|
||||
sqlite3_result_text(context, (char*)zOut, j, sqlite3_free);
|
||||
}
|
||||
|
||||
/*
|
||||
** Implementation of the TRIM(), LTRIM(), and RTRIM() functions.
|
||||
** The userdata is 0x1 for left trim, 0x2 for right trim, 0x3 for both.
|
||||
*/
|
||||
static void trimFunc(
|
||||
sqlite3_context *context,
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
const unsigned char *zIn; /* Input string */
|
||||
const unsigned char *zCharSet; /* Set of characters to trim */
|
||||
int nIn; /* Number of bytes in input */
|
||||
int flags;
|
||||
int i;
|
||||
unsigned char cFirst, cNext;
|
||||
if( sqlite3_value_type(argv[0])==SQLITE_NULL ){
|
||||
return;
|
||||
}
|
||||
zIn = sqlite3_value_text(argv[0]);
|
||||
nIn = sqlite3_value_bytes(argv[0]);
|
||||
if( argc==1 ){
|
||||
static const unsigned char zSpace[] = " ";
|
||||
zCharSet = zSpace;
|
||||
}else if( sqlite3_value_type(argv[1])==SQLITE_NULL ){
|
||||
return;
|
||||
}else{
|
||||
zCharSet = sqlite3_value_text(argv[1]);
|
||||
}
|
||||
cFirst = zCharSet[0];
|
||||
if( cFirst ){
|
||||
flags = (int)sqlite3_user_data(context);
|
||||
if( flags & 1 ){
|
||||
for(; nIn>0; nIn--, zIn++){
|
||||
if( cFirst==zIn[0] ) continue;
|
||||
for(i=1; zCharSet[i] && zCharSet[i]!=zIn[0]; i++){}
|
||||
if( zCharSet[i]==0 ) break;
|
||||
}
|
||||
}
|
||||
if( flags & 2 ){
|
||||
for(; nIn>0; nIn--){
|
||||
cNext = zIn[nIn-1];
|
||||
if( cFirst==cNext ) continue;
|
||||
for(i=1; zCharSet[i] && zCharSet[i]!=cNext; i++){}
|
||||
if( zCharSet[i]==0 ) break;
|
||||
}
|
||||
}
|
||||
}
|
||||
sqlite3_result_text(context, (char*)zIn, nIn, SQLITE_TRANSIENT);
|
||||
}
|
||||
|
||||
#ifdef SQLITE_SOUNDEX
|
||||
/*
|
||||
** Compute the soundex encoding of a word.
|
||||
|
@ -1019,7 +1127,7 @@ static void minmaxStep(sqlite3_context *context, int argc, sqlite3_value **argv)
|
|||
** Therefore the next statement sets variable 'max' to 1 for the max()
|
||||
** aggregate, or 0 for min().
|
||||
*/
|
||||
max = ((sqlite3_user_data(context)==(void *)-1)?1:0);
|
||||
max = sqlite3_user_data(context)!=0;
|
||||
cmp = sqlite3MemCompare(pBest, pArg, pColl);
|
||||
if( (max && cmp<0) || (!max && cmp>0) ){
|
||||
sqlite3VdbeMemCopy(pBest, pArg);
|
||||
|
@ -1049,15 +1157,15 @@ void sqlite3RegisterBuiltinFunctions(sqlite3 *db){
|
|||
static const struct {
|
||||
char *zName;
|
||||
signed char nArg;
|
||||
u8 argType; /* 0: none. 1: db 2: (-1) */
|
||||
u8 argType; /* ff: db 1: 0, 2: 1, 3: 2,... N: N-1. */
|
||||
u8 eTextRep; /* 1: UTF-16. 0: UTF-8 */
|
||||
u8 needCollSeq;
|
||||
void (*xFunc)(sqlite3_context*,int,sqlite3_value **);
|
||||
} aFuncs[] = {
|
||||
{ "min", -1, 0, SQLITE_UTF8, 1, minmaxFunc },
|
||||
{ "min", 0, 0, SQLITE_UTF8, 1, 0 },
|
||||
{ "max", -1, 2, SQLITE_UTF8, 1, minmaxFunc },
|
||||
{ "max", 0, 2, SQLITE_UTF8, 1, 0 },
|
||||
{ "max", -1, 1, SQLITE_UTF8, 1, minmaxFunc },
|
||||
{ "max", 0, 1, SQLITE_UTF8, 1, 0 },
|
||||
{ "typeof", 1, 0, SQLITE_UTF8, 0, typeofFunc },
|
||||
{ "length", 1, 0, SQLITE_UTF8, 0, lengthFunc },
|
||||
{ "substr", 3, 0, SQLITE_UTF8, 0, substrFunc },
|
||||
|
@ -1079,22 +1187,29 @@ void sqlite3RegisterBuiltinFunctions(sqlite3 *db){
|
|||
{ "nullif", 2, 0, SQLITE_UTF8, 1, nullifFunc },
|
||||
{ "sqlite_version", 0, 0, SQLITE_UTF8, 0, versionFunc},
|
||||
{ "quote", 1, 0, SQLITE_UTF8, 0, quoteFunc },
|
||||
{ "last_insert_rowid", 0, 1, SQLITE_UTF8, 0, last_insert_rowid },
|
||||
{ "changes", 0, 1, SQLITE_UTF8, 0, changes },
|
||||
{ "total_changes", 0, 1, SQLITE_UTF8, 0, total_changes },
|
||||
{ "last_insert_rowid", 0, 0xff, SQLITE_UTF8, 0, last_insert_rowid },
|
||||
{ "changes", 0, 0xff, SQLITE_UTF8, 0, changes },
|
||||
{ "total_changes", 0, 0xff, SQLITE_UTF8, 0, total_changes },
|
||||
{ "replace", 3, 0, SQLITE_UTF8, 0, replaceFunc },
|
||||
{ "ltrim", 1, 1, SQLITE_UTF8, 0, trimFunc },
|
||||
{ "ltrim", 2, 1, SQLITE_UTF8, 0, trimFunc },
|
||||
{ "rtrim", 1, 2, SQLITE_UTF8, 0, trimFunc },
|
||||
{ "rtrim", 2, 2, SQLITE_UTF8, 0, trimFunc },
|
||||
{ "trim", 1, 3, SQLITE_UTF8, 0, trimFunc },
|
||||
{ "trim", 2, 3, SQLITE_UTF8, 0, trimFunc },
|
||||
#ifdef SQLITE_SOUNDEX
|
||||
{ "soundex", 1, 0, SQLITE_UTF8, 0, soundexFunc},
|
||||
{ "soundex", 1, 0, SQLITE_UTF8, 0, soundexFunc},
|
||||
#endif
|
||||
#ifndef SQLITE_OMIT_LOAD_EXTENSION
|
||||
{ "load_extension", 1, 1, SQLITE_UTF8, 0, loadExt },
|
||||
{ "load_extension", 2, 1, SQLITE_UTF8, 0, loadExt },
|
||||
{ "load_extension", 1, 0xff, SQLITE_UTF8, 0, loadExt },
|
||||
{ "load_extension", 2, 0xff, SQLITE_UTF8, 0, loadExt },
|
||||
#endif
|
||||
#ifdef SQLITE_TEST
|
||||
{ "randstr", 2, 0, SQLITE_UTF8, 0, randStr },
|
||||
{ "test_destructor", 1, 1, SQLITE_UTF8, 0, test_destructor},
|
||||
{ "test_destructor_count", 0, 0, SQLITE_UTF8, 0, test_destructor_count},
|
||||
{ "test_auxdata", -1, 0, SQLITE_UTF8, 0, test_auxdata},
|
||||
{ "test_error", 1, 0, SQLITE_UTF8, 0, test_error},
|
||||
{ "randstr", 2, 0, SQLITE_UTF8, 0, randStr },
|
||||
{ "test_destructor", 1, 0xff, SQLITE_UTF8, 0, test_destructor},
|
||||
{ "test_destructor_count", 0, 0, SQLITE_UTF8, 0, test_destructor_count},
|
||||
{ "test_auxdata", -1, 0, SQLITE_UTF8, 0, test_auxdata},
|
||||
{ "test_error", 1, 0, SQLITE_UTF8, 0, test_error},
|
||||
#endif
|
||||
};
|
||||
static const struct {
|
||||
|
@ -1106,7 +1221,7 @@ void sqlite3RegisterBuiltinFunctions(sqlite3 *db){
|
|||
void (*xFinalize)(sqlite3_context*);
|
||||
} aAggs[] = {
|
||||
{ "min", 1, 0, 1, minmaxStep, minMaxFinalize },
|
||||
{ "max", 1, 2, 1, minmaxStep, minMaxFinalize },
|
||||
{ "max", 1, 1, 1, minmaxStep, minMaxFinalize },
|
||||
{ "sum", 1, 0, 0, sumStep, sumFinalize },
|
||||
{ "total", 1, 0, 0, sumStep, totalFinalize },
|
||||
{ "avg", 1, 0, 0, sumStep, avgFinalize },
|
||||
|
@ -1116,10 +1231,12 @@ void sqlite3RegisterBuiltinFunctions(sqlite3 *db){
|
|||
int i;
|
||||
|
||||
for(i=0; i<sizeof(aFuncs)/sizeof(aFuncs[0]); i++){
|
||||
void *pArg = 0;
|
||||
switch( aFuncs[i].argType ){
|
||||
case 1: pArg = db; break;
|
||||
case 2: pArg = (void *)(-1); break;
|
||||
void *pArg;
|
||||
u8 argType = aFuncs[i].argType;
|
||||
if( argType==0xff ){
|
||||
pArg = db;
|
||||
}else{
|
||||
pArg = (void*)(int)argType;
|
||||
}
|
||||
sqlite3CreateFunc(db, aFuncs[i].zName, aFuncs[i].nArg,
|
||||
aFuncs[i].eTextRep, pArg, aFuncs[i].xFunc, 0, 0);
|
||||
|
@ -1138,11 +1255,7 @@ void sqlite3RegisterBuiltinFunctions(sqlite3 *db){
|
|||
sqlite3AttachFunctions(db);
|
||||
#endif
|
||||
for(i=0; i<sizeof(aAggs)/sizeof(aAggs[0]); i++){
|
||||
void *pArg = 0;
|
||||
switch( aAggs[i].argType ){
|
||||
case 1: pArg = db; break;
|
||||
case 2: pArg = (void *)(-1); break;
|
||||
}
|
||||
void *pArg = (void*)(int)aAggs[i].argType;
|
||||
sqlite3CreateFunc(db, aAggs[i].zName, aAggs[i].nArg, SQLITE_UTF8,
|
||||
pArg, 0, aAggs[i].xStep, aAggs[i].xFinalize);
|
||||
if( aAggs[i].needCollSeq ){
|
||||
|
|
|
@ -291,7 +291,7 @@ static void removeElementGivenHash(
|
|||
if( pEntry->count<=0 ){
|
||||
pEntry->chain = 0;
|
||||
}
|
||||
if( pH->copyKey && elem->pKey ){
|
||||
if( pH->copyKey ){
|
||||
pH->xFree(elem->pKey);
|
||||
}
|
||||
pH->xFree( elem );
|
||||
|
@ -378,6 +378,9 @@ void *sqlite3HashInsert(Hash *pH, const void *pKey, int nKey, void *data){
|
|||
rehash(pH,8);
|
||||
if( pH->htsize==0 ){
|
||||
pH->count = 0;
|
||||
if( pH->copyKey ){
|
||||
pH->xFree(new_elem->pKey);
|
||||
}
|
||||
pH->xFree(new_elem);
|
||||
return data;
|
||||
}
|
||||
|
|
|
@ -118,6 +118,117 @@ static int selectReadsTable(Select *p, Schema *pSchema, int iTab){
|
|||
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:
|
||||
**
|
||||
|
@ -133,7 +244,7 @@ static int selectReadsTable(Select *p, Schema *pSchema, int iTab){
|
|||
** 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
|
||||
** 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:
|
||||
**
|
||||
|
@ -142,16 +253,37 @@ static int selectReadsTable(Select *p, Schema *pSchema, int iTab){
|
|||
** write the resulting record into <table>
|
||||
** cleanup
|
||||
**
|
||||
** If the statement is of the form
|
||||
** The three remaining templates assume 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:
|
||||
** 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 tables in the SELECT
|
||||
** loop over the rows in the SELECT
|
||||
** gosub C
|
||||
** end loop
|
||||
** cleanup after the SELECT
|
||||
|
@ -162,7 +294,7 @@ static int selectReadsTable(Select *p, Schema *pSchema, int iTab){
|
|||
** return
|
||||
** D: cleanup
|
||||
**
|
||||
** The third template is used if the insert statement takes its
|
||||
** 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
|
||||
|
@ -214,6 +346,7 @@ void sqlite3Insert(
|
|||
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;
|
||||
|
||||
#ifndef SQLITE_OMIT_TRIGGER
|
||||
|
@ -221,10 +354,6 @@ void sqlite3Insert(
|
|||
int triggers_exist = 0; /* True if there are FOR EACH ROW triggers */
|
||||
#endif
|
||||
|
||||
#ifndef SQLITE_OMIT_AUTOINCREMENT
|
||||
int counterRowid = 0; /* Memory cell holding rowid of autoinc counter */
|
||||
#endif
|
||||
|
||||
if( pParse->nErr || sqlite3MallocFailed() ){
|
||||
goto insert_cleanup;
|
||||
}
|
||||
|
@ -291,31 +420,27 @@ void sqlite3Insert(
|
|||
newIdx = pParse->nTab++;
|
||||
}
|
||||
|
||||
#ifndef SQLITE_OMIT_AUTOINCREMENT
|
||||
#ifndef SQLITE_OMIT_XFER_OPT
|
||||
/* If the statement is of the form
|
||||
**
|
||||
** INSERT INTO <table1> SELECT * FROM <table2>;
|
||||
**
|
||||
** Then special optimizations can be applied that make the transfer
|
||||
** very fast and which reduce fragmentation of indices.
|
||||
*/
|
||||
if( pColumn==0 && xferOptimization(pParse, pTab, pSelect, onError, iDb) ){
|
||||
assert( !triggers_exist );
|
||||
assert( pList==0 );
|
||||
goto insert_cleanup;
|
||||
}
|
||||
#endif /* SQLITE_OMIT_XFER_OPT */
|
||||
|
||||
/* If this is an AUTOINCREMENT table, look up the sequence number in the
|
||||
** sqlite_sequence table and store it in memory cell counterMem. Also
|
||||
** remember the rowid of the sqlite_sequence table entry in memory cell
|
||||
** counterRowid.
|
||||
*/
|
||||
if( pTab->autoInc ){
|
||||
int iCur = pParse->nTab;
|
||||
int addr = sqlite3VdbeCurrentAddr(v);
|
||||
counterRowid = pParse->nMem++;
|
||||
counterMem = pParse->nMem++;
|
||||
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, counterRowid, 1);
|
||||
sqlite3VdbeAddOp(v, OP_Column, iCur, 1);
|
||||
sqlite3VdbeAddOp(v, OP_MemStore, counterMem, 1);
|
||||
sqlite3VdbeAddOp(v, OP_Goto, 0, addr+13);
|
||||
sqlite3VdbeAddOp(v, OP_Next, iCur, addr+4);
|
||||
sqlite3VdbeAddOp(v, OP_Close, iCur, 0);
|
||||
}
|
||||
#endif /* SQLITE_OMIT_AUTOINCREMENT */
|
||||
counterMem = autoIncBegin(pParse, iDb, pTab);
|
||||
|
||||
/* Figure out how many columns of data are supplied. If the data
|
||||
** is coming from a SELECT statement, then this step also generates
|
||||
|
@ -365,7 +490,7 @@ void sqlite3Insert(
|
|||
sqlite3VdbeAddOp(v, OP_MakeRecord, nColumn, 0);
|
||||
sqlite3VdbeAddOp(v, OP_NewRowid, srcTab, 0);
|
||||
sqlite3VdbeAddOp(v, OP_Pull, 1, 0);
|
||||
sqlite3VdbeAddOp(v, OP_Insert, srcTab, 0);
|
||||
sqlite3VdbeAddOp(v, OP_Insert, srcTab, OPFLAG_APPEND);
|
||||
sqlite3VdbeAddOp(v, OP_Return, 0, 0);
|
||||
|
||||
/* The following code runs first because the GOTO at the very top
|
||||
|
@ -577,25 +702,32 @@ void sqlite3Insert(
|
|||
}else if( pSelect ){
|
||||
sqlite3VdbeAddOp(v, OP_Dup, nColumn - keyColumn - 1, 1);
|
||||
}else{
|
||||
VdbeOp *pOp;
|
||||
sqlite3ExprCode(pParse, pList->a[keyColumn].pExpr);
|
||||
pOp = sqlite3VdbeGetOp(v, sqlite3VdbeCurrentAddr(v) - 1);
|
||||
if( pOp->opcode==OP_Null ){
|
||||
appendFlag = 1;
|
||||
pOp->opcode = OP_NewRowid;
|
||||
pOp->p1 = base;
|
||||
pOp->p2 = counterMem;
|
||||
}
|
||||
}
|
||||
/* If the PRIMARY KEY expression is NULL, then use OP_NewRowid
|
||||
** to generate a unique primary key value.
|
||||
*/
|
||||
sqlite3VdbeAddOp(v, OP_NotNull, -1, sqlite3VdbeCurrentAddr(v)+3);
|
||||
sqlite3VdbeAddOp(v, OP_Pop, 1, 0);
|
||||
sqlite3VdbeAddOp(v, OP_NewRowid, base, counterMem);
|
||||
sqlite3VdbeAddOp(v, OP_MustBeInt, 0, 0);
|
||||
if( !appendFlag ){
|
||||
sqlite3VdbeAddOp(v, OP_NotNull, -1, sqlite3VdbeCurrentAddr(v)+3);
|
||||
sqlite3VdbeAddOp(v, OP_Pop, 1, 0);
|
||||
sqlite3VdbeAddOp(v, OP_NewRowid, base, counterMem);
|
||||
sqlite3VdbeAddOp(v, OP_MustBeInt, 0, 0);
|
||||
}
|
||||
}else if( IsVirtual(pTab) ){
|
||||
sqlite3VdbeAddOp(v, OP_Null, 0, 0);
|
||||
}else{
|
||||
sqlite3VdbeAddOp(v, OP_NewRowid, base, counterMem);
|
||||
appendFlag = 1;
|
||||
}
|
||||
#ifndef SQLITE_OMIT_AUTOINCREMENT
|
||||
if( pTab->autoInc ){
|
||||
sqlite3VdbeAddOp(v, OP_MemMax, counterMem, 0);
|
||||
}
|
||||
#endif /* SQLITE_OMIT_AUTOINCREMENT */
|
||||
autoIncStep(pParse, counterMem);
|
||||
|
||||
/* Push onto the stack, data for all columns of the new entry, beginning
|
||||
** with the first column.
|
||||
|
@ -641,7 +773,8 @@ void sqlite3Insert(
|
|||
sqlite3GenerateConstraintChecks(pParse, pTab, base, 0, keyColumn>=0,
|
||||
0, onError, endOfLoop);
|
||||
sqlite3CompleteInsertion(pParse, pTab, base, 0,0,0,
|
||||
(triggers_exist & TRIGGER_AFTER)!=0 ? newIdx : -1);
|
||||
(triggers_exist & TRIGGER_AFTER)!=0 ? newIdx : -1,
|
||||
appendFlag);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -688,26 +821,11 @@ void sqlite3Insert(
|
|||
}
|
||||
}
|
||||
|
||||
#ifndef SQLITE_OMIT_AUTOINCREMENT
|
||||
/* Update the sqlite_sequence table by storing the content of the
|
||||
** counter value in memory counterMem back into the sqlite_sequence
|
||||
** table.
|
||||
*/
|
||||
if( pTab->autoInc ){
|
||||
int iCur = pParse->nTab;
|
||||
int addr = sqlite3VdbeCurrentAddr(v);
|
||||
sqlite3OpenTable(pParse, iCur, iDb, pDb->pSchema->pSeqTab, OP_OpenWrite);
|
||||
sqlite3VdbeAddOp(v, OP_MemLoad, counterRowid, 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, counterMem, 0);
|
||||
sqlite3VdbeAddOp(v, OP_MakeRecord, 2, 0);
|
||||
sqlite3VdbeAddOp(v, OP_Insert, iCur, 0);
|
||||
sqlite3VdbeAddOp(v, OP_Close, iCur, 0);
|
||||
}
|
||||
#endif
|
||||
autoIncEnd(pParse, iDb, pTab, counterMem);
|
||||
|
||||
/*
|
||||
** Return the number of rows inserted. If this routine is
|
||||
|
@ -1067,7 +1185,8 @@ void sqlite3CompleteInsertion(
|
|||
char *aIdxUsed, /* Which indices are used. NULL means all are used */
|
||||
int rowidChng, /* True if the record number will change */
|
||||
int isUpdate, /* True for UPDATE, False for INSERT */
|
||||
int newIdx /* Index of NEW table for triggers. -1 if none */
|
||||
int newIdx, /* Index of NEW table for triggers. -1 if none */
|
||||
int appendBias /* True if this is likely to be an append */
|
||||
){
|
||||
int i;
|
||||
Vdbe *v;
|
||||
|
@ -1098,6 +1217,9 @@ void sqlite3CompleteInsertion(
|
|||
pik_flags = OPFLAG_NCHANGE;
|
||||
pik_flags |= (isUpdate?OPFLAG_ISUPDATE:OPFLAG_LASTROWID);
|
||||
}
|
||||
if( appendBias ){
|
||||
pik_flags |= OPFLAG_APPEND;
|
||||
}
|
||||
sqlite3VdbeAddOp(v, OP_Insert, base, pik_flags);
|
||||
if( !pParse->nested ){
|
||||
sqlite3VdbeChangeP3(v, -1, pTab->zName, P3_STATIC);
|
||||
|
@ -1140,3 +1262,327 @@ void sqlite3OpenTableAndIndices(
|
|||
pParse->nTab = base+i;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#ifdef SQLITE_TEST
|
||||
/*
|
||||
** The following global variable is incremented whenever the
|
||||
** transfer optimization is used. This is used for testing
|
||||
** purposes only - to make sure the transfer optimization really
|
||||
** is happening when it is suppose to.
|
||||
*/
|
||||
int sqlite3_xferopt_count;
|
||||
#endif /* SQLITE_TEST */
|
||||
|
||||
|
||||
#ifndef SQLITE_OMIT_XFER_OPT
|
||||
/*
|
||||
** Check to collation names to see if they are compatible.
|
||||
*/
|
||||
static int xferCompatibleCollation(const char *z1, const char *z2){
|
||||
if( z1==0 ){
|
||||
return z2==0;
|
||||
}
|
||||
if( z2==0 ){
|
||||
return 0;
|
||||
}
|
||||
return sqlite3StrICmp(z1, z2)==0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Check to see if index pSrc is compatible as a source of data
|
||||
** for index pDest in an insert transfer optimization. The rules
|
||||
** for a compatible index:
|
||||
**
|
||||
** * The index is over the same set of columns
|
||||
** * The same DESC and ASC markings occurs on all columns
|
||||
** * The same onError processing (OE_Abort, OE_Ignore, etc)
|
||||
** * The same collating sequence on each column
|
||||
*/
|
||||
static int xferCompatibleIndex(Index *pDest, Index *pSrc){
|
||||
int i;
|
||||
assert( pDest && pSrc );
|
||||
assert( pDest->pTable!=pSrc->pTable );
|
||||
if( pDest->nColumn!=pSrc->nColumn ){
|
||||
return 0; /* Different number of columns */
|
||||
}
|
||||
if( pDest->onError!=pSrc->onError ){
|
||||
return 0; /* Different conflict resolution strategies */
|
||||
}
|
||||
for(i=0; i<pSrc->nColumn; i++){
|
||||
if( pSrc->aiColumn[i]!=pDest->aiColumn[i] ){
|
||||
return 0; /* Different columns indexed */
|
||||
}
|
||||
if( pSrc->aSortOrder[i]!=pDest->aSortOrder[i] ){
|
||||
return 0; /* Different sort orders */
|
||||
}
|
||||
if( pSrc->azColl[i]!=pDest->azColl[i] ){
|
||||
return 0; /* Different sort orders */
|
||||
}
|
||||
}
|
||||
|
||||
/* If no test above fails then the indices must be compatible */
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
** Attempt the transfer optimization on INSERTs of the form
|
||||
**
|
||||
** INSERT INTO tab1 SELECT * FROM tab2;
|
||||
**
|
||||
** This optimization is only attempted if
|
||||
**
|
||||
** (1) tab1 and tab2 have identical schemas including all the
|
||||
** same indices and constraints
|
||||
**
|
||||
** (2) tab1 and tab2 are different tables
|
||||
**
|
||||
** (3) There must be no triggers on tab1
|
||||
**
|
||||
** (4) The result set of the SELECT statement is "*"
|
||||
**
|
||||
** (5) The SELECT statement has no WHERE, HAVING, ORDER BY, GROUP BY,
|
||||
** or LIMIT clause.
|
||||
**
|
||||
** (6) The SELECT statement is a simple (not a compound) select that
|
||||
** contains only tab2 in its FROM clause
|
||||
**
|
||||
** This method for implementing the INSERT transfers raw records from
|
||||
** tab2 over to tab1. The columns are not decoded. Raw records from
|
||||
** the indices of tab2 are transfered to tab1 as well. In so doing,
|
||||
** the resulting tab1 has much less fragmentation.
|
||||
**
|
||||
** This routine returns TRUE if the optimization is attempted. If any
|
||||
** of the conditions above fail so that the optimization should not
|
||||
** be attempted, then this routine returns FALSE.
|
||||
*/
|
||||
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 */
|
||||
){
|
||||
ExprList *pEList; /* The result set of the SELECT */
|
||||
Table *pSrc; /* The table in the FROM clause of SELECT */
|
||||
Index *pSrcIdx, *pDestIdx; /* Source and destination indices */
|
||||
struct SrcList_item *pItem; /* An element of pSelect->pSrc */
|
||||
int i; /* Loop counter */
|
||||
int iDbSrc; /* The database of pSrc */
|
||||
int iSrc, iDest; /* Cursors from source and destination */
|
||||
int addr1, addr2; /* Loop addresses */
|
||||
int emptyDestTest; /* Address of test for empty pDest */
|
||||
int emptySrcTest; /* Address of test for empty pSrc */
|
||||
int memRowid = 0; /* A memcell containing a rowid from pSrc */
|
||||
Vdbe *v; /* The VDBE we are building */
|
||||
KeyInfo *pKey; /* Key information for an index */
|
||||
int counterMem; /* Memory register used by AUTOINC */
|
||||
|
||||
if( pSelect==0 ){
|
||||
return 0; /* Must be of the form INSERT INTO ... SELECT ... */
|
||||
}
|
||||
if( pDest->pTrigger ){
|
||||
return 0; /* tab1 must not have triggers */
|
||||
}
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
if( pDest->isVirtual ){
|
||||
return 0; /* tab1 must not be a virtual table */
|
||||
}
|
||||
#endif
|
||||
if( onError==OE_Default ){
|
||||
onError = OE_Abort;
|
||||
}
|
||||
if( onError!=OE_Abort && onError!=OE_Rollback ){
|
||||
return 0; /* Cannot do OR REPLACE or OR IGNORE or OR FAIL */
|
||||
}
|
||||
if( pSelect->pSrc==0 ){
|
||||
return 0; /* SELECT must have a FROM clause */
|
||||
}
|
||||
if( pSelect->pSrc->nSrc!=1 ){
|
||||
return 0; /* FROM clause must have exactly one term */
|
||||
}
|
||||
if( pSelect->pSrc->a[0].pSelect ){
|
||||
return 0; /* FROM clause cannot contain a subquery */
|
||||
}
|
||||
if( pSelect->pWhere ){
|
||||
return 0; /* SELECT may not have a WHERE clause */
|
||||
}
|
||||
if( pSelect->pOrderBy ){
|
||||
return 0; /* SELECT may not have an ORDER BY clause */
|
||||
}
|
||||
/* Do not need to test for a HAVING clause. If HAVING is present but
|
||||
** there is no ORDER BY, we will get an error. */
|
||||
if( pSelect->pGroupBy ){
|
||||
return 0; /* SELECT may not have a GROUP BY clause */
|
||||
}
|
||||
if( pSelect->pLimit ){
|
||||
return 0; /* SELECT may not have a LIMIT clause */
|
||||
}
|
||||
assert( pSelect->pOffset==0 ); /* Must be so if pLimit==0 */
|
||||
if( pSelect->pPrior ){
|
||||
return 0; /* SELECT may not be a compound query */
|
||||
}
|
||||
if( pSelect->isDistinct ){
|
||||
return 0; /* SELECT may not be DISTINCT */
|
||||
}
|
||||
pEList = pSelect->pEList;
|
||||
assert( pEList!=0 );
|
||||
if( pEList->nExpr!=1 ){
|
||||
return 0; /* The result set must have exactly one column */
|
||||
}
|
||||
assert( pEList->a[0].pExpr );
|
||||
if( pEList->a[0].pExpr->op!=TK_ALL ){
|
||||
return 0; /* The result set must be the special operator "*" */
|
||||
}
|
||||
|
||||
/* At this point we have established that the statement is of the
|
||||
** correct syntactic form to participate in this optimization. Now
|
||||
** we have to check the semantics.
|
||||
*/
|
||||
pItem = pSelect->pSrc->a;
|
||||
pSrc = sqlite3LocateTable(pParse, pItem->zName, pItem->zDatabase);
|
||||
if( pSrc==0 ){
|
||||
return 0; /* FROM clause does not contain a real table */
|
||||
}
|
||||
if( pSrc==pDest ){
|
||||
return 0; /* tab1 and tab2 may not be the same table */
|
||||
}
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
if( pSrc->isVirtual ){
|
||||
return 0; /* tab2 must not be a virtual table */
|
||||
}
|
||||
#endif
|
||||
if( pSrc->pSelect ){
|
||||
return 0; /* tab2 may not be a view */
|
||||
}
|
||||
if( pDest->nCol!=pSrc->nCol ){
|
||||
return 0; /* Number of columns must be the same in tab1 and tab2 */
|
||||
}
|
||||
if( pDest->iPKey!=pSrc->iPKey ){
|
||||
return 0; /* Both tables must have the same INTEGER PRIMARY KEY */
|
||||
}
|
||||
for(i=0; i<pDest->nCol; i++){
|
||||
if( pDest->aCol[i].affinity!=pSrc->aCol[i].affinity ){
|
||||
return 0; /* Affinity must be the same on all columns */
|
||||
}
|
||||
if( !xferCompatibleCollation(pDest->aCol[i].zColl, pSrc->aCol[i].zColl) ){
|
||||
return 0; /* Collating sequence must be the same on all columns */
|
||||
}
|
||||
if( pDest->aCol[i].notNull && !pSrc->aCol[i].notNull ){
|
||||
return 0; /* tab2 must be NOT NULL if tab1 is */
|
||||
}
|
||||
}
|
||||
for(pDestIdx=pDest->pIndex; pDestIdx; pDestIdx=pDestIdx->pNext){
|
||||
for(pSrcIdx=pSrc->pIndex; pSrcIdx; pSrcIdx=pSrcIdx->pNext){
|
||||
if( xferCompatibleIndex(pDestIdx, pSrcIdx) ) break;
|
||||
}
|
||||
if( pSrcIdx==0 ){
|
||||
return 0; /* pDestIdx has no corresponding index in pSrc */
|
||||
}
|
||||
}
|
||||
#ifndef SQLITE_OMIT_CHECK
|
||||
if( pDest->pCheck && !sqlite3ExprCompare(pSrc->pCheck, pDest->pCheck) ){
|
||||
return 0; /* Tables have different CHECK constraints. Ticket #2252 */
|
||||
}
|
||||
#endif
|
||||
|
||||
/* If we get this far, it means either:
|
||||
**
|
||||
** * We can always do the transfer if the table contains an
|
||||
** an integer primary key
|
||||
**
|
||||
** * We can conditionally do the transfer if the destination
|
||||
** table is empty.
|
||||
*/
|
||||
#ifdef SQLITE_TEST
|
||||
sqlite3_xferopt_count++;
|
||||
#endif
|
||||
iDbSrc = sqlite3SchemaToIndex(pParse->db, pSrc->pSchema);
|
||||
v = sqlite3GetVdbe(pParse);
|
||||
iSrc = pParse->nTab++;
|
||||
iDest = pParse->nTab++;
|
||||
counterMem = autoIncBegin(pParse, iDbDest, pDest);
|
||||
sqlite3OpenTable(pParse, iDest, iDbDest, pDest, OP_OpenWrite);
|
||||
if( pDest->iPKey<0 && pDest->pIndex!=0 ){
|
||||
/* If tables do not have an INTEGER PRIMARY KEY and there
|
||||
** are indices to be copied and the destination is not empty,
|
||||
** we have to disallow the transfer optimization because the
|
||||
** the rowids might change which will mess up indexing.
|
||||
*/
|
||||
addr1 = sqlite3VdbeAddOp(v, OP_Rewind, iDest, 0);
|
||||
emptyDestTest = sqlite3VdbeAddOp(v, OP_Goto, 0, 0);
|
||||
sqlite3VdbeJumpHere(v, addr1);
|
||||
}else{
|
||||
emptyDestTest = 0;
|
||||
}
|
||||
sqlite3OpenTable(pParse, iSrc, iDbSrc, pSrc, OP_OpenRead);
|
||||
emptySrcTest = sqlite3VdbeAddOp(v, OP_Rewind, iSrc, 0);
|
||||
if( pDest->pIndex!=0 ){
|
||||
sqlite3VdbeAddOp(v, OP_Rowid, iSrc, 0);
|
||||
memRowid = pParse->nMem++;
|
||||
sqlite3VdbeAddOp(v, OP_MemStore, memRowid, pDest->iPKey>=0);
|
||||
}
|
||||
if( pDest->iPKey>=0 ){
|
||||
addr1 = sqlite3VdbeAddOp(v, OP_Rowid, iSrc, 0);
|
||||
sqlite3VdbeAddOp(v, OP_Dup, 0, 0);
|
||||
addr2 = sqlite3VdbeAddOp(v, OP_NotExists, iDest, 0);
|
||||
sqlite3VdbeOp3(v, OP_Halt, SQLITE_CONSTRAINT, onError,
|
||||
"PRIMARY KEY must be unique", P3_STATIC);
|
||||
sqlite3VdbeJumpHere(v, addr2);
|
||||
autoIncStep(pParse, counterMem);
|
||||
}else if( pDest->pIndex==0 ){
|
||||
addr1 = sqlite3VdbeAddOp(v, OP_NewRowid, iDest, 0);
|
||||
}else{
|
||||
addr1 = sqlite3VdbeAddOp(v, OP_Rowid, iSrc, 0);
|
||||
assert( pDest->autoInc==0 );
|
||||
}
|
||||
sqlite3VdbeAddOp(v, OP_RowData, iSrc, 0);
|
||||
sqlite3VdbeOp3(v, OP_Insert, iDest,
|
||||
OPFLAG_NCHANGE|OPFLAG_LASTROWID|OPFLAG_APPEND,
|
||||
pDest->zName, 0);
|
||||
sqlite3VdbeAddOp(v, OP_Next, iSrc, addr1);
|
||||
autoIncEnd(pParse, iDbDest, pDest, counterMem);
|
||||
for(pDestIdx=pDest->pIndex; pDestIdx; pDestIdx=pDestIdx->pNext){
|
||||
for(pSrcIdx=pSrc->pIndex; pSrcIdx; pSrcIdx=pSrcIdx->pNext){
|
||||
if( xferCompatibleIndex(pDestIdx, pSrcIdx) ) break;
|
||||
}
|
||||
assert( pSrcIdx );
|
||||
sqlite3VdbeAddOp(v, OP_Close, iSrc, 0);
|
||||
sqlite3VdbeAddOp(v, OP_Close, iDest, 0);
|
||||
sqlite3VdbeAddOp(v, OP_Integer, iDbSrc, 0);
|
||||
pKey = sqlite3IndexKeyinfo(pParse, pSrcIdx);
|
||||
VdbeComment((v, "# %s", pSrcIdx->zName));
|
||||
sqlite3VdbeOp3(v, OP_OpenRead, iSrc, pSrcIdx->tnum,
|
||||
(char*)pKey, P3_KEYINFO_HANDOFF);
|
||||
sqlite3VdbeAddOp(v, OP_Integer, iDbDest, 0);
|
||||
pKey = sqlite3IndexKeyinfo(pParse, pDestIdx);
|
||||
VdbeComment((v, "# %s", pDestIdx->zName));
|
||||
sqlite3VdbeOp3(v, OP_OpenWrite, iDest, pDestIdx->tnum,
|
||||
(char*)pKey, P3_KEYINFO_HANDOFF);
|
||||
addr1 = sqlite3VdbeAddOp(v, OP_Rewind, iSrc, 0);
|
||||
sqlite3VdbeAddOp(v, OP_RowKey, iSrc, 0);
|
||||
if( pDestIdx->onError!=OE_None ){
|
||||
sqlite3VdbeAddOp(v, OP_MemLoad, memRowid, 0);
|
||||
addr2 = sqlite3VdbeAddOp(v, OP_IsUnique, iDest, 0);
|
||||
sqlite3VdbeOp3(v, OP_Halt, SQLITE_CONSTRAINT, onError,
|
||||
"UNIQUE constraint failed", P3_STATIC);
|
||||
sqlite3VdbeJumpHere(v, addr2);
|
||||
}
|
||||
sqlite3VdbeAddOp(v, OP_IdxInsert, iDest, 1);
|
||||
sqlite3VdbeAddOp(v, OP_Next, iSrc, addr1+1);
|
||||
sqlite3VdbeJumpHere(v, addr1);
|
||||
}
|
||||
sqlite3VdbeJumpHere(v, emptySrcTest);
|
||||
sqlite3VdbeAddOp(v, OP_Close, iSrc, 0);
|
||||
sqlite3VdbeAddOp(v, OP_Close, iDest, 0);
|
||||
if( emptyDestTest ){
|
||||
sqlite3VdbeAddOp(v, OP_Halt, SQLITE_OK, 0);
|
||||
sqlite3VdbeJumpHere(v, emptyDestTest);
|
||||
sqlite3VdbeAddOp(v, OP_Close, iDest, 0);
|
||||
return 0;
|
||||
}else{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
#endif /* SQLITE_OMIT_XFER_OPT */
|
||||
|
|
|
@ -1,85 +1,98 @@
|
|||
/* Hash score: 167 */
|
||||
/***** This file contains automatically generated code ******
|
||||
**
|
||||
** The code in this file has been automatically generated by
|
||||
**
|
||||
** $Header$
|
||||
**
|
||||
** The code in this file implements a function that determines whether
|
||||
** or not a given identifier is really an SQL keyword. The same thing
|
||||
** might be implemented more directly using a hand-written hash table.
|
||||
** But by using this automatically generated code, the size of the code
|
||||
** is substantially reduced. This is important for embedded applications
|
||||
** on platforms with limited memory.
|
||||
*/
|
||||
/* Hash score: 165 */
|
||||
static int keywordCode(const char *z, int n){
|
||||
static const char zText[544] =
|
||||
static const char zText[536] =
|
||||
"ABORTABLEFTEMPORARYADDATABASELECTHENDEFAULTRANSACTIONATURALTER"
|
||||
"AISEACHECKEYAFTEREFERENCESCAPELSEXCEPTRIGGEREGEXPLAINITIALLYANALYZE"
|
||||
"XCLUSIVEXISTSTATEMENTANDEFERRABLEATTACHAVINGLOBEFOREIGNOREINDEX"
|
||||
"AUTOINCREMENTBEGINNERENAMEBETWEENOTNULLIKEBYCASCADEFERREDELETE"
|
||||
"CASECASTCOLLATECOLUMNCOMMITCONFLICTCONSTRAINTERSECTCREATECROSS"
|
||||
"CURRENT_DATECURRENT_TIMESTAMPLANDESCDETACHDISTINCTDROPRAGMATCH"
|
||||
"FAILIMITFROMFULLGROUPDATEIFIMMEDIATEINSERTINSTEADINTOFFSETISNULL"
|
||||
"JOINORDEREPLACEOUTERESTRICTPRIMARYQUERYRIGHTROLLBACKROWHENUNION"
|
||||
"UNIQUEUSINGVACUUMVALUESVIEWHEREVIRTUAL";
|
||||
"XCLUSIVEXISTSANDEFERRABLEATTACHAVINGLOBEFOREIGNOREINDEXAUTOINCREMENT"
|
||||
"BEGINNERENAMEBETWEENOTNULLIKEBYCASCADEFERREDELETECASECASTCOLLATE"
|
||||
"COLUMNCOMMITCONFLICTCONSTRAINTERSECTCREATECROSSCURRENT_DATECURRENT_TIMESTAMP"
|
||||
"LANDESCDETACHDISTINCTDROPRAGMATCHFAILIMITFROMFULLGROUPDATEIFIMMEDIATE"
|
||||
"INSERTINSTEADINTOFFSETISNULLJOINORDEREPLACEOUTERESTRICTPRIMARY"
|
||||
"QUERYRIGHTROLLBACKROWHENUNIONUNIQUEUSINGVACUUMVALUESVIEWHEREVIRTUAL"
|
||||
;
|
||||
static const unsigned char aHash[127] = {
|
||||
92, 80, 107, 91, 0, 4, 0, 0, 114, 0, 83, 0, 0,
|
||||
95, 44, 76, 93, 0, 106, 109, 97, 90, 0, 10, 0, 0,
|
||||
113, 0, 117, 103, 0, 28, 48, 0, 41, 0, 0, 65, 71,
|
||||
0, 63, 19, 0, 105, 36, 104, 0, 108, 74, 0, 0, 33,
|
||||
0, 61, 37, 0, 8, 0, 115, 38, 12, 0, 77, 40, 25,
|
||||
66, 0, 0, 31, 81, 53, 30, 50, 20, 88, 0, 34, 0,
|
||||
75, 26, 0, 72, 0, 0, 0, 64, 47, 67, 22, 87, 29,
|
||||
69, 86, 0, 1, 0, 9, 101, 58, 18, 0, 112, 82, 99,
|
||||
54, 6, 85, 0, 0, 49, 94, 0, 102, 0, 70, 0, 0,
|
||||
15, 0, 116, 51, 56, 0, 2, 55, 0, 111,
|
||||
91, 79, 106, 90, 0, 4, 0, 0, 113, 0, 82, 0, 0,
|
||||
94, 43, 75, 92, 0, 105, 108, 96, 89, 0, 10, 0, 0,
|
||||
112, 0, 116, 102, 0, 28, 47, 0, 40, 0, 0, 64, 70,
|
||||
0, 62, 19, 0, 104, 35, 103, 0, 107, 73, 0, 0, 33,
|
||||
0, 60, 36, 0, 8, 0, 114, 37, 12, 0, 76, 39, 25,
|
||||
65, 0, 0, 31, 80, 52, 30, 49, 20, 87, 0, 34, 0,
|
||||
74, 26, 0, 71, 0, 0, 0, 63, 46, 66, 22, 86, 29,
|
||||
68, 85, 0, 1, 0, 9, 100, 57, 18, 0, 111, 81, 98,
|
||||
53, 6, 84, 0, 0, 48, 93, 0, 101, 0, 69, 0, 0,
|
||||
15, 0, 115, 50, 55, 0, 2, 54, 0, 110,
|
||||
};
|
||||
static const unsigned char aNext[117] = {
|
||||
static const unsigned char aNext[116] = {
|
||||
0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0,
|
||||
0, 11, 0, 0, 0, 0, 5, 13, 0, 7, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 43, 0, 0, 0, 0, 0,
|
||||
0, 0, 16, 0, 23, 52, 0, 0, 0, 0, 45, 0, 59,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 73, 42, 0, 24, 60,
|
||||
21, 0, 79, 0, 0, 68, 0, 0, 84, 46, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 39, 96, 98, 0, 0, 100, 0, 32,
|
||||
0, 14, 27, 78, 0, 57, 89, 0, 35, 0, 62, 0, 110,
|
||||
0, 11, 0, 0, 0, 0, 5, 13, 7, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 42, 0, 0, 0, 0, 0, 0,
|
||||
0, 16, 0, 23, 51, 0, 0, 0, 0, 44, 0, 58, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 72, 41, 0, 24, 59, 21,
|
||||
0, 78, 0, 0, 67, 0, 0, 83, 45, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 38, 95, 97, 0, 0, 99, 0, 32, 0,
|
||||
14, 27, 77, 0, 56, 88, 0, 0, 0, 61, 0, 109,
|
||||
};
|
||||
static const unsigned char aLen[117] = {
|
||||
static const unsigned char aLen[116] = {
|
||||
5, 5, 4, 4, 9, 2, 3, 8, 2, 6, 4, 3, 7,
|
||||
11, 2, 7, 5, 5, 4, 5, 3, 5, 10, 6, 4, 6,
|
||||
7, 6, 7, 9, 3, 7, 9, 6, 9, 3, 10, 6, 6,
|
||||
4, 6, 3, 7, 6, 7, 5, 13, 2, 2, 5, 5, 6,
|
||||
7, 3, 7, 4, 4, 2, 7, 3, 8, 6, 4, 4, 7,
|
||||
6, 6, 8, 10, 9, 6, 5, 12, 12, 17, 4, 4, 6,
|
||||
8, 2, 4, 6, 5, 4, 5, 4, 4, 5, 6, 2, 9,
|
||||
6, 7, 4, 2, 6, 3, 6, 4, 5, 7, 5, 8, 7,
|
||||
5, 5, 8, 3, 4, 5, 6, 5, 6, 6, 4, 5, 7,
|
||||
7, 6, 7, 9, 3, 7, 9, 6, 3, 10, 6, 6, 4,
|
||||
6, 3, 7, 6, 7, 5, 13, 2, 2, 5, 5, 6, 7,
|
||||
3, 7, 4, 4, 2, 7, 3, 8, 6, 4, 4, 7, 6,
|
||||
6, 8, 10, 9, 6, 5, 12, 12, 17, 4, 4, 6, 8,
|
||||
2, 4, 6, 5, 4, 5, 4, 4, 5, 6, 2, 9, 6,
|
||||
7, 4, 2, 6, 3, 6, 4, 5, 7, 5, 8, 7, 5,
|
||||
5, 8, 3, 4, 5, 6, 5, 6, 6, 4, 5, 7,
|
||||
};
|
||||
static const unsigned short int aOffset[117] = {
|
||||
static const unsigned short int aOffset[116] = {
|
||||
0, 4, 7, 10, 10, 14, 19, 21, 26, 27, 32, 34, 36,
|
||||
42, 51, 52, 57, 61, 65, 67, 71, 74, 78, 86, 91, 94,
|
||||
99, 105, 108, 113, 118, 122, 128, 136, 141, 150, 152, 162, 167,
|
||||
172, 175, 177, 177, 181, 185, 187, 192, 194, 196, 205, 208, 212,
|
||||
218, 224, 224, 227, 230, 234, 236, 237, 241, 248, 254, 258, 262,
|
||||
269, 275, 281, 289, 296, 305, 311, 316, 328, 328, 344, 348, 352,
|
||||
358, 359, 366, 369, 373, 378, 381, 386, 390, 394, 397, 403, 405,
|
||||
414, 420, 427, 430, 430, 433, 436, 442, 446, 450, 457, 461, 469,
|
||||
476, 481, 486, 494, 496, 500, 505, 511, 516, 522, 528, 531, 536,
|
||||
99, 105, 108, 113, 118, 122, 128, 136, 142, 144, 154, 159, 164,
|
||||
167, 169, 169, 173, 177, 179, 184, 186, 188, 197, 200, 204, 210,
|
||||
216, 216, 219, 222, 226, 228, 229, 233, 240, 246, 250, 254, 261,
|
||||
267, 273, 281, 288, 297, 303, 308, 320, 320, 336, 340, 344, 350,
|
||||
351, 358, 361, 365, 370, 373, 378, 382, 386, 389, 395, 397, 406,
|
||||
412, 419, 422, 422, 425, 428, 434, 438, 442, 449, 453, 461, 468,
|
||||
473, 478, 486, 488, 492, 497, 503, 508, 514, 520, 523, 528,
|
||||
};
|
||||
static const unsigned char aCode[117] = {
|
||||
static const unsigned char aCode[116] = {
|
||||
TK_ABORT, TK_TABLE, TK_JOIN_KW, TK_TEMP, TK_TEMP,
|
||||
TK_OR, TK_ADD, TK_DATABASE, TK_AS, TK_SELECT,
|
||||
TK_THEN, TK_END, TK_DEFAULT, TK_TRANSACTION,TK_ON,
|
||||
TK_JOIN_KW, TK_ALTER, TK_RAISE, TK_EACH, TK_CHECK,
|
||||
TK_KEY, TK_AFTER, TK_REFERENCES, TK_ESCAPE, TK_ELSE,
|
||||
TK_EXCEPT, TK_TRIGGER, TK_LIKE_KW, TK_EXPLAIN, TK_INITIALLY,
|
||||
TK_ALL, TK_ANALYZE, TK_EXCLUSIVE, TK_EXISTS, TK_STATEMENT,
|
||||
TK_AND, TK_DEFERRABLE, TK_ATTACH, TK_HAVING, TK_LIKE_KW,
|
||||
TK_BEFORE, TK_FOR, TK_FOREIGN, TK_IGNORE, TK_REINDEX,
|
||||
TK_INDEX, TK_AUTOINCR, TK_TO, TK_IN, TK_BEGIN,
|
||||
TK_JOIN_KW, TK_RENAME, TK_BETWEEN, TK_NOT, TK_NOTNULL,
|
||||
TK_NULL, TK_LIKE_KW, TK_BY, TK_CASCADE, TK_ASC,
|
||||
TK_DEFERRED, TK_DELETE, TK_CASE, TK_CAST, TK_COLLATE,
|
||||
TK_COLUMNKW, TK_COMMIT, TK_CONFLICT, TK_CONSTRAINT, TK_INTERSECT,
|
||||
TK_CREATE, TK_JOIN_KW, TK_CTIME_KW, TK_CTIME_KW, TK_CTIME_KW,
|
||||
TK_PLAN, TK_DESC, TK_DETACH, TK_DISTINCT, TK_IS,
|
||||
TK_DROP, TK_PRAGMA, TK_MATCH, TK_FAIL, TK_LIMIT,
|
||||
TK_FROM, TK_JOIN_KW, TK_GROUP, TK_UPDATE, TK_IF,
|
||||
TK_IMMEDIATE, TK_INSERT, TK_INSTEAD, TK_INTO, TK_OF,
|
||||
TK_OFFSET, TK_SET, TK_ISNULL, TK_JOIN, TK_ORDER,
|
||||
TK_REPLACE, TK_JOIN_KW, TK_RESTRICT, TK_PRIMARY, TK_QUERY,
|
||||
TK_JOIN_KW, TK_ROLLBACK, TK_ROW, TK_WHEN, TK_UNION,
|
||||
TK_UNIQUE, TK_USING, TK_VACUUM, TK_VALUES, TK_VIEW,
|
||||
TK_WHERE, TK_VIRTUAL,
|
||||
TK_ALL, TK_ANALYZE, TK_EXCLUSIVE, TK_EXISTS, TK_AND,
|
||||
TK_DEFERRABLE, TK_ATTACH, TK_HAVING, TK_LIKE_KW, TK_BEFORE,
|
||||
TK_FOR, TK_FOREIGN, TK_IGNORE, TK_REINDEX, TK_INDEX,
|
||||
TK_AUTOINCR, TK_TO, TK_IN, TK_BEGIN, TK_JOIN_KW,
|
||||
TK_RENAME, TK_BETWEEN, TK_NOT, TK_NOTNULL, TK_NULL,
|
||||
TK_LIKE_KW, TK_BY, TK_CASCADE, TK_ASC, TK_DEFERRED,
|
||||
TK_DELETE, TK_CASE, TK_CAST, TK_COLLATE, TK_COLUMNKW,
|
||||
TK_COMMIT, TK_CONFLICT, TK_CONSTRAINT, TK_INTERSECT, TK_CREATE,
|
||||
TK_JOIN_KW, TK_CTIME_KW, TK_CTIME_KW, TK_CTIME_KW, TK_PLAN,
|
||||
TK_DESC, TK_DETACH, TK_DISTINCT, TK_IS, TK_DROP,
|
||||
TK_PRAGMA, TK_MATCH, TK_FAIL, TK_LIMIT, TK_FROM,
|
||||
TK_JOIN_KW, TK_GROUP, TK_UPDATE, TK_IF, TK_IMMEDIATE,
|
||||
TK_INSERT, TK_INSTEAD, TK_INTO, TK_OF, TK_OFFSET,
|
||||
TK_SET, TK_ISNULL, TK_JOIN, TK_ORDER, TK_REPLACE,
|
||||
TK_JOIN_KW, TK_RESTRICT, TK_PRIMARY, TK_QUERY, TK_JOIN_KW,
|
||||
TK_ROLLBACK, TK_ROW, TK_WHEN, TK_UNION, TK_UNIQUE,
|
||||
TK_USING, TK_VACUUM, TK_VALUES, TK_VIEW, TK_WHERE,
|
||||
TK_VIRTUAL,
|
||||
};
|
||||
int h, i;
|
||||
if( n<2 ) return TK_ID;
|
||||
|
|
|
@ -229,6 +229,13 @@ const sqlite3_api_routines sqlite3_apis = {
|
|||
*************************************************************************
|
||||
*/
|
||||
sqlite3_overload_function,
|
||||
|
||||
/*
|
||||
** Added after 3.3.13
|
||||
*/
|
||||
sqlite3_prepare_v2,
|
||||
sqlite3_prepare16_v2,
|
||||
sqlite3_clear_bindings,
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
|
@ -20,12 +20,6 @@
|
|||
#include "os.h"
|
||||
#include <ctype.h>
|
||||
|
||||
/*
|
||||
** The following constant value is used by the SQLITE_BIGENDIAN and
|
||||
** SQLITE_LITTLEENDIAN macros.
|
||||
*/
|
||||
const int sqlite3one = 1;
|
||||
|
||||
/*
|
||||
** The version of the library
|
||||
*/
|
||||
|
@ -33,6 +27,24 @@ const char sqlite3_version[] = SQLITE_VERSION;
|
|||
const char *sqlite3_libversion(void){ return sqlite3_version; }
|
||||
int sqlite3_libversion_number(void){ return SQLITE_VERSION_NUMBER; }
|
||||
|
||||
/*
|
||||
** If the following function pointer is not NULL and if
|
||||
** SQLITE_ENABLE_IOTRACE is enabled, then messages describing
|
||||
** I/O active are written using this function. These messages
|
||||
** are intended for debugging activity only.
|
||||
*/
|
||||
void (*sqlite3_io_trace)(const char*, ...) = 0;
|
||||
|
||||
/*
|
||||
** If the following global variable points to a string which is the
|
||||
** name of a directory, then that directory will be used to store
|
||||
** temporary files.
|
||||
**
|
||||
** See also the "PRAGMA temp_store_directory" SQL command.
|
||||
*/
|
||||
char *sqlite3_temp_directory = 0;
|
||||
|
||||
|
||||
/*
|
||||
** This is the default collating function named "BINARY" which is always
|
||||
** available.
|
||||
|
@ -128,6 +140,9 @@ int sqlite3_close(sqlite3 *db){
|
|||
** cannot be opened for some reason. So this routine needs to run in
|
||||
** that case. But maybe there should be an extra magic value for the
|
||||
** "failed to open" state.
|
||||
**
|
||||
** TODO: Coverage tests do not test the case where this condition is
|
||||
** true. It's hard to see how to cause it without messing with threads.
|
||||
*/
|
||||
if( db->magic!=SQLITE_MAGIC_CLOSED && sqlite3SafetyOn(db) ){
|
||||
/* printf("DID NOT CLOSE\n"); fflush(stdout); */
|
||||
|
@ -239,7 +254,6 @@ const char *sqlite3ErrStr(int rc){
|
|||
case SQLITE_CORRUPT: z = "database disk image is malformed"; break;
|
||||
case SQLITE_FULL: z = "database or disk is full"; break;
|
||||
case SQLITE_CANTOPEN: z = "unable to open database file"; break;
|
||||
case SQLITE_PROTOCOL: z = "database locking protocol failure"; break;
|
||||
case SQLITE_EMPTY: z = "table contains no data"; break;
|
||||
case SQLITE_SCHEMA: z = "database schema has changed"; break;
|
||||
case SQLITE_CONSTRAINT: z = "constraint failed"; break;
|
||||
|
@ -722,7 +736,8 @@ int sqlite3BtreeFactory(
|
|||
*/
|
||||
const char *sqlite3_errmsg(sqlite3 *db){
|
||||
const char *z;
|
||||
if( !db || sqlite3MallocFailed() ){
|
||||
assert( !sqlite3MallocFailed() );
|
||||
if( !db ){
|
||||
return sqlite3ErrStr(SQLITE_NOMEM);
|
||||
}
|
||||
if( sqlite3SafetyCheck(db) || db->errCode==SQLITE_MISUSE ){
|
||||
|
@ -761,7 +776,8 @@ const void *sqlite3_errmsg16(sqlite3 *db){
|
|||
};
|
||||
|
||||
const void *z;
|
||||
if( sqlite3MallocFailed() ){
|
||||
assert( !sqlite3MallocFailed() );
|
||||
if( !db ){
|
||||
return (void *)(&outOfMemBe[SQLITE_UTF16NATIVE==SQLITE_UTF16LE?1:0]);
|
||||
}
|
||||
if( sqlite3SafetyCheck(db) || db->errCode==SQLITE_MISUSE ){
|
||||
|
@ -876,6 +892,9 @@ static int openDatabase(
|
|||
db->flags |= SQLITE_ShortColNames
|
||||
#if SQLITE_DEFAULT_FILE_FORMAT<4
|
||||
| SQLITE_LegacyFileFmt
|
||||
#endif
|
||||
#ifdef SQLITE_ENABLE_LOAD_EXTENSION
|
||||
| SQLITE_LoadExtension
|
||||
#endif
|
||||
;
|
||||
sqlite3HashInit(&db->aFunc, SQLITE_HASH_STRING, 0);
|
||||
|
@ -958,6 +977,16 @@ static int openDatabase(
|
|||
}
|
||||
#endif
|
||||
|
||||
/* -DSQLITE_DEFAULT_LOCKING_MODE=1 makes EXCLUSIVE the default locking
|
||||
** mode. -DSQLITE_DEFAULT_LOCKING_MODE=0 make NORMAL the default locking
|
||||
** mode. Doing nothing at all also makes NORMAL the default.
|
||||
*/
|
||||
#ifdef SQLITE_DEFAULT_LOCKING_MODE
|
||||
db->dfltLockMode = SQLITE_DEFAULT_LOCKING_MODE;
|
||||
sqlite3PagerLockingMode(sqlite3BtreePager(db->aDb[0].pBt),
|
||||
SQLITE_DEFAULT_LOCKING_MODE);
|
||||
#endif
|
||||
|
||||
opendb_out:
|
||||
if( SQLITE_NOMEM==(rc = sqlite3_errcode(db)) ){
|
||||
sqlite3_close(db);
|
||||
|
|
|
@ -61,31 +61,31 @@ const char *const sqlite3OpcodeNames[] = { "?",
|
|||
/* 57 */ "Function",
|
||||
/* 58 */ "NewRowid",
|
||||
/* 59 */ "Blob",
|
||||
/* 60 */ "Next",
|
||||
/* 61 */ "Or",
|
||||
/* 62 */ "And",
|
||||
/* 60 */ "Or",
|
||||
/* 61 */ "And",
|
||||
/* 62 */ "Next",
|
||||
/* 63 */ "ForceInt",
|
||||
/* 64 */ "ReadCookie",
|
||||
/* 65 */ "Halt",
|
||||
/* 66 */ "IsNull",
|
||||
/* 67 */ "NotNull",
|
||||
/* 68 */ "Ne",
|
||||
/* 69 */ "Eq",
|
||||
/* 70 */ "Gt",
|
||||
/* 71 */ "Le",
|
||||
/* 72 */ "Lt",
|
||||
/* 73 */ "Ge",
|
||||
/* 74 */ "Expire",
|
||||
/* 75 */ "BitAnd",
|
||||
/* 76 */ "BitOr",
|
||||
/* 77 */ "ShiftLeft",
|
||||
/* 78 */ "ShiftRight",
|
||||
/* 79 */ "Add",
|
||||
/* 80 */ "Subtract",
|
||||
/* 81 */ "Multiply",
|
||||
/* 82 */ "Divide",
|
||||
/* 83 */ "Remainder",
|
||||
/* 84 */ "Concat",
|
||||
/* 65 */ "IsNull",
|
||||
/* 66 */ "NotNull",
|
||||
/* 67 */ "Ne",
|
||||
/* 68 */ "Eq",
|
||||
/* 69 */ "Gt",
|
||||
/* 70 */ "Le",
|
||||
/* 71 */ "Lt",
|
||||
/* 72 */ "Ge",
|
||||
/* 73 */ "Halt",
|
||||
/* 74 */ "BitAnd",
|
||||
/* 75 */ "BitOr",
|
||||
/* 76 */ "ShiftLeft",
|
||||
/* 77 */ "ShiftRight",
|
||||
/* 78 */ "Add",
|
||||
/* 79 */ "Subtract",
|
||||
/* 80 */ "Multiply",
|
||||
/* 81 */ "Divide",
|
||||
/* 82 */ "Remainder",
|
||||
/* 83 */ "Concat",
|
||||
/* 84 */ "Expire",
|
||||
/* 85 */ "Negative",
|
||||
/* 86 */ "DropIndex",
|
||||
/* 87 */ "BitNot",
|
||||
|
@ -126,9 +126,9 @@ const char *const sqlite3OpcodeNames[] = { "?",
|
|||
/* 122 */ "MakeRecord",
|
||||
/* 123 */ "Variable",
|
||||
/* 124 */ "CreateTable",
|
||||
/* 125 */ "Insert",
|
||||
/* 126 */ "Real",
|
||||
/* 127 */ "HexBlob",
|
||||
/* 125 */ "Real",
|
||||
/* 126 */ "HexBlob",
|
||||
/* 127 */ "Insert",
|
||||
/* 128 */ "IdxGE",
|
||||
/* 129 */ "OpenRead",
|
||||
/* 130 */ "IdxRowid",
|
||||
|
@ -139,11 +139,10 @@ const char *const sqlite3OpcodeNames[] = { "?",
|
|||
/* 135 */ "NotUsed_135",
|
||||
/* 136 */ "NotUsed_136",
|
||||
/* 137 */ "NotUsed_137",
|
||||
/* 138 */ "NotUsed_138",
|
||||
/* 139 */ "ToText",
|
||||
/* 140 */ "ToBlob",
|
||||
/* 141 */ "ToNumeric",
|
||||
/* 142 */ "ToInt",
|
||||
/* 143 */ "ToReal",
|
||||
/* 138 */ "ToText",
|
||||
/* 139 */ "ToBlob",
|
||||
/* 140 */ "ToNumeric",
|
||||
/* 141 */ "ToInt",
|
||||
/* 142 */ "ToReal",
|
||||
};
|
||||
#endif
|
||||
|
|
|
@ -3,9 +3,9 @@
|
|||
#define OP_NotExists 1
|
||||
#define OP_Dup 2
|
||||
#define OP_MoveLt 3
|
||||
#define OP_Multiply 81 /* same as TK_STAR */
|
||||
#define OP_Multiply 80 /* same as TK_STAR */
|
||||
#define OP_VCreate 4
|
||||
#define OP_BitAnd 75 /* same as TK_BITAND */
|
||||
#define OP_BitAnd 74 /* same as TK_BITAND */
|
||||
#define OP_DropTrigger 5
|
||||
#define OP_OpenPseudo 6
|
||||
#define OP_MemInt 7
|
||||
|
@ -14,9 +14,9 @@
|
|||
#define OP_LoadAnalysis 10
|
||||
#define OP_IdxGT 11
|
||||
#define OP_Last 12
|
||||
#define OP_Subtract 80 /* same as TK_MINUS */
|
||||
#define OP_Subtract 79 /* same as TK_MINUS */
|
||||
#define OP_MemLoad 13
|
||||
#define OP_Remainder 83 /* same as TK_REM */
|
||||
#define OP_Remainder 82 /* same as TK_REM */
|
||||
#define OP_SetCookie 14
|
||||
#define OP_Sequence 15
|
||||
#define OP_Pull 17
|
||||
|
@ -25,36 +25,36 @@
|
|||
#define OP_DropTable 20
|
||||
#define OP_MemStore 21
|
||||
#define OP_ContextPush 22
|
||||
#define OP_NotNull 67 /* same as TK_NOTNULL */
|
||||
#define OP_NotNull 66 /* same as TK_NOTNULL */
|
||||
#define OP_Rowid 23
|
||||
#define OP_Real 126 /* same as TK_FLOAT */
|
||||
#define OP_String8 89 /* same as TK_STRING */
|
||||
#define OP_And 62 /* same as TK_AND */
|
||||
#define OP_BitNot 88 /* same as TK_BITNOT */
|
||||
#define OP_Real 125 /* same as TK_FLOAT */
|
||||
#define OP_String8 88 /* same as TK_STRING */
|
||||
#define OP_And 61 /* same as TK_AND */
|
||||
#define OP_BitNot 87 /* same as TK_BITNOT */
|
||||
#define OP_VFilter 24
|
||||
#define OP_NullRow 25
|
||||
#define OP_Noop 26
|
||||
#define OP_VRowid 27
|
||||
#define OP_Ge 73 /* same as TK_GE */
|
||||
#define OP_HexBlob 127 /* same as TK_BLOB */
|
||||
#define OP_Ge 72 /* same as TK_GE */
|
||||
#define OP_HexBlob 126 /* same as TK_BLOB */
|
||||
#define OP_ParseSchema 28
|
||||
#define OP_Statement 29
|
||||
#define OP_CollSeq 30
|
||||
#define OP_ContextPop 31
|
||||
#define OP_ToText 139 /* same as TK_TO_TEXT */
|
||||
#define OP_ToText 138 /* same as TK_TO_TEXT */
|
||||
#define OP_MemIncr 32
|
||||
#define OP_MoveGe 33
|
||||
#define OP_Eq 69 /* same as TK_EQ */
|
||||
#define OP_ToNumeric 141 /* same as TK_TO_NUMERIC*/
|
||||
#define OP_Eq 68 /* same as TK_EQ */
|
||||
#define OP_ToNumeric 140 /* same as TK_TO_NUMERIC*/
|
||||
#define OP_If 34
|
||||
#define OP_IfNot 35
|
||||
#define OP_ShiftRight 78 /* same as TK_RSHIFT */
|
||||
#define OP_ShiftRight 77 /* same as TK_RSHIFT */
|
||||
#define OP_Destroy 36
|
||||
#define OP_Distinct 37
|
||||
#define OP_CreateIndex 38
|
||||
#define OP_SetNumColumns 39
|
||||
#define OP_Not 16 /* same as TK_NOT */
|
||||
#define OP_Gt 70 /* same as TK_GT */
|
||||
#define OP_Gt 69 /* same as TK_GT */
|
||||
#define OP_ResetCount 40
|
||||
#define OP_MakeIdxRec 41
|
||||
#define OP_Goto 42
|
||||
|
@ -69,40 +69,40 @@
|
|||
#define OP_AutoCommit 51
|
||||
#define OP_String 52
|
||||
#define OP_FifoWrite 53
|
||||
#define OP_ToInt 142 /* same as TK_TO_INT */
|
||||
#define OP_ToInt 141 /* same as TK_TO_INT */
|
||||
#define OP_Return 54
|
||||
#define OP_Callback 55
|
||||
#define OP_AddImm 56
|
||||
#define OP_Function 57
|
||||
#define OP_Concat 84 /* same as TK_CONCAT */
|
||||
#define OP_Concat 83 /* same as TK_CONCAT */
|
||||
#define OP_NewRowid 58
|
||||
#define OP_Blob 59
|
||||
#define OP_IsNull 66 /* same as TK_ISNULL */
|
||||
#define OP_Next 60
|
||||
#define OP_IsNull 65 /* same as TK_ISNULL */
|
||||
#define OP_Next 62
|
||||
#define OP_ForceInt 63
|
||||
#define OP_ReadCookie 64
|
||||
#define OP_Halt 65
|
||||
#define OP_Expire 74
|
||||
#define OP_Or 61 /* same as TK_OR */
|
||||
#define OP_DropIndex 85
|
||||
#define OP_IdxInsert 87
|
||||
#define OP_ShiftLeft 77 /* same as TK_LSHIFT */
|
||||
#define OP_Halt 73
|
||||
#define OP_Expire 84
|
||||
#define OP_Or 60 /* same as TK_OR */
|
||||
#define OP_DropIndex 86
|
||||
#define OP_IdxInsert 89
|
||||
#define OP_ShiftLeft 76 /* same as TK_LSHIFT */
|
||||
#define OP_FifoRead 90
|
||||
#define OP_Column 91
|
||||
#define OP_Int64 92
|
||||
#define OP_Gosub 93
|
||||
#define OP_IfMemNeg 94
|
||||
#define OP_RowData 95
|
||||
#define OP_BitOr 76 /* same as TK_BITOR */
|
||||
#define OP_BitOr 75 /* same as TK_BITOR */
|
||||
#define OP_MemMax 96
|
||||
#define OP_Close 97
|
||||
#define OP_ToReal 143 /* same as TK_TO_REAL */
|
||||
#define OP_ToReal 142 /* same as TK_TO_REAL */
|
||||
#define OP_VerifyCookie 98
|
||||
#define OP_IfMemPos 99
|
||||
#define OP_Null 100
|
||||
#define OP_Integer 101
|
||||
#define OP_Transaction 102
|
||||
#define OP_Divide 82 /* same as TK_SLASH */
|
||||
#define OP_Divide 81 /* same as TK_SLASH */
|
||||
#define OP_IdxLT 103
|
||||
#define OP_Delete 104
|
||||
#define OP_Rewind 105
|
||||
|
@ -117,34 +117,33 @@
|
|||
#define OP_VOpen 114
|
||||
#define OP_AggFinal 115
|
||||
#define OP_OpenWrite 116
|
||||
#define OP_Negative 86 /* same as TK_UMINUS */
|
||||
#define OP_Le 71 /* same as TK_LE */
|
||||
#define OP_Negative 85 /* same as TK_UMINUS */
|
||||
#define OP_Le 70 /* same as TK_LE */
|
||||
#define OP_VNext 117
|
||||
#define OP_AbsValue 118
|
||||
#define OP_Sort 119
|
||||
#define OP_NotFound 120
|
||||
#define OP_MoveLe 121
|
||||
#define OP_MakeRecord 122
|
||||
#define OP_Add 79 /* same as TK_PLUS */
|
||||
#define OP_Ne 68 /* same as TK_NE */
|
||||
#define OP_Add 78 /* same as TK_PLUS */
|
||||
#define OP_Ne 67 /* same as TK_NE */
|
||||
#define OP_Variable 123
|
||||
#define OP_CreateTable 124
|
||||
#define OP_Insert 125
|
||||
#define OP_Insert 127
|
||||
#define OP_IdxGE 128
|
||||
#define OP_OpenRead 129
|
||||
#define OP_IdxRowid 130
|
||||
#define OP_ToBlob 140 /* same as TK_TO_BLOB */
|
||||
#define OP_ToBlob 139 /* same as TK_TO_BLOB */
|
||||
#define OP_VBegin 131
|
||||
#define OP_TableLock 132
|
||||
#define OP_OpenEphemeral 133
|
||||
#define OP_Lt 72 /* same as TK_LT */
|
||||
#define OP_Lt 71 /* same as TK_LT */
|
||||
#define OP_Pop 134
|
||||
|
||||
/* The following opcode values are never used */
|
||||
#define OP_NotUsed_135 135
|
||||
#define OP_NotUsed_136 136
|
||||
#define OP_NotUsed_137 137
|
||||
#define OP_NotUsed_138 138
|
||||
|
||||
/* Opcodes that are guaranteed to never push a value onto the stack
|
||||
** contain a 1 their corresponding position of the following mask
|
||||
|
@ -154,8 +153,8 @@
|
|||
#define NOPUSH_MASK_2 0xedaf
|
||||
#define NOPUSH_MASK_3 0xf1eb
|
||||
#define NOPUSH_MASK_4 0xfffe
|
||||
#define NOPUSH_MASK_5 0x61ef
|
||||
#define NOPUSH_MASK_5 0x62f7
|
||||
#define NOPUSH_MASK_6 0xbfcf
|
||||
#define NOPUSH_MASK_7 0x23bf
|
||||
#define NOPUSH_MASK_8 0xf87b
|
||||
#define NOPUSH_MASK_7 0x83bf
|
||||
#define NOPUSH_MASK_8 0x7c7b
|
||||
#define NOPUSH_MASK_9 0x0000
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#define _SQLITE_OS_C_ 1
|
||||
#include "sqliteInt.h"
|
||||
#include "os.h"
|
||||
#undef _SQLITE_OS_C_
|
||||
|
||||
/*
|
||||
** The following routines are convenience wrappers around methods
|
||||
|
@ -75,6 +76,10 @@ int sqlite3OsLockState(OsFile *id){
|
|||
int sqlite3OsCheckReservedLock(OsFile *id){
|
||||
return id->pMethod->xCheckReservedLock(id);
|
||||
}
|
||||
int sqlite3OsSectorSize(OsFile *id){
|
||||
int (*xSectorSize)(OsFile*) = id->pMethod->xSectorSize;
|
||||
return xSectorSize ? xSectorSize(id) : SQLITE_DEFAULT_SECTOR_SIZE;
|
||||
}
|
||||
|
||||
#ifdef SQLITE_ENABLE_REDEF_IO
|
||||
/*
|
||||
|
|
|
@ -21,6 +21,18 @@
|
|||
** Figure out if we are dealing with Unix, Windows, or some other
|
||||
** operating system.
|
||||
*/
|
||||
#if defined(OS_OTHER)
|
||||
# if OS_OTHER==1
|
||||
# undef OS_UNIX
|
||||
# define OS_UNIX 0
|
||||
# undef OS_WIN
|
||||
# define OS_WIN 0
|
||||
# undef OS_OS2
|
||||
# define OS_OS2 0
|
||||
# else
|
||||
# undef OS_OTHER
|
||||
# endif
|
||||
#endif
|
||||
#if !defined(OS_UNIX) && !defined(OS_OTHER)
|
||||
# define OS_OTHER 0
|
||||
# ifndef OS_WIN
|
||||
|
@ -73,6 +85,13 @@
|
|||
# define SET_FULLSYNC(x,y)
|
||||
#endif
|
||||
|
||||
/*
|
||||
** The default size of a disk sector
|
||||
*/
|
||||
#ifndef SQLITE_DEFAULT_SECTOR_SIZE
|
||||
# define SQLITE_DEFAULT_SECTOR_SIZE 512
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Temporary files are named starting with this prefix followed by 16 random
|
||||
** alphanumeric characters, and no file extension. They are stored in the
|
||||
|
@ -216,6 +235,7 @@ struct IoMethod {
|
|||
int (*xUnlock)(OsFile*, int);
|
||||
int (*xLockState)(OsFile *id);
|
||||
int (*xCheckReservedLock)(OsFile *id);
|
||||
int (*xSectorSize)(OsFile *id);
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -346,6 +366,7 @@ int sqlite3OsFileExists(const char*);
|
|||
char *sqlite3OsFullPathname(const char*);
|
||||
int sqlite3OsIsDirWritable(char*);
|
||||
int sqlite3OsSyncDirectory(const char*);
|
||||
int sqlite3OsSectorSize(OsFile *id);
|
||||
int sqlite3OsTempFileName(char*);
|
||||
int sqlite3OsRandomSeed(char*);
|
||||
int sqlite3OsSleep(int ms);
|
||||
|
@ -426,9 +447,12 @@ struct sqlite3OsVtbl {
|
|||
#endif
|
||||
|
||||
|
||||
#ifdef _SQLITE_OS_C_
|
||||
#if defined(_SQLITE_OS_C_) || defined(SQLITE_AMALGAMATION)
|
||||
/*
|
||||
** The os.c file implements the global virtual function table.
|
||||
** We have to put this file here because the initializers
|
||||
** (ex: sqlite3OsRandomSeed) are macros that are about to be
|
||||
** redefined.
|
||||
*/
|
||||
struct sqlite3OsVtbl sqlite3Os = {
|
||||
IF_DISKIO( sqlite3OsOpenReadWrite ),
|
||||
|
|
|
@ -38,25 +38,23 @@ unsigned int sqlite3_pending_byte = 0x40000000;
|
|||
|
||||
int sqlite3_os_trace = 0;
|
||||
#ifdef SQLITE_DEBUG
|
||||
static int last_page = 0;
|
||||
#define SEEK(X) last_page=(X)
|
||||
#define TRACE1(X) if( sqlite3_os_trace ) sqlite3DebugPrintf(X)
|
||||
#define TRACE2(X,Y) if( sqlite3_os_trace ) sqlite3DebugPrintf(X,Y)
|
||||
#define TRACE3(X,Y,Z) if( sqlite3_os_trace ) sqlite3DebugPrintf(X,Y,Z)
|
||||
#define TRACE4(X,Y,Z,A) if( sqlite3_os_trace ) sqlite3DebugPrintf(X,Y,Z,A)
|
||||
#define TRACE5(X,Y,Z,A,B) if( sqlite3_os_trace ) sqlite3DebugPrintf(X,Y,Z,A,B)
|
||||
#define TRACE6(X,Y,Z,A,B,C) if(sqlite3_os_trace) sqlite3DebugPrintf(X,Y,Z,A,B,C)
|
||||
#define TRACE7(X,Y,Z,A,B,C,D) \
|
||||
#define OSTRACE1(X) if( sqlite3_os_trace ) sqlite3DebugPrintf(X)
|
||||
#define OSTRACE2(X,Y) if( sqlite3_os_trace ) sqlite3DebugPrintf(X,Y)
|
||||
#define OSTRACE3(X,Y,Z) if( sqlite3_os_trace ) sqlite3DebugPrintf(X,Y,Z)
|
||||
#define OSTRACE4(X,Y,Z,A) if( sqlite3_os_trace ) sqlite3DebugPrintf(X,Y,Z,A)
|
||||
#define OSTRACE5(X,Y,Z,A,B) if( sqlite3_os_trace ) sqlite3DebugPrintf(X,Y,Z,A,B)
|
||||
#define OSTRACE6(X,Y,Z,A,B,C) \
|
||||
if(sqlite3_os_trace) sqlite3DebugPrintf(X,Y,Z,A,B,C)
|
||||
#define OSTRACE7(X,Y,Z,A,B,C,D) \
|
||||
if(sqlite3_os_trace) sqlite3DebugPrintf(X,Y,Z,A,B,C,D)
|
||||
#else
|
||||
#define SEEK(X)
|
||||
#define TRACE1(X)
|
||||
#define TRACE2(X,Y)
|
||||
#define TRACE3(X,Y,Z)
|
||||
#define TRACE4(X,Y,Z,A)
|
||||
#define TRACE5(X,Y,Z,A,B)
|
||||
#define TRACE6(X,Y,Z,A,B,C)
|
||||
#define TRACE7(X,Y,Z,A,B,C,D)
|
||||
#define OSTRACE1(X)
|
||||
#define OSTRACE2(X,Y)
|
||||
#define OSTRACE3(X,Y,Z)
|
||||
#define OSTRACE4(X,Y,Z,A)
|
||||
#define OSTRACE5(X,Y,Z,A,B)
|
||||
#define OSTRACE6(X,Y,Z,A,B,C)
|
||||
#define OSTRACE7(X,Y,Z,A,B,C,D)
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
@ -90,19 +88,23 @@ static unsigned int elapse;
|
|||
#ifdef SQLITE_TEST
|
||||
int sqlite3_io_error_hit = 0;
|
||||
int sqlite3_io_error_pending = 0;
|
||||
int sqlite3_io_error_persist = 0;
|
||||
int sqlite3_diskfull_pending = 0;
|
||||
int sqlite3_diskfull = 0;
|
||||
#define SimulateIOError(CODE) \
|
||||
if( sqlite3_io_error_pending ) \
|
||||
if( sqlite3_io_error_pending-- == 1 ){ local_ioerr(); CODE; }
|
||||
if( sqlite3_io_error_pending || sqlite3_io_error_hit ) \
|
||||
if( sqlite3_io_error_pending-- == 1 \
|
||||
|| (sqlite3_io_error_persist && sqlite3_io_error_hit) ) \
|
||||
{ local_ioerr(); CODE; }
|
||||
static void local_ioerr(){
|
||||
sqlite3_io_error_hit = 1; /* Really just a place to set a breakpoint */
|
||||
sqlite3_io_error_hit = 1;
|
||||
}
|
||||
#define SimulateDiskfullError(CODE) \
|
||||
if( sqlite3_diskfull_pending ){ \
|
||||
if( sqlite3_diskfull_pending == 1 ){ \
|
||||
local_ioerr(); \
|
||||
sqlite3_diskfull = 1; \
|
||||
sqlite3_io_error_hit = 1; \
|
||||
CODE; \
|
||||
}else{ \
|
||||
sqlite3_diskfull_pending--; \
|
||||
|
@ -186,3 +188,10 @@ void sqlite3GenericFree(void *p){
|
|||
/* Never actually used, but needed for the linker */
|
||||
int sqlite3GenericAllocationSize(void *p){ return 0; }
|
||||
#endif
|
||||
|
||||
/*
|
||||
** The default size of a disk sector
|
||||
*/
|
||||
#ifndef PAGER_SECTOR_SIZE
|
||||
# define PAGER_SECTOR_SIZE 512
|
||||
#endif
|
||||
|
|
|
@ -59,7 +59,10 @@
|
|||
** If we are to be thread-safe, include the pthreads header and define
|
||||
** the SQLITE_UNIX_THREADS macro.
|
||||
*/
|
||||
#if defined(THREADSAFE) && THREADSAFE
|
||||
#ifndef THREADSAFE
|
||||
# define THREADSAFE 1
|
||||
#endif
|
||||
#if THREADSAFE
|
||||
# include <pthread.h>
|
||||
# define SQLITE_UNIX_THREADS 1
|
||||
#endif
|
||||
|
@ -457,7 +460,7 @@ static int lockTrace(int fd, int op, struct flock *p){
|
|||
sqlite3DebugPrintf("fcntl %d %d %s %s %d %d %d %d\n",
|
||||
threadid, fd, zOpName, zType, (int)p->l_start, (int)p->l_len,
|
||||
(int)p->l_pid, s);
|
||||
if( s && op==F_SETLK && (p->l_type==F_RDLCK || p->l_type==F_WRLCK) ){
|
||||
if( s==(-1) && op==F_SETLK && (p->l_type==F_RDLCK || p->l_type==F_WRLCK) ){
|
||||
struct flock l2;
|
||||
l2 = *p;
|
||||
fcntl(fd, F_GETLK, &l2);
|
||||
|
@ -753,19 +756,20 @@ static int transferOwnership(unixFile *pFile){
|
|||
hSelf = pthread_self();
|
||||
if( pthread_equal(pFile->tid, hSelf) ){
|
||||
/* We are still in the same thread */
|
||||
TRACE1("No-transfer, same thread\n");
|
||||
OSTRACE1("No-transfer, same thread\n");
|
||||
return SQLITE_OK;
|
||||
}
|
||||
if( pFile->locktype!=NO_LOCK ){
|
||||
/* We cannot change ownership while we are holding a lock! */
|
||||
return SQLITE_MISUSE;
|
||||
}
|
||||
TRACE4("Transfer ownership of %d from %d to %d\n", pFile->h,pFile->tid,hSelf);
|
||||
OSTRACE4("Transfer ownership of %d from %d to %d\n",
|
||||
pFile->h, pFile->tid, hSelf);
|
||||
pFile->tid = hSelf;
|
||||
if (pFile->pLock != NULL) {
|
||||
releaseLockInfo(pFile->pLock);
|
||||
rc = findLockInfo(pFile->h, &pFile->pLock, 0);
|
||||
TRACE5("LOCK %d is now %s(%s,%d)\n", pFile->h,
|
||||
OSTRACE5("LOCK %d is now %s(%s,%d)\n", pFile->h,
|
||||
locktypeName(pFile->locktype),
|
||||
locktypeName(pFile->pLock->locktype), pFile->pLock->cnt);
|
||||
return rc;
|
||||
|
@ -782,6 +786,7 @@ static int transferOwnership(unixFile *pFile){
|
|||
** Delete the named file
|
||||
*/
|
||||
int sqlite3UnixDelete(const char *zFilename){
|
||||
SimulateIOError(return SQLITE_IOERR_DELETE);
|
||||
unlink(zFilename);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
@ -864,7 +869,7 @@ int sqlite3UnixOpenExclusive(const char *zFilename, OsFile **pId, int delFlag){
|
|||
assert( 0==*pId );
|
||||
h = open(zFilename,
|
||||
O_RDWR|O_CREAT|O_EXCL|O_NOFOLLOW|O_LARGEFILE|O_BINARY,
|
||||
SQLITE_DEFAULT_FILE_PERMISSIONS);
|
||||
delFlag ? 0600 : SQLITE_DEFAULT_FILE_PERMISSIONS);
|
||||
if( h<0 ){
|
||||
return SQLITE_CANTOPEN;
|
||||
}
|
||||
|
@ -914,30 +919,17 @@ static int unixOpenDirectory(
|
|||
const char *zDirname
|
||||
){
|
||||
unixFile *pFile = (unixFile*)id;
|
||||
if( pFile==0 ){
|
||||
/* Do not open the directory if the corresponding file is not already
|
||||
** open. */
|
||||
return SQLITE_CANTOPEN;
|
||||
}
|
||||
assert( pFile!=0 );
|
||||
SET_THREADID(pFile);
|
||||
assert( pFile->dirfd<0 );
|
||||
pFile->dirfd = open(zDirname, O_RDONLY|O_BINARY, 0);
|
||||
if( pFile->dirfd<0 ){
|
||||
return SQLITE_CANTOPEN;
|
||||
}
|
||||
TRACE3("OPENDIR %-3d %s\n", pFile->dirfd, zDirname);
|
||||
OSTRACE3("OPENDIR %-3d %s\n", pFile->dirfd, zDirname);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** If the following global variable points to a string which is the
|
||||
** name of a directory, then that directory will be used to store
|
||||
** temporary files.
|
||||
**
|
||||
** See also the "PRAGMA temp_store_directory" SQL command.
|
||||
*/
|
||||
char *sqlite3_temp_directory = 0;
|
||||
|
||||
/*
|
||||
** Create a temporary file name in zBuf. zBuf must be big enough to
|
||||
** hold at least SQLITE_TEMPNAME_SIZE characters.
|
||||
|
@ -1001,15 +993,23 @@ int sqlite3UnixIsDirWritable(char *zBuf){
|
|||
static int seekAndRead(unixFile *id, void *pBuf, int cnt){
|
||||
int got;
|
||||
i64 newOffset;
|
||||
#ifdef USE_PREAD
|
||||
TIMER_START;
|
||||
#if defined(USE_PREAD)
|
||||
got = pread(id->h, pBuf, cnt, id->offset);
|
||||
SimulateIOError( got = -1 );
|
||||
#elif defined(USE_PREAD64)
|
||||
got = pread64(id->h, pBuf, cnt, id->offset);
|
||||
SimulateIOError( got = -1 );
|
||||
#else
|
||||
newOffset = lseek(id->h, id->offset, SEEK_SET);
|
||||
SimulateIOError( newOffset-- );
|
||||
if( newOffset!=id->offset ){
|
||||
return -1;
|
||||
}
|
||||
got = read(id->h, pBuf, cnt);
|
||||
#endif
|
||||
TIMER_END;
|
||||
OSTRACE5("READ %-3d %5d %7lld %d\n", id->h, got, id->offset, TIMER_ELAPSED);
|
||||
if( got>0 ){
|
||||
id->offset += got;
|
||||
}
|
||||
|
@ -1024,13 +1024,7 @@ static int seekAndRead(unixFile *id, void *pBuf, int cnt){
|
|||
static int unixRead(OsFile *id, void *pBuf, int amt){
|
||||
int got;
|
||||
assert( id );
|
||||
TIMER_START;
|
||||
got = seekAndRead((unixFile*)id, pBuf, amt);
|
||||
TIMER_END;
|
||||
TRACE5("READ %-3d %5d %7d %d\n", ((unixFile*)id)->h, got,
|
||||
last_page, TIMER_ELAPSED);
|
||||
SEEK(0);
|
||||
SimulateIOError( got = -1 );
|
||||
if( got==amt ){
|
||||
return SQLITE_OK;
|
||||
}else if( got<0 ){
|
||||
|
@ -1048,8 +1042,11 @@ static int unixRead(OsFile *id, void *pBuf, int amt){
|
|||
static int seekAndWrite(unixFile *id, const void *pBuf, int cnt){
|
||||
int got;
|
||||
i64 newOffset;
|
||||
#ifdef USE_PREAD
|
||||
TIMER_START;
|
||||
#if defined(USE_PREAD)
|
||||
got = pwrite(id->h, pBuf, cnt, id->offset);
|
||||
#elif defined(USE_PREAD64)
|
||||
got = pwrite64(id->h, pBuf, cnt, id->offset);
|
||||
#else
|
||||
newOffset = lseek(id->h, id->offset, SEEK_SET);
|
||||
if( newOffset!=id->offset ){
|
||||
|
@ -1057,6 +1054,8 @@ static int seekAndWrite(unixFile *id, const void *pBuf, int cnt){
|
|||
}
|
||||
got = write(id->h, pBuf, cnt);
|
||||
#endif
|
||||
TIMER_END;
|
||||
OSTRACE5("WRITE %-3d %5d %7lld %d\n", id->h, got, id->offset, TIMER_ELAPSED);
|
||||
if( got>0 ){
|
||||
id->offset += got;
|
||||
}
|
||||
|
@ -1072,15 +1071,10 @@ static int unixWrite(OsFile *id, const void *pBuf, int amt){
|
|||
int wrote = 0;
|
||||
assert( id );
|
||||
assert( amt>0 );
|
||||
TIMER_START;
|
||||
while( amt>0 && (wrote = seekAndWrite((unixFile*)id, pBuf, amt))>0 ){
|
||||
amt -= wrote;
|
||||
pBuf = &((char*)pBuf)[wrote];
|
||||
}
|
||||
TIMER_END;
|
||||
TRACE5("WRITE %-3d %5d %7d %d\n", ((unixFile*)id)->h, wrote,
|
||||
last_page, TIMER_ELAPSED);
|
||||
SEEK(0);
|
||||
SimulateIOError(( wrote=(-1), amt=1 ));
|
||||
SimulateDiskfullError(( wrote=0, amt=1 ));
|
||||
if( amt>0 ){
|
||||
|
@ -1098,7 +1092,6 @@ static int unixWrite(OsFile *id, const void *pBuf, int amt){
|
|||
*/
|
||||
static int unixSeek(OsFile *id, i64 offset){
|
||||
assert( id );
|
||||
SEEK(offset/1024 + 1);
|
||||
#ifdef SQLITE_TEST
|
||||
if( offset ) SimulateDiskfullError(return SQLITE_FULL);
|
||||
#endif
|
||||
|
@ -1212,14 +1205,14 @@ static int unixSync(OsFile *id, int dataOnly){
|
|||
int rc;
|
||||
unixFile *pFile = (unixFile*)id;
|
||||
assert( pFile );
|
||||
TRACE2("SYNC %-3d\n", pFile->h);
|
||||
OSTRACE2("SYNC %-3d\n", pFile->h);
|
||||
rc = full_fsync(pFile->h, pFile->fullSync, dataOnly);
|
||||
SimulateIOError( rc=1 );
|
||||
if( rc ){
|
||||
return SQLITE_IOERR_FSYNC;
|
||||
}
|
||||
if( pFile->dirfd>=0 ){
|
||||
TRACE4("DIRSYNC %-3d (have_fullfsync=%d fullsync=%d)\n", pFile->dirfd,
|
||||
OSTRACE4("DIRSYNC %-3d (have_fullfsync=%d fullsync=%d)\n", pFile->dirfd,
|
||||
HAVE_FULLFSYNC, pFile->fullSync);
|
||||
#ifndef SQLITE_DISABLE_DIRSYNC
|
||||
/* The directory sync is only attempted if full_fsync is
|
||||
|
@ -1257,7 +1250,7 @@ int sqlite3UnixSyncDirectory(const char *zDirname){
|
|||
int fd;
|
||||
int r;
|
||||
fd = open(zDirname, O_RDONLY|O_BINARY, 0);
|
||||
TRACE3("DIRSYNC %-3d (%s)\n", fd, zDirname);
|
||||
OSTRACE3("DIRSYNC %-3d (%s)\n", fd, zDirname);
|
||||
if( fd<0 ){
|
||||
return SQLITE_CANTOPEN;
|
||||
}
|
||||
|
@ -1336,7 +1329,7 @@ static int unixCheckReservedLock(OsFile *id){
|
|||
}
|
||||
|
||||
sqlite3OsLeaveMutex();
|
||||
TRACE3("TEST WR-LOCK %d %d\n", pFile->h, r);
|
||||
OSTRACE3("TEST WR-LOCK %d %d\n", pFile->h, r);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
@ -1411,7 +1404,7 @@ static int unixLock(OsFile *id, int locktype){
|
|||
int s;
|
||||
|
||||
assert( pFile );
|
||||
TRACE7("LOCK %d %s was %s(%s,%d) pid=%d\n", pFile->h,
|
||||
OSTRACE7("LOCK %d %s was %s(%s,%d) pid=%d\n", pFile->h,
|
||||
locktypeName(locktype), locktypeName(pFile->locktype),
|
||||
locktypeName(pLock->locktype), pLock->cnt , getpid());
|
||||
|
||||
|
@ -1420,7 +1413,7 @@ static int unixLock(OsFile *id, int locktype){
|
|||
** sqlite3OsEnterMutex() hasn't been called yet.
|
||||
*/
|
||||
if( pFile->locktype>=locktype ){
|
||||
TRACE3("LOCK %d %s ok (already held)\n", pFile->h,
|
||||
OSTRACE3("LOCK %d %s ok (already held)\n", pFile->h,
|
||||
locktypeName(locktype));
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
@ -1483,7 +1476,7 @@ static int unixLock(OsFile *id, int locktype){
|
|||
lock.l_type = (locktype==SHARED_LOCK?F_RDLCK:F_WRLCK);
|
||||
lock.l_start = PENDING_BYTE;
|
||||
s = fcntl(pFile->h, F_SETLK, &lock);
|
||||
if( s ){
|
||||
if( s==(-1) ){
|
||||
rc = (errno==EINVAL) ? SQLITE_NOLFS : SQLITE_BUSY;
|
||||
goto end_lock;
|
||||
}
|
||||
|
@ -1510,7 +1503,7 @@ static int unixLock(OsFile *id, int locktype){
|
|||
rc = SQLITE_IOERR_UNLOCK; /* This should never happen */
|
||||
goto end_lock;
|
||||
}
|
||||
if( s ){
|
||||
if( s==(-1) ){
|
||||
rc = (errno==EINVAL) ? SQLITE_NOLFS : SQLITE_BUSY;
|
||||
}else{
|
||||
pFile->locktype = SHARED_LOCK;
|
||||
|
@ -1540,7 +1533,7 @@ static int unixLock(OsFile *id, int locktype){
|
|||
assert(0);
|
||||
}
|
||||
s = fcntl(pFile->h, F_SETLK, &lock);
|
||||
if( s ){
|
||||
if( s==(-1) ){
|
||||
rc = (errno==EINVAL) ? SQLITE_NOLFS : SQLITE_BUSY;
|
||||
}
|
||||
}
|
||||
|
@ -1555,7 +1548,7 @@ static int unixLock(OsFile *id, int locktype){
|
|||
|
||||
end_lock:
|
||||
sqlite3OsLeaveMutex();
|
||||
TRACE4("LOCK %d %s %s\n", pFile->h, locktypeName(locktype),
|
||||
OSTRACE4("LOCK %d %s %s\n", pFile->h, locktypeName(locktype),
|
||||
rc==SQLITE_OK ? "ok" : "failed");
|
||||
return rc;
|
||||
}
|
||||
|
@ -1574,7 +1567,7 @@ static int unixUnlock(OsFile *id, int locktype){
|
|||
unixFile *pFile = (unixFile*)id;
|
||||
|
||||
assert( pFile );
|
||||
TRACE7("UNLOCK %d %d was %d(%d,%d) pid=%d\n", pFile->h, locktype,
|
||||
OSTRACE7("UNLOCK %d %d was %d(%d,%d) pid=%d\n", pFile->h, locktype,
|
||||
pFile->locktype, pFile->pLock->locktype, pFile->pLock->cnt, getpid());
|
||||
|
||||
assert( locktype<=SHARED_LOCK );
|
||||
|
@ -1594,7 +1587,7 @@ static int unixUnlock(OsFile *id, int locktype){
|
|||
lock.l_whence = SEEK_SET;
|
||||
lock.l_start = SHARED_FIRST;
|
||||
lock.l_len = SHARED_SIZE;
|
||||
if( fcntl(pFile->h, F_SETLK, &lock)!=0 ){
|
||||
if( fcntl(pFile->h, F_SETLK, &lock)==(-1) ){
|
||||
/* This should never happen */
|
||||
rc = SQLITE_IOERR_RDLOCK;
|
||||
}
|
||||
|
@ -1603,7 +1596,7 @@ static int unixUnlock(OsFile *id, int locktype){
|
|||
lock.l_whence = SEEK_SET;
|
||||
lock.l_start = PENDING_BYTE;
|
||||
lock.l_len = 2L; assert( PENDING_BYTE+1==RESERVED_BYTE );
|
||||
if( fcntl(pFile->h, F_SETLK, &lock)==0 ){
|
||||
if( fcntl(pFile->h, F_SETLK, &lock)!=(-1) ){
|
||||
pLock->locktype = SHARED_LOCK;
|
||||
}else{
|
||||
rc = SQLITE_IOERR_UNLOCK; /* This should never happen */
|
||||
|
@ -1621,7 +1614,7 @@ static int unixUnlock(OsFile *id, int locktype){
|
|||
lock.l_type = F_UNLCK;
|
||||
lock.l_whence = SEEK_SET;
|
||||
lock.l_start = lock.l_len = 0L;
|
||||
if( fcntl(pFile->h, F_SETLK, &lock)==0 ){
|
||||
if( fcntl(pFile->h, F_SETLK, &lock)!=(-1) ){
|
||||
pLock->locktype = NO_LOCK;
|
||||
}else{
|
||||
rc = SQLITE_IOERR_UNLOCK; /* This should never happen */
|
||||
|
@ -1687,7 +1680,7 @@ static int unixClose(OsFile **pId){
|
|||
|
||||
sqlite3OsLeaveMutex();
|
||||
id->isOpen = 0;
|
||||
TRACE2("CLOSE %-3d\n", id->h);
|
||||
OSTRACE2("CLOSE %-3d\n", id->h);
|
||||
OpenCounter(-1);
|
||||
sqlite3ThreadSafeFree(id);
|
||||
*pId = 0;
|
||||
|
@ -1734,11 +1727,11 @@ static int _AFPFSSetLock(const char *path, int fd, unsigned long long offset,
|
|||
pb.offset = offset;
|
||||
pb.length = length;
|
||||
pb.fd = fd;
|
||||
TRACE5("AFPLOCK setting lock %s for %d in range %llx:%llx\n",
|
||||
OSTRACE5("AFPLOCK setting lock %s for %d in range %llx:%llx\n",
|
||||
(setLockFlag?"ON":"OFF"), fd, offset, length);
|
||||
err = fsctl(path, afpfsByteRangeLock2FSCTL, &pb, 0);
|
||||
if ( err==-1 ) {
|
||||
TRACE4("AFPLOCK failed to fsctl() '%s' %d %s\n", path, errno,
|
||||
OSTRACE4("AFPLOCK failed to fsctl() '%s' %d %s\n", path, errno,
|
||||
strerror(errno));
|
||||
return 1; // error
|
||||
} else {
|
||||
|
@ -1778,7 +1771,7 @@ static int afpUnixCheckReservedLock(OsFile *id){
|
|||
_AFPFSSetLock(context->filePath, pFile->h, RESERVED_BYTE, 1, 0);
|
||||
}
|
||||
}
|
||||
TRACE3("TEST WR-LOCK %d %d\n", pFile->h, r);
|
||||
OSTRACE3("TEST WR-LOCK %d %d\n", pFile->h, r);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
@ -1793,14 +1786,14 @@ static int afpUnixLock(OsFile *id, int locktype)
|
|||
int gotPendingLock = 0;
|
||||
|
||||
assert( pFile );
|
||||
TRACE5("LOCK %d %s was %s pid=%d\n", pFile->h,
|
||||
OSTRACE5("LOCK %d %s was %s pid=%d\n", pFile->h,
|
||||
locktypeName(locktype), locktypeName(pFile->locktype), getpid());
|
||||
/* If there is already a lock of this type or more restrictive on the
|
||||
** OsFile, do nothing. Don't use the afp_end_lock: exit path, as
|
||||
** sqlite3OsEnterMutex() hasn't been called yet.
|
||||
*/
|
||||
if( pFile->locktype>=locktype ){
|
||||
TRACE3("LOCK %d %s ok (already held)\n", pFile->h,
|
||||
OSTRACE3("LOCK %d %s ok (already held)\n", pFile->h,
|
||||
locktypeName(locktype));
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
@ -1907,7 +1900,7 @@ static int afpUnixLock(OsFile *id, int locktype)
|
|||
|
||||
afp_end_lock:
|
||||
sqlite3OsLeaveMutex();
|
||||
TRACE4("LOCK %d %s %s\n", pFile->h, locktypeName(locktype),
|
||||
OSTRACE4("LOCK %d %s %s\n", pFile->h, locktypeName(locktype),
|
||||
rc==SQLITE_OK ? "ok" : "failed");
|
||||
return rc;
|
||||
}
|
||||
|
@ -1926,7 +1919,7 @@ static int afpUnixUnlock(OsFile *id, int locktype) {
|
|||
afpLockingContext *context = (afpLockingContext *) pFile->lockingContext;
|
||||
|
||||
assert( pFile );
|
||||
TRACE5("UNLOCK %d %d was %d pid=%d\n", pFile->h, locktype,
|
||||
OSTRACE5("UNLOCK %d %d was %d pid=%d\n", pFile->h, locktype,
|
||||
pFile->locktype, getpid());
|
||||
|
||||
assert( locktype<=SHARED_LOCK );
|
||||
|
@ -2003,7 +1996,7 @@ static int afpUnixClose(OsFile **pId) {
|
|||
id->dirfd = -1;
|
||||
close(id->h);
|
||||
id->isOpen = 0;
|
||||
TRACE2("CLOSE %-3d\n", id->h);
|
||||
OSTRACE2("CLOSE %-3d\n", id->h);
|
||||
OpenCounter(-1);
|
||||
sqlite3ThreadSafeFree(id);
|
||||
*pId = 0;
|
||||
|
@ -2099,7 +2092,7 @@ static int flockUnixClose(OsFile **pId) {
|
|||
close(id->h);
|
||||
sqlite3OsLeaveMutex();
|
||||
id->isOpen = 0;
|
||||
TRACE2("CLOSE %-3d\n", id->h);
|
||||
OSTRACE2("CLOSE %-3d\n", id->h);
|
||||
OpenCounter(-1);
|
||||
sqlite3ThreadSafeFree(id);
|
||||
*pId = 0;
|
||||
|
@ -2218,7 +2211,7 @@ static int dotlockUnixClose(OsFile **pId) {
|
|||
|
||||
sqlite3OsLeaveMutex();
|
||||
id->isOpen = 0;
|
||||
TRACE2("CLOSE %-3d\n", id->h);
|
||||
OSTRACE2("CLOSE %-3d\n", id->h);
|
||||
OpenCounter(-1);
|
||||
sqlite3ThreadSafeFree(id);
|
||||
*pId = 0;
|
||||
|
@ -2260,7 +2253,7 @@ static int nolockUnixClose(OsFile **pId) {
|
|||
|
||||
sqlite3OsLeaveMutex();
|
||||
id->isOpen = 0;
|
||||
TRACE2("CLOSE %-3d\n", id->h);
|
||||
OSTRACE2("CLOSE %-3d\n", id->h);
|
||||
OpenCounter(-1);
|
||||
sqlite3ThreadSafeFree(id);
|
||||
*pId = 0;
|
||||
|
@ -2341,6 +2334,20 @@ static int unixLockState(OsFile *id){
|
|||
return ((unixFile*)id)->locktype;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the sector size in bytes of the underlying block device for
|
||||
** the specified file. This is almost always 512 bytes, but may be
|
||||
** larger for some devices.
|
||||
**
|
||||
** SQLite code assumes this function cannot fail. It also assumes that
|
||||
** if two files are created in the same file-system directory (i.e.
|
||||
** a database and it's journal file) that the sector size will be the
|
||||
** same for both.
|
||||
*/
|
||||
static int unixSectorSize(OsFile *id){
|
||||
return SQLITE_DEFAULT_SECTOR_SIZE;
|
||||
}
|
||||
|
||||
/*
|
||||
** This vector defines all the methods that can operate on an OsFile
|
||||
** for unix.
|
||||
|
@ -2360,6 +2367,7 @@ static const IoMethod sqlite3UnixIoMethod = {
|
|||
unixUnlock,
|
||||
unixLockState,
|
||||
unixCheckReservedLock,
|
||||
unixSectorSize,
|
||||
};
|
||||
|
||||
#ifdef SQLITE_ENABLE_LOCKING_STYLE
|
||||
|
@ -2382,6 +2390,7 @@ static const IoMethod sqlite3AFPLockingUnixIoMethod = {
|
|||
afpUnixUnlock,
|
||||
unixLockState,
|
||||
afpUnixCheckReservedLock,
|
||||
unixSectorSize,
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -2403,6 +2412,7 @@ static const IoMethod sqlite3FlockLockingUnixIoMethod = {
|
|||
flockUnixUnlock,
|
||||
unixLockState,
|
||||
flockUnixCheckReservedLock,
|
||||
unixSectorSize,
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -2424,6 +2434,7 @@ static const IoMethod sqlite3DotlockLockingUnixIoMethod = {
|
|||
dotlockUnixUnlock,
|
||||
unixLockState,
|
||||
dotlockUnixCheckReservedLock,
|
||||
unixSectorSize,
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -2445,6 +2456,7 @@ static const IoMethod sqlite3NolockLockingUnixIoMethod = {
|
|||
nolockUnixUnlock,
|
||||
unixLockState,
|
||||
nolockUnixCheckReservedLock,
|
||||
unixSectorSize,
|
||||
};
|
||||
|
||||
#endif /* SQLITE_ENABLE_LOCKING_STYLE */
|
||||
|
@ -2472,6 +2484,7 @@ static int allocateUnixFile(
|
|||
unixFile f;
|
||||
int rc;
|
||||
|
||||
memset(&f, 0, sizeof(f));
|
||||
lockingStyle = sqlite3DetectLockingStyle(zFilename, h);
|
||||
if ( lockingStyle == posixLockingStyle ) {
|
||||
sqlite3OsEnterMutex();
|
||||
|
@ -2491,9 +2504,6 @@ static int allocateUnixFile(
|
|||
unlink(zFilename);
|
||||
}
|
||||
f.dirfd = -1;
|
||||
f.fullSync = 0;
|
||||
f.locktype = 0;
|
||||
f.offset = 0;
|
||||
f.h = h;
|
||||
SET_THREADID(&f);
|
||||
pNew = sqlite3ThreadSafeMalloc( sizeof(unixFile) );
|
||||
|
@ -2560,6 +2570,7 @@ static int allocateUnixFile(
|
|||
unixFile f;
|
||||
int rc;
|
||||
|
||||
memset(&f, 0, sizeof(f));
|
||||
sqlite3OsEnterMutex();
|
||||
rc = findLockInfo(h, &f.pLock, &f.pOpen);
|
||||
sqlite3OsLeaveMutex();
|
||||
|
@ -2570,11 +2581,8 @@ static int allocateUnixFile(
|
|||
close(h);
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
TRACE3("OPEN %-3d %s\n", h, zFilename);
|
||||
OSTRACE3("OPEN %-3d %s\n", h, zFilename);
|
||||
f.dirfd = -1;
|
||||
f.fullSync = 0;
|
||||
f.locktype = 0;
|
||||
f.offset = 0;
|
||||
f.h = h;
|
||||
SET_THREADID(&f);
|
||||
pNew = sqlite3ThreadSafeMalloc( sizeof(unixFile) );
|
||||
|
@ -2899,8 +2907,7 @@ int sqlite3UnixCurrentTime(double *prNow){
|
|||
*prNow = t/86400.0 + 2440587.5;
|
||||
#else
|
||||
struct timeval sNow;
|
||||
struct timezone sTz; /* Not used */
|
||||
gettimeofday(&sNow, &sTz);
|
||||
gettimeofday(&sNow, 0);
|
||||
*prNow = 2440587.5 + sNow.tv_sec/86400.0 + sNow.tv_usec/86400000000.0;
|
||||
#endif
|
||||
#ifdef SQLITE_TEST
|
||||
|
|
|
@ -596,6 +596,7 @@ int sqlite3WinDelete(const char *zFilename){
|
|||
if( zConverted==0 ){
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
SimulateIOError(return SQLITE_IOERR_DELETE);
|
||||
if( isNT() ){
|
||||
do{
|
||||
rc = DeleteFileW(zConverted);
|
||||
|
@ -612,7 +613,7 @@ int sqlite3WinDelete(const char *zFilename){
|
|||
#endif
|
||||
}
|
||||
sqliteFree(zConverted);
|
||||
TRACE2("DELETE \"%s\"\n", zFilename);
|
||||
OSTRACE2("DELETE \"%s\"\n", zFilename);
|
||||
return rc!=0 ? SQLITE_OK : SQLITE_IOERR;
|
||||
}
|
||||
|
||||
|
@ -738,7 +739,7 @@ int sqlite3WinOpenReadWrite(
|
|||
#if OS_WINCE
|
||||
f.zDeleteOnClose = 0;
|
||||
#endif
|
||||
TRACE3("OPEN R/W %d \"%s\"\n", h, zFilename);
|
||||
OSTRACE3("OPEN R/W %d \"%s\"\n", h, zFilename);
|
||||
return allocateWinFile(&f, pId);
|
||||
}
|
||||
|
||||
|
@ -819,7 +820,7 @@ int sqlite3WinOpenExclusive(const char *zFilename, OsFile **pId, int delFlag){
|
|||
return SQLITE_CANTOPEN;
|
||||
}
|
||||
f.h = h;
|
||||
TRACE3("OPEN EX %d \"%s\"\n", h, zFilename);
|
||||
OSTRACE3("OPEN EX %d \"%s\"\n", h, zFilename);
|
||||
return allocateWinFile(&f, pId);
|
||||
}
|
||||
|
||||
|
@ -870,7 +871,7 @@ int sqlite3WinOpenReadOnly(const char *zFilename, OsFile **pId){
|
|||
f.zDeleteOnClose = 0;
|
||||
f.hMutex = NULL;
|
||||
#endif
|
||||
TRACE3("OPEN RO %d \"%s\"\n", h, zFilename);
|
||||
OSTRACE3("OPEN RO %d \"%s\"\n", h, zFilename);
|
||||
return allocateWinFile(&f, pId);
|
||||
}
|
||||
|
||||
|
@ -897,13 +898,6 @@ static int winOpenDirectory(
|
|||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** If the following global variable points to a string which is the
|
||||
** name of a directory, then that directory will be used to store
|
||||
** temporary files.
|
||||
*/
|
||||
char *sqlite3_temp_directory = 0;
|
||||
|
||||
/*
|
||||
** Create a temporary file name in zBuf. zBuf must be big enough to
|
||||
** hold at least SQLITE_TEMPNAME_SIZE characters.
|
||||
|
@ -955,7 +949,7 @@ int sqlite3WinTempFileName(char *zBuf){
|
|||
zBuf[j] = 0;
|
||||
if( !sqlite3OsFileExists(zBuf) ) break;
|
||||
}
|
||||
TRACE2("TEMP FILENAME: %s\n", zBuf);
|
||||
OSTRACE2("TEMP FILENAME: %s\n", zBuf);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
|
@ -975,7 +969,7 @@ static int winClose(OsFile **pId){
|
|||
int rc = 1;
|
||||
if( pId && (pFile = (winFile*)*pId)!=0 ){
|
||||
int rc, cnt = 0;
|
||||
TRACE2("CLOSE %d\n", pFile->h);
|
||||
OSTRACE2("CLOSE %d\n", pFile->h);
|
||||
do{
|
||||
rc = CloseHandle(pFile->h);
|
||||
}while( rc==0 && cnt++ < MX_CLOSE_ATTEMPT && (Sleep(100), 1) );
|
||||
|
@ -1002,7 +996,7 @@ static int winRead(OsFile *id, void *pBuf, int amt){
|
|||
DWORD got;
|
||||
assert( id!=0 );
|
||||
SimulateIOError(return SQLITE_IOERR_READ);
|
||||
TRACE3("READ %d lock=%d\n", ((winFile*)id)->h, ((winFile*)id)->locktype);
|
||||
OSTRACE3("READ %d lock=%d\n", ((winFile*)id)->h, ((winFile*)id)->locktype);
|
||||
if( !ReadFile(((winFile*)id)->h, pBuf, amt, &got, 0) ){
|
||||
return SQLITE_IOERR_READ;
|
||||
}
|
||||
|
@ -1024,7 +1018,7 @@ static int winWrite(OsFile *id, const void *pBuf, int amt){
|
|||
assert( id!=0 );
|
||||
SimulateIOError(return SQLITE_IOERR_READ);
|
||||
SimulateDiskfullError(return SQLITE_FULL);
|
||||
TRACE3("WRITE %d lock=%d\n", ((winFile*)id)->h, ((winFile*)id)->locktype);
|
||||
OSTRACE3("WRITE %d lock=%d\n", ((winFile*)id)->h, ((winFile*)id)->locktype);
|
||||
assert( amt>0 );
|
||||
while( amt>0 && (rc = WriteFile(((winFile*)id)->h, pBuf, amt, &wrote, 0))!=0
|
||||
&& wrote>0 ){
|
||||
|
@ -1055,9 +1049,8 @@ static int winSeek(OsFile *id, i64 offset){
|
|||
#ifdef SQLITE_TEST
|
||||
if( offset ) SimulateDiskfullError(return SQLITE_FULL);
|
||||
#endif
|
||||
SEEK(offset/1024 + 1);
|
||||
rc = SetFilePointer(((winFile*)id)->h, lowerBits, &upperBits, FILE_BEGIN);
|
||||
TRACE3("SEEK %d %lld\n", ((winFile*)id)->h, offset);
|
||||
OSTRACE3("SEEK %d %lld\n", ((winFile*)id)->h, offset);
|
||||
if( rc==INVALID_SET_FILE_POINTER && GetLastError()!=NO_ERROR ){
|
||||
return SQLITE_FULL;
|
||||
}
|
||||
|
@ -1069,7 +1062,7 @@ static int winSeek(OsFile *id, i64 offset){
|
|||
*/
|
||||
static int winSync(OsFile *id, int dataOnly){
|
||||
assert( id!=0 );
|
||||
TRACE3("SYNC %d lock=%d\n", ((winFile*)id)->h, ((winFile*)id)->locktype);
|
||||
OSTRACE3("SYNC %d lock=%d\n", ((winFile*)id)->h, ((winFile*)id)->locktype);
|
||||
if( FlushFileBuffers(((winFile*)id)->h) ){
|
||||
return SQLITE_OK;
|
||||
}else{
|
||||
|
@ -1092,7 +1085,7 @@ int sqlite3WinSyncDirectory(const char *zDirname){
|
|||
static int winTruncate(OsFile *id, i64 nByte){
|
||||
LONG upperBits = nByte>>32;
|
||||
assert( id!=0 );
|
||||
TRACE3("TRUNCATE %d %lld\n", ((winFile*)id)->h, nByte);
|
||||
OSTRACE3("TRUNCATE %d %lld\n", ((winFile*)id)->h, nByte);
|
||||
SimulateIOError(return SQLITE_IOERR_TRUNCATE);
|
||||
SetFilePointer(((winFile*)id)->h, nByte, &upperBits, FILE_BEGIN);
|
||||
SetEndOfFile(((winFile*)id)->h);
|
||||
|
@ -1220,7 +1213,7 @@ static int winLock(OsFile *id, int locktype){
|
|||
winFile *pFile = (winFile*)id;
|
||||
|
||||
assert( pFile!=0 );
|
||||
TRACE5("LOCK %d %d was %d(%d)\n",
|
||||
OSTRACE5("LOCK %d %d was %d(%d)\n",
|
||||
pFile->h, locktype, pFile->locktype, pFile->sharedLockByte);
|
||||
|
||||
/* If there is already a lock of this type or more restrictive on the
|
||||
|
@ -1250,7 +1243,7 @@ static int winLock(OsFile *id, int locktype){
|
|||
/* Try 3 times to get the pending lock. The pending lock might be
|
||||
** held by another reader process who will release it momentarily.
|
||||
*/
|
||||
TRACE2("could not get a PENDING lock. cnt=%d\n", cnt);
|
||||
OSTRACE2("could not get a PENDING lock. cnt=%d\n", cnt);
|
||||
Sleep(1);
|
||||
}
|
||||
gotPendingLock = res;
|
||||
|
@ -1288,12 +1281,12 @@ static int winLock(OsFile *id, int locktype){
|
|||
if( locktype==EXCLUSIVE_LOCK && res ){
|
||||
assert( pFile->locktype>=SHARED_LOCK );
|
||||
res = unlockReadLock(pFile);
|
||||
TRACE2("unreadlock = %d\n", res);
|
||||
OSTRACE2("unreadlock = %d\n", res);
|
||||
res = LockFile(pFile->h, SHARED_FIRST, 0, SHARED_SIZE, 0);
|
||||
if( res ){
|
||||
newLocktype = EXCLUSIVE_LOCK;
|
||||
}else{
|
||||
TRACE2("error-code = %d\n", GetLastError());
|
||||
OSTRACE2("error-code = %d\n", GetLastError());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1310,7 +1303,7 @@ static int winLock(OsFile *id, int locktype){
|
|||
if( res ){
|
||||
rc = SQLITE_OK;
|
||||
}else{
|
||||
TRACE4("LOCK FAILED %d trying for %d but got %d\n", pFile->h,
|
||||
OSTRACE4("LOCK FAILED %d trying for %d but got %d\n", pFile->h,
|
||||
locktype, newLocktype);
|
||||
rc = SQLITE_BUSY;
|
||||
}
|
||||
|
@ -1329,14 +1322,14 @@ static int winCheckReservedLock(OsFile *id){
|
|||
assert( pFile!=0 );
|
||||
if( pFile->locktype>=RESERVED_LOCK ){
|
||||
rc = 1;
|
||||
TRACE3("TEST WR-LOCK %d %d (local)\n", pFile->h, rc);
|
||||
OSTRACE3("TEST WR-LOCK %d %d (local)\n", pFile->h, rc);
|
||||
}else{
|
||||
rc = LockFile(pFile->h, RESERVED_BYTE, 0, 1, 0);
|
||||
if( rc ){
|
||||
UnlockFile(pFile->h, RESERVED_BYTE, 0, 1, 0);
|
||||
}
|
||||
rc = !rc;
|
||||
TRACE3("TEST WR-LOCK %d %d (remote)\n", pFile->h, rc);
|
||||
OSTRACE3("TEST WR-LOCK %d %d (remote)\n", pFile->h, rc);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
@ -1358,7 +1351,7 @@ static int winUnlock(OsFile *id, int locktype){
|
|||
winFile *pFile = (winFile*)id;
|
||||
assert( pFile!=0 );
|
||||
assert( locktype<=SHARED_LOCK );
|
||||
TRACE5("UNLOCK %d to %d was %d(%d)\n", pFile->h, locktype,
|
||||
OSTRACE5("UNLOCK %d to %d was %d(%d)\n", pFile->h, locktype,
|
||||
pFile->locktype, pFile->sharedLockByte);
|
||||
type = pFile->locktype;
|
||||
if( type>=EXCLUSIVE_LOCK ){
|
||||
|
@ -1454,6 +1447,20 @@ static int winLockState(OsFile *id){
|
|||
return ((winFile*)id)->locktype;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the sector size in bytes of the underlying block device for
|
||||
** the specified file. This is almost always 512 bytes, but may be
|
||||
** larger for some devices.
|
||||
**
|
||||
** SQLite code assumes this function cannot fail. It also assumes that
|
||||
** if two files are created in the same file-system directory (i.e.
|
||||
** a database and it's journal file) that the sector size will be the
|
||||
** same for both.
|
||||
*/
|
||||
static int winSectorSize(OsFile *id){
|
||||
return SQLITE_DEFAULT_SECTOR_SIZE;
|
||||
}
|
||||
|
||||
/*
|
||||
** This vector defines all the methods that can operate on an OsFile
|
||||
** for win32.
|
||||
|
@ -1473,6 +1480,7 @@ static const IoMethod sqlite3WinIoMethod = {
|
|||
winUnlock,
|
||||
winLockState,
|
||||
winCheckReservedLock,
|
||||
winSectorSize,
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -57,67 +57,91 @@ typedef unsigned int Pgno;
|
|||
typedef struct Pager Pager;
|
||||
|
||||
/*
|
||||
** Allowed values for the flags parameter to sqlite3pager_open().
|
||||
** Handle type for pages.
|
||||
*/
|
||||
typedef struct PgHdr DbPage;
|
||||
|
||||
/*
|
||||
** Allowed values for the flags parameter to sqlite3PagerOpen().
|
||||
**
|
||||
** NOTE: This values must match the corresponding BTREE_ values in btree.h.
|
||||
*/
|
||||
#define PAGER_OMIT_JOURNAL 0x0001 /* Do not use a rollback journal */
|
||||
#define PAGER_NO_READLOCK 0x0002 /* Omit readlocks on readonly files */
|
||||
|
||||
/*
|
||||
** Valid values for the second argument to sqlite3PagerLockingMode().
|
||||
*/
|
||||
#define PAGER_LOCKINGMODE_QUERY -1
|
||||
#define PAGER_LOCKINGMODE_NORMAL 0
|
||||
#define PAGER_LOCKINGMODE_EXCLUSIVE 1
|
||||
|
||||
/*
|
||||
** See source code comments for a detailed description of the following
|
||||
** routines:
|
||||
*/
|
||||
int sqlite3pager_open(Pager **ppPager, const char *zFilename,
|
||||
int sqlite3PagerOpen(Pager **ppPager, const char *zFilename,
|
||||
int nExtra, int flags);
|
||||
void sqlite3pager_set_busyhandler(Pager*, BusyHandler *pBusyHandler);
|
||||
void sqlite3pager_set_destructor(Pager*, void(*)(void*,int));
|
||||
void sqlite3pager_set_reiniter(Pager*, void(*)(void*,int));
|
||||
int sqlite3pager_set_pagesize(Pager*, int);
|
||||
int sqlite3pager_read_fileheader(Pager*, int, unsigned char*);
|
||||
void sqlite3pager_set_cachesize(Pager*, int);
|
||||
int sqlite3pager_close(Pager *pPager);
|
||||
int sqlite3pager_get(Pager *pPager, Pgno pgno, void **ppPage);
|
||||
void *sqlite3pager_lookup(Pager *pPager, Pgno pgno);
|
||||
int sqlite3pager_ref(void*);
|
||||
int sqlite3pager_unref(void*);
|
||||
Pgno sqlite3pager_pagenumber(void*);
|
||||
int sqlite3pager_write(void*);
|
||||
int sqlite3pager_iswriteable(void*);
|
||||
int sqlite3pager_overwrite(Pager *pPager, Pgno pgno, void*);
|
||||
int sqlite3pager_pagecount(Pager*);
|
||||
int sqlite3pager_truncate(Pager*,Pgno);
|
||||
int sqlite3pager_begin(void*, int exFlag);
|
||||
int sqlite3pager_commit(Pager*);
|
||||
int sqlite3pager_sync(Pager*,const char *zMaster, Pgno);
|
||||
int sqlite3pager_rollback(Pager*);
|
||||
int sqlite3pager_isreadonly(Pager*);
|
||||
int sqlite3pager_stmt_begin(Pager*);
|
||||
int sqlite3pager_stmt_commit(Pager*);
|
||||
int sqlite3pager_stmt_rollback(Pager*);
|
||||
void sqlite3pager_dont_rollback(void*);
|
||||
void sqlite3pager_dont_write(Pager*, Pgno);
|
||||
int sqlite3pager_refcount(Pager*);
|
||||
int *sqlite3pager_stats(Pager*);
|
||||
void sqlite3pager_set_safety_level(Pager*,int,int);
|
||||
const char *sqlite3pager_filename(Pager*);
|
||||
const char *sqlite3pager_dirname(Pager*);
|
||||
const char *sqlite3pager_journalname(Pager*);
|
||||
int sqlite3pager_nosync(Pager*);
|
||||
int sqlite3pager_rename(Pager*, const char *zNewName);
|
||||
void sqlite3pager_set_codec(Pager*,void*(*)(void*,void*,Pgno,int),void*);
|
||||
int sqlite3pager_movepage(Pager*,void*,Pgno);
|
||||
int sqlite3pager_reset(Pager*);
|
||||
int sqlite3pager_release_memory(int);
|
||||
void sqlite3PagerSetBusyhandler(Pager*, BusyHandler *pBusyHandler);
|
||||
void sqlite3PagerSetDestructor(Pager*, void(*)(DbPage*,int));
|
||||
void sqlite3PagerSetReiniter(Pager*, void(*)(DbPage*,int));
|
||||
int sqlite3PagerSetPagesize(Pager*, int);
|
||||
int sqlite3PagerReadFileheader(Pager*, int, unsigned char*);
|
||||
void sqlite3PagerSetCachesize(Pager*, int);
|
||||
int sqlite3PagerClose(Pager *pPager);
|
||||
int sqlite3PagerAcquire(Pager *pPager, Pgno pgno, DbPage **ppPage, int clrFlag);
|
||||
#define sqlite3PagerGet(A,B,C) sqlite3PagerAcquire(A,B,C,0)
|
||||
DbPage *sqlite3PagerLookup(Pager *pPager, Pgno pgno);
|
||||
int sqlite3PagerRef(DbPage*);
|
||||
int sqlite3PagerUnref(DbPage*);
|
||||
Pgno sqlite3PagerPagenumber(DbPage*);
|
||||
int sqlite3PagerWrite(DbPage*);
|
||||
int sqlite3PagerIswriteable(DbPage*);
|
||||
int sqlite3PagerOverwrite(Pager *pPager, Pgno pgno, void*);
|
||||
int sqlite3PagerPagecount(Pager*);
|
||||
int sqlite3PagerTruncate(Pager*,Pgno);
|
||||
int sqlite3PagerBegin(DbPage*, int exFlag);
|
||||
int sqlite3PagerCommitPhaseOne(Pager*,const char *zMaster, Pgno);
|
||||
int sqlite3PagerCommitPhaseTwo(Pager*);
|
||||
int sqlite3PagerRollback(Pager*);
|
||||
int sqlite3PagerIsreadonly(Pager*);
|
||||
int sqlite3PagerStmtBegin(Pager*);
|
||||
int sqlite3PagerStmtCommit(Pager*);
|
||||
int sqlite3PagerStmtRollback(Pager*);
|
||||
void sqlite3PagerDontRollback(DbPage*);
|
||||
void sqlite3PagerDontWrite(Pager*, Pgno);
|
||||
int sqlite3PagerRefcount(Pager*);
|
||||
int *sqlite3PagerStats(Pager*);
|
||||
void sqlite3PagerSetSafetyLevel(Pager*,int,int);
|
||||
const char *sqlite3PagerFilename(Pager*);
|
||||
const char *sqlite3PagerDirname(Pager*);
|
||||
const char *sqlite3PagerJournalname(Pager*);
|
||||
int sqlite3PagerNosync(Pager*);
|
||||
int sqlite3PagerRename(Pager*, const char *zNewName);
|
||||
void sqlite3PagerSetCodec(Pager*,void*(*)(void*,void*,Pgno,int),void*);
|
||||
int sqlite3PagerMovepage(Pager*,DbPage*,Pgno);
|
||||
int sqlite3PagerReset(Pager*);
|
||||
int sqlite3PagerReleaseMemory(int);
|
||||
|
||||
void *sqlite3PagerGetData(DbPage *);
|
||||
void *sqlite3PagerGetExtra(DbPage *);
|
||||
int sqlite3PagerLockingMode(Pager *, int);
|
||||
|
||||
#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
|
||||
int sqlite3pager_lockstate(Pager*);
|
||||
int sqlite3PagerLockstate(Pager*);
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_TEST
|
||||
void sqlite3pager_refdump(Pager*);
|
||||
void sqlite3PagerRefdump(Pager*);
|
||||
int pager3_refinfo_enable;
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_TEST
|
||||
void disable_simulated_io_errors(void);
|
||||
void enable_simulated_io_errors(void);
|
||||
#else
|
||||
# define disable_simulated_io_errors()
|
||||
# define enable_simulated_io_errors()
|
||||
#endif
|
||||
|
||||
#endif /* _PAGER_H_ */
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -49,105 +49,104 @@
|
|||
#define TK_REPLACE 49
|
||||
#define TK_RESTRICT 50
|
||||
#define TK_ROW 51
|
||||
#define TK_STATEMENT 52
|
||||
#define TK_TRIGGER 53
|
||||
#define TK_VACUUM 54
|
||||
#define TK_VIEW 55
|
||||
#define TK_VIRTUAL 56
|
||||
#define TK_REINDEX 57
|
||||
#define TK_RENAME 58
|
||||
#define TK_CTIME_KW 59
|
||||
#define TK_ANY 60
|
||||
#define TK_OR 61
|
||||
#define TK_AND 62
|
||||
#define TK_IS 63
|
||||
#define TK_BETWEEN 64
|
||||
#define TK_IN 65
|
||||
#define TK_ISNULL 66
|
||||
#define TK_NOTNULL 67
|
||||
#define TK_NE 68
|
||||
#define TK_EQ 69
|
||||
#define TK_GT 70
|
||||
#define TK_LE 71
|
||||
#define TK_LT 72
|
||||
#define TK_GE 73
|
||||
#define TK_ESCAPE 74
|
||||
#define TK_BITAND 75
|
||||
#define TK_BITOR 76
|
||||
#define TK_LSHIFT 77
|
||||
#define TK_RSHIFT 78
|
||||
#define TK_PLUS 79
|
||||
#define TK_MINUS 80
|
||||
#define TK_STAR 81
|
||||
#define TK_SLASH 82
|
||||
#define TK_REM 83
|
||||
#define TK_CONCAT 84
|
||||
#define TK_COLLATE 85
|
||||
#define TK_UMINUS 86
|
||||
#define TK_UPLUS 87
|
||||
#define TK_BITNOT 88
|
||||
#define TK_STRING 89
|
||||
#define TK_JOIN_KW 90
|
||||
#define TK_CONSTRAINT 91
|
||||
#define TK_DEFAULT 92
|
||||
#define TK_NULL 93
|
||||
#define TK_PRIMARY 94
|
||||
#define TK_UNIQUE 95
|
||||
#define TK_CHECK 96
|
||||
#define TK_REFERENCES 97
|
||||
#define TK_AUTOINCR 98
|
||||
#define TK_ON 99
|
||||
#define TK_DELETE 100
|
||||
#define TK_UPDATE 101
|
||||
#define TK_INSERT 102
|
||||
#define TK_SET 103
|
||||
#define TK_DEFERRABLE 104
|
||||
#define TK_FOREIGN 105
|
||||
#define TK_DROP 106
|
||||
#define TK_UNION 107
|
||||
#define TK_ALL 108
|
||||
#define TK_EXCEPT 109
|
||||
#define TK_INTERSECT 110
|
||||
#define TK_SELECT 111
|
||||
#define TK_DISTINCT 112
|
||||
#define TK_DOT 113
|
||||
#define TK_FROM 114
|
||||
#define TK_JOIN 115
|
||||
#define TK_USING 116
|
||||
#define TK_ORDER 117
|
||||
#define TK_BY 118
|
||||
#define TK_GROUP 119
|
||||
#define TK_HAVING 120
|
||||
#define TK_LIMIT 121
|
||||
#define TK_WHERE 122
|
||||
#define TK_INTO 123
|
||||
#define TK_VALUES 124
|
||||
#define TK_INTEGER 125
|
||||
#define TK_FLOAT 126
|
||||
#define TK_BLOB 127
|
||||
#define TK_REGISTER 128
|
||||
#define TK_VARIABLE 129
|
||||
#define TK_CASE 130
|
||||
#define TK_WHEN 131
|
||||
#define TK_THEN 132
|
||||
#define TK_ELSE 133
|
||||
#define TK_INDEX 134
|
||||
#define TK_ALTER 135
|
||||
#define TK_TO 136
|
||||
#define TK_ADD 137
|
||||
#define TK_COLUMNKW 138
|
||||
#define TK_TO_TEXT 139
|
||||
#define TK_TO_BLOB 140
|
||||
#define TK_TO_NUMERIC 141
|
||||
#define TK_TO_INT 142
|
||||
#define TK_TO_REAL 143
|
||||
#define TK_END_OF_FILE 144
|
||||
#define TK_ILLEGAL 145
|
||||
#define TK_SPACE 146
|
||||
#define TK_UNCLOSED_STRING 147
|
||||
#define TK_COMMENT 148
|
||||
#define TK_FUNCTION 149
|
||||
#define TK_COLUMN 150
|
||||
#define TK_AGG_FUNCTION 151
|
||||
#define TK_AGG_COLUMN 152
|
||||
#define TK_CONST_FUNC 153
|
||||
#define TK_TRIGGER 52
|
||||
#define TK_VACUUM 53
|
||||
#define TK_VIEW 54
|
||||
#define TK_VIRTUAL 55
|
||||
#define TK_REINDEX 56
|
||||
#define TK_RENAME 57
|
||||
#define TK_CTIME_KW 58
|
||||
#define TK_ANY 59
|
||||
#define TK_OR 60
|
||||
#define TK_AND 61
|
||||
#define TK_IS 62
|
||||
#define TK_BETWEEN 63
|
||||
#define TK_IN 64
|
||||
#define TK_ISNULL 65
|
||||
#define TK_NOTNULL 66
|
||||
#define TK_NE 67
|
||||
#define TK_EQ 68
|
||||
#define TK_GT 69
|
||||
#define TK_LE 70
|
||||
#define TK_LT 71
|
||||
#define TK_GE 72
|
||||
#define TK_ESCAPE 73
|
||||
#define TK_BITAND 74
|
||||
#define TK_BITOR 75
|
||||
#define TK_LSHIFT 76
|
||||
#define TK_RSHIFT 77
|
||||
#define TK_PLUS 78
|
||||
#define TK_MINUS 79
|
||||
#define TK_STAR 80
|
||||
#define TK_SLASH 81
|
||||
#define TK_REM 82
|
||||
#define TK_CONCAT 83
|
||||
#define TK_COLLATE 84
|
||||
#define TK_UMINUS 85
|
||||
#define TK_UPLUS 86
|
||||
#define TK_BITNOT 87
|
||||
#define TK_STRING 88
|
||||
#define TK_JOIN_KW 89
|
||||
#define TK_CONSTRAINT 90
|
||||
#define TK_DEFAULT 91
|
||||
#define TK_NULL 92
|
||||
#define TK_PRIMARY 93
|
||||
#define TK_UNIQUE 94
|
||||
#define TK_CHECK 95
|
||||
#define TK_REFERENCES 96
|
||||
#define TK_AUTOINCR 97
|
||||
#define TK_ON 98
|
||||
#define TK_DELETE 99
|
||||
#define TK_UPDATE 100
|
||||
#define TK_INSERT 101
|
||||
#define TK_SET 102
|
||||
#define TK_DEFERRABLE 103
|
||||
#define TK_FOREIGN 104
|
||||
#define TK_DROP 105
|
||||
#define TK_UNION 106
|
||||
#define TK_ALL 107
|
||||
#define TK_EXCEPT 108
|
||||
#define TK_INTERSECT 109
|
||||
#define TK_SELECT 110
|
||||
#define TK_DISTINCT 111
|
||||
#define TK_DOT 112
|
||||
#define TK_FROM 113
|
||||
#define TK_JOIN 114
|
||||
#define TK_USING 115
|
||||
#define TK_ORDER 116
|
||||
#define TK_BY 117
|
||||
#define TK_GROUP 118
|
||||
#define TK_HAVING 119
|
||||
#define TK_LIMIT 120
|
||||
#define TK_WHERE 121
|
||||
#define TK_INTO 122
|
||||
#define TK_VALUES 123
|
||||
#define TK_INTEGER 124
|
||||
#define TK_FLOAT 125
|
||||
#define TK_BLOB 126
|
||||
#define TK_REGISTER 127
|
||||
#define TK_VARIABLE 128
|
||||
#define TK_CASE 129
|
||||
#define TK_WHEN 130
|
||||
#define TK_THEN 131
|
||||
#define TK_ELSE 132
|
||||
#define TK_INDEX 133
|
||||
#define TK_ALTER 134
|
||||
#define TK_TO 135
|
||||
#define TK_ADD 136
|
||||
#define TK_COLUMNKW 137
|
||||
#define TK_TO_TEXT 138
|
||||
#define TK_TO_BLOB 139
|
||||
#define TK_TO_NUMERIC 140
|
||||
#define TK_TO_INT 141
|
||||
#define TK_TO_REAL 142
|
||||
#define TK_END_OF_FILE 143
|
||||
#define TK_ILLEGAL 144
|
||||
#define TK_SPACE 145
|
||||
#define TK_UNCLOSED_STRING 146
|
||||
#define TK_COMMENT 147
|
||||
#define TK_FUNCTION 148
|
||||
#define TK_COLUMN 149
|
||||
#define TK_AGG_FUNCTION 150
|
||||
#define TK_AGG_COLUMN 151
|
||||
#define TK_CONST_FUNC 152
|
||||
|
|
|
@ -175,7 +175,7 @@ id(A) ::= ID(X). {A = X;}
|
|||
ABORT AFTER ANALYZE ASC ATTACH BEFORE BEGIN CASCADE CAST CONFLICT
|
||||
DATABASE DEFERRED DESC DETACH EACH END EXCLUSIVE EXPLAIN FAIL FOR
|
||||
IGNORE IMMEDIATE INITIALLY INSTEAD LIKE_KW MATCH PLAN QUERY KEY
|
||||
OF OFFSET PRAGMA RAISE REPLACE RESTRICT ROW STATEMENT
|
||||
OF OFFSET PRAGMA RAISE REPLACE RESTRICT ROW
|
||||
TEMP TRIGGER VACUUM VIEW VIRTUAL
|
||||
%ifdef SQLITE_OMIT_COMPOUND_SELECT
|
||||
EXCEPT INTERSECT UNION
|
||||
|
@ -239,9 +239,8 @@ typetoken(A) ::= typename(X) LP signed COMMA signed RP(Y). {
|
|||
%type typename {Token}
|
||||
typename(A) ::= ids(X). {A = X;}
|
||||
typename(A) ::= typename(X) ids(Y). {A.z=X.z; A.n=Y.n+(Y.z-X.z);}
|
||||
%type signed {int}
|
||||
signed(A) ::= plus_num(X). { A = atoi((char*)X.z); }
|
||||
signed(A) ::= minus_num(X). { A = -atoi((char*)X.z); }
|
||||
signed ::= plus_num.
|
||||
signed ::= minus_num.
|
||||
|
||||
// "carglist" is a list of additional constraints that come after the
|
||||
// column name and column type in a CREATE TABLE statement.
|
||||
|
@ -543,10 +542,18 @@ having_opt(A) ::= . {A = 0;}
|
|||
having_opt(A) ::= HAVING expr(X). {A = X;}
|
||||
|
||||
%type limit_opt {struct LimitVal}
|
||||
%destructor limit_opt {
|
||||
sqlite3ExprDelete($$.pLimit);
|
||||
sqlite3ExprDelete($$.pOffset);
|
||||
}
|
||||
|
||||
// The destructor for limit_opt will never fire in the current grammar.
|
||||
// The limit_opt non-terminal only occurs at the end of a single production
|
||||
// rule for SELECT statements. As soon as the rule that create the
|
||||
// limit_opt non-terminal reduces, the SELECT statement rule will also
|
||||
// reduce. So there is never a limit_opt non-terminal on the stack
|
||||
// except as a transient. So there is never anything to destroy.
|
||||
//
|
||||
//%destructor limit_opt {
|
||||
// sqlite3ExprDelete($$.pLimit);
|
||||
// sqlite3ExprDelete($$.pOffset);
|
||||
//}
|
||||
limit_opt(A) ::= . {A.pLimit = 0; A.pOffset = 0;}
|
||||
limit_opt(A) ::= LIMIT expr(X). {A.pLimit = X; A.pOffset = 0;}
|
||||
limit_opt(A) ::= LIMIT expr(X) OFFSET expr(Y).
|
||||
|
@ -890,8 +897,10 @@ cmd ::= DROP INDEX ifexists(E) fullname(X). {sqlite3DropIndex(pParse, X, E);}
|
|||
///////////////////////////// The VACUUM command /////////////////////////////
|
||||
//
|
||||
%ifndef SQLITE_OMIT_VACUUM
|
||||
%ifndef SQLITE_OMIT_ATTACH
|
||||
cmd ::= VACUUM. {sqlite3Vacuum(pParse);}
|
||||
cmd ::= VACUUM nm. {sqlite3Vacuum(pParse);}
|
||||
%endif SQLITE_OMIT_ATTACH
|
||||
%endif SQLITE_OMIT_VACUUM
|
||||
|
||||
///////////////////////////// The PRAGMA command /////////////////////////////
|
||||
|
@ -926,8 +935,8 @@ cmd ::= CREATE trigger_decl(A) BEGIN trigger_cmd_list(S) END(Z). {
|
|||
|
||||
trigger_decl(A) ::= temp(T) TRIGGER ifnotexists(NOERR) nm(B) dbnm(Z)
|
||||
trigger_time(C) trigger_event(D)
|
||||
ON fullname(E) foreach_clause(F) when_clause(G). {
|
||||
sqlite3BeginTrigger(pParse, &B, &Z, C, D.a, D.b, E, F, G, T, NOERR);
|
||||
ON fullname(E) foreach_clause when_clause(G). {
|
||||
sqlite3BeginTrigger(pParse, &B, &Z, C, D.a, D.b, E, G, T, NOERR);
|
||||
A = (Z.n==0?B:Z);
|
||||
}
|
||||
|
||||
|
@ -943,10 +952,8 @@ trigger_event(A) ::= DELETE|INSERT(OP). {A.a = @OP; A.b = 0;}
|
|||
trigger_event(A) ::= UPDATE(OP). {A.a = @OP; A.b = 0;}
|
||||
trigger_event(A) ::= UPDATE OF inscollist(X). {A.a = TK_UPDATE; A.b = X;}
|
||||
|
||||
%type foreach_clause {int}
|
||||
foreach_clause(A) ::= . { A = TK_ROW; }
|
||||
foreach_clause(A) ::= FOR EACH ROW. { A = TK_ROW; }
|
||||
foreach_clause(A) ::= FOR EACH STATEMENT. { A = TK_STATEMENT; }
|
||||
foreach_clause ::= .
|
||||
foreach_clause ::= FOR EACH ROW.
|
||||
|
||||
%type when_clause {Expr*}
|
||||
%destructor when_clause {sqlite3ExprDelete($$);}
|
||||
|
@ -1018,9 +1025,14 @@ cmd ::= DROP TRIGGER ifexists(NOERR) fullname(X). {
|
|||
%endif !SQLITE_OMIT_TRIGGER
|
||||
|
||||
//////////////////////// ATTACH DATABASE file AS name /////////////////////////
|
||||
%ifndef SQLITE_OMIT_ATTACH
|
||||
cmd ::= ATTACH database_kw_opt expr(F) AS expr(D) key_opt(K). {
|
||||
sqlite3Attach(pParse, F, D, K);
|
||||
}
|
||||
cmd ::= DETACH database_kw_opt expr(D). {
|
||||
sqlite3Detach(pParse, D);
|
||||
}
|
||||
|
||||
%type key_opt {Expr *}
|
||||
%destructor key_opt {sqlite3ExprDelete($$);}
|
||||
key_opt(A) ::= . { A = 0; }
|
||||
|
@ -1028,11 +1040,7 @@ key_opt(A) ::= KEY expr(X). { A = X; }
|
|||
|
||||
database_kw_opt ::= DATABASE.
|
||||
database_kw_opt ::= .
|
||||
|
||||
//////////////////////// DETACH DATABASE name /////////////////////////////////
|
||||
cmd ::= DETACH database_kw_opt expr(D). {
|
||||
sqlite3Detach(pParse, D);
|
||||
}
|
||||
%endif SQLITE_OMIT_ATTACH
|
||||
|
||||
////////////////////////// REINDEX collation //////////////////////////////////
|
||||
%ifndef SQLITE_OMIT_REINDEX
|
||||
|
|
|
@ -62,6 +62,17 @@ static int getBoolean(const char *z){
|
|||
return getSafetyLevel(z)&1;
|
||||
}
|
||||
|
||||
/*
|
||||
** Interpret the given string as a locking mode value.
|
||||
*/
|
||||
static int getLockingMode(const char *z){
|
||||
if( z ){
|
||||
if( 0==sqlite3StrICmp(z, "exclusive") ) return PAGER_LOCKINGMODE_EXCLUSIVE;
|
||||
if( 0==sqlite3StrICmp(z, "normal") ) return PAGER_LOCKINGMODE_NORMAL;
|
||||
}
|
||||
return PAGER_LOCKINGMODE_QUERY;
|
||||
}
|
||||
|
||||
#ifndef SQLITE_OMIT_PAGER_PRAGMAS
|
||||
/*
|
||||
** Interpret the given string as a temp db location. Return 1 for file
|
||||
|
@ -89,7 +100,7 @@ static int getTempStore(const char *z){
|
|||
static int invalidateTempStorage(Parse *pParse){
|
||||
sqlite3 *db = pParse->db;
|
||||
if( db->aDb[1].pBt!=0 ){
|
||||
if( db->flags & SQLITE_InTrans ){
|
||||
if( !db->autoCommit ){
|
||||
sqlite3ErrorMsg(pParse, "temporary storage cannot be changed "
|
||||
"from within a transaction");
|
||||
return SQLITE_ERROR;
|
||||
|
@ -157,7 +168,7 @@ static int flagPragma(Parse *pParse, const char *zLeft, const char *zRight){
|
|||
{ "ignore_check_constraints", SQLITE_IgnoreChecks },
|
||||
#endif
|
||||
/* The following is VERY experimental */
|
||||
{ "writable_schema", SQLITE_WriteSchema },
|
||||
{ "writable_schema", SQLITE_WriteSchema|SQLITE_RecoveryMode },
|
||||
{ "omit_readlock", SQLITE_NoReadlock },
|
||||
|
||||
/* TODO: Maybe it shouldn't be possible to change the ReadUncommitted
|
||||
|
@ -315,6 +326,53 @@ void sqlite3Pragma(
|
|||
sqlite3BtreeSetPageSize(pBt, atoi(zRight), -1);
|
||||
}
|
||||
}else
|
||||
|
||||
/*
|
||||
** PRAGMA [database.]locking_mode
|
||||
** PRAGMA [database.]locking_mode = (normal|exclusive)
|
||||
*/
|
||||
if( sqlite3StrICmp(zLeft,"locking_mode")==0 ){
|
||||
const char *zRet = "normal";
|
||||
int eMode = getLockingMode(zRight);
|
||||
|
||||
if( pId2->n==0 && eMode==PAGER_LOCKINGMODE_QUERY ){
|
||||
/* Simple "PRAGMA locking_mode;" statement. This is a query for
|
||||
** the current default locking mode (which may be different to
|
||||
** the locking-mode of the main database).
|
||||
*/
|
||||
eMode = db->dfltLockMode;
|
||||
}else{
|
||||
Pager *pPager;
|
||||
if( pId2->n==0 ){
|
||||
/* This indicates that no database name was specified as part
|
||||
** of the PRAGMA command. In this case the locking-mode must be
|
||||
** set on all attached databases, as well as the main db file.
|
||||
**
|
||||
** Also, the sqlite3.dfltLockMode variable is set so that
|
||||
** any subsequently attached databases also use the specified
|
||||
** locking mode.
|
||||
*/
|
||||
int ii;
|
||||
assert(pDb==&db->aDb[0]);
|
||||
for(ii=2; ii<db->nDb; ii++){
|
||||
pPager = sqlite3BtreePager(db->aDb[ii].pBt);
|
||||
sqlite3PagerLockingMode(pPager, eMode);
|
||||
}
|
||||
db->dfltLockMode = eMode;
|
||||
}
|
||||
pPager = sqlite3BtreePager(pDb->pBt);
|
||||
eMode = sqlite3PagerLockingMode(pPager, eMode);
|
||||
}
|
||||
|
||||
assert(eMode==PAGER_LOCKINGMODE_NORMAL||eMode==PAGER_LOCKINGMODE_EXCLUSIVE);
|
||||
if( eMode==PAGER_LOCKINGMODE_EXCLUSIVE ){
|
||||
zRet = "exclusive";
|
||||
}
|
||||
sqlite3VdbeSetNumCols(v, 1);
|
||||
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "locking_mode", P3_STATIC);
|
||||
sqlite3VdbeOp3(v, OP_String8, 0, 0, zRet, 0);
|
||||
sqlite3VdbeAddOp(v, OP_Callback, 1, 0);
|
||||
}else
|
||||
#endif /* SQLITE_OMIT_PAGER_PRAGMAS */
|
||||
|
||||
/*
|
||||
|
@ -916,7 +974,7 @@ void sqlite3Pragma(
|
|||
sqlite3VdbeSetNumCols(v, 1);
|
||||
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, zLeft, P3_TRANSIENT);
|
||||
}
|
||||
}
|
||||
}else
|
||||
#endif /* SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS */
|
||||
|
||||
#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
|
||||
|
@ -941,7 +999,7 @@ void sqlite3Pragma(
|
|||
if( pBt==0 || (pPager = sqlite3BtreePager(pBt))==0 ){
|
||||
sqlite3VdbeOp3(v, OP_String8, 0, 0, "closed", P3_STATIC);
|
||||
}else{
|
||||
int j = sqlite3pager_lockstate(pPager);
|
||||
int j = sqlite3PagerLockstate(pPager);
|
||||
sqlite3VdbeOp3(v, OP_String8, 0, 0,
|
||||
(j>=0 && j<=4) ? azLockName[j] : "unknown", P3_STATIC);
|
||||
}
|
||||
|
|
|
@ -310,10 +310,17 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
|
|||
rc = SQLITE_NOMEM;
|
||||
sqlite3ResetInternalSchema(db, 0);
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
if( rc==SQLITE_OK || (db->flags&SQLITE_RecoveryMode)){
|
||||
/* Black magic: If the SQLITE_RecoveryMode flag is set, then consider
|
||||
** the schema loaded, even if errors occured. In this situation the
|
||||
** current sqlite3_prepare() operation will fail, but the following one
|
||||
** will attempt to compile the supplied statement against whatever subset
|
||||
** of the schema was loaded before the error occured. The primary
|
||||
** purpose of this is to allow access to the sqlite_master table
|
||||
** even when it's contents have been corrupted.
|
||||
*/
|
||||
DbSetProperty(db, iDb, DB_SchemaLoaded);
|
||||
}else{
|
||||
sqlite3ResetInternalSchema(db, iDb);
|
||||
rc = SQLITE_OK;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
@ -559,7 +566,7 @@ int sqlite3Prepare(
|
|||
*/
|
||||
int sqlite3Reprepare(Vdbe *p){
|
||||
int rc;
|
||||
Vdbe *pNew;
|
||||
sqlite3_stmt *pNew;
|
||||
const char *zSql;
|
||||
sqlite3 *db;
|
||||
|
||||
|
@ -568,17 +575,17 @@ int sqlite3Reprepare(Vdbe *p){
|
|||
return 0;
|
||||
}
|
||||
db = sqlite3VdbeDb(p);
|
||||
rc = sqlite3Prepare(db, zSql, -1, 0, (sqlite3_stmt**)&pNew, 0);
|
||||
rc = sqlite3Prepare(db, zSql, -1, 0, &pNew, 0);
|
||||
if( rc ){
|
||||
assert( pNew==0 );
|
||||
return 0;
|
||||
}else{
|
||||
assert( pNew!=0 );
|
||||
}
|
||||
sqlite3VdbeSwap(pNew, p);
|
||||
sqlite3_transfer_bindings((sqlite3_stmt*)pNew, (sqlite3_stmt*)p);
|
||||
sqlite3VdbeResetStepResult(pNew);
|
||||
sqlite3VdbeFinalize(pNew);
|
||||
sqlite3VdbeSwap((Vdbe*)pNew, p);
|
||||
sqlite3_transfer_bindings(pNew, (sqlite3_stmt*)p);
|
||||
sqlite3VdbeResetStepResult((Vdbe*)pNew);
|
||||
sqlite3VdbeFinalize((Vdbe*)pNew);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
|
@ -821,9 +821,8 @@ char *sqlite3_vmprintf(const char *zFormat, va_list ap){
|
|||
char *sqlite3_mprintf(const char *zFormat, ...){
|
||||
va_list ap;
|
||||
char *z;
|
||||
char zBase[SQLITE_PRINT_BUF_SIZE];
|
||||
va_start(ap, zFormat);
|
||||
z = base_vprintf(sqlite3_realloc, 0, zBase, sizeof(zBase), zFormat, ap);
|
||||
z = sqlite3_vmprintf(zFormat, ap);
|
||||
va_end(ap);
|
||||
return z;
|
||||
}
|
||||
|
|
|
@ -66,6 +66,7 @@ Select *sqlite3SelectNew(
|
|||
pNew->pOrderBy = pOrderBy;
|
||||
pNew->isDistinct = isDistinct;
|
||||
pNew->op = TK_SELECT;
|
||||
assert( pOffset==0 || pLimit!=0 );
|
||||
pNew->pLimit = pLimit;
|
||||
pNew->pOffset = pOffset;
|
||||
pNew->iLimit = -1;
|
||||
|
@ -532,7 +533,7 @@ static int selectInnerLoop(
|
|||
}else{
|
||||
sqlite3VdbeAddOp(v, OP_NewRowid, iParm, 0);
|
||||
sqlite3VdbeAddOp(v, OP_Pull, 1, 0);
|
||||
sqlite3VdbeAddOp(v, OP_Insert, iParm, 0);
|
||||
sqlite3VdbeAddOp(v, OP_Insert, iParm, OPFLAG_APPEND);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -691,7 +692,7 @@ static void generateSortTail(
|
|||
int cont = sqlite3VdbeMakeLabel(v);
|
||||
int addr;
|
||||
int iTab;
|
||||
int pseudoTab;
|
||||
int pseudoTab = 0;
|
||||
ExprList *pOrderBy = p->pOrderBy;
|
||||
|
||||
iTab = pOrderBy->iECursor;
|
||||
|
@ -711,7 +712,7 @@ static void generateSortTail(
|
|||
case SRT_EphemTab: {
|
||||
sqlite3VdbeAddOp(v, OP_NewRowid, iParm, 0);
|
||||
sqlite3VdbeAddOp(v, OP_Pull, 1, 0);
|
||||
sqlite3VdbeAddOp(v, OP_Insert, iParm, 0);
|
||||
sqlite3VdbeAddOp(v, OP_Insert, iParm, OPFLAG_APPEND);
|
||||
break;
|
||||
}
|
||||
#ifndef SQLITE_OMIT_SUBQUERY
|
||||
|
@ -2364,6 +2365,8 @@ static int simpleMinMaxQuery(Parse *pParse, Select *p, int eDest, int iParm){
|
|||
iCol = pExpr->iColumn;
|
||||
pTab = pSrc->a[0].pTab;
|
||||
|
||||
/* This optimization cannot be used with virtual tables. */
|
||||
if( IsVirtual(pTab) ) return 0;
|
||||
|
||||
/* If we get to here, it means the query is of the correct form.
|
||||
** Check to make sure we have an index and make pIdx point to the
|
||||
|
@ -3142,11 +3145,7 @@ int sqlite3Select(
|
|||
for(i=0; i<sAggInfo.nColumn; i++){
|
||||
struct AggInfo_col *pCol = &sAggInfo.aCol[i];
|
||||
if( pCol->iSorterColumn<j ) continue;
|
||||
if( pCol->iColumn<0 ){
|
||||
sqlite3VdbeAddOp(v, OP_Rowid, pCol->iTable, 0);
|
||||
}else{
|
||||
sqlite3VdbeAddOp(v, OP_Column, pCol->iTable, pCol->iColumn);
|
||||
}
|
||||
sqlite3ExprCodeGetColumn(v, pCol->pTab, pCol->iColumn, pCol->iTable);
|
||||
j++;
|
||||
}
|
||||
sqlite3VdbeAddOp(v, OP_MakeRecord, j, 0);
|
||||
|
@ -3296,7 +3295,7 @@ select_end:
|
|||
return rc;
|
||||
}
|
||||
|
||||
#if defined(SQLITE_TEST) || defined(SQLITE_DEBUG)
|
||||
#if defined(SQLITE_DEBUG)
|
||||
/*
|
||||
*******************************************************************************
|
||||
** The following code is used for testing and debugging only. The code
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include <assert.h>
|
||||
#include "sqlite3.h"
|
||||
#include <ctype.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#if !defined(_WIN32) && !defined(WIN32) && !defined(__MACOS__) && !defined(__OS2__)
|
||||
# include <signal.h>
|
||||
|
@ -97,6 +98,28 @@ static char *Argv0;
|
|||
static char mainPrompt[20]; /* First line prompt. default: "sqlite> "*/
|
||||
static char continuePrompt[20]; /* Continuation prompt. default: " ...> " */
|
||||
|
||||
/*
|
||||
** Write I/O traces to the following stream.
|
||||
*/
|
||||
static FILE *iotrace = 0;
|
||||
|
||||
/*
|
||||
** This routine works like printf in that its first argument is a
|
||||
** format string and subsequent arguments are values to be substituted
|
||||
** in place of % fields. The result of formatting this string
|
||||
** is written to iotrace.
|
||||
*/
|
||||
static void iotracePrintf(const char *zFormat, ...){
|
||||
va_list ap;
|
||||
char *z;
|
||||
if( iotrace==0 ) return;
|
||||
va_start(ap, zFormat);
|
||||
z = sqlite3_vmprintf(zFormat, ap);
|
||||
va_end(ap);
|
||||
fprintf(iotrace, "%s", z);
|
||||
sqlite3_free(z);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Determines if a string is a number of not.
|
||||
|
@ -1219,6 +1242,26 @@ static int do_meta_command(char *zLine, struct callback_data *p){
|
|||
}
|
||||
}else
|
||||
|
||||
if( c=='i' && strncmp(azArg[0], "iotrace", n)==0 ){
|
||||
extern void (*sqlite3_io_trace)(const char*, ...);
|
||||
if( iotrace && iotrace!=stdout ) fclose(iotrace);
|
||||
iotrace = 0;
|
||||
if( nArg<2 ){
|
||||
sqlite3_io_trace = 0;
|
||||
}else if( strcmp(azArg[1], "-")==0 ){
|
||||
sqlite3_io_trace = iotracePrintf;
|
||||
iotrace = stdout;
|
||||
}else{
|
||||
iotrace = fopen(azArg[1], "w");
|
||||
if( iotrace==0 ){
|
||||
fprintf(stderr, "cannot open \"%s\"\n", azArg[1]);
|
||||
sqlite3_io_trace = 0;
|
||||
}else{
|
||||
sqlite3_io_trace = iotracePrintf;
|
||||
}
|
||||
}
|
||||
}else
|
||||
|
||||
#ifndef SQLITE_OMIT_LOAD_EXTENSION
|
||||
if( c=='l' && strncmp(azArg[0], "load", n)==0 && nArg>=2 ){
|
||||
const char *zFile, *zProc;
|
||||
|
|
|
@ -182,7 +182,7 @@ int sqlite3_exec(
|
|||
#define SQLITE_NOTFOUND 12 /* NOT USED. Table or record not found */
|
||||
#define SQLITE_FULL 13 /* Insertion failed because database is full */
|
||||
#define SQLITE_CANTOPEN 14 /* Unable to open the database file */
|
||||
#define SQLITE_PROTOCOL 15 /* Database lock protocol error */
|
||||
#define SQLITE_PROTOCOL 15 /* NOT USED. Database lock protocol error */
|
||||
#define SQLITE_EMPTY 16 /* Database is empty */
|
||||
#define SQLITE_SCHEMA 17 /* The database schema changed */
|
||||
#define SQLITE_TOOBIG 18 /* NOT USED. Too much data for one row */
|
||||
|
@ -230,6 +230,7 @@ int sqlite3_exec(
|
|||
#define SQLITE_IOERR_FSTAT (SQLITE_IOERR | (7<<8))
|
||||
#define SQLITE_IOERR_UNLOCK (SQLITE_IOERR | (8<<8))
|
||||
#define SQLITE_IOERR_RDLOCK (SQLITE_IOERR | (9<<8))
|
||||
#define SQLITE_IOERR_DELETE (SQLITE_IOERR | (10<<8))
|
||||
|
||||
/*
|
||||
** Enable or disable the extended result codes.
|
||||
|
@ -239,25 +240,29 @@ int sqlite3_extended_result_codes(sqlite3*, int onoff);
|
|||
/*
|
||||
** Each entry in an SQLite table has a unique integer key. (The key is
|
||||
** the value of the INTEGER PRIMARY KEY column if there is such a column,
|
||||
** otherwise the key is generated at random. The unique key is always
|
||||
** otherwise the key is generated automatically. The unique key is always
|
||||
** available as the ROWID, OID, or _ROWID_ column.) The following routine
|
||||
** returns the integer key of the most recent insert in the database.
|
||||
**
|
||||
** This function is similar to the mysql_insert_id() function from MySQL.
|
||||
*/
|
||||
sqlite_int64 sqlite3_last_insert_rowid(sqlite3*);
|
||||
|
||||
/*
|
||||
** This function returns the number of database rows that were changed
|
||||
** (or inserted or deleted) by the most recent called sqlite3_exec().
|
||||
** (or inserted or deleted) by the most recent SQL statement. Only
|
||||
** changes that are directly specified by the INSERT, UPDATE, or
|
||||
** DELETE statement are counted. Auxiliary changes caused by
|
||||
** triggers are not counted. Within the body of a trigger, however,
|
||||
** the sqlite3_changes() API can be called to find the number of
|
||||
** changes in the most recently completed INSERT, UPDATE, or DELETE
|
||||
** statement within the body of the trigger.
|
||||
**
|
||||
** All changes are counted, even if they were later undone by a
|
||||
** ROLLBACK or ABORT. Except, changes associated with creating and
|
||||
** dropping tables are not counted.
|
||||
**
|
||||
** If a callback invokes sqlite3_exec() recursively, then the changes
|
||||
** in the inner, recursive call are counted together with the changes
|
||||
** in the outer call.
|
||||
** If a callback invokes sqlite3_exec() or sqlite3_step() recursively,
|
||||
** then the changes in the inner, recursive call are counted together
|
||||
** with the changes in the outer call.
|
||||
**
|
||||
** SQLite implements the command "DELETE FROM table" without a WHERE clause
|
||||
** by dropping and recreating the table. (This is much faster than going
|
||||
|
@ -292,6 +297,9 @@ int sqlite3_total_changes(sqlite3*);
|
|||
** called in response to a user action such as pressing "Cancel"
|
||||
** or Ctrl-C where the user wants a long query operation to halt
|
||||
** immediately.
|
||||
**
|
||||
** It is safe to call this routine from a different thread that the
|
||||
** thread that is currently running the database operation.
|
||||
*/
|
||||
void sqlite3_interrupt(sqlite3*);
|
||||
|
||||
|
@ -302,9 +310,13 @@ void sqlite3_interrupt(sqlite3*);
|
|||
** sqlite3_complete16(), a nul-terminated machine byte order UTF-16 string
|
||||
** is required.
|
||||
**
|
||||
** The algorithm is simple. If the last token other than spaces
|
||||
** and comments is a semicolon, then return true. otherwise return
|
||||
** false.
|
||||
** This routine is useful for command-line input to see of the user has
|
||||
** entered a complete statement of SQL or if the current statement needs
|
||||
** to be continued on the next line. The algorithm is simple. If the
|
||||
** last token other than spaces and comments is a semicolon, then return
|
||||
** true. Actually, the algorithm is a little more complicated than that
|
||||
** in order to deal with triggers, but the basic idea is the same: the
|
||||
** statement is not complete unless it ends in a semicolon.
|
||||
*/
|
||||
int sqlite3_complete(const char *sql);
|
||||
int sqlite3_complete16(const void *sql);
|
||||
|
@ -743,31 +755,32 @@ typedef struct Mem sqlite3_value;
|
|||
|
||||
/*
|
||||
** In the SQL strings input to sqlite3_prepare() and sqlite3_prepare16(),
|
||||
** one or more literals can be replace by parameters "?" or ":AAA" or
|
||||
** "$VVV" where AAA is an identifer and VVV is a variable name according
|
||||
** to the syntax rules of the TCL programming language.
|
||||
** The value of these parameters (also called "host parameter names") can
|
||||
** be set using the routines listed below.
|
||||
** one or more literals can be replace by parameters "?" or "?NNN" or
|
||||
** ":AAA" or "@AAA" or "$VVV" where NNN is a integer, AAA is an identifer,
|
||||
** and VVV is a variable name according to the syntax rules of the
|
||||
** TCL programming language. The value of these parameters (also called
|
||||
** "host parameter names") can be set using the routines listed below.
|
||||
**
|
||||
** In every case, the first parameter is a pointer to the sqlite3_stmt
|
||||
** structure returned from sqlite3_prepare(). The second parameter is the
|
||||
** index of the parameter. The first parameter as an index of 1. For
|
||||
** named parameters (":AAA" or "$VVV") you can use
|
||||
** In every case, the first argument is a pointer to the sqlite3_stmt
|
||||
** structure returned from sqlite3_prepare(). The second argument is the
|
||||
** index of the host parameter name. The first host parameter as an index
|
||||
** of 1. For named host parameters (":AAA" or "$VVV") you can use
|
||||
** sqlite3_bind_parameter_index() to get the correct index value given
|
||||
** the parameters name. If the same named parameter occurs more than
|
||||
** the parameter name. If the same named parameter occurs more than
|
||||
** once, it is assigned the same index each time.
|
||||
**
|
||||
** The fifth parameter to sqlite3_bind_blob(), sqlite3_bind_text(), and
|
||||
** The fifth argument to sqlite3_bind_blob(), sqlite3_bind_text(), and
|
||||
** sqlite3_bind_text16() is a destructor used to dispose of the BLOB or
|
||||
** text after SQLite has finished with it. If the fifth argument is the
|
||||
** special value SQLITE_STATIC, then the library assumes that the information
|
||||
** is in static, unmanaged space and does not need to be freed. If the
|
||||
** fifth argument has the value SQLITE_TRANSIENT, then SQLite makes its
|
||||
** own private copy of the data.
|
||||
** own private copy of the data before the sqlite3_bind_* routine returns.
|
||||
**
|
||||
** The sqlite3_bind_* routine must be called before sqlite3_step() after
|
||||
** an sqlite3_prepare() or sqlite3_reset(). Unbound parameterss are
|
||||
** interpreted as NULL.
|
||||
** The sqlite3_bind_* routine must be called before sqlite3_step() and after
|
||||
** an sqlite3_prepare() or sqlite3_reset(). Bindings persist across
|
||||
** multiple calls to sqlite3_reset() and sqlite3_step(). Unbound parameters
|
||||
** are interpreted as NULL.
|
||||
*/
|
||||
int sqlite3_bind_blob(sqlite3_stmt*, int, const void*, int n, void(*)(void*));
|
||||
int sqlite3_bind_double(sqlite3_stmt*, int, double);
|
||||
|
@ -779,13 +792,13 @@ int sqlite3_bind_text16(sqlite3_stmt*, int, const void*, int, void(*)(void*));
|
|||
int sqlite3_bind_value(sqlite3_stmt*, int, const sqlite3_value*);
|
||||
|
||||
/*
|
||||
** Return the number of parameters in a compiled SQL statement. This
|
||||
** Return the number of host parameters in a compiled SQL statement. This
|
||||
** routine was added to support DBD::SQLite.
|
||||
*/
|
||||
int sqlite3_bind_parameter_count(sqlite3_stmt*);
|
||||
|
||||
/*
|
||||
** Return the name of the i-th parameter. Ordinary parameters "?" are
|
||||
** Return the name of the i-th name parameter. Ordinary parameters "?" are
|
||||
** nameless and a NULL is returned. For parameters of the form :AAA or
|
||||
** $VVV the complete text of the parameter name is returned, including
|
||||
** the initial ":" or "$". NULL is returned if the index is out of range.
|
||||
|
@ -821,7 +834,7 @@ const char *sqlite3_column_name(sqlite3_stmt*,int);
|
|||
const void *sqlite3_column_name16(sqlite3_stmt*,int);
|
||||
|
||||
/*
|
||||
** The first parameter to the following calls is a compiled SQL statement.
|
||||
** The first argument to the following calls is a compiled SQL statement.
|
||||
** These functions return information about the Nth column returned by
|
||||
** the statement, where N is the second function argument.
|
||||
**
|
||||
|
|
|
@ -142,8 +142,11 @@ struct sqlite3_api_routines {
|
|||
const void * (*value_text16be)(sqlite3_value*);
|
||||
const void * (*value_text16le)(sqlite3_value*);
|
||||
int (*value_type)(sqlite3_value*);
|
||||
char * (*vmprintf)(const char*,va_list);
|
||||
char *(*vmprintf)(const char*,va_list);
|
||||
int (*overload_function)(sqlite3*, const char *zFuncName, int nArg);
|
||||
int (*prepare_v2)(sqlite3*,const char*,int,sqlite3_stmt**,const char**);
|
||||
int (*prepare16_v2)(sqlite3*,const void*,int,sqlite3_stmt**,const void**);
|
||||
int (*clear_bindings)(sqlite3_stmt*);
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -232,6 +235,8 @@ struct sqlite3_api_routines {
|
|||
#define sqlite3_open16 sqlite3_api->open16
|
||||
#define sqlite3_prepare sqlite3_api->prepare
|
||||
#define sqlite3_prepare16 sqlite3_api->prepare16
|
||||
#define sqlite3_prepare_v2 sqlite3_api->prepare_v2
|
||||
#define sqlite3_prepare16_v2 sqlite3_api->prepare16_v2
|
||||
#define sqlite3_profile sqlite3_api->profile
|
||||
#define sqlite3_progress_handler sqlite3_api->progress_handler
|
||||
#define sqlite3_realloc sqlite3_api->realloc
|
||||
|
@ -274,6 +279,9 @@ struct sqlite3_api_routines {
|
|||
#define sqlite3_value_type sqlite3_api->value_type
|
||||
#define sqlite3_vmprintf sqlite3_api->vmprintf
|
||||
#define sqlite3_overload_function sqlite3_api->overload_function
|
||||
#define sqlite3_prepare_v2 sqlite3_api->prepare_v2
|
||||
#define sqlite3_prepare16_v2 sqlite3_api->prepare16_v2
|
||||
#define sqlite3_clear_bindings sqlite3_api->clear_bindings
|
||||
#endif /* SQLITE_CORE */
|
||||
|
||||
#define SQLITE_EXTENSION_INIT1 const sqlite3_api_routines *sqlite3_api;
|
||||
|
|
|
@ -16,11 +16,8 @@
|
|||
#ifndef _SQLITEINT_H_
|
||||
#define _SQLITEINT_H_
|
||||
|
||||
/*
|
||||
** Extra interface definitions for those who need them
|
||||
*/
|
||||
#ifdef SQLITE_EXTRA
|
||||
# include "sqliteExtra.h"
|
||||
#if defined(SQLITE_TCL) || defined(TCLSH)
|
||||
# include <tcl.h>
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
@ -215,8 +212,15 @@ typedef UINT8_TYPE i8; /* 1-byte signed integer */
|
|||
** evaluated at runtime.
|
||||
*/
|
||||
extern const int sqlite3one;
|
||||
#define SQLITE_BIGENDIAN (*(char *)(&sqlite3one)==0)
|
||||
#define SQLITE_LITTLEENDIAN (*(char *)(&sqlite3one)==1)
|
||||
#if defined(i386) || defined(__i386__) || defined(_M_IX86)
|
||||
# define SQLITE_BIGENDIAN 0
|
||||
# define SQLITE_LITTLEENDIAN 1
|
||||
# define SQLITE_UTF16NATIVE SQLITE_UTF16LE
|
||||
#else
|
||||
# define SQLITE_BIGENDIAN (*(char *)(&sqlite3one)==0)
|
||||
# define SQLITE_LITTLEENDIAN (*(char *)(&sqlite3one)==1)
|
||||
# define SQLITE_UTF16NATIVE (SQLITE_BIGENDIAN?SQLITE_UTF16BE:SQLITE_UTF16LE)
|
||||
#endif
|
||||
|
||||
/*
|
||||
** An instance of the following structure is used to store the busy-handler
|
||||
|
@ -414,7 +418,6 @@ struct Schema {
|
|||
#define DB_UnresetViews 0x0002 /* Some views have defined column names */
|
||||
#define DB_Empty 0x0004 /* The file is empty (length 0 bytes) */
|
||||
|
||||
#define SQLITE_UTF16NATIVE (SQLITE_BIGENDIAN?SQLITE_UTF16BE:SQLITE_UTF16LE)
|
||||
|
||||
/*
|
||||
** Each database is an instance of the following structure.
|
||||
|
@ -510,6 +513,7 @@ struct sqlite3 {
|
|||
#ifdef SQLITE_SSE
|
||||
sqlite3_stmt *pFetch; /* Used by SSE to fetch stored statements */
|
||||
#endif
|
||||
u8 dfltLockMode; /* Default locking-mode for attached dbs */
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -545,6 +549,8 @@ struct sqlite3 {
|
|||
#define SQLITE_FullFSync 0x00010000 /* Use full fsync on the backend */
|
||||
#define SQLITE_LoadExtension 0x00020000 /* Enable load_extension */
|
||||
|
||||
#define SQLITE_RecoveryMode 0x00040000 /* Ignore schema errors */
|
||||
|
||||
/*
|
||||
** Possible values for the sqlite.magic field.
|
||||
** The numbers are obtained at random and have no special meaning, other
|
||||
|
@ -922,6 +928,7 @@ struct AggInfo {
|
|||
ExprList *pGroupBy; /* The group by clause */
|
||||
int nSortingColumn; /* Number of columns in the sorting index */
|
||||
struct AggInfo_col { /* For each column used in source tables */
|
||||
Table *pTab; /* Source table */
|
||||
int iTable; /* Cursor number of the source table */
|
||||
int iColumn; /* Column number within the source table */
|
||||
int iSorterColumn; /* Column number in the sorting index */
|
||||
|
@ -1159,12 +1166,16 @@ struct WhereLevel {
|
|||
int iTabCur; /* The VDBE cursor used to access the table */
|
||||
int iIdxCur; /* The VDBE cursor used to acesss pIdx */
|
||||
int brk; /* Jump here to break out of the loop */
|
||||
int nxt; /* Jump here to start the next IN combination */
|
||||
int cont; /* Jump here to continue with the next loop cycle */
|
||||
int top; /* First instruction of interior of the loop */
|
||||
int op, p1, p2; /* Opcode used to terminate the loop */
|
||||
int nEq; /* Number of == or IN constraints on this loop */
|
||||
int nIn; /* Number of IN operators constraining this loop */
|
||||
int *aInLoop; /* Loop terminators for IN operators */
|
||||
struct InLoop {
|
||||
int iCur; /* The VDBE cursor used by this IN operator */
|
||||
int topAddr; /* Top of the IN loop */
|
||||
} *aInLoop; /* Information about each nested IN operator */
|
||||
sqlite3_index_info *pBestIdx; /* Index information for this level */
|
||||
|
||||
/* The following field is really not part of the current level. But
|
||||
|
@ -1371,6 +1382,7 @@ struct AuthContext {
|
|||
#define OPFLAG_NCHANGE 1 /* Set to update db->nChange */
|
||||
#define OPFLAG_LASTROWID 2 /* Set to update db->lastRowid */
|
||||
#define OPFLAG_ISUPDATE 4 /* This OP_Insert is an sql UPDATE */
|
||||
#define OPFLAG_APPEND 8 /* This is likely to be an append */
|
||||
|
||||
/*
|
||||
* Each trigger present in the database schema is stored as an instance of
|
||||
|
@ -1395,7 +1407,6 @@ struct Trigger {
|
|||
Expr *pWhen; /* The WHEN clause of the expresion (may be NULL) */
|
||||
IdList *pColumns; /* If this is an UPDATE OF <column-list> trigger,
|
||||
the <column-list> is stored here */
|
||||
int foreach; /* One of TK_ROW or TK_STATEMENT */
|
||||
Token nameToken; /* Token containing zName. Use during parsing only */
|
||||
Schema *pSchema; /* Schema containing the trigger */
|
||||
Schema *pTabSchema; /* Schema containing the table */
|
||||
|
@ -1566,7 +1577,7 @@ void *sqlite3Realloc(void*,int);
|
|||
char *sqlite3StrDup(const char*);
|
||||
char *sqlite3StrNDup(const char*, int);
|
||||
# define sqlite3CheckMemory(a,b)
|
||||
void sqlite3ReallocOrFree(void**,int);
|
||||
void *sqlite3ReallocOrFree(void*,int);
|
||||
void sqlite3FreeX(void*);
|
||||
void *sqlite3MallocX(int);
|
||||
int sqlite3AllocSize(void *);
|
||||
|
@ -1598,7 +1609,6 @@ int sqlite3InitCallback(void*, int, char**, char**);
|
|||
void sqlite3Pragma(Parse*,Token*,Token*,Token*,int);
|
||||
void sqlite3ResetInternalSchema(sqlite3*, int);
|
||||
void sqlite3BeginParse(Parse*,int);
|
||||
void sqlite3RollbackInternalChanges(sqlite3*);
|
||||
void sqlite3CommitInternalChanges(sqlite3*);
|
||||
Table *sqlite3ResultSetOfSelect(Parse*,char*,Select*);
|
||||
void sqlite3OpenMasterTable(Parse *, int);
|
||||
|
@ -1623,7 +1633,7 @@ void sqlite3CreateView(Parse*,Token*,Token*,Token*,Select*,int,int);
|
|||
void sqlite3DropTable(Parse*, SrcList*, int, int);
|
||||
void sqlite3DeleteTable(sqlite3*, Table*);
|
||||
void sqlite3Insert(Parse*, SrcList*, ExprList*, Select*, IdList*, int);
|
||||
int sqlite3ArrayAllocate(void**,int,int);
|
||||
void *sqlite3ArrayAllocate(void*,int,int,int*,int*,int*);
|
||||
IdList *sqlite3IdListAppend(IdList*, Token*);
|
||||
int sqlite3IdListIndex(IdList*,const char*);
|
||||
SrcList *sqlite3SrcListAppend(SrcList*, Token*, Token*);
|
||||
|
@ -1650,6 +1660,7 @@ void sqlite3DeleteFrom(Parse*, SrcList*, Expr*);
|
|||
void sqlite3Update(Parse*, SrcList*, ExprList*, Expr*, int);
|
||||
WhereInfo *sqlite3WhereBegin(Parse*, SrcList*, Expr*, ExprList**);
|
||||
void sqlite3WhereEnd(WhereInfo*);
|
||||
void sqlite3ExprCodeGetColumn(Vdbe*, Table*, int, int);
|
||||
void sqlite3ExprCode(Parse*, Expr*);
|
||||
void sqlite3ExprCodeAndCache(Parse*, Expr*);
|
||||
int sqlite3ExprCodeExprList(Parse*, ExprList*);
|
||||
|
@ -1686,7 +1697,7 @@ void sqlite3GenerateRowDelete(sqlite3*, Vdbe*, Table*, int, int);
|
|||
void sqlite3GenerateRowIndexDelete(Vdbe*, Table*, int, char*);
|
||||
void sqlite3GenerateIndexKey(Vdbe*, Index*, int);
|
||||
void sqlite3GenerateConstraintChecks(Parse*,Table*,int,char*,int,int,int,int);
|
||||
void sqlite3CompleteInsertion(Parse*, Table*, int, char*, int, int, int);
|
||||
void sqlite3CompleteInsertion(Parse*, Table*, int, char*, int, int, int, int);
|
||||
void sqlite3OpenTableAndIndices(Parse*, Table*, int, int);
|
||||
void sqlite3BeginWriteOperation(Parse*, int, int);
|
||||
Expr *sqlite3ExprDup(Expr*);
|
||||
|
@ -1705,7 +1716,7 @@ void sqlite3ChangeCookie(sqlite3*, Vdbe*, int);
|
|||
|
||||
#ifndef SQLITE_OMIT_TRIGGER
|
||||
void sqlite3BeginTrigger(Parse*, Token*,Token*,int,int,IdList*,SrcList*,
|
||||
int,Expr*,int, int);
|
||||
Expr*,int, int);
|
||||
void sqlite3FinishTrigger(Parse*, TriggerStep*, Token*);
|
||||
void sqlite3DropTrigger(Parse*, SrcList*, int);
|
||||
void sqlite3DropTriggerPtr(Parse*, Trigger*);
|
||||
|
@ -1895,4 +1906,18 @@ int sqlite3Reprepare(Vdbe*);
|
|||
#include "sseInt.h"
|
||||
#endif
|
||||
|
||||
/*
|
||||
** If the SQLITE_ENABLE IOTRACE exists then the global variable
|
||||
** sqlite3_io_trace is a pointer to a printf-like routine used to
|
||||
** print I/O tracing messages.
|
||||
*/
|
||||
#ifdef SQLITE_ENABLE_IOTRACE
|
||||
# define IOTRACE(A) if( sqlite3_io_trace ){ sqlite3_io_trace A; }
|
||||
void sqlite3VdbeIOTraceSql(Vdbe*);
|
||||
#else
|
||||
# define IOTRACE(A)
|
||||
# define sqlite3VdbeIOTraceSql(X)
|
||||
#endif
|
||||
extern void (*sqlite3_io_trace)(const char*,...);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -9,19 +9,25 @@
|
|||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
*************************************************************************
|
||||
** A TCL Interface to SQLite
|
||||
** A TCL Interface to SQLite. Append this file to sqlite3.c and
|
||||
** compile the whole thing to build a TCL-enabled version of SQLite.
|
||||
**
|
||||
** $Id$
|
||||
*/
|
||||
#ifndef NO_TCL /* Omit this whole file if TCL is unavailable */
|
||||
|
||||
#include "sqliteInt.h"
|
||||
#include "hash.h"
|
||||
#include "tcl.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
|
||||
/*
|
||||
** Some additional include files are needed if this file is not
|
||||
** appended to the amalgamation.
|
||||
*/
|
||||
#ifndef SQLITE_AMALGAMATION
|
||||
# include "sqliteInt.h"
|
||||
# include "hash.h"
|
||||
# include <stdlib.h>
|
||||
# include <string.h>
|
||||
# include <assert.h>
|
||||
# include <ctype.h>
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Windows needs to know which symbols to export. Unix does not.
|
||||
|
@ -2205,12 +2211,14 @@ int TCLSH_MAIN(int argc, char **argv){
|
|||
extern int Sqlitetest6_Init(Tcl_Interp*);
|
||||
extern int Sqlitetest7_Init(Tcl_Interp*);
|
||||
extern int Sqlitetest8_Init(Tcl_Interp*);
|
||||
extern int Sqlitetest9_Init(Tcl_Interp*);
|
||||
extern int Md5_Init(Tcl_Interp*);
|
||||
extern int Sqlitetestsse_Init(Tcl_Interp*);
|
||||
extern int Sqlitetestasync_Init(Tcl_Interp*);
|
||||
extern int Sqlitetesttclvar_Init(Tcl_Interp*);
|
||||
extern int Sqlitetestschema_Init(Tcl_Interp*);
|
||||
extern int Sqlitetest_autoext_Init(Tcl_Interp*);
|
||||
extern int Sqlitetest_hexio_Init(Tcl_Interp*);
|
||||
|
||||
Sqlitetest1_Init(interp);
|
||||
Sqlitetest2_Init(interp);
|
||||
|
@ -2220,10 +2228,12 @@ int TCLSH_MAIN(int argc, char **argv){
|
|||
Sqlitetest6_Init(interp);
|
||||
Sqlitetest7_Init(interp);
|
||||
Sqlitetest8_Init(interp);
|
||||
Sqlitetest9_Init(interp);
|
||||
Sqlitetestasync_Init(interp);
|
||||
Sqlitetesttclvar_Init(interp);
|
||||
Sqlitetestschema_Init(interp);
|
||||
Sqlitetest_autoext_Init(interp);
|
||||
Sqlitetest_hexio_Init(interp);
|
||||
Md5_Init(interp);
|
||||
#ifdef SQLITE_SSE
|
||||
Sqlitetestsse_Init(interp);
|
||||
|
@ -2254,5 +2264,3 @@ int TCLSH_MAIN(int argc, char **argv){
|
|||
return 0;
|
||||
}
|
||||
#endif /* TCLSH */
|
||||
|
||||
#endif /* !defined(NO_TCL) */
|
||||
|
|
|
@ -112,7 +112,7 @@ const char *sqlite3TestErrorName(int rc){
|
|||
}
|
||||
return zName;
|
||||
}
|
||||
#define errorName sqlite3TestErrorName
|
||||
#define t1ErrorName sqlite3TestErrorName
|
||||
|
||||
/*
|
||||
** Convert an sqlite3_stmt* into an sqlite3*. This depends on the
|
||||
|
@ -129,7 +129,7 @@ int sqlite3TestErrCode(Tcl_Interp *interp, sqlite3 *db, int rc){
|
|||
char zBuf[200];
|
||||
int r2 = sqlite3_errcode(db);
|
||||
sprintf(zBuf, "error code %s (%d) does not match sqlite3_errcode %s (%d)",
|
||||
errorName(rc), rc, errorName(r2), r2);
|
||||
t1ErrorName(rc), rc, t1ErrorName(r2), r2);
|
||||
Tcl_ResetResult(interp);
|
||||
Tcl_AppendResult(interp, zBuf, 0);
|
||||
return 1;
|
||||
|
@ -490,7 +490,7 @@ static int sqlite_test_close(
|
|||
}
|
||||
if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
|
||||
rc = sqlite3_close(db);
|
||||
Tcl_SetResult(interp, (char *)errorName(rc), TCL_STATIC);
|
||||
Tcl_SetResult(interp, (char *)t1ErrorName(rc), TCL_STATIC);
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
|
@ -498,7 +498,11 @@ static int sqlite_test_close(
|
|||
** Implementation of the x_coalesce() function.
|
||||
** Return the first argument non-NULL argument.
|
||||
*/
|
||||
static void ifnullFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
|
||||
static void t1_ifnullFunc(
|
||||
sqlite3_context *context,
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
int i;
|
||||
for(i=0; i<argc; i++){
|
||||
if( SQLITE_NULL!=sqlite3_value_type(argv[i]) ){
|
||||
|
@ -682,7 +686,7 @@ static int test_create_function(
|
|||
}
|
||||
if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
|
||||
rc = sqlite3_create_function(db, "x_coalesce", -1, SQLITE_ANY, 0,
|
||||
ifnullFunc, 0, 0);
|
||||
t1_ifnullFunc, 0, 0);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3_create_function(db, "hex8", 1, SQLITE_ANY, 0,
|
||||
hex8Func, 0, 0);
|
||||
|
@ -716,7 +720,7 @@ static int test_create_function(
|
|||
#endif
|
||||
|
||||
if( sqlite3TestErrCode(interp, db, rc) ) return TCL_ERROR;
|
||||
Tcl_SetResult(interp, (char *)errorName(rc), 0);
|
||||
Tcl_SetResult(interp, (char *)t1ErrorName(rc), 0);
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
|
@ -731,12 +735,16 @@ static int test_create_function(
|
|||
** is reported on the step function. If the total count is 42, then
|
||||
** a UTF-8 error is reported on the finalize function.
|
||||
*/
|
||||
typedef struct CountCtx CountCtx;
|
||||
struct CountCtx {
|
||||
typedef struct t1CountCtx t1CountCtx;
|
||||
struct t1CountCtx {
|
||||
int n;
|
||||
};
|
||||
static void countStep(sqlite3_context *context, int argc, sqlite3_value **argv){
|
||||
CountCtx *p;
|
||||
static void t1CountStep(
|
||||
sqlite3_context *context,
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
t1CountCtx *p;
|
||||
p = sqlite3_aggregate_context(context, sizeof(*p));
|
||||
if( (argc==0 || SQLITE_NULL!=sqlite3_value_type(argv[0]) ) && p ){
|
||||
p->n++;
|
||||
|
@ -753,8 +761,8 @@ static void countStep(sqlite3_context *context, int argc, sqlite3_value **argv){
|
|||
}
|
||||
}
|
||||
}
|
||||
static void countFinalize(sqlite3_context *context){
|
||||
CountCtx *p;
|
||||
static void t1CountFinalize(sqlite3_context *context){
|
||||
t1CountCtx *p;
|
||||
p = sqlite3_aggregate_context(context, sizeof(*p));
|
||||
if( p ){
|
||||
if( p->n==42 ){
|
||||
|
@ -794,10 +802,10 @@ static int test_create_aggregate(
|
|||
}
|
||||
if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
|
||||
rc = sqlite3_create_function(db, "x_count", 0, SQLITE_UTF8, 0, 0,
|
||||
countStep,countFinalize);
|
||||
t1CountStep,t1CountFinalize);
|
||||
if( rc==SQLITE_OK ){
|
||||
sqlite3_create_function(db, "x_count", 1, SQLITE_UTF8, 0, 0,
|
||||
countStep,countFinalize);
|
||||
t1CountStep,t1CountFinalize);
|
||||
}
|
||||
if( sqlite3TestErrCode(interp, db, rc) ) return TCL_ERROR;
|
||||
return TCL_OK;
|
||||
|
@ -926,6 +934,40 @@ static int sqlite3_mprintf_str(
|
|||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Usage: sqlite3_snprintf_str INTEGER FORMAT INTEGER INTEGER STRING
|
||||
**
|
||||
** Call mprintf with two integer arguments and one string argument
|
||||
*/
|
||||
static int sqlite3_snprintf_str(
|
||||
void *NotUsed,
|
||||
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
|
||||
int argc, /* Number of arguments */
|
||||
char **argv /* Text of each argument */
|
||||
){
|
||||
int a[3], i;
|
||||
int n;
|
||||
char *z;
|
||||
if( argc<5 || argc>6 ){
|
||||
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
|
||||
" INT FORMAT INT INT ?STRING?\"", 0);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
if( Tcl_GetInt(interp, argv[1], &n) ) return TCL_ERROR;
|
||||
if( n<0 ){
|
||||
Tcl_AppendResult(interp, "N must be non-negative", 0);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
for(i=3; i<5; i++){
|
||||
if( Tcl_GetInt(interp, argv[i], &a[i-3]) ) return TCL_ERROR;
|
||||
}
|
||||
z = sqlite3_malloc( n+1 );
|
||||
sqlite3_snprintf(n, z, argv[2], a[0], a[1], argc>4 ? argv[5] : NULL);
|
||||
Tcl_AppendResult(interp, z, 0);
|
||||
sqlite3_free(z);
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Usage: sqlite3_mprintf_double FORMAT INTEGER INTEGER DOUBLE
|
||||
**
|
||||
|
@ -1497,7 +1539,7 @@ static int test_finalize(
|
|||
db = StmtToDb(pStmt);
|
||||
}
|
||||
rc = sqlite3_finalize(pStmt);
|
||||
Tcl_SetResult(interp, (char *)errorName(rc), TCL_STATIC);
|
||||
Tcl_SetResult(interp, (char *)t1ErrorName(rc), TCL_STATIC);
|
||||
if( db && sqlite3TestErrCode(interp, db, rc) ) return TCL_ERROR;
|
||||
return TCL_OK;
|
||||
}
|
||||
|
@ -1528,7 +1570,7 @@ static int test_reset(
|
|||
if( pStmt && sqlite3TestErrCode(interp, StmtToDb(pStmt), rc) ){
|
||||
return TCL_ERROR;
|
||||
}
|
||||
Tcl_SetResult(interp, (char *)errorName(rc), TCL_STATIC);
|
||||
Tcl_SetResult(interp, (char *)t1ErrorName(rc), TCL_STATIC);
|
||||
/*
|
||||
if( rc ){
|
||||
return TCL_ERROR;
|
||||
|
@ -2052,7 +2094,7 @@ static int test_errstr(
|
|||
|
||||
zCode = Tcl_GetString(objv[1]);
|
||||
for(i=0; i<200; i++){
|
||||
if( 0==strcmp(errorName(i), zCode) ) break;
|
||||
if( 0==strcmp(t1ErrorName(i), zCode) ) break;
|
||||
}
|
||||
Tcl_SetResult(interp, (char *)sqlite3ErrStr(i), 0);
|
||||
return TCL_OK;
|
||||
|
@ -2504,7 +2546,7 @@ static int test_errcode(
|
|||
}else{
|
||||
sprintf(zBuf,"+%d", rc>>8);
|
||||
}
|
||||
Tcl_AppendResult(interp, (char *)errorName(rc), zBuf, 0);
|
||||
Tcl_AppendResult(interp, (char *)t1ErrorName(rc), zBuf, 0);
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
|
@ -2900,7 +2942,7 @@ static int test_step(
|
|||
rc = sqlite3_step(pStmt);
|
||||
|
||||
/* if( rc!=SQLITE_DONE && rc!=SQLITE_ROW ) return TCL_ERROR; */
|
||||
Tcl_SetResult(interp, (char *)errorName(rc), 0);
|
||||
Tcl_SetResult(interp, (char *)t1ErrorName(rc), 0);
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
|
@ -3137,7 +3179,7 @@ static int test_global_recover(
|
|||
return TCL_ERROR;
|
||||
}
|
||||
rc = sqlite3_global_recover();
|
||||
Tcl_SetResult(interp, (char *)errorName(rc), TCL_STATIC);
|
||||
Tcl_SetResult(interp, (char *)t1ErrorName(rc), TCL_STATIC);
|
||||
#endif
|
||||
return TCL_OK;
|
||||
}
|
||||
|
@ -3235,7 +3277,7 @@ static int test_sqlite3OsOpenReadWrite(
|
|||
|
||||
rc = sqlite3OsOpenReadWrite(Tcl_GetString(objv[1]), &pFile, &dummy);
|
||||
if( rc!=SQLITE_OK ){
|
||||
Tcl_SetResult(interp, (char *)errorName(rc), TCL_STATIC);
|
||||
Tcl_SetResult(interp, (char *)t1ErrorName(rc), TCL_STATIC);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
sqlite3TestMakePointerStr(interp, zBuf, pFile);
|
||||
|
@ -3266,7 +3308,7 @@ static int test_sqlite3OsClose(
|
|||
}
|
||||
rc = sqlite3OsClose(&pFile);
|
||||
if( rc!=SQLITE_OK ){
|
||||
Tcl_SetResult(interp, (char *)errorName(rc), TCL_STATIC);
|
||||
Tcl_SetResult(interp, (char *)t1ErrorName(rc), TCL_STATIC);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
return TCL_OK;
|
||||
|
@ -3314,7 +3356,7 @@ static int test_sqlite3OsLock(
|
|||
}
|
||||
|
||||
if( rc!=SQLITE_OK ){
|
||||
Tcl_SetResult(interp, (char *)errorName(rc), TCL_STATIC);
|
||||
Tcl_SetResult(interp, (char *)t1ErrorName(rc), TCL_STATIC);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
return TCL_OK;
|
||||
|
@ -3343,7 +3385,7 @@ static int test_sqlite3OsUnlock(
|
|||
}
|
||||
rc = sqlite3OsUnlock(pFile, NO_LOCK);
|
||||
if( rc!=SQLITE_OK ){
|
||||
Tcl_SetResult(interp, (char *)errorName(rc), TCL_STATIC);
|
||||
Tcl_SetResult(interp, (char *)t1ErrorName(rc), TCL_STATIC);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
return TCL_OK;
|
||||
|
@ -3363,7 +3405,7 @@ static int test_sqlite3OsTempFileName(
|
|||
|
||||
rc = sqlite3OsTempFileName(zFile);
|
||||
if( rc!=SQLITE_OK ){
|
||||
Tcl_SetResult(interp, (char *)errorName(rc), TCL_STATIC);
|
||||
Tcl_SetResult(interp, (char *)t1ErrorName(rc), TCL_STATIC);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
Tcl_AppendResult(interp, zFile, 0);
|
||||
|
@ -3492,7 +3534,7 @@ static int delete_function(
|
|||
}
|
||||
if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
|
||||
rc = sqlite3_create_function(db, argv[2], -1, SQLITE_UTF8, 0, 0, 0, 0);
|
||||
Tcl_SetResult(interp, (char *)errorName(rc), TCL_STATIC);
|
||||
Tcl_SetResult(interp, (char *)t1ErrorName(rc), TCL_STATIC);
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
|
@ -3518,7 +3560,7 @@ static int delete_collation(
|
|||
}
|
||||
if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
|
||||
rc = sqlite3_create_collation(db, argv[2], SQLITE_UTF8, 0, 0);
|
||||
Tcl_SetResult(interp, (char *)errorName(rc), TCL_STATIC);
|
||||
Tcl_SetResult(interp, (char *)t1ErrorName(rc), TCL_STATIC);
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
|
@ -3708,6 +3750,44 @@ static int test_thread_cleanup(
|
|||
}
|
||||
|
||||
|
||||
/*
|
||||
** Usage: sqlite3_pager_refcounts DB
|
||||
**
|
||||
** Return a list of numbers which are the PagerRefcount for all
|
||||
** pagers on each database connection.
|
||||
*/
|
||||
static int test_pager_refcounts(
|
||||
void * clientData,
|
||||
Tcl_Interp *interp,
|
||||
int objc,
|
||||
Tcl_Obj *CONST objv[]
|
||||
){
|
||||
sqlite3 *db;
|
||||
int i;
|
||||
int v, *a;
|
||||
Tcl_Obj *pResult;
|
||||
|
||||
if( objc!=2 ){
|
||||
Tcl_AppendResult(interp, "wrong # args: should be \"",
|
||||
Tcl_GetStringFromObj(objv[0], 0), " DB", 0);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
|
||||
pResult = Tcl_NewObj();
|
||||
for(i=0; i<db->nDb; i++){
|
||||
if( db->aDb[i].pBt==0 ){
|
||||
v = -1;
|
||||
}else{
|
||||
a = sqlite3PagerStats(sqlite3BtreePager(db->aDb[i].pBt));
|
||||
v = a[0];
|
||||
}
|
||||
Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(v));
|
||||
}
|
||||
Tcl_SetObjResult(interp, pResult);
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** This routine sets entries in the global ::sqlite_options() array variable
|
||||
** according to the compile-time configuration of the database. Test
|
||||
|
@ -3750,6 +3830,12 @@ static void set_options(Tcl_Interp *interp){
|
|||
Tcl_SetVar2(interp, "sqlite_options", "analyze", "1", TCL_GLOBAL_ONLY);
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_OMIT_ATTACH
|
||||
Tcl_SetVar2(interp, "sqlite_options", "attach", "0", TCL_GLOBAL_ONLY);
|
||||
#else
|
||||
Tcl_SetVar2(interp, "sqlite_options", "attach", "1", TCL_GLOBAL_ONLY);
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_OMIT_AUTHORIZATION
|
||||
Tcl_SetVar2(interp, "sqlite_options", "auth", "0", TCL_GLOBAL_ONLY);
|
||||
#else
|
||||
|
@ -3893,6 +3979,12 @@ static void set_options(Tcl_Interp *interp){
|
|||
Tcl_SetVar2(interp, "sqlite_options", "like_opt", "1", TCL_GLOBAL_ONLY);
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_OMIT_LOAD_EXTENSION
|
||||
Tcl_SetVar2(interp, "sqlite_options", "load_ext", "0", TCL_GLOBAL_ONLY);
|
||||
#else
|
||||
Tcl_SetVar2(interp, "sqlite_options", "load_ext", "1", TCL_GLOBAL_ONLY);
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_OMIT_MEMORYDB
|
||||
Tcl_SetVar2(interp, "sqlite_options", "memorydb", "0", TCL_GLOBAL_ONLY);
|
||||
#else
|
||||
|
@ -4008,7 +4100,7 @@ static void set_options(Tcl_Interp *interp){
|
|||
Tcl_SetVar2(interp, "sqlite_options", "utf16", "1", TCL_GLOBAL_ONLY);
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_OMIT_VACUUM
|
||||
#if defined(SQLITE_OMIT_VACUUM) || defined(SQLITE_OMIT_ATTACH)
|
||||
Tcl_SetVar2(interp, "sqlite_options", "vacuum", "0", TCL_GLOBAL_ONLY);
|
||||
#else
|
||||
Tcl_SetVar2(interp, "sqlite_options", "vacuum", "1", TCL_GLOBAL_ONLY);
|
||||
|
@ -4025,6 +4117,25 @@ static void set_options(Tcl_Interp *interp){
|
|||
#else
|
||||
Tcl_SetVar2(interp, "sqlite_options", "vtab", "1", TCL_GLOBAL_ONLY);
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_DEFAULT_FILE_FORMAT
|
||||
Tcl_ObjSetVar2(interp,
|
||||
Tcl_NewStringObj("sqlite_default_file_format", -1), 0,
|
||||
Tcl_NewIntObj(SQLITE_DEFAULT_FILE_FORMAT), TCL_GLOBAL_ONLY
|
||||
);
|
||||
#endif
|
||||
#ifdef SQLITE_MAX_PAGE_SIZE
|
||||
Tcl_ObjSetVar2(interp,
|
||||
Tcl_NewStringObj("SQLITE_MAX_PAGE_SIZE", -1), 0,
|
||||
Tcl_NewIntObj(SQLITE_MAX_PAGE_SIZE), TCL_GLOBAL_ONLY
|
||||
);
|
||||
#endif
|
||||
#ifdef TEMP_STORE
|
||||
Tcl_ObjSetVar2(interp,
|
||||
Tcl_NewStringObj("TEMP_STORE", -1), 0,
|
||||
Tcl_NewIntObj(TEMP_STORE), TCL_GLOBAL_ONLY
|
||||
);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -4072,6 +4183,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
|
|||
{ "sqlite3_mprintf_int", (Tcl_CmdProc*)sqlite3_mprintf_int },
|
||||
{ "sqlite3_mprintf_int64", (Tcl_CmdProc*)sqlite3_mprintf_int64 },
|
||||
{ "sqlite3_mprintf_str", (Tcl_CmdProc*)sqlite3_mprintf_str },
|
||||
{ "sqlite3_snprintf_str", (Tcl_CmdProc*)sqlite3_snprintf_str },
|
||||
{ "sqlite3_mprintf_stronly", (Tcl_CmdProc*)sqlite3_mprintf_stronly},
|
||||
{ "sqlite3_mprintf_double", (Tcl_CmdProc*)sqlite3_mprintf_double },
|
||||
{ "sqlite3_mprintf_scaled", (Tcl_CmdProc*)sqlite3_mprintf_scaled },
|
||||
|
@ -4146,6 +4258,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
|
|||
{ "sqlite3_clear_tsd_memdebug", test_clear_tsd_memdebug, 0},
|
||||
{ "sqlite3_tsd_release", test_tsd_release, 0},
|
||||
{ "sqlite3_thread_cleanup", test_thread_cleanup, 0},
|
||||
{ "sqlite3_pager_refcounts", test_pager_refcounts, 0},
|
||||
|
||||
{ "sqlite3_load_extension", test_load_extension, 0},
|
||||
{ "sqlite3_enable_load_extension", test_enable_load, 0},
|
||||
|
@ -4220,10 +4333,11 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
|
|||
extern int sqlite3_sync_count, sqlite3_fullsync_count;
|
||||
extern int sqlite3_opentemp_count;
|
||||
extern int sqlite3_memUsed;
|
||||
extern int sqlite3_malloc_id;
|
||||
extern char *sqlite3_malloc_id;
|
||||
extern int sqlite3_memMax;
|
||||
extern int sqlite3_like_count;
|
||||
extern int sqlite3_tsd_count;
|
||||
extern int sqlite3_xferopt_count;
|
||||
#if OS_UNIX && defined(SQLITE_TEST) && defined(THREADSAFE) && THREADSAFE
|
||||
extern int threadsOverrideEachOthersLocks;
|
||||
#endif
|
||||
|
@ -4261,6 +4375,8 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
|
|||
(char*)&sqlite3_os_trace, TCL_LINK_INT);
|
||||
Tcl_LinkVar(interp, "sqlite3_tsd_count",
|
||||
(char*)&sqlite3_tsd_count, TCL_LINK_INT);
|
||||
Tcl_LinkVar(interp, "sqlite3_xferopt_count",
|
||||
(char*)&sqlite3_xferopt_count, TCL_LINK_INT);
|
||||
#ifndef SQLITE_OMIT_UTF16
|
||||
Tcl_LinkVar(interp, "unaligned_string_counter",
|
||||
(char*)&unaligned_string_counter, TCL_LINK_INT);
|
||||
|
|
|
@ -78,13 +78,13 @@ static int pager_open(
|
|||
return TCL_ERROR;
|
||||
}
|
||||
if( Tcl_GetInt(interp, argv[2], &nPage) ) return TCL_ERROR;
|
||||
rc = sqlite3pager_open(&pPager, argv[1], 0, 0);
|
||||
rc = sqlite3PagerOpen(&pPager, argv[1], 0, 0);
|
||||
if( rc!=SQLITE_OK ){
|
||||
Tcl_AppendResult(interp, errorName(rc), 0);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
sqlite3pager_set_cachesize(pPager, nPage);
|
||||
sqlite3pager_set_pagesize(pPager, test_pagesize);
|
||||
sqlite3PagerSetCachesize(pPager, nPage);
|
||||
sqlite3PagerSetPagesize(pPager, test_pagesize);
|
||||
sqlite3_snprintf(sizeof(zBuf),zBuf,"%p",pPager);
|
||||
Tcl_AppendResult(interp, zBuf, 0);
|
||||
return TCL_OK;
|
||||
|
@ -109,7 +109,7 @@ static int pager_close(
|
|||
return TCL_ERROR;
|
||||
}
|
||||
pPager = sqlite3TextToPtr(argv[1]);
|
||||
rc = sqlite3pager_close(pPager);
|
||||
rc = sqlite3PagerClose(pPager);
|
||||
if( rc!=SQLITE_OK ){
|
||||
Tcl_AppendResult(interp, errorName(rc), 0);
|
||||
return TCL_ERROR;
|
||||
|
@ -136,7 +136,7 @@ static int pager_rollback(
|
|||
return TCL_ERROR;
|
||||
}
|
||||
pPager = sqlite3TextToPtr(argv[1]);
|
||||
rc = sqlite3pager_rollback(pPager);
|
||||
rc = sqlite3PagerRollback(pPager);
|
||||
if( rc!=SQLITE_OK ){
|
||||
Tcl_AppendResult(interp, errorName(rc), 0);
|
||||
return TCL_ERROR;
|
||||
|
@ -163,7 +163,12 @@ static int pager_commit(
|
|||
return TCL_ERROR;
|
||||
}
|
||||
pPager = sqlite3TextToPtr(argv[1]);
|
||||
rc = sqlite3pager_commit(pPager);
|
||||
rc = sqlite3PagerCommitPhaseOne(pPager, 0, 0);
|
||||
if( rc!=SQLITE_OK ){
|
||||
Tcl_AppendResult(interp, errorName(rc), 0);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
rc = sqlite3PagerCommitPhaseTwo(pPager);
|
||||
if( rc!=SQLITE_OK ){
|
||||
Tcl_AppendResult(interp, errorName(rc), 0);
|
||||
return TCL_ERROR;
|
||||
|
@ -190,7 +195,7 @@ static int pager_stmt_begin(
|
|||
return TCL_ERROR;
|
||||
}
|
||||
pPager = sqlite3TextToPtr(argv[1]);
|
||||
rc = sqlite3pager_stmt_begin(pPager);
|
||||
rc = sqlite3PagerStmtBegin(pPager);
|
||||
if( rc!=SQLITE_OK ){
|
||||
Tcl_AppendResult(interp, errorName(rc), 0);
|
||||
return TCL_ERROR;
|
||||
|
@ -217,7 +222,7 @@ static int pager_stmt_rollback(
|
|||
return TCL_ERROR;
|
||||
}
|
||||
pPager = sqlite3TextToPtr(argv[1]);
|
||||
rc = sqlite3pager_stmt_rollback(pPager);
|
||||
rc = sqlite3PagerStmtRollback(pPager);
|
||||
if( rc!=SQLITE_OK ){
|
||||
Tcl_AppendResult(interp, errorName(rc), 0);
|
||||
return TCL_ERROR;
|
||||
|
@ -244,7 +249,7 @@ static int pager_stmt_commit(
|
|||
return TCL_ERROR;
|
||||
}
|
||||
pPager = sqlite3TextToPtr(argv[1]);
|
||||
rc = sqlite3pager_stmt_commit(pPager);
|
||||
rc = sqlite3PagerStmtCommit(pPager);
|
||||
if( rc!=SQLITE_OK ){
|
||||
Tcl_AppendResult(interp, errorName(rc), 0);
|
||||
return TCL_ERROR;
|
||||
|
@ -271,7 +276,7 @@ static int pager_stats(
|
|||
return TCL_ERROR;
|
||||
}
|
||||
pPager = sqlite3TextToPtr(argv[1]);
|
||||
a = sqlite3pager_stats(pPager);
|
||||
a = sqlite3PagerStats(pPager);
|
||||
for(i=0; i<9; i++){
|
||||
static char *zName[] = {
|
||||
"ref", "page", "max", "size", "state", "err",
|
||||
|
@ -304,7 +309,7 @@ static int pager_pagecount(
|
|||
return TCL_ERROR;
|
||||
}
|
||||
pPager = sqlite3TextToPtr(argv[1]);
|
||||
sqlite3_snprintf(sizeof(zBuf),zBuf,"%d",sqlite3pager_pagecount(pPager));
|
||||
sqlite3_snprintf(sizeof(zBuf),zBuf,"%d",sqlite3PagerPagecount(pPager));
|
||||
Tcl_AppendResult(interp, zBuf, 0);
|
||||
return TCL_OK;
|
||||
}
|
||||
|
@ -322,7 +327,7 @@ static int page_get(
|
|||
){
|
||||
Pager *pPager;
|
||||
char zBuf[100];
|
||||
void *pPage;
|
||||
DbPage *pPage;
|
||||
int pgno;
|
||||
int rc;
|
||||
if( argc!=3 ){
|
||||
|
@ -332,7 +337,7 @@ static int page_get(
|
|||
}
|
||||
pPager = sqlite3TextToPtr(argv[1]);
|
||||
if( Tcl_GetInt(interp, argv[2], &pgno) ) return TCL_ERROR;
|
||||
rc = sqlite3pager_get(pPager, pgno, &pPage);
|
||||
rc = sqlite3PagerGet(pPager, pgno, &pPage);
|
||||
if( rc!=SQLITE_OK ){
|
||||
Tcl_AppendResult(interp, errorName(rc), 0);
|
||||
return TCL_ERROR;
|
||||
|
@ -356,7 +361,7 @@ static int page_lookup(
|
|||
){
|
||||
Pager *pPager;
|
||||
char zBuf[100];
|
||||
void *pPage;
|
||||
DbPage *pPage;
|
||||
int pgno;
|
||||
if( argc!=3 ){
|
||||
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
|
||||
|
@ -365,7 +370,7 @@ static int page_lookup(
|
|||
}
|
||||
pPager = sqlite3TextToPtr(argv[1]);
|
||||
if( Tcl_GetInt(interp, argv[2], &pgno) ) return TCL_ERROR;
|
||||
pPage = sqlite3pager_lookup(pPager, pgno);
|
||||
pPage = sqlite3PagerLookup(pPager, pgno);
|
||||
if( pPage ){
|
||||
sqlite3_snprintf(sizeof(zBuf),zBuf,"%p",pPage);
|
||||
Tcl_AppendResult(interp, zBuf, 0);
|
||||
|
@ -392,7 +397,7 @@ static int pager_truncate(
|
|||
}
|
||||
pPager = sqlite3TextToPtr(argv[1]);
|
||||
if( Tcl_GetInt(interp, argv[2], &pgno) ) return TCL_ERROR;
|
||||
rc = sqlite3pager_truncate(pPager, pgno);
|
||||
rc = sqlite3PagerTruncate(pPager, pgno);
|
||||
if( rc!=SQLITE_OK ){
|
||||
Tcl_AppendResult(interp, errorName(rc), 0);
|
||||
return TCL_ERROR;
|
||||
|
@ -412,15 +417,15 @@ static int page_unref(
|
|||
int argc, /* Number of arguments */
|
||||
const char **argv /* Text of each argument */
|
||||
){
|
||||
void *pPage;
|
||||
DbPage *pPage;
|
||||
int rc;
|
||||
if( argc!=2 ){
|
||||
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
|
||||
" PAGE\"", 0);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
pPage = sqlite3TextToPtr(argv[1]);
|
||||
rc = sqlite3pager_unref(pPage);
|
||||
pPage = (DbPage *)sqlite3TextToPtr(argv[1]);
|
||||
rc = sqlite3PagerUnref(pPage);
|
||||
if( rc!=SQLITE_OK ){
|
||||
Tcl_AppendResult(interp, errorName(rc), 0);
|
||||
return TCL_ERROR;
|
||||
|
@ -440,14 +445,14 @@ static int page_read(
|
|||
const char **argv /* Text of each argument */
|
||||
){
|
||||
char zBuf[100];
|
||||
void *pPage;
|
||||
DbPage *pPage;
|
||||
if( argc!=2 ){
|
||||
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
|
||||
" PAGE\"", 0);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
pPage = sqlite3TextToPtr(argv[1]);
|
||||
memcpy(zBuf, pPage, sizeof(zBuf));
|
||||
memcpy(zBuf, sqlite3PagerGetData(pPage), sizeof(zBuf));
|
||||
Tcl_AppendResult(interp, zBuf, 0);
|
||||
return TCL_OK;
|
||||
}
|
||||
|
@ -464,14 +469,14 @@ static int page_number(
|
|||
const char **argv /* Text of each argument */
|
||||
){
|
||||
char zBuf[100];
|
||||
void *pPage;
|
||||
DbPage *pPage;
|
||||
if( argc!=2 ){
|
||||
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
|
||||
" PAGE\"", 0);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
pPage = sqlite3TextToPtr(argv[1]);
|
||||
sqlite3_snprintf(sizeof(zBuf), zBuf, "%d", sqlite3pager_pagenumber(pPage));
|
||||
pPage = (DbPage *)sqlite3TextToPtr(argv[1]);
|
||||
sqlite3_snprintf(sizeof(zBuf), zBuf, "%d", sqlite3PagerPagenumber(pPage));
|
||||
Tcl_AppendResult(interp, zBuf, 0);
|
||||
return TCL_OK;
|
||||
}
|
||||
|
@ -487,21 +492,23 @@ static int page_write(
|
|||
int argc, /* Number of arguments */
|
||||
const char **argv /* Text of each argument */
|
||||
){
|
||||
void *pPage;
|
||||
DbPage *pPage;
|
||||
char *pData;
|
||||
int rc;
|
||||
if( argc!=3 ){
|
||||
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
|
||||
" PAGE DATA\"", 0);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
pPage = sqlite3TextToPtr(argv[1]);
|
||||
rc = sqlite3pager_write(pPage);
|
||||
pPage = (DbPage *)sqlite3TextToPtr(argv[1]);
|
||||
rc = sqlite3PagerWrite(pPage);
|
||||
if( rc!=SQLITE_OK ){
|
||||
Tcl_AppendResult(interp, errorName(rc), 0);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
strncpy((char*)pPage, argv[2], test_pagesize-1);
|
||||
((char*)pPage)[test_pagesize-1] = 0;
|
||||
pData = sqlite3PagerGetData(pPage);
|
||||
strncpy(pData, argv[2], test_pagesize-1);
|
||||
pData[test_pagesize-1] = 0;
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
|
@ -558,10 +565,12 @@ static int fake_big_file(
|
|||
** Register commands with the TCL interpreter.
|
||||
*/
|
||||
int Sqlitetest2_Init(Tcl_Interp *interp){
|
||||
extern int sqlite3_io_error_persist;
|
||||
extern int sqlite3_io_error_pending;
|
||||
extern int sqlite3_io_error_hit;
|
||||
extern int sqlite3_diskfull_pending;
|
||||
extern int sqlite3_diskfull;
|
||||
extern int sqlite3_pager_n_sort_bucket;
|
||||
static struct {
|
||||
char *zName;
|
||||
Tcl_CmdProc *xProc;
|
||||
|
@ -592,6 +601,8 @@ int Sqlitetest2_Init(Tcl_Interp *interp){
|
|||
}
|
||||
Tcl_LinkVar(interp, "sqlite_io_error_pending",
|
||||
(char*)&sqlite3_io_error_pending, TCL_LINK_INT);
|
||||
Tcl_LinkVar(interp, "sqlite_io_error_persist",
|
||||
(char*)&sqlite3_io_error_persist, TCL_LINK_INT);
|
||||
Tcl_LinkVar(interp, "sqlite_io_error_hit",
|
||||
(char*)&sqlite3_io_error_hit, TCL_LINK_INT);
|
||||
Tcl_LinkVar(interp, "sqlite_diskfull_pending",
|
||||
|
@ -602,5 +613,7 @@ int Sqlitetest2_Init(Tcl_Interp *interp){
|
|||
(char*)&sqlite3_pending_byte, TCL_LINK_INT);
|
||||
Tcl_LinkVar(interp, "pager_pagesize",
|
||||
(char*)&test_pagesize, TCL_LINK_INT);
|
||||
Tcl_LinkVar(interp, "sqlite_pager_n_sort_bucket",
|
||||
(char*)&sqlite3_pager_n_sort_bucket, TCL_LINK_INT);
|
||||
return TCL_OK;
|
||||
}
|
||||
|
|
|
@ -511,7 +511,7 @@ static int btree_pager_stats(
|
|||
return TCL_ERROR;
|
||||
}
|
||||
pBt = sqlite3TextToPtr(argv[1]);
|
||||
a = sqlite3pager_stats(sqlite3BtreePager(pBt));
|
||||
a = sqlite3PagerStats(sqlite3BtreePager(pBt));
|
||||
for(i=0; i<11; i++){
|
||||
static char *zName[] = {
|
||||
"ref", "page", "max", "size", "state", "err",
|
||||
|
@ -545,7 +545,7 @@ static int btree_pager_ref_dump(
|
|||
}
|
||||
pBt = sqlite3TextToPtr(argv[1]);
|
||||
#ifdef SQLITE_DEBUG
|
||||
sqlite3pager_refdump(sqlite3BtreePager(pBt));
|
||||
sqlite3PagerRefdump(sqlite3BtreePager(pBt));
|
||||
#endif
|
||||
return TCL_OK;
|
||||
}
|
||||
|
@ -706,9 +706,9 @@ static int btree_move_to(
|
|||
if( sqlite3BtreeFlags(pCur) & BTREE_INTKEY ){
|
||||
int iKey;
|
||||
if( Tcl_GetInt(interp, argv[2], &iKey) ) return TCL_ERROR;
|
||||
rc = sqlite3BtreeMoveto(pCur, 0, iKey, &res);
|
||||
rc = sqlite3BtreeMoveto(pCur, 0, iKey, 0, &res);
|
||||
}else{
|
||||
rc = sqlite3BtreeMoveto(pCur, argv[2], strlen(argv[2]), &res);
|
||||
rc = sqlite3BtreeMoveto(pCur, argv[2], strlen(argv[2]), 0, &res);
|
||||
}
|
||||
if( rc ){
|
||||
Tcl_AppendResult(interp, errorName(rc), 0);
|
||||
|
@ -775,7 +775,7 @@ static int btree_insert(
|
|||
unsigned char *pBuf;
|
||||
if( Tcl_GetWideIntFromObj(interp, objv[2], &iKey) ) return TCL_ERROR;
|
||||
pBuf = Tcl_GetByteArrayFromObj(objv[3], &len);
|
||||
rc = sqlite3BtreeInsert(pCur, 0, iKey, pBuf, len);
|
||||
rc = sqlite3BtreeInsert(pCur, 0, iKey, pBuf, len, 0);
|
||||
}else{
|
||||
int keylen;
|
||||
int dlen;
|
||||
|
@ -783,7 +783,7 @@ static int btree_insert(
|
|||
unsigned char *pDBuf;
|
||||
pKBuf = Tcl_GetByteArrayFromObj(objv[2], &keylen);
|
||||
pDBuf = Tcl_GetByteArrayFromObj(objv[3], &dlen);
|
||||
rc = sqlite3BtreeInsert(pCur, pKBuf, keylen, pDBuf, dlen);
|
||||
rc = sqlite3BtreeInsert(pCur, pKBuf, keylen, pDBuf, dlen, 0);
|
||||
}
|
||||
if( rc ){
|
||||
Tcl_AppendResult(interp, errorName(rc), 0);
|
||||
|
@ -1229,7 +1229,7 @@ static int btree_cursor_info(
|
|||
/*
|
||||
** Copied from btree.c:
|
||||
*/
|
||||
static u32 get4byte(unsigned char *p){
|
||||
static u32 t4Get4byte(unsigned char *p){
|
||||
return (p[0]<<24) | (p[1]<<16) | (p[2]<<8) | p[3];
|
||||
}
|
||||
|
||||
|
@ -1282,15 +1282,17 @@ static int btree_ovfl_info(
|
|||
n = (n + dataSize - 1)/dataSize;
|
||||
pgno = (u32)aResult[10];
|
||||
while( pgno && n-- ){
|
||||
DbPage *pDbPage;
|
||||
sprintf(zElem, "%d", pgno);
|
||||
Tcl_DStringAppendElement(&str, zElem);
|
||||
if( sqlite3pager_get(pPager, pgno, &pPage)!=SQLITE_OK ){
|
||||
if( sqlite3PagerGet(pPager, pgno, &pDbPage)!=SQLITE_OK ){
|
||||
Tcl_DStringFree(&str);
|
||||
Tcl_AppendResult(interp, "unable to get page ", zElem, 0);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
pgno = get4byte((unsigned char*)pPage);
|
||||
sqlite3pager_unref(pPage);
|
||||
pPage = sqlite3PagerGetData(pDbPage);
|
||||
pgno = t4Get4byte((unsigned char*)pPage);
|
||||
sqlite3PagerUnref(pDbPage);
|
||||
}
|
||||
Tcl_DStringResult(interp, &str);
|
||||
return SQLITE_OK;
|
||||
|
|
|
@ -47,7 +47,6 @@ void sqlite3BeginTrigger(
|
|||
int op, /* One of TK_INSERT, TK_UPDATE, TK_DELETE */
|
||||
IdList *pColumns, /* column list if this is an UPDATE OF trigger */
|
||||
SrcList *pTableName,/* The name of the table/view the trigger applies to */
|
||||
int foreach, /* One of TK_ROW or TK_STATEMENT */
|
||||
Expr *pWhen, /* WHEN clause */
|
||||
int isTemp, /* True if the TEMPORARY keyword is present */
|
||||
int noErr /* Suppress errors if the trigger already exists */
|
||||
|
@ -180,7 +179,6 @@ void sqlite3BeginTrigger(
|
|||
pTrigger->tr_tm = tr_tm==TK_BEFORE ? TRIGGER_BEFORE : TRIGGER_AFTER;
|
||||
pTrigger->pWhen = sqlite3ExprDup(pWhen);
|
||||
pTrigger->pColumns = sqlite3IdListDup(pColumns);
|
||||
pTrigger->foreach = foreach;
|
||||
sqlite3TokenCopy(&pTrigger->nameToken,pName);
|
||||
assert( pParse->pNewTrigger==0 );
|
||||
pParse->pNewTrigger = pTrigger;
|
||||
|
@ -390,7 +388,11 @@ TriggerStep *sqlite3TriggerUpdateStep(
|
|||
int orconf /* The conflict algorithm. (OE_Abort, OE_Ignore, etc) */
|
||||
){
|
||||
TriggerStep *pTriggerStep = sqliteMalloc(sizeof(TriggerStep));
|
||||
if( pTriggerStep==0 ) return 0;
|
||||
if( pTriggerStep==0 ){
|
||||
sqlite3ExprListDelete(pEList);
|
||||
sqlite3ExprDelete(pWhere);
|
||||
return 0;
|
||||
}
|
||||
|
||||
pTriggerStep->op = TK_UPDATE;
|
||||
pTriggerStep->target = *pTableName;
|
||||
|
@ -409,7 +411,10 @@ TriggerStep *sqlite3TriggerUpdateStep(
|
|||
*/
|
||||
TriggerStep *sqlite3TriggerDeleteStep(Token *pTableName, Expr *pWhere){
|
||||
TriggerStep *pTriggerStep = sqliteMalloc(sizeof(TriggerStep));
|
||||
if( pTriggerStep==0 ) return 0;
|
||||
if( pTriggerStep==0 ){
|
||||
sqlite3ExprDelete(pWhere);
|
||||
return 0;
|
||||
}
|
||||
|
||||
pTriggerStep->op = TK_DELETE;
|
||||
pTriggerStep->target = *pTableName;
|
||||
|
|
|
@ -465,7 +465,7 @@ void sqlite3Update(
|
|||
|
||||
/* Create the new index entries and the new record.
|
||||
*/
|
||||
sqlite3CompleteInsertion(pParse, pTab, iCur, aIdxUsed, chngRowid, 1, -1);
|
||||
sqlite3CompleteInsertion(pParse, pTab, iCur, aIdxUsed, chngRowid, 1, -1, 0);
|
||||
}
|
||||
|
||||
/* Increment the row counter
|
||||
|
@ -617,6 +617,7 @@ static void updateVirtualTable(
|
|||
sqlite3VdbeOp3(v, OP_VUpdate, 0, pTab->nCol+2,
|
||||
(const char*)pTab->pVtab, P3_VTAB);
|
||||
sqlite3VdbeAddOp(v, OP_Next, ephemTab, addr);
|
||||
sqlite3VdbeJumpHere(v, addr-1);
|
||||
sqlite3VdbeAddOp(v, OP_Close, ephemTab, 0);
|
||||
|
||||
/* Cleanup */
|
||||
|
|
|
@ -62,6 +62,12 @@
|
|||
#include <assert.h>
|
||||
#include "vdbeInt.h"
|
||||
|
||||
/*
|
||||
** The following constant value is used by the SQLITE_BIGENDIAN and
|
||||
** SQLITE_LITTLEENDIAN macros.
|
||||
*/
|
||||
const int sqlite3one = 1;
|
||||
|
||||
/*
|
||||
** This table maps from the first byte of a UTF-8 character to the number
|
||||
** of trailing bytes expected. A value '4' indicates that the table key
|
||||
|
|
|
@ -83,7 +83,7 @@ void sqlite3_soft_heap_limit(int n){
|
|||
** Release memory held by SQLite instances created by the current thread.
|
||||
*/
|
||||
int sqlite3_release_memory(int n){
|
||||
return sqlite3pager_release_memory(n);
|
||||
return sqlite3PagerReleaseMemory(n);
|
||||
}
|
||||
#else
|
||||
/* If SQLITE_ENABLE_MEMORY_MANAGEMENT is not defined, then define a version
|
||||
|
@ -661,12 +661,13 @@ void *sqlite3Malloc(int n, int doMemManage){
|
|||
}
|
||||
return p;
|
||||
}
|
||||
void sqlite3ReallocOrFree(void **pp, int n){
|
||||
void *p = sqlite3Realloc(*pp, n);
|
||||
if( !p ){
|
||||
sqlite3FreeX(*pp);
|
||||
void *sqlite3ReallocOrFree(void *p, int n){
|
||||
void *pNew;
|
||||
pNew = sqlite3Realloc(p, n);
|
||||
if( !pNew ){
|
||||
sqlite3FreeX(p);
|
||||
}
|
||||
*pp = p;
|
||||
return pNew;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -750,7 +751,7 @@ void sqlite3SetString(char **pz, ...){
|
|||
const char *z;
|
||||
char *zResult;
|
||||
|
||||
if( pz==0 ) return;
|
||||
assert( pz!=0 );
|
||||
nByte = 1;
|
||||
va_start(ap, pz);
|
||||
while( (z = va_arg(ap, const char*))!=0 ){
|
||||
|
@ -1132,6 +1133,13 @@ int sqlite3FitsIn64Bits(const char *zNum){
|
|||
** Return an error (non-zero) if the magic was not SQLITE_MAGIC_OPEN
|
||||
** when this routine is called.
|
||||
**
|
||||
** This routine is called when entering an SQLite API. The SQLITE_MAGIC_OPEN
|
||||
** value indicates that the database connection passed into the API is
|
||||
** open and is not being used by another thread. By changing the value
|
||||
** to SQLITE_MAGIC_BUSY we indicate that the connection is in use.
|
||||
** sqlite3SafetyOff() below will change the value back to SQLITE_MAGIC_OPEN
|
||||
** when the API exits.
|
||||
**
|
||||
** This routine is a attempt to detect if two threads use the
|
||||
** same sqlite* pointer at the same time. There is a race
|
||||
** condition so it is possible that the error is not detected.
|
||||
|
@ -1165,11 +1173,11 @@ int sqlite3SafetyOff(sqlite3 *db){
|
|||
if( db->magic==SQLITE_MAGIC_BUSY ){
|
||||
db->magic = SQLITE_MAGIC_OPEN;
|
||||
return 0;
|
||||
}else if( db->magic==SQLITE_MAGIC_OPEN ){
|
||||
}else {
|
||||
db->magic = SQLITE_MAGIC_ERROR;
|
||||
db->u1.isInterrupted = 1;
|
||||
return 1;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1384,11 +1392,11 @@ void *sqlite3TextToPtr(const char *z){
|
|||
z++;
|
||||
}
|
||||
if( sizeof(p)==sizeof(v) ){
|
||||
p = *(void**)&v;
|
||||
memcpy(&p, &v, sizeof(p));
|
||||
}else{
|
||||
assert( sizeof(p)==sizeof(v2) );
|
||||
v2 = (u32)v;
|
||||
p = *(void**)&v2;
|
||||
memcpy(&p, &v2, sizeof(p));
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
@ -1461,9 +1469,11 @@ int sqlite3MallocFailed(){
|
|||
** Set the "malloc has failed" condition to true for this thread.
|
||||
*/
|
||||
void sqlite3FailedMalloc(){
|
||||
sqlite3OsEnterMutex();
|
||||
assert( mallocHasFailed==0 );
|
||||
mallocHasFailed = 1;
|
||||
if( !sqlite3MallocFailed() ){
|
||||
sqlite3OsEnterMutex();
|
||||
assert( mallocHasFailed==0 );
|
||||
mallocHasFailed = 1;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef SQLITE_MEMDEBUG
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
#include "vdbeInt.h"
|
||||
#include "os.h"
|
||||
|
||||
#ifndef SQLITE_OMIT_VACUUM
|
||||
#if !defined(SQLITE_OMIT_VACUUM) && !defined(SQLITE_OMIT_ATTACH)
|
||||
/*
|
||||
** Execute zSql on database db. Return an error code.
|
||||
*/
|
||||
|
@ -83,13 +83,11 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
|
|||
char *zSql = 0; /* SQL statements */
|
||||
int saved_flags; /* Saved value of the db->flags */
|
||||
Db *pDb = 0; /* Database to detach at end of vacuum */
|
||||
char zTemp[SQLITE_TEMPNAME_SIZE+20]; /* Name of the TEMP file */
|
||||
|
||||
/* Save the current value of the write-schema flag before setting it. */
|
||||
saved_flags = db->flags;
|
||||
db->flags |= SQLITE_WriteSchema | SQLITE_IgnoreChecks;
|
||||
|
||||
sqlite3OsTempFileName(zTemp);
|
||||
if( !db->autoCommit ){
|
||||
sqlite3SetString(pzErrMsg, "cannot VACUUM from within a transaction",
|
||||
(char*)0);
|
||||
|
@ -106,20 +104,18 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
|
|||
**
|
||||
** An optimisation would be to use a non-journaled pager.
|
||||
*/
|
||||
zSql = sqlite3MPrintf("ATTACH '%q' AS vacuum_db;", zTemp);
|
||||
if( !zSql ){
|
||||
rc = SQLITE_NOMEM;
|
||||
goto end_of_vacuum;
|
||||
}
|
||||
zSql = "ATTACH '' AS vacuum_db;";
|
||||
rc = execSql(db, zSql);
|
||||
sqliteFree(zSql);
|
||||
zSql = 0;
|
||||
if( rc!=SQLITE_OK ) goto end_of_vacuum;
|
||||
pDb = &db->aDb[db->nDb-1];
|
||||
assert( strcmp(db->aDb[db->nDb-1].zName,"vacuum_db")==0 );
|
||||
pTemp = db->aDb[db->nDb-1].pBt;
|
||||
sqlite3BtreeSetPageSize(pTemp, sqlite3BtreeGetPageSize(pMain),
|
||||
sqlite3BtreeGetReserve(pMain));
|
||||
if( sqlite3MallocFailed() ){
|
||||
rc = SQLITE_NOMEM;
|
||||
goto end_of_vacuum;
|
||||
}
|
||||
assert( sqlite3BtreeGetPageSize(pTemp)==sqlite3BtreeGetPageSize(pMain) );
|
||||
rc = execSql(db, "PRAGMA vacuum_db.synchronous=OFF");
|
||||
if( rc!=SQLITE_OK ){
|
||||
|
@ -259,12 +255,8 @@ end_of_vacuum:
|
|||
pDb->pSchema = 0;
|
||||
}
|
||||
|
||||
sqlite3OsDelete(zTemp);
|
||||
strcat(zTemp, "-journal");
|
||||
sqlite3OsDelete(zTemp);
|
||||
sqliteFree( zSql );
|
||||
sqlite3ResetInternalSchema(db, 0);
|
||||
|
||||
return rc;
|
||||
}
|
||||
#endif /* SQLITE_OMIT_VACUUM */
|
||||
#endif /* SQLITE_OMIT_VACUUM && SQLITE_OMIT_ATTACH */
|
||||
|
|
|
@ -211,7 +211,7 @@ static void applyNumericAffinity(Mem *pRec){
|
|||
sqlite3VdbeChangeEncoding(pRec, SQLITE_UTF8);
|
||||
if( !realnum && sqlite3atoi64(pRec->z, &value) ){
|
||||
sqlite3VdbeMemRelease(pRec);
|
||||
pRec->i = value;
|
||||
pRec->u.i = value;
|
||||
pRec->flags = MEM_Int;
|
||||
}else{
|
||||
sqlite3VdbeMemRealify(pRec);
|
||||
|
@ -454,6 +454,7 @@ int sqlite3VdbeExec(
|
|||
p->resOnStack = 0;
|
||||
db->busyHandler.nBusy = 0;
|
||||
CHECK_FOR_INTERRUPT;
|
||||
sqlite3VdbeIOTraceSql(p);
|
||||
#ifdef SQLITE_DEBUG
|
||||
if( (p->db->flags & SQLITE_VdbeListing)!=0
|
||||
|| sqlite3OsFileExists("vdbe_explain")
|
||||
|
@ -669,7 +670,7 @@ case OP_Halt: { /* no-push */
|
|||
case OP_Integer: {
|
||||
pTos++;
|
||||
pTos->flags = MEM_Int;
|
||||
pTos->i = pOp->p1;
|
||||
pTos->u.i = pOp->p1;
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -685,7 +686,7 @@ case OP_Int64: {
|
|||
pTos->z = pOp->p3;
|
||||
pTos->n = strlen(pTos->z);
|
||||
pTos->enc = SQLITE_UTF8;
|
||||
pTos->i = sqlite3VdbeIntValue(pTos);
|
||||
pTos->u.i = sqlite3VdbeIntValue(pTos);
|
||||
pTos->flags |= MEM_Int;
|
||||
break;
|
||||
}
|
||||
|
@ -1098,8 +1099,8 @@ case OP_Remainder: { /* same as TK_REM, no-push */
|
|||
pTos->flags = MEM_Null;
|
||||
}else if( (pTos->flags & pNos->flags & MEM_Int)==MEM_Int ){
|
||||
i64 a, b;
|
||||
a = pTos->i;
|
||||
b = pNos->i;
|
||||
a = pTos->u.i;
|
||||
b = pNos->u.i;
|
||||
switch( pOp->opcode ){
|
||||
case OP_Add: b += a; break;
|
||||
case OP_Subtract: b -= a; break;
|
||||
|
@ -1118,7 +1119,7 @@ case OP_Remainder: { /* same as TK_REM, no-push */
|
|||
Release(pTos);
|
||||
pTos--;
|
||||
Release(pTos);
|
||||
pTos->i = b;
|
||||
pTos->u.i = b;
|
||||
pTos->flags = MEM_Int;
|
||||
}else{
|
||||
double a, b;
|
||||
|
@ -1309,7 +1310,7 @@ case OP_ShiftRight: { /* same as TK_RSHIFT, no-push */
|
|||
Release(pTos);
|
||||
pTos--;
|
||||
Release(pTos);
|
||||
pTos->i = a;
|
||||
pTos->u.i = a;
|
||||
pTos->flags = MEM_Int;
|
||||
break;
|
||||
}
|
||||
|
@ -1324,7 +1325,7 @@ case OP_ShiftRight: { /* same as TK_RSHIFT, no-push */
|
|||
case OP_AddImm: { /* no-push */
|
||||
assert( pTos>=p->aStack );
|
||||
sqlite3VdbeMemIntegerify(pTos);
|
||||
pTos->i += pOp->p1;
|
||||
pTos->u.i += pOp->p1;
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -1349,7 +1350,7 @@ case OP_ForceInt: { /* no-push */
|
|||
break;
|
||||
}
|
||||
if( pTos->flags & MEM_Int ){
|
||||
v = pTos->i + (pOp->p1!=0);
|
||||
v = pTos->u.i + (pOp->p1!=0);
|
||||
}else{
|
||||
/* FIX ME: should this not be assert( pTos->flags & MEM_Real ) ??? */
|
||||
sqlite3VdbeMemRealify(pTos);
|
||||
|
@ -1358,7 +1359,7 @@ case OP_ForceInt: { /* no-push */
|
|||
if( pOp->p1 && pTos->r==(double)v ) v++;
|
||||
}
|
||||
Release(pTos);
|
||||
pTos->i = v;
|
||||
pTos->u.i = v;
|
||||
pTos->flags = MEM_Int;
|
||||
break;
|
||||
}
|
||||
|
@ -1647,7 +1648,7 @@ case OP_Ge: { /* same as TK_GE, no-push */
|
|||
}else{
|
||||
pTos++;
|
||||
pTos->flags = MEM_Int;
|
||||
pTos->i = res;
|
||||
pTos->u.i = res;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -1674,13 +1675,13 @@ case OP_Or: { /* same as TK_OR, no-push */
|
|||
v1 = 2;
|
||||
}else{
|
||||
sqlite3VdbeMemIntegerify(pTos);
|
||||
v1 = pTos->i==0;
|
||||
v1 = pTos->u.i==0;
|
||||
}
|
||||
if( pNos->flags & MEM_Null ){
|
||||
v2 = 2;
|
||||
}else{
|
||||
sqlite3VdbeMemIntegerify(pNos);
|
||||
v2 = pNos->i==0;
|
||||
v2 = pNos->u.i==0;
|
||||
}
|
||||
if( pOp->opcode==OP_And ){
|
||||
static const unsigned char and_logic[] = { 0, 1, 2, 1, 1, 1, 2, 1, 2 };
|
||||
|
@ -1694,7 +1695,7 @@ case OP_Or: { /* same as TK_OR, no-push */
|
|||
if( v1==2 ){
|
||||
pTos->flags = MEM_Null;
|
||||
}else{
|
||||
pTos->i = v1==0;
|
||||
pTos->u.i = v1==0;
|
||||
pTos->flags = MEM_Int;
|
||||
}
|
||||
break;
|
||||
|
@ -1724,8 +1725,8 @@ case OP_AbsValue: {
|
|||
pTos->flags = MEM_Real;
|
||||
}else if( pTos->flags & MEM_Int ){
|
||||
Release(pTos);
|
||||
if( pOp->opcode==OP_Negative || pTos->i<0 ){
|
||||
pTos->i = -pTos->i;
|
||||
if( pOp->opcode==OP_Negative || pTos->u.i<0 ){
|
||||
pTos->u.i = -pTos->u.i;
|
||||
}
|
||||
pTos->flags = MEM_Int;
|
||||
}else if( pTos->flags & MEM_Null ){
|
||||
|
@ -1748,7 +1749,7 @@ case OP_Not: { /* same as TK_NOT, no-push */
|
|||
if( pTos->flags & MEM_Null ) break; /* Do nothing to NULLs */
|
||||
sqlite3VdbeMemIntegerify(pTos);
|
||||
assert( (pTos->flags & MEM_Dyn)==0 );
|
||||
pTos->i = !pTos->i;
|
||||
pTos->u.i = !pTos->u.i;
|
||||
pTos->flags = MEM_Int;
|
||||
break;
|
||||
}
|
||||
|
@ -1764,7 +1765,7 @@ case OP_BitNot: { /* same as TK_BITNOT, no-push */
|
|||
if( pTos->flags & MEM_Null ) break; /* Do nothing to NULLs */
|
||||
sqlite3VdbeMemIntegerify(pTos);
|
||||
assert( (pTos->flags & MEM_Dyn)==0 );
|
||||
pTos->i = ~pTos->i;
|
||||
pTos->u.i = ~pTos->u.i;
|
||||
pTos->flags = MEM_Int;
|
||||
break;
|
||||
}
|
||||
|
@ -1936,6 +1937,9 @@ case OP_Column: {
|
|||
** which is the number of records.
|
||||
*/
|
||||
pC = p->apCsr[p1];
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
assert( pC->pVtabCursor==0 );
|
||||
#endif
|
||||
assert( pC!=0 );
|
||||
if( pC->pCursor!=0 ){
|
||||
/* The record is stored in a B-Tree */
|
||||
|
@ -2445,7 +2449,7 @@ case OP_ReadCookie: {
|
|||
*/
|
||||
rc = sqlite3BtreeGetMeta(db->aDb[pOp->p1].pBt, 1 + pOp->p2, (u32 *)&iMeta);
|
||||
pTos++;
|
||||
pTos->i = iMeta;
|
||||
pTos->u.i = iMeta;
|
||||
pTos->flags = MEM_Int;
|
||||
break;
|
||||
}
|
||||
|
@ -2469,14 +2473,14 @@ case OP_SetCookie: { /* no-push */
|
|||
assert( pTos>=p->aStack );
|
||||
sqlite3VdbeMemIntegerify(pTos);
|
||||
/* See note about index shifting on OP_ReadCookie */
|
||||
rc = sqlite3BtreeUpdateMeta(pDb->pBt, 1+pOp->p2, (int)pTos->i);
|
||||
rc = sqlite3BtreeUpdateMeta(pDb->pBt, 1+pOp->p2, (int)pTos->u.i);
|
||||
if( pOp->p2==0 ){
|
||||
/* When the schema cookie changes, record the new cookie internally */
|
||||
pDb->pSchema->schema_cookie = pTos->i;
|
||||
pDb->pSchema->schema_cookie = pTos->u.i;
|
||||
db->flags |= SQLITE_InternChanges;
|
||||
}else if( pOp->p2==1 ){
|
||||
/* Record changes in the file format */
|
||||
pDb->pSchema->file_format = pTos->i;
|
||||
pDb->pSchema->file_format = pTos->u.i;
|
||||
}
|
||||
assert( (pTos->flags & MEM_Dyn)==0 );
|
||||
pTos--;
|
||||
|
@ -2578,7 +2582,7 @@ case OP_OpenWrite: { /* no-push */
|
|||
|
||||
assert( pTos>=p->aStack );
|
||||
sqlite3VdbeMemIntegerify(pTos);
|
||||
iDb = pTos->i;
|
||||
iDb = pTos->u.i;
|
||||
assert( (pTos->flags & MEM_Dyn)==0 );
|
||||
pTos--;
|
||||
assert( iDb>=0 && iDb<db->nDb );
|
||||
|
@ -2596,7 +2600,7 @@ case OP_OpenWrite: { /* no-push */
|
|||
if( p2<=0 ){
|
||||
assert( pTos>=p->aStack );
|
||||
sqlite3VdbeMemIntegerify(pTos);
|
||||
p2 = pTos->i;
|
||||
p2 = pTos->u.i;
|
||||
assert( (pTos->flags & MEM_Dyn)==0 );
|
||||
pTos--;
|
||||
assert( p2>=2 );
|
||||
|
@ -2822,7 +2826,7 @@ case OP_MoveGt: { /* no-push */
|
|||
if( pC->isTable ){
|
||||
i64 iKey;
|
||||
sqlite3VdbeMemIntegerify(pTos);
|
||||
iKey = intToKey(pTos->i);
|
||||
iKey = intToKey(pTos->u.i);
|
||||
if( pOp->p2==0 && pOp->opcode==OP_MoveGe ){
|
||||
pC->movetoTarget = iKey;
|
||||
pC->deferredMoveto = 1;
|
||||
|
@ -2830,16 +2834,16 @@ case OP_MoveGt: { /* no-push */
|
|||
pTos--;
|
||||
break;
|
||||
}
|
||||
rc = sqlite3BtreeMoveto(pC->pCursor, 0, (u64)iKey, &res);
|
||||
rc = sqlite3BtreeMoveto(pC->pCursor, 0, (u64)iKey, 0, &res);
|
||||
if( rc!=SQLITE_OK ){
|
||||
goto abort_due_to_error;
|
||||
}
|
||||
pC->lastRowid = pTos->i;
|
||||
pC->lastRowid = pTos->u.i;
|
||||
pC->rowidIsValid = res==0;
|
||||
}else{
|
||||
assert( pTos->flags & MEM_Blob );
|
||||
/* Stringify(pTos, encoding); */
|
||||
rc = sqlite3BtreeMoveto(pC->pCursor, pTos->z, pTos->n, &res);
|
||||
rc = sqlite3BtreeMoveto(pC->pCursor, pTos->z, pTos->n, 0, &res);
|
||||
if( rc!=SQLITE_OK ){
|
||||
goto abort_due_to_error;
|
||||
}
|
||||
|
@ -2946,7 +2950,7 @@ case OP_Found: { /* no-push */
|
|||
int res, rx;
|
||||
assert( pC->isTable==0 );
|
||||
Stringify(pTos, encoding);
|
||||
rx = sqlite3BtreeMoveto(pC->pCursor, pTos->z, pTos->n, &res);
|
||||
rx = sqlite3BtreeMoveto(pC->pCursor, pTos->z, pTos->n, 0, &res);
|
||||
alreadyExists = rx==SQLITE_OK && res==0;
|
||||
pC->deferredMoveto = 0;
|
||||
pC->cacheStatus = CACHE_STALE;
|
||||
|
@ -2995,7 +2999,7 @@ case OP_IsUnique: { /* no-push */
|
|||
*/
|
||||
assert( pNos>=p->aStack );
|
||||
sqlite3VdbeMemIntegerify(pTos);
|
||||
R = pTos->i;
|
||||
R = pTos->u.i;
|
||||
assert( (pTos->flags & MEM_Dyn)==0 );
|
||||
pTos--;
|
||||
assert( i>=0 && i<p->nCursor );
|
||||
|
@ -3024,7 +3028,7 @@ case OP_IsUnique: { /* no-push */
|
|||
*/
|
||||
assert( pCx->deferredMoveto==0 );
|
||||
pCx->cacheStatus = CACHE_STALE;
|
||||
rc = sqlite3BtreeMoveto(pCrsr, zKey, len, &res);
|
||||
rc = sqlite3BtreeMoveto(pCrsr, zKey, len, 0, &res);
|
||||
if( rc!=SQLITE_OK ){
|
||||
goto abort_due_to_error;
|
||||
}
|
||||
|
@ -3061,7 +3065,7 @@ case OP_IsUnique: { /* no-push */
|
|||
** constraint.)
|
||||
*/
|
||||
pTos++;
|
||||
pTos->i = v;
|
||||
pTos->u.i = v;
|
||||
pTos->flags = MEM_Int;
|
||||
}
|
||||
break;
|
||||
|
@ -3093,15 +3097,17 @@ case OP_NotExists: { /* no-push */
|
|||
u64 iKey;
|
||||
assert( pTos->flags & MEM_Int );
|
||||
assert( p->apCsr[i]->isTable );
|
||||
iKey = intToKey(pTos->i);
|
||||
rc = sqlite3BtreeMoveto(pCrsr, 0, iKey, &res);
|
||||
pC->lastRowid = pTos->i;
|
||||
iKey = intToKey(pTos->u.i);
|
||||
rc = sqlite3BtreeMoveto(pCrsr, 0, iKey, 0,&res);
|
||||
pC->lastRowid = pTos->u.i;
|
||||
pC->rowidIsValid = res==0;
|
||||
pC->nullRow = 0;
|
||||
pC->cacheStatus = CACHE_STALE;
|
||||
/* res might be uninitialized if rc!=SQLITE_OK. But if rc!=SQLITE_OK
|
||||
** processing is about to abort so we really do not care whether or not
|
||||
** the following jump is taken. */
|
||||
** the following jump is taken. (In other words, do not stress over
|
||||
** the error that valgrind sometimes shows on the next statement when
|
||||
** running ioerr.test and similar failure-recovery test scripts.) */
|
||||
if( res!=0 ){
|
||||
pc = pOp->p2 - 1;
|
||||
pC->rowidIsValid = 0;
|
||||
|
@ -3124,7 +3130,7 @@ case OP_Sequence: {
|
|||
assert( i>=0 && i<p->nCursor );
|
||||
assert( p->apCsr[i]!=0 );
|
||||
pTos++;
|
||||
pTos->i = p->apCsr[i]->seqCount++;
|
||||
pTos->u.i = p->apCsr[i]->seqCount++;
|
||||
pTos->flags = MEM_Int;
|
||||
break;
|
||||
}
|
||||
|
@ -3233,14 +3239,14 @@ case OP_NewRowid: {
|
|||
pMem = &p->aMem[pOp->p2];
|
||||
sqlite3VdbeMemIntegerify(pMem);
|
||||
assert( (pMem->flags & MEM_Int)!=0 ); /* mem(P2) holds an integer */
|
||||
if( pMem->i==MAX_ROWID || pC->useRandomRowid ){
|
||||
if( pMem->u.i==MAX_ROWID || pC->useRandomRowid ){
|
||||
rc = SQLITE_FULL;
|
||||
goto abort_due_to_error;
|
||||
}
|
||||
if( v<pMem->i+1 ){
|
||||
v = pMem->i + 1;
|
||||
if( v<pMem->u.i+1 ){
|
||||
v = pMem->u.i + 1;
|
||||
}
|
||||
pMem->i = v;
|
||||
pMem->u.i = v;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -3266,7 +3272,7 @@ case OP_NewRowid: {
|
|||
}
|
||||
if( v==0 ) continue;
|
||||
x = intToKey(v);
|
||||
rx = sqlite3BtreeMoveto(pC->pCursor, 0, (u64)x, &res);
|
||||
rx = sqlite3BtreeMoveto(pC->pCursor, 0, (u64)x, 0, &res);
|
||||
cnt++;
|
||||
}while( cnt<1000 && rx==SQLITE_OK && res==0 );
|
||||
db->priorNewRowid = v;
|
||||
|
@ -3280,7 +3286,7 @@ case OP_NewRowid: {
|
|||
pC->cacheStatus = CACHE_STALE;
|
||||
}
|
||||
pTos++;
|
||||
pTos->i = v;
|
||||
pTos->u.i = v;
|
||||
pTos->flags = MEM_Int;
|
||||
break;
|
||||
}
|
||||
|
@ -3317,11 +3323,11 @@ case OP_Insert: { /* no-push */
|
|||
|
||||
assert( pNos->flags & MEM_Int );
|
||||
assert( pC->isTable );
|
||||
iKey = intToKey(pNos->i);
|
||||
iKey = intToKey(pNos->u.i);
|
||||
|
||||
if( pOp->p2 & OPFLAG_NCHANGE ) p->nChange++;
|
||||
if( pOp->p2 & OPFLAG_LASTROWID ) db->lastRowid = pNos->i;
|
||||
if( pC->nextRowidValid && pNos->i>=pC->nextRowid ){
|
||||
if( pOp->p2 & OPFLAG_LASTROWID ) db->lastRowid = pNos->u.i;
|
||||
if( pC->nextRowidValid && pNos->u.i>=pC->nextRowid ){
|
||||
pC->nextRowidValid = 0;
|
||||
}
|
||||
if( pTos->flags & MEM_Null ){
|
||||
|
@ -3346,7 +3352,9 @@ case OP_Insert: { /* no-push */
|
|||
}
|
||||
pC->nullRow = 0;
|
||||
}else{
|
||||
rc = sqlite3BtreeInsert(pC->pCursor, 0, iKey, pTos->z, pTos->n);
|
||||
rc = sqlite3BtreeInsert(pC->pCursor, 0, iKey,
|
||||
pTos->z, pTos->n,
|
||||
pOp->p2 & OPFLAG_APPEND);
|
||||
}
|
||||
|
||||
pC->rowidIsValid = 0;
|
||||
|
@ -3500,9 +3508,9 @@ case OP_RowData: {
|
|||
pTos->z = z;
|
||||
}
|
||||
if( pC->isIndex ){
|
||||
sqlite3BtreeKey(pCrsr, 0, n, pTos->z);
|
||||
rc = sqlite3BtreeKey(pCrsr, 0, n, pTos->z);
|
||||
}else{
|
||||
sqlite3BtreeData(pCrsr, 0, n, pTos->z);
|
||||
rc = sqlite3BtreeData(pCrsr, 0, n, pTos->z);
|
||||
}
|
||||
}else if( pC->pseudoTable ){
|
||||
pTos->n = pC->nData;
|
||||
|
@ -3543,7 +3551,7 @@ case OP_Rowid: {
|
|||
sqlite3BtreeKeySize(pC->pCursor, &v);
|
||||
v = keyToInt(v);
|
||||
}
|
||||
pTos->i = v;
|
||||
pTos->u.i = v;
|
||||
pTos->flags = MEM_Int;
|
||||
break;
|
||||
}
|
||||
|
@ -3673,7 +3681,9 @@ case OP_Next: { /* no-push */
|
|||
CHECK_FOR_INTERRUPT;
|
||||
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
|
||||
pC = p->apCsr[pOp->p1];
|
||||
assert( pC!=0 );
|
||||
if( pC==0 ){
|
||||
break; /* See ticket #2273 */
|
||||
}
|
||||
if( (pCrsr = pC->pCursor)!=0 ){
|
||||
int res;
|
||||
if( pC->nullRow ){
|
||||
|
@ -3698,12 +3708,15 @@ case OP_Next: { /* no-push */
|
|||
break;
|
||||
}
|
||||
|
||||
/* Opcode: IdxInsert P1 * *
|
||||
/* Opcode: IdxInsert P1 P2 *
|
||||
**
|
||||
** The top of the stack holds a SQL index key made using either the
|
||||
** MakeIdxRec or MakeRecord instructions. This opcode writes that key
|
||||
** into the index P1. Data for the entry is nil.
|
||||
**
|
||||
** P2 is a flag that provides a hint to the b-tree layer that this
|
||||
** insert is likely to be an append.
|
||||
**
|
||||
** This instruction only works for indices. The equivalent instruction
|
||||
** for tables is OP_Insert.
|
||||
*/
|
||||
|
@ -3715,12 +3728,11 @@ case OP_IdxInsert: { /* no-push */
|
|||
assert( i>=0 && i<p->nCursor );
|
||||
assert( p->apCsr[i]!=0 );
|
||||
assert( pTos->flags & MEM_Blob );
|
||||
assert( pOp->p2==0 );
|
||||
if( (pCrsr = (pC = p->apCsr[i])->pCursor)!=0 ){
|
||||
int nKey = pTos->n;
|
||||
const char *zKey = pTos->z;
|
||||
assert( pC->isTable==0 );
|
||||
rc = sqlite3BtreeInsert(pCrsr, zKey, nKey, "", 0);
|
||||
rc = sqlite3BtreeInsert(pCrsr, zKey, nKey, "", 0, pOp->p2);
|
||||
assert( pC->deferredMoveto==0 );
|
||||
pC->cacheStatus = CACHE_STALE;
|
||||
}
|
||||
|
@ -3745,7 +3757,7 @@ case OP_IdxDelete: { /* no-push */
|
|||
assert( p->apCsr[i]!=0 );
|
||||
if( (pCrsr = (pC = p->apCsr[i])->pCursor)!=0 ){
|
||||
int res;
|
||||
rc = sqlite3BtreeMoveto(pCrsr, pTos->z, pTos->n, &res);
|
||||
rc = sqlite3BtreeMoveto(pCrsr, pTos->z, pTos->n, 0, &res);
|
||||
if( rc==SQLITE_OK && res==0 ){
|
||||
rc = sqlite3BtreeDelete(pCrsr);
|
||||
}
|
||||
|
@ -3787,7 +3799,7 @@ case OP_IdxRowid: {
|
|||
goto abort_due_to_error;
|
||||
}
|
||||
pTos->flags = MEM_Int;
|
||||
pTos->i = rowid;
|
||||
pTos->u.i = rowid;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -3914,7 +3926,7 @@ case OP_Destroy: {
|
|||
rc = sqlite3BtreeDropTable(db->aDb[pOp->p2].pBt, pOp->p1, &iMoved);
|
||||
pTos++;
|
||||
pTos->flags = MEM_Int;
|
||||
pTos->i = iMoved;
|
||||
pTos->u.i = iMoved;
|
||||
#ifndef SQLITE_OMIT_AUTOVACUUM
|
||||
if( rc==SQLITE_OK && iMoved!=0 ){
|
||||
sqlite3RootPageMoved(&db->aDb[pOp->p2], iMoved, pOp->p1);
|
||||
|
@ -4013,7 +4025,7 @@ case OP_CreateTable: {
|
|||
rc = sqlite3BtreeCreateTable(pDb->pBt, &pgno, flags);
|
||||
pTos++;
|
||||
if( rc==SQLITE_OK ){
|
||||
pTos->i = pgno;
|
||||
pTos->u.i = pgno;
|
||||
pTos->flags = MEM_Int;
|
||||
}else{
|
||||
pTos->flags = MEM_Null;
|
||||
|
@ -4160,14 +4172,14 @@ case OP_IntegrityCk: {
|
|||
assert( (pnErr->flags & MEM_Int)!=0 );
|
||||
for(j=0; j<nRoot; j++){
|
||||
Mem *pMem = &pTos[-j];
|
||||
aRoot[j] = pMem->i;
|
||||
aRoot[j] = pMem->u.i;
|
||||
}
|
||||
aRoot[j] = 0;
|
||||
popStack(&pTos, nRoot);
|
||||
pTos++;
|
||||
z = sqlite3BtreeIntegrityCheck(db->aDb[pOp->p2].pBt, aRoot, nRoot,
|
||||
pnErr->i, &nErr);
|
||||
pnErr->i -= nErr;
|
||||
pnErr->u.i, &nErr);
|
||||
pnErr->u.i -= nErr;
|
||||
if( nErr==0 ){
|
||||
assert( z==0 );
|
||||
pTos->flags = MEM_Null;
|
||||
|
@ -4192,7 +4204,7 @@ case OP_IntegrityCk: {
|
|||
case OP_FifoWrite: { /* no-push */
|
||||
assert( pTos>=p->aStack );
|
||||
sqlite3VdbeMemIntegerify(pTos);
|
||||
sqlite3VdbeFifoPush(&p->sFifo, pTos->i);
|
||||
sqlite3VdbeFifoPush(&p->sFifo, pTos->u.i);
|
||||
assert( (pTos->flags & MEM_Dyn)==0 );
|
||||
pTos--;
|
||||
break;
|
||||
|
@ -4211,7 +4223,7 @@ case OP_FifoRead: {
|
|||
pc = pOp->p2 - 1;
|
||||
}else{
|
||||
pTos++;
|
||||
pTos->i = v;
|
||||
pTos->u.i = v;
|
||||
pTos->flags = MEM_Int;
|
||||
}
|
||||
break;
|
||||
|
@ -4232,7 +4244,8 @@ case OP_ContextPush: { /* no-push */
|
|||
/* FIX ME: This should be allocated as part of the vdbe at compile-time */
|
||||
if( i>=p->contextStackDepth ){
|
||||
p->contextStackDepth = i+1;
|
||||
sqliteReallocOrFree((void**)&p->contextStack, sizeof(Context)*(i+1));
|
||||
p->contextStack = sqliteReallocOrFree(p->contextStack,
|
||||
sizeof(Context)*(i+1));
|
||||
if( p->contextStack==0 ) goto no_mem;
|
||||
}
|
||||
pContext = &p->contextStack[i];
|
||||
|
@ -4317,8 +4330,8 @@ case OP_MemMax: { /* no-push */
|
|||
pMem = &p->aMem[i];
|
||||
sqlite3VdbeMemIntegerify(pMem);
|
||||
sqlite3VdbeMemIntegerify(pTos);
|
||||
if( pMem->i<pTos->i){
|
||||
pMem->i = pTos->i;
|
||||
if( pMem->u.i<pTos->u.i){
|
||||
pMem->u.i = pTos->u.i;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -4337,7 +4350,7 @@ case OP_MemIncr: { /* no-push */
|
|||
assert( i>=0 && i<p->nMem );
|
||||
pMem = &p->aMem[i];
|
||||
assert( pMem->flags==MEM_Int );
|
||||
pMem->i += pOp->p1;
|
||||
pMem->u.i += pOp->p1;
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -4354,7 +4367,7 @@ case OP_IfMemPos: { /* no-push */
|
|||
assert( i>=0 && i<p->nMem );
|
||||
pMem = &p->aMem[i];
|
||||
assert( pMem->flags==MEM_Int );
|
||||
if( pMem->i>0 ){
|
||||
if( pMem->u.i>0 ){
|
||||
pc = pOp->p2 - 1;
|
||||
}
|
||||
break;
|
||||
|
@ -4373,7 +4386,7 @@ case OP_IfMemNeg: { /* no-push */
|
|||
assert( i>=0 && i<p->nMem );
|
||||
pMem = &p->aMem[i];
|
||||
assert( pMem->flags==MEM_Int );
|
||||
if( pMem->i<0 ){
|
||||
if( pMem->u.i<0 ){
|
||||
pc = pOp->p2 - 1;
|
||||
}
|
||||
break;
|
||||
|
@ -4392,7 +4405,7 @@ case OP_IfMemZero: { /* no-push */
|
|||
assert( i>=0 && i<p->nMem );
|
||||
pMem = &p->aMem[i];
|
||||
assert( pMem->flags==MEM_Int );
|
||||
if( pMem->i==0 ){
|
||||
if( pMem->u.i==0 ){
|
||||
pc = pOp->p2 - 1;
|
||||
}
|
||||
break;
|
||||
|
@ -4506,7 +4519,7 @@ case OP_AggFinal: { /* no-push */
|
|||
}
|
||||
|
||||
|
||||
#ifndef SQLITE_OMIT_VACUUM
|
||||
#if !defined(SQLITE_OMIT_VACUUM) && !defined(SQLITE_OMIT_ATTACH)
|
||||
/* Opcode: Vacuum * * *
|
||||
**
|
||||
** Vacuum the entire database. This opcode will cause other virtual
|
||||
|
@ -4679,7 +4692,7 @@ case OP_VFilter: { /* no-push */
|
|||
/* Grab the index number and argc parameters off the top of the stack. */
|
||||
assert( (&pTos[-1])>=p->aStack );
|
||||
assert( (pTos[0].flags&MEM_Int)!=0 && pTos[-1].flags==MEM_Int );
|
||||
nArg = pTos[-1].i;
|
||||
nArg = pTos[-1].u.i;
|
||||
|
||||
/* Invoke the xFilter method */
|
||||
{
|
||||
|
@ -4693,7 +4706,7 @@ case OP_VFilter: { /* no-push */
|
|||
|
||||
if( sqlite3SafetyOff(db) ) goto abort_due_to_misuse;
|
||||
p->inVtabMethod = 1;
|
||||
rc = pModule->xFilter(pCur->pVtabCursor, pTos->i, pOp->p3, nArg, apArg);
|
||||
rc = pModule->xFilter(pCur->pVtabCursor, pTos->u.i, pOp->p3, nArg, apArg);
|
||||
p->inVtabMethod = 0;
|
||||
if( rc==SQLITE_OK ){
|
||||
res = pModule->xEof(pCur->pVtabCursor);
|
||||
|
@ -4735,7 +4748,7 @@ case OP_VRowid: {
|
|||
|
||||
pTos++;
|
||||
pTos->flags = MEM_Int;
|
||||
pTos->i = iRow;
|
||||
pTos->u.i = iRow;
|
||||
}
|
||||
|
||||
break;
|
||||
|
@ -4934,9 +4947,9 @@ default: {
|
|||
if( pTos[i].flags & MEM_Null ){
|
||||
fprintf(p->trace, " NULL");
|
||||
}else if( (pTos[i].flags & (MEM_Int|MEM_Str))==(MEM_Int|MEM_Str) ){
|
||||
fprintf(p->trace, " si:%lld", pTos[i].i);
|
||||
fprintf(p->trace, " si:%lld", pTos[i].u.i);
|
||||
}else if( pTos[i].flags & MEM_Int ){
|
||||
fprintf(p->trace, " i:%lld", pTos[i].i);
|
||||
fprintf(p->trace, " i:%lld", pTos[i].u.i);
|
||||
}else if( pTos[i].flags & MEM_Real ){
|
||||
fprintf(p->trace, " r:%g", pTos[i].r);
|
||||
}else{
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
** array is defined in a separate source code file named opcode.c which is
|
||||
** automatically generated by the makefile.
|
||||
*/
|
||||
extern char *sqlite3OpcodeNames[];
|
||||
extern const char *const sqlite3OpcodeNames[];
|
||||
|
||||
/*
|
||||
** SQL is translated into a sequence of instructions to be
|
||||
|
@ -125,7 +125,10 @@ typedef struct Cursor Cursor;
|
|||
** SQLITE_BLOB.
|
||||
*/
|
||||
struct Mem {
|
||||
i64 i; /* Integer value. Or FuncDef* when flags==MEM_Agg */
|
||||
union {
|
||||
i64 i; /* Integer value. Or FuncDef* when flags==MEM_Agg */
|
||||
FuncDef *pDef; /* Used only when flags==MEM_Agg */
|
||||
} u;
|
||||
double r; /* Real value */
|
||||
char *z; /* String or BLOB value */
|
||||
int n; /* Number of characters in string value, including '\0' */
|
||||
|
|
|
@ -341,7 +341,7 @@ void *sqlite3_aggregate_context(sqlite3_context *p, int nByte){
|
|||
}else{
|
||||
pMem->flags = MEM_Agg;
|
||||
pMem->xDel = sqlite3FreeX;
|
||||
*(FuncDef**)&pMem->i = p->pFunc;
|
||||
pMem->u.pDef = p->pFunc;
|
||||
if( nByte<=NBFS ){
|
||||
pMem->z = pMem->zShort;
|
||||
memset(pMem->z, 0, nByte);
|
||||
|
@ -443,7 +443,7 @@ static Mem *columnMem(sqlite3_stmt *pStmt, int i){
|
|||
Vdbe *pVm = (Vdbe *)pStmt;
|
||||
int vals = sqlite3_data_count(pStmt);
|
||||
if( i>=vals || i<0 ){
|
||||
static const Mem nullMem = {0, 0.0, "", 0, MEM_Null, MEM_Null };
|
||||
static const Mem nullMem = {{0}, 0.0, "", 0, MEM_Null, MEM_Null };
|
||||
sqlite3Error(pVm->db, SQLITE_RANGE, 0);
|
||||
return (Mem*)&nullMem;
|
||||
}
|
||||
|
|
|
@ -195,8 +195,8 @@ int sqlite3VdbeMakeLabel(Vdbe *p){
|
|||
assert( p->magic==VDBE_MAGIC_INIT );
|
||||
if( i>=p->nLabelAlloc ){
|
||||
p->nLabelAlloc = p->nLabelAlloc*2 + 10;
|
||||
sqliteReallocOrFree((void**)&p->aLabel,
|
||||
p->nLabelAlloc*sizeof(p->aLabel[0]));
|
||||
p->aLabel = sqliteReallocOrFree(p->aLabel,
|
||||
p->nLabelAlloc*sizeof(p->aLabel[0]));
|
||||
}
|
||||
if( p->aLabel ){
|
||||
p->aLabel[i] = -1;
|
||||
|
@ -719,11 +719,11 @@ int sqlite3VdbeList(
|
|||
Mem *pMem = p->aStack;
|
||||
pMem->flags = MEM_Int;
|
||||
pMem->type = SQLITE_INTEGER;
|
||||
pMem->i = i; /* Program counter */
|
||||
pMem->u.i = i; /* Program counter */
|
||||
pMem++;
|
||||
|
||||
pMem->flags = MEM_Static|MEM_Str|MEM_Term;
|
||||
pMem->z = sqlite3OpcodeNames[pOp->opcode]; /* Opcode */
|
||||
pMem->z = (char*)sqlite3OpcodeNames[pOp->opcode]; /* Opcode */
|
||||
assert( pMem->z!=0 );
|
||||
pMem->n = strlen(pMem->z);
|
||||
pMem->type = SQLITE_TEXT;
|
||||
|
@ -731,12 +731,12 @@ int sqlite3VdbeList(
|
|||
pMem++;
|
||||
|
||||
pMem->flags = MEM_Int;
|
||||
pMem->i = pOp->p1; /* P1 */
|
||||
pMem->u.i = pOp->p1; /* P1 */
|
||||
pMem->type = SQLITE_INTEGER;
|
||||
pMem++;
|
||||
|
||||
pMem->flags = MEM_Int;
|
||||
pMem->i = pOp->p2; /* P2 */
|
||||
pMem->u.i = pOp->p2; /* P2 */
|
||||
pMem->type = SQLITE_INTEGER;
|
||||
pMem++;
|
||||
|
||||
|
@ -757,11 +757,11 @@ int sqlite3VdbeList(
|
|||
}
|
||||
#endif /* SQLITE_OMIT_EXPLAIN */
|
||||
|
||||
#ifdef SQLITE_DEBUG
|
||||
/*
|
||||
** Print the SQL that was used to generate a VDBE program.
|
||||
*/
|
||||
void sqlite3VdbePrintSql(Vdbe *p){
|
||||
#ifdef SQLITE_DEBUG
|
||||
int nOp = p->nOp;
|
||||
VdbeOp *pOp;
|
||||
if( nOp<1 ) return;
|
||||
|
@ -771,8 +771,39 @@ void sqlite3VdbePrintSql(Vdbe *p){
|
|||
while( isspace(*(u8*)z) ) z++;
|
||||
printf("SQL: [%s]\n", z);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !defined(SQLITE_OMIT_TRACE) && defined(SQLITE_ENABLE_IOTRACE)
|
||||
/*
|
||||
** Print an IOTRACE message showing SQL content.
|
||||
*/
|
||||
void sqlite3VdbeIOTraceSql(Vdbe *p){
|
||||
int nOp = p->nOp;
|
||||
VdbeOp *pOp;
|
||||
if( sqlite3_io_trace==0 ) return;
|
||||
if( nOp<1 ) return;
|
||||
pOp = &p->aOp[nOp-1];
|
||||
if( pOp->opcode==OP_Noop && pOp->p3!=0 ){
|
||||
char *z = sqlite3StrDup(pOp->p3);
|
||||
int i, j;
|
||||
for(i=0; isspace(z[i]); i++){}
|
||||
for(j=0; z[i]; i++){
|
||||
if( isspace(z[i]) ){
|
||||
if( z[i-1]!=' ' ){
|
||||
z[j++] = ' ';
|
||||
}
|
||||
}else{
|
||||
z[j++] = z[i];
|
||||
}
|
||||
}
|
||||
z[j] = 0;
|
||||
sqlite3_io_trace("SQL %s\n", z);
|
||||
sqliteFree(z);
|
||||
}
|
||||
}
|
||||
#endif /* !SQLITE_OMIT_TRACE && SQLITE_ENABLE_IOTRACE */
|
||||
|
||||
|
||||
/*
|
||||
** Prepare a virtual machine for execution. This involves things such
|
||||
|
@ -1059,18 +1090,22 @@ static int vdbeCommit(sqlite3 *db){
|
|||
for(i=0; rc==SQLITE_OK && i<db->nDb; i++){
|
||||
Btree *pBt = db->aDb[i].pBt;
|
||||
if( pBt ){
|
||||
rc = sqlite3BtreeSync(pBt, 0);
|
||||
rc = sqlite3BtreeCommitPhaseOne(pBt, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/* Do the commit only if all databases successfully synced */
|
||||
if( rc==SQLITE_OK ){
|
||||
for(i=0; i<db->nDb; i++){
|
||||
Btree *pBt = db->aDb[i].pBt;
|
||||
if( pBt ){
|
||||
sqlite3BtreeCommit(pBt);
|
||||
}
|
||||
/* Do the commit only if all databases successfully complete phase 1.
|
||||
** If one of the BtreeCommitPhaseOne() calls fails, this indicates an
|
||||
** IO error while deleting or truncating a journal file. It is unlikely,
|
||||
** but could happen. In this case abandon processing and return the error.
|
||||
*/
|
||||
for(i=0; rc==SQLITE_OK && i<db->nDb; i++){
|
||||
Btree *pBt = db->aDb[i].pBt;
|
||||
if( pBt ){
|
||||
rc = sqlite3BtreeCommitPhaseTwo(pBt);
|
||||
}
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
sqlite3VtabCommit(db);
|
||||
}
|
||||
}
|
||||
|
@ -1147,16 +1182,16 @@ static int vdbeCommit(sqlite3 *db){
|
|||
** sets the master journal pointer in each individual journal. If
|
||||
** an error occurs here, do not delete the master journal file.
|
||||
**
|
||||
** If the error occurs during the first call to sqlite3BtreeSync(),
|
||||
** then there is a chance that the master journal file will be
|
||||
** orphaned. But we cannot delete it, in case the master journal
|
||||
** file name was written into the journal file before the failure
|
||||
** occured.
|
||||
** If the error occurs during the first call to
|
||||
** sqlite3BtreeCommitPhaseOne(), then there is a chance that the
|
||||
** master journal file will be orphaned. But we cannot delete it,
|
||||
** in case the master journal file name was written into the journal
|
||||
** file before the failure occured.
|
||||
*/
|
||||
for(i=0; rc==SQLITE_OK && i<db->nDb; i++){
|
||||
Btree *pBt = db->aDb[i].pBt;
|
||||
if( pBt && sqlite3BtreeIsInTrans(pBt) ){
|
||||
rc = sqlite3BtreeSync(pBt, zMaster);
|
||||
rc = sqlite3BtreeCommitPhaseOne(pBt, zMaster);
|
||||
}
|
||||
}
|
||||
sqlite3OsClose(&master);
|
||||
|
@ -1170,11 +1205,11 @@ static int vdbeCommit(sqlite3 *db){
|
|||
** transaction files are deleted.
|
||||
*/
|
||||
rc = sqlite3OsDelete(zMaster);
|
||||
sqliteFree(zMaster);
|
||||
zMaster = 0;
|
||||
if( rc ){
|
||||
return rc;
|
||||
}
|
||||
sqliteFree(zMaster);
|
||||
zMaster = 0;
|
||||
rc = sqlite3OsSyncDirectory(zMainFile);
|
||||
if( rc!=SQLITE_OK ){
|
||||
/* This is not good. The master journal file has been deleted, but
|
||||
|
@ -1188,18 +1223,21 @@ static int vdbeCommit(sqlite3 *db){
|
|||
}
|
||||
|
||||
/* All files and directories have already been synced, so the following
|
||||
** calls to sqlite3BtreeCommit() are only closing files and deleting
|
||||
** journals. If something goes wrong while this is happening we don't
|
||||
** really care. The integrity of the transaction is already guaranteed,
|
||||
** but some stray 'cold' journals may be lying around. Returning an
|
||||
** error code won't help matters.
|
||||
** calls to sqlite3BtreeCommitPhaseTwo() are only closing files and
|
||||
** deleting or truncating journals. If something goes wrong while
|
||||
** this is happening we don't really care. The integrity of the
|
||||
** transaction is already guaranteed, but some stray 'cold' journals
|
||||
** may be lying around. Returning an error code won't help matters.
|
||||
*/
|
||||
disable_simulated_io_errors();
|
||||
for(i=0; i<db->nDb; i++){
|
||||
Btree *pBt = db->aDb[i].pBt;
|
||||
if( pBt ){
|
||||
sqlite3BtreeCommit(pBt);
|
||||
sqlite3BtreeCommitPhaseTwo(pBt);
|
||||
}
|
||||
}
|
||||
enable_simulated_io_errors();
|
||||
|
||||
sqlite3VtabCommit(db);
|
||||
}
|
||||
#endif
|
||||
|
@ -1470,10 +1508,6 @@ void sqlite3VdbeResetStepResult(Vdbe *p){
|
|||
*/
|
||||
int sqlite3VdbeReset(Vdbe *p){
|
||||
sqlite3 *db;
|
||||
if( p->magic!=VDBE_MAGIC_RUN && p->magic!=VDBE_MAGIC_HALT ){
|
||||
sqlite3Error(p->db, SQLITE_MISUSE, 0);
|
||||
return SQLITE_MISUSE;
|
||||
}
|
||||
db = p->db;
|
||||
|
||||
/* If the VM did not run to completion or if it encountered an
|
||||
|
@ -1624,12 +1658,7 @@ int sqlite3VdbeCursorMoveto(Cursor *p){
|
|||
extern int sqlite3_search_count;
|
||||
#endif
|
||||
assert( p->isTable );
|
||||
if( p->isTable ){
|
||||
rc = sqlite3BtreeMoveto(p->pCursor, 0, p->movetoTarget, &res);
|
||||
}else{
|
||||
rc = sqlite3BtreeMoveto(p->pCursor,(char*)&p->movetoTarget,
|
||||
sizeof(i64),&res);
|
||||
}
|
||||
rc = sqlite3BtreeMoveto(p->pCursor, 0, p->movetoTarget, 0, &res);
|
||||
if( rc ) return rc;
|
||||
*p->pIncrKey = 0;
|
||||
p->lastRowid = keyToInt(p->movetoTarget);
|
||||
|
@ -1701,7 +1730,7 @@ u32 sqlite3VdbeSerialType(Mem *pMem, int file_format){
|
|||
if( flags&MEM_Int ){
|
||||
/* Figure out whether to use 1, 2, 4, 6 or 8 bytes. */
|
||||
# define MAX_6BYTE ((((i64)0x00001000)<<32)-1)
|
||||
i64 i = pMem->i;
|
||||
i64 i = pMem->u.i;
|
||||
u64 u;
|
||||
if( file_format>=4 && (i&1)==i ){
|
||||
return 8+i;
|
||||
|
@ -1722,10 +1751,8 @@ u32 sqlite3VdbeSerialType(Mem *pMem, int file_format){
|
|||
assert( n>=0 );
|
||||
return ((n*2) + 13);
|
||||
}
|
||||
if( flags&MEM_Blob ){
|
||||
return (pMem->n*2 + 12);
|
||||
}
|
||||
return 0;
|
||||
assert( (flags & MEM_Blob)!=0 );
|
||||
return (pMem->n*2 + 12);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1754,9 +1781,10 @@ int sqlite3VdbeSerialPut(unsigned char *buf, Mem *pMem, int file_format){
|
|||
u64 v;
|
||||
int i;
|
||||
if( serial_type==7 ){
|
||||
v = *(u64*)&pMem->r;
|
||||
assert( sizeof(v)==sizeof(pMem->r) );
|
||||
memcpy(&v, &pMem->r, sizeof(v));
|
||||
}else{
|
||||
v = *(u64*)&pMem->i;
|
||||
v = pMem->u.i;
|
||||
}
|
||||
len = i = sqlite3VdbeSerialTypeLen(serial_type);
|
||||
while( i-- ){
|
||||
|
@ -1794,22 +1822,22 @@ int sqlite3VdbeSerialGet(
|
|||
break;
|
||||
}
|
||||
case 1: { /* 1-byte signed integer */
|
||||
pMem->i = (signed char)buf[0];
|
||||
pMem->u.i = (signed char)buf[0];
|
||||
pMem->flags = MEM_Int;
|
||||
return 1;
|
||||
}
|
||||
case 2: { /* 2-byte signed integer */
|
||||
pMem->i = (((signed char)buf[0])<<8) | buf[1];
|
||||
pMem->u.i = (((signed char)buf[0])<<8) | buf[1];
|
||||
pMem->flags = MEM_Int;
|
||||
return 2;
|
||||
}
|
||||
case 3: { /* 3-byte signed integer */
|
||||
pMem->i = (((signed char)buf[0])<<16) | (buf[1]<<8) | buf[2];
|
||||
pMem->u.i = (((signed char)buf[0])<<16) | (buf[1]<<8) | buf[2];
|
||||
pMem->flags = MEM_Int;
|
||||
return 3;
|
||||
}
|
||||
case 4: { /* 4-byte signed integer */
|
||||
pMem->i = (buf[0]<<24) | (buf[1]<<16) | (buf[2]<<8) | buf[3];
|
||||
pMem->u.i = (buf[0]<<24) | (buf[1]<<16) | (buf[2]<<8) | buf[3];
|
||||
pMem->flags = MEM_Int;
|
||||
return 4;
|
||||
}
|
||||
|
@ -1817,7 +1845,7 @@ int sqlite3VdbeSerialGet(
|
|||
u64 x = (((signed char)buf[0])<<8) | buf[1];
|
||||
u32 y = (buf[2]<<24) | (buf[3]<<16) | (buf[4]<<8) | buf[5];
|
||||
x = (x<<32) | y;
|
||||
pMem->i = *(i64*)&x;
|
||||
pMem->u.i = *(i64*)&x;
|
||||
pMem->flags = MEM_Int;
|
||||
return 6;
|
||||
}
|
||||
|
@ -1830,24 +1858,27 @@ int sqlite3VdbeSerialGet(
|
|||
** byte order. The byte order differs on some (broken) architectures.
|
||||
*/
|
||||
static const u64 t1 = ((u64)0x3ff00000)<<32;
|
||||
assert( 1.0==*(double*)&t1 );
|
||||
static const double r1 = 1.0;
|
||||
assert( sizeof(r1)==sizeof(t1) && memcmp(&r1, &t1, sizeof(r1))==0 );
|
||||
#endif
|
||||
|
||||
x = (buf[0]<<24) | (buf[1]<<16) | (buf[2]<<8) | buf[3];
|
||||
y = (buf[4]<<24) | (buf[5]<<16) | (buf[6]<<8) | buf[7];
|
||||
x = (x<<32) | y;
|
||||
if( serial_type==6 ){
|
||||
pMem->i = *(i64*)&x;
|
||||
pMem->u.i = *(i64*)&x;
|
||||
pMem->flags = MEM_Int;
|
||||
}else{
|
||||
pMem->r = *(double*)&x;
|
||||
assert( sizeof(x)==8 && sizeof(pMem->r)==8 );
|
||||
memcpy(&pMem->r, &x, sizeof(x));
|
||||
/* pMem->r = *(double*)&x; */
|
||||
pMem->flags = MEM_Real;
|
||||
}
|
||||
return 8;
|
||||
}
|
||||
case 8: /* Integer 0 */
|
||||
case 9: { /* Integer 1 */
|
||||
pMem->i = serial_type-8;
|
||||
pMem->u.i = serial_type-8;
|
||||
pMem->flags = MEM_Int;
|
||||
return 0;
|
||||
}
|
||||
|
@ -1984,7 +2015,7 @@ int sqlite3VdbeIdxRowidLen(const u8 *aKey){
|
|||
** Return SQLITE_OK if everything works, or an error code otherwise.
|
||||
*/
|
||||
int sqlite3VdbeIdxRowid(BtCursor *pCur, i64 *rowid){
|
||||
i64 nCellKey;
|
||||
i64 nCellKey = 0;
|
||||
int rc;
|
||||
u32 szHdr; /* Size of the header */
|
||||
u32 typeRowid; /* Serial type of the rowid */
|
||||
|
@ -2003,7 +2034,7 @@ int sqlite3VdbeIdxRowid(BtCursor *pCur, i64 *rowid){
|
|||
sqlite3GetVarint32((u8*)&m.z[szHdr-1], &typeRowid);
|
||||
lenRowid = sqlite3VdbeSerialTypeLen(typeRowid);
|
||||
sqlite3VdbeSerialGet((u8*)&m.z[m.n-lenRowid], typeRowid, &v);
|
||||
*rowid = v.i;
|
||||
*rowid = v.u.i;
|
||||
sqlite3VdbeMemRelease(&m);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
@ -2023,7 +2054,7 @@ int sqlite3VdbeIdxKeyCompare(
|
|||
int nKey, const u8 *pKey, /* The key to compare */
|
||||
int *res /* Write the comparison result here */
|
||||
){
|
||||
i64 nCellKey;
|
||||
i64 nCellKey = 0;
|
||||
int rc;
|
||||
BtCursor *pCur = pC->pCursor;
|
||||
int lenRowid;
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
** Allocate a new FifoPage and return a pointer to it. Return NULL if
|
||||
** we run out of memory. Leave space on the page for nEntry entries.
|
||||
*/
|
||||
static FifoPage *allocatePage(int nEntry){
|
||||
static FifoPage *allocateFifoPage(int nEntry){
|
||||
FifoPage *pPage;
|
||||
if( nEntry>32767 ){
|
||||
nEntry = 32767;
|
||||
|
@ -50,12 +50,12 @@ int sqlite3VdbeFifoPush(Fifo *pFifo, i64 val){
|
|||
FifoPage *pPage;
|
||||
pPage = pFifo->pLast;
|
||||
if( pPage==0 ){
|
||||
pPage = pFifo->pLast = pFifo->pFirst = allocatePage(20);
|
||||
pPage = pFifo->pLast = pFifo->pFirst = allocateFifoPage(20);
|
||||
if( pPage==0 ){
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
}else if( pPage->iWrite>=pPage->nSlot ){
|
||||
pPage->pNext = allocatePage(pFifo->nEntry);
|
||||
pPage->pNext = allocateFifoPage(pFifo->nEntry);
|
||||
if( pPage->pNext==0 ){
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
|
|
|
@ -170,7 +170,7 @@ int sqlite3VdbeMemStringify(Mem *pMem, int enc){
|
|||
** FIX ME: It would be better if sqlite3_snprintf() could do UTF-16.
|
||||
*/
|
||||
if( fg & MEM_Int ){
|
||||
sqlite3_snprintf(NBFS, z, "%lld", pMem->i);
|
||||
sqlite3_snprintf(NBFS, z, "%lld", pMem->u.i);
|
||||
}else{
|
||||
assert( fg & MEM_Real );
|
||||
sqlite3_snprintf(NBFS, z, "%!.15g", pMem->r);
|
||||
|
@ -195,7 +195,7 @@ int sqlite3VdbeMemFinalize(Mem *pMem, FuncDef *pFunc){
|
|||
int rc = SQLITE_OK;
|
||||
if( pFunc && pFunc->xFinalize ){
|
||||
sqlite3_context ctx;
|
||||
assert( (pMem->flags & MEM_Null)!=0 || pFunc==*(FuncDef**)&pMem->i );
|
||||
assert( (pMem->flags & MEM_Null)!=0 || pFunc==pMem->u.pDef );
|
||||
ctx.s.flags = MEM_Null;
|
||||
ctx.s.z = pMem->zShort;
|
||||
ctx.pMem = pMem;
|
||||
|
@ -225,7 +225,7 @@ void sqlite3VdbeMemRelease(Mem *p){
|
|||
if( p->flags & (MEM_Dyn|MEM_Agg) ){
|
||||
if( p->xDel ){
|
||||
if( p->flags & MEM_Agg ){
|
||||
sqlite3VdbeMemFinalize(p, *(FuncDef**)&p->i);
|
||||
sqlite3VdbeMemFinalize(p, p->u.pDef);
|
||||
assert( (p->flags & MEM_Agg)==0 );
|
||||
sqlite3VdbeMemRelease(p);
|
||||
}else{
|
||||
|
@ -252,7 +252,7 @@ void sqlite3VdbeMemRelease(Mem *p){
|
|||
i64 sqlite3VdbeIntValue(Mem *pMem){
|
||||
int flags = pMem->flags;
|
||||
if( flags & MEM_Int ){
|
||||
return pMem->i;
|
||||
return pMem->u.i;
|
||||
}else if( flags & MEM_Real ){
|
||||
return (i64)pMem->r;
|
||||
}else if( flags & (MEM_Str|MEM_Blob) ){
|
||||
|
@ -279,7 +279,7 @@ double sqlite3VdbeRealValue(Mem *pMem){
|
|||
if( pMem->flags & MEM_Real ){
|
||||
return pMem->r;
|
||||
}else if( pMem->flags & MEM_Int ){
|
||||
return (double)pMem->i;
|
||||
return (double)pMem->u.i;
|
||||
}else if( pMem->flags & (MEM_Str|MEM_Blob) ){
|
||||
double val = 0.0;
|
||||
if( sqlite3VdbeChangeEncoding(pMem, SQLITE_UTF8)
|
||||
|
@ -300,8 +300,8 @@ double sqlite3VdbeRealValue(Mem *pMem){
|
|||
*/
|
||||
void sqlite3VdbeIntegerAffinity(Mem *pMem){
|
||||
assert( pMem->flags & MEM_Real );
|
||||
pMem->i = pMem->r;
|
||||
if( ((double)pMem->i)==pMem->r ){
|
||||
pMem->u.i = pMem->r;
|
||||
if( ((double)pMem->u.i)==pMem->r ){
|
||||
pMem->flags |= MEM_Int;
|
||||
}
|
||||
}
|
||||
|
@ -310,7 +310,7 @@ void sqlite3VdbeIntegerAffinity(Mem *pMem){
|
|||
** Convert pMem to type integer. Invalidate any prior representations.
|
||||
*/
|
||||
int sqlite3VdbeMemIntegerify(Mem *pMem){
|
||||
pMem->i = sqlite3VdbeIntValue(pMem);
|
||||
pMem->u.i = sqlite3VdbeIntValue(pMem);
|
||||
sqlite3VdbeMemRelease(pMem);
|
||||
pMem->flags = MEM_Int;
|
||||
return SQLITE_OK;
|
||||
|
@ -353,7 +353,7 @@ void sqlite3VdbeMemSetNull(Mem *pMem){
|
|||
*/
|
||||
void sqlite3VdbeMemSetInt64(Mem *pMem, i64 val){
|
||||
sqlite3VdbeMemRelease(pMem);
|
||||
pMem->i = val;
|
||||
pMem->u.i = val;
|
||||
pMem->flags = MEM_Int;
|
||||
pMem->type = SQLITE_INTEGER;
|
||||
}
|
||||
|
@ -538,12 +538,12 @@ int sqlite3MemCompare(const Mem *pMem1, const Mem *pMem2, const CollSeq *pColl){
|
|||
if( (f1 & f2 & MEM_Int)==0 ){
|
||||
double r1, r2;
|
||||
if( (f1&MEM_Real)==0 ){
|
||||
r1 = pMem1->i;
|
||||
r1 = pMem1->u.i;
|
||||
}else{
|
||||
r1 = pMem1->r;
|
||||
}
|
||||
if( (f2&MEM_Real)==0 ){
|
||||
r2 = pMem2->i;
|
||||
r2 = pMem2->u.i;
|
||||
}else{
|
||||
r2 = pMem2->r;
|
||||
}
|
||||
|
@ -553,8 +553,8 @@ int sqlite3MemCompare(const Mem *pMem1, const Mem *pMem2, const CollSeq *pColl){
|
|||
}else{
|
||||
assert( f1&MEM_Int );
|
||||
assert( f2&MEM_Int );
|
||||
if( pMem1->i < pMem2->i ) return -1;
|
||||
if( pMem1->i > pMem2->i ) return 1;
|
||||
if( pMem1->u.i < pMem2->u.i ) return -1;
|
||||
if( pMem1->u.i > pMem2->u.i ) return 1;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
@ -637,14 +637,15 @@ int sqlite3VdbeMemFromBtree(
|
|||
int key, /* If true, retrieve from the btree key, not data. */
|
||||
Mem *pMem /* OUT: Return data in this Mem structure. */
|
||||
){
|
||||
char *zData; /* Data from the btree layer */
|
||||
int available; /* Number of bytes available on the local btree page */
|
||||
char *zData; /* Data from the btree layer */
|
||||
int available = 0; /* Number of bytes available on the local btree page */
|
||||
|
||||
if( key ){
|
||||
zData = (char *)sqlite3BtreeKeyFetch(pCur, &available);
|
||||
}else{
|
||||
zData = (char *)sqlite3BtreeDataFetch(pCur, &available);
|
||||
}
|
||||
assert( zData!=0 );
|
||||
|
||||
pMem->n = amt;
|
||||
if( offset+amt<=available ){
|
||||
|
@ -735,7 +736,7 @@ void sqlite3VdbeMemSanity(Mem *pMem){
|
|||
|| (pMem->flags&MEM_Null)==0 );
|
||||
/* If the MEM is both real and integer, the values are equal */
|
||||
assert( (pMem->flags & (MEM_Int|MEM_Real))!=(MEM_Int|MEM_Real)
|
||||
|| pMem->r==pMem->i );
|
||||
|| pMem->r==pMem->u.i );
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -831,7 +832,7 @@ int sqlite3ValueFromExpr(
|
|||
}
|
||||
}else if( op==TK_UMINUS ) {
|
||||
if( SQLITE_OK==sqlite3ValueFromExpr(pExpr->pLeft, enc, affinity, &pVal) ){
|
||||
pVal->i = -1 * pVal->i;
|
||||
pVal->u.i = -1 * pVal->u.i;
|
||||
pVal->r = -1.0 * pVal->r;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,9 +35,9 @@
|
|||
*/
|
||||
#if defined(SQLITE_TEST) || defined(SQLITE_DEBUG)
|
||||
int sqlite3_where_trace = 0;
|
||||
# define TRACE(X) if(sqlite3_where_trace) sqlite3DebugPrintf X
|
||||
# define WHERETRACE(X) if(sqlite3_where_trace) sqlite3DebugPrintf X
|
||||
#else
|
||||
# define TRACE(X)
|
||||
# define WHERETRACE(X)
|
||||
#endif
|
||||
|
||||
/* Forward reference
|
||||
|
@ -220,6 +220,9 @@ static void whereClauseClear(WhereClause *pWC){
|
|||
** Add a new entries to the WhereClause structure. Increase the allocated
|
||||
** space as necessary.
|
||||
**
|
||||
** If the flags argument includes TERM_DYNAMIC, then responsibility
|
||||
** for freeing the expression p is assumed by the WhereClause object.
|
||||
**
|
||||
** WARNING: This routine might reallocate the space used to store
|
||||
** WhereTerms. All pointers to WhereTerms should be invalided after
|
||||
** calling this routine. Such pointers may be reinitialized by referencing
|
||||
|
@ -231,7 +234,12 @@ static int whereClauseInsert(WhereClause *pWC, Expr *p, int flags){
|
|||
if( pWC->nTerm>=pWC->nSlot ){
|
||||
WhereTerm *pOld = pWC->a;
|
||||
pWC->a = sqliteMalloc( sizeof(pWC->a[0])*pWC->nSlot*2 );
|
||||
if( pWC->a==0 ) return 0;
|
||||
if( pWC->a==0 ){
|
||||
if( flags & TERM_DYNAMIC ){
|
||||
sqlite3ExprDelete(p);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
memcpy(pWC->a, pOld, sizeof(pWC->a[0])*pWC->nTerm);
|
||||
if( pOld!=pWC->aStatic ){
|
||||
sqliteFree(pOld);
|
||||
|
@ -523,6 +531,10 @@ static int isLikeOrGlob(
|
|||
}
|
||||
pColl = pLeft->pColl;
|
||||
if( pColl==0 ){
|
||||
/* TODO: Coverage testing doesn't get this case. Is it actually possible
|
||||
** for an expression of type TK_COLUMN to not have an assigned collation
|
||||
** sequence at this point?
|
||||
*/
|
||||
pColl = db->pDfltColl;
|
||||
}
|
||||
if( (pColl->type!=SQLITE_COLL_BINARY || noCase) &&
|
||||
|
@ -582,6 +594,92 @@ static void transferJoinMarkings(Expr *pDerived, Expr *pBase){
|
|||
pDerived->iRightJoinTable = pBase->iRightJoinTable;
|
||||
}
|
||||
|
||||
#if !defined(SQLITE_OMIT_OR_OPTIMIZATION) && !defined(SQLITE_OMIT_SUBQUERY)
|
||||
/*
|
||||
** Return TRUE if the given term of an OR clause can be converted
|
||||
** into an IN clause. The iCursor and iColumn define the left-hand
|
||||
** side of the IN clause.
|
||||
**
|
||||
** The context is that we have multiple OR-connected equality terms
|
||||
** like this:
|
||||
**
|
||||
** a=<expr1> OR a=<expr2> OR b=<expr3> OR ...
|
||||
**
|
||||
** The pOrTerm input to this routine corresponds to a single term of
|
||||
** this OR clause. In order for the term to be a condidate for
|
||||
** conversion to an IN operator, the following must be true:
|
||||
**
|
||||
** * The left-hand side of the term must be the column which
|
||||
** is identified by iCursor and iColumn.
|
||||
**
|
||||
** * If the right-hand side is also a column, then the affinities
|
||||
** of both right and left sides must be such that no type
|
||||
** conversions are required on the right. (Ticket #2249)
|
||||
**
|
||||
** If both of these conditions are true, then return true. Otherwise
|
||||
** return false.
|
||||
*/
|
||||
static int orTermIsOptCandidate(WhereTerm *pOrTerm, int iCursor, int iColumn){
|
||||
int affLeft, affRight;
|
||||
assert( pOrTerm->eOperator==WO_EQ );
|
||||
if( pOrTerm->leftCursor!=iCursor ){
|
||||
return 0;
|
||||
}
|
||||
if( pOrTerm->leftColumn!=iColumn ){
|
||||
return 0;
|
||||
}
|
||||
affRight = sqlite3ExprAffinity(pOrTerm->pExpr->pRight);
|
||||
if( affRight==0 ){
|
||||
return 1;
|
||||
}
|
||||
affLeft = sqlite3ExprAffinity(pOrTerm->pExpr->pLeft);
|
||||
if( affRight!=affLeft ){
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return true if the given term of an OR clause can be ignored during
|
||||
** a check to make sure all OR terms are candidates for optimization.
|
||||
** In other words, return true if a call to the orTermIsOptCandidate()
|
||||
** above returned false but it is not necessary to disqualify the
|
||||
** optimization.
|
||||
**
|
||||
** Suppose the original OR phrase was this:
|
||||
**
|
||||
** a=4 OR a=11 OR a=b
|
||||
**
|
||||
** During analysis, the third term gets flipped around and duplicate
|
||||
** so that we are left with this:
|
||||
**
|
||||
** a=4 OR a=11 OR a=b OR b=a
|
||||
**
|
||||
** Since the last two terms are duplicates, only one of them
|
||||
** has to qualify in order for the whole phrase to qualify. When
|
||||
** this routine is called, we know that pOrTerm did not qualify.
|
||||
** This routine merely checks to see if pOrTerm has a duplicate that
|
||||
** might qualify. If there is a duplicate that has not yet been
|
||||
** disqualified, then return true. If there are no duplicates, or
|
||||
** the duplicate has also been disqualifed, return false.
|
||||
*/
|
||||
static int orTermHasOkDuplicate(WhereClause *pOr, WhereTerm *pOrTerm){
|
||||
if( pOrTerm->flags & TERM_COPIED ){
|
||||
/* This is the original term. The duplicate is to the left had
|
||||
** has not yet been analyzed and thus has not yet been disqualified. */
|
||||
return 1;
|
||||
}
|
||||
if( (pOrTerm->flags & TERM_VIRTUAL)!=0
|
||||
&& (pOr->a[pOrTerm->iParent].flags & TERM_OR_OK)!=0 ){
|
||||
/* This is a duplicate term. The original qualified so this one
|
||||
** does not have to. */
|
||||
return 1;
|
||||
}
|
||||
/* This is either a singleton term or else it is a duplicate for
|
||||
** which the original did not qualify. Either way we are done for. */
|
||||
return 0;
|
||||
}
|
||||
#endif /* !SQLITE_OMIT_OR_OPTIMIZATION && !SQLITE_OMIT_SUBQUERY */
|
||||
|
||||
/*
|
||||
** The input to this routine is an WhereTerm structure with only the
|
||||
|
@ -644,7 +742,7 @@ static void exprAnalyze(
|
|||
int idxNew;
|
||||
pDup = sqlite3ExprDup(pExpr);
|
||||
if( sqlite3MallocFailed() ){
|
||||
sqliteFree(pDup);
|
||||
sqlite3ExprDelete(pDup);
|
||||
return;
|
||||
}
|
||||
idxNew = whereClauseInsert(pWC, pDup, TERM_VIRTUAL|TERM_DYNAMIC);
|
||||
|
@ -716,9 +814,10 @@ static void exprAnalyze(
|
|||
whereClauseInit(&sOr, pWC->pParse, pMaskSet);
|
||||
whereSplit(&sOr, pExpr, TK_OR);
|
||||
exprAnalyzeAll(pSrc, &sOr);
|
||||
assert( sOr.nTerm>0 );
|
||||
assert( sOr.nTerm>=2 );
|
||||
j = 0;
|
||||
do{
|
||||
assert( j<sOr.nTerm );
|
||||
iColumn = sOr.a[j].leftColumn;
|
||||
iCursor = sOr.a[j].leftCursor;
|
||||
ok = iCursor>=0;
|
||||
|
@ -726,17 +825,15 @@ static void exprAnalyze(
|
|||
if( pOrTerm->eOperator!=WO_EQ ){
|
||||
goto or_not_possible;
|
||||
}
|
||||
if( pOrTerm->leftCursor==iCursor && pOrTerm->leftColumn==iColumn ){
|
||||
if( orTermIsOptCandidate(pOrTerm, iCursor, iColumn) ){
|
||||
pOrTerm->flags |= TERM_OR_OK;
|
||||
}else if( (pOrTerm->flags & TERM_COPIED)!=0 ||
|
||||
((pOrTerm->flags & TERM_VIRTUAL)!=0 &&
|
||||
(sOr.a[pOrTerm->iParent].flags & TERM_OR_OK)!=0) ){
|
||||
}else if( orTermHasOkDuplicate(&sOr, pOrTerm) ){
|
||||
pOrTerm->flags &= ~TERM_OR_OK;
|
||||
}else{
|
||||
ok = 0;
|
||||
}
|
||||
}
|
||||
}while( !ok && (sOr.a[j++].flags & TERM_COPIED)!=0 && j<sOr.nTerm );
|
||||
}while( !ok && (sOr.a[j++].flags & TERM_COPIED)!=0 && j<2 );
|
||||
if( ok ){
|
||||
ExprList *pList = 0;
|
||||
Expr *pNew, *pDup;
|
||||
|
@ -1041,8 +1138,7 @@ static double estLog(double N){
|
|||
** SQLITE_TEST or SQLITE_DEBUG are defined, then these routines
|
||||
** are no-ops.
|
||||
*/
|
||||
#if !defined(SQLITE_OMIT_VIRTUALTABLE) && \
|
||||
(defined(SQLITE_TEST) || defined(SQLITE_DEBUG))
|
||||
#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_DEBUG)
|
||||
static void TRACE_IDX_INPUTS(sqlite3_index_info *p){
|
||||
int i;
|
||||
if( !sqlite3_where_trace ) return;
|
||||
|
@ -1124,7 +1220,7 @@ static double bestVirtualIndex(
|
|||
if( pIdxInfo==0 ){
|
||||
WhereTerm *pTerm;
|
||||
int nTerm;
|
||||
TRACE(("Recomputing index info for %s...\n", pTab->zName));
|
||||
WHERETRACE(("Recomputing index info for %s...\n", pTab->zName));
|
||||
|
||||
/* Count the number of possible WHERE clause constraints referring
|
||||
** to this virtual table */
|
||||
|
@ -1207,13 +1303,19 @@ static double bestVirtualIndex(
|
|||
** xBestIndex.
|
||||
*/
|
||||
|
||||
/* The module name must be defined */
|
||||
/* The module name must be defined. Also, by this point there must
|
||||
** be a pointer to an sqlite3_vtab structure. Otherwise
|
||||
** sqlite3ViewGetColumnNames() would have picked up the error.
|
||||
*/
|
||||
assert( pTab->azModuleArg && pTab->azModuleArg[0] );
|
||||
assert( pTab->pVtab );
|
||||
#if 0
|
||||
if( pTab->pVtab==0 ){
|
||||
sqlite3ErrorMsg(pParse, "undefined module %s for table %s",
|
||||
pTab->azModuleArg[0], pTab->zName);
|
||||
return 0.0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Set the aConstraint[].usable fields and initialize all
|
||||
** output variables to zero.
|
||||
|
@ -1257,7 +1359,7 @@ static double bestVirtualIndex(
|
|||
}
|
||||
|
||||
sqlite3SafetyOff(pParse->db);
|
||||
TRACE(("xBestIndex for %s\n", pTab->zName));
|
||||
WHERETRACE(("xBestIndex for %s\n", pTab->zName));
|
||||
TRACE_IDX_INPUTS(pIdxInfo);
|
||||
rc = pTab->pVtab->pModule->xBestIndex(pTab->pVtab, pIdxInfo);
|
||||
TRACE_IDX_OUTPUTS(pIdxInfo);
|
||||
|
@ -1272,6 +1374,7 @@ static double bestVirtualIndex(
|
|||
rc = sqlite3SafetyOn(pParse->db);
|
||||
}
|
||||
*(int*)&pIdxInfo->nOrderBy = nOrderBy;
|
||||
|
||||
return pIdxInfo->estimatedCost;
|
||||
}
|
||||
#endif /* SQLITE_OMIT_VIRTUALTABLE */
|
||||
|
@ -1317,7 +1420,7 @@ static double bestIndex(
|
|||
int eqTermMask; /* Mask of valid equality operators */
|
||||
double cost; /* Cost of using pProbe */
|
||||
|
||||
TRACE(("bestIndex: tbl=%s notReady=%x\n", pSrc->pTab->zName, notReady));
|
||||
WHERETRACE(("bestIndex: tbl=%s notReady=%x\n", pSrc->pTab->zName, notReady));
|
||||
lowestCost = SQLITE_BIG_DBL;
|
||||
pProbe = pSrc->pTab->pIndex;
|
||||
|
||||
|
@ -1348,7 +1451,7 @@ static double bestIndex(
|
|||
** a single row is generated, output is always in sorted order */
|
||||
*pFlags = WHERE_ROWID_EQ | WHERE_UNIQUE;
|
||||
*pnEq = 1;
|
||||
TRACE(("... best is rowid\n"));
|
||||
WHERETRACE(("... best is rowid\n"));
|
||||
return 0.0;
|
||||
}else if( (pExpr = pTerm->pExpr)->pList!=0 ){
|
||||
/* Rowid IN (LIST): cost is NlogN where N is the number of list
|
||||
|
@ -1361,14 +1464,14 @@ static double bestIndex(
|
|||
** that value so make a wild guess. */
|
||||
lowestCost = 200;
|
||||
}
|
||||
TRACE(("... rowid IN cost: %.9g\n", lowestCost));
|
||||
WHERETRACE(("... rowid IN cost: %.9g\n", lowestCost));
|
||||
}
|
||||
|
||||
/* Estimate the cost of a table scan. If we do not know how many
|
||||
** entries are in the table, use 1 million as a guess.
|
||||
*/
|
||||
cost = pProbe ? pProbe->aiRowEst[0] : 1000000;
|
||||
TRACE(("... table scan base cost: %.9g\n", cost));
|
||||
WHERETRACE(("... table scan base cost: %.9g\n", cost));
|
||||
flags = WHERE_ROWID_RANGE;
|
||||
|
||||
/* Check for constraints on a range of rowids in a table scan.
|
||||
|
@ -1383,7 +1486,7 @@ static double bestIndex(
|
|||
flags |= WHERE_BTM_LIMIT;
|
||||
cost /= 3; /* Guess that rowid>EXPR eliminates two-thirds of rows */
|
||||
}
|
||||
TRACE(("... rowid range reduces cost to %.9g\n", cost));
|
||||
WHERETRACE(("... rowid range reduces cost to %.9g\n", cost));
|
||||
}else{
|
||||
flags = 0;
|
||||
}
|
||||
|
@ -1398,7 +1501,7 @@ static double bestIndex(
|
|||
}
|
||||
}else{
|
||||
cost += cost*estLog(cost);
|
||||
TRACE(("... sorting increases cost to %.9g\n", cost));
|
||||
WHERETRACE(("... sorting increases cost to %.9g\n", cost));
|
||||
}
|
||||
}
|
||||
if( cost<lowestCost ){
|
||||
|
@ -1423,7 +1526,7 @@ static double bestIndex(
|
|||
int i; /* Loop counter */
|
||||
double inMultiplier = 1;
|
||||
|
||||
TRACE(("... index %s:\n", pProbe->zName));
|
||||
WHERETRACE(("... index %s:\n", pProbe->zName));
|
||||
|
||||
/* Count the number of columns in the index that are satisfied
|
||||
** by x=EXPR constraints or x IN (...) constraints.
|
||||
|
@ -1450,7 +1553,7 @@ static double bestIndex(
|
|||
&& nEq==pProbe->nColumn ){
|
||||
flags |= WHERE_UNIQUE;
|
||||
}
|
||||
TRACE(("...... nEq=%d inMult=%.9g cost=%.9g\n", nEq, inMultiplier, cost));
|
||||
WHERETRACE(("...... nEq=%d inMult=%.9g cost=%.9g\n", nEq, inMultiplier, cost));
|
||||
|
||||
/* Look for range constraints
|
||||
*/
|
||||
|
@ -1467,7 +1570,7 @@ static double bestIndex(
|
|||
flags |= WHERE_BTM_LIMIT;
|
||||
cost /= 3;
|
||||
}
|
||||
TRACE(("...... range reduces cost to %.9g\n", cost));
|
||||
WHERETRACE(("...... range reduces cost to %.9g\n", cost));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1485,7 +1588,7 @@ static double bestIndex(
|
|||
}
|
||||
}else{
|
||||
cost += cost*estLog(cost);
|
||||
TRACE(("...... orderby increases cost to %.9g\n", cost));
|
||||
WHERETRACE(("...... orderby increases cost to %.9g\n", cost));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1505,7 +1608,7 @@ static double bestIndex(
|
|||
if( m==0 ){
|
||||
flags |= WHERE_IDX_ONLY;
|
||||
cost /= 2;
|
||||
TRACE(("...... idx-only reduces cost to %.9g\n", cost));
|
||||
WHERETRACE(("...... idx-only reduces cost to %.9g\n", cost));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1523,7 +1626,7 @@ static double bestIndex(
|
|||
/* Report the best result
|
||||
*/
|
||||
*ppIndex = bestIdx;
|
||||
TRACE(("best index is %s, cost=%.9g, flags=%x, nEq=%d\n",
|
||||
WHERETRACE(("best index is %s, cost=%.9g, flags=%x, nEq=%d\n",
|
||||
bestIdx ? bestIdx->zName : "(none)", lowestCost, bestFlags, bestNEq));
|
||||
*pFlags = bestFlags | eqTermMask;
|
||||
*pnEq = bestNEq;
|
||||
|
@ -1601,7 +1704,6 @@ static void buildIndexProbe(
|
|||
static void codeEqualityTerm(
|
||||
Parse *pParse, /* The parsing context */
|
||||
WhereTerm *pTerm, /* The term of the WHERE clause to be coded */
|
||||
int brk, /* Jump here to abandon the loop */
|
||||
WhereLevel *pLevel /* When level of the FROM clause we are working on */
|
||||
){
|
||||
Expr *pX = pTerm->pExpr;
|
||||
|
@ -1613,21 +1715,25 @@ static void codeEqualityTerm(
|
|||
#ifndef SQLITE_OMIT_SUBQUERY
|
||||
}else{
|
||||
int iTab;
|
||||
int *aIn;
|
||||
struct InLoop *pIn;
|
||||
|
||||
assert( pX->op==TK_IN );
|
||||
sqlite3CodeSubselect(pParse, pX);
|
||||
iTab = pX->iTable;
|
||||
sqlite3VdbeAddOp(v, OP_Rewind, iTab, 0);
|
||||
VdbeComment((v, "# %.*s", pX->span.n, pX->span.z));
|
||||
if( pLevel->nIn==0 ){
|
||||
pLevel->nxt = sqlite3VdbeMakeLabel(v);
|
||||
}
|
||||
pLevel->nIn++;
|
||||
sqliteReallocOrFree((void**)&pLevel->aInLoop,
|
||||
sizeof(pLevel->aInLoop[0])*2*pLevel->nIn);
|
||||
aIn = pLevel->aInLoop;
|
||||
if( aIn ){
|
||||
aIn += pLevel->nIn*2 - 2;
|
||||
aIn[0] = iTab;
|
||||
aIn[1] = sqlite3VdbeAddOp(v, OP_Column, iTab, 0);
|
||||
pLevel->aInLoop = sqliteReallocOrFree(pLevel->aInLoop,
|
||||
sizeof(pLevel->aInLoop[0])*pLevel->nIn);
|
||||
pIn = pLevel->aInLoop;
|
||||
if( pIn ){
|
||||
pIn += pLevel->nIn - 1;
|
||||
pIn->iCur = iTab;
|
||||
pIn->topAddr = sqlite3VdbeAddOp(v, OP_Column, iTab, 0);
|
||||
sqlite3VdbeAddOp(v, OP_IsNull, -1, 0);
|
||||
}else{
|
||||
pLevel->nIn = 0;
|
||||
}
|
||||
|
@ -1663,8 +1769,7 @@ static void codeAllEqualityTerms(
|
|||
Parse *pParse, /* Parsing context */
|
||||
WhereLevel *pLevel, /* Which nested loop of the FROM we are coding */
|
||||
WhereClause *pWC, /* The WHERE clause */
|
||||
Bitmask notReady, /* Which parts of FROM have not yet been coded */
|
||||
int brk /* Jump here to end the loop */
|
||||
Bitmask notReady /* Which parts of FROM have not yet been coded */
|
||||
){
|
||||
int nEq = pLevel->nEq; /* The number of == or IN constraints to code */
|
||||
int termsInMem = 0; /* If true, store value in mem[] cells */
|
||||
|
@ -1693,9 +1798,9 @@ static void codeAllEqualityTerms(
|
|||
pTerm = findTerm(pWC, iCur, k, notReady, pLevel->flags, pIdx);
|
||||
if( pTerm==0 ) break;
|
||||
assert( (pTerm->flags & TERM_CODED)==0 );
|
||||
codeEqualityTerm(pParse, pTerm, brk, pLevel);
|
||||
if( (pTerm->eOperator & WO_ISNULL)==0 ){
|
||||
sqlite3VdbeAddOp(v, OP_IsNull, termsInMem ? -1 : -(j+1), brk);
|
||||
codeEqualityTerm(pParse, pTerm, pLevel);
|
||||
if( (pTerm->eOperator & (WO_ISNULL|WO_IN))==0 ){
|
||||
sqlite3VdbeAddOp(v, OP_IsNull, termsInMem ? -1 : -(j+1), pLevel->brk);
|
||||
}
|
||||
if( termsInMem ){
|
||||
sqlite3VdbeAddOp(v, OP_MemStore, pLevel->iMem+j+1, 1);
|
||||
|
@ -1734,6 +1839,10 @@ static void whereInfoFree(WhereInfo *pWInfo){
|
|||
sqlite3_index_info *pInfo = pWInfo->a[i].pIdxInfo;
|
||||
if( pInfo ){
|
||||
if( pInfo->needToFreeIdxStr ){
|
||||
/* Coverage: Don't think this can be reached. By the time this
|
||||
** function is called, the index-strings have been passed
|
||||
** to the vdbe layer for deletion.
|
||||
*/
|
||||
sqlite3_free(pInfo->idxStr);
|
||||
}
|
||||
sqliteFree(pInfo);
|
||||
|
@ -1917,7 +2026,7 @@ WhereInfo *sqlite3WhereBegin(
|
|||
pTabItem = pTabList->a;
|
||||
pLevel = pWInfo->a;
|
||||
andFlags = ~0;
|
||||
TRACE(("*** Optimizer Start ***\n"));
|
||||
WHERETRACE(("*** Optimizer Start ***\n"));
|
||||
for(i=iFrom=0, pLevel=pWInfo->a; i<pTabList->nSrc; i++, pLevel++){
|
||||
Index *pIdx; /* Index for FROM table at pTabItem */
|
||||
int flags; /* Flags asssociated with pIdx */
|
||||
|
@ -1958,6 +2067,14 @@ WhereInfo *sqlite3WhereBegin(
|
|||
}
|
||||
pIdx = 0;
|
||||
nEq = 0;
|
||||
if( (SQLITE_BIG_DBL/2.0)<cost ){
|
||||
/* The cost is not allowed to be larger than SQLITE_BIG_DBL (the
|
||||
** inital value of lowestCost in this loop. If it is, then
|
||||
** the (cost<lowestCost) test below will never be true and
|
||||
** pLevel->pBestIdx never set.
|
||||
*/
|
||||
cost = (SQLITE_BIG_DBL/2.0);
|
||||
}
|
||||
}else
|
||||
#endif
|
||||
{
|
||||
|
@ -1977,7 +2094,7 @@ WhereInfo *sqlite3WhereBegin(
|
|||
}
|
||||
if( doNotReorder ) break;
|
||||
}
|
||||
TRACE(("*** Optimizer choose table %d for loop %d\n", bestJ,
|
||||
WHERETRACE(("*** Optimizer choose table %d for loop %d\n", bestJ,
|
||||
pLevel-pWInfo->a));
|
||||
if( (bestFlags & WHERE_ORDERBY)!=0 ){
|
||||
*ppOrderBy = 0;
|
||||
|
@ -1996,7 +2113,7 @@ WhereInfo *sqlite3WhereBegin(
|
|||
notReady &= ~getMask(&maskSet, pTabList->a[bestJ].iCursor);
|
||||
pLevel->iFrom = bestJ;
|
||||
}
|
||||
TRACE(("*** Optimizer Finished ***\n"));
|
||||
WHERETRACE(("*** Optimizer Finished ***\n"));
|
||||
|
||||
/* If the total query only selects a single row, then the ORDER BY
|
||||
** clause is irrelevant.
|
||||
|
@ -2090,6 +2207,7 @@ WhereInfo *sqlite3WhereBegin(
|
|||
int j;
|
||||
int iCur = pTabItem->iCursor; /* The VDBE cursor for the table */
|
||||
Index *pIdx; /* The index we will be using */
|
||||
int nxt; /* Where to jump to continue with the next IN case */
|
||||
int iIdxCur; /* The VDBE cursor for the index */
|
||||
int omitTable; /* True if we use the index only */
|
||||
int bRev; /* True if we need to scan in reverse order */
|
||||
|
@ -2105,8 +2223,13 @@ WhereInfo *sqlite3WhereBegin(
|
|||
** for the current loop. Jump to brk to break out of a loop.
|
||||
** Jump to cont to go immediately to the next iteration of the
|
||||
** loop.
|
||||
**
|
||||
** When there is an IN operator, we also have a "nxt" label that
|
||||
** means to continue with the next IN value combination. When
|
||||
** there are no IN operators in the constraints, the "nxt" label
|
||||
** is the same as "brk".
|
||||
*/
|
||||
brk = pLevel->brk = sqlite3VdbeMakeLabel(v);
|
||||
brk = pLevel->brk = pLevel->nxt = sqlite3VdbeMakeLabel(v);
|
||||
cont = pLevel->cont = sqlite3VdbeMakeLabel(v);
|
||||
|
||||
/* If this is the right table of a LEFT OUTER JOIN, allocate and
|
||||
|
@ -2172,9 +2295,10 @@ WhereInfo *sqlite3WhereBegin(
|
|||
assert( pTerm->pExpr!=0 );
|
||||
assert( pTerm->leftCursor==iCur );
|
||||
assert( omitTable==0 );
|
||||
codeEqualityTerm(pParse, pTerm, brk, pLevel);
|
||||
sqlite3VdbeAddOp(v, OP_MustBeInt, 1, brk);
|
||||
sqlite3VdbeAddOp(v, OP_NotExists, iCur, brk);
|
||||
codeEqualityTerm(pParse, pTerm, pLevel);
|
||||
nxt = pLevel->nxt;
|
||||
sqlite3VdbeAddOp(v, OP_MustBeInt, 1, nxt);
|
||||
sqlite3VdbeAddOp(v, OP_NotExists, iCur, nxt);
|
||||
VdbeComment((v, "pk"));
|
||||
pLevel->op = OP_Noop;
|
||||
}else if( pLevel->flags & WHERE_ROWID_RANGE ){
|
||||
|
@ -2253,7 +2377,7 @@ WhereInfo *sqlite3WhereBegin(
|
|||
/* Generate code to evaluate all constraint terms using == or IN
|
||||
** and level the values of those terms on the stack.
|
||||
*/
|
||||
codeAllEqualityTerms(pParse, pLevel, &wc, notReady, brk);
|
||||
codeAllEqualityTerms(pParse, pLevel, &wc, notReady);
|
||||
|
||||
/* Duplicate the equality term values because they will all be
|
||||
** used twice: once to make the termination key and once to make the
|
||||
|
@ -2284,6 +2408,7 @@ WhereInfo *sqlite3WhereBegin(
|
|||
** 2002-Dec-04: On a reverse-order scan, the so-called "termination"
|
||||
** key computed here really ends up being the start key.
|
||||
*/
|
||||
nxt = pLevel->nxt;
|
||||
if( topLimit ){
|
||||
Expr *pX;
|
||||
int k = pIdx->aiColumn[j];
|
||||
|
@ -2292,7 +2417,7 @@ WhereInfo *sqlite3WhereBegin(
|
|||
pX = pTerm->pExpr;
|
||||
assert( (pTerm->flags & TERM_CODED)==0 );
|
||||
sqlite3ExprCode(pParse, pX->pRight);
|
||||
sqlite3VdbeAddOp(v, OP_IsNull, -(nEq+1), brk);
|
||||
sqlite3VdbeAddOp(v, OP_IsNull, -(nEq+1), nxt);
|
||||
topEq = pTerm->eOperator & (WO_LE|WO_GE);
|
||||
disableTerm(pLevel, pTerm);
|
||||
testOp = OP_IdxGE;
|
||||
|
@ -2306,7 +2431,7 @@ WhereInfo *sqlite3WhereBegin(
|
|||
buildIndexProbe(v, nCol, pIdx);
|
||||
if( bRev ){
|
||||
int op = topEq ? OP_MoveLe : OP_MoveLt;
|
||||
sqlite3VdbeAddOp(v, op, iIdxCur, brk);
|
||||
sqlite3VdbeAddOp(v, op, iIdxCur, nxt);
|
||||
}else{
|
||||
sqlite3VdbeAddOp(v, OP_MemStore, pLevel->iMem, 1);
|
||||
}
|
||||
|
@ -2331,7 +2456,7 @@ WhereInfo *sqlite3WhereBegin(
|
|||
pX = pTerm->pExpr;
|
||||
assert( (pTerm->flags & TERM_CODED)==0 );
|
||||
sqlite3ExprCode(pParse, pX->pRight);
|
||||
sqlite3VdbeAddOp(v, OP_IsNull, -(nEq+1), brk);
|
||||
sqlite3VdbeAddOp(v, OP_IsNull, -(nEq+1), nxt);
|
||||
btmEq = pTerm->eOperator & (WO_LE|WO_GE);
|
||||
disableTerm(pLevel, pTerm);
|
||||
}else{
|
||||
|
@ -2346,7 +2471,7 @@ WhereInfo *sqlite3WhereBegin(
|
|||
testOp = OP_IdxLT;
|
||||
}else{
|
||||
int op = btmEq ? OP_MoveGe : OP_MoveGt;
|
||||
sqlite3VdbeAddOp(v, op, iIdxCur, brk);
|
||||
sqlite3VdbeAddOp(v, op, iIdxCur, nxt);
|
||||
}
|
||||
}else if( bRev ){
|
||||
testOp = OP_Noop;
|
||||
|
@ -2361,7 +2486,7 @@ WhereInfo *sqlite3WhereBegin(
|
|||
start = sqlite3VdbeCurrentAddr(v);
|
||||
if( testOp!=OP_Noop ){
|
||||
sqlite3VdbeAddOp(v, OP_MemLoad, pLevel->iMem, 0);
|
||||
sqlite3VdbeAddOp(v, testOp, iIdxCur, brk);
|
||||
sqlite3VdbeAddOp(v, testOp, iIdxCur, nxt);
|
||||
if( (topEq && !bRev) || (!btmEq && bRev) ){
|
||||
sqlite3VdbeChangeP3(v, -1, "+", P3_STATIC);
|
||||
}
|
||||
|
@ -2390,7 +2515,8 @@ WhereInfo *sqlite3WhereBegin(
|
|||
/* Generate code to evaluate all constraint terms using == or IN
|
||||
** and leave the values of those terms on the stack.
|
||||
*/
|
||||
codeAllEqualityTerms(pParse, pLevel, &wc, notReady, brk);
|
||||
codeAllEqualityTerms(pParse, pLevel, &wc, notReady);
|
||||
nxt = pLevel->nxt;
|
||||
|
||||
/* Generate a single key that will be used to both start and terminate
|
||||
** the search
|
||||
|
@ -2399,21 +2525,21 @@ WhereInfo *sqlite3WhereBegin(
|
|||
sqlite3VdbeAddOp(v, OP_MemStore, pLevel->iMem, 0);
|
||||
|
||||
/* Generate code (1) to move to the first matching element of the table.
|
||||
** Then generate code (2) that jumps to "brk" after the cursor is past
|
||||
** Then generate code (2) that jumps to "nxt" after the cursor is past
|
||||
** the last matching element of the table. The code (1) is executed
|
||||
** once to initialize the search, the code (2) is executed before each
|
||||
** iteration of the scan to see if the scan has finished. */
|
||||
if( bRev ){
|
||||
/* Scan in reverse order */
|
||||
sqlite3VdbeAddOp(v, OP_MoveLe, iIdxCur, brk);
|
||||
sqlite3VdbeAddOp(v, OP_MoveLe, iIdxCur, nxt);
|
||||
start = sqlite3VdbeAddOp(v, OP_MemLoad, pLevel->iMem, 0);
|
||||
sqlite3VdbeAddOp(v, OP_IdxLT, iIdxCur, brk);
|
||||
sqlite3VdbeAddOp(v, OP_IdxLT, iIdxCur, nxt);
|
||||
pLevel->op = OP_Prev;
|
||||
}else{
|
||||
/* Scan in the forward order */
|
||||
sqlite3VdbeAddOp(v, OP_MoveGe, iIdxCur, brk);
|
||||
sqlite3VdbeAddOp(v, OP_MoveGe, iIdxCur, nxt);
|
||||
start = sqlite3VdbeAddOp(v, OP_MemLoad, pLevel->iMem, 0);
|
||||
sqlite3VdbeOp3(v, OP_IdxGE, iIdxCur, brk, "+", P3_STATIC);
|
||||
sqlite3VdbeOp3(v, OP_IdxGE, iIdxCur, nxt, "+", P3_STATIC);
|
||||
pLevel->op = OP_Next;
|
||||
}
|
||||
if( !omitTable ){
|
||||
|
@ -2546,16 +2672,18 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
|
|||
if( pLevel->op!=OP_Noop ){
|
||||
sqlite3VdbeAddOp(v, pLevel->op, pLevel->p1, pLevel->p2);
|
||||
}
|
||||
sqlite3VdbeResolveLabel(v, pLevel->brk);
|
||||
if( pLevel->nIn ){
|
||||
int *a;
|
||||
struct InLoop *pIn;
|
||||
int j;
|
||||
for(j=pLevel->nIn, a=&pLevel->aInLoop[j*2-2]; j>0; j--, a-=2){
|
||||
sqlite3VdbeAddOp(v, OP_Next, a[0], a[1]);
|
||||
sqlite3VdbeJumpHere(v, a[1]-1);
|
||||
sqlite3VdbeResolveLabel(v, pLevel->nxt);
|
||||
for(j=pLevel->nIn, pIn=&pLevel->aInLoop[j-1]; j>0; j--, pIn--){
|
||||
sqlite3VdbeJumpHere(v, pIn->topAddr+1);
|
||||
sqlite3VdbeAddOp(v, OP_Next, pIn->iCur, pIn->topAddr);
|
||||
sqlite3VdbeJumpHere(v, pIn->topAddr-1);
|
||||
}
|
||||
sqliteFree(pLevel->aInLoop);
|
||||
}
|
||||
sqlite3VdbeResolveLabel(v, pLevel->brk);
|
||||
if( pLevel->iLeftJoin ){
|
||||
int addr;
|
||||
addr = sqlite3VdbeAddOp(v, OP_IfMemPos, pLevel->iLeftJoin, 0);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue