mirror of
https://github.com/php/php-src.git
synced 2025-08-20 01:14:28 +02:00
Upgrade sqlite lib to 3.2.5
This commit is contained in:
parent
4509fb9d5d
commit
bb38017142
64 changed files with 6261 additions and 4244 deletions
|
|
@ -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;
|
||||
|
|
|
|||
388
ext/pdo_sqlite/sqlite/src/analyze.c
Normal file
388
ext/pdo_sqlite/sqlite/src/analyze.c
Normal 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 */
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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*);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@
|
|||
** $Id$
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include "os.h"
|
||||
|
||||
/*
|
||||
** Set all the parameters in the compiled SQL statement to NULL.
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
**
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -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
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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). {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
||||
|
|
|
|||
|
|
@ -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 ){
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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*);
|
||||
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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 ){
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 ){
|
||||
|
|
|
|||
|
|
@ -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*);
|
||||
|
|
|
|||
|
|
@ -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*);
|
||||
|
|
|
|||
|
|
@ -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) );
|
||||
|
|
|
|||
|
|
@ -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];
|
||||
|
|
|
|||
114
ext/pdo_sqlite/sqlite/src/vdbefifo.c
Normal file
114
ext/pdo_sqlite/sqlite/src/vdbefifo.c
Normal 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);
|
||||
}
|
||||
|
|
@ -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
Loading…
Add table
Add a link
Reference in a new issue