b=326458, Upgrade tree sqlite to 3.3.3
git-svn-id: svn://10.0.0.236/trunk@189436 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
parent
d20ce0fd6b
commit
e109bc7bd7
@ -1,15 +1,11 @@
|
||||
|
||||
This is sqlite 3.2.7.
|
||||
This is sqlite 3.3.3
|
||||
|
||||
See http://www.sqlite.org/ for more info.
|
||||
|
||||
We have a mozilla-specific Makefile.in in src/ (normally no
|
||||
Makefile.in there) that we use to build.
|
||||
|
||||
There's also a hand-written config.h in src; the only thing
|
||||
sqlite wants there is SQLITE_PTR_SZ, which we define to be
|
||||
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;
|
||||
@ -23,5 +19,5 @@ sqlite3 windows source .zip, or autoconfiscate and build a tarball and
|
||||
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
|
||||
-- Vlad Vukicevic <vladimir@pobox.com> 02/2006
|
||||
|
||||
|
||||
80
mozilla/db/sqlite3/sqlite3-param-indexes.patch
Normal file
80
mozilla/db/sqlite3/sqlite3-param-indexes.patch
Normal file
@ -0,0 +1,80 @@
|
||||
diff -ru orig/sqlite333/sqlite3.h sqlite333/sqlite3.h
|
||||
--- orig/sqlite333/sqlite3.h 2006-01-31 08:23:57.000000000 -0800
|
||||
+++ sqlite333/sqlite3.h 2006-02-08 12:12:42.156250000 -0800
|
||||
@@ -1377,6 +1377,20 @@
|
||||
# undef double
|
||||
#endif
|
||||
|
||||
+/*
|
||||
+** Given a wildcard parameter name, return the set of indexes of the
|
||||
+** variables with that name. If there are no variables with the given
|
||||
+** name, return 0. Otherwise, return the number of indexes returned
|
||||
+** in *pIndexes. The array should be freed with
|
||||
+** sqlite3_free_parameter_indexes.
|
||||
+*/
|
||||
+int sqlite3_bind_parameter_indexes(
|
||||
+ sqlite3_stmt *pStmt,
|
||||
+ const char *zName,
|
||||
+ int **pIndexes
|
||||
+);
|
||||
+void sqlite3_free_parameter_indexes(int *pIndexes);
|
||||
+
|
||||
#ifdef __cplusplus
|
||||
} /* End of the 'extern "C"' block */
|
||||
#endif
|
||||
Only in sqlite333: sqlite3.h~
|
||||
diff -ru orig/sqlite333/vdbeapi.c sqlite333/vdbeapi.c
|
||||
--- orig/sqlite333/vdbeapi.c 2006-01-31 08:23:57.000000000 -0800
|
||||
+++ sqlite333/vdbeapi.c 2006-02-08 12:13:46.562500000 -0800
|
||||
@@ -764,6 +764,50 @@
|
||||
}
|
||||
|
||||
/*
|
||||
+** Given a wildcard parameter name, return the set of indexes of the
|
||||
+** variables with that name. If there are no variables with the given
|
||||
+** name, return 0. Otherwise, return the number of indexes returned
|
||||
+** in *pIndexes. The array should be freed with
|
||||
+** sqlite3_free_parameter_indexes.
|
||||
+*/
|
||||
+int sqlite3_bind_parameter_indexes(
|
||||
+ sqlite3_stmt *pStmt,
|
||||
+ const char *zName,
|
||||
+ int **pIndexes
|
||||
+){
|
||||
+ Vdbe *p = (Vdbe*)pStmt;
|
||||
+ int i, j, nVars, *indexes;
|
||||
+ if( p==0 ){
|
||||
+ return 0;
|
||||
+ }
|
||||
+ createVarMap(p);
|
||||
+ if( !zName )
|
||||
+ return 0;
|
||||
+ /* first count */
|
||||
+ nVars = 0;
|
||||
+ for(i=0; i<p->nVar; i++){
|
||||
+ const char *z = p->azVar[i];
|
||||
+ if( z && strcmp(z,zName)==0 ){
|
||||
+ nVars++;
|
||||
+ }
|
||||
+ }
|
||||
+ indexes = sqliteMalloc( sizeof(int) * nVars );
|
||||
+ j = 0;
|
||||
+ for(i=0; i<p->nVar; i++){
|
||||
+ const char *z = p->azVar[i];
|
||||
+ if( z && strcmp(z,zName)==0 )
|
||||
+ indexes[j++] = i+1;
|
||||
+ }
|
||||
+ *pIndexes = indexes;
|
||||
+ return nVars;
|
||||
+}
|
||||
+
|
||||
+void sqlite3_free_parameter_indexes(int *pIndexes)
|
||||
+{
|
||||
+ sqliteFree( pIndexes );
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
** Transfer all bindings from the first statement over to the second.
|
||||
** If the two statements contain a different number of bindings, then
|
||||
** an SQLITE_ERROR is returned.
|
||||
Only in sqlite333: vdbeapi.c~
|
||||
@ -69,6 +69,7 @@ CSRCS = \
|
||||
legacy.c \
|
||||
main.c \
|
||||
opcodes.c \
|
||||
os.c \
|
||||
os_unix.c \
|
||||
os_win.c \
|
||||
os_os2.c \
|
||||
|
||||
@ -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.4 2005-12-13 19:49:35 vladimir%pobox.com Exp $
|
||||
** $Id: alter.c,v 1.5 2006-02-08 21:10:09 vladimir%pobox.com Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include <ctype.h>
|
||||
@ -47,7 +47,7 @@ static void renameTableFunc(
|
||||
|
||||
int token;
|
||||
Token tname;
|
||||
char const *zCsr = zSql;
|
||||
unsigned char const *zCsr = zSql;
|
||||
int len = 0;
|
||||
char *zRet;
|
||||
|
||||
@ -96,7 +96,7 @@ static void renameTriggerFunc(
|
||||
int token;
|
||||
Token tname;
|
||||
int dist = 3;
|
||||
char const *zCsr = zSql;
|
||||
unsigned char const *zCsr = zSql;
|
||||
int len = 0;
|
||||
char *zRet;
|
||||
|
||||
@ -162,7 +162,7 @@ void sqlite3AlterFunctions(sqlite3 *db){
|
||||
int i;
|
||||
|
||||
for(i=0; i<sizeof(aFuncs)/sizeof(aFuncs[0]); i++){
|
||||
sqlite3_create_function(db, aFuncs[i].zName, aFuncs[i].nArg,
|
||||
sqlite3CreateFunc(db, aFuncs[i].zName, aFuncs[i].nArg,
|
||||
SQLITE_UTF8, 0, aFuncs[i].xFunc, 0, 0);
|
||||
}
|
||||
}
|
||||
@ -177,9 +177,16 @@ static char *whereTempTriggers(Parse *pParse, Table *pTab){
|
||||
Trigger *pTrig;
|
||||
char *zWhere = 0;
|
||||
char *tmp = 0;
|
||||
if( pTab->iDb!=1 ){
|
||||
const Schema *pTempSchema = pParse->db->aDb[1].pSchema; /* Temp db schema */
|
||||
|
||||
/* If the table is not located in the temp-db (in which case NULL is
|
||||
** returned, loop through the tables list of triggers. For each trigger
|
||||
** that is not part of the temp-db schema, add a clause to the WHERE
|
||||
** expression being built up in zWhere.
|
||||
*/
|
||||
if( pTab->pSchema!=pTempSchema ){
|
||||
for( pTrig=pTab->pTrigger; pTrig; pTrig=pTrig->pNext ){
|
||||
if( pTrig->iDb==1 ){
|
||||
if( pTrig->pSchema==pTempSchema ){
|
||||
if( !zWhere ){
|
||||
zWhere = sqlite3MPrintf("name=%Q", pTrig->name);
|
||||
}else{
|
||||
@ -204,20 +211,22 @@ static char *whereTempTriggers(Parse *pParse, Table *pTab){
|
||||
static void reloadTableSchema(Parse *pParse, Table *pTab, const char *zName){
|
||||
Vdbe *v;
|
||||
char *zWhere;
|
||||
int iDb;
|
||||
int iDb; /* Index of database containing pTab */
|
||||
#ifndef SQLITE_OMIT_TRIGGER
|
||||
Trigger *pTrig;
|
||||
#endif
|
||||
|
||||
v = sqlite3GetVdbe(pParse);
|
||||
if( !v ) return;
|
||||
iDb = pTab->iDb;
|
||||
iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
|
||||
assert( iDb>=0 );
|
||||
|
||||
#ifndef SQLITE_OMIT_TRIGGER
|
||||
/* Drop any table triggers from the internal schema. */
|
||||
for(pTrig=pTab->pTrigger; pTrig; pTrig=pTrig->pNext){
|
||||
assert( pTrig->iDb==iDb || pTrig->iDb==1 );
|
||||
sqlite3VdbeOp3(v, OP_DropTrigger, pTrig->iDb, 0, pTrig->name, 0);
|
||||
int iTrigDb = sqlite3SchemaToIndex(pParse->db, pTrig->pSchema);
|
||||
assert( iTrigDb==iDb || iTrigDb==1 );
|
||||
sqlite3VdbeOp3(v, OP_DropTrigger, iTrigDb, 0, pTrig->name, 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -233,7 +242,7 @@ static void reloadTableSchema(Parse *pParse, Table *pTab, const char *zName){
|
||||
/* Now, if the table is not stored in the temp database, reload any temp
|
||||
** triggers. Don't use IN(...) in case SQLITE_OMIT_SUBQUERY is defined.
|
||||
*/
|
||||
if( (zWhere=whereTempTriggers(pParse, pTab)) ){
|
||||
if( (zWhere=whereTempTriggers(pParse, pTab))!=0 ){
|
||||
sqlite3VdbeOp3(v, OP_ParseSchema, 1, 0, zWhere, P3_DYNAMIC);
|
||||
}
|
||||
#endif
|
||||
@ -258,12 +267,12 @@ void sqlite3AlterRenameTable(
|
||||
char *zWhere = 0; /* Where clause to locate temp triggers */
|
||||
#endif
|
||||
|
||||
if( sqlite3_malloc_failed ) goto exit_rename_table;
|
||||
if( sqlite3MallocFailed() ) goto exit_rename_table;
|
||||
assert( pSrc->nSrc==1 );
|
||||
|
||||
pTab = sqlite3LocateTable(pParse, pSrc->a[0].zName, pSrc->a[0].zDatabase);
|
||||
if( !pTab ) goto exit_rename_table;
|
||||
iDb = pTab->iDb;
|
||||
iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
|
||||
zDb = db->aDb[iDb].zName;
|
||||
|
||||
/* Get a NULL terminated version of the new table name. */
|
||||
@ -349,7 +358,7 @@ void sqlite3AlterRenameTable(
|
||||
** table. Don't do this if the table being ALTERed is itself located in
|
||||
** the temp database.
|
||||
*/
|
||||
if( (zWhere=whereTempTriggers(pParse, pTab)) ){
|
||||
if( (zWhere=whereTempTriggers(pParse, pTab))!=0 ){
|
||||
sqlite3NestedParse(pParse,
|
||||
"UPDATE sqlite_temp_master SET "
|
||||
"sql = sqlite_rename_trigger(sql, %Q), "
|
||||
@ -385,13 +394,12 @@ void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){
|
||||
char *zCol; /* Null-terminated column definition */
|
||||
Column *pCol; /* The new column */
|
||||
Expr *pDflt; /* Default value for the new column */
|
||||
Vdbe *v;
|
||||
|
||||
if( pParse->nErr ) return;
|
||||
pNew = pParse->pNewTable;
|
||||
assert( pNew );
|
||||
|
||||
iDb = pNew->iDb;
|
||||
iDb = sqlite3SchemaToIndex(pParse->db, pNew->pSchema);
|
||||
zDb = pParse->db->aDb[iDb].zName;
|
||||
zTab = pNew->zName;
|
||||
pCol = &pNew->aCol[pNew->nCol-1];
|
||||
@ -399,6 +407,13 @@ void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){
|
||||
pTab = sqlite3FindTable(pParse->db, zTab, zDb);
|
||||
assert( pTab );
|
||||
|
||||
#ifndef SQLITE_OMIT_AUTHORIZATION
|
||||
/* Invoke the authorization callback. */
|
||||
if( sqlite3AuthCheck(pParse, SQLITE_ALTER_TABLE, zDb, pTab->zName, 0) ){
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* If the default value for the new column was specified with a
|
||||
** literal NULL, then set pDflt to 0. This simplifies checking
|
||||
** for an SQL NULL default below.
|
||||
@ -442,7 +457,7 @@ void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){
|
||||
}
|
||||
|
||||
/* Modify the CREATE TABLE statement. */
|
||||
zCol = sqliteStrNDup(pColDef->z, pColDef->n);
|
||||
zCol = sqliteStrNDup((char*)pColDef->z, pColDef->n);
|
||||
if( zCol ){
|
||||
char *zEnd = &zCol[pColDef->n-1];
|
||||
while( (zEnd>zCol && *zEnd==';') || isspace(*(unsigned char *)zEnd) ){
|
||||
@ -462,22 +477,12 @@ void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){
|
||||
** format to 2. If the default value of the new column is not NULL,
|
||||
** the file format becomes 3.
|
||||
*/
|
||||
if( (v=sqlite3GetVdbe(pParse)) ){
|
||||
int f = (pDflt?3:2);
|
||||
|
||||
/* Only set the file format to $f if it is currently less than $f. */
|
||||
sqlite3VdbeAddOp(v, OP_ReadCookie, iDb, 1);
|
||||
sqlite3VdbeAddOp(v, OP_Integer, f, 0);
|
||||
sqlite3VdbeAddOp(v, OP_Ge, 0, sqlite3VdbeCurrentAddr(v)+3);
|
||||
sqlite3VdbeAddOp(v, OP_Integer, f, 0);
|
||||
sqlite3VdbeAddOp(v, OP_SetCookie, iDb, 1);
|
||||
}
|
||||
sqlite3MinimumFileFormat(pParse, iDb, pDflt ? 3 : 2);
|
||||
|
||||
/* Reload the schema of the modified table. */
|
||||
reloadTableSchema(pParse, pTab, pTab->zName);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** This function is called by the parser after the table-name in
|
||||
** an "ALTER TABLE <table-name> ADD" statement is parsed. Argument
|
||||
@ -501,10 +506,9 @@ void sqlite3AlterBeginAddColumn(Parse *pParse, SrcList *pSrc){
|
||||
int i;
|
||||
int nAlloc;
|
||||
|
||||
|
||||
/* Look up the table being altered. */
|
||||
assert( pParse->pNewTable==0 );
|
||||
if( sqlite3_malloc_failed ) goto exit_begin_add_column;
|
||||
if( sqlite3MallocFailed() ) goto exit_begin_add_column;
|
||||
pTab = sqlite3LocateTable(pParse, pSrc->a[0].zName, pSrc->a[0].zDatabase);
|
||||
if( !pTab ) goto exit_begin_add_column;
|
||||
|
||||
@ -515,7 +519,7 @@ void sqlite3AlterBeginAddColumn(Parse *pParse, SrcList *pSrc){
|
||||
}
|
||||
|
||||
assert( pTab->addColOffset>0 );
|
||||
iDb = pTab->iDb;
|
||||
iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
|
||||
|
||||
/* Put a copy of the Table struct in Parse.pNewTable for the
|
||||
** sqlite3AddColumn() function and friends to modify.
|
||||
@ -540,7 +544,7 @@ void sqlite3AlterBeginAddColumn(Parse *pParse, SrcList *pSrc){
|
||||
pCol->zType = 0;
|
||||
pCol->pDflt = 0;
|
||||
}
|
||||
pNew->iDb = iDb;
|
||||
pNew->pSchema = pParse->db->aDb[iDb].pSchema;
|
||||
pNew->addColOffset = pTab->addColOffset;
|
||||
pNew->nRef = 1;
|
||||
|
||||
|
||||
@ -11,7 +11,7 @@
|
||||
*************************************************************************
|
||||
** 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 $
|
||||
** @(#) $Id: analyze.c,v 1.2 2006-02-08 21:10:09 vladimir%pobox.com Exp $
|
||||
*/
|
||||
#ifndef SQLITE_OMIT_ANALYZE
|
||||
#include "sqliteInt.h"
|
||||
@ -61,8 +61,14 @@ static void openStatTable(
|
||||
sqlite3VdbeAddOp(v, OP_Clear, pStat->tnum, iDb);
|
||||
}
|
||||
|
||||
/* Open the sqlite_stat1 table for writing.
|
||||
/* Open the sqlite_stat1 table for writing. Unless it was created
|
||||
** by this vdbe program, lock it for writing at the shared-cache level.
|
||||
** If this vdbe did create the sqlite_stat1 table, then it must have
|
||||
** already obtained a schema-lock, making the write-lock redundant.
|
||||
*/
|
||||
if( iRootPage>0 ){
|
||||
sqlite3TableLock(pParse, iDb, iRootPage, 1, "sqlite_stat1");
|
||||
}
|
||||
sqlite3VdbeAddOp(v, OP_Integer, iDb, 0);
|
||||
sqlite3VdbeAddOp(v, OP_OpenWrite, iStatCur, iRootPage);
|
||||
sqlite3VdbeAddOp(v, OP_SetNumColumns, iStatCur, 3);
|
||||
@ -86,6 +92,7 @@ static void analyzeOneTable(
|
||||
int topOfLoop; /* The top of the loop */
|
||||
int endOfLoop; /* The end of the loop */
|
||||
int addr; /* The address of an instruction */
|
||||
int iDb; /* Index of database containing pTab */
|
||||
|
||||
v = sqlite3GetVdbe(pParse);
|
||||
if( pTab==0 || pTab->pIndex==0 ){
|
||||
@ -93,21 +100,29 @@ static void analyzeOneTable(
|
||||
return;
|
||||
}
|
||||
|
||||
iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
|
||||
assert( iDb>=0 );
|
||||
#ifndef SQLITE_OMIT_AUTHORIZATION
|
||||
if( sqlite3AuthCheck(pParse, SQLITE_ANALYZE, pTab->zName, 0,
|
||||
pParse->db->aDb[pTab->iDb].zName ) ){
|
||||
pParse->db->aDb[iDb].zName ) ){
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Establish a read-lock on the table at the shared-cache level. */
|
||||
sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName);
|
||||
|
||||
iIdxCur = pParse->nTab;
|
||||
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
|
||||
KeyInfo *pKey = sqlite3IndexKeyinfo(pParse, pIdx);
|
||||
|
||||
/* Open a cursor to the index to be analyzed
|
||||
*/
|
||||
sqlite3VdbeAddOp(v, OP_Integer, pIdx->iDb, 0);
|
||||
assert( iDb==sqlite3SchemaToIndex(pParse->db, pIdx->pSchema) );
|
||||
sqlite3VdbeAddOp(v, OP_Integer, iDb, 0);
|
||||
VdbeComment((v, "# %s", pIdx->zName));
|
||||
sqlite3VdbeOp3(v, OP_OpenRead, iIdxCur, pIdx->tnum,
|
||||
(char*)&pIdx->keyInfo, P3_KEYINFO);
|
||||
(char *)pKey, P3_KEYINFO_HANDOFF);
|
||||
nCol = pIdx->nColumn;
|
||||
if( iMem+nCol*2>=pParse->nMem ){
|
||||
pParse->nMem = iMem+nCol*2+1;
|
||||
@ -139,7 +154,7 @@ static void analyzeOneTable(
|
||||
endOfLoop = sqlite3VdbeMakeLabel(v);
|
||||
sqlite3VdbeAddOp(v, OP_Rewind, iIdxCur, endOfLoop);
|
||||
topOfLoop = sqlite3VdbeCurrentAddr(v);
|
||||
sqlite3VdbeAddOp(v, OP_MemIncr, iMem, 0);
|
||||
sqlite3VdbeAddOp(v, OP_MemIncr, 1, iMem);
|
||||
for(i=0; i<nCol; i++){
|
||||
sqlite3VdbeAddOp(v, OP_Column, iIdxCur, i);
|
||||
sqlite3VdbeAddOp(v, OP_MemLoad, iMem+nCol+i+1, 0);
|
||||
@ -147,7 +162,7 @@ static void analyzeOneTable(
|
||||
}
|
||||
sqlite3VdbeAddOp(v, OP_Goto, 0, endOfLoop);
|
||||
for(i=0; i<nCol; i++){
|
||||
addr = sqlite3VdbeAddOp(v, OP_MemIncr, iMem+i+1, 0);
|
||||
addr = sqlite3VdbeAddOp(v, OP_MemIncr, 1, iMem+i+1);
|
||||
sqlite3VdbeChangeP2(v, topOfLoop + 3*i + 3, addr);
|
||||
sqlite3VdbeAddOp(v, OP_Column, iIdxCur, i);
|
||||
sqlite3VdbeAddOp(v, OP_MemStore, iMem+nCol+i+1, 1);
|
||||
@ -188,13 +203,14 @@ static void analyzeOneTable(
|
||||
sqlite3VdbeAddOp(v, OP_AddImm, -1, 0);
|
||||
sqlite3VdbeAddOp(v, OP_MemLoad, iMem+i+1, 0);
|
||||
sqlite3VdbeAddOp(v, OP_Divide, 0, 0);
|
||||
sqlite3VdbeAddOp(v, OP_ToInt, 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);
|
||||
sqlite3VdbeOp3(v, OP_MakeRecord, 3, 0, "aaa", 0);
|
||||
sqlite3VdbeAddOp(v, OP_Insert, iStatCur, 0);
|
||||
sqlite3VdbeJumpHere(v, addr);
|
||||
}
|
||||
@ -214,6 +230,7 @@ static void loadAnalysis(Parse *pParse, int iDb){
|
||||
*/
|
||||
static void analyzeDatabase(Parse *pParse, int iDb){
|
||||
sqlite3 *db = pParse->db;
|
||||
Schema *pSchema = db->aDb[iDb].pSchema; /* Schema of database iDb */
|
||||
HashElem *k;
|
||||
int iStatCur;
|
||||
int iMem;
|
||||
@ -222,7 +239,7 @@ static void analyzeDatabase(Parse *pParse, int iDb){
|
||||
iStatCur = pParse->nTab++;
|
||||
openStatTable(pParse, iDb, iStatCur, 0);
|
||||
iMem = pParse->nMem;
|
||||
for(k=sqliteHashFirst(&db->aDb[iDb].tblHash); k; k=sqliteHashNext(k)){
|
||||
for(k=sqliteHashFirst(&pSchema->tblHash); k; k=sqliteHashNext(k)){
|
||||
Table *pTab = (Table*)sqliteHashData(k);
|
||||
analyzeOneTable(pParse, pTab, iStatCur, iMem);
|
||||
}
|
||||
@ -238,7 +255,7 @@ static void analyzeTable(Parse *pParse, Table *pTab){
|
||||
int iStatCur;
|
||||
|
||||
assert( pTab!=0 );
|
||||
iDb = pTab->iDb;
|
||||
iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
|
||||
sqlite3BeginWriteOperation(pParse, 0, iDb);
|
||||
iStatCur = pParse->nTab++;
|
||||
openStatTable(pParse, iDb, iStatCur, pTab->zName);
|
||||
@ -360,7 +377,7 @@ void sqlite3AnalysisLoad(sqlite3 *db, int iDb){
|
||||
char *zSql;
|
||||
|
||||
/* Clear any prior statistics */
|
||||
for(i=sqliteHashFirst(&db->aDb[iDb].idxHash); i; i=sqliteHashNext(i)){
|
||||
for(i=sqliteHashFirst(&db->aDb[iDb].pSchema->idxHash);i;i=sqliteHashNext(i)){
|
||||
Index *pIdx = sqliteHashData(i);
|
||||
sqlite3DefaultRowEst(pIdx);
|
||||
}
|
||||
|
||||
@ -11,201 +11,342 @@
|
||||
*************************************************************************
|
||||
** This file contains code used to implement the ATTACH and DETACH commands.
|
||||
**
|
||||
** $Id: attach.c,v 1.34 2005/08/20 03:03:04 drh Exp $
|
||||
** $Id: attach.c,v 1.49 2006/01/24 12:09:18 danielk1977 Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
|
||||
/*
|
||||
** This routine is called by the parser to process an ATTACH statement:
|
||||
** Resolve an expression that was part of an ATTACH or DETACH statement. This
|
||||
** is slightly different from resolving a normal SQL expression, because simple
|
||||
** identifiers are treated as strings, not possible column names or aliases.
|
||||
**
|
||||
** ATTACH DATABASE filename AS dbname
|
||||
** i.e. if the parser sees:
|
||||
**
|
||||
** The pFilename and pDbname arguments are the tokens that define the
|
||||
** filename and dbname in the ATTACH statement.
|
||||
** ATTACH DATABASE abc AS def
|
||||
**
|
||||
** it treats the two expressions as literal strings 'abc' and 'def' instead of
|
||||
** looking for columns of the same name.
|
||||
**
|
||||
** This only applies to the root node of pExpr, so the statement:
|
||||
**
|
||||
** ATTACH DATABASE abc||def AS 'db2'
|
||||
**
|
||||
** will fail because neither abc or def can be resolved.
|
||||
*/
|
||||
void sqlite3Attach(
|
||||
Parse *pParse, /* The parser context */
|
||||
Token *pFilename, /* Name of database file */
|
||||
Token *pDbname, /* Name of the database to use internally */
|
||||
int keyType, /* 0: no key. 1: TEXT, 2: BLOB */
|
||||
Token *pKey /* Text of the key for keytype 1 and 2 */
|
||||
static int resolveAttachExpr(NameContext *pName, Expr *pExpr)
|
||||
{
|
||||
int rc = SQLITE_OK;
|
||||
if( pExpr ){
|
||||
if( pExpr->op!=TK_ID ){
|
||||
rc = sqlite3ExprResolveNames(pName, pExpr);
|
||||
}else{
|
||||
pExpr->op = TK_STRING;
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** An SQL user-function registered to do the work of an ATTACH statement. The
|
||||
** three arguments to the function come directly from an attach statement:
|
||||
**
|
||||
** ATTACH DATABASE x AS y KEY z
|
||||
**
|
||||
** SELECT sqlite_attach(x, y, z)
|
||||
**
|
||||
** If the optional "KEY z" syntax is omitted, an SQL NULL is passed as the
|
||||
** third argument.
|
||||
*/
|
||||
static void attachFunc(
|
||||
sqlite3_context *context,
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
int i;
|
||||
int rc = 0;
|
||||
sqlite3 *db = sqlite3_user_data(context);
|
||||
const char *zName;
|
||||
const char *zFile;
|
||||
Db *aNew;
|
||||
int rc, i;
|
||||
char *zFile = 0;
|
||||
char *zName = 0;
|
||||
sqlite3 *db;
|
||||
Vdbe *v;
|
||||
char zErr[128];
|
||||
char *zErrDyn = 0;
|
||||
|
||||
v = sqlite3GetVdbe(pParse);
|
||||
if( !v ) return;
|
||||
sqlite3VdbeAddOp(v, OP_Expire, 1, 0);
|
||||
sqlite3VdbeAddOp(v, OP_Halt, 0, 0);
|
||||
if( pParse->explain ) return;
|
||||
db = pParse->db;
|
||||
zFile = (const char *)sqlite3_value_text(argv[0]);
|
||||
zName = (const char *)sqlite3_value_text(argv[1]);
|
||||
|
||||
/* Check for the following errors:
|
||||
**
|
||||
** * Too many attached databases,
|
||||
** * Transaction currently open
|
||||
** * Specified database name already being used.
|
||||
*/
|
||||
if( db->nDb>=MAX_ATTACHED+2 ){
|
||||
sqlite3ErrorMsg(pParse, "too many attached databases - max %d",
|
||||
MAX_ATTACHED);
|
||||
pParse->rc = SQLITE_ERROR;
|
||||
return;
|
||||
sqlite3_snprintf(
|
||||
127, zErr, "too many attached databases - max %d", MAX_ATTACHED
|
||||
);
|
||||
goto attach_error;
|
||||
}
|
||||
|
||||
if( !db->autoCommit ){
|
||||
sqlite3ErrorMsg(pParse, "cannot ATTACH database within transaction");
|
||||
pParse->rc = SQLITE_ERROR;
|
||||
return;
|
||||
}
|
||||
|
||||
zFile = sqlite3NameFromToken(pFilename);
|
||||
if( zFile==0 ){
|
||||
goto attach_end;
|
||||
}
|
||||
#ifndef SQLITE_OMIT_AUTHORIZATION
|
||||
if( sqlite3AuthCheck(pParse, SQLITE_ATTACH, zFile, 0, 0)!=SQLITE_OK ){
|
||||
goto attach_end;
|
||||
}
|
||||
#endif /* SQLITE_OMIT_AUTHORIZATION */
|
||||
|
||||
zName = sqlite3NameFromToken(pDbname);
|
||||
if( zName==0 ){
|
||||
goto attach_end;
|
||||
strcpy(zErr, "cannot ATTACH database within transaction");
|
||||
goto attach_error;
|
||||
}
|
||||
for(i=0; i<db->nDb; i++){
|
||||
char *z = db->aDb[i].zName;
|
||||
if( z && sqlite3StrICmp(z, zName)==0 ){
|
||||
sqlite3ErrorMsg(pParse, "database %s is already in use", zName);
|
||||
pParse->rc = SQLITE_ERROR;
|
||||
goto attach_end;
|
||||
sqlite3_snprintf(127, zErr, "database %s is already in use", zName);
|
||||
goto attach_error;
|
||||
}
|
||||
}
|
||||
|
||||
/* Allocate the new entry in the db->aDb[] array and initialise the schema
|
||||
** hash tables.
|
||||
*/
|
||||
if( db->aDb==db->aDbStatic ){
|
||||
aNew = sqliteMalloc( sizeof(db->aDb[0])*3 );
|
||||
if( aNew==0 ){
|
||||
goto attach_end;
|
||||
return;
|
||||
}
|
||||
memcpy(aNew, db->aDb, sizeof(db->aDb[0])*2);
|
||||
}else{
|
||||
aNew = sqliteRealloc(db->aDb, sizeof(db->aDb[0])*(db->nDb+1) );
|
||||
if( aNew==0 ){
|
||||
goto attach_end;
|
||||
return;
|
||||
}
|
||||
}
|
||||
db->aDb = aNew;
|
||||
aNew = &db->aDb[db->nDb++];
|
||||
memset(aNew, 0, sizeof(*aNew));
|
||||
sqlite3HashInit(&aNew->tblHash, SQLITE_HASH_STRING, 0);
|
||||
sqlite3HashInit(&aNew->idxHash, SQLITE_HASH_STRING, 0);
|
||||
sqlite3HashInit(&aNew->trigHash, SQLITE_HASH_STRING, 0);
|
||||
sqlite3HashInit(&aNew->aFKey, SQLITE_HASH_STRING, 1);
|
||||
aNew->zName = zName;
|
||||
zName = 0;
|
||||
aNew->safety_level = 3;
|
||||
|
||||
/* Open the database file. If the btree is successfully opened, use
|
||||
** it to obtain the database schema. At this point the schema may
|
||||
** or may not be initialised.
|
||||
*/
|
||||
rc = sqlite3BtreeFactory(db, zFile, 0, MAX_PAGES, &aNew->pBt);
|
||||
if( rc ){
|
||||
sqlite3ErrorMsg(pParse, "unable to open database: %s", zFile);
|
||||
if( rc==SQLITE_OK ){
|
||||
aNew->pSchema = sqlite3SchemaGet(aNew->pBt);
|
||||
if( !aNew->pSchema ){
|
||||
rc = SQLITE_NOMEM;
|
||||
}else if( aNew->pSchema->file_format && aNew->pSchema->enc!=ENC(db) ){
|
||||
strcpy(zErr,
|
||||
"attached databases must use the same text encoding as main database");
|
||||
goto attach_error;
|
||||
}
|
||||
}
|
||||
aNew->zName = sqliteStrDup(zName);
|
||||
aNew->safety_level = 3;
|
||||
|
||||
#if SQLITE_HAS_CODEC
|
||||
{
|
||||
extern int sqlite3CodecAttach(sqlite3*, int, void*, int);
|
||||
char *zKey;
|
||||
extern void sqlite3CodecGetKey(sqlite3*, int, void**, int*);
|
||||
int nKey;
|
||||
if( keyType==0 ){
|
||||
/* No key specified. Use the key from the main database */
|
||||
extern void sqlite3CodecGetKey(sqlite3*, int, void**, int*);
|
||||
sqlite3CodecGetKey(db, 0, (void**)&zKey, &nKey);
|
||||
}else if( keyType==1 ){
|
||||
/* Key specified as text */
|
||||
zKey = sqlite3NameFromToken(pKey);
|
||||
nKey = strlen(zKey);
|
||||
}else{
|
||||
/* Key specified as a BLOB */
|
||||
char *zTemp;
|
||||
assert( keyType==2 );
|
||||
pKey->z++;
|
||||
pKey->n--;
|
||||
zTemp = sqlite3NameFromToken(pKey);
|
||||
zKey = sqlite3HexToBlob(zTemp);
|
||||
sqliteFree(zTemp);
|
||||
}
|
||||
sqlite3CodecAttach(db, db->nDb-1, zKey, nKey);
|
||||
if( keyType ){
|
||||
sqliteFree(zKey);
|
||||
char *zKey;
|
||||
int t = sqlite3_value_type(argv[2]);
|
||||
switch( t ){
|
||||
case SQLITE_INTEGER:
|
||||
case SQLITE_FLOAT:
|
||||
zErrDyn = sqliteStrDup("Invalid key value");
|
||||
rc = SQLITE_ERROR;
|
||||
break;
|
||||
|
||||
case SQLITE_TEXT:
|
||||
case SQLITE_BLOB:
|
||||
nKey = sqlite3_value_bytes(argv[2]);
|
||||
zKey = (char *)sqlite3_value_blob(argv[2]);
|
||||
sqlite3CodecAttach(db, db->nDb-1, zKey, nKey);
|
||||
break;
|
||||
|
||||
case SQLITE_NULL:
|
||||
/* No key specified. Use the key from the main database */
|
||||
sqlite3CodecGetKey(db, 0, (void**)&zKey, &nKey);
|
||||
sqlite3CodecAttach(db, db->nDb-1, zKey, nKey);
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
db->flags &= ~SQLITE_Initialized;
|
||||
if( pParse->nErr==0 && rc==SQLITE_OK ){
|
||||
rc = sqlite3ReadSchema(pParse);
|
||||
|
||||
/* If the file was opened successfully, read the schema for the new database.
|
||||
** If this fails, or if opening the file failed, then close the file and
|
||||
** remove the entry from the db->aDb[] array. i.e. put everything back the way
|
||||
** we found it.
|
||||
*/
|
||||
if( rc==SQLITE_OK ){
|
||||
sqlite3SafetyOn(db);
|
||||
rc = sqlite3Init(db, &zErrDyn);
|
||||
sqlite3SafetyOff(db);
|
||||
}
|
||||
if( rc ){
|
||||
int i = db->nDb - 1;
|
||||
assert( i>=2 );
|
||||
if( db->aDb[i].pBt ){
|
||||
sqlite3BtreeClose(db->aDb[i].pBt);
|
||||
db->aDb[i].pBt = 0;
|
||||
int iDb = db->nDb - 1;
|
||||
assert( iDb>=2 );
|
||||
if( db->aDb[iDb].pBt ){
|
||||
sqlite3BtreeClose(db->aDb[iDb].pBt);
|
||||
db->aDb[iDb].pBt = 0;
|
||||
db->aDb[iDb].pSchema = 0;
|
||||
}
|
||||
sqlite3ResetInternalSchema(db, 0);
|
||||
assert( pParse->nErr>0 ); /* Always set by sqlite3ReadSchema() */
|
||||
if( pParse->rc==SQLITE_OK ){
|
||||
pParse->rc = SQLITE_ERROR;
|
||||
}
|
||||
db->nDb = iDb;
|
||||
sqlite3_snprintf(127, zErr, "unable to open database: %s", zFile);
|
||||
goto attach_error;
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
attach_end:
|
||||
sqliteFree(zFile);
|
||||
sqliteFree(zName);
|
||||
attach_error:
|
||||
/* Return an error if we get here */
|
||||
if( zErrDyn ){
|
||||
sqlite3_result_error(context, zErrDyn, -1);
|
||||
sqliteFree(zErrDyn);
|
||||
}else{
|
||||
zErr[sizeof(zErr)-1] = 0;
|
||||
sqlite3_result_error(context, zErr, -1);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** This routine is called by the parser to process a DETACH statement:
|
||||
** An SQL user-function registered to do the work of an DETACH statement. The
|
||||
** three arguments to the function come directly from a detach statement:
|
||||
**
|
||||
** DETACH DATABASE dbname
|
||||
** DETACH DATABASE x
|
||||
**
|
||||
** The pDbname argument is the name of the database in the DETACH statement.
|
||||
** SELECT sqlite_detach(x)
|
||||
*/
|
||||
void sqlite3Detach(Parse *pParse, Token *pDbname){
|
||||
static void detachFunc(
|
||||
sqlite3_context *context,
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
const char *zName = (const char *)sqlite3_value_text(argv[0]);
|
||||
sqlite3 *db = sqlite3_user_data(context);
|
||||
int i;
|
||||
sqlite3 *db;
|
||||
Vdbe *v;
|
||||
Db *pDb = 0;
|
||||
char *zName;
|
||||
char zErr[128];
|
||||
|
||||
v = sqlite3GetVdbe(pParse);
|
||||
if( !v ) return;
|
||||
sqlite3VdbeAddOp(v, OP_Expire, 0, 0);
|
||||
sqlite3VdbeAddOp(v, OP_Halt, 0, 0);
|
||||
if( pParse->explain ) return;
|
||||
db = pParse->db;
|
||||
zName = sqlite3NameFromToken(pDbname);
|
||||
if( zName==0 ) return;
|
||||
assert(zName);
|
||||
for(i=0; i<db->nDb; i++){
|
||||
pDb = &db->aDb[i];
|
||||
if( pDb->pBt==0 ) continue;
|
||||
if( sqlite3StrICmp(pDb->zName, zName)==0 ) break;
|
||||
}
|
||||
|
||||
if( i>=db->nDb ){
|
||||
sqlite3ErrorMsg(pParse, "no such database: %z", zName);
|
||||
return;
|
||||
sqlite3_snprintf(sizeof(zErr), zErr, "no such database: %s", zName);
|
||||
goto detach_error;
|
||||
}
|
||||
if( i<2 ){
|
||||
sqlite3ErrorMsg(pParse, "cannot detach database %z", zName);
|
||||
return;
|
||||
sqlite3_snprintf(sizeof(zErr), zErr, "cannot detach database %s", zName);
|
||||
goto detach_error;
|
||||
}
|
||||
sqliteFree(zName);
|
||||
if( !db->autoCommit ){
|
||||
sqlite3ErrorMsg(pParse, "cannot DETACH database within transaction");
|
||||
pParse->rc = SQLITE_ERROR;
|
||||
return;
|
||||
strcpy(zErr, "cannot DETACH database within transaction");
|
||||
goto detach_error;
|
||||
}
|
||||
#ifndef SQLITE_OMIT_AUTHORIZATION
|
||||
if( sqlite3AuthCheck(pParse,SQLITE_DETACH,db->aDb[i].zName,0,0)!=SQLITE_OK ){
|
||||
return;
|
||||
}
|
||||
#endif /* SQLITE_OMIT_AUTHORIZATION */
|
||||
|
||||
sqlite3BtreeClose(pDb->pBt);
|
||||
pDb->pBt = 0;
|
||||
pDb->pSchema = 0;
|
||||
sqlite3ResetInternalSchema(db, 0);
|
||||
return;
|
||||
|
||||
detach_error:
|
||||
sqlite3_result_error(context, zErr, -1);
|
||||
}
|
||||
|
||||
/*
|
||||
** This procedure generates VDBE code for a single invocation of either the
|
||||
** sqlite_detach() or sqlite_attach() SQL user functions.
|
||||
*/
|
||||
static void codeAttach(
|
||||
Parse *pParse, /* The parser context */
|
||||
int type, /* Either SQLITE_ATTACH or SQLITE_DETACH */
|
||||
const char *zFunc, /* Either "sqlite_attach" or "sqlite_detach */
|
||||
int nFunc, /* Number of args to pass to zFunc */
|
||||
Expr *pAuthArg, /* Expression to pass to authorization callback */
|
||||
Expr *pFilename, /* Name of database file */
|
||||
Expr *pDbname, /* Name of the database to use internally */
|
||||
Expr *pKey /* Database key for encryption extension */
|
||||
){
|
||||
int rc;
|
||||
NameContext sName;
|
||||
Vdbe *v;
|
||||
FuncDef *pFunc;
|
||||
sqlite3* db = pParse->db;
|
||||
|
||||
#ifndef SQLITE_OMIT_AUTHORIZATION
|
||||
assert( sqlite3MallocFailed() || pAuthArg );
|
||||
if( pAuthArg ){
|
||||
char *zAuthArg = sqlite3NameFromToken(&pAuthArg->span);
|
||||
if( !zAuthArg ){
|
||||
goto attach_end;
|
||||
}
|
||||
rc = sqlite3AuthCheck(pParse, type, zAuthArg, 0, 0);
|
||||
sqliteFree(zAuthArg);
|
||||
if(rc!=SQLITE_OK ){
|
||||
goto attach_end;
|
||||
}
|
||||
}
|
||||
#endif /* SQLITE_OMIT_AUTHORIZATION */
|
||||
|
||||
memset(&sName, 0, sizeof(NameContext));
|
||||
sName.pParse = pParse;
|
||||
|
||||
if(
|
||||
SQLITE_OK!=(rc = resolveAttachExpr(&sName, pFilename)) ||
|
||||
SQLITE_OK!=(rc = resolveAttachExpr(&sName, pDbname)) ||
|
||||
SQLITE_OK!=(rc = resolveAttachExpr(&sName, pKey))
|
||||
){
|
||||
pParse->nErr++;
|
||||
goto attach_end;
|
||||
}
|
||||
|
||||
v = sqlite3GetVdbe(pParse);
|
||||
sqlite3ExprCode(pParse, pFilename);
|
||||
sqlite3ExprCode(pParse, pDbname);
|
||||
sqlite3ExprCode(pParse, pKey);
|
||||
|
||||
assert( v || sqlite3MallocFailed() );
|
||||
if( v ){
|
||||
sqlite3VdbeAddOp(v, OP_Function, 0, nFunc);
|
||||
pFunc = sqlite3FindFunction(db, zFunc, strlen(zFunc), nFunc, SQLITE_UTF8,0);
|
||||
sqlite3VdbeChangeP3(v, -1, (char *)pFunc, P3_FUNCDEF);
|
||||
|
||||
/* Code an OP_Expire. For an ATTACH statement, set P1 to true (expire this
|
||||
** statement only). For DETACH, set it to false (expire all existing
|
||||
** statements).
|
||||
*/
|
||||
sqlite3VdbeAddOp(v, OP_Expire, (type==SQLITE_ATTACH), 0);
|
||||
}
|
||||
|
||||
attach_end:
|
||||
sqlite3ExprDelete(pFilename);
|
||||
sqlite3ExprDelete(pDbname);
|
||||
sqlite3ExprDelete(pKey);
|
||||
}
|
||||
|
||||
/*
|
||||
** Called by the parser to compile a DETACH statement.
|
||||
**
|
||||
** DETACH pDbname
|
||||
*/
|
||||
void sqlite3Detach(Parse *pParse, Expr *pDbname){
|
||||
codeAttach(pParse, SQLITE_DETACH, "sqlite_detach", 1, pDbname, 0, 0, pDbname);
|
||||
}
|
||||
|
||||
/*
|
||||
** Called by the parser to compile an ATTACH statement.
|
||||
**
|
||||
** ATTACH p AS pDbname KEY pKey
|
||||
*/
|
||||
void sqlite3Attach(Parse *pParse, Expr *p, Expr *pDbname, Expr *pKey){
|
||||
codeAttach(pParse, SQLITE_ATTACH, "sqlite_attach", 3, p, p, pDbname, pKey);
|
||||
}
|
||||
|
||||
/*
|
||||
** Register the functions sqlite_attach and sqlite_detach.
|
||||
*/
|
||||
void sqlite3AttachFunctions(sqlite3 *db){
|
||||
static const int enc = SQLITE_UTF8;
|
||||
sqlite3CreateFunc(db, "sqlite_attach", 3, enc, db, attachFunc, 0, 0);
|
||||
sqlite3CreateFunc(db, "sqlite_detach", 1, enc, db, detachFunc, 0, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@ -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.22 2005/07/29 15:36:15 drh Exp $
|
||||
** $Id: auth.c,v 1.24 2006/01/13 13:55:45 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
|
||||
@ -112,10 +112,17 @@ void sqlite3AuthRead(
|
||||
int iSrc; /* Index in pTabList->a[] of table being read */
|
||||
const char *zDBase; /* Name of database being accessed */
|
||||
TriggerStack *pStack; /* The stack of current triggers */
|
||||
int iDb; /* The index of the database the expression refers to */
|
||||
|
||||
if( db->xAuth==0 ) return;
|
||||
if( pExpr->op==TK_AS ) return;
|
||||
assert( pExpr->op==TK_COLUMN );
|
||||
iDb = sqlite3SchemaToIndex(pParse->db, pExpr->pSchema);
|
||||
if( iDb<0 ){
|
||||
/* An attempt to read a column out of a subquery or other
|
||||
** temporary table. */
|
||||
return;
|
||||
}
|
||||
for(iSrc=0; pTabList && iSrc<pTabList->nSrc; iSrc++){
|
||||
if( pExpr->iTable==pTabList->a[iSrc].iCursor ) break;
|
||||
}
|
||||
@ -140,14 +147,14 @@ void sqlite3AuthRead(
|
||||
}else{
|
||||
zCol = "ROWID";
|
||||
}
|
||||
assert( pExpr->iDb<db->nDb );
|
||||
zDBase = db->aDb[pExpr->iDb].zName;
|
||||
assert( iDb>=0 && iDb<db->nDb );
|
||||
zDBase = db->aDb[iDb].zName;
|
||||
rc = db->xAuth(db->pAuthArg, SQLITE_READ, pTab->zName, zCol, zDBase,
|
||||
pParse->zAuthContext);
|
||||
if( rc==SQLITE_IGNORE ){
|
||||
pExpr->op = TK_NULL;
|
||||
}else if( rc==SQLITE_DENY ){
|
||||
if( db->nDb>2 || pExpr->iDb!=0 ){
|
||||
if( db->nDb>2 || iDb!=0 ){
|
||||
sqlite3ErrorMsg(pParse, "access to %s.%s.%s is prohibited",
|
||||
zDBase, pTab->zName, zCol);
|
||||
}else{
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -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.64 2005/08/27 16:36:49 drh Exp $
|
||||
** @(#) $Id: btree.h,v 1.69 2006/01/07 13:21:04 danielk1977 Exp $
|
||||
*/
|
||||
#ifndef _BTREE_H_
|
||||
#define _BTREE_H_
|
||||
@ -36,10 +36,12 @@
|
||||
*/
|
||||
typedef struct Btree Btree;
|
||||
typedef struct BtCursor BtCursor;
|
||||
typedef struct BtShared BtShared;
|
||||
|
||||
|
||||
int sqlite3BtreeOpen(
|
||||
const char *zFilename, /* Name of database file to open */
|
||||
sqlite3 *db, /* Associated database connection */
|
||||
Btree **, /* Return open Btree* here */
|
||||
int flags /* Flags */
|
||||
);
|
||||
@ -74,7 +76,9 @@ int sqlite3BtreeCreateTable(Btree*, int*, int flags);
|
||||
int sqlite3BtreeIsInTrans(Btree*);
|
||||
int sqlite3BtreeIsInStmt(Btree*);
|
||||
int sqlite3BtreeSync(Btree*, const char *zMaster);
|
||||
int sqlite3BtreeReset(Btree *);
|
||||
void *sqlite3BtreeSchema(Btree *, int, void(*)(void *));
|
||||
int sqlite3BtreeSchemaLocked(Btree *);
|
||||
int sqlite3BtreeLockTable(Btree *, int, u8);
|
||||
|
||||
const char *sqlite3BtreeGetFilename(Btree *);
|
||||
const char *sqlite3BtreeGetDirname(Btree *);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -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.2 2005-12-13 19:49:35 vladimir%pobox.com Exp $
|
||||
** $Id: callback.c,v 1.3 2006-02-08 21:10:10 vladimir%pobox.com Exp $
|
||||
*/
|
||||
|
||||
#include "sqliteInt.h"
|
||||
@ -29,17 +29,19 @@ static void callCollNeeded(sqlite3 *db, const char *zName, int nName){
|
||||
if( db->xCollNeeded ){
|
||||
char *zExternal = sqliteStrNDup(zName, nName);
|
||||
if( !zExternal ) return;
|
||||
db->xCollNeeded(db->pCollNeededArg, db, (int)db->enc, zExternal);
|
||||
db->xCollNeeded(db->pCollNeededArg, db, (int)ENC(db), zExternal);
|
||||
sqliteFree(zExternal);
|
||||
}
|
||||
#ifndef SQLITE_OMIT_UTF16
|
||||
if( db->xCollNeeded16 ){
|
||||
char const *zExternal;
|
||||
sqlite3_value *pTmp = sqlite3GetTransientValue(db);
|
||||
sqlite3ValueSetStr(pTmp, -1, zName, SQLITE_UTF8, SQLITE_STATIC);
|
||||
sqlite3_value *pTmp = sqlite3ValueNew();
|
||||
sqlite3ValueSetStr(pTmp, nName, zName, SQLITE_UTF8, SQLITE_STATIC);
|
||||
zExternal = sqlite3ValueText(pTmp, SQLITE_UTF16NATIVE);
|
||||
if( !zExternal ) return;
|
||||
db->xCollNeeded16(db->pCollNeededArg, db, (int)db->enc, zExternal);
|
||||
if( zExternal ){
|
||||
db->xCollNeeded16(db->pCollNeededArg, db, (int)ENC(db), zExternal);
|
||||
}
|
||||
sqlite3ValueFree(pTmp);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@ -90,14 +92,14 @@ CollSeq *sqlite3GetCollSeq(
|
||||
|
||||
p = pColl;
|
||||
if( !p ){
|
||||
p = sqlite3FindCollSeq(db, db->enc, zName, nName, 0);
|
||||
p = sqlite3FindCollSeq(db, ENC(db), zName, nName, 0);
|
||||
}
|
||||
if( !p || !p->xCmp ){
|
||||
/* No collation sequence of this type for this encoding is registered.
|
||||
** Call the collation factory to see if it can supply us with one.
|
||||
*/
|
||||
callCollNeeded(db, zName, nName);
|
||||
p = sqlite3FindCollSeq(db, db->enc, zName, nName, 0);
|
||||
p = sqlite3FindCollSeq(db, ENC(db), zName, nName, 0);
|
||||
}
|
||||
if( p && !p->xCmp && synthCollSeq(db, p) ){
|
||||
p = 0;
|
||||
@ -128,6 +130,7 @@ int sqlite3CheckCollSeq(Parse *pParse, CollSeq *pColl){
|
||||
pParse->nErr++;
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
assert( p==pColl );
|
||||
}
|
||||
return SQLITE_OK;
|
||||
}
|
||||
@ -175,7 +178,8 @@ static CollSeq *findCollSeqEntry(
|
||||
** return the pColl pointer to be deleted (because it wasn't added
|
||||
** to the hash table).
|
||||
*/
|
||||
assert( !pDel || (sqlite3_malloc_failed && pDel==pColl) );
|
||||
assert( !pDel ||
|
||||
(sqlite3MallocFailed() && pDel==pColl) );
|
||||
sqliteFree(pDel);
|
||||
}
|
||||
}
|
||||
@ -197,7 +201,12 @@ CollSeq *sqlite3FindCollSeq(
|
||||
int nName,
|
||||
int create
|
||||
){
|
||||
CollSeq *pColl = findCollSeqEntry(db, zName, nName, create);
|
||||
CollSeq *pColl;
|
||||
if( zName ){
|
||||
pColl = findCollSeqEntry(db, zName, nName, create);
|
||||
}else{
|
||||
pColl = db->pDfltColl;
|
||||
}
|
||||
assert( SQLITE_UTF8==1 && SQLITE_UTF16LE==2 && SQLITE_UTF16BE==3 );
|
||||
assert( enc>=SQLITE_UTF8 && enc<=SQLITE_UTF16BE );
|
||||
if( pColl ) pColl += enc-1;
|
||||
@ -286,7 +295,7 @@ FuncDef *sqlite3FindFunction(
|
||||
** new entry to the hash table and return it.
|
||||
*/
|
||||
if( createFlag && bestmatch<6 &&
|
||||
(pBest = sqliteMalloc(sizeof(*pBest)+nName)) ){
|
||||
(pBest = sqliteMalloc(sizeof(*pBest)+nName))!=0 ){
|
||||
pBest->nArg = nArg;
|
||||
pBest->pNext = pFirst;
|
||||
pBest->iPrefEnc = enc;
|
||||
|
||||
@ -16,7 +16,7 @@
|
||||
** 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 $
|
||||
** $Id: complete.c,v 1.2 2006-02-08 21:10:10 vladimir%pobox.com Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#ifndef SQLITE_OMIT_COMPLETE
|
||||
@ -257,7 +257,7 @@ int sqlite3_complete16(const void *zSql){
|
||||
rc = sqlite3_complete(zSql8);
|
||||
}
|
||||
sqlite3ValueFree(pVal);
|
||||
return rc;
|
||||
return sqlite3ApiExit(0, 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.45 2005/06/25 18:42:14 drh Exp $
|
||||
** $Id: date.c,v 1.53 2006/01/24 12:09:19 danielk1977 Exp $
|
||||
**
|
||||
** NOTES:
|
||||
**
|
||||
@ -105,18 +105,20 @@ static int getDigits(const char *zDate, ...){
|
||||
val = 0;
|
||||
while( N-- ){
|
||||
if( !isdigit(*(u8*)zDate) ){
|
||||
return cnt;
|
||||
goto end_getDigits;
|
||||
}
|
||||
val = val*10 + *zDate - '0';
|
||||
zDate++;
|
||||
}
|
||||
if( val<min || val>max || (nextC!=0 && nextC!=*zDate) ){
|
||||
return cnt;
|
||||
goto end_getDigits;
|
||||
}
|
||||
*pVal = val;
|
||||
zDate++;
|
||||
cnt++;
|
||||
}while( nextC );
|
||||
va_end(ap);
|
||||
end_getDigits:
|
||||
return cnt;
|
||||
}
|
||||
|
||||
@ -236,7 +238,7 @@ static void computeJD(DateTime *p){
|
||||
if( p->validHMS ){
|
||||
p->rJD += (p->h*3600.0 + p->m*60.0 + p->s)/86400.0;
|
||||
if( p->validTZ ){
|
||||
p->rJD += p->tz*60/86400.0;
|
||||
p->rJD -= p->tz*60/86400.0;
|
||||
p->validHMS = 0;
|
||||
p->validTZ = 0;
|
||||
}
|
||||
@ -639,10 +641,10 @@ static int isDate(int argc, sqlite3_value **argv, DateTime *p){
|
||||
int i;
|
||||
if( argc==0 ) return 1;
|
||||
if( SQLITE_NULL==sqlite3_value_type(argv[0]) ||
|
||||
parseDateOrTime(sqlite3_value_text(argv[0]), p) ) return 1;
|
||||
parseDateOrTime((char*)sqlite3_value_text(argv[0]), p) ) return 1;
|
||||
for(i=1; i<argc; i++){
|
||||
if( SQLITE_NULL==sqlite3_value_type(argv[i]) ||
|
||||
parseModifier(sqlite3_value_text(argv[i]), p) ) return 1;
|
||||
parseModifier((char*)sqlite3_value_text(argv[i]), p) ) return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -755,7 +757,7 @@ static void strftimeFunc(
|
||||
DateTime x;
|
||||
int n, i, j;
|
||||
char *z;
|
||||
const char *zFmt = sqlite3_value_text(argv[0]);
|
||||
const char *zFmt = (const char*)sqlite3_value_text(argv[0]);
|
||||
char zBuf[100];
|
||||
if( zFmt==0 || isDate(argc-1, argv+1, &x) ) return;
|
||||
for(i=0, n=1; zFmt[i]; i++, n++){
|
||||
@ -816,20 +818,20 @@ static void strftimeFunc(
|
||||
case 'H': sprintf(&z[j],"%02d",x.h); j+=2; break;
|
||||
case 'W': /* Fall thru */
|
||||
case 'j': {
|
||||
int n; /* Number of days since 1st day of year */
|
||||
int nDay; /* Number of days since 1st day of year */
|
||||
DateTime y = x;
|
||||
y.validJD = 0;
|
||||
y.M = 1;
|
||||
y.D = 1;
|
||||
computeJD(&y);
|
||||
n = x.rJD - y.rJD;
|
||||
nDay = x.rJD - y.rJD;
|
||||
if( zFmt[i]=='W' ){
|
||||
int wd; /* 0=Monday, 1=Tuesday, ... 6=Sunday */
|
||||
wd = ((int)(x.rJD+0.5)) % 7;
|
||||
sprintf(&z[j],"%02d",(n+7-wd)/7);
|
||||
sprintf(&z[j],"%02d",(nDay+7-wd)/7);
|
||||
j += 2;
|
||||
}else{
|
||||
sprintf(&z[j],"%03d",n+1);
|
||||
sprintf(&z[j],"%03d",nDay+1);
|
||||
j += 3;
|
||||
}
|
||||
break;
|
||||
@ -974,7 +976,7 @@ void sqlite3RegisterDateTimeFunctions(sqlite3 *db){
|
||||
int i;
|
||||
|
||||
for(i=0; i<sizeof(aFuncs)/sizeof(aFuncs[0]); i++){
|
||||
sqlite3_create_function(db, aFuncs[i].zName, aFuncs[i].nArg,
|
||||
sqlite3CreateFunc(db, aFuncs[i].zName, aFuncs[i].nArg,
|
||||
SQLITE_UTF8, 0, aFuncs[i].xFunc, 0, 0);
|
||||
}
|
||||
#else
|
||||
@ -989,7 +991,7 @@ void sqlite3RegisterDateTimeFunctions(sqlite3 *db){
|
||||
int i;
|
||||
|
||||
for(i=0; i<sizeof(aFuncs)/sizeof(aFuncs[0]); i++){
|
||||
sqlite3_create_function(db, aFuncs[i].zName, 0, SQLITE_UTF8,
|
||||
sqlite3CreateFunc(db, aFuncs[i].zName, 0, SQLITE_UTF8,
|
||||
aFuncs[i].zFormat, currentTimeFunc, 0, 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -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.111 2005/09/20 17:42:23 drh Exp $
|
||||
** $Id: delete.c,v 1.120 2006/01/24 12:09:19 danielk1977 Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
|
||||
@ -59,14 +59,19 @@ int sqlite3IsReadOnly(Parse *pParse, Table *pTab, int viewOk){
|
||||
/*
|
||||
** Generate code that will open a table for reading.
|
||||
*/
|
||||
void sqlite3OpenTableForReading(
|
||||
Vdbe *v, /* Generate code into this VDBE */
|
||||
void sqlite3OpenTable(
|
||||
Parse *p, /* Generate code into this VDBE */
|
||||
int iCur, /* The cursor number of the table */
|
||||
Table *pTab /* The table to be opened */
|
||||
int iDb, /* The database index in sqlite3.aDb[] */
|
||||
Table *pTab, /* The table to be opened */
|
||||
int opcode /* OP_OpenRead or OP_OpenWrite */
|
||||
){
|
||||
sqlite3VdbeAddOp(v, OP_Integer, pTab->iDb, 0);
|
||||
Vdbe *v = sqlite3GetVdbe(p);
|
||||
assert( opcode==OP_OpenWrite || opcode==OP_OpenRead );
|
||||
sqlite3TableLock(p, iDb, pTab->tnum, (opcode==OP_OpenWrite), pTab->zName);
|
||||
sqlite3VdbeAddOp(v, OP_Integer, iDb, 0);
|
||||
VdbeComment((v, "# %s", pTab->zName));
|
||||
sqlite3VdbeAddOp(v, OP_OpenRead, iCur, pTab->tnum);
|
||||
sqlite3VdbeAddOp(v, opcode, iCur, pTab->tnum);
|
||||
sqlite3VdbeAddOp(v, OP_SetNumColumns, iCur, pTab->nCol);
|
||||
}
|
||||
|
||||
@ -95,6 +100,7 @@ void sqlite3DeleteFrom(
|
||||
AuthContext sContext; /* Authorization context */
|
||||
int oldIdx = -1; /* Cursor for the OLD table of AFTER triggers */
|
||||
NameContext sNC; /* Name context to resolve expressions in */
|
||||
int iDb;
|
||||
|
||||
#ifndef SQLITE_OMIT_TRIGGER
|
||||
int isView; /* True if attempting to delete from a view */
|
||||
@ -102,7 +108,7 @@ void sqlite3DeleteFrom(
|
||||
#endif
|
||||
|
||||
sContext.pParse = 0;
|
||||
if( pParse->nErr || sqlite3_malloc_failed ){
|
||||
if( pParse->nErr || sqlite3MallocFailed() ){
|
||||
goto delete_from_cleanup;
|
||||
}
|
||||
db = pParse->db;
|
||||
@ -134,8 +140,9 @@ void sqlite3DeleteFrom(
|
||||
if( sqlite3IsReadOnly(pParse, pTab, triggers_exist) ){
|
||||
goto delete_from_cleanup;
|
||||
}
|
||||
assert( pTab->iDb<db->nDb );
|
||||
zDb = db->aDb[pTab->iDb].zName;
|
||||
iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
|
||||
assert( iDb<db->nDb );
|
||||
zDb = db->aDb[iDb].zName;
|
||||
if( sqlite3AuthCheck(pParse, SQLITE_DELETE, pTab->zName, 0, zDb) ){
|
||||
goto delete_from_cleanup;
|
||||
}
|
||||
@ -176,7 +183,7 @@ void sqlite3DeleteFrom(
|
||||
goto delete_from_cleanup;
|
||||
}
|
||||
if( pParse->nested==0 ) sqlite3VdbeCountChanges(v);
|
||||
sqlite3BeginWriteOperation(pParse, triggers_exist, pTab->iDb);
|
||||
sqlite3BeginWriteOperation(pParse, triggers_exist, iDb);
|
||||
|
||||
/* If we are trying to delete from a view, realize that view into
|
||||
** a ephemeral table.
|
||||
@ -203,20 +210,24 @@ void sqlite3DeleteFrom(
|
||||
/* If counting rows deleted, just count the total number of
|
||||
** entries in the table. */
|
||||
int endOfLoop = sqlite3VdbeMakeLabel(v);
|
||||
int addr;
|
||||
int addr2;
|
||||
if( !isView ){
|
||||
sqlite3OpenTableForReading(v, iCur, pTab);
|
||||
sqlite3OpenTable(pParse, iCur, iDb, pTab, OP_OpenRead);
|
||||
}
|
||||
sqlite3VdbeAddOp(v, OP_Rewind, iCur, sqlite3VdbeCurrentAddr(v)+2);
|
||||
addr = sqlite3VdbeAddOp(v, OP_AddImm, 1, 0);
|
||||
sqlite3VdbeAddOp(v, OP_Next, iCur, addr);
|
||||
addr2 = sqlite3VdbeAddOp(v, OP_AddImm, 1, 0);
|
||||
sqlite3VdbeAddOp(v, OP_Next, iCur, addr2);
|
||||
sqlite3VdbeResolveLabel(v, endOfLoop);
|
||||
sqlite3VdbeAddOp(v, OP_Close, iCur, 0);
|
||||
}
|
||||
if( !isView ){
|
||||
sqlite3VdbeAddOp(v, OP_Clear, pTab->tnum, pTab->iDb);
|
||||
sqlite3VdbeAddOp(v, OP_Clear, pTab->tnum, iDb);
|
||||
if( !pParse->nested ){
|
||||
sqlite3VdbeChangeP3(v, -1, pTab->zName, P3_STATIC);
|
||||
}
|
||||
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
|
||||
sqlite3VdbeAddOp(v, OP_Clear, pIdx->tnum, pIdx->iDb);
|
||||
assert( pIdx->pSchema==pTab->pSchema );
|
||||
sqlite3VdbeAddOp(v, OP_Clear, pIdx->tnum, iDb);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -225,13 +236,6 @@ void sqlite3DeleteFrom(
|
||||
** the table and pick which records to delete.
|
||||
*/
|
||||
else{
|
||||
/* Ensure all required collation sequences are available. */
|
||||
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
|
||||
if( sqlite3CheckIndexCollSeq(pParse, pIdx) ){
|
||||
goto delete_from_cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
/* Begin the database scan
|
||||
*/
|
||||
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 0);
|
||||
@ -269,7 +273,7 @@ void sqlite3DeleteFrom(
|
||||
addr = sqlite3VdbeAddOp(v, OP_FifoRead, 0, end);
|
||||
if( !isView ){
|
||||
sqlite3VdbeAddOp(v, OP_Dup, 0, 0);
|
||||
sqlite3OpenTableForReading(v, iCur, pTab);
|
||||
sqlite3OpenTable(pParse, iCur, iDb, pTab, OP_OpenRead);
|
||||
}
|
||||
sqlite3VdbeAddOp(v, OP_MoveGe, iCur, 0);
|
||||
sqlite3VdbeAddOp(v, OP_Rowid, iCur, 0);
|
||||
@ -380,6 +384,9 @@ void sqlite3GenerateRowDelete(
|
||||
addr = sqlite3VdbeAddOp(v, OP_NotExists, iCur, 0);
|
||||
sqlite3GenerateRowIndexDelete(db, v, pTab, iCur, 0);
|
||||
sqlite3VdbeAddOp(v, OP_Delete, iCur, (count?OPFLAG_NCHANGE:0));
|
||||
if( count ){
|
||||
sqlite3VdbeChangeP3(v, -1, pTab->zName, P3_STATIC);
|
||||
}
|
||||
sqlite3VdbeJumpHere(v, addr);
|
||||
}
|
||||
|
||||
|
||||
@ -12,9 +12,10 @@
|
||||
** This file contains C code routines that are not a part of the official
|
||||
** SQLite API. These routines are unsupported.
|
||||
**
|
||||
** $Id: experimental.c,v 1.1 2005-06-10 01:27:31 vladimir%pobox.com Exp $
|
||||
** $Id: experimental.c,v 1.2 2006-02-08 21:10:10 vladimir%pobox.com Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include "os.h"
|
||||
|
||||
/*
|
||||
** Set all the parameters in the compiled SQL statement to NULL.
|
||||
|
||||
@ -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.230 2005/09/23 21:11:54 drh Exp $
|
||||
** $Id: expr.c,v 1.253 2006/01/30 14:36:59 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include <ctype.h>
|
||||
@ -75,12 +75,10 @@ CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr){
|
||||
char sqlite3CompareAffinity(Expr *pExpr, char aff2){
|
||||
char aff1 = sqlite3ExprAffinity(pExpr);
|
||||
if( aff1 && aff2 ){
|
||||
/* Both sides of the comparison are columns. If one has numeric or
|
||||
** integer affinity, use that. Otherwise use no affinity.
|
||||
/* Both sides of the comparison are columns. If one has numeric
|
||||
** affinity, use that. Otherwise use no affinity.
|
||||
*/
|
||||
if( aff1==SQLITE_AFF_INTEGER || aff2==SQLITE_AFF_INTEGER ){
|
||||
return SQLITE_AFF_INTEGER;
|
||||
}else if( aff1==SQLITE_AFF_NUMERIC || aff2==SQLITE_AFF_NUMERIC ){
|
||||
if( sqlite3IsNumericAffinity(aff1) || sqlite3IsNumericAffinity(aff2) ){
|
||||
return SQLITE_AFF_NUMERIC;
|
||||
}else{
|
||||
return SQLITE_AFF_NONE;
|
||||
@ -89,7 +87,6 @@ char sqlite3CompareAffinity(Expr *pExpr, char aff2){
|
||||
/* Neither side of the comparison is a column. Compare the
|
||||
** results directly.
|
||||
*/
|
||||
/* return SQLITE_AFF_NUMERIC; // Ticket #805 */
|
||||
return SQLITE_AFF_NONE;
|
||||
}else{
|
||||
/* One side is a column, the other is not. Use the columns affinity. */
|
||||
@ -129,11 +126,14 @@ static char comparisonAffinity(Expr *pExpr){
|
||||
*/
|
||||
int sqlite3IndexAffinityOk(Expr *pExpr, char idx_affinity){
|
||||
char aff = comparisonAffinity(pExpr);
|
||||
return
|
||||
(aff==SQLITE_AFF_NONE) ||
|
||||
(aff==SQLITE_AFF_NUMERIC && idx_affinity==SQLITE_AFF_INTEGER) ||
|
||||
(aff==SQLITE_AFF_INTEGER && idx_affinity==SQLITE_AFF_NUMERIC) ||
|
||||
(aff==idx_affinity);
|
||||
switch( aff ){
|
||||
case SQLITE_AFF_NONE:
|
||||
return 1;
|
||||
case SQLITE_AFF_TEXT:
|
||||
return idx_affinity==SQLITE_AFF_TEXT;
|
||||
default:
|
||||
return sqlite3IsNumericAffinity(idx_affinity);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@ -235,7 +235,7 @@ Expr *sqlite3RegisterExpr(Parse *pParse, Token *pToken){
|
||||
if( p==0 ){
|
||||
return 0; /* Malloc failed */
|
||||
}
|
||||
depth = atoi(&pToken->z[1]);
|
||||
depth = atoi((char*)&pToken->z[1]);
|
||||
p->iTable = pParse->nMem++;
|
||||
sqlite3VdbeAddOp(v, OP_Dup, depth, 0);
|
||||
sqlite3VdbeAddOp(v, OP_MemStore, p->iTable, 1);
|
||||
@ -263,7 +263,7 @@ Expr *sqlite3ExprAnd(Expr *pLeft, Expr *pRight){
|
||||
void sqlite3ExprSpan(Expr *pExpr, Token *pLeft, Token *pRight){
|
||||
assert( pRight!=0 );
|
||||
assert( pLeft!=0 );
|
||||
if( !sqlite3_malloc_failed && pRight->z && pLeft->z ){
|
||||
if( !sqlite3MallocFailed() && pRight->z && pLeft->z ){
|
||||
assert( pLeft->dyn==0 || pLeft->z[pLeft->n]==0 );
|
||||
if( pLeft->dyn==0 && pRight->dyn==0 ){
|
||||
pExpr->span.z = pLeft->z;
|
||||
@ -280,6 +280,7 @@ void sqlite3ExprSpan(Expr *pExpr, Token *pLeft, Token *pRight){
|
||||
*/
|
||||
Expr *sqlite3ExprFunction(ExprList *pList, Token *pToken){
|
||||
Expr *pNew;
|
||||
assert( pToken );
|
||||
pNew = sqliteMalloc( sizeof(Expr) );
|
||||
if( pNew==0 ){
|
||||
sqlite3ExprListDelete(pList); /* Avoid leaking memory when malloc fails */
|
||||
@ -287,12 +288,8 @@ Expr *sqlite3ExprFunction(ExprList *pList, Token *pToken){
|
||||
}
|
||||
pNew->op = TK_FUNCTION;
|
||||
pNew->pList = pList;
|
||||
if( pToken ){
|
||||
assert( pToken->dyn==0 );
|
||||
pNew->token = *pToken;
|
||||
}else{
|
||||
pNew->token.z = 0;
|
||||
}
|
||||
assert( pToken->dyn==0 );
|
||||
pNew->token = *pToken;
|
||||
pNew->span = pNew->token;
|
||||
return pNew;
|
||||
}
|
||||
@ -327,7 +324,7 @@ void sqlite3ExprAssignVarNumber(Parse *pParse, Expr *pExpr){
|
||||
/* Wildcard of the form "?nnn". Convert "nnn" to an integer and
|
||||
** use it as the variable number */
|
||||
int i;
|
||||
pExpr->iTable = i = atoi(&pToken->z[1]);
|
||||
pExpr->iTable = i = atoi((char*)&pToken->z[1]);
|
||||
if( i<1 || i>SQLITE_MAX_VARIABLE_NUMBER ){
|
||||
sqlite3ErrorMsg(pParse, "variable number must be between ?1 and ?%d",
|
||||
SQLITE_MAX_VARIABLE_NUMBER);
|
||||
@ -355,10 +352,10 @@ void sqlite3ExprAssignVarNumber(Parse *pParse, Expr *pExpr){
|
||||
pExpr->iTable = ++pParse->nVar;
|
||||
if( pParse->nVarExpr>=pParse->nVarExprAlloc-1 ){
|
||||
pParse->nVarExprAlloc += pParse->nVarExprAlloc + 10;
|
||||
sqlite3ReallocOrFree((void**)&pParse->apVarExpr,
|
||||
sqliteReallocOrFree((void**)&pParse->apVarExpr,
|
||||
pParse->nVarExprAlloc*sizeof(pParse->apVarExpr[0]) );
|
||||
}
|
||||
if( !sqlite3_malloc_failed ){
|
||||
if( !sqlite3MallocFailed() ){
|
||||
assert( pParse->apVarExpr!=0 );
|
||||
pParse->apVarExpr[pParse->nVarExpr++] = pExpr;
|
||||
}
|
||||
@ -415,7 +412,7 @@ Expr *sqlite3ExprDup(Expr *p){
|
||||
if( pNew==0 ) return 0;
|
||||
memcpy(pNew, p, sizeof(*pNew));
|
||||
if( p->token.z!=0 ){
|
||||
pNew->token.z = sqliteStrNDup(p->token.z, p->token.n);
|
||||
pNew->token.z = (u8*)sqliteStrNDup((char*)p->token.z, p->token.n);
|
||||
pNew->token.dyn = 1;
|
||||
}else{
|
||||
assert( pNew->token.z==0 );
|
||||
@ -432,7 +429,7 @@ void sqlite3TokenCopy(Token *pTo, Token *pFrom){
|
||||
if( pTo->dyn ) sqliteFree((char*)pTo->z);
|
||||
if( pFrom->z ){
|
||||
pTo->n = pFrom->n;
|
||||
pTo->z = sqliteStrNDup(pFrom->z, pFrom->n);
|
||||
pTo->z = (u8*)sqliteStrNDup((char*)pFrom->z, pFrom->n);
|
||||
pTo->dyn = 1;
|
||||
}else{
|
||||
pTo->z = 0;
|
||||
@ -462,7 +459,8 @@ ExprList *sqlite3ExprListDup(ExprList *p){
|
||||
sqlite3TokenCopy(&pNewExpr->span, &pOldExpr->span);
|
||||
}
|
||||
assert( pNewExpr==0 || pNewExpr->span.z!=0
|
||||
|| pOldExpr->span.z==0 || sqlite3_malloc_failed );
|
||||
|| pOldExpr->span.z==0
|
||||
|| sqlite3MallocFailed() );
|
||||
pItem->zName = sqliteStrDup(pOldItem->zName);
|
||||
pItem->sortOrder = pOldItem->sortOrder;
|
||||
pItem->isAgg = pOldItem->isAgg;
|
||||
@ -752,7 +750,7 @@ int sqlite3ExprIsConstantOrFunction(Expr *p){
|
||||
int sqlite3ExprIsInteger(Expr *p, int *pValue){
|
||||
switch( p->op ){
|
||||
case TK_INTEGER: {
|
||||
if( sqlite3GetInt32(p->token.z, pValue) ){
|
||||
if( sqlite3GetInt32((char*)p->token.z, pValue) ){
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
@ -809,7 +807,7 @@ int sqlite3IsRowid(const char *z){
|
||||
** in pParse and return non-zero. Return zero on success.
|
||||
*/
|
||||
static int lookupName(
|
||||
Parse *pParse, /* The parsing context */
|
||||
Parse *pParse, /* The parsing context */
|
||||
Token *pDbToken, /* Name of the database containing table, or NULL */
|
||||
Token *pTableToken, /* Name of table containing column, or NULL */
|
||||
Token *pColumnToken, /* Name of the column. */
|
||||
@ -831,19 +829,19 @@ static int lookupName(
|
||||
zDb = sqlite3NameFromToken(pDbToken);
|
||||
zTab = sqlite3NameFromToken(pTableToken);
|
||||
zCol = sqlite3NameFromToken(pColumnToken);
|
||||
if( sqlite3_malloc_failed ){
|
||||
if( sqlite3MallocFailed() ){
|
||||
goto lookupname_end;
|
||||
}
|
||||
|
||||
pExpr->iTable = -1;
|
||||
while( pNC && cnt==0 ){
|
||||
ExprList *pEList;
|
||||
SrcList *pSrcList = pNC->pSrcList;
|
||||
ExprList *pEList = pNC->pEList;
|
||||
|
||||
/* assert( zTab==0 || pEList==0 ); */
|
||||
if( pSrcList ){
|
||||
for(i=0, pItem=pSrcList->a; i<pSrcList->nSrc; i++, pItem++){
|
||||
Table *pTab = pItem->pTab;
|
||||
int iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
|
||||
Column *pCol;
|
||||
|
||||
if( pTab==0 ) continue;
|
||||
@ -855,27 +853,28 @@ static int lookupName(
|
||||
}else{
|
||||
char *zTabName = pTab->zName;
|
||||
if( zTabName==0 || sqlite3StrICmp(zTabName, zTab)!=0 ) continue;
|
||||
if( zDb!=0 && sqlite3StrICmp(db->aDb[pTab->iDb].zName, zDb)!=0 ){
|
||||
if( zDb!=0 && sqlite3StrICmp(db->aDb[iDb].zName, zDb)!=0 ){
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
if( 0==(cntTab++) ){
|
||||
pExpr->iTable = pItem->iCursor;
|
||||
pExpr->iDb = pTab->iDb;
|
||||
pExpr->pSchema = pTab->pSchema;
|
||||
pMatch = pItem;
|
||||
}
|
||||
for(j=0, pCol=pTab->aCol; j<pTab->nCol; j++, pCol++){
|
||||
if( sqlite3StrICmp(pCol->zName, zCol)==0 ){
|
||||
const char *zColl = pTab->aCol[j].zColl;
|
||||
IdList *pUsing;
|
||||
cnt++;
|
||||
pExpr->iTable = pItem->iCursor;
|
||||
pMatch = pItem;
|
||||
pExpr->iDb = pTab->iDb;
|
||||
pExpr->pSchema = pTab->pSchema;
|
||||
/* Substitute the rowid (column -1) for the INTEGER PRIMARY KEY */
|
||||
pExpr->iColumn = j==pTab->iPKey ? -1 : j;
|
||||
pExpr->affinity = pTab->aCol[j].affinity;
|
||||
pExpr->pColl = pTab->aCol[j].pColl;
|
||||
pExpr->pColl = sqlite3FindCollSeq(db, ENC(db), zColl,-1, 0);
|
||||
if( pItem->jointype & JT_NATURAL ){
|
||||
/* If this match occurred in the left table of a natural join,
|
||||
** then skip the right table to avoid a duplicate match */
|
||||
@ -919,17 +918,18 @@ static int lookupName(
|
||||
}
|
||||
|
||||
if( pTab ){
|
||||
int j;
|
||||
int iCol;
|
||||
Column *pCol = pTab->aCol;
|
||||
|
||||
pExpr->iDb = pTab->iDb;
|
||||
pExpr->pSchema = pTab->pSchema;
|
||||
cntTab++;
|
||||
for(j=0; j < pTab->nCol; j++, pCol++) {
|
||||
for(iCol=0; iCol < pTab->nCol; iCol++, pCol++) {
|
||||
if( sqlite3StrICmp(pCol->zName, zCol)==0 ){
|
||||
const char *zColl = pTab->aCol[iCol].zColl;
|
||||
cnt++;
|
||||
pExpr->iColumn = j==pTab->iPKey ? -1 : j;
|
||||
pExpr->affinity = pTab->aCol[j].affinity;
|
||||
pExpr->pColl = pTab->aCol[j].pColl;
|
||||
pExpr->iColumn = iCol==pTab->iPKey ? -1 : iCol;
|
||||
pExpr->affinity = pTab->aCol[iCol].affinity;
|
||||
pExpr->pColl = sqlite3FindCollSeq(db, ENC(db), zColl,-1, 0);
|
||||
pExpr->pTab = pTab;
|
||||
break;
|
||||
}
|
||||
@ -959,7 +959,7 @@ static int lookupName(
|
||||
** Note that the expression in the result set should have already been
|
||||
** resolved by the time the WHERE clause is resolved.
|
||||
*/
|
||||
if( cnt==0 && pEList!=0 && zTab==0 ){
|
||||
if( cnt==0 && (pEList = pNC->pEList)!=0 && zTab==0 ){
|
||||
for(j=0; j<pEList->nExpr; j++){
|
||||
char *zAs = pEList->a[j].zName;
|
||||
if( zAs!=0 && sqlite3StrICmp(zAs, zCol)==0 ){
|
||||
@ -1006,9 +1006,9 @@ static int lookupName(
|
||||
char *zErr;
|
||||
zErr = cnt==0 ? "no such column: %s" : "ambiguous column name: %s";
|
||||
if( zDb ){
|
||||
sqlite3SetString(&z, zDb, ".", zTab, ".", zCol, 0);
|
||||
sqlite3SetString(&z, zDb, ".", zTab, ".", zCol, (char*)0);
|
||||
}else if( zTab ){
|
||||
sqlite3SetString(&z, zTab, ".", zCol, 0);
|
||||
sqlite3SetString(&z, zTab, ".", zCol, (char*)0);
|
||||
}else{
|
||||
z = sqliteStrDup(zCol);
|
||||
}
|
||||
@ -1077,20 +1077,19 @@ lookupname_end_2:
|
||||
*/
|
||||
static int nameResolverStep(void *pArg, Expr *pExpr){
|
||||
NameContext *pNC = (NameContext*)pArg;
|
||||
SrcList *pSrcList;
|
||||
Parse *pParse;
|
||||
|
||||
if( pExpr==0 ) return 1;
|
||||
assert( pNC!=0 );
|
||||
pSrcList = pNC->pSrcList;
|
||||
pParse = pNC->pParse;
|
||||
|
||||
if( ExprHasAnyProperty(pExpr, EP_Resolved) ) return 1;
|
||||
ExprSetProperty(pExpr, EP_Resolved);
|
||||
#ifndef NDEBUG
|
||||
if( pSrcList ){
|
||||
if( pNC->pSrcList && pNC->pSrcList->nAlloc>0 ){
|
||||
SrcList *pSrcList = pNC->pSrcList;
|
||||
int i;
|
||||
for(i=0; i<pSrcList->nSrc; i++){
|
||||
for(i=0; i<pNC->pSrcList->nSrc; i++){
|
||||
assert( pSrcList->a[i].iCursor>=0 && pSrcList->a[i].iCursor<pParse->nTab);
|
||||
}
|
||||
}
|
||||
@ -1149,9 +1148,9 @@ static int nameResolverStep(void *pArg, Expr *pExpr){
|
||||
int nId; /* Number of characters in function name */
|
||||
const char *zId; /* The function name. */
|
||||
FuncDef *pDef; /* Information about the function */
|
||||
int enc = pParse->db->enc; /* The database encoding */
|
||||
int enc = ENC(pParse->db); /* The database encoding */
|
||||
|
||||
zId = pExpr->token.z;
|
||||
zId = (char*)pExpr->token.z;
|
||||
nId = pExpr->token.n;
|
||||
pDef = sqlite3FindFunction(pParse->db, zId, nId, n, enc, 0);
|
||||
if( pDef==0 ){
|
||||
@ -1197,13 +1196,27 @@ static int nameResolverStep(void *pArg, Expr *pExpr){
|
||||
case TK_IN: {
|
||||
if( pExpr->pSelect ){
|
||||
int nRef = pNC->nRef;
|
||||
#ifndef SQLITE_OMIT_CHECK
|
||||
if( pNC->isCheck ){
|
||||
sqlite3ErrorMsg(pParse,"subqueries prohibited in CHECK constraints");
|
||||
}
|
||||
#endif
|
||||
sqlite3SelectResolve(pParse, pExpr->pSelect, pNC);
|
||||
assert( pNC->nRef>=nRef );
|
||||
if( nRef!=pNC->nRef ){
|
||||
ExprSetProperty(pExpr, EP_VarSelect);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
#ifndef SQLITE_OMIT_CHECK
|
||||
case TK_VARIABLE: {
|
||||
if( pNC->isCheck ){
|
||||
sqlite3ErrorMsg(pParse,"parameters prohibited in CHECK constraints");
|
||||
}
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -1261,17 +1274,16 @@ struct QueryCoder {
|
||||
|
||||
|
||||
/*
|
||||
** Generate code for subqueries and IN operators.
|
||||
** Generate code for scalar subqueries used as an expression
|
||||
** and IN operators. Examples:
|
||||
**
|
||||
** IN operators comes in two forms:
|
||||
** (SELECT a FROM b) -- subquery
|
||||
** EXISTS (SELECT a FROM b) -- EXISTS subquery
|
||||
** x IN (4,5,11) -- IN operator with list on right-hand side
|
||||
** x IN (SELECT a FROM b) -- IN operator with subquery on the right
|
||||
**
|
||||
** expr IN (exprlist)
|
||||
** and
|
||||
** expr IN (SELECT ...)
|
||||
**
|
||||
** The first form is handled by creating a set holding the list
|
||||
** of allowed values. The second form causes the SELECT to generate
|
||||
** a temporary table.
|
||||
** The pExpr parameter describes the expression that contains the IN
|
||||
** operator or subquery.
|
||||
*/
|
||||
#ifndef SQLITE_OMIT_SUBQUERY
|
||||
void sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){
|
||||
@ -1293,7 +1305,7 @@ void sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){
|
||||
int mem = pParse->nMem++;
|
||||
sqlite3VdbeAddOp(v, OP_MemLoad, mem, 0);
|
||||
testAddr = sqlite3VdbeAddOp(v, OP_If, 0, 0);
|
||||
assert( testAddr>0 || sqlite3_malloc_failed );
|
||||
assert( testAddr>0 || sqlite3MallocFailed() );
|
||||
sqlite3VdbeAddOp(v, OP_MemInt, 1, mem);
|
||||
}
|
||||
|
||||
@ -1367,9 +1379,9 @@ void sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){
|
||||
*/
|
||||
if( testAddr>0 && !sqlite3ExprIsConstant(pE2) ){
|
||||
VdbeOp *aOp = sqlite3VdbeGetOp(v, testAddr-1);
|
||||
int i;
|
||||
for(i=0; i<3; i++){
|
||||
aOp[i].opcode = OP_Noop;
|
||||
int j;
|
||||
for(j=0; j<3; j++){
|
||||
aOp[j].opcode = OP_Noop;
|
||||
}
|
||||
testAddr = 0;
|
||||
}
|
||||
@ -1390,21 +1402,25 @@ void sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){
|
||||
** value of this select in a memory cell and record the number
|
||||
** of the memory cell in iColumn.
|
||||
*/
|
||||
int sop;
|
||||
static const Token one = { (u8*)"1", 0, 1 };
|
||||
Select *pSel;
|
||||
int iMem;
|
||||
int sop;
|
||||
|
||||
pExpr->iColumn = pParse->nMem++;
|
||||
pExpr->iColumn = iMem = pParse->nMem++;
|
||||
pSel = pExpr->pSelect;
|
||||
if( pExpr->op==TK_SELECT ){
|
||||
sop = SRT_Mem;
|
||||
sqlite3VdbeAddOp(v, OP_MemNull, iMem, 0);
|
||||
VdbeComment((v, "# Init subquery result"));
|
||||
}else{
|
||||
static const Token one = { "1", 0, 1 };
|
||||
sop = SRT_Exists;
|
||||
sqlite3ExprListDelete(pSel->pEList);
|
||||
pSel->pEList = sqlite3ExprListAppend(0,
|
||||
sqlite3Expr(TK_INTEGER, 0, 0, &one), 0);
|
||||
sqlite3VdbeAddOp(v, OP_MemInt, 0, iMem);
|
||||
VdbeComment((v, "# Init EXISTS result"));
|
||||
}
|
||||
sqlite3Select(pParse, pSel, sop, pExpr->iColumn, 0, 0, 0, 0);
|
||||
sqlite3ExprDelete(pSel->pLimit);
|
||||
pSel->pLimit = sqlite3Expr(TK_INTEGER, 0, 0, &one);
|
||||
sqlite3Select(pParse, pSel, sop, iMem, 0, 0, 0, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -1444,6 +1460,8 @@ static void codeInteger(Vdbe *v, const char *z, int n){
|
||||
void sqlite3ExprCode(Parse *pParse, Expr *pExpr){
|
||||
Vdbe *v = pParse->pVdbe;
|
||||
int op;
|
||||
int stackChng = 1; /* Amount of change to stack depth */
|
||||
|
||||
if( v==0 ) return;
|
||||
if( pExpr==0 ){
|
||||
sqlite3VdbeAddOp(v, OP_Null, 0, 0);
|
||||
@ -1465,16 +1483,27 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){
|
||||
/* Otherwise, fall thru into the TK_COLUMN case */
|
||||
}
|
||||
case TK_COLUMN: {
|
||||
if( pExpr->iColumn>=0 ){
|
||||
sqlite3VdbeAddOp(v, OP_Column, pExpr->iTable, pExpr->iColumn);
|
||||
sqlite3ColumnDefault(v, pExpr->pTab, pExpr->iColumn);
|
||||
if( pExpr->iTable<0 ){
|
||||
/* This only happens when coding check constraints */
|
||||
assert( pParse->ckOffset>0 );
|
||||
sqlite3VdbeAddOp(v, OP_Dup, pParse->ckOffset-pExpr->iColumn-1, 1);
|
||||
}else if( pExpr->iColumn>=0 ){
|
||||
Table *pTab = pExpr->pTab;
|
||||
int iCol = pExpr->iColumn;
|
||||
sqlite3VdbeAddOp(v, OP_Column, pExpr->iTable, iCol);
|
||||
sqlite3ColumnDefault(v, pTab, iCol);
|
||||
#ifndef SQLITE_OMIT_FLOATING_POINT
|
||||
if( pTab && pTab->aCol[iCol].affinity==SQLITE_AFF_REAL ){
|
||||
sqlite3VdbeAddOp(v, OP_RealAffinity, 0, 0);
|
||||
}
|
||||
#endif
|
||||
}else{
|
||||
sqlite3VdbeAddOp(v, OP_Rowid, pExpr->iTable, 0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TK_INTEGER: {
|
||||
codeInteger(v, pExpr->token.z, pExpr->token.n);
|
||||
codeInteger(v, (char*)pExpr->token.z, pExpr->token.n);
|
||||
break;
|
||||
}
|
||||
case TK_FLOAT:
|
||||
@ -1482,7 +1511,7 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){
|
||||
assert( TK_FLOAT==OP_Real );
|
||||
assert( TK_STRING==OP_String8 );
|
||||
sqlite3DequoteExpr(pExpr);
|
||||
sqlite3VdbeOp3(v, op, 0, 0, pExpr->token.z, pExpr->token.n);
|
||||
sqlite3VdbeOp3(v, op, 0, 0, (char*)pExpr->token.z, pExpr->token.n);
|
||||
break;
|
||||
}
|
||||
case TK_NULL: {
|
||||
@ -1495,7 +1524,7 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){
|
||||
const char *z;
|
||||
assert( TK_BLOB==OP_HexBlob );
|
||||
n = pExpr->token.n - 3;
|
||||
z = pExpr->token.z + 2;
|
||||
z = (char*)pExpr->token.z + 2;
|
||||
assert( n>=0 );
|
||||
if( n==0 ){
|
||||
z = "";
|
||||
@ -1507,7 +1536,7 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){
|
||||
case TK_VARIABLE: {
|
||||
sqlite3VdbeAddOp(v, OP_Variable, pExpr->iTable, 0);
|
||||
if( pExpr->token.n>1 ){
|
||||
sqlite3VdbeChangeP3(v, -1, pExpr->token.z, pExpr->token.n);
|
||||
sqlite3VdbeChangeP3(v, -1, (char*)pExpr->token.z, pExpr->token.n);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -1518,16 +1547,17 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){
|
||||
#ifndef SQLITE_OMIT_CAST
|
||||
case TK_CAST: {
|
||||
/* Expressions of the form: CAST(pLeft AS token) */
|
||||
int aff, op;
|
||||
int aff, to_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);
|
||||
to_op = aff - SQLITE_AFF_TEXT + OP_ToText;
|
||||
assert( to_op==OP_ToText || aff!=SQLITE_AFF_TEXT );
|
||||
assert( to_op==OP_ToBlob || aff!=SQLITE_AFF_NONE );
|
||||
assert( to_op==OP_ToNumeric || aff!=SQLITE_AFF_NUMERIC );
|
||||
assert( to_op==OP_ToInt || aff!=SQLITE_AFF_INTEGER );
|
||||
assert( to_op==OP_ToReal || aff!=SQLITE_AFF_REAL );
|
||||
sqlite3VdbeAddOp(v, to_op, 0, 0);
|
||||
stackChng = 0;
|
||||
break;
|
||||
}
|
||||
#endif /* SQLITE_OMIT_CAST */
|
||||
@ -1546,6 +1576,7 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){
|
||||
sqlite3ExprCode(pParse, pExpr->pLeft);
|
||||
sqlite3ExprCode(pParse, pExpr->pRight);
|
||||
codeCompare(pParse, pExpr->pLeft, pExpr->pRight, op, 0, 0);
|
||||
stackChng = -1;
|
||||
break;
|
||||
}
|
||||
case TK_AND:
|
||||
@ -1574,6 +1605,7 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){
|
||||
sqlite3ExprCode(pParse, pExpr->pLeft);
|
||||
sqlite3ExprCode(pParse, pExpr->pRight);
|
||||
sqlite3VdbeAddOp(v, op, 0, 0);
|
||||
stackChng = -1;
|
||||
break;
|
||||
}
|
||||
case TK_UMINUS: {
|
||||
@ -1581,8 +1613,7 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){
|
||||
assert( pLeft );
|
||||
if( pLeft->op==TK_FLOAT || pLeft->op==TK_INTEGER ){
|
||||
Token *p = &pLeft->token;
|
||||
char *z = sqliteMalloc( p->n + 2 );
|
||||
sprintf(z, "-%.*s", p->n, p->z);
|
||||
char *z = sqlite3MPrintf("-%.*s", p->n, p->z);
|
||||
if( pLeft->op==TK_FLOAT ){
|
||||
sqlite3VdbeOp3(v, OP_Real, 0, 0, z, p->n+1);
|
||||
}else{
|
||||
@ -1599,6 +1630,7 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){
|
||||
assert( TK_NOT==OP_Not );
|
||||
sqlite3ExprCode(pParse, pExpr->pLeft);
|
||||
sqlite3VdbeAddOp(v, op, 0, 0);
|
||||
stackChng = 0;
|
||||
break;
|
||||
}
|
||||
case TK_ISNULL:
|
||||
@ -1611,11 +1643,17 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){
|
||||
dest = sqlite3VdbeCurrentAddr(v) + 2;
|
||||
sqlite3VdbeAddOp(v, op, 1, dest);
|
||||
sqlite3VdbeAddOp(v, OP_AddImm, -1, 0);
|
||||
stackChng = 0;
|
||||
break;
|
||||
}
|
||||
case TK_AGG_FUNCTION: {
|
||||
AggInfo *pInfo = pExpr->pAggInfo;
|
||||
sqlite3VdbeAddOp(v, OP_MemLoad, pInfo->aFunc[pExpr->iAgg].iMem, 0);
|
||||
if( pInfo==0 ){
|
||||
sqlite3ErrorMsg(pParse, "misuse of aggregate: %T",
|
||||
&pExpr->span);
|
||||
}else{
|
||||
sqlite3VdbeAddOp(v, OP_MemLoad, pInfo->aFunc[pExpr->iAgg].iMem, 0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TK_CONST_FUNC:
|
||||
@ -1627,9 +1665,9 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){
|
||||
const char *zId;
|
||||
int constMask = 0;
|
||||
int i;
|
||||
u8 enc = pParse->db->enc;
|
||||
u8 enc = ENC(pParse->db);
|
||||
CollSeq *pColl = 0;
|
||||
zId = pExpr->token.z;
|
||||
zId = (char*)pExpr->token.z;
|
||||
nId = pExpr->token.n;
|
||||
pDef = sqlite3FindFunction(pParse->db, zId, nId, nExpr, enc, 0);
|
||||
assert( pDef!=0 );
|
||||
@ -1647,6 +1685,7 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){
|
||||
sqlite3VdbeOp3(v, OP_CollSeq, 0, 0, (char *)pColl, P3_COLLSEQ);
|
||||
}
|
||||
sqlite3VdbeOp3(v, OP_Function, constMask, nExpr, (char*)pDef, P3_FUNCDEF);
|
||||
stackChng = 1-nExpr;
|
||||
break;
|
||||
}
|
||||
#ifndef SQLITE_OMIT_SUBQUERY
|
||||
@ -1660,6 +1699,7 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){
|
||||
case TK_IN: {
|
||||
int addr;
|
||||
char affinity;
|
||||
int ckOffset = pParse->ckOffset;
|
||||
sqlite3CodeSubselect(pParse, pExpr);
|
||||
|
||||
/* Figure out the affinity to use to create a key from the results
|
||||
@ -1669,6 +1709,7 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){
|
||||
affinity = comparisonAffinity(pExpr);
|
||||
|
||||
sqlite3VdbeAddOp(v, OP_Integer, 1, 0);
|
||||
pParse->ckOffset = ckOffset+1;
|
||||
|
||||
/* Code the <expr> from "<expr> IN (...)". The temporary table
|
||||
** pExpr->iTable contains the values that make up the (...) set.
|
||||
@ -1705,6 +1746,7 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){
|
||||
case TK_UPLUS:
|
||||
case TK_AS: {
|
||||
sqlite3ExprCode(pParse, pExpr->pLeft);
|
||||
stackChng = 0;
|
||||
break;
|
||||
}
|
||||
case TK_CASE: {
|
||||
@ -1763,16 +1805,22 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){
|
||||
pExpr->iColumn == OE_Fail );
|
||||
sqlite3DequoteExpr(pExpr);
|
||||
sqlite3VdbeOp3(v, OP_Halt, SQLITE_CONSTRAINT, pExpr->iColumn,
|
||||
pExpr->token.z, pExpr->token.n);
|
||||
(char*)pExpr->token.z, pExpr->token.n);
|
||||
} else {
|
||||
assert( pExpr->iColumn == OE_Ignore );
|
||||
sqlite3VdbeAddOp(v, OP_ContextPop, 0, 0);
|
||||
sqlite3VdbeAddOp(v, OP_Goto, 0, pParse->trigStack->ignoreJump);
|
||||
VdbeComment((v, "# raise(IGNORE)"));
|
||||
}
|
||||
stackChng = 0;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
if( pParse->ckOffset ){
|
||||
pParse->ckOffset += stackChng;
|
||||
assert( pParse->ckOffset );
|
||||
}
|
||||
}
|
||||
|
||||
@ -1840,6 +1888,7 @@ int sqlite3ExprCodeExprList(
|
||||
void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
|
||||
Vdbe *v = pParse->pVdbe;
|
||||
int op = 0;
|
||||
int ckOffset = pParse->ckOffset;
|
||||
if( v==0 || pExpr==0 ) return;
|
||||
op = pExpr->op;
|
||||
switch( op ){
|
||||
@ -1914,6 +1963,7 @@ void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
|
||||
break;
|
||||
}
|
||||
}
|
||||
pParse->ckOffset = ckOffset;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1927,6 +1977,7 @@ void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
|
||||
void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
|
||||
Vdbe *v = pParse->pVdbe;
|
||||
int op = 0;
|
||||
int ckOffset = pParse->ckOffset;
|
||||
if( v==0 || pExpr==0 ) return;
|
||||
|
||||
/* The value of pExpr->op and op are related as follows:
|
||||
@ -2023,6 +2074,7 @@ void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
|
||||
break;
|
||||
}
|
||||
}
|
||||
pParse->ckOffset = ckOffset;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -2031,10 +2083,8 @@ void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
|
||||
*/
|
||||
int sqlite3ExprCompare(Expr *pA, Expr *pB){
|
||||
int i;
|
||||
if( pA==0 ){
|
||||
return pB==0;
|
||||
}else if( pB==0 ){
|
||||
return 0;
|
||||
if( pA==0||pB==0 ){
|
||||
return pB==pA;
|
||||
}
|
||||
if( pA->op!=pB->op ) return 0;
|
||||
if( (pA->flags & EP_Distinct)!=(pB->flags & EP_Distinct) ) return 0;
|
||||
@ -2056,7 +2106,9 @@ int sqlite3ExprCompare(Expr *pA, Expr *pB){
|
||||
if( pA->token.z ){
|
||||
if( pB->token.z==0 ) return 0;
|
||||
if( pB->token.n!=pA->token.n ) return 0;
|
||||
if( sqlite3StrNICmp(pA->token.z, pB->token.z, pB->token.n)!=0 ) return 0;
|
||||
if( sqlite3StrNICmp((char*)pA->token.z,(char*)pB->token.z,pB->token.n)!=0 ){
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
@ -2180,14 +2232,14 @@ static int analyzeAggregate(void *pArg, Expr *pExpr){
|
||||
if( i>=pAggInfo->nFunc ){
|
||||
/* pExpr is original. Make a new entry in pAggInfo->aFunc[]
|
||||
*/
|
||||
u8 enc = pParse->db->enc;
|
||||
u8 enc = ENC(pParse->db);
|
||||
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,
|
||||
(char*)pExpr->token.z, pExpr->token.n,
|
||||
pExpr->pList ? pExpr->pList->nExpr : 0, enc, 0);
|
||||
if( pExpr->flags & EP_Distinct ){
|
||||
pItem->iDistinct = pParse->nTab++;
|
||||
|
||||
@ -16,11 +16,11 @@
|
||||
** sqliteRegisterBuildinFunctions() found at the bottom of the file.
|
||||
** All other code has file scope.
|
||||
**
|
||||
** $Id: func.c,v 1.110 2005/09/08 20:37:43 drh Exp $
|
||||
** $Id: func.c,v 1.117 2006/01/17 13:21:40 danielk1977 Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include <ctype.h>
|
||||
#include <math.h>
|
||||
/* #include <math.h> */
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include "vdbeInt.h"
|
||||
@ -101,7 +101,7 @@ static void lengthFunc(
|
||||
break;
|
||||
}
|
||||
case SQLITE_TEXT: {
|
||||
const char *z = sqlite3_value_text(argv[0]);
|
||||
const unsigned char *z = sqlite3_value_text(argv[0]);
|
||||
for(len=0; *z; z++){ if( (0xc0&*z)!=0x80 ) len++; }
|
||||
sqlite3_result_int(context, len);
|
||||
break;
|
||||
@ -146,8 +146,8 @@ static void substrFunc(
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
const char *z;
|
||||
const char *z2;
|
||||
const unsigned char *z;
|
||||
const unsigned char *z2;
|
||||
int i;
|
||||
int p1, p2, len;
|
||||
|
||||
@ -178,7 +178,7 @@ static void substrFunc(
|
||||
}
|
||||
while( z[i] && (z[i]&0xc0)==0x80 ){ i++; p2++; }
|
||||
if( p2<0 ) p2 = 0;
|
||||
sqlite3_result_text(context, &z[p1], p2, SQLITE_TRANSIENT);
|
||||
sqlite3_result_text(context, (char*)&z[p1], p2, SQLITE_TRANSIENT);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -210,11 +210,11 @@ static void upperFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
|
||||
if( argc<1 || SQLITE_NULL==sqlite3_value_type(argv[0]) ) return;
|
||||
z = sqliteMalloc(sqlite3_value_bytes(argv[0])+1);
|
||||
if( z==0 ) return;
|
||||
strcpy(z, sqlite3_value_text(argv[0]));
|
||||
strcpy((char*)z, (char*)sqlite3_value_text(argv[0]));
|
||||
for(i=0; z[i]; i++){
|
||||
z[i] = toupper(z[i]);
|
||||
}
|
||||
sqlite3_result_text(context, z, -1, SQLITE_TRANSIENT);
|
||||
sqlite3_result_text(context, (char*)z, -1, SQLITE_TRANSIENT);
|
||||
sqliteFree(z);
|
||||
}
|
||||
static void lowerFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
|
||||
@ -223,11 +223,11 @@ static void lowerFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
|
||||
if( argc<1 || SQLITE_NULL==sqlite3_value_type(argv[0]) ) return;
|
||||
z = sqliteMalloc(sqlite3_value_bytes(argv[0])+1);
|
||||
if( z==0 ) return;
|
||||
strcpy(z, sqlite3_value_text(argv[0]));
|
||||
strcpy((char*)z, (char*)sqlite3_value_text(argv[0]));
|
||||
for(i=0; z[i]; i++){
|
||||
z[i] = tolower(z[i]);
|
||||
}
|
||||
sqlite3_result_text(context, z, -1, SQLITE_TRANSIENT);
|
||||
sqlite3_result_text(context, (char*)z, -1, SQLITE_TRANSIENT);
|
||||
sqliteFree(z);
|
||||
}
|
||||
|
||||
@ -495,7 +495,7 @@ static void likeFunc(
|
||||
** Otherwise, return an error.
|
||||
*/
|
||||
const unsigned char *zEsc = sqlite3_value_text(argv[2]);
|
||||
if( sqlite3utf8CharLen(zEsc, -1)!=1 ){
|
||||
if( sqlite3utf8CharLen((char*)zEsc, -1)!=1 ){
|
||||
sqlite3_result_error(context,
|
||||
"ESCAPE expression must be a single character", -1);
|
||||
return;
|
||||
@ -592,7 +592,7 @@ static void quoteFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
|
||||
}
|
||||
case SQLITE_TEXT: {
|
||||
int i,j,n;
|
||||
const char *zArg = sqlite3_value_text(argv[0]);
|
||||
const unsigned char *zArg = sqlite3_value_text(argv[0]);
|
||||
char *z;
|
||||
|
||||
for(i=n=0; zArg[i]; i++){ if( zArg[i]=='\'' ) n++; }
|
||||
@ -692,7 +692,7 @@ static void randStr(sqlite3_context *context, int argc, sqlite3_value **argv){
|
||||
zBuf[i] = zSrc[zBuf[i]%(sizeof(zSrc)-1)];
|
||||
}
|
||||
zBuf[n] = 0;
|
||||
sqlite3_result_text(context, zBuf, n, SQLITE_TRANSIENT);
|
||||
sqlite3_result_text(context, (char*)zBuf, n, SQLITE_TRANSIENT);
|
||||
}
|
||||
#endif /* SQLITE_TEST */
|
||||
|
||||
@ -728,17 +728,17 @@ static void test_destructor(
|
||||
test_destructor_count_var++;
|
||||
assert( nArg==1 );
|
||||
if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return;
|
||||
len = sqlite3ValueBytes(argv[0], db->enc);
|
||||
len = sqlite3ValueBytes(argv[0], ENC(db));
|
||||
zVal = sqliteMalloc(len+3);
|
||||
zVal[len] = 0;
|
||||
zVal[len-1] = 0;
|
||||
assert( zVal );
|
||||
zVal++;
|
||||
memcpy(zVal, sqlite3ValueText(argv[0], db->enc), len);
|
||||
if( db->enc==SQLITE_UTF8 ){
|
||||
memcpy(zVal, sqlite3ValueText(argv[0], ENC(db)), len);
|
||||
if( ENC(db)==SQLITE_UTF8 ){
|
||||
sqlite3_result_text(pCtx, zVal, -1, destructor);
|
||||
#ifndef SQLITE_OMIT_UTF16
|
||||
}else if( db->enc==SQLITE_UTF16LE ){
|
||||
}else if( ENC(db)==SQLITE_UTF16LE ){
|
||||
sqlite3_result_text16le(pCtx, zVal, -1, destructor);
|
||||
}else{
|
||||
sqlite3_result_text16be(pCtx, zVal, -1, destructor);
|
||||
@ -776,7 +776,7 @@ static void test_auxdata(
|
||||
char *zRet = sqliteMalloc(nArg*2);
|
||||
if( !zRet ) return;
|
||||
for(i=0; i<nArg; i++){
|
||||
char const *z = sqlite3_value_text(argv[i]);
|
||||
char const *z = (char*)sqlite3_value_text(argv[i]);
|
||||
if( z ){
|
||||
char *zAux = sqlite3_get_auxdata(pCtx, i);
|
||||
if( zAux ){
|
||||
@ -807,7 +807,7 @@ static void test_error(
|
||||
int nArg,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
sqlite3_result_error(pCtx, sqlite3_value_text(argv[0]), 0);
|
||||
sqlite3_result_error(pCtx, (char*)sqlite3_value_text(argv[0]), 0);
|
||||
}
|
||||
#endif /* SQLITE_TEST */
|
||||
|
||||
@ -823,7 +823,13 @@ struct SumCtx {
|
||||
};
|
||||
|
||||
/*
|
||||
** Routines used to compute the sum or average.
|
||||
** Routines used to compute the sum, average, and total.
|
||||
**
|
||||
** The SUM() function follows the (broken) SQL standard which means
|
||||
** that it returns NULL if it sums over no inputs. TOTAL returns
|
||||
** 0.0 in that case. In addition, TOTAL always returns a float where
|
||||
** SUM might return an integer if it never encounters a floating point
|
||||
** value.
|
||||
*/
|
||||
static void sumStep(sqlite3_context *context, int argc, sqlite3_value **argv){
|
||||
SumCtx *p;
|
||||
@ -857,6 +863,11 @@ static void avgFinalize(sqlite3_context *context){
|
||||
sqlite3_result_double(context, p->sum/(double)p->cnt);
|
||||
}
|
||||
}
|
||||
static void totalFinalize(sqlite3_context *context){
|
||||
SumCtx *p;
|
||||
p = sqlite3_aggregate_context(context, 0);
|
||||
sqlite3_result_double(context, p ? p->sum : 0.0);
|
||||
}
|
||||
|
||||
/*
|
||||
** An instance of the following structure holds the context of a
|
||||
@ -1000,6 +1011,7 @@ void sqlite3RegisterBuiltinFunctions(sqlite3 *db){
|
||||
{ "min", 1, 0, 1, minmaxStep, minMaxFinalize },
|
||||
{ "max", 1, 2, 1, minmaxStep, minMaxFinalize },
|
||||
{ "sum", 1, 0, 0, sumStep, sumFinalize },
|
||||
{ "total", 1, 0, 0, sumStep, totalFinalize },
|
||||
{ "avg", 1, 0, 0, sumStep, avgFinalize },
|
||||
{ "count", 0, 0, 0, countStep, countFinalize },
|
||||
{ "count", 1, 0, 0, countStep, countFinalize },
|
||||
@ -1012,7 +1024,7 @@ void sqlite3RegisterBuiltinFunctions(sqlite3 *db){
|
||||
case 1: pArg = db; break;
|
||||
case 2: pArg = (void *)(-1); break;
|
||||
}
|
||||
sqlite3_create_function(db, aFuncs[i].zName, aFuncs[i].nArg,
|
||||
sqlite3CreateFunc(db, aFuncs[i].zName, aFuncs[i].nArg,
|
||||
aFuncs[i].eTextRep, pArg, aFuncs[i].xFunc, 0, 0);
|
||||
if( aFuncs[i].needCollSeq ){
|
||||
FuncDef *pFunc = sqlite3FindFunction(db, aFuncs[i].zName,
|
||||
@ -1024,6 +1036,9 @@ void sqlite3RegisterBuiltinFunctions(sqlite3 *db){
|
||||
}
|
||||
#ifndef SQLITE_OMIT_ALTERTABLE
|
||||
sqlite3AlterFunctions(db);
|
||||
#endif
|
||||
#ifndef SQLITE_OMIT_PARSER
|
||||
sqlite3AttachFunctions(db);
|
||||
#endif
|
||||
for(i=0; i<sizeof(aAggs)/sizeof(aAggs[0]); i++){
|
||||
void *pArg = 0;
|
||||
@ -1031,7 +1046,7 @@ void sqlite3RegisterBuiltinFunctions(sqlite3 *db){
|
||||
case 1: pArg = db; break;
|
||||
case 2: pArg = (void *)(-1); break;
|
||||
}
|
||||
sqlite3_create_function(db, aAggs[i].zName, aAggs[i].nArg, SQLITE_UTF8,
|
||||
sqlite3CreateFunc(db, aAggs[i].zName, aAggs[i].nArg, SQLITE_UTF8,
|
||||
pArg, 0, aAggs[i].xStep, aAggs[i].xFinalize);
|
||||
if( aAggs[i].needCollSeq ){
|
||||
FuncDef *pFunc = sqlite3FindFunction( db, aAggs[i].zName,
|
||||
@ -1075,9 +1090,9 @@ void sqlite3RegisterLikeFunctions(sqlite3 *db, int caseSensitive){
|
||||
}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,
|
||||
sqlite3CreateFunc(db, "like", 2, SQLITE_UTF8, pInfo, likeFunc, 0, 0);
|
||||
sqlite3CreateFunc(db, "like", 3, SQLITE_UTF8, pInfo, likeFunc, 0, 0);
|
||||
sqlite3CreateFunc(db, "glob", 2, SQLITE_UTF8,
|
||||
(struct compareInfo*)&globInfo, likeFunc, 0,0);
|
||||
setLikeOptFlag(db, "glob", SQLITE_FUNC_LIKE | SQLITE_FUNC_CASE);
|
||||
setLikeOptFlag(db, "like",
|
||||
@ -1099,7 +1114,7 @@ int sqlite3IsLikeFunction(sqlite3 *db, Expr *pExpr, int *pIsNocase, char *aWc){
|
||||
if( pExpr->pList->nExpr!=2 ){
|
||||
return 0;
|
||||
}
|
||||
pDef = sqlite3FindFunction(db, pExpr->token.z, pExpr->token.n, 2,
|
||||
pDef = sqlite3FindFunction(db, (char*)pExpr->token.z, pExpr->token.n, 2,
|
||||
SQLITE_UTF8, 0);
|
||||
if( pDef==0 || (pDef->flags & SQLITE_FUNC_LIKE)==0 ){
|
||||
return 0;
|
||||
|
||||
@ -12,7 +12,7 @@
|
||||
** This is the implementation of generic hash-tables
|
||||
** used in SQLite.
|
||||
**
|
||||
** $Id: hash.c,v 1.16 2005/01/31 12:56:44 danielk1977 Exp $
|
||||
** $Id: hash.c,v 1.17 2005/10/03 15:11:09 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include <assert.h>
|
||||
@ -294,6 +294,11 @@ static void removeElementGivenHash(
|
||||
}
|
||||
sqliteFree( elem );
|
||||
pH->count--;
|
||||
if( pH->count<=0 ){
|
||||
assert( pH->first==0 );
|
||||
assert( pH->count==0 );
|
||||
sqlite3HashClear(pH);
|
||||
}
|
||||
}
|
||||
|
||||
/* Attempt to locate an element of the hash table pH with a key
|
||||
|
||||
@ -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.143 2005/09/20 17:42:23 drh Exp $
|
||||
** $Id: insert.c,v 1.160 2006/01/24 12:09:19 danielk1977 Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
|
||||
@ -23,10 +23,11 @@
|
||||
**
|
||||
** Character Column affinity
|
||||
** ------------------------------
|
||||
** 'n' NUMERIC
|
||||
** 'i' INTEGER
|
||||
** 't' TEXT
|
||||
** 'o' NONE
|
||||
** 'a' TEXT
|
||||
** 'b' NONE
|
||||
** 'c' NUMERIC
|
||||
** 'd' INTEGER
|
||||
** 'e' REAL
|
||||
*/
|
||||
void sqlite3IndexAffinityStr(Vdbe *v, Index *pIdx){
|
||||
if( !pIdx->zColAff ){
|
||||
@ -61,10 +62,11 @@ void sqlite3IndexAffinityStr(Vdbe *v, Index *pIdx){
|
||||
**
|
||||
** Character Column affinity
|
||||
** ------------------------------
|
||||
** 'n' NUMERIC
|
||||
** 'i' INTEGER
|
||||
** 't' TEXT
|
||||
** 'o' NONE
|
||||
** 'a' TEXT
|
||||
** 'b' NONE
|
||||
** 'c' NUMERIC
|
||||
** 'd' INTEGER
|
||||
** 'e' REAL
|
||||
*/
|
||||
void sqlite3TableAffinityStr(Vdbe *v, Table *pTab){
|
||||
/* The first time a column affinity string for a particular table
|
||||
@ -102,15 +104,15 @@ void sqlite3TableAffinityStr(Vdbe *v, Table *pTab){
|
||||
**
|
||||
** No checking is done for sub-selects that are part of expressions.
|
||||
*/
|
||||
static int selectReadsTable(Select *p, int iDb, int iTab){
|
||||
static int selectReadsTable(Select *p, Schema *pSchema, int iTab){
|
||||
int i;
|
||||
struct SrcList_item *pItem;
|
||||
if( p->pSrc==0 ) return 0;
|
||||
for(i=0, pItem=p->pSrc->a; i<p->pSrc->nSrc; i++, pItem++){
|
||||
if( pItem->pSelect ){
|
||||
if( selectReadsTable(pItem->pSelect, iDb, iTab) ) return 1;
|
||||
if( selectReadsTable(pItem->pSelect, pSchema, iTab) ) return 1;
|
||||
}else{
|
||||
if( pItem->pTab->iDb==iDb && pItem->pTab->tnum==iTab ) return 1;
|
||||
if( pItem->pTab->pSchema==pSchema && pItem->pTab->tnum==iTab ) return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
@ -212,6 +214,7 @@ void sqlite3Insert(
|
||||
int newIdx = -1; /* Cursor for the NEW table */
|
||||
Db *pDb; /* The database containing table being inserted into */
|
||||
int counterMem = 0; /* Memory cell holding AUTOINCREMENT counter */
|
||||
int iDb;
|
||||
|
||||
#ifndef SQLITE_OMIT_TRIGGER
|
||||
int isView; /* True if attempting to insert into a view */
|
||||
@ -219,10 +222,12 @@ void sqlite3Insert(
|
||||
#endif
|
||||
|
||||
#ifndef SQLITE_OMIT_AUTOINCREMENT
|
||||
int counterRowid; /* Memory cell holding rowid of autoinc counter */
|
||||
int counterRowid = 0; /* Memory cell holding rowid of autoinc counter */
|
||||
#endif
|
||||
|
||||
if( pParse->nErr || sqlite3_malloc_failed ) goto insert_cleanup;
|
||||
if( pParse->nErr || sqlite3MallocFailed() ){
|
||||
goto insert_cleanup;
|
||||
}
|
||||
db = pParse->db;
|
||||
|
||||
/* Locate the table into which we will be inserting new information.
|
||||
@ -234,8 +239,9 @@ void sqlite3Insert(
|
||||
if( pTab==0 ){
|
||||
goto insert_cleanup;
|
||||
}
|
||||
assert( pTab->iDb<db->nDb );
|
||||
pDb = &db->aDb[pTab->iDb];
|
||||
iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
|
||||
assert( iDb<db->nDb );
|
||||
pDb = &db->aDb[iDb];
|
||||
zDb = pDb->zName;
|
||||
if( sqlite3AuthCheck(pParse, SQLITE_INSERT, pTab->zName, 0, zDb) ){
|
||||
goto insert_cleanup;
|
||||
@ -271,19 +277,12 @@ void sqlite3Insert(
|
||||
goto insert_cleanup;
|
||||
}
|
||||
|
||||
/* Ensure all required collation sequences are available. */
|
||||
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
|
||||
if( sqlite3CheckIndexCollSeq(pParse, pIdx) ){
|
||||
goto insert_cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
/* Allocate a VDBE
|
||||
*/
|
||||
v = sqlite3GetVdbe(pParse);
|
||||
if( v==0 ) goto insert_cleanup;
|
||||
if( pParse->nested==0 ) sqlite3VdbeCountChanges(v);
|
||||
sqlite3BeginWriteOperation(pParse, pSelect || triggers_exist, pTab->iDb);
|
||||
sqlite3BeginWriteOperation(pParse, pSelect || triggers_exist, iDb);
|
||||
|
||||
/* if there are row triggers, allocate a temp table for new.* references. */
|
||||
if( triggers_exist ){
|
||||
@ -298,22 +297,20 @@ void sqlite3Insert(
|
||||
*/
|
||||
if( pTab->autoInc ){
|
||||
int iCur = pParse->nTab;
|
||||
int base = sqlite3VdbeCurrentAddr(v);
|
||||
int addr = sqlite3VdbeCurrentAddr(v);
|
||||
counterRowid = pParse->nMem++;
|
||||
counterMem = pParse->nMem++;
|
||||
sqlite3VdbeAddOp(v, OP_Integer, pTab->iDb, 0);
|
||||
sqlite3VdbeAddOp(v, OP_OpenRead, iCur, pDb->pSeqTab->tnum);
|
||||
sqlite3VdbeAddOp(v, OP_SetNumColumns, iCur, 2);
|
||||
sqlite3VdbeAddOp(v, OP_Rewind, iCur, base+13);
|
||||
sqlite3OpenTable(pParse, iCur, iDb, pDb->pSchema->pSeqTab, OP_OpenRead);
|
||||
sqlite3VdbeAddOp(v, OP_Rewind, iCur, addr+13);
|
||||
sqlite3VdbeAddOp(v, OP_Column, iCur, 0);
|
||||
sqlite3VdbeOp3(v, OP_String8, 0, 0, pTab->zName, 0);
|
||||
sqlite3VdbeAddOp(v, OP_Ne, 28417, base+12);
|
||||
sqlite3VdbeAddOp(v, OP_Ne, 0x100, addr+12);
|
||||
sqlite3VdbeAddOp(v, OP_Rowid, iCur, 0);
|
||||
sqlite3VdbeAddOp(v, OP_MemStore, counterRowid, 1);
|
||||
sqlite3VdbeAddOp(v, OP_Column, iCur, 1);
|
||||
sqlite3VdbeAddOp(v, OP_MemStore, counterMem, 1);
|
||||
sqlite3VdbeAddOp(v, OP_Goto, 0, base+13);
|
||||
sqlite3VdbeAddOp(v, OP_Next, iCur, base+4);
|
||||
sqlite3VdbeAddOp(v, OP_Goto, 0, addr+13);
|
||||
sqlite3VdbeAddOp(v, OP_Next, iCur, addr+4);
|
||||
sqlite3VdbeAddOp(v, OP_Close, iCur, 0);
|
||||
}
|
||||
#endif /* SQLITE_OMIT_AUTOINCREMENT */
|
||||
@ -336,7 +333,9 @@ void sqlite3Insert(
|
||||
|
||||
/* Resolve the expressions in the SELECT statement and execute it. */
|
||||
rc = sqlite3Select(pParse, pSelect, SRT_Subroutine, iInsertBlock,0,0,0,0);
|
||||
if( rc || pParse->nErr || sqlite3_malloc_failed ) goto insert_cleanup;
|
||||
if( rc || pParse->nErr || sqlite3MallocFailed() ){
|
||||
goto insert_cleanup;
|
||||
}
|
||||
|
||||
iCleanup = sqlite3VdbeMakeLabel(v);
|
||||
sqlite3VdbeAddOp(v, OP_Goto, 0, iCleanup);
|
||||
@ -351,7 +350,7 @@ void sqlite3Insert(
|
||||
** of the tables being read by the SELECT statement. Also use a
|
||||
** temp table in the case of row triggers.
|
||||
*/
|
||||
if( triggers_exist || selectReadsTable(pSelect, pTab->iDb, pTab->tnum) ){
|
||||
if( triggers_exist || selectReadsTable(pSelect,pTab->pSchema,pTab->tnum) ){
|
||||
useTempTable = 1;
|
||||
}
|
||||
|
||||
@ -362,7 +361,6 @@ void sqlite3Insert(
|
||||
srcTab = pParse->nTab++;
|
||||
sqlite3VdbeResolveLabel(v, iInsertBlock);
|
||||
sqlite3VdbeAddOp(v, OP_MakeRecord, nColumn, 0);
|
||||
sqlite3TableAffinityStr(v, pTab);
|
||||
sqlite3VdbeAddOp(v, OP_NewRowid, srcTab, 0);
|
||||
sqlite3VdbeAddOp(v, OP_Pull, 1, 0);
|
||||
sqlite3VdbeAddOp(v, OP_Insert, srcTab, 0);
|
||||
@ -635,7 +633,7 @@ void sqlite3Insert(
|
||||
/* Update the count of rows that are inserted
|
||||
*/
|
||||
if( (db->flags & SQLITE_CountRows)!=0 ){
|
||||
sqlite3VdbeAddOp(v, OP_MemIncr, iCntMem, 0);
|
||||
sqlite3VdbeAddOp(v, OP_MemIncr, 1, iCntMem);
|
||||
}
|
||||
|
||||
if( triggers_exist ){
|
||||
@ -682,12 +680,10 @@ void sqlite3Insert(
|
||||
*/
|
||||
if( pTab->autoInc ){
|
||||
int iCur = pParse->nTab;
|
||||
int base = sqlite3VdbeCurrentAddr(v);
|
||||
sqlite3VdbeAddOp(v, OP_Integer, pTab->iDb, 0);
|
||||
sqlite3VdbeAddOp(v, OP_OpenWrite, iCur, pDb->pSeqTab->tnum);
|
||||
sqlite3VdbeAddOp(v, OP_SetNumColumns, iCur, 2);
|
||||
int addr = sqlite3VdbeCurrentAddr(v);
|
||||
sqlite3OpenTable(pParse, iCur, iDb, pDb->pSchema->pSeqTab, OP_OpenWrite);
|
||||
sqlite3VdbeAddOp(v, OP_MemLoad, counterRowid, 0);
|
||||
sqlite3VdbeAddOp(v, OP_NotNull, -1, base+7);
|
||||
sqlite3VdbeAddOp(v, OP_NotNull, -1, addr+7);
|
||||
sqlite3VdbeAddOp(v, OP_Pop, 1, 0);
|
||||
sqlite3VdbeAddOp(v, OP_NewRowid, iCur, 0);
|
||||
sqlite3VdbeOp3(v, OP_String8, 0, 0, pTab->zName, 0);
|
||||
@ -870,7 +866,18 @@ void sqlite3GenerateConstraintChecks(
|
||||
|
||||
/* Test all CHECK constraints
|
||||
*/
|
||||
/**** TBD ****/
|
||||
#ifndef SQLITE_OMIT_CHECK
|
||||
if( pTab->pCheck && (pParse->db->flags & SQLITE_IgnoreChecks)==0 ){
|
||||
int allOk = sqlite3VdbeMakeLabel(v);
|
||||
assert( pParse->ckOffset==0 );
|
||||
pParse->ckOffset = nCol;
|
||||
sqlite3ExprIfTrue(pParse, pTab->pCheck, allOk, 1);
|
||||
assert( pParse->ckOffset==nCol );
|
||||
pParse->ckOffset = 0;
|
||||
sqlite3VdbeAddOp(v, OP_Halt, SQLITE_CONSTRAINT, OE_Abort);
|
||||
sqlite3VdbeResolveLabel(v, allOk);
|
||||
}
|
||||
#endif /* !defined(SQLITE_OMIT_CHECK) */
|
||||
|
||||
/* If we have an INTEGER PRIMARY KEY, make sure the primary key
|
||||
** of the new record does not previously exist. Except, if this
|
||||
@ -1067,9 +1074,13 @@ void sqlite3CompleteInsertion(
|
||||
if( pParse->nested ){
|
||||
pik_flags = 0;
|
||||
}else{
|
||||
pik_flags = (OPFLAG_NCHANGE|(isUpdate?0:OPFLAG_LASTROWID));
|
||||
pik_flags = OPFLAG_NCHANGE;
|
||||
pik_flags |= (isUpdate?OPFLAG_ISUPDATE:OPFLAG_LASTROWID);
|
||||
}
|
||||
sqlite3VdbeAddOp(v, OP_Insert, base, pik_flags);
|
||||
if( !pParse->nested ){
|
||||
sqlite3VdbeChangeP3(v, -1, pTab->zName, P3_STATIC);
|
||||
}
|
||||
|
||||
if( isUpdate && rowidChng ){
|
||||
sqlite3VdbeAddOp(v, OP_Pop, 1, 0);
|
||||
@ -1088,18 +1099,17 @@ void sqlite3OpenTableAndIndices(
|
||||
int op /* OP_OpenRead or OP_OpenWrite */
|
||||
){
|
||||
int i;
|
||||
int iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
|
||||
Index *pIdx;
|
||||
Vdbe *v = sqlite3GetVdbe(pParse);
|
||||
assert( v!=0 );
|
||||
sqlite3VdbeAddOp(v, OP_Integer, pTab->iDb, 0);
|
||||
VdbeComment((v, "# %s", pTab->zName));
|
||||
sqlite3VdbeAddOp(v, op, base, pTab->tnum);
|
||||
sqlite3VdbeAddOp(v, OP_SetNumColumns, base, pTab->nCol);
|
||||
sqlite3OpenTable(pParse, base, iDb, pTab, op);
|
||||
for(i=1, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
|
||||
sqlite3VdbeAddOp(v, OP_Integer, pIdx->iDb, 0);
|
||||
KeyInfo *pKey = sqlite3IndexKeyinfo(pParse, pIdx);
|
||||
assert( pIdx->pSchema==pTab->pSchema );
|
||||
sqlite3VdbeAddOp(v, OP_Integer, iDb, 0);
|
||||
VdbeComment((v, "# %s", pIdx->zName));
|
||||
sqlite3VdbeOp3(v, op, i+base, pIdx->tnum,
|
||||
(char*)&pIdx->keyInfo, P3_KEYINFO);
|
||||
sqlite3VdbeOp3(v, op, i+base, pIdx->tnum, (char*)pKey, P3_KEYINFO_HANDOFF);
|
||||
}
|
||||
if( pParse->nTab<=base+i ){
|
||||
pParse->nTab = base+i;
|
||||
|
||||
@ -1,28 +1,28 @@
|
||||
/* Hash score: 158 */
|
||||
/* Hash score: 159 */
|
||||
static int keywordCode(const char *z, int n){
|
||||
static const char zText[535] =
|
||||
static const char zText[537] =
|
||||
"ABORTABLEFTEMPORARYADDATABASELECTHENDEFAULTRANSACTIONATURALTER"
|
||||
"AISEACHECKEYAFTEREFERENCESCAPELSEXCEPTRIGGEREGEXPLAINITIALLYANALYZE"
|
||||
"XCLUSIVEXISTSTATEMENTANDEFERRABLEATTACHAVINGLOBEFOREIGNOREINDEX"
|
||||
"AUTOINCREMENTBEGINNERENAMEBETWEENOTNULLIKEBYCASCADEFERREDELETE"
|
||||
"CASECASTCOLLATECOLUMNCOMMITCONFLICTCONSTRAINTERSECTCREATECROSS"
|
||||
"CURRENT_DATECURRENT_TIMESTAMPLANDESCDETACHDISTINCTDROPRAGMATCH"
|
||||
"FAILIMITFROMFULLGROUPDATEIMMEDIATEINSERTINSTEADINTOFFSETISNULL"
|
||||
"FAILIMITFROMFULLGROUPDATEIFIMMEDIATEINSERTINSTEADINTOFFSETISNULL"
|
||||
"JOINORDEREPLACEOUTERESTRICTPRIMARYQUERYRIGHTROLLBACKROWHENUNION"
|
||||
"UNIQUEUSINGVACUUMVALUESVIEWHERE";
|
||||
static const unsigned char aHash[127] = {
|
||||
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,
|
||||
92, 80, 107, 91, 0, 4, 0, 0, 114, 0, 83, 0, 0,
|
||||
95, 44, 76, 93, 0, 106, 109, 97, 90, 0, 10, 0, 0,
|
||||
113, 0, 110, 103, 0, 28, 48, 0, 41, 0, 0, 65, 71,
|
||||
0, 63, 19, 0, 105, 36, 104, 0, 108, 74, 0, 0, 33,
|
||||
0, 61, 37, 0, 8, 0, 115, 38, 12, 0, 77, 40, 25,
|
||||
66, 0, 0, 31, 81, 53, 30, 50, 20, 88, 0, 34, 0,
|
||||
75, 26, 0, 72, 0, 0, 0, 64, 47, 67, 22, 87, 29,
|
||||
69, 86, 0, 1, 0, 9, 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,
|
||||
69, 86, 0, 1, 0, 9, 101, 58, 18, 0, 112, 82, 99,
|
||||
54, 6, 85, 0, 0, 49, 94, 0, 102, 0, 70, 0, 0,
|
||||
15, 0, 116, 51, 56, 0, 2, 55, 0, 111,
|
||||
};
|
||||
static const unsigned char aNext[115] = {
|
||||
static const unsigned char aNext[116] = {
|
||||
0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0,
|
||||
0, 11, 0, 0, 0, 0, 5, 13, 0, 7, 0, 0, 0,
|
||||
@ -30,32 +30,32 @@ static int keywordCode(const char *z, int n){
|
||||
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,
|
||||
0, 0, 0, 0, 0, 39, 96, 98, 0, 0, 100, 0, 32,
|
||||
0, 14, 27, 78, 0, 57, 89, 0, 35, 0, 62, 0,
|
||||
};
|
||||
static const unsigned char aLen[115] = {
|
||||
static const unsigned char aLen[116] = {
|
||||
5, 5, 4, 4, 9, 2, 3, 8, 2, 6, 4, 3, 7,
|
||||
11, 2, 7, 5, 5, 4, 5, 3, 5, 10, 6, 4, 6,
|
||||
7, 6, 7, 9, 3, 7, 9, 6, 9, 3, 10, 6, 6,
|
||||
4, 6, 3, 7, 6, 7, 5, 13, 2, 2, 5, 5, 6,
|
||||
7, 3, 7, 4, 4, 2, 7, 3, 8, 6, 4, 4, 7,
|
||||
6, 6, 8, 10, 9, 6, 5, 12, 12, 17, 4, 4, 6,
|
||||
8, 2, 4, 6, 5, 4, 5, 4, 4, 5, 6, 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,
|
||||
8, 2, 4, 6, 5, 4, 5, 4, 4, 5, 6, 2, 9,
|
||||
6, 7, 4, 2, 6, 3, 6, 4, 5, 7, 5, 8, 7,
|
||||
5, 5, 8, 3, 4, 5, 6, 5, 6, 6, 4, 5,
|
||||
};
|
||||
static const unsigned short int aOffset[115] = {
|
||||
static const unsigned short int aOffset[116] = {
|
||||
0, 4, 7, 10, 10, 14, 19, 21, 26, 27, 32, 34, 36,
|
||||
42, 51, 52, 57, 61, 65, 67, 71, 74, 78, 86, 91, 94,
|
||||
99, 105, 108, 113, 118, 122, 128, 136, 141, 150, 152, 162, 167,
|
||||
172, 175, 177, 177, 181, 185, 187, 192, 194, 196, 205, 208, 212,
|
||||
218, 224, 224, 227, 230, 234, 236, 237, 241, 248, 254, 258, 262,
|
||||
269, 275, 281, 289, 296, 305, 311, 316, 328, 328, 344, 348, 352,
|
||||
358, 359, 366, 369, 373, 378, 381, 386, 390, 394, 397, 403, 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,
|
||||
358, 359, 366, 369, 373, 378, 381, 386, 390, 394, 397, 403, 405,
|
||||
414, 420, 427, 430, 430, 433, 436, 442, 446, 450, 457, 461, 469,
|
||||
476, 481, 486, 494, 496, 500, 505, 511, 516, 522, 528, 531,
|
||||
};
|
||||
static const unsigned char aCode[115] = {
|
||||
static const unsigned char aCode[116] = {
|
||||
TK_ABORT, TK_TABLE, TK_JOIN_KW, TK_TEMP, TK_TEMP,
|
||||
TK_OR, TK_ADD, TK_DATABASE, TK_AS, TK_SELECT,
|
||||
TK_THEN, TK_END, TK_DEFAULT, TK_TRANSACTION,TK_ON,
|
||||
@ -73,12 +73,13 @@ static int keywordCode(const char *z, int n){
|
||||
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,
|
||||
TK_FROM, TK_JOIN_KW, TK_GROUP, TK_UPDATE, TK_IF,
|
||||
TK_IMMEDIATE, TK_INSERT, TK_INSTEAD, TK_INTO, TK_OF,
|
||||
TK_OFFSET, TK_SET, TK_ISNULL, TK_JOIN, TK_ORDER,
|
||||
TK_REPLACE, TK_JOIN_KW, TK_RESTRICT, TK_PRIMARY, TK_QUERY,
|
||||
TK_JOIN_KW, TK_ROLLBACK, TK_ROW, TK_WHEN, TK_UNION,
|
||||
TK_UNIQUE, TK_USING, TK_VACUUM, TK_VALUES, TK_VIEW,
|
||||
TK_WHERE,
|
||||
};
|
||||
int h, i;
|
||||
if( n<2 ) return TK_ID;
|
||||
@ -92,6 +93,6 @@ static int keywordCode(const char *z, int n){
|
||||
}
|
||||
return TK_ID;
|
||||
}
|
||||
int sqlite3KeywordCode(const char *z, int n){
|
||||
return keywordCode(z, n);
|
||||
int sqlite3KeywordCode(const unsigned char *z, int n){
|
||||
return keywordCode((char*)z, n);
|
||||
}
|
||||
|
||||
@ -14,7 +14,7 @@
|
||||
** other files are for internal use by SQLite and should not be
|
||||
** accessed by users of the library.
|
||||
**
|
||||
** $Id: legacy.c,v 1.7 2004/09/06 17:34:13 drh Exp $
|
||||
** $Id: legacy.c,v 1.13 2006/01/23 13:14:55 drh Exp $
|
||||
*/
|
||||
|
||||
#include "sqliteInt.h"
|
||||
@ -68,9 +68,8 @@ int sqlite3_exec(
|
||||
nCallback = 0;
|
||||
|
||||
nCol = sqlite3_column_count(pStmt);
|
||||
azCols = sqliteMalloc(2*nCol*sizeof(const char *));
|
||||
if( nCol && !azCols ){
|
||||
rc = SQLITE_NOMEM;
|
||||
azCols = sqliteMalloc(2*nCol*sizeof(const char *) + 1);
|
||||
if( azCols==0 ){
|
||||
goto exec_out;
|
||||
}
|
||||
|
||||
@ -122,9 +121,7 @@ exec_out:
|
||||
if( pStmt ) sqlite3_finalize(pStmt);
|
||||
if( azCols ) sqliteFree(azCols);
|
||||
|
||||
if( sqlite3_malloc_failed ){
|
||||
rc = SQLITE_NOMEM;
|
||||
}
|
||||
rc = sqlite3ApiExit(0, rc);
|
||||
if( rc!=SQLITE_OK && rc==sqlite3_errcode(db) && pzErrMsg ){
|
||||
*pzErrMsg = malloc(1+strlen(sqlite3_errmsg(db)));
|
||||
if( *pzErrMsg ){
|
||||
|
||||
@ -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.302 2005/09/17 15:20:27 drh Exp $
|
||||
** $Id: main.c,v 1.331 2006/01/24 16:37:58 danielk1977 Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include "os.h"
|
||||
@ -26,28 +26,6 @@
|
||||
*/
|
||||
const int sqlite3one = 1;
|
||||
|
||||
#ifndef SQLITE_OMIT_GLOBALRECOVER
|
||||
/*
|
||||
** Linked list of all open database handles. This is used by the
|
||||
** sqlite3_global_recover() function. Entries are added to the list
|
||||
** by openDatabase() and removed by sqlite3_close().
|
||||
*/
|
||||
static sqlite3 *pDbList = 0;
|
||||
#endif
|
||||
|
||||
#ifndef SQLITE_OMIT_UTF16
|
||||
/*
|
||||
** Return the transient sqlite3_value object used for encoding conversions
|
||||
** during SQL compilation.
|
||||
*/
|
||||
sqlite3_value *sqlite3GetTransientValue(sqlite3 *db){
|
||||
if( !db->pValue ){
|
||||
db->pValue = sqlite3ValueNew();
|
||||
}
|
||||
return db->pValue;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
** The version of the library
|
||||
*/
|
||||
@ -158,6 +136,9 @@ int sqlite3_close(sqlite3 *db){
|
||||
if( pDb->pBt ){
|
||||
sqlite3BtreeClose(pDb->pBt);
|
||||
pDb->pBt = 0;
|
||||
if( j!=1 ){
|
||||
pDb->pSchema = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
sqlite3ResetInternalSchema(db, 0);
|
||||
@ -179,33 +160,21 @@ int sqlite3_close(sqlite3 *db){
|
||||
|
||||
sqlite3HashClear(&db->aFunc);
|
||||
sqlite3Error(db, SQLITE_OK, 0); /* Deallocates any cached error strings. */
|
||||
if( db->pValue ){
|
||||
sqlite3ValueFree(db->pValue);
|
||||
}
|
||||
if( db->pErr ){
|
||||
sqlite3ValueFree(db->pErr);
|
||||
}
|
||||
|
||||
#ifndef SQLITE_OMIT_GLOBALRECOVER
|
||||
{
|
||||
sqlite3 *pPrev;
|
||||
sqlite3OsEnterMutex();
|
||||
pPrev = pDbList;
|
||||
while( pPrev && pPrev->pNext!=db ){
|
||||
pPrev = pPrev->pNext;
|
||||
}
|
||||
if( pPrev ){
|
||||
pPrev->pNext = db->pNext;
|
||||
}else{
|
||||
assert( pDbList==db );
|
||||
pDbList = db->pNext;
|
||||
}
|
||||
sqlite3OsLeaveMutex();
|
||||
}
|
||||
#endif
|
||||
|
||||
db->magic = SQLITE_MAGIC_ERROR;
|
||||
|
||||
/* The temp-database schema is allocated differently from the other schema
|
||||
** objects (using sqliteMalloc() directly, instead of sqlite3BtreeSchema()).
|
||||
** So it needs to be freed here. Todo: Why not roll the temp schema into
|
||||
** the same sqliteMalloc() as the one that allocates the database
|
||||
** structure?
|
||||
*/
|
||||
sqliteFree(db->aDb[1].pSchema);
|
||||
sqliteFree(db);
|
||||
sqlite3ReleaseThreadData();
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
@ -214,13 +183,24 @@ int sqlite3_close(sqlite3 *db){
|
||||
*/
|
||||
void sqlite3RollbackAll(sqlite3 *db){
|
||||
int i;
|
||||
int inTrans = 0;
|
||||
for(i=0; i<db->nDb; i++){
|
||||
if( db->aDb[i].pBt ){
|
||||
if( sqlite3BtreeIsInTrans(db->aDb[i].pBt) ){
|
||||
inTrans = 1;
|
||||
}
|
||||
sqlite3BtreeRollback(db->aDb[i].pBt);
|
||||
db->aDb[i].inTrans = 0;
|
||||
}
|
||||
}
|
||||
sqlite3ResetInternalSchema(db, 0);
|
||||
if( db->flags&SQLITE_InternChanges ){
|
||||
sqlite3ResetInternalSchema(db, 0);
|
||||
}
|
||||
|
||||
/* If one has been configured, invoke the rollback-hook callback */
|
||||
if( db->xRollbackCallback && (inTrans || !db->autoCommit) ){
|
||||
db->xRollbackCallback(db->pRollbackArg);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@ -402,9 +382,12 @@ void sqlite3_interrupt(sqlite3 *db){
|
||||
void sqlite3_free(char *p){ free(p); }
|
||||
|
||||
/*
|
||||
** Create new user functions.
|
||||
** This function is exactly the same as sqlite3_create_function(), except
|
||||
** that it is designed to be called by internal code. The difference is
|
||||
** that if a malloc() fails in sqlite3_create_function(), an error code
|
||||
** is returned and the mallocFailed flag cleared.
|
||||
*/
|
||||
int sqlite3_create_function(
|
||||
int sqlite3CreateFunc(
|
||||
sqlite3 *db,
|
||||
const char *zFunctionName,
|
||||
int nArg,
|
||||
@ -441,10 +424,10 @@ int sqlite3_create_function(
|
||||
enc = SQLITE_UTF16NATIVE;
|
||||
}else if( enc==SQLITE_ANY ){
|
||||
int rc;
|
||||
rc = sqlite3_create_function(db, zFunctionName, nArg, SQLITE_UTF8,
|
||||
rc = sqlite3CreateFunc(db, zFunctionName, nArg, SQLITE_UTF8,
|
||||
pUserData, xFunc, xStep, xFinal);
|
||||
if( rc!=SQLITE_OK ) return rc;
|
||||
rc = sqlite3_create_function(db, zFunctionName, nArg, SQLITE_UTF16LE,
|
||||
rc = sqlite3CreateFunc(db, zFunctionName, nArg, SQLITE_UTF16LE,
|
||||
pUserData, xFunc, xStep, xFinal);
|
||||
if( rc!=SQLITE_OK ) return rc;
|
||||
enc = SQLITE_UTF16BE;
|
||||
@ -463,6 +446,7 @@ int sqlite3_create_function(
|
||||
if( db->activeVdbeCnt ){
|
||||
sqlite3Error(db, SQLITE_BUSY,
|
||||
"Unable to delete/modify user-function due to active statements");
|
||||
assert( !sqlite3MallocFailed() );
|
||||
return SQLITE_BUSY;
|
||||
}else{
|
||||
sqlite3ExpirePreparedStatements(db);
|
||||
@ -470,42 +454,56 @@ 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;
|
||||
p->pUserData = pUserData;
|
||||
if( p ){
|
||||
p->flags = 0;
|
||||
p->xFunc = xFunc;
|
||||
p->xStep = xStep;
|
||||
p->xFinalize = xFinal;
|
||||
p->pUserData = pUserData;
|
||||
}
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Create new user functions.
|
||||
*/
|
||||
int sqlite3_create_function(
|
||||
sqlite3 *db,
|
||||
const char *zFunctionName,
|
||||
int nArg,
|
||||
int enc,
|
||||
void *p,
|
||||
void (*xFunc)(sqlite3_context*,int,sqlite3_value **),
|
||||
void (*xStep)(sqlite3_context*,int,sqlite3_value **),
|
||||
void (*xFinal)(sqlite3_context*)
|
||||
){
|
||||
int rc;
|
||||
assert( !sqlite3MallocFailed() );
|
||||
rc = sqlite3CreateFunc(db, zFunctionName, nArg, enc, p, xFunc, xStep, xFinal);
|
||||
|
||||
return sqlite3ApiExit(db, rc);
|
||||
}
|
||||
|
||||
#ifndef SQLITE_OMIT_UTF16
|
||||
int sqlite3_create_function16(
|
||||
sqlite3 *db,
|
||||
const void *zFunctionName,
|
||||
int nArg,
|
||||
int eTextRep,
|
||||
void *pUserData,
|
||||
void *p,
|
||||
void (*xFunc)(sqlite3_context*,int,sqlite3_value**),
|
||||
void (*xStep)(sqlite3_context*,int,sqlite3_value**),
|
||||
void (*xFinal)(sqlite3_context*)
|
||||
){
|
||||
int rc;
|
||||
char const *zFunc8;
|
||||
sqlite3_value *pTmp;
|
||||
char *zFunc8;
|
||||
assert( !sqlite3MallocFailed() );
|
||||
|
||||
if( sqlite3SafetyCheck(db) ){
|
||||
return SQLITE_MISUSE;
|
||||
}
|
||||
pTmp = sqlite3GetTransientValue(db);
|
||||
sqlite3ValueSetStr(pTmp, -1, zFunctionName, SQLITE_UTF16NATIVE,SQLITE_STATIC);
|
||||
zFunc8 = sqlite3ValueText(pTmp, SQLITE_UTF8);
|
||||
zFunc8 = sqlite3utf16to8(zFunctionName, -1);
|
||||
rc = sqlite3CreateFunc(db, zFunc8, nArg, eTextRep, p, xFunc, xStep, xFinal);
|
||||
sqliteFree(zFunc8);
|
||||
|
||||
if( !zFunc8 ){
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
rc = sqlite3_create_function(db, zFunc8, nArg, eTextRep,
|
||||
pUserData, xFunc, xStep, xFinal);
|
||||
return rc;
|
||||
return sqlite3ApiExit(db, rc);
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -547,7 +545,7 @@ void *sqlite3_profile(
|
||||
/*** EXPERIMENTAL ***
|
||||
**
|
||||
** Register a function to be invoked when a transaction comments.
|
||||
** If either function returns non-zero, then the commit becomes a
|
||||
** If the invoked function returns non-zero, then the commit becomes a
|
||||
** rollback.
|
||||
*/
|
||||
void *sqlite3_commit_hook(
|
||||
@ -561,6 +559,35 @@ void *sqlite3_commit_hook(
|
||||
return pOld;
|
||||
}
|
||||
|
||||
/*
|
||||
** Register a callback to be invoked each time a row is updated,
|
||||
** inserted or deleted using this database connection.
|
||||
*/
|
||||
void *sqlite3_update_hook(
|
||||
sqlite3 *db, /* Attach the hook to this database */
|
||||
void (*xCallback)(void*,int,char const *,char const *,sqlite_int64),
|
||||
void *pArg /* Argument to the function */
|
||||
){
|
||||
void *pRet = db->pUpdateArg;
|
||||
db->xUpdateCallback = xCallback;
|
||||
db->pUpdateArg = pArg;
|
||||
return pRet;
|
||||
}
|
||||
|
||||
/*
|
||||
** Register a callback to be invoked each time a transaction is rolled
|
||||
** back by this database connection.
|
||||
*/
|
||||
void *sqlite3_rollback_hook(
|
||||
sqlite3 *db, /* Attach the hook to this database */
|
||||
void (*xCallback)(void*), /* Callback function */
|
||||
void *pArg /* Argument to the function */
|
||||
){
|
||||
void *pRet = db->pRollbackArg;
|
||||
db->xRollbackCallback = xCallback;
|
||||
db->pRollbackArg = pArg;
|
||||
return pRet;
|
||||
}
|
||||
|
||||
/*
|
||||
** This routine is called to create a connection to a database BTree
|
||||
@ -621,7 +648,7 @@ int sqlite3BtreeFactory(
|
||||
#endif /* SQLITE_OMIT_MEMORYDB */
|
||||
}
|
||||
|
||||
rc = sqlite3BtreeOpen(zFilename, ppBtree, btree_flags);
|
||||
rc = sqlite3BtreeOpen(zFilename, (sqlite3 *)db, ppBtree, btree_flags);
|
||||
if( rc==SQLITE_OK ){
|
||||
sqlite3BtreeSetBusyHandler(*ppBtree, (void*)&db->busyHandler);
|
||||
sqlite3BtreeSetCacheSize(*ppBtree, nCache);
|
||||
@ -635,13 +662,13 @@ int sqlite3BtreeFactory(
|
||||
*/
|
||||
const char *sqlite3_errmsg(sqlite3 *db){
|
||||
const char *z;
|
||||
if( sqlite3_malloc_failed ){
|
||||
if( !db || sqlite3MallocFailed() ){
|
||||
return sqlite3ErrStr(SQLITE_NOMEM);
|
||||
}
|
||||
if( sqlite3SafetyCheck(db) || db->errCode==SQLITE_MISUSE ){
|
||||
return sqlite3ErrStr(SQLITE_MISUSE);
|
||||
}
|
||||
z = sqlite3_value_text(db->pErr);
|
||||
z = (char*)sqlite3_value_text(db->pErr);
|
||||
if( z==0 ){
|
||||
z = sqlite3ErrStr(db->errCode);
|
||||
}
|
||||
@ -674,7 +701,7 @@ const void *sqlite3_errmsg16(sqlite3 *db){
|
||||
};
|
||||
|
||||
const void *z;
|
||||
if( sqlite3_malloc_failed ){
|
||||
if( sqlite3MallocFailed() ){
|
||||
return (void *)(&outOfMemBe[SQLITE_UTF16NATIVE==SQLITE_UTF16LE?1:0]);
|
||||
}
|
||||
if( sqlite3SafetyCheck(db) || db->errCode==SQLITE_MISUSE ){
|
||||
@ -686,15 +713,17 @@ const void *sqlite3_errmsg16(sqlite3 *db){
|
||||
SQLITE_UTF8, SQLITE_STATIC);
|
||||
z = sqlite3_value_text16(db->pErr);
|
||||
}
|
||||
sqlite3ApiExit(0, 0);
|
||||
return z;
|
||||
}
|
||||
#endif /* SQLITE_OMIT_UTF16 */
|
||||
|
||||
/*
|
||||
** Return the most recent error code generated by an SQLite routine.
|
||||
** Return the most recent error code generated by an SQLite routine. If NULL is
|
||||
** passed to this function, we assume a malloc() failed during sqlite3_open().
|
||||
*/
|
||||
int sqlite3_errcode(sqlite3 *db){
|
||||
if( sqlite3_malloc_failed ){
|
||||
if( !db || sqlite3MallocFailed() ){
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
if( sqlite3SafetyCheck(db) ){
|
||||
@ -703,6 +732,60 @@ int sqlite3_errcode(sqlite3 *db){
|
||||
return db->errCode;
|
||||
}
|
||||
|
||||
static int createCollation(
|
||||
sqlite3* db,
|
||||
const char *zName,
|
||||
int enc,
|
||||
void* pCtx,
|
||||
int(*xCompare)(void*,int,const void*,int,const void*)
|
||||
){
|
||||
CollSeq *pColl;
|
||||
|
||||
if( sqlite3SafetyCheck(db) ){
|
||||
return SQLITE_MISUSE;
|
||||
}
|
||||
|
||||
/* If SQLITE_UTF16 is specified as the encoding type, transform this
|
||||
** to one of SQLITE_UTF16LE or SQLITE_UTF16BE using the
|
||||
** SQLITE_UTF16NATIVE macro. SQLITE_UTF16 is not used internally.
|
||||
*/
|
||||
if( enc==SQLITE_UTF16 ){
|
||||
enc = SQLITE_UTF16NATIVE;
|
||||
}
|
||||
|
||||
if( enc!=SQLITE_UTF8 && enc!=SQLITE_UTF16LE && enc!=SQLITE_UTF16BE ){
|
||||
sqlite3Error(db, SQLITE_ERROR,
|
||||
"Param 3 to sqlite3_create_collation() must be one of "
|
||||
"SQLITE_UTF8, SQLITE_UTF16, SQLITE_UTF16LE or SQLITE_UTF16BE"
|
||||
);
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
|
||||
/* Check if this call is removing or replacing an existing collation
|
||||
** sequence. If so, and there are active VMs, return busy. If there
|
||||
** are no active VMs, invalidate any pre-compiled statements.
|
||||
*/
|
||||
pColl = sqlite3FindCollSeq(db, (u8)enc, zName, strlen(zName), 0);
|
||||
if( pColl && pColl->xCmp ){
|
||||
if( db->activeVdbeCnt ){
|
||||
sqlite3Error(db, SQLITE_BUSY,
|
||||
"Unable to delete/modify collation sequence due to active statements");
|
||||
return SQLITE_BUSY;
|
||||
}
|
||||
sqlite3ExpirePreparedStatements(db);
|
||||
}
|
||||
|
||||
pColl = sqlite3FindCollSeq(db, (u8)enc, zName, strlen(zName), 1);
|
||||
if( pColl ){
|
||||
pColl->xCmp = xCompare;
|
||||
pColl->pUser = pCtx;
|
||||
pColl->enc = enc;
|
||||
}
|
||||
sqlite3Error(db, SQLITE_OK, 0);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** This routine does the work of opening a database on behalf of
|
||||
** sqlite3_open() and sqlite3_open16(). The database filename "zFilename"
|
||||
@ -713,9 +796,11 @@ static int openDatabase(
|
||||
sqlite3 **ppDb /* OUT: Returned database handle */
|
||||
){
|
||||
sqlite3 *db;
|
||||
int rc, i;
|
||||
int rc;
|
||||
CollSeq *pColl;
|
||||
|
||||
assert( !sqlite3MallocFailed() );
|
||||
|
||||
/* Allocate the sqlite data structure */
|
||||
db = sqliteMalloc( sizeof(sqlite3) );
|
||||
if( db==0 ) goto opendb_out;
|
||||
@ -723,33 +808,26 @@ static int openDatabase(
|
||||
db->magic = SQLITE_MAGIC_BUSY;
|
||||
db->nDb = 2;
|
||||
db->aDb = db->aDbStatic;
|
||||
db->enc = SQLITE_UTF8;
|
||||
db->autoCommit = 1;
|
||||
db->flags |= SQLITE_ShortColNames;
|
||||
sqlite3HashInit(&db->aFunc, SQLITE_HASH_STRING, 0);
|
||||
sqlite3HashInit(&db->aCollSeq, SQLITE_HASH_STRING, 0);
|
||||
for(i=0; i<db->nDb; i++){
|
||||
sqlite3HashInit(&db->aDb[i].tblHash, SQLITE_HASH_STRING, 0);
|
||||
sqlite3HashInit(&db->aDb[i].idxHash, SQLITE_HASH_STRING, 0);
|
||||
sqlite3HashInit(&db->aDb[i].trigHash, SQLITE_HASH_STRING, 0);
|
||||
sqlite3HashInit(&db->aDb[i].aFKey, SQLITE_HASH_STRING, 1);
|
||||
}
|
||||
|
||||
|
||||
/* Add the default collation sequence BINARY. BINARY works for both UTF-8
|
||||
** and UTF-16, so add a version for each to avoid any unnecessary
|
||||
** conversions. The only error that can occur here is a malloc() failure.
|
||||
*/
|
||||
if( sqlite3_create_collation(db, "BINARY", SQLITE_UTF8, 0,binCollFunc) ||
|
||||
sqlite3_create_collation(db, "BINARY", SQLITE_UTF16, 0,binCollFunc) ||
|
||||
!(db->pDfltColl = sqlite3FindCollSeq(db, db->enc, "BINARY", 6, 0)) ){
|
||||
rc = db->errCode;
|
||||
assert( rc!=SQLITE_OK );
|
||||
if( createCollation(db, "BINARY", SQLITE_UTF8, 0,binCollFunc) ||
|
||||
createCollation(db, "BINARY", SQLITE_UTF16, 0,binCollFunc) ||
|
||||
(db->pDfltColl = sqlite3FindCollSeq(db, SQLITE_UTF8, "BINARY", 6, 0))==0
|
||||
){
|
||||
assert( sqlite3MallocFailed() );
|
||||
db->magic = SQLITE_MAGIC_CLOSED;
|
||||
goto opendb_out;
|
||||
}
|
||||
|
||||
/* Also add a UTF-8 case-insensitive collation sequence. */
|
||||
sqlite3_create_collation(db, "NOCASE", SQLITE_UTF8, 0, nocaseCollatingFunc);
|
||||
createCollation(db, "NOCASE", SQLITE_UTF8, 0, nocaseCollatingFunc);
|
||||
|
||||
/* Set flags on the built-in collating sequences */
|
||||
db->pDfltColl->type = SQLITE_COLL_BINARY;
|
||||
@ -765,6 +843,14 @@ static int openDatabase(
|
||||
db->magic = SQLITE_MAGIC_CLOSED;
|
||||
goto opendb_out;
|
||||
}
|
||||
#ifndef SQLITE_OMIT_PARSER
|
||||
db->aDb[0].pSchema = sqlite3SchemaGet(db->aDb[0].pBt);
|
||||
db->aDb[1].pSchema = sqlite3SchemaGet(0);
|
||||
#endif
|
||||
|
||||
if( db->aDb[0].pSchema ){
|
||||
ENC(db) = SQLITE_UTF8;
|
||||
}
|
||||
|
||||
/* The default safety_level for the main database is 'full'; for the temp
|
||||
** database it is 'NONE'. This matches the pager layer defaults.
|
||||
@ -776,29 +862,23 @@ static int openDatabase(
|
||||
db->aDb[1].safety_level = 1;
|
||||
#endif
|
||||
|
||||
|
||||
/* Register all built-in functions, but do not attempt to read the
|
||||
** database schema yet. This is delayed until the first time the database
|
||||
** is accessed.
|
||||
*/
|
||||
sqlite3RegisterBuiltinFunctions(db);
|
||||
sqlite3Error(db, SQLITE_OK, 0);
|
||||
if( !sqlite3MallocFailed() ){
|
||||
sqlite3RegisterBuiltinFunctions(db);
|
||||
sqlite3Error(db, SQLITE_OK, 0);
|
||||
}
|
||||
db->magic = SQLITE_MAGIC_OPEN;
|
||||
|
||||
opendb_out:
|
||||
if( sqlite3_errcode(db)==SQLITE_OK && sqlite3_malloc_failed ){
|
||||
sqlite3Error(db, SQLITE_NOMEM, 0);
|
||||
if( SQLITE_NOMEM==(rc = sqlite3_errcode(db)) ){
|
||||
sqlite3_close(db);
|
||||
db = 0;
|
||||
}
|
||||
*ppDb = db;
|
||||
#ifndef SQLITE_OMIT_GLOBALRECOVER
|
||||
if( db ){
|
||||
sqlite3OsEnterMutex();
|
||||
db->pNext = pDbList;
|
||||
pDbList = db;
|
||||
sqlite3OsLeaveMutex();
|
||||
}
|
||||
#endif
|
||||
return sqlite3_errcode(db);
|
||||
return sqlite3ApiExit(0, rc);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -820,9 +900,10 @@ int sqlite3_open16(
|
||||
sqlite3 **ppDb
|
||||
){
|
||||
char const *zFilename8; /* zFilename encoded in UTF-8 instead of UTF-16 */
|
||||
int rc = SQLITE_NOMEM;
|
||||
int rc = SQLITE_OK;
|
||||
sqlite3_value *pVal;
|
||||
|
||||
assert( zFilename );
|
||||
assert( ppDb );
|
||||
*ppDb = 0;
|
||||
pVal = sqlite3ValueNew();
|
||||
@ -831,14 +912,16 @@ int sqlite3_open16(
|
||||
if( zFilename8 ){
|
||||
rc = openDatabase(zFilename8, ppDb);
|
||||
if( rc==SQLITE_OK && *ppDb ){
|
||||
sqlite3_exec(*ppDb, "PRAGMA encoding = 'UTF-16'", 0, 0, 0);
|
||||
rc = sqlite3_exec(*ppDb, "PRAGMA encoding = 'UTF-16'", 0, 0, 0);
|
||||
if( rc!=SQLITE_OK ){
|
||||
sqlite3_close(*ppDb);
|
||||
*ppDb = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
if( pVal ){
|
||||
sqlite3ValueFree(pVal);
|
||||
}
|
||||
sqlite3ValueFree(pVal);
|
||||
|
||||
return rc;
|
||||
return sqlite3ApiExit(0, rc);
|
||||
}
|
||||
#endif /* SQLITE_OMIT_UTF16 */
|
||||
|
||||
@ -890,53 +973,10 @@ int sqlite3_create_collation(
|
||||
void* pCtx,
|
||||
int(*xCompare)(void*,int,const void*,int,const void*)
|
||||
){
|
||||
CollSeq *pColl;
|
||||
int rc = SQLITE_OK;
|
||||
|
||||
if( sqlite3SafetyCheck(db) ){
|
||||
return SQLITE_MISUSE;
|
||||
}
|
||||
|
||||
/* If SQLITE_UTF16 is specified as the encoding type, transform this
|
||||
** to one of SQLITE_UTF16LE or SQLITE_UTF16BE using the
|
||||
** SQLITE_UTF16NATIVE macro. SQLITE_UTF16 is not used internally.
|
||||
*/
|
||||
if( enc==SQLITE_UTF16 ){
|
||||
enc = SQLITE_UTF16NATIVE;
|
||||
}
|
||||
|
||||
if( enc!=SQLITE_UTF8 && enc!=SQLITE_UTF16LE && enc!=SQLITE_UTF16BE ){
|
||||
sqlite3Error(db, SQLITE_ERROR,
|
||||
"Param 3 to sqlite3_create_collation() must be one of "
|
||||
"SQLITE_UTF8, SQLITE_UTF16, SQLITE_UTF16LE or SQLITE_UTF16BE"
|
||||
);
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
|
||||
/* Check if this call is removing or replacing an existing collation
|
||||
** sequence. If so, and there are active VMs, return busy. If there
|
||||
** are no active VMs, invalidate any pre-compiled statements.
|
||||
*/
|
||||
pColl = sqlite3FindCollSeq(db, (u8)enc, zName, strlen(zName), 0);
|
||||
if( pColl && pColl->xCmp ){
|
||||
if( db->activeVdbeCnt ){
|
||||
sqlite3Error(db, SQLITE_BUSY,
|
||||
"Unable to delete/modify collation sequence due to active statements");
|
||||
return SQLITE_BUSY;
|
||||
}
|
||||
sqlite3ExpirePreparedStatements(db);
|
||||
}
|
||||
|
||||
pColl = sqlite3FindCollSeq(db, (u8)enc, zName, strlen(zName), 1);
|
||||
if( 0==pColl ){
|
||||
rc = SQLITE_NOMEM;
|
||||
}else{
|
||||
pColl->xCmp = xCompare;
|
||||
pColl->pUser = pCtx;
|
||||
pColl->enc = enc;
|
||||
}
|
||||
sqlite3Error(db, rc, 0);
|
||||
return rc;
|
||||
int rc;
|
||||
assert( !sqlite3MallocFailed() );
|
||||
rc = createCollation(db, zName, enc, pCtx, xCompare);
|
||||
return sqlite3ApiExit(db, rc);
|
||||
}
|
||||
|
||||
#ifndef SQLITE_OMIT_UTF16
|
||||
@ -950,15 +990,15 @@ int sqlite3_create_collation16(
|
||||
void* pCtx,
|
||||
int(*xCompare)(void*,int,const void*,int,const void*)
|
||||
){
|
||||
char const *zName8;
|
||||
sqlite3_value *pTmp;
|
||||
if( sqlite3SafetyCheck(db) ){
|
||||
return SQLITE_MISUSE;
|
||||
int rc = SQLITE_OK;
|
||||
char *zName8;
|
||||
assert( !sqlite3MallocFailed() );
|
||||
zName8 = sqlite3utf16to8(zName, -1);
|
||||
if( zName8 ){
|
||||
rc = createCollation(db, zName8, enc, pCtx, xCompare);
|
||||
sqliteFree(zName8);
|
||||
}
|
||||
pTmp = sqlite3GetTransientValue(db);
|
||||
sqlite3ValueSetStr(pTmp, -1, zName, SQLITE_UTF16NATIVE, SQLITE_STATIC);
|
||||
zName8 = sqlite3ValueText(pTmp, SQLITE_UTF8);
|
||||
return sqlite3_create_collation(db, zName8, enc, pCtx, xCompare);
|
||||
return sqlite3ApiExit(db, rc);
|
||||
}
|
||||
#endif /* SQLITE_OMIT_UTF16 */
|
||||
|
||||
@ -1002,37 +1042,11 @@ int sqlite3_collation_needed16(
|
||||
|
||||
#ifndef SQLITE_OMIT_GLOBALRECOVER
|
||||
/*
|
||||
** This function is called to recover from a malloc failure that occured
|
||||
** within SQLite.
|
||||
**
|
||||
** This function is *not* threadsafe. Calling this from within a threaded
|
||||
** application when threads other than the caller have used SQLite is
|
||||
** dangerous and will almost certainly result in malfunctions.
|
||||
** This function is now an anachronism. It used to be used to recover from a
|
||||
** malloc() failure, but SQLite now does this automatically.
|
||||
*/
|
||||
int sqlite3_global_recover(){
|
||||
int rc = SQLITE_OK;
|
||||
|
||||
if( sqlite3_malloc_failed ){
|
||||
sqlite3 *db;
|
||||
int i;
|
||||
sqlite3_malloc_failed = 0;
|
||||
for(db=pDbList; db; db=db->pNext ){
|
||||
sqlite3ExpirePreparedStatements(db);
|
||||
for(i=0; i<db->nDb; i++){
|
||||
Btree *pBt = db->aDb[i].pBt;
|
||||
if( pBt && (rc=sqlite3BtreeReset(pBt)) ){
|
||||
goto recover_out;
|
||||
}
|
||||
}
|
||||
db->autoCommit = 1;
|
||||
}
|
||||
}
|
||||
|
||||
recover_out:
|
||||
if( rc!=SQLITE_OK ){
|
||||
sqlite3_malloc_failed = 1;
|
||||
}
|
||||
return rc;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -1058,3 +1072,44 @@ int sqlite3Corrupt(void){
|
||||
return SQLITE_CORRUPT;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef SQLITE_OMIT_SHARED_CACHE
|
||||
/*
|
||||
** Enable or disable the shared pager and schema features for the
|
||||
** current thread.
|
||||
**
|
||||
** This routine should only be called when there are no open
|
||||
** database connections.
|
||||
*/
|
||||
int sqlite3_enable_shared_cache(int enable){
|
||||
ThreadData *pTd = sqlite3ThreadData();
|
||||
if( pTd ){
|
||||
/* It is only legal to call sqlite3_enable_shared_cache() when there
|
||||
** are no currently open b-trees that were opened by the calling thread.
|
||||
** This condition is only easy to detect if the shared-cache were
|
||||
** previously enabled (and is being disabled).
|
||||
*/
|
||||
if( pTd->pBtree && !enable ){
|
||||
assert( pTd->useSharedData );
|
||||
return SQLITE_MISUSE;
|
||||
}
|
||||
|
||||
pTd->useSharedData = enable;
|
||||
sqlite3ReleaseThreadData();
|
||||
}
|
||||
return sqlite3ApiExit(0, SQLITE_OK);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
** This is a convenience routine that makes sure that all thread-specific
|
||||
** data for this thread has been deallocated.
|
||||
*/
|
||||
void sqlite3_thread_cleanup(void){
|
||||
ThreadData *pTd = sqlite3OsThreadSpecificData(0);
|
||||
if( pTd ){
|
||||
memset(pTd, 0, sizeof(*pTd));
|
||||
sqlite3OsThreadSpecificData(-1);
|
||||
}
|
||||
}
|
||||
|
||||
@ -11,111 +11,111 @@ const char *const sqlite3OpcodeNames[] = { "?",
|
||||
/* 7 */ "RowKey",
|
||||
/* 8 */ "OpenWrite",
|
||||
/* 9 */ "If",
|
||||
/* 10 */ "ToInt",
|
||||
/* 11 */ "Pop",
|
||||
/* 12 */ "CollSeq",
|
||||
/* 13 */ "OpenRead",
|
||||
/* 14 */ "Expire",
|
||||
/* 15 */ "AutoCommit",
|
||||
/* 16 */ "IntegrityCk",
|
||||
/* 10 */ "Pop",
|
||||
/* 11 */ "CollSeq",
|
||||
/* 12 */ "OpenRead",
|
||||
/* 13 */ "Expire",
|
||||
/* 14 */ "AutoCommit",
|
||||
/* 15 */ "IntegrityCk",
|
||||
/* 16 */ "Not",
|
||||
/* 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",
|
||||
/* 22 */ "IfMemNeg",
|
||||
/* 23 */ "Variable",
|
||||
/* 24 */ "String",
|
||||
/* 25 */ "RealAffinity",
|
||||
/* 26 */ "ParseSchema",
|
||||
/* 27 */ "Close",
|
||||
/* 28 */ "CreateIndex",
|
||||
/* 29 */ "IsUnique",
|
||||
/* 30 */ "IdxIsNull",
|
||||
/* 31 */ "NotFound",
|
||||
/* 32 */ "Int64",
|
||||
/* 33 */ "MustBeInt",
|
||||
/* 34 */ "Halt",
|
||||
/* 35 */ "Rowid",
|
||||
/* 36 */ "IdxLT",
|
||||
/* 37 */ "AddImm",
|
||||
/* 38 */ "Statement",
|
||||
/* 39 */ "RowData",
|
||||
/* 40 */ "MemMax",
|
||||
/* 41 */ "Push",
|
||||
/* 42 */ "NotExists",
|
||||
/* 43 */ "MemIncr",
|
||||
/* 44 */ "Gosub",
|
||||
/* 45 */ "Integer",
|
||||
/* 46 */ "MemInt",
|
||||
/* 47 */ "Prev",
|
||||
/* 48 */ "CreateTable",
|
||||
/* 49 */ "Last",
|
||||
/* 50 */ "IdxRowid",
|
||||
/* 51 */ "MakeIdxRec",
|
||||
/* 52 */ "ResetCount",
|
||||
/* 53 */ "FifoWrite",
|
||||
/* 54 */ "Callback",
|
||||
/* 55 */ "ContextPush",
|
||||
/* 56 */ "DropTrigger",
|
||||
/* 57 */ "DropIndex",
|
||||
/* 58 */ "IdxGE",
|
||||
/* 59 */ "Or",
|
||||
/* 60 */ "And",
|
||||
/* 61 */ "IdxDelete",
|
||||
/* 62 */ "Vacuum",
|
||||
/* 63 */ "MoveLe",
|
||||
/* 64 */ "IsNull",
|
||||
/* 65 */ "NotNull",
|
||||
/* 66 */ "Ne",
|
||||
/* 67 */ "Eq",
|
||||
/* 68 */ "Gt",
|
||||
/* 69 */ "Le",
|
||||
/* 70 */ "Lt",
|
||||
/* 71 */ "Ge",
|
||||
/* 72 */ "IfNot",
|
||||
/* 73 */ "BitAnd",
|
||||
/* 74 */ "BitOr",
|
||||
/* 75 */ "ShiftLeft",
|
||||
/* 76 */ "ShiftRight",
|
||||
/* 77 */ "Add",
|
||||
/* 78 */ "Subtract",
|
||||
/* 79 */ "Multiply",
|
||||
/* 80 */ "Divide",
|
||||
/* 81 */ "Remainder",
|
||||
/* 82 */ "Concat",
|
||||
/* 83 */ "Negative",
|
||||
/* 84 */ "DropTable",
|
||||
/* 85 */ "BitNot",
|
||||
/* 86 */ "String8",
|
||||
/* 87 */ "MakeRecord",
|
||||
/* 88 */ "Delete",
|
||||
/* 89 */ "AggFinal",
|
||||
/* 90 */ "Dup",
|
||||
/* 91 */ "Goto",
|
||||
/* 92 */ "TableLock",
|
||||
/* 93 */ "FifoRead",
|
||||
/* 94 */ "Clear",
|
||||
/* 95 */ "IdxGT",
|
||||
/* 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",
|
||||
/* 100 */ "SetNumColumns",
|
||||
/* 101 */ "AbsValue",
|
||||
/* 102 */ "Transaction",
|
||||
/* 103 */ "ContextPop",
|
||||
/* 104 */ "Next",
|
||||
/* 105 */ "IdxInsert",
|
||||
/* 106 */ "Distinct",
|
||||
/* 107 */ "Insert",
|
||||
/* 108 */ "Destroy",
|
||||
/* 109 */ "ReadCookie",
|
||||
/* 110 */ "ForceInt",
|
||||
/* 111 */ "LoadAnalysis",
|
||||
/* 112 */ "OpenVirtual",
|
||||
/* 113 */ "Explain",
|
||||
/* 114 */ "IfMemZero",
|
||||
/* 115 */ "OpenPseudo",
|
||||
/* 116 */ "Null",
|
||||
/* 117 */ "Blob",
|
||||
@ -125,16 +125,23 @@ const char *const sqlite3OpcodeNames[] = { "?",
|
||||
/* 121 */ "MemMove",
|
||||
/* 122 */ "MemNull",
|
||||
/* 123 */ "Found",
|
||||
/* 124 */ "NullRow",
|
||||
/* 125 */ "NotUsed_125",
|
||||
/* 126 */ "NotUsed_126",
|
||||
/* 124 */ "Real",
|
||||
/* 125 */ "HexBlob",
|
||||
/* 126 */ "NullRow",
|
||||
/* 127 */ "NotUsed_127",
|
||||
/* 128 */ "NotUsed_128",
|
||||
/* 129 */ "NotUsed_129",
|
||||
/* 130 */ "NotUsed_130",
|
||||
/* 131 */ "NotUsed_131",
|
||||
/* 132 */ "NotUsed_132",
|
||||
/* 133 */ "Real",
|
||||
/* 134 */ "HexBlob",
|
||||
/* 133 */ "NotUsed_133",
|
||||
/* 134 */ "NotUsed_134",
|
||||
/* 135 */ "NotUsed_135",
|
||||
/* 136 */ "NotUsed_136",
|
||||
/* 137 */ "ToText",
|
||||
/* 138 */ "ToBlob",
|
||||
/* 139 */ "ToNumeric",
|
||||
/* 140 */ "ToInt",
|
||||
/* 141 */ "ToReal",
|
||||
};
|
||||
#endif
|
||||
|
||||
@ -1,149 +1,159 @@
|
||||
/* Automatically generated. Do not edit */
|
||||
/* See the mkopcodeh.awk script for details */
|
||||
#define OP_MemLoad 1
|
||||
#define OP_HexBlob 134 /* same as TK_BLOB */
|
||||
#define OP_HexBlob 125 /* same as TK_BLOB */
|
||||
#define OP_Column 2
|
||||
#define OP_SetCookie 3
|
||||
#define OP_IfMemPos 4
|
||||
#define OP_Real 133 /* same as TK_FLOAT */
|
||||
#define OP_Real 124 /* same as TK_FLOAT */
|
||||
#define OP_Sequence 5
|
||||
#define OP_MoveGt 6
|
||||
#define OP_Ge 80 /* same as TK_GE */
|
||||
#define OP_Ge 71 /* same as TK_GE */
|
||||
#define OP_RowKey 7
|
||||
#define OP_Eq 76 /* same as TK_EQ */
|
||||
#define OP_Eq 67 /* same as TK_EQ */
|
||||
#define OP_OpenWrite 8
|
||||
#define OP_NotNull 74 /* same as TK_NOTNULL */
|
||||
#define OP_NotNull 65 /* 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_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_ToInt 140 /* same as TK_TO_INT */
|
||||
#define OP_String8 86 /* same as TK_STRING */
|
||||
#define OP_Pop 10
|
||||
#define OP_CollSeq 11
|
||||
#define OP_OpenRead 12
|
||||
#define OP_Expire 13
|
||||
#define OP_AutoCommit 14
|
||||
#define OP_Gt 68 /* same as TK_GT */
|
||||
#define OP_IntegrityCk 15
|
||||
#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_And 60 /* same as TK_AND */
|
||||
#define OP_Subtract 78 /* same as TK_MINUS */
|
||||
#define OP_Noop 19
|
||||
#define OP_Return 20
|
||||
#define OP_Remainder 90 /* same as TK_REM */
|
||||
#define OP_Remainder 81 /* 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_Multiply 79 /* same as TK_STAR */
|
||||
#define OP_IfMemNeg 22
|
||||
#define OP_Variable 23
|
||||
#define OP_String 24
|
||||
#define OP_RealAffinity 25
|
||||
#define OP_ParseSchema 26
|
||||
#define OP_Close 27
|
||||
#define OP_CreateIndex 28
|
||||
#define OP_IsUnique 29
|
||||
#define OP_IdxIsNull 30
|
||||
#define OP_NotFound 31
|
||||
#define OP_Int64 32
|
||||
#define OP_MustBeInt 33
|
||||
#define OP_Halt 34
|
||||
#define OP_Rowid 35
|
||||
#define OP_IdxLT 36
|
||||
#define OP_AddImm 37
|
||||
#define OP_Statement 38
|
||||
#define OP_RowData 39
|
||||
#define OP_MemMax 40
|
||||
#define OP_Push 41
|
||||
#define OP_Or 59 /* same as TK_OR */
|
||||
#define OP_NotExists 42
|
||||
#define OP_MemIncr 43
|
||||
#define OP_Gosub 44
|
||||
#define OP_Divide 80 /* same as TK_SLASH */
|
||||
#define OP_Integer 45
|
||||
#define OP_ToNumeric 139 /* same as TK_TO_NUMERIC*/
|
||||
#define OP_MemInt 46
|
||||
#define OP_Prev 47
|
||||
#define OP_Concat 82 /* same as TK_CONCAT */
|
||||
#define OP_BitAnd 73 /* same as TK_BITAND */
|
||||
#define OP_CreateTable 48
|
||||
#define OP_Last 49
|
||||
#define OP_IsNull 64 /* same as TK_ISNULL */
|
||||
#define OP_IdxRowid 50
|
||||
#define OP_MakeIdxRec 51
|
||||
#define OP_ShiftRight 76 /* same as TK_RSHIFT */
|
||||
#define OP_ResetCount 52
|
||||
#define OP_FifoWrite 53
|
||||
#define OP_Callback 54
|
||||
#define OP_ContextPush 55
|
||||
#define OP_DropTrigger 56
|
||||
#define OP_DropIndex 57
|
||||
#define OP_IdxGE 58
|
||||
#define OP_IdxDelete 61
|
||||
#define OP_Vacuum 62
|
||||
#define OP_MoveLe 63
|
||||
#define OP_IfNot 72
|
||||
#define OP_DropTable 84
|
||||
#define OP_MakeRecord 87
|
||||
#define OP_ToBlob 138 /* same as TK_TO_BLOB */
|
||||
#define OP_Delete 88
|
||||
#define OP_AggFinal 89
|
||||
#define OP_ShiftLeft 75 /* same as TK_LSHIFT */
|
||||
#define OP_Dup 90
|
||||
#define OP_Goto 91
|
||||
#define OP_TableLock 92
|
||||
#define OP_FifoRead 93
|
||||
#define OP_Clear 94
|
||||
#define OP_IdxGT 95
|
||||
#define OP_MoveLt 96
|
||||
#define OP_Le 78 /* same as TK_LE */
|
||||
#define OP_Le 69 /* 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_ToText 137 /* same as TK_TO_TEXT */
|
||||
#define OP_Not 16 /* same as TK_NOT */
|
||||
#define OP_ToReal 141 /* same as TK_TO_REAL */
|
||||
#define OP_SetNumColumns 100
|
||||
#define OP_AbsValue 101
|
||||
#define OP_Transaction 102
|
||||
#define OP_Negative 83 /* same as TK_UMINUS */
|
||||
#define OP_Ne 66 /* same as TK_NE */
|
||||
#define OP_ContextPop 103
|
||||
#define OP_BitOr 74 /* same as TK_BITOR */
|
||||
#define OP_Next 104
|
||||
#define OP_IdxInsert 105
|
||||
#define OP_Distinct 106
|
||||
#define OP_Lt 70 /* same as TK_LT */
|
||||
#define OP_Insert 107
|
||||
#define OP_Destroy 108
|
||||
#define OP_ReadCookie 109
|
||||
#define OP_ForceInt 110
|
||||
#define OP_LoadAnalysis 111
|
||||
#define OP_OpenVirtual 112
|
||||
#define OP_Explain 113
|
||||
#define OP_IfMemZero 114
|
||||
#define OP_OpenPseudo 115
|
||||
#define OP_Null 116
|
||||
#define OP_Blob 117
|
||||
#define OP_Add 86 /* same as TK_PLUS */
|
||||
#define OP_Add 77 /* 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_BitNot 85 /* same as TK_BITNOT */
|
||||
#define OP_MemMove 121
|
||||
#define OP_MemNull 122
|
||||
#define OP_Found 123
|
||||
#define OP_NullRow 124
|
||||
#define OP_NullRow 126
|
||||
|
||||
/* The following opcode values are never used */
|
||||
#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 OP_NotUsed_133 133
|
||||
#define OP_NotUsed_134 134
|
||||
#define OP_NotUsed_135 135
|
||||
#define OP_NotUsed_136 136
|
||||
|
||||
#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
|
||||
/* Opcodes that are guaranteed to never push a value onto the stack
|
||||
** contain a 1 their corresponding position of the following mask
|
||||
** set. See the opcodeNoPush() function in vdbeaux.c */
|
||||
#define NOPUSH_MASK_0 0x7f58
|
||||
#define NOPUSH_MASK_1 0xee5b
|
||||
#define NOPUSH_MASK_2 0x9f76
|
||||
#define NOPUSH_MASK_3 0xfff2
|
||||
#define NOPUSH_MASK_4 0xffff
|
||||
#define NOPUSH_MASK_5 0xdb3b
|
||||
#define NOPUSH_MASK_6 0xcfdf
|
||||
#define NOPUSH_MASK_7 0x49cd
|
||||
#define NOPUSH_MASK_8 0x3e00
|
||||
#define NOPUSH_MASK_9 0x0000
|
||||
|
||||
92
mozilla/db/sqlite3/src/os.c
Normal file
92
mozilla/db/sqlite3/src/os.c
Normal file
@ -0,0 +1,92 @@
|
||||
/*
|
||||
** 2005 November 29
|
||||
**
|
||||
** 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 OS interface code that is common to all
|
||||
** architectures.
|
||||
*/
|
||||
#define _SQLITE_OS_C_ 1
|
||||
#include "sqliteInt.h"
|
||||
#include "os.h"
|
||||
|
||||
/*
|
||||
** The following routines are convenience wrappers around methods
|
||||
** of the OsFile object. This is mostly just syntactic sugar. All
|
||||
** of this would be completely automatic if SQLite were coded using
|
||||
** C++ instead of plain old C.
|
||||
*/
|
||||
int sqlite3OsClose(OsFile **pId){
|
||||
OsFile *id;
|
||||
if( pId!=0 && (id = *pId)!=0 ){
|
||||
return id->pMethod->xClose(pId);
|
||||
}else{
|
||||
return SQLITE_OK;
|
||||
}
|
||||
}
|
||||
int sqlite3OsOpenDirectory(OsFile *id, const char *zName){
|
||||
return id->pMethod->xOpenDirectory(id, zName);
|
||||
}
|
||||
int sqlite3OsRead(OsFile *id, void *pBuf, int amt){
|
||||
return id->pMethod->xRead(id, pBuf, amt);
|
||||
}
|
||||
int sqlite3OsWrite(OsFile *id, const void *pBuf, int amt){
|
||||
return id->pMethod->xWrite(id, pBuf, amt);
|
||||
}
|
||||
int sqlite3OsSeek(OsFile *id, i64 offset){
|
||||
return id->pMethod->xSeek(id, offset);
|
||||
}
|
||||
int sqlite3OsTruncate(OsFile *id, i64 size){
|
||||
return id->pMethod->xTruncate(id, size);
|
||||
}
|
||||
int sqlite3OsSync(OsFile *id, int fullsync){
|
||||
return id->pMethod->xSync(id, fullsync);
|
||||
}
|
||||
void sqlite3OsSetFullSync(OsFile *id, int value){
|
||||
id->pMethod->xSetFullSync(id, value);
|
||||
}
|
||||
#if defined(SQLITE_TEST) || defined(SQLITE_DEBUG)
|
||||
/* This method is currently only used while interactively debugging the
|
||||
** pager. More specificly, it can only be used when sqlite3DebugPrintf() is
|
||||
** included in the build. */
|
||||
int sqlite3OsFileHandle(OsFile *id){
|
||||
return id->pMethod->xFileHandle(id);
|
||||
}
|
||||
#endif
|
||||
int sqlite3OsFileSize(OsFile *id, i64 *pSize){
|
||||
return id->pMethod->xFileSize(id, pSize);
|
||||
}
|
||||
int sqlite3OsLock(OsFile *id, int lockType){
|
||||
return id->pMethod->xLock(id, lockType);
|
||||
}
|
||||
int sqlite3OsUnlock(OsFile *id, int lockType){
|
||||
return id->pMethod->xUnlock(id, lockType);
|
||||
}
|
||||
int sqlite3OsLockState(OsFile *id){
|
||||
return id->pMethod->xLockState(id);
|
||||
}
|
||||
int sqlite3OsCheckReservedLock(OsFile *id){
|
||||
return id->pMethod->xCheckReservedLock(id);
|
||||
}
|
||||
|
||||
#ifdef SQLITE_ENABLE_REDEF_IO
|
||||
/*
|
||||
** A function to return a pointer to the virtual function table.
|
||||
** This routine really does not accomplish very much since the
|
||||
** virtual function table is a global variable and anybody who
|
||||
** can call this function can just as easily access the variable
|
||||
** for themselves. Nevertheless, we include this routine for
|
||||
** backwards compatibility with an earlier redefinable I/O
|
||||
** interface design.
|
||||
*/
|
||||
struct sqlite3OsVtbl *sqlite3_os_switch(void){
|
||||
return &sqlite3Os;
|
||||
}
|
||||
#endif
|
||||
@ -18,12 +18,10 @@
|
||||
#define _SQLITE_OS_H_
|
||||
|
||||
/*
|
||||
** Figure out if we are dealing with Unix, Windows or MacOS.
|
||||
**
|
||||
** N.B. MacOS means Mac Classic (or Carbon). Treat Darwin (OS X) as Unix.
|
||||
** The MacOS build is designed to use CodeWarrior (tested with v8)
|
||||
** Figure out if we are dealing with Unix, Windows, or some other
|
||||
** operating system.
|
||||
*/
|
||||
#if !defined(OS_UNIX) && !defined(OS_TEST) && !defined(OS_OTHER)
|
||||
#if !defined(OS_UNIX) && !defined(OS_OTHER)
|
||||
# define OS_OTHER 0
|
||||
# ifndef OS_WIN
|
||||
# if defined(_WIN32) || defined(WIN32) || defined(__CYGWIN__) || defined(__MINGW32__) || defined(__BORLANDC__)
|
||||
@ -49,28 +47,15 @@
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Invoke the appropriate operating-system specific header file.
|
||||
*/
|
||||
#if OS_TEST
|
||||
# include "os_test.h"
|
||||
#endif
|
||||
#if OS_UNIX
|
||||
# include "os_unix.h"
|
||||
#endif
|
||||
#if OS_WIN
|
||||
# include "os_win.h"
|
||||
#endif
|
||||
#if OS_OS2
|
||||
# include "os_os2.h"
|
||||
#endif
|
||||
|
||||
/* os_other.c and os_other.h are not delivered with SQLite. These files
|
||||
** are place-holders that can be filled in by third-party developers to
|
||||
** implement backends to their on proprietary operating systems.
|
||||
/*
|
||||
** Define the maximum size of a temporary filename
|
||||
*/
|
||||
#if OS_OTHER
|
||||
# include "os_other.h"
|
||||
#if OS_WIN
|
||||
# include <windows.h>
|
||||
# define SQLITE_TEMPNAME_SIZE (MAX_PATH+50)
|
||||
#else
|
||||
# define SQLITE_TEMPNAME_SIZE 200
|
||||
#endif
|
||||
|
||||
/* If the SET_FULLSYNC macro is not defined above, then make it
|
||||
@ -93,6 +78,104 @@
|
||||
# define TEMP_FILE_PREFIX "sqlite_"
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Define the interfaces for Unix and for Windows.
|
||||
*/
|
||||
#if OS_UNIX
|
||||
#define sqlite3OsOpenReadWrite sqlite3UnixOpenReadWrite
|
||||
#define sqlite3OsOpenExclusive sqlite3UnixOpenExclusive
|
||||
#define sqlite3OsOpenReadOnly sqlite3UnixOpenReadOnly
|
||||
#define sqlite3OsDelete sqlite3UnixDelete
|
||||
#define sqlite3OsFileExists sqlite3UnixFileExists
|
||||
#define sqlite3OsFullPathname sqlite3UnixFullPathname
|
||||
#define sqlite3OsIsDirWritable sqlite3UnixIsDirWritable
|
||||
#define sqlite3OsSyncDirectory sqlite3UnixSyncDirectory
|
||||
#define sqlite3OsTempFileName sqlite3UnixTempFileName
|
||||
#define sqlite3OsRandomSeed sqlite3UnixRandomSeed
|
||||
#define sqlite3OsSleep sqlite3UnixSleep
|
||||
#define sqlite3OsCurrentTime sqlite3UnixCurrentTime
|
||||
#define sqlite3OsEnterMutex sqlite3UnixEnterMutex
|
||||
#define sqlite3OsLeaveMutex sqlite3UnixLeaveMutex
|
||||
#define sqlite3OsInMutex sqlite3UnixInMutex
|
||||
#define sqlite3OsThreadSpecificData sqlite3UnixThreadSpecificData
|
||||
#define sqlite3OsMalloc sqlite3GenericMalloc
|
||||
#define sqlite3OsRealloc sqlite3GenericRealloc
|
||||
#define sqlite3OsFree sqlite3GenericFree
|
||||
#define sqlite3OsAllocationSize sqlite3GenericAllocationSize
|
||||
#endif
|
||||
#if OS_WIN
|
||||
#define sqlite3OsOpenReadWrite sqlite3WinOpenReadWrite
|
||||
#define sqlite3OsOpenExclusive sqlite3WinOpenExclusive
|
||||
#define sqlite3OsOpenReadOnly sqlite3WinOpenReadOnly
|
||||
#define sqlite3OsDelete sqlite3WinDelete
|
||||
#define sqlite3OsFileExists sqlite3WinFileExists
|
||||
#define sqlite3OsFullPathname sqlite3WinFullPathname
|
||||
#define sqlite3OsIsDirWritable sqlite3WinIsDirWritable
|
||||
#define sqlite3OsSyncDirectory sqlite3WinSyncDirectory
|
||||
#define sqlite3OsTempFileName sqlite3WinTempFileName
|
||||
#define sqlite3OsRandomSeed sqlite3WinRandomSeed
|
||||
#define sqlite3OsSleep sqlite3WinSleep
|
||||
#define sqlite3OsCurrentTime sqlite3WinCurrentTime
|
||||
#define sqlite3OsEnterMutex sqlite3WinEnterMutex
|
||||
#define sqlite3OsLeaveMutex sqlite3WinLeaveMutex
|
||||
#define sqlite3OsInMutex sqlite3WinInMutex
|
||||
#define sqlite3OsThreadSpecificData sqlite3WinThreadSpecificData
|
||||
#define sqlite3OsMalloc sqlite3GenericMalloc
|
||||
#define sqlite3OsRealloc sqlite3GenericRealloc
|
||||
#define sqlite3OsFree sqlite3GenericFree
|
||||
#define sqlite3OsAllocationSize sqlite3GenericAllocationSize
|
||||
#endif
|
||||
|
||||
/*
|
||||
** If using an alternative OS interface, then we must have an "os_other.h"
|
||||
** header file available for that interface. Presumably the "os_other.h"
|
||||
** header file contains #defines similar to those above.
|
||||
*/
|
||||
#if OS_OTHER
|
||||
# include "os_other.h"
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/*
|
||||
** Forward declarations
|
||||
*/
|
||||
typedef struct OsFile OsFile;
|
||||
typedef struct IoMethod IoMethod;
|
||||
|
||||
/*
|
||||
** An instance of the following structure contains pointers to all
|
||||
** methods on an OsFile object.
|
||||
*/
|
||||
struct IoMethod {
|
||||
int (*xClose)(OsFile**);
|
||||
int (*xOpenDirectory)(OsFile*, const char*);
|
||||
int (*xRead)(OsFile*, void*, int amt);
|
||||
int (*xWrite)(OsFile*, const void*, int amt);
|
||||
int (*xSeek)(OsFile*, i64 offset);
|
||||
int (*xTruncate)(OsFile*, i64 size);
|
||||
int (*xSync)(OsFile*, int);
|
||||
void (*xSetFullSync)(OsFile *id, int setting);
|
||||
int (*xFileHandle)(OsFile *id);
|
||||
int (*xFileSize)(OsFile*, i64 *pSize);
|
||||
int (*xLock)(OsFile*, int);
|
||||
int (*xUnlock)(OsFile*, int);
|
||||
int (*xLockState)(OsFile *id);
|
||||
int (*xCheckReservedLock)(OsFile *id);
|
||||
};
|
||||
|
||||
/*
|
||||
** The OsFile object describes an open disk file in an OS-dependent way.
|
||||
** The version of OsFile defined here is a generic version. Each OS
|
||||
** implementation defines its own subclass of this structure that contains
|
||||
** additional information needed to handle file I/O. But the pMethod
|
||||
** entry (pointing to the virtual function table) always occurs first
|
||||
** so that we can always find the appropriate methods.
|
||||
*/
|
||||
struct OsFile {
|
||||
IoMethod const *pMethod;
|
||||
};
|
||||
|
||||
/*
|
||||
** The following values may be passed as the second argument to
|
||||
** sqlite3OsLock(). The various locks exhibit the following semantics:
|
||||
@ -147,8 +230,10 @@
|
||||
** a random byte is selected for a shared lock. The pool of bytes for
|
||||
** shared locks begins at SHARED_FIRST.
|
||||
**
|
||||
** These #defines are available in os.h so that Unix can use the same
|
||||
** byte ranges for locking. This leaves open the possiblity of having
|
||||
** These #defines are available in sqlite_aux.h so that adaptors for
|
||||
** connecting SQLite to other operating systems can use the same byte
|
||||
** ranges for locking. In particular, the same locking strategy and
|
||||
** byte ranges are used for Unix. This leaves open the possiblity of having
|
||||
** clients on win95, winNT, and unix all talking to the same shared file
|
||||
** and all locking correctly. To do so would require that samba (or whatever
|
||||
** tool is being used for file sharing) implements locks correctly between
|
||||
@ -182,36 +267,181 @@ extern unsigned int sqlite3_pending_byte;
|
||||
#define SHARED_FIRST (PENDING_BYTE+2)
|
||||
#define SHARED_SIZE 510
|
||||
|
||||
|
||||
int sqlite3OsDelete(const char*);
|
||||
int sqlite3OsFileExists(const char*);
|
||||
int sqlite3OsOpenReadWrite(const char*, OsFile*, int*);
|
||||
int sqlite3OsOpenExclusive(const char*, OsFile*, int);
|
||||
int sqlite3OsOpenReadOnly(const char*, OsFile*);
|
||||
int sqlite3OsOpenDirectory(const char*, OsFile*);
|
||||
int sqlite3OsSyncDirectory(const char*);
|
||||
int sqlite3OsTempFileName(char*);
|
||||
int sqlite3OsIsDirWritable(char*);
|
||||
int sqlite3OsClose(OsFile*);
|
||||
/*
|
||||
** Prototypes for operating system interface routines.
|
||||
*/
|
||||
int sqlite3OsClose(OsFile**);
|
||||
int sqlite3OsOpenDirectory(OsFile*, const char*);
|
||||
int sqlite3OsRead(OsFile*, void*, int amt);
|
||||
int sqlite3OsWrite(OsFile*, const void*, int amt);
|
||||
int sqlite3OsSeek(OsFile*, i64 offset);
|
||||
int sqlite3OsSync(OsFile*, int);
|
||||
int sqlite3OsTruncate(OsFile*, i64 size);
|
||||
int sqlite3OsSync(OsFile*, int);
|
||||
void sqlite3OsSetFullSync(OsFile *id, int setting);
|
||||
int sqlite3OsFileHandle(OsFile *id);
|
||||
int sqlite3OsFileSize(OsFile*, i64 *pSize);
|
||||
char *sqlite3OsFullPathname(const char*);
|
||||
int sqlite3OsLock(OsFile*, int);
|
||||
int sqlite3OsUnlock(OsFile*, int);
|
||||
int sqlite3OsLockState(OsFile *id);
|
||||
int sqlite3OsCheckReservedLock(OsFile *id);
|
||||
|
||||
|
||||
/* The interface for file I/O is above. Other miscellaneous functions
|
||||
** are below */
|
||||
|
||||
int sqlite3OsOpenReadWrite(const char*, OsFile**, int*);
|
||||
int sqlite3OsOpenExclusive(const char*, OsFile**, int);
|
||||
int sqlite3OsOpenReadOnly(const char*, OsFile**);
|
||||
int sqlite3OsDelete(const char*);
|
||||
int sqlite3OsFileExists(const char*);
|
||||
char *sqlite3OsFullPathname(const char*);
|
||||
int sqlite3OsIsDirWritable(char*);
|
||||
int sqlite3OsSyncDirectory(const char*);
|
||||
int sqlite3OsTempFileName(char*);
|
||||
int sqlite3OsRandomSeed(char*);
|
||||
int sqlite3OsSleep(int ms);
|
||||
int sqlite3OsCurrentTime(double*);
|
||||
void sqlite3OsEnterMutex(void);
|
||||
void sqlite3OsLeaveMutex(void);
|
||||
int sqlite3OsInMutex(int);
|
||||
ThreadData *sqlite3OsThreadSpecificData(int);
|
||||
void *sqlite3OsMalloc(int);
|
||||
void *sqlite3OsRealloc(void *, int);
|
||||
void sqlite3OsFree(void *);
|
||||
int sqlite3OsAllocationSize(void *);
|
||||
|
||||
/*
|
||||
** If the SQLITE_ENABLE_REDEF_IO macro is defined, then the OS-layer
|
||||
** interface routines are not called directly but are invoked using
|
||||
** pointers to functions. This allows the implementation of various
|
||||
** OS-layer interface routines to be modified at run-time. There are
|
||||
** obscure but legitimate reasons for wanting to do this. But for
|
||||
** most users, a direct call to the underlying interface is preferable
|
||||
** so the the redefinable I/O interface is turned off by default.
|
||||
*/
|
||||
#ifdef SQLITE_ENABLE_REDEF_IO
|
||||
|
||||
/*
|
||||
** When redefinable I/O is enabled, a single global instance of the
|
||||
** following structure holds pointers to the routines that SQLite
|
||||
** uses to talk with the underlying operating system. Modify this
|
||||
** structure (before using any SQLite API!) to accomodate perculiar
|
||||
** operating system interfaces or behaviors.
|
||||
*/
|
||||
struct sqlite3OsVtbl {
|
||||
int (*xOpenReadWrite)(const char*, OsFile**, int*);
|
||||
int (*xOpenExclusive)(const char*, OsFile**, int);
|
||||
int (*xOpenReadOnly)(const char*, OsFile**);
|
||||
|
||||
int (*xDelete)(const char*);
|
||||
int (*xFileExists)(const char*);
|
||||
char *(*xFullPathname)(const char*);
|
||||
int (*xIsDirWritable)(char*);
|
||||
int (*xSyncDirectory)(const char*);
|
||||
int (*xTempFileName)(char*);
|
||||
|
||||
int (*xRandomSeed)(char*);
|
||||
int (*xSleep)(int ms);
|
||||
int (*xCurrentTime)(double*);
|
||||
|
||||
void (*xEnterMutex)(void);
|
||||
void (*xLeaveMutex)(void);
|
||||
int (*xInMutex)(int);
|
||||
ThreadData *(*xThreadSpecificData)(int);
|
||||
|
||||
void *(*xMalloc)(int);
|
||||
void *(*xRealloc)(void *, int);
|
||||
void (*xFree)(void *);
|
||||
int (*xAllocationSize)(void *);
|
||||
};
|
||||
|
||||
/* Macro used to comment out routines that do not exists when there is
|
||||
** no disk I/O
|
||||
*/
|
||||
#ifdef SQLITE_OMIT_DISKIO
|
||||
# define IF_DISKIO(X) 0
|
||||
#else
|
||||
# define IF_DISKIO(X) X
|
||||
#endif
|
||||
|
||||
#ifdef _SQLITE_OS_C_
|
||||
/*
|
||||
** The os.c file implements the global virtual function table.
|
||||
*/
|
||||
struct sqlite3OsVtbl sqlite3Os = {
|
||||
IF_DISKIO( sqlite3OsOpenReadWrite ),
|
||||
IF_DISKIO( sqlite3OsOpenExclusive ),
|
||||
IF_DISKIO( sqlite3OsOpenReadOnly ),
|
||||
IF_DISKIO( sqlite3OsDelete ),
|
||||
IF_DISKIO( sqlite3OsFileExists ),
|
||||
IF_DISKIO( sqlite3OsFullPathname ),
|
||||
IF_DISKIO( sqlite3OsIsDirWritable ),
|
||||
IF_DISKIO( sqlite3OsSyncDirectory ),
|
||||
IF_DISKIO( sqlite3OsTempFileName ),
|
||||
sqlite3OsRandomSeed,
|
||||
sqlite3OsSleep,
|
||||
sqlite3OsCurrentTime,
|
||||
sqlite3OsEnterMutex,
|
||||
sqlite3OsLeaveMutex,
|
||||
sqlite3OsInMutex,
|
||||
sqlite3OsThreadSpecificData,
|
||||
sqlite3OsMalloc,
|
||||
sqlite3OsRealloc,
|
||||
sqlite3OsFree,
|
||||
sqlite3OsAllocationSize
|
||||
};
|
||||
#else
|
||||
/*
|
||||
** Files other than os.c just reference the global virtual function table.
|
||||
*/
|
||||
extern struct sqlite3OsVtbl sqlite3Os;
|
||||
#endif /* _SQLITE_OS_C_ */
|
||||
|
||||
|
||||
/* This additional API routine is available with redefinable I/O */
|
||||
struct sqlite3OsVtbl *sqlite3_os_switch(void);
|
||||
|
||||
|
||||
/*
|
||||
** Redefine the OS interface to go through the virtual function table
|
||||
** rather than calling routines directly.
|
||||
*/
|
||||
#undef sqlite3OsOpenReadWrite
|
||||
#undef sqlite3OsOpenExclusive
|
||||
#undef sqlite3OsOpenReadOnly
|
||||
#undef sqlite3OsDelete
|
||||
#undef sqlite3OsFileExists
|
||||
#undef sqlite3OsFullPathname
|
||||
#undef sqlite3OsIsDirWritable
|
||||
#undef sqlite3OsSyncDirectory
|
||||
#undef sqlite3OsTempFileName
|
||||
#undef sqlite3OsRandomSeed
|
||||
#undef sqlite3OsSleep
|
||||
#undef sqlite3OsCurrentTime
|
||||
#undef sqlite3OsEnterMutex
|
||||
#undef sqlite3OsLeaveMutex
|
||||
#undef sqlite3OsInMutex
|
||||
#undef sqlite3OsThreadSpecificData
|
||||
#undef sqlite3OsMalloc
|
||||
#undef sqlite3OsRealloc
|
||||
#undef sqlite3OsFree
|
||||
#undef sqlite3OsAllocationSize
|
||||
#define sqlite3OsOpenReadWrite sqlite3Os.xOpenReadWrite
|
||||
#define sqlite3OsOpenExclusive sqlite3Os.xOpenExclusive
|
||||
#define sqlite3OsOpenReadOnly sqlite3Os.xOpenReadOnly
|
||||
#define sqlite3OsDelete sqlite3Os.xDelete
|
||||
#define sqlite3OsFileExists sqlite3Os.xFileExists
|
||||
#define sqlite3OsFullPathname sqlite3Os.xFullPathname
|
||||
#define sqlite3OsIsDirWritable sqlite3Os.xIsDirWritable
|
||||
#define sqlite3OsSyncDirectory sqlite3Os.xSyncDirectory
|
||||
#define sqlite3OsTempFileName sqlite3Os.xTempFileName
|
||||
#define sqlite3OsRandomSeed sqlite3Os.xRandomSeed
|
||||
#define sqlite3OsSleep sqlite3Os.xSleep
|
||||
#define sqlite3OsCurrentTime sqlite3Os.xCurrentTime
|
||||
#define sqlite3OsEnterMutex sqlite3Os.xEnterMutex
|
||||
#define sqlite3OsLeaveMutex sqlite3Os.xLeaveMutex
|
||||
#define sqlite3OsInMutex sqlite3Os.xInMutex
|
||||
#define sqlite3OsThreadSpecificData sqlite3Os.xThreadSpecificData
|
||||
#define sqlite3OsMalloc sqlite3Os.xMalloc
|
||||
#define sqlite3OsRealloc sqlite3Os.xRealloc
|
||||
#define sqlite3OsFree sqlite3Os.xFree
|
||||
#define sqlite3OsAllocationSize sqlite3Os.xAllocationSize
|
||||
|
||||
#endif /* SQLITE_ENABLE_REDEF_IO */
|
||||
|
||||
#endif /* _SQLITE_OS_H_ */
|
||||
|
||||
@ -88,6 +88,7 @@ static unsigned int elapse;
|
||||
** is used for testing the I/O recovery logic.
|
||||
*/
|
||||
#ifdef SQLITE_TEST
|
||||
int sqlite3_io_error_hit = 0;
|
||||
int sqlite3_io_error_pending = 0;
|
||||
int sqlite3_diskfull_pending = 0;
|
||||
int sqlite3_diskfull = 0;
|
||||
@ -95,7 +96,7 @@ int sqlite3_diskfull = 0;
|
||||
if( sqlite3_io_error_pending ) \
|
||||
if( sqlite3_io_error_pending-- == 1 ){ local_ioerr(); return A; }
|
||||
static void local_ioerr(){
|
||||
sqlite3_io_error_pending = 0; /* Really just a place to set a breakpoint */
|
||||
sqlite3_io_error_hit = 1; /* Really just a place to set a breakpoint */
|
||||
}
|
||||
#define SimulateDiskfullError \
|
||||
if( sqlite3_diskfull_pending ){ \
|
||||
@ -121,3 +122,67 @@ int sqlite3_open_file_count = 0;
|
||||
#else
|
||||
#define OpenCounter(X)
|
||||
#endif
|
||||
|
||||
/*
|
||||
** sqlite3GenericMalloc
|
||||
** sqlite3GenericRealloc
|
||||
** sqlite3GenericOsFree
|
||||
** sqlite3GenericAllocationSize
|
||||
**
|
||||
** Implementation of the os level dynamic memory allocation interface in terms
|
||||
** of the standard malloc(), realloc() and free() found in many operating
|
||||
** systems. No rocket science here.
|
||||
**
|
||||
** There are two versions of these four functions here. The version
|
||||
** implemented here is only used if memory-management or memory-debugging is
|
||||
** enabled. This version allocates an extra 8-bytes at the beginning of each
|
||||
** block and stores the size of the allocation there.
|
||||
**
|
||||
** If neither memory-management or debugging is enabled, the second
|
||||
** set of implementations is used instead.
|
||||
*/
|
||||
#if defined(SQLITE_ENABLE_MEMORY_MANAGEMENT) || defined (SQLITE_MEMDEBUG)
|
||||
void *sqlite3GenericMalloc(int n){
|
||||
char *p = (char *)malloc(n+8);
|
||||
assert(n>0);
|
||||
assert(sizeof(int)<=8);
|
||||
if( p ){
|
||||
*(int *)p = n;
|
||||
p += 8;
|
||||
}
|
||||
return (void *)p;
|
||||
}
|
||||
void *sqlite3GenericRealloc(void *p, int n){
|
||||
char *p2 = ((char *)p - 8);
|
||||
assert(n>0);
|
||||
p2 = realloc(p2, n+8);
|
||||
if( p2 ){
|
||||
*(int *)p2 = n;
|
||||
p2 += 8;
|
||||
}
|
||||
return (void *)p2;
|
||||
}
|
||||
void sqlite3GenericFree(void *p){
|
||||
assert(p);
|
||||
free((void *)((char *)p - 8));
|
||||
}
|
||||
int sqlite3GenericAllocationSize(void *p){
|
||||
return p ? *(int *)((char *)p - 8) : 0;
|
||||
}
|
||||
#else
|
||||
void *sqlite3GenericMalloc(int n){
|
||||
char *p = (char *)malloc(n);
|
||||
return (void *)p;
|
||||
}
|
||||
void *sqlite3GenericRealloc(void *p, int n){
|
||||
assert(n>0);
|
||||
p = realloc(p, n);
|
||||
return p;
|
||||
}
|
||||
void sqlite3GenericFree(void *p){
|
||||
assert(p);
|
||||
free(p);
|
||||
}
|
||||
/* Never actually used, but needed for the linker */
|
||||
int sqlite3GenericAllocationSize(void *p){ return 0; }
|
||||
#endif
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -13,9 +13,12 @@
|
||||
** 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.46 2005/09/19 19:05:21 drh Exp $
|
||||
** @(#) $Id: pager.h,v 1.48 2005/12/19 14:18:11 danielk1977 Exp $
|
||||
*/
|
||||
|
||||
#ifndef _PAGER_H_
|
||||
#define _PAGER_H_
|
||||
|
||||
/*
|
||||
** The default size of a database page.
|
||||
*/
|
||||
@ -105,6 +108,7 @@ int sqlite3pager_rename(Pager*, const char *zNewName);
|
||||
void sqlite3pager_set_codec(Pager*,void(*)(void*,void*,Pgno,int),void*);
|
||||
int sqlite3pager_movepage(Pager*,void*,Pgno);
|
||||
int sqlite3pager_reset(Pager*);
|
||||
int sqlite3pager_release_memory(int);
|
||||
|
||||
#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
|
||||
int sqlite3pager_lockstate(Pager*);
|
||||
@ -114,3 +118,5 @@ int sqlite3pager_lockstate(Pager*);
|
||||
void sqlite3pager_refdump(Pager*);
|
||||
int pager3_refinfo_enable;
|
||||
#endif
|
||||
|
||||
#endif /* _PAGER_H_ */
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,145 +1,151 @@
|
||||
#define TK_END_OF_FILE 1
|
||||
#define TK_ILLEGAL 2
|
||||
#define TK_SPACE 3
|
||||
#define TK_UNCLOSED_STRING 4
|
||||
#define TK_COMMENT 5
|
||||
#define TK_FUNCTION 6
|
||||
#define TK_COLUMN 7
|
||||
#define TK_AGG_FUNCTION 8
|
||||
#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
|
||||
#define TK_SEMI 1
|
||||
#define TK_EXPLAIN 2
|
||||
#define TK_QUERY 3
|
||||
#define TK_PLAN 4
|
||||
#define TK_BEGIN 5
|
||||
#define TK_TRANSACTION 6
|
||||
#define TK_DEFERRED 7
|
||||
#define TK_IMMEDIATE 8
|
||||
#define TK_EXCLUSIVE 9
|
||||
#define TK_COMMIT 10
|
||||
#define TK_END 11
|
||||
#define TK_ROLLBACK 12
|
||||
#define TK_CREATE 13
|
||||
#define TK_TABLE 14
|
||||
#define TK_IF 15
|
||||
#define TK_NOT 16
|
||||
#define TK_EXISTS 17
|
||||
#define TK_TEMP 18
|
||||
#define TK_LP 19
|
||||
#define TK_RP 20
|
||||
#define TK_AS 21
|
||||
#define TK_COMMA 22
|
||||
#define TK_ID 23
|
||||
#define TK_ABORT 24
|
||||
#define TK_AFTER 25
|
||||
#define TK_ANALYZE 26
|
||||
#define TK_ASC 27
|
||||
#define TK_ATTACH 28
|
||||
#define TK_BEFORE 29
|
||||
#define TK_CASCADE 30
|
||||
#define TK_CAST 31
|
||||
#define TK_CONFLICT 32
|
||||
#define TK_DATABASE 33
|
||||
#define TK_DESC 34
|
||||
#define TK_DETACH 35
|
||||
#define TK_EACH 36
|
||||
#define TK_FAIL 37
|
||||
#define TK_FOR 38
|
||||
#define TK_IGNORE 39
|
||||
#define TK_INITIALLY 40
|
||||
#define TK_INSTEAD 41
|
||||
#define TK_LIKE_KW 42
|
||||
#define TK_MATCH 43
|
||||
#define TK_KEY 44
|
||||
#define TK_OF 45
|
||||
#define TK_OFFSET 46
|
||||
#define TK_PRAGMA 47
|
||||
#define TK_RAISE 48
|
||||
#define TK_REPLACE 49
|
||||
#define TK_RESTRICT 50
|
||||
#define TK_ROW 51
|
||||
#define TK_STATEMENT 52
|
||||
#define TK_TRIGGER 53
|
||||
#define TK_VACUUM 54
|
||||
#define TK_VIEW 55
|
||||
#define TK_REINDEX 56
|
||||
#define TK_RENAME 57
|
||||
#define TK_CTIME_KW 58
|
||||
#define TK_OR 59
|
||||
#define TK_AND 60
|
||||
#define TK_IS 61
|
||||
#define TK_BETWEEN 62
|
||||
#define TK_IN 63
|
||||
#define TK_ISNULL 64
|
||||
#define TK_NOTNULL 65
|
||||
#define TK_NE 66
|
||||
#define TK_EQ 67
|
||||
#define TK_GT 68
|
||||
#define TK_LE 69
|
||||
#define TK_LT 70
|
||||
#define TK_GE 71
|
||||
#define TK_ESCAPE 72
|
||||
#define TK_BITAND 73
|
||||
#define TK_BITOR 74
|
||||
#define TK_LSHIFT 75
|
||||
#define TK_RSHIFT 76
|
||||
#define TK_PLUS 77
|
||||
#define TK_MINUS 78
|
||||
#define TK_STAR 79
|
||||
#define TK_SLASH 80
|
||||
#define TK_REM 81
|
||||
#define TK_CONCAT 82
|
||||
#define TK_UMINUS 83
|
||||
#define TK_UPLUS 84
|
||||
#define TK_BITNOT 85
|
||||
#define TK_STRING 86
|
||||
#define TK_JOIN_KW 87
|
||||
#define TK_CONSTRAINT 88
|
||||
#define TK_DEFAULT 89
|
||||
#define TK_NULL 90
|
||||
#define TK_PRIMARY 91
|
||||
#define TK_UNIQUE 92
|
||||
#define TK_CHECK 93
|
||||
#define TK_REFERENCES 94
|
||||
#define TK_COLLATE 95
|
||||
#define TK_AUTOINCR 96
|
||||
#define TK_ON 97
|
||||
#define TK_DELETE 98
|
||||
#define TK_UPDATE 99
|
||||
#define TK_INSERT 100
|
||||
#define TK_SET 101
|
||||
#define TK_DEFERRABLE 102
|
||||
#define TK_FOREIGN 103
|
||||
#define TK_DROP 104
|
||||
#define TK_UNION 105
|
||||
#define TK_ALL 106
|
||||
#define TK_EXCEPT 107
|
||||
#define TK_INTERSECT 108
|
||||
#define TK_SELECT 109
|
||||
#define TK_DISTINCT 110
|
||||
#define TK_DOT 111
|
||||
#define TK_FROM 112
|
||||
#define TK_JOIN 113
|
||||
#define TK_USING 114
|
||||
#define TK_ORDER 115
|
||||
#define TK_BY 116
|
||||
#define TK_GROUP 117
|
||||
#define TK_HAVING 118
|
||||
#define TK_LIMIT 119
|
||||
#define TK_WHERE 120
|
||||
#define TK_INTO 121
|
||||
#define TK_VALUES 122
|
||||
#define TK_INTEGER 123
|
||||
#define TK_FLOAT 124
|
||||
#define TK_BLOB 125
|
||||
#define TK_REGISTER 126
|
||||
#define TK_VARIABLE 127
|
||||
#define TK_CASE 128
|
||||
#define TK_WHEN 129
|
||||
#define TK_THEN 130
|
||||
#define TK_ELSE 131
|
||||
#define TK_INDEX 132
|
||||
#define TK_ALTER 133
|
||||
#define TK_TO 134
|
||||
#define TK_ADD 135
|
||||
#define TK_COLUMNKW 136
|
||||
#define TK_TO_TEXT 137
|
||||
#define TK_TO_BLOB 138
|
||||
#define TK_TO_NUMERIC 139
|
||||
#define TK_TO_INT 140
|
||||
#define TK_TO_REAL 141
|
||||
#define TK_END_OF_FILE 142
|
||||
#define TK_ILLEGAL 143
|
||||
#define TK_SPACE 144
|
||||
#define TK_UNCLOSED_STRING 145
|
||||
#define TK_COMMENT 146
|
||||
#define TK_FUNCTION 147
|
||||
#define TK_COLUMN 148
|
||||
#define TK_AGG_FUNCTION 149
|
||||
#define TK_AGG_COLUMN 150
|
||||
#define TK_CONST_FUNC 151
|
||||
|
||||
@ -11,7 +11,7 @@
|
||||
*************************************************************************
|
||||
** This file contains code used to implement the PRAGMA command.
|
||||
**
|
||||
** $Id: pragma.c,v 1.100 2005/09/20 17:42:23 drh Exp $
|
||||
** $Id: pragma.c,v 1.114 2006/01/12 01:56:44 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include "os.h"
|
||||
@ -36,7 +36,7 @@
|
||||
** to support legacy SQL code. The safety level used to be boolean
|
||||
** and older scripts may have used numbers 0 for OFF and 1 for ON.
|
||||
*/
|
||||
static int getSafetyLevel(const u8 *z){
|
||||
static int getSafetyLevel(const char *z){
|
||||
/* 123456789 123456789 */
|
||||
static const char zText[] = "onoffalseyestruefull";
|
||||
static const u8 iOffset[] = {0, 1, 2, 4, 9, 12, 16};
|
||||
@ -58,7 +58,7 @@ static int getSafetyLevel(const u8 *z){
|
||||
/*
|
||||
** Interpret the given string as a boolean value.
|
||||
*/
|
||||
static int getBoolean(const u8 *z){
|
||||
static int getBoolean(const char *z){
|
||||
return getSafetyLevel(z)&1;
|
||||
}
|
||||
|
||||
@ -151,9 +151,17 @@ static int flagPragma(Parse *pParse, const char *zLeft, const char *zRight){
|
||||
{ "short_column_names", SQLITE_ShortColNames },
|
||||
{ "count_changes", SQLITE_CountRows },
|
||||
{ "empty_result_callbacks", SQLITE_NullCallback },
|
||||
{ "legacy_file_format", SQLITE_LegacyFileFmt },
|
||||
#ifndef SQLITE_OMIT_CHECK
|
||||
{ "ignore_check_constraints", SQLITE_IgnoreChecks },
|
||||
#endif
|
||||
/* The following is VERY experimental */
|
||||
{ "writable_schema", SQLITE_WriteSchema },
|
||||
{ "omit_readlock", SQLITE_NoReadlock },
|
||||
|
||||
/* TODO: Maybe it shouldn't be possible to change the ReadUncommitted
|
||||
** flag if there are any active statements. */
|
||||
{ "read_uncommitted", SQLITE_ReadUncommitted },
|
||||
};
|
||||
int i;
|
||||
const struct sPragmaType *p;
|
||||
@ -280,8 +288,8 @@ void sqlite3Pragma(
|
||||
sqlite3VdbeAddOp(v, OP_Ge, 0, addr+3);
|
||||
sqlite3VdbeAddOp(v, OP_Negative, 0, 0);
|
||||
sqlite3VdbeAddOp(v, OP_SetCookie, iDb, 2);
|
||||
pDb->cache_size = size;
|
||||
sqlite3BtreeSetCacheSize(pDb->pBt, pDb->cache_size);
|
||||
pDb->pSchema->cache_size = size;
|
||||
sqlite3BtreeSetCacheSize(pDb->pBt, pDb->pSchema->cache_size);
|
||||
}
|
||||
}else
|
||||
|
||||
@ -342,12 +350,12 @@ void sqlite3Pragma(
|
||||
if( sqlite3StrICmp(zLeft,"cache_size")==0 ){
|
||||
if( sqlite3ReadSchema(pParse) ) goto pragma_out;
|
||||
if( !zRight ){
|
||||
returnSingleInt(pParse, "cache_size", pDb->cache_size);
|
||||
returnSingleInt(pParse, "cache_size", pDb->pSchema->cache_size);
|
||||
}else{
|
||||
int size = atoi(zRight);
|
||||
if( size<0 ) size = -size;
|
||||
pDb->cache_size = size;
|
||||
sqlite3BtreeSetCacheSize(pDb->pBt, pDb->cache_size);
|
||||
pDb->pSchema->cache_size = size;
|
||||
sqlite3BtreeSetCacheSize(pDb->pBt, pDb->pSchema->cache_size);
|
||||
}
|
||||
}else
|
||||
|
||||
@ -647,6 +655,7 @@ void sqlite3Pragma(
|
||||
/* Do an integrity check on each database file */
|
||||
for(i=0; i<db->nDb; i++){
|
||||
HashElem *x;
|
||||
Hash *pTbls;
|
||||
int cnt = 0;
|
||||
|
||||
if( OMIT_TEMPDB && i==1 ) continue;
|
||||
@ -655,13 +664,13 @@ void sqlite3Pragma(
|
||||
|
||||
/* Do an integrity check of the B-Tree
|
||||
*/
|
||||
for(x=sqliteHashFirst(&db->aDb[i].tblHash); x; x=sqliteHashNext(x)){
|
||||
pTbls = &db->aDb[i].pSchema->tblHash;
|
||||
for(x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){
|
||||
Table *pTab = sqliteHashData(x);
|
||||
Index *pIdx;
|
||||
sqlite3VdbeAddOp(v, OP_Integer, pTab->tnum, 0);
|
||||
cnt++;
|
||||
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
|
||||
if( sqlite3CheckIndexCollSeq(pParse, pIdx) ) goto pragma_out;
|
||||
sqlite3VdbeAddOp(v, OP_Integer, pIdx->tnum, 0);
|
||||
cnt++;
|
||||
}
|
||||
@ -670,18 +679,19 @@ void sqlite3Pragma(
|
||||
sqlite3VdbeAddOp(v, OP_IntegrityCk, cnt, i);
|
||||
sqlite3VdbeAddOp(v, OP_Dup, 0, 1);
|
||||
addr = sqlite3VdbeOp3(v, OP_String8, 0, 0, "ok", P3_STATIC);
|
||||
sqlite3VdbeAddOp(v, OP_Eq, 0, addr+6);
|
||||
sqlite3VdbeAddOp(v, OP_Eq, 0, addr+7);
|
||||
sqlite3VdbeOp3(v, OP_String8, 0, 0,
|
||||
sqlite3MPrintf("*** in database %s ***\n", db->aDb[i].zName),
|
||||
P3_DYNAMIC);
|
||||
sqlite3VdbeAddOp(v, OP_Pull, 1, 0);
|
||||
sqlite3VdbeAddOp(v, OP_Concat, 0, 1);
|
||||
sqlite3VdbeAddOp(v, OP_Callback, 1, 0);
|
||||
sqlite3VdbeAddOp(v, OP_MemIncr, 1, 0);
|
||||
|
||||
/* Make sure all the indices are constructed correctly.
|
||||
*/
|
||||
sqlite3CodeVerifySchema(pParse, i);
|
||||
for(x=sqliteHashFirst(&db->aDb[i].tblHash); x; x=sqliteHashNext(x)){
|
||||
for(x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){
|
||||
Table *pTab = sqliteHashData(x);
|
||||
Index *pIdx;
|
||||
int loopTop;
|
||||
@ -690,11 +700,11 @@ void sqlite3Pragma(
|
||||
sqlite3OpenTableAndIndices(pParse, pTab, 1, OP_OpenRead);
|
||||
sqlite3VdbeAddOp(v, OP_MemInt, 0, 1);
|
||||
loopTop = sqlite3VdbeAddOp(v, OP_Rewind, 1, 0);
|
||||
sqlite3VdbeAddOp(v, OP_MemIncr, 1, 0);
|
||||
sqlite3VdbeAddOp(v, OP_MemIncr, 1, 1);
|
||||
for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
|
||||
int jmp2;
|
||||
static const VdbeOpList idxErr[] = {
|
||||
{ OP_MemIncr, 0, 0, 0},
|
||||
{ OP_MemIncr, 1, 0, 0},
|
||||
{ OP_String8, 0, 0, "rowid "},
|
||||
{ OP_Rowid, 1, 0, 0},
|
||||
{ OP_String8, 0, 0, " missing from index "},
|
||||
@ -714,12 +724,12 @@ void sqlite3Pragma(
|
||||
static const VdbeOpList cntIdx[] = {
|
||||
{ OP_MemInt, 0, 2, 0},
|
||||
{ OP_Rewind, 0, 0, 0}, /* 1 */
|
||||
{ OP_MemIncr, 2, 0, 0},
|
||||
{ OP_MemIncr, 1, 2, 0},
|
||||
{ OP_Next, 0, 0, 0}, /* 3 */
|
||||
{ OP_MemLoad, 1, 0, 0},
|
||||
{ OP_MemLoad, 2, 0, 0},
|
||||
{ OP_Eq, 0, 0, 0}, /* 6 */
|
||||
{ OP_MemIncr, 0, 0, 0},
|
||||
{ OP_MemIncr, 1, 0, 0},
|
||||
{ OP_String8, 0, 0, "wrong # of entries in index "},
|
||||
{ OP_String8, 0, 0, 0}, /* 9 */
|
||||
{ OP_Concat, 0, 0, 0},
|
||||
@ -787,7 +797,7 @@ void sqlite3Pragma(
|
||||
sqlite3VdbeSetColName(v, 0, "encoding", P3_STATIC);
|
||||
sqlite3VdbeAddOp(v, OP_String8, 0, 0);
|
||||
for(pEnc=&encnames[0]; pEnc->zName; pEnc++){
|
||||
if( pEnc->enc==pParse->db->enc ){
|
||||
if( pEnc->enc==ENC(pParse->db) ){
|
||||
sqlite3VdbeChangeP3(v, -1, pEnc->zName, P3_STATIC);
|
||||
break;
|
||||
}
|
||||
@ -799,10 +809,13 @@ void sqlite3Pragma(
|
||||
** will be overwritten when the schema is next loaded. If it does not
|
||||
** already exists, it will be created to use the new encoding value.
|
||||
*/
|
||||
if( !(pParse->db->flags&SQLITE_Initialized) ){
|
||||
if(
|
||||
!(DbHasProperty(db, 0, DB_SchemaLoaded)) ||
|
||||
DbHasProperty(db, 0, DB_Empty)
|
||||
){
|
||||
for(pEnc=&encnames[0]; pEnc->zName; pEnc++){
|
||||
if( 0==sqlite3StrICmp(zRight, pEnc->zName) ){
|
||||
pParse->db->enc = pEnc->enc;
|
||||
ENC(pParse->db) = pEnc->enc;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -918,6 +931,12 @@ void sqlite3Pragma(
|
||||
}else
|
||||
#endif
|
||||
|
||||
#if SQLITE_HAS_CODEC
|
||||
if( sqlite3StrICmp(zLeft, "key")==0 ){
|
||||
sqlite3_key(db, zRight, strlen(zRight));
|
||||
}else
|
||||
#endif
|
||||
|
||||
{}
|
||||
|
||||
if( v ){
|
||||
|
||||
@ -13,7 +13,7 @@
|
||||
** interface, and routines that contribute to loading the database schema
|
||||
** from disk.
|
||||
**
|
||||
** $Id: prepare.c,v 1.2 2005-12-13 19:49:35 vladimir%pobox.com Exp $
|
||||
** $Id: prepare.c,v 1.3 2006-02-08 21:10:11 vladimir%pobox.com Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include "os.h"
|
||||
@ -24,7 +24,7 @@
|
||||
** that the database is corrupt.
|
||||
*/
|
||||
static void corruptSchema(InitData *pData, const char *zExtra){
|
||||
if( !sqlite3_malloc_failed ){
|
||||
if( !sqlite3MallocFailed() ){
|
||||
sqlite3SetString(pData->pzErrMsg, "malformed database schema",
|
||||
zExtra!=0 && zExtra[0]!=0 ? " - " : (char*)0, zExtra, (char*)0);
|
||||
}
|
||||
@ -49,6 +49,10 @@ int sqlite3InitCallback(void *pInit, int argc, char **argv, char **azColName){
|
||||
sqlite3 *db = pData->db;
|
||||
int iDb;
|
||||
|
||||
if( sqlite3MallocFailed() ){
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
|
||||
assert( argc==4 );
|
||||
if( argv==0 ) return 0; /* Might happen if EMPTY_RESULT_CALLBACKS are on */
|
||||
if( argv[1]==0 || argv[3]==0 ){
|
||||
@ -71,7 +75,11 @@ int sqlite3InitCallback(void *pInit, int argc, char **argv, char **azColName){
|
||||
rc = sqlite3_exec(db, argv[2], 0, 0, &zErr);
|
||||
db->init.iDb = 0;
|
||||
if( SQLITE_OK!=rc ){
|
||||
corruptSchema(pData, zErr);
|
||||
if( rc==SQLITE_NOMEM ){
|
||||
sqlite3FailedMalloc();
|
||||
}else{
|
||||
corruptSchema(pData, zErr);
|
||||
}
|
||||
sqlite3_free(zErr);
|
||||
return rc;
|
||||
}
|
||||
@ -111,6 +119,7 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
|
||||
BtCursor *curMain;
|
||||
int size;
|
||||
Table *pTab;
|
||||
Db *pDb;
|
||||
char const *azArg[5];
|
||||
char zDbNum[30];
|
||||
int meta[10];
|
||||
@ -145,6 +154,7 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
|
||||
#endif
|
||||
|
||||
assert( iDb>=0 && iDb<db->nDb );
|
||||
assert( db->aDb[iDb].pSchema );
|
||||
|
||||
/* zMasterSchema and zInitScript are set to point at the master schema
|
||||
** and initialisation script appropriate for the database being
|
||||
@ -180,11 +190,14 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
|
||||
|
||||
/* Create a cursor to hold the database open
|
||||
*/
|
||||
if( db->aDb[iDb].pBt==0 ){
|
||||
if( !OMIT_TEMPDB && iDb==1 ) DbSetProperty(db, 1, DB_SchemaLoaded);
|
||||
pDb = &db->aDb[iDb];
|
||||
if( pDb->pBt==0 ){
|
||||
if( !OMIT_TEMPDB && iDb==1 ){
|
||||
DbSetProperty(db, 1, DB_SchemaLoaded);
|
||||
}
|
||||
return SQLITE_OK;
|
||||
}
|
||||
rc = sqlite3BtreeCursor(db->aDb[iDb].pBt, MASTER_ROOT, 0, 0, 0, &curMain);
|
||||
rc = sqlite3BtreeCursor(pDb->pBt, MASTER_ROOT, 0, 0, 0, &curMain);
|
||||
if( rc!=SQLITE_OK && rc!=SQLITE_EMPTY ){
|
||||
sqlite3SetString(pzErrMsg, sqlite3ErrStr(rc), (char*)0);
|
||||
return rc;
|
||||
@ -204,13 +217,13 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
|
||||
** meta[8]
|
||||
** meta[9]
|
||||
**
|
||||
** Note: The hash defined SQLITE_UTF* symbols in sqliteInt.h correspond to
|
||||
** Note: The #defined SQLITE_UTF* symbols in sqliteInt.h correspond to
|
||||
** the possible values of meta[4].
|
||||
*/
|
||||
if( rc==SQLITE_OK ){
|
||||
int i;
|
||||
for(i=0; rc==SQLITE_OK && i<sizeof(meta)/sizeof(meta[0]); i++){
|
||||
rc = sqlite3BtreeGetMeta(db->aDb[iDb].pBt, i+1, (u32 *)&meta[i]);
|
||||
rc = sqlite3BtreeGetMeta(pDb->pBt, i+1, (u32 *)&meta[i]);
|
||||
}
|
||||
if( rc ){
|
||||
sqlite3SetString(pzErrMsg, sqlite3ErrStr(rc), (char*)0);
|
||||
@ -220,7 +233,7 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
|
||||
}else{
|
||||
memset(meta, 0, sizeof(meta));
|
||||
}
|
||||
db->aDb[iDb].schema_cookie = meta[0];
|
||||
pDb->pSchema->schema_cookie = meta[0];
|
||||
|
||||
/* If opening a non-empty database, check the text encoding. For the
|
||||
** main database, set sqlite3.enc to the encoding of the main database.
|
||||
@ -229,55 +242,44 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
|
||||
*/
|
||||
if( meta[4] ){ /* text encoding */
|
||||
if( iDb==0 ){
|
||||
/* If opening the main database, set db->enc. */
|
||||
db->enc = (u8)meta[4];
|
||||
db->pDfltColl = sqlite3FindCollSeq(db, db->enc, "BINARY", 6, 0);
|
||||
/* If opening the main database, set ENC(db). */
|
||||
ENC(db) = (u8)meta[4];
|
||||
db->pDfltColl = sqlite3FindCollSeq(db, SQLITE_UTF8, "BINARY", 6, 0);
|
||||
}else{
|
||||
/* If opening an attached database, the encoding much match db->enc */
|
||||
if( meta[4]!=db->enc ){
|
||||
/* If opening an attached database, the encoding much match ENC(db) */
|
||||
if( meta[4]!=ENC(db) ){
|
||||
sqlite3BtreeCloseCursor(curMain);
|
||||
sqlite3SetString(pzErrMsg, "attached databases must use the same"
|
||||
" text encoding as main database", (char*)0);
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
}
|
||||
}else{
|
||||
DbSetProperty(db, iDb, DB_Empty);
|
||||
}
|
||||
pDb->pSchema->enc = ENC(db);
|
||||
|
||||
size = meta[2];
|
||||
if( size==0 ){ size = MAX_PAGES; }
|
||||
db->aDb[iDb].cache_size = size;
|
||||
|
||||
if( iDb==0 ){
|
||||
db->file_format = meta[1];
|
||||
if( db->file_format==0 ){
|
||||
/* This happens if the database was initially empty */
|
||||
db->file_format = 1;
|
||||
}
|
||||
|
||||
if( db->file_format==2 || db->file_format==3 ){
|
||||
/* File format 2 is treated exactly as file format 1. New
|
||||
** databases are created with file format 1.
|
||||
*/
|
||||
db->file_format = 1;
|
||||
}
|
||||
}
|
||||
pDb->pSchema->cache_size = size;
|
||||
sqlite3BtreeSetCacheSize(pDb->pBt, pDb->pSchema->cache_size);
|
||||
|
||||
/*
|
||||
** file_format==1 Version 3.0.0.
|
||||
** file_format==2 Version 3.1.3.
|
||||
** file_format==3 Version 3.1.4.
|
||||
**
|
||||
** Version 3.0 can only use files with file_format==1. Version 3.1.3
|
||||
** can read and write files with file_format==1 or file_format==2.
|
||||
** Version 3.1.4 can read and write file formats 1, 2 and 3.
|
||||
** file_format==2 Version 3.1.3. // ALTER TABLE ADD COLUMN
|
||||
** file_format==3 Version 3.1.4. // ditto but with non-NULL defaults
|
||||
** file_format==4 Version 3.3.0. // DESC indices. Boolean constants
|
||||
*/
|
||||
if( meta[1]>3 ){
|
||||
pDb->pSchema->file_format = meta[1];
|
||||
if( pDb->pSchema->file_format==0 ){
|
||||
pDb->pSchema->file_format = 1;
|
||||
}
|
||||
if( pDb->pSchema->file_format>SQLITE_MAX_FILE_FORMAT ){
|
||||
sqlite3BtreeCloseCursor(curMain);
|
||||
sqlite3SetString(pzErrMsg, "unsupported file format", (char*)0);
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
|
||||
sqlite3BtreeSetCacheSize(db->aDb[iDb].pBt, db->aDb[iDb].cache_size);
|
||||
|
||||
/* Read the schema information out of the schema tables
|
||||
*/
|
||||
@ -301,8 +303,8 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
|
||||
#endif
|
||||
sqlite3BtreeCloseCursor(curMain);
|
||||
}
|
||||
if( sqlite3_malloc_failed ){
|
||||
sqlite3SetString(pzErrMsg, "out of memory", (char*)0);
|
||||
if( sqlite3MallocFailed() ){
|
||||
/* sqlite3SetString(pzErrMsg, "out of memory", (char*)0); */
|
||||
rc = SQLITE_NOMEM;
|
||||
sqlite3ResetInternalSchema(db, 0);
|
||||
}
|
||||
@ -320,14 +322,15 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
|
||||
** created using ATTACH statements. Return a success code. If an
|
||||
** error occurs, write an error message into *pzErrMsg.
|
||||
**
|
||||
** After the database is initialized, the SQLITE_Initialized
|
||||
** bit is set in the flags field of the sqlite structure.
|
||||
** After a database is initialized, the DB_SchemaLoaded bit is set
|
||||
** bit is set in the flags field of the Db structure. If the database
|
||||
** file was of zero-length, then the DB_Empty flag is also set.
|
||||
*/
|
||||
int sqlite3Init(sqlite3 *db, char **pzErrMsg){
|
||||
int i, rc;
|
||||
int called_initone = 0;
|
||||
|
||||
if( db->init.busy ) return SQLITE_OK;
|
||||
assert( (db->flags & SQLITE_Initialized)==0 );
|
||||
rc = SQLITE_OK;
|
||||
db->init.busy = 1;
|
||||
for(i=0; rc==SQLITE_OK && i<db->nDb; i++){
|
||||
@ -336,6 +339,7 @@ int sqlite3Init(sqlite3 *db, char **pzErrMsg){
|
||||
if( rc ){
|
||||
sqlite3ResetInternalSchema(db, i);
|
||||
}
|
||||
called_initone = 1;
|
||||
}
|
||||
|
||||
/* Once all the other databases have been initialised, load the schema
|
||||
@ -348,19 +352,16 @@ int sqlite3Init(sqlite3 *db, char **pzErrMsg){
|
||||
if( rc ){
|
||||
sqlite3ResetInternalSchema(db, 1);
|
||||
}
|
||||
called_initone = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
db->init.busy = 0;
|
||||
if( rc==SQLITE_OK ){
|
||||
db->flags |= SQLITE_Initialized;
|
||||
if( rc==SQLITE_OK && called_initone ){
|
||||
sqlite3CommitInternalChanges(db);
|
||||
}
|
||||
|
||||
if( rc!=SQLITE_OK ){
|
||||
db->flags &= ~SQLITE_Initialized;
|
||||
}
|
||||
return rc;
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -371,11 +372,8 @@ int sqlite3ReadSchema(Parse *pParse){
|
||||
int rc = SQLITE_OK;
|
||||
sqlite3 *db = pParse->db;
|
||||
if( !db->init.busy ){
|
||||
if( (db->flags & SQLITE_Initialized)==0 ){
|
||||
rc = sqlite3Init(db, &pParse->zErrMsg);
|
||||
}
|
||||
rc = sqlite3Init(db, &pParse->zErrMsg);
|
||||
}
|
||||
assert( rc!=SQLITE_OK || (db->flags & SQLITE_Initialized) || db->init.busy );
|
||||
if( rc!=SQLITE_OK ){
|
||||
pParse->rc = rc;
|
||||
pParse->nErr++;
|
||||
@ -402,7 +400,7 @@ static int schemaIsValid(sqlite3 *db){
|
||||
rc = sqlite3BtreeCursor(pBt, MASTER_ROOT, 0, 0, 0, &curTemp);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3BtreeGetMeta(pBt, 1, (u32 *)&cookie);
|
||||
if( rc==SQLITE_OK && cookie!=db->aDb[iDb].schema_cookie ){
|
||||
if( rc==SQLITE_OK && cookie!=db->aDb[iDb].pSchema->schema_cookie ){
|
||||
allOk = 0;
|
||||
}
|
||||
sqlite3BtreeCloseCursor(curTemp);
|
||||
@ -411,6 +409,88 @@ static int schemaIsValid(sqlite3 *db){
|
||||
return allOk;
|
||||
}
|
||||
|
||||
/*
|
||||
** Free all resources held by the schema structure. The void* argument points
|
||||
** at a Schema struct. This function does not call sqliteFree() on the
|
||||
** pointer itself, it just cleans up subsiduary resources (i.e. the contents
|
||||
** of the schema hash tables).
|
||||
*/
|
||||
void sqlite3SchemaFree(void *p){
|
||||
Hash temp1;
|
||||
Hash temp2;
|
||||
HashElem *pElem;
|
||||
Schema *pSchema = (Schema *)p;
|
||||
|
||||
temp1 = pSchema->tblHash;
|
||||
temp2 = pSchema->trigHash;
|
||||
sqlite3HashInit(&pSchema->trigHash, SQLITE_HASH_STRING, 0);
|
||||
sqlite3HashClear(&pSchema->aFKey);
|
||||
sqlite3HashClear(&pSchema->idxHash);
|
||||
for(pElem=sqliteHashFirst(&temp2); pElem; pElem=sqliteHashNext(pElem)){
|
||||
sqlite3DeleteTrigger((Trigger*)sqliteHashData(pElem));
|
||||
}
|
||||
sqlite3HashClear(&temp2);
|
||||
sqlite3HashInit(&pSchema->tblHash, SQLITE_HASH_STRING, 0);
|
||||
for(pElem=sqliteHashFirst(&temp1); pElem; pElem=sqliteHashNext(pElem)){
|
||||
Table *pTab = sqliteHashData(pElem);
|
||||
sqlite3DeleteTable(0, pTab);
|
||||
}
|
||||
sqlite3HashClear(&temp1);
|
||||
pSchema->pSeqTab = 0;
|
||||
pSchema->flags &= ~DB_SchemaLoaded;
|
||||
}
|
||||
|
||||
/*
|
||||
** Find and return the schema associated with a BTree. Create
|
||||
** a new one if necessary.
|
||||
*/
|
||||
Schema *sqlite3SchemaGet(Btree *pBt){
|
||||
Schema * p;
|
||||
if( pBt ){
|
||||
p = (Schema *)sqlite3BtreeSchema(pBt,sizeof(Schema),sqlite3SchemaFree);
|
||||
}else{
|
||||
p = (Schema *)sqliteMalloc(sizeof(Schema));
|
||||
}
|
||||
if( p && 0==p->file_format ){
|
||||
sqlite3HashInit(&p->tblHash, SQLITE_HASH_STRING, 0);
|
||||
sqlite3HashInit(&p->idxHash, SQLITE_HASH_STRING, 0);
|
||||
sqlite3HashInit(&p->trigHash, SQLITE_HASH_STRING, 0);
|
||||
sqlite3HashInit(&p->aFKey, SQLITE_HASH_STRING, 1);
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
/*
|
||||
** Convert a schema pointer into the iDb index that indicates
|
||||
** which database file in db->aDb[] the schema refers to.
|
||||
**
|
||||
** If the same database is attached more than once, the first
|
||||
** attached database is returned.
|
||||
*/
|
||||
int sqlite3SchemaToIndex(sqlite3 *db, Schema *pSchema){
|
||||
int i = -1000000;
|
||||
|
||||
/* If pSchema is NULL, then return -1000000. This happens when code in
|
||||
** expr.c is trying to resolve a reference to a transient table (i.e. one
|
||||
** created by a sub-select). In this case the return value of this
|
||||
** function should never be used.
|
||||
**
|
||||
** We return -1000000 instead of the more usual -1 simply because using
|
||||
** -1000000 as incorrectly using -1000000 index into db->aDb[] is much
|
||||
** more likely to cause a segfault than -1 (of course there are assert()
|
||||
** statements too, but it never hurts to play the odds).
|
||||
*/
|
||||
if( pSchema ){
|
||||
for(i=0; i<db->nDb; i++){
|
||||
if( db->aDb[i].pSchema==pSchema ){
|
||||
break;
|
||||
}
|
||||
}
|
||||
assert( i>=0 &&i>=0 && i<db->nDb );
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
/*
|
||||
** Compile the UTF-8 encoded SQL statement zSql into a statement handle.
|
||||
*/
|
||||
@ -424,10 +504,10 @@ int sqlite3_prepare(
|
||||
Parse sParse;
|
||||
char *zErrMsg = 0;
|
||||
int rc = SQLITE_OK;
|
||||
int i;
|
||||
|
||||
if( sqlite3_malloc_failed ){
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
/* Assert that malloc() has not failed */
|
||||
assert( !sqlite3MallocFailed() );
|
||||
|
||||
assert( ppStmt );
|
||||
*ppStmt = 0;
|
||||
@ -435,19 +515,35 @@ int sqlite3_prepare(
|
||||
return SQLITE_MISUSE;
|
||||
}
|
||||
|
||||
/* If any attached database schemas are locked, do not proceed with
|
||||
** compilation. Instead return SQLITE_LOCKED immediately.
|
||||
*/
|
||||
for(i=0; i<db->nDb; i++) {
|
||||
Btree *pBt = db->aDb[i].pBt;
|
||||
if( pBt && sqlite3BtreeSchemaLocked(pBt) ){
|
||||
const char *zDb = db->aDb[i].zName;
|
||||
sqlite3Error(db, SQLITE_LOCKED, "database schema is locked: %s", zDb);
|
||||
sqlite3SafetyOff(db);
|
||||
return SQLITE_LOCKED;
|
||||
}
|
||||
}
|
||||
|
||||
memset(&sParse, 0, sizeof(sParse));
|
||||
sParse.db = db;
|
||||
sqlite3RunParser(&sParse, zSql, &zErrMsg);
|
||||
if( nBytes>=0 && zSql[nBytes]!=0 ){
|
||||
char *zSqlCopy = sqlite3StrNDup(zSql, nBytes);
|
||||
sqlite3RunParser(&sParse, zSqlCopy, &zErrMsg);
|
||||
sParse.zTail += zSql - zSqlCopy;
|
||||
sqliteFree(zSqlCopy);
|
||||
}else{
|
||||
sqlite3RunParser(&sParse, zSql, &zErrMsg);
|
||||
}
|
||||
|
||||
if( sqlite3_malloc_failed ){
|
||||
rc = SQLITE_NOMEM;
|
||||
sqlite3RollbackAll(db);
|
||||
sqlite3ResetInternalSchema(db, 0);
|
||||
db->flags &= ~SQLITE_InTrans;
|
||||
goto prepare_out;
|
||||
if( sqlite3MallocFailed() ){
|
||||
sParse.rc = SQLITE_NOMEM;
|
||||
}
|
||||
if( sParse.rc==SQLITE_DONE ) sParse.rc = SQLITE_OK;
|
||||
if( sParse.rc!=SQLITE_OK && sParse.checkSchema && !schemaIsValid(db) ){
|
||||
if( sParse.checkSchema && !schemaIsValid(db) ){
|
||||
sParse.rc = SQLITE_SCHEMA;
|
||||
}
|
||||
if( sParse.rc==SQLITE_SCHEMA ){
|
||||
@ -474,7 +570,6 @@ int sqlite3_prepare(
|
||||
}
|
||||
#endif
|
||||
|
||||
prepare_out:
|
||||
if( sqlite3SafetyOff(db) ){
|
||||
rc = SQLITE_MISUSE;
|
||||
}
|
||||
@ -490,6 +585,9 @@ prepare_out:
|
||||
}else{
|
||||
sqlite3Error(db, rc, 0);
|
||||
}
|
||||
|
||||
rc = sqlite3ApiExit(db, rc);
|
||||
sqlite3ReleaseThreadData();
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -508,22 +606,17 @@ int sqlite3_prepare16(
|
||||
** encoded string to UTF-8, then invoking sqlite3_prepare(). The
|
||||
** tricky bit is figuring out the pointer to return in *pzTail.
|
||||
*/
|
||||
char const *zSql8 = 0;
|
||||
char const *zTail8 = 0;
|
||||
int rc;
|
||||
sqlite3_value *pTmp;
|
||||
char *zSql8;
|
||||
const char *zTail8 = 0;
|
||||
int rc = SQLITE_OK;
|
||||
|
||||
if( sqlite3SafetyCheck(db) ){
|
||||
return SQLITE_MISUSE;
|
||||
}
|
||||
pTmp = sqlite3GetTransientValue(db);
|
||||
sqlite3ValueSetStr(pTmp, -1, zSql, SQLITE_UTF16NATIVE, SQLITE_STATIC);
|
||||
zSql8 = sqlite3ValueText(pTmp, SQLITE_UTF8);
|
||||
if( !zSql8 ){
|
||||
sqlite3Error(db, SQLITE_NOMEM, 0);
|
||||
return SQLITE_NOMEM;
|
||||
zSql8 = sqlite3utf16to8(zSql, nBytes);
|
||||
if( zSql8 ){
|
||||
rc = sqlite3_prepare(db, zSql8, -1, ppStmt, &zTail8);
|
||||
}
|
||||
rc = sqlite3_prepare(db, zSql8, -1, ppStmt, &zTail8);
|
||||
|
||||
if( zTail8 && pzTail ){
|
||||
/* If sqlite3_prepare returns a tail pointer, we calculate the
|
||||
@ -534,7 +627,7 @@ int sqlite3_prepare16(
|
||||
int chars_parsed = sqlite3utf8CharLen(zSql8, zTail8-zSql8);
|
||||
*pzTail = (u8 *)zSql + sqlite3utf16ByteLen(zSql, chars_parsed);
|
||||
}
|
||||
|
||||
return rc;
|
||||
sqliteFree(zSql8);
|
||||
return sqlite3ApiExit(db, rc);
|
||||
}
|
||||
#endif /* SQLITE_OMIT_UTF16 */
|
||||
|
||||
@ -120,10 +120,12 @@ static const et_info fmtinfo[] = {
|
||||
{ 'u', 10, 0, etRADIX, 0, 0 },
|
||||
{ 'x', 16, 0, etRADIX, 16, 1 },
|
||||
{ 'X', 16, 0, etRADIX, 0, 4 },
|
||||
#ifndef SQLITE_OMIT_FLOATING_POINT
|
||||
{ 'f', 0, 1, etFLOAT, 0, 0 },
|
||||
{ 'e', 0, 1, etEXP, 30, 0 },
|
||||
{ 'E', 0, 1, etEXP, 14, 0 },
|
||||
{ 'G', 0, 1, etGENERIC, 14, 0 },
|
||||
#endif
|
||||
{ 'i', 10, 1, etRADIX, 0, 0 },
|
||||
{ 'n', 0, 0, etSIZE, 0, 0 },
|
||||
{ '%', 0, 0, etPERCENT, 0, 0 },
|
||||
@ -134,10 +136,10 @@ static const et_info fmtinfo[] = {
|
||||
#define etNINFO (sizeof(fmtinfo)/sizeof(fmtinfo[0]))
|
||||
|
||||
/*
|
||||
** If NOFLOATINGPOINT is defined, then none of the floating point
|
||||
** If SQLITE_OMIT_FLOATING_POINT is defined, then none of the floating point
|
||||
** conversions will work.
|
||||
*/
|
||||
#ifndef etNOFLOATINGPOINT
|
||||
#ifndef SQLITE_OMIT_FLOATING_POINT
|
||||
/*
|
||||
** "*val" is a double such that 0.1 <= *val < 10.0
|
||||
** Return the ascii code for the leading digit of *val, then
|
||||
@ -161,7 +163,7 @@ static int et_getdigit(LONGDOUBLE_TYPE *val, int *cnt){
|
||||
*val = (*val - d)*10.0;
|
||||
return digit;
|
||||
}
|
||||
#endif
|
||||
#endif /* SQLITE_OMIT_FLOATING_POINT */
|
||||
|
||||
/*
|
||||
** On machines with a small stack size, you can redefine the
|
||||
@ -234,7 +236,7 @@ static int vxprintf(
|
||||
static const char spaces[] =
|
||||
" ";
|
||||
#define etSPACESIZE (sizeof(spaces)-1)
|
||||
#ifndef etNOFLOATINGPOINT
|
||||
#ifndef SQLITE_OMIT_FLOATING_POINT
|
||||
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 */
|
||||
@ -425,7 +427,7 @@ static int vxprintf(
|
||||
case etEXP:
|
||||
case etGENERIC:
|
||||
realvalue = va_arg(ap,double);
|
||||
#ifndef etNOFLOATINGPOINT
|
||||
#ifndef SQLITE_OMIT_FLOATING_POINT
|
||||
if( precision<0 ) precision = 6; /* Set default precision */
|
||||
if( precision>etBUFSIZE/2-10 ) precision = etBUFSIZE/2-10;
|
||||
if( realvalue<0.0 ){
|
||||
@ -594,13 +596,13 @@ static int vxprintf(
|
||||
break;
|
||||
case etSQLESCAPE:
|
||||
case etSQLESCAPE2: {
|
||||
int i, j, n, c, isnull;
|
||||
int i, j, n, ch, 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++;
|
||||
char *escarg = va_arg(ap,char*);
|
||||
isnull = escarg==0;
|
||||
if( isnull ) escarg = (xtype==etSQLESCAPE2 ? "NULL" : "(NULL)");
|
||||
for(i=n=0; (ch=escarg[i])!=0; i++){
|
||||
if( ch=='\'' ) n++;
|
||||
}
|
||||
needQuote = !isnull && xtype==etSQLESCAPE2;
|
||||
n += i + 1 + needQuote*2;
|
||||
@ -612,9 +614,9 @@ static int vxprintf(
|
||||
}
|
||||
j = 0;
|
||||
if( needQuote ) bufpt[j++] = '\'';
|
||||
for(i=0; (c=arg[i])!=0; i++){
|
||||
bufpt[j++] = c;
|
||||
if( c=='\'' ) bufpt[j++] = c;
|
||||
for(i=0; (ch=escarg[i])!=0; i++){
|
||||
bufpt[j++] = ch;
|
||||
if( ch=='\'' ) bufpt[j++] = ch;
|
||||
}
|
||||
if( needQuote ) bufpt[j++] = '\'';
|
||||
bufpt[j] = 0;
|
||||
@ -625,7 +627,7 @@ static int vxprintf(
|
||||
case etTOKEN: {
|
||||
Token *pToken = va_arg(ap, Token*);
|
||||
if( pToken && pToken->z ){
|
||||
(*func)(arg, pToken->z, pToken->n);
|
||||
(*func)(arg, (char*)pToken->z, pToken->n);
|
||||
}
|
||||
length = width = 0;
|
||||
break;
|
||||
|
||||
@ -15,7 +15,7 @@
|
||||
** Random numbers are used by some of the database backends in order
|
||||
** to generate random integer keys for tables or random filenames.
|
||||
**
|
||||
** $Id: random.c,v 1.13 2005/06/12 21:35:52 drh Exp $
|
||||
** $Id: random.c,v 1.15 2006/01/06 14:32:20 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include "os.h"
|
||||
|
||||
@ -12,11 +12,28 @@
|
||||
** This file contains C code routines that are called by the parser
|
||||
** to handle SELECT statements in SQLite.
|
||||
**
|
||||
** $Id: select.c,v 1.276 2005/09/20 18:13:24 drh Exp $
|
||||
** $Id: select.c,v 1.301 2006/01/24 12:09:19 danielk1977 Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
|
||||
|
||||
/*
|
||||
** Delete all the content of a Select structure but do not deallocate
|
||||
** the select structure itself.
|
||||
*/
|
||||
static void clearSelect(Select *p){
|
||||
sqlite3ExprListDelete(p->pEList);
|
||||
sqlite3SrcListDelete(p->pSrc);
|
||||
sqlite3ExprDelete(p->pWhere);
|
||||
sqlite3ExprListDelete(p->pGroupBy);
|
||||
sqlite3ExprDelete(p->pHaving);
|
||||
sqlite3ExprListDelete(p->pOrderBy);
|
||||
sqlite3SelectDelete(p->pPrior);
|
||||
sqlite3ExprDelete(p->pLimit);
|
||||
sqlite3ExprDelete(p->pOffset);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Allocate a new Select structure and return a pointer to that
|
||||
** structure.
|
||||
@ -33,40 +50,48 @@ Select *sqlite3SelectNew(
|
||||
Expr *pOffset /* OFFSET value. NULL means no offset */
|
||||
){
|
||||
Select *pNew;
|
||||
Select standin;
|
||||
pNew = sqliteMalloc( sizeof(*pNew) );
|
||||
assert( !pOffset || pLimit ); /* Can't have OFFSET without LIMIT. */
|
||||
if( pNew==0 ){
|
||||
sqlite3ExprListDelete(pEList);
|
||||
sqlite3SrcListDelete(pSrc);
|
||||
sqlite3ExprDelete(pWhere);
|
||||
sqlite3ExprListDelete(pGroupBy);
|
||||
sqlite3ExprDelete(pHaving);
|
||||
sqlite3ExprListDelete(pOrderBy);
|
||||
sqlite3ExprDelete(pLimit);
|
||||
sqlite3ExprDelete(pOffset);
|
||||
}else{
|
||||
if( pEList==0 ){
|
||||
pEList = sqlite3ExprListAppend(0, sqlite3Expr(TK_ALL,0,0,0), 0);
|
||||
}
|
||||
pNew->pEList = pEList;
|
||||
pNew->pSrc = pSrc;
|
||||
pNew->pWhere = pWhere;
|
||||
pNew->pGroupBy = pGroupBy;
|
||||
pNew->pHaving = pHaving;
|
||||
pNew->pOrderBy = pOrderBy;
|
||||
pNew->isDistinct = isDistinct;
|
||||
pNew->op = TK_SELECT;
|
||||
pNew->pLimit = pLimit;
|
||||
pNew->pOffset = pOffset;
|
||||
pNew->iLimit = -1;
|
||||
pNew->iOffset = -1;
|
||||
pNew->addrOpenVirt[0] = -1;
|
||||
pNew->addrOpenVirt[1] = -1;
|
||||
pNew->addrOpenVirt[2] = -1;
|
||||
pNew = &standin;
|
||||
memset(pNew, 0, sizeof(*pNew));
|
||||
}
|
||||
if( pEList==0 ){
|
||||
pEList = sqlite3ExprListAppend(0, sqlite3Expr(TK_ALL,0,0,0), 0);
|
||||
}
|
||||
pNew->pEList = pEList;
|
||||
pNew->pSrc = pSrc;
|
||||
pNew->pWhere = pWhere;
|
||||
pNew->pGroupBy = pGroupBy;
|
||||
pNew->pHaving = pHaving;
|
||||
pNew->pOrderBy = pOrderBy;
|
||||
pNew->isDistinct = isDistinct;
|
||||
pNew->op = TK_SELECT;
|
||||
pNew->pLimit = pLimit;
|
||||
pNew->pOffset = pOffset;
|
||||
pNew->iLimit = -1;
|
||||
pNew->iOffset = -1;
|
||||
pNew->addrOpenVirt[0] = -1;
|
||||
pNew->addrOpenVirt[1] = -1;
|
||||
pNew->addrOpenVirt[2] = -1;
|
||||
if( pNew==&standin) {
|
||||
clearSelect(pNew);
|
||||
pNew = 0;
|
||||
}
|
||||
return pNew;
|
||||
}
|
||||
|
||||
/*
|
||||
** Delete the given Select structure and all of its substructures.
|
||||
*/
|
||||
void sqlite3SelectDelete(Select *p){
|
||||
if( p ){
|
||||
clearSelect(p);
|
||||
sqliteFree(p);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Given 1 to 3 identifiers preceeding the JOIN keyword, determine the
|
||||
** type of join. Return an integer constant that expresses that type
|
||||
@ -109,7 +134,7 @@ int sqlite3JoinType(Parse *pParse, Token *pA, Token *pB, Token *pC){
|
||||
p = apAll[i];
|
||||
for(j=0; j<sizeof(keywords)/sizeof(keywords[0]); j++){
|
||||
if( p->n==keywords[j].nChar
|
||||
&& sqlite3StrNICmp(p->z, keywords[j].zKeyword, p->n)==0 ){
|
||||
&& sqlite3StrNICmp((char*)p->z, keywords[j].zKeyword, p->n)==0 ){
|
||||
jointype |= keywords[j].code;
|
||||
break;
|
||||
}
|
||||
@ -154,8 +179,8 @@ static int columnIndex(Table *pTab, const char *zCol){
|
||||
** Set the value of a token to a '\000'-terminated string.
|
||||
*/
|
||||
static void setToken(Token *p, const char *z){
|
||||
p->z = z;
|
||||
p->n = strlen(z);
|
||||
p->z = (u8*)z;
|
||||
p->n = z ? strlen(z) : 0;
|
||||
p->dyn = 0;
|
||||
}
|
||||
|
||||
@ -330,59 +355,53 @@ static int sqliteProcessJoin(Parse *pParse, Select *p){
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Delete the given Select structure and all of its substructures.
|
||||
*/
|
||||
void sqlite3SelectDelete(Select *p){
|
||||
if( p==0 ) return;
|
||||
sqlite3ExprListDelete(p->pEList);
|
||||
sqlite3SrcListDelete(p->pSrc);
|
||||
sqlite3ExprDelete(p->pWhere);
|
||||
sqlite3ExprListDelete(p->pGroupBy);
|
||||
sqlite3ExprDelete(p->pHaving);
|
||||
sqlite3ExprListDelete(p->pOrderBy);
|
||||
sqlite3SelectDelete(p->pPrior);
|
||||
sqlite3ExprDelete(p->pLimit);
|
||||
sqlite3ExprDelete(p->pOffset);
|
||||
sqliteFree(p);
|
||||
}
|
||||
|
||||
/*
|
||||
** Insert code into "v" that will push the record on the top of the
|
||||
** stack into the sorter.
|
||||
*/
|
||||
static void pushOntoSorter(Parse *pParse, Vdbe *v, ExprList *pOrderBy){
|
||||
static void pushOntoSorter(
|
||||
Parse *pParse, /* Parser context */
|
||||
ExprList *pOrderBy, /* The ORDER BY clause */
|
||||
Select *pSelect /* The whole SELECT statement */
|
||||
){
|
||||
Vdbe *v = pParse->pVdbe;
|
||||
sqlite3ExprCodeExprList(pParse, pOrderBy);
|
||||
sqlite3VdbeAddOp(v, OP_Sequence, pOrderBy->iECursor, 0);
|
||||
sqlite3VdbeAddOp(v, OP_Pull, pOrderBy->nExpr + 1, 0);
|
||||
sqlite3VdbeAddOp(v, OP_MakeRecord, pOrderBy->nExpr + 2, 0);
|
||||
sqlite3VdbeAddOp(v, OP_IdxInsert, pOrderBy->iECursor, 0);
|
||||
if( pSelect->iLimit>=0 ){
|
||||
int addr1, addr2;
|
||||
addr1 = sqlite3VdbeAddOp(v, OP_IfMemZero, pSelect->iLimit+1, 0);
|
||||
sqlite3VdbeAddOp(v, OP_MemIncr, -1, pSelect->iLimit+1);
|
||||
addr2 = sqlite3VdbeAddOp(v, OP_Goto, 0, 0);
|
||||
sqlite3VdbeJumpHere(v, addr1);
|
||||
sqlite3VdbeAddOp(v, OP_Last, pOrderBy->iECursor, 0);
|
||||
sqlite3VdbeAddOp(v, OP_Delete, pOrderBy->iECursor, 0);
|
||||
sqlite3VdbeJumpHere(v, addr2);
|
||||
pSelect->iLimit = -1;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Add code to implement the OFFSET and LIMIT
|
||||
** Add code to implement the OFFSET
|
||||
*/
|
||||
static void codeLimiter(
|
||||
static void codeOffset(
|
||||
Vdbe *v, /* Generate code into this VM */
|
||||
Select *p, /* The SELECT statement being coded */
|
||||
int iContinue, /* Jump here to skip the current record */
|
||||
int iBreak, /* Jump here to end the loop */
|
||||
int nPop /* Number of times to pop stack when jumping */
|
||||
){
|
||||
if( p->iOffset>=0 && iContinue!=0 ){
|
||||
int addr = sqlite3VdbeCurrentAddr(v) + 3;
|
||||
if( nPop>0 ) addr++;
|
||||
sqlite3VdbeAddOp(v, OP_MemIncr, p->iOffset, 0);
|
||||
sqlite3VdbeAddOp(v, OP_IfMemPos, p->iOffset, addr);
|
||||
int addr;
|
||||
sqlite3VdbeAddOp(v, OP_MemIncr, -1, p->iOffset);
|
||||
addr = sqlite3VdbeAddOp(v, OP_IfMemNeg, p->iOffset, 0);
|
||||
if( nPop>0 ){
|
||||
sqlite3VdbeAddOp(v, OP_Pop, nPop, 0);
|
||||
}
|
||||
sqlite3VdbeAddOp(v, OP_Goto, 0, iContinue);
|
||||
VdbeComment((v, "# skip OFFSET records"));
|
||||
}
|
||||
if( p->iLimit>=0 && iBreak!=0 ){
|
||||
sqlite3VdbeAddOp(v, OP_MemIncr, p->iLimit, iBreak);
|
||||
VdbeComment((v, "# exit when LIMIT reached"));
|
||||
sqlite3VdbeJumpHere(v, addr);
|
||||
}
|
||||
}
|
||||
|
||||
@ -447,9 +466,9 @@ static int selectInnerLoop(
|
||||
/* If there was a LIMIT clause on the SELECT statement, then do the check
|
||||
** to see if this row should be output.
|
||||
*/
|
||||
hasDistinct = distinct>=0 && pEList && pEList->nExpr>0;
|
||||
hasDistinct = distinct>=0 && pEList->nExpr>0;
|
||||
if( pOrderBy==0 && !hasDistinct ){
|
||||
codeLimiter(v, p, iContinue, iBreak, 0);
|
||||
codeOffset(v, p, iContinue, 0);
|
||||
}
|
||||
|
||||
/* Pull the requested columns.
|
||||
@ -471,7 +490,7 @@ static int selectInnerLoop(
|
||||
int n = pEList->nExpr;
|
||||
codeDistinct(v, distinct, iContinue, n, n+1);
|
||||
if( pOrderBy==0 ){
|
||||
codeLimiter(v, p, iContinue, iBreak, nColumn);
|
||||
codeOffset(v, p, iContinue, nColumn);
|
||||
}
|
||||
}
|
||||
|
||||
@ -509,7 +528,7 @@ static int selectInnerLoop(
|
||||
case SRT_VirtualTab: {
|
||||
sqlite3VdbeAddOp(v, OP_MakeRecord, nColumn, 0);
|
||||
if( pOrderBy ){
|
||||
pushOntoSorter(pParse, v, pOrderBy);
|
||||
pushOntoSorter(pParse, pOrderBy, p);
|
||||
}else{
|
||||
sqlite3VdbeAddOp(v, OP_NewRowid, iParm, 0);
|
||||
sqlite3VdbeAddOp(v, OP_Pull, 1, 0);
|
||||
@ -536,29 +555,37 @@ static int selectInnerLoop(
|
||||
** ORDER BY in this case since the order of entries in the set
|
||||
** does not matter. But there might be a LIMIT clause, in which
|
||||
** case the order does matter */
|
||||
pushOntoSorter(pParse, v, pOrderBy);
|
||||
pushOntoSorter(pParse, pOrderBy, p);
|
||||
}else{
|
||||
char aff = (iParm>>16)&0xFF;
|
||||
aff = sqlite3CompareAffinity(pEList->a[0].pExpr, aff);
|
||||
sqlite3VdbeOp3(v, OP_MakeRecord, 1, 0, &aff, 1);
|
||||
char affinity = (iParm>>16)&0xFF;
|
||||
affinity = sqlite3CompareAffinity(pEList->a[0].pExpr, affinity);
|
||||
sqlite3VdbeOp3(v, OP_MakeRecord, 1, 0, &affinity, 1);
|
||||
sqlite3VdbeAddOp(v, OP_IdxInsert, (iParm&0x0000FFFF), 0);
|
||||
}
|
||||
sqlite3VdbeJumpHere(v, addr2);
|
||||
break;
|
||||
}
|
||||
|
||||
/* If any row exist in the result set, record that fact and abort.
|
||||
*/
|
||||
case SRT_Exists: {
|
||||
sqlite3VdbeAddOp(v, OP_MemInt, 1, iParm);
|
||||
sqlite3VdbeAddOp(v, OP_Pop, nColumn, 0);
|
||||
/* The LIMIT clause will terminate the loop for us */
|
||||
break;
|
||||
}
|
||||
|
||||
/* If this is a scalar select that is part of an expression, then
|
||||
** store the results in the appropriate memory cell and break out
|
||||
** of the scan loop.
|
||||
*/
|
||||
case SRT_Exists:
|
||||
case SRT_Mem: {
|
||||
assert( nColumn==1 );
|
||||
if( pOrderBy ){
|
||||
pushOntoSorter(pParse, v, pOrderBy);
|
||||
pushOntoSorter(pParse, pOrderBy, p);
|
||||
}else{
|
||||
sqlite3VdbeAddOp(v, OP_MemStore, iParm, 1);
|
||||
sqlite3VdbeAddOp(v, OP_Goto, 0, iBreak);
|
||||
/* The LIMIT clause will jump out of the loop for us */
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -572,7 +599,7 @@ static int selectInnerLoop(
|
||||
case SRT_Callback: {
|
||||
if( pOrderBy ){
|
||||
sqlite3VdbeAddOp(v, OP_MakeRecord, nColumn, 0);
|
||||
pushOntoSorter(pParse, v, pOrderBy);
|
||||
pushOntoSorter(pParse, pOrderBy, p);
|
||||
}else if( eDest==SRT_Subroutine ){
|
||||
sqlite3VdbeAddOp(v, OP_Gosub, 0, iParm);
|
||||
}else{
|
||||
@ -594,6 +621,13 @@ static int selectInnerLoop(
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Jump to the end of the loop if the LIMIT is reached.
|
||||
*/
|
||||
if( p->iLimit>=0 && pOrderBy==0 ){
|
||||
sqlite3VdbeAddOp(v, OP_MemIncr, -1, p->iLimit);
|
||||
sqlite3VdbeAddOp(v, OP_IfMemZero, p->iLimit, iBreak);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -622,9 +656,9 @@ static KeyInfo *keyInfoFromExprList(Parse *pParse, ExprList *pList){
|
||||
nExpr = pList->nExpr;
|
||||
pInfo = sqliteMalloc( sizeof(*pInfo) + nExpr*(sizeof(CollSeq*)+1) );
|
||||
if( pInfo ){
|
||||
pInfo->aSortOrder = (char*)&pInfo->aColl[nExpr];
|
||||
pInfo->aSortOrder = (u8*)&pInfo->aColl[nExpr];
|
||||
pInfo->nField = nExpr;
|
||||
pInfo->enc = db->enc;
|
||||
pInfo->enc = ENC(db);
|
||||
for(i=0, pItem=pList->a; i<nExpr; i++, pItem++){
|
||||
CollSeq *pColl;
|
||||
pColl = sqlite3ExprCollSeq(pParse, pItem->pExpr);
|
||||
@ -661,7 +695,7 @@ static void generateSortTail(
|
||||
|
||||
iTab = pOrderBy->iECursor;
|
||||
addr = 1 + sqlite3VdbeAddOp(v, OP_Sort, iTab, brk);
|
||||
codeLimiter(v, p, cont, brk, 0);
|
||||
codeOffset(v, p, cont, 0);
|
||||
sqlite3VdbeAddOp(v, OP_Column, iTab, pOrderBy->nExpr + 1);
|
||||
switch( eDest ){
|
||||
case SRT_Table:
|
||||
@ -677,15 +711,14 @@ static void generateSortTail(
|
||||
sqlite3VdbeAddOp(v, OP_NotNull, -1, sqlite3VdbeCurrentAddr(v)+3);
|
||||
sqlite3VdbeAddOp(v, OP_Pop, 1, 0);
|
||||
sqlite3VdbeAddOp(v, OP_Goto, 0, sqlite3VdbeCurrentAddr(v)+3);
|
||||
sqlite3VdbeOp3(v, OP_MakeRecord, 1, 0, "n", P3_STATIC);
|
||||
sqlite3VdbeOp3(v, OP_MakeRecord, 1, 0, "c", P3_STATIC);
|
||||
sqlite3VdbeAddOp(v, OP_IdxInsert, (iParm&0x0000FFFF), 0);
|
||||
break;
|
||||
}
|
||||
case SRT_Exists:
|
||||
case SRT_Mem: {
|
||||
assert( nColumn==1 );
|
||||
sqlite3VdbeAddOp(v, OP_MemStore, iParm, 1);
|
||||
sqlite3VdbeAddOp(v, OP_Goto, 0, brk);
|
||||
/* The LIMIT clause will terminate the loop for us */
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
@ -710,6 +743,16 @@ static void generateSortTail(
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Jump to the end of the loop when the LIMIT is reached
|
||||
*/
|
||||
if( p->iLimit>=0 ){
|
||||
sqlite3VdbeAddOp(v, OP_MemIncr, -1, p->iLimit);
|
||||
sqlite3VdbeAddOp(v, OP_IfMemZero, p->iLimit, brk);
|
||||
}
|
||||
|
||||
/* The bottom of the loop
|
||||
*/
|
||||
sqlite3VdbeResolveLabel(v, cont);
|
||||
sqlite3VdbeAddOp(v, OP_Next, iTab, addr);
|
||||
sqlite3VdbeResolveLabel(v, brk);
|
||||
@ -837,7 +880,7 @@ static void generateColumnNames(
|
||||
#endif
|
||||
|
||||
assert( v!=0 );
|
||||
if( pParse->colNamesSet || v==0 || sqlite3_malloc_failed ) return;
|
||||
if( pParse->colNamesSet || v==0 || sqlite3MallocFailed() ) return;
|
||||
pParse->colNamesSet = 1;
|
||||
fullNames = (db->flags & SQLITE_FullColNames)!=0;
|
||||
shortNames = (db->flags & SQLITE_ShortColNames)!=0;
|
||||
@ -866,20 +909,20 @@ static void generateColumnNames(
|
||||
zCol = pTab->aCol[iCol].zName;
|
||||
}
|
||||
if( !shortNames && !fullNames && p->span.z && p->span.z[0] ){
|
||||
sqlite3VdbeSetColName(v, i, p->span.z, p->span.n);
|
||||
sqlite3VdbeSetColName(v, i, (char*)p->span.z, p->span.n);
|
||||
}else if( fullNames || (!shortNames && pTabList->nSrc>1) ){
|
||||
char *zName = 0;
|
||||
char *zTab;
|
||||
|
||||
zTab = pTabList->a[j].zAlias;
|
||||
if( fullNames || zTab==0 ) zTab = pTab->zName;
|
||||
sqlite3SetString(&zName, zTab, ".", zCol, 0);
|
||||
sqlite3SetString(&zName, zTab, ".", zCol, (char*)0);
|
||||
sqlite3VdbeSetColName(v, i, zName, P3_DYNAMIC);
|
||||
}else{
|
||||
sqlite3VdbeSetColName(v, i, zCol, strlen(zCol));
|
||||
}
|
||||
}else if( p->span.z && p->span.z[0] ){
|
||||
sqlite3VdbeSetColName(v, i, p->span.z, p->span.n);
|
||||
sqlite3VdbeSetColName(v, i, (char*)p->span.z, p->span.n);
|
||||
/* sqlite3VdbeCompressSpace(v, addr); */
|
||||
}else{
|
||||
char zName[30];
|
||||
@ -943,6 +986,7 @@ Table *sqlite3ResultSetOfSelect(Parse *pParse, char *zTabName, Select *pSelect){
|
||||
char *zType;
|
||||
char *zName;
|
||||
char *zBasename;
|
||||
CollSeq *pColl;
|
||||
int cnt;
|
||||
NameContext sNC;
|
||||
|
||||
@ -965,7 +1009,7 @@ Table *sqlite3ResultSetOfSelect(Parse *pParse, char *zTabName, Select *pSelect){
|
||||
zName = sqlite3MPrintf("column%d", i+1);
|
||||
}
|
||||
sqlite3Dequote(zName);
|
||||
if( sqlite3_malloc_failed ){
|
||||
if( sqlite3MallocFailed() ){
|
||||
sqliteFree(zName);
|
||||
sqlite3DeleteTable(0, pTab);
|
||||
return 0;
|
||||
@ -995,9 +1039,9 @@ Table *sqlite3ResultSetOfSelect(Parse *pParse, char *zTabName, Select *pSelect){
|
||||
zType = sqliteStrDup(columnType(&sNC, p));
|
||||
pCol->zType = zType;
|
||||
pCol->affinity = sqlite3ExprAffinity(p);
|
||||
pCol->pColl = sqlite3ExprCollSeq(pParse, p);
|
||||
if( !pCol->pColl ){
|
||||
pCol->pColl = pParse->db->pDfltColl;
|
||||
pColl = sqlite3ExprCollSeq(pParse, p);
|
||||
if( pColl ){
|
||||
pCol->zColl = sqliteStrDup(pColl->zName);
|
||||
}
|
||||
}
|
||||
pTab->iPKey = -1;
|
||||
@ -1034,10 +1078,11 @@ static int prepSelectStmt(Parse *pParse, Select *p){
|
||||
int i, j, k, rc;
|
||||
SrcList *pTabList;
|
||||
ExprList *pEList;
|
||||
Table *pTab;
|
||||
struct SrcList_item *pFrom;
|
||||
|
||||
if( p==0 || p->pSrc==0 || sqlite3_malloc_failed ) return 1;
|
||||
if( p==0 || p->pSrc==0 || sqlite3MallocFailed() ){
|
||||
return 1;
|
||||
}
|
||||
pTabList = p->pSrc;
|
||||
pEList = p->pEList;
|
||||
|
||||
@ -1051,6 +1096,7 @@ static int prepSelectStmt(Parse *pParse, Select *p){
|
||||
** then create a transient table structure to describe the subquery.
|
||||
*/
|
||||
for(i=0, pFrom=pTabList->a; i<pTabList->nSrc; i++, pFrom++){
|
||||
Table *pTab;
|
||||
if( pFrom->pTab!=0 ){
|
||||
/* This statement has already been prepared. There is no need
|
||||
** to go further. */
|
||||
@ -1145,7 +1191,11 @@ static int prepSelectStmt(Parse *pParse, Select *p){
|
||||
/* This particular expression does not need to be expanded.
|
||||
*/
|
||||
pNew = sqlite3ExprListAppend(pNew, a[k].pExpr, 0);
|
||||
pNew->a[pNew->nExpr-1].zName = a[k].zName;
|
||||
if( pNew ){
|
||||
pNew->a[pNew->nExpr-1].zName = a[k].zName;
|
||||
}else{
|
||||
rc = 1;
|
||||
}
|
||||
a[k].pExpr = 0;
|
||||
a[k].zName = 0;
|
||||
}else{
|
||||
@ -1170,7 +1220,7 @@ static int prepSelectStmt(Parse *pParse, Select *p){
|
||||
}
|
||||
tableSeen = 1;
|
||||
for(j=0; j<pTab->nCol; j++){
|
||||
Expr *pExpr, *pLeft, *pRight;
|
||||
Expr *pExpr, *pRight;
|
||||
char *zName = pTab->aCol[j].zName;
|
||||
|
||||
if( i>0 ){
|
||||
@ -1191,7 +1241,7 @@ static int prepSelectStmt(Parse *pParse, Select *p){
|
||||
if( pRight==0 ) break;
|
||||
setToken(&pRight->token, zName);
|
||||
if( zTabName && (longNames || pTabList->nSrc>1) ){
|
||||
pLeft = sqlite3Expr(TK_ID, 0, 0, 0);
|
||||
Expr *pLeft = sqlite3Expr(TK_ID, 0, 0, 0);
|
||||
pExpr = sqlite3Expr(TK_DOT, pLeft, pRight, 0);
|
||||
if( pExpr==0 ) break;
|
||||
setToken(&pLeft->token, zTabName);
|
||||
@ -1326,25 +1376,31 @@ Vdbe *sqlite3GetVdbe(Parse *pParse){
|
||||
return v;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Compute the iLimit and iOffset fields of the SELECT based on the
|
||||
** pLimit and pOffset expressions. nLimit and nOffset hold the expressions
|
||||
** pLimit and pOffset expressions. pLimit and pOffset hold the expressions
|
||||
** that appear in the original SQL statement after the LIMIT and OFFSET
|
||||
** keywords. Or NULL if those keywords are omitted. iLimit and iOffset
|
||||
** are the integer memory register numbers for counters used to compute
|
||||
** the limit and offset. If there is no limit and/or offset, then
|
||||
** iLimit and iOffset are negative.
|
||||
**
|
||||
** This routine changes the values if iLimit and iOffset only if
|
||||
** a limit or offset is defined by nLimit and nOffset. iLimit and
|
||||
** This routine changes the values of iLimit and iOffset only if
|
||||
** a limit or offset is defined by pLimit and pOffset. iLimit and
|
||||
** iOffset should have been preset to appropriate default values
|
||||
** (usually but not always -1) prior to calling this routine.
|
||||
** Only if nLimit>=0 or nOffset>0 do the limit registers get
|
||||
** Only if pLimit!=0 or pOffset!=0 do the limit registers get
|
||||
** redefined. The UNION ALL operator uses this property to force
|
||||
** the reuse of the same limit and offset registers across multiple
|
||||
** SELECT statements.
|
||||
*/
|
||||
static void computeLimitRegisters(Parse *pParse, Select *p){
|
||||
static void computeLimitRegisters(Parse *pParse, Select *p, int iBreak){
|
||||
Vdbe *v = 0;
|
||||
int iLimit = 0;
|
||||
int iOffset;
|
||||
int addr1, addr2;
|
||||
|
||||
/*
|
||||
** "LIMIT -1" always shows all rows. There is some
|
||||
** contraversy about what the correct behavior should be.
|
||||
@ -1352,26 +1408,41 @@ static void computeLimitRegisters(Parse *pParse, Select *p){
|
||||
** no rows.
|
||||
*/
|
||||
if( p->pLimit ){
|
||||
int iMem = pParse->nMem++;
|
||||
Vdbe *v = sqlite3GetVdbe(pParse);
|
||||
p->iLimit = iLimit = pParse->nMem;
|
||||
pParse->nMem += 2;
|
||||
v = sqlite3GetVdbe(pParse);
|
||||
if( v==0 ) return;
|
||||
sqlite3ExprCode(pParse, p->pLimit);
|
||||
sqlite3VdbeAddOp(v, OP_MustBeInt, 0, 0);
|
||||
sqlite3VdbeAddOp(v, OP_Negative, 0, 0);
|
||||
sqlite3VdbeAddOp(v, OP_MemStore, iMem, 1);
|
||||
sqlite3VdbeAddOp(v, OP_MemStore, iLimit, 0);
|
||||
VdbeComment((v, "# LIMIT counter"));
|
||||
p->iLimit = iMem;
|
||||
sqlite3VdbeAddOp(v, OP_IfMemZero, iLimit, iBreak);
|
||||
}
|
||||
if( p->pOffset ){
|
||||
int iMem = pParse->nMem++;
|
||||
Vdbe *v = sqlite3GetVdbe(pParse);
|
||||
p->iOffset = iOffset = pParse->nMem++;
|
||||
v = sqlite3GetVdbe(pParse);
|
||||
if( v==0 ) return;
|
||||
sqlite3ExprCode(pParse, p->pOffset);
|
||||
sqlite3VdbeAddOp(v, OP_MustBeInt, 0, 0);
|
||||
sqlite3VdbeAddOp(v, OP_Negative, 0, 0);
|
||||
sqlite3VdbeAddOp(v, OP_MemStore, iMem, 1);
|
||||
sqlite3VdbeAddOp(v, OP_MemStore, iOffset, p->pLimit==0);
|
||||
VdbeComment((v, "# OFFSET counter"));
|
||||
p->iOffset = iMem;
|
||||
addr1 = sqlite3VdbeAddOp(v, OP_IfMemPos, iOffset, 0);
|
||||
sqlite3VdbeAddOp(v, OP_Pop, 1, 0);
|
||||
sqlite3VdbeAddOp(v, OP_Integer, 0, 0);
|
||||
sqlite3VdbeJumpHere(v, addr1);
|
||||
if( p->pLimit ){
|
||||
sqlite3VdbeAddOp(v, OP_Add, 0, 0);
|
||||
}
|
||||
}
|
||||
if( p->pLimit ){
|
||||
addr1 = sqlite3VdbeAddOp(v, OP_IfMemPos, iLimit, 0);
|
||||
sqlite3VdbeAddOp(v, OP_Pop, 1, 0);
|
||||
sqlite3VdbeAddOp(v, OP_MemInt, -1, iLimit+1);
|
||||
addr2 = sqlite3VdbeAddOp(v, OP_Goto, 0, 0);
|
||||
sqlite3VdbeJumpHere(v, addr1);
|
||||
sqlite3VdbeAddOp(v, OP_MemStore, iLimit+1, 1);
|
||||
VdbeComment((v, "# LIMIT+OFFSET"));
|
||||
sqlite3VdbeJumpHere(v, addr2);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1519,23 +1590,31 @@ static int multiSelect(
|
||||
switch( p->op ){
|
||||
case TK_ALL: {
|
||||
if( pOrderBy==0 ){
|
||||
int addr = 0;
|
||||
assert( !pPrior->pLimit );
|
||||
pPrior->pLimit = p->pLimit;
|
||||
pPrior->pOffset = p->pOffset;
|
||||
rc = sqlite3Select(pParse, pPrior, eDest, iParm, 0, 0, 0, aff);
|
||||
p->pLimit = 0;
|
||||
p->pOffset = 0;
|
||||
if( rc ){
|
||||
goto multi_select_end;
|
||||
}
|
||||
p->pPrior = 0;
|
||||
p->iLimit = pPrior->iLimit;
|
||||
p->iOffset = pPrior->iOffset;
|
||||
p->pLimit = 0;
|
||||
p->pOffset = 0;
|
||||
if( p->iLimit>=0 ){
|
||||
addr = sqlite3VdbeAddOp(v, OP_IfMemZero, p->iLimit, 0);
|
||||
VdbeComment((v, "# Jump ahead if LIMIT reached"));
|
||||
}
|
||||
rc = sqlite3Select(pParse, p, eDest, iParm, 0, 0, 0, aff);
|
||||
p->pPrior = pPrior;
|
||||
if( rc ){
|
||||
goto multi_select_end;
|
||||
}
|
||||
if( addr ){
|
||||
sqlite3VdbeJumpHere(v, addr);
|
||||
}
|
||||
break;
|
||||
}
|
||||
/* For UNION ALL ... ORDER BY fall through to the next case */
|
||||
@ -1622,8 +1701,8 @@ static int multiSelect(
|
||||
}
|
||||
iBreak = sqlite3VdbeMakeLabel(v);
|
||||
iCont = sqlite3VdbeMakeLabel(v);
|
||||
computeLimitRegisters(pParse, p, iBreak);
|
||||
sqlite3VdbeAddOp(v, OP_Rewind, unionTab, iBreak);
|
||||
computeLimitRegisters(pParse, p);
|
||||
iStart = sqlite3VdbeCurrentAddr(v);
|
||||
rc = selectInnerLoop(pParse, p, p->pEList, unionTab, p->pEList->nExpr,
|
||||
pOrderBy, -1, eDest, iParm,
|
||||
@ -1698,8 +1777,8 @@ static int multiSelect(
|
||||
}
|
||||
iBreak = sqlite3VdbeMakeLabel(v);
|
||||
iCont = sqlite3VdbeMakeLabel(v);
|
||||
computeLimitRegisters(pParse, p, iBreak);
|
||||
sqlite3VdbeAddOp(v, OP_Rewind, tab1, iBreak);
|
||||
computeLimitRegisters(pParse, p);
|
||||
iStart = sqlite3VdbeAddOp(v, OP_RowKey, tab1, 0);
|
||||
sqlite3VdbeAddOp(v, OP_NotFound, tab2, iCont);
|
||||
rc = selectInnerLoop(pParse, p, p->pEList, tab1, p->pEList->nExpr,
|
||||
@ -1760,7 +1839,7 @@ static int multiSelect(
|
||||
goto multi_select_end;
|
||||
}
|
||||
|
||||
pKeyInfo->enc = pParse->db->enc;
|
||||
pKeyInfo->enc = ENC(pParse->db);
|
||||
pKeyInfo->nField = nCol;
|
||||
|
||||
for(i=0, apColl=pKeyInfo->aColl; i<nCol; i++, apColl++){
|
||||
@ -1786,15 +1865,15 @@ static int multiSelect(
|
||||
|
||||
if( pOrderBy ){
|
||||
struct ExprList_item *pOTerm = pOrderBy->a;
|
||||
int nExpr = pOrderBy->nExpr;
|
||||
int nOrderByExpr = pOrderBy->nExpr;
|
||||
int addr;
|
||||
u8 *pSortOrder;
|
||||
|
||||
aCopy = (CollSeq**)&pKeyInfo[1];
|
||||
pSortOrder = pKeyInfo->aSortOrder = (u8*)&aCopy[nExpr];
|
||||
aCopy = &pKeyInfo->aColl[nCol];
|
||||
pSortOrder = pKeyInfo->aSortOrder = (u8*)&aCopy[nCol];
|
||||
memcpy(aCopy, pKeyInfo->aColl, nCol*sizeof(CollSeq*));
|
||||
apColl = pKeyInfo->aColl;
|
||||
for(i=0; i<pOrderBy->nExpr; i++, pOTerm++, apColl++, pSortOrder++){
|
||||
for(i=0; i<nOrderByExpr; i++, pOTerm++, apColl++, pSortOrder++){
|
||||
Expr *pExpr = pOTerm->pExpr;
|
||||
char *zName = pOTerm->zName;
|
||||
assert( pExpr->op==TK_COLUMN && pExpr->iColumn<nCol );
|
||||
@ -1809,7 +1888,7 @@ static int multiSelect(
|
||||
assert( p->addrOpenVirt[2]>=0 );
|
||||
addr = p->addrOpenVirt[2];
|
||||
sqlite3VdbeChangeP2(v, addr, p->pEList->nExpr+2);
|
||||
pKeyInfo->nField = pOrderBy->nExpr;
|
||||
pKeyInfo->nField = nOrderByExpr;
|
||||
sqlite3VdbeChangeP3(v, addr, (char*)pKeyInfo, P3_KEYINFO_HANDOFF);
|
||||
pKeyInfo = 0;
|
||||
generateSortTail(pParse, p, v, p->pEList->nExpr, eDest, iParm);
|
||||
@ -1949,6 +2028,10 @@ static void substSelect(Select *p, int iTable, ExprList *pEList){
|
||||
** (12) The subquery is not the right term of a LEFT OUTER JOIN or the
|
||||
** subquery has no WHERE clause. (added by ticket #350)
|
||||
**
|
||||
** (13) The subquery and outer query do not both use LIMIT
|
||||
**
|
||||
** (14) The subquery does not use OFFSET
|
||||
**
|
||||
** In this routine, the "p" parameter is a pointer to the outer query.
|
||||
** The subquery is p->pSrc->a[iFrom]. isAgg is true if the outer query
|
||||
** uses aggregates and subqueryIsAgg is true if the subquery uses aggregates.
|
||||
@ -1983,18 +2066,26 @@ static int flattenSubquery(
|
||||
pSubitem = &pSrc->a[iFrom];
|
||||
pSub = pSubitem->pSelect;
|
||||
assert( pSub!=0 );
|
||||
if( isAgg && subqueryIsAgg ) return 0;
|
||||
if( subqueryIsAgg && pSrc->nSrc>1 ) return 0;
|
||||
if( isAgg && subqueryIsAgg ) return 0; /* Restriction (1) */
|
||||
if( subqueryIsAgg && pSrc->nSrc>1 ) return 0; /* Restriction (2) */
|
||||
pSubSrc = pSub->pSrc;
|
||||
assert( pSubSrc );
|
||||
if( (pSub->pLimit && p->pLimit) || pSub->pOffset ||
|
||||
(pSub->pLimit && isAgg) ) return 0;
|
||||
if( pSubSrc->nSrc==0 ) return 0;
|
||||
if( pSub->isDistinct && (pSrc->nSrc>1 || isAgg) ){
|
||||
return 0;
|
||||
/* Prior to version 3.1.2, when LIMIT and OFFSET had to be simple constants,
|
||||
** not arbitrary expresssions, we allowed some combining of LIMIT and OFFSET
|
||||
** because they could be computed at compile-time. But when LIMIT and OFFSET
|
||||
** became arbitrary expressions, we were forced to add restrictions (13)
|
||||
** and (14). */
|
||||
if( pSub->pLimit && p->pLimit ) return 0; /* Restriction (13) */
|
||||
if( pSub->pOffset ) return 0; /* Restriction (14) */
|
||||
if( pSubSrc->nSrc==0 ) return 0; /* Restriction (7) */
|
||||
if( (pSub->isDistinct || pSub->pLimit)
|
||||
&& (pSrc->nSrc>1 || isAgg) ){ /* Restrictions (4)(5)(8)(9) */
|
||||
return 0;
|
||||
}
|
||||
if( p->isDistinct && subqueryIsAgg ) return 0; /* Restriction (6) */
|
||||
if( (p->disallowOrderBy || p->pOrderBy) && pSub->pOrderBy ){
|
||||
return 0; /* Restriction (11) */
|
||||
}
|
||||
if( p->isDistinct && subqueryIsAgg ) return 0;
|
||||
if( (p->disallowOrderBy || p->pOrderBy) && pSub->pOrderBy ) return 0;
|
||||
|
||||
/* Restriction 3: If the subquery is a join, make sure the subquery is
|
||||
** not used as the right operand of an outer join. Examples of why this
|
||||
@ -2085,7 +2176,7 @@ static int flattenSubquery(
|
||||
for(i=0; i<pList->nExpr; i++){
|
||||
Expr *pExpr;
|
||||
if( pList->a[i].zName==0 && (pExpr = pList->a[i].pExpr)->span.z!=0 ){
|
||||
pList->a[i].zName = sqliteStrNDup(pExpr->span.z, pExpr->span.n);
|
||||
pList->a[i].zName = sqliteStrNDup((char*)pExpr->span.z, pExpr->span.n);
|
||||
}
|
||||
}
|
||||
if( isAgg ){
|
||||
@ -2124,6 +2215,9 @@ static int flattenSubquery(
|
||||
|
||||
/*
|
||||
** SELECT ... FROM (SELECT ... LIMIT a OFFSET b) LIMIT x OFFSET y;
|
||||
**
|
||||
** One is tempted to try to add a and b to combine the limits. But this
|
||||
** does not work if either limit is negative.
|
||||
*/
|
||||
if( pSub->pLimit ){
|
||||
p->pLimit = pSub->pLimit;
|
||||
@ -2166,10 +2260,11 @@ static int simpleMinMaxQuery(Parse *pParse, Select *p, int eDest, int iParm){
|
||||
int base;
|
||||
Vdbe *v;
|
||||
int seekOp;
|
||||
int cont;
|
||||
ExprList *pEList, *pList, eList;
|
||||
struct ExprList_item eListItem;
|
||||
SrcList *pSrc;
|
||||
int brk;
|
||||
int iDb;
|
||||
|
||||
/* Check to see if this query is a simple min() or max() query. Return
|
||||
** zero if it is not.
|
||||
@ -2184,9 +2279,9 @@ static int simpleMinMaxQuery(Parse *pParse, Select *p, int eDest, int iParm){
|
||||
pList = pExpr->pList;
|
||||
if( pList==0 || pList->nExpr!=1 ) return 0;
|
||||
if( pExpr->token.n!=3 ) return 0;
|
||||
if( sqlite3StrNICmp(pExpr->token.z,"min",3)==0 ){
|
||||
if( sqlite3StrNICmp((char*)pExpr->token.z,"min",3)==0 ){
|
||||
seekOp = OP_Rewind;
|
||||
}else if( sqlite3StrNICmp(pExpr->token.z,"max",3)==0 ){
|
||||
}else if( sqlite3StrNICmp((char*)pExpr->token.z,"max",3)==0 ){
|
||||
seekOp = OP_Last;
|
||||
}else{
|
||||
return 0;
|
||||
@ -2196,6 +2291,7 @@ static int simpleMinMaxQuery(Parse *pParse, Select *p, int eDest, int iParm){
|
||||
iCol = pExpr->iColumn;
|
||||
pTab = pSrc->a[0].pTab;
|
||||
|
||||
|
||||
/* If we get to here, it means the query is of the correct form.
|
||||
** Check to make sure we have an index and make pIdx point to the
|
||||
** appropriate index. If the min() or max() is on an INTEGER PRIMARY
|
||||
@ -2208,7 +2304,10 @@ static int simpleMinMaxQuery(Parse *pParse, Select *p, int eDest, int iParm){
|
||||
CollSeq *pColl = sqlite3ExprCollSeq(pParse, pExpr);
|
||||
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
|
||||
assert( pIdx->nColumn>=1 );
|
||||
if( pIdx->aiColumn[0]==iCol && pIdx->keyInfo.aColl[0]==pColl ) break;
|
||||
if( pIdx->aiColumn[0]==iCol &&
|
||||
0==sqlite3StrICmp(pIdx->azColl[0], pColl->zName) ){
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( pIdx==0 ) return 0;
|
||||
}
|
||||
@ -2231,13 +2330,16 @@ static int simpleMinMaxQuery(Parse *pParse, Select *p, int eDest, int iParm){
|
||||
** the min() or max() is on the INTEGER PRIMARY KEY, then find the first
|
||||
** or last entry in the main table.
|
||||
*/
|
||||
sqlite3CodeVerifySchema(pParse, pTab->iDb);
|
||||
iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
|
||||
assert( iDb>=0 || pTab->isTransient );
|
||||
sqlite3CodeVerifySchema(pParse, iDb);
|
||||
sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName);
|
||||
base = pSrc->a[0].iCursor;
|
||||
computeLimitRegisters(pParse, p);
|
||||
brk = sqlite3VdbeMakeLabel(v);
|
||||
computeLimitRegisters(pParse, p, brk);
|
||||
if( pSrc->a[0].pSelect==0 ){
|
||||
sqlite3OpenTableForReading(v, base, pTab);
|
||||
sqlite3OpenTable(pParse, base, iDb, pTab, OP_OpenRead);
|
||||
}
|
||||
cont = sqlite3VdbeMakeLabel(v);
|
||||
if( pIdx==0 ){
|
||||
sqlite3VdbeAddOp(v, seekOp, base, 0);
|
||||
}else{
|
||||
@ -2248,10 +2350,12 @@ static int simpleMinMaxQuery(Parse *pParse, Select *p, int eDest, int iParm){
|
||||
** "INSERT INTO x SELECT max() FROM x".
|
||||
*/
|
||||
int iIdx;
|
||||
KeyInfo *pKey = sqlite3IndexKeyinfo(pParse, pIdx);
|
||||
iIdx = pParse->nTab++;
|
||||
sqlite3VdbeAddOp(v, OP_Integer, pIdx->iDb, 0);
|
||||
sqlite3VdbeOp3(v, OP_OpenRead, iIdx, pIdx->tnum,
|
||||
(char*)&pIdx->keyInfo, P3_KEYINFO);
|
||||
assert( pIdx->pSchema==pTab->pSchema );
|
||||
sqlite3VdbeAddOp(v, OP_Integer, iDb, 0);
|
||||
sqlite3VdbeOp3(v, OP_OpenRead, iIdx, pIdx->tnum,
|
||||
(char*)pKey, P3_KEYINFO_HANDOFF);
|
||||
if( seekOp==OP_Rewind ){
|
||||
sqlite3VdbeAddOp(v, OP_Null, 0, 0);
|
||||
sqlite3VdbeAddOp(v, OP_MakeRecord, 1, 0);
|
||||
@ -2266,8 +2370,8 @@ static int simpleMinMaxQuery(Parse *pParse, Select *p, int eDest, int iParm){
|
||||
memset(&eListItem, 0, sizeof(eListItem));
|
||||
eList.a = &eListItem;
|
||||
eList.a[0].pExpr = pExpr;
|
||||
selectInnerLoop(pParse, p, &eList, 0, 0, 0, -1, eDest, iParm, cont, cont, 0);
|
||||
sqlite3VdbeResolveLabel(v, cont);
|
||||
selectInnerLoop(pParse, p, &eList, 0, 0, 0, -1, eDest, iParm, brk, brk, 0);
|
||||
sqlite3VdbeResolveLabel(v, brk);
|
||||
sqlite3VdbeAddOp(v, OP_Close, base, 0);
|
||||
|
||||
return 1;
|
||||
@ -2356,14 +2460,8 @@ int sqlite3SelectResolve(
|
||||
/* Resolve the expressions in the LIMIT and OFFSET clauses. These
|
||||
** are not allowed to refer to any names, so pass an empty NameContext.
|
||||
*/
|
||||
memset(&sNC, 0, sizeof(sNC));
|
||||
sNC.pParse = pParse;
|
||||
sNC.hasAgg = 0;
|
||||
sNC.nErr = 0;
|
||||
sNC.nRef = 0;
|
||||
sNC.pEList = 0;
|
||||
sNC.allowAgg = 0;
|
||||
sNC.pSrcList = 0;
|
||||
sNC.pNext = 0;
|
||||
if( sqlite3ExprResolveNames(&sNC, p->pLimit) ||
|
||||
sqlite3ExprResolveNames(&sNC, p->pOffset) ){
|
||||
return SQLITE_ERROR;
|
||||
@ -2615,8 +2713,11 @@ int sqlite3Select(
|
||||
int rc = 1; /* Value to return from this function */
|
||||
int addrSortIndex; /* Address of an OP_OpenVirtual instruction */
|
||||
AggInfo sAggInfo; /* Information used by aggregate queries */
|
||||
int iEnd; /* Address of the end of the query */
|
||||
|
||||
if( sqlite3_malloc_failed || pParse->nErr || p==0 ) return 1;
|
||||
if( p==0 || sqlite3MallocFailed() || pParse->nErr ){
|
||||
return 1;
|
||||
}
|
||||
if( sqlite3AuthCheck(pParse, SQLITE_SELECT, 0, 0, 0) ) return 1;
|
||||
memset(&sAggInfo, 0, sizeof(sAggInfo));
|
||||
|
||||
@ -2663,7 +2764,6 @@ int sqlite3Select(
|
||||
/* If writing to memory or generating a set
|
||||
** only a single column may be output.
|
||||
*/
|
||||
assert( eDest!=SRT_Exists || pEList->nExpr==1 );
|
||||
#ifndef SQLITE_OMIT_SUBQUERY
|
||||
if( (eDest==SRT_Mem || eDest==SRT_Set) && pEList->nExpr>1 ){
|
||||
sqlite3ErrorMsg(pParse, "only a single result allowed for "
|
||||
@ -2772,7 +2872,8 @@ int sqlite3Select(
|
||||
|
||||
/* Set the limiter.
|
||||
*/
|
||||
computeLimitRegisters(pParse, p);
|
||||
iEnd = sqlite3VdbeMakeLabel(v);
|
||||
computeLimitRegisters(pParse, p, iEnd);
|
||||
|
||||
/* If the output is destined for a temporary table, open that table.
|
||||
*/
|
||||
@ -2780,15 +2881,6 @@ int sqlite3Select(
|
||||
sqlite3VdbeAddOp(v, OP_OpenVirtual, iParm, pEList->nExpr);
|
||||
}
|
||||
|
||||
|
||||
/* Initialize the memory cell to NULL for SRT_Mem or 0 for SRT_Exists
|
||||
*/
|
||||
if( eDest==SRT_Mem ){
|
||||
sqlite3VdbeAddOp(v, OP_MemNull, iParm, 0);
|
||||
}else if( eDest==SRT_Exists ){
|
||||
sqlite3VdbeAddOp(v, OP_MemInt, 0, iParm);
|
||||
}
|
||||
|
||||
/* Open a virtual index to use for the distinct set.
|
||||
*/
|
||||
if( isDistinct ){
|
||||
@ -2879,7 +2971,7 @@ int sqlite3Select(
|
||||
goto select_end;
|
||||
}
|
||||
}
|
||||
if( sqlite3_malloc_failed ) goto select_end;
|
||||
if( sqlite3MallocFailed() ) goto select_end;
|
||||
|
||||
/* Processing for aggregates with GROUP BY is very different and
|
||||
** much more complex tha aggregates without a GROUP BY.
|
||||
@ -3112,6 +3204,10 @@ int sqlite3Select(
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Jump here to skip this query
|
||||
*/
|
||||
sqlite3VdbeResolveLabel(v, iEnd);
|
||||
|
||||
/* The SELECT was successfully coded. Set the return code to 0
|
||||
** to indicate no errors.
|
||||
*/
|
||||
|
||||
@ -12,7 +12,7 @@
|
||||
** This file contains code to implement the "sqlite" command line
|
||||
** utility for accessing SQLite databases.
|
||||
**
|
||||
** $Id: shell.c,v 1.128 2005/09/11 02:03:04 drh Exp $
|
||||
** $Id: shell.c,v 1.131 2006/01/25 15:55:38 drh Exp $
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@ -81,7 +81,7 @@ static char continuePrompt[20]; /* Continuation prompt. default: " ...> " */
|
||||
/*
|
||||
** Determines if a string is a number of not.
|
||||
*/
|
||||
static int isNumber(const unsigned char *z, int *realnum){
|
||||
static int isNumber(const char *z, int *realnum){
|
||||
if( *z=='-' || *z=='+' ) z++;
|
||||
if( !isdigit(*z) ){
|
||||
return 0;
|
||||
@ -690,8 +690,9 @@ static int dump_callback(void *pArg, int nArg, char **azArg, char **azCol){
|
||||
zSelect = appendText(zSelect, " || ' VALUES(' || ", 0);
|
||||
rc = sqlite3_step(pTableInfo);
|
||||
while( rc==SQLITE_ROW ){
|
||||
const char *zText = (const char *)sqlite3_column_text(pTableInfo, 1);
|
||||
zSelect = appendText(zSelect, "quote(", 0);
|
||||
zSelect = appendText(zSelect, sqlite3_column_text(pTableInfo, 1), '"');
|
||||
zSelect = appendText(zSelect, zText, '"');
|
||||
rc = sqlite3_step(pTableInfo);
|
||||
if( rc==SQLITE_ROW ){
|
||||
zSelect = appendText(zSelect, ") || ', ' || ", 0);
|
||||
@ -773,9 +774,6 @@ static char zHelp[] =
|
||||
".prompt MAIN CONTINUE Replace the standard prompts\n"
|
||||
".quit Exit this program\n"
|
||||
".read FILENAME Execute SQL in FILENAME\n"
|
||||
#ifdef SQLITE_HAS_CODEC
|
||||
".rekey OLD NEW NEW Change the encryption key\n"
|
||||
#endif
|
||||
".schema ?TABLE? Show the CREATE statements\n"
|
||||
".separator STRING Change separator used by output mode and .import\n"
|
||||
".show Show the current values for various settings\n"
|
||||
@ -795,9 +793,6 @@ static void open_db(struct callback_data *p){
|
||||
if( p->db==0 ){
|
||||
sqlite3_open(p->zDbFilename, &p->db);
|
||||
db = p->db;
|
||||
#ifdef SQLITE_HAS_CODEC
|
||||
sqlite3_key(p->db, p->zKey, p->zKey ? strlen(p->zKey) : 0);
|
||||
#endif
|
||||
sqlite3_create_function(db, "shellstatic", 0, SQLITE_UTF8, 0,
|
||||
shellstaticFunc, 0, 0);
|
||||
if( SQLITE_OK!=sqlite3_errcode(db) ){
|
||||
@ -829,7 +824,7 @@ static void resolve_backslashes(char *z){
|
||||
}else if( c=='r' ){
|
||||
c = '\r';
|
||||
}else if( c>='0' && c<='7' ){
|
||||
c =- '0';
|
||||
c -= '0';
|
||||
if( z[i+1]>='0' && z[i+1]<='7' ){
|
||||
i++;
|
||||
c = (c<<3) + z[i] - '0';
|
||||
@ -1226,22 +1221,6 @@ static int do_meta_command(char *zLine, struct callback_data *p){
|
||||
}
|
||||
}else
|
||||
|
||||
#ifdef SQLITE_HAS_CODEC
|
||||
if( c=='r' && strncmp(azArg[0],"rekey", n)==0 && nArg==4 ){
|
||||
char *zOld = p->zKey;
|
||||
if( zOld==0 ) zOld = "";
|
||||
if( strcmp(azArg[1],zOld) ){
|
||||
fprintf(stderr,"old key is incorrect\n");
|
||||
}else if( strcmp(azArg[2], azArg[3]) ){
|
||||
fprintf(stderr,"2nd copy of new key does not match the 1st\n");
|
||||
}else{
|
||||
sqlite3_free(p->zKey);
|
||||
p->zKey = sqlite3_mprintf("%s", azArg[2]);
|
||||
sqlite3_rekey(p->db, p->zKey, strlen(p->zKey));
|
||||
}
|
||||
}else
|
||||
#endif
|
||||
|
||||
if( c=='s' && strncmp(azArg[0], "schema", n)==0 ){
|
||||
struct callback_data data;
|
||||
char *zErrMsg = 0;
|
||||
@ -1619,9 +1598,6 @@ static const char zOptions[] =
|
||||
" -[no]header turn headers on or off\n"
|
||||
" -column set output mode to 'column'\n"
|
||||
" -html set output mode to HTML\n"
|
||||
#ifdef SQLITE_HAS_CODEC
|
||||
" -key KEY encryption key\n"
|
||||
#endif
|
||||
" -line set output mode to 'line'\n"
|
||||
" -list set output mode to 'list'\n"
|
||||
" -separator 'x' set output field separator (|)\n"
|
||||
|
||||
@ -12,7 +12,7 @@
|
||||
** This header file defines the interface that the SQLite library
|
||||
** presents to client programs.
|
||||
**
|
||||
** @(#) $Id: sqlite.h.in,v 1.141 2005/09/08 10:58:52 drh Exp $
|
||||
** @(#) $Id: sqlite.h.in,v 1.156 2006/01/12 02:50:10 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.7"
|
||||
#define SQLITE_VERSION "3.3.3"
|
||||
|
||||
/*
|
||||
** 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 3002007
|
||||
#define SQLITE_VERSION_NUMBER 3003003
|
||||
|
||||
/*
|
||||
** The version string is also compiled into the library so that a program
|
||||
@ -86,6 +86,13 @@ typedef struct sqlite3 sqlite3;
|
||||
typedef unsigned long long int sqlite_uint64;
|
||||
#endif
|
||||
|
||||
/*
|
||||
** If compiling for a processor that lacks floating point support,
|
||||
** substitute integer for floating-point
|
||||
*/
|
||||
#ifdef SQLITE_OMIT_FLOATING_POINT
|
||||
# define double sqlite_int64
|
||||
#endif
|
||||
|
||||
/*
|
||||
** A function to close the database.
|
||||
@ -185,6 +192,7 @@ int sqlite3_exec(
|
||||
#define SQLITE_NOTADB 26 /* File opened that is not a database file */
|
||||
#define SQLITE_ROW 100 /* sqlite3_step() has another row ready */
|
||||
#define SQLITE_DONE 101 /* sqlite3_step() has finished executing */
|
||||
/* end-of-return-codes */
|
||||
|
||||
/*
|
||||
** Each entry in an SQLite table has a unique integer key. (The key is
|
||||
@ -1251,7 +1259,7 @@ extern char *sqlite3_temp_directory;
|
||||
** This functionality can be omitted from a build by defining the
|
||||
** SQLITE_OMIT_GLOBALRECOVER at compile time.
|
||||
*/
|
||||
int sqlite3_global_recover();
|
||||
int sqlite3_global_recover(void);
|
||||
|
||||
/*
|
||||
** Test to see whether or not the database connection is in autocommit
|
||||
@ -1269,6 +1277,106 @@ int sqlite3_get_autocommit(sqlite3*);
|
||||
*/
|
||||
sqlite3 *sqlite3_db_handle(sqlite3_stmt*);
|
||||
|
||||
/*
|
||||
** Register a callback function with the database connection identified by the
|
||||
** first argument to be invoked whenever a row is updated, inserted or deleted.
|
||||
** Any callback set by a previous call to this function for the same
|
||||
** database connection is overridden.
|
||||
**
|
||||
** The second argument is a pointer to the function to invoke when a
|
||||
** row is updated, inserted or deleted. The first argument to the callback is
|
||||
** a copy of the third argument to sqlite3_update_hook. The second callback
|
||||
** argument is one of SQLITE_INSERT, SQLITE_DELETE or SQLITE_UPDATE, depending
|
||||
** on the operation that caused the callback to be invoked. The third and
|
||||
** fourth arguments to the callback contain pointers to the database and
|
||||
** table name containing the affected row. The final callback parameter is
|
||||
** the rowid of the row. In the case of an update, this is the rowid after
|
||||
** the update takes place.
|
||||
**
|
||||
** The update hook is not invoked when internal system tables are
|
||||
** modified (i.e. sqlite_master and sqlite_sequence).
|
||||
**
|
||||
** If another function was previously registered, its pArg value is returned.
|
||||
** Otherwise NULL is returned.
|
||||
*/
|
||||
void *sqlite3_update_hook(
|
||||
sqlite3*,
|
||||
void(*)(void *,int ,char const *,char const *,sqlite_int64),
|
||||
void*
|
||||
);
|
||||
|
||||
/*
|
||||
** Register a callback to be invoked whenever a transaction is rolled
|
||||
** back.
|
||||
**
|
||||
** The new callback function overrides any existing rollback-hook
|
||||
** callback. If there was an existing callback, then it's pArg value
|
||||
** (the third argument to sqlite3_rollback_hook() when it was registered)
|
||||
** is returned. Otherwise, NULL is returned.
|
||||
**
|
||||
** For the purposes of this API, a transaction is said to have been
|
||||
** rolled back if an explicit "ROLLBACK" statement is executed, or
|
||||
** an error or constraint causes an implicit rollback to occur. The
|
||||
** callback is not invoked if a transaction is automatically rolled
|
||||
** back because the database connection is closed.
|
||||
*/
|
||||
void *sqlite3_rollback_hook(sqlite3*, void(*)(void *), void*);
|
||||
|
||||
/*
|
||||
** This function is only available if the library is compiled without
|
||||
** the SQLITE_OMIT_SHARED_CACHE macro defined. It is used to enable or
|
||||
** disable (if the argument is true or false, respectively) the
|
||||
** "shared pager" feature.
|
||||
*/
|
||||
int sqlite3_enable_shared_cache(int);
|
||||
|
||||
/*
|
||||
** Attempt to free N bytes of heap memory by deallocating non-essential
|
||||
** memory allocations held by the database library (example: memory
|
||||
** used to cache database pages to improve performance).
|
||||
**
|
||||
** This function is not a part of standard builds. It is only created
|
||||
** if SQLite is compiled with the SQLITE_ENABLE_MEMORY_MANAGEMENT macro.
|
||||
*/
|
||||
int sqlite3_release_memory(int);
|
||||
|
||||
/*
|
||||
** Place a "soft" limit on the amount of heap memory that may be allocated by
|
||||
** SQLite within the current thread. If an internal allocation is requested
|
||||
** that would exceed the specified limit, sqlite3_release_memory() is invoked
|
||||
** one or more times to free up some space before the allocation is made.
|
||||
**
|
||||
** The limit is called "soft", because if sqlite3_release_memory() cannot free
|
||||
** sufficient memory to prevent the limit from being exceeded, the memory is
|
||||
** allocated anyway and the current operation proceeds.
|
||||
**
|
||||
** This function is only available if the library was compiled with the
|
||||
** SQLITE_ENABLE_MEMORY_MANAGEMENT option set.
|
||||
** memory-management has been enabled.
|
||||
*/
|
||||
void sqlite3_soft_heap_limit(int);
|
||||
|
||||
/*
|
||||
** This routine makes sure that all thread-local storage has been
|
||||
** deallocated for the current thread.
|
||||
**
|
||||
** This routine is not technically necessary. All thread-local storage
|
||||
** will be automatically deallocated once memory-management and
|
||||
** shared-cache are disabled and the soft heap limit has been set
|
||||
** to zero. This routine is provided as a convenience for users who
|
||||
** want to make absolutely sure they have not forgotten something
|
||||
** prior to killing off a thread.
|
||||
*/
|
||||
void sqlite3_thread_cleanup(void);
|
||||
|
||||
/*
|
||||
** Undo the hack that converts floating point types to integer for
|
||||
** builds on processors without floating point support.
|
||||
*/
|
||||
#ifdef SQLITE_OMIT_FLOATING_POINT
|
||||
# undef double
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Given a wildcard parameter name, return the set of indexes of the
|
||||
** variables with that name. If there are no variables with the given
|
||||
|
||||
@ -11,11 +11,18 @@
|
||||
*************************************************************************
|
||||
** Internal interface definitions for SQLite.
|
||||
**
|
||||
** @(#) $Id: sqliteInt.h,v 1.421 2005/09/19 21:05:49 drh Exp $
|
||||
** @(#) $Id: sqliteInt.h,v 1.479 2006/01/24 16:37:58 danielk1977 Exp $
|
||||
*/
|
||||
#ifndef _SQLITEINT_H_
|
||||
#define _SQLITEINT_H_
|
||||
|
||||
/*
|
||||
** Extra interface definitions for those who need them
|
||||
*/
|
||||
#ifdef SQLITE_EXTRA
|
||||
# include "sqliteExtra.h"
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Many people are failing to set -DNDEBUG=1 when compiling SQLite.
|
||||
** Setting NDEBUG makes the code smaller and run faster. So the following
|
||||
@ -23,7 +30,7 @@
|
||||
** option is set. Thus NDEBUG becomes an opt-in rather than an opt-out
|
||||
** feature.
|
||||
*/
|
||||
#if !defined(NDEBUG) && !defined(SQLITE_DEBUG)
|
||||
#if !defined(NDEBUG) && !defined(SQLITE_DEBUG)
|
||||
# define NDEBUG 1
|
||||
#endif
|
||||
|
||||
@ -50,8 +57,6 @@
|
||||
# define _LARGEFILE_SOURCE 1
|
||||
#endif
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "sqlite3.h"
|
||||
#include "hash.h"
|
||||
#include "parse.h"
|
||||
@ -61,6 +66,23 @@
|
||||
#include <assert.h>
|
||||
#include <stddef.h>
|
||||
|
||||
/*
|
||||
** If compiling for a processor that lacks floating point support,
|
||||
** substitute integer for floating-point
|
||||
*/
|
||||
#ifdef SQLITE_OMIT_FLOATING_POINT
|
||||
# define double sqlite_int64
|
||||
# define LONGDOUBLE_TYPE sqlite_int64
|
||||
# ifndef SQLITE_BIG_DBL
|
||||
# define SQLITE_BIG_DBL (0x7fffffffffffffff)
|
||||
# endif
|
||||
# define SQLITE_OMIT_DATETIME_FUNCS 1
|
||||
# define SQLITE_OMIT_TRACE 1
|
||||
#endif
|
||||
#ifndef SQLITE_BIG_DBL
|
||||
# define SQLITE_BIG_DBL (1e99)
|
||||
#endif
|
||||
|
||||
/*
|
||||
** The maximum number of in-memory pages to use for the main database
|
||||
** table and for temporary tables. Internally, the MAX_PAGES and
|
||||
@ -131,18 +153,15 @@
|
||||
#define SQLITE_MAX_VARIABLE_NUMBER 999
|
||||
|
||||
/*
|
||||
** When building SQLite for embedded systems where memory is scarce,
|
||||
** you can define one or more of the following macros to omit extra
|
||||
** features of the library and thus keep the size of the library to
|
||||
** a minimum.
|
||||
** The "file format" number is an integer that is incremented whenever
|
||||
** the VDBE-level file format changes. The following macros define the
|
||||
** the default file format for new databases and the maximum file format
|
||||
** that the library can read.
|
||||
*/
|
||||
/* #define SQLITE_OMIT_AUTHORIZATION 1 */
|
||||
/* #define SQLITE_OMIT_MEMORYDB 1 */
|
||||
/* #define SQLITE_OMIT_VACUUM 1 */
|
||||
/* #define SQLITE_OMIT_DATETIME_FUNCS 1 */
|
||||
/* #define SQLITE_OMIT_PROGRESS_CALLBACK 1 */
|
||||
/* #define SQLITE_OMIT_AUTOVACUUM */
|
||||
/* #define SQLITE_OMIT_ALTERTABLE */
|
||||
#define SQLITE_MAX_FILE_FORMAT 4
|
||||
#ifndef SQLITE_DEFAULT_FILE_FORMAT
|
||||
# define SQLITE_DEFAULT_FILE_FORMAT 4
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Provide a default value for TEMP_STORE in case it is not specified
|
||||
@ -230,6 +249,7 @@ struct BusyHandler {
|
||||
*/
|
||||
#include "vdbe.h"
|
||||
#include "btree.h"
|
||||
#include "pager.h"
|
||||
|
||||
/*
|
||||
** This macro casts a pointer to an integer. Useful for doing
|
||||
@ -237,53 +257,66 @@ struct BusyHandler {
|
||||
*/
|
||||
#define Addr(X) ((uptr)X)
|
||||
|
||||
/*
|
||||
** If memory allocation problems are found, recompile with
|
||||
**
|
||||
** -DSQLITE_DEBUG=1
|
||||
**
|
||||
** to enable some sanity checking on malloc() and free(). To
|
||||
** check for memory leaks, recompile with
|
||||
**
|
||||
** -DSQLITE_DEBUG=2
|
||||
**
|
||||
** and a line of text will be written to standard error for
|
||||
** each malloc() and free(). This output can be analyzed
|
||||
** by an AWK script to determine if there are any leaks.
|
||||
*/
|
||||
#ifdef SQLITE_MEMDEBUG
|
||||
# define sqliteMalloc(X) sqlite3Malloc_(X,1,__FILE__,__LINE__)
|
||||
# define sqliteMallocRaw(X) sqlite3Malloc_(X,0,__FILE__,__LINE__)
|
||||
# define sqliteFree(X) sqlite3Free_(X,__FILE__,__LINE__)
|
||||
# define sqliteRealloc(X,Y) sqlite3Realloc_(X,Y,__FILE__,__LINE__)
|
||||
# define sqliteStrDup(X) sqlite3StrDup_(X,__FILE__,__LINE__)
|
||||
# define sqliteStrNDup(X,Y) sqlite3StrNDup_(X,Y,__FILE__,__LINE__)
|
||||
#else
|
||||
# define sqliteFree sqlite3FreeX
|
||||
# define sqliteMalloc sqlite3Malloc
|
||||
# define sqliteMallocRaw sqlite3MallocRaw
|
||||
# define sqliteRealloc sqlite3Realloc
|
||||
# define sqliteStrDup sqlite3StrDup
|
||||
# define sqliteStrNDup sqlite3StrNDup
|
||||
#endif
|
||||
|
||||
/*
|
||||
** This variable gets set if malloc() ever fails. After it gets set,
|
||||
** the SQLite library shuts down permanently.
|
||||
*/
|
||||
extern int sqlite3_malloc_failed;
|
||||
|
||||
/*
|
||||
** The following global variables are used for testing and debugging
|
||||
** only. They only work if SQLITE_DEBUG is defined.
|
||||
** only. They only work if SQLITE_MEMDEBUG is defined.
|
||||
*/
|
||||
#ifdef SQLITE_MEMDEBUG
|
||||
extern int sqlite3_nMalloc; /* Number of sqliteMalloc() calls */
|
||||
extern int sqlite3_nFree; /* Number of sqliteFree() calls */
|
||||
extern int sqlite3_iMallocFail; /* Fail sqliteMalloc() after this many calls */
|
||||
extern int sqlite3_iMallocReset; /* Set iMallocFail to this when it reaches 0 */
|
||||
|
||||
|
||||
extern void *sqlite3_pFirst; /* Pointer to linked list of allocations */
|
||||
extern int sqlite3_nMaxAlloc; /* High water mark of ThreadData.nAlloc */
|
||||
extern int sqlite3_mallocDisallowed; /* assert() in sqlite3Malloc() if set */
|
||||
extern int sqlite3_isFail; /* True if all malloc calls should fail */
|
||||
extern const char *sqlite3_zFile; /* Filename to associate debug info with */
|
||||
extern int sqlite3_iLine; /* Line number for debug info */
|
||||
|
||||
#define ENTER_MALLOC (sqlite3_zFile = __FILE__, sqlite3_iLine = __LINE__)
|
||||
#define sqliteMalloc(x) (ENTER_MALLOC, sqlite3Malloc(x))
|
||||
#define sqliteMallocRaw(x) (ENTER_MALLOC, sqlite3MallocRaw(x))
|
||||
#define sqliteRealloc(x,y) (ENTER_MALLOC, sqlite3Realloc(x,y))
|
||||
#define sqliteStrDup(x) (ENTER_MALLOC, sqlite3StrDup(x))
|
||||
#define sqliteStrNDup(x,y) (ENTER_MALLOC, sqlite3StrNDup(x,y))
|
||||
#define sqliteReallocOrFree(x,y) (ENTER_MALLOC, sqlite3ReallocOrFree(x,y))
|
||||
|
||||
#else
|
||||
|
||||
#define sqliteMalloc(x) sqlite3Malloc(x)
|
||||
#define sqliteMallocRaw(x) sqlite3MallocRaw(x)
|
||||
#define sqliteRealloc(x,y) sqlite3Realloc(x,y)
|
||||
#define sqliteStrDup(x) sqlite3StrDup(x)
|
||||
#define sqliteStrNDup(x,y) sqlite3StrNDup(x,y)
|
||||
#define sqliteReallocOrFree(x,y) sqlite3ReallocOrFree(x,y)
|
||||
|
||||
#endif
|
||||
|
||||
#define sqliteFree(x) sqlite3FreeX(x)
|
||||
#define sqliteAllocSize(x) sqlite3AllocSize(x)
|
||||
|
||||
|
||||
/*
|
||||
** An instance of this structure might be allocated to store information
|
||||
** specific to a single thread.
|
||||
*/
|
||||
struct ThreadData {
|
||||
int dummy; /* So that this structure is never empty */
|
||||
|
||||
#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
|
||||
int nSoftHeapLimit; /* Suggested max mem allocation. No limit if <0 */
|
||||
int nAlloc; /* Number of bytes currently allocated */
|
||||
Pager *pPager; /* Linked list of all pagers in this thread */
|
||||
#endif
|
||||
|
||||
#ifndef SQLITE_OMIT_SHARED_CACHE
|
||||
u8 useSharedData; /* True if shared pagers and schemas are enabled */
|
||||
BtShared *pBtree; /* Linked list of all currently open BTrees */
|
||||
#endif
|
||||
};
|
||||
|
||||
/*
|
||||
** Name of the master database table. The master database table
|
||||
** is a special table that holds the names and attributes of all
|
||||
@ -316,6 +349,7 @@ typedef struct AuthContext AuthContext;
|
||||
typedef struct CollSeq CollSeq;
|
||||
typedef struct Column Column;
|
||||
typedef struct Db Db;
|
||||
typedef struct Schema Schema;
|
||||
typedef struct Expr Expr;
|
||||
typedef struct ExprList ExprList;
|
||||
typedef struct FKey FKey;
|
||||
@ -328,7 +362,9 @@ typedef struct NameContext NameContext;
|
||||
typedef struct Parse Parse;
|
||||
typedef struct Select Select;
|
||||
typedef struct SrcList SrcList;
|
||||
typedef struct ThreadData ThreadData;
|
||||
typedef struct Table Table;
|
||||
typedef struct TableLock TableLock;
|
||||
typedef struct Token Token;
|
||||
typedef struct TriggerStack TriggerStack;
|
||||
typedef struct TriggerStep TriggerStep;
|
||||
@ -346,28 +382,37 @@ typedef struct WhereLevel WhereLevel;
|
||||
struct Db {
|
||||
char *zName; /* Name of this database */
|
||||
Btree *pBt; /* The B*Tree structure for this database file */
|
||||
u8 inTrans; /* 0: not writable. 1: Transaction. 2: Checkpoint */
|
||||
u8 safety_level; /* How aggressive at synching data to disk */
|
||||
void *pAux; /* Auxiliary data. Usually NULL */
|
||||
void (*xFreeAux)(void*); /* Routine to free pAux */
|
||||
Schema *pSchema; /* Pointer to database schema (possibly shared) */
|
||||
};
|
||||
|
||||
/*
|
||||
** An instance of the following structure stores a database schema.
|
||||
*/
|
||||
struct Schema {
|
||||
int schema_cookie; /* Database schema version number for this file */
|
||||
Hash tblHash; /* All tables indexed by name */
|
||||
Hash idxHash; /* All (named) indices indexed by name */
|
||||
Hash trigHash; /* All triggers indexed by name */
|
||||
Hash aFKey; /* Foreign keys indexed by to-table */
|
||||
u16 flags; /* Flags associated with this database */
|
||||
u8 inTrans; /* 0: not writable. 1: Transaction. 2: Checkpoint */
|
||||
u8 safety_level; /* How aggressive at synching data to disk */
|
||||
int cache_size; /* Number of pages to use in the cache */
|
||||
Table *pSeqTab; /* The sqlite_sequence table used by AUTOINCREMENT */
|
||||
void *pAux; /* Auxiliary data. Usually NULL */
|
||||
void (*xFreeAux)(void*); /* Routine to free pAux */
|
||||
u8 file_format; /* Schema format version for this file */
|
||||
u8 enc; /* Text encoding used by this database */
|
||||
u16 flags; /* Flags associated with this schema */
|
||||
int cache_size; /* Number of pages to use in the cache */
|
||||
};
|
||||
|
||||
/*
|
||||
** These macros can be used to test, set, or clear bits in the
|
||||
** Db.flags field.
|
||||
*/
|
||||
#define DbHasProperty(D,I,P) (((D)->aDb[I].flags&(P))==(P))
|
||||
#define DbHasAnyProperty(D,I,P) (((D)->aDb[I].flags&(P))!=0)
|
||||
#define DbSetProperty(D,I,P) (D)->aDb[I].flags|=(P)
|
||||
#define DbClearProperty(D,I,P) (D)->aDb[I].flags&=~(P)
|
||||
#define DbHasProperty(D,I,P) (((D)->aDb[I].pSchema->flags&(P))==(P))
|
||||
#define DbHasAnyProperty(D,I,P) (((D)->aDb[I].pSchema->flags&(P))!=0)
|
||||
#define DbSetProperty(D,I,P) (D)->aDb[I].pSchema->flags|=(P)
|
||||
#define DbClearProperty(D,I,P) (D)->aDb[I].pSchema->flags&=~(P)
|
||||
|
||||
/*
|
||||
** Allowed values for the DB.flags field.
|
||||
@ -381,6 +426,7 @@ struct Db {
|
||||
*/
|
||||
#define DB_SchemaLoaded 0x0001 /* The schema has been loaded */
|
||||
#define DB_UnresetViews 0x0002 /* Some views have defined column names */
|
||||
#define DB_Empty 0x0004 /* The file is empty (length 0 bytes) */
|
||||
|
||||
#define SQLITE_UTF16NATIVE (SQLITE_BIGENDIAN?SQLITE_UTF16BE:SQLITE_UTF16LE)
|
||||
|
||||
@ -415,9 +461,7 @@ struct sqlite3 {
|
||||
Db *aDb; /* All backends */
|
||||
int flags; /* Miscellanous flags. See below */
|
||||
int errCode; /* Most recent error code (SQLITE_*) */
|
||||
u8 enc; /* Text encoding for this database. */
|
||||
u8 autoCommit; /* The auto-commit flag. */
|
||||
u8 file_format; /* What file format version is this database? */
|
||||
u8 temp_store; /* 1: file 2: memory 0: default */
|
||||
int nTable; /* Number of tables in the database */
|
||||
CollSeq *pDfltColl; /* The default collating sequence (BINARY) */
|
||||
@ -437,12 +481,15 @@ struct sqlite3 {
|
||||
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 *pCommitArg; /* Argument to xCommitCallback() */
|
||||
int (*xCommitCallback)(void*); /* Invoked at every commit. */
|
||||
void *pRollbackArg; /* Argument to xRollbackCallback() */
|
||||
void (*xRollbackCallback)(void*); /* Invoked at every commit. */
|
||||
void *pUpdateArg;
|
||||
void (*xUpdateCallback)(void*,int, const char*,const char*,sqlite_int64);
|
||||
void(*xCollNeeded)(void*,sqlite3*,int eTextRep,const char*);
|
||||
void(*xCollNeeded16)(void*,sqlite3*,int eTextRep,const void*);
|
||||
void *pCollNeededArg;
|
||||
sqlite3_value *pValue; /* Value used for transient conversions */
|
||||
sqlite3_value *pErr; /* Most recent error message */
|
||||
char *zErrMsg; /* Most recent error message (UTF-8 encoded) */
|
||||
char *zErrMsg16; /* Most recent error message (UTF-16 encoded) */
|
||||
@ -469,6 +516,8 @@ struct sqlite3 {
|
||||
#endif
|
||||
};
|
||||
|
||||
#define ENC(db) ((db)->aDb[0].pSchema->enc)
|
||||
|
||||
/*
|
||||
** Possible values for the sqlite.flags and or Db.flags fields.
|
||||
**
|
||||
@ -477,7 +526,6 @@ struct sqlite3 {
|
||||
** transaction is active on that particular database file.
|
||||
*/
|
||||
#define SQLITE_VdbeTrace 0x00000001 /* True to trace VDBE execution */
|
||||
#define SQLITE_Initialized 0x00000002 /* True after initialization */
|
||||
#define SQLITE_Interrupt 0x00000004 /* Cancel current operation */
|
||||
#define SQLITE_InTrans 0x00000008 /* True if in a transaction */
|
||||
#define SQLITE_InternChanges 0x00000010 /* Uncommitted Hash table changes */
|
||||
@ -493,6 +541,9 @@ struct sqlite3 {
|
||||
#define SQLITE_WriteSchema 0x00000800 /* OK to update SQLITE_MASTER */
|
||||
#define SQLITE_NoReadlock 0x00001000 /* Readlocks are omitted when
|
||||
** accessing read-only databases */
|
||||
#define SQLITE_IgnoreChecks 0x00002000 /* Do not enforce check constraints */
|
||||
#define SQLITE_ReadUncommitted 0x00004000 /* For shared-cache mode */
|
||||
#define SQLITE_LegacyFileFmt 0x00008000 /* Create new databases in format 1 */
|
||||
|
||||
/*
|
||||
** Possible values for the sqlite.magic field.
|
||||
@ -537,7 +588,7 @@ struct Column {
|
||||
char *zName; /* Name of this column */
|
||||
Expr *pDflt; /* Default value of this column */
|
||||
char *zType; /* Data type for this column */
|
||||
CollSeq *pColl; /* Collating sequence. If NULL, use the default */
|
||||
char *zColl; /* Collating sequence. If NULL, use the default */
|
||||
u8 notNull; /* True if there is a NOT NULL constraint */
|
||||
u8 isPrimKey; /* True if this column is part of the PRIMARY KEY */
|
||||
char affinity; /* One of the SQLITE_AFF_... values */
|
||||
@ -553,7 +604,7 @@ struct Column {
|
||||
** processes text encoded in UTF-16 (CollSeq.xCmp16), using the machine
|
||||
** native byte order. When a collation sequence is invoked, SQLite selects
|
||||
** the version that will require the least expensive encoding
|
||||
** transalations, if any.
|
||||
** translations, if any.
|
||||
**
|
||||
** The CollSeq.pUser member variable is an extra parameter that passed in
|
||||
** as the first argument to the UTF-8 comparison function, xCmp.
|
||||
@ -588,12 +639,25 @@ struct CollSeq {
|
||||
|
||||
/*
|
||||
** Column affinity types.
|
||||
**
|
||||
** These used to have mnemonic name like 'i' for SQLITE_AFF_INTEGER and
|
||||
** 't' for SQLITE_AFF_TEXT. But we can save a little space and improve
|
||||
** the speed a little by number the values consecutively.
|
||||
**
|
||||
** But rather than start with 0 or 1, we begin with 'a'. That way,
|
||||
** when multiple affinity types are concatenated into a string and
|
||||
** used as the P3 operand, they will be more readable.
|
||||
**
|
||||
** Note also that the numeric types are grouped together so that testing
|
||||
** for a numeric type is a single comparison.
|
||||
*/
|
||||
#define SQLITE_AFF_INTEGER 'i'
|
||||
#define SQLITE_AFF_NUMERIC 'n'
|
||||
#define SQLITE_AFF_TEXT 't'
|
||||
#define SQLITE_AFF_NONE 'o'
|
||||
#define SQLITE_AFF_TEXT 'a'
|
||||
#define SQLITE_AFF_NONE 'b'
|
||||
#define SQLITE_AFF_NUMERIC 'c'
|
||||
#define SQLITE_AFF_INTEGER 'd'
|
||||
#define SQLITE_AFF_REAL 'e'
|
||||
|
||||
#define sqlite3IsNumericAffinity(X) ((X)>=SQLITE_AFF_NUMERIC)
|
||||
|
||||
/*
|
||||
** Each SQL table is represented in memory by an instance of the
|
||||
@ -634,7 +698,6 @@ struct Table {
|
||||
int tnum; /* Root BTree node for this table (see note above) */
|
||||
Select *pSelect; /* NULL for tables. Points to definition if a view. */
|
||||
u8 readOnly; /* True if this table should not be written by the user */
|
||||
u8 iDb; /* Index into sqlite.aDb[] of the backend for this table */
|
||||
u8 isTransient; /* True if automatically deleted when VDBE finishes */
|
||||
u8 hasPrimKey; /* True if there exists a primary key */
|
||||
u8 keyConf; /* What to do in case of uniqueness conflict on iPKey */
|
||||
@ -643,9 +706,13 @@ struct Table {
|
||||
Trigger *pTrigger; /* List of SQL triggers on this table */
|
||||
FKey *pFKey; /* Linked list of all foreign keys in this table */
|
||||
char *zColAff; /* String defining the affinity of each column */
|
||||
#ifndef SQLITE_OMIT_CHECK
|
||||
Expr *pCheck; /* The AND of all CHECK constraints */
|
||||
#endif
|
||||
#ifndef SQLITE_OMIT_ALTERTABLE
|
||||
int addColOffset; /* Offset in CREATE TABLE statement to add a new column */
|
||||
#endif
|
||||
Schema *pSchema;
|
||||
};
|
||||
|
||||
/*
|
||||
@ -781,10 +848,11 @@ struct Index {
|
||||
int tnum; /* Page containing root of this index in database file */
|
||||
u8 onError; /* OE_Abort, OE_Ignore, OE_Replace, or OE_None */
|
||||
u8 autoIndex; /* True if is automatically created (ex: by UNIQUE) */
|
||||
u8 iDb; /* Index in sqlite.aDb[] of where this index is stored */
|
||||
char *zColAff; /* String defining the affinity of each column */
|
||||
Index *pNext; /* The next index associated with the same table */
|
||||
KeyInfo keyInfo; /* Info on how to order keys. MUST BE LAST */
|
||||
Schema *pSchema; /* Schema containing this index */
|
||||
u8 *aSortOrder; /* Array of size Index.nColumn. True==DESC, False==ASC */
|
||||
char **azColl; /* Array of collation sequence names for index */
|
||||
};
|
||||
|
||||
/*
|
||||
@ -893,7 +961,6 @@ struct AggInfo {
|
||||
struct Expr {
|
||||
u8 op; /* Operation performed by this node */
|
||||
char affinity; /* The affinity of the column or 0 if not a column */
|
||||
u8 iDb; /* Database referenced by this expression */
|
||||
u8 flags; /* Various flags. See below */
|
||||
CollSeq *pColl; /* The collation type of the column or 0 */
|
||||
Expr *pLeft, *pRight; /* Left and right subnodes */
|
||||
@ -909,6 +976,7 @@ struct Expr {
|
||||
Select *pSelect; /* When the expression is a sub-select. Also the
|
||||
** right side of "<expr> IN (<select>)" */
|
||||
Table *pTab; /* Table for OP_Column expressions. */
|
||||
Schema *pSchema;
|
||||
};
|
||||
|
||||
/*
|
||||
@ -1089,6 +1157,7 @@ struct NameContext {
|
||||
int nErr; /* Number of errors encountered while resolving names */
|
||||
u8 allowAgg; /* Aggregate functions allowed here */
|
||||
u8 hasAgg; /* True if aggregates are seen */
|
||||
u8 isCheck; /* True if resolving names in a CHECK constraint */
|
||||
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 */
|
||||
@ -1151,7 +1220,7 @@ struct Select {
|
||||
#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 */
|
||||
#define SRT_Exists 10 /* Store 1 if the result is not empty */
|
||||
|
||||
/*
|
||||
** An SQL parser context. A copy of this structure is passed through
|
||||
@ -1162,6 +1231,12 @@ struct Select {
|
||||
** generate call themselves recursively, the first part of the structure
|
||||
** is constant but the second part is reset at the beginning and end of
|
||||
** each recursion.
|
||||
**
|
||||
** The nTableLock and aTableLock variables are only used if the shared-cache
|
||||
** feature is enabled (if sqlite3Tsd()->useSharedData is true). They are
|
||||
** used to store the set of table-locks required by the statement being
|
||||
** compiled. Function sqlite3TableLock() is used to add entries to the
|
||||
** list.
|
||||
*/
|
||||
struct Parse {
|
||||
sqlite3 *db; /* The main database structure */
|
||||
@ -1176,10 +1251,15 @@ struct Parse {
|
||||
int nTab; /* Number of previously allocated VDBE cursors */
|
||||
int nMem; /* Number of memory cells used so far */
|
||||
int nSet; /* Number of sets used so far */
|
||||
int ckOffset; /* Stack offset to data used by CHECK constraints */
|
||||
u32 writeMask; /* Start a write transaction on these databases */
|
||||
u32 cookieMask; /* Bitmask of schema verified databases */
|
||||
int cookieGoto; /* Address of OP_Goto to cookie verifier subroutine */
|
||||
int cookieValue[MAX_ATTACHED+2]; /* Values of cookies to verify */
|
||||
#ifndef SQLITE_OMIT_SHARED_CACHE
|
||||
int nTableLock; /* Number of locks in aTableLock */
|
||||
TableLock *aTableLock; /* Required table locks for shared-cache mode */
|
||||
#endif
|
||||
|
||||
/* Above is constant between recursions. Below is reset before and after
|
||||
** each recursion */
|
||||
@ -1214,6 +1294,7 @@ struct AuthContext {
|
||||
*/
|
||||
#define OPFLAG_NCHANGE 1 /* Set to update db->nChange */
|
||||
#define OPFLAG_LASTROWID 2 /* Set to update db->lastRowid */
|
||||
#define OPFLAG_ISUPDATE 4 /* This OP_Insert is an sql UPDATE */
|
||||
|
||||
/*
|
||||
* Each trigger present in the database schema is stored as an instance of
|
||||
@ -1233,8 +1314,6 @@ struct AuthContext {
|
||||
struct Trigger {
|
||||
char *name; /* The name of the trigger */
|
||||
char *table; /* The table or view to which the trigger applies */
|
||||
u8 iDb; /* Database containing this trigger */
|
||||
u8 iTabDb; /* Database containing Trigger.table */
|
||||
u8 op; /* One of TK_DELETE, TK_UPDATE, TK_INSERT */
|
||||
u8 tr_tm; /* One of TRIGGER_BEFORE, TRIGGER_AFTER */
|
||||
Expr *pWhen; /* The WHEN clause of the expresion (may be NULL) */
|
||||
@ -1242,7 +1321,8 @@ struct Trigger {
|
||||
the <column-list> is stored here */
|
||||
int foreach; /* One of TK_ROW or TK_STATEMENT */
|
||||
Token nameToken; /* Token containing zName. Use during parsing only */
|
||||
|
||||
Schema *pSchema; /* Schema containing the trigger */
|
||||
Schema *pTabSchema; /* Schema containing the table */
|
||||
TriggerStep *step_list; /* Link list of trigger program steps */
|
||||
Trigger *pNext; /* Next trigger associated with the table */
|
||||
};
|
||||
@ -1400,35 +1480,29 @@ int sqlite3IsNumber(const char*, int*, u8);
|
||||
int sqlite3Compare(const char *, const char *);
|
||||
int sqlite3SortCompare(const char *, const char *);
|
||||
void sqlite3RealToSortable(double r, char *);
|
||||
#ifdef SQLITE_MEMDEBUG
|
||||
void *sqlite3Malloc_(int,int,char*,int);
|
||||
void sqlite3Free_(void*,char*,int);
|
||||
void *sqlite3Realloc_(void*,int,char*,int);
|
||||
char *sqlite3StrDup_(const char*,char*,int);
|
||||
char *sqlite3StrNDup_(const char*, int,char*,int);
|
||||
void sqlite3CheckMemory(void*,int);
|
||||
#else
|
||||
void *sqlite3Malloc(int);
|
||||
void *sqlite3MallocRaw(int);
|
||||
void sqlite3Free(void*);
|
||||
void *sqlite3Realloc(void*,int);
|
||||
char *sqlite3StrDup(const char*);
|
||||
char *sqlite3StrNDup(const char*, int);
|
||||
|
||||
void *sqlite3Malloc(int);
|
||||
void *sqlite3MallocRaw(int);
|
||||
void sqlite3Free(void*);
|
||||
void *sqlite3Realloc(void*,int);
|
||||
char *sqlite3StrDup(const char*);
|
||||
char *sqlite3StrNDup(const char*, int);
|
||||
# define sqlite3CheckMemory(a,b)
|
||||
# define sqlite3MallocX sqlite3Malloc
|
||||
#endif
|
||||
void sqlite3ReallocOrFree(void**,int);
|
||||
void sqlite3FreeX(void*);
|
||||
void *sqlite3MallocX(int);
|
||||
int sqlite3AllocSize(void *);
|
||||
|
||||
char *sqlite3MPrintf(const char*, ...);
|
||||
char *sqlite3VMPrintf(const char*, va_list);
|
||||
void sqlite3DebugPrintf(const char*, ...);
|
||||
void *sqlite3TextToPtr(const char*);
|
||||
void sqlite3SetString(char **, ...);
|
||||
void sqlite3ErrorMsg(Parse*, const char*, ...);
|
||||
void sqlite3ErrorClear(Parse*);
|
||||
void sqlite3Dequote(char*);
|
||||
void sqlite3DequoteExpr(Expr*);
|
||||
int sqlite3KeywordCode(const char*, int);
|
||||
int sqlite3KeywordCode(const unsigned char*, int);
|
||||
int sqlite3RunParser(Parse*, const char*, char **);
|
||||
void sqlite3FinishCoding(Parse*);
|
||||
Expr *sqlite3Expr(int, Expr*, Expr*, const Token*);
|
||||
@ -1448,11 +1522,12 @@ void sqlite3BeginParse(Parse*,int);
|
||||
void sqlite3RollbackInternalChanges(sqlite3*);
|
||||
void sqlite3CommitInternalChanges(sqlite3*);
|
||||
Table *sqlite3ResultSetOfSelect(Parse*,char*,Select*);
|
||||
void sqlite3OpenMasterTable(Vdbe *v, int);
|
||||
void sqlite3StartTable(Parse*,Token*,Token*,Token*,int,int);
|
||||
void sqlite3OpenMasterTable(Parse *, int);
|
||||
void sqlite3StartTable(Parse*,Token*,Token*,Token*,int,int,int);
|
||||
void sqlite3AddColumn(Parse*,Token*);
|
||||
void sqlite3AddNotNull(Parse*, int);
|
||||
void sqlite3AddPrimaryKey(Parse*, ExprList*, int, int);
|
||||
void sqlite3AddPrimaryKey(Parse*, ExprList*, int, int, int);
|
||||
void sqlite3AddCheckConstraint(Parse*, Expr*);
|
||||
void sqlite3AddColumnType(Parse*,Token*);
|
||||
void sqlite3AddDefaultValue(Parse*,Expr*);
|
||||
void sqlite3AddCollateType(Parse*, const char*, int);
|
||||
@ -1465,7 +1540,7 @@ void sqlite3EndTable(Parse*,Token*,Token*,Select*);
|
||||
# define sqlite3ViewGetColumnNames(A,B) 0
|
||||
#endif
|
||||
|
||||
void sqlite3DropTable(Parse*, SrcList*, int);
|
||||
void sqlite3DropTable(Parse*, SrcList*, int, int);
|
||||
void sqlite3DeleteTable(sqlite3*, Table*);
|
||||
void sqlite3Insert(Parse*, SrcList*, ExprList*, Select*, IdList*, int);
|
||||
int sqlite3ArrayAllocate(void**,int,int);
|
||||
@ -1477,8 +1552,8 @@ void sqlite3SrcListAssignCursors(Parse*, SrcList*);
|
||||
void sqlite3IdListDelete(IdList*);
|
||||
void sqlite3SrcListDelete(SrcList*);
|
||||
void sqlite3CreateIndex(Parse*,Token*,Token*,SrcList*,ExprList*,int,Token*,
|
||||
Token*);
|
||||
void sqlite3DropIndex(Parse*, SrcList*);
|
||||
Token*, int, int);
|
||||
void sqlite3DropIndex(Parse*, SrcList*, int);
|
||||
void sqlite3AddKeyType(Vdbe*, ExprList*);
|
||||
void sqlite3AddIdxKeyType(Vdbe*, Index*);
|
||||
int sqlite3Select(Parse*, Select*, int, int, Select*, int, int*, char *aff);
|
||||
@ -1488,8 +1563,7 @@ void sqlite3SelectDelete(Select*);
|
||||
void sqlite3SelectUnbind(Select*);
|
||||
Table *sqlite3SrcListLookup(Parse*, SrcList*);
|
||||
int sqlite3IsReadOnly(Parse*, Table*, int);
|
||||
void sqlite3OpenTableForReading(Vdbe*, int iCur, Table*);
|
||||
void sqlite3OpenTable(Vdbe*, int iCur, Table*, int);
|
||||
void sqlite3OpenTable(Parse*, int iCur, int iDb, Table*, int);
|
||||
void sqlite3DeleteFrom(Parse*, SrcList*, Expr*);
|
||||
void sqlite3Update(Parse*, SrcList*, ExprList*, Expr*, int);
|
||||
WhereInfo *sqlite3WhereBegin(Parse*, SrcList*, Expr*, ExprList**);
|
||||
@ -1585,8 +1659,8 @@ void sqlite3DeferForeignKey(Parse*, int);
|
||||
# define sqlite3AuthContextPush(a,b,c)
|
||||
# define sqlite3AuthContextPop(a) ((void)(a))
|
||||
#endif
|
||||
void sqlite3Attach(Parse*, Token*, Token*, int, Token*);
|
||||
void sqlite3Detach(Parse*, Token*);
|
||||
void sqlite3Attach(Parse*, Expr*, Expr*, Expr*);
|
||||
void sqlite3Detach(Parse*, Expr*);
|
||||
int sqlite3BtreeFactory(const sqlite3 *db, const char *zFilename,
|
||||
int omitJournal, int nCache, Btree **ppBtree);
|
||||
int sqlite3FixInit(DbFixer*, Parse*, int, const char*, const Token*);
|
||||
@ -1632,7 +1706,7 @@ int sqlite3ValueBytes(sqlite3_value*, u8);
|
||||
void sqlite3ValueSetStr(sqlite3_value*, int, const void *,u8, void(*)(void*));
|
||||
void sqlite3ValueFree(sqlite3_value*);
|
||||
sqlite3_value *sqlite3ValueNew(void);
|
||||
sqlite3_value *sqlite3GetTransientValue(sqlite3*db);
|
||||
char *sqlite3utf16to8(const void*, int);
|
||||
int sqlite3ValueFromExpr(Expr *, u8, u8, sqlite3_value **);
|
||||
void sqlite3ValueApplyAffinity(sqlite3_value *, u8, u8);
|
||||
extern const unsigned char sqlite3UpperToLower[];
|
||||
@ -1658,6 +1732,38 @@ void sqlite3AnalysisLoad(sqlite3*,int iDB);
|
||||
void sqlite3DefaultRowEst(Index*);
|
||||
void sqlite3RegisterLikeFunctions(sqlite3*, int);
|
||||
int sqlite3IsLikeFunction(sqlite3*,Expr*,int*,char*);
|
||||
ThreadData *sqlite3ThreadData(void);
|
||||
const ThreadData *sqlite3ThreadDataReadOnly(void);
|
||||
void sqlite3ReleaseThreadData(void);
|
||||
void sqlite3AttachFunctions(sqlite3 *);
|
||||
void sqlite3MinimumFileFormat(Parse*, int, int);
|
||||
void sqlite3SchemaFree(void *);
|
||||
Schema *sqlite3SchemaGet(Btree *);
|
||||
int sqlite3SchemaToIndex(sqlite3 *db, Schema *);
|
||||
KeyInfo *sqlite3IndexKeyinfo(Parse *, Index *);
|
||||
int sqlite3CreateFunc(sqlite3 *, const char *, int, int, void *,
|
||||
void (*)(sqlite3_context*,int,sqlite3_value **),
|
||||
void (*)(sqlite3_context*,int,sqlite3_value **), void (*)(sqlite3_context*));
|
||||
int sqlite3ApiExit(sqlite3 *db, int);
|
||||
int sqlite3MallocFailed(void);
|
||||
void sqlite3FailedMalloc(void);
|
||||
void sqlite3AbortOtherActiveVdbes(sqlite3 *, Vdbe *);
|
||||
|
||||
#ifndef SQLITE_OMIT_SHARED_CACHE
|
||||
void sqlite3TableLock(Parse *, int, int, u8, const char *);
|
||||
#else
|
||||
#define sqlite3TableLock(v,w,x,y,z)
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_MEMDEBUG
|
||||
void sqlite3MallocDisallow(void);
|
||||
void sqlite3MallocAllow(void);
|
||||
int sqlite3TestMallocFail(void);
|
||||
#else
|
||||
#define sqlite3TestMallocFail() 0
|
||||
#define sqlite3MallocDisallow()
|
||||
#define sqlite3MallocAllow()
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_SSE
|
||||
#include "sseInt.h"
|
||||
|
||||
@ -16,9 +16,11 @@
|
||||
** These routines are in a separate files so that they will not be linked
|
||||
** if they are not used.
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "sqliteInt.h"
|
||||
|
||||
#ifndef SQLITE_OMIT_GET_TABLE
|
||||
|
||||
/*
|
||||
** This structure is used to pass data from sqlite3_get_table() through
|
||||
@ -193,3 +195,5 @@ void sqlite3_free_table(
|
||||
free(azResult);
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* SQLITE_OMIT_GET_TABLE */
|
||||
|
||||
@ -11,7 +11,7 @@
|
||||
*************************************************************************
|
||||
** A TCL Interface to SQLite
|
||||
**
|
||||
** $Id: tclsqlite.c,v 1.132 2005/08/29 23:00:04 drh Exp $
|
||||
** $Id: tclsqlite.c,v 1.150 2006/01/23 13:00:38 drh Exp $
|
||||
*/
|
||||
#ifndef NO_TCL /* Omit this whole file if TCL is unavailable */
|
||||
|
||||
@ -23,6 +23,16 @@
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
|
||||
/*
|
||||
* Windows needs to know which symbols to export. Unix does not.
|
||||
* BUILD_sqlite should be undefined for Unix.
|
||||
*/
|
||||
|
||||
#ifdef BUILD_sqlite
|
||||
#undef TCL_STORAGE_CLASS
|
||||
#define TCL_STORAGE_CLASS DLLEXPORT
|
||||
#endif /* BUILD_sqlite */
|
||||
|
||||
#define NUM_PREPARED_STMTS 10
|
||||
#define MAX_PREPARED_STMTS 100
|
||||
|
||||
@ -79,7 +89,7 @@ struct SqlPreparedStmt {
|
||||
*/
|
||||
typedef struct SqliteDb SqliteDb;
|
||||
struct SqliteDb {
|
||||
sqlite3 *db; /* The "real" database structure */
|
||||
sqlite3 *db; /* The "real" database structure. MUST BE FIRST */
|
||||
Tcl_Interp *interp; /* The interpreter used for this database */
|
||||
char *zBusy; /* The busy callback routine */
|
||||
char *zCommit; /* The commit hook callback routine */
|
||||
@ -89,6 +99,8 @@ struct SqliteDb {
|
||||
char *zAuth; /* The authorization callback routine */
|
||||
char *zNull; /* Text to substitute for an SQL NULL value */
|
||||
SqlFunc *pFunc; /* List of SQL functions */
|
||||
Tcl_Obj *pUpdateHook; /* Update hook script (if any) */
|
||||
Tcl_Obj *pRollbackHook; /* Rollback hook script (if any) */
|
||||
SqlCollate *pCollate; /* List of SQL collation functions */
|
||||
int rc; /* Return code of most recent sqlite3_exec() */
|
||||
Tcl_Obj *pCollateNeeded; /* Collation needed script */
|
||||
@ -200,6 +212,15 @@ static void DbDeleteCmd(void *db){
|
||||
if( pDb->zNull ){
|
||||
Tcl_Free(pDb->zNull);
|
||||
}
|
||||
if( pDb->pUpdateHook ){
|
||||
Tcl_DecrRefCount(pDb->pUpdateHook);
|
||||
}
|
||||
if( pDb->pRollbackHook ){
|
||||
Tcl_DecrRefCount(pDb->pRollbackHook);
|
||||
}
|
||||
if( pDb->pCollateNeeded ){
|
||||
Tcl_DecrRefCount(pDb->pCollateNeeded);
|
||||
}
|
||||
Tcl_Free((char*)pDb);
|
||||
}
|
||||
|
||||
@ -235,6 +256,7 @@ static int DbProgressHandler(void *cd){
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifndef SQLITE_OMIT_TRACE
|
||||
/*
|
||||
** This routine is called by the SQLite trace handler whenever a new
|
||||
** block of SQL is executed. The TCL script in pDb->zTrace is executed.
|
||||
@ -250,7 +272,9 @@ static void DbTraceHandler(void *cd, const char *zSql){
|
||||
Tcl_DStringFree(&str);
|
||||
Tcl_ResetResult(pDb->interp);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef SQLITE_OMIT_TRACE
|
||||
/*
|
||||
** This routine is called by the SQLite profile handler after a statement
|
||||
** SQL has executed. The TCL script in pDb->zProfile is evaluated.
|
||||
@ -269,6 +293,7 @@ static void DbProfileHandler(void *cd, const char *zSql, sqlite_uint64 tm){
|
||||
Tcl_DStringFree(&str);
|
||||
Tcl_ResetResult(pDb->interp);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
** This routine is called when a transaction is committed. The
|
||||
@ -287,6 +312,37 @@ static int DbCommitHandler(void *cd){
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void DbRollbackHandler(void *clientData){
|
||||
SqliteDb *pDb = (SqliteDb*)clientData;
|
||||
assert(pDb->pRollbackHook);
|
||||
if( TCL_OK!=Tcl_EvalObjEx(pDb->interp, pDb->pRollbackHook, 0) ){
|
||||
Tcl_BackgroundError(pDb->interp);
|
||||
}
|
||||
}
|
||||
|
||||
static void DbUpdateHandler(
|
||||
void *p,
|
||||
int op,
|
||||
const char *zDb,
|
||||
const char *zTbl,
|
||||
sqlite_int64 rowid
|
||||
){
|
||||
SqliteDb *pDb = (SqliteDb *)p;
|
||||
Tcl_Obj *pCmd;
|
||||
|
||||
assert( pDb->pUpdateHook );
|
||||
assert( op==SQLITE_INSERT || op==SQLITE_UPDATE || op==SQLITE_DELETE );
|
||||
|
||||
pCmd = Tcl_DuplicateObj(pDb->pUpdateHook);
|
||||
Tcl_IncrRefCount(pCmd);
|
||||
Tcl_ListObjAppendElement(0, pCmd, Tcl_NewStringObj(
|
||||
( (op==SQLITE_INSERT)?"INSERT":(op==SQLITE_UPDATE)?"UPDATE":"DELETE"), -1));
|
||||
Tcl_ListObjAppendElement(0, pCmd, Tcl_NewStringObj(zDb, -1));
|
||||
Tcl_ListObjAppendElement(0, pCmd, Tcl_NewStringObj(zTbl, -1));
|
||||
Tcl_ListObjAppendElement(0, pCmd, Tcl_NewWideIntObj(rowid));
|
||||
Tcl_EvalObjEx(pDb->interp, pCmd, TCL_EVAL_DIRECT);
|
||||
}
|
||||
|
||||
static void tclCollateNeeded(
|
||||
void *pCtx,
|
||||
sqlite3 *db,
|
||||
@ -392,7 +448,7 @@ static void tclSqlFunc(sqlite3_context *context, int argc, sqlite3_value**argv){
|
||||
}
|
||||
default: {
|
||||
int bytes = sqlite3_value_bytes(pIn);
|
||||
pVal = Tcl_NewStringObj(sqlite3_value_text(pIn), bytes);
|
||||
pVal = Tcl_NewStringObj((char *)sqlite3_value_text(pIn), bytes);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -439,8 +495,8 @@ static void tclSqlFunc(sqlite3_context *context, int argc, sqlite3_value**argv){
|
||||
Tcl_GetWideIntFromObj(0, pVar, &v);
|
||||
sqlite3_result_int64(context, v);
|
||||
}else{
|
||||
data = Tcl_GetStringFromObj(pVar, &n);
|
||||
sqlite3_result_text(context, data, n, SQLITE_TRANSIENT);
|
||||
data = (unsigned char *)Tcl_GetStringFromObj(pVar, &n);
|
||||
sqlite3_result_text(context, (char *)data, n, SQLITE_TRANSIENT);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -611,10 +667,11 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
||||
"changes", "close", "collate",
|
||||
"collation_needed", "commit_hook", "complete",
|
||||
"copy", "errorcode", "eval",
|
||||
"function", "last_insert_rowid", "nullvalue",
|
||||
"onecolumn", "profile", "progress",
|
||||
"rekey", "timeout", "total_changes",
|
||||
"trace", "transaction", "version",
|
||||
"exists", "function", "last_insert_rowid",
|
||||
"nullvalue", "onecolumn", "profile",
|
||||
"progress", "rekey", "rollback_hook",
|
||||
"timeout", "total_changes", "trace",
|
||||
"transaction", "update_hook", "version",
|
||||
0
|
||||
};
|
||||
enum DB_enum {
|
||||
@ -622,10 +679,11 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
||||
DB_CHANGES, DB_CLOSE, DB_COLLATE,
|
||||
DB_COLLATION_NEEDED, DB_COMMIT_HOOK, DB_COMPLETE,
|
||||
DB_COPY, DB_ERRORCODE, DB_EVAL,
|
||||
DB_FUNCTION, DB_LAST_INSERT_ROWID,DB_NULLVALUE,
|
||||
DB_ONECOLUMN, DB_PROFILE, DB_PROGRESS,
|
||||
DB_REKEY, DB_TIMEOUT, DB_TOTAL_CHANGES,
|
||||
DB_TRACE, DB_TRANSACTION, DB_VERSION
|
||||
DB_EXISTS, DB_FUNCTION, DB_LAST_INSERT_ROWID,
|
||||
DB_NULLVALUE, DB_ONECOLUMN, DB_PROFILE,
|
||||
DB_PROGRESS, DB_REKEY, DB_ROLLBACK_HOOK,
|
||||
DB_TIMEOUT, DB_TOTAL_CHANGES, DB_TRACE,
|
||||
DB_TRANSACTION, DB_UPDATE_HOOK, DB_VERSION
|
||||
};
|
||||
/* don't leave trailing commas on DB_enum, it confuses the AIX xlc compiler */
|
||||
|
||||
@ -1126,7 +1184,8 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
||||
** lindex [$db eval $sql] 0
|
||||
*/
|
||||
case DB_ONECOLUMN:
|
||||
case DB_EVAL: {
|
||||
case DB_EVAL:
|
||||
case DB_EXISTS: {
|
||||
char const *zSql; /* Next SQL statement to execute */
|
||||
char const *zLeft; /* What is left after first stmt in zSql */
|
||||
sqlite3_stmt *pStmt; /* Compiled SQL statment */
|
||||
@ -1139,19 +1198,24 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
||||
SqlPreparedStmt *pPreStmt; /* Pointer to a prepared statement */
|
||||
int rc2;
|
||||
|
||||
if( choice==DB_ONECOLUMN ){
|
||||
if( objc!=3 ){
|
||||
Tcl_WrongNumArgs(interp, 2, objv, "SQL");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
pRet = 0;
|
||||
}else{
|
||||
if( choice==DB_EVAL ){
|
||||
if( objc<3 || objc>5 ){
|
||||
Tcl_WrongNumArgs(interp, 2, objv, "SQL ?ARRAY-NAME? ?SCRIPT?");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
pRet = Tcl_NewObj();
|
||||
Tcl_IncrRefCount(pRet);
|
||||
}else{
|
||||
if( objc!=3 ){
|
||||
Tcl_WrongNumArgs(interp, 2, objv, "SQL");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
if( choice==DB_EXISTS ){
|
||||
pRet = Tcl_NewBooleanObj(0);
|
||||
Tcl_IncrRefCount(pRet);
|
||||
}else{
|
||||
pRet = 0;
|
||||
}
|
||||
}
|
||||
if( objc==3 ){
|
||||
pArray = pScript = 0;
|
||||
@ -1275,8 +1339,8 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
||||
Tcl_GetWideIntFromObj(interp, pVar, &v);
|
||||
sqlite3_bind_int64(pStmt, i, v);
|
||||
}else{
|
||||
data = Tcl_GetStringFromObj(pVar, &n);
|
||||
sqlite3_bind_text(pStmt, i, data, n, SQLITE_STATIC);
|
||||
data = (unsigned char *)Tcl_GetStringFromObj(pVar, &n);
|
||||
sqlite3_bind_text(pStmt, i, (char *)data, n, SQLITE_STATIC);
|
||||
Tcl_IncrRefCount(pVar);
|
||||
apParm[nParm++] = pVar;
|
||||
}
|
||||
@ -1344,7 +1408,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
pVal = dbTextToObj(sqlite3_column_text(pStmt, i));
|
||||
pVal = dbTextToObj((char *)sqlite3_column_text(pStmt, i));
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -1356,11 +1420,19 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
||||
Tcl_ObjSetVar2(interp, pArray, apColName[i], pVal, 0);
|
||||
}
|
||||
}else if( choice==DB_ONECOLUMN ){
|
||||
assert( pRet==0 );
|
||||
if( pRet==0 ){
|
||||
pRet = pVal;
|
||||
Tcl_IncrRefCount(pRet);
|
||||
}
|
||||
rc = TCL_BREAK;
|
||||
i = nCol;
|
||||
}else if( choice==DB_EXISTS ){
|
||||
Tcl_DecrRefCount(pRet);
|
||||
pRet = Tcl_NewBooleanObj(1);
|
||||
Tcl_IncrRefCount(pRet);
|
||||
rc = TCL_BREAK;
|
||||
i = nCol;
|
||||
}else{
|
||||
Tcl_ListObjAppendElement(interp, pRet, pVal);
|
||||
}
|
||||
@ -1797,6 +1869,48 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
** $db update_hook ?script?
|
||||
** $db rollback_hook ?script?
|
||||
*/
|
||||
case DB_UPDATE_HOOK:
|
||||
case DB_ROLLBACK_HOOK: {
|
||||
|
||||
/* set ppHook to point at pUpdateHook or pRollbackHook, depending on
|
||||
** whether [$db update_hook] or [$db rollback_hook] was invoked.
|
||||
*/
|
||||
Tcl_Obj **ppHook;
|
||||
if( choice==DB_UPDATE_HOOK ){
|
||||
ppHook = &pDb->pUpdateHook;
|
||||
}else{
|
||||
ppHook = &pDb->pRollbackHook;
|
||||
}
|
||||
|
||||
if( objc!=2 && objc!=3 ){
|
||||
Tcl_WrongNumArgs(interp, 2, objv, "?SCRIPT?");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
if( *ppHook ){
|
||||
Tcl_SetObjResult(interp, *ppHook);
|
||||
if( objc==3 ){
|
||||
Tcl_DecrRefCount(*ppHook);
|
||||
*ppHook = 0;
|
||||
}
|
||||
}
|
||||
if( objc==3 ){
|
||||
assert( !(*ppHook) );
|
||||
if( Tcl_GetCharLength(objv[2])>0 ){
|
||||
*ppHook = objv[2];
|
||||
Tcl_IncrRefCount(*ppHook);
|
||||
}
|
||||
}
|
||||
|
||||
sqlite3_update_hook(pDb->db, (pDb->pUpdateHook?DbUpdateHandler:0), pDb);
|
||||
sqlite3_rollback_hook(pDb->db,(pDb->pRollbackHook?DbRollbackHandler:0),pDb);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
/* $db version
|
||||
**
|
||||
** Return the version string for this database.
|
||||
@ -1849,7 +1963,6 @@ static int DbMain(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
||||
const char *zArg;
|
||||
char *zErrMsg;
|
||||
const char *zFile;
|
||||
char zBuf[80];
|
||||
if( objc==2 ){
|
||||
zArg = Tcl_GetStringFromObj(objv[1], 0);
|
||||
if( strcmp(zArg,"-version")==0 ){
|
||||
@ -1917,14 +2030,6 @@ static int DbMain(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
||||
zArg = Tcl_GetStringFromObj(objv[1], 0);
|
||||
Tcl_CreateObjCommand(interp, zArg, DbObjCmd, (char*)p, DbDeleteCmd);
|
||||
|
||||
/* The return value is the value of the sqlite* pointer
|
||||
*/
|
||||
sprintf(zBuf, "%p", p->db);
|
||||
if( strncmp(zBuf,"0x",2) ){
|
||||
sprintf(zBuf, "0x%p", p->db);
|
||||
}
|
||||
Tcl_AppendResult(interp, zBuf, 0);
|
||||
|
||||
/* If compiled with SQLITE_TEST turned on, then register the "md5sum"
|
||||
** SQL function.
|
||||
*/
|
||||
@ -1939,7 +2044,7 @@ static int DbMain(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
||||
#ifdef SQLITE_MEMDEBUG
|
||||
sqlite3_iMallocFail = mallocfail;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#endif
|
||||
p->interp = interp;
|
||||
return TCL_OK;
|
||||
@ -1954,6 +2059,15 @@ static int DbMain(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
||||
# define Tcl_InitStubs(a,b,c)
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Make sure we have a PACKAGE_VERSION macro defined. This will be
|
||||
** defined automatically by the TEA makefile. But other makefiles
|
||||
** do not define it.
|
||||
*/
|
||||
#ifndef PACKAGE_VERSION
|
||||
# define PACKAGE_VERSION SQLITE_VERSION
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Initialize this module.
|
||||
**
|
||||
@ -1963,23 +2077,23 @@ static int DbMain(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
||||
** used to open a new SQLite database. See the DbMain() routine above
|
||||
** for additional information.
|
||||
*/
|
||||
int Sqlite3_Init(Tcl_Interp *interp){
|
||||
EXTERN int Sqlite3_Init(Tcl_Interp *interp){
|
||||
Tcl_InitStubs(interp, "8.4", 0);
|
||||
Tcl_CreateObjCommand(interp, "sqlite3", (Tcl_ObjCmdProc*)DbMain, 0, 0);
|
||||
Tcl_PkgProvide(interp, "sqlite3", "3.0");
|
||||
Tcl_PkgProvide(interp, "sqlite3", PACKAGE_VERSION);
|
||||
Tcl_CreateObjCommand(interp, "sqlite", (Tcl_ObjCmdProc*)DbMain, 0, 0);
|
||||
Tcl_PkgProvide(interp, "sqlite", "3.0");
|
||||
Tcl_PkgProvide(interp, "sqlite", PACKAGE_VERSION);
|
||||
return TCL_OK;
|
||||
}
|
||||
int Tclsqlite3_Init(Tcl_Interp *interp){ return Sqlite3_Init(interp); }
|
||||
int Sqlite3_SafeInit(Tcl_Interp *interp){ return TCL_OK; }
|
||||
int Tclsqlite3_SafeInit(Tcl_Interp *interp){ return TCL_OK; }
|
||||
EXTERN int Tclsqlite3_Init(Tcl_Interp *interp){ return Sqlite3_Init(interp); }
|
||||
EXTERN int Sqlite3_SafeInit(Tcl_Interp *interp){ return TCL_OK; }
|
||||
EXTERN int Tclsqlite3_SafeInit(Tcl_Interp *interp){ return TCL_OK; }
|
||||
|
||||
#ifndef SQLITE_3_SUFFIX_ONLY
|
||||
int Sqlite_Init(Tcl_Interp *interp){ return Sqlite3_Init(interp); }
|
||||
int Tclsqlite_Init(Tcl_Interp *interp){ return Sqlite3_Init(interp); }
|
||||
int Sqlite_SafeInit(Tcl_Interp *interp){ return TCL_OK; }
|
||||
int Tclsqlite_SafeInit(Tcl_Interp *interp){ return TCL_OK; }
|
||||
EXTERN int Sqlite_Init(Tcl_Interp *interp){ return Sqlite3_Init(interp); }
|
||||
EXTERN int Tclsqlite_Init(Tcl_Interp *interp){ return Sqlite3_Init(interp); }
|
||||
EXTERN int Sqlite_SafeInit(Tcl_Interp *interp){ return TCL_OK; }
|
||||
EXTERN int Tclsqlite_SafeInit(Tcl_Interp *interp){ return TCL_OK; }
|
||||
#endif
|
||||
|
||||
#ifdef TCLSH
|
||||
@ -2040,14 +2154,20 @@ int TCLSH_MAIN(int argc, char **argv){
|
||||
extern int Sqlitetest3_Init(Tcl_Interp*);
|
||||
extern int Sqlitetest4_Init(Tcl_Interp*);
|
||||
extern int Sqlitetest5_Init(Tcl_Interp*);
|
||||
extern int Sqlitetest6_Init(Tcl_Interp*);
|
||||
extern int Sqlitetest7_Init(Tcl_Interp*);
|
||||
extern int Md5_Init(Tcl_Interp*);
|
||||
extern int Sqlitetestsse_Init(Tcl_Interp*);
|
||||
extern int Sqlitetestasync_Init(Tcl_Interp*);
|
||||
|
||||
Sqlitetest1_Init(interp);
|
||||
Sqlitetest2_Init(interp);
|
||||
Sqlitetest3_Init(interp);
|
||||
Sqlitetest4_Init(interp);
|
||||
Sqlitetest5_Init(interp);
|
||||
Sqlitetest6_Init(interp);
|
||||
Sqlitetest7_Init(interp);
|
||||
Sqlitetestasync_Init(interp);
|
||||
Md5_Init(interp);
|
||||
#ifdef SQLITE_SSE
|
||||
Sqlitetestsse_Init(interp);
|
||||
|
||||
@ -15,7 +15,7 @@
|
||||
** individual tokens and sends those tokens one-by-one over to the
|
||||
** parser for analysis.
|
||||
**
|
||||
** $Id: tokenize.c,v 1.107 2005/08/23 11:31:26 drh Exp $
|
||||
** $Id: tokenize.c,v 1.116 2006/01/20 17:56:33 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include "os.h"
|
||||
@ -196,9 +196,13 @@ static int getToken(const unsigned char *z, int *tokenType){
|
||||
}
|
||||
}
|
||||
}
|
||||
if( c ) i++;
|
||||
*tokenType = TK_STRING;
|
||||
return i;
|
||||
if( c ){
|
||||
*tokenType = TK_STRING;
|
||||
return i+1;
|
||||
}else{
|
||||
*tokenType = TK_ILLEGAL;
|
||||
return i;
|
||||
}
|
||||
}
|
||||
case '.': {
|
||||
#ifndef SQLITE_OMIT_FLOATING_POINT
|
||||
@ -344,7 +348,6 @@ int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzErrMsg){
|
||||
i = 0;
|
||||
pEngine = sqlite3ParserAlloc((void*(*)(int))sqlite3MallocX);
|
||||
if( pEngine==0 ){
|
||||
sqlite3SetString(pzErrMsg, "out of memory", (char*)0);
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
assert( pParse->sLastToken.dyn==0 );
|
||||
@ -355,9 +358,9 @@ int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzErrMsg){
|
||||
assert( pParse->nVarExprAlloc==0 );
|
||||
assert( pParse->apVarExpr==0 );
|
||||
pParse->zTail = pParse->zSql = zSql;
|
||||
while( sqlite3_malloc_failed==0 && zSql[i]!=0 ){
|
||||
while( !sqlite3MallocFailed() && zSql[i]!=0 ){
|
||||
assert( i>=0 );
|
||||
pParse->sLastToken.z = &zSql[i];
|
||||
pParse->sLastToken.z = (u8*)&zSql[i];
|
||||
assert( pParse->sLastToken.dyn==0 );
|
||||
pParse->sLastToken.n = getToken((unsigned char*)&zSql[i],&tokenType);
|
||||
i += pParse->sLastToken.n;
|
||||
@ -403,12 +406,11 @@ abort_parse:
|
||||
sqlite3Parser(pEngine, 0, pParse->sLastToken, pParse);
|
||||
}
|
||||
sqlite3ParserFree(pEngine, sqlite3FreeX);
|
||||
if( sqlite3_malloc_failed ){
|
||||
if( sqlite3MallocFailed() ){
|
||||
pParse->rc = SQLITE_NOMEM;
|
||||
}
|
||||
if( pParse->rc!=SQLITE_OK && pParse->rc!=SQLITE_DONE && pParse->zErrMsg==0 ){
|
||||
sqlite3SetString(&pParse->zErrMsg, sqlite3ErrStr(pParse->rc),
|
||||
(char*)0);
|
||||
sqlite3SetString(&pParse->zErrMsg, sqlite3ErrStr(pParse->rc), (char*)0);
|
||||
}
|
||||
if( pParse->zErrMsg ){
|
||||
if( pzErrMsg && *pzErrMsg==0 ){
|
||||
@ -423,6 +425,13 @@ abort_parse:
|
||||
sqlite3VdbeDelete(pParse->pVdbe);
|
||||
pParse->pVdbe = 0;
|
||||
}
|
||||
#ifndef SQLITE_OMIT_SHARED_CACHE
|
||||
if( pParse->nested==0 ){
|
||||
sqliteFree(pParse->aTableLock);
|
||||
pParse->aTableLock = 0;
|
||||
pParse->nTableLock = 0;
|
||||
}
|
||||
#endif
|
||||
sqlite3DeleteTable(pParse->db, pParse->pNewTable);
|
||||
sqlite3DeleteTrigger(pParse->pNewTrigger);
|
||||
sqliteFree(pParse->apVarExpr);
|
||||
|
||||
@ -58,6 +58,7 @@ void sqlite3BeginTrigger(
|
||||
int iDb; /* The database to store the trigger in */
|
||||
Token *pName; /* The unqualified db name */
|
||||
DbFixer sFix;
|
||||
int iTabDb;
|
||||
|
||||
if( isTemp ){
|
||||
/* If TEMP was specified, then the trigger name may not be qualified. */
|
||||
@ -80,14 +81,16 @@ void sqlite3BeginTrigger(
|
||||
** If sqlite3SrcListLookup() returns 0, indicating the table does not
|
||||
** exist, the error is caught by the block below.
|
||||
*/
|
||||
if( !pTableName || sqlite3_malloc_failed ) goto trigger_cleanup;
|
||||
if( !pTableName || sqlite3MallocFailed() ){
|
||||
goto trigger_cleanup;
|
||||
}
|
||||
pTab = sqlite3SrcListLookup(pParse, pTableName);
|
||||
if( pName2->n==0 && pTab && pTab->iDb==1 ){
|
||||
if( pName2->n==0 && pTab && pTab->pSchema==db->aDb[1].pSchema ){
|
||||
iDb = 1;
|
||||
}
|
||||
|
||||
/* Ensure the table name matches database name and that the table exists */
|
||||
if( sqlite3_malloc_failed ) goto trigger_cleanup;
|
||||
if( sqlite3MallocFailed() ) goto trigger_cleanup;
|
||||
assert( pTableName->nSrc==1 );
|
||||
if( sqlite3FixInit(&sFix, pParse, iDb, "trigger", pName) &&
|
||||
sqlite3FixSrcList(&sFix, pTableName) ){
|
||||
@ -105,7 +108,7 @@ void sqlite3BeginTrigger(
|
||||
if( !zName || SQLITE_OK!=sqlite3CheckObjectName(pParse, zName) ){
|
||||
goto trigger_cleanup;
|
||||
}
|
||||
if( sqlite3HashFind(&(db->aDb[iDb].trigHash), zName,pName->n+1) ){
|
||||
if( sqlite3HashFind(&(db->aDb[iDb].pSchema->trigHash), zName,pName->n+1) ){
|
||||
sqlite3ErrorMsg(pParse, "trigger %T already exists", pName);
|
||||
goto trigger_cleanup;
|
||||
}
|
||||
@ -130,17 +133,18 @@ void sqlite3BeginTrigger(
|
||||
" trigger on table: %S", pTableName, 0);
|
||||
goto trigger_cleanup;
|
||||
}
|
||||
iTabDb = sqlite3SchemaToIndex(db, pTab->pSchema);
|
||||
|
||||
#ifndef SQLITE_OMIT_AUTHORIZATION
|
||||
{
|
||||
int code = SQLITE_CREATE_TRIGGER;
|
||||
const char *zDb = db->aDb[pTab->iDb].zName;
|
||||
const char *zDb = db->aDb[iTabDb].zName;
|
||||
const char *zDbTrig = isTemp ? db->aDb[1].zName : zDb;
|
||||
if( pTab->iDb==1 || isTemp ) code = SQLITE_CREATE_TEMP_TRIGGER;
|
||||
if( iTabDb==1 || isTemp ) code = SQLITE_CREATE_TEMP_TRIGGER;
|
||||
if( sqlite3AuthCheck(pParse, code, zName, pTab->zName, zDbTrig) ){
|
||||
goto trigger_cleanup;
|
||||
}
|
||||
if( sqlite3AuthCheck(pParse, SQLITE_INSERT, SCHEMA_TABLE(pTab->iDb),0,zDb)){
|
||||
if( sqlite3AuthCheck(pParse, SQLITE_INSERT, SCHEMA_TABLE(iTabDb),0,zDb)){
|
||||
goto trigger_cleanup;
|
||||
}
|
||||
}
|
||||
@ -161,8 +165,8 @@ void sqlite3BeginTrigger(
|
||||
pTrigger->name = zName;
|
||||
zName = 0;
|
||||
pTrigger->table = sqliteStrDup(pTableName->a[0].zName);
|
||||
pTrigger->iDb = iDb;
|
||||
pTrigger->iTabDb = pTab->iDb;
|
||||
pTrigger->pSchema = db->aDb[iDb].pSchema;
|
||||
pTrigger->pTabSchema = pTab->pSchema;
|
||||
pTrigger->op = op;
|
||||
pTrigger->tr_tm = tr_tm==TK_BEFORE ? TRIGGER_BEFORE : TRIGGER_AFTER;
|
||||
pTrigger->pWhen = sqlite3ExprDup(pWhen);
|
||||
@ -196,16 +200,18 @@ void sqlite3FinishTrigger(
|
||||
Trigger *pTrig = 0; /* The trigger whose construction is finishing up */
|
||||
sqlite3 *db = pParse->db; /* The database */
|
||||
DbFixer sFix;
|
||||
int iDb; /* Database containing the trigger */
|
||||
|
||||
pTrig = pParse->pNewTrigger;
|
||||
pParse->pNewTrigger = 0;
|
||||
if( pParse->nErr || pTrig==0 ) goto triggerfinish_cleanup;
|
||||
if( pParse->nErr || !pTrig ) goto triggerfinish_cleanup;
|
||||
iDb = sqlite3SchemaToIndex(pParse->db, pTrig->pSchema);
|
||||
pTrig->step_list = pStepList;
|
||||
while( pStepList ){
|
||||
pStepList->pTrig = pTrig;
|
||||
pStepList = pStepList->pNext;
|
||||
}
|
||||
if( sqlite3FixInit(&sFix, pParse, pTrig->iDb, "trigger", &pTrig->nameToken)
|
||||
if( sqlite3FixInit(&sFix, pParse, iDb, "trigger", &pTrig->nameToken)
|
||||
&& sqlite3FixTriggerStep(&sFix, pTrig->step_list) ){
|
||||
goto triggerfinish_cleanup;
|
||||
}
|
||||
@ -223,7 +229,7 @@ void sqlite3FinishTrigger(
|
||||
{ OP_String8, 0, 0, "CREATE TRIGGER "},
|
||||
{ OP_String8, 0, 0, 0 }, /* 6: SQL */
|
||||
{ OP_Concat, 0, 0, 0 },
|
||||
{ OP_MakeRecord, 5, 0, "tttit" },
|
||||
{ OP_MakeRecord, 5, 0, "aaada" },
|
||||
{ OP_Insert, 0, 0, 0 },
|
||||
};
|
||||
int addr;
|
||||
@ -232,28 +238,30 @@ void sqlite3FinishTrigger(
|
||||
/* Make an entry in the sqlite_master table */
|
||||
v = sqlite3GetVdbe(pParse);
|
||||
if( v==0 ) goto triggerfinish_cleanup;
|
||||
sqlite3BeginWriteOperation(pParse, 0, pTrig->iDb);
|
||||
sqlite3OpenMasterTable(v, pTrig->iDb);
|
||||
sqlite3BeginWriteOperation(pParse, 0, iDb);
|
||||
sqlite3OpenMasterTable(pParse, iDb);
|
||||
addr = sqlite3VdbeAddOpList(v, ArraySize(insertTrig), insertTrig);
|
||||
sqlite3VdbeChangeP3(v, addr+2, pTrig->name, 0);
|
||||
sqlite3VdbeChangeP3(v, addr+3, pTrig->table, 0);
|
||||
sqlite3VdbeChangeP3(v, addr+6, pAll->z, pAll->n);
|
||||
sqlite3ChangeCookie(db, v, pTrig->iDb);
|
||||
sqlite3VdbeChangeP3(v, addr+6, (char*)pAll->z, pAll->n);
|
||||
sqlite3ChangeCookie(db, v, iDb);
|
||||
sqlite3VdbeAddOp(v, OP_Close, 0, 0);
|
||||
sqlite3VdbeOp3(v, OP_ParseSchema, pTrig->iDb, 0,
|
||||
sqlite3VdbeOp3(v, OP_ParseSchema, iDb, 0,
|
||||
sqlite3MPrintf("type='trigger' AND name='%q'", pTrig->name), P3_DYNAMIC);
|
||||
}
|
||||
|
||||
if( db->init.busy ){
|
||||
int n;
|
||||
Table *pTab;
|
||||
Trigger *pDel;
|
||||
pDel = sqlite3HashInsert(&db->aDb[pTrig->iDb].trigHash,
|
||||
pDel = sqlite3HashInsert(&db->aDb[iDb].pSchema->trigHash,
|
||||
pTrig->name, strlen(pTrig->name)+1, pTrig);
|
||||
if( pDel ){
|
||||
assert( sqlite3_malloc_failed && pDel==pTrig );
|
||||
assert( sqlite3MallocFailed() && pDel==pTrig );
|
||||
goto triggerfinish_cleanup;
|
||||
}
|
||||
pTab = sqlite3LocateTable(pParse,pTrig->table,db->aDb[pTrig->iTabDb].zName);
|
||||
n = strlen(pTrig->table) + 1;
|
||||
pTab = sqlite3HashFind(&pTrig->pTabSchema->tblHash, pTrig->table, n);
|
||||
assert( pTab!=0 );
|
||||
pTrig->pNext = pTab->pTrigger;
|
||||
pTab->pTrigger = pTrig;
|
||||
@ -278,7 +286,7 @@ triggerfinish_cleanup:
|
||||
*/
|
||||
static void sqlitePersistTriggerStep(TriggerStep *p){
|
||||
if( p->target.z ){
|
||||
p->target.z = sqliteStrNDup(p->target.z, p->target.n);
|
||||
p->target.z = (u8*)sqliteStrNDup((char*)p->target.z, p->target.n);
|
||||
p->target.dyn = 1;
|
||||
}
|
||||
if( p->pSelect ){
|
||||
@ -312,7 +320,10 @@ static void sqlitePersistTriggerStep(TriggerStep *p){
|
||||
*/
|
||||
TriggerStep *sqlite3TriggerSelectStep(Select *pSelect){
|
||||
TriggerStep *pTriggerStep = sqliteMalloc(sizeof(TriggerStep));
|
||||
if( pTriggerStep==0 ) return 0;
|
||||
if( pTriggerStep==0 ) {
|
||||
sqlite3SelectDelete(pSelect);
|
||||
return 0;
|
||||
}
|
||||
|
||||
pTriggerStep->op = TK_SELECT;
|
||||
pTriggerStep->pSelect = pSelect;
|
||||
@ -430,7 +441,7 @@ void sqlite3DropTrigger(Parse *pParse, SrcList *pName){
|
||||
int nName;
|
||||
sqlite3 *db = pParse->db;
|
||||
|
||||
if( sqlite3_malloc_failed ) goto drop_trigger_cleanup;
|
||||
if( sqlite3MallocFailed() ) goto drop_trigger_cleanup;
|
||||
if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){
|
||||
goto drop_trigger_cleanup;
|
||||
}
|
||||
@ -442,7 +453,7 @@ void sqlite3DropTrigger(Parse *pParse, SrcList *pName){
|
||||
for(i=OMIT_TEMPDB; i<db->nDb; i++){
|
||||
int j = (i<2) ? i^1 : i; /* Search TEMP before MAIN */
|
||||
if( zDb && sqlite3StrICmp(db->aDb[j].zName, zDb) ) continue;
|
||||
pTrigger = sqlite3HashFind(&(db->aDb[j].trigHash), zName, nName+1);
|
||||
pTrigger = sqlite3HashFind(&(db->aDb[j].pSchema->trigHash), zName, nName+1);
|
||||
if( pTrigger ) break;
|
||||
}
|
||||
if( !pTrigger ){
|
||||
@ -460,7 +471,8 @@ drop_trigger_cleanup:
|
||||
** is set on.
|
||||
*/
|
||||
static Table *tableOfTrigger(sqlite3 *db, Trigger *pTrigger){
|
||||
return sqlite3FindTable(db,pTrigger->table,db->aDb[pTrigger->iTabDb].zName);
|
||||
int n = strlen(pTrigger->table) + 1;
|
||||
return sqlite3HashFind(&pTrigger->pTabSchema->tblHash, pTrigger->table, n);
|
||||
}
|
||||
|
||||
|
||||
@ -475,11 +487,11 @@ void sqlite3DropTriggerPtr(Parse *pParse, Trigger *pTrigger, int nested){
|
||||
sqlite3 *db = pParse->db;
|
||||
int iDb;
|
||||
|
||||
iDb = pTrigger->iDb;
|
||||
iDb = sqlite3SchemaToIndex(pParse->db, pTrigger->pSchema);
|
||||
assert( iDb>=0 && iDb<db->nDb );
|
||||
pTable = tableOfTrigger(db, pTrigger);
|
||||
assert(pTable);
|
||||
assert( pTable->iDb==iDb || iDb==1 );
|
||||
assert( pTable->pSchema==pTrigger->pSchema || iDb==1 );
|
||||
#ifndef SQLITE_OMIT_AUTHORIZATION
|
||||
{
|
||||
int code = SQLITE_DROP_TRIGGER;
|
||||
@ -510,7 +522,7 @@ void sqlite3DropTriggerPtr(Parse *pParse, Trigger *pTrigger, int nested){
|
||||
};
|
||||
|
||||
sqlite3BeginWriteOperation(pParse, 0, iDb);
|
||||
sqlite3OpenMasterTable(v, iDb);
|
||||
sqlite3OpenMasterTable(pParse, iDb);
|
||||
base = sqlite3VdbeAddOpList(v, ArraySize(dropTrigger), dropTrigger);
|
||||
sqlite3VdbeChangeP3(v, base+1, pTrigger->name, 0);
|
||||
sqlite3ChangeCookie(db, v, iDb);
|
||||
@ -525,7 +537,7 @@ void sqlite3DropTriggerPtr(Parse *pParse, Trigger *pTrigger, int nested){
|
||||
void sqlite3UnlinkAndDeleteTrigger(sqlite3 *db, int iDb, const char *zName){
|
||||
Trigger *pTrigger;
|
||||
int nName = strlen(zName);
|
||||
pTrigger = sqlite3HashInsert(&(db->aDb[iDb].trigHash), zName, nName+1, 0);
|
||||
pTrigger = sqlite3HashInsert(&(db->aDb[iDb].pSchema->trigHash), zName, nName+1, 0);
|
||||
if( pTrigger ){
|
||||
Table *pTable = tableOfTrigger(db, pTrigger);
|
||||
assert( pTable!=0 );
|
||||
@ -617,11 +629,11 @@ static SrcList *targetSrcList(
|
||||
int iDb; /* Index of the database to use */
|
||||
SrcList *pSrc; /* SrcList to be returned */
|
||||
|
||||
iDb = pStep->pTrig->iDb;
|
||||
iDb = sqlite3SchemaToIndex(pParse->db, pStep->pTrig->pSchema);
|
||||
if( iDb==0 || iDb>=2 ){
|
||||
assert( iDb<pParse->db->nDb );
|
||||
sDb.z = pParse->db->aDb[iDb].zName;
|
||||
sDb.n = strlen(sDb.z);
|
||||
sDb.z = (u8*)pParse->db->aDb[iDb].zName;
|
||||
sDb.n = strlen((char*)sDb.z);
|
||||
pSrc = sqlite3SrcListAppend(0, &sDb, &pStep->target);
|
||||
} else {
|
||||
pSrc = sqlite3SrcListAppend(0, &pStep->target, 0);
|
||||
@ -730,8 +742,7 @@ int sqlite3CodeRowTrigger(
|
||||
int orconf, /* ON CONFLICT policy */
|
||||
int ignoreJump /* Instruction to jump to for RAISE(IGNORE) */
|
||||
){
|
||||
Trigger *pTrigger;
|
||||
TriggerStack *pStack;
|
||||
Trigger *p;
|
||||
TriggerStack trigStackEntry;
|
||||
|
||||
assert(op == TK_UPDATE || op == TK_INSERT || op == TK_DELETE);
|
||||
@ -739,21 +750,20 @@ int sqlite3CodeRowTrigger(
|
||||
|
||||
assert(newIdx != -1 || oldIdx != -1);
|
||||
|
||||
pTrigger = pTab->pTrigger;
|
||||
while( pTrigger ){
|
||||
for(p=pTab->pTrigger; p; p=p->pNext){
|
||||
int fire_this = 0;
|
||||
|
||||
/* determine whether we should code this trigger */
|
||||
if( pTrigger->op == op && pTrigger->tr_tm == tr_tm ){
|
||||
fire_this = 1;
|
||||
for(pStack=pParse->trigStack; pStack; pStack=pStack->pNext){
|
||||
if( pStack->pTrigger==pTrigger ){
|
||||
fire_this = 0;
|
||||
}
|
||||
}
|
||||
if( op == TK_UPDATE && pTrigger->pColumns &&
|
||||
!checkColumnOverLap(pTrigger->pColumns, pChanges) ){
|
||||
fire_this = 0;
|
||||
/* Determine whether we should code this trigger */
|
||||
if(
|
||||
p->op==op &&
|
||||
p->tr_tm==tr_tm &&
|
||||
(p->pSchema==p->pTabSchema || p->pSchema==pParse->db->aDb[1].pSchema) &&
|
||||
(op!=TK_UPDATE||!p->pColumns||checkColumnOverLap(p->pColumns,pChanges))
|
||||
){
|
||||
TriggerStack *pS; /* Pointer to trigger-stack entry */
|
||||
for(pS=pParse->trigStack; pS && p!=pS->pTrigger; pS=pS->pNext);
|
||||
if( !pS ){
|
||||
fire_this = 1;
|
||||
}
|
||||
}
|
||||
|
||||
@ -767,18 +777,18 @@ int sqlite3CodeRowTrigger(
|
||||
sNC.pParse = pParse;
|
||||
|
||||
/* Push an entry on to the trigger stack */
|
||||
trigStackEntry.pTrigger = pTrigger;
|
||||
trigStackEntry.pTrigger = p;
|
||||
trigStackEntry.newIdx = newIdx;
|
||||
trigStackEntry.oldIdx = oldIdx;
|
||||
trigStackEntry.pTab = pTab;
|
||||
trigStackEntry.pNext = pParse->trigStack;
|
||||
trigStackEntry.ignoreJump = ignoreJump;
|
||||
pParse->trigStack = &trigStackEntry;
|
||||
sqlite3AuthContextPush(pParse, &sContext, pTrigger->name);
|
||||
sqlite3AuthContextPush(pParse, &sContext, p->name);
|
||||
|
||||
/* code the WHEN clause */
|
||||
endTrigger = sqlite3VdbeMakeLabel(pParse->pVdbe);
|
||||
whenExpr = sqlite3ExprDup(pTrigger->pWhen);
|
||||
whenExpr = sqlite3ExprDup(p->pWhen);
|
||||
if( sqlite3ExprResolveNames(&sNC, whenExpr) ){
|
||||
pParse->trigStack = trigStackEntry.pNext;
|
||||
sqlite3ExprDelete(whenExpr);
|
||||
@ -787,7 +797,7 @@ int sqlite3CodeRowTrigger(
|
||||
sqlite3ExprIfFalse(pParse, whenExpr, endTrigger, 1);
|
||||
sqlite3ExprDelete(whenExpr);
|
||||
|
||||
codeTriggerProgram(pParse, pTrigger->step_list, orconf);
|
||||
codeTriggerProgram(pParse, p->step_list, orconf);
|
||||
|
||||
/* Pop the entry off the trigger stack */
|
||||
pParse->trigStack = trigStackEntry.pNext;
|
||||
@ -795,7 +805,6 @@ int sqlite3CodeRowTrigger(
|
||||
|
||||
sqlite3VdbeResolveLabel(pParse->pVdbe, endTrigger);
|
||||
}
|
||||
pTrigger = pTrigger->pNext;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -12,13 +12,13 @@
|
||||
** This file contains C code routines that are called by the parser
|
||||
** to handle UPDATE statements.
|
||||
**
|
||||
** $Id: update.c,v 1.112 2005/09/20 17:42:23 drh Exp $
|
||||
** $Id: update.c,v 1.121 2006/01/18 16:51:36 danielk1977 Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
|
||||
/*
|
||||
** The most recently coded instruction was an OP_Column to retrieve column
|
||||
** 'i' of table pTab. This routine sets the P3 parameter of the
|
||||
** The most recently coded instruction was an OP_Column to retrieve the
|
||||
** i-th column of table pTab. This routine sets the P3 parameter of the
|
||||
** OP_Column to the default value, if any.
|
||||
**
|
||||
** The default value of a column is specified by a DEFAULT clause in the
|
||||
@ -44,7 +44,7 @@
|
||||
void sqlite3ColumnDefault(Vdbe *v, Table *pTab, int i){
|
||||
if( pTab && !pTab->pSelect ){
|
||||
sqlite3_value *pValue;
|
||||
u8 enc = sqlite3VdbeDb(v)->enc;
|
||||
u8 enc = ENC(sqlite3VdbeDb(v));
|
||||
Column *pCol = &pTab->aCol[i];
|
||||
sqlite3ValueFromExpr(pCol->pDflt, enc, pCol->affinity, &pValue);
|
||||
if( pValue ){
|
||||
@ -89,6 +89,7 @@ void sqlite3Update(
|
||||
int openAll = 0; /* True if all indices need to be opened */
|
||||
AuthContext sContext; /* The authorization context */
|
||||
NameContext sNC; /* The name-context to resolve expressions in */
|
||||
int iDb; /* Database containing the table being updated */
|
||||
|
||||
#ifndef SQLITE_OMIT_TRIGGER
|
||||
int isView; /* Trying to update a view */
|
||||
@ -99,7 +100,9 @@ void sqlite3Update(
|
||||
int oldIdx = -1; /* index of trigger "old" temp table */
|
||||
|
||||
sContext.pParse = 0;
|
||||
if( pParse->nErr || sqlite3_malloc_failed ) goto update_cleanup;
|
||||
if( pParse->nErr || sqlite3MallocFailed() ){
|
||||
goto update_cleanup;
|
||||
}
|
||||
db = pParse->db;
|
||||
assert( pTabList->nSrc==1 );
|
||||
|
||||
@ -107,6 +110,7 @@ void sqlite3Update(
|
||||
*/
|
||||
pTab = sqlite3SrcListLookup(pParse, pTabList);
|
||||
if( pTab==0 ) goto update_cleanup;
|
||||
iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
|
||||
|
||||
/* Figure out if we have any triggers and if the table being
|
||||
** updated is a view
|
||||
@ -192,7 +196,7 @@ void sqlite3Update(
|
||||
{
|
||||
int rc;
|
||||
rc = sqlite3AuthCheck(pParse, SQLITE_UPDATE, pTab->zName,
|
||||
pTab->aCol[j].zName, db->aDb[pTab->iDb].zName);
|
||||
pTab->aCol[j].zName, db->aDb[iDb].zName);
|
||||
if( rc==SQLITE_DENY ){
|
||||
goto update_cleanup;
|
||||
}else if( rc==SQLITE_IGNORE ){
|
||||
@ -231,7 +235,6 @@ void sqlite3Update(
|
||||
}
|
||||
}
|
||||
if( i<pIdx->nColumn ){
|
||||
if( sqlite3CheckIndexCollSeq(pParse, pIdx) ) goto update_cleanup;
|
||||
apIdx[nIdx++] = pIdx;
|
||||
aIdxUsed[j] = 1;
|
||||
}else{
|
||||
@ -257,7 +260,7 @@ void sqlite3Update(
|
||||
v = sqlite3GetVdbe(pParse);
|
||||
if( v==0 ) goto update_cleanup;
|
||||
if( pParse->nested==0 ) sqlite3VdbeCountChanges(v);
|
||||
sqlite3BeginWriteOperation(pParse, 1, pTab->iDb);
|
||||
sqlite3BeginWriteOperation(pParse, 1, iDb);
|
||||
|
||||
/* If we are trying to update a view, realize that view into
|
||||
** a ephemeral table.
|
||||
@ -307,7 +310,7 @@ void sqlite3Update(
|
||||
/* Open a cursor and make it point to the record that is
|
||||
** being updated.
|
||||
*/
|
||||
sqlite3OpenTableForReading(v, iCur, pTab);
|
||||
sqlite3OpenTable(pParse, iCur, iDb, pTab, OP_OpenRead);
|
||||
}
|
||||
sqlite3VdbeAddOp(v, OP_MoveGe, iCur, 0);
|
||||
|
||||
@ -362,9 +365,7 @@ void sqlite3Update(
|
||||
** action, then we need to open all indices because we might need
|
||||
** to be deleting some records.
|
||||
*/
|
||||
sqlite3VdbeAddOp(v, OP_Integer, pTab->iDb, 0);
|
||||
sqlite3VdbeAddOp(v, OP_OpenWrite, iCur, pTab->tnum);
|
||||
sqlite3VdbeAddOp(v, OP_SetNumColumns, iCur, pTab->nCol);
|
||||
sqlite3OpenTable(pParse, iCur, iDb, pTab, OP_OpenWrite);
|
||||
if( onError==OE_Replace ){
|
||||
openAll = 1;
|
||||
}else{
|
||||
@ -378,9 +379,10 @@ void sqlite3Update(
|
||||
}
|
||||
for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
|
||||
if( openAll || aIdxUsed[i] ){
|
||||
sqlite3VdbeAddOp(v, OP_Integer, pIdx->iDb, 0);
|
||||
KeyInfo *pKey = sqlite3IndexKeyinfo(pParse, pIdx);
|
||||
sqlite3VdbeAddOp(v, OP_Integer, iDb, 0);
|
||||
sqlite3VdbeOp3(v, OP_OpenWrite, iCur+i+1, pIdx->tnum,
|
||||
(char*)&pIdx->keyInfo, P3_KEYINFO);
|
||||
(char*)pKey, P3_KEYINFO_HANDOFF);
|
||||
assert( pParse->nTab>iCur+i+1 );
|
||||
}
|
||||
}
|
||||
|
||||
@ -12,7 +12,7 @@
|
||||
** This file contains routines used to translate between UTF-8,
|
||||
** UTF-16, UTF-16BE, and UTF-16LE.
|
||||
**
|
||||
** $Id: utf.c,v 1.32 2005/01/28 01:29:08 drh Exp $
|
||||
** $Id: utf.c,v 1.37 2006/01/24 10:58:22 danielk1977 Exp $
|
||||
**
|
||||
** Notes on UTF-8:
|
||||
**
|
||||
@ -272,7 +272,7 @@ int sqlite3VdbeMemTranslate(Mem *pMem, u8 desiredEnc){
|
||||
assert( rc==SQLITE_NOMEM );
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
zIn = pMem->z;
|
||||
zIn = (u8*)pMem->z;
|
||||
zTerm = &zIn[pMem->n];
|
||||
while( zIn<zTerm ){
|
||||
temp = *zIn;
|
||||
@ -308,7 +308,7 @@ int sqlite3VdbeMemTranslate(Mem *pMem, u8 desiredEnc){
|
||||
** obtained from malloc(), or Mem.zShort, if it large enough and not in
|
||||
** use, or the zShort array on the stack (see above).
|
||||
*/
|
||||
zIn = pMem->z;
|
||||
zIn = (u8*)pMem->z;
|
||||
zTerm = &zIn[pMem->n];
|
||||
if( len>NBFS ){
|
||||
zOut = sqliteMallocRaw(len);
|
||||
@ -360,12 +360,12 @@ int sqlite3VdbeMemTranslate(Mem *pMem, u8 desiredEnc){
|
||||
pMem->enc = desiredEnc;
|
||||
if( zOut==zShort ){
|
||||
memcpy(pMem->zShort, zOut, len);
|
||||
zOut = pMem->zShort;
|
||||
zOut = (u8*)pMem->zShort;
|
||||
pMem->flags |= (MEM_Term|MEM_Short);
|
||||
}else{
|
||||
pMem->flags |= (MEM_Term|MEM_Dyn);
|
||||
}
|
||||
pMem->z = zOut;
|
||||
pMem->z = (char*)zOut;
|
||||
|
||||
translate_out:
|
||||
#if defined(TRANSLATE_TRACE) && defined(SQLITE_DEBUG)
|
||||
@ -450,6 +450,23 @@ int sqlite3utf8CharLen(const char *z, int nByte){
|
||||
}
|
||||
|
||||
#ifndef SQLITE_OMIT_UTF16
|
||||
/*
|
||||
** Convert a UTF-16 string in the native encoding into a UTF-8 string.
|
||||
** Memory to hold the UTF-8 string is obtained from malloc and must be
|
||||
** freed by the calling function.
|
||||
**
|
||||
** NULL is returned if there is an allocation error.
|
||||
*/
|
||||
char *sqlite3utf16to8(const void *z, int nByte){
|
||||
Mem m;
|
||||
memset(&m, 0, sizeof(m));
|
||||
sqlite3VdbeMemSetStr(&m, z, nByte, SQLITE_UTF16NATIVE, SQLITE_STATIC);
|
||||
sqlite3VdbeChangeEncoding(&m, SQLITE_UTF8);
|
||||
assert( m.flags & MEM_Term );
|
||||
assert( m.flags & MEM_Str );
|
||||
return (m.flags & MEM_Dyn)!=0 ? m.z : sqliteStrDup(m.z);
|
||||
}
|
||||
|
||||
/*
|
||||
** pZ is a UTF-16 encoded unicode string. If nChar is less than zero,
|
||||
** return the number of bytes up to (but not including), the first pair
|
||||
@ -462,6 +479,15 @@ int sqlite3utf16ByteLen(const void *zIn, int nChar){
|
||||
char const *z = zIn;
|
||||
int n = 0;
|
||||
if( SQLITE_UTF16NATIVE==SQLITE_UTF16BE ){
|
||||
/* Using an "if (SQLITE_UTF16NATIVE==SQLITE_UTF16BE)" construct here
|
||||
** and in other parts of this file means that at one branch will
|
||||
** not be covered by coverage testing on any single host. But coverage
|
||||
** will be complete if the tests are run on both a little-endian and
|
||||
** big-endian host. Because both the UTF16NATIVE and SQLITE_UTF16BE
|
||||
** macros are constant at compile time the compiler can determine
|
||||
** which branch will be followed. It is therefore assumed that no runtime
|
||||
** penalty is paid for this "if" statement.
|
||||
*/
|
||||
while( c && ((nChar<0) || n<nChar) ){
|
||||
READ_UTF16BE(z, c);
|
||||
n++;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -14,9 +14,10 @@
|
||||
** Most of the code in this file may be omitted by defining the
|
||||
** SQLITE_OMIT_VACUUM macro.
|
||||
**
|
||||
** $Id: vacuum.c,v 1.45 2005/06/07 09:21:07 danielk1977 Exp $
|
||||
** $Id: vacuum.c,v 1.58 2006/01/18 16:51:36 danielk1977 Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include "vdbeInt.h"
|
||||
#include "os.h"
|
||||
|
||||
#ifndef SQLITE_OMIT_VACUUM
|
||||
@ -58,7 +59,7 @@ static int execExecSql(sqlite3 *db, const char *zSql){
|
||||
if( rc!=SQLITE_OK ) return rc;
|
||||
|
||||
while( SQLITE_ROW==sqlite3_step(pStmt) ){
|
||||
rc = execSql(db, sqlite3_column_text(pStmt, 0));
|
||||
rc = execSql(db, (char*)sqlite3_column_text(pStmt, 0));
|
||||
if( rc!=SQLITE_OK ){
|
||||
sqlite3_finalize(pStmt);
|
||||
return rc;
|
||||
@ -100,11 +101,12 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
|
||||
Btree *pMain; /* The database being vacuumed */
|
||||
Btree *pTemp;
|
||||
char *zSql = 0;
|
||||
int writeschema_flag; /* Saved value of the write-schema flag */
|
||||
int saved_flags; /* Saved value of the db->flags */
|
||||
Db *pDb = 0; /* Database to detach at end of vacuum */
|
||||
|
||||
/* Save the current value of the write-schema flag before setting it. */
|
||||
writeschema_flag = db->flags&SQLITE_WriteSchema;
|
||||
db->flags |= SQLITE_WriteSchema;
|
||||
saved_flags = db->flags;
|
||||
db->flags |= SQLITE_WriteSchema | SQLITE_IgnoreChecks;
|
||||
|
||||
if( !db->autoCommit ){
|
||||
sqlite3SetString(pzErrMsg, "cannot VACUUM from within a transaction",
|
||||
@ -164,19 +166,23 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
|
||||
sqliteFree(zSql);
|
||||
zSql = 0;
|
||||
if( rc!=SQLITE_OK ) goto end_of_vacuum;
|
||||
pDb = &db->aDb[db->nDb-1];
|
||||
assert( strcmp(db->aDb[db->nDb-1].zName,"vacuum_db")==0 );
|
||||
pTemp = db->aDb[db->nDb-1].pBt;
|
||||
sqlite3BtreeSetPageSize(pTemp, sqlite3BtreeGetPageSize(pMain),
|
||||
sqlite3BtreeGetReserve(pMain));
|
||||
assert( sqlite3BtreeGetPageSize(pTemp)==sqlite3BtreeGetPageSize(pMain) );
|
||||
execSql(db, "PRAGMA vacuum_db.synchronous=OFF");
|
||||
rc = execSql(db, "PRAGMA vacuum_db.synchronous=OFF");
|
||||
if( rc!=SQLITE_OK ){
|
||||
goto end_of_vacuum;
|
||||
}
|
||||
|
||||
#ifndef SQLITE_OMIT_AUTOVACUUM
|
||||
sqlite3BtreeSetAutoVacuum(pTemp, sqlite3BtreeGetAutoVacuum(pMain));
|
||||
#endif
|
||||
|
||||
/* Begin a transaction */
|
||||
rc = execSql(db, "BEGIN;");
|
||||
rc = execSql(db, "BEGIN EXCLUSIVE;");
|
||||
if( rc!=SQLITE_OK ) goto end_of_vacuum;
|
||||
|
||||
/* Query the schema of the main database. Create a mirror schema
|
||||
@ -247,7 +253,7 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
|
||||
** opened for writing. This way, the SQL transaction used to create the
|
||||
** temporary database never needs to be committed.
|
||||
*/
|
||||
if( sqlite3BtreeIsInTrans(pTemp) ){
|
||||
if( rc==SQLITE_OK ){
|
||||
u32 meta;
|
||||
int i;
|
||||
|
||||
@ -264,26 +270,27 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
|
||||
6, 0, /* Preserve the user version */
|
||||
};
|
||||
|
||||
assert( 0==sqlite3BtreeIsInTrans(pMain) );
|
||||
rc = sqlite3BtreeBeginTrans(pMain, 1);
|
||||
if( rc!=SQLITE_OK ) goto end_of_vacuum;
|
||||
assert( 1==sqlite3BtreeIsInTrans(pTemp) );
|
||||
assert( 1==sqlite3BtreeIsInTrans(pMain) );
|
||||
|
||||
/* Copy Btree meta values */
|
||||
for(i=0; i<sizeof(aCopy)/sizeof(aCopy[0]); i+=2){
|
||||
rc = sqlite3BtreeGetMeta(pMain, aCopy[i], &meta);
|
||||
if( rc!=SQLITE_OK ) goto end_of_vacuum;
|
||||
rc = sqlite3BtreeUpdateMeta(pTemp, aCopy[i], meta+aCopy[i+1]);
|
||||
if( rc!=SQLITE_OK ) goto end_of_vacuum;
|
||||
}
|
||||
|
||||
rc = sqlite3BtreeCopyFile(pMain, pTemp);
|
||||
if( rc!=SQLITE_OK ) goto end_of_vacuum;
|
||||
rc = sqlite3BtreeCommit(pTemp);
|
||||
if( rc!=SQLITE_OK ) goto end_of_vacuum;
|
||||
rc = sqlite3BtreeCommit(pMain);
|
||||
}
|
||||
|
||||
end_of_vacuum:
|
||||
/* Restore the original value of the write-schema flag. */
|
||||
db->flags &= ~SQLITE_WriteSchema;
|
||||
db->flags |= writeschema_flag;
|
||||
/* Restore the original value of db->flags */
|
||||
db->flags = saved_flags;
|
||||
|
||||
/* Currently there is an SQL level transaction open on the vacuum
|
||||
** database. No locks are held on any other files (since the main file
|
||||
@ -293,16 +300,28 @@ end_of_vacuum:
|
||||
** is closed by the DETACH.
|
||||
*/
|
||||
db->autoCommit = 1;
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = execSql(db, "DETACH vacuum_db;");
|
||||
}else{
|
||||
execSql(db, "DETACH vacuum_db;");
|
||||
|
||||
if( pDb ){
|
||||
sqlite3MallocDisallow();
|
||||
sqlite3BtreeClose(pDb->pBt);
|
||||
sqlite3MallocAllow();
|
||||
pDb->pBt = 0;
|
||||
pDb->pSchema = 0;
|
||||
}
|
||||
|
||||
/* If one of the execSql() calls above returned SQLITE_NOMEM, then the
|
||||
** mallocFailed flag will be clear (because execSql() calls sqlite3_exec()).
|
||||
** Fix this so the flag and return code match.
|
||||
*/
|
||||
if( rc==SQLITE_NOMEM ){
|
||||
sqlite3MallocFailed();
|
||||
}
|
||||
|
||||
if( zTemp ){
|
||||
sqlite3OsDelete(zTemp);
|
||||
sqliteFree(zTemp);
|
||||
}
|
||||
if( zSql ) sqliteFree( zSql );
|
||||
sqliteFree( zSql );
|
||||
sqlite3ResetInternalSchema(db, 0);
|
||||
#endif
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -60,6 +60,7 @@ typedef unsigned char Bool;
|
||||
*/
|
||||
struct Cursor {
|
||||
BtCursor *pCursor; /* The cursor structure of the backend */
|
||||
int iDb; /* Index of cursor database in db->aDb[] (or -1) */
|
||||
i64 lastRowid; /* Last rowid from a Next or NextIdx operation */
|
||||
i64 nextRowid; /* Next rowid returned by OP_NewRowid */
|
||||
Bool zeroed; /* True if zeroed out and ready for reuse */
|
||||
@ -85,9 +86,10 @@ struct Cursor {
|
||||
|
||||
/* Cached information about the header for the data record that the
|
||||
** cursor is currently pointing to. Only valid if cacheValid is true.
|
||||
** zRow might point to (ephemeral) data for the current row, or it might
|
||||
** be NULL. */
|
||||
Bool cacheValid; /* True if the cache is valid */
|
||||
** aRow might point to (ephemeral) data for the current row, or it might
|
||||
** be NULL.
|
||||
*/
|
||||
int cacheStatus; /* Cache is valid if this matches Vdbe.cacheCtr */
|
||||
int payloadSize; /* Total number of bytes in the record */
|
||||
u32 *aType; /* Type values for all entries in the record */
|
||||
u32 *aOffset; /* Cached offsets to the start of each columns data */
|
||||
@ -102,6 +104,11 @@ typedef struct Cursor Cursor;
|
||||
*/
|
||||
#define NBFS 32
|
||||
|
||||
/*
|
||||
** A value for Cursor.cacheValid that means the cache is always invalid.
|
||||
*/
|
||||
#define CACHE_STALE 0
|
||||
|
||||
/*
|
||||
** Internally, the vdbe manipulates nearly all SQL values as Mem
|
||||
** structures. Each Mem struct may cache multiple representations (string,
|
||||
@ -250,7 +257,7 @@ struct Fifo {
|
||||
*/
|
||||
typedef struct Context Context;
|
||||
struct Context {
|
||||
int lastRowid; /* Last insert rowid (sqlite3.lastRowid) */
|
||||
i64 lastRowid; /* Last insert rowid (sqlite3.lastRowid) */
|
||||
int nChange; /* Statement changes (Vdbe.nChanges) */
|
||||
Fifo sFifo; /* Records that will participate in a DELETE or UPDATE */
|
||||
};
|
||||
@ -286,6 +293,7 @@ struct Vdbe {
|
||||
int nMem; /* Number of memory locations currently allocated */
|
||||
Mem *aMem; /* The memory locations */
|
||||
int nCallback; /* Number of callbacks invoked so far */
|
||||
int cacheCtr; /* Cursor row cache generation counter */
|
||||
Fifo sFifo; /* A list of ROWIDs */
|
||||
int contextStackTop; /* Index of top element in the context stack */
|
||||
int contextStackDepth; /* The size of the "context" stack */
|
||||
@ -306,6 +314,7 @@ struct Vdbe {
|
||||
u8 changeCntOn; /* True to update the change-counter */
|
||||
u8 aborted; /* True if ROLLBACK in another VM causes an abort */
|
||||
u8 expired; /* True if the VM needs to be recompiled */
|
||||
u8 minWriteFileFormat; /* Minimum file format for writable database files */
|
||||
int nChange; /* Number of db changes made since last reset */
|
||||
i64 startTime; /* Time when query started - used for profiling */
|
||||
};
|
||||
@ -331,8 +340,8 @@ void sqlite3VdbePrintOp(FILE*, int, Op*);
|
||||
void sqlite3VdbePrintSql(Vdbe*);
|
||||
#endif
|
||||
int sqlite3VdbeSerialTypeLen(u32);
|
||||
u32 sqlite3VdbeSerialType(Mem*);
|
||||
int sqlite3VdbeSerialPut(unsigned char*, Mem*);
|
||||
u32 sqlite3VdbeSerialType(Mem*, int);
|
||||
int sqlite3VdbeSerialPut(unsigned char*, Mem*, int);
|
||||
int sqlite3VdbeSerialGet(const unsigned char*, u32, Mem*);
|
||||
void sqlite3VdbeDeleteAuxData(VdbeFunc*, int);
|
||||
|
||||
@ -360,10 +369,12 @@ int sqlite3VdbeMemStringify(Mem*, int);
|
||||
i64 sqlite3VdbeIntValue(Mem*);
|
||||
int sqlite3VdbeMemIntegerify(Mem*);
|
||||
double sqlite3VdbeRealValue(Mem*);
|
||||
void sqlite3VdbeIntegerAffinity(Mem*);
|
||||
int sqlite3VdbeMemRealify(Mem*);
|
||||
int sqlite3VdbeMemNumerify(Mem*);
|
||||
int sqlite3VdbeMemFromBtree(BtCursor*,int,int,int,Mem*);
|
||||
void sqlite3VdbeMemRelease(Mem *p);
|
||||
void sqlite3VdbeMemFinalize(Mem*, FuncDef*);
|
||||
int sqlite3VdbeMemFinalize(Mem*, FuncDef*);
|
||||
#ifndef NDEBUG
|
||||
void sqlite3VdbeMemSanity(Mem*, u8);
|
||||
int sqlite3VdbeOpcodeNoPush(u8);
|
||||
|
||||
@ -58,7 +58,7 @@ sqlite_int64 sqlite3_value_int64(sqlite3_value *pVal){
|
||||
return sqlite3VdbeIntValue((Mem*)pVal);
|
||||
}
|
||||
const unsigned char *sqlite3_value_text(sqlite3_value *pVal){
|
||||
return (const char *)sqlite3ValueText(pVal, SQLITE_UTF8);
|
||||
return (const unsigned char *)sqlite3ValueText(pVal, SQLITE_UTF8);
|
||||
}
|
||||
#ifndef SQLITE_OMIT_UTF16
|
||||
const void *sqlite3_value_text16(sqlite3_value* pVal){
|
||||
@ -95,10 +95,12 @@ void sqlite3_result_error(sqlite3_context *pCtx, const char *z, int n){
|
||||
pCtx->isError = 1;
|
||||
sqlite3VdbeMemSetStr(&pCtx->s, z, n, SQLITE_UTF8, SQLITE_TRANSIENT);
|
||||
}
|
||||
#ifndef SQLITE_OMIT_UTF16
|
||||
void sqlite3_result_error16(sqlite3_context *pCtx, const void *z, int n){
|
||||
pCtx->isError = 1;
|
||||
sqlite3VdbeMemSetStr(&pCtx->s, z, n, SQLITE_UTF16NATIVE, SQLITE_TRANSIENT);
|
||||
}
|
||||
#endif
|
||||
void sqlite3_result_int(sqlite3_context *pCtx, int iVal){
|
||||
sqlite3VdbeMemSetInt64(&pCtx->s, (i64)iVal);
|
||||
}
|
||||
@ -156,6 +158,9 @@ int sqlite3_step(sqlite3_stmt *pStmt){
|
||||
sqlite3 *db;
|
||||
int rc;
|
||||
|
||||
/* Assert that malloc() has not failed */
|
||||
assert( !sqlite3MallocFailed() );
|
||||
|
||||
if( p==0 || p->magic!=VDBE_MAGIC_RUN ){
|
||||
return SQLITE_MISUSE;
|
||||
}
|
||||
@ -238,7 +243,8 @@ int sqlite3_step(sqlite3_stmt *pStmt){
|
||||
}
|
||||
#endif
|
||||
|
||||
sqlite3Error(p->db, rc, p->zErrMsg ? "%s" : 0, p->zErrMsg);
|
||||
sqlite3Error(p->db, rc, 0);
|
||||
p->rc = sqlite3ApiExit(p->db, p->rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -375,30 +381,76 @@ static Mem *columnMem(sqlite3_stmt *pStmt, int i){
|
||||
return &pVm->pTos[(1-vals)+i];
|
||||
}
|
||||
|
||||
/*
|
||||
** This function is called after invoking an sqlite3_value_XXX function on a
|
||||
** column value (i.e. a value returned by evaluating an SQL expression in the
|
||||
** select list of a SELECT statement) that may cause a malloc() failure. If
|
||||
** malloc() has failed, the threads mallocFailed flag is cleared and the result
|
||||
** code of statement pStmt set to SQLITE_NOMEM.
|
||||
**
|
||||
** Specificly, this is called from within:
|
||||
**
|
||||
** sqlite3_column_int()
|
||||
** sqlite3_column_int64()
|
||||
** sqlite3_column_text()
|
||||
** sqlite3_column_text16()
|
||||
** sqlite3_column_real()
|
||||
** sqlite3_column_bytes()
|
||||
** sqlite3_column_bytes16()
|
||||
**
|
||||
** But not for sqlite3_column_blob(), which never calls malloc().
|
||||
*/
|
||||
static void columnMallocFailure(sqlite3_stmt *pStmt)
|
||||
{
|
||||
/* If malloc() failed during an encoding conversion within an
|
||||
** sqlite3_column_XXX API, then set the return code of the statement to
|
||||
** SQLITE_NOMEM. The next call to _step() (if any) will return SQLITE_ERROR
|
||||
** and _finalize() will return NOMEM.
|
||||
*/
|
||||
Vdbe *p = (Vdbe *)pStmt;
|
||||
p->rc = sqlite3ApiExit(0, p->rc);
|
||||
}
|
||||
|
||||
/**************************** sqlite3_column_ *******************************
|
||||
** The following routines are used to access elements of the current row
|
||||
** in the result set.
|
||||
*/
|
||||
const void *sqlite3_column_blob(sqlite3_stmt *pStmt, int i){
|
||||
return sqlite3_value_blob( columnMem(pStmt,i) );
|
||||
const void *val;
|
||||
sqlite3MallocDisallow();
|
||||
val = sqlite3_value_blob( columnMem(pStmt,i) );
|
||||
sqlite3MallocAllow();
|
||||
return val;
|
||||
}
|
||||
int sqlite3_column_bytes(sqlite3_stmt *pStmt, int i){
|
||||
return sqlite3_value_bytes( columnMem(pStmt,i) );
|
||||
int val = sqlite3_value_bytes( columnMem(pStmt,i) );
|
||||
columnMallocFailure(pStmt);
|
||||
return val;
|
||||
}
|
||||
int sqlite3_column_bytes16(sqlite3_stmt *pStmt, int i){
|
||||
return sqlite3_value_bytes16( columnMem(pStmt,i) );
|
||||
int val = sqlite3_value_bytes16( columnMem(pStmt,i) );
|
||||
columnMallocFailure(pStmt);
|
||||
return val;
|
||||
}
|
||||
double sqlite3_column_double(sqlite3_stmt *pStmt, int i){
|
||||
return sqlite3_value_double( columnMem(pStmt,i) );
|
||||
double val = sqlite3_value_double( columnMem(pStmt,i) );
|
||||
columnMallocFailure(pStmt);
|
||||
return val;
|
||||
}
|
||||
int sqlite3_column_int(sqlite3_stmt *pStmt, int i){
|
||||
return sqlite3_value_int( columnMem(pStmt,i) );
|
||||
int val = sqlite3_value_int( columnMem(pStmt,i) );
|
||||
columnMallocFailure(pStmt);
|
||||
return val;
|
||||
}
|
||||
sqlite_int64 sqlite3_column_int64(sqlite3_stmt *pStmt, int i){
|
||||
return sqlite3_value_int64( columnMem(pStmt,i) );
|
||||
sqlite_int64 val = sqlite3_value_int64( columnMem(pStmt,i) );
|
||||
columnMallocFailure(pStmt);
|
||||
return val;
|
||||
}
|
||||
const unsigned char *sqlite3_column_text(sqlite3_stmt *pStmt, int i){
|
||||
return sqlite3_value_text( columnMem(pStmt,i) );
|
||||
const unsigned char *val = sqlite3_value_text( columnMem(pStmt,i) );
|
||||
columnMallocFailure(pStmt);
|
||||
return val;
|
||||
}
|
||||
#if 0
|
||||
sqlite3_value *sqlite3_column_value(sqlite3_stmt *pStmt, int i){
|
||||
@ -407,7 +459,9 @@ sqlite3_value *sqlite3_column_value(sqlite3_stmt *pStmt, int i){
|
||||
#endif
|
||||
#ifndef SQLITE_OMIT_UTF16
|
||||
const void *sqlite3_column_text16(sqlite3_stmt *pStmt, int i){
|
||||
return sqlite3_value_text16( columnMem(pStmt,i) );
|
||||
const void *val = sqlite3_value_text16( columnMem(pStmt,i) );
|
||||
columnMallocFailure(pStmt);
|
||||
return val;
|
||||
}
|
||||
#endif /* SQLITE_OMIT_UTF16 */
|
||||
int sqlite3_column_type(sqlite3_stmt *pStmt, int i){
|
||||
@ -436,6 +490,7 @@ static const void *columnName(
|
||||
const void *(*xFunc)(Mem*),
|
||||
int useType
|
||||
){
|
||||
const void *ret;
|
||||
Vdbe *p = (Vdbe *)pStmt;
|
||||
int n = sqlite3_column_count(pStmt);
|
||||
|
||||
@ -443,9 +498,14 @@ static const void *columnName(
|
||||
return 0;
|
||||
}
|
||||
N += useType*n;
|
||||
return xFunc(&p->aColName[N]);
|
||||
}
|
||||
ret = xFunc(&p->aColName[N]);
|
||||
|
||||
/* A malloc may have failed inside of the xFunc() call. If this is the case,
|
||||
** clear the mallocFailed flag and return NULL.
|
||||
*/
|
||||
sqlite3ApiExit(0, 0);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the name of the Nth column of the result set returned by SQL
|
||||
@ -571,13 +631,12 @@ static int bindText(
|
||||
}
|
||||
pVar = &p->aVar[i-1];
|
||||
rc = sqlite3VdbeMemSetStr(pVar, zData, nData, encoding, xDel);
|
||||
if( rc ){
|
||||
return rc;
|
||||
}
|
||||
if( rc==SQLITE_OK && encoding!=0 ){
|
||||
rc = sqlite3VdbeChangeEncoding(pVar, p->db->enc);
|
||||
rc = sqlite3VdbeChangeEncoding(pVar, ENC(p->db));
|
||||
}
|
||||
return rc;
|
||||
|
||||
sqlite3Error(((Vdbe *)pStmt)->db, rc, 0);
|
||||
return sqlite3ApiExit(((Vdbe *)pStmt)->db, rc);
|
||||
}
|
||||
|
||||
|
||||
@ -704,39 +763,6 @@ int sqlite3_bind_parameter_index(sqlite3_stmt *pStmt, const char *zName){
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Transfer all bindings from the first statement over to the second.
|
||||
** If the two statements contain a different number of bindings, then
|
||||
** an SQLITE_ERROR is returned.
|
||||
*/
|
||||
int sqlite3_transfer_bindings(sqlite3_stmt *pFromStmt, sqlite3_stmt *pToStmt){
|
||||
Vdbe *pFrom = (Vdbe*)pFromStmt;
|
||||
Vdbe *pTo = (Vdbe*)pToStmt;
|
||||
int i, rc = SQLITE_OK;
|
||||
if( (pFrom->magic!=VDBE_MAGIC_RUN && pFrom->magic!=VDBE_MAGIC_HALT)
|
||||
|| (pTo->magic!=VDBE_MAGIC_RUN && pTo->magic!=VDBE_MAGIC_HALT) ){
|
||||
return SQLITE_MISUSE;
|
||||
}
|
||||
if( pFrom->nVar!=pTo->nVar ){
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
for(i=0; rc==SQLITE_OK && i<pFrom->nVar; i++){
|
||||
rc = sqlite3VdbeMemMove(&pTo->aVar[i], &pFrom->aVar[i]);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the sqlite3* database handle to which the prepared statement given
|
||||
** in the argument belongs. This is the same database handle that was
|
||||
** the first argument to the sqlite3_prepare() that was used to create
|
||||
** the statement in the first place.
|
||||
*/
|
||||
sqlite3 *sqlite3_db_handle(sqlite3_stmt *pStmt){
|
||||
return pStmt ? ((Vdbe*)pStmt)->db : 0;
|
||||
}
|
||||
|
||||
/** experimental **/
|
||||
/*
|
||||
** Given a wildcard parameter name, return the set of indexes of the
|
||||
** variables with that name. If there are no variables with the given
|
||||
@ -754,7 +780,7 @@ int sqlite3_bind_parameter_indexes(
|
||||
if( p==0 ){
|
||||
return 0;
|
||||
}
|
||||
createVarMap(p);
|
||||
createVarMap(p);
|
||||
if( !zName )
|
||||
return 0;
|
||||
/* first count */
|
||||
@ -774,9 +800,43 @@ int sqlite3_bind_parameter_indexes(
|
||||
}
|
||||
*pIndexes = indexes;
|
||||
return nVars;
|
||||
}
|
||||
|
||||
void sqlite3_free_parameter_indexes(int *pIndexes)
|
||||
{
|
||||
sqliteFree( pIndexes );
|
||||
}
|
||||
|
||||
/*
|
||||
** Transfer all bindings from the first statement over to the second.
|
||||
** If the two statements contain a different number of bindings, then
|
||||
** an SQLITE_ERROR is returned.
|
||||
*/
|
||||
int sqlite3_transfer_bindings(sqlite3_stmt *pFromStmt, sqlite3_stmt *pToStmt){
|
||||
Vdbe *pFrom = (Vdbe*)pFromStmt;
|
||||
Vdbe *pTo = (Vdbe*)pToStmt;
|
||||
int i, rc = SQLITE_OK;
|
||||
if( (pFrom->magic!=VDBE_MAGIC_RUN && pFrom->magic!=VDBE_MAGIC_HALT)
|
||||
|| (pTo->magic!=VDBE_MAGIC_RUN && pTo->magic!=VDBE_MAGIC_HALT) ){
|
||||
return SQLITE_MISUSE;
|
||||
}
|
||||
if( pFrom->nVar!=pTo->nVar ){
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
for(i=0; rc==SQLITE_OK && i<pFrom->nVar; i++){
|
||||
sqlite3MallocDisallow();
|
||||
rc = sqlite3VdbeMemMove(&pTo->aVar[i], &pFrom->aVar[i]);
|
||||
sqlite3MallocAllow();
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
void sqlite3_free_parameter_indexes(int *pIndexes)
|
||||
{
|
||||
sqliteFree( pIndexes );
|
||||
/*
|
||||
** Return the sqlite3* database handle to which the prepared statement given
|
||||
** in the argument belongs. This is the same database handle that was
|
||||
** the first argument to the sqlite3_prepare() that was used to create
|
||||
** the statement in the first place.
|
||||
*/
|
||||
sqlite3 *sqlite3_db_handle(sqlite3_stmt *pStmt){
|
||||
return pStmt ? ((Vdbe*)pStmt)->db : 0;
|
||||
}
|
||||
|
||||
@ -58,8 +58,14 @@ void sqlite3VdbeTrace(Vdbe *p, FILE *trace){
|
||||
/*
|
||||
** Resize the Vdbe.aOp array so that it contains at least N
|
||||
** elements. If the Vdbe is in VDBE_MAGIC_RUN state, then
|
||||
** the Vdbe.aOp array will be sized to contain exactly N
|
||||
** elements.
|
||||
** the Vdbe.aOp array will be sized to contain exactly N
|
||||
** elements. Vdbe.nOpAlloc is set to reflect the new size of
|
||||
** the array.
|
||||
**
|
||||
** If an out-of-memory error occurs while resizing the array,
|
||||
** Vdbe.aOp and Vdbe.nOpAlloc remain unchanged (this is so that
|
||||
** any opcodes already allocated can be correctly deallocated
|
||||
** along with the rest of the Vdbe).
|
||||
*/
|
||||
static void resizeOpArray(Vdbe *p, int N){
|
||||
int runMode = p->magic==VDBE_MAGIC_RUN;
|
||||
@ -102,7 +108,7 @@ int sqlite3VdbeAddOp(Vdbe *p, int op, int p1, int p2){
|
||||
p->nOp++;
|
||||
assert( p->magic==VDBE_MAGIC_INIT );
|
||||
resizeOpArray(p, i+1);
|
||||
if( sqlite3_malloc_failed ){
|
||||
if( sqlite3MallocFailed() ){
|
||||
return 0;
|
||||
}
|
||||
pOp = &p->aOp[i];
|
||||
@ -147,7 +153,7 @@ int sqlite3VdbeMakeLabel(Vdbe *p){
|
||||
assert( p->magic==VDBE_MAGIC_INIT );
|
||||
if( i>=p->nLabelAlloc ){
|
||||
p->nLabelAlloc = p->nLabelAlloc*2 + 10;
|
||||
sqlite3ReallocOrFree((void**)&p->aLabel,
|
||||
sqliteReallocOrFree((void**)&p->aLabel,
|
||||
p->nLabelAlloc*sizeof(p->aLabel[0]));
|
||||
}
|
||||
if( p->aLabel ){
|
||||
@ -202,6 +208,7 @@ static int opcodeNoPush(u8 op){
|
||||
NOPUSH_MASK_6 + (NOPUSH_MASK_7<<16),
|
||||
NOPUSH_MASK_8 + (NOPUSH_MASK_9<<16)
|
||||
};
|
||||
assert( op<32*5 );
|
||||
return (masks[op>>5] & (1<<(op&0x1F)));
|
||||
}
|
||||
|
||||
@ -300,7 +307,7 @@ int sqlite3VdbeAddOpList(Vdbe *p, int nOp, VdbeOpList const *aOp){
|
||||
int addr;
|
||||
assert( p->magic==VDBE_MAGIC_INIT );
|
||||
resizeOpArray(p, p->nOp + nOp);
|
||||
if( sqlite3_malloc_failed ){
|
||||
if( sqlite3MallocFailed() ){
|
||||
return 0;
|
||||
}
|
||||
addr = p->nOp;
|
||||
@ -414,8 +421,10 @@ static void freeP3(int p3type, void *p3){
|
||||
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 ){
|
||||
freeP3(n, (void*)*(char**)&zP3);
|
||||
if( p==0 || p->aOp==0 || sqlite3MallocFailed() ){
|
||||
if (n != P3_KEYINFO) {
|
||||
freeP3(n, (void*)*(char**)&zP3);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if( addr<0 || addr>=p->nOp ){
|
||||
@ -432,16 +441,18 @@ void sqlite3VdbeChangeP3(Vdbe *p, int addr, const char *zP3, int n){
|
||||
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]);
|
||||
nByte = sizeof(*pKeyInfo) + (nField-1)*sizeof(pKeyInfo->aColl[0]) + nField;
|
||||
pKeyInfo = sqliteMallocRaw( nByte );
|
||||
pOp->p3 = (char*)pKeyInfo;
|
||||
if( pKeyInfo ){
|
||||
unsigned char *aSortOrder;
|
||||
memcpy(pKeyInfo, zP3, nByte);
|
||||
aSortOrder = pKeyInfo->aSortOrder;
|
||||
if( aSortOrder ){
|
||||
pKeyInfo->aSortOrder = (unsigned char*)&pKeyInfo->aColl[nField];
|
||||
memcpy(pKeyInfo->aSortOrder, aSortOrder, nField);
|
||||
}
|
||||
pOp->p3type = P3_KEYINFO;
|
||||
}else{
|
||||
pOp->p3type = P3_NOTUSED;
|
||||
@ -467,7 +478,8 @@ void sqlite3VdbeChangeP3(Vdbe *p, int addr, const char *zP3, int n){
|
||||
void sqlite3VdbeComment(Vdbe *p, const char *zFormat, ...){
|
||||
va_list ap;
|
||||
assert( p->nOp>0 );
|
||||
assert( p->aOp==0 || p->aOp[p->nOp-1].p3==0 );
|
||||
assert( p->aOp==0 || p->aOp[p->nOp-1].p3==0
|
||||
|| sqlite3MallocFailed() );
|
||||
va_start(ap, zFormat);
|
||||
sqlite3VdbeChangeP3(p, -1, sqlite3VMPrintf(zFormat, ap), P3_DYNAMIC);
|
||||
va_end(ap);
|
||||
@ -733,7 +745,7 @@ void sqlite3VdbeMakeReady(
|
||||
+ nMem*sizeof(Mem) /* aMem */
|
||||
+ nCursor*sizeof(Cursor*) /* apCsr */
|
||||
);
|
||||
if( !sqlite3_malloc_failed ){
|
||||
if( !sqlite3MallocFailed() ){
|
||||
p->aMem = &p->aStack[nStack];
|
||||
p->nMem = nMem;
|
||||
p->aVar = &p->aMem[nMem];
|
||||
@ -777,6 +789,8 @@ void sqlite3VdbeMakeReady(
|
||||
p->explain |= isExplain;
|
||||
p->magic = VDBE_MAGIC_RUN;
|
||||
p->nChange = 0;
|
||||
p->cacheCtr = 1;
|
||||
p->minWriteFileFormat = 255;
|
||||
#ifdef VDBE_PROFILE
|
||||
{
|
||||
int i;
|
||||
@ -857,9 +871,10 @@ static void Cleanup(Vdbe *p){
|
||||
void sqlite3VdbeSetNumCols(Vdbe *p, int nResColumn){
|
||||
Mem *pColName;
|
||||
int n;
|
||||
assert( 0==p->nResColumn );
|
||||
p->nResColumn = nResColumn;
|
||||
releaseMemArray(p->aColName, p->nResColumn*2);
|
||||
sqliteFree(p->aColName);
|
||||
n = nResColumn*2;
|
||||
p->nResColumn = nResColumn;
|
||||
p->aColName = pColName = (Mem*)sqliteMalloc( sizeof(Mem)*n );
|
||||
if( p->aColName==0 ) return;
|
||||
while( n-- > 0 ){
|
||||
@ -882,7 +897,7 @@ int sqlite3VdbeSetColName(Vdbe *p, int idx, const char *zName, int N){
|
||||
int rc;
|
||||
Mem *pColName;
|
||||
assert( idx<(2*p->nResColumn) );
|
||||
if( sqlite3_malloc_failed ) return SQLITE_NOMEM;
|
||||
if( sqlite3MallocFailed() ) return SQLITE_NOMEM;
|
||||
assert( p->aColName!=0 );
|
||||
pColName = &(p->aColName[idx]);
|
||||
if( N==P3_DYNAMIC || N==P3_STATIC ){
|
||||
@ -919,7 +934,6 @@ static int vdbeCommit(sqlite3 *db){
|
||||
|
||||
/* If there are any write-transactions at all, invoke the commit hook */
|
||||
if( needXcommit && db->xCommitCallback ){
|
||||
int rc;
|
||||
sqlite3SafetyOff(db);
|
||||
rc = db->xCommitCallback(db->pCommitArg);
|
||||
sqlite3SafetyOn(db);
|
||||
@ -965,7 +979,7 @@ static int vdbeCommit(sqlite3 *db){
|
||||
int needSync = 0;
|
||||
char *zMaster = 0; /* File-name for the master journal */
|
||||
char const *zMainFile = sqlite3BtreeGetFilename(db->aDb[0].pBt);
|
||||
OsFile master;
|
||||
OsFile *master = 0;
|
||||
|
||||
/* Select a master journal file name */
|
||||
do {
|
||||
@ -979,7 +993,6 @@ static int vdbeCommit(sqlite3 *db){
|
||||
}while( sqlite3OsFileExists(zMaster) );
|
||||
|
||||
/* Open the master journal. */
|
||||
memset(&master, 0, sizeof(master));
|
||||
rc = sqlite3OsOpenExclusive(zMaster, &master, 0);
|
||||
if( rc!=SQLITE_OK ){
|
||||
sqliteFree(zMaster);
|
||||
@ -1001,7 +1014,7 @@ static int vdbeCommit(sqlite3 *db){
|
||||
if( !needSync && !sqlite3BtreeSyncDisabled(pBt) ){
|
||||
needSync = 1;
|
||||
}
|
||||
rc = sqlite3OsWrite(&master, zFile, strlen(zFile)+1);
|
||||
rc = sqlite3OsWrite(master, zFile, strlen(zFile)+1);
|
||||
if( rc!=SQLITE_OK ){
|
||||
sqlite3OsClose(&master);
|
||||
sqlite3OsDelete(zMaster);
|
||||
@ -1016,9 +1029,9 @@ static int vdbeCommit(sqlite3 *db){
|
||||
** the master journal file is store in so that it gets synced too.
|
||||
*/
|
||||
zMainFile = sqlite3BtreeGetDirname(db->aDb[0].pBt);
|
||||
rc = sqlite3OsOpenDirectory(zMainFile, &master);
|
||||
rc = sqlite3OsOpenDirectory(master, zMainFile);
|
||||
if( rc!=SQLITE_OK ||
|
||||
(needSync && (rc=sqlite3OsSync(&master,0))!=SQLITE_OK) ){
|
||||
(needSync && (rc=sqlite3OsSync(master,0))!=SQLITE_OK) ){
|
||||
sqlite3OsClose(&master);
|
||||
sqlite3OsDelete(zMaster);
|
||||
sqliteFree(zMaster);
|
||||
@ -1094,10 +1107,10 @@ static int vdbeCommit(sqlite3 *db){
|
||||
** aborted so that they do not have data rolled out from underneath
|
||||
** them leading to a segfault.
|
||||
*/
|
||||
static void abortOtherActiveVdbes(Vdbe *pVdbe){
|
||||
void sqlite3AbortOtherActiveVdbes(sqlite3 *db, Vdbe *pExcept){
|
||||
Vdbe *pOther;
|
||||
for(pOther=pVdbe->db->pVdbe; pOther; pOther=pOther->pNext){
|
||||
if( pOther==pVdbe ) continue;
|
||||
for(pOther=db->pVdbe; pOther; pOther=pOther->pNext){
|
||||
if( pOther==pExcept ) continue;
|
||||
if( pOther->magic!=VDBE_MAGIC_RUN || pOther->pc<0 ) continue;
|
||||
closeAllCursors(pOther);
|
||||
pOther->aborted = 1;
|
||||
@ -1146,7 +1159,39 @@ int sqlite3VdbeHalt(Vdbe *p){
|
||||
sqlite3 *db = p->db;
|
||||
int i;
|
||||
int (*xFunc)(Btree *pBt) = 0; /* Function to call on each btree backend */
|
||||
int isSpecialError; /* Set to true if SQLITE_NOMEM or IOERR */
|
||||
|
||||
/* This function contains the logic that determines if a statement or
|
||||
** transaction will be committed or rolled back as a result of the
|
||||
** execution of this virtual machine.
|
||||
**
|
||||
** Special errors:
|
||||
**
|
||||
** If an SQLITE_NOMEM error has occured in a statement that writes to
|
||||
** the database, then either a statement or transaction must be rolled
|
||||
** back to ensure the tree-structures are in a consistent state. A
|
||||
** statement transaction is rolled back if one is open, otherwise the
|
||||
** entire transaction must be rolled back.
|
||||
**
|
||||
** If an SQLITE_IOERR error has occured in a statement that writes to
|
||||
** the database, then the entire transaction must be rolled back. The
|
||||
** I/O error may have caused garbage to be written to the journal
|
||||
** file. Were the transaction to continue and eventually be rolled
|
||||
** back that garbage might end up in the database file.
|
||||
**
|
||||
** In both of the above cases, the Vdbe.errorAction variable is
|
||||
** ignored. If the sqlite3.autoCommit flag is false and a transaction
|
||||
** is rolled back, it will be set to true.
|
||||
**
|
||||
** Other errors:
|
||||
**
|
||||
** No error:
|
||||
**
|
||||
*/
|
||||
|
||||
if( sqlite3MallocFailed() ){
|
||||
p->rc = SQLITE_NOMEM;
|
||||
}
|
||||
if( p->magic!=VDBE_MAGIC_RUN ){
|
||||
/* Already halted. Nothing to do. */
|
||||
assert( p->magic==VDBE_MAGIC_HALT );
|
||||
@ -1154,65 +1199,131 @@ int sqlite3VdbeHalt(Vdbe *p){
|
||||
}
|
||||
closeAllCursors(p);
|
||||
checkActiveVdbeCnt(db);
|
||||
if( p->pc<0 ){
|
||||
/* No commit or rollback needed if the program never started */
|
||||
}else if( db->autoCommit && db->activeVdbeCnt==1 ){
|
||||
if( p->rc==SQLITE_OK || p->errorAction==OE_Fail ){
|
||||
/* The auto-commit flag is true, there are no other active queries
|
||||
** using this handle and the vdbe program was successful or hit an
|
||||
** 'OR FAIL' constraint. This means a commit is required.
|
||||
|
||||
/* No commit or rollback needed if the program never started */
|
||||
if( p->pc>=0 ){
|
||||
|
||||
/* Check for one of the special errors - SQLITE_NOMEM or SQLITE_IOERR */
|
||||
isSpecialError = ((p->rc==SQLITE_NOMEM || p->rc==SQLITE_IOERR)?1:0);
|
||||
if( isSpecialError ){
|
||||
/* This loop does static analysis of the query to see which of the
|
||||
** following three categories it falls into:
|
||||
**
|
||||
** Read-only
|
||||
** Query with statement journal
|
||||
** Query without statement journal
|
||||
**
|
||||
** We could do something more elegant than this static analysis (i.e.
|
||||
** store the type of query as part of the compliation phase), but
|
||||
** handling malloc() or IO failure is a fairly obscure edge case so
|
||||
** this is probably easier. Todo: Might be an opportunity to reduce
|
||||
** code size a very small amount though...
|
||||
*/
|
||||
int rc = vdbeCommit(db);
|
||||
if( rc==SQLITE_BUSY ){
|
||||
return SQLITE_BUSY;
|
||||
}else if( rc!=SQLITE_OK ){
|
||||
p->rc = rc;
|
||||
xFunc = sqlite3BtreeRollback;
|
||||
int isReadOnly = 1;
|
||||
int isStatement = 0;
|
||||
assert(p->aOp || p->nOp==0);
|
||||
for(i=0; i<p->nOp; i++){
|
||||
switch( p->aOp[i].opcode ){
|
||||
case OP_Transaction:
|
||||
isReadOnly = 0;
|
||||
break;
|
||||
case OP_Statement:
|
||||
isStatement = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* If the query was read-only, we need do no rollback at all. Otherwise,
|
||||
** proceed with the special handling.
|
||||
*/
|
||||
if( !isReadOnly ){
|
||||
if( p->rc==SQLITE_NOMEM && isStatement ){
|
||||
xFunc = sqlite3BtreeRollbackStmt;
|
||||
}else{
|
||||
/* We are forced to roll back the active transaction. Before doing
|
||||
** so, abort any other statements this handle currently has active.
|
||||
*/
|
||||
sqlite3AbortOtherActiveVdbes(db, p);
|
||||
sqlite3RollbackAll(db);
|
||||
db->autoCommit = 1;
|
||||
}
|
||||
}
|
||||
}else{
|
||||
xFunc = sqlite3BtreeRollback;
|
||||
}
|
||||
}else{
|
||||
if( p->rc==SQLITE_OK || p->errorAction==OE_Fail ){
|
||||
xFunc = sqlite3BtreeCommitStmt;
|
||||
}else if( p->errorAction==OE_Abort ){
|
||||
xFunc = sqlite3BtreeRollbackStmt;
|
||||
}else{
|
||||
xFunc = sqlite3BtreeRollback;
|
||||
db->autoCommit = 1;
|
||||
abortOtherActiveVdbes(p);
|
||||
|
||||
/* If the auto-commit flag is set and this is the only active vdbe, then
|
||||
** we do either a commit or rollback of the current transaction.
|
||||
**
|
||||
** Note: This block also runs if one of the special errors handled
|
||||
** above has occured.
|
||||
*/
|
||||
if( db->autoCommit && db->activeVdbeCnt==1 ){
|
||||
if( p->rc==SQLITE_OK || (p->errorAction==OE_Fail && !isSpecialError) ){
|
||||
/* The auto-commit flag is true, and the vdbe program was
|
||||
** successful or hit an 'OR FAIL' constraint. This means a commit
|
||||
** is required.
|
||||
*/
|
||||
int rc = vdbeCommit(db);
|
||||
if( rc==SQLITE_BUSY ){
|
||||
return SQLITE_BUSY;
|
||||
}else if( rc!=SQLITE_OK ){
|
||||
p->rc = rc;
|
||||
sqlite3RollbackAll(db);
|
||||
}else{
|
||||
sqlite3CommitInternalChanges(db);
|
||||
}
|
||||
}else{
|
||||
sqlite3RollbackAll(db);
|
||||
}
|
||||
}else if( !xFunc ){
|
||||
if( p->rc==SQLITE_OK || p->errorAction==OE_Fail ){
|
||||
xFunc = sqlite3BtreeCommitStmt;
|
||||
}else if( p->errorAction==OE_Abort ){
|
||||
xFunc = sqlite3BtreeRollbackStmt;
|
||||
}else{
|
||||
sqlite3AbortOtherActiveVdbes(db, p);
|
||||
sqlite3RollbackAll(db);
|
||||
db->autoCommit = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* If xFunc is not NULL, then it is one of sqlite3BtreeRollback,
|
||||
** sqlite3BtreeRollbackStmt or sqlite3BtreeCommitStmt. Call it once on
|
||||
** each backend. If an error occurs and the return code is still
|
||||
** SQLITE_OK, set the return code to the new error value.
|
||||
*/
|
||||
for(i=0; xFunc && i<db->nDb; i++){
|
||||
int rc;
|
||||
Btree *pBt = db->aDb[i].pBt;
|
||||
if( pBt ){
|
||||
rc = xFunc(pBt);
|
||||
if( p->rc==SQLITE_OK ) p->rc = rc;
|
||||
|
||||
/* If xFunc is not NULL, then it is one of sqlite3BtreeRollbackStmt or
|
||||
** sqlite3BtreeCommitStmt. Call it once on each backend. If an error occurs
|
||||
** and the return code is still SQLITE_OK, set the return code to the new
|
||||
** error value.
|
||||
*/
|
||||
assert(!xFunc ||
|
||||
xFunc==sqlite3BtreeCommitStmt ||
|
||||
xFunc==sqlite3BtreeRollbackStmt
|
||||
);
|
||||
for(i=0; xFunc && i<db->nDb; i++){
|
||||
int rc;
|
||||
Btree *pBt = db->aDb[i].pBt;
|
||||
if( pBt ){
|
||||
rc = xFunc(pBt);
|
||||
if( rc && (p->rc==SQLITE_OK || p->rc==SQLITE_CONSTRAINT) ){
|
||||
p->rc = rc;
|
||||
sqlite3SetString(&p->zErrMsg, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* If this was an INSERT, UPDATE or DELETE, set the change counter. */
|
||||
if( p->changeCntOn && p->pc>=0 ){
|
||||
if( !xFunc || xFunc==sqlite3BtreeCommitStmt ){
|
||||
sqlite3VdbeSetChanges(db, p->nChange);
|
||||
}else{
|
||||
sqlite3VdbeSetChanges(db, 0);
|
||||
|
||||
/* If this was an INSERT, UPDATE or DELETE and the statement was committed,
|
||||
** set the change counter.
|
||||
*/
|
||||
if( p->changeCntOn && p->pc>=0 ){
|
||||
if( !xFunc || xFunc==sqlite3BtreeCommitStmt ){
|
||||
sqlite3VdbeSetChanges(db, p->nChange);
|
||||
}else{
|
||||
sqlite3VdbeSetChanges(db, 0);
|
||||
}
|
||||
p->nChange = 0;
|
||||
}
|
||||
|
||||
/* Rollback or commit any schema changes that occurred. */
|
||||
if( p->rc!=SQLITE_OK && db->flags&SQLITE_InternChanges ){
|
||||
sqlite3ResetInternalSchema(db, 0);
|
||||
db->flags = (db->flags | SQLITE_InternChanges);
|
||||
}
|
||||
p->nChange = 0;
|
||||
}
|
||||
|
||||
/* Rollback or commit any schema changes that occurred. */
|
||||
if( p->rc!=SQLITE_OK ){
|
||||
sqlite3RollbackInternalChanges(db);
|
||||
}else if( db->flags & SQLITE_InternChanges ){
|
||||
sqlite3CommitInternalChanges(db);
|
||||
}
|
||||
|
||||
/* We have successfully halted and closed the VM. Record this fact. */
|
||||
@ -1255,8 +1366,9 @@ int sqlite3VdbeReset(Vdbe *p){
|
||||
*/
|
||||
if( p->pc>=0 ){
|
||||
if( p->zErrMsg ){
|
||||
sqlite3Error(p->db, p->rc, "%s", p->zErrMsg);
|
||||
sqliteFree(p->zErrMsg);
|
||||
sqlite3* db = p->db;
|
||||
sqlite3ValueSetStr(db->pErr, -1, p->zErrMsg, SQLITE_UTF8, sqlite3FreeX);
|
||||
db->errCode = p->rc;
|
||||
p->zErrMsg = 0;
|
||||
}else if( p->rc ){
|
||||
sqlite3Error(p->db, p->rc, 0);
|
||||
@ -1277,7 +1389,7 @@ int sqlite3VdbeReset(Vdbe *p){
|
||||
|
||||
/* Save profiling information from this VDBE run.
|
||||
*/
|
||||
assert( p->pTos<&p->aStack[p->pc<0?0:p->pc] || sqlite3_malloc_failed==1 );
|
||||
assert( p->pTos<&p->aStack[p->pc<0?0:p->pc] || !p->aStack );
|
||||
#ifdef VDBE_PROFILE
|
||||
{
|
||||
FILE *out = fopen("vdbe_profile.out", "a");
|
||||
@ -1401,7 +1513,7 @@ int sqlite3VdbeCursorMoveto(Cursor *p){
|
||||
}
|
||||
sqlite3_search_count++;
|
||||
p->deferredMoveto = 0;
|
||||
p->cacheValid = 0;
|
||||
p->cacheStatus = CACHE_STALE;
|
||||
}
|
||||
return SQLITE_OK;
|
||||
}
|
||||
@ -1438,16 +1550,20 @@ int sqlite3VdbeCursorMoveto(Cursor *p){
|
||||
** 5 6 signed integer
|
||||
** 6 8 signed integer
|
||||
** 7 8 IEEE float
|
||||
** 8-11 reserved for expansion
|
||||
** 8 0 Integer constant 0
|
||||
** 9 0 Integer constant 1
|
||||
** 10,11 reserved for expansion
|
||||
** N>=12 and even (N-12)/2 BLOB
|
||||
** N>=13 and odd (N-13)/2 text
|
||||
**
|
||||
** The 8 and 9 types were added in 3.3.0, file format 4. Prior versions
|
||||
** of SQLite will not understand those serial types.
|
||||
*/
|
||||
|
||||
/*
|
||||
** Return the serial-type for the value stored in pMem.
|
||||
*/
|
||||
u32 sqlite3VdbeSerialType(Mem *pMem){
|
||||
u32 sqlite3VdbeSerialType(Mem *pMem, int file_format){
|
||||
int flags = pMem->flags;
|
||||
|
||||
if( flags&MEM_Null ){
|
||||
@ -1457,7 +1573,11 @@ u32 sqlite3VdbeSerialType(Mem *pMem){
|
||||
/* Figure out whether to use 1, 2, 4, 6 or 8 bytes. */
|
||||
# define MAX_6BYTE ((((i64)0x00001000)<<32)-1)
|
||||
i64 i = pMem->i;
|
||||
u64 u = i<0 ? -i : i;
|
||||
u64 u;
|
||||
if( file_format>=4 && (i&1)==i ){
|
||||
return 8+i;
|
||||
}
|
||||
u = i<0 ? -i : i;
|
||||
if( u<=127 ) return 1;
|
||||
if( u<=32767 ) return 2;
|
||||
if( u<=8388607 ) return 3;
|
||||
@ -1496,17 +1616,12 @@ int sqlite3VdbeSerialTypeLen(u32 serial_type){
|
||||
** buf. It is assumed that the caller has allocated sufficient space.
|
||||
** Return the number of bytes written.
|
||||
*/
|
||||
int sqlite3VdbeSerialPut(unsigned char *buf, Mem *pMem){
|
||||
u32 serial_type = sqlite3VdbeSerialType(pMem);
|
||||
int sqlite3VdbeSerialPut(unsigned char *buf, Mem *pMem, int file_format){
|
||||
u32 serial_type = sqlite3VdbeSerialType(pMem, file_format);
|
||||
int len;
|
||||
|
||||
/* NULL */
|
||||
if( serial_type==0 ){
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Integer and Real */
|
||||
if( serial_type<=7 ){
|
||||
if( serial_type<=7 && serial_type>0 ){
|
||||
u64 v;
|
||||
int i;
|
||||
if( serial_type==7 ){
|
||||
@ -1521,12 +1636,16 @@ int sqlite3VdbeSerialPut(unsigned char *buf, Mem *pMem){
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
/* String or blob */
|
||||
assert( serial_type>=12 );
|
||||
len = sqlite3VdbeSerialTypeLen(serial_type);
|
||||
memcpy(buf, pMem->z, len);
|
||||
return len;
|
||||
if( serial_type>=12 ){
|
||||
len = sqlite3VdbeSerialTypeLen(serial_type);
|
||||
memcpy(buf, pMem->z, len);
|
||||
return len;
|
||||
}
|
||||
|
||||
/* NULL or constants 0 or 1 */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1539,8 +1658,6 @@ int sqlite3VdbeSerialGet(
|
||||
Mem *pMem /* Memory cell to write value into */
|
||||
){
|
||||
switch( serial_type ){
|
||||
case 8: /* Reserved for future use */
|
||||
case 9: /* Reserved for future use */
|
||||
case 10: /* Reserved for future use */
|
||||
case 11: /* Reserved for future use */
|
||||
case 0: { /* NULL */
|
||||
@ -1579,7 +1696,7 @@ int sqlite3VdbeSerialGet(
|
||||
case 7: { /* IEEE floating point */
|
||||
u64 x;
|
||||
u32 y;
|
||||
#ifndef NDEBUG
|
||||
#if !defined(NDEBUG) && !defined(SQLITE_OMIT_FLOATING_POINT)
|
||||
/* Verify that integers and floating point values use the same
|
||||
** byte order. The byte order differs on some (broken) architectures.
|
||||
*/
|
||||
@ -1599,6 +1716,12 @@ int sqlite3VdbeSerialGet(
|
||||
}
|
||||
return 8;
|
||||
}
|
||||
case 8: /* Integer 0 */
|
||||
case 9: { /* Integer 1 */
|
||||
pMem->i = serial_type-8;
|
||||
pMem->flags = MEM_Int;
|
||||
return 0;
|
||||
}
|
||||
default: {
|
||||
int len = (serial_type-12)/2;
|
||||
pMem->z = (char *)buf;
|
||||
@ -1615,6 +1738,23 @@ int sqlite3VdbeSerialGet(
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** The header of a record consists of a sequence variable-length integers.
|
||||
** These integers are almost always small and are encoded as a single byte.
|
||||
** The following macro takes advantage this fact to provide a fast decode
|
||||
** of the integers in a record header. It is faster for the common case
|
||||
** where the integer is a single byte. It is a little slower when the
|
||||
** integer is two or more bytes. But overall it is faster.
|
||||
**
|
||||
** The following expressions are equivalent:
|
||||
**
|
||||
** x = sqlite3GetVarint32( A, &B );
|
||||
**
|
||||
** x = GetVarint( A, B );
|
||||
**
|
||||
*/
|
||||
#define GetVarint(A,B) ((B = *(A))<=0x7f ? 1 : sqlite3GetVarint32(A, &B))
|
||||
|
||||
/*
|
||||
** This function compares the two table rows or index records specified by
|
||||
** {nKey1, pKey1} and {nKey2, pKey2}, returning a negative, zero
|
||||
@ -1642,9 +1782,9 @@ int sqlite3VdbeRecordCompare(
|
||||
mem1.enc = pKeyInfo->enc;
|
||||
mem2.enc = pKeyInfo->enc;
|
||||
|
||||
idx1 = sqlite3GetVarint32(pKey1, &szHdr1);
|
||||
idx1 = GetVarint(aKey1, szHdr1);
|
||||
d1 = szHdr1;
|
||||
idx2 = sqlite3GetVarint32(pKey2, &szHdr2);
|
||||
idx2 = GetVarint(aKey2, szHdr2);
|
||||
d2 = szHdr2;
|
||||
nField = pKeyInfo->nField;
|
||||
while( idx1<szHdr1 && idx2<szHdr2 ){
|
||||
@ -1652,9 +1792,9 @@ int sqlite3VdbeRecordCompare(
|
||||
u32 serial_type2;
|
||||
|
||||
/* Read the serial types for the next element in each key. */
|
||||
idx1 += sqlite3GetVarint32(&aKey1[idx1], &serial_type1);
|
||||
idx1 += GetVarint( aKey1+idx1, serial_type1 );
|
||||
if( d1>=nKey1 && sqlite3VdbeSerialTypeLen(serial_type1)>0 ) break;
|
||||
idx2 += sqlite3GetVarint32(&aKey2[idx2], &serial_type2);
|
||||
idx2 += GetVarint( aKey2+idx2, serial_type2 );
|
||||
if( d2>=nKey2 && sqlite3VdbeSerialTypeLen(serial_type2)>0 ) break;
|
||||
|
||||
/* Assert that there is enough space left in each key for the blob of
|
||||
@ -1686,9 +1826,8 @@ int sqlite3VdbeRecordCompare(
|
||||
}else if( d2<nKey2 ){
|
||||
rc = -1;
|
||||
}
|
||||
}
|
||||
|
||||
if( pKeyInfo->aSortOrder && i<pKeyInfo->nField && pKeyInfo->aSortOrder[i] ){
|
||||
}else if( pKeyInfo->aSortOrder && i<pKeyInfo->nField
|
||||
&& pKeyInfo->aSortOrder[i] ){
|
||||
rc = -rc;
|
||||
}
|
||||
|
||||
@ -1732,10 +1871,10 @@ int sqlite3VdbeIdxRowid(BtCursor *pCur, i64 *rowid){
|
||||
if( rc ){
|
||||
return rc;
|
||||
}
|
||||
sqlite3GetVarint32(m.z, &szHdr);
|
||||
sqlite3GetVarint32(&m.z[szHdr-1], &typeRowid);
|
||||
sqlite3GetVarint32((u8*)m.z, &szHdr);
|
||||
sqlite3GetVarint32((u8*)&m.z[szHdr-1], &typeRowid);
|
||||
lenRowid = sqlite3VdbeSerialTypeLen(typeRowid);
|
||||
sqlite3VdbeSerialGet(&m.z[m.n-lenRowid], typeRowid, &v);
|
||||
sqlite3VdbeSerialGet((u8*)&m.z[m.n-lenRowid], typeRowid, &v);
|
||||
*rowid = v.i;
|
||||
sqlite3VdbeMemRelease(&m);
|
||||
return SQLITE_OK;
|
||||
@ -1771,7 +1910,7 @@ int sqlite3VdbeIdxKeyCompare(
|
||||
if( rc ){
|
||||
return rc;
|
||||
}
|
||||
lenRowid = sqlite3VdbeIdxRowidLen(m.n, m.z);
|
||||
lenRowid = sqlite3VdbeIdxRowidLen(m.n, (u8*)m.z);
|
||||
*res = sqlite3VdbeRecordCompare(pC->pKeyInfo, m.n-lenRowid, m.z, nKey, pKey);
|
||||
sqlite3VdbeMemRelease(&m);
|
||||
return SQLITE_OK;
|
||||
|
||||
@ -41,11 +41,21 @@ int sqlite3VdbeChangeEncoding(Mem *pMem, int desiredEnc){
|
||||
#ifdef SQLITE_OMIT_UTF16
|
||||
return SQLITE_ERROR;
|
||||
#else
|
||||
|
||||
/* MemTranslate() may return SQLITE_OK or SQLITE_NOMEM. If NOMEM is returned,
|
||||
** then the encoding of the value may not have changed.
|
||||
*/
|
||||
rc = sqlite3VdbeMemTranslate(pMem, desiredEnc);
|
||||
assert(rc==SQLITE_OK || rc==SQLITE_NOMEM);
|
||||
assert(rc==SQLITE_OK || pMem->enc!=desiredEnc);
|
||||
assert(rc==SQLITE_NOMEM || pMem->enc==desiredEnc);
|
||||
|
||||
if( rc==SQLITE_NOMEM ){
|
||||
/*
|
||||
sqlite3VdbeMemRelease(pMem);
|
||||
pMem->flags = MEM_Null;
|
||||
pMem->z = 0;
|
||||
*/
|
||||
}
|
||||
return rc;
|
||||
#endif
|
||||
@ -73,7 +83,7 @@ int sqlite3VdbeMemDynamicify(Mem *pMem){
|
||||
memcpy(z, pMem->z, n );
|
||||
z[n] = 0;
|
||||
z[n+1] = 0;
|
||||
pMem->z = z;
|
||||
pMem->z = (char*)z;
|
||||
pMem->flags &= ~(MEM_Ephem|MEM_Static|MEM_Short);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
@ -93,7 +103,7 @@ int sqlite3VdbeMemMakeWriteable(Mem *pMem){
|
||||
assert( (pMem->flags & MEM_Dyn)==0 );
|
||||
assert( pMem->flags & (MEM_Str|MEM_Blob) );
|
||||
if( (n = pMem->n)+2<sizeof(pMem->zShort) ){
|
||||
z = pMem->zShort;
|
||||
z = (u8*)pMem->zShort;
|
||||
pMem->flags |= MEM_Short|MEM_Term;
|
||||
}else{
|
||||
z = sqliteMallocRaw( n+2 );
|
||||
@ -106,7 +116,7 @@ int sqlite3VdbeMemMakeWriteable(Mem *pMem){
|
||||
memcpy(z, pMem->z, n );
|
||||
z[n] = 0;
|
||||
z[n+1] = 0;
|
||||
pMem->z = z;
|
||||
pMem->z = (char*)z;
|
||||
pMem->flags &= ~(MEM_Ephem|MEM_Static);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
@ -162,7 +172,7 @@ int sqlite3VdbeMemNulTerminate(Mem *pMem){
|
||||
int sqlite3VdbeMemStringify(Mem *pMem, int enc){
|
||||
int rc = SQLITE_OK;
|
||||
int fg = pMem->flags;
|
||||
u8 *z = pMem->zShort;
|
||||
char *z = pMem->zShort;
|
||||
|
||||
assert( !(fg&(MEM_Str|MEM_Blob)) );
|
||||
assert( fg&(MEM_Int|MEM_Real) );
|
||||
@ -173,11 +183,11 @@ 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);
|
||||
}else{
|
||||
assert( fg & MEM_Int );
|
||||
if( fg & MEM_Int ){
|
||||
sqlite3_snprintf(NBFS, z, "%lld", pMem->i);
|
||||
}else{
|
||||
assert( fg & MEM_Real );
|
||||
sqlite3_snprintf(NBFS, z, "%!.15g", pMem->r);
|
||||
}
|
||||
pMem->n = strlen(z);
|
||||
pMem->z = z;
|
||||
@ -191,8 +201,12 @@ int sqlite3VdbeMemStringify(Mem *pMem, int enc){
|
||||
** 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.
|
||||
**
|
||||
** Return SQLITE_ERROR if the finalizer reports an error. SQLITE_OK
|
||||
** otherwise.
|
||||
*/
|
||||
void sqlite3VdbeMemFinalize(Mem *pMem, FuncDef *pFunc){
|
||||
int sqlite3VdbeMemFinalize(Mem *pMem, FuncDef *pFunc){
|
||||
int rc = SQLITE_OK;
|
||||
if( pFunc && pFunc->xFinalize ){
|
||||
sqlite3_context ctx;
|
||||
assert( (pMem->flags & MEM_Null)!=0 || pFunc==*(FuncDef**)&pMem->i );
|
||||
@ -200,6 +214,7 @@ void sqlite3VdbeMemFinalize(Mem *pMem, FuncDef *pFunc){
|
||||
ctx.s.z = pMem->zShort;
|
||||
ctx.pMem = pMem;
|
||||
ctx.pFunc = pFunc;
|
||||
ctx.isError = 0;
|
||||
pFunc->xFinalize(&ctx);
|
||||
if( pMem->z && pMem->z!=pMem->zShort ){
|
||||
sqliteFree( pMem->z );
|
||||
@ -208,7 +223,11 @@ void sqlite3VdbeMemFinalize(Mem *pMem, FuncDef *pFunc){
|
||||
if( pMem->flags & MEM_Short ){
|
||||
pMem->z = pMem->zShort;
|
||||
}
|
||||
if( ctx.isError ){
|
||||
rc = SQLITE_ERROR;
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -254,7 +273,7 @@ i64 sqlite3VdbeIntValue(Mem *pMem){
|
||||
i64 value;
|
||||
if( sqlite3VdbeChangeEncoding(pMem, SQLITE_UTF8)
|
||||
|| sqlite3VdbeMemNulTerminate(pMem) ){
|
||||
return SQLITE_NOMEM;
|
||||
return 0;
|
||||
}
|
||||
assert( pMem->z );
|
||||
sqlite3atoi64(pMem->z, &value);
|
||||
@ -264,16 +283,6 @@ i64 sqlite3VdbeIntValue(Mem *pMem){
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Convert pMem to type integer. Invalidate any prior representations.
|
||||
*/
|
||||
int sqlite3VdbeMemIntegerify(Mem *pMem){
|
||||
pMem->i = sqlite3VdbeIntValue(pMem);
|
||||
sqlite3VdbeMemRelease(pMem);
|
||||
pMem->flags = MEM_Int;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the best representation of pMem that we can get into a
|
||||
** double. If pMem is already a double or an integer, return its
|
||||
@ -289,7 +298,7 @@ double sqlite3VdbeRealValue(Mem *pMem){
|
||||
double val = 0.0;
|
||||
if( sqlite3VdbeChangeEncoding(pMem, SQLITE_UTF8)
|
||||
|| sqlite3VdbeMemNulTerminate(pMem) ){
|
||||
return SQLITE_NOMEM;
|
||||
return 0.0;
|
||||
}
|
||||
assert( pMem->z );
|
||||
sqlite3AtoF(pMem->z, &val);
|
||||
@ -300,8 +309,30 @@ double sqlite3VdbeRealValue(Mem *pMem){
|
||||
}
|
||||
|
||||
/*
|
||||
** Convert pMem so that it is of type MEM_Real. Invalidate any
|
||||
** prior representations.
|
||||
** The MEM structure is already a MEM_Real. Try to also make it a
|
||||
** MEM_Int if we can.
|
||||
*/
|
||||
void sqlite3VdbeIntegerAffinity(Mem *pMem){
|
||||
assert( pMem->flags & MEM_Real );
|
||||
pMem->i = pMem->r;
|
||||
if( ((double)pMem->i)==pMem->r ){
|
||||
pMem->flags |= MEM_Int;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Convert pMem to type integer. Invalidate any prior representations.
|
||||
*/
|
||||
int sqlite3VdbeMemIntegerify(Mem *pMem){
|
||||
pMem->i = sqlite3VdbeIntValue(pMem);
|
||||
sqlite3VdbeMemRelease(pMem);
|
||||
pMem->flags = MEM_Int;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Convert pMem so that it is of type MEM_Real.
|
||||
** Invalidate any prior representations.
|
||||
*/
|
||||
int sqlite3VdbeMemRealify(Mem *pMem){
|
||||
pMem->r = sqlite3VdbeRealValue(pMem);
|
||||
@ -310,6 +341,16 @@ int sqlite3VdbeMemRealify(Mem *pMem){
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Convert pMem so that it has types MEM_Real or MEM_Int or both.
|
||||
** Invalidate any prior representations.
|
||||
*/
|
||||
int sqlite3VdbeMemNumerify(Mem *pMem){
|
||||
sqlite3VdbeMemRealify(pMem);
|
||||
sqlite3VdbeIntegerAffinity(pMem);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Delete any previous value and set the value stored in *pMem to NULL.
|
||||
*/
|
||||
@ -547,9 +588,9 @@ int sqlite3MemCompare(const Mem *pMem1, const Mem *pMem2, const CollSeq *pColl){
|
||||
assert( pMem1->enc==SQLITE_UTF8 ||
|
||||
pMem1->enc==SQLITE_UTF16LE || pMem1->enc==SQLITE_UTF16BE );
|
||||
|
||||
/* This assert may fail if the collation sequence is deleted after this
|
||||
** vdbe program is compiled. The documentation defines this as an
|
||||
** undefined condition. A crash is usual result.
|
||||
/* The collation sequence must be defined at this point, even if
|
||||
** the user deletes the collation sequence after the vdbe program is
|
||||
** compiled (this was not always the case).
|
||||
*/
|
||||
assert( !pColl || pColl->xCmp );
|
||||
|
||||
@ -719,12 +760,15 @@ const void *sqlite3ValueText(sqlite3_value* pVal, u8 enc){
|
||||
if( pVal->flags&MEM_Null ){
|
||||
return 0;
|
||||
}
|
||||
assert( (MEM_Blob>>3) == MEM_Str );
|
||||
pVal->flags |= (pVal->flags & MEM_Blob)>>3;
|
||||
if( pVal->flags&MEM_Str ){
|
||||
sqlite3VdbeChangeEncoding(pVal, enc);
|
||||
}else if( !(pVal->flags&MEM_Blob) ){
|
||||
sqlite3VdbeMemStringify(pVal, enc);
|
||||
}
|
||||
return (const void *)(pVal->z);
|
||||
assert(pVal->enc==enc || sqlite3MallocFailed() );
|
||||
return (const void *)(pVal->enc==enc ? (pVal->z) : 0);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -766,7 +810,7 @@ int sqlite3ValueFromExpr(
|
||||
op = pExpr->op;
|
||||
|
||||
if( op==TK_STRING || op==TK_FLOAT || op==TK_INTEGER ){
|
||||
zVal = sqliteStrNDup(pExpr->token.z, pExpr->token.n);
|
||||
zVal = sqliteStrNDup((char*)pExpr->token.z, pExpr->token.n);
|
||||
pVal = sqlite3ValueNew();
|
||||
if( !zVal || !pVal ) goto no_mem;
|
||||
sqlite3Dequote(zVal);
|
||||
@ -786,7 +830,7 @@ int sqlite3ValueFromExpr(
|
||||
else if( op==TK_BLOB ){
|
||||
int nVal;
|
||||
pVal = sqlite3ValueNew();
|
||||
zVal = sqliteStrNDup(pExpr->token.z+1, pExpr->token.n-1);
|
||||
zVal = sqliteStrNDup((char*)pExpr->token.z+1, pExpr->token.n-1);
|
||||
if( !zVal || !pVal ) goto no_mem;
|
||||
sqlite3Dequote(zVal);
|
||||
nVal = strlen(zVal)/2;
|
||||
|
||||
@ -16,7 +16,7 @@
|
||||
** so is applicable. Because this module is responsible for selecting
|
||||
** indices, you might also think of this module as the "query optimizer".
|
||||
**
|
||||
** $Id: where.c,v 1.179 2005/09/20 17:42:23 drh Exp $
|
||||
** $Id: where.c,v 1.203 2006/01/24 12:09:20 danielk1977 Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
|
||||
@ -83,7 +83,7 @@ struct WhereTerm {
|
||||
i16 iParent; /* Disable pWC->a[iParent] when this term disabled */
|
||||
i16 leftCursor; /* Cursor number of X in "X <op> <expr>" */
|
||||
i16 leftColumn; /* Column number of X in "X <op> <expr>" */
|
||||
u16 operator; /* A WO_xx value describing <op> */
|
||||
u16 eOperator; /* A WO_xx value describing <op> */
|
||||
u8 flags; /* Bit flags. See below */
|
||||
u8 nChild; /* Number of children that must disable us */
|
||||
WhereClause *pWC; /* The clause this term is part of */
|
||||
@ -418,13 +418,13 @@ static WhereTerm *findTerm(
|
||||
if( pTerm->leftCursor==iCur
|
||||
&& (pTerm->prereqRight & notReady)==0
|
||||
&& pTerm->leftColumn==iColumn
|
||||
&& (pTerm->operator & op)!=0
|
||||
&& (pTerm->eOperator & op)!=0
|
||||
){
|
||||
if( iCur>=0 && pIdx ){
|
||||
Expr *pX = pTerm->pExpr;
|
||||
CollSeq *pColl;
|
||||
char idxaff;
|
||||
int k;
|
||||
int j;
|
||||
Parse *pParse = pWC->pParse;
|
||||
|
||||
idxaff = pIdx->pTable->aCol[iColumn].affinity;
|
||||
@ -438,9 +438,9 @@ static WhereTerm *findTerm(
|
||||
pColl = pParse->db->pDfltColl;
|
||||
}
|
||||
}
|
||||
for(k=0; k<pIdx->nColumn && pIdx->aiColumn[k]!=iColumn; k++){}
|
||||
assert( k<pIdx->nColumn );
|
||||
if( pColl!=pIdx->keyInfo.aColl[k] ) continue;
|
||||
for(j=0; j<pIdx->nColumn && pIdx->aiColumn[j]!=iColumn; j++){}
|
||||
assert( j<pIdx->nColumn );
|
||||
if( sqlite3StrICmp(pColl->zName, pIdx->azColl[j]) ) continue;
|
||||
}
|
||||
return pTerm;
|
||||
}
|
||||
@ -511,7 +511,7 @@ static int isLikeOrGlob(
|
||||
return 0;
|
||||
}
|
||||
sqlite3DequoteExpr(pRight);
|
||||
z = pRight->token.z;
|
||||
z = (char *)pRight->token.z;
|
||||
for(cnt=0; (c=z[cnt])!=0 && c!=wc[0] && c!=wc[1] && c!=wc[2]; cnt++){}
|
||||
if( cnt==0 || 255==(u8)z[cnt] ){
|
||||
return 0;
|
||||
@ -522,6 +522,16 @@ static int isLikeOrGlob(
|
||||
}
|
||||
#endif /* SQLITE_OMIT_LIKE_OPTIMIZATION */
|
||||
|
||||
/*
|
||||
** If the pBase expression originated in the ON or USING clause of
|
||||
** a join, then transfer the appropriate markings over to derived.
|
||||
*/
|
||||
static void transferJoinMarkings(Expr *pDerived, Expr *pBase){
|
||||
pDerived->flags |= pBase->flags & EP_FromJoin;
|
||||
pDerived->iRightJoinTable = pBase->iRightJoinTable;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** The input to this routine is an WhereTerm structure with only the
|
||||
** "pExpr" field filled in. The job of this routine is to analyze the
|
||||
@ -547,7 +557,7 @@ static void exprAnalyze(
|
||||
int nPattern;
|
||||
int isComplete;
|
||||
|
||||
if( sqlite3_malloc_failed ) return;
|
||||
if( sqlite3MallocFailed() ) return;
|
||||
prereqLeft = exprTableUsage(pMaskSet, pExpr->pLeft);
|
||||
if( pExpr->op==TK_IN ){
|
||||
assert( pExpr->pRight==0 );
|
||||
@ -563,14 +573,14 @@ static void exprAnalyze(
|
||||
pTerm->prereqAll = prereqAll;
|
||||
pTerm->leftCursor = -1;
|
||||
pTerm->iParent = -1;
|
||||
pTerm->operator = 0;
|
||||
pTerm->eOperator = 0;
|
||||
if( allowedOp(pExpr->op) && (pTerm->prereqRight & prereqLeft)==0 ){
|
||||
Expr *pLeft = pExpr->pLeft;
|
||||
Expr *pRight = pExpr->pRight;
|
||||
if( pLeft->op==TK_COLUMN ){
|
||||
pTerm->leftCursor = pLeft->iTable;
|
||||
pTerm->leftColumn = pLeft->iColumn;
|
||||
pTerm->operator = operatorMask(pExpr->op);
|
||||
pTerm->eOperator = operatorMask(pExpr->op);
|
||||
}
|
||||
if( pRight && pRight->op==TK_COLUMN ){
|
||||
WhereTerm *pNew;
|
||||
@ -595,7 +605,7 @@ static void exprAnalyze(
|
||||
pNew->leftColumn = pLeft->iColumn;
|
||||
pNew->prereqRight = prereqLeft;
|
||||
pNew->prereqAll = prereqAll;
|
||||
pNew->operator = operatorMask(pDup->op);
|
||||
pNew->eOperator = operatorMask(pDup->op);
|
||||
}
|
||||
}
|
||||
|
||||
@ -623,7 +633,7 @@ static void exprAnalyze(
|
||||
}
|
||||
#endif /* SQLITE_OMIT_BETWEEN_OPTIMIZATION */
|
||||
|
||||
#ifndef SQLITE_OMIT_OR_OPTIMIZATION
|
||||
#if !defined(SQLITE_OMIT_OR_OPTIMIZATION) && !defined(SQLITE_OMIT_SUBQUERY)
|
||||
/* Attempt to convert OR-connected terms into an IN operator so that
|
||||
** they can make use of indices. Example:
|
||||
**
|
||||
@ -632,6 +642,9 @@ static void exprAnalyze(
|
||||
** is converted into
|
||||
**
|
||||
** x IN (expr1,expr2,expr3)
|
||||
**
|
||||
** This optimization must be omitted if OMIT_SUBQUERY is defined because
|
||||
** the compiler for the the IN operator is part of sub-queries.
|
||||
*/
|
||||
else if( pExpr->op==TK_OR ){
|
||||
int ok;
|
||||
@ -651,7 +664,7 @@ static void exprAnalyze(
|
||||
iCursor = sOr.a[j].leftCursor;
|
||||
ok = iCursor>=0;
|
||||
for(i=sOr.nTerm-1, pOrTerm=sOr.a; i>=0 && ok; i--, pOrTerm++){
|
||||
if( pOrTerm->operator!=WO_EQ ){
|
||||
if( pOrTerm->eOperator!=WO_EQ ){
|
||||
goto or_not_possible;
|
||||
}
|
||||
if( pOrTerm->leftCursor==iCursor && pOrTerm->leftColumn==iColumn ){
|
||||
@ -680,14 +693,17 @@ static void exprAnalyze(
|
||||
}
|
||||
pNew = sqlite3Expr(TK_IN, pDup, 0, 0);
|
||||
if( pNew ){
|
||||
int idxNew;
|
||||
transferJoinMarkings(pNew, pExpr);
|
||||
pNew->pList = pList;
|
||||
idxNew = whereClauseInsert(pWC, pNew, TERM_VIRTUAL|TERM_DYNAMIC);
|
||||
exprAnalyze(pSrc, pMaskSet, pWC, idxNew);
|
||||
pTerm = &pWC->a[idxTerm];
|
||||
pWC->a[idxNew].iParent = idxTerm;
|
||||
pTerm->nChild = 1;
|
||||
}else{
|
||||
sqlite3ExprListDelete(pList);
|
||||
}
|
||||
pTerm->pExpr = pNew;
|
||||
pTerm->flags |= TERM_DYNAMIC;
|
||||
exprAnalyze(pSrc, pMaskSet, pWC, idxTerm);
|
||||
pTerm = &pWC->a[idxTerm];
|
||||
}
|
||||
or_not_possible:
|
||||
whereClauseClear(&sOr);
|
||||
@ -762,7 +778,7 @@ static int isSortingIndex(
|
||||
int *pbRev /* Set to 1 if ORDER BY is DESC */
|
||||
){
|
||||
int i, j; /* Loop counters */
|
||||
int sortOrder = SQLITE_SO_ASC; /* Which direction we are sorting */
|
||||
int sortOrder = 0; /* XOR of index and ORDER BY sort direction */
|
||||
int nTerm; /* Number of ORDER BY terms */
|
||||
struct ExprList_item *pTerm; /* A term of the ORDER BY clause */
|
||||
sqlite3 *db = pParse->db;
|
||||
@ -777,6 +793,7 @@ static int isSortingIndex(
|
||||
for(i=j=0, pTerm=pOrderBy->a; j<nTerm && i<pIdx->nColumn; i++){
|
||||
Expr *pExpr; /* The expression of the ORDER BY pTerm */
|
||||
CollSeq *pColl; /* The collating sequence of pExpr */
|
||||
int termSortOrder; /* Sort order for this term */
|
||||
|
||||
pExpr = pTerm->pExpr;
|
||||
if( pExpr->op!=TK_COLUMN || pExpr->iTable!=base ){
|
||||
@ -786,7 +803,8 @@ static int isSortingIndex(
|
||||
}
|
||||
pColl = sqlite3ExprCollSeq(pParse, pExpr);
|
||||
if( !pColl ) pColl = db->pDfltColl;
|
||||
if( pExpr->iColumn!=pIdx->aiColumn[i] || pColl!=pIdx->keyInfo.aColl[i] ){
|
||||
if( pExpr->iColumn!=pIdx->aiColumn[i] ||
|
||||
sqlite3StrICmp(pColl->zName, pIdx->azColl[i]) ){
|
||||
/* Term j of the ORDER BY clause does not match column i of the index */
|
||||
if( i<nEqCol ){
|
||||
/* If an index column that is constrained by == fails to match an
|
||||
@ -800,14 +818,18 @@ static int isSortingIndex(
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
assert( pIdx->aSortOrder!=0 );
|
||||
assert( pTerm->sortOrder==0 || pTerm->sortOrder==1 );
|
||||
assert( pIdx->aSortOrder[i]==0 || pIdx->aSortOrder[i]==1 );
|
||||
termSortOrder = pIdx->aSortOrder[i] ^ pTerm->sortOrder;
|
||||
if( i>nEqCol ){
|
||||
if( pTerm->sortOrder!=sortOrder ){
|
||||
if( termSortOrder!=sortOrder ){
|
||||
/* Indices can only be used if all ORDER BY terms past the
|
||||
** equality constraints are all either DESC or ASC. */
|
||||
return 0;
|
||||
}
|
||||
}else{
|
||||
sortOrder = pTerm->sortOrder;
|
||||
sortOrder = termSortOrder;
|
||||
}
|
||||
j++;
|
||||
pTerm++;
|
||||
@ -817,7 +839,7 @@ static int isSortingIndex(
|
||||
** are covered.
|
||||
*/
|
||||
if( j>=nTerm ){
|
||||
*pbRev = sortOrder==SQLITE_SO_DESC;
|
||||
*pbRev = sortOrder!=0;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
@ -854,10 +876,10 @@ static int sortableByRowid(
|
||||
** logN is a little off.
|
||||
*/
|
||||
static double estLog(double N){
|
||||
double logN = 1.0;
|
||||
double x = 10.0;
|
||||
double logN = 1;
|
||||
double x = 10;
|
||||
while( N>x ){
|
||||
logN += 1.0;
|
||||
logN += 1;
|
||||
x *= 10;
|
||||
}
|
||||
return logN;
|
||||
@ -893,7 +915,7 @@ static double bestIndex(
|
||||
){
|
||||
WhereTerm *pTerm;
|
||||
Index *bestIdx = 0; /* Index that gives the lowest cost */
|
||||
double lowestCost = 1.0e99; /* The cost of using bestIdx */
|
||||
double lowestCost; /* The cost of using bestIdx */
|
||||
int bestFlags = 0; /* Flags associated with bestIdx */
|
||||
int bestNEq = 0; /* Best value for nEq */
|
||||
int iCur = pSrc->iCursor; /* The cursor of the table to be accessed */
|
||||
@ -904,6 +926,7 @@ static double bestIndex(
|
||||
double cost; /* Cost of using pProbe */
|
||||
|
||||
TRACE(("bestIndex: tbl=%s notReady=%x\n", pSrc->pTab->zName, notReady));
|
||||
lowestCost = SQLITE_BIG_DBL;
|
||||
|
||||
/* Check for a rowid=EXPR or rowid IN (...) constraints
|
||||
*/
|
||||
@ -912,7 +935,7 @@ static double bestIndex(
|
||||
Expr *pExpr;
|
||||
*ppIndex = 0;
|
||||
bestFlags = WHERE_ROWID_EQ;
|
||||
if( pTerm->operator & WO_EQ ){
|
||||
if( pTerm->eOperator & WO_EQ ){
|
||||
/* Rowid== is always the best pick. Look no further. Because only
|
||||
** a single row is generated, output is always in sorted order */
|
||||
*pFlags = WHERE_ROWID_EQ | WHERE_UNIQUE;
|
||||
@ -928,7 +951,7 @@ static double bestIndex(
|
||||
/* Rowid IN (SELECT): cost is NlogN where N is the number of rows
|
||||
** in the result of the inner select. We have no way to estimate
|
||||
** that value so make a wild guess. */
|
||||
lowestCost = 200.0;
|
||||
lowestCost = 200;
|
||||
}
|
||||
TRACE(("... rowid IN cost: %.9g\n", lowestCost));
|
||||
}
|
||||
@ -937,7 +960,7 @@ static double bestIndex(
|
||||
** entries are in the table, use 1 million as a guess.
|
||||
*/
|
||||
pProbe = pSrc->pTab->pIndex;
|
||||
cost = pProbe ? pProbe->aiRowEst[0] : 1000000.0;
|
||||
cost = pProbe ? pProbe->aiRowEst[0] : 1000000;
|
||||
TRACE(("... table scan base cost: %.9g\n", cost));
|
||||
flags = WHERE_ROWID_RANGE;
|
||||
|
||||
@ -947,11 +970,11 @@ static double bestIndex(
|
||||
if( pTerm ){
|
||||
if( findTerm(pWC, iCur, -1, notReady, WO_LT|WO_LE, 0) ){
|
||||
flags |= WHERE_TOP_LIMIT;
|
||||
cost *= 0.333; /* Guess that rowid<EXPR eliminates two-thirds or rows */
|
||||
cost /= 3; /* Guess that rowid<EXPR eliminates two-thirds or rows */
|
||||
}
|
||||
if( findTerm(pWC, iCur, -1, notReady, WO_GT|WO_GE, 0) ){
|
||||
flags |= WHERE_BTM_LIMIT;
|
||||
cost *= 0.333; /* Guess that rowid>EXPR eliminates two-thirds of rows */
|
||||
cost /= 3; /* Guess that rowid>EXPR eliminates two-thirds of rows */
|
||||
}
|
||||
TRACE(("... rowid range reduces cost to %.9g\n", cost));
|
||||
}else{
|
||||
@ -980,7 +1003,7 @@ static double bestIndex(
|
||||
*/
|
||||
for(; pProbe; pProbe=pProbe->pNext){
|
||||
int i; /* Loop counter */
|
||||
double inMultiplier = 1.0;
|
||||
double inMultiplier = 1;
|
||||
|
||||
TRACE(("... index %s:\n", pProbe->zName));
|
||||
|
||||
@ -993,13 +1016,13 @@ static double bestIndex(
|
||||
pTerm = findTerm(pWC, iCur, j, notReady, WO_EQ|WO_IN, pProbe);
|
||||
if( pTerm==0 ) break;
|
||||
flags |= WHERE_COLUMN_EQ;
|
||||
if( pTerm->operator & WO_IN ){
|
||||
if( pTerm->eOperator & WO_IN ){
|
||||
Expr *pExpr = pTerm->pExpr;
|
||||
flags |= WHERE_COLUMN_IN;
|
||||
if( pExpr->pSelect!=0 ){
|
||||
inMultiplier *= 100.0;
|
||||
inMultiplier *= 100;
|
||||
}else if( pExpr->pList!=0 ){
|
||||
inMultiplier *= pExpr->pList->nExpr + 1.0;
|
||||
inMultiplier *= pExpr->pList->nExpr + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1020,11 +1043,11 @@ static double bestIndex(
|
||||
flags |= WHERE_COLUMN_RANGE;
|
||||
if( findTerm(pWC, iCur, j, notReady, WO_LT|WO_LE, pProbe) ){
|
||||
flags |= WHERE_TOP_LIMIT;
|
||||
cost *= 0.333;
|
||||
cost /= 3;
|
||||
}
|
||||
if( findTerm(pWC, iCur, j, notReady, WO_GT|WO_GE, pProbe) ){
|
||||
flags |= WHERE_BTM_LIMIT;
|
||||
cost *= 0.333;
|
||||
cost /= 3;
|
||||
}
|
||||
TRACE(("...... range reduces cost to %.9g\n", cost));
|
||||
}
|
||||
@ -1063,7 +1086,7 @@ static double bestIndex(
|
||||
}
|
||||
if( m==0 ){
|
||||
flags |= WHERE_IDX_ONLY;
|
||||
cost *= 0.5;
|
||||
cost /= 2;
|
||||
TRACE(("...... idx-only reduces cost to %.9g\n", cost));
|
||||
}
|
||||
}
|
||||
@ -1134,14 +1157,24 @@ static void disableTerm(WhereLevel *pLevel, WhereTerm *pTerm){
|
||||
** * Check the top nColumn entries on the stack. If any
|
||||
** of those entries are NULL, jump immediately to brk,
|
||||
** which is the loop exit, since no index entry will match
|
||||
** if any part of the key is NULL.
|
||||
** if any part of the key is NULL. Pop (nColumn+nExtra)
|
||||
** elements from the stack.
|
||||
**
|
||||
** * Construct a probe entry from the top nColumn entries in
|
||||
** the stack with affinities appropriate for index pIdx.
|
||||
** the stack with affinities appropriate for index pIdx.
|
||||
** Only nColumn elements are popped from the stack in this case
|
||||
** (by OP_MakeRecord).
|
||||
**
|
||||
*/
|
||||
static void buildIndexProbe(Vdbe *v, int nColumn, int brk, Index *pIdx){
|
||||
static void buildIndexProbe(
|
||||
Vdbe *v,
|
||||
int nColumn,
|
||||
int nExtra,
|
||||
int brk,
|
||||
Index *pIdx
|
||||
){
|
||||
sqlite3VdbeAddOp(v, OP_NotNull, -nColumn, sqlite3VdbeCurrentAddr(v)+3);
|
||||
sqlite3VdbeAddOp(v, OP_Pop, nColumn, 0);
|
||||
sqlite3VdbeAddOp(v, OP_Pop, nColumn+nExtra, 0);
|
||||
sqlite3VdbeAddOp(v, OP_Goto, 0, brk);
|
||||
sqlite3VdbeAddOp(v, OP_MakeRecord, nColumn, 0);
|
||||
sqlite3IndexAffinityStr(v, pIdx);
|
||||
@ -1180,7 +1213,7 @@ static void codeEqualityTerm(
|
||||
sqlite3VdbeAddOp(v, OP_Rewind, iTab, brk);
|
||||
VdbeComment((v, "# %.*s", pX->span.n, pX->span.z));
|
||||
pLevel->nIn++;
|
||||
sqlite3ReallocOrFree((void**)&pLevel->aInLoop,
|
||||
sqliteReallocOrFree((void**)&pLevel->aInLoop,
|
||||
sizeof(pLevel->aInLoop[0])*3*pLevel->nIn);
|
||||
aIn = pLevel->aInLoop;
|
||||
if( aIn ){
|
||||
@ -1408,7 +1441,7 @@ WhereInfo *sqlite3WhereBegin(
|
||||
** return value.
|
||||
*/
|
||||
pWInfo = sqliteMalloc( sizeof(WhereInfo) + pTabList->nSrc*sizeof(WhereLevel));
|
||||
if( sqlite3_malloc_failed ){
|
||||
if( sqlite3MallocFailed() ){
|
||||
goto whereBeginNoMem;
|
||||
}
|
||||
pWInfo->pParse = pParse;
|
||||
@ -1432,7 +1465,7 @@ WhereInfo *sqlite3WhereBegin(
|
||||
createMask(&maskSet, pTabList->a[i].iCursor);
|
||||
}
|
||||
exprAnalyzeAll(pTabList, &maskSet, &wc);
|
||||
if( sqlite3_malloc_failed ){
|
||||
if( sqlite3MallocFailed() ){
|
||||
goto whereBeginNoMem;
|
||||
}
|
||||
|
||||
@ -1464,10 +1497,11 @@ WhereInfo *sqlite3WhereBegin(
|
||||
Index *pBest = 0; /* The best index seen so far */
|
||||
int bestFlags = 0; /* Flags associated with pBest */
|
||||
int bestNEq = 0; /* nEq associated with pBest */
|
||||
double lowestCost = 1.0e99; /* Cost of the pBest */
|
||||
int bestJ; /* The value of j */
|
||||
double lowestCost; /* Cost of the pBest */
|
||||
int bestJ = 0; /* The value of j */
|
||||
Bitmask m; /* Bitmask value for j or bestJ */
|
||||
|
||||
lowestCost = SQLITE_BIG_DBL;
|
||||
for(j=iFrom, pTabItem=&pTabList->a[j]; j<pTabList->nSrc; j++, pTabItem++){
|
||||
m = getMask(&maskSet, pTabItem->iCursor);
|
||||
if( (m & notReady)==0 ){
|
||||
@ -1524,8 +1558,9 @@ WhereInfo *sqlite3WhereBegin(
|
||||
sqlite3CodeVerifySchema(pParse, -1); /* Insert the cookie verifier Goto */
|
||||
pLevel = pWInfo->a;
|
||||
for(i=0, pLevel=pWInfo->a; i<pTabList->nSrc; i++, pLevel++){
|
||||
Table *pTab;
|
||||
Index *pIx;
|
||||
Table *pTab; /* Table to open */
|
||||
Index *pIx; /* Index used to access pTab (if any) */
|
||||
int iDb; /* Index of database containing table/index */
|
||||
int iIdxCur = pLevel->iIdxCur;
|
||||
|
||||
#ifndef SQLITE_OMIT_EXPLAIN
|
||||
@ -1538,27 +1573,41 @@ WhereInfo *sqlite3WhereBegin(
|
||||
}
|
||||
if( (pIx = pLevel->pIdx)!=0 ){
|
||||
zMsg = sqlite3MPrintf("%z WITH INDEX %s", zMsg, pIx->zName);
|
||||
}else if( pLevel->flags & (WHERE_ROWID_EQ|WHERE_ROWID_RANGE) ){
|
||||
zMsg = sqlite3MPrintf("%z USING PRIMARY KEY", zMsg);
|
||||
}
|
||||
sqlite3VdbeOp3(v, OP_Explain, i, pLevel->iFrom, zMsg, P3_DYNAMIC);
|
||||
}
|
||||
#endif /* SQLITE_OMIT_EXPLAIN */
|
||||
pTabItem = &pTabList->a[pLevel->iFrom];
|
||||
pTab = pTabItem->pTab;
|
||||
iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
|
||||
if( pTab->isTransient || pTab->pSelect ) continue;
|
||||
if( (pLevel->flags & WHERE_IDX_ONLY)==0 ){
|
||||
sqlite3OpenTableForReading(v, pTabItem->iCursor, pTab);
|
||||
sqlite3OpenTable(pParse, pTabItem->iCursor, iDb, pTab, OP_OpenRead);
|
||||
if( pTab->nCol<(sizeof(Bitmask)*8) ){
|
||||
Bitmask b = pTabItem->colUsed;
|
||||
int n = 0;
|
||||
for(; b; b=b>>1, n++);
|
||||
sqlite3VdbeChangeP2(v, sqlite3VdbeCurrentAddr(v)-1, n);
|
||||
assert( n<=pTab->nCol );
|
||||
}
|
||||
}else{
|
||||
sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName);
|
||||
}
|
||||
pLevel->iTabCur = pTabItem->iCursor;
|
||||
if( (pIx = pLevel->pIdx)!=0 ){
|
||||
sqlite3VdbeAddOp(v, OP_Integer, pIx->iDb, 0);
|
||||
KeyInfo *pKey = sqlite3IndexKeyinfo(pParse, pIx);
|
||||
assert( pIx->pSchema==pTab->pSchema );
|
||||
sqlite3VdbeAddOp(v, OP_Integer, iDb, 0);
|
||||
VdbeComment((v, "# %s", pIx->zName));
|
||||
sqlite3VdbeOp3(v, OP_OpenRead, iIdxCur, pIx->tnum,
|
||||
(char*)&pIx->keyInfo, P3_KEYINFO);
|
||||
(char*)pKey, P3_KEYINFO_HANDOFF);
|
||||
}
|
||||
if( (pLevel->flags & WHERE_IDX_ONLY)!=0 ){
|
||||
sqlite3VdbeAddOp(v, OP_SetNumColumns, iIdxCur, pIx->nColumn+1);
|
||||
}
|
||||
sqlite3CodeVerifySchema(pParse, pTab->iDb);
|
||||
sqlite3CodeVerifySchema(pParse, iDb);
|
||||
}
|
||||
pWInfo->iTop = sqlite3VdbeCurrentAddr(v);
|
||||
|
||||
@ -1667,7 +1716,7 @@ WhereInfo *sqlite3WhereBegin(
|
||||
if( testOp!=OP_Noop ){
|
||||
sqlite3VdbeAddOp(v, OP_Rowid, iCur, 0);
|
||||
sqlite3VdbeAddOp(v, OP_MemLoad, pLevel->iMem, 0);
|
||||
sqlite3VdbeAddOp(v, testOp, 'n', brk);
|
||||
sqlite3VdbeAddOp(v, testOp, SQLITE_AFF_NUMERIC, brk);
|
||||
}
|
||||
}else if( pLevel->flags & WHERE_COLUMN_RANGE ){
|
||||
/* Case 3: The WHERE clause term that refers to the right-most
|
||||
@ -1683,8 +1732,11 @@ WhereInfo *sqlite3WhereBegin(
|
||||
*/
|
||||
int start;
|
||||
int nEq = pLevel->nEq;
|
||||
int leFlag=0, geFlag=0;
|
||||
int topEq=0; /* True if top limit uses ==. False is strictly < */
|
||||
int btmEq=0; /* True if btm limit uses ==. False if strictly > */
|
||||
int topOp, btmOp; /* Operators for the top and bottom search bounds */
|
||||
int testOp;
|
||||
int nNotNull; /* Number of rows of index that must be non-NULL */
|
||||
int topLimit = (pLevel->flags & WHERE_TOP_LIMIT)!=0;
|
||||
int btmLimit = (pLevel->flags & WHERE_BTM_LIMIT)!=0;
|
||||
|
||||
@ -1701,6 +1753,21 @@ WhereInfo *sqlite3WhereBegin(
|
||||
sqlite3VdbeAddOp(v, OP_Dup, nEq-1, 0);
|
||||
}
|
||||
|
||||
/* Figure out what comparison operators to use for top and bottom
|
||||
** search bounds. For an ascending index, the bottom bound is a > or >=
|
||||
** operator and the top bound is a < or <= operator. For a descending
|
||||
** index the operators are reversed.
|
||||
*/
|
||||
nNotNull = nEq + topLimit;
|
||||
if( pIdx->aSortOrder[nEq]==SQLITE_SO_ASC ){
|
||||
topOp = WO_LT|WO_LE;
|
||||
btmOp = WO_GT|WO_GE;
|
||||
}else{
|
||||
topOp = WO_GT|WO_GE;
|
||||
btmOp = WO_LT|WO_LE;
|
||||
SWAP(int, topLimit, btmLimit);
|
||||
}
|
||||
|
||||
/* Generate the termination key. This is the key value that
|
||||
** will end the search. There is no termination key if there
|
||||
** are no equality terms and no "X<..." term.
|
||||
@ -1711,24 +1778,24 @@ WhereInfo *sqlite3WhereBegin(
|
||||
if( topLimit ){
|
||||
Expr *pX;
|
||||
int k = pIdx->aiColumn[j];
|
||||
pTerm = findTerm(&wc, iCur, k, notReady, WO_LT|WO_LE, pIdx);
|
||||
pTerm = findTerm(&wc, iCur, k, notReady, topOp, pIdx);
|
||||
assert( pTerm!=0 );
|
||||
pX = pTerm->pExpr;
|
||||
assert( (pTerm->flags & TERM_CODED)==0 );
|
||||
sqlite3ExprCode(pParse, pX->pRight);
|
||||
leFlag = pX->op==TK_LE;
|
||||
topEq = pTerm->eOperator & (WO_LE|WO_GE);
|
||||
disableTerm(pLevel, pTerm);
|
||||
testOp = OP_IdxGE;
|
||||
}else{
|
||||
testOp = nEq>0 ? OP_IdxGE : OP_Noop;
|
||||
leFlag = 1;
|
||||
topEq = 1;
|
||||
}
|
||||
if( testOp!=OP_Noop ){
|
||||
int nCol = nEq + topLimit;
|
||||
pLevel->iMem = pParse->nMem++;
|
||||
buildIndexProbe(v, nCol, brk, pIdx);
|
||||
buildIndexProbe(v, nCol, nEq, brk, pIdx);
|
||||
if( bRev ){
|
||||
int op = leFlag ? OP_MoveLe : OP_MoveLt;
|
||||
int op = topEq ? OP_MoveLe : OP_MoveLt;
|
||||
sqlite3VdbeAddOp(v, op, iIdxCur, brk);
|
||||
}else{
|
||||
sqlite3VdbeAddOp(v, OP_MemStore, pLevel->iMem, 1);
|
||||
@ -1749,25 +1816,25 @@ WhereInfo *sqlite3WhereBegin(
|
||||
if( btmLimit ){
|
||||
Expr *pX;
|
||||
int k = pIdx->aiColumn[j];
|
||||
pTerm = findTerm(&wc, iCur, k, notReady, WO_GT|WO_GE, pIdx);
|
||||
pTerm = findTerm(&wc, iCur, k, notReady, btmOp, pIdx);
|
||||
assert( pTerm!=0 );
|
||||
pX = pTerm->pExpr;
|
||||
assert( (pTerm->flags & TERM_CODED)==0 );
|
||||
sqlite3ExprCode(pParse, pX->pRight);
|
||||
geFlag = pX->op==TK_GE;
|
||||
btmEq = pTerm->eOperator & (WO_LE|WO_GE);
|
||||
disableTerm(pLevel, pTerm);
|
||||
}else{
|
||||
geFlag = 1;
|
||||
btmEq = 1;
|
||||
}
|
||||
if( nEq>0 || btmLimit ){
|
||||
int nCol = nEq + btmLimit;
|
||||
buildIndexProbe(v, nCol, brk, pIdx);
|
||||
buildIndexProbe(v, nCol, 0, brk, pIdx);
|
||||
if( bRev ){
|
||||
pLevel->iMem = pParse->nMem++;
|
||||
sqlite3VdbeAddOp(v, OP_MemStore, pLevel->iMem, 1);
|
||||
testOp = OP_IdxLT;
|
||||
}else{
|
||||
int op = geFlag ? OP_MoveGe : OP_MoveGt;
|
||||
int op = btmEq ? OP_MoveGe : OP_MoveGt;
|
||||
sqlite3VdbeAddOp(v, op, iIdxCur, brk);
|
||||
}
|
||||
}else if( bRev ){
|
||||
@ -1784,12 +1851,12 @@ WhereInfo *sqlite3WhereBegin(
|
||||
if( testOp!=OP_Noop ){
|
||||
sqlite3VdbeAddOp(v, OP_MemLoad, pLevel->iMem, 0);
|
||||
sqlite3VdbeAddOp(v, testOp, iIdxCur, brk);
|
||||
if( (leFlag && !bRev) || (!geFlag && bRev) ){
|
||||
if( (topEq && !bRev) || (!btmEq && bRev) ){
|
||||
sqlite3VdbeChangeP3(v, -1, "+", P3_STATIC);
|
||||
}
|
||||
}
|
||||
sqlite3VdbeAddOp(v, OP_RowKey, iIdxCur, 0);
|
||||
sqlite3VdbeAddOp(v, OP_IdxIsNull, nEq + topLimit, cont);
|
||||
sqlite3VdbeAddOp(v, OP_IdxIsNull, nNotNull, cont);
|
||||
if( !omitTable ){
|
||||
sqlite3VdbeAddOp(v, OP_IdxRowid, iIdxCur, 0);
|
||||
sqlite3VdbeAddOp(v, OP_MoveGe, iCur, 0);
|
||||
@ -1815,7 +1882,7 @@ WhereInfo *sqlite3WhereBegin(
|
||||
/* Generate a single key that will be used to both start and terminate
|
||||
** the search
|
||||
*/
|
||||
buildIndexProbe(v, nEq, brk, pIdx);
|
||||
buildIndexProbe(v, nEq, 0, brk, pIdx);
|
||||
sqlite3VdbeAddOp(v, OP_MemStore, pLevel->iMem, 0);
|
||||
|
||||
/* Generate code (1) to move to the first matching element of the table.
|
||||
@ -2018,14 +2085,14 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
|
||||
** reference the index.
|
||||
*/
|
||||
if( pLevel->flags & WHERE_IDX_ONLY ){
|
||||
int i, j, last;
|
||||
int k, j, last;
|
||||
VdbeOp *pOp;
|
||||
Index *pIdx = pLevel->pIdx;
|
||||
|
||||
assert( pIdx!=0 );
|
||||
pOp = sqlite3VdbeGetOp(v, pWInfo->iTop);
|
||||
last = sqlite3VdbeCurrentAddr(v);
|
||||
for(i=pWInfo->iTop; i<last; i++, pOp++){
|
||||
for(k=pWInfo->iTop; k<last; k++, pOp++){
|
||||
if( pOp->p1!=pLevel->iTabCur ) continue;
|
||||
if( pOp->opcode==OP_Column ){
|
||||
pOp->p1 = pLevel->iIdxCur;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user