1
0
Fork 0
mirror of https://github.com/DBD-SQLite/DBD-SQLite synced 2025-06-07 14:19:10 -04:00

DBD::SQLite: updated bundled SQLite to 3.6.10, and bumped up the version requirement for installed SQLite to 3.6.0 as 3.6.x has backward incompatibility (cont.)

This commit is contained in:
Kenichi Ishigaki 2009-01-29 01:28:06 +00:00
parent 22dc86ddcb
commit e366c24c23
101 changed files with 55510 additions and 25960 deletions

View file

@ -1,5 +1,10 @@
Revision history for Perl extension DBD::SQLite. Revision history for Perl extension DBD::SQLite.
1.15
- Updated to SQLite 3.6.10, and bumped up the version
requirement for installed sqlite3 to 3.6.0 as 3.6.x
has backward incompatiblity (ISHIGAKI)
1.14 1.14
- Updated to SQLite 3.4.2 - Updated to SQLite 3.4.2
- Switch to sqlite3_prepare_v2 which fixes a number of bugs - Switch to sqlite3_prepare_v2 which fixes a number of bugs

254
MANIFEST
View file

@ -1,114 +1,140 @@
alter.c alter.c
analyze.c analyze.c
attach.c attach.c
auth.c auth.c
btree.c bitvec.c
btree.h btmutex.c
btreeInt.h btree.c
build.c btree.h
callback.c btreeInt.h
Changes build.c
complete.c callback.c
date.c Changes
dbdimp.c complete.c
dbdimp.h date.c
delete.c dbdimp.c
expr.c dbdimp.h
func.c delete.c
fts2.c expr.c
fts2.h fault.c
fts2_hash.c fts3.c
fts2_hash.h fts3.h
fts2_icu.c fts3_expr.c
fts2_porter.c fts3_expr.h
fts2_tokenizer.c fts3_hash.c
fts2_tokenizer.h fts3_hash.h
fts2_tokenizer1.c fts3_icu.c
getsqlite.pl fts3_porter.c
hash.c fts3_tokenizer.c
hash.h fts3_tokenizer.h
insert.c fts3_tokenizer1.c
keywordhash.h func.c
legacy.c getsqlite.pl
lib/DBD/SQLite.pm global.c
loadext.c hash.c
main.c hash.h
Makefile.PL hwtime.h
malloc.c insert.c
MANIFEST journal.c
MANIFEST.SKIP keywordhash.h
META.yml Module meta-data (added by MakeMaker) legacy.c
opcodes.c lib/DBD/SQLite.pm
opcodes.h loadext.c
os.c main.c
os.h Makefile.PL
os_common.h malloc.c
os_os2.c MANIFEST This list of files
os_os2.h MANIFEST.SKIP
os_unix.c mem0.c
os_win.c mem1.c
pager.c mem2.c
pager.h mem3.c
parse.c mem5.c
parse.h memjournal.c
ppport.h META.yml
pragma.c mutex.c
prepare.c mutex.h
printf.c mutex_noop.c
random.c mutex_os2.c
README mutex_unix.c
select.c mutex_w32.c
SQLite.xs opcodes.c
sqlite3.h opcodes.h
sqlite3ext.h os.c
sqliteInt.h os.h
sqliteLimit.h os_common.h
SQLiteXS.h os_os2.c
t/00basic.t os_unix.c
t/01logon.t os_win.c
t/02cr_table.t pager.c
t/03insert.t pager.h
t/04select.t parse.c
t/05tran.t parse.h
t/06error.t pcache.c
t/07busy.t pcache.h
t/08create_function.t pcache1.c
t/09create_aggregate.t ppport.h
t/10dsnlist.t pragma.c
t/11unicode.t prepare.c
t/20createdrop.t printf.c
t/30insertfetch.t random.c
t/40bindparam.t README
t/40blobs.t resolve.c
t/40blobtext.t rowset.c
t/40listfields.t select.c
t/40nulls.t shell.c
t/40numrows.t SQLite.xs
t/40prepcached.t sqlite3.h
t/50chopblanks.t sqlite3ext.h
t/50commit.t sqliteInt.h
t/60metadata.t sqliteLimit.h
t/70schemachange.t SQLiteXS.h
t/90cppcomments.t status.c
t/99cleanup.t t/00basic.t
t/ak-dbd.t t/01logon.t
t/dbdadmin.t t/02cr_table.t
t/lib.pl t/03insert.t
t/SQLite.dbtest t/04select.t
table.c t/05tran.t
tokenize.c t/06error.t
trigger.c t/07busy.t
update.c t/08create_function.t
utf.c t/09create_aggregate.t
util.c t/10dsnlist.t
vacuum.c t/11unicode.t
vdbe.c t/20createdrop.t
vdbe.h t/30insertfetch.t
vdbeapi.c t/40bindparam.t
vdbeaux.c t/40blobs.t
vdbeblob.c t/40blobtext.t
vdbefifo.c t/40listfields.t
vdbeInt.h t/40nulls.t
vdbemem.c t/40numrows.t
vtab.c t/40prepcached.t
where.c t/50chopblanks.t
t/50commit.t
t/60metadata.t
t/70schemachange.t
t/90cppcomments.t
t/99cleanup.t
t/ak-dbd.t
t/dbdadmin.t
t/lib.pl
t/SQLite.dbtest
table.c
tokenize.c
trigger.c
update.c
utf.c
util.c
vacuum.c
vdbe.c
vdbe.h
vdbeapi.c
vdbeaux.c
vdbeblob.c
vdbeInt.h
vdbemem.c
vtab.c
walker.c
where.c

View file

@ -18,3 +18,5 @@ output/.*
^Makefile\.[a-z]+$ ^Makefile\.[a-z]+$
^pm_to_blib$ ^pm_to_blib$
~$ ~$
^sqlite\-
\.svn

View file

@ -89,8 +89,8 @@ unless ( $force_local ) {
last if $version; last if $version;
} }
} }
unless ( $version && ($version >= 3003009) ) { unless ( $version && ($version >= 3006000) ) {
warn "SQLite version must be at least 3.3.9. No header file at that\n"; warn "SQLite version must be at least 3.6.0. No header file at that\n";
warn "version or higher was found. Using the local version instead.\n"; warn "version or higher was found. Using the local version instead.\n";
$force_local = 1; $force_local = 1;
undef $sqlite_lib; undef $sqlite_lib;
@ -127,7 +127,7 @@ if ( $sqlite_inc ) {
my @CC_DEFINE = ( my @CC_DEFINE = (
'-DSQLITE_CORE', '-DSQLITE_CORE',
'-DSQLITE_ENABLE_FTS2', '-DSQLITE_ENABLE_FTS3',
'-DNDEBUG=1', '-DNDEBUG=1',
"-DSQLITE_PTR_SZ=$Config{ptrsize}" "-DSQLITE_PTR_SZ=$Config{ptrsize}"
); );

147
alter.c
View file

@ -12,7 +12,7 @@
** This file contains C code routines that used to generate VDBE code ** This file contains C code routines that used to generate VDBE code
** that implements the ALTER TABLE command. ** that implements the ALTER TABLE command.
** **
** $Id: alter.c,v 1.27 2007/06/27 17:09:24 danielk1977 Exp $ ** $Id: alter.c,v 1.51 2008/12/10 19:26:22 drh Exp $
*/ */
#include "sqliteInt.h" #include "sqliteInt.h"
#include <ctype.h> #include <ctype.h>
@ -39,7 +39,7 @@
*/ */
static void renameTableFunc( static void renameTableFunc(
sqlite3_context *context, sqlite3_context *context,
int argc, int NotUsed,
sqlite3_value **argv sqlite3_value **argv
){ ){
unsigned char const *zSql = sqlite3_value_text(argv[0]); unsigned char const *zSql = sqlite3_value_text(argv[0]);
@ -51,9 +51,13 @@ static void renameTableFunc(
int len = 0; int len = 0;
char *zRet; char *zRet;
sqlite3 *db = sqlite3_context_db_handle(context);
UNUSED_PARAMETER(NotUsed);
/* The principle used to locate the table name in the CREATE TABLE /* The principle used to locate the table name in the CREATE TABLE
** statement is that the table name is the first token that is immediatedly ** statement is that the table name is the first non-space token that
** followed by a left parenthesis - TK_LP - or "USING" TK_USING. ** is immediately followed by a TK_LP or TK_USING token.
*/ */
if( zSql ){ if( zSql ){
do { do {
@ -67,7 +71,7 @@ static void renameTableFunc(
tname.n = len; tname.n = len;
/* Advance zCsr to the next token. Store that token type in 'token', /* Advance zCsr to the next token. Store that token type in 'token',
** and it's length in 'len' (to be used next iteration of this loop). ** and its length in 'len' (to be used next iteration of this loop).
*/ */
do { do {
zCsr += len; zCsr += len;
@ -76,9 +80,9 @@ static void renameTableFunc(
assert( len>0 ); assert( len>0 );
} while( token!=TK_LP && token!=TK_USING ); } while( token!=TK_LP && token!=TK_USING );
zRet = sqlite3MPrintf("%.*s%Q%s", tname.z - zSql, zSql, zRet = sqlite3MPrintf(db, "%.*s\"%w\"%s", tname.z - zSql, zSql,
zTableName, tname.z+tname.n); zTableName, tname.z+tname.n);
sqlite3_result_text(context, zRet, -1, sqlite3FreeX); sqlite3_result_text(context, zRet, -1, SQLITE_DYNAMIC);
} }
} }
@ -92,7 +96,7 @@ static void renameTableFunc(
*/ */
static void renameTriggerFunc( static void renameTriggerFunc(
sqlite3_context *context, sqlite3_context *context,
int argc, int NotUsed,
sqlite3_value **argv sqlite3_value **argv
){ ){
unsigned char const *zSql = sqlite3_value_text(argv[0]); unsigned char const *zSql = sqlite3_value_text(argv[0]);
@ -104,6 +108,9 @@ static void renameTriggerFunc(
unsigned char const *zCsr = zSql; unsigned char const *zCsr = zSql;
int len = 0; int len = 0;
char *zRet; char *zRet;
sqlite3 *db = sqlite3_context_db_handle(context);
UNUSED_PARAMETER(NotUsed);
/* The principle used to locate the table name in the CREATE TRIGGER /* The principle used to locate the table name in the CREATE TRIGGER
** statement is that the table name is the first token that is immediatedly ** statement is that the table name is the first token that is immediatedly
@ -123,7 +130,7 @@ static void renameTriggerFunc(
tname.n = len; tname.n = len;
/* Advance zCsr to the next token. Store that token type in 'token', /* Advance zCsr to the next token. Store that token type in 'token',
** and it's length in 'len' (to be used next iteration of this loop). ** and its length in 'len' (to be used next iteration of this loop).
*/ */
do { do {
zCsr += len; zCsr += len;
@ -149,9 +156,9 @@ static void renameTriggerFunc(
/* Variable tname now contains the token that is the old table-name /* Variable tname now contains the token that is the old table-name
** in the CREATE TRIGGER statement. ** in the CREATE TRIGGER statement.
*/ */
zRet = sqlite3MPrintf("%.*s%Q%s", tname.z - zSql, zSql, zRet = sqlite3MPrintf(db, "%.*s\"%w\"%s", tname.z - zSql, zSql,
zTableName, tname.z+tname.n); zTableName, tname.z+tname.n);
sqlite3_result_text(context, zRet, -1, sqlite3FreeX); sqlite3_result_text(context, zRet, -1, SQLITE_DYNAMIC);
} }
} }
#endif /* !SQLITE_OMIT_TRIGGER */ #endif /* !SQLITE_OMIT_TRIGGER */
@ -160,22 +167,12 @@ static void renameTriggerFunc(
** Register built-in functions used to help implement ALTER TABLE ** Register built-in functions used to help implement ALTER TABLE
*/ */
void sqlite3AlterFunctions(sqlite3 *db){ void sqlite3AlterFunctions(sqlite3 *db){
static const struct { sqlite3CreateFunc(db, "sqlite_rename_table", 2, SQLITE_UTF8, 0,
char *zName; renameTableFunc, 0, 0);
signed char nArg;
void (*xFunc)(sqlite3_context*,int,sqlite3_value **);
} aFuncs[] = {
{ "sqlite_rename_table", 2, renameTableFunc},
#ifndef SQLITE_OMIT_TRIGGER #ifndef SQLITE_OMIT_TRIGGER
{ "sqlite_rename_trigger", 2, renameTriggerFunc}, sqlite3CreateFunc(db, "sqlite_rename_trigger", 2, SQLITE_UTF8, 0,
renameTriggerFunc, 0, 0);
#endif #endif
};
int i;
for(i=0; i<sizeof(aFuncs)/sizeof(aFuncs[0]); i++){
sqlite3CreateFunc(db, aFuncs[i].zName, aFuncs[i].nArg,
SQLITE_UTF8, 0, aFuncs[i].xFunc, 0, 0);
}
} }
/* /*
@ -196,14 +193,15 @@ static char *whereTempTriggers(Parse *pParse, Table *pTab){
** expression being built up in zWhere. ** expression being built up in zWhere.
*/ */
if( pTab->pSchema!=pTempSchema ){ if( pTab->pSchema!=pTempSchema ){
sqlite3 *db = pParse->db;
for( pTrig=pTab->pTrigger; pTrig; pTrig=pTrig->pNext ){ for( pTrig=pTab->pTrigger; pTrig; pTrig=pTrig->pNext ){
if( pTrig->pSchema==pTempSchema ){ if( pTrig->pSchema==pTempSchema ){
if( !zWhere ){ if( !zWhere ){
zWhere = sqlite3MPrintf("name=%Q", pTrig->name); zWhere = sqlite3MPrintf(db, "name=%Q", pTrig->name);
}else{ }else{
tmp = zWhere; tmp = zWhere;
zWhere = sqlite3MPrintf("%s OR name=%Q", zWhere, pTrig->name); zWhere = sqlite3MPrintf(db, "%s OR name=%Q", zWhere, pTrig->name);
sqliteFree(tmp); sqlite3DbFree(db, tmp);
} }
} }
} }
@ -229,6 +227,7 @@ static void reloadTableSchema(Parse *pParse, Table *pTab, const char *zName){
v = sqlite3GetVdbe(pParse); v = sqlite3GetVdbe(pParse);
if( !v ) return; if( !v ) return;
assert( sqlite3BtreeHoldsAllMutexes(pParse->db) );
iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema); iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
assert( iDb>=0 ); assert( iDb>=0 );
@ -237,24 +236,24 @@ static void reloadTableSchema(Parse *pParse, Table *pTab, const char *zName){
for(pTrig=pTab->pTrigger; pTrig; pTrig=pTrig->pNext){ for(pTrig=pTab->pTrigger; pTrig; pTrig=pTrig->pNext){
int iTrigDb = sqlite3SchemaToIndex(pParse->db, pTrig->pSchema); int iTrigDb = sqlite3SchemaToIndex(pParse->db, pTrig->pSchema);
assert( iTrigDb==iDb || iTrigDb==1 ); assert( iTrigDb==iDb || iTrigDb==1 );
sqlite3VdbeOp3(v, OP_DropTrigger, iTrigDb, 0, pTrig->name, 0); sqlite3VdbeAddOp4(v, OP_DropTrigger, iTrigDb, 0, 0, pTrig->name, 0);
} }
#endif #endif
/* Drop the table and index from the internal schema */ /* Drop the table and index from the internal schema */
sqlite3VdbeOp3(v, OP_DropTable, iDb, 0, pTab->zName, 0); sqlite3VdbeAddOp4(v, OP_DropTable, iDb, 0, 0, pTab->zName, 0);
/* Reload the table, index and permanent trigger schemas. */ /* Reload the table, index and permanent trigger schemas. */
zWhere = sqlite3MPrintf("tbl_name=%Q", zName); zWhere = sqlite3MPrintf(pParse->db, "tbl_name=%Q", zName);
if( !zWhere ) return; if( !zWhere ) return;
sqlite3VdbeOp3(v, OP_ParseSchema, iDb, 0, zWhere, P3_DYNAMIC); sqlite3VdbeAddOp4(v, OP_ParseSchema, iDb, 0, 0, zWhere, P4_DYNAMIC);
#ifndef SQLITE_OMIT_TRIGGER #ifndef SQLITE_OMIT_TRIGGER
/* Now, if the table is not stored in the temp database, reload any temp /* 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. ** triggers. Don't use IN(...) in case SQLITE_OMIT_SUBQUERY is defined.
*/ */
if( (zWhere=whereTempTriggers(pParse, pTab))!=0 ){ if( (zWhere=whereTempTriggers(pParse, pTab))!=0 ){
sqlite3VdbeOp3(v, OP_ParseSchema, 1, 0, zWhere, P3_DYNAMIC); sqlite3VdbeAddOp4(v, OP_ParseSchema, 1, 0, 0, zWhere, P4_DYNAMIC);
} }
#endif #endif
} }
@ -281,16 +280,17 @@ void sqlite3AlterRenameTable(
#endif #endif
int isVirtualRename = 0; /* True if this is a v-table with an xRename() */ int isVirtualRename = 0; /* True if this is a v-table with an xRename() */
if( sqlite3MallocFailed() ) goto exit_rename_table; if( db->mallocFailed ) goto exit_rename_table;
assert( pSrc->nSrc==1 ); assert( pSrc->nSrc==1 );
assert( sqlite3BtreeHoldsAllMutexes(pParse->db) );
pTab = sqlite3LocateTable(pParse, pSrc->a[0].zName, pSrc->a[0].zDatabase); pTab = sqlite3LocateTable(pParse, 0, pSrc->a[0].zName, pSrc->a[0].zDatabase);
if( !pTab ) goto exit_rename_table; if( !pTab ) goto exit_rename_table;
iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema); iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
zDb = db->aDb[iDb].zName; zDb = db->aDb[iDb].zName;
/* Get a NULL terminated version of the new table name. */ /* Get a NULL terminated version of the new table name. */
zName = sqlite3NameFromToken(pName); zName = sqlite3NameFromToken(db, pName);
if( !zName ) goto exit_rename_table; if( !zName ) goto exit_rename_table;
/* Check that a table or index named 'zName' does not already exist /* Check that a table or index named 'zName' does not already exist
@ -305,7 +305,9 @@ void sqlite3AlterRenameTable(
/* Make sure it is not a system table being altered, or a reserved name /* Make sure it is not a system table being altered, or a reserved name
** that the table is being renamed to. ** that the table is being renamed to.
*/ */
if( strlen(pTab->zName)>6 && 0==sqlite3StrNICmp(pTab->zName, "sqlite_", 7) ){ if( sqlite3Strlen30(pTab->zName)>6
&& 0==sqlite3StrNICmp(pTab->zName, "sqlite_", 7)
){
sqlite3ErrorMsg(pParse, "table %s may not be altered", pTab->zName); sqlite3ErrorMsg(pParse, "table %s may not be altered", pTab->zName);
goto exit_rename_table; goto exit_rename_table;
} }
@ -313,6 +315,13 @@ void sqlite3AlterRenameTable(
goto exit_rename_table; goto exit_rename_table;
} }
#ifndef SQLITE_OMIT_VIEW
if( pTab->pSelect ){
sqlite3ErrorMsg(pParse, "view %s may not be altered", pTab->zName);
goto exit_rename_table;
}
#endif
#ifndef SQLITE_OMIT_AUTHORIZATION #ifndef SQLITE_OMIT_AUTHORIZATION
/* Invoke the authorization callback. */ /* Invoke the authorization callback. */
if( sqlite3AuthCheck(pParse, SQLITE_ALTER_TABLE, zDb, pTab->zName, 0) ){ if( sqlite3AuthCheck(pParse, SQLITE_ALTER_TABLE, zDb, pTab->zName, 0) ){
@ -339,7 +348,7 @@ void sqlite3AlterRenameTable(
goto exit_rename_table; goto exit_rename_table;
} }
sqlite3BeginWriteOperation(pParse, isVirtualRename, iDb); sqlite3BeginWriteOperation(pParse, isVirtualRename, iDb);
sqlite3ChangeCookie(db, v, iDb); sqlite3ChangeCookie(pParse, iDb);
/* If this is a virtual table, invoke the xRename() function if /* If this is a virtual table, invoke the xRename() function if
** one is defined. The xRename() callback will modify the names ** one is defined. The xRename() callback will modify the names
@ -348,8 +357,9 @@ void sqlite3AlterRenameTable(
*/ */
#ifndef SQLITE_OMIT_VIRTUALTABLE #ifndef SQLITE_OMIT_VIRTUALTABLE
if( isVirtualRename ){ if( isVirtualRename ){
sqlite3VdbeOp3(v, OP_String8, 0, 0, zName, 0); int i = ++pParse->nMem;
sqlite3VdbeOp3(v, OP_VRename, 0, 0, (const char*)pTab->pVtab, P3_VTAB); sqlite3VdbeAddOp4(v, OP_String8, 0, i, 0, zName, 0);
sqlite3VdbeAddOp4(v, OP_VRename, i, 0, 0,(const char*)pTab->pVtab, P4_VTAB);
} }
#endif #endif
@ -371,7 +381,7 @@ void sqlite3AlterRenameTable(
"name = CASE " "name = CASE "
"WHEN type='table' THEN %Q " "WHEN type='table' THEN %Q "
"WHEN name LIKE 'sqlite_autoindex%%' AND type='index' THEN " "WHEN name LIKE 'sqlite_autoindex%%' AND type='index' THEN "
"'sqlite_autoindex_' || %Q || substr(name,%d+18,10) " "'sqlite_autoindex_' || %Q || substr(name,%d+18) "
"ELSE name END " "ELSE name END "
"WHERE tbl_name=%Q AND " "WHERE tbl_name=%Q AND "
"(type='table' OR type='index' OR type='trigger');", "(type='table' OR type='index' OR type='trigger');",
@ -388,7 +398,7 @@ void sqlite3AlterRenameTable(
*/ */
if( sqlite3FindTable(db, "sqlite_sequence", zDb) ){ if( sqlite3FindTable(db, "sqlite_sequence", zDb) ){
sqlite3NestedParse(pParse, sqlite3NestedParse(pParse,
"UPDATE %Q.sqlite_sequence set name = %Q WHERE name = %Q", "UPDATE \"%w\".sqlite_sequence set name = %Q WHERE name = %Q",
zDb, zName, pTab->zName); zDb, zName, pTab->zName);
} }
#endif #endif
@ -404,7 +414,7 @@ void sqlite3AlterRenameTable(
"sql = sqlite_rename_trigger(sql, %Q), " "sql = sqlite_rename_trigger(sql, %Q), "
"tbl_name = %Q " "tbl_name = %Q "
"WHERE %s;", zName, zName, zWhere); "WHERE %s;", zName, zName, zWhere);
sqliteFree(zWhere); sqlite3DbFree(db, zWhere);
} }
#endif #endif
@ -412,8 +422,8 @@ void sqlite3AlterRenameTable(
reloadTableSchema(pParse, pTab, zName); reloadTableSchema(pParse, pTab, zName);
exit_rename_table: exit_rename_table:
sqlite3SrcListDelete(pSrc); sqlite3SrcListDelete(db, pSrc);
sqliteFree(zName); sqlite3DbFree(db, zName);
} }
@ -434,17 +444,20 @@ void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){
char *zCol; /* Null-terminated column definition */ char *zCol; /* Null-terminated column definition */
Column *pCol; /* The new column */ Column *pCol; /* The new column */
Expr *pDflt; /* Default value for the new column */ Expr *pDflt; /* Default value for the new column */
sqlite3 *db; /* The database connection; */
if( pParse->nErr ) return; db = pParse->db;
if( pParse->nErr || db->mallocFailed ) return;
pNew = pParse->pNewTable; pNew = pParse->pNewTable;
assert( pNew ); assert( pNew );
iDb = sqlite3SchemaToIndex(pParse->db, pNew->pSchema); assert( sqlite3BtreeHoldsAllMutexes(db) );
zDb = pParse->db->aDb[iDb].zName; iDb = sqlite3SchemaToIndex(db, pNew->pSchema);
zDb = db->aDb[iDb].zName;
zTab = pNew->zName; zTab = pNew->zName;
pCol = &pNew->aCol[pNew->nCol-1]; pCol = &pNew->aCol[pNew->nCol-1];
pDflt = pCol->pDflt; pDflt = pCol->pDflt;
pTab = sqlite3FindTable(pParse->db, zTab, zDb); pTab = sqlite3FindTable(db, zTab, zDb);
assert( pTab ); assert( pTab );
#ifndef SQLITE_OMIT_AUTHORIZATION #ifndef SQLITE_OMIT_AUTHORIZATION
@ -485,8 +498,8 @@ void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){
*/ */
if( pDflt ){ if( pDflt ){
sqlite3_value *pVal; sqlite3_value *pVal;
if( sqlite3ValueFromExpr(pDflt, SQLITE_UTF8, SQLITE_AFF_NONE, &pVal) ){ if( sqlite3ValueFromExpr(db, pDflt, SQLITE_UTF8, SQLITE_AFF_NONE, &pVal) ){
/* malloc() has failed */ db->mallocFailed = 1;
return; return;
} }
if( !pVal ){ if( !pVal ){
@ -497,20 +510,20 @@ void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){
} }
/* Modify the CREATE TABLE statement. */ /* Modify the CREATE TABLE statement. */
zCol = sqliteStrNDup((char*)pColDef->z, pColDef->n); zCol = sqlite3DbStrNDup(db, (char*)pColDef->z, pColDef->n);
if( zCol ){ if( zCol ){
char *zEnd = &zCol[pColDef->n-1]; char *zEnd = &zCol[pColDef->n-1];
while( (zEnd>zCol && *zEnd==';') || isspace(*(unsigned char *)zEnd) ){ while( (zEnd>zCol && *zEnd==';') || isspace(*(unsigned char *)zEnd) ){
*zEnd-- = '\0'; *zEnd-- = '\0';
} }
sqlite3NestedParse(pParse, sqlite3NestedParse(pParse,
"UPDATE %Q.%s SET " "UPDATE \"%w\".%s SET "
"sql = substr(sql,1,%d) || ', ' || %Q || substr(sql,%d,length(sql)) " "sql = substr(sql,1,%d) || ', ' || %Q || substr(sql,%d) "
"WHERE type = 'table' AND name = %Q", "WHERE type = 'table' AND name = %Q",
zDb, SCHEMA_TABLE(iDb), pNew->addColOffset, zCol, pNew->addColOffset+1, zDb, SCHEMA_TABLE(iDb), pNew->addColOffset, zCol, pNew->addColOffset+1,
zTab zTab
); );
sqliteFree(zCol); sqlite3DbFree(db, zCol);
} }
/* If the default value of the new column is NULL, then set the file /* If the default value of the new column is NULL, then set the file
@ -545,11 +558,13 @@ void sqlite3AlterBeginAddColumn(Parse *pParse, SrcList *pSrc){
int iDb; int iDb;
int i; int i;
int nAlloc; int nAlloc;
sqlite3 *db = pParse->db;
/* Look up the table being altered. */ /* Look up the table being altered. */
assert( pParse->pNewTable==0 ); assert( pParse->pNewTable==0 );
if( sqlite3MallocFailed() ) goto exit_begin_add_column; assert( sqlite3BtreeHoldsAllMutexes(db) );
pTab = sqlite3LocateTable(pParse, pSrc->a[0].zName, pSrc->a[0].zDatabase); if( db->mallocFailed ) goto exit_begin_add_column;
pTab = sqlite3LocateTable(pParse, 0, pSrc->a[0].zName, pSrc->a[0].zDatabase);
if( !pTab ) goto exit_begin_add_column; if( !pTab ) goto exit_begin_add_column;
#ifndef SQLITE_OMIT_VIRTUALTABLE #ifndef SQLITE_OMIT_VIRTUALTABLE
@ -566,33 +581,35 @@ void sqlite3AlterBeginAddColumn(Parse *pParse, SrcList *pSrc){
} }
assert( pTab->addColOffset>0 ); assert( pTab->addColOffset>0 );
iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema); iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
/* Put a copy of the Table struct in Parse.pNewTable for the /* Put a copy of the Table struct in Parse.pNewTable for the
** sqlite3AddColumn() function and friends to modify. ** sqlite3AddColumn() function and friends to modify.
*/ */
pNew = (Table *)sqliteMalloc(sizeof(Table)); pNew = (Table*)sqlite3DbMallocZero(db, sizeof(Table));
if( !pNew ) goto exit_begin_add_column; if( !pNew ) goto exit_begin_add_column;
pParse->pNewTable = pNew; pParse->pNewTable = pNew;
pNew->nRef = 1; pNew->nRef = 1;
pNew->db = db;
pNew->nCol = pTab->nCol; pNew->nCol = pTab->nCol;
assert( pNew->nCol>0 ); assert( pNew->nCol>0 );
nAlloc = (((pNew->nCol-1)/8)*8)+8; nAlloc = (((pNew->nCol-1)/8)*8)+8;
assert( nAlloc>=pNew->nCol && nAlloc%8==0 && nAlloc-pNew->nCol<8 ); assert( nAlloc>=pNew->nCol && nAlloc%8==0 && nAlloc-pNew->nCol<8 );
pNew->aCol = (Column *)sqliteMalloc(sizeof(Column)*nAlloc); pNew->aCol = (Column*)sqlite3DbMallocZero(db, sizeof(Column)*nAlloc);
pNew->zName = sqliteStrDup(pTab->zName); pNew->zName = sqlite3DbStrDup(db, pTab->zName);
if( !pNew->aCol || !pNew->zName ){ if( !pNew->aCol || !pNew->zName ){
db->mallocFailed = 1;
goto exit_begin_add_column; goto exit_begin_add_column;
} }
memcpy(pNew->aCol, pTab->aCol, sizeof(Column)*pNew->nCol); memcpy(pNew->aCol, pTab->aCol, sizeof(Column)*pNew->nCol);
for(i=0; i<pNew->nCol; i++){ for(i=0; i<pNew->nCol; i++){
Column *pCol = &pNew->aCol[i]; Column *pCol = &pNew->aCol[i];
pCol->zName = sqliteStrDup(pCol->zName); pCol->zName = sqlite3DbStrDup(db, pCol->zName);
pCol->zColl = 0; pCol->zColl = 0;
pCol->zType = 0; pCol->zType = 0;
pCol->pDflt = 0; pCol->pDflt = 0;
} }
pNew->pSchema = pParse->db->aDb[iDb].pSchema; pNew->pSchema = db->aDb[iDb].pSchema;
pNew->addColOffset = pTab->addColOffset; pNew->addColOffset = pTab->addColOffset;
pNew->nRef = 1; pNew->nRef = 1;
@ -600,10 +617,10 @@ void sqlite3AlterBeginAddColumn(Parse *pParse, SrcList *pSrc){
sqlite3BeginWriteOperation(pParse, 0, iDb); sqlite3BeginWriteOperation(pParse, 0, iDb);
v = sqlite3GetVdbe(pParse); v = sqlite3GetVdbe(pParse);
if( !v ) goto exit_begin_add_column; if( !v ) goto exit_begin_add_column;
sqlite3ChangeCookie(pParse->db, v, iDb); sqlite3ChangeCookie(pParse, iDb);
exit_begin_add_column: exit_begin_add_column:
sqlite3SrcListDelete(pSrc); sqlite3SrcListDelete(db, pSrc);
return; return;
} }
#endif /* SQLITE_ALTER_TABLE */ #endif /* SQLITE_ALTER_TABLE */

155
analyze.c
View file

@ -11,7 +11,7 @@
************************************************************************* *************************************************************************
** This file contains code associated with the ANALYZE command. ** This file contains code associated with the ANALYZE command.
** **
** @(#) $Id: analyze.c,v 1.19 2007/06/20 13:37:31 drh Exp $ ** @(#) $Id: analyze.c,v 1.47 2008/12/10 16:45:51 drh Exp $
*/ */
#ifndef SQLITE_OMIT_ANALYZE #ifndef SQLITE_OMIT_ANALYZE
#include "sqliteInt.h" #include "sqliteInt.h"
@ -33,21 +33,25 @@ static void openStatTable(
sqlite3 *db = pParse->db; sqlite3 *db = pParse->db;
Db *pDb; Db *pDb;
int iRootPage; int iRootPage;
u8 createStat1 = 0;
Table *pStat; Table *pStat;
Vdbe *v = sqlite3GetVdbe(pParse); Vdbe *v = sqlite3GetVdbe(pParse);
if( v==0 ) return; if( v==0 ) return;
assert( sqlite3BtreeHoldsAllMutexes(db) );
assert( sqlite3VdbeDb(v)==db );
pDb = &db->aDb[iDb]; pDb = &db->aDb[iDb];
if( (pStat = sqlite3FindTable(db, "sqlite_stat1", pDb->zName))==0 ){ if( (pStat = sqlite3FindTable(db, "sqlite_stat1", pDb->zName))==0 ){
/* The sqlite_stat1 tables does not exist. Create it. /* The sqlite_stat1 tables does not exist. Create it.
** Note that a side-effect of the CREATE TABLE statement is to leave ** Note that a side-effect of the CREATE TABLE statement is to leave
** the rootpage of the new table on the top of the stack. This is ** the rootpage of the new table in register pParse->regRoot. This is
** important because the OpenWrite opcode below will be needing it. */ ** important because the OpenWrite opcode below will be needing it. */
sqlite3NestedParse(pParse, sqlite3NestedParse(pParse,
"CREATE TABLE %Q.sqlite_stat1(tbl,idx,stat)", "CREATE TABLE %Q.sqlite_stat1(tbl,idx,stat)",
pDb->zName pDb->zName
); );
iRootPage = 0; /* Cause rootpage to be taken from top of stack */ iRootPage = pParse->regRoot;
createStat1 = 1; /* Cause rootpage to be taken from top of stack */
}else if( zWhere ){ }else if( zWhere ){
/* The sqlite_stat1 table exists. Delete all entries associated with /* The sqlite_stat1 table exists. Delete all entries associated with
** the table zWhere. */ ** the table zWhere. */
@ -59,7 +63,7 @@ static void openStatTable(
}else{ }else{
/* The sqlite_stat1 table already exists. Delete all rows. */ /* The sqlite_stat1 table already exists. Delete all rows. */
iRootPage = pStat->tnum; iRootPage = pStat->tnum;
sqlite3VdbeAddOp(v, OP_Clear, pStat->tnum, iDb); sqlite3VdbeAddOp2(v, OP_Clear, pStat->tnum, iDb);
} }
/* Open the sqlite_stat1 table for writing. Unless it was created /* Open the sqlite_stat1 table for writing. Unless it was created
@ -67,12 +71,12 @@ static void openStatTable(
** If this vdbe did create the sqlite_stat1 table, then it must have ** If this vdbe did create the sqlite_stat1 table, then it must have
** already obtained a schema-lock, making the write-lock redundant. ** already obtained a schema-lock, making the write-lock redundant.
*/ */
if( iRootPage>0 ){ if( !createStat1 ){
sqlite3TableLock(pParse, iDb, iRootPage, 1, "sqlite_stat1"); sqlite3TableLock(pParse, iDb, iRootPage, 1, "sqlite_stat1");
} }
sqlite3VdbeAddOp(v, OP_Integer, iDb, 0); sqlite3VdbeAddOp2(v, OP_SetNumColumns, 0, 3);
sqlite3VdbeAddOp(v, OP_OpenWrite, iStatCur, iRootPage); sqlite3VdbeAddOp3(v, OP_OpenWrite, iStatCur, iRootPage, iDb);
sqlite3VdbeAddOp(v, OP_SetNumColumns, iStatCur, 3); sqlite3VdbeChangeP5(v, createStat1);
} }
/* /*
@ -82,11 +86,11 @@ static void openStatTable(
static void analyzeOneTable( static void analyzeOneTable(
Parse *pParse, /* Parser context */ Parse *pParse, /* Parser context */
Table *pTab, /* Table whose indices are to be analyzed */ Table *pTab, /* Table whose indices are to be analyzed */
int iStatCur, /* Cursor that writes to the sqlite_stat1 table */ int iStatCur, /* Index of VdbeCursor that writes the sqlite_stat1 table */
int iMem /* Available memory locations begin here */ int iMem /* Available memory locations begin here */
){ ){
Index *pIdx; /* An index to being analyzed */ Index *pIdx; /* An index to being analyzed */
int iIdxCur; /* Cursor number for index being analyzed */ int iIdxCur; /* Index of VdbeCursor for index being analyzed */
int nCol; /* Number of columns in the index */ int nCol; /* Number of columns in the index */
Vdbe *v; /* The virtual machine being built up */ Vdbe *v; /* The virtual machine being built up */
int i; /* Loop counter */ int i; /* Loop counter */
@ -100,7 +104,7 @@ static void analyzeOneTable(
/* Do no analysis for tables that have no indices */ /* Do no analysis for tables that have no indices */
return; return;
} }
assert( sqlite3BtreeHoldsAllMutexes(pParse->db) );
iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema); iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
assert( iDb>=0 ); assert( iDb>=0 );
#ifndef SQLITE_OMIT_AUTHORIZATION #ifndef SQLITE_OMIT_AUTHORIZATION
@ -116,19 +120,27 @@ static void analyzeOneTable(
iIdxCur = pParse->nTab; iIdxCur = pParse->nTab;
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
KeyInfo *pKey = sqlite3IndexKeyinfo(pParse, pIdx); KeyInfo *pKey = sqlite3IndexKeyinfo(pParse, pIdx);
int regFields; /* Register block for building records */
int regRec; /* Register holding completed record */
int regTemp; /* Temporary use register */
int regCol; /* Content of a column from the table being analyzed */
int regRowid; /* Rowid for the inserted record */
int regF2;
/* Open a cursor to the index to be analyzed /* Open a cursor to the index to be analyzed
*/ */
assert( iDb==sqlite3SchemaToIndex(pParse->db, pIdx->pSchema) ); 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 *)pKey, P3_KEYINFO_HANDOFF);
nCol = pIdx->nColumn; nCol = pIdx->nColumn;
if( iMem+nCol*2>=pParse->nMem ){ sqlite3VdbeAddOp2(v, OP_SetNumColumns, 0, nCol+1);
pParse->nMem = iMem+nCol*2+1; sqlite3VdbeAddOp4(v, OP_OpenRead, iIdxCur, pIdx->tnum, iDb,
(char *)pKey, P4_KEYINFO_HANDOFF);
VdbeComment((v, "%s", pIdx->zName));
regFields = iMem+nCol*2;
regTemp = regRowid = regCol = regFields+3;
regRec = regCol+1;
if( regRec>pParse->nMem ){
pParse->nMem = regRec;
} }
sqlite3VdbeAddOp(v, OP_SetNumColumns, iIdxCur, nCol+1);
/* Memory cells are used as follows: /* Memory cells are used as follows:
** **
@ -144,33 +156,33 @@ static void analyzeOneTable(
** are initialized to NULL. ** are initialized to NULL.
*/ */
for(i=0; i<=nCol; i++){ for(i=0; i<=nCol; i++){
sqlite3VdbeAddOp(v, OP_MemInt, 0, iMem+i); sqlite3VdbeAddOp2(v, OP_Integer, 0, iMem+i);
} }
for(i=0; i<nCol; i++){ for(i=0; i<nCol; i++){
sqlite3VdbeAddOp(v, OP_MemNull, iMem+nCol+i+1, 0); sqlite3VdbeAddOp2(v, OP_Null, 0, iMem+nCol+i+1);
} }
/* Do the analysis. /* Do the analysis.
*/ */
endOfLoop = sqlite3VdbeMakeLabel(v); endOfLoop = sqlite3VdbeMakeLabel(v);
sqlite3VdbeAddOp(v, OP_Rewind, iIdxCur, endOfLoop); sqlite3VdbeAddOp2(v, OP_Rewind, iIdxCur, endOfLoop);
topOfLoop = sqlite3VdbeCurrentAddr(v); topOfLoop = sqlite3VdbeCurrentAddr(v);
sqlite3VdbeAddOp(v, OP_MemIncr, 1, iMem); sqlite3VdbeAddOp2(v, OP_AddImm, iMem, 1);
for(i=0; i<nCol; i++){ for(i=0; i<nCol; i++){
sqlite3VdbeAddOp(v, OP_Column, iIdxCur, i); sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, i, regCol);
sqlite3VdbeAddOp(v, OP_MemLoad, iMem+nCol+i+1, 0); sqlite3VdbeAddOp3(v, OP_Ne, regCol, 0, iMem+nCol+i+1);
sqlite3VdbeAddOp(v, OP_Ne, 0x100, 0); /**** TODO: add collating sequence *****/
sqlite3VdbeChangeP5(v, SQLITE_JUMPIFNULL);
} }
sqlite3VdbeAddOp(v, OP_Goto, 0, endOfLoop); sqlite3VdbeAddOp2(v, OP_Goto, 0, endOfLoop);
for(i=0; i<nCol; i++){ for(i=0; i<nCol; i++){
addr = sqlite3VdbeAddOp(v, OP_MemIncr, 1, iMem+i+1); sqlite3VdbeJumpHere(v, topOfLoop + 2*(i + 1));
sqlite3VdbeChangeP2(v, topOfLoop + 3*i + 3, addr); sqlite3VdbeAddOp2(v, OP_AddImm, iMem+i+1, 1);
sqlite3VdbeAddOp(v, OP_Column, iIdxCur, i); sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, i, iMem+nCol+i+1);
sqlite3VdbeAddOp(v, OP_MemStore, iMem+nCol+i+1, 1);
} }
sqlite3VdbeResolveLabel(v, endOfLoop); sqlite3VdbeResolveLabel(v, endOfLoop);
sqlite3VdbeAddOp(v, OP_Next, iIdxCur, topOfLoop); sqlite3VdbeAddOp2(v, OP_Next, iIdxCur, topOfLoop);
sqlite3VdbeAddOp(v, OP_Close, iIdxCur, 0); sqlite3VdbeAddOp1(v, OP_Close, iIdxCur);
/* Store the results. /* Store the results.
** **
@ -190,29 +202,24 @@ static void analyzeOneTable(
** If K>0 then it is always the case the D>0 so division by zero ** If K>0 then it is always the case the D>0 so division by zero
** is never possible. ** is never possible.
*/ */
sqlite3VdbeAddOp(v, OP_MemLoad, iMem, 0); addr = sqlite3VdbeAddOp1(v, OP_IfNot, iMem);
addr = sqlite3VdbeAddOp(v, OP_IfNot, 0, 0); sqlite3VdbeAddOp4(v, OP_String8, 0, regFields, 0, pTab->zName, 0);
sqlite3VdbeAddOp(v, OP_NewRowid, iStatCur, 0); sqlite3VdbeAddOp4(v, OP_String8, 0, regFields+1, 0, pIdx->zName, 0);
sqlite3VdbeOp3(v, OP_String8, 0, 0, pTab->zName, 0); regF2 = regFields+2;
sqlite3VdbeOp3(v, OP_String8, 0, 0, pIdx->zName, 0); sqlite3VdbeAddOp2(v, OP_SCopy, iMem, regF2);
sqlite3VdbeAddOp(v, OP_MemLoad, iMem, 0);
sqlite3VdbeOp3(v, OP_String8, 0, 0, " ", 0);
for(i=0; i<nCol; i++){ for(i=0; i<nCol; i++){
sqlite3VdbeAddOp(v, OP_MemLoad, iMem, 0); sqlite3VdbeAddOp4(v, OP_String8, 0, regTemp, 0, " ", 0);
sqlite3VdbeAddOp(v, OP_MemLoad, iMem+i+1, 0); sqlite3VdbeAddOp3(v, OP_Concat, regTemp, regF2, regF2);
sqlite3VdbeAddOp(v, OP_Add, 0, 0); sqlite3VdbeAddOp3(v, OP_Add, iMem, iMem+i+1, regTemp);
sqlite3VdbeAddOp(v, OP_AddImm, -1, 0); sqlite3VdbeAddOp2(v, OP_AddImm, regTemp, -1);
sqlite3VdbeAddOp(v, OP_MemLoad, iMem+i+1, 0); sqlite3VdbeAddOp3(v, OP_Divide, iMem+i+1, regTemp, regTemp);
sqlite3VdbeAddOp(v, OP_Divide, 0, 0); sqlite3VdbeAddOp1(v, OP_ToInt, regTemp);
sqlite3VdbeAddOp(v, OP_ToInt, 0, 0); sqlite3VdbeAddOp3(v, OP_Concat, regTemp, regF2, regF2);
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, "aaa", 0); sqlite3VdbeAddOp4(v, OP_MakeRecord, regFields, 3, regRec, "aaa", 0);
sqlite3VdbeAddOp(v, OP_Insert, iStatCur, OPFLAG_APPEND); sqlite3VdbeAddOp2(v, OP_NewRowid, iStatCur, regRowid);
sqlite3VdbeAddOp3(v, OP_Insert, iStatCur, regRec, regRowid);
sqlite3VdbeChangeP5(v, OPFLAG_APPEND);
sqlite3VdbeJumpHere(v, addr); sqlite3VdbeJumpHere(v, addr);
} }
} }
@ -224,7 +231,7 @@ static void analyzeOneTable(
static void loadAnalysis(Parse *pParse, int iDb){ static void loadAnalysis(Parse *pParse, int iDb){
Vdbe *v = sqlite3GetVdbe(pParse); Vdbe *v = sqlite3GetVdbe(pParse);
if( v ){ if( v ){
sqlite3VdbeAddOp(v, OP_LoadAnalysis, iDb, 0); sqlite3VdbeAddOp1(v, OP_LoadAnalysis, iDb);
} }
} }
@ -241,7 +248,7 @@ static void analyzeDatabase(Parse *pParse, int iDb){
sqlite3BeginWriteOperation(pParse, 0, iDb); sqlite3BeginWriteOperation(pParse, 0, iDb);
iStatCur = pParse->nTab++; iStatCur = pParse->nTab++;
openStatTable(pParse, iDb, iStatCur, 0); openStatTable(pParse, iDb, iStatCur, 0);
iMem = pParse->nMem; iMem = pParse->nMem+1;
for(k=sqliteHashFirst(&pSchema->tblHash); k; k=sqliteHashNext(k)){ for(k=sqliteHashFirst(&pSchema->tblHash); k; k=sqliteHashNext(k)){
Table *pTab = (Table*)sqliteHashData(k); Table *pTab = (Table*)sqliteHashData(k);
analyzeOneTable(pParse, pTab, iStatCur, iMem); analyzeOneTable(pParse, pTab, iStatCur, iMem);
@ -258,11 +265,12 @@ static void analyzeTable(Parse *pParse, Table *pTab){
int iStatCur; int iStatCur;
assert( pTab!=0 ); assert( pTab!=0 );
assert( sqlite3BtreeHoldsAllMutexes(pParse->db) );
iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema); iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
sqlite3BeginWriteOperation(pParse, 0, iDb); sqlite3BeginWriteOperation(pParse, 0, iDb);
iStatCur = pParse->nTab++; iStatCur = pParse->nTab++;
openStatTable(pParse, iDb, iStatCur, pTab->zName); openStatTable(pParse, iDb, iStatCur, pTab->zName);
analyzeOneTable(pParse, pTab, iStatCur, pParse->nMem); analyzeOneTable(pParse, pTab, iStatCur, pParse->nMem+1);
loadAnalysis(pParse, iDb); loadAnalysis(pParse, iDb);
} }
@ -288,6 +296,7 @@ void sqlite3Analyze(Parse *pParse, Token *pName1, Token *pName2){
/* Read the database schema. If an error occurs, leave an error message /* Read the database schema. If an error occurs, leave an error message
** and code in pParse and return NULL. */ ** and code in pParse and return NULL. */
assert( sqlite3BtreeHoldsAllMutexes(pParse->db) );
if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){ if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){
return; return;
} }
@ -304,11 +313,13 @@ void sqlite3Analyze(Parse *pParse, Token *pName1, Token *pName2){
if( iDb>=0 ){ if( iDb>=0 ){
analyzeDatabase(pParse, iDb); analyzeDatabase(pParse, iDb);
}else{ }else{
z = sqlite3NameFromToken(pName1); z = sqlite3NameFromToken(db, pName1);
pTab = sqlite3LocateTable(pParse, z, 0); if( z ){
sqliteFree(z); pTab = sqlite3LocateTable(pParse, 0, z, 0);
if( pTab ){ sqlite3DbFree(db, z);
analyzeTable(pParse, pTab); if( pTab ){
analyzeTable(pParse, pTab);
}
} }
} }
}else{ }else{
@ -316,10 +327,10 @@ void sqlite3Analyze(Parse *pParse, Token *pName1, Token *pName2){
iDb = sqlite3TwoPartName(pParse, pName1, pName2, &pTableName); iDb = sqlite3TwoPartName(pParse, pName1, pName2, &pTableName);
if( iDb>=0 ){ if( iDb>=0 ){
zDb = db->aDb[iDb].zName; zDb = db->aDb[iDb].zName;
z = sqlite3NameFromToken(pTableName); z = sqlite3NameFromToken(db, pTableName);
if( z ){ if( z ){
pTab = sqlite3LocateTable(pParse, z, zDb); pTab = sqlite3LocateTable(pParse, 0, z, zDb);
sqliteFree(z); sqlite3DbFree(db, z);
if( pTab ){ if( pTab ){
analyzeTable(pParse, pTab); analyzeTable(pParse, pTab);
} }
@ -345,7 +356,7 @@ struct analysisInfo {
** argv[0] = name of the index ** argv[0] = name of the index
** argv[1] = results of analysis - on integer for each column ** argv[1] = results of analysis - on integer for each column
*/ */
static int analysisLoader(void *pData, int argc, char **argv, char **azNotUsed){ static int analysisLoader(void *pData, int argc, char **argv, char **NotUsed){
analysisInfo *pInfo = (analysisInfo*)pData; analysisInfo *pInfo = (analysisInfo*)pData;
Index *pIndex; Index *pIndex;
int i, c; int i, c;
@ -353,6 +364,8 @@ static int analysisLoader(void *pData, int argc, char **argv, char **azNotUsed){
const char *z; const char *z;
assert( argc==2 ); assert( argc==2 );
UNUSED_PARAMETER2(NotUsed, argc);
if( argv==0 || argv[0]==0 || argv[1]==0 ){ if( argv==0 || argv[0]==0 || argv[1]==0 ){
return 0; return 0;
} }
@ -382,6 +395,10 @@ int sqlite3AnalysisLoad(sqlite3 *db, int iDb){
char *zSql; char *zSql;
int rc; int rc;
assert( iDb>=0 && iDb<db->nDb );
assert( db->aDb[iDb].pBt!=0 );
assert( sqlite3BtreeHoldsMutex(db->aDb[iDb].pBt) );
/* Clear any prior statistics */ /* Clear any prior statistics */
for(i=sqliteHashFirst(&db->aDb[iDb].pSchema->idxHash);i;i=sqliteHashNext(i)){ for(i=sqliteHashFirst(&db->aDb[iDb].pSchema->idxHash);i;i=sqliteHashNext(i)){
Index *pIdx = sqliteHashData(i); Index *pIdx = sqliteHashData(i);
@ -397,12 +414,12 @@ int sqlite3AnalysisLoad(sqlite3 *db, int iDb){
/* Load new statistics out of the sqlite_stat1 table */ /* Load new statistics out of the sqlite_stat1 table */
zSql = sqlite3MPrintf("SELECT idx, stat FROM %Q.sqlite_stat1", zSql = sqlite3MPrintf(db, "SELECT idx, stat FROM %Q.sqlite_stat1",
sInfo.zDatabase); sInfo.zDatabase);
sqlite3SafetyOff(db); (void)sqlite3SafetyOff(db);
rc = sqlite3_exec(db, zSql, analysisLoader, &sInfo, 0); rc = sqlite3_exec(db, zSql, analysisLoader, &sInfo, 0);
sqlite3SafetyOn(db); (void)sqlite3SafetyOn(db);
sqliteFree(zSql); sqlite3DbFree(db, zSql);
return rc; return rc;
} }

141
attach.c
View file

@ -11,7 +11,7 @@
************************************************************************* *************************************************************************
** This file contains code used to implement the ATTACH and DETACH commands. ** This file contains code used to implement the ATTACH and DETACH commands.
** **
** $Id: attach.c,v 1.60 2007/05/09 20:31:30 drh Exp $ ** $Id: attach.c,v 1.81 2008/12/10 16:45:51 drh Exp $
*/ */
#include "sqliteInt.h" #include "sqliteInt.h"
@ -39,7 +39,7 @@ static int resolveAttachExpr(NameContext *pName, Expr *pExpr)
int rc = SQLITE_OK; int rc = SQLITE_OK;
if( pExpr ){ if( pExpr ){
if( pExpr->op!=TK_ID ){ if( pExpr->op!=TK_ID ){
rc = sqlite3ExprResolveNames(pName, pExpr); rc = sqlite3ResolveExprNames(pName, pExpr);
if( rc==SQLITE_OK && !sqlite3ExprIsConstant(pExpr) ){ if( rc==SQLITE_OK && !sqlite3ExprIsConstant(pExpr) ){
sqlite3ErrorMsg(pName->pParse, "invalid name: \"%T\"", &pExpr->span); sqlite3ErrorMsg(pName->pParse, "invalid name: \"%T\"", &pExpr->span);
return SQLITE_ERROR; return SQLITE_ERROR;
@ -64,17 +64,19 @@ static int resolveAttachExpr(NameContext *pName, Expr *pExpr)
*/ */
static void attachFunc( static void attachFunc(
sqlite3_context *context, sqlite3_context *context,
int argc, int NotUsed,
sqlite3_value **argv sqlite3_value **argv
){ ){
int i; int i;
int rc = 0; int rc = 0;
sqlite3 *db = sqlite3_user_data(context); sqlite3 *db = sqlite3_context_db_handle(context);
const char *zName; const char *zName;
const char *zFile; const char *zFile;
Db *aNew; Db *aNew;
char zErr[128];
char *zErrDyn = 0; char *zErrDyn = 0;
char zErr[128];
UNUSED_PARAMETER(NotUsed);
zFile = (const char *)sqlite3_value_text(argv[0]); zFile = (const char *)sqlite3_value_text(argv[0]);
zName = (const char *)sqlite3_value_text(argv[1]); zName = (const char *)sqlite3_value_text(argv[1]);
@ -87,10 +89,10 @@ static void attachFunc(
** * Transaction currently open ** * Transaction currently open
** * Specified database name already being used. ** * Specified database name already being used.
*/ */
if( db->nDb>=SQLITE_MAX_ATTACHED+2 ){ if( db->nDb>=db->aLimit[SQLITE_LIMIT_ATTACHED]+2 ){
sqlite3_snprintf( sqlite3_snprintf(
sizeof(zErr), zErr, "too many attached databases - max %d", sizeof(zErr), zErr, "too many attached databases - max %d",
SQLITE_MAX_ATTACHED db->aLimit[SQLITE_LIMIT_ATTACHED]
); );
goto attach_error; goto attach_error;
} }
@ -102,7 +104,8 @@ static void attachFunc(
for(i=0; i<db->nDb; i++){ for(i=0; i<db->nDb; i++){
char *z = db->aDb[i].zName; char *z = db->aDb[i].zName;
if( z && zName && sqlite3StrICmp(z, zName)==0 ){ if( z && zName && sqlite3StrICmp(z, zName)==0 ){
sqlite3_snprintf(sizeof(zErr), zErr, "database %s is already in use", zName); sqlite3_snprintf(sizeof(zErr), zErr,
"database %s is already in use", zName);
goto attach_error; goto attach_error;
} }
} }
@ -111,16 +114,12 @@ static void attachFunc(
** hash tables. ** hash tables.
*/ */
if( db->aDb==db->aDbStatic ){ if( db->aDb==db->aDbStatic ){
aNew = sqliteMalloc( sizeof(db->aDb[0])*3 ); aNew = sqlite3DbMallocRaw(db, sizeof(db->aDb[0])*3 );
if( aNew==0 ){ if( aNew==0 ) return;
return;
}
memcpy(aNew, db->aDb, sizeof(db->aDb[0])*2); memcpy(aNew, db->aDb, sizeof(db->aDb[0])*2);
}else{ }else{
aNew = sqliteRealloc(db->aDb, sizeof(db->aDb[0])*(db->nDb+1) ); aNew = sqlite3DbRealloc(db, db->aDb, sizeof(db->aDb[0])*(db->nDb+1) );
if( aNew==0 ){ if( aNew==0 ) return;
return;
}
} }
db->aDb = aNew; db->aDb = aNew;
aNew = &db->aDb[db->nDb++]; aNew = &db->aDb[db->nDb++];
@ -130,9 +129,12 @@ static void attachFunc(
** it to obtain the database schema. At this point the schema may ** it to obtain the database schema. At this point the schema may
** or may not be initialised. ** or may not be initialised.
*/ */
rc = sqlite3BtreeFactory(db, zFile, 0, SQLITE_DEFAULT_CACHE_SIZE, &aNew->pBt); rc = sqlite3BtreeFactory(db, zFile, 0, SQLITE_DEFAULT_CACHE_SIZE,
db->openFlags | SQLITE_OPEN_MAIN_DB,
&aNew->pBt);
if( rc==SQLITE_OK ){ if( rc==SQLITE_OK ){
aNew->pSchema = sqlite3SchemaGet(aNew->pBt); Pager *pPager;
aNew->pSchema = sqlite3SchemaGet(db, aNew->pBt);
if( !aNew->pSchema ){ if( !aNew->pSchema ){
rc = SQLITE_NOMEM; rc = SQLITE_NOMEM;
}else if( aNew->pSchema->file_format && aNew->pSchema->enc!=ENC(db) ){ }else if( aNew->pSchema->file_format && aNew->pSchema->enc!=ENC(db) ){
@ -140,9 +142,11 @@ static void attachFunc(
"attached databases must use the same text encoding as main database"); "attached databases must use the same text encoding as main database");
goto attach_error; goto attach_error;
} }
sqlite3PagerLockingMode(sqlite3BtreePager(aNew->pBt), db->dfltLockMode); pPager = sqlite3BtreePager(aNew->pBt);
sqlite3PagerLockingMode(pPager, db->dfltLockMode);
sqlite3PagerJournalMode(pPager, db->dfltJournalMode);
} }
aNew->zName = sqliteStrDup(zName); aNew->zName = sqlite3DbStrDup(db, zName);
aNew->safety_level = 3; aNew->safety_level = 3;
#if SQLITE_HAS_CODEC #if SQLITE_HAS_CODEC
@ -155,7 +159,7 @@ static void attachFunc(
switch( t ){ switch( t ){
case SQLITE_INTEGER: case SQLITE_INTEGER:
case SQLITE_FLOAT: case SQLITE_FLOAT:
zErrDyn = sqliteStrDup("Invalid key value"); zErrDyn = sqlite3DbStrDup(db, "Invalid key value");
rc = SQLITE_ERROR; rc = SQLITE_ERROR;
break; break;
@ -181,9 +185,11 @@ static void attachFunc(
** we found it. ** we found it.
*/ */
if( rc==SQLITE_OK ){ if( rc==SQLITE_OK ){
sqlite3SafetyOn(db); (void)sqlite3SafetyOn(db);
sqlite3BtreeEnterAll(db);
rc = sqlite3Init(db, &zErrDyn); rc = sqlite3Init(db, &zErrDyn);
sqlite3SafetyOff(db); sqlite3BtreeLeaveAll(db);
(void)sqlite3SafetyOff(db);
} }
if( rc ){ if( rc ){
int iDb = db->nDb - 1; int iDb = db->nDb - 1;
@ -195,8 +201,8 @@ static void attachFunc(
} }
sqlite3ResetInternalSchema(db, 0); sqlite3ResetInternalSchema(db, 0);
db->nDb = iDb; db->nDb = iDb;
if( rc==SQLITE_NOMEM ){ if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ){
sqlite3FailedMalloc(); db->mallocFailed = 1;
sqlite3_snprintf(sizeof(zErr),zErr, "out of memory"); sqlite3_snprintf(sizeof(zErr),zErr, "out of memory");
}else{ }else{
sqlite3_snprintf(sizeof(zErr),zErr, "unable to open database: %s", zFile); sqlite3_snprintf(sizeof(zErr),zErr, "unable to open database: %s", zFile);
@ -210,11 +216,12 @@ attach_error:
/* Return an error if we get here */ /* Return an error if we get here */
if( zErrDyn ){ if( zErrDyn ){
sqlite3_result_error(context, zErrDyn, -1); sqlite3_result_error(context, zErrDyn, -1);
sqliteFree(zErrDyn); sqlite3DbFree(db, zErrDyn);
}else{ }else{
zErr[sizeof(zErr)-1] = 0; zErr[sizeof(zErr)-1] = 0;
sqlite3_result_error(context, zErr, -1); sqlite3_result_error(context, zErr, -1);
} }
if( rc ) sqlite3_result_error_code(context, rc);
} }
/* /*
@ -227,15 +234,17 @@ attach_error:
*/ */
static void detachFunc( static void detachFunc(
sqlite3_context *context, sqlite3_context *context,
int argc, int NotUsed,
sqlite3_value **argv sqlite3_value **argv
){ ){
const char *zName = (const char *)sqlite3_value_text(argv[0]); const char *zName = (const char *)sqlite3_value_text(argv[0]);
sqlite3 *db = sqlite3_user_data(context); sqlite3 *db = sqlite3_context_db_handle(context);
int i; int i;
Db *pDb = 0; Db *pDb = 0;
char zErr[128]; char zErr[128];
UNUSED_PARAMETER(NotUsed);
if( zName==0 ) zName = ""; if( zName==0 ) zName = "";
for(i=0; i<db->nDb; i++){ for(i=0; i<db->nDb; i++){
pDb = &db->aDb[i]; pDb = &db->aDb[i];
@ -278,8 +287,7 @@ detach_error:
static void codeAttach( static void codeAttach(
Parse *pParse, /* The parser context */ Parse *pParse, /* The parser context */
int type, /* Either SQLITE_ATTACH or SQLITE_DETACH */ int type, /* Either SQLITE_ATTACH or SQLITE_DETACH */
const char *zFunc, /* Either "sqlite_attach" or "sqlite_detach */ FuncDef *pFunc, /* FuncDef wrapper for detachFunc() or attachFunc() */
int nFunc, /* Number of args to pass to zFunc */
Expr *pAuthArg, /* Expression to pass to authorization callback */ Expr *pAuthArg, /* Expression to pass to authorization callback */
Expr *pFilename, /* Name of database file */ Expr *pFilename, /* Name of database file */
Expr *pDbname, /* Name of the database to use internally */ Expr *pDbname, /* Name of the database to use internally */
@ -288,18 +296,18 @@ static void codeAttach(
int rc; int rc;
NameContext sName; NameContext sName;
Vdbe *v; Vdbe *v;
FuncDef *pFunc;
sqlite3* db = pParse->db; sqlite3* db = pParse->db;
int regArgs;
#ifndef SQLITE_OMIT_AUTHORIZATION #ifndef SQLITE_OMIT_AUTHORIZATION
assert( sqlite3MallocFailed() || pAuthArg ); assert( db->mallocFailed || pAuthArg );
if( pAuthArg ){ if( pAuthArg ){
char *zAuthArg = sqlite3NameFromToken(&pAuthArg->span); char *zAuthArg = sqlite3NameFromToken(db, &pAuthArg->span);
if( !zAuthArg ){ if( !zAuthArg ){
goto attach_end; goto attach_end;
} }
rc = sqlite3AuthCheck(pParse, type, zAuthArg, 0, 0); rc = sqlite3AuthCheck(pParse, type, zAuthArg, 0, 0);
sqliteFree(zAuthArg); sqlite3DbFree(db, zAuthArg);
if(rc!=SQLITE_OK ){ if(rc!=SQLITE_OK ){
goto attach_end; goto attach_end;
} }
@ -319,27 +327,29 @@ static void codeAttach(
} }
v = sqlite3GetVdbe(pParse); v = sqlite3GetVdbe(pParse);
sqlite3ExprCode(pParse, pFilename); regArgs = sqlite3GetTempRange(pParse, 4);
sqlite3ExprCode(pParse, pDbname); sqlite3ExprCode(pParse, pFilename, regArgs);
sqlite3ExprCode(pParse, pKey); sqlite3ExprCode(pParse, pDbname, regArgs+1);
sqlite3ExprCode(pParse, pKey, regArgs+2);
assert( v || sqlite3MallocFailed() ); assert( v || db->mallocFailed );
if( v ){ if( v ){
sqlite3VdbeAddOp(v, OP_Function, 0, nFunc); sqlite3VdbeAddOp3(v, OP_Function, 0, regArgs+3-pFunc->nArg, regArgs+3);
pFunc = sqlite3FindFunction(db, zFunc, strlen(zFunc), nFunc, SQLITE_UTF8,0); assert( pFunc->nArg==-1 || (pFunc->nArg&0xff)==pFunc->nArg );
sqlite3VdbeChangeP3(v, -1, (char *)pFunc, P3_FUNCDEF); sqlite3VdbeChangeP5(v, (u8)(pFunc->nArg));
sqlite3VdbeChangeP4(v, -1, (char *)pFunc, P4_FUNCDEF);
/* Code an OP_Expire. For an ATTACH statement, set P1 to true (expire this /* 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 ** statement only). For DETACH, set it to false (expire all existing
** statements). ** statements).
*/ */
sqlite3VdbeAddOp(v, OP_Expire, (type==SQLITE_ATTACH), 0); sqlite3VdbeAddOp1(v, OP_Expire, (type==SQLITE_ATTACH));
} }
attach_end: attach_end:
sqlite3ExprDelete(pFilename); sqlite3ExprDelete(db, pFilename);
sqlite3ExprDelete(pDbname); sqlite3ExprDelete(db, pDbname);
sqlite3ExprDelete(pKey); sqlite3ExprDelete(db, pKey);
} }
/* /*
@ -348,7 +358,19 @@ attach_end:
** DETACH pDbname ** DETACH pDbname
*/ */
void sqlite3Detach(Parse *pParse, Expr *pDbname){ void sqlite3Detach(Parse *pParse, Expr *pDbname){
codeAttach(pParse, SQLITE_DETACH, "sqlite_detach", 1, pDbname, 0, 0, pDbname); static FuncDef detach_func = {
1, /* nArg */
SQLITE_UTF8, /* iPrefEnc */
0, /* flags */
0, /* pUserData */
0, /* pNext */
detachFunc, /* xFunc */
0, /* xStep */
0, /* xFinalize */
"sqlite_detach", /* zName */
0 /* pHash */
};
codeAttach(pParse, SQLITE_DETACH, &detach_func, pDbname, 0, 0, pDbname);
} }
/* /*
@ -357,21 +379,22 @@ void sqlite3Detach(Parse *pParse, Expr *pDbname){
** ATTACH p AS pDbname KEY pKey ** ATTACH p AS pDbname KEY pKey
*/ */
void sqlite3Attach(Parse *pParse, Expr *p, Expr *pDbname, Expr *pKey){ void sqlite3Attach(Parse *pParse, Expr *p, Expr *pDbname, Expr *pKey){
codeAttach(pParse, SQLITE_ATTACH, "sqlite_attach", 3, p, p, pDbname, pKey); static FuncDef attach_func = {
3, /* nArg */
SQLITE_UTF8, /* iPrefEnc */
0, /* flags */
0, /* pUserData */
0, /* pNext */
attachFunc, /* xFunc */
0, /* xStep */
0, /* xFinalize */
"sqlite_attach", /* zName */
0 /* pHash */
};
codeAttach(pParse, SQLITE_ATTACH, &attach_func, p, p, pDbname, pKey);
} }
#endif /* SQLITE_OMIT_ATTACH */ #endif /* SQLITE_OMIT_ATTACH */
/*
** Register the functions sqlite_attach and sqlite_detach.
*/
void sqlite3AttachFunctions(sqlite3 *db){
#ifndef SQLITE_OMIT_ATTACH
static const int enc = SQLITE_UTF8;
sqlite3CreateFunc(db, "sqlite_attach", 3, enc, db, attachFunc, 0, 0);
sqlite3CreateFunc(db, "sqlite_detach", 1, enc, db, detachFunc, 0, 0);
#endif
}
/* /*
** Initialize a DbFixer structure. This routine must be called prior ** Initialize a DbFixer structure. This routine must be called prior
** to passing the structure to one of the sqliteFixAAAA() routines below. ** to passing the structure to one of the sqliteFixAAAA() routines below.
@ -424,7 +447,7 @@ int sqlite3FixSrcList(
zDb = pFix->zDb; zDb = pFix->zDb;
for(i=0, pItem=pList->a; i<pList->nSrc; i++, pItem++){ for(i=0, pItem=pList->a; i<pList->nSrc; i++, pItem++){
if( pItem->zDatabase==0 ){ if( pItem->zDatabase==0 ){
pItem->zDatabase = sqliteStrDup(zDb); pItem->zDatabase = sqlite3DbStrDup(pFix->pParse->db, zDb);
}else if( sqlite3StrICmp(pItem->zDatabase,zDb)!=0 ){ }else if( sqlite3StrICmp(pItem->zDatabase,zDb)!=0 ){
sqlite3ErrorMsg(pFix->pParse, sqlite3ErrorMsg(pFix->pParse,
"%s %T cannot reference objects in database %s", "%s %T cannot reference objects in database %s",

11
auth.c
View file

@ -14,7 +14,7 @@
** systems that do not need this facility may omit it by recompiling ** systems that do not need this facility may omit it by recompiling
** the library with -DSQLITE_OMIT_AUTHORIZATION=1 ** the library with -DSQLITE_OMIT_AUTHORIZATION=1
** **
** $Id: auth.c,v 1.26 2007/05/14 11:34:47 drh Exp $ ** $Id: auth.c,v 1.29 2007/09/18 15:55:07 drh Exp $
*/ */
#include "sqliteInt.h" #include "sqliteInt.h"
@ -74,9 +74,11 @@ int sqlite3_set_authorizer(
int (*xAuth)(void*,int,const char*,const char*,const char*,const char*), int (*xAuth)(void*,int,const char*,const char*,const char*,const char*),
void *pArg void *pArg
){ ){
sqlite3_mutex_enter(db->mutex);
db->xAuth = xAuth; db->xAuth = xAuth;
db->pAuthArg = pArg; db->pAuthArg = pArg;
sqlite3ExpirePreparedStatements(db); sqlite3ExpirePreparedStatements(db);
sqlite3_mutex_leave(db->mutex);
return SQLITE_OK; return SQLITE_OK;
} }
@ -103,11 +105,12 @@ static void sqliteAuthBadReturnCode(Parse *pParse, int rc){
void sqlite3AuthRead( void sqlite3AuthRead(
Parse *pParse, /* The parser context */ Parse *pParse, /* The parser context */
Expr *pExpr, /* The expression to check authorization on */ Expr *pExpr, /* The expression to check authorization on */
Schema *pSchema, /* The schema of the expression */
SrcList *pTabList /* All table that pExpr might refer to */ SrcList *pTabList /* All table that pExpr might refer to */
){ ){
sqlite3 *db = pParse->db; sqlite3 *db = pParse->db;
int rc; int rc;
Table *pTab; /* The table being read */ Table *pTab = 0; /* The table being read */
const char *zCol; /* Name of the column of the table */ const char *zCol; /* Name of the column of the table */
int iSrc; /* Index in pTabList->a[] of table being read */ int iSrc; /* Index in pTabList->a[] of table being read */
const char *zDBase; /* Name of database being accessed */ const char *zDBase; /* Name of database being accessed */
@ -116,7 +119,7 @@ void sqlite3AuthRead(
if( db->xAuth==0 ) return; if( db->xAuth==0 ) return;
if( pExpr->op!=TK_COLUMN ) return; if( pExpr->op!=TK_COLUMN ) return;
iDb = sqlite3SchemaToIndex(pParse->db, pExpr->pSchema); iDb = sqlite3SchemaToIndex(pParse->db, pSchema);
if( iDb<0 ){ if( iDb<0 ){
/* An attempt to read a column out of a subquery or other /* An attempt to read a column out of a subquery or other
** temporary table. */ ** temporary table. */
@ -133,8 +136,6 @@ void sqlite3AuthRead(
*/ */
assert( pExpr->iTable==pStack->newIdx || pExpr->iTable==pStack->oldIdx ); assert( pExpr->iTable==pStack->newIdx || pExpr->iTable==pStack->oldIdx );
pTab = pStack->pTab; pTab = pStack->pTab;
}else{
return;
} }
if( pTab==0 ) return; if( pTab==0 ) return;
if( pExpr->iColumn>=0 ){ if( pExpr->iColumn>=0 ){

386
bitvec.c Normal file
View file

@ -0,0 +1,386 @@
/*
** 2008 February 16
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
**
** May you do good and not evil.
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
*************************************************************************
** This file implements an object that represents a fixed-length
** bitmap. Bits are numbered starting with 1.
**
** A bitmap is used to record which pages of a database file have been
** journalled during a transaction, or which pages have the "dont-write"
** property. Usually only a few pages are meet either condition.
** So the bitmap is usually sparse and has low cardinality.
** But sometimes (for example when during a DROP of a large table) most
** or all of the pages in a database can get journalled. In those cases,
** the bitmap becomes dense with high cardinality. The algorithm needs
** to handle both cases well.
**
** The size of the bitmap is fixed when the object is created.
**
** All bits are clear when the bitmap is created. Individual bits
** may be set or cleared one at a time.
**
** Test operations are about 100 times more common that set operations.
** Clear operations are exceedingly rare. There are usually between
** 5 and 500 set operations per Bitvec object, though the number of sets can
** sometimes grow into tens of thousands or larger. The size of the
** Bitvec object is the number of pages in the database file at the
** start of a transaction, and is thus usually less than a few thousand,
** but can be as large as 2 billion for a really big database.
**
** @(#) $Id: bitvec.c,v 1.10 2009/01/02 21:39:39 drh Exp $
*/
#include "sqliteInt.h"
/* Size of the Bitvec structure in bytes. */
#define BITVEC_SZ 512
/* Round the union size down to the nearest pointer boundary, since that's how
** it will be aligned within the Bitvec struct. */
#define BITVEC_USIZE (((BITVEC_SZ-(3*sizeof(u32)))/sizeof(Bitvec*))*sizeof(Bitvec*))
/* Type of the array "element" for the bitmap representation.
** Should be a power of 2, and ideally, evenly divide into BITVEC_USIZE.
** Setting this to the "natural word" size of your CPU may improve
** performance. */
#define BITVEC_TELEM u8
/* Size, in bits, of the bitmap element. */
#define BITVEC_SZELEM 8
/* Number of elements in a bitmap array. */
#define BITVEC_NELEM (BITVEC_USIZE/sizeof(BITVEC_TELEM))
/* Number of bits in the bitmap array. */
#define BITVEC_NBIT (BITVEC_NELEM*BITVEC_SZELEM)
/* Number of u32 values in hash table. */
#define BITVEC_NINT (BITVEC_USIZE/sizeof(u32))
/* Maximum number of entries in hash table before
** sub-dividing and re-hashing. */
#define BITVEC_MXHASH (BITVEC_NINT/2)
/* Hashing function for the aHash representation.
** Empirical testing showed that the *37 multiplier
** (an arbitrary prime)in the hash function provided
** no fewer collisions than the no-op *1. */
#define BITVEC_HASH(X) (((X)*1)%BITVEC_NINT)
#define BITVEC_NPTR (BITVEC_USIZE/sizeof(Bitvec *))
/*
** A bitmap is an instance of the following structure.
**
** This bitmap records the existance of zero or more bits
** with values between 1 and iSize, inclusive.
**
** There are three possible representations of the bitmap.
** If iSize<=BITVEC_NBIT, then Bitvec.u.aBitmap[] is a straight
** bitmap. The least significant bit is bit 1.
**
** If iSize>BITVEC_NBIT and iDivisor==0 then Bitvec.u.aHash[] is
** a hash table that will hold up to BITVEC_MXHASH distinct values.
**
** Otherwise, the value i is redirected into one of BITVEC_NPTR
** sub-bitmaps pointed to by Bitvec.u.apSub[]. Each subbitmap
** handles up to iDivisor separate values of i. apSub[0] holds
** values between 1 and iDivisor. apSub[1] holds values between
** iDivisor+1 and 2*iDivisor. apSub[N] holds values between
** N*iDivisor+1 and (N+1)*iDivisor. Each subbitmap is normalized
** to hold deal with values between 1 and iDivisor.
*/
struct Bitvec {
u32 iSize; /* Maximum bit index. Max iSize is 4,294,967,296. */
u32 nSet; /* Number of bits that are set - only valid for aHash element */
/* Max nSet is BITVEC_NINT. For BITVEC_SZ of 512, this would be 125. */
u32 iDivisor; /* Number of bits handled by each apSub[] entry. */
/* Should >=0 for apSub element. */
/* Max iDivisor is max(u32) / BITVEC_NPTR + 1. */
/* For a BITVEC_SZ of 512, this would be 34,359,739. */
union {
BITVEC_TELEM aBitmap[BITVEC_NELEM]; /* Bitmap representation */
u32 aHash[BITVEC_NINT]; /* Hash table representation */
Bitvec *apSub[BITVEC_NPTR]; /* Recursive representation */
} u;
};
/*
** Create a new bitmap object able to handle bits between 0 and iSize,
** inclusive. Return a pointer to the new object. Return NULL if
** malloc fails.
*/
Bitvec *sqlite3BitvecCreate(u32 iSize){
Bitvec *p;
assert( sizeof(*p)==BITVEC_SZ );
p = sqlite3MallocZero( sizeof(*p) );
if( p ){
p->iSize = iSize;
}
return p;
}
/*
** Check to see if the i-th bit is set. Return true or false.
** If p is NULL (if the bitmap has not been created) or if
** i is out of range, then return false.
*/
int sqlite3BitvecTest(Bitvec *p, u32 i){
if( p==0 ) return 0;
if( i>p->iSize || i==0 ) return 0;
i--;
while( p->iDivisor ){
u32 bin = i/p->iDivisor;
i = i%p->iDivisor;
p = p->u.apSub[bin];
if (!p) {
return 0;
}
}
if( p->iSize<=BITVEC_NBIT ){
return (p->u.aBitmap[i/BITVEC_SZELEM] & (1<<(i&(BITVEC_SZELEM-1))))!=0;
} else{
u32 h = BITVEC_HASH(i++);
while( p->u.aHash[h] ){
if( p->u.aHash[h]==i ) return 1;
h++;
if( h>=BITVEC_NINT ) h = 0;
}
return 0;
}
}
/*
** Set the i-th bit. Return 0 on success and an error code if
** anything goes wrong.
**
** This routine might cause sub-bitmaps to be allocated. Failing
** to get the memory needed to hold the sub-bitmap is the only
** that can go wrong with an insert, assuming p and i are valid.
**
** The calling function must ensure that p is a valid Bitvec object
** and that the value for "i" is within range of the Bitvec object.
** Otherwise the behavior is undefined.
*/
int sqlite3BitvecSet(Bitvec *p, u32 i){
u32 h;
assert( p!=0 );
assert( i>0 );
assert( i<=p->iSize );
i--;
while((p->iSize > BITVEC_NBIT) && p->iDivisor) {
u32 bin = i/p->iDivisor;
i = i%p->iDivisor;
if( p->u.apSub[bin]==0 ){
p->u.apSub[bin] = sqlite3BitvecCreate( p->iDivisor );
if( p->u.apSub[bin]==0 ) return SQLITE_NOMEM;
}
p = p->u.apSub[bin];
}
if( p->iSize<=BITVEC_NBIT ){
p->u.aBitmap[i/BITVEC_SZELEM] |= 1 << (i&(BITVEC_SZELEM-1));
return SQLITE_OK;
}
h = BITVEC_HASH(i++);
/* if there wasn't a hash collision, and this doesn't */
/* completely fill the hash, then just add it without */
/* worring about sub-dividing and re-hashing. */
if( !p->u.aHash[h] ){
if (p->nSet<(BITVEC_NINT-1)) {
goto bitvec_set_end;
} else {
goto bitvec_set_rehash;
}
}
/* there was a collision, check to see if it's already */
/* in hash, if not, try to find a spot for it */
do {
if( p->u.aHash[h]==i ) return SQLITE_OK;
h++;
if( h>=BITVEC_NINT ) h = 0;
} while( p->u.aHash[h] );
/* we didn't find it in the hash. h points to the first */
/* available free spot. check to see if this is going to */
/* make our hash too "full". */
bitvec_set_rehash:
if( p->nSet>=BITVEC_MXHASH ){
unsigned int j;
int rc;
u32 aiValues[BITVEC_NINT];
memcpy(aiValues, p->u.aHash, sizeof(aiValues));
memset(p->u.apSub, 0, sizeof(aiValues));
p->iDivisor = (p->iSize + BITVEC_NPTR - 1)/BITVEC_NPTR;
rc = sqlite3BitvecSet(p, i);
for(j=0; j<BITVEC_NINT; j++){
if( aiValues[j] ) rc |= sqlite3BitvecSet(p, aiValues[j]);
}
return rc;
}
bitvec_set_end:
p->nSet++;
p->u.aHash[h] = i;
return SQLITE_OK;
}
/*
** Clear the i-th bit.
*/
void sqlite3BitvecClear(Bitvec *p, u32 i){
assert( p!=0 );
assert( i>0 );
i--;
while( p->iDivisor ){
u32 bin = i/p->iDivisor;
i = i%p->iDivisor;
p = p->u.apSub[bin];
if (!p) {
return;
}
}
if( p->iSize<=BITVEC_NBIT ){
p->u.aBitmap[i/BITVEC_SZELEM] &= ~(1 << (i&(BITVEC_SZELEM-1)));
}else{
unsigned int j;
u32 aiValues[BITVEC_NINT];
memcpy(aiValues, p->u.aHash, sizeof(aiValues));
memset(p->u.aHash, 0, sizeof(aiValues));
p->nSet = 0;
for(j=0; j<BITVEC_NINT; j++){
if( aiValues[j] && aiValues[j]!=(i+1) ){
u32 h = BITVEC_HASH(aiValues[j]-1);
p->nSet++;
while( p->u.aHash[h] ){
h++;
if( h>=BITVEC_NINT ) h = 0;
}
p->u.aHash[h] = aiValues[j];
}
}
}
}
/*
** Destroy a bitmap object. Reclaim all memory used.
*/
void sqlite3BitvecDestroy(Bitvec *p){
if( p==0 ) return;
if( p->iDivisor ){
unsigned int i;
for(i=0; i<BITVEC_NPTR; i++){
sqlite3BitvecDestroy(p->u.apSub[i]);
}
}
sqlite3_free(p);
}
#ifndef SQLITE_OMIT_BUILTIN_TEST
/*
** Let V[] be an array of unsigned characters sufficient to hold
** up to N bits. Let I be an integer between 0 and N. 0<=I<N.
** Then the following macros can be used to set, clear, or test
** individual bits within V.
*/
#define SETBIT(V,I) V[I>>3] |= (1<<(I&7))
#define CLEARBIT(V,I) V[I>>3] &= ~(1<<(I&7))
#define TESTBIT(V,I) (V[I>>3]&(1<<(I&7)))!=0
/*
** This routine runs an extensive test of the Bitvec code.
**
** The input is an array of integers that acts as a program
** to test the Bitvec. The integers are opcodes followed
** by 0, 1, or 3 operands, depending on the opcode. Another
** opcode follows immediately after the last operand.
**
** There are 6 opcodes numbered from 0 through 5. 0 is the
** "halt" opcode and causes the test to end.
**
** 0 Halt and return the number of errors
** 1 N S X Set N bits beginning with S and incrementing by X
** 2 N S X Clear N bits beginning with S and incrementing by X
** 3 N Set N randomly chosen bits
** 4 N Clear N randomly chosen bits
** 5 N S X Set N bits from S increment X in array only, not in bitvec
**
** The opcodes 1 through 4 perform set and clear operations are performed
** on both a Bitvec object and on a linear array of bits obtained from malloc.
** Opcode 5 works on the linear array only, not on the Bitvec.
** Opcode 5 is used to deliberately induce a fault in order to
** confirm that error detection works.
**
** At the conclusion of the test the linear array is compared
** against the Bitvec object. If there are any differences,
** an error is returned. If they are the same, zero is returned.
**
** If a memory allocation error occurs, return -1.
*/
int sqlite3BitvecBuiltinTest(int sz, int *aOp){
Bitvec *pBitvec = 0;
unsigned char *pV = 0;
int rc = -1;
int i, nx, pc, op;
/* Allocate the Bitvec to be tested and a linear array of
** bits to act as the reference */
pBitvec = sqlite3BitvecCreate( sz );
pV = sqlite3_malloc( (sz+7)/8 + 1 );
if( pBitvec==0 || pV==0 ) goto bitvec_end;
memset(pV, 0, (sz+7)/8 + 1);
/* Run the program */
pc = 0;
while( (op = aOp[pc])!=0 ){
switch( op ){
case 1:
case 2:
case 5: {
nx = 4;
i = aOp[pc+2] - 1;
aOp[pc+2] += aOp[pc+3];
break;
}
case 3:
case 4:
default: {
nx = 2;
sqlite3_randomness(sizeof(i), &i);
break;
}
}
if( (--aOp[pc+1]) > 0 ) nx = 0;
pc += nx;
i = (i & 0x7fffffff)%sz;
if( (op & 1)!=0 ){
SETBIT(pV, (i+1));
if( op!=5 ){
if( sqlite3BitvecSet(pBitvec, i+1) ) goto bitvec_end;
}
}else{
CLEARBIT(pV, (i+1));
sqlite3BitvecClear(pBitvec, i+1);
}
}
/* Test to make sure the linear array exactly matches the
** Bitvec object. Start with the assumption that they do
** match (rc==0). Change rc to non-zero if a discrepancy
** is found.
*/
rc = sqlite3BitvecTest(0,0) + sqlite3BitvecTest(pBitvec, sz+1)
+ sqlite3BitvecTest(pBitvec, 0);
for(i=1; i<=sz; i++){
if( (TESTBIT(pV,i))!=sqlite3BitvecTest(pBitvec,i) ){
rc = i;
break;
}
}
/* Free allocated structure */
bitvec_end:
sqlite3_free(pV);
sqlite3BitvecDestroy(pBitvec);
return rc;
}
#endif /* SQLITE_OMIT_BUILTIN_TEST */

315
btmutex.c Normal file
View file

@ -0,0 +1,315 @@
/*
** 2007 August 27
**
** 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.
**
*************************************************************************
**
** $Id: btmutex.c,v 1.12 2008/11/17 19:18:55 danielk1977 Exp $
**
** This file contains code used to implement mutexes on Btree objects.
** This code really belongs in btree.c. But btree.c is getting too
** big and we want to break it down some. This packaged seemed like
** a good breakout.
*/
#include "btreeInt.h"
#if SQLITE_THREADSAFE && !defined(SQLITE_OMIT_SHARED_CACHE)
/*
** Enter a mutex on the given BTree object.
**
** If the object is not sharable, then no mutex is ever required
** and this routine is a no-op. The underlying mutex is non-recursive.
** But we keep a reference count in Btree.wantToLock so the behavior
** of this interface is recursive.
**
** To avoid deadlocks, multiple Btrees are locked in the same order
** by all database connections. The p->pNext is a list of other
** Btrees belonging to the same database connection as the p Btree
** which need to be locked after p. If we cannot get a lock on
** p, then first unlock all of the others on p->pNext, then wait
** for the lock to become available on p, then relock all of the
** subsequent Btrees that desire a lock.
*/
void sqlite3BtreeEnter(Btree *p){
Btree *pLater;
/* Some basic sanity checking on the Btree. The list of Btrees
** connected by pNext and pPrev should be in sorted order by
** Btree.pBt value. All elements of the list should belong to
** the same connection. Only shared Btrees are on the list. */
assert( p->pNext==0 || p->pNext->pBt>p->pBt );
assert( p->pPrev==0 || p->pPrev->pBt<p->pBt );
assert( p->pNext==0 || p->pNext->db==p->db );
assert( p->pPrev==0 || p->pPrev->db==p->db );
assert( p->sharable || (p->pNext==0 && p->pPrev==0) );
/* Check for locking consistency */
assert( !p->locked || p->wantToLock>0 );
assert( p->sharable || p->wantToLock==0 );
/* We should already hold a lock on the database connection */
assert( sqlite3_mutex_held(p->db->mutex) );
if( !p->sharable ) return;
p->wantToLock++;
if( p->locked ) return;
/* In most cases, we should be able to acquire the lock we
** want without having to go throught the ascending lock
** procedure that follows. Just be sure not to block.
*/
if( sqlite3_mutex_try(p->pBt->mutex)==SQLITE_OK ){
p->locked = 1;
return;
}
/* To avoid deadlock, first release all locks with a larger
** BtShared address. Then acquire our lock. Then reacquire
** the other BtShared locks that we used to hold in ascending
** order.
*/
for(pLater=p->pNext; pLater; pLater=pLater->pNext){
assert( pLater->sharable );
assert( pLater->pNext==0 || pLater->pNext->pBt>pLater->pBt );
assert( !pLater->locked || pLater->wantToLock>0 );
if( pLater->locked ){
sqlite3_mutex_leave(pLater->pBt->mutex);
pLater->locked = 0;
}
}
sqlite3_mutex_enter(p->pBt->mutex);
p->locked = 1;
for(pLater=p->pNext; pLater; pLater=pLater->pNext){
if( pLater->wantToLock ){
sqlite3_mutex_enter(pLater->pBt->mutex);
pLater->locked = 1;
}
}
}
/*
** Exit the recursive mutex on a Btree.
*/
void sqlite3BtreeLeave(Btree *p){
if( p->sharable ){
assert( p->wantToLock>0 );
p->wantToLock--;
if( p->wantToLock==0 ){
assert( p->locked );
sqlite3_mutex_leave(p->pBt->mutex);
p->locked = 0;
}
}
}
#ifndef NDEBUG
/*
** Return true if the BtShared mutex is held on the btree.
**
** This routine makes no determination one why or another if the
** database connection mutex is held.
**
** This routine is used only from within assert() statements.
*/
int sqlite3BtreeHoldsMutex(Btree *p){
return (p->sharable==0 ||
(p->locked && p->wantToLock && sqlite3_mutex_held(p->pBt->mutex)));
}
#endif
#ifndef SQLITE_OMIT_INCRBLOB
/*
** Enter and leave a mutex on a Btree given a cursor owned by that
** Btree. These entry points are used by incremental I/O and can be
** omitted if that module is not used.
*/
void sqlite3BtreeEnterCursor(BtCursor *pCur){
sqlite3BtreeEnter(pCur->pBtree);
}
void sqlite3BtreeLeaveCursor(BtCursor *pCur){
sqlite3BtreeLeave(pCur->pBtree);
}
#endif /* SQLITE_OMIT_INCRBLOB */
/*
** Enter the mutex on every Btree associated with a database
** connection. This is needed (for example) prior to parsing
** a statement since we will be comparing table and column names
** against all schemas and we do not want those schemas being
** reset out from under us.
**
** There is a corresponding leave-all procedures.
**
** Enter the mutexes in accending order by BtShared pointer address
** to avoid the possibility of deadlock when two threads with
** two or more btrees in common both try to lock all their btrees
** at the same instant.
*/
void sqlite3BtreeEnterAll(sqlite3 *db){
int i;
Btree *p, *pLater;
assert( sqlite3_mutex_held(db->mutex) );
for(i=0; i<db->nDb; i++){
p = db->aDb[i].pBt;
if( p && p->sharable ){
p->wantToLock++;
if( !p->locked ){
assert( p->wantToLock==1 );
while( p->pPrev ) p = p->pPrev;
while( p->locked && p->pNext ) p = p->pNext;
for(pLater = p->pNext; pLater; pLater=pLater->pNext){
if( pLater->locked ){
sqlite3_mutex_leave(pLater->pBt->mutex);
pLater->locked = 0;
}
}
while( p ){
sqlite3_mutex_enter(p->pBt->mutex);
p->locked++;
p = p->pNext;
}
}
}
}
}
void sqlite3BtreeLeaveAll(sqlite3 *db){
int i;
Btree *p;
assert( sqlite3_mutex_held(db->mutex) );
for(i=0; i<db->nDb; i++){
p = db->aDb[i].pBt;
if( p && p->sharable ){
assert( p->wantToLock>0 );
p->wantToLock--;
if( p->wantToLock==0 ){
assert( p->locked );
sqlite3_mutex_leave(p->pBt->mutex);
p->locked = 0;
}
}
}
}
#ifndef NDEBUG
/*
** Return true if the current thread holds the database connection
** mutex and all required BtShared mutexes.
**
** This routine is used inside assert() statements only.
*/
int sqlite3BtreeHoldsAllMutexes(sqlite3 *db){
int i;
if( !sqlite3_mutex_held(db->mutex) ){
return 0;
}
for(i=0; i<db->nDb; i++){
Btree *p;
p = db->aDb[i].pBt;
if( p && p->sharable &&
(p->wantToLock==0 || !sqlite3_mutex_held(p->pBt->mutex)) ){
return 0;
}
}
return 1;
}
#endif /* NDEBUG */
/*
** Add a new Btree pointer to a BtreeMutexArray.
** if the pointer can possibly be shared with
** another database connection.
**
** The pointers are kept in sorted order by pBtree->pBt. That
** way when we go to enter all the mutexes, we can enter them
** in order without every having to backup and retry and without
** worrying about deadlock.
**
** The number of shared btrees will always be small (usually 0 or 1)
** so an insertion sort is an adequate algorithm here.
*/
void sqlite3BtreeMutexArrayInsert(BtreeMutexArray *pArray, Btree *pBtree){
int i, j;
BtShared *pBt;
if( pBtree==0 || pBtree->sharable==0 ) return;
#ifndef NDEBUG
{
for(i=0; i<pArray->nMutex; i++){
assert( pArray->aBtree[i]!=pBtree );
}
}
#endif
assert( pArray->nMutex>=0 );
assert( pArray->nMutex<ArraySize(pArray->aBtree)-1 );
pBt = pBtree->pBt;
for(i=0; i<pArray->nMutex; i++){
assert( pArray->aBtree[i]!=pBtree );
if( pArray->aBtree[i]->pBt>pBt ){
for(j=pArray->nMutex; j>i; j--){
pArray->aBtree[j] = pArray->aBtree[j-1];
}
pArray->aBtree[i] = pBtree;
pArray->nMutex++;
return;
}
}
pArray->aBtree[pArray->nMutex++] = pBtree;
}
/*
** Enter the mutex of every btree in the array. This routine is
** called at the beginning of sqlite3VdbeExec(). The mutexes are
** exited at the end of the same function.
*/
void sqlite3BtreeMutexArrayEnter(BtreeMutexArray *pArray){
int i;
for(i=0; i<pArray->nMutex; i++){
Btree *p = pArray->aBtree[i];
/* Some basic sanity checking */
assert( i==0 || pArray->aBtree[i-1]->pBt<p->pBt );
assert( !p->locked || p->wantToLock>0 );
/* We should already hold a lock on the database connection */
assert( sqlite3_mutex_held(p->db->mutex) );
p->wantToLock++;
if( !p->locked && p->sharable ){
sqlite3_mutex_enter(p->pBt->mutex);
p->locked = 1;
}
}
}
/*
** Leave the mutex of every btree in the group.
*/
void sqlite3BtreeMutexArrayLeave(BtreeMutexArray *pArray){
int i;
for(i=0; i<pArray->nMutex; i++){
Btree *p = pArray->aBtree[i];
/* Some basic sanity checking */
assert( i==0 || pArray->aBtree[i-1]->pBt<p->pBt );
assert( p->locked || !p->sharable );
assert( p->wantToLock>0 );
/* We should already hold a lock on the database connection */
assert( sqlite3_mutex_held(p->db->mutex) );
p->wantToLock--;
if( p->wantToLock==0 && p->locked ){
sqlite3_mutex_leave(p->pBt->mutex);
p->locked = 0;
}
}
}
#endif /* SQLITE_THREADSAFE && !SQLITE_OMIT_SHARED_CACHE */

3846
btree.c

File diff suppressed because it is too large Load diff

94
btree.h
View file

@ -13,7 +13,7 @@
** subsystem. See comments in the source code for a detailed description ** subsystem. See comments in the source code for a detailed description
** of what each interface routine does. ** of what each interface routine does.
** **
** @(#) $Id: btree.h,v 1.82 2007/05/08 21:45:27 drh Exp $ ** @(#) $Id: btree.h,v 1.106 2008/12/17 17:30:26 danielk1977 Exp $
*/ */
#ifndef _BTREE_H_ #ifndef _BTREE_H_
#define _BTREE_H_ #define _BTREE_H_
@ -41,13 +41,26 @@
typedef struct Btree Btree; typedef struct Btree Btree;
typedef struct BtCursor BtCursor; typedef struct BtCursor BtCursor;
typedef struct BtShared BtShared; typedef struct BtShared BtShared;
typedef struct BtreeMutexArray BtreeMutexArray;
/*
** This structure records all of the Btrees that need to hold
** a mutex before we enter sqlite3VdbeExec(). The Btrees are
** are placed in aBtree[] in order of aBtree[]->pBt. That way,
** we can always lock and unlock them all quickly.
*/
struct BtreeMutexArray {
int nMutex;
Btree *aBtree[SQLITE_MAX_ATTACHED+1];
};
int sqlite3BtreeOpen( int sqlite3BtreeOpen(
const char *zFilename, /* Name of database file to open */ const char *zFilename, /* Name of database file to open */
sqlite3 *db, /* Associated database connection */ sqlite3 *db, /* Associated database connection */
Btree **, /* Return open Btree* here */ Btree **, /* Return open Btree* here */
int flags /* Flags */ int flags, /* Flags */
int vfsFlags /* Flags passed through to VFS open */
); );
/* The flags parameter to sqlite3BtreeOpen can be the bitwise or of the /* The flags parameter to sqlite3BtreeOpen can be the bitwise or of the
@ -59,9 +72,11 @@ int sqlite3BtreeOpen(
#define BTREE_OMIT_JOURNAL 1 /* Do not use journal. No argument */ #define BTREE_OMIT_JOURNAL 1 /* Do not use journal. No argument */
#define BTREE_NO_READLOCK 2 /* Omit readlocks on readonly files */ #define BTREE_NO_READLOCK 2 /* Omit readlocks on readonly files */
#define BTREE_MEMORY 4 /* In-memory DB. No argument */ #define BTREE_MEMORY 4 /* In-memory DB. No argument */
#define BTREE_READONLY 8 /* Open the database in read-only mode */
#define BTREE_READWRITE 16 /* Open for both reading and writing */
#define BTREE_CREATE 32 /* Create the database if it does not exist */
int sqlite3BtreeClose(Btree*); int sqlite3BtreeClose(Btree*);
int sqlite3BtreeSetBusyHandler(Btree*,BusyHandler*);
int sqlite3BtreeSetCacheSize(Btree*,int); int sqlite3BtreeSetCacheSize(Btree*,int);
int sqlite3BtreeSetSafetyLevel(Btree*,int,int); int sqlite3BtreeSetSafetyLevel(Btree*,int,int);
int sqlite3BtreeSyncDisabled(Btree*); int sqlite3BtreeSyncDisabled(Btree*);
@ -86,6 +101,7 @@ int sqlite3BtreeIsInReadTrans(Btree*);
void *sqlite3BtreeSchema(Btree *, int, void(*)(void *)); void *sqlite3BtreeSchema(Btree *, int, void(*)(void *));
int sqlite3BtreeSchemaLocked(Btree *); int sqlite3BtreeSchemaLocked(Btree *);
int sqlite3BtreeLockTable(Btree *, int, u8); int sqlite3BtreeLockTable(Btree *, int, u8);
int sqlite3BtreeSavepoint(Btree *, int, int);
const char *sqlite3BtreeGetFilename(Btree *); const char *sqlite3BtreeGetFilename(Btree *);
const char *sqlite3BtreeGetDirname(Btree *); const char *sqlite3BtreeGetDirname(Btree *);
@ -102,21 +118,36 @@ int sqlite3BtreeIncrVacuum(Btree *);
#define BTREE_LEAFDATA 4 /* Data stored in leaves only. Implies INTKEY */ #define BTREE_LEAFDATA 4 /* Data stored in leaves only. Implies INTKEY */
int sqlite3BtreeDropTable(Btree*, int, int*); int sqlite3BtreeDropTable(Btree*, int, int*);
int sqlite3BtreeClearTable(Btree*, int); int sqlite3BtreeClearTable(Btree*, int, int*);
int sqlite3BtreeGetMeta(Btree*, int idx, u32 *pValue); int sqlite3BtreeGetMeta(Btree*, int idx, u32 *pValue);
int sqlite3BtreeUpdateMeta(Btree*, int idx, u32 value); int sqlite3BtreeUpdateMeta(Btree*, int idx, u32 value);
void sqlite3BtreeTripAllCursors(Btree*, int);
int sqlite3BtreeCursor( int sqlite3BtreeCursor(
Btree*, /* BTree containing table to open */ Btree*, /* BTree containing table to open */
int iTable, /* Index of root page */ int iTable, /* Index of root page */
int wrFlag, /* 1 for writing. 0 for read-only */ int wrFlag, /* 1 for writing. 0 for read-only */
int(*)(void*,int,const void*,int,const void*), /* Key comparison function */ struct KeyInfo*, /* First argument to compare function */
void*, /* First argument to compare function */ BtCursor *pCursor /* Space to write cursor structure */
BtCursor **ppCursor /* Returned cursor */
); );
int sqlite3BtreeCursorSize(void);
int sqlite3BtreeCloseCursor(BtCursor*); int sqlite3BtreeCloseCursor(BtCursor*);
int sqlite3BtreeMoveto(BtCursor*,const void *pKey,i64 nKey,int bias,int *pRes); int sqlite3BtreeMoveto(
BtCursor*,
const void *pKey,
i64 nKey,
int bias,
int *pRes
);
int sqlite3BtreeMovetoUnpacked(
BtCursor*,
UnpackedRecord *pUnKey,
i64 intKey,
int bias,
int *pRes
);
int sqlite3BtreeCursorHasMoved(BtCursor*, int*);
int sqlite3BtreeDelete(BtCursor*); int sqlite3BtreeDelete(BtCursor*);
int sqlite3BtreeInsert(BtCursor*, const void *pKey, i64 nKey, int sqlite3BtreeInsert(BtCursor*, const void *pKey, i64 nKey,
const void *pData, int nData, const void *pData, int nData,
@ -129,6 +160,7 @@ int sqlite3BtreeFlags(BtCursor*);
int sqlite3BtreePrevious(BtCursor*, int *pRes); int sqlite3BtreePrevious(BtCursor*, int *pRes);
int sqlite3BtreeKeySize(BtCursor*, i64 *pSize); int sqlite3BtreeKeySize(BtCursor*, i64 *pSize);
int sqlite3BtreeKey(BtCursor*, u32 offset, u32 amt, void*); int sqlite3BtreeKey(BtCursor*, u32 offset, u32 amt, void*);
sqlite3 *sqlite3BtreeCursorDb(const BtCursor*);
const void *sqlite3BtreeKeyFetch(BtCursor*, int *pAmt); const void *sqlite3BtreeKeyFetch(BtCursor*, int *pAmt);
const void *sqlite3BtreeDataFetch(BtCursor*, int *pAmt); const void *sqlite3BtreeDataFetch(BtCursor*, int *pAmt);
int sqlite3BtreeDataSize(BtCursor*, u32 *pSize); int sqlite3BtreeDataSize(BtCursor*, u32 *pSize);
@ -139,11 +171,55 @@ struct Pager *sqlite3BtreePager(Btree*);
int sqlite3BtreePutData(BtCursor*, u32 offset, u32 amt, void*); int sqlite3BtreePutData(BtCursor*, u32 offset, u32 amt, void*);
void sqlite3BtreeCacheOverflow(BtCursor *); void sqlite3BtreeCacheOverflow(BtCursor *);
void sqlite3BtreeClearCursor(BtCursor *);
#ifdef SQLITE_TEST #ifdef SQLITE_TEST
int sqlite3BtreeCursorInfo(BtCursor*, int*, int); int sqlite3BtreeCursorInfo(BtCursor*, int*, int);
void sqlite3BtreeCursorList(Btree*); void sqlite3BtreeCursorList(Btree*);
int sqlite3BtreePageDump(Btree*, int, int recursive);
#endif #endif
/*
** If we are not using shared cache, then there is no need to
** use mutexes to access the BtShared structures. So make the
** Enter and Leave procedures no-ops.
*/
#if !defined(SQLITE_OMIT_SHARED_CACHE) && SQLITE_THREADSAFE
void sqlite3BtreeEnter(Btree*);
void sqlite3BtreeLeave(Btree*);
#ifndef NDEBUG
/* This routine is used inside assert() statements only. */
int sqlite3BtreeHoldsMutex(Btree*);
#endif
void sqlite3BtreeEnterCursor(BtCursor*);
void sqlite3BtreeLeaveCursor(BtCursor*);
void sqlite3BtreeEnterAll(sqlite3*);
void sqlite3BtreeLeaveAll(sqlite3*);
#ifndef NDEBUG
/* This routine is used inside assert() statements only. */
int sqlite3BtreeHoldsAllMutexes(sqlite3*);
#endif
void sqlite3BtreeMutexArrayEnter(BtreeMutexArray*);
void sqlite3BtreeMutexArrayLeave(BtreeMutexArray*);
void sqlite3BtreeMutexArrayInsert(BtreeMutexArray*, Btree*);
#else
# define sqlite3BtreeEnter(X)
# define sqlite3BtreeLeave(X)
#ifndef NDEBUG
/* This routine is used inside assert() statements only. */
# define sqlite3BtreeHoldsMutex(X) 1
#endif
# define sqlite3BtreeEnterCursor(X)
# define sqlite3BtreeLeaveCursor(X)
# define sqlite3BtreeEnterAll(X)
# define sqlite3BtreeLeaveAll(X)
#ifndef NDEBUG
/* This routine is used inside assert() statements only. */
# define sqlite3BtreeHoldsAllMutexes(X) 1
#endif
# define sqlite3BtreeMutexArrayEnter(X)
# define sqlite3BtreeMutexArrayLeave(X)
# define sqlite3BtreeMutexArrayInsert(X,Y)
#endif
#endif /* _BTREE_H_ */ #endif /* _BTREE_H_ */

View file

@ -9,7 +9,7 @@
** May you share freely, never taking more than you give. ** May you share freely, never taking more than you give.
** **
************************************************************************* *************************************************************************
** $Id: btreeInt.h,v 1.5 2007/06/15 12:06:59 drh Exp $ ** $Id: btreeInt.h,v 1.38 2008/12/27 15:23:13 danielk1977 Exp $
** **
** This file implements a external (disk-based) database using BTrees. ** This file implements a external (disk-based) database using BTrees.
** For a detailed discussion of BTrees, refer to ** For a detailed discussion of BTrees, refer to
@ -221,10 +221,11 @@
#define MX_CELL_SIZE(pBt) (pBt->pageSize-8) #define MX_CELL_SIZE(pBt) (pBt->pageSize-8)
/* The maximum number of cells on a single page of the database. This /* The maximum number of cells on a single page of the database. This
** assumes a minimum cell size of 3 bytes. Such small cells will be ** assumes a minimum cell size of 6 bytes (4 bytes for the cell itself
** exceedingly rare, but they are possible. ** plus 2 bytes for the index to the cell in the page header). Such
** small cells will be rare, but they are possible.
*/ */
#define MX_CELL(pBt) ((pBt->pageSize-8)/3) #define MX_CELL(pBt) ((pBt->pageSize-8)/6)
/* Forward declarations */ /* Forward declarations */
typedef struct MemPage MemPage; typedef struct MemPage MemPage;
@ -248,7 +249,7 @@ typedef struct BtLock BtLock;
/* /*
** Page type flags. An ORed combination of these flags appear as the ** Page type flags. An ORed combination of these flags appear as the
** first byte of every BTree page. ** first byte of on-disk image of every BTree page.
*/ */
#define PTF_INTKEY 0x01 #define PTF_INTKEY 0x01
#define PTF_ZERODATA 0x02 #define PTF_ZERODATA 0x02
@ -264,33 +265,32 @@ typedef struct BtLock BtLock;
** walk up the BTree from any leaf to the root. Care must be taken to ** walk up the BTree from any leaf to the root. Care must be taken to
** unref() the parent page pointer when this page is no longer referenced. ** unref() the parent page pointer when this page is no longer referenced.
** The pageDestructor() routine handles that chore. ** The pageDestructor() routine handles that chore.
**
** Access to all fields of this structure is controlled by the mutex
** stored in MemPage.pBt->mutex.
*/ */
struct MemPage { struct MemPage {
u8 isInit; /* True if previously initialized. MUST BE FIRST! */ u8 isInit; /* True if previously initialized. MUST BE FIRST! */
u8 idxShift; /* True if Cell indices have changed */
u8 nOverflow; /* Number of overflow cell bodies in aCell[] */ u8 nOverflow; /* Number of overflow cell bodies in aCell[] */
u8 intKey; /* True if intkey flag is set */ u8 intKey; /* True if intkey flag is set */
u8 leaf; /* True if leaf flag is set */ u8 leaf; /* True if leaf flag is set */
u8 zeroData; /* True if table stores keys only */
u8 leafData; /* True if tables stores data on leaves only */
u8 hasData; /* True if this page stores data */ u8 hasData; /* True if this page stores data */
u8 hdrOffset; /* 100 for page 1. 0 otherwise */ u8 hdrOffset; /* 100 for page 1. 0 otherwise */
u8 childPtrSize; /* 0 if leaf==1. 4 if leaf==0 */ u8 childPtrSize; /* 0 if leaf==1. 4 if leaf==0 */
u16 maxLocal; /* Copy of Btree.maxLocal or Btree.maxLeaf */ u16 maxLocal; /* Copy of BtShared.maxLocal or BtShared.maxLeaf */
u16 minLocal; /* Copy of Btree.minLocal or Btree.minLeaf */ u16 minLocal; /* Copy of BtShared.minLocal or BtShared.minLeaf */
u16 cellOffset; /* Index in aData of first cell pointer */ u16 cellOffset; /* Index in aData of first cell pointer */
u16 idxParent; /* Index in parent of this node */
u16 nFree; /* Number of free bytes on the page */ u16 nFree; /* Number of free bytes on the page */
u16 nCell; /* Number of cells on this page, local and ovfl */ u16 nCell; /* Number of cells on this page, local and ovfl */
u16 maskPage; /* Mask for page offset */
struct _OvflCell { /* Cells that will not fit on aData[] */ struct _OvflCell { /* Cells that will not fit on aData[] */
u8 *pCell; /* Pointers to the body of the overflow cell */ u8 *pCell; /* Pointers to the body of the overflow cell */
u16 idx; /* Insert this cell before idx-th non-overflow cell */ u16 idx; /* Insert this cell before idx-th non-overflow cell */
} aOvfl[5]; } aOvfl[5];
BtShared *pBt; /* Pointer back to BTree structure */ BtShared *pBt; /* Pointer to BtShared that this page is part of */
u8 *aData; /* Pointer back to the start of the page */ u8 *aData; /* Pointer to disk image of the page data */
DbPage *pDbPage; /* Pager page handle */ DbPage *pDbPage; /* Pager page handle */
Pgno pgno; /* Page number for this page */ Pgno pgno; /* Page number for this page */
MemPage *pParent; /* The parent of this page. NULL for root */
}; };
/* /*
@ -300,11 +300,36 @@ struct MemPage {
*/ */
#define EXTRA_SIZE sizeof(MemPage) #define EXTRA_SIZE sizeof(MemPage)
/* Btree handle */ /* A Btree handle
**
** A database connection contains a pointer to an instance of
** this object for every database file that it has open. This structure
** is opaque to the database connection. The database connection cannot
** see the internals of this structure and only deals with pointers to
** this structure.
**
** For some database files, the same underlying database cache might be
** shared between multiple connections. In that case, each contection
** has it own pointer to this object. But each instance of this object
** points to the same BtShared object. The database cache and the
** schema associated with the database file are all contained within
** the BtShared object.
**
** All fields in this structure are accessed under sqlite3.mutex.
** The pBt pointer itself may not be changed while there exists cursors
** in the referenced BtShared that point back to this Btree since those
** cursors have to do go through this Btree to find their BtShared and
** they often do so without holding sqlite3.mutex.
*/
struct Btree { struct Btree {
sqlite3 *pSqlite; sqlite3 *db; /* The database connection holding this btree */
BtShared *pBt; BtShared *pBt; /* Sharable content of this btree */
u8 inTrans; /* TRANS_NONE, TRANS_READ or TRANS_WRITE */ u8 inTrans; /* TRANS_NONE, TRANS_READ or TRANS_WRITE */
u8 sharable; /* True if we can share pBt with another db */
u8 locked; /* True if db currently has pBt locked */
int wantToLock; /* Number of nested calls to sqlite3BtreeEnter() */
Btree *pNext; /* List of other sharable Btrees from the same db */
Btree *pPrev; /* Back pointer of the same list */
}; };
/* /*
@ -312,47 +337,59 @@ struct Btree {
** **
** If the shared-data extension is enabled, there may be multiple users ** If the shared-data extension is enabled, there may be multiple users
** of the Btree structure. At most one of these may open a write transaction, ** of the Btree structure. At most one of these may open a write transaction,
** but any number may have active read transactions. Variable Btree.pDb ** but any number may have active read transactions.
** points to the handle that owns any current write-transaction.
*/ */
#define TRANS_NONE 0 #define TRANS_NONE 0
#define TRANS_READ 1 #define TRANS_READ 1
#define TRANS_WRITE 2 #define TRANS_WRITE 2
/* /*
** Everything we need to know about an open database ** An instance of this object represents a single database file.
**
** A single database file can be in use as the same time by two
** or more database connections. When two or more connections are
** sharing the same database file, each connection has it own
** private Btree object for the file and each of those Btrees points
** to this one BtShared object. BtShared.nRef is the number of
** connections currently sharing this database file.
**
** Fields in this structure are accessed under the BtShared.mutex
** mutex, except for nRef and pNext which are accessed under the
** global SQLITE_MUTEX_STATIC_MASTER mutex. The pPager field
** may not be modified once it is initially set as long as nRef>0.
** The pSchema field may be set once under BtShared.mutex and
** thereafter is unchanged as long as nRef>0.
*/ */
struct BtShared { struct BtShared {
Pager *pPager; /* The page cache */ Pager *pPager; /* The page cache */
sqlite3 *db; /* Database connection currently using this Btree */
BtCursor *pCursor; /* A list of all open cursors */ BtCursor *pCursor; /* A list of all open cursors */
MemPage *pPage1; /* First page of the database */ MemPage *pPage1; /* First page of the database */
u8 inStmt; /* True if we are in a statement subtransaction */ u8 inStmt; /* True if we are in a statement subtransaction */
u8 readOnly; /* True if the underlying file is readonly */ u8 readOnly; /* True if the underlying file is readonly */
u8 maxEmbedFrac; /* Maximum payload as % of total page size */
u8 minEmbedFrac; /* Minimum payload as % of total page size */
u8 minLeafFrac; /* Minimum leaf payload as % of total page size */
u8 pageSizeFixed; /* True if the page size can no longer be changed */ u8 pageSizeFixed; /* True if the page size can no longer be changed */
#ifndef SQLITE_OMIT_AUTOVACUUM #ifndef SQLITE_OMIT_AUTOVACUUM
u8 autoVacuum; /* True if auto-vacuum is enabled */ u8 autoVacuum; /* True if auto-vacuum is enabled */
u8 incrVacuum; /* True if incr-vacuum is enabled */ u8 incrVacuum; /* True if incr-vacuum is enabled */
Pgno nTrunc; /* Non-zero if the db will be truncated (incr vacuum) */
#endif #endif
u16 pageSize; /* Total number of bytes on a page */ u16 pageSize; /* Total number of bytes on a page */
u16 usableSize; /* Number of usable bytes on each page */ u16 usableSize; /* Number of usable bytes on each page */
int maxLocal; /* Maximum local payload in non-LEAFDATA tables */ u16 maxLocal; /* Maximum local payload in non-LEAFDATA tables */
int minLocal; /* Minimum local payload in non-LEAFDATA tables */ u16 minLocal; /* Minimum local payload in non-LEAFDATA tables */
int maxLeaf; /* Maximum local payload in a LEAFDATA table */ u16 maxLeaf; /* Maximum local payload in a LEAFDATA table */
int minLeaf; /* Minimum local payload in a LEAFDATA table */ u16 minLeaf; /* Minimum local payload in a LEAFDATA table */
BusyHandler *pBusyHandler; /* Callback for when there is lock contention */
u8 inTransaction; /* Transaction state */ u8 inTransaction; /* Transaction state */
int nRef; /* Number of references to this structure */
int nTransaction; /* Number of open transactions (read + write) */ int nTransaction; /* Number of open transactions (read + write) */
void *pSchema; /* Pointer to space allocated by sqlite3BtreeSchema() */ void *pSchema; /* Pointer to space allocated by sqlite3BtreeSchema() */
void (*xFreeSchema)(void*); /* Destructor for BtShared.pSchema */ void (*xFreeSchema)(void*); /* Destructor for BtShared.pSchema */
sqlite3_mutex *mutex; /* Non-recursive mutex required to access this struct */
#ifndef SQLITE_OMIT_SHARED_CACHE #ifndef SQLITE_OMIT_SHARED_CACHE
int nRef; /* Number of references to this structure */
BtShared *pNext; /* Next on a list of sharable BtShared structs */
BtLock *pLock; /* List of locks held on this shared-btree struct */ BtLock *pLock; /* List of locks held on this shared-btree struct */
BtShared *pNext; /* Next in ThreadData.pBtree linked list */ Btree *pExclusive; /* Btree with an EXCLUSIVE lock on the whole db */
#endif #endif
u8 *pTmpSpace; /* BtShared.pageSize bytes of space for tmp use */
}; };
/* /*
@ -373,20 +410,40 @@ struct CellInfo {
}; };
/* /*
** A cursor is a pointer to a particular entry in the BTree. ** Maximum depth of an SQLite B-Tree structure. Any B-Tree deeper than
** this will be declared corrupt. This value is calculated based on a
** maximum database size of 2^31 pages a minimum fanout of 2 for a
** root-node and 3 for all other internal nodes.
**
** If a tree that appears to be taller than this is encountered, it is
** assumed that the database is corrupt.
*/
#define BTCURSOR_MAX_DEPTH 20
/*
** A cursor is a pointer to a particular entry within a particular
** b-tree within a database file.
**
** The entry is identified by its MemPage and the index in ** The entry is identified by its MemPage and the index in
** MemPage.aCell[] of the entry. ** MemPage.aCell[] of the entry.
**
** When a single database file can shared by two more database connections,
** but cursors cannot be shared. Each cursor is associated with a
** particular database connection identified BtCursor.pBtree.db.
**
** Fields in this structure are accessed under the BtShared.mutex
** found at self->pBt->mutex.
*/ */
struct BtCursor { struct BtCursor {
Btree *pBtree; /* The Btree to which this cursor belongs */ Btree *pBtree; /* The Btree to which this cursor belongs */
BtShared *pBt; /* The BtShared this cursor points to */
BtCursor *pNext, *pPrev; /* Forms a linked list of all cursors */ BtCursor *pNext, *pPrev; /* Forms a linked list of all cursors */
int (*xCompare)(void*,int,const void*,int,const void*); /* Key comp func */ struct KeyInfo *pKeyInfo; /* Argument passed to comparison function */
void *pArg; /* First arg to xCompare() */
Pgno pgnoRoot; /* The root page of this tree */ Pgno pgnoRoot; /* The root page of this tree */
MemPage *pPage; /* Page that contains the entry */
int idx; /* Index of the entry in pPage->aCell[] */
CellInfo info; /* A parse of the cell we are pointing at */ CellInfo info; /* A parse of the cell we are pointing at */
u8 wrFlag; /* True if writable */ u8 wrFlag; /* True if writable */
u8 atLast; /* Cursor pointing to the last entry */
u8 validNKey; /* True if info.nKey is valid */
u8 eState; /* One of the CURSOR_XXX constants (see below) */ u8 eState; /* One of the CURSOR_XXX constants (see below) */
void *pKey; /* Saved key that was cursor's last known position */ void *pKey; /* Saved key that was cursor's last known position */
i64 nKey; /* Size of pKey, or last integer key */ i64 nKey; /* Size of pKey, or last integer key */
@ -395,6 +452,12 @@ struct BtCursor {
u8 isIncrblobHandle; /* True if this cursor is an incr. io handle */ u8 isIncrblobHandle; /* True if this cursor is an incr. io handle */
Pgno *aOverflow; /* Cache of overflow page locations */ Pgno *aOverflow; /* Cache of overflow page locations */
#endif #endif
#ifndef NDEBUG
u8 pagesShuffled; /* True if Btree pages are rearranged by balance()*/
#endif
i16 iPage; /* Index of current page in apPage */
MemPage *apPage[BTCURSOR_MAX_DEPTH]; /* Pages from root to current page */
u16 aiIdx[BTCURSOR_MAX_DEPTH]; /* Current index in apPage[i] */
}; };
/* /*
@ -412,32 +475,20 @@ struct BtCursor {
** The table that this cursor was opened on still exists, but has been ** The table that this cursor was opened on still exists, but has been
** modified since the cursor was last used. The cursor position is saved ** modified since the cursor was last used. The cursor position is saved
** in variables BtCursor.pKey and BtCursor.nKey. When a cursor is in ** in variables BtCursor.pKey and BtCursor.nKey. When a cursor is in
** this state, restoreOrClearCursorPosition() can be called to attempt to ** this state, restoreCursorPosition() can be called to attempt to
** seek the cursor to the saved position. ** seek the cursor to the saved position.
**
** CURSOR_FAULT:
** A unrecoverable error (an I/O error or a malloc failure) has occurred
** on a different connection that shares the BtShared cache with this
** cursor. The error has left the cache in an inconsistent state.
** Do nothing else with this cursor. Any attempt to use the cursor
** should return the error code stored in BtCursor.skip
*/ */
#define CURSOR_INVALID 0 #define CURSOR_INVALID 0
#define CURSOR_VALID 1 #define CURSOR_VALID 1
#define CURSOR_REQUIRESEEK 2 #define CURSOR_REQUIRESEEK 2
#define CURSOR_FAULT 3
/*
** The TRACE macro will print high-level status information about the
** btree operation when the global variable sqlite3_btree_trace is
** enabled.
*/
#if SQLITE_TEST
# define TRACE(X) if( sqlite3_btree_trace ){ printf X; fflush(stdout); }
#else
# define TRACE(X)
#endif
/*
** Routines to read and write variable-length integers. These used to
** be defined locally, but now we use the varint routines in the util.c
** file.
*/
#define getVarint sqlite3GetVarint
#define getVarint32(A,B) ((*B=*(A))<=0x7f?1:sqlite3GetVarint32(A,B))
#define putVarint sqlite3PutVarint
/* The database page the PENDING_BYTE occupies. This page is never used. /* The database page the PENDING_BYTE occupies. This page is never used.
** TODO: This macro is very similary to PAGER_MJ_PGNO() in pager.c. They ** TODO: This macro is very similary to PAGER_MJ_PGNO() in pager.c. They
@ -449,7 +500,7 @@ struct BtCursor {
#ifdef SQLITE_OMIT_DISKIO #ifdef SQLITE_OMIT_DISKIO
# define PENDING_BYTE_PAGE(pBt) 0x7fffffff # define PENDING_BYTE_PAGE(pBt) 0x7fffffff
#else #else
# define PENDING_BYTE_PAGE(pBt) ((PENDING_BYTE/(pBt)->pageSize)+1) # define PENDING_BYTE_PAGE(pBt) ((Pgno)((PENDING_BYTE/(pBt)->pageSize)+1))
#endif #endif
/* /*
@ -486,7 +537,7 @@ struct BtLock {
** this test. ** this test.
*/ */
#define PTRMAP_PAGENO(pBt, pgno) ptrmapPageno(pBt, pgno) #define PTRMAP_PAGENO(pBt, pgno) ptrmapPageno(pBt, pgno)
#define PTRMAP_PTROFFSET(pBt, pgno) (5*(pgno-ptrmapPageno(pBt, pgno)-1)) #define PTRMAP_PTROFFSET(pgptrmap, pgno) (5*(pgno-pgptrmap-1))
#define PTRMAP_ISPAGE(pBt, pgno) (PTRMAP_PAGENO((pBt),(pgno))==(pgno)) #define PTRMAP_ISPAGE(pBt, pgno) (PTRMAP_PAGENO((pBt),(pgno))==(pgno))
/* /*
@ -530,8 +581,6 @@ struct BtLock {
** of handle p (type Btree*) are internally consistent. ** of handle p (type Btree*) are internally consistent.
*/ */
#define btreeIntegrity(p) \ #define btreeIntegrity(p) \
assert( p->inTrans!=TRANS_NONE || p->pBt->nTransaction<p->pBt->nRef ); \
assert( p->pBt->nTransaction<=p->pBt->nRef ); \
assert( p->pBt->inTransaction!=TRANS_NONE || p->pBt->nTransaction==0 ); \ assert( p->pBt->inTransaction!=TRANS_NONE || p->pBt->nTransaction==0 ); \
assert( p->pBt->inTransaction>=p->inTrans ); assert( p->pBt->inTransaction>=p->inTrans );
@ -558,18 +607,19 @@ typedef struct IntegrityCk IntegrityCk;
struct IntegrityCk { struct IntegrityCk {
BtShared *pBt; /* The tree being checked out */ BtShared *pBt; /* The tree being checked out */
Pager *pPager; /* The associated pager. Also accessible by pBt->pPager */ Pager *pPager; /* The associated pager. Also accessible by pBt->pPager */
int nPage; /* Number of pages in the database */ Pgno nPage; /* Number of pages in the database */
int *anRef; /* Number of times each page is referenced */ int *anRef; /* Number of times each page is referenced */
int mxErr; /* Stop accumulating errors when this reaches zero */ int mxErr; /* Stop accumulating errors when this reaches zero */
char *zErrMsg; /* An error message. NULL if no errors seen. */
int nErr; /* Number of messages written to zErrMsg so far */ int nErr; /* Number of messages written to zErrMsg so far */
int mallocFailed; /* A memory allocation error has occurred */
StrAccum errMsg; /* Accumulate the error message text here */
}; };
/* /*
** Read or write a two- and four-byte big-endian integer values. ** Read or write a two- and four-byte big-endian integer values.
*/ */
#define get2byte(x) ((x)[0]<<8 | (x)[1]) #define get2byte(x) ((x)[0]<<8 | (x)[1])
#define put2byte(p,v) ((p)[0] = (v)>>8, (p)[1] = (v)) #define put2byte(p,v) ((p)[0] = (u8)((v)>>8), (p)[1] = (u8)(v))
#define get4byte sqlite3Get4byte #define get4byte sqlite3Get4byte
#define put4byte sqlite3Put4byte #define put4byte sqlite3Put4byte
@ -577,12 +627,10 @@ struct IntegrityCk {
** Internal routines that should be accessed by the btree layer only. ** Internal routines that should be accessed by the btree layer only.
*/ */
int sqlite3BtreeGetPage(BtShared*, Pgno, MemPage**, int); int sqlite3BtreeGetPage(BtShared*, Pgno, MemPage**, int);
int sqlite3BtreeInitPage(MemPage *pPage, MemPage *pParent); int sqlite3BtreeInitPage(MemPage *pPage);
void sqlite3BtreeParseCellPtr(MemPage*, u8*, CellInfo*); void sqlite3BtreeParseCellPtr(MemPage*, u8*, CellInfo*);
void sqlite3BtreeParseCell(MemPage*, int, CellInfo*); void sqlite3BtreeParseCell(MemPage*, int, CellInfo*);
u8 *sqlite3BtreeFindCell(MemPage *pPage, int iCell); int sqlite3BtreeRestoreCursorPosition(BtCursor *pCur);
int sqlite3BtreeRestoreOrClearCursorPosition(BtCursor *pCur);
void sqlite3BtreeGetTempCursor(BtCursor *pCur, BtCursor *pTempCur); void sqlite3BtreeGetTempCursor(BtCursor *pCur, BtCursor *pTempCur);
void sqlite3BtreeReleaseTempCursor(BtCursor *pCur); void sqlite3BtreeReleaseTempCursor(BtCursor *pCur);
int sqlite3BtreeIsRootPage(MemPage *pPage);
void sqlite3BtreeMoveToParent(BtCursor *pCur); void sqlite3BtreeMoveToParent(BtCursor *pCur);

936
build.c

File diff suppressed because it is too large Load diff

View file

@ -13,7 +13,7 @@
** This file contains functions used to access the internal hash tables ** This file contains functions used to access the internal hash tables
** of user defined functions and collation sequences. ** of user defined functions and collation sequences.
** **
** $Id: callback.c,v 1.18 2007/05/07 09:32:45 danielk1977 Exp $ ** $Id: callback.c,v 1.34 2008/12/10 21:19:57 drh Exp $
*/ */
#include "sqliteInt.h" #include "sqliteInt.h"
@ -25,17 +25,17 @@
*/ */
static void callCollNeeded(sqlite3 *db, const char *zName, int nName){ static void callCollNeeded(sqlite3 *db, const char *zName, int nName){
assert( !db->xCollNeeded || !db->xCollNeeded16 ); assert( !db->xCollNeeded || !db->xCollNeeded16 );
if( nName<0 ) nName = strlen(zName); if( nName<0 ) nName = sqlite3Strlen(db, zName);
if( db->xCollNeeded ){ if( db->xCollNeeded ){
char *zExternal = sqliteStrNDup(zName, nName); char *zExternal = sqlite3DbStrNDup(db, zName, nName);
if( !zExternal ) return; if( !zExternal ) return;
db->xCollNeeded(db->pCollNeededArg, db, (int)ENC(db), zExternal); db->xCollNeeded(db->pCollNeededArg, db, (int)ENC(db), zExternal);
sqliteFree(zExternal); sqlite3DbFree(db, zExternal);
} }
#ifndef SQLITE_OMIT_UTF16 #ifndef SQLITE_OMIT_UTF16
if( db->xCollNeeded16 ){ if( db->xCollNeeded16 ){
char const *zExternal; char const *zExternal;
sqlite3_value *pTmp = sqlite3ValueNew(); sqlite3_value *pTmp = sqlite3ValueNew(db);
sqlite3ValueSetStr(pTmp, nName, zName, SQLITE_UTF8, SQLITE_STATIC); sqlite3ValueSetStr(pTmp, nName, zName, SQLITE_UTF8, SQLITE_STATIC);
zExternal = sqlite3ValueText(pTmp, SQLITE_UTF16NATIVE); zExternal = sqlite3ValueText(pTmp, SQLITE_UTF16NATIVE);
if( zExternal ){ if( zExternal ){
@ -56,7 +56,7 @@ static void callCollNeeded(sqlite3 *db, const char *zName, int nName){
static int synthCollSeq(sqlite3 *db, CollSeq *pColl){ static int synthCollSeq(sqlite3 *db, CollSeq *pColl){
CollSeq *pColl2; CollSeq *pColl2;
char *z = pColl->zName; char *z = pColl->zName;
int n = strlen(z); int n = sqlite3Strlen30(z);
int i; int i;
static const u8 aEnc[] = { SQLITE_UTF16BE, SQLITE_UTF16LE, SQLITE_UTF8 }; static const u8 aEnc[] = { SQLITE_UTF16BE, SQLITE_UTF16LE, SQLITE_UTF8 };
for(i=0; i<3; i++){ for(i=0; i<3; i++){
@ -158,11 +158,11 @@ static CollSeq *findCollSeqEntry(
int create int create
){ ){
CollSeq *pColl; CollSeq *pColl;
if( nName<0 ) nName = strlen(zName); if( nName<0 ) nName = sqlite3Strlen(db, zName);
pColl = sqlite3HashFind(&db->aCollSeq, zName, nName); pColl = sqlite3HashFind(&db->aCollSeq, zName, nName);
if( 0==pColl && create ){ if( 0==pColl && create ){
pColl = sqliteMalloc( 3*sizeof(*pColl) + nName + 1 ); pColl = sqlite3DbMallocZero(db, 3*sizeof(*pColl) + nName + 1 );
if( pColl ){ if( pColl ){
CollSeq *pDel = 0; CollSeq *pDel = 0;
pColl[0].zName = (char*)&pColl[3]; pColl[0].zName = (char*)&pColl[3];
@ -179,9 +179,10 @@ static CollSeq *findCollSeqEntry(
** return the pColl pointer to be deleted (because it wasn't added ** return the pColl pointer to be deleted (because it wasn't added
** to the hash table). ** to the hash table).
*/ */
assert( !pDel || (sqlite3MallocFailed() && pDel==pColl) ); assert( pDel==0 || pDel==pColl );
if( pDel ){ if( pDel!=0 ){
sqliteFree(pDel); db->mallocFailed = 1;
sqlite3DbFree(db, pDel);
pColl = 0; pColl = 0;
} }
} }
@ -221,6 +222,87 @@ CollSeq *sqlite3FindCollSeq(
return pColl; return pColl;
} }
/* During the search for the best function definition, this procedure
** is called to test how well the function passed as the first argument
** matches the request for a function with nArg arguments in a system
** that uses encoding enc. The value returned indicates how well the
** request is matched. A higher value indicates a better match.
**
** The returned value is always between 1 and 6, as follows:
**
** 1: A variable arguments function that prefers UTF-8 when a UTF-16
** encoding is requested, or vice versa.
** 2: A variable arguments function that uses UTF-16BE when UTF-16LE is
** requested, or vice versa.
** 3: A variable arguments function using the same text encoding.
** 4: A function with the exact number of arguments requested that
** prefers UTF-8 when a UTF-16 encoding is requested, or vice versa.
** 5: A function with the exact number of arguments requested that
** prefers UTF-16LE when UTF-16BE is requested, or vice versa.
** 6: An exact match.
**
*/
static int matchQuality(FuncDef *p, int nArg, u8 enc){
int match = 0;
if( p->nArg==-1 || p->nArg==nArg || nArg==-1 ){
match = 1;
if( p->nArg==nArg || nArg==-1 ){
match = 4;
}
if( enc==p->iPrefEnc ){
match += 2;
}
else if( (enc==SQLITE_UTF16LE && p->iPrefEnc==SQLITE_UTF16BE) ||
(enc==SQLITE_UTF16BE && p->iPrefEnc==SQLITE_UTF16LE) ){
match += 1;
}
}
return match;
}
/*
** Search a FuncDefHash for a function with the given name. Return
** a pointer to the matching FuncDef if found, or 0 if there is no match.
*/
static FuncDef *functionSearch(
FuncDefHash *pHash, /* Hash table to search */
int h, /* Hash of the name */
const char *zFunc, /* Name of function */
int nFunc /* Number of bytes in zFunc */
){
FuncDef *p;
for(p=pHash->a[h]; p; p=p->pHash){
if( sqlite3StrNICmp(p->zName, zFunc, nFunc)==0 && p->zName[nFunc]==0 ){
return p;
}
}
return 0;
}
/*
** Insert a new FuncDef into a FuncDefHash hash table.
*/
void sqlite3FuncDefInsert(
FuncDefHash *pHash, /* The hash table into which to insert */
FuncDef *pDef /* The function definition to insert */
){
FuncDef *pOther;
int nName = sqlite3Strlen30(pDef->zName);
u8 c1 = (u8)pDef->zName[0];
int h = (sqlite3UpperToLower[c1] + nName) % ArraySize(pHash->a);
pOther = functionSearch(pHash, h, pDef->zName, nName);
if( pOther ){
pDef->pNext = pOther->pNext;
pOther->pNext = pDef;
}else{
pDef->pNext = 0;
pDef->pHash = pHash->a[h];
pHash->a[h] = pDef;
}
}
/* /*
** Locate a user function given a name, a number of arguments and a flag ** Locate a user function given a name, a number of arguments and a flag
** indicating whether the function prefers UTF-16 over UTF-8. Return a ** indicating whether the function prefers UTF-16 over UTF-8. Return a
@ -250,69 +332,60 @@ FuncDef *sqlite3FindFunction(
int createFlag /* Create new entry if true and does not otherwise exist */ int createFlag /* Create new entry if true and does not otherwise exist */
){ ){
FuncDef *p; /* Iterator variable */ FuncDef *p; /* Iterator variable */
FuncDef *pFirst; /* First function with this name */
FuncDef *pBest = 0; /* Best match found so far */ FuncDef *pBest = 0; /* Best match found so far */
int bestmatch = 0; int bestScore = 0; /* Score of best match */
int h; /* Hash value */
assert( enc==SQLITE_UTF8 || enc==SQLITE_UTF16LE || enc==SQLITE_UTF16BE ); assert( enc==SQLITE_UTF8 || enc==SQLITE_UTF16LE || enc==SQLITE_UTF16BE );
if( nArg<-1 ) nArg = -1; if( nArg<-1 ) nArg = -1;
h = (sqlite3UpperToLower[(u8)zName[0]] + nName) % ArraySize(db->aFunc.a);
pFirst = (FuncDef*)sqlite3HashFind(&db->aFunc, zName, nName); /* First search for a match amongst the application-defined functions.
for(p=pFirst; p; p=p->pNext){ */
/* During the search for the best function definition, bestmatch is set p = functionSearch(&db->aFunc, h, zName, nName);
** as follows to indicate the quality of the match with the definition while( p ){
** pointed to by pBest: int score = matchQuality(p, nArg, enc);
** if( score>bestScore ){
** 0: pBest is NULL. No match has been found. pBest = p;
** 1: A variable arguments function that prefers UTF-8 when a UTF-16 bestScore = score;
** encoding is requested, or vice versa. }
** 2: A variable arguments function that uses UTF-16BE when UTF-16LE is p = p->pNext;
** requested, or vice versa. }
** 3: A variable arguments function using the same text encoding.
** 4: A function with the exact number of arguments requested that
** prefers UTF-8 when a UTF-16 encoding is requested, or vice versa.
** 5: A function with the exact number of arguments requested that
** prefers UTF-16LE when UTF-16BE is requested, or vice versa.
** 6: An exact match.
**
** A larger value of 'matchqual' indicates a more desirable match.
*/
if( p->nArg==-1 || p->nArg==nArg || nArg==-1 ){
int match = 1; /* Quality of this match */
if( p->nArg==nArg || nArg==-1 ){
match = 4;
}
if( enc==p->iPrefEnc ){
match += 2;
}
else if( (enc==SQLITE_UTF16LE && p->iPrefEnc==SQLITE_UTF16BE) ||
(enc==SQLITE_UTF16BE && p->iPrefEnc==SQLITE_UTF16LE) ){
match += 1;
}
if( match>bestmatch ){ /* If no match is found, search the built-in functions.
**
** Except, if createFlag is true, that means that we are trying to
** install a new function. Whatever FuncDef structure is returned will
** have fields overwritten with new information appropriate for the
** new function. But the FuncDefs for built-in functions are read-only.
** So we must not search for built-ins when creating a new function.
*/
if( !createFlag && !pBest ){
FuncDefHash *pHash = &GLOBAL(FuncDefHash, sqlite3GlobalFunctions);
p = functionSearch(pHash, h, zName, nName);
while( p ){
int score = matchQuality(p, nArg, enc);
if( score>bestScore ){
pBest = p; pBest = p;
bestmatch = match; bestScore = score;
} }
p = p->pNext;
} }
} }
/* If the createFlag parameter is true, and the seach did not reveal an /* If the createFlag parameter is true and the search did not reveal an
** exact match for the name, number of arguments and encoding, then add a ** exact match for the name, number of arguments and encoding, then add a
** new entry to the hash table and return it. ** new entry to the hash table and return it.
*/ */
if( createFlag && bestmatch<6 && if( createFlag && (bestScore<6 || pBest->nArg!=nArg) &&
(pBest = sqliteMalloc(sizeof(*pBest)+nName))!=0 ){ (pBest = sqlite3DbMallocZero(db, sizeof(*pBest)+nName+1))!=0 ){
pBest->nArg = nArg; pBest->zName = (char *)&pBest[1];
pBest->pNext = pFirst; pBest->nArg = (u16)nArg;
pBest->iPrefEnc = enc; pBest->iPrefEnc = enc;
memcpy(pBest->zName, zName, nName); memcpy(pBest->zName, zName, nName);
pBest->zName[nName] = 0; pBest->zName[nName] = 0;
if( pBest==sqlite3HashInsert(&db->aFunc,pBest->zName,nName,(void*)pBest) ){ sqlite3FuncDefInsert(&db->aFunc, pBest);
sqliteFree(pBest);
return 0;
}
} }
if( pBest && (pBest->xStep || pBest->xFunc || createFlag) ){ if( pBest && (pBest->xStep || pBest->xFunc || createFlag) ){
@ -323,9 +396,11 @@ FuncDef *sqlite3FindFunction(
/* /*
** Free all resources held by the schema structure. The void* argument points ** Free all resources held by the schema structure. The void* argument points
** at a Schema struct. This function does not call sqliteFree() on the ** at a Schema struct. This function does not call sqlite3DbFree(db, ) on the
** pointer itself, it just cleans up subsiduary resources (i.e. the contents ** pointer itself, it just cleans up subsiduary resources (i.e. the contents
** of the schema hash tables). ** of the schema hash tables).
**
** The Schema.cache_size variable is not cleared.
*/ */
void sqlite3SchemaFree(void *p){ void sqlite3SchemaFree(void *p){
Hash temp1; Hash temp1;
@ -335,14 +410,14 @@ void sqlite3SchemaFree(void *p){
temp1 = pSchema->tblHash; temp1 = pSchema->tblHash;
temp2 = pSchema->trigHash; temp2 = pSchema->trigHash;
sqlite3HashInit(&pSchema->trigHash, SQLITE_HASH_STRING, 0); sqlite3HashInit(&pSchema->trigHash, 0);
sqlite3HashClear(&pSchema->aFKey); sqlite3HashClear(&pSchema->aFKey);
sqlite3HashClear(&pSchema->idxHash); sqlite3HashClear(&pSchema->idxHash);
for(pElem=sqliteHashFirst(&temp2); pElem; pElem=sqliteHashNext(pElem)){ for(pElem=sqliteHashFirst(&temp2); pElem; pElem=sqliteHashNext(pElem)){
sqlite3DeleteTrigger((Trigger*)sqliteHashData(pElem)); sqlite3DeleteTrigger(0, (Trigger*)sqliteHashData(pElem));
} }
sqlite3HashClear(&temp2); sqlite3HashClear(&temp2);
sqlite3HashInit(&pSchema->tblHash, SQLITE_HASH_STRING, 0); sqlite3HashInit(&pSchema->tblHash, 0);
for(pElem=sqliteHashFirst(&temp1); pElem; pElem=sqliteHashNext(pElem)){ for(pElem=sqliteHashFirst(&temp1); pElem; pElem=sqliteHashNext(pElem)){
Table *pTab = sqliteHashData(pElem); Table *pTab = sqliteHashData(pElem);
sqlite3DeleteTable(pTab); sqlite3DeleteTable(pTab);
@ -356,18 +431,20 @@ void sqlite3SchemaFree(void *p){
** Find and return the schema associated with a BTree. Create ** Find and return the schema associated with a BTree. Create
** a new one if necessary. ** a new one if necessary.
*/ */
Schema *sqlite3SchemaGet(Btree *pBt){ Schema *sqlite3SchemaGet(sqlite3 *db, Btree *pBt){
Schema * p; Schema * p;
if( pBt ){ if( pBt ){
p = (Schema *)sqlite3BtreeSchema(pBt,sizeof(Schema),sqlite3SchemaFree); p = (Schema *)sqlite3BtreeSchema(pBt, sizeof(Schema), sqlite3SchemaFree);
}else{ }else{
p = (Schema *)sqliteMalloc(sizeof(Schema)); p = (Schema *)sqlite3MallocZero(sizeof(Schema));
} }
if( p && 0==p->file_format ){ if( !p ){
sqlite3HashInit(&p->tblHash, SQLITE_HASH_STRING, 0); db->mallocFailed = 1;
sqlite3HashInit(&p->idxHash, SQLITE_HASH_STRING, 0); }else if ( 0==p->file_format ){
sqlite3HashInit(&p->trigHash, SQLITE_HASH_STRING, 0); sqlite3HashInit(&p->tblHash, 0);
sqlite3HashInit(&p->aFKey, SQLITE_HASH_STRING, 1); sqlite3HashInit(&p->idxHash, 0);
sqlite3HashInit(&p->trigHash, 0);
sqlite3HashInit(&p->aFKey, 1);
p->enc = SQLITE_UTF8; p->enc = SQLITE_UTF8;
} }
return p; return p;

View file

@ -16,7 +16,7 @@
** separating it out, the code will be automatically omitted from ** separating it out, the code will be automatically omitted from
** static links that do not use it. ** static links that do not use it.
** **
** $Id: complete.c,v 1.3 2006/01/18 15:25:17 danielk1977 Exp $ ** $Id: complete.c,v 1.7 2008/06/13 18:24:27 drh Exp $
*/ */
#include "sqliteInt.h" #include "sqliteInt.h"
#ifndef SQLITE_OMIT_COMPLETE #ifndef SQLITE_OMIT_COMPLETE
@ -24,8 +24,16 @@
/* /*
** This is defined in tokenize.c. We just have to import the definition. ** This is defined in tokenize.c. We just have to import the definition.
*/ */
extern const char sqlite3IsIdChar[]; #ifndef SQLITE_AMALGAMATION
#define IdChar(C) (((c=C)&0x80)!=0 || (c>0x1f && sqlite3IsIdChar[c-0x20])) #ifdef SQLITE_ASCII
extern const char sqlite3IsAsciiIdChar[];
#define IdChar(C) (((c=C)&0x80)!=0 || (c>0x1f && sqlite3IsAsciiIdChar[c-0x20]))
#endif
#ifdef SQLITE_EBCDIC
extern const char sqlite3IsEbcdicIdChar[];
#define IdChar(C) (((c=C)>=0x42 && sqlite3IsEbcdicIdChar[c-0x40]))
#endif
#endif /* SQLITE_AMALGAMATION */
/* /*
@ -248,13 +256,19 @@ int sqlite3_complete(const char *zSql){
int sqlite3_complete16(const void *zSql){ int sqlite3_complete16(const void *zSql){
sqlite3_value *pVal; sqlite3_value *pVal;
char const *zSql8; char const *zSql8;
int rc = 0; int rc = SQLITE_NOMEM;
pVal = sqlite3ValueNew(); #ifndef SQLITE_OMIT_AUTOINIT
rc = sqlite3_initialize();
if( rc ) return rc;
#endif
pVal = sqlite3ValueNew(0);
sqlite3ValueSetStr(pVal, -1, zSql, SQLITE_UTF16NATIVE, SQLITE_STATIC); sqlite3ValueSetStr(pVal, -1, zSql, SQLITE_UTF16NATIVE, SQLITE_STATIC);
zSql8 = sqlite3ValueText(pVal, SQLITE_UTF8); zSql8 = sqlite3ValueText(pVal, SQLITE_UTF8);
if( zSql8 ){ if( zSql8 ){
rc = sqlite3_complete(zSql8); rc = sqlite3_complete(zSql8);
}else{
rc = SQLITE_NOMEM;
} }
sqlite3ValueFree(pVal); sqlite3ValueFree(pVal);
return sqlite3ApiExit(0, rc); return sqlite3ApiExit(0, rc);

404
date.c
View file

@ -16,7 +16,7 @@
** sqlite3RegisterDateTimeFunctions() found at the bottom of the file. ** sqlite3RegisterDateTimeFunctions() found at the bottom of the file.
** All other code has file scope. ** All other code has file scope.
** **
** $Id: date.c,v 1.66 2007/05/08 21:56:00 drh Exp $ ** $Id: date.c,v 1.99 2008/12/20 13:18:50 drh Exp $
** **
** SQLite processes all times and dates as Julian Day numbers. The ** SQLite processes all times and dates as Julian Day numbers. The
** dates and times are stored as the number of days since noon ** dates and times are stored as the number of days since noon
@ -46,7 +46,6 @@
** Richmond, Virginia (USA) ** Richmond, Virginia (USA)
*/ */
#include "sqliteInt.h" #include "sqliteInt.h"
#include "os.h"
#include <ctype.h> #include <ctype.h>
#include <stdlib.h> #include <stdlib.h>
#include <assert.h> #include <assert.h>
@ -54,20 +53,37 @@
#ifndef SQLITE_OMIT_DATETIME_FUNCS #ifndef SQLITE_OMIT_DATETIME_FUNCS
/*
** On recent Windows platforms, the localtime_s() function is available
** as part of the "Secure CRT". It is essentially equivalent to
** localtime_r() available under most POSIX platforms, except that the
** order of the parameters is reversed.
**
** See http://msdn.microsoft.com/en-us/library/a442x3ye(VS.80).aspx.
**
** If the user has not indicated to use localtime_r() or localtime_s()
** already, check for an MSVC build environment that provides
** localtime_s().
*/
#if !defined(HAVE_LOCALTIME_R) && !defined(HAVE_LOCALTIME_S) && \
defined(_MSC_VER) && defined(_CRT_INSECURE_DEPRECATE)
#define HAVE_LOCALTIME_S 1
#endif
/* /*
** A structure for holding a single date and time. ** A structure for holding a single date and time.
*/ */
typedef struct DateTime DateTime; typedef struct DateTime DateTime;
struct DateTime { struct DateTime {
double rJD; /* The julian day number */ sqlite3_int64 iJD; /* The julian day number times 86400000 */
int Y, M, D; /* Year, month, and day */ int Y, M, D; /* Year, month, and day */
int h, m; /* Hour and minutes */ int h, m; /* Hour and minutes */
int tz; /* Timezone offset in minutes */ int tz; /* Timezone offset in minutes */
double s; /* Seconds */ double s; /* Seconds */
char validYMD; /* True if Y,M,D are valid */ char validYMD; /* True (1) if Y,M,D are valid */
char validHMS; /* True if h,m,s are valid */ char validHMS; /* True (1) if h,m,s are valid */
char validJD; /* True if rJD is valid */ char validJD; /* True (1) if iJD is valid */
char validTZ; /* True if tz is valid */ char validTZ; /* True (1) if tz is valid */
}; };
@ -132,23 +148,32 @@ end_getDigits:
** **
** (+/-)HH:MM ** (+/-)HH:MM
** **
** Or the "zulu" notation:
**
** Z
**
** If the parse is successful, write the number of minutes ** If the parse is successful, write the number of minutes
** of change in *pnMin and return 0. If a parser error occurs, ** of change in p->tz and return 0. If a parser error occurs,
** return 0. ** return non-zero.
** **
** A missing specifier is not considered an error. ** A missing specifier is not considered an error.
*/ */
static int parseTimezone(const char *zDate, DateTime *p){ static int parseTimezone(const char *zDate, DateTime *p){
int sgn = 0; int sgn = 0;
int nHr, nMn; int nHr, nMn;
int c;
while( isspace(*(u8*)zDate) ){ zDate++; } while( isspace(*(u8*)zDate) ){ zDate++; }
p->tz = 0; p->tz = 0;
if( *zDate=='-' ){ c = *zDate;
if( c=='-' ){
sgn = -1; sgn = -1;
}else if( *zDate=='+' ){ }else if( c=='+' ){
sgn = +1; sgn = +1;
}else if( c=='Z' || c=='z' ){
zDate++;
goto zulu_time;
}else{ }else{
return *zDate!=0; return c!=0;
} }
zDate++; zDate++;
if( getDigits(zDate, 2, 0, 14, ':', &nHr, 2, 0, 59, 0, &nMn)!=2 ){ if( getDigits(zDate, 2, 0, 14, ':', &nHr, 2, 0, 59, 0, &nMn)!=2 ){
@ -156,6 +181,7 @@ static int parseTimezone(const char *zDate, DateTime *p){
} }
zDate += 5; zDate += 5;
p->tz = sgn*(nMn + nHr*60); p->tz = sgn*(nMn + nHr*60);
zulu_time:
while( isspace(*(u8*)zDate) ){ zDate++; } while( isspace(*(u8*)zDate) ){ zDate++; }
return *zDate!=0; return *zDate!=0;
} }
@ -199,7 +225,7 @@ static int parseHhMmSs(const char *zDate, DateTime *p){
p->m = m; p->m = m;
p->s = s + ms; p->s = s + ms;
if( parseTimezone(zDate, p) ) return 1; if( parseTimezone(zDate, p) ) return 1;
p->validTZ = p->tz!=0; p->validTZ = (p->tz!=0)?1:0;
return 0; return 0;
} }
@ -228,14 +254,14 @@ static void computeJD(DateTime *p){
} }
A = Y/100; A = Y/100;
B = 2 - A + (A/4); B = 2 - A + (A/4);
X1 = 365.25*(Y+4716); X1 = 36525*(Y+4716)/100;
X2 = 30.6001*(M+1); X2 = 306001*(M+1)/10000;
p->rJD = X1 + X2 + D + B - 1524.5; p->iJD = (sqlite3_int64)((X1 + X2 + D + B - 1524.5 ) * 86400000);
p->validJD = 1; p->validJD = 1;
if( p->validHMS ){ if( p->validHMS ){
p->rJD += (p->h*3600.0 + p->m*60.0 + p->s)/86400.0; p->iJD += p->h*3600000 + p->m*60000 + (sqlite3_int64)(p->s*1000);
if( p->validTZ ){ if( p->validTZ ){
p->rJD -= p->tz*60/86400.0; p->iJD -= p->tz*60000;
p->validYMD = 0; p->validYMD = 0;
p->validHMS = 0; p->validHMS = 0;
p->validTZ = 0; p->validTZ = 0;
@ -287,6 +313,17 @@ static int parseYyyyMmDd(const char *zDate, DateTime *p){
return 0; return 0;
} }
/*
** Set the time to the current time reported by the VFS
*/
static void setDateTimeToCurrent(sqlite3_context *context, DateTime *p){
double r;
sqlite3 *db = sqlite3_context_db_handle(context);
sqlite3OsCurrentTime(db->pVfs, &r);
p->iJD = (sqlite3_int64)(r*86400000.0 + 0.5);
p->validJD = 1;
}
/* /*
** Attempt to parse the given string into a Julian Day Number. Return ** Attempt to parse the given string into a Julian Day Number. Return
** the number of errors. ** the number of errors.
@ -303,20 +340,22 @@ static int parseYyyyMmDd(const char *zDate, DateTime *p){
** as there is a time string. The time string can be omitted as long ** as there is a time string. The time string can be omitted as long
** as there is a year and date. ** as there is a year and date.
*/ */
static int parseDateOrTime(const char *zDate, DateTime *p){ static int parseDateOrTime(
memset(p, 0, sizeof(*p)); sqlite3_context *context,
const char *zDate,
DateTime *p
){
if( parseYyyyMmDd(zDate,p)==0 ){ if( parseYyyyMmDd(zDate,p)==0 ){
return 0; return 0;
}else if( parseHhMmSs(zDate, p)==0 ){ }else if( parseHhMmSs(zDate, p)==0 ){
return 0; return 0;
}else if( sqlite3StrICmp(zDate,"now")==0){ }else if( sqlite3StrICmp(zDate,"now")==0){
double r; setDateTimeToCurrent(context, p);
sqlite3OsCurrentTime(&r);
p->rJD = r;
p->validJD = 1;
return 0; return 0;
}else if( sqlite3IsNumber(zDate, 0, SQLITE_UTF8) ){ }else if( sqlite3IsNumber(zDate, 0, SQLITE_UTF8) ){
getValue(zDate, &p->rJD); double r;
getValue(zDate, &r);
p->iJD = (sqlite3_int64)(r*86400000.0 + 0.5);
p->validJD = 1; p->validJD = 1;
return 0; return 0;
} }
@ -334,14 +373,14 @@ static void computeYMD(DateTime *p){
p->M = 1; p->M = 1;
p->D = 1; p->D = 1;
}else{ }else{
Z = p->rJD + 0.5; Z = (int)((p->iJD + 43200000)/86400000);
A = (Z - 1867216.25)/36524.25; A = (int)((Z - 1867216.25)/36524.25);
A = Z + 1 + A - (A/4); A = Z + 1 + A - (A/4);
B = A + 1524; B = A + 1524;
C = (B - 122.1)/365.25; C = (int)((B - 122.1)/365.25);
D = 365.25*C; D = (36525*C)/100;
E = (B-D)/30.6001; E = (int)((B-D)/30.6001);
X1 = 30.6001*E; X1 = (int)(30.6001*E);
p->D = B - D - X1; p->D = B - D - X1;
p->M = E<14 ? E-1 : E-13; p->M = E<14 ? E-1 : E-13;
p->Y = p->M>2 ? C - 4716 : C - 4715; p->Y = p->M>2 ? C - 4716 : C - 4715;
@ -353,13 +392,12 @@ static void computeYMD(DateTime *p){
** Compute the Hour, Minute, and Seconds from the julian day number. ** Compute the Hour, Minute, and Seconds from the julian day number.
*/ */
static void computeHMS(DateTime *p){ static void computeHMS(DateTime *p){
int Z, s; int s;
if( p->validHMS ) return; if( p->validHMS ) return;
computeJD(p); computeJD(p);
Z = p->rJD + 0.5; s = (int)((p->iJD + 43200000) % 86400000);
s = (p->rJD + 0.5 - Z)*86400000.0 + 0.5; p->s = s/1000.0;
p->s = 0.001*s; s = (int)p->s;
s = p->s;
p->s -= s; p->s -= s;
p->h = s/3600; p->h = s/3600;
s -= p->h*3600; s -= p->h*3600;
@ -385,11 +423,13 @@ static void clearYMD_HMS_TZ(DateTime *p){
p->validTZ = 0; p->validTZ = 0;
} }
#ifndef SQLITE_OMIT_LOCALTIME
/* /*
** Compute the difference (in days) between localtime and UTC (a.k.a. GMT) ** Compute the difference (in milliseconds)
** between localtime and UTC (a.k.a. GMT)
** for the time value p where p is in UTC. ** for the time value p where p is in UTC.
*/ */
static double localtimeOffset(DateTime *p){ static sqlite3_int64 localtimeOffset(DateTime *p){
DateTime x, y; DateTime x, y;
time_t t; time_t t;
x = *p; x = *p;
@ -402,13 +442,13 @@ static double localtimeOffset(DateTime *p){
x.m = 0; x.m = 0;
x.s = 0.0; x.s = 0.0;
} else { } else {
int s = x.s + 0.5; int s = (int)(x.s + 0.5);
x.s = s; x.s = s;
} }
x.tz = 0; x.tz = 0;
x.validJD = 0; x.validJD = 0;
computeJD(&x); computeJD(&x);
t = (x.rJD-2440587.5)*86400.0 + 0.5; t = x.iJD/1000 - 21086676*(i64)10000;
#ifdef HAVE_LOCALTIME_R #ifdef HAVE_LOCALTIME_R
{ {
struct tm sLocal; struct tm sLocal;
@ -420,10 +460,21 @@ static double localtimeOffset(DateTime *p){
y.m = sLocal.tm_min; y.m = sLocal.tm_min;
y.s = sLocal.tm_sec; y.s = sLocal.tm_sec;
} }
#elif defined(HAVE_LOCALTIME_S)
{
struct tm sLocal;
localtime_s(&sLocal, &t);
y.Y = sLocal.tm_year + 1900;
y.M = sLocal.tm_mon + 1;
y.D = sLocal.tm_mday;
y.h = sLocal.tm_hour;
y.m = sLocal.tm_min;
y.s = sLocal.tm_sec;
}
#else #else
{ {
struct tm *pTm; struct tm *pTm;
sqlite3OsEnterMutex(); sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
pTm = localtime(&t); pTm = localtime(&t);
y.Y = pTm->tm_year + 1900; y.Y = pTm->tm_year + 1900;
y.M = pTm->tm_mon + 1; y.M = pTm->tm_mon + 1;
@ -431,7 +482,7 @@ static double localtimeOffset(DateTime *p){
y.h = pTm->tm_hour; y.h = pTm->tm_hour;
y.m = pTm->tm_min; y.m = pTm->tm_min;
y.s = pTm->tm_sec; y.s = pTm->tm_sec;
sqlite3OsLeaveMutex(); sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
} }
#endif #endif
y.validYMD = 1; y.validYMD = 1;
@ -439,8 +490,9 @@ static double localtimeOffset(DateTime *p){
y.validJD = 0; y.validJD = 0;
y.validTZ = 0; y.validTZ = 0;
computeJD(&y); computeJD(&y);
return y.rJD - x.rJD; return y.iJD - x.iJD;
} }
#endif /* SQLITE_OMIT_LOCALTIME */
/* /*
** Process a modifier to a date-time stamp. The modifiers are ** Process a modifier to a date-time stamp. The modifiers are
@ -469,11 +521,12 @@ static int parseModifier(const char *zMod, DateTime *p){
double r; double r;
char *z, zBuf[30]; char *z, zBuf[30];
z = zBuf; z = zBuf;
for(n=0; n<sizeof(zBuf)-1 && zMod[n]; n++){ for(n=0; n<ArraySize(zBuf)-1 && zMod[n]; n++){
z[n] = tolower(zMod[n]); z[n] = (char)sqlite3UpperToLower[(u8)zMod[n]];
} }
z[n] = 0; z[n] = 0;
switch( z[0] ){ switch( z[0] ){
#ifndef SQLITE_OMIT_LOCALTIME
case 'l': { case 'l': {
/* localtime /* localtime
** **
@ -482,32 +535,36 @@ static int parseModifier(const char *zMod, DateTime *p){
*/ */
if( strcmp(z, "localtime")==0 ){ if( strcmp(z, "localtime")==0 ){
computeJD(p); computeJD(p);
p->rJD += localtimeOffset(p); p->iJD += localtimeOffset(p);
clearYMD_HMS_TZ(p); clearYMD_HMS_TZ(p);
rc = 0; rc = 0;
} }
break; break;
} }
#endif
case 'u': { case 'u': {
/* /*
** unixepoch ** unixepoch
** **
** Treat the current value of p->rJD as the number of ** Treat the current value of p->iJD as the number of
** seconds since 1970. Convert to a real julian day number. ** seconds since 1970. Convert to a real julian day number.
*/ */
if( strcmp(z, "unixepoch")==0 && p->validJD ){ if( strcmp(z, "unixepoch")==0 && p->validJD ){
p->rJD = p->rJD/86400.0 + 2440587.5; p->iJD = p->iJD/86400 + 21086676*(i64)10000000;
clearYMD_HMS_TZ(p); clearYMD_HMS_TZ(p);
rc = 0; rc = 0;
}else if( strcmp(z, "utc")==0 ){
double c1;
computeJD(p);
c1 = localtimeOffset(p);
p->rJD -= c1;
clearYMD_HMS_TZ(p);
p->rJD += c1 - localtimeOffset(p);
rc = 0;
} }
#ifndef SQLITE_OMIT_LOCALTIME
else if( strcmp(z, "utc")==0 ){
sqlite3_int64 c1;
computeJD(p);
c1 = localtimeOffset(p);
p->iJD -= c1;
clearYMD_HMS_TZ(p);
p->iJD += c1 - localtimeOffset(p);
rc = 0;
}
#endif
break; break;
} }
case 'w': { case 'w': {
@ -519,16 +576,15 @@ static int parseModifier(const char *zMod, DateTime *p){
** date is already on the appropriate weekday, this is a no-op. ** date is already on the appropriate weekday, this is a no-op.
*/ */
if( strncmp(z, "weekday ", 8)==0 && getValue(&z[8],&r)>0 if( strncmp(z, "weekday ", 8)==0 && getValue(&z[8],&r)>0
&& (n=r)==r && n>=0 && r<7 ){ && (n=(int)r)==r && n>=0 && r<7 ){
int Z; sqlite3_int64 Z;
computeYMD_HMS(p); computeYMD_HMS(p);
p->validTZ = 0; p->validTZ = 0;
p->validJD = 0; p->validJD = 0;
computeJD(p); computeJD(p);
Z = p->rJD + 1.5; Z = ((p->iJD + 129600000)/86400000) % 7;
Z %= 7;
if( Z>n ) Z -= 7; if( Z>n ) Z -= 7;
p->rJD += n - Z; p->iJD += (n - Z)*86400000;
clearYMD_HMS_TZ(p); clearYMD_HMS_TZ(p);
rc = 0; rc = 0;
} }
@ -584,52 +640,52 @@ static int parseModifier(const char *zMod, DateTime *p){
*/ */
const char *z2 = z; const char *z2 = z;
DateTime tx; DateTime tx;
int day; sqlite3_int64 day;
if( !isdigit(*(u8*)z2) ) z2++; if( !isdigit(*(u8*)z2) ) z2++;
memset(&tx, 0, sizeof(tx)); memset(&tx, 0, sizeof(tx));
if( parseHhMmSs(z2, &tx) ) break; if( parseHhMmSs(z2, &tx) ) break;
computeJD(&tx); computeJD(&tx);
tx.rJD -= 0.5; tx.iJD -= 43200000;
day = (int)tx.rJD; day = tx.iJD/86400000;
tx.rJD -= day; tx.iJD -= day*86400000;
if( z[0]=='-' ) tx.rJD = -tx.rJD; if( z[0]=='-' ) tx.iJD = -tx.iJD;
computeJD(p); computeJD(p);
clearYMD_HMS_TZ(p); clearYMD_HMS_TZ(p);
p->rJD += tx.rJD; p->iJD += tx.iJD;
rc = 0; rc = 0;
break; break;
} }
z += n; z += n;
while( isspace(*(u8*)z) ) z++; while( isspace(*(u8*)z) ) z++;
n = strlen(z); n = sqlite3Strlen30(z);
if( n>10 || n<3 ) break; if( n>10 || n<3 ) break;
if( z[n-1]=='s' ){ z[n-1] = 0; n--; } if( z[n-1]=='s' ){ z[n-1] = 0; n--; }
computeJD(p); computeJD(p);
rc = 0; rc = 0;
if( n==3 && strcmp(z,"day")==0 ){ if( n==3 && strcmp(z,"day")==0 ){
p->rJD += r; p->iJD += (sqlite3_int64)(r*86400000.0 + 0.5);
}else if( n==4 && strcmp(z,"hour")==0 ){ }else if( n==4 && strcmp(z,"hour")==0 ){
p->rJD += r/24.0; p->iJD += (sqlite3_int64)(r*(86400000.0/24.0) + 0.5);
}else if( n==6 && strcmp(z,"minute")==0 ){ }else if( n==6 && strcmp(z,"minute")==0 ){
p->rJD += r/(24.0*60.0); p->iJD += (sqlite3_int64)(r*(86400000.0/(24.0*60.0)) + 0.5);
}else if( n==6 && strcmp(z,"second")==0 ){ }else if( n==6 && strcmp(z,"second")==0 ){
p->rJD += r/(24.0*60.0*60.0); p->iJD += (sqlite3_int64)(r*(86400000.0/(24.0*60.0*60.0)) + 0.5);
}else if( n==5 && strcmp(z,"month")==0 ){ }else if( n==5 && strcmp(z,"month")==0 ){
int x, y; int x, y;
computeYMD_HMS(p); computeYMD_HMS(p);
p->M += r; p->M += (int)r;
x = p->M>0 ? (p->M-1)/12 : (p->M-12)/12; x = p->M>0 ? (p->M-1)/12 : (p->M-12)/12;
p->Y += x; p->Y += x;
p->M -= x*12; p->M -= x*12;
p->validJD = 0; p->validJD = 0;
computeJD(p); computeJD(p);
y = r; y = (int)r;
if( y!=r ){ if( y!=r ){
p->rJD += (r - y)*30.0; p->iJD += (sqlite3_int64)((r - y)*30.0*86400000.0 + 0.5);
} }
}else if( n==4 && strcmp(z,"year")==0 ){ }else if( n==4 && strcmp(z,"year")==0 ){
computeYMD_HMS(p); computeYMD_HMS(p);
p->Y += r; p->Y += (int)r;
p->validJD = 0; p->validJD = 0;
computeJD(p); computeJD(p);
}else{ }else{
@ -650,13 +706,31 @@ static int parseModifier(const char *zMod, DateTime *p){
** argv[1] and following are modifiers. Parse them all and write ** argv[1] and following are modifiers. Parse them all and write
** the resulting time into the DateTime structure p. Return 0 ** the resulting time into the DateTime structure p. Return 0
** on success and 1 if there are any errors. ** on success and 1 if there are any errors.
**
** If there are zero parameters (if even argv[0] is undefined)
** then assume a default value of "now" for argv[0].
*/ */
static int isDate(int argc, sqlite3_value **argv, DateTime *p){ static int isDate(
sqlite3_context *context,
int argc,
sqlite3_value **argv,
DateTime *p
){
int i; int i;
const unsigned char *z; const unsigned char *z;
if( argc==0 ) return 1; int eType;
if( (z = sqlite3_value_text(argv[0]))==0 || parseDateOrTime((char*)z, p) ){ memset(p, 0, sizeof(*p));
return 1; if( argc==0 ){
setDateTimeToCurrent(context, p);
}else if( (eType = sqlite3_value_type(argv[0]))==SQLITE_FLOAT
|| eType==SQLITE_INTEGER ){
p->iJD = (sqlite3_int64)(sqlite3_value_double(argv[0])*86400000.0 + 0.5);
p->validJD = 1;
}else{
z = sqlite3_value_text(argv[0]);
if( !z || parseDateOrTime(context, (char*)z, p) ){
return 1;
}
} }
for(i=1; i<argc; i++){ for(i=1; i<argc; i++){
if( (z = sqlite3_value_text(argv[i]))==0 || parseModifier((char*)z, p) ){ if( (z = sqlite3_value_text(argv[i]))==0 || parseModifier((char*)z, p) ){
@ -683,9 +757,9 @@ static void juliandayFunc(
sqlite3_value **argv sqlite3_value **argv
){ ){
DateTime x; DateTime x;
if( isDate(argc, argv, &x)==0 ){ if( isDate(context, argc, argv, &x)==0 ){
computeJD(&x); computeJD(&x);
sqlite3_result_double(context, x.rJD); sqlite3_result_double(context, x.iJD/86400000.0);
} }
} }
@ -700,7 +774,7 @@ static void datetimeFunc(
sqlite3_value **argv sqlite3_value **argv
){ ){
DateTime x; DateTime x;
if( isDate(argc, argv, &x)==0 ){ if( isDate(context, argc, argv, &x)==0 ){
char zBuf[100]; char zBuf[100];
computeYMD_HMS(&x); computeYMD_HMS(&x);
sqlite3_snprintf(sizeof(zBuf), zBuf, "%04d-%02d-%02d %02d:%02d:%02d", sqlite3_snprintf(sizeof(zBuf), zBuf, "%04d-%02d-%02d %02d:%02d:%02d",
@ -720,7 +794,7 @@ static void timeFunc(
sqlite3_value **argv sqlite3_value **argv
){ ){
DateTime x; DateTime x;
if( isDate(argc, argv, &x)==0 ){ if( isDate(context, argc, argv, &x)==0 ){
char zBuf[100]; char zBuf[100];
computeHMS(&x); computeHMS(&x);
sqlite3_snprintf(sizeof(zBuf), zBuf, "%02d:%02d:%02d", x.h, x.m, (int)x.s); sqlite3_snprintf(sizeof(zBuf), zBuf, "%02d:%02d:%02d", x.h, x.m, (int)x.s);
@ -739,7 +813,7 @@ static void dateFunc(
sqlite3_value **argv sqlite3_value **argv
){ ){
DateTime x; DateTime x;
if( isDate(argc, argv, &x)==0 ){ if( isDate(context, argc, argv, &x)==0 ){
char zBuf[100]; char zBuf[100];
computeYMD(&x); computeYMD(&x);
sqlite3_snprintf(sizeof(zBuf), zBuf, "%04d-%02d-%02d", x.Y, x.M, x.D); sqlite3_snprintf(sizeof(zBuf), zBuf, "%04d-%02d-%02d", x.Y, x.M, x.D);
@ -773,11 +847,13 @@ static void strftimeFunc(
){ ){
DateTime x; DateTime x;
u64 n; u64 n;
int i, j; size_t i,j;
char *z; char *z;
sqlite3 *db;
const char *zFmt = (const char*)sqlite3_value_text(argv[0]); const char *zFmt = (const char*)sqlite3_value_text(argv[0]);
char zBuf[100]; char zBuf[100];
if( zFmt==0 || isDate(argc-1, argv+1, &x) ) return; if( zFmt==0 || isDate(context, argc-1, argv+1, &x) ) return;
db = sqlite3_context_db_handle(context);
for(i=0, n=1; zFmt[i]; i++, n++){ for(i=0, n=1; zFmt[i]; i++, n++){
if( zFmt[i]=='%' ){ if( zFmt[i]=='%' ){
switch( zFmt[i+1] ){ switch( zFmt[i+1] ){
@ -813,12 +889,15 @@ static void strftimeFunc(
} }
if( n<sizeof(zBuf) ){ if( n<sizeof(zBuf) ){
z = zBuf; z = zBuf;
}else if( n>SQLITE_MAX_LENGTH ){ }else if( n>(u64)db->aLimit[SQLITE_LIMIT_LENGTH] ){
sqlite3_result_error_toobig(context); sqlite3_result_error_toobig(context);
return; return;
}else{ }else{
z = sqliteMalloc( n ); z = sqlite3DbMallocRaw(db, (int)n);
if( z==0 ) return; if( z==0 ){
sqlite3_result_error_nomem(context);
return;
}
} }
computeJD(&x); computeJD(&x);
computeYMD_HMS(&x); computeYMD_HMS(&x);
@ -833,7 +912,7 @@ static void strftimeFunc(
double s = x.s; double s = x.s;
if( s>59.999 ) s = 59.999; if( s>59.999 ) s = 59.999;
sqlite3_snprintf(7, &z[j],"%06.3f", s); sqlite3_snprintf(7, &z[j],"%06.3f", s);
j += strlen(&z[j]); j += sqlite3Strlen30(&z[j]);
break; break;
} }
case 'H': sqlite3_snprintf(3, &z[j],"%02d",x.h); j+=2; break; case 'H': sqlite3_snprintf(3, &z[j],"%02d",x.h); j+=2; break;
@ -845,10 +924,10 @@ static void strftimeFunc(
y.M = 1; y.M = 1;
y.D = 1; y.D = 1;
computeJD(&y); computeJD(&y);
nDay = x.rJD - y.rJD + 0.5; nDay = (int)((x.iJD-y.iJD+43200000)/86400000);
if( zFmt[i]=='W' ){ if( zFmt[i]=='W' ){
int wd; /* 0=Monday, 1=Tuesday, ... 6=Sunday */ int wd; /* 0=Monday, 1=Tuesday, ... 6=Sunday */
wd = ((int)(x.rJD+0.5)) % 7; wd = (int)(((x.iJD+43200000)/86400000)%7);
sqlite3_snprintf(3, &z[j],"%02d",(nDay+7-wd)/7); sqlite3_snprintf(3, &z[j],"%02d",(nDay+7-wd)/7);
j += 2; j += 2;
}else{ }else{
@ -858,30 +937,34 @@ static void strftimeFunc(
break; break;
} }
case 'J': { case 'J': {
sqlite3_snprintf(20, &z[j],"%.16g",x.rJD); sqlite3_snprintf(20, &z[j],"%.16g",x.iJD/86400000.0);
j+=strlen(&z[j]); j+=sqlite3Strlen30(&z[j]);
break; break;
} }
case 'm': sqlite3_snprintf(3, &z[j],"%02d",x.M); j+=2; break; case 'm': sqlite3_snprintf(3, &z[j],"%02d",x.M); j+=2; break;
case 'M': sqlite3_snprintf(3, &z[j],"%02d",x.m); j+=2; break; case 'M': sqlite3_snprintf(3, &z[j],"%02d",x.m); j+=2; break;
case 's': { case 's': {
sqlite3_snprintf(30,&z[j],"%d", sqlite3_snprintf(30,&z[j],"%d",
(int)((x.rJD-2440587.5)*86400.0 + 0.5)); (int)(x.iJD/1000.0 - 210866760000.0));
j += strlen(&z[j]); j += sqlite3Strlen30(&z[j]);
break; break;
} }
case 'S': sqlite3_snprintf(3,&z[j],"%02d",(int)x.s); j+=2; break; case 'S': sqlite3_snprintf(3,&z[j],"%02d",(int)x.s); j+=2; break;
case 'w': z[j++] = (((int)(x.rJD+1.5)) % 7) + '0'; break; case 'w': {
case 'Y': sqlite3_snprintf(5,&z[j],"%04d",x.Y); j+=strlen(&z[j]);break; z[j++] = (char)(((x.iJD+129600000)/86400000) % 7) + '0';
case '%': z[j++] = '%'; break; break;
}
case 'Y': {
sqlite3_snprintf(5,&z[j],"%04d",x.Y); j+=sqlite3Strlen30(&z[j]);
break;
}
default: z[j++] = '%'; break;
} }
} }
} }
z[j] = 0; z[j] = 0;
sqlite3_result_text(context, z, -1, SQLITE_TRANSIENT); sqlite3_result_text(context, z, -1,
if( z!=zBuf ){ z==zBuf ? SQLITE_TRANSIENT : SQLITE_DYNAMIC);
sqliteFree(z);
}
} }
/* /*
@ -891,15 +974,11 @@ static void strftimeFunc(
*/ */
static void ctimeFunc( static void ctimeFunc(
sqlite3_context *context, sqlite3_context *context,
int argc, int NotUsed,
sqlite3_value **argv sqlite3_value **NotUsed2
){ ){
sqlite3_value *pVal = sqlite3ValueNew(); UNUSED_PARAMETER2(NotUsed, NotUsed2);
if( pVal ){ timeFunc(context, 0, 0);
sqlite3ValueSetStr(pVal, -1, "now", SQLITE_UTF8, SQLITE_STATIC);
timeFunc(context, 1, &pVal);
sqlite3ValueFree(pVal);
}
} }
/* /*
@ -909,15 +988,11 @@ static void ctimeFunc(
*/ */
static void cdateFunc( static void cdateFunc(
sqlite3_context *context, sqlite3_context *context,
int argc, int NotUsed,
sqlite3_value **argv sqlite3_value **NotUsed2
){ ){
sqlite3_value *pVal = sqlite3ValueNew(); UNUSED_PARAMETER2(NotUsed, NotUsed2);
if( pVal ){ dateFunc(context, 0, 0);
sqlite3ValueSetStr(pVal, -1, "now", SQLITE_UTF8, SQLITE_STATIC);
dateFunc(context, 1, &pVal);
sqlite3ValueFree(pVal);
}
} }
/* /*
@ -927,15 +1002,11 @@ static void cdateFunc(
*/ */
static void ctimestampFunc( static void ctimestampFunc(
sqlite3_context *context, sqlite3_context *context,
int argc, int NotUsed,
sqlite3_value **argv sqlite3_value **NotUsed2
){ ){
sqlite3_value *pVal = sqlite3ValueNew(); UNUSED_PARAMETER2(NotUsed, NotUsed2);
if( pVal ){ datetimeFunc(context, 0, 0);
sqlite3ValueSetStr(pVal, -1, "now", SQLITE_UTF8, SQLITE_STATIC);
datetimeFunc(context, 1, &pVal);
sqlite3ValueFree(pVal);
}
} }
#endif /* !defined(SQLITE_OMIT_DATETIME_FUNCS) */ #endif /* !defined(SQLITE_OMIT_DATETIME_FUNCS) */
@ -958,18 +1029,13 @@ static void currentTimeFunc(
){ ){
time_t t; time_t t;
char *zFormat = (char *)sqlite3_user_data(context); char *zFormat = (char *)sqlite3_user_data(context);
sqlite3 *db;
double rT;
char zBuf[20]; char zBuf[20];
time(&t); db = sqlite3_context_db_handle(context);
#ifdef SQLITE_TEST sqlite3OsCurrentTime(db->pVfs, &rT);
{ t = 86400.0*(rT - 2440587.5) + 0.5;
extern int sqlite3_current_time; /* See os_XXX.c */
if( sqlite3_current_time ){
t = sqlite3_current_time;
}
}
#endif
#ifdef HAVE_GMTIME_R #ifdef HAVE_GMTIME_R
{ {
struct tm sNow; struct tm sNow;
@ -979,10 +1045,10 @@ static void currentTimeFunc(
#else #else
{ {
struct tm *pTm; struct tm *pTm;
sqlite3OsEnterMutex(); sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
pTm = gmtime(&t); pTm = gmtime(&t);
strftime(zBuf, 20, zFormat, pTm); strftime(zBuf, 20, zFormat, pTm);
sqlite3OsLeaveMutex(); sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
} }
#endif #endif
@ -995,42 +1061,28 @@ static void currentTimeFunc(
** functions. This should be the only routine in this file with ** functions. This should be the only routine in this file with
** external linkage. ** external linkage.
*/ */
void sqlite3RegisterDateTimeFunctions(sqlite3 *db){ void sqlite3RegisterDateTimeFunctions(void){
static SQLITE_WSD FuncDef aDateTimeFuncs[] = {
#ifndef SQLITE_OMIT_DATETIME_FUNCS #ifndef SQLITE_OMIT_DATETIME_FUNCS
static const struct { FUNCTION(julianday, -1, 0, 0, juliandayFunc ),
char *zName; FUNCTION(date, -1, 0, 0, dateFunc ),
int nArg; FUNCTION(time, -1, 0, 0, timeFunc ),
void (*xFunc)(sqlite3_context*,int,sqlite3_value**); FUNCTION(datetime, -1, 0, 0, datetimeFunc ),
} aFuncs[] = { FUNCTION(strftime, -1, 0, 0, strftimeFunc ),
{ "julianday", -1, juliandayFunc }, FUNCTION(current_time, 0, 0, 0, ctimeFunc ),
{ "date", -1, dateFunc }, FUNCTION(current_timestamp, 0, 0, 0, ctimestampFunc),
{ "time", -1, timeFunc }, FUNCTION(current_date, 0, 0, 0, cdateFunc ),
{ "datetime", -1, datetimeFunc },
{ "strftime", -1, strftimeFunc },
{ "current_time", 0, ctimeFunc },
{ "current_timestamp", 0, ctimestampFunc },
{ "current_date", 0, cdateFunc },
};
int i;
for(i=0; i<sizeof(aFuncs)/sizeof(aFuncs[0]); i++){
sqlite3CreateFunc(db, aFuncs[i].zName, aFuncs[i].nArg,
SQLITE_UTF8, 0, aFuncs[i].xFunc, 0, 0);
}
#else #else
static const struct { STR_FUNCTION(current_time, 0, "%H:%M:%S", 0, currentTimeFunc),
char *zName; STR_FUNCTION(current_timestamp, 0, "%Y-%m-%d", 0, currentTimeFunc),
char *zFormat; STR_FUNCTION(current_date, 0, "%Y-%m-%d %H:%M:%S", 0, currentTimeFunc),
} aFuncs[] = { #endif
{ "current_time", "%H:%M:%S" },
{ "current_date", "%Y-%m-%d" },
{ "current_timestamp", "%Y-%m-%d %H:%M:%S" }
}; };
int i; int i;
FuncDefHash *pHash = &GLOBAL(FuncDefHash, sqlite3GlobalFunctions);
FuncDef *aFunc = (FuncDef*)&GLOBAL(FuncDef, aDateTimeFuncs);
for(i=0; i<sizeof(aFuncs)/sizeof(aFuncs[0]); i++){ for(i=0; i<ArraySize(aDateTimeFuncs); i++){
sqlite3CreateFunc(db, aFuncs[i].zName, 0, SQLITE_UTF8, sqlite3FuncDefInsert(pHash, &aFunc[i]);
aFuncs[i].zFormat, currentTimeFunc, 0, 0);
} }
#endif
} }

457
delete.c
View file

@ -12,7 +12,7 @@
** This file contains C code routines that are called by the parser ** This file contains C code routines that are called by the parser
** in order to generate code for DELETE FROM statements. ** in order to generate code for DELETE FROM statements.
** **
** $Id: delete.c,v 1.129 2007/04/16 15:06:25 danielk1977 Exp $ ** $Id: delete.c,v 1.191 2008/12/23 23:56:22 drh Exp $
*/ */
#include "sqliteInt.h" #include "sqliteInt.h"
@ -22,16 +22,17 @@
** are found, return a pointer to the last table. ** are found, return a pointer to the last table.
*/ */
Table *sqlite3SrcListLookup(Parse *pParse, SrcList *pSrc){ Table *sqlite3SrcListLookup(Parse *pParse, SrcList *pSrc){
Table *pTab = 0; struct SrcList_item *pItem = pSrc->a;
int i; Table *pTab;
struct SrcList_item *pItem; assert( pItem && pSrc->nSrc==1 );
for(i=0, pItem=pSrc->a; i<pSrc->nSrc; i++, pItem++){ pTab = sqlite3LocateTable(pParse, 0, pItem->zName, pItem->zDatabase);
pTab = sqlite3LocateTable(pParse, pItem->zName, pItem->zDatabase); sqlite3DeleteTable(pItem->pTab);
sqlite3DeleteTable(pItem->pTab); pItem->pTab = pTab;
pItem->pTab = pTab; if( pTab ){
if( pTab ){ pTab->nRef++;
pTab->nRef++; }
} if( sqlite3IndexedByLookup(pParse, pItem) ){
pTab = 0;
} }
return pTab; return pTab;
} }
@ -42,7 +43,8 @@ Table *sqlite3SrcListLookup(Parse *pParse, SrcList *pSrc){
** writable return 0; ** writable return 0;
*/ */
int sqlite3IsReadOnly(Parse *pParse, Table *pTab, int viewOk){ int sqlite3IsReadOnly(Parse *pParse, Table *pTab, int viewOk){
if( (pTab->readOnly && (pParse->db->flags & SQLITE_WriteSchema)==0 if( ((pTab->tabFlags & TF_Readonly)!=0
&& (pParse->db->flags & SQLITE_WriteSchema)==0
&& pParse->nested==0) && pParse->nested==0)
#ifndef SQLITE_OMIT_VIRTUALTABLE #ifndef SQLITE_OMIT_VIRTUALTABLE
|| (pTab->pMod && pTab->pMod->pModule->xUpdate==0) || (pTab->pMod && pTab->pMod->pModule->xUpdate==0)
@ -74,14 +76,138 @@ void sqlite3OpenTable(
if( IsVirtual(pTab) ) return; if( IsVirtual(pTab) ) return;
v = sqlite3GetVdbe(p); v = sqlite3GetVdbe(p);
assert( opcode==OP_OpenWrite || opcode==OP_OpenRead ); assert( opcode==OP_OpenWrite || opcode==OP_OpenRead );
sqlite3TableLock(p, iDb, pTab->tnum, (opcode==OP_OpenWrite), pTab->zName); sqlite3TableLock(p, iDb, pTab->tnum, (opcode==OP_OpenWrite)?1:0, pTab->zName);
sqlite3VdbeAddOp(v, OP_Integer, iDb, 0); sqlite3VdbeAddOp2(v, OP_SetNumColumns, 0, pTab->nCol);
VdbeComment((v, "# %s", pTab->zName)); sqlite3VdbeAddOp3(v, opcode, iCur, pTab->tnum, iDb);
sqlite3VdbeAddOp(v, opcode, iCur, pTab->tnum); VdbeComment((v, "%s", pTab->zName));
sqlite3VdbeAddOp(v, OP_SetNumColumns, iCur, pTab->nCol);
} }
#if !defined(SQLITE_OMIT_VIEW) && !defined(SQLITE_OMIT_TRIGGER)
/*
** Evaluate a view and store its result in an ephemeral table. The
** pWhere argument is an optional WHERE clause that restricts the
** set of rows in the view that are to be added to the ephemeral table.
*/
void sqlite3MaterializeView(
Parse *pParse, /* Parsing context */
Table *pView, /* View definition */
Expr *pWhere, /* Optional WHERE clause to be added */
int iCur /* Cursor number for ephemerial table */
){
SelectDest dest;
Select *pDup;
sqlite3 *db = pParse->db;
pDup = sqlite3SelectDup(db, pView->pSelect);
if( pWhere ){
SrcList *pFrom;
Token viewName;
pWhere = sqlite3ExprDup(db, pWhere);
viewName.z = (u8*)pView->zName;
viewName.n = (unsigned int)sqlite3Strlen30((const char*)viewName.z);
pFrom = sqlite3SrcListAppendFromTerm(pParse, 0, 0, 0, &viewName, pDup, 0,0);
pDup = sqlite3SelectNew(pParse, 0, pFrom, pWhere, 0, 0, 0, 0, 0, 0);
}
sqlite3SelectDestInit(&dest, SRT_EphemTab, iCur);
sqlite3Select(pParse, pDup, &dest);
sqlite3SelectDelete(db, pDup);
}
#endif /* !defined(SQLITE_OMIT_VIEW) && !defined(SQLITE_OMIT_TRIGGER) */
#if defined(SQLITE_ENABLE_UPDATE_DELETE_LIMIT) && !defined(SQLITE_OMIT_SUBQUERY)
/*
** Generate an expression tree to implement the WHERE, ORDER BY,
** and LIMIT/OFFSET portion of DELETE and UPDATE statements.
**
** DELETE FROM table_wxyz WHERE a<5 ORDER BY a LIMIT 1;
** \__________________________/
** pLimitWhere (pInClause)
*/
Expr *sqlite3LimitWhere(
Parse *pParse, /* The parser context */
SrcList *pSrc, /* the FROM clause -- which tables to scan */
Expr *pWhere, /* The WHERE clause. May be null */
ExprList *pOrderBy, /* The ORDER BY clause. May be null */
Expr *pLimit, /* The LIMIT clause. May be null */
Expr *pOffset, /* The OFFSET clause. May be null */
char *zStmtType /* Either DELETE or UPDATE. For error messages. */
){
Expr *pWhereRowid = NULL; /* WHERE rowid .. */
Expr *pInClause = NULL; /* WHERE rowid IN ( select ) */
Expr *pSelectRowid = NULL; /* SELECT rowid ... */
ExprList *pEList = NULL; /* Expression list contaning only pSelectRowid */
SrcList *pSelectSrc = NULL; /* SELECT rowid FROM x ... (dup of pSrc) */
Select *pSelect = NULL; /* Complete SELECT tree */
/* Check that there isn't an ORDER BY without a LIMIT clause.
*/
if( pOrderBy && (pLimit == 0) ) {
sqlite3ErrorMsg(pParse, "ORDER BY without LIMIT on %s", zStmtType);
pParse->parseError = 1;
goto limit_where_cleanup_2;
}
/* We only need to generate a select expression if there
** is a limit/offset term to enforce.
*/
if( pLimit == 0 ) {
/* if pLimit is null, pOffset will always be null as well. */
assert( pOffset == 0 );
return pWhere;
}
/* Generate a select expression tree to enforce the limit/offset
** term for the DELETE or UPDATE statement. For example:
** DELETE FROM table_a WHERE col1=1 ORDER BY col2 LIMIT 1 OFFSET 1
** becomes:
** DELETE FROM table_a WHERE rowid IN (
** SELECT rowid FROM table_a WHERE col1=1 ORDER BY col2 LIMIT 1 OFFSET 1
** );
*/
pSelectRowid = sqlite3Expr(pParse->db, TK_ROW, 0, 0, 0);
if( pSelectRowid == 0 ) goto limit_where_cleanup_2;
pEList = sqlite3ExprListAppend(pParse, 0, pSelectRowid, 0);
if( pEList == 0 ) goto limit_where_cleanup_2;
/* duplicate the FROM clause as it is needed by both the DELETE/UPDATE tree
** and the SELECT subtree. */
pSelectSrc = sqlite3SrcListDup(pParse->db, pSrc);
if( pSelectSrc == 0 ) {
sqlite3ExprListDelete(pParse->db, pEList);
goto limit_where_cleanup_2;
}
/* generate the SELECT expression tree. */
pSelect = sqlite3SelectNew(pParse,pEList,pSelectSrc,pWhere,0,0,pOrderBy,0,pLimit,pOffset);
if( pSelect == 0 ) return 0;
/* now generate the new WHERE rowid IN clause for the DELETE/UDPATE */
pWhereRowid = sqlite3Expr(pParse->db, TK_ROW, 0, 0, 0);
if( pWhereRowid == 0 ) goto limit_where_cleanup_1;
pInClause = sqlite3PExpr(pParse, TK_IN, pWhereRowid, 0, 0);
if( pInClause == 0 ) goto limit_where_cleanup_1;
pInClause->pSelect = pSelect;
sqlite3ExprSetHeight(pParse, pInClause);
return pInClause;
/* something went wrong. clean up anything allocated. */
limit_where_cleanup_1:
sqlite3SelectDelete(pParse->db, pSelect);
return 0;
limit_where_cleanup_2:
sqlite3ExprDelete(pParse->db, pWhere);
sqlite3ExprListDelete(pParse->db, pOrderBy);
sqlite3ExprDelete(pParse->db, pLimit);
sqlite3ExprDelete(pParse->db, pOffset);
return 0;
}
#endif /* defined(SQLITE_ENABLE_UPDATE_DELETE_LIMIT) && !defined(SQLITE_OMIT_SUBQUERY) */
/* /*
** Generate code for a DELETE FROM statement. ** Generate code for a DELETE FROM statement.
** **
@ -107,18 +233,24 @@ void sqlite3DeleteFrom(
int oldIdx = -1; /* Cursor for the OLD table of AFTER triggers */ int oldIdx = -1; /* Cursor for the OLD table of AFTER triggers */
NameContext sNC; /* Name context to resolve expressions in */ NameContext sNC; /* Name context to resolve expressions in */
int iDb; /* Database number */ int iDb; /* Database number */
int memCnt = 0; /* Memory cell used for change counting */ int memCnt = -1; /* Memory cell used for change counting */
int rcauth; /* Value returned by authorization callback */
#ifndef SQLITE_OMIT_TRIGGER #ifndef SQLITE_OMIT_TRIGGER
int isView; /* True if attempting to delete from a view */ int isView; /* True if attempting to delete from a view */
int triggers_exist = 0; /* True if any triggers exist */ int triggers_exist = 0; /* True if any triggers exist */
#endif #endif
int iBeginAfterTrigger = 0; /* Address of after trigger program */
int iEndAfterTrigger = 0; /* Exit of after trigger program */
int iBeginBeforeTrigger = 0; /* Address of before trigger program */
int iEndBeforeTrigger = 0; /* Exit of before trigger program */
u32 old_col_mask = 0; /* Mask of OLD.* columns in use */
sContext.pParse = 0; sContext.pParse = 0;
if( pParse->nErr || sqlite3MallocFailed() ){ db = pParse->db;
if( pParse->nErr || db->mallocFailed ){
goto delete_from_cleanup; goto delete_from_cleanup;
} }
db = pParse->db;
assert( pTabList->nSrc==1 ); assert( pTabList->nSrc==1 );
/* Locate the table which we want to delete. This table has to be /* Locate the table which we want to delete. This table has to be
@ -133,7 +265,7 @@ void sqlite3DeleteFrom(
** deleted from is a view ** deleted from is a view
*/ */
#ifndef SQLITE_OMIT_TRIGGER #ifndef SQLITE_OMIT_TRIGGER
triggers_exist = sqlite3TriggersExist(pParse, pTab, TK_DELETE, 0); triggers_exist = sqlite3TriggersExist(pTab, TK_DELETE, 0);
isView = pTab->pSelect!=0; isView = pTab->pSelect!=0;
#else #else
# define triggers_exist 0 # define triggers_exist 0
@ -150,9 +282,12 @@ void sqlite3DeleteFrom(
iDb = sqlite3SchemaToIndex(db, pTab->pSchema); iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
assert( iDb<db->nDb ); assert( iDb<db->nDb );
zDb = db->aDb[iDb].zName; zDb = db->aDb[iDb].zName;
if( sqlite3AuthCheck(pParse, SQLITE_DELETE, pTab->zName, 0, zDb) ){ rcauth = sqlite3AuthCheck(pParse, SQLITE_DELETE, pTab->zName, 0, zDb);
assert( rcauth==SQLITE_OK || rcauth==SQLITE_DENY || rcauth==SQLITE_IGNORE );
if( rcauth==SQLITE_DENY ){
goto delete_from_cleanup; goto delete_from_cleanup;
} }
assert(!isView || triggers_exist);
/* If pTab is really a view, make sure it has been initialized. /* If pTab is really a view, make sure it has been initialized.
*/ */
@ -166,15 +301,12 @@ void sqlite3DeleteFrom(
oldIdx = pParse->nTab++; oldIdx = pParse->nTab++;
} }
/* Resolve the column names in the WHERE clause. /* Assign cursor number to the table and all its indices.
*/ */
assert( pTabList->nSrc==1 ); assert( pTabList->nSrc==1 );
iCur = pTabList->a[0].iCursor = pParse->nTab++; iCur = pTabList->a[0].iCursor = pParse->nTab++;
memset(&sNC, 0, sizeof(sNC)); for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
sNC.pParse = pParse; pParse->nTab++;
sNC.pSrcList = pTabList;
if( sqlite3ExprResolveNames(&sNC, pWhere) ){
goto delete_from_cleanup;
} }
/* Start the view context /* Start the view context
@ -192,79 +324,90 @@ void sqlite3DeleteFrom(
if( pParse->nested==0 ) sqlite3VdbeCountChanges(v); if( pParse->nested==0 ) sqlite3VdbeCountChanges(v);
sqlite3BeginWriteOperation(pParse, triggers_exist, iDb); sqlite3BeginWriteOperation(pParse, triggers_exist, iDb);
if( triggers_exist ){
int orconf = ((pParse->trigStack)?pParse->trigStack->orconf:OE_Default);
int iGoto = sqlite3VdbeAddOp0(v, OP_Goto);
addr = sqlite3VdbeMakeLabel(v);
iBeginBeforeTrigger = sqlite3VdbeCurrentAddr(v);
(void)sqlite3CodeRowTrigger(pParse, TK_DELETE, 0, TRIGGER_BEFORE, pTab,
-1, oldIdx, orconf, addr, &old_col_mask, 0);
iEndBeforeTrigger = sqlite3VdbeAddOp0(v, OP_Goto);
iBeginAfterTrigger = sqlite3VdbeCurrentAddr(v);
(void)sqlite3CodeRowTrigger(pParse, TK_DELETE, 0, TRIGGER_AFTER, pTab, -1,
oldIdx, orconf, addr, &old_col_mask, 0);
iEndAfterTrigger = sqlite3VdbeAddOp0(v, OP_Goto);
sqlite3VdbeJumpHere(v, iGoto);
}
/* If we are trying to delete from a view, realize that view into /* If we are trying to delete from a view, realize that view into
** a ephemeral table. ** a ephemeral table.
*/ */
#if !defined(SQLITE_OMIT_VIEW) && !defined(SQLITE_OMIT_TRIGGER)
if( isView ){ if( isView ){
Select *pView = sqlite3SelectDup(pTab->pSelect); sqlite3MaterializeView(pParse, pTab, pWhere, iCur);
sqlite3Select(pParse, pView, SRT_EphemTab, iCur, 0, 0, 0, 0); }
sqlite3SelectDelete(pView); #endif
/* Resolve the column names in the WHERE clause.
*/
memset(&sNC, 0, sizeof(sNC));
sNC.pParse = pParse;
sNC.pSrcList = pTabList;
if( sqlite3ResolveExprNames(&sNC, pWhere) ){
goto delete_from_cleanup;
} }
/* Initialize the counter of the number of rows deleted, if /* Initialize the counter of the number of rows deleted, if
** we are counting rows. ** we are counting rows.
*/ */
if( db->flags & SQLITE_CountRows ){ if( db->flags & SQLITE_CountRows ){
memCnt = pParse->nMem++; memCnt = ++pParse->nMem;
sqlite3VdbeAddOp(v, OP_MemInt, 0, memCnt); sqlite3VdbeAddOp2(v, OP_Integer, 0, memCnt);
} }
#ifndef SQLITE_OMIT_TRUNCATE_OPTIMIZATION
/* Special case: A DELETE without a WHERE clause deletes everything. /* Special case: A DELETE without a WHERE clause deletes everything.
** It is easier just to erase the whole table. Note, however, that ** It is easier just to erase the whole table. Note, however, that
** this means that the row change count will be incorrect. ** this means that the row change count will be incorrect.
*/ */
if( pWhere==0 && !triggers_exist && !IsVirtual(pTab) ){ if( rcauth==SQLITE_OK && pWhere==0 && !triggers_exist && !IsVirtual(pTab) ){
if( db->flags & SQLITE_CountRows ){ assert( !isView );
/* If counting rows deleted, just count the total number of sqlite3VdbeAddOp3(v, OP_Clear, pTab->tnum, iDb, memCnt);
** entries in the table. */ if( !pParse->nested ){
int endOfLoop = sqlite3VdbeMakeLabel(v); sqlite3VdbeChangeP4(v, -1, pTab->zName, P4_STATIC);
int addr2;
if( !isView ){
sqlite3OpenTable(pParse, iCur, iDb, pTab, OP_OpenRead);
}
sqlite3VdbeAddOp(v, OP_Rewind, iCur, sqlite3VdbeCurrentAddr(v)+2);
addr2 = sqlite3VdbeAddOp(v, OP_MemIncr, 1, memCnt);
sqlite3VdbeAddOp(v, OP_Next, iCur, addr2);
sqlite3VdbeResolveLabel(v, endOfLoop);
sqlite3VdbeAddOp(v, OP_Close, iCur, 0);
} }
if( !isView ){ for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
sqlite3VdbeAddOp(v, OP_Clear, pTab->tnum, iDb); assert( pIdx->pSchema==pTab->pSchema );
if( !pParse->nested ){ sqlite3VdbeAddOp2(v, OP_Clear, pIdx->tnum, iDb);
sqlite3VdbeChangeP3(v, -1, pTab->zName, P3_STATIC);
}
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
assert( pIdx->pSchema==pTab->pSchema );
sqlite3VdbeAddOp(v, OP_Clear, pIdx->tnum, iDb);
}
} }
} }else
#endif /* SQLITE_OMIT_TRUNCATE_OPTIMIZATION */
/* The usual case: There is a WHERE clause so we have to scan through /* The usual case: There is a WHERE clause so we have to scan through
** the table and pick which records to delete. ** the table and pick which records to delete.
*/ */
else{ {
/* Begin the database scan int iRowid = ++pParse->nMem; /* Used for storing rowid values. */
int iRowSet = ++pParse->nMem; /* Register for rowset of rows to delete */
/* Collect rowids of every row to be deleted.
*/ */
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 0); sqlite3VdbeAddOp2(v, OP_Null, 0, iRowSet);
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 0,
WHERE_FILL_ROWSET, iRowSet);
if( pWInfo==0 ) goto delete_from_cleanup; if( pWInfo==0 ) goto delete_from_cleanup;
/* Remember the rowid of every item to be deleted.
*/
sqlite3VdbeAddOp(v, IsVirtual(pTab) ? OP_VRowid : OP_Rowid, iCur, 0);
sqlite3VdbeAddOp(v, OP_FifoWrite, 0, 0);
if( db->flags & SQLITE_CountRows ){ if( db->flags & SQLITE_CountRows ){
sqlite3VdbeAddOp(v, OP_MemIncr, 1, memCnt); sqlite3VdbeAddOp2(v, OP_AddImm, memCnt, 1);
} }
/* End the database scan loop.
*/
sqlite3WhereEnd(pWInfo); sqlite3WhereEnd(pWInfo);
/* Open the pseudo-table used to store OLD if there are triggers. /* Open the pseudo-table used to store OLD if there are triggers.
*/ */
if( triggers_exist ){ if( triggers_exist ){
sqlite3VdbeAddOp(v, OP_OpenPseudo, oldIdx, 0); sqlite3VdbeAddOp2(v, OP_SetNumColumns, 0, pTab->nCol);
sqlite3VdbeAddOp(v, OP_SetNumColumns, oldIdx, pTab->nCol); sqlite3VdbeAddOp1(v, OP_OpenPseudo, oldIdx);
} }
/* Delete every item whose key was written to the list during the /* Delete every item whose key was written to the list during the
@ -273,52 +416,53 @@ void sqlite3DeleteFrom(
*/ */
end = sqlite3VdbeMakeLabel(v); end = sqlite3VdbeMakeLabel(v);
/* This is the beginning of the delete loop when there are if( !isView ){
** row triggers. /* Open cursors for the table we are deleting from and
** all its indices.
*/
sqlite3OpenTableAndIndices(pParse, pTab, iCur, OP_OpenWrite);
}
/* This is the beginning of the delete loop. If a trigger encounters
** an IGNORE constraint, it jumps back to here.
*/ */
if( triggers_exist ){ if( triggers_exist ){
addr = sqlite3VdbeAddOp(v, OP_FifoRead, 0, end); sqlite3VdbeResolveLabel(v, addr);
if( !isView ){ }
sqlite3VdbeAddOp(v, OP_Dup, 0, 0); addr = sqlite3VdbeAddOp3(v, OP_RowSetRead, iRowSet, end, iRowid);
sqlite3OpenTable(pParse, iCur, iDb, pTab, OP_OpenRead);
}
sqlite3VdbeAddOp(v, OP_MoveGe, iCur, 0);
sqlite3VdbeAddOp(v, OP_Rowid, iCur, 0);
sqlite3VdbeAddOp(v, OP_RowData, iCur, 0);
sqlite3VdbeAddOp(v, OP_Insert, oldIdx, 0);
if( !isView ){
sqlite3VdbeAddOp(v, OP_Close, iCur, 0);
}
(void)sqlite3CodeRowTrigger(pParse, TK_DELETE, 0, TRIGGER_BEFORE, pTab, if( triggers_exist ){
-1, oldIdx, (pParse->trigStack)?pParse->trigStack->orconf:OE_Default, int iData = ++pParse->nMem; /* For storing row data of OLD table */
addr);
/* If the record is no longer present in the table, jump to the
** next iteration of the loop through the contents of the fifo.
*/
sqlite3VdbeAddOp3(v, OP_NotExists, iCur, addr, iRowid);
/* Populate the OLD.* pseudo-table */
if( old_col_mask ){
sqlite3VdbeAddOp2(v, OP_RowData, iCur, iData);
}else{
sqlite3VdbeAddOp2(v, OP_Null, 0, iData);
}
sqlite3VdbeAddOp3(v, OP_Insert, oldIdx, iData, iRowid);
/* Jump back and run the BEFORE triggers */
sqlite3VdbeAddOp2(v, OP_Goto, 0, iBeginBeforeTrigger);
sqlite3VdbeJumpHere(v, iEndBeforeTrigger);
} }
if( !isView ){ if( !isView ){
/* Open cursors for the table we are deleting from and all its
** indices. If there are row triggers, this happens inside the
** OP_FifoRead loop because the cursor have to all be closed
** before the trigger fires. If there are no row triggers, the
** cursors are opened only once on the outside the loop.
*/
sqlite3OpenTableAndIndices(pParse, pTab, iCur, OP_OpenWrite);
/* This is the beginning of the delete loop when there are no
** row triggers */
if( !triggers_exist ){
addr = sqlite3VdbeAddOp(v, OP_FifoRead, 0, end);
}
/* Delete the row */ /* Delete the row */
#ifndef SQLITE_OMIT_VIRTUALTABLE #ifndef SQLITE_OMIT_VIRTUALTABLE
if( IsVirtual(pTab) ){ if( IsVirtual(pTab) ){
pParse->pVirtualLock = pTab; const char *pVtab = (const char *)pTab->pVtab;
sqlite3VdbeOp3(v, OP_VUpdate, 0, 1, (const char*)pTab->pVtab, P3_VTAB); sqlite3VtabMakeWritable(pParse, pTab);
sqlite3VdbeAddOp4(v, OP_VUpdate, 0, 1, iRowid, pVtab, P4_VTAB);
}else }else
#endif #endif
{ {
sqlite3GenerateRowDelete(db, v, pTab, iCur, pParse->nested==0); sqlite3GenerateRowDelete(pParse, pTab, iCur, iRowid, pParse->nested==0);
} }
} }
@ -326,27 +470,21 @@ void sqlite3DeleteFrom(
** the AFTER triggers ** the AFTER triggers
*/ */
if( triggers_exist ){ if( triggers_exist ){
if( !isView ){ /* Jump back and run the AFTER triggers */
for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){ sqlite3VdbeAddOp2(v, OP_Goto, 0, iBeginAfterTrigger);
sqlite3VdbeAddOp(v, OP_Close, iCur + i, pIdx->tnum); sqlite3VdbeJumpHere(v, iEndAfterTrigger);
}
sqlite3VdbeAddOp(v, OP_Close, iCur, 0);
}
(void)sqlite3CodeRowTrigger(pParse, TK_DELETE, 0, TRIGGER_AFTER, pTab, -1,
oldIdx, (pParse->trigStack)?pParse->trigStack->orconf:OE_Default,
addr);
} }
/* End of the delete loop */ /* End of the delete loop */
sqlite3VdbeAddOp(v, OP_Goto, 0, addr); sqlite3VdbeAddOp2(v, OP_Goto, 0, addr);
sqlite3VdbeResolveLabel(v, end); sqlite3VdbeResolveLabel(v, end);
/* Close the cursors after the loop if there are no row triggers */ /* Close the cursors after the loop if there are no row triggers */
if( !triggers_exist && !IsVirtual(pTab) ){ if( !isView && !IsVirtual(pTab) ){
for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){ for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
sqlite3VdbeAddOp(v, OP_Close, iCur + i, pIdx->tnum); sqlite3VdbeAddOp2(v, OP_Close, iCur + i, pIdx->tnum);
} }
sqlite3VdbeAddOp(v, OP_Close, iCur, 0); sqlite3VdbeAddOp1(v, OP_Close, iCur);
} }
} }
@ -356,16 +494,15 @@ void sqlite3DeleteFrom(
** invoke the callback function. ** invoke the callback function.
*/ */
if( db->flags & SQLITE_CountRows && pParse->nested==0 && !pParse->trigStack ){ if( db->flags & SQLITE_CountRows && pParse->nested==0 && !pParse->trigStack ){
sqlite3VdbeAddOp(v, OP_MemLoad, memCnt, 0); sqlite3VdbeAddOp2(v, OP_ResultRow, memCnt, 1);
sqlite3VdbeAddOp(v, OP_Callback, 1, 0);
sqlite3VdbeSetNumCols(v, 1); sqlite3VdbeSetNumCols(v, 1);
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "rows deleted", P3_STATIC); sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "rows deleted", SQLITE_STATIC);
} }
delete_from_cleanup: delete_from_cleanup:
sqlite3AuthContextPop(&sContext); sqlite3AuthContextPop(&sContext);
sqlite3SrcListDelete(pTabList); sqlite3SrcListDelete(db, pTabList);
sqlite3ExprDelete(pWhere); sqlite3ExprDelete(db, pWhere);
return; return;
} }
@ -382,26 +519,29 @@ delete_from_cleanup:
** 2. Read/write cursors for all indices of pTab must be open as ** 2. Read/write cursors for all indices of pTab must be open as
** cursor number base+i for the i-th index. ** cursor number base+i for the i-th index.
** **
** 3. The record number of the row to be deleted must be on the top ** 3. The record number of the row to be deleted must be stored in
** of the stack. ** memory cell iRowid.
** **
** This routine pops the top of the stack to remove the record number ** This routine pops the top of the stack to remove the record number
** and then generates code to remove both the table record and all index ** and then generates code to remove both the table record and all index
** entries that point to that record. ** entries that point to that record.
*/ */
void sqlite3GenerateRowDelete( void sqlite3GenerateRowDelete(
sqlite3 *db, /* The database containing the index */ Parse *pParse, /* Parsing context */
Vdbe *v, /* Generate code into this VDBE */
Table *pTab, /* Table containing the row to be deleted */ Table *pTab, /* Table containing the row to be deleted */
int iCur, /* Cursor number for the table */ int iCur, /* Cursor number for the table */
int iRowid, /* Memory cell that contains the rowid to delete */
int count /* Increment the row change counter */ int count /* Increment the row change counter */
){ ){
int addr; int addr;
addr = sqlite3VdbeAddOp(v, OP_NotExists, iCur, 0); Vdbe *v;
sqlite3GenerateRowIndexDelete(v, pTab, iCur, 0);
sqlite3VdbeAddOp(v, OP_Delete, iCur, (count?OPFLAG_NCHANGE:0)); v = pParse->pVdbe;
addr = sqlite3VdbeAddOp3(v, OP_NotExists, iCur, 0, iRowid);
sqlite3GenerateRowIndexDelete(pParse, pTab, iCur, 0);
sqlite3VdbeAddOp2(v, OP_Delete, iCur, (count?OPFLAG_NCHANGE:0));
if( count ){ if( count ){
sqlite3VdbeChangeP3(v, -1, pTab->zName, P3_STATIC); sqlite3VdbeChangeP4(v, -1, pTab->zName, P4_STATIC);
} }
sqlite3VdbeJumpHere(v, addr); sqlite3VdbeJumpHere(v, addr);
} }
@ -423,45 +563,68 @@ void sqlite3GenerateRowDelete(
** deleted. ** deleted.
*/ */
void sqlite3GenerateRowIndexDelete( void sqlite3GenerateRowIndexDelete(
Vdbe *v, /* Generate code into this VDBE */ Parse *pParse, /* Parsing and code generating context */
Table *pTab, /* Table containing the row to be deleted */ Table *pTab, /* Table containing the row to be deleted */
int iCur, /* Cursor number for the table */ int iCur, /* Cursor number for the table */
char *aIdxUsed /* Only delete if aIdxUsed!=0 && aIdxUsed[i]!=0 */ int *aRegIdx /* Only delete if aRegIdx!=0 && aRegIdx[i]>0 */
){ ){
int i; int i;
Index *pIdx; Index *pIdx;
int r1;
for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){ for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
if( aIdxUsed!=0 && aIdxUsed[i-1]==0 ) continue; if( aRegIdx!=0 && aRegIdx[i-1]==0 ) continue;
sqlite3GenerateIndexKey(v, pIdx, iCur); r1 = sqlite3GenerateIndexKey(pParse, pIdx, iCur, 0, 0);
sqlite3VdbeAddOp(v, OP_IdxDelete, iCur+i, 0); sqlite3VdbeAddOp3(pParse->pVdbe, OP_IdxDelete, iCur+i, r1,pIdx->nColumn+1);
} }
} }
/* /*
** Generate code that will assemble an index key and put it on the top ** Generate code that will assemble an index key and put it in register
** of the tack. The key with be for index pIdx which is an index on pTab. ** regOut. The key with be for index pIdx which is an index on pTab.
** iCur is the index of a cursor open on the pTab table and pointing to ** iCur is the index of a cursor open on the pTab table and pointing to
** the entry that needs indexing. ** the entry that needs indexing.
**
** Return a register number which is the first in a block of
** registers that holds the elements of the index key. The
** block of registers has already been deallocated by the time
** this routine returns.
*/ */
void sqlite3GenerateIndexKey( int sqlite3GenerateIndexKey(
Vdbe *v, /* Generate code into this VDBE */ Parse *pParse, /* Parsing context */
Index *pIdx, /* The index for which to generate a key */ Index *pIdx, /* The index for which to generate a key */
int iCur /* Cursor number for the pIdx->pTable table */ int iCur, /* Cursor number for the pIdx->pTable table */
int regOut, /* Write the new index key to this register */
int doMakeRec /* Run the OP_MakeRecord instruction if true */
){ ){
Vdbe *v = pParse->pVdbe;
int j; int j;
Table *pTab = pIdx->pTable; Table *pTab = pIdx->pTable;
int regBase;
int nCol;
sqlite3VdbeAddOp(v, OP_Rowid, iCur, 0); nCol = pIdx->nColumn;
for(j=0; j<pIdx->nColumn; j++){ regBase = sqlite3GetTempRange(pParse, nCol+1);
sqlite3VdbeAddOp2(v, OP_Rowid, iCur, regBase+nCol);
for(j=0; j<nCol; j++){
int idx = pIdx->aiColumn[j]; int idx = pIdx->aiColumn[j];
if( idx==pTab->iPKey ){ if( idx==pTab->iPKey ){
sqlite3VdbeAddOp(v, OP_Dup, j, 0); sqlite3VdbeAddOp2(v, OP_SCopy, regBase+nCol, regBase+j);
}else{ }else{
sqlite3VdbeAddOp(v, OP_Column, iCur, idx); sqlite3VdbeAddOp3(v, OP_Column, iCur, idx, regBase+j);
sqlite3ColumnDefault(v, pTab, idx); sqlite3ColumnDefault(v, pTab, idx);
} }
} }
sqlite3VdbeAddOp(v, OP_MakeIdxRec, pIdx->nColumn, 0); if( doMakeRec ){
sqlite3IndexAffinityStr(v, pIdx); sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase, nCol+1, regOut);
sqlite3IndexAffinityStr(v, pIdx);
sqlite3ExprCacheAffinityChange(pParse, regBase, nCol+1);
}
sqlite3ReleaseTempRange(pParse, regBase, nCol+1);
return regBase;
} }
/* Make sure "isView" gets undefined in case this file becomes part of
** the amalgamation - so that subsequent files do not see isView as a
** macro. */
#undef isView

3351
expr.c

File diff suppressed because it is too large Load diff

91
fault.c Normal file
View file

@ -0,0 +1,91 @@
/*
** 2008 Jan 22
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
**
** May you do good and not evil.
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
*************************************************************************
**
** $Id: fault.c,v 1.11 2008/09/02 00:52:52 drh Exp $
*/
/*
** This file contains code to support the concept of "benign"
** malloc failures (when the xMalloc() or xRealloc() method of the
** sqlite3_mem_methods structure fails to allocate a block of memory
** and returns 0).
**
** Most malloc failures are non-benign. After they occur, SQLite
** abandons the current operation and returns an error code (usually
** SQLITE_NOMEM) to the user. However, sometimes a fault is not necessarily
** fatal. For example, if a malloc fails while resizing a hash table, this
** is completely recoverable simply by not carrying out the resize. The
** hash table will continue to function normally. So a malloc failure
** during a hash table resize is a benign fault.
*/
#include "sqliteInt.h"
#ifndef SQLITE_OMIT_BUILTIN_TEST
/*
** Global variables.
*/
typedef struct BenignMallocHooks BenignMallocHooks;
static SQLITE_WSD struct BenignMallocHooks {
void (*xBenignBegin)(void);
void (*xBenignEnd)(void);
} sqlite3Hooks = { 0, 0 };
/* The "wsdHooks" macro will resolve to the appropriate BenignMallocHooks
** structure. If writable static data is unsupported on the target,
** we have to locate the state vector at run-time. In the more common
** case where writable static data is supported, wsdHooks can refer directly
** to the "sqlite3Hooks" state vector declared above.
*/
#ifdef SQLITE_OMIT_WSD
# define wsdHooksInit \
BenignMallocHooks *x = &GLOBAL(BenignMallocHooks,sqlite3Hooks)
# define wsdHooks x[0]
#else
# define wsdHooksInit
# define wsdHooks sqlite3Hooks
#endif
/*
** Register hooks to call when sqlite3BeginBenignMalloc() and
** sqlite3EndBenignMalloc() are called, respectively.
*/
void sqlite3BenignMallocHooks(
void (*xBenignBegin)(void),
void (*xBenignEnd)(void)
){
wsdHooksInit;
wsdHooks.xBenignBegin = xBenignBegin;
wsdHooks.xBenignEnd = xBenignEnd;
}
/*
** This (sqlite3EndBenignMalloc()) is called by SQLite code to indicate that
** subsequent malloc failures are benign. A call to sqlite3EndBenignMalloc()
** indicates that subsequent malloc failures are non-benign.
*/
void sqlite3BeginBenignMalloc(void){
wsdHooksInit;
if( wsdHooks.xBenignBegin ){
wsdHooks.xBenignBegin();
}
}
void sqlite3EndBenignMalloc(void){
wsdHooksInit;
if( wsdHooks.xBenignEnd ){
wsdHooks.xBenignEnd();
}
}
#endif /* #ifndef SQLITE_OMIT_BUILTIN_TEST */

File diff suppressed because it is too large Load diff

View file

@ -11,7 +11,7 @@
****************************************************************************** ******************************************************************************
** **
** This header file is used by programs that want to link against the ** This header file is used by programs that want to link against the
** FTS2 library. All it does is declare the sqlite3Fts2Init() interface. ** FTS3 library. All it does is declare the sqlite3Fts3Init() interface.
*/ */
#include "sqlite3.h" #include "sqlite3.h"
@ -19,7 +19,7 @@
extern "C" { extern "C" {
#endif /* __cplusplus */ #endif /* __cplusplus */
int sqlite3Fts2Init(sqlite3 *db); int sqlite3Fts3Init(sqlite3 *db);
#ifdef __cplusplus #ifdef __cplusplus
} /* extern "C" */ } /* extern "C" */

890
fts3_expr.c Normal file
View file

@ -0,0 +1,890 @@
/*
** 2008 Nov 28
**
** 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 module contains code that implements a parser for fts3 query strings
** (the right-hand argument to the MATCH operator). Because the supported
** syntax is relatively simple, the whole tokenizer/parser system is
** hand-coded. The public interface to this module is declared in source
** code file "fts3_expr.h".
*/
#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3)
/*
** By default, this module parses the legacy syntax that has been
** traditionally used by fts3. Or, if SQLITE_ENABLE_FTS3_PARENTHESIS
** is defined, then it uses the new syntax. The differences between
** the new and the old syntaxes are:
**
** a) The new syntax supports parenthesis. The old does not.
**
** b) The new syntax supports the AND and NOT operators. The old does not.
**
** c) The old syntax supports the "-" token qualifier. This is not
** supported by the new syntax (it is replaced by the NOT operator).
**
** d) When using the old syntax, the OR operator has a greater precedence
** than an implicit AND. When using the new, both implicity and explicit
** AND operators have a higher precedence than OR.
**
** If compiled with SQLITE_TEST defined, then this module exports the
** symbol "int sqlite3_fts3_enable_parentheses". Setting this variable
** to zero causes the module to use the old syntax. If it is set to
** non-zero the new syntax is activated. This is so both syntaxes can
** be tested using a single build of testfixture.
*/
#ifdef SQLITE_TEST
int sqlite3_fts3_enable_parentheses = 0;
#else
# ifdef SQLITE_ENABLE_FTS3_PARENTHESIS
# define sqlite3_fts3_enable_parentheses 1
# else
# define sqlite3_fts3_enable_parentheses 0
# endif
#endif
/*
** Default span for NEAR operators.
*/
#define SQLITE_FTS3_DEFAULT_NEAR_PARAM 10
#include "fts3_expr.h"
#include "sqlite3.h"
#include <ctype.h>
#include <string.h>
#include <assert.h>
typedef struct ParseContext ParseContext;
struct ParseContext {
sqlite3_tokenizer *pTokenizer; /* Tokenizer module */
const char **azCol; /* Array of column names for fts3 table */
int nCol; /* Number of entries in azCol[] */
int iDefaultCol; /* Default column to query */
sqlite3_context *pCtx; /* Write error message here */
int nNest; /* Number of nested brackets */
};
/*
** This function is equivalent to the standard isspace() function.
**
** The standard isspace() can be awkward to use safely, because although it
** is defined to accept an argument of type int, its behaviour when passed
** an integer that falls outside of the range of the unsigned char type
** is undefined (and sometimes, "undefined" means segfault). This wrapper
** is defined to accept an argument of type char, and always returns 0 for
** any values that fall outside of the range of the unsigned char type (i.e.
** negative values).
*/
static int fts3isspace(char c){
return (c&0x80)==0 ? isspace(c) : 0;
}
/*
** Extract the next token from buffer z (length n) using the tokenizer
** and other information (column names etc.) in pParse. Create an Fts3Expr
** structure of type FTSQUERY_PHRASE containing a phrase consisting of this
** single token and set *ppExpr to point to it. If the end of the buffer is
** reached before a token is found, set *ppExpr to zero. It is the
** responsibility of the caller to eventually deallocate the allocated
** Fts3Expr structure (if any) by passing it to sqlite3_free().
**
** Return SQLITE_OK if successful, or SQLITE_NOMEM if a memory allocation
** fails.
*/
static int getNextToken(
ParseContext *pParse, /* fts3 query parse context */
int iCol, /* Value for Fts3Phrase.iColumn */
const char *z, int n, /* Input string */
Fts3Expr **ppExpr, /* OUT: expression */
int *pnConsumed /* OUT: Number of bytes consumed */
){
sqlite3_tokenizer *pTokenizer = pParse->pTokenizer;
sqlite3_tokenizer_module const *pModule = pTokenizer->pModule;
int rc;
sqlite3_tokenizer_cursor *pCursor;
Fts3Expr *pRet = 0;
int nConsumed = 0;
rc = pModule->xOpen(pTokenizer, z, n, &pCursor);
if( rc==SQLITE_OK ){
const char *zToken;
int nToken, iStart, iEnd, iPosition;
int nByte; /* total space to allocate */
pCursor->pTokenizer = pTokenizer;
rc = pModule->xNext(pCursor, &zToken, &nToken, &iStart, &iEnd, &iPosition);
if( rc==SQLITE_OK ){
nByte = sizeof(Fts3Expr) + sizeof(Fts3Phrase) + nToken;
pRet = (Fts3Expr *)sqlite3_malloc(nByte);
if( !pRet ){
rc = SQLITE_NOMEM;
}else{
memset(pRet, 0, nByte);
pRet->eType = FTSQUERY_PHRASE;
pRet->pPhrase = (Fts3Phrase *)&pRet[1];
pRet->pPhrase->nToken = 1;
pRet->pPhrase->iColumn = iCol;
pRet->pPhrase->aToken[0].n = nToken;
pRet->pPhrase->aToken[0].z = (char *)&pRet->pPhrase[1];
memcpy(pRet->pPhrase->aToken[0].z, zToken, nToken);
if( iEnd<n && z[iEnd]=='*' ){
pRet->pPhrase->aToken[0].isPrefix = 1;
iEnd++;
}
if( !sqlite3_fts3_enable_parentheses && iStart>0 && z[iStart-1]=='-' ){
pRet->pPhrase->isNot = 1;
}
}
}
nConsumed = iEnd;
pModule->xClose(pCursor);
}
*pnConsumed = nConsumed;
*ppExpr = pRet;
return rc;
}
/*
** Enlarge a memory allocation. If an out-of-memory allocation occurs,
** then free the old allocation.
*/
void *fts3ReallocOrFree(void *pOrig, int nNew){
void *pRet = sqlite3_realloc(pOrig, nNew);
if( !pRet ){
sqlite3_free(pOrig);
}
return pRet;
}
/*
** Buffer zInput, length nInput, contains the contents of a quoted string
** that appeared as part of an fts3 query expression. Neither quote character
** is included in the buffer. This function attempts to tokenize the entire
** input buffer and create an Fts3Expr structure of type FTSQUERY_PHRASE
** containing the results.
**
** If successful, SQLITE_OK is returned and *ppExpr set to point at the
** allocated Fts3Expr structure. Otherwise, either SQLITE_NOMEM (out of memory
** error) or SQLITE_ERROR (tokenization error) is returned and *ppExpr set
** to 0.
*/
static int getNextString(
ParseContext *pParse, /* fts3 query parse context */
const char *zInput, int nInput, /* Input string */
Fts3Expr **ppExpr /* OUT: expression */
){
sqlite3_tokenizer *pTokenizer = pParse->pTokenizer;
sqlite3_tokenizer_module const *pModule = pTokenizer->pModule;
int rc;
Fts3Expr *p = 0;
sqlite3_tokenizer_cursor *pCursor = 0;
char *zTemp = 0;
int nTemp = 0;
rc = pModule->xOpen(pTokenizer, zInput, nInput, &pCursor);
if( rc==SQLITE_OK ){
int ii;
pCursor->pTokenizer = pTokenizer;
for(ii=0; rc==SQLITE_OK; ii++){
const char *zToken;
int nToken, iBegin, iEnd, iPos;
rc = pModule->xNext(pCursor, &zToken, &nToken, &iBegin, &iEnd, &iPos);
if( rc==SQLITE_OK ){
int nByte = sizeof(Fts3Expr) + sizeof(Fts3Phrase);
p = fts3ReallocOrFree(p, nByte+ii*sizeof(struct PhraseToken));
zTemp = fts3ReallocOrFree(zTemp, nTemp + nToken);
if( !p || !zTemp ){
goto no_mem;
}
if( ii==0 ){
memset(p, 0, nByte);
p->pPhrase = (Fts3Phrase *)&p[1];
p->eType = FTSQUERY_PHRASE;
p->pPhrase->iColumn = pParse->iDefaultCol;
}
p->pPhrase = (Fts3Phrase *)&p[1];
p->pPhrase->nToken = ii+1;
p->pPhrase->aToken[ii].n = nToken;
memcpy(&zTemp[nTemp], zToken, nToken);
nTemp += nToken;
if( iEnd<nInput && zInput[iEnd]=='*' ){
p->pPhrase->aToken[ii].isPrefix = 1;
}else{
p->pPhrase->aToken[ii].isPrefix = 0;
}
}
}
pModule->xClose(pCursor);
pCursor = 0;
}
if( rc==SQLITE_DONE ){
int jj;
char *zNew;
int nNew = 0;
int nByte = sizeof(Fts3Expr) + sizeof(Fts3Phrase);
nByte += (p->pPhrase->nToken-1) * sizeof(struct PhraseToken);
p = fts3ReallocOrFree(p, nByte + nTemp);
if( !p ){
goto no_mem;
}
p->pPhrase = (Fts3Phrase *)&p[1];
zNew = &(((char *)p)[nByte]);
memcpy(zNew, zTemp, nTemp);
for(jj=0; jj<p->pPhrase->nToken; jj++){
p->pPhrase->aToken[jj].z = &zNew[nNew];
nNew += p->pPhrase->aToken[jj].n;
}
sqlite3_free(zTemp);
rc = SQLITE_OK;
}
*ppExpr = p;
return rc;
no_mem:
if( pCursor ){
pModule->xClose(pCursor);
}
sqlite3_free(zTemp);
sqlite3_free(p);
*ppExpr = 0;
return SQLITE_NOMEM;
}
/*
** Function getNextNode(), which is called by fts3ExprParse(), may itself
** call fts3ExprParse(). So this forward declaration is required.
*/
static int fts3ExprParse(ParseContext *, const char *, int, Fts3Expr **, int *);
/*
** The output variable *ppExpr is populated with an allocated Fts3Expr
** structure, or set to 0 if the end of the input buffer is reached.
**
** Returns an SQLite error code. SQLITE_OK if everything works, SQLITE_NOMEM
** if a malloc failure occurs, or SQLITE_ERROR if a parse error is encountered.
** If SQLITE_ERROR is returned, pContext is populated with an error message.
*/
static int getNextNode(
ParseContext *pParse, /* fts3 query parse context */
const char *z, int n, /* Input string */
Fts3Expr **ppExpr, /* OUT: expression */
int *pnConsumed /* OUT: Number of bytes consumed */
){
static const struct Fts3Keyword {
char z[4]; /* Keyword text */
unsigned char n; /* Length of the keyword */
unsigned char parenOnly; /* Only valid in paren mode */
unsigned char eType; /* Keyword code */
} aKeyword[] = {
{ "OR" , 2, 0, FTSQUERY_OR },
{ "AND", 3, 1, FTSQUERY_AND },
{ "NOT", 3, 1, FTSQUERY_NOT },
{ "NEAR", 4, 0, FTSQUERY_NEAR }
};
int ii;
int iCol;
int iColLen;
int rc;
Fts3Expr *pRet = 0;
const char *zInput = z;
int nInput = n;
/* Skip over any whitespace before checking for a keyword, an open or
** close bracket, or a quoted string.
*/
while( nInput>0 && fts3isspace(*zInput) ){
nInput--;
zInput++;
}
if( nInput==0 ){
return SQLITE_DONE;
}
/* See if we are dealing with a keyword. */
for(ii=0; ii<(int)(sizeof(aKeyword)/sizeof(struct Fts3Keyword)); ii++){
const struct Fts3Keyword *pKey = &aKeyword[ii];
if( (pKey->parenOnly & ~sqlite3_fts3_enable_parentheses)!=0 ){
continue;
}
if( nInput>=pKey->n && 0==memcmp(zInput, pKey->z, pKey->n) ){
int nNear = SQLITE_FTS3_DEFAULT_NEAR_PARAM;
int nKey = pKey->n;
char cNext;
/* If this is a "NEAR" keyword, check for an explicit nearness. */
if( pKey->eType==FTSQUERY_NEAR ){
assert( nKey==4 );
if( zInput[4]=='/' && zInput[5]>='0' && zInput[5]<='9' ){
nNear = 0;
for(nKey=5; zInput[nKey]>='0' && zInput[nKey]<='9'; nKey++){
nNear = nNear * 10 + (zInput[nKey] - '0');
}
}
}
/* At this point this is probably a keyword. But for that to be true,
** the next byte must contain either whitespace, an open or close
** parenthesis, a quote character, or EOF.
*/
cNext = zInput[nKey];
if( fts3isspace(cNext)
|| cNext=='"' || cNext=='(' || cNext==')' || cNext==0
){
pRet = (Fts3Expr *)sqlite3_malloc(sizeof(Fts3Expr));
memset(pRet, 0, sizeof(Fts3Expr));
pRet->eType = pKey->eType;
pRet->nNear = nNear;
*ppExpr = pRet;
*pnConsumed = (zInput - z) + nKey;
return SQLITE_OK;
}
/* Turns out that wasn't a keyword after all. This happens if the
** user has supplied a token such as "ORacle". Continue.
*/
}
}
/* Check for an open bracket. */
if( sqlite3_fts3_enable_parentheses ){
if( *zInput=='(' ){
int nConsumed;
int rc;
pParse->nNest++;
rc = fts3ExprParse(pParse, &zInput[1], nInput-1, ppExpr, &nConsumed);
if( rc==SQLITE_OK && !*ppExpr ){
rc = SQLITE_DONE;
}
*pnConsumed = (zInput - z) + 1 + nConsumed;
return rc;
}
/* Check for a close bracket. */
if( *zInput==')' ){
pParse->nNest--;
*pnConsumed = (zInput - z) + 1;
return SQLITE_DONE;
}
}
/* See if we are dealing with a quoted phrase. If this is the case, then
** search for the closing quote and pass the whole string to getNextString()
** for processing. This is easy to do, as fts3 has no syntax for escaping
** a quote character embedded in a string.
*/
if( *zInput=='"' ){
for(ii=1; ii<nInput && zInput[ii]!='"'; ii++);
*pnConsumed = (zInput - z) + ii + 1;
if( ii==nInput ){
return SQLITE_ERROR;
}
return getNextString(pParse, &zInput[1], ii-1, ppExpr);
}
/* If control flows to this point, this must be a regular token, or
** the end of the input. Read a regular token using the sqlite3_tokenizer
** interface. Before doing so, figure out if there is an explicit
** column specifier for the token.
**
** TODO: Strangely, it is not possible to associate a column specifier
** with a quoted phrase, only with a single token. Not sure if this was
** an implementation artifact or an intentional decision when fts3 was
** first implemented. Whichever it was, this module duplicates the
** limitation.
*/
iCol = pParse->iDefaultCol;
iColLen = 0;
for(ii=0; ii<pParse->nCol; ii++){
const char *zStr = pParse->azCol[ii];
int nStr = strlen(zStr);
if( nInput>nStr && zInput[nStr]==':' && memcmp(zStr, zInput, nStr)==0 ){
iCol = ii;
iColLen = ((zInput - z) + nStr + 1);
break;
}
}
rc = getNextToken(pParse, iCol, &z[iColLen], n-iColLen, ppExpr, pnConsumed);
*pnConsumed += iColLen;
return rc;
}
/*
** The argument is an Fts3Expr structure for a binary operator (any type
** except an FTSQUERY_PHRASE). Return an integer value representing the
** precedence of the operator. Lower values have a higher precedence (i.e.
** group more tightly). For example, in the C language, the == operator
** groups more tightly than ||, and would therefore have a higher precedence.
**
** When using the new fts3 query syntax (when SQLITE_ENABLE_FTS3_PARENTHESIS
** is defined), the order of the operators in precedence from highest to
** lowest is:
**
** NEAR
** NOT
** AND (including implicit ANDs)
** OR
**
** Note that when using the old query syntax, the OR operator has a higher
** precedence than the AND operator.
*/
static int opPrecedence(Fts3Expr *p){
assert( p->eType!=FTSQUERY_PHRASE );
if( sqlite3_fts3_enable_parentheses ){
return p->eType;
}else if( p->eType==FTSQUERY_NEAR ){
return 1;
}else if( p->eType==FTSQUERY_OR ){
return 2;
}
assert( p->eType==FTSQUERY_AND );
return 3;
}
/*
** Argument ppHead contains a pointer to the current head of a query
** expression tree being parsed. pPrev is the expression node most recently
** inserted into the tree. This function adds pNew, which is always a binary
** operator node, into the expression tree based on the relative precedence
** of pNew and the existing nodes of the tree. This may result in the head
** of the tree changing, in which case *ppHead is set to the new root node.
*/
static void insertBinaryOperator(
Fts3Expr **ppHead, /* Pointer to the root node of a tree */
Fts3Expr *pPrev, /* Node most recently inserted into the tree */
Fts3Expr *pNew /* New binary node to insert into expression tree */
){
Fts3Expr *pSplit = pPrev;
while( pSplit->pParent && opPrecedence(pSplit->pParent)<=opPrecedence(pNew) ){
pSplit = pSplit->pParent;
}
if( pSplit->pParent ){
assert( pSplit->pParent->pRight==pSplit );
pSplit->pParent->pRight = pNew;
pNew->pParent = pSplit->pParent;
}else{
*ppHead = pNew;
}
pNew->pLeft = pSplit;
pSplit->pParent = pNew;
}
/*
** Parse the fts3 query expression found in buffer z, length n. This function
** returns either when the end of the buffer is reached or an unmatched
** closing bracket - ')' - is encountered.
**
** If successful, SQLITE_OK is returned, *ppExpr is set to point to the
** parsed form of the expression and *pnConsumed is set to the number of
** bytes read from buffer z. Otherwise, *ppExpr is set to 0 and SQLITE_NOMEM
** (out of memory error) or SQLITE_ERROR (parse error) is returned.
*/
static int fts3ExprParse(
ParseContext *pParse, /* fts3 query parse context */
const char *z, int n, /* Text of MATCH query */
Fts3Expr **ppExpr, /* OUT: Parsed query structure */
int *pnConsumed /* OUT: Number of bytes consumed */
){
Fts3Expr *pRet = 0;
Fts3Expr *pPrev = 0;
Fts3Expr *pNotBranch = 0; /* Only used in legacy parse mode */
int nIn = n;
const char *zIn = z;
int rc = SQLITE_OK;
int isRequirePhrase = 1;
while( rc==SQLITE_OK ){
Fts3Expr *p = 0;
int nByte = 0;
rc = getNextNode(pParse, zIn, nIn, &p, &nByte);
if( rc==SQLITE_OK ){
int isPhrase;
if( !sqlite3_fts3_enable_parentheses
&& p->eType==FTSQUERY_PHRASE && p->pPhrase->isNot
){
/* Create an implicit NOT operator. */
Fts3Expr *pNot = sqlite3_malloc(sizeof(Fts3Expr));
if( !pNot ){
sqlite3Fts3ExprFree(p);
rc = SQLITE_NOMEM;
goto exprparse_out;
}
memset(pNot, 0, sizeof(Fts3Expr));
pNot->eType = FTSQUERY_NOT;
pNot->pRight = p;
if( pNotBranch ){
pNotBranch->pLeft = p;
pNot->pRight = pNotBranch;
}
pNotBranch = pNot;
}else{
int eType = p->eType;
assert( eType!=FTSQUERY_PHRASE || !p->pPhrase->isNot );
isPhrase = (eType==FTSQUERY_PHRASE || p->pLeft);
/* The isRequirePhrase variable is set to true if a phrase or
** an expression contained in parenthesis is required. If a
** binary operator (AND, OR, NOT or NEAR) is encounted when
** isRequirePhrase is set, this is a syntax error.
*/
if( !isPhrase && isRequirePhrase ){
sqlite3Fts3ExprFree(p);
rc = SQLITE_ERROR;
goto exprparse_out;
}
if( isPhrase && !isRequirePhrase ){
/* Insert an implicit AND operator. */
Fts3Expr *pAnd;
assert( pRet && pPrev );
pAnd = sqlite3_malloc(sizeof(Fts3Expr));
if( !pAnd ){
sqlite3Fts3ExprFree(p);
rc = SQLITE_NOMEM;
goto exprparse_out;
}
memset(pAnd, 0, sizeof(Fts3Expr));
pAnd->eType = FTSQUERY_AND;
insertBinaryOperator(&pRet, pPrev, pAnd);
pPrev = pAnd;
}
/* This test catches attempts to make either operand of a NEAR
** operator something other than a phrase. For example, either of
** the following:
**
** (bracketed expression) NEAR phrase
** phrase NEAR (bracketed expression)
**
** Return an error in either case.
*/
if( pPrev && (
(eType==FTSQUERY_NEAR && !isPhrase && pPrev->eType!=FTSQUERY_PHRASE)
|| (eType!=FTSQUERY_PHRASE && isPhrase && pPrev->eType==FTSQUERY_NEAR)
)){
sqlite3Fts3ExprFree(p);
rc = SQLITE_ERROR;
goto exprparse_out;
}
if( isPhrase ){
if( pRet ){
assert( pPrev && pPrev->pLeft && pPrev->pRight==0 );
pPrev->pRight = p;
p->pParent = pPrev;
}else{
pRet = p;
}
}else{
insertBinaryOperator(&pRet, pPrev, p);
}
isRequirePhrase = !isPhrase;
}
assert( nByte>0 );
}
assert( rc!=SQLITE_OK || (nByte>0 && nByte<=nIn) );
nIn -= nByte;
zIn += nByte;
pPrev = p;
}
if( rc==SQLITE_DONE && pRet && isRequirePhrase ){
rc = SQLITE_ERROR;
}
if( rc==SQLITE_DONE ){
rc = SQLITE_OK;
if( !sqlite3_fts3_enable_parentheses && pNotBranch ){
if( !pRet ){
rc = SQLITE_ERROR;
}else{
pNotBranch->pLeft = pRet;
pRet = pNotBranch;
}
}
}
*pnConsumed = n - nIn;
exprparse_out:
if( rc!=SQLITE_OK ){
sqlite3Fts3ExprFree(pRet);
sqlite3Fts3ExprFree(pNotBranch);
pRet = 0;
}
*ppExpr = pRet;
return rc;
}
/*
** Parameters z and n contain a pointer to and length of a buffer containing
** an fts3 query expression, respectively. This function attempts to parse the
** query expression and create a tree of Fts3Expr structures representing the
** parsed expression. If successful, *ppExpr is set to point to the head
** of the parsed expression tree and SQLITE_OK is returned. If an error
** occurs, either SQLITE_NOMEM (out-of-memory error) or SQLITE_ERROR (parse
** error) is returned and *ppExpr is set to 0.
**
** If parameter n is a negative number, then z is assumed to point to a
** nul-terminated string and the length is determined using strlen().
**
** The first parameter, pTokenizer, is passed the fts3 tokenizer module to
** use to normalize query tokens while parsing the expression. The azCol[]
** array, which is assumed to contain nCol entries, should contain the names
** of each column in the target fts3 table, in order from left to right.
** Column names must be nul-terminated strings.
**
** The iDefaultCol parameter should be passed the index of the table column
** that appears on the left-hand-side of the MATCH operator (the default
** column to match against for tokens for which a column name is not explicitly
** specified as part of the query string), or -1 if tokens may by default
** match any table column.
*/
int sqlite3Fts3ExprParse(
sqlite3_tokenizer *pTokenizer, /* Tokenizer module */
char **azCol, /* Array of column names for fts3 table */
int nCol, /* Number of entries in azCol[] */
int iDefaultCol, /* Default column to query */
const char *z, int n, /* Text of MATCH query */
Fts3Expr **ppExpr /* OUT: Parsed query structure */
){
int nParsed;
int rc;
ParseContext sParse;
sParse.pTokenizer = pTokenizer;
sParse.azCol = (const char **)azCol;
sParse.nCol = nCol;
sParse.iDefaultCol = iDefaultCol;
sParse.nNest = 0;
if( z==0 ){
*ppExpr = 0;
return SQLITE_OK;
}
if( n<0 ){
n = strlen(z);
}
rc = fts3ExprParse(&sParse, z, n, ppExpr, &nParsed);
/* Check for mismatched parenthesis */
if( rc==SQLITE_OK && sParse.nNest ){
rc = SQLITE_ERROR;
sqlite3Fts3ExprFree(*ppExpr);
*ppExpr = 0;
}
return rc;
}
/*
** Free a parsed fts3 query expression allocated by sqlite3Fts3ExprParse().
*/
void sqlite3Fts3ExprFree(Fts3Expr *p){
if( p ){
sqlite3Fts3ExprFree(p->pLeft);
sqlite3Fts3ExprFree(p->pRight);
sqlite3_free(p);
}
}
/****************************************************************************
*****************************************************************************
** Everything after this point is just test code.
*/
#ifdef SQLITE_TEST
#include <stdio.h>
/*
** Function to query the hash-table of tokenizers (see README.tokenizers).
*/
static int queryTestTokenizer(
sqlite3 *db,
const char *zName,
const sqlite3_tokenizer_module **pp
){
int rc;
sqlite3_stmt *pStmt;
const char zSql[] = "SELECT fts3_tokenizer(?)";
*pp = 0;
rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0);
if( rc!=SQLITE_OK ){
return rc;
}
sqlite3_bind_text(pStmt, 1, zName, -1, SQLITE_STATIC);
if( SQLITE_ROW==sqlite3_step(pStmt) ){
if( sqlite3_column_type(pStmt, 0)==SQLITE_BLOB ){
memcpy(pp, sqlite3_column_blob(pStmt, 0), sizeof(*pp));
}
}
return sqlite3_finalize(pStmt);
}
/*
** This function is part of the test interface for the query parser. It
** writes a text representation of the query expression pExpr into the
** buffer pointed to by argument zBuf. It is assumed that zBuf is large
** enough to store the required text representation.
*/
static void exprToString(Fts3Expr *pExpr, char *zBuf){
switch( pExpr->eType ){
case FTSQUERY_PHRASE: {
Fts3Phrase *pPhrase = pExpr->pPhrase;
int i;
zBuf += sprintf(zBuf, "PHRASE %d %d", pPhrase->iColumn, pPhrase->isNot);
for(i=0; i<pPhrase->nToken; i++){
zBuf += sprintf(zBuf," %.*s",pPhrase->aToken[i].n,pPhrase->aToken[i].z);
zBuf += sprintf(zBuf,"%s", (pPhrase->aToken[i].isPrefix?"+":""));
}
return;
}
case FTSQUERY_NEAR:
zBuf += sprintf(zBuf, "NEAR/%d ", pExpr->nNear);
break;
case FTSQUERY_NOT:
zBuf += sprintf(zBuf, "NOT ");
break;
case FTSQUERY_AND:
zBuf += sprintf(zBuf, "AND ");
break;
case FTSQUERY_OR:
zBuf += sprintf(zBuf, "OR ");
break;
}
zBuf += sprintf(zBuf, "{");
exprToString(pExpr->pLeft, zBuf);
zBuf += strlen(zBuf);
zBuf += sprintf(zBuf, "} ");
zBuf += sprintf(zBuf, "{");
exprToString(pExpr->pRight, zBuf);
zBuf += strlen(zBuf);
zBuf += sprintf(zBuf, "}");
}
/*
** This is the implementation of a scalar SQL function used to test the
** expression parser. It should be called as follows:
**
** fts3_exprtest(<tokenizer>, <expr>, <column 1>, ...);
**
** The first argument, <tokenizer>, is the name of the fts3 tokenizer used
** to parse the query expression (see README.tokenizers). The second argument
** is the query expression to parse. Each subsequent argument is the name
** of a column of the fts3 table that the query expression may refer to.
** For example:
**
** SELECT fts3_exprtest('simple', 'Bill col2:Bloggs', 'col1', 'col2');
*/
static void fts3ExprTest(
sqlite3_context *context,
int argc,
sqlite3_value **argv
){
sqlite3_tokenizer_module const *pModule = 0;
sqlite3_tokenizer *pTokenizer = 0;
int rc;
char **azCol = 0;
const char *zExpr;
int nExpr;
int nCol;
int ii;
Fts3Expr *pExpr;
sqlite3 *db = sqlite3_context_db_handle(context);
if( argc<3 ){
sqlite3_result_error(context,
"Usage: fts3_exprtest(tokenizer, expr, col1, ...", -1
);
return;
}
rc = queryTestTokenizer(db,
(const char *)sqlite3_value_text(argv[0]), &pModule);
if( rc==SQLITE_NOMEM ){
sqlite3_result_error_nomem(context);
goto exprtest_out;
}else if( !pModule ){
sqlite3_result_error(context, "No such tokenizer module", -1);
goto exprtest_out;
}
rc = pModule->xCreate(0, 0, &pTokenizer);
assert( rc==SQLITE_NOMEM || rc==SQLITE_OK );
if( rc==SQLITE_NOMEM ){
sqlite3_result_error_nomem(context);
goto exprtest_out;
}
pTokenizer->pModule = pModule;
zExpr = (const char *)sqlite3_value_text(argv[1]);
nExpr = sqlite3_value_bytes(argv[1]);
nCol = argc-2;
azCol = (char **)sqlite3_malloc(nCol*sizeof(char *));
if( !azCol ){
sqlite3_result_error_nomem(context);
goto exprtest_out;
}
for(ii=0; ii<nCol; ii++){
azCol[ii] = (char *)sqlite3_value_text(argv[ii+2]);
}
rc = sqlite3Fts3ExprParse(
pTokenizer, azCol, nCol, nCol, zExpr, nExpr, &pExpr
);
if( rc==SQLITE_NOMEM ){
sqlite3_result_error_nomem(context);
goto exprtest_out;
}else if( rc==SQLITE_OK ){
char zBuf[4096];
exprToString(pExpr, zBuf);
sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT);
sqlite3Fts3ExprFree(pExpr);
}else{
sqlite3_result_error(context, "Error parsing expression", -1);
}
exprtest_out:
if( pModule && pTokenizer ){
rc = pModule->xDestroy(pTokenizer);
}
sqlite3_free(azCol);
}
/*
** Register the query expression parser test function fts3_exprtest()
** with database connection db.
*/
void sqlite3Fts3ExprInitTestInterface(sqlite3* db){
sqlite3_create_function(
db, "fts3_exprtest", -1, SQLITE_UTF8, 0, fts3ExprTest, 0, 0
);
}
#endif
#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) */

96
fts3_expr.h Normal file
View file

@ -0,0 +1,96 @@
/*
** 2008 Nov 28
**
** 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.
**
******************************************************************************
**
*/
#include "fts3_tokenizer.h"
#include "sqlite3.h"
/*
** The following describes the syntax supported by the fts3 MATCH
** operator in a similar format to that used by the lemon parser
** generator. This module does not use actually lemon, it uses a
** custom parser.
**
** query ::= andexpr (OR andexpr)*.
**
** andexpr ::= notexpr (AND? notexpr)*.
**
** notexpr ::= nearexpr (NOT nearexpr|-TOKEN)*.
** notexpr ::= LP query RP.
**
** nearexpr ::= phrase (NEAR distance_opt nearexpr)*.
**
** distance_opt ::= .
** distance_opt ::= / INTEGER.
**
** phrase ::= TOKEN.
** phrase ::= COLUMN:TOKEN.
** phrase ::= "TOKEN TOKEN TOKEN...".
*/
typedef struct Fts3Expr Fts3Expr;
typedef struct Fts3Phrase Fts3Phrase;
/*
** A "phrase" is a sequence of one or more tokens that must match in
** sequence. A single token is the base case and the most common case.
** For a sequence of tokens contained in "...", nToken will be the number
** of tokens in the string.
*/
struct Fts3Phrase {
int nToken; /* Number of tokens in the phrase */
int iColumn; /* Index of column this phrase must match */
int isNot; /* Phrase prefixed by unary not (-) operator */
struct PhraseToken {
char *z; /* Text of the token */
int n; /* Number of bytes in buffer pointed to by z */
int isPrefix; /* True if token ends in with a "*" character */
} aToken[1]; /* One entry for each token in the phrase */
};
/*
** A tree of these objects forms the RHS of a MATCH operator.
*/
struct Fts3Expr {
int eType; /* One of the FTSQUERY_XXX values defined below */
int nNear; /* Valid if eType==FTSQUERY_NEAR */
Fts3Expr *pParent; /* pParent->pLeft==this or pParent->pRight==this */
Fts3Expr *pLeft; /* Left operand */
Fts3Expr *pRight; /* Right operand */
Fts3Phrase *pPhrase; /* Valid if eType==FTSQUERY_PHRASE */
};
int sqlite3Fts3ExprParse(sqlite3_tokenizer *, char **, int, int,
const char *, int, Fts3Expr **);
void sqlite3Fts3ExprFree(Fts3Expr *);
/*
** Candidate values for Fts3Query.eType. Note that the order of the first
** four values is in order of precedence when parsing expressions. For
** example, the following:
**
** "a OR b AND c NOT d NEAR e"
**
** is equivalent to:
**
** "a OR (b AND (c NOT (d NEAR e)))"
*/
#define FTSQUERY_NEAR 1
#define FTSQUERY_NOT 2
#define FTSQUERY_AND 3
#define FTSQUERY_OR 4
#define FTSQUERY_PHRASE 5
#ifdef SQLITE_TEST
void sqlite3Fts3ExprInitTestInterface(sqlite3 *db);
#endif

View file

@ -17,79 +17,84 @@
/* /*
** The code in this file is only compiled if: ** The code in this file is only compiled if:
** **
** * The FTS2 module is being built as an extension ** * The FTS3 module is being built as an extension
** (in which case SQLITE_CORE is not defined), or ** (in which case SQLITE_CORE is not defined), or
** **
** * The FTS2 module is being built into the core of ** * The FTS3 module is being built into the core of
** SQLite (in which case SQLITE_ENABLE_FTS2 is defined). ** SQLite (in which case SQLITE_ENABLE_FTS3 is defined).
*/ */
#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS2) #if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3)
#include <assert.h> #include <assert.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include "fts2_hash.h" #include "sqlite3.h"
#include "fts3_hash.h"
static void *malloc_and_zero(int n){ /*
void *p = malloc(n); ** Malloc and Free functions
*/
static void *fts3HashMalloc(int n){
void *p = sqlite3_malloc(n);
if( p ){ if( p ){
memset(p, 0, n); memset(p, 0, n);
} }
return p; return p;
} }
static void fts3HashFree(void *p){
sqlite3_free(p);
}
/* Turn bulk memory into a hash table object by initializing the /* Turn bulk memory into a hash table object by initializing the
** fields of the Hash structure. ** fields of the Hash structure.
** **
** "pNew" is a pointer to the hash table that is to be initialized. ** "pNew" is a pointer to the hash table that is to be initialized.
** keyClass is one of the constants ** keyClass is one of the constants
** FTS2_HASH_BINARY or FTS2_HASH_STRING. The value of keyClass ** FTS3_HASH_BINARY or FTS3_HASH_STRING. The value of keyClass
** determines what kind of key the hash table will use. "copyKey" is ** determines what kind of key the hash table will use. "copyKey" is
** true if the hash table should make its own private copy of keys and ** true if the hash table should make its own private copy of keys and
** false if it should just use the supplied pointer. ** false if it should just use the supplied pointer.
*/ */
void sqlite3Fts2HashInit(fts2Hash *pNew, int keyClass, int copyKey){ void sqlite3Fts3HashInit(fts3Hash *pNew, int keyClass, int copyKey){
assert( pNew!=0 ); assert( pNew!=0 );
assert( keyClass>=FTS2_HASH_STRING && keyClass<=FTS2_HASH_BINARY ); assert( keyClass>=FTS3_HASH_STRING && keyClass<=FTS3_HASH_BINARY );
pNew->keyClass = keyClass; pNew->keyClass = keyClass;
pNew->copyKey = copyKey; pNew->copyKey = copyKey;
pNew->first = 0; pNew->first = 0;
pNew->count = 0; pNew->count = 0;
pNew->htsize = 0; pNew->htsize = 0;
pNew->ht = 0; pNew->ht = 0;
pNew->xMalloc = malloc_and_zero;
pNew->xFree = free;
} }
/* Remove all entries from a hash table. Reclaim all memory. /* Remove all entries from a hash table. Reclaim all memory.
** Call this routine to delete a hash table or to reset a hash table ** Call this routine to delete a hash table or to reset a hash table
** to the empty state. ** to the empty state.
*/ */
void sqlite3Fts2HashClear(fts2Hash *pH){ void sqlite3Fts3HashClear(fts3Hash *pH){
fts2HashElem *elem; /* For looping over all elements of the table */ fts3HashElem *elem; /* For looping over all elements of the table */
assert( pH!=0 ); assert( pH!=0 );
elem = pH->first; elem = pH->first;
pH->first = 0; pH->first = 0;
if( pH->ht ) pH->xFree(pH->ht); fts3HashFree(pH->ht);
pH->ht = 0; pH->ht = 0;
pH->htsize = 0; pH->htsize = 0;
while( elem ){ while( elem ){
fts2HashElem *next_elem = elem->next; fts3HashElem *next_elem = elem->next;
if( pH->copyKey && elem->pKey ){ if( pH->copyKey && elem->pKey ){
pH->xFree(elem->pKey); fts3HashFree(elem->pKey);
} }
pH->xFree(elem); fts3HashFree(elem);
elem = next_elem; elem = next_elem;
} }
pH->count = 0; pH->count = 0;
} }
/* /*
** Hash and comparison functions when the mode is FTS2_HASH_STRING ** Hash and comparison functions when the mode is FTS3_HASH_STRING
*/ */
static int strHash(const void *pKey, int nKey){ static int fts3StrHash(const void *pKey, int nKey){
const char *z = (const char *)pKey; const char *z = (const char *)pKey;
int h = 0; int h = 0;
if( nKey<=0 ) nKey = (int) strlen(z); if( nKey<=0 ) nKey = (int) strlen(z);
@ -99,15 +104,15 @@ static int strHash(const void *pKey, int nKey){
} }
return h & 0x7fffffff; return h & 0x7fffffff;
} }
static int strCompare(const void *pKey1, int n1, const void *pKey2, int n2){ static int fts3StrCompare(const void *pKey1, int n1, const void *pKey2, int n2){
if( n1!=n2 ) return 1; if( n1!=n2 ) return 1;
return strncmp((const char*)pKey1,(const char*)pKey2,n1); return strncmp((const char*)pKey1,(const char*)pKey2,n1);
} }
/* /*
** Hash and comparison functions when the mode is FTS2_HASH_BINARY ** Hash and comparison functions when the mode is FTS3_HASH_BINARY
*/ */
static int binHash(const void *pKey, int nKey){ static int fts3BinHash(const void *pKey, int nKey){
int h = 0; int h = 0;
const char *z = (const char *)pKey; const char *z = (const char *)pKey;
while( nKey-- > 0 ){ while( nKey-- > 0 ){
@ -115,7 +120,7 @@ static int binHash(const void *pKey, int nKey){
} }
return h & 0x7fffffff; return h & 0x7fffffff;
} }
static int binCompare(const void *pKey1, int n1, const void *pKey2, int n2){ static int fts3BinCompare(const void *pKey1, int n1, const void *pKey2, int n2){
if( n1!=n2 ) return 1; if( n1!=n2 ) return 1;
return memcmp(pKey1,pKey2,n1); return memcmp(pKey1,pKey2,n1);
} }
@ -126,18 +131,18 @@ static int binCompare(const void *pKey1, int n1, const void *pKey2, int n2){
** The C syntax in this function definition may be unfamilar to some ** The C syntax in this function definition may be unfamilar to some
** programmers, so we provide the following additional explanation: ** programmers, so we provide the following additional explanation:
** **
** The name of the function is "hashFunction". The function takes a ** The name of the function is "ftsHashFunction". The function takes a
** single parameter "keyClass". The return value of hashFunction() ** single parameter "keyClass". The return value of ftsHashFunction()
** is a pointer to another function. Specifically, the return value ** is a pointer to another function. Specifically, the return value
** of hashFunction() is a pointer to a function that takes two parameters ** of ftsHashFunction() is a pointer to a function that takes two parameters
** with types "const void*" and "int" and returns an "int". ** with types "const void*" and "int" and returns an "int".
*/ */
static int (*hashFunction(int keyClass))(const void*,int){ static int (*ftsHashFunction(int keyClass))(const void*,int){
if( keyClass==FTS2_HASH_STRING ){ if( keyClass==FTS3_HASH_STRING ){
return &strHash; return &fts3StrHash;
}else{ }else{
assert( keyClass==FTS2_HASH_BINARY ); assert( keyClass==FTS3_HASH_BINARY );
return &binHash; return &fts3BinHash;
} }
} }
@ -147,23 +152,23 @@ static int (*hashFunction(int keyClass))(const void*,int){
** For help in interpreted the obscure C code in the function definition, ** For help in interpreted the obscure C code in the function definition,
** see the header comment on the previous function. ** see the header comment on the previous function.
*/ */
static int (*compareFunction(int keyClass))(const void*,int,const void*,int){ static int (*ftsCompareFunction(int keyClass))(const void*,int,const void*,int){
if( keyClass==FTS2_HASH_STRING ){ if( keyClass==FTS3_HASH_STRING ){
return &strCompare; return &fts3StrCompare;
}else{ }else{
assert( keyClass==FTS2_HASH_BINARY ); assert( keyClass==FTS3_HASH_BINARY );
return &binCompare; return &fts3BinCompare;
} }
} }
/* Link an element into the hash table /* Link an element into the hash table
*/ */
static void insertElement( static void fts3HashInsertElement(
fts2Hash *pH, /* The complete hash table */ fts3Hash *pH, /* The complete hash table */
struct _fts2ht *pEntry, /* The entry into which pNew is inserted */ struct _fts3ht *pEntry, /* The entry into which pNew is inserted */
fts2HashElem *pNew /* The element to be inserted */ fts3HashElem *pNew /* The element to be inserted */
){ ){
fts2HashElem *pHead; /* First element already in pEntry */ fts3HashElem *pHead; /* First element already in pEntry */
pHead = pEntry->chain; pHead = pEntry->chain;
if( pHead ){ if( pHead ){
pNew->next = pHead; pNew->next = pHead;
@ -186,22 +191,22 @@ static void insertElement(
** "new_size" must be a power of 2. The hash table might fail ** "new_size" must be a power of 2. The hash table might fail
** to resize if sqliteMalloc() fails. ** to resize if sqliteMalloc() fails.
*/ */
static void rehash(fts2Hash *pH, int new_size){ static void fts3Rehash(fts3Hash *pH, int new_size){
struct _fts2ht *new_ht; /* The new hash table */ struct _fts3ht *new_ht; /* The new hash table */
fts2HashElem *elem, *next_elem; /* For looping over existing elements */ fts3HashElem *elem, *next_elem; /* For looping over existing elements */
int (*xHash)(const void*,int); /* The hash function */ int (*xHash)(const void*,int); /* The hash function */
assert( (new_size & (new_size-1))==0 ); assert( (new_size & (new_size-1))==0 );
new_ht = (struct _fts2ht *)pH->xMalloc( new_size*sizeof(struct _fts2ht) ); new_ht = (struct _fts3ht *)fts3HashMalloc( new_size*sizeof(struct _fts3ht) );
if( new_ht==0 ) return; if( new_ht==0 ) return;
if( pH->ht ) pH->xFree(pH->ht); fts3HashFree(pH->ht);
pH->ht = new_ht; pH->ht = new_ht;
pH->htsize = new_size; pH->htsize = new_size;
xHash = hashFunction(pH->keyClass); xHash = ftsHashFunction(pH->keyClass);
for(elem=pH->first, pH->first=0; elem; elem = next_elem){ for(elem=pH->first, pH->first=0; elem; elem = next_elem){
int h = (*xHash)(elem->pKey, elem->nKey) & (new_size-1); int h = (*xHash)(elem->pKey, elem->nKey) & (new_size-1);
next_elem = elem->next; next_elem = elem->next;
insertElement(pH, &new_ht[h], elem); fts3HashInsertElement(pH, &new_ht[h], elem);
} }
} }
@ -209,21 +214,21 @@ static void rehash(fts2Hash *pH, int new_size){
** hash table that matches the given key. The hash for this key has ** hash table that matches the given key. The hash for this key has
** already been computed and is passed as the 4th parameter. ** already been computed and is passed as the 4th parameter.
*/ */
static fts2HashElem *findElementGivenHash( static fts3HashElem *fts3FindElementByHash(
const fts2Hash *pH, /* The pH to be searched */ const fts3Hash *pH, /* The pH to be searched */
const void *pKey, /* The key we are searching for */ const void *pKey, /* The key we are searching for */
int nKey, int nKey,
int h /* The hash for this key. */ int h /* The hash for this key. */
){ ){
fts2HashElem *elem; /* Used to loop thru the element list */ fts3HashElem *elem; /* Used to loop thru the element list */
int count; /* Number of elements left to test */ int count; /* Number of elements left to test */
int (*xCompare)(const void*,int,const void*,int); /* comparison function */ int (*xCompare)(const void*,int,const void*,int); /* comparison function */
if( pH->ht ){ if( pH->ht ){
struct _fts2ht *pEntry = &pH->ht[h]; struct _fts3ht *pEntry = &pH->ht[h];
elem = pEntry->chain; elem = pEntry->chain;
count = pEntry->count; count = pEntry->count;
xCompare = compareFunction(pH->keyClass); xCompare = ftsCompareFunction(pH->keyClass);
while( count-- && elem ){ while( count-- && elem ){
if( (*xCompare)(elem->pKey,elem->nKey,pKey,nKey)==0 ){ if( (*xCompare)(elem->pKey,elem->nKey,pKey,nKey)==0 ){
return elem; return elem;
@ -237,12 +242,12 @@ static fts2HashElem *findElementGivenHash(
/* Remove a single entry from the hash table given a pointer to that /* Remove a single entry from the hash table given a pointer to that
** element and a hash on the element's key. ** element and a hash on the element's key.
*/ */
static void removeElementGivenHash( static void fts3RemoveElementByHash(
fts2Hash *pH, /* The pH containing "elem" */ fts3Hash *pH, /* The pH containing "elem" */
fts2HashElem* elem, /* The element to be removed from the pH */ fts3HashElem* elem, /* The element to be removed from the pH */
int h /* Hash value for the element */ int h /* Hash value for the element */
){ ){
struct _fts2ht *pEntry; struct _fts3ht *pEntry;
if( elem->prev ){ if( elem->prev ){
elem->prev->next = elem->next; elem->prev->next = elem->next;
}else{ }else{
@ -260,14 +265,14 @@ static void removeElementGivenHash(
pEntry->chain = 0; pEntry->chain = 0;
} }
if( pH->copyKey && elem->pKey ){ if( pH->copyKey && elem->pKey ){
pH->xFree(elem->pKey); fts3HashFree(elem->pKey);
} }
pH->xFree( elem ); fts3HashFree( elem );
pH->count--; pH->count--;
if( pH->count<=0 ){ if( pH->count<=0 ){
assert( pH->first==0 ); assert( pH->first==0 );
assert( pH->count==0 ); assert( pH->count==0 );
fts2HashClear(pH); fts3HashClear(pH);
} }
} }
@ -275,17 +280,17 @@ static void removeElementGivenHash(
** that matches pKey,nKey. Return the data for this element if it is ** that matches pKey,nKey. Return the data for this element if it is
** found, or NULL if there is no match. ** found, or NULL if there is no match.
*/ */
void *sqlite3Fts2HashFind(const fts2Hash *pH, const void *pKey, int nKey){ void *sqlite3Fts3HashFind(const fts3Hash *pH, const void *pKey, int nKey){
int h; /* A hash on key */ int h; /* A hash on key */
fts2HashElem *elem; /* The element that matches key */ fts3HashElem *elem; /* The element that matches key */
int (*xHash)(const void*,int); /* The hash function */ int (*xHash)(const void*,int); /* The hash function */
if( pH==0 || pH->ht==0 ) return 0; if( pH==0 || pH->ht==0 ) return 0;
xHash = hashFunction(pH->keyClass); xHash = ftsHashFunction(pH->keyClass);
assert( xHash!=0 ); assert( xHash!=0 );
h = (*xHash)(pKey,nKey); h = (*xHash)(pKey,nKey);
assert( (pH->htsize & (pH->htsize-1))==0 ); assert( (pH->htsize & (pH->htsize-1))==0 );
elem = findElementGivenHash(pH,pKey,nKey, h & (pH->htsize-1)); elem = fts3FindElementByHash(pH,pKey,nKey, h & (pH->htsize-1));
return elem ? elem->data : 0; return elem ? elem->data : 0;
} }
@ -304,41 +309,48 @@ void *sqlite3Fts2HashFind(const fts2Hash *pH, const void *pKey, int nKey){
** If the "data" parameter to this function is NULL, then the ** If the "data" parameter to this function is NULL, then the
** element corresponding to "key" is removed from the hash table. ** element corresponding to "key" is removed from the hash table.
*/ */
void *sqlite3Fts2HashInsert( void *sqlite3Fts3HashInsert(
fts2Hash *pH, /* The hash table to insert into */ fts3Hash *pH, /* The hash table to insert into */
const void *pKey, /* The key */ const void *pKey, /* The key */
int nKey, /* Number of bytes in the key */ int nKey, /* Number of bytes in the key */
void *data /* The data */ void *data /* The data */
){ ){
int hraw; /* Raw hash value of the key */ int hraw; /* Raw hash value of the key */
int h; /* the hash of the key modulo hash table size */ int h; /* the hash of the key modulo hash table size */
fts2HashElem *elem; /* Used to loop thru the element list */ fts3HashElem *elem; /* Used to loop thru the element list */
fts2HashElem *new_elem; /* New element added to the pH */ fts3HashElem *new_elem; /* New element added to the pH */
int (*xHash)(const void*,int); /* The hash function */ int (*xHash)(const void*,int); /* The hash function */
assert( pH!=0 ); assert( pH!=0 );
xHash = hashFunction(pH->keyClass); xHash = ftsHashFunction(pH->keyClass);
assert( xHash!=0 ); assert( xHash!=0 );
hraw = (*xHash)(pKey, nKey); hraw = (*xHash)(pKey, nKey);
assert( (pH->htsize & (pH->htsize-1))==0 ); assert( (pH->htsize & (pH->htsize-1))==0 );
h = hraw & (pH->htsize-1); h = hraw & (pH->htsize-1);
elem = findElementGivenHash(pH,pKey,nKey,h); elem = fts3FindElementByHash(pH,pKey,nKey,h);
if( elem ){ if( elem ){
void *old_data = elem->data; void *old_data = elem->data;
if( data==0 ){ if( data==0 ){
removeElementGivenHash(pH,elem,h); fts3RemoveElementByHash(pH,elem,h);
}else{ }else{
elem->data = data; elem->data = data;
} }
return old_data; return old_data;
} }
if( data==0 ) return 0; if( data==0 ) return 0;
new_elem = (fts2HashElem*)pH->xMalloc( sizeof(fts2HashElem) ); if( pH->htsize==0 ){
fts3Rehash(pH,8);
if( pH->htsize==0 ){
pH->count = 0;
return data;
}
}
new_elem = (fts3HashElem*)fts3HashMalloc( sizeof(fts3HashElem) );
if( new_elem==0 ) return data; if( new_elem==0 ) return data;
if( pH->copyKey && pKey!=0 ){ if( pH->copyKey && pKey!=0 ){
new_elem->pKey = pH->xMalloc( nKey ); new_elem->pKey = fts3HashMalloc( nKey );
if( new_elem->pKey==0 ){ if( new_elem->pKey==0 ){
pH->xFree(new_elem); fts3HashFree(new_elem);
return data; return data;
} }
memcpy((void*)new_elem->pKey, pKey, nKey); memcpy((void*)new_elem->pKey, pKey, nKey);
@ -347,23 +359,15 @@ void *sqlite3Fts2HashInsert(
} }
new_elem->nKey = nKey; new_elem->nKey = nKey;
pH->count++; pH->count++;
if( pH->htsize==0 ){
rehash(pH,8);
if( pH->htsize==0 ){
pH->count = 0;
pH->xFree(new_elem);
return data;
}
}
if( pH->count > pH->htsize ){ if( pH->count > pH->htsize ){
rehash(pH,pH->htsize*2); fts3Rehash(pH,pH->htsize*2);
} }
assert( pH->htsize>0 ); assert( pH->htsize>0 );
assert( (pH->htsize & (pH->htsize-1))==0 ); assert( (pH->htsize & (pH->htsize-1))==0 );
h = hraw & (pH->htsize-1); h = hraw & (pH->htsize-1);
insertElement(pH, &pH->ht[h], new_elem); fts3HashInsertElement(pH, &pH->ht[h], new_elem);
new_elem->data = data; new_elem->data = data;
return 0; return 0;
} }
#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS2) */ #endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) */

View file

@ -14,12 +14,12 @@
** hash table implementation for the full-text indexing module. ** hash table implementation for the full-text indexing module.
** **
*/ */
#ifndef _FTS2_HASH_H_ #ifndef _FTS3_HASH_H_
#define _FTS2_HASH_H_ #define _FTS3_HASH_H_
/* Forward declarations of structures. */ /* Forward declarations of structures. */
typedef struct fts2Hash fts2Hash; typedef struct fts3Hash fts3Hash;
typedef struct fts2HashElem fts2HashElem; typedef struct fts3HashElem fts3HashElem;
/* A complete hash table is an instance of the following structure. /* A complete hash table is an instance of the following structure.
** The internals of this structure are intended to be opaque -- client ** The internals of this structure are intended to be opaque -- client
@ -29,17 +29,15 @@ typedef struct fts2HashElem fts2HashElem;
** accessing this structure are really macros, so we can't really make ** accessing this structure are really macros, so we can't really make
** this structure opaque. ** this structure opaque.
*/ */
struct fts2Hash { struct fts3Hash {
char keyClass; /* HASH_INT, _POINTER, _STRING, _BINARY */ char keyClass; /* HASH_INT, _POINTER, _STRING, _BINARY */
char copyKey; /* True if copy of key made on insert */ char copyKey; /* True if copy of key made on insert */
int count; /* Number of entries in this table */ int count; /* Number of entries in this table */
fts2HashElem *first; /* The first element of the array */ fts3HashElem *first; /* The first element of the array */
void *(*xMalloc)(int); /* malloc() function to use */
void (*xFree)(void *); /* free() function to use */
int htsize; /* Number of buckets in the hash table */ int htsize; /* Number of buckets in the hash table */
struct _fts2ht { /* the hash table */ struct _fts3ht { /* the hash table */
int count; /* Number of entries with this hash */ int count; /* Number of entries with this hash */
fts2HashElem *chain; /* Pointer to first entry with this hash */ fts3HashElem *chain; /* Pointer to first entry with this hash */
} *ht; } *ht;
}; };
@ -49,8 +47,8 @@ struct fts2Hash {
** Again, this structure is intended to be opaque, but it can't really ** Again, this structure is intended to be opaque, but it can't really
** be opaque because it is used by macros. ** be opaque because it is used by macros.
*/ */
struct fts2HashElem { struct fts3HashElem {
fts2HashElem *next, *prev; /* Next and previous elements in the table */ fts3HashElem *next, *prev; /* Next and previous elements in the table */
void *data; /* Data associated with this element */ void *data; /* Data associated with this element */
void *pKey; int nKey; /* Key associated with this element */ void *pKey; int nKey; /* Key associated with this element */
}; };
@ -58,55 +56,55 @@ struct fts2HashElem {
/* /*
** There are 2 different modes of operation for a hash table: ** There are 2 different modes of operation for a hash table:
** **
** FTS2_HASH_STRING pKey points to a string that is nKey bytes long ** FTS3_HASH_STRING pKey points to a string that is nKey bytes long
** (including the null-terminator, if any). Case ** (including the null-terminator, if any). Case
** is respected in comparisons. ** is respected in comparisons.
** **
** FTS2_HASH_BINARY pKey points to binary data nKey bytes long. ** FTS3_HASH_BINARY pKey points to binary data nKey bytes long.
** memcmp() is used to compare keys. ** memcmp() is used to compare keys.
** **
** A copy of the key is made if the copyKey parameter to fts2HashInit is 1. ** A copy of the key is made if the copyKey parameter to fts3HashInit is 1.
*/ */
#define FTS2_HASH_STRING 1 #define FTS3_HASH_STRING 1
#define FTS2_HASH_BINARY 2 #define FTS3_HASH_BINARY 2
/* /*
** Access routines. To delete, insert a NULL pointer. ** Access routines. To delete, insert a NULL pointer.
*/ */
void sqlite3Fts2HashInit(fts2Hash*, int keytype, int copyKey); void sqlite3Fts3HashInit(fts3Hash*, int keytype, int copyKey);
void *sqlite3Fts2HashInsert(fts2Hash*, const void *pKey, int nKey, void *pData); void *sqlite3Fts3HashInsert(fts3Hash*, const void *pKey, int nKey, void *pData);
void *sqlite3Fts2HashFind(const fts2Hash*, const void *pKey, int nKey); void *sqlite3Fts3HashFind(const fts3Hash*, const void *pKey, int nKey);
void sqlite3Fts2HashClear(fts2Hash*); void sqlite3Fts3HashClear(fts3Hash*);
/* /*
** Shorthand for the functions above ** Shorthand for the functions above
*/ */
#define fts2HashInit sqlite3Fts2HashInit #define fts3HashInit sqlite3Fts3HashInit
#define fts2HashInsert sqlite3Fts2HashInsert #define fts3HashInsert sqlite3Fts3HashInsert
#define fts2HashFind sqlite3Fts2HashFind #define fts3HashFind sqlite3Fts3HashFind
#define fts2HashClear sqlite3Fts2HashClear #define fts3HashClear sqlite3Fts3HashClear
/* /*
** Macros for looping over all elements of a hash table. The idiom is ** Macros for looping over all elements of a hash table. The idiom is
** like this: ** like this:
** **
** fts2Hash h; ** fts3Hash h;
** fts2HashElem *p; ** fts3HashElem *p;
** ... ** ...
** for(p=fts2HashFirst(&h); p; p=fts2HashNext(p)){ ** for(p=fts3HashFirst(&h); p; p=fts3HashNext(p)){
** SomeStructure *pData = fts2HashData(p); ** SomeStructure *pData = fts3HashData(p);
** // do something with pData ** // do something with pData
** } ** }
*/ */
#define fts2HashFirst(H) ((H)->first) #define fts3HashFirst(H) ((H)->first)
#define fts2HashNext(E) ((E)->next) #define fts3HashNext(E) ((E)->next)
#define fts2HashData(E) ((E)->data) #define fts3HashData(E) ((E)->data)
#define fts2HashKey(E) ((E)->pKey) #define fts3HashKey(E) ((E)->pKey)
#define fts2HashKeysize(E) ((E)->nKey) #define fts3HashKeysize(E) ((E)->nKey)
/* /*
** Number of entries in a hash table ** Number of entries in a hash table
*/ */
#define fts2HashCount(H) ((H)->count) #define fts3HashCount(H) ((H)->count)
#endif /* _FTS2_HASH_H_ */ #endif /* _FTS3_HASH_H_ */

View file

@ -9,17 +9,17 @@
** May you share freely, never taking more than you give. ** May you share freely, never taking more than you give.
** **
************************************************************************* *************************************************************************
** This file implements a tokenizer for fts2 based on the ICU library. ** This file implements a tokenizer for fts3 based on the ICU library.
** **
** $Id: fts2_icu.c,v 1.1 2007/06/22 15:21:16 danielk1977 Exp $ ** $Id: fts3_icu.c,v 1.3 2008/09/01 18:34:20 danielk1977 Exp $
*/ */
#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS2) #if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3)
#ifdef SQLITE_ENABLE_ICU #ifdef SQLITE_ENABLE_ICU
#include <assert.h> #include <assert.h>
#include <string.h> #include <string.h>
#include "fts2_tokenizer.h" #include "fts3_tokenizer.h"
#include <unicode/ubrk.h> #include <unicode/ubrk.h>
#include <unicode/ucol.h> #include <unicode/ucol.h>
@ -112,6 +112,9 @@ static int icuOpen(
*ppCursor = 0; *ppCursor = 0;
if( nInput<0 ){
nInput = strlen(zInput);
}
nChar = nInput+1; nChar = nInput+1;
pCsr = (IcuCursor *)sqlite3_malloc( pCsr = (IcuCursor *)sqlite3_malloc(
sizeof(IcuCursor) + /* IcuCursor */ sizeof(IcuCursor) + /* IcuCursor */
@ -247,11 +250,11 @@ static const sqlite3_tokenizer_module icuTokenizerModule = {
/* /*
** Set *ppModule to point at the implementation of the ICU tokenizer. ** Set *ppModule to point at the implementation of the ICU tokenizer.
*/ */
void sqlite3Fts2IcuTokenizerModule( void sqlite3Fts3IcuTokenizerModule(
sqlite3_tokenizer_module const**ppModule sqlite3_tokenizer_module const**ppModule
){ ){
*ppModule = &icuTokenizerModule; *ppModule = &icuTokenizerModule;
} }
#endif /* defined(SQLITE_ENABLE_ICU) */ #endif /* defined(SQLITE_ENABLE_ICU) */
#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS2) */ #endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) */

View file

@ -16,13 +16,13 @@
/* /*
** The code in this file is only compiled if: ** The code in this file is only compiled if:
** **
** * The FTS2 module is being built as an extension ** * The FTS3 module is being built as an extension
** (in which case SQLITE_CORE is not defined), or ** (in which case SQLITE_CORE is not defined), or
** **
** * The FTS2 module is being built into the core of ** * The FTS3 module is being built into the core of
** SQLite (in which case SQLITE_ENABLE_FTS2 is defined). ** SQLite (in which case SQLITE_ENABLE_FTS3 is defined).
*/ */
#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS2) #if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3)
#include <assert.h> #include <assert.h>
@ -31,7 +31,7 @@
#include <string.h> #include <string.h>
#include <ctype.h> #include <ctype.h>
#include "fts2_tokenizer.h" #include "fts3_tokenizer.h"
/* /*
** Class derived from sqlite3_tokenizer ** Class derived from sqlite3_tokenizer
@ -66,9 +66,9 @@ static int porterCreate(
sqlite3_tokenizer **ppTokenizer sqlite3_tokenizer **ppTokenizer
){ ){
porter_tokenizer *t; porter_tokenizer *t;
t = (porter_tokenizer *) calloc(sizeof(*t), 1); t = (porter_tokenizer *) sqlite3_malloc(sizeof(*t));
if( t==NULL ) return SQLITE_NOMEM; if( t==NULL ) return SQLITE_NOMEM;
memset(t, 0, sizeof(*t));
*ppTokenizer = &t->base; *ppTokenizer = &t->base;
return SQLITE_OK; return SQLITE_OK;
} }
@ -77,7 +77,7 @@ static int porterCreate(
** Destroy a tokenizer ** Destroy a tokenizer
*/ */
static int porterDestroy(sqlite3_tokenizer *pTokenizer){ static int porterDestroy(sqlite3_tokenizer *pTokenizer){
free(pTokenizer); sqlite3_free(pTokenizer);
return SQLITE_OK; return SQLITE_OK;
} }
@ -94,7 +94,7 @@ static int porterOpen(
){ ){
porter_tokenizer_cursor *c; porter_tokenizer_cursor *c;
c = (porter_tokenizer_cursor *) malloc(sizeof(*c)); c = (porter_tokenizer_cursor *) sqlite3_malloc(sizeof(*c));
if( c==NULL ) return SQLITE_NOMEM; if( c==NULL ) return SQLITE_NOMEM;
c->zInput = zInput; c->zInput = zInput;
@ -120,8 +120,8 @@ static int porterOpen(
*/ */
static int porterClose(sqlite3_tokenizer_cursor *pCursor){ static int porterClose(sqlite3_tokenizer_cursor *pCursor){
porter_tokenizer_cursor *c = (porter_tokenizer_cursor *) pCursor; porter_tokenizer_cursor *c = (porter_tokenizer_cursor *) pCursor;
free(c->zToken); sqlite3_free(c->zToken);
free(c); sqlite3_free(c);
return SQLITE_OK; return SQLITE_OK;
} }
/* /*
@ -603,7 +603,7 @@ static int porterNext(
int n = c->iOffset-iStartOffset; int n = c->iOffset-iStartOffset;
if( n>c->nAllocated ){ if( n>c->nAllocated ){
c->nAllocated = n+20; c->nAllocated = n+20;
c->zToken = realloc(c->zToken, c->nAllocated); c->zToken = sqlite3_realloc(c->zToken, c->nAllocated);
if( c->zToken==NULL ) return SQLITE_NOMEM; if( c->zToken==NULL ) return SQLITE_NOMEM;
} }
porter_stemmer(&z[iStartOffset], n, c->zToken, pnBytes); porter_stemmer(&z[iStartOffset], n, c->zToken, pnBytes);
@ -633,10 +633,10 @@ static const sqlite3_tokenizer_module porterTokenizerModule = {
** Allocate a new porter tokenizer. Return a pointer to the new ** Allocate a new porter tokenizer. Return a pointer to the new
** tokenizer in *ppModule ** tokenizer in *ppModule
*/ */
void sqlite3Fts2PorterTokenizerModule( void sqlite3Fts3PorterTokenizerModule(
sqlite3_tokenizer_module const**ppModule sqlite3_tokenizer_module const**ppModule
){ ){
*ppModule = &porterTokenizerModule; *ppModule = &porterTokenizerModule;
} }
#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS2) */ #endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) */

View file

@ -17,20 +17,21 @@
/* /*
** The code in this file is only compiled if: ** The code in this file is only compiled if:
** **
** * The FTS2 module is being built as an extension ** * The FTS3 module is being built as an extension
** (in which case SQLITE_CORE is not defined), or ** (in which case SQLITE_CORE is not defined), or
** **
** * The FTS2 module is being built into the core of ** * The FTS3 module is being built into the core of
** SQLite (in which case SQLITE_ENABLE_FTS2 is defined). ** SQLite (in which case SQLITE_ENABLE_FTS3 is defined).
*/ */
#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS2) #if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3)
#include "sqlite3.h"
#include "sqlite3ext.h" #include "sqlite3ext.h"
#ifndef SQLITE_CORE
SQLITE_EXTENSION_INIT1
#endif
#include "fts2_hash.h" #include "fts3_hash.h"
#include "fts2_tokenizer.h" #include "fts3_tokenizer.h"
#include <assert.h> #include <assert.h>
/* /*
@ -41,7 +42,7 @@
** SELECT <function-name>(<key-name>, <pointer>); ** SELECT <function-name>(<key-name>, <pointer>);
** **
** where <function-name> is the name passed as the second argument ** where <function-name> is the name passed as the second argument
** to the sqlite3Fts2InitHashTable() function (e.g. 'fts2_tokenizer'). ** to the sqlite3Fts3InitHashTable() function (e.g. 'fts3_tokenizer').
** **
** If the <pointer> argument is specified, it must be a blob value ** If the <pointer> argument is specified, it must be a blob value
** containing a pointer to be stored as the hash data corresponding ** containing a pointer to be stored as the hash data corresponding
@ -58,14 +59,14 @@ static void scalarFunc(
int argc, int argc,
sqlite3_value **argv sqlite3_value **argv
){ ){
fts2Hash *pHash; fts3Hash *pHash;
void *pPtr = 0; void *pPtr = 0;
const unsigned char *zName; const unsigned char *zName;
int nName; int nName;
assert( argc==1 || argc==2 ); assert( argc==1 || argc==2 );
pHash = (fts2Hash *)sqlite3_user_data(context); pHash = (fts3Hash *)sqlite3_user_data(context);
zName = sqlite3_value_text(argv[0]); zName = sqlite3_value_text(argv[0]);
nName = sqlite3_value_bytes(argv[0])+1; nName = sqlite3_value_bytes(argv[0])+1;
@ -78,13 +79,13 @@ static void scalarFunc(
return; return;
} }
pPtr = *(void **)sqlite3_value_blob(argv[1]); pPtr = *(void **)sqlite3_value_blob(argv[1]);
pOld = sqlite3Fts2HashInsert(pHash, (void *)zName, nName, pPtr); pOld = sqlite3Fts3HashInsert(pHash, (void *)zName, nName, pPtr);
if( pOld==pPtr ){ if( pOld==pPtr ){
sqlite3_result_error(context, "out of memory", -1); sqlite3_result_error(context, "out of memory", -1);
return; return;
} }
}else{ }else{
pPtr = sqlite3Fts2HashFind(pHash, zName, nName); pPtr = sqlite3Fts3HashFind(pHash, zName, nName);
if( !pPtr ){ if( !pPtr ){
char *zErr = sqlite3_mprintf("unknown tokenizer: %s", zName); char *zErr = sqlite3_mprintf("unknown tokenizer: %s", zName);
sqlite3_result_error(context, zErr, -1); sqlite3_result_error(context, zErr, -1);
@ -110,8 +111,8 @@ static void scalarFunc(
** SELECT <function-name>(<key-name>, <pointer>); ** SELECT <function-name>(<key-name>, <pointer>);
** **
** where <function-name> is the name passed as the second argument ** where <function-name> is the name passed as the second argument
** to the sqlite3Fts2InitHashTable() function (e.g. 'fts2_tokenizer') ** to the sqlite3Fts3InitHashTable() function (e.g. 'fts3_tokenizer')
** concatenated with the string '_test' (e.g. 'fts2_tokenizer_test'). ** concatenated with the string '_test' (e.g. 'fts3_tokenizer_test').
** **
** The return value is a string that may be interpreted as a Tcl ** The return value is a string that may be interpreted as a Tcl
** list. For each token in the <input-string>, three elements are ** list. For each token in the <input-string>, three elements are
@ -132,7 +133,7 @@ static void testFunc(
int argc, int argc,
sqlite3_value **argv sqlite3_value **argv
){ ){
fts2Hash *pHash; fts3Hash *pHash;
sqlite3_tokenizer_module *p; sqlite3_tokenizer_module *p;
sqlite3_tokenizer *pTokenizer = 0; sqlite3_tokenizer *pTokenizer = 0;
sqlite3_tokenizer_cursor *pCsr = 0; sqlite3_tokenizer_cursor *pCsr = 0;
@ -165,8 +166,8 @@ static void testFunc(
zArg = (const char *)sqlite3_value_text(argv[1]); zArg = (const char *)sqlite3_value_text(argv[1]);
} }
pHash = (fts2Hash *)sqlite3_user_data(context); pHash = (fts3Hash *)sqlite3_user_data(context);
p = (sqlite3_tokenizer_module *)sqlite3Fts2HashFind(pHash, zName, nName+1); p = (sqlite3_tokenizer_module *)sqlite3Fts3HashFind(pHash, zName, nName+1);
if( !p ){ if( !p ){
char *zErr = sqlite3_mprintf("unknown tokenizer: %s", zName); char *zErr = sqlite3_mprintf("unknown tokenizer: %s", zName);
@ -223,7 +224,7 @@ int registerTokenizer(
){ ){
int rc; int rc;
sqlite3_stmt *pStmt; sqlite3_stmt *pStmt;
const char zSql[] = "SELECT fts2_tokenizer(?, ?)"; const char zSql[] = "SELECT fts3_tokenizer(?, ?)";
rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0); rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0);
if( rc!=SQLITE_OK ){ if( rc!=SQLITE_OK ){
@ -245,7 +246,7 @@ int queryTokenizer(
){ ){
int rc; int rc;
sqlite3_stmt *pStmt; sqlite3_stmt *pStmt;
const char zSql[] = "SELECT fts2_tokenizer(?)"; const char zSql[] = "SELECT fts3_tokenizer(?)";
*pp = 0; *pp = 0;
rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0); rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0);
@ -263,24 +264,24 @@ int queryTokenizer(
return sqlite3_finalize(pStmt); return sqlite3_finalize(pStmt);
} }
void sqlite3Fts2SimpleTokenizerModule(sqlite3_tokenizer_module const**ppModule); void sqlite3Fts3SimpleTokenizerModule(sqlite3_tokenizer_module const**ppModule);
/* /*
** Implementation of the scalar function fts2_tokenizer_internal_test(). ** Implementation of the scalar function fts3_tokenizer_internal_test().
** This function is used for testing only, it is not included in the ** This function is used for testing only, it is not included in the
** build unless SQLITE_TEST is defined. ** build unless SQLITE_TEST is defined.
** **
** The purpose of this is to test that the fts2_tokenizer() function ** The purpose of this is to test that the fts3_tokenizer() function
** can be used as designed by the C-code in the queryTokenizer and ** can be used as designed by the C-code in the queryTokenizer and
** registerTokenizer() functions above. These two functions are repeated ** registerTokenizer() functions above. These two functions are repeated
** in the README.tokenizer file as an example, so it is important to ** in the README.tokenizer file as an example, so it is important to
** test them. ** test them.
** **
** To run the tests, evaluate the fts2_tokenizer_internal_test() scalar ** To run the tests, evaluate the fts3_tokenizer_internal_test() scalar
** function with no arguments. An assert() will fail if a problem is ** function with no arguments. An assert() will fail if a problem is
** detected. i.e.: ** detected. i.e.:
** **
** SELECT fts2_tokenizer_internal_test(); ** SELECT fts3_tokenizer_internal_test();
** **
*/ */
static void intTestFunc( static void intTestFunc(
@ -294,7 +295,7 @@ static void intTestFunc(
sqlite3 *db = (sqlite3 *)sqlite3_user_data(context); sqlite3 *db = (sqlite3 *)sqlite3_user_data(context);
/* Test the query function */ /* Test the query function */
sqlite3Fts2SimpleTokenizerModule(&p1); sqlite3Fts3SimpleTokenizerModule(&p1);
rc = queryTokenizer(db, "simple", &p2); rc = queryTokenizer(db, "simple", &p2);
assert( rc==SQLITE_OK ); assert( rc==SQLITE_OK );
assert( p1==p2 ); assert( p1==p2 );
@ -321,7 +322,7 @@ static void intTestFunc(
** been initialised to use string keys, and to take a private copy ** been initialised to use string keys, and to take a private copy
** of the key when a value is inserted. i.e. by a call similar to: ** of the key when a value is inserted. i.e. by a call similar to:
** **
** sqlite3Fts2HashInit(pHash, FTS2_HASH_STRING, 1); ** sqlite3Fts3HashInit(pHash, FTS3_HASH_STRING, 1);
** **
** This function adds a scalar function (see header comment above ** This function adds a scalar function (see header comment above
** scalarFunc() in this file for details) and, if ENABLE_TABLE is ** scalarFunc() in this file for details) and, if ENABLE_TABLE is
@ -332,9 +333,9 @@ static void intTestFunc(
** The third argument to this function, zName, is used as the name ** The third argument to this function, zName, is used as the name
** of both the scalar and, if created, the virtual table. ** of both the scalar and, if created, the virtual table.
*/ */
int sqlite3Fts2InitHashTable( int sqlite3Fts3InitHashTable(
sqlite3 *db, sqlite3 *db,
fts2Hash *pHash, fts3Hash *pHash,
const char *zName const char *zName
){ ){
int rc = SQLITE_OK; int rc = SQLITE_OK;
@ -367,4 +368,4 @@ int sqlite3Fts2InitHashTable(
return rc; return rc;
} }
#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS2) */ #endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) */

View file

@ -17,8 +17,8 @@
** sqlite3_tokenizer_cursor is generated by a tokenizer to generate ** sqlite3_tokenizer_cursor is generated by a tokenizer to generate
** tokens from a particular input. ** tokens from a particular input.
*/ */
#ifndef _FTS2_TOKENIZER_H_ #ifndef _FTS3_TOKENIZER_H_
#define _FTS2_TOKENIZER_H_ #define _FTS3_TOKENIZER_H_
/* TODO(shess) Only used for SQLITE_OK and SQLITE_DONE at this time. /* TODO(shess) Only used for SQLITE_OK and SQLITE_DONE at this time.
** If tokenizers are to be allowed to call sqlite3_*() functions, then ** If tokenizers are to be allowed to call sqlite3_*() functions, then
@ -32,12 +32,12 @@
** an sqlite3_tokenizer_module containing pointers to the callback ** an sqlite3_tokenizer_module containing pointers to the callback
** functions that make up an implementation. ** functions that make up an implementation.
** **
** When an fts2 table is created, it passes any arguments passed to ** When an fts3 table is created, it passes any arguments passed to
** the tokenizer clause of the CREATE VIRTUAL TABLE statement to the ** the tokenizer clause of the CREATE VIRTUAL TABLE statement to the
** sqlite3_tokenizer_module.xCreate() function of the requested tokenizer ** sqlite3_tokenizer_module.xCreate() function of the requested tokenizer
** implementation. The xCreate() function in turn returns an ** implementation. The xCreate() function in turn returns an
** sqlite3_tokenizer structure representing the specific tokenizer to ** sqlite3_tokenizer structure representing the specific tokenizer to
** be used for the fts2 table (customized by the tokenizer clause arguments). ** be used for the fts3 table (customized by the tokenizer clause arguments).
** **
** To tokenize an input buffer, the sqlite3_tokenizer_module.xOpen() ** To tokenize an input buffer, the sqlite3_tokenizer_module.xOpen()
** method is called. It returns an sqlite3_tokenizer_cursor object ** method is called. It returns an sqlite3_tokenizer_cursor object
@ -59,10 +59,10 @@ struct sqlite3_tokenizer_module {
/* /*
** Create a new tokenizer. The values in the argv[] array are the ** Create a new tokenizer. The values in the argv[] array are the
** arguments passed to the "tokenizer" clause of the CREATE VIRTUAL ** arguments passed to the "tokenizer" clause of the CREATE VIRTUAL
** TABLE statement that created the fts2 table. For example, if ** TABLE statement that created the fts3 table. For example, if
** the following SQL is executed: ** the following SQL is executed:
** **
** CREATE .. USING fts2( ... , tokenizer <tokenizer-name> arg1 arg2) ** CREATE .. USING fts3( ... , tokenizer <tokenizer-name> arg1 arg2)
** **
** then argc is set to 2, and the argv[] array contains pointers ** then argc is set to 2, and the argv[] array contains pointers
** to the strings "arg1" and "arg2". ** to the strings "arg1" and "arg2".
@ -80,7 +80,7 @@ struct sqlite3_tokenizer_module {
); );
/* /*
** Destroy an existing tokenizer. The fts2 module calls this method ** Destroy an existing tokenizer. The fts3 module calls this method
** exactly once for each successful call to xCreate(). ** exactly once for each successful call to xCreate().
*/ */
int (*xDestroy)(sqlite3_tokenizer *pTokenizer); int (*xDestroy)(sqlite3_tokenizer *pTokenizer);
@ -97,7 +97,7 @@ struct sqlite3_tokenizer_module {
); );
/* /*
** Destroy an existing tokenizer cursor. The fts2 module calls this ** Destroy an existing tokenizer cursor. The fts3 module calls this
** method exactly once for each successful call to xOpen(). ** method exactly once for each successful call to xOpen().
*/ */
int (*xClose)(sqlite3_tokenizer_cursor *pCursor); int (*xClose)(sqlite3_tokenizer_cursor *pCursor);
@ -142,4 +142,4 @@ struct sqlite3_tokenizer_cursor {
/* Tokenizer implementations will typically add additional fields */ /* Tokenizer implementations will typically add additional fields */
}; };
#endif /* _FTS2_TOKENIZER_H_ */ #endif /* _FTS3_TOKENIZER_H_ */

View file

@ -16,13 +16,13 @@
/* /*
** The code in this file is only compiled if: ** The code in this file is only compiled if:
** **
** * The FTS2 module is being built as an extension ** * The FTS3 module is being built as an extension
** (in which case SQLITE_CORE is not defined), or ** (in which case SQLITE_CORE is not defined), or
** **
** * The FTS2 module is being built into the core of ** * The FTS3 module is being built into the core of
** SQLite (in which case SQLITE_ENABLE_FTS2 is defined). ** SQLite (in which case SQLITE_ENABLE_FTS3 is defined).
*/ */
#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS2) #if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3)
#include <assert.h> #include <assert.h>
@ -31,7 +31,7 @@
#include <string.h> #include <string.h>
#include <ctype.h> #include <ctype.h>
#include "fts2_tokenizer.h" #include "fts3_tokenizer.h"
typedef struct simple_tokenizer { typedef struct simple_tokenizer {
sqlite3_tokenizer base; sqlite3_tokenizer base;
@ -65,8 +65,9 @@ static int simpleCreate(
){ ){
simple_tokenizer *t; simple_tokenizer *t;
t = (simple_tokenizer *) calloc(sizeof(*t), 1); t = (simple_tokenizer *) sqlite3_malloc(sizeof(*t));
if( t==NULL ) return SQLITE_NOMEM; if( t==NULL ) return SQLITE_NOMEM;
memset(t, 0, sizeof(*t));
/* TODO(shess) Delimiters need to remain the same from run to run, /* TODO(shess) Delimiters need to remain the same from run to run,
** else we need to reindex. One solution would be a meta-table to ** else we need to reindex. One solution would be a meta-table to
@ -79,7 +80,7 @@ static int simpleCreate(
unsigned char ch = argv[1][i]; unsigned char ch = argv[1][i];
/* We explicitly don't support UTF-8 delimiters for now. */ /* We explicitly don't support UTF-8 delimiters for now. */
if( ch>=0x80 ){ if( ch>=0x80 ){
free(t); sqlite3_free(t);
return SQLITE_ERROR; return SQLITE_ERROR;
} }
t->delim[ch] = 1; t->delim[ch] = 1;
@ -100,7 +101,7 @@ static int simpleCreate(
** Destroy a tokenizer ** Destroy a tokenizer
*/ */
static int simpleDestroy(sqlite3_tokenizer *pTokenizer){ static int simpleDestroy(sqlite3_tokenizer *pTokenizer){
free(pTokenizer); sqlite3_free(pTokenizer);
return SQLITE_OK; return SQLITE_OK;
} }
@ -117,7 +118,7 @@ static int simpleOpen(
){ ){
simple_tokenizer_cursor *c; simple_tokenizer_cursor *c;
c = (simple_tokenizer_cursor *) malloc(sizeof(*c)); c = (simple_tokenizer_cursor *) sqlite3_malloc(sizeof(*c));
if( c==NULL ) return SQLITE_NOMEM; if( c==NULL ) return SQLITE_NOMEM;
c->pInput = pInput; c->pInput = pInput;
@ -143,8 +144,8 @@ static int simpleOpen(
*/ */
static int simpleClose(sqlite3_tokenizer_cursor *pCursor){ static int simpleClose(sqlite3_tokenizer_cursor *pCursor){
simple_tokenizer_cursor *c = (simple_tokenizer_cursor *) pCursor; simple_tokenizer_cursor *c = (simple_tokenizer_cursor *) pCursor;
free(c->pToken); sqlite3_free(c->pToken);
free(c); sqlite3_free(c);
return SQLITE_OK; return SQLITE_OK;
} }
@ -182,7 +183,7 @@ static int simpleNext(
int i, n = c->iOffset-iStartOffset; int i, n = c->iOffset-iStartOffset;
if( n>c->nTokenAllocated ){ if( n>c->nTokenAllocated ){
c->nTokenAllocated = n+20; c->nTokenAllocated = n+20;
c->pToken = realloc(c->pToken, c->nTokenAllocated); c->pToken = sqlite3_realloc(c->pToken, c->nTokenAllocated);
if( c->pToken==NULL ) return SQLITE_NOMEM; if( c->pToken==NULL ) return SQLITE_NOMEM;
} }
for(i=0; i<n; i++){ for(i=0; i<n; i++){
@ -220,10 +221,10 @@ static const sqlite3_tokenizer_module simpleTokenizerModule = {
** Allocate a new simple tokenizer. Return a pointer to the new ** Allocate a new simple tokenizer. Return a pointer to the new
** tokenizer in *ppModule ** tokenizer in *ppModule
*/ */
void sqlite3Fts2SimpleTokenizerModule( void sqlite3Fts3SimpleTokenizerModule(
sqlite3_tokenizer_module const**ppModule sqlite3_tokenizer_module const**ppModule
){ ){
*ppModule = &simpleTokenizerModule; *ppModule = &simpleTokenizerModule;
} }
#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS2) */ #endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) */

657
func.c
View file

@ -16,16 +16,13 @@
** sqliteRegisterBuildinFunctions() found at the bottom of the file. ** sqliteRegisterBuildinFunctions() found at the bottom of the file.
** All other code has file scope. ** All other code has file scope.
** **
** $Id: func.c,v 1.163 2007/07/26 06:50:06 danielk1977 Exp $ ** $Id: func.c,v 1.209 2008/12/10 23:04:13 drh Exp $
*/ */
#include "sqliteInt.h" #include "sqliteInt.h"
#include <ctype.h> #include <ctype.h>
/* #include <math.h> */
#include <stdlib.h> #include <stdlib.h>
#include <assert.h> #include <assert.h>
#include "vdbeInt.h" #include "vdbeInt.h"
#include "os.h"
/* /*
** Return the collating function associated with a function. ** Return the collating function associated with a function.
@ -68,10 +65,11 @@ static void minmaxFunc(
*/ */
static void typeofFunc( static void typeofFunc(
sqlite3_context *context, sqlite3_context *context,
int argc, int NotUsed,
sqlite3_value **argv sqlite3_value **argv
){ ){
const char *z = 0; const char *z = 0;
UNUSED_PARAMETER(NotUsed);
switch( sqlite3_value_type(argv[0]) ){ switch( sqlite3_value_type(argv[0]) ){
case SQLITE_NULL: z = "null"; break; case SQLITE_NULL: z = "null"; break;
case SQLITE_INTEGER: z = "integer"; break; case SQLITE_INTEGER: z = "integer"; break;
@ -94,6 +92,7 @@ static void lengthFunc(
int len; int len;
assert( argc==1 ); assert( argc==1 );
UNUSED_PARAMETER(argc);
switch( sqlite3_value_type(argv[0]) ){ switch( sqlite3_value_type(argv[0]) ){
case SQLITE_BLOB: case SQLITE_BLOB:
case SQLITE_INTEGER: case SQLITE_INTEGER:
@ -124,6 +123,7 @@ static void lengthFunc(
*/ */
static void absFunc(sqlite3_context *context, int argc, sqlite3_value **argv){ static void absFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
assert( argc==1 ); assert( argc==1 );
UNUSED_PARAMETER(argc);
switch( sqlite3_value_type(argv[0]) ){ switch( sqlite3_value_type(argv[0]) ){
case SQLITE_INTEGER: { case SQLITE_INTEGER: {
i64 iVal = sqlite3_value_int64(argv[0]); i64 iVal = sqlite3_value_int64(argv[0]);
@ -171,7 +171,7 @@ static void substrFunc(
int p0type; int p0type;
i64 p1, p2; i64 p1, p2;
assert( argc==3 ); assert( argc==3 || argc==2 );
p0type = sqlite3_value_type(argv[0]); p0type = sqlite3_value_type(argv[0]);
if( p0type==SQLITE_BLOB ){ if( p0type==SQLITE_BLOB ){
len = sqlite3_value_bytes(argv[0]); len = sqlite3_value_bytes(argv[0]);
@ -187,7 +187,11 @@ static void substrFunc(
} }
} }
p1 = sqlite3_value_int(argv[1]); p1 = sqlite3_value_int(argv[1]);
p2 = sqlite3_value_int(argv[2]); if( argc==3 ){
p2 = sqlite3_value_int(argv[2]);
}else{
p2 = sqlite3_context_db_handle(context)->aLimit[SQLITE_LIMIT_LENGTH];
}
if( p1<0 ){ if( p1<0 ){
p1 += len; p1 += len;
if( p1<0 ){ if( p1<0 ){
@ -208,10 +212,10 @@ static void substrFunc(
for(z2=z; *z2 && p2; p2--){ for(z2=z; *z2 && p2; p2--){
SQLITE_SKIP_UTF8(z2); SQLITE_SKIP_UTF8(z2);
} }
sqlite3_result_text(context, (char*)z, z2-z, SQLITE_TRANSIENT); sqlite3_result_text(context, (char*)z, (int)(z2-z), SQLITE_TRANSIENT);
}else{ }else{
if( p2<0 ) p2 = 0; if( p2<0 ) p2 = 0;
sqlite3_result_blob(context, (char*)&z[p1], p2, SQLITE_TRANSIENT); sqlite3_result_blob(context, (char*)&z[p1], (int)p2, SQLITE_TRANSIENT);
} }
} }
@ -236,6 +240,25 @@ static void roundFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
sqlite3_result_double(context, r); sqlite3_result_double(context, r);
} }
/*
** Allocate nByte bytes of space using sqlite3_malloc(). If the
** allocation fails, call sqlite3_result_error_nomem() to notify
** the database handle that malloc() has failed.
*/
static void *contextMalloc(sqlite3_context *context, i64 nByte){
char *z;
if( nByte>sqlite3_context_db_handle(context)->aLimit[SQLITE_LIMIT_LENGTH] ){
sqlite3_result_error_toobig(context);
z = 0;
}else{
z = sqlite3Malloc((int)nByte);
if( !z && nByte>0 ){
sqlite3_result_error_nomem(context);
}
}
return z;
}
/* /*
** Implementation of the upper() and lower() SQL functions. ** Implementation of the upper() and lower() SQL functions.
*/ */
@ -249,11 +272,11 @@ static void upperFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
/* Verify that the call to _bytes() does not invalidate the _text() pointer */ /* Verify that the call to _bytes() does not invalidate the _text() pointer */
assert( z2==(char*)sqlite3_value_text(argv[0]) ); assert( z2==(char*)sqlite3_value_text(argv[0]) );
if( z2 ){ if( z2 ){
z1 = sqlite3_malloc(n+1); z1 = contextMalloc(context, ((i64)n)+1);
if( z1 ){ if( z1 ){
memcpy(z1, z2, n+1); memcpy(z1, z2, n+1);
for(i=0; z1[i]; i++){ for(i=0; z1[i]; i++){
z1[i] = toupper(z1[i]); z1[i] = (char)toupper(z1[i]);
} }
sqlite3_result_text(context, z1, -1, sqlite3_free); sqlite3_result_text(context, z1, -1, sqlite3_free);
} }
@ -269,11 +292,11 @@ static void lowerFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
/* Verify that the call to _bytes() does not invalidate the _text() pointer */ /* Verify that the call to _bytes() does not invalidate the _text() pointer */
assert( z2==(char*)sqlite3_value_text(argv[0]) ); assert( z2==(char*)sqlite3_value_text(argv[0]) );
if( z2 ){ if( z2 ){
z1 = sqlite3_malloc(n+1); z1 = contextMalloc(context, ((i64)n)+1);
if( z1 ){ if( z1 ){
memcpy(z1, z2, n+1); memcpy(z1, z2, n+1);
for(i=0; z1[i]; i++){ for(i=0; z1[i]; i++){
z1[i] = tolower(z1[i]); z1[i] = (char)tolower(z1[i]);
} }
sqlite3_result_text(context, z1, -1, sqlite3_free); sqlite3_result_text(context, z1, -1, sqlite3_free);
} }
@ -304,11 +327,12 @@ static void ifnullFunc(
*/ */
static void randomFunc( static void randomFunc(
sqlite3_context *context, sqlite3_context *context,
int argc, int NotUsed,
sqlite3_value **argv sqlite3_value **NotUsed2
){ ){
sqlite_int64 r; sqlite_int64 r;
sqlite3Randomness(sizeof(r), &r); UNUSED_PARAMETER2(NotUsed, NotUsed2);
sqlite3_randomness(sizeof(r), &r);
if( (r<<1)==0 ) r = 0; /* Prevent 0x8000.... as the result so that we */ if( (r<<1)==0 ) r = 0; /* Prevent 0x8000.... as the result so that we */
/* can always do abs() of the result */ /* can always do abs() of the result */
sqlite3_result_int64(context, r); sqlite3_result_int64(context, r);
@ -326,18 +350,15 @@ static void randomBlob(
int n; int n;
unsigned char *p; unsigned char *p;
assert( argc==1 ); assert( argc==1 );
UNUSED_PARAMETER(argc);
n = sqlite3_value_int(argv[0]); n = sqlite3_value_int(argv[0]);
if( n<1 ){ if( n<1 ){
n = 1; n = 1;
} }
if( n>SQLITE_MAX_LENGTH ){ p = contextMalloc(context, n);
sqlite3_result_error_toobig(context);
return;
}
p = sqliteMalloc(n);
if( p ){ if( p ){
sqlite3Randomness(n, p); sqlite3_randomness(n, p);
sqlite3_result_blob(context, (char*)p, n, sqlite3FreeX); sqlite3_result_blob(context, (char*)p, n, sqlite3_free);
} }
} }
@ -347,10 +368,11 @@ static void randomBlob(
*/ */
static void last_insert_rowid( static void last_insert_rowid(
sqlite3_context *context, sqlite3_context *context,
int arg, int NotUsed,
sqlite3_value **argv sqlite3_value **NotUsed2
){ ){
sqlite3 *db = sqlite3_user_data(context); sqlite3 *db = sqlite3_context_db_handle(context);
UNUSED_PARAMETER2(NotUsed, NotUsed2);
sqlite3_result_int64(context, sqlite3_last_insert_rowid(db)); sqlite3_result_int64(context, sqlite3_last_insert_rowid(db));
} }
@ -360,10 +382,11 @@ static void last_insert_rowid(
*/ */
static void changes( static void changes(
sqlite3_context *context, sqlite3_context *context,
int arg, int NotUsed,
sqlite3_value **argv sqlite3_value **NotUsed2
){ ){
sqlite3 *db = sqlite3_user_data(context); sqlite3 *db = sqlite3_context_db_handle(context);
UNUSED_PARAMETER2(NotUsed, NotUsed2);
sqlite3_result_int(context, sqlite3_changes(db)); sqlite3_result_int(context, sqlite3_changes(db));
} }
@ -373,10 +396,11 @@ static void changes(
*/ */
static void total_changes( static void total_changes(
sqlite3_context *context, sqlite3_context *context,
int arg, int NotUsed,
sqlite3_value **argv sqlite3_value **NotUsed2
){ ){
sqlite3 *db = sqlite3_user_data(context); sqlite3 *db = sqlite3_context_db_handle(context);
UNUSED_PARAMETER2(NotUsed, NotUsed2);
sqlite3_result_int(context, sqlite3_total_changes(db)); sqlite3_result_int(context, sqlite3_total_changes(db));
} }
@ -390,6 +414,19 @@ struct compareInfo {
u8 noCase; u8 noCase;
}; };
/*
** For LIKE and GLOB matching on EBCDIC machines, assume that every
** character is exactly one byte in size. Also, all characters are
** able to participate in upper-case-to-lower-case mappings in EBCDIC
** whereas only characters less than 0x80 do in ASCII.
*/
#if defined(SQLITE_EBCDIC)
# define sqlite3Utf8Read(A,B,C) (*(A++))
# define GlogUpperToLower(A) A = sqlite3UpperToLower[A]
#else
# define GlogUpperToLower(A) if( A<0x80 ){ A = sqlite3UpperToLower[A]; }
#endif
static const struct compareInfo globInfo = { '*', '?', '[', 0 }; static const struct compareInfo globInfo = { '*', '?', '[', 0 };
/* The correct SQL-92 behavior is for the LIKE operator to ignore /* The correct SQL-92 behavior is for the LIKE operator to ignore
** case. Thus 'a' LIKE 'A' would be true. */ ** case. Thus 'a' LIKE 'A' would be true. */
@ -466,11 +503,11 @@ static int patternCompare(
} }
while( (c2 = sqlite3Utf8Read(zString,0,&zString))!=0 ){ while( (c2 = sqlite3Utf8Read(zString,0,&zString))!=0 ){
if( noCase ){ if( noCase ){
c2 = c2<0x80 ? sqlite3UpperToLower[c2] : c2; GlogUpperToLower(c2);
c = c<0x80 ? sqlite3UpperToLower[c] : c; GlogUpperToLower(c);
while( c2 != 0 && c2 != c ){ while( c2 != 0 && c2 != c ){
c2 = sqlite3Utf8Read(zString, 0, &zString); c2 = sqlite3Utf8Read(zString, 0, &zString);
if( c2<0x80 ) c2 = sqlite3UpperToLower[c2]; GlogUpperToLower(c2);
} }
}else{ }else{
while( c2 != 0 && c2 != c ){ while( c2 != 0 && c2 != c ){
@ -522,8 +559,8 @@ static int patternCompare(
}else{ }else{
c2 = sqlite3Utf8Read(zString, 0, &zString); c2 = sqlite3Utf8Read(zString, 0, &zString);
if( noCase ){ if( noCase ){
c = c<0x80 ? sqlite3UpperToLower[c] : c; GlogUpperToLower(c);
c2 = c2<0x80 ? sqlite3UpperToLower[c2] : c2; GlogUpperToLower(c2);
} }
if( c!=c2 ){ if( c!=c2 ){
return 0; return 0;
@ -563,6 +600,7 @@ static void likeFunc(
){ ){
const unsigned char *zA, *zB; const unsigned char *zA, *zB;
int escape = 0; int escape = 0;
sqlite3 *db = sqlite3_context_db_handle(context);
zB = sqlite3_value_text(argv[0]); zB = sqlite3_value_text(argv[0]);
zA = sqlite3_value_text(argv[1]); zA = sqlite3_value_text(argv[1]);
@ -570,7 +608,8 @@ static void likeFunc(
/* Limit the length of the LIKE or GLOB pattern to avoid problems /* Limit the length of the LIKE or GLOB pattern to avoid problems
** of deep recursion and N*N behavior in patternCompare(). ** of deep recursion and N*N behavior in patternCompare().
*/ */
if( sqlite3_value_bytes(argv[0])>SQLITE_MAX_LIKE_PATTERN_LENGTH ){ if( sqlite3_value_bytes(argv[0]) >
db->aLimit[SQLITE_LIMIT_LIKE_PATTERN_LENGTH] ){
sqlite3_result_error(context, "LIKE or GLOB pattern too complex", -1); sqlite3_result_error(context, "LIKE or GLOB pattern too complex", -1);
return; return;
} }
@ -606,10 +645,11 @@ static void likeFunc(
*/ */
static void nullifFunc( static void nullifFunc(
sqlite3_context *context, sqlite3_context *context,
int argc, int NotUsed,
sqlite3_value **argv sqlite3_value **argv
){ ){
CollSeq *pColl = sqlite3GetFuncCollSeq(context); CollSeq *pColl = sqlite3GetFuncCollSeq(context);
UNUSED_PARAMETER(NotUsed);
if( sqlite3MemCompare(argv[0], argv[1], pColl)!=0 ){ if( sqlite3MemCompare(argv[0], argv[1], pColl)!=0 ){
sqlite3_result_value(context, argv[0]); sqlite3_result_value(context, argv[0]);
} }
@ -621,9 +661,10 @@ static void nullifFunc(
*/ */
static void versionFunc( static void versionFunc(
sqlite3_context *context, sqlite3_context *context,
int argc, int NotUsed,
sqlite3_value **argv sqlite3_value **NotUsed2
){ ){
UNUSED_PARAMETER2(NotUsed, NotUsed2);
sqlite3_result_text(context, sqlite3_version, -1, SQLITE_STATIC); sqlite3_result_text(context, sqlite3_version, -1, SQLITE_STATIC);
} }
@ -662,15 +703,8 @@ static void quoteFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
char const *zBlob = sqlite3_value_blob(argv[0]); char const *zBlob = sqlite3_value_blob(argv[0]);
int nBlob = sqlite3_value_bytes(argv[0]); int nBlob = sqlite3_value_bytes(argv[0]);
assert( zBlob==sqlite3_value_blob(argv[0]) ); /* No encoding change */ assert( zBlob==sqlite3_value_blob(argv[0]) ); /* No encoding change */
zText = (char *)contextMalloc(context, (2*(i64)nBlob)+4);
if( 2*nBlob+4>SQLITE_MAX_LENGTH ){ if( zText ){
sqlite3_result_error_toobig(context);
return;
}
zText = (char *)sqliteMalloc((2*nBlob)+4);
if( !zText ){
sqlite3_result_error(context, "out of memory", -1);
}else{
int i; int i;
for(i=0; i<nBlob; i++){ for(i=0; i<nBlob; i++){
zText[(i*2)+2] = hexdigits[(zBlob[i]>>4)&0x0F]; zText[(i*2)+2] = hexdigits[(zBlob[i]>>4)&0x0F];
@ -681,7 +715,7 @@ static void quoteFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
zText[0] = 'X'; zText[0] = 'X';
zText[1] = '\''; zText[1] = '\'';
sqlite3_result_text(context, zText, -1, SQLITE_TRANSIENT); sqlite3_result_text(context, zText, -1, SQLITE_TRANSIENT);
sqliteFree(zText); sqlite3_free(zText);
} }
break; break;
} }
@ -693,23 +727,19 @@ static void quoteFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
if( zArg==0 ) return; if( zArg==0 ) return;
for(i=0, n=0; zArg[i]; i++){ if( zArg[i]=='\'' ) n++; } for(i=0, n=0; zArg[i]; i++){ if( zArg[i]=='\'' ) n++; }
if( i+n+3>SQLITE_MAX_LENGTH ){ z = contextMalloc(context, ((i64)i)+((i64)n)+3);
sqlite3_result_error_toobig(context); if( z ){
return; z[0] = '\'';
} for(i=0, j=1; zArg[i]; i++){
z = sqliteMalloc( i+n+3 ); z[j++] = zArg[i];
if( z==0 ) return; if( zArg[i]=='\'' ){
z[0] = '\''; z[j++] = '\'';
for(i=0, j=1; zArg[i]; i++){ }
z[j++] = zArg[i];
if( zArg[i]=='\'' ){
z[j++] = '\'';
} }
z[j++] = '\'';
z[j] = 0;
sqlite3_result_text(context, z, j, sqlite3_free);
} }
z[j++] = '\'';
z[j] = 0;
sqlite3_result_text(context, z, j, SQLITE_TRANSIENT);
sqliteFree(z);
} }
} }
} }
@ -727,22 +757,20 @@ static void hexFunc(
const unsigned char *pBlob; const unsigned char *pBlob;
char *zHex, *z; char *zHex, *z;
assert( argc==1 ); assert( argc==1 );
UNUSED_PARAMETER(argc);
pBlob = sqlite3_value_blob(argv[0]); pBlob = sqlite3_value_blob(argv[0]);
n = sqlite3_value_bytes(argv[0]); n = sqlite3_value_bytes(argv[0]);
if( n*2+1>SQLITE_MAX_LENGTH ){
sqlite3_result_error_toobig(context);
return;
}
assert( pBlob==sqlite3_value_blob(argv[0]) ); /* No encoding change */ assert( pBlob==sqlite3_value_blob(argv[0]) ); /* No encoding change */
z = zHex = sqlite3_malloc(n*2 + 1); z = zHex = contextMalloc(context, ((i64)n)*2 + 1);
if( zHex==0 ) return; if( zHex ){
for(i=0; i<n; i++, pBlob++){ for(i=0; i<n; i++, pBlob++){
unsigned char c = *pBlob; unsigned char c = *pBlob;
*(z++) = hexdigits[(c>>4)&0xf]; *(z++) = hexdigits[(c>>4)&0xf];
*(z++) = hexdigits[c&0xf]; *(z++) = hexdigits[c&0xf];
}
*z = 0;
sqlite3_result_text(context, zHex, n*2, sqlite3_free);
} }
*z = 0;
sqlite3_result_text(context, zHex, n*2, sqlite3_free);
} }
/* /*
@ -755,11 +783,12 @@ static void zeroblobFunc(
){ ){
i64 n; i64 n;
assert( argc==1 ); assert( argc==1 );
UNUSED_PARAMETER(argc);
n = sqlite3_value_int64(argv[0]); n = sqlite3_value_int64(argv[0]);
if( n>SQLITE_MAX_LENGTH ){ if( n>SQLITE_MAX_LENGTH ){
sqlite3_result_error_toobig(context); sqlite3_result_error_toobig(context);
}else{ }else{
sqlite3_result_zeroblob(context, n); sqlite3_result_zeroblob(context, (int)n);
} }
} }
@ -786,6 +815,7 @@ static void replaceFunc(
int i, j; /* Loop counters */ int i, j; /* Loop counters */
assert( argc==3 ); assert( argc==3 );
UNUSED_PARAMETER(argc);
zStr = sqlite3_value_text(argv[0]); zStr = sqlite3_value_text(argv[0]);
if( zStr==0 ) return; if( zStr==0 ) return;
nStr = sqlite3_value_bytes(argv[0]); nStr = sqlite3_value_bytes(argv[0]);
@ -800,7 +830,7 @@ static void replaceFunc(
assert( zRep==sqlite3_value_text(argv[2]) ); assert( zRep==sqlite3_value_text(argv[2]) );
nOut = nStr + 1; nOut = nStr + 1;
assert( nOut<SQLITE_MAX_LENGTH ); assert( nOut<SQLITE_MAX_LENGTH );
zOut = sqlite3_malloc((int)nOut); zOut = contextMalloc(context, (i64)nOut);
if( zOut==0 ){ if( zOut==0 ){
return; return;
} }
@ -809,14 +839,19 @@ static void replaceFunc(
if( zStr[i]!=zPattern[0] || memcmp(&zStr[i], zPattern, nPattern) ){ if( zStr[i]!=zPattern[0] || memcmp(&zStr[i], zPattern, nPattern) ){
zOut[j++] = zStr[i]; zOut[j++] = zStr[i];
}else{ }else{
u8 *zOld;
sqlite3 *db = sqlite3_context_db_handle(context);
nOut += nRep - nPattern; nOut += nRep - nPattern;
if( nOut>=SQLITE_MAX_LENGTH ){ if( nOut>=db->aLimit[SQLITE_LIMIT_LENGTH] ){
sqlite3_result_error_toobig(context); sqlite3_result_error_toobig(context);
sqlite3_free(zOut); sqlite3DbFree(db, zOut);
return; return;
} }
zOld = zOut;
zOut = sqlite3_realloc(zOut, (int)nOut); zOut = sqlite3_realloc(zOut, (int)nOut);
if( zOut==0 ){ if( zOut==0 ){
sqlite3_result_error_nomem(context);
sqlite3DbFree(db, zOld);
return; return;
} }
memcpy(&zOut[j], zRep, nRep); memcpy(&zOut[j], zRep, nRep);
@ -846,8 +881,8 @@ static void trimFunc(
int nIn; /* Number of bytes in input */ int nIn; /* Number of bytes in input */
int flags; /* 1: trimleft 2: trimright 3: trim */ int flags; /* 1: trimleft 2: trimright 3: trim */
int i; /* Loop counter */ int i; /* Loop counter */
unsigned char *aLen; /* Length of each character in zCharSet */ unsigned char *aLen = 0; /* Length of each character in zCharSet */
const unsigned char **azChar; /* Individual characters in zCharSet */ unsigned char **azChar = 0; /* Individual characters in zCharSet */
int nChar; /* Number of characters in zCharSet */ int nChar; /* Number of characters in zCharSet */
if( sqlite3_value_type(argv[0])==SQLITE_NULL ){ if( sqlite3_value_type(argv[0])==SQLITE_NULL ){
@ -859,10 +894,10 @@ static void trimFunc(
assert( zIn==sqlite3_value_text(argv[0]) ); assert( zIn==sqlite3_value_text(argv[0]) );
if( argc==1 ){ if( argc==1 ){
static const unsigned char lenOne[] = { 1 }; static const unsigned char lenOne[] = { 1 };
static const unsigned char *azOne[] = { (u8*)" " }; static unsigned char * const azOne[] = { (u8*)" " };
nChar = 1; nChar = 1;
aLen = (u8*)lenOne; aLen = (u8*)lenOne;
azChar = azOne; azChar = (unsigned char **)azOne;
zCharSet = 0; zCharSet = 0;
}else if( (zCharSet = sqlite3_value_text(argv[1]))==0 ){ }else if( (zCharSet = sqlite3_value_text(argv[1]))==0 ){
return; return;
@ -872,23 +907,23 @@ static void trimFunc(
SQLITE_SKIP_UTF8(z); SQLITE_SKIP_UTF8(z);
} }
if( nChar>0 ){ if( nChar>0 ){
azChar = sqlite3_malloc( nChar*(sizeof(char*)+1) ); azChar = contextMalloc(context, ((i64)nChar)*(sizeof(char*)+1));
if( azChar==0 ){ if( azChar==0 ){
return; return;
} }
aLen = (unsigned char*)&azChar[nChar]; aLen = (unsigned char*)&azChar[nChar];
for(z=zCharSet, nChar=0; *z; nChar++){ for(z=zCharSet, nChar=0; *z; nChar++){
azChar[nChar] = z; azChar[nChar] = (unsigned char *)z;
SQLITE_SKIP_UTF8(z); SQLITE_SKIP_UTF8(z);
aLen[nChar] = z - azChar[nChar]; aLen[nChar] = (u8)(z - azChar[nChar]);
} }
} }
} }
if( nChar>0 ){ if( nChar>0 ){
flags = (int)sqlite3_user_data(context); flags = SQLITE_PTR_TO_INT(sqlite3_user_data(context));
if( flags & 1 ){ if( flags & 1 ){
while( nIn>0 ){ while( nIn>0 ){
int len; int len = 0;
for(i=0; i<nChar; i++){ for(i=0; i<nChar; i++){
len = aLen[i]; len = aLen[i];
if( memcmp(zIn, azChar[i], len)==0 ) break; if( memcmp(zIn, azChar[i], len)==0 ) break;
@ -900,7 +935,7 @@ static void trimFunc(
} }
if( flags & 2 ){ if( flags & 2 ){
while( nIn>0 ){ while( nIn>0 ){
int len; int len = 0;
for(i=0; i<nChar; i++){ for(i=0; i<nChar; i++){
len = aLen[i]; len = aLen[i];
if( len<=nIn && memcmp(&zIn[nIn-len],azChar[i],len)==0 ) break; if( len<=nIn && memcmp(&zIn[nIn-len],azChar[i],len)==0 ) break;
@ -916,6 +951,7 @@ static void trimFunc(
sqlite3_result_text(context, (char*)zIn, nIn, SQLITE_TRANSIENT); sqlite3_result_text(context, (char*)zIn, nIn, SQLITE_TRANSIENT);
} }
#ifdef SQLITE_SOUNDEX #ifdef SQLITE_SOUNDEX
/* /*
** Compute the soundex encoding of a word. ** Compute the soundex encoding of a word.
@ -974,7 +1010,7 @@ static void soundexFunc(
static void loadExt(sqlite3_context *context, int argc, sqlite3_value **argv){ static void loadExt(sqlite3_context *context, int argc, sqlite3_value **argv){
const char *zFile = (const char *)sqlite3_value_text(argv[0]); const char *zFile = (const char *)sqlite3_value_text(argv[0]);
const char *zProc; const char *zProc;
sqlite3 *db = sqlite3_user_data(context); sqlite3 *db = sqlite3_context_db_handle(context);
char *zErrMsg = 0; char *zErrMsg = 0;
if( argc==2 ){ if( argc==2 ){
@ -989,164 +1025,6 @@ static void loadExt(sqlite3_context *context, int argc, sqlite3_value **argv){
} }
#endif #endif
#ifdef SQLITE_TEST
/*
** This function generates a string of random characters. Used for
** generating test data.
*/
static void randStr(sqlite3_context *context, int argc, sqlite3_value **argv){
static const unsigned char zSrc[] =
"abcdefghijklmnopqrstuvwxyz"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"0123456789"
".-!,:*^+=_|?/<> ";
int iMin, iMax, n, r, i;
unsigned char zBuf[1000];
if( argc>=1 ){
iMin = sqlite3_value_int(argv[0]);
if( iMin<0 ) iMin = 0;
if( iMin>=sizeof(zBuf) ) iMin = sizeof(zBuf)-1;
}else{
iMin = 1;
}
if( argc>=2 ){
iMax = sqlite3_value_int(argv[1]);
if( iMax<iMin ) iMax = iMin;
if( iMax>=sizeof(zBuf) ) iMax = sizeof(zBuf)-1;
}else{
iMax = 50;
}
n = iMin;
if( iMax>iMin ){
sqlite3Randomness(sizeof(r), &r);
r &= 0x7fffffff;
n += r%(iMax + 1 - iMin);
}
assert( n<sizeof(zBuf) );
sqlite3Randomness(n, zBuf);
for(i=0; i<n; i++){
zBuf[i] = zSrc[zBuf[i]%(sizeof(zSrc)-1)];
}
zBuf[n] = 0;
sqlite3_result_text(context, (char*)zBuf, n, SQLITE_TRANSIENT);
}
#endif /* SQLITE_TEST */
#ifdef SQLITE_TEST
/*
** The following two SQL functions are used to test returning a text
** result with a destructor. Function 'test_destructor' takes one argument
** and returns the same argument interpreted as TEXT. A destructor is
** passed with the sqlite3_result_text() call.
**
** SQL function 'test_destructor_count' returns the number of outstanding
** allocations made by 'test_destructor';
**
** WARNING: Not threadsafe.
*/
static int test_destructor_count_var = 0;
static void destructor(void *p){
char *zVal = (char *)p;
assert(zVal);
zVal--;
sqliteFree(zVal);
test_destructor_count_var--;
}
static void test_destructor(
sqlite3_context *pCtx,
int nArg,
sqlite3_value **argv
){
char *zVal;
int len;
sqlite3 *db = sqlite3_user_data(pCtx);
test_destructor_count_var++;
assert( nArg==1 );
if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return;
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], ENC(db)), len);
if( ENC(db)==SQLITE_UTF8 ){
sqlite3_result_text(pCtx, zVal, -1, destructor);
#ifndef SQLITE_OMIT_UTF16
}else if( ENC(db)==SQLITE_UTF16LE ){
sqlite3_result_text16le(pCtx, zVal, -1, destructor);
}else{
sqlite3_result_text16be(pCtx, zVal, -1, destructor);
#endif /* SQLITE_OMIT_UTF16 */
}
}
static void test_destructor_count(
sqlite3_context *pCtx,
int nArg,
sqlite3_value **argv
){
sqlite3_result_int(pCtx, test_destructor_count_var);
}
#endif /* SQLITE_TEST */
#ifdef SQLITE_TEST
/*
** Routines for testing the sqlite3_get_auxdata() and sqlite3_set_auxdata()
** interface.
**
** The test_auxdata() SQL function attempts to register each of its arguments
** as auxiliary data. If there are no prior registrations of aux data for
** that argument (meaning the argument is not a constant or this is its first
** call) then the result for that argument is 0. If there is a prior
** registration, the result for that argument is 1. The overall result
** is the individual argument results separated by spaces.
*/
static void free_test_auxdata(void *p) {sqliteFree(p);}
static void test_auxdata(
sqlite3_context *pCtx,
int nArg,
sqlite3_value **argv
){
int i;
char *zRet = sqliteMalloc(nArg*2);
if( !zRet ) return;
for(i=0; i<nArg; i++){
char const *z = (char*)sqlite3_value_text(argv[i]);
if( z ){
char *zAux = sqlite3_get_auxdata(pCtx, i);
if( zAux ){
zRet[i*2] = '1';
if( strcmp(zAux, z) ){
free_test_auxdata((void *)zRet);
sqlite3_result_error(pCtx, "Auxilary data corruption", -1);
return;
}
}else{
zRet[i*2] = '0';
zAux = sqliteStrDup(z);
sqlite3_set_auxdata(pCtx, i, zAux, free_test_auxdata);
}
zRet[i*2+1] = ' ';
}
}
sqlite3_result_text(pCtx, zRet, 2*nArg-1, free_test_auxdata);
}
#endif /* SQLITE_TEST */
#ifdef SQLITE_TEST
/*
** A function to test error reporting from user functions. This function
** returns a copy of it's first argument as an error.
*/
static void test_error(
sqlite3_context *pCtx,
int nArg,
sqlite3_value **argv
){
sqlite3_result_error(pCtx, (char*)sqlite3_value_text(argv[0]), 0);
}
#endif /* SQLITE_TEST */
/* /*
** An instance of the following structure holds the context of a ** An instance of the following structure holds the context of a
@ -1175,6 +1053,7 @@ static void sumStep(sqlite3_context *context, int argc, sqlite3_value **argv){
SumCtx *p; SumCtx *p;
int type; int type;
assert( argc==1 ); assert( argc==1 );
UNUSED_PARAMETER(argc);
p = sqlite3_aggregate_context(context, sizeof(*p)); p = sqlite3_aggregate_context(context, sizeof(*p));
type = sqlite3_value_numeric_type(argv[0]); type = sqlite3_value_numeric_type(argv[0]);
if( p && type!=SQLITE_NULL ){ if( p && type!=SQLITE_NULL ){
@ -1184,10 +1063,10 @@ static void sumStep(sqlite3_context *context, int argc, sqlite3_value **argv){
p->rSum += v; p->rSum += v;
if( (p->approx|p->overflow)==0 ){ if( (p->approx|p->overflow)==0 ){
i64 iNewSum = p->iSum + v; i64 iNewSum = p->iSum + v;
int s1 = p->iSum >> (sizeof(i64)*8-1); int s1 = (int)(p->iSum >> (sizeof(i64)*8-1));
int s2 = v >> (sizeof(i64)*8-1); int s2 = (int)(v >> (sizeof(i64)*8-1));
int s3 = iNewSum >> (sizeof(i64)*8-1); int s3 = (int)(iNewSum >> (sizeof(i64)*8-1));
p->overflow = (s1&s2&~s3) | (~s1&~s2&s3); p->overflow = ((s1&s2&~s3) | (~s1&~s2&s3))?1:0;
p->iSum = iNewSum; p->iSum = iNewSum;
} }
}else{ }else{
@ -1250,9 +1129,14 @@ static void countFinalize(sqlite3_context *context){
/* /*
** Routines to implement min() and max() aggregate functions. ** Routines to implement min() and max() aggregate functions.
*/ */
static void minmaxStep(sqlite3_context *context, int argc, sqlite3_value **argv){ static void minmaxStep(
sqlite3_context *context,
int NotUsed,
sqlite3_value **argv
){
Mem *pArg = (Mem *)argv[0]; Mem *pArg = (Mem *)argv[0];
Mem *pBest; Mem *pBest;
UNUSED_PARAMETER(NotUsed);
if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return; if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return;
pBest = (Mem *)sqlite3_aggregate_context(context, sizeof(*pBest)); pBest = (Mem *)sqlite3_aggregate_context(context, sizeof(*pBest));
@ -1290,6 +1174,58 @@ static void minMaxFinalize(sqlite3_context *context){
} }
} }
/*
** group_concat(EXPR, ?SEPARATOR?)
*/
static void groupConcatStep(
sqlite3_context *context,
int argc,
sqlite3_value **argv
){
const char *zVal;
StrAccum *pAccum;
const char *zSep;
int nVal, nSep, i;
if( argc==0 || sqlite3_value_type(argv[0])==SQLITE_NULL ) return;
pAccum = (StrAccum*)sqlite3_aggregate_context(context, sizeof(*pAccum));
if( pAccum ){
sqlite3 *db = sqlite3_context_db_handle(context);
pAccum->useMalloc = 1;
pAccum->mxAlloc = db->aLimit[SQLITE_LIMIT_LENGTH];
if( pAccum->nChar ){
if( argc>1 ){
zSep = (char*)sqlite3_value_text(argv[argc-1]);
nSep = sqlite3_value_bytes(argv[argc-1]);
}else{
zSep = ",";
nSep = 1;
}
sqlite3StrAccumAppend(pAccum, zSep, nSep);
}
i = 0;
do{
zVal = (char*)sqlite3_value_text(argv[i]);
nVal = sqlite3_value_bytes(argv[i]);
sqlite3StrAccumAppend(pAccum, zVal, nVal);
i++;
}while( i<argc-1 );
}
}
static void groupConcatFinalize(sqlite3_context *context){
StrAccum *pAccum;
pAccum = sqlite3_aggregate_context(context, 0);
if( pAccum ){
if( pAccum->tooBig ){
sqlite3_result_error_toobig(context);
}else if( pAccum->mallocFailed ){
sqlite3_result_error_nomem(context);
}else{
sqlite3_result_text(context, sqlite3StrAccumFinish(pAccum), -1,
sqlite3_free);
}
}
}
/* /*
** This function registered all of the above C functions as SQL ** This function registered all of the above C functions as SQL
@ -1297,140 +1233,28 @@ static void minMaxFinalize(sqlite3_context *context){
** external linkage. ** external linkage.
*/ */
void sqlite3RegisterBuiltinFunctions(sqlite3 *db){ void sqlite3RegisterBuiltinFunctions(sqlite3 *db){
static const struct {
char *zName;
signed char nArg;
u8 argType; /* ff: db 1: 0, 2: 1, 3: 2,... N: N-1. */
u8 eTextRep; /* 1: UTF-16. 0: UTF-8 */
u8 needCollSeq;
void (*xFunc)(sqlite3_context*,int,sqlite3_value **);
} aFuncs[] = {
{ "min", -1, 0, SQLITE_UTF8, 1, minmaxFunc },
{ "min", 0, 0, SQLITE_UTF8, 1, 0 },
{ "max", -1, 1, SQLITE_UTF8, 1, minmaxFunc },
{ "max", 0, 1, SQLITE_UTF8, 1, 0 },
{ "typeof", 1, 0, SQLITE_UTF8, 0, typeofFunc },
{ "length", 1, 0, SQLITE_UTF8, 0, lengthFunc },
{ "substr", 3, 0, SQLITE_UTF8, 0, substrFunc },
{ "abs", 1, 0, SQLITE_UTF8, 0, absFunc },
{ "round", 1, 0, SQLITE_UTF8, 0, roundFunc },
{ "round", 2, 0, SQLITE_UTF8, 0, roundFunc },
{ "upper", 1, 0, SQLITE_UTF8, 0, upperFunc },
{ "lower", 1, 0, SQLITE_UTF8, 0, lowerFunc },
{ "coalesce", -1, 0, SQLITE_UTF8, 0, ifnullFunc },
{ "coalesce", 0, 0, SQLITE_UTF8, 0, 0 },
{ "coalesce", 1, 0, SQLITE_UTF8, 0, 0 },
{ "hex", 1, 0, SQLITE_UTF8, 0, hexFunc },
{ "ifnull", 2, 0, SQLITE_UTF8, 1, ifnullFunc },
{ "random", -1, 0, SQLITE_UTF8, 0, randomFunc },
{ "randomblob", 1, 0, SQLITE_UTF8, 0, randomBlob },
{ "nullif", 2, 0, SQLITE_UTF8, 1, nullifFunc },
{ "sqlite_version", 0, 0, SQLITE_UTF8, 0, versionFunc},
{ "quote", 1, 0, SQLITE_UTF8, 0, quoteFunc },
{ "last_insert_rowid", 0, 0xff, SQLITE_UTF8, 0, last_insert_rowid },
{ "changes", 0, 0xff, SQLITE_UTF8, 0, changes },
{ "total_changes", 0, 0xff, SQLITE_UTF8, 0, total_changes },
{ "replace", 3, 0, SQLITE_UTF8, 0, replaceFunc },
{ "ltrim", 1, 1, SQLITE_UTF8, 0, trimFunc },
{ "ltrim", 2, 1, SQLITE_UTF8, 0, trimFunc },
{ "rtrim", 1, 2, SQLITE_UTF8, 0, trimFunc },
{ "rtrim", 2, 2, SQLITE_UTF8, 0, trimFunc },
{ "trim", 1, 3, SQLITE_UTF8, 0, trimFunc },
{ "trim", 2, 3, SQLITE_UTF8, 0, trimFunc },
{ "zeroblob", 1, 0, SQLITE_UTF8, 0, zeroblobFunc },
#ifdef SQLITE_SOUNDEX
{ "soundex", 1, 0, SQLITE_UTF8, 0, soundexFunc},
#endif
#ifndef SQLITE_OMIT_LOAD_EXTENSION
{ "load_extension", 1, 0xff, SQLITE_UTF8, 0, loadExt },
{ "load_extension", 2, 0xff, SQLITE_UTF8, 0, loadExt },
#endif
#ifdef SQLITE_TEST
{ "randstr", 2, 0, SQLITE_UTF8, 0, randStr },
{ "test_destructor", 1, 0xff, SQLITE_UTF8, 0, test_destructor},
{ "test_destructor_count", 0, 0, SQLITE_UTF8, 0, test_destructor_count},
{ "test_auxdata", -1, 0, SQLITE_UTF8, 0, test_auxdata},
{ "test_error", 1, 0, SQLITE_UTF8, 0, test_error},
#endif
};
static const struct {
char *zName;
signed char nArg;
u8 argType;
u8 needCollSeq;
void (*xStep)(sqlite3_context*,int,sqlite3_value**);
void (*xFinalize)(sqlite3_context*);
} aAggs[] = {
{ "min", 1, 0, 1, minmaxStep, minMaxFinalize },
{ "max", 1, 1, 1, minmaxStep, minMaxFinalize },
{ "sum", 1, 0, 0, sumStep, sumFinalize },
{ "total", 1, 0, 0, sumStep, totalFinalize },
{ "avg", 1, 0, 0, sumStep, avgFinalize },
{ "count", 0, 0, 0, countStep, countFinalize },
{ "count", 1, 0, 0, countStep, countFinalize },
};
int i;
for(i=0; i<sizeof(aFuncs)/sizeof(aFuncs[0]); i++){
void *pArg;
u8 argType = aFuncs[i].argType;
if( argType==0xff ){
pArg = db;
}else{
pArg = (void*)(int)argType;
}
sqlite3CreateFunc(db, aFuncs[i].zName, aFuncs[i].nArg,
aFuncs[i].eTextRep, pArg, aFuncs[i].xFunc, 0, 0);
if( aFuncs[i].needCollSeq ){
FuncDef *pFunc = sqlite3FindFunction(db, aFuncs[i].zName,
strlen(aFuncs[i].zName), aFuncs[i].nArg, aFuncs[i].eTextRep, 0);
if( pFunc && aFuncs[i].needCollSeq ){
pFunc->needCollSeq = 1;
}
}
}
#ifndef SQLITE_OMIT_ALTERTABLE #ifndef SQLITE_OMIT_ALTERTABLE
sqlite3AlterFunctions(db); sqlite3AlterFunctions(db);
#endif #endif
#ifndef SQLITE_OMIT_PARSER if( !db->mallocFailed ){
sqlite3AttachFunctions(db);
#endif
for(i=0; i<sizeof(aAggs)/sizeof(aAggs[0]); i++){
void *pArg = (void*)(int)aAggs[i].argType;
sqlite3CreateFunc(db, aAggs[i].zName, aAggs[i].nArg, SQLITE_UTF8,
pArg, 0, aAggs[i].xStep, aAggs[i].xFinalize);
if( aAggs[i].needCollSeq ){
FuncDef *pFunc = sqlite3FindFunction( db, aAggs[i].zName,
strlen(aAggs[i].zName), aAggs[i].nArg, SQLITE_UTF8, 0);
if( pFunc && aAggs[i].needCollSeq ){
pFunc->needCollSeq = 1;
}
}
}
sqlite3RegisterDateTimeFunctions(db);
if( !sqlite3MallocFailed() ){
int rc = sqlite3_overload_function(db, "MATCH", 2); int rc = sqlite3_overload_function(db, "MATCH", 2);
assert( rc==SQLITE_NOMEM || rc==SQLITE_OK ); assert( rc==SQLITE_NOMEM || rc==SQLITE_OK );
if( rc==SQLITE_NOMEM ){ if( rc==SQLITE_NOMEM ){
sqlite3FailedMalloc(); db->mallocFailed = 1;
} }
} }
#ifdef SQLITE_SSE #ifdef SQLITE_SSE
(void)sqlite3SseFunctions(db); (void)sqlite3SseFunctions(db);
#endif #endif
#ifdef SQLITE_CASE_SENSITIVE_LIKE
sqlite3RegisterLikeFunctions(db, 1);
#else
sqlite3RegisterLikeFunctions(db, 0);
#endif
} }
/* /*
** Set the LIKEOPT flag on the 2-argument function with the given name. ** Set the LIKEOPT flag on the 2-argument function with the given name.
*/ */
static void setLikeOptFlag(sqlite3 *db, const char *zName, int flagVal){ static void setLikeOptFlag(sqlite3 *db, const char *zName, u8 flagVal){
FuncDef *pDef; FuncDef *pDef;
pDef = sqlite3FindFunction(db, zName, strlen(zName), 2, SQLITE_UTF8, 0); pDef = sqlite3FindFunction(db, zName, sqlite3Strlen30(zName),
2, SQLITE_UTF8, 0);
if( pDef ){ if( pDef ){
pDef->flags = flagVal; pDef->flags = flagVal;
} }
@ -1489,3 +1313,90 @@ int sqlite3IsLikeFunction(sqlite3 *db, Expr *pExpr, int *pIsNocase, char *aWc){
*pIsNocase = (pDef->flags & SQLITE_FUNC_CASE)==0; *pIsNocase = (pDef->flags & SQLITE_FUNC_CASE)==0;
return 1; return 1;
} }
/*
** All all of the FuncDef structures in the aBuiltinFunc[] array above
** to the global function hash table. This occurs at start-time (as
** a consequence of calling sqlite3_initialize()).
**
** After this routine runs
*/
void sqlite3RegisterGlobalFunctions(void){
/*
** The following array holds FuncDef structures for all of the functions
** defined in this file.
**
** The array cannot be constant since changes are made to the
** FuncDef.pHash elements at start-time. The elements of this array
** are read-only after initialization is complete.
*/
static SQLITE_WSD FuncDef aBuiltinFunc[] = {
FUNCTION(ltrim, 1, 1, 0, trimFunc ),
FUNCTION(ltrim, 2, 1, 0, trimFunc ),
FUNCTION(rtrim, 1, 2, 0, trimFunc ),
FUNCTION(rtrim, 2, 2, 0, trimFunc ),
FUNCTION(trim, 1, 3, 0, trimFunc ),
FUNCTION(trim, 2, 3, 0, trimFunc ),
FUNCTION(min, -1, 0, 1, minmaxFunc ),
FUNCTION(min, 0, 0, 1, 0 ),
AGGREGATE(min, 1, 0, 1, minmaxStep, minMaxFinalize ),
FUNCTION(max, -1, 1, 1, minmaxFunc ),
FUNCTION(max, 0, 1, 1, 0 ),
AGGREGATE(max, 1, 1, 1, minmaxStep, minMaxFinalize ),
FUNCTION(typeof, 1, 0, 0, typeofFunc ),
FUNCTION(length, 1, 0, 0, lengthFunc ),
FUNCTION(substr, 2, 0, 0, substrFunc ),
FUNCTION(substr, 3, 0, 0, substrFunc ),
FUNCTION(abs, 1, 0, 0, absFunc ),
FUNCTION(round, 1, 0, 0, roundFunc ),
FUNCTION(round, 2, 0, 0, roundFunc ),
FUNCTION(upper, 1, 0, 0, upperFunc ),
FUNCTION(lower, 1, 0, 0, lowerFunc ),
FUNCTION(coalesce, 1, 0, 0, 0 ),
FUNCTION(coalesce, -1, 0, 0, ifnullFunc ),
FUNCTION(coalesce, 0, 0, 0, 0 ),
FUNCTION(hex, 1, 0, 0, hexFunc ),
FUNCTION(ifnull, 2, 0, 1, ifnullFunc ),
FUNCTION(random, -1, 0, 0, randomFunc ),
FUNCTION(randomblob, 1, 0, 0, randomBlob ),
FUNCTION(nullif, 2, 0, 1, nullifFunc ),
FUNCTION(sqlite_version, 0, 0, 0, versionFunc ),
FUNCTION(quote, 1, 0, 0, quoteFunc ),
FUNCTION(last_insert_rowid, 0, 0, 0, last_insert_rowid),
FUNCTION(changes, 0, 0, 0, changes ),
FUNCTION(total_changes, 0, 0, 0, total_changes ),
FUNCTION(replace, 3, 0, 0, replaceFunc ),
FUNCTION(zeroblob, 1, 0, 0, zeroblobFunc ),
#ifdef SQLITE_SOUNDEX
FUNCTION(soundex, 1, 0, 0, soundexFunc ),
#endif
#ifndef SQLITE_OMIT_LOAD_EXTENSION
FUNCTION(load_extension, 1, 0, 0, loadExt ),
FUNCTION(load_extension, 2, 0, 0, loadExt ),
#endif
AGGREGATE(sum, 1, 0, 0, sumStep, sumFinalize ),
AGGREGATE(total, 1, 0, 0, sumStep, totalFinalize ),
AGGREGATE(avg, 1, 0, 0, sumStep, avgFinalize ),
AGGREGATE(count, 0, 0, 0, countStep, countFinalize ),
AGGREGATE(count, 1, 0, 0, countStep, countFinalize ),
AGGREGATE(group_concat, -1, 0, 0, groupConcatStep, groupConcatFinalize),
LIKEFUNC(glob, 2, &globInfo, SQLITE_FUNC_LIKE|SQLITE_FUNC_CASE),
#ifdef SQLITE_CASE_SENSITIVE_LIKE
LIKEFUNC(like, 2, &likeInfoAlt, SQLITE_FUNC_LIKE|SQLITE_FUNC_CASE),
LIKEFUNC(like, 3, &likeInfoAlt, SQLITE_FUNC_LIKE|SQLITE_FUNC_CASE),
#else
LIKEFUNC(like, 2, &likeInfoNorm, SQLITE_FUNC_LIKE),
LIKEFUNC(like, 3, &likeInfoNorm, SQLITE_FUNC_LIKE),
#endif
};
int i;
FuncDefHash *pHash = &GLOBAL(FuncDefHash, sqlite3GlobalFunctions);
FuncDef *aFunc = (FuncDef*)&GLOBAL(FuncDef, aBuiltinFunc);
for(i=0; i<ArraySize(aBuiltinFunc); i++){
sqlite3FuncDefInsert(pHash, &aFunc[i]);
}
sqlite3RegisterDateTimeFunctions();
}

104
global.c Normal file
View file

@ -0,0 +1,104 @@
/*
** 2008 June 13
**
** 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 definitions of global variables and contants.
**
** $Id: global.c,v 1.9 2008/12/08 18:19:18 drh Exp $
*/
#include "sqliteInt.h"
/* An array to map all upper-case characters into their corresponding
** lower-case character.
**
** SQLite only considers US-ASCII (or EBCDIC) characters. We do not
** handle case conversions for the UTF character set since the tables
** involved are nearly as big or bigger than SQLite itself.
*/
const unsigned char sqlite3UpperToLower[] = {
#ifdef SQLITE_ASCII
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53,
54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 97, 98, 99,100,101,102,103,
104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,
122, 91, 92, 93, 94, 95, 96, 97, 98, 99,100,101,102,103,104,105,106,107,
108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,
126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,
144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,
162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,
180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,
198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,
216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,
234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,
252,253,254,255
#endif
#ifdef SQLITE_EBCDIC
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, /* 0x */
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, /* 1x */
32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, /* 2x */
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, /* 3x */
64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, /* 4x */
80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, /* 5x */
96, 97, 66, 67, 68, 69, 70, 71, 72, 73,106,107,108,109,110,111, /* 6x */
112, 81, 82, 83, 84, 85, 86, 87, 88, 89,122,123,124,125,126,127, /* 7x */
128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143, /* 8x */
144,145,146,147,148,149,150,151,152,153,154,155,156,157,156,159, /* 9x */
160,161,162,163,164,165,166,167,168,169,170,171,140,141,142,175, /* Ax */
176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191, /* Bx */
192,129,130,131,132,133,134,135,136,137,202,203,204,205,206,207, /* Cx */
208,145,146,147,148,149,150,151,152,153,218,219,220,221,222,223, /* Dx */
224,225,162,163,164,165,166,167,168,169,232,203,204,205,206,207, /* Ex */
239,240,241,242,243,244,245,246,247,248,249,219,220,221,222,255, /* Fx */
#endif
};
/*
** The following singleton contains the global configuration for
** the SQLite library.
*/
SQLITE_WSD struct Sqlite3Config sqlite3Config = {
SQLITE_DEFAULT_MEMSTATUS, /* bMemstat */
1, /* bCoreMutex */
SQLITE_THREADSAFE==1, /* bFullMutex */
0x7ffffffe, /* mxStrlen */
100, /* szLookaside */
500, /* nLookaside */
{0,0,0,0,0,0,0,0}, /* m */
{0,0,0,0,0,0,0,0,0}, /* mutex */
{0,0,0,0,0,0,0,0,0,0,0}, /* pcache */
(void*)0, /* pHeap */
0, /* nHeap */
0, 0, /* mnHeap, mxHeap */
(void*)0, /* pScratch */
0, /* szScratch */
0, /* nScratch */
(void*)0, /* pPage */
0, /* szPage */
0, /* nPage */
0, /* mxParserStack */
0, /* sharedCacheEnabled */
/* All the rest need to always be zero */
0, /* isInit */
0, /* inProgress */
0, /* isMallocInit */
0, /* pInitMutex */
0, /* nRefInitMutex */
};
/*
** Hash table for global functions - functions common to all
** database connections. After initialization, this table is
** read-only.
*/
SQLITE_WSD FuncDefHash sqlite3GlobalFunctions;

236
hash.c
View file

@ -12,7 +12,7 @@
** This is the implementation of generic hash-tables ** This is the implementation of generic hash-tables
** used in SQLite. ** used in SQLite.
** **
** $Id: hash.c,v 1.19 2007/03/31 03:59:24 drh Exp $ ** $Id: hash.c,v 1.33 2009/01/09 01:12:28 drh Exp $
*/ */
#include "sqliteInt.h" #include "sqliteInt.h"
#include <assert.h> #include <assert.h>
@ -21,28 +21,16 @@
** fields of the Hash structure. ** fields of the Hash structure.
** **
** "pNew" is a pointer to the hash table that is to be initialized. ** "pNew" is a pointer to the hash table that is to be initialized.
** keyClass is one of the constants SQLITE_HASH_INT, SQLITE_HASH_POINTER, ** "copyKey" is true if the hash table should make its own private
** SQLITE_HASH_BINARY, or SQLITE_HASH_STRING. The value of keyClass ** copy of keys and false if it should just use the supplied pointer.
** determines what kind of key the hash table will use. "copyKey" is
** true if the hash table should make its own private copy of keys and
** false if it should just use the supplied pointer. CopyKey only makes
** sense for SQLITE_HASH_STRING and SQLITE_HASH_BINARY and is ignored
** for other key classes.
*/ */
void sqlite3HashInit(Hash *pNew, int keyClass, int copyKey){ void sqlite3HashInit(Hash *pNew, int copyKey){
assert( pNew!=0 ); assert( pNew!=0 );
assert( keyClass>=SQLITE_HASH_STRING && keyClass<=SQLITE_HASH_BINARY ); pNew->copyKey = copyKey!=0;
pNew->keyClass = keyClass;
#if 0
if( keyClass==SQLITE_HASH_POINTER || keyClass==SQLITE_HASH_INT ) copyKey = 0;
#endif
pNew->copyKey = copyKey;
pNew->first = 0; pNew->first = 0;
pNew->count = 0; pNew->count = 0;
pNew->htsize = 0; pNew->htsize = 0;
pNew->ht = 0; pNew->ht = 0;
pNew->xMalloc = sqlite3MallocX;
pNew->xFree = sqlite3FreeX;
} }
/* Remove all entries from a hash table. Reclaim all memory. /* Remove all entries from a hash table. Reclaim all memory.
@ -55,54 +43,27 @@ void sqlite3HashClear(Hash *pH){
assert( pH!=0 ); assert( pH!=0 );
elem = pH->first; elem = pH->first;
pH->first = 0; pH->first = 0;
if( pH->ht ) pH->xFree(pH->ht); sqlite3_free(pH->ht);
pH->ht = 0; pH->ht = 0;
pH->htsize = 0; pH->htsize = 0;
while( elem ){ while( elem ){
HashElem *next_elem = elem->next; HashElem *next_elem = elem->next;
if( pH->copyKey && elem->pKey ){ if( pH->copyKey ){
pH->xFree(elem->pKey); sqlite3_free(elem->pKey);
} }
pH->xFree(elem); sqlite3_free(elem);
elem = next_elem; elem = next_elem;
} }
pH->count = 0; pH->count = 0;
} }
#if 0 /* NOT USED */
/*
** Hash and comparison functions when the mode is SQLITE_HASH_INT
*/
static int intHash(const void *pKey, int nKey){
return nKey ^ (nKey<<8) ^ (nKey>>8);
}
static int intCompare(const void *pKey1, int n1, const void *pKey2, int n2){
return n2 - n1;
}
#endif
#if 0 /* NOT USED */
/*
** Hash and comparison functions when the mode is SQLITE_HASH_POINTER
*/
static int ptrHash(const void *pKey, int nKey){
uptr x = Addr(pKey);
return x ^ (x<<8) ^ (x>>8);
}
static int ptrCompare(const void *pKey1, int n1, const void *pKey2, int n2){
if( pKey1==pKey2 ) return 0;
if( pKey1<pKey2 ) return -1;
return 1;
}
#endif
/* /*
** Hash and comparison functions when the mode is SQLITE_HASH_STRING ** Hash and comparison functions when the mode is SQLITE_HASH_STRING
*/ */
static int strHash(const void *pKey, int nKey){ static int strHash(const void *pKey, int nKey){
const char *z = (const char *)pKey; const char *z = (const char *)pKey;
int h = 0; int h = 0;
if( nKey<=0 ) nKey = strlen(z); if( nKey<=0 ) nKey = sqlite3Strlen30(z);
while( nKey > 0 ){ while( nKey > 0 ){
h = (h<<3) ^ h ^ sqlite3UpperToLower[(unsigned char)*z++]; h = (h<<3) ^ h ^ sqlite3UpperToLower[(unsigned char)*z++];
nKey--; nKey--;
@ -114,79 +75,6 @@ static int strCompare(const void *pKey1, int n1, const void *pKey2, int n2){
return sqlite3StrNICmp((const char*)pKey1,(const char*)pKey2,n1); return sqlite3StrNICmp((const char*)pKey1,(const char*)pKey2,n1);
} }
/*
** Hash and comparison functions when the mode is SQLITE_HASH_BINARY
*/
static int binHash(const void *pKey, int nKey){
int h = 0;
const char *z = (const char *)pKey;
while( nKey-- > 0 ){
h = (h<<3) ^ h ^ *(z++);
}
return h & 0x7fffffff;
}
static int binCompare(const void *pKey1, int n1, const void *pKey2, int n2){
if( n1!=n2 ) return 1;
return memcmp(pKey1,pKey2,n1);
}
/*
** Return a pointer to the appropriate hash function given the key class.
**
** The C syntax in this function definition may be unfamilar to some
** programmers, so we provide the following additional explanation:
**
** The name of the function is "hashFunction". The function takes a
** single parameter "keyClass". The return value of hashFunction()
** is a pointer to another function. Specifically, the return value
** of hashFunction() is a pointer to a function that takes two parameters
** with types "const void*" and "int" and returns an "int".
*/
static int (*hashFunction(int keyClass))(const void*,int){
#if 0 /* HASH_INT and HASH_POINTER are never used */
switch( keyClass ){
case SQLITE_HASH_INT: return &intHash;
case SQLITE_HASH_POINTER: return &ptrHash;
case SQLITE_HASH_STRING: return &strHash;
case SQLITE_HASH_BINARY: return &binHash;;
default: break;
}
return 0;
#else
if( keyClass==SQLITE_HASH_STRING ){
return &strHash;
}else{
assert( keyClass==SQLITE_HASH_BINARY );
return &binHash;
}
#endif
}
/*
** Return a pointer to the appropriate hash function given the key class.
**
** For help in interpreted the obscure C code in the function definition,
** see the header comment on the previous function.
*/
static int (*compareFunction(int keyClass))(const void*,int,const void*,int){
#if 0 /* HASH_INT and HASH_POINTER are never used */
switch( keyClass ){
case SQLITE_HASH_INT: return &intCompare;
case SQLITE_HASH_POINTER: return &ptrCompare;
case SQLITE_HASH_STRING: return &strCompare;
case SQLITE_HASH_BINARY: return &binCompare;
default: break;
}
return 0;
#else
if( keyClass==SQLITE_HASH_STRING ){
return &strCompare;
}else{
assert( keyClass==SQLITE_HASH_BINARY );
return &binCompare;
}
#endif
}
/* Link an element into the hash table /* Link an element into the hash table
*/ */
@ -216,22 +104,34 @@ static void insertElement(
/* Resize the hash table so that it cantains "new_size" buckets. /* Resize the hash table so that it cantains "new_size" buckets.
** "new_size" must be a power of 2. The hash table might fail ** "new_size" must be a power of 2. The hash table might fail
** to resize if sqliteMalloc() fails. ** to resize if sqlite3_malloc() fails.
*/ */
static void rehash(Hash *pH, int new_size){ static void rehash(Hash *pH, int new_size){
struct _ht *new_ht; /* The new hash table */ struct _ht *new_ht; /* The new hash table */
HashElem *elem, *next_elem; /* For looping over existing elements */ HashElem *elem, *next_elem; /* For looping over existing elements */
int (*xHash)(const void*,int); /* The hash function */
assert( (new_size & (new_size-1))==0 ); #ifdef SQLITE_MALLOC_SOFT_LIMIT
new_ht = (struct _ht *)pH->xMalloc( new_size*sizeof(struct _ht) ); if( new_size*sizeof(struct _ht)>SQLITE_MALLOC_SOFT_LIMIT ){
new_size = SQLITE_MALLOC_SOFT_LIMIT/sizeof(struct _ht);
}
if( new_size==pH->htsize ) return;
#endif
/* There is a call to sqlite3_malloc() inside rehash(). If there is
** already an allocation at pH->ht, then if this malloc() fails it
** is benign (since failing to resize a hash table is a performance
** hit only, not a fatal error).
*/
if( pH->htsize>0 ) sqlite3BeginBenignMalloc();
new_ht = (struct _ht *)sqlite3MallocZero( new_size*sizeof(struct _ht) );
if( pH->htsize>0 ) sqlite3EndBenignMalloc();
if( new_ht==0 ) return; if( new_ht==0 ) return;
if( pH->ht ) pH->xFree(pH->ht); sqlite3_free(pH->ht);
pH->ht = new_ht; pH->ht = new_ht;
pH->htsize = new_size; pH->htsize = new_size;
xHash = hashFunction(pH->keyClass);
for(elem=pH->first, pH->first=0; elem; elem = next_elem){ for(elem=pH->first, pH->first=0; elem; elem = next_elem){
int h = (*xHash)(elem->pKey, elem->nKey) & (new_size-1); int h = strHash(elem->pKey, elem->nKey) & (new_size-1);
next_elem = elem->next; next_elem = elem->next;
insertElement(pH, &new_ht[h], elem); insertElement(pH, &new_ht[h], elem);
} }
@ -249,15 +149,13 @@ static HashElem *findElementGivenHash(
){ ){
HashElem *elem; /* Used to loop thru the element list */ HashElem *elem; /* Used to loop thru the element list */
int count; /* Number of elements left to test */ int count; /* Number of elements left to test */
int (*xCompare)(const void*,int,const void*,int); /* comparison function */
if( pH->ht ){ if( pH->ht ){
struct _ht *pEntry = &pH->ht[h]; struct _ht *pEntry = &pH->ht[h];
elem = pEntry->chain; elem = pEntry->chain;
count = pEntry->count; count = pEntry->count;
xCompare = compareFunction(pH->keyClass);
while( count-- && elem ){ while( count-- && elem ){
if( (*xCompare)(elem->pKey,elem->nKey,pKey,nKey)==0 ){ if( strCompare(elem->pKey,elem->nKey,pKey,nKey)==0 ){
return elem; return elem;
} }
elem = elem->next; elem = elem->next;
@ -292,9 +190,9 @@ static void removeElementGivenHash(
pEntry->chain = 0; pEntry->chain = 0;
} }
if( pH->copyKey ){ if( pH->copyKey ){
pH->xFree(elem->pKey); sqlite3_free(elem->pKey);
} }
pH->xFree( elem ); sqlite3_free( elem );
pH->count--; pH->count--;
if( pH->count<=0 ){ if( pH->count<=0 ){
assert( pH->first==0 ); assert( pH->first==0 );
@ -303,21 +201,28 @@ static void removeElementGivenHash(
} }
} }
/* Attempt to locate an element of the hash table pH with a key
** that matches pKey,nKey. Return a pointer to the corresponding
** HashElem structure for this element if it is found, or NULL
** otherwise.
*/
HashElem *sqlite3HashFindElem(const Hash *pH, const void *pKey, int nKey){
int h; /* A hash on key */
HashElem *elem; /* The element that matches key */
if( pH==0 || pH->ht==0 ) return 0;
h = strHash(pKey,nKey);
elem = findElementGivenHash(pH,pKey,nKey, h % pH->htsize);
return elem;
}
/* Attempt to locate an element of the hash table pH with a key /* Attempt to locate an element of the hash table pH with a key
** that matches pKey,nKey. Return the data for this element if it is ** that matches pKey,nKey. Return the data for this element if it is
** found, or NULL if there is no match. ** found, or NULL if there is no match.
*/ */
void *sqlite3HashFind(const Hash *pH, const void *pKey, int nKey){ void *sqlite3HashFind(const Hash *pH, const void *pKey, int nKey){
int h; /* A hash on key */
HashElem *elem; /* The element that matches key */ HashElem *elem; /* The element that matches key */
int (*xHash)(const void*,int); /* The hash function */ elem = sqlite3HashFindElem(pH, pKey, nKey);
if( pH==0 || pH->ht==0 ) return 0;
xHash = hashFunction(pH->keyClass);
assert( xHash!=0 );
h = (*xHash)(pKey,nKey);
assert( (pH->htsize & (pH->htsize-1))==0 );
elem = findElementGivenHash(pH,pKey,nKey, h & (pH->htsize-1));
return elem ? elem->data : 0; return elem ? elem->data : 0;
} }
@ -341,31 +246,33 @@ void *sqlite3HashInsert(Hash *pH, const void *pKey, int nKey, void *data){
int h; /* the hash of the key modulo hash table size */ int h; /* the hash of the key modulo hash table size */
HashElem *elem; /* Used to loop thru the element list */ HashElem *elem; /* Used to loop thru the element list */
HashElem *new_elem; /* New element added to the pH */ HashElem *new_elem; /* New element added to the pH */
int (*xHash)(const void*,int); /* The hash function */
assert( pH!=0 ); assert( pH!=0 );
xHash = hashFunction(pH->keyClass); hraw = strHash(pKey, nKey);
assert( xHash!=0 ); if( pH->htsize ){
hraw = (*xHash)(pKey, nKey); h = hraw % pH->htsize;
assert( (pH->htsize & (pH->htsize-1))==0 ); elem = findElementGivenHash(pH,pKey,nKey,h);
h = hraw & (pH->htsize-1); if( elem ){
elem = findElementGivenHash(pH,pKey,nKey,h); void *old_data = elem->data;
if( elem ){ if( data==0 ){
void *old_data = elem->data; removeElementGivenHash(pH,elem,h);
if( data==0 ){ }else{
removeElementGivenHash(pH,elem,h); elem->data = data;
}else{ if( !pH->copyKey ){
elem->data = data; elem->pKey = (void *)pKey;
}
assert(nKey==elem->nKey);
}
return old_data;
} }
return old_data;
} }
if( data==0 ) return 0; if( data==0 ) return 0;
new_elem = (HashElem*)pH->xMalloc( sizeof(HashElem) ); new_elem = (HashElem*)sqlite3Malloc( sizeof(HashElem) );
if( new_elem==0 ) return data; if( new_elem==0 ) return data;
if( pH->copyKey && pKey!=0 ){ if( pH->copyKey && pKey!=0 ){
new_elem->pKey = pH->xMalloc( nKey ); new_elem->pKey = sqlite3Malloc( nKey );
if( new_elem->pKey==0 ){ if( new_elem->pKey==0 ){
pH->xFree(new_elem); sqlite3_free(new_elem);
return data; return data;
} }
memcpy((void*)new_elem->pKey, pKey, nKey); memcpy((void*)new_elem->pKey, pKey, nKey);
@ -375,13 +282,13 @@ void *sqlite3HashInsert(Hash *pH, const void *pKey, int nKey, void *data){
new_elem->nKey = nKey; new_elem->nKey = nKey;
pH->count++; pH->count++;
if( pH->htsize==0 ){ if( pH->htsize==0 ){
rehash(pH,8); rehash(pH, 128/sizeof(pH->ht[0]));
if( pH->htsize==0 ){ if( pH->htsize==0 ){
pH->count = 0; pH->count = 0;
if( pH->copyKey ){ if( pH->copyKey ){
pH->xFree(new_elem->pKey); sqlite3_free(new_elem->pKey);
} }
pH->xFree(new_elem); sqlite3_free(new_elem);
return data; return data;
} }
} }
@ -389,8 +296,7 @@ void *sqlite3HashInsert(Hash *pH, const void *pKey, int nKey, void *data){
rehash(pH,pH->htsize*2); rehash(pH,pH->htsize*2);
} }
assert( pH->htsize>0 ); assert( pH->htsize>0 );
assert( (pH->htsize & (pH->htsize-1))==0 ); h = hraw % pH->htsize;
h = hraw & (pH->htsize-1);
insertElement(pH, &pH->ht[h], new_elem); insertElement(pH, &pH->ht[h], new_elem);
new_elem->data = data; new_elem->data = data;
return 0; return 0;

44
hash.h
View file

@ -12,7 +12,7 @@
** This is the header file for the generic hash-table implemenation ** This is the header file for the generic hash-table implemenation
** used in SQLite. ** used in SQLite.
** **
** $Id: hash.h,v 1.9 2006/02/14 10:48:39 danielk1977 Exp $ ** $Id: hash.h,v 1.12 2008/10/10 17:41:29 drh Exp $
*/ */
#ifndef _SQLITE_HASH_H_ #ifndef _SQLITE_HASH_H_
#define _SQLITE_HASH_H_ #define _SQLITE_HASH_H_
@ -30,16 +30,13 @@ typedef struct HashElem HashElem;
** this structure opaque. ** this structure opaque.
*/ */
struct Hash { struct Hash {
char keyClass; /* SQLITE_HASH_INT, _POINTER, _STRING, _BINARY */ unsigned int copyKey: 1; /* True if copy of key made on insert */
char copyKey; /* True if copy of key made on insert */ unsigned int htsize : 31; /* Number of buckets in the hash table */
int count; /* Number of entries in this table */ unsigned int count; /* Number of entries in this table */
HashElem *first; /* The first element of the array */ HashElem *first; /* The first element of the array */
void *(*xMalloc)(int); /* malloc() function to use */ struct _ht { /* the hash table */
void (*xFree)(void *); /* free() function to use */ int count; /* Number of entries with this hash */
int htsize; /* Number of buckets in the hash table */ HashElem *chain; /* Pointer to first entry with this hash */
struct _ht { /* the hash table */
int count; /* Number of entries with this hash */
HashElem *chain; /* Pointer to first entry with this hash */
} *ht; } *ht;
}; };
@ -55,34 +52,13 @@ struct HashElem {
void *pKey; int nKey; /* Key associated with this element */ void *pKey; int nKey; /* Key associated with this element */
}; };
/*
** There are 4 different modes of operation for a hash table:
**
** SQLITE_HASH_INT nKey is used as the key and pKey is ignored.
**
** SQLITE_HASH_POINTER pKey is used as the key and nKey is ignored.
**
** SQLITE_HASH_STRING pKey points to a string that is nKey bytes long
** (including the null-terminator, if any). Case
** is ignored in comparisons.
**
** SQLITE_HASH_BINARY pKey points to binary data nKey bytes long.
** memcmp() is used to compare keys.
**
** A copy of the key is made for SQLITE_HASH_STRING and SQLITE_HASH_BINARY
** if the copyKey parameter to HashInit is 1.
*/
/* #define SQLITE_HASH_INT 1 // NOT USED */
/* #define SQLITE_HASH_POINTER 2 // NOT USED */
#define SQLITE_HASH_STRING 3
#define SQLITE_HASH_BINARY 4
/* /*
** Access routines. To delete, insert a NULL pointer. ** Access routines. To delete, insert a NULL pointer.
*/ */
void sqlite3HashInit(Hash*, int keytype, int copyKey); void sqlite3HashInit(Hash*, int copyKey);
void *sqlite3HashInsert(Hash*, const void *pKey, int nKey, void *pData); void *sqlite3HashInsert(Hash*, const void *pKey, int nKey, void *pData);
void *sqlite3HashFind(const Hash*, const void *pKey, int nKey); void *sqlite3HashFind(const Hash*, const void *pKey, int nKey);
HashElem *sqlite3HashFindElem(const Hash*, const void *pKey, int nKey);
void sqlite3HashClear(Hash*); void sqlite3HashClear(Hash*);
/* /*

87
hwtime.h Normal file
View file

@ -0,0 +1,87 @@
/*
** 2008 May 27
**
** 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 inline asm code for retrieving "high-performance"
** counters for x86 class CPUs.
**
** $Id: hwtime.h,v 1.3 2008/08/01 14:33:15 shane Exp $
*/
#ifndef _HWTIME_H_
#define _HWTIME_H_
/*
** The following routine only works on pentium-class (or newer) processors.
** It uses the RDTSC opcode to read the cycle count value out of the
** processor and returns that value. This can be used for high-res
** profiling.
*/
#if (defined(__GNUC__) || defined(_MSC_VER)) && \
(defined(i386) || defined(__i386__) || defined(_M_IX86))
#if defined(__GNUC__)
__inline__ sqlite_uint64 sqlite3Hwtime(void){
unsigned int lo, hi;
__asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi));
return (sqlite_uint64)hi << 32 | lo;
}
#elif defined(_MSC_VER)
__declspec(naked) __inline sqlite_uint64 __cdecl sqlite3Hwtime(void){
__asm {
rdtsc
ret ; return value at EDX:EAX
}
}
#endif
#elif (defined(__GNUC__) && defined(__x86_64__))
__inline__ sqlite_uint64 sqlite3Hwtime(void){
unsigned long val;
__asm__ __volatile__ ("rdtsc" : "=A" (val));
return val;
}
#elif (defined(__GNUC__) && defined(__ppc__))
__inline__ sqlite_uint64 sqlite3Hwtime(void){
unsigned long long retval;
unsigned long junk;
__asm__ __volatile__ ("\n\
1: mftbu %1\n\
mftb %L0\n\
mftbu %0\n\
cmpw %0,%1\n\
bne 1b"
: "=r" (retval), "=r" (junk));
return retval;
}
#else
#error Need implementation of sqlite3Hwtime() for your platform.
/*
** To compile without implementing sqlite3Hwtime() for your platform,
** you can remove the above #error and use the following
** stub function. You will lose timing support for many
** of the debugging and testing utilities, but it should at
** least compile and run.
*/
sqlite_uint64 sqlite3Hwtime(void){ return ((sqlite_uint64)0); }
#endif
#endif /* !defined(_HWTIME_H_) */

971
insert.c

File diff suppressed because it is too large Load diff

239
journal.c Normal file
View file

@ -0,0 +1,239 @@
/*
** 2007 August 22
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
**
** May you do good and not evil.
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
*************************************************************************
**
** @(#) $Id: journal.c,v 1.8 2008/05/01 18:01:47 drh Exp $
*/
#ifdef SQLITE_ENABLE_ATOMIC_WRITE
/*
** This file implements a special kind of sqlite3_file object used
** by SQLite to create journal files if the atomic-write optimization
** is enabled.
**
** The distinctive characteristic of this sqlite3_file is that the
** actual on disk file is created lazily. When the file is created,
** the caller specifies a buffer size for an in-memory buffer to
** be used to service read() and write() requests. The actual file
** on disk is not created or populated until either:
**
** 1) The in-memory representation grows too large for the allocated
** buffer, or
** 2) The xSync() method is called.
*/
#include "sqliteInt.h"
/*
** A JournalFile object is a subclass of sqlite3_file used by
** as an open file handle for journal files.
*/
struct JournalFile {
sqlite3_io_methods *pMethod; /* I/O methods on journal files */
int nBuf; /* Size of zBuf[] in bytes */
char *zBuf; /* Space to buffer journal writes */
int iSize; /* Amount of zBuf[] currently used */
int flags; /* xOpen flags */
sqlite3_vfs *pVfs; /* The "real" underlying VFS */
sqlite3_file *pReal; /* The "real" underlying file descriptor */
const char *zJournal; /* Name of the journal file */
};
typedef struct JournalFile JournalFile;
/*
** If it does not already exists, create and populate the on-disk file
** for JournalFile p.
*/
static int createFile(JournalFile *p){
int rc = SQLITE_OK;
if( !p->pReal ){
sqlite3_file *pReal = (sqlite3_file *)&p[1];
rc = sqlite3OsOpen(p->pVfs, p->zJournal, pReal, p->flags, 0);
if( rc==SQLITE_OK ){
p->pReal = pReal;
if( p->iSize>0 ){
assert(p->iSize<=p->nBuf);
rc = sqlite3OsWrite(p->pReal, p->zBuf, p->iSize, 0);
}
}
}
return rc;
}
/*
** Close the file.
*/
static int jrnlClose(sqlite3_file *pJfd){
JournalFile *p = (JournalFile *)pJfd;
if( p->pReal ){
sqlite3OsClose(p->pReal);
}
sqlite3_free(p->zBuf);
return SQLITE_OK;
}
/*
** Read data from the file.
*/
static int jrnlRead(
sqlite3_file *pJfd, /* The journal file from which to read */
void *zBuf, /* Put the results here */
int iAmt, /* Number of bytes to read */
sqlite_int64 iOfst /* Begin reading at this offset */
){
int rc = SQLITE_OK;
JournalFile *p = (JournalFile *)pJfd;
if( p->pReal ){
rc = sqlite3OsRead(p->pReal, zBuf, iAmt, iOfst);
}else{
assert( iAmt+iOfst<=p->iSize );
memcpy(zBuf, &p->zBuf[iOfst], iAmt);
}
return rc;
}
/*
** Write data to the file.
*/
static int jrnlWrite(
sqlite3_file *pJfd, /* The journal file into which to write */
const void *zBuf, /* Take data to be written from here */
int iAmt, /* Number of bytes to write */
sqlite_int64 iOfst /* Begin writing at this offset into the file */
){
int rc = SQLITE_OK;
JournalFile *p = (JournalFile *)pJfd;
if( !p->pReal && (iOfst+iAmt)>p->nBuf ){
rc = createFile(p);
}
if( rc==SQLITE_OK ){
if( p->pReal ){
rc = sqlite3OsWrite(p->pReal, zBuf, iAmt, iOfst);
}else{
memcpy(&p->zBuf[iOfst], zBuf, iAmt);
if( p->iSize<(iOfst+iAmt) ){
p->iSize = (iOfst+iAmt);
}
}
}
return rc;
}
/*
** Truncate the file.
*/
static int jrnlTruncate(sqlite3_file *pJfd, sqlite_int64 size){
int rc = SQLITE_OK;
JournalFile *p = (JournalFile *)pJfd;
if( p->pReal ){
rc = sqlite3OsTruncate(p->pReal, size);
}else if( size<p->iSize ){
p->iSize = size;
}
return rc;
}
/*
** Sync the file.
*/
static int jrnlSync(sqlite3_file *pJfd, int flags){
int rc;
JournalFile *p = (JournalFile *)pJfd;
if( p->pReal ){
rc = sqlite3OsSync(p->pReal, flags);
}else{
rc = SQLITE_OK;
}
return rc;
}
/*
** Query the size of the file in bytes.
*/
static int jrnlFileSize(sqlite3_file *pJfd, sqlite_int64 *pSize){
int rc = SQLITE_OK;
JournalFile *p = (JournalFile *)pJfd;
if( p->pReal ){
rc = sqlite3OsFileSize(p->pReal, pSize);
}else{
*pSize = (sqlite_int64) p->iSize;
}
return rc;
}
/*
** Table of methods for JournalFile sqlite3_file object.
*/
static struct sqlite3_io_methods JournalFileMethods = {
1, /* iVersion */
jrnlClose, /* xClose */
jrnlRead, /* xRead */
jrnlWrite, /* xWrite */
jrnlTruncate, /* xTruncate */
jrnlSync, /* xSync */
jrnlFileSize, /* xFileSize */
0, /* xLock */
0, /* xUnlock */
0, /* xCheckReservedLock */
0, /* xFileControl */
0, /* xSectorSize */
0 /* xDeviceCharacteristics */
};
/*
** Open a journal file.
*/
int sqlite3JournalOpen(
sqlite3_vfs *pVfs, /* The VFS to use for actual file I/O */
const char *zName, /* Name of the journal file */
sqlite3_file *pJfd, /* Preallocated, blank file handle */
int flags, /* Opening flags */
int nBuf /* Bytes buffered before opening the file */
){
JournalFile *p = (JournalFile *)pJfd;
memset(p, 0, sqlite3JournalSize(pVfs));
if( nBuf>0 ){
p->zBuf = sqlite3MallocZero(nBuf);
if( !p->zBuf ){
return SQLITE_NOMEM;
}
}else{
return sqlite3OsOpen(pVfs, zName, pJfd, flags, 0);
}
p->pMethod = &JournalFileMethods;
p->nBuf = nBuf;
p->flags = flags;
p->zJournal = zName;
p->pVfs = pVfs;
return SQLITE_OK;
}
/*
** If the argument p points to a JournalFile structure, and the underlying
** file has not yet been created, create it now.
*/
int sqlite3JournalCreate(sqlite3_file *p){
if( p->pMethods!=&JournalFileMethods ){
return SQLITE_OK;
}
return createFile((JournalFile *)p);
}
/*
** Return the number of bytes required to store a JournalFile that uses vfs
** pVfs to create the underlying on-disk files.
*/
int sqlite3JournalSize(sqlite3_vfs *pVfs){
return (pVfs->szOsFile+sizeof(JournalFile));
}
#endif

View file

@ -2,7 +2,7 @@
** **
** The code in this file has been automatically generated by ** The code in this file has been automatically generated by
** **
** $Header: /sqlite/sqlite/tool/mkkeywordhash.c,v 1.31 2007/07/30 18:26:20 rse Exp $ ** $Header: /sqlite/sqlite/tool/mkkeywordhash.c,v 1.36 2008/12/31 21:52:41 drh Exp $
** **
** The code in this file implements a function that determines whether ** The code in this file implements a function that determines whether
** or not a given identifier is really an SQL keyword. The same thing ** or not a given identifier is really an SQL keyword. The same thing
@ -11,89 +11,124 @@
** is substantially reduced. This is important for embedded applications ** is substantially reduced. This is important for embedded applications
** on platforms with limited memory. ** on platforms with limited memory.
*/ */
/* Hash score: 165 */ /* Hash score: 171 */
static int keywordCode(const char *z, int n){ static int keywordCode(const char *z, int n){
/* zText[] encodes 775 bytes of keywords in 526 bytes */ /* zText[] encodes 801 bytes of keywords in 541 bytes */
static const char zText[526] = /* REINDEXEDESCAPEACHECKEYBEFOREIGNOREGEXPLAINSTEADDATABASELECT */
"BEFOREIGNOREGEXPLAINSTEADDESCAPEACHECKEYCONSTRAINTERSECTABLEFT" /* ABLEFTHENDEFERRABLELSEXCEPTRANSACTIONATURALTERAISEXCLUSIVE */
"HENDATABASELECTRANSACTIONATURALTERAISELSEXCEPTRIGGEREFERENCES" /* XISTSAVEPOINTERSECTRIGGEREFERENCESCONSTRAINTOFFSETEMPORARY */
"UNIQUERYATTACHAVINGROUPDATEMPORARYBEGINNEREINDEXCLUSIVEXISTSBETWEEN" /* UNIQUERYATTACHAVINGROUPDATEBEGINNERELEASEBETWEENOTNULLIKE */
"OTNULLIKECASCADEFERRABLECASECOLLATECREATECURRENT_DATEDELETEDETACH" /* CASCADELETECASECOLLATECREATECURRENT_DATEDETACHIMMEDIATEJOIN */
"IMMEDIATEJOINSERTMATCHPLANALYZEPRAGMABORTVALUESVIRTUALIMITWHEN" /* SERTMATCHPLANALYZEPRAGMABORTVALUESVIRTUALIMITWHENWHERENAME */
"WHERENAMEAFTEREPLACEANDEFAULTAUTOINCREMENTCASTCOLUMNCOMMITCONFLICT" /* AFTEREPLACEANDEFAULTAUTOINCREMENTCASTCOLUMNCOMMITCONFLICTCROSS */
"CROSSCURRENT_TIMESTAMPRIMARYDEFERREDISTINCTDROPFAILFROMFULLGLOB" /* CURRENT_TIMESTAMPRIMARYDEFERREDISTINCTDROPFAILFROMFULLGLOBYIF */
"YIFINTOFFSETISNULLORDERESTRICTOUTERIGHTROLLBACKROWUNIONUSINGVACUUM" /* ISNULLORDERESTRICTOUTERIGHTROLLBACKROWUNIONUSINGVACUUMVIEW */
"VIEWINITIALLY"; /* INITIALLY */
static const char zText[540] = {
'R','E','I','N','D','E','X','E','D','E','S','C','A','P','E','A','C','H',
'E','C','K','E','Y','B','E','F','O','R','E','I','G','N','O','R','E','G',
'E','X','P','L','A','I','N','S','T','E','A','D','D','A','T','A','B','A',
'S','E','L','E','C','T','A','B','L','E','F','T','H','E','N','D','E','F',
'E','R','R','A','B','L','E','L','S','E','X','C','E','P','T','R','A','N',
'S','A','C','T','I','O','N','A','T','U','R','A','L','T','E','R','A','I',
'S','E','X','C','L','U','S','I','V','E','X','I','S','T','S','A','V','E',
'P','O','I','N','T','E','R','S','E','C','T','R','I','G','G','E','R','E',
'F','E','R','E','N','C','E','S','C','O','N','S','T','R','A','I','N','T',
'O','F','F','S','E','T','E','M','P','O','R','A','R','Y','U','N','I','Q',
'U','E','R','Y','A','T','T','A','C','H','A','V','I','N','G','R','O','U',
'P','D','A','T','E','B','E','G','I','N','N','E','R','E','L','E','A','S',
'E','B','E','T','W','E','E','N','O','T','N','U','L','L','I','K','E','C',
'A','S','C','A','D','E','L','E','T','E','C','A','S','E','C','O','L','L',
'A','T','E','C','R','E','A','T','E','C','U','R','R','E','N','T','_','D',
'A','T','E','D','E','T','A','C','H','I','M','M','E','D','I','A','T','E',
'J','O','I','N','S','E','R','T','M','A','T','C','H','P','L','A','N','A',
'L','Y','Z','E','P','R','A','G','M','A','B','O','R','T','V','A','L','U',
'E','S','V','I','R','T','U','A','L','I','M','I','T','W','H','E','N','W',
'H','E','R','E','N','A','M','E','A','F','T','E','R','E','P','L','A','C',
'E','A','N','D','E','F','A','U','L','T','A','U','T','O','I','N','C','R',
'E','M','E','N','T','C','A','S','T','C','O','L','U','M','N','C','O','M',
'M','I','T','C','O','N','F','L','I','C','T','C','R','O','S','S','C','U',
'R','R','E','N','T','_','T','I','M','E','S','T','A','M','P','R','I','M',
'A','R','Y','D','E','F','E','R','R','E','D','I','S','T','I','N','C','T',
'D','R','O','P','F','A','I','L','F','R','O','M','F','U','L','L','G','L',
'O','B','Y','I','F','I','S','N','U','L','L','O','R','D','E','R','E','S',
'T','R','I','C','T','O','U','T','E','R','I','G','H','T','R','O','L','L',
'B','A','C','K','R','O','W','U','N','I','O','N','U','S','I','N','G','V',
'A','C','U','U','M','V','I','E','W','I','N','I','T','I','A','L','L','Y',
};
static const unsigned char aHash[127] = { static const unsigned char aHash[127] = {
63, 92, 109, 61, 0, 39, 0, 0, 69, 0, 64, 0, 0, 70, 99, 112, 68, 0, 43, 0, 0, 76, 0, 71, 0, 0,
101, 4, 65, 7, 0, 108, 72, 103, 99, 0, 22, 0, 0, 41, 12, 72, 15, 0, 111, 79, 49, 106, 0, 19, 0, 0,
113, 0, 111, 106, 0, 18, 80, 0, 1, 0, 0, 56, 57, 116, 0, 114, 109, 0, 22, 87, 0, 9, 0, 0, 64, 65,
0, 55, 11, 0, 33, 77, 89, 0, 110, 88, 0, 0, 45, 0, 63, 6, 0, 47, 84, 96, 0, 113, 95, 0, 0, 44,
0, 90, 54, 0, 20, 0, 114, 34, 19, 0, 10, 97, 28, 0, 97, 24, 0, 17, 0, 117, 48, 23, 0, 5, 104, 25,
83, 0, 0, 116, 93, 47, 115, 41, 12, 44, 0, 78, 0, 90, 0, 0, 119, 100, 55, 118, 52, 7, 50, 0, 85, 0,
87, 29, 0, 86, 0, 0, 0, 82, 79, 84, 75, 96, 6, 94, 26, 0, 93, 0, 0, 0, 89, 86, 91, 82, 103, 14,
14, 95, 0, 68, 0, 21, 76, 98, 27, 0, 112, 67, 104, 38, 102, 0, 75, 0, 18, 83, 105, 31, 0, 115, 74, 107,
49, 40, 71, 0, 0, 81, 100, 0, 107, 0, 15, 0, 0, 56, 45, 78, 0, 0, 88, 39, 0, 110, 0, 35, 0, 0,
24, 0, 73, 42, 50, 0, 16, 48, 0, 37, 28, 0, 80, 53, 58, 0, 20, 57, 0, 51,
}; };
static const unsigned char aNext[116] = { static const unsigned char aNext[119] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 13, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
17, 0, 0, 0, 36, 38, 0, 0, 25, 0, 0, 31, 0, 0, 0, 0, 0, 32, 21, 0, 0, 0, 42, 2, 46, 0,
0, 0, 43, 52, 0, 0, 0, 53, 0, 0, 0, 0, 0, 0, 0, 0, 0, 29, 0, 37, 0, 0, 0, 1, 60, 0,
0, 0, 0, 0, 51, 0, 0, 0, 0, 26, 0, 8, 46, 0, 61, 0, 40, 0, 0, 0, 0, 0, 0, 0, 59, 0,
3, 0, 0, 0, 0, 0, 0, 0, 2, 58, 66, 0, 13, 0, 0, 0, 30, 54, 16, 33, 11, 0, 0, 0, 0, 0,
0, 91, 85, 0, 94, 0, 74, 0, 0, 0, 62, 35, 102, 0, 0, 10, 66, 73, 0, 8, 0, 98, 92, 0, 101, 0,
0, 0, 105, 23, 30, 60, 70, 0, 0, 59, 0, 0, 81, 0, 69, 0, 0, 108, 27, 36, 67, 77, 0, 34, 62,
0, 0,
}; };
static const unsigned char aLen[116] = { static const unsigned char aLen[119] = {
6, 3, 7, 6, 6, 7, 7, 3, 4, 6, 4, 5, 3, 7, 5, 7, 4, 6, 4, 5, 3, 6, 3, 7, 6, 6,
10, 9, 5, 4, 4, 3, 8, 2, 6, 11, 2, 7, 5, 7, 7, 3, 8, 2, 6, 5, 4, 4, 3, 10, 4, 6,
5, 4, 6, 7, 10, 6, 5, 6, 6, 5, 6, 9, 4, 11, 2, 7, 5, 5, 9, 6, 9, 9, 7, 10, 10, 4,
2, 5, 5, 7, 5, 9, 6, 7, 7, 3, 4, 4, 7, 6, 2, 3, 4, 9, 2, 6, 5, 6, 6, 5, 6, 5,
3, 10, 4, 7, 6, 12, 6, 6, 9, 4, 6, 5, 4, 5, 7, 7, 3, 7, 4, 4, 7, 3, 6, 4, 7, 6,
7, 6, 5, 6, 7, 5, 4, 5, 6, 5, 7, 3, 7, 12, 6, 9, 4, 6, 5, 4, 7, 6, 5, 6, 7, 5,
13, 2, 2, 4, 6, 6, 8, 5, 17, 12, 7, 8, 8, 4, 5, 6, 5, 7, 3, 7, 13, 2, 2, 4, 6, 6,
2, 4, 4, 4, 4, 4, 2, 2, 4, 2, 6, 3, 6, 8, 5, 17, 12, 7, 8, 8, 2, 4, 4, 4, 4, 4,
5, 8, 5, 5, 8, 3, 5, 5, 6, 4, 9, 3, 2, 2, 6, 5, 8, 5, 5, 8, 3, 5, 5, 6, 4,
9, 3,
}; };
static const unsigned short int aOffset[116] = { static const unsigned short int aOffset[119] = {
0, 2, 2, 6, 10, 13, 18, 23, 25, 26, 31, 33, 37, 0, 2, 2, 8, 9, 14, 16, 20, 23, 25, 25, 29, 33,
40, 47, 55, 58, 61, 63, 65, 70, 71, 76, 85, 86, 91, 36, 41, 46, 48, 53, 54, 59, 62, 65, 67, 69, 78, 81,
95, 99, 102, 107, 113, 123, 126, 131, 136, 141, 144, 148, 148, 86, 95, 96, 101, 105, 109, 117, 122, 128, 136, 142, 152, 159,
152, 157, 160, 164, 166, 169, 177, 183, 189, 189, 192, 195, 199, 162, 162, 165, 167, 167, 171, 176, 179, 184, 189, 194, 197, 203,
200, 204, 214, 218, 225, 231, 243, 249, 255, 264, 266, 272, 277, 206, 210, 217, 223, 223, 226, 229, 233, 234, 238, 244, 248, 255,
279, 286, 291, 296, 302, 308, 313, 317, 320, 326, 330, 337, 339, 261, 273, 279, 288, 290, 296, 301, 303, 310, 315, 320, 326, 332,
346, 348, 350, 359, 363, 369, 375, 383, 388, 388, 404, 411, 418, 337, 341, 344, 350, 354, 361, 363, 370, 372, 374, 383, 387, 393,
419, 426, 430, 434, 438, 442, 445, 447, 449, 452, 452, 455, 458, 399, 407, 412, 412, 428, 435, 442, 443, 450, 454, 458, 462, 466,
464, 468, 476, 480, 485, 493, 496, 501, 506, 512, 516, 521, 469, 471, 473, 479, 483, 491, 495, 500, 508, 511, 516, 521, 527,
531, 536,
}; };
static const unsigned char aCode[116] = { static const unsigned char aCode[119] = {
TK_BEFORE, TK_FOR, TK_FOREIGN, TK_IGNORE, TK_LIKE_KW, TK_REINDEX, TK_INDEX, TK_INDEXED, TK_DESC, TK_ESCAPE,
TK_EXPLAIN, TK_INSTEAD, TK_ADD, TK_DESC, TK_ESCAPE, TK_EACH, TK_CHECK, TK_KEY, TK_BEFORE, TK_FOR,
TK_EACH, TK_CHECK, TK_KEY, TK_CONSTRAINT, TK_INTERSECT, TK_FOREIGN, TK_IGNORE, TK_LIKE_KW, TK_EXPLAIN, TK_INSTEAD,
TK_TABLE, TK_JOIN_KW, TK_THEN, TK_END, TK_DATABASE, TK_ADD, TK_DATABASE, TK_AS, TK_SELECT, TK_TABLE,
TK_AS, TK_SELECT, TK_TRANSACTION,TK_ON, TK_JOIN_KW, TK_JOIN_KW, TK_THEN, TK_END, TK_DEFERRABLE, TK_ELSE,
TK_ALTER, TK_RAISE, TK_ELSE, TK_EXCEPT, TK_TRIGGER, TK_EXCEPT, TK_TRANSACTION,TK_ON, TK_JOIN_KW, TK_ALTER,
TK_REFERENCES, TK_UNIQUE, TK_QUERY, TK_ATTACH, TK_HAVING, TK_RAISE, TK_EXCLUSIVE, TK_EXISTS, TK_SAVEPOINT, TK_INTERSECT,
TK_GROUP, TK_UPDATE, TK_TEMP, TK_TEMP, TK_OR, TK_TRIGGER, TK_REFERENCES, TK_CONSTRAINT, TK_INTO, TK_OFFSET,
TK_BEGIN, TK_JOIN_KW, TK_REINDEX, TK_INDEX, TK_EXCLUSIVE, TK_OF, TK_SET, TK_TEMP, TK_TEMP, TK_OR,
TK_EXISTS, TK_BETWEEN, TK_NOTNULL, TK_NOT, TK_NULL, TK_UNIQUE, TK_QUERY, TK_ATTACH, TK_HAVING, TK_GROUP,
TK_LIKE_KW, TK_CASCADE, TK_ASC, TK_DEFERRABLE, TK_CASE, TK_UPDATE, TK_BEGIN, TK_JOIN_KW, TK_RELEASE, TK_BETWEEN,
TK_COLLATE, TK_CREATE, TK_CTIME_KW, TK_DELETE, TK_DETACH, TK_NOT, TK_NOTNULL, TK_NULL, TK_LIKE_KW, TK_CASCADE,
TK_IMMEDIATE, TK_JOIN, TK_INSERT, TK_MATCH, TK_PLAN, TK_ASC, TK_DELETE, TK_CASE, TK_COLLATE, TK_CREATE,
TK_ANALYZE, TK_PRAGMA, TK_ABORT, TK_VALUES, TK_VIRTUAL, TK_CTIME_KW, TK_DETACH, TK_IMMEDIATE, TK_JOIN, TK_INSERT,
TK_LIMIT, TK_WHEN, TK_WHERE, TK_RENAME, TK_AFTER, TK_MATCH, TK_PLAN, TK_ANALYZE, TK_PRAGMA, TK_ABORT,
TK_REPLACE, TK_AND, TK_DEFAULT, TK_AUTOINCR, TK_TO, TK_VALUES, TK_VIRTUAL, TK_LIMIT, TK_WHEN, TK_WHERE,
TK_IN, TK_CAST, TK_COLUMNKW, TK_COMMIT, TK_CONFLICT, TK_RENAME, TK_AFTER, TK_REPLACE, TK_AND, TK_DEFAULT,
TK_JOIN_KW, TK_CTIME_KW, TK_CTIME_KW, TK_PRIMARY, TK_DEFERRED, TK_AUTOINCR, TK_TO, TK_IN, TK_CAST, TK_COLUMNKW,
TK_DISTINCT, TK_IS, TK_DROP, TK_FAIL, TK_FROM, TK_COMMIT, TK_CONFLICT, TK_JOIN_KW, TK_CTIME_KW, TK_CTIME_KW,
TK_JOIN_KW, TK_LIKE_KW, TK_BY, TK_IF, TK_INTO, TK_PRIMARY, TK_DEFERRED, TK_DISTINCT, TK_IS, TK_DROP,
TK_OF, TK_OFFSET, TK_SET, TK_ISNULL, TK_ORDER, TK_FAIL, TK_FROM, TK_JOIN_KW, TK_LIKE_KW, TK_BY,
TK_RESTRICT, TK_JOIN_KW, TK_JOIN_KW, TK_ROLLBACK, TK_ROW, TK_IF, TK_ISNULL, TK_ORDER, TK_RESTRICT, TK_JOIN_KW,
TK_UNION, TK_USING, TK_VACUUM, TK_VIEW, TK_INITIALLY, TK_JOIN_KW, TK_ROLLBACK, TK_ROW, TK_UNION, TK_USING,
TK_ALL, TK_VACUUM, TK_VIEW, TK_INITIALLY, TK_ALL,
}; };
int h, i; int h, i;
if( n<2 ) return TK_ID; if( n<2 ) return TK_ID;
@ -102,6 +137,125 @@ static int keywordCode(const char *z, int n){
n) % 127; n) % 127;
for(i=((int)aHash[h])-1; i>=0; i=((int)aNext[i])-1){ for(i=((int)aHash[h])-1; i>=0; i=((int)aNext[i])-1){
if( aLen[i]==n && sqlite3StrNICmp(&zText[aOffset[i]],z,n)==0 ){ if( aLen[i]==n && sqlite3StrNICmp(&zText[aOffset[i]],z,n)==0 ){
testcase( i==0 ); /* TK_REINDEX */
testcase( i==1 ); /* TK_INDEX */
testcase( i==2 ); /* TK_INDEXED */
testcase( i==3 ); /* TK_DESC */
testcase( i==4 ); /* TK_ESCAPE */
testcase( i==5 ); /* TK_EACH */
testcase( i==6 ); /* TK_CHECK */
testcase( i==7 ); /* TK_KEY */
testcase( i==8 ); /* TK_BEFORE */
testcase( i==9 ); /* TK_FOR */
testcase( i==10 ); /* TK_FOREIGN */
testcase( i==11 ); /* TK_IGNORE */
testcase( i==12 ); /* TK_LIKE_KW */
testcase( i==13 ); /* TK_EXPLAIN */
testcase( i==14 ); /* TK_INSTEAD */
testcase( i==15 ); /* TK_ADD */
testcase( i==16 ); /* TK_DATABASE */
testcase( i==17 ); /* TK_AS */
testcase( i==18 ); /* TK_SELECT */
testcase( i==19 ); /* TK_TABLE */
testcase( i==20 ); /* TK_JOIN_KW */
testcase( i==21 ); /* TK_THEN */
testcase( i==22 ); /* TK_END */
testcase( i==23 ); /* TK_DEFERRABLE */
testcase( i==24 ); /* TK_ELSE */
testcase( i==25 ); /* TK_EXCEPT */
testcase( i==26 ); /* TK_TRANSACTION */
testcase( i==27 ); /* TK_ON */
testcase( i==28 ); /* TK_JOIN_KW */
testcase( i==29 ); /* TK_ALTER */
testcase( i==30 ); /* TK_RAISE */
testcase( i==31 ); /* TK_EXCLUSIVE */
testcase( i==32 ); /* TK_EXISTS */
testcase( i==33 ); /* TK_SAVEPOINT */
testcase( i==34 ); /* TK_INTERSECT */
testcase( i==35 ); /* TK_TRIGGER */
testcase( i==36 ); /* TK_REFERENCES */
testcase( i==37 ); /* TK_CONSTRAINT */
testcase( i==38 ); /* TK_INTO */
testcase( i==39 ); /* TK_OFFSET */
testcase( i==40 ); /* TK_OF */
testcase( i==41 ); /* TK_SET */
testcase( i==42 ); /* TK_TEMP */
testcase( i==43 ); /* TK_TEMP */
testcase( i==44 ); /* TK_OR */
testcase( i==45 ); /* TK_UNIQUE */
testcase( i==46 ); /* TK_QUERY */
testcase( i==47 ); /* TK_ATTACH */
testcase( i==48 ); /* TK_HAVING */
testcase( i==49 ); /* TK_GROUP */
testcase( i==50 ); /* TK_UPDATE */
testcase( i==51 ); /* TK_BEGIN */
testcase( i==52 ); /* TK_JOIN_KW */
testcase( i==53 ); /* TK_RELEASE */
testcase( i==54 ); /* TK_BETWEEN */
testcase( i==55 ); /* TK_NOT */
testcase( i==56 ); /* TK_NOTNULL */
testcase( i==57 ); /* TK_NULL */
testcase( i==58 ); /* TK_LIKE_KW */
testcase( i==59 ); /* TK_CASCADE */
testcase( i==60 ); /* TK_ASC */
testcase( i==61 ); /* TK_DELETE */
testcase( i==62 ); /* TK_CASE */
testcase( i==63 ); /* TK_COLLATE */
testcase( i==64 ); /* TK_CREATE */
testcase( i==65 ); /* TK_CTIME_KW */
testcase( i==66 ); /* TK_DETACH */
testcase( i==67 ); /* TK_IMMEDIATE */
testcase( i==68 ); /* TK_JOIN */
testcase( i==69 ); /* TK_INSERT */
testcase( i==70 ); /* TK_MATCH */
testcase( i==71 ); /* TK_PLAN */
testcase( i==72 ); /* TK_ANALYZE */
testcase( i==73 ); /* TK_PRAGMA */
testcase( i==74 ); /* TK_ABORT */
testcase( i==75 ); /* TK_VALUES */
testcase( i==76 ); /* TK_VIRTUAL */
testcase( i==77 ); /* TK_LIMIT */
testcase( i==78 ); /* TK_WHEN */
testcase( i==79 ); /* TK_WHERE */
testcase( i==80 ); /* TK_RENAME */
testcase( i==81 ); /* TK_AFTER */
testcase( i==82 ); /* TK_REPLACE */
testcase( i==83 ); /* TK_AND */
testcase( i==84 ); /* TK_DEFAULT */
testcase( i==85 ); /* TK_AUTOINCR */
testcase( i==86 ); /* TK_TO */
testcase( i==87 ); /* TK_IN */
testcase( i==88 ); /* TK_CAST */
testcase( i==89 ); /* TK_COLUMNKW */
testcase( i==90 ); /* TK_COMMIT */
testcase( i==91 ); /* TK_CONFLICT */
testcase( i==92 ); /* TK_JOIN_KW */
testcase( i==93 ); /* TK_CTIME_KW */
testcase( i==94 ); /* TK_CTIME_KW */
testcase( i==95 ); /* TK_PRIMARY */
testcase( i==96 ); /* TK_DEFERRED */
testcase( i==97 ); /* TK_DISTINCT */
testcase( i==98 ); /* TK_IS */
testcase( i==99 ); /* TK_DROP */
testcase( i==100 ); /* TK_FAIL */
testcase( i==101 ); /* TK_FROM */
testcase( i==102 ); /* TK_JOIN_KW */
testcase( i==103 ); /* TK_LIKE_KW */
testcase( i==104 ); /* TK_BY */
testcase( i==105 ); /* TK_IF */
testcase( i==106 ); /* TK_ISNULL */
testcase( i==107 ); /* TK_ORDER */
testcase( i==108 ); /* TK_RESTRICT */
testcase( i==109 ); /* TK_JOIN_KW */
testcase( i==110 ); /* TK_JOIN_KW */
testcase( i==111 ); /* TK_ROLLBACK */
testcase( i==112 ); /* TK_ROW */
testcase( i==113 ); /* TK_UNION */
testcase( i==114 ); /* TK_USING */
testcase( i==115 ); /* TK_VACUUM */
testcase( i==116 ); /* TK_VIEW */
testcase( i==117 ); /* TK_INITIALLY */
testcase( i==118 ); /* TK_ALL */
return aCode[i]; return aCode[i];
} }
} }

View file

@ -14,11 +14,10 @@
** other files are for internal use by SQLite and should not be ** other files are for internal use by SQLite and should not be
** accessed by users of the library. ** accessed by users of the library.
** **
** $Id: legacy.c,v 1.18 2007/05/04 13:15:56 drh Exp $ ** $Id: legacy.c,v 1.30 2008/12/10 19:26:24 drh Exp $
*/ */
#include "sqliteInt.h" #include "sqliteInt.h"
#include "os.h"
#include <ctype.h> #include <ctype.h>
/* /*
@ -46,7 +45,10 @@ int sqlite3_exec(
int nRetry = 0; int nRetry = 0;
int nCallback; int nCallback;
if( zSql==0 ) return SQLITE_OK; if( zSql==0 ) zSql = "";
sqlite3_mutex_enter(db->mutex);
sqlite3Error(db, SQLITE_OK, 0);
while( (rc==SQLITE_OK || (rc==SQLITE_SCHEMA && (++nRetry)<2)) && zSql[0] ){ while( (rc==SQLITE_OK || (rc==SQLITE_SCHEMA && (++nRetry)<2)) && zSql[0] ){
int nCol; int nCol;
char **azVals = 0; char **azVals = 0;
@ -64,12 +66,7 @@ int sqlite3_exec(
} }
nCallback = 0; nCallback = 0;
nCol = sqlite3_column_count(pStmt); nCol = sqlite3_column_count(pStmt);
azCols = sqliteMalloc(2*nCol*sizeof(const char *) + 1);
if( azCols==0 ){
goto exec_out;
}
while( 1 ){ while( 1 ){
int i; int i;
@ -79,8 +76,17 @@ int sqlite3_exec(
if( xCallback && (SQLITE_ROW==rc || if( xCallback && (SQLITE_ROW==rc ||
(SQLITE_DONE==rc && !nCallback && db->flags&SQLITE_NullCallback)) ){ (SQLITE_DONE==rc && !nCallback && db->flags&SQLITE_NullCallback)) ){
if( 0==nCallback ){ if( 0==nCallback ){
if( azCols==0 ){
azCols = sqlite3DbMallocZero(db, 2*nCol*sizeof(const char*) + 1);
if( azCols==0 ){
goto exec_out;
}
}
for(i=0; i<nCol; i++){ for(i=0; i<nCol; i++){
azCols[i] = (char *)sqlite3_column_name(pStmt, i); azCols[i] = (char *)sqlite3_column_name(pStmt, i);
/* sqlite3VdbeSetColName() installs column names as UTF8
** strings so there is no way for sqlite3_column_name() to fail. */
assert( azCols[i]!=0 );
} }
nCallback++; nCallback++;
} }
@ -88,10 +94,17 @@ int sqlite3_exec(
azVals = &azCols[nCol]; azVals = &azCols[nCol];
for(i=0; i<nCol; i++){ for(i=0; i<nCol; i++){
azVals[i] = (char *)sqlite3_column_text(pStmt, i); azVals[i] = (char *)sqlite3_column_text(pStmt, i);
if( !azVals[i] && sqlite3_column_type(pStmt, i)!=SQLITE_NULL ){
db->mallocFailed = 1;
goto exec_out;
}
} }
} }
if( xCallback(pArg, nCol, azVals, azCols) ){ if( xCallback(pArg, nCol, azVals, azCols) ){
rc = SQLITE_ABORT; rc = SQLITE_ABORT;
sqlite3_finalize(pStmt);
pStmt = 0;
sqlite3Error(db, SQLITE_ABORT, 0);
goto exec_out; goto exec_out;
} }
} }
@ -108,18 +121,18 @@ int sqlite3_exec(
} }
} }
sqliteFree(azCols); sqlite3DbFree(db, azCols);
azCols = 0; azCols = 0;
} }
exec_out: exec_out:
if( pStmt ) sqlite3_finalize(pStmt); if( pStmt ) sqlite3_finalize(pStmt);
if( azCols ) sqliteFree(azCols); sqlite3DbFree(db, azCols);
rc = sqlite3ApiExit(0, rc); rc = sqlite3ApiExit(db, rc);
if( rc!=SQLITE_OK && rc==sqlite3_errcode(db) && pzErrMsg ){ if( rc!=SQLITE_OK && rc==sqlite3_errcode(db) && pzErrMsg ){
int nErrMsg = 1 + strlen(sqlite3_errmsg(db)); int nErrMsg = 1 + sqlite3Strlen30(sqlite3_errmsg(db));
*pzErrMsg = sqlite3_malloc(nErrMsg); *pzErrMsg = sqlite3Malloc(nErrMsg);
if( *pzErrMsg ){ if( *pzErrMsg ){
memcpy(*pzErrMsg, sqlite3_errmsg(db), nErrMsg); memcpy(*pzErrMsg, sqlite3_errmsg(db), nErrMsg);
} }
@ -128,5 +141,6 @@ exec_out:
} }
assert( (rc&db->errMask)==rc ); assert( (rc&db->errMask)==rc );
sqlite3_mutex_leave(db->mutex);
return rc; return rc;
} }

280
loadext.c
View file

@ -11,16 +11,20 @@
************************************************************************* *************************************************************************
** This file contains code used to dynamically load extensions into ** This file contains code used to dynamically load extensions into
** the SQLite library. ** the SQLite library.
**
** $Id: loadext.c,v 1.57 2008/12/08 18:19:18 drh Exp $
*/ */
#ifndef SQLITE_OMIT_LOAD_EXTENSION
#define SQLITE_CORE 1 /* Disable the API redefinition in sqlite3ext.h */ #ifndef SQLITE_CORE
#define SQLITE_CORE 1 /* Disable the API redefinition in sqlite3ext.h */
#endif
#include "sqlite3ext.h" #include "sqlite3ext.h"
#include "sqliteInt.h" #include "sqliteInt.h"
#include "os.h"
#include <string.h> #include <string.h>
#include <ctype.h> #include <ctype.h>
#ifndef SQLITE_OMIT_LOAD_EXTENSION
/* /*
** Some API routines are omitted when various features are ** Some API routines are omitted when various features are
** excluded from a build of SQLite. Substitute a NULL pointer ** excluded from a build of SQLite. Substitute a NULL pointer
@ -94,6 +98,15 @@
# define sqlite3_get_table 0 # define sqlite3_get_table 0
#endif #endif
#ifdef SQLITE_OMIT_INCRBLOB
#define sqlite3_bind_zeroblob 0
#define sqlite3_blob_bytes 0
#define sqlite3_blob_close 0
#define sqlite3_blob_open 0
#define sqlite3_blob_read 0
#define sqlite3_blob_write 0
#endif
/* /*
** The following structure contains pointers to all SQLite API routines. ** The following structure contains pointers to all SQLite API routines.
** A pointer to this structure is passed into extensions when they are ** A pointer to this structure is passed into extensions when they are
@ -109,9 +122,13 @@
** also check to make sure that the pointer to the function is ** also check to make sure that the pointer to the function is
** not NULL before calling it. ** not NULL before calling it.
*/ */
const sqlite3_api_routines sqlite3_apis = { static const sqlite3_api_routines sqlite3Apis = {
sqlite3_aggregate_context, sqlite3_aggregate_context,
#ifndef SQLITE_OMIT_DEPRECATED
sqlite3_aggregate_count, sqlite3_aggregate_count,
#else
0,
#endif
sqlite3_bind_blob, sqlite3_bind_blob,
sqlite3_bind_double, sqlite3_bind_double,
sqlite3_bind_int, sqlite3_bind_int,
@ -166,7 +183,11 @@ const sqlite3_api_routines sqlite3_apis = {
sqlite3_errmsg, sqlite3_errmsg,
sqlite3_errmsg16, sqlite3_errmsg16,
sqlite3_exec, sqlite3_exec,
#ifndef SQLITE_OMIT_DEPRECATED
sqlite3_expired, sqlite3_expired,
#else
0,
#endif
sqlite3_finalize, sqlite3_finalize,
sqlite3_free, sqlite3_free,
sqlite3_free_table, sqlite3_free_table,
@ -206,10 +227,18 @@ const sqlite3_api_routines sqlite3_apis = {
sqlite3_snprintf, sqlite3_snprintf,
sqlite3_step, sqlite3_step,
sqlite3_table_column_metadata, sqlite3_table_column_metadata,
#ifndef SQLITE_OMIT_DEPRECATED
sqlite3_thread_cleanup, sqlite3_thread_cleanup,
#else
0,
#endif
sqlite3_total_changes, sqlite3_total_changes,
sqlite3_trace, sqlite3_trace,
#ifndef SQLITE_OMIT_DEPRECATED
sqlite3_transfer_bindings, sqlite3_transfer_bindings,
#else
0,
#endif
sqlite3_update_hook, sqlite3_update_hook,
sqlite3_user_data, sqlite3_user_data,
sqlite3_value_blob, sqlite3_value_blob,
@ -247,6 +276,60 @@ const sqlite3_api_routines sqlite3_apis = {
*/ */
sqlite3_create_module_v2, sqlite3_create_module_v2,
/*
** Added for 3.5.0
*/
sqlite3_bind_zeroblob,
sqlite3_blob_bytes,
sqlite3_blob_close,
sqlite3_blob_open,
sqlite3_blob_read,
sqlite3_blob_write,
sqlite3_create_collation_v2,
sqlite3_file_control,
sqlite3_memory_highwater,
sqlite3_memory_used,
#ifdef SQLITE_MUTEX_OMIT
0,
0,
0,
0,
0,
#else
sqlite3_mutex_alloc,
sqlite3_mutex_enter,
sqlite3_mutex_free,
sqlite3_mutex_leave,
sqlite3_mutex_try,
#endif
sqlite3_open_v2,
sqlite3_release_memory,
sqlite3_result_error_nomem,
sqlite3_result_error_toobig,
sqlite3_sleep,
sqlite3_soft_heap_limit,
sqlite3_vfs_find,
sqlite3_vfs_register,
sqlite3_vfs_unregister,
/*
** Added for 3.5.8
*/
sqlite3_threadsafe,
sqlite3_result_zeroblob,
sqlite3_result_error_code,
sqlite3_test_control,
sqlite3_randomness,
sqlite3_context_db_handle,
/*
** Added for 3.6.0
*/
sqlite3_extended_result_codes,
sqlite3_limit,
sqlite3_next_stmt,
sqlite3_sql,
sqlite3_status,
}; };
/* /*
@ -259,14 +342,15 @@ const sqlite3_api_routines sqlite3_apis = {
** **
** If an error occurs and pzErrMsg is not 0, then fill *pzErrMsg with ** If an error occurs and pzErrMsg is not 0, then fill *pzErrMsg with
** error message text. The calling function should free this memory ** error message text. The calling function should free this memory
** by calling sqlite3_free(). ** by calling sqlite3DbFree(db, ).
*/ */
int sqlite3_load_extension( static int sqlite3LoadExtension(
sqlite3 *db, /* Load the extension into this database connection */ sqlite3 *db, /* Load the extension into this database connection */
const char *zFile, /* Name of the shared library containing extension */ const char *zFile, /* Name of the shared library containing extension */
const char *zProc, /* Entry point. Use "sqlite3_extension_init" if 0 */ const char *zProc, /* Entry point. Use "sqlite3_extension_init" if 0 */
char **pzErrMsg /* Put error message here if not 0 */ char **pzErrMsg /* Put error message here if not 0 */
){ ){
sqlite3_vfs *pVfs = db->pVfs;
void *handle; void *handle;
int (*xInit)(sqlite3*,char**,const sqlite3_api_routines*); int (*xInit)(sqlite3*,char**,const sqlite3_api_routines*);
char *zErrmsg = 0; char *zErrmsg = 0;
@ -289,46 +373,66 @@ int sqlite3_load_extension(
zProc = "sqlite3_extension_init"; zProc = "sqlite3_extension_init";
} }
handle = sqlite3OsDlopen(zFile); handle = sqlite3OsDlOpen(pVfs, zFile);
if( handle==0 ){ if( handle==0 ){
if( pzErrMsg ){ if( pzErrMsg ){
*pzErrMsg = sqlite3_mprintf("unable to open shared library [%s]", zFile); char zErr[256];
zErr[sizeof(zErr)-1] = '\0';
sqlite3_snprintf(sizeof(zErr)-1, zErr,
"unable to open shared library [%s]", zFile);
sqlite3OsDlError(pVfs, sizeof(zErr)-1, zErr);
*pzErrMsg = sqlite3DbStrDup(0, zErr);
} }
return SQLITE_ERROR; return SQLITE_ERROR;
} }
xInit = (int(*)(sqlite3*,char**,const sqlite3_api_routines*)) xInit = (int(*)(sqlite3*,char**,const sqlite3_api_routines*))
sqlite3OsDlsym(handle, zProc); sqlite3OsDlSym(pVfs, handle, zProc);
if( xInit==0 ){ if( xInit==0 ){
if( pzErrMsg ){ if( pzErrMsg ){
*pzErrMsg = sqlite3_mprintf("no entry point [%s] in shared library [%s]", char zErr[256];
zProc, zFile); zErr[sizeof(zErr)-1] = '\0';
sqlite3_snprintf(sizeof(zErr)-1, zErr,
"no entry point [%s] in shared library [%s]", zProc,zFile);
sqlite3OsDlError(pVfs, sizeof(zErr)-1, zErr);
*pzErrMsg = sqlite3DbStrDup(0, zErr);
sqlite3OsDlClose(pVfs, handle);
} }
sqlite3OsDlclose(handle);
return SQLITE_ERROR; return SQLITE_ERROR;
}else if( xInit(db, &zErrmsg, &sqlite3_apis) ){ }else if( xInit(db, &zErrmsg, &sqlite3Apis) ){
if( pzErrMsg ){ if( pzErrMsg ){
*pzErrMsg = sqlite3_mprintf("error during initialization: %s", zErrmsg); *pzErrMsg = sqlite3_mprintf("error during initialization: %s", zErrmsg);
} }
sqlite3_free(zErrmsg); sqlite3_free(zErrmsg);
sqlite3OsDlclose(handle); sqlite3OsDlClose(pVfs, handle);
return SQLITE_ERROR; return SQLITE_ERROR;
} }
/* Append the new shared library handle to the db->aExtension array. */ /* Append the new shared library handle to the db->aExtension array. */
db->nExtension++; aHandle = sqlite3DbMallocZero(db, sizeof(handle)*(db->nExtension+1));
aHandle = sqliteMalloc(sizeof(handle)*db->nExtension);
if( aHandle==0 ){ if( aHandle==0 ){
return SQLITE_NOMEM; return SQLITE_NOMEM;
} }
if( db->nExtension>0 ){ if( db->nExtension>0 ){
memcpy(aHandle, db->aExtension, sizeof(handle)*(db->nExtension-1)); memcpy(aHandle, db->aExtension, sizeof(handle)*db->nExtension);
} }
sqliteFree(db->aExtension); sqlite3DbFree(db, db->aExtension);
db->aExtension = aHandle; db->aExtension = aHandle;
db->aExtension[db->nExtension-1] = handle; db->aExtension[db->nExtension++] = handle;
return SQLITE_OK; return SQLITE_OK;
} }
int sqlite3_load_extension(
sqlite3 *db, /* Load the extension into this database connection */
const char *zFile, /* Name of the shared library containing extension */
const char *zProc, /* Entry point. Use "sqlite3_extension_init" if 0 */
char **pzErrMsg /* Put error message here if not 0 */
){
int rc;
sqlite3_mutex_enter(db->mutex);
rc = sqlite3LoadExtension(db, zFile, zProc, pzErrMsg);
sqlite3_mutex_leave(db->mutex);
return rc;
}
/* /*
** Call this routine when the database connection is closing in order ** Call this routine when the database connection is closing in order
@ -336,10 +440,11 @@ int sqlite3_load_extension(
*/ */
void sqlite3CloseExtensions(sqlite3 *db){ void sqlite3CloseExtensions(sqlite3 *db){
int i; int i;
assert( sqlite3_mutex_held(db->mutex) );
for(i=0; i<db->nExtension; i++){ for(i=0; i<db->nExtension; i++){
sqlite3OsDlclose(db->aExtension[i]); sqlite3OsDlClose(db->pVfs, db->aExtension[i]);
} }
sqliteFree(db->aExtension); sqlite3DbFree(db, db->aExtension);
} }
/* /*
@ -347,60 +452,116 @@ void sqlite3CloseExtensions(sqlite3 *db){
** default so as not to open security holes in older applications. ** default so as not to open security holes in older applications.
*/ */
int sqlite3_enable_load_extension(sqlite3 *db, int onoff){ int sqlite3_enable_load_extension(sqlite3 *db, int onoff){
sqlite3_mutex_enter(db->mutex);
if( onoff ){ if( onoff ){
db->flags |= SQLITE_LoadExtension; db->flags |= SQLITE_LoadExtension;
}else{ }else{
db->flags &= ~SQLITE_LoadExtension; db->flags &= ~SQLITE_LoadExtension;
} }
sqlite3_mutex_leave(db->mutex);
return SQLITE_OK; return SQLITE_OK;
} }
#endif /* SQLITE_OMIT_LOAD_EXTENSION */
/* /*
** A list of automatically loaded extensions. ** The auto-extension code added regardless of whether or not extension
** ** loading is supported. We need a dummy sqlite3Apis pointer for that
** This list is shared across threads, so be sure to hold the ** code if regular extension loading is not available. This is that
** mutex while accessing or changing it. ** dummy pointer.
*/ */
static int nAutoExtension = 0; #ifdef SQLITE_OMIT_LOAD_EXTENSION
static void **aAutoExtension = 0; static const sqlite3_api_routines sqlite3Apis = { 0 };
#endif
/*
** The following object holds the list of automatically loaded
** extensions.
**
** This list is shared across threads. The SQLITE_MUTEX_STATIC_MASTER
** mutex must be held while accessing this list.
*/
typedef struct sqlite3AutoExtList sqlite3AutoExtList;
static SQLITE_WSD struct sqlite3AutoExtList {
int nExt; /* Number of entries in aExt[] */
void (**aExt)(void); /* Pointers to the extension init functions */
} sqlite3Autoext = { 0, 0 };
/* The "wsdAutoext" macro will resolve to the autoextension
** state vector. If writable static data is unsupported on the target,
** we have to locate the state vector at run-time. In the more common
** case where writable static data is supported, wsdStat can refer directly
** to the "sqlite3Autoext" state vector declared above.
*/
#ifdef SQLITE_OMIT_WSD
# define wsdAutoextInit \
sqlite3AutoExtList *x = &GLOBAL(sqlite3AutoExtList,sqlite3Autoext)
# define wsdAutoext x[0]
#else
# define wsdAutoextInit
# define wsdAutoext sqlite3Autoext
#endif
/* /*
** Register a statically linked extension that is automatically ** Register a statically linked extension that is automatically
** loaded by every new database connection. ** loaded by every new database connection.
*/ */
int sqlite3_auto_extension(void *xInit){ int sqlite3_auto_extension(void (*xInit)(void)){
int i;
int rc = SQLITE_OK; int rc = SQLITE_OK;
sqlite3OsEnterMutex(); #ifndef SQLITE_OMIT_AUTOINIT
for(i=0; i<nAutoExtension; i++){ rc = sqlite3_initialize();
if( aAutoExtension[i]==xInit ) break; if( rc ){
} return rc;
if( i==nAutoExtension ){ }else
nAutoExtension++; #endif
aAutoExtension = sqlite3Realloc( aAutoExtension, {
nAutoExtension*sizeof(aAutoExtension[0]) ); int i;
if( aAutoExtension==0 ){ #if SQLITE_THREADSAFE
nAutoExtension = 0; sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER);
rc = SQLITE_NOMEM; #endif
}else{ wsdAutoextInit;
aAutoExtension[nAutoExtension-1] = xInit; sqlite3_mutex_enter(mutex);
for(i=0; i<wsdAutoext.nExt; i++){
if( wsdAutoext.aExt[i]==xInit ) break;
} }
if( i==wsdAutoext.nExt ){
int nByte = (wsdAutoext.nExt+1)*sizeof(wsdAutoext.aExt[0]);
void (**aNew)(void);
aNew = sqlite3_realloc(wsdAutoext.aExt, nByte);
if( aNew==0 ){
rc = SQLITE_NOMEM;
}else{
wsdAutoext.aExt = aNew;
wsdAutoext.aExt[wsdAutoext.nExt] = xInit;
wsdAutoext.nExt++;
}
}
sqlite3_mutex_leave(mutex);
assert( (rc&0xff)==rc );
return rc;
} }
sqlite3OsLeaveMutex();
assert( (rc&0xff)==rc );
return rc;
} }
/* /*
** Reset the automatic extension loading mechanism. ** Reset the automatic extension loading mechanism.
*/ */
void sqlite3_reset_auto_extension(void){ void sqlite3_reset_auto_extension(void){
sqlite3OsEnterMutex(); #ifndef SQLITE_OMIT_AUTOINIT
sqliteFree(aAutoExtension); if( sqlite3_initialize()==SQLITE_OK )
aAutoExtension = 0; #endif
nAutoExtension = 0; {
sqlite3OsLeaveMutex(); #if SQLITE_THREADSAFE
sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER);
#endif
wsdAutoextInit;
sqlite3_mutex_enter(mutex);
sqlite3_free(wsdAutoext.aExt);
wsdAutoext.aExt = 0;
wsdAutoext.nExt = 0;
sqlite3_mutex_leave(mutex);
}
} }
/* /*
@ -412,29 +573,32 @@ int sqlite3AutoLoadExtensions(sqlite3 *db){
int rc = SQLITE_OK; int rc = SQLITE_OK;
int (*xInit)(sqlite3*,char**,const sqlite3_api_routines*); int (*xInit)(sqlite3*,char**,const sqlite3_api_routines*);
if( nAutoExtension==0 ){ wsdAutoextInit;
if( wsdAutoext.nExt==0 ){
/* Common case: early out without every having to acquire a mutex */ /* Common case: early out without every having to acquire a mutex */
return SQLITE_OK; return SQLITE_OK;
} }
for(i=0; go; i++){ for(i=0; go; i++){
char *zErrmsg = 0; char *zErrmsg = 0;
sqlite3OsEnterMutex(); #if SQLITE_THREADSAFE
if( i>=nAutoExtension ){ sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER);
#endif
sqlite3_mutex_enter(mutex);
if( i>=wsdAutoext.nExt ){
xInit = 0; xInit = 0;
go = 0; go = 0;
}else{ }else{
xInit = (int(*)(sqlite3*,char**,const sqlite3_api_routines*)) xInit = (int(*)(sqlite3*,char**,const sqlite3_api_routines*))
aAutoExtension[i]; wsdAutoext.aExt[i];
} }
sqlite3OsLeaveMutex(); sqlite3_mutex_leave(mutex);
if( xInit && xInit(db, &zErrmsg, &sqlite3_apis) ){ if( xInit && xInit(db, &zErrmsg, &sqlite3Apis) ){
sqlite3Error(db, SQLITE_ERROR, sqlite3Error(db, SQLITE_ERROR,
"automatic extension loading failed: %s", zErrmsg); "automatic extension loading failed: %s", zErrmsg);
go = 0; go = 0;
rc = SQLITE_ERROR; rc = SQLITE_ERROR;
sqlite3_free(zErrmsg);
} }
} }
return rc; return rc;
} }
#endif /* SQLITE_OMIT_LOAD_EXTENSION */

1303
main.c

File diff suppressed because it is too large Load diff

1377
malloc.c

File diff suppressed because it is too large Load diff

61
mem0.c Normal file
View file

@ -0,0 +1,61 @@
/*
** 2008 October 28
**
** 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 a no-op memory allocation drivers for use when
** SQLITE_ZERO_MALLOC is defined. The allocation drivers implemented
** here always fail. SQLite will not operate with these drivers. These
** are merely placeholders. Real drivers must be substituted using
** sqlite3_config() before SQLite will operate.
**
** $Id: mem0.c,v 1.1 2008/10/28 18:58:20 drh Exp $
*/
#include "sqliteInt.h"
/*
** This version of the memory allocator is the default. It is
** used when no other memory allocator is specified using compile-time
** macros.
*/
#ifdef SQLITE_ZERO_MALLOC
/*
** No-op versions of all memory allocation routines
*/
static void *sqlite3MemMalloc(int nByte){ return 0; }
static void sqlite3MemFree(void *pPrior){ return; }
static void *sqlite3MemRealloc(void *pPrior, int nByte){ return 0; }
static int sqlite3MemSize(void *pPrior){ return 0; }
static int sqlite3MemRoundup(int n){ return n; }
static int sqlite3MemInit(void *NotUsed){ return SQLITE_OK; }
static void sqlite3MemShutdown(void *NotUsed){ return; }
/*
** This routine is the only routine in this file with external linkage.
**
** Populate the low-level memory allocation function pointers in
** sqlite3GlobalConfig.m with pointers to the routines in this file.
*/
void sqlite3MemSetDefault(void){
static const sqlite3_mem_methods defaultMethods = {
sqlite3MemMalloc,
sqlite3MemFree,
sqlite3MemRealloc,
sqlite3MemSize,
sqlite3MemRoundup,
sqlite3MemInit,
sqlite3MemShutdown,
0
};
sqlite3_config(SQLITE_CONFIG_MALLOC, &defaultMethods);
}
#endif /* SQLITE_ZERO_MALLOC */

145
mem1.c Normal file
View file

@ -0,0 +1,145 @@
/*
** 2007 August 14
**
** 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 low-level memory allocation drivers for when
** SQLite will use the standard C-library malloc/realloc/free interface
** to obtain the memory it needs.
**
** This file contains implementations of the low-level memory allocation
** routines specified in the sqlite3_mem_methods object.
**
** $Id: mem1.c,v 1.29 2008/12/10 21:19:57 drh Exp $
*/
#include "sqliteInt.h"
/*
** This version of the memory allocator is the default. It is
** used when no other memory allocator is specified using compile-time
** macros.
*/
#ifdef SQLITE_SYSTEM_MALLOC
/*
** Like malloc(), but remember the size of the allocation
** so that we can find it later using sqlite3MemSize().
**
** For this low-level routine, we are guaranteed that nByte>0 because
** cases of nByte<=0 will be intercepted and dealt with by higher level
** routines.
*/
static void *sqlite3MemMalloc(int nByte){
sqlite3_int64 *p;
assert( nByte>0 );
nByte = (nByte+7)&~7;
p = malloc( nByte+8 );
if( p ){
p[0] = nByte;
p++;
}
return (void *)p;
}
/*
** Like free() but works for allocations obtained from sqlite3MemMalloc()
** or sqlite3MemRealloc().
**
** For this low-level routine, we already know that pPrior!=0 since
** cases where pPrior==0 will have been intecepted and dealt with
** by higher-level routines.
*/
static void sqlite3MemFree(void *pPrior){
sqlite3_int64 *p = (sqlite3_int64*)pPrior;
assert( pPrior!=0 );
p--;
free(p);
}
/*
** Like realloc(). Resize an allocation previously obtained from
** sqlite3MemMalloc().
**
** For this low-level interface, we know that pPrior!=0. Cases where
** pPrior==0 while have been intercepted by higher-level routine and
** redirected to xMalloc. Similarly, we know that nByte>0 becauses
** cases where nByte<=0 will have been intercepted by higher-level
** routines and redirected to xFree.
*/
static void *sqlite3MemRealloc(void *pPrior, int nByte){
sqlite3_int64 *p = (sqlite3_int64*)pPrior;
assert( pPrior!=0 && nByte>0 );
nByte = (nByte+7)&~7;
p = (sqlite3_int64*)pPrior;
p--;
p = realloc(p, nByte+8 );
if( p ){
p[0] = nByte;
p++;
}
return (void*)p;
}
/*
** Report the allocated size of a prior return from xMalloc()
** or xRealloc().
*/
static int sqlite3MemSize(void *pPrior){
sqlite3_int64 *p;
if( pPrior==0 ) return 0;
p = (sqlite3_int64*)pPrior;
p--;
return (int)p[0];
}
/*
** Round up a request size to the next valid allocation size.
*/
static int sqlite3MemRoundup(int n){
return (n+7) & ~7;
}
/*
** Initialize this module.
*/
static int sqlite3MemInit(void *NotUsed){
UNUSED_PARAMETER(NotUsed);
return SQLITE_OK;
}
/*
** Deinitialize this module.
*/
static void sqlite3MemShutdown(void *NotUsed){
UNUSED_PARAMETER(NotUsed);
return;
}
/*
** This routine is the only routine in this file with external linkage.
**
** Populate the low-level memory allocation function pointers in
** sqlite3GlobalConfig.m with pointers to the routines in this file.
*/
void sqlite3MemSetDefault(void){
static const sqlite3_mem_methods defaultMethods = {
sqlite3MemMalloc,
sqlite3MemFree,
sqlite3MemRealloc,
sqlite3MemSize,
sqlite3MemRoundup,
sqlite3MemInit,
sqlite3MemShutdown,
0
};
sqlite3_config(SQLITE_CONFIG_MALLOC, &defaultMethods);
}
#endif /* SQLITE_SYSTEM_MALLOC */

440
mem2.c Normal file
View file

@ -0,0 +1,440 @@
/*
** 2007 August 15
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
**
** May you do good and not evil.
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
*************************************************************************
**
** This file contains low-level memory allocation drivers for when
** SQLite will use the standard C-library malloc/realloc/free interface
** to obtain the memory it needs while adding lots of additional debugging
** information to each allocation in order to help detect and fix memory
** leaks and memory usage errors.
**
** This file contains implementations of the low-level memory allocation
** routines specified in the sqlite3_mem_methods object.
**
** $Id: mem2.c,v 1.42 2008/12/10 19:26:24 drh Exp $
*/
#include "sqliteInt.h"
/*
** This version of the memory allocator is used only if the
** SQLITE_MEMDEBUG macro is defined
*/
#ifdef SQLITE_MEMDEBUG
/*
** The backtrace functionality is only available with GLIBC
*/
#ifdef __GLIBC__
extern int backtrace(void**,int);
extern void backtrace_symbols_fd(void*const*,int,int);
#else
# define backtrace(A,B) 1
# define backtrace_symbols_fd(A,B,C)
#endif
#include <stdio.h>
/*
** Each memory allocation looks like this:
**
** ------------------------------------------------------------------------
** | Title | backtrace pointers | MemBlockHdr | allocation | EndGuard |
** ------------------------------------------------------------------------
**
** The application code sees only a pointer to the allocation. We have
** to back up from the allocation pointer to find the MemBlockHdr. The
** MemBlockHdr tells us the size of the allocation and the number of
** backtrace pointers. There is also a guard word at the end of the
** MemBlockHdr.
*/
struct MemBlockHdr {
i64 iSize; /* Size of this allocation */
struct MemBlockHdr *pNext, *pPrev; /* Linked list of all unfreed memory */
char nBacktrace; /* Number of backtraces on this alloc */
char nBacktraceSlots; /* Available backtrace slots */
short nTitle; /* Bytes of title; includes '\0' */
int iForeGuard; /* Guard word for sanity */
};
/*
** Guard words
*/
#define FOREGUARD 0x80F5E153
#define REARGUARD 0xE4676B53
/*
** Number of malloc size increments to track.
*/
#define NCSIZE 1000
/*
** All of the static variables used by this module are collected
** into a single structure named "mem". This is to keep the
** static variables organized and to reduce namespace pollution
** when this module is combined with other in the amalgamation.
*/
static struct {
/*
** Mutex to control access to the memory allocation subsystem.
*/
sqlite3_mutex *mutex;
/*
** Head and tail of a linked list of all outstanding allocations
*/
struct MemBlockHdr *pFirst;
struct MemBlockHdr *pLast;
/*
** The number of levels of backtrace to save in new allocations.
*/
int nBacktrace;
void (*xBacktrace)(int, int, void **);
/*
** Title text to insert in front of each block
*/
int nTitle; /* Bytes of zTitle to save. Includes '\0' and padding */
char zTitle[100]; /* The title text */
/*
** sqlite3MallocDisallow() increments the following counter.
** sqlite3MallocAllow() decrements it.
*/
int disallow; /* Do not allow memory allocation */
/*
** Gather statistics on the sizes of memory allocations.
** nAlloc[i] is the number of allocation attempts of i*8
** bytes. i==NCSIZE is the number of allocation attempts for
** sizes more than NCSIZE*8 bytes.
*/
int nAlloc[NCSIZE]; /* Total number of allocations */
int nCurrent[NCSIZE]; /* Current number of allocations */
int mxCurrent[NCSIZE]; /* Highwater mark for nCurrent */
} mem;
/*
** Adjust memory usage statistics
*/
static void adjustStats(int iSize, int increment){
int i = ((iSize+7)&~7)/8;
if( i>NCSIZE-1 ){
i = NCSIZE - 1;
}
if( increment>0 ){
mem.nAlloc[i]++;
mem.nCurrent[i]++;
if( mem.nCurrent[i]>mem.mxCurrent[i] ){
mem.mxCurrent[i] = mem.nCurrent[i];
}
}else{
mem.nCurrent[i]--;
assert( mem.nCurrent[i]>=0 );
}
}
/*
** Given an allocation, find the MemBlockHdr for that allocation.
**
** This routine checks the guards at either end of the allocation and
** if they are incorrect it asserts.
*/
static struct MemBlockHdr *sqlite3MemsysGetHeader(void *pAllocation){
struct MemBlockHdr *p;
int *pInt;
u8 *pU8;
int nReserve;
p = (struct MemBlockHdr*)pAllocation;
p--;
assert( p->iForeGuard==(int)FOREGUARD );
nReserve = (p->iSize+7)&~7;
pInt = (int*)pAllocation;
pU8 = (u8*)pAllocation;
assert( pInt[nReserve/sizeof(int)]==(int)REARGUARD );
assert( (nReserve-0)<=p->iSize || pU8[nReserve-1]==0x65 );
assert( (nReserve-1)<=p->iSize || pU8[nReserve-2]==0x65 );
assert( (nReserve-2)<=p->iSize || pU8[nReserve-3]==0x65 );
return p;
}
/*
** Return the number of bytes currently allocated at address p.
*/
static int sqlite3MemSize(void *p){
struct MemBlockHdr *pHdr;
if( !p ){
return 0;
}
pHdr = sqlite3MemsysGetHeader(p);
return pHdr->iSize;
}
/*
** Initialize the memory allocation subsystem.
*/
static int sqlite3MemInit(void *NotUsed){
UNUSED_PARAMETER(NotUsed);
if( !sqlite3GlobalConfig.bMemstat ){
/* If memory status is enabled, then the malloc.c wrapper will already
** hold the STATIC_MEM mutex when the routines here are invoked. */
mem.mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MEM);
}
return SQLITE_OK;
}
/*
** Deinitialize the memory allocation subsystem.
*/
static void sqlite3MemShutdown(void *NotUsed){
UNUSED_PARAMETER(NotUsed);
mem.mutex = 0;
}
/*
** Round up a request size to the next valid allocation size.
*/
static int sqlite3MemRoundup(int n){
return (n+7) & ~7;
}
/*
** Allocate nByte bytes of memory.
*/
static void *sqlite3MemMalloc(int nByte){
struct MemBlockHdr *pHdr;
void **pBt;
char *z;
int *pInt;
void *p = 0;
int totalSize;
int nReserve;
sqlite3_mutex_enter(mem.mutex);
assert( mem.disallow==0 );
nReserve = (nByte+7)&~7;
totalSize = nReserve + sizeof(*pHdr) + sizeof(int) +
mem.nBacktrace*sizeof(void*) + mem.nTitle;
p = malloc(totalSize);
if( p ){
z = p;
pBt = (void**)&z[mem.nTitle];
pHdr = (struct MemBlockHdr*)&pBt[mem.nBacktrace];
pHdr->pNext = 0;
pHdr->pPrev = mem.pLast;
if( mem.pLast ){
mem.pLast->pNext = pHdr;
}else{
mem.pFirst = pHdr;
}
mem.pLast = pHdr;
pHdr->iForeGuard = FOREGUARD;
pHdr->nBacktraceSlots = mem.nBacktrace;
pHdr->nTitle = mem.nTitle;
if( mem.nBacktrace ){
void *aAddr[40];
pHdr->nBacktrace = backtrace(aAddr, mem.nBacktrace+1)-1;
memcpy(pBt, &aAddr[1], pHdr->nBacktrace*sizeof(void*));
if( mem.xBacktrace ){
mem.xBacktrace(nByte, pHdr->nBacktrace-1, &aAddr[1]);
}
}else{
pHdr->nBacktrace = 0;
}
if( mem.nTitle ){
memcpy(z, mem.zTitle, mem.nTitle);
}
pHdr->iSize = nByte;
adjustStats(nByte, +1);
pInt = (int*)&pHdr[1];
pInt[nReserve/sizeof(int)] = REARGUARD;
memset(pInt, 0x65, nReserve);
p = (void*)pInt;
}
sqlite3_mutex_leave(mem.mutex);
return p;
}
/*
** Free memory.
*/
static void sqlite3MemFree(void *pPrior){
struct MemBlockHdr *pHdr;
void **pBt;
char *z;
assert( sqlite3GlobalConfig.bMemstat || mem.mutex!=0 );
pHdr = sqlite3MemsysGetHeader(pPrior);
pBt = (void**)pHdr;
pBt -= pHdr->nBacktraceSlots;
sqlite3_mutex_enter(mem.mutex);
if( pHdr->pPrev ){
assert( pHdr->pPrev->pNext==pHdr );
pHdr->pPrev->pNext = pHdr->pNext;
}else{
assert( mem.pFirst==pHdr );
mem.pFirst = pHdr->pNext;
}
if( pHdr->pNext ){
assert( pHdr->pNext->pPrev==pHdr );
pHdr->pNext->pPrev = pHdr->pPrev;
}else{
assert( mem.pLast==pHdr );
mem.pLast = pHdr->pPrev;
}
z = (char*)pBt;
z -= pHdr->nTitle;
adjustStats(pHdr->iSize, -1);
memset(z, 0x2b, sizeof(void*)*pHdr->nBacktraceSlots + sizeof(*pHdr) +
pHdr->iSize + sizeof(int) + pHdr->nTitle);
free(z);
sqlite3_mutex_leave(mem.mutex);
}
/*
** Change the size of an existing memory allocation.
**
** For this debugging implementation, we *always* make a copy of the
** allocation into a new place in memory. In this way, if the
** higher level code is using pointer to the old allocation, it is
** much more likely to break and we are much more liking to find
** the error.
*/
static void *sqlite3MemRealloc(void *pPrior, int nByte){
struct MemBlockHdr *pOldHdr;
void *pNew;
assert( mem.disallow==0 );
pOldHdr = sqlite3MemsysGetHeader(pPrior);
pNew = sqlite3MemMalloc(nByte);
if( pNew ){
memcpy(pNew, pPrior, nByte<pOldHdr->iSize ? nByte : pOldHdr->iSize);
if( nByte>pOldHdr->iSize ){
memset(&((char*)pNew)[pOldHdr->iSize], 0x2b, nByte - pOldHdr->iSize);
}
sqlite3MemFree(pPrior);
}
return pNew;
}
/*
** Populate the low-level memory allocation function pointers in
** sqlite3GlobalConfig.m with pointers to the routines in this file.
*/
void sqlite3MemSetDefault(void){
static const sqlite3_mem_methods defaultMethods = {
sqlite3MemMalloc,
sqlite3MemFree,
sqlite3MemRealloc,
sqlite3MemSize,
sqlite3MemRoundup,
sqlite3MemInit,
sqlite3MemShutdown,
0
};
sqlite3_config(SQLITE_CONFIG_MALLOC, &defaultMethods);
}
/*
** Set the number of backtrace levels kept for each allocation.
** A value of zero turns off backtracing. The number is always rounded
** up to a multiple of 2.
*/
void sqlite3MemdebugBacktrace(int depth){
if( depth<0 ){ depth = 0; }
if( depth>20 ){ depth = 20; }
depth = (depth+1)&0xfe;
mem.nBacktrace = depth;
}
void sqlite3MemdebugBacktraceCallback(void (*xBacktrace)(int, int, void **)){
mem.xBacktrace = xBacktrace;
}
/*
** Set the title string for subsequent allocations.
*/
void sqlite3MemdebugSettitle(const char *zTitle){
unsigned int n = sqlite3Strlen30(zTitle) + 1;
sqlite3_mutex_enter(mem.mutex);
if( n>=sizeof(mem.zTitle) ) n = sizeof(mem.zTitle)-1;
memcpy(mem.zTitle, zTitle, n);
mem.zTitle[n] = 0;
mem.nTitle = (n+7)&~7;
sqlite3_mutex_leave(mem.mutex);
}
void sqlite3MemdebugSync(){
struct MemBlockHdr *pHdr;
for(pHdr=mem.pFirst; pHdr; pHdr=pHdr->pNext){
void **pBt = (void**)pHdr;
pBt -= pHdr->nBacktraceSlots;
mem.xBacktrace(pHdr->iSize, pHdr->nBacktrace-1, &pBt[1]);
}
}
/*
** Open the file indicated and write a log of all unfreed memory
** allocations into that log.
*/
void sqlite3MemdebugDump(const char *zFilename){
FILE *out;
struct MemBlockHdr *pHdr;
void **pBt;
int i;
out = fopen(zFilename, "w");
if( out==0 ){
fprintf(stderr, "** Unable to output memory debug output log: %s **\n",
zFilename);
return;
}
for(pHdr=mem.pFirst; pHdr; pHdr=pHdr->pNext){
char *z = (char*)pHdr;
z -= pHdr->nBacktraceSlots*sizeof(void*) + pHdr->nTitle;
fprintf(out, "**** %lld bytes at %p from %s ****\n",
pHdr->iSize, &pHdr[1], pHdr->nTitle ? z : "???");
if( pHdr->nBacktrace ){
fflush(out);
pBt = (void**)pHdr;
pBt -= pHdr->nBacktraceSlots;
backtrace_symbols_fd(pBt, pHdr->nBacktrace, fileno(out));
fprintf(out, "\n");
}
}
fprintf(out, "COUNTS:\n");
for(i=0; i<NCSIZE-1; i++){
if( mem.nAlloc[i] ){
fprintf(out, " %5d: %10d %10d %10d\n",
i*8, mem.nAlloc[i], mem.nCurrent[i], mem.mxCurrent[i]);
}
}
if( mem.nAlloc[NCSIZE-1] ){
fprintf(out, " %5d: %10d %10d %10d\n",
NCSIZE*8-8, mem.nAlloc[NCSIZE-1],
mem.nCurrent[NCSIZE-1], mem.mxCurrent[NCSIZE-1]);
}
fclose(out);
}
/*
** Return the number of times sqlite3MemMalloc() has been called.
*/
int sqlite3MemdebugMallocCount(){
int i;
int nTotal = 0;
for(i=0; i<NCSIZE; i++){
nTotal += mem.nAlloc[i];
}
return nTotal;
}
#endif /* SQLITE_MEMDEBUG */

688
mem3.c Normal file
View file

@ -0,0 +1,688 @@
/*
** 2007 October 14
**
** 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 the C functions that implement a memory
** allocation subsystem for use by SQLite.
**
** This version of the memory allocation subsystem omits all
** use of malloc(). The SQLite user supplies a block of memory
** before calling sqlite3_initialize() from which allocations
** are made and returned by the xMalloc() and xRealloc()
** implementations. Once sqlite3_initialize() has been called,
** the amount of memory available to SQLite is fixed and cannot
** be changed.
**
** This version of the memory allocation subsystem is included
** in the build only if SQLITE_ENABLE_MEMSYS3 is defined.
**
** $Id: mem3.c,v 1.25 2008/11/19 16:52:44 danielk1977 Exp $
*/
#include "sqliteInt.h"
/*
** This version of the memory allocator is only built into the library
** SQLITE_ENABLE_MEMSYS3 is defined. Defining this symbol does not
** mean that the library will use a memory-pool by default, just that
** it is available. The mempool allocator is activated by calling
** sqlite3_config().
*/
#ifdef SQLITE_ENABLE_MEMSYS3
/*
** Maximum size (in Mem3Blocks) of a "small" chunk.
*/
#define MX_SMALL 10
/*
** Number of freelist hash slots
*/
#define N_HASH 61
/*
** A memory allocation (also called a "chunk") consists of two or
** more blocks where each block is 8 bytes. The first 8 bytes are
** a header that is not returned to the user.
**
** A chunk is two or more blocks that is either checked out or
** free. The first block has format u.hdr. u.hdr.size4x is 4 times the
** size of the allocation in blocks if the allocation is free.
** The u.hdr.size4x&1 bit is true if the chunk is checked out and
** false if the chunk is on the freelist. The u.hdr.size4x&2 bit
** is true if the previous chunk is checked out and false if the
** previous chunk is free. The u.hdr.prevSize field is the size of
** the previous chunk in blocks if the previous chunk is on the
** freelist. If the previous chunk is checked out, then
** u.hdr.prevSize can be part of the data for that chunk and should
** not be read or written.
**
** We often identify a chunk by its index in mem3.aPool[]. When
** this is done, the chunk index refers to the second block of
** the chunk. In this way, the first chunk has an index of 1.
** A chunk index of 0 means "no such chunk" and is the equivalent
** of a NULL pointer.
**
** The second block of free chunks is of the form u.list. The
** two fields form a double-linked list of chunks of related sizes.
** Pointers to the head of the list are stored in mem3.aiSmall[]
** for smaller chunks and mem3.aiHash[] for larger chunks.
**
** The second block of a chunk is user data if the chunk is checked
** out. If a chunk is checked out, the user data may extend into
** the u.hdr.prevSize value of the following chunk.
*/
typedef struct Mem3Block Mem3Block;
struct Mem3Block {
union {
struct {
u32 prevSize; /* Size of previous chunk in Mem3Block elements */
u32 size4x; /* 4x the size of current chunk in Mem3Block elements */
} hdr;
struct {
u32 next; /* Index in mem3.aPool[] of next free chunk */
u32 prev; /* Index in mem3.aPool[] of previous free chunk */
} list;
} u;
};
/*
** All of the static variables used by this module are collected
** into a single structure named "mem3". This is to keep the
** static variables organized and to reduce namespace pollution
** when this module is combined with other in the amalgamation.
*/
static SQLITE_WSD struct Mem3Global {
/*
** Memory available for allocation. nPool is the size of the array
** (in Mem3Blocks) pointed to by aPool less 2.
*/
u32 nPool;
Mem3Block *aPool;
/*
** True if we are evaluating an out-of-memory callback.
*/
int alarmBusy;
/*
** Mutex to control access to the memory allocation subsystem.
*/
sqlite3_mutex *mutex;
/*
** The minimum amount of free space that we have seen.
*/
u32 mnMaster;
/*
** iMaster is the index of the master chunk. Most new allocations
** occur off of this chunk. szMaster is the size (in Mem3Blocks)
** of the current master. iMaster is 0 if there is not master chunk.
** The master chunk is not in either the aiHash[] or aiSmall[].
*/
u32 iMaster;
u32 szMaster;
/*
** Array of lists of free blocks according to the block size
** for smaller chunks, or a hash on the block size for larger
** chunks.
*/
u32 aiSmall[MX_SMALL-1]; /* For sizes 2 through MX_SMALL, inclusive */
u32 aiHash[N_HASH]; /* For sizes MX_SMALL+1 and larger */
} mem3 = { 97535575 };
#define mem3 GLOBAL(struct Mem3Global, mem3)
/*
** Unlink the chunk at mem3.aPool[i] from list it is currently
** on. *pRoot is the list that i is a member of.
*/
static void memsys3UnlinkFromList(u32 i, u32 *pRoot){
u32 next = mem3.aPool[i].u.list.next;
u32 prev = mem3.aPool[i].u.list.prev;
assert( sqlite3_mutex_held(mem3.mutex) );
if( prev==0 ){
*pRoot = next;
}else{
mem3.aPool[prev].u.list.next = next;
}
if( next ){
mem3.aPool[next].u.list.prev = prev;
}
mem3.aPool[i].u.list.next = 0;
mem3.aPool[i].u.list.prev = 0;
}
/*
** Unlink the chunk at index i from
** whatever list is currently a member of.
*/
static void memsys3Unlink(u32 i){
u32 size, hash;
assert( sqlite3_mutex_held(mem3.mutex) );
assert( (mem3.aPool[i-1].u.hdr.size4x & 1)==0 );
assert( i>=1 );
size = mem3.aPool[i-1].u.hdr.size4x/4;
assert( size==mem3.aPool[i+size-1].u.hdr.prevSize );
assert( size>=2 );
if( size <= MX_SMALL ){
memsys3UnlinkFromList(i, &mem3.aiSmall[size-2]);
}else{
hash = size % N_HASH;
memsys3UnlinkFromList(i, &mem3.aiHash[hash]);
}
}
/*
** Link the chunk at mem3.aPool[i] so that is on the list rooted
** at *pRoot.
*/
static void memsys3LinkIntoList(u32 i, u32 *pRoot){
assert( sqlite3_mutex_held(mem3.mutex) );
mem3.aPool[i].u.list.next = *pRoot;
mem3.aPool[i].u.list.prev = 0;
if( *pRoot ){
mem3.aPool[*pRoot].u.list.prev = i;
}
*pRoot = i;
}
/*
** Link the chunk at index i into either the appropriate
** small chunk list, or into the large chunk hash table.
*/
static void memsys3Link(u32 i){
u32 size, hash;
assert( sqlite3_mutex_held(mem3.mutex) );
assert( i>=1 );
assert( (mem3.aPool[i-1].u.hdr.size4x & 1)==0 );
size = mem3.aPool[i-1].u.hdr.size4x/4;
assert( size==mem3.aPool[i+size-1].u.hdr.prevSize );
assert( size>=2 );
if( size <= MX_SMALL ){
memsys3LinkIntoList(i, &mem3.aiSmall[size-2]);
}else{
hash = size % N_HASH;
memsys3LinkIntoList(i, &mem3.aiHash[hash]);
}
}
/*
** If the STATIC_MEM mutex is not already held, obtain it now. The mutex
** will already be held (obtained by code in malloc.c) if
** sqlite3GlobalConfig.bMemStat is true.
*/
static void memsys3Enter(void){
if( sqlite3GlobalConfig.bMemstat==0 && mem3.mutex==0 ){
mem3.mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MEM);
}
sqlite3_mutex_enter(mem3.mutex);
}
static void memsys3Leave(void){
sqlite3_mutex_leave(mem3.mutex);
}
/*
** Called when we are unable to satisfy an allocation of nBytes.
*/
static void memsys3OutOfMemory(int nByte){
if( !mem3.alarmBusy ){
mem3.alarmBusy = 1;
assert( sqlite3_mutex_held(mem3.mutex) );
sqlite3_mutex_leave(mem3.mutex);
sqlite3_release_memory(nByte);
sqlite3_mutex_enter(mem3.mutex);
mem3.alarmBusy = 0;
}
}
/*
** Chunk i is a free chunk that has been unlinked. Adjust its
** size parameters for check-out and return a pointer to the
** user portion of the chunk.
*/
static void *memsys3Checkout(u32 i, u32 nBlock){
u32 x;
assert( sqlite3_mutex_held(mem3.mutex) );
assert( i>=1 );
assert( mem3.aPool[i-1].u.hdr.size4x/4==nBlock );
assert( mem3.aPool[i+nBlock-1].u.hdr.prevSize==nBlock );
x = mem3.aPool[i-1].u.hdr.size4x;
mem3.aPool[i-1].u.hdr.size4x = nBlock*4 | 1 | (x&2);
mem3.aPool[i+nBlock-1].u.hdr.prevSize = nBlock;
mem3.aPool[i+nBlock-1].u.hdr.size4x |= 2;
return &mem3.aPool[i];
}
/*
** Carve a piece off of the end of the mem3.iMaster free chunk.
** Return a pointer to the new allocation. Or, if the master chunk
** is not large enough, return 0.
*/
static void *memsys3FromMaster(u32 nBlock){
assert( sqlite3_mutex_held(mem3.mutex) );
assert( mem3.szMaster>=nBlock );
if( nBlock>=mem3.szMaster-1 ){
/* Use the entire master */
void *p = memsys3Checkout(mem3.iMaster, mem3.szMaster);
mem3.iMaster = 0;
mem3.szMaster = 0;
mem3.mnMaster = 0;
return p;
}else{
/* Split the master block. Return the tail. */
u32 newi, x;
newi = mem3.iMaster + mem3.szMaster - nBlock;
assert( newi > mem3.iMaster+1 );
mem3.aPool[mem3.iMaster+mem3.szMaster-1].u.hdr.prevSize = nBlock;
mem3.aPool[mem3.iMaster+mem3.szMaster-1].u.hdr.size4x |= 2;
mem3.aPool[newi-1].u.hdr.size4x = nBlock*4 + 1;
mem3.szMaster -= nBlock;
mem3.aPool[newi-1].u.hdr.prevSize = mem3.szMaster;
x = mem3.aPool[mem3.iMaster-1].u.hdr.size4x & 2;
mem3.aPool[mem3.iMaster-1].u.hdr.size4x = mem3.szMaster*4 | x;
if( mem3.szMaster < mem3.mnMaster ){
mem3.mnMaster = mem3.szMaster;
}
return (void*)&mem3.aPool[newi];
}
}
/*
** *pRoot is the head of a list of free chunks of the same size
** or same size hash. In other words, *pRoot is an entry in either
** mem3.aiSmall[] or mem3.aiHash[].
**
** This routine examines all entries on the given list and tries
** to coalesce each entries with adjacent free chunks.
**
** If it sees a chunk that is larger than mem3.iMaster, it replaces
** the current mem3.iMaster with the new larger chunk. In order for
** this mem3.iMaster replacement to work, the master chunk must be
** linked into the hash tables. That is not the normal state of
** affairs, of course. The calling routine must link the master
** chunk before invoking this routine, then must unlink the (possibly
** changed) master chunk once this routine has finished.
*/
static void memsys3Merge(u32 *pRoot){
u32 iNext, prev, size, i, x;
assert( sqlite3_mutex_held(mem3.mutex) );
for(i=*pRoot; i>0; i=iNext){
iNext = mem3.aPool[i].u.list.next;
size = mem3.aPool[i-1].u.hdr.size4x;
assert( (size&1)==0 );
if( (size&2)==0 ){
memsys3UnlinkFromList(i, pRoot);
assert( i > mem3.aPool[i-1].u.hdr.prevSize );
prev = i - mem3.aPool[i-1].u.hdr.prevSize;
if( prev==iNext ){
iNext = mem3.aPool[prev].u.list.next;
}
memsys3Unlink(prev);
size = i + size/4 - prev;
x = mem3.aPool[prev-1].u.hdr.size4x & 2;
mem3.aPool[prev-1].u.hdr.size4x = size*4 | x;
mem3.aPool[prev+size-1].u.hdr.prevSize = size;
memsys3Link(prev);
i = prev;
}else{
size /= 4;
}
if( size>mem3.szMaster ){
mem3.iMaster = i;
mem3.szMaster = size;
}
}
}
/*
** Return a block of memory of at least nBytes in size.
** Return NULL if unable.
**
** This function assumes that the necessary mutexes, if any, are
** already held by the caller. Hence "Unsafe".
*/
static void *memsys3MallocUnsafe(int nByte){
u32 i;
u32 nBlock;
u32 toFree;
assert( sqlite3_mutex_held(mem3.mutex) );
assert( sizeof(Mem3Block)==8 );
if( nByte<=12 ){
nBlock = 2;
}else{
nBlock = (nByte + 11)/8;
}
assert( nBlock>=2 );
/* STEP 1:
** Look for an entry of the correct size in either the small
** chunk table or in the large chunk hash table. This is
** successful most of the time (about 9 times out of 10).
*/
if( nBlock <= MX_SMALL ){
i = mem3.aiSmall[nBlock-2];
if( i>0 ){
memsys3UnlinkFromList(i, &mem3.aiSmall[nBlock-2]);
return memsys3Checkout(i, nBlock);
}
}else{
int hash = nBlock % N_HASH;
for(i=mem3.aiHash[hash]; i>0; i=mem3.aPool[i].u.list.next){
if( mem3.aPool[i-1].u.hdr.size4x/4==nBlock ){
memsys3UnlinkFromList(i, &mem3.aiHash[hash]);
return memsys3Checkout(i, nBlock);
}
}
}
/* STEP 2:
** Try to satisfy the allocation by carving a piece off of the end
** of the master chunk. This step usually works if step 1 fails.
*/
if( mem3.szMaster>=nBlock ){
return memsys3FromMaster(nBlock);
}
/* STEP 3:
** Loop through the entire memory pool. Coalesce adjacent free
** chunks. Recompute the master chunk as the largest free chunk.
** Then try again to satisfy the allocation by carving a piece off
** of the end of the master chunk. This step happens very
** rarely (we hope!)
*/
for(toFree=nBlock*16; toFree<(mem3.nPool*16); toFree *= 2){
memsys3OutOfMemory(toFree);
if( mem3.iMaster ){
memsys3Link(mem3.iMaster);
mem3.iMaster = 0;
mem3.szMaster = 0;
}
for(i=0; i<N_HASH; i++){
memsys3Merge(&mem3.aiHash[i]);
}
for(i=0; i<MX_SMALL-1; i++){
memsys3Merge(&mem3.aiSmall[i]);
}
if( mem3.szMaster ){
memsys3Unlink(mem3.iMaster);
if( mem3.szMaster>=nBlock ){
return memsys3FromMaster(nBlock);
}
}
}
/* If none of the above worked, then we fail. */
return 0;
}
/*
** Free an outstanding memory allocation.
**
** This function assumes that the necessary mutexes, if any, are
** already held by the caller. Hence "Unsafe".
*/
void memsys3FreeUnsafe(void *pOld){
Mem3Block *p = (Mem3Block*)pOld;
int i;
u32 size, x;
assert( sqlite3_mutex_held(mem3.mutex) );
assert( p>mem3.aPool && p<&mem3.aPool[mem3.nPool] );
i = p - mem3.aPool;
assert( (mem3.aPool[i-1].u.hdr.size4x&1)==1 );
size = mem3.aPool[i-1].u.hdr.size4x/4;
assert( i+size<=mem3.nPool+1 );
mem3.aPool[i-1].u.hdr.size4x &= ~1;
mem3.aPool[i+size-1].u.hdr.prevSize = size;
mem3.aPool[i+size-1].u.hdr.size4x &= ~2;
memsys3Link(i);
/* Try to expand the master using the newly freed chunk */
if( mem3.iMaster ){
while( (mem3.aPool[mem3.iMaster-1].u.hdr.size4x&2)==0 ){
size = mem3.aPool[mem3.iMaster-1].u.hdr.prevSize;
mem3.iMaster -= size;
mem3.szMaster += size;
memsys3Unlink(mem3.iMaster);
x = mem3.aPool[mem3.iMaster-1].u.hdr.size4x & 2;
mem3.aPool[mem3.iMaster-1].u.hdr.size4x = mem3.szMaster*4 | x;
mem3.aPool[mem3.iMaster+mem3.szMaster-1].u.hdr.prevSize = mem3.szMaster;
}
x = mem3.aPool[mem3.iMaster-1].u.hdr.size4x & 2;
while( (mem3.aPool[mem3.iMaster+mem3.szMaster-1].u.hdr.size4x&1)==0 ){
memsys3Unlink(mem3.iMaster+mem3.szMaster);
mem3.szMaster += mem3.aPool[mem3.iMaster+mem3.szMaster-1].u.hdr.size4x/4;
mem3.aPool[mem3.iMaster-1].u.hdr.size4x = mem3.szMaster*4 | x;
mem3.aPool[mem3.iMaster+mem3.szMaster-1].u.hdr.prevSize = mem3.szMaster;
}
}
}
/*
** Return the size of an outstanding allocation, in bytes. The
** size returned omits the 8-byte header overhead. This only
** works for chunks that are currently checked out.
*/
static int memsys3Size(void *p){
Mem3Block *pBlock;
if( p==0 ) return 0;
pBlock = (Mem3Block*)p;
assert( (pBlock[-1].u.hdr.size4x&1)!=0 );
return (pBlock[-1].u.hdr.size4x&~3)*2 - 4;
}
/*
** Round up a request size to the next valid allocation size.
*/
static int memsys3Roundup(int n){
if( n<=12 ){
return 12;
}else{
return ((n+11)&~7) - 4;
}
}
/*
** Allocate nBytes of memory.
*/
static void *memsys3Malloc(int nBytes){
sqlite3_int64 *p;
assert( nBytes>0 ); /* malloc.c filters out 0 byte requests */
memsys3Enter();
p = memsys3MallocUnsafe(nBytes);
memsys3Leave();
return (void*)p;
}
/*
** Free memory.
*/
void memsys3Free(void *pPrior){
assert( pPrior );
memsys3Enter();
memsys3FreeUnsafe(pPrior);
memsys3Leave();
}
/*
** Change the size of an existing memory allocation
*/
void *memsys3Realloc(void *pPrior, int nBytes){
int nOld;
void *p;
if( pPrior==0 ){
return sqlite3_malloc(nBytes);
}
if( nBytes<=0 ){
sqlite3_free(pPrior);
return 0;
}
nOld = memsys3Size(pPrior);
if( nBytes<=nOld && nBytes>=nOld-128 ){
return pPrior;
}
memsys3Enter();
p = memsys3MallocUnsafe(nBytes);
if( p ){
if( nOld<nBytes ){
memcpy(p, pPrior, nOld);
}else{
memcpy(p, pPrior, nBytes);
}
memsys3FreeUnsafe(pPrior);
}
memsys3Leave();
return p;
}
/*
** Initialize this module.
*/
static int memsys3Init(void *NotUsed){
UNUSED_PARAMETER(NotUsed);
if( !sqlite3GlobalConfig.pHeap ){
return SQLITE_ERROR;
}
/* Store a pointer to the memory block in global structure mem3. */
assert( sizeof(Mem3Block)==8 );
mem3.aPool = (Mem3Block *)sqlite3GlobalConfig.pHeap;
mem3.nPool = (sqlite3GlobalConfig.nHeap / sizeof(Mem3Block)) - 2;
/* Initialize the master block. */
mem3.szMaster = mem3.nPool;
mem3.mnMaster = mem3.szMaster;
mem3.iMaster = 1;
mem3.aPool[0].u.hdr.size4x = (mem3.szMaster<<2) + 2;
mem3.aPool[mem3.nPool].u.hdr.prevSize = mem3.nPool;
mem3.aPool[mem3.nPool].u.hdr.size4x = 1;
return SQLITE_OK;
}
/*
** Deinitialize this module.
*/
static void memsys3Shutdown(void *NotUsed){
UNUSED_PARAMETER(NotUsed);
return;
}
/*
** Open the file indicated and write a log of all unfreed memory
** allocations into that log.
*/
void sqlite3Memsys3Dump(const char *zFilename){
#ifdef SQLITE_DEBUG
FILE *out;
u32 i, j;
u32 size;
if( zFilename==0 || zFilename[0]==0 ){
out = stdout;
}else{
out = fopen(zFilename, "w");
if( out==0 ){
fprintf(stderr, "** Unable to output memory debug output log: %s **\n",
zFilename);
return;
}
}
memsys3Enter();
fprintf(out, "CHUNKS:\n");
for(i=1; i<=mem3.nPool; i+=size/4){
size = mem3.aPool[i-1].u.hdr.size4x;
if( size/4<=1 ){
fprintf(out, "%p size error\n", &mem3.aPool[i]);
assert( 0 );
break;
}
if( (size&1)==0 && mem3.aPool[i+size/4-1].u.hdr.prevSize!=size/4 ){
fprintf(out, "%p tail size does not match\n", &mem3.aPool[i]);
assert( 0 );
break;
}
if( ((mem3.aPool[i+size/4-1].u.hdr.size4x&2)>>1)!=(size&1) ){
fprintf(out, "%p tail checkout bit is incorrect\n", &mem3.aPool[i]);
assert( 0 );
break;
}
if( size&1 ){
fprintf(out, "%p %6d bytes checked out\n", &mem3.aPool[i], (size/4)*8-8);
}else{
fprintf(out, "%p %6d bytes free%s\n", &mem3.aPool[i], (size/4)*8-8,
i==mem3.iMaster ? " **master**" : "");
}
}
for(i=0; i<MX_SMALL-1; i++){
if( mem3.aiSmall[i]==0 ) continue;
fprintf(out, "small(%2d):", i);
for(j = mem3.aiSmall[i]; j>0; j=mem3.aPool[j].u.list.next){
fprintf(out, " %p(%d)", &mem3.aPool[j],
(mem3.aPool[j-1].u.hdr.size4x/4)*8-8);
}
fprintf(out, "\n");
}
for(i=0; i<N_HASH; i++){
if( mem3.aiHash[i]==0 ) continue;
fprintf(out, "hash(%2d):", i);
for(j = mem3.aiHash[i]; j>0; j=mem3.aPool[j].u.list.next){
fprintf(out, " %p(%d)", &mem3.aPool[j],
(mem3.aPool[j-1].u.hdr.size4x/4)*8-8);
}
fprintf(out, "\n");
}
fprintf(out, "master=%d\n", mem3.iMaster);
fprintf(out, "nowUsed=%d\n", mem3.nPool*8 - mem3.szMaster*8);
fprintf(out, "mxUsed=%d\n", mem3.nPool*8 - mem3.mnMaster*8);
sqlite3_mutex_leave(mem3.mutex);
if( out==stdout ){
fflush(stdout);
}else{
fclose(out);
}
#else
UNUSED_PARAMETER(zFilename);
#endif
}
/*
** This routine is the only routine in this file with external
** linkage.
**
** Populate the low-level memory allocation function pointers in
** sqlite3GlobalConfig.m with pointers to the routines in this file. The
** arguments specify the block of memory to manage.
**
** This routine is only called by sqlite3_config(), and therefore
** is not required to be threadsafe (it is not).
*/
const sqlite3_mem_methods *sqlite3MemGetMemsys3(void){
static const sqlite3_mem_methods mempoolMethods = {
memsys3Malloc,
memsys3Free,
memsys3Realloc,
memsys3Size,
memsys3Roundup,
memsys3Init,
memsys3Shutdown,
0
};
return &mempoolMethods;
}
#endif /* SQLITE_ENABLE_MEMSYS3 */

488
mem5.c Normal file
View file

@ -0,0 +1,488 @@
/*
** 2007 October 14
**
** 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 the C functions that implement a memory
** allocation subsystem for use by SQLite.
**
** This version of the memory allocation subsystem omits all
** use of malloc(). The SQLite user supplies a block of memory
** before calling sqlite3_initialize() from which allocations
** are made and returned by the xMalloc() and xRealloc()
** implementations. Once sqlite3_initialize() has been called,
** the amount of memory available to SQLite is fixed and cannot
** be changed.
**
** This version of the memory allocation subsystem is included
** in the build only if SQLITE_ENABLE_MEMSYS5 is defined.
**
** $Id: mem5.c,v 1.19 2008/11/19 16:52:44 danielk1977 Exp $
*/
#include "sqliteInt.h"
/*
** This version of the memory allocator is used only when
** SQLITE_ENABLE_MEMSYS5 is defined.
*/
#ifdef SQLITE_ENABLE_MEMSYS5
/*
** A minimum allocation is an instance of the following structure.
** Larger allocations are an array of these structures where the
** size of the array is a power of 2.
*/
typedef struct Mem5Link Mem5Link;
struct Mem5Link {
int next; /* Index of next free chunk */
int prev; /* Index of previous free chunk */
};
/*
** Maximum size of any allocation is ((1<<LOGMAX)*mem5.nAtom). Since
** mem5.nAtom is always at least 8, this is not really a practical
** limitation.
*/
#define LOGMAX 30
/*
** Masks used for mem5.aCtrl[] elements.
*/
#define CTRL_LOGSIZE 0x1f /* Log2 Size of this block relative to POW2_MIN */
#define CTRL_FREE 0x20 /* True if not checked out */
/*
** All of the static variables used by this module are collected
** into a single structure named "mem5". This is to keep the
** static variables organized and to reduce namespace pollution
** when this module is combined with other in the amalgamation.
*/
static SQLITE_WSD struct Mem5Global {
/*
** Memory available for allocation
*/
int nAtom; /* Smallest possible allocation in bytes */
int nBlock; /* Number of nAtom sized blocks in zPool */
u8 *zPool;
/*
** Mutex to control access to the memory allocation subsystem.
*/
sqlite3_mutex *mutex;
/*
** Performance statistics
*/
u64 nAlloc; /* Total number of calls to malloc */
u64 totalAlloc; /* Total of all malloc calls - includes internal frag */
u64 totalExcess; /* Total internal fragmentation */
u32 currentOut; /* Current checkout, including internal fragmentation */
u32 currentCount; /* Current number of distinct checkouts */
u32 maxOut; /* Maximum instantaneous currentOut */
u32 maxCount; /* Maximum instantaneous currentCount */
u32 maxRequest; /* Largest allocation (exclusive of internal frag) */
/*
** Lists of free blocks of various sizes.
*/
int aiFreelist[LOGMAX+1];
/*
** Space for tracking which blocks are checked out and the size
** of each block. One byte per block.
*/
u8 *aCtrl;
} mem5 = { 19804167 };
#define mem5 GLOBAL(struct Mem5Global, mem5)
#define MEM5LINK(idx) ((Mem5Link *)(&mem5.zPool[(idx)*mem5.nAtom]))
/*
** Unlink the chunk at mem5.aPool[i] from list it is currently
** on. It should be found on mem5.aiFreelist[iLogsize].
*/
static void memsys5Unlink(int i, int iLogsize){
int next, prev;
assert( i>=0 && i<mem5.nBlock );
assert( iLogsize>=0 && iLogsize<=LOGMAX );
assert( (mem5.aCtrl[i] & CTRL_LOGSIZE)==iLogsize );
next = MEM5LINK(i)->next;
prev = MEM5LINK(i)->prev;
if( prev<0 ){
mem5.aiFreelist[iLogsize] = next;
}else{
MEM5LINK(prev)->next = next;
}
if( next>=0 ){
MEM5LINK(next)->prev = prev;
}
}
/*
** Link the chunk at mem5.aPool[i] so that is on the iLogsize
** free list.
*/
static void memsys5Link(int i, int iLogsize){
int x;
assert( sqlite3_mutex_held(mem5.mutex) );
assert( i>=0 && i<mem5.nBlock );
assert( iLogsize>=0 && iLogsize<=LOGMAX );
assert( (mem5.aCtrl[i] & CTRL_LOGSIZE)==iLogsize );
x = MEM5LINK(i)->next = mem5.aiFreelist[iLogsize];
MEM5LINK(i)->prev = -1;
if( x>=0 ){
assert( x<mem5.nBlock );
MEM5LINK(x)->prev = i;
}
mem5.aiFreelist[iLogsize] = i;
}
/*
** If the STATIC_MEM mutex is not already held, obtain it now. The mutex
** will already be held (obtained by code in malloc.c) if
** sqlite3GlobalConfig.bMemStat is true.
*/
static void memsys5Enter(void){
if( sqlite3GlobalConfig.bMemstat==0 && mem5.mutex==0 ){
mem5.mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MEM);
}
sqlite3_mutex_enter(mem5.mutex);
}
static void memsys5Leave(void){
sqlite3_mutex_leave(mem5.mutex);
}
/*
** Return the size of an outstanding allocation, in bytes. The
** size returned omits the 8-byte header overhead. This only
** works for chunks that are currently checked out.
*/
static int memsys5Size(void *p){
int iSize = 0;
if( p ){
int i = ((u8 *)p-mem5.zPool)/mem5.nAtom;
assert( i>=0 && i<mem5.nBlock );
iSize = mem5.nAtom * (1 << (mem5.aCtrl[i]&CTRL_LOGSIZE));
}
return iSize;
}
/*
** Find the first entry on the freelist iLogsize. Unlink that
** entry and return its index.
*/
static int memsys5UnlinkFirst(int iLogsize){
int i;
int iFirst;
assert( iLogsize>=0 && iLogsize<=LOGMAX );
i = iFirst = mem5.aiFreelist[iLogsize];
assert( iFirst>=0 );
while( i>0 ){
if( i<iFirst ) iFirst = i;
i = MEM5LINK(i)->next;
}
memsys5Unlink(iFirst, iLogsize);
return iFirst;
}
/*
** Return a block of memory of at least nBytes in size.
** Return NULL if unable.
*/
static void *memsys5MallocUnsafe(int nByte){
int i; /* Index of a mem5.aPool[] slot */
int iBin; /* Index into mem5.aiFreelist[] */
int iFullSz; /* Size of allocation rounded up to power of 2 */
int iLogsize; /* Log2 of iFullSz/POW2_MIN */
/* Keep track of the maximum allocation request. Even unfulfilled
** requests are counted */
if( (u32)nByte>mem5.maxRequest ){
mem5.maxRequest = nByte;
}
/* Round nByte up to the next valid power of two */
for(iFullSz=mem5.nAtom, iLogsize=0; iFullSz<nByte; iFullSz *= 2, iLogsize++){}
/* Make sure mem5.aiFreelist[iLogsize] contains at least one free
** block. If not, then split a block of the next larger power of
** two in order to create a new free block of size iLogsize.
*/
for(iBin=iLogsize; mem5.aiFreelist[iBin]<0 && iBin<=LOGMAX; iBin++){}
if( iBin>LOGMAX ) return 0;
i = memsys5UnlinkFirst(iBin);
while( iBin>iLogsize ){
int newSize;
iBin--;
newSize = 1 << iBin;
mem5.aCtrl[i+newSize] = CTRL_FREE | iBin;
memsys5Link(i+newSize, iBin);
}
mem5.aCtrl[i] = iLogsize;
/* Update allocator performance statistics. */
mem5.nAlloc++;
mem5.totalAlloc += iFullSz;
mem5.totalExcess += iFullSz - nByte;
mem5.currentCount++;
mem5.currentOut += iFullSz;
if( mem5.maxCount<mem5.currentCount ) mem5.maxCount = mem5.currentCount;
if( mem5.maxOut<mem5.currentOut ) mem5.maxOut = mem5.currentOut;
/* Return a pointer to the allocated memory. */
return (void*)&mem5.zPool[i*mem5.nAtom];
}
/*
** Free an outstanding memory allocation.
*/
static void memsys5FreeUnsafe(void *pOld){
u32 size, iLogsize;
int iBlock;
/* Set iBlock to the index of the block pointed to by pOld in
** the array of mem5.nAtom byte blocks pointed to by mem5.zPool.
*/
iBlock = ((u8 *)pOld-mem5.zPool)/mem5.nAtom;
/* Check that the pointer pOld points to a valid, non-free block. */
assert( iBlock>=0 && iBlock<mem5.nBlock );
assert( ((u8 *)pOld-mem5.zPool)%mem5.nAtom==0 );
assert( (mem5.aCtrl[iBlock] & CTRL_FREE)==0 );
iLogsize = mem5.aCtrl[iBlock] & CTRL_LOGSIZE;
size = 1<<iLogsize;
assert( iBlock+size-1<(u32)mem5.nBlock );
mem5.aCtrl[iBlock] |= CTRL_FREE;
mem5.aCtrl[iBlock+size-1] |= CTRL_FREE;
assert( mem5.currentCount>0 );
assert( mem5.currentOut>=(size*mem5.nAtom) );
mem5.currentCount--;
mem5.currentOut -= size*mem5.nAtom;
assert( mem5.currentOut>0 || mem5.currentCount==0 );
assert( mem5.currentCount>0 || mem5.currentOut==0 );
mem5.aCtrl[iBlock] = CTRL_FREE | iLogsize;
while( iLogsize<LOGMAX ){
int iBuddy;
if( (iBlock>>iLogsize) & 1 ){
iBuddy = iBlock - size;
}else{
iBuddy = iBlock + size;
}
assert( iBuddy>=0 );
if( (iBuddy+(1<<iLogsize))>mem5.nBlock ) break;
if( mem5.aCtrl[iBuddy]!=(CTRL_FREE | iLogsize) ) break;
memsys5Unlink(iBuddy, iLogsize);
iLogsize++;
if( iBuddy<iBlock ){
mem5.aCtrl[iBuddy] = CTRL_FREE | iLogsize;
mem5.aCtrl[iBlock] = 0;
iBlock = iBuddy;
}else{
mem5.aCtrl[iBlock] = CTRL_FREE | iLogsize;
mem5.aCtrl[iBuddy] = 0;
}
size *= 2;
}
memsys5Link(iBlock, iLogsize);
}
/*
** Allocate nBytes of memory
*/
static void *memsys5Malloc(int nBytes){
sqlite3_int64 *p = 0;
if( nBytes>0 ){
memsys5Enter();
p = memsys5MallocUnsafe(nBytes);
memsys5Leave();
}
return (void*)p;
}
/*
** Free memory.
*/
static void memsys5Free(void *pPrior){
if( pPrior==0 ){
assert(0);
return;
}
memsys5Enter();
memsys5FreeUnsafe(pPrior);
memsys5Leave();
}
/*
** Change the size of an existing memory allocation
*/
static void *memsys5Realloc(void *pPrior, int nBytes){
int nOld;
void *p;
if( pPrior==0 ){
return memsys5Malloc(nBytes);
}
if( nBytes<=0 ){
memsys5Free(pPrior);
return 0;
}
nOld = memsys5Size(pPrior);
if( nBytes<=nOld ){
return pPrior;
}
memsys5Enter();
p = memsys5MallocUnsafe(nBytes);
if( p ){
memcpy(p, pPrior, nOld);
memsys5FreeUnsafe(pPrior);
}
memsys5Leave();
return p;
}
/*
** Round up a request size to the next valid allocation size.
*/
static int memsys5Roundup(int n){
int iFullSz;
for(iFullSz=mem5.nAtom; iFullSz<n; iFullSz *= 2);
return iFullSz;
}
static int memsys5Log(int iValue){
int iLog;
for(iLog=0; (1<<iLog)<iValue; iLog++);
return iLog;
}
/*
** Initialize this module.
*/
static int memsys5Init(void *NotUsed){
int ii;
int nByte = sqlite3GlobalConfig.nHeap;
u8 *zByte = (u8 *)sqlite3GlobalConfig.pHeap;
int nMinLog; /* Log of minimum allocation size in bytes*/
int iOffset;
UNUSED_PARAMETER(NotUsed);
if( !zByte ){
return SQLITE_ERROR;
}
nMinLog = memsys5Log(sqlite3GlobalConfig.mnReq);
mem5.nAtom = (1<<nMinLog);
while( (int)sizeof(Mem5Link)>mem5.nAtom ){
mem5.nAtom = mem5.nAtom << 1;
}
mem5.nBlock = (nByte / (mem5.nAtom+sizeof(u8)));
mem5.zPool = zByte;
mem5.aCtrl = (u8 *)&mem5.zPool[mem5.nBlock*mem5.nAtom];
for(ii=0; ii<=LOGMAX; ii++){
mem5.aiFreelist[ii] = -1;
}
iOffset = 0;
for(ii=LOGMAX; ii>=0; ii--){
int nAlloc = (1<<ii);
if( (iOffset+nAlloc)<=mem5.nBlock ){
mem5.aCtrl[iOffset] = ii | CTRL_FREE;
memsys5Link(iOffset, ii);
iOffset += nAlloc;
}
assert((iOffset+nAlloc)>mem5.nBlock);
}
return SQLITE_OK;
}
/*
** Deinitialize this module.
*/
static void memsys5Shutdown(void *NotUsed){
UNUSED_PARAMETER(NotUsed);
return;
}
/*
** Open the file indicated and write a log of all unfreed memory
** allocations into that log.
*/
void sqlite3Memsys5Dump(const char *zFilename){
#ifdef SQLITE_DEBUG
FILE *out;
int i, j, n;
int nMinLog;
if( zFilename==0 || zFilename[0]==0 ){
out = stdout;
}else{
out = fopen(zFilename, "w");
if( out==0 ){
fprintf(stderr, "** Unable to output memory debug output log: %s **\n",
zFilename);
return;
}
}
memsys5Enter();
nMinLog = memsys5Log(mem5.nAtom);
for(i=0; i<=LOGMAX && i+nMinLog<32; i++){
for(n=0, j=mem5.aiFreelist[i]; j>=0; j = MEM5LINK(j)->next, n++){}
fprintf(out, "freelist items of size %d: %d\n", mem5.nAtom << i, n);
}
fprintf(out, "mem5.nAlloc = %llu\n", mem5.nAlloc);
fprintf(out, "mem5.totalAlloc = %llu\n", mem5.totalAlloc);
fprintf(out, "mem5.totalExcess = %llu\n", mem5.totalExcess);
fprintf(out, "mem5.currentOut = %u\n", mem5.currentOut);
fprintf(out, "mem5.currentCount = %u\n", mem5.currentCount);
fprintf(out, "mem5.maxOut = %u\n", mem5.maxOut);
fprintf(out, "mem5.maxCount = %u\n", mem5.maxCount);
fprintf(out, "mem5.maxRequest = %u\n", mem5.maxRequest);
memsys5Leave();
if( out==stdout ){
fflush(stdout);
}else{
fclose(out);
}
#else
UNUSED_PARAMETER(zFilename);
#endif
}
/*
** This routine is the only routine in this file with external
** linkage. It returns a pointer to a static sqlite3_mem_methods
** struct populated with the memsys5 methods.
*/
const sqlite3_mem_methods *sqlite3MemGetMemsys5(void){
static const sqlite3_mem_methods memsys5Methods = {
memsys5Malloc,
memsys5Free,
memsys5Realloc,
memsys5Size,
memsys5Roundup,
memsys5Init,
memsys5Shutdown,
0
};
return &memsys5Methods;
}
#endif /* SQLITE_ENABLE_MEMSYS5 */

245
memjournal.c Normal file
View file

@ -0,0 +1,245 @@
/*
** 2008 October 7
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
**
** May you do good and not evil.
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
*************************************************************************
**
** This file contains code use to implement an in-memory rollback journal.
** The in-memory rollback journal is used to journal transactions for
** ":memory:" databases and when the journal_mode=MEMORY pragma is used.
**
** @(#) $Id: memjournal.c,v 1.8 2008/12/20 02:14:40 drh Exp $
*/
#include "sqliteInt.h"
/* Forward references to internal structures */
typedef struct MemJournal MemJournal;
typedef struct FilePoint FilePoint;
typedef struct FileChunk FileChunk;
/* Space to hold the rollback journal is allocated in increments of
** this many bytes.
*/
#define JOURNAL_CHUNKSIZE 1024
/* Macro to find the minimum of two numeric values.
*/
#ifndef MIN
# define MIN(x,y) ((x)<(y)?(x):(y))
#endif
/*
** The rollback journal is composed of a linked list of these structures.
*/
struct FileChunk {
FileChunk *pNext; /* Next chunk in the journal */
u8 zChunk[JOURNAL_CHUNKSIZE]; /* Content of this chunk */
};
/*
** An instance of this object serves as a cursor into the rollback journal.
** The cursor can be either for reading or writing.
*/
struct FilePoint {
sqlite3_int64 iOffset; /* Offset from the beginning of the file */
FileChunk *pChunk; /* Specific chunk into which cursor points */
};
/*
** This subclass is a subclass of sqlite3_file. Each open memory-journal
** is an instance of this class.
*/
struct MemJournal {
sqlite3_io_methods *pMethod; /* Parent class. MUST BE FIRST */
FileChunk *pFirst; /* Head of in-memory chunk-list */
FilePoint endpoint; /* Pointer to the end of the file */
FilePoint readpoint; /* Pointer to the end of the last xRead() */
};
/*
** Read data from the file.
*/
static int memjrnlRead(
sqlite3_file *pJfd, /* The journal file from which to read */
void *zBuf, /* Put the results here */
int iAmt, /* Number of bytes to read */
sqlite_int64 iOfst /* Begin reading at this offset */
){
MemJournal *p = (MemJournal *)pJfd;
u8 *zOut = zBuf;
int nRead = iAmt;
int iChunkOffset;
FileChunk *pChunk;
assert( iOfst+iAmt<=p->endpoint.iOffset );
if( p->readpoint.iOffset!=iOfst || iOfst==0 ){
sqlite3_int64 iOff = 0;
for(pChunk=p->pFirst;
pChunk && (iOff+JOURNAL_CHUNKSIZE)<=iOfst;
pChunk=pChunk->pNext
){
iOff += JOURNAL_CHUNKSIZE;
}
}else{
pChunk = p->readpoint.pChunk;
}
iChunkOffset = (int)(iOfst%JOURNAL_CHUNKSIZE);
do {
int iSpace = JOURNAL_CHUNKSIZE - iChunkOffset;
int nCopy = MIN(nRead, (JOURNAL_CHUNKSIZE - iChunkOffset));
memcpy(zOut, &pChunk->zChunk[iChunkOffset], nCopy);
zOut += nCopy;
nRead -= iSpace;
iChunkOffset = 0;
} while( nRead>=0 && (pChunk=pChunk->pNext)!=0 && nRead>0 );
p->readpoint.iOffset = iOfst+iAmt;
p->readpoint.pChunk = pChunk;
return SQLITE_OK;
}
/*
** Write data to the file.
*/
static int memjrnlWrite(
sqlite3_file *pJfd, /* The journal file into which to write */
const void *zBuf, /* Take data to be written from here */
int iAmt, /* Number of bytes to write */
sqlite_int64 iOfst /* Begin writing at this offset into the file */
){
MemJournal *p = (MemJournal *)pJfd;
int nWrite = iAmt;
u8 *zWrite = (u8 *)zBuf;
/* An in-memory journal file should only ever be appended to. Random
** access writes are not required by sqlite.
*/
assert(iOfst==p->endpoint.iOffset);
UNUSED_PARAMETER(iOfst);
while( nWrite>0 ){
FileChunk *pChunk = p->endpoint.pChunk;
int iChunkOffset = (int)(p->endpoint.iOffset%JOURNAL_CHUNKSIZE);
int iSpace = MIN(nWrite, JOURNAL_CHUNKSIZE - iChunkOffset);
if( iChunkOffset==0 ){
/* New chunk is required to extend the file. */
FileChunk *pNew = sqlite3_malloc(sizeof(FileChunk));
if( !pNew ){
return SQLITE_IOERR_NOMEM;
}
pNew->pNext = 0;
if( pChunk ){
assert( p->pFirst );
pChunk->pNext = pNew;
}else{
assert( !p->pFirst );
p->pFirst = pNew;
}
p->endpoint.pChunk = pNew;
}
memcpy(&p->endpoint.pChunk->zChunk[iChunkOffset], zWrite, iSpace);
zWrite += iSpace;
nWrite -= iSpace;
p->endpoint.iOffset += iSpace;
}
return SQLITE_OK;
}
/*
** Truncate the file.
*/
static int memjrnlTruncate(sqlite3_file *pJfd, sqlite_int64 size){
MemJournal *p = (MemJournal *)pJfd;
FileChunk *pChunk;
assert(size==0);
UNUSED_PARAMETER(size);
pChunk = p->pFirst;
while( pChunk ){
FileChunk *pTmp = pChunk;
pChunk = pChunk->pNext;
sqlite3_free(pTmp);
}
sqlite3MemJournalOpen(pJfd);
return SQLITE_OK;
}
/*
** Close the file.
*/
static int memjrnlClose(sqlite3_file *pJfd){
memjrnlTruncate(pJfd, 0);
return SQLITE_OK;
}
/*
** Sync the file.
*/
static int memjrnlSync(sqlite3_file *NotUsed, int NotUsed2){
UNUSED_PARAMETER2(NotUsed, NotUsed2);
return SQLITE_OK;
}
/*
** Query the size of the file in bytes.
*/
static int memjrnlFileSize(sqlite3_file *pJfd, sqlite_int64 *pSize){
MemJournal *p = (MemJournal *)pJfd;
*pSize = (sqlite_int64) p->endpoint.iOffset;
return SQLITE_OK;
}
/*
** Table of methods for MemJournal sqlite3_file object.
*/
static struct sqlite3_io_methods MemJournalMethods = {
1, /* iVersion */
memjrnlClose, /* xClose */
memjrnlRead, /* xRead */
memjrnlWrite, /* xWrite */
memjrnlTruncate, /* xTruncate */
memjrnlSync, /* xSync */
memjrnlFileSize, /* xFileSize */
0, /* xLock */
0, /* xUnlock */
0, /* xCheckReservedLock */
0, /* xFileControl */
0, /* xSectorSize */
0 /* xDeviceCharacteristics */
};
/*
** Open a journal file.
*/
void sqlite3MemJournalOpen(sqlite3_file *pJfd){
MemJournal *p = (MemJournal *)pJfd;
memset(p, 0, sqlite3MemJournalSize());
p->pMethod = &MemJournalMethods;
}
/*
** Return true if the file-handle passed as an argument is
** an in-memory journal
*/
int sqlite3IsMemJournal(sqlite3_file *pJfd){
return pJfd->pMethods==&MemJournalMethods;
}
/*
** Return the number of bytes required to store a MemJournal that uses vfs
** pVfs to create the underlying on-disk files.
*/
int sqlite3MemJournalSize(void){
return sizeof(MemJournal);
}

147
mutex.c Normal file
View file

@ -0,0 +1,147 @@
/*
** 2007 August 14
**
** 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 the C functions that implement mutexes.
**
** This file contains code that is common across all mutex implementations.
**
** $Id: mutex.c,v 1.29 2008/10/07 15:25:48 drh Exp $
*/
#include "sqliteInt.h"
#ifndef SQLITE_MUTEX_OMIT
/*
** Initialize the mutex system.
*/
int sqlite3MutexInit(void){
int rc = SQLITE_OK;
if( sqlite3GlobalConfig.bCoreMutex ){
if( !sqlite3GlobalConfig.mutex.xMutexAlloc ){
/* If the xMutexAlloc method has not been set, then the user did not
** install a mutex implementation via sqlite3_config() prior to
** sqlite3_initialize() being called. This block copies pointers to
** the default implementation into the sqlite3GlobalConfig structure.
**
** The danger is that although sqlite3_config() is not a threadsafe
** API, sqlite3_initialize() is, and so multiple threads may be
** attempting to run this function simultaneously. To guard write
** access to the sqlite3GlobalConfig structure, the 'MASTER' static mutex
** is obtained before modifying it.
*/
sqlite3_mutex_methods *p = sqlite3DefaultMutex();
sqlite3_mutex *pMaster = 0;
rc = p->xMutexInit();
if( rc==SQLITE_OK ){
pMaster = p->xMutexAlloc(SQLITE_MUTEX_STATIC_MASTER);
assert(pMaster);
p->xMutexEnter(pMaster);
assert( sqlite3GlobalConfig.mutex.xMutexAlloc==0
|| sqlite3GlobalConfig.mutex.xMutexAlloc==p->xMutexAlloc
);
if( !sqlite3GlobalConfig.mutex.xMutexAlloc ){
sqlite3GlobalConfig.mutex = *p;
}
p->xMutexLeave(pMaster);
}
}else{
rc = sqlite3GlobalConfig.mutex.xMutexInit();
}
}
return rc;
}
/*
** Shutdown the mutex system. This call frees resources allocated by
** sqlite3MutexInit().
*/
int sqlite3MutexEnd(void){
int rc = SQLITE_OK;
rc = sqlite3GlobalConfig.mutex.xMutexEnd();
return rc;
}
/*
** Retrieve a pointer to a static mutex or allocate a new dynamic one.
*/
sqlite3_mutex *sqlite3_mutex_alloc(int id){
#ifndef SQLITE_OMIT_AUTOINIT
if( sqlite3_initialize() ) return 0;
#endif
return sqlite3GlobalConfig.mutex.xMutexAlloc(id);
}
sqlite3_mutex *sqlite3MutexAlloc(int id){
if( !sqlite3GlobalConfig.bCoreMutex ){
return 0;
}
return sqlite3GlobalConfig.mutex.xMutexAlloc(id);
}
/*
** Free a dynamic mutex.
*/
void sqlite3_mutex_free(sqlite3_mutex *p){
if( p ){
sqlite3GlobalConfig.mutex.xMutexFree(p);
}
}
/*
** Obtain the mutex p. If some other thread already has the mutex, block
** until it can be obtained.
*/
void sqlite3_mutex_enter(sqlite3_mutex *p){
if( p ){
sqlite3GlobalConfig.mutex.xMutexEnter(p);
}
}
/*
** Obtain the mutex p. If successful, return SQLITE_OK. Otherwise, if another
** thread holds the mutex and it cannot be obtained, return SQLITE_BUSY.
*/
int sqlite3_mutex_try(sqlite3_mutex *p){
int rc = SQLITE_OK;
if( p ){
return sqlite3GlobalConfig.mutex.xMutexTry(p);
}
return rc;
}
/*
** The sqlite3_mutex_leave() routine exits a mutex that was previously
** entered by the same thread. The behavior is undefined if the mutex
** is not currently entered. If a NULL pointer is passed as an argument
** this function is a no-op.
*/
void sqlite3_mutex_leave(sqlite3_mutex *p){
if( p ){
sqlite3GlobalConfig.mutex.xMutexLeave(p);
}
}
#ifndef NDEBUG
/*
** The sqlite3_mutex_held() and sqlite3_mutex_notheld() routine are
** intended for use inside assert() statements.
*/
int sqlite3_mutex_held(sqlite3_mutex *p){
return p==0 || sqlite3GlobalConfig.mutex.xMutexHeld(p);
}
int sqlite3_mutex_notheld(sqlite3_mutex *p){
return p==0 || sqlite3GlobalConfig.mutex.xMutexNotheld(p);
}
#endif
#endif /* SQLITE_OMIT_MUTEX */

73
mutex.h Normal file
View file

@ -0,0 +1,73 @@
/*
** 2007 August 28
**
** 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 the common header for all mutex implementations.
** The sqliteInt.h header #includes this file so that it is available
** to all source files. We break it out in an effort to keep the code
** better organized.
**
** NOTE: source files should *not* #include this header file directly.
** Source files should #include the sqliteInt.h file and let that file
** include this one indirectly.
**
** $Id: mutex.h,v 1.9 2008/10/07 15:25:48 drh Exp $
*/
/*
** Figure out what version of the code to use. The choices are
**
** SQLITE_MUTEX_OMIT No mutex logic. Not even stubs. The
** mutexes implemention cannot be overridden
** at start-time.
**
** SQLITE_MUTEX_NOOP For single-threaded applications. No
** mutual exclusion is provided. But this
** implementation can be overridden at
** start-time.
**
** SQLITE_MUTEX_PTHREADS For multi-threaded applications on Unix.
**
** SQLITE_MUTEX_W32 For multi-threaded applications on Win32.
**
** SQLITE_MUTEX_OS2 For multi-threaded applications on OS/2.
*/
#if !SQLITE_THREADSAFE
# define SQLITE_MUTEX_OMIT
#endif
#if SQLITE_THREADSAFE && !defined(SQLITE_MUTEX_NOOP)
# if SQLITE_OS_UNIX
# define SQLITE_MUTEX_PTHREADS
# elif SQLITE_OS_WIN
# define SQLITE_MUTEX_W32
# elif SQLITE_OS_OS2
# define SQLITE_MUTEX_OS2
# else
# define SQLITE_MUTEX_NOOP
# endif
#endif
#ifdef SQLITE_MUTEX_OMIT
/*
** If this is a no-op implementation, implement everything as macros.
*/
#define sqlite3_mutex_alloc(X) ((sqlite3_mutex*)8)
#define sqlite3_mutex_free(X)
#define sqlite3_mutex_enter(X)
#define sqlite3_mutex_try(X) SQLITE_OK
#define sqlite3_mutex_leave(X)
#define sqlite3_mutex_held(X) 1
#define sqlite3_mutex_notheld(X) 1
#define sqlite3MutexAlloc(X) ((sqlite3_mutex*)8)
#define sqlite3MutexInit() SQLITE_OK
#define sqlite3MutexEnd()
#endif /* defined(SQLITE_OMIT_MUTEX) */

186
mutex_noop.c Normal file
View file

@ -0,0 +1,186 @@
/*
** 2008 October 07
**
** 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 the C functions that implement mutexes.
**
** This implementation in this file does not provide any mutual
** exclusion and is thus suitable for use only in applications
** that use SQLite in a single thread. The routines defined
** here are place-holders. Applications can substitute working
** mutex routines at start-time using the
**
** sqlite3_config(SQLITE_CONFIG_MUTEX,...)
**
** interface.
**
** If compiled with SQLITE_DEBUG, then additional logic is inserted
** that does error checking on mutexes to make sure they are being
** called correctly.
**
** $Id: mutex_noop.c,v 1.3 2008/12/05 17:17:08 drh Exp $
*/
#include "sqliteInt.h"
#if defined(SQLITE_MUTEX_NOOP) && !defined(SQLITE_DEBUG)
/*
** Stub routines for all mutex methods.
**
** This routines provide no mutual exclusion or error checking.
*/
static int noopMutexHeld(sqlite3_mutex *p){ return 1; }
static int noopMutexNotheld(sqlite3_mutex *p){ return 1; }
static int noopMutexInit(void){ return SQLITE_OK; }
static int noopMutexEnd(void){ return SQLITE_OK; }
static sqlite3_mutex *noopMutexAlloc(int id){ return (sqlite3_mutex*)8; }
static void noopMutexFree(sqlite3_mutex *p){ return; }
static void noopMutexEnter(sqlite3_mutex *p){ return; }
static int noopMutexTry(sqlite3_mutex *p){ return SQLITE_OK; }
static void noopMutexLeave(sqlite3_mutex *p){ return; }
sqlite3_mutex_methods *sqlite3DefaultMutex(void){
static sqlite3_mutex_methods sMutex = {
noopMutexInit,
noopMutexEnd,
noopMutexAlloc,
noopMutexFree,
noopMutexEnter,
noopMutexTry,
noopMutexLeave,
noopMutexHeld,
noopMutexNotheld
};
return &sMutex;
}
#endif /* defined(SQLITE_MUTEX_NOOP) && !defined(SQLITE_DEBUG) */
#if defined(SQLITE_MUTEX_NOOP) && defined(SQLITE_DEBUG)
/*
** In this implementation, error checking is provided for testing
** and debugging purposes. The mutexes still do not provide any
** mutual exclusion.
*/
/*
** The mutex object
*/
struct sqlite3_mutex {
int id; /* The mutex type */
int cnt; /* Number of entries without a matching leave */
};
/*
** The sqlite3_mutex_held() and sqlite3_mutex_notheld() routine are
** intended for use inside assert() statements.
*/
static int debugMutexHeld(sqlite3_mutex *p){
return p==0 || p->cnt>0;
}
static int debugMutexNotheld(sqlite3_mutex *p){
return p==0 || p->cnt==0;
}
/*
** Initialize and deinitialize the mutex subsystem.
*/
static int debugMutexInit(void){ return SQLITE_OK; }
static int debugMutexEnd(void){ return SQLITE_OK; }
/*
** The sqlite3_mutex_alloc() routine allocates a new
** mutex and returns a pointer to it. If it returns NULL
** that means that a mutex could not be allocated.
*/
static sqlite3_mutex *debugMutexAlloc(int id){
static sqlite3_mutex aStatic[6];
sqlite3_mutex *pNew = 0;
switch( id ){
case SQLITE_MUTEX_FAST:
case SQLITE_MUTEX_RECURSIVE: {
pNew = sqlite3Malloc(sizeof(*pNew));
if( pNew ){
pNew->id = id;
pNew->cnt = 0;
}
break;
}
default: {
assert( id-2 >= 0 );
assert( id-2 < (int)(sizeof(aStatic)/sizeof(aStatic[0])) );
pNew = &aStatic[id-2];
pNew->id = id;
break;
}
}
return pNew;
}
/*
** This routine deallocates a previously allocated mutex.
*/
static void debugMutexFree(sqlite3_mutex *p){
assert( p->cnt==0 );
assert( p->id==SQLITE_MUTEX_FAST || p->id==SQLITE_MUTEX_RECURSIVE );
sqlite3_free(p);
}
/*
** The sqlite3_mutex_enter() and sqlite3_mutex_try() routines attempt
** to enter a mutex. If another thread is already within the mutex,
** sqlite3_mutex_enter() will block and sqlite3_mutex_try() will return
** SQLITE_BUSY. The sqlite3_mutex_try() interface returns SQLITE_OK
** upon successful entry. Mutexes created using SQLITE_MUTEX_RECURSIVE can
** be entered multiple times by the same thread. In such cases the,
** mutex must be exited an equal number of times before another thread
** can enter. If the same thread tries to enter any other kind of mutex
** more than once, the behavior is undefined.
*/
static void debugMutexEnter(sqlite3_mutex *p){
assert( p->id==SQLITE_MUTEX_RECURSIVE || debugMutexNotheld(p) );
p->cnt++;
}
static int debugMutexTry(sqlite3_mutex *p){
assert( p->id==SQLITE_MUTEX_RECURSIVE || debugMutexNotheld(p) );
p->cnt++;
return SQLITE_OK;
}
/*
** The sqlite3_mutex_leave() routine exits a mutex that was
** previously entered by the same thread. The behavior
** is undefined if the mutex is not currently entered or
** is not currently allocated. SQLite will never do either.
*/
static void debugMutexLeave(sqlite3_mutex *p){
assert( debugMutexHeld(p) );
p->cnt--;
assert( p->id==SQLITE_MUTEX_RECURSIVE || debugMutexNotheld(p) );
}
sqlite3_mutex_methods *sqlite3DefaultMutex(void){
static sqlite3_mutex_methods sMutex = {
debugMutexInit,
debugMutexEnd,
debugMutexAlloc,
debugMutexFree,
debugMutexEnter,
debugMutexTry,
debugMutexLeave,
debugMutexHeld,
debugMutexNotheld
};
return &sMutex;
}
#endif /* defined(SQLITE_MUTEX_NOOP) && defined(SQLITE_DEBUG) */

273
mutex_os2.c Normal file
View file

@ -0,0 +1,273 @@
/*
** 2007 August 28
**
** 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 the C functions that implement mutexes for OS/2
**
** $Id: mutex_os2.c,v 1.11 2008/11/22 19:50:54 pweilbacher Exp $
*/
#include "sqliteInt.h"
/*
** The code in this file is only used if SQLITE_MUTEX_OS2 is defined.
** See the mutex.h file for details.
*/
#ifdef SQLITE_MUTEX_OS2
/********************** OS/2 Mutex Implementation **********************
**
** This implementation of mutexes is built using the OS/2 API.
*/
/*
** The mutex object
** Each recursive mutex is an instance of the following structure.
*/
struct sqlite3_mutex {
HMTX mutex; /* Mutex controlling the lock */
int id; /* Mutex type */
int nRef; /* Number of references */
TID owner; /* Thread holding this mutex */
};
#define OS2_MUTEX_INITIALIZER 0,0,0,0
/*
** Initialize and deinitialize the mutex subsystem.
*/
static int os2MutexInit(void){ return SQLITE_OK; }
static int os2MutexEnd(void){ return SQLITE_OK; }
/*
** The sqlite3_mutex_alloc() routine allocates a new
** mutex and returns a pointer to it. If it returns NULL
** that means that a mutex could not be allocated.
** SQLite will unwind its stack and return an error. The argument
** to sqlite3_mutex_alloc() is one of these integer constants:
**
** <ul>
** <li> SQLITE_MUTEX_FAST 0
** <li> SQLITE_MUTEX_RECURSIVE 1
** <li> SQLITE_MUTEX_STATIC_MASTER 2
** <li> SQLITE_MUTEX_STATIC_MEM 3
** <li> SQLITE_MUTEX_STATIC_PRNG 4
** </ul>
**
** The first two constants cause sqlite3_mutex_alloc() to create
** a new mutex. The new mutex is recursive when SQLITE_MUTEX_RECURSIVE
** is used but not necessarily so when SQLITE_MUTEX_FAST is used.
** The mutex implementation does not need to make a distinction
** between SQLITE_MUTEX_RECURSIVE and SQLITE_MUTEX_FAST if it does
** not want to. But SQLite will only request a recursive mutex in
** cases where it really needs one. If a faster non-recursive mutex
** implementation is available on the host platform, the mutex subsystem
** might return such a mutex in response to SQLITE_MUTEX_FAST.
**
** The other allowed parameters to sqlite3_mutex_alloc() each return
** a pointer to a static preexisting mutex. Three static mutexes are
** used by the current version of SQLite. Future versions of SQLite
** may add additional static mutexes. Static mutexes are for internal
** use by SQLite only. Applications that use SQLite mutexes should
** use only the dynamic mutexes returned by SQLITE_MUTEX_FAST or
** SQLITE_MUTEX_RECURSIVE.
**
** Note that if one of the dynamic mutex parameters (SQLITE_MUTEX_FAST
** or SQLITE_MUTEX_RECURSIVE) is used then sqlite3_mutex_alloc()
** returns a different mutex on every call. But for the static
** mutex types, the same mutex is returned on every call that has
** the same type number.
*/
static sqlite3_mutex *os2MutexAlloc(int iType){
sqlite3_mutex *p = NULL;
switch( iType ){
case SQLITE_MUTEX_FAST:
case SQLITE_MUTEX_RECURSIVE: {
p = sqlite3MallocZero( sizeof(*p) );
if( p ){
p->id = iType;
if( DosCreateMutexSem( 0, &p->mutex, 0, FALSE ) != NO_ERROR ){
sqlite3_free( p );
p = NULL;
}
}
break;
}
default: {
static volatile int isInit = 0;
static sqlite3_mutex staticMutexes[] = {
{ OS2_MUTEX_INITIALIZER, },
{ OS2_MUTEX_INITIALIZER, },
{ OS2_MUTEX_INITIALIZER, },
{ OS2_MUTEX_INITIALIZER, },
{ OS2_MUTEX_INITIALIZER, },
{ OS2_MUTEX_INITIALIZER, },
};
if ( !isInit ){
APIRET rc;
PTIB ptib;
PPIB ppib;
HMTX mutex;
char name[32];
DosGetInfoBlocks( &ptib, &ppib );
sqlite3_snprintf( sizeof(name), name, "\\SEM32\\SQLITE%04x",
ppib->pib_ulpid );
while( !isInit ){
mutex = 0;
rc = DosCreateMutexSem( name, &mutex, 0, FALSE);
if( rc == NO_ERROR ){
unsigned int i;
if( !isInit ){
for( i = 0; i < sizeof(staticMutexes)/sizeof(staticMutexes[0]); i++ ){
DosCreateMutexSem( 0, &staticMutexes[i].mutex, 0, FALSE );
}
isInit = 1;
}
DosCloseMutexSem( mutex );
}else if( rc == ERROR_DUPLICATE_NAME ){
DosSleep( 1 );
}else{
return p;
}
}
}
assert( iType-2 >= 0 );
assert( iType-2 < sizeof(staticMutexes)/sizeof(staticMutexes[0]) );
p = &staticMutexes[iType-2];
p->id = iType;
break;
}
}
return p;
}
/*
** This routine deallocates a previously allocated mutex.
** SQLite is careful to deallocate every mutex that it allocates.
*/
static void os2MutexFree(sqlite3_mutex *p){
if( p==0 ) return;
assert( p->nRef==0 );
assert( p->id==SQLITE_MUTEX_FAST || p->id==SQLITE_MUTEX_RECURSIVE );
DosCloseMutexSem( p->mutex );
sqlite3_free( p );
}
/*
** The sqlite3_mutex_enter() and sqlite3_mutex_try() routines attempt
** to enter a mutex. If another thread is already within the mutex,
** sqlite3_mutex_enter() will block and sqlite3_mutex_try() will return
** SQLITE_BUSY. The sqlite3_mutex_try() interface returns SQLITE_OK
** upon successful entry. Mutexes created using SQLITE_MUTEX_RECURSIVE can
** be entered multiple times by the same thread. In such cases the,
** mutex must be exited an equal number of times before another thread
** can enter. If the same thread tries to enter any other kind of mutex
** more than once, the behavior is undefined.
*/
static void os2MutexEnter(sqlite3_mutex *p){
TID tid;
PID holder1;
ULONG holder2;
if( p==0 ) return;
assert( p->id==SQLITE_MUTEX_RECURSIVE || os2MutexNotheld(p) );
DosRequestMutexSem(p->mutex, SEM_INDEFINITE_WAIT);
DosQueryMutexSem(p->mutex, &holder1, &tid, &holder2);
p->owner = tid;
p->nRef++;
}
static int os2MutexTry(sqlite3_mutex *p){
int rc;
TID tid;
PID holder1;
ULONG holder2;
if( p==0 ) return SQLITE_OK;
assert( p->id==SQLITE_MUTEX_RECURSIVE || os2MutexNotheld(p) );
if( DosRequestMutexSem(p->mutex, SEM_IMMEDIATE_RETURN) == NO_ERROR) {
DosQueryMutexSem(p->mutex, &holder1, &tid, &holder2);
p->owner = tid;
p->nRef++;
rc = SQLITE_OK;
} else {
rc = SQLITE_BUSY;
}
return rc;
}
/*
** The sqlite3_mutex_leave() routine exits a mutex that was
** previously entered by the same thread. The behavior
** is undefined if the mutex is not currently entered or
** is not currently allocated. SQLite will never do either.
*/
static void os2MutexLeave(sqlite3_mutex *p){
TID tid;
PID holder1;
ULONG holder2;
if( p==0 ) return;
assert( p->nRef>0 );
DosQueryMutexSem(p->mutex, &holder1, &tid, &holder2);
assert( p->owner==tid );
p->nRef--;
assert( p->nRef==0 || p->id==SQLITE_MUTEX_RECURSIVE );
DosReleaseMutexSem(p->mutex);
}
#ifdef SQLITE_DEBUG
/*
** The sqlite3_mutex_held() and sqlite3_mutex_notheld() routine are
** intended for use inside assert() statements.
*/
static int os2MutexHeld(sqlite3_mutex *p){
TID tid;
PID pid;
ULONG ulCount;
PTIB ptib;
if( p!=0 ) {
DosQueryMutexSem(p->mutex, &pid, &tid, &ulCount);
} else {
DosGetInfoBlocks(&ptib, NULL);
tid = ptib->tib_ptib2->tib2_ultid;
}
return p==0 || (p->nRef!=0 && p->owner==tid);
}
static int os2MutexNotheld(sqlite3_mutex *p){
TID tid;
PID pid;
ULONG ulCount;
PTIB ptib;
if( p!= 0 ) {
DosQueryMutexSem(p->mutex, &pid, &tid, &ulCount);
} else {
DosGetInfoBlocks(&ptib, NULL);
tid = ptib->tib_ptib2->tib2_ultid;
}
return p==0 || p->nRef==0 || p->owner!=tid;
}
#endif
sqlite3_mutex_methods *sqlite3DefaultMutex(void){
static sqlite3_mutex_methods sMutex = {
os2MutexInit,
os2MutexEnd,
os2MutexAlloc,
os2MutexFree,
os2MutexEnter,
os2MutexTry,
os2MutexLeave,
#ifdef SQLITE_DEBUG
os2MutexHeld,
os2MutexNotheld
#endif
};
return &sMutex;
}
#endif /* SQLITE_MUTEX_OS2 */

328
mutex_unix.c Normal file
View file

@ -0,0 +1,328 @@
/*
** 2007 August 28
**
** 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 the C functions that implement mutexes for pthreads
**
** $Id: mutex_unix.c,v 1.16 2008/12/08 18:19:18 drh Exp $
*/
#include "sqliteInt.h"
/*
** The code in this file is only used if we are compiling threadsafe
** under unix with pthreads.
**
** Note that this implementation requires a version of pthreads that
** supports recursive mutexes.
*/
#ifdef SQLITE_MUTEX_PTHREADS
#include <pthread.h>
/*
** Each recursive mutex is an instance of the following structure.
*/
struct sqlite3_mutex {
pthread_mutex_t mutex; /* Mutex controlling the lock */
int id; /* Mutex type */
int nRef; /* Number of entrances */
pthread_t owner; /* Thread that is within this mutex */
#ifdef SQLITE_DEBUG
int trace; /* True to trace changes */
#endif
};
#ifdef SQLITE_DEBUG
#define SQLITE3_MUTEX_INITIALIZER { PTHREAD_MUTEX_INITIALIZER, 0, 0, (pthread_t)0, 0 }
#else
#define SQLITE3_MUTEX_INITIALIZER { PTHREAD_MUTEX_INITIALIZER, 0, 0, (pthread_t)0 }
#endif
/*
** The sqlite3_mutex_held() and sqlite3_mutex_notheld() routine are
** intended for use only inside assert() statements. On some platforms,
** there might be race conditions that can cause these routines to
** deliver incorrect results. In particular, if pthread_equal() is
** not an atomic operation, then these routines might delivery
** incorrect results. On most platforms, pthread_equal() is a
** comparison of two integers and is therefore atomic. But we are
** told that HPUX is not such a platform. If so, then these routines
** will not always work correctly on HPUX.
**
** On those platforms where pthread_equal() is not atomic, SQLite
** should be compiled without -DSQLITE_DEBUG and with -DNDEBUG to
** make sure no assert() statements are evaluated and hence these
** routines are never called.
*/
#if !defined(NDEBUG) || defined(SQLITE_DEBUG)
static int pthreadMutexHeld(sqlite3_mutex *p){
return (p->nRef!=0 && pthread_equal(p->owner, pthread_self()));
}
static int pthreadMutexNotheld(sqlite3_mutex *p){
return p->nRef==0 || pthread_equal(p->owner, pthread_self())==0;
}
#endif
/*
** Initialize and deinitialize the mutex subsystem.
*/
static int pthreadMutexInit(void){ return SQLITE_OK; }
static int pthreadMutexEnd(void){ return SQLITE_OK; }
/*
** The sqlite3_mutex_alloc() routine allocates a new
** mutex and returns a pointer to it. If it returns NULL
** that means that a mutex could not be allocated. SQLite
** will unwind its stack and return an error. The argument
** to sqlite3_mutex_alloc() is one of these integer constants:
**
** <ul>
** <li> SQLITE_MUTEX_FAST
** <li> SQLITE_MUTEX_RECURSIVE
** <li> SQLITE_MUTEX_STATIC_MASTER
** <li> SQLITE_MUTEX_STATIC_MEM
** <li> SQLITE_MUTEX_STATIC_MEM2
** <li> SQLITE_MUTEX_STATIC_PRNG
** <li> SQLITE_MUTEX_STATIC_LRU
** </ul>
**
** The first two constants cause sqlite3_mutex_alloc() to create
** a new mutex. The new mutex is recursive when SQLITE_MUTEX_RECURSIVE
** is used but not necessarily so when SQLITE_MUTEX_FAST is used.
** The mutex implementation does not need to make a distinction
** between SQLITE_MUTEX_RECURSIVE and SQLITE_MUTEX_FAST if it does
** not want to. But SQLite will only request a recursive mutex in
** cases where it really needs one. If a faster non-recursive mutex
** implementation is available on the host platform, the mutex subsystem
** might return such a mutex in response to SQLITE_MUTEX_FAST.
**
** The other allowed parameters to sqlite3_mutex_alloc() each return
** a pointer to a static preexisting mutex. Three static mutexes are
** used by the current version of SQLite. Future versions of SQLite
** may add additional static mutexes. Static mutexes are for internal
** use by SQLite only. Applications that use SQLite mutexes should
** use only the dynamic mutexes returned by SQLITE_MUTEX_FAST or
** SQLITE_MUTEX_RECURSIVE.
**
** Note that if one of the dynamic mutex parameters (SQLITE_MUTEX_FAST
** or SQLITE_MUTEX_RECURSIVE) is used then sqlite3_mutex_alloc()
** returns a different mutex on every call. But for the static
** mutex types, the same mutex is returned on every call that has
** the same type number.
*/
static sqlite3_mutex *pthreadMutexAlloc(int iType){
static sqlite3_mutex staticMutexes[] = {
SQLITE3_MUTEX_INITIALIZER,
SQLITE3_MUTEX_INITIALIZER,
SQLITE3_MUTEX_INITIALIZER,
SQLITE3_MUTEX_INITIALIZER,
SQLITE3_MUTEX_INITIALIZER,
SQLITE3_MUTEX_INITIALIZER
};
sqlite3_mutex *p;
switch( iType ){
case SQLITE_MUTEX_RECURSIVE: {
p = sqlite3MallocZero( sizeof(*p) );
if( p ){
#ifdef SQLITE_HOMEGROWN_RECURSIVE_MUTEX
/* If recursive mutexes are not available, we will have to
** build our own. See below. */
pthread_mutex_init(&p->mutex, 0);
#else
/* Use a recursive mutex if it is available */
pthread_mutexattr_t recursiveAttr;
pthread_mutexattr_init(&recursiveAttr);
pthread_mutexattr_settype(&recursiveAttr, PTHREAD_MUTEX_RECURSIVE);
pthread_mutex_init(&p->mutex, &recursiveAttr);
pthread_mutexattr_destroy(&recursiveAttr);
#endif
p->id = iType;
}
break;
}
case SQLITE_MUTEX_FAST: {
p = sqlite3MallocZero( sizeof(*p) );
if( p ){
p->id = iType;
pthread_mutex_init(&p->mutex, 0);
}
break;
}
default: {
assert( iType-2 >= 0 );
assert( iType-2 < ArraySize(staticMutexes) );
p = &staticMutexes[iType-2];
p->id = iType;
break;
}
}
return p;
}
/*
** This routine deallocates a previously
** allocated mutex. SQLite is careful to deallocate every
** mutex that it allocates.
*/
static void pthreadMutexFree(sqlite3_mutex *p){
assert( p->nRef==0 );
assert( p->id==SQLITE_MUTEX_FAST || p->id==SQLITE_MUTEX_RECURSIVE );
pthread_mutex_destroy(&p->mutex);
sqlite3_free(p);
}
/*
** The sqlite3_mutex_enter() and sqlite3_mutex_try() routines attempt
** to enter a mutex. If another thread is already within the mutex,
** sqlite3_mutex_enter() will block and sqlite3_mutex_try() will return
** SQLITE_BUSY. The sqlite3_mutex_try() interface returns SQLITE_OK
** upon successful entry. Mutexes created using SQLITE_MUTEX_RECURSIVE can
** be entered multiple times by the same thread. In such cases the,
** mutex must be exited an equal number of times before another thread
** can enter. If the same thread tries to enter any other kind of mutex
** more than once, the behavior is undefined.
*/
static void pthreadMutexEnter(sqlite3_mutex *p){
assert( p->id==SQLITE_MUTEX_RECURSIVE || pthreadMutexNotheld(p) );
#ifdef SQLITE_HOMEGROWN_RECURSIVE_MUTEX
/* If recursive mutexes are not available, then we have to grow
** our own. This implementation assumes that pthread_equal()
** is atomic - that it cannot be deceived into thinking self
** and p->owner are equal if p->owner changes between two values
** that are not equal to self while the comparison is taking place.
** This implementation also assumes a coherent cache - that
** separate processes cannot read different values from the same
** address at the same time. If either of these two conditions
** are not met, then the mutexes will fail and problems will result.
*/
{
pthread_t self = pthread_self();
if( p->nRef>0 && pthread_equal(p->owner, self) ){
p->nRef++;
}else{
pthread_mutex_lock(&p->mutex);
assert( p->nRef==0 );
p->owner = self;
p->nRef = 1;
}
}
#else
/* Use the built-in recursive mutexes if they are available.
*/
pthread_mutex_lock(&p->mutex);
p->owner = pthread_self();
p->nRef++;
#endif
#ifdef SQLITE_DEBUG
if( p->trace ){
printf("enter mutex %p (%d) with nRef=%d\n", p, p->trace, p->nRef);
}
#endif
}
static int pthreadMutexTry(sqlite3_mutex *p){
int rc;
assert( p->id==SQLITE_MUTEX_RECURSIVE || pthreadMutexNotheld(p) );
#ifdef SQLITE_HOMEGROWN_RECURSIVE_MUTEX
/* If recursive mutexes are not available, then we have to grow
** our own. This implementation assumes that pthread_equal()
** is atomic - that it cannot be deceived into thinking self
** and p->owner are equal if p->owner changes between two values
** that are not equal to self while the comparison is taking place.
** This implementation also assumes a coherent cache - that
** separate processes cannot read different values from the same
** address at the same time. If either of these two conditions
** are not met, then the mutexes will fail and problems will result.
*/
{
pthread_t self = pthread_self();
if( p->nRef>0 && pthread_equal(p->owner, self) ){
p->nRef++;
rc = SQLITE_OK;
}else if( pthread_mutex_trylock(&p->mutex)==0 ){
assert( p->nRef==0 );
p->owner = self;
p->nRef = 1;
rc = SQLITE_OK;
}else{
rc = SQLITE_BUSY;
}
}
#else
/* Use the built-in recursive mutexes if they are available.
*/
if( pthread_mutex_trylock(&p->mutex)==0 ){
p->owner = pthread_self();
p->nRef++;
rc = SQLITE_OK;
}else{
rc = SQLITE_BUSY;
}
#endif
#ifdef SQLITE_DEBUG
if( rc==SQLITE_OK && p->trace ){
printf("enter mutex %p (%d) with nRef=%d\n", p, p->trace, p->nRef);
}
#endif
return rc;
}
/*
** The sqlite3_mutex_leave() routine exits a mutex that was
** previously entered by the same thread. The behavior
** is undefined if the mutex is not currently entered or
** is not currently allocated. SQLite will never do either.
*/
static void pthreadMutexLeave(sqlite3_mutex *p){
assert( pthreadMutexHeld(p) );
p->nRef--;
assert( p->nRef==0 || p->id==SQLITE_MUTEX_RECURSIVE );
#ifdef SQLITE_HOMEGROWN_RECURSIVE_MUTEX
if( p->nRef==0 ){
pthread_mutex_unlock(&p->mutex);
}
#else
pthread_mutex_unlock(&p->mutex);
#endif
#ifdef SQLITE_DEBUG
if( p->trace ){
printf("leave mutex %p (%d) with nRef=%d\n", p, p->trace, p->nRef);
}
#endif
}
sqlite3_mutex_methods *sqlite3DefaultMutex(void){
static sqlite3_mutex_methods sMutex = {
pthreadMutexInit,
pthreadMutexEnd,
pthreadMutexAlloc,
pthreadMutexFree,
pthreadMutexEnter,
pthreadMutexTry,
pthreadMutexLeave,
#ifdef SQLITE_DEBUG
pthreadMutexHeld,
pthreadMutexNotheld
#else
0,
0
#endif
};
return &sMutex;
}
#endif /* SQLITE_MUTEX_PTHREAD */

254
mutex_w32.c Normal file
View file

@ -0,0 +1,254 @@
/*
** 2007 August 14
**
** 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 the C functions that implement mutexes for win32
**
** $Id: mutex_w32.c,v 1.13 2008/12/08 18:19:18 drh Exp $
*/
#include "sqliteInt.h"
/*
** The code in this file is only used if we are compiling multithreaded
** on a win32 system.
*/
#ifdef SQLITE_MUTEX_W32
/*
** Each recursive mutex is an instance of the following structure.
*/
struct sqlite3_mutex {
CRITICAL_SECTION mutex; /* Mutex controlling the lock */
int id; /* Mutex type */
int nRef; /* Number of enterances */
DWORD owner; /* Thread holding this mutex */
};
/*
** Return true (non-zero) if we are running under WinNT, Win2K, WinXP,
** or WinCE. Return false (zero) for Win95, Win98, or WinME.
**
** Here is an interesting observation: Win95, Win98, and WinME lack
** the LockFileEx() API. But we can still statically link against that
** API as long as we don't call it win running Win95/98/ME. A call to
** this routine is used to determine if the host is Win95/98/ME or
** WinNT/2K/XP so that we will know whether or not we can safely call
** the LockFileEx() API.
**
** mutexIsNT() is only used for the TryEnterCriticalSection() API call,
** which is only available if your application was compiled with
** _WIN32_WINNT defined to a value >= 0x0400. Currently, the only
** call to TryEnterCriticalSection() is #ifdef'ed out, so #ifdef
** this out as well.
*/
#if 0
#if SQLITE_OS_WINCE
# define mutexIsNT() (1)
#else
static int mutexIsNT(void){
static int osType = 0;
if( osType==0 ){
OSVERSIONINFO sInfo;
sInfo.dwOSVersionInfoSize = sizeof(sInfo);
GetVersionEx(&sInfo);
osType = sInfo.dwPlatformId==VER_PLATFORM_WIN32_NT ? 2 : 1;
}
return osType==2;
}
#endif /* SQLITE_OS_WINCE */
#endif
#ifdef SQLITE_DEBUG
/*
** The sqlite3_mutex_held() and sqlite3_mutex_notheld() routine are
** intended for use only inside assert() statements.
*/
static int winMutexHeld(sqlite3_mutex *p){
return p->nRef!=0 && p->owner==GetCurrentThreadId();
}
static int winMutexNotheld(sqlite3_mutex *p){
return p->nRef==0 || p->owner!=GetCurrentThreadId();
}
#endif
/*
** Initialize and deinitialize the mutex subsystem.
*/
static int winMutexInit(void){ return SQLITE_OK; }
static int winMutexEnd(void){ return SQLITE_OK; }
/*
** The sqlite3_mutex_alloc() routine allocates a new
** mutex and returns a pointer to it. If it returns NULL
** that means that a mutex could not be allocated. SQLite
** will unwind its stack and return an error. The argument
** to sqlite3_mutex_alloc() is one of these integer constants:
**
** <ul>
** <li> SQLITE_MUTEX_FAST 0
** <li> SQLITE_MUTEX_RECURSIVE 1
** <li> SQLITE_MUTEX_STATIC_MASTER 2
** <li> SQLITE_MUTEX_STATIC_MEM 3
** <li> SQLITE_MUTEX_STATIC_PRNG 4
** </ul>
**
** The first two constants cause sqlite3_mutex_alloc() to create
** a new mutex. The new mutex is recursive when SQLITE_MUTEX_RECURSIVE
** is used but not necessarily so when SQLITE_MUTEX_FAST is used.
** The mutex implementation does not need to make a distinction
** between SQLITE_MUTEX_RECURSIVE and SQLITE_MUTEX_FAST if it does
** not want to. But SQLite will only request a recursive mutex in
** cases where it really needs one. If a faster non-recursive mutex
** implementation is available on the host platform, the mutex subsystem
** might return such a mutex in response to SQLITE_MUTEX_FAST.
**
** The other allowed parameters to sqlite3_mutex_alloc() each return
** a pointer to a static preexisting mutex. Three static mutexes are
** used by the current version of SQLite. Future versions of SQLite
** may add additional static mutexes. Static mutexes are for internal
** use by SQLite only. Applications that use SQLite mutexes should
** use only the dynamic mutexes returned by SQLITE_MUTEX_FAST or
** SQLITE_MUTEX_RECURSIVE.
**
** Note that if one of the dynamic mutex parameters (SQLITE_MUTEX_FAST
** or SQLITE_MUTEX_RECURSIVE) is used then sqlite3_mutex_alloc()
** returns a different mutex on every call. But for the static
** mutex types, the same mutex is returned on every call that has
** the same type number.
*/
static sqlite3_mutex *winMutexAlloc(int iType){
sqlite3_mutex *p;
switch( iType ){
case SQLITE_MUTEX_FAST:
case SQLITE_MUTEX_RECURSIVE: {
p = sqlite3MallocZero( sizeof(*p) );
if( p ){
p->id = iType;
InitializeCriticalSection(&p->mutex);
}
break;
}
default: {
static sqlite3_mutex staticMutexes[6];
static int isInit = 0;
while( !isInit ){
static long lock = 0;
if( InterlockedIncrement(&lock)==1 ){
int i;
for(i=0; i<sizeof(staticMutexes)/sizeof(staticMutexes[0]); i++){
InitializeCriticalSection(&staticMutexes[i].mutex);
}
isInit = 1;
}else{
Sleep(1);
}
}
assert( iType-2 >= 0 );
assert( iType-2 < sizeof(staticMutexes)/sizeof(staticMutexes[0]) );
p = &staticMutexes[iType-2];
p->id = iType;
break;
}
}
return p;
}
/*
** This routine deallocates a previously
** allocated mutex. SQLite is careful to deallocate every
** mutex that it allocates.
*/
static void winMutexFree(sqlite3_mutex *p){
assert( p );
assert( p->nRef==0 );
assert( p->id==SQLITE_MUTEX_FAST || p->id==SQLITE_MUTEX_RECURSIVE );
DeleteCriticalSection(&p->mutex);
sqlite3_free(p);
}
/*
** The sqlite3_mutex_enter() and sqlite3_mutex_try() routines attempt
** to enter a mutex. If another thread is already within the mutex,
** sqlite3_mutex_enter() will block and sqlite3_mutex_try() will return
** SQLITE_BUSY. The sqlite3_mutex_try() interface returns SQLITE_OK
** upon successful entry. Mutexes created using SQLITE_MUTEX_RECURSIVE can
** be entered multiple times by the same thread. In such cases the,
** mutex must be exited an equal number of times before another thread
** can enter. If the same thread tries to enter any other kind of mutex
** more than once, the behavior is undefined.
*/
static void winMutexEnter(sqlite3_mutex *p){
assert( p->id==SQLITE_MUTEX_RECURSIVE || winMutexNotheld(p) );
EnterCriticalSection(&p->mutex);
p->owner = GetCurrentThreadId();
p->nRef++;
}
static int winMutexTry(sqlite3_mutex *p){
int rc = SQLITE_BUSY;
assert( p->id==SQLITE_MUTEX_RECURSIVE || winMutexNotheld(p) );
/*
** The sqlite3_mutex_try() routine is very rarely used, and when it
** is used it is merely an optimization. So it is OK for it to always
** fail.
**
** The TryEnterCriticalSection() interface is only available on WinNT.
** And some windows compilers complain if you try to use it without
** first doing some #defines that prevent SQLite from building on Win98.
** For that reason, we will omit this optimization for now. See
** ticket #2685.
*/
#if 0
if( mutexIsNT() && TryEnterCriticalSection(&p->mutex) ){
p->owner = GetCurrentThreadId();
p->nRef++;
rc = SQLITE_OK;
}
#endif
return rc;
}
/*
** The sqlite3_mutex_leave() routine exits a mutex that was
** previously entered by the same thread. The behavior
** is undefined if the mutex is not currently entered or
** is not currently allocated. SQLite will never do either.
*/
static void winMutexLeave(sqlite3_mutex *p){
assert( p->nRef>0 );
assert( p->owner==GetCurrentThreadId() );
p->nRef--;
assert( p->nRef==0 || p->id==SQLITE_MUTEX_RECURSIVE );
LeaveCriticalSection(&p->mutex);
}
sqlite3_mutex_methods *sqlite3DefaultMutex(void){
static sqlite3_mutex_methods sMutex = {
winMutexInit,
winMutexEnd,
winMutexAlloc,
winMutexFree,
winMutexEnter,
winMutexTry,
winMutexLeave,
#ifdef SQLITE_DEBUG
winMutexHeld,
winMutexNotheld
#else
0,
0
#endif
};
return &sMutex;
}
#endif /* SQLITE_MUTEX_W32 */

149
opcodes.c
View file

@ -1,148 +1,9 @@
/* Automatically generated. Do not edit */ /* Automatically generated. Do not edit */
/* See the mkopcodec.awk script for details. */ /* See the mkopcodec.awk script for details. */
#if !defined(SQLITE_OMIT_EXPLAIN) || !defined(NDEBUG) || defined(VDBE_PROFILE) || defined(SQLITE_DEBUG) #if !defined(SQLITE_OMIT_EXPLAIN) || !defined(NDEBUG) || defined(VDBE_PROFILE) || defined(SQLITE_DEBUG)
const char *const sqlite3OpcodeNames[] = { "?", const char *sqlite3OpcodeName(int i){
/* 1 */ "ReadCookie", static const char *const azName[] = { "?",
/* 2 */ "AutoCommit", };
/* 3 */ "Found", return azName[i];
/* 4 */ "NullRow", }
/* 5 */ "MoveLe",
/* 6 */ "Variable",
/* 7 */ "Pull",
/* 8 */ "RealAffinity",
/* 9 */ "Sort",
/* 10 */ "IfNot",
/* 11 */ "Gosub",
/* 12 */ "NotFound",
/* 13 */ "MoveLt",
/* 14 */ "Rowid",
/* 15 */ "CreateIndex",
/* 16 */ "Not",
/* 17 */ "Push",
/* 18 */ "Explain",
/* 19 */ "Statement",
/* 20 */ "Callback",
/* 21 */ "MemLoad",
/* 22 */ "DropIndex",
/* 23 */ "Null",
/* 24 */ "Int64",
/* 25 */ "LoadAnalysis",
/* 26 */ "IdxInsert",
/* 27 */ "VUpdate",
/* 28 */ "Next",
/* 29 */ "SetNumColumns",
/* 30 */ "MemInt",
/* 31 */ "Dup",
/* 32 */ "Rewind",
/* 33 */ "Last",
/* 34 */ "MustBeInt",
/* 35 */ "MoveGe",
/* 36 */ "IncrVacuum",
/* 37 */ "String",
/* 38 */ "VFilter",
/* 39 */ "ForceInt",
/* 40 */ "Close",
/* 41 */ "AggFinal",
/* 42 */ "AbsValue",
/* 43 */ "RowData",
/* 44 */ "IdxRowid",
/* 45 */ "MoveGt",
/* 46 */ "OpenPseudo",
/* 47 */ "Halt",
/* 48 */ "MemMove",
/* 49 */ "NewRowid",
/* 50 */ "IdxLT",
/* 51 */ "Distinct",
/* 52 */ "MemMax",
/* 53 */ "Function",
/* 54 */ "IntegrityCk",
/* 55 */ "FifoWrite",
/* 56 */ "NotExists",
/* 57 */ "VDestroy",
/* 58 */ "MemStore",
/* 59 */ "IdxDelete",
/* 60 */ "Or",
/* 61 */ "And",
/* 62 */ "Vacuum",
/* 63 */ "If",
/* 64 */ "Destroy",
/* 65 */ "IsNull",
/* 66 */ "NotNull",
/* 67 */ "Ne",
/* 68 */ "Eq",
/* 69 */ "Gt",
/* 70 */ "Le",
/* 71 */ "Lt",
/* 72 */ "Ge",
/* 73 */ "AggStep",
/* 74 */ "BitAnd",
/* 75 */ "BitOr",
/* 76 */ "ShiftLeft",
/* 77 */ "ShiftRight",
/* 78 */ "Add",
/* 79 */ "Subtract",
/* 80 */ "Multiply",
/* 81 */ "Divide",
/* 82 */ "Remainder",
/* 83 */ "Concat",
/* 84 */ "Clear",
/* 85 */ "Negative",
/* 86 */ "Insert",
/* 87 */ "BitNot",
/* 88 */ "String8",
/* 89 */ "VBegin",
/* 90 */ "IdxGE",
/* 91 */ "OpenEphemeral",
/* 92 */ "IfMemZero",
/* 93 */ "VRowid",
/* 94 */ "MakeRecord",
/* 95 */ "SetCookie",
/* 96 */ "Prev",
/* 97 */ "ContextPush",
/* 98 */ "DropTrigger",
/* 99 */ "IdxGT",
/* 100 */ "MemNull",
/* 101 */ "IfMemNeg",
/* 102 */ "VColumn",
/* 103 */ "Return",
/* 104 */ "OpenWrite",
/* 105 */ "Integer",
/* 106 */ "Transaction",
/* 107 */ "CollSeq",
/* 108 */ "VRename",
/* 109 */ "Sequence",
/* 110 */ "ContextPop",
/* 111 */ "VCreate",
/* 112 */ "CreateTable",
/* 113 */ "AddImm",
/* 114 */ "DropTable",
/* 115 */ "IsUnique",
/* 116 */ "VOpen",
/* 117 */ "Noop",
/* 118 */ "RowKey",
/* 119 */ "Expire",
/* 120 */ "FifoRead",
/* 121 */ "Delete",
/* 122 */ "IfMemPos",
/* 123 */ "MemIncr",
/* 124 */ "Blob",
/* 125 */ "Real",
/* 126 */ "HexBlob",
/* 127 */ "MakeIdxRec",
/* 128 */ "Goto",
/* 129 */ "ParseSchema",
/* 130 */ "VNext",
/* 131 */ "Pop",
/* 132 */ "TableLock",
/* 133 */ "VerifyCookie",
/* 134 */ "Column",
/* 135 */ "OpenRead",
/* 136 */ "ResetCount",
/* 137 */ "NotUsed_137",
/* 138 */ "ToText",
/* 139 */ "ToBlob",
/* 140 */ "ToNumeric",
/* 141 */ "ToInt",
/* 142 */ "ToReal",
};
#endif #endif

325
opcodes.h
View file

@ -1,160 +1,181 @@
/* Automatically generated. Do not edit */ /* Automatically generated. Do not edit */
/* See the mkopcodeh.awk script for details */ /* See the mkopcodeh.awk script for details */
#define OP_ReadCookie 1 #define OP_VRowid 1
#define OP_AutoCommit 2 #define OP_VFilter 2
#define OP_Found 3 #define OP_IfNeg 3
#define OP_NullRow 4 #define OP_ContextPop 4
#define OP_Lt 71 /* same as TK_LT */ #define OP_IntegrityCk 5
#define OP_MoveLe 5 #define OP_DropTrigger 6
#define OP_Variable 6 #define OP_DropIndex 7
#define OP_Pull 7 #define OP_IdxInsert 8
#define OP_RealAffinity 8 #define OP_Delete 9
#define OP_Sort 9 #define OP_SeekLt 10
#define OP_IfNot 10 #define OP_OpenEphemeral 11
#define OP_Gosub 11 #define OP_VerifyCookie 12
#define OP_Add 78 /* same as TK_PLUS */ #define OP_Blob 13
#define OP_NotFound 12 #define OP_RowKey 14
#define OP_IsNull 65 /* same as TK_ISNULL */ #define OP_IsUnique 15
#define OP_MoveLt 13 #define OP_SetNumColumns 16
#define OP_Rowid 14 #define OP_Eq 71 /* same as TK_EQ */
#define OP_CreateIndex 15 #define OP_VUpdate 17
#define OP_Push 17 #define OP_Expire 18
#define OP_Explain 18 #define OP_NullRow 20
#define OP_Statement 19 #define OP_OpenPseudo 21
#define OP_Callback 20 #define OP_OpenWrite 22
#define OP_MemLoad 21 #define OP_OpenRead 23
#define OP_DropIndex 22 #define OP_Transaction 24
#define OP_Null 23 #define OP_AutoCommit 25
#define OP_ToInt 141 /* same as TK_TO_INT */ #define OP_Copy 26
#define OP_Int64 24 #define OP_Halt 27
#define OP_LoadAnalysis 25 #define OP_VRename 28
#define OP_IdxInsert 26 #define OP_Vacuum 29
#define OP_VUpdate 27 #define OP_RowData 30
#define OP_Next 28 #define OP_NotExists 31
#define OP_SetNumColumns 29 #define OP_SetCookie 32
#define OP_ToNumeric 140 /* same as TK_TO_NUMERIC*/ #define OP_Move 33
#define OP_Ge 72 /* same as TK_GE */ #define OP_Variable 34
#define OP_BitNot 87 /* same as TK_BITNOT */ #define OP_Pagecount 35
#define OP_MemInt 30 #define OP_VNext 36
#define OP_Dup 31 #define OP_VDestroy 37
#define OP_Rewind 32 #define OP_TableLock 38
#define OP_Multiply 80 /* same as TK_STAR */ #define OP_RowSetAdd 39
#define OP_ToReal 142 /* same as TK_TO_REAL */ #define OP_LoadAnalysis 40
#define OP_Gt 69 /* same as TK_GT */ #define OP_IdxDelete 41
#define OP_Last 33 #define OP_Sort 42
#define OP_MustBeInt 34 #define OP_ResetCount 43
#define OP_Ne 67 /* same as TK_NE */ #define OP_NotNull 69 /* same as TK_NOTNULL */
#define OP_MoveGe 35 #define OP_Ge 75 /* same as TK_GE */
#define OP_IncrVacuum 36 #define OP_Remainder 85 /* same as TK_REM */
#define OP_String 37 #define OP_Divide 84 /* same as TK_SLASH */
#define OP_VFilter 38 #define OP_Integer 44
#define OP_ForceInt 39 #define OP_Explain 45
#define OP_Close 40 #define OP_IncrVacuum 46
#define OP_AggFinal 41 #define OP_AggStep 47
#define OP_AbsValue 42 #define OP_CreateIndex 48
#define OP_RowData 43
#define OP_IdxRowid 44
#define OP_BitOr 75 /* same as TK_BITOR */
#define OP_NotNull 66 /* same as TK_NOTNULL */
#define OP_MoveGt 45
#define OP_Not 16 /* same as TK_NOT */
#define OP_OpenPseudo 46
#define OP_Halt 47
#define OP_MemMove 48
#define OP_NewRowid 49 #define OP_NewRowid 49
#define OP_Real 125 /* same as TK_FLOAT */ #define OP_And 64 /* same as TK_AND */
#define OP_IdxLT 50 #define OP_ShiftLeft 79 /* same as TK_LSHIFT */
#define OP_Distinct 51 #define OP_Real 129 /* same as TK_FLOAT */
#define OP_MemMax 52 #define OP_Return 50
#define OP_Function 53 #define OP_Trace 51
#define OP_IntegrityCk 54 #define OP_IfPos 52
#define OP_Remainder 82 /* same as TK_REM */ #define OP_IdxLT 53
#define OP_HexBlob 126 /* same as TK_BLOB */ #define OP_Rewind 54
#define OP_ShiftLeft 76 /* same as TK_LSHIFT */ #define OP_SeekGe 55
#define OP_FifoWrite 55 #define OP_Affinity 56
#define OP_BitAnd 74 /* same as TK_BITAND */ #define OP_Gt 72 /* same as TK_GT */
#define OP_Or 60 /* same as TK_OR */ #define OP_AddImm 57
#define OP_NotExists 56 #define OP_Subtract 82 /* same as TK_MINUS */
#define OP_VDestroy 57 #define OP_Null 58
#define OP_MemStore 58 #define OP_VColumn 59
#define OP_IdxDelete 59 #define OP_Clear 60
#define OP_Vacuum 62 #define OP_IsNull 68 /* same as TK_ISNULL */
#define OP_If 63 #define OP_If 61
#define OP_Destroy 64 #define OP_Permutation 62
#define OP_AggStep 73 #define OP_ToBlob 142 /* same as TK_TO_BLOB */
#define OP_Clear 84 #define OP_RealAffinity 65
#define OP_Insert 86 #define OP_Yield 66
#define OP_VBegin 89 #define OP_AggFinal 67
#define OP_IdxGE 90 #define OP_IfZero 76
#define OP_OpenEphemeral 91 #define OP_Last 87
#define OP_Divide 81 /* same as TK_SLASH */ #define OP_Rowid 88
#define OP_String8 88 /* same as TK_STRING */ #define OP_Sequence 89
#define OP_IfMemZero 92 #define OP_NotFound 92
#define OP_Concat 83 /* same as TK_CONCAT */ #define OP_SeekGt 93
#define OP_VRowid 93
#define OP_MakeRecord 94 #define OP_MakeRecord 94
#define OP_SetCookie 95 #define OP_ToText 141 /* same as TK_TO_TEXT */
#define OP_Prev 96 #define OP_BitAnd 77 /* same as TK_BITAND */
#define OP_ContextPush 97 #define OP_Add 81 /* same as TK_PLUS */
#define OP_DropTrigger 98 #define OP_ResultRow 95
#define OP_IdxGT 99 #define OP_String 96
#define OP_MemNull 100 #define OP_Goto 97
#define OP_IfMemNeg 101 #define OP_Noop 98
#define OP_And 61 /* same as TK_AND */ #define OP_VCreate 99
#define OP_VColumn 102 #define OP_RowSetRead 100
#define OP_Return 103 #define OP_DropTable 101
#define OP_OpenWrite 104 #define OP_IdxRowid 102
#define OP_Integer 105 #define OP_Insert 103
#define OP_Transaction 106 #define OP_Column 104
#define OP_CollSeq 107 #define OP_Not 19 /* same as TK_NOT */
#define OP_VRename 108 #define OP_Compare 105
#define OP_ToBlob 139 /* same as TK_TO_BLOB */ #define OP_Le 73 /* same as TK_LE */
#define OP_Sequence 109 #define OP_BitOr 78 /* same as TK_BITOR */
#define OP_ContextPop 110 #define OP_Multiply 83 /* same as TK_STAR */
#define OP_ShiftRight 77 /* same as TK_RSHIFT */ #define OP_String8 91 /* same as TK_STRING */
#define OP_VCreate 111 #define OP_VOpen 106
#define OP_CreateTable 112 #define OP_CreateTable 107
#define OP_AddImm 113 #define OP_Found 108
#define OP_ToText 138 /* same as TK_TO_TEXT */ #define OP_Seek 109
#define OP_DropTable 114 #define OP_Close 110
#define OP_IsUnique 115 #define OP_Savepoint 111
#define OP_VOpen 116 #define OP_Statement 112
#define OP_Noop 117 #define OP_IfNot 113
#define OP_RowKey 118 #define OP_ToInt 144 /* same as TK_TO_INT */
#define OP_Expire 119 #define OP_VBegin 114
#define OP_FifoRead 120 #define OP_MemMax 115
#define OP_Delete 121 #define OP_Next 116
#define OP_IfMemPos 122 #define OP_Prev 117
#define OP_Subtract 79 /* same as TK_MINUS */ #define OP_SeekLe 118
#define OP_MemIncr 123 #define OP_Lt 74 /* same as TK_LT */
#define OP_Blob 124 #define OP_Ne 70 /* same as TK_NE */
#define OP_MakeIdxRec 127 #define OP_MustBeInt 119
#define OP_Goto 128 #define OP_ShiftRight 80 /* same as TK_RSHIFT */
#define OP_Negative 85 /* same as TK_UMINUS */ #define OP_CollSeq 120
#define OP_ParseSchema 129 #define OP_Gosub 121
#define OP_Eq 68 /* same as TK_EQ */ #define OP_ContextPush 122
#define OP_VNext 130 #define OP_ParseSchema 123
#define OP_Pop 131 #define OP_Destroy 124
#define OP_Le 70 /* same as TK_LE */ #define OP_IdxGE 125
#define OP_TableLock 132 #define OP_ReadCookie 126
#define OP_VerifyCookie 133 #define OP_BitNot 90 /* same as TK_BITNOT */
#define OP_Column 134 #define OP_Or 63 /* same as TK_OR */
#define OP_OpenRead 135 #define OP_Jump 127
#define OP_ResetCount 136 #define OP_ToReal 145 /* same as TK_TO_REAL */
#define OP_ToNumeric 143 /* same as TK_TO_NUMERIC*/
#define OP_Function 128
#define OP_Concat 86 /* same as TK_CONCAT */
#define OP_SCopy 130
#define OP_Int64 131
/* The following opcode values are never used */ /* The following opcode values are never used */
#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 OP_NotUsed_137 137 #define OP_NotUsed_137 137
#define OP_NotUsed_138 138
#define OP_NotUsed_139 139
#define OP_NotUsed_140 140
/* Opcodes that are guaranteed to never push a value onto the stack
** contain a 1 their corresponding position of the following mask /* Properties such as "out2" or "jump" that are specified in
** set. See the opcodeNoPush() function in vdbeaux.c */ ** comments following the "case" for each opcode in the vdbe.c
#define NOPUSH_MASK_0 0x3fbc ** are encoded into bitvectors as follows:
#define NOPUSH_MASK_1 0x3e5b */
#define NOPUSH_MASK_2 0xe3df #define OPFLG_JUMP 0x0001 /* jump: P2 holds jmp target */
#define NOPUSH_MASK_3 0xff9c #define OPFLG_OUT2_PRERELEASE 0x0002 /* out2-prerelease: */
#define NOPUSH_MASK_4 0xfffe #define OPFLG_IN1 0x0004 /* in1: P1 is an input */
#define NOPUSH_MASK_5 0x9ef7 #define OPFLG_IN2 0x0008 /* in2: P2 is an input */
#define NOPUSH_MASK_6 0xddaf #define OPFLG_IN3 0x0010 /* in3: P3 is an input */
#define NOPUSH_MASK_7 0x0ebe #define OPFLG_OUT3 0x0020 /* out3: P3 is an output */
#define NOPUSH_MASK_8 0x7dbf #define OPFLG_INITIALIZER {\
#define NOPUSH_MASK_9 0x0000 /* 0 */ 0x00, 0x02, 0x01, 0x05, 0x00, 0x00, 0x00, 0x00,\
/* 8 */ 0x08, 0x00, 0x11, 0x00, 0x00, 0x02, 0x00, 0x11,\
/* 16 */ 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00,\
/* 24 */ 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x11,\
/* 32 */ 0x10, 0x00, 0x02, 0x02, 0x01, 0x00, 0x00, 0x08,\
/* 40 */ 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00,\
/* 48 */ 0x02, 0x02, 0x04, 0x00, 0x05, 0x11, 0x01, 0x11,\
/* 56 */ 0x00, 0x04, 0x02, 0x00, 0x00, 0x05, 0x00, 0x2c,\
/* 64 */ 0x2c, 0x04, 0x04, 0x00, 0x05, 0x05, 0x15, 0x15,\
/* 72 */ 0x15, 0x15, 0x15, 0x15, 0x05, 0x2c, 0x2c, 0x2c,\
/* 80 */ 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x01,\
/* 88 */ 0x02, 0x02, 0x04, 0x02, 0x11, 0x11, 0x00, 0x00,\
/* 96 */ 0x02, 0x01, 0x00, 0x00, 0x21, 0x00, 0x02, 0x00,\
/* 104 */ 0x00, 0x00, 0x00, 0x02, 0x11, 0x08, 0x00, 0x00,\
/* 112 */ 0x00, 0x05, 0x00, 0x0c, 0x01, 0x01, 0x11, 0x05,\
/* 120 */ 0x00, 0x01, 0x00, 0x00, 0x02, 0x11, 0x02, 0x01,\
/* 128 */ 0x00, 0x02, 0x04, 0x02, 0x00, 0x00, 0x00, 0x00,\
/* 136 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x04, 0x04,\
/* 144 */ 0x04, 0x04,}

290
os.c
View file

@ -12,85 +12,267 @@
** **
** This file contains OS interface code that is common to all ** This file contains OS interface code that is common to all
** architectures. ** architectures.
**
** $Id: os.c,v 1.125 2008/12/08 18:19:18 drh Exp $
*/ */
#define _SQLITE_OS_C_ 1 #define _SQLITE_OS_C_ 1
#include "sqliteInt.h" #include "sqliteInt.h"
#include "os.h"
#undef _SQLITE_OS_C_ #undef _SQLITE_OS_C_
/*
** The default SQLite sqlite3_vfs implementations do not allocate
** memory (actually, os_unix.c allocates a small amount of memory
** from within OsOpen()), but some third-party implementations may.
** So we test the effects of a malloc() failing and the sqlite3OsXXX()
** function returning SQLITE_IOERR_NOMEM using the DO_OS_MALLOC_TEST macro.
**
** The following functions are instrumented for malloc() failure
** testing:
**
** sqlite3OsOpen()
** sqlite3OsRead()
** sqlite3OsWrite()
** sqlite3OsSync()
** sqlite3OsLock()
**
*/
#if defined(SQLITE_TEST) && (SQLITE_OS_WIN==0)
#define DO_OS_MALLOC_TEST if (1) { \
void *pTstAlloc = sqlite3Malloc(10); \
if (!pTstAlloc) return SQLITE_IOERR_NOMEM; \
sqlite3_free(pTstAlloc); \
}
#else
#define DO_OS_MALLOC_TEST
#endif
/* /*
** The following routines are convenience wrappers around methods ** The following routines are convenience wrappers around methods
** of the OsFile object. This is mostly just syntactic sugar. All ** of the sqlite3_file object. This is mostly just syntactic sugar. All
** of this would be completely automatic if SQLite were coded using ** of this would be completely automatic if SQLite were coded using
** C++ instead of plain old C. ** C++ instead of plain old C.
*/ */
int sqlite3OsClose(OsFile **pId){ int sqlite3OsClose(sqlite3_file *pId){
OsFile *id; int rc = SQLITE_OK;
if( pId!=0 && (id = *pId)!=0 ){ if( pId->pMethods ){
return id->pMethod->xClose(pId); rc = pId->pMethods->xClose(pId);
}else{ pId->pMethods = 0;
return SQLITE_OK;
} }
return rc;
} }
int sqlite3OsOpenDirectory(OsFile *id, const char *zName){ int sqlite3OsRead(sqlite3_file *id, void *pBuf, int amt, i64 offset){
return id->pMethod->xOpenDirectory(id, zName); DO_OS_MALLOC_TEST;
return id->pMethods->xRead(id, pBuf, amt, offset);
} }
int sqlite3OsRead(OsFile *id, void *pBuf, int amt){ int sqlite3OsWrite(sqlite3_file *id, const void *pBuf, int amt, i64 offset){
return id->pMethod->xRead(id, pBuf, amt); DO_OS_MALLOC_TEST;
return id->pMethods->xWrite(id, pBuf, amt, offset);
} }
int sqlite3OsWrite(OsFile *id, const void *pBuf, int amt){ int sqlite3OsTruncate(sqlite3_file *id, i64 size){
return id->pMethod->xWrite(id, pBuf, amt); return id->pMethods->xTruncate(id, size);
} }
int sqlite3OsSeek(OsFile *id, i64 offset){ int sqlite3OsSync(sqlite3_file *id, int flags){
return id->pMethod->xSeek(id, offset); DO_OS_MALLOC_TEST;
return id->pMethods->xSync(id, flags);
} }
int sqlite3OsTruncate(OsFile *id, i64 size){ int sqlite3OsFileSize(sqlite3_file *id, i64 *pSize){
return id->pMethod->xTruncate(id, size); DO_OS_MALLOC_TEST;
return id->pMethods->xFileSize(id, pSize);
} }
int sqlite3OsSync(OsFile *id, int fullsync){ int sqlite3OsLock(sqlite3_file *id, int lockType){
return id->pMethod->xSync(id, fullsync); DO_OS_MALLOC_TEST;
return id->pMethods->xLock(id, lockType);
} }
void sqlite3OsSetFullSync(OsFile *id, int value){ int sqlite3OsUnlock(sqlite3_file *id, int lockType){
id->pMethod->xSetFullSync(id, value); return id->pMethods->xUnlock(id, lockType);
} }
int sqlite3OsFileSize(OsFile *id, i64 *pSize){ int sqlite3OsCheckReservedLock(sqlite3_file *id, int *pResOut){
return id->pMethod->xFileSize(id, pSize); DO_OS_MALLOC_TEST;
return id->pMethods->xCheckReservedLock(id, pResOut);
} }
int sqlite3OsLock(OsFile *id, int lockType){ int sqlite3OsFileControl(sqlite3_file *id, int op, void *pArg){
return id->pMethod->xLock(id, lockType); return id->pMethods->xFileControl(id, op, pArg);
} }
int sqlite3OsUnlock(OsFile *id, int lockType){ int sqlite3OsSectorSize(sqlite3_file *id){
return id->pMethod->xUnlock(id, lockType); int (*xSectorSize)(sqlite3_file*) = id->pMethods->xSectorSize;
return (xSectorSize ? xSectorSize(id) : SQLITE_DEFAULT_SECTOR_SIZE);
} }
int sqlite3OsCheckReservedLock(OsFile *id){ int sqlite3OsDeviceCharacteristics(sqlite3_file *id){
return id->pMethod->xCheckReservedLock(id); return id->pMethods->xDeviceCharacteristics(id);
}
int sqlite3OsSectorSize(OsFile *id){
int (*xSectorSize)(OsFile*) = id->pMethod->xSectorSize;
return xSectorSize ? xSectorSize(id) : SQLITE_DEFAULT_SECTOR_SIZE;
} }
#if defined(SQLITE_TEST) || defined(SQLITE_DEBUG)
/* These methods are currently only used for testing and debugging. */
int sqlite3OsFileHandle(OsFile *id){
return id->pMethod->xFileHandle(id);
}
int sqlite3OsLockState(OsFile *id){
return id->pMethod->xLockState(id);
}
#endif
#ifdef SQLITE_ENABLE_REDEF_IO
/* /*
** A function to return a pointer to the virtual function table. ** The next group of routines are convenience wrappers around the
** This routine really does not accomplish very much since the ** VFS methods.
** 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){ int sqlite3OsOpen(
return &sqlite3Os; sqlite3_vfs *pVfs,
const char *zPath,
sqlite3_file *pFile,
int flags,
int *pFlagsOut
){
DO_OS_MALLOC_TEST;
return pVfs->xOpen(pVfs, zPath, pFile, flags, pFlagsOut);
} }
int sqlite3OsDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){
return pVfs->xDelete(pVfs, zPath, dirSync);
}
int sqlite3OsAccess(
sqlite3_vfs *pVfs,
const char *zPath,
int flags,
int *pResOut
){
DO_OS_MALLOC_TEST;
return pVfs->xAccess(pVfs, zPath, flags, pResOut);
}
int sqlite3OsFullPathname(
sqlite3_vfs *pVfs,
const char *zPath,
int nPathOut,
char *zPathOut
){
return pVfs->xFullPathname(pVfs, zPath, nPathOut, zPathOut);
}
#ifndef SQLITE_OMIT_LOAD_EXTENSION
void *sqlite3OsDlOpen(sqlite3_vfs *pVfs, const char *zPath){
return pVfs->xDlOpen(pVfs, zPath);
}
void sqlite3OsDlError(sqlite3_vfs *pVfs, int nByte, char *zBufOut){
pVfs->xDlError(pVfs, nByte, zBufOut);
}
void (*sqlite3OsDlSym(sqlite3_vfs *pVfs, void *pHdle, const char *zSym))(void){
return pVfs->xDlSym(pVfs, pHdle, zSym);
}
void sqlite3OsDlClose(sqlite3_vfs *pVfs, void *pHandle){
pVfs->xDlClose(pVfs, pHandle);
}
#endif /* SQLITE_OMIT_LOAD_EXTENSION */
int sqlite3OsRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufOut){
return pVfs->xRandomness(pVfs, nByte, zBufOut);
}
int sqlite3OsSleep(sqlite3_vfs *pVfs, int nMicro){
return pVfs->xSleep(pVfs, nMicro);
}
int sqlite3OsCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){
return pVfs->xCurrentTime(pVfs, pTimeOut);
}
int sqlite3OsOpenMalloc(
sqlite3_vfs *pVfs,
const char *zFile,
sqlite3_file **ppFile,
int flags,
int *pOutFlags
){
int rc = SQLITE_NOMEM;
sqlite3_file *pFile;
pFile = (sqlite3_file *)sqlite3Malloc(pVfs->szOsFile);
if( pFile ){
rc = sqlite3OsOpen(pVfs, zFile, pFile, flags, pOutFlags);
if( rc!=SQLITE_OK ){
sqlite3_free(pFile);
}else{
*ppFile = pFile;
}
}
return rc;
}
int sqlite3OsCloseFree(sqlite3_file *pFile){
int rc = SQLITE_OK;
assert( pFile );
rc = sqlite3OsClose(pFile);
sqlite3_free(pFile);
return rc;
}
/*
** The list of all registered VFS implementations.
*/
static sqlite3_vfs * SQLITE_WSD vfsList = 0;
#define vfsList GLOBAL(sqlite3_vfs *, vfsList)
/*
** Locate a VFS by name. If no name is given, simply return the
** first VFS on the list.
*/
sqlite3_vfs *sqlite3_vfs_find(const char *zVfs){
sqlite3_vfs *pVfs = 0;
#if SQLITE_THREADSAFE
sqlite3_mutex *mutex;
#endif #endif
#ifndef SQLITE_OMIT_AUTOINIT
int rc = sqlite3_initialize();
if( rc ) return 0;
#endif
#if SQLITE_THREADSAFE
mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER);
#endif
sqlite3_mutex_enter(mutex);
for(pVfs = vfsList; pVfs; pVfs=pVfs->pNext){
if( zVfs==0 ) break;
if( strcmp(zVfs, pVfs->zName)==0 ) break;
}
sqlite3_mutex_leave(mutex);
return pVfs;
}
/*
** Unlink a VFS from the linked list
*/
static void vfsUnlink(sqlite3_vfs *pVfs){
assert( sqlite3_mutex_held(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER)) );
if( pVfs==0 ){
/* No-op */
}else if( vfsList==pVfs ){
vfsList = pVfs->pNext;
}else if( vfsList ){
sqlite3_vfs *p = vfsList;
while( p->pNext && p->pNext!=pVfs ){
p = p->pNext;
}
if( p->pNext==pVfs ){
p->pNext = pVfs->pNext;
}
}
}
/*
** Register a VFS with the system. It is harmless to register the same
** VFS multiple times. The new VFS becomes the default if makeDflt is
** true.
*/
int sqlite3_vfs_register(sqlite3_vfs *pVfs, int makeDflt){
sqlite3_mutex *mutex = 0;
#ifndef SQLITE_OMIT_AUTOINIT
int rc = sqlite3_initialize();
if( rc ) return rc;
#endif
mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER);
sqlite3_mutex_enter(mutex);
vfsUnlink(pVfs);
if( makeDflt || vfsList==0 ){
pVfs->pNext = vfsList;
vfsList = pVfs;
}else{
pVfs->pNext = vfsList->pNext;
vfsList->pNext = pVfs;
}
assert(vfsList);
sqlite3_mutex_leave(mutex);
return SQLITE_OK;
}
/*
** Unregister a VFS so that it is no longer accessible.
*/
int sqlite3_vfs_unregister(sqlite3_vfs *pVfs){
#if SQLITE_THREADSAFE
sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER);
#endif
sqlite3_mutex_enter(mutex);
vfsUnlink(pVfs);
sqlite3_mutex_leave(mutex);
return SQLITE_OK;
}

444
os.h
View file

@ -13,60 +13,78 @@
** This header file (together with is companion C source-code file ** This header file (together with is companion C source-code file
** "os.c") attempt to abstract the underlying operating system so that ** "os.c") attempt to abstract the underlying operating system so that
** the SQLite library will work on both POSIX and windows systems. ** the SQLite library will work on both POSIX and windows systems.
**
** This header file is #include-ed by sqliteInt.h and thus ends up
** being included by every source file.
**
** $Id: os.h,v 1.107 2009/01/14 23:03:41 drh Exp $
*/ */
#ifndef _SQLITE_OS_H_ #ifndef _SQLITE_OS_H_
#define _SQLITE_OS_H_ #define _SQLITE_OS_H_
/* /*
** Figure out if we are dealing with Unix, Windows, or some other ** Figure out if we are dealing with Unix, Windows, or some other
** operating system. ** operating system. After the following block of preprocess macros,
** all of SQLITE_OS_UNIX, SQLITE_OS_WIN, SQLITE_OS_OS2, and SQLITE_OS_OTHER
** will defined to either 1 or 0. One of the four will be 1. The other
** three will be 0.
*/ */
#if defined(OS_OTHER) #if defined(SQLITE_OS_OTHER)
# if OS_OTHER==1 # if SQLITE_OS_OTHER==1
# undef OS_UNIX # undef SQLITE_OS_UNIX
# define OS_UNIX 0 # define SQLITE_OS_UNIX 0
# undef OS_WIN # undef SQLITE_OS_WIN
# define OS_WIN 0 # define SQLITE_OS_WIN 0
# undef OS_OS2 # undef SQLITE_OS_OS2
# define OS_OS2 0 # define SQLITE_OS_OS2 0
# else # else
# undef OS_OTHER # undef SQLITE_OS_OTHER
# endif # endif
#endif #endif
#if !defined(OS_UNIX) && !defined(OS_OTHER) #if !defined(SQLITE_OS_UNIX) && !defined(SQLITE_OS_OTHER)
# define OS_OTHER 0 # define SQLITE_OS_OTHER 0
# ifndef OS_WIN # ifndef SQLITE_OS_WIN
# if defined(_WIN32) || defined(WIN32) || defined(__CYGWIN__) || defined(__MINGW32__) || defined(__BORLANDC__) # if defined(_WIN32) || defined(WIN32) || defined(__CYGWIN__) || defined(__MINGW32__) || defined(__BORLANDC__)
# define OS_WIN 1 # define SQLITE_OS_WIN 1
# define OS_UNIX 0 # define SQLITE_OS_UNIX 0
# define OS_OS2 0 # define SQLITE_OS_OS2 0
# elif defined(__EMX__) || defined(_OS2) || defined(OS2) || defined(_OS2_) || defined(__OS2__) # elif defined(__EMX__) || defined(_OS2) || defined(OS2) || defined(_OS2_) || defined(__OS2__)
# define OS_WIN 0 # define SQLITE_OS_WIN 0
# define OS_UNIX 0 # define SQLITE_OS_UNIX 0
# define OS_OS2 1 # define SQLITE_OS_OS2 1
# else # else
# define OS_WIN 0 # define SQLITE_OS_WIN 0
# define OS_UNIX 1 # define SQLITE_OS_UNIX 1
# define OS_OS2 0 # define SQLITE_OS_OS2 0
# endif # endif
# else # else
# define OS_UNIX 0 # define SQLITE_OS_UNIX 0
# define OS_OS2 0 # define SQLITE_OS_OS2 0
# endif # endif
#else #else
# ifndef OS_WIN # ifndef SQLITE_OS_WIN
# define OS_WIN 0 # define SQLITE_OS_WIN 0
# endif # endif
#endif #endif
/*
** Determine if we are dealing with WindowsCE - which has a much
** reduced API.
*/
#if defined(_WIN32_WCE)
# define SQLITE_OS_WINCE 1
#else
# define SQLITE_OS_WINCE 0
#endif
/* /*
** Define the maximum size of a temporary filename ** Define the maximum size of a temporary filename
*/ */
#if OS_WIN #if SQLITE_OS_WIN
# include <windows.h> # include <windows.h>
# define SQLITE_TEMPNAME_SIZE (MAX_PATH+50) # define SQLITE_TEMPNAME_SIZE (MAX_PATH+50)
#elif OS_OS2 #elif SQLITE_OS_OS2
# if (__GNUC__ > 3 || __GNUC__ == 3 && __GNUC_MINOR__ >= 3) && defined(OS2_HIGH_MEMORY) # if (__GNUC__ > 3 || __GNUC__ == 3 && __GNUC_MINOR__ >= 3) && defined(OS2_HIGH_MEMORY)
# include <os2safe.h> /* has to be included before os2.h for linking to work */ # include <os2safe.h> /* has to be included before os2.h for linking to work */
# endif # endif
@ -76,7 +94,9 @@
# define INCL_DOSMISC # define INCL_DOSMISC
# define INCL_DOSPROCESS # define INCL_DOSPROCESS
# define INCL_DOSMODULEMGR # define INCL_DOSMODULEMGR
# define INCL_DOSSEMAPHORES
# include <os2.h> # include <os2.h>
# include <uconv.h>
# define SQLITE_TEMPNAME_SIZE (CCHMAXPATHCOMP) # define SQLITE_TEMPNAME_SIZE (CCHMAXPATHCOMP)
#else #else
# define SQLITE_TEMPNAME_SIZE 200 # define SQLITE_TEMPNAME_SIZE 200
@ -103,7 +123,7 @@
** If sqlite is being embedded in another program, you may wish to change the ** If sqlite is being embedded in another program, you may wish to change the
** prefix to reflect your program's name, so that if your program exits ** prefix to reflect your program's name, so that if your program exits
** prematurely, old temporary files can be easily identified. This can be done ** prematurely, old temporary files can be easily identified. This can be done
** using -DTEMP_FILE_PREFIX=myprefix_ on the compiler command line. ** using -DSQLITE_TEMP_FILE_PREFIX=myprefix_ on the compiler command line.
** **
** 2006-10-31: The default prefix used to be "sqlite_". But then ** 2006-10-31: The default prefix used to be "sqlite_". But then
** Mcafee started using SQLite in their anti-virus product and it ** Mcafee started using SQLite in their anti-virus product and it
@ -117,143 +137,10 @@
** enough to know that calling the developer will not help get rid ** enough to know that calling the developer will not help get rid
** of the file. ** of the file.
*/ */
#ifndef TEMP_FILE_PREFIX #ifndef SQLITE_TEMP_FILE_PREFIX
# define TEMP_FILE_PREFIX "etilqs_" # define SQLITE_TEMP_FILE_PREFIX "etilqs_"
#endif #endif
/*
** Define the interfaces for Unix, Windows, and OS/2.
*/
#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
#define sqlite3OsDlopen sqlite3UnixDlopen
#define sqlite3OsDlsym sqlite3UnixDlsym
#define sqlite3OsDlclose sqlite3UnixDlclose
#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
#define sqlite3OsDlopen sqlite3WinDlopen
#define sqlite3OsDlsym sqlite3WinDlsym
#define sqlite3OsDlclose sqlite3WinDlclose
#endif
#if OS_OS2
#define sqlite3OsOpenReadWrite sqlite3Os2OpenReadWrite
#define sqlite3OsOpenExclusive sqlite3Os2OpenExclusive
#define sqlite3OsOpenReadOnly sqlite3Os2OpenReadOnly
#define sqlite3OsDelete sqlite3Os2Delete
#define sqlite3OsFileExists sqlite3Os2FileExists
#define sqlite3OsFullPathname sqlite3Os2FullPathname
#define sqlite3OsIsDirWritable sqlite3Os2IsDirWritable
#define sqlite3OsSyncDirectory sqlite3Os2SyncDirectory
#define sqlite3OsTempFileName sqlite3Os2TempFileName
#define sqlite3OsRandomSeed sqlite3Os2RandomSeed
#define sqlite3OsSleep sqlite3Os2Sleep
#define sqlite3OsCurrentTime sqlite3Os2CurrentTime
#define sqlite3OsEnterMutex sqlite3Os2EnterMutex
#define sqlite3OsLeaveMutex sqlite3Os2LeaveMutex
#define sqlite3OsInMutex sqlite3Os2InMutex
#define sqlite3OsThreadSpecificData sqlite3Os2ThreadSpecificData
#define sqlite3OsMalloc sqlite3GenericMalloc
#define sqlite3OsRealloc sqlite3GenericRealloc
#define sqlite3OsFree sqlite3GenericFree
#define sqlite3OsAllocationSize sqlite3GenericAllocationSize
#define sqlite3OsDlopen sqlite3Os2Dlopen
#define sqlite3OsDlsym sqlite3Os2Dlsym
#define sqlite3OsDlclose sqlite3Os2Dlclose
#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);
int (*xSectorSize)(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 ** The following values may be passed as the second argument to
** sqlite3OsLock(). The various locks exhibit the following semantics: ** sqlite3OsLock(). The various locks exhibit the following semantics:
@ -345,204 +232,45 @@ extern unsigned int sqlite3_pending_byte;
#define SHARED_FIRST (PENDING_BYTE+2) #define SHARED_FIRST (PENDING_BYTE+2)
#define SHARED_SIZE 510 #define SHARED_SIZE 510
/* /*
** Prototypes for operating system interface routines. ** Functions for accessing sqlite3_file methods
*/ */
int sqlite3OsClose(OsFile**); int sqlite3OsClose(sqlite3_file*);
int sqlite3OsOpenDirectory(OsFile*, const char*); int sqlite3OsRead(sqlite3_file*, void*, int amt, i64 offset);
int sqlite3OsRead(OsFile*, void*, int amt); int sqlite3OsWrite(sqlite3_file*, const void*, int amt, i64 offset);
int sqlite3OsWrite(OsFile*, const void*, int amt); int sqlite3OsTruncate(sqlite3_file*, i64 size);
int sqlite3OsSeek(OsFile*, i64 offset); int sqlite3OsSync(sqlite3_file*, int);
int sqlite3OsTruncate(OsFile*, i64 size); int sqlite3OsFileSize(sqlite3_file*, i64 *pSize);
int sqlite3OsSync(OsFile*, int); int sqlite3OsLock(sqlite3_file*, int);
void sqlite3OsSetFullSync(OsFile *id, int setting); int sqlite3OsUnlock(sqlite3_file*, int);
int sqlite3OsFileSize(OsFile*, i64 *pSize); int sqlite3OsCheckReservedLock(sqlite3_file *id, int *pResOut);
int sqlite3OsLock(OsFile*, int); int sqlite3OsFileControl(sqlite3_file*,int,void*);
int sqlite3OsUnlock(OsFile*, int); #define SQLITE_FCNTL_DB_UNCHANGED 0xca093fa0
int sqlite3OsCheckReservedLock(OsFile *id); int sqlite3OsSectorSize(sqlite3_file *id);
int sqlite3OsOpenReadWrite(const char*, OsFile**, int*); int sqlite3OsDeviceCharacteristics(sqlite3_file *id);
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 sqlite3OsSectorSize(OsFile *id);
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 *);
void *sqlite3OsDlopen(const char*);
void *sqlite3OsDlsym(void*, const char*);
int sqlite3OsDlclose(void*);
#if defined(SQLITE_TEST) || defined(SQLITE_DEBUG) /*
int sqlite3OsFileHandle(OsFile *id); ** Functions for accessing sqlite3_vfs methods
int sqlite3OsLockState(OsFile *id); */
#endif int sqlite3OsOpen(sqlite3_vfs *, const char *, sqlite3_file*, int, int *);
int sqlite3OsDelete(sqlite3_vfs *, const char *, int);
int sqlite3OsAccess(sqlite3_vfs *, const char *, int, int *pResOut);
int sqlite3OsFullPathname(sqlite3_vfs *, const char *, int, char *);
#ifndef SQLITE_OMIT_LOAD_EXTENSION
void *sqlite3OsDlOpen(sqlite3_vfs *, const char *);
void sqlite3OsDlError(sqlite3_vfs *, int, char *);
void (*sqlite3OsDlSym(sqlite3_vfs *, void *, const char *))(void);
void sqlite3OsDlClose(sqlite3_vfs *, void *);
#endif /* SQLITE_OMIT_LOAD_EXTENSION */
int sqlite3OsRandomness(sqlite3_vfs *, int, char *);
int sqlite3OsSleep(sqlite3_vfs *, int);
int sqlite3OsCurrentTime(sqlite3_vfs *, double*);
/* /*
** If the SQLITE_ENABLE_REDEF_IO macro is defined, then the OS-layer ** Convenience functions for opening and closing files using
** interface routines are not called directly but are invoked using ** sqlite3_malloc() to obtain space for the file-handle structure.
** 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 int sqlite3OsOpenMalloc(sqlite3_vfs *, const char *, sqlite3_file **, int,int*);
int sqlite3OsCloseFree(sqlite3_file *);
/*
** 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 *);
void *(*xDlopen)(const char*);
void *(*xDlsym)(void*, const char*);
int (*xDlclose)(void*);
};
/* Macro used to comment out routines that do not exists when there is
** no disk I/O or extension loading
*/
#ifdef SQLITE_OMIT_DISKIO
# define IF_DISKIO(X) 0
#else
# define IF_DISKIO(X) X
#endif
#ifdef SQLITE_OMIT_LOAD_EXTENSION
# define IF_DLOPEN(X) 0
#else
# define IF_DLOPEN(X) X
#endif
#if defined(_SQLITE_OS_C_) || defined(SQLITE_AMALGAMATION)
/*
** The os.c file implements the global virtual function table.
** We have to put this file here because the initializers
** (ex: sqlite3OsRandomSeed) are macros that are about to be
** redefined.
*/
struct sqlite3OsVtbl sqlite3Os = {
IF_DISKIO( sqlite3OsOpenReadWrite ),
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,
IF_DLOPEN( sqlite3OsDlopen ),
IF_DLOPEN( sqlite3OsDlsym ),
IF_DLOPEN( sqlite3OsDlclose ),
};
#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_ */ #endif /* _SQLITE_OS_H_ */

View file

@ -16,7 +16,11 @@
** **
** This file should be #included by the os_*.c files only. It is not a ** This file should be #included by the os_*.c files only. It is not a
** general purpose header file. ** general purpose header file.
**
** $Id: os_common.h,v 1.37 2008/05/29 20:22:37 shane Exp $
*/ */
#ifndef _OS_COMMON_H_
#define _OS_COMMON_H_
/* /*
** At least two bugs have slipped in because we changed the MEMORY_DEBUG ** At least two bugs have slipped in because we changed the MEMORY_DEBUG
@ -37,16 +41,16 @@ unsigned int sqlite3_pending_byte = 0x40000000;
#endif #endif
#ifdef SQLITE_DEBUG #ifdef SQLITE_DEBUG
int sqlite3_os_trace = 0; int sqlite3OSTrace = 0;
#define OSTRACE1(X) if( sqlite3_os_trace ) sqlite3DebugPrintf(X) #define OSTRACE1(X) if( sqlite3OSTrace ) sqlite3DebugPrintf(X)
#define OSTRACE2(X,Y) if( sqlite3_os_trace ) sqlite3DebugPrintf(X,Y) #define OSTRACE2(X,Y) if( sqlite3OSTrace ) sqlite3DebugPrintf(X,Y)
#define OSTRACE3(X,Y,Z) if( sqlite3_os_trace ) sqlite3DebugPrintf(X,Y,Z) #define OSTRACE3(X,Y,Z) if( sqlite3OSTrace ) sqlite3DebugPrintf(X,Y,Z)
#define OSTRACE4(X,Y,Z,A) if( sqlite3_os_trace ) sqlite3DebugPrintf(X,Y,Z,A) #define OSTRACE4(X,Y,Z,A) if( sqlite3OSTrace ) sqlite3DebugPrintf(X,Y,Z,A)
#define OSTRACE5(X,Y,Z,A,B) if( sqlite3_os_trace ) sqlite3DebugPrintf(X,Y,Z,A,B) #define OSTRACE5(X,Y,Z,A,B) if( sqlite3OSTrace ) sqlite3DebugPrintf(X,Y,Z,A,B)
#define OSTRACE6(X,Y,Z,A,B,C) \ #define OSTRACE6(X,Y,Z,A,B,C) \
if(sqlite3_os_trace) sqlite3DebugPrintf(X,Y,Z,A,B,C) if(sqlite3OSTrace) sqlite3DebugPrintf(X,Y,Z,A,B,C)
#define OSTRACE7(X,Y,Z,A,B,C,D) \ #define OSTRACE7(X,Y,Z,A,B,C,D) \
if(sqlite3_os_trace) sqlite3DebugPrintf(X,Y,Z,A,B,C,D) if(sqlite3OSTrace) sqlite3DebugPrintf(X,Y,Z,A,B,C,D)
#else #else
#define OSTRACE1(X) #define OSTRACE1(X)
#define OSTRACE2(X,Y) #define OSTRACE2(X,Y)
@ -62,22 +66,22 @@ int sqlite3_os_trace = 0;
** on i486 hardware. ** on i486 hardware.
*/ */
#ifdef SQLITE_PERFORMANCE_TRACE #ifdef SQLITE_PERFORMANCE_TRACE
__inline__ unsigned long long int hwtime(void){
unsigned long long int x; /*
__asm__("rdtsc\n\t" ** hwtime.h contains inline assembler code for implementing
"mov %%edx, %%ecx\n\t" ** high-performance timing routines.
:"=A" (x)); */
return x; #include "hwtime.h"
}
static unsigned long long int g_start; static sqlite_uint64 g_start;
static unsigned int elapse; static sqlite_uint64 g_elapsed;
#define TIMER_START g_start=hwtime() #define TIMER_START g_start=sqlite3Hwtime()
#define TIMER_END elapse=hwtime()-g_start #define TIMER_END g_elapsed=sqlite3Hwtime()-g_start
#define TIMER_ELAPSED elapse #define TIMER_ELAPSED g_elapsed
#else #else
#define TIMER_START #define TIMER_START
#define TIMER_END #define TIMER_END
#define TIMER_ELAPSED 0 #define TIMER_ELAPSED ((sqlite_uint64)0)
#endif #endif
/* /*
@ -86,19 +90,22 @@ static unsigned int elapse;
** is used for testing the I/O recovery logic. ** is used for testing the I/O recovery logic.
*/ */
#ifdef SQLITE_TEST #ifdef SQLITE_TEST
int sqlite3_io_error_hit = 0; int sqlite3_io_error_hit = 0; /* Total number of I/O Errors */
int sqlite3_io_error_pending = 0; int sqlite3_io_error_hardhit = 0; /* Number of non-benign errors */
int sqlite3_io_error_persist = 0; int sqlite3_io_error_pending = 0; /* Count down to first I/O error */
int sqlite3_io_error_persist = 0; /* True if I/O errors persist */
int sqlite3_io_error_benign = 0; /* True if errors are benign */
int sqlite3_diskfull_pending = 0; int sqlite3_diskfull_pending = 0;
int sqlite3_diskfull = 0; int sqlite3_diskfull = 0;
#define SimulateIOErrorBenign(X) sqlite3_io_error_benign=(X)
#define SimulateIOError(CODE) \ #define SimulateIOError(CODE) \
if( sqlite3_io_error_pending || sqlite3_io_error_hit ) \ if( (sqlite3_io_error_persist && sqlite3_io_error_hit) \
if( sqlite3_io_error_pending-- == 1 \ || sqlite3_io_error_pending-- == 1 ) \
|| (sqlite3_io_error_persist && sqlite3_io_error_hit) ) \ { local_ioerr(); CODE; }
{ local_ioerr(); CODE; }
static void local_ioerr(){ static void local_ioerr(){
IOTRACE(("IOERR\n")); IOTRACE(("IOERR\n"));
sqlite3_io_error_hit = 1; sqlite3_io_error_hit++;
if( !sqlite3_io_error_benign ) sqlite3_io_error_hardhit++;
} }
#define SimulateDiskfullError(CODE) \ #define SimulateDiskfullError(CODE) \
if( sqlite3_diskfull_pending ){ \ if( sqlite3_diskfull_pending ){ \
@ -112,6 +119,7 @@ static void local_ioerr(){
} \ } \
} }
#else #else
#define SimulateIOErrorBenign(X)
#define SimulateIOError(A) #define SimulateIOError(A)
#define SimulateDiskfullError(A) #define SimulateDiskfullError(A)
#endif #endif
@ -126,73 +134,4 @@ int sqlite3_open_file_count = 0;
#define OpenCounter(X) #define OpenCounter(X)
#endif #endif
/* #endif /* !defined(_OS_COMMON_H_) */
** 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 = (char*)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
/*
** The default size of a disk sector
*/
#ifndef PAGER_SECTOR_SIZE
# define PAGER_SECTOR_SIZE 512
#endif

1247
os_os2.c

File diff suppressed because it is too large Load diff

6326
os_unix.c

File diff suppressed because it is too large Load diff

1664
os_win.c

File diff suppressed because it is too large Load diff

4564
pager.c

File diff suppressed because it is too large Load diff

68
pager.h
View file

@ -13,17 +13,25 @@
** subsystem. The page cache subsystem reads and writes a file a page ** subsystem. The page cache subsystem reads and writes a file a page
** at a time and provides a journal for rollback. ** at a time and provides a journal for rollback.
** **
** @(#) $Id: pager.h,v 1.61 2007/05/08 21:45:28 drh Exp $ ** @(#) $Id: pager.h,v 1.93 2009/01/07 15:18:21 danielk1977 Exp $
*/ */
#ifndef _PAGER_H_ #ifndef _PAGER_H_
#define _PAGER_H_ #define _PAGER_H_
/*
** If defined as non-zero, auto-vacuum is enabled by default. Otherwise
** it must be turned on for each database using "PRAGMA auto_vacuum = 1".
*/
#ifndef SQLITE_DEFAULT_JOURNAL_SIZE_LIMIT
#define SQLITE_DEFAULT_JOURNAL_SIZE_LIMIT -1
#endif
/* /*
** The type used to represent a page number. The first page in a file ** The type used to represent a page number. The first page in a file
** is called page 1. 0 is used to represent "not a page". ** is called page 1. 0 is used to represent "not a page".
*/ */
typedef unsigned int Pgno; typedef u32 Pgno;
/* /*
** Each open file is managed by a separate instance of the "Pager" structure. ** Each open file is managed by a separate instance of the "Pager" structure.
@ -50,16 +58,24 @@ typedef struct PgHdr DbPage;
#define PAGER_LOCKINGMODE_NORMAL 0 #define PAGER_LOCKINGMODE_NORMAL 0
#define PAGER_LOCKINGMODE_EXCLUSIVE 1 #define PAGER_LOCKINGMODE_EXCLUSIVE 1
/*
** Valid values for the second argument to sqlite3PagerJournalMode().
*/
#define PAGER_JOURNALMODE_QUERY -1
#define PAGER_JOURNALMODE_DELETE 0 /* Commit by deleting journal file */
#define PAGER_JOURNALMODE_PERSIST 1 /* Commit by zeroing journal header */
#define PAGER_JOURNALMODE_OFF 2 /* Journal omitted. */
#define PAGER_JOURNALMODE_TRUNCATE 3 /* Commit by truncating journal */
#define PAGER_JOURNALMODE_MEMORY 4 /* In-memory journal file */
/* /*
** See source code comments for a detailed description of the following ** See source code comments for a detailed description of the following
** routines: ** routines:
*/ */
int sqlite3PagerOpen(Pager **ppPager, const char *zFilename, int sqlite3PagerOpen(sqlite3_vfs *, Pager **ppPager, const char*, int,int,int);
int nExtra, int flags); void sqlite3PagerSetBusyhandler(Pager*, int(*)(void *), void *);
void sqlite3PagerSetBusyhandler(Pager*, BusyHandler *pBusyHandler); void sqlite3PagerSetReiniter(Pager*, void(*)(DbPage*));
void sqlite3PagerSetDestructor(Pager*, void(*)(DbPage*,int)); int sqlite3PagerSetPagesize(Pager*, u16*);
void sqlite3PagerSetReiniter(Pager*, void(*)(DbPage*,int));
int sqlite3PagerSetPagesize(Pager*, int);
int sqlite3PagerMaxPageCount(Pager*, int); int sqlite3PagerMaxPageCount(Pager*, int);
int sqlite3PagerReadFileheader(Pager*, int, unsigned char*); int sqlite3PagerReadFileheader(Pager*, int, unsigned char*);
void sqlite3PagerSetCachesize(Pager*, int); void sqlite3PagerSetCachesize(Pager*, int);
@ -67,35 +83,41 @@ int sqlite3PagerClose(Pager *pPager);
int sqlite3PagerAcquire(Pager *pPager, Pgno pgno, DbPage **ppPage, int clrFlag); int sqlite3PagerAcquire(Pager *pPager, Pgno pgno, DbPage **ppPage, int clrFlag);
#define sqlite3PagerGet(A,B,C) sqlite3PagerAcquire(A,B,C,0) #define sqlite3PagerGet(A,B,C) sqlite3PagerAcquire(A,B,C,0)
DbPage *sqlite3PagerLookup(Pager *pPager, Pgno pgno); DbPage *sqlite3PagerLookup(Pager *pPager, Pgno pgno);
int sqlite3PagerPageRefcount(DbPage*);
int sqlite3PagerRef(DbPage*); int sqlite3PagerRef(DbPage*);
int sqlite3PagerUnref(DbPage*); int sqlite3PagerUnref(DbPage*);
int sqlite3PagerWrite(DbPage*); int sqlite3PagerWrite(DbPage*);
int sqlite3PagerOverwrite(Pager *pPager, Pgno pgno, void*); int sqlite3PagerPagecount(Pager*, int*);
int sqlite3PagerPagecount(Pager*);
int sqlite3PagerTruncate(Pager*,Pgno);
int sqlite3PagerBegin(DbPage*, int exFlag); int sqlite3PagerBegin(DbPage*, int exFlag);
int sqlite3PagerCommitPhaseOne(Pager*,const char *zMaster, Pgno); int sqlite3PagerCommitPhaseOne(Pager*,const char *zMaster, int);
int sqlite3PagerCommitPhaseTwo(Pager*); int sqlite3PagerCommitPhaseTwo(Pager*);
int sqlite3PagerRollback(Pager*); int sqlite3PagerRollback(Pager*);
int sqlite3PagerIsreadonly(Pager*); u8 sqlite3PagerIsreadonly(Pager*);
int sqlite3PagerStmtBegin(Pager*);
int sqlite3PagerStmtCommit(Pager*);
int sqlite3PagerStmtRollback(Pager*);
void sqlite3PagerDontRollback(DbPage*); void sqlite3PagerDontRollback(DbPage*);
void sqlite3PagerDontWrite(DbPage*); int sqlite3PagerDontWrite(DbPage*);
int sqlite3PagerRefcount(Pager*); int sqlite3PagerRefcount(Pager*);
void sqlite3PagerSetSafetyLevel(Pager*,int,int); void sqlite3PagerSetSafetyLevel(Pager*,int,int);
const char *sqlite3PagerFilename(Pager*); const char *sqlite3PagerFilename(Pager*);
const sqlite3_vfs *sqlite3PagerVfs(Pager*);
sqlite3_file *sqlite3PagerFile(Pager*);
const char *sqlite3PagerDirname(Pager*); const char *sqlite3PagerDirname(Pager*);
const char *sqlite3PagerJournalname(Pager*); const char *sqlite3PagerJournalname(Pager*);
int sqlite3PagerNosync(Pager*); int sqlite3PagerNosync(Pager*);
int sqlite3PagerMovepage(Pager*,DbPage*,Pgno); int sqlite3PagerMovepage(Pager*,DbPage*,Pgno,int);
void *sqlite3PagerGetData(DbPage *); void *sqlite3PagerGetData(DbPage *);
void *sqlite3PagerGetExtra(DbPage *); void *sqlite3PagerGetExtra(DbPage *);
int sqlite3PagerLockingMode(Pager *, int); int sqlite3PagerLockingMode(Pager *, int);
int sqlite3PagerJournalMode(Pager *, int);
i64 sqlite3PagerJournalSizeLimit(Pager *, i64);
void *sqlite3PagerTempSpace(Pager*);
int sqlite3PagerSync(Pager *pPager);
#if defined(SQLITE_ENABLE_MEMORY_MANAGEMENT) && !defined(SQLITE_OMIT_DISKIO) int sqlite3PagerOpenSavepoint(Pager *pPager, int n);
int sqlite3PagerReleaseMemory(int); int sqlite3PagerSavepoint(Pager *pPager, int op, int iSavepoint);
#ifndef SQLITE_OMIT_AUTOVACUUM
void sqlite3PagerTruncateImage(Pager*,Pgno);
Pgno sqlite3PagerImageSize(Pager *);
#endif #endif
#ifdef SQLITE_HAS_CODEC #ifdef SQLITE_HAS_CODEC
@ -107,14 +129,10 @@ int sqlite3PagerLockingMode(Pager *, int);
int sqlite3PagerIswriteable(DbPage*); int sqlite3PagerIswriteable(DbPage*);
#endif #endif
#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
int sqlite3PagerLockstate(Pager*);
#endif
#ifdef SQLITE_TEST #ifdef SQLITE_TEST
int *sqlite3PagerStats(Pager*); int *sqlite3PagerStats(Pager*);
void sqlite3PagerRefdump(Pager*); void sqlite3PagerRefdump(Pager*);
int pager3_refinfo_enable; int sqlite3PagerIsMemdb(Pager*);
#endif #endif
#ifdef SQLITE_TEST #ifdef SQLITE_TEST

4708
parse.c

File diff suppressed because it is too large Load diff

282
parse.h
View file

@ -10,143 +10,145 @@
#define TK_COMMIT 10 #define TK_COMMIT 10
#define TK_END 11 #define TK_END 11
#define TK_ROLLBACK 12 #define TK_ROLLBACK 12
#define TK_CREATE 13 #define TK_SAVEPOINT 13
#define TK_TABLE 14 #define TK_RELEASE 14
#define TK_IF 15 #define TK_TO 15
#define TK_NOT 16 #define TK_CREATE 16
#define TK_EXISTS 17 #define TK_TABLE 17
#define TK_TEMP 18 #define TK_IF 18
#define TK_LP 19 #define TK_NOT 19
#define TK_RP 20 #define TK_EXISTS 20
#define TK_AS 21 #define TK_TEMP 21
#define TK_COMMA 22 #define TK_LP 22
#define TK_ID 23 #define TK_RP 23
#define TK_ABORT 24 #define TK_AS 24
#define TK_AFTER 25 #define TK_COMMA 25
#define TK_ANALYZE 26 #define TK_ID 26
#define TK_ASC 27 #define TK_ABORT 27
#define TK_ATTACH 28 #define TK_AFTER 28
#define TK_BEFORE 29 #define TK_ANALYZE 29
#define TK_CASCADE 30 #define TK_ASC 30
#define TK_CAST 31 #define TK_ATTACH 31
#define TK_CONFLICT 32 #define TK_BEFORE 32
#define TK_DATABASE 33 #define TK_CASCADE 33
#define TK_DESC 34 #define TK_CAST 34
#define TK_DETACH 35 #define TK_CONFLICT 35
#define TK_EACH 36 #define TK_DATABASE 36
#define TK_FAIL 37 #define TK_DESC 37
#define TK_FOR 38 #define TK_DETACH 38
#define TK_IGNORE 39 #define TK_EACH 39
#define TK_INITIALLY 40 #define TK_FAIL 40
#define TK_INSTEAD 41 #define TK_FOR 41
#define TK_LIKE_KW 42 #define TK_IGNORE 42
#define TK_MATCH 43 #define TK_INITIALLY 43
#define TK_KEY 44 #define TK_INSTEAD 44
#define TK_OF 45 #define TK_LIKE_KW 45
#define TK_OFFSET 46 #define TK_MATCH 46
#define TK_PRAGMA 47 #define TK_KEY 47
#define TK_RAISE 48 #define TK_OF 48
#define TK_REPLACE 49 #define TK_OFFSET 49
#define TK_RESTRICT 50 #define TK_PRAGMA 50
#define TK_ROW 51 #define TK_RAISE 51
#define TK_TRIGGER 52 #define TK_REPLACE 52
#define TK_VACUUM 53 #define TK_RESTRICT 53
#define TK_VIEW 54 #define TK_ROW 54
#define TK_VIRTUAL 55 #define TK_TRIGGER 55
#define TK_REINDEX 56 #define TK_VACUUM 56
#define TK_RENAME 57 #define TK_VIEW 57
#define TK_CTIME_KW 58 #define TK_VIRTUAL 58
#define TK_ANY 59 #define TK_REINDEX 59
#define TK_OR 60 #define TK_RENAME 60
#define TK_AND 61 #define TK_CTIME_KW 61
#define TK_IS 62 #define TK_ANY 62
#define TK_BETWEEN 63 #define TK_OR 63
#define TK_IN 64 #define TK_AND 64
#define TK_ISNULL 65 #define TK_IS 65
#define TK_NOTNULL 66 #define TK_BETWEEN 66
#define TK_NE 67 #define TK_IN 67
#define TK_EQ 68 #define TK_ISNULL 68
#define TK_GT 69 #define TK_NOTNULL 69
#define TK_LE 70 #define TK_NE 70
#define TK_LT 71 #define TK_EQ 71
#define TK_GE 72 #define TK_GT 72
#define TK_ESCAPE 73 #define TK_LE 73
#define TK_BITAND 74 #define TK_LT 74
#define TK_BITOR 75 #define TK_GE 75
#define TK_LSHIFT 76 #define TK_ESCAPE 76
#define TK_RSHIFT 77 #define TK_BITAND 77
#define TK_PLUS 78 #define TK_BITOR 78
#define TK_MINUS 79 #define TK_LSHIFT 79
#define TK_STAR 80 #define TK_RSHIFT 80
#define TK_SLASH 81 #define TK_PLUS 81
#define TK_REM 82 #define TK_MINUS 82
#define TK_CONCAT 83 #define TK_STAR 83
#define TK_COLLATE 84 #define TK_SLASH 84
#define TK_UMINUS 85 #define TK_REM 85
#define TK_UPLUS 86 #define TK_CONCAT 86
#define TK_BITNOT 87 #define TK_COLLATE 87
#define TK_STRING 88 #define TK_UMINUS 88
#define TK_JOIN_KW 89 #define TK_UPLUS 89
#define TK_CONSTRAINT 90 #define TK_BITNOT 90
#define TK_DEFAULT 91 #define TK_STRING 91
#define TK_NULL 92 #define TK_JOIN_KW 92
#define TK_PRIMARY 93 #define TK_CONSTRAINT 93
#define TK_UNIQUE 94 #define TK_DEFAULT 94
#define TK_CHECK 95 #define TK_NULL 95
#define TK_REFERENCES 96 #define TK_PRIMARY 96
#define TK_AUTOINCR 97 #define TK_UNIQUE 97
#define TK_ON 98 #define TK_CHECK 98
#define TK_DELETE 99 #define TK_REFERENCES 99
#define TK_UPDATE 100 #define TK_AUTOINCR 100
#define TK_INSERT 101 #define TK_ON 101
#define TK_SET 102 #define TK_DELETE 102
#define TK_DEFERRABLE 103 #define TK_UPDATE 103
#define TK_FOREIGN 104 #define TK_INSERT 104
#define TK_DROP 105 #define TK_SET 105
#define TK_UNION 106 #define TK_DEFERRABLE 106
#define TK_ALL 107 #define TK_FOREIGN 107
#define TK_EXCEPT 108 #define TK_DROP 108
#define TK_INTERSECT 109 #define TK_UNION 109
#define TK_SELECT 110 #define TK_ALL 110
#define TK_DISTINCT 111 #define TK_EXCEPT 111
#define TK_DOT 112 #define TK_INTERSECT 112
#define TK_FROM 113 #define TK_SELECT 113
#define TK_JOIN 114 #define TK_DISTINCT 114
#define TK_USING 115 #define TK_DOT 115
#define TK_ORDER 116 #define TK_FROM 116
#define TK_BY 117 #define TK_JOIN 117
#define TK_GROUP 118 #define TK_INDEXED 118
#define TK_HAVING 119 #define TK_BY 119
#define TK_LIMIT 120 #define TK_USING 120
#define TK_WHERE 121 #define TK_ORDER 121
#define TK_INTO 122 #define TK_GROUP 122
#define TK_VALUES 123 #define TK_HAVING 123
#define TK_INTEGER 124 #define TK_LIMIT 124
#define TK_FLOAT 125 #define TK_WHERE 125
#define TK_BLOB 126 #define TK_INTO 126
#define TK_REGISTER 127 #define TK_VALUES 127
#define TK_VARIABLE 128 #define TK_INTEGER 128
#define TK_CASE 129 #define TK_FLOAT 129
#define TK_WHEN 130 #define TK_BLOB 130
#define TK_THEN 131 #define TK_REGISTER 131
#define TK_ELSE 132 #define TK_VARIABLE 132
#define TK_INDEX 133 #define TK_CASE 133
#define TK_ALTER 134 #define TK_WHEN 134
#define TK_TO 135 #define TK_THEN 135
#define TK_ADD 136 #define TK_ELSE 136
#define TK_COLUMNKW 137 #define TK_INDEX 137
#define TK_TO_TEXT 138 #define TK_ALTER 138
#define TK_TO_BLOB 139 #define TK_ADD 139
#define TK_TO_NUMERIC 140 #define TK_COLUMNKW 140
#define TK_TO_INT 141 #define TK_TO_TEXT 141
#define TK_TO_REAL 142 #define TK_TO_BLOB 142
#define TK_END_OF_FILE 143 #define TK_TO_NUMERIC 143
#define TK_ILLEGAL 144 #define TK_TO_INT 144
#define TK_SPACE 145 #define TK_TO_REAL 145
#define TK_UNCLOSED_STRING 146 #define TK_END_OF_FILE 146
#define TK_COMMENT 147 #define TK_ILLEGAL 147
#define TK_FUNCTION 148 #define TK_SPACE 148
#define TK_COLUMN 149 #define TK_UNCLOSED_STRING 149
#define TK_AGG_FUNCTION 150 #define TK_FUNCTION 150
#define TK_AGG_COLUMN 151 #define TK_COLUMN 151
#define TK_CONST_FUNC 152 #define TK_AGG_FUNCTION 152
#define TK_AGG_COLUMN 153
#define TK_CONST_FUNC 154

580
pcache.c Normal file
View file

@ -0,0 +1,580 @@
/*
** 2008 August 05
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
**
** May you do good and not evil.
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
*************************************************************************
** This file implements that page cache.
**
** @(#) $Id: pcache.c,v 1.39 2008/12/04 20:40:10 drh Exp $
*/
#include "sqliteInt.h"
/*
** A complete page cache is an instance of this structure.
*/
struct PCache {
PgHdr *pDirty, *pDirtyTail; /* List of dirty pages in LRU order */
PgHdr *pSynced; /* Last synced page in dirty page list */
int nRef; /* Number of referenced pages */
int nMax; /* Configured cache size */
int nMin; /* Configured minimum cache size */
int szPage; /* Size of every page in this cache */
int szExtra; /* Size of extra space for each page */
int bPurgeable; /* True if pages are on backing store */
int (*xStress)(void*,PgHdr*); /* Call to try make a page clean */
void *pStress; /* Argument to xStress */
sqlite3_pcache *pCache; /* Pluggable cache module */
PgHdr *pPage1;
};
/*
** Some of the assert() macros in this code are too expensive to run
** even during normal debugging. Use them only rarely on long-running
** tests. Enable the expensive asserts using the
** -DSQLITE_ENABLE_EXPENSIVE_ASSERT=1 compile-time option.
*/
#ifdef SQLITE_ENABLE_EXPENSIVE_ASSERT
# define expensive_assert(X) assert(X)
#else
# define expensive_assert(X)
#endif
/********************************** Linked List Management ********************/
#if !defined(NDEBUG) && defined(SQLITE_ENABLE_EXPENSIVE_ASSERT)
/*
** Check that the pCache->pSynced variable is set correctly. If it
** is not, either fail an assert or return zero. Otherwise, return
** non-zero. This is only used in debugging builds, as follows:
**
** expensive_assert( pcacheCheckSynced(pCache) );
*/
static int pcacheCheckSynced(PCache *pCache){
PgHdr *p;
for(p=pCache->pDirtyTail; p!=pCache->pSynced; p=p->pDirtyPrev){
assert( p->nRef || (p->flags&PGHDR_NEED_SYNC) );
}
return (p==0 || p->nRef || (p->flags&PGHDR_NEED_SYNC)==0);
}
#endif /* !NDEBUG && SQLITE_ENABLE_EXPENSIVE_ASSERT */
/*
** Remove page pPage from the list of dirty pages.
*/
static void pcacheRemoveFromDirtyList(PgHdr *pPage){
PCache *p = pPage->pCache;
assert( pPage->pDirtyNext || pPage==p->pDirtyTail );
assert( pPage->pDirtyPrev || pPage==p->pDirty );
/* Update the PCache1.pSynced variable if necessary. */
if( p->pSynced==pPage ){
PgHdr *pSynced = pPage->pDirtyPrev;
while( pSynced && (pSynced->flags&PGHDR_NEED_SYNC) ){
pSynced = pSynced->pDirtyPrev;
}
p->pSynced = pSynced;
}
if( pPage->pDirtyNext ){
pPage->pDirtyNext->pDirtyPrev = pPage->pDirtyPrev;
}else{
assert( pPage==p->pDirtyTail );
p->pDirtyTail = pPage->pDirtyPrev;
}
if( pPage->pDirtyPrev ){
pPage->pDirtyPrev->pDirtyNext = pPage->pDirtyNext;
}else{
assert( pPage==p->pDirty );
p->pDirty = pPage->pDirtyNext;
}
pPage->pDirtyNext = 0;
pPage->pDirtyPrev = 0;
expensive_assert( pcacheCheckSynced(p) );
}
/*
** Add page pPage to the head of the dirty list (PCache1.pDirty is set to
** pPage).
*/
static void pcacheAddToDirtyList(PgHdr *pPage){
PCache *p = pPage->pCache;
assert( pPage->pDirtyNext==0 && pPage->pDirtyPrev==0 && p->pDirty!=pPage );
pPage->pDirtyNext = p->pDirty;
if( pPage->pDirtyNext ){
assert( pPage->pDirtyNext->pDirtyPrev==0 );
pPage->pDirtyNext->pDirtyPrev = pPage;
}
p->pDirty = pPage;
if( !p->pDirtyTail ){
p->pDirtyTail = pPage;
}
if( !p->pSynced && 0==(pPage->flags&PGHDR_NEED_SYNC) ){
p->pSynced = pPage;
}
expensive_assert( pcacheCheckSynced(p) );
}
/*
** Wrapper around the pluggable caches xUnpin method. If the cache is
** being used for an in-memory database, this function is a no-op.
*/
static void pcacheUnpin(PgHdr *p){
PCache *pCache = p->pCache;
if( pCache->bPurgeable ){
if( p->pgno==1 ){
pCache->pPage1 = 0;
}
sqlite3GlobalConfig.pcache.xUnpin(pCache->pCache, p, 0);
}
}
/*************************************************** General Interfaces ******
**
** Initialize and shutdown the page cache subsystem. Neither of these
** functions are threadsafe.
*/
int sqlite3PcacheInitialize(void){
if( sqlite3GlobalConfig.pcache.xInit==0 ){
sqlite3PCacheSetDefault();
}
return sqlite3GlobalConfig.pcache.xInit(sqlite3GlobalConfig.pcache.pArg);
}
void sqlite3PcacheShutdown(void){
if( sqlite3GlobalConfig.pcache.xShutdown ){
sqlite3GlobalConfig.pcache.xShutdown(sqlite3GlobalConfig.pcache.pArg);
}
}
/*
** Return the size in bytes of a PCache object.
*/
int sqlite3PcacheSize(void){ return sizeof(PCache); }
/*
** Create a new PCache object. Storage space to hold the object
** has already been allocated and is passed in as the p pointer.
** The caller discovers how much space needs to be allocated by
** calling sqlite3PcacheSize().
*/
void sqlite3PcacheOpen(
int szPage, /* Size of every page */
int szExtra, /* Extra space associated with each page */
int bPurgeable, /* True if pages are on backing store */
int (*xStress)(void*,PgHdr*),/* Call to try to make pages clean */
void *pStress, /* Argument to xStress */
PCache *p /* Preallocated space for the PCache */
){
memset(p, 0, sizeof(PCache));
p->szPage = szPage;
p->szExtra = szExtra;
p->bPurgeable = bPurgeable;
p->xStress = xStress;
p->pStress = pStress;
p->nMax = 100;
p->nMin = 10;
}
/*
** Change the page size for PCache object. The caller must ensure that there
** are no outstanding page references when this function is called.
*/
void sqlite3PcacheSetPageSize(PCache *pCache, int szPage){
assert( pCache->nRef==0 && pCache->pDirty==0 );
if( pCache->pCache ){
sqlite3GlobalConfig.pcache.xDestroy(pCache->pCache);
pCache->pCache = 0;
}
pCache->szPage = szPage;
}
/*
** Try to obtain a page from the cache.
*/
int sqlite3PcacheFetch(
PCache *pCache, /* Obtain the page from this cache */
Pgno pgno, /* Page number to obtain */
int createFlag, /* If true, create page if it does not exist already */
PgHdr **ppPage /* Write the page here */
){
PgHdr *pPage = 0;
int eCreate;
assert( pCache!=0 );
assert( pgno>0 );
/* If the pluggable cache (sqlite3_pcache*) has not been allocated,
** allocate it now.
*/
if( !pCache->pCache && createFlag ){
sqlite3_pcache *p;
int nByte;
nByte = pCache->szPage + pCache->szExtra + sizeof(PgHdr);
p = sqlite3GlobalConfig.pcache.xCreate(nByte, pCache->bPurgeable);
if( !p ){
return SQLITE_NOMEM;
}
sqlite3GlobalConfig.pcache.xCachesize(p, pCache->nMax);
pCache->pCache = p;
}
eCreate = createFlag ? 1 : 0;
if( eCreate && (!pCache->bPurgeable || !pCache->pDirty) ){
eCreate = 2;
}
if( pCache->pCache ){
pPage = sqlite3GlobalConfig.pcache.xFetch(pCache->pCache, pgno, eCreate);
}
if( !pPage && eCreate==1 ){
PgHdr *pPg;
/* Find a dirty page to write-out and recycle. First try to find a
** page that does not require a journal-sync (one with PGHDR_NEED_SYNC
** cleared), but if that is not possible settle for any other
** unreferenced dirty page.
*/
expensive_assert( pcacheCheckSynced(pCache) );
for(pPg=pCache->pSynced;
pPg && (pPg->nRef || (pPg->flags&PGHDR_NEED_SYNC));
pPg=pPg->pDirtyPrev
);
if( !pPg ){
for(pPg=pCache->pDirtyTail; pPg && pPg->nRef; pPg=pPg->pDirtyPrev);
}
if( pPg ){
int rc;
rc = pCache->xStress(pCache->pStress, pPg);
if( rc!=SQLITE_OK && rc!=SQLITE_BUSY ){
return rc;
}
}
pPage = sqlite3GlobalConfig.pcache.xFetch(pCache->pCache, pgno, 2);
}
if( pPage ){
if( 0==pPage->nRef ){
pCache->nRef++;
}
pPage->nRef++;
pPage->pData = (void*)&pPage[1];
pPage->pExtra = (void*)&((char*)pPage->pData)[pCache->szPage];
pPage->pCache = pCache;
pPage->pgno = pgno;
if( pgno==1 ){
pCache->pPage1 = pPage;
}
}
*ppPage = pPage;
return (pPage==0 && eCreate) ? SQLITE_NOMEM : SQLITE_OK;
}
/*
** Decrement the reference count on a page. If the page is clean and the
** reference count drops to 0, then it is made elible for recycling.
*/
void sqlite3PcacheRelease(PgHdr *p){
assert( p->nRef>0 );
p->nRef--;
if( p->nRef==0 ){
PCache *pCache = p->pCache;
pCache->nRef--;
if( (p->flags&PGHDR_DIRTY)==0 ){
pcacheUnpin(p);
}else{
/* Move the page to the head of the dirty list. */
pcacheRemoveFromDirtyList(p);
pcacheAddToDirtyList(p);
}
}
}
/*
** Increase the reference count of a supplied page by 1.
*/
void sqlite3PcacheRef(PgHdr *p){
assert(p->nRef>0);
p->nRef++;
}
/*
** Drop a page from the cache. There must be exactly one reference to the
** page. This function deletes that reference, so after it returns the
** page pointed to by p is invalid.
*/
void sqlite3PcacheDrop(PgHdr *p){
PCache *pCache;
assert( p->nRef==1 );
if( p->flags&PGHDR_DIRTY ){
pcacheRemoveFromDirtyList(p);
}
pCache = p->pCache;
pCache->nRef--;
if( p->pgno==1 ){
pCache->pPage1 = 0;
}
sqlite3GlobalConfig.pcache.xUnpin(pCache->pCache, p, 1);
}
/*
** Make sure the page is marked as dirty. If it isn't dirty already,
** make it so.
*/
void sqlite3PcacheMakeDirty(PgHdr *p){
PCache *pCache;
p->flags &= ~PGHDR_DONT_WRITE;
assert( p->nRef>0 );
if( 0==(p->flags & PGHDR_DIRTY) ){
pCache = p->pCache;
p->flags |= PGHDR_DIRTY;
pcacheAddToDirtyList( p);
}
}
/*
** Make sure the page is marked as clean. If it isn't clean already,
** make it so.
*/
void sqlite3PcacheMakeClean(PgHdr *p){
if( (p->flags & PGHDR_DIRTY) ){
pcacheRemoveFromDirtyList(p);
p->flags &= ~(PGHDR_DIRTY|PGHDR_NEED_SYNC);
if( p->nRef==0 ){
pcacheUnpin(p);
}
}
}
/*
** Make every page in the cache clean.
*/
void sqlite3PcacheCleanAll(PCache *pCache){
PgHdr *p;
while( (p = pCache->pDirty)!=0 ){
sqlite3PcacheMakeClean(p);
}
}
/*
** Clear the PGHDR_NEED_SYNC flag from all dirty pages.
*/
void sqlite3PcacheClearSyncFlags(PCache *pCache){
PgHdr *p;
for(p=pCache->pDirty; p; p=p->pDirtyNext){
p->flags &= ~PGHDR_NEED_SYNC;
}
pCache->pSynced = pCache->pDirtyTail;
}
/*
** Change the page number of page p to newPgno.
*/
void sqlite3PcacheMove(PgHdr *p, Pgno newPgno){
PCache *pCache = p->pCache;
assert( p->nRef>0 );
assert( newPgno>0 );
sqlite3GlobalConfig.pcache.xRekey(pCache->pCache, p, p->pgno, newPgno);
p->pgno = newPgno;
if( (p->flags&PGHDR_DIRTY) && (p->flags&PGHDR_NEED_SYNC) ){
pcacheRemoveFromDirtyList(p);
pcacheAddToDirtyList(p);
}
}
/*
** Drop every cache entry whose page number is greater than "pgno". The
** caller must ensure that there are no outstanding references to any pages
** other than page 1 with a page number greater than pgno.
**
** If there is a reference to page 1 and the pgno parameter passed to this
** function is 0, then the data area associated with page 1 is zeroed, but
** the page object is not dropped.
*/
void sqlite3PcacheTruncate(PCache *pCache, Pgno pgno){
if( pCache->pCache ){
PgHdr *p;
PgHdr *pNext;
for(p=pCache->pDirty; p; p=pNext){
pNext = p->pDirtyNext;
if( p->pgno>pgno ){
assert( p->flags&PGHDR_DIRTY );
sqlite3PcacheMakeClean(p);
}
}
if( pgno==0 && pCache->pPage1 ){
memset(pCache->pPage1->pData, 0, pCache->szPage);
pgno = 1;
}
sqlite3GlobalConfig.pcache.xTruncate(pCache->pCache, pgno+1);
}
}
/*
** Close a cache.
*/
void sqlite3PcacheClose(PCache *pCache){
if( pCache->pCache ){
sqlite3GlobalConfig.pcache.xDestroy(pCache->pCache);
}
}
/*
** Discard the contents of the cache.
*/
int sqlite3PcacheClear(PCache *pCache){
sqlite3PcacheTruncate(pCache, 0);
return SQLITE_OK;
}
/*
** Merge two lists of pages connected by pDirty and in pgno order.
** Do not both fixing the pDirtyPrev pointers.
*/
static PgHdr *pcacheMergeDirtyList(PgHdr *pA, PgHdr *pB){
PgHdr result, *pTail;
pTail = &result;
while( pA && pB ){
if( pA->pgno<pB->pgno ){
pTail->pDirty = pA;
pTail = pA;
pA = pA->pDirty;
}else{
pTail->pDirty = pB;
pTail = pB;
pB = pB->pDirty;
}
}
if( pA ){
pTail->pDirty = pA;
}else if( pB ){
pTail->pDirty = pB;
}else{
pTail->pDirty = 0;
}
return result.pDirty;
}
/*
** Sort the list of pages in accending order by pgno. Pages are
** connected by pDirty pointers. The pDirtyPrev pointers are
** corrupted by this sort.
*/
#define N_SORT_BUCKET_ALLOC 25
#define N_SORT_BUCKET 25
#ifdef SQLITE_TEST
int sqlite3_pager_n_sort_bucket = 0;
#undef N_SORT_BUCKET
#define N_SORT_BUCKET \
(sqlite3_pager_n_sort_bucket?sqlite3_pager_n_sort_bucket:N_SORT_BUCKET_ALLOC)
#endif
static PgHdr *pcacheSortDirtyList(PgHdr *pIn){
PgHdr *a[N_SORT_BUCKET_ALLOC], *p;
int i;
memset(a, 0, sizeof(a));
while( pIn ){
p = pIn;
pIn = p->pDirty;
p->pDirty = 0;
for(i=0; i<N_SORT_BUCKET-1; i++){
if( a[i]==0 ){
a[i] = p;
break;
}else{
p = pcacheMergeDirtyList(a[i], p);
a[i] = 0;
}
}
if( i==N_SORT_BUCKET-1 ){
/* Coverage: To get here, there need to be 2^(N_SORT_BUCKET)
** elements in the input list. This is possible, but impractical.
** Testing this line is the point of global variable
** sqlite3_pager_n_sort_bucket.
*/
a[i] = pcacheMergeDirtyList(a[i], p);
}
}
p = a[0];
for(i=1; i<N_SORT_BUCKET; i++){
p = pcacheMergeDirtyList(p, a[i]);
}
return p;
}
/*
** Return a list of all dirty pages in the cache, sorted by page number.
*/
PgHdr *sqlite3PcacheDirtyList(PCache *pCache){
PgHdr *p;
for(p=pCache->pDirty; p; p=p->pDirtyNext){
p->pDirty = p->pDirtyNext;
}
return pcacheSortDirtyList(pCache->pDirty);
}
/*
** Return the total number of referenced pages held by the cache.
*/
int sqlite3PcacheRefCount(PCache *pCache){
return pCache->nRef;
}
/*
** Return the number of references to the page supplied as an argument.
*/
int sqlite3PcachePageRefcount(PgHdr *p){
return p->nRef;
}
/*
** Return the total number of pages in the cache.
*/
int sqlite3PcachePagecount(PCache *pCache){
int nPage = 0;
if( pCache->pCache ){
nPage = sqlite3GlobalConfig.pcache.xPagecount(pCache->pCache);
}
return nPage;
}
#ifdef SQLITE_TEST
/*
** Get the suggested cache-size value.
*/
int sqlite3PcacheGetCachesize(PCache *pCache){
return pCache->nMax;
}
#endif
/*
** Set the suggested cache-size value.
*/
void sqlite3PcacheSetCachesize(PCache *pCache, int mxPage){
pCache->nMax = mxPage;
if( pCache->pCache ){
sqlite3GlobalConfig.pcache.xCachesize(pCache->pCache, mxPage);
}
}
#ifdef SQLITE_CHECK_PAGES
/*
** For all dirty pages currently in the cache, invoke the specified
** callback. This is only used if the SQLITE_CHECK_PAGES macro is
** defined.
*/
void sqlite3PcacheIterateDirty(PCache *pCache, void (*xIter)(PgHdr *)){
PgHdr *pDirty;
for(pDirty=pCache->pDirty; pDirty; pDirty=pDirty->pDirtyNext){
xIter(pDirty);
}
}
#endif

157
pcache.h Normal file
View file

@ -0,0 +1,157 @@
/*
** 2008 August 05
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
**
** May you do good and not evil.
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
*************************************************************************
** This header file defines the interface that the sqlite page cache
** subsystem.
**
** @(#) $Id: pcache.h,v 1.16 2008/11/19 16:52:44 danielk1977 Exp $
*/
#ifndef _PCACHE_H_
typedef struct PgHdr PgHdr;
typedef struct PCache PCache;
/*
** Every page in the cache is controlled by an instance of the following
** structure.
*/
struct PgHdr {
void *pData; /* Content of this page */
void *pExtra; /* Extra content */
PgHdr *pDirty; /* Transient list of dirty pages */
Pgno pgno; /* Page number for this page */
Pager *pPager; /* The pager this page is part of */
#ifdef SQLITE_CHECK_PAGES
u32 pageHash; /* Hash of page content */
#endif
u16 flags; /* PGHDR flags defined below */
/**********************************************************************
** Elements above are public. All that follows is private to pcache.c
** and should not be accessed by other modules.
*/
i16 nRef; /* Number of users of this page */
PCache *pCache; /* Cache that owns this page */
PgHdr *pDirtyNext; /* Next element in list of dirty pages */
PgHdr *pDirtyPrev; /* Previous element in list of dirty pages */
};
/* Bit values for PgHdr.flags */
#define PGHDR_DIRTY 0x002 /* Page has changed */
#define PGHDR_NEED_SYNC 0x004 /* Fsync the rollback journal before
** writing this page to the database */
#define PGHDR_NEED_READ 0x008 /* Content is unread */
#define PGHDR_REUSE_UNLIKELY 0x010 /* A hint that reuse is unlikely */
#define PGHDR_DONT_WRITE 0x020 /* Do not write content to disk */
/* Initialize and shutdown the page cache subsystem */
int sqlite3PcacheInitialize(void);
void sqlite3PcacheShutdown(void);
/* Page cache buffer management:
** These routines implement SQLITE_CONFIG_PAGECACHE.
*/
void sqlite3PCacheBufferSetup(void *, int sz, int n);
/* Create a new pager cache.
** Under memory stress, invoke xStress to try to make pages clean.
** Only clean and unpinned pages can be reclaimed.
*/
void sqlite3PcacheOpen(
int szPage, /* Size of every page */
int szExtra, /* Extra space associated with each page */
int bPurgeable, /* True if pages are on backing store */
int (*xStress)(void*, PgHdr*), /* Call to try to make pages clean */
void *pStress, /* Argument to xStress */
PCache *pToInit /* Preallocated space for the PCache */
);
/* Modify the page-size after the cache has been created. */
void sqlite3PcacheSetPageSize(PCache *, int);
/* Return the size in bytes of a PCache object. Used to preallocate
** storage space.
*/
int sqlite3PcacheSize(void);
/* One release per successful fetch. Page is pinned until released.
** Reference counted.
*/
int sqlite3PcacheFetch(PCache*, Pgno, int createFlag, PgHdr**);
void sqlite3PcacheRelease(PgHdr*);
void sqlite3PcacheDrop(PgHdr*); /* Remove page from cache */
void sqlite3PcacheMakeDirty(PgHdr*); /* Make sure page is marked dirty */
void sqlite3PcacheMakeClean(PgHdr*); /* Mark a single page as clean */
void sqlite3PcacheCleanAll(PCache*); /* Mark all dirty list pages as clean */
/* Change a page number. Used by incr-vacuum. */
void sqlite3PcacheMove(PgHdr*, Pgno);
/* Remove all pages with pgno>x. Reset the cache if x==0 */
void sqlite3PcacheTruncate(PCache*, Pgno x);
/* Get a list of all dirty pages in the cache, sorted by page number */
PgHdr *sqlite3PcacheDirtyList(PCache*);
/* Reset and close the cache object */
void sqlite3PcacheClose(PCache*);
/* Clear flags from pages of the page cache */
void sqlite3PcacheClearSyncFlags(PCache *);
/* Discard the contents of the cache */
int sqlite3PcacheClear(PCache*);
/* Return the total number of outstanding page references */
int sqlite3PcacheRefCount(PCache*);
/* Increment the reference count of an existing page */
void sqlite3PcacheRef(PgHdr*);
int sqlite3PcachePageRefcount(PgHdr*);
/* Return the total number of pages stored in the cache */
int sqlite3PcachePagecount(PCache*);
#ifdef SQLITE_CHECK_PAGES
/* Iterate through all dirty pages currently stored in the cache. This
** interface is only available if SQLITE_CHECK_PAGES is defined when the
** library is built.
*/
void sqlite3PcacheIterateDirty(PCache *pCache, void (*xIter)(PgHdr *));
#endif
/* Set and get the suggested cache-size for the specified pager-cache.
**
** If no global maximum is configured, then the system attempts to limit
** the total number of pages cached by purgeable pager-caches to the sum
** of the suggested cache-sizes.
*/
void sqlite3PcacheSetCachesize(PCache *, int);
#ifdef SQLITE_TEST
int sqlite3PcacheGetCachesize(PCache *);
#endif
#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
/* Try to return memory used by the pcache module to the main memory heap */
int sqlite3PcacheReleaseMemory(int);
#endif
#ifdef SQLITE_TEST
void sqlite3PcacheStats(int*,int*,int*,int*);
#endif
void sqlite3PCacheSetDefault(void);
#endif /* _PCACHE_H_ */

751
pcache1.c Normal file
View file

@ -0,0 +1,751 @@
/*
** 2008 November 05
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
**
** May you do good and not evil.
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
*************************************************************************
**
** This file implements the default page cache implementation (the
** sqlite3_pcache interface). It also contains part of the implementation
** of the SQLITE_CONFIG_PAGECACHE and sqlite3_release_memory() features.
** If the default page cache implementation is overriden, then neither of
** these two features are available.
**
** @(#) $Id: pcache1.c,v 1.7 2009/01/07 15:18:21 danielk1977 Exp $
*/
#include "sqliteInt.h"
typedef struct PCache1 PCache1;
typedef struct PgHdr1 PgHdr1;
typedef struct PgFreeslot PgFreeslot;
/* Pointers to structures of this type are cast and returned as
** opaque sqlite3_pcache* handles
*/
struct PCache1 {
/* Cache configuration parameters. Page size (szPage) and the purgeable
** flag (bPurgeable) are set when the cache is created. nMax may be
** modified at any time by a call to the pcache1CacheSize() method.
** The global mutex must be held when accessing nMax.
*/
int szPage; /* Size of allocated pages in bytes */
int bPurgeable; /* True if cache is purgeable */
unsigned int nMin; /* Minimum number of pages reserved */
unsigned int nMax; /* Configured "cache_size" value */
/* Hash table of all pages. The following variables may only be accessed
** when the accessor is holding the global mutex (see pcache1EnterMutex()
** and pcache1LeaveMutex()).
*/
unsigned int nRecyclable; /* Number of pages in the LRU list */
unsigned int nPage; /* Total number of pages in apHash */
unsigned int nHash; /* Number of slots in apHash[] */
PgHdr1 **apHash; /* Hash table for fast lookup by key */
unsigned int iMaxKey; /* Largest key seen since xTruncate() */
};
/*
** Each cache entry is represented by an instance of the following
** structure. A buffer of PgHdr1.pCache->szPage bytes is allocated
** directly after the structure in memory (see the PGHDR1_TO_PAGE()
** macro below).
*/
struct PgHdr1 {
unsigned int iKey; /* Key value (page number) */
PgHdr1 *pNext; /* Next in hash table chain */
PCache1 *pCache; /* Cache that currently owns this page */
PgHdr1 *pLruNext; /* Next in LRU list of unpinned pages */
PgHdr1 *pLruPrev; /* Previous in LRU list of unpinned pages */
};
/*
** Free slots in the allocator used to divide up the buffer provided using
** the SQLITE_CONFIG_PAGECACHE mechanism.
*/
struct PgFreeslot {
PgFreeslot *pNext; /* Next free slot */
};
/*
** Global data used by this cache.
*/
static SQLITE_WSD struct PCacheGlobal {
sqlite3_mutex *mutex; /* static mutex MUTEX_STATIC_LRU */
int nMaxPage; /* Sum of nMaxPage for purgeable caches */
int nMinPage; /* Sum of nMinPage for purgeable caches */
int nCurrentPage; /* Number of purgeable pages allocated */
PgHdr1 *pLruHead, *pLruTail; /* LRU list of unpinned pages */
/* Variables related to SQLITE_CONFIG_PAGECACHE settings. */
int szSlot; /* Size of each free slot */
void *pStart, *pEnd; /* Bounds of pagecache malloc range */
PgFreeslot *pFree; /* Free page blocks */
} pcache1_g;
/*
** All code in this file should access the global structure above via the
** alias "pcache1". This ensures that the WSD emulation is used when
** compiling for systems that do not support real WSD.
*/
#define pcache1 (GLOBAL(struct PCacheGlobal, pcache1_g))
/*
** When a PgHdr1 structure is allocated, the associated PCache1.szPage
** bytes of data are located directly after it in memory (i.e. the total
** size of the allocation is sizeof(PgHdr1)+PCache1.szPage byte). The
** PGHDR1_TO_PAGE() macro takes a pointer to a PgHdr1 structure as
** an argument and returns a pointer to the associated block of szPage
** bytes. The PAGE_TO_PGHDR1() macro does the opposite: its argument is
** a pointer to a block of szPage bytes of data and the return value is
** a pointer to the associated PgHdr1 structure.
**
** assert( PGHDR1_TO_PAGE(PAGE_TO_PGHDR1(X))==X );
*/
#define PGHDR1_TO_PAGE(p) (void *)(&((unsigned char *)p)[sizeof(PgHdr1)])
#define PAGE_TO_PGHDR1(p) (PgHdr1 *)(&((unsigned char *)p)[-1*(int)sizeof(PgHdr1)])
/*
** Macros to enter and leave the global LRU mutex.
*/
#define pcache1EnterMutex() sqlite3_mutex_enter(pcache1.mutex)
#define pcache1LeaveMutex() sqlite3_mutex_leave(pcache1.mutex)
/******************************************************************************/
/******** Page Allocation/SQLITE_CONFIG_PCACHE Related Functions **************/
/*
** This function is called during initialization if a static buffer is
** supplied to use for the page-cache by passing the SQLITE_CONFIG_PAGECACHE
** verb to sqlite3_config(). Parameter pBuf points to an allocation large
** enough to contain 'n' buffers of 'sz' bytes each.
*/
void sqlite3PCacheBufferSetup(void *pBuf, int sz, int n){
PgFreeslot *p;
sz &= ~7;
pcache1.szSlot = sz;
pcache1.pStart = pBuf;
pcache1.pFree = 0;
while( n-- ){
p = (PgFreeslot*)pBuf;
p->pNext = pcache1.pFree;
pcache1.pFree = p;
pBuf = (void*)&((char*)pBuf)[sz];
}
pcache1.pEnd = pBuf;
}
/*
** Malloc function used within this file to allocate space from the buffer
** configured using sqlite3_config(SQLITE_CONFIG_PAGECACHE) option. If no
** such buffer exists or there is no space left in it, this function falls
** back to sqlite3Malloc().
*/
static void *pcache1Alloc(int nByte){
void *p;
assert( sqlite3_mutex_held(pcache1.mutex) );
if( nByte<=pcache1.szSlot && pcache1.pFree ){
p = (PgHdr1 *)pcache1.pFree;
pcache1.pFree = pcache1.pFree->pNext;
sqlite3StatusSet(SQLITE_STATUS_PAGECACHE_SIZE, nByte);
sqlite3StatusAdd(SQLITE_STATUS_PAGECACHE_USED, 1);
}else{
/* Allocate a new buffer using sqlite3Malloc. Before doing so, exit the
** global pcache mutex and unlock the pager-cache object pCache. This is
** so that if the attempt to allocate a new buffer causes the the
** configured soft-heap-limit to be breached, it will be possible to
** reclaim memory from this pager-cache.
*/
pcache1LeaveMutex();
p = sqlite3Malloc(nByte);
pcache1EnterMutex();
if( p ){
int sz = sqlite3MallocSize(p);
sqlite3StatusAdd(SQLITE_STATUS_PAGECACHE_OVERFLOW, sz);
}
}
return p;
}
/*
** Free an allocated buffer obtained from pcache1Alloc().
*/
static void pcache1Free(void *p){
assert( sqlite3_mutex_held(pcache1.mutex) );
if( p==0 ) return;
if( p>=pcache1.pStart && p<pcache1.pEnd ){
PgFreeslot *pSlot;
sqlite3StatusAdd(SQLITE_STATUS_PAGECACHE_USED, -1);
pSlot = (PgFreeslot*)p;
pSlot->pNext = pcache1.pFree;
pcache1.pFree = pSlot;
}else{
int iSize = sqlite3MallocSize(p);
sqlite3StatusAdd(SQLITE_STATUS_PAGECACHE_OVERFLOW, -iSize);
sqlite3_free(p);
}
}
/*
** Allocate a new page object initially associated with cache pCache.
*/
static PgHdr1 *pcache1AllocPage(PCache1 *pCache){
int nByte = sizeof(PgHdr1) + pCache->szPage;
PgHdr1 *p = (PgHdr1 *)pcache1Alloc(nByte);
if( p ){
memset(p, 0, nByte);
if( pCache->bPurgeable ){
pcache1.nCurrentPage++;
}
}
return p;
}
/*
** Free a page object allocated by pcache1AllocPage().
*/
static void pcache1FreePage(PgHdr1 *p){
if( p ){
if( p->pCache->bPurgeable ){
pcache1.nCurrentPage--;
}
pcache1Free(p);
}
}
/*
** Malloc function used by SQLite to obtain space from the buffer configured
** using sqlite3_config(SQLITE_CONFIG_PAGECACHE) option. If no such buffer
** exists, this function falls back to sqlite3Malloc().
*/
void *sqlite3PageMalloc(int sz){
void *p;
pcache1EnterMutex();
p = pcache1Alloc(sz);
pcache1LeaveMutex();
return p;
}
/*
** Free an allocated buffer obtained from sqlite3PageMalloc().
*/
void sqlite3PageFree(void *p){
pcache1EnterMutex();
pcache1Free(p);
pcache1LeaveMutex();
}
/******************************************************************************/
/******** General Implementation Functions ************************************/
/*
** This function is used to resize the hash table used by the cache passed
** as the first argument.
**
** The global mutex must be held when this function is called.
*/
static int pcache1ResizeHash(PCache1 *p){
PgHdr1 **apNew;
unsigned int nNew;
unsigned int i;
assert( sqlite3_mutex_held(pcache1.mutex) );
nNew = p->nHash*2;
if( nNew<256 ){
nNew = 256;
}
pcache1LeaveMutex();
if( p->nHash ){ sqlite3BeginBenignMalloc(); }
apNew = (PgHdr1 **)sqlite3_malloc(sizeof(PgHdr1 *)*nNew);
if( p->nHash ){ sqlite3EndBenignMalloc(); }
pcache1EnterMutex();
if( apNew ){
memset(apNew, 0, sizeof(PgHdr1 *)*nNew);
for(i=0; i<p->nHash; i++){
PgHdr1 *pPage;
PgHdr1 *pNext = p->apHash[i];
while( (pPage = pNext)!=0 ){
unsigned int h = pPage->iKey % nNew;
pNext = pPage->pNext;
pPage->pNext = apNew[h];
apNew[h] = pPage;
}
}
sqlite3_free(p->apHash);
p->apHash = apNew;
p->nHash = nNew;
}
return (p->apHash ? SQLITE_OK : SQLITE_NOMEM);
}
/*
** This function is used internally to remove the page pPage from the
** global LRU list, if is part of it. If pPage is not part of the global
** LRU list, then this function is a no-op.
**
** The global mutex must be held when this function is called.
*/
static void pcache1PinPage(PgHdr1 *pPage){
assert( sqlite3_mutex_held(pcache1.mutex) );
if( pPage && (pPage->pLruNext || pPage==pcache1.pLruTail) ){
if( pPage->pLruPrev ){
pPage->pLruPrev->pLruNext = pPage->pLruNext;
}
if( pPage->pLruNext ){
pPage->pLruNext->pLruPrev = pPage->pLruPrev;
}
if( pcache1.pLruHead==pPage ){
pcache1.pLruHead = pPage->pLruNext;
}
if( pcache1.pLruTail==pPage ){
pcache1.pLruTail = pPage->pLruPrev;
}
pPage->pLruNext = 0;
pPage->pLruPrev = 0;
pPage->pCache->nRecyclable--;
}
}
/*
** Remove the page supplied as an argument from the hash table
** (PCache1.apHash structure) that it is currently stored in.
**
** The global mutex must be held when this function is called.
*/
static void pcache1RemoveFromHash(PgHdr1 *pPage){
unsigned int h;
PCache1 *pCache = pPage->pCache;
PgHdr1 **pp;
h = pPage->iKey % pCache->nHash;
for(pp=&pCache->apHash[h]; (*pp)!=pPage; pp=&(*pp)->pNext);
*pp = (*pp)->pNext;
pCache->nPage--;
}
/*
** If there are currently more than pcache.nMaxPage pages allocated, try
** to recycle pages to reduce the number allocated to pcache.nMaxPage.
*/
static void pcache1EnforceMaxPage(void){
assert( sqlite3_mutex_held(pcache1.mutex) );
while( pcache1.nCurrentPage>pcache1.nMaxPage && pcache1.pLruTail ){
PgHdr1 *p = pcache1.pLruTail;
pcache1PinPage(p);
pcache1RemoveFromHash(p);
pcache1FreePage(p);
}
}
/*
** Discard all pages from cache pCache with a page number (key value)
** greater than or equal to iLimit. Any pinned pages that meet this
** criteria are unpinned before they are discarded.
**
** The global mutex must be held when this function is called.
*/
static void pcache1TruncateUnsafe(
PCache1 *pCache,
unsigned int iLimit
){
unsigned int h;
assert( sqlite3_mutex_held(pcache1.mutex) );
for(h=0; h<pCache->nHash; h++){
PgHdr1 **pp = &pCache->apHash[h];
PgHdr1 *pPage;
while( (pPage = *pp)!=0 ){
if( pPage->iKey>=iLimit ){
pcache1PinPage(pPage);
*pp = pPage->pNext;
pcache1FreePage(pPage);
}else{
pp = &pPage->pNext;
}
}
}
}
/******************************************************************************/
/******** sqlite3_pcache Methods **********************************************/
/*
** Implementation of the sqlite3_pcache.xInit method.
*/
static int pcache1Init(void *NotUsed){
UNUSED_PARAMETER(NotUsed);
memset(&pcache1, 0, sizeof(pcache1));
if( sqlite3GlobalConfig.bCoreMutex ){
pcache1.mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_LRU);
}
return SQLITE_OK;
}
/*
** Implementation of the sqlite3_pcache.xShutdown method.
*/
static void pcache1Shutdown(void *NotUsed){
UNUSED_PARAMETER(NotUsed);
/* no-op */
}
/*
** Implementation of the sqlite3_pcache.xCreate method.
**
** Allocate a new cache.
*/
static sqlite3_pcache *pcache1Create(int szPage, int bPurgeable){
PCache1 *pCache;
pCache = (PCache1 *)sqlite3_malloc(sizeof(PCache1));
if( pCache ){
memset(pCache, 0, sizeof(PCache1));
pCache->szPage = szPage;
pCache->bPurgeable = (bPurgeable ? 1 : 0);
if( bPurgeable ){
pCache->nMin = 10;
pcache1EnterMutex();
pcache1.nMinPage += pCache->nMin;
pcache1LeaveMutex();
}
}
return (sqlite3_pcache *)pCache;
}
/*
** Implementation of the sqlite3_pcache.xCachesize method.
**
** Configure the cache_size limit for a cache.
*/
static void pcache1Cachesize(sqlite3_pcache *p, int nMax){
PCache1 *pCache = (PCache1 *)p;
if( pCache->bPurgeable ){
pcache1EnterMutex();
pcache1.nMaxPage += (nMax - pCache->nMax);
pCache->nMax = nMax;
pcache1EnforceMaxPage();
pcache1LeaveMutex();
}
}
/*
** Implementation of the sqlite3_pcache.xPagecount method.
*/
static int pcache1Pagecount(sqlite3_pcache *p){
int n;
pcache1EnterMutex();
n = ((PCache1 *)p)->nPage;
pcache1LeaveMutex();
return n;
}
/*
** Implementation of the sqlite3_pcache.xFetch method.
**
** Fetch a page by key value.
**
** Whether or not a new page may be allocated by this function depends on
** the value of the createFlag argument.
**
** There are three different approaches to obtaining space for a page,
** depending on the value of parameter createFlag (which may be 0, 1 or 2).
**
** 1. Regardless of the value of createFlag, the cache is searched for a
** copy of the requested page. If one is found, it is returned.
**
** 2. If createFlag==0 and the page is not already in the cache, NULL is
** returned.
**
** 3. If createFlag is 1, the cache is marked as purgeable and the page is
** not already in the cache, and if either of the following are true,
** return NULL:
**
** (a) the number of pages pinned by the cache is greater than
** PCache1.nMax, or
** (b) the number of pages pinned by the cache is greater than
** the sum of nMax for all purgeable caches, less the sum of
** nMin for all other purgeable caches.
**
** 4. If none of the first three conditions apply and the cache is marked
** as purgeable, and if one of the following is true:
**
** (a) The number of pages allocated for the cache is already
** PCache1.nMax, or
**
** (b) The number of pages allocated for all purgeable caches is
** already equal to or greater than the sum of nMax for all
** purgeable caches,
**
** then attempt to recycle a page from the LRU list. If it is the right
** size, return the recycled buffer. Otherwise, free the buffer and
** proceed to step 5.
**
** 5. Otherwise, allocate and return a new page buffer.
*/
static void *pcache1Fetch(sqlite3_pcache *p, unsigned int iKey, int createFlag){
unsigned int nPinned;
PCache1 *pCache = (PCache1 *)p;
PgHdr1 *pPage = 0;
pcache1EnterMutex();
if( createFlag==1 ) sqlite3BeginBenignMalloc();
/* Search the hash table for an existing entry. */
if( pCache->nHash>0 ){
unsigned int h = iKey % pCache->nHash;
for(pPage=pCache->apHash[h]; pPage&&pPage->iKey!=iKey; pPage=pPage->pNext);
}
if( pPage || createFlag==0 ){
pcache1PinPage(pPage);
goto fetch_out;
}
/* Step 3 of header comment. */
nPinned = pCache->nPage - pCache->nRecyclable;
if( createFlag==1 && pCache->bPurgeable && (
nPinned>=(pcache1.nMaxPage+pCache->nMin-pcache1.nMinPage)
|| nPinned>=(pCache->nMax)
)){
goto fetch_out;
}
if( pCache->nPage>=pCache->nHash && pcache1ResizeHash(pCache) ){
goto fetch_out;
}
/* Step 4. Try to recycle a page buffer if appropriate. */
if( pCache->bPurgeable && pcache1.pLruTail && (
pCache->nPage>=pCache->nMax-1 || pcache1.nCurrentPage>=pcache1.nMaxPage
)){
pPage = pcache1.pLruTail;
pcache1RemoveFromHash(pPage);
pcache1PinPage(pPage);
if( pPage->pCache->szPage!=pCache->szPage ){
pcache1FreePage(pPage);
pPage = 0;
}else{
pcache1.nCurrentPage -= (pPage->pCache->bPurgeable - pCache->bPurgeable);
}
}
/* Step 5. If a usable page buffer has still not been found,
** attempt to allocate a new one.
*/
if( !pPage ){
pPage = pcache1AllocPage(pCache);
}
if( pPage ){
unsigned int h = iKey % pCache->nHash;
memset(pPage, 0, pCache->szPage + sizeof(PgHdr1));
pCache->nPage++;
pPage->iKey = iKey;
pPage->pNext = pCache->apHash[h];
pPage->pCache = pCache;
pCache->apHash[h] = pPage;
}
fetch_out:
if( pPage && iKey>pCache->iMaxKey ){
pCache->iMaxKey = iKey;
}
if( createFlag==1 ) sqlite3EndBenignMalloc();
pcache1LeaveMutex();
return (pPage ? PGHDR1_TO_PAGE(pPage) : 0);
}
/*
** Implementation of the sqlite3_pcache.xUnpin method.
**
** Mark a page as unpinned (eligible for asynchronous recycling).
*/
static void pcache1Unpin(sqlite3_pcache *p, void *pPg, int reuseUnlikely){
PCache1 *pCache = (PCache1 *)p;
PgHdr1 *pPage = PAGE_TO_PGHDR1(pPg);
pcache1EnterMutex();
/* It is an error to call this function if the page is already
** part of the global LRU list.
*/
assert( pPage->pLruPrev==0 && pPage->pLruNext==0 );
assert( pcache1.pLruHead!=pPage && pcache1.pLruTail!=pPage );
if( reuseUnlikely || pcache1.nCurrentPage>pcache1.nMaxPage ){
pcache1RemoveFromHash(pPage);
pcache1FreePage(pPage);
}else{
/* Add the page to the global LRU list. Normally, the page is added to
** the head of the list (last page to be recycled). However, if the
** reuseUnlikely flag passed to this function is true, the page is added
** to the tail of the list (first page to be recycled).
*/
if( pcache1.pLruHead ){
pcache1.pLruHead->pLruPrev = pPage;
pPage->pLruNext = pcache1.pLruHead;
pcache1.pLruHead = pPage;
}else{
pcache1.pLruTail = pPage;
pcache1.pLruHead = pPage;
}
pCache->nRecyclable++;
}
pcache1LeaveMutex();
}
/*
** Implementation of the sqlite3_pcache.xRekey method.
*/
static void pcache1Rekey(
sqlite3_pcache *p,
void *pPg,
unsigned int iOld,
unsigned int iNew
){
PCache1 *pCache = (PCache1 *)p;
PgHdr1 *pPage = PAGE_TO_PGHDR1(pPg);
PgHdr1 **pp;
unsigned int h;
assert( pPage->iKey==iOld );
pcache1EnterMutex();
h = iOld%pCache->nHash;
pp = &pCache->apHash[h];
while( (*pp)!=pPage ){
pp = &(*pp)->pNext;
}
*pp = pPage->pNext;
h = iNew%pCache->nHash;
pPage->iKey = iNew;
pPage->pNext = pCache->apHash[h];
pCache->apHash[h] = pPage;
if( iNew>pCache->iMaxKey ){
pCache->iMaxKey = iNew;
}
pcache1LeaveMutex();
}
/*
** Implementation of the sqlite3_pcache.xTruncate method.
**
** Discard all unpinned pages in the cache with a page number equal to
** or greater than parameter iLimit. Any pinned pages with a page number
** equal to or greater than iLimit are implicitly unpinned.
*/
static void pcache1Truncate(sqlite3_pcache *p, unsigned int iLimit){
PCache1 *pCache = (PCache1 *)p;
pcache1EnterMutex();
if( iLimit<=pCache->iMaxKey ){
pcache1TruncateUnsafe(pCache, iLimit);
pCache->iMaxKey = iLimit-1;
}
pcache1LeaveMutex();
}
/*
** Implementation of the sqlite3_pcache.xDestroy method.
**
** Destroy a cache allocated using pcache1Create().
*/
static void pcache1Destroy(sqlite3_pcache *p){
PCache1 *pCache = (PCache1 *)p;
pcache1EnterMutex();
pcache1TruncateUnsafe(pCache, 0);
pcache1.nMaxPage -= pCache->nMax;
pcache1.nMinPage -= pCache->nMin;
pcache1EnforceMaxPage();
pcache1LeaveMutex();
sqlite3_free(pCache->apHash);
sqlite3_free(pCache);
}
/*
** This function is called during initialization (sqlite3_initialize()) to
** install the default pluggable cache module, assuming the user has not
** already provided an alternative.
*/
void sqlite3PCacheSetDefault(void){
static sqlite3_pcache_methods defaultMethods = {
0, /* pArg */
pcache1Init, /* xInit */
pcache1Shutdown, /* xShutdown */
pcache1Create, /* xCreate */
pcache1Cachesize, /* xCachesize */
pcache1Pagecount, /* xPagecount */
pcache1Fetch, /* xFetch */
pcache1Unpin, /* xUnpin */
pcache1Rekey, /* xRekey */
pcache1Truncate, /* xTruncate */
pcache1Destroy /* xDestroy */
};
sqlite3_config(SQLITE_CONFIG_PCACHE, &defaultMethods);
}
#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
/*
** This function is called to free superfluous dynamically allocated memory
** held by the pager system. Memory in use by any SQLite pager allocated
** by the current thread may be sqlite3_free()ed.
**
** nReq is the number of bytes of memory required. Once this much has
** been released, the function returns. The return value is the total number
** of bytes of memory released.
*/
int sqlite3PcacheReleaseMemory(int nReq){
int nFree = 0;
if( pcache1.pStart==0 ){
PgHdr1 *p;
pcache1EnterMutex();
while( (nReq<0 || nFree<nReq) && (p=pcache1.pLruTail) ){
nFree += sqlite3MallocSize(p);
pcache1PinPage(p);
pcache1RemoveFromHash(p);
pcache1FreePage(p);
}
pcache1LeaveMutex();
}
return nFree;
}
#endif /* SQLITE_ENABLE_MEMORY_MANAGEMENT */
#ifdef SQLITE_TEST
/*
** This function is used by test procedures to inspect the internal state
** of the global cache.
*/
void sqlite3PcacheStats(
int *pnCurrent, /* OUT: Total number of pages cached */
int *pnMax, /* OUT: Global maximum cache size */
int *pnMin, /* OUT: Sum of PCache1.nMin for purgeable caches */
int *pnRecyclable /* OUT: Total number of pages available for recycling */
){
PgHdr1 *p;
int nRecyclable = 0;
for(p=pcache1.pLruHead; p; p=p->pLruNext){
nRecyclable++;
}
*pnCurrent = pcache1.nCurrentPage;
*pnMax = pcache1.nMaxPage;
*pnMin = pcache1.nMinPage;
*pnRecyclable = nRecyclable;
}
#endif

5473
ppport.h

File diff suppressed because it is too large Load diff

714
pragma.c

File diff suppressed because it is too large Load diff

352
prepare.c
View file

@ -13,20 +13,29 @@
** interface, and routines that contribute to loading the database schema ** interface, and routines that contribute to loading the database schema
** from disk. ** from disk.
** **
** $Id: prepare.c,v 1.52 2007/08/13 14:41:19 danielk1977 Exp $ ** $Id: prepare.c,v 1.104 2009/01/09 02:49:32 drh Exp $
*/ */
#include "sqliteInt.h" #include "sqliteInt.h"
#include "os.h"
#include <ctype.h> #include <ctype.h>
/* /*
** Fill the InitData structure with an error message that indicates ** Fill the InitData structure with an error message that indicates
** that the database is corrupt. ** that the database is corrupt.
*/ */
static void corruptSchema(InitData *pData, const char *zExtra){ static void corruptSchema(
if( !sqlite3MallocFailed() ){ InitData *pData, /* Initialization context */
sqlite3SetString(pData->pzErrMsg, "malformed database schema", const char *zObj, /* Object being parsed at the point of error */
zExtra!=0 && zExtra[0]!=0 ? " - " : (char*)0, zExtra, (char*)0); const char *zExtra /* Error information */
){
sqlite3 *db = pData->db;
if( !db->mallocFailed && (db->flags & SQLITE_RecoveryMode)==0 ){
if( zObj==0 ) zObj = "?";
sqlite3SetString(pData->pzErrMsg, pData->db,
"malformed database schema (%s)", zObj);
if( zExtra && zExtra[0] ){
*pData->pzErrMsg = sqlite3MAppendf(pData->db, *pData->pzErrMsg, "%s - %s",
*pData->pzErrMsg, zExtra);
}
} }
pData->rc = SQLITE_CORRUPT; pData->rc = SQLITE_CORRUPT;
} }
@ -43,26 +52,25 @@ static void corruptSchema(InitData *pData, const char *zExtra){
** argv[2] = SQL text for the CREATE statement. ** argv[2] = SQL text for the CREATE statement.
** **
*/ */
int sqlite3InitCallback(void *pInit, int argc, char **argv, char **azColName){ int sqlite3InitCallback(void *pInit, int argc, char **argv, char **NotUsed){
InitData *pData = (InitData*)pInit; InitData *pData = (InitData*)pInit;
sqlite3 *db = pData->db; sqlite3 *db = pData->db;
int iDb = pData->iDb; int iDb = pData->iDb;
pData->rc = SQLITE_OK; assert( argc==3 );
UNUSED_PARAMETER2(NotUsed, argc);
assert( sqlite3_mutex_held(db->mutex) );
DbClearProperty(db, iDb, DB_Empty); DbClearProperty(db, iDb, DB_Empty);
if( sqlite3MallocFailed() ){ if( db->mallocFailed ){
corruptSchema(pData, 0); corruptSchema(pData, argv[0], 0);
return SQLITE_NOMEM; return SQLITE_NOMEM;
} }
assert( argc==3 ); assert( iDb>=0 && iDb<db->nDb );
if( argv==0 ) return 0; /* Might happen if EMPTY_RESULT_CALLBACKS are on */ if( argv==0 ) return 0; /* Might happen if EMPTY_RESULT_CALLBACKS are on */
if( argv[1]==0 ){ if( argv[1]==0 ){
corruptSchema(pData, 0); corruptSchema(pData, argv[0], 0);
return 1; }else if( argv[2] && argv[2][0] ){
}
assert( iDb>=0 && iDb<db->nDb );
if( argv[2] && argv[2][0] ){
/* Call the parser to process a CREATE TABLE, INDEX or VIEW. /* Call the parser to process a CREATE TABLE, INDEX or VIEW.
** But because db->init.busy is set to 1, no VDBE code is generated ** But because db->init.busy is set to 1, no VDBE code is generated
** or executed. All the parser does is build the internal data ** or executed. All the parser does is build the internal data
@ -70,22 +78,27 @@ int sqlite3InitCallback(void *pInit, int argc, char **argv, char **azColName){
*/ */
char *zErr; char *zErr;
int rc; int rc;
u8 lookasideEnabled;
assert( db->init.busy ); assert( db->init.busy );
db->init.iDb = iDb; db->init.iDb = iDb;
db->init.newTnum = atoi(argv[1]); db->init.newTnum = atoi(argv[1]);
lookasideEnabled = db->lookaside.bEnabled;
db->lookaside.bEnabled = 0;
rc = sqlite3_exec(db, argv[2], 0, 0, &zErr); rc = sqlite3_exec(db, argv[2], 0, 0, &zErr);
db->init.iDb = 0; db->init.iDb = 0;
db->lookaside.bEnabled = lookasideEnabled;
assert( rc!=SQLITE_OK || zErr==0 ); assert( rc!=SQLITE_OK || zErr==0 );
if( SQLITE_OK!=rc ){ if( SQLITE_OK!=rc ){
pData->rc = rc; pData->rc = rc;
if( rc==SQLITE_NOMEM ){ if( rc==SQLITE_NOMEM ){
sqlite3FailedMalloc(); db->mallocFailed = 1;
}else if( rc!=SQLITE_INTERRUPT ){ }else if( rc!=SQLITE_INTERRUPT ){
corruptSchema(pData, zErr); corruptSchema(pData, argv[0], zErr);
} }
sqlite3_free(zErr); sqlite3DbFree(db, zErr);
return 1;
} }
}else if( argv[0]==0 ){
corruptSchema(pData, 0, 0);
}else{ }else{
/* If the SQL column is blank it means this is an index that /* If the SQL column is blank it means this is an index that
** was created to be the PRIMARY KEY or to fulfill a UNIQUE ** was created to be the PRIMARY KEY or to fulfill a UNIQUE
@ -157,6 +170,8 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
assert( iDb>=0 && iDb<db->nDb ); assert( iDb>=0 && iDb<db->nDb );
assert( db->aDb[iDb].pSchema ); assert( db->aDb[iDb].pSchema );
assert( sqlite3_mutex_held(db->mutex) );
assert( iDb==1 || sqlite3BtreeHoldsMutex(db->aDb[iDb].pBt) );
/* zMasterSchema and zInitScript are set to point at the master schema /* zMasterSchema and zInitScript are set to point at the master schema
** and initialisation script appropriate for the database being ** and initialisation script appropriate for the database being
@ -170,24 +185,25 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
zMasterName = SCHEMA_TABLE(iDb); zMasterName = SCHEMA_TABLE(iDb);
/* Construct the schema tables. */ /* Construct the schema tables. */
sqlite3SafetyOff(db);
azArg[0] = zMasterName; azArg[0] = zMasterName;
azArg[1] = "1"; azArg[1] = "1";
azArg[2] = zMasterSchema; azArg[2] = zMasterSchema;
azArg[3] = 0; azArg[3] = 0;
initData.db = db; initData.db = db;
initData.iDb = iDb; initData.iDb = iDb;
initData.rc = SQLITE_OK;
initData.pzErrMsg = pzErrMsg; initData.pzErrMsg = pzErrMsg;
rc = sqlite3InitCallback(&initData, 3, (char **)azArg, 0); (void)sqlite3SafetyOff(db);
if( rc ){ sqlite3InitCallback(&initData, 3, (char **)azArg, 0);
sqlite3SafetyOn(db); (void)sqlite3SafetyOn(db);
return initData.rc; if( initData.rc ){
rc = initData.rc;
goto error_out;
} }
pTab = sqlite3FindTable(db, zMasterName, db->aDb[iDb].zName); pTab = sqlite3FindTable(db, zMasterName, db->aDb[iDb].zName);
if( pTab ){ if( pTab ){
pTab->readOnly = 1; pTab->tabFlags |= TF_Readonly;
} }
sqlite3SafetyOn(db);
/* Create a cursor to hold the database open /* Create a cursor to hold the database open
*/ */
@ -198,10 +214,16 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
} }
return SQLITE_OK; return SQLITE_OK;
} }
rc = sqlite3BtreeCursor(pDb->pBt, MASTER_ROOT, 0, 0, 0, &curMain); curMain = sqlite3MallocZero(sqlite3BtreeCursorSize());
if( !curMain ){
rc = SQLITE_NOMEM;
goto error_out;
}
sqlite3BtreeEnter(pDb->pBt);
rc = sqlite3BtreeCursor(pDb->pBt, MASTER_ROOT, 0, 0, curMain);
if( rc!=SQLITE_OK && rc!=SQLITE_EMPTY ){ if( rc!=SQLITE_OK && rc!=SQLITE_EMPTY ){
sqlite3SetString(pzErrMsg, sqlite3ErrStr(rc), (char*)0); sqlite3SetString(pzErrMsg, db, "%s", sqlite3ErrStr(rc));
return rc; goto initone_error_out;
} }
/* Get the database meta information. /* Get the database meta information.
@ -223,13 +245,12 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
*/ */
if( rc==SQLITE_OK ){ if( rc==SQLITE_OK ){
int i; int i;
for(i=0; rc==SQLITE_OK && i<sizeof(meta)/sizeof(meta[0]); i++){ for(i=0; i<ArraySize(meta); i++){
rc = sqlite3BtreeGetMeta(pDb->pBt, i+1, (u32 *)&meta[i]); rc = sqlite3BtreeGetMeta(pDb->pBt, i+1, (u32 *)&meta[i]);
} if( rc ){
if( rc ){ sqlite3SetString(pzErrMsg, db, "%s", sqlite3ErrStr(rc));
sqlite3SetString(pzErrMsg, sqlite3ErrStr(rc), (char*)0); goto initone_error_out;
sqlite3BtreeCloseCursor(curMain); }
return rc;
} }
}else{ }else{
memset(meta, 0, sizeof(meta)); memset(meta, 0, sizeof(meta));
@ -249,10 +270,10 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
}else{ }else{
/* If opening an attached database, the encoding much match ENC(db) */ /* If opening an attached database, the encoding much match ENC(db) */
if( meta[4]!=ENC(db) ){ if( meta[4]!=ENC(db) ){
sqlite3BtreeCloseCursor(curMain); sqlite3SetString(pzErrMsg, db, "attached databases must use the same"
sqlite3SetString(pzErrMsg, "attached databases must use the same" " text encoding as main database");
" text encoding as main database", (char*)0); rc = SQLITE_ERROR;
return SQLITE_ERROR; goto initone_error_out;
} }
} }
}else{ }else{
@ -260,10 +281,13 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
} }
pDb->pSchema->enc = ENC(db); pDb->pSchema->enc = ENC(db);
size = meta[2]; if( pDb->pSchema->cache_size==0 ){
if( size==0 ){ size = SQLITE_DEFAULT_CACHE_SIZE; } size = meta[2];
pDb->pSchema->cache_size = size; if( size==0 ){ size = SQLITE_DEFAULT_CACHE_SIZE; }
sqlite3BtreeSetCacheSize(pDb->pBt, pDb->pSchema->cache_size); if( size<0 ) size = -size;
pDb->pSchema->cache_size = size;
sqlite3BtreeSetCacheSize(pDb->pBt, pDb->pSchema->cache_size);
}
/* /*
** file_format==1 Version 3.0.0. ** file_format==1 Version 3.0.0.
@ -271,16 +295,24 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
** file_format==3 Version 3.1.4. // ditto but with non-NULL defaults ** file_format==3 Version 3.1.4. // ditto but with non-NULL defaults
** file_format==4 Version 3.3.0. // DESC indices. Boolean constants ** file_format==4 Version 3.3.0. // DESC indices. Boolean constants
*/ */
pDb->pSchema->file_format = meta[1]; pDb->pSchema->file_format = (u8)meta[1];
if( pDb->pSchema->file_format==0 ){ if( pDb->pSchema->file_format==0 ){
pDb->pSchema->file_format = 1; pDb->pSchema->file_format = 1;
} }
if( pDb->pSchema->file_format>SQLITE_MAX_FILE_FORMAT ){ if( pDb->pSchema->file_format>SQLITE_MAX_FILE_FORMAT ){
sqlite3BtreeCloseCursor(curMain); sqlite3SetString(pzErrMsg, db, "unsupported file format");
sqlite3SetString(pzErrMsg, "unsupported file format", (char*)0); rc = SQLITE_ERROR;
return SQLITE_ERROR; goto initone_error_out;
} }
/* Ticket #2804: When we open a database in the newer file format,
** clear the legacy_file_format pragma flag so that a VACUUM will
** not downgrade the database and thus invalidate any descending
** indices that the user might have created.
*/
if( iDb==0 && meta[1]>=4 ){
db->flags &= ~SQLITE_LegacyFileFmt;
}
/* Read the schema information out of the schema tables /* Read the schema information out of the schema tables
*/ */
@ -290,23 +322,31 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
rc = SQLITE_OK; rc = SQLITE_OK;
}else{ }else{
char *zSql; char *zSql;
zSql = sqlite3MPrintf( zSql = sqlite3MPrintf(db,
"SELECT name, rootpage, sql FROM '%q'.%s", "SELECT name, rootpage, sql FROM '%q'.%s",
db->aDb[iDb].zName, zMasterName); db->aDb[iDb].zName, zMasterName);
sqlite3SafetyOff(db); (void)sqlite3SafetyOff(db);
rc = sqlite3_exec(db, zSql, sqlite3InitCallback, &initData, 0); #ifndef SQLITE_OMIT_AUTHORIZATION
if( rc==SQLITE_ABORT ) rc = initData.rc; {
sqlite3SafetyOn(db); int (*xAuth)(void*,int,const char*,const char*,const char*,const char*);
sqliteFree(zSql); xAuth = db->xAuth;
db->xAuth = 0;
#endif
rc = sqlite3_exec(db, zSql, sqlite3InitCallback, &initData, 0);
#ifndef SQLITE_OMIT_AUTHORIZATION
db->xAuth = xAuth;
}
#endif
if( rc==SQLITE_OK ) rc = initData.rc;
(void)sqlite3SafetyOn(db);
sqlite3DbFree(db, zSql);
#ifndef SQLITE_OMIT_ANALYZE #ifndef SQLITE_OMIT_ANALYZE
if( rc==SQLITE_OK ){ if( rc==SQLITE_OK ){
sqlite3AnalysisLoad(db, iDb); sqlite3AnalysisLoad(db, iDb);
} }
#endif #endif
sqlite3BtreeCloseCursor(curMain);
} }
if( sqlite3MallocFailed() ){ if( db->mallocFailed ){
/* sqlite3SetString(pzErrMsg, "out of memory", (char*)0); */
rc = SQLITE_NOMEM; rc = SQLITE_NOMEM;
sqlite3ResetInternalSchema(db, 0); sqlite3ResetInternalSchema(db, 0);
} }
@ -317,11 +357,25 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
** will attempt to compile the supplied statement against whatever subset ** will attempt to compile the supplied statement against whatever subset
** of the schema was loaded before the error occured. The primary ** of the schema was loaded before the error occured. The primary
** purpose of this is to allow access to the sqlite_master table ** purpose of this is to allow access to the sqlite_master table
** even when it's contents have been corrupted. ** even when its contents have been corrupted.
*/ */
DbSetProperty(db, iDb, DB_SchemaLoaded); DbSetProperty(db, iDb, DB_SchemaLoaded);
rc = SQLITE_OK; rc = SQLITE_OK;
} }
/* Jump here for an error that occurs after successfully allocating
** curMain and calling sqlite3BtreeEnter(). For an error that occurs
** before that point, jump to error_out.
*/
initone_error_out:
sqlite3BtreeCloseCursor(curMain);
sqlite3_free(curMain);
sqlite3BtreeLeave(pDb->pBt);
error_out:
if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ){
db->mallocFailed = 1;
}
return rc; return rc;
} }
@ -339,6 +393,7 @@ int sqlite3Init(sqlite3 *db, char **pzErrMsg){
int i, rc; int i, rc;
int commit_internal = !(db->flags&SQLITE_InternChanges); int commit_internal = !(db->flags&SQLITE_InternChanges);
assert( sqlite3_mutex_held(db->mutex) );
if( db->init.busy ) return SQLITE_OK; if( db->init.busy ) return SQLITE_OK;
rc = SQLITE_OK; rc = SQLITE_OK;
db->init.busy = 1; db->init.busy = 1;
@ -378,6 +433,7 @@ int sqlite3Init(sqlite3 *db, char **pzErrMsg){
int sqlite3ReadSchema(Parse *pParse){ int sqlite3ReadSchema(Parse *pParse){
int rc = SQLITE_OK; int rc = SQLITE_OK;
sqlite3 *db = pParse->db; sqlite3 *db = pParse->db;
assert( sqlite3_mutex_held(db->mutex) );
if( !db->init.busy ){ if( !db->init.busy ){
rc = sqlite3Init(db, &pParse->zErrMsg); rc = sqlite3Init(db, &pParse->zErrMsg);
} }
@ -400,19 +456,32 @@ static int schemaIsValid(sqlite3 *db){
int cookie; int cookie;
int allOk = 1; int allOk = 1;
for(iDb=0; allOk && iDb<db->nDb; iDb++){ curTemp = (BtCursor *)sqlite3Malloc(sqlite3BtreeCursorSize());
Btree *pBt; if( curTemp ){
pBt = db->aDb[iDb].pBt; assert( sqlite3_mutex_held(db->mutex) );
if( pBt==0 ) continue; for(iDb=0; allOk && iDb<db->nDb; iDb++){
rc = sqlite3BtreeCursor(pBt, MASTER_ROOT, 0, 0, 0, &curTemp); Btree *pBt;
if( rc==SQLITE_OK ){ pBt = db->aDb[iDb].pBt;
rc = sqlite3BtreeGetMeta(pBt, 1, (u32 *)&cookie); if( pBt==0 ) continue;
if( rc==SQLITE_OK && cookie!=db->aDb[iDb].pSchema->schema_cookie ){ memset(curTemp, 0, sqlite3BtreeCursorSize());
allOk = 0; rc = sqlite3BtreeCursor(pBt, MASTER_ROOT, 0, 0, curTemp);
if( rc==SQLITE_OK ){
rc = sqlite3BtreeGetMeta(pBt, 1, (u32 *)&cookie);
if( rc==SQLITE_OK && cookie!=db->aDb[iDb].pSchema->schema_cookie ){
allOk = 0;
}
sqlite3BtreeCloseCursor(curTemp);
}
if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ){
db->mallocFailed = 1;
} }
sqlite3BtreeCloseCursor(curTemp);
} }
sqlite3_free(curTemp);
}else{
allOk = 0;
db->mallocFailed = 1;
} }
return allOk; return allOk;
} }
@ -432,17 +501,18 @@ int sqlite3SchemaToIndex(sqlite3 *db, Schema *pSchema){
** function should never be used. ** function should never be used.
** **
** We return -1000000 instead of the more usual -1 simply because using ** We return -1000000 instead of the more usual -1 simply because using
** -1000000 as incorrectly using -1000000 index into db->aDb[] is much ** -1000000 as the incorrect index into db->aDb[] is much
** more likely to cause a segfault than -1 (of course there are assert() ** more likely to cause a segfault than -1 (of course there are assert()
** statements too, but it never hurts to play the odds). ** statements too, but it never hurts to play the odds).
*/ */
assert( sqlite3_mutex_held(db->mutex) );
if( pSchema ){ if( pSchema ){
for(i=0; i<db->nDb; i++){ for(i=0; ALWAYS(i<db->nDb); i++){
if( db->aDb[i].pSchema==pSchema ){ if( db->aDb[i].pSchema==pSchema ){
break; break;
} }
} }
assert( i>=0 &&i>=0 && i<db->nDb ); assert( i>=0 && i<db->nDb );
} }
return i; return i;
} }
@ -450,7 +520,7 @@ int sqlite3SchemaToIndex(sqlite3 *db, Schema *pSchema){
/* /*
** Compile the UTF-8 encoded SQL statement zSql into a statement handle. ** Compile the UTF-8 encoded SQL statement zSql into a statement handle.
*/ */
int sqlite3Prepare( static int sqlite3Prepare(
sqlite3 *db, /* Database handle. */ sqlite3 *db, /* Database handle. */
const char *zSql, /* UTF-8 encoded SQL statement. */ const char *zSql, /* UTF-8 encoded SQL statement. */
int nBytes, /* Length of zSql in bytes. */ int nBytes, /* Length of zSql in bytes. */
@ -463,46 +533,53 @@ int sqlite3Prepare(
int rc = SQLITE_OK; int rc = SQLITE_OK;
int i; int i;
/* Assert that malloc() has not failed */
assert( !sqlite3MallocFailed() );
assert( ppStmt ); assert( ppStmt );
*ppStmt = 0; *ppStmt = 0;
if( sqlite3SafetyOn(db) ){ if( sqlite3SafetyOn(db) ){
return SQLITE_MISUSE; return SQLITE_MISUSE;
} }
assert( !db->mallocFailed );
assert( sqlite3_mutex_held(db->mutex) );
/* If any attached database schemas are locked, do not proceed with /* If any attached database schemas are locked, do not proceed with
** compilation. Instead return SQLITE_LOCKED immediately. ** compilation. Instead return SQLITE_LOCKED immediately.
*/ */
for(i=0; i<db->nDb; i++) { for(i=0; i<db->nDb; i++) {
Btree *pBt = db->aDb[i].pBt; Btree *pBt = db->aDb[i].pBt;
if( pBt && sqlite3BtreeSchemaLocked(pBt) ){ if( pBt ){
const char *zDb = db->aDb[i].zName; rc = sqlite3BtreeSchemaLocked(pBt);
sqlite3Error(db, SQLITE_LOCKED, "database schema is locked: %s", zDb); if( rc ){
sqlite3SafetyOff(db); const char *zDb = db->aDb[i].zName;
return SQLITE_LOCKED; sqlite3Error(db, SQLITE_LOCKED, "database schema is locked: %s", zDb);
(void)sqlite3SafetyOff(db);
return sqlite3ApiExit(db, SQLITE_LOCKED);
}
} }
} }
memset(&sParse, 0, sizeof(sParse)); memset(&sParse, 0, sizeof(sParse));
sParse.db = db; sParse.db = db;
if( nBytes>=0 && zSql[nBytes]!=0 ){ if( nBytes>=0 && (nBytes==0 || zSql[nBytes-1]!=0) ){
char *zSqlCopy; char *zSqlCopy;
if( nBytes>SQLITE_MAX_SQL_LENGTH ){ int mxLen = db->aLimit[SQLITE_LIMIT_SQL_LENGTH];
return SQLITE_TOOBIG; if( nBytes>mxLen ){
sqlite3Error(db, SQLITE_TOOBIG, "statement too long");
(void)sqlite3SafetyOff(db);
return sqlite3ApiExit(db, SQLITE_TOOBIG);
} }
zSqlCopy = sqlite3StrNDup(zSql, nBytes); zSqlCopy = sqlite3DbStrNDup(db, zSql, nBytes);
if( zSqlCopy ){ if( zSqlCopy ){
sqlite3RunParser(&sParse, zSqlCopy, &zErrMsg); sqlite3RunParser(&sParse, zSqlCopy, &zErrMsg);
sqliteFree(zSqlCopy); sqlite3DbFree(db, zSqlCopy);
sParse.zTail = &zSql[sParse.zTail-zSqlCopy];
}else{
sParse.zTail = &zSql[nBytes];
} }
sParse.zTail = &zSql[nBytes];
}else{ }else{
sqlite3RunParser(&sParse, zSql, &zErrMsg); sqlite3RunParser(&sParse, zSql, &zErrMsg);
} }
if( sqlite3MallocFailed() ){ if( db->mallocFailed ){
sParse.rc = SQLITE_NOMEM; sParse.rc = SQLITE_NOMEM;
} }
if( sParse.rc==SQLITE_DONE ) sParse.rc = SQLITE_OK; if( sParse.rc==SQLITE_DONE ) sParse.rc = SQLITE_OK;
@ -512,7 +589,7 @@ int sqlite3Prepare(
if( sParse.rc==SQLITE_SCHEMA ){ if( sParse.rc==SQLITE_SCHEMA ){
sqlite3ResetInternalSchema(db, 0); sqlite3ResetInternalSchema(db, 0);
} }
if( sqlite3MallocFailed() ){ if( db->mallocFailed ){
sParse.rc = SQLITE_NOMEM; sParse.rc = SQLITE_NOMEM;
} }
if( pzTail ){ if( pzTail ){
@ -524,16 +601,19 @@ int sqlite3Prepare(
if( rc==SQLITE_OK && sParse.pVdbe && sParse.explain ){ if( rc==SQLITE_OK && sParse.pVdbe && sParse.explain ){
if( sParse.explain==2 ){ if( sParse.explain==2 ){
sqlite3VdbeSetNumCols(sParse.pVdbe, 3); sqlite3VdbeSetNumCols(sParse.pVdbe, 3);
sqlite3VdbeSetColName(sParse.pVdbe, 0, COLNAME_NAME, "order", P3_STATIC); sqlite3VdbeSetColName(sParse.pVdbe, 0, COLNAME_NAME, "order", SQLITE_STATIC);
sqlite3VdbeSetColName(sParse.pVdbe, 1, COLNAME_NAME, "from", P3_STATIC); sqlite3VdbeSetColName(sParse.pVdbe, 1, COLNAME_NAME, "from", SQLITE_STATIC);
sqlite3VdbeSetColName(sParse.pVdbe, 2, COLNAME_NAME, "detail", P3_STATIC); sqlite3VdbeSetColName(sParse.pVdbe, 2, COLNAME_NAME, "detail", SQLITE_STATIC);
}else{ }else{
sqlite3VdbeSetNumCols(sParse.pVdbe, 5); sqlite3VdbeSetNumCols(sParse.pVdbe, 8);
sqlite3VdbeSetColName(sParse.pVdbe, 0, COLNAME_NAME, "addr", P3_STATIC); sqlite3VdbeSetColName(sParse.pVdbe, 0, COLNAME_NAME, "addr", SQLITE_STATIC);
sqlite3VdbeSetColName(sParse.pVdbe, 1, COLNAME_NAME, "opcode", P3_STATIC); sqlite3VdbeSetColName(sParse.pVdbe, 1, COLNAME_NAME, "opcode", SQLITE_STATIC);
sqlite3VdbeSetColName(sParse.pVdbe, 2, COLNAME_NAME, "p1", P3_STATIC); sqlite3VdbeSetColName(sParse.pVdbe, 2, COLNAME_NAME, "p1", SQLITE_STATIC);
sqlite3VdbeSetColName(sParse.pVdbe, 3, COLNAME_NAME, "p2", P3_STATIC); sqlite3VdbeSetColName(sParse.pVdbe, 3, COLNAME_NAME, "p2", SQLITE_STATIC);
sqlite3VdbeSetColName(sParse.pVdbe, 4, COLNAME_NAME, "p3", P3_STATIC); sqlite3VdbeSetColName(sParse.pVdbe, 4, COLNAME_NAME, "p3", SQLITE_STATIC);
sqlite3VdbeSetColName(sParse.pVdbe, 5, COLNAME_NAME, "p4", SQLITE_STATIC);
sqlite3VdbeSetColName(sParse.pVdbe, 6, COLNAME_NAME, "p5", SQLITE_STATIC);
sqlite3VdbeSetColName(sParse.pVdbe, 7, COLNAME_NAME, "comment", SQLITE_STATIC);
} }
} }
#endif #endif
@ -543,9 +623,9 @@ int sqlite3Prepare(
} }
if( saveSqlFlag ){ if( saveSqlFlag ){
sqlite3VdbeSetSql(sParse.pVdbe, zSql, sParse.zTail - zSql); sqlite3VdbeSetSql(sParse.pVdbe, zSql, (int)(sParse.zTail - zSql));
} }
if( rc!=SQLITE_OK || sqlite3MallocFailed() ){ if( rc!=SQLITE_OK || db->mallocFailed ){
sqlite3_finalize((sqlite3_stmt*)sParse.pVdbe); sqlite3_finalize((sqlite3_stmt*)sParse.pVdbe);
assert(!(*ppStmt)); assert(!(*ppStmt));
}else{ }else{
@ -554,16 +634,34 @@ int sqlite3Prepare(
if( zErrMsg ){ if( zErrMsg ){
sqlite3Error(db, rc, "%s", zErrMsg); sqlite3Error(db, rc, "%s", zErrMsg);
sqliteFree(zErrMsg); sqlite3DbFree(db, zErrMsg);
}else{ }else{
sqlite3Error(db, rc, 0); sqlite3Error(db, rc, 0);
} }
rc = sqlite3ApiExit(db, rc); rc = sqlite3ApiExit(db, rc);
sqlite3ReleaseThreadData();
assert( (rc&db->errMask)==rc ); assert( (rc&db->errMask)==rc );
return rc; return rc;
} }
static int sqlite3LockAndPrepare(
sqlite3 *db, /* Database handle. */
const char *zSql, /* UTF-8 encoded SQL statement. */
int nBytes, /* Length of zSql in bytes. */
int saveSqlFlag, /* True to copy SQL text into the sqlite3_stmt */
sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */
const char **pzTail /* OUT: End of parsed string */
){
int rc;
if( !sqlite3SafetyCheckOk(db) ){
return SQLITE_MISUSE;
}
sqlite3_mutex_enter(db->mutex);
sqlite3BtreeEnterAll(db);
rc = sqlite3Prepare(db, zSql, nBytes, saveSqlFlag, ppStmt, pzTail);
sqlite3BtreeLeaveAll(db);
sqlite3_mutex_leave(db->mutex);
return rc;
}
/* /*
** Rerun the compilation of a statement after a schema change. ** Rerun the compilation of a statement after a schema change.
@ -575,21 +673,24 @@ int sqlite3Reprepare(Vdbe *p){
sqlite3_stmt *pNew; sqlite3_stmt *pNew;
const char *zSql; const char *zSql;
sqlite3 *db; sqlite3 *db;
zSql = sqlite3VdbeGetSql(p); assert( sqlite3_mutex_held(sqlite3VdbeDb(p)->mutex) );
if( zSql==0 ){ zSql = sqlite3_sql((sqlite3_stmt *)p);
return 0; assert( zSql!=0 ); /* Reprepare only called for prepare_v2() statements */
}
db = sqlite3VdbeDb(p); db = sqlite3VdbeDb(p);
rc = sqlite3Prepare(db, zSql, -1, 0, &pNew, 0); assert( sqlite3_mutex_held(db->mutex) );
rc = sqlite3LockAndPrepare(db, zSql, -1, 0, &pNew, 0);
if( rc ){ if( rc ){
if( rc==SQLITE_NOMEM ){
db->mallocFailed = 1;
}
assert( pNew==0 ); assert( pNew==0 );
return 0; return 0;
}else{ }else{
assert( pNew!=0 ); assert( pNew!=0 );
} }
sqlite3VdbeSwap((Vdbe*)pNew, p); sqlite3VdbeSwap((Vdbe*)pNew, p);
sqlite3_transfer_bindings(pNew, (sqlite3_stmt*)p); sqlite3TransferBindings(pNew, (sqlite3_stmt*)p);
sqlite3VdbeResetStepResult((Vdbe*)pNew); sqlite3VdbeResetStepResult((Vdbe*)pNew);
sqlite3VdbeFinalize((Vdbe*)pNew); sqlite3VdbeFinalize((Vdbe*)pNew);
return 1; return 1;
@ -611,7 +712,10 @@ int sqlite3_prepare(
sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */ sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */
const char **pzTail /* OUT: End of parsed string */ const char **pzTail /* OUT: End of parsed string */
){ ){
return sqlite3Prepare(db,zSql,nBytes,0,ppStmt,pzTail); int rc;
rc = sqlite3LockAndPrepare(db,zSql,nBytes,0,ppStmt,pzTail);
assert( rc==SQLITE_OK || ppStmt==0 || *ppStmt==0 ); /* VERIFY: F13021 */
return rc;
} }
int sqlite3_prepare_v2( int sqlite3_prepare_v2(
sqlite3 *db, /* Database handle. */ sqlite3 *db, /* Database handle. */
@ -620,7 +724,10 @@ int sqlite3_prepare_v2(
sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */ sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */
const char **pzTail /* OUT: End of parsed string */ const char **pzTail /* OUT: End of parsed string */
){ ){
return sqlite3Prepare(db,zSql,nBytes,1,ppStmt,pzTail); int rc;
rc = sqlite3LockAndPrepare(db,zSql,nBytes,1,ppStmt,pzTail);
assert( rc==SQLITE_OK || ppStmt==0 || *ppStmt==0 ); /* VERIFY: F13021 */
return rc;
} }
@ -644,12 +751,13 @@ static int sqlite3Prepare16(
const char *zTail8 = 0; const char *zTail8 = 0;
int rc = SQLITE_OK; int rc = SQLITE_OK;
if( sqlite3SafetyCheck(db) ){ if( !sqlite3SafetyCheckOk(db) ){
return SQLITE_MISUSE; return SQLITE_MISUSE;
} }
zSql8 = sqlite3Utf16to8(zSql, nBytes); sqlite3_mutex_enter(db->mutex);
zSql8 = sqlite3Utf16to8(db, zSql, nBytes);
if( zSql8 ){ if( zSql8 ){
rc = sqlite3Prepare(db, zSql8, -1, saveSqlFlag, ppStmt, &zTail8); rc = sqlite3LockAndPrepare(db, zSql8, -1, saveSqlFlag, ppStmt, &zTail8);
} }
if( zTail8 && pzTail ){ if( zTail8 && pzTail ){
@ -658,11 +766,13 @@ static int sqlite3Prepare16(
** characters between zSql8 and zTail8, and then returning a pointer ** characters between zSql8 and zTail8, and then returning a pointer
** the same number of characters into the UTF-16 string. ** the same number of characters into the UTF-16 string.
*/ */
int chars_parsed = sqlite3Utf8CharLen(zSql8, zTail8-zSql8); int chars_parsed = sqlite3Utf8CharLen(zSql8, (int)(zTail8-zSql8));
*pzTail = (u8 *)zSql + sqlite3Utf16ByteLen(zSql, chars_parsed); *pzTail = (u8 *)zSql + sqlite3Utf16ByteLen(zSql, chars_parsed);
} }
sqliteFree(zSql8); sqlite3DbFree(db, zSql8);
return sqlite3ApiExit(db, rc); rc = sqlite3ApiExit(db, rc);
sqlite3_mutex_leave(db->mutex);
return rc;
} }
/* /*
@ -680,7 +790,10 @@ int sqlite3_prepare16(
sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */ sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */
const void **pzTail /* OUT: End of parsed string */ const void **pzTail /* OUT: End of parsed string */
){ ){
return sqlite3Prepare16(db,zSql,nBytes,0,ppStmt,pzTail); int rc;
rc = sqlite3Prepare16(db,zSql,nBytes,0,ppStmt,pzTail);
assert( rc==SQLITE_OK || ppStmt==0 || *ppStmt==0 ); /* VERIFY: F13021 */
return rc;
} }
int sqlite3_prepare16_v2( int sqlite3_prepare16_v2(
sqlite3 *db, /* Database handle. */ sqlite3 *db, /* Database handle. */
@ -689,7 +802,10 @@ int sqlite3_prepare16_v2(
sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */ sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */
const void **pzTail /* OUT: End of parsed string */ const void **pzTail /* OUT: End of parsed string */
){ ){
return sqlite3Prepare16(db,zSql,nBytes,1,ppStmt,pzTail); int rc;
rc = sqlite3Prepare16(db,zSql,nBytes,1,ppStmt,pzTail);
assert( rc==SQLITE_OK || ppStmt==0 || *ppStmt==0 ); /* VERIFY: F13021 */
return rc;
} }
#endif /* SQLITE_OMIT_UTF16 */ #endif /* SQLITE_OMIT_UTF16 */

407
printf.c
View file

@ -5,6 +5,8 @@
** an historical reference. Most of the "enhancements" have been backed ** an historical reference. Most of the "enhancements" have been backed
** out so that the functionality is now the same as standard printf(). ** out so that the functionality is now the same as standard printf().
** **
** $Id: printf.c,v 1.99 2008/12/10 19:26:24 drh Exp $
**
************************************************************************** **************************************************************************
** **
** The following modules is an enhanced replacement for the "printf" subroutines ** The following modules is an enhanced replacement for the "printf" subroutines
@ -51,7 +53,6 @@
** **
*/ */
#include "sqliteInt.h" #include "sqliteInt.h"
#include <math.h>
/* /*
** Conversion types fall into various categories as defined by the ** Conversion types fall into various categories as defined by the
@ -67,14 +68,14 @@
#define etPERCENT 8 /* Percent symbol. %% */ #define etPERCENT 8 /* Percent symbol. %% */
#define etCHARX 9 /* Characters. %c */ #define etCHARX 9 /* Characters. %c */
/* The rest are extensions, not normally found in printf() */ /* The rest are extensions, not normally found in printf() */
#define etCHARLIT 10 /* Literal characters. %' */ #define etSQLESCAPE 10 /* Strings with '\'' doubled. %q */
#define etSQLESCAPE 11 /* Strings with '\'' doubled. %q */ #define etSQLESCAPE2 11 /* Strings with '\'' doubled and enclosed in '',
#define etSQLESCAPE2 12 /* Strings with '\'' doubled and enclosed in '',
NULL pointers replaced by SQL NULL. %Q */ NULL pointers replaced by SQL NULL. %Q */
#define etTOKEN 13 /* a pointer to a Token structure */ #define etTOKEN 12 /* a pointer to a Token structure */
#define etSRCLIST 14 /* a pointer to a SrcList */ #define etSRCLIST 13 /* a pointer to a SrcList */
#define etPOINTER 15 /* The %p conversion */ #define etPOINTER 14 /* The %p conversion */
#define etSQLESCAPE3 16 /* %w -> Strings with '\"' doubled */ #define etSQLESCAPE3 15 /* %w -> Strings with '\"' doubled */
#define etORDINAL 16 /* %r -> 1st, 2nd, 3rd, 4th, etc. English only */
/* /*
@ -113,7 +114,7 @@ static const et_info fmtinfo[] = {
{ 'd', 10, 1, etRADIX, 0, 0 }, { 'd', 10, 1, etRADIX, 0, 0 },
{ 's', 0, 4, etSTRING, 0, 0 }, { 's', 0, 4, etSTRING, 0, 0 },
{ 'g', 0, 1, etGENERIC, 30, 0 }, { 'g', 0, 1, etGENERIC, 30, 0 },
{ 'z', 0, 6, etDYNSTRING, 0, 0 }, { 'z', 0, 4, etDYNSTRING, 0, 0 },
{ 'q', 0, 4, etSQLESCAPE, 0, 0 }, { 'q', 0, 4, etSQLESCAPE, 0, 0 },
{ 'Q', 0, 4, etSQLESCAPE2, 0, 0 }, { 'Q', 0, 4, etSQLESCAPE2, 0, 0 },
{ 'w', 0, 4, etSQLESCAPE3, 0, 0 }, { 'w', 0, 4, etSQLESCAPE3, 0, 0 },
@ -134,8 +135,8 @@ static const et_info fmtinfo[] = {
{ 'p', 16, 0, etPOINTER, 0, 1 }, { 'p', 16, 0, etPOINTER, 0, 1 },
{ 'T', 0, 2, etTOKEN, 0, 0 }, { 'T', 0, 2, etTOKEN, 0, 0 },
{ 'S', 0, 2, etSRCLIST, 0, 0 }, { 'S', 0, 2, etSRCLIST, 0, 0 },
{ 'r', 10, 3, etORDINAL, 0, 0 },
}; };
#define etNINFO (sizeof(fmtinfo)/sizeof(fmtinfo[0]))
/* /*
** If SQLITE_OMIT_FLOATING_POINT is defined, then none of the floating point ** If SQLITE_OMIT_FLOATING_POINT is defined, then none of the floating point
@ -155,7 +156,7 @@ static const et_info fmtinfo[] = {
** 16 (the number of significant digits in a 64-bit float) '0' is ** 16 (the number of significant digits in a 64-bit float) '0' is
** always returned. ** always returned.
*/ */
static int et_getdigit(LONGDOUBLE_TYPE *val, int *cnt){ static char et_getdigit(LONGDOUBLE_TYPE *val, int *cnt){
int digit; int digit;
LONGDOUBLE_TYPE d; LONGDOUBLE_TYPE d;
if( (*cnt)++ >= 16 ) return '0'; if( (*cnt)++ >= 16 ) return '0';
@ -163,10 +164,24 @@ static int et_getdigit(LONGDOUBLE_TYPE *val, int *cnt){
d = digit; d = digit;
digit += '0'; digit += '0';
*val = (*val - d)*10.0; *val = (*val - d)*10.0;
return digit; return (char)digit;
} }
#endif /* SQLITE_OMIT_FLOATING_POINT */ #endif /* SQLITE_OMIT_FLOATING_POINT */
/*
** Append N space characters to the given string buffer.
*/
static void appendSpace(StrAccum *pAccum, int N){
static const char zSpaces[] = " ";
while( N>=(int)sizeof(zSpaces)-1 ){
sqlite3StrAccumAppend(pAccum, zSpaces, sizeof(zSpaces)-1);
N -= sizeof(zSpaces)-1;
}
if( N>0 ){
sqlite3StrAccumAppend(pAccum, zSpaces, N);
}
}
/* /*
** On machines with a small stack size, you can redefine the ** On machines with a small stack size, you can redefine the
** SQLITE_PRINT_BUF_SIZE to be less than 350. But beware - for ** SQLITE_PRINT_BUF_SIZE to be less than 350. But beware - for
@ -204,9 +219,8 @@ static int et_getdigit(LONGDOUBLE_TYPE *val, int *cnt){
** seems to make a big difference in determining how fast this beast ** seems to make a big difference in determining how fast this beast
** will run. ** will run.
*/ */
static int vxprintf( void sqlite3VXPrintf(
void (*func)(void*,const char*,int), /* Consumer of text */ StrAccum *pAccum, /* Accumulate results here */
void *arg, /* First argument to the consumer */
int useExtended, /* Allow extended %-conversions */ int useExtended, /* Allow extended %-conversions */
const char *fmt, /* Format string */ const char *fmt, /* Format string */
va_list ap /* arguments */ va_list ap /* arguments */
@ -216,7 +230,6 @@ static int vxprintf(
int precision; /* Precision of the current field */ int precision; /* Precision of the current field */
int length; /* Length of the field */ int length; /* Length of the field */
int idx; /* A general purpose loop counter */ int idx; /* A general purpose loop counter */
int count; /* Total number of characters output */
int width; /* Width of the current field */ int width; /* Width of the current field */
etByte flag_leftjustify; /* True if "-" flag is present */ etByte flag_leftjustify; /* True if "-" flag is present */
etByte flag_plussign; /* True if "+" flag is present */ etByte flag_plussign; /* True if "+" flag is present */
@ -232,12 +245,8 @@ static int vxprintf(
const et_info *infop; /* Pointer to the appropriate info structure */ const et_info *infop; /* Pointer to the appropriate info structure */
char buf[etBUFSIZE]; /* Conversion buffer */ char buf[etBUFSIZE]; /* Conversion buffer */
char prefix; /* Prefix character. "+" or "-" or " " or '\0'. */ char prefix; /* Prefix character. "+" or "-" or " " or '\0'. */
etByte errorflag = 0; /* True if an error is encountered */ etByte xtype = 0; /* Conversion paradigm */
etByte xtype; /* Conversion paradigm */
char *zExtra; /* Extra memory used for etTCLESCAPE conversions */ char *zExtra; /* Extra memory used for etTCLESCAPE conversions */
static const char spaces[] =
" ";
#define etSPACESIZE (sizeof(spaces)-1)
#ifndef SQLITE_OMIT_FLOATING_POINT #ifndef SQLITE_OMIT_FLOATING_POINT
int exp, e2; /* exponent of real numbers */ int exp, e2; /* exponent of real numbers */
double rounder; /* Used for rounding floating point values */ double rounder; /* Used for rounding floating point values */
@ -247,8 +256,7 @@ static int vxprintf(
int nsd; /* Number of significant digits returned */ int nsd; /* Number of significant digits returned */
#endif #endif
func(arg,"",0); length = 0;
count = length = 0;
bufpt = 0; bufpt = 0;
for(; (c=(*fmt))!=0; ++fmt){ for(; (c=(*fmt))!=0; ++fmt){
if( c!='%' ){ if( c!='%' ){
@ -256,14 +264,11 @@ static int vxprintf(
bufpt = (char *)fmt; bufpt = (char *)fmt;
amt = 1; amt = 1;
while( (c=(*++fmt))!='%' && c!=0 ) amt++; while( (c=(*++fmt))!='%' && c!=0 ) amt++;
(*func)(arg,bufpt,amt); sqlite3StrAccumAppend(pAccum, bufpt, amt);
count += amt;
if( c==0 ) break; if( c==0 ) break;
} }
if( (c=(*++fmt))==0 ){ if( (c=(*++fmt))==0 ){
errorflag = 1; sqlite3StrAccumAppend(pAccum, "%", 1);
(*func)(arg,"%",1);
count++;
break; break;
} }
/* Find out what flags are present */ /* Find out what flags are present */
@ -331,20 +336,20 @@ static int vxprintf(
} }
/* Fetch the info entry for the field */ /* Fetch the info entry for the field */
infop = 0; infop = 0;
for(idx=0; idx<etNINFO; idx++){ for(idx=0; idx<ArraySize(fmtinfo); idx++){
if( c==fmtinfo[idx].fmttype ){ if( c==fmtinfo[idx].fmttype ){
infop = &fmtinfo[idx]; infop = &fmtinfo[idx];
if( useExtended || (infop->flags & FLAG_INTERN)==0 ){ if( useExtended || (infop->flags & FLAG_INTERN)==0 ){
xtype = infop->type; xtype = infop->type;
}else{ }else{
return -1; return;
} }
break; break;
} }
} }
zExtra = 0; zExtra = 0;
if( infop==0 ){ if( infop==0 ){
return -1; return;
} }
@ -379,6 +384,7 @@ static int vxprintf(
flag_longlong = sizeof(char*)==sizeof(i64); flag_longlong = sizeof(char*)==sizeof(i64);
flag_long = sizeof(char*)==sizeof(long int); flag_long = sizeof(char*)==sizeof(long int);
/* Fall through into the next case */ /* Fall through into the next case */
case etORDINAL:
case etRADIX: case etRADIX:
if( infop->flags & FLAG_SIGNED ){ if( infop->flags & FLAG_SIGNED ){
i64 v; i64 v;
@ -405,6 +411,16 @@ static int vxprintf(
precision = width-(prefix!=0); precision = width-(prefix!=0);
} }
bufpt = &buf[etBUFSIZE-1]; bufpt = &buf[etBUFSIZE-1];
if( xtype==etORDINAL ){
static const char zOrd[] = "thstndrd";
int x = (int)(longvalue % 10);
if( x>=4 || (longvalue/10)%10==1 ){
x = 0;
}
buf[etBUFSIZE-3] = zOrd[x*2];
buf[etBUFSIZE-2] = zOrd[x*2+1];
bufpt -= 2;
}
{ {
register const char *cset; /* Use registers for speed */ register const char *cset; /* Use registers for speed */
register int base; register int base;
@ -415,7 +431,7 @@ static int vxprintf(
longvalue = longvalue/base; longvalue = longvalue/base;
}while( longvalue>0 ); }while( longvalue>0 );
} }
length = &buf[etBUFSIZE-1]-bufpt; length = (int)(&buf[etBUFSIZE-1]-bufpt);
for(idx=precision-length; idx>0; idx--){ for(idx=precision-length; idx>0; idx--){
*(--bufpt) = '0'; /* Zero pad */ *(--bufpt) = '0'; /* Zero pad */
} }
@ -424,11 +440,9 @@ static int vxprintf(
const char *pre; const char *pre;
char x; char x;
pre = &aPrefix[infop->prefix]; pre = &aPrefix[infop->prefix];
if( *bufpt!=pre[0] ){ for(; (x=(*pre))!=0; pre++) *(--bufpt) = x;
for(; (x=(*pre))!=0; pre++) *(--bufpt) = x;
}
} }
length = &buf[etBUFSIZE-1]-bufpt; length = (int)(&buf[etBUFSIZE-1]-bufpt);
break; break;
case etFLOAT: case etFLOAT:
case etEXP: case etEXP:
@ -456,7 +470,7 @@ static int vxprintf(
if( xtype==etFLOAT ) realvalue += rounder; if( xtype==etFLOAT ) realvalue += rounder;
/* Normalize realvalue to within 10.0 > realvalue >= 1.0 */ /* Normalize realvalue to within 10.0 > realvalue >= 1.0 */
exp = 0; exp = 0;
if( sqlite3_isnan(realvalue) ){ if( sqlite3IsNaN((double)realvalue) ){
bufpt = "NaN"; bufpt = "NaN";
length = 3; length = 3;
break; break;
@ -465,9 +479,9 @@ static int vxprintf(
while( realvalue>=1e32 && exp<=350 ){ realvalue *= 1e-32; exp+=32; } while( realvalue>=1e32 && exp<=350 ){ realvalue *= 1e-32; exp+=32; }
while( realvalue>=1e8 && exp<=350 ){ realvalue *= 1e-8; exp+=8; } while( realvalue>=1e8 && exp<=350 ){ realvalue *= 1e-8; exp+=8; }
while( realvalue>=10.0 && exp<=350 ){ realvalue *= 0.1; exp++; } while( realvalue>=10.0 && exp<=350 ){ realvalue *= 0.1; exp++; }
while( realvalue<1e-8 && exp>=-350 ){ realvalue *= 1e8; exp-=8; } while( realvalue<1e-8 ){ realvalue *= 1e8; exp-=8; }
while( realvalue<1.0 && exp>=-350 ){ realvalue *= 10.0; exp--; } while( realvalue<1.0 ){ realvalue *= 10.0; exp--; }
if( exp>350 || exp<-350 ){ if( exp>350 ){
if( prefix=='-' ){ if( prefix=='-' ){
bufpt = "-Inf"; bufpt = "-Inf";
}else if( prefix=='+' ){ }else if( prefix=='+' ){
@ -475,7 +489,7 @@ static int vxprintf(
}else{ }else{
bufpt = "Inf"; bufpt = "Inf";
} }
length = strlen(bufpt); length = sqlite3Strlen30(bufpt);
break; break;
} }
} }
@ -506,7 +520,7 @@ static int vxprintf(
e2 = exp; e2 = exp;
} }
nsd = 0; nsd = 0;
flag_dp = (precision>0) | flag_alternateform | flag_altform2; flag_dp = (precision>0 ?1:0) | flag_alternateform | flag_altform2;
/* The sign in front of the number */ /* The sign in front of the number */
if( prefix ){ if( prefix ){
*(bufpt++) = prefix; *(bufpt++) = prefix;
@ -525,7 +539,8 @@ static int vxprintf(
} }
/* "0" digits after the decimal point but before the first /* "0" digits after the decimal point but before the first
** significant digit of the number */ ** significant digit of the number */
for(e2++; e2<0 && precision>0; precision--, e2++){ for(e2++; e2<0; precision--, e2++){
assert( precision>0 );
*(bufpt++) = '0'; *(bufpt++) = '0';
} }
/* Significant digits after the decimal point */ /* Significant digits after the decimal point */
@ -545,7 +560,7 @@ static int vxprintf(
} }
} }
/* Add the "eNNN" suffix */ /* Add the "eNNN" suffix */
if( flag_exp || (xtype==etEXP && exp) ){ if( flag_exp || xtype==etEXP ){
*(bufpt++) = aDigits[infop->charset]; *(bufpt++) = aDigits[infop->charset];
if( exp<0 ){ if( exp<0 ){
*(bufpt++) = '-'; exp = -exp; *(bufpt++) = '-'; exp = -exp;
@ -553,18 +568,18 @@ static int vxprintf(
*(bufpt++) = '+'; *(bufpt++) = '+';
} }
if( exp>=100 ){ if( exp>=100 ){
*(bufpt++) = (exp/100)+'0'; /* 100's digit */ *(bufpt++) = (char)((exp/100)+'0'); /* 100's digit */
exp %= 100; exp %= 100;
} }
*(bufpt++) = exp/10+'0'; /* 10's digit */ *(bufpt++) = (char)(exp/10+'0'); /* 10's digit */
*(bufpt++) = exp%10+'0'; /* 1's digit */ *(bufpt++) = (char)(exp%10+'0'); /* 1's digit */
} }
*bufpt = 0; *bufpt = 0;
/* The converted number is in buf[] and zero terminated. Output it. /* The converted number is in buf[] and zero terminated. Output it.
** Note that the number is in the usual order, not reversed as with ** Note that the number is in the usual order, not reversed as with
** integer conversions. */ ** integer conversions. */
length = bufpt-buf; length = (int)(bufpt-buf);
bufpt = buf; bufpt = buf;
/* Special case: Add leading zeros if the flag_zeropad flag is /* Special case: Add leading zeros if the flag_zeropad flag is
@ -582,7 +597,7 @@ static int vxprintf(
#endif #endif
break; break;
case etSIZE: case etSIZE:
*(va_arg(ap,int*)) = count; *(va_arg(ap,int*)) = pAccum->nChar;
length = width = 0; length = width = 0;
break; break;
case etPERCENT: case etPERCENT:
@ -590,11 +605,11 @@ static int vxprintf(
bufpt = buf; bufpt = buf;
length = 1; length = 1;
break; break;
case etCHARLIT:
case etCHARX: case etCHARX:
c = buf[0] = (xtype==etCHARX ? va_arg(ap,int) : *++fmt); c = va_arg(ap,int);
buf[0] = (char)c;
if( precision>=0 ){ if( precision>=0 ){
for(idx=1; idx<precision; idx++) buf[idx] = c; for(idx=1; idx<precision; idx++) buf[idx] = (char)c;
length = precision; length = precision;
}else{ }else{
length =1; length =1;
@ -609,14 +624,18 @@ static int vxprintf(
}else if( xtype==etDYNSTRING ){ }else if( xtype==etDYNSTRING ){
zExtra = bufpt; zExtra = bufpt;
} }
length = strlen(bufpt); if( precision>=0 ){
if( precision>=0 && precision<length ) length = precision; for(length=0; length<precision && bufpt[length]; length++){}
}else{
length = sqlite3Strlen30(bufpt);
}
break; break;
case etSQLESCAPE: case etSQLESCAPE:
case etSQLESCAPE2: case etSQLESCAPE2:
case etSQLESCAPE3: { case etSQLESCAPE3: {
int i, j, n, ch, isnull; int i, j, n, isnull;
int needQuote; int needQuote;
char ch;
char q = ((xtype==etSQLESCAPE3)?'"':'\''); /* Quote character */ char q = ((xtype==etSQLESCAPE3)?'"':'\''); /* Quote character */
char *escarg = va_arg(ap,char*); char *escarg = va_arg(ap,char*);
isnull = escarg==0; isnull = escarg==0;
@ -627,8 +646,11 @@ static int vxprintf(
needQuote = !isnull && xtype==etSQLESCAPE2; needQuote = !isnull && xtype==etSQLESCAPE2;
n += i + 1 + needQuote*2; n += i + 1 + needQuote*2;
if( n>etBUFSIZE ){ if( n>etBUFSIZE ){
bufpt = zExtra = sqliteMalloc( n ); bufpt = zExtra = sqlite3Malloc( n );
if( bufpt==0 ) return -1; if( bufpt==0 ){
pAccum->mallocFailed = 1;
return;
}
}else{ }else{
bufpt = buf; bufpt = buf;
} }
@ -647,8 +669,8 @@ static int vxprintf(
} }
case etTOKEN: { case etTOKEN: {
Token *pToken = va_arg(ap, Token*); Token *pToken = va_arg(ap, Token*);
if( pToken && pToken->z ){ if( pToken ){
(*func)(arg, (char*)pToken->z, pToken->n); sqlite3StrAccumAppend(pAccum, (const char*)pToken->z, pToken->n);
} }
length = width = 0; length = width = 0;
break; break;
@ -658,11 +680,11 @@ static int vxprintf(
int k = va_arg(ap, int); int k = va_arg(ap, int);
struct SrcList_item *pItem = &pSrc->a[k]; struct SrcList_item *pItem = &pSrc->a[k];
assert( k>=0 && k<pSrc->nSrc ); assert( k>=0 && k<pSrc->nSrc );
if( pItem->zDatabase && pItem->zDatabase[0] ){ if( pItem->zDatabase ){
(*func)(arg, pItem->zDatabase, strlen(pItem->zDatabase)); sqlite3StrAccumAppend(pAccum, pItem->zDatabase, -1);
(*func)(arg, ".", 1); sqlite3StrAccumAppend(pAccum, ".", 1);
} }
(*func)(arg, pItem->zName, strlen(pItem->zName)); sqlite3StrAccumAppend(pAccum, pItem->zName, -1);
length = width = 0; length = width = 0;
break; break;
} }
@ -676,161 +698,181 @@ static int vxprintf(
register int nspace; register int nspace;
nspace = width-length; nspace = width-length;
if( nspace>0 ){ if( nspace>0 ){
count += nspace; appendSpace(pAccum, nspace);
while( nspace>=etSPACESIZE ){
(*func)(arg,spaces,etSPACESIZE);
nspace -= etSPACESIZE;
}
if( nspace>0 ) (*func)(arg,spaces,nspace);
} }
} }
if( length>0 ){ if( length>0 ){
(*func)(arg,bufpt,length); sqlite3StrAccumAppend(pAccum, bufpt, length);
count += length;
} }
if( flag_leftjustify ){ if( flag_leftjustify ){
register int nspace; register int nspace;
nspace = width-length; nspace = width-length;
if( nspace>0 ){ if( nspace>0 ){
count += nspace; appendSpace(pAccum, nspace);
while( nspace>=etSPACESIZE ){
(*func)(arg,spaces,etSPACESIZE);
nspace -= etSPACESIZE;
}
if( nspace>0 ) (*func)(arg,spaces,nspace);
} }
} }
if( zExtra ){ if( zExtra ){
sqliteFree(zExtra); sqlite3_free(zExtra);
} }
}/* End for loop over the format string */ }/* End for loop over the format string */
return errorflag ? -1 : count;
} /* End of function */ } /* End of function */
/*
/* This structure is used to store state information about the ** Append N bytes of text from z to the StrAccum object.
** write to memory that is currently in progress.
*/ */
struct sgMprintf { void sqlite3StrAccumAppend(StrAccum *p, const char *z, int N){
char *zBase; /* A base allocation */ if( p->tooBig | p->mallocFailed ){
char *zText; /* The string collected so far */ return;
int nChar; /* Length of the string so far */ }
int nTotal; /* Output size if unconstrained */ if( N<0 ){
int nAlloc; /* Amount of space allocated in zText */ N = sqlite3Strlen30(z);
void *(*xRealloc)(void*,int); /* Function used to realloc memory */ }
}; if( N==0 || z==0 ){
return;
/* }
** This function implements the callback from vxprintf. if( p->nChar+N >= p->nAlloc ){
** char *zNew;
** This routine add nNewChar characters of text in zNewText to if( !p->useMalloc ){
** the sgMprintf structure pointed to by "arg". p->tooBig = 1;
*/ N = p->nAlloc - p->nChar - 1;
static void mout(void *arg, const char *zNewText, int nNewChar){ if( N<=0 ){
struct sgMprintf *pM = (struct sgMprintf*)arg; return;
pM->nTotal += nNewChar; }
if( pM->nChar + nNewChar + 1 > pM->nAlloc ){
if( pM->xRealloc==0 ){
nNewChar = pM->nAlloc - pM->nChar - 1;
}else{ }else{
int nAlloc = pM->nChar + nNewChar*2 + 1; i64 szNew = p->nChar;
if( pM->zText==pM->zBase ){ szNew += N + 1;
pM->zText = pM->xRealloc(0, nAlloc); if( szNew > p->mxAlloc ){
if( pM->zText && pM->nChar ){ sqlite3StrAccumReset(p);
memcpy(pM->zText, pM->zBase, pM->nChar); p->tooBig = 1;
} return;
}else{ }else{
char *zNew; p->nAlloc = (int)szNew;
zNew = pM->xRealloc(pM->zText, nAlloc);
if( zNew ){
pM->zText = zNew;
}else{
return;
}
} }
pM->nAlloc = nAlloc; zNew = sqlite3DbMallocRaw(p->db, p->nAlloc );
}
}
if( pM->zText ){
if( nNewChar>0 ){
memcpy(&pM->zText[pM->nChar], zNewText, nNewChar);
pM->nChar += nNewChar;
}
pM->zText[pM->nChar] = 0;
}
}
/*
** This routine is a wrapper around xprintf() that invokes mout() as
** the consumer.
*/
static char *base_vprintf(
void *(*xRealloc)(void*,int), /* Routine to realloc memory. May be NULL */
int useInternal, /* Use internal %-conversions if true */
char *zInitBuf, /* Initially write here, before mallocing */
int nInitBuf, /* Size of zInitBuf[] */
const char *zFormat, /* format string */
va_list ap /* arguments */
){
struct sgMprintf sM;
sM.zBase = sM.zText = zInitBuf;
sM.nChar = sM.nTotal = 0;
sM.nAlloc = nInitBuf;
sM.xRealloc = xRealloc;
vxprintf(mout, &sM, useInternal, zFormat, ap);
if( xRealloc ){
if( sM.zText==sM.zBase ){
sM.zText = xRealloc(0, sM.nChar+1);
if( sM.zText ){
memcpy(sM.zText, sM.zBase, sM.nChar+1);
}
}else if( sM.nAlloc>sM.nChar+10 ){
char *zNew = xRealloc(sM.zText, sM.nChar+1);
if( zNew ){ if( zNew ){
sM.zText = zNew; memcpy(zNew, p->zText, p->nChar);
sqlite3StrAccumReset(p);
p->zText = zNew;
}else{
p->mallocFailed = 1;
sqlite3StrAccumReset(p);
return;
} }
} }
} }
return sM.zText; memcpy(&p->zText[p->nChar], z, N);
p->nChar += N;
} }
/* /*
** Realloc that is a real function, not a macro. ** Finish off a string by making sure it is zero-terminated.
** Return a pointer to the resulting string. Return a NULL
** pointer if any kind of error was encountered.
*/ */
static void *printf_realloc(void *old, int size){ char *sqlite3StrAccumFinish(StrAccum *p){
return sqliteRealloc(old,size); if( p->zText ){
p->zText[p->nChar] = 0;
if( p->useMalloc && p->zText==p->zBase ){
p->zText = sqlite3DbMallocRaw(p->db, p->nChar+1 );
if( p->zText ){
memcpy(p->zText, p->zBase, p->nChar+1);
}else{
p->mallocFailed = 1;
}
}
}
return p->zText;
}
/*
** Reset an StrAccum string. Reclaim all malloced memory.
*/
void sqlite3StrAccumReset(StrAccum *p){
if( p->zText!=p->zBase ){
sqlite3DbFree(p->db, p->zText);
}
p->zText = 0;
}
/*
** Initialize a string accumulator
*/
void sqlite3StrAccumInit(StrAccum *p, char *zBase, int n, int mx){
p->zText = p->zBase = zBase;
p->db = 0;
p->nChar = 0;
p->nAlloc = n;
p->mxAlloc = mx;
p->useMalloc = 1;
p->tooBig = 0;
p->mallocFailed = 0;
} }
/* /*
** Print into memory obtained from sqliteMalloc(). Use the internal ** Print into memory obtained from sqliteMalloc(). Use the internal
** %-conversion extensions. ** %-conversion extensions.
*/ */
char *sqlite3VMPrintf(const char *zFormat, va_list ap){ char *sqlite3VMPrintf(sqlite3 *db, const char *zFormat, va_list ap){
char zBase[SQLITE_PRINT_BUF_SIZE];
return base_vprintf(printf_realloc, 1, zBase, sizeof(zBase), zFormat, ap);
}
/*
** Print into memory obtained from sqliteMalloc(). Use the internal
** %-conversion extensions.
*/
char *sqlite3MPrintf(const char *zFormat, ...){
va_list ap;
char *z; char *z;
char zBase[SQLITE_PRINT_BUF_SIZE]; char zBase[SQLITE_PRINT_BUF_SIZE];
StrAccum acc;
sqlite3StrAccumInit(&acc, zBase, sizeof(zBase),
db ? db->aLimit[SQLITE_LIMIT_LENGTH] : SQLITE_MAX_LENGTH);
acc.db = db;
sqlite3VXPrintf(&acc, 1, zFormat, ap);
z = sqlite3StrAccumFinish(&acc);
if( acc.mallocFailed && db ){
db->mallocFailed = 1;
}
return z;
}
/*
** Print into memory obtained from sqliteMalloc(). Use the internal
** %-conversion extensions.
*/
char *sqlite3MPrintf(sqlite3 *db, const char *zFormat, ...){
va_list ap;
char *z;
va_start(ap, zFormat); va_start(ap, zFormat);
z = base_vprintf(printf_realloc, 1, zBase, sizeof(zBase), zFormat, ap); z = sqlite3VMPrintf(db, zFormat, ap);
va_end(ap); va_end(ap);
return z; return z;
} }
/*
** Like sqlite3MPrintf(), but call sqlite3DbFree() on zStr after formatting
** the string and before returnning. This routine is intended to be used
** to modify an existing string. For example:
**
** x = sqlite3MPrintf(db, x, "prefix %s suffix", x);
**
*/
char *sqlite3MAppendf(sqlite3 *db, char *zStr, const char *zFormat, ...){
va_list ap;
char *z;
va_start(ap, zFormat);
z = sqlite3VMPrintf(db, zFormat, ap);
va_end(ap);
sqlite3DbFree(db, zStr);
return z;
}
/* /*
** Print into memory obtained from sqlite3_malloc(). Omit the internal ** Print into memory obtained from sqlite3_malloc(). Omit the internal
** %-conversion extensions. ** %-conversion extensions.
*/ */
char *sqlite3_vmprintf(const char *zFormat, va_list ap){ char *sqlite3_vmprintf(const char *zFormat, va_list ap){
char *z;
char zBase[SQLITE_PRINT_BUF_SIZE]; char zBase[SQLITE_PRINT_BUF_SIZE];
return base_vprintf(sqlite3_realloc, 0, zBase, sizeof(zBase), zFormat, ap); StrAccum acc;
#ifndef SQLITE_OMIT_AUTOINIT
if( sqlite3_initialize() ) return 0;
#endif
sqlite3StrAccumInit(&acc, zBase, sizeof(zBase), SQLITE_MAX_LENGTH);
sqlite3VXPrintf(&acc, 0, zFormat, ap);
z = sqlite3StrAccumFinish(&acc);
return z;
} }
/* /*
@ -840,6 +882,9 @@ char *sqlite3_vmprintf(const char *zFormat, va_list ap){
char *sqlite3_mprintf(const char *zFormat, ...){ char *sqlite3_mprintf(const char *zFormat, ...){
va_list ap; va_list ap;
char *z; char *z;
#ifndef SQLITE_OMIT_AUTOINIT
if( sqlite3_initialize() ) return 0;
#endif
va_start(ap, zFormat); va_start(ap, zFormat);
z = sqlite3_vmprintf(zFormat, ap); z = sqlite3_vmprintf(zFormat, ap);
va_end(ap); va_end(ap);
@ -855,30 +900,36 @@ char *sqlite3_mprintf(const char *zFormat, ...){
char *sqlite3_snprintf(int n, char *zBuf, const char *zFormat, ...){ char *sqlite3_snprintf(int n, char *zBuf, const char *zFormat, ...){
char *z; char *z;
va_list ap; va_list ap;
StrAccum acc;
if( n<=0 ){ if( n<=0 ){
return zBuf; return zBuf;
} }
zBuf[0] = 0; sqlite3StrAccumInit(&acc, zBuf, n, 0);
acc.useMalloc = 0;
va_start(ap,zFormat); va_start(ap,zFormat);
z = base_vprintf(0, 0, zBuf, n, zFormat, ap); sqlite3VXPrintf(&acc, 0, zFormat, ap);
va_end(ap); va_end(ap);
z = sqlite3StrAccumFinish(&acc);
return z; return z;
} }
#if defined(SQLITE_TEST) || defined(SQLITE_DEBUG) || defined(SQLITE_MEMDEBUG) #if defined(SQLITE_DEBUG)
/* /*
** A version of printf() that understands %lld. Used for debugging. ** A version of printf() that understands %lld. Used for debugging.
** The printf() built into some versions of windows does not understand %lld ** The printf() built into some versions of windows does not understand %lld
** and segfaults if you give it a long long int. ** and segfaults if you give it a long long int.
*/ */
void sqlite3DebugPrintf(const char *zFormat, ...){ void sqlite3DebugPrintf(const char *zFormat, ...){
extern int getpid(void);
va_list ap; va_list ap;
StrAccum acc;
char zBuf[500]; char zBuf[500];
va_start(ap, zFormat); sqlite3StrAccumInit(&acc, zBuf, sizeof(zBuf), 0);
base_vprintf(0, 0, zBuf, sizeof(zBuf), zFormat, ap); acc.useMalloc = 0;
va_start(ap,zFormat);
sqlite3VXPrintf(&acc, 0, zFormat, ap);
va_end(ap); va_end(ap);
sqlite3StrAccumFinish(&acc);
fprintf(stdout,"%s", zBuf); fprintf(stdout,"%s", zBuf);
fflush(stdout); fflush(stdout);
} }

107
random.c
View file

@ -15,12 +15,20 @@
** Random numbers are used by some of the database backends in order ** Random numbers are used by some of the database backends in order
** to generate random integer keys for tables or random filenames. ** to generate random integer keys for tables or random filenames.
** **
** $Id: random.c,v 1.16 2007/01/05 14:38:56 drh Exp $ ** $Id: random.c,v 1.29 2008/12/10 19:26:24 drh Exp $
*/ */
#include "sqliteInt.h" #include "sqliteInt.h"
#include "os.h"
/* All threads share a single random number generator.
** This structure is the current state of the generator.
*/
static SQLITE_WSD struct sqlite3PrngType {
unsigned char isInit; /* True if initialized */
unsigned char i, j; /* State variables */
unsigned char s[256]; /* State variables */
} sqlite3Prng;
/* /*
** Get a single 8-bit random value from the RC4 PRNG. The Mutex ** Get a single 8-bit random value from the RC4 PRNG. The Mutex
** must be held while executing this routine. ** must be held while executing this routine.
@ -37,17 +45,23 @@
** (Later): Actually, OP_NewRowid does not depend on a good source of ** (Later): Actually, OP_NewRowid does not depend on a good source of
** randomness any more. But we will leave this code in all the same. ** randomness any more. But we will leave this code in all the same.
*/ */
static int randomByte(void){ static u8 randomByte(void){
unsigned char t; unsigned char t;
/* All threads share a single random number generator.
** This structure is the current state of the generator. /* The "wsdPrng" macro will resolve to the pseudo-random number generator
** state vector. If writable static data is unsupported on the target,
** we have to locate the state vector at run-time. In the more common
** case where writable static data is supported, wsdPrng can refer directly
** to the "sqlite3Prng" state vector declared above.
*/ */
static struct { #ifdef SQLITE_OMIT_WSD
unsigned char isInit; /* True if initialized */ struct sqlite3PrngType *p = &GLOBAL(struct sqlite3PrngType, sqlite3Prng);
unsigned char i, j; /* State variables */ # define wsdPrng p[0]
unsigned char s[256]; /* State variables */ #else
} prng; # define wsdPrng sqlite3Prng
#endif
/* Initialize the state of the random number generator once, /* Initialize the state of the random number generator once,
** the first time this routine is called. The seed value does ** the first time this routine is called. The seed value does
@ -58,43 +72,76 @@ static int randomByte(void){
** encryption. The RC4 algorithm is being used as a PRNG (pseudo-random ** encryption. The RC4 algorithm is being used as a PRNG (pseudo-random
** number generator) not as an encryption device. ** number generator) not as an encryption device.
*/ */
if( !prng.isInit ){ if( !wsdPrng.isInit ){
int i; int i;
char k[256]; char k[256];
prng.j = 0; wsdPrng.j = 0;
prng.i = 0; wsdPrng.i = 0;
sqlite3OsRandomSeed(k); sqlite3OsRandomness(sqlite3_vfs_find(0), 256, k);
for(i=0; i<256; i++){ for(i=0; i<256; i++){
prng.s[i] = i; wsdPrng.s[i] = (u8)i;
} }
for(i=0; i<256; i++){ for(i=0; i<256; i++){
prng.j += prng.s[i] + k[i]; wsdPrng.j += wsdPrng.s[i] + k[i];
t = prng.s[prng.j]; t = wsdPrng.s[wsdPrng.j];
prng.s[prng.j] = prng.s[i]; wsdPrng.s[wsdPrng.j] = wsdPrng.s[i];
prng.s[i] = t; wsdPrng.s[i] = t;
} }
prng.isInit = 1; wsdPrng.isInit = 1;
} }
/* Generate and return single random byte /* Generate and return single random byte
*/ */
prng.i++; wsdPrng.i++;
t = prng.s[prng.i]; t = wsdPrng.s[wsdPrng.i];
prng.j += t; wsdPrng.j += t;
prng.s[prng.i] = prng.s[prng.j]; wsdPrng.s[wsdPrng.i] = wsdPrng.s[wsdPrng.j];
prng.s[prng.j] = t; wsdPrng.s[wsdPrng.j] = t;
t += prng.s[prng.i]; t += wsdPrng.s[wsdPrng.i];
return prng.s[t]; return wsdPrng.s[t];
} }
/* /*
** Return N random bytes. ** Return N random bytes.
*/ */
void sqlite3Randomness(int N, void *pBuf){ void sqlite3_randomness(int N, void *pBuf){
unsigned char *zBuf = pBuf; unsigned char *zBuf = pBuf;
sqlite3OsEnterMutex(); #if SQLITE_THREADSAFE
sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_PRNG);
#endif
sqlite3_mutex_enter(mutex);
while( N-- ){ while( N-- ){
*(zBuf++) = randomByte(); *(zBuf++) = randomByte();
} }
sqlite3OsLeaveMutex(); sqlite3_mutex_leave(mutex);
} }
#ifndef SQLITE_OMIT_BUILTIN_TEST
/*
** For testing purposes, we sometimes want to preserve the state of
** PRNG and restore the PRNG to its saved state at a later time, or
** to reset the PRNG to its initial state. These routines accomplish
** those tasks.
**
** The sqlite3_test_control() interface calls these routines to
** control the PRNG.
*/
static SQLITE_WSD struct sqlite3PrngType sqlite3SavedPrng;
void sqlite3PrngSaveState(void){
memcpy(
&GLOBAL(struct sqlite3PrngType, sqlite3SavedPrng),
&GLOBAL(struct sqlite3PrngType, sqlite3Prng),
sizeof(sqlite3Prng)
);
}
void sqlite3PrngRestoreState(void){
memcpy(
&GLOBAL(struct sqlite3PrngType, sqlite3Prng),
&GLOBAL(struct sqlite3PrngType, sqlite3SavedPrng),
sizeof(sqlite3Prng)
);
}
void sqlite3PrngResetState(void){
GLOBAL(struct sqlite3PrngType, sqlite3Prng).isInit = 0;
}
#endif /* SQLITE_OMIT_BUILTIN_TEST */

1169
resolve.c Normal file

File diff suppressed because it is too large Load diff

238
rowset.c Normal file
View file

@ -0,0 +1,238 @@
/*
** 2008 December 3
**
** 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 module implements an object we call a "Row Set".
**
** The RowSet object is a bag of rowids. Rowids
** are inserted into the bag in an arbitrary order. Then they are
** pulled from the bag in sorted order. Rowids only appear in the
** bag once. If the same rowid is inserted multiple times, the
** second and subsequent inserts make no difference on the output.
**
** This implementation accumulates rowids in a linked list. For
** output, it first sorts the linked list (removing duplicates during
** the sort) then returns elements one by one by walking the list.
**
** Big chunks of rowid/next-ptr pairs are allocated at a time, to
** reduce the malloc overhead.
**
** $Id: rowset.c,v 1.3 2009/01/13 20:14:16 drh Exp $
*/
#include "sqliteInt.h"
/*
** The number of rowset entries per allocation chunk.
*/
#define ROWSET_ENTRY_PER_CHUNK 63
/*
** Each entry in a RowSet is an instance of the following
** structure:
*/
struct RowSetEntry {
i64 v; /* ROWID value for this entry */
struct RowSetEntry *pNext; /* Next entry on a list of all entries */
};
/*
** Index entries are allocated in large chunks (instances of the
** following structure) to reduce memory allocation overhead. The
** chunks are kept on a linked list so that they can be deallocated
** when the RowSet is destroyed.
*/
struct RowSetChunk {
struct RowSetChunk *pNext; /* Next chunk on list of them all */
struct RowSetEntry aEntry[ROWSET_ENTRY_PER_CHUNK]; /* Allocated entries */
};
/*
** A RowSet in an instance of the following structure.
**
** A typedef of this structure if found in sqliteInt.h.
*/
struct RowSet {
struct RowSetChunk *pChunk; /* List of all chunk allocations */
sqlite3 *db; /* The database connection */
struct RowSetEntry *pEntry; /* List of entries in the rowset */
struct RowSetEntry *pLast; /* Last entry on the pEntry list */
struct RowSetEntry *pFresh; /* Source of new entry objects */
u16 nFresh; /* Number of objects on pFresh */
u8 isSorted; /* True if content is sorted */
};
/*
** Turn bulk memory into a RowSet object. N bytes of memory
** are available at pSpace. The db pointer is used as a memory context
** for any subsequent allocations that need to occur.
** Return a pointer to the new RowSet object.
**
** It must be the case that N is sufficient to make a Rowset. If not
** an assertion fault occurs.
**
** If N is larger than the minimum, use the surplus as an initial
** allocation of entries available to be filled.
*/
RowSet *sqlite3RowSetInit(sqlite3 *db, void *pSpace, unsigned int N){
RowSet *p;
assert( N >= sizeof(*p) );
p = pSpace;
p->pChunk = 0;
p->db = db;
p->pEntry = 0;
p->pLast = 0;
p->pFresh = (struct RowSetEntry*)&p[1];
p->nFresh = (u16)((N - sizeof(*p))/sizeof(struct RowSetEntry));
p->isSorted = 1;
return p;
}
/*
** Deallocate all chunks from a RowSet.
*/
void sqlite3RowSetClear(RowSet *p){
struct RowSetChunk *pChunk, *pNextChunk;
for(pChunk=p->pChunk; pChunk; pChunk = pNextChunk){
pNextChunk = pChunk->pNext;
sqlite3DbFree(p->db, pChunk);
}
p->pChunk = 0;
p->nFresh = 0;
p->pEntry = 0;
p->pLast = 0;
p->isSorted = 1;
}
/*
** Insert a new value into a RowSet.
**
** The mallocFailed flag of the database connection is set if a
** memory allocation fails.
*/
void sqlite3RowSetInsert(RowSet *p, i64 rowid){
struct RowSetEntry *pEntry;
struct RowSetEntry *pLast;
if( p==0 ) return; /* Must have been a malloc failure */
if( p->nFresh==0 ){
struct RowSetChunk *pNew;
pNew = sqlite3DbMallocRaw(p->db, sizeof(*pNew));
if( pNew==0 ){
return;
}
pNew->pNext = p->pChunk;
p->pChunk = pNew;
p->pFresh = pNew->aEntry;
p->nFresh = ROWSET_ENTRY_PER_CHUNK;
}
pEntry = p->pFresh++;
p->nFresh--;
pEntry->v = rowid;
pEntry->pNext = 0;
pLast = p->pLast;
if( pLast ){
if( p->isSorted && rowid<=pLast->v ){
p->isSorted = 0;
}
pLast->pNext = pEntry;
}else{
assert( p->pEntry==0 );
p->pEntry = pEntry;
}
p->pLast = pEntry;
}
/*
** Merge two lists of RowSet entries. Remove duplicates.
**
** The input lists are assumed to be in sorted order.
*/
static struct RowSetEntry *boolidxMerge(
struct RowSetEntry *pA, /* First sorted list to be merged */
struct RowSetEntry *pB /* Second sorted list to be merged */
){
struct RowSetEntry head;
struct RowSetEntry *pTail;
pTail = &head;
while( pA && pB ){
assert( pA->pNext==0 || pA->v<=pA->pNext->v );
assert( pB->pNext==0 || pB->v<=pB->pNext->v );
if( pA->v<pB->v ){
pTail->pNext = pA;
pA = pA->pNext;
pTail = pTail->pNext;
}else if( pB->v<pA->v ){
pTail->pNext = pB;
pB = pB->pNext;
pTail = pTail->pNext;
}else{
pA = pA->pNext;
}
}
if( pA ){
assert( pA->pNext==0 || pA->v<=pA->pNext->v );
pTail->pNext = pA;
}else{
assert( pB==0 || pB->pNext==0 || pB->v<=pB->pNext->v );
pTail->pNext = pB;
}
return head.pNext;
}
/*
** Sort all elements of the RowSet into ascending order.
*/
static void sqlite3RowSetSort(RowSet *p){
unsigned int i;
struct RowSetEntry *pEntry;
struct RowSetEntry *aBucket[40];
assert( p->isSorted==0 );
memset(aBucket, 0, sizeof(aBucket));
while( p->pEntry ){
pEntry = p->pEntry;
p->pEntry = pEntry->pNext;
pEntry->pNext = 0;
for(i=0; aBucket[i]; i++){
pEntry = boolidxMerge(aBucket[i],pEntry);
aBucket[i] = 0;
}
aBucket[i] = pEntry;
}
pEntry = 0;
for(i=0; i<sizeof(aBucket)/sizeof(aBucket[0]); i++){
pEntry = boolidxMerge(pEntry,aBucket[i]);
}
p->pEntry = pEntry;
p->pLast = 0;
p->isSorted = 1;
}
/*
** Extract the next (smallest) element from the RowSet.
** Write the element into *pRowid. Return 1 on success. Return
** 0 if the RowSet is already empty.
*/
int sqlite3RowSetNext(RowSet *p, i64 *pRowid){
if( !p->isSorted ){
sqlite3RowSetSort(p);
}
if( p->pEntry ){
*pRowid = p->pEntry->v;
p->pEntry = p->pEntry->pNext;
if( p->pEntry==0 ){
sqlite3RowSetClear(p);
}
return 1;
}else{
return 0;
}
}

4111
select.c

File diff suppressed because it is too large Load diff

2148
shell.c Normal file

File diff suppressed because it is too large Load diff

6313
sqlite3.h

File diff suppressed because it is too large Load diff

View file

@ -15,7 +15,7 @@
** as extensions by SQLite should #include this file instead of ** as extensions by SQLite should #include this file instead of
** sqlite3.h. ** sqlite3.h.
** **
** @(#) $Id: sqlite3ext.h,v 1.12 2007/07/20 10:48:36 drh Exp $ ** @(#) $Id: sqlite3ext.h,v 1.25 2008/10/12 00:27:54 shane Exp $
*/ */
#ifndef _SQLITE3EXT_H_ #ifndef _SQLITE3EXT_H_
#define _SQLITE3EXT_H_ #define _SQLITE3EXT_H_
@ -24,13 +24,13 @@
typedef struct sqlite3_api_routines sqlite3_api_routines; typedef struct sqlite3_api_routines sqlite3_api_routines;
/* /*
** The following structure hold pointers to all of the SQLite API ** The following structure holds pointers to all of the SQLite API
** routines. ** routines.
** **
** WARNING: In order to maintain backwards compatibility, add new ** WARNING: In order to maintain backwards compatibility, add new
** interfaces to the end of this structure only. If you insert new ** interfaces to the end of this structure only. If you insert new
** interfaces in the middle of this structure, then older different ** interfaces in the middle of this structure, then older different
** versions of SQLite will not be able to load each others shared ** versions of SQLite will not be able to load each others' shared
** libraries! ** libraries!
*/ */
struct sqlite3_api_routines { struct sqlite3_api_routines {
@ -78,7 +78,7 @@ struct sqlite3_api_routines {
int (*complete)(const char*sql); int (*complete)(const char*sql);
int (*complete16)(const void*sql); int (*complete16)(const void*sql);
int (*create_collation)(sqlite3*,const char*,int,void*,int(*)(void*,int,const void*,int,const void*)); int (*create_collation)(sqlite3*,const char*,int,void*,int(*)(void*,int,const void*,int,const void*));
int (*create_collation16)(sqlite3*,const char*,int,void*,int(*)(void*,int,const void*,int,const void*)); int (*create_collation16)(sqlite3*,const void*,int,void*,int(*)(void*,int,const void*,int,const void*));
int (*create_function)(sqlite3*,const char*,int,int,void*,void (*xFunc)(sqlite3_context*,int,sqlite3_value**),void (*xStep)(sqlite3_context*,int,sqlite3_value**),void (*xFinal)(sqlite3_context*)); int (*create_function)(sqlite3*,const char*,int,int,void*,void (*xFunc)(sqlite3_context*,int,sqlite3_value**),void (*xStep)(sqlite3_context*,int,sqlite3_value**),void (*xFinal)(sqlite3_context*));
int (*create_function16)(sqlite3*,const void*,int,int,void*,void (*xFunc)(sqlite3_context*,int,sqlite3_value**),void (*xStep)(sqlite3_context*,int,sqlite3_value**),void (*xFinal)(sqlite3_context*)); int (*create_function16)(sqlite3*,const void*,int,int,void*,void (*xFunc)(sqlite3_context*,int,sqlite3_value**),void (*xStep)(sqlite3_context*,int,sqlite3_value**),void (*xFinal)(sqlite3_context*));
int (*create_module)(sqlite3*,const char*,const sqlite3_module*,void*); int (*create_module)(sqlite3*,const char*,const sqlite3_module*,void*);
@ -149,11 +149,50 @@ struct sqlite3_api_routines {
const void * (*value_text16le)(sqlite3_value*); const void * (*value_text16le)(sqlite3_value*);
int (*value_type)(sqlite3_value*); int (*value_type)(sqlite3_value*);
char *(*vmprintf)(const char*,va_list); char *(*vmprintf)(const char*,va_list);
/* Added ??? */
int (*overload_function)(sqlite3*, const char *zFuncName, int nArg); int (*overload_function)(sqlite3*, const char *zFuncName, int nArg);
/* Added by 3.3.13 */
int (*prepare_v2)(sqlite3*,const char*,int,sqlite3_stmt**,const char**); int (*prepare_v2)(sqlite3*,const char*,int,sqlite3_stmt**,const char**);
int (*prepare16_v2)(sqlite3*,const void*,int,sqlite3_stmt**,const void**); int (*prepare16_v2)(sqlite3*,const void*,int,sqlite3_stmt**,const void**);
int (*clear_bindings)(sqlite3_stmt*); int (*clear_bindings)(sqlite3_stmt*);
/* Added by 3.4.1 */
int (*create_module_v2)(sqlite3*,const char*,const sqlite3_module*,void*,void (*xDestroy)(void *)); int (*create_module_v2)(sqlite3*,const char*,const sqlite3_module*,void*,void (*xDestroy)(void *));
/* Added by 3.5.0 */
int (*bind_zeroblob)(sqlite3_stmt*,int,int);
int (*blob_bytes)(sqlite3_blob*);
int (*blob_close)(sqlite3_blob*);
int (*blob_open)(sqlite3*,const char*,const char*,const char*,sqlite3_int64,int,sqlite3_blob**);
int (*blob_read)(sqlite3_blob*,void*,int,int);
int (*blob_write)(sqlite3_blob*,const void*,int,int);
int (*create_collation_v2)(sqlite3*,const char*,int,void*,int(*)(void*,int,const void*,int,const void*),void(*)(void*));
int (*file_control)(sqlite3*,const char*,int,void*);
sqlite3_int64 (*memory_highwater)(int);
sqlite3_int64 (*memory_used)(void);
sqlite3_mutex *(*mutex_alloc)(int);
void (*mutex_enter)(sqlite3_mutex*);
void (*mutex_free)(sqlite3_mutex*);
void (*mutex_leave)(sqlite3_mutex*);
int (*mutex_try)(sqlite3_mutex*);
int (*open_v2)(const char*,sqlite3**,int,const char*);
int (*release_memory)(int);
void (*result_error_nomem)(sqlite3_context*);
void (*result_error_toobig)(sqlite3_context*);
int (*sleep)(int);
void (*soft_heap_limit)(int);
sqlite3_vfs *(*vfs_find)(const char*);
int (*vfs_register)(sqlite3_vfs*,int);
int (*vfs_unregister)(sqlite3_vfs*);
int (*xthreadsafe)(void);
void (*result_zeroblob)(sqlite3_context*,int);
void (*result_error_code)(sqlite3_context*,int);
int (*test_control)(int, ...);
void (*randomness)(int,void*);
sqlite3 *(*context_db_handle)(sqlite3_context*);
int (*extended_result_codes)(sqlite3*,int);
int (*limit)(sqlite3*,int,int);
sqlite3_stmt *(*next_stmt)(sqlite3*,sqlite3_stmt*);
const char *(*sql)(sqlite3_stmt*);
int (*status)(int,int*,int*,int);
}; };
/* /*
@ -169,7 +208,9 @@ struct sqlite3_api_routines {
*/ */
#ifndef SQLITE_CORE #ifndef SQLITE_CORE
#define sqlite3_aggregate_context sqlite3_api->aggregate_context #define sqlite3_aggregate_context sqlite3_api->aggregate_context
#ifndef SQLITE_OMIT_DEPRECATED
#define sqlite3_aggregate_count sqlite3_api->aggregate_count #define sqlite3_aggregate_count sqlite3_api->aggregate_count
#endif
#define sqlite3_bind_blob sqlite3_api->bind_blob #define sqlite3_bind_blob sqlite3_api->bind_blob
#define sqlite3_bind_double sqlite3_api->bind_double #define sqlite3_bind_double sqlite3_api->bind_double
#define sqlite3_bind_int sqlite3_api->bind_int #define sqlite3_bind_int sqlite3_api->bind_int
@ -225,14 +266,18 @@ struct sqlite3_api_routines {
#define sqlite3_errmsg sqlite3_api->errmsg #define sqlite3_errmsg sqlite3_api->errmsg
#define sqlite3_errmsg16 sqlite3_api->errmsg16 #define sqlite3_errmsg16 sqlite3_api->errmsg16
#define sqlite3_exec sqlite3_api->exec #define sqlite3_exec sqlite3_api->exec
#ifndef SQLITE_OMIT_DEPRECATED
#define sqlite3_expired sqlite3_api->expired #define sqlite3_expired sqlite3_api->expired
#endif
#define sqlite3_finalize sqlite3_api->finalize #define sqlite3_finalize sqlite3_api->finalize
#define sqlite3_free sqlite3_api->free #define sqlite3_free sqlite3_api->free
#define sqlite3_free_table sqlite3_api->free_table #define sqlite3_free_table sqlite3_api->free_table
#define sqlite3_get_autocommit sqlite3_api->get_autocommit #define sqlite3_get_autocommit sqlite3_api->get_autocommit
#define sqlite3_get_auxdata sqlite3_api->get_auxdata #define sqlite3_get_auxdata sqlite3_api->get_auxdata
#define sqlite3_get_table sqlite3_api->get_table #define sqlite3_get_table sqlite3_api->get_table
#ifndef SQLITE_OMIT_DEPRECATED
#define sqlite3_global_recover sqlite3_api->global_recover #define sqlite3_global_recover sqlite3_api->global_recover
#endif
#define sqlite3_interrupt sqlite3_api->interruptx #define sqlite3_interrupt sqlite3_api->interruptx
#define sqlite3_last_insert_rowid sqlite3_api->last_insert_rowid #define sqlite3_last_insert_rowid sqlite3_api->last_insert_rowid
#define sqlite3_libversion sqlite3_api->libversion #define sqlite3_libversion sqlite3_api->libversion
@ -270,7 +315,9 @@ struct sqlite3_api_routines {
#define sqlite3_thread_cleanup sqlite3_api->thread_cleanup #define sqlite3_thread_cleanup sqlite3_api->thread_cleanup
#define sqlite3_total_changes sqlite3_api->total_changes #define sqlite3_total_changes sqlite3_api->total_changes
#define sqlite3_trace sqlite3_api->trace #define sqlite3_trace sqlite3_api->trace
#ifndef SQLITE_OMIT_DEPRECATED
#define sqlite3_transfer_bindings sqlite3_api->transfer_bindings #define sqlite3_transfer_bindings sqlite3_api->transfer_bindings
#endif
#define sqlite3_update_hook sqlite3_api->update_hook #define sqlite3_update_hook sqlite3_api->update_hook
#define sqlite3_user_data sqlite3_api->user_data #define sqlite3_user_data sqlite3_api->user_data
#define sqlite3_value_blob sqlite3_api->value_blob #define sqlite3_value_blob sqlite3_api->value_blob
@ -290,9 +337,44 @@ struct sqlite3_api_routines {
#define sqlite3_prepare_v2 sqlite3_api->prepare_v2 #define sqlite3_prepare_v2 sqlite3_api->prepare_v2
#define sqlite3_prepare16_v2 sqlite3_api->prepare16_v2 #define sqlite3_prepare16_v2 sqlite3_api->prepare16_v2
#define sqlite3_clear_bindings sqlite3_api->clear_bindings #define sqlite3_clear_bindings sqlite3_api->clear_bindings
#define sqlite3_bind_zeroblob sqlite3_api->bind_zeroblob
#define sqlite3_blob_bytes sqlite3_api->blob_bytes
#define sqlite3_blob_close sqlite3_api->blob_close
#define sqlite3_blob_open sqlite3_api->blob_open
#define sqlite3_blob_read sqlite3_api->blob_read
#define sqlite3_blob_write sqlite3_api->blob_write
#define sqlite3_create_collation_v2 sqlite3_api->create_collation_v2
#define sqlite3_file_control sqlite3_api->file_control
#define sqlite3_memory_highwater sqlite3_api->memory_highwater
#define sqlite3_memory_used sqlite3_api->memory_used
#define sqlite3_mutex_alloc sqlite3_api->mutex_alloc
#define sqlite3_mutex_enter sqlite3_api->mutex_enter
#define sqlite3_mutex_free sqlite3_api->mutex_free
#define sqlite3_mutex_leave sqlite3_api->mutex_leave
#define sqlite3_mutex_try sqlite3_api->mutex_try
#define sqlite3_open_v2 sqlite3_api->open_v2
#define sqlite3_release_memory sqlite3_api->release_memory
#define sqlite3_result_error_nomem sqlite3_api->result_error_nomem
#define sqlite3_result_error_toobig sqlite3_api->result_error_toobig
#define sqlite3_sleep sqlite3_api->sleep
#define sqlite3_soft_heap_limit sqlite3_api->soft_heap_limit
#define sqlite3_vfs_find sqlite3_api->vfs_find
#define sqlite3_vfs_register sqlite3_api->vfs_register
#define sqlite3_vfs_unregister sqlite3_api->vfs_unregister
#define sqlite3_threadsafe sqlite3_api->xthreadsafe
#define sqlite3_result_zeroblob sqlite3_api->result_zeroblob
#define sqlite3_result_error_code sqlite3_api->result_error_code
#define sqlite3_test_control sqlite3_api->test_control
#define sqlite3_randomness sqlite3_api->randomness
#define sqlite3_context_db_handle sqlite3_api->context_db_handle
#define sqlite3_extended_result_codes sqlite3_api->extended_result_codes
#define sqlite3_limit sqlite3_api->limit
#define sqlite3_next_stmt sqlite3_api->next_stmt
#define sqlite3_sql sqlite3_api->sql
#define sqlite3_status sqlite3_api->status
#endif /* SQLITE_CORE */ #endif /* SQLITE_CORE */
#define SQLITE_EXTENSION_INIT1 const sqlite3_api_routines *sqlite3_api; #define SQLITE_EXTENSION_INIT1 const sqlite3_api_routines *sqlite3_api = 0;
#define SQLITE_EXTENSION_INIT2(v) sqlite3_api = v; #define SQLITE_EXTENSION_INIT2(v) sqlite3_api = v;
#endif /* _SQLITE3EXT_H_ */ #endif /* _SQLITE3EXT_H_ */

File diff suppressed because it is too large Load diff

View file

@ -12,7 +12,7 @@
** **
** This file defines various limits of what SQLite can process. ** This file defines various limits of what SQLite can process.
** **
** @(#) $Id: sqliteLimit.h,v 1.1 2007/06/19 15:23:48 drh Exp $ ** @(#) $Id: sqliteLimit.h,v 1.10 2009/01/10 16:15:09 danielk1977 Exp $
*/ */
/* /*
@ -49,18 +49,24 @@
/* /*
** The maximum length of a single SQL statement in bytes. ** The maximum length of a single SQL statement in bytes.
** The hard limit here is the same as SQLITE_MAX_LENGTH. **
** It used to be the case that setting this value to zero would
** turn the limit off. That is no longer true. It is not possible
** to turn this limit off.
*/ */
#ifndef SQLITE_MAX_SQL_LENGTH #ifndef SQLITE_MAX_SQL_LENGTH
# define SQLITE_MAX_SQL_LENGTH 1000000 # define SQLITE_MAX_SQL_LENGTH 1000000000
#endif #endif
/* /*
** The maximum depth of an expression tree. This is limited to ** The maximum depth of an expression tree. This is limited to
** some extent by SQLITE_MAX_SQL_LENGTH. But sometime you might ** some extent by SQLITE_MAX_SQL_LENGTH. But sometime you might
** want to place more severe limits on the complexity of an ** want to place more severe limits on the complexity of an
** expression. A value of 0 (the default) means do not enforce ** expression.
** any limitation on expression tree depth. **
** A value of 0 used to mean that the limit was not enforced.
** But that is no longer true. The limit is now strictly enforced
** at all times.
*/ */
#ifndef SQLITE_MAX_EXPR_DEPTH #ifndef SQLITE_MAX_EXPR_DEPTH
# define SQLITE_MAX_EXPR_DEPTH 1000 # define SQLITE_MAX_EXPR_DEPTH 1000
@ -90,7 +96,7 @@
** The maximum number of arguments to an SQL function. ** The maximum number of arguments to an SQL function.
*/ */
#ifndef SQLITE_MAX_FUNCTION_ARG #ifndef SQLITE_MAX_FUNCTION_ARG
# define SQLITE_MAX_FUNCTION_ARG 100 # define SQLITE_MAX_FUNCTION_ARG 127
#endif #endif
/* /*
@ -105,11 +111,9 @@
#endif #endif
/* /*
** The maximum number of attached databases. This must be at least 2 ** The maximum number of attached databases. This must be between 0
** in order to support the main database file (0) and the file used to ** and 30. The upper bound on 30 is because a 32-bit integer bitmap
** hold temporary tables (1). And it must be less than 32 because ** is used internally to track attached databases.
** we use a bitmask of databases with a u32 in places (for example
** the Parse.cookieMask field).
*/ */
#ifndef SQLITE_MAX_ATTACHED #ifndef SQLITE_MAX_ATTACHED
# define SQLITE_MAX_ATTACHED 10 # define SQLITE_MAX_ATTACHED 10
@ -123,21 +127,49 @@
# define SQLITE_MAX_VARIABLE_NUMBER 999 # define SQLITE_MAX_VARIABLE_NUMBER 999
#endif #endif
/* Maximum page size. The upper bound on this value is 32768. This a limit
** imposed by the necessity of storing the value in a 2-byte unsigned integer
** and the fact that the page size must be a power of 2.
**
** If this limit is changed, then the compiled library is technically
** incompatible with an SQLite library compiled with a different limit. If
** a process operating on a database with a page-size of 65536 bytes
** crashes, then an instance of SQLite compiled with the default page-size
** limit will not be able to rollback the aborted transaction. This could
** lead to database corruption.
*/
#ifndef SQLITE_MAX_PAGE_SIZE
# define SQLITE_MAX_PAGE_SIZE 32768
#endif
/* /*
** The default size of a database page. ** The default size of a database page.
*/ */
#ifndef SQLITE_DEFAULT_PAGE_SIZE #ifndef SQLITE_DEFAULT_PAGE_SIZE
# define SQLITE_DEFAULT_PAGE_SIZE 1024 # define SQLITE_DEFAULT_PAGE_SIZE 1024
#endif #endif
#if SQLITE_DEFAULT_PAGE_SIZE>SQLITE_MAX_PAGE_SIZE
/* Maximum page size. The upper bound on this value is 32768. This a limit # undef SQLITE_DEFAULT_PAGE_SIZE
** imposed by the necessity of storing the value in a 2-byte unsigned integer # define SQLITE_DEFAULT_PAGE_SIZE SQLITE_MAX_PAGE_SIZE
** and the fact that the page size must be a power of 2.
*/
#ifndef SQLITE_MAX_PAGE_SIZE
# define SQLITE_MAX_PAGE_SIZE 32768
#endif #endif
/*
** Ordinarily, if no value is explicitly provided, SQLite creates databases
** with page size SQLITE_DEFAULT_PAGE_SIZE. However, based on certain
** device characteristics (sector-size and atomic write() support),
** SQLite may choose a larger value. This constant is the maximum value
** SQLite will choose on its own.
*/
#ifndef SQLITE_MAX_DEFAULT_PAGE_SIZE
# define SQLITE_MAX_DEFAULT_PAGE_SIZE 8192
#endif
#if SQLITE_MAX_DEFAULT_PAGE_SIZE>SQLITE_MAX_PAGE_SIZE
# undef SQLITE_MAX_DEFAULT_PAGE_SIZE
# define SQLITE_MAX_DEFAULT_PAGE_SIZE SQLITE_MAX_PAGE_SIZE
#endif
/* /*
** Maximum number of pages in one database file. ** Maximum number of pages in one database file.
** **

122
status.c Normal file
View file

@ -0,0 +1,122 @@
/*
** 2008 June 18
**
** 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 module implements the sqlite3_status() interface and related
** functionality.
**
** $Id: status.c,v 1.9 2008/09/02 00:52:52 drh Exp $
*/
#include "sqliteInt.h"
/*
** Variables in which to record status information.
*/
typedef struct sqlite3StatType sqlite3StatType;
static SQLITE_WSD struct sqlite3StatType {
int nowValue[9]; /* Current value */
int mxValue[9]; /* Maximum value */
} sqlite3Stat = { {0,}, {0,} };
/* The "wsdStat" macro will resolve to the status information
** state vector. If writable static data is unsupported on the target,
** we have to locate the state vector at run-time. In the more common
** case where writable static data is supported, wsdStat can refer directly
** to the "sqlite3Stat" state vector declared above.
*/
#ifdef SQLITE_OMIT_WSD
# define wsdStatInit sqlite3StatType *x = &GLOBAL(sqlite3StatType,sqlite3Stat)
# define wsdStat x[0]
#else
# define wsdStatInit
# define wsdStat sqlite3Stat
#endif
/*
** Return the current value of a status parameter.
*/
int sqlite3StatusValue(int op){
wsdStatInit;
assert( op>=0 && op<ArraySize(wsdStat.nowValue) );
return wsdStat.nowValue[op];
}
/*
** Add N to the value of a status record. It is assumed that the
** caller holds appropriate locks.
*/
void sqlite3StatusAdd(int op, int N){
wsdStatInit;
assert( op>=0 && op<ArraySize(wsdStat.nowValue) );
wsdStat.nowValue[op] += N;
if( wsdStat.nowValue[op]>wsdStat.mxValue[op] ){
wsdStat.mxValue[op] = wsdStat.nowValue[op];
}
}
/*
** Set the value of a status to X.
*/
void sqlite3StatusSet(int op, int X){
wsdStatInit;
assert( op>=0 && op<ArraySize(wsdStat.nowValue) );
wsdStat.nowValue[op] = X;
if( wsdStat.nowValue[op]>wsdStat.mxValue[op] ){
wsdStat.mxValue[op] = wsdStat.nowValue[op];
}
}
/*
** Query status information.
**
** This implementation assumes that reading or writing an aligned
** 32-bit integer is an atomic operation. If that assumption is not true,
** then this routine is not threadsafe.
*/
int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetFlag){
wsdStatInit;
if( op<0 || op>=ArraySize(wsdStat.nowValue) ){
return SQLITE_MISUSE;
}
*pCurrent = wsdStat.nowValue[op];
*pHighwater = wsdStat.mxValue[op];
if( resetFlag ){
wsdStat.mxValue[op] = wsdStat.nowValue[op];
}
return SQLITE_OK;
}
/*
** Query status information for a single database connection
*/
int sqlite3_db_status(
sqlite3 *db, /* The database connection whose status is desired */
int op, /* Status verb */
int *pCurrent, /* Write current value here */
int *pHighwater, /* Write high-water mark here */
int resetFlag /* Reset high-water mark if true */
){
switch( op ){
case SQLITE_DBSTATUS_LOOKASIDE_USED: {
*pCurrent = db->lookaside.nOut;
*pHighwater = db->lookaside.mxOut;
if( resetFlag ){
db->lookaside.mxOut = db->lookaside.nOut;
}
break;
}
default: {
return SQLITE_ERROR;
}
}
return SQLITE_OK;
}

50
table.c
View file

@ -15,6 +15,8 @@
** **
** These routines are in a separate files so that they will not be linked ** These routines are in a separate files so that they will not be linked
** if they are not used. ** if they are not used.
**
** $Id: table.c,v 1.38 2008/12/10 19:26:24 drh Exp $
*/ */
#include "sqliteInt.h" #include "sqliteInt.h"
#include <stdlib.h> #include <stdlib.h>
@ -70,17 +72,15 @@ static int sqlite3_get_table_cb(void *pArg, int nCol, char **argv, char **colv){
if( p->nRow==0 ){ if( p->nRow==0 ){
p->nColumn = nCol; p->nColumn = nCol;
for(i=0; i<nCol; i++){ for(i=0; i<nCol; i++){
if( colv[i]==0 ){ z = sqlite3_mprintf("%s", colv[i]);
z = sqlite3_mprintf(""); if( z==0 ) goto malloc_failed;
}else{
z = sqlite3_mprintf("%s", colv[i]);
}
p->azResult[p->nData++] = z; p->azResult[p->nData++] = z;
} }
}else if( p->nColumn!=nCol ){ }else if( p->nColumn!=nCol ){
sqlite3SetString(&p->zErrMsg, sqlite3_free(p->zErrMsg);
"sqlite3_get_table() called with two or more incompatible queries", p->zErrMsg = sqlite3_mprintf(
(char*)0); "sqlite3_get_table() called with two or more incompatible queries"
);
p->rc = SQLITE_ERROR; p->rc = SQLITE_ERROR;
return 1; return 1;
} }
@ -92,7 +92,7 @@ static int sqlite3_get_table_cb(void *pArg, int nCol, char **argv, char **colv){
if( argv[i]==0 ){ if( argv[i]==0 ){
z = 0; z = 0;
}else{ }else{
int n = strlen(argv[i])+1; int n = sqlite3Strlen30(argv[i])+1;
z = sqlite3_malloc( n ); z = sqlite3_malloc( n );
if( z==0 ) goto malloc_failed; if( z==0 ) goto malloc_failed;
memcpy(z, argv[i], n); memcpy(z, argv[i], n);
@ -128,7 +128,7 @@ int sqlite3_get_table(
){ ){
int rc; int rc;
TabResult res; TabResult res;
if( pazResult==0 ){ return SQLITE_ERROR; }
*pazResult = 0; *pazResult = 0;
if( pnColumn ) *pnColumn = 0; if( pnColumn ) *pnColumn = 0;
if( pnRow ) *pnRow = 0; if( pnRow ) *pnRow = 0;
@ -139,14 +139,15 @@ int sqlite3_get_table(
res.nData = 1; res.nData = 1;
res.nAlloc = 20; res.nAlloc = 20;
res.rc = SQLITE_OK; res.rc = SQLITE_OK;
res.azResult = sqlite3_malloc( sizeof(char*)*res.nAlloc ); res.azResult = sqlite3_malloc(sizeof(char*)*res.nAlloc );
if( res.azResult==0 ) return SQLITE_NOMEM; if( res.azResult==0 ){
db->errCode = SQLITE_NOMEM;
return SQLITE_NOMEM;
}
res.azResult[0] = 0; res.azResult[0] = 0;
rc = sqlite3_exec(db, zSql, sqlite3_get_table_cb, &res, pzErrMsg); rc = sqlite3_exec(db, zSql, sqlite3_get_table_cb, &res, pzErrMsg);
if( res.azResult ){ assert( sizeof(res.azResult[0])>= sizeof(res.nData) );
assert( sizeof(res.azResult[0])>= sizeof(res.nData) ); res.azResult[0] = SQLITE_INT_TO_PTR(res.nData);
res.azResult[0] = (char*)res.nData;
}
if( (rc&0xff)==SQLITE_ABORT ){ if( (rc&0xff)==SQLITE_ABORT ){
sqlite3_free_table(&res.azResult[1]); sqlite3_free_table(&res.azResult[1]);
if( res.zErrMsg ){ if( res.zErrMsg ){
@ -154,21 +155,22 @@ int sqlite3_get_table(
sqlite3_free(*pzErrMsg); sqlite3_free(*pzErrMsg);
*pzErrMsg = sqlite3_mprintf("%s",res.zErrMsg); *pzErrMsg = sqlite3_mprintf("%s",res.zErrMsg);
} }
sqliteFree(res.zErrMsg); sqlite3_free(res.zErrMsg);
} }
db->errCode = res.rc; db->errCode = res.rc; /* Assume 32-bit assignment is atomic */
return res.rc & db->errMask; return res.rc;
} }
sqliteFree(res.zErrMsg); sqlite3_free(res.zErrMsg);
if( rc!=SQLITE_OK ){ if( rc!=SQLITE_OK ){
sqlite3_free_table(&res.azResult[1]); sqlite3_free_table(&res.azResult[1]);
return rc & db->errMask; return rc;
} }
if( res.nAlloc>res.nData ){ if( res.nAlloc>res.nData ){
char **azNew; char **azNew;
azNew = sqlite3_realloc( res.azResult, sizeof(char*)*(res.nData+1) ); azNew = sqlite3_realloc( res.azResult, sizeof(char*)*(res.nData+1) );
if( azNew==0 ){ if( azNew==0 ){
sqlite3_free_table(&res.azResult[1]); sqlite3_free_table(&res.azResult[1]);
db->errCode = SQLITE_NOMEM;
return SQLITE_NOMEM; return SQLITE_NOMEM;
} }
res.nAlloc = res.nData+1; res.nAlloc = res.nData+1;
@ -177,7 +179,7 @@ int sqlite3_get_table(
*pazResult = &res.azResult[1]; *pazResult = &res.azResult[1];
if( pnColumn ) *pnColumn = res.nColumn; if( pnColumn ) *pnColumn = res.nColumn;
if( pnRow ) *pnRow = res.nRow; if( pnRow ) *pnRow = res.nRow;
return rc & db->errMask; return rc;
} }
/* /*
@ -189,8 +191,8 @@ void sqlite3_free_table(
if( azResult ){ if( azResult ){
int i, n; int i, n;
azResult--; azResult--;
if( azResult==0 ) return; assert( azResult!=0 );
n = (int)azResult[0]; n = SQLITE_PTR_TO_INT(azResult[0]);
for(i=1; i<n; i++){ if( azResult[i] ) sqlite3_free(azResult[i]); } for(i=1; i<n; i++){ if( azResult[i] ) sqlite3_free(azResult[i]); }
sqlite3_free(azResult); sqlite3_free(azResult);
} }

View file

@ -15,10 +15,9 @@
** individual tokens and sends those tokens one-by-one over to the ** individual tokens and sends those tokens one-by-one over to the
** parser for analysis. ** parser for analysis.
** **
** $Id: tokenize.c,v 1.131 2007/07/23 19:31:17 drh Exp $ ** $Id: tokenize.c,v 1.152 2008/09/01 15:52:11 drh Exp $
*/ */
#include "sqliteInt.h" #include "sqliteInt.h"
#include "os.h"
#include <ctype.h> #include <ctype.h>
#include <stdlib.h> #include <stdlib.h>
@ -86,7 +85,7 @@ const unsigned char ebcdicToAscii[] = {
** But the feature is undocumented. ** But the feature is undocumented.
*/ */
#ifdef SQLITE_ASCII #ifdef SQLITE_ASCII
const char sqlite3IsIdChar[] = { const char sqlite3IsAsciiIdChar[] = {
/* x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF */ /* x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF */
0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 2x */ 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 2x */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, /* 3x */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, /* 3x */
@ -95,10 +94,10 @@ const char sqlite3IsIdChar[] = {
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 6x */ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 6x */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, /* 7x */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, /* 7x */
}; };
#define IdChar(C) (((c=C)&0x80)!=0 || (c>0x1f && sqlite3IsIdChar[c-0x20])) #define IdChar(C) (((c=C)&0x80)!=0 || (c>0x1f && sqlite3IsAsciiIdChar[c-0x20]))
#endif #endif
#ifdef SQLITE_EBCDIC #ifdef SQLITE_EBCDIC
const char sqlite3IsIdChar[] = { const char sqlite3IsEbcdicIdChar[] = {
/* x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF */ /* x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF */
0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, /* 4x */ 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, /* 4x */
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, /* 5x */ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, /* 5x */
@ -113,7 +112,7 @@ const char sqlite3IsIdChar[] = {
0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, /* Ex */ 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, /* Ex */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, /* Fx */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, /* Fx */
}; };
#define IdChar(C) (((c=C)>=0x42 && sqlite3IsIdChar[c-0x40])) #define IdChar(C) (((c=C)>=0x42 && sqlite3IsEbcdicIdChar[c-0x40]))
#endif #endif
@ -121,7 +120,7 @@ const char sqlite3IsIdChar[] = {
** Return the length of the token that begins at z[0]. ** Return the length of the token that begins at z[0].
** Store the token type in *tokenType before returning. ** Store the token type in *tokenType before returning.
*/ */
static int getToken(const unsigned char *z, int *tokenType){ int sqlite3GetToken(const unsigned char *z, int *tokenType){
int i, c; int i, c;
switch( *z ){ switch( *z ){
case ' ': case '\t': case '\n': case '\f': case '\r': { case ' ': case '\t': case '\n': case '\f': case '\r': {
@ -132,7 +131,7 @@ static int getToken(const unsigned char *z, int *tokenType){
case '-': { case '-': {
if( z[1]=='-' ){ if( z[1]=='-' ){
for(i=2; (c=z[i])!=0 && c!='\n'; i++){} for(i=2; (c=z[i])!=0 && c!='\n'; i++){}
*tokenType = TK_COMMENT; *tokenType = TK_SPACE;
return i; return i;
} }
*tokenType = TK_MINUS; *tokenType = TK_MINUS;
@ -165,7 +164,7 @@ static int getToken(const unsigned char *z, int *tokenType){
} }
for(i=3, c=z[2]; (c!='*' || z[i]!='/') && (c=z[i])!=0; i++){} for(i=3, c=z[2]; (c!='*' || z[i]!='/') && (c=z[i])!=0; i++){}
if( c ) i++; if( c ) i++;
*tokenType = TK_COMMENT; *tokenType = TK_SPACE;
return i; return i;
} }
case '%': { case '%': {
@ -246,9 +245,12 @@ static int getToken(const unsigned char *z, int *tokenType){
} }
} }
} }
if( c ){ if( c=='\'' ){
*tokenType = TK_STRING; *tokenType = TK_STRING;
return i+1; return i+1;
}else if( c!=0 ){
*tokenType = TK_ID;
return i+1;
}else{ }else{
*tokenType = TK_ILLEGAL; *tokenType = TK_ILLEGAL;
return i; return i;
@ -293,7 +295,7 @@ static int getToken(const unsigned char *z, int *tokenType){
} }
case '[': { case '[': {
for(i=1, c=z[0]; c!=']' && (c=z[i])!=0; i++){} for(i=1, c=z[0]; c!=']' && (c=z[i])!=0; i++){}
*tokenType = TK_ID; *tokenType = c==']' ? TK_ID : TK_ILLEGAL;
return i; return i;
} }
case '?': { case '?': {
@ -345,19 +347,14 @@ static int getToken(const unsigned char *z, int *tokenType){
} }
#ifndef SQLITE_OMIT_BLOB_LITERAL #ifndef SQLITE_OMIT_BLOB_LITERAL
case 'x': case 'X': { case 'x': case 'X': {
if( (c=z[1])=='\'' || c=='"' ){ if( z[1]=='\'' ){
int delim = c;
*tokenType = TK_BLOB; *tokenType = TK_BLOB;
for(i=2; (c=z[i])!=0; i++){ for(i=2; (c=z[i])!=0 && c!='\''; i++){
if( c==delim ){
if( i%2 ) *tokenType = TK_ILLEGAL;
break;
}
if( !isxdigit(c) ){ if( !isxdigit(c) ){
*tokenType = TK_ILLEGAL; *tokenType = TK_ILLEGAL;
return i;
} }
} }
if( i%2 || !c ) *tokenType = TK_ILLEGAL;
if( c ) i++; if( c ) i++;
return i; return i;
} }
@ -376,16 +373,13 @@ static int getToken(const unsigned char *z, int *tokenType){
*tokenType = TK_ILLEGAL; *tokenType = TK_ILLEGAL;
return 1; return 1;
} }
int sqlite3GetToken(const unsigned char *z, int *tokenType){
return getToken(z, tokenType);
}
/* /*
** Run the parser on the given SQL string. The parser structure is ** Run the parser on the given SQL string. The parser structure is
** passed in. An SQLITE_ status code is returned. If an error occurs ** passed in. An SQLITE_ status code is returned. If an error occurs
** and pzErrMsg!=NULL then an error message might be written into ** then an and attempt is made to write an error message into
** memory obtained from malloc() and *pzErrMsg made to point to that ** memory obtained from sqlite3_malloc() and to make *pzErrMsg point to that
** error message. Or maybe not. ** error message.
*/ */
int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzErrMsg){ int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzErrMsg){
int nErr = 0; int nErr = 0;
@ -394,14 +388,18 @@ int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzErrMsg){
int tokenType; int tokenType;
int lastTokenParsed = -1; int lastTokenParsed = -1;
sqlite3 *db = pParse->db; sqlite3 *db = pParse->db;
int mxSqlLen = db->aLimit[SQLITE_LIMIT_SQL_LENGTH];
if( db->activeVdbeCnt==0 ){ if( db->activeVdbeCnt==0 ){
db->u1.isInterrupted = 0; db->u1.isInterrupted = 0;
} }
pParse->rc = SQLITE_OK; pParse->rc = SQLITE_OK;
pParse->zTail = pParse->zSql = zSql;
i = 0; i = 0;
pEngine = sqlite3ParserAlloc((void*(*)(size_t))sqlite3MallocX); assert( pzErrMsg!=0 );
pEngine = sqlite3ParserAlloc((void*(*)(size_t))sqlite3Malloc);
if( pEngine==0 ){ if( pEngine==0 ){
db->mallocFailed = 1;
return SQLITE_NOMEM; return SQLITE_NOMEM;
} }
assert( pParse->sLastToken.dyn==0 ); assert( pParse->sLastToken.dyn==0 );
@ -411,33 +409,29 @@ int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzErrMsg){
assert( pParse->nVarExpr==0 ); assert( pParse->nVarExpr==0 );
assert( pParse->nVarExprAlloc==0 ); assert( pParse->nVarExprAlloc==0 );
assert( pParse->apVarExpr==0 ); assert( pParse->apVarExpr==0 );
pParse->zTail = pParse->zSql = zSql; while( !db->mallocFailed && zSql[i]!=0 ){
while( !sqlite3MallocFailed() && zSql[i]!=0 ){
assert( i>=0 ); assert( i>=0 );
pParse->sLastToken.z = (u8*)&zSql[i]; pParse->sLastToken.z = (u8*)&zSql[i];
assert( pParse->sLastToken.dyn==0 ); assert( pParse->sLastToken.dyn==0 );
pParse->sLastToken.n = getToken((unsigned char*)&zSql[i],&tokenType); pParse->sLastToken.n = sqlite3GetToken((unsigned char*)&zSql[i],&tokenType);
i += pParse->sLastToken.n; i += pParse->sLastToken.n;
if( i>SQLITE_MAX_SQL_LENGTH ){ if( i>mxSqlLen ){
pParse->rc = SQLITE_TOOBIG; pParse->rc = SQLITE_TOOBIG;
break; break;
} }
switch( tokenType ){ switch( tokenType ){
case TK_SPACE: case TK_SPACE: {
case TK_COMMENT: {
if( db->u1.isInterrupted ){ if( db->u1.isInterrupted ){
pParse->rc = SQLITE_INTERRUPT; pParse->rc = SQLITE_INTERRUPT;
sqlite3SetString(pzErrMsg, "interrupt", (char*)0); sqlite3SetString(pzErrMsg, db, "interrupt");
goto abort_parse; goto abort_parse;
} }
break; break;
} }
case TK_ILLEGAL: { case TK_ILLEGAL: {
if( pzErrMsg ){ sqlite3DbFree(db, *pzErrMsg);
sqliteFree(*pzErrMsg); *pzErrMsg = sqlite3MPrintf(db, "unrecognized token: \"%T\"",
*pzErrMsg = sqlite3MPrintf("unrecognized token: \"%T\"", &pParse->sLastToken);
&pParse->sLastToken);
}
nErr++; nErr++;
goto abort_parse; goto abort_parse;
} }
@ -463,21 +457,26 @@ abort_parse:
} }
sqlite3Parser(pEngine, 0, pParse->sLastToken, pParse); sqlite3Parser(pEngine, 0, pParse->sLastToken, pParse);
} }
sqlite3ParserFree(pEngine, sqlite3FreeX); #ifdef YYTRACKMAXSTACKDEPTH
if( sqlite3MallocFailed() ){ sqlite3StatusSet(SQLITE_STATUS_PARSER_STACK,
sqlite3ParserStackPeak(pEngine)
);
#endif /* YYDEBUG */
sqlite3ParserFree(pEngine, sqlite3_free);
if( db->mallocFailed ){
pParse->rc = SQLITE_NOMEM; pParse->rc = SQLITE_NOMEM;
} }
if( pParse->rc!=SQLITE_OK && pParse->rc!=SQLITE_DONE && pParse->zErrMsg==0 ){ if( pParse->rc!=SQLITE_OK && pParse->rc!=SQLITE_DONE && pParse->zErrMsg==0 ){
sqlite3SetString(&pParse->zErrMsg, sqlite3ErrStr(pParse->rc), (char*)0); sqlite3SetString(&pParse->zErrMsg, db, "%s", sqlite3ErrStr(pParse->rc));
} }
if( pParse->zErrMsg ){ if( pParse->zErrMsg ){
if( pzErrMsg && *pzErrMsg==0 ){ if( *pzErrMsg==0 ){
*pzErrMsg = pParse->zErrMsg; *pzErrMsg = pParse->zErrMsg;
}else{ }else{
sqliteFree(pParse->zErrMsg); sqlite3DbFree(db, pParse->zErrMsg);
} }
pParse->zErrMsg = 0; pParse->zErrMsg = 0;
if( !nErr ) nErr++; nErr++;
} }
if( pParse->pVdbe && pParse->nErr>0 && pParse->nested==0 ){ if( pParse->pVdbe && pParse->nErr>0 && pParse->nested==0 ){
sqlite3VdbeDelete(pParse->pVdbe); sqlite3VdbeDelete(pParse->pVdbe);
@ -485,11 +484,14 @@ abort_parse:
} }
#ifndef SQLITE_OMIT_SHARED_CACHE #ifndef SQLITE_OMIT_SHARED_CACHE
if( pParse->nested==0 ){ if( pParse->nested==0 ){
sqliteFree(pParse->aTableLock); sqlite3DbFree(db, pParse->aTableLock);
pParse->aTableLock = 0; pParse->aTableLock = 0;
pParse->nTableLock = 0; pParse->nTableLock = 0;
} }
#endif #endif
#ifndef SQLITE_OMIT_VIRTUALTABLE
sqlite3DbFree(db, pParse->apVtabLock);
#endif
if( !IN_DECLARE_VTAB ){ if( !IN_DECLARE_VTAB ){
/* If the pParse->declareVtab flag is set, do not delete any table /* If the pParse->declareVtab flag is set, do not delete any table
@ -499,8 +501,14 @@ abort_parse:
sqlite3DeleteTable(pParse->pNewTable); sqlite3DeleteTable(pParse->pNewTable);
} }
sqlite3DeleteTrigger(pParse->pNewTrigger); sqlite3DeleteTrigger(db, pParse->pNewTrigger);
sqliteFree(pParse->apVarExpr); sqlite3DbFree(db, pParse->apVarExpr);
sqlite3DbFree(db, pParse->aAlias);
while( pParse->pZombieTab ){
Table *p = pParse->pZombieTab;
pParse->pZombieTab = p->pNextZombie;
sqlite3DeleteTable(p);
}
if( nErr>0 && (pParse->rc==SQLITE_OK || pParse->rc==SQLITE_DONE) ){ if( nErr>0 && (pParse->rc==SQLITE_OK || pParse->rc==SQLITE_DONE) ){
pParse->rc = SQLITE_ERROR; pParse->rc = SQLITE_ERROR;
} }

295
trigger.c
View file

@ -8,7 +8,9 @@
** May you share freely, never taking more than you give. ** May you share freely, never taking more than you give.
** **
************************************************************************* *************************************************************************
* **
**
** $Id: trigger.c,v 1.133 2008/12/26 07:56:39 danielk1977 Exp $
*/ */
#include "sqliteInt.h" #include "sqliteInt.h"
@ -16,18 +18,18 @@
/* /*
** Delete a linked list of TriggerStep structures. ** Delete a linked list of TriggerStep structures.
*/ */
void sqlite3DeleteTriggerStep(TriggerStep *pTriggerStep){ void sqlite3DeleteTriggerStep(sqlite3 *db, TriggerStep *pTriggerStep){
while( pTriggerStep ){ while( pTriggerStep ){
TriggerStep * pTmp = pTriggerStep; TriggerStep * pTmp = pTriggerStep;
pTriggerStep = pTriggerStep->pNext; pTriggerStep = pTriggerStep->pNext;
if( pTmp->target.dyn ) sqliteFree((char*)pTmp->target.z); if( pTmp->target.dyn ) sqlite3DbFree(db, (char*)pTmp->target.z);
sqlite3ExprDelete(pTmp->pWhere); sqlite3ExprDelete(db, pTmp->pWhere);
sqlite3ExprListDelete(pTmp->pExprList); sqlite3ExprListDelete(db, pTmp->pExprList);
sqlite3SelectDelete(pTmp->pSelect); sqlite3SelectDelete(db, pTmp->pSelect);
sqlite3IdListDelete(pTmp->pIdList); sqlite3IdListDelete(db, pTmp->pIdList);
sqliteFree(pTmp); sqlite3DbFree(db, pTmp);
} }
} }
@ -62,6 +64,8 @@ void sqlite3BeginTrigger(
assert( pName1!=0 ); /* pName1->z might be NULL, but not pName1 itself */ assert( pName1!=0 ); /* pName1->z might be NULL, but not pName1 itself */
assert( pName2!=0 ); assert( pName2!=0 );
assert( op==TK_INSERT || op==TK_UPDATE || op==TK_DELETE );
assert( op>0 && op<0xff );
if( isTemp ){ if( isTemp ){
/* If TEMP was specified, then the trigger name may not be qualified. */ /* If TEMP was specified, then the trigger name may not be qualified. */
if( pName2->n>0 ){ if( pName2->n>0 ){
@ -83,7 +87,7 @@ void sqlite3BeginTrigger(
** If sqlite3SrcListLookup() returns 0, indicating the table does not ** If sqlite3SrcListLookup() returns 0, indicating the table does not
** exist, the error is caught by the block below. ** exist, the error is caught by the block below.
*/ */
if( !pTableName || sqlite3MallocFailed() ){ if( !pTableName || db->mallocFailed ){
goto trigger_cleanup; goto trigger_cleanup;
} }
pTab = sqlite3SrcListLookup(pParse, pTableName); pTab = sqlite3SrcListLookup(pParse, pTableName);
@ -92,7 +96,7 @@ void sqlite3BeginTrigger(
} }
/* Ensure the table name matches database name and that the table exists */ /* Ensure the table name matches database name and that the table exists */
if( sqlite3MallocFailed() ) goto trigger_cleanup; if( db->mallocFailed ) goto trigger_cleanup;
assert( pTableName->nSrc==1 ); assert( pTableName->nSrc==1 );
if( sqlite3FixInit(&sFix, pParse, iDb, "trigger", pName) && if( sqlite3FixInit(&sFix, pParse, iDb, "trigger", pName) &&
sqlite3FixSrcList(&sFix, pTableName) ){ sqlite3FixSrcList(&sFix, pTableName) ){
@ -110,11 +114,12 @@ void sqlite3BeginTrigger(
/* Check that the trigger name is not reserved and that no trigger of the /* Check that the trigger name is not reserved and that no trigger of the
** specified name exists */ ** specified name exists */
zName = sqlite3NameFromToken(pName); zName = sqlite3NameFromToken(db, pName);
if( !zName || SQLITE_OK!=sqlite3CheckObjectName(pParse, zName) ){ if( !zName || SQLITE_OK!=sqlite3CheckObjectName(pParse, zName) ){
goto trigger_cleanup; goto trigger_cleanup;
} }
if( sqlite3HashFind(&(db->aDb[iDb].pSchema->trigHash), zName,strlen(zName)) ){ if( sqlite3HashFind(&(db->aDb[iDb].pSchema->trigHash),
zName, sqlite3Strlen30(zName)) ){
if( !noErr ){ if( !noErr ){
sqlite3ErrorMsg(pParse, "trigger %T already exists", pName); sqlite3ErrorMsg(pParse, "trigger %T already exists", pName);
} }
@ -168,28 +173,28 @@ void sqlite3BeginTrigger(
} }
/* Build the Trigger object */ /* Build the Trigger object */
pTrigger = (Trigger*)sqliteMalloc(sizeof(Trigger)); pTrigger = (Trigger*)sqlite3DbMallocZero(db, sizeof(Trigger));
if( pTrigger==0 ) goto trigger_cleanup; if( pTrigger==0 ) goto trigger_cleanup;
pTrigger->name = zName; pTrigger->name = zName;
zName = 0; zName = 0;
pTrigger->table = sqliteStrDup(pTableName->a[0].zName); pTrigger->table = sqlite3DbStrDup(db, pTableName->a[0].zName);
pTrigger->pSchema = db->aDb[iDb].pSchema; pTrigger->pSchema = db->aDb[iDb].pSchema;
pTrigger->pTabSchema = pTab->pSchema; pTrigger->pTabSchema = pTab->pSchema;
pTrigger->op = op; pTrigger->op = (u8)op;
pTrigger->tr_tm = tr_tm==TK_BEFORE ? TRIGGER_BEFORE : TRIGGER_AFTER; pTrigger->tr_tm = tr_tm==TK_BEFORE ? TRIGGER_BEFORE : TRIGGER_AFTER;
pTrigger->pWhen = sqlite3ExprDup(pWhen); pTrigger->pWhen = sqlite3ExprDup(db, pWhen);
pTrigger->pColumns = sqlite3IdListDup(pColumns); pTrigger->pColumns = sqlite3IdListDup(db, pColumns);
sqlite3TokenCopy(&pTrigger->nameToken,pName); sqlite3TokenCopy(db, &pTrigger->nameToken,pName);
assert( pParse->pNewTrigger==0 ); assert( pParse->pNewTrigger==0 );
pParse->pNewTrigger = pTrigger; pParse->pNewTrigger = pTrigger;
trigger_cleanup: trigger_cleanup:
sqliteFree(zName); sqlite3DbFree(db, zName);
sqlite3SrcListDelete(pTableName); sqlite3SrcListDelete(db, pTableName);
sqlite3IdListDelete(pColumns); sqlite3IdListDelete(db, pColumns);
sqlite3ExprDelete(pWhen); sqlite3ExprDelete(db, pWhen);
if( !pParse->pNewTrigger ){ if( !pParse->pNewTrigger ){
sqlite3DeleteTrigger(pTrigger); sqlite3DeleteTrigger(db, pTrigger);
}else{ }else{
assert( pParse->pNewTrigger==pTrigger ); assert( pParse->pNewTrigger==pTrigger );
} }
@ -227,34 +232,23 @@ void sqlite3FinishTrigger(
** build the sqlite_master entry ** build the sqlite_master entry
*/ */
if( !db->init.busy ){ if( !db->init.busy ){
static const VdbeOpList insertTrig[] = {
{ OP_NewRowid, 0, 0, 0 },
{ OP_String8, 0, 0, "trigger" },
{ OP_String8, 0, 0, 0 }, /* 2: trigger name */
{ OP_String8, 0, 0, 0 }, /* 3: table name */
{ OP_Integer, 0, 0, 0 },
{ OP_String8, 0, 0, "CREATE TRIGGER "},
{ OP_String8, 0, 0, 0 }, /* 6: SQL */
{ OP_Concat, 0, 0, 0 },
{ OP_MakeRecord, 5, 0, "aaada" },
{ OP_Insert, 0, 0, 0 },
};
int addr;
Vdbe *v; Vdbe *v;
char *z;
/* Make an entry in the sqlite_master table */ /* Make an entry in the sqlite_master table */
v = sqlite3GetVdbe(pParse); v = sqlite3GetVdbe(pParse);
if( v==0 ) goto triggerfinish_cleanup; if( v==0 ) goto triggerfinish_cleanup;
sqlite3BeginWriteOperation(pParse, 0, iDb); sqlite3BeginWriteOperation(pParse, 0, iDb);
sqlite3OpenMasterTable(pParse, iDb); z = sqlite3DbStrNDup(db, (char*)pAll->z, pAll->n);
addr = sqlite3VdbeAddOpList(v, ArraySize(insertTrig), insertTrig); sqlite3NestedParse(pParse,
sqlite3VdbeChangeP3(v, addr+2, pTrig->name, 0); "INSERT INTO %Q.%s VALUES('trigger',%Q,%Q,0,'CREATE TRIGGER %q')",
sqlite3VdbeChangeP3(v, addr+3, pTrig->table, 0); db->aDb[iDb].zName, SCHEMA_TABLE(iDb), pTrig->name,
sqlite3VdbeChangeP3(v, addr+6, (char*)pAll->z, pAll->n); pTrig->table, z);
sqlite3ChangeCookie(db, v, iDb); sqlite3DbFree(db, z);
sqlite3VdbeAddOp(v, OP_Close, 0, 0); sqlite3ChangeCookie(pParse, iDb);
sqlite3VdbeOp3(v, OP_ParseSchema, iDb, 0, sqlite3VdbeAddOp4(v, OP_ParseSchema, iDb, 0, 0, sqlite3MPrintf(
sqlite3MPrintf("type='trigger' AND name='%q'", pTrig->name), P3_DYNAMIC); db, "type='trigger' AND name='%q'", pTrig->name), P4_DYNAMIC
);
} }
if( db->init.busy ){ if( db->init.busy ){
@ -262,12 +256,13 @@ void sqlite3FinishTrigger(
Table *pTab; Table *pTab;
Trigger *pDel; Trigger *pDel;
pDel = sqlite3HashInsert(&db->aDb[iDb].pSchema->trigHash, pDel = sqlite3HashInsert(&db->aDb[iDb].pSchema->trigHash,
pTrig->name, strlen(pTrig->name), pTrig); pTrig->name, sqlite3Strlen30(pTrig->name), pTrig);
if( pDel ){ if( pDel ){
assert( sqlite3MallocFailed() && pDel==pTrig ); assert( pDel==pTrig );
db->mallocFailed = 1;
goto triggerfinish_cleanup; goto triggerfinish_cleanup;
} }
n = strlen(pTrig->table) + 1; n = sqlite3Strlen30(pTrig->table) + 1;
pTab = sqlite3HashFind(&pTrig->pTabSchema->tblHash, pTrig->table, n); pTab = sqlite3HashFind(&pTrig->pTabSchema->tblHash, pTrig->table, n);
assert( pTab!=0 ); assert( pTab!=0 );
pTrig->pNext = pTab->pTrigger; pTrig->pNext = pTab->pTrigger;
@ -276,44 +271,44 @@ void sqlite3FinishTrigger(
} }
triggerfinish_cleanup: triggerfinish_cleanup:
sqlite3DeleteTrigger(pTrig); sqlite3DeleteTrigger(db, pTrig);
assert( !pParse->pNewTrigger ); assert( !pParse->pNewTrigger );
sqlite3DeleteTriggerStep(pStepList); sqlite3DeleteTriggerStep(db, pStepList);
} }
/* /*
** Make a copy of all components of the given trigger step. This has ** Make a copy of all components of the given trigger step. This has
** the effect of copying all Expr.token.z values into memory obtained ** the effect of copying all Expr.token.z values into memory obtained
** from sqliteMalloc(). As initially created, the Expr.token.z values ** from sqlite3_malloc(). As initially created, the Expr.token.z values
** all point to the input string that was fed to the parser. But that ** all point to the input string that was fed to the parser. But that
** string is ephemeral - it will go away as soon as the sqlite3_exec() ** string is ephemeral - it will go away as soon as the sqlite3_exec()
** call that started the parser exits. This routine makes a persistent ** call that started the parser exits. This routine makes a persistent
** copy of all the Expr.token.z strings so that the TriggerStep structure ** copy of all the Expr.token.z strings so that the TriggerStep structure
** will be valid even after the sqlite3_exec() call returns. ** will be valid even after the sqlite3_exec() call returns.
*/ */
static void sqlitePersistTriggerStep(TriggerStep *p){ static void sqlitePersistTriggerStep(sqlite3 *db, TriggerStep *p){
if( p->target.z ){ if( p->target.z ){
p->target.z = (u8*)sqliteStrNDup((char*)p->target.z, p->target.n); p->target.z = (u8*)sqlite3DbStrNDup(db, (char*)p->target.z, p->target.n);
p->target.dyn = 1; p->target.dyn = 1;
} }
if( p->pSelect ){ if( p->pSelect ){
Select *pNew = sqlite3SelectDup(p->pSelect); Select *pNew = sqlite3SelectDup(db, p->pSelect);
sqlite3SelectDelete(p->pSelect); sqlite3SelectDelete(db, p->pSelect);
p->pSelect = pNew; p->pSelect = pNew;
} }
if( p->pWhere ){ if( p->pWhere ){
Expr *pNew = sqlite3ExprDup(p->pWhere); Expr *pNew = sqlite3ExprDup(db, p->pWhere);
sqlite3ExprDelete(p->pWhere); sqlite3ExprDelete(db, p->pWhere);
p->pWhere = pNew; p->pWhere = pNew;
} }
if( p->pExprList ){ if( p->pExprList ){
ExprList *pNew = sqlite3ExprListDup(p->pExprList); ExprList *pNew = sqlite3ExprListDup(db, p->pExprList);
sqlite3ExprListDelete(p->pExprList); sqlite3ExprListDelete(db, p->pExprList);
p->pExprList = pNew; p->pExprList = pNew;
} }
if( p->pIdList ){ if( p->pIdList ){
IdList *pNew = sqlite3IdListDup(p->pIdList); IdList *pNew = sqlite3IdListDup(db, p->pIdList);
sqlite3IdListDelete(p->pIdList); sqlite3IdListDelete(db, p->pIdList);
p->pIdList = pNew; p->pIdList = pNew;
} }
} }
@ -325,17 +320,17 @@ static void sqlitePersistTriggerStep(TriggerStep *p){
** The parser calls this routine when it finds a SELECT statement in ** The parser calls this routine when it finds a SELECT statement in
** body of a TRIGGER. ** body of a TRIGGER.
*/ */
TriggerStep *sqlite3TriggerSelectStep(Select *pSelect){ TriggerStep *sqlite3TriggerSelectStep(sqlite3 *db, Select *pSelect){
TriggerStep *pTriggerStep = sqliteMalloc(sizeof(TriggerStep)); TriggerStep *pTriggerStep = sqlite3DbMallocZero(db, sizeof(TriggerStep));
if( pTriggerStep==0 ) { if( pTriggerStep==0 ) {
sqlite3SelectDelete(pSelect); sqlite3SelectDelete(db, pSelect);
return 0; return 0;
} }
pTriggerStep->op = TK_SELECT; pTriggerStep->op = TK_SELECT;
pTriggerStep->pSelect = pSelect; pTriggerStep->pSelect = pSelect;
pTriggerStep->orconf = OE_Default; pTriggerStep->orconf = OE_Default;
sqlitePersistTriggerStep(pTriggerStep); sqlitePersistTriggerStep(db, pTriggerStep);
return pTriggerStep; return pTriggerStep;
} }
@ -348,17 +343,19 @@ TriggerStep *sqlite3TriggerSelectStep(Select *pSelect){
** body of a trigger. ** body of a trigger.
*/ */
TriggerStep *sqlite3TriggerInsertStep( TriggerStep *sqlite3TriggerInsertStep(
sqlite3 *db, /* The database connection */
Token *pTableName, /* Name of the table into which we insert */ Token *pTableName, /* Name of the table into which we insert */
IdList *pColumn, /* List of columns in pTableName to insert into */ IdList *pColumn, /* List of columns in pTableName to insert into */
ExprList *pEList, /* The VALUE clause: a list of values to be inserted */ ExprList *pEList, /* The VALUE clause: a list of values to be inserted */
Select *pSelect, /* A SELECT statement that supplies values */ Select *pSelect, /* A SELECT statement that supplies values */
int orconf /* The conflict algorithm (OE_Abort, OE_Replace, etc.) */ int orconf /* The conflict algorithm (OE_Abort, OE_Replace, etc.) */
){ ){
TriggerStep *pTriggerStep = sqliteMalloc(sizeof(TriggerStep)); TriggerStep *pTriggerStep;
assert(pEList == 0 || pSelect == 0); assert(pEList == 0 || pSelect == 0);
assert(pEList != 0 || pSelect != 0); assert(pEList != 0 || pSelect != 0 || db->mallocFailed);
pTriggerStep = sqlite3DbMallocZero(db, sizeof(TriggerStep));
if( pTriggerStep ){ if( pTriggerStep ){
pTriggerStep->op = TK_INSERT; pTriggerStep->op = TK_INSERT;
pTriggerStep->pSelect = pSelect; pTriggerStep->pSelect = pSelect;
@ -366,11 +363,11 @@ TriggerStep *sqlite3TriggerInsertStep(
pTriggerStep->pIdList = pColumn; pTriggerStep->pIdList = pColumn;
pTriggerStep->pExprList = pEList; pTriggerStep->pExprList = pEList;
pTriggerStep->orconf = orconf; pTriggerStep->orconf = orconf;
sqlitePersistTriggerStep(pTriggerStep); sqlitePersistTriggerStep(db, pTriggerStep);
}else{ }else{
sqlite3IdListDelete(pColumn); sqlite3IdListDelete(db, pColumn);
sqlite3ExprListDelete(pEList); sqlite3ExprListDelete(db, pEList);
sqlite3SelectDup(pSelect); sqlite3SelectDelete(db, pSelect);
} }
return pTriggerStep; return pTriggerStep;
@ -382,15 +379,16 @@ TriggerStep *sqlite3TriggerInsertStep(
** sees an UPDATE statement inside the body of a CREATE TRIGGER. ** sees an UPDATE statement inside the body of a CREATE TRIGGER.
*/ */
TriggerStep *sqlite3TriggerUpdateStep( TriggerStep *sqlite3TriggerUpdateStep(
sqlite3 *db, /* The database connection */
Token *pTableName, /* Name of the table to be updated */ Token *pTableName, /* Name of the table to be updated */
ExprList *pEList, /* The SET clause: list of column and new values */ ExprList *pEList, /* The SET clause: list of column and new values */
Expr *pWhere, /* The WHERE clause */ Expr *pWhere, /* The WHERE clause */
int orconf /* The conflict algorithm. (OE_Abort, OE_Ignore, etc) */ int orconf /* The conflict algorithm. (OE_Abort, OE_Ignore, etc) */
){ ){
TriggerStep *pTriggerStep = sqliteMalloc(sizeof(TriggerStep)); TriggerStep *pTriggerStep = sqlite3DbMallocZero(db, sizeof(TriggerStep));
if( pTriggerStep==0 ){ if( pTriggerStep==0 ){
sqlite3ExprListDelete(pEList); sqlite3ExprListDelete(db, pEList);
sqlite3ExprDelete(pWhere); sqlite3ExprDelete(db, pWhere);
return 0; return 0;
} }
@ -399,7 +397,7 @@ TriggerStep *sqlite3TriggerUpdateStep(
pTriggerStep->pExprList = pEList; pTriggerStep->pExprList = pEList;
pTriggerStep->pWhere = pWhere; pTriggerStep->pWhere = pWhere;
pTriggerStep->orconf = orconf; pTriggerStep->orconf = orconf;
sqlitePersistTriggerStep(pTriggerStep); sqlitePersistTriggerStep(db, pTriggerStep);
return pTriggerStep; return pTriggerStep;
} }
@ -409,10 +407,14 @@ TriggerStep *sqlite3TriggerUpdateStep(
** a pointer to that trigger step. The parser calls this routine when it ** a pointer to that trigger step. The parser calls this routine when it
** sees a DELETE statement inside the body of a CREATE TRIGGER. ** sees a DELETE statement inside the body of a CREATE TRIGGER.
*/ */
TriggerStep *sqlite3TriggerDeleteStep(Token *pTableName, Expr *pWhere){ TriggerStep *sqlite3TriggerDeleteStep(
TriggerStep *pTriggerStep = sqliteMalloc(sizeof(TriggerStep)); sqlite3 *db, /* Database connection */
Token *pTableName, /* The table from which rows are deleted */
Expr *pWhere /* The WHERE clause */
){
TriggerStep *pTriggerStep = sqlite3DbMallocZero(db, sizeof(TriggerStep));
if( pTriggerStep==0 ){ if( pTriggerStep==0 ){
sqlite3ExprDelete(pWhere); sqlite3ExprDelete(db, pWhere);
return 0; return 0;
} }
@ -420,7 +422,7 @@ TriggerStep *sqlite3TriggerDeleteStep(Token *pTableName, Expr *pWhere){
pTriggerStep->target = *pTableName; pTriggerStep->target = *pTableName;
pTriggerStep->pWhere = pWhere; pTriggerStep->pWhere = pWhere;
pTriggerStep->orconf = OE_Default; pTriggerStep->orconf = OE_Default;
sqlitePersistTriggerStep(pTriggerStep); sqlitePersistTriggerStep(db, pTriggerStep);
return pTriggerStep; return pTriggerStep;
} }
@ -428,15 +430,15 @@ TriggerStep *sqlite3TriggerDeleteStep(Token *pTableName, Expr *pWhere){
/* /*
** Recursively delete a Trigger structure ** Recursively delete a Trigger structure
*/ */
void sqlite3DeleteTrigger(Trigger *pTrigger){ void sqlite3DeleteTrigger(sqlite3 *db, Trigger *pTrigger){
if( pTrigger==0 ) return; if( pTrigger==0 ) return;
sqlite3DeleteTriggerStep(pTrigger->step_list); sqlite3DeleteTriggerStep(db, pTrigger->step_list);
sqliteFree(pTrigger->name); sqlite3DbFree(db, pTrigger->name);
sqliteFree(pTrigger->table); sqlite3DbFree(db, pTrigger->table);
sqlite3ExprDelete(pTrigger->pWhen); sqlite3ExprDelete(db, pTrigger->pWhen);
sqlite3IdListDelete(pTrigger->pColumns); sqlite3IdListDelete(db, pTrigger->pColumns);
if( pTrigger->nameToken.dyn ) sqliteFree((char*)pTrigger->nameToken.z); if( pTrigger->nameToken.dyn ) sqlite3DbFree(db, (char*)pTrigger->nameToken.z);
sqliteFree(pTrigger); sqlite3DbFree(db, pTrigger);
} }
/* /*
@ -455,7 +457,7 @@ void sqlite3DropTrigger(Parse *pParse, SrcList *pName, int noErr){
int nName; int nName;
sqlite3 *db = pParse->db; sqlite3 *db = pParse->db;
if( sqlite3MallocFailed() ) goto drop_trigger_cleanup; if( db->mallocFailed ) goto drop_trigger_cleanup;
if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){ if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){
goto drop_trigger_cleanup; goto drop_trigger_cleanup;
} }
@ -463,7 +465,7 @@ void sqlite3DropTrigger(Parse *pParse, SrcList *pName, int noErr){
assert( pName->nSrc==1 ); assert( pName->nSrc==1 );
zDb = pName->a[0].zDatabase; zDb = pName->a[0].zDatabase;
zName = pName->a[0].zName; zName = pName->a[0].zName;
nName = strlen(zName); nName = sqlite3Strlen30(zName);
for(i=OMIT_TEMPDB; i<db->nDb; i++){ for(i=OMIT_TEMPDB; i<db->nDb; i++){
int j = (i<2) ? i^1 : i; /* Search TEMP before MAIN */ int j = (i<2) ? i^1 : i; /* Search TEMP before MAIN */
if( zDb && sqlite3StrICmp(db->aDb[j].zName, zDb) ) continue; if( zDb && sqlite3StrICmp(db->aDb[j].zName, zDb) ) continue;
@ -479,7 +481,7 @@ void sqlite3DropTrigger(Parse *pParse, SrcList *pName, int noErr){
sqlite3DropTriggerPtr(pParse, pTrigger); sqlite3DropTriggerPtr(pParse, pTrigger);
drop_trigger_cleanup: drop_trigger_cleanup:
sqlite3SrcListDelete(pName); sqlite3SrcListDelete(db, pName);
} }
/* /*
@ -487,7 +489,7 @@ drop_trigger_cleanup:
** is set on. ** is set on.
*/ */
static Table *tableOfTrigger(Trigger *pTrigger){ static Table *tableOfTrigger(Trigger *pTrigger){
int n = strlen(pTrigger->table) + 1; int n = sqlite3Strlen30(pTrigger->table) + 1;
return sqlite3HashFind(&pTrigger->pTabSchema->tblHash, pTrigger->table, n); return sqlite3HashFind(&pTrigger->pTabSchema->tblHash, pTrigger->table, n);
} }
@ -526,12 +528,12 @@ void sqlite3DropTriggerPtr(Parse *pParse, Trigger *pTrigger){
int base; int base;
static const VdbeOpList dropTrigger[] = { static const VdbeOpList dropTrigger[] = {
{ OP_Rewind, 0, ADDR(9), 0}, { OP_Rewind, 0, ADDR(9), 0},
{ OP_String8, 0, 0, 0}, /* 1 */ { OP_String8, 0, 1, 0}, /* 1 */
{ OP_Column, 0, 1, 0}, { OP_Column, 0, 1, 2},
{ OP_Ne, 0, ADDR(8), 0}, { OP_Ne, 2, ADDR(8), 1},
{ OP_String8, 0, 0, "trigger"}, { OP_String8, 0, 1, 0}, /* 4: "trigger" */
{ OP_Column, 0, 0, 0}, { OP_Column, 0, 0, 2},
{ OP_Ne, 0, ADDR(8), 0}, { OP_Ne, 2, ADDR(8), 1},
{ OP_Delete, 0, 0, 0}, { OP_Delete, 0, 0, 0},
{ OP_Next, 0, ADDR(1), 0}, /* 8 */ { OP_Next, 0, ADDR(1), 0}, /* 8 */
}; };
@ -539,10 +541,11 @@ void sqlite3DropTriggerPtr(Parse *pParse, Trigger *pTrigger){
sqlite3BeginWriteOperation(pParse, 0, iDb); sqlite3BeginWriteOperation(pParse, 0, iDb);
sqlite3OpenMasterTable(pParse, iDb); sqlite3OpenMasterTable(pParse, iDb);
base = sqlite3VdbeAddOpList(v, ArraySize(dropTrigger), dropTrigger); base = sqlite3VdbeAddOpList(v, ArraySize(dropTrigger), dropTrigger);
sqlite3VdbeChangeP3(v, base+1, pTrigger->name, 0); sqlite3VdbeChangeP4(v, base+1, pTrigger->name, 0);
sqlite3ChangeCookie(db, v, iDb); sqlite3VdbeChangeP4(v, base+4, "trigger", P4_STATIC);
sqlite3VdbeAddOp(v, OP_Close, 0, 0); sqlite3ChangeCookie(pParse, iDb);
sqlite3VdbeOp3(v, OP_DropTrigger, iDb, 0, pTrigger->name, 0); sqlite3VdbeAddOp2(v, OP_Close, 0, 0);
sqlite3VdbeAddOp4(v, OP_DropTrigger, iDb, 0, 0, pTrigger->name, 0);
} }
} }
@ -551,7 +554,7 @@ void sqlite3DropTriggerPtr(Parse *pParse, Trigger *pTrigger){
*/ */
void sqlite3UnlinkAndDeleteTrigger(sqlite3 *db, int iDb, const char *zName){ void sqlite3UnlinkAndDeleteTrigger(sqlite3 *db, int iDb, const char *zName){
Trigger *pTrigger; Trigger *pTrigger;
int nName = strlen(zName); int nName = sqlite3Strlen30(zName);
pTrigger = sqlite3HashInsert(&(db->aDb[iDb].pSchema->trigHash), pTrigger = sqlite3HashInsert(&(db->aDb[iDb].pSchema->trigHash),
zName, nName, 0); zName, nName, 0);
if( pTrigger ){ if( pTrigger ){
@ -570,7 +573,7 @@ void sqlite3UnlinkAndDeleteTrigger(sqlite3 *db, int iDb, const char *zName){
} }
assert(cc); assert(cc);
} }
sqlite3DeleteTrigger(pTrigger); sqlite3DeleteTrigger(db, pTrigger);
db->flags |= SQLITE_InternChanges; db->flags |= SQLITE_InternChanges;
} }
} }
@ -603,7 +606,6 @@ static int checkColumnOverLap(IdList *pIdList, ExprList *pEList){
** TRIGGER_AFTER. ** TRIGGER_AFTER.
*/ */
int sqlite3TriggersExist( int sqlite3TriggersExist(
Parse *pParse, /* Used to check for recursive triggers */
Table *pTab, /* The table the contains the triggers */ Table *pTab, /* The table the contains the triggers */
int op, /* one of TK_DELETE, TK_INSERT, TK_UPDATE */ int op, /* one of TK_DELETE, TK_INSERT, TK_UPDATE */
ExprList *pChanges /* Columns that change in an UPDATE statement */ ExprList *pChanges /* Columns that change in an UPDATE statement */
@ -643,10 +645,10 @@ static SrcList *targetSrcList(
if( iDb==0 || iDb>=2 ){ if( iDb==0 || iDb>=2 ){
assert( iDb<pParse->db->nDb ); assert( iDb<pParse->db->nDb );
sDb.z = (u8*)pParse->db->aDb[iDb].zName; sDb.z = (u8*)pParse->db->aDb[iDb].zName;
sDb.n = strlen((char*)sDb.z); sDb.n = sqlite3Strlen30((char*)sDb.z);
pSrc = sqlite3SrcListAppend(0, &sDb, &pStep->target); pSrc = sqlite3SrcListAppend(pParse->db, 0, &sDb, &pStep->target);
} else { } else {
pSrc = sqlite3SrcListAppend(0, &pStep->target, 0); pSrc = sqlite3SrcListAppend(pParse->db, 0, &pStep->target, 0);
} }
return pSrc; return pSrc;
} }
@ -663,51 +665,56 @@ static int codeTriggerProgram(
TriggerStep * pTriggerStep = pStepList; TriggerStep * pTriggerStep = pStepList;
int orconf; int orconf;
Vdbe *v = pParse->pVdbe; Vdbe *v = pParse->pVdbe;
sqlite3 *db = pParse->db;
assert( pTriggerStep!=0 ); assert( pTriggerStep!=0 );
assert( v!=0 ); assert( v!=0 );
sqlite3VdbeAddOp(v, OP_ContextPush, 0, 0); sqlite3VdbeAddOp2(v, OP_ContextPush, 0, 0);
VdbeComment((v, "# begin trigger %s", pStepList->pTrig->name)); VdbeComment((v, "begin trigger %s", pStepList->pTrig->name));
while( pTriggerStep ){ while( pTriggerStep ){
sqlite3ExprClearColumnCache(pParse, -1);
orconf = (orconfin == OE_Default)?pTriggerStep->orconf:orconfin; orconf = (orconfin == OE_Default)?pTriggerStep->orconf:orconfin;
pParse->trigStack->orconf = orconf; pParse->trigStack->orconf = orconf;
switch( pTriggerStep->op ){ switch( pTriggerStep->op ){
case TK_SELECT: { case TK_SELECT: {
Select *ss = sqlite3SelectDup(pTriggerStep->pSelect); Select *ss = sqlite3SelectDup(db, pTriggerStep->pSelect);
if( ss ){ if( ss ){
sqlite3SelectResolve(pParse, ss, 0); SelectDest dest;
sqlite3Select(pParse, ss, SRT_Discard, 0, 0, 0, 0, 0);
sqlite3SelectDelete(ss); sqlite3SelectDestInit(&dest, SRT_Discard, 0);
sqlite3Select(pParse, ss, &dest);
sqlite3SelectDelete(db, ss);
} }
break; break;
} }
case TK_UPDATE: { case TK_UPDATE: {
SrcList *pSrc; SrcList *pSrc;
pSrc = targetSrcList(pParse, pTriggerStep); pSrc = targetSrcList(pParse, pTriggerStep);
sqlite3VdbeAddOp(v, OP_ResetCount, 0, 0); sqlite3VdbeAddOp2(v, OP_ResetCount, 0, 0);
sqlite3Update(pParse, pSrc, sqlite3Update(pParse, pSrc,
sqlite3ExprListDup(pTriggerStep->pExprList), sqlite3ExprListDup(db, pTriggerStep->pExprList),
sqlite3ExprDup(pTriggerStep->pWhere), orconf); sqlite3ExprDup(db, pTriggerStep->pWhere), orconf);
sqlite3VdbeAddOp(v, OP_ResetCount, 1, 0); sqlite3VdbeAddOp2(v, OP_ResetCount, 1, 0);
break; break;
} }
case TK_INSERT: { case TK_INSERT: {
SrcList *pSrc; SrcList *pSrc;
pSrc = targetSrcList(pParse, pTriggerStep); pSrc = targetSrcList(pParse, pTriggerStep);
sqlite3VdbeAddOp(v, OP_ResetCount, 0, 0); sqlite3VdbeAddOp2(v, OP_ResetCount, 0, 0);
sqlite3Insert(pParse, pSrc, sqlite3Insert(pParse, pSrc,
sqlite3ExprListDup(pTriggerStep->pExprList), sqlite3ExprListDup(db, pTriggerStep->pExprList),
sqlite3SelectDup(pTriggerStep->pSelect), sqlite3SelectDup(db, pTriggerStep->pSelect),
sqlite3IdListDup(pTriggerStep->pIdList), orconf); sqlite3IdListDup(db, pTriggerStep->pIdList), orconf);
sqlite3VdbeAddOp(v, OP_ResetCount, 1, 0); sqlite3VdbeAddOp2(v, OP_ResetCount, 1, 0);
break; break;
} }
case TK_DELETE: { case TK_DELETE: {
SrcList *pSrc; SrcList *pSrc;
sqlite3VdbeAddOp(v, OP_ResetCount, 0, 0); sqlite3VdbeAddOp2(v, OP_ResetCount, 0, 0);
pSrc = targetSrcList(pParse, pTriggerStep); pSrc = targetSrcList(pParse, pTriggerStep);
sqlite3DeleteFrom(pParse, pSrc, sqlite3ExprDup(pTriggerStep->pWhere)); sqlite3DeleteFrom(pParse, pSrc,
sqlite3VdbeAddOp(v, OP_ResetCount, 1, 0); sqlite3ExprDup(db, pTriggerStep->pWhere));
sqlite3VdbeAddOp2(v, OP_ResetCount, 1, 0);
break; break;
} }
default: default:
@ -715,8 +722,8 @@ static int codeTriggerProgram(
} }
pTriggerStep = pTriggerStep->pNext; pTriggerStep = pTriggerStep->pNext;
} }
sqlite3VdbeAddOp(v, OP_ContextPop, 0, 0); sqlite3VdbeAddOp2(v, OP_ContextPop, 0, 0);
VdbeComment((v, "# end trigger %s", pStepList->pTrig->name)); VdbeComment((v, "end trigger %s", pStepList->pTrig->name));
return 0; return 0;
} }
@ -740,6 +747,13 @@ static int codeTriggerProgram(
** a row containing values to be substituted for old.* expressions in the ** a row containing values to be substituted for old.* expressions in the
** trigger program(s). ** trigger program(s).
** **
** If they are not NULL, the piOldColMask and piNewColMask output variables
** are set to values that describe the columns used by the trigger program
** in the OLD.* and NEW.* tables respectively. If column N of the
** pseudo-table is read at least once, the corresponding bit of the output
** mask is set. If a column with an index greater than 32 is read, the
** output mask is set to the special value 0xffffffff.
**
*/ */
int sqlite3CodeRowTrigger( int sqlite3CodeRowTrigger(
Parse *pParse, /* Parse context */ Parse *pParse, /* Parse context */
@ -750,11 +764,17 @@ int sqlite3CodeRowTrigger(
int newIdx, /* The indice of the "new" row to access */ int newIdx, /* The indice of the "new" row to access */
int oldIdx, /* The indice of the "old" row to access */ int oldIdx, /* The indice of the "old" row to access */
int orconf, /* ON CONFLICT policy */ int orconf, /* ON CONFLICT policy */
int ignoreJump /* Instruction to jump to for RAISE(IGNORE) */ int ignoreJump, /* Instruction to jump to for RAISE(IGNORE) */
u32 *piOldColMask, /* OUT: Mask of columns used from the OLD.* table */
u32 *piNewColMask /* OUT: Mask of columns used from the NEW.* table */
){ ){
Trigger *p; Trigger *p;
sqlite3 *db = pParse->db;
TriggerStack trigStackEntry; TriggerStack trigStackEntry;
trigStackEntry.oldColMask = 0;
trigStackEntry.newColMask = 0;
assert(op == TK_UPDATE || op == TK_INSERT || op == TK_DELETE); assert(op == TK_UPDATE || op == TK_INSERT || op == TK_DELETE);
assert(tr_tm == TRIGGER_BEFORE || tr_tm == TRIGGER_AFTER ); assert(tr_tm == TRIGGER_BEFORE || tr_tm == TRIGGER_AFTER );
@ -767,7 +787,7 @@ int sqlite3CodeRowTrigger(
if( if(
p->op==op && p->op==op &&
p->tr_tm==tr_tm && p->tr_tm==tr_tm &&
(p->pSchema==p->pTabSchema || p->pSchema==pParse->db->aDb[1].pSchema) && (p->pSchema==p->pTabSchema || p->pSchema==db->aDb[1].pSchema) &&
(op!=TK_UPDATE||!p->pColumns||checkColumnOverLap(p->pColumns,pChanges)) (op!=TK_UPDATE||!p->pColumns||checkColumnOverLap(p->pColumns,pChanges))
){ ){
TriggerStack *pS; /* Pointer to trigger-stack entry */ TriggerStack *pS; /* Pointer to trigger-stack entry */
@ -790,6 +810,11 @@ int sqlite3CodeRowTrigger(
AuthContext sContext; AuthContext sContext;
NameContext sNC; NameContext sNC;
#ifndef SQLITE_OMIT_TRACE
sqlite3VdbeAddOp4(pParse->pVdbe, OP_Trace, 0, 0, 0,
sqlite3MPrintf(db, "-- TRIGGER %s", p->name),
P4_DYNAMIC);
#endif
memset(&sNC, 0, sizeof(sNC)); memset(&sNC, 0, sizeof(sNC));
sNC.pParse = pParse; sNC.pParse = pParse;
@ -805,14 +830,14 @@ int sqlite3CodeRowTrigger(
/* code the WHEN clause */ /* code the WHEN clause */
endTrigger = sqlite3VdbeMakeLabel(pParse->pVdbe); endTrigger = sqlite3VdbeMakeLabel(pParse->pVdbe);
whenExpr = sqlite3ExprDup(p->pWhen); whenExpr = sqlite3ExprDup(db, p->pWhen);
if( sqlite3ExprResolveNames(&sNC, whenExpr) ){ if( db->mallocFailed || sqlite3ResolveExprNames(&sNC, whenExpr) ){
pParse->trigStack = trigStackEntry.pNext; pParse->trigStack = trigStackEntry.pNext;
sqlite3ExprDelete(whenExpr); sqlite3ExprDelete(db, whenExpr);
return 1; return 1;
} }
sqlite3ExprIfFalse(pParse, whenExpr, endTrigger, 1); sqlite3ExprIfFalse(pParse, whenExpr, endTrigger, SQLITE_JUMPIFNULL);
sqlite3ExprDelete(whenExpr); sqlite3ExprDelete(db, whenExpr);
codeTriggerProgram(pParse, p->step_list, orconf); codeTriggerProgram(pParse, p->step_list, orconf);
@ -823,6 +848,8 @@ int sqlite3CodeRowTrigger(
sqlite3VdbeResolveLabel(pParse->pVdbe, endTrigger); sqlite3VdbeResolveLabel(pParse->pVdbe, endTrigger);
} }
} }
if( piOldColMask ) *piOldColMask |= trigStackEntry.oldColMask;
if( piNewColMask ) *piNewColMask |= trigStackEntry.newColMask;
return 0; return 0;
} }
#endif /* !defined(SQLITE_OMIT_TRIGGER) */ #endif /* !defined(SQLITE_OMIT_TRIGGER) */

468
update.c
View file

@ -12,7 +12,7 @@
** This file contains C code routines that are called by the parser ** This file contains C code routines that are called by the parser
** to handle UPDATE statements. ** to handle UPDATE statements.
** **
** $Id: update.c,v 1.138 2007/06/25 16:29:34 danielk1977 Exp $ ** $Id: update.c,v 1.191 2008/12/23 23:56:22 drh Exp $
*/ */
#include "sqliteInt.h" #include "sqliteInt.h"
@ -31,7 +31,7 @@ static void updateVirtualTable(
/* /*
** The most recently coded instruction was an OP_Column to retrieve 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 ** i-th column of table pTab. This routine sets the P4 parameter of the
** OP_Column to the default value, if any. ** OP_Column to the default value, if any.
** **
** The default value of a column is specified by a DEFAULT clause in the ** The default value of a column is specified by a DEFAULT clause in the
@ -39,9 +39,9 @@ static void updateVirtualTable(
** was created, or added later to the table definition by an ALTER TABLE ** was created, or added later to the table definition by an ALTER TABLE
** command. If the latter, then the row-records in the table btree on disk ** command. If the latter, then the row-records in the table btree on disk
** may not contain a value for the column and the default value, taken ** may not contain a value for the column and the default value, taken
** from the P3 parameter of the OP_Column instruction, is returned instead. ** from the P4 parameter of the OP_Column instruction, is returned instead.
** If the former, then all row-records are guaranteed to include a value ** If the former, then all row-records are guaranteed to include a value
** for the column and the P3 value is not required. ** for the column and the P4 value is not required.
** **
** Column definitions created by an ALTER TABLE command may only have ** Column definitions created by an ALTER TABLE command may only have
** literal default values specified: a number, null or a string. (If a more ** literal default values specified: a number, null or a string. (If a more
@ -49,7 +49,7 @@ static void updateVirtualTable(
** when the ALTER TABLE is executed and one of the literal values written ** when the ALTER TABLE is executed and one of the literal values written
** into the sqlite_master table.) ** into the sqlite_master table.)
** **
** Therefore, the P3 parameter is only required if the default value for ** Therefore, the P4 parameter is only required if the default value for
** the column is a literal number, string or null. The sqlite3ValueFromExpr() ** the column is a literal number, string or null. The sqlite3ValueFromExpr()
** function is capable of transforming these types of expressions into ** function is capable of transforming these types of expressions into
** sqlite3_value objects. ** sqlite3_value objects.
@ -59,12 +59,12 @@ void sqlite3ColumnDefault(Vdbe *v, Table *pTab, int i){
sqlite3_value *pValue; sqlite3_value *pValue;
u8 enc = ENC(sqlite3VdbeDb(v)); u8 enc = ENC(sqlite3VdbeDb(v));
Column *pCol = &pTab->aCol[i]; Column *pCol = &pTab->aCol[i];
VdbeComment((v, "%s.%s", pTab->zName, pCol->zName));
assert( i<pTab->nCol ); assert( i<pTab->nCol );
sqlite3ValueFromExpr(pCol->pDflt, enc, pCol->affinity, &pValue); sqlite3ValueFromExpr(sqlite3VdbeDb(v), pCol->pDflt, enc,
pCol->affinity, &pValue);
if( pValue ){ if( pValue ){
sqlite3VdbeChangeP3(v, -1, (const char *)pValue, P3_MEM); sqlite3VdbeChangeP4(v, -1, (const char *)pValue, P4_MEM);
}else{
VdbeComment((v, "# %s.%s", pTab->zName, pCol->zName));
} }
} }
} }
@ -90,11 +90,9 @@ void sqlite3Update(
Vdbe *v; /* The virtual database engine */ Vdbe *v; /* The virtual database engine */
Index *pIdx; /* For looping over indices */ Index *pIdx; /* For looping over indices */
int nIdx; /* Number of indices that need updating */ int nIdx; /* Number of indices that need updating */
int nIdxTotal; /* Total number of indices */
int iCur; /* VDBE Cursor number of pTab */ int iCur; /* VDBE Cursor number of pTab */
sqlite3 *db; /* The database structure */ sqlite3 *db; /* The database structure */
Index **apIdx = 0; /* An array of indices that need updating too */ int *aRegIdx = 0; /* One register assigned to each index to be updated */
char *aIdxUsed = 0; /* aIdxUsed[i]==1 if the i-th index is used */
int *aXRef = 0; /* aXRef[i] is the index in pChanges->a[] of the int *aXRef = 0; /* aXRef[i] is the index in pChanges->a[] of the
** an expression for the i-th column of the table. ** an expression for the i-th column of the table.
** aXRef[i]==-1 if the i-th column is not changed. */ ** aXRef[i]==-1 if the i-th column is not changed. */
@ -104,21 +102,35 @@ void sqlite3Update(
AuthContext sContext; /* The authorization context */ AuthContext sContext; /* The authorization context */
NameContext sNC; /* The name-context to resolve expressions in */ NameContext sNC; /* The name-context to resolve expressions in */
int iDb; /* Database containing the table being updated */ int iDb; /* Database containing the table being updated */
int memCnt = 0; /* Memory cell used for counting rows changed */ int j1; /* Addresses of jump instructions */
int okOnePass; /* True for one-pass algorithm without the FIFO */
#ifndef SQLITE_OMIT_TRIGGER #ifndef SQLITE_OMIT_TRIGGER
int isView; /* Trying to update a view */ int isView; /* Trying to update a view */
int triggers_exist = 0; /* True if any row triggers exist */ int triggers_exist = 0; /* True if any row triggers exist */
#endif #endif
int iBeginAfterTrigger = 0; /* Address of after trigger program */
int iEndAfterTrigger = 0; /* Exit of after trigger program */
int iBeginBeforeTrigger = 0; /* Address of before trigger program */
int iEndBeforeTrigger = 0; /* Exit of before trigger program */
u32 old_col_mask = 0; /* Mask of OLD.* columns in use */
u32 new_col_mask = 0; /* Mask of NEW.* columns in use */
int newIdx = -1; /* index of trigger "new" temp table */ int newIdx = -1; /* index of trigger "new" temp table */
int oldIdx = -1; /* index of trigger "old" temp table */ int oldIdx = -1; /* index of trigger "old" temp table */
/* Register Allocations */
int regRowCount = 0; /* A count of rows changed */
int regOldRowid; /* The old rowid */
int regNewRowid; /* The new rowid */
int regData; /* New data for the row */
int regRowSet = 0; /* Rowset of rows to be updated */
sContext.pParse = 0; sContext.pParse = 0;
if( pParse->nErr || sqlite3MallocFailed() ){ db = pParse->db;
if( pParse->nErr || db->mallocFailed ){
goto update_cleanup; goto update_cleanup;
} }
db = pParse->db;
assert( pTabList->nSrc==1 ); assert( pTabList->nSrc==1 );
/* Locate the table which we want to update. /* Locate the table which we want to update.
@ -131,7 +143,7 @@ void sqlite3Update(
** updated is a view ** updated is a view
*/ */
#ifndef SQLITE_OMIT_TRIGGER #ifndef SQLITE_OMIT_TRIGGER
triggers_exist = sqlite3TriggersExist(pParse, pTab, TK_UPDATE, pChanges); triggers_exist = sqlite3TriggersExist(pTab, TK_UPDATE, pChanges);
isView = pTab->pSelect!=0; isView = pTab->pSelect!=0;
#else #else
# define triggers_exist 0 # define triggers_exist 0
@ -148,7 +160,7 @@ void sqlite3Update(
if( sqlite3ViewGetColumnNames(pParse, pTab) ){ if( sqlite3ViewGetColumnNames(pParse, pTab) ){
goto update_cleanup; goto update_cleanup;
} }
aXRef = sqliteMallocRaw( sizeof(int) * pTab->nCol ); aXRef = sqlite3DbMallocRaw(db, sizeof(int) * pTab->nCol );
if( aXRef==0 ) goto update_cleanup; if( aXRef==0 ) goto update_cleanup;
for(i=0; i<pTab->nCol; i++) aXRef[i] = -1; for(i=0; i<pTab->nCol; i++) aXRef[i] = -1;
@ -183,7 +195,7 @@ void sqlite3Update(
*/ */
chngRowid = 0; chngRowid = 0;
for(i=0; i<pChanges->nExpr; i++){ for(i=0; i<pChanges->nExpr; i++){
if( sqlite3ExprResolveNames(&sNC, pChanges->a[i].pExpr) ){ if( sqlite3ResolveExprNames(&sNC, pChanges->a[i].pExpr) ){
goto update_cleanup; goto update_cleanup;
} }
for(j=0; j<pTab->nCol; j++){ for(j=0; j<pTab->nCol; j++){
@ -219,41 +231,47 @@ void sqlite3Update(
#endif #endif
} }
/* Allocate memory for the array apIdx[] and fill it with pointers to every /* Allocate memory for the array aRegIdx[]. There is one entry in the
** index that needs to be updated. Indices only need updating if their ** array for each index associated with table being updated. Fill in
** key includes one of the columns named in pChanges or if the record ** the value with a register number for indices that are to be used
** number of the original table entry is changing. ** and with zero for unused indices.
*/ */
for(nIdx=nIdxTotal=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, nIdxTotal++){ for(nIdx=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, nIdx++){}
if( nIdx>0 ){
aRegIdx = sqlite3DbMallocRaw(db, sizeof(Index*) * nIdx );
if( aRegIdx==0 ) goto update_cleanup;
}
for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
int reg;
if( chngRowid ){ if( chngRowid ){
i = 0; reg = ++pParse->nMem;
}else { }else{
reg = 0;
for(i=0; i<pIdx->nColumn; i++){ for(i=0; i<pIdx->nColumn; i++){
if( aXRef[pIdx->aiColumn[i]]>=0 ) break; if( aXRef[pIdx->aiColumn[i]]>=0 ){
reg = ++pParse->nMem;
break;
}
} }
} }
if( i<pIdx->nColumn ) nIdx++; aRegIdx[j] = reg;
} }
if( nIdxTotal>0 ){
apIdx = sqliteMallocRaw( sizeof(Index*) * nIdx + nIdxTotal ); /* Allocate a block of register used to store the change record
if( apIdx==0 ) goto update_cleanup; ** sent to sqlite3GenerateConstraintChecks(). There are either
aIdxUsed = (char*)&apIdx[nIdx]; ** one or two registers for holding the rowid. One rowid register
} ** is used if chngRowid is false and two are used if chngRowid is
for(nIdx=j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){ ** true. Following these are pTab->nCol register holding column
if( chngRowid ){ ** data.
i = 0; */
}else{ regOldRowid = regNewRowid = pParse->nMem + 1;
for(i=0; i<pIdx->nColumn; i++){ pParse->nMem += pTab->nCol + 1;
if( aXRef[pIdx->aiColumn[i]]>=0 ) break; if( chngRowid ){
} regNewRowid++;
} pParse->nMem++;
if( i<pIdx->nColumn ){
apIdx[nIdx++] = pIdx;
aIdxUsed[j] = 1;
}else{
aIdxUsed[j] = 0;
}
} }
regData = regNewRowid+1;
/* Begin generating code. /* Begin generating code.
*/ */
@ -273,38 +291,72 @@ void sqlite3Update(
} }
#endif #endif
/* Resolve the column names in all the expressions in the
** WHERE clause.
*/
if( sqlite3ExprResolveNames(&sNC, pWhere) ){
goto update_cleanup;
}
/* Start the view context /* Start the view context
*/ */
if( isView ){ if( isView ){
sqlite3AuthContextPush(pParse, &sContext, pTab->zName); sqlite3AuthContextPush(pParse, &sContext, pTab->zName);
} }
/* Generate the code for triggers.
*/
if( triggers_exist ){
int iGoto;
/* Create pseudo-tables for NEW and OLD
*/
sqlite3VdbeAddOp2(v, OP_SetNumColumns, 0, pTab->nCol);
sqlite3VdbeAddOp2(v, OP_OpenPseudo, oldIdx, 0);
sqlite3VdbeAddOp2(v, OP_SetNumColumns, 0, pTab->nCol);
sqlite3VdbeAddOp2(v, OP_OpenPseudo, newIdx, 0);
iGoto = sqlite3VdbeAddOp2(v, OP_Goto, 0, 0);
addr = sqlite3VdbeMakeLabel(v);
iBeginBeforeTrigger = sqlite3VdbeCurrentAddr(v);
if( sqlite3CodeRowTrigger(pParse, TK_UPDATE, pChanges, TRIGGER_BEFORE, pTab,
newIdx, oldIdx, onError, addr, &old_col_mask, &new_col_mask) ){
goto update_cleanup;
}
iEndBeforeTrigger = sqlite3VdbeAddOp2(v, OP_Goto, 0, 0);
iBeginAfterTrigger = sqlite3VdbeCurrentAddr(v);
if( sqlite3CodeRowTrigger(pParse, TK_UPDATE, pChanges, TRIGGER_AFTER, pTab,
newIdx, oldIdx, onError, addr, &old_col_mask, &new_col_mask) ){
goto update_cleanup;
}
iEndAfterTrigger = sqlite3VdbeAddOp2(v, OP_Goto, 0, 0);
sqlite3VdbeJumpHere(v, iGoto);
}
/* If we are trying to update a view, realize that view into /* If we are trying to update a view, realize that view into
** a ephemeral table. ** a ephemeral table.
*/ */
#if !defined(SQLITE_OMIT_VIEW) && !defined(SQLITE_OMIT_TRIGGER)
if( isView ){ if( isView ){
Select *pView; sqlite3MaterializeView(pParse, pTab, pWhere, iCur);
pView = sqlite3SelectDup(pTab->pSelect); }
sqlite3Select(pParse, pView, SRT_EphemTab, iCur, 0, 0, 0, 0); #endif
sqlite3SelectDelete(pView);
/* Resolve the column names in all the expressions in the
** WHERE clause.
*/
if( sqlite3ResolveExprNames(&sNC, pWhere) ){
goto update_cleanup;
} }
/* Begin the database scan /* Begin the database scan
*/ */
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 0); sqlite3VdbeAddOp2(v, OP_Null, 0, regOldRowid);
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 0,
WHERE_ONEPASS_DESIRED, 0);
if( pWInfo==0 ) goto update_cleanup; if( pWInfo==0 ) goto update_cleanup;
okOnePass = pWInfo->okOnePass;
/* Remember the rowid of every item to be updated. /* Remember the rowid of every item to be updated.
*/ */
sqlite3VdbeAddOp(v, IsVirtual(pTab) ? OP_VRowid : OP_Rowid, iCur, 0); sqlite3VdbeAddOp2(v, IsVirtual(pTab)?OP_VRowid:OP_Rowid, iCur, regOldRowid);
sqlite3VdbeAddOp(v, OP_FifoWrite, 0, 0); if( !okOnePass ){
regRowSet = ++pParse->nMem;
sqlite3VdbeAddOp2(v, OP_RowSetAdd, regRowSet, regOldRowid);
}
/* End the database scan loop. /* End the database scan loop.
*/ */
@ -313,74 +365,8 @@ void sqlite3Update(
/* Initialize the count of updated rows /* Initialize the count of updated rows
*/ */
if( db->flags & SQLITE_CountRows && !pParse->trigStack ){ if( db->flags & SQLITE_CountRows && !pParse->trigStack ){
memCnt = pParse->nMem++; regRowCount = ++pParse->nMem;
sqlite3VdbeAddOp(v, OP_MemInt, 0, memCnt); sqlite3VdbeAddOp2(v, OP_Integer, 0, regRowCount);
}
if( triggers_exist ){
/* Create pseudo-tables for NEW and OLD
*/
sqlite3VdbeAddOp(v, OP_OpenPseudo, oldIdx, 0);
sqlite3VdbeAddOp(v, OP_SetNumColumns, oldIdx, pTab->nCol);
sqlite3VdbeAddOp(v, OP_OpenPseudo, newIdx, 0);
sqlite3VdbeAddOp(v, OP_SetNumColumns, newIdx, pTab->nCol);
/* The top of the update loop for when there are triggers.
*/
addr = sqlite3VdbeAddOp(v, OP_FifoRead, 0, 0);
if( !isView ){
sqlite3VdbeAddOp(v, OP_Dup, 0, 0);
sqlite3VdbeAddOp(v, OP_Dup, 0, 0);
/* Open a cursor and make it point to the record that is
** being updated.
*/
sqlite3OpenTable(pParse, iCur, iDb, pTab, OP_OpenRead);
}
sqlite3VdbeAddOp(v, OP_MoveGe, iCur, 0);
/* Generate the OLD table
*/
sqlite3VdbeAddOp(v, OP_Rowid, iCur, 0);
sqlite3VdbeAddOp(v, OP_RowData, iCur, 0);
sqlite3VdbeAddOp(v, OP_Insert, oldIdx, 0);
/* Generate the NEW table
*/
if( chngRowid ){
sqlite3ExprCodeAndCache(pParse, pRowidExpr);
}else{
sqlite3VdbeAddOp(v, OP_Rowid, iCur, 0);
}
for(i=0; i<pTab->nCol; i++){
if( i==pTab->iPKey ){
sqlite3VdbeAddOp(v, OP_Null, 0, 0);
continue;
}
j = aXRef[i];
if( j<0 ){
sqlite3VdbeAddOp(v, OP_Column, iCur, i);
sqlite3ColumnDefault(v, pTab, i);
}else{
sqlite3ExprCodeAndCache(pParse, pChanges->a[j].pExpr);
}
}
sqlite3VdbeAddOp(v, OP_MakeRecord, pTab->nCol, 0);
if( !isView ){
sqlite3TableAffinityStr(v, pTab);
}
if( pParse->nErr ) goto update_cleanup;
sqlite3VdbeAddOp(v, OP_Insert, newIdx, 0);
if( !isView ){
sqlite3VdbeAddOp(v, OP_Close, iCur, 0);
}
/* Fire the BEFORE and INSTEAD OF triggers
*/
if( sqlite3CodeRowTrigger(pParse, TK_UPDATE, pChanges, TRIGGER_BEFORE, pTab,
newIdx, oldIdx, onError, addr) ){
goto update_cleanup;
}
} }
if( !isView && !IsVirtual(pTab) ){ if( !isView && !IsVirtual(pTab) ){
@ -390,7 +376,7 @@ void sqlite3Update(
** action, then we need to open all indices because we might need ** action, then we need to open all indices because we might need
** to be deleting some records. ** to be deleting some records.
*/ */
sqlite3OpenTable(pParse, iCur, iDb, pTab, OP_OpenWrite); if( !okOnePass ) sqlite3OpenTable(pParse, iCur, iDb, pTab, OP_OpenWrite);
if( onError==OE_Replace ){ if( onError==OE_Replace ){
openAll = 1; openAll = 1;
}else{ }else{
@ -403,112 +389,179 @@ void sqlite3Update(
} }
} }
for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){ for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
if( openAll || aIdxUsed[i] ){ if( openAll || aRegIdx[i]>0 ){
KeyInfo *pKey = sqlite3IndexKeyinfo(pParse, pIdx); KeyInfo *pKey = sqlite3IndexKeyinfo(pParse, pIdx);
sqlite3VdbeAddOp(v, OP_Integer, iDb, 0); sqlite3VdbeAddOp4(v, OP_OpenWrite, iCur+i+1, pIdx->tnum, iDb,
sqlite3VdbeOp3(v, OP_OpenWrite, iCur+i+1, pIdx->tnum, (char*)pKey, P4_KEYINFO_HANDOFF);
(char*)pKey, P3_KEYINFO_HANDOFF);
assert( pParse->nTab>iCur+i+1 ); assert( pParse->nTab>iCur+i+1 );
} }
} }
}
/* Jump back to this point if a trigger encounters an IGNORE constraint. */
if( triggers_exist ){
sqlite3VdbeResolveLabel(v, addr);
}
/* Top of the update loop */
if( okOnePass ){
int a1 = sqlite3VdbeAddOp1(v, OP_NotNull, regOldRowid);
addr = sqlite3VdbeAddOp0(v, OP_Goto);
sqlite3VdbeJumpHere(v, a1);
}else{
addr = sqlite3VdbeAddOp3(v, OP_RowSetRead, regRowSet, 0, regOldRowid);
}
if( triggers_exist ){
int regRowid;
int regRow;
int regCols;
/* Make cursor iCur point to the record that is being updated.
*/
sqlite3VdbeAddOp3(v, OP_NotExists, iCur, addr, regOldRowid);
/* Generate the OLD table
*/
regRowid = sqlite3GetTempReg(pParse);
regRow = sqlite3GetTempReg(pParse);
sqlite3VdbeAddOp2(v, OP_Rowid, iCur, regRowid);
if( !old_col_mask ){
sqlite3VdbeAddOp2(v, OP_Null, 0, regRow);
}else{
sqlite3VdbeAddOp2(v, OP_RowData, iCur, regRow);
}
sqlite3VdbeAddOp3(v, OP_Insert, oldIdx, regRow, regRowid);
/* Generate the NEW table
*/
if( chngRowid ){
sqlite3ExprCodeAndCache(pParse, pRowidExpr, regRowid);
sqlite3VdbeAddOp1(v, OP_MustBeInt, regRowid);
}else{
sqlite3VdbeAddOp2(v, OP_Rowid, iCur, regRowid);
}
regCols = sqlite3GetTempRange(pParse, pTab->nCol);
for(i=0; i<pTab->nCol; i++){
if( i==pTab->iPKey ){
sqlite3VdbeAddOp2(v, OP_Null, 0, regCols+i);
continue;
}
j = aXRef[i];
if( new_col_mask&((u32)1<<i) || new_col_mask==0xffffffff ){
if( j<0 ){
sqlite3VdbeAddOp3(v, OP_Column, iCur, i, regCols+i);
sqlite3ColumnDefault(v, pTab, i);
}else{
sqlite3ExprCodeAndCache(pParse, pChanges->a[j].pExpr, regCols+i);
}
}else{
sqlite3VdbeAddOp2(v, OP_Null, 0, regCols+i);
}
}
sqlite3VdbeAddOp3(v, OP_MakeRecord, regCols, pTab->nCol, regRow);
if( !isView ){
sqlite3TableAffinityStr(v, pTab);
sqlite3ExprCacheAffinityChange(pParse, regCols, pTab->nCol);
}
sqlite3ReleaseTempRange(pParse, regCols, pTab->nCol);
/* if( pParse->nErr ) goto update_cleanup; */
sqlite3VdbeAddOp3(v, OP_Insert, newIdx, regRow, regRowid);
sqlite3ReleaseTempReg(pParse, regRowid);
sqlite3ReleaseTempReg(pParse, regRow);
sqlite3VdbeAddOp2(v, OP_Goto, 0, iBeginBeforeTrigger);
sqlite3VdbeJumpHere(v, iEndBeforeTrigger);
}
if( !isView && !IsVirtual(pTab) ){
/* Loop over every record that needs updating. We have to load /* Loop over every record that needs updating. We have to load
** the old data for each record to be updated because some columns ** the old data for each record to be updated because some columns
** might not change and we will need to copy the old value. ** might not change and we will need to copy the old value.
** Also, the old data is needed to delete the old index entries. ** Also, the old data is needed to delete the old index entries.
** So make the cursor point at the old record. ** So make the cursor point at the old record.
*/ */
if( !triggers_exist ){ sqlite3VdbeAddOp3(v, OP_NotExists, iCur, addr, regOldRowid);
addr = sqlite3VdbeAddOp(v, OP_FifoRead, 0, 0);
sqlite3VdbeAddOp(v, OP_Dup, 0, 0);
}
sqlite3VdbeAddOp(v, OP_NotExists, iCur, addr);
/* If the record number will change, push the record number as it /* If the record number will change, push the record number as it
** will be after the update. (The old record number is currently ** will be after the update. (The old record number is currently
** on top of the stack.) ** on top of the stack.)
*/ */
if( chngRowid ){ if( chngRowid ){
sqlite3ExprCode(pParse, pRowidExpr); sqlite3ExprCode(pParse, pRowidExpr, regNewRowid);
sqlite3VdbeAddOp(v, OP_MustBeInt, 0, 0); sqlite3VdbeAddOp1(v, OP_MustBeInt, regNewRowid);
} }
/* Compute new data for this record. /* Compute new data for this record.
*/ */
for(i=0; i<pTab->nCol; i++){ for(i=0; i<pTab->nCol; i++){
if( i==pTab->iPKey ){ if( i==pTab->iPKey ){
sqlite3VdbeAddOp(v, OP_Null, 0, 0); sqlite3VdbeAddOp2(v, OP_Null, 0, regData+i);
continue; continue;
} }
j = aXRef[i]; j = aXRef[i];
if( j<0 ){ if( j<0 ){
sqlite3VdbeAddOp(v, OP_Column, iCur, i); sqlite3VdbeAddOp3(v, OP_Column, iCur, i, regData+i);
sqlite3ColumnDefault(v, pTab, i); sqlite3ColumnDefault(v, pTab, i);
}else{ }else{
sqlite3ExprCode(pParse, pChanges->a[j].pExpr); sqlite3ExprCode(pParse, pChanges->a[j].pExpr, regData+i);
} }
} }
/* Do constraint checks /* Do constraint checks
*/ */
sqlite3GenerateConstraintChecks(pParse, pTab, iCur, aIdxUsed, chngRowid, 1, sqlite3GenerateConstraintChecks(pParse, pTab, iCur, regNewRowid,
onError, addr); aRegIdx, chngRowid, 1,
onError, addr);
/* Delete the old indices for the current record. /* Delete the old indices for the current record.
*/ */
sqlite3GenerateRowIndexDelete(v, pTab, iCur, aIdxUsed); j1 = sqlite3VdbeAddOp3(v, OP_NotExists, iCur, 0, regOldRowid);
sqlite3GenerateRowIndexDelete(pParse, pTab, iCur, aRegIdx);
/* If changing the record number, delete the old record. /* If changing the record number, delete the old record.
*/ */
if( chngRowid ){ if( chngRowid ){
sqlite3VdbeAddOp(v, OP_Delete, iCur, 0); sqlite3VdbeAddOp2(v, OP_Delete, iCur, 0);
} }
sqlite3VdbeJumpHere(v, j1);
/* Create the new index entries and the new record. /* Create the new index entries and the new record.
*/ */
sqlite3CompleteInsertion(pParse, pTab, iCur, aIdxUsed, chngRowid, 1, -1, 0); sqlite3CompleteInsertion(pParse, pTab, iCur, regNewRowid,
aRegIdx, 1, -1, 0);
} }
/* Increment the row counter /* Increment the row counter
*/ */
if( db->flags & SQLITE_CountRows && !pParse->trigStack){ if( db->flags & SQLITE_CountRows && !pParse->trigStack){
sqlite3VdbeAddOp(v, OP_MemIncr, 1, memCnt); sqlite3VdbeAddOp2(v, OP_AddImm, regRowCount, 1);
} }
/* If there are triggers, close all the cursors after each iteration /* If there are triggers, close all the cursors after each iteration
** through the loop. The fire the after triggers. ** through the loop. The fire the after triggers.
*/ */
if( triggers_exist ){ if( triggers_exist ){
if( !isView ){ sqlite3VdbeAddOp2(v, OP_Goto, 0, iBeginAfterTrigger);
for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){ sqlite3VdbeJumpHere(v, iEndAfterTrigger);
if( openAll || aIdxUsed[i] )
sqlite3VdbeAddOp(v, OP_Close, iCur+i+1, 0);
}
sqlite3VdbeAddOp(v, OP_Close, iCur, 0);
}
if( sqlite3CodeRowTrigger(pParse, TK_UPDATE, pChanges, TRIGGER_AFTER, pTab,
newIdx, oldIdx, onError, addr) ){
goto update_cleanup;
}
} }
/* Repeat the above with the next record to be updated, until /* Repeat the above with the next record to be updated, until
** all record selected by the WHERE clause have been updated. ** all record selected by the WHERE clause have been updated.
*/ */
sqlite3VdbeAddOp(v, OP_Goto, 0, addr); sqlite3VdbeAddOp2(v, OP_Goto, 0, addr);
sqlite3VdbeJumpHere(v, addr); sqlite3VdbeJumpHere(v, addr);
/* Close all tables if there were no FOR EACH ROW triggers */ /* Close all tables */
if( !triggers_exist ){ for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){ if( openAll || aRegIdx[i]>0 ){
if( openAll || aIdxUsed[i] ){ sqlite3VdbeAddOp2(v, OP_Close, iCur+i+1, 0);
sqlite3VdbeAddOp(v, OP_Close, iCur+i+1, 0);
}
} }
sqlite3VdbeAddOp(v, OP_Close, iCur, 0); }
}else{ sqlite3VdbeAddOp2(v, OP_Close, iCur, 0);
sqlite3VdbeAddOp(v, OP_Close, newIdx, 0); if( triggers_exist ){
sqlite3VdbeAddOp(v, OP_Close, oldIdx, 0); sqlite3VdbeAddOp2(v, OP_Close, newIdx, 0);
sqlite3VdbeAddOp2(v, OP_Close, oldIdx, 0);
} }
/* /*
@ -517,19 +570,18 @@ void sqlite3Update(
** invoke the callback function. ** invoke the callback function.
*/ */
if( db->flags & SQLITE_CountRows && !pParse->trigStack && pParse->nested==0 ){ if( db->flags & SQLITE_CountRows && !pParse->trigStack && pParse->nested==0 ){
sqlite3VdbeAddOp(v, OP_MemLoad, memCnt, 0); sqlite3VdbeAddOp2(v, OP_ResultRow, regRowCount, 1);
sqlite3VdbeAddOp(v, OP_Callback, 1, 0);
sqlite3VdbeSetNumCols(v, 1); sqlite3VdbeSetNumCols(v, 1);
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "rows updated", P3_STATIC); sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "rows updated", SQLITE_STATIC);
} }
update_cleanup: update_cleanup:
sqlite3AuthContextPop(&sContext); sqlite3AuthContextPop(&sContext);
sqliteFree(apIdx); sqlite3DbFree(db, aRegIdx);
sqliteFree(aXRef); sqlite3DbFree(db, aXRef);
sqlite3SrcListDelete(pTabList); sqlite3SrcListDelete(db, pTabList);
sqlite3ExprListDelete(pChanges); sqlite3ExprListDelete(db, pChanges);
sqlite3ExprDelete(pWhere); sqlite3ExprDelete(db, pWhere);
return; return;
} }
@ -569,59 +621,65 @@ static void updateVirtualTable(
int ephemTab; /* Table holding the result of the SELECT */ int ephemTab; /* Table holding the result of the SELECT */
int i; /* Loop counter */ int i; /* Loop counter */
int addr; /* Address of top of loop */ int addr; /* Address of top of loop */
int iReg; /* First register in set passed to OP_VUpdate */
sqlite3 *db = pParse->db; /* Database connection */
const char *pVtab = (const char*)pTab->pVtab;
SelectDest dest;
/* Construct the SELECT statement that will find the new values for /* Construct the SELECT statement that will find the new values for
** all updated rows. ** all updated rows.
*/ */
pEList = sqlite3ExprListAppend(0, sqlite3CreateIdExpr("_rowid_"), 0); pEList = sqlite3ExprListAppend(pParse, 0,
sqlite3CreateIdExpr(pParse, "_rowid_"), 0);
if( pRowid ){ if( pRowid ){
pEList = sqlite3ExprListAppend(pEList, sqlite3ExprDup(pRowid), 0); pEList = sqlite3ExprListAppend(pParse, pEList,
sqlite3ExprDup(db, pRowid), 0);
} }
assert( pTab->iPKey<0 ); assert( pTab->iPKey<0 );
for(i=0; i<pTab->nCol; i++){ for(i=0; i<pTab->nCol; i++){
if( aXRef[i]>=0 ){ if( aXRef[i]>=0 ){
pExpr = sqlite3ExprDup(pChanges->a[aXRef[i]].pExpr); pExpr = sqlite3ExprDup(db, pChanges->a[aXRef[i]].pExpr);
}else{ }else{
pExpr = sqlite3CreateIdExpr(pTab->aCol[i].zName); pExpr = sqlite3CreateIdExpr(pParse, pTab->aCol[i].zName);
} }
pEList = sqlite3ExprListAppend(pEList, pExpr, 0); pEList = sqlite3ExprListAppend(pParse, pEList, pExpr, 0);
} }
pSelect = sqlite3SelectNew(pEList, pSrc, pWhere, 0, 0, 0, 0, 0, 0); pSelect = sqlite3SelectNew(pParse, pEList, pSrc, pWhere, 0, 0, 0, 0, 0, 0);
/* Create the ephemeral table into which the update results will /* Create the ephemeral table into which the update results will
** be stored. ** be stored.
*/ */
assert( v ); assert( v );
ephemTab = pParse->nTab++; ephemTab = pParse->nTab++;
sqlite3VdbeAddOp(v, OP_OpenEphemeral, ephemTab, pTab->nCol+1+(pRowid!=0)); sqlite3VdbeAddOp2(v, OP_OpenEphemeral, ephemTab, pTab->nCol+1+(pRowid!=0));
/* fill the ephemeral table /* fill the ephemeral table
*/ */
sqlite3Select(pParse, pSelect, SRT_Table, ephemTab, 0, 0, 0, 0); sqlite3SelectDestInit(&dest, SRT_Table, ephemTab);
sqlite3Select(pParse, pSelect, &dest);
/* /* Generate code to scan the ephemeral table and call VUpdate. */
** Generate code to scan the ephemeral table and call VDelete and iReg = ++pParse->nMem;
** VInsert pParse->nMem += pTab->nCol+1;
*/ sqlite3VdbeAddOp2(v, OP_Rewind, ephemTab, 0);
sqlite3VdbeAddOp(v, OP_Rewind, ephemTab, 0);
addr = sqlite3VdbeCurrentAddr(v); addr = sqlite3VdbeCurrentAddr(v);
sqlite3VdbeAddOp(v, OP_Column, ephemTab, 0); sqlite3VdbeAddOp3(v, OP_Column, ephemTab, 0, iReg);
if( pRowid ){ sqlite3VdbeAddOp3(v, OP_Column, ephemTab, (pRowid?1:0), iReg+1);
sqlite3VdbeAddOp(v, OP_Column, ephemTab, 1);
}else{
sqlite3VdbeAddOp(v, OP_Dup, 0, 0);
}
for(i=0; i<pTab->nCol; i++){ for(i=0; i<pTab->nCol; i++){
sqlite3VdbeAddOp(v, OP_Column, ephemTab, i+1+(pRowid!=0)); sqlite3VdbeAddOp3(v, OP_Column, ephemTab, i+1+(pRowid!=0), iReg+2+i);
} }
pParse->pVirtualLock = pTab; sqlite3VtabMakeWritable(pParse, pTab);
sqlite3VdbeOp3(v, OP_VUpdate, 0, pTab->nCol+2, sqlite3VdbeAddOp4(v, OP_VUpdate, 0, pTab->nCol+2, iReg, pVtab, P4_VTAB);
(const char*)pTab->pVtab, P3_VTAB); sqlite3VdbeAddOp2(v, OP_Next, ephemTab, addr);
sqlite3VdbeAddOp(v, OP_Next, ephemTab, addr);
sqlite3VdbeJumpHere(v, addr-1); sqlite3VdbeJumpHere(v, addr-1);
sqlite3VdbeAddOp(v, OP_Close, ephemTab, 0); sqlite3VdbeAddOp2(v, OP_Close, ephemTab, 0);
/* Cleanup */ /* Cleanup */
sqlite3SelectDelete(pSelect); sqlite3SelectDelete(db, pSelect);
} }
#endif /* SQLITE_OMIT_VIRTUALTABLE */ #endif /* SQLITE_OMIT_VIRTUALTABLE */
/* Make sure "isView" gets undefined in case this file becomes part of
** the amalgamation - so that subsequent files do not see isView as a
** macro. */
#undef isView

243
utf.c
View file

@ -12,7 +12,7 @@
** This file contains routines used to translate between UTF-8, ** This file contains routines used to translate between UTF-8,
** UTF-16, UTF-16BE, and UTF-16LE. ** UTF-16, UTF-16BE, and UTF-16LE.
** **
** $Id: utf.c,v 1.53 2007/08/07 17:04:59 drh Exp $ ** $Id: utf.c,v 1.70 2008/12/10 22:30:25 shane Exp $
** **
** Notes on UTF-8: ** Notes on UTF-8:
** **
@ -39,17 +39,19 @@
#include <assert.h> #include <assert.h>
#include "vdbeInt.h" #include "vdbeInt.h"
#ifndef SQLITE_AMALGAMATION
/* /*
** The following constant value is used by the SQLITE_BIGENDIAN and ** The following constant value is used by the SQLITE_BIGENDIAN and
** SQLITE_LITTLEENDIAN macros. ** SQLITE_LITTLEENDIAN macros.
*/ */
const int sqlite3one = 1; const int sqlite3one = 1;
#endif /* SQLITE_AMALGAMATION */
/* /*
** This lookup table is used to help decode the first byte of ** This lookup table is used to help decode the first byte of
** a multi-byte UTF8 character. ** a multi-byte UTF8 character.
*/ */
static const unsigned char sqlite3UtfTrans1[] = { static const unsigned char sqlite3Utf8Trans1[] = {
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
@ -63,46 +65,46 @@ static const unsigned char sqlite3UtfTrans1[] = {
#define WRITE_UTF8(zOut, c) { \ #define WRITE_UTF8(zOut, c) { \
if( c<0x00080 ){ \ if( c<0x00080 ){ \
*zOut++ = (c&0xFF); \ *zOut++ = (u8)(c&0xFF); \
} \ } \
else if( c<0x00800 ){ \ else if( c<0x00800 ){ \
*zOut++ = 0xC0 + ((c>>6)&0x1F); \ *zOut++ = 0xC0 + (u8)((c>>6)&0x1F); \
*zOut++ = 0x80 + (c & 0x3F); \ *zOut++ = 0x80 + (u8)(c & 0x3F); \
} \ } \
else if( c<0x10000 ){ \ else if( c<0x10000 ){ \
*zOut++ = 0xE0 + ((c>>12)&0x0F); \ *zOut++ = 0xE0 + (u8)((c>>12)&0x0F); \
*zOut++ = 0x80 + ((c>>6) & 0x3F); \ *zOut++ = 0x80 + (u8)((c>>6) & 0x3F); \
*zOut++ = 0x80 + (c & 0x3F); \ *zOut++ = 0x80 + (u8)(c & 0x3F); \
}else{ \ }else{ \
*zOut++ = 0xF0 + ((c>>18) & 0x07); \ *zOut++ = 0xF0 + (u8)((c>>18) & 0x07); \
*zOut++ = 0x80 + ((c>>12) & 0x3F); \ *zOut++ = 0x80 + (u8)((c>>12) & 0x3F); \
*zOut++ = 0x80 + ((c>>6) & 0x3F); \ *zOut++ = 0x80 + (u8)((c>>6) & 0x3F); \
*zOut++ = 0x80 + (c & 0x3F); \ *zOut++ = 0x80 + (u8)(c & 0x3F); \
} \ } \
} }
#define WRITE_UTF16LE(zOut, c) { \ #define WRITE_UTF16LE(zOut, c) { \
if( c<=0xFFFF ){ \ if( c<=0xFFFF ){ \
*zOut++ = (c&0x00FF); \ *zOut++ = (u8)(c&0x00FF); \
*zOut++ = ((c>>8)&0x00FF); \ *zOut++ = (u8)((c>>8)&0x00FF); \
}else{ \ }else{ \
*zOut++ = (((c>>10)&0x003F) + (((c-0x10000)>>10)&0x00C0)); \ *zOut++ = (u8)(((c>>10)&0x003F) + (((c-0x10000)>>10)&0x00C0)); \
*zOut++ = (0x00D8 + (((c-0x10000)>>18)&0x03)); \ *zOut++ = (u8)(0x00D8 + (((c-0x10000)>>18)&0x03)); \
*zOut++ = (c&0x00FF); \ *zOut++ = (u8)(c&0x00FF); \
*zOut++ = (0x00DC + ((c>>8)&0x03)); \ *zOut++ = (u8)(0x00DC + ((c>>8)&0x03)); \
} \ } \
} }
#define WRITE_UTF16BE(zOut, c) { \ #define WRITE_UTF16BE(zOut, c) { \
if( c<=0xFFFF ){ \ if( c<=0xFFFF ){ \
*zOut++ = ((c>>8)&0x00FF); \ *zOut++ = (u8)((c>>8)&0x00FF); \
*zOut++ = (c&0x00FF); \ *zOut++ = (u8)(c&0x00FF); \
}else{ \ }else{ \
*zOut++ = (0x00D8 + (((c-0x10000)>>18)&0x03)); \ *zOut++ = (u8)(0x00D8 + (((c-0x10000)>>18)&0x03)); \
*zOut++ = (((c>>10)&0x003F) + (((c-0x10000)>>10)&0x00C0)); \ *zOut++ = (u8)(((c>>10)&0x003F) + (((c-0x10000)>>10)&0x00C0)); \
*zOut++ = (0x00DC + ((c>>8)&0x03)); \ *zOut++ = (u8)(0x00DC + ((c>>8)&0x03)); \
*zOut++ = (c&0x00FF); \ *zOut++ = (u8)(c&0x00FF); \
} \ } \
} }
#define READ_UTF16LE(zIn, c){ \ #define READ_UTF16LE(zIn, c){ \
@ -154,27 +156,31 @@ static const unsigned char sqlite3UtfTrans1[] = {
** for unicode values 0x80 and greater. It do not change over-length ** for unicode values 0x80 and greater. It do not change over-length
** encodings to 0xfffd as some systems recommend. ** encodings to 0xfffd as some systems recommend.
*/ */
#define READ_UTF8(zIn, zTerm, c) \
c = *(zIn++); \
if( c>=0xc0 ){ \
c = sqlite3Utf8Trans1[c-0xc0]; \
while( zIn!=zTerm && (*zIn & 0xc0)==0x80 ){ \
c = (c<<6) + (0x3f & *(zIn++)); \
} \
if( c<0x80 \
|| (c&0xFFFFF800)==0xD800 \
|| (c&0xFFFFFFFE)==0xFFFE ){ c = 0xFFFD; } \
}
int sqlite3Utf8Read( int sqlite3Utf8Read(
const unsigned char *z, /* First byte of UTF-8 character */ const unsigned char *z, /* First byte of UTF-8 character */
const unsigned char *zTerm, /* Pretend this byte is 0x00 */ const unsigned char *zTerm, /* Pretend this byte is 0x00 */
const unsigned char **pzNext /* Write first byte past UTF-8 char here */ const unsigned char **pzNext /* Write first byte past UTF-8 char here */
){ ){
int c = *(z++); int c;
if( c>=0xc0 ){ READ_UTF8(z, zTerm, c);
c = sqlite3UtfTrans1[c-0xc0];
while( z!=zTerm && (*z & 0xc0)==0x80 ){
c = (c<<6) + (0x3f & *(z++));
}
if( c<0x80
|| (c&0xFFFFF800)==0xD800
|| (c&0xFFFFFFFE)==0xFFFE ){ c = 0xFFFD; }
}
*pzNext = z; *pzNext = z;
return c; return c;
} }
/* /*
** If the TRANSLATE_TRACE macro is defined, the value of each Mem is ** If the TRANSLATE_TRACE macro is defined, the value of each Mem is
** printed on stderr on the way into and out of sqlite3VdbeMemTranslate(). ** printed on stderr on the way into and out of sqlite3VdbeMemTranslate().
@ -188,7 +194,6 @@ int sqlite3Utf8Read(
** encoding, or if *pMem does not contain a string value. ** encoding, or if *pMem does not contain a string value.
*/ */
int sqlite3VdbeMemTranslate(Mem *pMem, u8 desiredEnc){ int sqlite3VdbeMemTranslate(Mem *pMem, u8 desiredEnc){
unsigned char zShort[NBFS]; /* Temporary short output buffer */
int len; /* Maximum length of output string in bytes */ int len; /* Maximum length of output string in bytes */
unsigned char *zOut; /* Output buffer */ unsigned char *zOut; /* Output buffer */
unsigned char *zIn; /* Input iterator */ unsigned char *zIn; /* Input iterator */
@ -196,6 +201,7 @@ int sqlite3VdbeMemTranslate(Mem *pMem, u8 desiredEnc){
unsigned char *z; /* Output iterator */ unsigned char *z; /* Output iterator */
unsigned int c; unsigned int c;
assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
assert( pMem->flags&MEM_Str ); assert( pMem->flags&MEM_Str );
assert( pMem->enc!=desiredEnc ); assert( pMem->enc!=desiredEnc );
assert( pMem->enc!=0 ); assert( pMem->enc!=0 );
@ -222,7 +228,7 @@ int sqlite3VdbeMemTranslate(Mem *pMem, u8 desiredEnc){
return SQLITE_NOMEM; return SQLITE_NOMEM;
} }
zIn = (u8*)pMem->z; zIn = (u8*)pMem->z;
zTerm = &zIn[pMem->n]; zTerm = &zIn[pMem->n&~1];
while( zIn<zTerm ){ while( zIn<zTerm ){
temp = *zIn; temp = *zIn;
*zIn = *(zIn+1); *zIn = *(zIn+1);
@ -240,6 +246,7 @@ int sqlite3VdbeMemTranslate(Mem *pMem, u8 desiredEnc){
** A single byte is required for the output string ** A single byte is required for the output string
** nul-terminator. ** nul-terminator.
*/ */
pMem->n &= ~1;
len = pMem->n * 2 + 1; len = pMem->n * 2 + 1;
}else{ }else{
/* When converting from UTF-8 to UTF-16 the maximum growth is caused /* When converting from UTF-8 to UTF-16 the maximum growth is caused
@ -253,17 +260,14 @@ int sqlite3VdbeMemTranslate(Mem *pMem, u8 desiredEnc){
/* Set zIn to point at the start of the input buffer and zTerm to point 1 /* Set zIn to point at the start of the input buffer and zTerm to point 1
** byte past the end. ** byte past the end.
** **
** Variable zOut is set to point at the output buffer. This may be space ** Variable zOut is set to point at the output buffer, space obtained
** obtained from malloc(), or Mem.zShort, if it large enough and not in ** from sqlite3_malloc().
** use, or the zShort array on the stack (see above).
*/ */
zIn = (u8*)pMem->z; zIn = (u8*)pMem->z;
zTerm = &zIn[pMem->n]; zTerm = &zIn[pMem->n];
if( len>NBFS ){ zOut = sqlite3DbMallocRaw(pMem->db, len);
zOut = sqliteMallocRaw(len); if( !zOut ){
if( !zOut ) return SQLITE_NOMEM; return SQLITE_NOMEM;
}else{
zOut = zShort;
} }
z = zOut; z = zOut;
@ -271,18 +275,20 @@ int sqlite3VdbeMemTranslate(Mem *pMem, u8 desiredEnc){
if( desiredEnc==SQLITE_UTF16LE ){ if( desiredEnc==SQLITE_UTF16LE ){
/* UTF-8 -> UTF-16 Little-endian */ /* UTF-8 -> UTF-16 Little-endian */
while( zIn<zTerm ){ while( zIn<zTerm ){
c = sqlite3Utf8Read(zIn, zTerm, (const u8**)&zIn); /* c = sqlite3Utf8Read(zIn, zTerm, (const u8**)&zIn); */
READ_UTF8(zIn, zTerm, c);
WRITE_UTF16LE(z, c); WRITE_UTF16LE(z, c);
} }
}else{ }else{
assert( desiredEnc==SQLITE_UTF16BE ); assert( desiredEnc==SQLITE_UTF16BE );
/* UTF-8 -> UTF-16 Big-endian */ /* UTF-8 -> UTF-16 Big-endian */
while( zIn<zTerm ){ while( zIn<zTerm ){
c = sqlite3Utf8Read(zIn, zTerm, (const u8**)&zIn); /* c = sqlite3Utf8Read(zIn, zTerm, (const u8**)&zIn); */
READ_UTF8(zIn, zTerm, c);
WRITE_UTF16BE(z, c); WRITE_UTF16BE(z, c);
} }
} }
pMem->n = z - zOut; pMem->n = (int)(z - zOut);
*z++ = 0; *z++ = 0;
}else{ }else{
assert( desiredEnc==SQLITE_UTF8 ); assert( desiredEnc==SQLITE_UTF8 );
@ -293,28 +299,23 @@ int sqlite3VdbeMemTranslate(Mem *pMem, u8 desiredEnc){
WRITE_UTF8(z, c); WRITE_UTF8(z, c);
} }
}else{ }else{
/* UTF-16 Little-endian -> UTF-8 */ /* UTF-16 Big-endian -> UTF-8 */
while( zIn<zTerm ){ while( zIn<zTerm ){
READ_UTF16BE(zIn, c); READ_UTF16BE(zIn, c);
WRITE_UTF8(z, c); WRITE_UTF8(z, c);
} }
} }
pMem->n = z - zOut; pMem->n = (int)(z - zOut);
} }
*z = 0; *z = 0;
assert( (pMem->n+(desiredEnc==SQLITE_UTF8?1:2))<=len ); assert( (pMem->n+(desiredEnc==SQLITE_UTF8?1:2))<=len );
sqlite3VdbeMemRelease(pMem); sqlite3VdbeMemRelease(pMem);
pMem->flags &= ~(MEM_Static|MEM_Dyn|MEM_Ephem|MEM_Short); pMem->flags &= ~(MEM_Static|MEM_Dyn|MEM_Ephem);
pMem->enc = desiredEnc; pMem->enc = desiredEnc;
if( zOut==zShort ){ pMem->flags |= (MEM_Term|MEM_Dyn);
memcpy(pMem->zShort, zOut, len);
zOut = (u8*)pMem->zShort;
pMem->flags |= (MEM_Term|MEM_Short);
}else{
pMem->flags |= (MEM_Term|MEM_Dyn);
}
pMem->z = (char*)zOut; pMem->z = (char*)zOut;
pMem->zMalloc = pMem->z;
translate_out: translate_out:
#if defined(TRANSLATE_TRACE) && defined(SQLITE_DEBUG) #if defined(TRANSLATE_TRACE) && defined(SQLITE_DEBUG)
@ -352,23 +353,14 @@ int sqlite3VdbeMemHandleBom(Mem *pMem){
} }
if( bom ){ if( bom ){
/* This function is called as soon as a string is stored in a Mem*, rc = sqlite3VdbeMemMakeWriteable(pMem);
** from within sqlite3VdbeMemSetStr(). At that point it is not possible if( rc==SQLITE_OK ){
** for the string to be stored in Mem.zShort, or for it to be stored pMem->n -= 2;
** in dynamic memory with no destructor. memmove(pMem->z, &pMem->z[2], pMem->n);
*/ pMem->z[pMem->n] = '\0';
assert( !(pMem->flags&MEM_Short) ); pMem->z[pMem->n+1] = '\0';
assert( !(pMem->flags&MEM_Dyn) || pMem->xDel ); pMem->flags |= MEM_Term;
if( pMem->flags & MEM_Dyn ){ pMem->enc = bom;
void (*xDel)(void*) = pMem->xDel;
char *z = pMem->z;
pMem->z = 0;
pMem->xDel = 0;
rc = sqlite3VdbeMemSetStr(pMem, &z[2], pMem->n-2, bom, SQLITE_TRANSIENT);
xDel(z);
}else{
rc = sqlite3VdbeMemSetStr(pMem, &pMem->z[2], pMem->n-2, bom,
SQLITE_TRANSIENT);
} }
} }
return rc; return rc;
@ -399,22 +391,57 @@ int sqlite3Utf8CharLen(const char *zIn, int nByte){
return r; return r;
} }
/* This test function is not currently used by the automated test-suite.
** Hence it is only available in debug builds.
*/
#if defined(SQLITE_TEST) && defined(SQLITE_DEBUG)
/*
** Translate UTF-8 to UTF-8.
**
** This has the effect of making sure that the string is well-formed
** UTF-8. Miscoded characters are removed.
**
** The translation is done in-place (since it is impossible for the
** correct UTF-8 encoding to be longer than a malformed encoding).
*/
int sqlite3Utf8To8(unsigned char *zIn){
unsigned char *zOut = zIn;
unsigned char *zStart = zIn;
unsigned char *zTerm = &zIn[sqlite3Strlen30((char *)zIn)];
u32 c;
while( zIn[0] ){
c = sqlite3Utf8Read(zIn, zTerm, (const u8**)&zIn);
if( c!=0xfffd ){
WRITE_UTF8(zOut, c);
}
}
*zOut = 0;
return zOut - zStart;
}
#endif
#ifndef SQLITE_OMIT_UTF16 #ifndef SQLITE_OMIT_UTF16
/* /*
** Convert a UTF-16 string in the native encoding into a UTF-8 string. ** 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 ** Memory to hold the UTF-8 string is obtained from sqlite3_malloc and must
** freed by the calling function. ** be freed by the calling function.
** **
** NULL is returned if there is an allocation error. ** NULL is returned if there is an allocation error.
*/ */
char *sqlite3Utf16to8(const void *z, int nByte){ char *sqlite3Utf16to8(sqlite3 *db, const void *z, int nByte){
Mem m; Mem m;
memset(&m, 0, sizeof(m)); memset(&m, 0, sizeof(m));
m.db = db;
sqlite3VdbeMemSetStr(&m, z, nByte, SQLITE_UTF16NATIVE, SQLITE_STATIC); sqlite3VdbeMemSetStr(&m, z, nByte, SQLITE_UTF16NATIVE, SQLITE_STATIC);
sqlite3VdbeChangeEncoding(&m, SQLITE_UTF8); sqlite3VdbeChangeEncoding(&m, SQLITE_UTF8);
assert( (m.flags & MEM_Term)!=0 || sqlite3MallocFailed() ); if( db->mallocFailed ){
assert( (m.flags & MEM_Str)!=0 || sqlite3MallocFailed() ); sqlite3VdbeMemRelease(&m);
return (m.flags & MEM_Dyn)!=0 ? m.z : sqliteStrDup(m.z); m.z = 0;
}
assert( (m.flags & MEM_Term)!=0 || db->mallocFailed );
assert( (m.flags & MEM_Str)!=0 || db->mallocFailed );
return (m.flags & MEM_Dyn)!=0 ? m.z : sqlite3DbStrDup(db, m.z);
} }
/* /*
@ -448,43 +475,16 @@ int sqlite3Utf16ByteLen(const void *zIn, int nChar){
n++; n++;
} }
} }
return (z-(char const *)zIn)-((c==0)?2:0); return (int)(z-(char const *)zIn)-((c==0)?2:0);
} }
#if defined(SQLITE_TEST)
/*
** Translate UTF-8 to UTF-8.
**
** This has the effect of making sure that the string is well-formed
** UTF-8. Miscoded characters are removed.
**
** The translation is done in-place (since it is impossible for the
** correct UTF-8 encoding to be longer than a malformed encoding).
*/
int sqlite3Utf8To8(unsigned char *zIn){
unsigned char *zOut = zIn;
unsigned char *zStart = zIn;
unsigned char *zTerm;
u32 c;
while( zIn[0] ){
c = sqlite3Utf8Read(zIn, zTerm, (const u8**)&zIn);
if( c!=0xfffd ){
WRITE_UTF8(zOut, c);
}
}
*zOut = 0;
return zOut - zStart;
}
#endif
#if defined(SQLITE_TEST) #if defined(SQLITE_TEST)
/* /*
** This routine is called from the TCL test function "translate_selftest". ** This routine is called from the TCL test function "translate_selftest".
** It checks that the primitives for serializing and deserializing ** It checks that the primitives for serializing and deserializing
** characters in each encoding are inverses of each other. ** characters in each encoding are inverses of each other.
*/ */
void sqlite3UtfSelfTest(){ void sqlite3UtfSelfTest(void){
unsigned int i, t; unsigned int i, t;
unsigned char zBuf[20]; unsigned char zBuf[20];
unsigned char *z; unsigned char *z;
@ -495,7 +495,8 @@ void sqlite3UtfSelfTest(){
for(i=0; i<0x00110000; i++){ for(i=0; i<0x00110000; i++){
z = zBuf; z = zBuf;
WRITE_UTF8(z, i); WRITE_UTF8(z, i);
n = z-zBuf; n = (int)(z-zBuf);
assert( n>0 && n<=4 );
z[0] = 0; z[0] = 0;
zTerm = z; zTerm = z;
z = zBuf; z = zBuf;
@ -510,7 +511,8 @@ void sqlite3UtfSelfTest(){
if( i>=0xD800 && i<0xE000 ) continue; if( i>=0xD800 && i<0xE000 ) continue;
z = zBuf; z = zBuf;
WRITE_UTF16LE(z, i); WRITE_UTF16LE(z, i);
n = z-zBuf; n = (int)(z-zBuf);
assert( n>0 && n<=4 );
z[0] = 0; z[0] = 0;
z = zBuf; z = zBuf;
READ_UTF16LE(z, c); READ_UTF16LE(z, c);
@ -521,7 +523,8 @@ void sqlite3UtfSelfTest(){
if( i>=0xD800 && i<0xE000 ) continue; if( i>=0xD800 && i<0xE000 ) continue;
z = zBuf; z = zBuf;
WRITE_UTF16BE(z, i); WRITE_UTF16BE(z, i);
n = z-zBuf; n = (int)(z-zBuf);
assert( n>0 && n<=4 );
z[0] = 0; z[0] = 0;
z = zBuf; z = zBuf;
READ_UTF16BE(z, c); READ_UTF16BE(z, c);

601
util.c
View file

@ -14,14 +14,101 @@
** This file contains functions for allocating memory, comparing ** This file contains functions for allocating memory, comparing
** strings, and stuff like that. ** strings, and stuff like that.
** **
** $Id: util.c,v 1.207 2007/06/26 00:37:28 drh Exp $ ** $Id: util.c,v 1.246 2009/01/10 16:15:22 drh Exp $
*/ */
#include "sqliteInt.h" #include "sqliteInt.h"
#include "os.h"
#include <stdarg.h> #include <stdarg.h>
#include <ctype.h> #include <ctype.h>
/*
** Routine needed to support the testcase() macro.
*/
#ifdef SQLITE_COVERAGE_TEST
void sqlite3Coverage(int x){
static int dummy = 0;
dummy += x;
}
#endif
/*
** Routine needed to support the ALWAYS() and NEVER() macros.
**
** The argument to ALWAYS() should always be true and the argument
** to NEVER() should always be false. If either is not the case
** then this routine is called in order to throw an error.
**
** This routine only exists if assert() is operational. It always
** throws an assert on its first invocation. The variable has a long
** name to help the assert() message be more readable. The variable
** is used to prevent a too-clever optimizer from optimizing out the
** entire call.
*/
#ifndef NDEBUG
int sqlite3Assert(void){
static volatile int ALWAYS_was_false_or_NEVER_was_true = 0;
assert( ALWAYS_was_false_or_NEVER_was_true ); /* Always fails */
return ALWAYS_was_false_or_NEVER_was_true++; /* Not Reached */
}
#endif
/*
** Return true if the floating point value is Not a Number (NaN).
*/
int sqlite3IsNaN(double x){
/* This NaN test sometimes fails if compiled on GCC with -ffast-math.
** On the other hand, the use of -ffast-math comes with the following
** warning:
**
** This option [-ffast-math] should never be turned on by any
** -O option since it can result in incorrect output for programs
** which depend on an exact implementation of IEEE or ISO
** rules/specifications for math functions.
**
** Under MSVC, this NaN test may fail if compiled with a floating-
** point precision mode other than /fp:precise. From the MSDN
** documentation:
**
** The compiler [with /fp:precise] will properly handle comparisons
** involving NaN. For example, x != x evaluates to true if x is NaN
** ...
*/
#ifdef __FAST_MATH__
# error SQLite will not work correctly with the -ffast-math option of GCC.
#endif
volatile double y = x;
volatile double z = y;
return y!=z;
}
/*
** Compute a string length that is limited to what can be stored in
** lower 30 bits of a 32-bit signed integer.
*/
int sqlite3Strlen30(const char *z){
const char *z2 = z;
while( *z2 ){ z2++; }
return 0x3fffffff & (int)(z2 - z);
}
/*
** Return the length of a string, except do not allow the string length
** to exceed the SQLITE_LIMIT_LENGTH setting.
*/
int sqlite3Strlen(sqlite3 *db, const char *z){
const char *z2 = z;
int len;
int x;
while( *z2 ){ z2++; }
x = (int)(z2 - z);
len = 0x7fffffff & x;
if( len!=x || len > db->aLimit[SQLITE_LIMIT_LENGTH] ){
return db->aLimit[SQLITE_LIMIT_LENGTH];
}else{
return len;
}
}
/* /*
** Set the most recent error code and error string for the sqlite ** Set the most recent error code and error string for the sqlite
** handle "db". The error code is set to "err_code". ** handle "db". The error code is set to "err_code".
@ -44,15 +131,15 @@
** to NULL. ** to NULL.
*/ */
void sqlite3Error(sqlite3 *db, int err_code, const char *zFormat, ...){ void sqlite3Error(sqlite3 *db, int err_code, const char *zFormat, ...){
if( db && (db->pErr || (db->pErr = sqlite3ValueNew())!=0) ){ if( db && (db->pErr || (db->pErr = sqlite3ValueNew(db))!=0) ){
db->errCode = err_code; db->errCode = err_code;
if( zFormat ){ if( zFormat ){
char *z; char *z;
va_list ap; va_list ap;
va_start(ap, zFormat); va_start(ap, zFormat);
z = sqlite3VMPrintf(zFormat, ap); z = sqlite3VMPrintf(db, zFormat, ap);
va_end(ap); va_end(ap);
sqlite3ValueSetStr(db->pErr, -1, z, SQLITE_UTF8, sqlite3FreeX); sqlite3ValueSetStr(db->pErr, -1, z, SQLITE_UTF8, SQLITE_DYNAMIC);
}else{ }else{
sqlite3ValueSetStr(db->pErr, 0, 0, SQLITE_UTF8, SQLITE_STATIC); sqlite3ValueSetStr(db->pErr, 0, 0, SQLITE_UTF8, SQLITE_STATIC);
} }
@ -78,10 +165,11 @@ void sqlite3Error(sqlite3 *db, int err_code, const char *zFormat, ...){
*/ */
void sqlite3ErrorMsg(Parse *pParse, const char *zFormat, ...){ void sqlite3ErrorMsg(Parse *pParse, const char *zFormat, ...){
va_list ap; va_list ap;
sqlite3 *db = pParse->db;
pParse->nErr++; pParse->nErr++;
sqliteFree(pParse->zErrMsg); sqlite3DbFree(db, pParse->zErrMsg);
va_start(ap, zFormat); va_start(ap, zFormat);
pParse->zErrMsg = sqlite3VMPrintf(zFormat, ap); pParse->zErrMsg = sqlite3VMPrintf(db, zFormat, ap);
va_end(ap); va_end(ap);
if( pParse->rc==SQLITE_OK ){ if( pParse->rc==SQLITE_OK ){
pParse->rc = SQLITE_ERROR; pParse->rc = SQLITE_ERROR;
@ -92,7 +180,7 @@ void sqlite3ErrorMsg(Parse *pParse, const char *zFormat, ...){
** Clear the error message in pParse, if any ** Clear the error message in pParse, if any
*/ */
void sqlite3ErrorClear(Parse *pParse){ void sqlite3ErrorClear(Parse *pParse){
sqliteFree(pParse->zErrMsg); sqlite3DbFree(pParse->db, pParse->zErrMsg);
pParse->zErrMsg = 0; pParse->zErrMsg = 0;
pParse->nErr = 0; pParse->nErr = 0;
} }
@ -108,7 +196,7 @@ void sqlite3ErrorClear(Parse *pParse){
** "a-b-c". ** "a-b-c".
*/ */
void sqlite3Dequote(char *z){ void sqlite3Dequote(char *z){
int quote; char quote;
int i, j; int i, j;
if( z==0 ) return; if( z==0 ) return;
quote = z[0]; quote = z[0];
@ -134,46 +222,7 @@ void sqlite3Dequote(char *z){
} }
} }
/* An array to map all upper-case characters into their corresponding /* Convenient short-hand */
** lower-case character.
*/
const unsigned char sqlite3UpperToLower[] = {
#ifdef SQLITE_ASCII
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53,
54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 97, 98, 99,100,101,102,103,
104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,
122, 91, 92, 93, 94, 95, 96, 97, 98, 99,100,101,102,103,104,105,106,107,
108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,
126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,
144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,
162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,
180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,
198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,
216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,
234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,
252,253,254,255
#endif
#ifdef SQLITE_EBCDIC
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, /* 0x */
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, /* 1x */
32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, /* 2x */
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, /* 3x */
64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, /* 4x */
80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, /* 5x */
96, 97, 66, 67, 68, 69, 70, 71, 72, 73,106,107,108,109,110,111, /* 6x */
112, 81, 82, 83, 84, 85, 86, 87, 88, 89,122,123,124,125,126,127, /* 7x */
128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143, /* 8x */
144,145,146,147,148,149,150,151,152,153,154,155,156,157,156,159, /* 9x */
160,161,162,163,164,165,166,167,168,169,170,171,140,141,142,175, /* Ax */
176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191, /* Bx */
192,129,130,131,132,133,134,135,136,137,202,203,204,205,206,207, /* Cx */
208,145,146,147,148,149,150,151,152,153,218,219,220,221,222,223, /* Dx */
224,225,162,163,164,165,166,167,168,169,232,203,204,205,206,207, /* Ex */
239,240,241,242,243,244,245,246,247,248,249,219,220,221,222,255, /* Fx */
#endif
};
#define UpperToLower sqlite3UpperToLower #define UpperToLower sqlite3UpperToLower
/* /*
@ -246,6 +295,7 @@ int sqlite3AtoF(const char *z, double *pResult){
int sign = 1; int sign = 1;
const char *zBegin = z; const char *zBegin = z;
LONGDOUBLE_TYPE v1 = 0.0; LONGDOUBLE_TYPE v1 = 0.0;
int nSignificant = 0;
while( isspace(*(u8*)z) ) z++; while( isspace(*(u8*)z) ) z++;
if( *z=='-' ){ if( *z=='-' ){
sign = -1; sign = -1;
@ -253,16 +303,29 @@ int sqlite3AtoF(const char *z, double *pResult){
}else if( *z=='+' ){ }else if( *z=='+' ){
z++; z++;
} }
while( z[0]=='0' ){
z++;
}
while( isdigit(*(u8*)z) ){ while( isdigit(*(u8*)z) ){
v1 = v1*10.0 + (*z - '0'); v1 = v1*10.0 + (*z - '0');
z++; z++;
nSignificant++;
} }
if( *z=='.' ){ if( *z=='.' ){
LONGDOUBLE_TYPE divisor = 1.0; LONGDOUBLE_TYPE divisor = 1.0;
z++; z++;
if( nSignificant==0 ){
while( z[0]=='0' ){
divisor *= 10.0;
z++;
}
}
while( isdigit(*(u8*)z) ){ while( isdigit(*(u8*)z) ){
v1 = v1*10.0 + (*z - '0'); if( nSignificant<18 ){
divisor *= 10.0; v1 = v1*10.0 + (*z - '0');
divisor *= 10.0;
nSignificant++;
}
z++; z++;
} }
v1 /= divisor; v1 /= divisor;
@ -292,8 +355,8 @@ int sqlite3AtoF(const char *z, double *pResult){
v1 *= scale; v1 *= scale;
} }
} }
*pResult = sign<0 ? -v1 : v1; *pResult = (double)(sign<0 ? -v1 : v1);
return z - zBegin; return (int)(z - zBegin);
#else #else
return sqlite3Atoi64(z, pResult); return sqlite3Atoi64(z, pResult);
#endif /* SQLITE_OMIT_FLOATING_POINT */ #endif /* SQLITE_OMIT_FLOATING_POINT */
@ -336,6 +399,7 @@ int sqlite3Atoi64(const char *zNum, i64 *pNum){
i64 v = 0; i64 v = 0;
int neg; int neg;
int i, c; int i, c;
const char *zStart;
while( isspace(*(u8*)zNum) ) zNum++; while( isspace(*(u8*)zNum) ) zNum++;
if( *zNum=='-' ){ if( *zNum=='-' ){
neg = 1; neg = 1;
@ -346,12 +410,13 @@ int sqlite3Atoi64(const char *zNum, i64 *pNum){
}else{ }else{
neg = 0; neg = 0;
} }
zStart = zNum;
while( zNum[0]=='0' ){ zNum++; } /* Skip over leading zeros. Ticket #2454 */ while( zNum[0]=='0' ){ zNum++; } /* Skip over leading zeros. Ticket #2454 */
for(i=0; (c=zNum[i])>='0' && c<='9'; i++){ for(i=0; (c=zNum[i])>='0' && c<='9'; i++){
v = v*10 + c - '0'; v = v*10 + c - '0';
} }
*pNum = neg ? -v : v; *pNum = neg ? -v : v;
if( c!=0 || i==0 || i>19 ){ if( c!=0 || (i==0 && zStart==zNum) || i>19 ){
/* zNum is empty or contains non-numeric text or is longer /* zNum is empty or contains non-numeric text or is longer
** than 19 digits (thus guaranting that it is too large) */ ** than 19 digits (thus guaranting that it is too large) */
return 0; return 0;
@ -377,7 +442,7 @@ int sqlite3Atoi64(const char *zNum, i64 *pNum){
** 9223373036854775808 will not fit in 64 bits. So it seems safer to return ** 9223373036854775808 will not fit in 64 bits. So it seems safer to return
** false. ** false.
*/ */
int sqlite3FitsIn64Bits(const char *zNum){ int sqlite3FitsIn64Bits(const char *zNum, int negFlag){
int i, c; int i, c;
int neg = 0; int neg = 0;
if( *zNum=='-' ){ if( *zNum=='-' ){
@ -386,6 +451,7 @@ int sqlite3FitsIn64Bits(const char *zNum){
}else if( *zNum=='+' ){ }else if( *zNum=='+' ){
zNum++; zNum++;
} }
if( negFlag ) neg = 1-neg;
while( *zNum=='0' ){ while( *zNum=='0' ){
zNum++; /* Skip leading zeros. Ticket #2454 */ zNum++; /* Skip leading zeros. Ticket #2454 */
} }
@ -421,10 +487,16 @@ int sqlite3GetInt32(const char *zNum, int *pValue){
zNum++; zNum++;
} }
while( zNum[0]=='0' ) zNum++; while( zNum[0]=='0' ) zNum++;
for(i=0; i<10 && (c = zNum[i] - '0')>=0 && c<=9; i++){ for(i=0; i<11 && (c = zNum[i] - '0')>=0 && c<=9; i++){
v = v*10 + c; v = v*10 + c;
} }
if( i>9 ){
/* The longest decimal representation of a 32 bit integer is 10 digits:
**
** 1234567890
** 2^31 -> 2147483648
*/
if( i>10 ){
return 0; return 0;
} }
if( v-neg>2147483647 ){ if( v-neg>2147483647 ){
@ -437,25 +509,6 @@ int sqlite3GetInt32(const char *zNum, int *pValue){
return 1; return 1;
} }
/*
** Check to make sure we have a valid db pointer. This test is not
** foolproof but it does provide some measure of protection against
** misuse of the interface such as passing in db pointers that are
** NULL or which have been previously closed. If this routine returns
** TRUE it means that the db pointer is invalid and should not be
** dereferenced for any reason. The calling function should invoke
** SQLITE_MISUSE immediately.
*/
int sqlite3SafetyCheck(sqlite3 *db){
int magic;
if( db==0 ) return 1;
magic = db->magic;
if( magic!=SQLITE_MAGIC_CLOSED &&
magic!=SQLITE_MAGIC_OPEN &&
magic!=SQLITE_MAGIC_BUSY ) return 1;
return 0;
}
/* /*
** The variable-length integer encoding is as follows: ** The variable-length integer encoding is as follows:
** **
@ -489,17 +542,17 @@ int sqlite3PutVarint(unsigned char *p, u64 v){
int i, j, n; int i, j, n;
u8 buf[10]; u8 buf[10];
if( v & (((u64)0xff000000)<<32) ){ if( v & (((u64)0xff000000)<<32) ){
p[8] = v; p[8] = (u8)v;
v >>= 8; v >>= 8;
for(i=7; i>=0; i--){ for(i=7; i>=0; i--){
p[i] = (v & 0x7f) | 0x80; p[i] = (u8)((v & 0x7f) | 0x80);
v >>= 7; v >>= 7;
} }
return 9; return 9;
} }
n = 0; n = 0;
do{ do{
buf[n++] = (v & 0x7f) | 0x80; buf[n++] = (u8)((v & 0x7f) | 0x80);
v >>= 7; v >>= 7;
}while( v!=0 ); }while( v!=0 );
buf[0] &= 0x7f; buf[0] &= 0x7f;
@ -510,72 +563,272 @@ int sqlite3PutVarint(unsigned char *p, u64 v){
return n; return n;
} }
/*
** This routine is a faster version of sqlite3PutVarint() that only
** works for 32-bit positive integers and which is optimized for
** the common case of small integers. A MACRO version, putVarint32,
** is provided which inlines the single-byte case. All code should use
** the MACRO version as this function assumes the single-byte case has
** already been handled.
*/
int sqlite3PutVarint32(unsigned char *p, u32 v){
#ifndef putVarint32
if( (v & ~0x7f)==0 ){
p[0] = v;
return 1;
}
#endif
if( (v & ~0x3fff)==0 ){
p[0] = (u8)((v>>7) | 0x80);
p[1] = (u8)(v & 0x7f);
return 2;
}
return sqlite3PutVarint(p, v);
}
/* /*
** Read a 64-bit variable-length integer from memory starting at p[0]. ** Read a 64-bit variable-length integer from memory starting at p[0].
** Return the number of bytes read. The value is stored in *v. ** Return the number of bytes read. The value is stored in *v.
*/ */
int sqlite3GetVarint(const unsigned char *p, u64 *v){ u8 sqlite3GetVarint(const unsigned char *p, u64 *v){
u32 x; u32 a,b,s;
u64 x64;
int n; a = *p;
unsigned char c; /* a: p0 (unmasked) */
if( ((c = p[0]) & 0x80)==0 ){ if (!(a&0x80))
*v = c; {
*v = a;
return 1; return 1;
} }
x = c & 0x7f;
if( ((c = p[1]) & 0x80)==0 ){ p++;
*v = (x<<7) | c; b = *p;
/* b: p1 (unmasked) */
if (!(b&0x80))
{
a &= 0x7f;
a = a<<7;
a |= b;
*v = a;
return 2; return 2;
} }
x = (x<<7) | (c&0x7f);
if( ((c = p[2]) & 0x80)==0 ){ p++;
*v = (x<<7) | c; a = a<<14;
a |= *p;
/* a: p0<<14 | p2 (unmasked) */
if (!(a&0x80))
{
a &= (0x7f<<14)|(0x7f);
b &= 0x7f;
b = b<<7;
a |= b;
*v = a;
return 3; return 3;
} }
x = (x<<7) | (c&0x7f);
if( ((c = p[3]) & 0x80)==0 ){ /* CSE1 from below */
*v = (x<<7) | c; a &= (0x7f<<14)|(0x7f);
p++;
b = b<<14;
b |= *p;
/* b: p1<<14 | p3 (unmasked) */
if (!(b&0x80))
{
b &= (0x7f<<14)|(0x7f);
/* moved CSE1 up */
/* a &= (0x7f<<14)|(0x7f); */
a = a<<7;
a |= b;
*v = a;
return 4; return 4;
} }
x64 = (x<<7) | (c&0x7f);
n = 4; /* a: p0<<14 | p2 (masked) */
do{ /* b: p1<<14 | p3 (unmasked) */
c = p[n++]; /* 1:save off p0<<21 | p1<<14 | p2<<7 | p3 (masked) */
if( n==9 ){ /* moved CSE1 up */
x64 = (x64<<8) | c; /* a &= (0x7f<<14)|(0x7f); */
break; b &= (0x7f<<14)|(0x7f);
} s = a;
x64 = (x64<<7) | (c&0x7f); /* s: p0<<14 | p2 (masked) */
}while( (c & 0x80)!=0 );
*v = x64; p++;
return n; a = a<<14;
a |= *p;
/* a: p0<<28 | p2<<14 | p4 (unmasked) */
if (!(a&0x80))
{
/* we can skip these cause they were (effectively) done above in calc'ing s */
/* a &= (0x7f<<28)|(0x7f<<14)|(0x7f); */
/* b &= (0x7f<<14)|(0x7f); */
b = b<<7;
a |= b;
s = s>>18;
*v = ((u64)s)<<32 | a;
return 5;
}
/* 2:save off p0<<21 | p1<<14 | p2<<7 | p3 (masked) */
s = s<<7;
s |= b;
/* s: p0<<21 | p1<<14 | p2<<7 | p3 (masked) */
p++;
b = b<<14;
b |= *p;
/* b: p1<<28 | p3<<14 | p5 (unmasked) */
if (!(b&0x80))
{
/* we can skip this cause it was (effectively) done above in calc'ing s */
/* b &= (0x7f<<28)|(0x7f<<14)|(0x7f); */
a &= (0x7f<<14)|(0x7f);
a = a<<7;
a |= b;
s = s>>18;
*v = ((u64)s)<<32 | a;
return 6;
}
p++;
a = a<<14;
a |= *p;
/* a: p2<<28 | p4<<14 | p6 (unmasked) */
if (!(a&0x80))
{
a &= (0x7f<<28)|(0x7f<<14)|(0x7f);
b &= (0x7f<<14)|(0x7f);
b = b<<7;
a |= b;
s = s>>11;
*v = ((u64)s)<<32 | a;
return 7;
}
/* CSE2 from below */
a &= (0x7f<<14)|(0x7f);
p++;
b = b<<14;
b |= *p;
/* b: p3<<28 | p5<<14 | p7 (unmasked) */
if (!(b&0x80))
{
b &= (0x7f<<28)|(0x7f<<14)|(0x7f);
/* moved CSE2 up */
/* a &= (0x7f<<14)|(0x7f); */
a = a<<7;
a |= b;
s = s>>4;
*v = ((u64)s)<<32 | a;
return 8;
}
p++;
a = a<<15;
a |= *p;
/* a: p4<<29 | p6<<15 | p8 (unmasked) */
/* moved CSE2 up */
/* a &= (0x7f<<29)|(0x7f<<15)|(0xff); */
b &= (0x7f<<14)|(0x7f);
b = b<<8;
a |= b;
s = s<<4;
b = p[-4];
b &= 0x7f;
b = b>>3;
s |= b;
*v = ((u64)s)<<32 | a;
return 9;
} }
/* /*
** Read a 32-bit variable-length integer from memory starting at p[0]. ** Read a 32-bit variable-length integer from memory starting at p[0].
** Return the number of bytes read. The value is stored in *v. ** Return the number of bytes read. The value is stored in *v.
** A MACRO version, getVarint32, is provided which inlines the
** single-byte case. All code should use the MACRO version as
** this function assumes the single-byte case has already been handled.
*/ */
int sqlite3GetVarint32(const unsigned char *p, u32 *v){ u8 sqlite3GetVarint32(const unsigned char *p, u32 *v){
u32 x; u32 a,b;
int n;
unsigned char c; a = *p;
if( ((signed char*)p)[0]>=0 ){ /* a: p0 (unmasked) */
*v = p[0]; #ifndef getVarint32
if (!(a&0x80))
{
*v = a;
return 1; return 1;
} }
x = p[0] & 0x7f; #endif
if( ((signed char*)p)[1]>=0 ){
*v = (x<<7) | p[1]; p++;
b = *p;
/* b: p1 (unmasked) */
if (!(b&0x80))
{
a &= 0x7f;
a = a<<7;
*v = a | b;
return 2; return 2;
} }
x = (x<<7) | (p[1] & 0x7f);
n = 2; p++;
do{ a = a<<14;
x = (x<<7) | ((c = p[n++])&0x7f); a |= *p;
}while( (c & 0x80)!=0 && n<9 ); /* a: p0<<14 | p2 (unmasked) */
*v = x; if (!(a&0x80))
return n; {
a &= (0x7f<<14)|(0x7f);
b &= 0x7f;
b = b<<7;
*v = a | b;
return 3;
}
p++;
b = b<<14;
b |= *p;
/* b: p1<<14 | p3 (unmasked) */
if (!(b&0x80))
{
b &= (0x7f<<14)|(0x7f);
a &= (0x7f<<14)|(0x7f);
a = a<<7;
*v = a | b;
return 4;
}
p++;
a = a<<14;
a |= *p;
/* a: p0<<28 | p2<<14 | p4 (unmasked) */
if (!(a&0x80))
{
a &= (0x7f<<28)|(0x7f<<14)|(0x7f);
b &= (0x7f<<28)|(0x7f<<14)|(0x7f);
b = b<<7;
*v = a | b;
return 5;
}
/* We can only reach this point when reading a corrupt database
** file. In that case we are not in any hurry. Use the (relatively
** slow) general-purpose sqlite3GetVarint() routine to extract the
** value. */
{
u64 v64;
u8 n;
p -= 4;
n = sqlite3GetVarint(p, &v64);
assert( n>5 && n<=9 );
*v = (u32)v64;
return n;
}
} }
/* /*
@ -599,30 +852,31 @@ u32 sqlite3Get4byte(const u8 *p){
return (p[0]<<24) | (p[1]<<16) | (p[2]<<8) | p[3]; return (p[0]<<24) | (p[1]<<16) | (p[2]<<8) | p[3];
} }
void sqlite3Put4byte(unsigned char *p, u32 v){ void sqlite3Put4byte(unsigned char *p, u32 v){
p[0] = v>>24; p[0] = (u8)(v>>24);
p[1] = v>>16; p[1] = (u8)(v>>16);
p[2] = v>>8; p[2] = (u8)(v>>8);
p[3] = v; p[3] = (u8)v;
} }
#if !defined(SQLITE_OMIT_BLOB_LITERAL) || defined(SQLITE_HAS_CODEC) \ #if !defined(SQLITE_OMIT_BLOB_LITERAL) || defined(SQLITE_HAS_CODEC)
|| defined(SQLITE_TEST)
/* /*
** Translate a single byte of Hex into an integer. ** Translate a single byte of Hex into an integer.
** This routinen only works if h really is a valid hexadecimal
** character: 0..9a..fA..F
*/ */
static int hexToInt(int h){ static u8 hexToInt(int h){
if( h>='0' && h<='9' ){ assert( (h>='0' && h<='9') || (h>='a' && h<='f') || (h>='A' && h<='F') );
return h - '0'; #ifdef SQLITE_ASCII
}else if( h>='a' && h<='f' ){ h += 9*(1&(h>>6));
return h - 'a' + 10; #endif
}else{ #ifdef SQLITE_EBCDIC
assert( h>='A' && h<='F' ); h += 9*(1&~(h>>4));
return h - 'A' + 10; #endif
} return (u8)(h & 0xf);
} }
#endif /* !SQLITE_OMIT_BLOB_LITERAL || SQLITE_HAS_CODEC || SQLITE_TEST */ #endif /* !SQLITE_OMIT_BLOB_LITERAL || SQLITE_HAS_CODEC */
#if !defined(SQLITE_OMIT_BLOB_LITERAL) || defined(SQLITE_HAS_CODEC) #if !defined(SQLITE_OMIT_BLOB_LITERAL) || defined(SQLITE_HAS_CODEC)
/* /*
@ -631,17 +885,17 @@ static int hexToInt(int h){
** binary value has been obtained from malloc and must be freed by ** binary value has been obtained from malloc and must be freed by
** the calling routine. ** the calling routine.
*/ */
void *sqlite3HexToBlob(const char *z){ void *sqlite3HexToBlob(sqlite3 *db, const char *z, int n){
char *zBlob; char *zBlob;
int i; int i;
int n = strlen(z);
if( n%2 ) return 0;
zBlob = (char *)sqliteMalloc(n/2); zBlob = (char *)sqlite3DbMallocRaw(db, n/2 + 1);
n--;
if( zBlob ){ if( zBlob ){
for(i=0; i<n; i+=2){ for(i=0; i<n; i+=2){
zBlob[i/2] = (hexToInt(z[i])<<4) | hexToInt(z[i+1]); zBlob[i/2] = (hexToInt(z[i])<<4) | hexToInt(z[i+1]);
} }
zBlob[i/2] = 0;
} }
return zBlob; return zBlob;
} }
@ -673,9 +927,11 @@ void *sqlite3HexToBlob(const char *z){
** call to sqlite3_close(db) and db has been deallocated. And we do ** call to sqlite3_close(db) and db has been deallocated. And we do
** not want to write into deallocated memory. ** not want to write into deallocated memory.
*/ */
#ifdef SQLITE_DEBUG
int sqlite3SafetyOn(sqlite3 *db){ int sqlite3SafetyOn(sqlite3 *db){
if( db->magic==SQLITE_MAGIC_OPEN ){ if( db->magic==SQLITE_MAGIC_OPEN ){
db->magic = SQLITE_MAGIC_BUSY; db->magic = SQLITE_MAGIC_BUSY;
assert( sqlite3_mutex_held(db->mutex) );
return 0; return 0;
}else if( db->magic==SQLITE_MAGIC_BUSY ){ }else if( db->magic==SQLITE_MAGIC_BUSY ){
db->magic = SQLITE_MAGIC_ERROR; db->magic = SQLITE_MAGIC_ERROR;
@ -683,50 +939,55 @@ int sqlite3SafetyOn(sqlite3 *db){
} }
return 1; return 1;
} }
#endif
/* /*
** Change the magic from SQLITE_MAGIC_BUSY to SQLITE_MAGIC_OPEN. ** Change the magic from SQLITE_MAGIC_BUSY to SQLITE_MAGIC_OPEN.
** Return an error (non-zero) if the magic was not SQLITE_MAGIC_BUSY ** Return an error (non-zero) if the magic was not SQLITE_MAGIC_BUSY
** when this routine is called. ** when this routine is called.
*/ */
#ifdef SQLITE_DEBUG
int sqlite3SafetyOff(sqlite3 *db){ int sqlite3SafetyOff(sqlite3 *db){
if( db->magic==SQLITE_MAGIC_BUSY ){ if( db->magic==SQLITE_MAGIC_BUSY ){
db->magic = SQLITE_MAGIC_OPEN; db->magic = SQLITE_MAGIC_OPEN;
assert( sqlite3_mutex_held(db->mutex) );
return 0; return 0;
}else { }else{
db->magic = SQLITE_MAGIC_ERROR; db->magic = SQLITE_MAGIC_ERROR;
db->u1.isInterrupted = 1; db->u1.isInterrupted = 1;
return 1; return 1;
} }
} }
#endif
/* /*
** Return a pointer to the ThreadData associated with the calling thread. ** Check to make sure we have a valid db pointer. This test is not
** foolproof but it does provide some measure of protection against
** misuse of the interface such as passing in db pointers that are
** NULL or which have been previously closed. If this routine returns
** 1 it means that the db pointer is valid and 0 if it should not be
** dereferenced for any reason. The calling function should invoke
** SQLITE_MISUSE immediately.
**
** sqlite3SafetyCheckOk() requires that the db pointer be valid for
** use. sqlite3SafetyCheckSickOrOk() allows a db pointer that failed to
** open properly and is not fit for general use but which can be
** used as an argument to sqlite3_errmsg() or sqlite3_close().
*/ */
ThreadData *sqlite3ThreadData(){ int sqlite3SafetyCheckOk(sqlite3 *db){
ThreadData *p = (ThreadData*)sqlite3OsThreadSpecificData(1); u32 magic;
if( !p ){ if( db==0 ) return 0;
sqlite3FailedMalloc(); magic = db->magic;
} if( magic!=SQLITE_MAGIC_OPEN &&
return p; magic!=SQLITE_MAGIC_BUSY ) return 0;
return 1;
} }
int sqlite3SafetyCheckSickOrOk(sqlite3 *db){
/* u32 magic;
** Return a pointer to the ThreadData associated with the calling thread. if( db==0 ) return 0;
** If no ThreadData has been allocated to this thread yet, return a pointer magic = db->magic;
** to a substitute ThreadData structure that is all zeros. if( magic!=SQLITE_MAGIC_SICK &&
*/ magic!=SQLITE_MAGIC_OPEN &&
const ThreadData *sqlite3ThreadDataReadOnly(){ magic!=SQLITE_MAGIC_BUSY ) return 0;
static const ThreadData zeroData = {0}; /* Initializer to silence warnings return 1;
** from broken compilers */
const ThreadData *pTd = sqlite3OsThreadSpecificData(0);
return pTd ? pTd : &zeroData;
}
/*
** Check to see if the ThreadData for this thread is all zero. If it
** is, then deallocate it.
*/
void sqlite3ReleaseThreadData(){
sqlite3OsThreadSpecificData(-1);
} }

View file

@ -14,11 +14,10 @@
** Most of the code in this file may be omitted by defining the ** Most of the code in this file may be omitted by defining the
** SQLITE_OMIT_VACUUM macro. ** SQLITE_OMIT_VACUUM macro.
** **
** $Id: vacuum.c,v 1.69 2007/03/27 16:19:52 danielk1977 Exp $ ** $Id: vacuum.c,v 1.84 2008/11/17 19:18:55 danielk1977 Exp $
*/ */
#include "sqliteInt.h" #include "sqliteInt.h"
#include "vdbeInt.h" #include "vdbeInt.h"
#include "os.h"
#if !defined(SQLITE_OMIT_VACUUM) && !defined(SQLITE_OMIT_ATTACH) #if !defined(SQLITE_OMIT_VACUUM) && !defined(SQLITE_OMIT_ATTACH)
/* /*
@ -26,6 +25,9 @@
*/ */
static int execSql(sqlite3 *db, const char *zSql){ static int execSql(sqlite3 *db, const char *zSql){
sqlite3_stmt *pStmt; sqlite3_stmt *pStmt;
if( !zSql ){
return SQLITE_NOMEM;
}
if( SQLITE_OK!=sqlite3_prepare(db, zSql, -1, &pStmt, 0) ){ if( SQLITE_OK!=sqlite3_prepare(db, zSql, -1, &pStmt, 0) ){
return sqlite3_errcode(db); return sqlite3_errcode(db);
} }
@ -68,7 +70,7 @@ static int execExecSql(sqlite3 *db, const char *zSql){
void sqlite3Vacuum(Parse *pParse){ void sqlite3Vacuum(Parse *pParse){
Vdbe *v = sqlite3GetVdbe(pParse); Vdbe *v = sqlite3GetVdbe(pParse);
if( v ){ if( v ){
sqlite3VdbeAddOp(v, OP_Vacuum, 0, 0); sqlite3VdbeAddOp2(v, OP_Vacuum, 0, 0);
} }
return; return;
} }
@ -79,22 +81,30 @@ void sqlite3Vacuum(Parse *pParse){
int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
int rc = SQLITE_OK; /* Return code from service routines */ int rc = SQLITE_OK; /* Return code from service routines */
Btree *pMain; /* The database being vacuumed */ Btree *pMain; /* The database being vacuumed */
Pager *pMainPager; /* Pager for database being vacuumed */
Btree *pTemp; /* The temporary database we vacuum into */ Btree *pTemp; /* The temporary database we vacuum into */
char *zSql = 0; /* SQL statements */ char *zSql = 0; /* SQL statements */
int saved_flags; /* Saved value of the db->flags */ int saved_flags; /* Saved value of the db->flags */
int saved_nChange; /* Saved value of db->nChange */
int saved_nTotalChange; /* Saved value of db->nTotalChange */
Db *pDb = 0; /* Database to detach at end of vacuum */ Db *pDb = 0; /* Database to detach at end of vacuum */
int isMemDb; /* True is vacuuming a :memory: database */
int nRes;
/* Save the current value of the write-schema flag before setting it. */ /* Save the current value of the write-schema flag before setting it. */
saved_flags = db->flags; saved_flags = db->flags;
saved_nChange = db->nChange;
saved_nTotalChange = db->nTotalChange;
db->flags |= SQLITE_WriteSchema | SQLITE_IgnoreChecks; db->flags |= SQLITE_WriteSchema | SQLITE_IgnoreChecks;
if( !db->autoCommit ){ if( !db->autoCommit ){
sqlite3SetString(pzErrMsg, "cannot VACUUM from within a transaction", sqlite3SetString(pzErrMsg, db, "cannot VACUUM from within a transaction");
(char*)0);
rc = SQLITE_ERROR; rc = SQLITE_ERROR;
goto end_of_vacuum; goto end_of_vacuum;
} }
pMain = db->aDb[0].pBt; pMain = db->aDb[0].pBt;
pMainPager = sqlite3BtreePager(pMain);
isMemDb = sqlite3PagerFile(pMainPager)->pMethods==0;
/* Attach the temporary database as 'vacuum_db'. The synchronous pragma /* Attach the temporary database as 'vacuum_db'. The synchronous pragma
** can be set to 'off' for this file, as it is not recovered if a crash ** can be set to 'off' for this file, as it is not recovered if a crash
@ -103,6 +113,12 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
** sqlite3BtreeCopyFile() is called. ** sqlite3BtreeCopyFile() is called.
** **
** An optimisation would be to use a non-journaled pager. ** An optimisation would be to use a non-journaled pager.
** (Later:) I tried setting "PRAGMA vacuum_db.journal_mode=OFF" but
** that actually made the VACUUM run slower. Very little journalling
** actually occurs when doing a vacuum since the vacuum_db is initially
** empty. Only the journal header is written. Apparently it takes more
** time to parse and run the PRAGMA to turn journalling off than it does
** to write the journal header file.
*/ */
zSql = "ATTACH '' AS vacuum_db;"; zSql = "ATTACH '' AS vacuum_db;";
rc = execSql(db, zSql); rc = execSql(db, zSql);
@ -110,20 +126,35 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
pDb = &db->aDb[db->nDb-1]; pDb = &db->aDb[db->nDb-1];
assert( strcmp(db->aDb[db->nDb-1].zName,"vacuum_db")==0 ); assert( strcmp(db->aDb[db->nDb-1].zName,"vacuum_db")==0 );
pTemp = db->aDb[db->nDb-1].pBt; pTemp = db->aDb[db->nDb-1].pBt;
sqlite3BtreeSetPageSize(pTemp, sqlite3BtreeGetPageSize(pMain),
sqlite3BtreeGetReserve(pMain)); nRes = sqlite3BtreeGetReserve(pMain);
if( sqlite3MallocFailed() ){
/* A VACUUM cannot change the pagesize of an encrypted database. */
#ifdef SQLITE_HAS_CODEC
if( db->nextPagesize ){
extern void sqlite3CodecGetKey(sqlite3*, int, void**, int*);
int nKey;
char *zKey;
sqlite3CodecGetKey(db, 0, (void**)&zKey, &nKey);
if( nKey ) db->nextPagesize = 0;
}
#endif
if( sqlite3BtreeSetPageSize(pTemp, sqlite3BtreeGetPageSize(pMain), nRes)
|| (!isMemDb && sqlite3BtreeSetPageSize(pTemp, db->nextPagesize, nRes))
|| db->mallocFailed
){
rc = SQLITE_NOMEM; rc = SQLITE_NOMEM;
goto end_of_vacuum; goto end_of_vacuum;
} }
assert( sqlite3BtreeGetPageSize(pTemp)==sqlite3BtreeGetPageSize(pMain) );
rc = execSql(db, "PRAGMA vacuum_db.synchronous=OFF"); rc = execSql(db, "PRAGMA vacuum_db.synchronous=OFF");
if( rc!=SQLITE_OK ){ if( rc!=SQLITE_OK ){
goto end_of_vacuum; goto end_of_vacuum;
} }
#ifndef SQLITE_OMIT_AUTOVACUUM #ifndef SQLITE_OMIT_AUTOVACUUM
sqlite3BtreeSetAutoVacuum(pTemp, sqlite3BtreeGetAutoVacuum(pMain)); sqlite3BtreeSetAutoVacuum(pTemp, db->nextAutovac>=0 ? db->nextAutovac :
sqlite3BtreeGetAutoVacuum(pMain));
#endif #endif
/* Begin a transaction */ /* Begin a transaction */
@ -134,17 +165,17 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
** in the temporary database. ** in the temporary database.
*/ */
rc = execExecSql(db, rc = execExecSql(db,
"SELECT 'CREATE TABLE vacuum_db.' || substr(sql,14,100000000) " "SELECT 'CREATE TABLE vacuum_db.' || substr(sql,14) "
" FROM sqlite_master WHERE type='table' AND name!='sqlite_sequence'" " FROM sqlite_master WHERE type='table' AND name!='sqlite_sequence'"
" AND rootpage>0" " AND rootpage>0"
); );
if( rc!=SQLITE_OK ) goto end_of_vacuum; if( rc!=SQLITE_OK ) goto end_of_vacuum;
rc = execExecSql(db, rc = execExecSql(db,
"SELECT 'CREATE INDEX vacuum_db.' || substr(sql,14,100000000)" "SELECT 'CREATE INDEX vacuum_db.' || substr(sql,14)"
" FROM sqlite_master WHERE sql LIKE 'CREATE INDEX %' "); " FROM sqlite_master WHERE sql LIKE 'CREATE INDEX %' ");
if( rc!=SQLITE_OK ) goto end_of_vacuum; if( rc!=SQLITE_OK ) goto end_of_vacuum;
rc = execExecSql(db, rc = execExecSql(db,
"SELECT 'CREATE UNIQUE INDEX vacuum_db.' || substr(sql,21,100000000) " "SELECT 'CREATE UNIQUE INDEX vacuum_db.' || substr(sql,21) "
" FROM sqlite_master WHERE sql LIKE 'CREATE UNIQUE INDEX %'"); " FROM sqlite_master WHERE sql LIKE 'CREATE UNIQUE INDEX %'");
if( rc!=SQLITE_OK ) goto end_of_vacuum; if( rc!=SQLITE_OK ) goto end_of_vacuum;
@ -220,7 +251,7 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
assert( 1==sqlite3BtreeIsInTrans(pMain) ); assert( 1==sqlite3BtreeIsInTrans(pMain) );
/* Copy Btree meta values */ /* Copy Btree meta values */
for(i=0; i<sizeof(aCopy)/sizeof(aCopy[0]); i+=2){ for(i=0; i<ArraySize(aCopy); i+=2){
rc = sqlite3BtreeGetMeta(pMain, aCopy[i], &meta); rc = sqlite3BtreeGetMeta(pMain, aCopy[i], &meta);
if( rc!=SQLITE_OK ) goto end_of_vacuum; if( rc!=SQLITE_OK ) goto end_of_vacuum;
rc = sqlite3BtreeUpdateMeta(pTemp, aCopy[i], meta+aCopy[i+1]); rc = sqlite3BtreeUpdateMeta(pTemp, aCopy[i], meta+aCopy[i+1]);
@ -231,12 +262,21 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
if( rc!=SQLITE_OK ) goto end_of_vacuum; if( rc!=SQLITE_OK ) goto end_of_vacuum;
rc = sqlite3BtreeCommit(pTemp); rc = sqlite3BtreeCommit(pTemp);
if( rc!=SQLITE_OK ) goto end_of_vacuum; if( rc!=SQLITE_OK ) goto end_of_vacuum;
#ifndef SQLITE_OMIT_AUTOVACUUM
sqlite3BtreeSetAutoVacuum(pMain, sqlite3BtreeGetAutoVacuum(pTemp));
#endif
rc = sqlite3BtreeCommit(pMain); rc = sqlite3BtreeCommit(pMain);
} }
if( rc==SQLITE_OK ){
rc = sqlite3BtreeSetPageSize(pMain, sqlite3BtreeGetPageSize(pTemp), nRes);
}
end_of_vacuum: end_of_vacuum:
/* Restore the original value of db->flags */ /* Restore the original value of db->flags */
db->flags = saved_flags; db->flags = saved_flags;
db->nChange = saved_nChange;
db->nTotalChange = saved_nTotalChange;
/* Currently there is an SQL level transaction open on the vacuum /* Currently there is an SQL level transaction open on the vacuum
** database. No locks are held on any other files (since the main file ** database. No locks are held on any other files (since the main file
@ -248,9 +288,7 @@ end_of_vacuum:
db->autoCommit = 1; db->autoCommit = 1;
if( pDb ){ if( pDb ){
sqlite3MallocDisallow();
sqlite3BtreeClose(pDb->pBt); sqlite3BtreeClose(pDb->pBt);
sqlite3MallocAllow();
pDb->pBt = 0; pDb->pBt = 0;
pDb->pSchema = 0; pDb->pSchema = 0;
} }

4841
vdbe.c

File diff suppressed because it is too large Load diff

110
vdbe.h
View file

@ -15,7 +15,7 @@
** or VDBE. The VDBE implements an abstract machine that runs a ** or VDBE. The VDBE implements an abstract machine that runs a
** simple program to access and modify the underlying database. ** simple program to access and modify the underlying database.
** **
** $Id: vdbe.h,v 1.110 2007/05/08 21:45:28 drh Exp $ ** $Id: vdbe.h,v 1.139 2008/10/31 10:53:23 danielk1977 Exp $
*/ */
#ifndef _SQLITE_VDBE_H_ #ifndef _SQLITE_VDBE_H_
#define _SQLITE_VDBE_H_ #define _SQLITE_VDBE_H_
@ -28,6 +28,13 @@
*/ */
typedef struct Vdbe Vdbe; typedef struct Vdbe Vdbe;
/*
** The names of the following types declared in vdbeInt.h are required
** for the VdbeOp definition.
*/
typedef struct VdbeFunc VdbeFunc;
typedef struct Mem Mem;
/* /*
** A single instruction of the virtual machine has an opcode ** A single instruction of the virtual machine has an opcode
** and as many as three operands. The instruction is recorded ** and as many as three operands. The instruction is recorded
@ -35,13 +42,32 @@ typedef struct Vdbe Vdbe;
*/ */
struct VdbeOp { struct VdbeOp {
u8 opcode; /* What operation to perform */ u8 opcode; /* What operation to perform */
signed char p4type; /* One of the P4_xxx constants for p4 */
u8 opflags; /* Not currently used */
u8 p5; /* Fifth parameter is an unsigned character */
int p1; /* First operand */ int p1; /* First operand */
int p2; /* Second parameter (often the jump destination) */ int p2; /* Second parameter (often the jump destination) */
char *p3; /* Third parameter */ int p3; /* The third parameter */
int p3type; /* One of the P3_xxx constants defined below */ union { /* forth parameter */
int i; /* Integer value if p4type==P4_INT32 */
void *p; /* Generic pointer */
char *z; /* Pointer to data for string (char array) types */
i64 *pI64; /* Used when p4type is P4_INT64 */
double *pReal; /* Used when p4type is P4_REAL */
FuncDef *pFunc; /* Used when p4type is P4_FUNCDEF */
VdbeFunc *pVdbeFunc; /* Used when p4type is P4_VDBEFUNC */
CollSeq *pColl; /* Used when p4type is P4_COLLSEQ */
Mem *pMem; /* Used when p4type is P4_MEM */
sqlite3_vtab *pVtab; /* Used when p4type is P4_VTAB */
KeyInfo *pKeyInfo; /* Used when p4type is P4_KEYINFO */
int *ai; /* Used when p4type is P4_INTARRAY */
} p4;
#ifdef SQLITE_DEBUG
char *zComment; /* Comment to improve readability */
#endif
#ifdef VDBE_PROFILE #ifdef VDBE_PROFILE
int cnt; /* Number of times this instruction was executed */ int cnt; /* Number of times this instruction was executed */
long long cycles; /* Total time spend executing this instruction */ u64 cycles; /* Total time spent executing this instruction */
#endif #endif
}; };
typedef struct VdbeOp VdbeOp; typedef struct VdbeOp VdbeOp;
@ -53,34 +79,39 @@ typedef struct VdbeOp VdbeOp;
struct VdbeOpList { struct VdbeOpList {
u8 opcode; /* What operation to perform */ u8 opcode; /* What operation to perform */
signed char p1; /* First operand */ signed char p1; /* First operand */
short int p2; /* Second parameter (often the jump destination) */ signed char p2; /* Second parameter (often the jump destination) */
char *p3; /* Third parameter */ signed char p3; /* Third parameter */
}; };
typedef struct VdbeOpList VdbeOpList; typedef struct VdbeOpList VdbeOpList;
/* /*
** Allowed values of VdbeOp.p3type ** Allowed values of VdbeOp.p3type
*/ */
#define P3_NOTUSED 0 /* The P3 parameter is not used */ #define P4_NOTUSED 0 /* The P4 parameter is not used */
#define P3_DYNAMIC (-1) /* Pointer to a string obtained from sqliteMalloc() */ #define P4_DYNAMIC (-1) /* Pointer to a string obtained from sqliteMalloc() */
#define P3_STATIC (-2) /* Pointer to a static string */ #define P4_STATIC (-2) /* Pointer to a static string */
#define P3_COLLSEQ (-4) /* P3 is a pointer to a CollSeq structure */ #define P4_COLLSEQ (-4) /* P4 is a pointer to a CollSeq structure */
#define P3_FUNCDEF (-5) /* P3 is a pointer to a FuncDef structure */ #define P4_FUNCDEF (-5) /* P4 is a pointer to a FuncDef structure */
#define P3_KEYINFO (-6) /* P3 is a pointer to a KeyInfo structure */ #define P4_KEYINFO (-6) /* P4 is a pointer to a KeyInfo structure */
#define P3_VDBEFUNC (-7) /* P3 is a pointer to a VdbeFunc structure */ #define P4_VDBEFUNC (-7) /* P4 is a pointer to a VdbeFunc structure */
#define P3_MEM (-8) /* P3 is a pointer to a Mem* structure */ #define P4_MEM (-8) /* P4 is a pointer to a Mem* structure */
#define P3_TRANSIENT (-9) /* P3 is a pointer to a transient string */ #define P4_TRANSIENT (-9) /* P4 is a pointer to a transient string */
#define P3_VTAB (-10) /* P3 is a pointer to an sqlite3_vtab structure */ #define P4_VTAB (-10) /* P4 is a pointer to an sqlite3_vtab structure */
#define P3_MPRINTF (-11) /* P3 is a string obtained from sqlite3_mprintf() */ #define P4_MPRINTF (-11) /* P4 is a string obtained from sqlite3_mprintf() */
#define P4_REAL (-12) /* P4 is a 64-bit floating point value */
#define P4_INT64 (-13) /* P4 is a 64-bit signed integer */
#define P4_INT32 (-14) /* P4 is a 32-bit signed integer */
#define P4_INTARRAY (-15) /* P4 is a vector of 32-bit integers */
/* When adding a P3 argument using P3_KEYINFO, a copy of the KeyInfo structure /* When adding a P4 argument using P4_KEYINFO, a copy of the KeyInfo structure
** is made. That copy is freed when the Vdbe is finalized. But if the ** is made. That copy is freed when the Vdbe is finalized. But if the
** argument is P3_KEYINFO_HANDOFF, the passed in pointer is used. It still ** argument is P4_KEYINFO_HANDOFF, the passed in pointer is used. It still
** gets freed when the Vdbe is finalized so it still should be obtained ** gets freed when the Vdbe is finalized so it still should be obtained
** from a single sqliteMalloc(). But no copy is made and the calling ** from a single sqliteMalloc(). But no copy is made and the calling
** function should *not* try to free the KeyInfo. ** function should *not* try to free the KeyInfo.
*/ */
#define P3_KEYINFO_HANDOFF (-9) #define P4_KEYINFO_HANDOFF (-16)
#define P4_KEYINFO_STATIC (-17)
/* /*
** The Vdbe.aColName array contains 5n Mem structures, where n is the ** The Vdbe.aColName array contains 5n Mem structures, where n is the
@ -91,7 +122,15 @@ typedef struct VdbeOpList VdbeOpList;
#define COLNAME_DATABASE 2 #define COLNAME_DATABASE 2
#define COLNAME_TABLE 3 #define COLNAME_TABLE 3
#define COLNAME_COLUMN 4 #define COLNAME_COLUMN 4
#define COLNAME_N 5 /* Number of COLNAME_xxx symbols */ #ifdef SQLITE_ENABLE_COLUMN_METADATA
# define COLNAME_N 5 /* Number of COLNAME_xxx symbols */
#else
# ifdef SQLITE_OMIT_DECLTYPE
# define COLNAME_N 1 /* Store only the name */
# else
# define COLNAME_N 2 /* Store the name and decltype */
# endif
#endif
/* /*
** The following macro converts a relative address in the p2 field ** The following macro converts a relative address in the p2 field
@ -112,14 +151,20 @@ typedef struct VdbeOpList VdbeOpList;
** for a description of what each of these routines does. ** for a description of what each of these routines does.
*/ */
Vdbe *sqlite3VdbeCreate(sqlite3*); Vdbe *sqlite3VdbeCreate(sqlite3*);
int sqlite3VdbeAddOp(Vdbe*,int,int,int); int sqlite3VdbeAddOp0(Vdbe*,int);
int sqlite3VdbeOp3(Vdbe*,int,int,int,const char *zP3,int); int sqlite3VdbeAddOp1(Vdbe*,int,int);
int sqlite3VdbeAddOp2(Vdbe*,int,int,int);
int sqlite3VdbeAddOp3(Vdbe*,int,int,int,int);
int sqlite3VdbeAddOp4(Vdbe*,int,int,int,int,const char *zP4,int);
int sqlite3VdbeAddOpList(Vdbe*, int nOp, VdbeOpList const *aOp); int sqlite3VdbeAddOpList(Vdbe*, int nOp, VdbeOpList const *aOp);
void sqlite3VdbeChangeP1(Vdbe*, int addr, int P1); void sqlite3VdbeChangeP1(Vdbe*, int addr, int P1);
void sqlite3VdbeChangeP2(Vdbe*, int addr, int P2); void sqlite3VdbeChangeP2(Vdbe*, int addr, int P2);
void sqlite3VdbeChangeP3(Vdbe*, int addr, int P3);
void sqlite3VdbeChangeP5(Vdbe*, u8 P5);
void sqlite3VdbeJumpHere(Vdbe*, int addr); void sqlite3VdbeJumpHere(Vdbe*, int addr);
void sqlite3VdbeChangeToNoop(Vdbe*, int addr, int N); void sqlite3VdbeChangeToNoop(Vdbe*, int addr, int N);
void sqlite3VdbeChangeP3(Vdbe*, int addr, const char *zP1, int N); void sqlite3VdbeChangeP4(Vdbe*, int addr, const char *zP4, int N);
void sqlite3VdbeUsesBtree(Vdbe*, int);
VdbeOp *sqlite3VdbeGetOp(Vdbe*, int); VdbeOp *sqlite3VdbeGetOp(Vdbe*, int);
int sqlite3VdbeMakeLabel(Vdbe*); int sqlite3VdbeMakeLabel(Vdbe*);
void sqlite3VdbeDelete(Vdbe*); void sqlite3VdbeDelete(Vdbe*);
@ -133,18 +178,29 @@ int sqlite3VdbeCurrentAddr(Vdbe*);
void sqlite3VdbeResetStepResult(Vdbe*); void sqlite3VdbeResetStepResult(Vdbe*);
int sqlite3VdbeReset(Vdbe*); int sqlite3VdbeReset(Vdbe*);
void sqlite3VdbeSetNumCols(Vdbe*,int); void sqlite3VdbeSetNumCols(Vdbe*,int);
int sqlite3VdbeSetColName(Vdbe*, int, int, const char *, int); int sqlite3VdbeSetColName(Vdbe*, int, int, const char *, void(*)(void*));
void sqlite3VdbeCountChanges(Vdbe*); void sqlite3VdbeCountChanges(Vdbe*);
sqlite3 *sqlite3VdbeDb(Vdbe*); sqlite3 *sqlite3VdbeDb(Vdbe*);
void sqlite3VdbeSetSql(Vdbe*, const char *z, int n); void sqlite3VdbeSetSql(Vdbe*, const char *z, int n);
const char *sqlite3VdbeGetSql(Vdbe*);
void sqlite3VdbeSwap(Vdbe*,Vdbe*); void sqlite3VdbeSwap(Vdbe*,Vdbe*);
#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
int sqlite3VdbeReleaseMemory(int);
#endif
UnpackedRecord *sqlite3VdbeRecordUnpack(KeyInfo*,int,const void*,
UnpackedRecord*,int);
void sqlite3VdbeDeleteUnpackedRecord(UnpackedRecord*);
int sqlite3VdbeRecordCompare(int,const void*,UnpackedRecord*);
#ifndef NDEBUG #ifndef NDEBUG
void sqlite3VdbeComment(Vdbe*, const char*, ...); void sqlite3VdbeComment(Vdbe*, const char*, ...);
# define VdbeComment(X) sqlite3VdbeComment X # define VdbeComment(X) sqlite3VdbeComment X
void sqlite3VdbeNoopComment(Vdbe*, const char*, ...);
# define VdbeNoopComment(X) sqlite3VdbeNoopComment X
#else #else
# define VdbeComment(X) # define VdbeComment(X)
# define VdbeNoopComment(X)
#endif #endif
#endif #endif

144
vdbeInt.h
View file

@ -14,6 +14,8 @@
** source code file "vdbe.c". When that file became too big (over ** source code file "vdbe.c". When that file became too big (over
** 6000 lines long) it was split up into several smaller files and ** 6000 lines long) it was split up into several smaller files and
** this header information was factored out. ** this header information was factored out.
**
** $Id: vdbeInt.h,v 1.161 2009/01/05 18:02:27 drh Exp $
*/ */
#ifndef _VDBEINT_H_ #ifndef _VDBEINT_H_
#define _VDBEINT_H_ #define _VDBEINT_H_
@ -25,13 +27,6 @@
#define keyToInt(X) (X) #define keyToInt(X) (X)
#define intToKey(X) (X) #define intToKey(X) (X)
/*
** The makefile scans the vdbe.c source file and creates the following
** array of string constants which are the names of all VDBE opcodes. This
** array is defined in a separate source code file named opcode.c which is
** automatically generated by the makefile.
*/
extern const char *const sqlite3OpcodeNames[];
/* /*
** SQL is translated into a sequence of instructions to be ** SQL is translated into a sequence of instructions to be
@ -55,12 +50,12 @@ typedef unsigned char Bool;
** Every cursor that the virtual machine has open is represented by an ** Every cursor that the virtual machine has open is represented by an
** instance of the following structure. ** instance of the following structure.
** **
** If the Cursor.isTriggerRow flag is set it means that this cursor is ** If the VdbeCursor.isTriggerRow flag is set it means that this cursor is
** really a single row that represents the NEW or OLD pseudo-table of ** really a single row that represents the NEW or OLD pseudo-table of
** a row trigger. The data for the row is stored in Cursor.pData and ** a row trigger. The data for the row is stored in VdbeCursor.pData and
** the rowid is in Cursor.iKey. ** the rowid is in VdbeCursor.iKey.
*/ */
struct Cursor { struct VdbeCursor {
BtCursor *pCursor; /* The cursor structure of the backend */ BtCursor *pCursor; /* The cursor structure of the backend */
int iDb; /* Index of cursor database in db->aDb[] (or -1) */ int iDb; /* Index of cursor database in db->aDb[] (or -1) */
i64 lastRowid; /* Last rowid from a Next or NextIdx operation */ i64 lastRowid; /* Last rowid from a Next or NextIdx operation */
@ -72,16 +67,15 @@ struct Cursor {
Bool nullRow; /* True if pointing to a row with no data */ Bool nullRow; /* True if pointing to a row with no data */
Bool nextRowidValid; /* True if the nextRowid field is valid */ Bool nextRowidValid; /* True if the nextRowid field is valid */
Bool pseudoTable; /* This is a NEW or OLD pseudo-tables of a trigger */ Bool pseudoTable; /* This is a NEW or OLD pseudo-tables of a trigger */
Bool ephemPseudoTable;
Bool deferredMoveto; /* A call to sqlite3BtreeMoveto() is needed */ Bool deferredMoveto; /* A call to sqlite3BtreeMoveto() is needed */
Bool isTable; /* True if a table requiring integer keys */ Bool isTable; /* True if a table requiring integer keys */
Bool isIndex; /* True if an index containing keys only - no data */ Bool isIndex; /* True if an index containing keys only - no data */
u8 bogusIncrKey; /* Something for pIncrKey to point to if pKeyInfo==0 */
i64 movetoTarget; /* Argument to the deferred sqlite3BtreeMoveto() */ i64 movetoTarget; /* Argument to the deferred sqlite3BtreeMoveto() */
Btree *pBt; /* Separate file holding temporary table */ Btree *pBt; /* Separate file holding temporary table */
int nData; /* Number of bytes in pData */ int nData; /* Number of bytes in pData */
char *pData; /* Data for a NEW or OLD pseudo-table */ char *pData; /* Data for a NEW or OLD pseudo-table */
i64 iKey; /* Key for the NEW or OLD pseudo-table row */ i64 iKey; /* Key for the NEW or OLD pseudo-table row */
u8 *pIncrKey; /* Pointer to pKeyInfo->incrKey */
KeyInfo *pKeyInfo; /* Info about index keys needed by index cursors */ KeyInfo *pKeyInfo; /* Info about index keys needed by index cursors */
int nField; /* Number of fields in the header */ int nField; /* Number of fields in the header */
i64 seqCount; /* Sequence counter */ i64 seqCount; /* Sequence counter */
@ -99,17 +93,10 @@ struct Cursor {
u32 *aOffset; /* Cached offsets to the start of each columns data */ u32 *aOffset; /* Cached offsets to the start of each columns data */
u8 *aRow; /* Data for the current row, if all on one page */ u8 *aRow; /* Data for the current row, if all on one page */
}; };
typedef struct Cursor Cursor; typedef struct VdbeCursor VdbeCursor;
/* /*
** Number of bytes of string storage space available to each stack ** A value for VdbeCursor.cacheValid that means the cache is always invalid.
** layer without having to malloc. NBFS is short for Number of Bytes
** For Strings.
*/
#define NBFS 32
/*
** A value for Cursor.cacheValid that means the cache is always invalid.
*/ */
#define CACHE_STALE 0 #define CACHE_STALE 0
@ -126,19 +113,21 @@ typedef struct Cursor Cursor;
*/ */
struct Mem { struct Mem {
union { union {
i64 i; /* Integer value. Or FuncDef* when flags==MEM_Agg */ i64 i; /* Integer value. */
int nZero; /* Used when bit MEM_Zero is set in flags */
FuncDef *pDef; /* Used only when flags==MEM_Agg */ FuncDef *pDef; /* Used only when flags==MEM_Agg */
RowSet *pRowSet; /* Used only when flags==MEM_RowSet */
} u; } u;
double r; /* Real value */ double r; /* Real value */
sqlite3 *db; /* The associated database connection */
char *z; /* String or BLOB value */ char *z; /* String or BLOB value */
int n; /* Number of characters in string value, including '\0' */ int n; /* Number of characters in string value, excluding '\0' */
u16 flags; /* Some combination of MEM_Null, MEM_Str, MEM_Dyn, etc. */ u16 flags; /* Some combination of MEM_Null, MEM_Str, MEM_Dyn, etc. */
u8 type; /* One of SQLITE_NULL, SQLITE_TEXT, SQLITE_INTEGER, etc */ u8 type; /* One of SQLITE_NULL, SQLITE_TEXT, SQLITE_INTEGER, etc */
u8 enc; /* SQLITE_UTF8, SQLITE_UTF16BE, SQLITE_UTF16LE */ u8 enc; /* SQLITE_UTF8, SQLITE_UTF16BE, SQLITE_UTF16LE */
void (*xDel)(void *); /* If not null, call this function to delete Mem.z */ void (*xDel)(void *); /* If not null, call this function to delete Mem.z */
char zShort[NBFS]; /* Space for short strings */ char *zMalloc; /* Dynamic buffer allocated by sqlite3_malloc() */
}; };
typedef struct Mem Mem;
/* One or more of the following flags are set to indicate the validOK /* One or more of the following flags are set to indicate the validOK
** representations of the value stored in the Mem struct. ** representations of the value stored in the Mem struct.
@ -160,19 +149,20 @@ typedef struct Mem Mem;
#define MEM_Int 0x0004 /* Value is an integer */ #define MEM_Int 0x0004 /* Value is an integer */
#define MEM_Real 0x0008 /* Value is a real number */ #define MEM_Real 0x0008 /* Value is a real number */
#define MEM_Blob 0x0010 /* Value is a BLOB */ #define MEM_Blob 0x0010 /* Value is a BLOB */
#define MEM_RowSet 0x0020 /* Value is a RowSet object */
#define MEM_TypeMask 0x00ff /* Mask of type bits */
/* Whenever Mem contains a valid string or blob representation, one of /* Whenever Mem contains a valid string or blob representation, one of
** the following flags must be set to determine the memory management ** the following flags must be set to determine the memory management
** policy for Mem.z. The MEM_Term flag tells us whether or not the ** policy for Mem.z. The MEM_Term flag tells us whether or not the
** string is \000 or \u0000 terminated ** string is \000 or \u0000 terminated
*/ */
#define MEM_Term 0x0020 /* String rep is nul terminated */ #define MEM_Term 0x0200 /* String rep is nul terminated */
#define MEM_Dyn 0x0040 /* Need to call sqliteFree() on Mem.z */ #define MEM_Dyn 0x0400 /* Need to call sqliteFree() on Mem.z */
#define MEM_Static 0x0080 /* Mem.z points to a static string */ #define MEM_Static 0x0800 /* Mem.z points to a static string */
#define MEM_Ephem 0x0100 /* Mem.z points to an ephemeral string */ #define MEM_Ephem 0x1000 /* Mem.z points to an ephemeral string */
#define MEM_Short 0x0200 /* Mem.z points to Mem.zShort */ #define MEM_Agg 0x2000 /* Mem.z points to an agg function context */
#define MEM_Agg 0x0400 /* Mem.z points to an agg function context */ #define MEM_Zero 0x4000 /* Mem.i contains count of 0s appended to blob */
#define MEM_Zero 0x0800 /* Mem.i contains count of 0s appended to blob */
#ifdef SQLITE_OMIT_INCRBLOB #ifdef SQLITE_OMIT_INCRBLOB
#undef MEM_Zero #undef MEM_Zero
@ -180,6 +170,13 @@ typedef struct Mem Mem;
#endif #endif
/*
** Clear any existing type flags from a Mem and replace them with f
*/
#define MemSetTypeFlag(p, f) \
((p)->flags = ((p)->flags&~(MEM_TypeMask|MEM_Zero))|f)
/* A VdbeFunc is just a FuncDef (defined in sqliteInt.h) that contains /* A VdbeFunc is just a FuncDef (defined in sqliteInt.h) that contains
** additional information about auxiliary information bound to arguments ** additional information about auxiliary information bound to arguments
** of the function. This is used to implement the sqlite3_get_auxdata() ** of the function. This is used to implement the sqlite3_get_auxdata()
@ -197,7 +194,6 @@ struct VdbeFunc {
void (*xDelete)(void *); /* Destructor for the aux data */ void (*xDelete)(void *); /* Destructor for the aux data */
} apAux[1]; /* One slot for each function argument */ } apAux[1]; /* One slot for each function argument */
}; };
typedef struct VdbeFunc VdbeFunc;
/* /*
** The "context" argument for a installable function. A pointer to an ** The "context" argument for a installable function. A pointer to an
@ -217,7 +213,7 @@ struct sqlite3_context {
VdbeFunc *pVdbeFunc; /* Auxilary data, if created. */ VdbeFunc *pVdbeFunc; /* Auxilary data, if created. */
Mem s; /* The return value is stored here */ Mem s; /* The return value is stored here */
Mem *pMem; /* Memory cell used to store aggregate context */ Mem *pMem; /* Memory cell used to store aggregate context */
u8 isError; /* Set to true for an error */ int isError; /* Error code returned by the function. */
CollSeq *pColl; /* Collating sequence */ CollSeq *pColl; /* Collating sequence */
}; };
@ -233,32 +229,6 @@ struct Set {
HashElem *prev; /* Previously accessed hash elemen */ HashElem *prev; /* Previously accessed hash elemen */
}; };
/*
** A FifoPage structure holds a single page of valves. Pages are arranged
** in a list.
*/
typedef struct FifoPage FifoPage;
struct FifoPage {
int nSlot; /* Number of entries aSlot[] */
int iWrite; /* Push the next value into this entry in aSlot[] */
int iRead; /* Read the next value from this entry in aSlot[] */
FifoPage *pNext; /* Next page in the fifo */
i64 aSlot[1]; /* One or more slots for rowid values */
};
/*
** The Fifo structure is typedef-ed in vdbeInt.h. But the implementation
** of that structure is private to this file.
**
** The Fifo structure describes the entire fifo.
*/
typedef struct Fifo Fifo;
struct Fifo {
int nEntry; /* Total number of entries */
FifoPage *pFirst; /* First page on the list */
FifoPage *pLast; /* Last page on the list */
};
/* /*
** A Context stores the last insert rowid, the last statement change count, ** A Context stores the last insert rowid, the last statement change count,
** and the current statement change count (i.e. changes since last statement). ** and the current statement change count (i.e. changes since last statement).
@ -272,7 +242,6 @@ typedef struct Context Context;
struct Context { struct Context {
i64 lastRowid; /* Last insert rowid (sqlite3.lastRowid) */ i64 lastRowid; /* Last insert rowid (sqlite3.lastRowid) */
int nChange; /* Statement changes (Vdbe.nChanges) */ int nChange; /* Statement changes (Vdbe.nChanges) */
Fifo sFifo; /* Records that will participate in a DELETE or UPDATE */
}; };
/* /*
@ -299,22 +268,19 @@ struct Vdbe {
int nLabel; /* Number of labels used */ int nLabel; /* Number of labels used */
int nLabelAlloc; /* Number of slots allocated in aLabel[] */ int nLabelAlloc; /* Number of slots allocated in aLabel[] */
int *aLabel; /* Space to hold the labels */ int *aLabel; /* Space to hold the labels */
Mem *aStack; /* The operand stack, except string values */
Mem *pTos; /* Top entry in the operand stack */
Mem **apArg; /* Arguments to currently executing user function */ Mem **apArg; /* Arguments to currently executing user function */
Mem *aColName; /* Column names to return */ Mem *aColName; /* Column names to return */
int nCursor; /* Number of slots in apCsr[] */ int nCursor; /* Number of slots in apCsr[] */
Cursor **apCsr; /* One element of this array for each open cursor */ VdbeCursor **apCsr; /* One element of this array for each open cursor */
int nVar; /* Number of entries in aVar[] */ int nVar; /* Number of entries in aVar[] */
Mem *aVar; /* Values for the OP_Variable opcode. */ Mem *aVar; /* Values for the OP_Variable opcode. */
char **azVar; /* Name of variables */ char **azVar; /* Name of variables */
int okVar; /* True if azVar[] has been initialized */ int okVar; /* True if azVar[] has been initialized */
int magic; /* Magic number for sanity checking */ u32 magic; /* Magic number for sanity checking */
int nMem; /* Number of memory locations currently allocated */ int nMem; /* Number of memory locations currently allocated */
Mem *aMem; /* The memory locations */ Mem *aMem; /* The memory locations */
int nCallback; /* Number of callbacks invoked so far */ int nCallback; /* Number of callbacks invoked so far */
int cacheCtr; /* Cursor row cache generation counter */ int cacheCtr; /* VdbeCursor row cache generation counter */
Fifo sFifo; /* A list of ROWIDs */
int contextStackTop; /* Index of top element in the context stack */ int contextStackTop; /* Index of top element in the context stack */
int contextStackDepth; /* The size of the "context" stack */ int contextStackDepth; /* The size of the "context" stack */
Context *contextStack; /* Stack used by opcodes ContextPush & ContextPop*/ Context *contextStack; /* Stack used by opcodes ContextPush & ContextPop*/
@ -323,31 +289,36 @@ struct Vdbe {
unsigned uniqueCnt; /* Used by OP_MakeRecord when P2!=0 */ unsigned uniqueCnt; /* Used by OP_MakeRecord when P2!=0 */
int errorAction; /* Recovery action to do in case of an error */ int errorAction; /* Recovery action to do in case of an error */
int inTempTrans; /* True if temp database is transactioned */ int inTempTrans; /* True if temp database is transactioned */
int returnStack[100]; /* Return address stack for OP_Gosub & OP_Return */
int returnDepth; /* Next unused element in returnStack[] */
int nResColumn; /* Number of columns in one row of the result set */ int nResColumn; /* Number of columns in one row of the result set */
char **azResColumn; /* Values for one row of result */ char **azResColumn; /* Values for one row of result */
int popStack; /* Pop the stack this much on entry to VdbeExec() */
char *zErrMsg; /* Error message written here */ char *zErrMsg; /* Error message written here */
u8 resOnStack; /* True if there are result values on the stack */ Mem *pResultSet; /* Pointer to an array of results */
u8 explain; /* True if EXPLAIN present on SQL command */ u8 explain; /* True if EXPLAIN present on SQL command */
u8 changeCntOn; /* True to update the change-counter */ 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 expired; /* True if the VM needs to be recompiled */
u8 minWriteFileFormat; /* Minimum file format for writable database files */ u8 minWriteFileFormat; /* Minimum file format for writable database files */
u8 inVtabMethod; /* See comments above */ u8 inVtabMethod; /* See comments above */
u8 usesStmtJournal; /* True if uses a statement journal */
u8 readOnly; /* True for read-only statements */
int nChange; /* Number of db changes made since last reset */ int nChange; /* Number of db changes made since last reset */
i64 startTime; /* Time when query started - used for profiling */ i64 startTime; /* Time when query started - used for profiling */
int btreeMask; /* Bitmask of db->aDb[] entries referenced */
BtreeMutexArray aMutex; /* An array of Btree used here and needing locks */
int aCounter[2]; /* Counters used by sqlite3_stmt_status() */
int nSql; /* Number of bytes in zSql */ int nSql; /* Number of bytes in zSql */
char *zSql; /* Text of the SQL statement that generated this */ char *zSql; /* Text of the SQL statement that generated this */
#ifdef SQLITE_DEBUG #ifdef SQLITE_DEBUG
FILE *trace; /* Write an execution trace here, if not NULL */ FILE *trace; /* Write an execution trace here, if not NULL */
#endif #endif
int openedStatement; /* True if this VM has opened a statement journal */ int openedStatement; /* True if this VM has opened a statement journal */
#ifdef SQLITE_SSE #ifdef SQLITE_SSE
int fetchId; /* Statement number used by sqlite3_fetch_statement */ int fetchId; /* Statement number used by sqlite3_fetch_statement */
int lru; /* Counter used for LRU cache replacement */ int lru; /* Counter used for LRU cache replacement */
#endif #endif
#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
Vdbe *pLruPrev;
Vdbe *pLruNext;
#endif
}; };
/* /*
@ -361,9 +332,9 @@ struct Vdbe {
/* /*
** Function prototypes ** Function prototypes
*/ */
void sqlite3VdbeFreeCursor(Vdbe *, Cursor*); void sqlite3VdbeFreeCursor(Vdbe *, VdbeCursor*);
void sqliteVdbePopStack(Vdbe*,int); void sqliteVdbePopStack(Vdbe*,int);
int sqlite3VdbeCursorMoveto(Cursor*); int sqlite3VdbeCursorMoveto(VdbeCursor*);
#if defined(SQLITE_DEBUG) || defined(VDBE_PROFILE) #if defined(SQLITE_DEBUG) || defined(VDBE_PROFILE)
void sqlite3VdbePrintOp(FILE*, int, Op*); void sqlite3VdbePrintOp(FILE*, int, Op*);
#endif #endif
@ -374,11 +345,9 @@ int sqlite3VdbeSerialGet(const unsigned char*, u32, Mem*);
void sqlite3VdbeDeleteAuxData(VdbeFunc*, int); void sqlite3VdbeDeleteAuxData(VdbeFunc*, int);
int sqlite2BtreeKeyCompare(BtCursor *, const void *, int, int, int *); int sqlite2BtreeKeyCompare(BtCursor *, const void *, int, int, int *);
int sqlite3VdbeIdxKeyCompare(Cursor*, int , const unsigned char*, int*); int sqlite3VdbeIdxKeyCompare(VdbeCursor*,UnpackedRecord*,int*);
int sqlite3VdbeIdxRowid(BtCursor *, i64 *); int sqlite3VdbeIdxRowid(BtCursor *, i64 *);
int sqlite3MemCompare(const Mem*, const Mem*, const CollSeq*); int sqlite3MemCompare(const Mem*, const Mem*, const CollSeq*);
int sqlite3VdbeRecordCompare(void*,int,const void*,int, const void*);
int sqlite3VdbeIdxRowidLen(const u8*);
int sqlite3VdbeExec(Vdbe*); int sqlite3VdbeExec(Vdbe*);
int sqlite3VdbeList(Vdbe*); int sqlite3VdbeList(Vdbe*);
int sqlite3VdbeHalt(Vdbe*); int sqlite3VdbeHalt(Vdbe*);
@ -386,15 +355,15 @@ int sqlite3VdbeChangeEncoding(Mem *, int);
int sqlite3VdbeMemTooBig(Mem*); int sqlite3VdbeMemTooBig(Mem*);
int sqlite3VdbeMemCopy(Mem*, const Mem*); int sqlite3VdbeMemCopy(Mem*, const Mem*);
void sqlite3VdbeMemShallowCopy(Mem*, const Mem*, int); void sqlite3VdbeMemShallowCopy(Mem*, const Mem*, int);
int sqlite3VdbeMemMove(Mem*, Mem*); void sqlite3VdbeMemMove(Mem*, Mem*);
int sqlite3VdbeMemNulTerminate(Mem*); int sqlite3VdbeMemNulTerminate(Mem*);
int sqlite3VdbeMemSetStr(Mem*, const char*, int, u8, void(*)(void*)); int sqlite3VdbeMemSetStr(Mem*, const char*, int, u8, void(*)(void*));
void sqlite3VdbeMemSetInt64(Mem*, i64); void sqlite3VdbeMemSetInt64(Mem*, i64);
void sqlite3VdbeMemSetDouble(Mem*, double); void sqlite3VdbeMemSetDouble(Mem*, double);
void sqlite3VdbeMemSetNull(Mem*); void sqlite3VdbeMemSetNull(Mem*);
void sqlite3VdbeMemSetZeroBlob(Mem*,int); void sqlite3VdbeMemSetZeroBlob(Mem*,int);
void sqlite3VdbeMemSetRowSet(Mem*);
int sqlite3VdbeMemMakeWriteable(Mem*); int sqlite3VdbeMemMakeWriteable(Mem*);
int sqlite3VdbeMemDynamicify(Mem*);
int sqlite3VdbeMemStringify(Mem*, int); int sqlite3VdbeMemStringify(Mem*, int);
i64 sqlite3VdbeIntValue(Mem*); i64 sqlite3VdbeIntValue(Mem*);
int sqlite3VdbeMemIntegerify(Mem*); int sqlite3VdbeMemIntegerify(Mem*);
@ -404,10 +373,17 @@ int sqlite3VdbeMemRealify(Mem*);
int sqlite3VdbeMemNumerify(Mem*); int sqlite3VdbeMemNumerify(Mem*);
int sqlite3VdbeMemFromBtree(BtCursor*,int,int,int,Mem*); int sqlite3VdbeMemFromBtree(BtCursor*,int,int,int,Mem*);
void sqlite3VdbeMemRelease(Mem *p); void sqlite3VdbeMemRelease(Mem *p);
void sqlite3VdbeMemReleaseExternal(Mem *p);
int sqlite3VdbeMemFinalize(Mem*, FuncDef*); int sqlite3VdbeMemFinalize(Mem*, FuncDef*);
const char *sqlite3OpcodeName(int);
int sqlite3VdbeOpcodeHasProperty(int, int);
int sqlite3VdbeMemGrow(Mem *pMem, int n, int preserve);
#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
int sqlite3VdbeReleaseBuffers(Vdbe *p);
#endif
#ifndef NDEBUG #ifndef NDEBUG
void sqlite3VdbeMemSanity(Mem*); void sqlite3VdbeMemSanity(Mem*);
int sqlite3VdbeOpcodeNoPush(u8);
#endif #endif
int sqlite3VdbeMemTranslate(Mem*, u8); int sqlite3VdbeMemTranslate(Mem*, u8);
#ifdef SQLITE_DEBUG #ifdef SQLITE_DEBUG
@ -415,10 +391,6 @@ int sqlite3VdbeMemTranslate(Mem*, u8);
void sqlite3VdbeMemPrettyPrint(Mem *pMem, char *zBuf); void sqlite3VdbeMemPrettyPrint(Mem *pMem, char *zBuf);
#endif #endif
int sqlite3VdbeMemHandleBom(Mem *pMem); int sqlite3VdbeMemHandleBom(Mem *pMem);
void sqlite3VdbeFifoInit(Fifo*);
int sqlite3VdbeFifoPush(Fifo*, i64);
int sqlite3VdbeFifoPop(Fifo*, i64*);
void sqlite3VdbeFifoClear(Fifo*);
#ifndef SQLITE_OMIT_INCRBLOB #ifndef SQLITE_OMIT_INCRBLOB
int sqlite3VdbeMemExpandBlob(Mem *); int sqlite3VdbeMemExpandBlob(Mem *);

648
vdbeapi.c

File diff suppressed because it is too large Load diff

1529
vdbeaux.c

File diff suppressed because it is too large Load diff

View file

@ -12,7 +12,7 @@
** **
** This file contains code used to implement incremental BLOB I/O. ** This file contains code used to implement incremental BLOB I/O.
** **
** $Id: vdbeblob.c,v 1.11 2007/06/27 00:36:14 drh Exp $ ** $Id: vdbeblob.c,v 1.26 2008/10/02 14:49:02 danielk1977 Exp $
*/ */
#include "sqliteInt.h" #include "sqliteInt.h"
@ -30,6 +30,7 @@ struct Incrblob {
int iOffset; /* Byte offset of blob in cursor data */ int iOffset; /* Byte offset of blob in cursor data */
BtCursor *pCsr; /* Cursor pointing at blob row */ BtCursor *pCsr; /* Cursor pointing at blob row */
sqlite3_stmt *pStmt; /* Statement holding cursor open */ sqlite3_stmt *pStmt; /* Statement holding cursor open */
sqlite3 *db; /* The associated database */
}; };
/* /*
@ -53,7 +54,7 @@ int sqlite3_blob_open(
** vdbe program will take advantage of the various transaction, ** vdbe program will take advantage of the various transaction,
** locking and error handling infrastructure built into the vdbe. ** locking and error handling infrastructure built into the vdbe.
** **
** After seeking the cursor, the vdbe executes an OP_Callback. ** After seeking the cursor, the vdbe executes an OP_ResultRow.
** Code external to the Vdbe then "borrows" the b-tree cursor and ** Code external to the Vdbe then "borrows" the b-tree cursor and
** uses it to implement the blob_read(), blob_write() and ** uses it to implement the blob_read(), blob_write() and
** blob_bytes() functions. ** blob_bytes() functions.
@ -65,20 +66,20 @@ int sqlite3_blob_open(
static const VdbeOpList openBlob[] = { static const VdbeOpList openBlob[] = {
{OP_Transaction, 0, 0, 0}, /* 0: Start a transaction */ {OP_Transaction, 0, 0, 0}, /* 0: Start a transaction */
{OP_VerifyCookie, 0, 0, 0}, /* 1: Check the schema cookie */ {OP_VerifyCookie, 0, 0, 0}, /* 1: Check the schema cookie */
{OP_Integer, 0, 0, 0}, /* 2: Database number */
/* One of the following two instructions is replaced by an /* One of the following two instructions is replaced by an
** OP_Noop before exection. ** OP_Noop before exection.
*/ */
{OP_SetNumColumns, 0, 0, 0}, /* 2: Num cols for cursor */
{OP_OpenRead, 0, 0, 0}, /* 3: Open cursor 0 for reading */ {OP_OpenRead, 0, 0, 0}, /* 3: Open cursor 0 for reading */
{OP_OpenWrite, 0, 0, 0}, /* 4: Open cursor 0 for read/write */ {OP_SetNumColumns, 0, 0, 0}, /* 4: Num cols for cursor */
{OP_SetNumColumns, 0, 0, 0}, /* 5: Num cols for cursor */ {OP_OpenWrite, 0, 0, 0}, /* 5: Open cursor 0 for read/write */
{OP_Variable, 1, 0, 0}, /* 6: Push the rowid to the stack */ {OP_Variable, 1, 1, 0}, /* 6: Push the rowid to the stack */
{OP_NotExists, 0, 10, 0}, /* 7: Seek the cursor */ {OP_NotExists, 0, 10, 1}, /* 7: Seek the cursor */
{OP_Column, 0, 0, 0}, /* 8 */ {OP_Column, 0, 0, 1}, /* 8 */
{OP_Callback, 0, 0, 0}, /* 9 */ {OP_ResultRow, 1, 0, 0}, /* 9 */
{OP_Close, 0, 0, 0}, /* 10 */ {OP_Close, 0, 0, 0}, /* 10 */
{OP_Halt, 0, 0, 0}, /* 11 */ {OP_Halt, 0, 0, 0}, /* 11 */
}; };
@ -87,6 +88,7 @@ int sqlite3_blob_open(
char zErr[128]; char zErr[128];
zErr[0] = 0; zErr[0] = 0;
sqlite3_mutex_enter(db->mutex);
do { do {
Parse sParse; Parse sParse;
Table *pTab; Table *pTab;
@ -94,19 +96,31 @@ int sqlite3_blob_open(
memset(&sParse, 0, sizeof(Parse)); memset(&sParse, 0, sizeof(Parse));
sParse.db = db; sParse.db = db;
rc = sqlite3SafetyOn(db); if( sqlite3SafetyOn(db) ){
if( rc!=SQLITE_OK ){ sqlite3_mutex_leave(db->mutex);
return rc; return SQLITE_MISUSE;
} }
pTab = sqlite3LocateTable(&sParse, zTable, zDb); sqlite3BtreeEnterAll(db);
pTab = sqlite3LocateTable(&sParse, 0, zTable, zDb);
if( pTab && IsVirtual(pTab) ){
pTab = 0;
sqlite3ErrorMsg(&sParse, "cannot open virtual table: %s", zTable);
}
#ifndef SQLITE_OMIT_VIEW
if( pTab && pTab->pSelect ){
pTab = 0;
sqlite3ErrorMsg(&sParse, "cannot open view: %s", zTable);
}
#endif
if( !pTab ){ if( !pTab ){
if( sParse.zErrMsg ){ if( sParse.zErrMsg ){
sqlite3_snprintf(sizeof(zErr), zErr, "%s", sParse.zErrMsg); sqlite3_snprintf(sizeof(zErr), zErr, "%s", sParse.zErrMsg);
} }
sqliteFree(sParse.zErrMsg); sqlite3DbFree(db, sParse.zErrMsg);
rc = SQLITE_ERROR; rc = SQLITE_ERROR;
sqlite3SafetyOff(db); (void)sqlite3SafetyOff(db);
sqlite3BtreeLeaveAll(db);
goto blob_open_out; goto blob_open_out;
} }
@ -119,7 +133,8 @@ int sqlite3_blob_open(
if( iCol==pTab->nCol ){ if( iCol==pTab->nCol ){
sqlite3_snprintf(sizeof(zErr), zErr, "no such column: \"%s\"", zColumn); sqlite3_snprintf(sizeof(zErr), zErr, "no such column: \"%s\"", zColumn);
rc = SQLITE_ERROR; rc = SQLITE_ERROR;
sqlite3SafetyOff(db); (void)sqlite3SafetyOff(db);
sqlite3BtreeLeaveAll(db);
goto blob_open_out; goto blob_open_out;
} }
@ -136,7 +151,8 @@ int sqlite3_blob_open(
sqlite3_snprintf(sizeof(zErr), zErr, sqlite3_snprintf(sizeof(zErr), zErr,
"cannot open indexed column for writing"); "cannot open indexed column for writing");
rc = SQLITE_ERROR; rc = SQLITE_ERROR;
sqlite3SafetyOff(db); (void)sqlite3SafetyOff(db);
sqlite3BtreeLeaveAll(db);
goto blob_open_out; goto blob_open_out;
} }
} }
@ -156,14 +172,15 @@ int sqlite3_blob_open(
sqlite3VdbeChangeP1(v, 1, iDb); sqlite3VdbeChangeP1(v, 1, iDb);
sqlite3VdbeChangeP2(v, 1, pTab->pSchema->schema_cookie); sqlite3VdbeChangeP2(v, 1, pTab->pSchema->schema_cookie);
/* Configure the db number pushed onto the stack */ /* Make sure a mutex is held on the table to be accessed */
sqlite3VdbeChangeP1(v, 2, iDb); sqlite3VdbeUsesBtree(v, iDb);
/* Remove either the OP_OpenWrite or OpenRead. Set the P2 /* Remove either the OP_OpenWrite or OpenRead. Set the P2
** parameter of the other to pTab->tnum. ** parameter of the other to pTab->tnum.
*/ */
sqlite3VdbeChangeToNoop(v, (flags ? 3 : 4), 1); sqlite3VdbeChangeToNoop(v, (flags ? 3 : 5), 1);
sqlite3VdbeChangeP2(v, (flags ? 4 : 3), pTab->tnum); sqlite3VdbeChangeP2(v, (flags ? 5 : 3), pTab->tnum);
sqlite3VdbeChangeP3(v, (flags ? 5 : 3), iDb);
/* Configure the OP_SetNumColumns. Configure the cursor to /* Configure the OP_SetNumColumns. Configure the cursor to
** think that the table has one more column than it really ** think that the table has one more column than it really
@ -172,14 +189,16 @@ int sqlite3_blob_open(
** we can invoke OP_Column to fill in the vdbe cursors type ** we can invoke OP_Column to fill in the vdbe cursors type
** and offset cache without causing any IO. ** and offset cache without causing any IO.
*/ */
sqlite3VdbeChangeP2(v, 5, pTab->nCol+1); sqlite3VdbeChangeP2(v, flags ? 4 : 2, pTab->nCol+1);
if( !sqlite3MallocFailed() ){ sqlite3VdbeChangeP2(v, 8, pTab->nCol);
sqlite3VdbeMakeReady(v, 1, 0, 1, 0); if( !db->mallocFailed ){
sqlite3VdbeMakeReady(v, 1, 1, 1, 0);
} }
} }
sqlite3BtreeLeaveAll(db);
rc = sqlite3SafetyOff(db); rc = sqlite3SafetyOff(db);
if( rc!=SQLITE_OK || sqlite3MallocFailed() ){ if( rc!=SQLITE_OK || db->mallocFailed ){
goto blob_open_out; goto blob_open_out;
} }
@ -208,17 +227,20 @@ int sqlite3_blob_open(
rc = SQLITE_ERROR; rc = SQLITE_ERROR;
goto blob_open_out; goto blob_open_out;
} }
pBlob = (Incrblob *)sqliteMalloc(sizeof(Incrblob)); pBlob = (Incrblob *)sqlite3DbMallocZero(db, sizeof(Incrblob));
if( sqlite3MallocFailed() ){ if( db->mallocFailed ){
sqliteFree(pBlob); sqlite3DbFree(db, pBlob);
goto blob_open_out; goto blob_open_out;
} }
pBlob->flags = flags; pBlob->flags = flags;
pBlob->pCsr = v->apCsr[0]->pCursor; pBlob->pCsr = v->apCsr[0]->pCursor;
sqlite3BtreeEnterCursor(pBlob->pCsr);
sqlite3BtreeCacheOverflow(pBlob->pCsr); sqlite3BtreeCacheOverflow(pBlob->pCsr);
sqlite3BtreeLeaveCursor(pBlob->pCsr);
pBlob->pStmt = (sqlite3_stmt *)v; pBlob->pStmt = (sqlite3_stmt *)v;
pBlob->iOffset = v->apCsr[0]->aOffset[iCol]; pBlob->iOffset = v->apCsr[0]->aOffset[iCol];
pBlob->nByte = sqlite3VdbeSerialTypeLen(type); pBlob->nByte = sqlite3VdbeSerialTypeLen(type);
pBlob->db = db;
*ppBlob = (sqlite3_blob *)pBlob; *ppBlob = (sqlite3_blob *)pBlob;
rc = SQLITE_OK; rc = SQLITE_OK;
}else if( rc==SQLITE_OK ){ }else if( rc==SQLITE_OK ){
@ -228,11 +250,13 @@ int sqlite3_blob_open(
blob_open_out: blob_open_out:
zErr[sizeof(zErr)-1] = '\0'; zErr[sizeof(zErr)-1] = '\0';
if( rc!=SQLITE_OK || sqlite3MallocFailed() ){ if( rc!=SQLITE_OK || db->mallocFailed ){
sqlite3_finalize((sqlite3_stmt *)v); sqlite3_finalize((sqlite3_stmt *)v);
} }
sqlite3Error(db, rc, (rc==SQLITE_OK?0:zErr)); sqlite3Error(db, rc, (rc==SQLITE_OK?0:zErr));
return sqlite3ApiExit(db, rc); rc = sqlite3ApiExit(db, rc);
sqlite3_mutex_leave(db->mutex);
return rc;
} }
/* /*
@ -241,12 +265,16 @@ blob_open_out:
*/ */
int sqlite3_blob_close(sqlite3_blob *pBlob){ int sqlite3_blob_close(sqlite3_blob *pBlob){
Incrblob *p = (Incrblob *)pBlob; Incrblob *p = (Incrblob *)pBlob;
sqlite3_stmt *pStmt = p->pStmt; int rc;
sqliteFree(p);
return sqlite3_finalize(pStmt); rc = sqlite3_finalize(p->pStmt);
sqlite3DbFree(p->db, p);
return rc;
} }
/*
** Perform a read or write operation on a blob
*/
static int blobReadWrite( static int blobReadWrite(
sqlite3_blob *pBlob, sqlite3_blob *pBlob,
void *z, void *z,
@ -256,33 +284,40 @@ static int blobReadWrite(
){ ){
int rc; int rc;
Incrblob *p = (Incrblob *)pBlob; Incrblob *p = (Incrblob *)pBlob;
Vdbe *v = (Vdbe *)(p->pStmt); Vdbe *v;
sqlite3 *db; sqlite3 *db = p->db;
/* If there is no statement handle, then the blob-handle has sqlite3_mutex_enter(db->mutex);
** already been invalidated. Return SQLITE_ABORT in this case. v = (Vdbe*)p->pStmt;
*/
if( !v ) return SQLITE_ABORT;
/* Request is out of range. Return a transient error. */ if( n<0 || iOffset<0 || (iOffset+n)>p->nByte ){
if( (iOffset+n)>p->nByte ){ /* Request is out of range. Return a transient error. */
return SQLITE_ERROR; rc = SQLITE_ERROR;
} sqlite3Error(db, SQLITE_ERROR, 0);
} else if( v==0 ){
/* Call either BtreeData() or BtreePutData(). If SQLITE_ABORT is /* If there is no statement handle, then the blob-handle has
** returned, clean-up the statement handle. ** already been invalidated. Return SQLITE_ABORT in this case.
*/ */
db = v->db; rc = SQLITE_ABORT;
rc = xCall(p->pCsr, iOffset+p->iOffset, n, z);
if( rc==SQLITE_ABORT ){
sqlite3VdbeFinalize(v);
p->pStmt = 0;
}else{ }else{
db->errCode = rc; /* Call either BtreeData() or BtreePutData(). If SQLITE_ABORT is
v->rc = rc; ** returned, clean-up the statement handle.
*/
assert( db == v->db );
sqlite3BtreeEnterCursor(p->pCsr);
rc = xCall(p->pCsr, iOffset+p->iOffset, n, z);
sqlite3BtreeLeaveCursor(p->pCsr);
if( rc==SQLITE_ABORT ){
sqlite3VdbeFinalize(v);
p->pStmt = 0;
}else{
db->errCode = rc;
v->rc = rc;
}
} }
rc = sqlite3ApiExit(db, rc);
return sqlite3ApiExit(db, rc); sqlite3_mutex_leave(db->mutex);
return rc;
} }
/* /*
@ -301,6 +336,9 @@ int sqlite3_blob_write(sqlite3_blob *pBlob, const void *z, int n, int iOffset){
/* /*
** Query a blob handle for the size of the data. ** Query a blob handle for the size of the data.
**
** The Incrblob.nByte field is fixed for the lifetime of the Incrblob
** so no mutex is required for access.
*/ */
int sqlite3_blob_bytes(sqlite3_blob *pBlob){ int sqlite3_blob_bytes(sqlite3_blob *pBlob){
Incrblob *p = (Incrblob *)pBlob; Incrblob *p = (Incrblob *)pBlob;

View file

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

691
vdbemem.c

File diff suppressed because it is too large Load diff

250
vtab.c
View file

@ -11,7 +11,7 @@
************************************************************************* *************************************************************************
** This file contains code used to help implement virtual tables. ** This file contains code used to help implement virtual tables.
** **
** $Id: vtab.c,v 1.48 2007/06/26 10:38:55 danielk1977 Exp $ ** $Id: vtab.c,v 1.81 2008/12/10 19:26:24 drh Exp $
*/ */
#ifndef SQLITE_OMIT_VIRTUALTABLE #ifndef SQLITE_OMIT_VIRTUALTABLE
#include "sqliteInt.h" #include "sqliteInt.h"
@ -23,23 +23,35 @@ static int createModule(
void *pAux, /* Context pointer for xCreate/xConnect */ void *pAux, /* Context pointer for xCreate/xConnect */
void (*xDestroy)(void *) /* Module destructor function */ void (*xDestroy)(void *) /* Module destructor function */
) { ) {
int nName = strlen(zName); int rc, nName;
Module *pMod = (Module *)sqliteMallocRaw(sizeof(Module) + nName + 1); Module *pMod;
sqlite3_mutex_enter(db->mutex);
nName = sqlite3Strlen30(zName);
pMod = (Module *)sqlite3DbMallocRaw(db, sizeof(Module) + nName + 1);
if( pMod ){ if( pMod ){
Module *pDel;
char *zCopy = (char *)(&pMod[1]); char *zCopy = (char *)(&pMod[1]);
memcpy(zCopy, zName, nName+1); memcpy(zCopy, zName, nName+1);
pMod->zName = zCopy; pMod->zName = zCopy;
pMod->pModule = pModule; pMod->pModule = pModule;
pMod->pAux = pAux; pMod->pAux = pAux;
pMod->xDestroy = xDestroy; pMod->xDestroy = xDestroy;
pMod = (Module *)sqlite3HashInsert(&db->aModule, zCopy, nName, (void*)pMod); pDel = (Module *)sqlite3HashInsert(&db->aModule, zCopy, nName, (void*)pMod);
if( pMod && pMod->xDestroy ){ if( pDel && pDel->xDestroy ){
pMod->xDestroy(pMod->pAux); pDel->xDestroy(pDel->pAux);
}
sqlite3DbFree(db, pDel);
if( pDel==pMod ){
db->mallocFailed = 1;
} }
sqliteFree(pMod);
sqlite3ResetInternalSchema(db, 0); sqlite3ResetInternalSchema(db, 0);
}else if( xDestroy ){
xDestroy(pAux);
} }
return sqlite3ApiExit(db, SQLITE_OK); rc = sqlite3ApiExit(db, SQLITE_OK);
sqlite3_mutex_leave(db->mutex);
return rc;
} }
@ -87,12 +99,12 @@ void sqlite3VtabLock(sqlite3_vtab *pVtab){
void sqlite3VtabUnlock(sqlite3 *db, sqlite3_vtab *pVtab){ void sqlite3VtabUnlock(sqlite3 *db, sqlite3_vtab *pVtab){
pVtab->nRef--; pVtab->nRef--;
assert(db); assert(db);
assert(!sqlite3SafetyCheck(db)); assert( sqlite3SafetyCheckOk(db) );
if( pVtab->nRef==0 ){ if( pVtab->nRef==0 ){
if( db->magic==SQLITE_MAGIC_BUSY ){ if( db->magic==SQLITE_MAGIC_BUSY ){
sqlite3SafetyOff(db); (void)sqlite3SafetyOff(db);
pVtab->pModule->xDisconnect(pVtab); pVtab->pModule->xDisconnect(pVtab);
sqlite3SafetyOn(db); (void)sqlite3SafetyOn(db);
} else { } else {
pVtab->pModule->xDisconnect(pVtab); pVtab->pModule->xDisconnect(pVtab);
} }
@ -106,17 +118,18 @@ void sqlite3VtabUnlock(sqlite3 *db, sqlite3_vtab *pVtab){
*/ */
void sqlite3VtabClear(Table *p){ void sqlite3VtabClear(Table *p){
sqlite3_vtab *pVtab = p->pVtab; sqlite3_vtab *pVtab = p->pVtab;
sqlite3 *db = p->db;
if( pVtab ){ if( pVtab ){
assert( p->pMod && p->pMod->pModule ); assert( p->pMod && p->pMod->pModule );
sqlite3VtabUnlock(p->pSchema->db, pVtab); sqlite3VtabUnlock(db, pVtab);
p->pVtab = 0; p->pVtab = 0;
} }
if( p->azModuleArg ){ if( p->azModuleArg ){
int i; int i;
for(i=0; i<p->nModuleArg; i++){ for(i=0; i<p->nModuleArg; i++){
sqliteFree(p->azModuleArg[i]); sqlite3DbFree(db, p->azModuleArg[i]);
} }
sqliteFree(p->azModuleArg); sqlite3DbFree(db, p->azModuleArg);
} }
} }
@ -126,18 +139,18 @@ void sqlite3VtabClear(Table *p){
** string will be freed automatically when the table is ** string will be freed automatically when the table is
** deleted. ** deleted.
*/ */
static void addModuleArgument(Table *pTable, char *zArg){ static void addModuleArgument(sqlite3 *db, Table *pTable, char *zArg){
int i = pTable->nModuleArg++; int i = pTable->nModuleArg++;
int nBytes = sizeof(char *)*(1+pTable->nModuleArg); int nBytes = sizeof(char *)*(1+pTable->nModuleArg);
char **azModuleArg; char **azModuleArg;
azModuleArg = sqliteRealloc(pTable->azModuleArg, nBytes); azModuleArg = sqlite3DbRealloc(db, pTable->azModuleArg, nBytes);
if( azModuleArg==0 ){ if( azModuleArg==0 ){
int j; int j;
for(j=0; j<i; j++){ for(j=0; j<i; j++){
sqliteFree(pTable->azModuleArg[j]); sqlite3DbFree(db, pTable->azModuleArg[j]);
} }
sqliteFree(zArg); sqlite3DbFree(db, zArg);
sqliteFree(pTable->azModuleArg); sqlite3DbFree(db, pTable->azModuleArg);
pTable->nModuleArg = 0; pTable->nModuleArg = 0;
}else{ }else{
azModuleArg[i] = zArg; azModuleArg[i] = zArg;
@ -159,28 +172,28 @@ void sqlite3VtabBeginParse(
){ ){
int iDb; /* The database the table is being created in */ int iDb; /* The database the table is being created in */
Table *pTable; /* The new virtual table */ Table *pTable; /* The new virtual table */
sqlite3 *db; /* Database connection */
#ifndef SQLITE_OMIT_SHARED_CACHE if( pParse->db->flags & SQLITE_SharedCache ){
if( sqlite3ThreadDataReadOnly()->useSharedData ){
sqlite3ErrorMsg(pParse, "Cannot use virtual tables in shared-cache mode"); sqlite3ErrorMsg(pParse, "Cannot use virtual tables in shared-cache mode");
return; return;
} }
#endif
sqlite3StartTable(pParse, pName1, pName2, 0, 0, 1, 0); sqlite3StartTable(pParse, pName1, pName2, 0, 0, 1, 0);
pTable = pParse->pNewTable; pTable = pParse->pNewTable;
if( pTable==0 || pParse->nErr ) return; if( pTable==0 || pParse->nErr ) return;
assert( 0==pTable->pIndex ); assert( 0==pTable->pIndex );
iDb = sqlite3SchemaToIndex(pParse->db, pTable->pSchema); db = pParse->db;
iDb = sqlite3SchemaToIndex(db, pTable->pSchema);
assert( iDb>=0 ); assert( iDb>=0 );
pTable->isVirtual = 1; pTable->tabFlags |= TF_Virtual;
pTable->nModuleArg = 0; pTable->nModuleArg = 0;
addModuleArgument(pTable, sqlite3NameFromToken(pModuleName)); addModuleArgument(db, pTable, sqlite3NameFromToken(db, pModuleName));
addModuleArgument(pTable, sqlite3StrDup(pParse->db->aDb[iDb].zName)); addModuleArgument(db, pTable, sqlite3DbStrDup(db, db->aDb[iDb].zName));
addModuleArgument(pTable, sqlite3StrDup(pTable->zName)); addModuleArgument(db, pTable, sqlite3DbStrDup(db, pTable->zName));
pParse->sNameToken.n = pModuleName->z + pModuleName->n - pName1->z; pParse->sNameToken.n = (int)(&pModuleName->z[pModuleName->n] - pName1->z);
#ifndef SQLITE_OMIT_AUTHORIZATION #ifndef SQLITE_OMIT_AUTHORIZATION
/* Creating a virtual table invokes the authorization callback twice. /* Creating a virtual table invokes the authorization callback twice.
@ -204,7 +217,8 @@ static void addArgumentToVtab(Parse *pParse){
if( pParse->sArg.z && pParse->pNewTable ){ if( pParse->sArg.z && pParse->pNewTable ){
const char *z = (const char*)pParse->sArg.z; const char *z = (const char*)pParse->sArg.z;
int n = pParse->sArg.n; int n = pParse->sArg.n;
addModuleArgument(pParse->pNewTable, sqliteStrNDup(z, n)); sqlite3 *db = pParse->db;
addModuleArgument(db, pParse->pNewTable, sqlite3DbStrNDup(db, z, n));
} }
} }
@ -227,7 +241,8 @@ void sqlite3VtabFinishParse(Parse *pParse, Token *pEnd){
db = pParse->db; db = pParse->db;
if( pTab->nModuleArg<1 ) return; if( pTab->nModuleArg<1 ) return;
zModule = pTab->azModuleArg[0]; zModule = pTab->azModuleArg[0];
pMod = (Module *)sqlite3HashFind(&db->aModule, zModule, strlen(zModule)); pMod = (Module*)sqlite3HashFind(&db->aModule, zModule,
sqlite3Strlen30(zModule));
pTab->pMod = pMod; pTab->pMod = pMod;
/* If the CREATE VIRTUAL TABLE statement is being entered for the /* If the CREATE VIRTUAL TABLE statement is being entered for the
@ -244,37 +259,38 @@ void sqlite3VtabFinishParse(Parse *pParse, Token *pEnd){
/* Compute the complete text of the CREATE VIRTUAL TABLE statement */ /* Compute the complete text of the CREATE VIRTUAL TABLE statement */
if( pEnd ){ if( pEnd ){
pParse->sNameToken.n = pEnd->z - pParse->sNameToken.z + pEnd->n; pParse->sNameToken.n = (int)(pEnd->z - pParse->sNameToken.z) + pEnd->n;
} }
zStmt = sqlite3MPrintf("CREATE VIRTUAL TABLE %T", &pParse->sNameToken); zStmt = sqlite3MPrintf(db, "CREATE VIRTUAL TABLE %T", &pParse->sNameToken);
/* A slot for the record has already been allocated in the /* A slot for the record has already been allocated in the
** SQLITE_MASTER table. We just need to update that slot with all ** SQLITE_MASTER table. We just need to update that slot with all
** the information we've collected. ** the information we've collected.
** **
** The top of the stack is the rootpage allocated by sqlite3StartTable(). ** The VM register number pParse->regRowid holds the rowid of an
** This value is always 0 and is ignored, a virtual table does not have a ** entry in the sqlite_master table tht was created for this vtab
** rootpage. The next entry on the stack is the rowid of the record ** by sqlite3StartTable().
** in the sqlite_master table.
*/ */
iDb = sqlite3SchemaToIndex(db, pTab->pSchema); iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
sqlite3NestedParse(pParse, sqlite3NestedParse(pParse,
"UPDATE %Q.%s " "UPDATE %Q.%s "
"SET type='table', name=%Q, tbl_name=%Q, rootpage=0, sql=%Q " "SET type='table', name=%Q, tbl_name=%Q, rootpage=0, sql=%Q "
"WHERE rowid=#1", "WHERE rowid=#%d",
db->aDb[iDb].zName, SCHEMA_TABLE(iDb), db->aDb[iDb].zName, SCHEMA_TABLE(iDb),
pTab->zName, pTab->zName,
pTab->zName, pTab->zName,
zStmt zStmt,
pParse->regRowid
); );
sqliteFree(zStmt); sqlite3DbFree(db, zStmt);
v = sqlite3GetVdbe(pParse); v = sqlite3GetVdbe(pParse);
sqlite3ChangeCookie(db, v, iDb); sqlite3ChangeCookie(pParse, iDb);
sqlite3VdbeAddOp(v, OP_Expire, 0, 0); sqlite3VdbeAddOp2(v, OP_Expire, 0, 0);
zWhere = sqlite3MPrintf("name='%q'", pTab->zName); zWhere = sqlite3MPrintf(db, "name='%q'", pTab->zName);
sqlite3VdbeOp3(v, OP_ParseSchema, iDb, 1, zWhere, P3_DYNAMIC); sqlite3VdbeAddOp4(v, OP_ParseSchema, iDb, 1, 0, zWhere, P4_DYNAMIC);
sqlite3VdbeOp3(v, OP_VCreate, iDb, 0, pTab->zName, strlen(pTab->zName) + 1); sqlite3VdbeAddOp4(v, OP_VCreate, iDb, 0, 0,
pTab->zName, sqlite3Strlen30(pTab->zName) + 1);
} }
/* If we are rereading the sqlite_master table create the in-memory /* If we are rereading the sqlite_master table create the in-memory
@ -285,9 +301,10 @@ void sqlite3VtabFinishParse(Parse *pParse, Token *pEnd){
Table *pOld; Table *pOld;
Schema *pSchema = pTab->pSchema; Schema *pSchema = pTab->pSchema;
const char *zName = pTab->zName; const char *zName = pTab->zName;
int nName = strlen(zName) + 1; int nName = sqlite3Strlen30(zName) + 1;
pOld = sqlite3HashInsert(&pSchema->tblHash, zName, nName, pTab); pOld = sqlite3HashInsert(&pSchema->tblHash, zName, nName, pTab);
if( pOld ){ if( pOld ){
db->mallocFailed = 1;
assert( pTab==pOld ); /* Malloc must have failed inside HashInsert() */ assert( pTab==pOld ); /* Malloc must have failed inside HashInsert() */
return; return;
} }
@ -317,7 +334,7 @@ void sqlite3VtabArgExtend(Parse *pParse, Token *p){
pArg->n = p->n; pArg->n = p->n;
}else{ }else{
assert(pArg->z < p->z); assert(pArg->z < p->z);
pArg->n = (p->z + p->n - pArg->z); pArg->n = (int)(&p->z[p->n] - pArg->z);
} }
} }
@ -335,11 +352,11 @@ static int vtabCallConstructor(
){ ){
int rc; int rc;
int rc2; int rc2;
sqlite3_vtab *pVtab; sqlite3_vtab *pVtab = 0;
const char *const*azArg = (const char *const*)pTab->azModuleArg; const char *const*azArg = (const char *const*)pTab->azModuleArg;
int nArg = pTab->nModuleArg; int nArg = pTab->nModuleArg;
char *zErr = 0; char *zErr = 0;
char *zModuleName = sqlite3MPrintf("%s", pTab->zName); char *zModuleName = sqlite3MPrintf(db, "%s", pTab->zName);
if( !zModuleName ){ if( !zModuleName ){
return SQLITE_NOMEM; return SQLITE_NOMEM;
@ -351,31 +368,31 @@ static int vtabCallConstructor(
db->pVTab = pTab; db->pVTab = pTab;
rc = sqlite3SafetyOff(db); rc = sqlite3SafetyOff(db);
assert( rc==SQLITE_OK ); assert( rc==SQLITE_OK );
rc = xConstruct(db, pMod->pAux, nArg, azArg, &pTab->pVtab, &zErr); rc = xConstruct(db, pMod->pAux, nArg, azArg, &pVtab, &zErr);
rc2 = sqlite3SafetyOn(db); rc2 = sqlite3SafetyOn(db);
pVtab = pTab->pVtab;
if( rc==SQLITE_OK && pVtab ){ if( rc==SQLITE_OK && pVtab ){
pVtab->pModule = pMod->pModule; pVtab->pModule = pMod->pModule;
pVtab->nRef = 1; pVtab->nRef = 1;
pTab->pVtab = pVtab;
} }
if( SQLITE_OK!=rc ){ if( SQLITE_OK!=rc ){
if( zErr==0 ){ if( zErr==0 ){
*pzErr = sqlite3MPrintf("vtable constructor failed: %s", zModuleName); *pzErr = sqlite3MPrintf(db, "vtable constructor failed: %s", zModuleName);
}else { }else {
*pzErr = sqlite3MPrintf("%s", zErr); *pzErr = sqlite3MPrintf(db, "%s", zErr);
sqlite3_free(zErr); sqlite3DbFree(db, zErr);
} }
}else if( db->pVTab ){ }else if( db->pVTab ){
const char *zFormat = "vtable constructor did not declare schema: %s"; const char *zFormat = "vtable constructor did not declare schema: %s";
*pzErr = sqlite3MPrintf(zFormat, pTab->zName); *pzErr = sqlite3MPrintf(db, zFormat, pTab->zName);
rc = SQLITE_ERROR; rc = SQLITE_ERROR;
} }
if( rc==SQLITE_OK ){ if( rc==SQLITE_OK ){
rc = rc2; rc = rc2;
} }
db->pVTab = 0; db->pVTab = 0;
sqliteFree(zModuleName); sqlite3DbFree(db, zModuleName);
/* If everything went according to plan, loop through the columns /* If everything went according to plan, loop through the columns
** of the table to see if any of them contain the token "hidden". ** of the table to see if any of them contain the token "hidden".
@ -389,7 +406,7 @@ static int vtabCallConstructor(
int nType; int nType;
int i = 0; int i = 0;
if( !zType ) continue; if( !zType ) continue;
nType = strlen(zType); nType = sqlite3Strlen30(zType);
if( sqlite3StrNICmp("hidden", zType, 6) || (zType[6] && zType[6]!=' ') ){ if( sqlite3StrNICmp("hidden", zType, 6) || (zType[6] && zType[6]!=' ') ){
for(i=0; i<nType; i++){ for(i=0; i<nType; i++){
if( (0==sqlite3StrNICmp(" hidden", &zType[i], 7)) if( (0==sqlite3StrNICmp(" hidden", &zType[i], 7))
@ -428,7 +445,7 @@ int sqlite3VtabCallConnect(Parse *pParse, Table *pTab){
Module *pMod; Module *pMod;
int rc = SQLITE_OK; int rc = SQLITE_OK;
if( !pTab || !pTab->isVirtual || pTab->pVtab ){ if( !pTab || (pTab->tabFlags & TF_Virtual)==0 || pTab->pVtab ){
return SQLITE_OK; return SQLITE_OK;
} }
@ -444,7 +461,7 @@ int sqlite3VtabCallConnect(Parse *pParse, Table *pTab){
if( rc!=SQLITE_OK ){ if( rc!=SQLITE_OK ){
sqlite3ErrorMsg(pParse, "%s", zErr); sqlite3ErrorMsg(pParse, "%s", zErr);
} }
sqliteFree(zErr); sqlite3DbFree(db, zErr);
} }
return rc; return rc;
@ -460,7 +477,7 @@ static int addToVTrans(sqlite3 *db, sqlite3_vtab *pVtab){
if( (db->nVTrans%ARRAY_INCR)==0 ){ if( (db->nVTrans%ARRAY_INCR)==0 ){
sqlite3_vtab **aVTrans; sqlite3_vtab **aVTrans;
int nBytes = sizeof(sqlite3_vtab *) * (db->nVTrans + ARRAY_INCR); int nBytes = sizeof(sqlite3_vtab *) * (db->nVTrans + ARRAY_INCR);
aVTrans = sqliteRealloc((void *)db->aVTrans, nBytes); aVTrans = sqlite3DbRealloc(db, (void *)db->aVTrans, nBytes);
if( !aVTrans ){ if( !aVTrans ){
return SQLITE_NOMEM; return SQLITE_NOMEM;
} }
@ -480,7 +497,7 @@ static int addToVTrans(sqlite3 *db, sqlite3_vtab *pVtab){
** **
** If an error occurs, *pzErr is set to point an an English language ** If an error occurs, *pzErr is set to point an an English language
** description of the error and an SQLITE_XXX error code is returned. ** description of the error and an SQLITE_XXX error code is returned.
** In this case the caller must call sqliteFree() on *pzErr. ** In this case the caller must call sqlite3DbFree(db, ) on *pzErr.
*/ */
int sqlite3VtabCallCreate(sqlite3 *db, int iDb, const char *zTab, char **pzErr){ int sqlite3VtabCallCreate(sqlite3 *db, int iDb, const char *zTab, char **pzErr){
int rc = SQLITE_OK; int rc = SQLITE_OK;
@ -489,7 +506,7 @@ int sqlite3VtabCallCreate(sqlite3 *db, int iDb, const char *zTab, char **pzErr){
const char *zModule; const char *zModule;
pTab = sqlite3FindTable(db, zTab, db->aDb[iDb].zName); pTab = sqlite3FindTable(db, zTab, db->aDb[iDb].zName);
assert(pTab && pTab->isVirtual && !pTab->pVtab); assert(pTab && (pTab->tabFlags & TF_Virtual)!=0 && !pTab->pVtab);
pMod = pTab->pMod; pMod = pTab->pMod;
zModule = pTab->azModuleArg[0]; zModule = pTab->azModuleArg[0];
@ -498,7 +515,7 @@ int sqlite3VtabCallCreate(sqlite3 *db, int iDb, const char *zTab, char **pzErr){
** error. Otherwise, do nothing. ** error. Otherwise, do nothing.
*/ */
if( !pMod ){ if( !pMod ){
*pzErr = sqlite3MPrintf("no such module: %s", zModule); *pzErr = sqlite3MPrintf(db, "no such module: %s", zModule);
rc = SQLITE_ERROR; rc = SQLITE_ERROR;
}else{ }else{
rc = vtabCallConstructor(db, pTab, pMod, pMod->pModule->xCreate, pzErr); rc = vtabCallConstructor(db, pTab, pMod, pMod->pModule->xCreate, pzErr);
@ -520,14 +537,17 @@ int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){
Parse sParse; Parse sParse;
int rc = SQLITE_OK; int rc = SQLITE_OK;
Table *pTab = db->pVTab; Table *pTab;
char *zErr = 0; char *zErr = 0;
sqlite3_mutex_enter(db->mutex);
pTab = db->pVTab;
if( !pTab ){ if( !pTab ){
sqlite3Error(db, SQLITE_MISUSE, 0); sqlite3Error(db, SQLITE_MISUSE, 0);
sqlite3_mutex_leave(db->mutex);
return SQLITE_MISUSE; return SQLITE_MISUSE;
} }
assert(pTab->isVirtual && pTab->nCol==0 && pTab->aCol==0); assert((pTab->tabFlags & TF_Virtual)!=0 && pTab->nCol==0 && pTab->aCol==0);
memset(&sParse, 0, sizeof(Parse)); memset(&sParse, 0, sizeof(Parse));
sParse.declareVtab = 1; sParse.declareVtab = 1;
@ -537,7 +557,7 @@ int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){
SQLITE_OK == sqlite3RunParser(&sParse, zCreateTable, &zErr) && SQLITE_OK == sqlite3RunParser(&sParse, zCreateTable, &zErr) &&
sParse.pNewTable && sParse.pNewTable &&
!sParse.pNewTable->pSelect && !sParse.pNewTable->pSelect &&
!sParse.pNewTable->isVirtual (sParse.pNewTable->tabFlags & TF_Virtual)==0
){ ){
pTab->aCol = sParse.pNewTable->aCol; pTab->aCol = sParse.pNewTable->aCol;
pTab->nCol = sParse.pNewTable->nCol; pTab->nCol = sParse.pNewTable->nCol;
@ -546,7 +566,7 @@ int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){
db->pVTab = 0; db->pVTab = 0;
} else { } else {
sqlite3Error(db, SQLITE_ERROR, zErr); sqlite3Error(db, SQLITE_ERROR, zErr);
sqliteFree(zErr); sqlite3DbFree(db, zErr);
rc = SQLITE_ERROR; rc = SQLITE_ERROR;
} }
sParse.declareVtab = 0; sParse.declareVtab = 0;
@ -556,7 +576,9 @@ int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){
sParse.pNewTable = 0; sParse.pNewTable = 0;
assert( (rc&0xff)==rc ); assert( (rc&0xff)==rc );
return sqlite3ApiExit(db, rc); rc = sqlite3ApiExit(db, rc);
sqlite3_mutex_leave(db->mutex);
return rc;
} }
/* /*
@ -580,8 +602,15 @@ int sqlite3VtabCallDestroy(sqlite3 *db, int iDb, const char *zTab)
if( xDestroy ){ if( xDestroy ){
rc = xDestroy(pTab->pVtab); rc = xDestroy(pTab->pVtab);
} }
sqlite3SafetyOn(db); (void)sqlite3SafetyOn(db);
if( rc==SQLITE_OK ){ if( rc==SQLITE_OK ){
int i;
for(i=0; i<db->nVTrans; i++){
if( db->aVTrans[i]==pTab->pVtab ){
db->aVTrans[i] = db->aVTrans[--db->nVTrans];
break;
}
}
pTab->pVtab = 0; pTab->pVtab = 0;
} }
} }
@ -607,24 +636,25 @@ static void callFinaliser(sqlite3 *db, int offset){
if( x ) x(pVtab); if( x ) x(pVtab);
sqlite3VtabUnlock(db, pVtab); sqlite3VtabUnlock(db, pVtab);
} }
sqliteFree(db->aVTrans); sqlite3DbFree(db, db->aVTrans);
db->nVTrans = 0; db->nVTrans = 0;
db->aVTrans = 0; db->aVTrans = 0;
} }
} }
/* /*
** If argument rc2 is not SQLITE_OK, then return it and do nothing. ** Invoke the xSync method of all virtual tables in the sqlite3.aVTrans
** Otherwise, invoke the xSync method of all virtual tables in the ** array. Return the error code for the first error that occurs, or
** sqlite3.aVTrans array. Return the error code for the first error ** SQLITE_OK if all xSync operations are successful.
** that occurs, or SQLITE_OK if all xSync operations are successful. **
** Set *pzErrmsg to point to a buffer that should be released using
** sqlite3DbFree() containing an error message, if one is available.
*/ */
int sqlite3VtabSync(sqlite3 *db, int rc2){ int sqlite3VtabSync(sqlite3 *db, char **pzErrmsg){
int i; int i;
int rc = SQLITE_OK; int rc = SQLITE_OK;
int rcsafety; int rcsafety;
sqlite3_vtab **aVTrans = db->aVTrans; sqlite3_vtab **aVTrans = db->aVTrans;
if( rc2!=SQLITE_OK ) return rc2;
rc = sqlite3SafetyOff(db); rc = sqlite3SafetyOff(db);
db->aVTrans = 0; db->aVTrans = 0;
@ -634,6 +664,9 @@ int sqlite3VtabSync(sqlite3 *db, int rc2){
x = pVtab->pModule->xSync; x = pVtab->pModule->xSync;
if( x ){ if( x ){
rc = x(pVtab); rc = x(pVtab);
sqlite3DbFree(db, *pzErrmsg);
*pzErrmsg = pVtab->zErrMsg;
pVtab->zErrMsg = 0;
} }
} }
db->aVTrans = aVTrans; db->aVTrans = aVTrans;
@ -650,7 +683,7 @@ int sqlite3VtabSync(sqlite3 *db, int rc2){
** sqlite3.aVTrans array. Then clear the array itself. ** sqlite3.aVTrans array. Then clear the array itself.
*/ */
int sqlite3VtabRollback(sqlite3 *db){ int sqlite3VtabRollback(sqlite3 *db){
callFinaliser(db, (int)(&((sqlite3_module *)0)->xRollback)); callFinaliser(db, offsetof(sqlite3_module,xRollback));
return SQLITE_OK; return SQLITE_OK;
} }
@ -659,7 +692,7 @@ int sqlite3VtabRollback(sqlite3 *db){
** sqlite3.aVTrans array. Then clear the array itself. ** sqlite3.aVTrans array. Then clear the array itself.
*/ */
int sqlite3VtabCommit(sqlite3 *db){ int sqlite3VtabCommit(sqlite3 *db){
callFinaliser(db, (int)(&((sqlite3_module *)0)->xCommit)); callFinaliser(db, offsetof(sqlite3_module,xCommit));
return SQLITE_OK; return SQLITE_OK;
} }
@ -680,7 +713,7 @@ int sqlite3VtabBegin(sqlite3 *db, sqlite3_vtab *pVtab){
** virtual module xSync() callback. It is illegal to write to ** virtual module xSync() callback. It is illegal to write to
** virtual module tables in this case, so return SQLITE_LOCKED. ** virtual module tables in this case, so return SQLITE_LOCKED.
*/ */
if( 0==db->aVTrans && db->nVTrans>0 ){ if( sqlite3VtabInSync(db) ){
return SQLITE_LOCKED; return SQLITE_LOCKED;
} }
if( !pVtab ){ if( !pVtab ){
@ -701,11 +734,9 @@ int sqlite3VtabBegin(sqlite3 *db, sqlite3_vtab *pVtab){
/* Invoke the xBegin method */ /* Invoke the xBegin method */
rc = pModule->xBegin(pVtab); rc = pModule->xBegin(pVtab);
if( rc!=SQLITE_OK ){ if( rc==SQLITE_OK ){
return rc; rc = addToVTrans(db, pVtab);
} }
rc = addToVTrans(db, pVtab);
} }
return rc; return rc;
} }
@ -724,6 +755,7 @@ int sqlite3VtabBegin(sqlite3 *db, sqlite3_vtab *pVtab){
** SQLITE_FUNC_EPHEM flag. ** SQLITE_FUNC_EPHEM flag.
*/ */
FuncDef *sqlite3VtabOverloadFunction( FuncDef *sqlite3VtabOverloadFunction(
sqlite3 *db, /* Database connection for reporting malloc problems */
FuncDef *pDef, /* Function to possibly overload */ FuncDef *pDef, /* Function to possibly overload */
int nArg, /* Number of arguments to the function */ int nArg, /* Number of arguments to the function */
Expr *pExpr /* First argument to the function */ Expr *pExpr /* First argument to the function */
@ -731,10 +763,10 @@ FuncDef *sqlite3VtabOverloadFunction(
Table *pTab; Table *pTab;
sqlite3_vtab *pVtab; sqlite3_vtab *pVtab;
sqlite3_module *pMod; sqlite3_module *pMod;
void (*xFunc)(sqlite3_context*,int,sqlite3_value**); void (*xFunc)(sqlite3_context*,int,sqlite3_value**) = 0;
void *pArg; void *pArg = 0;
FuncDef *pNew; FuncDef *pNew;
int rc; int rc = 0;
char *zLowerName; char *zLowerName;
unsigned char *z; unsigned char *z;
@ -744,38 +776,68 @@ FuncDef *sqlite3VtabOverloadFunction(
if( pExpr->op!=TK_COLUMN ) return pDef; if( pExpr->op!=TK_COLUMN ) return pDef;
pTab = pExpr->pTab; pTab = pExpr->pTab;
if( pTab==0 ) return pDef; if( pTab==0 ) return pDef;
if( !pTab->isVirtual ) return pDef; if( (pTab->tabFlags & TF_Virtual)==0 ) return pDef;
pVtab = pTab->pVtab; pVtab = pTab->pVtab;
assert( pVtab!=0 ); assert( pVtab!=0 );
assert( pVtab->pModule!=0 ); assert( pVtab->pModule!=0 );
pMod = (sqlite3_module *)pVtab->pModule; pMod = (sqlite3_module *)pVtab->pModule;
if( pMod->xFindFunction==0 ) return pDef; if( pMod->xFindFunction==0 ) return pDef;
/* Call the xFuncFunction method on the virtual table implementation /* Call the xFindFunction method on the virtual table implementation
** to see if the implementation wants to overload this function ** to see if the implementation wants to overload this function
*/ */
zLowerName = sqlite3StrDup(pDef->zName); zLowerName = sqlite3DbStrDup(db, pDef->zName);
for(z=(unsigned char*)zLowerName; *z; z++){ if( zLowerName ){
*z = sqlite3UpperToLower[*z]; for(z=(unsigned char*)zLowerName; *z; z++){
*z = sqlite3UpperToLower[*z];
}
rc = pMod->xFindFunction(pVtab, nArg, zLowerName, &xFunc, &pArg);
sqlite3DbFree(db, zLowerName);
if( pVtab->zErrMsg ){
sqlite3Error(db, rc, "%s", pVtab->zErrMsg);
sqlite3DbFree(db, pVtab->zErrMsg);
pVtab->zErrMsg = 0;
}
} }
rc = pMod->xFindFunction(pVtab, nArg, zLowerName, &xFunc, &pArg);
sqliteFree(zLowerName);
if( rc==0 ){ if( rc==0 ){
return pDef; return pDef;
} }
/* Create a new ephemeral function definition for the overloaded /* Create a new ephemeral function definition for the overloaded
** function */ ** function */
pNew = sqliteMalloc( sizeof(*pNew) + strlen(pDef->zName) ); pNew = sqlite3DbMallocZero(db, sizeof(*pNew)
+ sqlite3Strlen30(pDef->zName) );
if( pNew==0 ){ if( pNew==0 ){
return pDef; return pDef;
} }
*pNew = *pDef; *pNew = *pDef;
memcpy(pNew->zName, pDef->zName, strlen(pDef->zName)+1); pNew->zName = (char *)&pNew[1];
memcpy(pNew->zName, pDef->zName, sqlite3Strlen30(pDef->zName)+1);
pNew->xFunc = xFunc; pNew->xFunc = xFunc;
pNew->pUserData = pArg; pNew->pUserData = pArg;
pNew->flags |= SQLITE_FUNC_EPHEM; pNew->flags |= SQLITE_FUNC_EPHEM;
return pNew; return pNew;
} }
/*
** Make sure virtual table pTab is contained in the pParse->apVirtualLock[]
** array so that an OP_VBegin will get generated for it. Add pTab to the
** array if it is missing. If pTab is already in the array, this routine
** is a no-op.
*/
void sqlite3VtabMakeWritable(Parse *pParse, Table *pTab){
int i, n;
assert( IsVirtual(pTab) );
for(i=0; i<pParse->nVtabLock; i++){
if( pTab==pParse->apVtabLock[i] ) return;
}
n = (pParse->nVtabLock+1)*sizeof(pParse->apVtabLock[0]);
pParse->apVtabLock = sqlite3_realloc(pParse->apVtabLock, n);
if( pParse->apVtabLock ){
pParse->apVtabLock[pParse->nVtabLock++] = pTab;
}else{
pParse->db->mallocFailed = 1;
}
}
#endif /* SQLITE_OMIT_VIRTUALTABLE */ #endif /* SQLITE_OMIT_VIRTUALTABLE */

Some files were not shown because too many files have changed in this diff Show more