Upgrade to SQLite 3.2.7, r=darin
This commit is contained in:
Родитель
e6d06e8485
Коммит
7ec2aabd8f
|
@ -1,5 +1,5 @@
|
|||
|
||||
This is sqlite 3.0.8. (SQLITE_3_0_8 tag)
|
||||
This is sqlite 3.2.7.
|
||||
|
||||
See http://www.sqlite.org/ for more info.
|
||||
|
||||
|
@ -12,13 +12,11 @@ PR_BYTES_PER_WORD.
|
|||
|
||||
We only imported the bits that we actually need for the build --
|
||||
basically, the contents of the src directory, plus autogenerated files
|
||||
(see below). Note that we don't use all the files in the src dir,
|
||||
but we import *.c *.h *.in for simplicity.
|
||||
(see below). Note that we don't use all the files in the src dir;
|
||||
we just bring in *.c *.h (including a full sqlite3.h).
|
||||
|
||||
To move to a new version:
|
||||
|
||||
Update VERSION in src/Makefile.in
|
||||
|
||||
Update opcodes.c, opcodes.h, parse.c, parse.h, all of which are
|
||||
normally generated as part of the sqlite build. Pull these out of the
|
||||
sqlite3 windows source .zip, or autoconfiscate and build a tarball and
|
||||
|
@ -26,3 +24,4 @@ copy them out. Yes, this sucks, but it's better than having to build
|
|||
the parser and all that goop as part of our build.
|
||||
|
||||
-- Vlad Vukicevic <vladimir@pobox.com> 10/2004
|
||||
|
||||
|
|
|
@ -52,11 +52,13 @@ EXPORTS = sqlite3.h
|
|||
|
||||
CSRCS = \
|
||||
alter.c \
|
||||
analyze.c \
|
||||
attach.c \
|
||||
auth.c \
|
||||
btree.c \
|
||||
build.c \
|
||||
callback.c \
|
||||
complete.c \
|
||||
date.c \
|
||||
delete.c \
|
||||
experimental.c \
|
||||
|
@ -87,6 +89,7 @@ CSRCS = \
|
|||
vdbe.c \
|
||||
vdbeapi.c \
|
||||
vdbeaux.c \
|
||||
vdbefifo.c \
|
||||
vdbemem.c \
|
||||
where.c \
|
||||
$(NULL)
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
** This file contains C code routines that used to generate VDBE code
|
||||
** that implements the ALTER TABLE command.
|
||||
**
|
||||
** $Id: alter.c,v 1.3 2005-08-20 01:23:48 vladimir%pobox.com Exp $
|
||||
** $Id: alter.c,v 1.4 2005-12-13 19:49:35 vladimir%pobox.com Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include <ctype.h>
|
||||
|
@ -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;
|
||||
|
|
|
@ -0,0 +1,386 @@
|
|||
/*
|
||||
** 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: analyze.c,v 1.1 2005-12-13 19:49:35 vladimir%pobox.com Exp $
|
||||
*/
|
||||
#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 ){
|
||||
/* Do no analysis for tables that have no 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.
|
||||
*/
|
||||
for(i=0; i<=nCol; i++){
|
||||
sqlite3VdbeAddOp(v, OP_MemInt, 0, iMem+i);
|
||||
}
|
||||
for(i=0; i<nCol; i++){
|
||||
sqlite3VdbeAddOp(v, OP_MemNull, iMem+nCol+i+1, 0);
|
||||
}
|
||||
|
||||
/* 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);
|
||||
sqlite3VdbeJumpHere(v, addr);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** 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 || 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 */
|
|
@ -11,7 +11,7 @@
|
|||
*************************************************************************
|
||||
** This file contains code used to implement the ATTACH and DETACH commands.
|
||||
**
|
||||
** $Id: attach.c,v 1.33 2005/03/16 12:15:21 danielk1977 Exp $
|
||||
** $Id: attach.c,v 1.34 2005/08/20 03:03:04 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
** systems that do not need this facility may omit it by recompiling
|
||||
** the library with -DSQLITE_OMIT_AUTHORIZATION=1
|
||||
**
|
||||
** $Id: auth.c,v 1.21 2005/01/29 08:32:44 danielk1977 Exp $
|
||||
** $Id: auth.c,v 1.22 2005/07/29 15:36:15 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
|
||||
|
@ -114,6 +114,7 @@ void sqlite3AuthRead(
|
|||
TriggerStack *pStack; /* The stack of current triggers */
|
||||
|
||||
if( db->xAuth==0 ) return;
|
||||
if( pExpr->op==TK_AS ) return;
|
||||
assert( pExpr->op==TK_COLUMN );
|
||||
for(iSrc=0; pTabList && iSrc<pTabList->nSrc; iSrc++){
|
||||
if( pExpr->iTable==pTabList->a[iSrc].iCursor ) break;
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
*************************************************************************
|
||||
** $Id: btree.c,v 1.261 2005/05/24 20:19:58 drh Exp $
|
||||
** $Id: btree.c,v 1.269 2005/09/17 15:20:27 drh Exp $
|
||||
**
|
||||
** This file implements a external (disk-based) database using BTrees.
|
||||
** For a detailed discussion of BTrees, refer to
|
||||
|
@ -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
|
||||
|
@ -483,7 +494,7 @@ static int ptrmapPut(Btree *pBt, Pgno key, u8 eType, Pgno parent){
|
|||
|
||||
assert( pBt->autoVacuum );
|
||||
if( key==0 ){
|
||||
return SQLITE_CORRUPT;
|
||||
return SQLITE_CORRUPT_BKPT;
|
||||
}
|
||||
iPtrmap = PTRMAP_PAGENO(pBt->usableSize, key);
|
||||
rc = sqlite3pager_get(pBt->pPager, iPtrmap, (void **)&pPtrmap);
|
||||
|
@ -529,7 +540,7 @@ static int ptrmapGet(Btree *pBt, Pgno key, u8 *pEType, Pgno *pPgno){
|
|||
if( pPgno ) *pPgno = get4byte(&pPtrmap[offset+1]);
|
||||
|
||||
sqlite3pager_unref(pPtrmap);
|
||||
if( *pEType<1 || *pEType>5 ) return SQLITE_CORRUPT;
|
||||
if( *pEType<1 || *pEType>5 ) return SQLITE_CORRUPT_BKPT;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
|
@ -1019,7 +1030,7 @@ static int initPage(
|
|||
assert( pPage->aData == &((unsigned char*)pPage)[-pBt->pageSize] );
|
||||
if( pPage->pParent!=pParent && (pPage->pParent!=0 || pPage->isInit) ){
|
||||
/* The parent page should never change unless the file is corrupt */
|
||||
return SQLITE_CORRUPT; /* bkpt-CORRUPT */
|
||||
return SQLITE_CORRUPT_BKPT;
|
||||
}
|
||||
if( pPage->isInit ) return SQLITE_OK;
|
||||
if( pPage->pParent==0 && pParent!=0 ){
|
||||
|
@ -1037,11 +1048,11 @@ static int initPage(
|
|||
pPage->nCell = get2byte(&data[hdr+3]);
|
||||
if( pPage->nCell>MX_CELL(pBt) ){
|
||||
/* To many cells for a single page. The page must be corrupt */
|
||||
return SQLITE_CORRUPT; /* bkpt-CORRUPT */
|
||||
return SQLITE_CORRUPT_BKPT;
|
||||
}
|
||||
if( pPage->nCell==0 && pParent!=0 && pParent->pgno!=1 ){
|
||||
/* All pages must have at least one cell, except for root pages */
|
||||
return SQLITE_CORRUPT; /* bkpt-CORRUPT */
|
||||
return SQLITE_CORRUPT_BKPT;
|
||||
}
|
||||
|
||||
/* Compute the total free space on the page */
|
||||
|
@ -1051,13 +1062,13 @@ static int initPage(
|
|||
int next, size;
|
||||
if( pc>usableSize-4 ){
|
||||
/* Free block is off the page */
|
||||
return SQLITE_CORRUPT; /* bkpt-CORRUPT */
|
||||
return SQLITE_CORRUPT_BKPT;
|
||||
}
|
||||
next = get2byte(&data[pc]);
|
||||
size = get2byte(&data[pc+2]);
|
||||
if( next>0 && next<=pc+size+3 ){
|
||||
/* Free blocks must be in accending order */
|
||||
return SQLITE_CORRUPT; /* bkpt-CORRUPT */
|
||||
return SQLITE_CORRUPT_BKPT;
|
||||
}
|
||||
nFree += size;
|
||||
pc = next;
|
||||
|
@ -1065,7 +1076,7 @@ static int initPage(
|
|||
pPage->nFree = nFree;
|
||||
if( nFree>=usableSize ){
|
||||
/* Free space cannot exceed total page size */
|
||||
return SQLITE_CORRUPT; /* bkpt-CORRUPT */
|
||||
return SQLITE_CORRUPT_BKPT;
|
||||
}
|
||||
|
||||
pPage->isInit = 1;
|
||||
|
@ -1135,7 +1146,7 @@ static int getAndInitPage(
|
|||
){
|
||||
int rc;
|
||||
if( pgno==0 ){
|
||||
return SQLITE_CORRUPT; /* bkpt-CORRUPT */
|
||||
return SQLITE_CORRUPT_BKPT;
|
||||
}
|
||||
rc = getPage(pBt, pgno, ppPage);
|
||||
if( rc==SQLITE_OK && (*ppPage)->isInit==0 ){
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -1698,7 +1714,7 @@ static int modifyPagePointer(MemPage *pPage, Pgno iFrom, Pgno iTo, u8 eType){
|
|||
if( eType==PTRMAP_OVERFLOW2 ){
|
||||
/* The pointer is always the first 4 bytes of the page in this case. */
|
||||
if( get4byte(pPage->aData)!=iFrom ){
|
||||
return SQLITE_CORRUPT;
|
||||
return SQLITE_CORRUPT_BKPT;
|
||||
}
|
||||
put4byte(pPage->aData, iTo);
|
||||
}else{
|
||||
|
@ -1731,7 +1747,7 @@ static int modifyPagePointer(MemPage *pPage, Pgno iFrom, Pgno iTo, u8 eType){
|
|||
if( i==nCell ){
|
||||
if( eType!=PTRMAP_BTREE ||
|
||||
get4byte(&pPage->aData[pPage->hdrOffset+8])!=iFrom ){
|
||||
return SQLITE_CORRUPT;
|
||||
return SQLITE_CORRUPT_BKPT;
|
||||
}
|
||||
put4byte(&pPage->aData[pPage->hdrOffset+8], iTo);
|
||||
}
|
||||
|
@ -1844,7 +1860,7 @@ static int autoVacuumCommit(Btree *pBt, Pgno *nTrunc){
|
|||
|
||||
assert( pBt->autoVacuum );
|
||||
if( PTRMAP_ISPAGE(pgsz, sqlite3pager_pagecount(pPager)) ){
|
||||
return SQLITE_CORRUPT;
|
||||
return SQLITE_CORRUPT_BKPT;
|
||||
}
|
||||
|
||||
/* Figure out how many free-pages are in the database. If there are no
|
||||
|
@ -1859,7 +1875,7 @@ static int autoVacuumCommit(Btree *pBt, Pgno *nTrunc){
|
|||
origSize = sqlite3pager_pagecount(pPager);
|
||||
nPtrMap = (nFreeList-origSize+PTRMAP_PAGENO(pgsz, origSize)+pgsz/5)/(pgsz/5);
|
||||
finSize = origSize - nFreeList - nPtrMap;
|
||||
if( origSize>PENDING_BYTE_PAGE(pBt) && finSize<=PENDING_BYTE_PAGE(pBt) ){
|
||||
if( origSize>=PENDING_BYTE_PAGE(pBt) && finSize<=PENDING_BYTE_PAGE(pBt) ){
|
||||
finSize--;
|
||||
if( PTRMAP_ISPAGE(pBt->usableSize, finSize) ){
|
||||
finSize--;
|
||||
|
@ -1882,7 +1898,7 @@ static int autoVacuumCommit(Btree *pBt, Pgno *nTrunc){
|
|||
rc = ptrmapGet(pBt, iDbPage, &eType, &iPtrPage);
|
||||
if( rc!=SQLITE_OK ) goto autovacuum_out;
|
||||
if( eType==PTRMAP_ROOTPAGE ){
|
||||
rc = SQLITE_CORRUPT;
|
||||
rc = SQLITE_CORRUPT_BKPT;
|
||||
goto autovacuum_out;
|
||||
}
|
||||
|
||||
|
@ -2398,7 +2414,7 @@ static int getPayload(
|
|||
}
|
||||
|
||||
if( amt>0 ){
|
||||
return SQLITE_CORRUPT; /* bkpt-CORRUPT */
|
||||
return SQLITE_CORRUPT_BKPT;
|
||||
}
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
@ -2416,7 +2432,7 @@ int sqlite3BtreeKey(BtCursor *pCur, u32 offset, u32 amt, void *pBuf){
|
|||
assert( pCur->isValid );
|
||||
assert( pCur->pPage!=0 );
|
||||
if( pCur->pPage->intKey ){
|
||||
return SQLITE_CORRUPT;
|
||||
return SQLITE_CORRUPT_BKPT;
|
||||
}
|
||||
assert( pCur->pPage->intKey==0 );
|
||||
assert( pCur->idx>=0 && pCur->idx<pCur->pPage->nCell );
|
||||
|
@ -2465,13 +2481,11 @@ static const unsigned char *fetchPayload(
|
|||
){
|
||||
unsigned char *aPayload;
|
||||
MemPage *pPage;
|
||||
Btree *pBt;
|
||||
u32 nKey;
|
||||
int nLocal;
|
||||
|
||||
assert( pCur!=0 && pCur->pPage!=0 );
|
||||
assert( pCur->isValid );
|
||||
pBt = pCur->pBt;
|
||||
pPage = pCur->pPage;
|
||||
pageIntegrity(pPage);
|
||||
assert( pCur->idx>=0 && pCur->idx<pPage->nCell );
|
||||
|
@ -2538,7 +2552,7 @@ static int moveToChild(BtCursor *pCur, u32 newPgno){
|
|||
pCur->idx = 0;
|
||||
pCur->info.nSize = 0;
|
||||
if( pNewPage->nCell<1 ){
|
||||
return SQLITE_CORRUPT; /* bkpt-CORRUPT */
|
||||
return SQLITE_CORRUPT_BKPT;
|
||||
}
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
@ -2569,7 +2583,6 @@ static int isRootPage(MemPage *pPage){
|
|||
** the largest cell index.
|
||||
*/
|
||||
static void moveToParent(BtCursor *pCur){
|
||||
Pgno oldPgno;
|
||||
MemPage *pParent;
|
||||
MemPage *pPage;
|
||||
int idxParent;
|
||||
|
@ -2584,7 +2597,6 @@ static void moveToParent(BtCursor *pCur){
|
|||
pageIntegrity(pParent);
|
||||
idxParent = pPage->idxParent;
|
||||
sqlite3pager_ref(pParent->aData);
|
||||
oldPgno = pPage->pgno;
|
||||
releasePage(pPage);
|
||||
pCur->pPage = pParent;
|
||||
pCur->info.nSize = 0;
|
||||
|
@ -2749,7 +2761,7 @@ int sqlite3BtreeMoveto(BtCursor *pCur, const void *pKey, i64 nKey, int *pRes){
|
|||
lwr = 0;
|
||||
upr = pPage->nCell-1;
|
||||
if( !pPage->intKey && pKey==0 ){
|
||||
return SQLITE_CORRUPT;
|
||||
return SQLITE_CORRUPT_BKPT;
|
||||
}
|
||||
pageIntegrity(pPage);
|
||||
while( lwr<=upr ){
|
||||
|
@ -3034,7 +3046,7 @@ static int allocatePage(
|
|||
TRACE(("ALLOCATE: %d trunk - %d free pages left\n", *pPgno, n-1));
|
||||
}else if( k>pBt->usableSize/4 - 8 ){
|
||||
/* Value of k is out of range. Database corruption */
|
||||
return SQLITE_CORRUPT; /* bkpt-CORRUPT */
|
||||
return SQLITE_CORRUPT_BKPT;
|
||||
#ifndef SQLITE_OMIT_AUTOVACUUM
|
||||
}else if( searchList && nearby==iTrunk ){
|
||||
/* The list is being searched and this trunk page is the page
|
||||
|
@ -3109,7 +3121,7 @@ static int allocatePage(
|
|||
*pPgno = iPage;
|
||||
if( *pPgno>sqlite3pager_pagecount(pBt->pPager) ){
|
||||
/* Free page off the end of the file */
|
||||
return SQLITE_CORRUPT; /* bkpt-CORRUPT */
|
||||
return SQLITE_CORRUPT_BKPT;
|
||||
}
|
||||
TRACE(("ALLOCATE: %d was leaf %d of %d on trunk %d"
|
||||
": %d more free pages\n",
|
||||
|
@ -3203,7 +3215,7 @@ static int freePage(MemPage *pPage){
|
|||
put4byte(&pPage1->aData[32], pPage->pgno);
|
||||
TRACE(("FREE-PAGE: %d first\n", pPage->pgno));
|
||||
}else{
|
||||
/* Other free pages already exist. Retrieve the first trunk page
|
||||
/* Other free pages already exist. Retrive the first trunk page
|
||||
** of the freelist and find out how many leaves it has. */
|
||||
MemPage *pTrunk;
|
||||
rc = getPage(pBt, get4byte(&pPage1->aData[32]), &pTrunk);
|
||||
|
@ -3250,7 +3262,7 @@ static int clearCell(MemPage *pPage, unsigned char *pCell){
|
|||
while( ovflPgno!=0 ){
|
||||
MemPage *pOvfl;
|
||||
if( ovflPgno>sqlite3pager_pagecount(pBt->pPager) ){
|
||||
return SQLITE_CORRUPT;
|
||||
return SQLITE_CORRUPT_BKPT;
|
||||
}
|
||||
rc = getPage(pBt, ovflPgno, &pOvfl);
|
||||
if( rc ) return rc;
|
||||
|
@ -3595,17 +3607,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 +3823,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 +4096,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 +4190,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
|
||||
|
@ -4649,7 +4668,7 @@ int sqlite3BtreeDelete(BtCursor *pCur){
|
|||
rc = sqlite3BtreeNext(&leafCur, ¬Used);
|
||||
if( rc!=SQLITE_OK ){
|
||||
if( rc!=SQLITE_NOMEM ){
|
||||
rc = SQLITE_CORRUPT; /* bkpt-CORRUPT */
|
||||
rc = SQLITE_CORRUPT_BKPT;
|
||||
}
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
|
@ -4835,7 +4854,7 @@ static int clearDatabasePage(
|
|||
int i;
|
||||
|
||||
if( pgno>sqlite3pager_pagecount(pBt->pPager) ){
|
||||
return SQLITE_CORRUPT;
|
||||
return SQLITE_CORRUPT_BKPT;
|
||||
}
|
||||
|
||||
rc = getAndInitPage(pBt, pgno, &pPage, pParent);
|
||||
|
@ -5457,7 +5476,7 @@ static int checkTreePage(
|
|||
u8 *data;
|
||||
BtCursor cur;
|
||||
Btree *pBt;
|
||||
int maxLocal, usableSize;
|
||||
int usableSize;
|
||||
char zContext[100];
|
||||
char *hit;
|
||||
|
||||
|
@ -5474,7 +5493,6 @@ static int checkTreePage(
|
|||
"unable to get the page. error code=%d", rc);
|
||||
return 0;
|
||||
}
|
||||
maxLocal = pPage->leafData ? pBt->maxLeaf : pBt->maxLocal;
|
||||
if( (rc = initPage(pPage, pParent))!=0 ){
|
||||
checkAppendMsg(pCheck, zContext, "initPage() returns error code %d", rc);
|
||||
releasePage(pPage);
|
||||
|
@ -5721,7 +5739,7 @@ const char *sqlite3BtreeGetJournalname(Btree *pBt){
|
|||
*/
|
||||
int sqlite3BtreeCopyFile(Btree *pBtTo, Btree *pBtFrom){
|
||||
int rc = SQLITE_OK;
|
||||
Pgno i, nPage, nToPage;
|
||||
Pgno i, nPage, nToPage, iSkip;
|
||||
|
||||
if( pBtTo->inTrans!=TRANS_WRITE || pBtFrom->inTrans!=TRANS_WRITE ){
|
||||
return SQLITE_ERROR;
|
||||
|
@ -5729,8 +5747,10 @@ int sqlite3BtreeCopyFile(Btree *pBtTo, Btree *pBtFrom){
|
|||
if( pBtTo->pCursor ) return SQLITE_BUSY;
|
||||
nToPage = sqlite3pager_pagecount(pBtTo->pPager);
|
||||
nPage = sqlite3pager_pagecount(pBtFrom->pPager);
|
||||
iSkip = PENDING_BYTE_PAGE(pBtTo);
|
||||
for(i=1; rc==SQLITE_OK && i<=nPage; i++){
|
||||
void *pPage;
|
||||
if( i==iSkip ) continue;
|
||||
rc = sqlite3pager_get(pBtFrom->pPager, i, &pPage);
|
||||
if( rc ) break;
|
||||
rc = sqlite3pager_overwrite(pBtTo->pPager, i, pPage);
|
||||
|
@ -5739,6 +5759,7 @@ int sqlite3BtreeCopyFile(Btree *pBtTo, Btree *pBtFrom){
|
|||
}
|
||||
for(i=nPage+1; rc==SQLITE_OK && i<=nToPage; i++){
|
||||
void *pPage;
|
||||
if( i==iSkip ) continue;
|
||||
rc = sqlite3pager_get(pBtTo->pPager, i, &pPage);
|
||||
if( rc ) break;
|
||||
rc = sqlite3pager_write(pPage);
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
** subsystem. See comments in the source code for a detailed description
|
||||
** of what each interface routine does.
|
||||
**
|
||||
** @(#) $Id: btree.h,v 1.63 2005/03/21 04:04:03 danielk1977 Exp $
|
||||
** @(#) $Id: btree.h,v 1.64 2005/08/27 16:36:49 drh Exp $
|
||||
*/
|
||||
#ifndef _BTREE_H_
|
||||
#define _BTREE_H_
|
||||
|
@ -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*);
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
** COMMIT
|
||||
** ROLLBACK
|
||||
**
|
||||
** $Id: build.c,v 1.326 2005/06/12 21:35:52 drh Exp $
|
||||
** $Id: build.c,v 1.351 2005/09/20 17:42:23 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include <ctype.h>
|
||||
|
@ -76,7 +76,7 @@ void sqlite3FinishCoding(Parse *pParse){
|
|||
if( pParse->cookieGoto>0 ){
|
||||
u32 mask;
|
||||
int iDb;
|
||||
sqlite3VdbeChangeP2(v, pParse->cookieGoto-1, sqlite3VdbeCurrentAddr(v));
|
||||
sqlite3VdbeJumpHere(v, pParse->cookieGoto-1);
|
||||
for(iDb=0, mask=1; iDb<db->nDb; mask<<=1, iDb++){
|
||||
if( (mask & pParse->cookieMask)==0 ) continue;
|
||||
sqlite3VdbeAddOp(v, OP_Transaction, iDb, (mask & pParse->writeMask)!=0);
|
||||
|
@ -85,6 +85,7 @@ void sqlite3FinishCoding(Parse *pParse){
|
|||
sqlite3VdbeAddOp(v, OP_Goto, 0, pParse->cookieGoto);
|
||||
}
|
||||
|
||||
#ifndef SQLITE_OMIT_TRACE
|
||||
/* Add a No-op that contains the complete text of the compiled SQL
|
||||
** statement as its P3 argument. This does not change the functionality
|
||||
** of the program.
|
||||
|
@ -92,6 +93,7 @@ void sqlite3FinishCoding(Parse *pParse){
|
|||
** This is used to implement sqlite3_trace().
|
||||
*/
|
||||
sqlite3VdbeOp3(v, OP_Noop, 0, 0, pParse->zSql, pParse->zTail-pParse->zSql);
|
||||
#endif /* SQLITE_OMIT_TRACE */
|
||||
}
|
||||
|
||||
|
||||
|
@ -101,7 +103,7 @@ void sqlite3FinishCoding(Parse *pParse){
|
|||
FILE *trace = (db->flags & SQLITE_VdbeTrace)!=0 ? stdout : 0;
|
||||
sqlite3VdbeTrace(v, trace);
|
||||
sqlite3VdbeMakeReady(v, pParse->nVar, pParse->nMem+3,
|
||||
pParse->nTab+3, pParse->nMaxDepth+1, pParse->explain);
|
||||
pParse->nTab+3, pParse->explain);
|
||||
pParse->rc = SQLITE_DONE;
|
||||
pParse->colNamesSet = 0;
|
||||
}else if( pParse->rc==SQLITE_OK ){
|
||||
|
@ -130,7 +132,6 @@ void sqlite3FinishCoding(Parse *pParse){
|
|||
void sqlite3NestedParse(Parse *pParse, const char *zFormat, ...){
|
||||
va_list ap;
|
||||
char *zSql;
|
||||
int rc;
|
||||
# define SAVE_SZ (sizeof(Parse) - offsetof(Parse,nVar))
|
||||
char saveBuf[SAVE_SZ];
|
||||
|
||||
|
@ -145,7 +146,7 @@ void sqlite3NestedParse(Parse *pParse, const char *zFormat, ...){
|
|||
pParse->nested++;
|
||||
memcpy(saveBuf, &pParse->nVar, SAVE_SZ);
|
||||
memset(&pParse->nVar, 0, SAVE_SZ);
|
||||
rc = sqlite3RunParser(pParse, zSql, 0);
|
||||
sqlite3RunParser(pParse, zSql, 0);
|
||||
sqliteFree(zSql);
|
||||
memcpy(&pParse->nVar, saveBuf, SAVE_SZ);
|
||||
pParse->nested--;
|
||||
|
@ -200,9 +201,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 +256,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 +530,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 +578,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++;
|
||||
|
@ -640,7 +635,6 @@ void sqlite3StartTable(
|
|||
int isView /* True if this is a VIEW */
|
||||
){
|
||||
Table *pTable;
|
||||
Index *pIdx;
|
||||
char *zName = 0; /* The name of the new table */
|
||||
sqlite3 *db = pParse->db;
|
||||
Vdbe *v;
|
||||
|
@ -719,8 +713,7 @@ void sqlite3StartTable(
|
|||
sqlite3ErrorMsg(pParse, "table %T already exists", pName);
|
||||
goto begin_table_error;
|
||||
}
|
||||
if( (pIdx = sqlite3FindIndex(db, zName, 0))!=0 &&
|
||||
( iDb==0 || !db->init.busy) ){
|
||||
if( sqlite3FindIndex(db, zName, 0)!=0 && (iDb==0 || !db->init.busy) ){
|
||||
sqlite3ErrorMsg(pParse, "there is already an index named %s", zName);
|
||||
goto begin_table_error;
|
||||
}
|
||||
|
@ -745,7 +738,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 +895,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 +931,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);
|
||||
sqliteFree(pCol->zType);
|
||||
pCol->zType = sqlite3NameFromToken(pType);
|
||||
pCol->affinity = sqlite3AffinityType(pType);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -977,14 +958,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);
|
||||
}
|
||||
|
@ -1033,7 +1015,9 @@ void sqlite3AddPrimaryKey(
|
|||
break;
|
||||
}
|
||||
}
|
||||
if( iCol<pTab->nCol ) pTab->aCol[iCol].isPrimKey = 1;
|
||||
if( iCol<pTab->nCol ){
|
||||
pTab->aCol[iCol].isPrimKey = 1;
|
||||
}
|
||||
}
|
||||
if( pList->nExpr>1 ) iCol = -1;
|
||||
}
|
||||
|
@ -1317,13 +1301,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 +1517,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 +1958,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,18 +1986,23 @@ 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));
|
||||
sqlite3VdbeJumpHere(v, addr1);
|
||||
sqlite3VdbeAddOp(v, OP_Close, iTab, 0);
|
||||
sqlite3VdbeAddOp(v, OP_Close, iIdx, 0);
|
||||
}
|
||||
|
@ -2079,7 +2068,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);
|
||||
|
@ -2124,14 +2115,12 @@ void sqlite3CreateIndex(
|
|||
goto exit_create_index;
|
||||
}
|
||||
if( !db->init.busy ){
|
||||
Index *pISameName; /* Another index with the same name */
|
||||
Table *pTSameName; /* A table with same name as the index */
|
||||
if( SQLITE_OK!=sqlite3ReadSchema(pParse) ) goto exit_create_index;
|
||||
if( (pISameName = sqlite3FindIndex(db, zName, db->aDb[iDb].zName))!=0 ){
|
||||
if( sqlite3FindIndex(db, zName, db->aDb[iDb].zName)!=0 ){
|
||||
sqlite3ErrorMsg(pParse, "index %s already exists", zName);
|
||||
goto exit_create_index;
|
||||
}
|
||||
if( (pTSameName = sqlite3FindTable(db, zName, 0))!=0 ){
|
||||
if( sqlite3FindTable(db, zName, 0)!=0 ){
|
||||
sqlite3ErrorMsg(pParse, "there is already a table named %s", zName);
|
||||
goto exit_create_index;
|
||||
}
|
||||
|
@ -2177,11 +2166,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 = (unsigned*)&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 +2207,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 +2374,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){
|
||||
unsigned *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.
|
||||
|
@ -2444,6 +2466,47 @@ exit_drop_index:
|
|||
sqlite3SrcListDelete(pName);
|
||||
}
|
||||
|
||||
/*
|
||||
** ppArray points into a structure where there is an array pointer
|
||||
** followed by two integers. The first integer is the
|
||||
** number of elements in the structure array. The second integer
|
||||
** is the number of allocated slots in the array.
|
||||
**
|
||||
** In other words, the structure looks something like this:
|
||||
**
|
||||
** struct Example1 {
|
||||
** struct subElem *aEntry;
|
||||
** int nEntry;
|
||||
** int nAlloc;
|
||||
** }
|
||||
**
|
||||
** The pnEntry parameter points to the equivalent of Example1.nEntry.
|
||||
**
|
||||
** This routine allocates a new slot in the array, zeros it out,
|
||||
** and returns its index. If malloc fails a negative number is returned.
|
||||
**
|
||||
** szEntry is the sizeof of a single array entry. initSize is the
|
||||
** number of array entries allocated on the initial allocation.
|
||||
*/
|
||||
int sqlite3ArrayAllocate(void **ppArray, int szEntry, int initSize){
|
||||
char *p;
|
||||
int *an = (int*)&ppArray[1];
|
||||
if( an[0]>=an[1] ){
|
||||
void *pNew;
|
||||
int newSize;
|
||||
newSize = an[1]*2 + initSize;
|
||||
pNew = sqliteRealloc(*ppArray, newSize*szEntry);
|
||||
if( pNew==0 ){
|
||||
return -1;
|
||||
}
|
||||
an[1] = newSize;
|
||||
*ppArray = pNew;
|
||||
}
|
||||
p = *ppArray;
|
||||
memset(&p[an[0]*szEntry], 0, szEntry);
|
||||
return an[0]++;
|
||||
}
|
||||
|
||||
/*
|
||||
** Append a new element to the given IdList. Create a new IdList if
|
||||
** need be.
|
||||
|
@ -2451,27 +2514,47 @@ exit_drop_index:
|
|||
** A new IdList is returned, or NULL if malloc() fails.
|
||||
*/
|
||||
IdList *sqlite3IdListAppend(IdList *pList, Token *pToken){
|
||||
int i;
|
||||
if( pList==0 ){
|
||||
pList = sqliteMalloc( sizeof(IdList) );
|
||||
if( pList==0 ) return 0;
|
||||
pList->nAlloc = 0;
|
||||
}
|
||||
if( pList->nId>=pList->nAlloc ){
|
||||
struct IdList_item *a;
|
||||
pList->nAlloc = pList->nAlloc*2 + 5;
|
||||
a = sqliteRealloc(pList->a, pList->nAlloc*sizeof(pList->a[0]) );
|
||||
if( a==0 ){
|
||||
sqlite3IdListDelete(pList);
|
||||
return 0;
|
||||
}
|
||||
pList->a = a;
|
||||
i = sqlite3ArrayAllocate((void**)&pList->a, sizeof(pList->a[0]), 5);
|
||||
if( i<0 ){
|
||||
sqlite3IdListDelete(pList);
|
||||
return 0;
|
||||
}
|
||||
memset(&pList->a[pList->nId], 0, sizeof(pList->a[0]));
|
||||
pList->a[pList->nId].zName = sqlite3NameFromToken(pToken);
|
||||
pList->nId++;
|
||||
pList->a[i].zName = sqlite3NameFromToken(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 +2639,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 +2841,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 +2859,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 +2868,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);
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
** This file contains functions used to access the internal hash tables
|
||||
** of user defined functions and collation sequences.
|
||||
**
|
||||
** $Id: callback.c,v 1.1 2005-08-20 01:23:48 vladimir%pobox.com Exp $
|
||||
** $Id: callback.c,v 1.2 2005-12-13 19:49:35 vladimir%pobox.com Exp $
|
||||
*/
|
||||
|
||||
#include "sqliteInt.h"
|
||||
|
@ -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;
|
||||
|
|
|
@ -0,0 +1,263 @@
|
|||
/*
|
||||
** 2001 September 15
|
||||
**
|
||||
** 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.
|
||||
**
|
||||
*************************************************************************
|
||||
** An tokenizer for SQL
|
||||
**
|
||||
** This file contains C code that implements the sqlite3_complete() API.
|
||||
** This code used to be part of the tokenizer.c source file. But by
|
||||
** separating it out, the code will be automatically omitted from
|
||||
** static links that do not use it.
|
||||
**
|
||||
** $Id: complete.c,v 1.1 2005-12-13 19:49:35 vladimir%pobox.com Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#ifndef SQLITE_OMIT_COMPLETE
|
||||
|
||||
/*
|
||||
** This is defined in tokenize.c. We just have to import the definition.
|
||||
*/
|
||||
extern const char sqlite3IsIdChar[];
|
||||
#define IdChar(C) (((c=C)&0x80)!=0 || (c>0x1f && sqlite3IsIdChar[c-0x20]))
|
||||
|
||||
|
||||
/*
|
||||
** 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 '`': /* Grave-accent quoted symbols used by MySQL */
|
||||
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 */
|
|
@ -16,7 +16,7 @@
|
|||
** sqlite3RegisterDateTimeFunctions() found at the bottom of the file.
|
||||
** All other code has file scope.
|
||||
**
|
||||
** $Id: date.c,v 1.44 2005/03/21 00:43:44 drh Exp $
|
||||
** $Id: date.c,v 1.45 2005/06/25 18:42:14 drh Exp $
|
||||
**
|
||||
** NOTES:
|
||||
**
|
||||
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
** This file contains C code routines that are called by the parser
|
||||
** in order to generate code for DELETE FROM statements.
|
||||
**
|
||||
** $Id: delete.c,v 1.106 2005/06/12 21:35:52 drh Exp $
|
||||
** $Id: delete.c,v 1.111 2005/09/20 17:42:23 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -178,12 +178,12 @@ void sqlite3DeleteFrom(
|
|||
if( pParse->nested==0 ) sqlite3VdbeCountChanges(v);
|
||||
sqlite3BeginWriteOperation(pParse, triggers_exist, pTab->iDb);
|
||||
|
||||
/* If we are trying to delete from a view, construct that view into
|
||||
** a temporary table.
|
||||
/* If we are trying to delete from a view, realize that view into
|
||||
** a ephemeral table.
|
||||
*/
|
||||
if( isView ){
|
||||
Select *pView = sqlite3SelectDup(pTab->pSelect);
|
||||
sqlite3Select(pParse, pView, SRT_TempTable, iCur, 0, 0, 0, 0);
|
||||
sqlite3Select(pParse, pView, SRT_VirtualTab, iCur, 0, 0, 0, 0);
|
||||
sqlite3SelectDelete(pView);
|
||||
}
|
||||
|
||||
|
@ -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 ){
|
||||
|
@ -382,7 +380,7 @@ void sqlite3GenerateRowDelete(
|
|||
addr = sqlite3VdbeAddOp(v, OP_NotExists, iCur, 0);
|
||||
sqlite3GenerateRowIndexDelete(db, v, pTab, iCur, 0);
|
||||
sqlite3VdbeAddOp(v, OP_Delete, iCur, (count?OPFLAG_NCHANGE:0));
|
||||
sqlite3VdbeChangeP2(v, addr, sqlite3VdbeCurrentAddr(v));
|
||||
sqlite3VdbeJumpHere(v, addr);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
** This file contains routines used for analyzing expressions and
|
||||
** for generating VDBE code that evaluates expressions in SQLite.
|
||||
**
|
||||
** $Id: expr.c,v 1.206 2005/06/12 21:35:52 drh Exp $
|
||||
** $Id: expr.c,v 1.230 2005/09/23 21:11:54 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include <ctype.h>
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -353,7 +355,7 @@ void sqlite3ExprAssignVarNumber(Parse *pParse, Expr *pExpr){
|
|||
pExpr->iTable = ++pParse->nVar;
|
||||
if( pParse->nVarExpr>=pParse->nVarExprAlloc-1 ){
|
||||
pParse->nVarExprAlloc += pParse->nVarExprAlloc + 10;
|
||||
pParse->apVarExpr = sqliteRealloc(pParse->apVarExpr,
|
||||
sqlite3ReallocOrFree((void**)&pParse->apVarExpr,
|
||||
pParse->nVarExprAlloc*sizeof(pParse->apVarExpr[0]) );
|
||||
}
|
||||
if( !sqlite3_malloc_failed ){
|
||||
|
@ -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,9 +546,14 @@ Select *sqlite3SelectDup(Select *p){
|
|||
pNew->pOffset = sqlite3ExprDup(p->pOffset);
|
||||
pNew->iLimit = -1;
|
||||
pNew->iOffset = -1;
|
||||
pNew->ppOpenTemp = 0;
|
||||
pNew->isResolved = p->isResolved;
|
||||
pNew->isAgg = p->isAgg;
|
||||
pNew->usesVirt = 0;
|
||||
pNew->disallowOrderBy = 0;
|
||||
pNew->pRightmost = 0;
|
||||
pNew->addrOpenVirt[0] = -1;
|
||||
pNew->addrOpenVirt[1] = -1;
|
||||
pNew->addrOpenVirt[2] = -1;
|
||||
return pNew;
|
||||
}
|
||||
#else
|
||||
|
@ -607,6 +629,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 +688,27 @@ 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:
|
||||
case TK_AGG_COLUMN:
|
||||
#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 +716,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 +728,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
|
||||
|
@ -1184,11 +1233,19 @@ int sqlite3ExprResolveNames(
|
|||
NameContext *pNC, /* Namespace to resolve expressions in. */
|
||||
Expr *pExpr /* The expression to be analyzed. */
|
||||
){
|
||||
int savedHasAgg;
|
||||
if( pExpr==0 ) return 0;
|
||||
savedHasAgg = pNC->hasAgg;
|
||||
pNC->hasAgg = 0;
|
||||
walkExprTree(pExpr, nameResolverStep, pNC);
|
||||
if( pNC->nErr>0 ){
|
||||
ExprSetProperty(pExpr, EP_Error);
|
||||
}
|
||||
if( pNC->hasAgg ){
|
||||
ExprSetProperty(pExpr, EP_Agg);
|
||||
}else if( savedHasAgg ){
|
||||
pNC->hasAgg = 1;
|
||||
}
|
||||
return ExprHasProperty(pExpr, EP_Error);
|
||||
}
|
||||
|
||||
|
@ -1218,37 +1275,38 @@ 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);
|
||||
sqlite3VdbeAddOp(v, OP_Integer, 1, 0);
|
||||
sqlite3VdbeAddOp(v, OP_MemStore, mem, 1);
|
||||
}
|
||||
|
||||
if( pExpr->pSelect ){
|
||||
sqlite3VdbeAddOp(v, OP_AggContextPush, 0, 0);
|
||||
testAddr = sqlite3VdbeAddOp(v, OP_If, 0, 0);
|
||||
assert( testAddr>0 || sqlite3_malloc_failed );
|
||||
sqlite3VdbeAddOp(v, OP_MemInt, 1, mem);
|
||||
}
|
||||
|
||||
switch( pExpr->op ){
|
||||
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 +1319,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 +1348,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<3; i++){
|
||||
aOp[i].opcode = OP_Noop;
|
||||
}
|
||||
testAddr = 0;
|
||||
}
|
||||
|
||||
/* Evaluate the expression and insert it into the temp table */
|
||||
|
@ -1341,11 +1409,8 @@ void sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){
|
|||
}
|
||||
}
|
||||
|
||||
if( pExpr->pSelect ){
|
||||
sqlite3VdbeAddOp(v, OP_AggContextPop, 0, 0);
|
||||
}
|
||||
if( label<0 ){
|
||||
sqlite3VdbeResolveLabel(v, label);
|
||||
if( testAddr ){
|
||||
sqlite3VdbeJumpHere(v, testAddr);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -1360,7 +1425,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);
|
||||
}
|
||||
|
@ -1386,10 +1451,21 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){
|
|||
}
|
||||
op = pExpr->op;
|
||||
switch( op ){
|
||||
case TK_AGG_COLUMN: {
|
||||
AggInfo *pAggInfo = pExpr->pAggInfo;
|
||||
struct AggInfo_col *pCol = &pAggInfo->aCol[pExpr->iAgg];
|
||||
if( !pAggInfo->directMode ){
|
||||
sqlite3VdbeAddOp(v, OP_MemLoad, pCol->iMem, 0);
|
||||
break;
|
||||
}else if( pAggInfo->useSortingIdx ){
|
||||
sqlite3VdbeAddOp(v, OP_Column, pAggInfo->sortingIdx,
|
||||
pCol->iSorterColumn);
|
||||
break;
|
||||
}
|
||||
/* Otherwise, fall thru into the TK_COLUMN case */
|
||||
}
|
||||
case TK_COLUMN: {
|
||||
if( !pParse->fillAgg && pExpr->iAgg>=0 ){
|
||||
sqlite3VdbeAddOp(v, OP_AggGet, pExpr->iAggCtx, pExpr->iAgg);
|
||||
}else if( pExpr->iColumn>=0 ){
|
||||
if( pExpr->iColumn>=0 ){
|
||||
sqlite3VdbeAddOp(v, OP_Column, pExpr->iTable, pExpr->iColumn);
|
||||
sqlite3ColumnDefault(v, pExpr->pTab, pExpr->iColumn);
|
||||
}else{
|
||||
|
@ -1405,8 +1481,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 +1491,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 +1515,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:
|
||||
|
@ -1515,7 +1614,8 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){
|
|||
break;
|
||||
}
|
||||
case TK_AGG_FUNCTION: {
|
||||
sqlite3VdbeAddOp(v, OP_AggGet, 0, pExpr->iAgg);
|
||||
AggInfo *pInfo = pExpr->pAggInfo;
|
||||
sqlite3VdbeAddOp(v, OP_MemLoad, pInfo->aFunc[pExpr->iAgg].iMem, 0);
|
||||
break;
|
||||
}
|
||||
case TK_CONST_FUNC:
|
||||
|
@ -1525,7 +1625,7 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){
|
|||
FuncDef *pDef;
|
||||
int nId;
|
||||
const char *zId;
|
||||
int p2 = 0;
|
||||
int constMask = 0;
|
||||
int i;
|
||||
u8 enc = pParse->db->enc;
|
||||
CollSeq *pColl = 0;
|
||||
|
@ -1536,7 +1636,7 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){
|
|||
nExpr = sqlite3ExprCodeExprList(pParse, pList);
|
||||
for(i=0; i<nExpr && i<32; i++){
|
||||
if( sqlite3ExprIsConstant(pList->a[i].pExpr) ){
|
||||
p2 |= (1<<i);
|
||||
constMask |= (1<<i);
|
||||
}
|
||||
if( pDef->needCollSeq && !pColl ){
|
||||
pColl = sqlite3ExprCollSeq(pParse, pList->a[i].pExpr);
|
||||
|
@ -1546,7 +1646,7 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){
|
|||
if( !pColl ) pColl = pParse->db->pDfltColl;
|
||||
sqlite3VdbeOp3(v, OP_CollSeq, 0, 0, (char *)pColl, P3_COLLSEQ);
|
||||
}
|
||||
sqlite3VdbeOp3(v, OP_Function, nExpr, p2, (char*)pDef, P3_FUNCDEF);
|
||||
sqlite3VdbeOp3(v, OP_Function, constMask, nExpr, (char*)pDef, P3_FUNCDEF);
|
||||
break;
|
||||
}
|
||||
#ifndef SQLITE_OMIT_SUBQUERY
|
||||
|
@ -1610,7 +1710,6 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){
|
|||
case TK_CASE: {
|
||||
int expr_end_label;
|
||||
int jumpInst;
|
||||
int addr;
|
||||
int nExpr;
|
||||
int i;
|
||||
ExprList *pEList;
|
||||
|
@ -1638,8 +1737,7 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){
|
|||
}
|
||||
sqlite3ExprCode(pParse, aListelem[i+1].pExpr);
|
||||
sqlite3VdbeAddOp(v, OP_Goto, 0, expr_end_label);
|
||||
addr = sqlite3VdbeCurrentAddr(v);
|
||||
sqlite3VdbeChangeP2(v, jumpInst, addr);
|
||||
sqlite3VdbeJumpHere(v, jumpInst);
|
||||
}
|
||||
if( pExpr->pLeft ){
|
||||
sqlite3VdbeAddOp(v, OP_Pop, 1, 0);
|
||||
|
@ -1663,9 +1761,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 +1815,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;
|
||||
|
@ -1808,7 +1904,7 @@ void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
|
|||
codeCompare(pParse, pLeft, pRight, OP_Le, dest, jumpIfNull);
|
||||
|
||||
sqlite3VdbeAddOp(v, OP_Integer, 0, 0);
|
||||
sqlite3VdbeChangeP2(v, addr, sqlite3VdbeCurrentAddr(v));
|
||||
sqlite3VdbeJumpHere(v, addr);
|
||||
sqlite3VdbeAddOp(v, OP_Pop, 1, 0);
|
||||
break;
|
||||
}
|
||||
|
@ -1941,6 +2037,7 @@ int sqlite3ExprCompare(Expr *pA, Expr *pB){
|
|||
return 0;
|
||||
}
|
||||
if( pA->op!=pB->op ) return 0;
|
||||
if( (pA->flags & EP_Distinct)!=(pB->flags & EP_Distinct) ) return 0;
|
||||
if( !sqlite3ExprCompare(pA->pLeft, pB->pLeft) ) return 0;
|
||||
if( !sqlite3ExprCompare(pA->pRight, pB->pRight) ) return 0;
|
||||
if( pA->pList ){
|
||||
|
@ -1964,23 +2061,32 @@ int sqlite3ExprCompare(Expr *pA, Expr *pB){
|
|||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Add a new element to the pParse->aAgg[] array and return its index.
|
||||
** The new element is initialized to zero. The calling function is
|
||||
** expected to fill it in.
|
||||
** Add a new element to the pAggInfo->aCol[] array. Return the index of
|
||||
** the new element. Return a negative number if malloc fails.
|
||||
*/
|
||||
static int appendAggInfo(Parse *pParse){
|
||||
if( (pParse->nAgg & 0x7)==0 ){
|
||||
int amt = pParse->nAgg + 8;
|
||||
AggExpr *aAgg = sqliteRealloc(pParse->aAgg, amt*sizeof(pParse->aAgg[0]));
|
||||
if( aAgg==0 ){
|
||||
return -1;
|
||||
}
|
||||
pParse->aAgg = aAgg;
|
||||
static int addAggInfoColumn(AggInfo *pInfo){
|
||||
int i;
|
||||
i = sqlite3ArrayAllocate((void**)&pInfo->aCol, sizeof(pInfo->aCol[0]), 3);
|
||||
if( i<0 ){
|
||||
return -1;
|
||||
}
|
||||
memset(&pParse->aAgg[pParse->nAgg], 0, sizeof(pParse->aAgg[0]));
|
||||
return pParse->nAgg++;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
/*
|
||||
** Add a new element to the pAggInfo->aFunc[] array. Return the index of
|
||||
** the new element. Return a negative number if malloc fails.
|
||||
*/
|
||||
static int addAggInfoFunc(AggInfo *pInfo){
|
||||
int i;
|
||||
i = sqlite3ArrayAllocate((void**)&pInfo->aFunc, sizeof(pInfo->aFunc[0]), 2);
|
||||
if( i<0 ){
|
||||
return -1;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
/*
|
||||
** This is an xFunc for walkExprTree() used to implement
|
||||
|
@ -1991,60 +2097,118 @@ static int appendAggInfo(Parse *pParse){
|
|||
*/
|
||||
static int analyzeAggregate(void *pArg, Expr *pExpr){
|
||||
int i;
|
||||
AggExpr *aAgg;
|
||||
NameContext *pNC = (NameContext *)pArg;
|
||||
Parse *pParse = pNC->pParse;
|
||||
SrcList *pSrcList = pNC->pSrcList;
|
||||
AggInfo *pAggInfo = pNC->pAggInfo;
|
||||
|
||||
|
||||
switch( pExpr->op ){
|
||||
case TK_COLUMN: {
|
||||
for(i=0; pSrcList && i<pSrcList->nSrc; i++){
|
||||
if( pExpr->iTable==pSrcList->a[i].iCursor ){
|
||||
aAgg = pParse->aAgg;
|
||||
for(i=0; i<pParse->nAgg; i++){
|
||||
if( aAgg[i].isAgg ) continue;
|
||||
if( aAgg[i].pExpr->iTable==pExpr->iTable
|
||||
&& aAgg[i].pExpr->iColumn==pExpr->iColumn ){
|
||||
break;
|
||||
/* Check to see if the column is in one of the tables in the FROM
|
||||
** clause of the aggregate query */
|
||||
if( pSrcList ){
|
||||
struct SrcList_item *pItem = pSrcList->a;
|
||||
for(i=0; i<pSrcList->nSrc; i++, pItem++){
|
||||
struct AggInfo_col *pCol;
|
||||
if( pExpr->iTable==pItem->iCursor ){
|
||||
/* If we reach this point, it means that pExpr refers to a table
|
||||
** that is in the FROM clause of the aggregate query.
|
||||
**
|
||||
** Make an entry for the column in pAggInfo->aCol[] if there
|
||||
** is not an entry there already.
|
||||
*/
|
||||
pCol = pAggInfo->aCol;
|
||||
for(i=0; i<pAggInfo->nColumn; i++, pCol++){
|
||||
if( pCol->iTable==pExpr->iTable &&
|
||||
pCol->iColumn==pExpr->iColumn ){
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if( i>=pParse->nAgg ){
|
||||
i = appendAggInfo(pParse);
|
||||
if( i<0 ) return 1;
|
||||
pParse->aAgg[i].isAgg = 0;
|
||||
pParse->aAgg[i].pExpr = pExpr;
|
||||
}
|
||||
pExpr->iAgg = i;
|
||||
pExpr->iAggCtx = pNC->nDepth;
|
||||
return 1;
|
||||
}
|
||||
if( i>=pAggInfo->nColumn && (i = addAggInfoColumn(pAggInfo))>=0 ){
|
||||
pCol = &pAggInfo->aCol[i];
|
||||
pCol->iTable = pExpr->iTable;
|
||||
pCol->iColumn = pExpr->iColumn;
|
||||
pCol->iMem = pParse->nMem++;
|
||||
pCol->iSorterColumn = -1;
|
||||
pCol->pExpr = pExpr;
|
||||
if( pAggInfo->pGroupBy ){
|
||||
int j, n;
|
||||
ExprList *pGB = pAggInfo->pGroupBy;
|
||||
struct ExprList_item *pTerm = pGB->a;
|
||||
n = pGB->nExpr;
|
||||
for(j=0; j<n; j++, pTerm++){
|
||||
Expr *pE = pTerm->pExpr;
|
||||
if( pE->op==TK_COLUMN && pE->iTable==pExpr->iTable &&
|
||||
pE->iColumn==pExpr->iColumn ){
|
||||
pCol->iSorterColumn = j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if( pCol->iSorterColumn<0 ){
|
||||
pCol->iSorterColumn = pAggInfo->nSortingColumn++;
|
||||
}
|
||||
}
|
||||
/* There is now an entry for pExpr in pAggInfo->aCol[] (either
|
||||
** because it was there before or because we just created it).
|
||||
** Convert the pExpr to be a TK_AGG_COLUMN referring to that
|
||||
** pAggInfo->aCol[] entry.
|
||||
*/
|
||||
pExpr->pAggInfo = pAggInfo;
|
||||
pExpr->op = TK_AGG_COLUMN;
|
||||
pExpr->iAgg = i;
|
||||
break;
|
||||
} /* endif pExpr->iTable==pItem->iCursor */
|
||||
} /* end loop over pSrcList */
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
case TK_AGG_FUNCTION: {
|
||||
/* The pNC->nDepth==0 test causes aggregate functions in subqueries
|
||||
** to be ignored */
|
||||
if( pNC->nDepth==0 ){
|
||||
aAgg = pParse->aAgg;
|
||||
for(i=0; i<pParse->nAgg; i++){
|
||||
if( !aAgg[i].isAgg ) continue;
|
||||
if( sqlite3ExprCompare(aAgg[i].pExpr, pExpr) ){
|
||||
/* Check to see if pExpr is a duplicate of another aggregate
|
||||
** function that is already in the pAggInfo structure
|
||||
*/
|
||||
struct AggInfo_func *pItem = pAggInfo->aFunc;
|
||||
for(i=0; i<pAggInfo->nFunc; i++, pItem++){
|
||||
if( sqlite3ExprCompare(pItem->pExpr, pExpr) ){
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( i>=pParse->nAgg ){
|
||||
if( i>=pAggInfo->nFunc ){
|
||||
/* pExpr is original. Make a new entry in pAggInfo->aFunc[]
|
||||
*/
|
||||
u8 enc = pParse->db->enc;
|
||||
i = appendAggInfo(pParse);
|
||||
if( i<0 ) return 1;
|
||||
pParse->aAgg[i].isAgg = 1;
|
||||
pParse->aAgg[i].pExpr = pExpr;
|
||||
pParse->aAgg[i].pFunc = sqlite3FindFunction(pParse->db,
|
||||
pExpr->token.z, pExpr->token.n,
|
||||
pExpr->pList ? pExpr->pList->nExpr : 0, enc, 0);
|
||||
i = addAggInfoFunc(pAggInfo);
|
||||
if( i>=0 ){
|
||||
pItem = &pAggInfo->aFunc[i];
|
||||
pItem->pExpr = pExpr;
|
||||
pItem->iMem = pParse->nMem++;
|
||||
pItem->pFunc = sqlite3FindFunction(pParse->db,
|
||||
pExpr->token.z, pExpr->token.n,
|
||||
pExpr->pList ? pExpr->pList->nExpr : 0, enc, 0);
|
||||
if( pExpr->flags & EP_Distinct ){
|
||||
pItem->iDistinct = pParse->nTab++;
|
||||
}else{
|
||||
pItem->iDistinct = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Make pExpr point to the appropriate pAggInfo->aFunc[] entry
|
||||
*/
|
||||
pExpr->iAgg = i;
|
||||
pExpr->pAggInfo = pAggInfo;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Recursively walk subqueries looking for TK_COLUMN nodes that need
|
||||
** to be changed to TK_AGG_COLUMN. But increment nDepth so that
|
||||
** TK_AGG_FUNCTION nodes in subqueries will be unchanged.
|
||||
*/
|
||||
if( pExpr->pSelect ){
|
||||
pNC->nDepth++;
|
||||
walkSelectExpr(pExpr->pSelect, analyzeAggregate, pNC);
|
||||
|
@ -2069,3 +2233,21 @@ int sqlite3ExprAnalyzeAggregates(NameContext *pNC, Expr *pExpr){
|
|||
walkExprTree(pExpr, analyzeAggregate, pNC);
|
||||
return pNC->pParse->nErr - nErr;
|
||||
}
|
||||
|
||||
/*
|
||||
** Call sqlite3ExprAnalyzeAggregates() for every expression in an
|
||||
** expression list. Return the number of errors.
|
||||
**
|
||||
** If an error is found, the analysis is cut short.
|
||||
*/
|
||||
int sqlite3ExprAnalyzeAggList(NameContext *pNC, ExprList *pList){
|
||||
struct ExprList_item *pItem;
|
||||
int i;
|
||||
int nErr = 0;
|
||||
if( pList ){
|
||||
for(pItem=pList->a, i=0; nErr==0 && i<pList->nExpr; i++, pItem++){
|
||||
nErr += sqlite3ExprAnalyzeAggregates(pNC, pItem->pExpr);
|
||||
}
|
||||
}
|
||||
return nErr;
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
** sqliteRegisterBuildinFunctions() found at the bottom of the file.
|
||||
** All other code has file scope.
|
||||
**
|
||||
** $Id: func.c,v 1.98 2005/05/24 12:01:02 danielk1977 Exp $
|
||||
** $Id: func.c,v 1.110 2005/09/08 20:37:43 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include <ctype.h>
|
||||
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -813,6 +819,7 @@ typedef struct SumCtx SumCtx;
|
|||
struct SumCtx {
|
||||
double sum; /* Sum of terms */
|
||||
int cnt; /* Number of elements summed */
|
||||
u8 seenFloat; /* True if there has been any floating point value */
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -820,21 +827,32 @@ struct SumCtx {
|
|||
*/
|
||||
static void sumStep(sqlite3_context *context, int argc, sqlite3_value **argv){
|
||||
SumCtx *p;
|
||||
if( argc<1 ) return;
|
||||
int type;
|
||||
assert( argc==1 );
|
||||
p = sqlite3_aggregate_context(context, sizeof(*p));
|
||||
if( p && SQLITE_NULL!=sqlite3_value_type(argv[0]) ){
|
||||
type = sqlite3_value_type(argv[0]);
|
||||
if( p && type!=SQLITE_NULL ){
|
||||
p->sum += sqlite3_value_double(argv[0]);
|
||||
p->cnt++;
|
||||
if( type==SQLITE_FLOAT ){
|
||||
p->seenFloat = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
static void sumFinalize(sqlite3_context *context){
|
||||
SumCtx *p;
|
||||
p = sqlite3_aggregate_context(context, sizeof(*p));
|
||||
sqlite3_result_double(context, p ? p->sum : 0.0);
|
||||
p = sqlite3_aggregate_context(context, 0);
|
||||
if( p && p->cnt>0 ){
|
||||
if( p->seenFloat ){
|
||||
sqlite3_result_double(context, p->sum);
|
||||
}else{
|
||||
sqlite3_result_int64(context, (i64)p->sum);
|
||||
}
|
||||
}
|
||||
}
|
||||
static void avgFinalize(sqlite3_context *context){
|
||||
SumCtx *p;
|
||||
p = sqlite3_aggregate_context(context, sizeof(*p));
|
||||
p = sqlite3_aggregate_context(context, 0);
|
||||
if( p && p->cnt>0 ){
|
||||
sqlite3_result_double(context, p->sum/(double)p->cnt);
|
||||
}
|
||||
|
@ -872,20 +890,10 @@ static void countStep(sqlite3_context *context, int argc, sqlite3_value **argv){
|
|||
}
|
||||
static void countFinalize(sqlite3_context *context){
|
||||
CountCtx *p;
|
||||
p = sqlite3_aggregate_context(context, sizeof(*p));
|
||||
p = sqlite3_aggregate_context(context, 0);
|
||||
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.
|
||||
*/
|
||||
|
@ -920,11 +928,13 @@ static void minmaxStep(sqlite3_context *context, int argc, sqlite3_value **argv)
|
|||
}
|
||||
static void minMaxFinalize(sqlite3_context *context){
|
||||
sqlite3_value *pRes;
|
||||
pRes = (sqlite3_value *)sqlite3_aggregate_context(context, sizeof(Mem));
|
||||
if( pRes->flags ){
|
||||
sqlite3_result_value(context, pRes);
|
||||
pRes = (sqlite3_value *)sqlite3_aggregate_context(context, 0);
|
||||
if( pRes ){
|
||||
if( pRes->flags ){
|
||||
sqlite3_result_value(context, pRes);
|
||||
}
|
||||
sqlite3VdbeMemRelease(pRes);
|
||||
}
|
||||
sqlite3VdbeMemRelease(pRes);
|
||||
}
|
||||
|
||||
|
||||
|
@ -962,9 +972,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 +1043,76 @@ 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, int flagVal){
|
||||
FuncDef *pDef;
|
||||
pDef = sqlite3FindFunction(db, zName, strlen(zName), 2, SQLITE_UTF8, 0);
|
||||
if( pDef ){
|
||||
pDef->flags = flagVal;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** 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", SQLITE_FUNC_LIKE | SQLITE_FUNC_CASE);
|
||||
setLikeOptFlag(db, "like",
|
||||
caseSensitive ? (SQLITE_FUNC_LIKE | SQLITE_FUNC_CASE) : SQLITE_FUNC_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, int *pIsNocase, 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_LIKE)==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 );
|
||||
*pIsNocase = (pDef->flags & SQLITE_FUNC_CASE)==0;
|
||||
return 1;
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
** This file contains C code routines that are called by the parser
|
||||
** to handle INSERT statements in SQLite.
|
||||
**
|
||||
** $Id: insert.c,v 1.139 2005/06/12 21:35:52 drh Exp $
|
||||
** $Id: insert.c,v 1.143 2005/09/20 17:42:23 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
|
||||
|
@ -372,13 +372,13 @@ void sqlite3Insert(
|
|||
** of the program jumps to it. Create the temporary table, then jump
|
||||
** back up and execute the SELECT code above.
|
||||
*/
|
||||
sqlite3VdbeChangeP2(v, iInitCode, sqlite3VdbeCurrentAddr(v));
|
||||
sqlite3VdbeAddOp(v, OP_OpenTemp, srcTab, 0);
|
||||
sqlite3VdbeJumpHere(v, iInitCode);
|
||||
sqlite3VdbeAddOp(v, OP_OpenVirtual, srcTab, 0);
|
||||
sqlite3VdbeAddOp(v, OP_SetNumColumns, srcTab, nColumn);
|
||||
sqlite3VdbeAddOp(v, OP_Goto, 0, iSelectLoop);
|
||||
sqlite3VdbeResolveLabel(v, iCleanup);
|
||||
}else{
|
||||
sqlite3VdbeChangeP2(v, iInitCode, sqlite3VdbeCurrentAddr(v));
|
||||
sqlite3VdbeJumpHere(v, iInitCode);
|
||||
}
|
||||
}else{
|
||||
/* This is the case if the data for the INSERT is coming from a VALUES
|
||||
|
@ -470,8 +470,7 @@ void sqlite3Insert(
|
|||
*/
|
||||
if( db->flags & SQLITE_CountRows ){
|
||||
iCntMem = pParse->nMem++;
|
||||
sqlite3VdbeAddOp(v, OP_Integer, 0, 0);
|
||||
sqlite3VdbeAddOp(v, OP_MemStore, iCntMem, 1);
|
||||
sqlite3VdbeAddOp(v, OP_MemInt, 0, iCntMem);
|
||||
}
|
||||
|
||||
/* Open tables and indices if there are no row triggers */
|
||||
|
@ -817,7 +816,6 @@ void sqlite3GenerateConstraintChecks(
|
|||
Index *pIdx;
|
||||
int seenReplace = 0;
|
||||
int jumpInst1=0, jumpInst2;
|
||||
int contAddr;
|
||||
int hasTwoRowids = (isUpdate && rowidChng);
|
||||
|
||||
v = sqlite3GetVdbe(pParse);
|
||||
|
@ -867,7 +865,7 @@ void sqlite3GenerateConstraintChecks(
|
|||
break;
|
||||
}
|
||||
}
|
||||
sqlite3VdbeChangeP2(v, addr, sqlite3VdbeCurrentAddr(v));
|
||||
sqlite3VdbeJumpHere(v, addr);
|
||||
}
|
||||
|
||||
/* Test all CHECK constraints
|
||||
|
@ -921,10 +919,9 @@ void sqlite3GenerateConstraintChecks(
|
|||
break;
|
||||
}
|
||||
}
|
||||
contAddr = sqlite3VdbeCurrentAddr(v);
|
||||
sqlite3VdbeChangeP2(v, jumpInst2, contAddr);
|
||||
sqlite3VdbeJumpHere(v, jumpInst2);
|
||||
if( isUpdate ){
|
||||
sqlite3VdbeChangeP2(v, jumpInst1, contAddr);
|
||||
sqlite3VdbeJumpHere(v, jumpInst1);
|
||||
sqlite3VdbeAddOp(v, OP_Dup, nCol+1, 1);
|
||||
sqlite3VdbeAddOp(v, OP_MoveGe, base, 0);
|
||||
}
|
||||
|
@ -949,7 +946,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 */
|
||||
|
@ -1018,12 +1015,10 @@ void sqlite3GenerateConstraintChecks(
|
|||
break;
|
||||
}
|
||||
}
|
||||
contAddr = sqlite3VdbeCurrentAddr(v);
|
||||
assert( contAddr<(1<<24) );
|
||||
#if NULL_DISTINCT_FOR_UNIQUE
|
||||
sqlite3VdbeChangeP2(v, jumpInst1, contAddr | (1<<24));
|
||||
sqlite3VdbeJumpHere(v, jumpInst1);
|
||||
#endif
|
||||
sqlite3VdbeChangeP2(v, jumpInst2, contAddr);
|
||||
sqlite3VdbeJumpHere(v, jumpInst2);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1097,11 +1092,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: 158 */
|
||||
static int keywordCode(const char *z, int n){
|
||||
static const char zText[515] =
|
||||
static const char zText[535] =
|
||||
"ABORTABLEFTEMPORARYADDATABASELECTHENDEFAULTRANSACTIONATURALTER"
|
||||
"AISEACHECKEYAFTEREFERENCESCAPELSEXCEPTRIGGEREGEXPLAINITIALLYAND"
|
||||
"EFERRABLEXCLUSIVEXISTSTATEMENTATTACHAVINGLOBEFOREIGNOREINDEXAUTOINCREMENT"
|
||||
"BEGINNERENAMEBETWEENOTNULLIKEBYCASCADEFERREDELETECASECOLLATECOLUMN"
|
||||
"COMMITCONFLICTCONSTRAINTERSECTCREATECROSSCURRENT_DATECURRENT_TIMESTAMP"
|
||||
"RAGMATCHDESCDETACHDISTINCTDROPRIMARYFAILIMITFROMFULLGROUPDATE"
|
||||
"IMMEDIATEINSERTINSTEADINTOFFSETISNULLJOINORDEREPLACEOUTERESTRICT"
|
||||
"RIGHTROLLBACKROWHENUNIONUNIQUEUSINGVACUUMVALUESVIEWHERE";
|
||||
"AISEACHECKEYAFTEREFERENCESCAPELSEXCEPTRIGGEREGEXPLAINITIALLYANALYZE"
|
||||
"XCLUSIVEXISTSTATEMENTANDEFERRABLEATTACHAVINGLOBEFOREIGNOREINDEX"
|
||||
"AUTOINCREMENTBEGINNERENAMEBETWEENOTNULLIKEBYCASCADEFERREDELETE"
|
||||
"CASECASTCOLLATECOLUMNCOMMITCONFLICTCONSTRAINTERSECTCREATECROSS"
|
||||
"CURRENT_DATECURRENT_TIMESTAMPLANDESCDETACHDISTINCTDROPRAGMATCH"
|
||||
"FAILIMITFROMFULLGROUPDATEIMMEDIATEINSERTINSTEADINTOFFSETISNULL"
|
||||
"JOINORDEREPLACEOUTERESTRICTPRIMARYQUERYRIGHTROLLBACKROWHENUNION"
|
||||
"UNIQUEUSINGVACUUMVALUESVIEWHERE";
|
||||
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, 80, 106, 90, 0, 4, 0, 0, 113, 0, 83, 0, 0,
|
||||
94, 44, 76, 92, 0, 105, 108, 96, 0, 0, 10, 0, 0,
|
||||
112, 0, 109, 102, 0, 28, 48, 0, 41, 0, 0, 65, 71,
|
||||
0, 63, 19, 0, 104, 36, 103, 0, 107, 74, 0, 0, 33,
|
||||
0, 61, 37, 0, 8, 0, 114, 38, 12, 0, 77, 40, 25,
|
||||
66, 0, 0, 31, 81, 53, 30, 50, 20, 88, 0, 34, 0,
|
||||
75, 26, 0, 72, 0, 0, 0, 64, 47, 67, 22, 87, 29,
|
||||
69, 86, 0, 1, 0, 9, 100, 58, 18, 0, 111, 82, 98,
|
||||
54, 6, 85, 0, 0, 49, 93, 0, 101, 0, 70, 0, 0,
|
||||
15, 0, 115, 51, 56, 0, 2, 55, 0, 110,
|
||||
};
|
||||
static const unsigned char aNext[111] = {
|
||||
static const unsigned char aNext[115] = {
|
||||
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, 24, 60,
|
||||
21, 0, 79, 0, 0, 68, 0, 0, 84, 46, 0, 0, 0,
|
||||
0, 0, 0, 0, 39, 95, 97, 0, 0, 99, 0, 32, 0,
|
||||
14, 27, 78, 0, 57, 89, 0, 35, 0, 62, 0,
|
||||
};
|
||||
static const unsigned char aLen[111] = {
|
||||
static const unsigned char aLen[115] = {
|
||||
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, 4, 4, 6,
|
||||
8, 2, 4, 6, 5, 4, 5, 4, 4, 5, 6, 9, 6,
|
||||
7, 4, 2, 6, 3, 6, 4, 5, 7, 5, 8, 7, 5,
|
||||
5, 8, 3, 4, 5, 6, 5, 6, 6, 4, 5,
|
||||
};
|
||||
static const unsigned short int aOffset[111] = {
|
||||
static const unsigned short int aOffset[115] = {
|
||||
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, 352,
|
||||
358, 359, 366, 369, 373, 378, 381, 386, 390, 394, 397, 403, 412,
|
||||
418, 425, 428, 428, 431, 434, 440, 444, 448, 455, 459, 467, 474,
|
||||
479, 484, 492, 494, 498, 503, 509, 514, 520, 526, 529,
|
||||
};
|
||||
static const unsigned char aCode[111] = {
|
||||
static const unsigned char aCode[115] = {
|
||||
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_PLAN, TK_DESC, TK_DETACH, TK_DISTINCT, TK_IS,
|
||||
TK_DROP, TK_PRAGMA, TK_MATCH, TK_FAIL, TK_LIMIT,
|
||||
TK_FROM, TK_JOIN_KW, TK_GROUP, TK_UPDATE, TK_IMMEDIATE,
|
||||
TK_INSERT, TK_INSTEAD, TK_INTO, TK_OF, TK_OFFSET,
|
||||
TK_SET, TK_ISNULL, TK_JOIN, TK_ORDER, TK_REPLACE,
|
||||
TK_JOIN_KW, TK_RESTRICT, TK_PRIMARY, TK_QUERY, TK_JOIN_KW,
|
||||
TK_ROLLBACK, TK_ROW, TK_WHEN, TK_UNION, TK_UNIQUE,
|
||||
TK_USING, TK_VACUUM, TK_VALUES, TK_VIEW, TK_WHERE,
|
||||
};
|
||||
int h, i;
|
||||
if( n<2 ) return TK_ID;
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
** other files are for internal use by SQLite and should not be
|
||||
** accessed by users of the library.
|
||||
**
|
||||
** $Id: main.c,v 1.293 2005/05/26 16:23:34 drh Exp $
|
||||
** $Id: main.c,v 1.302 2005/09/17 15:20:27 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include "os.h"
|
||||
|
@ -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;
|
||||
|
@ -491,13 +509,14 @@ int sqlite3_create_function16(
|
|||
}
|
||||
#endif
|
||||
|
||||
#ifndef SQLITE_OMIT_TRACE
|
||||
/*
|
||||
** Register a trace function. The pArg from the previously registered trace
|
||||
** is returned.
|
||||
**
|
||||
** A NULL trace function means that no tracing is executes. A non-NULL
|
||||
** trace is a pointer to a function that is invoked at the start of each
|
||||
** sqlite3_exec().
|
||||
** SQL statement.
|
||||
*/
|
||||
void *sqlite3_trace(sqlite3 *db, void (*xTrace)(void*,const char*), void *pArg){
|
||||
void *pOld = db->pTraceArg;
|
||||
|
@ -505,6 +524,25 @@ void *sqlite3_trace(sqlite3 *db, void (*xTrace)(void*,const char*), void *pArg){
|
|||
db->pTraceArg = pArg;
|
||||
return pOld;
|
||||
}
|
||||
/*
|
||||
** Register a profile function. The pArg from the previously registered
|
||||
** profile function is returned.
|
||||
**
|
||||
** A NULL profile function means that no profiling is executes. A non-NULL
|
||||
** profile is a pointer to a function that is invoked at the conclusion of
|
||||
** each SQL statement that is run.
|
||||
*/
|
||||
void *sqlite3_profile(
|
||||
sqlite3 *db,
|
||||
void (*xProfile)(void*,const char*,sqlite_uint64),
|
||||
void *pArg
|
||||
){
|
||||
void *pOld = db->pProfileArg;
|
||||
db->xProfile = xProfile;
|
||||
db->pProfileArg = pArg;
|
||||
return pOld;
|
||||
}
|
||||
#endif /* SQLITE_OMIT_TRACE */
|
||||
|
||||
/*** EXPERIMENTAL ***
|
||||
**
|
||||
|
@ -530,11 +568,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:
|
||||
**
|
||||
|
@ -676,6 +714,7 @@ static int openDatabase(
|
|||
){
|
||||
sqlite3 *db;
|
||||
int rc, i;
|
||||
CollSeq *pColl;
|
||||
|
||||
/* Allocate the sqlite data structure */
|
||||
db = sqliteMalloc( sizeof(sqlite3) );
|
||||
|
@ -712,6 +751,13 @@ static int openDatabase(
|
|||
/* Also add a UTF-8 case-insensitive collation sequence. */
|
||||
sqlite3_create_collation(db, "NOCASE", SQLITE_UTF8, 0, nocaseCollatingFunc);
|
||||
|
||||
/* Set flags on the built-in collating sequences */
|
||||
db->pDfltColl->type = SQLITE_COLL_BINARY;
|
||||
pColl = sqlite3FindCollSeq(db, SQLITE_UTF8, "NOCASE", 6, 0);
|
||||
if( pColl ){
|
||||
pColl->type = SQLITE_COLL_NOCASE;
|
||||
}
|
||||
|
||||
/* Open the backend database driver */
|
||||
rc = sqlite3BtreeFactory(db, zFilename, 0, MAX_PAGES, &db->aDb[0].pBt);
|
||||
if( rc!=SQLITE_OK ){
|
||||
|
@ -829,7 +875,7 @@ int sqlite3_reset(sqlite3_stmt *pStmt){
|
|||
rc = SQLITE_OK;
|
||||
}else{
|
||||
rc = sqlite3VdbeReset((Vdbe*)pStmt);
|
||||
sqlite3VdbeMakeReady((Vdbe*)pStmt, -1, 0, 0, 0, 0);
|
||||
sqlite3VdbeMakeReady((Vdbe*)pStmt, -1, 0, 0, 0);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
@ -883,7 +929,7 @@ int sqlite3_create_collation(
|
|||
|
||||
pColl = sqlite3FindCollSeq(db, (u8)enc, zName, strlen(zName), 1);
|
||||
if( 0==pColl ){
|
||||
rc = SQLITE_NOMEM;
|
||||
rc = SQLITE_NOMEM;
|
||||
}else{
|
||||
pColl->xCmp = xCompare;
|
||||
pColl->pUser = pCtx;
|
||||
|
@ -1001,3 +1047,14 @@ recover_out:
|
|||
int sqlite3_get_autocommit(sqlite3 *db){
|
||||
return db->autoCommit;
|
||||
}
|
||||
|
||||
#ifdef SQLITE_DEBUG
|
||||
/*
|
||||
** The following routine is subtituted for constant SQLITE_CORRUPT in
|
||||
** debugging builds. This provides a way to set a breakpoint for when
|
||||
** corruption is first detected.
|
||||
*/
|
||||
int sqlite3Corrupt(void){
|
||||
return SQLITE_CORRUPT;
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -6,130 +6,135 @@ const char *const sqlite3OpcodeNames[] = { "?",
|
|||
/* 2 */ "Column",
|
||||
/* 3 */ "SetCookie",
|
||||
/* 4 */ "IfMemPos",
|
||||
/* 5 */ "MoveGt",
|
||||
/* 6 */ "AggFocus",
|
||||
/* 5 */ "Sequence",
|
||||
/* 6 */ "MoveGt",
|
||||
/* 7 */ "RowKey",
|
||||
/* 8 */ "AggNext",
|
||||
/* 9 */ "OpenWrite",
|
||||
/* 10 */ "If",
|
||||
/* 8 */ "OpenWrite",
|
||||
/* 9 */ "If",
|
||||
/* 10 */ "ToInt",
|
||||
/* 11 */ "Pop",
|
||||
/* 12 */ "AggContextPush",
|
||||
/* 13 */ "CollSeq",
|
||||
/* 14 */ "OpenRead",
|
||||
/* 15 */ "Expire",
|
||||
/* 16 */ "SortReset",
|
||||
/* 17 */ "AutoCommit",
|
||||
/* 18 */ "Sort",
|
||||
/* 19 */ "ListRewind",
|
||||
/* 20 */ "IntegrityCk",
|
||||
/* 21 */ "SortInsert",
|
||||
/* 22 */ "Function",
|
||||
/* 23 */ "Noop",
|
||||
/* 24 */ "Return",
|
||||
/* 25 */ "NewRowid",
|
||||
/* 26 */ "Variable",
|
||||
/* 27 */ "String",
|
||||
/* 28 */ "ParseSchema",
|
||||
/* 29 */ "AggFunc",
|
||||
/* 30 */ "Close",
|
||||
/* 31 */ "ListWrite",
|
||||
/* 32 */ "CreateIndex",
|
||||
/* 33 */ "IsUnique",
|
||||
/* 34 */ "IdxIsNull",
|
||||
/* 35 */ "NotFound",
|
||||
/* 36 */ "MustBeInt",
|
||||
/* 37 */ "Halt",
|
||||
/* 38 */ "Rowid",
|
||||
/* 39 */ "IdxLT",
|
||||
/* 40 */ "AddImm",
|
||||
/* 41 */ "Statement",
|
||||
/* 42 */ "RowData",
|
||||
/* 43 */ "MemMax",
|
||||
/* 44 */ "Push",
|
||||
/* 45 */ "NotExists",
|
||||
/* 46 */ "OpenTemp",
|
||||
/* 47 */ "MemIncr",
|
||||
/* 48 */ "Gosub",
|
||||
/* 49 */ "AggSet",
|
||||
/* 50 */ "Integer",
|
||||
/* 51 */ "SortNext",
|
||||
/* 52 */ "Prev",
|
||||
/* 53 */ "CreateTable",
|
||||
/* 54 */ "Last",
|
||||
/* 55 */ "IdxRowid",
|
||||
/* 56 */ "ResetCount",
|
||||
/* 57 */ "Callback",
|
||||
/* 58 */ "ContextPush",
|
||||
/* 59 */ "DropTrigger",
|
||||
/* 60 */ "DropIndex",
|
||||
/* 61 */ "IdxGE",
|
||||
/* 62 */ "Or",
|
||||
/* 63 */ "And",
|
||||
/* 64 */ "Not",
|
||||
/* 65 */ "IdxDelete",
|
||||
/* 66 */ "Vacuum",
|
||||
/* 67 */ "MoveLe",
|
||||
/* 68 */ "IsNull",
|
||||
/* 69 */ "NotNull",
|
||||
/* 70 */ "Ne",
|
||||
/* 71 */ "Eq",
|
||||
/* 72 */ "Gt",
|
||||
/* 73 */ "Le",
|
||||
/* 74 */ "Lt",
|
||||
/* 75 */ "Ge",
|
||||
/* 76 */ "IfNot",
|
||||
/* 77 */ "BitAnd",
|
||||
/* 78 */ "BitOr",
|
||||
/* 79 */ "ShiftLeft",
|
||||
/* 80 */ "ShiftRight",
|
||||
/* 81 */ "Add",
|
||||
/* 82 */ "Subtract",
|
||||
/* 83 */ "Multiply",
|
||||
/* 84 */ "Divide",
|
||||
/* 85 */ "Remainder",
|
||||
/* 86 */ "Concat",
|
||||
/* 87 */ "Negative",
|
||||
/* 88 */ "DropTable",
|
||||
/* 89 */ "BitNot",
|
||||
/* 90 */ "String8",
|
||||
/* 91 */ "MakeRecord",
|
||||
/* 92 */ "Delete",
|
||||
/* 93 */ "AggContextPop",
|
||||
/* 94 */ "ListRead",
|
||||
/* 95 */ "ListReset",
|
||||
/* 96 */ "Dup",
|
||||
/* 97 */ "Goto",
|
||||
/* 98 */ "Clear",
|
||||
/* 99 */ "IdxGT",
|
||||
/* 100 */ "MoveLt",
|
||||
/* 101 */ "VerifyCookie",
|
||||
/* 102 */ "Pull",
|
||||
/* 103 */ "SetNumColumns",
|
||||
/* 104 */ "AbsValue",
|
||||
/* 105 */ "Transaction",
|
||||
/* 106 */ "AggGet",
|
||||
/* 107 */ "ContextPop",
|
||||
/* 108 */ "Next",
|
||||
/* 109 */ "AggInit",
|
||||
/* 110 */ "IdxInsert",
|
||||
/* 111 */ "Distinct",
|
||||
/* 112 */ "AggReset",
|
||||
/* 113 */ "Insert",
|
||||
/* 114 */ "Destroy",
|
||||
/* 115 */ "ReadCookie",
|
||||
/* 116 */ "ForceInt",
|
||||
/* 117 */ "OpenPseudo",
|
||||
/* 118 */ "Null",
|
||||
/* 119 */ "Blob",
|
||||
/* 120 */ "MemStore",
|
||||
/* 121 */ "Rewind",
|
||||
/* 122 */ "MoveGe",
|
||||
/* 12 */ "CollSeq",
|
||||
/* 13 */ "OpenRead",
|
||||
/* 14 */ "Expire",
|
||||
/* 15 */ "AutoCommit",
|
||||
/* 16 */ "IntegrityCk",
|
||||
/* 17 */ "Sort",
|
||||
/* 18 */ "Function",
|
||||
/* 19 */ "Noop",
|
||||
/* 20 */ "Return",
|
||||
/* 21 */ "NewRowid",
|
||||
/* 22 */ "Variable",
|
||||
/* 23 */ "String",
|
||||
/* 24 */ "ParseSchema",
|
||||
/* 25 */ "Close",
|
||||
/* 26 */ "CreateIndex",
|
||||
/* 27 */ "IsUnique",
|
||||
/* 28 */ "IdxIsNull",
|
||||
/* 29 */ "NotFound",
|
||||
/* 30 */ "Int64",
|
||||
/* 31 */ "MustBeInt",
|
||||
/* 32 */ "Halt",
|
||||
/* 33 */ "Rowid",
|
||||
/* 34 */ "IdxLT",
|
||||
/* 35 */ "AddImm",
|
||||
/* 36 */ "Statement",
|
||||
/* 37 */ "RowData",
|
||||
/* 38 */ "MemMax",
|
||||
/* 39 */ "Push",
|
||||
/* 40 */ "NotExists",
|
||||
/* 41 */ "MemIncr",
|
||||
/* 42 */ "Gosub",
|
||||
/* 43 */ "Integer",
|
||||
/* 44 */ "ToNumeric",
|
||||
/* 45 */ "MemInt",
|
||||
/* 46 */ "Prev",
|
||||
/* 47 */ "CreateTable",
|
||||
/* 48 */ "Last",
|
||||
/* 49 */ "IdxRowid",
|
||||
/* 50 */ "MakeIdxRec",
|
||||
/* 51 */ "ResetCount",
|
||||
/* 52 */ "FifoWrite",
|
||||
/* 53 */ "Callback",
|
||||
/* 54 */ "ContextPush",
|
||||
/* 55 */ "DropTrigger",
|
||||
/* 56 */ "DropIndex",
|
||||
/* 57 */ "IdxGE",
|
||||
/* 58 */ "IdxDelete",
|
||||
/* 59 */ "Vacuum",
|
||||
/* 60 */ "MoveLe",
|
||||
/* 61 */ "IfNot",
|
||||
/* 62 */ "DropTable",
|
||||
/* 63 */ "MakeRecord",
|
||||
/* 64 */ "ToBlob",
|
||||
/* 65 */ "Delete",
|
||||
/* 66 */ "AggFinal",
|
||||
/* 67 */ "Or",
|
||||
/* 68 */ "And",
|
||||
/* 69 */ "Not",
|
||||
/* 70 */ "Dup",
|
||||
/* 71 */ "Goto",
|
||||
/* 72 */ "FifoRead",
|
||||
/* 73 */ "IsNull",
|
||||
/* 74 */ "NotNull",
|
||||
/* 75 */ "Ne",
|
||||
/* 76 */ "Eq",
|
||||
/* 77 */ "Gt",
|
||||
/* 78 */ "Le",
|
||||
/* 79 */ "Lt",
|
||||
/* 80 */ "Ge",
|
||||
/* 81 */ "Clear",
|
||||
/* 82 */ "BitAnd",
|
||||
/* 83 */ "BitOr",
|
||||
/* 84 */ "ShiftLeft",
|
||||
/* 85 */ "ShiftRight",
|
||||
/* 86 */ "Add",
|
||||
/* 87 */ "Subtract",
|
||||
/* 88 */ "Multiply",
|
||||
/* 89 */ "Divide",
|
||||
/* 90 */ "Remainder",
|
||||
/* 91 */ "Concat",
|
||||
/* 92 */ "Negative",
|
||||
/* 93 */ "IdxGT",
|
||||
/* 94 */ "BitNot",
|
||||
/* 95 */ "String8",
|
||||
/* 96 */ "MoveLt",
|
||||
/* 97 */ "VerifyCookie",
|
||||
/* 98 */ "AggStep",
|
||||
/* 99 */ "Pull",
|
||||
/* 100 */ "ToText",
|
||||
/* 101 */ "SetNumColumns",
|
||||
/* 102 */ "AbsValue",
|
||||
/* 103 */ "Transaction",
|
||||
/* 104 */ "ContextPop",
|
||||
/* 105 */ "Next",
|
||||
/* 106 */ "IdxInsert",
|
||||
/* 107 */ "Distinct",
|
||||
/* 108 */ "Insert",
|
||||
/* 109 */ "Destroy",
|
||||
/* 110 */ "ReadCookie",
|
||||
/* 111 */ "ForceInt",
|
||||
/* 112 */ "LoadAnalysis",
|
||||
/* 113 */ "OpenVirtual",
|
||||
/* 114 */ "Explain",
|
||||
/* 115 */ "OpenPseudo",
|
||||
/* 116 */ "Null",
|
||||
/* 117 */ "Blob",
|
||||
/* 118 */ "MemStore",
|
||||
/* 119 */ "Rewind",
|
||||
/* 120 */ "MoveGe",
|
||||
/* 121 */ "MemMove",
|
||||
/* 122 */ "MemNull",
|
||||
/* 123 */ "Found",
|
||||
/* 124 */ "NullRow",
|
||||
/* 125 */ "NotUsed_125",
|
||||
/* 126 */ "NotUsed_126",
|
||||
/* 127 */ "NotUsed_127",
|
||||
/* 128 */ "Real",
|
||||
/* 129 */ "HexBlob",
|
||||
/* 128 */ "NotUsed_128",
|
||||
/* 129 */ "NotUsed_129",
|
||||
/* 130 */ "NotUsed_130",
|
||||
/* 131 */ "NotUsed_131",
|
||||
/* 132 */ "NotUsed_132",
|
||||
/* 133 */ "Real",
|
||||
/* 134 */ "HexBlob",
|
||||
};
|
||||
#endif
|
||||
|
|
|
@ -1,129 +1,129 @@
|
|||
/* 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 134 /* 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_MoveGt 5
|
||||
#define OP_Ge 75 /* same as TK_GE */
|
||||
#define OP_AggFocus 6
|
||||
#define OP_Real 133 /* same as TK_FLOAT */
|
||||
#define OP_Sequence 5
|
||||
#define OP_MoveGt 6
|
||||
#define OP_Ge 80 /* same as TK_GE */
|
||||
#define OP_RowKey 7
|
||||
#define OP_AggNext 8
|
||||
#define OP_Eq 71 /* same as TK_EQ */
|
||||
#define OP_OpenWrite 9
|
||||
#define OP_NotNull 69 /* same as TK_NOTNULL */
|
||||
#define OP_If 10
|
||||
#define OP_String8 90 /* same as TK_STRING */
|
||||
#define OP_Eq 76 /* same as TK_EQ */
|
||||
#define OP_OpenWrite 8
|
||||
#define OP_NotNull 74 /* same as TK_NOTNULL */
|
||||
#define OP_If 9
|
||||
#define OP_ToInt 10
|
||||
#define OP_String8 95 /* 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_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_Noop 23
|
||||
#define OP_Return 24
|
||||
#define OP_Remainder 85 /* same as TK_REM */
|
||||
#define OP_NewRowid 25
|
||||
#define OP_Multiply 83 /* 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_MustBeInt 36
|
||||
#define OP_Halt 37
|
||||
#define OP_Rowid 38
|
||||
#define OP_IdxLT 39
|
||||
#define OP_AddImm 40
|
||||
#define OP_Statement 41
|
||||
#define OP_RowData 42
|
||||
#define OP_MemMax 43
|
||||
#define OP_Push 44
|
||||
#define OP_Or 62 /* 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_SortNext 51
|
||||
#define OP_Prev 52
|
||||
#define OP_Concat 86 /* same as TK_CONCAT */
|
||||
#define OP_BitAnd 77 /* same as TK_BITAND */
|
||||
#define OP_CreateTable 53
|
||||
#define OP_Last 54
|
||||
#define OP_IsNull 68 /* 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_CollSeq 12
|
||||
#define OP_OpenRead 13
|
||||
#define OP_Expire 14
|
||||
#define OP_AutoCommit 15
|
||||
#define OP_Gt 77 /* same as TK_GT */
|
||||
#define OP_IntegrityCk 16
|
||||
#define OP_Sort 17
|
||||
#define OP_Function 18
|
||||
#define OP_And 68 /* same as TK_AND */
|
||||
#define OP_Subtract 87 /* same as TK_MINUS */
|
||||
#define OP_Noop 19
|
||||
#define OP_Return 20
|
||||
#define OP_Remainder 90 /* same as TK_REM */
|
||||
#define OP_NewRowid 21
|
||||
#define OP_Multiply 88 /* same as TK_STAR */
|
||||
#define OP_Variable 22
|
||||
#define OP_String 23
|
||||
#define OP_ParseSchema 24
|
||||
#define OP_Close 25
|
||||
#define OP_CreateIndex 26
|
||||
#define OP_IsUnique 27
|
||||
#define OP_IdxIsNull 28
|
||||
#define OP_NotFound 29
|
||||
#define OP_Int64 30
|
||||
#define OP_MustBeInt 31
|
||||
#define OP_Halt 32
|
||||
#define OP_Rowid 33
|
||||
#define OP_IdxLT 34
|
||||
#define OP_AddImm 35
|
||||
#define OP_Statement 36
|
||||
#define OP_RowData 37
|
||||
#define OP_MemMax 38
|
||||
#define OP_Push 39
|
||||
#define OP_Or 67 /* same as TK_OR */
|
||||
#define OP_NotExists 40
|
||||
#define OP_MemIncr 41
|
||||
#define OP_Gosub 42
|
||||
#define OP_Divide 89 /* same as TK_SLASH */
|
||||
#define OP_Integer 43
|
||||
#define OP_ToNumeric 44
|
||||
#define OP_MemInt 45
|
||||
#define OP_Prev 46
|
||||
#define OP_Concat 91 /* same as TK_CONCAT */
|
||||
#define OP_BitAnd 82 /* same as TK_BITAND */
|
||||
#define OP_CreateTable 47
|
||||
#define OP_Last 48
|
||||
#define OP_IsNull 73 /* same as TK_ISNULL */
|
||||
#define OP_IdxRowid 49
|
||||
#define OP_MakeIdxRec 50
|
||||
#define OP_ShiftRight 85 /* same as TK_RSHIFT */
|
||||
#define OP_ResetCount 51
|
||||
#define OP_FifoWrite 52
|
||||
#define OP_Callback 53
|
||||
#define OP_ContextPush 54
|
||||
#define OP_DropTrigger 55
|
||||
#define OP_DropIndex 56
|
||||
#define OP_IdxGE 57
|
||||
#define OP_IdxDelete 58
|
||||
#define OP_Vacuum 59
|
||||
#define OP_MoveLe 60
|
||||
#define OP_IfNot 61
|
||||
#define OP_DropTable 62
|
||||
#define OP_MakeRecord 63
|
||||
#define OP_ToBlob 64
|
||||
#define OP_Delete 65
|
||||
#define OP_AggFinal 66
|
||||
#define OP_ShiftLeft 84 /* same as TK_LSHIFT */
|
||||
#define OP_Dup 70
|
||||
#define OP_Goto 71
|
||||
#define OP_FifoRead 72
|
||||
#define OP_Clear 81
|
||||
#define OP_IdxGT 93
|
||||
#define OP_MoveLt 96
|
||||
#define OP_Le 78 /* same as TK_LE */
|
||||
#define OP_VerifyCookie 97
|
||||
#define OP_AggStep 98
|
||||
#define OP_Pull 99
|
||||
#define OP_ToText 100
|
||||
#define OP_Not 69 /* same as TK_NOT */
|
||||
#define OP_SetNumColumns 101
|
||||
#define OP_AbsValue 102
|
||||
#define OP_Transaction 103
|
||||
#define OP_Negative 92 /* same as TK_UMINUS */
|
||||
#define OP_Ne 75 /* same as TK_NE */
|
||||
#define OP_ContextPop 104
|
||||
#define OP_BitOr 83 /* same as TK_BITOR */
|
||||
#define OP_Next 105
|
||||
#define OP_IdxInsert 106
|
||||
#define OP_Distinct 107
|
||||
#define OP_Lt 79 /* same as TK_LT */
|
||||
#define OP_Insert 108
|
||||
#define OP_Destroy 109
|
||||
#define OP_ReadCookie 110
|
||||
#define OP_ForceInt 111
|
||||
#define OP_LoadAnalysis 112
|
||||
#define OP_OpenVirtual 113
|
||||
#define OP_Explain 114
|
||||
#define OP_OpenPseudo 115
|
||||
#define OP_Null 116
|
||||
#define OP_Blob 117
|
||||
#define OP_Add 86 /* same as TK_PLUS */
|
||||
#define OP_MemStore 118
|
||||
#define OP_Rewind 119
|
||||
#define OP_MoveGe 120
|
||||
#define OP_BitNot 94 /* same as TK_BITNOT */
|
||||
#define OP_MemMove 121
|
||||
#define OP_MemNull 122
|
||||
#define OP_Found 123
|
||||
#define OP_NullRow 124
|
||||
|
||||
|
@ -131,14 +131,19 @@
|
|||
#define OP_NotUsed_125 125
|
||||
#define OP_NotUsed_126 126
|
||||
#define OP_NotUsed_127 127
|
||||
#define OP_NotUsed_128 128
|
||||
#define OP_NotUsed_129 129
|
||||
#define OP_NotUsed_130 130
|
||||
#define OP_NotUsed_131 131
|
||||
#define OP_NotUsed_132 132
|
||||
|
||||
#define NOPUSH_MASK_0 65400
|
||||
#define NOPUSH_MASK_1 61871
|
||||
#define NOPUSH_MASK_2 64446
|
||||
#define NOPUSH_MASK_3 65363
|
||||
#define NOPUSH_MASK_4 65535
|
||||
#define NOPUSH_MASK_5 46015
|
||||
#define NOPUSH_MASK_6 64254
|
||||
#define NOPUSH_MASK_7 7987
|
||||
#define NOPUSH_MASK_0 65368
|
||||
#define NOPUSH_MASK_1 47898
|
||||
#define NOPUSH_MASK_2 22493
|
||||
#define NOPUSH_MASK_3 32761
|
||||
#define NOPUSH_MASK_4 65215
|
||||
#define NOPUSH_MASK_5 30719
|
||||
#define NOPUSH_MASK_6 40895
|
||||
#define NOPUSH_MASK_7 6603
|
||||
#define NOPUSH_MASK_8 0
|
||||
#define NOPUSH_MASK_9 0
|
||||
|
|
|
@ -171,8 +171,13 @@
|
|||
** 1GB boundary.
|
||||
**
|
||||
*/
|
||||
#ifndef SQLITE_TEST
|
||||
#define PENDING_BYTE 0x40000000 /* First byte past the 1GB boundary */
|
||||
/* #define PENDING_BYTE 0x5400 // Page 22 - for testing */
|
||||
#else
|
||||
extern unsigned int sqlite3_pending_byte;
|
||||
#define PENDING_BYTE sqlite3_pending_byte
|
||||
#endif
|
||||
|
||||
#define RESERVED_BYTE (PENDING_BYTE+1)
|
||||
#define SHARED_FIRST (PENDING_BYTE+2)
|
||||
#define SHARED_SIZE 510
|
||||
|
@ -191,7 +196,7 @@ int sqlite3OsClose(OsFile*);
|
|||
int sqlite3OsRead(OsFile*, void*, int amt);
|
||||
int sqlite3OsWrite(OsFile*, const void*, int amt);
|
||||
int sqlite3OsSeek(OsFile*, i64 offset);
|
||||
int sqlite3OsSync(OsFile*);
|
||||
int sqlite3OsSync(OsFile*, int);
|
||||
int sqlite3OsTruncate(OsFile*, i64 size);
|
||||
int sqlite3OsFileSize(OsFile*, i64 *pSize);
|
||||
char *sqlite3OsFullPathname(const char*);
|
||||
|
|
|
@ -28,6 +28,14 @@
|
|||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* When testing, this global variable stores the location of the
|
||||
* pending-byte in the database file.
|
||||
*/
|
||||
#ifdef SQLITE_TEST
|
||||
unsigned int sqlite3_pending_byte = 0x40000000;
|
||||
#endif
|
||||
|
||||
int sqlite3_os_trace = 0;
|
||||
#ifdef SQLITE_DEBUG
|
||||
static int last_page = 0;
|
||||
|
@ -82,6 +90,7 @@ static unsigned int elapse;
|
|||
#ifdef SQLITE_TEST
|
||||
int sqlite3_io_error_pending = 0;
|
||||
int sqlite3_diskfull_pending = 0;
|
||||
int sqlite3_diskfull = 0;
|
||||
#define SimulateIOError(A) \
|
||||
if( sqlite3_io_error_pending ) \
|
||||
if( sqlite3_io_error_pending-- == 1 ){ local_ioerr(); return A; }
|
||||
|
@ -89,8 +98,15 @@ static void local_ioerr(){
|
|||
sqlite3_io_error_pending = 0; /* Really just a place to set a breakpoint */
|
||||
}
|
||||
#define SimulateDiskfullError \
|
||||
if( sqlite3_diskfull_pending ) \
|
||||
if( sqlite3_diskfull_pending-- == 1 ){ local_ioerr(); return SQLITE_FULL; }
|
||||
if( sqlite3_diskfull_pending ){ \
|
||||
if( sqlite3_diskfull_pending == 1 ){ \
|
||||
local_ioerr(); \
|
||||
sqlite3_diskfull = 1; \
|
||||
return SQLITE_FULL; \
|
||||
}else{ \
|
||||
sqlite3_diskfull_pending--; \
|
||||
} \
|
||||
}
|
||||
#else
|
||||
#define SimulateIOError(A)
|
||||
#define SimulateDiskfullError
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
|
||||
|
||||
#include <time.h>
|
||||
#include <sys/time.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
|
||||
|
@ -56,25 +57,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 +276,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 +514,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 +566,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 +602,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 +647,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 ){
|
||||
|
@ -696,6 +772,9 @@ int sqlite3OsWrite(OsFile *id, const void *pBuf, int amt){
|
|||
int sqlite3OsSeek(OsFile *id, i64 offset){
|
||||
assert( id->isOpen );
|
||||
SEEK(offset/1024 + 1);
|
||||
#ifdef SQLITE_TEST
|
||||
if( offset ) SimulateDiskfullError
|
||||
#endif
|
||||
lseek(id->h, offset, SEEK_SET);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
@ -721,7 +800,7 @@ int sqlite3_fullsync_count = 0;
|
|||
** enabled, however, since with SQLITE_NO_SYNC enabled, an OS crash
|
||||
** or power failure will likely corrupt the database file.
|
||||
*/
|
||||
static int full_fsync(int fd, int fullSync){
|
||||
static int full_fsync(int fd, int fullSync, int dataOnly){
|
||||
int rc;
|
||||
|
||||
/* Record the number of times that we do a normal fsync() and
|
||||
|
@ -749,8 +828,15 @@ static int full_fsync(int fd, int fullSync){
|
|||
/* If the FULLSYNC failed, try to do a normal fsync() */
|
||||
if( rc ) rc = fsync(fd);
|
||||
|
||||
#else
|
||||
rc = fsync(fd);
|
||||
#else /* if !defined(F_FULLSYNC) */
|
||||
#if defined(_POSIX_SYNCHRONIZED_IO) && _POSIX_SYNCHRONIZED_IO>0
|
||||
if( dataOnly ){
|
||||
rc = fdatasync(fd);
|
||||
}else
|
||||
#endif /* _POSIX_SYNCHRONIZED_IO > 0 */
|
||||
{
|
||||
rc = fsync(fd);
|
||||
}
|
||||
#endif /* defined(F_FULLFSYNC) */
|
||||
#endif /* defined(SQLITE_NO_SYNC) */
|
||||
|
||||
|
@ -760,6 +846,10 @@ static int full_fsync(int fd, int fullSync){
|
|||
/*
|
||||
** Make sure all writes to a particular file are committed to disk.
|
||||
**
|
||||
** If dataOnly==0 then both the file itself and its metadata (file
|
||||
** size, access time, etc) are synced. If dataOnly!=0 then only the
|
||||
** file data is synced.
|
||||
**
|
||||
** Under Unix, also make sure that the directory entry for the file
|
||||
** has been created by fsync-ing the directory that contains the file.
|
||||
** If we do not do this and we encounter a power failure, the directory
|
||||
|
@ -768,16 +858,16 @@ static int full_fsync(int fd, int fullSync){
|
|||
** the directory entry for the journal was never created) and the transaction
|
||||
** will not roll back - possibly leading to database corruption.
|
||||
*/
|
||||
int sqlite3OsSync(OsFile *id){
|
||||
int sqlite3OsSync(OsFile *id, int dataOnly){
|
||||
assert( id->isOpen );
|
||||
SimulateIOError(SQLITE_IOERR);
|
||||
TRACE2("SYNC %-3d\n", id->h);
|
||||
if( full_fsync(id->h, id->fullSync) ){
|
||||
if( full_fsync(id->h, id->fullSync, dataOnly) ){
|
||||
return SQLITE_IOERR;
|
||||
}
|
||||
if( id->dirfd>=0 ){
|
||||
TRACE2("DIRSYNC %-3d\n", id->dirfd);
|
||||
full_fsync(id->dirfd, id->fullSync);
|
||||
full_fsync(id->dirfd, id->fullSync, 0);
|
||||
close(id->dirfd); /* Only need to sync once, so close the directory */
|
||||
id->dirfd = -1; /* when we are done. */
|
||||
}
|
||||
|
@ -839,6 +929,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 +1047,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 +1094,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 +1130,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 +1203,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 +1228,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 +1246,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 +1280,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 +1293,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 */
|
||||
|
@ -1221,10 +1325,14 @@ char *sqlite3OsFullPathname(const char *zRelative){
|
|||
if( zRelative[0]=='/' ){
|
||||
sqlite3SetString(&zFull, zRelative, (char*)0);
|
||||
}else{
|
||||
char zBuf[5000];
|
||||
char *zBuf = sqliteMalloc(5000);
|
||||
if( zBuf==0 ){
|
||||
return 0;
|
||||
}
|
||||
zBuf[0] = 0;
|
||||
sqlite3SetString(&zFull, getcwd(zBuf, sizeof(zBuf)), "/", zRelative,
|
||||
sqlite3SetString(&zFull, getcwd(zBuf, 5000), "/", zRelative,
|
||||
(char*)0);
|
||||
sqliteFree(zBuf);
|
||||
}
|
||||
return zFull;
|
||||
}
|
||||
|
@ -1331,9 +1439,16 @@ int sqlite3_current_time = 0;
|
|||
** return 0. Return 1 if the time and date cannot be found.
|
||||
*/
|
||||
int sqlite3OsCurrentTime(double *prNow){
|
||||
#ifdef NO_GETTOD
|
||||
time_t t;
|
||||
time(&t);
|
||||
*prNow = t/86400.0 + 2440587.5;
|
||||
#else
|
||||
struct timeval sNow;
|
||||
struct timezone sTz; /* Not used */
|
||||
gettimeofday(&sNow, &sTz);
|
||||
*prNow = 2440587.5 + sNow.tv_sec/86400.0 + sNow.tv_usec/86400000000.0;
|
||||
#endif
|
||||
#ifdef SQLITE_TEST
|
||||
if( sqlite3_current_time ){
|
||||
*prNow = sqlite3_current_time/86400.0 + 2440587.5;
|
||||
|
|
|
@ -1,102 +0,0 @@
|
|||
/*
|
||||
** 2004 May 22
|
||||
**
|
||||
** 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 header file defined OS-specific features for Unix.
|
||||
*/
|
||||
#ifndef _SQLITE_OS_UNIX_H_
|
||||
#define _SQLITE_OS_UNIX_H_
|
||||
|
||||
/*
|
||||
** Helpful hint: To get this to compile on HP/UX, add -D_INCLUDE_POSIX_SOURCE
|
||||
** to the compiler command line.
|
||||
*/
|
||||
|
||||
/*
|
||||
** These #defines should enable >2GB file support on Posix if the
|
||||
** underlying operating system supports it. If the OS lacks
|
||||
** large file support, or if the OS is windows, these should be no-ops.
|
||||
**
|
||||
** Large file support can be disabled using the -DSQLITE_DISABLE_LFS switch
|
||||
** on the compiler command line. This is necessary if you are compiling
|
||||
** on a recent machine (ex: RedHat 7.2) but you want your code to work
|
||||
** on an older machine (ex: RedHat 6.0). If you compile on RedHat 7.2
|
||||
** without this option, LFS is enable. But LFS does not exist in the kernel
|
||||
** in RedHat 6.0, so the code won't work. Hence, for maximum binary
|
||||
** portability you should omit LFS.
|
||||
**
|
||||
** Similar is true for MacOS. LFS is only supported on MacOS 9 and later.
|
||||
*/
|
||||
#ifndef SQLITE_DISABLE_LFS
|
||||
# define _LARGE_FILE 1
|
||||
# ifndef _FILE_OFFSET_BITS
|
||||
# define _FILE_OFFSET_BITS 64
|
||||
# endif
|
||||
# define _LARGEFILE_SOURCE 1
|
||||
#endif
|
||||
|
||||
/*
|
||||
** standard include files.
|
||||
*/
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/*
|
||||
** The OsFile structure is a operating-system independing representation
|
||||
** of an open file handle. It is defined differently for each architecture.
|
||||
**
|
||||
** This is the definition for Unix.
|
||||
**
|
||||
** OsFile.locktype takes one of the values SHARED_LOCK, RESERVED_LOCK,
|
||||
** PENDING_LOCK or EXCLUSIVE_LOCK.
|
||||
*/
|
||||
typedef struct OsFile OsFile;
|
||||
struct OsFile {
|
||||
struct Pager *pPager; /* The pager that owns this OsFile. Might be 0 */
|
||||
struct openCnt *pOpen; /* Info about all open fd's on this inode */
|
||||
struct lockInfo *pLock; /* Info about locks on this inode */
|
||||
int h; /* The file descriptor */
|
||||
unsigned char locktype; /* The type of lock held on this fd */
|
||||
unsigned char isOpen; /* True if needs to be closed */
|
||||
unsigned char fullSync; /* Use F_FULLSYNC if available */
|
||||
int dirfd; /* File descriptor for the directory */
|
||||
};
|
||||
|
||||
/*
|
||||
** A macro to set the OsFile.fullSync flag, if it exists.
|
||||
*/
|
||||
#define SET_FULLSYNC(x,y) ((x).fullSync = (y))
|
||||
|
||||
/*
|
||||
** Maximum number of characters in a temporary file name
|
||||
*/
|
||||
#define SQLITE_TEMPNAME_SIZE 200
|
||||
|
||||
/*
|
||||
** Minimum interval supported by sqlite3OsSleep().
|
||||
*/
|
||||
#if defined(HAVE_USLEEP) && HAVE_USLEEP
|
||||
# define SQLITE_MIN_SLEEP_MS 1
|
||||
#else
|
||||
# define SQLITE_MIN_SLEEP_MS 1000
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Default permissions when creating a new file
|
||||
*/
|
||||
#ifndef SQLITE_DEFAULT_FILE_PERMISSIONS
|
||||
# define SQLITE_DEFAULT_FILE_PERMISSIONS 0644
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* _SQLITE_OS_UNIX_H_ */
|
|
@ -41,11 +41,99 @@
|
|||
*/
|
||||
#ifndef SQLITE_OMIT_DISKIO
|
||||
|
||||
/*
|
||||
** The following variable is (normally) set once and never changes
|
||||
** thereafter. It records whether the operating system is Win95
|
||||
** or WinNT.
|
||||
**
|
||||
** 0: Operating system unknown.
|
||||
** 1: Operating system is Win95.
|
||||
** 2: Operating system is WinNT.
|
||||
**
|
||||
** In order to facilitate testing on a WinNT system, the test fixture
|
||||
** can manually set this value to 1 to emulate Win98 behavior.
|
||||
*/
|
||||
int sqlite3_os_type = 0;
|
||||
|
||||
/*
|
||||
** Return true (non-zero) if we are running under WinNT, Win2K or WinXP.
|
||||
** Return false (zero) for Win95, Win98, or WinME.
|
||||
**
|
||||
** Here is an interesting observation: Win95, Win98, and WinME lack
|
||||
** the LockFileEx() API. But we can still statically link against that
|
||||
** API as long as we don't call it win running Win95/98/ME. A call to
|
||||
** this routine is used to determine if the host is Win95/98/ME or
|
||||
** WinNT/2K/XP so that we will know whether or not we can safely call
|
||||
** the LockFileEx() API.
|
||||
*/
|
||||
static int isNT(void){
|
||||
if( sqlite3_os_type==0 ){
|
||||
OSVERSIONINFO sInfo;
|
||||
sInfo.dwOSVersionInfoSize = sizeof(sInfo);
|
||||
GetVersionEx(&sInfo);
|
||||
sqlite3_os_type = sInfo.dwPlatformId==VER_PLATFORM_WIN32_NT ? 2 : 1;
|
||||
}
|
||||
return sqlite3_os_type==2;
|
||||
}
|
||||
|
||||
/*
|
||||
** Convert a UTF-8 string to UTF-32. Space to hold the returned string
|
||||
** is obtained from sqliteMalloc.
|
||||
*/
|
||||
static WCHAR *utf8ToUnicode(const char *zFilename){
|
||||
int nByte;
|
||||
WCHAR *zWideFilename;
|
||||
|
||||
if( !isNT() ){
|
||||
return 0;
|
||||
}
|
||||
nByte = MultiByteToWideChar(CP_UTF8, 0, zFilename, -1, NULL, 0)*sizeof(WCHAR);
|
||||
zWideFilename = sqliteMalloc( nByte*sizeof(zWideFilename[0]) );
|
||||
if( zWideFilename==0 ){
|
||||
return 0;
|
||||
}
|
||||
nByte = MultiByteToWideChar(CP_UTF8, 0, zFilename, -1, zWideFilename, nByte);
|
||||
if( nByte==0 ){
|
||||
sqliteFree(zWideFilename);
|
||||
zWideFilename = 0;
|
||||
}
|
||||
return zWideFilename;
|
||||
}
|
||||
|
||||
/*
|
||||
** Convert UTF-32 to UTF-8. Space to hold the returned string is
|
||||
** obtained from sqliteMalloc().
|
||||
*/
|
||||
static char *unicodeToUtf8(const WCHAR *zWideFilename){
|
||||
int nByte;
|
||||
char *zFilename;
|
||||
|
||||
nByte = WideCharToMultiByte(CP_UTF8, 0, zWideFilename, -1, 0, 0, 0, 0);
|
||||
zFilename = sqliteMalloc( nByte );
|
||||
if( zFilename==0 ){
|
||||
return 0;
|
||||
}
|
||||
nByte = WideCharToMultiByte(CP_UTF8, 0, zWideFilename, -1, zFilename, nByte,
|
||||
0, 0);
|
||||
if( nByte == 0 ){
|
||||
sqliteFree(zFilename);
|
||||
zFilename = 0;
|
||||
}
|
||||
return zFilename;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Delete the named file
|
||||
*/
|
||||
int sqlite3OsDelete(const char *zFilename){
|
||||
DeleteFileA(zFilename);
|
||||
WCHAR *zWide = utf8ToUnicode(zFilename);
|
||||
if( zWide ){
|
||||
DeleteFileW(zWide);
|
||||
sqliteFree(zWide);
|
||||
}else{
|
||||
DeleteFileA(zFilename);
|
||||
}
|
||||
TRACE2("DELETE \"%s\"\n", zFilename);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
@ -54,7 +142,15 @@ int sqlite3OsDelete(const char *zFilename){
|
|||
** Return TRUE if the named file exists.
|
||||
*/
|
||||
int sqlite3OsFileExists(const char *zFilename){
|
||||
return GetFileAttributesA(zFilename) != 0xffffffff;
|
||||
int exists = 0;
|
||||
WCHAR *zWide = utf8ToUnicode(zFilename);
|
||||
if( zWide ){
|
||||
exists = GetFileAttributesW(zWide) != 0xffffffff;
|
||||
sqliteFree(zWide);
|
||||
}else{
|
||||
exists = GetFileAttributesA(zFilename) != 0xffffffff;
|
||||
}
|
||||
return exists;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -76,30 +172,60 @@ int sqlite3OsOpenReadWrite(
|
|||
int *pReadonly
|
||||
){
|
||||
HANDLE h;
|
||||
WCHAR *zWide = utf8ToUnicode(zFilename);
|
||||
assert( !id->isOpen );
|
||||
h = CreateFileA(zFilename,
|
||||
GENERIC_READ | GENERIC_WRITE,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||
NULL,
|
||||
OPEN_ALWAYS,
|
||||
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS,
|
||||
NULL
|
||||
);
|
||||
if( h==INVALID_HANDLE_VALUE ){
|
||||
h = CreateFileA(zFilename,
|
||||
GENERIC_READ,
|
||||
FILE_SHARE_READ,
|
||||
if( zWide ){
|
||||
h = CreateFileW(zWide,
|
||||
GENERIC_READ | GENERIC_WRITE,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||
NULL,
|
||||
OPEN_ALWAYS,
|
||||
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS,
|
||||
NULL
|
||||
);
|
||||
if( h==INVALID_HANDLE_VALUE ){
|
||||
return SQLITE_CANTOPEN;
|
||||
h = CreateFileW(zWide,
|
||||
GENERIC_READ,
|
||||
FILE_SHARE_READ,
|
||||
NULL,
|
||||
OPEN_ALWAYS,
|
||||
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS,
|
||||
NULL
|
||||
);
|
||||
if( h==INVALID_HANDLE_VALUE ){
|
||||
sqliteFree(zWide);
|
||||
return SQLITE_CANTOPEN;
|
||||
}
|
||||
*pReadonly = 1;
|
||||
}else{
|
||||
*pReadonly = 0;
|
||||
}
|
||||
*pReadonly = 1;
|
||||
sqliteFree(zWide);
|
||||
}else{
|
||||
*pReadonly = 0;
|
||||
h = CreateFileA(zFilename,
|
||||
GENERIC_READ | GENERIC_WRITE,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||
NULL,
|
||||
OPEN_ALWAYS,
|
||||
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS,
|
||||
NULL
|
||||
);
|
||||
if( h==INVALID_HANDLE_VALUE ){
|
||||
h = CreateFileA(zFilename,
|
||||
GENERIC_READ,
|
||||
FILE_SHARE_READ,
|
||||
NULL,
|
||||
OPEN_ALWAYS,
|
||||
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS,
|
||||
NULL
|
||||
);
|
||||
if( h==INVALID_HANDLE_VALUE ){
|
||||
return SQLITE_CANTOPEN;
|
||||
}
|
||||
*pReadonly = 1;
|
||||
}else{
|
||||
*pReadonly = 0;
|
||||
}
|
||||
}
|
||||
id->h = h;
|
||||
id->locktype = NO_LOCK;
|
||||
|
@ -128,6 +254,7 @@ int sqlite3OsOpenReadWrite(
|
|||
int sqlite3OsOpenExclusive(const char *zFilename, OsFile *id, int delFlag){
|
||||
HANDLE h;
|
||||
int fileflags;
|
||||
WCHAR *zWide = utf8ToUnicode(zFilename);
|
||||
assert( !id->isOpen );
|
||||
if( delFlag ){
|
||||
fileflags = FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_RANDOM_ACCESS
|
||||
|
@ -135,14 +262,26 @@ int sqlite3OsOpenExclusive(const char *zFilename, OsFile *id, int delFlag){
|
|||
}else{
|
||||
fileflags = FILE_FLAG_RANDOM_ACCESS;
|
||||
}
|
||||
h = CreateFileA(zFilename,
|
||||
GENERIC_READ | GENERIC_WRITE,
|
||||
0,
|
||||
NULL,
|
||||
CREATE_ALWAYS,
|
||||
fileflags,
|
||||
NULL
|
||||
);
|
||||
if( zWide ){
|
||||
h = CreateFileW(zWide,
|
||||
GENERIC_READ | GENERIC_WRITE,
|
||||
0,
|
||||
NULL,
|
||||
CREATE_ALWAYS,
|
||||
fileflags,
|
||||
NULL
|
||||
);
|
||||
sqliteFree(zWide);
|
||||
}else{
|
||||
h = CreateFileA(zFilename,
|
||||
GENERIC_READ | GENERIC_WRITE,
|
||||
0,
|
||||
NULL,
|
||||
CREATE_ALWAYS,
|
||||
fileflags,
|
||||
NULL
|
||||
);
|
||||
}
|
||||
if( h==INVALID_HANDLE_VALUE ){
|
||||
return SQLITE_CANTOPEN;
|
||||
}
|
||||
|
@ -164,15 +303,28 @@ int sqlite3OsOpenExclusive(const char *zFilename, OsFile *id, int delFlag){
|
|||
*/
|
||||
int sqlite3OsOpenReadOnly(const char *zFilename, OsFile *id){
|
||||
HANDLE h;
|
||||
WCHAR *zWide = utf8ToUnicode(zFilename);
|
||||
assert( !id->isOpen );
|
||||
h = CreateFileA(zFilename,
|
||||
GENERIC_READ,
|
||||
0,
|
||||
NULL,
|
||||
OPEN_EXISTING,
|
||||
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS,
|
||||
NULL
|
||||
);
|
||||
if( zWide ){
|
||||
h = CreateFileW(zWide,
|
||||
GENERIC_READ,
|
||||
0,
|
||||
NULL,
|
||||
OPEN_EXISTING,
|
||||
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS,
|
||||
NULL
|
||||
);
|
||||
sqliteFree(zWide);
|
||||
}else{
|
||||
h = CreateFileA(zFilename,
|
||||
GENERIC_READ,
|
||||
0,
|
||||
NULL,
|
||||
OPEN_EXISTING,
|
||||
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS,
|
||||
NULL
|
||||
);
|
||||
}
|
||||
if( h==INVALID_HANDLE_VALUE ){
|
||||
return SQLITE_CANTOPEN;
|
||||
}
|
||||
|
@ -229,6 +381,16 @@ int sqlite3OsTempFileName(char *zBuf){
|
|||
if( sqlite3_temp_directory ){
|
||||
strncpy(zTempPath, sqlite3_temp_directory, SQLITE_TEMPNAME_SIZE-30);
|
||||
zTempPath[SQLITE_TEMPNAME_SIZE-30] = 0;
|
||||
}else if( isNT() ){
|
||||
char *zMulti;
|
||||
WCHAR zWidePath[SQLITE_TEMPNAME_SIZE];
|
||||
GetTempPathW(SQLITE_TEMPNAME_SIZE-30, zWidePath);
|
||||
zMulti = unicodeToUtf8(zWidePath);
|
||||
if( zMulti ){
|
||||
strncpy(zTempPath, zMulti, SQLITE_TEMPNAME_SIZE-30);
|
||||
zTempPath[SQLITE_TEMPNAME_SIZE-30] = 0;
|
||||
sqliteFree(zMulti);
|
||||
}
|
||||
}else{
|
||||
GetTempPathA(SQLITE_TEMPNAME_SIZE-30, zTempPath);
|
||||
}
|
||||
|
@ -303,6 +465,13 @@ int sqlite3OsWrite(OsFile *id, const void *pBuf, int amt){
|
|||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Some microsoft compilers lack this definition.
|
||||
*/
|
||||
#ifndef INVALID_SET_FILE_POINTER
|
||||
# define INVALID_SET_FILE_POINTER ((DWORD)-1)
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Move the read/write pointer in a file.
|
||||
*/
|
||||
|
@ -311,16 +480,22 @@ int sqlite3OsSeek(OsFile *id, i64 offset){
|
|||
LONG lowerBits = offset & 0xffffffff;
|
||||
DWORD rc;
|
||||
assert( id->isOpen );
|
||||
#ifdef SQLITE_TEST
|
||||
if( offset ) SimulateDiskfullError
|
||||
#endif
|
||||
SEEK(offset/1024 + 1);
|
||||
rc = SetFilePointer(id->h, lowerBits, &upperBits, FILE_BEGIN);
|
||||
TRACE3("SEEK %d %lld\n", id->h, offset);
|
||||
if( rc==INVALID_SET_FILE_POINTER && GetLastError()!=NO_ERROR ){
|
||||
return SQLITE_FULL;
|
||||
}
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Make sure all writes to a particular file are committed to disk.
|
||||
*/
|
||||
int sqlite3OsSync(OsFile *id){
|
||||
int sqlite3OsSync(OsFile *id, int dataOnly){
|
||||
assert( id->isOpen );
|
||||
TRACE3("SYNC %d lock=%d\n", id->h, id->locktype);
|
||||
if( FlushFileBuffers(id->h) ){
|
||||
|
@ -364,28 +539,6 @@ int sqlite3OsFileSize(OsFile *id, i64 *pSize){
|
|||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return true (non-zero) if we are running under WinNT, Win2K or WinXP.
|
||||
** Return false (zero) for Win95, Win98, or WinME.
|
||||
**
|
||||
** Here is an interesting observation: Win95, Win98, and WinME lack
|
||||
** the LockFileEx() API. But we can still statically link against that
|
||||
** API as long as we don't call it win running Win95/98/ME. A call to
|
||||
** this routine is used to determine if the host is Win95/98/ME or
|
||||
** WinNT/2K/XP so that we will know whether or not we can safely call
|
||||
** the LockFileEx() API.
|
||||
*/
|
||||
static int isNT(void){
|
||||
static int osType = 0; /* 0=unknown 1=win95 2=winNT */
|
||||
if( osType==0 ){
|
||||
OSVERSIONINFO sInfo;
|
||||
sInfo.dwOSVersionInfoSize = sizeof(sInfo);
|
||||
GetVersionEx(&sInfo);
|
||||
osType = sInfo.dwPlatformId==VER_PLATFORM_WIN32_NT ? 2 : 1;
|
||||
}
|
||||
return osType==2;
|
||||
}
|
||||
|
||||
/*
|
||||
** Acquire a reader lock.
|
||||
** Different API routines are called depending on whether or not this
|
||||
|
@ -426,11 +579,18 @@ static int unlockReadLock(OsFile *id){
|
|||
** Check that a given pathname is a directory and is writable
|
||||
**
|
||||
*/
|
||||
int sqlite3OsIsDirWritable(char *zBuf){
|
||||
int sqlite3OsIsDirWritable(char *zDirname){
|
||||
int fileAttr;
|
||||
if(! zBuf ) return 0;
|
||||
if(! isNT() && strlen(zBuf) > MAX_PATH ) return 0;
|
||||
fileAttr = GetFileAttributesA(zBuf);
|
||||
WCHAR *zWide;
|
||||
if( zDirname==0 ) return 0;
|
||||
if( !isNT() && strlen(zDirname)>MAX_PATH ) return 0;
|
||||
zWide = utf8ToUnicode(zDirname);
|
||||
if( zWide ){
|
||||
fileAttr = GetFileAttributesW(zWide);
|
||||
sqliteFree(zWide);
|
||||
}else{
|
||||
fileAttr = GetFileAttributesA(zDirname);
|
||||
}
|
||||
if( fileAttr == 0xffffffff ) return 0;
|
||||
if( (fileAttr & FILE_ATTRIBUTE_DIRECTORY) != FILE_ATTRIBUTE_DIRECTORY ){
|
||||
return 0;
|
||||
|
@ -641,6 +801,7 @@ int sqlite3OsUnlock(OsFile *id, int locktype){
|
|||
char *sqlite3OsFullPathname(const char *zRelative){
|
||||
char *zNotUsed;
|
||||
char *zFull;
|
||||
WCHAR *zWide;
|
||||
int nByte;
|
||||
#ifdef __CYGWIN__
|
||||
nByte = strlen(zRelative) + MAX_PATH + 1001;
|
||||
|
@ -648,10 +809,22 @@ char *sqlite3OsFullPathname(const char *zRelative){
|
|||
if( zFull==0 ) return 0;
|
||||
if( cygwin_conv_to_full_win32_path(zRelative, zFull) ) return 0;
|
||||
#else
|
||||
nByte = GetFullPathNameA(zRelative, 0, 0, &zNotUsed) + 1;
|
||||
zFull = sqliteMalloc( nByte );
|
||||
if( zFull==0 ) return 0;
|
||||
GetFullPathNameA(zRelative, nByte, zFull, &zNotUsed);
|
||||
zWide = utf8ToUnicode(zRelative);
|
||||
if( zWide ){
|
||||
WCHAR *zTemp, *zNotUsedW;
|
||||
nByte = GetFullPathNameW(zWide, 0, 0, &zNotUsedW) + 1;
|
||||
zTemp = sqliteMalloc( nByte*sizeof(zTemp[0]) );
|
||||
if( zTemp==0 ) return 0;
|
||||
GetFullPathNameW(zWide, nByte, zTemp, &zNotUsedW);
|
||||
sqliteFree(zWide);
|
||||
zFull = unicodeToUtf8(zTemp);
|
||||
sqliteFree(zTemp);
|
||||
}else{
|
||||
nByte = GetFullPathNameA(zRelative, 0, 0, &zNotUsed) + 1;
|
||||
zFull = sqliteMalloc( nByte*sizeof(zFull[0]) );
|
||||
if( zFull==0 ) return 0;
|
||||
GetFullPathNameA(zRelative, nByte, zFull, &zNotUsed);
|
||||
}
|
||||
#endif
|
||||
return zFull;
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
** file simultaneously, or one process from reading the database while
|
||||
** another is writing.
|
||||
**
|
||||
** @(#) $Id: pager.c,v 1.207 2005/06/07 02:12:30 drh Exp $
|
||||
** @(#) $Id: pager.c,v 1.215 2005/09/17 15:20:27 drh Exp $
|
||||
*/
|
||||
#ifndef SQLITE_OMIT_DISKIO
|
||||
#include "sqliteInt.h"
|
||||
|
@ -657,8 +657,10 @@ static int writeJournalHdr(Pager *pPager){
|
|||
** file descriptor to the end of the journal header sector.
|
||||
*/
|
||||
if( rc==SQLITE_OK ){
|
||||
sqlite3OsSeek(&pPager->jfd, pPager->journalOff-1);
|
||||
rc = sqlite3OsWrite(&pPager->jfd, "\000", 1);
|
||||
rc = sqlite3OsSeek(&pPager->jfd, pPager->journalOff-1);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3OsWrite(&pPager->jfd, "\000", 1);
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
@ -779,7 +781,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;
|
||||
}
|
||||
|
||||
|
@ -1038,8 +1040,10 @@ static int pager_playback_one_page(Pager *pPager, OsFile *jfd, int useCksum){
|
|||
assert( pPager->state>=PAGER_EXCLUSIVE || pPg!=0 );
|
||||
TRACE3("PLAYBACK %d page %d\n", PAGERID(pPager), pgno);
|
||||
if( pPager->state>=PAGER_EXCLUSIVE && (pPg==0 || pPg->needSync==0) ){
|
||||
sqlite3OsSeek(&pPager->fd, (pgno-1)*(i64)pPager->pageSize);
|
||||
rc = sqlite3OsWrite(&pPager->fd, aData, pPager->pageSize);
|
||||
rc = sqlite3OsSeek(&pPager->fd, (pgno-1)*(i64)pPager->pageSize);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3OsWrite(&pPager->fd, aData, pPager->pageSize);
|
||||
}
|
||||
if( pPg ) pPg->dirty = 0;
|
||||
}
|
||||
if( pPg ){
|
||||
|
@ -1168,8 +1172,10 @@ static int pager_reload_cache(Pager *pPager){
|
|||
char zBuf[SQLITE_MAX_PAGE_SIZE];
|
||||
if( !pPg->dirty ) continue;
|
||||
if( (int)pPg->pgno <= pPager->origDbSize ){
|
||||
sqlite3OsSeek(&pPager->fd, pPager->pageSize*(i64)(pPg->pgno-1));
|
||||
rc = sqlite3OsRead(&pPager->fd, zBuf, pPager->pageSize);
|
||||
rc = sqlite3OsSeek(&pPager->fd, pPager->pageSize*(i64)(pPg->pgno-1));
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3OsRead(&pPager->fd, zBuf, pPager->pageSize);
|
||||
}
|
||||
TRACE3("REFETCH %d page %d\n", PAGERID(pPager), pPg->pgno);
|
||||
if( rc ) break;
|
||||
CODEC(pPager, zBuf, pPg->pgno, 2);
|
||||
|
@ -1485,7 +1491,7 @@ static int pager_stmt_playback(Pager *pPager){
|
|||
end_stmt_playback:
|
||||
if( rc!=SQLITE_OK ){
|
||||
pPager->errMask |= PAGER_ERR_CORRUPT;
|
||||
rc = SQLITE_CORRUPT; /* bkpt-CORRUPT */
|
||||
rc = SQLITE_CORRUPT;
|
||||
}else{
|
||||
pPager->journalOff = szJ;
|
||||
/* pager_reload_cache(pPager); */
|
||||
|
@ -1746,25 +1752,35 @@ void sqlite3pager_read_fileheader(Pager *pPager, int N, unsigned char *pDest){
|
|||
|
||||
/*
|
||||
** Return the total number of pages in the disk file associated with
|
||||
** pPager.
|
||||
** pPager.
|
||||
**
|
||||
** If the PENDING_BYTE lies on the page directly after the end of the
|
||||
** file, then consider this page part of the file too. For example, if
|
||||
** PENDING_BYTE is byte 4096 (the first byte of page 5) and the size of the
|
||||
** file is 4096 bytes, 5 is returned instead of 4.
|
||||
*/
|
||||
int sqlite3pager_pagecount(Pager *pPager){
|
||||
i64 n;
|
||||
assert( pPager!=0 );
|
||||
if( pPager->dbSize>=0 ){
|
||||
return pPager->dbSize;
|
||||
n = pPager->dbSize;
|
||||
} else {
|
||||
if( sqlite3OsFileSize(&pPager->fd, &n)!=SQLITE_OK ){
|
||||
pPager->errMask |= PAGER_ERR_DISK;
|
||||
return 0;
|
||||
}
|
||||
if( n>0 && n<pPager->pageSize ){
|
||||
n = 1;
|
||||
}else{
|
||||
n /= pPager->pageSize;
|
||||
}
|
||||
if( pPager->state!=PAGER_UNLOCK ){
|
||||
pPager->dbSize = n;
|
||||
}
|
||||
}
|
||||
if( sqlite3OsFileSize(&pPager->fd, &n)!=SQLITE_OK ){
|
||||
pPager->errMask |= PAGER_ERR_DISK;
|
||||
return 0;
|
||||
}
|
||||
n /= pPager->pageSize;
|
||||
if( !MEMDB && n==PENDING_BYTE/pPager->pageSize ){
|
||||
if( n==(PENDING_BYTE/pPager->pageSize) ){
|
||||
n++;
|
||||
}
|
||||
if( pPager->state!=PAGER_UNLOCK ){
|
||||
pPager->dbSize = n;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
|
@ -1866,7 +1882,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 +1896,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;
|
||||
}
|
||||
|
@ -2122,17 +2133,20 @@ static int syncJournal(Pager *pPager){
|
|||
*/
|
||||
if( pPager->fullSync ){
|
||||
TRACE2("SYNC journal of %d\n", PAGERID(pPager));
|
||||
rc = sqlite3OsSync(&pPager->jfd);
|
||||
rc = sqlite3OsSync(&pPager->jfd, 0);
|
||||
if( rc!=0 ) return rc;
|
||||
}
|
||||
sqlite3OsSeek(&pPager->jfd, pPager->journalHdr + sizeof(aJournalMagic));
|
||||
rc = sqlite3OsSeek(&pPager->jfd,
|
||||
pPager->journalHdr + sizeof(aJournalMagic));
|
||||
if( rc ) return rc;
|
||||
rc = write32bits(&pPager->jfd, pPager->nRec);
|
||||
if( rc ) return rc;
|
||||
|
||||
sqlite3OsSeek(&pPager->jfd, pPager->journalOff);
|
||||
rc = sqlite3OsSeek(&pPager->jfd, pPager->journalOff);
|
||||
if( rc ) return rc;
|
||||
}
|
||||
TRACE2("SYNC journal of %d\n", PAGERID(pPager));
|
||||
rc = sqlite3OsSync(&pPager->jfd);
|
||||
rc = sqlite3OsSync(&pPager->jfd, pPager->fullSync);
|
||||
if( rc!=0 ) return rc;
|
||||
pPager->journalStarted = 1;
|
||||
}
|
||||
|
@ -2197,7 +2211,8 @@ static int pager_write_pagelist(PgHdr *pList){
|
|||
|
||||
while( pList ){
|
||||
assert( pList->dirty );
|
||||
sqlite3OsSeek(&pPager->fd, (pList->pgno-1)*(i64)pPager->pageSize);
|
||||
rc = sqlite3OsSeek(&pPager->fd, (pList->pgno-1)*(i64)pPager->pageSize);
|
||||
if( rc ) return rc;
|
||||
/* If there are dirty pages in the page cache with page numbers greater
|
||||
** than Pager.dbSize, this means sqlite3pager_truncate() was called to
|
||||
** make the file smaller (presumably by auto-vacuum code). Do not write
|
||||
|
@ -2292,8 +2307,8 @@ int sqlite3pager_get(Pager *pPager, Pgno pgno, void **ppPage){
|
|||
/* The maximum page number is 2^31. Return SQLITE_CORRUPT if a page
|
||||
** number greater than this, or zero, is requested.
|
||||
*/
|
||||
if( pgno>PAGER_MAX_PGNO || pgno==0 ){
|
||||
return SQLITE_CORRUPT;
|
||||
if( pgno>PAGER_MAX_PGNO || pgno==0 || pgno==PAGER_MJ_PGNO(pPager) ){
|
||||
return SQLITE_CORRUPT_BKPT;
|
||||
}
|
||||
|
||||
/* Make sure we have not hit any critical errors.
|
||||
|
@ -2507,8 +2522,10 @@ int sqlite3pager_get(Pager *pPager, Pgno pgno, void **ppPage){
|
|||
}else{
|
||||
int rc;
|
||||
assert( MEMDB==0 );
|
||||
sqlite3OsSeek(&pPager->fd, (pgno-1)*(i64)pPager->pageSize);
|
||||
rc = sqlite3OsRead(&pPager->fd, PGHDR_TO_DATA(pPg), pPager->pageSize);
|
||||
rc = sqlite3OsSeek(&pPager->fd, (pgno-1)*(i64)pPager->pageSize);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3OsRead(&pPager->fd, PGHDR_TO_DATA(pPg), pPager->pageSize);
|
||||
}
|
||||
TRACE3("FETCH %d page %d\n", PAGERID(pPager), pPg->pgno);
|
||||
CODEC(pPager, PGHDR_TO_DATA(pPg), pPg->pgno, 3);
|
||||
if( rc!=SQLITE_OK ){
|
||||
|
@ -2816,6 +2833,10 @@ int sqlite3pager_write(void *pData){
|
|||
}
|
||||
}else{
|
||||
u32 cksum;
|
||||
/* We should never write to the journal file the page that
|
||||
** contains the database locks. The following assert verifies
|
||||
** that we do not. */
|
||||
assert( pPg->pgno!=PAGER_MJ_PGNO(pPager) );
|
||||
CODEC(pPager, pData, pPg->pgno, 7);
|
||||
cksum = pager_cksum(pPager, pPg->pgno, pData);
|
||||
saved = *(u32*)PGHDR_TO_EXTRA(pPg, pPager);
|
||||
|
@ -3172,7 +3193,7 @@ int sqlite3pager_rollback(Pager *pPager){
|
|||
rc = pager_playback(pPager);
|
||||
}
|
||||
if( rc!=SQLITE_OK ){
|
||||
rc = SQLITE_CORRUPT; /* bkpt-CORRUPT */
|
||||
rc = SQLITE_CORRUPT_BKPT;
|
||||
pPager->errMask |= PAGER_ERR_CORRUPT;
|
||||
}
|
||||
pPager->dbSize = -1;
|
||||
|
@ -3346,6 +3367,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
|
||||
*/
|
||||
|
@ -3434,8 +3463,9 @@ int sqlite3pager_sync(Pager *pPager, const char *zMaster, Pgno nTrunc){
|
|||
*/
|
||||
Pgno i;
|
||||
void *pPage;
|
||||
int iSkip = PAGER_MJ_PGNO(pPager);
|
||||
for( i=nTrunc+1; i<=pPager->origDbSize; i++ ){
|
||||
if( !(pPager->aInJournal[i/8] & (1<<(i&7))) ){
|
||||
if( !(pPager->aInJournal[i/8] & (1<<(i&7))) && i!=iSkip ){
|
||||
rc = sqlite3pager_get(pPager, i, &pPage);
|
||||
if( rc!=SQLITE_OK ) goto sync_exit;
|
||||
rc = sqlite3pager_write(pPage);
|
||||
|
@ -3465,7 +3495,7 @@ int sqlite3pager_sync(Pager *pPager, const char *zMaster, Pgno nTrunc){
|
|||
|
||||
/* Sync the database file. */
|
||||
if( !pPager->noSync ){
|
||||
rc = sqlite3OsSync(&pPager->fd);
|
||||
rc = sqlite3OsSync(&pPager->fd, 0);
|
||||
}
|
||||
|
||||
pPager->state = PAGER_SYNCED;
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
** subsystem. The page cache subsystem reads and writes a file a page
|
||||
** at a time and provides a journal for rollback.
|
||||
**
|
||||
** @(#) $Id: pager.h,v 1.44 2005/05/20 20:01:56 drh Exp $
|
||||
** @(#) $Id: pager.h,v 1.46 2005/09/19 19:05:21 drh Exp $
|
||||
*/
|
||||
|
||||
/*
|
||||
|
@ -34,7 +34,7 @@
|
|||
** reasonable, like 1024.
|
||||
*/
|
||||
#ifndef SQLITE_MAX_PAGE_SIZE
|
||||
# define SQLITE_MAX_PAGE_SIZE 8192
|
||||
# define SQLITE_MAX_PAGE_SIZE 32768
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
@ -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);
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -6,135 +6,140 @@
|
|||
#define TK_FUNCTION 6
|
||||
#define TK_COLUMN 7
|
||||
#define TK_AGG_FUNCTION 8
|
||||
#define TK_CONST_FUNC 9
|
||||
#define TK_SEMI 10
|
||||
#define TK_EXPLAIN 11
|
||||
#define TK_BEGIN 12
|
||||
#define TK_TRANSACTION 13
|
||||
#define TK_DEFERRED 14
|
||||
#define TK_IMMEDIATE 15
|
||||
#define TK_EXCLUSIVE 16
|
||||
#define TK_COMMIT 17
|
||||
#define TK_END 18
|
||||
#define TK_ROLLBACK 19
|
||||
#define TK_CREATE 20
|
||||
#define TK_TABLE 21
|
||||
#define TK_TEMP 22
|
||||
#define TK_LP 23
|
||||
#define TK_RP 24
|
||||
#define TK_AS 25
|
||||
#define TK_COMMA 26
|
||||
#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_AGG_COLUMN 9
|
||||
#define TK_CONST_FUNC 10
|
||||
#define TK_SEMI 11
|
||||
#define TK_EXPLAIN 12
|
||||
#define TK_QUERY 13
|
||||
#define TK_PLAN 14
|
||||
#define TK_BEGIN 15
|
||||
#define TK_TRANSACTION 16
|
||||
#define TK_DEFERRED 17
|
||||
#define TK_IMMEDIATE 18
|
||||
#define TK_EXCLUSIVE 19
|
||||
#define TK_COMMIT 20
|
||||
#define TK_END 21
|
||||
#define TK_ROLLBACK 22
|
||||
#define TK_CREATE 23
|
||||
#define TK_TABLE 24
|
||||
#define TK_TEMP 25
|
||||
#define TK_LP 26
|
||||
#define TK_RP 27
|
||||
#define TK_AS 28
|
||||
#define TK_COMMA 29
|
||||
#define TK_ID 30
|
||||
#define TK_ABORT 31
|
||||
#define TK_AFTER 32
|
||||
#define TK_ANALYZE 33
|
||||
#define TK_ASC 34
|
||||
#define TK_ATTACH 35
|
||||
#define TK_BEFORE 36
|
||||
#define TK_CASCADE 37
|
||||
#define TK_CAST 38
|
||||
#define TK_CONFLICT 39
|
||||
#define TK_DATABASE 40
|
||||
#define TK_DESC 41
|
||||
#define TK_DETACH 42
|
||||
#define TK_EACH 43
|
||||
#define TK_FAIL 44
|
||||
#define TK_FOR 45
|
||||
#define TK_IGNORE 46
|
||||
#define TK_INITIALLY 47
|
||||
#define TK_INSTEAD 48
|
||||
#define TK_LIKE_KW 49
|
||||
#define TK_MATCH 50
|
||||
#define TK_KEY 51
|
||||
#define TK_OF 52
|
||||
#define TK_OFFSET 53
|
||||
#define TK_PRAGMA 54
|
||||
#define TK_RAISE 55
|
||||
#define TK_REPLACE 56
|
||||
#define TK_RESTRICT 57
|
||||
#define TK_ROW 58
|
||||
#define TK_STATEMENT 59
|
||||
#define TK_TRIGGER 60
|
||||
#define TK_VACUUM 61
|
||||
#define TK_VIEW 62
|
||||
#define TK_REINDEX 63
|
||||
#define TK_RENAME 64
|
||||
#define TK_CTIME_KW 65
|
||||
#define TK_ALTER 66
|
||||
#define TK_OR 67
|
||||
#define TK_AND 68
|
||||
#define TK_NOT 69
|
||||
#define TK_IS 70
|
||||
#define TK_BETWEEN 71
|
||||
#define TK_IN 72
|
||||
#define TK_ISNULL 73
|
||||
#define TK_NOTNULL 74
|
||||
#define TK_NE 75
|
||||
#define TK_EQ 76
|
||||
#define TK_GT 77
|
||||
#define TK_LE 78
|
||||
#define TK_LT 79
|
||||
#define TK_GE 80
|
||||
#define TK_ESCAPE 81
|
||||
#define TK_BITAND 82
|
||||
#define TK_BITOR 83
|
||||
#define TK_LSHIFT 84
|
||||
#define TK_RSHIFT 85
|
||||
#define TK_PLUS 86
|
||||
#define TK_MINUS 87
|
||||
#define TK_STAR 88
|
||||
#define TK_SLASH 89
|
||||
#define TK_REM 90
|
||||
#define TK_CONCAT 91
|
||||
#define TK_UMINUS 92
|
||||
#define TK_UPLUS 93
|
||||
#define TK_BITNOT 94
|
||||
#define TK_STRING 95
|
||||
#define TK_JOIN_KW 96
|
||||
#define TK_CONSTRAINT 97
|
||||
#define TK_DEFAULT 98
|
||||
#define TK_NULL 99
|
||||
#define TK_PRIMARY 100
|
||||
#define TK_UNIQUE 101
|
||||
#define TK_CHECK 102
|
||||
#define TK_REFERENCES 103
|
||||
#define TK_COLLATE 104
|
||||
#define TK_AUTOINCR 105
|
||||
#define TK_ON 106
|
||||
#define TK_DELETE 107
|
||||
#define TK_UPDATE 108
|
||||
#define TK_INSERT 109
|
||||
#define TK_SET 110
|
||||
#define TK_DEFERRABLE 111
|
||||
#define TK_FOREIGN 112
|
||||
#define TK_DROP 113
|
||||
#define TK_UNION 114
|
||||
#define TK_ALL 115
|
||||
#define TK_INTERSECT 116
|
||||
#define TK_EXCEPT 117
|
||||
#define TK_SELECT 118
|
||||
#define TK_DISTINCT 119
|
||||
#define TK_DOT 120
|
||||
#define TK_FROM 121
|
||||
#define TK_JOIN 122
|
||||
#define TK_USING 123
|
||||
#define TK_ORDER 124
|
||||
#define TK_BY 125
|
||||
#define TK_GROUP 126
|
||||
#define TK_HAVING 127
|
||||
#define TK_LIMIT 128
|
||||
#define TK_WHERE 129
|
||||
#define TK_INTO 130
|
||||
#define TK_VALUES 131
|
||||
#define TK_INTEGER 132
|
||||
#define TK_FLOAT 133
|
||||
#define TK_BLOB 134
|
||||
#define TK_REGISTER 135
|
||||
#define TK_VARIABLE 136
|
||||
#define TK_EXISTS 137
|
||||
#define TK_CASE 138
|
||||
#define TK_WHEN 139
|
||||
#define TK_THEN 140
|
||||
#define TK_ELSE 141
|
||||
#define TK_INDEX 142
|
||||
#define TK_TO 143
|
||||
#define TK_ADD 144
|
||||
#define TK_COLUMNKW 145
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
*************************************************************************
|
||||
** This file contains code used to implement the PRAGMA command.
|
||||
**
|
||||
** $Id: pragma.c,v 1.95 2005/06/12 21:35:52 drh Exp $
|
||||
** $Id: pragma.c,v 1.100 2005/09/20 17:42:23 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include "os.h"
|
||||
|
@ -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,26 +603,29 @@ 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;
|
||||
|
||||
/* Code that initializes the integrity check program. Set the
|
||||
** error count 0
|
||||
*/
|
||||
static const VdbeOpList initCode[] = {
|
||||
{ OP_Integer, 0, 0, 0},
|
||||
{ OP_MemStore, 0, 1, 0},
|
||||
};
|
||||
|
||||
/* Code that appears at the end of the integrity check. If no error
|
||||
** messages have been generated, output OK. Otherwise output the
|
||||
** error message
|
||||
|
@ -638,7 +642,7 @@ void sqlite3Pragma(
|
|||
if( sqlite3ReadSchema(pParse) ) goto pragma_out;
|
||||
sqlite3VdbeSetNumCols(v, 1);
|
||||
sqlite3VdbeSetColName(v, 0, "integrity_check", P3_STATIC);
|
||||
sqlite3VdbeAddOpList(v, ArraySize(initCode), initCode);
|
||||
sqlite3VdbeAddOp(v, OP_MemInt, 0, 0); /* Initialize error count to 0 */
|
||||
|
||||
/* Do an integrity check on each database file */
|
||||
for(i=0; i<db->nDb; i++){
|
||||
|
@ -684,8 +688,7 @@ void sqlite3Pragma(
|
|||
|
||||
if( pTab->pIndex==0 ) continue;
|
||||
sqlite3OpenTableAndIndices(pParse, pTab, 1, OP_OpenRead);
|
||||
sqlite3VdbeAddOp(v, OP_Integer, 0, 0);
|
||||
sqlite3VdbeAddOp(v, OP_MemStore, 1, 1);
|
||||
sqlite3VdbeAddOp(v, OP_MemInt, 0, 1);
|
||||
loopTop = sqlite3VdbeAddOp(v, OP_Rewind, 1, 0);
|
||||
sqlite3VdbeAddOp(v, OP_MemIncr, 1, 0);
|
||||
for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
|
||||
|
@ -703,39 +706,38 @@ void sqlite3Pragma(
|
|||
jmp2 = sqlite3VdbeAddOp(v, OP_Found, j+2, 0);
|
||||
addr = sqlite3VdbeAddOpList(v, ArraySize(idxErr), idxErr);
|
||||
sqlite3VdbeChangeP3(v, addr+4, pIdx->zName, P3_STATIC);
|
||||
sqlite3VdbeChangeP2(v, jmp2, sqlite3VdbeCurrentAddr(v));
|
||||
sqlite3VdbeJumpHere(v, jmp2);
|
||||
}
|
||||
sqlite3VdbeAddOp(v, OP_Next, 1, loopTop+1);
|
||||
sqlite3VdbeChangeP2(v, loopTop, sqlite3VdbeCurrentAddr(v));
|
||||
sqlite3VdbeJumpHere(v, loopTop);
|
||||
for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
|
||||
static const VdbeOpList cntIdx[] = {
|
||||
{ OP_Integer, 0, 0, 0},
|
||||
{ OP_MemStore, 2, 1, 0},
|
||||
{ OP_Rewind, 0, 0, 0}, /* 2 */
|
||||
{ OP_MemInt, 0, 2, 0},
|
||||
{ OP_Rewind, 0, 0, 0}, /* 1 */
|
||||
{ OP_MemIncr, 2, 0, 0},
|
||||
{ OP_Next, 0, 0, 0}, /* 4 */
|
||||
{ OP_Next, 0, 0, 0}, /* 3 */
|
||||
{ OP_MemLoad, 1, 0, 0},
|
||||
{ OP_MemLoad, 2, 0, 0},
|
||||
{ OP_Eq, 0, 0, 0}, /* 7 */
|
||||
{ OP_Eq, 0, 0, 0}, /* 6 */
|
||||
{ OP_MemIncr, 0, 0, 0},
|
||||
{ OP_String8, 0, 0, "wrong # of entries in index "},
|
||||
{ OP_String8, 0, 0, 0}, /* 10 */
|
||||
{ OP_String8, 0, 0, 0}, /* 9 */
|
||||
{ OP_Concat, 0, 0, 0},
|
||||
{ OP_Callback, 1, 0, 0},
|
||||
};
|
||||
if( pIdx->tnum==0 ) continue;
|
||||
addr = sqlite3VdbeAddOpList(v, ArraySize(cntIdx), cntIdx);
|
||||
sqlite3VdbeChangeP1(v, addr+2, j+2);
|
||||
sqlite3VdbeChangeP2(v, addr+2, addr+5);
|
||||
sqlite3VdbeChangeP1(v, addr+4, j+2);
|
||||
sqlite3VdbeChangeP2(v, addr+4, addr+3);
|
||||
sqlite3VdbeChangeP2(v, addr+7, addr+ArraySize(cntIdx));
|
||||
sqlite3VdbeChangeP3(v, addr+10, pIdx->zName, P3_STATIC);
|
||||
sqlite3VdbeChangeP1(v, addr+1, j+2);
|
||||
sqlite3VdbeChangeP2(v, addr+1, addr+4);
|
||||
sqlite3VdbeChangeP1(v, addr+3, j+2);
|
||||
sqlite3VdbeChangeP2(v, addr+3, addr+2);
|
||||
sqlite3VdbeJumpHere(v, addr+6);
|
||||
sqlite3VdbeChangeP3(v, addr+9, pIdx->zName, P3_STATIC);
|
||||
}
|
||||
}
|
||||
}
|
||||
addr = sqlite3VdbeAddOpList(v, ArraySize(endCode), endCode);
|
||||
sqlite3VdbeChangeP2(v, addr+2, addr+ArraySize(endCode));
|
||||
sqlite3VdbeJumpHere(v, addr+2);
|
||||
}else
|
||||
#endif /* SQLITE_OMIT_INTEGRITY_CHECK */
|
||||
|
||||
|
@ -891,13 +893,13 @@ void sqlite3Pragma(
|
|||
Btree *pBt;
|
||||
Pager *pPager;
|
||||
if( db->aDb[i].zName==0 ) continue;
|
||||
sqlite3VdbeOp3(v, OP_String, 0, 0, db->aDb[i].zName, P3_STATIC);
|
||||
sqlite3VdbeOp3(v, OP_String8, 0, 0, db->aDb[i].zName, P3_STATIC);
|
||||
pBt = db->aDb[i].pBt;
|
||||
if( pBt==0 || (pPager = sqlite3BtreePager(pBt))==0 ){
|
||||
sqlite3VdbeOp3(v, OP_String, 0, 0, "closed", P3_STATIC);
|
||||
sqlite3VdbeOp3(v, OP_String8, 0, 0, "closed", P3_STATIC);
|
||||
}else{
|
||||
int j = sqlite3pager_lockstate(pPager);
|
||||
sqlite3VdbeOp3(v, OP_String, 0, 0,
|
||||
sqlite3VdbeOp3(v, OP_String8, 0, 0,
|
||||
(j>=0 && j<=4) ? azLockName[j] : "unknown", P3_STATIC);
|
||||
}
|
||||
sqlite3VdbeAddOp(v, OP_Callback, 2, 0);
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
** interface, and routines that contribute to loading the database schema
|
||||
** from disk.
|
||||
**
|
||||
** $Id: prepare.c,v 1.1 2005-08-20 01:23:48 vladimir%pobox.com Exp $
|
||||
** $Id: prepare.c,v 1.2 2005-12-13 19:49:35 vladimir%pobox.com Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include "os.h"
|
||||
|
@ -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++;
|
||||
|
@ -453,12 +458,19 @@ int sqlite3_prepare(
|
|||
|
||||
#ifndef SQLITE_OMIT_EXPLAIN
|
||||
if( rc==SQLITE_OK && sParse.pVdbe && sParse.explain ){
|
||||
sqlite3VdbeSetNumCols(sParse.pVdbe, 5);
|
||||
sqlite3VdbeSetColName(sParse.pVdbe, 0, "addr", P3_STATIC);
|
||||
sqlite3VdbeSetColName(sParse.pVdbe, 1, "opcode", P3_STATIC);
|
||||
sqlite3VdbeSetColName(sParse.pVdbe, 2, "p1", P3_STATIC);
|
||||
sqlite3VdbeSetColName(sParse.pVdbe, 3, "p2", P3_STATIC);
|
||||
sqlite3VdbeSetColName(sParse.pVdbe, 4, "p3", P3_STATIC);
|
||||
if( sParse.explain==2 ){
|
||||
sqlite3VdbeSetNumCols(sParse.pVdbe, 3);
|
||||
sqlite3VdbeSetColName(sParse.pVdbe, 0, "order", P3_STATIC);
|
||||
sqlite3VdbeSetColName(sParse.pVdbe, 1, "from", P3_STATIC);
|
||||
sqlite3VdbeSetColName(sParse.pVdbe, 2, "detail", P3_STATIC);
|
||||
}else{
|
||||
sqlite3VdbeSetNumCols(sParse.pVdbe, 5);
|
||||
sqlite3VdbeSetColName(sParse.pVdbe, 0, "addr", P3_STATIC);
|
||||
sqlite3VdbeSetColName(sParse.pVdbe, 1, "opcode", P3_STATIC);
|
||||
sqlite3VdbeSetColName(sParse.pVdbe, 2, "p1", P3_STATIC);
|
||||
sqlite3VdbeSetColName(sParse.pVdbe, 3, "p2", P3_STATIC);
|
||||
sqlite3VdbeSetColName(sParse.pVdbe, 4, "p3", P3_STATIC);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -526,4 +538,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 },
|
||||
|
@ -163,7 +163,15 @@ static int et_getdigit(LONGDOUBLE_TYPE *val, int *cnt){
|
|||
}
|
||||
#endif
|
||||
|
||||
#define etBUFSIZE 1000 /* Size of the output buffer */
|
||||
/*
|
||||
** On machines with a small stack size, you can redefine the
|
||||
** SQLITE_PRINT_BUF_SIZE to be less than 350. But beware - for
|
||||
** smaller values some %f conversions may go into an infinite loop.
|
||||
*/
|
||||
#ifndef SQLITE_PRINT_BUF_SIZE
|
||||
# define SQLITE_PRINT_BUF_SIZE 350
|
||||
#endif
|
||||
#define etBUFSIZE SQLITE_PRINT_BUF_SIZE /* Size of the output buffer */
|
||||
|
||||
/*
|
||||
** The root program. All variations call this core.
|
||||
|
@ -210,9 +218,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 +235,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 +264,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 +348,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 +427,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 +436,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,10 +444,11 @@ 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>=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; }
|
||||
|
@ -467,51 +480,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 +593,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 ){
|
||||
|
@ -698,7 +726,11 @@ static void mout(void *arg, const char *zNewText, int nNewChar){
|
|||
memcpy(pM->zText, pM->zBase, pM->nChar);
|
||||
}
|
||||
}else{
|
||||
pM->zText = pM->xRealloc(pM->zText, pM->nAlloc);
|
||||
char *zNew;
|
||||
zNew = pM->xRealloc(pM->zText, pM->nAlloc);
|
||||
if( zNew ){
|
||||
pM->zText = zNew;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -736,7 +768,10 @@ static char *base_vprintf(
|
|||
memcpy(sM.zText, sM.zBase, sM.nChar+1);
|
||||
}
|
||||
}else if( sM.nAlloc>sM.nChar+10 ){
|
||||
sM.zText = xRealloc(sM.zText, sM.nChar+1);
|
||||
char *zNew = xRealloc(sM.zText, sM.nChar+1);
|
||||
if( zNew ){
|
||||
sM.zText = zNew;
|
||||
}
|
||||
}
|
||||
}
|
||||
return sM.zText;
|
||||
|
@ -754,7 +789,7 @@ static void *printf_realloc(void *old, int size){
|
|||
** %-conversion extensions.
|
||||
*/
|
||||
char *sqlite3VMPrintf(const char *zFormat, va_list ap){
|
||||
char zBase[1000];
|
||||
char zBase[SQLITE_PRINT_BUF_SIZE];
|
||||
return base_vprintf(printf_realloc, 1, zBase, sizeof(zBase), zFormat, ap);
|
||||
}
|
||||
|
||||
|
@ -765,7 +800,7 @@ char *sqlite3VMPrintf(const char *zFormat, va_list ap){
|
|||
char *sqlite3MPrintf(const char *zFormat, ...){
|
||||
va_list ap;
|
||||
char *z;
|
||||
char zBase[1000];
|
||||
char zBase[SQLITE_PRINT_BUF_SIZE];
|
||||
va_start(ap, zFormat);
|
||||
z = base_vprintf(printf_realloc, 1, zBase, sizeof(zBase), zFormat, ap);
|
||||
va_end(ap);
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -12,7 +12,7 @@
|
|||
** This file contains code to implement the "sqlite" command line
|
||||
** utility for accessing SQLite databases.
|
||||
**
|
||||
** $Id: shell.c,v 1.122 2005/02/23 12:35:41 drh Exp $
|
||||
** $Id: shell.c,v 1.128 2005/09/11 02:03:04 drh Exp $
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
@ -313,7 +313,7 @@ static void output_c_string(FILE *out, const char *z){
|
|||
fputc('\\', out);
|
||||
fputc('r', out);
|
||||
}else if( !isprint(c) ){
|
||||
fprintf(out, "\\%03o", c);
|
||||
fprintf(out, "\\%03o", c&0xff);
|
||||
}else{
|
||||
fputc(c, out);
|
||||
}
|
||||
|
@ -656,10 +656,14 @@ static int dump_callback(void *pArg, int nArg, char **azArg, char **azCol){
|
|||
zType = azArg[1];
|
||||
zSql = azArg[2];
|
||||
|
||||
if( strcmp(zTable,"sqlite_sequence")!=0 ){
|
||||
fprintf(p->out, "%s;\n", zSql);
|
||||
}else{
|
||||
if( strcmp(zTable, "sqlite_sequence")==0 ){
|
||||
fprintf(p->out, "DELETE FROM sqlite_sequence;\n");
|
||||
}else if( strcmp(zTable, "sqlite_stat1")==0 ){
|
||||
fprintf(p->out, "ANALYZE sqlite_master;\n");
|
||||
}else if( strncmp(zTable, "sqlite_", 7)==0 ){
|
||||
return 0;
|
||||
}else{
|
||||
fprintf(p->out, "%s;\n", zSql);
|
||||
}
|
||||
|
||||
if( strcmp(zType, "table")==0 ){
|
||||
|
@ -984,10 +988,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 +1097,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);
|
||||
|
@ -1289,7 +1294,7 @@ static int do_meta_command(char *zLine, struct callback_data *p){
|
|||
"SELECT sql FROM "
|
||||
" (SELECT * FROM sqlite_master UNION ALL"
|
||||
" SELECT * FROM sqlite_temp_master) "
|
||||
"WHERE type!='meta' AND sql NOTNULL "
|
||||
"WHERE type!='meta' AND sql NOTNULL AND name NOT LIKE 'sqlite_%'"
|
||||
"ORDER BY substr(type,2,1), name",
|
||||
callback, &data, &zErrMsg
|
||||
);
|
||||
|
@ -1333,7 +1338,7 @@ static int do_meta_command(char *zLine, struct callback_data *p){
|
|||
if( nArg==1 ){
|
||||
rc = sqlite3_get_table(p->db,
|
||||
"SELECT name FROM sqlite_master "
|
||||
"WHERE type IN ('table','view') "
|
||||
"WHERE type IN ('table','view') AND name NOT LIKE 'sqlite_%'"
|
||||
"UNION ALL "
|
||||
"SELECT name FROM sqlite_temp_master "
|
||||
"WHERE type IN ('table','view') "
|
||||
|
@ -1697,6 +1702,13 @@ int main(int argc, char **argv){
|
|||
}
|
||||
data.out = stdout;
|
||||
|
||||
#ifdef SQLITE_OMIT_MEMORYDB
|
||||
if( data.zDbFilename==0 ){
|
||||
fprintf(stderr,"%s: no database filename specified\n", argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Go ahead and open the database file if it already exists. If the
|
||||
** file does not exist, delay opening it. This prevents empty database
|
||||
** files from being created if a user mistypes the database name argument
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
** This header file defines the interface that the SQLite library
|
||||
** presents to client programs.
|
||||
**
|
||||
** @(#) $Id: sqlite.h.in,v 1.136 2005/06/12 22:12:39 drh Exp $
|
||||
** @(#) $Id: sqlite.h.in,v 1.141 2005/09/08 10:58:52 drh Exp $
|
||||
*/
|
||||
#ifndef _SQLITE3_H_
|
||||
#define _SQLITE3_H_
|
||||
|
@ -31,7 +31,7 @@ extern "C" {
|
|||
#ifdef SQLITE_VERSION
|
||||
# undef SQLITE_VERSION
|
||||
#endif
|
||||
#define SQLITE_VERSION "3.2.2"
|
||||
#define SQLITE_VERSION "3.2.7"
|
||||
|
||||
/*
|
||||
** The format of the version string is "X.Y.Z<trailing string>", where
|
||||
|
@ -48,7 +48,7 @@ extern "C" {
|
|||
#ifdef SQLITE_VERSION_NUMBER
|
||||
# undef SQLITE_VERSION_NUMBER
|
||||
#endif
|
||||
#define SQLITE_VERSION_NUMBER 3002002
|
||||
#define SQLITE_VERSION_NUMBER 3002007
|
||||
|
||||
/*
|
||||
** The version string is also compiled into the library so that a program
|
||||
|
@ -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 */
|
||||
|
@ -373,8 +373,9 @@ void sqlite3_free_table(char **result);
|
|||
**
|
||||
** We can use this text in an SQL statement as follows:
|
||||
**
|
||||
** sqlite3_exec_printf(db, "INSERT INTO table VALUES('%q')",
|
||||
** callback1, 0, 0, zText);
|
||||
** char *z = sqlite3_mprintf("INSERT INTO TABLES('%q')", zText);
|
||||
** sqlite3_exec(db, z, callback1, 0, 0);
|
||||
** sqlite3_free(z);
|
||||
**
|
||||
** Because the %q format string is used, the '\'' character in zText
|
||||
** is escaped and the SQL generated is as follows:
|
||||
|
@ -452,6 +453,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 */
|
||||
|
||||
|
||||
/*
|
||||
|
@ -463,11 +465,18 @@ int sqlite3_set_authorizer(
|
|||
#define SQLITE_IGNORE 2 /* Don't allow access, but don't generate an error */
|
||||
|
||||
/*
|
||||
** Register a function that is called at every invocation of sqlite3_exec()
|
||||
** or sqlite3_prepare(). This function can be used (for example) to generate
|
||||
** a log file of all SQL executed against a database.
|
||||
** Register a function for tracing SQL command evaluation. The function
|
||||
** registered by sqlite3_trace() is invoked at the first sqlite3_step()
|
||||
** for the evaluation of an SQL statement. The function registered by
|
||||
** sqlite3_profile() runs at the end of each SQL statement and includes
|
||||
** information on how long that statement ran.
|
||||
**
|
||||
** The sqlite3_profile() API is currently considered experimental and
|
||||
** is subject to change.
|
||||
*/
|
||||
void *sqlite3_trace(sqlite3*, void(*xTrace)(void*,const char*), void*);
|
||||
void *sqlite3_profile(sqlite3*,
|
||||
void(*xProfile)(void*,const char*,sqlite_uint64), void*);
|
||||
|
||||
/*
|
||||
** This routine configures a callback function - the progress callback - that
|
||||
|
@ -1002,10 +1011,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*);
|
||||
|
||||
|
|
|
@ -11,11 +11,22 @@
|
|||
*************************************************************************
|
||||
** Internal interface definitions for SQLite.
|
||||
**
|
||||
** @(#) $Id: sqliteInt.h,v 1.387 2005/06/12 21:35:52 drh Exp $
|
||||
** @(#) $Id: sqliteInt.h,v 1.421 2005/09/19 21:05:49 drh Exp $
|
||||
*/
|
||||
#ifndef _SQLITEINT_H_
|
||||
#define _SQLITEINT_H_
|
||||
|
||||
/*
|
||||
** Many people are failing to set -DNDEBUG=1 when compiling SQLite.
|
||||
** Setting NDEBUG makes the code smaller and run faster. So the following
|
||||
** lines are added to automatically set NDEBUG unless the -DSQLITE_DEBUG=1
|
||||
** option is set. Thus NDEBUG becomes an opt-in rather than an opt-out
|
||||
** feature.
|
||||
*/
|
||||
#if !defined(NDEBUG) && !defined(SQLITE_DEBUG)
|
||||
# define NDEBUG 1
|
||||
#endif
|
||||
|
||||
/*
|
||||
** These #defines should enable >2GB file support on Posix if the
|
||||
** underlying operating system supports it. If the OS lacks
|
||||
|
@ -210,6 +221,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 */
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -299,30 +311,30 @@ extern int sqlite3_iMallocReset; /* Set iMallocFail to this when it reaches 0 */
|
|||
/*
|
||||
** Forward references to structures
|
||||
*/
|
||||
typedef struct AggInfo AggInfo;
|
||||
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
|
||||
|
@ -421,8 +433,10 @@ struct sqlite3 {
|
|||
} init;
|
||||
struct Vdbe *pVdbe; /* List of active virtual machines */
|
||||
int activeVdbeCnt; /* Number of vdbes currently executing */
|
||||
void (*xTrace)(void*,const char*); /* Trace function */
|
||||
void *pTraceArg; /* Argument to the trace function */
|
||||
void (*xTrace)(void*,const char*); /* Trace function */
|
||||
void *pTraceArg; /* Argument to the trace function */
|
||||
void (*xProfile)(void*,const char*,u64); /* Profiling function */
|
||||
void *pProfileArg; /* Argument to profile function */
|
||||
void *pCommitArg; /* Argument to xCommitCallback() */
|
||||
int (*xCommitCallback)(void*);/* Invoked at every commit. */
|
||||
void(*xCollNeeded)(void*,sqlite3*,int eTextRep,const char*);
|
||||
|
@ -497,17 +511,24 @@ 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_LIKE 0x01 /* Candidate for the LIKE optimization */
|
||||
#define SQLITE_FUNC_CASE 0x02 /* Case-sensitive LIKE-type function */
|
||||
|
||||
/*
|
||||
** information about each column of an SQL table is held in an instance
|
||||
** of this structure.
|
||||
|
@ -546,10 +567,19 @@ struct Column {
|
|||
struct CollSeq {
|
||||
char *zName; /* Name of the collating sequence, UTF-8 encoded */
|
||||
u8 enc; /* Text encoding handled by xCmp() */
|
||||
u8 type; /* One of the SQLITE_COLL_... values below */
|
||||
void *pUser; /* First argument to xCmp() */
|
||||
int (*xCmp)(void*,int, const void*, int, const void*);
|
||||
};
|
||||
|
||||
/*
|
||||
** Allowed values of CollSeq flags:
|
||||
*/
|
||||
#define SQLITE_COLL_BINARY 1 /* The default memcmp() collating sequence */
|
||||
#define SQLITE_COLL_NOCASE 2 /* The built-in NOCASE collating sequence */
|
||||
#define SQLITE_COLL_REVERSE 3 /* The built-in REVERSE collating sequence */
|
||||
#define SQLITE_COLL_USER 0 /* Any other user-defined collating sequence */
|
||||
|
||||
/*
|
||||
** A sort order can be either ASC or DESC.
|
||||
*/
|
||||
|
@ -746,6 +776,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 */
|
||||
|
@ -770,6 +801,49 @@ struct Token {
|
|||
unsigned n : 31; /* Number of characters in this token */
|
||||
};
|
||||
|
||||
/*
|
||||
** An instance of this structure contains information needed to generate
|
||||
** code for a SELECT that contains aggregate functions.
|
||||
**
|
||||
** If Expr.op==TK_AGG_COLUMN or TK_AGG_FUNCTION then Expr.pAggInfo is a
|
||||
** pointer to this structure. The Expr.iColumn field is the index in
|
||||
** AggInfo.aCol[] or AggInfo.aFunc[] of information needed to generate
|
||||
** code for that node.
|
||||
**
|
||||
** AggInfo.pGroupBy and AggInfo.aFunc.pExpr point to fields within the
|
||||
** original Select structure that describes the SELECT statement. These
|
||||
** fields do not need to be freed when deallocating the AggInfo structure.
|
||||
*/
|
||||
struct AggInfo {
|
||||
u8 directMode; /* Direct rendering mode means take data directly
|
||||
** from source tables rather than from accumulators */
|
||||
u8 useSortingIdx; /* In direct mode, reference the sorting index rather
|
||||
** than the source table */
|
||||
int sortingIdx; /* Cursor number of the sorting index */
|
||||
ExprList *pGroupBy; /* The group by clause */
|
||||
int nSortingColumn; /* Number of columns in the sorting index */
|
||||
struct AggInfo_col { /* For each column used in source tables */
|
||||
int iTable; /* Cursor number of the source table */
|
||||
int iColumn; /* Column number within the source table */
|
||||
int iSorterColumn; /* Column number in the sorting index */
|
||||
int iMem; /* Memory location that acts as accumulator */
|
||||
Expr *pExpr; /* The original expression */
|
||||
} *aCol;
|
||||
int nColumn; /* Number of used entries in aCol[] */
|
||||
int nColumnAlloc; /* Number of slots allocated for aCol[] */
|
||||
int nAccumulator; /* Number of columns that show through to the output.
|
||||
** Additional columns are used only as parameters to
|
||||
** aggregate functions */
|
||||
struct AggInfo_func { /* For each aggregate function */
|
||||
Expr *pExpr; /* Expression encoding the function */
|
||||
FuncDef *pFunc; /* The aggregate function implementation */
|
||||
int iMem; /* Memory location that acts as accumulator */
|
||||
int iDistinct; /* Virtual table used to enforce DISTINCT */
|
||||
} *aFunc;
|
||||
int nFunc; /* Number of entries in aFunc[] */
|
||||
int nFuncAlloc; /* Number of slots allocated for aFunc[] */
|
||||
};
|
||||
|
||||
/*
|
||||
** Each node of an expression in the parse tree is an instance
|
||||
** of this structure.
|
||||
|
@ -829,9 +903,9 @@ struct Expr {
|
|||
Token span; /* Complete text of the expression */
|
||||
int iTable, iColumn; /* When op==TK_COLUMN, then this expr node means the
|
||||
** iColumn-th field of the iTable-th table. */
|
||||
int iAgg; /* When op==TK_COLUMN and pParse->fillAgg==FALSE, pull
|
||||
** result from the iAgg-th element of the aggregator */
|
||||
int iAggCtx; /* The value to pass as P1 of OP_AggGet. */
|
||||
AggInfo *pAggInfo; /* Used by TK_AGG_COLUMN and TK_AGG_FUNCTION */
|
||||
int iAgg; /* Which entry in pAggInfo->aCol[] or ->aFunc[] */
|
||||
int iRightJoinTable; /* If EP_FromJoin, the right table of the join */
|
||||
Select *pSelect; /* When the expression is a sub-select. Also the
|
||||
** right side of "<expr> IN (<select>)" */
|
||||
Table *pTab; /* Table for OP_Column expressions. */
|
||||
|
@ -840,12 +914,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_Distinct 0x10 /* Aggregate function with DISTINCT keyword */
|
||||
#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
|
||||
|
@ -867,6 +942,7 @@ struct Expr {
|
|||
struct ExprList {
|
||||
int nExpr; /* Number of expressions on the list */
|
||||
int nAlloc; /* Number of entries allocated below */
|
||||
int iECursor; /* VDBE Cursor associated with this ExprList */
|
||||
struct ExprList_item {
|
||||
Expr *pExpr; /* The list of expressions */
|
||||
char *zName; /* Token associated with this expression */
|
||||
|
@ -892,12 +968,12 @@ struct ExprList {
|
|||
** If "a" is the k-th column of table "t", then IdList.a[0].idx==k.
|
||||
*/
|
||||
struct IdList {
|
||||
int nId; /* Number of identifiers on the list */
|
||||
int nAlloc; /* Number of entries allocated for a[] below */
|
||||
struct IdList_item {
|
||||
char *zName; /* Name of the identifier */
|
||||
int idx; /* Index in some Table.aCol[] of a column named zName */
|
||||
} *a;
|
||||
int nId; /* Number of identifiers on the list */
|
||||
int nAlloc; /* Number of entries allocated for a[] below */
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -925,8 +1001,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 */
|
||||
|
@ -937,11 +1013,12 @@ struct SrcList {
|
|||
** Permitted values of the SrcList.a.jointype field
|
||||
*/
|
||||
#define JT_INNER 0x0001 /* Any kind of inner or cross join */
|
||||
#define JT_NATURAL 0x0002 /* True for a "natural" join */
|
||||
#define JT_LEFT 0x0004 /* Left outer join */
|
||||
#define JT_RIGHT 0x0008 /* Right outer join */
|
||||
#define JT_OUTER 0x0010 /* The "OUTER" keyword is present */
|
||||
#define JT_ERROR 0x0020 /* unknown or unsupported join type */
|
||||
#define JT_CROSS 0x0002 /* Explicit use of the CROSS keyword */
|
||||
#define JT_NATURAL 0x0004 /* True for a "natural" join */
|
||||
#define JT_LEFT 0x0008 /* Left outer join */
|
||||
#define JT_RIGHT 0x0010 /* Right outer join */
|
||||
#define JT_OUTER 0x0020 /* The "OUTER" keyword is present */
|
||||
#define JT_ERROR 0x0040 /* unknown or unsupported join type */
|
||||
|
||||
/*
|
||||
** For each nested loop in a WHERE clause implementation, the WhereInfo
|
||||
|
@ -950,18 +1027,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 */
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -1009,8 +1088,9 @@ struct NameContext {
|
|||
int nRef; /* Number of names resolved by this context */
|
||||
int nErr; /* Number of errors encountered while resolving names */
|
||||
u8 allowAgg; /* Aggregate functions allowed here */
|
||||
u8 hasAgg;
|
||||
u8 hasAgg; /* True if aggregates are seen */
|
||||
int nDepth; /* Depth of subquery recursion. 1 for no recursion */
|
||||
AggInfo *pAggInfo; /* Information about aggregates at this level */
|
||||
NameContext *pNext; /* Next outer name context. NULL for outermost */
|
||||
};
|
||||
|
||||
|
@ -1023,64 +1103,55 @@ struct NameContext {
|
|||
** limit and nOffset to the value of the offset (or 0 if there is not
|
||||
** offset). But later on, nLimit and nOffset become the memory locations
|
||||
** in the VDBE that record the limit and offset counters.
|
||||
**
|
||||
** addrOpenVirt[] entries contain the address of OP_OpenVirtual opcodes.
|
||||
** These addresses must be stored so that we can go back and fill in
|
||||
** the P3_KEYINFO and P2 parameters later. Neither the KeyInfo nor
|
||||
** the number of columns in P2 can be computed at the same time
|
||||
** as the OP_OpenVirtual instruction is coded because not
|
||||
** enough information about the compound query is known at that point.
|
||||
** The KeyInfo for addrOpenVirt[0] and [1] contains collating sequences
|
||||
** for the result set. The KeyInfo for addrOpenVirt[2] contains collating
|
||||
** sequences for the ORDER BY clause.
|
||||
*/
|
||||
struct Select {
|
||||
ExprList *pEList; /* The fields of the result */
|
||||
u8 op; /* One of: TK_UNION TK_ALL TK_INTERSECT TK_EXCEPT */
|
||||
u8 isDistinct; /* True if the DISTINCT keyword is present */
|
||||
u8 isResolved; /* True once sqlite3SelectResolve() has run. */
|
||||
u8 isAgg; /* True if this is an aggregate query */
|
||||
u8 usesVirt; /* True if uses an OpenVirtual opcode */
|
||||
u8 disallowOrderBy; /* Do not allow an ORDER BY to be attached if TRUE */
|
||||
SrcList *pSrc; /* The FROM clause */
|
||||
Expr *pWhere; /* The WHERE clause */
|
||||
ExprList *pGroupBy; /* The GROUP BY clause */
|
||||
Expr *pHaving; /* The HAVING clause */
|
||||
ExprList *pOrderBy; /* The ORDER BY clause */
|
||||
Select *pPrior; /* Prior select in a compound select statement */
|
||||
Select *pRightmost; /* Right-most select in a compound select statement */
|
||||
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 */
|
||||
u8 isResolved; /* True once sqlite3SelectResolve() has run. */
|
||||
u8 isAgg; /* True if this is an aggregate query */
|
||||
int addrOpenVirt[3]; /* OP_OpenVirtual opcodes related to this select */
|
||||
};
|
||||
|
||||
/*
|
||||
** The results of a select can be distributed in several ways.
|
||||
*/
|
||||
#define SRT_Callback 1 /* Invoke a callback with each row of result */
|
||||
#define SRT_Mem 2 /* Store result in a memory cell */
|
||||
#define SRT_Set 3 /* Store result as unique keys in a table */
|
||||
#define SRT_Union 5 /* Store result as keys in a table */
|
||||
#define SRT_Except 6 /* Remove result from a UNION table */
|
||||
#define SRT_Table 7 /* Store result as data with a unique key */
|
||||
#define SRT_TempTable 8 /* Store result in a trasient table */
|
||||
#define SRT_Discard 9 /* Do not save the results anywhere */
|
||||
#define SRT_Sorter 10 /* Store results in the sorter */
|
||||
#define SRT_Subroutine 11 /* Call a subroutine to handle results */
|
||||
#define SRT_Exists 12 /* Put 0 or 1 in a memory cell */
|
||||
#define SRT_Union 1 /* Store result as keys in an index */
|
||||
#define SRT_Except 2 /* Remove result from a UNION index */
|
||||
#define SRT_Discard 3 /* Do not save the results anywhere */
|
||||
|
||||
/*
|
||||
** When a SELECT uses aggregate functions (like "count(*)" or "avg(f1)")
|
||||
** we have to do some additional analysis of expressions. An instance
|
||||
** of the following structure holds information about a single subexpression
|
||||
** somewhere in the SELECT statement. An array of these structures holds
|
||||
** all the information we need to generate code for aggregate
|
||||
** expressions.
|
||||
**
|
||||
** Note that when analyzing a SELECT containing aggregates, both
|
||||
** non-aggregate field variables and aggregate functions are stored
|
||||
** in the AggExpr array of the Parser structure.
|
||||
**
|
||||
** The pExpr field points to an expression that is part of either the
|
||||
** field list, the GROUP BY clause, the HAVING clause or the ORDER BY
|
||||
** clause. The expression will be freed when those clauses are cleaned
|
||||
** up. Do not try to delete the expression attached to AggExpr.pExpr.
|
||||
**
|
||||
** If AggExpr.pExpr==0, that means the expression is "count(*)".
|
||||
*/
|
||||
struct AggExpr {
|
||||
int isAgg; /* if TRUE contains an aggregate function */
|
||||
Expr *pExpr; /* The expression */
|
||||
FuncDef *pFunc; /* Information about the aggregate function */
|
||||
};
|
||||
/* The ORDER BY clause is ignored for all of the above */
|
||||
#define IgnorableOrderby(X) (X<=SRT_Discard)
|
||||
|
||||
#define SRT_Callback 4 /* Invoke a callback with each row of result */
|
||||
#define SRT_Mem 5 /* Store result in a memory cell */
|
||||
#define SRT_Set 6 /* Store non-null results as keys in an index */
|
||||
#define SRT_Table 7 /* Store result as data with an automatic rowid */
|
||||
#define SRT_VirtualTab 8 /* Create virtual table and store like SRT_Table */
|
||||
#define SRT_Subroutine 9 /* Call a subroutine to handle results */
|
||||
#define SRT_Exists 10 /* Put 0 or 1 in a memory cell */
|
||||
|
||||
/*
|
||||
** An SQL parser context. A copy of this structure is passed through
|
||||
|
@ -1101,7 +1172,6 @@ struct Parse {
|
|||
u8 nameClash; /* A permanent table name clashes with temp table name */
|
||||
u8 checkSchema; /* Causes schema cookie check after an error */
|
||||
u8 nested; /* Number of nested calls to the parser/code generator */
|
||||
u8 fillAgg; /* If true, ignore the Expr.iAgg field. Normally false */
|
||||
int nErr; /* Number of errors seen */
|
||||
int nTab; /* Number of previously allocated VDBE cursors */
|
||||
int nMem; /* Number of memory cells used so far */
|
||||
|
@ -1128,9 +1198,6 @@ struct Parse {
|
|||
Trigger *pNewTrigger; /* Trigger under construct by a CREATE TRIGGER */
|
||||
TriggerStack *trigStack; /* Trigger actions being coded */
|
||||
const char *zAuthContext; /* The 6th parameter to db->xAuth callbacks */
|
||||
int nAgg; /* Number of aggregate expressions */
|
||||
AggExpr *aAgg; /* An array of aggregate expressions */
|
||||
int nMaxDepth; /* Maximum depth of subquery recursion */
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -1310,6 +1377,19 @@ typedef struct {
|
|||
*/
|
||||
extern int sqlite3_always_code_trigger_setup;
|
||||
|
||||
/*
|
||||
** The SQLITE_CORRUPT_BKPT macro can be either a constant (for production
|
||||
** builds) or a function call (for debugging). If it is a function call,
|
||||
** it allows the operator to set a breakpoint at the spot where database
|
||||
** corruption is first detected.
|
||||
*/
|
||||
#ifdef SQLITE_DEBUG
|
||||
extern int sqlite3Corrupt(void);
|
||||
# define SQLITE_CORRUPT_BKPT sqlite3Corrupt()
|
||||
#else
|
||||
# define SQLITE_CORRUPT_BKPT SQLITE_CORRUPT
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Internal function prototypes
|
||||
*/
|
||||
|
@ -1337,6 +1417,7 @@ void sqlite3RealToSortable(double r, char *);
|
|||
# define sqlite3CheckMemory(a,b)
|
||||
# define sqlite3MallocX sqlite3Malloc
|
||||
#endif
|
||||
void sqlite3ReallocOrFree(void**,int);
|
||||
void sqlite3FreeX(void*);
|
||||
void *sqlite3MallocX(int);
|
||||
char *sqlite3MPrintf(const char*, ...);
|
||||
|
@ -1346,6 +1427,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*);
|
||||
|
@ -1371,7 +1453,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*);
|
||||
|
@ -1386,6 +1468,7 @@ void sqlite3EndTable(Parse*,Token*,Token*,Select*);
|
|||
void sqlite3DropTable(Parse*, SrcList*, int);
|
||||
void sqlite3DeleteTable(sqlite3*, Table*);
|
||||
void sqlite3Insert(Parse*, SrcList*, ExprList*, Select*, IdList*, int);
|
||||
int sqlite3ArrayAllocate(void**,int,int);
|
||||
IdList *sqlite3IdListAppend(IdList*, Token*);
|
||||
int sqlite3IdListIndex(IdList*,const char*);
|
||||
SrcList *sqlite3SrcListAppend(SrcList*, Token*, Token*);
|
||||
|
@ -1430,6 +1513,7 @@ int sqlite3ExprCompare(Expr*, Expr*);
|
|||
int sqliteFuncId(Token*);
|
||||
int sqlite3ExprResolveNames(NameContext *, Expr *);
|
||||
int sqlite3ExprAnalyzeAggregates(NameContext*, Expr*);
|
||||
int sqlite3ExprAnalyzeAggList(NameContext*,ExprList*);
|
||||
Vdbe *sqlite3GetVdbe(Parse*);
|
||||
void sqlite3Randomness(int, void*);
|
||||
void sqlite3RollbackAll(sqlite3*);
|
||||
|
@ -1438,6 +1522,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);
|
||||
|
@ -1510,7 +1595,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 *);
|
||||
|
@ -1546,7 +1631,7 @@ const void *sqlite3ValueText(sqlite3_value*, u8);
|
|||
int sqlite3ValueBytes(sqlite3_value*, u8);
|
||||
void sqlite3ValueSetStr(sqlite3_value*, int, const void *,u8, void(*)(void*));
|
||||
void sqlite3ValueFree(sqlite3_value*);
|
||||
sqlite3_value *sqlite3ValueNew();
|
||||
sqlite3_value *sqlite3ValueNew(void);
|
||||
sqlite3_value *sqlite3GetTransientValue(sqlite3*db);
|
||||
int sqlite3ValueFromExpr(Expr *, u8, u8, sqlite3_value **);
|
||||
void sqlite3ValueApplyAffinity(sqlite3_value *, u8, u8);
|
||||
|
@ -1565,6 +1650,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*,int*,char*);
|
||||
|
||||
#ifdef SQLITE_SSE
|
||||
#include "sseInt.h"
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -15,7 +15,7 @@
|
|||
** individual tokens and sends those tokens one-by-one over to the
|
||||
** parser for analysis.
|
||||
**
|
||||
** $Id: tokenize.c,v 1.103 2005/06/06 14:45:43 drh Exp $
|
||||
** $Id: tokenize.c,v 1.107 2005/08/23 11:31:26 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include "os.h"
|
||||
|
@ -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 */
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
** This file contains C code routines that are called by the parser
|
||||
** to handle UPDATE statements.
|
||||
**
|
||||
** $Id: update.c,v 1.108 2005/06/12 21:35:53 drh Exp $
|
||||
** $Id: update.c,v 1.112 2005/09/20 17:42:23 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
|
||||
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -255,13 +259,13 @@ void sqlite3Update(
|
|||
if( pParse->nested==0 ) sqlite3VdbeCountChanges(v);
|
||||
sqlite3BeginWriteOperation(pParse, 1, pTab->iDb);
|
||||
|
||||
/* If we are trying to update a view, construct that view into
|
||||
** a temporary table.
|
||||
/* If we are trying to update a view, realize that view into
|
||||
** a ephemeral table.
|
||||
*/
|
||||
if( isView ){
|
||||
Select *pView;
|
||||
pView = sqlite3SelectDup(pTab->pSelect);
|
||||
sqlite3Select(pParse, pView, SRT_TempTable, iCur, 0, 0, 0, 0);
|
||||
sqlite3Select(pParse, pView, SRT_VirtualTab, iCur, 0, 0, 0, 0);
|
||||
sqlite3SelectDelete(pView);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -467,8 +469,7 @@ void sqlite3Update(
|
|||
** all record selected by the WHERE clause have been updated.
|
||||
*/
|
||||
sqlite3VdbeAddOp(v, OP_Goto, 0, addr);
|
||||
sqlite3VdbeChangeP2(v, addr, sqlite3VdbeCurrentAddr(v));
|
||||
sqlite3VdbeAddOp(v, OP_ListReset, 0, 0);
|
||||
sqlite3VdbeJumpHere(v, addr);
|
||||
|
||||
/* Close all tables if there were no FOR EACH ROW triggers */
|
||||
if( !triggers_exist ){
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
** This file contains functions for allocating memory, comparing
|
||||
** strings, and stuff like that.
|
||||
**
|
||||
** $Id: util.c,v 1.136 2005/06/06 15:06:39 drh Exp $
|
||||
** $Id: util.c,v 1.146 2005/09/17 18:34:11 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include <stdarg.h>
|
||||
|
@ -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++;
|
||||
}
|
||||
|
@ -340,6 +366,19 @@ char *sqlite3StrNDup(const char *z, int n){
|
|||
}
|
||||
#endif /* !defined(SQLITE_MEMDEBUG) */
|
||||
|
||||
/*
|
||||
** Reallocate a buffer to a different size. This is similar to
|
||||
** sqliteRealloc() except that if the allocation fails the buffer
|
||||
** is freed.
|
||||
*/
|
||||
void sqlite3ReallocOrFree(void **ppBuf, int newSize){
|
||||
void *pNew = sqliteRealloc(*ppBuf, newSize);
|
||||
if( pNew==0 ){
|
||||
sqliteFree(*ppBuf);
|
||||
}
|
||||
*ppBuf = pNew;
|
||||
}
|
||||
|
||||
/*
|
||||
** Create a string from the 2nd and subsequent arguments (up to the
|
||||
** first NULL argument), store the string in memory obtained from
|
||||
|
@ -372,8 +411,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 +499,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 +605,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 +654,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 +761,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 +777,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;
|
||||
}
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -15,7 +15,7 @@
|
|||
** or VDBE. The VDBE implements an abstract machine that runs a
|
||||
** simple program to access and modify the underlying database.
|
||||
**
|
||||
** $Id: vdbe.h,v 1.95 2005/05/19 08:43:00 danielk1977 Exp $
|
||||
** $Id: vdbe.h,v 1.99 2005/09/20 17:42:23 drh Exp $
|
||||
*/
|
||||
#ifndef _SQLITE_VDBE_H_
|
||||
#define _SQLITE_VDBE_H_
|
||||
|
@ -104,13 +104,12 @@ int sqlite3VdbeOp3(Vdbe*,int,int,int,const char *zP3,int);
|
|||
int sqlite3VdbeAddOpList(Vdbe*, int nOp, VdbeOpList const *aOp);
|
||||
void sqlite3VdbeChangeP1(Vdbe*, int addr, int P1);
|
||||
void sqlite3VdbeChangeP2(Vdbe*, int addr, int P2);
|
||||
void sqlite3VdbeJumpHere(Vdbe*, int addr);
|
||||
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*);
|
||||
void sqlite3VdbeMakeReady(Vdbe*,int,int,int,int,int);
|
||||
void sqlite3VdbeMakeReady(Vdbe*,int,int,int,int);
|
||||
int sqlite3VdbeFinalize(Vdbe*);
|
||||
void sqlite3VdbeResolveLabel(Vdbe*, int);
|
||||
int sqlite3VdbeCurrentAddr(Vdbe*);
|
||||
|
|
|
@ -81,6 +81,7 @@ struct Cursor {
|
|||
u8 *pIncrKey; /* Pointer to pKeyInfo->incrKey */
|
||||
KeyInfo *pKeyInfo; /* Info about index keys needed by index cursors */
|
||||
int nField; /* Number of fields in the header */
|
||||
i64 seqCount; /* Sequence counter */
|
||||
|
||||
/* Cached information about the header for the data record that the
|
||||
** cursor is currently pointing to. Only valid if cacheValid is true.
|
||||
|
@ -113,35 +114,18 @@ typedef struct Cursor Cursor;
|
|||
** SQLITE_BLOB.
|
||||
*/
|
||||
struct Mem {
|
||||
i64 i; /* Integer value */
|
||||
i64 i; /* Integer value. Or FuncDef* when flags==MEM_Agg */
|
||||
double r; /* Real value */
|
||||
char *z; /* String or BLOB value */
|
||||
int n; /* Number of characters in string value, including '\0' */
|
||||
u16 flags; /* Some combination of MEM_Null, MEM_Str, MEM_Dyn, etc. */
|
||||
u8 type; /* One of MEM_Null, MEM_Str, etc. */
|
||||
u8 enc; /* TEXT_Utf8, TEXT_Utf16le, or TEXT_Utf16be */
|
||||
double r; /* Real value */
|
||||
char *z; /* String or BLOB value */
|
||||
void (*xDel)(void *); /* If not null, call this function to delete Mem.z */
|
||||
char zShort[NBFS]; /* Space for short strings */
|
||||
};
|
||||
typedef struct Mem Mem;
|
||||
|
||||
/*
|
||||
** A sorter builds a list of elements to be sorted. Each element of
|
||||
** the list is an instance of the following structure.
|
||||
*/
|
||||
typedef struct Sorter Sorter;
|
||||
struct Sorter {
|
||||
int nKey; /* Number of bytes in the key */
|
||||
char *zKey; /* The key by which we will sort */
|
||||
Mem data;
|
||||
Sorter *pNext; /* Next in the list */
|
||||
};
|
||||
|
||||
/*
|
||||
** Number of buckets used for merge-sort.
|
||||
*/
|
||||
#define NSORT 30
|
||||
|
||||
/* One or more of the following flags are set to indicate the validOK
|
||||
** representations of the value stored in the Mem struct.
|
||||
**
|
||||
|
@ -173,12 +157,7 @@ struct Sorter {
|
|||
#define MEM_Static 0x0080 /* Mem.z points to a static string */
|
||||
#define MEM_Ephem 0x0100 /* Mem.z points to an ephemeral string */
|
||||
#define MEM_Short 0x0200 /* Mem.z points to Mem.zShort */
|
||||
|
||||
/* The following MEM_ value appears only in AggElem.aMem.s.flag fields.
|
||||
** It indicates that the corresponding AggElem.aMem.z points to a
|
||||
** aggregate function context that needs to be finalized.
|
||||
*/
|
||||
#define MEM_AggCtx 0x0400 /* Mem.z points to an agg function context */
|
||||
#define MEM_Agg 0x0400 /* Mem.z points to an agg function context */
|
||||
|
||||
|
||||
/* A VdbeFunc is just a FuncDef (defined in sqliteInt.h) that contains
|
||||
|
@ -210,41 +189,16 @@ typedef struct VdbeFunc VdbeFunc;
|
|||
** But this file is the only place where the internal details of this
|
||||
** structure are known.
|
||||
**
|
||||
** This structure is defined inside of vdbe.c because it uses substructures
|
||||
** This structure is defined inside of vdbeInt.h because it uses substructures
|
||||
** (Mem) which are only defined there.
|
||||
*/
|
||||
struct sqlite3_context {
|
||||
FuncDef *pFunc; /* Pointer to function information. MUST BE FIRST */
|
||||
FuncDef *pFunc; /* Pointer to function information. MUST BE FIRST */
|
||||
VdbeFunc *pVdbeFunc; /* Auxilary data, if created. */
|
||||
Mem s; /* The return value is stored here */
|
||||
void *pAgg; /* Aggregate context */
|
||||
u8 isError; /* Set to true for an error */
|
||||
int cnt; /* Number of times that the step function has been called */
|
||||
CollSeq *pColl;
|
||||
};
|
||||
|
||||
/*
|
||||
** An Agg structure describes an Aggregator. Each Agg consists of
|
||||
** zero or more Aggregator elements (AggElem). Each AggElem contains
|
||||
** a key and one or more values. The values are used in processing
|
||||
** aggregate functions in a SELECT. The key is used to implement
|
||||
** the GROUP BY clause of a select.
|
||||
*/
|
||||
typedef struct Agg Agg;
|
||||
typedef struct AggElem AggElem;
|
||||
struct Agg {
|
||||
int nMem; /* Number of values stored in each AggElem */
|
||||
AggElem *pCurrent; /* The AggElem currently in focus */
|
||||
FuncDef **apFunc; /* Information about aggregate functions */
|
||||
Btree *pBtree; /* The tmp. btree used to group elements, if required. */
|
||||
BtCursor *pCsr; /* Read/write cursor to the table in pBtree */
|
||||
int nTab; /* Root page of the table in pBtree */
|
||||
u8 searching; /* True between the first AggNext and AggReset */
|
||||
};
|
||||
struct AggElem {
|
||||
char *zKey; /* The key to this AggElem */
|
||||
int nKey; /* Number of bytes in the key, including '\0' at end */
|
||||
Mem aMem[1]; /* The values for this AggElem */
|
||||
Mem s; /* The return value is stored here */
|
||||
Mem *pMem; /* Memory cell used to store aggregate context */
|
||||
u8 isError; /* Set to true for an error */
|
||||
CollSeq *pColl; /* Collating sequence */
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -260,17 +214,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 +252,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 */
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -312,8 +278,6 @@ struct Vdbe {
|
|||
Mem *aColName; /* Column names to return */
|
||||
int nCursor; /* Number of slots in apCsr[] */
|
||||
Cursor **apCsr; /* One element of this array for each open cursor */
|
||||
Sorter *pSort; /* A linked list of objects to be sorted */
|
||||
Sorter *pSortTail; /* Last element on the pSort list */
|
||||
int nVar; /* Number of entries in aVar[] */
|
||||
Mem *aVar; /* Values for the OP_Variable opcode. */
|
||||
char **azVar; /* Name of variables */
|
||||
|
@ -321,11 +285,8 @@ struct Vdbe {
|
|||
int magic; /* Magic number for sanity checking */
|
||||
int nMem; /* Number of memory locations currently allocated */
|
||||
Mem *aMem; /* The memory locations */
|
||||
int nAgg; /* Number of elements in apAgg */
|
||||
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*/
|
||||
|
@ -346,6 +307,7 @@ struct Vdbe {
|
|||
u8 aborted; /* True if ROLLBACK in another VM causes an abort */
|
||||
u8 expired; /* True if the VM needs to be recompiled */
|
||||
int nChange; /* Number of db changes made since last reset */
|
||||
i64 startTime; /* Time when query started - used for profiling */
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -360,9 +322,6 @@ struct Vdbe {
|
|||
** Function prototypes
|
||||
*/
|
||||
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)
|
||||
|
@ -404,6 +363,7 @@ double sqlite3VdbeRealValue(Mem*);
|
|||
int sqlite3VdbeMemRealify(Mem*);
|
||||
int sqlite3VdbeMemFromBtree(BtCursor*,int,int,int,Mem*);
|
||||
void sqlite3VdbeMemRelease(Mem *p);
|
||||
void sqlite3VdbeMemFinalize(Mem*, FuncDef*);
|
||||
#ifndef NDEBUG
|
||||
void sqlite3VdbeMemSanity(Mem*, u8);
|
||||
int sqlite3VdbeOpcodeNoPush(u8);
|
||||
|
@ -411,3 +371,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*);
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include "vdbeInt.h"
|
||||
#include "os.h"
|
||||
|
||||
/*
|
||||
** Return TRUE (non-zero) of the statement supplied as an argument needs
|
||||
|
@ -84,7 +85,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){
|
||||
|
@ -173,9 +174,10 @@ int sqlite3_step(sqlite3_stmt *pStmt){
|
|||
return SQLITE_MISUSE;
|
||||
}
|
||||
if( p->pc<0 ){
|
||||
#ifndef SQLITE_OMIT_TRACE
|
||||
/* Invoke the trace callback if there is one
|
||||
*/
|
||||
if( (db = p->db)->xTrace && !db->init.busy ){
|
||||
if( db->xTrace && !db->init.busy ){
|
||||
assert( p->nOp>0 );
|
||||
assert( p->aOp[p->nOp-1].opcode==OP_Noop );
|
||||
assert( p->aOp[p->nOp-1].p3!=0 );
|
||||
|
@ -187,6 +189,12 @@ int sqlite3_step(sqlite3_stmt *pStmt){
|
|||
return SQLITE_MISUSE;
|
||||
}
|
||||
}
|
||||
if( db->xProfile && !db->init.busy ){
|
||||
double rNow;
|
||||
sqlite3OsCurrentTime(&rNow);
|
||||
p->startTime = (rNow - (int)rNow)*3600.0*24.0*1000000000.0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Print a copy of SQL as it is executed if the SQL_TRACE pragma is turned
|
||||
** on in debugging mode.
|
||||
|
@ -213,7 +221,24 @@ int sqlite3_step(sqlite3_stmt *pStmt){
|
|||
rc = SQLITE_MISUSE;
|
||||
}
|
||||
|
||||
sqlite3Error(p->db, rc, p->zErrMsg);
|
||||
#ifndef SQLITE_OMIT_TRACE
|
||||
/* Invoke the profile callback if there is one
|
||||
*/
|
||||
if( rc!=SQLITE_ROW && db->xProfile && !db->init.busy ){
|
||||
double rNow;
|
||||
u64 elapseTime;
|
||||
|
||||
sqlite3OsCurrentTime(&rNow);
|
||||
elapseTime = (rNow - (int)rNow)*3600.0*24.0*1000000000.0 - p->startTime;
|
||||
assert( p->nOp>0 );
|
||||
assert( p->aOp[p->nOp-1].opcode==OP_Noop );
|
||||
assert( p->aOp[p->nOp-1].p3!=0 );
|
||||
assert( p->aOp[p->nOp-1].p3type==P3_DYNAMIC );
|
||||
db->xProfile(db->pProfileArg, p->aOp[p->nOp-1].p3, elapseTime);
|
||||
}
|
||||
#endif
|
||||
|
||||
sqlite3Error(p->db, rc, p->zErrMsg ? "%s" : 0, p->zErrMsg);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
@ -230,22 +255,27 @@ 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){
|
||||
Mem *pMem = p->pMem;
|
||||
assert( p && p->pFunc && p->pFunc->xStep );
|
||||
if( p->pAgg==0 ){
|
||||
if( nByte<=NBFS ){
|
||||
p->pAgg = (void*)p->s.z;
|
||||
memset(p->pAgg, 0, nByte);
|
||||
if( (pMem->flags & MEM_Agg)==0 ){
|
||||
if( nByte==0 ){
|
||||
assert( pMem->flags==MEM_Null );
|
||||
pMem->z = 0;
|
||||
}else{
|
||||
p->pAgg = sqliteMalloc( nByte );
|
||||
pMem->flags = MEM_Agg;
|
||||
pMem->xDel = sqlite3FreeX;
|
||||
*(FuncDef**)&pMem->i = p->pFunc;
|
||||
if( nByte<=NBFS ){
|
||||
pMem->z = pMem->zShort;
|
||||
memset(pMem->z, 0, nByte);
|
||||
}else{
|
||||
pMem->z = sqliteMalloc( nByte );
|
||||
}
|
||||
}
|
||||
}
|
||||
return p->pAgg;
|
||||
return (void*)pMem->z;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -278,8 +308,9 @@ void sqlite3_set_auxdata(
|
|||
pVdbeFunc = pCtx->pVdbeFunc;
|
||||
if( !pVdbeFunc || pVdbeFunc->nAux<=iArg ){
|
||||
int nMalloc = sizeof(VdbeFunc) + sizeof(struct AuxData)*iArg;
|
||||
pCtx->pVdbeFunc = pVdbeFunc = sqliteRealloc(pVdbeFunc, nMalloc);
|
||||
pVdbeFunc = sqliteRealloc(pVdbeFunc, nMalloc);
|
||||
if( !pVdbeFunc ) return;
|
||||
pCtx->pVdbeFunc = pVdbeFunc;
|
||||
memset(&pVdbeFunc->apAux[pVdbeFunc->nAux], 0,
|
||||
sizeof(struct AuxData)*(iArg+1-pVdbeFunc->nAux));
|
||||
pVdbeFunc->nAux = iArg+1;
|
||||
|
@ -304,7 +335,7 @@ void sqlite3_set_auxdata(
|
|||
*/
|
||||
int sqlite3_aggregate_count(sqlite3_context *p){
|
||||
assert( p && p->pFunc && p->pFunc->xStep );
|
||||
return p->cnt;
|
||||
return p->pMem->n;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -369,6 +400,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
|
||||
|
||||
|
@ -62,16 +62,18 @@ void sqlite3VdbeTrace(Vdbe *p, FILE *trace){
|
|||
** elements.
|
||||
*/
|
||||
static void resizeOpArray(Vdbe *p, int N){
|
||||
if( p->magic==VDBE_MAGIC_RUN ){
|
||||
assert( N==p->nOp );
|
||||
p->nOpAlloc = N;
|
||||
p->aOp = sqliteRealloc(p->aOp, N*sizeof(Op));
|
||||
}else if( p->nOpAlloc<N ){
|
||||
int runMode = p->magic==VDBE_MAGIC_RUN;
|
||||
if( runMode || p->nOpAlloc<N ){
|
||||
VdbeOp *pNew;
|
||||
int nNew = N + 100*(!runMode);
|
||||
int oldSize = p->nOpAlloc;
|
||||
p->nOpAlloc = N+100;
|
||||
p->aOp = sqliteRealloc(p->aOp, p->nOpAlloc*sizeof(Op));
|
||||
if( p->aOp ){
|
||||
memset(&p->aOp[oldSize], 0, (p->nOpAlloc-oldSize)*sizeof(Op));
|
||||
pNew = sqliteRealloc(p->aOp, nNew*sizeof(Op));
|
||||
if( pNew ){
|
||||
p->nOpAlloc = nNew;
|
||||
p->aOp = pNew;
|
||||
if( nNew>oldSize ){
|
||||
memset(&p->aOp[oldSize], 0, (nNew-oldSize)*sizeof(Op));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -100,7 +102,7 @@ int sqlite3VdbeAddOp(Vdbe *p, int op, int p1, int p2){
|
|||
p->nOp++;
|
||||
assert( p->magic==VDBE_MAGIC_INIT );
|
||||
resizeOpArray(p, i+1);
|
||||
if( p->aOp==0 ){
|
||||
if( sqlite3_malloc_failed ){
|
||||
return 0;
|
||||
}
|
||||
pOp = &p->aOp[i];
|
||||
|
@ -109,6 +111,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
|
||||
|
@ -144,7 +147,8 @@ int sqlite3VdbeMakeLabel(Vdbe *p){
|
|||
assert( p->magic==VDBE_MAGIC_INIT );
|
||||
if( i>=p->nLabelAlloc ){
|
||||
p->nLabelAlloc = p->nLabelAlloc*2 + 10;
|
||||
p->aLabel = sqliteRealloc( p->aLabel, p->nLabelAlloc*sizeof(p->aLabel[0]));
|
||||
sqlite3ReallocOrFree((void**)&p->aLabel,
|
||||
p->nLabelAlloc*sizeof(p->aLabel[0]));
|
||||
}
|
||||
if( p->aLabel ){
|
||||
p->aLabel[i] = -1;
|
||||
|
@ -214,8 +218,8 @@ int sqlite3VdbeOpcodeNoPush(u8 op){
|
|||
**
|
||||
** This routine is called once after all opcodes have been inserted.
|
||||
**
|
||||
** Variable *pMaxFuncArgs is set to the maximum value of any P1 argument
|
||||
** to an OP_Function or P2 to an OP_AggFunc opcode. This is used by
|
||||
** Variable *pMaxFuncArgs is set to the maximum value of any P2 argument
|
||||
** to an OP_Function or OP_AggStep opcode. This is used by
|
||||
** sqlite3VdbeMakeReady() to size the Vdbe.apArg[] array.
|
||||
**
|
||||
** The integer *pMaxStack is set to the maximum number of vdbe stack
|
||||
|
@ -238,12 +242,7 @@ static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs, int *pMaxStack){
|
|||
for(pOp=p->aOp, i=p->nOp-1; i>=0; i--, pOp++){
|
||||
u8 opcode = pOp->opcode;
|
||||
|
||||
/* Todo: Maybe OP_AggFunc should change to use P1 in the same
|
||||
* way as OP_Function.
|
||||
*/
|
||||
if( opcode==OP_Function ){
|
||||
if( pOp->p1>nMaxArgs ) nMaxArgs = pOp->p1;
|
||||
}else if( opcode==OP_AggFunc ){
|
||||
if( opcode==OP_Function || opcode==OP_AggStep ){
|
||||
if( pOp->p2>nMaxArgs ) nMaxArgs = pOp->p2;
|
||||
}else if( opcode==OP_Halt ){
|
||||
if( pOp->p1==SQLITE_CONSTRAINT && pOp->p2==OE_Abort ){
|
||||
|
@ -301,7 +300,7 @@ int sqlite3VdbeAddOpList(Vdbe *p, int nOp, VdbeOpList const *aOp){
|
|||
int addr;
|
||||
assert( p->magic==VDBE_MAGIC_INIT );
|
||||
resizeOpArray(p, p->nOp + nOp);
|
||||
if( p->aOp==0 ){
|
||||
if( sqlite3_malloc_failed ){
|
||||
return 0;
|
||||
}
|
||||
addr = p->nOp;
|
||||
|
@ -352,6 +351,41 @@ void sqlite3VdbeChangeP2(Vdbe *p, int addr, int val){
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Change teh P2 operand of instruction addr so that it points to
|
||||
** the address of the next instruction to be coded.
|
||||
*/
|
||||
void sqlite3VdbeJumpHere(Vdbe *p, int addr){
|
||||
sqlite3VdbeChangeP2(p, addr, p->nOp);
|
||||
}
|
||||
|
||||
/*
|
||||
** Delete a P3 value if necessary.
|
||||
*/
|
||||
static void freeP3(int p3type, void *p3){
|
||||
if( p3 ){
|
||||
switch( p3type ){
|
||||
case P3_DYNAMIC:
|
||||
case P3_KEYINFO:
|
||||
case P3_KEYINFO_HANDOFF: {
|
||||
sqliteFree(p3);
|
||||
break;
|
||||
}
|
||||
case P3_VDBEFUNC: {
|
||||
VdbeFunc *pVdbeFunc = (VdbeFunc *)p3;
|
||||
sqlite3VdbeDeleteAuxData(pVdbeFunc, 0);
|
||||
sqliteFree(pVdbeFunc);
|
||||
break;
|
||||
}
|
||||
case P3_MEM: {
|
||||
sqlite3ValueFree((sqlite3_value*)p3);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Change the value of the P3 operand for a specific instruction.
|
||||
** This routine is useful when a large program is loaded from a
|
||||
|
@ -381,12 +415,7 @@ void sqlite3VdbeChangeP3(Vdbe *p, int addr, const char *zP3, int n){
|
|||
Op *pOp;
|
||||
assert( p->magic==VDBE_MAGIC_INIT );
|
||||
if( p==0 || p->aOp==0 ){
|
||||
if( n==P3_DYNAMIC || n==P3_KEYINFO_HANDOFF ){
|
||||
sqliteFree((void*)zP3);
|
||||
}
|
||||
if( n==P3_MEM ){
|
||||
sqlite3ValueFree((sqlite3_value *)zP3);
|
||||
}
|
||||
freeP3(n, (void*)*(char**)&zP3);
|
||||
return;
|
||||
}
|
||||
if( addr<0 || addr>=p->nOp ){
|
||||
|
@ -394,16 +423,19 @@ void sqlite3VdbeChangeP3(Vdbe *p, int addr, const char *zP3, int n){
|
|||
if( addr<0 ) return;
|
||||
}
|
||||
pOp = &p->aOp[addr];
|
||||
if( pOp->p3 && pOp->p3type==P3_DYNAMIC ){
|
||||
sqliteFree(pOp->p3);
|
||||
pOp->p3 = 0;
|
||||
}
|
||||
freeP3(pOp->p3type, pOp->p3);
|
||||
pOp->p3 = 0;
|
||||
if( zP3==0 ){
|
||||
pOp->p3 = 0;
|
||||
pOp->p3type = P3_NOTUSED;
|
||||
}else if( n==P3_KEYINFO ){
|
||||
KeyInfo *pKeyInfo;
|
||||
int nField, nByte;
|
||||
|
||||
/* KeyInfo structures that include an KeyInfo.aSortOrder are always
|
||||
** sent in using P3_KEYINFO_HANDOFF. The KeyInfo.aSortOrder array
|
||||
** is not duplicated when P3_KEYINFO is used. */
|
||||
/* assert( pKeyInfo->aSortOrder==0 ); */
|
||||
nField = ((KeyInfo*)zP3)->nField;
|
||||
nByte = sizeof(*pKeyInfo) + (nField-1)*sizeof(pKeyInfo->aColl[0]);
|
||||
pKeyInfo = sqliteMallocRaw( nByte );
|
||||
|
@ -442,47 +474,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.
|
||||
*/
|
||||
|
@ -617,8 +608,9 @@ int sqlite3VdbeList(
|
|||
}
|
||||
p->resOnStack = 0;
|
||||
|
||||
|
||||
i = p->pc++;
|
||||
do{
|
||||
i = p->pc++;
|
||||
}while( i<p->nOp && p->explain==2 && p->aOp[i].opcode!=OP_Explain );
|
||||
if( i>=p->nOp ){
|
||||
p->rc = SQLITE_OK;
|
||||
rc = SQLITE_DONE;
|
||||
|
@ -657,7 +649,7 @@ int sqlite3VdbeList(
|
|||
pMem->type = SQLITE_TEXT;
|
||||
pMem->enc = SQLITE_UTF8;
|
||||
|
||||
p->nResColumn = 5;
|
||||
p->nResColumn = 5 - 2*(p->explain-1);
|
||||
p->pTos = pMem;
|
||||
p->rc = SQLITE_OK;
|
||||
p->resOnStack = 1;
|
||||
|
@ -698,7 +690,6 @@ void sqlite3VdbeMakeReady(
|
|||
int nVar, /* Number of '?' see in the SQL statement */
|
||||
int nMem, /* Number of memory cells to allocate */
|
||||
int nCursor, /* Number of cursors to allocate */
|
||||
int nAgg, /* Number of aggregate contexts required */
|
||||
int isExplain /* True if the EXPLAIN keywords is present */
|
||||
){
|
||||
int n;
|
||||
|
@ -741,7 +732,6 @@ void sqlite3VdbeMakeReady(
|
|||
+ nVar*sizeof(char*) /* azVar */
|
||||
+ nMem*sizeof(Mem) /* aMem */
|
||||
+ nCursor*sizeof(Cursor*) /* apCsr */
|
||||
+ nAgg*sizeof(Agg) /* Aggregate contexts */
|
||||
);
|
||||
if( !sqlite3_malloc_failed ){
|
||||
p->aMem = &p->aStack[nStack];
|
||||
|
@ -752,17 +742,12 @@ void sqlite3VdbeMakeReady(
|
|||
p->apArg = (Mem**)&p->aVar[nVar];
|
||||
p->azVar = (char**)&p->apArg[nArg];
|
||||
p->apCsr = (Cursor**)&p->azVar[nVar];
|
||||
if( nAgg>0 ){
|
||||
p->nAgg = nAgg;
|
||||
p->apAgg = (Agg*)&p->apCsr[nCursor];
|
||||
}
|
||||
p->nCursor = nCursor;
|
||||
for(n=0; n<nVar; n++){
|
||||
p->aVar[n].flags = MEM_Null;
|
||||
}
|
||||
}
|
||||
}
|
||||
p->pAgg = p->apAgg;
|
||||
for(n=0; n<p->nMem; n++){
|
||||
p->aMem[n].flags = MEM_Null;
|
||||
}
|
||||
|
@ -803,167 +788,6 @@ void sqlite3VdbeMakeReady(
|
|||
#endif
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Remove any elements that remain on the sorter for the VDBE given.
|
||||
*/
|
||||
void sqlite3VdbeSorterReset(Vdbe *p){
|
||||
while( p->pSort ){
|
||||
Sorter *pSorter = p->pSort;
|
||||
p->pSort = pSorter->pNext;
|
||||
sqliteFree(pSorter->zKey);
|
||||
sqlite3VdbeMemRelease(&pSorter->data);
|
||||
sqliteFree(pSorter);
|
||||
}
|
||||
p->pSortTail = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Free all resources allociated with AggElem pElem, an element of
|
||||
** aggregate pAgg.
|
||||
*/
|
||||
static void freeAggElem(AggElem *pElem, Agg *pAgg){
|
||||
int i;
|
||||
for(i=0; i<pAgg->nMem; i++){
|
||||
Mem *pMem = &pElem->aMem[i];
|
||||
if( pAgg->apFunc && pAgg->apFunc[i] && (pMem->flags & MEM_AggCtx)!=0 ){
|
||||
sqlite3_context ctx;
|
||||
ctx.pFunc = pAgg->apFunc[i];
|
||||
ctx.s.flags = MEM_Null;
|
||||
ctx.pAgg = pMem->z;
|
||||
ctx.cnt = pMem->i;
|
||||
ctx.isError = 0;
|
||||
(*ctx.pFunc->xFinalize)(&ctx);
|
||||
pMem->z = ctx.pAgg;
|
||||
if( pMem->z!=0 && pMem->z!=pMem->zShort ){
|
||||
sqliteFree(pMem->z);
|
||||
}
|
||||
sqlite3VdbeMemRelease(&ctx.s);
|
||||
}else{
|
||||
sqlite3VdbeMemRelease(pMem);
|
||||
}
|
||||
}
|
||||
sqliteFree(pElem);
|
||||
}
|
||||
|
||||
/*
|
||||
** Reset an Agg structure. Delete all its contents.
|
||||
**
|
||||
** For installable aggregate functions, if the step function has been
|
||||
** called, make sure the finalizer function has also been called. The
|
||||
** finalizer might need to free memory that was allocated as part of its
|
||||
** private context. If the finalizer has not been called yet, call it
|
||||
** now.
|
||||
**
|
||||
** If db is NULL, then this is being called from sqliteVdbeReset(). In
|
||||
** this case clean up all references to the temp-table used for
|
||||
** aggregates (if it was ever opened).
|
||||
**
|
||||
** If db is not NULL, then this is being called from with an OP_AggReset
|
||||
** opcode. Open the temp-table, if it has not already been opened and
|
||||
** delete the contents of the table used for aggregate information, ready
|
||||
** for the next round of aggregate processing.
|
||||
*/
|
||||
int sqlite3VdbeAggReset(sqlite3 *db, Agg *pAgg, KeyInfo *pKeyInfo){
|
||||
int rc = 0;
|
||||
BtCursor *pCsr;
|
||||
|
||||
if( !pAgg ) return SQLITE_OK;
|
||||
pCsr = pAgg->pCsr;
|
||||
assert( (pCsr && pAgg->nTab>0) || (!pCsr && pAgg->nTab==0)
|
||||
|| sqlite3_malloc_failed );
|
||||
|
||||
/* If pCsr is not NULL, then the table used for aggregate information
|
||||
** is open. Loop through it and free the AggElem* structure pointed at
|
||||
** by each entry. If the finalizer has not been called for an AggElem,
|
||||
** do that too. Finally, clear the btree table itself.
|
||||
*/
|
||||
if( pCsr ){
|
||||
int res;
|
||||
assert( pAgg->pBtree );
|
||||
assert( pAgg->nTab>0 );
|
||||
|
||||
rc=sqlite3BtreeFirst(pCsr, &res);
|
||||
while( res==0 && rc==SQLITE_OK ){
|
||||
AggElem *pElem;
|
||||
rc = sqlite3BtreeData(pCsr, 0, sizeof(AggElem*), (char *)&pElem);
|
||||
if( rc!=SQLITE_OK ){
|
||||
return rc;
|
||||
}
|
||||
assert( pAgg->apFunc!=0 );
|
||||
freeAggElem(pElem, pAgg);
|
||||
rc=sqlite3BtreeNext(pCsr, &res);
|
||||
}
|
||||
if( rc!=SQLITE_OK ){
|
||||
return rc;
|
||||
}
|
||||
|
||||
sqlite3BtreeCloseCursor(pCsr);
|
||||
sqlite3BtreeClearTable(pAgg->pBtree, pAgg->nTab);
|
||||
}else{
|
||||
/* The cursor may not be open because the aggregator was never used,
|
||||
** or it could be that it was used but there was no GROUP BY clause.
|
||||
*/
|
||||
if( pAgg->pCurrent ){
|
||||
freeAggElem(pAgg->pCurrent, pAgg);
|
||||
}
|
||||
}
|
||||
|
||||
/* If db is not NULL and we have not yet and we have not yet opened
|
||||
** the temporary btree then do so and create the table to store aggregate
|
||||
** information.
|
||||
**
|
||||
** If db is NULL, then close the temporary btree if it is open.
|
||||
*/
|
||||
if( db ){
|
||||
if( !pAgg->pBtree ){
|
||||
assert( pAgg->nTab==0 );
|
||||
#ifndef SQLITE_OMIT_MEMORYDB
|
||||
rc = sqlite3BtreeFactory(db, ":memory:", 0, TEMP_PAGES, &pAgg->pBtree);
|
||||
#else
|
||||
rc = sqlite3BtreeFactory(db, 0, 0, TEMP_PAGES, &pAgg->pBtree);
|
||||
#endif
|
||||
if( rc!=SQLITE_OK ) return rc;
|
||||
sqlite3BtreeBeginTrans(pAgg->pBtree, 1);
|
||||
rc = sqlite3BtreeCreateTable(pAgg->pBtree, &pAgg->nTab, 0);
|
||||
if( rc!=SQLITE_OK ) return rc;
|
||||
}
|
||||
assert( pAgg->nTab!=0 );
|
||||
|
||||
rc = sqlite3BtreeCursor(pAgg->pBtree, pAgg->nTab, 1,
|
||||
sqlite3VdbeRecordCompare, pKeyInfo, &pAgg->pCsr);
|
||||
if( rc!=SQLITE_OK ) return rc;
|
||||
}else{
|
||||
if( pAgg->pBtree ){
|
||||
sqlite3BtreeClose(pAgg->pBtree);
|
||||
pAgg->pBtree = 0;
|
||||
pAgg->nTab = 0;
|
||||
}
|
||||
pAgg->pCsr = 0;
|
||||
}
|
||||
|
||||
if( pAgg->apFunc ){
|
||||
sqliteFree(pAgg->apFunc);
|
||||
pAgg->apFunc = 0;
|
||||
}
|
||||
pAgg->pCurrent = 0;
|
||||
pAgg->nMem = 0;
|
||||
pAgg->searching = 0;
|
||||
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,20 +834,13 @@ 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);
|
||||
}
|
||||
sqlite3VdbeSorterReset(p);
|
||||
for(i=0; i<p->nAgg; i++){
|
||||
sqlite3VdbeAggReset(0, &p->apAgg[i], 0);
|
||||
}
|
||||
p->contextStack = 0;
|
||||
p->contextStackDepth = 0;
|
||||
p->contextStackTop = 0;
|
||||
|
@ -1145,6 +962,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 +998,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 +1017,8 @@ 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,0))!=SQLITE_OK) ){
|
||||
sqlite3OsClose(&master);
|
||||
sqlite3OsDelete(zMaster);
|
||||
sqliteFree(zMaster);
|
||||
|
@ -1540,17 +1362,7 @@ void sqlite3VdbeDelete(Vdbe *p){
|
|||
if( p->aOp ){
|
||||
for(i=0; i<p->nOp; i++){
|
||||
Op *pOp = &p->aOp[i];
|
||||
if( pOp->p3type==P3_DYNAMIC || pOp->p3type==P3_KEYINFO ){
|
||||
sqliteFree(pOp->p3);
|
||||
}
|
||||
if( pOp->p3type==P3_VDBEFUNC ){
|
||||
VdbeFunc *pVdbeFunc = (VdbeFunc *)pOp->p3;
|
||||
sqlite3VdbeDeleteAuxData(pVdbeFunc, 0);
|
||||
sqliteFree(pVdbeFunc);
|
||||
}
|
||||
if( pOp->p3type==P3_MEM ){
|
||||
sqlite3ValueFree((sqlite3_value*)pOp->p3);
|
||||
}
|
||||
freeP3(pOp->p3type, pOp->p3);
|
||||
}
|
||||
sqliteFree(p->aOp);
|
||||
}
|
||||
|
@ -1763,10 +1575,20 @@ 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];
|
||||
u64 x;
|
||||
u32 y;
|
||||
#ifndef NDEBUG
|
||||
/* Verify that integers and floating point values use the same
|
||||
** byte order. The byte order differs on some (broken) architectures.
|
||||
*/
|
||||
static const u64 t1 = ((u64)0x3ff00000)<<32;
|
||||
assert( 1.0==*(double*)&t1 );
|
||||
#endif
|
||||
|
||||
x = (buf[0]<<24) | (buf[1]<<16) | (buf[2]<<8) | buf[3];
|
||||
y = (buf[4]<<24) | (buf[5]<<16) | (buf[6]<<8) | buf[7];
|
||||
x = (x<<32) | y;
|
||||
if( serial_type==6 ){
|
||||
pMem->i = *(i64*)&x;
|
||||
|
@ -1904,7 +1726,7 @@ int sqlite3VdbeIdxRowid(BtCursor *pCur, i64 *rowid){
|
|||
|
||||
sqlite3BtreeKeySize(pCur, &nCellKey);
|
||||
if( nCellKey<=0 ){
|
||||
return SQLITE_CORRUPT;
|
||||
return SQLITE_CORRUPT_BKPT;
|
||||
}
|
||||
rc = sqlite3VdbeMemFromBtree(pCur, 0, nCellKey, 1, &m);
|
||||
if( rc ){
|
||||
|
|
|
@ -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);
|
||||
|
@ -187,15 +187,45 @@ int sqlite3VdbeMemStringify(Mem *pMem, int enc){
|
|||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Memory cell pMem contains the context of an aggregate function.
|
||||
** This routine calls the finalize method for that function. The
|
||||
** result of the aggregate is stored back into pMem.
|
||||
*/
|
||||
void sqlite3VdbeMemFinalize(Mem *pMem, FuncDef *pFunc){
|
||||
if( pFunc && pFunc->xFinalize ){
|
||||
sqlite3_context ctx;
|
||||
assert( (pMem->flags & MEM_Null)!=0 || pFunc==*(FuncDef**)&pMem->i );
|
||||
ctx.s.flags = MEM_Null;
|
||||
ctx.s.z = pMem->zShort;
|
||||
ctx.pMem = pMem;
|
||||
ctx.pFunc = pFunc;
|
||||
pFunc->xFinalize(&ctx);
|
||||
if( pMem->z && pMem->z!=pMem->zShort ){
|
||||
sqliteFree( pMem->z );
|
||||
}
|
||||
*pMem = ctx.s;
|
||||
if( pMem->flags & MEM_Short ){
|
||||
pMem->z = pMem->zShort;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Release any memory held by the Mem. This may leave the Mem in an
|
||||
** inconsistent state, for example with (Mem.z==0) and
|
||||
** (Mem.type==SQLITE_TEXT).
|
||||
*/
|
||||
void sqlite3VdbeMemRelease(Mem *p){
|
||||
if( p->flags & MEM_Dyn ){
|
||||
if( p->flags & (MEM_Dyn|MEM_Agg) ){
|
||||
if( p->xDel ){
|
||||
p->xDel((void *)p->z);
|
||||
if( p->flags & MEM_Agg ){
|
||||
sqlite3VdbeMemFinalize(p, *(FuncDef**)&p->i);
|
||||
assert( (p->flags & MEM_Agg)==0 );
|
||||
sqlite3VdbeMemRelease(p);
|
||||
}else{
|
||||
p->xDel((void *)p->z);
|
||||
}
|
||||
}else{
|
||||
sqliteFree(p->z);
|
||||
}
|
||||
|
@ -256,12 +286,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;
|
||||
}
|
||||
|
@ -285,6 +317,7 @@ void sqlite3VdbeMemSetNull(Mem *pMem){
|
|||
sqlite3VdbeMemRelease(pMem);
|
||||
pMem->flags = MEM_Null;
|
||||
pMem->type = SQLITE_NULL;
|
||||
pMem->n = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -406,6 +439,7 @@ int sqlite3VdbeMemSetStr(
|
|||
switch( enc ){
|
||||
case 0:
|
||||
pMem->flags |= MEM_Blob;
|
||||
pMem->enc = SQLITE_UTF8;
|
||||
break;
|
||||
|
||||
case SQLITE_UTF8:
|
||||
|
@ -666,9 +700,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
|
||||
|
||||
|
@ -696,7 +730,7 @@ const void *sqlite3ValueText(sqlite3_value* pVal, u8 enc){
|
|||
/*
|
||||
** Create a new sqlite3_value object.
|
||||
*/
|
||||
sqlite3_value* sqlite3ValueNew(){
|
||||
sqlite3_value* sqlite3ValueNew(void){
|
||||
Mem *p = sqliteMalloc(sizeof(*p));
|
||||
if( p ){
|
||||
p->flags = MEM_Null;
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Загрузка…
Ссылка в новой задаче