Upgrade sqlite lib to 3.2.5

This commit is contained in:
Ilia Alshanetsky 2005-08-28 16:57:01 +00:00
parent 4509fb9d5d
commit bb38017142
64 changed files with 6261 additions and 4244 deletions

View file

@ -258,6 +258,7 @@ void sqlite3AlterRenameTable(
char *zWhere = 0; /* Where clause to locate temp triggers */
#endif
if( sqlite3_malloc_failed ) goto exit_rename_table;
assert( pSrc->nSrc==1 );
pTab = sqlite3LocateTable(pParse, pSrc->a[0].zName, pSrc->a[0].zDatabase);
@ -500,8 +501,10 @@ void sqlite3AlterBeginAddColumn(Parse *pParse, SrcList *pSrc){
int i;
int nAlloc;
/* Look up the table being altered. */
assert( !pParse->pNewTable );
assert( pParse->pNewTable==0 );
if( sqlite3_malloc_failed ) goto exit_begin_add_column;
pTab = sqlite3LocateTable(pParse, pSrc->a[0].zName, pSrc->a[0].zDatabase);
if( !pTab ) goto exit_begin_add_column;
@ -520,6 +523,7 @@ void sqlite3AlterBeginAddColumn(Parse *pParse, SrcList *pSrc){
pNew = (Table *)sqliteMalloc(sizeof(Table));
if( !pNew ) goto exit_begin_add_column;
pParse->pNewTable = pNew;
pNew->nRef = 1;
pNew->nCol = pTab->nCol;
assert( pNew->nCol>0 );
nAlloc = (((pNew->nCol-1)/8)*8)+8;

View file

@ -0,0 +1,388 @@
/*
** 2005 July 8
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
**
** May you do good and not evil.
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
*************************************************************************
** This file contains code associated with the ANALYZE command.
**
** @(#) $Id$
*/
#ifndef SQLITE_OMIT_ANALYZE
#include "sqliteInt.h"
/*
** This routine generates code that opens the sqlite_stat1 table on cursor
** iStatCur.
**
** If the sqlite_stat1 tables does not previously exist, it is created.
** If it does previously exist, all entires associated with table zWhere
** are removed. If zWhere==0 then all entries are removed.
*/
static void openStatTable(
Parse *pParse, /* Parsing context */
int iDb, /* The database we are looking in */
int iStatCur, /* Open the sqlite_stat1 table on this cursor */
const char *zWhere /* Delete entries associated with this table */
){
sqlite3 *db = pParse->db;
Db *pDb;
int iRootPage;
Table *pStat;
Vdbe *v = sqlite3GetVdbe(pParse);
pDb = &db->aDb[iDb];
if( (pStat = sqlite3FindTable(db, "sqlite_stat1", pDb->zName))==0 ){
/* The sqlite_stat1 tables does not exist. Create it.
** Note that a side-effect of the CREATE TABLE statement is to leave
** the rootpage of the new table on the top of the stack. This is
** important because the OpenWrite opcode below will be needing it. */
sqlite3NestedParse(pParse,
"CREATE TABLE %Q.sqlite_stat1(tbl,idx,stat)",
pDb->zName
);
iRootPage = 0; /* Cause rootpage to be taken from top of stack */
}else if( zWhere ){
/* The sqlite_stat1 table exists. Delete all entries associated with
** the table zWhere. */
sqlite3NestedParse(pParse,
"DELETE FROM %Q.sqlite_stat1 WHERE tbl=%Q",
pDb->zName, zWhere
);
iRootPage = pStat->tnum;
}else{
/* The sqlite_stat1 table already exists. Delete all rows. */
iRootPage = pStat->tnum;
sqlite3VdbeAddOp(v, OP_Clear, pStat->tnum, iDb);
}
/* Open the sqlite_stat1 table for writing.
*/
sqlite3VdbeAddOp(v, OP_Integer, iDb, 0);
sqlite3VdbeAddOp(v, OP_OpenWrite, iStatCur, iRootPage);
sqlite3VdbeAddOp(v, OP_SetNumColumns, iStatCur, 3);
}
/*
** Generate code to do an analysis of all indices associated with
** a single table.
*/
static void analyzeOneTable(
Parse *pParse, /* Parser context */
Table *pTab, /* Table whose indices are to be analyzed */
int iStatCur, /* Cursor that writes to the sqlite_stat1 table */
int iMem /* Available memory locations begin here */
){
Index *pIdx; /* An index to being analyzed */
int iIdxCur; /* Cursor number for index being analyzed */
int nCol; /* Number of columns in the index */
Vdbe *v; /* The virtual machine being built up */
int i; /* Loop counter */
int topOfLoop; /* The top of the loop */
int endOfLoop; /* The end of the loop */
int addr; /* The address of an instruction */
v = sqlite3GetVdbe(pParse);
if( pTab==0 || pTab->pIndex==0 || pTab->pIndex->pNext==0 ){
/* Do no analysis for tables with fewer than 2 indices */
return;
}
#ifndef SQLITE_OMIT_AUTHORIZATION
if( sqlite3AuthCheck(pParse, SQLITE_ANALYZE, pTab->zName, 0,
pParse->db->aDb[pTab->iDb].zName ) ){
return;
}
#endif
iIdxCur = pParse->nTab;
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
/* Open a cursor to the index to be analyzed
*/
sqlite3VdbeAddOp(v, OP_Integer, pIdx->iDb, 0);
VdbeComment((v, "# %s", pIdx->zName));
sqlite3VdbeOp3(v, OP_OpenRead, iIdxCur, pIdx->tnum,
(char*)&pIdx->keyInfo, P3_KEYINFO);
nCol = pIdx->nColumn;
if( iMem+nCol*2>=pParse->nMem ){
pParse->nMem = iMem+nCol*2+1;
}
sqlite3VdbeAddOp(v, OP_SetNumColumns, iIdxCur, nCol+1);
/* Memory cells are used as follows:
**
** mem[iMem]: The total number of rows in the table.
** mem[iMem+1]: Number of distinct values in column 1
** ...
** mem[iMem+nCol]: Number of distinct values in column N
** mem[iMem+nCol+1] Last observed value of column 1
** ...
** mem[iMem+nCol+nCol]: Last observed value of column N
**
** Cells iMem through iMem+nCol are initialized to 0. The others
** are initialized to NULL.
*/
sqlite3VdbeAddOp(v, OP_Integer, 0, 0);
for(i=0; i<=nCol; i++){
sqlite3VdbeAddOp(v, OP_MemStore, iMem+i, i==nCol);
}
sqlite3VdbeAddOp(v, OP_Null, 0, 0);
for(i=0; i<nCol; i++){
sqlite3VdbeAddOp(v, OP_MemStore, iMem+nCol+i+1, i==nCol-1);
}
/* Do the analysis.
*/
endOfLoop = sqlite3VdbeMakeLabel(v);
sqlite3VdbeAddOp(v, OP_Rewind, iIdxCur, endOfLoop);
topOfLoop = sqlite3VdbeCurrentAddr(v);
sqlite3VdbeAddOp(v, OP_MemIncr, iMem, 0);
for(i=0; i<nCol; i++){
sqlite3VdbeAddOp(v, OP_Column, iIdxCur, i);
sqlite3VdbeAddOp(v, OP_MemLoad, iMem+nCol+i+1, 0);
sqlite3VdbeAddOp(v, OP_Ne, 0x100, 0);
}
sqlite3VdbeAddOp(v, OP_Goto, 0, endOfLoop);
for(i=0; i<nCol; i++){
addr = sqlite3VdbeAddOp(v, OP_MemIncr, iMem+i+1, 0);
sqlite3VdbeChangeP2(v, topOfLoop + 3*i + 3, addr);
sqlite3VdbeAddOp(v, OP_Column, iIdxCur, i);
sqlite3VdbeAddOp(v, OP_MemStore, iMem+nCol+i+1, 1);
}
sqlite3VdbeResolveLabel(v, endOfLoop);
sqlite3VdbeAddOp(v, OP_Next, iIdxCur, topOfLoop);
sqlite3VdbeAddOp(v, OP_Close, iIdxCur, 0);
/* Store the results.
**
** The result is a single row of the sqlite_stmt1 table. The first
** two columns are the names of the table and index. The third column
** is a string composed of a list of integer statistics about the
** index. The first integer in the list is the total number of entires
** in the index. There is one additional integer in the list for each
** column of the table. This additional integer is a guess of how many
** rows of the table the index will select. If D is the count of distinct
** values and K is the total number of rows, then the integer is computed
** as:
**
** I = (K+D-1)/D
**
** If K==0 then no entry is made into the sqlite_stat1 table.
** If K>0 then it is always the case the D>0 so division by zero
** is never possible.
*/
sqlite3VdbeAddOp(v, OP_MemLoad, iMem, 0);
addr = sqlite3VdbeAddOp(v, OP_IfNot, 0, 0);
sqlite3VdbeAddOp(v, OP_NewRowid, iStatCur, 0);
sqlite3VdbeOp3(v, OP_String8, 0, 0, pTab->zName, 0);
sqlite3VdbeOp3(v, OP_String8, 0, 0, pIdx->zName, 0);
sqlite3VdbeAddOp(v, OP_MemLoad, iMem, 0);
sqlite3VdbeOp3(v, OP_String8, 0, 0, " ", 0);
for(i=0; i<nCol; i++){
sqlite3VdbeAddOp(v, OP_MemLoad, iMem, 0);
sqlite3VdbeAddOp(v, OP_MemLoad, iMem+i+1, 0);
sqlite3VdbeAddOp(v, OP_Add, 0, 0);
sqlite3VdbeAddOp(v, OP_AddImm, -1, 0);
sqlite3VdbeAddOp(v, OP_MemLoad, iMem+i+1, 0);
sqlite3VdbeAddOp(v, OP_Divide, 0, 0);
if( i==nCol-1 ){
sqlite3VdbeAddOp(v, OP_Concat, nCol*2-1, 0);
}else{
sqlite3VdbeAddOp(v, OP_Dup, 1, 0);
}
}
sqlite3VdbeOp3(v, OP_MakeRecord, 3, 0, "ttt", 0);
sqlite3VdbeAddOp(v, OP_Insert, iStatCur, 0);
sqlite3VdbeChangeP2(v, addr, sqlite3VdbeCurrentAddr(v));
}
}
/*
** Generate code that will cause the most recent index analysis to
** be laoded into internal hash tables where is can be used.
*/
static void loadAnalysis(Parse *pParse, int iDb){
Vdbe *v = sqlite3GetVdbe(pParse);
sqlite3VdbeAddOp(v, OP_LoadAnalysis, iDb, 0);
}
/*
** Generate code that will do an analysis of an entire database
*/
static void analyzeDatabase(Parse *pParse, int iDb){
sqlite3 *db = pParse->db;
HashElem *k;
int iStatCur;
int iMem;
sqlite3BeginWriteOperation(pParse, 0, iDb);
iStatCur = pParse->nTab++;
openStatTable(pParse, iDb, iStatCur, 0);
iMem = pParse->nMem;
for(k=sqliteHashFirst(&db->aDb[iDb].tblHash); k; k=sqliteHashNext(k)){
Table *pTab = (Table*)sqliteHashData(k);
analyzeOneTable(pParse, pTab, iStatCur, iMem);
}
loadAnalysis(pParse, iDb);
}
/*
** Generate code that will do an analysis of a single table in
** a database.
*/
static void analyzeTable(Parse *pParse, Table *pTab){
int iDb;
int iStatCur;
assert( pTab!=0 );
iDb = pTab->iDb;
sqlite3BeginWriteOperation(pParse, 0, iDb);
iStatCur = pParse->nTab++;
openStatTable(pParse, iDb, iStatCur, pTab->zName);
analyzeOneTable(pParse, pTab, iStatCur, pParse->nMem);
loadAnalysis(pParse, iDb);
}
/*
** Generate code for the ANALYZE command. The parser calls this routine
** when it recognizes an ANALYZE command.
**
** ANALYZE -- 1
** ANALYZE <database> -- 2
** ANALYZE ?<database>.?<tablename> -- 3
**
** Form 1 causes all indices in all attached databases to be analyzed.
** Form 2 analyzes all indices the single database named.
** Form 3 analyzes all indices associated with the named table.
*/
void sqlite3Analyze(Parse *pParse, Token *pName1, Token *pName2){
sqlite3 *db = pParse->db;
int iDb;
int i;
char *z, *zDb;
Table *pTab;
Token *pTableName;
/* Read the database schema. If an error occurs, leave an error message
** and code in pParse and return NULL. */
if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){
return;
}
if( pName1==0 ){
/* Form 1: Analyze everything */
for(i=0; i<db->nDb; i++){
if( i==1 ) continue; /* Do not analyze the TEMP database */
analyzeDatabase(pParse, i);
}
}else if( pName2==0 || pName2->n==0 ){
/* Form 2: Analyze the database or table named */
iDb = sqlite3FindDb(db, pName1);
if( iDb>=0 ){
analyzeDatabase(pParse, iDb);
}else{
z = sqlite3NameFromToken(pName1);
pTab = sqlite3LocateTable(pParse, z, 0);
sqliteFree(z);
if( pTab ){
analyzeTable(pParse, pTab);
}
}
}else{
/* Form 3: Analyze the fully qualified table name */
iDb = sqlite3TwoPartName(pParse, pName1, pName2, &pTableName);
if( iDb>=0 ){
zDb = db->aDb[iDb].zName;
z = sqlite3NameFromToken(pTableName);
pTab = sqlite3LocateTable(pParse, z, zDb);
sqliteFree(z);
if( pTab ){
analyzeTable(pParse, pTab);
}
}
}
}
/*
** Used to pass information from the analyzer reader through to the
** callback routine.
*/
typedef struct analysisInfo analysisInfo;
struct analysisInfo {
sqlite3 *db;
const char *zDatabase;
};
/*
** This callback is invoked once for each index when reading the
** sqlite_stat1 table.
**
** argv[0] = name of the index
** argv[1] = results of analysis - on integer for each column
*/
static int analysisLoader(void *pData, int argc, char **argv, char **azNotUsed){
analysisInfo *pInfo = (analysisInfo*)pData;
Index *pIndex;
int i, c;
unsigned int v;
const char *z;
assert( argc==2 );
if( argv[0]==0 || argv[1]==0 ){
return 0;
}
pIndex = sqlite3FindIndex(pInfo->db, argv[0], pInfo->zDatabase);
if( pIndex==0 ){
return 0;
}
z = argv[1];
for(i=0; *z && i<=pIndex->nColumn; i++){
v = 0;
while( (c=z[0])>='0' && c<='9' ){
v = v*10 + c - '0';
z++;
}
pIndex->aiRowEst[i] = v;
if( *z==' ' ) z++;
}
return 0;
}
/*
** Load the content of the sqlite_stat1 table into the index hash tables.
*/
void sqlite3AnalysisLoad(sqlite3 *db, int iDb){
analysisInfo sInfo;
HashElem *i;
char *zSql;
/* Clear any prior statistics */
for(i=sqliteHashFirst(&db->aDb[iDb].idxHash); i; i=sqliteHashNext(i)){
Index *pIdx = sqliteHashData(i);
sqlite3DefaultRowEst(pIdx);
}
/* Check to make sure the sqlite_stat1 table existss */
sInfo.db = db;
sInfo.zDatabase = db->aDb[iDb].zName;
if( sqlite3FindTable(db, "sqlite_stat1", sInfo.zDatabase)==0 ){
return;
}
/* Load new statistics out of the sqlite_stat1 table */
zSql = sqlite3MPrintf("SELECT idx, stat FROM %Q.sqlite_stat1",
sInfo.zDatabase);
sqlite3SafetyOff(db);
sqlite3_exec(db, zSql, analysisLoader, &sInfo, 0);
sqlite3SafetyOn(db);
sqliteFree(zSql);
}
#endif /* SQLITE_OMIT_ANALYZE */

View file

@ -146,8 +146,8 @@ void sqlite3Attach(
db->aDb[i].pBt = 0;
}
sqlite3ResetInternalSchema(db, 0);
if( 0==pParse->nErr ){
pParse->nErr++;
assert( pParse->nErr>0 ); /* Always set by sqlite3ReadSchema() */
if( pParse->rc==SQLITE_OK ){
pParse->rc = SQLITE_ERROR;
}
}

View file

@ -234,8 +234,19 @@ typedef struct MemPage MemPage;
/*
** This is a magic string that appears at the beginning of every
** SQLite database in order to identify the file as a real database.
** 123456789 123456 */
static const char zMagicHeader[] = "SQLite format 3";
**
** You can change this value at compile-time by specifying a
** -DSQLITE_FILE_HEADER="..." on the compiler command-line. The
** header must be exactly 16 bytes including the zero-terminator so
** the string itself should be 15 characters long. If you change
** the header, then your custom library will not be able to read
** databases generated by the standard tools and the standard tools
** will not be able to read databases created by your custom library.
*/
#ifndef SQLITE_FILE_HEADER /* 123456789 123456 */
# define SQLITE_FILE_HEADER "SQLite format 3"
#endif
static const char zMagicHeader[] = SQLITE_FILE_HEADER;
/*
** Page type flags. An ORed combination of these flags appear as the
@ -1334,6 +1345,15 @@ int sqlite3BtreeSetSafetyLevel(Btree *pBt, int level){
}
#endif
/*
** Return TRUE if the given btree is set to safety level 1. In other
** words, return TRUE if no sync() occurs on the disk files.
*/
int sqlite3BtreeSyncDisabled(Btree *pBt){
assert( pBt && pBt->pPager );
return sqlite3pager_nosync(pBt->pPager);
}
#if !defined(SQLITE_OMIT_PAGER_PRAGMAS) || !defined(SQLITE_OMIT_VACUUM)
/*
** Change the default pages size and the number of reserved bytes per page.
@ -1595,8 +1615,6 @@ static int newDatabase(Btree *pBt){
*/
int sqlite3BtreeBeginTrans(Btree *pBt, int wrflag){
int rc = SQLITE_OK;
int busy = 0;
BusyHandler *pH;
/* If the btree is already in a write-transaction, or it
** is already in a read-transaction and a read-transaction
@ -1630,9 +1648,7 @@ int sqlite3BtreeBeginTrans(Btree *pBt, int wrflag){
unlockBtreeIfUnused(pBt);
}
}while( rc==SQLITE_BUSY && pBt->inTrans==TRANS_NONE &&
(pH = pBt->pBusyHandler)!=0 &&
pH->xFunc && pH->xFunc(pH->pArg, busy++)
);
sqlite3InvokeBusyHandler(pBt->pBusyHandler) );
return rc;
}
@ -3595,17 +3611,19 @@ static void assemblePage(
data = pPage->aData;
hdr = pPage->hdrOffset;
put2byte(&data[hdr+3], nCell);
cellbody = allocateSpace(pPage, totalSize);
assert( cellbody>0 );
assert( pPage->nFree >= 2*nCell );
pPage->nFree -= 2*nCell;
for(i=0; i<nCell; i++){
put2byte(&data[cellptr], cellbody);
memcpy(&data[cellbody], apCell[i], aSize[i]);
cellptr += 2;
cellbody += aSize[i];
if( nCell ){
cellbody = allocateSpace(pPage, totalSize);
assert( cellbody>0 );
assert( pPage->nFree >= 2*nCell );
pPage->nFree -= 2*nCell;
for(i=0; i<nCell; i++){
put2byte(&data[cellptr], cellbody);
memcpy(&data[cellbody], apCell[i], aSize[i]);
cellptr += 2;
cellbody += aSize[i];
}
assert( cellbody==pPage->pBt->usableSize );
}
assert( cellbody==pPage->pBt->usableSize );
pPage->nCell = nCell;
}
@ -3809,7 +3827,7 @@ static int balance_nonroot(MemPage *pPage){
/*
** A special case: If a new entry has just been inserted into a
** table (that is, a btree with integer keys and all data at the leaves)
** an the new entry is the right-most entry in the tree (it has the
** and the new entry is the right-most entry in the tree (it has the
** largest key) then use the special balance_quick() routine for
** balancing. balance_quick() is much faster and results in a tighter
** packing of data in the common case.
@ -4082,7 +4100,12 @@ static int balance_nonroot(MemPage *pPage){
szNew[i] = szRight;
szNew[i-1] = szLeft;
}
assert( cntNew[0]>0 );
/* Either we found one or more cells (cntnew[0])>0) or we are the
** a virtual root page. A virtual root page is when the real root
** page is page 1 and we are the only child of that page.
*/
assert( cntNew[0]>0 || (pParent->pgno==1 && pParent->nCell==0) );
/*
** Allocate k new pages. Reuse old pages where possible.
@ -4171,7 +4194,7 @@ static int balance_nonroot(MemPage *pPage){
assert( j<nMaxCells );
assert( pNew->pgno==pgnoNew[i] );
assemblePage(pNew, cntNew[i]-j, &apCell[j], &szCell[j]);
assert( pNew->nCell>0 );
assert( pNew->nCell>0 || (nNew==1 && cntNew[0]==0) );
assert( pNew->nOverflow==0 );
#ifndef SQLITE_OMIT_AUTOVACUUM

View file

@ -58,6 +58,7 @@ int sqlite3BtreeClose(Btree*);
int sqlite3BtreeSetBusyHandler(Btree*,BusyHandler*);
int sqlite3BtreeSetCacheSize(Btree*,int);
int sqlite3BtreeSetSafetyLevel(Btree*,int);
int sqlite3BtreeSyncDisabled(Btree*);
int sqlite3BtreeSetPageSize(Btree*,int,int);
int sqlite3BtreeGetPageSize(Btree*);
int sqlite3BtreeGetReserve(Btree*);

View file

@ -200,9 +200,6 @@ Table *sqlite3LocateTable(Parse *pParse, const char *zName, const char *zDbase){
if( p==0 ){
if( zDbase ){
sqlite3ErrorMsg(pParse, "no such table: %s.%s", zDbase, zName);
}else if( sqlite3FindTable(pParse->db, zName, 0)!=0 ){
sqlite3ErrorMsg(pParse, "table \"%s\" is not in database \"%s\"",
zName, zDbase);
}else{
sqlite3ErrorMsg(pParse, "no such table: %s", zName);
}
@ -258,10 +255,7 @@ static void sqliteDeleteIndex(sqlite3 *db, Index *p){
assert( db!=0 && p->zName!=0 );
pOld = sqlite3HashInsert(&db->aDb[p->iDb].idxHash, p->zName,
strlen(p->zName)+1, 0);
if( pOld!=0 && pOld!=p ){
sqlite3HashInsert(&db->aDb[p->iDb].idxHash, pOld->zName,
strlen(pOld->zName)+1, pOld);
}
assert( pOld==0 || pOld==p );
freeIndex(p);
}
@ -535,7 +529,7 @@ void sqlite3OpenMasterTable(Vdbe *v, int iDb){
** index of the named database in db->aDb[], or -1 if the named db
** does not exist.
*/
static int findDb(sqlite3 *db, Token *pName){
int sqlite3FindDb(sqlite3 *db, Token *pName){
int i = -1; /* Database number */
int n; /* Number of characters in the name */
Db *pDb; /* A database whose name space is being searched */
@ -583,7 +577,7 @@ int sqlite3TwoPartName(
if( pName2 && pName2->n>0 ){
assert( !db->init.busy );
*pUnqual = pName2;
iDb = findDb(db, pName1);
iDb = sqlite3FindDb(db, pName1);
if( iDb<0 ){
sqlite3ErrorMsg(pParse, "unknown database %T", pName1);
pParse->nErr++;
@ -745,7 +739,7 @@ void sqlite3StartTable(
** so that INSERT can find the table easily.
*/
#ifndef SQLITE_OMIT_AUTOINCREMENT
if( strcmp(zName, "sqlite_sequence")==0 ){
if( !pParse->nested && strcmp(zName, "sqlite_sequence")==0 ){
db->aDb[iDb].pSeqTab = pTable;
}
#endif
@ -902,11 +896,11 @@ void sqlite3AddNotNull(Parse *pParse, int onError){
** If none of the substrings in the above table are found,
** SQLITE_AFF_NUMERIC is returned.
*/
static char sqlite3AffinityType(const char *zType, int nType){
char sqlite3AffinityType(const Token *pType){
u32 h = 0;
char aff = SQLITE_AFF_NUMERIC;
const unsigned char *zIn = zType;
const unsigned char *zEnd = (zIn+nType);
const unsigned char *zIn = pType->z;
const unsigned char *zEnd = &pType->z[pType->n];
while( zIn!=zEnd ){
h = (h<<8) + sqlite3UpperToLower[*zIn];
@ -938,30 +932,18 @@ static char sqlite3AffinityType(const char *zType, int nType){
** that contains the typename of the column and store that string
** in zType.
*/
void sqlite3AddColumnType(Parse *pParse, Token *pFirst, Token *pLast){
void sqlite3AddColumnType(Parse *pParse, Token *pType){
Table *p;
int i, j;
int n;
char *z;
const unsigned char *zIn;
int i;
Column *pCol;
if( (p = pParse->pNewTable)==0 ) return;
i = p->nCol-1;
if( i<0 ) return;
pCol = &p->aCol[i];
zIn = pFirst->z;
n = pLast->n + (pLast->z - zIn);
assert( pCol->zType==0 );
z = pCol->zType = sqliteMallocRaw(n+1);
if( z==0 ) return;
for(i=j=0; i<n; i++){
int c = zIn[i];
if( isspace(c) ) continue;
z[j++] = c;
}
z[j] = 0;
pCol->affinity = sqlite3AffinityType(z, n);
pCol->zType = sqlite3NameFromToken(pType);
pCol->affinity = sqlite3AffinityType(pType);
}
/*
@ -977,14 +959,15 @@ void sqlite3AddColumnType(Parse *pParse, Token *pFirst, Token *pLast){
void sqlite3AddDefaultValue(Parse *pParse, Expr *pExpr){
Table *p;
Column *pCol;
if( (p = pParse->pNewTable)==0 ) return;
pCol = &(p->aCol[p->nCol-1]);
if( !sqlite3ExprIsConstant(pExpr) ){
sqlite3ErrorMsg(pParse, "default value of column [%s] is not constant",
pCol->zName);
}else{
sqlite3ExprDelete(pCol->pDflt);
pCol->pDflt = sqlite3ExprDup(pExpr);
if( (p = pParse->pNewTable)!=0 ){
pCol = &(p->aCol[p->nCol-1]);
if( !sqlite3ExprIsConstantOrFunction(pExpr) ){
sqlite3ErrorMsg(pParse, "default value of column [%s] is not constant",
pCol->zName);
}else{
sqlite3ExprDelete(pCol->pDflt);
pCol->pDflt = sqlite3ExprDup(pExpr);
}
}
sqlite3ExprDelete(pExpr);
}
@ -1317,13 +1300,11 @@ void sqlite3EndTable(
*/
if( p->pSelect==0 ){
/* A regular table */
/* sqlite3VdbeAddOp(v, OP_CreateTable, p->iDb, 0); */
zType = "table";
zType2 = "TABLE";
#ifndef SQLITE_OMIT_VIEW
}else{
/* A view */
/* sqlite3VdbeAddOp(v, OP_Integer, 0, 0); */
zType = "view";
zType2 = "VIEW";
#endif
@ -1535,10 +1516,13 @@ int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){
** Actually, this error is caught previously and so the following test
** should always fail. But we will leave it in place just to be safe.
*/
#if 0
if( pTable->nCol<0 ){
sqlite3ErrorMsg(pParse, "view %s is circularly defined", pTable->zName);
return 1;
}
#endif
assert( pTable->nCol>=0 );
/* If we get this far, it means we need to compute the table names.
** Note that the call to sqlite3ResultSetOfSelect() will expand any
@ -1973,7 +1957,6 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){
int addr1; /* Address of top of loop */
int tnum; /* Root page of index */
Vdbe *v; /* Generate code into this virtual machine */
int isUnique; /* True for a unique index */
#ifndef SQLITE_OMIT_AUTHORIZATION
if( sqlite3AuthCheck(pParse, SQLITE_REINDEX, pIndex->zName, 0,
@ -2002,16 +1985,21 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){
sqlite3VdbeAddOp(v, OP_Integer, pIndex->iDb, 0);
sqlite3VdbeOp3(v, OP_OpenWrite, iIdx, tnum,
(char*)&pIndex->keyInfo, P3_KEYINFO);
sqlite3VdbeAddOp(v, OP_Integer, pTab->iDb, 0);
sqlite3VdbeAddOp(v, OP_OpenRead, iTab, pTab->tnum);
sqlite3VdbeAddOp(v, OP_SetNumColumns, iTab, pTab->nCol);
sqlite3OpenTableForReading(v, iTab, pTab);
addr1 = sqlite3VdbeAddOp(v, OP_Rewind, iTab, 0);
sqlite3GenerateIndexKey(v, pIndex, iTab);
isUnique = pIndex->onError!=OE_None;
sqlite3VdbeAddOp(v, OP_IdxInsert, iIdx, isUnique);
if( isUnique ){
sqlite3VdbeChangeP3(v, -1, "indexed columns are not unique", P3_STATIC);
if( pIndex->onError!=OE_None ){
int curaddr = sqlite3VdbeCurrentAddr(v);
int addr2 = curaddr+4;
sqlite3VdbeChangeP2(v, curaddr-1, addr2);
sqlite3VdbeAddOp(v, OP_Rowid, iTab, 0);
sqlite3VdbeAddOp(v, OP_AddImm, 1, 0);
sqlite3VdbeAddOp(v, OP_IsUnique, iIdx, addr2);
sqlite3VdbeOp3(v, OP_Halt, SQLITE_CONSTRAINT, OE_Abort,
"indexed columns are not unique", P3_STATIC);
assert( addr2==sqlite3VdbeCurrentAddr(v) );
}
sqlite3VdbeAddOp(v, OP_IdxInsert, iIdx, 0);
sqlite3VdbeAddOp(v, OP_Next, iTab, addr1+1);
sqlite3VdbeChangeP2(v, addr1, sqlite3VdbeCurrentAddr(v));
sqlite3VdbeAddOp(v, OP_Close, iTab, 0);
@ -2079,7 +2067,9 @@ void sqlite3CreateIndex(
if( sqlite3FixInit(&sFix, pParse, iDb, "index", pName) &&
sqlite3FixSrcList(&sFix, pTblName)
){
goto exit_create_index;
/* Because the parser constructs pTblName from a single identifier,
** sqlite3FixSrcList can never fail. */
assert(0);
}
pTab = sqlite3LocateTable(pParse, pTblName->a[0].zName,
pTblName->a[0].zDatabase);
@ -2177,11 +2167,12 @@ void sqlite3CreateIndex(
/*
** Allocate the index structure.
*/
pIndex = sqliteMalloc( sizeof(Index) + strlen(zName) + 1 +
(sizeof(int) + sizeof(CollSeq*))*pList->nExpr );
pIndex = sqliteMalloc( sizeof(Index) + strlen(zName) + 1 + sizeof(int) +
(sizeof(int)*2 + sizeof(CollSeq*))*pList->nExpr );
if( sqlite3_malloc_failed ) goto exit_create_index;
pIndex->aiColumn = (int*)&pIndex->keyInfo.aColl[pList->nExpr];
pIndex->zName = (char*)&pIndex->aiColumn[pList->nExpr];
pIndex->aiRowEst = &pIndex->aiColumn[pList->nExpr];
pIndex->zName = (char*)&pIndex->aiRowEst[pList->nExpr+1];
strcpy(pIndex->zName, zName);
pIndex->pTable = pTab;
pIndex->nColumn = pList->nExpr;
@ -2217,6 +2208,7 @@ void sqlite3CreateIndex(
}
}
pIndex->keyInfo.nField = pList->nExpr;
sqlite3DefaultRowEst(pIndex);
if( pTab==pParse->pNewTable ){
/* This routine has been called to create an automatic index as a
@ -2383,6 +2375,37 @@ exit_create_index:
return;
}
/*
** Fill the Index.aiRowEst[] array with default information - information
** to be used when we have not run the ANALYZE command.
**
** aiRowEst[0] is suppose to contain the number of elements in the index.
** Since we do not know, guess 1 million. aiRowEst[1] is an estimate of the
** number of rows in the table that match any particular value of the
** first column of the index. aiRowEst[2] is an estimate of the number
** of rows that match any particular combiniation of the first 2 columns
** of the index. And so forth. It must always be the case that
*
** aiRowEst[N]<=aiRowEst[N-1]
** aiRowEst[N]>=1
**
** Apart from that, we have little to go on besides intuition as to
** how aiRowEst[] should be initialized. The numbers generated here
** are based on typical values found in actual indices.
*/
void sqlite3DefaultRowEst(Index *pIdx){
int *a = pIdx->aiRowEst;
int i;
assert( a!=0 );
a[0] = 1000000;
for(i=pIdx->nColumn; i>=1; i--){
a[i] = 10;
}
if( pIdx->onError!=OE_None ){
a[pIdx->nColumn] = 1;
}
}
/*
** This routine will drop an existing named index. This routine
** implements the DROP INDEX statement.
@ -2472,6 +2495,32 @@ IdList *sqlite3IdListAppend(IdList *pList, Token *pToken){
return pList;
}
/*
** Delete an IdList.
*/
void sqlite3IdListDelete(IdList *pList){
int i;
if( pList==0 ) return;
for(i=0; i<pList->nId; i++){
sqliteFree(pList->a[i].zName);
}
sqliteFree(pList->a);
sqliteFree(pList);
}
/*
** Return the index in pList of the identifier named zId. Return -1
** if not found.
*/
int sqlite3IdListIndex(IdList *pList, const char *zName){
int i;
if( pList==0 ) return -1;
for(i=0; i<pList->nId; i++){
if( sqlite3StrICmp(pList->a[i].zName, zName)==0 ) return i;
}
return -1;
}
/*
** Append a new table name to the given SrcList. Create a new SrcList if
** need be. A new entry is created in the SrcList even if pToken is NULL.
@ -2556,32 +2605,6 @@ void sqlite3SrcListAddAlias(SrcList *pList, Token *pToken){
}
}
/*
** Delete an IdList.
*/
void sqlite3IdListDelete(IdList *pList){
int i;
if( pList==0 ) return;
for(i=0; i<pList->nId; i++){
sqliteFree(pList->a[i].zName);
}
sqliteFree(pList->a);
sqliteFree(pList);
}
/*
** Return the index in pList of the identifier named zId. Return -1
** if not found.
*/
int sqlite3IdListIndex(IdList *pList, const char *zName){
int i;
if( pList==0 ) return -1;
for(i=0; i<pList->nId; i++){
if( sqlite3StrICmp(pList->a[i].zName, zName)==0 ) return i;
}
return -1;
}
/*
** Delete an entire SrcList including all its substructure.
*/
@ -2784,7 +2807,7 @@ static int collationMatch(CollSeq *pColl, Index *pIndex){
** If pColl==0 then recompute all indices of pTab.
*/
#ifndef SQLITE_OMIT_REINDEX
void reindexTable(Parse *pParse, Table *pTab, CollSeq *pColl){
static void reindexTable(Parse *pParse, Table *pTab, CollSeq *pColl){
Index *pIndex; /* An index associated with pTab */
for(pIndex=pTab->pIndex; pIndex; pIndex=pIndex->pNext){
@ -2802,7 +2825,7 @@ void reindexTable(Parse *pParse, Table *pTab, CollSeq *pColl){
** all indices everywhere.
*/
#ifndef SQLITE_OMIT_REINDEX
void reindexDatabases(Parse *pParse, CollSeq *pColl){
static void reindexDatabases(Parse *pParse, CollSeq *pColl){
Db *pDb; /* A single database */
int iDb; /* The database index number */
sqlite3 *db = pParse->db; /* The database connection */
@ -2811,7 +2834,7 @@ void reindexDatabases(Parse *pParse, CollSeq *pColl){
for(iDb=0, pDb=db->aDb; iDb<db->nDb; iDb++, pDb++){
if( pDb==0 ) continue;
for(k=sqliteHashFirst(&pDb->tblHash); k; k=sqliteHashNext(k)){
for(k=sqliteHashFirst(&pDb->tblHash); k; k=sqliteHashNext(k)){
pTab = (Table*)sqliteHashData(k);
reindexTable(pParse, pTab, pColl);
}

View file

@ -147,7 +147,7 @@ int sqlite3CheckCollSeq(Parse *pParse, CollSeq *pColl){
** the collation sequence name. A pointer to this string is stored in
** each collation sequence structure.
*/
static CollSeq * findCollSeqEntry(
static CollSeq *findCollSeqEntry(
sqlite3 *db,
const char *zName,
int nName,
@ -286,10 +286,9 @@ FuncDef *sqlite3FindFunction(
** new entry to the hash table and return it.
*/
if( createFlag && bestmatch<6 &&
(pBest = sqliteMalloc(sizeof(*pBest)+nName+1)) ){
(pBest = sqliteMalloc(sizeof(*pBest)+nName)) ){
pBest->nArg = nArg;
pBest->pNext = pFirst;
pBest->zName = (char*)&pBest[1];
pBest->iPrefEnc = enc;
memcpy(pBest->zName, zName, nName);
pBest->zName[nName] = 0;

View file

@ -124,11 +124,7 @@ static int getDigits(const char *zDate, ...){
** Read text from z[] and convert into a floating point number. Return
** the number of digits converted.
*/
static int getValue(const char *z, double *pR){
const char *zEnd;
*pR = sqlite3AtoF(z, &zEnd);
return zEnd - z;
}
#define getValue sqlite3AtoF
/*
** Parse a timezone extension on the end of a date-time.
@ -320,7 +316,7 @@ static int parseDateOrTime(const char *zDate, DateTime *p){
p->validJD = 1;
return 0;
}else if( sqlite3IsNumber(zDate, 0, SQLITE_UTF8) ){
p->rJD = sqlite3AtoF(zDate, 0);
getValue(zDate, &p->rJD);
p->validJD = 1;
return 0;
}

View file

@ -65,8 +65,8 @@ void sqlite3OpenTableForReading(
Table *pTab /* The table to be opened */
){
sqlite3VdbeAddOp(v, OP_Integer, pTab->iDb, 0);
sqlite3VdbeAddOp(v, OP_OpenRead, iCur, pTab->tnum);
VdbeComment((v, "# %s", pTab->zName));
sqlite3VdbeAddOp(v, OP_OpenRead, iCur, pTab->tnum);
sqlite3VdbeAddOp(v, OP_SetNumColumns, iCur, pTab->nCol);
}
@ -240,7 +240,7 @@ void sqlite3DeleteFrom(
/* Remember the rowid of every item to be deleted.
*/
sqlite3VdbeAddOp(v, OP_Rowid, iCur, 0);
sqlite3VdbeAddOp(v, OP_ListWrite, 0, 0);
sqlite3VdbeAddOp(v, OP_FifoWrite, 0, 0);
if( db->flags & SQLITE_CountRows ){
sqlite3VdbeAddOp(v, OP_AddImm, 1, 0);
}
@ -260,14 +260,13 @@ void sqlite3DeleteFrom(
** database scan. We have to delete items after the scan is complete
** because deleting an item can change the scan order.
*/
sqlite3VdbeAddOp(v, OP_ListRewind, 0, 0);
end = sqlite3VdbeMakeLabel(v);
/* This is the beginning of the delete loop when there are
** row triggers.
*/
if( triggers_exist ){
addr = sqlite3VdbeAddOp(v, OP_ListRead, 0, end);
addr = sqlite3VdbeAddOp(v, OP_FifoRead, 0, end);
if( !isView ){
sqlite3VdbeAddOp(v, OP_Dup, 0, 0);
sqlite3OpenTableForReading(v, iCur, pTab);
@ -288,7 +287,7 @@ void sqlite3DeleteFrom(
if( !isView ){
/* Open cursors for the table we are deleting from and all its
** indices. If there are row triggers, this happens inside the
** OP_ListRead loop because the cursor have to all be closed
** OP_FifoRead loop because the cursor have to all be closed
** before the trigger fires. If there are no row triggers, the
** cursors are opened only once on the outside the loop.
*/
@ -297,7 +296,7 @@ void sqlite3DeleteFrom(
/* This is the beginning of the delete loop when there are no
** row triggers */
if( !triggers_exist ){
addr = sqlite3VdbeAddOp(v, OP_ListRead, 0, end);
addr = sqlite3VdbeAddOp(v, OP_FifoRead, 0, end);
}
/* Delete the row */
@ -322,7 +321,6 @@ void sqlite3DeleteFrom(
/* End of the delete loop */
sqlite3VdbeAddOp(v, OP_Goto, 0, addr);
sqlite3VdbeResolveLabel(v, end);
sqlite3VdbeAddOp(v, OP_ListReset, 0, 0);
/* Close the cursors after the loop if there are no row triggers */
if( !triggers_exist ){
@ -442,6 +440,6 @@ void sqlite3GenerateIndexKey(
sqlite3ColumnDefault(v, pTab, idx);
}
}
sqlite3VdbeAddOp(v, OP_MakeRecord, pIdx->nColumn, (1<<24));
sqlite3VdbeAddOp(v, OP_MakeIdxRec, pIdx->nColumn, 0);
sqlite3IndexAffinityStr(v, pIdx);
}

View file

@ -15,7 +15,6 @@
** $Id$
*/
#include "sqliteInt.h"
#include "os.h"
/*
** Set all the parameters in the compiled SQL statement to NULL.

View file

@ -34,12 +34,18 @@
** SELECT * FROM t1 WHERE (select a from t1);
*/
char sqlite3ExprAffinity(Expr *pExpr){
if( pExpr->op==TK_AS ){
int op = pExpr->op;
if( op==TK_AS ){
return sqlite3ExprAffinity(pExpr->pLeft);
}
if( pExpr->op==TK_SELECT ){
if( op==TK_SELECT ){
return sqlite3ExprAffinity(pExpr->pSelect->pEList->a[0].pExpr);
}
#ifndef SQLITE_OMIT_CAST
if( op==TK_CAST ){
return sqlite3AffinityType(&pExpr->token);
}
#endif
return pExpr->affinity;
}
@ -51,7 +57,7 @@ CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr){
CollSeq *pColl = 0;
if( pExpr ){
pColl = pExpr->pColl;
if( pExpr->op==TK_AS && !pColl ){
if( (pExpr->op==TK_AS || pExpr->op==TK_CAST) && !pColl ){
return sqlite3ExprCollSeq(pParse, pExpr->pLeft);
}
}
@ -87,6 +93,7 @@ char sqlite3CompareAffinity(Expr *pExpr, char aff2){
return SQLITE_AFF_NONE;
}else{
/* One side is a column, the other is not. Use the columns affinity. */
assert( aff1==0 || aff2==0 );
return (aff1 + aff2);
}
}
@ -207,9 +214,8 @@ Expr *sqlite3Expr(int op, Expr *pLeft, Expr *pRight, const Token *pToken){
/*
** When doing a nested parse, you can include terms in an expression
** that look like this: #0 #1 #2 ... These terms refer to elements
** on the stack. "#0" (or just "#") means the top of the stack.
** "#1" means the next down on the stack. And so forth. #-1 means
** memory location 0. #-2 means memory location 1. And so forth.
** on the stack. "#0" means the top of the stack.
** "#1" means the next down on the stack. And so forth.
**
** This routine is called by the parser to deal with on of those terms.
** It immediately generates code to store the value in a memory location.
@ -220,23 +226,19 @@ Expr *sqlite3RegisterExpr(Parse *pParse, Token *pToken){
Vdbe *v = pParse->pVdbe;
Expr *p;
int depth;
if( v==0 ) return 0;
if( pParse->nested==0 ){
sqlite3ErrorMsg(pParse, "near \"%T\": syntax error", pToken);
return 0;
}
if( v==0 ) return 0;
p = sqlite3Expr(TK_REGISTER, 0, 0, pToken);
if( p==0 ){
return 0; /* Malloc failed */
}
depth = atoi(&pToken->z[1]);
if( depth>=0 ){
p->iTable = pParse->nMem++;
sqlite3VdbeAddOp(v, OP_Dup, depth, 0);
sqlite3VdbeAddOp(v, OP_MemStore, p->iTable, 1);
}else{
p->iTable = -1-depth;
}
p->iTable = pParse->nMem++;
sqlite3VdbeAddOp(v, OP_Dup, depth, 0);
sqlite3VdbeAddOp(v, OP_MemStore, p->iTable, 1);
return p;
}
@ -378,6 +380,21 @@ void sqlite3ExprDelete(Expr *p){
sqliteFree(p);
}
/*
** The Expr.token field might be a string literal that is quoted.
** If so, remove the quotation marks.
*/
void sqlite3DequoteExpr(Expr *p){
if( ExprHasAnyProperty(p, EP_Dequoted) ){
return;
}
ExprSetProperty(p, EP_Dequoted);
if( p->token.dyn==0 ){
sqlite3TokenCopy(&p->token, &p->token);
}
sqlite3Dequote((char*)p->token.z);
}
/*
** The following group of routines make deep copies of expressions,
@ -529,7 +546,7 @@ Select *sqlite3SelectDup(Select *p){
pNew->pOffset = sqlite3ExprDup(p->pOffset);
pNew->iLimit = -1;
pNew->iOffset = -1;
pNew->ppOpenTemp = 0;
pNew->ppOpenVirtual = 0;
pNew->isResolved = p->isResolved;
pNew->isAgg = p->isAgg;
return pNew;
@ -607,6 +624,8 @@ void sqlite3ExprListDelete(ExprList *pList){
**
** The return value from this routine is 1 to abandon the tree walk
** and 0 to continue.
**
** NOTICE: This routine does *not* descend into subqueries.
*/
static int walkExprList(ExprList *, int (*)(void *, Expr*), void *);
static int walkExprTree(Expr *pExpr, int (*xFunc)(void*,Expr*), void *pArg){
@ -664,17 +683,26 @@ static int walkSelectExpr(Select *p, int (*xFunc)(void *, Expr*), void *pArg){
*/
static int exprNodeIsConstant(void *pArg, Expr *pExpr){
switch( pExpr->op ){
/* Consider functions to be constant if all their arguments are constant
** and *pArg==2 */
case TK_FUNCTION:
if( *((int*)pArg)==2 ) return 0;
/* Fall through */
case TK_ID:
case TK_COLUMN:
case TK_DOT:
case TK_AGG_FUNCTION:
case TK_FUNCTION:
#ifndef SQLITE_OMIT_SUBQUERY
case TK_SELECT:
case TK_EXISTS:
#endif
*((int*)pArg) = 0;
return 2;
case TK_IN:
if( pExpr->pSelect ){
*((int*)pArg) = 0;
return 2;
}
default:
return 0;
}
@ -682,7 +710,7 @@ static int exprNodeIsConstant(void *pArg, Expr *pExpr){
/*
** Walk an expression tree. Return 1 if the expression is constant
** and 0 if it involves variables.
** and 0 if it involves variables or function calls.
**
** For the purposes of this function, a double-quoted string (ex: "abc")
** is considered a variable but a single-quoted string (ex: 'abc') is
@ -694,6 +722,21 @@ int sqlite3ExprIsConstant(Expr *p){
return isConst;
}
/*
** Walk an expression tree. Return 1 if the expression is constant
** or a function call with constant arguments. Return and 0 if there
** are any variables.
**
** For the purposes of this function, a double-quoted string (ex: "abc")
** is considered a variable but a single-quoted string (ex: 'abc') is
** a constant.
*/
int sqlite3ExprIsConstantOrFunction(Expr *p){
int isConst = 2;
walkExprTree(p, exprNodeIsConstant, &isConst);
return isConst!=0;
}
/*
** If the expression p codes a constant integer that is small enough
** to fit in a 32-bit integer, return 1 and put the value of the integer
@ -1218,19 +1261,25 @@ struct QueryCoder {
*/
#ifndef SQLITE_OMIT_SUBQUERY
void sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){
int label = 0; /* Address after sub-select code */
int testAddr = 0; /* One-time test address */
Vdbe *v = sqlite3GetVdbe(pParse);
if( v==0 ) return;
/* If this is not a variable (correlated) select, then execute
** it only once. Unless this is part of a trigger program. In
** that case re-execute every time (this could be optimized).
/* This code must be run in its entirety every time it is encountered
** if any of the following is true:
**
** * The right-hand side is a correlated subquery
** * The right-hand side is an expression list containing variables
** * We are inside a trigger
**
** If all of the above are false, then we can run this code just once
** save the results, and reuse the same result on subsequent invocations.
*/
if( !ExprHasAnyProperty(pExpr, EP_VarSelect) && !pParse->trigStack ){
int mem = pParse->nMem++;
sqlite3VdbeAddOp(v, OP_MemLoad, mem, 0);
label = sqlite3VdbeMakeLabel(v);
sqlite3VdbeAddOp(v, OP_If, 0, label);
testAddr = sqlite3VdbeAddOp(v, OP_If, 0, 0);
assert( testAddr>0 );
sqlite3VdbeAddOp(v, OP_Integer, 1, 0);
sqlite3VdbeAddOp(v, OP_MemStore, mem, 1);
}
@ -1243,12 +1292,12 @@ void sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){
case TK_IN: {
char affinity;
KeyInfo keyInfo;
int addr; /* Address of OP_OpenTemp instruction */
int addr; /* Address of OP_OpenVirtual instruction */
affinity = sqlite3ExprAffinity(pExpr->pLeft);
/* Whether this is an 'x IN(SELECT...)' or an 'x IN(<exprlist>)'
** expression it is handled the same way. A temporary table is
** expression it is handled the same way. A virtual table is
** filled with single-field index keys representing the results
** from the SELECT or the <exprlist>.
**
@ -1261,7 +1310,7 @@ void sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){
** is used.
*/
pExpr->iTable = pParse->nTab++;
addr = sqlite3VdbeAddOp(v, OP_OpenTemp, pExpr->iTable, 0);
addr = sqlite3VdbeAddOp(v, OP_OpenVirtual, pExpr->iTable, 0);
memset(&keyInfo, 0, sizeof(keyInfo));
keyInfo.nField = 1;
sqlite3VdbeAddOp(v, OP_SetNumColumns, pExpr->iTable, 1);
@ -1290,20 +1339,30 @@ void sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){
** a column, use numeric affinity.
*/
int i;
ExprList *pList = pExpr->pList;
struct ExprList_item *pItem;
if( !affinity ){
affinity = SQLITE_AFF_NUMERIC;
}
keyInfo.aColl[0] = pExpr->pLeft->pColl;
/* Loop through each expression in <exprlist>. */
for(i=0; i<pExpr->pList->nExpr; i++){
Expr *pE2 = pExpr->pList->a[i].pExpr;
for(i=pList->nExpr, pItem=pList->a; i>0; i--, pItem++){
Expr *pE2 = pItem->pExpr;
/* Check that the expression is constant and valid. */
if( !sqlite3ExprIsConstant(pE2) ){
sqlite3ErrorMsg(pParse,
"right-hand side of IN operator must be constant");
return;
/* If the expression is not constant then we will need to
** disable the test that was generated above that makes sure
** this code only executes once. Because for a non-constant
** expression we need to rerun this code each time.
*/
if( testAddr>0 && !sqlite3ExprIsConstant(pE2) ){
VdbeOp *aOp = sqlite3VdbeGetOp(v, testAddr-1);
int i;
for(i=0; i<4; i++){
aOp[i].opcode = OP_Noop;
}
testAddr = 0;
}
/* Evaluate the expression and insert it into the temp table */
@ -1344,8 +1403,8 @@ void sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){
if( pExpr->pSelect ){
sqlite3VdbeAddOp(v, OP_AggContextPop, 0, 0);
}
if( label<0 ){
sqlite3VdbeResolveLabel(v, label);
if( testAddr ){
sqlite3VdbeChangeP2(v, testAddr, sqlite3VdbeCurrentAddr(v));
}
return;
}
@ -1360,7 +1419,7 @@ static void codeInteger(Vdbe *v, const char *z, int n){
if( sqlite3GetInt32(z, &i) ){
sqlite3VdbeAddOp(v, OP_Integer, i, 0);
}else if( sqlite3FitsIn64Bits(z) ){
sqlite3VdbeOp3(v, OP_Integer, 0, 0, z, n);
sqlite3VdbeOp3(v, OP_Int64, 0, 0, z, n);
}else{
sqlite3VdbeOp3(v, OP_Real, 0, 0, z, n);
}
@ -1405,8 +1464,8 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){
case TK_STRING: {
assert( TK_FLOAT==OP_Real );
assert( TK_STRING==OP_String8 );
sqlite3DequoteExpr(pExpr);
sqlite3VdbeOp3(v, op, 0, 0, pExpr->token.z, pExpr->token.n);
sqlite3VdbeDequoteP3(v, -1);
break;
}
case TK_NULL: {
@ -1415,9 +1474,16 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){
}
#ifndef SQLITE_OMIT_BLOB_LITERAL
case TK_BLOB: {
int n;
const char *z;
assert( TK_BLOB==OP_HexBlob );
sqlite3VdbeOp3(v, op, 0, 0, pExpr->token.z+1, pExpr->token.n-1);
sqlite3VdbeDequoteP3(v, -1);
n = pExpr->token.n - 3;
z = pExpr->token.z + 2;
assert( n>=0 );
if( n==0 ){
z = "";
}
sqlite3VdbeOp3(v, op, 0, 0, z, n);
break;
}
#endif
@ -1432,6 +1498,22 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){
sqlite3VdbeAddOp(v, OP_MemLoad, pExpr->iTable, 0);
break;
}
#ifndef SQLITE_OMIT_CAST
case TK_CAST: {
/* Expressions of the form: CAST(pLeft AS token) */
int aff, op;
sqlite3ExprCode(pParse, pExpr->pLeft);
aff = sqlite3AffinityType(&pExpr->token);
switch( aff ){
case SQLITE_AFF_INTEGER: op = OP_ToInt; break;
case SQLITE_AFF_NUMERIC: op = OP_ToNumeric; break;
case SQLITE_AFF_TEXT: op = OP_ToText; break;
case SQLITE_AFF_NONE: op = OP_ToBlob; break;
}
sqlite3VdbeAddOp(v, op, 0, 0);
break;
}
#endif /* SQLITE_OMIT_CAST */
case TK_LT:
case TK_LE:
case TK_GT:
@ -1663,9 +1745,9 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){
assert( pExpr->iColumn==OE_Rollback ||
pExpr->iColumn == OE_Abort ||
pExpr->iColumn == OE_Fail );
sqlite3DequoteExpr(pExpr);
sqlite3VdbeOp3(v, OP_Halt, SQLITE_CONSTRAINT, pExpr->iColumn,
pExpr->token.z, pExpr->token.n);
sqlite3VdbeDequoteP3(v, -1);
} else {
assert( pExpr->iColumn == OE_Ignore );
sqlite3VdbeAddOp(v, OP_ContextPop, 0, 0);
@ -1717,11 +1799,9 @@ int sqlite3ExprCodeExprList(
){
struct ExprList_item *pItem;
int i, n;
Vdbe *v;
if( pList==0 ) return 0;
v = sqlite3GetVdbe(pParse);
n = pList->nExpr;
for(pItem=pList->a, i=0; i<n; i++, pItem++){
for(pItem=pList->a, i=n; i>0; i--, pItem++){
sqlite3ExprCode(pParse, pItem->pExpr);
}
return n;

View file

@ -26,6 +26,9 @@
#include "vdbeInt.h"
#include "os.h"
/*
** Return the collating function associated with a function.
*/
static CollSeq *sqlite3GetFuncCollSeq(sqlite3_context *context){
return context->pColl;
}
@ -78,6 +81,7 @@ static void typeofFunc(
sqlite3_result_text(context, z, -1, SQLITE_STATIC);
}
/*
** Implementation of the length() function
*/
@ -183,7 +187,7 @@ static void substrFunc(
static void roundFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
int n = 0;
double r;
char zBuf[100];
char zBuf[500]; /* larger than the %f representation of the largest double */
assert( argc==1 || argc==2 );
if( argc==2 ){
if( SQLITE_NULL==sqlite3_value_type(argv[1]) ) return;
@ -193,7 +197,7 @@ static void roundFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
}
if( SQLITE_NULL==sqlite3_value_type(argv[0]) ) return;
r = sqlite3_value_double(argv[0]);
sprintf(zBuf,"%.*f",n,r);
sqlite3_snprintf(sizeof(zBuf),zBuf,"%.*f",n,r);
sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT);
}
@ -307,8 +311,14 @@ struct compareInfo {
u8 matchSet;
u8 noCase;
};
static const struct compareInfo globInfo = { '*', '?', '[', 0 };
static const struct compareInfo likeInfo = { '%', '_', 0, 1 };
/* The correct SQL-92 behavior is for the LIKE operator to ignore
** case. Thus 'a' LIKE 'A' would be true. */
static const struct compareInfo likeInfoNorm = { '%', '_', 0, 1 };
/* If SQLITE_CASE_SENSITIVE_LIKE is defined, then the LIKE operator
** is case sensitive causing 'a' LIKE 'A' to be false */
static const struct compareInfo likeInfoAlt = { '%', '_', 0, 0 };
/*
** X is a pointer to the first byte of a UTF-8 character. Increment
@ -450,6 +460,15 @@ static int patternCompare(
return *zString==0;
}
/*
** Count the number of times that the LIKE operator (or GLOB which is
** just a variation of LIKE) gets called. This is used for testing
** only.
*/
#ifdef SQLITE_TEST
int sqlite3_like_count = 0;
#endif
/*
** Implementation of the like() SQL function. This function implements
@ -460,8 +479,8 @@ static int patternCompare(
**
** is implemented as like(B,A).
**
** If the pointer retrieved by via a call to sqlite3_user_data() is
** not NULL, then this function uses UTF-16. Otherwise UTF-8.
** This same function (with a different compareInfo structure) computes
** the GLOB operator.
*/
static void likeFunc(
sqlite3_context *context,
@ -484,24 +503,11 @@ static void likeFunc(
escape = sqlite3ReadUtf8(zEsc);
}
if( zA && zB ){
sqlite3_result_int(context, patternCompare(zA, zB, &likeInfo, escape));
}
}
/*
** Implementation of the glob() SQL function. This function implements
** the build-in GLOB operator. The first argument to the function is the
** string and the second argument is the pattern. So, the SQL statements:
**
** A GLOB B
**
** is implemented as glob(B,A).
*/
static void globFunc(sqlite3_context *context, int arg, sqlite3_value **argv){
const unsigned char *zA = sqlite3_value_text(argv[0]);
const unsigned char *zB = sqlite3_value_text(argv[1]);
if( zA && zB ){
sqlite3_result_int(context, patternCompare(zA, zB, &globInfo, 0));
struct compareInfo *pInfo = sqlite3_user_data(context);
#ifdef SQLITE_TEST
sqlite3_like_count++;
#endif
sqlite3_result_int(context, patternCompare(zA, zB, pInfo, escape));
}
}
@ -876,16 +882,6 @@ static void countFinalize(sqlite3_context *context){
sqlite3_result_int(context, p ? p->n : 0);
}
/*
** This function tracks state information for the min() and max()
** aggregate functions.
*/
typedef struct MinMaxCtx MinMaxCtx;
struct MinMaxCtx {
char *z; /* The best so far */
char zBuf[28]; /* Space that can be used for storage */
};
/*
** Routines to implement min() and max() aggregate functions.
*/
@ -962,9 +958,6 @@ void sqlite3RegisterBuiltinFunctions(sqlite3 *db){
{ "coalesce", 1, 0, SQLITE_UTF8, 0, 0 },
{ "ifnull", 2, 0, SQLITE_UTF8, 1, ifnullFunc },
{ "random", -1, 0, SQLITE_UTF8, 0, randomFunc },
{ "like", 2, 0, SQLITE_UTF8, 0, likeFunc },
{ "like", 3, 0, SQLITE_UTF8, 0, likeFunc },
{ "glob", 2, 0, SQLITE_UTF8, 0, globFunc },
{ "nullif", 2, 0, SQLITE_UTF8, 1, nullifFunc },
{ "sqlite_version", 0, 0, SQLITE_UTF8, 0, versionFunc},
{ "quote", 1, 0, SQLITE_UTF8, 0, quoteFunc },
@ -1036,8 +1029,77 @@ void sqlite3RegisterBuiltinFunctions(sqlite3 *db){
}
sqlite3RegisterDateTimeFunctions(db);
#ifdef SQLITE_SSE
{
sqlite3SseFunctions(db);
}
sqlite3SseFunctions(db);
#endif
#ifdef SQLITE_CASE_SENSITIVE_LIKE
sqlite3RegisterLikeFunctions(db, 1);
#else
sqlite3RegisterLikeFunctions(db, 0);
#endif
}
/*
** Set the LIKEOPT flag on the 2-argument function with the given name.
*/
static void setLikeOptFlag(sqlite3 *db, const char *zName){
FuncDef *pDef;
pDef = sqlite3FindFunction(db, zName, strlen(zName), 2, SQLITE_UTF8, 0);
if( pDef ){
pDef->flags = SQLITE_FUNC_LIKEOPT;
}
}
/*
** Register the built-in LIKE and GLOB functions. The caseSensitive
** parameter determines whether or not the LIKE operator is case
** sensitive. GLOB is always case sensitive.
*/
void sqlite3RegisterLikeFunctions(sqlite3 *db, int caseSensitive){
struct compareInfo *pInfo;
if( caseSensitive ){
pInfo = (struct compareInfo*)&likeInfoAlt;
}else{
pInfo = (struct compareInfo*)&likeInfoNorm;
}
sqlite3_create_function(db, "like", 2, SQLITE_UTF8, pInfo, likeFunc, 0, 0);
sqlite3_create_function(db, "like", 3, SQLITE_UTF8, pInfo, likeFunc, 0, 0);
sqlite3_create_function(db, "glob", 2, SQLITE_UTF8,
(struct compareInfo*)&globInfo, likeFunc, 0,0);
setLikeOptFlag(db, "glob");
if( caseSensitive ){
setLikeOptFlag(db, "like");
}
}
/*
** pExpr points to an expression which implements a function. If
** it is appropriate to apply the LIKE optimization to that function
** then set aWc[0] through aWc[2] to the wildcard characters and
** return TRUE. If the function is not a LIKE-style function then
** return FALSE.
*/
int sqlite3IsLikeFunction(sqlite3 *db, Expr *pExpr, char *aWc){
FuncDef *pDef;
if( pExpr->op!=TK_FUNCTION ){
return 0;
}
if( pExpr->pList->nExpr!=2 ){
return 0;
}
pDef = sqlite3FindFunction(db, pExpr->token.z, pExpr->token.n, 2,
SQLITE_UTF8, 0);
if( pDef==0 || (pDef->flags & SQLITE_FUNC_LIKEOPT)==0 ){
return 0;
}
/* The memcpy() statement assumes that the wildcard characters are
** the first three statements in the compareInfo structure. The
** asserts() that follow verify that assumption
*/
memcpy(aWc, pDef->pUserData, 3);
assert( (char*)&likeInfoAlt == (char*)&likeInfoAlt.matchAll );
assert( &((char*)&likeInfoAlt)[1] == (char*)&likeInfoAlt.matchOne );
assert( &((char*)&likeInfoAlt)[2] == (char*)&likeInfoAlt.matchSet );
return 1;
}

View file

@ -373,7 +373,7 @@ void sqlite3Insert(
** back up and execute the SELECT code above.
*/
sqlite3VdbeChangeP2(v, iInitCode, sqlite3VdbeCurrentAddr(v));
sqlite3VdbeAddOp(v, OP_OpenTemp, srcTab, 0);
sqlite3VdbeAddOp(v, OP_OpenVirtual, srcTab, 0);
sqlite3VdbeAddOp(v, OP_SetNumColumns, srcTab, nColumn);
sqlite3VdbeAddOp(v, OP_Goto, 0, iSelectLoop);
sqlite3VdbeResolveLabel(v, iCleanup);
@ -949,7 +949,7 @@ void sqlite3GenerateConstraintChecks(
sqlite3VdbeAddOp(v, OP_Dup, i+extra+nCol-idx, 1);
}
}
jumpInst1 = sqlite3VdbeAddOp(v, OP_MakeRecord, pIdx->nColumn, (1<<24));
jumpInst1 = sqlite3VdbeAddOp(v, OP_MakeIdxRec, pIdx->nColumn, 0);
sqlite3IndexAffinityStr(v, pIdx);
/* Find out what action to take in case there is an indexing conflict */
@ -1019,9 +1019,8 @@ void sqlite3GenerateConstraintChecks(
}
}
contAddr = sqlite3VdbeCurrentAddr(v);
assert( contAddr<(1<<24) );
#if NULL_DISTINCT_FOR_UNIQUE
sqlite3VdbeChangeP2(v, jumpInst1, contAddr | (1<<24));
sqlite3VdbeChangeP2(v, jumpInst1, contAddr);
#endif
sqlite3VdbeChangeP2(v, jumpInst2, contAddr);
}
@ -1097,11 +1096,12 @@ void sqlite3OpenTableAndIndices(
Vdbe *v = sqlite3GetVdbe(pParse);
assert( v!=0 );
sqlite3VdbeAddOp(v, OP_Integer, pTab->iDb, 0);
sqlite3VdbeAddOp(v, op, base, pTab->tnum);
VdbeComment((v, "# %s", pTab->zName));
sqlite3VdbeAddOp(v, op, base, pTab->tnum);
sqlite3VdbeAddOp(v, OP_SetNumColumns, base, pTab->nCol);
for(i=1, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
sqlite3VdbeAddOp(v, OP_Integer, pIdx->iDb, 0);
VdbeComment((v, "# %s", pIdx->zName));
sqlite3VdbeOp3(v, op, i+base, pIdx->tnum,
(char*)&pIdx->keyInfo, P3_KEYINFO);
}

View file

@ -1,83 +1,84 @@
/* Hash score: 153 */
/* Hash score: 156 */
static int keywordCode(const char *z, int n){
static const char zText[515] =
static const char zText[526] =
"ABORTABLEFTEMPORARYADDATABASELECTHENDEFAULTRANSACTIONATURALTER"
"AISEACHECKEYAFTEREFERENCESCAPELSEXCEPTRIGGEREGEXPLAINITIALLYAND"
"EFERRABLEXCLUSIVEXISTSTATEMENTATTACHAVINGLOBEFOREIGNOREINDEXAUTOINCREMENT"
"BEGINNERENAMEBETWEENOTNULLIKEBYCASCADEFERREDELETECASECOLLATECOLUMN"
"COMMITCONFLICTCONSTRAINTERSECTCREATECROSSCURRENT_DATECURRENT_TIMESTAMP"
"RAGMATCHDESCDETACHDISTINCTDROPRIMARYFAILIMITFROMFULLGROUPDATE"
"IMMEDIATEINSERTINSTEADINTOFFSETISNULLJOINORDEREPLACEOUTERESTRICT"
"RIGHTROLLBACKROWHENUNIONUNIQUEUSINGVACUUMVALUESVIEWHERE";
"AISEACHECKEYAFTEREFERENCESCAPELSEXCEPTRIGGEREGEXPLAINITIALLYANALYZE"
"XCLUSIVEXISTSTATEMENTANDEFERRABLEATTACHAVINGLOBEFOREIGNOREINDEX"
"AUTOINCREMENTBEGINNERENAMEBETWEENOTNULLIKEBYCASCADEFERREDELETE"
"CASECASTCOLLATECOLUMNCOMMITCONFLICTCONSTRAINTERSECTCREATECROSS"
"CURRENT_DATECURRENT_TIMESTAMPRAGMATCHDESCDETACHDISTINCTDROPRIMARY"
"FAILIMITFROMFULLGROUPDATEIMMEDIATEINSERTINSTEADINTOFFSETISNULL"
"JOINORDEREPLACEOUTERESTRICTRIGHTROLLBACKROWHENUNIONUNIQUEUSING"
"VACUUMVALUESVIEWHERE";
static const unsigned char aHash[127] = {
89, 79, 102, 88, 0, 4, 0, 0, 109, 0, 75, 0, 0,
92, 43, 0, 90, 0, 101, 104, 94, 0, 0, 10, 0, 0,
108, 0, 105, 100, 0, 28, 47, 0, 40, 0, 0, 63, 69,
0, 62, 19, 0, 0, 32, 81, 0, 103, 72, 0, 0, 34,
0, 60, 33, 0, 8, 0, 110, 37, 12, 0, 76, 39, 25,
64, 0, 0, 31, 80, 52, 30, 49, 20, 86, 0, 35, 0,
73, 26, 0, 70, 0, 0, 0, 0, 46, 65, 22, 85, 29,
67, 84, 0, 1, 0, 9, 98, 57, 18, 0, 107, 74, 96,
53, 6, 83, 0, 0, 48, 91, 0, 99, 0, 68, 0, 0,
15, 0, 111, 50, 55, 0, 2, 54, 0, 106,
91, 81, 104, 90, 0, 4, 0, 0, 111, 0, 77, 0, 0,
94, 44, 0, 92, 0, 103, 106, 96, 0, 0, 10, 0, 0,
110, 0, 107, 102, 0, 28, 48, 0, 41, 0, 0, 65, 71,
0, 63, 19, 0, 0, 36, 83, 0, 105, 74, 0, 0, 33,
0, 61, 37, 0, 8, 0, 112, 38, 12, 0, 78, 40, 25,
66, 0, 0, 31, 82, 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, 100, 58, 18, 0, 109, 76, 98,
54, 6, 85, 0, 0, 49, 93, 0, 101, 0, 70, 0, 0,
15, 0, 113, 51, 56, 0, 2, 55, 0, 108,
};
static const unsigned char aNext[111] = {
static const unsigned char aNext[113] = {
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, 7, 0, 5, 13, 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, 58, 0, 0,
0, 0, 0, 0, 0, 0, 71, 41, 0, 0, 24, 59, 21,
0, 78, 0, 66, 0, 0, 82, 45, 0, 0, 0, 0, 0,
0, 0, 38, 93, 95, 0, 0, 97, 0, 14, 27, 77, 0,
56, 87, 0, 36, 0, 61, 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, 0, 24,
60, 21, 0, 80, 32, 68, 0, 0, 84, 46, 0, 0, 0,
0, 0, 0, 0, 39, 95, 97, 0, 0, 99, 0, 14, 27,
79, 0, 57, 89, 0, 35, 0, 62, 0,
};
static const unsigned char aLen[111] = {
static const unsigned char aLen[113] = {
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, 3, 10, 9, 6, 9, 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, 7, 6, 6,
8, 10, 9, 6, 5, 12, 12, 17, 6, 5, 4, 6, 8,
2, 4, 7, 4, 5, 4, 4, 5, 6, 9, 6, 7, 4,
2, 6, 3, 6, 4, 5, 7, 5, 8, 5, 8, 3, 4,
5, 6, 5, 6, 6, 4, 5,
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, 6, 5, 4,
6, 8, 2, 4, 7, 4, 5, 4, 4, 5, 6, 9, 6,
7, 4, 2, 6, 3, 6, 4, 5, 7, 5, 8, 5, 8,
3, 4, 5, 6, 5, 6, 6, 4, 5,
};
static const unsigned short int aOffset[111] = {
static const unsigned short int aOffset[113] = {
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, 124, 133, 141, 146, 155, 160, 165,
168, 170, 170, 174, 178, 180, 185, 187, 189, 198, 201, 205, 211,
217, 217, 220, 223, 227, 229, 230, 234, 241, 247, 251, 258, 264,
270, 278, 285, 294, 300, 305, 317, 317, 333, 337, 342, 346, 352,
353, 360, 363, 370, 373, 378, 382, 386, 389, 395, 404, 410, 417,
420, 420, 423, 426, 432, 436, 440, 447, 451, 459, 464, 472, 474,
478, 483, 489, 494, 500, 506, 509,
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, 353,
357, 363, 364, 371, 374, 381, 384, 389, 393, 397, 400, 406, 415,
421, 428, 431, 431, 434, 437, 443, 447, 451, 458, 462, 470, 475,
483, 485, 489, 494, 500, 505, 511, 517, 520,
};
static const unsigned char aCode[111] = {
static const unsigned char aCode[113] = {
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_AND, TK_DEFERRABLE, TK_EXCLUSIVE, TK_EXISTS,
TK_STATEMENT, 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_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_PRAGMA, TK_MATCH,
TK_DESC, TK_DETACH, TK_DISTINCT, TK_IS, TK_DROP,
TK_PRIMARY, TK_FAIL, TK_LIMIT, TK_FROM, TK_JOIN_KW,
TK_GROUP, TK_UPDATE, 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_JOIN_KW, TK_ROLLBACK, TK_ROW, TK_WHEN, TK_UNION,
TK_UNIQUE, TK_USING, TK_VACUUM, TK_VALUES, TK_VIEW,
TK_WHERE,
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_PRAGMA, TK_MATCH, TK_DESC, TK_DETACH, TK_DISTINCT,
TK_IS, TK_DROP, TK_PRIMARY, TK_FAIL, TK_LIMIT,
TK_FROM, TK_JOIN_KW, TK_GROUP, TK_UPDATE, 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_JOIN_KW, TK_ROLLBACK, TK_ROW,
TK_WHEN, TK_UNION, TK_UNIQUE, TK_USING, TK_VACUUM,
TK_VALUES, TK_VIEW, TK_WHERE,
};
int h, i;
if( n<2 ) return TK_ID;

View file

@ -234,7 +234,6 @@ const char *sqlite3ErrStr(int rc){
case SQLITE_DONE:
case SQLITE_OK: z = "not an error"; break;
case SQLITE_ERROR: z = "SQL logic error or missing database"; break;
case SQLITE_INTERNAL: z = "internal SQLite implementation flaw"; break;
case SQLITE_PERM: z = "access permission denied"; break;
case SQLITE_ABORT: z = "callback requested query abort"; break;
case SQLITE_BUSY: z = "database is locked"; break;
@ -244,13 +243,11 @@ const char *sqlite3ErrStr(int rc){
case SQLITE_INTERRUPT: z = "interrupted"; break;
case SQLITE_IOERR: z = "disk I/O error"; break;
case SQLITE_CORRUPT: z = "database disk image is malformed"; break;
case SQLITE_NOTFOUND: z = "table or record not found"; break;
case SQLITE_FULL: z = "database is full"; 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_TOOBIG: z = "too much data for one table row"; break;
case SQLITE_CONSTRAINT: z = "constraint failed"; break;
case SQLITE_MISMATCH: z = "datatype mismatch"; break;
case SQLITE_MISUSE: z = "library routine called out of sequence";break;
@ -298,7 +295,7 @@ static int sqliteDefaultBusyCallback(
sqlite3OsSleep(delay);
return 1;
#else
int timeout = (int)Timeout;
int timeout = ((sqlite3 *)ptr)->busyTimeout;
if( (count+1)*1000 > timeout ){
return 0;
}
@ -307,6 +304,25 @@ static int sqliteDefaultBusyCallback(
#endif
}
/*
** Invoke the given busy handler.
**
** This routine is called when an operation failed with a lock.
** If this routine returns non-zero, the lock is retried. If it
** returns 0, the operation aborts with an SQLITE_BUSY error.
*/
int sqlite3InvokeBusyHandler(BusyHandler *p){
int rc;
if( p==0 || p->xFunc==0 || p->nBusy<0 ) return 0;
rc = p->xFunc(p->pArg, p->nBusy);
if( rc==0 ){
p->nBusy = -1;
}else{
p->nBusy++;
}
return rc;
}
/*
** This routine sets the busy callback for an Sqlite database to the
** given callback function with the given argument.
@ -321,6 +337,7 @@ int sqlite3_busy_handler(
}
db->busyHandler.xFunc = xBusy;
db->busyHandler.pArg = pArg;
db->busyHandler.nBusy = 0;
return SQLITE_OK;
}
@ -454,6 +471,7 @@ int sqlite3_create_function(
p = sqlite3FindFunction(db, zFunctionName, nName, nArg, enc, 1);
if( p==0 ) return SQLITE_NOMEM;
p->flags = 0;
p->xFunc = xFunc;
p->xStep = xStep;
p->xFinalize = xFinal;
@ -530,11 +548,11 @@ void *sqlite3_commit_hook(
** opened and used. If zFilename is the magic name ":memory:" then
** the database is stored in memory (and is thus forgotten as soon as
** the connection is closed.) If zFilename is NULL then the database
** is for temporary use only and is deleted as soon as the connection
** is closed.
** is a "virtual" database for transient use only and is deleted as
** soon as the connection is closed.
**
** A temporary database can be either a disk file (that is automatically
** deleted when the file is closed) or a set of red-black trees held in memory,
** A virtual database can be either a disk file (that is automatically
** deleted when the file is closed) or it an be held entirely in memory,
** depending on the values of the TEMP_STORE compile-time macro and the
** db->temp_store variable, according to the following chart:
**

View file

@ -1,51 +1,51 @@
/* Automatically generated. Do not edit */
/* See the mkopcodeh.awk script for details */
#define OP_MemLoad 1
#define OP_HexBlob 129 /* same as TK_BLOB */
#define OP_HexBlob 131 /* same as TK_BLOB */
#define OP_Column 2
#define OP_SetCookie 3
#define OP_IfMemPos 4
#define OP_Real 128 /* same as TK_FLOAT */
#define OP_Real 130 /* same as TK_FLOAT */
#define OP_MoveGt 5
#define OP_Ge 75 /* same as TK_GE */
#define OP_Ge 77 /* same as TK_GE */
#define OP_AggFocus 6
#define OP_RowKey 7
#define OP_AggNext 8
#define OP_Eq 71 /* same as TK_EQ */
#define OP_Eq 73 /* same as TK_EQ */
#define OP_OpenWrite 9
#define OP_NotNull 69 /* same as TK_NOTNULL */
#define OP_NotNull 71 /* same as TK_NOTNULL */
#define OP_If 10
#define OP_String8 90 /* same as TK_STRING */
#define OP_Pop 11
#define OP_AggContextPush 12
#define OP_CollSeq 13
#define OP_OpenRead 14
#define OP_Expire 15
#define OP_SortReset 16
#define OP_AutoCommit 17
#define OP_Gt 72 /* same as TK_GT */
#define OP_Sort 18
#define OP_ListRewind 19
#define OP_ToInt 11
#define OP_String8 92 /* same as TK_STRING */
#define OP_Pop 12
#define OP_AggContextPush 13
#define OP_CollSeq 14
#define OP_OpenRead 15
#define OP_Expire 16
#define OP_SortReset 17
#define OP_AutoCommit 18
#define OP_Gt 74 /* same as TK_GT */
#define OP_Sort 19
#define OP_IntegrityCk 20
#define OP_SortInsert 21
#define OP_Function 22
#define OP_And 63 /* same as TK_AND */
#define OP_Subtract 82 /* same as TK_MINUS */
#define OP_And 65 /* same as TK_AND */
#define OP_Subtract 84 /* same as TK_MINUS */
#define OP_Noop 23
#define OP_Return 24
#define OP_Remainder 85 /* same as TK_REM */
#define OP_Remainder 87 /* same as TK_REM */
#define OP_NewRowid 25
#define OP_Multiply 83 /* same as TK_STAR */
#define OP_Multiply 85 /* same as TK_STAR */
#define OP_Variable 26
#define OP_String 27
#define OP_ParseSchema 28
#define OP_AggFunc 29
#define OP_Close 30
#define OP_ListWrite 31
#define OP_CreateIndex 32
#define OP_IsUnique 33
#define OP_IdxIsNull 34
#define OP_NotFound 35
#define OP_CreateIndex 31
#define OP_IsUnique 32
#define OP_IdxIsNull 33
#define OP_NotFound 34
#define OP_Int64 35
#define OP_MustBeInt 36
#define OP_Halt 37
#define OP_Rowid 38
@ -55,90 +55,90 @@
#define OP_RowData 42
#define OP_MemMax 43
#define OP_Push 44
#define OP_Or 62 /* same as TK_OR */
#define OP_Or 64 /* same as TK_OR */
#define OP_NotExists 45
#define OP_OpenTemp 46
#define OP_MemIncr 47
#define OP_Gosub 48
#define OP_Divide 84 /* same as TK_SLASH */
#define OP_AggSet 49
#define OP_Integer 50
#define OP_MemIncr 46
#define OP_Gosub 47
#define OP_Divide 86 /* same as TK_SLASH */
#define OP_AggSet 48
#define OP_Integer 49
#define OP_ToNumeric 50
#define OP_SortNext 51
#define OP_Prev 52
#define OP_Concat 86 /* same as TK_CONCAT */
#define OP_BitAnd 77 /* same as TK_BITAND */
#define OP_Concat 88 /* same as TK_CONCAT */
#define OP_BitAnd 79 /* same as TK_BITAND */
#define OP_CreateTable 53
#define OP_Last 54
#define OP_IsNull 68 /* same as TK_ISNULL */
#define OP_IsNull 70 /* same as TK_ISNULL */
#define OP_IdxRowid 55
#define OP_ShiftRight 80 /* same as TK_RSHIFT */
#define OP_ResetCount 56
#define OP_Callback 57
#define OP_ContextPush 58
#define OP_DropTrigger 59
#define OP_DropIndex 60
#define OP_IdxGE 61
#define OP_IdxDelete 65
#define OP_Vacuum 66
#define OP_MoveLe 67
#define OP_IfNot 76
#define OP_DropTable 88
#define OP_MakeRecord 91
#define OP_Delete 92
#define OP_AggContextPop 93
#define OP_ListRead 94
#define OP_ListReset 95
#define OP_ShiftLeft 79 /* same as TK_LSHIFT */
#define OP_Dup 96
#define OP_Goto 97
#define OP_Clear 98
#define OP_IdxGT 99
#define OP_MoveLt 100
#define OP_Le 73 /* same as TK_LE */
#define OP_VerifyCookie 101
#define OP_Pull 102
#define OP_Not 64 /* same as TK_NOT */
#define OP_SetNumColumns 103
#define OP_AbsValue 104
#define OP_Transaction 105
#define OP_Negative 87 /* same as TK_UMINUS */
#define OP_Ne 70 /* same as TK_NE */
#define OP_AggGet 106
#define OP_ContextPop 107
#define OP_BitOr 78 /* same as TK_BITOR */
#define OP_Next 108
#define OP_AggInit 109
#define OP_IdxInsert 110
#define OP_Distinct 111
#define OP_Lt 74 /* same as TK_LT */
#define OP_AggReset 112
#define OP_Insert 113
#define OP_Destroy 114
#define OP_ReadCookie 115
#define OP_ForceInt 116
#define OP_OpenPseudo 117
#define OP_Null 118
#define OP_Blob 119
#define OP_Add 81 /* same as TK_PLUS */
#define OP_MemStore 120
#define OP_Rewind 121
#define OP_MoveGe 122
#define OP_BitNot 89 /* same as TK_BITNOT */
#define OP_Found 123
#define OP_NullRow 124
/* The following opcode values are never used */
#define OP_NotUsed_125 125
#define OP_NotUsed_126 126
#define OP_NotUsed_127 127
#define OP_MakeIdxRec 56
#define OP_ShiftRight 82 /* same as TK_RSHIFT */
#define OP_ResetCount 57
#define OP_FifoWrite 58
#define OP_Callback 59
#define OP_ContextPush 60
#define OP_DropTrigger 61
#define OP_DropIndex 62
#define OP_IdxGE 63
#define OP_IdxDelete 67
#define OP_Vacuum 68
#define OP_MoveLe 69
#define OP_IfNot 78
#define OP_DropTable 90
#define OP_MakeRecord 93
#define OP_ToBlob 94
#define OP_Delete 95
#define OP_AggContextPop 96
#define OP_ShiftLeft 81 /* same as TK_LSHIFT */
#define OP_Dup 97
#define OP_Goto 98
#define OP_FifoRead 99
#define OP_Clear 100
#define OP_IdxGT 101
#define OP_MoveLt 102
#define OP_Le 75 /* same as TK_LE */
#define OP_VerifyCookie 103
#define OP_Pull 104
#define OP_ToText 105
#define OP_Not 66 /* same as TK_NOT */
#define OP_SetNumColumns 106
#define OP_AbsValue 107
#define OP_Transaction 108
#define OP_Negative 89 /* same as TK_UMINUS */
#define OP_Ne 72 /* same as TK_NE */
#define OP_AggGet 109
#define OP_ContextPop 110
#define OP_BitOr 80 /* same as TK_BITOR */
#define OP_Next 111
#define OP_AggInit 112
#define OP_IdxInsert 113
#define OP_Distinct 114
#define OP_Lt 76 /* same as TK_LT */
#define OP_AggReset 115
#define OP_Insert 116
#define OP_Destroy 117
#define OP_ReadCookie 118
#define OP_ForceInt 119
#define OP_LoadAnalysis 120
#define OP_OpenVirtual 121
#define OP_OpenPseudo 122
#define OP_Null 123
#define OP_Blob 124
#define OP_Add 83 /* same as TK_PLUS */
#define OP_MemStore 125
#define OP_Rewind 126
#define OP_MoveGe 127
#define OP_BitNot 91 /* same as TK_BITNOT */
#define OP_Found 128
#define OP_NullRow 129
#define NOPUSH_MASK_0 65400
#define NOPUSH_MASK_1 61871
#define NOPUSH_MASK_2 64446
#define NOPUSH_MASK_3 65363
#define NOPUSH_MASK_1 29103
#define NOPUSH_MASK_2 64439
#define NOPUSH_MASK_3 65109
#define NOPUSH_MASK_4 65535
#define NOPUSH_MASK_5 46015
#define NOPUSH_MASK_6 64254
#define NOPUSH_MASK_7 7987
#define NOPUSH_MASK_8 0
#define NOPUSH_MASK_5 52991
#define NOPUSH_MASK_6 55285
#define NOPUSH_MASK_7 59295
#define NOPUSH_MASK_8 3
#define NOPUSH_MASK_9 0

View file

@ -56,25 +56,36 @@
# define fcntl(A,B,C) 0
#endif
/*
** Macros used to determine whether or not to use threads. The
** SQLITE_UNIX_THREADS macro is defined if we are synchronizing for
** Posix threads and SQLITE_W32_THREADS is defined if we are
** synchronizing using Win32 threads.
*/
#if defined(THREADSAFE) && THREADSAFE
# include <pthread.h>
# define SQLITE_UNIX_THREADS 1
#endif
/*
** Include code that is common to all os_*.c files
*/
#include "os_common.h"
#if defined(THREADSAFE) && THREADSAFE && defined(__linux__)
#define getpid pthread_self
/*
** The threadid macro resolves to the thread-id or to 0. Used for
** testing and debugging only.
*/
#ifdef SQLITE_UNIX_THREADS
#define threadid pthread_self()
#else
#define threadid 0
#endif
/*
** Set or check the OsFile.tid field. This field is set when an OsFile
** is first opened. All subsequent uses of the OsFile verify that the
** same thread is operating on the OsFile. Some operating systems do
** not allow locks to be overridden by other threads and that restriction
** means that sqlite3* database handles cannot be moved from one thread
** to another. This logic makes sure a user does not try to do that
** by mistake.
*/
#ifdef SQLITE_UNIX_THREADS
# define SET_THREADID(X) X->tid = pthread_self()
# define CHECK_THREADID(X) (!pthread_equal(X->tid, pthread_self()))
#else
# define SET_THREADID(X)
# define CHECK_THREADID(X) 0
#endif
/*
@ -264,6 +275,65 @@ struct threadTestData {
int result; /* Result of the locking operation */
};
#ifdef SQLITE_LOCK_TRACE
/*
** Print out information about all locking operations.
**
** This routine is used for troubleshooting locks on multithreaded
** platforms. Enable by compiling with the -DSQLITE_LOCK_TRACE
** command-line option on the compiler. This code is normally
** turnned off.
*/
static int lockTrace(int fd, int op, struct flock *p){
char *zOpName, *zType;
int s;
int savedErrno;
if( op==F_GETLK ){
zOpName = "GETLK";
}else if( op==F_SETLK ){
zOpName = "SETLK";
}else{
s = fcntl(fd, op, p);
sqlite3DebugPrintf("fcntl unknown %d %d %d\n", fd, op, s);
return s;
}
if( p->l_type==F_RDLCK ){
zType = "RDLCK";
}else if( p->l_type==F_WRLCK ){
zType = "WRLCK";
}else if( p->l_type==F_UNLCK ){
zType = "UNLCK";
}else{
assert( 0 );
}
assert( p->l_whence==SEEK_SET );
s = fcntl(fd, op, p);
savedErrno = errno;
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) ){
struct flock l2;
l2 = *p;
fcntl(fd, F_GETLK, &l2);
if( l2.l_type==F_RDLCK ){
zType = "RDLCK";
}else if( l2.l_type==F_WRLCK ){
zType = "WRLCK";
}else if( l2.l_type==F_UNLCK ){
zType = "UNLCK";
}else{
assert( 0 );
}
sqlite3DebugPrintf("fcntl-failure-reason: %s %d %d %d\n",
zType, (int)l2.l_start, (int)l2.l_len, (int)l2.l_pid);
}
errno = savedErrno;
return s;
}
#define fcntl lockTrace
#endif /* SQLITE_LOCK_TRACE */
/*
** The testThreadLockingBehavior() routine launches two separate
** threads on this routine. This routine attempts to lock a file
@ -443,6 +513,7 @@ int sqlite3OsOpenReadWrite(
int rc;
assert( !id->isOpen );
id->dirfd = -1;
SET_THREADID(id);
id->h = open(zFilename, O_RDWR|O_CREAT|O_LARGEFILE|O_BINARY,
SQLITE_DEFAULT_FILE_PERMISSIONS);
if( id->h<0 ){
@ -494,9 +565,11 @@ int sqlite3OsOpenExclusive(const char *zFilename, OsFile *id, int delFlag){
if( access(zFilename, 0)==0 ){
return SQLITE_CANTOPEN;
}
SET_THREADID(id);
id->dirfd = -1;
id->h = open(zFilename,
O_RDWR|O_CREAT|O_EXCL|O_NOFOLLOW|O_LARGEFILE|O_BINARY, 0600);
O_RDWR|O_CREAT|O_EXCL|O_NOFOLLOW|O_LARGEFILE|O_BINARY,
SQLITE_DEFAULT_FILE_PERMISSIONS);
if( id->h<0 ){
return SQLITE_CANTOPEN;
}
@ -528,6 +601,7 @@ int sqlite3OsOpenExclusive(const char *zFilename, OsFile *id, int delFlag){
int sqlite3OsOpenReadOnly(const char *zFilename, OsFile *id){
int rc;
assert( !id->isOpen );
SET_THREADID(id);
id->dirfd = -1;
id->h = open(zFilename, O_RDONLY|O_LARGEFILE|O_BINARY);
if( id->h<0 ){
@ -572,6 +646,7 @@ int sqlite3OsOpenDirectory(
** open. */
return SQLITE_CANTOPEN;
}
SET_THREADID(id);
assert( id->dirfd<0 );
id->dirfd = open(zDirname, O_RDONLY|O_BINARY, 0);
if( id->dirfd<0 ){
@ -839,6 +914,7 @@ int sqlite3OsCheckReservedLock(OsFile *id){
int r = 0;
assert( id->isOpen );
if( CHECK_THREADID(id) ) return SQLITE_MISUSE;
sqlite3OsEnterMutex(); /* Needed because id->pLock is shared across threads */
/* Check if a thread in this process holds such a lock */
@ -956,6 +1032,7 @@ int sqlite3OsLock(OsFile *id, int locktype){
TRACE7("LOCK %d %s was %s(%s,%d) pid=%d\n", id->h, locktypeName(locktype),
locktypeName(id->locktype), locktypeName(pLock->locktype), pLock->cnt
,getpid() );
if( CHECK_THREADID(id) ) return SQLITE_MISUSE;
/* If there is already a lock of this type or more restrictive on the
** OsFile, do nothing. Don't use the end_lock: exit path, as
@ -1002,6 +1079,7 @@ int sqlite3OsLock(OsFile *id, int locktype){
}
lock.l_len = 1L;
lock.l_whence = SEEK_SET;
/* A PENDING lock is needed before acquiring a SHARED lock and before
@ -1037,7 +1115,10 @@ int sqlite3OsLock(OsFile *id, int locktype){
lock.l_start = PENDING_BYTE;
lock.l_len = 1L;
lock.l_type = F_UNLCK;
fcntl(id->h, F_SETLK, &lock);
if( fcntl(id->h, F_SETLK, &lock)!=0 ){
rc = SQLITE_IOERR; /* This should never happen */
goto end_lock;
}
if( s ){
rc = (errno==EINVAL) ? SQLITE_NOLFS : SQLITE_BUSY;
}else{
@ -1107,6 +1188,7 @@ int sqlite3OsUnlock(OsFile *id, int locktype){
assert( id->isOpen );
TRACE7("UNLOCK %d %d was %d(%d,%d) pid=%d\n", id->h, locktype, id->locktype,
id->pLock->locktype, id->pLock->cnt, getpid());
if( CHECK_THREADID(id) ) return SQLITE_MISUSE;
assert( locktype<=SHARED_LOCK );
if( id->locktype<=locktype ){
@ -1131,8 +1213,11 @@ int sqlite3OsUnlock(OsFile *id, int locktype){
lock.l_whence = SEEK_SET;
lock.l_start = PENDING_BYTE;
lock.l_len = 2L; assert( PENDING_BYTE+1==RESERVED_BYTE );
fcntl(id->h, F_SETLK, &lock);
pLock->locktype = SHARED_LOCK;
if( fcntl(id->h, F_SETLK, &lock)==0 ){
pLock->locktype = SHARED_LOCK;
}else{
rc = SQLITE_IOERR; /* This should never happen */
}
}
if( locktype==NO_LOCK ){
struct openCnt *pOpen;
@ -1146,8 +1231,11 @@ int sqlite3OsUnlock(OsFile *id, int locktype){
lock.l_type = F_UNLCK;
lock.l_whence = SEEK_SET;
lock.l_start = lock.l_len = 0L;
fcntl(id->h, F_SETLK, &lock);
pLock->locktype = NO_LOCK;
if( fcntl(id->h, F_SETLK, &lock)==0 ){
pLock->locktype = NO_LOCK;
}else{
rc = SQLITE_IOERR; /* This should never happen */
}
}
/* Decrement the count of locks against this same file. When the
@ -1177,6 +1265,7 @@ int sqlite3OsUnlock(OsFile *id, int locktype){
*/
int sqlite3OsClose(OsFile *id){
if( !id->isOpen ) return SQLITE_OK;
if( CHECK_THREADID(id) ) return SQLITE_MISUSE;
sqlite3OsUnlock(id, NO_LOCK);
if( id->dirfd>=0 ) close(id->dirfd);
id->dirfd = -1;
@ -1189,13 +1278,13 @@ int sqlite3OsClose(OsFile *id){
*/
int *aNew;
struct openCnt *pOpen = id->pOpen;
pOpen->nPending++;
aNew = sqliteRealloc( pOpen->aPending, pOpen->nPending*sizeof(int) );
aNew = sqliteRealloc( pOpen->aPending, (pOpen->nPending+1)*sizeof(int) );
if( aNew==0 ){
/* If a malloc fails, just leak the file descriptor */
}else{
pOpen->aPending = aNew;
pOpen->aPending[pOpen->nPending-1] = id->h;
pOpen->aPending[pOpen->nPending] = id->h;
pOpen->nPending++;
}
}else{
/* There are no outstanding locks so we can close the file immediately */

View file

@ -51,6 +51,17 @@
#include <fcntl.h>
#include <unistd.h>
/*
** Macros used to determine whether or not to use threads. The
** SQLITE_UNIX_THREADS macro is defined if we are synchronizing for
** Posix threads and SQLITE_W32_THREADS is defined if we are
** synchronizing using Win32 threads.
*/
#if defined(THREADSAFE) && THREADSAFE
# include <pthread.h>
# define SQLITE_UNIX_THREADS 1
#endif
/*
** The OsFile structure is a operating-system independing representation
** of an open file handle. It is defined differently for each architecture.
@ -70,6 +81,9 @@ struct OsFile {
unsigned char isOpen; /* True if needs to be closed */
unsigned char fullSync; /* Use F_FULLSYNC if available */
int dirfd; /* File descriptor for the directory */
#ifdef SQLITE_UNIX_THREADS
pthread_t tid; /* The thread authorized to use this OsFile */
#endif
};
/*

View file

@ -779,7 +779,7 @@ static int writeMasterJournal(Pager *pPager, const char *zMaster){
if( rc!=SQLITE_OK ) return rc;
rc = sqlite3OsWrite(&pPager->jfd, aJournalMagic, sizeof(aJournalMagic));
pPager->needSync = 1;
pPager->needSync = !pPager->noSync;
return rc;
}
@ -1758,7 +1758,11 @@ int sqlite3pager_pagecount(Pager *pPager){
pPager->errMask |= PAGER_ERR_DISK;
return 0;
}
n /= pPager->pageSize;
if( n>0 && n<pPager->pageSize ){
n = 1;
}else{
n /= pPager->pageSize;
}
if( !MEMDB && n==PENDING_BYTE/pPager->pageSize ){
n++;
}
@ -1866,7 +1870,7 @@ static void memoryTruncate(Pager *pPager){
/*
** Try to obtain a lock on a file. Invoke the busy callback if the lock
** is currently not available. Repeate until the busy callback returns
** is currently not available. Repeat until the busy callback returns
** false or until the lock succeeds.
**
** Return SQLITE_OK on success and an error code if we cannot obtain
@ -1880,14 +1884,9 @@ static int pager_wait_on_lock(Pager *pPager, int locktype){
if( pPager->state>=locktype ){
rc = SQLITE_OK;
}else{
int busy = 1;
BusyHandler *pH;
do {
rc = sqlite3OsLock(&pPager->fd, locktype);
}while( rc==SQLITE_BUSY &&
(pH = pPager->pBusyHandler)!=0 &&
pH->xFunc && pH->xFunc(pH->pArg, busy++)
);
}while( rc==SQLITE_BUSY && sqlite3InvokeBusyHandler(pPager->pBusyHandler) );
if( rc==SQLITE_OK ){
pPager->state = locktype;
}
@ -3346,6 +3345,14 @@ const char *sqlite3pager_journalname(Pager *pPager){
return pPager->zJournal;
}
/*
** Return true if fsync() calls are disabled for this pager. Return FALSE
** if fsync()s are executed normally.
*/
int sqlite3pager_nosync(Pager *pPager){
return pPager->noSync;
}
/*
** Set the codec for this pager
*/

View file

@ -100,6 +100,7 @@ void sqlite3pager_set_safety_level(Pager*,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);

File diff suppressed because it is too large Load diff

View file

@ -27,114 +27,116 @@
#define TK_ID 27
#define TK_ABORT 28
#define TK_AFTER 29
#define TK_ASC 30
#define TK_ATTACH 31
#define TK_BEFORE 32
#define TK_CASCADE 33
#define TK_CONFLICT 34
#define TK_DATABASE 35
#define TK_DESC 36
#define TK_DETACH 37
#define TK_EACH 38
#define TK_FAIL 39
#define TK_FOR 40
#define TK_IGNORE 41
#define TK_INITIALLY 42
#define TK_INSTEAD 43
#define TK_LIKE_KW 44
#define TK_MATCH 45
#define TK_KEY 46
#define TK_OF 47
#define TK_OFFSET 48
#define TK_PRAGMA 49
#define TK_RAISE 50
#define TK_REPLACE 51
#define TK_RESTRICT 52
#define TK_ROW 53
#define TK_STATEMENT 54
#define TK_TRIGGER 55
#define TK_VACUUM 56
#define TK_VIEW 57
#define TK_REINDEX 58
#define TK_RENAME 59
#define TK_CTIME_KW 60
#define TK_ALTER 61
#define TK_OR 62
#define TK_AND 63
#define TK_NOT 64
#define TK_IS 65
#define TK_BETWEEN 66
#define TK_IN 67
#define TK_ISNULL 68
#define TK_NOTNULL 69
#define TK_NE 70
#define TK_EQ 71
#define TK_GT 72
#define TK_LE 73
#define TK_LT 74
#define TK_GE 75
#define TK_ESCAPE 76
#define TK_BITAND 77
#define TK_BITOR 78
#define TK_LSHIFT 79
#define TK_RSHIFT 80
#define TK_PLUS 81
#define TK_MINUS 82
#define TK_STAR 83
#define TK_SLASH 84
#define TK_REM 85
#define TK_CONCAT 86
#define TK_UMINUS 87
#define TK_UPLUS 88
#define TK_BITNOT 89
#define TK_STRING 90
#define TK_JOIN_KW 91
#define TK_CONSTRAINT 92
#define TK_DEFAULT 93
#define TK_NULL 94
#define TK_PRIMARY 95
#define TK_UNIQUE 96
#define TK_CHECK 97
#define TK_REFERENCES 98
#define TK_COLLATE 99
#define TK_AUTOINCR 100
#define TK_ON 101
#define TK_DELETE 102
#define TK_UPDATE 103
#define TK_INSERT 104
#define TK_SET 105
#define TK_DEFERRABLE 106
#define TK_FOREIGN 107
#define TK_DROP 108
#define TK_UNION 109
#define TK_ALL 110
#define TK_INTERSECT 111
#define TK_EXCEPT 112
#define TK_SELECT 113
#define TK_DISTINCT 114
#define TK_DOT 115
#define TK_FROM 116
#define TK_JOIN 117
#define TK_USING 118
#define TK_ORDER 119
#define TK_BY 120
#define TK_GROUP 121
#define TK_HAVING 122
#define TK_LIMIT 123
#define TK_WHERE 124
#define TK_INTO 125
#define TK_VALUES 126
#define TK_INTEGER 127
#define TK_FLOAT 128
#define TK_BLOB 129
#define TK_REGISTER 130
#define TK_VARIABLE 131
#define TK_EXISTS 132
#define TK_CASE 133
#define TK_WHEN 134
#define TK_THEN 135
#define TK_ELSE 136
#define TK_INDEX 137
#define TK_TO 138
#define TK_ADD 139
#define TK_COLUMNKW 140
#define TK_ANALYZE 30
#define TK_ASC 31
#define TK_ATTACH 32
#define TK_BEFORE 33
#define TK_CASCADE 34
#define TK_CAST 35
#define TK_CONFLICT 36
#define TK_DATABASE 37
#define TK_DESC 38
#define TK_DETACH 39
#define TK_EACH 40
#define TK_FAIL 41
#define TK_FOR 42
#define TK_IGNORE 43
#define TK_INITIALLY 44
#define TK_INSTEAD 45
#define TK_LIKE_KW 46
#define TK_MATCH 47
#define TK_KEY 48
#define TK_OF 49
#define TK_OFFSET 50
#define TK_PRAGMA 51
#define TK_RAISE 52
#define TK_REPLACE 53
#define TK_RESTRICT 54
#define TK_ROW 55
#define TK_STATEMENT 56
#define TK_TRIGGER 57
#define TK_VACUUM 58
#define TK_VIEW 59
#define TK_REINDEX 60
#define TK_RENAME 61
#define TK_CTIME_KW 62
#define TK_ALTER 63
#define TK_OR 64
#define TK_AND 65
#define TK_NOT 66
#define TK_IS 67
#define TK_BETWEEN 68
#define TK_IN 69
#define TK_ISNULL 70
#define TK_NOTNULL 71
#define TK_NE 72
#define TK_EQ 73
#define TK_GT 74
#define TK_LE 75
#define TK_LT 76
#define TK_GE 77
#define TK_ESCAPE 78
#define TK_BITAND 79
#define TK_BITOR 80
#define TK_LSHIFT 81
#define TK_RSHIFT 82
#define TK_PLUS 83
#define TK_MINUS 84
#define TK_STAR 85
#define TK_SLASH 86
#define TK_REM 87
#define TK_CONCAT 88
#define TK_UMINUS 89
#define TK_UPLUS 90
#define TK_BITNOT 91
#define TK_STRING 92
#define TK_JOIN_KW 93
#define TK_CONSTRAINT 94
#define TK_DEFAULT 95
#define TK_NULL 96
#define TK_PRIMARY 97
#define TK_UNIQUE 98
#define TK_CHECK 99
#define TK_REFERENCES 100
#define TK_COLLATE 101
#define TK_AUTOINCR 102
#define TK_ON 103
#define TK_DELETE 104
#define TK_UPDATE 105
#define TK_INSERT 106
#define TK_SET 107
#define TK_DEFERRABLE 108
#define TK_FOREIGN 109
#define TK_DROP 110
#define TK_UNION 111
#define TK_ALL 112
#define TK_INTERSECT 113
#define TK_EXCEPT 114
#define TK_SELECT 115
#define TK_DISTINCT 116
#define TK_DOT 117
#define TK_FROM 118
#define TK_JOIN 119
#define TK_USING 120
#define TK_ORDER 121
#define TK_BY 122
#define TK_GROUP 123
#define TK_HAVING 124
#define TK_LIMIT 125
#define TK_WHERE 126
#define TK_INTO 127
#define TK_VALUES 128
#define TK_INTEGER 129
#define TK_FLOAT 130
#define TK_BLOB 131
#define TK_REGISTER 132
#define TK_VARIABLE 133
#define TK_EXISTS 134
#define TK_CASE 135
#define TK_WHEN 136
#define TK_THEN 137
#define TK_ELSE 138
#define TK_INDEX 139
#define TK_TO 140
#define TK_ADD 141
#define TK_COLUMNKW 142

View file

@ -16,10 +16,21 @@
**
** @(#) $Id$
*/
// All token codes are small integers with #defines that begin with "TK_"
%token_prefix TK_
// The type of the data attached to each token is Token. This is also the
// default type for non-terminals.
//
%token_type {Token}
%default_type {Token}
// The generated parser function takes a 4th argument as follows:
%extra_argument {Parse *pParse}
// This code runs whenever there is a syntax error
//
%syntax_error {
if( pParse->zErrMsg==0 ){
if( TOKEN.z[0] ){
@ -29,7 +40,14 @@
}
}
}
// The name of the generated procedure that implements the parser
// is as follows:
%name sqlite3Parser
// The following text is included near the beginning of the C source
// code file that implements the parser.
//
%include {
#include "sqliteInt.h"
#include "parse.h"
@ -126,9 +144,10 @@ create_table_args ::= AS select(S). {
columnlist ::= columnlist COMMA column.
columnlist ::= column.
// About the only information used for a column is the name of the
// column. The type is always just "text". But the code will accept
// an elaborate typename. Perhaps someday we'll do something with it.
// A "column" is a complete description of a single column in a
// CREATE TABLE statement. This includes the column name, its
// datatype, and other keywords such as PRIMARY KEY, UNIQUE, REFERENCES,
// NOT NULL and so forth.
//
column(A) ::= columnid(X) type carglist. {
A.z = X.z;
@ -151,7 +170,7 @@ id(A) ::= ID(X). {A = X;}
// This obviates the need for the "id" nonterminal.
//
%fallback ID
ABORT AFTER ASC ATTACH BEFORE BEGIN CASCADE CONFLICT
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 KEY
OF OFFSET PRAGMA RAISE REPLACE RESTRICT ROW STATEMENT
@ -198,22 +217,38 @@ nm(A) ::= ID(X). {A = X;}
nm(A) ::= STRING(X). {A = X;}
nm(A) ::= JOIN_KW(X). {A = X;}
// A typetoken is really one or more tokens that form a type name such
// as can be found after the column name in a CREATE TABLE statement.
// Multiple tokens are concatenated to form the value of the typetoken.
//
%type typetoken {Token}
type ::= .
type ::= typename(X). {sqlite3AddColumnType(pParse,&X,&X);}
type ::= typename(X) LP signed RP(Y). {sqlite3AddColumnType(pParse,&X,&Y);}
type ::= typename(X) LP signed COMMA signed RP(Y).
{sqlite3AddColumnType(pParse,&X,&Y);}
type ::= typetoken(X). {sqlite3AddColumnType(pParse,&X);}
typetoken(A) ::= typename(X). {A = X;}
typetoken(A) ::= typename(X) LP signed RP(Y). {
A.z = X.z;
A.n = &Y.z[Y.n] - X.z;
}
typetoken(A) ::= typename(X) LP signed COMMA signed RP(Y). {
A.z = X.z;
A.n = &Y.z[Y.n] - X.z;
}
%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(X.z); }
signed(A) ::= minus_num(X). { A = -atoi(X.z); }
// "carglist" is a list of additional constraints that come after the
// column name and column type in a CREATE TABLE statement.
//
carglist ::= carglist carg.
carglist ::= .
carg ::= CONSTRAINT nm ccons.
carg ::= ccons.
carg ::= DEFAULT term(X). {sqlite3AddDefaultValue(pParse,X);}
carg ::= DEFAULT LP expr(X) RP. {sqlite3AddDefaultValue(pParse,X);}
carg ::= DEFAULT PLUS term(X). {sqlite3AddDefaultValue(pParse,X);}
carg ::= DEFAULT MINUS term(X). {
Expr *p = sqlite3Expr(TK_UMINUS, X, 0, 0);
@ -619,6 +654,12 @@ expr(A) ::= VARIABLE(X). {
Expr *pExpr = A = sqlite3Expr(TK_VARIABLE, 0, 0, pToken);
sqlite3ExprAssignVarNumber(pParse, pExpr);
}
%ifndef SQLITE_OMIT_CAST
expr(A) ::= CAST(X) LP expr(E) AS typetoken(T) RP(Y). {
A = sqlite3Expr(TK_CAST, E, 0, &T);
sqlite3ExprSpan(A,&X,&Y);
}
%endif // SQLITE_OMIT_CAST
expr(A) ::= ID(X) LP exprlist(Y) RP(E). {
A = sqlite3ExprFunction(Y, &X);
sqlite3ExprSpan(A,&X,&E);
@ -979,6 +1020,12 @@ cmd ::= REINDEX. {sqlite3Reindex(pParse, 0, 0);}
cmd ::= REINDEX nm(X) dbnm(Y). {sqlite3Reindex(pParse, &X, &Y);}
%endif
/////////////////////////////////// ANALYZE ///////////////////////////////////
%ifndef SQLITE_OMIT_ANALYZE
cmd ::= ANALYZE. {sqlite3Analyze(pParse, 0, 0);}
cmd ::= ANALYZE nm(X) dbnm(Y). {sqlite3Analyze(pParse, &X, &Y);}
%endif
//////////////////////// ALTER TABLE table ... ////////////////////////////////
%ifndef SQLITE_OMIT_ALTERTABLE
cmd ::= ALTER TABLE fullname(X) RENAME TO nm(Z). {

View file

@ -583,12 +583,13 @@ void sqlite3Pragma(
while(pFK){
int j;
for(j=0; j<pFK->nCol; j++){
char *zCol = pFK->aCol[j].zCol;
sqlite3VdbeAddOp(v, OP_Integer, i, 0);
sqlite3VdbeAddOp(v, OP_Integer, j, 0);
sqlite3VdbeOp3(v, OP_String8, 0, 0, pFK->zTo, 0);
sqlite3VdbeOp3(v, OP_String8, 0, 0,
pTab->aCol[pFK->aCol[j].iFrom].zName, 0);
sqlite3VdbeOp3(v, OP_String8, 0, 0, pFK->aCol[j].zCol, 0);
sqlite3VdbeOp3(v, zCol ? OP_String8 : OP_Null, 0, 0, zCol, 0);
sqlite3VdbeAddOp(v, OP_Callback, 5, 0);
}
++i;
@ -602,14 +603,25 @@ void sqlite3Pragma(
#ifndef NDEBUG
if( sqlite3StrICmp(zLeft, "parser_trace")==0 ){
extern void sqlite3ParserTrace(FILE*, char *);
if( getBoolean(zRight) ){
sqlite3ParserTrace(stdout, "parser: ");
}else{
sqlite3ParserTrace(0, 0);
if( zRight ){
if( getBoolean(zRight) ){
sqlite3ParserTrace(stderr, "parser: ");
}else{
sqlite3ParserTrace(0, 0);
}
}
}else
#endif
/* Reinstall the LIKE and GLOB functions. The variant of LIKE
** used will be case sensitive or not depending on the RHS.
*/
if( sqlite3StrICmp(zLeft, "case_sensitive_like")==0 ){
if( zRight ){
sqlite3RegisterLikeFunctions(db, getBoolean(zRight));
}
}else
#ifndef SQLITE_OMIT_INTEGRITY_CHECK
if( sqlite3StrICmp(zLeft, "integrity_check")==0 ){
int i, j, addr;

View file

@ -294,6 +294,11 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
rc = sqlite3_exec(db, zSql, sqlite3InitCallback, &initData, 0);
sqlite3SafetyOn(db);
sqliteFree(zSql);
#ifndef SQLITE_OMIT_ANALYZE
if( rc==SQLITE_OK ){
sqlite3AnalysisLoad(db, iDb);
}
#endif
sqlite3BtreeCloseCursor(curMain);
}
if( sqlite3_malloc_failed ){
@ -370,7 +375,7 @@ int sqlite3ReadSchema(Parse *pParse){
rc = sqlite3Init(db, &pParse->zErrMsg);
}
}
assert( rc!=SQLITE_OK || (db->flags & SQLITE_Initialized)||db->init.busy );
assert( rc!=SQLITE_OK || (db->flags & SQLITE_Initialized) || db->init.busy );
if( rc!=SQLITE_OK ){
pParse->rc = rc;
pParse->nErr++;
@ -526,4 +531,3 @@ int sqlite3_prepare16(
return rc;
}
#endif /* SQLITE_OMIT_UTF16 */

View file

@ -111,6 +111,7 @@ static const char aPrefix[] = "-x0\000X0";
static const et_info fmtinfo[] = {
{ 'd', 10, 1, etRADIX, 0, 0 },
{ 's', 0, 4, etSTRING, 0, 0 },
{ 'g', 0, 1, etGENERIC, 30, 0 },
{ 'z', 0, 6, etDYNSTRING, 0, 0 },
{ 'q', 0, 4, etSQLESCAPE, 0, 0 },
{ 'Q', 0, 4, etSQLESCAPE2, 0, 0 },
@ -122,7 +123,6 @@ static const et_info fmtinfo[] = {
{ 'f', 0, 1, etFLOAT, 0, 0 },
{ 'e', 0, 1, etEXP, 30, 0 },
{ 'E', 0, 1, etEXP, 14, 0 },
{ 'g', 0, 1, etGENERIC, 30, 0 },
{ 'G', 0, 1, etGENERIC, 14, 0 },
{ 'i', 10, 1, etRADIX, 0, 0 },
{ 'n', 0, 0, etSIZE, 0, 0 },
@ -210,9 +210,11 @@ static int vxprintf(
etByte flag_plussign; /* True if "+" flag is present */
etByte flag_blanksign; /* True if " " flag is present */
etByte flag_alternateform; /* True if "#" flag is present */
etByte flag_altform2; /* True if "!" flag is present */
etByte flag_zeropad; /* True if field width constant starts with zero */
etByte flag_long; /* True if "l" flag is present */
etByte flag_longlong; /* True if the "ll" flag is present */
etByte done; /* Loop termination flag */
UINT64_TYPE longvalue; /* Value for integer types */
LONGDOUBLE_TYPE realvalue; /* Value for real types */
const et_info *infop; /* Pointer to the appropriate info structure */
@ -225,7 +227,7 @@ static int vxprintf(
" ";
#define etSPACESIZE (sizeof(spaces)-1)
#ifndef etNOFLOATINGPOINT
int exp; /* exponent of real numbers */
int exp, e2; /* exponent of real numbers */
double rounder; /* Used for rounding floating point values */
etByte flag_dp; /* True if decimal point should be shown */
etByte flag_rtz; /* True if trailing zeros should be removed */
@ -254,17 +256,19 @@ static int vxprintf(
}
/* Find out what flags are present */
flag_leftjustify = flag_plussign = flag_blanksign =
flag_alternateform = flag_zeropad = 0;
flag_alternateform = flag_altform2 = flag_zeropad = 0;
done = 0;
do{
switch( c ){
case '-': flag_leftjustify = 1; c = 0; break;
case '+': flag_plussign = 1; c = 0; break;
case ' ': flag_blanksign = 1; c = 0; break;
case '#': flag_alternateform = 1; c = 0; break;
case '0': flag_zeropad = 1; c = 0; break;
default: break;
case '-': flag_leftjustify = 1; break;
case '+': flag_plussign = 1; break;
case ' ': flag_blanksign = 1; break;
case '#': flag_alternateform = 1; break;
case '!': flag_altform2 = 1; break;
case '0': flag_zeropad = 1; break;
default: done = 1; break;
}
}while( c==0 && (c=(*++fmt))!=0 );
}while( !done && (c=(*++fmt))!=0 );
/* Get the field width */
width = 0;
if( c=='*' ){
@ -336,6 +340,7 @@ static int vxprintf(
** At this point, variables are initialized as follows:
**
** flag_alternateform TRUE if a '#' is present.
** flag_altform2 TRUE if a '!' is present.
** flag_plussign TRUE if a '+' is present.
** flag_leftjustify TRUE if a '-' is present or if the
** field width was negative.
@ -414,7 +419,7 @@ static int vxprintf(
realvalue = va_arg(ap,double);
#ifndef etNOFLOATINGPOINT
if( precision<0 ) precision = 6; /* Set default precision */
if( precision>etBUFSIZE-10 ) precision = etBUFSIZE-10;
if( precision>etBUFSIZE/2-10 ) precision = etBUFSIZE/2-10;
if( realvalue<0.0 ){
realvalue = -realvalue;
prefix = '-';
@ -423,8 +428,7 @@ static int vxprintf(
else if( flag_blanksign ) prefix = ' ';
else prefix = 0;
}
if( infop->type==etGENERIC && precision>0 ) precision--;
rounder = 0.0;
if( xtype==etGENERIC && precision>0 ) precision--;
#if 0
/* Rounding works like BSD when the constant 0.4999 is used. Wierd! */
for(idx=precision, rounder=0.4999; idx>0; idx--, rounder*=0.1);
@ -432,12 +436,13 @@ static int vxprintf(
/* It makes more sense to use 0.5 */
for(idx=precision, rounder=0.5; idx>0; idx--, rounder*=0.1);
#endif
if( infop->type==etFLOAT ) realvalue += rounder;
if( xtype==etFLOAT ) realvalue += rounder;
/* Normalize realvalue to within 10.0 > realvalue >= 1.0 */
exp = 0;
if( realvalue>0.0 ){
while( realvalue>=1e8 && exp<=350 ){ realvalue *= 1e-8; exp+=8; }
while( realvalue>=10.0 && exp<=350 ){ realvalue *= 0.1; exp++; }
while( realvalue>1e32 && exp<=350 ){ realvalue *= 1e-32; exp+=32; }
while( realvalue>1e8 && exp<=350 ){ realvalue *= 1e-8; exp+=8; }
while( realvalue>10.0 && exp<=350 ){ realvalue *= 0.1; exp++; }
while( realvalue<1e-8 && exp>=-350 ){ realvalue *= 1e8; exp-=8; }
while( realvalue<1.0 && exp>=-350 ){ realvalue *= 10.0; exp--; }
if( exp>350 || exp<-350 ){
@ -467,51 +472,67 @@ static int vxprintf(
}else{
flag_rtz = 0;
}
/*
** The "exp+precision" test causes output to be of type etEXP if
** the precision is too large to fit in buf[].
*/
if( xtype==etEXP ){
e2 = 0;
}else{
e2 = exp;
}
nsd = 0;
if( xtype==etFLOAT && exp+precision<etBUFSIZE-30 ){
flag_dp = (precision>0 || flag_alternateform);
if( prefix ) *(bufpt++) = prefix; /* Sign */
if( exp<0 ) *(bufpt++) = '0'; /* Digits before "." */
else for(; exp>=0; exp--) *(bufpt++) = et_getdigit(&realvalue,&nsd);
if( flag_dp ) *(bufpt++) = '.'; /* The decimal point */
for(exp++; exp<0 && precision>0; precision--, exp++){
*(bufpt++) = '0';
}
while( (precision--)>0 ) *(bufpt++) = et_getdigit(&realvalue,&nsd);
*(bufpt--) = 0; /* Null terminate */
if( flag_rtz && flag_dp ){ /* Remove trailing zeros and "." */
while( bufpt>=buf && *bufpt=='0' ) *(bufpt--) = 0;
if( bufpt>=buf && *bufpt=='.' ) *(bufpt--) = 0;
}
bufpt++; /* point to next free slot */
}else{ /* etEXP or etGENERIC */
flag_dp = (precision>0 || flag_alternateform);
if( prefix ) *(bufpt++) = prefix; /* Sign */
*(bufpt++) = et_getdigit(&realvalue,&nsd); /* First digit */
if( flag_dp ) *(bufpt++) = '.'; /* Decimal point */
while( (precision--)>0 ) *(bufpt++) = et_getdigit(&realvalue,&nsd);
bufpt--; /* point to last digit */
if( flag_rtz && flag_dp ){ /* Remove tail zeros */
while( bufpt>=buf && *bufpt=='0' ) *(bufpt--) = 0;
if( bufpt>=buf && *bufpt=='.' ) *(bufpt--) = 0;
}
bufpt++; /* point to next free slot */
if( exp || flag_exp ){
*(bufpt++) = aDigits[infop->charset];
if( exp<0 ){ *(bufpt++) = '-'; exp = -exp; } /* sign of exp */
else { *(bufpt++) = '+'; }
if( exp>=100 ){
*(bufpt++) = (exp/100)+'0'; /* 100's digit */
exp %= 100;
}
*(bufpt++) = exp/10+'0'; /* 10's digit */
*(bufpt++) = exp%10+'0'; /* 1's digit */
flag_dp = (precision>0) | flag_alternateform | flag_altform2;
/* The sign in front of the number */
if( prefix ){
*(bufpt++) = prefix;
}
/* Digits prior to the decimal point */
if( e2<0 ){
*(bufpt++) = '0';
}else{
for(; e2>=0; e2--){
*(bufpt++) = et_getdigit(&realvalue,&nsd);
}
}
/* The decimal point */
if( flag_dp ){
*(bufpt++) = '.';
}
/* "0" digits after the decimal point but before the first
** significant digit of the number */
for(e2++; e2<0 && precision>0; precision--, e2++){
*(bufpt++) = '0';
}
/* Significant digits after the decimal point */
while( (precision--)>0 ){
*(bufpt++) = et_getdigit(&realvalue,&nsd);
}
/* Remove trailing zeros and the "." if no digits follow the "." */
if( flag_rtz && flag_dp ){
while( bufpt[-1]=='0' ) *(--bufpt) = 0;
assert( bufpt>buf );
if( bufpt[-1]=='.' ){
if( flag_altform2 ){
*(bufpt++) = '0';
}else{
*(--bufpt) = 0;
}
}
}
/* Add the "eNNN" suffix */
if( flag_exp || (xtype==etEXP && exp) ){
*(bufpt++) = aDigits[infop->charset];
if( exp<0 ){
*(bufpt++) = '-'; exp = -exp;
}else{
*(bufpt++) = '+';
}
if( exp>=100 ){
*(bufpt++) = (exp/100)+'0'; /* 100's digit */
exp %= 100;
}
*(bufpt++) = exp/10+'0'; /* 10's digit */
*(bufpt++) = exp%10+'0'; /* 1's digit */
}
*bufpt = 0;
/* The converted number is in buf[] and zero terminated. Output it.
** Note that the number is in the usual order, not reversed as with
** integer conversions. */
@ -564,36 +585,35 @@ static int vxprintf(
if( precision>=0 && precision<length ) length = precision;
break;
case etSQLESCAPE:
case etSQLESCAPE2:
{
int i, j, n, c, isnull;
int needQuote;
char *arg = va_arg(ap,char*);
isnull = arg==0;
if( isnull ) arg = (xtype==etSQLESCAPE2 ? "NULL" : "(NULL)");
for(i=n=0; (c=arg[i])!=0; i++){
if( c=='\'' ) n++;
}
needQuote = !isnull && xtype==etSQLESCAPE2;
n += i + 1 + needQuote*2;
if( n>etBUFSIZE ){
bufpt = zExtra = sqliteMalloc( n );
if( bufpt==0 ) return -1;
}else{
bufpt = buf;
}
j = 0;
if( needQuote ) bufpt[j++] = '\'';
for(i=0; (c=arg[i])!=0; i++){
bufpt[j++] = c;
if( c=='\'' ) bufpt[j++] = c;
}
if( needQuote ) bufpt[j++] = '\'';
bufpt[j] = 0;
length = j;
if( precision>=0 && precision<length ) length = precision;
case etSQLESCAPE2: {
int i, j, n, c, isnull;
int needQuote;
char *arg = va_arg(ap,char*);
isnull = arg==0;
if( isnull ) arg = (xtype==etSQLESCAPE2 ? "NULL" : "(NULL)");
for(i=n=0; (c=arg[i])!=0; i++){
if( c=='\'' ) n++;
}
needQuote = !isnull && xtype==etSQLESCAPE2;
n += i + 1 + needQuote*2;
if( n>etBUFSIZE ){
bufpt = zExtra = sqliteMalloc( n );
if( bufpt==0 ) return -1;
}else{
bufpt = buf;
}
j = 0;
if( needQuote ) bufpt[j++] = '\'';
for(i=0; (c=arg[i])!=0; i++){
bufpt[j++] = c;
if( c=='\'' ) bufpt[j++] = c;
}
if( needQuote ) bufpt[j++] = '\'';
bufpt[j] = 0;
length = j;
if( precision>=0 && precision<length ) length = precision;
break;
}
case etTOKEN: {
Token *pToken = va_arg(ap, Token*);
if( pToken && pToken->z ){

View file

@ -85,7 +85,7 @@ int sqlite3JoinType(Parse *pParse, Token *pA, Token *pB, Token *pC){
Token *apAll[3];
Token *p;
static const struct {
const char *zKeyword;
const char zKeyword[8];
u8 nChar;
u8 code;
} keywords[] = {
@ -155,6 +155,15 @@ static void setToken(Token *p, const char *z){
p->dyn = 0;
}
/*
** Create an expression node for an identifier with the name of zName
*/
static Expr *createIdExpr(const char *zName){
Token dummy;
setToken(&dummy, zName);
return sqlite3Expr(TK_ID, 0, 0, &dummy);
}
/*
** Add a term to the WHERE expression in *ppExpr that requires the
@ -168,24 +177,20 @@ static void addWhereTerm(
const char *zAlias2, /* Alias for second table. May be NULL */
Expr **ppExpr /* Add the equality term to this expression */
){
Token dummy;
Expr *pE1a, *pE1b, *pE1c;
Expr *pE2a, *pE2b, *pE2c;
Expr *pE;
setToken(&dummy, zCol);
pE1a = sqlite3Expr(TK_ID, 0, 0, &dummy);
pE2a = sqlite3Expr(TK_ID, 0, 0, &dummy);
pE1a = createIdExpr(zCol);
pE2a = createIdExpr(zCol);
if( zAlias1==0 ){
zAlias1 = pTab1->zName;
}
setToken(&dummy, zAlias1);
pE1b = sqlite3Expr(TK_ID, 0, 0, &dummy);
pE1b = createIdExpr(zAlias1);
if( zAlias2==0 ){
zAlias2 = pTab2->zName;
}
setToken(&dummy, zAlias2);
pE2b = sqlite3Expr(TK_ID, 0, 0, &dummy);
pE2b = createIdExpr(zAlias2);
pE1c = sqlite3Expr(TK_DOT, pE1b, pE1a, 0);
pE2c = sqlite3Expr(TK_DOT, pE2b, pE2a, 0);
pE = sqlite3Expr(TK_EQ, pE1c, pE2c, 0);
@ -321,10 +326,7 @@ void sqlite3SelectDelete(Select *p){
** stack into the sorter.
*/
static void pushOntoSorter(Parse *pParse, Vdbe *v, ExprList *pOrderBy){
int i;
for(i=0; i<pOrderBy->nExpr; i++){
sqlite3ExprCode(pParse, pOrderBy->a[i].pExpr);
}
sqlite3ExprCodeExprList(pParse, pOrderBy);
sqlite3VdbeAddOp(v, OP_MakeRecord, pOrderBy->nExpr, 0);
sqlite3VdbeAddOp(v, OP_SortInsert, 0, 0);
}
@ -402,9 +404,7 @@ static int selectInnerLoop(
}
}else{
nColumn = pEList->nExpr;
for(i=0; i<pEList->nExpr; i++){
sqlite3ExprCode(pParse, pEList->a[i].pExpr);
}
sqlite3ExprCodeExprList(pParse, pEList);
}
/* If the DISTINCT keyword was present on the SELECT statement
@ -412,14 +412,15 @@ static int selectInnerLoop(
** part of the result.
*/
if( hasDistinct ){
int n = pEList->nExpr;
#if NULL_ALWAYS_DISTINCT
sqlite3VdbeAddOp(v, OP_IsNull, -pEList->nExpr, sqlite3VdbeCurrentAddr(v)+7);
#endif
/* Deliberately leave the affinity string off of the following
** OP_MakeRecord */
sqlite3VdbeAddOp(v, OP_MakeRecord, pEList->nExpr * -1, 0);
sqlite3VdbeAddOp(v, OP_MakeRecord, -n, 0);
sqlite3VdbeAddOp(v, OP_Distinct, distinct, sqlite3VdbeCurrentAddr(v)+3);
sqlite3VdbeAddOp(v, OP_Pop, pEList->nExpr+1, 0);
sqlite3VdbeAddOp(v, OP_Pop, n+1, 0);
sqlite3VdbeAddOp(v, OP_Goto, 0, iContinue);
VdbeComment((v, "# skip indistinct records"));
sqlite3VdbeAddOp(v, OP_IdxInsert, distinct, 0);
@ -511,29 +512,21 @@ static int selectInnerLoop(
}
#endif /* #ifndef SQLITE_OMIT_SUBQUERY */
/* Send the data to the callback function.
/* Send the data to the callback function or to a subroutine. In the
** case of a subroutine, the subroutine itself is responsible for
** popping the data from the stack.
*/
case SRT_Subroutine:
case SRT_Callback:
case SRT_Sorter: {
if( pOrderBy ){
sqlite3VdbeAddOp(v, OP_MakeRecord, nColumn, 0);
pushOntoSorter(pParse, v, pOrderBy);
}else{
assert( eDest==SRT_Callback );
sqlite3VdbeAddOp(v, OP_Callback, nColumn, 0);
}
break;
}
/* Invoke a subroutine to handle the results. The subroutine itself
** is responsible for popping the results off of the stack.
*/
case SRT_Subroutine: {
if( pOrderBy ){
sqlite3VdbeAddOp(v, OP_MakeRecord, nColumn, 0);
pushOntoSorter(pParse, v, pOrderBy);
}else{
}else if( eDest==SRT_Subroutine ){
sqlite3VdbeAddOp(v, OP_Gosub, 0, iParm);
}else{
assert( eDest!=SRT_Sorter );
sqlite3VdbeAddOp(v, OP_Callback, nColumn, 0);
}
break;
}
@ -1322,9 +1315,9 @@ static void computeLimitRegisters(Parse *pParse, Select *p){
** DISTINCT, UNION, INTERSECT and EXCEPT select statements (but not
** UNION ALL).
**
** The value returned is the address of the OP_OpenTemp instruction.
** The value returned is the address of the OP_OpenVirtual instruction.
*/
static int openTempIndex(Parse *pParse, Select *p, int iTab){
static int openVirtualIndex(Parse *pParse, Select *p, int iTab){
KeyInfo *pKeyInfo;
int nColumn;
sqlite3 *db = pParse->db;
@ -1346,18 +1339,18 @@ static int openTempIndex(Parse *pParse, Select *p, int iTab){
pKeyInfo->aColl[i] = db->pDfltColl;
}
}
addr = sqlite3VdbeOp3(v, OP_OpenTemp, iTab, 0,
addr = sqlite3VdbeOp3(v, OP_OpenVirtual, iTab, 0,
(char*)pKeyInfo, P3_KEYINFO_HANDOFF);
return addr;
}
#ifndef SQLITE_OMIT_COMPOUND_SELECT
/*
** Add the address "addr" to the set of all OpenTemp opcode addresses
** that are being accumulated in p->ppOpenTemp.
** Add the address "addr" to the set of all OpenVirtual opcode addresses
** that are being accumulated in p->ppOpenVirtual.
*/
static int multiSelectOpenTempAddr(Select *p, int addr){
IdList *pList = *p->ppOpenTemp = sqlite3IdListAppend(*p->ppOpenTemp, 0);
static int multiSelectOpenVirtualAddr(Select *p, int addr){
IdList *pList = *p->ppOpenVirtual = sqlite3IdListAppend(*p->ppOpenVirtual, 0);
if( pList==0 ){
return SQLITE_NOMEM;
}
@ -1430,7 +1423,7 @@ static int multiSelect(
int rc = SQLITE_OK; /* Success code from a subroutine */
Select *pPrior; /* Another SELECT immediately to our left */
Vdbe *v; /* Generate code to this VDBE */
IdList *pOpenTemp = 0;/* OP_OpenTemp opcodes that need a KeyInfo */
IdList *pOpenVirtual = 0;/* OP_OpenVirtual opcodes that need a KeyInfo */
int aAddr[5]; /* Addresses of SetNumColumns operators */
int nAddr = 0; /* Number used */
int nCol; /* Number of columns in the result set */
@ -1465,21 +1458,21 @@ static int multiSelect(
}
/* If *p this is the right-most select statement, then initialize
** p->ppOpenTemp to point to pOpenTemp. If *p is not the right most
** statement then p->ppOpenTemp will have already been initialized
** by a prior call to this same procedure. Pass along the pOpenTemp
** p->ppOpenVirtual to point to pOpenVirtual. If *p is not the right most
** statement then p->ppOpenVirtual will have already been initialized
** by a prior call to this same procedure. Pass along the pOpenVirtual
** pointer to pPrior, the next statement to our left.
*/
if( p->ppOpenTemp==0 ){
p->ppOpenTemp = &pOpenTemp;
if( p->ppOpenVirtual==0 ){
p->ppOpenVirtual = &pOpenVirtual;
}
pPrior->ppOpenTemp = p->ppOpenTemp;
pPrior->ppOpenVirtual = p->ppOpenVirtual;
/* Create the destination temporary table if necessary
*/
if( eDest==SRT_TempTable ){
assert( p->pEList );
sqlite3VdbeAddOp(v, OP_OpenTemp, iParm, 0);
sqlite3VdbeAddOp(v, OP_OpenVirtual, iParm, 0);
assert( nAddr==0 );
aAddr[nAddr++] = sqlite3VdbeAddOp(v, OP_SetNumColumns, iParm, 0);
eDest = SRT_Table;
@ -1536,9 +1529,9 @@ static int multiSelect(
rc = 1;
goto multi_select_end;
}
addr = sqlite3VdbeAddOp(v, OP_OpenTemp, unionTab, 0);
addr = sqlite3VdbeAddOp(v, OP_OpenVirtual, unionTab, 0);
if( p->op!=TK_ALL ){
rc = multiSelectOpenTempAddr(p, addr);
rc = multiSelectOpenVirtualAddr(p, addr);
if( rc!=SQLITE_OK ){
goto multi_select_end;
}
@ -1628,8 +1621,8 @@ static int multiSelect(
goto multi_select_end;
}
addr = sqlite3VdbeAddOp(v, OP_OpenTemp, tab1, 0);
rc = multiSelectOpenTempAddr(p, addr);
addr = sqlite3VdbeAddOp(v, OP_OpenVirtual, tab1, 0);
rc = multiSelectOpenVirtualAddr(p, addr);
if( rc!=SQLITE_OK ){
goto multi_select_end;
}
@ -1646,8 +1639,8 @@ static int multiSelect(
/* Code the current SELECT into temporary table "tab2"
*/
addr = sqlite3VdbeAddOp(v, OP_OpenTemp, tab2, 0);
rc = multiSelectOpenTempAddr(p, addr);
addr = sqlite3VdbeAddOp(v, OP_OpenVirtual, tab2, 0);
rc = multiSelectOpenVirtualAddr(p, addr);
if( rc!=SQLITE_OK ){
goto multi_select_end;
}
@ -1725,11 +1718,11 @@ static int multiSelect(
** SELECT might also skip this part if it has no ORDER BY clause and
** no temp tables are required.
*/
if( p->pOrderBy || (pOpenTemp && pOpenTemp->nId>0) ){
if( p->pOrderBy || (pOpenVirtual && pOpenVirtual->nId>0) ){
int i; /* Loop counter */
KeyInfo *pKeyInfo; /* Collating sequence for the result set */
assert( p->ppOpenTemp == &pOpenTemp );
assert( p->ppOpenVirtual == &pOpenVirtual );
pKeyInfo = sqliteMalloc(sizeof(*pKeyInfo)+nCol*sizeof(CollSeq*));
if( !pKeyInfo ){
rc = SQLITE_NOMEM;
@ -1746,9 +1739,9 @@ static int multiSelect(
}
}
for(i=0; pOpenTemp && i<pOpenTemp->nId; i++){
for(i=0; pOpenVirtual && i<pOpenVirtual->nId; i++){
int p3type = (i==0?P3_KEYINFO_HANDOFF:P3_KEYINFO);
int addr = pOpenTemp->a[i].idx;
int addr = pOpenVirtual->a[i].idx;
sqlite3VdbeChangeP3(v, addr, (char *)pKeyInfo, p3type);
}
@ -1768,17 +1761,17 @@ static int multiSelect(
generateSortTail(pParse, p, v, p->pEList->nExpr, eDest, iParm);
}
if( !pOpenTemp ){
if( !pOpenVirtual ){
/* This happens for UNION ALL ... ORDER BY */
sqliteFree(pKeyInfo);
}
}
multi_select_end:
if( pOpenTemp ){
sqlite3IdListDelete(pOpenTemp);
if( pOpenVirtual ){
sqlite3IdListDelete(pOpenVirtual);
}
p->ppOpenTemp = 0;
p->ppOpenVirtual = 0;
return rc;
}
#endif /* SQLITE_OMIT_COMPOUND_SELECT */
@ -2183,7 +2176,7 @@ static int simpleMinMaxQuery(Parse *pParse, Select *p, int eDest, int iParm){
/* If the output is destined for a temporary table, open that table.
*/
if( eDest==SRT_TempTable ){
sqlite3VdbeAddOp(v, OP_OpenTemp, iParm, 0);
sqlite3VdbeAddOp(v, OP_OpenVirtual, iParm, 0);
sqlite3VdbeAddOp(v, OP_SetNumColumns, iParm, 1);
}
@ -2653,7 +2646,7 @@ int sqlite3Select(
/* If the output is destined for a temporary table, open that table.
*/
if( eDest==SRT_TempTable ){
sqlite3VdbeAddOp(v, OP_OpenTemp, iParm, 0);
sqlite3VdbeAddOp(v, OP_OpenVirtual, iParm, 0);
sqlite3VdbeAddOp(v, OP_SetNumColumns, iParm, pEList->nExpr);
}
@ -2737,7 +2730,7 @@ int sqlite3Select(
*/
if( isDistinct ){
distinct = pParse->nTab++;
openTempIndex(pParse, p, distinct);
openVirtualIndex(pParse, p, distinct);
}else{
distinct = -1;
}
@ -2766,9 +2759,7 @@ int sqlite3Select(
int lbl1 = 0;
pParse->fillAgg = 1;
if( pGroupBy ){
for(i=0; i<pGroupBy->nExpr; i++){
sqlite3ExprCode(pParse, pGroupBy->a[i].pExpr);
}
sqlite3ExprCodeExprList(pParse, pGroupBy);
/* No affinity string is attached to the following OP_MakeRecord
** because we do not need to do any coercion of datatypes. */
sqlite3VdbeAddOp(v, OP_MakeRecord, pGroupBy->nExpr, 0);

View file

@ -984,10 +984,10 @@ static int do_meta_command(char *zLine, struct callback_data *p){
p->showHeader = 1;
memset(p->colWidth,0,ArraySize(p->colWidth));
p->colWidth[0] = 4;
p->colWidth[1] = 12;
p->colWidth[1] = 14;
p->colWidth[2] = 10;
p->colWidth[3] = 10;
p->colWidth[4] = 35;
p->colWidth[4] = 33;
}else if (p->explainPrev.valid) {
p->explainPrev.valid = 0;
p->mode = p->explainPrev.mode;
@ -1093,6 +1093,7 @@ static int do_meta_command(char *zLine, struct callback_data *p){
}
}
}
*z = 0;
if( i+1!=nCol ){
fprintf(stderr,"%s line %d: expected %d columns of data but found %d\n",
zFile, lineno, nCol, i+1);

View file

@ -158,7 +158,7 @@ int sqlite3_exec(
*/
#define SQLITE_OK 0 /* Successful result */
#define SQLITE_ERROR 1 /* SQL error or missing database */
#define SQLITE_INTERNAL 2 /* An internal logic error in SQLite */
#define SQLITE_INTERNAL 2 /* NOT USED. Internal logic error in SQLite */
#define SQLITE_PERM 3 /* Access permission denied */
#define SQLITE_ABORT 4 /* Callback routine requested an abort */
#define SQLITE_BUSY 5 /* The database file is locked */
@ -168,13 +168,13 @@ int sqlite3_exec(
#define SQLITE_INTERRUPT 9 /* Operation terminated by sqlite3_interrupt()*/
#define SQLITE_IOERR 10 /* Some kind of disk I/O error occurred */
#define SQLITE_CORRUPT 11 /* The database disk image is malformed */
#define SQLITE_NOTFOUND 12 /* (Internal Only) Table or record not found */
#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_EMPTY 16 /* Database is empty */
#define SQLITE_SCHEMA 17 /* The database schema changed */
#define SQLITE_TOOBIG 18 /* Too much data for one row of a table */
#define SQLITE_TOOBIG 18 /* NOT USED. Too much data for one row */
#define SQLITE_CONSTRAINT 19 /* Abort due to contraint violation */
#define SQLITE_MISMATCH 20 /* Data type mismatch */
#define SQLITE_MISUSE 21 /* Library used incorrectly */
@ -452,6 +452,7 @@ int sqlite3_set_authorizer(
#define SQLITE_DETACH 25 /* Database Name NULL */
#define SQLITE_ALTER_TABLE 26 /* Database Name Table Name */
#define SQLITE_REINDEX 27 /* Index Name NULL */
#define SQLITE_ANALYZE 28 /* Table Name NULL */
/*
@ -1002,10 +1003,9 @@ int sqlite3_value_type(sqlite3_value*);
void *sqlite3_aggregate_context(sqlite3_context*, int nBytes);
/*
** The pUserData parameter to the sqlite3_create_function() and
** sqlite3_create_aggregate() routines used to register user functions
** is available to the implementation of the function using this
** call.
** The pUserData parameter to the sqlite3_create_function()
** routine used to register user functions is available to
** the implementation of the function using this call.
*/
void *sqlite3_user_data(sqlite3_context*);

View file

@ -39,7 +39,6 @@
# define _LARGEFILE_SOURCE 1
#endif
#include "config.h"
#include "sqlite3.h"
#include "hash.h"
#include "parse.h"
@ -209,6 +208,7 @@ typedef struct BusyHandler BusyHandler;
struct BusyHandler {
int (*xFunc)(void *,int); /* The busy callback */
void *pArg; /* First arg to busy callback */
int nBusy; /* Incremented with each busy call */
};
/*
@ -298,30 +298,30 @@ extern int sqlite3_iMallocReset; /* Set iMallocFail to this when it reaches 0 */
/*
** Forward references to structures
*/
typedef struct AggExpr AggExpr;
typedef struct AuthContext AuthContext;
typedef struct CollSeq CollSeq;
typedef struct Column Column;
typedef struct Table Table;
typedef struct Index Index;
typedef struct Db Db;
typedef struct Expr Expr;
typedef struct ExprList ExprList;
typedef struct Parse Parse;
typedef struct Token Token;
typedef struct IdList IdList;
typedef struct SrcList SrcList;
typedef struct WhereInfo WhereInfo;
typedef struct WhereLevel WhereLevel;
typedef struct Select Select;
typedef struct AggExpr AggExpr;
typedef struct FuncDef FuncDef;
typedef struct Trigger Trigger;
typedef struct TriggerStep TriggerStep;
typedef struct TriggerStack TriggerStack;
typedef struct FKey FKey;
typedef struct Db Db;
typedef struct AuthContext AuthContext;
typedef struct FuncDef FuncDef;
typedef struct IdList IdList;
typedef struct Index Index;
typedef struct KeyClass KeyClass;
typedef struct CollSeq CollSeq;
typedef struct KeyInfo KeyInfo;
typedef struct NameContext NameContext;
typedef struct Parse Parse;
typedef struct Select Select;
typedef struct SrcList SrcList;
typedef struct Table Table;
typedef struct Token Token;
typedef struct TriggerStack TriggerStack;
typedef struct TriggerStep TriggerStep;
typedef struct Trigger Trigger;
typedef struct WhereInfo WhereInfo;
typedef struct WhereLevel WhereLevel;
/*
** Each database file to be accessed by the system is an instance
@ -496,17 +496,23 @@ struct sqlite3 {
** points to a linked list of these structures.
*/
struct FuncDef {
char *zName; /* SQL name of the function */
int nArg; /* Number of arguments. -1 means unlimited */
i16 nArg; /* Number of arguments. -1 means unlimited */
u8 iPrefEnc; /* Preferred text encoding (SQLITE_UTF8, 16LE, 16BE) */
u8 needCollSeq; /* True if sqlite3GetFuncCollSeq() might be called */
u8 flags; /* Some combination of SQLITE_FUNC_* */
void *pUserData; /* User data parameter */
FuncDef *pNext; /* Next function with same name */
void (*xFunc)(sqlite3_context*,int,sqlite3_value**); /* Regular function */
void (*xStep)(sqlite3_context*,int,sqlite3_value**); /* Aggregate step */
void (*xFinalize)(sqlite3_context*); /* Aggregate finializer */
u8 needCollSeq; /* True if sqlite3GetFuncCollSeq() might be called */
char zName[1]; /* SQL name of the function. MUST BE LAST */
};
/*
** Possible values for FuncDef.flags
*/
#define SQLITE_FUNC_LIKEOPT 0x01 /* Candidate for the LIKE optimization */
/*
** information about each column of an SQL table is held in an instance
** of this structure.
@ -745,6 +751,7 @@ struct Index {
char *zName; /* Name of this index */
int nColumn; /* Number of columns in the table used by this index */
int *aiColumn; /* Which columns are used by this index. 1st is 0 */
unsigned *aiRowEst; /* Result of ANALYZE: Est. rows selected by each column */
Table *pTable; /* The SQL table being indexed */
int tnum; /* Page containing root of this index in database file */
u8 onError; /* OE_Abort, OE_Ignore, OE_Replace, or OE_None */
@ -839,12 +846,13 @@ struct Expr {
/*
** The following are the meanings of bits in the Expr.flags field.
*/
#define EP_FromJoin 0x0001 /* Originated in ON or USING clause of a join */
#define EP_Agg 0x0002 /* Contains one or more aggregate functions */
#define EP_Resolved 0x0004 /* IDs have been resolved to COLUMNs */
#define EP_Error 0x0008 /* Expression contains one or more errors */
#define EP_Not 0x0010 /* Operator preceeded by NOT */
#define EP_VarSelect 0x0020 /* pSelect is correlated, not constant */
#define EP_FromJoin 0x01 /* Originated in ON or USING clause of a join */
#define EP_Agg 0x02 /* Contains one or more aggregate functions */
#define EP_Resolved 0x04 /* IDs have been resolved to COLUMNs */
#define EP_Error 0x08 /* Expression contains one or more errors */
#define EP_Not 0x10 /* Operator preceeded by NOT */
#define EP_VarSelect 0x20 /* pSelect is correlated, not constant */
#define EP_Dequoted 0x40 /* True if the string has been dequoted */
/*
** These macros can be used to test, set, or clear bits in the
@ -924,8 +932,8 @@ struct SrcList {
char *zAlias; /* The "B" part of a "A AS B" phrase. zName is the "A" */
Table *pTab; /* An SQL table corresponding to zName */
Select *pSelect; /* A SELECT statement used in place of a table name */
int jointype; /* Type of join between this table and the next */
int iCursor; /* The VDBE cursor number used to access this table */
u8 jointype; /* Type of join between this table and the next */
i16 iCursor; /* The VDBE cursor number used to access this table */
Expr *pOn; /* The ON clause of a join */
IdList *pUsing; /* The USING clause of a join */
Bitmask colUsed; /* Bit N (1<<N) set if column N or pTab is used */
@ -949,18 +957,20 @@ struct SrcList {
** access or modified by other modules.
*/
struct WhereLevel {
int iMem; /* Memory cell used by this level */
Index *pIdx; /* Index used. NULL if no index */
int iTabCur; /* The VDBE cursor used to access the table */
int iIdxCur; /* The VDBE cursor used to acesss pIdx */
int score; /* How well this index scored */
int brk; /* Jump here to break out of the loop */
int cont; /* Jump here to continue with the next loop cycle */
int op, p1, p2; /* Opcode used to terminate the loop */
int iLeftJoin; /* Memory cell used to implement LEFT OUTER JOIN */
int top; /* First instruction of interior of the loop */
int inOp, inP1, inP2;/* Opcode used to implement an IN operator */
int bRev; /* Do the scan in the reverse direction */
int iFrom; /* Which entry in the FROM clause */
int flags; /* Flags associated with this level */
int iMem; /* First memory cell used by this level */
int iLeftJoin; /* Memory cell used to implement LEFT OUTER JOIN */
Index *pIdx; /* Index used. NULL if no index */
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 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 */
};
/*
@ -1036,7 +1046,7 @@ struct Select {
Expr *pLimit; /* LIMIT expression. NULL means not used. */
Expr *pOffset; /* OFFSET expression. NULL means not used. */
int iLimit, iOffset; /* Memory registers holding LIMIT & OFFSET counters */
IdList **ppOpenTemp; /* OP_OpenTemp addresses used by multi-selects */
IdList **ppOpenVirtual;/* OP_OpenVirtual addresses used by multi-selects */
u8 isResolved; /* True once sqlite3SelectResolve() has run. */
u8 isAgg; /* True if this is an aggregate query */
};
@ -1345,6 +1355,7 @@ void *sqlite3TextToPtr(const char*);
void sqlite3SetString(char **, ...);
void sqlite3ErrorMsg(Parse*, const char*, ...);
void sqlite3Dequote(char*);
void sqlite3DequoteExpr(Expr*);
int sqlite3KeywordCode(const char*, int);
int sqlite3RunParser(Parse*, const char*, char **);
void sqlite3FinishCoding(Parse*);
@ -1370,7 +1381,7 @@ void sqlite3StartTable(Parse*,Token*,Token*,Token*,int,int);
void sqlite3AddColumn(Parse*,Token*);
void sqlite3AddNotNull(Parse*, int);
void sqlite3AddPrimaryKey(Parse*, ExprList*, int, int);
void sqlite3AddColumnType(Parse*,Token*,Token*);
void sqlite3AddColumnType(Parse*,Token*);
void sqlite3AddDefaultValue(Parse*,Expr*);
void sqlite3AddCollateType(Parse*, const char*, int);
void sqlite3EndTable(Parse*,Token*,Token*,Select*);
@ -1437,6 +1448,7 @@ void sqlite3BeginTransaction(Parse*, int);
void sqlite3CommitTransaction(Parse*);
void sqlite3RollbackTransaction(Parse*);
int sqlite3ExprIsConstant(Expr*);
int sqlite3ExprIsConstantOrFunction(Expr*);
int sqlite3ExprIsInteger(Expr*, int*);
int sqlite3IsRowid(const char*);
void sqlite3GenerateRowDelete(sqlite3*, Vdbe*, Table*, int, int);
@ -1509,7 +1521,7 @@ int sqlite3FixSelect(DbFixer*, Select*);
int sqlite3FixExpr(DbFixer*, Expr*);
int sqlite3FixExprList(DbFixer*, ExprList*);
int sqlite3FixTriggerStep(DbFixer*, TriggerStep*);
double sqlite3AtoF(const char *z, const char **);
int sqlite3AtoF(const char *z, double*);
char *sqlite3_snprintf(int,char*,const char*,...);
int sqlite3GetInt32(const char *, int*);
int sqlite3FitsIn64Bits(const char *);
@ -1564,6 +1576,14 @@ void sqlite3AlterFinishAddColumn(Parse *, Token *);
void sqlite3AlterBeginAddColumn(Parse *, SrcList *);
const char *sqlite3TestErrorName(int);
CollSeq *sqlite3GetCollSeq(sqlite3*, CollSeq *, const char *, int);
char sqlite3AffinityType(const Token*);
void sqlite3Analyze(Parse*, Token*, Token*);
int sqlite3InvokeBusyHandler(BusyHandler*);
int sqlite3FindDb(sqlite3*, Token*);
void sqlite3AnalysisLoad(sqlite3*,int iDB);
void sqlite3DefaultRowEst(Index*);
void sqlite3RegisterLikeFunctions(sqlite3*, int);
int sqlite3IsLikeFunction(sqlite3*,Expr*,char*);
#ifdef SQLITE_SSE
#include "sseInt.h"

View file

@ -21,6 +21,7 @@
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <ctype.h>
#define NUM_PREPARED_STMTS 10
#define MAX_PREPARED_STMTS 100
@ -42,7 +43,9 @@
typedef struct SqlFunc SqlFunc;
struct SqlFunc {
Tcl_Interp *interp; /* The TCL interpret to execute the function */
char *zScript; /* The script to be run */
Tcl_Obj *pScript; /* The Tcl_Obj representation of the script */
int useEvalObjv; /* True if it is safe to use Tcl_EvalObjv */
char *zName; /* Name of this function */
SqlFunc *pNext; /* Next function on the list of them all */
};
@ -54,7 +57,7 @@ typedef struct SqlCollate SqlCollate;
struct SqlCollate {
Tcl_Interp *interp; /* The TCL interpret to execute the function */
char *zScript; /* The script to be run */
SqlCollate *pNext; /* Next function on the list of them all */
SqlCollate *pNext; /* Next function on the list of them all */
};
/*
@ -76,24 +79,76 @@ struct SqlPreparedStmt {
*/
typedef struct SqliteDb SqliteDb;
struct SqliteDb {
sqlite3 *db; /* The "real" database structure */
Tcl_Interp *interp; /* The interpreter used for this database */
char *zBusy; /* The busy callback routine */
char *zCommit; /* The commit hook callback routine */
char *zTrace; /* The trace callback routine */
char *zProgress; /* The progress callback routine */
char *zAuth; /* The authorization callback routine */
char *zNull; /* Text to substitute for an SQL NULL value */
SqlFunc *pFunc; /* List of SQL functions */
SqlCollate *pCollate; /* List of SQL collation functions */
int rc; /* Return code of most recent sqlite3_exec() */
Tcl_Obj *pCollateNeeded; /* Collation needed script */
sqlite3 *db; /* The "real" database structure */
Tcl_Interp *interp; /* The interpreter used for this database */
char *zBusy; /* The busy callback routine */
char *zCommit; /* The commit hook callback routine */
char *zTrace; /* The trace callback routine */
char *zProgress; /* The progress callback routine */
char *zAuth; /* The authorization callback routine */
char *zNull; /* Text to substitute for an SQL NULL value */
SqlFunc *pFunc; /* List of SQL functions */
SqlCollate *pCollate; /* List of SQL collation functions */
int rc; /* Return code of most recent sqlite3_exec() */
Tcl_Obj *pCollateNeeded; /* Collation needed script */
SqlPreparedStmt *stmtList; /* List of prepared statements*/
SqlPreparedStmt *stmtLast; /* Last statement in the list */
int maxStmt; /* The next maximum number of stmtList */
int nStmt; /* Number of statements in stmtList */
};
/*
** Look at the script prefix in pCmd. We will be executing this script
** after first appending one or more arguments. This routine analyzes
** the script to see if it is safe to use Tcl_EvalObjv() on the script
** rather than the more general Tcl_EvalEx(). Tcl_EvalObjv() is much
** faster.
**
** Scripts that are safe to use with Tcl_EvalObjv() consists of a
** command name followed by zero or more arguments with no [...] or $
** or {...} or ; to be seen anywhere. Most callback scripts consist
** of just a single procedure name and they meet this requirement.
*/
static int safeToUseEvalObjv(Tcl_Interp *interp, Tcl_Obj *pCmd){
/* We could try to do something with Tcl_Parse(). But we will instead
** just do a search for forbidden characters. If any of the forbidden
** characters appear in pCmd, we will report the string as unsafe.
*/
const char *z;
int n;
z = Tcl_GetStringFromObj(pCmd, &n);
while( n-- > 0 ){
int c = *(z++);
if( c=='$' || c=='[' || c==';' ) return 0;
}
return 1;
}
/*
** Find an SqlFunc structure with the given name. Or create a new
** one if an existing one cannot be found. Return a pointer to the
** structure.
*/
static SqlFunc *findSqlFunc(SqliteDb *pDb, const char *zName){
SqlFunc *p, *pNew;
int i;
pNew = (SqlFunc*)Tcl_Alloc( sizeof(*pNew) + strlen(zName) + 1 );
pNew->zName = (char*)&pNew[1];
for(i=0; zName[i]; i++){ pNew->zName[i] = tolower(zName[i]); }
pNew->zName[i] = 0;
for(p=pDb->pFunc; p; p=p->pNext){
if( strcmp(p->zName, pNew->zName)==0 ){
Tcl_Free((char*)pNew);
return p;
}
}
pNew->interp = pDb->interp;
pNew->pScript = 0;
pNew->pNext = pDb->pFunc;
pDb->pFunc = pNew;
return pNew;
}
/*
** Finalize and free a list of prepared statements
*/
@ -121,6 +176,7 @@ static void DbDeleteCmd(void *db){
while( pDb->pFunc ){
SqlFunc *pFunc = pDb->pFunc;
pDb->pFunc = pFunc->pNext;
Tcl_DecrRefCount(pFunc->pScript);
Tcl_Free((char*)pFunc);
}
while( pDb->pCollate ){
@ -151,16 +207,9 @@ static int DbBusyHandler(void *cd, int nTries){
SqliteDb *pDb = (SqliteDb*)cd;
int rc;
char zVal[30];
char *zCmd;
Tcl_DString cmd;
Tcl_DStringInit(&cmd);
Tcl_DStringAppend(&cmd, pDb->zBusy, -1);
sprintf(zVal, "%d", nTries);
Tcl_DStringAppendElement(&cmd, zVal);
zCmd = Tcl_DStringValue(&cmd);
rc = Tcl_Eval(pDb->interp, zCmd);
Tcl_DStringFree(&cmd);
rc = Tcl_VarEval(pDb->interp, pDb->zBusy, " ", zVal, (char*)0);
if( rc!=TCL_OK || atoi(Tcl_GetStringResult(pDb->interp)) ){
return 0;
}
@ -247,7 +296,7 @@ static int tclSqlCollate(
Tcl_IncrRefCount(pCmd);
Tcl_ListObjAppendElement(p->interp, pCmd, Tcl_NewStringObj(zA, nA));
Tcl_ListObjAppendElement(p->interp, pCmd, Tcl_NewStringObj(zB, nB));
Tcl_EvalObjEx(p->interp, pCmd, 0);
Tcl_EvalObjEx(p->interp, pCmd, TCL_EVAL_DIRECT);
Tcl_DecrRefCount(pCmd);
return (atoi(Tcl_GetStringResult(p->interp)));
}
@ -258,22 +307,88 @@ static int tclSqlCollate(
*/
static void tclSqlFunc(sqlite3_context *context, int argc, sqlite3_value**argv){
SqlFunc *p = sqlite3_user_data(context);
Tcl_DString cmd;
Tcl_Obj *pCmd;
int i;
int rc;
Tcl_DStringInit(&cmd);
Tcl_DStringAppend(&cmd, p->zScript, -1);
for(i=0; i<argc; i++){
if( SQLITE_NULL==sqlite3_value_type(argv[i]) ){
Tcl_DStringAppendElement(&cmd, "");
}else{
Tcl_DStringAppendElement(&cmd, sqlite3_value_text(argv[i]));
if( argc==0 ){
/* If there are no arguments to the function, call Tcl_EvalObjEx on the
** script object directly. This allows the TCL compiler to generate
** bytecode for the command on the first invocation and thus make
** subsequent invocations much faster. */
pCmd = p->pScript;
Tcl_IncrRefCount(pCmd);
rc = Tcl_EvalObjEx(p->interp, pCmd, 0);
Tcl_DecrRefCount(pCmd);
}else{
/* If there are arguments to the function, make a shallow copy of the
** script object, lappend the arguments, then evaluate the copy.
**
** By "shallow" copy, we mean a only the outer list Tcl_Obj is duplicated.
** The new Tcl_Obj contains pointers to the original list elements.
** That way, when Tcl_EvalObjv() is run and shimmers the first element
** of the list to tclCmdNameType, that alternate representation will
** be preserved and reused on the next invocation.
*/
Tcl_Obj **aArg;
int nArg;
if( Tcl_ListObjGetElements(p->interp, p->pScript, &nArg, &aArg) ){
sqlite3_result_error(context, Tcl_GetStringResult(p->interp), -1);
return;
}
pCmd = Tcl_NewListObj(nArg, aArg);
Tcl_IncrRefCount(pCmd);
for(i=0; i<argc; i++){
sqlite3_value *pIn = argv[i];
Tcl_Obj *pVal;
/* Set pVal to contain the i'th column of this row. */
switch( sqlite3_value_type(pIn) ){
case SQLITE_BLOB: {
int bytes = sqlite3_value_bytes(pIn);
pVal = Tcl_NewByteArrayObj(sqlite3_value_blob(pIn), bytes);
break;
}
case SQLITE_INTEGER: {
sqlite_int64 v = sqlite3_value_int64(pIn);
if( v>=-2147483647 && v<=2147483647 ){
pVal = Tcl_NewIntObj(v);
}else{
pVal = Tcl_NewWideIntObj(v);
}
break;
}
case SQLITE_FLOAT: {
double r = sqlite3_value_double(pIn);
pVal = Tcl_NewDoubleObj(r);
break;
}
case SQLITE_NULL: {
pVal = Tcl_NewStringObj("", 0);
break;
}
default: {
int bytes = sqlite3_value_bytes(pIn);
pVal = Tcl_NewStringObj(sqlite3_value_text(pIn), bytes);
break;
}
}
rc = Tcl_ListObjAppendElement(p->interp, pCmd, pVal);
if( rc ){
Tcl_DecrRefCount(pCmd);
sqlite3_result_error(context, Tcl_GetStringResult(p->interp), -1);
return;
}
}
if( !p->useEvalObjv ){
/* Tcl_EvalObjEx() will automatically call Tcl_EvalObjv() if pCmd
** is a list without a string representation. To prevent this from
** happening, make sure pCmd has a valid string representation */
Tcl_GetString(pCmd);
}
rc = Tcl_EvalObjEx(p->interp, pCmd, TCL_EVAL_DIRECT);
Tcl_DecrRefCount(pCmd);
}
rc = Tcl_EvalEx(p->interp, Tcl_DStringValue(&cmd), Tcl_DStringLength(&cmd),
TCL_EVAL_DIRECT);
Tcl_DStringFree(&cmd);
if( rc && rc!=TCL_RETURN ){
sqlite3_result_error(context, Tcl_GetStringResult(p->interp), -1);
@ -283,7 +398,9 @@ static void tclSqlFunc(sqlite3_context *context, int argc, sqlite3_value**argv){
u8 *data;
char *zType = pVar->typePtr ? pVar->typePtr->name : "";
char c = zType[0];
if( c=='b' && strcmp(zType,"bytearray")==0 ){
if( c=='b' && strcmp(zType,"bytearray")==0 && pVar->bytes==0 ){
/* Only return a BLOB type if the Tcl variable is a bytearray and
** has no string representation. */
data = Tcl_GetByteArrayFromObj(pVar, &n);
sqlite3_result_blob(context, data, n, SQLITE_TRANSIENT);
}else if( (c=='b' && strcmp(zType,"boolean")==0) ||
@ -294,6 +411,10 @@ static void tclSqlFunc(sqlite3_context *context, int argc, sqlite3_value**argv){
double r;
Tcl_GetDoubleFromObj(0, pVar, &r);
sqlite3_result_double(context, r);
}else if( c=='w' && strcmp(zType,"wideInt")==0 ){
Tcl_WideInt v;
Tcl_GetWideIntFromObj(0, pVar, &v);
sqlite3_result_int64(context, v);
}else{
data = Tcl_GetStringFromObj(pVar, &n);
sqlite3_result_text(context, data, n, SQLITE_TRANSIENT);
@ -351,6 +472,7 @@ static int auth_callback(
case SQLITE_DETACH : zCode="SQLITE_DETACH"; break;
case SQLITE_ALTER_TABLE : zCode="SQLITE_ALTER_TABLE"; break;
case SQLITE_REINDEX : zCode="SQLITE_REINDEX"; break;
case SQLITE_ANALYZE : zCode="SQLITE_ANALYZE"; break;
default : zCode="????"; break;
}
Tcl_DStringInit(&str);
@ -469,8 +591,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
"function", "last_insert_rowid", "nullvalue",
"onecolumn", "progress", "rekey",
"timeout", "total_changes", "trace",
"version",
0
"transaction", "version", 0
};
enum DB_enum {
DB_AUTHORIZER, DB_BUSY, DB_CACHE,
@ -480,7 +601,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
DB_FUNCTION, DB_LAST_INSERT_ROWID,DB_NULLVALUE,
DB_ONECOLUMN, DB_PROGRESS, DB_REKEY,
DB_TIMEOUT, DB_TOTAL_CHANGES, DB_TRACE,
DB_VERSION
DB_TRANSACTION, DB_VERSION,
};
/* don't leave trailing commas on DB_enum, it confuses the AIX xlc compiler */
@ -924,7 +1045,9 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
u8 *data;
char *zType = pVar->typePtr ? pVar->typePtr->name : "";
char c = zType[0];
if( c=='b' && strcmp(zType,"bytearray")==0 ){
if( c=='b' && strcmp(zType,"bytearray")==0 && pVar->bytes==0 ){
/* Only load a BLOB type if the Tcl variable is a bytearray and
** has no string representation. */
data = Tcl_GetByteArrayFromObj(pVar, &n);
sqlite3_bind_blob(pStmt, i, data, n, SQLITE_STATIC);
Tcl_IncrRefCount(pVar);
@ -937,6 +1060,10 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
double r;
Tcl_GetDoubleFromObj(interp, pVar, &r);
sqlite3_bind_double(pStmt, i, r);
}else if( c=='w' && strcmp(zType,"wideInt")==0 ){
Tcl_WideInt v;
Tcl_GetWideIntFromObj(interp, pVar, &v);
sqlite3_bind_int64(pStmt, i, v);
}else{
data = Tcl_GetStringFromObj(pVar, &n);
sqlite3_bind_text(pStmt, i, data, n, SQLITE_STATIC);
@ -1146,22 +1273,22 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
*/
case DB_FUNCTION: {
SqlFunc *pFunc;
Tcl_Obj *pScript;
char *zName;
char *zScript;
int nScript;
if( objc!=4 ){
Tcl_WrongNumArgs(interp, 2, objv, "NAME SCRIPT");
return TCL_ERROR;
}
zName = Tcl_GetStringFromObj(objv[2], 0);
zScript = Tcl_GetStringFromObj(objv[3], &nScript);
pFunc = (SqlFunc*)Tcl_Alloc( sizeof(*pFunc) + nScript + 1 );
pScript = objv[3];
pFunc = findSqlFunc(pDb, zName);
if( pFunc==0 ) return TCL_ERROR;
pFunc->interp = interp;
pFunc->pNext = pDb->pFunc;
pFunc->zScript = (char*)&pFunc[1];
pDb->pFunc = pFunc;
strcpy(pFunc->zScript, zScript);
if( pFunc->pScript ){
Tcl_DecrRefCount(pFunc->pScript);
}
pFunc->pScript = pScript;
Tcl_IncrRefCount(pScript);
pFunc->useEvalObjv = safeToUseEvalObjv(interp, pScript);
rc = sqlite3_create_function(pDb->db, zName, -1, SQLITE_UTF8,
pFunc, tclSqlFunc, 0, 0);
if( rc!=SQLITE_OK ){
@ -1362,6 +1489,63 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
break;
}
/* $db transaction [-deferred|-immediate|-exclusive] SCRIPT
**
** Start a new transaction (if we are not already in the midst of a
** transaction) and execute the TCL script SCRIPT. After SCRIPT
** completes, either commit the transaction or roll it back if SCRIPT
** throws an exception. Or if no new transation was started, do nothing.
** pass the exception on up the stack.
**
** This command was inspired by Dave Thomas's talk on Ruby at the
** 2005 O'Reilly Open Source Convention (OSCON).
*/
case DB_TRANSACTION: {
int inTrans;
Tcl_Obj *pScript;
const char *zBegin = "BEGIN";
if( objc!=3 && objc!=4 ){
Tcl_WrongNumArgs(interp, 2, objv, "[TYPE] SCRIPT");
return TCL_ERROR;
}
if( objc==3 ){
pScript = objv[2];
} else {
static const char *TTYPE_strs[] = {
"deferred", "exclusive", "immediate", 0
};
enum TTYPE_enum {
TTYPE_DEFERRED, TTYPE_EXCLUSIVE, TTYPE_IMMEDIATE
};
int ttype;
if( Tcl_GetIndexFromObj(interp, objv[2], TTYPE_strs, "transaction type",
0, &ttype) ){
return TCL_ERROR;
}
switch( (enum TTYPE_enum)ttype ){
case TTYPE_DEFERRED: /* no-op */; break;
case TTYPE_EXCLUSIVE: zBegin = "BEGIN EXCLUSIVE"; break;
case TTYPE_IMMEDIATE: zBegin = "BEGIN IMMEDIATE"; break;
}
pScript = objv[3];
}
inTrans = !sqlite3_get_autocommit(pDb->db);
if( !inTrans ){
sqlite3_exec(pDb->db, zBegin, 0, 0, 0);
}
rc = Tcl_EvalObjEx(interp, pScript, 0);
if( !inTrans ){
const char *zEnd;
if( rc==TCL_ERROR ){
zEnd = "ROLLBACK";
} else {
zEnd = "COMMIT";
}
sqlite3_exec(pDb->db, zEnd, 0, 0, 0);
}
break;
}
/* $db copy conflict-algorithm table filename ?SEPARATOR? ?NULLINDICATOR?
**
** Copy data into table from filename, optionally using SEPARATOR

View file

@ -26,7 +26,6 @@ const char *sqlite3TestErrorName(int rc){
switch( rc ){
case SQLITE_OK: zName = "SQLITE_OK"; break;
case SQLITE_ERROR: zName = "SQLITE_ERROR"; break;
case SQLITE_INTERNAL: zName = "SQLITE_INTERNAL"; break;
case SQLITE_PERM: zName = "SQLITE_PERM"; break;
case SQLITE_ABORT: zName = "SQLITE_ABORT"; break;
case SQLITE_BUSY: zName = "SQLITE_BUSY"; break;
@ -36,13 +35,11 @@ const char *sqlite3TestErrorName(int rc){
case SQLITE_INTERRUPT: zName = "SQLITE_INTERRUPT"; break;
case SQLITE_IOERR: zName = "SQLITE_IOERR"; break;
case SQLITE_CORRUPT: zName = "SQLITE_CORRUPT"; break;
case SQLITE_NOTFOUND: zName = "SQLITE_NOTFOUND"; break;
case SQLITE_FULL: zName = "SQLITE_FULL"; break;
case SQLITE_CANTOPEN: zName = "SQLITE_CANTOPEN"; break;
case SQLITE_PROTOCOL: zName = "SQLITE_PROTOCOL"; break;
case SQLITE_EMPTY: zName = "SQLITE_EMPTY"; break;
case SQLITE_SCHEMA: zName = "SQLITE_SCHEMA"; break;
case SQLITE_TOOBIG: zName = "SQLITE_TOOBIG"; break;
case SQLITE_CONSTRAINT: zName = "SQLITE_CONSTRAINT"; break;
case SQLITE_MISMATCH: zName = "SQLITE_MISMATCH"; break;
case SQLITE_MISUSE: zName = "SQLITE_MISUSE"; break;
@ -2759,12 +2756,24 @@ static void set_options(Tcl_Interp *interp){
Tcl_SetVar2(interp, "sqlite_options", "rowid32", "0", TCL_GLOBAL_ONLY);
#endif
#ifdef SQLITE_CASE_SENSITIVE_LIKE
Tcl_SetVar2(interp, "sqlite_options","casesensitivelike","1",TCL_GLOBAL_ONLY);
#else
Tcl_SetVar2(interp, "sqlite_options","casesensitivelike","0",TCL_GLOBAL_ONLY);
#endif
#ifdef SQLITE_OMIT_ALTERTABLE
Tcl_SetVar2(interp, "sqlite_options", "altertable", "0", TCL_GLOBAL_ONLY);
#else
Tcl_SetVar2(interp, "sqlite_options", "altertable", "1", TCL_GLOBAL_ONLY);
#endif
#ifdef SQLITE_OMIT_ANALYZE
Tcl_SetVar2(interp, "sqlite_options", "analyze", "0", TCL_GLOBAL_ONLY);
#else
Tcl_SetVar2(interp, "sqlite_options", "analyze", "1", TCL_GLOBAL_ONLY);
#endif
#ifdef SQLITE_OMIT_AUTHORIZATION
Tcl_SetVar2(interp, "sqlite_options", "auth", "0", TCL_GLOBAL_ONLY);
#else
@ -2788,12 +2797,24 @@ static void set_options(Tcl_Interp *interp){
Tcl_SetVar2(interp,"sqlite_options","default_autovacuum","1",TCL_GLOBAL_ONLY);
#endif
#ifdef SQLITE_OMIT_BETWEEN_OPTIMIZATION
Tcl_SetVar2(interp, "sqlite_options", "between_opt", "0", TCL_GLOBAL_ONLY);
#else
Tcl_SetVar2(interp, "sqlite_options", "between_opt", "1", TCL_GLOBAL_ONLY);
#endif
#ifdef SQLITE_OMIT_BLOB_LITERAL
Tcl_SetVar2(interp, "sqlite_options", "bloblit", "0", TCL_GLOBAL_ONLY);
#else
Tcl_SetVar2(interp, "sqlite_options", "bloblit", "1", TCL_GLOBAL_ONLY);
#endif
#ifdef SQLITE_OMIT_CAST
Tcl_SetVar2(interp, "sqlite_options", "cast", "0", TCL_GLOBAL_ONLY);
#else
Tcl_SetVar2(interp, "sqlite_options", "cast", "1", TCL_GLOBAL_ONLY);
#endif
#ifdef SQLITE_OMIT_COMPLETE
Tcl_SetVar2(interp, "sqlite_options", "complete", "0", TCL_GLOBAL_ONLY);
#else
@ -2854,12 +2875,24 @@ static void set_options(Tcl_Interp *interp){
Tcl_SetVar2(interp, "sqlite_options", "integrityck", "1", TCL_GLOBAL_ONLY);
#endif
#ifdef SQLITE_OMIT_LIKE_OPTIMIZATION
Tcl_SetVar2(interp, "sqlite_options", "like_opt", "0", TCL_GLOBAL_ONLY);
#else
Tcl_SetVar2(interp, "sqlite_options", "like_opt", "1", TCL_GLOBAL_ONLY);
#endif
#ifdef SQLITE_OMIT_MEMORYDB
Tcl_SetVar2(interp, "sqlite_options", "memorydb", "0", TCL_GLOBAL_ONLY);
#else
Tcl_SetVar2(interp, "sqlite_options", "memorydb", "1", TCL_GLOBAL_ONLY);
#endif
#ifdef SQLITE_OMIT_OR_OPTIMIZATION
Tcl_SetVar2(interp, "sqlite_options", "or_opt", "0", TCL_GLOBAL_ONLY);
#else
Tcl_SetVar2(interp, "sqlite_options", "or_opt", "1", TCL_GLOBAL_ONLY);
#endif
#ifdef SQLITE_OMIT_PAGER_PRAGMAS
Tcl_SetVar2(interp, "sqlite_options", "pager_pragmas", "0", TCL_GLOBAL_ONLY);
#else
@ -3073,8 +3106,17 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
static int bitmask_size = sizeof(Bitmask)*8;
int i;
extern int sqlite3_os_trace;
extern int sqlite3_where_trace;
extern int sqlite3_sync_count, sqlite3_fullsync_count;
extern int sqlite3_opentemp_count;
extern int sqlite3_memUsed;
extern int sqlite3_memMax;
extern char sqlite3_query_plan[];
extern int sqlite3_like_count;
#ifdef SQLITE_DEBUG
extern int sqlite3_vdbe_addop_trace;
#endif
static char *query_plan = sqlite3_query_plan;
for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){
Tcl_CreateCommand(interp, aCmd[i].zName, aCmd[i].xProc, 0, 0);
@ -3087,6 +3129,8 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
(char*)&sqlite3_search_count, TCL_LINK_INT);
Tcl_LinkVar(interp, "sqlite_sort_count",
(char*)&sqlite3_sort_count, TCL_LINK_INT);
Tcl_LinkVar(interp, "sqlite_like_count",
(char*)&sqlite3_like_count, TCL_LINK_INT);
Tcl_LinkVar(interp, "sqlite_interrupt_count",
(char*)&sqlite3_interrupt_count, TCL_LINK_INT);
Tcl_LinkVar(interp, "sqlite_open_file_count",
@ -3095,6 +3139,20 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
(char*)&sqlite3_current_time, TCL_LINK_INT);
Tcl_LinkVar(interp, "sqlite_os_trace",
(char*)&sqlite3_os_trace, TCL_LINK_INT);
Tcl_LinkVar(interp, "sqlite_where_trace",
(char*)&sqlite3_where_trace, TCL_LINK_INT);
#ifdef SQLITE_DEBUG
Tcl_LinkVar(interp, "sqlite_addop_trace",
(char*)&sqlite3_vdbe_addop_trace, TCL_LINK_INT);
#endif
#ifdef SQLITE_MEMDEBUG
Tcl_LinkVar(interp, "sqlite_memused",
(char*)&sqlite3_memUsed, TCL_LINK_INT | TCL_LINK_READ_ONLY);
Tcl_LinkVar(interp, "sqlite_memmax",
(char*)&sqlite3_memMax, TCL_LINK_INT | TCL_LINK_READ_ONLY);
#endif
Tcl_LinkVar(interp, "sqlite_query_plan",
(char*)&query_plan, TCL_LINK_STRING|TCL_LINK_READ_ONLY);
#ifndef SQLITE_OMIT_DISKIO
Tcl_LinkVar(interp, "sqlite_opentemp_count",
(char*)&sqlite3_opentemp_count, TCL_LINK_INT);

View file

@ -30,7 +30,6 @@ static char *errorName(int rc){
switch( rc ){
case SQLITE_OK: zName = "SQLITE_OK"; break;
case SQLITE_ERROR: zName = "SQLITE_ERROR"; break;
case SQLITE_INTERNAL: zName = "SQLITE_INTERNAL"; break;
case SQLITE_PERM: zName = "SQLITE_PERM"; break;
case SQLITE_ABORT: zName = "SQLITE_ABORT"; break;
case SQLITE_BUSY: zName = "SQLITE_BUSY"; break;
@ -39,13 +38,11 @@ static char *errorName(int rc){
case SQLITE_INTERRUPT: zName = "SQLITE_INTERRUPT"; break;
case SQLITE_IOERR: zName = "SQLITE_IOERR"; break;
case SQLITE_CORRUPT: zName = "SQLITE_CORRUPT"; break;
case SQLITE_NOTFOUND: zName = "SQLITE_NOTFOUND"; break;
case SQLITE_FULL: zName = "SQLITE_FULL"; break;
case SQLITE_CANTOPEN: zName = "SQLITE_CANTOPEN"; break;
case SQLITE_PROTOCOL: zName = "SQLITE_PROTOCOL"; break;
case SQLITE_EMPTY: zName = "SQLITE_EMPTY"; break;
case SQLITE_SCHEMA: zName = "SQLITE_SCHEMA"; break;
case SQLITE_TOOBIG: zName = "SQLITE_TOOBIG"; break;
case SQLITE_CONSTRAINT: zName = "SQLITE_CONSTRAINT"; break;
case SQLITE_MISMATCH: zName = "SQLITE_MISMATCH"; break;
case SQLITE_MISUSE: zName = "SQLITE_MISUSE"; break;

View file

@ -30,7 +30,6 @@ static char *errorName(int rc){
switch( rc ){
case SQLITE_OK: zName = "SQLITE_OK"; break;
case SQLITE_ERROR: zName = "SQLITE_ERROR"; break;
case SQLITE_INTERNAL: zName = "SQLITE_INTERNAL"; break;
case SQLITE_PERM: zName = "SQLITE_PERM"; break;
case SQLITE_ABORT: zName = "SQLITE_ABORT"; break;
case SQLITE_BUSY: zName = "SQLITE_BUSY"; break;
@ -39,7 +38,6 @@ static char *errorName(int rc){
case SQLITE_INTERRUPT: zName = "SQLITE_INTERRUPT"; break;
case SQLITE_IOERR: zName = "SQLITE_IOERR"; break;
case SQLITE_CORRUPT: zName = "SQLITE_CORRUPT"; break;
case SQLITE_NOTFOUND: zName = "SQLITE_NOTFOUND"; break;
case SQLITE_FULL: zName = "SQLITE_FULL"; break;
case SQLITE_CANTOPEN: zName = "SQLITE_CANTOPEN"; break;
case SQLITE_PROTOCOL: zName = "SQLITE_PROTOCOL"; break;

View file

@ -375,7 +375,6 @@ static int tcl_thread_result(
switch( threadset[i].rc ){
case SQLITE_OK: zName = "SQLITE_OK"; break;
case SQLITE_ERROR: zName = "SQLITE_ERROR"; break;
case SQLITE_INTERNAL: zName = "SQLITE_INTERNAL"; break;
case SQLITE_PERM: zName = "SQLITE_PERM"; break;
case SQLITE_ABORT: zName = "SQLITE_ABORT"; break;
case SQLITE_BUSY: zName = "SQLITE_BUSY"; break;
@ -385,13 +384,11 @@ static int tcl_thread_result(
case SQLITE_INTERRUPT: zName = "SQLITE_INTERRUPT"; break;
case SQLITE_IOERR: zName = "SQLITE_IOERR"; break;
case SQLITE_CORRUPT: zName = "SQLITE_CORRUPT"; break;
case SQLITE_NOTFOUND: zName = "SQLITE_NOTFOUND"; break;
case SQLITE_FULL: zName = "SQLITE_FULL"; break;
case SQLITE_CANTOPEN: zName = "SQLITE_CANTOPEN"; break;
case SQLITE_PROTOCOL: zName = "SQLITE_PROTOCOL"; break;
case SQLITE_EMPTY: zName = "SQLITE_EMPTY"; break;
case SQLITE_SCHEMA: zName = "SQLITE_SCHEMA"; break;
case SQLITE_TOOBIG: zName = "SQLITE_TOOBIG"; break;
case SQLITE_CONSTRAINT: zName = "SQLITE_CONSTRAINT"; break;
case SQLITE_MISMATCH: zName = "SQLITE_MISMATCH"; break;
case SQLITE_MISUSE: zName = "SQLITE_MISUSE"; break;

View file

@ -38,9 +38,9 @@
/*
** If X is a character that can be used in an identifier and
** X&0x80==0 then isIdChar[X] will be 1. If X&0x80==0x80 then
** X&0x80==0 then sqlite3IsIdChar[X] will be 1. If X&0x80==0x80 then
** X is always an identifier character. (Hence all UTF-8
** characters can be part of an identifier). isIdChar[X] will
** characters can be part of an identifier). sqlite3IsIdChar[X] will
** be 0 for every character in the lower 128 ASCII characters
** that cannot be used as part of an identifier.
**
@ -55,7 +55,7 @@
** SQLite will allow '$' in identifiers for compatibility.
** But the feature is undocumented.
*/
static const char isIdChar[] = {
const char sqlite3IsIdChar[] = {
/* x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF */
0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 2x */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, /* 3x */
@ -65,7 +65,7 @@ static const char isIdChar[] = {
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, /* 7x */
};
#define IdChar(C) (((c=C)&0x80)!=0 || (c>0x1f && isIdChar[c-0x20]))
#define IdChar(C) (((c=C)&0x80)!=0 || (c>0x1f && sqlite3IsIdChar[c-0x20]))
/*
** Return the length of the token that begins at z[0].
@ -183,12 +183,9 @@ static int getToken(const unsigned char *z, int *tokenType){
*tokenType = TK_BITNOT;
return 1;
}
case '#': {
for(i=1; isdigit(z[i]) || (i==1 && z[1]=='-'); i++){}
*tokenType = TK_REGISTER;
return i;
}
case '\'': case '"': {
case '`':
case '\'':
case '"': {
int delim = z[0];
for(i=1; (c=z[i])!=0; i++){
if( c==delim ){
@ -204,16 +201,23 @@ static int getToken(const unsigned char *z, int *tokenType){
return i;
}
case '.': {
*tokenType = TK_DOT;
return 1;
#ifndef SQLITE_OMIT_FLOATING_POINT
if( !isdigit(z[1]) )
#endif
{
*tokenType = TK_DOT;
return 1;
}
/* If the next character is a digit, this is a floating point
** number that begins with ".". Fall thru into the next case */
}
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9': {
*tokenType = TK_INTEGER;
for(i=1; isdigit(z[i]); i++){}
for(i=0; isdigit(z[i]); i++){}
#ifndef SQLITE_OMIT_FLOATING_POINT
if( z[i]=='.' && isdigit(z[i+1]) ){
i += 2;
if( z[i]=='.' ){
i++;
while( isdigit(z[i]) ){ i++; }
*tokenType = TK_FLOAT;
}
@ -239,50 +243,47 @@ static int getToken(const unsigned char *z, int *tokenType){
for(i=1; isdigit(z[i]); i++){}
return i;
}
case ':': {
for(i=1; IdChar(z[i]); i++){}
*tokenType = i>1 ? TK_VARIABLE : TK_ILLEGAL;
return i;
case '#': {
for(i=1; isdigit(z[i]); i++){}
if( i>1 ){
/* Parameters of the form #NNN (where NNN is a number) are used
** internally by sqlite3NestedParse. */
*tokenType = TK_REGISTER;
return i;
}
/* Fall through into the next case if the '#' is not followed by
** a digit. Try to match #AAAA where AAAA is a parameter name. */
}
#ifndef SQLITE_OMIT_TCL_VARIABLE
case '$': {
case '$':
#endif
case ':': {
int n = 0;
*tokenType = TK_VARIABLE;
if( z[1]=='{' ){
int nBrace = 1;
for(i=2; (c=z[i])!=0 && nBrace; i++){
if( c=='{' ){
nBrace++;
}else if( c=='}' ){
nBrace--;
}
}
if( c==0 ) *tokenType = TK_ILLEGAL;
}else{
int n = 0;
for(i=1; (c=z[i])!=0; i++){
if( isalnum(c) || c=='_' ){
n++;
}else if( c=='(' && n>0 ){
do{
i++;
}while( (c=z[i])!=0 && !isspace(c) && c!=')' );
if( c==')' ){
i++;
}else{
*tokenType = TK_ILLEGAL;
}
break;
}else if( c==':' && z[i+1]==':' ){
for(i=1; (c=z[i])!=0; i++){
if( IdChar(c) ){
n++;
#ifndef SQLITE_OMIT_TCL_VARIABLE
}else if( c=='(' && n>0 ){
do{
i++;
}while( (c=z[i])!=0 && !isspace(c) && c!=')' );
if( c==')' ){
i++;
}else{
break;
*tokenType = TK_ILLEGAL;
}
break;
}else if( c==':' && z[i+1]==':' ){
i++;
#endif
}else{
break;
}
if( n==0 ) *tokenType = TK_ILLEGAL;
}
if( n==0 ) *tokenType = TK_ILLEGAL;
return i;
}
#endif
#ifndef SQLITE_OMIT_BLOB_LITERAL
case 'x': case 'X': {
if( (c=z[1])=='\'' || c=='"' ){
@ -430,241 +431,3 @@ abort_parse:
}
return nErr;
}
/* The sqlite3_complete() API may be omitted (to save code space) by
** defining the following symbol.
*/
#ifndef SQLITE_OMIT_COMPLETE
/*
** Token types used by the sqlite3_complete() routine. See the header
** comments on that procedure for additional information.
*/
#define tkSEMI 0
#define tkWS 1
#define tkOTHER 2
#define tkEXPLAIN 3
#define tkCREATE 4
#define tkTEMP 5
#define tkTRIGGER 6
#define tkEND 7
/*
** Return TRUE if the given SQL string ends in a semicolon.
**
** Special handling is require for CREATE TRIGGER statements.
** Whenever the CREATE TRIGGER keywords are seen, the statement
** must end with ";END;".
**
** This implementation uses a state machine with 7 states:
**
** (0) START At the beginning or end of an SQL statement. This routine
** returns 1 if it ends in the START state and 0 if it ends
** in any other state.
**
** (1) NORMAL We are in the middle of statement which ends with a single
** semicolon.
**
** (2) EXPLAIN The keyword EXPLAIN has been seen at the beginning of
** a statement.
**
** (3) CREATE The keyword CREATE has been seen at the beginning of a
** statement, possibly preceeded by EXPLAIN and/or followed by
** TEMP or TEMPORARY
**
** (4) TRIGGER We are in the middle of a trigger definition that must be
** ended by a semicolon, the keyword END, and another semicolon.
**
** (5) SEMI We've seen the first semicolon in the ";END;" that occurs at
** the end of a trigger definition.
**
** (6) END We've seen the ";END" of the ";END;" that occurs at the end
** of a trigger difinition.
**
** Transitions between states above are determined by tokens extracted
** from the input. The following tokens are significant:
**
** (0) tkSEMI A semicolon.
** (1) tkWS Whitespace
** (2) tkOTHER Any other SQL token.
** (3) tkEXPLAIN The "explain" keyword.
** (4) tkCREATE The "create" keyword.
** (5) tkTEMP The "temp" or "temporary" keyword.
** (6) tkTRIGGER The "trigger" keyword.
** (7) tkEND The "end" keyword.
**
** Whitespace never causes a state transition and is always ignored.
**
** If we compile with SQLITE_OMIT_TRIGGER, all of the computation needed
** to recognize the end of a trigger can be omitted. All we have to do
** is look for a semicolon that is not part of an string or comment.
*/
int sqlite3_complete(const char *zSql){
u8 state = 0; /* Current state, using numbers defined in header comment */
u8 token; /* Value of the next token */
#ifndef SQLITE_OMIT_TRIGGER
/* A complex statement machine used to detect the end of a CREATE TRIGGER
** statement. This is the normal case.
*/
static const u8 trans[7][8] = {
/* Token: */
/* State: ** SEMI WS OTHER EXPLAIN CREATE TEMP TRIGGER END */
/* 0 START: */ { 0, 0, 1, 2, 3, 1, 1, 1, },
/* 1 NORMAL: */ { 0, 1, 1, 1, 1, 1, 1, 1, },
/* 2 EXPLAIN: */ { 0, 2, 1, 1, 3, 1, 1, 1, },
/* 3 CREATE: */ { 0, 3, 1, 1, 1, 3, 4, 1, },
/* 4 TRIGGER: */ { 5, 4, 4, 4, 4, 4, 4, 4, },
/* 5 SEMI: */ { 5, 5, 4, 4, 4, 4, 4, 6, },
/* 6 END: */ { 0, 6, 4, 4, 4, 4, 4, 4, },
};
#else
/* If triggers are not suppored by this compile then the statement machine
** used to detect the end of a statement is much simplier
*/
static const u8 trans[2][3] = {
/* Token: */
/* State: ** SEMI WS OTHER */
/* 0 START: */ { 0, 0, 1, },
/* 1 NORMAL: */ { 0, 1, 1, },
};
#endif /* SQLITE_OMIT_TRIGGER */
while( *zSql ){
switch( *zSql ){
case ';': { /* A semicolon */
token = tkSEMI;
break;
}
case ' ':
case '\r':
case '\t':
case '\n':
case '\f': { /* White space is ignored */
token = tkWS;
break;
}
case '/': { /* C-style comments */
if( zSql[1]!='*' ){
token = tkOTHER;
break;
}
zSql += 2;
while( zSql[0] && (zSql[0]!='*' || zSql[1]!='/') ){ zSql++; }
if( zSql[0]==0 ) return 0;
zSql++;
token = tkWS;
break;
}
case '-': { /* SQL-style comments from "--" to end of line */
if( zSql[1]!='-' ){
token = tkOTHER;
break;
}
while( *zSql && *zSql!='\n' ){ zSql++; }
if( *zSql==0 ) return state==0;
token = tkWS;
break;
}
case '[': { /* Microsoft-style identifiers in [...] */
zSql++;
while( *zSql && *zSql!=']' ){ zSql++; }
if( *zSql==0 ) return 0;
token = tkOTHER;
break;
}
case '"': /* single- and double-quoted strings */
case '\'': {
int c = *zSql;
zSql++;
while( *zSql && *zSql!=c ){ zSql++; }
if( *zSql==0 ) return 0;
token = tkOTHER;
break;
}
default: {
int c;
if( IdChar((u8)*zSql) ){
/* Keywords and unquoted identifiers */
int nId;
for(nId=1; IdChar(zSql[nId]); nId++){}
#ifdef SQLITE_OMIT_TRIGGER
token = tkOTHER;
#else
switch( *zSql ){
case 'c': case 'C': {
if( nId==6 && sqlite3StrNICmp(zSql, "create", 6)==0 ){
token = tkCREATE;
}else{
token = tkOTHER;
}
break;
}
case 't': case 'T': {
if( nId==7 && sqlite3StrNICmp(zSql, "trigger", 7)==0 ){
token = tkTRIGGER;
}else if( nId==4 && sqlite3StrNICmp(zSql, "temp", 4)==0 ){
token = tkTEMP;
}else if( nId==9 && sqlite3StrNICmp(zSql, "temporary", 9)==0 ){
token = tkTEMP;
}else{
token = tkOTHER;
}
break;
}
case 'e': case 'E': {
if( nId==3 && sqlite3StrNICmp(zSql, "end", 3)==0 ){
token = tkEND;
}else
#ifndef SQLITE_OMIT_EXPLAIN
if( nId==7 && sqlite3StrNICmp(zSql, "explain", 7)==0 ){
token = tkEXPLAIN;
}else
#endif
{
token = tkOTHER;
}
break;
}
default: {
token = tkOTHER;
break;
}
}
#endif /* SQLITE_OMIT_TRIGGER */
zSql += nId-1;
}else{
/* Operators and special symbols */
token = tkOTHER;
}
break;
}
}
state = trans[state][token];
zSql++;
}
return state==0;
}
#ifndef SQLITE_OMIT_UTF16
/*
** This routine is the same as the sqlite3_complete() routine described
** above, except that the parameter is required to be UTF-16 encoded, not
** UTF-8.
*/
int sqlite3_complete16(const void *zSql){
sqlite3_value *pVal;
char const *zSql8;
int rc = 0;
pVal = sqlite3ValueNew();
sqlite3ValueSetStr(pVal, -1, zSql, SQLITE_UTF16NATIVE, SQLITE_STATIC);
zSql8 = sqlite3ValueText(pVal, SQLITE_UTF8);
if( zSql8 ){
rc = sqlite3_complete(zSql8);
}
sqlite3ValueFree(pVal);
return rc;
}
#endif /* SQLITE_OMIT_UTF16 */
#endif /* SQLITE_OMIT_COMPLETE */

View file

@ -47,7 +47,11 @@ void sqlite3ColumnDefault(Vdbe *v, Table *pTab, int i){
u8 enc = sqlite3VdbeDb(v)->enc;
Column *pCol = &pTab->aCol[i];
sqlite3ValueFromExpr(pCol->pDflt, enc, pCol->affinity, &pValue);
sqlite3VdbeChangeP3(v, -1, (const char *)pValue, P3_MEM);
if( pValue ){
sqlite3VdbeChangeP3(v, -1, (const char *)pValue, P3_MEM);
}else{
VdbeComment((v, "# %s.%s", pTab->zName, pCol->zName));
}
}
}
@ -273,7 +277,7 @@ void sqlite3Update(
/* Remember the index of every item to be updated.
*/
sqlite3VdbeAddOp(v, OP_Rowid, iCur, 0);
sqlite3VdbeAddOp(v, OP_ListWrite, 0, 0);
sqlite3VdbeAddOp(v, OP_FifoWrite, 0, 0);
/* End the database scan loop.
*/
@ -295,8 +299,7 @@ void sqlite3Update(
/* The top of the update loop for when there are triggers.
*/
sqlite3VdbeAddOp(v, OP_ListRewind, 0, 0);
addr = sqlite3VdbeAddOp(v, OP_ListRead, 0, 0);
addr = sqlite3VdbeAddOp(v, OP_FifoRead, 0, 0);
if( !isView ){
sqlite3VdbeAddOp(v, OP_Dup, 0, 0);
@ -389,8 +392,7 @@ void sqlite3Update(
** So make the cursor point at the old record.
*/
if( !triggers_exist ){
sqlite3VdbeAddOp(v, OP_ListRewind, 0, 0);
addr = sqlite3VdbeAddOp(v, OP_ListRead, 0, 0);
addr = sqlite3VdbeAddOp(v, OP_FifoRead, 0, 0);
sqlite3VdbeAddOp(v, OP_Dup, 0, 0);
}
sqlite3VdbeAddOp(v, OP_NotExists, iCur, addr);
@ -468,7 +470,6 @@ void sqlite3Update(
*/
sqlite3VdbeAddOp(v, OP_Goto, 0, addr);
sqlite3VdbeChangeP2(v, addr, sqlite3VdbeCurrentAddr(v));
sqlite3VdbeAddOp(v, OP_ListReset, 0, 0);
/* Close all tables if there were no FOR EACH ROW triggers */
if( !triggers_exist ){

View file

@ -58,6 +58,8 @@ int sqlite3_malloc_failed = 0;
*/
int sqlite3_nMalloc; /* Number of sqliteMalloc() calls */
int sqlite3_nFree; /* Number of sqliteFree() calls */
int sqlite3_memUsed; /* Total memory obtained from malloc */
int sqlite3_memMax; /* Mem usage high-water mark */
int sqlite3_iMallocFail; /* Fail sqliteMalloc() after this many calls */
int sqlite3_iMallocReset = -1; /* When iMallocFail reaches 0, set to this */
#if SQLITE_MEMDEBUG>1
@ -72,13 +74,10 @@ static int memcnt = 0;
#define N_GUARD 2
/*
** Allocate new memory and set it to zero. Return NULL if
** no memory is available.
** Check for a simulated memory allocation failure. Return true if
** the failure should be simulated. Return false to proceed as normal.
*/
void *sqlite3Malloc_(int n, int bZero, char *zFile, int line){
void *p;
int *pi;
int i, k;
static int simulatedMallocFailure(int n, char *zFile, int line){
if( sqlite3_iMallocFail>=0 ){
sqlite3_iMallocFail--;
if( sqlite3_iMallocFail==0 ){
@ -88,10 +87,28 @@ void *sqlite3Malloc_(int n, int bZero, char *zFile, int line){
n, zFile,line);
#endif
sqlite3_iMallocFail = sqlite3_iMallocReset;
return 0;
return 1;
}
}
if( n==0 ) return 0;
return 0;
}
/*
** Allocate new memory and set it to zero. Return NULL if
** no memory is available.
*/
void *sqlite3Malloc_(int n, int bZero, char *zFile, int line){
void *p;
int *pi;
int i, k;
if( n==0 ){
return 0;
}
if( simulatedMallocFailure(n, zFile, line) ){
return 0;
}
sqlite3_memUsed += n;
if( sqlite3_memMax<sqlite3_memUsed ) sqlite3_memMax = sqlite3_memUsed;
k = (n+sizeof(int)-1)/sizeof(int);
pi = malloc( (N_GUARD*2+1+k)*sizeof(int));
if( pi==0 ){
@ -157,6 +174,7 @@ void sqlite3Free_(void *p, char *zFile, int line){
}
}
n = pi[N_GUARD];
sqlite3_memUsed -= n;
k = (n+sizeof(int)-1)/sizeof(int);
for(i=0; i<N_GUARD; i++){
if( pi[k+N_GUARD+1+i]!=0xdead3344 ){
@ -188,6 +206,9 @@ void *sqlite3Realloc_(void *oldP, int n, char *zFile, int line){
sqlite3Free_(oldP,zFile,line);
return 0;
}
if( simulatedMallocFailure(n, zFile, line) ){
return 0;
}
oldPi = oldP;
oldPi -= N_GUARD+1;
if( oldPi[0]!=0xdead1122 ){
@ -195,6 +216,7 @@ void *sqlite3Realloc_(void *oldP, int n, char *zFile, int line){
return 0;
}
oldN = oldPi[N_GUARD];
sqlite3_memUsed -= oldN;
oldK = (oldN+sizeof(int)-1)/sizeof(int);
for(i=0; i<N_GUARD; i++){
if( oldPi[oldK+N_GUARD+1+i]!=0xdead3344 ){
@ -211,6 +233,8 @@ void *sqlite3Realloc_(void *oldP, int n, char *zFile, int line){
}
for(i=0; i<N_GUARD; i++) pi[i] = 0xdead1122;
pi[N_GUARD] = n;
sqlite3_memUsed += n;
if( sqlite3_memMax<sqlite3_memUsed ) sqlite3_memMax = sqlite3_memUsed;
for(i=0; i<N_GUARD; i++) pi[k+N_GUARD+1+i] = 0xdead3344;
p = &pi[N_GUARD+1];
memcpy(p, oldP, n>oldN ? oldN : n);
@ -268,6 +292,7 @@ void sqlite3FreeX(void *p){
*/
void *sqlite3Malloc(int n){
void *p;
if( n==0 ) return 0;
if( (p = malloc(n))==0 ){
if( n>0 ) sqlite3_malloc_failed++;
}else{
@ -282,6 +307,7 @@ void *sqlite3Malloc(int n){
*/
void *sqlite3MallocRaw(int n){
void *p;
if( n==0 ) return 0;
if( (p = malloc(n))==0 ){
if( n>0 ) sqlite3_malloc_failed++;
}
@ -372,8 +398,8 @@ void sqlite3SetString(char **pz, ...){
zResult += strlen(zResult);
}
va_end(ap);
#ifdef SQLITE_DEBUG
#if SQLITE_DEBUG>1
#ifdef SQLITE_MEMDEBUG
#if SQLITE_MEMDEBUG>1
fprintf(stderr,"string at 0x%x is %s\n", (int)*pz, *pz);
#endif
#endif
@ -460,7 +486,8 @@ void sqlite3Dequote(char *z){
switch( quote ){
case '\'': break;
case '"': break;
case '[': quote = ']'; break;
case '`': break; /* For MySQL compatibility */
case '[': quote = ']'; break; /* For MS SqlServer compatibility */
default: return;
}
for(i=1, j=0; z[i]; i++){
@ -565,8 +592,9 @@ int sqlite3IsNumber(const char *z, int *realnum, u8 enc){
** of "." depending on how locale is set. But that would cause problems
** for SQL. So this routine always uses "." regardless of locale.
*/
double sqlite3AtoF(const char *z, const char **pzEnd){
int sqlite3AtoF(const char *z, double *pResult){
int sign = 1;
const char *zBegin = z;
LONGDOUBLE_TYPE v1 = 0.0;
if( *z=='-' ){
sign = -1;
@ -613,8 +641,8 @@ double sqlite3AtoF(const char *z, const char **pzEnd){
v1 *= scale;
}
}
if( pzEnd ) *pzEnd = z;
return sign<0 ? -v1 : v1;
*pResult = sign<0 ? -v1 : v1;
return z - zBegin;
}
/*
@ -720,7 +748,7 @@ int sqlite3SafetyOn(sqlite3 *db){
if( db->magic==SQLITE_MAGIC_OPEN ){
db->magic = SQLITE_MAGIC_BUSY;
return 0;
}else if( db->magic==SQLITE_MAGIC_BUSY || db->magic==SQLITE_MAGIC_ERROR ){
}else if( db->magic==SQLITE_MAGIC_BUSY ){
db->magic = SQLITE_MAGIC_ERROR;
db->flags |= SQLITE_Interrupt;
}
@ -736,7 +764,7 @@ int sqlite3SafetyOff(sqlite3 *db){
if( db->magic==SQLITE_MAGIC_BUSY ){
db->magic = SQLITE_MAGIC_OPEN;
return 0;
}else if( db->magic==SQLITE_MAGIC_OPEN || db->magic==SQLITE_MAGIC_ERROR ){
}else if( db->magic==SQLITE_MAGIC_OPEN ){
db->magic = SQLITE_MAGIC_ERROR;
db->flags |= SQLITE_Interrupt;
}

View file

@ -454,7 +454,6 @@ int sqlite3VdbeExec(
int rc = SQLITE_OK; /* Value to return */
sqlite3 *db = p->db; /* The database */
Mem *pTos; /* Top entry in the operand stack */
char zBuf[100]; /* Space to sprintf() an integer */
#ifdef VDBE_PROFILE
unsigned long long start; /* CPU clock count at start of opcode */
int origPc; /* Program counter at start of opcode */
@ -478,6 +477,7 @@ int sqlite3VdbeExec(
p->popStack = 0;
}
p->resOnStack = 0;
db->busyHandler.nBusy = 0;
CHECK_FOR_INTERRUPT;
for(pc=p->pc; rc==SQLITE_OK; pc++){
assert( pc>=0 && pc<p->nOp );
@ -633,7 +633,7 @@ case OP_Return: { /* no-push */
break;
}
/* Opcode: Halt P1 P2 *
/* Opcode: Halt P1 P2 P3
**
** Exit immediately. All open cursors, Lists, Sorts, etc are closed
** automatically.
@ -646,6 +646,8 @@ case OP_Return: { /* no-push */
** then back out all changes that have occurred during this execution of the
** VDBE, but do not rollback the transaction.
**
** If P3 is not null then it is an error message string.
**
** There is an implied "Halt 0 0 0" instruction inserted at the very end of
** every program. So a jump past the last instruction of the program
** is the same as executing Halt.
@ -667,28 +669,31 @@ case OP_Halt: { /* no-push */
return p->rc ? SQLITE_ERROR : SQLITE_DONE;
}
/* Opcode: Integer P1 * P3
/* Opcode: Integer P1 * *
**
** The integer value P1 is pushed onto the stack. If P3 is not zero
** then it is assumed to be a string representation of the same integer.
** If P1 is zero and P3 is not zero, then the value is derived from P3.
**
** If the value cannot be represented as a 32-bits then its value
** will be in P3.
** The 32-bit integer value P1 is pushed onto the stack.
*/
case OP_Integer: {
pTos++;
if( pOp->p3==0 ){
pTos->flags = MEM_Int;
pTos->i = pOp->p1;
}else{
pTos->flags = MEM_Str|MEM_Static|MEM_Term;
pTos->z = pOp->p3;
pTos->n = strlen(pTos->z);
pTos->enc = SQLITE_UTF8;
pTos->i = sqlite3VdbeIntValue(pTos);
pTos->flags |= MEM_Int;
}
pTos->flags = MEM_Int;
pTos->i = pOp->p1;
break;
}
/* Opcode: Int64 * * P3
**
** P3 is a string representation of an integer. Convert that integer
** to a 64-bit value and push it onto the stack.
*/
case OP_Int64: {
pTos++;
assert( pOp->p3!=0 );
pTos->flags = MEM_Str|MEM_Static|MEM_Term;
pTos->z = pOp->p3;
pTos->n = strlen(pTos->z);
pTos->enc = SQLITE_UTF8;
pTos->i = sqlite3VdbeIntValue(pTos);
pTos->flags |= MEM_Int;
break;
}
@ -1000,7 +1005,7 @@ case OP_Concat: { /* same as TK_CONCAT */
pTerm = &pTos[1-nField];
for(i=j=0; i<nField; i++, pTerm++){
int n = pTerm->n;
assert( pTerm->flags & MEM_Str );
assert( pTerm->flags & (MEM_Str|MEM_Blob) );
memcpy(&zNew[j], pTerm->z, n);
j += n;
}
@ -1377,6 +1382,94 @@ case OP_MustBeInt: { /* no-push */
break;
}
#ifndef SQLITE_OMIT_CAST
/* Opcode: ToInt * * *
**
** Force the value on the top of the stack to be an integer. If
** The value is currently a real number, drop its fractional part.
** If the value is text or blob, try to convert it to an integer using the
** equivalent of atoi() and store 0 if no such conversion is possible.
**
** A NULL value is not changed by this routine. It remains NULL.
*/
case OP_ToInt: { /* no-push */
assert( pTos>=p->aStack );
if( pTos->flags & MEM_Null ) break;
assert( MEM_Str==(MEM_Blob>>3) );
pTos->flags |= (pTos->flags&MEM_Blob)>>3;
applyAffinity(pTos, SQLITE_AFF_INTEGER, db->enc);
sqlite3VdbeMemIntegerify(pTos);
break;
}
/* Opcode: ToNumeric * * *
**
** Force the value on the top of the stack to be numeric (either an
** integer or a floating-point number.
** If the value is text or blob, try to convert it to an using the
** equivalent of atoi() or atof() and store 0 if no such conversion
** is possible.
**
** A NULL value is not changed by this routine. It remains NULL.
*/
case OP_ToNumeric: { /* no-push */
assert( pTos>=p->aStack );
if( pTos->flags & MEM_Null ) break;
assert( MEM_Str==(MEM_Blob>>3) );
pTos->flags |= (pTos->flags&MEM_Blob)>>3;
applyAffinity(pTos, SQLITE_AFF_NUMERIC, db->enc);
if( (pTos->flags & (MEM_Int|MEM_Real))==0 ){
sqlite3VdbeMemRealify(pTos);
}else{
sqlite3VdbeMemRelease(pTos);
}
assert( (pTos->flags & MEM_Dyn)==0 );
pTos->flags &= (MEM_Int|MEM_Real);
break;
}
/* Opcode: ToText * * *
**
** Force the value on the top of the stack to be text.
** If the value is numeric, convert it to an using the
** equivalent of printf(). Blob values are unchanged and
** are afterwards simply interpreted as text.
**
** A NULL value is not changed by this routine. It remains NULL.
*/
case OP_ToText: { /* no-push */
assert( pTos>=p->aStack );
if( pTos->flags & MEM_Null ) break;
assert( MEM_Str==(MEM_Blob>>3) );
pTos->flags |= (pTos->flags&MEM_Blob)>>3;
applyAffinity(pTos, SQLITE_AFF_TEXT, db->enc);
assert( pTos->flags & MEM_Str );
pTos->flags &= ~(MEM_Int|MEM_Real|MEM_Blob);
break;
}
/* Opcode: ToBlob * * *
**
** Force the value on the top of the stack to be a BLOB.
** If the value is numeric, convert it to a string first.
** Strings are simply reinterpreted as blobs with no change
** to the underlying data.
**
** A NULL value is not changed by this routine. It remains NULL.
*/
case OP_ToBlob: { /* no-push */
assert( pTos>=p->aStack );
if( pTos->flags & MEM_Null ) break;
if( (pTos->flags & MEM_Blob)==0 ){
applyAffinity(pTos, SQLITE_AFF_TEXT, db->enc);
assert( pTos->flags & MEM_Str );
pTos->flags |= MEM_Blob;
}
pTos->flags &= ~(MEM_Int|MEM_Real|MEM_Str);
break;
}
#endif /* SQLITE_OMIT_CAST */
/* Opcode: Eq P1 P2 P3
**
** Pop the top two elements from the stack. If they are equal, then
@ -1737,6 +1830,13 @@ case OP_SetNumColumns: { /* no-push */
** just a pointer into the record which is stored further down on the
** stack. The column value is not copied. The number of columns in the
** record is stored on the stack just above the record itself.
**
** If the column contains fewer than P2 fields, then push a NULL. Or
** if P3 is of type P3_MEM, then push the P3 value. The P3 value will
** be default value for a column that has been added using the ALTER TABLE
** ADD COLUMN command. If P3 is an ordinary string, just push a NULL.
** When P3 is a string it is really just a comment describing the value
** to be pushed, not a default value.
*/
case OP_Column: {
u32 payloadSize; /* Number of bytes in the record */
@ -1937,7 +2037,8 @@ case OP_Column: {
/* Get the column information. If aOffset[p2] is non-zero, then
** deserialize the value from the record. If aOffset[p2] is zero,
** then there are not enough fields in the record to satisfy the
** request. The value is NULL in this case.
** request. In this case, set the value NULL or to P3 if P3 is
** a pointer to a Mem object.
*/
if( aOffset[p2] ){
assert( rc==SQLITE_OK );
@ -1954,7 +2055,7 @@ case OP_Column: {
sqlite3VdbeSerialGet(zData, aType[p2], pTos);
pTos->enc = db->enc;
}else{
if( pOp->p3 ){
if( pOp->p3type==P3_MEM ){
sqlite3VdbeMemShallowCopy(pTos, (Mem *)(pOp->p3), MEM_Static);
}else{
pTos->flags = MEM_Null;
@ -2000,12 +2101,9 @@ op_column_out:
** The original stack entries are popped from the stack if P1>0 but
** remain on the stack if P1<0.
**
** The P2 argument is divided into two 16-bit words before it is processed.
** If the hi-word is non-zero, then an extra integer is read from the stack
** and appended to the record as a varint. If the low-word of P2 is not
** zero and one or more of the entries are NULL, then jump to the value of
** the low-word of P2. This feature can be used to skip a uniqueness test
** on indices.
** If P2 is not zero and one or more of the entries are NULL, then jump
** to the address given by P2. This feature can be used to skip a
** uniqueness test on indices.
**
** P3 may be a string that is P1 characters long. The nth character of the
** string indicates the column affinity that should be used for the nth
@ -2019,7 +2117,17 @@ op_column_out:
** 'o' = NONE.
**
** If P3 is NULL then all index fields have the affinity NONE.
**
** See also OP_MakeIdxRec
*/
/* Opcode: MakeRecordI P1 P2 P3
**
** This opcode works just OP_MakeRecord except that it reads an extra
** integer from the stack (thus reading a total of abs(P1+1) entries)
** and appends that extra integer to the end of the record as a varint.
** This results in an index key.
*/
case OP_MakeIdxRec:
case OP_MakeRecord: {
/* Assuming the record contains N fields, the record format looks
** like this:
@ -2057,8 +2165,8 @@ case OP_MakeRecord: {
leaveOnStack = ((pOp->p1<0)?1:0);
nField = pOp->p1 * (leaveOnStack?-1:1);
jumpIfNull = (pOp->p2 & 0x00FFFFFF);
addRowid = ((pOp->p2>>24) & 0x0000FFFF)?1:0;
jumpIfNull = pOp->p2;
addRowid = pOp->opcode==OP_MakeIdxRec;
zAffinity = pOp->p3;
pData0 = &pTos[1-nField];
@ -2145,6 +2253,7 @@ case OP_MakeRecord: {
pTos->flags = MEM_Blob | MEM_Dyn;
pTos->xDel = 0;
}
pTos->enc = SQLITE_UTF8; /* In case the blob is ever converted to text */
/* If a NULL was encountered and jumpIfNull is non-zero, take the jump. */
if( jumpIfNull && containsNull ){
@ -2429,11 +2538,7 @@ case OP_OpenWrite: { /* no-push */
p2 = pTos->i;
assert( (pTos->flags & MEM_Dyn)==0 );
pTos--;
if( p2<2 ){
sqlite3SetString(&p->zErrMsg, "root page number less than 2", (char*)0);
rc = SQLITE_INTERNAL;
break;
}
assert( p2>=2 );
}
assert( i>=0 );
pCur = allocateCursor(p, i);
@ -2498,25 +2603,18 @@ case OP_OpenWrite: { /* no-push */
break;
}
/* Opcode: OpenTemp P1 * P3
/* Opcode: OpenVirtual P1 * P3
**
** Open a new cursor to a transient table.
** The transient cursor is always opened read/write even if
** the main database is read-only. The transient table is deleted
** automatically when the cursor is closed.
** Open a new cursor to a transient or virtual table.
** The cursor is always opened read/write even if
** the main database is read-only. The transient or virtual
** table is deleted automatically when the cursor is closed.
**
** The cursor points to a BTree table if P3==0 and to a BTree index
** if P3 is not 0. If P3 is not NULL, it points to a KeyInfo structure
** that defines the format of keys in the index.
**
** This opcode is used for tables that exist for the duration of a single
** SQL statement only. Tables created using CREATE TEMPORARY TABLE
** are opened using OP_OpenRead or OP_OpenWrite. "Temporary" in the
** context of this opcode means for the duration of a single SQL statement
** whereas "Temporary" in the context of CREATE TABLE means for the duration
** of the connection to the database. Same word; different meanings.
*/
case OP_OpenTemp: { /* no-push */
case OP_OpenVirtual: { /* no-push */
int i = pOp->p1;
Cursor *pCx;
assert( i>=0 );
@ -3280,6 +3378,7 @@ case OP_RowData: {
}else{
pTos->flags = MEM_Null;
}
pTos->enc = SQLITE_UTF8; /* In case the blob is ever cast to text */
break;
}
@ -3444,17 +3543,12 @@ case OP_Next: { /* no-push */
break;
}
/* Opcode: IdxInsert P1 P2 P3
/* Opcode: IdxInsert P1 * *
**
** The top of the stack holds a SQL index key made using the
** MakeIdxKey instruction. This opcode writes that key into the
** index P1. Data for the entry is nil.
**
** If P2==1, then the key must be unique. If the key is not unique,
** the program aborts with a SQLITE_CONSTRAINT error and the database
** is rolled back. If P3 is not null, then it becomes part of the
** error message returned with the SQLITE_CONSTRAINT.
**
** This instruction only works for indices. The equivalent instruction
** for tables is OP_Insert.
*/
@ -3466,35 +3560,10 @@ 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;
if( pOp->p2 ){
int res;
int len;
/* 'len' is the length of the key minus the rowid at the end */
len = nKey - sqlite3VdbeIdxRowidLen(nKey, zKey);
rc = sqlite3BtreeMoveto(pCrsr, zKey, len, &res);
if( rc!=SQLITE_OK ) goto abort_due_to_error;
while( res!=0 && !sqlite3BtreeEof(pCrsr) ){
int c;
if( sqlite3VdbeIdxKeyCompare(pC, len, zKey, &c)==SQLITE_OK && c==0 ){
rc = SQLITE_CONSTRAINT;
if( pOp->p3 && pOp->p3[0] ){
sqlite3SetString(&p->zErrMsg, pOp->p3, (char*)0);
}
goto abort_due_to_error;
}
if( res<0 ){
sqlite3BtreeNext(pCrsr, &res);
res = +1;
}else{
break;
}
}
}
assert( pC->isTable==0 );
rc = sqlite3BtreeInsert(pCrsr, zKey, nKey, "", 0);
assert( pC->deferredMoveto==0 );
@ -3815,6 +3884,21 @@ case OP_ParseSchema: { /* no-push */
break;
}
#ifndef SQLITE_OMIT_ANALYZE
/* Opcode: LoadAnalysis P1 * *
**
** Read the sqlite_stat1 table for database P1 and load the content
** of that table into the internal index hash table. This will cause
** the analysis to be used when preparing all subsequent queries.
*/
case OP_LoadAnalysis: { /* no-push */
int iDb = pOp->p1;
assert( iDb>=0 && iDb<db->nDb );
sqlite3AnalysisLoad(db, iDb);
break;
}
#endif /* SQLITE_OMIT_ANALYZE */
/* Opcode: DropTable P1 * P3
**
** Remove the internal (in-memory) data structures that describe
@ -3906,86 +3990,35 @@ case OP_IntegrityCk: {
}
#endif /* SQLITE_OMIT_INTEGRITY_CHECK */
/* Opcode: ListWrite * * *
/* Opcode: FifoWrite * * *
**
** Write the integer on the top of the stack
** into the temporary storage list.
** into the Fifo.
*/
case OP_ListWrite: { /* no-push */
Keylist *pKeylist;
case OP_FifoWrite: { /* no-push */
assert( pTos>=p->aStack );
pKeylist = p->pList;
if( pKeylist==0 || pKeylist->nUsed>=pKeylist->nKey ){
pKeylist = sqliteMallocRaw( sizeof(Keylist)+999*sizeof(pKeylist->aKey[0]) );
if( pKeylist==0 ) goto no_mem;
pKeylist->nKey = 1000;
pKeylist->nRead = 0;
pKeylist->nUsed = 0;
pKeylist->pNext = p->pList;
p->pList = pKeylist;
}
Integerify(pTos);
pKeylist->aKey[pKeylist->nUsed++] = pTos->i;
sqlite3VdbeFifoPush(&p->sFifo, pTos->i);
assert( (pTos->flags & MEM_Dyn)==0 );
pTos--;
break;
}
/* Opcode: ListRewind * * *
/* Opcode: FifoRead * P2 *
**
** Rewind the temporary buffer back to the beginning.
*/
case OP_ListRewind: { /* no-push */
/* What this opcode codes, really, is reverse the order of the
** linked list of Keylist structures so that they are read out
** in the same order that they were read in. */
Keylist *pRev, *pTop;
pRev = 0;
while( p->pList ){
pTop = p->pList;
p->pList = pTop->pNext;
pTop->pNext = pRev;
pRev = pTop;
}
p->pList = pRev;
break;
}
/* Opcode: ListRead * P2 *
**
** Attempt to read an integer from the temporary storage buffer
** and push it onto the stack. If the storage buffer is empty,
** Attempt to read a single integer from the Fifo
** and push it onto the stack. If the Fifo is empty
** push nothing but instead jump to P2.
*/
case OP_ListRead: {
Keylist *pKeylist;
case OP_FifoRead: {
i64 v;
CHECK_FOR_INTERRUPT;
pKeylist = p->pList;
if( pKeylist!=0 ){
assert( pKeylist->nRead>=0 );
assert( pKeylist->nRead<pKeylist->nUsed );
assert( pKeylist->nRead<pKeylist->nKey );
pTos++;
pTos->i = pKeylist->aKey[pKeylist->nRead++];
pTos->flags = MEM_Int;
if( pKeylist->nRead>=pKeylist->nUsed ){
p->pList = pKeylist->pNext;
sqliteFree(pKeylist);
}
}else{
if( sqlite3VdbeFifoPop(&p->sFifo, &v)==SQLITE_DONE ){
pc = pOp->p2 - 1;
}
break;
}
/* Opcode: ListReset * * *
**
** Reset the temporary storage buffer so that it holds nothing.
*/
case OP_ListReset: { /* no-push */
if( p->pList ){
sqlite3VdbeKeylistFree(p->pList);
p->pList = 0;
}else{
pTos++;
pTos->i = v;
pTos->flags = MEM_Int;
}
break;
}
@ -4036,8 +4069,8 @@ case OP_ContextPush: { /* no-push */
pContext = &p->contextStack[i];
pContext->lastRowid = db->lastRowid;
pContext->nChange = p->nChange;
pContext->pList = p->pList;
p->pList = 0;
pContext->sFifo = p->sFifo;
sqlite3VdbeFifoInit(&p->sFifo);
break;
}
@ -4052,8 +4085,8 @@ case OP_ContextPop: { /* no-push */
assert( p->contextStackTop>=0 );
db->lastRowid = pContext->lastRowid;
p->nChange = pContext->nChange;
sqlite3VdbeKeylistFree(p->pList);
p->pList = pContext->pList;
sqlite3VdbeFifoClear(&p->sFifo);
p->sFifo = pContext->sFifo;
break;
}
#endif /* #ifndef SQLITE_OMIT_TRIGGER */
@ -4567,9 +4600,7 @@ case OP_Expire: { /* no-push */
/* An other opcode is illegal...
*/
default: {
sqlite3_snprintf(sizeof(zBuf),zBuf,"%d",pOp->opcode);
sqlite3SetString(&p->zErrMsg, "unknown opcode ", zBuf, (char*)0);
rc = SQLITE_INTERNAL;
assert( 0 );
break;
}
@ -4606,10 +4637,7 @@ default: {
if( pTos>=p->aStack ){
sqlite3VdbeMemSanity(pTos, db->enc);
}
if( pc<-1 || pc>=p->nOp ){
sqlite3SetString(&p->zErrMsg, "jump destination out of range", (char*)0);
rc = SQLITE_INTERNAL;
}
assert( pc>=-1 && pc<p->nOp );
#ifdef SQLITE_DEBUG
/* Code for tracing the vdbe stack. */
if( p->trace && pTos>=p->aStack ){

View file

@ -105,8 +105,6 @@ int sqlite3VdbeAddOpList(Vdbe*, int nOp, VdbeOpList const *aOp);
void sqlite3VdbeChangeP1(Vdbe*, int addr, int P1);
void sqlite3VdbeChangeP2(Vdbe*, int addr, int P2);
void sqlite3VdbeChangeP3(Vdbe*, int addr, const char *zP1, int N);
void sqlite3VdbeDequoteP3(Vdbe*, int addr);
int sqlite3VdbeFindOp(Vdbe*, int, int, int);
VdbeOp *sqlite3VdbeGetOp(Vdbe*, int);
int sqlite3VdbeMakeLabel(Vdbe*);
void sqlite3VdbeDelete(Vdbe*);

View file

@ -260,17 +260,29 @@ struct Set {
};
/*
** A Keylist is a bunch of keys into a table. The keylist can
** grow without bound. The keylist stores the ROWIDs of database
** records that need to be deleted or updated.
** A FifoPage structure holds a single page of valves. Pages are arranged
** in a list.
*/
typedef struct Keylist Keylist;
struct Keylist {
int nKey; /* Number of slots in aKey[] */
int nUsed; /* Next unwritten slot in aKey[] */
int nRead; /* Next unread slot in aKey[] */
Keylist *pNext; /* Next block of keys */
i64 aKey[1]; /* One or more keys. Extra space allocated as needed */
typedef struct FifoPage FifoPage;
struct FifoPage {
int nSlot; /* Number of entries aSlot[] */
int iWrite; /* Push the next value into this entry in aSlot[] */
int iRead; /* Read the next value from this entry in aSlot[] */
FifoPage *pNext; /* Next page in the fifo */
i64 aSlot[1]; /* One or more slots for rowid values */
};
/*
** The Fifo structure is typedef-ed in vdbeInt.h. But the implementation
** of that structure is private to this file.
**
** The Fifo structure describes the entire fifo.
*/
typedef struct Fifo Fifo;
struct Fifo {
int nEntry; /* Total number of entries */
FifoPage *pFirst; /* First page on the list */
FifoPage *pLast; /* Last page on the list */
};
/*
@ -286,7 +298,7 @@ typedef struct Context Context;
struct Context {
int lastRowid; /* Last insert rowid (sqlite3.lastRowid) */
int nChange; /* Statement changes (Vdbe.nChanges) */
Keylist *pList; /* Records that will participate in a DELETE or UPDATE */
Fifo sFifo; /* Records that will participate in a DELETE or UPDATE */
};
/*
@ -325,7 +337,7 @@ struct Vdbe {
Agg *apAgg; /* Array of aggregate contexts */
Agg *pAgg; /* Current aggregate context */
int nCallback; /* Number of callbacks invoked so far */
Keylist *pList; /* A list of ROWIDs */
Fifo sFifo; /* A list of ROWIDs */
int contextStackTop; /* Index of top element in the context stack */
int contextStackDepth; /* The size of the "context" stack */
Context *contextStack; /* Stack used by opcodes ContextPush & ContextPop*/
@ -362,7 +374,6 @@ struct Vdbe {
void sqlite3VdbeFreeCursor(Cursor*);
void sqlite3VdbeSorterReset(Vdbe*);
int sqlite3VdbeAggReset(sqlite3*, Agg *, KeyInfo *);
void sqlite3VdbeKeylistFree(Keylist*);
void sqliteVdbePopStack(Vdbe*,int);
int sqlite3VdbeCursorMoveto(Cursor*);
#if defined(SQLITE_DEBUG) || defined(VDBE_PROFILE)
@ -411,3 +422,7 @@ int sqlite3VdbeOpcodeNoPush(u8);
int sqlite3VdbeMemTranslate(Mem*, u8);
void sqlite3VdbeMemPrettyPrint(Mem *pMem, char *zBuf, int nBuf);
int sqlite3VdbeMemHandleBom(Mem *pMem);
void sqlite3VdbeFifoInit(Fifo*);
int sqlite3VdbeFifoPush(Fifo*, i64);
int sqlite3VdbeFifoPop(Fifo*, i64*);
void sqlite3VdbeFifoClear(Fifo*);

View file

@ -84,7 +84,7 @@ void sqlite3_result_blob(
int n,
void (*xDel)(void *)
){
assert( n>0 );
assert( n>=0 );
sqlite3VdbeMemSetStr(&pCtx->s, z, n, 0, xDel);
}
void sqlite3_result_double(sqlite3_context *pCtx, double rVal){
@ -213,7 +213,7 @@ int sqlite3_step(sqlite3_stmt *pStmt){
rc = SQLITE_MISUSE;
}
sqlite3Error(p->db, rc, p->zErrMsg);
sqlite3Error(p->db, rc, p->zErrMsg ? "%s" : 0, p->zErrMsg);
return rc;
}
@ -230,10 +230,6 @@ void *sqlite3_user_data(sqlite3_context *p){
** Allocate or return the aggregate context for a user function. A new
** context is allocated on the first call. Subsequent calls return the
** same context that was returned on prior calls.
**
** This routine is defined here in vdbe.c because it depends on knowing
** the internals of the sqlite3_context structure which is only defined in
** this source file.
*/
void *sqlite3_aggregate_context(sqlite3_context *p, int nByte){
assert( p && p->pFunc && p->pFunc->xStep );
@ -369,6 +365,11 @@ sqlite_int64 sqlite3_column_int64(sqlite3_stmt *pStmt, int i){
const unsigned char *sqlite3_column_text(sqlite3_stmt *pStmt, int i){
return sqlite3_value_text( columnMem(pStmt,i) );
}
#if 0
sqlite3_value *sqlite3_column_value(sqlite3_stmt *pStmt, int i){
return columnMem(pStmt, i);
}
#endif
#ifndef SQLITE_OMIT_UTF16
const void *sqlite3_column_text16(sqlite3_stmt *pStmt, int i){
return sqlite3_value_text16( columnMem(pStmt,i) );

View file

@ -25,7 +25,7 @@
** set the sqlite3_vdbe_addop_trace to 1 and all opcodes will be printed
** as they are added to the instruction stream.
*/
#ifndef NDEBUG
#ifdef SQLITE_DEBUG
int sqlite3_vdbe_addop_trace = 0;
#endif
@ -109,6 +109,7 @@ int sqlite3VdbeAddOp(Vdbe *p, int op, int p1, int p2){
pOp->p2 = p2;
pOp->p3 = 0;
pOp->p3type = P3_NOTUSED;
p->expired = 0;
#ifdef SQLITE_DEBUG
if( sqlite3_vdbe_addop_trace ) sqlite3VdbePrintOp(0, i, &p->aOp[i]);
#endif
@ -442,47 +443,6 @@ void sqlite3VdbeComment(Vdbe *p, const char *zFormat, ...){
}
#endif
/*
** If the P3 operand to the specified instruction appears
** to be a quoted string token, then this procedure removes
** the quotes.
**
** The quoting operator can be either a grave ascent (ASCII 0x27)
** or a double quote character (ASCII 0x22). Two quotes in a row
** resolve to be a single actual quote character within the string.
*/
void sqlite3VdbeDequoteP3(Vdbe *p, int addr){
Op *pOp;
assert( p->magic==VDBE_MAGIC_INIT );
if( p->aOp==0 ) return;
if( addr<0 || addr>=p->nOp ){
addr = p->nOp - 1;
if( addr<0 ) return;
}
pOp = &p->aOp[addr];
if( pOp->p3==0 || pOp->p3[0]==0 ) return;
if( pOp->p3type==P3_STATIC ){
pOp->p3 = sqliteStrDup(pOp->p3);
pOp->p3type = P3_DYNAMIC;
}
assert( pOp->p3type==P3_DYNAMIC );
sqlite3Dequote(pOp->p3);
}
/*
** Search the current program starting at instruction addr for the given
** opcode and P2 value. Return the address plus 1 if found and 0 if not
** found.
*/
int sqlite3VdbeFindOp(Vdbe *p, int addr, int op, int p2){
int i;
assert( p->magic==VDBE_MAGIC_INIT );
for(i=addr; i<p->nOp; i++){
if( p->aOp[i].opcode==op && p->aOp[i].p2==p2 ) return i+1;
}
return 0;
}
/*
** Return the opcode for a given address.
*/
@ -952,18 +912,6 @@ int sqlite3VdbeAggReset(sqlite3 *db, Agg *pAgg, KeyInfo *pKeyInfo){
return SQLITE_OK;
}
/*
** Delete a keylist
*/
void sqlite3VdbeKeylistFree(Keylist *p){
while( p ){
Keylist *pNext = p->pNext;
sqliteFree(p);
p = pNext;
}
}
/*
** Close a cursor and release all the resources that cursor happens
** to hold.
@ -1010,13 +958,10 @@ static void Cleanup(Vdbe *p){
}
closeAllCursors(p);
releaseMemArray(p->aMem, p->nMem);
if( p->pList ){
sqlite3VdbeKeylistFree(p->pList);
p->pList = 0;
}
sqlite3VdbeFifoClear(&p->sFifo);
if( p->contextStack ){
for(i=0; i<p->contextStackTop; i++){
sqlite3VdbeKeylistFree(p->contextStack[i].pList);
sqlite3VdbeFifoClear(&p->contextStack[i].sFifo);
}
sqliteFree(p->contextStack);
}
@ -1145,6 +1090,7 @@ static int vdbeCommit(sqlite3 *db){
*/
#ifndef SQLITE_OMIT_DISKIO
else{
int needSync = 0;
char *zMaster = 0; /* File-name for the master journal */
char const *zMainFile = sqlite3BtreeGetFilename(db->aDb[0].pBt);
OsFile master;
@ -1180,6 +1126,9 @@ static int vdbeCommit(sqlite3 *db){
if( pBt && sqlite3BtreeIsInTrans(pBt) ){
char const *zFile = sqlite3BtreeGetJournalname(pBt);
if( zFile[0]==0 ) continue; /* Ignore :memory: databases */
if( !needSync && !sqlite3BtreeSyncDisabled(pBt) ){
needSync = 1;
}
rc = sqlite3OsWrite(&master, zFile, strlen(zFile)+1);
if( rc!=SQLITE_OK ){
sqlite3OsClose(&master);
@ -1196,7 +1145,7 @@ static int vdbeCommit(sqlite3 *db){
*/
zMainFile = sqlite3BtreeGetDirname(db->aDb[0].pBt);
rc = sqlite3OsOpenDirectory(zMainFile, &master);
if( rc!=SQLITE_OK || (rc = sqlite3OsSync(&master))!=SQLITE_OK ){
if( rc!=SQLITE_OK || (needSync && (rc=sqlite3OsSync(&master))!=SQLITE_OK) ){
sqlite3OsClose(&master);
sqlite3OsDelete(zMaster);
sqliteFree(zMaster);
@ -1763,7 +1712,7 @@ int sqlite3VdbeSerialGet(
pMem->flags = MEM_Int;
return 6;
}
case 6: /* 6-byte signed integer */
case 6: /* 8-byte signed integer */
case 7: { /* IEEE floating point */
u64 x = (buf[0]<<24) | (buf[1]<<16) | (buf[2]<<8) | buf[3];
u32 y = (buf[4]<<24) | (buf[5]<<16) | (buf[6]<<8) | buf[7];

View file

@ -0,0 +1,114 @@
/*
** 2005 June 16
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
**
** May you do good and not evil.
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
*************************************************************************
** This file implements a FIFO queue of rowids used for processing
** UPDATE and DELETE statements.
*/
#include "sqliteInt.h"
#include "vdbeInt.h"
/*
** 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){
FifoPage *pPage;
if( nEntry>32767 ){
nEntry = 32767;
}
pPage = sqliteMallocRaw( sizeof(FifoPage) + sizeof(i64)*(nEntry-1) );
if( pPage ){
pPage->nSlot = nEntry;
pPage->iWrite = 0;
pPage->iRead = 0;
pPage->pNext = 0;
}
return pPage;
}
/*
** Initialize a Fifo structure.
*/
void sqlite3VdbeFifoInit(Fifo *pFifo){
memset(pFifo, 0, sizeof(*pFifo));
}
/*
** Push a single 64-bit integer value into the Fifo. Return SQLITE_OK
** normally. SQLITE_NOMEM is returned if we are unable to allocate
** memory.
*/
int sqlite3VdbeFifoPush(Fifo *pFifo, i64 val){
FifoPage *pPage;
pPage = pFifo->pLast;
if( pPage==0 ){
pPage = pFifo->pLast = pFifo->pFirst = allocatePage(20);
if( pPage==0 ){
return SQLITE_NOMEM;
}
}else if( pPage->iWrite>=pPage->nSlot ){
pPage->pNext = allocatePage(pFifo->nEntry);
if( pPage->pNext==0 ){
return SQLITE_NOMEM;
}
pPage = pFifo->pLast = pPage->pNext;
}
pPage->aSlot[pPage->iWrite++] = val;
pFifo->nEntry++;
return SQLITE_OK;
}
/*
** Extract a single 64-bit integer value from the Fifo. The integer
** extracted is the one least recently inserted. If the Fifo is empty
** return SQLITE_DONE.
*/
int sqlite3VdbeFifoPop(Fifo *pFifo, i64 *pVal){
FifoPage *pPage;
if( pFifo->nEntry==0 ){
return SQLITE_DONE;
}
assert( pFifo->nEntry>0 );
pPage = pFifo->pFirst;
assert( pPage!=0 );
assert( pPage->iWrite>pPage->iRead );
assert( pPage->iWrite<=pPage->nSlot );
assert( pPage->iRead<pPage->nSlot );
assert( pPage->iRead>=0 );
*pVal = pPage->aSlot[pPage->iRead++];
pFifo->nEntry--;
if( pPage->iRead>=pPage->iWrite ){
pFifo->pFirst = pPage->pNext;
sqliteFree(pPage);
if( pFifo->nEntry==0 ){
assert( pFifo->pLast==pPage );
pFifo->pLast = 0;
}else{
assert( pFifo->pFirst!=0 );
}
}else{
assert( pFifo->nEntry>0 );
}
return SQLITE_OK;
}
/*
** Delete all information from a Fifo object. Free all memory held
** by the Fifo.
*/
void sqlite3VdbeFifoClear(Fifo *pFifo){
FifoPage *pPage, *pNextPage;
for(pPage=pFifo->pFirst; pPage; pPage=pNextPage){
pNextPage = pPage->pNext;
sqliteFree(pPage);
}
sqlite3VdbeFifoInit(pFifo);
}

View file

@ -174,7 +174,7 @@ int sqlite3VdbeMemStringify(Mem *pMem, int enc){
** FIX ME: It would be better if sqlite3_snprintf() could do UTF-16.
*/
if( fg & MEM_Real ){
sqlite3_snprintf(NBFS, z, "%.15g", pMem->r);
sqlite3_snprintf(NBFS, z, "%!.15g", pMem->r);
}else{
assert( fg & MEM_Int );
sqlite3_snprintf(NBFS, z, "%lld", pMem->i);
@ -256,12 +256,14 @@ double sqlite3VdbeRealValue(Mem *pMem){
}else if( pMem->flags & MEM_Int ){
return (double)pMem->i;
}else if( pMem->flags & (MEM_Str|MEM_Blob) ){
double val = 0.0;
if( sqlite3VdbeChangeEncoding(pMem, SQLITE_UTF8)
|| sqlite3VdbeMemNulTerminate(pMem) ){
return SQLITE_NOMEM;
}
assert( pMem->z );
return sqlite3AtoF(pMem->z, 0);
sqlite3AtoF(pMem->z, &val);
return val;
}else{
return 0.0;
}
@ -406,6 +408,7 @@ int sqlite3VdbeMemSetStr(
switch( enc ){
case 0:
pMem->flags |= MEM_Blob;
pMem->enc = SQLITE_UTF8;
break;
case SQLITE_UTF8:
@ -666,9 +669,9 @@ void sqlite3VdbeMemSanity(Mem *pMem, u8 db_enc){
/* MEM_Null excludes all other types */
assert( (pMem->flags&(MEM_Str|MEM_Int|MEM_Real|MEM_Blob))==0
|| (pMem->flags&MEM_Null)==0 );
if( (pMem->flags & (MEM_Int|MEM_Real))==(MEM_Int|MEM_Real) ){
assert( pMem->r==pMem->i );
}
/* 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 );
}
#endif

File diff suppressed because it is too large Load diff