sqlite 3.5.1 windows source
parent
e36d23a85e
commit
354ea97baf
|
@ -0,0 +1,622 @@
|
|||
/*
|
||||
** 2005 February 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 C code routines that used to generate VDBE code
|
||||
** that implements the ALTER TABLE command.
|
||||
**
|
||||
** $Id: alter.c,v 1.32 2007/08/29 14:06:23 danielk1977 Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include <ctype.h>
|
||||
|
||||
/*
|
||||
** The code in this file only exists if we are not omitting the
|
||||
** ALTER TABLE logic from the build.
|
||||
*/
|
||||
#ifndef SQLITE_OMIT_ALTERTABLE
|
||||
|
||||
|
||||
/*
|
||||
** This function is used by SQL generated to implement the
|
||||
** ALTER TABLE command. The first argument is the text of a CREATE TABLE or
|
||||
** CREATE INDEX command. The second is a table name. The table name in
|
||||
** the CREATE TABLE or CREATE INDEX statement is replaced with the third
|
||||
** argument and the result returned. Examples:
|
||||
**
|
||||
** sqlite_rename_table('CREATE TABLE abc(a, b, c)', 'def')
|
||||
** -> 'CREATE TABLE def(a, b, c)'
|
||||
**
|
||||
** sqlite_rename_table('CREATE INDEX i ON abc(a)', 'def')
|
||||
** -> 'CREATE INDEX i ON def(a, b, c)'
|
||||
*/
|
||||
static void renameTableFunc(
|
||||
sqlite3_context *context,
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
unsigned char const *zSql = sqlite3_value_text(argv[0]);
|
||||
unsigned char const *zTableName = sqlite3_value_text(argv[1]);
|
||||
|
||||
int token;
|
||||
Token tname;
|
||||
unsigned char const *zCsr = zSql;
|
||||
int len = 0;
|
||||
char *zRet;
|
||||
|
||||
sqlite3 *db = sqlite3_user_data(context);
|
||||
|
||||
/* 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
|
||||
** followed by a left parenthesis - TK_LP - or "USING" TK_USING.
|
||||
*/
|
||||
if( zSql ){
|
||||
do {
|
||||
if( !*zCsr ){
|
||||
/* Ran out of input before finding an opening bracket. Return NULL. */
|
||||
return;
|
||||
}
|
||||
|
||||
/* Store the token that zCsr points to in tname. */
|
||||
tname.z = zCsr;
|
||||
tname.n = len;
|
||||
|
||||
/* 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).
|
||||
*/
|
||||
do {
|
||||
zCsr += len;
|
||||
len = sqlite3GetToken(zCsr, &token);
|
||||
} while( token==TK_SPACE );
|
||||
assert( len>0 );
|
||||
} while( token!=TK_LP && token!=TK_USING );
|
||||
|
||||
zRet = sqlite3MPrintf(db, "%.*s%Q%s", tname.z - zSql, zSql,
|
||||
zTableName, tname.z+tname.n);
|
||||
sqlite3_result_text(context, zRet, -1, sqlite3_free);
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef SQLITE_OMIT_TRIGGER
|
||||
/* This function is used by SQL generated to implement the
|
||||
** ALTER TABLE command. The first argument is the text of a CREATE TRIGGER
|
||||
** statement. The second is a table name. The table name in the CREATE
|
||||
** TRIGGER statement is replaced with the third argument and the result
|
||||
** returned. This is analagous to renameTableFunc() above, except for CREATE
|
||||
** TRIGGER, not CREATE INDEX and CREATE TABLE.
|
||||
*/
|
||||
static void renameTriggerFunc(
|
||||
sqlite3_context *context,
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
unsigned char const *zSql = sqlite3_value_text(argv[0]);
|
||||
unsigned char const *zTableName = sqlite3_value_text(argv[1]);
|
||||
|
||||
int token;
|
||||
Token tname;
|
||||
int dist = 3;
|
||||
unsigned char const *zCsr = zSql;
|
||||
int len = 0;
|
||||
char *zRet;
|
||||
|
||||
sqlite3 *db = sqlite3_user_data(context);
|
||||
|
||||
/* 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
|
||||
** preceded by either TK_ON or TK_DOT and immediatedly followed by one
|
||||
** of TK_WHEN, TK_BEGIN or TK_FOR.
|
||||
*/
|
||||
if( zSql ){
|
||||
do {
|
||||
|
||||
if( !*zCsr ){
|
||||
/* Ran out of input before finding the table name. Return NULL. */
|
||||
return;
|
||||
}
|
||||
|
||||
/* Store the token that zCsr points to in tname. */
|
||||
tname.z = zCsr;
|
||||
tname.n = len;
|
||||
|
||||
/* 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).
|
||||
*/
|
||||
do {
|
||||
zCsr += len;
|
||||
len = sqlite3GetToken(zCsr, &token);
|
||||
}while( token==TK_SPACE );
|
||||
assert( len>0 );
|
||||
|
||||
/* Variable 'dist' stores the number of tokens read since the most
|
||||
** recent TK_DOT or TK_ON. This means that when a WHEN, FOR or BEGIN
|
||||
** token is read and 'dist' equals 2, the condition stated above
|
||||
** to be met.
|
||||
**
|
||||
** Note that ON cannot be a database, table or column name, so
|
||||
** there is no need to worry about syntax like
|
||||
** "CREATE TRIGGER ... ON ON.ON BEGIN ..." etc.
|
||||
*/
|
||||
dist++;
|
||||
if( token==TK_DOT || token==TK_ON ){
|
||||
dist = 0;
|
||||
}
|
||||
} while( dist!=2 || (token!=TK_WHEN && token!=TK_FOR && token!=TK_BEGIN) );
|
||||
|
||||
/* Variable tname now contains the token that is the old table-name
|
||||
** in the CREATE TRIGGER statement.
|
||||
*/
|
||||
zRet = sqlite3MPrintf(db, "%.*s%Q%s", tname.z - zSql, zSql,
|
||||
zTableName, tname.z+tname.n);
|
||||
sqlite3_result_text(context, zRet, -1, sqlite3_free);
|
||||
}
|
||||
}
|
||||
#endif /* !SQLITE_OMIT_TRIGGER */
|
||||
|
||||
/*
|
||||
** Register built-in functions used to help implement ALTER TABLE
|
||||
*/
|
||||
void sqlite3AlterFunctions(sqlite3 *db){
|
||||
static const struct {
|
||||
char *zName;
|
||||
signed char nArg;
|
||||
void (*xFunc)(sqlite3_context*,int,sqlite3_value **);
|
||||
} aFuncs[] = {
|
||||
{ "sqlite_rename_table", 2, renameTableFunc},
|
||||
#ifndef SQLITE_OMIT_TRIGGER
|
||||
{ "sqlite_rename_trigger", 2, renameTriggerFunc},
|
||||
#endif
|
||||
};
|
||||
int i;
|
||||
|
||||
for(i=0; i<sizeof(aFuncs)/sizeof(aFuncs[0]); i++){
|
||||
sqlite3CreateFunc(db, aFuncs[i].zName, aFuncs[i].nArg,
|
||||
SQLITE_UTF8, (void *)db, aFuncs[i].xFunc, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Generate the text of a WHERE expression which can be used to select all
|
||||
** temporary triggers on table pTab from the sqlite_temp_master table. If
|
||||
** table pTab has no temporary triggers, or is itself stored in the
|
||||
** temporary database, NULL is returned.
|
||||
*/
|
||||
static char *whereTempTriggers(Parse *pParse, Table *pTab){
|
||||
Trigger *pTrig;
|
||||
char *zWhere = 0;
|
||||
char *tmp = 0;
|
||||
const Schema *pTempSchema = pParse->db->aDb[1].pSchema; /* Temp db schema */
|
||||
|
||||
/* If the table is not located in the temp-db (in which case NULL is
|
||||
** returned, loop through the tables list of triggers. For each trigger
|
||||
** that is not part of the temp-db schema, add a clause to the WHERE
|
||||
** expression being built up in zWhere.
|
||||
*/
|
||||
if( pTab->pSchema!=pTempSchema ){
|
||||
sqlite3 *db = pParse->db;
|
||||
for( pTrig=pTab->pTrigger; pTrig; pTrig=pTrig->pNext ){
|
||||
if( pTrig->pSchema==pTempSchema ){
|
||||
if( !zWhere ){
|
||||
zWhere = sqlite3MPrintf(db, "name=%Q", pTrig->name);
|
||||
}else{
|
||||
tmp = zWhere;
|
||||
zWhere = sqlite3MPrintf(db, "%s OR name=%Q", zWhere, pTrig->name);
|
||||
sqlite3_free(tmp);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return zWhere;
|
||||
}
|
||||
|
||||
/*
|
||||
** Generate code to drop and reload the internal representation of table
|
||||
** pTab from the database, including triggers and temporary triggers.
|
||||
** Argument zName is the name of the table in the database schema at
|
||||
** the time the generated code is executed. This can be different from
|
||||
** pTab->zName if this function is being called to code part of an
|
||||
** "ALTER TABLE RENAME TO" statement.
|
||||
*/
|
||||
static void reloadTableSchema(Parse *pParse, Table *pTab, const char *zName){
|
||||
Vdbe *v;
|
||||
char *zWhere;
|
||||
int iDb; /* Index of database containing pTab */
|
||||
#ifndef SQLITE_OMIT_TRIGGER
|
||||
Trigger *pTrig;
|
||||
#endif
|
||||
|
||||
v = sqlite3GetVdbe(pParse);
|
||||
if( !v ) return;
|
||||
assert( sqlite3BtreeHoldsAllMutexes(pParse->db) );
|
||||
iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
|
||||
assert( iDb>=0 );
|
||||
|
||||
#ifndef SQLITE_OMIT_TRIGGER
|
||||
/* Drop any table triggers from the internal schema. */
|
||||
for(pTrig=pTab->pTrigger; pTrig; pTrig=pTrig->pNext){
|
||||
int iTrigDb = sqlite3SchemaToIndex(pParse->db, pTrig->pSchema);
|
||||
assert( iTrigDb==iDb || iTrigDb==1 );
|
||||
sqlite3VdbeOp3(v, OP_DropTrigger, iTrigDb, 0, pTrig->name, 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Drop the table and index from the internal schema */
|
||||
sqlite3VdbeOp3(v, OP_DropTable, iDb, 0, pTab->zName, 0);
|
||||
|
||||
/* Reload the table, index and permanent trigger schemas. */
|
||||
zWhere = sqlite3MPrintf(pParse->db, "tbl_name=%Q", zName);
|
||||
if( !zWhere ) return;
|
||||
sqlite3VdbeOp3(v, OP_ParseSchema, iDb, 0, zWhere, P3_DYNAMIC);
|
||||
|
||||
#ifndef SQLITE_OMIT_TRIGGER
|
||||
/* Now, if the table is not stored in the temp database, reload any temp
|
||||
** triggers. Don't use IN(...) in case SQLITE_OMIT_SUBQUERY is defined.
|
||||
*/
|
||||
if( (zWhere=whereTempTriggers(pParse, pTab))!=0 ){
|
||||
sqlite3VdbeOp3(v, OP_ParseSchema, 1, 0, zWhere, P3_DYNAMIC);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
** Generate code to implement the "ALTER TABLE xxx RENAME TO yyy"
|
||||
** command.
|
||||
*/
|
||||
void sqlite3AlterRenameTable(
|
||||
Parse *pParse, /* Parser context. */
|
||||
SrcList *pSrc, /* The table to rename. */
|
||||
Token *pName /* The new table name. */
|
||||
){
|
||||
int iDb; /* Database that contains the table */
|
||||
char *zDb; /* Name of database iDb */
|
||||
Table *pTab; /* Table being renamed */
|
||||
char *zName = 0; /* NULL-terminated version of pName */
|
||||
sqlite3 *db = pParse->db; /* Database connection */
|
||||
int nTabName; /* Number of UTF-8 characters in zTabName */
|
||||
const char *zTabName; /* Original name of the table */
|
||||
Vdbe *v;
|
||||
#ifndef SQLITE_OMIT_TRIGGER
|
||||
char *zWhere = 0; /* Where clause to locate temp triggers */
|
||||
#endif
|
||||
int isVirtualRename = 0; /* True if this is a v-table with an xRename() */
|
||||
|
||||
if( db->mallocFailed ) goto exit_rename_table;
|
||||
assert( pSrc->nSrc==1 );
|
||||
assert( sqlite3BtreeHoldsAllMutexes(pParse->db) );
|
||||
|
||||
pTab = sqlite3LocateTable(pParse, pSrc->a[0].zName, pSrc->a[0].zDatabase);
|
||||
if( !pTab ) goto exit_rename_table;
|
||||
iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
|
||||
zDb = db->aDb[iDb].zName;
|
||||
|
||||
/* Get a NULL terminated version of the new table name. */
|
||||
zName = sqlite3NameFromToken(db, pName);
|
||||
if( !zName ) goto exit_rename_table;
|
||||
|
||||
/* Check that a table or index named 'zName' does not already exist
|
||||
** in database iDb. If so, this is an error.
|
||||
*/
|
||||
if( sqlite3FindTable(db, zName, zDb) || sqlite3FindIndex(db, zName, zDb) ){
|
||||
sqlite3ErrorMsg(pParse,
|
||||
"there is already another table or index with this name: %s", zName);
|
||||
goto exit_rename_table;
|
||||
}
|
||||
|
||||
/* Make sure it is not a system table being altered, or a reserved name
|
||||
** that the table is being renamed to.
|
||||
*/
|
||||
if( strlen(pTab->zName)>6 && 0==sqlite3StrNICmp(pTab->zName, "sqlite_", 7) ){
|
||||
sqlite3ErrorMsg(pParse, "table %s may not be altered", pTab->zName);
|
||||
goto exit_rename_table;
|
||||
}
|
||||
if( SQLITE_OK!=sqlite3CheckObjectName(pParse, zName) ){
|
||||
goto exit_rename_table;
|
||||
}
|
||||
|
||||
#ifndef SQLITE_OMIT_AUTHORIZATION
|
||||
/* Invoke the authorization callback. */
|
||||
if( sqlite3AuthCheck(pParse, SQLITE_ALTER_TABLE, zDb, pTab->zName, 0) ){
|
||||
goto exit_rename_table;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
if( sqlite3ViewGetColumnNames(pParse, pTab) ){
|
||||
goto exit_rename_table;
|
||||
}
|
||||
if( IsVirtual(pTab) && pTab->pMod->pModule->xRename ){
|
||||
isVirtualRename = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Begin a transaction and code the VerifyCookie for database iDb.
|
||||
** Then modify the schema cookie (since the ALTER TABLE modifies the
|
||||
** schema). Open a statement transaction if the table is a virtual
|
||||
** table.
|
||||
*/
|
||||
v = sqlite3GetVdbe(pParse);
|
||||
if( v==0 ){
|
||||
goto exit_rename_table;
|
||||
}
|
||||
sqlite3BeginWriteOperation(pParse, isVirtualRename, iDb);
|
||||
sqlite3ChangeCookie(db, v, iDb);
|
||||
|
||||
/* If this is a virtual table, invoke the xRename() function if
|
||||
** one is defined. The xRename() callback will modify the names
|
||||
** of any resources used by the v-table implementation (including other
|
||||
** SQLite tables) that are identified by the name of the virtual table.
|
||||
*/
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
if( isVirtualRename ){
|
||||
sqlite3VdbeOp3(v, OP_String8, 0, 0, zName, 0);
|
||||
sqlite3VdbeOp3(v, OP_VRename, 0, 0, (const char*)pTab->pVtab, P3_VTAB);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* figure out how many UTF-8 characters are in zName */
|
||||
zTabName = pTab->zName;
|
||||
nTabName = sqlite3Utf8CharLen(zTabName, -1);
|
||||
|
||||
/* Modify the sqlite_master table to use the new table name. */
|
||||
sqlite3NestedParse(pParse,
|
||||
"UPDATE %Q.%s SET "
|
||||
#ifdef SQLITE_OMIT_TRIGGER
|
||||
"sql = sqlite_rename_table(sql, %Q), "
|
||||
#else
|
||||
"sql = CASE "
|
||||
"WHEN type = 'trigger' THEN sqlite_rename_trigger(sql, %Q)"
|
||||
"ELSE sqlite_rename_table(sql, %Q) END, "
|
||||
#endif
|
||||
"tbl_name = %Q, "
|
||||
"name = CASE "
|
||||
"WHEN type='table' THEN %Q "
|
||||
"WHEN name LIKE 'sqlite_autoindex%%' AND type='index' THEN "
|
||||
"'sqlite_autoindex_' || %Q || substr(name,%d+18,10) "
|
||||
"ELSE name END "
|
||||
"WHERE tbl_name=%Q AND "
|
||||
"(type='table' OR type='index' OR type='trigger');",
|
||||
zDb, SCHEMA_TABLE(iDb), zName, zName, zName,
|
||||
#ifndef SQLITE_OMIT_TRIGGER
|
||||
zName,
|
||||
#endif
|
||||
zName, nTabName, zTabName
|
||||
);
|
||||
|
||||
#ifndef SQLITE_OMIT_AUTOINCREMENT
|
||||
/* If the sqlite_sequence table exists in this database, then update
|
||||
** it with the new table name.
|
||||
*/
|
||||
if( sqlite3FindTable(db, "sqlite_sequence", zDb) ){
|
||||
sqlite3NestedParse(pParse,
|
||||
"UPDATE %Q.sqlite_sequence set name = %Q WHERE name = %Q",
|
||||
zDb, zName, pTab->zName);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef SQLITE_OMIT_TRIGGER
|
||||
/* If there are TEMP triggers on this table, modify the sqlite_temp_master
|
||||
** table. Don't do this if the table being ALTERed is itself located in
|
||||
** the temp database.
|
||||
*/
|
||||
if( (zWhere=whereTempTriggers(pParse, pTab))!=0 ){
|
||||
sqlite3NestedParse(pParse,
|
||||
"UPDATE sqlite_temp_master SET "
|
||||
"sql = sqlite_rename_trigger(sql, %Q), "
|
||||
"tbl_name = %Q "
|
||||
"WHERE %s;", zName, zName, zWhere);
|
||||
sqlite3_free(zWhere);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Drop and reload the internal table schema. */
|
||||
reloadTableSchema(pParse, pTab, zName);
|
||||
|
||||
exit_rename_table:
|
||||
sqlite3SrcListDelete(pSrc);
|
||||
sqlite3_free(zName);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** This function is called after an "ALTER TABLE ... ADD" statement
|
||||
** has been parsed. Argument pColDef contains the text of the new
|
||||
** column definition.
|
||||
**
|
||||
** The Table structure pParse->pNewTable was extended to include
|
||||
** the new column during parsing.
|
||||
*/
|
||||
void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){
|
||||
Table *pNew; /* Copy of pParse->pNewTable */
|
||||
Table *pTab; /* Table being altered */
|
||||
int iDb; /* Database number */
|
||||
const char *zDb; /* Database name */
|
||||
const char *zTab; /* Table name */
|
||||
char *zCol; /* Null-terminated column definition */
|
||||
Column *pCol; /* The new column */
|
||||
Expr *pDflt; /* Default value for the new column */
|
||||
sqlite3 *db; /* The database connection; */
|
||||
|
||||
if( pParse->nErr ) return;
|
||||
pNew = pParse->pNewTable;
|
||||
assert( pNew );
|
||||
|
||||
db = pParse->db;
|
||||
assert( sqlite3BtreeHoldsAllMutexes(db) );
|
||||
iDb = sqlite3SchemaToIndex(db, pNew->pSchema);
|
||||
zDb = db->aDb[iDb].zName;
|
||||
zTab = pNew->zName;
|
||||
pCol = &pNew->aCol[pNew->nCol-1];
|
||||
pDflt = pCol->pDflt;
|
||||
pTab = sqlite3FindTable(db, zTab, zDb);
|
||||
assert( pTab );
|
||||
|
||||
#ifndef SQLITE_OMIT_AUTHORIZATION
|
||||
/* Invoke the authorization callback. */
|
||||
if( sqlite3AuthCheck(pParse, SQLITE_ALTER_TABLE, zDb, pTab->zName, 0) ){
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* If the default value for the new column was specified with a
|
||||
** literal NULL, then set pDflt to 0. This simplifies checking
|
||||
** for an SQL NULL default below.
|
||||
*/
|
||||
if( pDflt && pDflt->op==TK_NULL ){
|
||||
pDflt = 0;
|
||||
}
|
||||
|
||||
/* Check that the new column is not specified as PRIMARY KEY or UNIQUE.
|
||||
** If there is a NOT NULL constraint, then the default value for the
|
||||
** column must not be NULL.
|
||||
*/
|
||||
if( pCol->isPrimKey ){
|
||||
sqlite3ErrorMsg(pParse, "Cannot add a PRIMARY KEY column");
|
||||
return;
|
||||
}
|
||||
if( pNew->pIndex ){
|
||||
sqlite3ErrorMsg(pParse, "Cannot add a UNIQUE column");
|
||||
return;
|
||||
}
|
||||
if( pCol->notNull && !pDflt ){
|
||||
sqlite3ErrorMsg(pParse,
|
||||
"Cannot add a NOT NULL column with default value NULL");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Ensure the default expression is something that sqlite3ValueFromExpr()
|
||||
** can handle (i.e. not CURRENT_TIME etc.)
|
||||
*/
|
||||
if( pDflt ){
|
||||
sqlite3_value *pVal;
|
||||
if( sqlite3ValueFromExpr(db, pDflt, SQLITE_UTF8, SQLITE_AFF_NONE, &pVal) ){
|
||||
db->mallocFailed = 1;
|
||||
return;
|
||||
}
|
||||
if( !pVal ){
|
||||
sqlite3ErrorMsg(pParse, "Cannot add a column with non-constant default");
|
||||
return;
|
||||
}
|
||||
sqlite3ValueFree(pVal);
|
||||
}
|
||||
|
||||
/* Modify the CREATE TABLE statement. */
|
||||
zCol = sqlite3DbStrNDup(db, (char*)pColDef->z, pColDef->n);
|
||||
if( zCol ){
|
||||
char *zEnd = &zCol[pColDef->n-1];
|
||||
while( (zEnd>zCol && *zEnd==';') || isspace(*(unsigned char *)zEnd) ){
|
||||
*zEnd-- = '\0';
|
||||
}
|
||||
sqlite3NestedParse(pParse,
|
||||
"UPDATE %Q.%s SET "
|
||||
"sql = substr(sql,1,%d) || ', ' || %Q || substr(sql,%d,length(sql)) "
|
||||
"WHERE type = 'table' AND name = %Q",
|
||||
zDb, SCHEMA_TABLE(iDb), pNew->addColOffset, zCol, pNew->addColOffset+1,
|
||||
zTab
|
||||
);
|
||||
sqlite3_free(zCol);
|
||||
}
|
||||
|
||||
/* If the default value of the new column is NULL, then set the file
|
||||
** format to 2. If the default value of the new column is not NULL,
|
||||
** the file format becomes 3.
|
||||
*/
|
||||
sqlite3MinimumFileFormat(pParse, iDb, pDflt ? 3 : 2);
|
||||
|
||||
/* Reload the schema of the modified table. */
|
||||
reloadTableSchema(pParse, pTab, pTab->zName);
|
||||
}
|
||||
|
||||
/*
|
||||
** This function is called by the parser after the table-name in
|
||||
** an "ALTER TABLE <table-name> ADD" statement is parsed. Argument
|
||||
** pSrc is the full-name of the table being altered.
|
||||
**
|
||||
** This routine makes a (partial) copy of the Table structure
|
||||
** for the table being altered and sets Parse.pNewTable to point
|
||||
** to it. Routines called by the parser as the column definition
|
||||
** is parsed (i.e. sqlite3AddColumn()) add the new Column data to
|
||||
** the copy. The copy of the Table structure is deleted by tokenize.c
|
||||
** after parsing is finished.
|
||||
**
|
||||
** Routine sqlite3AlterFinishAddColumn() will be called to complete
|
||||
** coding the "ALTER TABLE ... ADD" statement.
|
||||
*/
|
||||
void sqlite3AlterBeginAddColumn(Parse *pParse, SrcList *pSrc){
|
||||
Table *pNew;
|
||||
Table *pTab;
|
||||
Vdbe *v;
|
||||
int iDb;
|
||||
int i;
|
||||
int nAlloc;
|
||||
sqlite3 *db = pParse->db;
|
||||
|
||||
/* Look up the table being altered. */
|
||||
assert( pParse->pNewTable==0 );
|
||||
assert( sqlite3BtreeHoldsAllMutexes(db) );
|
||||
if( db->mallocFailed ) goto exit_begin_add_column;
|
||||
pTab = sqlite3LocateTable(pParse, pSrc->a[0].zName, pSrc->a[0].zDatabase);
|
||||
if( !pTab ) goto exit_begin_add_column;
|
||||
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
if( IsVirtual(pTab) ){
|
||||
sqlite3ErrorMsg(pParse, "virtual tables may not be altered");
|
||||
goto exit_begin_add_column;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Make sure this is not an attempt to ALTER a view. */
|
||||
if( pTab->pSelect ){
|
||||
sqlite3ErrorMsg(pParse, "Cannot add a column to a view");
|
||||
goto exit_begin_add_column;
|
||||
}
|
||||
|
||||
assert( pTab->addColOffset>0 );
|
||||
iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
|
||||
|
||||
/* Put a copy of the Table struct in Parse.pNewTable for the
|
||||
** sqlite3AddColumn() function and friends to modify.
|
||||
*/
|
||||
pNew = (Table*)sqlite3DbMallocZero(db, sizeof(Table));
|
||||
if( !pNew ) goto exit_begin_add_column;
|
||||
pParse->pNewTable = pNew;
|
||||
pNew->nRef = 1;
|
||||
pNew->nCol = pTab->nCol;
|
||||
assert( pNew->nCol>0 );
|
||||
nAlloc = (((pNew->nCol-1)/8)*8)+8;
|
||||
assert( nAlloc>=pNew->nCol && nAlloc%8==0 && nAlloc-pNew->nCol<8 );
|
||||
pNew->aCol = (Column*)sqlite3DbMallocZero(db, sizeof(Column)*nAlloc);
|
||||
pNew->zName = sqlite3DbStrDup(db, pTab->zName);
|
||||
if( !pNew->aCol || !pNew->zName ){
|
||||
db->mallocFailed = 1;
|
||||
goto exit_begin_add_column;
|
||||
}
|
||||
memcpy(pNew->aCol, pTab->aCol, sizeof(Column)*pNew->nCol);
|
||||
for(i=0; i<pNew->nCol; i++){
|
||||
Column *pCol = &pNew->aCol[i];
|
||||
pCol->zName = sqlite3DbStrDup(db, pCol->zName);
|
||||
pCol->zColl = 0;
|
||||
pCol->zType = 0;
|
||||
pCol->pDflt = 0;
|
||||
}
|
||||
pNew->pSchema = db->aDb[iDb].pSchema;
|
||||
pNew->addColOffset = pTab->addColOffset;
|
||||
pNew->nRef = 1;
|
||||
|
||||
/* Begin a transaction and increment the schema cookie. */
|
||||
sqlite3BeginWriteOperation(pParse, 0, iDb);
|
||||
v = sqlite3GetVdbe(pParse);
|
||||
if( !v ) goto exit_begin_add_column;
|
||||
sqlite3ChangeCookie(db, v, iDb);
|
||||
|
||||
exit_begin_add_column:
|
||||
sqlite3SrcListDelete(pSrc);
|
||||
return;
|
||||
}
|
||||
#endif /* SQLITE_ALTER_TABLE */
|
|
@ -0,0 +1,418 @@
|
|||
/*
|
||||
** 2005 July 8
|
||||
**
|
||||
** The author disclaims copyright to this source code. In place of
|
||||
** a legal notice, here is a blessing:
|
||||
**
|
||||
** May you do good and not evil.
|
||||
** May you find forgiveness for yourself and forgive others.
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
*************************************************************************
|
||||
** This file contains code associated with the ANALYZE command.
|
||||
**
|
||||
** @(#) $Id: analyze.c,v 1.23 2007/08/29 17:43:20 drh Exp $
|
||||
*/
|
||||
#ifndef SQLITE_OMIT_ANALYZE
|
||||
#include "sqliteInt.h"
|
||||
|
||||
/*
|
||||
** This routine generates code that opens the sqlite_stat1 table on cursor
|
||||
** iStatCur.
|
||||
**
|
||||
** If the sqlite_stat1 tables does not previously exist, it is created.
|
||||
** If it does previously exist, all entires associated with table zWhere
|
||||
** are removed. If zWhere==0 then all entries are removed.
|
||||
*/
|
||||
static void openStatTable(
|
||||
Parse *pParse, /* Parsing context */
|
||||
int iDb, /* The database we are looking in */
|
||||
int iStatCur, /* Open the sqlite_stat1 table on this cursor */
|
||||
const char *zWhere /* Delete entries associated with this table */
|
||||
){
|
||||
sqlite3 *db = pParse->db;
|
||||
Db *pDb;
|
||||
int iRootPage;
|
||||
Table *pStat;
|
||||
Vdbe *v = sqlite3GetVdbe(pParse);
|
||||
|
||||
if( v==0 ) return;
|
||||
assert( sqlite3BtreeHoldsAllMutexes(db) );
|
||||
assert( sqlite3VdbeDb(v)==db );
|
||||
pDb = &db->aDb[iDb];
|
||||
if( (pStat = sqlite3FindTable(db, "sqlite_stat1", pDb->zName))==0 ){
|
||||
/* The sqlite_stat1 tables does not exist. Create it.
|
||||
** Note that a side-effect of the CREATE TABLE statement is to leave
|
||||
** the rootpage of the new table on the top of the stack. This is
|
||||
** important because the OpenWrite opcode below will be needing it. */
|
||||
sqlite3NestedParse(pParse,
|
||||
"CREATE TABLE %Q.sqlite_stat1(tbl,idx,stat)",
|
||||
pDb->zName
|
||||
);
|
||||
iRootPage = 0; /* Cause rootpage to be taken from top of stack */
|
||||
}else if( zWhere ){
|
||||
/* The sqlite_stat1 table exists. Delete all entries associated with
|
||||
** the table zWhere. */
|
||||
sqlite3NestedParse(pParse,
|
||||
"DELETE FROM %Q.sqlite_stat1 WHERE tbl=%Q",
|
||||
pDb->zName, zWhere
|
||||
);
|
||||
iRootPage = pStat->tnum;
|
||||
}else{
|
||||
/* The sqlite_stat1 table already exists. Delete all rows. */
|
||||
iRootPage = pStat->tnum;
|
||||
sqlite3VdbeAddOp(v, OP_Clear, pStat->tnum, iDb);
|
||||
}
|
||||
|
||||
/* Open the sqlite_stat1 table for writing. Unless it was created
|
||||
** by this vdbe program, lock it for writing at the shared-cache level.
|
||||
** If this vdbe did create the sqlite_stat1 table, then it must have
|
||||
** already obtained a schema-lock, making the write-lock redundant.
|
||||
*/
|
||||
if( iRootPage>0 ){
|
||||
sqlite3TableLock(pParse, iDb, iRootPage, 1, "sqlite_stat1");
|
||||
}
|
||||
sqlite3VdbeAddOp(v, OP_Integer, iDb, 0);
|
||||
sqlite3VdbeAddOp(v, OP_OpenWrite, iStatCur, iRootPage);
|
||||
sqlite3VdbeAddOp(v, OP_SetNumColumns, iStatCur, 3);
|
||||
}
|
||||
|
||||
/*
|
||||
** Generate code to do an analysis of all indices associated with
|
||||
** a single table.
|
||||
*/
|
||||
static void analyzeOneTable(
|
||||
Parse *pParse, /* Parser context */
|
||||
Table *pTab, /* Table whose indices are to be analyzed */
|
||||
int iStatCur, /* Cursor that writes to the sqlite_stat1 table */
|
||||
int iMem /* Available memory locations begin here */
|
||||
){
|
||||
Index *pIdx; /* An index to being analyzed */
|
||||
int iIdxCur; /* Cursor number for index being analyzed */
|
||||
int nCol; /* Number of columns in the index */
|
||||
Vdbe *v; /* The virtual machine being built up */
|
||||
int i; /* Loop counter */
|
||||
int topOfLoop; /* The top of the loop */
|
||||
int endOfLoop; /* The end of the loop */
|
||||
int addr; /* The address of an instruction */
|
||||
int iDb; /* Index of database containing pTab */
|
||||
|
||||
v = sqlite3GetVdbe(pParse);
|
||||
if( v==0 || pTab==0 || pTab->pIndex==0 ){
|
||||
/* Do no analysis for tables that have no indices */
|
||||
return;
|
||||
}
|
||||
assert( sqlite3BtreeHoldsAllMutexes(pParse->db) );
|
||||
iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
|
||||
assert( iDb>=0 );
|
||||
#ifndef SQLITE_OMIT_AUTHORIZATION
|
||||
if( sqlite3AuthCheck(pParse, SQLITE_ANALYZE, pTab->zName, 0,
|
||||
pParse->db->aDb[iDb].zName ) ){
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Establish a read-lock on the table at the shared-cache level. */
|
||||
sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName);
|
||||
|
||||
iIdxCur = pParse->nTab;
|
||||
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
|
||||
KeyInfo *pKey = sqlite3IndexKeyinfo(pParse, pIdx);
|
||||
|
||||
/* Open a cursor to the index to be analyzed
|
||||
*/
|
||||
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;
|
||||
if( iMem+nCol*2>=pParse->nMem ){
|
||||
pParse->nMem = iMem+nCol*2+1;
|
||||
}
|
||||
sqlite3VdbeAddOp(v, OP_SetNumColumns, iIdxCur, nCol+1);
|
||||
|
||||
/* Memory cells are used as follows:
|
||||
**
|
||||
** mem[iMem]: The total number of rows in the table.
|
||||
** mem[iMem+1]: Number of distinct values in column 1
|
||||
** ...
|
||||
** mem[iMem+nCol]: Number of distinct values in column N
|
||||
** mem[iMem+nCol+1] Last observed value of column 1
|
||||
** ...
|
||||
** mem[iMem+nCol+nCol]: Last observed value of column N
|
||||
**
|
||||
** Cells iMem through iMem+nCol are initialized to 0. The others
|
||||
** are initialized to NULL.
|
||||
*/
|
||||
for(i=0; i<=nCol; i++){
|
||||
sqlite3VdbeAddOp(v, OP_MemInt, 0, iMem+i);
|
||||
}
|
||||
for(i=0; i<nCol; i++){
|
||||
sqlite3VdbeAddOp(v, OP_MemNull, iMem+nCol+i+1, 0);
|
||||
}
|
||||
|
||||
/* Do the analysis.
|
||||
*/
|
||||
endOfLoop = sqlite3VdbeMakeLabel(v);
|
||||
sqlite3VdbeAddOp(v, OP_Rewind, iIdxCur, endOfLoop);
|
||||
topOfLoop = sqlite3VdbeCurrentAddr(v);
|
||||
sqlite3VdbeAddOp(v, OP_MemIncr, 1, iMem);
|
||||
for(i=0; i<nCol; i++){
|
||||
sqlite3VdbeAddOp(v, OP_Column, iIdxCur, i);
|
||||
sqlite3VdbeAddOp(v, OP_MemLoad, iMem+nCol+i+1, 0);
|
||||
sqlite3VdbeAddOp(v, OP_Ne, 0x100, 0);
|
||||
}
|
||||
sqlite3VdbeAddOp(v, OP_Goto, 0, endOfLoop);
|
||||
for(i=0; i<nCol; i++){
|
||||
addr = sqlite3VdbeAddOp(v, OP_MemIncr, 1, iMem+i+1);
|
||||
sqlite3VdbeChangeP2(v, topOfLoop + 3*i + 3, addr);
|
||||
sqlite3VdbeAddOp(v, OP_Column, iIdxCur, i);
|
||||
sqlite3VdbeAddOp(v, OP_MemStore, iMem+nCol+i+1, 1);
|
||||
}
|
||||
sqlite3VdbeResolveLabel(v, endOfLoop);
|
||||
sqlite3VdbeAddOp(v, OP_Next, iIdxCur, topOfLoop);
|
||||
sqlite3VdbeAddOp(v, OP_Close, iIdxCur, 0);
|
||||
|
||||
/* Store the results.
|
||||
**
|
||||
** The result is a single row of the sqlite_stat1 table. The first
|
||||
** two columns are the names of the table and index. The third column
|
||||
** is a string composed of a list of integer statistics about the
|
||||
** index. The first integer in the list is the total number of entires
|
||||
** in the index. There is one additional integer in the list for each
|
||||
** column of the table. This additional integer is a guess of how many
|
||||
** rows of the table the index will select. If D is the count of distinct
|
||||
** values and K is the total number of rows, then the integer is computed
|
||||
** as:
|
||||
**
|
||||
** I = (K+D-1)/D
|
||||
**
|
||||
** If K==0 then no entry is made into the sqlite_stat1 table.
|
||||
** If K>0 then it is always the case the D>0 so division by zero
|
||||
** is never possible.
|
||||
*/
|
||||
sqlite3VdbeAddOp(v, OP_MemLoad, iMem, 0);
|
||||
addr = sqlite3VdbeAddOp(v, OP_IfNot, 0, 0);
|
||||
sqlite3VdbeAddOp(v, OP_NewRowid, iStatCur, 0);
|
||||
sqlite3VdbeOp3(v, OP_String8, 0, 0, pTab->zName, 0);
|
||||
sqlite3VdbeOp3(v, OP_String8, 0, 0, pIdx->zName, 0);
|
||||
sqlite3VdbeAddOp(v, OP_MemLoad, iMem, 0);
|
||||
sqlite3VdbeOp3(v, OP_String8, 0, 0, " ", 0);
|
||||
for(i=0; i<nCol; i++){
|
||||
sqlite3VdbeAddOp(v, OP_MemLoad, iMem, 0);
|
||||
sqlite3VdbeAddOp(v, OP_MemLoad, iMem+i+1, 0);
|
||||
sqlite3VdbeAddOp(v, OP_Add, 0, 0);
|
||||
sqlite3VdbeAddOp(v, OP_AddImm, -1, 0);
|
||||
sqlite3VdbeAddOp(v, OP_MemLoad, iMem+i+1, 0);
|
||||
sqlite3VdbeAddOp(v, OP_Divide, 0, 0);
|
||||
sqlite3VdbeAddOp(v, OP_ToInt, 0, 0);
|
||||
if( i==nCol-1 ){
|
||||
sqlite3VdbeAddOp(v, OP_Concat, nCol*2-1, 0);
|
||||
}else{
|
||||
sqlite3VdbeAddOp(v, OP_Dup, 1, 0);
|
||||
}
|
||||
}
|
||||
sqlite3VdbeOp3(v, OP_MakeRecord, 3, 0, "aaa", 0);
|
||||
sqlite3VdbeAddOp(v, OP_Insert, iStatCur, OPFLAG_APPEND);
|
||||
sqlite3VdbeJumpHere(v, addr);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Generate code that will cause the most recent index analysis to
|
||||
** be laoded into internal hash tables where is can be used.
|
||||
*/
|
||||
static void loadAnalysis(Parse *pParse, int iDb){
|
||||
Vdbe *v = sqlite3GetVdbe(pParse);
|
||||
if( v ){
|
||||
sqlite3VdbeAddOp(v, OP_LoadAnalysis, iDb, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Generate code that will do an analysis of an entire database
|
||||
*/
|
||||
static void analyzeDatabase(Parse *pParse, int iDb){
|
||||
sqlite3 *db = pParse->db;
|
||||
Schema *pSchema = db->aDb[iDb].pSchema; /* Schema of database iDb */
|
||||
HashElem *k;
|
||||
int iStatCur;
|
||||
int iMem;
|
||||
|
||||
sqlite3BeginWriteOperation(pParse, 0, iDb);
|
||||
iStatCur = pParse->nTab++;
|
||||
openStatTable(pParse, iDb, iStatCur, 0);
|
||||
iMem = pParse->nMem;
|
||||
for(k=sqliteHashFirst(&pSchema->tblHash); k; k=sqliteHashNext(k)){
|
||||
Table *pTab = (Table*)sqliteHashData(k);
|
||||
analyzeOneTable(pParse, pTab, iStatCur, iMem);
|
||||
}
|
||||
loadAnalysis(pParse, iDb);
|
||||
}
|
||||
|
||||
/*
|
||||
** Generate code that will do an analysis of a single table in
|
||||
** a database.
|
||||
*/
|
||||
static void analyzeTable(Parse *pParse, Table *pTab){
|
||||
int iDb;
|
||||
int iStatCur;
|
||||
|
||||
assert( pTab!=0 );
|
||||
assert( sqlite3BtreeHoldsAllMutexes(pParse->db) );
|
||||
iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
|
||||
sqlite3BeginWriteOperation(pParse, 0, iDb);
|
||||
iStatCur = pParse->nTab++;
|
||||
openStatTable(pParse, iDb, iStatCur, pTab->zName);
|
||||
analyzeOneTable(pParse, pTab, iStatCur, pParse->nMem);
|
||||
loadAnalysis(pParse, iDb);
|
||||
}
|
||||
|
||||
/*
|
||||
** Generate code for the ANALYZE command. The parser calls this routine
|
||||
** when it recognizes an ANALYZE command.
|
||||
**
|
||||
** ANALYZE -- 1
|
||||
** ANALYZE <database> -- 2
|
||||
** ANALYZE ?<database>.?<tablename> -- 3
|
||||
**
|
||||
** Form 1 causes all indices in all attached databases to be analyzed.
|
||||
** Form 2 analyzes all indices the single database named.
|
||||
** Form 3 analyzes all indices associated with the named table.
|
||||
*/
|
||||
void sqlite3Analyze(Parse *pParse, Token *pName1, Token *pName2){
|
||||
sqlite3 *db = pParse->db;
|
||||
int iDb;
|
||||
int i;
|
||||
char *z, *zDb;
|
||||
Table *pTab;
|
||||
Token *pTableName;
|
||||
|
||||
/* Read the database schema. If an error occurs, leave an error message
|
||||
** and code in pParse and return NULL. */
|
||||
assert( sqlite3BtreeHoldsAllMutexes(pParse->db) );
|
||||
if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){
|
||||
return;
|
||||
}
|
||||
|
||||
if( pName1==0 ){
|
||||
/* Form 1: Analyze everything */
|
||||
for(i=0; i<db->nDb; i++){
|
||||
if( i==1 ) continue; /* Do not analyze the TEMP database */
|
||||
analyzeDatabase(pParse, i);
|
||||
}
|
||||
}else if( pName2==0 || pName2->n==0 ){
|
||||
/* Form 2: Analyze the database or table named */
|
||||
iDb = sqlite3FindDb(db, pName1);
|
||||
if( iDb>=0 ){
|
||||
analyzeDatabase(pParse, iDb);
|
||||
}else{
|
||||
z = sqlite3NameFromToken(db, pName1);
|
||||
pTab = sqlite3LocateTable(pParse, z, 0);
|
||||
sqlite3_free(z);
|
||||
if( pTab ){
|
||||
analyzeTable(pParse, pTab);
|
||||
}
|
||||
}
|
||||
}else{
|
||||
/* Form 3: Analyze the fully qualified table name */
|
||||
iDb = sqlite3TwoPartName(pParse, pName1, pName2, &pTableName);
|
||||
if( iDb>=0 ){
|
||||
zDb = db->aDb[iDb].zName;
|
||||
z = sqlite3NameFromToken(db, pTableName);
|
||||
if( z ){
|
||||
pTab = sqlite3LocateTable(pParse, z, zDb);
|
||||
sqlite3_free(z);
|
||||
if( pTab ){
|
||||
analyzeTable(pParse, pTab);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Used to pass information from the analyzer reader through to the
|
||||
** callback routine.
|
||||
*/
|
||||
typedef struct analysisInfo analysisInfo;
|
||||
struct analysisInfo {
|
||||
sqlite3 *db;
|
||||
const char *zDatabase;
|
||||
};
|
||||
|
||||
/*
|
||||
** This callback is invoked once for each index when reading the
|
||||
** sqlite_stat1 table.
|
||||
**
|
||||
** argv[0] = name of the index
|
||||
** argv[1] = results of analysis - on integer for each column
|
||||
*/
|
||||
static int analysisLoader(void *pData, int argc, char **argv, char **azNotUsed){
|
||||
analysisInfo *pInfo = (analysisInfo*)pData;
|
||||
Index *pIndex;
|
||||
int i, c;
|
||||
unsigned int v;
|
||||
const char *z;
|
||||
|
||||
assert( argc==2 );
|
||||
if( argv==0 || argv[0]==0 || argv[1]==0 ){
|
||||
return 0;
|
||||
}
|
||||
pIndex = sqlite3FindIndex(pInfo->db, argv[0], pInfo->zDatabase);
|
||||
if( pIndex==0 ){
|
||||
return 0;
|
||||
}
|
||||
z = argv[1];
|
||||
for(i=0; *z && i<=pIndex->nColumn; i++){
|
||||
v = 0;
|
||||
while( (c=z[0])>='0' && c<='9' ){
|
||||
v = v*10 + c - '0';
|
||||
z++;
|
||||
}
|
||||
pIndex->aiRowEst[i] = v;
|
||||
if( *z==' ' ) z++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Load the content of the sqlite_stat1 table into the index hash tables.
|
||||
*/
|
||||
int sqlite3AnalysisLoad(sqlite3 *db, int iDb){
|
||||
analysisInfo sInfo;
|
||||
HashElem *i;
|
||||
char *zSql;
|
||||
int rc;
|
||||
|
||||
assert( iDb>=0 && iDb<db->nDb );
|
||||
assert( db->aDb[iDb].pBt!=0 );
|
||||
assert( sqlite3BtreeHoldsMutex(db->aDb[iDb].pBt) );
|
||||
|
||||
/* Clear any prior statistics */
|
||||
for(i=sqliteHashFirst(&db->aDb[iDb].pSchema->idxHash);i;i=sqliteHashNext(i)){
|
||||
Index *pIdx = sqliteHashData(i);
|
||||
sqlite3DefaultRowEst(pIdx);
|
||||
}
|
||||
|
||||
/* Check to make sure the sqlite_stat1 table existss */
|
||||
sInfo.db = db;
|
||||
sInfo.zDatabase = db->aDb[iDb].zName;
|
||||
if( sqlite3FindTable(db, "sqlite_stat1", sInfo.zDatabase)==0 ){
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
|
||||
|
||||
/* Load new statistics out of the sqlite_stat1 table */
|
||||
zSql = sqlite3MPrintf(db, "SELECT idx, stat FROM %Q.sqlite_stat1",
|
||||
sInfo.zDatabase);
|
||||
sqlite3SafetyOff(db);
|
||||
rc = sqlite3_exec(db, zSql, analysisLoader, &sInfo, 0);
|
||||
sqlite3SafetyOn(db);
|
||||
sqlite3_free(zSql);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
#endif /* SQLITE_OMIT_ANALYZE */
|
|
@ -0,0 +1,521 @@
|
|||
/*
|
||||
** 2003 April 6
|
||||
**
|
||||
** 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 used to implement the ATTACH and DETACH commands.
|
||||
**
|
||||
** $Id: attach.c,v 1.63 2007/10/03 08:46:44 danielk1977 Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
|
||||
#ifndef SQLITE_OMIT_ATTACH
|
||||
/*
|
||||
** Resolve an expression that was part of an ATTACH or DETACH statement. This
|
||||
** is slightly different from resolving a normal SQL expression, because simple
|
||||
** identifiers are treated as strings, not possible column names or aliases.
|
||||
**
|
||||
** i.e. if the parser sees:
|
||||
**
|
||||
** ATTACH DATABASE abc AS def
|
||||
**
|
||||
** it treats the two expressions as literal strings 'abc' and 'def' instead of
|
||||
** looking for columns of the same name.
|
||||
**
|
||||
** This only applies to the root node of pExpr, so the statement:
|
||||
**
|
||||
** ATTACH DATABASE abc||def AS 'db2'
|
||||
**
|
||||
** will fail because neither abc or def can be resolved.
|
||||
*/
|
||||
static int resolveAttachExpr(NameContext *pName, Expr *pExpr)
|
||||
{
|
||||
int rc = SQLITE_OK;
|
||||
if( pExpr ){
|
||||
if( pExpr->op!=TK_ID ){
|
||||
rc = sqlite3ExprResolveNames(pName, pExpr);
|
||||
if( rc==SQLITE_OK && !sqlite3ExprIsConstant(pExpr) ){
|
||||
sqlite3ErrorMsg(pName->pParse, "invalid name: \"%T\"", &pExpr->span);
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
}else{
|
||||
pExpr->op = TK_STRING;
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** An SQL user-function registered to do the work of an ATTACH statement. The
|
||||
** three arguments to the function come directly from an attach statement:
|
||||
**
|
||||
** ATTACH DATABASE x AS y KEY z
|
||||
**
|
||||
** SELECT sqlite_attach(x, y, z)
|
||||
**
|
||||
** If the optional "KEY z" syntax is omitted, an SQL NULL is passed as the
|
||||
** third argument.
|
||||
*/
|
||||
static void attachFunc(
|
||||
sqlite3_context *context,
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
int i;
|
||||
int rc = 0;
|
||||
sqlite3 *db = sqlite3_user_data(context);
|
||||
const char *zName;
|
||||
const char *zFile;
|
||||
Db *aNew;
|
||||
char *zErrDyn = 0;
|
||||
char zErr[128];
|
||||
|
||||
zFile = (const char *)sqlite3_value_text(argv[0]);
|
||||
zName = (const char *)sqlite3_value_text(argv[1]);
|
||||
if( zFile==0 ) zFile = "";
|
||||
if( zName==0 ) zName = "";
|
||||
|
||||
/* Check for the following errors:
|
||||
**
|
||||
** * Too many attached databases,
|
||||
** * Transaction currently open
|
||||
** * Specified database name already being used.
|
||||
*/
|
||||
if( db->nDb>=SQLITE_MAX_ATTACHED+2 ){
|
||||
sqlite3_snprintf(
|
||||
sizeof(zErr), zErr, "too many attached databases - max %d",
|
||||
SQLITE_MAX_ATTACHED
|
||||
);
|
||||
goto attach_error;
|
||||
}
|
||||
if( !db->autoCommit ){
|
||||
sqlite3_snprintf(sizeof(zErr), zErr,
|
||||
"cannot ATTACH database within transaction");
|
||||
goto attach_error;
|
||||
}
|
||||
for(i=0; i<db->nDb; i++){
|
||||
char *z = db->aDb[i].zName;
|
||||
if( z && zName && sqlite3StrICmp(z, zName)==0 ){
|
||||
sqlite3_snprintf(sizeof(zErr), zErr,
|
||||
"database %s is already in use", zName);
|
||||
goto attach_error;
|
||||
}
|
||||
}
|
||||
|
||||
/* Allocate the new entry in the db->aDb[] array and initialise the schema
|
||||
** hash tables.
|
||||
*/
|
||||
if( db->aDb==db->aDbStatic ){
|
||||
aNew = sqlite3_malloc( sizeof(db->aDb[0])*3 );
|
||||
if( aNew==0 ){
|
||||
db->mallocFailed = 1;
|
||||
return;
|
||||
}
|
||||
memcpy(aNew, db->aDb, sizeof(db->aDb[0])*2);
|
||||
}else{
|
||||
aNew = sqlite3_realloc(db->aDb, sizeof(db->aDb[0])*(db->nDb+1) );
|
||||
if( aNew==0 ){
|
||||
db->mallocFailed = 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
db->aDb = aNew;
|
||||
aNew = &db->aDb[db->nDb++];
|
||||
memset(aNew, 0, sizeof(*aNew));
|
||||
|
||||
/* Open the database file. If the btree is successfully opened, use
|
||||
** it to obtain the database schema. At this point the schema may
|
||||
** or may not be initialised.
|
||||
*/
|
||||
rc = sqlite3BtreeFactory(db, zFile, 0, SQLITE_DEFAULT_CACHE_SIZE,
|
||||
db->openFlags | SQLITE_OPEN_MAIN_DB,
|
||||
&aNew->pBt);
|
||||
if( rc==SQLITE_OK ){
|
||||
aNew->pSchema = sqlite3SchemaGet(db, aNew->pBt);
|
||||
if( !aNew->pSchema ){
|
||||
rc = SQLITE_NOMEM;
|
||||
}else if( aNew->pSchema->file_format && aNew->pSchema->enc!=ENC(db) ){
|
||||
sqlite3_snprintf(sizeof(zErr), zErr,
|
||||
"attached databases must use the same text encoding as main database");
|
||||
goto attach_error;
|
||||
}
|
||||
sqlite3PagerLockingMode(sqlite3BtreePager(aNew->pBt), db->dfltLockMode);
|
||||
}
|
||||
aNew->zName = sqlite3DbStrDup(db, zName);
|
||||
aNew->safety_level = 3;
|
||||
|
||||
#if SQLITE_HAS_CODEC
|
||||
{
|
||||
extern int sqlite3CodecAttach(sqlite3*, int, const void*, int);
|
||||
extern void sqlite3CodecGetKey(sqlite3*, int, void**, int*);
|
||||
int nKey;
|
||||
char *zKey;
|
||||
int t = sqlite3_value_type(argv[2]);
|
||||
switch( t ){
|
||||
case SQLITE_INTEGER:
|
||||
case SQLITE_FLOAT:
|
||||
zErrDyn = sqlite3DbStrDup(db, "Invalid key value");
|
||||
rc = SQLITE_ERROR;
|
||||
break;
|
||||
|
||||
case SQLITE_TEXT:
|
||||
case SQLITE_BLOB:
|
||||
nKey = sqlite3_value_bytes(argv[2]);
|
||||
zKey = (char *)sqlite3_value_blob(argv[2]);
|
||||
sqlite3CodecAttach(db, db->nDb-1, zKey, nKey);
|
||||
break;
|
||||
|
||||
case SQLITE_NULL:
|
||||
/* No key specified. Use the key from the main database */
|
||||
sqlite3CodecGetKey(db, 0, (void**)&zKey, &nKey);
|
||||
sqlite3CodecAttach(db, db->nDb-1, zKey, nKey);
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* If the file was opened successfully, read the schema for the new database.
|
||||
** If this fails, or if opening the file failed, then close the file and
|
||||
** remove the entry from the db->aDb[] array. i.e. put everything back the way
|
||||
** we found it.
|
||||
*/
|
||||
if( rc==SQLITE_OK ){
|
||||
sqlite3SafetyOn(db);
|
||||
rc = sqlite3Init(db, &zErrDyn);
|
||||
sqlite3SafetyOff(db);
|
||||
}
|
||||
if( rc ){
|
||||
int iDb = db->nDb - 1;
|
||||
assert( iDb>=2 );
|
||||
if( db->aDb[iDb].pBt ){
|
||||
sqlite3BtreeClose(db->aDb[iDb].pBt);
|
||||
db->aDb[iDb].pBt = 0;
|
||||
db->aDb[iDb].pSchema = 0;
|
||||
}
|
||||
sqlite3ResetInternalSchema(db, 0);
|
||||
db->nDb = iDb;
|
||||
if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ){
|
||||
db->mallocFailed = 1;
|
||||
sqlite3_snprintf(sizeof(zErr),zErr, "out of memory");
|
||||
}else{
|
||||
sqlite3_snprintf(sizeof(zErr),zErr, "unable to open database: %s", zFile);
|
||||
}
|
||||
goto attach_error;
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
attach_error:
|
||||
/* Return an error if we get here */
|
||||
if( zErrDyn ){
|
||||
sqlite3_result_error(context, zErrDyn, -1);
|
||||
sqlite3_free(zErrDyn);
|
||||
}else{
|
||||
zErr[sizeof(zErr)-1] = 0;
|
||||
sqlite3_result_error(context, zErr, -1);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** An SQL user-function registered to do the work of an DETACH statement. The
|
||||
** three arguments to the function come directly from a detach statement:
|
||||
**
|
||||
** DETACH DATABASE x
|
||||
**
|
||||
** SELECT sqlite_detach(x)
|
||||
*/
|
||||
static void detachFunc(
|
||||
sqlite3_context *context,
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
const char *zName = (const char *)sqlite3_value_text(argv[0]);
|
||||
sqlite3 *db = sqlite3_user_data(context);
|
||||
int i;
|
||||
Db *pDb = 0;
|
||||
char zErr[128];
|
||||
|
||||
if( zName==0 ) zName = "";
|
||||
for(i=0; i<db->nDb; i++){
|
||||
pDb = &db->aDb[i];
|
||||
if( pDb->pBt==0 ) continue;
|
||||
if( sqlite3StrICmp(pDb->zName, zName)==0 ) break;
|
||||
}
|
||||
|
||||
if( i>=db->nDb ){
|
||||
sqlite3_snprintf(sizeof(zErr),zErr, "no such database: %s", zName);
|
||||
goto detach_error;
|
||||
}
|
||||
if( i<2 ){
|
||||
sqlite3_snprintf(sizeof(zErr),zErr, "cannot detach database %s", zName);
|
||||
goto detach_error;
|
||||
}
|
||||
if( !db->autoCommit ){
|
||||
sqlite3_snprintf(sizeof(zErr), zErr,
|
||||
"cannot DETACH database within transaction");
|
||||
goto detach_error;
|
||||
}
|
||||
if( sqlite3BtreeIsInReadTrans(pDb->pBt) ){
|
||||
sqlite3_snprintf(sizeof(zErr),zErr, "database %s is locked", zName);
|
||||
goto detach_error;
|
||||
}
|
||||
|
||||
sqlite3BtreeClose(pDb->pBt);
|
||||
pDb->pBt = 0;
|
||||
pDb->pSchema = 0;
|
||||
sqlite3ResetInternalSchema(db, 0);
|
||||
return;
|
||||
|
||||
detach_error:
|
||||
sqlite3_result_error(context, zErr, -1);
|
||||
}
|
||||
|
||||
/*
|
||||
** This procedure generates VDBE code for a single invocation of either the
|
||||
** sqlite_detach() or sqlite_attach() SQL user functions.
|
||||
*/
|
||||
static void codeAttach(
|
||||
Parse *pParse, /* The parser context */
|
||||
int type, /* Either SQLITE_ATTACH or SQLITE_DETACH */
|
||||
const char *zFunc, /* Either "sqlite_attach" or "sqlite_detach */
|
||||
int nFunc, /* Number of args to pass to zFunc */
|
||||
Expr *pAuthArg, /* Expression to pass to authorization callback */
|
||||
Expr *pFilename, /* Name of database file */
|
||||
Expr *pDbname, /* Name of the database to use internally */
|
||||
Expr *pKey /* Database key for encryption extension */
|
||||
){
|
||||
int rc;
|
||||
NameContext sName;
|
||||
Vdbe *v;
|
||||
FuncDef *pFunc;
|
||||
sqlite3* db = pParse->db;
|
||||
|
||||
#ifndef SQLITE_OMIT_AUTHORIZATION
|
||||
assert( db->mallocFailed || pAuthArg );
|
||||
if( pAuthArg ){
|
||||
char *zAuthArg = sqlite3NameFromToken(db, &pAuthArg->span);
|
||||
if( !zAuthArg ){
|
||||
goto attach_end;
|
||||
}
|
||||
rc = sqlite3AuthCheck(pParse, type, zAuthArg, 0, 0);
|
||||
sqlite3_free(zAuthArg);
|
||||
if(rc!=SQLITE_OK ){
|
||||
goto attach_end;
|
||||
}
|
||||
}
|
||||
#endif /* SQLITE_OMIT_AUTHORIZATION */
|
||||
|
||||
memset(&sName, 0, sizeof(NameContext));
|
||||
sName.pParse = pParse;
|
||||
|
||||
if(
|
||||
SQLITE_OK!=(rc = resolveAttachExpr(&sName, pFilename)) ||
|
||||
SQLITE_OK!=(rc = resolveAttachExpr(&sName, pDbname)) ||
|
||||
SQLITE_OK!=(rc = resolveAttachExpr(&sName, pKey))
|
||||
){
|
||||
pParse->nErr++;
|
||||
goto attach_end;
|
||||
}
|
||||
|
||||
v = sqlite3GetVdbe(pParse);
|
||||
sqlite3ExprCode(pParse, pFilename);
|
||||
sqlite3ExprCode(pParse, pDbname);
|
||||
sqlite3ExprCode(pParse, pKey);
|
||||
|
||||
assert( v || db->mallocFailed );
|
||||
if( v ){
|
||||
sqlite3VdbeAddOp(v, OP_Function, 0, nFunc);
|
||||
pFunc = sqlite3FindFunction(db, zFunc, strlen(zFunc), nFunc, SQLITE_UTF8,0);
|
||||
sqlite3VdbeChangeP3(v, -1, (char *)pFunc, P3_FUNCDEF);
|
||||
|
||||
/* Code an OP_Expire. For an ATTACH statement, set P1 to true (expire this
|
||||
** statement only). For DETACH, set it to false (expire all existing
|
||||
** statements).
|
||||
*/
|
||||
sqlite3VdbeAddOp(v, OP_Expire, (type==SQLITE_ATTACH), 0);
|
||||
}
|
||||
|
||||
attach_end:
|
||||
sqlite3ExprDelete(pFilename);
|
||||
sqlite3ExprDelete(pDbname);
|
||||
sqlite3ExprDelete(pKey);
|
||||
}
|
||||
|
||||
/*
|
||||
** Called by the parser to compile a DETACH statement.
|
||||
**
|
||||
** DETACH pDbname
|
||||
*/
|
||||
void sqlite3Detach(Parse *pParse, Expr *pDbname){
|
||||
codeAttach(pParse, SQLITE_DETACH, "sqlite_detach", 1, pDbname, 0, 0, pDbname);
|
||||
}
|
||||
|
||||
/*
|
||||
** Called by the parser to compile an ATTACH statement.
|
||||
**
|
||||
** ATTACH p AS pDbname KEY pKey
|
||||
*/
|
||||
void sqlite3Attach(Parse *pParse, Expr *p, Expr *pDbname, Expr *pKey){
|
||||
codeAttach(pParse, SQLITE_ATTACH, "sqlite_attach", 3, p, p, pDbname, pKey);
|
||||
}
|
||||
#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
|
||||
** to passing the structure to one of the sqliteFixAAAA() routines below.
|
||||
**
|
||||
** The return value indicates whether or not fixation is required. TRUE
|
||||
** means we do need to fix the database references, FALSE means we do not.
|
||||
*/
|
||||
int sqlite3FixInit(
|
||||
DbFixer *pFix, /* The fixer to be initialized */
|
||||
Parse *pParse, /* Error messages will be written here */
|
||||
int iDb, /* This is the database that must be used */
|
||||
const char *zType, /* "view", "trigger", or "index" */
|
||||
const Token *pName /* Name of the view, trigger, or index */
|
||||
){
|
||||
sqlite3 *db;
|
||||
|
||||
if( iDb<0 || iDb==1 ) return 0;
|
||||
db = pParse->db;
|
||||
assert( db->nDb>iDb );
|
||||
pFix->pParse = pParse;
|
||||
pFix->zDb = db->aDb[iDb].zName;
|
||||
pFix->zType = zType;
|
||||
pFix->pName = pName;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
** The following set of routines walk through the parse tree and assign
|
||||
** a specific database to all table references where the database name
|
||||
** was left unspecified in the original SQL statement. The pFix structure
|
||||
** must have been initialized by a prior call to sqlite3FixInit().
|
||||
**
|
||||
** These routines are used to make sure that an index, trigger, or
|
||||
** view in one database does not refer to objects in a different database.
|
||||
** (Exception: indices, triggers, and views in the TEMP database are
|
||||
** allowed to refer to anything.) If a reference is explicitly made
|
||||
** to an object in a different database, an error message is added to
|
||||
** pParse->zErrMsg and these routines return non-zero. If everything
|
||||
** checks out, these routines return 0.
|
||||
*/
|
||||
int sqlite3FixSrcList(
|
||||
DbFixer *pFix, /* Context of the fixation */
|
||||
SrcList *pList /* The Source list to check and modify */
|
||||
){
|
||||
int i;
|
||||
const char *zDb;
|
||||
struct SrcList_item *pItem;
|
||||
|
||||
if( pList==0 ) return 0;
|
||||
zDb = pFix->zDb;
|
||||
for(i=0, pItem=pList->a; i<pList->nSrc; i++, pItem++){
|
||||
if( pItem->zDatabase==0 ){
|
||||
pItem->zDatabase = sqlite3DbStrDup(pFix->pParse->db, zDb);
|
||||
}else if( sqlite3StrICmp(pItem->zDatabase,zDb)!=0 ){
|
||||
sqlite3ErrorMsg(pFix->pParse,
|
||||
"%s %T cannot reference objects in database %s",
|
||||
pFix->zType, pFix->pName, pItem->zDatabase);
|
||||
return 1;
|
||||
}
|
||||
#if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_TRIGGER)
|
||||
if( sqlite3FixSelect(pFix, pItem->pSelect) ) return 1;
|
||||
if( sqlite3FixExpr(pFix, pItem->pOn) ) return 1;
|
||||
#endif
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_TRIGGER)
|
||||
int sqlite3FixSelect(
|
||||
DbFixer *pFix, /* Context of the fixation */
|
||||
Select *pSelect /* The SELECT statement to be fixed to one database */
|
||||
){
|
||||
while( pSelect ){
|
||||
if( sqlite3FixExprList(pFix, pSelect->pEList) ){
|
||||
return 1;
|
||||
}
|
||||
if( sqlite3FixSrcList(pFix, pSelect->pSrc) ){
|
||||
return 1;
|
||||
}
|
||||
if( sqlite3FixExpr(pFix, pSelect->pWhere) ){
|
||||
return 1;
|
||||
}
|
||||
if( sqlite3FixExpr(pFix, pSelect->pHaving) ){
|
||||
return 1;
|
||||
}
|
||||
pSelect = pSelect->pPrior;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
int sqlite3FixExpr(
|
||||
DbFixer *pFix, /* Context of the fixation */
|
||||
Expr *pExpr /* The expression to be fixed to one database */
|
||||
){
|
||||
while( pExpr ){
|
||||
if( sqlite3FixSelect(pFix, pExpr->pSelect) ){
|
||||
return 1;
|
||||
}
|
||||
if( sqlite3FixExprList(pFix, pExpr->pList) ){
|
||||
return 1;
|
||||
}
|
||||
if( sqlite3FixExpr(pFix, pExpr->pRight) ){
|
||||
return 1;
|
||||
}
|
||||
pExpr = pExpr->pLeft;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
int sqlite3FixExprList(
|
||||
DbFixer *pFix, /* Context of the fixation */
|
||||
ExprList *pList /* The expression to be fixed to one database */
|
||||
){
|
||||
int i;
|
||||
struct ExprList_item *pItem;
|
||||
if( pList==0 ) return 0;
|
||||
for(i=0, pItem=pList->a; i<pList->nExpr; i++, pItem++){
|
||||
if( sqlite3FixExpr(pFix, pItem->pExpr) ){
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef SQLITE_OMIT_TRIGGER
|
||||
int sqlite3FixTriggerStep(
|
||||
DbFixer *pFix, /* Context of the fixation */
|
||||
TriggerStep *pStep /* The trigger step be fixed to one database */
|
||||
){
|
||||
while( pStep ){
|
||||
if( sqlite3FixSelect(pFix, pStep->pSelect) ){
|
||||
return 1;
|
||||
}
|
||||
if( sqlite3FixExpr(pFix, pStep->pWhere) ){
|
||||
return 1;
|
||||
}
|
||||
if( sqlite3FixExprList(pFix, pStep->pExprList) ){
|
||||
return 1;
|
||||
}
|
||||
pStep = pStep->pNext;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,234 @@
|
|||
/*
|
||||
** 2003 January 11
|
||||
**
|
||||
** 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 used to implement the sqlite3_set_authorizer()
|
||||
** API. This facility is an optional feature of the library. Embedded
|
||||
** systems that do not need this facility may omit it by recompiling
|
||||
** the library with -DSQLITE_OMIT_AUTHORIZATION=1
|
||||
**
|
||||
** $Id: auth.c,v 1.29 2007/09/18 15:55:07 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
|
||||
/*
|
||||
** All of the code in this file may be omitted by defining a single
|
||||
** macro.
|
||||
*/
|
||||
#ifndef SQLITE_OMIT_AUTHORIZATION
|
||||
|
||||
/*
|
||||
** Set or clear the access authorization function.
|
||||
**
|
||||
** The access authorization function is be called during the compilation
|
||||
** phase to verify that the user has read and/or write access permission on
|
||||
** various fields of the database. The first argument to the auth function
|
||||
** is a copy of the 3rd argument to this routine. The second argument
|
||||
** to the auth function is one of these constants:
|
||||
**
|
||||
** SQLITE_CREATE_INDEX
|
||||
** SQLITE_CREATE_TABLE
|
||||
** SQLITE_CREATE_TEMP_INDEX
|
||||
** SQLITE_CREATE_TEMP_TABLE
|
||||
** SQLITE_CREATE_TEMP_TRIGGER
|
||||
** SQLITE_CREATE_TEMP_VIEW
|
||||
** SQLITE_CREATE_TRIGGER
|
||||
** SQLITE_CREATE_VIEW
|
||||
** SQLITE_DELETE
|
||||
** SQLITE_DROP_INDEX
|
||||
** SQLITE_DROP_TABLE
|
||||
** SQLITE_DROP_TEMP_INDEX
|
||||
** SQLITE_DROP_TEMP_TABLE
|
||||
** SQLITE_DROP_TEMP_TRIGGER
|
||||
** SQLITE_DROP_TEMP_VIEW
|
||||
** SQLITE_DROP_TRIGGER
|
||||
** SQLITE_DROP_VIEW
|
||||
** SQLITE_INSERT
|
||||
** SQLITE_PRAGMA
|
||||
** SQLITE_READ
|
||||
** SQLITE_SELECT
|
||||
** SQLITE_TRANSACTION
|
||||
** SQLITE_UPDATE
|
||||
**
|
||||
** The third and fourth arguments to the auth function are the name of
|
||||
** the table and the column that are being accessed. The auth function
|
||||
** should return either SQLITE_OK, SQLITE_DENY, or SQLITE_IGNORE. If
|
||||
** SQLITE_OK is returned, it means that access is allowed. SQLITE_DENY
|
||||
** means that the SQL statement will never-run - the sqlite3_exec() call
|
||||
** will return with an error. SQLITE_IGNORE means that the SQL statement
|
||||
** should run but attempts to read the specified column will return NULL
|
||||
** and attempts to write the column will be ignored.
|
||||
**
|
||||
** Setting the auth function to NULL disables this hook. The default
|
||||
** setting of the auth function is NULL.
|
||||
*/
|
||||
int sqlite3_set_authorizer(
|
||||
sqlite3 *db,
|
||||
int (*xAuth)(void*,int,const char*,const char*,const char*,const char*),
|
||||
void *pArg
|
||||
){
|
||||
sqlite3_mutex_enter(db->mutex);
|
||||
db->xAuth = xAuth;
|
||||
db->pAuthArg = pArg;
|
||||
sqlite3ExpirePreparedStatements(db);
|
||||
sqlite3_mutex_leave(db->mutex);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Write an error message into pParse->zErrMsg that explains that the
|
||||
** user-supplied authorization function returned an illegal value.
|
||||
*/
|
||||
static void sqliteAuthBadReturnCode(Parse *pParse, int rc){
|
||||
sqlite3ErrorMsg(pParse, "illegal return value (%d) from the "
|
||||
"authorization function - should be SQLITE_OK, SQLITE_IGNORE, "
|
||||
"or SQLITE_DENY", rc);
|
||||
pParse->rc = SQLITE_ERROR;
|
||||
}
|
||||
|
||||
/*
|
||||
** The pExpr should be a TK_COLUMN expression. The table referred to
|
||||
** is in pTabList or else it is the NEW or OLD table of a trigger.
|
||||
** Check to see if it is OK to read this particular column.
|
||||
**
|
||||
** If the auth function returns SQLITE_IGNORE, change the TK_COLUMN
|
||||
** instruction into a TK_NULL. If the auth function returns SQLITE_DENY,
|
||||
** then generate an error.
|
||||
*/
|
||||
void sqlite3AuthRead(
|
||||
Parse *pParse, /* The parser context */
|
||||
Expr *pExpr, /* The expression to check authorization on */
|
||||
Schema *pSchema, /* The schema of the expression */
|
||||
SrcList *pTabList /* All table that pExpr might refer to */
|
||||
){
|
||||
sqlite3 *db = pParse->db;
|
||||
int rc;
|
||||
Table *pTab = 0; /* The table being read */
|
||||
const char *zCol; /* Name of the column of the table */
|
||||
int iSrc; /* Index in pTabList->a[] of table being read */
|
||||
const char *zDBase; /* Name of database being accessed */
|
||||
TriggerStack *pStack; /* The stack of current triggers */
|
||||
int iDb; /* The index of the database the expression refers to */
|
||||
|
||||
if( db->xAuth==0 ) return;
|
||||
if( pExpr->op!=TK_COLUMN ) return;
|
||||
iDb = sqlite3SchemaToIndex(pParse->db, pSchema);
|
||||
if( iDb<0 ){
|
||||
/* An attempt to read a column out of a subquery or other
|
||||
** temporary table. */
|
||||
return;
|
||||
}
|
||||
for(iSrc=0; pTabList && iSrc<pTabList->nSrc; iSrc++){
|
||||
if( pExpr->iTable==pTabList->a[iSrc].iCursor ) break;
|
||||
}
|
||||
if( iSrc>=0 && pTabList && iSrc<pTabList->nSrc ){
|
||||
pTab = pTabList->a[iSrc].pTab;
|
||||
}else if( (pStack = pParse->trigStack)!=0 ){
|
||||
/* This must be an attempt to read the NEW or OLD pseudo-tables
|
||||
** of a trigger.
|
||||
*/
|
||||
assert( pExpr->iTable==pStack->newIdx || pExpr->iTable==pStack->oldIdx );
|
||||
pTab = pStack->pTab;
|
||||
}
|
||||
if( pTab==0 ) return;
|
||||
if( pExpr->iColumn>=0 ){
|
||||
assert( pExpr->iColumn<pTab->nCol );
|
||||
zCol = pTab->aCol[pExpr->iColumn].zName;
|
||||
}else if( pTab->iPKey>=0 ){
|
||||
assert( pTab->iPKey<pTab->nCol );
|
||||
zCol = pTab->aCol[pTab->iPKey].zName;
|
||||
}else{
|
||||
zCol = "ROWID";
|
||||
}
|
||||
assert( iDb>=0 && iDb<db->nDb );
|
||||
zDBase = db->aDb[iDb].zName;
|
||||
rc = db->xAuth(db->pAuthArg, SQLITE_READ, pTab->zName, zCol, zDBase,
|
||||
pParse->zAuthContext);
|
||||
if( rc==SQLITE_IGNORE ){
|
||||
pExpr->op = TK_NULL;
|
||||
}else if( rc==SQLITE_DENY ){
|
||||
if( db->nDb>2 || iDb!=0 ){
|
||||
sqlite3ErrorMsg(pParse, "access to %s.%s.%s is prohibited",
|
||||
zDBase, pTab->zName, zCol);
|
||||
}else{
|
||||
sqlite3ErrorMsg(pParse, "access to %s.%s is prohibited",pTab->zName,zCol);
|
||||
}
|
||||
pParse->rc = SQLITE_AUTH;
|
||||
}else if( rc!=SQLITE_OK ){
|
||||
sqliteAuthBadReturnCode(pParse, rc);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Do an authorization check using the code and arguments given. Return
|
||||
** either SQLITE_OK (zero) or SQLITE_IGNORE or SQLITE_DENY. If SQLITE_DENY
|
||||
** is returned, then the error count and error message in pParse are
|
||||
** modified appropriately.
|
||||
*/
|
||||
int sqlite3AuthCheck(
|
||||
Parse *pParse,
|
||||
int code,
|
||||
const char *zArg1,
|
||||
const char *zArg2,
|
||||
const char *zArg3
|
||||
){
|
||||
sqlite3 *db = pParse->db;
|
||||
int rc;
|
||||
|
||||
/* Don't do any authorization checks if the database is initialising
|
||||
** or if the parser is being invoked from within sqlite3_declare_vtab.
|
||||
*/
|
||||
if( db->init.busy || IN_DECLARE_VTAB ){
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
if( db->xAuth==0 ){
|
||||
return SQLITE_OK;
|
||||
}
|
||||
rc = db->xAuth(db->pAuthArg, code, zArg1, zArg2, zArg3, pParse->zAuthContext);
|
||||
if( rc==SQLITE_DENY ){
|
||||
sqlite3ErrorMsg(pParse, "not authorized");
|
||||
pParse->rc = SQLITE_AUTH;
|
||||
}else if( rc!=SQLITE_OK && rc!=SQLITE_IGNORE ){
|
||||
rc = SQLITE_DENY;
|
||||
sqliteAuthBadReturnCode(pParse, rc);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Push an authorization context. After this routine is called, the
|
||||
** zArg3 argument to authorization callbacks will be zContext until
|
||||
** popped. Or if pParse==0, this routine is a no-op.
|
||||
*/
|
||||
void sqlite3AuthContextPush(
|
||||
Parse *pParse,
|
||||
AuthContext *pContext,
|
||||
const char *zContext
|
||||
){
|
||||
pContext->pParse = pParse;
|
||||
if( pParse ){
|
||||
pContext->zAuthContext = pParse->zAuthContext;
|
||||
pParse->zAuthContext = zContext;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Pop an authorization context that was previously pushed
|
||||
** by sqlite3AuthContextPush
|
||||
*/
|
||||
void sqlite3AuthContextPop(AuthContext *pContext){
|
||||
if( pContext->pParse ){
|
||||
pContext->pParse->zAuthContext = pContext->zAuthContext;
|
||||
pContext->pParse = 0;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* SQLITE_OMIT_AUTHORIZATION */
|
|
@ -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.7 2007/08/30 01:19:59 drh 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->pSqlite==p->pSqlite );
|
||||
assert( p->pPrev==0 || p->pPrev->pSqlite==p->pSqlite );
|
||||
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->pSqlite->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 */
|
||||
|
||||
/*
|
||||
** Potentially dd a new Btree pointer to a BtreeMutexArray.
|
||||
** Really only add the Btree if it can possibly be shared with
|
||||
** another database connection.
|
||||
**
|
||||
** The Btrees 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<sizeof(pArray->aBtree)/sizeof(pArray->aBtree[0])-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->pSqlite->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->pSqlite->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 */
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,204 @@
|
|||
/*
|
||||
** 2001 September 15
|
||||
**
|
||||
** The author disclaims copyright to this source code. In place of
|
||||
** a legal notice, here is a blessing:
|
||||
**
|
||||
** May you do good and not evil.
|
||||
** May you find forgiveness for yourself and forgive others.
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
*************************************************************************
|
||||
** This header file defines the interface that the sqlite B-Tree file
|
||||
** subsystem. See comments in the source code for a detailed description
|
||||
** of what each interface routine does.
|
||||
**
|
||||
** @(#) $Id: btree.h,v 1.93 2007/09/03 15:19:35 drh Exp $
|
||||
*/
|
||||
#ifndef _BTREE_H_
|
||||
#define _BTREE_H_
|
||||
|
||||
/* TODO: This definition is just included so other modules compile. It
|
||||
** needs to be revisited.
|
||||
*/
|
||||
#define SQLITE_N_BTREE_META 10
|
||||
|
||||
/*
|
||||
** 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_AUTOVACUUM
|
||||
#define SQLITE_DEFAULT_AUTOVACUUM 0
|
||||
#endif
|
||||
|
||||
#define BTREE_AUTOVACUUM_NONE 0 /* Do not do auto-vacuum */
|
||||
#define BTREE_AUTOVACUUM_FULL 1 /* Do full auto-vacuum */
|
||||
#define BTREE_AUTOVACUUM_INCR 2 /* Incremental vacuum */
|
||||
|
||||
/*
|
||||
** Forward declarations of structure
|
||||
*/
|
||||
typedef struct Btree Btree;
|
||||
typedef struct BtCursor BtCursor;
|
||||
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(
|
||||
const char *zFilename, /* Name of database file to open */
|
||||
sqlite3 *db, /* Associated database connection */
|
||||
Btree **, /* Return open Btree* here */
|
||||
int flags, /* Flags */
|
||||
int vfsFlags /* Flags passed through to VFS open */
|
||||
);
|
||||
|
||||
/* The flags parameter to sqlite3BtreeOpen can be the bitwise or of the
|
||||
** following values.
|
||||
**
|
||||
** NOTE: These values must match the corresponding PAGER_ values in
|
||||
** pager.h.
|
||||
*/
|
||||
#define BTREE_OMIT_JOURNAL 1 /* Do not use journal. No argument */
|
||||
#define BTREE_NO_READLOCK 2 /* Omit readlocks on readonly files */
|
||||
#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 */
|
||||
|
||||
/* Additional values for the 4th argument of sqlite3BtreeOpen that
|
||||
** are not associated with PAGER_ values.
|
||||
*/
|
||||
#define BTREE_PRIVATE 64 /* Never share with other connections */
|
||||
|
||||
int sqlite3BtreeClose(Btree*);
|
||||
int sqlite3BtreeSetBusyHandler(Btree*,BusyHandler*);
|
||||
int sqlite3BtreeSetCacheSize(Btree*,int);
|
||||
int sqlite3BtreeSetSafetyLevel(Btree*,int,int);
|
||||
int sqlite3BtreeSyncDisabled(Btree*);
|
||||
int sqlite3BtreeSetPageSize(Btree*,int,int);
|
||||
int sqlite3BtreeGetPageSize(Btree*);
|
||||
int sqlite3BtreeMaxPageCount(Btree*,int);
|
||||
int sqlite3BtreeGetReserve(Btree*);
|
||||
int sqlite3BtreeSetAutoVacuum(Btree *, int);
|
||||
int sqlite3BtreeGetAutoVacuum(Btree *);
|
||||
int sqlite3BtreeBeginTrans(Btree*,int);
|
||||
int sqlite3BtreeCommitPhaseOne(Btree*, const char *zMaster);
|
||||
int sqlite3BtreeCommitPhaseTwo(Btree*);
|
||||
int sqlite3BtreeCommit(Btree*);
|
||||
int sqlite3BtreeRollback(Btree*);
|
||||
int sqlite3BtreeBeginStmt(Btree*);
|
||||
int sqlite3BtreeCommitStmt(Btree*);
|
||||
int sqlite3BtreeRollbackStmt(Btree*);
|
||||
int sqlite3BtreeCreateTable(Btree*, int*, int flags);
|
||||
int sqlite3BtreeIsInTrans(Btree*);
|
||||
int sqlite3BtreeIsInStmt(Btree*);
|
||||
int sqlite3BtreeIsInReadTrans(Btree*);
|
||||
void *sqlite3BtreeSchema(Btree *, int, void(*)(void *));
|
||||
int sqlite3BtreeSchemaLocked(Btree *);
|
||||
int sqlite3BtreeLockTable(Btree *, int, u8);
|
||||
|
||||
const char *sqlite3BtreeGetFilename(Btree *);
|
||||
const char *sqlite3BtreeGetDirname(Btree *);
|
||||
const char *sqlite3BtreeGetJournalname(Btree *);
|
||||
int sqlite3BtreeCopyFile(Btree *, Btree *);
|
||||
|
||||
int sqlite3BtreeIncrVacuum(Btree *);
|
||||
|
||||
/* The flags parameter to sqlite3BtreeCreateTable can be the bitwise OR
|
||||
** of the following flags:
|
||||
*/
|
||||
#define BTREE_INTKEY 1 /* Table has only 64-bit signed integer keys */
|
||||
#define BTREE_ZERODATA 2 /* Table has keys only - no data */
|
||||
#define BTREE_LEAFDATA 4 /* Data stored in leaves only. Implies INTKEY */
|
||||
|
||||
int sqlite3BtreeDropTable(Btree*, int, int*);
|
||||
int sqlite3BtreeClearTable(Btree*, int);
|
||||
int sqlite3BtreeGetMeta(Btree*, int idx, u32 *pValue);
|
||||
int sqlite3BtreeUpdateMeta(Btree*, int idx, u32 value);
|
||||
void sqlite3BtreeTripAllCursors(Btree*, int);
|
||||
|
||||
int sqlite3BtreeCursor(
|
||||
Btree*, /* BTree containing table to open */
|
||||
int iTable, /* Index of root page */
|
||||
int wrFlag, /* 1 for writing. 0 for read-only */
|
||||
int(*)(void*,int,const void*,int,const void*), /* Key comparison function */
|
||||
void*, /* First argument to compare function */
|
||||
BtCursor **ppCursor /* Returned cursor */
|
||||
);
|
||||
|
||||
int sqlite3BtreeCloseCursor(BtCursor*);
|
||||
int sqlite3BtreeMoveto(BtCursor*,const void *pKey,i64 nKey,int bias,int *pRes);
|
||||
int sqlite3BtreeDelete(BtCursor*);
|
||||
int sqlite3BtreeInsert(BtCursor*, const void *pKey, i64 nKey,
|
||||
const void *pData, int nData,
|
||||
int nZero, int bias);
|
||||
int sqlite3BtreeFirst(BtCursor*, int *pRes);
|
||||
int sqlite3BtreeLast(BtCursor*, int *pRes);
|
||||
int sqlite3BtreeNext(BtCursor*, int *pRes);
|
||||
int sqlite3BtreeEof(BtCursor*);
|
||||
int sqlite3BtreeFlags(BtCursor*);
|
||||
int sqlite3BtreePrevious(BtCursor*, int *pRes);
|
||||
int sqlite3BtreeKeySize(BtCursor*, i64 *pSize);
|
||||
int sqlite3BtreeKey(BtCursor*, u32 offset, u32 amt, void*);
|
||||
sqlite3 *sqlite3BtreeCursorDb(const BtCursor*);
|
||||
const void *sqlite3BtreeKeyFetch(BtCursor*, int *pAmt);
|
||||
const void *sqlite3BtreeDataFetch(BtCursor*, int *pAmt);
|
||||
int sqlite3BtreeDataSize(BtCursor*, u32 *pSize);
|
||||
int sqlite3BtreeData(BtCursor*, u32 offset, u32 amt, void*);
|
||||
|
||||
char *sqlite3BtreeIntegrityCheck(Btree*, int *aRoot, int nRoot, int, int*);
|
||||
struct Pager *sqlite3BtreePager(Btree*);
|
||||
|
||||
int sqlite3BtreePutData(BtCursor*, u32 offset, u32 amt, void*);
|
||||
void sqlite3BtreeCacheOverflow(BtCursor *);
|
||||
|
||||
#ifdef SQLITE_TEST
|
||||
int sqlite3BtreeCursorInfo(BtCursor*, int*, int);
|
||||
void sqlite3BtreeCursorList(Btree*);
|
||||
int sqlite3BtreePageDump(Btree*, int, int recursive);
|
||||
#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*);
|
||||
int sqlite3BtreeHoldsMutex(Btree*);
|
||||
void sqlite3BtreeEnterCursor(BtCursor*);
|
||||
void sqlite3BtreeLeaveCursor(BtCursor*);
|
||||
void sqlite3BtreeEnterAll(sqlite3*);
|
||||
void sqlite3BtreeLeaveAll(sqlite3*);
|
||||
int sqlite3BtreeHoldsAllMutexes(sqlite3*);
|
||||
void sqlite3BtreeMutexArrayEnter(BtreeMutexArray*);
|
||||
void sqlite3BtreeMutexArrayLeave(BtreeMutexArray*);
|
||||
void sqlite3BtreeMutexArrayInsert(BtreeMutexArray*, Btree*);
|
||||
#else
|
||||
# define sqlite3BtreeEnter(X)
|
||||
# define sqlite3BtreeLeave(X)
|
||||
# define sqlite3BtreeHoldsMutex(X) 1
|
||||
# define sqlite3BtreeEnterCursor(X)
|
||||
# define sqlite3BtreeLeaveCursor(X)
|
||||
# define sqlite3BtreeEnterAll(X)
|
||||
# define sqlite3BtreeLeaveAll(X)
|
||||
# define sqlite3BtreeHoldsAllMutexes(X) 1
|
||||
# define sqlite3BtreeMutexArrayEnter(X)
|
||||
# define sqlite3BtreeMutexArrayLeave(X)
|
||||
# define sqlite3BtreeMutexArrayInsert(X,Y)
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* _BTREE_H_ */
|
|
@ -0,0 +1,648 @@
|
|||
/*
|
||||
** 2004 April 6
|
||||
**
|
||||
** 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: btreeInt.h,v 1.13 2007/08/30 01:19:59 drh Exp $
|
||||
**
|
||||
** This file implements a external (disk-based) database using BTrees.
|
||||
** For a detailed discussion of BTrees, refer to
|
||||
**
|
||||
** Donald E. Knuth, THE ART OF COMPUTER PROGRAMMING, Volume 3:
|
||||
** "Sorting And Searching", pages 473-480. Addison-Wesley
|
||||
** Publishing Company, Reading, Massachusetts.
|
||||
**
|
||||
** The basic idea is that each page of the file contains N database
|
||||
** entries and N+1 pointers to subpages.
|
||||
**
|
||||
** ----------------------------------------------------------------
|
||||
** | Ptr(0) | Key(0) | Ptr(1) | Key(1) | ... | Key(N-1) | Ptr(N) |
|
||||
** ----------------------------------------------------------------
|
||||
**
|
||||
** All of the keys on the page that Ptr(0) points to have values less
|
||||
** than Key(0). All of the keys on page Ptr(1) and its subpages have
|
||||
** values greater than Key(0) and less than Key(1). All of the keys
|
||||
** on Ptr(N) and its subpages have values greater than Key(N-1). And
|
||||
** so forth.
|
||||
**
|
||||
** Finding a particular key requires reading O(log(M)) pages from the
|
||||
** disk where M is the number of entries in the tree.
|
||||
**
|
||||
** In this implementation, a single file can hold one or more separate
|
||||
** BTrees. Each BTree is identified by the index of its root page. The
|
||||
** key and data for any entry are combined to form the "payload". A
|
||||
** fixed amount of payload can be carried directly on the database
|
||||
** page. If the payload is larger than the preset amount then surplus
|
||||
** bytes are stored on overflow pages. The payload for an entry
|
||||
** and the preceding pointer are combined to form a "Cell". Each
|
||||
** page has a small header which contains the Ptr(N) pointer and other
|
||||
** information such as the size of key and data.
|
||||
**
|
||||
** FORMAT DETAILS
|
||||
**
|
||||
** The file is divided into pages. The first page is called page 1,
|
||||
** the second is page 2, and so forth. A page number of zero indicates
|
||||
** "no such page". The page size can be anything between 512 and 65536.
|
||||
** Each page can be either a btree page, a freelist page or an overflow
|
||||
** page.
|
||||
**
|
||||
** The first page is always a btree page. The first 100 bytes of the first
|
||||
** page contain a special header (the "file header") that describes the file.
|
||||
** The format of the file header is as follows:
|
||||
**
|
||||
** OFFSET SIZE DESCRIPTION
|
||||
** 0 16 Header string: "SQLite format 3\000"
|
||||
** 16 2 Page size in bytes.
|
||||
** 18 1 File format write version
|
||||
** 19 1 File format read version
|
||||
** 20 1 Bytes of unused space at the end of each page
|
||||
** 21 1 Max embedded payload fraction
|
||||
** 22 1 Min embedded payload fraction
|
||||
** 23 1 Min leaf payload fraction
|
||||
** 24 4 File change counter
|
||||
** 28 4 Reserved for future use
|
||||
** 32 4 First freelist page
|
||||
** 36 4 Number of freelist pages in the file
|
||||
** 40 60 15 4-byte meta values passed to higher layers
|
||||
**
|
||||
** All of the integer values are big-endian (most significant byte first).
|
||||
**
|
||||
** The file change counter is incremented when the database is changed
|
||||
** This counter allows other processes to know when the file has changed
|
||||
** and thus when they need to flush their cache.
|
||||
**
|
||||
** The max embedded payload fraction is the amount of the total usable
|
||||
** space in a page that can be consumed by a single cell for standard
|
||||
** B-tree (non-LEAFDATA) tables. A value of 255 means 100%. The default
|
||||
** is to limit the maximum cell size so that at least 4 cells will fit
|
||||
** on one page. Thus the default max embedded payload fraction is 64.
|
||||
**
|
||||
** If the payload for a cell is larger than the max payload, then extra
|
||||
** payload is spilled to overflow pages. Once an overflow page is allocated,
|
||||
** as many bytes as possible are moved into the overflow pages without letting
|
||||
** the cell size drop below the min embedded payload fraction.
|
||||
**
|
||||
** The min leaf payload fraction is like the min embedded payload fraction
|
||||
** except that it applies to leaf nodes in a LEAFDATA tree. The maximum
|
||||
** payload fraction for a LEAFDATA tree is always 100% (or 255) and it
|
||||
** not specified in the header.
|
||||
**
|
||||
** Each btree pages is divided into three sections: The header, the
|
||||
** cell pointer array, and the cell content area. Page 1 also has a 100-byte
|
||||
** file header that occurs before the page header.
|
||||
**
|
||||
** |----------------|
|
||||
** | file header | 100 bytes. Page 1 only.
|
||||
** |----------------|
|
||||
** | page header | 8 bytes for leaves. 12 bytes for interior nodes
|
||||
** |----------------|
|
||||
** | cell pointer | | 2 bytes per cell. Sorted order.
|
||||
** | array | | Grows downward
|
||||
** | | v
|
||||
** |----------------|
|
||||
** | unallocated |
|
||||
** | space |
|
||||
** |----------------| ^ Grows upwards
|
||||
** | cell content | | Arbitrary order interspersed with freeblocks.
|
||||
** | area | | and free space fragments.
|
||||
** |----------------|
|
||||
**
|
||||
** The page headers looks like this:
|
||||
**
|
||||
** OFFSET SIZE DESCRIPTION
|
||||
** 0 1 Flags. 1: intkey, 2: zerodata, 4: leafdata, 8: leaf
|
||||
** 1 2 byte offset to the first freeblock
|
||||
** 3 2 number of cells on this page
|
||||
** 5 2 first byte of the cell content area
|
||||
** 7 1 number of fragmented free bytes
|
||||
** 8 4 Right child (the Ptr(N) value). Omitted on leaves.
|
||||
**
|
||||
** The flags define the format of this btree page. The leaf flag means that
|
||||
** this page has no children. The zerodata flag means that this page carries
|
||||
** only keys and no data. The intkey flag means that the key is a integer
|
||||
** which is stored in the key size entry of the cell header rather than in
|
||||
** the payload area.
|
||||
**
|
||||
** The cell pointer array begins on the first byte after the page header.
|
||||
** The cell pointer array contains zero or more 2-byte numbers which are
|
||||
** offsets from the beginning of the page to the cell content in the cell
|
||||
** content area. The cell pointers occur in sorted order. The system strives
|
||||
** to keep free space after the last cell pointer so that new cells can
|
||||
** be easily added without having to defragment the page.
|
||||
**
|
||||
** Cell content is stored at the very end of the page and grows toward the
|
||||
** beginning of the page.
|
||||
**
|
||||
** Unused space within the cell content area is collected into a linked list of
|
||||
** freeblocks. Each freeblock is at least 4 bytes in size. The byte offset
|
||||
** to the first freeblock is given in the header. Freeblocks occur in
|
||||
** increasing order. Because a freeblock must be at least 4 bytes in size,
|
||||
** any group of 3 or fewer unused bytes in the cell content area cannot
|
||||
** exist on the freeblock chain. A group of 3 or fewer free bytes is called
|
||||
** a fragment. The total number of bytes in all fragments is recorded.
|
||||
** in the page header at offset 7.
|
||||
**
|
||||
** SIZE DESCRIPTION
|
||||
** 2 Byte offset of the next freeblock
|
||||
** 2 Bytes in this freeblock
|
||||
**
|
||||
** Cells are of variable length. Cells are stored in the cell content area at
|
||||
** the end of the page. Pointers to the cells are in the cell pointer array
|
||||
** that immediately follows the page header. Cells is not necessarily
|
||||
** contiguous or in order, but cell pointers are contiguous and in order.
|
||||
**
|
||||
** Cell content makes use of variable length integers. A variable
|
||||
** length integer is 1 to 9 bytes where the lower 7 bits of each
|
||||
** byte are used. The integer consists of all bytes that have bit 8 set and
|
||||
** the first byte with bit 8 clear. The most significant byte of the integer
|
||||
** appears first. A variable-length integer may not be more than 9 bytes long.
|
||||
** As a special case, all 8 bytes of the 9th byte are used as data. This
|
||||
** allows a 64-bit integer to be encoded in 9 bytes.
|
||||
**
|
||||
** 0x00 becomes 0x00000000
|
||||
** 0x7f becomes 0x0000007f
|
||||
** 0x81 0x00 becomes 0x00000080
|
||||
** 0x82 0x00 becomes 0x00000100
|
||||
** 0x80 0x7f becomes 0x0000007f
|
||||
** 0x8a 0x91 0xd1 0xac 0x78 becomes 0x12345678
|
||||
** 0x81 0x81 0x81 0x81 0x01 becomes 0x10204081
|
||||
**
|
||||
** Variable length integers are used for rowids and to hold the number of
|
||||
** bytes of key and data in a btree cell.
|
||||
**
|
||||
** The content of a cell looks like this:
|
||||
**
|
||||
** SIZE DESCRIPTION
|
||||
** 4 Page number of the left child. Omitted if leaf flag is set.
|
||||
** var Number of bytes of data. Omitted if the zerodata flag is set.
|
||||
** var Number of bytes of key. Or the key itself if intkey flag is set.
|
||||
** * Payload
|
||||
** 4 First page of the overflow chain. Omitted if no overflow
|
||||
**
|
||||
** Overflow pages form a linked list. Each page except the last is completely
|
||||
** filled with data (pagesize - 4 bytes). The last page can have as little
|
||||
** as 1 byte of data.
|
||||
**
|
||||
** SIZE DESCRIPTION
|
||||
** 4 Page number of next overflow page
|
||||
** * Data
|
||||
**
|
||||
** Freelist pages come in two subtypes: trunk pages and leaf pages. The
|
||||
** file header points to the first in a linked list of trunk page. Each trunk
|
||||
** page points to multiple leaf pages. The content of a leaf page is
|
||||
** unspecified. A trunk page looks like this:
|
||||
**
|
||||
** SIZE DESCRIPTION
|
||||
** 4 Page number of next trunk page
|
||||
** 4 Number of leaf pointers on this page
|
||||
** * zero or more pages numbers of leaves
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include "pager.h"
|
||||
#include "btree.h"
|
||||
#include "os.h"
|
||||
#include <assert.h>
|
||||
|
||||
/* Round up a number to the next larger multiple of 8. This is used
|
||||
** to force 8-byte alignment on 64-bit architectures.
|
||||
*/
|
||||
#define ROUND8(x) ((x+7)&~7)
|
||||
|
||||
|
||||
/* The following value is the maximum cell size assuming a maximum page
|
||||
** size give above.
|
||||
*/
|
||||
#define MX_CELL_SIZE(pBt) (pBt->pageSize-8)
|
||||
|
||||
/* 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
|
||||
** exceedingly rare, but they are possible.
|
||||
*/
|
||||
#define MX_CELL(pBt) ((pBt->pageSize-8)/3)
|
||||
|
||||
/* Forward declarations */
|
||||
typedef struct MemPage MemPage;
|
||||
typedef struct BtLock BtLock;
|
||||
|
||||
/*
|
||||
** This is a magic string that appears at the beginning of every
|
||||
** SQLite database in order to identify the file as a real database.
|
||||
**
|
||||
** You can change this value at compile-time by specifying a
|
||||
** -DSQLITE_FILE_HEADER="..." on the compiler command-line. The
|
||||
** header must be exactly 16 bytes including the zero-terminator so
|
||||
** the string itself should be 15 characters long. If you change
|
||||
** the header, then your custom library will not be able to read
|
||||
** databases generated by the standard tools and the standard tools
|
||||
** will not be able to read databases created by your custom library.
|
||||
*/
|
||||
#ifndef SQLITE_FILE_HEADER /* 123456789 123456 */
|
||||
# define SQLITE_FILE_HEADER "SQLite format 3"
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Page type flags. An ORed combination of these flags appear as the
|
||||
** first byte of on-disk image of every BTree page.
|
||||
*/
|
||||
#define PTF_INTKEY 0x01
|
||||
#define PTF_ZERODATA 0x02
|
||||
#define PTF_LEAFDATA 0x04
|
||||
#define PTF_LEAF 0x08
|
||||
|
||||
/*
|
||||
** As each page of the file is loaded into memory, an instance of the following
|
||||
** structure is appended and initialized to zero. This structure stores
|
||||
** information about the page that is decoded from the raw file page.
|
||||
**
|
||||
** The pParent field points back to the parent page. This allows us 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.
|
||||
** 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 {
|
||||
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 intKey; /* True if intkey 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 hdrOffset; /* 100 for page 1. 0 otherwise */
|
||||
u8 childPtrSize; /* 0 if leaf==1. 4 if leaf==0 */
|
||||
u16 maxLocal; /* Copy of BtShared.maxLocal or BtShared.maxLeaf */
|
||||
u16 minLocal; /* Copy of BtShared.minLocal or BtShared.minLeaf */
|
||||
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 nCell; /* Number of cells on this page, local and ovfl */
|
||||
struct _OvflCell { /* Cells that will not fit on aData[] */
|
||||
u8 *pCell; /* Pointers to the body of the overflow cell */
|
||||
u16 idx; /* Insert this cell before idx-th non-overflow cell */
|
||||
} aOvfl[5];
|
||||
BtShared *pBt; /* Pointer to BtShared that this page is part of */
|
||||
u8 *aData; /* Pointer to disk image of the page data */
|
||||
DbPage *pDbPage; /* Pager page handle */
|
||||
Pgno pgno; /* Page number for this page */
|
||||
MemPage *pParent; /* The parent of this page. NULL for root */
|
||||
};
|
||||
|
||||
/*
|
||||
** The in-memory image of a disk page has the auxiliary information appended
|
||||
** to the end. EXTRA_SIZE is the number of bytes of space needed to hold
|
||||
** that extra information.
|
||||
*/
|
||||
#define EXTRA_SIZE sizeof(MemPage)
|
||||
|
||||
/* 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 {
|
||||
sqlite3 *pSqlite; /* The database connection holding this btree */
|
||||
BtShared *pBt; /* Sharable content of this btree */
|
||||
u8 inTrans; /* TRANS_NONE, TRANS_READ or TRANS_WRITE */
|
||||
u8 sharable; /* True if we can share pBt with other pSqlite */
|
||||
u8 locked; /* True if pSqlite currently has pBt locked */
|
||||
int wantToLock; /* Number of nested calls to sqlite3BtreeEnter() */
|
||||
Btree *pNext; /* List of other sharable Btrees from the same pSqlite */
|
||||
Btree *pPrev; /* Back pointer of the same list */
|
||||
};
|
||||
|
||||
/*
|
||||
** Btree.inTrans may take one of the following values.
|
||||
**
|
||||
** 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,
|
||||
** but any number may have active read transactions.
|
||||
*/
|
||||
#define TRANS_NONE 0
|
||||
#define TRANS_READ 1
|
||||
#define TRANS_WRITE 2
|
||||
|
||||
/*
|
||||
** 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 {
|
||||
Pager *pPager; /* The page cache */
|
||||
BtCursor *pCursor; /* A list of all open cursors */
|
||||
MemPage *pPage1; /* First page of the database */
|
||||
u8 inStmt; /* True if we are in a statement subtransaction */
|
||||
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 */
|
||||
#ifndef SQLITE_OMIT_AUTOVACUUM
|
||||
u8 autoVacuum; /* True if auto-vacuum is enabled */
|
||||
u8 incrVacuum; /* True if incr-vacuum is enabled */
|
||||
Pgno nTrunc; /* Non-zero if the db will be truncated (incr vacuum) */
|
||||
#endif
|
||||
u16 pageSize; /* Total number of bytes on a page */
|
||||
u16 usableSize; /* Number of usable bytes on each page */
|
||||
int maxLocal; /* Maximum local payload in non-LEAFDATA tables */
|
||||
int minLocal; /* Minimum local payload in non-LEAFDATA tables */
|
||||
int maxLeaf; /* Maximum local payload in a LEAFDATA table */
|
||||
int minLeaf; /* Minimum local payload in a LEAFDATA table */
|
||||
BusyHandler *pBusyHandler; /* Callback for when there is lock contention */
|
||||
u8 inTransaction; /* Transaction state */
|
||||
int nTransaction; /* Number of open transactions (read + write) */
|
||||
void *pSchema; /* Pointer to space allocated by sqlite3BtreeSchema() */
|
||||
void (*xFreeSchema)(void*); /* Destructor for BtShared.pSchema */
|
||||
sqlite3_mutex *mutex; /* Non-recursive mutex required to access this struct */
|
||||
#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 */
|
||||
#endif
|
||||
};
|
||||
|
||||
/*
|
||||
** An instance of the following structure is used to hold information
|
||||
** about a cell. The parseCellPtr() function fills in this structure
|
||||
** based on information extract from the raw disk page.
|
||||
*/
|
||||
typedef struct CellInfo CellInfo;
|
||||
struct CellInfo {
|
||||
u8 *pCell; /* Pointer to the start of cell content */
|
||||
i64 nKey; /* The key for INTKEY tables, or number of bytes in key */
|
||||
u32 nData; /* Number of bytes of data */
|
||||
u32 nPayload; /* Total amount of payload */
|
||||
u16 nHeader; /* Size of the cell content header in bytes */
|
||||
u16 nLocal; /* Amount of payload held locally */
|
||||
u16 iOverflow; /* Offset to overflow page number. Zero if no overflow */
|
||||
u16 nSize; /* Size of the cell content on the main b-tree page */
|
||||
};
|
||||
|
||||
/*
|
||||
** 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
|
||||
** 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.pSqlite.
|
||||
**
|
||||
** Fields in this structure are accessed under the BtShared.mutex
|
||||
** found at self->pBt->mutex.
|
||||
*/
|
||||
struct BtCursor {
|
||||
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 */
|
||||
int (*xCompare)(void*,int,const void*,int,const void*); /* Key comp func */
|
||||
void *pArg; /* First arg to xCompare() */
|
||||
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 */
|
||||
u8 wrFlag; /* True if writable */
|
||||
u8 eState; /* One of the CURSOR_XXX constants (see below) */
|
||||
void *pKey; /* Saved key that was cursor's last known position */
|
||||
i64 nKey; /* Size of pKey, or last integer key */
|
||||
int skip; /* (skip<0) -> Prev() is a no-op. (skip>0) -> Next() is */
|
||||
#ifndef SQLITE_OMIT_INCRBLOB
|
||||
u8 isIncrblobHandle; /* True if this cursor is an incr. io handle */
|
||||
Pgno *aOverflow; /* Cache of overflow page locations */
|
||||
#endif
|
||||
};
|
||||
|
||||
/*
|
||||
** Potential values for BtCursor.eState.
|
||||
**
|
||||
** CURSOR_VALID:
|
||||
** Cursor points to a valid entry. getPayload() etc. may be called.
|
||||
**
|
||||
** CURSOR_INVALID:
|
||||
** Cursor does not point to a valid entry. This can happen (for example)
|
||||
** because the table is empty or because BtreeCursorFirst() has not been
|
||||
** called.
|
||||
**
|
||||
** CURSOR_REQUIRESEEK:
|
||||
** 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
|
||||
** in variables BtCursor.pKey and BtCursor.nKey. When a cursor is in
|
||||
** this state, restoreOrClearCursorPosition() can be called to attempt to
|
||||
** 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_VALID 1
|
||||
#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.
|
||||
** TODO: This macro is very similary to PAGER_MJ_PGNO() in pager.c. They
|
||||
** should possibly be consolidated (presumably in pager.h).
|
||||
**
|
||||
** If disk I/O is omitted (meaning that the database is stored purely
|
||||
** in memory) then there is no pending byte.
|
||||
*/
|
||||
#ifdef SQLITE_OMIT_DISKIO
|
||||
# define PENDING_BYTE_PAGE(pBt) 0x7fffffff
|
||||
#else
|
||||
# define PENDING_BYTE_PAGE(pBt) ((PENDING_BYTE/(pBt)->pageSize)+1)
|
||||
#endif
|
||||
|
||||
/*
|
||||
** A linked list of the following structures is stored at BtShared.pLock.
|
||||
** Locks are added (or upgraded from READ_LOCK to WRITE_LOCK) when a cursor
|
||||
** is opened on the table with root page BtShared.iTable. Locks are removed
|
||||
** from this list when a transaction is committed or rolled back, or when
|
||||
** a btree handle is closed.
|
||||
*/
|
||||
struct BtLock {
|
||||
Btree *pBtree; /* Btree handle holding this lock */
|
||||
Pgno iTable; /* Root page of table */
|
||||
u8 eLock; /* READ_LOCK or WRITE_LOCK */
|
||||
BtLock *pNext; /* Next in BtShared.pLock list */
|
||||
};
|
||||
|
||||
/* Candidate values for BtLock.eLock */
|
||||
#define READ_LOCK 1
|
||||
#define WRITE_LOCK 2
|
||||
|
||||
/*
|
||||
** These macros define the location of the pointer-map entry for a
|
||||
** database page. The first argument to each is the number of usable
|
||||
** bytes on each page of the database (often 1024). The second is the
|
||||
** page number to look up in the pointer map.
|
||||
**
|
||||
** PTRMAP_PAGENO returns the database page number of the pointer-map
|
||||
** page that stores the required pointer. PTRMAP_PTROFFSET returns
|
||||
** the offset of the requested map entry.
|
||||
**
|
||||
** If the pgno argument passed to PTRMAP_PAGENO is a pointer-map page,
|
||||
** then pgno is returned. So (pgno==PTRMAP_PAGENO(pgsz, pgno)) can be
|
||||
** used to test if pgno is a pointer-map page. PTRMAP_ISPAGE implements
|
||||
** this test.
|
||||
*/
|
||||
#define PTRMAP_PAGENO(pBt, pgno) ptrmapPageno(pBt, pgno)
|
||||
#define PTRMAP_PTROFFSET(pBt, pgno) (5*(pgno-ptrmapPageno(pBt, pgno)-1))
|
||||
#define PTRMAP_ISPAGE(pBt, pgno) (PTRMAP_PAGENO((pBt),(pgno))==(pgno))
|
||||
|
||||
/*
|
||||
** The pointer map is a lookup table that identifies the parent page for
|
||||
** each child page in the database file. The parent page is the page that
|
||||
** contains a pointer to the child. Every page in the database contains
|
||||
** 0 or 1 parent pages. (In this context 'database page' refers
|
||||
** to any page that is not part of the pointer map itself.) Each pointer map
|
||||
** entry consists of a single byte 'type' and a 4 byte parent page number.
|
||||
** The PTRMAP_XXX identifiers below are the valid types.
|
||||
**
|
||||
** The purpose of the pointer map is to facility moving pages from one
|
||||
** position in the file to another as part of autovacuum. When a page
|
||||
** is moved, the pointer in its parent must be updated to point to the
|
||||
** new location. The pointer map is used to locate the parent page quickly.
|
||||
**
|
||||
** PTRMAP_ROOTPAGE: The database page is a root-page. The page-number is not
|
||||
** used in this case.
|
||||
**
|
||||
** PTRMAP_FREEPAGE: The database page is an unused (free) page. The page-number
|
||||
** is not used in this case.
|
||||
**
|
||||
** PTRMAP_OVERFLOW1: The database page is the first page in a list of
|
||||
** overflow pages. The page number identifies the page that
|
||||
** contains the cell with a pointer to this overflow page.
|
||||
**
|
||||
** PTRMAP_OVERFLOW2: The database page is the second or later page in a list of
|
||||
** overflow pages. The page-number identifies the previous
|
||||
** page in the overflow page list.
|
||||
**
|
||||
** PTRMAP_BTREE: The database page is a non-root btree page. The page number
|
||||
** identifies the parent page in the btree.
|
||||
*/
|
||||
#define PTRMAP_ROOTPAGE 1
|
||||
#define PTRMAP_FREEPAGE 2
|
||||
#define PTRMAP_OVERFLOW1 3
|
||||
#define PTRMAP_OVERFLOW2 4
|
||||
#define PTRMAP_BTREE 5
|
||||
|
||||
/* A bunch of assert() statements to check the transaction state variables
|
||||
** of handle p (type Btree*) are internally consistent.
|
||||
*/
|
||||
#define btreeIntegrity(p) \
|
||||
assert( p->pBt->inTransaction!=TRANS_NONE || p->pBt->nTransaction==0 ); \
|
||||
assert( p->pBt->inTransaction>=p->inTrans );
|
||||
|
||||
|
||||
/*
|
||||
** The ISAUTOVACUUM macro is used within balance_nonroot() to determine
|
||||
** if the database supports auto-vacuum or not. Because it is used
|
||||
** within an expression that is an argument to another macro
|
||||
** (sqliteMallocRaw), it is not possible to use conditional compilation.
|
||||
** So, this macro is defined instead.
|
||||
*/
|
||||
#ifndef SQLITE_OMIT_AUTOVACUUM
|
||||
#define ISAUTOVACUUM (pBt->autoVacuum)
|
||||
#else
|
||||
#define ISAUTOVACUUM 0
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
** This structure is passed around through all the sanity checking routines
|
||||
** in order to keep track of some global state information.
|
||||
*/
|
||||
typedef struct IntegrityCk IntegrityCk;
|
||||
struct IntegrityCk {
|
||||
BtShared *pBt; /* The tree being checked out */
|
||||
Pager *pPager; /* The associated pager. Also accessible by pBt->pPager */
|
||||
int nPage; /* Number of pages in the database */
|
||||
int *anRef; /* Number of times each page is referenced */
|
||||
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 */
|
||||
};
|
||||
|
||||
/*
|
||||
** Read or write a two- and four-byte big-endian integer values.
|
||||
*/
|
||||
#define get2byte(x) ((x)[0]<<8 | (x)[1])
|
||||
#define put2byte(p,v) ((p)[0] = (v)>>8, (p)[1] = (v))
|
||||
#define get4byte sqlite3Get4byte
|
||||
#define put4byte sqlite3Put4byte
|
||||
|
||||
/*
|
||||
** Internal routines that should be accessed by the btree layer only.
|
||||
*/
|
||||
int sqlite3BtreeGetPage(BtShared*, Pgno, MemPage**, int);
|
||||
int sqlite3BtreeInitPage(MemPage *pPage, MemPage *pParent);
|
||||
void sqlite3BtreeParseCellPtr(MemPage*, u8*, CellInfo*);
|
||||
void sqlite3BtreeParseCell(MemPage*, int, CellInfo*);
|
||||
#ifdef SQLITE_TEST
|
||||
u8 *sqlite3BtreeFindCell(MemPage *pPage, int iCell);
|
||||
#endif
|
||||
int sqlite3BtreeRestoreOrClearCursorPosition(BtCursor *pCur);
|
||||
void sqlite3BtreeGetTempCursor(BtCursor *pCur, BtCursor *pTempCur);
|
||||
void sqlite3BtreeReleaseTempCursor(BtCursor *pCur);
|
||||
int sqlite3BtreeIsRootPage(MemPage *pPage);
|
||||
void sqlite3BtreeMoveToParent(BtCursor *pCur);
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,378 @@
|
|||
/*
|
||||
** 2005 May 23
|
||||
**
|
||||
** 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 functions used to access the internal hash tables
|
||||
** of user defined functions and collation sequences.
|
||||
**
|
||||
** $Id: callback.c,v 1.23 2007/08/29 12:31:26 danielk1977 Exp $
|
||||
*/
|
||||
|
||||
#include "sqliteInt.h"
|
||||
|
||||
/*
|
||||
** Invoke the 'collation needed' callback to request a collation sequence
|
||||
** in the database text encoding of name zName, length nName.
|
||||
** If the collation sequence
|
||||
*/
|
||||
static void callCollNeeded(sqlite3 *db, const char *zName, int nName){
|
||||
assert( !db->xCollNeeded || !db->xCollNeeded16 );
|
||||
if( nName<0 ) nName = strlen(zName);
|
||||
if( db->xCollNeeded ){
|
||||
char *zExternal = sqlite3DbStrNDup(db, zName, nName);
|
||||
if( !zExternal ) return;
|
||||
db->xCollNeeded(db->pCollNeededArg, db, (int)ENC(db), zExternal);
|
||||
sqlite3_free(zExternal);
|
||||
}
|
||||
#ifndef SQLITE_OMIT_UTF16
|
||||
if( db->xCollNeeded16 ){
|
||||
char const *zExternal;
|
||||
sqlite3_value *pTmp = sqlite3ValueNew(db);
|
||||
sqlite3ValueSetStr(pTmp, nName, zName, SQLITE_UTF8, SQLITE_STATIC);
|
||||
zExternal = sqlite3ValueText(pTmp, SQLITE_UTF16NATIVE);
|
||||
if( zExternal ){
|
||||
db->xCollNeeded16(db->pCollNeededArg, db, (int)ENC(db), zExternal);
|
||||
}
|
||||
sqlite3ValueFree(pTmp);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
** This routine is called if the collation factory fails to deliver a
|
||||
** collation function in the best encoding but there may be other versions
|
||||
** of this collation function (for other text encodings) available. Use one
|
||||
** of these instead if they exist. Avoid a UTF-8 <-> UTF-16 conversion if
|
||||
** possible.
|
||||
*/
|
||||
static int synthCollSeq(sqlite3 *db, CollSeq *pColl){
|
||||
CollSeq *pColl2;
|
||||
char *z = pColl->zName;
|
||||
int n = strlen(z);
|
||||
int i;
|
||||
static const u8 aEnc[] = { SQLITE_UTF16BE, SQLITE_UTF16LE, SQLITE_UTF8 };
|
||||
for(i=0; i<3; i++){
|
||||
pColl2 = sqlite3FindCollSeq(db, aEnc[i], z, n, 0);
|
||||
if( pColl2->xCmp!=0 ){
|
||||
memcpy(pColl, pColl2, sizeof(CollSeq));
|
||||
pColl->xDel = 0; /* Do not copy the destructor */
|
||||
return SQLITE_OK;
|
||||
}
|
||||
}
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
|
||||
/*
|
||||
** This function is responsible for invoking the collation factory callback
|
||||
** or substituting a collation sequence of a different encoding when the
|
||||
** requested collation sequence is not available in the database native
|
||||
** encoding.
|
||||
**
|
||||
** If it is not NULL, then pColl must point to the database native encoding
|
||||
** collation sequence with name zName, length nName.
|
||||
**
|
||||
** The return value is either the collation sequence to be used in database
|
||||
** db for collation type name zName, length nName, or NULL, if no collation
|
||||
** sequence can be found.
|
||||
*/
|
||||
CollSeq *sqlite3GetCollSeq(
|
||||
sqlite3* db,
|
||||
CollSeq *pColl,
|
||||
const char *zName,
|
||||
int nName
|
||||
){
|
||||
CollSeq *p;
|
||||
|
||||
p = pColl;
|
||||
if( !p ){
|
||||
p = sqlite3FindCollSeq(db, ENC(db), zName, nName, 0);
|
||||
}
|
||||
if( !p || !p->xCmp ){
|
||||
/* No collation sequence of this type for this encoding is registered.
|
||||
** Call the collation factory to see if it can supply us with one.
|
||||
*/
|
||||
callCollNeeded(db, zName, nName);
|
||||
p = sqlite3FindCollSeq(db, ENC(db), zName, nName, 0);
|
||||
}
|
||||
if( p && !p->xCmp && synthCollSeq(db, p) ){
|
||||
p = 0;
|
||||
}
|
||||
assert( !p || p->xCmp );
|
||||
return p;
|
||||
}
|
||||
|
||||
/*
|
||||
** This routine is called on a collation sequence before it is used to
|
||||
** check that it is defined. An undefined collation sequence exists when
|
||||
** a database is loaded that contains references to collation sequences
|
||||
** that have not been defined by sqlite3_create_collation() etc.
|
||||
**
|
||||
** If required, this routine calls the 'collation needed' callback to
|
||||
** request a definition of the collating sequence. If this doesn't work,
|
||||
** an equivalent collating sequence that uses a text encoding different
|
||||
** from the main database is substituted, if one is available.
|
||||
*/
|
||||
int sqlite3CheckCollSeq(Parse *pParse, CollSeq *pColl){
|
||||
if( pColl ){
|
||||
const char *zName = pColl->zName;
|
||||
CollSeq *p = sqlite3GetCollSeq(pParse->db, pColl, zName, -1);
|
||||
if( !p ){
|
||||
if( pParse->nErr==0 ){
|
||||
sqlite3ErrorMsg(pParse, "no such collation sequence: %s", zName);
|
||||
}
|
||||
pParse->nErr++;
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
assert( p==pColl );
|
||||
}
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
** Locate and return an entry from the db.aCollSeq hash table. If the entry
|
||||
** specified by zName and nName is not found and parameter 'create' is
|
||||
** true, then create a new entry. Otherwise return NULL.
|
||||
**
|
||||
** Each pointer stored in the sqlite3.aCollSeq hash table contains an
|
||||
** array of three CollSeq structures. The first is the collation sequence
|
||||
** prefferred for UTF-8, the second UTF-16le, and the third UTF-16be.
|
||||
**
|
||||
** Stored immediately after the three collation sequences is a copy of
|
||||
** the collation sequence name. A pointer to this string is stored in
|
||||
** each collation sequence structure.
|
||||
*/
|
||||
static CollSeq *findCollSeqEntry(
|
||||
sqlite3 *db,
|
||||
const char *zName,
|
||||
int nName,
|
||||
int create
|
||||
){
|
||||
CollSeq *pColl;
|
||||
if( nName<0 ) nName = strlen(zName);
|
||||
pColl = sqlite3HashFind(&db->aCollSeq, zName, nName);
|
||||
|
||||
if( 0==pColl && create ){
|
||||
pColl = sqlite3DbMallocZero(db, 3*sizeof(*pColl) + nName + 1 );
|
||||
if( pColl ){
|
||||
CollSeq *pDel = 0;
|
||||
pColl[0].zName = (char*)&pColl[3];
|
||||
pColl[0].enc = SQLITE_UTF8;
|
||||
pColl[1].zName = (char*)&pColl[3];
|
||||
pColl[1].enc = SQLITE_UTF16LE;
|
||||
pColl[2].zName = (char*)&pColl[3];
|
||||
pColl[2].enc = SQLITE_UTF16BE;
|
||||
memcpy(pColl[0].zName, zName, nName);
|
||||
pColl[0].zName[nName] = 0;
|
||||
pDel = sqlite3HashInsert(&db->aCollSeq, pColl[0].zName, nName, pColl);
|
||||
|
||||
/* If a malloc() failure occured in sqlite3HashInsert(), it will
|
||||
** return the pColl pointer to be deleted (because it wasn't added
|
||||
** to the hash table).
|
||||
*/
|
||||
assert( pDel==0 || pDel==pColl );
|
||||
if( pDel!=0 ){
|
||||
db->mallocFailed = 1;
|
||||
sqlite3_free(pDel);
|
||||
pColl = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
return pColl;
|
||||
}
|
||||
|
||||
/*
|
||||
** Parameter zName points to a UTF-8 encoded string nName bytes long.
|
||||
** Return the CollSeq* pointer for the collation sequence named zName
|
||||
** for the encoding 'enc' from the database 'db'.
|
||||
**
|
||||
** If the entry specified is not found and 'create' is true, then create a
|
||||
** new entry. Otherwise return NULL.
|
||||
**
|
||||
** A separate function sqlite3LocateCollSeq() is a wrapper around
|
||||
** this routine. sqlite3LocateCollSeq() invokes the collation factory
|
||||
** if necessary and generates an error message if the collating sequence
|
||||
** cannot be found.
|
||||
*/
|
||||
CollSeq *sqlite3FindCollSeq(
|
||||
sqlite3 *db,
|
||||
u8 enc,
|
||||
const char *zName,
|
||||
int nName,
|
||||
int create
|
||||
){
|
||||
CollSeq *pColl;
|
||||
if( zName ){
|
||||
pColl = findCollSeqEntry(db, zName, nName, create);
|
||||
}else{
|
||||
pColl = db->pDfltColl;
|
||||
}
|
||||
assert( SQLITE_UTF8==1 && SQLITE_UTF16LE==2 && SQLITE_UTF16BE==3 );
|
||||
assert( enc>=SQLITE_UTF8 && enc<=SQLITE_UTF16BE );
|
||||
if( pColl ) pColl += enc-1;
|
||||
return pColl;
|
||||
}
|
||||
|
||||
/*
|
||||
** 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
|
||||
** pointer to the FuncDef structure that defines that function, or return
|
||||
** NULL if the function does not exist.
|
||||
**
|
||||
** If the createFlag argument is true, then a new (blank) FuncDef
|
||||
** structure is created and liked into the "db" structure if a
|
||||
** no matching function previously existed. When createFlag is true
|
||||
** and the nArg parameter is -1, then only a function that accepts
|
||||
** any number of arguments will be returned.
|
||||
**
|
||||
** If createFlag is false and nArg is -1, then the first valid
|
||||
** function found is returned. A function is valid if either xFunc
|
||||
** or xStep is non-zero.
|
||||
**
|
||||
** If createFlag is false, then a function with the required name and
|
||||
** number of arguments may be returned even if the eTextRep flag does not
|
||||
** match that requested.
|
||||
*/
|
||||
FuncDef *sqlite3FindFunction(
|
||||
sqlite3 *db, /* An open database */
|
||||
const char *zName, /* Name of the function. Not null-terminated */
|
||||
int nName, /* Number of characters in the name */
|
||||
int nArg, /* Number of arguments. -1 means any number */
|
||||
u8 enc, /* Preferred text encoding */
|
||||
int createFlag /* Create new entry if true and does not otherwise exist */
|
||||
){
|
||||
FuncDef *p; /* Iterator variable */
|
||||
FuncDef *pFirst; /* First function with this name */
|
||||
FuncDef *pBest = 0; /* Best match found so far */
|
||||
int bestmatch = 0;
|
||||
|
||||
|
||||
assert( enc==SQLITE_UTF8 || enc==SQLITE_UTF16LE || enc==SQLITE_UTF16BE );
|
||||
if( nArg<-1 ) nArg = -1;
|
||||
|
||||
pFirst = (FuncDef*)sqlite3HashFind(&db->aFunc, zName, nName);
|
||||
for(p=pFirst; p; p=p->pNext){
|
||||
/* During the search for the best function definition, bestmatch is set
|
||||
** as follows to indicate the quality of the match with the definition
|
||||
** pointed to by pBest:
|
||||
**
|
||||
** 0: pBest is NULL. No match has been found.
|
||||
** 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.
|
||||
**
|
||||
** 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 ){
|
||||
pBest = p;
|
||||
bestmatch = match;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* If the createFlag parameter is true, and the seach did not reveal an
|
||||
** exact match for the name, number of arguments and encoding, then add a
|
||||
** new entry to the hash table and return it.
|
||||
*/
|
||||
if( createFlag && bestmatch<6 &&
|
||||
(pBest = sqlite3DbMallocZero(db, sizeof(*pBest)+nName))!=0 ){
|
||||
pBest->nArg = nArg;
|
||||
pBest->pNext = pFirst;
|
||||
pBest->iPrefEnc = enc;
|
||||
memcpy(pBest->zName, zName, nName);
|
||||
pBest->zName[nName] = 0;
|
||||
if( pBest==sqlite3HashInsert(&db->aFunc,pBest->zName,nName,(void*)pBest) ){
|
||||
db->mallocFailed = 1;
|
||||
sqlite3_free(pBest);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if( pBest && (pBest->xStep || pBest->xFunc || createFlag) ){
|
||||
return pBest;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Free all resources held by the schema structure. The void* argument points
|
||||
** at a Schema struct. This function does not call sqlite3_free() on the
|
||||
** pointer itself, it just cleans up subsiduary resources (i.e. the contents
|
||||
** of the schema hash tables).
|
||||
*/
|
||||
void sqlite3SchemaFree(void *p){
|
||||
Hash temp1;
|
||||
Hash temp2;
|
||||
HashElem *pElem;
|
||||
Schema *pSchema = (Schema *)p;
|
||||
|
||||
temp1 = pSchema->tblHash;
|
||||
temp2 = pSchema->trigHash;
|
||||
sqlite3HashInit(&pSchema->trigHash, SQLITE_HASH_STRING, 0);
|
||||
sqlite3HashClear(&pSchema->aFKey);
|
||||
sqlite3HashClear(&pSchema->idxHash);
|
||||
for(pElem=sqliteHashFirst(&temp2); pElem; pElem=sqliteHashNext(pElem)){
|
||||
sqlite3DeleteTrigger((Trigger*)sqliteHashData(pElem));
|
||||
}
|
||||
sqlite3HashClear(&temp2);
|
||||
sqlite3HashInit(&pSchema->tblHash, SQLITE_HASH_STRING, 0);
|
||||
for(pElem=sqliteHashFirst(&temp1); pElem; pElem=sqliteHashNext(pElem)){
|
||||
Table *pTab = sqliteHashData(pElem);
|
||||
sqlite3DeleteTable(pTab);
|
||||
}
|
||||
sqlite3HashClear(&temp1);
|
||||
pSchema->pSeqTab = 0;
|
||||
pSchema->flags &= ~DB_SchemaLoaded;
|
||||
}
|
||||
|
||||
/*
|
||||
** Find and return the schema associated with a BTree. Create
|
||||
** a new one if necessary.
|
||||
*/
|
||||
Schema *sqlite3SchemaGet(sqlite3 *db, Btree *pBt){
|
||||
Schema * p;
|
||||
if( pBt ){
|
||||
p = (Schema *)sqlite3BtreeSchema(pBt, sizeof(Schema), sqlite3SchemaFree);
|
||||
}else{
|
||||
p = (Schema *)sqlite3MallocZero(sizeof(Schema));
|
||||
}
|
||||
if( !p ){
|
||||
db->mallocFailed = 1;
|
||||
}else if ( 0==p->file_format ){
|
||||
sqlite3HashInit(&p->tblHash, SQLITE_HASH_STRING, 0);
|
||||
sqlite3HashInit(&p->idxHash, SQLITE_HASH_STRING, 0);
|
||||
sqlite3HashInit(&p->trigHash, SQLITE_HASH_STRING, 0);
|
||||
sqlite3HashInit(&p->aFKey, SQLITE_HASH_STRING, 1);
|
||||
p->enc = SQLITE_UTF8;
|
||||
}
|
||||
return p;
|
||||
}
|
|
@ -0,0 +1,271 @@
|
|||
/*
|
||||
** 2001 September 15
|
||||
**
|
||||
** The author disclaims copyright to this source code. In place of
|
||||
** a legal notice, here is a blessing:
|
||||
**
|
||||
** May you do good and not evil.
|
||||
** May you find forgiveness for yourself and forgive others.
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
*************************************************************************
|
||||
** An tokenizer for SQL
|
||||
**
|
||||
** This file contains C code that implements the sqlite3_complete() API.
|
||||
** This code used to be part of the tokenizer.c source file. But by
|
||||
** separating it out, the code will be automatically omitted from
|
||||
** static links that do not use it.
|
||||
**
|
||||
** $Id: complete.c,v 1.6 2007/08/27 23:26:59 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#ifndef SQLITE_OMIT_COMPLETE
|
||||
|
||||
/*
|
||||
** This is defined in tokenize.c. We just have to import the definition.
|
||||
*/
|
||||
#ifndef SQLITE_AMALGAMATION
|
||||
#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 */
|
||||
|
||||
|
||||
/*
|
||||
** Token types used by the sqlite3_complete() routine. See the header
|
||||
** comments on that procedure for additional information.
|
||||
*/
|
||||
#define tkSEMI 0
|
||||
#define tkWS 1
|
||||
#define tkOTHER 2
|
||||
#define tkEXPLAIN 3
|
||||
#define tkCREATE 4
|
||||
#define tkTEMP 5
|
||||
#define tkTRIGGER 6
|
||||
#define tkEND 7
|
||||
|
||||
/*
|
||||
** Return TRUE if the given SQL string ends in a semicolon.
|
||||
**
|
||||
** Special handling is require for CREATE TRIGGER statements.
|
||||
** Whenever the CREATE TRIGGER keywords are seen, the statement
|
||||
** must end with ";END;".
|
||||
**
|
||||
** This implementation uses a state machine with 7 states:
|
||||
**
|
||||
** (0) START At the beginning or end of an SQL statement. This routine
|
||||
** returns 1 if it ends in the START state and 0 if it ends
|
||||
** in any other state.
|
||||
**
|
||||
** (1) NORMAL We are in the middle of statement which ends with a single
|
||||
** semicolon.
|
||||
**
|
||||
** (2) EXPLAIN The keyword EXPLAIN has been seen at the beginning of
|
||||
** a statement.
|
||||
**
|
||||
** (3) CREATE The keyword CREATE has been seen at the beginning of a
|
||||
** statement, possibly preceeded by EXPLAIN and/or followed by
|
||||
** TEMP or TEMPORARY
|
||||
**
|
||||
** (4) TRIGGER We are in the middle of a trigger definition that must be
|
||||
** ended by a semicolon, the keyword END, and another semicolon.
|
||||
**
|
||||
** (5) SEMI We've seen the first semicolon in the ";END;" that occurs at
|
||||
** the end of a trigger definition.
|
||||
**
|
||||
** (6) END We've seen the ";END" of the ";END;" that occurs at the end
|
||||
** of a trigger difinition.
|
||||
**
|
||||
** Transitions between states above are determined by tokens extracted
|
||||
** from the input. The following tokens are significant:
|
||||
**
|
||||
** (0) tkSEMI A semicolon.
|
||||
** (1) tkWS Whitespace
|
||||
** (2) tkOTHER Any other SQL token.
|
||||
** (3) tkEXPLAIN The "explain" keyword.
|
||||
** (4) tkCREATE The "create" keyword.
|
||||
** (5) tkTEMP The "temp" or "temporary" keyword.
|
||||
** (6) tkTRIGGER The "trigger" keyword.
|
||||
** (7) tkEND The "end" keyword.
|
||||
**
|
||||
** Whitespace never causes a state transition and is always ignored.
|
||||
**
|
||||
** If we compile with SQLITE_OMIT_TRIGGER, all of the computation needed
|
||||
** to recognize the end of a trigger can be omitted. All we have to do
|
||||
** is look for a semicolon that is not part of an string or comment.
|
||||
*/
|
||||
int sqlite3_complete(const char *zSql){
|
||||
u8 state = 0; /* Current state, using numbers defined in header comment */
|
||||
u8 token; /* Value of the next token */
|
||||
|
||||
#ifndef SQLITE_OMIT_TRIGGER
|
||||
/* A complex statement machine used to detect the end of a CREATE TRIGGER
|
||||
** statement. This is the normal case.
|
||||
*/
|
||||
static const u8 trans[7][8] = {
|
||||
/* Token: */
|
||||
/* State: ** SEMI WS OTHER EXPLAIN CREATE TEMP TRIGGER END */
|
||||
/* 0 START: */ { 0, 0, 1, 2, 3, 1, 1, 1, },
|
||||
/* 1 NORMAL: */ { 0, 1, 1, 1, 1, 1, 1, 1, },
|
||||
/* 2 EXPLAIN: */ { 0, 2, 1, 1, 3, 1, 1, 1, },
|
||||
/* 3 CREATE: */ { 0, 3, 1, 1, 1, 3, 4, 1, },
|
||||
/* 4 TRIGGER: */ { 5, 4, 4, 4, 4, 4, 4, 4, },
|
||||
/* 5 SEMI: */ { 5, 5, 4, 4, 4, 4, 4, 6, },
|
||||
/* 6 END: */ { 0, 6, 4, 4, 4, 4, 4, 4, },
|
||||
};
|
||||
#else
|
||||
/* If triggers are not suppored by this compile then the statement machine
|
||||
** used to detect the end of a statement is much simplier
|
||||
*/
|
||||
static const u8 trans[2][3] = {
|
||||
/* Token: */
|
||||
/* State: ** SEMI WS OTHER */
|
||||
/* 0 START: */ { 0, 0, 1, },
|
||||
/* 1 NORMAL: */ { 0, 1, 1, },
|
||||
};
|
||||
#endif /* SQLITE_OMIT_TRIGGER */
|
||||
|
||||
while( *zSql ){
|
||||
switch( *zSql ){
|
||||
case ';': { /* A semicolon */
|
||||
token = tkSEMI;
|
||||
break;
|
||||
}
|
||||
case ' ':
|
||||
case '\r':
|
||||
case '\t':
|
||||
case '\n':
|
||||
case '\f': { /* White space is ignored */
|
||||
token = tkWS;
|
||||
break;
|
||||
}
|
||||
case '/': { /* C-style comments */
|
||||
if( zSql[1]!='*' ){
|
||||
token = tkOTHER;
|
||||
break;
|
||||
}
|
||||
zSql += 2;
|
||||
while( zSql[0] && (zSql[0]!='*' || zSql[1]!='/') ){ zSql++; }
|
||||
if( zSql[0]==0 ) return 0;
|
||||
zSql++;
|
||||
token = tkWS;
|
||||
break;
|
||||
}
|
||||
case '-': { /* SQL-style comments from "--" to end of line */
|
||||
if( zSql[1]!='-' ){
|
||||
token = tkOTHER;
|
||||
break;
|
||||
}
|
||||
while( *zSql && *zSql!='\n' ){ zSql++; }
|
||||
if( *zSql==0 ) return state==0;
|
||||
token = tkWS;
|
||||
break;
|
||||
}
|
||||
case '[': { /* Microsoft-style identifiers in [...] */
|
||||
zSql++;
|
||||
while( *zSql && *zSql!=']' ){ zSql++; }
|
||||
if( *zSql==0 ) return 0;
|
||||
token = tkOTHER;
|
||||
break;
|
||||
}
|
||||
case '`': /* Grave-accent quoted symbols used by MySQL */
|
||||
case '"': /* single- and double-quoted strings */
|
||||
case '\'': {
|
||||
int c = *zSql;
|
||||
zSql++;
|
||||
while( *zSql && *zSql!=c ){ zSql++; }
|
||||
if( *zSql==0 ) return 0;
|
||||
token = tkOTHER;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
int c;
|
||||
if( IdChar((u8)*zSql) ){
|
||||
/* Keywords and unquoted identifiers */
|
||||
int nId;
|
||||
for(nId=1; IdChar(zSql[nId]); nId++){}
|
||||
#ifdef SQLITE_OMIT_TRIGGER
|
||||
token = tkOTHER;
|
||||
#else
|
||||
switch( *zSql ){
|
||||
case 'c': case 'C': {
|
||||
if( nId==6 && sqlite3StrNICmp(zSql, "create", 6)==0 ){
|
||||
token = tkCREATE;
|
||||
}else{
|
||||
token = tkOTHER;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 't': case 'T': {
|
||||
if( nId==7 && sqlite3StrNICmp(zSql, "trigger", 7)==0 ){
|
||||
token = tkTRIGGER;
|
||||
}else if( nId==4 && sqlite3StrNICmp(zSql, "temp", 4)==0 ){
|
||||
token = tkTEMP;
|
||||
}else if( nId==9 && sqlite3StrNICmp(zSql, "temporary", 9)==0 ){
|
||||
token = tkTEMP;
|
||||
}else{
|
||||
token = tkOTHER;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'e': case 'E': {
|
||||
if( nId==3 && sqlite3StrNICmp(zSql, "end", 3)==0 ){
|
||||
token = tkEND;
|
||||
}else
|
||||
#ifndef SQLITE_OMIT_EXPLAIN
|
||||
if( nId==7 && sqlite3StrNICmp(zSql, "explain", 7)==0 ){
|
||||
token = tkEXPLAIN;
|
||||
}else
|
||||
#endif
|
||||
{
|
||||
token = tkOTHER;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
token = tkOTHER;
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif /* SQLITE_OMIT_TRIGGER */
|
||||
zSql += nId-1;
|
||||
}else{
|
||||
/* Operators and special symbols */
|
||||
token = tkOTHER;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
state = trans[state][token];
|
||||
zSql++;
|
||||
}
|
||||
return state==0;
|
||||
}
|
||||
|
||||
#ifndef SQLITE_OMIT_UTF16
|
||||
/*
|
||||
** This routine is the same as the sqlite3_complete() routine described
|
||||
** above, except that the parameter is required to be UTF-16 encoded, not
|
||||
** UTF-8.
|
||||
*/
|
||||
int sqlite3_complete16(const void *zSql){
|
||||
sqlite3_value *pVal;
|
||||
char const *zSql8;
|
||||
int rc = SQLITE_NOMEM;
|
||||
|
||||
pVal = sqlite3ValueNew(0);
|
||||
sqlite3ValueSetStr(pVal, -1, zSql, SQLITE_UTF16NATIVE, SQLITE_STATIC);
|
||||
zSql8 = sqlite3ValueText(pVal, SQLITE_UTF8);
|
||||
if( zSql8 ){
|
||||
rc = sqlite3_complete(zSql8);
|
||||
}
|
||||
sqlite3ValueFree(pVal);
|
||||
return sqlite3ApiExit(0, rc);
|
||||
}
|
||||
#endif /* SQLITE_OMIT_UTF16 */
|
||||
#endif /* SQLITE_OMIT_COMPLETE */
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,467 @@
|
|||
/*
|
||||
** 2001 September 15
|
||||
**
|
||||
** The author disclaims copyright to this source code. In place of
|
||||
** a legal notice, here is a blessing:
|
||||
**
|
||||
** May you do good and not evil.
|
||||
** May you find forgiveness for yourself and forgive others.
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
*************************************************************************
|
||||
** This file contains C code routines that are called by the parser
|
||||
** in order to generate code for DELETE FROM statements.
|
||||
**
|
||||
** $Id: delete.c,v 1.130 2007/08/16 04:30:40 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
|
||||
/*
|
||||
** Look up every table that is named in pSrc. If any table is not found,
|
||||
** add an error message to pParse->zErrMsg and return NULL. If all tables
|
||||
** are found, return a pointer to the last table.
|
||||
*/
|
||||
Table *sqlite3SrcListLookup(Parse *pParse, SrcList *pSrc){
|
||||
Table *pTab = 0;
|
||||
int i;
|
||||
struct SrcList_item *pItem;
|
||||
for(i=0, pItem=pSrc->a; i<pSrc->nSrc; i++, pItem++){
|
||||
pTab = sqlite3LocateTable(pParse, pItem->zName, pItem->zDatabase);
|
||||
sqlite3DeleteTable(pItem->pTab);
|
||||
pItem->pTab = pTab;
|
||||
if( pTab ){
|
||||
pTab->nRef++;
|
||||
}
|
||||
}
|
||||
return pTab;
|
||||
}
|
||||
|
||||
/*
|
||||
** Check to make sure the given table is writable. If it is not
|
||||
** writable, generate an error message and return 1. If it is
|
||||
** writable return 0;
|
||||
*/
|
||||
int sqlite3IsReadOnly(Parse *pParse, Table *pTab, int viewOk){
|
||||
if( (pTab->readOnly && (pParse->db->flags & SQLITE_WriteSchema)==0
|
||||
&& pParse->nested==0)
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
|| (pTab->pMod && pTab->pMod->pModule->xUpdate==0)
|
||||
#endif
|
||||
){
|
||||
sqlite3ErrorMsg(pParse, "table %s may not be modified", pTab->zName);
|
||||
return 1;
|
||||
}
|
||||
#ifndef SQLITE_OMIT_VIEW
|
||||
if( !viewOk && pTab->pSelect ){
|
||||
sqlite3ErrorMsg(pParse,"cannot modify %s because it is a view",pTab->zName);
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Generate code that will open a table for reading.
|
||||
*/
|
||||
void sqlite3OpenTable(
|
||||
Parse *p, /* Generate code into this VDBE */
|
||||
int iCur, /* The cursor number of the table */
|
||||
int iDb, /* The database index in sqlite3.aDb[] */
|
||||
Table *pTab, /* The table to be opened */
|
||||
int opcode /* OP_OpenRead or OP_OpenWrite */
|
||||
){
|
||||
Vdbe *v;
|
||||
if( IsVirtual(pTab) ) return;
|
||||
v = sqlite3GetVdbe(p);
|
||||
assert( opcode==OP_OpenWrite || opcode==OP_OpenRead );
|
||||
sqlite3TableLock(p, iDb, pTab->tnum, (opcode==OP_OpenWrite), pTab->zName);
|
||||
sqlite3VdbeAddOp(v, OP_Integer, iDb, 0);
|
||||
VdbeComment((v, "# %s", pTab->zName));
|
||||
sqlite3VdbeAddOp(v, opcode, iCur, pTab->tnum);
|
||||
sqlite3VdbeAddOp(v, OP_SetNumColumns, iCur, pTab->nCol);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Generate code for a DELETE FROM statement.
|
||||
**
|
||||
** DELETE FROM table_wxyz WHERE a<5 AND b NOT NULL;
|
||||
** \________/ \________________/
|
||||
** pTabList pWhere
|
||||
*/
|
||||
void sqlite3DeleteFrom(
|
||||
Parse *pParse, /* The parser context */
|
||||
SrcList *pTabList, /* The table from which we should delete things */
|
||||
Expr *pWhere /* The WHERE clause. May be null */
|
||||
){
|
||||
Vdbe *v; /* The virtual database engine */
|
||||
Table *pTab; /* The table from which records will be deleted */
|
||||
const char *zDb; /* Name of database holding pTab */
|
||||
int end, addr = 0; /* A couple addresses of generated code */
|
||||
int i; /* Loop counter */
|
||||
WhereInfo *pWInfo; /* Information about the WHERE clause */
|
||||
Index *pIdx; /* For looping over indices of the table */
|
||||
int iCur; /* VDBE Cursor number for pTab */
|
||||
sqlite3 *db; /* Main database structure */
|
||||
AuthContext sContext; /* Authorization context */
|
||||
int oldIdx = -1; /* Cursor for the OLD table of AFTER triggers */
|
||||
NameContext sNC; /* Name context to resolve expressions in */
|
||||
int iDb; /* Database number */
|
||||
int memCnt = 0; /* Memory cell used for change counting */
|
||||
|
||||
#ifndef SQLITE_OMIT_TRIGGER
|
||||
int isView; /* True if attempting to delete from a view */
|
||||
int triggers_exist = 0; /* True if any triggers exist */
|
||||
#endif
|
||||
|
||||
sContext.pParse = 0;
|
||||
db = pParse->db;
|
||||
if( pParse->nErr || db->mallocFailed ){
|
||||
goto delete_from_cleanup;
|
||||
}
|
||||
assert( pTabList->nSrc==1 );
|
||||
|
||||
/* Locate the table which we want to delete. This table has to be
|
||||
** put in an SrcList structure because some of the subroutines we
|
||||
** will be calling are designed to work with multiple tables and expect
|
||||
** an SrcList* parameter instead of just a Table* parameter.
|
||||
*/
|
||||
pTab = sqlite3SrcListLookup(pParse, pTabList);
|
||||
if( pTab==0 ) goto delete_from_cleanup;
|
||||
|
||||
/* Figure out if we have any triggers and if the table being
|
||||
** deleted from is a view
|
||||
*/
|
||||
#ifndef SQLITE_OMIT_TRIGGER
|
||||
triggers_exist = sqlite3TriggersExist(pParse, pTab, TK_DELETE, 0);
|
||||
isView = pTab->pSelect!=0;
|
||||
#else
|
||||
# define triggers_exist 0
|
||||
# define isView 0
|
||||
#endif
|
||||
#ifdef SQLITE_OMIT_VIEW
|
||||
# undef isView
|
||||
# define isView 0
|
||||
#endif
|
||||
|
||||
if( sqlite3IsReadOnly(pParse, pTab, triggers_exist) ){
|
||||
goto delete_from_cleanup;
|
||||
}
|
||||
iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
|
||||
assert( iDb<db->nDb );
|
||||
zDb = db->aDb[iDb].zName;
|
||||
if( sqlite3AuthCheck(pParse, SQLITE_DELETE, pTab->zName, 0, zDb) ){
|
||||
goto delete_from_cleanup;
|
||||
}
|
||||
|
||||
/* If pTab is really a view, make sure it has been initialized.
|
||||
*/
|
||||
if( sqlite3ViewGetColumnNames(pParse, pTab) ){
|
||||
goto delete_from_cleanup;
|
||||
}
|
||||
|
||||
/* Allocate a cursor used to store the old.* data for a trigger.
|
||||
*/
|
||||
if( triggers_exist ){
|
||||
oldIdx = pParse->nTab++;
|
||||
}
|
||||
|
||||
/* Resolve the column names in the WHERE clause.
|
||||
*/
|
||||
assert( pTabList->nSrc==1 );
|
||||
iCur = pTabList->a[0].iCursor = pParse->nTab++;
|
||||
memset(&sNC, 0, sizeof(sNC));
|
||||
sNC.pParse = pParse;
|
||||
sNC.pSrcList = pTabList;
|
||||
if( sqlite3ExprResolveNames(&sNC, pWhere) ){
|
||||
goto delete_from_cleanup;
|
||||
}
|
||||
|
||||
/* Start the view context
|
||||
*/
|
||||
if( isView ){
|
||||
sqlite3AuthContextPush(pParse, &sContext, pTab->zName);
|
||||
}
|
||||
|
||||
/* Begin generating code.
|
||||
*/
|
||||
v = sqlite3GetVdbe(pParse);
|
||||
if( v==0 ){
|
||||
goto delete_from_cleanup;
|
||||
}
|
||||
if( pParse->nested==0 ) sqlite3VdbeCountChanges(v);
|
||||
sqlite3BeginWriteOperation(pParse, triggers_exist, iDb);
|
||||
|
||||
/* If we are trying to delete from a view, realize that view into
|
||||
** a ephemeral table.
|
||||
*/
|
||||
if( isView ){
|
||||
Select *pView = sqlite3SelectDup(db, pTab->pSelect);
|
||||
sqlite3Select(pParse, pView, SRT_EphemTab, iCur, 0, 0, 0, 0);
|
||||
sqlite3SelectDelete(pView);
|
||||
}
|
||||
|
||||
/* Initialize the counter of the number of rows deleted, if
|
||||
** we are counting rows.
|
||||
*/
|
||||
if( db->flags & SQLITE_CountRows ){
|
||||
memCnt = pParse->nMem++;
|
||||
sqlite3VdbeAddOp(v, OP_MemInt, 0, memCnt);
|
||||
}
|
||||
|
||||
/* Special case: A DELETE without a WHERE clause deletes everything.
|
||||
** It is easier just to erase the whole table. Note, however, that
|
||||
** this means that the row change count will be incorrect.
|
||||
*/
|
||||
if( pWhere==0 && !triggers_exist && !IsVirtual(pTab) ){
|
||||
if( db->flags & SQLITE_CountRows ){
|
||||
/* If counting rows deleted, just count the total number of
|
||||
** entries in the table. */
|
||||
int endOfLoop = sqlite3VdbeMakeLabel(v);
|
||||
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 ){
|
||||
sqlite3VdbeAddOp(v, OP_Clear, pTab->tnum, iDb);
|
||||
if( !pParse->nested ){
|
||||
sqlite3VdbeChangeP3(v, -1, pTab->zName, P3_STATIC);
|
||||
}
|
||||
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
|
||||
assert( pIdx->pSchema==pTab->pSchema );
|
||||
sqlite3VdbeAddOp(v, OP_Clear, pIdx->tnum, iDb);
|
||||
}
|
||||
}
|
||||
}
|
||||
/* The usual case: There is a WHERE clause so we have to scan through
|
||||
** the table and pick which records to delete.
|
||||
*/
|
||||
else{
|
||||
/* Begin the database scan
|
||||
*/
|
||||
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 0);
|
||||
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 ){
|
||||
sqlite3VdbeAddOp(v, OP_MemIncr, 1, memCnt);
|
||||
}
|
||||
|
||||
/* End the database scan loop.
|
||||
*/
|
||||
sqlite3WhereEnd(pWInfo);
|
||||
|
||||
/* Open the pseudo-table used to store OLD if there are triggers.
|
||||
*/
|
||||
if( triggers_exist ){
|
||||
sqlite3VdbeAddOp(v, OP_OpenPseudo, oldIdx, 0);
|
||||
sqlite3VdbeAddOp(v, OP_SetNumColumns, oldIdx, pTab->nCol);
|
||||
}
|
||||
|
||||
/* Delete every item whose key was written to the list during the
|
||||
** database scan. We have to delete items after the scan is complete
|
||||
** because deleting an item can change the scan order.
|
||||
*/
|
||||
end = sqlite3VdbeMakeLabel(v);
|
||||
|
||||
/* This is the beginning of the delete loop when there are
|
||||
** row triggers.
|
||||
*/
|
||||
if( triggers_exist ){
|
||||
addr = sqlite3VdbeAddOp(v, OP_FifoRead, 0, end);
|
||||
if( !isView ){
|
||||
sqlite3VdbeAddOp(v, OP_Dup, 0, 0);
|
||||
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,
|
||||
-1, oldIdx, (pParse->trigStack)?pParse->trigStack->orconf:OE_Default,
|
||||
addr);
|
||||
}
|
||||
|
||||
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 */
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
if( IsVirtual(pTab) ){
|
||||
pParse->pVirtualLock = pTab;
|
||||
sqlite3VdbeOp3(v, OP_VUpdate, 0, 1, (const char*)pTab->pVtab, P3_VTAB);
|
||||
}else
|
||||
#endif
|
||||
{
|
||||
sqlite3GenerateRowDelete(db, v, pTab, iCur, pParse->nested==0);
|
||||
}
|
||||
}
|
||||
|
||||
/* If there are row triggers, close all cursors then invoke
|
||||
** the AFTER triggers
|
||||
*/
|
||||
if( triggers_exist ){
|
||||
if( !isView ){
|
||||
for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
|
||||
sqlite3VdbeAddOp(v, OP_Close, iCur + i, pIdx->tnum);
|
||||
}
|
||||
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 */
|
||||
sqlite3VdbeAddOp(v, OP_Goto, 0, addr);
|
||||
sqlite3VdbeResolveLabel(v, end);
|
||||
|
||||
/* Close the cursors after the loop if there are no row triggers */
|
||||
if( !triggers_exist && !IsVirtual(pTab) ){
|
||||
for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
|
||||
sqlite3VdbeAddOp(v, OP_Close, iCur + i, pIdx->tnum);
|
||||
}
|
||||
sqlite3VdbeAddOp(v, OP_Close, iCur, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the number of rows that were deleted. If this routine is
|
||||
** generating code because of a call to sqlite3NestedParse(), do not
|
||||
** invoke the callback function.
|
||||
*/
|
||||
if( db->flags & SQLITE_CountRows && pParse->nested==0 && !pParse->trigStack ){
|
||||
sqlite3VdbeAddOp(v, OP_MemLoad, memCnt, 0);
|
||||
sqlite3VdbeAddOp(v, OP_Callback, 1, 0);
|
||||
sqlite3VdbeSetNumCols(v, 1);
|
||||
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "rows deleted", P3_STATIC);
|
||||
}
|
||||
|
||||
delete_from_cleanup:
|
||||
sqlite3AuthContextPop(&sContext);
|
||||
sqlite3SrcListDelete(pTabList);
|
||||
sqlite3ExprDelete(pWhere);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
** This routine generates VDBE code that causes a single row of a
|
||||
** single table to be deleted.
|
||||
**
|
||||
** The VDBE must be in a particular state when this routine is called.
|
||||
** These are the requirements:
|
||||
**
|
||||
** 1. A read/write cursor pointing to pTab, the table containing the row
|
||||
** to be deleted, must be opened as cursor number "base".
|
||||
**
|
||||
** 2. Read/write cursors for all indices of pTab must be open as
|
||||
** cursor number base+i for the i-th index.
|
||||
**
|
||||
** 3. The record number of the row to be deleted must be on the top
|
||||
** of the stack.
|
||||
**
|
||||
** 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
|
||||
** entries that point to that record.
|
||||
*/
|
||||
void sqlite3GenerateRowDelete(
|
||||
sqlite3 *db, /* The database containing the index */
|
||||
Vdbe *v, /* Generate code into this VDBE */
|
||||
Table *pTab, /* Table containing the row to be deleted */
|
||||
int iCur, /* Cursor number for the table */
|
||||
int count /* Increment the row change counter */
|
||||
){
|
||||
int addr;
|
||||
addr = sqlite3VdbeAddOp(v, OP_NotExists, iCur, 0);
|
||||
sqlite3GenerateRowIndexDelete(v, pTab, iCur, 0);
|
||||
sqlite3VdbeAddOp(v, OP_Delete, iCur, (count?OPFLAG_NCHANGE:0));
|
||||
if( count ){
|
||||
sqlite3VdbeChangeP3(v, -1, pTab->zName, P3_STATIC);
|
||||
}
|
||||
sqlite3VdbeJumpHere(v, addr);
|
||||
}
|
||||
|
||||
/*
|
||||
** This routine generates VDBE code that causes the deletion of all
|
||||
** index entries associated with a single row of a single table.
|
||||
**
|
||||
** The VDBE must be in a particular state when this routine is called.
|
||||
** These are the requirements:
|
||||
**
|
||||
** 1. A read/write cursor pointing to pTab, the table containing the row
|
||||
** to be deleted, must be opened as cursor number "iCur".
|
||||
**
|
||||
** 2. Read/write cursors for all indices of pTab must be open as
|
||||
** cursor number iCur+i for the i-th index.
|
||||
**
|
||||
** 3. The "iCur" cursor must be pointing to the row that is to be
|
||||
** deleted.
|
||||
*/
|
||||
void sqlite3GenerateRowIndexDelete(
|
||||
Vdbe *v, /* Generate code into this VDBE */
|
||||
Table *pTab, /* Table containing the row to be deleted */
|
||||
int iCur, /* Cursor number for the table */
|
||||
char *aIdxUsed /* Only delete if aIdxUsed!=0 && aIdxUsed[i]!=0 */
|
||||
){
|
||||
int i;
|
||||
Index *pIdx;
|
||||
|
||||
for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
|
||||
if( aIdxUsed!=0 && aIdxUsed[i-1]==0 ) continue;
|
||||
sqlite3GenerateIndexKey(v, pIdx, iCur);
|
||||
sqlite3VdbeAddOp(v, OP_IdxDelete, iCur+i, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Generate code that will assemble an index key and put it on the top
|
||||
** of the tack. 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
|
||||
** the entry that needs indexing.
|
||||
*/
|
||||
void sqlite3GenerateIndexKey(
|
||||
Vdbe *v, /* Generate code into this VDBE */
|
||||
Index *pIdx, /* The index for which to generate a key */
|
||||
int iCur /* Cursor number for the pIdx->pTable table */
|
||||
){
|
||||
int j;
|
||||
Table *pTab = pIdx->pTable;
|
||||
|
||||
sqlite3VdbeAddOp(v, OP_Rowid, iCur, 0);
|
||||
for(j=0; j<pIdx->nColumn; j++){
|
||||
int idx = pIdx->aiColumn[j];
|
||||
if( idx==pTab->iPKey ){
|
||||
sqlite3VdbeAddOp(v, OP_Dup, j, 0);
|
||||
}else{
|
||||
sqlite3VdbeAddOp(v, OP_Column, iCur, idx);
|
||||
sqlite3ColumnDefault(v, pTab, idx);
|
||||
}
|
||||
}
|
||||
sqlite3VdbeAddOp(v, OP_MakeIdxRec, pIdx->nColumn, 0);
|
||||
sqlite3IndexAffinityStr(v, pIdx);
|
||||
}
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,11 @@
|
|||
#include "sqlite3.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
int sqlite3Fts1Init(sqlite3 *db);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif /* __cplusplus */
|
|
@ -0,0 +1,369 @@
|
|||
/*
|
||||
** 2001 September 22
|
||||
**
|
||||
** The author disclaims copyright to this source code. In place of
|
||||
** a legal notice, here is a blessing:
|
||||
**
|
||||
** May you do good and not evil.
|
||||
** May you find forgiveness for yourself and forgive others.
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
*************************************************************************
|
||||
** This is the implementation of generic hash-tables used in SQLite.
|
||||
** We've modified it slightly to serve as a standalone hash table
|
||||
** implementation for the full-text indexing module.
|
||||
*/
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
/*
|
||||
** The code in this file is only compiled if:
|
||||
**
|
||||
** * The FTS1 module is being built as an extension
|
||||
** (in which case SQLITE_CORE is not defined), or
|
||||
**
|
||||
** * The FTS1 module is being built into the core of
|
||||
** SQLite (in which case SQLITE_ENABLE_FTS1 is defined).
|
||||
*/
|
||||
#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS1)
|
||||
|
||||
|
||||
#include "fts1_hash.h"
|
||||
|
||||
static void *malloc_and_zero(int n){
|
||||
void *p = malloc(n);
|
||||
if( p ){
|
||||
memset(p, 0, n);
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
/* Turn bulk memory into a hash table object by initializing the
|
||||
** fields of the Hash structure.
|
||||
**
|
||||
** "pNew" is a pointer to the hash table that is to be initialized.
|
||||
** keyClass is one of the constants
|
||||
** FTS1_HASH_BINARY or FTS1_HASH_STRING. The value of keyClass
|
||||
** 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.
|
||||
*/
|
||||
void sqlite3Fts1HashInit(fts1Hash *pNew, int keyClass, int copyKey){
|
||||
assert( pNew!=0 );
|
||||
assert( keyClass>=FTS1_HASH_STRING && keyClass<=FTS1_HASH_BINARY );
|
||||
pNew->keyClass = keyClass;
|
||||
pNew->copyKey = copyKey;
|
||||
pNew->first = 0;
|
||||
pNew->count = 0;
|
||||
pNew->htsize = 0;
|
||||
pNew->ht = 0;
|
||||
pNew->xMalloc = malloc_and_zero;
|
||||
pNew->xFree = free;
|
||||
}
|
||||
|
||||
/* Remove all entries from a hash table. Reclaim all memory.
|
||||
** Call this routine to delete a hash table or to reset a hash table
|
||||
** to the empty state.
|
||||
*/
|
||||
void sqlite3Fts1HashClear(fts1Hash *pH){
|
||||
fts1HashElem *elem; /* For looping over all elements of the table */
|
||||
|
||||
assert( pH!=0 );
|
||||
elem = pH->first;
|
||||
pH->first = 0;
|
||||
if( pH->ht ) pH->xFree(pH->ht);
|
||||
pH->ht = 0;
|
||||
pH->htsize = 0;
|
||||
while( elem ){
|
||||
fts1HashElem *next_elem = elem->next;
|
||||
if( pH->copyKey && elem->pKey ){
|
||||
pH->xFree(elem->pKey);
|
||||
}
|
||||
pH->xFree(elem);
|
||||
elem = next_elem;
|
||||
}
|
||||
pH->count = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Hash and comparison functions when the mode is FTS1_HASH_STRING
|
||||
*/
|
||||
static int strHash(const void *pKey, int nKey){
|
||||
const char *z = (const char *)pKey;
|
||||
int h = 0;
|
||||
if( nKey<=0 ) nKey = (int) strlen(z);
|
||||
while( nKey > 0 ){
|
||||
h = (h<<3) ^ h ^ *z++;
|
||||
nKey--;
|
||||
}
|
||||
return h & 0x7fffffff;
|
||||
}
|
||||
static int strCompare(const void *pKey1, int n1, const void *pKey2, int n2){
|
||||
if( n1!=n2 ) return 1;
|
||||
return strncmp((const char*)pKey1,(const char*)pKey2,n1);
|
||||
}
|
||||
|
||||
/*
|
||||
** Hash and comparison functions when the mode is FTS1_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( keyClass==FTS1_HASH_STRING ){
|
||||
return &strHash;
|
||||
}else{
|
||||
assert( keyClass==FTS1_HASH_BINARY );
|
||||
return &binHash;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** 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( keyClass==FTS1_HASH_STRING ){
|
||||
return &strCompare;
|
||||
}else{
|
||||
assert( keyClass==FTS1_HASH_BINARY );
|
||||
return &binCompare;
|
||||
}
|
||||
}
|
||||
|
||||
/* Link an element into the hash table
|
||||
*/
|
||||
static void insertElement(
|
||||
fts1Hash *pH, /* The complete hash table */
|
||||
struct _fts1ht *pEntry, /* The entry into which pNew is inserted */
|
||||
fts1HashElem *pNew /* The element to be inserted */
|
||||
){
|
||||
fts1HashElem *pHead; /* First element already in pEntry */
|
||||
pHead = pEntry->chain;
|
||||
if( pHead ){
|
||||
pNew->next = pHead;
|
||||
pNew->prev = pHead->prev;
|
||||
if( pHead->prev ){ pHead->prev->next = pNew; }
|
||||
else { pH->first = pNew; }
|
||||
pHead->prev = pNew;
|
||||
}else{
|
||||
pNew->next = pH->first;
|
||||
if( pH->first ){ pH->first->prev = pNew; }
|
||||
pNew->prev = 0;
|
||||
pH->first = pNew;
|
||||
}
|
||||
pEntry->count++;
|
||||
pEntry->chain = pNew;
|
||||
}
|
||||
|
||||
|
||||
/* Resize the hash table so that it cantains "new_size" buckets.
|
||||
** "new_size" must be a power of 2. The hash table might fail
|
||||
** to resize if sqliteMalloc() fails.
|
||||
*/
|
||||
static void rehash(fts1Hash *pH, int new_size){
|
||||
struct _fts1ht *new_ht; /* The new hash table */
|
||||
fts1HashElem *elem, *next_elem; /* For looping over existing elements */
|
||||
int (*xHash)(const void*,int); /* The hash function */
|
||||
|
||||
assert( (new_size & (new_size-1))==0 );
|
||||
new_ht = (struct _fts1ht *)pH->xMalloc( new_size*sizeof(struct _fts1ht) );
|
||||
if( new_ht==0 ) return;
|
||||
if( pH->ht ) pH->xFree(pH->ht);
|
||||
pH->ht = new_ht;
|
||||
pH->htsize = new_size;
|
||||
xHash = hashFunction(pH->keyClass);
|
||||
for(elem=pH->first, pH->first=0; elem; elem = next_elem){
|
||||
int h = (*xHash)(elem->pKey, elem->nKey) & (new_size-1);
|
||||
next_elem = elem->next;
|
||||
insertElement(pH, &new_ht[h], elem);
|
||||
}
|
||||
}
|
||||
|
||||
/* This function (for internal use only) locates an element in an
|
||||
** hash table that matches the given key. The hash for this key has
|
||||
** already been computed and is passed as the 4th parameter.
|
||||
*/
|
||||
static fts1HashElem *findElementGivenHash(
|
||||
const fts1Hash *pH, /* The pH to be searched */
|
||||
const void *pKey, /* The key we are searching for */
|
||||
int nKey,
|
||||
int h /* The hash for this key. */
|
||||
){
|
||||
fts1HashElem *elem; /* Used to loop thru the element list */
|
||||
int count; /* Number of elements left to test */
|
||||
int (*xCompare)(const void*,int,const void*,int); /* comparison function */
|
||||
|
||||
if( pH->ht ){
|
||||
struct _fts1ht *pEntry = &pH->ht[h];
|
||||
elem = pEntry->chain;
|
||||
count = pEntry->count;
|
||||
xCompare = compareFunction(pH->keyClass);
|
||||
while( count-- && elem ){
|
||||
if( (*xCompare)(elem->pKey,elem->nKey,pKey,nKey)==0 ){
|
||||
return elem;
|
||||
}
|
||||
elem = elem->next;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Remove a single entry from the hash table given a pointer to that
|
||||
** element and a hash on the element's key.
|
||||
*/
|
||||
static void removeElementGivenHash(
|
||||
fts1Hash *pH, /* The pH containing "elem" */
|
||||
fts1HashElem* elem, /* The element to be removed from the pH */
|
||||
int h /* Hash value for the element */
|
||||
){
|
||||
struct _fts1ht *pEntry;
|
||||
if( elem->prev ){
|
||||
elem->prev->next = elem->next;
|
||||
}else{
|
||||
pH->first = elem->next;
|
||||
}
|
||||
if( elem->next ){
|
||||
elem->next->prev = elem->prev;
|
||||
}
|
||||
pEntry = &pH->ht[h];
|
||||
if( pEntry->chain==elem ){
|
||||
pEntry->chain = elem->next;
|
||||
}
|
||||
pEntry->count--;
|
||||
if( pEntry->count<=0 ){
|
||||
pEntry->chain = 0;
|
||||
}
|
||||
if( pH->copyKey && elem->pKey ){
|
||||
pH->xFree(elem->pKey);
|
||||
}
|
||||
pH->xFree( elem );
|
||||
pH->count--;
|
||||
if( pH->count<=0 ){
|
||||
assert( pH->first==0 );
|
||||
assert( pH->count==0 );
|
||||
fts1HashClear(pH);
|
||||
}
|
||||
}
|
||||
|
||||
/* 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
|
||||
** found, or NULL if there is no match.
|
||||
*/
|
||||
void *sqlite3Fts1HashFind(const fts1Hash *pH, const void *pKey, int nKey){
|
||||
int h; /* A hash on key */
|
||||
fts1HashElem *elem; /* The element that matches key */
|
||||
int (*xHash)(const void*,int); /* The hash function */
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/* Insert an element into the hash table pH. The key is pKey,nKey
|
||||
** and the data is "data".
|
||||
**
|
||||
** If no element exists with a matching key, then a new
|
||||
** element is created. A copy of the key is made if the copyKey
|
||||
** flag is set. NULL is returned.
|
||||
**
|
||||
** If another element already exists with the same key, then the
|
||||
** new data replaces the old data and the old data is returned.
|
||||
** The key is not copied in this instance. If a malloc fails, then
|
||||
** the new data is returned and the hash table is unchanged.
|
||||
**
|
||||
** If the "data" parameter to this function is NULL, then the
|
||||
** element corresponding to "key" is removed from the hash table.
|
||||
*/
|
||||
void *sqlite3Fts1HashInsert(
|
||||
fts1Hash *pH, /* The hash table to insert into */
|
||||
const void *pKey, /* The key */
|
||||
int nKey, /* Number of bytes in the key */
|
||||
void *data /* The data */
|
||||
){
|
||||
int hraw; /* Raw hash value of the key */
|
||||
int h; /* the hash of the key modulo hash table size */
|
||||
fts1HashElem *elem; /* Used to loop thru the element list */
|
||||
fts1HashElem *new_elem; /* New element added to the pH */
|
||||
int (*xHash)(const void*,int); /* The hash function */
|
||||
|
||||
assert( pH!=0 );
|
||||
xHash = hashFunction(pH->keyClass);
|
||||
assert( xHash!=0 );
|
||||
hraw = (*xHash)(pKey, nKey);
|
||||
assert( (pH->htsize & (pH->htsize-1))==0 );
|
||||
h = hraw & (pH->htsize-1);
|
||||
elem = findElementGivenHash(pH,pKey,nKey,h);
|
||||
if( elem ){
|
||||
void *old_data = elem->data;
|
||||
if( data==0 ){
|
||||
removeElementGivenHash(pH,elem,h);
|
||||
}else{
|
||||
elem->data = data;
|
||||
}
|
||||
return old_data;
|
||||
}
|
||||
if( data==0 ) return 0;
|
||||
new_elem = (fts1HashElem*)pH->xMalloc( sizeof(fts1HashElem) );
|
||||
if( new_elem==0 ) return data;
|
||||
if( pH->copyKey && pKey!=0 ){
|
||||
new_elem->pKey = pH->xMalloc( nKey );
|
||||
if( new_elem->pKey==0 ){
|
||||
pH->xFree(new_elem);
|
||||
return data;
|
||||
}
|
||||
memcpy((void*)new_elem->pKey, pKey, nKey);
|
||||
}else{
|
||||
new_elem->pKey = (void*)pKey;
|
||||
}
|
||||
new_elem->nKey = nKey;
|
||||
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 ){
|
||||
rehash(pH,pH->htsize*2);
|
||||
}
|
||||
assert( pH->htsize>0 );
|
||||
assert( (pH->htsize & (pH->htsize-1))==0 );
|
||||
h = hraw & (pH->htsize-1);
|
||||
insertElement(pH, &pH->ht[h], new_elem);
|
||||
new_elem->data = data;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS1) */
|
|
@ -0,0 +1,112 @@
|
|||
/*
|
||||
** 2001 September 22
|
||||
**
|
||||
** The author disclaims copyright to this source code. In place of
|
||||
** a legal notice, here is a blessing:
|
||||
**
|
||||
** May you do good and not evil.
|
||||
** May you find forgiveness for yourself and forgive others.
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
*************************************************************************
|
||||
** This is the header file for the generic hash-table implemenation
|
||||
** used in SQLite. We've modified it slightly to serve as a standalone
|
||||
** hash table implementation for the full-text indexing module.
|
||||
**
|
||||
*/
|
||||
#ifndef _FTS1_HASH_H_
|
||||
#define _FTS1_HASH_H_
|
||||
|
||||
/* Forward declarations of structures. */
|
||||
typedef struct fts1Hash fts1Hash;
|
||||
typedef struct fts1HashElem fts1HashElem;
|
||||
|
||||
/* A complete hash table is an instance of the following structure.
|
||||
** The internals of this structure are intended to be opaque -- client
|
||||
** code should not attempt to access or modify the fields of this structure
|
||||
** directly. Change this structure only by using the routines below.
|
||||
** However, many of the "procedures" and "functions" for modifying and
|
||||
** accessing this structure are really macros, so we can't really make
|
||||
** this structure opaque.
|
||||
*/
|
||||
struct fts1Hash {
|
||||
char keyClass; /* HASH_INT, _POINTER, _STRING, _BINARY */
|
||||
char copyKey; /* True if copy of key made on insert */
|
||||
int count; /* Number of entries in this table */
|
||||
fts1HashElem *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 */
|
||||
struct _fts1ht { /* the hash table */
|
||||
int count; /* Number of entries with this hash */
|
||||
fts1HashElem *chain; /* Pointer to first entry with this hash */
|
||||
} *ht;
|
||||
};
|
||||
|
||||
/* Each element in the hash table is an instance of the following
|
||||
** structure. All elements are stored on a single doubly-linked list.
|
||||
**
|
||||
** Again, this structure is intended to be opaque, but it can't really
|
||||
** be opaque because it is used by macros.
|
||||
*/
|
||||
struct fts1HashElem {
|
||||
fts1HashElem *next, *prev; /* Next and previous elements in the table */
|
||||
void *data; /* Data associated with this element */
|
||||
void *pKey; int nKey; /* Key associated with this element */
|
||||
};
|
||||
|
||||
/*
|
||||
** There are 2 different modes of operation for a hash table:
|
||||
**
|
||||
** FTS1_HASH_STRING pKey points to a string that is nKey bytes long
|
||||
** (including the null-terminator, if any). Case
|
||||
** is respected in comparisons.
|
||||
**
|
||||
** FTS1_HASH_BINARY pKey points to binary data nKey bytes long.
|
||||
** memcmp() is used to compare keys.
|
||||
**
|
||||
** A copy of the key is made if the copyKey parameter to fts1HashInit is 1.
|
||||
*/
|
||||
#define FTS1_HASH_STRING 1
|
||||
#define FTS1_HASH_BINARY 2
|
||||
|
||||
/*
|
||||
** Access routines. To delete, insert a NULL pointer.
|
||||
*/
|
||||
void sqlite3Fts1HashInit(fts1Hash*, int keytype, int copyKey);
|
||||
void *sqlite3Fts1HashInsert(fts1Hash*, const void *pKey, int nKey, void *pData);
|
||||
void *sqlite3Fts1HashFind(const fts1Hash*, const void *pKey, int nKey);
|
||||
void sqlite3Fts1HashClear(fts1Hash*);
|
||||
|
||||
/*
|
||||
** Shorthand for the functions above
|
||||
*/
|
||||
#define fts1HashInit sqlite3Fts1HashInit
|
||||
#define fts1HashInsert sqlite3Fts1HashInsert
|
||||
#define fts1HashFind sqlite3Fts1HashFind
|
||||
#define fts1HashClear sqlite3Fts1HashClear
|
||||
|
||||
/*
|
||||
** Macros for looping over all elements of a hash table. The idiom is
|
||||
** like this:
|
||||
**
|
||||
** fts1Hash h;
|
||||
** fts1HashElem *p;
|
||||
** ...
|
||||
** for(p=fts1HashFirst(&h); p; p=fts1HashNext(p)){
|
||||
** SomeStructure *pData = fts1HashData(p);
|
||||
** // do something with pData
|
||||
** }
|
||||
*/
|
||||
#define fts1HashFirst(H) ((H)->first)
|
||||
#define fts1HashNext(E) ((E)->next)
|
||||
#define fts1HashData(E) ((E)->data)
|
||||
#define fts1HashKey(E) ((E)->pKey)
|
||||
#define fts1HashKeysize(E) ((E)->nKey)
|
||||
|
||||
/*
|
||||
** Number of entries in a hash table
|
||||
*/
|
||||
#define fts1HashCount(H) ((H)->count)
|
||||
|
||||
#endif /* _FTS1_HASH_H_ */
|
|
@ -0,0 +1,643 @@
|
|||
/*
|
||||
** 2006 September 30
|
||||
**
|
||||
** 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.
|
||||
**
|
||||
*************************************************************************
|
||||
** Implementation of the full-text-search tokenizer that implements
|
||||
** a Porter stemmer.
|
||||
*/
|
||||
|
||||
/*
|
||||
** The code in this file is only compiled if:
|
||||
**
|
||||
** * The FTS1 module is being built as an extension
|
||||
** (in which case SQLITE_CORE is not defined), or
|
||||
**
|
||||
** * The FTS1 module is being built into the core of
|
||||
** SQLite (in which case SQLITE_ENABLE_FTS1 is defined).
|
||||
*/
|
||||
#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS1)
|
||||
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "fts1_tokenizer.h"
|
||||
|
||||
/*
|
||||
** Class derived from sqlite3_tokenizer
|
||||
*/
|
||||
typedef struct porter_tokenizer {
|
||||
sqlite3_tokenizer base; /* Base class */
|
||||
} porter_tokenizer;
|
||||
|
||||
/*
|
||||
** Class derived from sqlit3_tokenizer_cursor
|
||||
*/
|
||||
typedef struct porter_tokenizer_cursor {
|
||||
sqlite3_tokenizer_cursor base;
|
||||
const char *zInput; /* input we are tokenizing */
|
||||
int nInput; /* size of the input */
|
||||
int iOffset; /* current position in zInput */
|
||||
int iToken; /* index of next token to be returned */
|
||||
char *zToken; /* storage for current token */
|
||||
int nAllocated; /* space allocated to zToken buffer */
|
||||
} porter_tokenizer_cursor;
|
||||
|
||||
|
||||
/* Forward declaration */
|
||||
static const sqlite3_tokenizer_module porterTokenizerModule;
|
||||
|
||||
|
||||
/*
|
||||
** Create a new tokenizer instance.
|
||||
*/
|
||||
static int porterCreate(
|
||||
int argc, const char * const *argv,
|
||||
sqlite3_tokenizer **ppTokenizer
|
||||
){
|
||||
porter_tokenizer *t;
|
||||
t = (porter_tokenizer *) calloc(sizeof(*t), 1);
|
||||
if( t==NULL ) return SQLITE_NOMEM;
|
||||
|
||||
*ppTokenizer = &t->base;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Destroy a tokenizer
|
||||
*/
|
||||
static int porterDestroy(sqlite3_tokenizer *pTokenizer){
|
||||
free(pTokenizer);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Prepare to begin tokenizing a particular string. The input
|
||||
** string to be tokenized is zInput[0..nInput-1]. A cursor
|
||||
** used to incrementally tokenize this string is returned in
|
||||
** *ppCursor.
|
||||
*/
|
||||
static int porterOpen(
|
||||
sqlite3_tokenizer *pTokenizer, /* The tokenizer */
|
||||
const char *zInput, int nInput, /* String to be tokenized */
|
||||
sqlite3_tokenizer_cursor **ppCursor /* OUT: Tokenization cursor */
|
||||
){
|
||||
porter_tokenizer_cursor *c;
|
||||
|
||||
c = (porter_tokenizer_cursor *) malloc(sizeof(*c));
|
||||
if( c==NULL ) return SQLITE_NOMEM;
|
||||
|
||||
c->zInput = zInput;
|
||||
if( zInput==0 ){
|
||||
c->nInput = 0;
|
||||
}else if( nInput<0 ){
|
||||
c->nInput = (int)strlen(zInput);
|
||||
}else{
|
||||
c->nInput = nInput;
|
||||
}
|
||||
c->iOffset = 0; /* start tokenizing at the beginning */
|
||||
c->iToken = 0;
|
||||
c->zToken = NULL; /* no space allocated, yet. */
|
||||
c->nAllocated = 0;
|
||||
|
||||
*ppCursor = &c->base;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Close a tokenization cursor previously opened by a call to
|
||||
** porterOpen() above.
|
||||
*/
|
||||
static int porterClose(sqlite3_tokenizer_cursor *pCursor){
|
||||
porter_tokenizer_cursor *c = (porter_tokenizer_cursor *) pCursor;
|
||||
free(c->zToken);
|
||||
free(c);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
/*
|
||||
** Vowel or consonant
|
||||
*/
|
||||
static const char cType[] = {
|
||||
0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0,
|
||||
1, 1, 1, 2, 1
|
||||
};
|
||||
|
||||
/*
|
||||
** isConsonant() and isVowel() determine if their first character in
|
||||
** the string they point to is a consonant or a vowel, according
|
||||
** to Porter ruls.
|
||||
**
|
||||
** A consonate is any letter other than 'a', 'e', 'i', 'o', or 'u'.
|
||||
** 'Y' is a consonant unless it follows another consonant,
|
||||
** in which case it is a vowel.
|
||||
**
|
||||
** In these routine, the letters are in reverse order. So the 'y' rule
|
||||
** is that 'y' is a consonant unless it is followed by another
|
||||
** consonent.
|
||||
*/
|
||||
static int isVowel(const char*);
|
||||
static int isConsonant(const char *z){
|
||||
int j;
|
||||
char x = *z;
|
||||
if( x==0 ) return 0;
|
||||
assert( x>='a' && x<='z' );
|
||||
j = cType[x-'a'];
|
||||
if( j<2 ) return j;
|
||||
return z[1]==0 || isVowel(z + 1);
|
||||
}
|
||||
static int isVowel(const char *z){
|
||||
int j;
|
||||
char x = *z;
|
||||
if( x==0 ) return 0;
|
||||
assert( x>='a' && x<='z' );
|
||||
j = cType[x-'a'];
|
||||
if( j<2 ) return 1-j;
|
||||
return isConsonant(z + 1);
|
||||
}
|
||||
|
||||
/*
|
||||
** Let any sequence of one or more vowels be represented by V and let
|
||||
** C be sequence of one or more consonants. Then every word can be
|
||||
** represented as:
|
||||
**
|
||||
** [C] (VC){m} [V]
|
||||
**
|
||||
** In prose: A word is an optional consonant followed by zero or
|
||||
** vowel-consonant pairs followed by an optional vowel. "m" is the
|
||||
** number of vowel consonant pairs. This routine computes the value
|
||||
** of m for the first i bytes of a word.
|
||||
**
|
||||
** Return true if the m-value for z is 1 or more. In other words,
|
||||
** return true if z contains at least one vowel that is followed
|
||||
** by a consonant.
|
||||
**
|
||||
** In this routine z[] is in reverse order. So we are really looking
|
||||
** for an instance of of a consonant followed by a vowel.
|
||||
*/
|
||||
static int m_gt_0(const char *z){
|
||||
while( isVowel(z) ){ z++; }
|
||||
if( *z==0 ) return 0;
|
||||
while( isConsonant(z) ){ z++; }
|
||||
return *z!=0;
|
||||
}
|
||||
|
||||
/* Like mgt0 above except we are looking for a value of m which is
|
||||
** exactly 1
|
||||
*/
|
||||
static int m_eq_1(const char *z){
|
||||
while( isVowel(z) ){ z++; }
|
||||
if( *z==0 ) return 0;
|
||||
while( isConsonant(z) ){ z++; }
|
||||
if( *z==0 ) return 0;
|
||||
while( isVowel(z) ){ z++; }
|
||||
if( *z==0 ) return 1;
|
||||
while( isConsonant(z) ){ z++; }
|
||||
return *z==0;
|
||||
}
|
||||
|
||||
/* Like mgt0 above except we are looking for a value of m>1 instead
|
||||
** or m>0
|
||||
*/
|
||||
static int m_gt_1(const char *z){
|
||||
while( isVowel(z) ){ z++; }
|
||||
if( *z==0 ) return 0;
|
||||
while( isConsonant(z) ){ z++; }
|
||||
if( *z==0 ) return 0;
|
||||
while( isVowel(z) ){ z++; }
|
||||
if( *z==0 ) return 0;
|
||||
while( isConsonant(z) ){ z++; }
|
||||
return *z!=0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return TRUE if there is a vowel anywhere within z[0..n-1]
|
||||
*/
|
||||
static int hasVowel(const char *z){
|
||||
while( isConsonant(z) ){ z++; }
|
||||
return *z!=0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return TRUE if the word ends in a double consonant.
|
||||
**
|
||||
** The text is reversed here. So we are really looking at
|
||||
** the first two characters of z[].
|
||||
*/
|
||||
static int doubleConsonant(const char *z){
|
||||
return isConsonant(z) && z[0]==z[1] && isConsonant(z+1);
|
||||
}
|
||||
|
||||
/*
|
||||
** Return TRUE if the word ends with three letters which
|
||||
** are consonant-vowel-consonent and where the final consonant
|
||||
** is not 'w', 'x', or 'y'.
|
||||
**
|
||||
** The word is reversed here. So we are really checking the
|
||||
** first three letters and the first one cannot be in [wxy].
|
||||
*/
|
||||
static int star_oh(const char *z){
|
||||
return
|
||||
z[0]!=0 && isConsonant(z) &&
|
||||
z[0]!='w' && z[0]!='x' && z[0]!='y' &&
|
||||
z[1]!=0 && isVowel(z+1) &&
|
||||
z[2]!=0 && isConsonant(z+2);
|
||||
}
|
||||
|
||||
/*
|
||||
** If the word ends with zFrom and xCond() is true for the stem
|
||||
** of the word that preceeds the zFrom ending, then change the
|
||||
** ending to zTo.
|
||||
**
|
||||
** The input word *pz and zFrom are both in reverse order. zTo
|
||||
** is in normal order.
|
||||
**
|
||||
** Return TRUE if zFrom matches. Return FALSE if zFrom does not
|
||||
** match. Not that TRUE is returned even if xCond() fails and
|
||||
** no substitution occurs.
|
||||
*/
|
||||
static int stem(
|
||||
char **pz, /* The word being stemmed (Reversed) */
|
||||
const char *zFrom, /* If the ending matches this... (Reversed) */
|
||||
const char *zTo, /* ... change the ending to this (not reversed) */
|
||||
int (*xCond)(const char*) /* Condition that must be true */
|
||||
){
|
||||
char *z = *pz;
|
||||
while( *zFrom && *zFrom==*z ){ z++; zFrom++; }
|
||||
if( *zFrom!=0 ) return 0;
|
||||
if( xCond && !xCond(z) ) return 1;
|
||||
while( *zTo ){
|
||||
*(--z) = *(zTo++);
|
||||
}
|
||||
*pz = z;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
** This is the fallback stemmer used when the porter stemmer is
|
||||
** inappropriate. The input word is copied into the output with
|
||||
** US-ASCII case folding. If the input word is too long (more
|
||||
** than 20 bytes if it contains no digits or more than 6 bytes if
|
||||
** it contains digits) then word is truncated to 20 or 6 bytes
|
||||
** by taking 10 or 3 bytes from the beginning and end.
|
||||
*/
|
||||
static void copy_stemmer(const char *zIn, int nIn, char *zOut, int *pnOut){
|
||||
int i, mx, j;
|
||||
int hasDigit = 0;
|
||||
for(i=0; i<nIn; i++){
|
||||
int c = zIn[i];
|
||||
if( c>='A' && c<='Z' ){
|
||||
zOut[i] = c - 'A' + 'a';
|
||||
}else{
|
||||
if( c>='0' && c<='9' ) hasDigit = 1;
|
||||
zOut[i] = c;
|
||||
}
|
||||
}
|
||||
mx = hasDigit ? 3 : 10;
|
||||
if( nIn>mx*2 ){
|
||||
for(j=mx, i=nIn-mx; i<nIn; i++, j++){
|
||||
zOut[j] = zOut[i];
|
||||
}
|
||||
i = j;
|
||||
}
|
||||
zOut[i] = 0;
|
||||
*pnOut = i;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Stem the input word zIn[0..nIn-1]. Store the output in zOut.
|
||||
** zOut is at least big enough to hold nIn bytes. Write the actual
|
||||
** size of the output word (exclusive of the '\0' terminator) into *pnOut.
|
||||
**
|
||||
** Any upper-case characters in the US-ASCII character set ([A-Z])
|
||||
** are converted to lower case. Upper-case UTF characters are
|
||||
** unchanged.
|
||||
**
|
||||
** Words that are longer than about 20 bytes are stemmed by retaining
|
||||
** a few bytes from the beginning and the end of the word. If the
|
||||
** word contains digits, 3 bytes are taken from the beginning and
|
||||
** 3 bytes from the end. For long words without digits, 10 bytes
|
||||
** are taken from each end. US-ASCII case folding still applies.
|
||||
**
|
||||
** If the input word contains not digits but does characters not
|
||||
** in [a-zA-Z] then no stemming is attempted and this routine just
|
||||
** copies the input into the input into the output with US-ASCII
|
||||
** case folding.
|
||||
**
|
||||
** Stemming never increases the length of the word. So there is
|
||||
** no chance of overflowing the zOut buffer.
|
||||
*/
|
||||
static void porter_stemmer(const char *zIn, int nIn, char *zOut, int *pnOut){
|
||||
int i, j, c;
|
||||
char zReverse[28];
|
||||
char *z, *z2;
|
||||
if( nIn<3 || nIn>=sizeof(zReverse)-7 ){
|
||||
/* The word is too big or too small for the porter stemmer.
|
||||
** Fallback to the copy stemmer */
|
||||
copy_stemmer(zIn, nIn, zOut, pnOut);
|
||||
return;
|
||||
}
|
||||
for(i=0, j=sizeof(zReverse)-6; i<nIn; i++, j--){
|
||||
c = zIn[i];
|
||||
if( c>='A' && c<='Z' ){
|
||||
zReverse[j] = c + 'a' - 'A';
|
||||
}else if( c>='a' && c<='z' ){
|
||||
zReverse[j] = c;
|
||||
}else{
|
||||
/* The use of a character not in [a-zA-Z] means that we fallback
|
||||
** to the copy stemmer */
|
||||
copy_stemmer(zIn, nIn, zOut, pnOut);
|
||||
return;
|
||||
}
|
||||
}
|
||||
memset(&zReverse[sizeof(zReverse)-5], 0, 5);
|
||||
z = &zReverse[j+1];
|
||||
|
||||
|
||||
/* Step 1a */
|
||||
if( z[0]=='s' ){
|
||||
if(
|
||||
!stem(&z, "sess", "ss", 0) &&
|
||||
!stem(&z, "sei", "i", 0) &&
|
||||
!stem(&z, "ss", "ss", 0)
|
||||
){
|
||||
z++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Step 1b */
|
||||
z2 = z;
|
||||
if( stem(&z, "dee", "ee", m_gt_0) ){
|
||||
/* Do nothing. The work was all in the test */
|
||||
}else if(
|
||||
(stem(&z, "gni", "", hasVowel) || stem(&z, "de", "", hasVowel))
|
||||
&& z!=z2
|
||||
){
|
||||
if( stem(&z, "ta", "ate", 0) ||
|
||||
stem(&z, "lb", "ble", 0) ||
|
||||
stem(&z, "zi", "ize", 0) ){
|
||||
/* Do nothing. The work was all in the test */
|
||||
}else if( doubleConsonant(z) && (*z!='l' && *z!='s' && *z!='z') ){
|
||||
z++;
|
||||
}else if( m_eq_1(z) && star_oh(z) ){
|
||||
*(--z) = 'e';
|
||||
}
|
||||
}
|
||||
|
||||
/* Step 1c */
|
||||
if( z[0]=='y' && hasVowel(z+1) ){
|
||||
z[0] = 'i';
|
||||
}
|
||||
|
||||
/* Step 2 */
|
||||
switch( z[1] ){
|
||||
case 'a':
|
||||
stem(&z, "lanoita", "ate", m_gt_0) ||
|
||||
stem(&z, "lanoit", "tion", m_gt_0);
|
||||
break;
|
||||
case 'c':
|
||||
stem(&z, "icne", "ence", m_gt_0) ||
|
||||
stem(&z, "icna", "ance", m_gt_0);
|
||||
break;
|
||||
case 'e':
|
||||
stem(&z, "rezi", "ize", m_gt_0);
|
||||
break;
|
||||
case 'g':
|
||||
stem(&z, "igol", "log", m_gt_0);
|
||||
break;
|
||||
case 'l':
|
||||
stem(&z, "ilb", "ble", m_gt_0) ||
|
||||
stem(&z, "illa", "al", m_gt_0) ||
|
||||
stem(&z, "iltne", "ent", m_gt_0) ||
|
||||
stem(&z, "ile", "e", m_gt_0) ||
|
||||
stem(&z, "ilsuo", "ous", m_gt_0);
|
||||
break;
|
||||
case 'o':
|
||||
stem(&z, "noitazi", "ize", m_gt_0) ||
|
||||
stem(&z, "noita", "ate", m_gt_0) ||
|
||||
stem(&z, "rota", "ate", m_gt_0);
|
||||
break;
|
||||
case 's':
|
||||
stem(&z, "msila", "al", m_gt_0) ||
|
||||
stem(&z, "ssenevi", "ive", m_gt_0) ||
|
||||
stem(&z, "ssenluf", "ful", m_gt_0) ||
|
||||
stem(&z, "ssensuo", "ous", m_gt_0);
|
||||
break;
|
||||
case 't':
|
||||
stem(&z, "itila", "al", m_gt_0) ||
|
||||
stem(&z, "itivi", "ive", m_gt_0) ||
|
||||
stem(&z, "itilib", "ble", m_gt_0);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Step 3 */
|
||||
switch( z[0] ){
|
||||
case 'e':
|
||||
stem(&z, "etaci", "ic", m_gt_0) ||
|
||||
stem(&z, "evita", "", m_gt_0) ||
|
||||
stem(&z, "ezila", "al", m_gt_0);
|
||||
break;
|
||||
case 'i':
|
||||
stem(&z, "itici", "ic", m_gt_0);
|
||||
break;
|
||||
case 'l':
|
||||
stem(&z, "laci", "ic", m_gt_0) ||
|
||||
stem(&z, "luf", "", m_gt_0);
|
||||
break;
|
||||
case 's':
|
||||
stem(&z, "ssen", "", m_gt_0);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Step 4 */
|
||||
switch( z[1] ){
|
||||
case 'a':
|
||||
if( z[0]=='l' && m_gt_1(z+2) ){
|
||||
z += 2;
|
||||
}
|
||||
break;
|
||||
case 'c':
|
||||
if( z[0]=='e' && z[2]=='n' && (z[3]=='a' || z[3]=='e') && m_gt_1(z+4) ){
|
||||
z += 4;
|
||||
}
|
||||
break;
|
||||
case 'e':
|
||||
if( z[0]=='r' && m_gt_1(z+2) ){
|
||||
z += 2;
|
||||
}
|
||||
break;
|
||||
case 'i':
|
||||
if( z[0]=='c' && m_gt_1(z+2) ){
|
||||
z += 2;
|
||||
}
|
||||
break;
|
||||
case 'l':
|
||||
if( z[0]=='e' && z[2]=='b' && (z[3]=='a' || z[3]=='i') && m_gt_1(z+4) ){
|
||||
z += 4;
|
||||
}
|
||||
break;
|
||||
case 'n':
|
||||
if( z[0]=='t' ){
|
||||
if( z[2]=='a' ){
|
||||
if( m_gt_1(z+3) ){
|
||||
z += 3;
|
||||
}
|
||||
}else if( z[2]=='e' ){
|
||||
stem(&z, "tneme", "", m_gt_1) ||
|
||||
stem(&z, "tnem", "", m_gt_1) ||
|
||||
stem(&z, "tne", "", m_gt_1);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'o':
|
||||
if( z[0]=='u' ){
|
||||
if( m_gt_1(z+2) ){
|
||||
z += 2;
|
||||
}
|
||||
}else if( z[3]=='s' || z[3]=='t' ){
|
||||
stem(&z, "noi", "", m_gt_1);
|
||||
}
|
||||
break;
|
||||
case 's':
|
||||
if( z[0]=='m' && z[2]=='i' && m_gt_1(z+3) ){
|
||||
z += 3;
|
||||
}
|
||||
break;
|
||||
case 't':
|
||||
stem(&z, "eta", "", m_gt_1) ||
|
||||
stem(&z, "iti", "", m_gt_1);
|
||||
break;
|
||||
case 'u':
|
||||
if( z[0]=='s' && z[2]=='o' && m_gt_1(z+3) ){
|
||||
z += 3;
|
||||
}
|
||||
break;
|
||||
case 'v':
|
||||
case 'z':
|
||||
if( z[0]=='e' && z[2]=='i' && m_gt_1(z+3) ){
|
||||
z += 3;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* Step 5a */
|
||||
if( z[0]=='e' ){
|
||||
if( m_gt_1(z+1) ){
|
||||
z++;
|
||||
}else if( m_eq_1(z+1) && !star_oh(z+1) ){
|
||||
z++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Step 5b */
|
||||
if( m_gt_1(z) && z[0]=='l' && z[1]=='l' ){
|
||||
z++;
|
||||
}
|
||||
|
||||
/* z[] is now the stemmed word in reverse order. Flip it back
|
||||
** around into forward order and return.
|
||||
*/
|
||||
*pnOut = i = strlen(z);
|
||||
zOut[i] = 0;
|
||||
while( *z ){
|
||||
zOut[--i] = *(z++);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Characters that can be part of a token. We assume any character
|
||||
** whose value is greater than 0x80 (any UTF character) can be
|
||||
** part of a token. In other words, delimiters all must have
|
||||
** values of 0x7f or lower.
|
||||
*/
|
||||
static const char isIdChar[] = {
|
||||
/* x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF */
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, /* 3x */
|
||||
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 4x */
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, /* 5x */
|
||||
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 */
|
||||
};
|
||||
#define idChar(C) (((ch=C)&0x80)!=0 || (ch>0x2f && isIdChar[ch-0x30]))
|
||||
#define isDelim(C) (((ch=C)&0x80)==0 && (ch<0x30 || !isIdChar[ch-0x30]))
|
||||
|
||||
/*
|
||||
** Extract the next token from a tokenization cursor. The cursor must
|
||||
** have been opened by a prior call to porterOpen().
|
||||
*/
|
||||
static int porterNext(
|
||||
sqlite3_tokenizer_cursor *pCursor, /* Cursor returned by porterOpen */
|
||||
const char **pzToken, /* OUT: *pzToken is the token text */
|
||||
int *pnBytes, /* OUT: Number of bytes in token */
|
||||
int *piStartOffset, /* OUT: Starting offset of token */
|
||||
int *piEndOffset, /* OUT: Ending offset of token */
|
||||
int *piPosition /* OUT: Position integer of token */
|
||||
){
|
||||
porter_tokenizer_cursor *c = (porter_tokenizer_cursor *) pCursor;
|
||||
const char *z = c->zInput;
|
||||
|
||||
while( c->iOffset<c->nInput ){
|
||||
int iStartOffset, ch;
|
||||
|
||||
/* Scan past delimiter characters */
|
||||
while( c->iOffset<c->nInput && isDelim(z[c->iOffset]) ){
|
||||
c->iOffset++;
|
||||
}
|
||||
|
||||
/* Count non-delimiter characters. */
|
||||
iStartOffset = c->iOffset;
|
||||
while( c->iOffset<c->nInput && !isDelim(z[c->iOffset]) ){
|
||||
c->iOffset++;
|
||||
}
|
||||
|
||||
if( c->iOffset>iStartOffset ){
|
||||
int n = c->iOffset-iStartOffset;
|
||||
if( n>c->nAllocated ){
|
||||
c->nAllocated = n+20;
|
||||
c->zToken = realloc(c->zToken, c->nAllocated);
|
||||
if( c->zToken==NULL ) return SQLITE_NOMEM;
|
||||
}
|
||||
porter_stemmer(&z[iStartOffset], n, c->zToken, pnBytes);
|
||||
*pzToken = c->zToken;
|
||||
*piStartOffset = iStartOffset;
|
||||
*piEndOffset = c->iOffset;
|
||||
*piPosition = c->iToken++;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
}
|
||||
return SQLITE_DONE;
|
||||
}
|
||||
|
||||
/*
|
||||
** The set of routines that implement the porter-stemmer tokenizer
|
||||
*/
|
||||
static const sqlite3_tokenizer_module porterTokenizerModule = {
|
||||
0,
|
||||
porterCreate,
|
||||
porterDestroy,
|
||||
porterOpen,
|
||||
porterClose,
|
||||
porterNext,
|
||||
};
|
||||
|
||||
/*
|
||||
** Allocate a new porter tokenizer. Return a pointer to the new
|
||||
** tokenizer in *ppModule
|
||||
*/
|
||||
void sqlite3Fts1PorterTokenizerModule(
|
||||
sqlite3_tokenizer_module const**ppModule
|
||||
){
|
||||
*ppModule = &porterTokenizerModule;
|
||||
}
|
||||
|
||||
#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS1) */
|
|
@ -0,0 +1,90 @@
|
|||
/*
|
||||
** 2006 July 10
|
||||
**
|
||||
** The author disclaims copyright to this source code.
|
||||
**
|
||||
*************************************************************************
|
||||
** Defines the interface to tokenizers used by fulltext-search. There
|
||||
** are three basic components:
|
||||
**
|
||||
** sqlite3_tokenizer_module is a singleton defining the tokenizer
|
||||
** interface functions. This is essentially the class structure for
|
||||
** tokenizers.
|
||||
**
|
||||
** sqlite3_tokenizer is used to define a particular tokenizer, perhaps
|
||||
** including customization information defined at creation time.
|
||||
**
|
||||
** sqlite3_tokenizer_cursor is generated by a tokenizer to generate
|
||||
** tokens from a particular input.
|
||||
*/
|
||||
#ifndef _FTS1_TOKENIZER_H_
|
||||
#define _FTS1_TOKENIZER_H_
|
||||
|
||||
/* TODO(shess) Only used for SQLITE_OK and SQLITE_DONE at this time.
|
||||
** If tokenizers are to be allowed to call sqlite3_*() functions, then
|
||||
** we will need a way to register the API consistently.
|
||||
*/
|
||||
#include "sqlite3.h"
|
||||
|
||||
/*
|
||||
** Structures used by the tokenizer interface.
|
||||
*/
|
||||
typedef struct sqlite3_tokenizer sqlite3_tokenizer;
|
||||
typedef struct sqlite3_tokenizer_cursor sqlite3_tokenizer_cursor;
|
||||
typedef struct sqlite3_tokenizer_module sqlite3_tokenizer_module;
|
||||
|
||||
struct sqlite3_tokenizer_module {
|
||||
int iVersion; /* currently 0 */
|
||||
|
||||
/*
|
||||
** Create and destroy a tokenizer. argc/argv are passed down from
|
||||
** the fulltext virtual table creation to allow customization.
|
||||
*/
|
||||
int (*xCreate)(int argc, const char *const*argv,
|
||||
sqlite3_tokenizer **ppTokenizer);
|
||||
int (*xDestroy)(sqlite3_tokenizer *pTokenizer);
|
||||
|
||||
/*
|
||||
** Tokenize a particular input. Call xOpen() to prepare to
|
||||
** tokenize, xNext() repeatedly until it returns SQLITE_DONE, then
|
||||
** xClose() to free any internal state. The pInput passed to
|
||||
** xOpen() must exist until the cursor is closed. The ppToken
|
||||
** result from xNext() is only valid until the next call to xNext()
|
||||
** or until xClose() is called.
|
||||
*/
|
||||
/* TODO(shess) current implementation requires pInput to be
|
||||
** nul-terminated. This should either be fixed, or pInput/nBytes
|
||||
** should be converted to zInput.
|
||||
*/
|
||||
int (*xOpen)(sqlite3_tokenizer *pTokenizer,
|
||||
const char *pInput, int nBytes,
|
||||
sqlite3_tokenizer_cursor **ppCursor);
|
||||
int (*xClose)(sqlite3_tokenizer_cursor *pCursor);
|
||||
int (*xNext)(sqlite3_tokenizer_cursor *pCursor,
|
||||
const char **ppToken, int *pnBytes,
|
||||
int *piStartOffset, int *piEndOffset, int *piPosition);
|
||||
};
|
||||
|
||||
struct sqlite3_tokenizer {
|
||||
const sqlite3_tokenizer_module *pModule; /* The module for this tokenizer */
|
||||
/* Tokenizer implementations will typically add additional fields */
|
||||
};
|
||||
|
||||
struct sqlite3_tokenizer_cursor {
|
||||
sqlite3_tokenizer *pTokenizer; /* Tokenizer for this cursor. */
|
||||
/* Tokenizer implementations will typically add additional fields */
|
||||
};
|
||||
|
||||
/*
|
||||
** Get the module for a tokenizer which generates tokens based on a
|
||||
** set of non-token characters. The default is to break tokens at any
|
||||
** non-alnum character, though the set of delimiters can also be
|
||||
** specified by the first argv argument to xCreate().
|
||||
*/
|
||||
/* TODO(shess) This doesn't belong here. Need some sort of
|
||||
** registration process.
|
||||
*/
|
||||
void sqlite3Fts1SimpleTokenizerModule(sqlite3_tokenizer_module const**ppModule);
|
||||
void sqlite3Fts1PorterTokenizerModule(sqlite3_tokenizer_module const**ppModule);
|
||||
|
||||
#endif /* _FTS1_TOKENIZER_H_ */
|
|
@ -0,0 +1,221 @@
|
|||
/*
|
||||
** The author disclaims copyright to this source code.
|
||||
**
|
||||
*************************************************************************
|
||||
** Implementation of the "simple" full-text-search tokenizer.
|
||||
*/
|
||||
|
||||
/*
|
||||
** The code in this file is only compiled if:
|
||||
**
|
||||
** * The FTS1 module is being built as an extension
|
||||
** (in which case SQLITE_CORE is not defined), or
|
||||
**
|
||||
** * The FTS1 module is being built into the core of
|
||||
** SQLite (in which case SQLITE_ENABLE_FTS1 is defined).
|
||||
*/
|
||||
#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS1)
|
||||
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "fts1_tokenizer.h"
|
||||
|
||||
typedef struct simple_tokenizer {
|
||||
sqlite3_tokenizer base;
|
||||
char delim[128]; /* flag ASCII delimiters */
|
||||
} simple_tokenizer;
|
||||
|
||||
typedef struct simple_tokenizer_cursor {
|
||||
sqlite3_tokenizer_cursor base;
|
||||
const char *pInput; /* input we are tokenizing */
|
||||
int nBytes; /* size of the input */
|
||||
int iOffset; /* current position in pInput */
|
||||
int iToken; /* index of next token to be returned */
|
||||
char *pToken; /* storage for current token */
|
||||
int nTokenAllocated; /* space allocated to zToken buffer */
|
||||
} simple_tokenizer_cursor;
|
||||
|
||||
|
||||
/* Forward declaration */
|
||||
static const sqlite3_tokenizer_module simpleTokenizerModule;
|
||||
|
||||
static int isDelim(simple_tokenizer *t, unsigned char c){
|
||||
return c<0x80 && t->delim[c];
|
||||
}
|
||||
|
||||
/*
|
||||
** Create a new tokenizer instance.
|
||||
*/
|
||||
static int simpleCreate(
|
||||
int argc, const char * const *argv,
|
||||
sqlite3_tokenizer **ppTokenizer
|
||||
){
|
||||
simple_tokenizer *t;
|
||||
|
||||
t = (simple_tokenizer *) calloc(sizeof(*t), 1);
|
||||
if( t==NULL ) return SQLITE_NOMEM;
|
||||
|
||||
/* 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
|
||||
** track such information in the database, then we'd only want this
|
||||
** information on the initial create.
|
||||
*/
|
||||
if( argc>1 ){
|
||||
int i, n = strlen(argv[1]);
|
||||
for(i=0; i<n; i++){
|
||||
unsigned char ch = argv[1][i];
|
||||
/* We explicitly don't support UTF-8 delimiters for now. */
|
||||
if( ch>=0x80 ){
|
||||
free(t);
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
t->delim[ch] = 1;
|
||||
}
|
||||
} else {
|
||||
/* Mark non-alphanumeric ASCII characters as delimiters */
|
||||
int i;
|
||||
for(i=1; i<0x80; i++){
|
||||
t->delim[i] = !isalnum(i);
|
||||
}
|
||||
}
|
||||
|
||||
*ppTokenizer = &t->base;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Destroy a tokenizer
|
||||
*/
|
||||
static int simpleDestroy(sqlite3_tokenizer *pTokenizer){
|
||||
free(pTokenizer);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Prepare to begin tokenizing a particular string. The input
|
||||
** string to be tokenized is pInput[0..nBytes-1]. A cursor
|
||||
** used to incrementally tokenize this string is returned in
|
||||
** *ppCursor.
|
||||
*/
|
||||
static int simpleOpen(
|
||||
sqlite3_tokenizer *pTokenizer, /* The tokenizer */
|
||||
const char *pInput, int nBytes, /* String to be tokenized */
|
||||
sqlite3_tokenizer_cursor **ppCursor /* OUT: Tokenization cursor */
|
||||
){
|
||||
simple_tokenizer_cursor *c;
|
||||
|
||||
c = (simple_tokenizer_cursor *) malloc(sizeof(*c));
|
||||
if( c==NULL ) return SQLITE_NOMEM;
|
||||
|
||||
c->pInput = pInput;
|
||||
if( pInput==0 ){
|
||||
c->nBytes = 0;
|
||||
}else if( nBytes<0 ){
|
||||
c->nBytes = (int)strlen(pInput);
|
||||
}else{
|
||||
c->nBytes = nBytes;
|
||||
}
|
||||
c->iOffset = 0; /* start tokenizing at the beginning */
|
||||
c->iToken = 0;
|
||||
c->pToken = NULL; /* no space allocated, yet. */
|
||||
c->nTokenAllocated = 0;
|
||||
|
||||
*ppCursor = &c->base;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Close a tokenization cursor previously opened by a call to
|
||||
** simpleOpen() above.
|
||||
*/
|
||||
static int simpleClose(sqlite3_tokenizer_cursor *pCursor){
|
||||
simple_tokenizer_cursor *c = (simple_tokenizer_cursor *) pCursor;
|
||||
free(c->pToken);
|
||||
free(c);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Extract the next token from a tokenization cursor. The cursor must
|
||||
** have been opened by a prior call to simpleOpen().
|
||||
*/
|
||||
static int simpleNext(
|
||||
sqlite3_tokenizer_cursor *pCursor, /* Cursor returned by simpleOpen */
|
||||
const char **ppToken, /* OUT: *ppToken is the token text */
|
||||
int *pnBytes, /* OUT: Number of bytes in token */
|
||||
int *piStartOffset, /* OUT: Starting offset of token */
|
||||
int *piEndOffset, /* OUT: Ending offset of token */
|
||||
int *piPosition /* OUT: Position integer of token */
|
||||
){
|
||||
simple_tokenizer_cursor *c = (simple_tokenizer_cursor *) pCursor;
|
||||
simple_tokenizer *t = (simple_tokenizer *) pCursor->pTokenizer;
|
||||
unsigned char *p = (unsigned char *)c->pInput;
|
||||
|
||||
while( c->iOffset<c->nBytes ){
|
||||
int iStartOffset;
|
||||
|
||||
/* Scan past delimiter characters */
|
||||
while( c->iOffset<c->nBytes && isDelim(t, p[c->iOffset]) ){
|
||||
c->iOffset++;
|
||||
}
|
||||
|
||||
/* Count non-delimiter characters. */
|
||||
iStartOffset = c->iOffset;
|
||||
while( c->iOffset<c->nBytes && !isDelim(t, p[c->iOffset]) ){
|
||||
c->iOffset++;
|
||||
}
|
||||
|
||||
if( c->iOffset>iStartOffset ){
|
||||
int i, n = c->iOffset-iStartOffset;
|
||||
if( n>c->nTokenAllocated ){
|
||||
c->nTokenAllocated = n+20;
|
||||
c->pToken = realloc(c->pToken, c->nTokenAllocated);
|
||||
if( c->pToken==NULL ) return SQLITE_NOMEM;
|
||||
}
|
||||
for(i=0; i<n; i++){
|
||||
/* TODO(shess) This needs expansion to handle UTF-8
|
||||
** case-insensitivity.
|
||||
*/
|
||||
unsigned char ch = p[iStartOffset+i];
|
||||
c->pToken[i] = ch<0x80 ? tolower(ch) : ch;
|
||||
}
|
||||
*ppToken = c->pToken;
|
||||
*pnBytes = n;
|
||||
*piStartOffset = iStartOffset;
|
||||
*piEndOffset = c->iOffset;
|
||||
*piPosition = c->iToken++;
|
||||
|
||||
return SQLITE_OK;
|
||||
}
|
||||
}
|
||||
return SQLITE_DONE;
|
||||
}
|
||||
|
||||
/*
|
||||
** The set of routines that implement the simple tokenizer
|
||||
*/
|
||||
static const sqlite3_tokenizer_module simpleTokenizerModule = {
|
||||
0,
|
||||
simpleCreate,
|
||||
simpleDestroy,
|
||||
simpleOpen,
|
||||
simpleClose,
|
||||
simpleNext,
|
||||
};
|
||||
|
||||
/*
|
||||
** Allocate a new simple tokenizer. Return a pointer to the new
|
||||
** tokenizer in *ppModule
|
||||
*/
|
||||
void sqlite3Fts1SimpleTokenizerModule(
|
||||
sqlite3_tokenizer_module const**ppModule
|
||||
){
|
||||
*ppModule = &simpleTokenizerModule;
|
||||
}
|
||||
|
||||
#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS1) */
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,418 @@
|
|||
/*
|
||||
** 2001 September 22
|
||||
**
|
||||
** The author disclaims copyright to this source code. In place of
|
||||
** a legal notice, here is a blessing:
|
||||
**
|
||||
** May you do good and not evil.
|
||||
** May you find forgiveness for yourself and forgive others.
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
*************************************************************************
|
||||
** This is the implementation of generic hash-tables
|
||||
** used in SQLite.
|
||||
**
|
||||
** $Id: hash.c,v 1.24 2007/09/04 14:31:47 danielk1977 Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include <assert.h>
|
||||
|
||||
/* Turn bulk memory into a hash table object by initializing the
|
||||
** fields of the Hash structure.
|
||||
**
|
||||
** "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,
|
||||
** SQLITE_HASH_BINARY, or SQLITE_HASH_STRING. The value of keyClass
|
||||
** 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){
|
||||
assert( pNew!=0 );
|
||||
assert( keyClass>=SQLITE_HASH_STRING && keyClass<=SQLITE_HASH_BINARY );
|
||||
pNew->keyClass = keyClass;
|
||||
#if 0
|
||||
if( keyClass==SQLITE_HASH_POINTER || keyClass==SQLITE_HASH_INT ) copyKey = 0;
|
||||
#endif
|
||||
pNew->copyKey = copyKey;
|
||||
pNew->first = 0;
|
||||
pNew->count = 0;
|
||||
pNew->htsize = 0;
|
||||
pNew->ht = 0;
|
||||
}
|
||||
|
||||
/* Remove all entries from a hash table. Reclaim all memory.
|
||||
** Call this routine to delete a hash table or to reset a hash table
|
||||
** to the empty state.
|
||||
*/
|
||||
void sqlite3HashClear(Hash *pH){
|
||||
HashElem *elem; /* For looping over all elements of the table */
|
||||
|
||||
assert( pH!=0 );
|
||||
elem = pH->first;
|
||||
pH->first = 0;
|
||||
if( pH->ht ) sqlite3_free(pH->ht);
|
||||
pH->ht = 0;
|
||||
pH->htsize = 0;
|
||||
while( elem ){
|
||||
HashElem *next_elem = elem->next;
|
||||
if( pH->copyKey && elem->pKey ){
|
||||
sqlite3_free(elem->pKey);
|
||||
}
|
||||
sqlite3_free(elem);
|
||||
elem = next_elem;
|
||||
}
|
||||
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
|
||||
*/
|
||||
static int strHash(const void *pKey, int nKey){
|
||||
const char *z = (const char *)pKey;
|
||||
int h = 0;
|
||||
if( nKey<=0 ) nKey = strlen(z);
|
||||
while( nKey > 0 ){
|
||||
h = (h<<3) ^ h ^ sqlite3UpperToLower[(unsigned char)*z++];
|
||||
nKey--;
|
||||
}
|
||||
return h & 0x7fffffff;
|
||||
}
|
||||
static int strCompare(const void *pKey1, int n1, const void *pKey2, int n2){
|
||||
if( n1!=n2 ) return 1;
|
||||
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
|
||||
*/
|
||||
static void insertElement(
|
||||
Hash *pH, /* The complete hash table */
|
||||
struct _ht *pEntry, /* The entry into which pNew is inserted */
|
||||
HashElem *pNew /* The element to be inserted */
|
||||
){
|
||||
HashElem *pHead; /* First element already in pEntry */
|
||||
pHead = pEntry->chain;
|
||||
if( pHead ){
|
||||
pNew->next = pHead;
|
||||
pNew->prev = pHead->prev;
|
||||
if( pHead->prev ){ pHead->prev->next = pNew; }
|
||||
else { pH->first = pNew; }
|
||||
pHead->prev = pNew;
|
||||
}else{
|
||||
pNew->next = pH->first;
|
||||
if( pH->first ){ pH->first->prev = pNew; }
|
||||
pNew->prev = 0;
|
||||
pH->first = pNew;
|
||||
}
|
||||
pEntry->count++;
|
||||
pEntry->chain = pNew;
|
||||
}
|
||||
|
||||
|
||||
/* Resize the hash table so that it cantains "new_size" buckets.
|
||||
** "new_size" must be a power of 2. The hash table might fail
|
||||
** to resize if sqlite3_malloc() fails.
|
||||
*/
|
||||
static void rehash(Hash *pH, int new_size){
|
||||
struct _ht *new_ht; /* The new hash table */
|
||||
HashElem *elem, *next_elem; /* For looping over existing elements */
|
||||
int (*xHash)(const void*,int); /* The hash function */
|
||||
|
||||
assert( (new_size & (new_size-1))==0 );
|
||||
|
||||
/* 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).
|
||||
*/
|
||||
sqlite3MallocBenignFailure(pH->htsize>0);
|
||||
|
||||
new_ht = (struct _ht *)sqlite3MallocZero( new_size*sizeof(struct _ht) );
|
||||
if( new_ht==0 ) return;
|
||||
if( pH->ht ) sqlite3_free(pH->ht);
|
||||
pH->ht = new_ht;
|
||||
pH->htsize = new_size;
|
||||
xHash = hashFunction(pH->keyClass);
|
||||
for(elem=pH->first, pH->first=0; elem; elem = next_elem){
|
||||
int h = (*xHash)(elem->pKey, elem->nKey) & (new_size-1);
|
||||
next_elem = elem->next;
|
||||
insertElement(pH, &new_ht[h], elem);
|
||||
}
|
||||
}
|
||||
|
||||
/* This function (for internal use only) locates an element in an
|
||||
** hash table that matches the given key. The hash for this key has
|
||||
** already been computed and is passed as the 4th parameter.
|
||||
*/
|
||||
static HashElem *findElementGivenHash(
|
||||
const Hash *pH, /* The pH to be searched */
|
||||
const void *pKey, /* The key we are searching for */
|
||||
int nKey,
|
||||
int h /* The hash for this key. */
|
||||
){
|
||||
HashElem *elem; /* Used to loop thru the element list */
|
||||
int count; /* Number of elements left to test */
|
||||
int (*xCompare)(const void*,int,const void*,int); /* comparison function */
|
||||
|
||||
if( pH->ht ){
|
||||
struct _ht *pEntry = &pH->ht[h];
|
||||
elem = pEntry->chain;
|
||||
count = pEntry->count;
|
||||
xCompare = compareFunction(pH->keyClass);
|
||||
while( count-- && elem ){
|
||||
if( (*xCompare)(elem->pKey,elem->nKey,pKey,nKey)==0 ){
|
||||
return elem;
|
||||
}
|
||||
elem = elem->next;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Remove a single entry from the hash table given a pointer to that
|
||||
** element and a hash on the element's key.
|
||||
*/
|
||||
static void removeElementGivenHash(
|
||||
Hash *pH, /* The pH containing "elem" */
|
||||
HashElem* elem, /* The element to be removed from the pH */
|
||||
int h /* Hash value for the element */
|
||||
){
|
||||
struct _ht *pEntry;
|
||||
if( elem->prev ){
|
||||
elem->prev->next = elem->next;
|
||||
}else{
|
||||
pH->first = elem->next;
|
||||
}
|
||||
if( elem->next ){
|
||||
elem->next->prev = elem->prev;
|
||||
}
|
||||
pEntry = &pH->ht[h];
|
||||
if( pEntry->chain==elem ){
|
||||
pEntry->chain = elem->next;
|
||||
}
|
||||
pEntry->count--;
|
||||
if( pEntry->count<=0 ){
|
||||
pEntry->chain = 0;
|
||||
}
|
||||
if( pH->copyKey ){
|
||||
sqlite3_free(elem->pKey);
|
||||
}
|
||||
sqlite3_free( elem );
|
||||
pH->count--;
|
||||
if( pH->count<=0 ){
|
||||
assert( pH->first==0 );
|
||||
assert( pH->count==0 );
|
||||
sqlite3HashClear(pH);
|
||||
}
|
||||
}
|
||||
|
||||
/* Attempt to locate an element of the hash table pH with a key
|
||||
** 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 */
|
||||
int (*xHash)(const void*,int); /* The hash function */
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/* 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
|
||||
** found, or NULL if there is no match.
|
||||
*/
|
||||
void *sqlite3HashFind(const Hash *pH, const void *pKey, int nKey){
|
||||
HashElem *elem; /* The element that matches key */
|
||||
elem = sqlite3HashFindElem(pH, pKey, nKey);
|
||||
return elem ? elem->data : 0;
|
||||
}
|
||||
|
||||
/* Insert an element into the hash table pH. The key is pKey,nKey
|
||||
** and the data is "data".
|
||||
**
|
||||
** If no element exists with a matching key, then a new
|
||||
** element is created. A copy of the key is made if the copyKey
|
||||
** flag is set. NULL is returned.
|
||||
**
|
||||
** If another element already exists with the same key, then the
|
||||
** new data replaces the old data and the old data is returned.
|
||||
** The key is not copied in this instance. If a malloc fails, then
|
||||
** the new data is returned and the hash table is unchanged.
|
||||
**
|
||||
** If the "data" parameter to this function is NULL, then the
|
||||
** element corresponding to "key" is removed from the hash table.
|
||||
*/
|
||||
void *sqlite3HashInsert(Hash *pH, const void *pKey, int nKey, void *data){
|
||||
int hraw; /* Raw hash value of the key */
|
||||
int h; /* the hash of the key modulo hash table size */
|
||||
HashElem *elem; /* Used to loop thru the element list */
|
||||
HashElem *new_elem; /* New element added to the pH */
|
||||
int (*xHash)(const void*,int); /* The hash function */
|
||||
|
||||
assert( pH!=0 );
|
||||
xHash = hashFunction(pH->keyClass);
|
||||
assert( xHash!=0 );
|
||||
hraw = (*xHash)(pKey, nKey);
|
||||
assert( (pH->htsize & (pH->htsize-1))==0 );
|
||||
h = hraw & (pH->htsize-1);
|
||||
elem = findElementGivenHash(pH,pKey,nKey,h);
|
||||
if( elem ){
|
||||
void *old_data = elem->data;
|
||||
if( data==0 ){
|
||||
removeElementGivenHash(pH,elem,h);
|
||||
}else{
|
||||
elem->data = data;
|
||||
if( !pH->copyKey ){
|
||||
elem->pKey = (void *)pKey;
|
||||
}
|
||||
assert(nKey==elem->nKey);
|
||||
}
|
||||
return old_data;
|
||||
}
|
||||
if( data==0 ) return 0;
|
||||
new_elem = (HashElem*)sqlite3_malloc( sizeof(HashElem) );
|
||||
if( new_elem==0 ) return data;
|
||||
if( pH->copyKey && pKey!=0 ){
|
||||
new_elem->pKey = sqlite3_malloc( nKey );
|
||||
if( new_elem->pKey==0 ){
|
||||
sqlite3_free(new_elem);
|
||||
return data;
|
||||
}
|
||||
memcpy((void*)new_elem->pKey, pKey, nKey);
|
||||
}else{
|
||||
new_elem->pKey = (void*)pKey;
|
||||
}
|
||||
new_elem->nKey = nKey;
|
||||
pH->count++;
|
||||
if( pH->htsize==0 ){
|
||||
rehash(pH,8);
|
||||
if( pH->htsize==0 ){
|
||||
pH->count = 0;
|
||||
if( pH->copyKey ){
|
||||
sqlite3_free(new_elem->pKey);
|
||||
}
|
||||
sqlite3_free(new_elem);
|
||||
return data;
|
||||
}
|
||||
}
|
||||
if( pH->count > pH->htsize ){
|
||||
rehash(pH,pH->htsize*2);
|
||||
}
|
||||
assert( pH->htsize>0 );
|
||||
assert( (pH->htsize & (pH->htsize-1))==0 );
|
||||
h = hraw & (pH->htsize-1);
|
||||
insertElement(pH, &pH->ht[h], new_elem);
|
||||
new_elem->data = data;
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,110 @@
|
|||
/*
|
||||
** 2001 September 22
|
||||
**
|
||||
** The author disclaims copyright to this source code. In place of
|
||||
** a legal notice, here is a blessing:
|
||||
**
|
||||
** May you do good and not evil.
|
||||
** May you find forgiveness for yourself and forgive others.
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
*************************************************************************
|
||||
** This is the header file for the generic hash-table implemenation
|
||||
** used in SQLite.
|
||||
**
|
||||
** $Id: hash.h,v 1.11 2007/09/04 14:31:47 danielk1977 Exp $
|
||||
*/
|
||||
#ifndef _SQLITE_HASH_H_
|
||||
#define _SQLITE_HASH_H_
|
||||
|
||||
/* Forward declarations of structures. */
|
||||
typedef struct Hash Hash;
|
||||
typedef struct HashElem HashElem;
|
||||
|
||||
/* A complete hash table is an instance of the following structure.
|
||||
** The internals of this structure are intended to be opaque -- client
|
||||
** code should not attempt to access or modify the fields of this structure
|
||||
** directly. Change this structure only by using the routines below.
|
||||
** However, many of the "procedures" and "functions" for modifying and
|
||||
** accessing this structure are really macros, so we can't really make
|
||||
** this structure opaque.
|
||||
*/
|
||||
struct Hash {
|
||||
char keyClass; /* SQLITE_HASH_INT, _POINTER, _STRING, _BINARY */
|
||||
char copyKey; /* True if copy of key made on insert */
|
||||
int count; /* Number of entries in this table */
|
||||
int htsize; /* Number of buckets in the hash table */
|
||||
HashElem *first; /* The first element of the array */
|
||||
struct _ht { /* the hash table */
|
||||
int count; /* Number of entries with this hash */
|
||||
HashElem *chain; /* Pointer to first entry with this hash */
|
||||
} *ht;
|
||||
};
|
||||
|
||||
/* Each element in the hash table is an instance of the following
|
||||
** structure. All elements are stored on a single doubly-linked list.
|
||||
**
|
||||
** Again, this structure is intended to be opaque, but it can't really
|
||||
** be opaque because it is used by macros.
|
||||
*/
|
||||
struct HashElem {
|
||||
HashElem *next, *prev; /* Next and previous elements in the table */
|
||||
void *data; /* Data 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.
|
||||
*/
|
||||
void sqlite3HashInit(Hash*, int keytype, int copyKey);
|
||||
void *sqlite3HashInsert(Hash*, const void *pKey, int nKey, void *pData);
|
||||
void *sqlite3HashFind(const Hash*, const void *pKey, int nKey);
|
||||
HashElem *sqlite3HashFindElem(const Hash*, const void *pKey, int nKey);
|
||||
void sqlite3HashClear(Hash*);
|
||||
|
||||
/*
|
||||
** Macros for looping over all elements of a hash table. The idiom is
|
||||
** like this:
|
||||
**
|
||||
** Hash h;
|
||||
** HashElem *p;
|
||||
** ...
|
||||
** for(p=sqliteHashFirst(&h); p; p=sqliteHashNext(p)){
|
||||
** SomeStructure *pData = sqliteHashData(p);
|
||||
** // do something with pData
|
||||
** }
|
||||
*/
|
||||
#define sqliteHashFirst(H) ((H)->first)
|
||||
#define sqliteHashNext(E) ((E)->next)
|
||||
#define sqliteHashData(E) ((E)->data)
|
||||
#define sqliteHashKey(E) ((E)->pKey)
|
||||
#define sqliteHashKeysize(E) ((E)->nKey)
|
||||
|
||||
/*
|
||||
** Number of entries in a hash table
|
||||
*/
|
||||
#define sqliteHashCount(H) ((H)->count)
|
||||
|
||||
#endif /* _SQLITE_HASH_H_ */
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,238 @@
|
|||
/*
|
||||
** 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.7 2007/09/06 13:49:37 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;
|
||||
rc = createFile(p);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3OsSync(p->pReal, flags);
|
||||
}
|
||||
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
|
|
@ -0,0 +1,112 @@
|
|||
/***** This file contains automatically generated code ******
|
||||
**
|
||||
** 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 $
|
||||
**
|
||||
** The code in this file implements a function that determines whether
|
||||
** or not a given identifier is really an SQL keyword. The same thing
|
||||
** might be implemented more directly using a hand-written hash table.
|
||||
** But by using this automatically generated code, the size of the code
|
||||
** is substantially reduced. This is important for embedded applications
|
||||
** on platforms with limited memory.
|
||||
*/
|
||||
/* Hash score: 165 */
|
||||
static int keywordCode(const char *z, int n){
|
||||
/* zText[] encodes 775 bytes of keywords in 526 bytes */
|
||||
static const char zText[526] =
|
||||
"BEFOREIGNOREGEXPLAINSTEADDESCAPEACHECKEYCONSTRAINTERSECTABLEFT"
|
||||
"HENDATABASELECTRANSACTIONATURALTERAISELSEXCEPTRIGGEREFERENCES"
|
||||
"UNIQUERYATTACHAVINGROUPDATEMPORARYBEGINNEREINDEXCLUSIVEXISTSBETWEEN"
|
||||
"OTNULLIKECASCADEFERRABLECASECOLLATECREATECURRENT_DATEDELETEDETACH"
|
||||
"IMMEDIATEJOINSERTMATCHPLANALYZEPRAGMABORTVALUESVIRTUALIMITWHEN"
|
||||
"WHERENAMEAFTEREPLACEANDEFAULTAUTOINCREMENTCASTCOLUMNCOMMITCONFLICT"
|
||||
"CROSSCURRENT_TIMESTAMPRIMARYDEFERREDISTINCTDROPFAILFROMFULLGLOB"
|
||||
"YIFINTOFFSETISNULLORDERESTRICTOUTERIGHTROLLBACKROWUNIONUSINGVACUUM"
|
||||
"VIEWINITIALLY";
|
||||
static const unsigned char aHash[127] = {
|
||||
63, 92, 109, 61, 0, 38, 0, 0, 69, 0, 64, 0, 0,
|
||||
102, 4, 65, 7, 0, 108, 72, 103, 99, 0, 22, 0, 0,
|
||||
113, 0, 111, 106, 0, 18, 80, 0, 1, 0, 0, 56, 57,
|
||||
0, 55, 11, 0, 33, 77, 89, 0, 110, 88, 0, 0, 45,
|
||||
0, 90, 54, 0, 20, 0, 114, 34, 19, 0, 10, 97, 28,
|
||||
83, 0, 0, 116, 93, 47, 115, 41, 12, 44, 0, 78, 0,
|
||||
87, 29, 0, 86, 0, 0, 0, 82, 79, 84, 75, 96, 6,
|
||||
14, 95, 0, 68, 0, 21, 76, 98, 27, 0, 112, 67, 104,
|
||||
49, 40, 71, 0, 0, 81, 100, 0, 107, 0, 15, 0, 0,
|
||||
24, 0, 73, 42, 50, 0, 16, 48, 0, 37,
|
||||
};
|
||||
static const unsigned char aNext[116] = {
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0,
|
||||
0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0,
|
||||
17, 0, 0, 0, 36, 39, 0, 0, 25, 0, 0, 31, 0,
|
||||
0, 0, 43, 52, 0, 0, 0, 53, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 51, 0, 0, 0, 0, 26, 0, 8, 46,
|
||||
2, 0, 0, 0, 0, 0, 0, 0, 3, 58, 66, 0, 13,
|
||||
0, 91, 85, 0, 94, 0, 74, 0, 0, 62, 0, 35, 101,
|
||||
0, 0, 105, 23, 30, 60, 70, 0, 0, 59, 0, 0,
|
||||
};
|
||||
static const unsigned char aLen[116] = {
|
||||
6, 7, 3, 6, 6, 7, 7, 3, 4, 6, 4, 5, 3,
|
||||
10, 9, 5, 4, 4, 3, 8, 2, 6, 11, 2, 7, 5,
|
||||
5, 4, 6, 7, 10, 6, 5, 6, 6, 5, 6, 4, 9,
|
||||
2, 5, 5, 7, 5, 9, 6, 7, 7, 3, 4, 4, 7,
|
||||
3, 10, 4, 7, 6, 12, 6, 6, 9, 4, 6, 5, 4,
|
||||
7, 6, 5, 6, 7, 5, 4, 5, 6, 5, 7, 3, 7,
|
||||
13, 2, 2, 4, 6, 6, 8, 5, 17, 12, 7, 8, 8,
|
||||
2, 4, 4, 4, 4, 4, 2, 2, 4, 6, 2, 3, 6,
|
||||
5, 8, 5, 5, 8, 3, 5, 5, 6, 4, 9, 3,
|
||||
};
|
||||
static const unsigned short int aOffset[116] = {
|
||||
0, 2, 2, 6, 10, 13, 18, 23, 25, 26, 31, 33, 37,
|
||||
40, 47, 55, 58, 61, 63, 65, 70, 71, 76, 85, 86, 91,
|
||||
95, 99, 102, 107, 113, 123, 126, 131, 136, 141, 144, 148, 148,
|
||||
152, 157, 160, 164, 166, 169, 177, 183, 189, 189, 192, 195, 199,
|
||||
200, 204, 214, 218, 225, 231, 243, 249, 255, 264, 266, 272, 277,
|
||||
279, 286, 291, 296, 302, 308, 313, 317, 320, 326, 330, 337, 339,
|
||||
346, 348, 350, 359, 363, 369, 375, 383, 388, 388, 404, 411, 418,
|
||||
419, 426, 430, 434, 438, 442, 445, 447, 449, 452, 452, 455, 458,
|
||||
464, 468, 476, 480, 485, 493, 496, 501, 506, 512, 516, 521,
|
||||
};
|
||||
static const unsigned char aCode[116] = {
|
||||
TK_BEFORE, TK_FOREIGN, TK_FOR, TK_IGNORE, TK_LIKE_KW,
|
||||
TK_EXPLAIN, TK_INSTEAD, TK_ADD, TK_DESC, TK_ESCAPE,
|
||||
TK_EACH, TK_CHECK, TK_KEY, TK_CONSTRAINT, TK_INTERSECT,
|
||||
TK_TABLE, TK_JOIN_KW, TK_THEN, TK_END, TK_DATABASE,
|
||||
TK_AS, TK_SELECT, TK_TRANSACTION,TK_ON, TK_JOIN_KW,
|
||||
TK_ALTER, TK_RAISE, TK_ELSE, TK_EXCEPT, TK_TRIGGER,
|
||||
TK_REFERENCES, TK_UNIQUE, TK_QUERY, TK_ATTACH, TK_HAVING,
|
||||
TK_GROUP, TK_UPDATE, TK_TEMP, TK_TEMP, TK_OR,
|
||||
TK_BEGIN, TK_JOIN_KW, TK_REINDEX, TK_INDEX, TK_EXCLUSIVE,
|
||||
TK_EXISTS, TK_BETWEEN, TK_NOTNULL, TK_NOT, TK_NULL,
|
||||
TK_LIKE_KW, TK_CASCADE, TK_ASC, TK_DEFERRABLE, TK_CASE,
|
||||
TK_COLLATE, TK_CREATE, TK_CTIME_KW, TK_DELETE, TK_DETACH,
|
||||
TK_IMMEDIATE, TK_JOIN, TK_INSERT, TK_MATCH, TK_PLAN,
|
||||
TK_ANALYZE, TK_PRAGMA, TK_ABORT, TK_VALUES, TK_VIRTUAL,
|
||||
TK_LIMIT, TK_WHEN, TK_WHERE, TK_RENAME, TK_AFTER,
|
||||
TK_REPLACE, TK_AND, TK_DEFAULT, TK_AUTOINCR, TK_TO,
|
||||
TK_IN, TK_CAST, TK_COLUMNKW, TK_COMMIT, TK_CONFLICT,
|
||||
TK_JOIN_KW, TK_CTIME_KW, TK_CTIME_KW, TK_PRIMARY, TK_DEFERRED,
|
||||
TK_DISTINCT, TK_IS, TK_DROP, TK_FAIL, TK_FROM,
|
||||
TK_JOIN_KW, TK_LIKE_KW, TK_BY, TK_IF, TK_INTO,
|
||||
TK_OFFSET, TK_OF, TK_SET, TK_ISNULL, TK_ORDER,
|
||||
TK_RESTRICT, TK_JOIN_KW, TK_JOIN_KW, TK_ROLLBACK, TK_ROW,
|
||||
TK_UNION, TK_USING, TK_VACUUM, TK_VIEW, TK_INITIALLY,
|
||||
TK_ALL,
|
||||
};
|
||||
int h, i;
|
||||
if( n<2 ) return TK_ID;
|
||||
h = ((charMap(z[0])*4) ^
|
||||
(charMap(z[n-1])*3) ^
|
||||
n) % 127;
|
||||
for(i=((int)aHash[h])-1; i>=0; i=((int)aNext[i])-1){
|
||||
if( aLen[i]==n && sqlite3StrNICmp(&zText[aOffset[i]],z,n)==0 ){
|
||||
return aCode[i];
|
||||
}
|
||||
}
|
||||
return TK_ID;
|
||||
}
|
||||
int sqlite3KeywordCode(const unsigned char *z, int n){
|
||||
return keywordCode((char*)z, n);
|
||||
}
|
|
@ -0,0 +1,134 @@
|
|||
/*
|
||||
** 2001 September 15
|
||||
**
|
||||
** The author disclaims copyright to this source code. In place of
|
||||
** a legal notice, here is a blessing:
|
||||
**
|
||||
** May you do good and not evil.
|
||||
** May you find forgiveness for yourself and forgive others.
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
*************************************************************************
|
||||
** Main file for the SQLite library. The routines in this file
|
||||
** implement the programmer interface to the library. Routines in
|
||||
** other files are for internal use by SQLite and should not be
|
||||
** accessed by users of the library.
|
||||
**
|
||||
** $Id: legacy.c,v 1.22 2007/08/29 12:31:26 danielk1977 Exp $
|
||||
*/
|
||||
|
||||
#include "sqliteInt.h"
|
||||
#include <ctype.h>
|
||||
|
||||
/*
|
||||
** Execute SQL code. Return one of the SQLITE_ success/failure
|
||||
** codes. Also write an error message into memory obtained from
|
||||
** malloc() and make *pzErrMsg point to that message.
|
||||
**
|
||||
** If the SQL is a query, then for each row in the query result
|
||||
** the xCallback() function is called. pArg becomes the first
|
||||
** argument to xCallback(). If xCallback=NULL then no callback
|
||||
** is invoked, even for queries.
|
||||
*/
|
||||
int sqlite3_exec(
|
||||
sqlite3 *db, /* The database on which the SQL executes */
|
||||
const char *zSql, /* The SQL to be executed */
|
||||
sqlite3_callback xCallback, /* Invoke this callback routine */
|
||||
void *pArg, /* First argument to xCallback() */
|
||||
char **pzErrMsg /* Write error messages here */
|
||||
){
|
||||
int rc = SQLITE_OK;
|
||||
const char *zLeftover;
|
||||
sqlite3_stmt *pStmt = 0;
|
||||
char **azCols = 0;
|
||||
|
||||
int nRetry = 0;
|
||||
int nCallback;
|
||||
|
||||
if( zSql==0 ) return SQLITE_OK;
|
||||
|
||||
sqlite3_mutex_enter(db->mutex);
|
||||
while( (rc==SQLITE_OK || (rc==SQLITE_SCHEMA && (++nRetry)<2)) && zSql[0] ){
|
||||
int nCol;
|
||||
char **azVals = 0;
|
||||
|
||||
pStmt = 0;
|
||||
rc = sqlite3_prepare(db, zSql, -1, &pStmt, &zLeftover);
|
||||
assert( rc==SQLITE_OK || pStmt==0 );
|
||||
if( rc!=SQLITE_OK ){
|
||||
continue;
|
||||
}
|
||||
if( !pStmt ){
|
||||
/* this happens for a comment or white-space */
|
||||
zSql = zLeftover;
|
||||
continue;
|
||||
}
|
||||
|
||||
nCallback = 0;
|
||||
|
||||
nCol = sqlite3_column_count(pStmt);
|
||||
azCols = sqlite3DbMallocZero(db, 2*nCol*sizeof(const char *) + 1);
|
||||
if( azCols==0 ){
|
||||
goto exec_out;
|
||||
}
|
||||
|
||||
while( 1 ){
|
||||
int i;
|
||||
rc = sqlite3_step(pStmt);
|
||||
|
||||
/* Invoke the callback function if required */
|
||||
if( xCallback && (SQLITE_ROW==rc ||
|
||||
(SQLITE_DONE==rc && !nCallback && db->flags&SQLITE_NullCallback)) ){
|
||||
if( 0==nCallback ){
|
||||
for(i=0; i<nCol; i++){
|
||||
azCols[i] = (char *)sqlite3_column_name(pStmt, i);
|
||||
}
|
||||
nCallback++;
|
||||
}
|
||||
if( rc==SQLITE_ROW ){
|
||||
azVals = &azCols[nCol];
|
||||
for(i=0; i<nCol; i++){
|
||||
azVals[i] = (char *)sqlite3_column_text(pStmt, i);
|
||||
}
|
||||
}
|
||||
if( xCallback(pArg, nCol, azVals, azCols) ){
|
||||
rc = SQLITE_ABORT;
|
||||
goto exec_out;
|
||||
}
|
||||
}
|
||||
|
||||
if( rc!=SQLITE_ROW ){
|
||||
rc = sqlite3_finalize(pStmt);
|
||||
pStmt = 0;
|
||||
if( rc!=SQLITE_SCHEMA ){
|
||||
nRetry = 0;
|
||||
zSql = zLeftover;
|
||||
while( isspace((unsigned char)zSql[0]) ) zSql++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
sqlite3_free(azCols);
|
||||
azCols = 0;
|
||||
}
|
||||
|
||||
exec_out:
|
||||
if( pStmt ) sqlite3_finalize(pStmt);
|
||||
if( azCols ) sqlite3_free(azCols);
|
||||
|
||||
rc = sqlite3ApiExit(db, rc);
|
||||
if( rc!=SQLITE_OK && rc==sqlite3_errcode(db) && pzErrMsg ){
|
||||
int nErrMsg = 1 + strlen(sqlite3_errmsg(db));
|
||||
*pzErrMsg = sqlite3_malloc(nErrMsg);
|
||||
if( *pzErrMsg ){
|
||||
memcpy(*pzErrMsg, sqlite3_errmsg(db), nErrMsg);
|
||||
}
|
||||
}else if( pzErrMsg ){
|
||||
*pzErrMsg = 0;
|
||||
}
|
||||
|
||||
assert( (rc&db->errMask)==rc );
|
||||
sqlite3_mutex_leave(db->mutex);
|
||||
return rc;
|
||||
}
|
|
@ -0,0 +1,516 @@
|
|||
/*
|
||||
** 2006 June 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 used to dynamically load extensions into
|
||||
** the SQLite library.
|
||||
*/
|
||||
#ifndef SQLITE_OMIT_LOAD_EXTENSION
|
||||
|
||||
#define SQLITE_CORE 1 /* Disable the API redefinition in sqlite3ext.h */
|
||||
#include "sqlite3ext.h"
|
||||
#include "sqliteInt.h"
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
/*
|
||||
** Some API routines are omitted when various features are
|
||||
** excluded from a build of SQLite. Substitute a NULL pointer
|
||||
** for any missing APIs.
|
||||
*/
|
||||
#ifndef SQLITE_ENABLE_COLUMN_METADATA
|
||||
# define sqlite3_column_database_name 0
|
||||
# define sqlite3_column_database_name16 0
|
||||
# define sqlite3_column_table_name 0
|
||||
# define sqlite3_column_table_name16 0
|
||||
# define sqlite3_column_origin_name 0
|
||||
# define sqlite3_column_origin_name16 0
|
||||
# define sqlite3_table_column_metadata 0
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_OMIT_AUTHORIZATION
|
||||
# define sqlite3_set_authorizer 0
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_OMIT_UTF16
|
||||
# define sqlite3_bind_text16 0
|
||||
# define sqlite3_collation_needed16 0
|
||||
# define sqlite3_column_decltype16 0
|
||||
# define sqlite3_column_name16 0
|
||||
# define sqlite3_column_text16 0
|
||||
# define sqlite3_complete16 0
|
||||
# define sqlite3_create_collation16 0
|
||||
# define sqlite3_create_function16 0
|
||||
# define sqlite3_errmsg16 0
|
||||
# define sqlite3_open16 0
|
||||
# define sqlite3_prepare16 0
|
||||
# define sqlite3_prepare16_v2 0
|
||||
# define sqlite3_result_error16 0
|
||||
# define sqlite3_result_text16 0
|
||||
# define sqlite3_result_text16be 0
|
||||
# define sqlite3_result_text16le 0
|
||||
# define sqlite3_value_text16 0
|
||||
# define sqlite3_value_text16be 0
|
||||
# define sqlite3_value_text16le 0
|
||||
# define sqlite3_column_database_name16 0
|
||||
# define sqlite3_column_table_name16 0
|
||||
# define sqlite3_column_origin_name16 0
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_OMIT_COMPLETE
|
||||
# define sqlite3_complete 0
|
||||
# define sqlite3_complete16 0
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_OMIT_PROGRESS_CALLBACK
|
||||
# define sqlite3_progress_handler 0
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_OMIT_VIRTUALTABLE
|
||||
# define sqlite3_create_module 0
|
||||
# define sqlite3_create_module_v2 0
|
||||
# define sqlite3_declare_vtab 0
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_OMIT_SHARED_CACHE
|
||||
# define sqlite3_enable_shared_cache 0
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_OMIT_TRACE
|
||||
# define sqlite3_profile 0
|
||||
# define sqlite3_trace 0
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_OMIT_GET_TABLE
|
||||
# define sqlite3_free_table 0
|
||||
# define sqlite3_get_table 0
|
||||
#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.
|
||||
** A pointer to this structure is passed into extensions when they are
|
||||
** loaded so that the extension can make calls back into the SQLite
|
||||
** library.
|
||||
**
|
||||
** When adding new APIs, add them to the bottom of this structure
|
||||
** in order to preserve backwards compatibility.
|
||||
**
|
||||
** Extensions that use newer APIs should first call the
|
||||
** sqlite3_libversion_number() to make sure that the API they
|
||||
** intend to use is supported by the library. Extensions should
|
||||
** also check to make sure that the pointer to the function is
|
||||
** not NULL before calling it.
|
||||
*/
|
||||
const sqlite3_api_routines sqlite3_apis = {
|
||||
sqlite3_aggregate_context,
|
||||
sqlite3_aggregate_count,
|
||||
sqlite3_bind_blob,
|
||||
sqlite3_bind_double,
|
||||
sqlite3_bind_int,
|
||||
sqlite3_bind_int64,
|
||||
sqlite3_bind_null,
|
||||
sqlite3_bind_parameter_count,
|
||||
sqlite3_bind_parameter_index,
|
||||
sqlite3_bind_parameter_name,
|
||||
sqlite3_bind_text,
|
||||
sqlite3_bind_text16,
|
||||
sqlite3_bind_value,
|
||||
sqlite3_busy_handler,
|
||||
sqlite3_busy_timeout,
|
||||
sqlite3_changes,
|
||||
sqlite3_close,
|
||||
sqlite3_collation_needed,
|
||||
sqlite3_collation_needed16,
|
||||
sqlite3_column_blob,
|
||||
sqlite3_column_bytes,
|
||||
sqlite3_column_bytes16,
|
||||
sqlite3_column_count,
|
||||
sqlite3_column_database_name,
|
||||
sqlite3_column_database_name16,
|
||||
sqlite3_column_decltype,
|
||||
sqlite3_column_decltype16,
|
||||
sqlite3_column_double,
|
||||
sqlite3_column_int,
|
||||
sqlite3_column_int64,
|
||||
sqlite3_column_name,
|
||||
sqlite3_column_name16,
|
||||
sqlite3_column_origin_name,
|
||||
sqlite3_column_origin_name16,
|
||||
sqlite3_column_table_name,
|
||||
sqlite3_column_table_name16,
|
||||
sqlite3_column_text,
|
||||
sqlite3_column_text16,
|
||||
sqlite3_column_type,
|
||||
sqlite3_column_value,
|
||||
sqlite3_commit_hook,
|
||||
sqlite3_complete,
|
||||
sqlite3_complete16,
|
||||
sqlite3_create_collation,
|
||||
sqlite3_create_collation16,
|
||||
sqlite3_create_function,
|
||||
sqlite3_create_function16,
|
||||
sqlite3_create_module,
|
||||
sqlite3_data_count,
|
||||
sqlite3_db_handle,
|
||||
sqlite3_declare_vtab,
|
||||
sqlite3_enable_shared_cache,
|
||||
sqlite3_errcode,
|
||||
sqlite3_errmsg,
|
||||
sqlite3_errmsg16,
|
||||
sqlite3_exec,
|
||||
sqlite3_expired,
|
||||
sqlite3_finalize,
|
||||
sqlite3_free,
|
||||
sqlite3_free_table,
|
||||
sqlite3_get_autocommit,
|
||||
sqlite3_get_auxdata,
|
||||
sqlite3_get_table,
|
||||
0, /* Was sqlite3_global_recover(), but that function is deprecated */
|
||||
sqlite3_interrupt,
|
||||
sqlite3_last_insert_rowid,
|
||||
sqlite3_libversion,
|
||||
sqlite3_libversion_number,
|
||||
sqlite3_malloc,
|
||||
sqlite3_mprintf,
|
||||
sqlite3_open,
|
||||
sqlite3_open16,
|
||||
sqlite3_prepare,
|
||||
sqlite3_prepare16,
|
||||
sqlite3_profile,
|
||||
sqlite3_progress_handler,
|
||||
sqlite3_realloc,
|
||||
sqlite3_reset,
|
||||
sqlite3_result_blob,
|
||||
sqlite3_result_double,
|
||||
sqlite3_result_error,
|
||||
sqlite3_result_error16,
|
||||
sqlite3_result_int,
|
||||
sqlite3_result_int64,
|
||||
sqlite3_result_null,
|
||||
sqlite3_result_text,
|
||||
sqlite3_result_text16,
|
||||
sqlite3_result_text16be,
|
||||
sqlite3_result_text16le,
|
||||
sqlite3_result_value,
|
||||
sqlite3_rollback_hook,
|
||||
sqlite3_set_authorizer,
|
||||
sqlite3_set_auxdata,
|
||||
sqlite3_snprintf,
|
||||
sqlite3_step,
|
||||
sqlite3_table_column_metadata,
|
||||
sqlite3_thread_cleanup,
|
||||
sqlite3_total_changes,
|
||||
sqlite3_trace,
|
||||
sqlite3_transfer_bindings,
|
||||
sqlite3_update_hook,
|
||||
sqlite3_user_data,
|
||||
sqlite3_value_blob,
|
||||
sqlite3_value_bytes,
|
||||
sqlite3_value_bytes16,
|
||||
sqlite3_value_double,
|
||||
sqlite3_value_int,
|
||||
sqlite3_value_int64,
|
||||
sqlite3_value_numeric_type,
|
||||
sqlite3_value_text,
|
||||
sqlite3_value_text16,
|
||||
sqlite3_value_text16be,
|
||||
sqlite3_value_text16le,
|
||||
sqlite3_value_type,
|
||||
sqlite3_vmprintf,
|
||||
/*
|
||||
** The original API set ends here. All extensions can call any
|
||||
** of the APIs above provided that the pointer is not NULL. But
|
||||
** before calling APIs that follow, extension should check the
|
||||
** sqlite3_libversion_number() to make sure they are dealing with
|
||||
** a library that is new enough to support that API.
|
||||
*************************************************************************
|
||||
*/
|
||||
sqlite3_overload_function,
|
||||
|
||||
/*
|
||||
** Added after 3.3.13
|
||||
*/
|
||||
sqlite3_prepare_v2,
|
||||
sqlite3_prepare16_v2,
|
||||
sqlite3_clear_bindings,
|
||||
|
||||
/*
|
||||
** Added for 3.4.1
|
||||
*/
|
||||
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_NOOP
|
||||
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,
|
||||
};
|
||||
|
||||
/*
|
||||
** Attempt to load an SQLite extension library contained in the file
|
||||
** zFile. The entry point is zProc. zProc may be 0 in which case a
|
||||
** default entry point name (sqlite3_extension_init) is used. Use
|
||||
** of the default name is recommended.
|
||||
**
|
||||
** Return SQLITE_OK on success and SQLITE_ERROR if something goes wrong.
|
||||
**
|
||||
** If an error occurs and pzErrMsg is not 0, then fill *pzErrMsg with
|
||||
** error message text. The calling function should free this memory
|
||||
** by calling sqlite3_free().
|
||||
*/
|
||||
static int sqlite3LoadExtension(
|
||||
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 */
|
||||
){
|
||||
sqlite3_vfs *pVfs = db->pVfs;
|
||||
void *handle;
|
||||
int (*xInit)(sqlite3*,char**,const sqlite3_api_routines*);
|
||||
char *zErrmsg = 0;
|
||||
void **aHandle;
|
||||
|
||||
/* Ticket #1863. To avoid a creating security problems for older
|
||||
** applications that relink against newer versions of SQLite, the
|
||||
** ability to run load_extension is turned off by default. One
|
||||
** must call sqlite3_enable_load_extension() to turn on extension
|
||||
** loading. Otherwise you get the following error.
|
||||
*/
|
||||
if( (db->flags & SQLITE_LoadExtension)==0 ){
|
||||
if( pzErrMsg ){
|
||||
*pzErrMsg = sqlite3_mprintf("not authorized");
|
||||
}
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
|
||||
if( zProc==0 ){
|
||||
zProc = "sqlite3_extension_init";
|
||||
}
|
||||
|
||||
handle = sqlite3OsDlOpen(pVfs, zFile);
|
||||
if( handle==0 ){
|
||||
if( pzErrMsg ){
|
||||
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(db, zErr);
|
||||
}
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
xInit = (int(*)(sqlite3*,char**,const sqlite3_api_routines*))
|
||||
sqlite3OsDlSym(pVfs, handle, zProc);
|
||||
if( xInit==0 ){
|
||||
if( pzErrMsg ){
|
||||
char zErr[256];
|
||||
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(db, zErr);
|
||||
sqlite3OsDlClose(pVfs, handle);
|
||||
}
|
||||
return SQLITE_ERROR;
|
||||
}else if( xInit(db, &zErrmsg, &sqlite3_apis) ){
|
||||
if( pzErrMsg ){
|
||||
*pzErrMsg = sqlite3_mprintf("error during initialization: %s", zErrmsg);
|
||||
}
|
||||
sqlite3_free(zErrmsg);
|
||||
sqlite3OsDlClose(pVfs, handle);
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
|
||||
/* Append the new shared library handle to the db->aExtension array. */
|
||||
db->nExtension++;
|
||||
aHandle = sqlite3DbMallocZero(db, sizeof(handle)*db->nExtension);
|
||||
if( aHandle==0 ){
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
if( db->nExtension>0 ){
|
||||
memcpy(aHandle, db->aExtension, sizeof(handle)*(db->nExtension-1));
|
||||
}
|
||||
sqlite3_free(db->aExtension);
|
||||
db->aExtension = aHandle;
|
||||
|
||||
db->aExtension[db->nExtension-1] = handle;
|
||||
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
|
||||
** to clean up loaded extensions
|
||||
*/
|
||||
void sqlite3CloseExtensions(sqlite3 *db){
|
||||
int i;
|
||||
assert( sqlite3_mutex_held(db->mutex) );
|
||||
for(i=0; i<db->nExtension; i++){
|
||||
sqlite3OsDlClose(db->pVfs, db->aExtension[i]);
|
||||
}
|
||||
sqlite3_free(db->aExtension);
|
||||
}
|
||||
|
||||
/*
|
||||
** Enable or disable extension loading. Extension loading is disabled by
|
||||
** default so as not to open security holes in older applications.
|
||||
*/
|
||||
int sqlite3_enable_load_extension(sqlite3 *db, int onoff){
|
||||
sqlite3_mutex_enter(db->mutex);
|
||||
if( onoff ){
|
||||
db->flags |= SQLITE_LoadExtension;
|
||||
}else{
|
||||
db->flags &= ~SQLITE_LoadExtension;
|
||||
}
|
||||
sqlite3_mutex_leave(db->mutex);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** 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.
|
||||
*/
|
||||
static struct {
|
||||
int nExt; /* Number of entries in aExt[] */
|
||||
void **aExt; /* Pointers to the extension init functions */
|
||||
} autoext = { 0, 0 };
|
||||
|
||||
|
||||
/*
|
||||
** Register a statically linked extension that is automatically
|
||||
** loaded by every new database connection.
|
||||
*/
|
||||
int sqlite3_auto_extension(void *xInit){
|
||||
int i;
|
||||
int rc = SQLITE_OK;
|
||||
sqlite3_mutex *mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER);
|
||||
sqlite3_mutex_enter(mutex);
|
||||
for(i=0; i<autoext.nExt; i++){
|
||||
if( autoext.aExt[i]==xInit ) break;
|
||||
}
|
||||
if( i==autoext.nExt ){
|
||||
int nByte = (autoext.nExt+1)*sizeof(autoext.aExt[0]);
|
||||
void **aNew;
|
||||
aNew = sqlite3_realloc(autoext.aExt, nByte);
|
||||
if( aNew==0 ){
|
||||
rc = SQLITE_NOMEM;
|
||||
}else{
|
||||
autoext.aExt = aNew;
|
||||
autoext.aExt[autoext.nExt] = xInit;
|
||||
autoext.nExt++;
|
||||
}
|
||||
}
|
||||
sqlite3_mutex_leave(mutex);
|
||||
assert( (rc&0xff)==rc );
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Reset the automatic extension loading mechanism.
|
||||
*/
|
||||
void sqlite3_reset_auto_extension(void){
|
||||
sqlite3_mutex *mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER);
|
||||
sqlite3_mutex_enter(mutex);
|
||||
sqlite3_free(autoext.aExt);
|
||||
autoext.aExt = 0;
|
||||
autoext.nExt = 0;
|
||||
sqlite3_mutex_leave(mutex);
|
||||
}
|
||||
|
||||
/*
|
||||
** Load all automatic extensions.
|
||||
*/
|
||||
int sqlite3AutoLoadExtensions(sqlite3 *db){
|
||||
int i;
|
||||
int go = 1;
|
||||
int rc = SQLITE_OK;
|
||||
int (*xInit)(sqlite3*,char**,const sqlite3_api_routines*);
|
||||
|
||||
if( autoext.nExt==0 ){
|
||||
/* Common case: early out without every having to acquire a mutex */
|
||||
return SQLITE_OK;
|
||||
}
|
||||
for(i=0; go; i++){
|
||||
char *zErrmsg = 0;
|
||||
sqlite3_mutex *mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER);
|
||||
sqlite3_mutex_enter(mutex);
|
||||
if( i>=autoext.nExt ){
|
||||
xInit = 0;
|
||||
go = 0;
|
||||
}else{
|
||||
xInit = (int(*)(sqlite3*,char**,const sqlite3_api_routines*))
|
||||
autoext.aExt[i];
|
||||
}
|
||||
sqlite3_mutex_leave(mutex);
|
||||
if( xInit && xInit(db, &zErrmsg, &sqlite3_apis) ){
|
||||
sqlite3Error(db, SQLITE_ERROR,
|
||||
"automatic extension loading failed: %s", zErrmsg);
|
||||
go = 0;
|
||||
rc = SQLITE_ERROR;
|
||||
sqlite3_free(zErrmsg);
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
#endif /* SQLITE_OMIT_LOAD_EXTENSION */
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,240 @@
|
|||
/*
|
||||
** 2001 September 15
|
||||
**
|
||||
** The author disclaims copyright to this source code. In place of
|
||||
** a legal notice, here is a blessing:
|
||||
**
|
||||
** May you do good and not evil.
|
||||
** May you find forgiveness for yourself and forgive others.
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
*************************************************************************
|
||||
** Memory allocation functions used throughout sqlite.
|
||||
**
|
||||
**
|
||||
** $Id: malloc.c,v 1.13 2007/08/29 14:06:23 danielk1977 Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include <stdarg.h>
|
||||
#include <ctype.h>
|
||||
|
||||
/*
|
||||
** This routine runs when the memory allocator sees that the
|
||||
** total memory allocation is about to exceed the soft heap
|
||||
** limit.
|
||||
*/
|
||||
static void softHeapLimitEnforcer(
|
||||
void *NotUsed,
|
||||
sqlite3_int64 inUse,
|
||||
int allocSize
|
||||
){
|
||||
sqlite3_release_memory(allocSize);
|
||||
}
|
||||
|
||||
/*
|
||||
** Set the soft heap-size limit for the current thread. Passing a
|
||||
** zero or negative value indicates no limit.
|
||||
*/
|
||||
void sqlite3_soft_heap_limit(int n){
|
||||
sqlite3_uint64 iLimit;
|
||||
int overage;
|
||||
if( n<0 ){
|
||||
iLimit = 0;
|
||||
}else{
|
||||
iLimit = n;
|
||||
}
|
||||
if( iLimit>0 ){
|
||||
sqlite3_memory_alarm(softHeapLimitEnforcer, 0, iLimit);
|
||||
}else{
|
||||
sqlite3_memory_alarm(0, 0, 0);
|
||||
}
|
||||
overage = sqlite3_memory_used() - n;
|
||||
if( overage>0 ){
|
||||
sqlite3_release_memory(overage);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Release memory held by SQLite instances created by the current thread.
|
||||
*/
|
||||
int sqlite3_release_memory(int n){
|
||||
#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
|
||||
return sqlite3PagerReleaseMemory(n);
|
||||
#else
|
||||
return SQLITE_OK;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Allocate and zero memory.
|
||||
*/
|
||||
void *sqlite3MallocZero(unsigned n){
|
||||
void *p = sqlite3_malloc(n);
|
||||
if( p ){
|
||||
memset(p, 0, n);
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
/*
|
||||
** Allocate and zero memory. If the allocation fails, make
|
||||
** the mallocFailed flag in the connection pointer.
|
||||
*/
|
||||
void *sqlite3DbMallocZero(sqlite3 *db, unsigned n){
|
||||
void *p = sqlite3DbMallocRaw(db, n);
|
||||
if( p ){
|
||||
memset(p, 0, n);
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
/*
|
||||
** Allocate and zero memory. If the allocation fails, make
|
||||
** the mallocFailed flag in the connection pointer.
|
||||
*/
|
||||
void *sqlite3DbMallocRaw(sqlite3 *db, unsigned n){
|
||||
void *p = 0;
|
||||
if( !db || db->mallocFailed==0 ){
|
||||
p = sqlite3_malloc(n);
|
||||
if( !p && db ){
|
||||
db->mallocFailed = 1;
|
||||
}
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
/*
|
||||
** Resize the block of memory pointed to by p to n bytes. If the
|
||||
** resize fails, set the mallocFailed flag inthe connection object.
|
||||
*/
|
||||
void *sqlite3DbRealloc(sqlite3 *db, void *p, int n){
|
||||
void *pNew = 0;
|
||||
if( db->mallocFailed==0 ){
|
||||
pNew = sqlite3_realloc(p, n);
|
||||
if( !pNew ){
|
||||
db->mallocFailed = 1;
|
||||
}
|
||||
}
|
||||
return pNew;
|
||||
}
|
||||
|
||||
/*
|
||||
** Attempt to reallocate p. If the reallocation fails, then free p
|
||||
** and set the mallocFailed flag in the database connection.
|
||||
*/
|
||||
void *sqlite3DbReallocOrFree(sqlite3 *db, void *p, int n){
|
||||
void *pNew;
|
||||
pNew = sqlite3DbRealloc(db, p, n);
|
||||
if( !pNew ){
|
||||
sqlite3_free(p);
|
||||
}
|
||||
return pNew;
|
||||
}
|
||||
|
||||
/*
|
||||
** Make a copy of a string in memory obtained from sqliteMalloc(). These
|
||||
** functions call sqlite3MallocRaw() directly instead of sqliteMalloc(). This
|
||||
** is because when memory debugging is turned on, these two functions are
|
||||
** called via macros that record the current file and line number in the
|
||||
** ThreadData structure.
|
||||
*/
|
||||
char *sqlite3StrDup(const char *z){
|
||||
char *zNew;
|
||||
int n;
|
||||
if( z==0 ) return 0;
|
||||
n = strlen(z)+1;
|
||||
zNew = sqlite3_malloc(n);
|
||||
if( zNew ) memcpy(zNew, z, n);
|
||||
return zNew;
|
||||
}
|
||||
char *sqlite3StrNDup(const char *z, int n){
|
||||
char *zNew;
|
||||
if( z==0 ) return 0;
|
||||
zNew = sqlite3_malloc(n+1);
|
||||
if( zNew ){
|
||||
memcpy(zNew, z, n);
|
||||
zNew[n] = 0;
|
||||
}
|
||||
return zNew;
|
||||
}
|
||||
|
||||
char *sqlite3DbStrDup(sqlite3 *db, const char *z){
|
||||
char *zNew = sqlite3StrDup(z);
|
||||
if( z && !zNew ){
|
||||
db->mallocFailed = 1;
|
||||
}
|
||||
return zNew;
|
||||
}
|
||||
char *sqlite3DbStrNDup(sqlite3 *db, const char *z, int n){
|
||||
char *zNew = sqlite3StrNDup(z, n);
|
||||
if( z && !zNew ){
|
||||
db->mallocFailed = 1;
|
||||
}
|
||||
return zNew;
|
||||
}
|
||||
|
||||
/*
|
||||
** Create a string from the 2nd and subsequent arguments (up to the
|
||||
** first NULL argument), store the string in memory obtained from
|
||||
** sqliteMalloc() and make the pointer indicated by the 1st argument
|
||||
** point to that string. The 1st argument must either be NULL or
|
||||
** point to memory obtained from sqliteMalloc().
|
||||
*/
|
||||
void sqlite3SetString(char **pz, ...){
|
||||
va_list ap;
|
||||
int nByte;
|
||||
const char *z;
|
||||
char *zResult;
|
||||
|
||||
assert( pz!=0 );
|
||||
nByte = 1;
|
||||
va_start(ap, pz);
|
||||
while( (z = va_arg(ap, const char*))!=0 ){
|
||||
nByte += strlen(z);
|
||||
}
|
||||
va_end(ap);
|
||||
sqlite3_free(*pz);
|
||||
*pz = zResult = sqlite3_malloc(nByte);
|
||||
if( zResult==0 ){
|
||||
return;
|
||||
}
|
||||
*zResult = 0;
|
||||
va_start(ap, pz);
|
||||
while( (z = va_arg(ap, const char*))!=0 ){
|
||||
int n = strlen(z);
|
||||
memcpy(zResult, z, n);
|
||||
zResult += n;
|
||||
}
|
||||
zResult[0] = 0;
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** This function must be called before exiting any API function (i.e.
|
||||
** returning control to the user) that has called sqlite3_malloc or
|
||||
** sqlite3_realloc.
|
||||
**
|
||||
** The returned value is normally a copy of the second argument to this
|
||||
** function. However, if a malloc() failure has occured since the previous
|
||||
** invocation SQLITE_NOMEM is returned instead.
|
||||
**
|
||||
** If the first argument, db, is not NULL and a malloc() error has occured,
|
||||
** then the connection error-code (the value returned by sqlite3_errcode())
|
||||
** is set to SQLITE_NOMEM.
|
||||
*/
|
||||
int sqlite3ApiExit(sqlite3* db, int rc){
|
||||
/* If the db handle is not NULL, then we must hold the connection handle
|
||||
** mutex here. Otherwise the read (and possible write) of db->mallocFailed
|
||||
** is unsafe, as is the call to sqlite3Error().
|
||||
*/
|
||||
assert( !db || sqlite3_mutex_held(db->mutex) );
|
||||
if( db && db->mallocFailed ){
|
||||
sqlite3Error(db, SQLITE_NOMEM, 0);
|
||||
db->mallocFailed = 0;
|
||||
rc = SQLITE_NOMEM;
|
||||
}
|
||||
return rc & (db ? db->errMask : 0xff);
|
||||
}
|
||||
|
|
@ -0,0 +1,229 @@
|
|||
/*
|
||||
** 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 a memory
|
||||
** allocation subsystem for use by SQLite.
|
||||
**
|
||||
** $Id: mem1.c,v 1.10 2007/09/02 17:50:35 drh Exp $
|
||||
*/
|
||||
|
||||
/*
|
||||
** This version of the memory allocator is the default. It is
|
||||
** used when no other memory allocator is specified using compile-time
|
||||
** macros.
|
||||
*/
|
||||
#if !defined(SQLITE_MEMDEBUG) && !defined(SQLITE_OMIT_MEMORY_ALLOCATION)
|
||||
|
||||
/*
|
||||
** We will eventually construct multiple memory allocation subsystems
|
||||
** suitable for use in various contexts:
|
||||
**
|
||||
** * Normal multi-threaded builds
|
||||
** * Normal single-threaded builds
|
||||
** * Debugging builds
|
||||
**
|
||||
** This initial version is suitable for use in normal multi-threaded
|
||||
** builds. We envision that alternative versions will be stored in
|
||||
** separate source files. #ifdefs will be used to select the code from
|
||||
** one of the various memN.c source files for use in any given build.
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
|
||||
/*
|
||||
** 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 {
|
||||
/*
|
||||
** The alarm callback and its arguments. The mem.mutex lock will
|
||||
** be held while the callback is running. Recursive calls into
|
||||
** the memory subsystem are allowed, but no new callbacks will be
|
||||
** issued. The alarmBusy variable is set to prevent recursive
|
||||
** callbacks.
|
||||
*/
|
||||
sqlite3_int64 alarmThreshold;
|
||||
void (*alarmCallback)(void*, sqlite3_int64,int);
|
||||
void *alarmArg;
|
||||
int alarmBusy;
|
||||
|
||||
/*
|
||||
** Mutex to control access to the memory allocation subsystem.
|
||||
*/
|
||||
sqlite3_mutex *mutex;
|
||||
|
||||
/*
|
||||
** Current allocation and high-water mark.
|
||||
*/
|
||||
sqlite3_int64 nowUsed;
|
||||
sqlite3_int64 mxUsed;
|
||||
|
||||
|
||||
} mem;
|
||||
|
||||
/*
|
||||
** Enter the mutex mem.mutex. Allocate it if it is not already allocated.
|
||||
*/
|
||||
static void enterMem(void){
|
||||
if( mem.mutex==0 ){
|
||||
mem.mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MEM);
|
||||
}
|
||||
sqlite3_mutex_enter(mem.mutex);
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the amount of memory currently checked out.
|
||||
*/
|
||||
sqlite3_int64 sqlite3_memory_used(void){
|
||||
sqlite3_int64 n;
|
||||
enterMem();
|
||||
n = mem.nowUsed;
|
||||
sqlite3_mutex_leave(mem.mutex);
|
||||
return n;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the maximum amount of memory that has ever been
|
||||
** checked out since either the beginning of this process
|
||||
** or since the most recent reset.
|
||||
*/
|
||||
sqlite3_int64 sqlite3_memory_highwater(int resetFlag){
|
||||
sqlite3_int64 n;
|
||||
enterMem();
|
||||
n = mem.mxUsed;
|
||||
if( resetFlag ){
|
||||
mem.mxUsed = mem.nowUsed;
|
||||
}
|
||||
sqlite3_mutex_leave(mem.mutex);
|
||||
return n;
|
||||
}
|
||||
|
||||
/*
|
||||
** Change the alarm callback
|
||||
*/
|
||||
int sqlite3_memory_alarm(
|
||||
void(*xCallback)(void *pArg, sqlite3_int64 used,int N),
|
||||
void *pArg,
|
||||
sqlite3_int64 iThreshold
|
||||
){
|
||||
enterMem();
|
||||
mem.alarmCallback = xCallback;
|
||||
mem.alarmArg = pArg;
|
||||
mem.alarmThreshold = iThreshold;
|
||||
sqlite3_mutex_leave(mem.mutex);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Trigger the alarm
|
||||
*/
|
||||
static void sqlite3MemsysAlarm(int nByte){
|
||||
void (*xCallback)(void*,sqlite3_int64,int);
|
||||
sqlite3_int64 nowUsed;
|
||||
void *pArg;
|
||||
if( mem.alarmCallback==0 || mem.alarmBusy ) return;
|
||||
mem.alarmBusy = 1;
|
||||
xCallback = mem.alarmCallback;
|
||||
nowUsed = mem.nowUsed;
|
||||
pArg = mem.alarmArg;
|
||||
sqlite3_mutex_leave(mem.mutex);
|
||||
xCallback(pArg, nowUsed, nByte);
|
||||
sqlite3_mutex_enter(mem.mutex);
|
||||
mem.alarmBusy = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Allocate nBytes of memory
|
||||
*/
|
||||
void *sqlite3_malloc(int nBytes){
|
||||
sqlite3_int64 *p = 0;
|
||||
if( nBytes>0 ){
|
||||
enterMem();
|
||||
if( mem.alarmCallback!=0 && mem.nowUsed+nBytes>=mem.alarmThreshold ){
|
||||
sqlite3MemsysAlarm(nBytes);
|
||||
}
|
||||
p = malloc(nBytes+8);
|
||||
if( p==0 ){
|
||||
sqlite3MemsysAlarm(nBytes);
|
||||
p = malloc(nBytes+8);
|
||||
}
|
||||
if( p ){
|
||||
p[0] = nBytes;
|
||||
p++;
|
||||
mem.nowUsed += nBytes;
|
||||
if( mem.nowUsed>mem.mxUsed ){
|
||||
mem.mxUsed = mem.nowUsed;
|
||||
}
|
||||
}
|
||||
sqlite3_mutex_leave(mem.mutex);
|
||||
}
|
||||
return (void*)p;
|
||||
}
|
||||
|
||||
/*
|
||||
** Free memory.
|
||||
*/
|
||||
void sqlite3_free(void *pPrior){
|
||||
sqlite3_int64 *p;
|
||||
int nByte;
|
||||
if( pPrior==0 ){
|
||||
return;
|
||||
}
|
||||
assert( mem.mutex!=0 );
|
||||
p = pPrior;
|
||||
p--;
|
||||
nByte = (int)*p;
|
||||
sqlite3_mutex_enter(mem.mutex);
|
||||
mem.nowUsed -= nByte;
|
||||
free(p);
|
||||
sqlite3_mutex_leave(mem.mutex);
|
||||
}
|
||||
|
||||
/*
|
||||
** Change the size of an existing memory allocation
|
||||
*/
|
||||
void *sqlite3_realloc(void *pPrior, int nBytes){
|
||||
int nOld;
|
||||
sqlite3_int64 *p;
|
||||
if( pPrior==0 ){
|
||||
return sqlite3_malloc(nBytes);
|
||||
}
|
||||
if( nBytes<=0 ){
|
||||
sqlite3_free(pPrior);
|
||||
return 0;
|
||||
}
|
||||
p = pPrior;
|
||||
p--;
|
||||
nOld = (int)p[0];
|
||||
assert( mem.mutex!=0 );
|
||||
sqlite3_mutex_enter(mem.mutex);
|
||||
if( mem.nowUsed+nBytes-nOld>=mem.alarmThreshold ){
|
||||
sqlite3MemsysAlarm(nBytes-nOld);
|
||||
}
|
||||
p = realloc(p, nBytes+8);
|
||||
if( p==0 ){
|
||||
sqlite3MemsysAlarm(nBytes);
|
||||
p = realloc(p, nBytes+8);
|
||||
}
|
||||
if( p ){
|
||||
p[0] = nBytes;
|
||||
p++;
|
||||
mem.nowUsed += nBytes-nOld;
|
||||
if( mem.nowUsed>mem.mxUsed ){
|
||||
mem.mxUsed = mem.nowUsed;
|
||||
}
|
||||
}
|
||||
sqlite3_mutex_leave(mem.mutex);
|
||||
return (void*)p;
|
||||
}
|
||||
|
||||
#endif /* !SQLITE_MEMDEBUG && !SQLITE_OMIT_MEMORY_ALLOCATION */
|
|
@ -0,0 +1,546 @@
|
|||
/*
|
||||
** 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 the C functions that implement a memory
|
||||
** allocation subsystem for use by SQLite.
|
||||
**
|
||||
** $Id: mem2.c,v 1.14 2007/10/03 08:46:45 danielk1977 Exp $
|
||||
*/
|
||||
|
||||
/*
|
||||
** This version of the memory allocator is used only if the
|
||||
** SQLITE_MEMDEBUG macro is defined and SQLITE_OMIT_MEMORY_ALLOCATION
|
||||
** is not defined.
|
||||
*/
|
||||
#if defined(SQLITE_MEMDEBUG) && !defined(SQLITE_OMIT_MEMORY_ALLOCATION)
|
||||
|
||||
/*
|
||||
** We will eventually construct multiple memory allocation subsystems
|
||||
** suitable for use in various contexts:
|
||||
**
|
||||
** * Normal multi-threaded builds
|
||||
** * Normal single-threaded builds
|
||||
** * Debugging builds
|
||||
**
|
||||
** This version is suitable for use in debugging builds.
|
||||
**
|
||||
** Features:
|
||||
**
|
||||
** * Every allocate has guards at both ends.
|
||||
** * New allocations are initialized with randomness
|
||||
** * Allocations are overwritten with randomness when freed
|
||||
** * Optional logs of malloc activity generated
|
||||
** * Summary of outstanding allocations with backtraces to the
|
||||
** point of allocation.
|
||||
** * The ability to simulate memory allocation failure
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include <stdio.h>
|
||||
|
||||
/*
|
||||
** 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) 0
|
||||
# define backtrace_symbols_fd(A,B,C)
|
||||
#endif
|
||||
|
||||
/*
|
||||
** 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 {
|
||||
struct MemBlockHdr *pNext, *pPrev; /* Linked list of all unfreed memory */
|
||||
int iSize; /* Size of this allocation */
|
||||
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
|
||||
|
||||
/*
|
||||
** 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 {
|
||||
/*
|
||||
** The alarm callback and its arguments. The mem.mutex lock will
|
||||
** be held while the callback is running. Recursive calls into
|
||||
** the memory subsystem are allowed, but no new callbacks will be
|
||||
** issued. The alarmBusy variable is set to prevent recursive
|
||||
** callbacks.
|
||||
*/
|
||||
sqlite3_int64 alarmThreshold;
|
||||
void (*alarmCallback)(void*, sqlite3_int64, int);
|
||||
void *alarmArg;
|
||||
int alarmBusy;
|
||||
|
||||
/*
|
||||
** Mutex to control access to the memory allocation subsystem.
|
||||
*/
|
||||
sqlite3_mutex *mutex;
|
||||
|
||||
/*
|
||||
** Current allocation and high-water mark.
|
||||
*/
|
||||
sqlite3_int64 nowUsed;
|
||||
sqlite3_int64 mxUsed;
|
||||
|
||||
/*
|
||||
** 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;
|
||||
|
||||
/*
|
||||
** 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 */
|
||||
|
||||
/*
|
||||
** These values are used to simulate malloc failures. When
|
||||
** iFail is 1, simulate a malloc failures and reset the value
|
||||
** to iReset.
|
||||
*/
|
||||
int iFail; /* Decrement and fail malloc when this is 1 */
|
||||
int iReset; /* When malloc fails set iiFail to this value */
|
||||
int iFailCnt; /* Number of failures */
|
||||
int iBenignFailCnt; /* Number of benign failures */
|
||||
int iNextIsBenign; /* True if the next call to malloc may fail benignly */
|
||||
int iIsBenign; /* All malloc calls may fail benignly */
|
||||
|
||||
/*
|
||||
** sqlite3MallocDisallow() increments the following counter.
|
||||
** sqlite3MallocAllow() decrements it.
|
||||
*/
|
||||
int disallow; /* Do not allow memory allocation */
|
||||
|
||||
|
||||
} mem;
|
||||
|
||||
|
||||
/*
|
||||
** Enter the mutex mem.mutex. Allocate it if it is not already allocated.
|
||||
*/
|
||||
static void enterMem(void){
|
||||
if( mem.mutex==0 ){
|
||||
mem.mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MEM);
|
||||
}
|
||||
sqlite3_mutex_enter(mem.mutex);
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the amount of memory currently checked out.
|
||||
*/
|
||||
sqlite3_int64 sqlite3_memory_used(void){
|
||||
sqlite3_int64 n;
|
||||
enterMem();
|
||||
n = mem.nowUsed;
|
||||
sqlite3_mutex_leave(mem.mutex);
|
||||
return n;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the maximum amount of memory that has ever been
|
||||
** checked out since either the beginning of this process
|
||||
** or since the most recent reset.
|
||||
*/
|
||||
sqlite3_int64 sqlite3_memory_highwater(int resetFlag){
|
||||
sqlite3_int64 n;
|
||||
enterMem();
|
||||
n = mem.mxUsed;
|
||||
if( resetFlag ){
|
||||
mem.mxUsed = mem.nowUsed;
|
||||
}
|
||||
sqlite3_mutex_leave(mem.mutex);
|
||||
return n;
|
||||
}
|
||||
|
||||
/*
|
||||
** Change the alarm callback
|
||||
*/
|
||||
int sqlite3_memory_alarm(
|
||||
void(*xCallback)(void *pArg, sqlite3_int64 used, int N),
|
||||
void *pArg,
|
||||
sqlite3_int64 iThreshold
|
||||
){
|
||||
enterMem();
|
||||
mem.alarmCallback = xCallback;
|
||||
mem.alarmArg = pArg;
|
||||
mem.alarmThreshold = iThreshold;
|
||||
sqlite3_mutex_leave(mem.mutex);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Trigger the alarm
|
||||
*/
|
||||
static void sqlite3MemsysAlarm(int nByte){
|
||||
void (*xCallback)(void*,sqlite3_int64,int);
|
||||
sqlite3_int64 nowUsed;
|
||||
void *pArg;
|
||||
if( mem.alarmCallback==0 || mem.alarmBusy ) return;
|
||||
mem.alarmBusy = 1;
|
||||
xCallback = mem.alarmCallback;
|
||||
nowUsed = mem.nowUsed;
|
||||
pArg = mem.alarmArg;
|
||||
sqlite3_mutex_leave(mem.mutex);
|
||||
xCallback(pArg, nowUsed, nByte);
|
||||
sqlite3_mutex_enter(mem.mutex);
|
||||
mem.alarmBusy = 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;
|
||||
|
||||
p = (struct MemBlockHdr*)pAllocation;
|
||||
p--;
|
||||
assert( p->iForeGuard==FOREGUARD );
|
||||
assert( (p->iSize & 3)==0 );
|
||||
pInt = (int*)pAllocation;
|
||||
assert( pInt[p->iSize/sizeof(int)]==REARGUARD );
|
||||
return p;
|
||||
}
|
||||
|
||||
/*
|
||||
** This routine is called once the first time a simulated memory
|
||||
** failure occurs. The sole purpose of this routine is to provide
|
||||
** a convenient place to set a debugger breakpoint when debugging
|
||||
** errors related to malloc() failures.
|
||||
*/
|
||||
static void sqlite3MemsysFailed(void){
|
||||
mem.iFailCnt = 0;
|
||||
mem.iBenignFailCnt = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Allocate nByte bytes of memory.
|
||||
*/
|
||||
void *sqlite3_malloc(int nByte){
|
||||
struct MemBlockHdr *pHdr;
|
||||
void **pBt;
|
||||
char *z;
|
||||
int *pInt;
|
||||
void *p = 0;
|
||||
int totalSize;
|
||||
|
||||
if( nByte>0 ){
|
||||
enterMem();
|
||||
assert( mem.disallow==0 );
|
||||
if( mem.alarmCallback!=0 && mem.nowUsed+nByte>=mem.alarmThreshold ){
|
||||
sqlite3MemsysAlarm(nByte);
|
||||
}
|
||||
nByte = (nByte+3)&~3;
|
||||
totalSize = nByte + sizeof(*pHdr) + sizeof(int) +
|
||||
mem.nBacktrace*sizeof(void*) + mem.nTitle;
|
||||
if( mem.iFail>0 ){
|
||||
if( mem.iFail==1 ){
|
||||
p = 0;
|
||||
mem.iFail = mem.iReset;
|
||||
if( mem.iFailCnt==0 ){
|
||||
sqlite3MemsysFailed(); /* A place to set a breakpoint */
|
||||
}
|
||||
mem.iFailCnt++;
|
||||
if( mem.iNextIsBenign || mem.iIsBenign ){
|
||||
mem.iBenignFailCnt++;
|
||||
}
|
||||
}else{
|
||||
p = malloc(totalSize);
|
||||
mem.iFail--;
|
||||
}
|
||||
}else{
|
||||
p = malloc(totalSize);
|
||||
if( p==0 ){
|
||||
sqlite3MemsysAlarm(nByte);
|
||||
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*));
|
||||
}else{
|
||||
pHdr->nBacktrace = 0;
|
||||
}
|
||||
if( mem.nTitle ){
|
||||
memcpy(z, mem.zTitle, mem.nTitle);
|
||||
}
|
||||
pHdr->iSize = nByte;
|
||||
pInt = (int*)&pHdr[1];
|
||||
pInt[nByte/sizeof(int)] = REARGUARD;
|
||||
memset(pInt, 0x65, nByte);
|
||||
mem.nowUsed += nByte;
|
||||
if( mem.nowUsed>mem.mxUsed ){
|
||||
mem.mxUsed = mem.nowUsed;
|
||||
}
|
||||
p = (void*)pInt;
|
||||
}
|
||||
sqlite3_mutex_leave(mem.mutex);
|
||||
}
|
||||
mem.iNextIsBenign = 0;
|
||||
return p;
|
||||
}
|
||||
|
||||
/*
|
||||
** Free memory.
|
||||
*/
|
||||
void sqlite3_free(void *pPrior){
|
||||
struct MemBlockHdr *pHdr;
|
||||
void **pBt;
|
||||
char *z;
|
||||
if( pPrior==0 ){
|
||||
return;
|
||||
}
|
||||
assert( mem.mutex!=0 );
|
||||
pHdr = sqlite3MemsysGetHeader(pPrior);
|
||||
pBt = (void**)pHdr;
|
||||
pBt -= pHdr->nBacktraceSlots;
|
||||
sqlite3_mutex_enter(mem.mutex);
|
||||
mem.nowUsed -= pHdr->iSize;
|
||||
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;
|
||||
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.
|
||||
*/
|
||||
void *sqlite3_realloc(void *pPrior, int nByte){
|
||||
struct MemBlockHdr *pOldHdr;
|
||||
void *pNew;
|
||||
if( pPrior==0 ){
|
||||
return sqlite3_malloc(nByte);
|
||||
}
|
||||
if( nByte<=0 ){
|
||||
sqlite3_free(pPrior);
|
||||
return 0;
|
||||
}
|
||||
assert( mem.disallow==0 );
|
||||
pOldHdr = sqlite3MemsysGetHeader(pPrior);
|
||||
pNew = sqlite3_malloc(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);
|
||||
}
|
||||
sqlite3_free(pPrior);
|
||||
}
|
||||
return pNew;
|
||||
}
|
||||
|
||||
/*
|
||||
** Set the number of backtrace levels kept for each allocation.
|
||||
** A value of zero turns of backtracing. The number is always rounded
|
||||
** up to a multiple of 2.
|
||||
*/
|
||||
void sqlite3_memdebug_backtrace(int depth){
|
||||
if( depth<0 ){ depth = 0; }
|
||||
if( depth>20 ){ depth = 20; }
|
||||
depth = (depth+1)&0xfe;
|
||||
mem.nBacktrace = depth;
|
||||
}
|
||||
|
||||
/*
|
||||
** Set the title string for subsequent allocations.
|
||||
*/
|
||||
void sqlite3_memdebug_settitle(const char *zTitle){
|
||||
int n = strlen(zTitle) + 1;
|
||||
enterMem();
|
||||
if( n>=sizeof(mem.zTitle) ) n = sizeof(mem.zTitle)-1;
|
||||
memcpy(mem.zTitle, zTitle, n);
|
||||
mem.zTitle[n] = 0;
|
||||
mem.nTitle = (n+3)&~3;
|
||||
sqlite3_mutex_leave(mem.mutex);
|
||||
}
|
||||
|
||||
/*
|
||||
** Open the file indicated and write a log of all unfreed memory
|
||||
** allocations into that log.
|
||||
*/
|
||||
void sqlite3_memdebug_dump(const char *zFilename){
|
||||
FILE *out;
|
||||
struct MemBlockHdr *pHdr;
|
||||
void **pBt;
|
||||
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, "**** %d 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");
|
||||
}
|
||||
}
|
||||
fclose(out);
|
||||
}
|
||||
|
||||
/*
|
||||
** This routine is used to simulate malloc failures.
|
||||
**
|
||||
** After calling this routine, there will be iFail successful
|
||||
** memory allocations and then a failure. If iRepeat is 1
|
||||
** all subsequent memory allocations will fail. If iRepeat is
|
||||
** 0, only a single allocation will fail. If iRepeat is negative
|
||||
** then the previous setting for iRepeat is unchanged.
|
||||
**
|
||||
** Each call to this routine overrides the previous. To disable
|
||||
** the simulated allocation failure mechanism, set iFail to -1.
|
||||
**
|
||||
** This routine returns the number of simulated failures that have
|
||||
** occurred since the previous call.
|
||||
*/
|
||||
int sqlite3_memdebug_fail(int iFail, int iRepeat, int *piBenign){
|
||||
int n = mem.iFailCnt;
|
||||
if( piBenign ){
|
||||
*piBenign = mem.iBenignFailCnt;
|
||||
}
|
||||
mem.iFail = iFail+1;
|
||||
if( iRepeat>=0 ){
|
||||
mem.iReset = iRepeat;
|
||||
}
|
||||
mem.iFailCnt = 0;
|
||||
mem.iBenignFailCnt = 0;
|
||||
return n;
|
||||
}
|
||||
|
||||
int sqlite3_memdebug_pending(){
|
||||
return (mem.iFail-1);
|
||||
}
|
||||
|
||||
/*
|
||||
** The following three functions are used to indicate to the test
|
||||
** infrastructure which malloc() calls may fail benignly without
|
||||
** affecting functionality. This can happen when resizing hash tables
|
||||
** (failing to resize a hash-table is a performance hit, but not an
|
||||
** error) or sometimes during a rollback operation.
|
||||
**
|
||||
** If the argument is true, sqlite3MallocBenignFailure() indicates that the
|
||||
** next call to allocate memory may fail benignly.
|
||||
**
|
||||
** If sqlite3MallocEnterBenignBlock() is called with a non-zero argument,
|
||||
** then all memory allocations requested before the next call to
|
||||
** sqlite3MallocLeaveBenignBlock() may fail benignly.
|
||||
*/
|
||||
void sqlite3MallocBenignFailure(int isBenign){
|
||||
if( isBenign ){
|
||||
mem.iNextIsBenign = 1;
|
||||
}
|
||||
}
|
||||
void sqlite3MallocEnterBenignBlock(int isBenign){
|
||||
if( isBenign ){
|
||||
mem.iIsBenign = 1;
|
||||
}
|
||||
}
|
||||
void sqlite3MallocLeaveBenignBlock(){
|
||||
mem.iIsBenign = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** The following two routines are used to assert that no memory
|
||||
** allocations occur between one call and the next. The use of
|
||||
** these routines does not change the computed results in any way.
|
||||
** These routines are like asserts.
|
||||
*/
|
||||
void sqlite3MallocDisallow(void){
|
||||
assert( mem.mutex!=0 );
|
||||
sqlite3_mutex_enter(mem.mutex);
|
||||
mem.disallow++;
|
||||
sqlite3_mutex_leave(mem.mutex);
|
||||
}
|
||||
void sqlite3MallocAllow(void){
|
||||
assert( mem.mutex );
|
||||
sqlite3_mutex_enter(mem.mutex);
|
||||
assert( mem.disallow>0 );
|
||||
mem.disallow--;
|
||||
sqlite3_mutex_leave(mem.mutex);
|
||||
}
|
||||
|
||||
#endif /* SQLITE_MEMDEBUG && !SQLITE_OMIT_MEMORY_ALLOCATION */
|
|
@ -0,0 +1,126 @@
|
|||
/*
|
||||
** 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.
|
||||
**
|
||||
** The 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. But this implementation
|
||||
** does do a lot of error checking on mutexes to make sure they
|
||||
** are called correctly and at appropriate times. Hence, this
|
||||
** implementation is suitable for testing.
|
||||
** debugging purposes
|
||||
**
|
||||
** $Id: mutex.c,v 1.16 2007/09/10 16:13:00 danielk1977 Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
|
||||
#ifdef SQLITE_MUTEX_NOOP_DEBUG
|
||||
/*
|
||||
** In this implementation, mutexes do not provide any mutual exclusion.
|
||||
** But the error checking is provided. This implementation is useful
|
||||
** for test purposes.
|
||||
*/
|
||||
|
||||
/*
|
||||
** The mutex object
|
||||
*/
|
||||
struct sqlite3_mutex {
|
||||
int id; /* The mutex type */
|
||||
int cnt; /* Number of entries without a matching leave */
|
||||
};
|
||||
|
||||
/*
|
||||
** 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.
|
||||
*/
|
||||
sqlite3_mutex *sqlite3_mutex_alloc(int id){
|
||||
static sqlite3_mutex aStatic[5];
|
||||
sqlite3_mutex *pNew = 0;
|
||||
switch( id ){
|
||||
case SQLITE_MUTEX_FAST:
|
||||
case SQLITE_MUTEX_RECURSIVE: {
|
||||
pNew = sqlite3_malloc(sizeof(*pNew));
|
||||
if( pNew ){
|
||||
pNew->id = id;
|
||||
pNew->cnt = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
assert( id-2 >= 0 );
|
||||
assert( id-2 < sizeof(aStatic)/sizeof(aStatic[0]) );
|
||||
pNew = &aStatic[id-2];
|
||||
pNew->id = id;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return pNew;
|
||||
}
|
||||
|
||||
/*
|
||||
** This routine deallocates a previously allocated mutex.
|
||||
*/
|
||||
void sqlite3_mutex_free(sqlite3_mutex *p){
|
||||
assert( 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.
|
||||
*/
|
||||
void sqlite3_mutex_enter(sqlite3_mutex *p){
|
||||
assert( p );
|
||||
assert( p->id==SQLITE_MUTEX_RECURSIVE || sqlite3_mutex_notheld(p) );
|
||||
p->cnt++;
|
||||
}
|
||||
int sqlite3_mutex_try(sqlite3_mutex *p){
|
||||
assert( p );
|
||||
assert( p->id==SQLITE_MUTEX_RECURSIVE || sqlite3_mutex_notheld(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.
|
||||
*/
|
||||
void sqlite3_mutex_leave(sqlite3_mutex *p){
|
||||
assert( p );
|
||||
assert( sqlite3_mutex_held(p) );
|
||||
p->cnt--;
|
||||
assert( p->id==SQLITE_MUTEX_RECURSIVE || sqlite3_mutex_notheld(p) );
|
||||
}
|
||||
|
||||
/*
|
||||
** 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 || p->cnt>0;
|
||||
}
|
||||
int sqlite3_mutex_notheld(sqlite3_mutex *p){
|
||||
return p==0 || p->cnt==0;
|
||||
}
|
||||
#endif /* SQLITE_MUTEX_NOOP_DEBUG */
|
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
** 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.2 2007/08/30 14:10:30 drh Exp $
|
||||
*/
|
||||
|
||||
|
||||
#ifdef SQLITE_MUTEX_APPDEF
|
||||
/*
|
||||
** If SQLITE_MUTEX_APPDEF is defined, then this whole module is
|
||||
** omitted and equivalent functionality must be provided by the
|
||||
** application that links against the SQLite library.
|
||||
*/
|
||||
#else
|
||||
/*
|
||||
** Figure out what version of the code to use. The choices are
|
||||
**
|
||||
** SQLITE_MUTEX_NOOP For single-threaded applications that
|
||||
** do not desire error checking.
|
||||
**
|
||||
** SQLITE_MUTEX_NOOP_DEBUG For single-threaded applications with
|
||||
** error checking to help verify that mutexes
|
||||
** are being used correctly even though they
|
||||
** are not needed. Used when SQLITE_DEBUG is
|
||||
** defined on single-threaded builds.
|
||||
**
|
||||
** 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.
|
||||
*/
|
||||
#define SQLITE_MUTEX_NOOP 1 /* The default */
|
||||
#if defined(SQLITE_DEBUG) && !SQLITE_THREADSAFE
|
||||
# undef SQLITE_MUTEX_NOOP
|
||||
# define SQLITE_MUTEX_NOOP_DEBUG
|
||||
#endif
|
||||
#if defined(SQLITE_MUTEX_NOOP) && SQLITE_THREADSAFE && OS_UNIX
|
||||
# undef SQLITE_MUTEX_NOOP
|
||||
# define SQLITE_MUTEX_PTHREADS
|
||||
#endif
|
||||
#if defined(SQLITE_MUTEX_NOOP) && SQLITE_THREADSAFE && OS_WIN
|
||||
# undef SQLITE_MUTEX_NOOP
|
||||
# define SQLITE_MUTEX_W32
|
||||
#endif
|
||||
#if defined(SQLITE_MUTEX_NOOP) && SQLITE_THREADSAFE && OS_OS2
|
||||
# undef SQLITE_MUTEX_NOOP
|
||||
# define SQLITE_MUTEX_OS2
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_MUTEX_NOOP
|
||||
/*
|
||||
** 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
|
||||
#endif
|
||||
|
||||
#endif /* SQLITE_MUTEX_APPDEF */
|
|
@ -0,0 +1,236 @@
|
|||
/*
|
||||
** 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.3 2007/10/02 19:56:04 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 {
|
||||
PSZ mutexName; /* Mutex name controlling the lock */
|
||||
HMTX mutex; /* Mutex controlling the lock */
|
||||
int id; /* Mutex type */
|
||||
int nRef; /* Number of references */
|
||||
TID owner; /* Thread holding this mutex */
|
||||
};
|
||||
|
||||
/*
|
||||
** 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.
|
||||
*/
|
||||
sqlite3_mutex *sqlite3_mutex_alloc(int iType){
|
||||
PSZ mutex_name = "\\SEM32\\SQLITE\\MUTEX";
|
||||
int mutex_name_len = strlen(mutex_name) + 1; /* name length + null byte */
|
||||
sqlite3_mutex *p;
|
||||
|
||||
switch( iType ){
|
||||
case SQLITE_MUTEX_FAST:
|
||||
case SQLITE_MUTEX_RECURSIVE: {
|
||||
p = sqlite3MallocZero( sizeof(*p) );
|
||||
if( p ){
|
||||
p->mutexName = (PSZ)malloc(mutex_name_len);
|
||||
sqlite3_snprintf(mutex_name_len, p->mutexName, "%s", mutex_name);
|
||||
p->id = iType;
|
||||
DosCreateMutexSem(p->mutexName, &p->mutex, 0, FALSE);
|
||||
DosOpenMutexSem(p->mutexName, &p->mutex);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
static sqlite3_mutex staticMutexes[5];
|
||||
static int isInit = 0;
|
||||
while( !isInit ) {
|
||||
static long lock = 0;
|
||||
DosEnterCritSec();
|
||||
lock++;
|
||||
if( lock == 1 ) {
|
||||
DosExitCritSec();
|
||||
int i;
|
||||
for(i = 0; i < sizeof(staticMutexes)/sizeof(staticMutexes[0]); i++) {
|
||||
staticMutexes[i].mutexName = (PSZ)malloc(mutex_name_len + 1);
|
||||
sqlite3_snprintf(mutex_name_len + 1, /* one more for the number */
|
||||
staticMutexes[i].mutexName, "%s%1d", mutex_name, i);
|
||||
DosCreateMutexSem(staticMutexes[i].mutexName,
|
||||
&staticMutexes[i].mutex, 0, FALSE);
|
||||
DosOpenMutexSem(staticMutexes[i].mutexName,
|
||||
&staticMutexes[i].mutex);
|
||||
}
|
||||
isInit = 1;
|
||||
} else {
|
||||
DosExitCritSec();
|
||||
DosSleep(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.
|
||||
*/
|
||||
void sqlite3_mutex_free(sqlite3_mutex *p){
|
||||
assert( p );
|
||||
assert( p->nRef==0 );
|
||||
assert( p->id==SQLITE_MUTEX_FAST || p->id==SQLITE_MUTEX_RECURSIVE );
|
||||
DosCloseMutexSem(p->mutex);
|
||||
free(p->mutexName);
|
||||
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.
|
||||
*/
|
||||
void sqlite3_mutex_enter(sqlite3_mutex *p){
|
||||
TID tid;
|
||||
PID holder1;
|
||||
ULONG holder2;
|
||||
assert( p );
|
||||
assert( p->id==SQLITE_MUTEX_RECURSIVE || sqlite3_mutex_notheld(p) );
|
||||
DosRequestMutexSem(p->mutex, SEM_INDEFINITE_WAIT);
|
||||
DosQueryMutexSem(p->mutex, &holder1, &tid, &holder2);
|
||||
p->owner = tid;
|
||||
p->nRef++;
|
||||
}
|
||||
int sqlite3_mutex_try(sqlite3_mutex *p){
|
||||
int rc;
|
||||
TID tid;
|
||||
PID holder1;
|
||||
ULONG holder2;
|
||||
assert( p );
|
||||
assert( p->id==SQLITE_MUTEX_RECURSIVE || sqlite3_mutex_notheld(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.
|
||||
*/
|
||||
void sqlite3_mutex_leave(sqlite3_mutex *p){
|
||||
TID tid;
|
||||
PID holder1;
|
||||
ULONG holder2;
|
||||
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);
|
||||
}
|
||||
|
||||
/*
|
||||
** The sqlite3_mutex_held() and sqlite3_mutex_notheld() routine are
|
||||
** intended for use inside assert() statements.
|
||||
*/
|
||||
int sqlite3_mutex_held(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);
|
||||
}
|
||||
int sqlite3_mutex_notheld(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 /* SQLITE_MUTEX_OS2 */
|
|
@ -0,0 +1,223 @@
|
|||
/*
|
||||
** 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.2 2007/08/28 22:24:35 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
|
||||
};
|
||||
|
||||
/*
|
||||
** 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.
|
||||
*/
|
||||
sqlite3_mutex *sqlite3_mutex_alloc(int iType){
|
||||
static sqlite3_mutex staticMutexes[] = {
|
||||
{ PTHREAD_MUTEX_INITIALIZER, },
|
||||
{ PTHREAD_MUTEX_INITIALIZER, },
|
||||
{ PTHREAD_MUTEX_INITIALIZER, },
|
||||
{ PTHREAD_MUTEX_INITIALIZER, },
|
||||
{ PTHREAD_MUTEX_INITIALIZER, },
|
||||
};
|
||||
sqlite3_mutex *p;
|
||||
switch( iType ){
|
||||
case SQLITE_MUTEX_RECURSIVE: {
|
||||
p = sqlite3MallocZero( sizeof(*p) );
|
||||
if( p ){
|
||||
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);
|
||||
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 < 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.
|
||||
*/
|
||||
void sqlite3_mutex_free(sqlite3_mutex *p){
|
||||
assert( 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.
|
||||
*/
|
||||
void sqlite3_mutex_enter(sqlite3_mutex *p){
|
||||
assert( p );
|
||||
assert( p->id==SQLITE_MUTEX_RECURSIVE || sqlite3_mutex_notheld(p) );
|
||||
pthread_mutex_lock(&p->mutex);
|
||||
p->owner = pthread_self();
|
||||
p->nRef++;
|
||||
#ifdef SQLITE_DEBUG
|
||||
if( p->trace ){
|
||||
printf("enter mutex %p (%d) with nRef=%d\n", p, p->trace, p->nRef);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
int sqlite3_mutex_try(sqlite3_mutex *p){
|
||||
int rc;
|
||||
assert( p );
|
||||
assert( p->id==SQLITE_MUTEX_RECURSIVE || sqlite3_mutex_notheld(p) );
|
||||
if( pthread_mutex_trylock(&p->mutex)==0 ){
|
||||
p->owner = pthread_self();
|
||||
p->nRef++;
|
||||
rc = SQLITE_OK;
|
||||
#ifdef SQLITE_DEBUG
|
||||
if( p->trace ){
|
||||
printf("enter mutex %p (%d) with nRef=%d\n", p, p->trace, p->nRef);
|
||||
}
|
||||
#endif
|
||||
}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.
|
||||
*/
|
||||
void sqlite3_mutex_leave(sqlite3_mutex *p){
|
||||
assert( p );
|
||||
assert( sqlite3_mutex_held(p) );
|
||||
p->nRef--;
|
||||
assert( p->nRef==0 || p->id==SQLITE_MUTEX_RECURSIVE );
|
||||
#ifdef SQLITE_DEBUG
|
||||
if( p->trace ){
|
||||
printf("leave mutex %p (%d) with nRef=%d\n", p, p->trace, p->nRef);
|
||||
}
|
||||
#endif
|
||||
pthread_mutex_unlock(&p->mutex);
|
||||
}
|
||||
|
||||
/*
|
||||
** 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.
|
||||
*/
|
||||
#ifndef NDEBUG
|
||||
int sqlite3_mutex_held(sqlite3_mutex *p){
|
||||
return p==0 || (p->nRef!=0 && pthread_equal(p->owner, pthread_self()));
|
||||
}
|
||||
int sqlite3_mutex_notheld(sqlite3_mutex *p){
|
||||
return p==0 || p->nRef==0 || pthread_equal(p->owner, pthread_self())==0;
|
||||
}
|
||||
#endif
|
||||
#endif /* SQLITE_MUTEX_PTHREAD */
|
|
@ -0,0 +1,210 @@
|
|||
/*
|
||||
** 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.4 2007/09/05 14:30:42 drh Exp $
|
||||
*/
|
||||
#define _WIN32_WINNT 0x0400
|
||||
#include <Windows.h>
|
||||
#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.
|
||||
*/
|
||||
#if 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 /* OS_WINCE */
|
||||
|
||||
|
||||
/*
|
||||
** 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.
|
||||
*/
|
||||
sqlite3_mutex *sqlite3_mutex_alloc(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[5];
|
||||
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.
|
||||
*/
|
||||
void sqlite3_mutex_free(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.
|
||||
*/
|
||||
void sqlite3_mutex_enter(sqlite3_mutex *p){
|
||||
assert( p );
|
||||
assert( p->id==SQLITE_MUTEX_RECURSIVE || sqlite3_mutex_notheld(p) );
|
||||
EnterCriticalSection(&p->mutex);
|
||||
p->owner = GetCurrentThreadId();
|
||||
p->nRef++;
|
||||
}
|
||||
int sqlite3_mutex_try(sqlite3_mutex *p){
|
||||
int rc;
|
||||
assert( p );
|
||||
assert( p->id==SQLITE_MUTEX_RECURSIVE || sqlite3_mutex_notheld(p) );
|
||||
if( mutexIsNT() && TryEnterCriticalSection(&p->mutex) ){
|
||||
p->owner = GetCurrentThreadId();
|
||||
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.
|
||||
*/
|
||||
void sqlite3_mutex_leave(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);
|
||||
}
|
||||
|
||||
/*
|
||||
** The sqlite3_mutex_held() and sqlite3_mutex_notheld() routine are
|
||||
** intended for use only inside assert() statements.
|
||||
*/
|
||||
int sqlite3_mutex_held(sqlite3_mutex *p){
|
||||
return p==0 || (p->nRef!=0 && p->owner==GetCurrentThreadId());
|
||||
}
|
||||
int sqlite3_mutex_notheld(sqlite3_mutex *p){
|
||||
return p==0 || p->nRef==0 || p->owner!=GetCurrentThreadId();
|
||||
}
|
||||
#endif /* SQLITE_MUTEX_W32 */
|
|
@ -0,0 +1,151 @@
|
|||
/* Automatically generated. Do not edit */
|
||||
/* See the mkopcodec.awk script for details. */
|
||||
#if !defined(SQLITE_OMIT_EXPLAIN) || !defined(NDEBUG) || defined(VDBE_PROFILE) || defined(SQLITE_DEBUG)
|
||||
const char *sqlite3OpcodeName(int i){
|
||||
static const char *const azName[] = { "?",
|
||||
/* 1 */ "VCreate",
|
||||
/* 2 */ "MemMax",
|
||||
/* 3 */ "LoadAnalysis",
|
||||
/* 4 */ "RowData",
|
||||
/* 5 */ "CreateIndex",
|
||||
/* 6 */ "Variable",
|
||||
/* 7 */ "MemStore",
|
||||
/* 8 */ "Clear",
|
||||
/* 9 */ "Last",
|
||||
/* 10 */ "MoveGe",
|
||||
/* 11 */ "Sequence",
|
||||
/* 12 */ "Int64",
|
||||
/* 13 */ "VBegin",
|
||||
/* 14 */ "RowKey",
|
||||
/* 15 */ "MemInt",
|
||||
/* 16 */ "Not",
|
||||
/* 17 */ "ResetCount",
|
||||
/* 18 */ "Delete",
|
||||
/* 19 */ "Rowid",
|
||||
/* 20 */ "OpenRead",
|
||||
/* 21 */ "Sort",
|
||||
/* 22 */ "VerifyCookie",
|
||||
/* 23 */ "VColumn",
|
||||
/* 24 */ "MemMove",
|
||||
/* 25 */ "Next",
|
||||
/* 26 */ "Insert",
|
||||
/* 27 */ "Prev",
|
||||
/* 28 */ "IdxGE",
|
||||
/* 29 */ "VRename",
|
||||
/* 30 */ "DropTable",
|
||||
/* 31 */ "MakeRecord",
|
||||
/* 32 */ "Null",
|
||||
/* 33 */ "IdxInsert",
|
||||
/* 34 */ "ReadCookie",
|
||||
/* 35 */ "VDestroy",
|
||||
/* 36 */ "DropIndex",
|
||||
/* 37 */ "MustBeInt",
|
||||
/* 38 */ "Callback",
|
||||
/* 39 */ "IntegrityCk",
|
||||
/* 40 */ "MoveGt",
|
||||
/* 41 */ "MoveLe",
|
||||
/* 42 */ "CollSeq",
|
||||
/* 43 */ "OpenEphemeral",
|
||||
/* 44 */ "VNext",
|
||||
/* 45 */ "Found",
|
||||
/* 46 */ "If",
|
||||
/* 47 */ "Dup",
|
||||
/* 48 */ "Goto",
|
||||
/* 49 */ "Function",
|
||||
/* 50 */ "Pop",
|
||||
/* 51 */ "Blob",
|
||||
/* 52 */ "MemIncr",
|
||||
/* 53 */ "IfMemPos",
|
||||
/* 54 */ "FifoWrite",
|
||||
/* 55 */ "IdxGT",
|
||||
/* 56 */ "NullRow",
|
||||
/* 57 */ "Transaction",
|
||||
/* 58 */ "VUpdate",
|
||||
/* 59 */ "TableLock",
|
||||
/* 60 */ "Or",
|
||||
/* 61 */ "And",
|
||||
/* 62 */ "IdxRowid",
|
||||
/* 63 */ "SetCookie",
|
||||
/* 64 */ "ContextPush",
|
||||
/* 65 */ "IsNull",
|
||||
/* 66 */ "NotNull",
|
||||
/* 67 */ "Ne",
|
||||
/* 68 */ "Eq",
|
||||
/* 69 */ "Gt",
|
||||
/* 70 */ "Le",
|
||||
/* 71 */ "Lt",
|
||||
/* 72 */ "Ge",
|
||||
/* 73 */ "DropTrigger",
|
||||
/* 74 */ "BitAnd",
|
||||
/* 75 */ "BitOr",
|
||||
/* 76 */ "ShiftLeft",
|
||||
/* 77 */ "ShiftRight",
|
||||
/* 78 */ "Add",
|
||||
/* 79 */ "Subtract",
|
||||
/* 80 */ "Multiply",
|
||||
/* 81 */ "Divide",
|
||||
/* 82 */ "Remainder",
|
||||
/* 83 */ "Concat",
|
||||
/* 84 */ "MoveLt",
|
||||
/* 85 */ "Negative",
|
||||
/* 86 */ "AutoCommit",
|
||||
/* 87 */ "BitNot",
|
||||
/* 88 */ "String8",
|
||||
/* 89 */ "Column",
|
||||
/* 90 */ "AbsValue",
|
||||
/* 91 */ "AddImm",
|
||||
/* 92 */ "ContextPop",
|
||||
/* 93 */ "IdxDelete",
|
||||
/* 94 */ "IncrVacuum",
|
||||
/* 95 */ "AggFinal",
|
||||
/* 96 */ "RealAffinity",
|
||||
/* 97 */ "Return",
|
||||
/* 98 */ "Expire",
|
||||
/* 99 */ "Rewind",
|
||||
/* 100 */ "Statement",
|
||||
/* 101 */ "Integer",
|
||||
/* 102 */ "IfMemZero",
|
||||
/* 103 */ "Destroy",
|
||||
/* 104 */ "IdxLT",
|
||||
/* 105 */ "MakeIdxRec",
|
||||
/* 106 */ "Vacuum",
|
||||
/* 107 */ "MemNull",
|
||||
/* 108 */ "IfNot",
|
||||
/* 109 */ "Pull",
|
||||
/* 110 */ "FifoRead",
|
||||
/* 111 */ "ParseSchema",
|
||||
/* 112 */ "NewRowid",
|
||||
/* 113 */ "SetNumColumns",
|
||||
/* 114 */ "Explain",
|
||||
/* 115 */ "String",
|
||||
/* 116 */ "AggStep",
|
||||
/* 117 */ "VRowid",
|
||||
/* 118 */ "VOpen",
|
||||
/* 119 */ "NotExists",
|
||||
/* 120 */ "Close",
|
||||
/* 121 */ "Halt",
|
||||
/* 122 */ "Noop",
|
||||
/* 123 */ "VFilter",
|
||||
/* 124 */ "OpenPseudo",
|
||||
/* 125 */ "Real",
|
||||
/* 126 */ "HexBlob",
|
||||
/* 127 */ "IfMemNeg",
|
||||
/* 128 */ "IsUnique",
|
||||
/* 129 */ "ForceInt",
|
||||
/* 130 */ "OpenWrite",
|
||||
/* 131 */ "Gosub",
|
||||
/* 132 */ "Distinct",
|
||||
/* 133 */ "MemLoad",
|
||||
/* 134 */ "NotFound",
|
||||
/* 135 */ "CreateTable",
|
||||
/* 136 */ "Push",
|
||||
/* 137 */ "NotUsed_137",
|
||||
/* 138 */ "ToText",
|
||||
/* 139 */ "ToBlob",
|
||||
/* 140 */ "ToNumeric",
|
||||
/* 141 */ "ToInt",
|
||||
/* 142 */ "ToReal",
|
||||
};
|
||||
return azName[i];
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,160 @@
|
|||
/* Automatically generated. Do not edit */
|
||||
/* See the mkopcodeh.awk script for details */
|
||||
#define OP_VCreate 1
|
||||
#define OP_MemMax 2
|
||||
#define OP_LoadAnalysis 3
|
||||
#define OP_RowData 4
|
||||
#define OP_CreateIndex 5
|
||||
#define OP_Variable 6
|
||||
#define OP_MemStore 7
|
||||
#define OP_Clear 8
|
||||
#define OP_Last 9
|
||||
#define OP_Add 78 /* same as TK_PLUS */
|
||||
#define OP_MoveGe 10
|
||||
#define OP_Sequence 11
|
||||
#define OP_Int64 12
|
||||
#define OP_VBegin 13
|
||||
#define OP_RowKey 14
|
||||
#define OP_Divide 81 /* same as TK_SLASH */
|
||||
#define OP_MemInt 15
|
||||
#define OP_ResetCount 17
|
||||
#define OP_Delete 18
|
||||
#define OP_Rowid 19
|
||||
#define OP_OpenRead 20
|
||||
#define OP_Sort 21
|
||||
#define OP_VerifyCookie 22
|
||||
#define OP_VColumn 23
|
||||
#define OP_MemMove 24
|
||||
#define OP_Next 25
|
||||
#define OP_Insert 26
|
||||
#define OP_Prev 27
|
||||
#define OP_IdxGE 28
|
||||
#define OP_Not 16 /* same as TK_NOT */
|
||||
#define OP_Ge 72 /* same as TK_GE */
|
||||
#define OP_VRename 29
|
||||
#define OP_DropTable 30
|
||||
#define OP_MakeRecord 31
|
||||
#define OP_Null 32
|
||||
#define OP_IdxInsert 33
|
||||
#define OP_ReadCookie 34
|
||||
#define OP_VDestroy 35
|
||||
#define OP_DropIndex 36
|
||||
#define OP_IsNull 65 /* same as TK_ISNULL */
|
||||
#define OP_MustBeInt 37
|
||||
#define OP_Callback 38
|
||||
#define OP_IntegrityCk 39
|
||||
#define OP_MoveGt 40
|
||||
#define OP_MoveLe 41
|
||||
#define OP_CollSeq 42
|
||||
#define OP_OpenEphemeral 43
|
||||
#define OP_HexBlob 126 /* same as TK_BLOB */
|
||||
#define OP_VNext 44
|
||||
#define OP_Eq 68 /* same as TK_EQ */
|
||||
#define OP_String8 88 /* same as TK_STRING */
|
||||
#define OP_Found 45
|
||||
#define OP_If 46
|
||||
#define OP_ToBlob 139 /* same as TK_TO_BLOB */
|
||||
#define OP_Multiply 80 /* same as TK_STAR */
|
||||
#define OP_Dup 47
|
||||
#define OP_ShiftRight 77 /* same as TK_RSHIFT */
|
||||
#define OP_Goto 48
|
||||
#define OP_Function 49
|
||||
#define OP_Pop 50
|
||||
#define OP_Blob 51
|
||||
#define OP_MemIncr 52
|
||||
#define OP_BitNot 87 /* same as TK_BITNOT */
|
||||
#define OP_IfMemPos 53
|
||||
#define OP_FifoWrite 54
|
||||
#define OP_IdxGT 55
|
||||
#define OP_Gt 69 /* same as TK_GT */
|
||||
#define OP_Le 70 /* same as TK_LE */
|
||||
#define OP_NullRow 56
|
||||
#define OP_Transaction 57
|
||||
#define OP_VUpdate 58
|
||||
#define OP_TableLock 59
|
||||
#define OP_IdxRowid 62
|
||||
#define OP_SetCookie 63
|
||||
#define OP_Negative 85 /* same as TK_UMINUS */
|
||||
#define OP_And 61 /* same as TK_AND */
|
||||
#define OP_ToNumeric 140 /* same as TK_TO_NUMERIC*/
|
||||
#define OP_ToText 138 /* same as TK_TO_TEXT */
|
||||
#define OP_ContextPush 64
|
||||
#define OP_DropTrigger 73
|
||||
#define OP_MoveLt 84
|
||||
#define OP_AutoCommit 86
|
||||
#define OP_Column 89
|
||||
#define OP_AbsValue 90
|
||||
#define OP_AddImm 91
|
||||
#define OP_Remainder 82 /* same as TK_REM */
|
||||
#define OP_ContextPop 92
|
||||
#define OP_IdxDelete 93
|
||||
#define OP_Ne 67 /* same as TK_NE */
|
||||
#define OP_ToInt 141 /* same as TK_TO_INT */
|
||||
#define OP_IncrVacuum 94
|
||||
#define OP_AggFinal 95
|
||||
#define OP_RealAffinity 96
|
||||
#define OP_Concat 83 /* same as TK_CONCAT */
|
||||
#define OP_Return 97
|
||||
#define OP_Expire 98
|
||||
#define OP_Rewind 99
|
||||
#define OP_Statement 100
|
||||
#define OP_BitOr 75 /* same as TK_BITOR */
|
||||
#define OP_Integer 101
|
||||
#define OP_IfMemZero 102
|
||||
#define OP_Destroy 103
|
||||
#define OP_IdxLT 104
|
||||
#define OP_MakeIdxRec 105
|
||||
#define OP_Lt 71 /* same as TK_LT */
|
||||
#define OP_Subtract 79 /* same as TK_MINUS */
|
||||
#define OP_Vacuum 106
|
||||
#define OP_MemNull 107
|
||||
#define OP_IfNot 108
|
||||
#define OP_Pull 109
|
||||
#define OP_FifoRead 110
|
||||
#define OP_ParseSchema 111
|
||||
#define OP_NewRowid 112
|
||||
#define OP_SetNumColumns 113
|
||||
#define OP_Explain 114
|
||||
#define OP_BitAnd 74 /* same as TK_BITAND */
|
||||
#define OP_String 115
|
||||
#define OP_AggStep 116
|
||||
#define OP_VRowid 117
|
||||
#define OP_VOpen 118
|
||||
#define OP_NotExists 119
|
||||
#define OP_Close 120
|
||||
#define OP_Halt 121
|
||||
#define OP_Noop 122
|
||||
#define OP_VFilter 123
|
||||
#define OP_OpenPseudo 124
|
||||
#define OP_Or 60 /* same as TK_OR */
|
||||
#define OP_ShiftLeft 76 /* same as TK_LSHIFT */
|
||||
#define OP_IfMemNeg 127
|
||||
#define OP_ToReal 142 /* same as TK_TO_REAL */
|
||||
#define OP_IsUnique 128
|
||||
#define OP_ForceInt 129
|
||||
#define OP_OpenWrite 130
|
||||
#define OP_Gosub 131
|
||||
#define OP_Real 125 /* same as TK_FLOAT */
|
||||
#define OP_Distinct 132
|
||||
#define OP_NotNull 66 /* same as TK_NOTNULL */
|
||||
#define OP_MemLoad 133
|
||||
#define OP_NotFound 134
|
||||
#define OP_CreateTable 135
|
||||
#define OP_Push 136
|
||||
|
||||
/* The following opcode values are never used */
|
||||
#define OP_NotUsed_137 137
|
||||
|
||||
/* Opcodes that are guaranteed to never push a value onto the stack
|
||||
** contain a 1 their corresponding position of the following mask
|
||||
** set. See the opcodeNoPush() function in vdbeaux.c */
|
||||
#define NOPUSH_MASK_0 0x278e
|
||||
#define NOPUSH_MASK_1 0x7e77
|
||||
#define NOPUSH_MASK_2 0x7f7a
|
||||
#define NOPUSH_MASK_3 0xbff5
|
||||
#define NOPUSH_MASK_4 0xffff
|
||||
#define NOPUSH_MASK_5 0xf8f7
|
||||
#define NOPUSH_MASK_6 0xb55f
|
||||
#define NOPUSH_MASK_7 0x9fd2
|
||||
#define NOPUSH_MASK_8 0x7d5f
|
||||
#define NOPUSH_MASK_9 0x0000
|
|
@ -0,0 +1,18 @@
|
|||
downloaded tarball from:
|
||||
http://www.sqlite.org/sqlite-3.5.1.tar.gz
|
||||
|
||||
source tree derived (in unix!) by running:
|
||||
make target_source
|
||||
in unix/build
|
||||
|
||||
two files removed: tclsqlite.c, fts1.c
|
||||
|
||||
in mutex_w32.c, added:
|
||||
#define _WIN32_WINNT 0x0400
|
||||
#include <Windows.h>
|
||||
|
||||
created sqlite_vs2005\sqlite_vs2005.sln
|
||||
|
||||
build all
|
||||
|
||||
copy sqlite_vs2005\release\sqlite_vs2005.dll to bin\sqlite3.dll
|
|
@ -0,0 +1,282 @@
|
|||
/*
|
||||
** 2005 November 29
|
||||
**
|
||||
** The author disclaims copyright to this source code. In place of
|
||||
** a legal notice, here is a blessing:
|
||||
**
|
||||
** May you do good and not evil.
|
||||
** May you find forgiveness for yourself and forgive others.
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
******************************************************************************
|
||||
**
|
||||
** This file contains OS interface code that is common to all
|
||||
** architectures.
|
||||
*/
|
||||
#define _SQLITE_OS_C_ 1
|
||||
#include "sqliteInt.h"
|
||||
#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()
|
||||
**
|
||||
*/
|
||||
#ifdef SQLITE_TEST
|
||||
#define DO_OS_MALLOC_TEST if (1) { \
|
||||
void *pTstAlloc = sqlite3_malloc(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
|
||||
** of the sqlite3_file object. This is mostly just syntactic sugar. All
|
||||
** of this would be completely automatic if SQLite were coded using
|
||||
** C++ instead of plain old C.
|
||||
*/
|
||||
int sqlite3OsClose(sqlite3_file *pId){
|
||||
int rc = SQLITE_OK;
|
||||
if( pId->pMethods ){
|
||||
rc = pId->pMethods->xClose(pId);
|
||||
pId->pMethods = 0;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
int sqlite3OsRead(sqlite3_file *id, void *pBuf, int amt, i64 offset){
|
||||
DO_OS_MALLOC_TEST;
|
||||
return id->pMethods->xRead(id, pBuf, amt, offset);
|
||||
}
|
||||
int sqlite3OsWrite(sqlite3_file *id, const void *pBuf, int amt, i64 offset){
|
||||
DO_OS_MALLOC_TEST;
|
||||
return id->pMethods->xWrite(id, pBuf, amt, offset);
|
||||
}
|
||||
int sqlite3OsTruncate(sqlite3_file *id, i64 size){
|
||||
return id->pMethods->xTruncate(id, size);
|
||||
}
|
||||
int sqlite3OsSync(sqlite3_file *id, int flags){
|
||||
DO_OS_MALLOC_TEST;
|
||||
return id->pMethods->xSync(id, flags);
|
||||
}
|
||||
int sqlite3OsFileSize(sqlite3_file *id, i64 *pSize){
|
||||
return id->pMethods->xFileSize(id, pSize);
|
||||
}
|
||||
int sqlite3OsLock(sqlite3_file *id, int lockType){
|
||||
DO_OS_MALLOC_TEST;
|
||||
return id->pMethods->xLock(id, lockType);
|
||||
}
|
||||
int sqlite3OsUnlock(sqlite3_file *id, int lockType){
|
||||
return id->pMethods->xUnlock(id, lockType);
|
||||
}
|
||||
int sqlite3OsCheckReservedLock(sqlite3_file *id){
|
||||
return id->pMethods->xCheckReservedLock(id);
|
||||
}
|
||||
int sqlite3OsFileControl(sqlite3_file *id, int op, void *pArg){
|
||||
return id->pMethods->xFileControl(id,op,pArg);
|
||||
}
|
||||
|
||||
#ifdef SQLITE_TEST
|
||||
/* The following two variables are used to override the values returned
|
||||
** by the xSectorSize() and xDeviceCharacteristics() vfs methods for
|
||||
** testing purposes. They are usually set by a test command implemented
|
||||
** in test6.c.
|
||||
*/
|
||||
int sqlite3_test_sector_size = 0;
|
||||
int sqlite3_test_device_characteristics = 0;
|
||||
int sqlite3OsDeviceCharacteristics(sqlite3_file *id){
|
||||
int dc = id->pMethods->xDeviceCharacteristics(id);
|
||||
return dc | sqlite3_test_device_characteristics;
|
||||
}
|
||||
int sqlite3OsSectorSize(sqlite3_file *id){
|
||||
if( sqlite3_test_sector_size==0 ){
|
||||
int (*xSectorSize)(sqlite3_file*) = id->pMethods->xSectorSize;
|
||||
return (xSectorSize ? xSectorSize(id) : SQLITE_DEFAULT_SECTOR_SIZE);
|
||||
}
|
||||
return sqlite3_test_sector_size;
|
||||
}
|
||||
#else
|
||||
int sqlite3OsSectorSize(sqlite3_file *id){
|
||||
int (*xSectorSize)(sqlite3_file*) = id->pMethods->xSectorSize;
|
||||
return (xSectorSize ? xSectorSize(id) : SQLITE_DEFAULT_SECTOR_SIZE);
|
||||
}
|
||||
int sqlite3OsDeviceCharacteristics(sqlite3_file *id){
|
||||
return id->pMethods->xDeviceCharacteristics(id);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
** The next group of routines are convenience wrappers around the
|
||||
** VFS methods.
|
||||
*/
|
||||
int sqlite3OsOpen(
|
||||
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){
|
||||
return pVfs->xAccess(pVfs, zPath, flags);
|
||||
}
|
||||
int sqlite3OsGetTempname(sqlite3_vfs *pVfs, int nBufOut, char *zBufOut){
|
||||
return pVfs->xGetTempname(pVfs, nBufOut, zBufOut);
|
||||
}
|
||||
int sqlite3OsFullPathname(
|
||||
sqlite3_vfs *pVfs,
|
||||
const char *zPath,
|
||||
int nPathOut,
|
||||
char *zPathOut
|
||||
){
|
||||
return pVfs->xFullPathname(pVfs, zPath, nPathOut, zPathOut);
|
||||
}
|
||||
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 *pHandle, const char *zSymbol){
|
||||
return pVfs->xDlSym(pVfs, pHandle, zSymbol);
|
||||
}
|
||||
void sqlite3OsDlClose(sqlite3_vfs *pVfs, void *pHandle){
|
||||
pVfs->xDlClose(pVfs, pHandle);
|
||||
}
|
||||
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 *)sqlite3_malloc(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;
|
||||
if( pFile ){
|
||||
rc = sqlite3OsClose(pFile);
|
||||
sqlite3_free(pFile);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** The list of all registered VFS implementations. This list is
|
||||
** initialized to the single VFS returned by sqlite3OsDefaultVfs()
|
||||
** upon the first call to sqlite3_vfs_find().
|
||||
*/
|
||||
static sqlite3_vfs *vfsList = 0;
|
||||
|
||||
/*
|
||||
** 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_mutex *mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER);
|
||||
sqlite3_vfs *pVfs;
|
||||
static int isInit = 0;
|
||||
sqlite3_mutex_enter(mutex);
|
||||
if( !isInit ){
|
||||
vfsList = sqlite3OsDefaultVfs();
|
||||
isInit = 1;
|
||||
}
|
||||
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(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER)) );
|
||||
if( vfsList==pVfs ){
|
||||
vfsList = pVfs->pNext;
|
||||
}else{
|
||||
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 = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER);
|
||||
sqlite3_vfs_find(0); /* Make sure we are initialized */
|
||||
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){
|
||||
sqlite3_mutex *mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER);
|
||||
sqlite3_mutex_enter(mutex);
|
||||
vfsUnlink(pVfs);
|
||||
assert(vfsList);
|
||||
sqlite3_mutex_leave(mutex);
|
||||
return SQLITE_OK;
|
||||
}
|
|
@ -0,0 +1,284 @@
|
|||
/*
|
||||
** 2001 September 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 header file (together with is companion C source-code file
|
||||
** "os.c") attempt to abstract the underlying operating system so that
|
||||
** 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.
|
||||
*/
|
||||
#ifndef _SQLITE_OS_H_
|
||||
#define _SQLITE_OS_H_
|
||||
|
||||
/*
|
||||
** Figure out if we are dealing with Unix, Windows, or some other
|
||||
** operating system. After the following block of preprocess macros,
|
||||
** all of OS_UNIX, OS_WIN, OS_OS2, and 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 OS_OTHER==1
|
||||
# undef OS_UNIX
|
||||
# define OS_UNIX 0
|
||||
# undef OS_WIN
|
||||
# define OS_WIN 0
|
||||
# undef OS_OS2
|
||||
# define OS_OS2 0
|
||||
# else
|
||||
# undef OS_OTHER
|
||||
# endif
|
||||
#endif
|
||||
#if !defined(OS_UNIX) && !defined(OS_OTHER)
|
||||
# define OS_OTHER 0
|
||||
# ifndef OS_WIN
|
||||
# if defined(_WIN32) || defined(WIN32) || defined(__CYGWIN__) || defined(__MINGW32__) || defined(__BORLANDC__)
|
||||
# define OS_WIN 1
|
||||
# define OS_UNIX 0
|
||||
# define OS_OS2 0
|
||||
# elif defined(__EMX__) || defined(_OS2) || defined(OS2) || defined(_OS2_) || defined(__OS2__)
|
||||
# define OS_WIN 0
|
||||
# define OS_UNIX 0
|
||||
# define OS_OS2 1
|
||||
# else
|
||||
# define OS_WIN 0
|
||||
# define OS_UNIX 1
|
||||
# define OS_OS2 0
|
||||
# endif
|
||||
# else
|
||||
# define OS_UNIX 0
|
||||
# define OS_OS2 0
|
||||
# endif
|
||||
#else
|
||||
# ifndef OS_WIN
|
||||
# define OS_WIN 0
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/*
|
||||
** Define the maximum size of a temporary filename
|
||||
*/
|
||||
#if OS_WIN
|
||||
# include <windows.h>
|
||||
# define SQLITE_TEMPNAME_SIZE (MAX_PATH+50)
|
||||
#elif OS_OS2
|
||||
# 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 */
|
||||
# endif
|
||||
# define INCL_DOSDATETIME
|
||||
# define INCL_DOSFILEMGR
|
||||
# define INCL_DOSERRORS
|
||||
# define INCL_DOSMISC
|
||||
# define INCL_DOSPROCESS
|
||||
# define INCL_DOSMODULEMGR
|
||||
# include <os2.h>
|
||||
# define SQLITE_TEMPNAME_SIZE (CCHMAXPATHCOMP)
|
||||
#else
|
||||
# define SQLITE_TEMPNAME_SIZE 200
|
||||
#endif
|
||||
|
||||
/* If the SET_FULLSYNC macro is not defined above, then make it
|
||||
** a no-op
|
||||
*/
|
||||
#ifndef SET_FULLSYNC
|
||||
# define SET_FULLSYNC(x,y)
|
||||
#endif
|
||||
|
||||
/*
|
||||
** The default size of a disk sector
|
||||
*/
|
||||
#ifndef SQLITE_DEFAULT_SECTOR_SIZE
|
||||
# define SQLITE_DEFAULT_SECTOR_SIZE 512
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Temporary files are named starting with this prefix followed by 16 random
|
||||
** alphanumeric characters, and no file extension. They are stored in the
|
||||
** OS's standard temporary file directory, and are deleted prior to exit.
|
||||
** 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
|
||||
** prematurely, old temporary files can be easily identified. This can be done
|
||||
** using -DSQLITE_TEMP_FILE_PREFIX=myprefix_ on the compiler command line.
|
||||
**
|
||||
** 2006-10-31: The default prefix used to be "sqlite_". But then
|
||||
** Mcafee started using SQLite in their anti-virus product and it
|
||||
** started putting files with the "sqlite" name in the c:/temp folder.
|
||||
** This annoyed many windows users. Those users would then do a
|
||||
** Google search for "sqlite", find the telephone numbers of the
|
||||
** developers and call to wake them up at night and complain.
|
||||
** For this reason, the default name prefix is changed to be "sqlite"
|
||||
** spelled backwards. So the temp files are still identified, but
|
||||
** anybody smart enough to figure out the code is also likely smart
|
||||
** enough to know that calling the developer will not help get rid
|
||||
** of the file.
|
||||
*/
|
||||
#ifndef SQLITE_TEMP_FILE_PREFIX
|
||||
# define SQLITE_TEMP_FILE_PREFIX "etilqs_"
|
||||
#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
|
||||
|
||||
|
||||
/*
|
||||
** The following values may be passed as the second argument to
|
||||
** sqlite3OsLock(). The various locks exhibit the following semantics:
|
||||
**
|
||||
** SHARED: Any number of processes may hold a SHARED lock simultaneously.
|
||||
** RESERVED: A single process may hold a RESERVED lock on a file at
|
||||
** any time. Other processes may hold and obtain new SHARED locks.
|
||||
** PENDING: A single process may hold a PENDING lock on a file at
|
||||
** any one time. Existing SHARED locks may persist, but no new
|
||||
** SHARED locks may be obtained by other processes.
|
||||
** EXCLUSIVE: An EXCLUSIVE lock precludes all other locks.
|
||||
**
|
||||
** PENDING_LOCK may not be passed directly to sqlite3OsLock(). Instead, a
|
||||
** process that requests an EXCLUSIVE lock may actually obtain a PENDING
|
||||
** lock. This can be upgraded to an EXCLUSIVE lock by a subsequent call to
|
||||
** sqlite3OsLock().
|
||||
*/
|
||||
#define NO_LOCK 0
|
||||
#define SHARED_LOCK 1
|
||||
#define RESERVED_LOCK 2
|
||||
#define PENDING_LOCK 3
|
||||
#define EXCLUSIVE_LOCK 4
|
||||
|
||||
/*
|
||||
** File Locking Notes: (Mostly about windows but also some info for Unix)
|
||||
**
|
||||
** We cannot use LockFileEx() or UnlockFileEx() on Win95/98/ME because
|
||||
** those functions are not available. So we use only LockFile() and
|
||||
** UnlockFile().
|
||||
**
|
||||
** LockFile() prevents not just writing but also reading by other processes.
|
||||
** A SHARED_LOCK is obtained by locking a single randomly-chosen
|
||||
** byte out of a specific range of bytes. The lock byte is obtained at
|
||||
** random so two separate readers can probably access the file at the
|
||||
** same time, unless they are unlucky and choose the same lock byte.
|
||||
** An EXCLUSIVE_LOCK is obtained by locking all bytes in the range.
|
||||
** There can only be one writer. A RESERVED_LOCK is obtained by locking
|
||||
** a single byte of the file that is designated as the reserved lock byte.
|
||||
** A PENDING_LOCK is obtained by locking a designated byte different from
|
||||
** the RESERVED_LOCK byte.
|
||||
**
|
||||
** On WinNT/2K/XP systems, LockFileEx() and UnlockFileEx() are available,
|
||||
** which means we can use reader/writer locks. When reader/writer locks
|
||||
** are used, the lock is placed on the same range of bytes that is used
|
||||
** for probabilistic locking in Win95/98/ME. Hence, the locking scheme
|
||||
** will support two or more Win95 readers or two or more WinNT readers.
|
||||
** But a single Win95 reader will lock out all WinNT readers and a single
|
||||
** WinNT reader will lock out all other Win95 readers.
|
||||
**
|
||||
** The following #defines specify the range of bytes used for locking.
|
||||
** SHARED_SIZE is the number of bytes available in the pool from which
|
||||
** a random byte is selected for a shared lock. The pool of bytes for
|
||||
** shared locks begins at SHARED_FIRST.
|
||||
**
|
||||
** These #defines are available in sqlite_aux.h so that adaptors for
|
||||
** connecting SQLite to other operating systems can use the same byte
|
||||
** ranges for locking. In particular, the same locking strategy and
|
||||
** byte ranges are used for Unix. This leaves open the possiblity of having
|
||||
** clients on win95, winNT, and unix all talking to the same shared file
|
||||
** and all locking correctly. To do so would require that samba (or whatever
|
||||
** tool is being used for file sharing) implements locks correctly between
|
||||
** windows and unix. I'm guessing that isn't likely to happen, but by
|
||||
** using the same locking range we are at least open to the possibility.
|
||||
**
|
||||
** Locking in windows is manditory. For this reason, we cannot store
|
||||
** actual data in the bytes used for locking. The pager never allocates
|
||||
** the pages involved in locking therefore. SHARED_SIZE is selected so
|
||||
** that all locks will fit on a single page even at the minimum page size.
|
||||
** PENDING_BYTE defines the beginning of the locks. By default PENDING_BYTE
|
||||
** is set high so that we don't have to allocate an unused page except
|
||||
** for very large databases. But one should test the page skipping logic
|
||||
** by setting PENDING_BYTE low and running the entire regression suite.
|
||||
**
|
||||
** Changing the value of PENDING_BYTE results in a subtly incompatible
|
||||
** file format. Depending on how it is changed, you might not notice
|
||||
** the incompatibility right away, even running a full regression test.
|
||||
** The default location of PENDING_BYTE is the first byte past the
|
||||
** 1GB boundary.
|
||||
**
|
||||
*/
|
||||
#ifndef SQLITE_TEST
|
||||
#define PENDING_BYTE 0x40000000 /* First byte past the 1GB boundary */
|
||||
#else
|
||||
extern unsigned int sqlite3_pending_byte;
|
||||
#define PENDING_BYTE sqlite3_pending_byte
|
||||
#endif
|
||||
|
||||
#define RESERVED_BYTE (PENDING_BYTE+1)
|
||||
#define SHARED_FIRST (PENDING_BYTE+2)
|
||||
#define SHARED_SIZE 510
|
||||
|
||||
/*
|
||||
** Functions for accessing sqlite3_file methods
|
||||
*/
|
||||
int sqlite3OsClose(sqlite3_file*);
|
||||
int sqlite3OsRead(sqlite3_file*, void*, int amt, i64 offset);
|
||||
int sqlite3OsWrite(sqlite3_file*, const void*, int amt, i64 offset);
|
||||
int sqlite3OsTruncate(sqlite3_file*, i64 size);
|
||||
int sqlite3OsSync(sqlite3_file*, int);
|
||||
int sqlite3OsFileSize(sqlite3_file*, i64 *pSize);
|
||||
int sqlite3OsLock(sqlite3_file*, int);
|
||||
int sqlite3OsUnlock(sqlite3_file*, int);
|
||||
int sqlite3OsCheckReservedLock(sqlite3_file *id);
|
||||
int sqlite3OsFileControl(sqlite3_file*,int,void*);
|
||||
int sqlite3OsSectorSize(sqlite3_file *id);
|
||||
int sqlite3OsDeviceCharacteristics(sqlite3_file *id);
|
||||
|
||||
/*
|
||||
** Functions for accessing sqlite3_vfs methods
|
||||
*/
|
||||
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 sqlite3OsGetTempname(sqlite3_vfs *, int, char *);
|
||||
int sqlite3OsFullPathname(sqlite3_vfs *, const char *, int, char *);
|
||||
void *sqlite3OsDlOpen(sqlite3_vfs *, const char *);
|
||||
void sqlite3OsDlError(sqlite3_vfs *, int, char *);
|
||||
void *sqlite3OsDlSym(sqlite3_vfs *, void *, const char *);
|
||||
void sqlite3OsDlClose(sqlite3_vfs *, void *);
|
||||
int sqlite3OsRandomness(sqlite3_vfs *, int, char *);
|
||||
int sqlite3OsSleep(sqlite3_vfs *, int);
|
||||
int sqlite3OsCurrentTime(sqlite3_vfs *, double*);
|
||||
|
||||
/*
|
||||
** Convenience functions for opening and closing files using
|
||||
** sqlite3_malloc() to obtain space for the file-handle structure.
|
||||
*/
|
||||
int sqlite3OsOpenMalloc(sqlite3_vfs *, const char *, sqlite3_file **, int,int*);
|
||||
int sqlite3OsCloseFree(sqlite3_file *);
|
||||
|
||||
/*
|
||||
** Each OS-specific backend defines an instance of the following
|
||||
** structure for returning a pointer to its sqlite3_vfs. If OS_OTHER
|
||||
** is defined (meaning that the application-defined OS interface layer
|
||||
** is used) then there is no default VFS. The application must
|
||||
** register one or more VFS structures using sqlite3_vfs_register()
|
||||
** before attempting to use SQLite.
|
||||
*/
|
||||
#if OS_UNIX || OS_WIN || OS_OS2
|
||||
sqlite3_vfs *sqlite3OsDefaultVfs(void);
|
||||
#else
|
||||
# define sqlite3OsDefaultVfs(X) 0
|
||||
#endif
|
||||
|
||||
#endif /* _SQLITE_OS_H_ */
|
|
@ -0,0 +1,127 @@
|
|||
/*
|
||||
** 2004 May 22
|
||||
**
|
||||
** The author disclaims copyright to this source code. In place of
|
||||
** a legal notice, here is a blessing:
|
||||
**
|
||||
** May you do good and not evil.
|
||||
** May you find forgiveness for yourself and forgive others.
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
******************************************************************************
|
||||
**
|
||||
** This file contains macros and a little bit of code that is common to
|
||||
** all of the platform-specific files (os_*.c) and is #included into those
|
||||
** files.
|
||||
**
|
||||
** This file should be #included by the os_*.c files only. It is not a
|
||||
** general purpose header file.
|
||||
*/
|
||||
|
||||
/*
|
||||
** At least two bugs have slipped in because we changed the MEMORY_DEBUG
|
||||
** macro to SQLITE_DEBUG and some older makefiles have not yet made the
|
||||
** switch. The following code should catch this problem at compile-time.
|
||||
*/
|
||||
#ifdef MEMORY_DEBUG
|
||||
# error "The MEMORY_DEBUG macro is obsolete. Use SQLITE_DEBUG instead."
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* When testing, this global variable stores the location of the
|
||||
* pending-byte in the database file.
|
||||
*/
|
||||
#ifdef SQLITE_TEST
|
||||
unsigned int sqlite3_pending_byte = 0x40000000;
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_DEBUG
|
||||
int sqlite3_os_trace = 0;
|
||||
#define OSTRACE1(X) if( sqlite3_os_trace ) sqlite3DebugPrintf(X)
|
||||
#define OSTRACE2(X,Y) if( sqlite3_os_trace ) sqlite3DebugPrintf(X,Y)
|
||||
#define OSTRACE3(X,Y,Z) if( sqlite3_os_trace ) sqlite3DebugPrintf(X,Y,Z)
|
||||
#define OSTRACE4(X,Y,Z,A) if( sqlite3_os_trace ) sqlite3DebugPrintf(X,Y,Z,A)
|
||||
#define OSTRACE5(X,Y,Z,A,B) if( sqlite3_os_trace ) sqlite3DebugPrintf(X,Y,Z,A,B)
|
||||
#define OSTRACE6(X,Y,Z,A,B,C) \
|
||||
if(sqlite3_os_trace) sqlite3DebugPrintf(X,Y,Z,A,B,C)
|
||||
#define OSTRACE7(X,Y,Z,A,B,C,D) \
|
||||
if(sqlite3_os_trace) sqlite3DebugPrintf(X,Y,Z,A,B,C,D)
|
||||
#else
|
||||
#define OSTRACE1(X)
|
||||
#define OSTRACE2(X,Y)
|
||||
#define OSTRACE3(X,Y,Z)
|
||||
#define OSTRACE4(X,Y,Z,A)
|
||||
#define OSTRACE5(X,Y,Z,A,B)
|
||||
#define OSTRACE6(X,Y,Z,A,B,C)
|
||||
#define OSTRACE7(X,Y,Z,A,B,C,D)
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Macros for performance tracing. Normally turned off. Only works
|
||||
** on i486 hardware.
|
||||
*/
|
||||
#ifdef SQLITE_PERFORMANCE_TRACE
|
||||
__inline__ unsigned long long int hwtime(void){
|
||||
unsigned long long int x;
|
||||
__asm__("rdtsc\n\t"
|
||||
"mov %%edx, %%ecx\n\t"
|
||||
:"=A" (x));
|
||||
return x;
|
||||
}
|
||||
static unsigned long long int g_start;
|
||||
static unsigned int elapse;
|
||||
#define TIMER_START g_start=hwtime()
|
||||
#define TIMER_END elapse=hwtime()-g_start
|
||||
#define TIMER_ELAPSED elapse
|
||||
#else
|
||||
#define TIMER_START
|
||||
#define TIMER_END
|
||||
#define TIMER_ELAPSED 0
|
||||
#endif
|
||||
|
||||
/*
|
||||
** If we compile with the SQLITE_TEST macro set, then the following block
|
||||
** of code will give us the ability to simulate a disk I/O error. This
|
||||
** is used for testing the I/O recovery logic.
|
||||
*/
|
||||
#ifdef SQLITE_TEST
|
||||
int sqlite3_io_error_hit = 0;
|
||||
int sqlite3_io_error_pending = 0;
|
||||
int sqlite3_io_error_persist = 0;
|
||||
int sqlite3_diskfull_pending = 0;
|
||||
int sqlite3_diskfull = 0;
|
||||
#define SimulateIOError(CODE) \
|
||||
if( sqlite3_io_error_pending || sqlite3_io_error_hit ) \
|
||||
if( sqlite3_io_error_pending-- == 1 \
|
||||
|| (sqlite3_io_error_persist && sqlite3_io_error_hit) ) \
|
||||
{ local_ioerr(); CODE; }
|
||||
static void local_ioerr(){
|
||||
IOTRACE(("IOERR\n"));
|
||||
sqlite3_io_error_hit = 1;
|
||||
}
|
||||
#define SimulateDiskfullError(CODE) \
|
||||
if( sqlite3_diskfull_pending ){ \
|
||||
if( sqlite3_diskfull_pending == 1 ){ \
|
||||
local_ioerr(); \
|
||||
sqlite3_diskfull = 1; \
|
||||
sqlite3_io_error_hit = 1; \
|
||||
CODE; \
|
||||
}else{ \
|
||||
sqlite3_diskfull_pending--; \
|
||||
} \
|
||||
}
|
||||
#else
|
||||
#define SimulateIOError(A)
|
||||
#define SimulateDiskfullError(A)
|
||||
#endif
|
||||
|
||||
/*
|
||||
** When testing, keep a count of the number of open files.
|
||||
*/
|
||||
#ifdef SQLITE_TEST
|
||||
int sqlite3_open_file_count = 0;
|
||||
#define OpenCounter(X) sqlite3_open_file_count+=(X)
|
||||
#else
|
||||
#define OpenCounter(X)
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,125 @@
|
|||
/*
|
||||
** 2001 September 15
|
||||
**
|
||||
** The author disclaims copyright to this source code. In place of
|
||||
** a legal notice, here is a blessing:
|
||||
**
|
||||
** May you do good and not evil.
|
||||
** May you find forgiveness for yourself and forgive others.
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
*************************************************************************
|
||||
** This header file defines the interface that the sqlite page cache
|
||||
** subsystem. The page cache subsystem reads and writes a file a page
|
||||
** at a time and provides a journal for rollback.
|
||||
**
|
||||
** @(#) $Id: pager.h,v 1.67 2007/09/03 15:19:35 drh Exp $
|
||||
*/
|
||||
|
||||
#ifndef _PAGER_H_
|
||||
#define _PAGER_H_
|
||||
|
||||
/*
|
||||
** 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".
|
||||
*/
|
||||
typedef unsigned int Pgno;
|
||||
|
||||
/*
|
||||
** Each open file is managed by a separate instance of the "Pager" structure.
|
||||
*/
|
||||
typedef struct Pager Pager;
|
||||
|
||||
/*
|
||||
** Handle type for pages.
|
||||
*/
|
||||
typedef struct PgHdr DbPage;
|
||||
|
||||
/*
|
||||
** Allowed values for the flags parameter to sqlite3PagerOpen().
|
||||
**
|
||||
** NOTE: This values must match the corresponding BTREE_ values in btree.h.
|
||||
*/
|
||||
#define PAGER_OMIT_JOURNAL 0x0001 /* Do not use a rollback journal */
|
||||
#define PAGER_NO_READLOCK 0x0002 /* Omit readlocks on readonly files */
|
||||
|
||||
/*
|
||||
** Valid values for the second argument to sqlite3PagerLockingMode().
|
||||
*/
|
||||
#define PAGER_LOCKINGMODE_QUERY -1
|
||||
#define PAGER_LOCKINGMODE_NORMAL 0
|
||||
#define PAGER_LOCKINGMODE_EXCLUSIVE 1
|
||||
|
||||
/*
|
||||
** See source code comments for a detailed description of the following
|
||||
** routines:
|
||||
*/
|
||||
int sqlite3PagerOpen(sqlite3_vfs *, Pager **ppPager, const char*, int,int,int);
|
||||
void sqlite3PagerSetBusyhandler(Pager*, BusyHandler *pBusyHandler);
|
||||
void sqlite3PagerSetDestructor(Pager*, void(*)(DbPage*,int));
|
||||
void sqlite3PagerSetReiniter(Pager*, void(*)(DbPage*,int));
|
||||
int sqlite3PagerSetPagesize(Pager*, u16*);
|
||||
int sqlite3PagerMaxPageCount(Pager*, int);
|
||||
int sqlite3PagerReadFileheader(Pager*, int, unsigned char*);
|
||||
void sqlite3PagerSetCachesize(Pager*, int);
|
||||
int sqlite3PagerClose(Pager *pPager);
|
||||
int sqlite3PagerAcquire(Pager *pPager, Pgno pgno, DbPage **ppPage, int clrFlag);
|
||||
#define sqlite3PagerGet(A,B,C) sqlite3PagerAcquire(A,B,C,0)
|
||||
DbPage *sqlite3PagerLookup(Pager *pPager, Pgno pgno);
|
||||
int sqlite3PagerRef(DbPage*);
|
||||
int sqlite3PagerUnref(DbPage*);
|
||||
int sqlite3PagerWrite(DbPage*);
|
||||
int sqlite3PagerOverwrite(Pager *pPager, Pgno pgno, void*);
|
||||
int sqlite3PagerPagecount(Pager*);
|
||||
int sqlite3PagerTruncate(Pager*,Pgno);
|
||||
int sqlite3PagerBegin(DbPage*, int exFlag);
|
||||
int sqlite3PagerCommitPhaseOne(Pager*,const char *zMaster, Pgno);
|
||||
int sqlite3PagerCommitPhaseTwo(Pager*);
|
||||
int sqlite3PagerRollback(Pager*);
|
||||
int sqlite3PagerIsreadonly(Pager*);
|
||||
int sqlite3PagerStmtBegin(Pager*);
|
||||
int sqlite3PagerStmtCommit(Pager*);
|
||||
int sqlite3PagerStmtRollback(Pager*);
|
||||
void sqlite3PagerDontRollback(DbPage*);
|
||||
void sqlite3PagerDontWrite(DbPage*);
|
||||
int sqlite3PagerRefcount(Pager*);
|
||||
void sqlite3PagerSetSafetyLevel(Pager*,int,int);
|
||||
const char *sqlite3PagerFilename(Pager*);
|
||||
const sqlite3_vfs *sqlite3PagerVfs(Pager*);
|
||||
sqlite3_file *sqlite3PagerFile(Pager*);
|
||||
const char *sqlite3PagerDirname(Pager*);
|
||||
const char *sqlite3PagerJournalname(Pager*);
|
||||
int sqlite3PagerNosync(Pager*);
|
||||
int sqlite3PagerMovepage(Pager*,DbPage*,Pgno);
|
||||
void *sqlite3PagerGetData(DbPage *);
|
||||
void *sqlite3PagerGetExtra(DbPage *);
|
||||
int sqlite3PagerLockingMode(Pager *, int);
|
||||
|
||||
#if defined(SQLITE_ENABLE_MEMORY_MANAGEMENT) && !defined(SQLITE_OMIT_DISKIO)
|
||||
int sqlite3PagerReleaseMemory(int);
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_HAS_CODEC
|
||||
void sqlite3PagerSetCodec(Pager*,void*(*)(void*,void*,Pgno,int),void*);
|
||||
#endif
|
||||
|
||||
#if !defined(NDEBUG) || defined(SQLITE_TEST)
|
||||
Pgno sqlite3PagerPagenumber(DbPage*);
|
||||
int sqlite3PagerIswriteable(DbPage*);
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_TEST
|
||||
int *sqlite3PagerStats(Pager*);
|
||||
void sqlite3PagerRefdump(Pager*);
|
||||
int pager3_refinfo_enable;
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_TEST
|
||||
void disable_simulated_io_errors(void);
|
||||
void enable_simulated_io_errors(void);
|
||||
#else
|
||||
# define disable_simulated_io_errors()
|
||||
# define enable_simulated_io_errors()
|
||||
#endif
|
||||
|
||||
#endif /* _PAGER_H_ */
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,152 @@
|
|||
#define TK_SEMI 1
|
||||
#define TK_EXPLAIN 2
|
||||
#define TK_QUERY 3
|
||||
#define TK_PLAN 4
|
||||
#define TK_BEGIN 5
|
||||
#define TK_TRANSACTION 6
|
||||
#define TK_DEFERRED 7
|
||||
#define TK_IMMEDIATE 8
|
||||
#define TK_EXCLUSIVE 9
|
||||
#define TK_COMMIT 10
|
||||
#define TK_END 11
|
||||
#define TK_ROLLBACK 12
|
||||
#define TK_CREATE 13
|
||||
#define TK_TABLE 14
|
||||
#define TK_IF 15
|
||||
#define TK_NOT 16
|
||||
#define TK_EXISTS 17
|
||||
#define TK_TEMP 18
|
||||
#define TK_LP 19
|
||||
#define TK_RP 20
|
||||
#define TK_AS 21
|
||||
#define TK_COMMA 22
|
||||
#define TK_ID 23
|
||||
#define TK_ABORT 24
|
||||
#define TK_AFTER 25
|
||||
#define TK_ANALYZE 26
|
||||
#define TK_ASC 27
|
||||
#define TK_ATTACH 28
|
||||
#define TK_BEFORE 29
|
||||
#define TK_CASCADE 30
|
||||
#define TK_CAST 31
|
||||
#define TK_CONFLICT 32
|
||||
#define TK_DATABASE 33
|
||||
#define TK_DESC 34
|
||||
#define TK_DETACH 35
|
||||
#define TK_EACH 36
|
||||
#define TK_FAIL 37
|
||||
#define TK_FOR 38
|
||||
#define TK_IGNORE 39
|
||||
#define TK_INITIALLY 40
|
||||
#define TK_INSTEAD 41
|
||||
#define TK_LIKE_KW 42
|
||||
#define TK_MATCH 43
|
||||
#define TK_KEY 44
|
||||
#define TK_OF 45
|
||||
#define TK_OFFSET 46
|
||||
#define TK_PRAGMA 47
|
||||
#define TK_RAISE 48
|
||||
#define TK_REPLACE 49
|
||||
#define TK_RESTRICT 50
|
||||
#define TK_ROW 51
|
||||
#define TK_TRIGGER 52
|
||||
#define TK_VACUUM 53
|
||||
#define TK_VIEW 54
|
||||
#define TK_VIRTUAL 55
|
||||
#define TK_REINDEX 56
|
||||
#define TK_RENAME 57
|
||||
#define TK_CTIME_KW 58
|
||||
#define TK_ANY 59
|
||||
#define TK_OR 60
|
||||
#define TK_AND 61
|
||||
#define TK_IS 62
|
||||
#define TK_BETWEEN 63
|
||||
#define TK_IN 64
|
||||
#define TK_ISNULL 65
|
||||
#define TK_NOTNULL 66
|
||||
#define TK_NE 67
|
||||
#define TK_EQ 68
|
||||
#define TK_GT 69
|
||||
#define TK_LE 70
|
||||
#define TK_LT 71
|
||||
#define TK_GE 72
|
||||
#define TK_ESCAPE 73
|
||||
#define TK_BITAND 74
|
||||
#define TK_BITOR 75
|
||||
#define TK_LSHIFT 76
|
||||
#define TK_RSHIFT 77
|
||||
#define TK_PLUS 78
|
||||
#define TK_MINUS 79
|
||||
#define TK_STAR 80
|
||||
#define TK_SLASH 81
|
||||
#define TK_REM 82
|
||||
#define TK_CONCAT 83
|
||||
#define TK_COLLATE 84
|
||||
#define TK_UMINUS 85
|
||||
#define TK_UPLUS 86
|
||||
#define TK_BITNOT 87
|
||||
#define TK_STRING 88
|
||||
#define TK_JOIN_KW 89
|
||||
#define TK_CONSTRAINT 90
|
||||
#define TK_DEFAULT 91
|
||||
#define TK_NULL 92
|
||||
#define TK_PRIMARY 93
|
||||
#define TK_UNIQUE 94
|
||||
#define TK_CHECK 95
|
||||
#define TK_REFERENCES 96
|
||||
#define TK_AUTOINCR 97
|
||||
#define TK_ON 98
|
||||
#define TK_DELETE 99
|
||||
#define TK_UPDATE 100
|
||||
#define TK_INSERT 101
|
||||
#define TK_SET 102
|
||||
#define TK_DEFERRABLE 103
|
||||
#define TK_FOREIGN 104
|
||||
#define TK_DROP 105
|
||||
#define TK_UNION 106
|
||||
#define TK_ALL 107
|
||||
#define TK_EXCEPT 108
|
||||
#define TK_INTERSECT 109
|
||||
#define TK_SELECT 110
|
||||
#define TK_DISTINCT 111
|
||||
#define TK_DOT 112
|
||||
#define TK_FROM 113
|
||||
#define TK_JOIN 114
|
||||
#define TK_USING 115
|
||||
#define TK_ORDER 116
|
||||
#define TK_BY 117
|
||||
#define TK_GROUP 118
|
||||
#define TK_HAVING 119
|
||||
#define TK_LIMIT 120
|
||||
#define TK_WHERE 121
|
||||
#define TK_INTO 122
|
||||
#define TK_VALUES 123
|
||||
#define TK_INTEGER 124
|
||||
#define TK_FLOAT 125
|
||||
#define TK_BLOB 126
|
||||
#define TK_REGISTER 127
|
||||
#define TK_VARIABLE 128
|
||||
#define TK_CASE 129
|
||||
#define TK_WHEN 130
|
||||
#define TK_THEN 131
|
||||
#define TK_ELSE 132
|
||||
#define TK_INDEX 133
|
||||
#define TK_ALTER 134
|
||||
#define TK_TO 135
|
||||
#define TK_ADD 136
|
||||
#define TK_COLUMNKW 137
|
||||
#define TK_TO_TEXT 138
|
||||
#define TK_TO_BLOB 139
|
||||
#define TK_TO_NUMERIC 140
|
||||
#define TK_TO_INT 141
|
||||
#define TK_TO_REAL 142
|
||||
#define TK_END_OF_FILE 143
|
||||
#define TK_ILLEGAL 144
|
||||
#define TK_SPACE 145
|
||||
#define TK_UNCLOSED_STRING 146
|
||||
#define TK_COMMENT 147
|
||||
#define TK_FUNCTION 148
|
||||
#define TK_COLUMN 149
|
||||
#define TK_AGG_FUNCTION 150
|
||||
#define TK_AGG_COLUMN 151
|
||||
#define TK_CONST_FUNC 152
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,742 @@
|
|||
/*
|
||||
** 2005 May 25
|
||||
**
|
||||
** 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 implementation of the sqlite3_prepare()
|
||||
** interface, and routines that contribute to loading the database schema
|
||||
** from disk.
|
||||
**
|
||||
** $Id: prepare.c,v 1.61 2007/10/03 08:46:45 danielk1977 Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include <ctype.h>
|
||||
|
||||
/*
|
||||
** Fill the InitData structure with an error message that indicates
|
||||
** that the database is corrupt.
|
||||
*/
|
||||
static void corruptSchema(InitData *pData, const char *zExtra){
|
||||
if( !pData->db->mallocFailed ){
|
||||
sqlite3SetString(pData->pzErrMsg, "malformed database schema",
|
||||
zExtra!=0 && zExtra[0]!=0 ? " - " : (char*)0, zExtra, (char*)0);
|
||||
}
|
||||
pData->rc = SQLITE_CORRUPT;
|
||||
}
|
||||
|
||||
/*
|
||||
** This is the callback routine for the code that initializes the
|
||||
** database. See sqlite3Init() below for additional information.
|
||||
** This routine is also called from the OP_ParseSchema opcode of the VDBE.
|
||||
**
|
||||
** Each callback contains the following information:
|
||||
**
|
||||
** argv[0] = name of thing being created
|
||||
** argv[1] = root page number for table or index. 0 for trigger or view.
|
||||
** argv[2] = SQL text for the CREATE statement.
|
||||
**
|
||||
*/
|
||||
int sqlite3InitCallback(void *pInit, int argc, char **argv, char **azColName){
|
||||
InitData *pData = (InitData*)pInit;
|
||||
sqlite3 *db = pData->db;
|
||||
int iDb = pData->iDb;
|
||||
|
||||
assert( sqlite3_mutex_held(db->mutex) );
|
||||
pData->rc = SQLITE_OK;
|
||||
DbClearProperty(db, iDb, DB_Empty);
|
||||
if( db->mallocFailed ){
|
||||
corruptSchema(pData, 0);
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
|
||||
assert( argc==3 );
|
||||
if( argv==0 ) return 0; /* Might happen if EMPTY_RESULT_CALLBACKS are on */
|
||||
if( argv[1]==0 ){
|
||||
corruptSchema(pData, 0);
|
||||
return 1;
|
||||
}
|
||||
assert( iDb>=0 && iDb<db->nDb );
|
||||
if( argv[2] && argv[2][0] ){
|
||||
/* 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
|
||||
** or executed. All the parser does is build the internal data
|
||||
** structures that describe the table, index, or view.
|
||||
*/
|
||||
char *zErr;
|
||||
int rc;
|
||||
assert( db->init.busy );
|
||||
db->init.iDb = iDb;
|
||||
db->init.newTnum = atoi(argv[1]);
|
||||
rc = sqlite3_exec(db, argv[2], 0, 0, &zErr);
|
||||
db->init.iDb = 0;
|
||||
assert( rc!=SQLITE_OK || zErr==0 );
|
||||
if( SQLITE_OK!=rc ){
|
||||
pData->rc = rc;
|
||||
if( rc==SQLITE_NOMEM ){
|
||||
db->mallocFailed = 1;
|
||||
}else if( rc!=SQLITE_INTERRUPT ){
|
||||
corruptSchema(pData, zErr);
|
||||
}
|
||||
sqlite3_free(zErr);
|
||||
return 1;
|
||||
}
|
||||
}else{
|
||||
/* 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
|
||||
** constraint for a CREATE TABLE. The index should have already
|
||||
** been created when we processed the CREATE TABLE. All we have
|
||||
** to do here is record the root page number for that index.
|
||||
*/
|
||||
Index *pIndex;
|
||||
pIndex = sqlite3FindIndex(db, argv[0], db->aDb[iDb].zName);
|
||||
if( pIndex==0 || pIndex->tnum!=0 ){
|
||||
/* This can occur if there exists an index on a TEMP table which
|
||||
** has the same name as another index on a permanent index. Since
|
||||
** the permanent table is hidden by the TEMP table, we can also
|
||||
** safely ignore the index on the permanent table.
|
||||
*/
|
||||
/* Do Nothing */;
|
||||
}else{
|
||||
pIndex->tnum = atoi(argv[1]);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Attempt to read the database schema and initialize internal
|
||||
** data structures for a single database file. The index of the
|
||||
** database file is given by iDb. iDb==0 is used for the main
|
||||
** database. iDb==1 should never be used. iDb>=2 is used for
|
||||
** auxiliary databases. Return one of the SQLITE_ error codes to
|
||||
** indicate success or failure.
|
||||
*/
|
||||
static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
|
||||
int rc;
|
||||
BtCursor *curMain;
|
||||
int size;
|
||||
Table *pTab;
|
||||
Db *pDb;
|
||||
char const *azArg[4];
|
||||
int meta[10];
|
||||
InitData initData;
|
||||
char const *zMasterSchema;
|
||||
char const *zMasterName = SCHEMA_TABLE(iDb);
|
||||
|
||||
/*
|
||||
** The master database table has a structure like this
|
||||
*/
|
||||
static const char master_schema[] =
|
||||
"CREATE TABLE sqlite_master(\n"
|
||||
" type text,\n"
|
||||
" name text,\n"
|
||||
" tbl_name text,\n"
|
||||
" rootpage integer,\n"
|
||||
" sql text\n"
|
||||
")"
|
||||
;
|
||||
#ifndef SQLITE_OMIT_TEMPDB
|
||||
static const char temp_master_schema[] =
|
||||
"CREATE TEMP TABLE sqlite_temp_master(\n"
|
||||
" type text,\n"
|
||||
" name text,\n"
|
||||
" tbl_name text,\n"
|
||||
" rootpage integer,\n"
|
||||
" sql text\n"
|
||||
")"
|
||||
;
|
||||
#else
|
||||
#define temp_master_schema 0
|
||||
#endif
|
||||
|
||||
assert( iDb>=0 && iDb<db->nDb );
|
||||
assert( db->aDb[iDb].pSchema );
|
||||
assert( sqlite3_mutex_held(db->mutex) );
|
||||
|
||||
/* zMasterSchema and zInitScript are set to point at the master schema
|
||||
** and initialisation script appropriate for the database being
|
||||
** initialised. zMasterName is the name of the master table.
|
||||
*/
|
||||
if( !OMIT_TEMPDB && iDb==1 ){
|
||||
zMasterSchema = temp_master_schema;
|
||||
}else{
|
||||
zMasterSchema = master_schema;
|
||||
}
|
||||
zMasterName = SCHEMA_TABLE(iDb);
|
||||
|
||||
/* Construct the schema tables. */
|
||||
sqlite3SafetyOff(db);
|
||||
azArg[0] = zMasterName;
|
||||
azArg[1] = "1";
|
||||
azArg[2] = zMasterSchema;
|
||||
azArg[3] = 0;
|
||||
initData.db = db;
|
||||
initData.iDb = iDb;
|
||||
initData.pzErrMsg = pzErrMsg;
|
||||
rc = sqlite3InitCallback(&initData, 3, (char **)azArg, 0);
|
||||
if( rc ){
|
||||
sqlite3SafetyOn(db);
|
||||
rc = initData.rc;
|
||||
goto error_out;
|
||||
}
|
||||
pTab = sqlite3FindTable(db, zMasterName, db->aDb[iDb].zName);
|
||||
if( pTab ){
|
||||
pTab->readOnly = 1;
|
||||
}
|
||||
sqlite3SafetyOn(db);
|
||||
|
||||
/* Create a cursor to hold the database open
|
||||
*/
|
||||
pDb = &db->aDb[iDb];
|
||||
if( pDb->pBt==0 ){
|
||||
if( !OMIT_TEMPDB && iDb==1 ){
|
||||
DbSetProperty(db, 1, DB_SchemaLoaded);
|
||||
}
|
||||
return SQLITE_OK;
|
||||
}
|
||||
sqlite3BtreeEnter(pDb->pBt);
|
||||
rc = sqlite3BtreeCursor(pDb->pBt, MASTER_ROOT, 0, 0, 0, &curMain);
|
||||
if( rc!=SQLITE_OK && rc!=SQLITE_EMPTY ){
|
||||
sqlite3SetString(pzErrMsg, sqlite3ErrStr(rc), (char*)0);
|
||||
sqlite3BtreeLeave(pDb->pBt);
|
||||
goto error_out;
|
||||
}
|
||||
|
||||
/* Get the database meta information.
|
||||
**
|
||||
** Meta values are as follows:
|
||||
** meta[0] Schema cookie. Changes with each schema change.
|
||||
** meta[1] File format of schema layer.
|
||||
** meta[2] Size of the page cache.
|
||||
** meta[3] Use freelist if 0. Autovacuum if greater than zero.
|
||||
** meta[4] Db text encoding. 1:UTF-8 2:UTF-16LE 3:UTF-16BE
|
||||
** meta[5] The user cookie. Used by the application.
|
||||
** meta[6] Incremental-vacuum flag.
|
||||
** meta[7]
|
||||
** meta[8]
|
||||
** meta[9]
|
||||
**
|
||||
** Note: The #defined SQLITE_UTF* symbols in sqliteInt.h correspond to
|
||||
** the possible values of meta[4].
|
||||
*/
|
||||
if( rc==SQLITE_OK ){
|
||||
int i;
|
||||
for(i=0; rc==SQLITE_OK && i<sizeof(meta)/sizeof(meta[0]); i++){
|
||||
rc = sqlite3BtreeGetMeta(pDb->pBt, i+1, (u32 *)&meta[i]);
|
||||
}
|
||||
if( rc ){
|
||||
sqlite3SetString(pzErrMsg, sqlite3ErrStr(rc), (char*)0);
|
||||
sqlite3BtreeCloseCursor(curMain);
|
||||
sqlite3BtreeLeave(pDb->pBt);
|
||||
goto error_out;
|
||||
}
|
||||
}else{
|
||||
memset(meta, 0, sizeof(meta));
|
||||
}
|
||||
pDb->pSchema->schema_cookie = meta[0];
|
||||
|
||||
/* If opening a non-empty database, check the text encoding. For the
|
||||
** main database, set sqlite3.enc to the encoding of the main database.
|
||||
** For an attached db, it is an error if the encoding is not the same
|
||||
** as sqlite3.enc.
|
||||
*/
|
||||
if( meta[4] ){ /* text encoding */
|
||||
if( iDb==0 ){
|
||||
/* If opening the main database, set ENC(db). */
|
||||
ENC(db) = (u8)meta[4];
|
||||
db->pDfltColl = sqlite3FindCollSeq(db, SQLITE_UTF8, "BINARY", 6, 0);
|
||||
}else{
|
||||
/* If opening an attached database, the encoding much match ENC(db) */
|
||||
if( meta[4]!=ENC(db) ){
|
||||
sqlite3BtreeCloseCursor(curMain);
|
||||
sqlite3SetString(pzErrMsg, "attached databases must use the same"
|
||||
" text encoding as main database", (char*)0);
|
||||
sqlite3BtreeLeave(pDb->pBt);
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
}
|
||||
}else{
|
||||
DbSetProperty(db, iDb, DB_Empty);
|
||||
}
|
||||
pDb->pSchema->enc = ENC(db);
|
||||
|
||||
size = meta[2];
|
||||
if( size==0 ){ size = SQLITE_DEFAULT_CACHE_SIZE; }
|
||||
pDb->pSchema->cache_size = size;
|
||||
sqlite3BtreeSetCacheSize(pDb->pBt, pDb->pSchema->cache_size);
|
||||
|
||||
/*
|
||||
** file_format==1 Version 3.0.0.
|
||||
** file_format==2 Version 3.1.3. // ALTER TABLE ADD COLUMN
|
||||
** file_format==3 Version 3.1.4. // ditto but with non-NULL defaults
|
||||
** file_format==4 Version 3.3.0. // DESC indices. Boolean constants
|
||||
*/
|
||||
pDb->pSchema->file_format = meta[1];
|
||||
if( pDb->pSchema->file_format==0 ){
|
||||
pDb->pSchema->file_format = 1;
|
||||
}
|
||||
if( pDb->pSchema->file_format>SQLITE_MAX_FILE_FORMAT ){
|
||||
sqlite3BtreeCloseCursor(curMain);
|
||||
sqlite3SetString(pzErrMsg, "unsupported file format", (char*)0);
|
||||
sqlite3BtreeLeave(pDb->pBt);
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
|
||||
|
||||
/* Read the schema information out of the schema tables
|
||||
*/
|
||||
assert( db->init.busy );
|
||||
if( rc==SQLITE_EMPTY ){
|
||||
/* For an empty database, there is nothing to read */
|
||||
rc = SQLITE_OK;
|
||||
}else{
|
||||
char *zSql;
|
||||
zSql = sqlite3MPrintf(db,
|
||||
"SELECT name, rootpage, sql FROM '%q'.%s",
|
||||
db->aDb[iDb].zName, zMasterName);
|
||||
sqlite3SafetyOff(db);
|
||||
rc = sqlite3_exec(db, zSql, sqlite3InitCallback, &initData, 0);
|
||||
if( rc==SQLITE_ABORT ) rc = initData.rc;
|
||||
sqlite3SafetyOn(db);
|
||||
sqlite3_free(zSql);
|
||||
#ifndef SQLITE_OMIT_ANALYZE
|
||||
if( rc==SQLITE_OK ){
|
||||
sqlite3AnalysisLoad(db, iDb);
|
||||
}
|
||||
#endif
|
||||
sqlite3BtreeCloseCursor(curMain);
|
||||
}
|
||||
if( db->mallocFailed ){
|
||||
/* sqlite3SetString(pzErrMsg, "out of memory", (char*)0); */
|
||||
rc = SQLITE_NOMEM;
|
||||
sqlite3ResetInternalSchema(db, 0);
|
||||
}
|
||||
if( rc==SQLITE_OK || (db->flags&SQLITE_RecoveryMode)){
|
||||
/* Black magic: If the SQLITE_RecoveryMode flag is set, then consider
|
||||
** the schema loaded, even if errors occured. In this situation the
|
||||
** current sqlite3_prepare() operation will fail, but the following one
|
||||
** will attempt to compile the supplied statement against whatever subset
|
||||
** of the schema was loaded before the error occured. The primary
|
||||
** purpose of this is to allow access to the sqlite_master table
|
||||
** even when it's contents have been corrupted.
|
||||
*/
|
||||
DbSetProperty(db, iDb, DB_SchemaLoaded);
|
||||
rc = SQLITE_OK;
|
||||
}
|
||||
sqlite3BtreeLeave(pDb->pBt);
|
||||
|
||||
error_out:
|
||||
if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ){
|
||||
db->mallocFailed = 1;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Initialize all database files - the main database file, the file
|
||||
** used to store temporary tables, and any additional database files
|
||||
** created using ATTACH statements. Return a success code. If an
|
||||
** error occurs, write an error message into *pzErrMsg.
|
||||
**
|
||||
** After a database is initialized, the DB_SchemaLoaded bit is set
|
||||
** bit is set in the flags field of the Db structure. If the database
|
||||
** file was of zero-length, then the DB_Empty flag is also set.
|
||||
*/
|
||||
int sqlite3Init(sqlite3 *db, char **pzErrMsg){
|
||||
int i, rc;
|
||||
int commit_internal = !(db->flags&SQLITE_InternChanges);
|
||||
|
||||
assert( sqlite3_mutex_held(db->mutex) );
|
||||
if( db->init.busy ) return SQLITE_OK;
|
||||
rc = SQLITE_OK;
|
||||
db->init.busy = 1;
|
||||
for(i=0; rc==SQLITE_OK && i<db->nDb; i++){
|
||||
if( DbHasProperty(db, i, DB_SchemaLoaded) || i==1 ) continue;
|
||||
rc = sqlite3InitOne(db, i, pzErrMsg);
|
||||
if( rc ){
|
||||
sqlite3ResetInternalSchema(db, i);
|
||||
}
|
||||
}
|
||||
|
||||
/* Once all the other databases have been initialised, load the schema
|
||||
** for the TEMP database. This is loaded last, as the TEMP database
|
||||
** schema may contain references to objects in other databases.
|
||||
*/
|
||||
#ifndef SQLITE_OMIT_TEMPDB
|
||||
if( rc==SQLITE_OK && db->nDb>1 && !DbHasProperty(db, 1, DB_SchemaLoaded) ){
|
||||
rc = sqlite3InitOne(db, 1, pzErrMsg);
|
||||
if( rc ){
|
||||
sqlite3ResetInternalSchema(db, 1);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
db->init.busy = 0;
|
||||
if( rc==SQLITE_OK && commit_internal ){
|
||||
sqlite3CommitInternalChanges(db);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** This routine is a no-op if the database schema is already initialised.
|
||||
** Otherwise, the schema is loaded. An error code is returned.
|
||||
*/
|
||||
int sqlite3ReadSchema(Parse *pParse){
|
||||
int rc = SQLITE_OK;
|
||||
sqlite3 *db = pParse->db;
|
||||
assert( sqlite3_mutex_held(db->mutex) );
|
||||
if( !db->init.busy ){
|
||||
rc = sqlite3Init(db, &pParse->zErrMsg);
|
||||
}
|
||||
if( rc!=SQLITE_OK ){
|
||||
pParse->rc = rc;
|
||||
pParse->nErr++;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Check schema cookies in all databases. If any cookie is out
|
||||
** of date, return 0. If all schema cookies are current, return 1.
|
||||
*/
|
||||
static int schemaIsValid(sqlite3 *db){
|
||||
int iDb;
|
||||
int rc;
|
||||
BtCursor *curTemp;
|
||||
int cookie;
|
||||
int allOk = 1;
|
||||
|
||||
assert( sqlite3_mutex_held(db->mutex) );
|
||||
for(iDb=0; allOk && iDb<db->nDb; iDb++){
|
||||
Btree *pBt;
|
||||
pBt = db->aDb[iDb].pBt;
|
||||
if( pBt==0 ) continue;
|
||||
rc = sqlite3BtreeCursor(pBt, MASTER_ROOT, 0, 0, 0, &curTemp);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3BtreeGetMeta(pBt, 1, (u32 *)&cookie);
|
||||
if( rc==SQLITE_OK && cookie!=db->aDb[iDb].pSchema->schema_cookie ){
|
||||
allOk = 0;
|
||||
}
|
||||
sqlite3BtreeCloseCursor(curTemp);
|
||||
}
|
||||
if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ){
|
||||
db->mallocFailed = 1;
|
||||
}
|
||||
}
|
||||
return allOk;
|
||||
}
|
||||
|
||||
/*
|
||||
** Convert a schema pointer into the iDb index that indicates
|
||||
** which database file in db->aDb[] the schema refers to.
|
||||
**
|
||||
** If the same database is attached more than once, the first
|
||||
** attached database is returned.
|
||||
*/
|
||||
int sqlite3SchemaToIndex(sqlite3 *db, Schema *pSchema){
|
||||
int i = -1000000;
|
||||
|
||||
/* If pSchema is NULL, then return -1000000. This happens when code in
|
||||
** expr.c is trying to resolve a reference to a transient table (i.e. one
|
||||
** created by a sub-select). In this case the return value of this
|
||||
** function should never be used.
|
||||
**
|
||||
** We return -1000000 instead of the more usual -1 simply because using
|
||||
** -1000000 as incorrectly using -1000000 index into db->aDb[] is much
|
||||
** more likely to cause a segfault than -1 (of course there are assert()
|
||||
** statements too, but it never hurts to play the odds).
|
||||
*/
|
||||
assert( sqlite3_mutex_held(db->mutex) );
|
||||
if( pSchema ){
|
||||
for(i=0; i<db->nDb; i++){
|
||||
if( db->aDb[i].pSchema==pSchema ){
|
||||
break;
|
||||
}
|
||||
}
|
||||
assert( i>=0 &&i>=0 && i<db->nDb );
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
/*
|
||||
** Compile the UTF-8 encoded SQL statement zSql into a statement handle.
|
||||
*/
|
||||
int sqlite3Prepare(
|
||||
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 */
|
||||
){
|
||||
Parse sParse;
|
||||
char *zErrMsg = 0;
|
||||
int rc = SQLITE_OK;
|
||||
int i;
|
||||
|
||||
assert( ppStmt );
|
||||
*ppStmt = 0;
|
||||
if( sqlite3SafetyOn(db) ){
|
||||
return SQLITE_MISUSE;
|
||||
}
|
||||
assert( !db->mallocFailed );
|
||||
assert( sqlite3_mutex_held(db->mutex) );
|
||||
|
||||
/* If any attached database schemas are locked, do not proceed with
|
||||
** compilation. Instead return SQLITE_LOCKED immediately.
|
||||
*/
|
||||
for(i=0; i<db->nDb; i++) {
|
||||
Btree *pBt = db->aDb[i].pBt;
|
||||
if( pBt ){
|
||||
int rc;
|
||||
rc = sqlite3BtreeSchemaLocked(pBt);
|
||||
if( rc ){
|
||||
const char *zDb = db->aDb[i].zName;
|
||||
sqlite3Error(db, SQLITE_LOCKED, "database schema is locked: %s", zDb);
|
||||
sqlite3SafetyOff(db);
|
||||
return SQLITE_LOCKED;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
memset(&sParse, 0, sizeof(sParse));
|
||||
sParse.db = db;
|
||||
if( nBytes>=0 && zSql[nBytes]!=0 ){
|
||||
char *zSqlCopy;
|
||||
if( nBytes>SQLITE_MAX_SQL_LENGTH ){
|
||||
return SQLITE_TOOBIG;
|
||||
}
|
||||
zSqlCopy = sqlite3DbStrNDup(db, zSql, nBytes);
|
||||
if( zSqlCopy ){
|
||||
sqlite3RunParser(&sParse, zSqlCopy, &zErrMsg);
|
||||
sqlite3_free(zSqlCopy);
|
||||
}
|
||||
sParse.zTail = &zSql[nBytes];
|
||||
}else{
|
||||
sqlite3RunParser(&sParse, zSql, &zErrMsg);
|
||||
}
|
||||
|
||||
if( db->mallocFailed ){
|
||||
sParse.rc = SQLITE_NOMEM;
|
||||
}
|
||||
if( sParse.rc==SQLITE_DONE ) sParse.rc = SQLITE_OK;
|
||||
if( sParse.checkSchema && !schemaIsValid(db) ){
|
||||
sParse.rc = SQLITE_SCHEMA;
|
||||
}
|
||||
if( sParse.rc==SQLITE_SCHEMA ){
|
||||
sqlite3ResetInternalSchema(db, 0);
|
||||
}
|
||||
if( db->mallocFailed ){
|
||||
sParse.rc = SQLITE_NOMEM;
|
||||
}
|
||||
if( pzTail ){
|
||||
*pzTail = sParse.zTail;
|
||||
}
|
||||
rc = sParse.rc;
|
||||
|
||||
#ifndef SQLITE_OMIT_EXPLAIN
|
||||
if( rc==SQLITE_OK && sParse.pVdbe && sParse.explain ){
|
||||
if( sParse.explain==2 ){
|
||||
sqlite3VdbeSetNumCols(sParse.pVdbe, 3);
|
||||
sqlite3VdbeSetColName(sParse.pVdbe, 0, COLNAME_NAME, "order", P3_STATIC);
|
||||
sqlite3VdbeSetColName(sParse.pVdbe, 1, COLNAME_NAME, "from", P3_STATIC);
|
||||
sqlite3VdbeSetColName(sParse.pVdbe, 2, COLNAME_NAME, "detail", P3_STATIC);
|
||||
}else{
|
||||
sqlite3VdbeSetNumCols(sParse.pVdbe, 5);
|
||||
sqlite3VdbeSetColName(sParse.pVdbe, 0, COLNAME_NAME, "addr", P3_STATIC);
|
||||
sqlite3VdbeSetColName(sParse.pVdbe, 1, COLNAME_NAME, "opcode", P3_STATIC);
|
||||
sqlite3VdbeSetColName(sParse.pVdbe, 2, COLNAME_NAME, "p1", P3_STATIC);
|
||||
sqlite3VdbeSetColName(sParse.pVdbe, 3, COLNAME_NAME, "p2", P3_STATIC);
|
||||
sqlite3VdbeSetColName(sParse.pVdbe, 4, COLNAME_NAME, "p3", P3_STATIC);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if( sqlite3SafetyOff(db) ){
|
||||
rc = SQLITE_MISUSE;
|
||||
}
|
||||
|
||||
if( saveSqlFlag ){
|
||||
sqlite3VdbeSetSql(sParse.pVdbe, zSql, sParse.zTail - zSql);
|
||||
}
|
||||
if( rc!=SQLITE_OK || db->mallocFailed ){
|
||||
sqlite3_finalize((sqlite3_stmt*)sParse.pVdbe);
|
||||
assert(!(*ppStmt));
|
||||
}else{
|
||||
*ppStmt = (sqlite3_stmt*)sParse.pVdbe;
|
||||
}
|
||||
|
||||
if( zErrMsg ){
|
||||
sqlite3Error(db, rc, "%s", zErrMsg);
|
||||
sqlite3_free(zErrMsg);
|
||||
}else{
|
||||
sqlite3Error(db, rc, 0);
|
||||
}
|
||||
|
||||
rc = sqlite3ApiExit(db, rc);
|
||||
/* sqlite3ReleaseThreadData(); */
|
||||
assert( (rc&db->errMask)==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( sqlite3SafetyCheck(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.
|
||||
** Return true if the statement was recompiled successfully.
|
||||
** Return false if there is an error of some kind.
|
||||
*/
|
||||
int sqlite3Reprepare(Vdbe *p){
|
||||
int rc;
|
||||
sqlite3_stmt *pNew;
|
||||
const char *zSql;
|
||||
sqlite3 *db;
|
||||
|
||||
assert( sqlite3_mutex_held(sqlite3VdbeDb(p)->mutex) );
|
||||
zSql = sqlite3VdbeGetSql(p);
|
||||
if( zSql==0 ){
|
||||
return 0;
|
||||
}
|
||||
db = sqlite3VdbeDb(p);
|
||||
assert( sqlite3_mutex_held(db->mutex) );
|
||||
rc = sqlite3LockAndPrepare(db, zSql, -1, 0, &pNew, 0);
|
||||
if( rc ){
|
||||
assert( pNew==0 );
|
||||
return 0;
|
||||
}else{
|
||||
assert( pNew!=0 );
|
||||
}
|
||||
sqlite3VdbeSwap((Vdbe*)pNew, p);
|
||||
sqlite3_transfer_bindings(pNew, (sqlite3_stmt*)p);
|
||||
sqlite3VdbeResetStepResult((Vdbe*)pNew);
|
||||
sqlite3VdbeFinalize((Vdbe*)pNew);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Two versions of the official API. Legacy and new use. In the legacy
|
||||
** version, the original SQL text is not saved in the prepared statement
|
||||
** and so if a schema change occurs, SQLITE_SCHEMA is returned by
|
||||
** sqlite3_step(). In the new version, the original SQL text is retained
|
||||
** and the statement is automatically recompiled if an schema change
|
||||
** occurs.
|
||||
*/
|
||||
int sqlite3_prepare(
|
||||
sqlite3 *db, /* Database handle. */
|
||||
const char *zSql, /* UTF-8 encoded SQL statement. */
|
||||
int nBytes, /* Length of zSql in bytes. */
|
||||
sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */
|
||||
const char **pzTail /* OUT: End of parsed string */
|
||||
){
|
||||
return sqlite3LockAndPrepare(db,zSql,nBytes,0,ppStmt,pzTail);
|
||||
}
|
||||
int sqlite3_prepare_v2(
|
||||
sqlite3 *db, /* Database handle. */
|
||||
const char *zSql, /* UTF-8 encoded SQL statement. */
|
||||
int nBytes, /* Length of zSql in bytes. */
|
||||
sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */
|
||||
const char **pzTail /* OUT: End of parsed string */
|
||||
){
|
||||
return sqlite3LockAndPrepare(db,zSql,nBytes,1,ppStmt,pzTail);
|
||||
}
|
||||
|
||||
|
||||
#ifndef SQLITE_OMIT_UTF16
|
||||
/*
|
||||
** Compile the UTF-16 encoded SQL statement zSql into a statement handle.
|
||||
*/
|
||||
static int sqlite3Prepare16(
|
||||
sqlite3 *db, /* Database handle. */
|
||||
const void *zSql, /* UTF-8 encoded SQL statement. */
|
||||
int nBytes, /* Length of zSql in bytes. */
|
||||
int saveSqlFlag, /* True to save SQL text into the sqlite3_stmt */
|
||||
sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */
|
||||
const void **pzTail /* OUT: End of parsed string */
|
||||
){
|
||||
/* This function currently works by first transforming the UTF-16
|
||||
** encoded string to UTF-8, then invoking sqlite3_prepare(). The
|
||||
** tricky bit is figuring out the pointer to return in *pzTail.
|
||||
*/
|
||||
char *zSql8;
|
||||
const char *zTail8 = 0;
|
||||
int rc = SQLITE_OK;
|
||||
|
||||
if( sqlite3SafetyCheck(db) ){
|
||||
return SQLITE_MISUSE;
|
||||
}
|
||||
sqlite3_mutex_enter(db->mutex);
|
||||
zSql8 = sqlite3Utf16to8(db, zSql, nBytes);
|
||||
if( zSql8 ){
|
||||
rc = sqlite3LockAndPrepare(db, zSql8, -1, saveSqlFlag, ppStmt, &zTail8);
|
||||
}
|
||||
|
||||
if( zTail8 && pzTail ){
|
||||
/* If sqlite3_prepare returns a tail pointer, we calculate the
|
||||
** equivalent pointer into the UTF-16 string by counting the unicode
|
||||
** characters between zSql8 and zTail8, and then returning a pointer
|
||||
** the same number of characters into the UTF-16 string.
|
||||
*/
|
||||
int chars_parsed = sqlite3Utf8CharLen(zSql8, zTail8-zSql8);
|
||||
*pzTail = (u8 *)zSql + sqlite3Utf16ByteLen(zSql, chars_parsed);
|
||||
}
|
||||
sqlite3_free(zSql8);
|
||||
rc = sqlite3ApiExit(db, rc);
|
||||
sqlite3_mutex_leave(db->mutex);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Two versions of the official API. Legacy and new use. In the legacy
|
||||
** version, the original SQL text is not saved in the prepared statement
|
||||
** and so if a schema change occurs, SQLITE_SCHEMA is returned by
|
||||
** sqlite3_step(). In the new version, the original SQL text is retained
|
||||
** and the statement is automatically recompiled if an schema change
|
||||
** occurs.
|
||||
*/
|
||||
int sqlite3_prepare16(
|
||||
sqlite3 *db, /* Database handle. */
|
||||
const void *zSql, /* UTF-8 encoded SQL statement. */
|
||||
int nBytes, /* Length of zSql in bytes. */
|
||||
sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */
|
||||
const void **pzTail /* OUT: End of parsed string */
|
||||
){
|
||||
return sqlite3Prepare16(db,zSql,nBytes,0,ppStmt,pzTail);
|
||||
}
|
||||
int sqlite3_prepare16_v2(
|
||||
sqlite3 *db, /* Database handle. */
|
||||
const void *zSql, /* UTF-8 encoded SQL statement. */
|
||||
int nBytes, /* Length of zSql in bytes. */
|
||||
sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */
|
||||
const void **pzTail /* OUT: End of parsed string */
|
||||
){
|
||||
return sqlite3Prepare16(db,zSql,nBytes,1,ppStmt,pzTail);
|
||||
}
|
||||
|
||||
#endif /* SQLITE_OMIT_UTF16 */
|
|
@ -0,0 +1,907 @@
|
|||
/*
|
||||
** The "printf" code that follows dates from the 1980's. It is in
|
||||
** the public domain. The original comments are included here for
|
||||
** completeness. They are very out-of-date but might be useful as
|
||||
** an historical reference. Most of the "enhancements" have been backed
|
||||
** out so that the functionality is now the same as standard printf().
|
||||
**
|
||||
**************************************************************************
|
||||
**
|
||||
** The following modules is an enhanced replacement for the "printf" subroutines
|
||||
** found in the standard C library. The following enhancements are
|
||||
** supported:
|
||||
**
|
||||
** + Additional functions. The standard set of "printf" functions
|
||||
** includes printf, fprintf, sprintf, vprintf, vfprintf, and
|
||||
** vsprintf. This module adds the following:
|
||||
**
|
||||
** * snprintf -- Works like sprintf, but has an extra argument
|
||||
** which is the size of the buffer written to.
|
||||
**
|
||||
** * mprintf -- Similar to sprintf. Writes output to memory
|
||||
** obtained from malloc.
|
||||
**
|
||||
** * xprintf -- Calls a function to dispose of output.
|
||||
**
|
||||
** * nprintf -- No output, but returns the number of characters
|
||||
** that would have been output by printf.
|
||||
**
|
||||
** * A v- version (ex: vsnprintf) of every function is also
|
||||
** supplied.
|
||||
**
|
||||
** + A few extensions to the formatting notation are supported:
|
||||
**
|
||||
** * The "=" flag (similar to "-") causes the output to be
|
||||
** be centered in the appropriately sized field.
|
||||
**
|
||||
** * The %b field outputs an integer in binary notation.
|
||||
**
|
||||
** * The %c field now accepts a precision. The character output
|
||||
** is repeated by the number of times the precision specifies.
|
||||
**
|
||||
** * The %' field works like %c, but takes as its character the
|
||||
** next character of the format string, instead of the next
|
||||
** argument. For example, printf("%.78'-") prints 78 minus
|
||||
** signs, the same as printf("%.78c",'-').
|
||||
**
|
||||
** + When compiled using GCC on a SPARC, this version of printf is
|
||||
** faster than the library printf for SUN OS 4.1.
|
||||
**
|
||||
** + All functions are fully reentrant.
|
||||
**
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include <math.h>
|
||||
|
||||
/*
|
||||
** Conversion types fall into various categories as defined by the
|
||||
** following enumeration.
|
||||
*/
|
||||
#define etRADIX 1 /* Integer types. %d, %x, %o, and so forth */
|
||||
#define etFLOAT 2 /* Floating point. %f */
|
||||
#define etEXP 3 /* Exponentional notation. %e and %E */
|
||||
#define etGENERIC 4 /* Floating or exponential, depending on exponent. %g */
|
||||
#define etSIZE 5 /* Return number of characters processed so far. %n */
|
||||
#define etSTRING 6 /* Strings. %s */
|
||||
#define etDYNSTRING 7 /* Dynamically allocated strings. %z */
|
||||
#define etPERCENT 8 /* Percent symbol. %% */
|
||||
#define etCHARX 9 /* Characters. %c */
|
||||
/* The rest are extensions, not normally found in printf() */
|
||||
#define etCHARLIT 10 /* Literal characters. %' */
|
||||
#define etSQLESCAPE 11 /* Strings with '\'' doubled. %q */
|
||||
#define etSQLESCAPE2 12 /* Strings with '\'' doubled and enclosed in '',
|
||||
NULL pointers replaced by SQL NULL. %Q */
|
||||
#define etTOKEN 13 /* a pointer to a Token structure */
|
||||
#define etSRCLIST 14 /* a pointer to a SrcList */
|
||||
#define etPOINTER 15 /* The %p conversion */
|
||||
#define etSQLESCAPE3 16 /* %w -> Strings with '\"' doubled */
|
||||
|
||||
|
||||
/*
|
||||
** An "etByte" is an 8-bit unsigned value.
|
||||
*/
|
||||
typedef unsigned char etByte;
|
||||
|
||||
/*
|
||||
** Each builtin conversion character (ex: the 'd' in "%d") is described
|
||||
** by an instance of the following structure
|
||||
*/
|
||||
typedef struct et_info { /* Information about each format field */
|
||||
char fmttype; /* The format field code letter */
|
||||
etByte base; /* The base for radix conversion */
|
||||
etByte flags; /* One or more of FLAG_ constants below */
|
||||
etByte type; /* Conversion paradigm */
|
||||
etByte charset; /* Offset into aDigits[] of the digits string */
|
||||
etByte prefix; /* Offset into aPrefix[] of the prefix string */
|
||||
} et_info;
|
||||
|
||||
/*
|
||||
** Allowed values for et_info.flags
|
||||
*/
|
||||
#define FLAG_SIGNED 1 /* True if the value to convert is signed */
|
||||
#define FLAG_INTERN 2 /* True if for internal use only */
|
||||
#define FLAG_STRING 4 /* Allow infinity precision */
|
||||
|
||||
|
||||
/*
|
||||
** The following table is searched linearly, so it is good to put the
|
||||
** most frequently used conversion types first.
|
||||
*/
|
||||
static const char aDigits[] = "0123456789ABCDEF0123456789abcdef";
|
||||
static const char aPrefix[] = "-x0\000X0";
|
||||
static const et_info fmtinfo[] = {
|
||||
{ 'd', 10, 1, etRADIX, 0, 0 },
|
||||
{ 's', 0, 4, etSTRING, 0, 0 },
|
||||
{ 'g', 0, 1, etGENERIC, 30, 0 },
|
||||
{ 'z', 0, 4, etDYNSTRING, 0, 0 },
|
||||
{ 'q', 0, 4, etSQLESCAPE, 0, 0 },
|
||||
{ 'Q', 0, 4, etSQLESCAPE2, 0, 0 },
|
||||
{ 'w', 0, 4, etSQLESCAPE3, 0, 0 },
|
||||
{ 'c', 0, 0, etCHARX, 0, 0 },
|
||||
{ 'o', 8, 0, etRADIX, 0, 2 },
|
||||
{ 'u', 10, 0, etRADIX, 0, 0 },
|
||||
{ 'x', 16, 0, etRADIX, 16, 1 },
|
||||
{ 'X', 16, 0, etRADIX, 0, 4 },
|
||||
#ifndef SQLITE_OMIT_FLOATING_POINT
|
||||
{ 'f', 0, 1, etFLOAT, 0, 0 },
|
||||
{ 'e', 0, 1, etEXP, 30, 0 },
|
||||
{ 'E', 0, 1, etEXP, 14, 0 },
|
||||
{ 'G', 0, 1, etGENERIC, 14, 0 },
|
||||
#endif
|
||||
{ 'i', 10, 1, etRADIX, 0, 0 },
|
||||
{ 'n', 0, 0, etSIZE, 0, 0 },
|
||||
{ '%', 0, 0, etPERCENT, 0, 0 },
|
||||
{ 'p', 16, 0, etPOINTER, 0, 1 },
|
||||
{ 'T', 0, 2, etTOKEN, 0, 0 },
|
||||
{ 'S', 0, 2, etSRCLIST, 0, 0 },
|
||||
};
|
||||
#define etNINFO (sizeof(fmtinfo)/sizeof(fmtinfo[0]))
|
||||
|
||||
/*
|
||||
** If SQLITE_OMIT_FLOATING_POINT is defined, then none of the floating point
|
||||
** conversions will work.
|
||||
*/
|
||||
#ifndef SQLITE_OMIT_FLOATING_POINT
|
||||
/*
|
||||
** "*val" is a double such that 0.1 <= *val < 10.0
|
||||
** Return the ascii code for the leading digit of *val, then
|
||||
** multiply "*val" by 10.0 to renormalize.
|
||||
**
|
||||
** Example:
|
||||
** input: *val = 3.14159
|
||||
** output: *val = 1.4159 function return = '3'
|
||||
**
|
||||
** The counter *cnt is incremented each time. After counter exceeds
|
||||
** 16 (the number of significant digits in a 64-bit float) '0' is
|
||||
** always returned.
|
||||
*/
|
||||
static int et_getdigit(LONGDOUBLE_TYPE *val, int *cnt){
|
||||
int digit;
|
||||
LONGDOUBLE_TYPE d;
|
||||
if( (*cnt)++ >= 16 ) return '0';
|
||||
digit = (int)*val;
|
||||
d = digit;
|
||||
digit += '0';
|
||||
*val = (*val - d)*10.0;
|
||||
return digit;
|
||||
}
|
||||
#endif /* SQLITE_OMIT_FLOATING_POINT */
|
||||
|
||||
/*
|
||||
** On machines with a small stack size, you can redefine the
|
||||
** SQLITE_PRINT_BUF_SIZE to be less than 350. But beware - for
|
||||
** smaller values some %f conversions may go into an infinite loop.
|
||||
*/
|
||||
#ifndef SQLITE_PRINT_BUF_SIZE
|
||||
# define SQLITE_PRINT_BUF_SIZE 350
|
||||
#endif
|
||||
#define etBUFSIZE SQLITE_PRINT_BUF_SIZE /* Size of the output buffer */
|
||||
|
||||
/*
|
||||
** The root program. All variations call this core.
|
||||
**
|
||||
** INPUTS:
|
||||
** func This is a pointer to a function taking three arguments
|
||||
** 1. A pointer to anything. Same as the "arg" parameter.
|
||||
** 2. A pointer to the list of characters to be output
|
||||
** (Note, this list is NOT null terminated.)
|
||||
** 3. An integer number of characters to be output.
|
||||
** (Note: This number might be zero.)
|
||||
**
|
||||
** arg This is the pointer to anything which will be passed as the
|
||||
** first argument to "func". Use it for whatever you like.
|
||||
**
|
||||
** fmt This is the format string, as in the usual print.
|
||||
**
|
||||
** ap This is a pointer to a list of arguments. Same as in
|
||||
** vfprint.
|
||||
**
|
||||
** OUTPUTS:
|
||||
** The return value is the total number of characters sent to
|
||||
** the function "func". Returns -1 on a error.
|
||||
**
|
||||
** Note that the order in which automatic variables are declared below
|
||||
** seems to make a big difference in determining how fast this beast
|
||||
** will run.
|
||||
*/
|
||||
static int vxprintf(
|
||||
void (*func)(void*,const char*,int), /* Consumer of text */
|
||||
void *arg, /* First argument to the consumer */
|
||||
int useExtended, /* Allow extended %-conversions */
|
||||
const char *fmt, /* Format string */
|
||||
va_list ap /* arguments */
|
||||
){
|
||||
int c; /* Next character in the format string */
|
||||
char *bufpt; /* Pointer to the conversion buffer */
|
||||
int precision; /* Precision of the current field */
|
||||
int length; /* Length of the field */
|
||||
int idx; /* A general purpose loop counter */
|
||||
int count; /* Total number of characters output */
|
||||
int width; /* Width of the current field */
|
||||
etByte flag_leftjustify; /* True if "-" flag is present */
|
||||
etByte flag_plussign; /* True if "+" flag is present */
|
||||
etByte flag_blanksign; /* True if " " flag is present */
|
||||
etByte flag_alternateform; /* True if "#" flag is present */
|
||||
etByte flag_altform2; /* True if "!" flag is present */
|
||||
etByte flag_zeropad; /* True if field width constant starts with zero */
|
||||
etByte flag_long; /* True if "l" flag is present */
|
||||
etByte flag_longlong; /* True if the "ll" flag is present */
|
||||
etByte done; /* Loop termination flag */
|
||||
sqlite_uint64 longvalue; /* Value for integer types */
|
||||
LONGDOUBLE_TYPE realvalue; /* Value for real types */
|
||||
const et_info *infop; /* Pointer to the appropriate info structure */
|
||||
char buf[etBUFSIZE]; /* Conversion buffer */
|
||||
char prefix; /* Prefix character. "+" or "-" or " " or '\0'. */
|
||||
etByte errorflag = 0; /* True if an error is encountered */
|
||||
etByte xtype; /* Conversion paradigm */
|
||||
char *zExtra; /* Extra memory used for etTCLESCAPE conversions */
|
||||
static const char spaces[] =
|
||||
" ";
|
||||
#define etSPACESIZE (sizeof(spaces)-1)
|
||||
#ifndef SQLITE_OMIT_FLOATING_POINT
|
||||
int exp, e2; /* exponent of real numbers */
|
||||
double rounder; /* Used for rounding floating point values */
|
||||
etByte flag_dp; /* True if decimal point should be shown */
|
||||
etByte flag_rtz; /* True if trailing zeros should be removed */
|
||||
etByte flag_exp; /* True to force display of the exponent */
|
||||
int nsd; /* Number of significant digits returned */
|
||||
#endif
|
||||
|
||||
func(arg,"",0);
|
||||
count = length = 0;
|
||||
bufpt = 0;
|
||||
for(; (c=(*fmt))!=0; ++fmt){
|
||||
if( c!='%' ){
|
||||
int amt;
|
||||
bufpt = (char *)fmt;
|
||||
amt = 1;
|
||||
while( (c=(*++fmt))!='%' && c!=0 ) amt++;
|
||||
(*func)(arg,bufpt,amt);
|
||||
count += amt;
|
||||
if( c==0 ) break;
|
||||
}
|
||||
if( (c=(*++fmt))==0 ){
|
||||
errorflag = 1;
|
||||
(*func)(arg,"%",1);
|
||||
count++;
|
||||
break;
|
||||
}
|
||||
/* Find out what flags are present */
|
||||
flag_leftjustify = flag_plussign = flag_blanksign =
|
||||
flag_alternateform = flag_altform2 = flag_zeropad = 0;
|
||||
done = 0;
|
||||
do{
|
||||
switch( c ){
|
||||
case '-': flag_leftjustify = 1; break;
|
||||
case '+': flag_plussign = 1; break;
|
||||
case ' ': flag_blanksign = 1; break;
|
||||
case '#': flag_alternateform = 1; break;
|
||||
case '!': flag_altform2 = 1; break;
|
||||
case '0': flag_zeropad = 1; break;
|
||||
default: done = 1; break;
|
||||
}
|
||||
}while( !done && (c=(*++fmt))!=0 );
|
||||
/* Get the field width */
|
||||
width = 0;
|
||||
if( c=='*' ){
|
||||
width = va_arg(ap,int);
|
||||
if( width<0 ){
|
||||
flag_leftjustify = 1;
|
||||
width = -width;
|
||||
}
|
||||
c = *++fmt;
|
||||
}else{
|
||||
while( c>='0' && c<='9' ){
|
||||
width = width*10 + c - '0';
|
||||
c = *++fmt;
|
||||
}
|
||||
}
|
||||
if( width > etBUFSIZE-10 ){
|
||||
width = etBUFSIZE-10;
|
||||
}
|
||||
/* Get the precision */
|
||||
if( c=='.' ){
|
||||
precision = 0;
|
||||
c = *++fmt;
|
||||
if( c=='*' ){
|
||||
precision = va_arg(ap,int);
|
||||
if( precision<0 ) precision = -precision;
|
||||
c = *++fmt;
|
||||
}else{
|
||||
while( c>='0' && c<='9' ){
|
||||
precision = precision*10 + c - '0';
|
||||
c = *++fmt;
|
||||
}
|
||||
}
|
||||
}else{
|
||||
precision = -1;
|
||||
}
|
||||
/* Get the conversion type modifier */
|
||||
if( c=='l' ){
|
||||
flag_long = 1;
|
||||
c = *++fmt;
|
||||
if( c=='l' ){
|
||||
flag_longlong = 1;
|
||||
c = *++fmt;
|
||||
}else{
|
||||
flag_longlong = 0;
|
||||
}
|
||||
}else{
|
||||
flag_long = flag_longlong = 0;
|
||||
}
|
||||
/* Fetch the info entry for the field */
|
||||
infop = 0;
|
||||
for(idx=0; idx<etNINFO; idx++){
|
||||
if( c==fmtinfo[idx].fmttype ){
|
||||
infop = &fmtinfo[idx];
|
||||
if( useExtended || (infop->flags & FLAG_INTERN)==0 ){
|
||||
xtype = infop->type;
|
||||
}else{
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
zExtra = 0;
|
||||
if( infop==0 ){
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/* Limit the precision to prevent overflowing buf[] during conversion */
|
||||
if( precision>etBUFSIZE-40 && (infop->flags & FLAG_STRING)==0 ){
|
||||
precision = etBUFSIZE-40;
|
||||
}
|
||||
|
||||
/*
|
||||
** At this point, variables are initialized as follows:
|
||||
**
|
||||
** flag_alternateform TRUE if a '#' is present.
|
||||
** flag_altform2 TRUE if a '!' is present.
|
||||
** flag_plussign TRUE if a '+' is present.
|
||||
** flag_leftjustify TRUE if a '-' is present or if the
|
||||
** field width was negative.
|
||||
** flag_zeropad TRUE if the width began with 0.
|
||||
** flag_long TRUE if the letter 'l' (ell) prefixed
|
||||
** the conversion character.
|
||||
** flag_longlong TRUE if the letter 'll' (ell ell) prefixed
|
||||
** the conversion character.
|
||||
** flag_blanksign TRUE if a ' ' is present.
|
||||
** width The specified field width. This is
|
||||
** always non-negative. Zero is the default.
|
||||
** precision The specified precision. The default
|
||||
** is -1.
|
||||
** xtype The class of the conversion.
|
||||
** infop Pointer to the appropriate info struct.
|
||||
*/
|
||||
switch( xtype ){
|
||||
case etPOINTER:
|
||||
flag_longlong = sizeof(char*)==sizeof(i64);
|
||||
flag_long = sizeof(char*)==sizeof(long int);
|
||||
/* Fall through into the next case */
|
||||
case etRADIX:
|
||||
if( infop->flags & FLAG_SIGNED ){
|
||||
i64 v;
|
||||
if( flag_longlong ) v = va_arg(ap,i64);
|
||||
else if( flag_long ) v = va_arg(ap,long int);
|
||||
else v = va_arg(ap,int);
|
||||
if( v<0 ){
|
||||
longvalue = -v;
|
||||
prefix = '-';
|
||||
}else{
|
||||
longvalue = v;
|
||||
if( flag_plussign ) prefix = '+';
|
||||
else if( flag_blanksign ) prefix = ' ';
|
||||
else prefix = 0;
|
||||
}
|
||||
}else{
|
||||
if( flag_longlong ) longvalue = va_arg(ap,u64);
|
||||
else if( flag_long ) longvalue = va_arg(ap,unsigned long int);
|
||||
else longvalue = va_arg(ap,unsigned int);
|
||||
prefix = 0;
|
||||
}
|
||||
if( longvalue==0 ) flag_alternateform = 0;
|
||||
if( flag_zeropad && precision<width-(prefix!=0) ){
|
||||
precision = width-(prefix!=0);
|
||||
}
|
||||
bufpt = &buf[etBUFSIZE-1];
|
||||
{
|
||||
register const char *cset; /* Use registers for speed */
|
||||
register int base;
|
||||
cset = &aDigits[infop->charset];
|
||||
base = infop->base;
|
||||
do{ /* Convert to ascii */
|
||||
*(--bufpt) = cset[longvalue%base];
|
||||
longvalue = longvalue/base;
|
||||
}while( longvalue>0 );
|
||||
}
|
||||
length = &buf[etBUFSIZE-1]-bufpt;
|
||||
for(idx=precision-length; idx>0; idx--){
|
||||
*(--bufpt) = '0'; /* Zero pad */
|
||||
}
|
||||
if( prefix ) *(--bufpt) = prefix; /* Add sign */
|
||||
if( flag_alternateform && infop->prefix ){ /* Add "0" or "0x" */
|
||||
const char *pre;
|
||||
char x;
|
||||
pre = &aPrefix[infop->prefix];
|
||||
if( *bufpt!=pre[0] ){
|
||||
for(; (x=(*pre))!=0; pre++) *(--bufpt) = x;
|
||||
}
|
||||
}
|
||||
length = &buf[etBUFSIZE-1]-bufpt;
|
||||
break;
|
||||
case etFLOAT:
|
||||
case etEXP:
|
||||
case etGENERIC:
|
||||
realvalue = va_arg(ap,double);
|
||||
#ifndef SQLITE_OMIT_FLOATING_POINT
|
||||
if( precision<0 ) precision = 6; /* Set default precision */
|
||||
if( precision>etBUFSIZE/2-10 ) precision = etBUFSIZE/2-10;
|
||||
if( realvalue<0.0 ){
|
||||
realvalue = -realvalue;
|
||||
prefix = '-';
|
||||
}else{
|
||||
if( flag_plussign ) prefix = '+';
|
||||
else if( flag_blanksign ) prefix = ' ';
|
||||
else prefix = 0;
|
||||
}
|
||||
if( xtype==etGENERIC && precision>0 ) precision--;
|
||||
#if 0
|
||||
/* Rounding works like BSD when the constant 0.4999 is used. Wierd! */
|
||||
for(idx=precision, rounder=0.4999; idx>0; idx--, rounder*=0.1);
|
||||
#else
|
||||
/* It makes more sense to use 0.5 */
|
||||
for(idx=precision, rounder=0.5; idx>0; idx--, rounder*=0.1){}
|
||||
#endif
|
||||
if( xtype==etFLOAT ) realvalue += rounder;
|
||||
/* Normalize realvalue to within 10.0 > realvalue >= 1.0 */
|
||||
exp = 0;
|
||||
if( sqlite3_isnan(realvalue) ){
|
||||
bufpt = "NaN";
|
||||
length = 3;
|
||||
break;
|
||||
}
|
||||
if( realvalue>0.0 ){
|
||||
while( realvalue>=1e32 && exp<=350 ){ realvalue *= 1e-32; exp+=32; }
|
||||
while( realvalue>=1e8 && exp<=350 ){ realvalue *= 1e-8; exp+=8; }
|
||||
while( realvalue>=10.0 && exp<=350 ){ realvalue *= 0.1; exp++; }
|
||||
while( realvalue<1e-8 && exp>=-350 ){ realvalue *= 1e8; exp-=8; }
|
||||
while( realvalue<1.0 && exp>=-350 ){ realvalue *= 10.0; exp--; }
|
||||
if( exp>350 || exp<-350 ){
|
||||
if( prefix=='-' ){
|
||||
bufpt = "-Inf";
|
||||
}else if( prefix=='+' ){
|
||||
bufpt = "+Inf";
|
||||
}else{
|
||||
bufpt = "Inf";
|
||||
}
|
||||
length = strlen(bufpt);
|
||||
break;
|
||||
}
|
||||
}
|
||||
bufpt = buf;
|
||||
/*
|
||||
** If the field type is etGENERIC, then convert to either etEXP
|
||||
** or etFLOAT, as appropriate.
|
||||
*/
|
||||
flag_exp = xtype==etEXP;
|
||||
if( xtype!=etFLOAT ){
|
||||
realvalue += rounder;
|
||||
if( realvalue>=10.0 ){ realvalue *= 0.1; exp++; }
|
||||
}
|
||||
if( xtype==etGENERIC ){
|
||||
flag_rtz = !flag_alternateform;
|
||||
if( exp<-4 || exp>precision ){
|
||||
xtype = etEXP;
|
||||
}else{
|
||||
precision = precision - exp;
|
||||
xtype = etFLOAT;
|
||||
}
|
||||
}else{
|
||||
flag_rtz = 0;
|
||||
}
|
||||
if( xtype==etEXP ){
|
||||
e2 = 0;
|
||||
}else{
|
||||
e2 = exp;
|
||||
}
|
||||
nsd = 0;
|
||||
flag_dp = (precision>0) | flag_alternateform | flag_altform2;
|
||||
/* The sign in front of the number */
|
||||
if( prefix ){
|
||||
*(bufpt++) = prefix;
|
||||
}
|
||||
/* Digits prior to the decimal point */
|
||||
if( e2<0 ){
|
||||
*(bufpt++) = '0';
|
||||
}else{
|
||||
for(; e2>=0; e2--){
|
||||
*(bufpt++) = et_getdigit(&realvalue,&nsd);
|
||||
}
|
||||
}
|
||||
/* The decimal point */
|
||||
if( flag_dp ){
|
||||
*(bufpt++) = '.';
|
||||
}
|
||||
/* "0" digits after the decimal point but before the first
|
||||
** significant digit of the number */
|
||||
for(e2++; e2<0 && precision>0; precision--, e2++){
|
||||
*(bufpt++) = '0';
|
||||
}
|
||||
/* Significant digits after the decimal point */
|
||||
while( (precision--)>0 ){
|
||||
*(bufpt++) = et_getdigit(&realvalue,&nsd);
|
||||
}
|
||||
/* Remove trailing zeros and the "." if no digits follow the "." */
|
||||
if( flag_rtz && flag_dp ){
|
||||
while( bufpt[-1]=='0' ) *(--bufpt) = 0;
|
||||
assert( bufpt>buf );
|
||||
if( bufpt[-1]=='.' ){
|
||||
if( flag_altform2 ){
|
||||
*(bufpt++) = '0';
|
||||
}else{
|
||||
*(--bufpt) = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Add the "eNNN" suffix */
|
||||
if( flag_exp || (xtype==etEXP && exp) ){
|
||||
*(bufpt++) = aDigits[infop->charset];
|
||||
if( exp<0 ){
|
||||
*(bufpt++) = '-'; exp = -exp;
|
||||
}else{
|
||||
*(bufpt++) = '+';
|
||||
}
|
||||
if( exp>=100 ){
|
||||
*(bufpt++) = (exp/100)+'0'; /* 100's digit */
|
||||
exp %= 100;
|
||||
}
|
||||
*(bufpt++) = exp/10+'0'; /* 10's digit */
|
||||
*(bufpt++) = exp%10+'0'; /* 1's digit */
|
||||
}
|
||||
*bufpt = 0;
|
||||
|
||||
/* The converted number is in buf[] and zero terminated. Output it.
|
||||
** Note that the number is in the usual order, not reversed as with
|
||||
** integer conversions. */
|
||||
length = bufpt-buf;
|
||||
bufpt = buf;
|
||||
|
||||
/* Special case: Add leading zeros if the flag_zeropad flag is
|
||||
** set and we are not left justified */
|
||||
if( flag_zeropad && !flag_leftjustify && length < width){
|
||||
int i;
|
||||
int nPad = width - length;
|
||||
for(i=width; i>=nPad; i--){
|
||||
bufpt[i] = bufpt[i-nPad];
|
||||
}
|
||||
i = prefix!=0;
|
||||
while( nPad-- ) bufpt[i++] = '0';
|
||||
length = width;
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
case etSIZE:
|
||||
*(va_arg(ap,int*)) = count;
|
||||
length = width = 0;
|
||||
break;
|
||||
case etPERCENT:
|
||||
buf[0] = '%';
|
||||
bufpt = buf;
|
||||
length = 1;
|
||||
break;
|
||||
case etCHARLIT:
|
||||
case etCHARX:
|
||||
c = buf[0] = (xtype==etCHARX ? va_arg(ap,int) : *++fmt);
|
||||
if( precision>=0 ){
|
||||
for(idx=1; idx<precision; idx++) buf[idx] = c;
|
||||
length = precision;
|
||||
}else{
|
||||
length =1;
|
||||
}
|
||||
bufpt = buf;
|
||||
break;
|
||||
case etSTRING:
|
||||
case etDYNSTRING:
|
||||
bufpt = va_arg(ap,char*);
|
||||
if( bufpt==0 ){
|
||||
bufpt = "";
|
||||
}else if( xtype==etDYNSTRING ){
|
||||
zExtra = bufpt;
|
||||
}
|
||||
length = strlen(bufpt);
|
||||
if( precision>=0 && precision<length ) length = precision;
|
||||
break;
|
||||
case etSQLESCAPE:
|
||||
case etSQLESCAPE2:
|
||||
case etSQLESCAPE3: {
|
||||
int i, j, n, ch, isnull;
|
||||
int needQuote;
|
||||
char q = ((xtype==etSQLESCAPE3)?'"':'\''); /* Quote character */
|
||||
char *escarg = va_arg(ap,char*);
|
||||
isnull = escarg==0;
|
||||
if( isnull ) escarg = (xtype==etSQLESCAPE2 ? "NULL" : "(NULL)");
|
||||
for(i=n=0; (ch=escarg[i])!=0; i++){
|
||||
if( ch==q ) n++;
|
||||
}
|
||||
needQuote = !isnull && xtype==etSQLESCAPE2;
|
||||
n += i + 1 + needQuote*2;
|
||||
if( n>etBUFSIZE ){
|
||||
bufpt = zExtra = sqlite3_malloc( n );
|
||||
if( bufpt==0 ) return -1;
|
||||
}else{
|
||||
bufpt = buf;
|
||||
}
|
||||
j = 0;
|
||||
if( needQuote ) bufpt[j++] = q;
|
||||
for(i=0; (ch=escarg[i])!=0; i++){
|
||||
bufpt[j++] = ch;
|
||||
if( ch==q ) bufpt[j++] = ch;
|
||||
}
|
||||
if( needQuote ) bufpt[j++] = q;
|
||||
bufpt[j] = 0;
|
||||
length = j;
|
||||
/* The precision is ignored on %q and %Q */
|
||||
/* if( precision>=0 && precision<length ) length = precision; */
|
||||
break;
|
||||
}
|
||||
case etTOKEN: {
|
||||
Token *pToken = va_arg(ap, Token*);
|
||||
if( pToken && pToken->z ){
|
||||
(*func)(arg, (char*)pToken->z, pToken->n);
|
||||
}
|
||||
length = width = 0;
|
||||
break;
|
||||
}
|
||||
case etSRCLIST: {
|
||||
SrcList *pSrc = va_arg(ap, SrcList*);
|
||||
int k = va_arg(ap, int);
|
||||
struct SrcList_item *pItem = &pSrc->a[k];
|
||||
assert( k>=0 && k<pSrc->nSrc );
|
||||
if( pItem->zDatabase && pItem->zDatabase[0] ){
|
||||
(*func)(arg, pItem->zDatabase, strlen(pItem->zDatabase));
|
||||
(*func)(arg, ".", 1);
|
||||
}
|
||||
(*func)(arg, pItem->zName, strlen(pItem->zName));
|
||||
length = width = 0;
|
||||
break;
|
||||
}
|
||||
}/* End switch over the format type */
|
||||
/*
|
||||
** The text of the conversion is pointed to by "bufpt" and is
|
||||
** "length" characters long. The field width is "width". Do
|
||||
** the output.
|
||||
*/
|
||||
if( !flag_leftjustify ){
|
||||
register int nspace;
|
||||
nspace = width-length;
|
||||
if( nspace>0 ){
|
||||
count += nspace;
|
||||
while( nspace>=etSPACESIZE ){
|
||||
(*func)(arg,spaces,etSPACESIZE);
|
||||
nspace -= etSPACESIZE;
|
||||
}
|
||||
if( nspace>0 ) (*func)(arg,spaces,nspace);
|
||||
}
|
||||
}
|
||||
if( length>0 ){
|
||||
(*func)(arg,bufpt,length);
|
||||
count += length;
|
||||
}
|
||||
if( flag_leftjustify ){
|
||||
register int nspace;
|
||||
nspace = width-length;
|
||||
if( nspace>0 ){
|
||||
count += nspace;
|
||||
while( nspace>=etSPACESIZE ){
|
||||
(*func)(arg,spaces,etSPACESIZE);
|
||||
nspace -= etSPACESIZE;
|
||||
}
|
||||
if( nspace>0 ) (*func)(arg,spaces,nspace);
|
||||
}
|
||||
}
|
||||
if( zExtra ){
|
||||
sqlite3_free(zExtra);
|
||||
}
|
||||
}/* End for loop over the format string */
|
||||
return errorflag ? -1 : count;
|
||||
} /* End of function */
|
||||
|
||||
|
||||
/* This structure is used to store state information about the
|
||||
** write to memory that is currently in progress.
|
||||
*/
|
||||
struct sgMprintf {
|
||||
char *zBase; /* A base allocation */
|
||||
char *zText; /* The string collected so far */
|
||||
int nChar; /* Length of the string so far */
|
||||
int nTotal; /* Output size if unconstrained */
|
||||
int nAlloc; /* Amount of space allocated in zText */
|
||||
void *(*xRealloc)(void*,int); /* Function used to realloc memory */
|
||||
int iMallocFailed; /* True if xRealloc() has failed */
|
||||
};
|
||||
|
||||
/*
|
||||
** This function implements the callback from vxprintf.
|
||||
**
|
||||
** This routine add nNewChar characters of text in zNewText to
|
||||
** the sgMprintf structure pointed to by "arg".
|
||||
*/
|
||||
static void mout(void *arg, const char *zNewText, int nNewChar){
|
||||
struct sgMprintf *pM = (struct sgMprintf*)arg;
|
||||
if( pM->iMallocFailed ) return;
|
||||
pM->nTotal += nNewChar;
|
||||
if( pM->zText ){
|
||||
if( pM->nChar + nNewChar + 1 > pM->nAlloc ){
|
||||
if( pM->xRealloc==0 ){
|
||||
nNewChar = pM->nAlloc - pM->nChar - 1;
|
||||
}else{
|
||||
int nAlloc = pM->nChar + nNewChar*2 + 1;
|
||||
if( pM->zText==pM->zBase ){
|
||||
pM->zText = pM->xRealloc(0, nAlloc);
|
||||
if( pM->zText==0 ){
|
||||
pM->nAlloc = 0;
|
||||
pM->iMallocFailed = 1;
|
||||
return;
|
||||
}else if( pM->nChar ){
|
||||
memcpy(pM->zText, pM->zBase, pM->nChar);
|
||||
}
|
||||
}else{
|
||||
char *zNew;
|
||||
zNew = pM->xRealloc(pM->zText, nAlloc);
|
||||
if( zNew ){
|
||||
pM->zText = zNew;
|
||||
}else{
|
||||
pM->iMallocFailed = 1;
|
||||
pM->xRealloc(pM->zText, 0);
|
||||
pM->zText = 0;
|
||||
pM->nAlloc = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
pM->nAlloc = nAlloc;
|
||||
}
|
||||
}
|
||||
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), /* realloc() function. 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;
|
||||
sM.iMallocFailed = 0;
|
||||
vxprintf(mout, &sM, useInternal, zFormat, ap);
|
||||
assert(sM.iMallocFailed==0 || sM.zText==0);
|
||||
if( xRealloc && !sM.iMallocFailed ){
|
||||
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;
|
||||
sqlite3MallocBenignFailure(1);
|
||||
zNew = xRealloc(sM.zText, sM.nChar+1);
|
||||
if( zNew ){
|
||||
sM.zText = zNew;
|
||||
}
|
||||
}
|
||||
}
|
||||
return sM.zText;
|
||||
}
|
||||
|
||||
/*
|
||||
** Realloc that is a real function, not a macro.
|
||||
*/
|
||||
static void *printf_realloc(void *old, int size){
|
||||
return sqlite3_realloc(old, size);
|
||||
}
|
||||
|
||||
/*
|
||||
** Print into memory obtained from sqliteMalloc(). Use the internal
|
||||
** %-conversion extensions.
|
||||
*/
|
||||
char *sqlite3VMPrintf(sqlite3 *db, const char *zFormat, va_list ap){
|
||||
char *z;
|
||||
char zBase[SQLITE_PRINT_BUF_SIZE];
|
||||
z = base_vprintf(printf_realloc, 1, zBase, sizeof(zBase), zFormat, ap);
|
||||
if( z==0 && db!=0 ){
|
||||
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;
|
||||
char zBase[SQLITE_PRINT_BUF_SIZE];
|
||||
va_start(ap, zFormat);
|
||||
z = base_vprintf(printf_realloc, 1, zBase, sizeof(zBase), zFormat, ap);
|
||||
va_end(ap);
|
||||
if( z==0 && db!=0 ){
|
||||
db->mallocFailed = 1;
|
||||
}
|
||||
return z;
|
||||
}
|
||||
|
||||
/*
|
||||
** Print into memory obtained from sqlite3_malloc(). Omit the internal
|
||||
** %-conversion extensions.
|
||||
*/
|
||||
char *sqlite3_vmprintf(const char *zFormat, va_list ap){
|
||||
char zBase[SQLITE_PRINT_BUF_SIZE];
|
||||
return base_vprintf(sqlite3_realloc, 0, zBase, sizeof(zBase), zFormat, ap);
|
||||
}
|
||||
|
||||
/*
|
||||
** Print into memory obtained from sqlite3_malloc()(). Omit the internal
|
||||
** %-conversion extensions.
|
||||
*/
|
||||
char *sqlite3_mprintf(const char *zFormat, ...){
|
||||
va_list ap;
|
||||
char *z;
|
||||
va_start(ap, zFormat);
|
||||
z = sqlite3_vmprintf(zFormat, ap);
|
||||
va_end(ap);
|
||||
return z;
|
||||
}
|
||||
|
||||
/*
|
||||
** sqlite3_snprintf() works like snprintf() except that it ignores the
|
||||
** current locale settings. This is important for SQLite because we
|
||||
** are not able to use a "," as the decimal point in place of "." as
|
||||
** specified by some locales.
|
||||
*/
|
||||
char *sqlite3_snprintf(int n, char *zBuf, const char *zFormat, ...){
|
||||
char *z;
|
||||
va_list ap;
|
||||
|
||||
if( n<=0 ){
|
||||
return zBuf;
|
||||
}
|
||||
zBuf[0] = 0;
|
||||
va_start(ap,zFormat);
|
||||
z = base_vprintf(0, 0, zBuf, n, zFormat, ap);
|
||||
va_end(ap);
|
||||
return z;
|
||||
}
|
||||
|
||||
#if defined(SQLITE_TEST) || defined(SQLITE_DEBUG) || defined(SQLITE_MEMDEBUG)
|
||||
/*
|
||||
** A version of printf() that understands %lld. Used for debugging.
|
||||
** The printf() built into some versions of windows does not understand %lld
|
||||
** and segfaults if you give it a long long int.
|
||||
*/
|
||||
void sqlite3DebugPrintf(const char *zFormat, ...){
|
||||
extern int getpid(void);
|
||||
va_list ap;
|
||||
char zBuf[500];
|
||||
va_start(ap, zFormat);
|
||||
base_vprintf(0, 0, zBuf, sizeof(zBuf), zFormat, ap);
|
||||
va_end(ap);
|
||||
fprintf(stdout,"%s", zBuf);
|
||||
fflush(stdout);
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,103 @@
|
|||
/*
|
||||
** 2001 September 15
|
||||
**
|
||||
** The author disclaims copyright to this source code. In place of
|
||||
** a legal notice, here is a blessing:
|
||||
**
|
||||
** May you do good and not evil.
|
||||
** May you find forgiveness for yourself and forgive others.
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
*************************************************************************
|
||||
** This file contains code to implement a pseudo-random number
|
||||
** generator (PRNG) for SQLite.
|
||||
**
|
||||
** Random numbers are used by some of the database backends in order
|
||||
** to generate random integer keys for tables or random filenames.
|
||||
**
|
||||
** $Id: random.c,v 1.20 2007/08/21 13:51:23 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
|
||||
|
||||
/*
|
||||
** Get a single 8-bit random value from the RC4 PRNG. The Mutex
|
||||
** must be held while executing this routine.
|
||||
**
|
||||
** Why not just use a library random generator like lrand48() for this?
|
||||
** Because the OP_NewRowid opcode in the VDBE depends on having a very
|
||||
** good source of random numbers. The lrand48() library function may
|
||||
** well be good enough. But maybe not. Or maybe lrand48() has some
|
||||
** subtle problems on some systems that could cause problems. It is hard
|
||||
** to know. To minimize the risk of problems due to bad lrand48()
|
||||
** implementations, SQLite uses this random number generator based
|
||||
** on RC4, which we know works very well.
|
||||
**
|
||||
** (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.
|
||||
*/
|
||||
static int randomByte(void){
|
||||
unsigned char t;
|
||||
|
||||
/* All threads share a single random number generator.
|
||||
** This structure is the current state of the generator.
|
||||
*/
|
||||
static struct {
|
||||
unsigned char isInit; /* True if initialized */
|
||||
unsigned char i, j; /* State variables */
|
||||
unsigned char s[256]; /* State variables */
|
||||
} prng;
|
||||
|
||||
/* Initialize the state of the random number generator once,
|
||||
** the first time this routine is called. The seed value does
|
||||
** not need to contain a lot of randomness since we are not
|
||||
** trying to do secure encryption or anything like that...
|
||||
**
|
||||
** Nothing in this file or anywhere else in SQLite does any kind of
|
||||
** encryption. The RC4 algorithm is being used as a PRNG (pseudo-random
|
||||
** number generator) not as an encryption device.
|
||||
*/
|
||||
if( !prng.isInit ){
|
||||
int i;
|
||||
char k[256];
|
||||
prng.j = 0;
|
||||
prng.i = 0;
|
||||
sqlite3OsRandomness(sqlite3_vfs_find(0), 256, k);
|
||||
for(i=0; i<256; i++){
|
||||
prng.s[i] = i;
|
||||
}
|
||||
for(i=0; i<256; i++){
|
||||
prng.j += prng.s[i] + k[i];
|
||||
t = prng.s[prng.j];
|
||||
prng.s[prng.j] = prng.s[i];
|
||||
prng.s[i] = t;
|
||||
}
|
||||
prng.isInit = 1;
|
||||
}
|
||||
|
||||
/* Generate and return single random byte
|
||||
*/
|
||||
prng.i++;
|
||||
t = prng.s[prng.i];
|
||||
prng.j += t;
|
||||
prng.s[prng.i] = prng.s[prng.j];
|
||||
prng.s[prng.j] = t;
|
||||
t += prng.s[prng.i];
|
||||
return prng.s[t];
|
||||
}
|
||||
|
||||
/*
|
||||
** Return N random bytes.
|
||||
*/
|
||||
void sqlite3Randomness(int N, void *pBuf){
|
||||
unsigned char *zBuf = pBuf;
|
||||
static sqlite3_mutex *mutex = 0;
|
||||
if( mutex==0 ){
|
||||
mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_PRNG);
|
||||
}
|
||||
sqlite3_mutex_enter(mutex);
|
||||
while( N-- ){
|
||||
*(zBuf++) = randomByte();
|
||||
}
|
||||
sqlite3_mutex_leave(mutex);
|
||||
}
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,350 @@
|
|||
/*
|
||||
** 2006 June 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 header file defines the SQLite interface for use by
|
||||
** shared libraries that want to be imported as extensions into
|
||||
** an SQLite instance. Shared libraries that intend to be loaded
|
||||
** as extensions by SQLite should #include this file instead of
|
||||
** sqlite3.h.
|
||||
**
|
||||
** @(#) $Id: sqlite3ext.h,v 1.17 2007/08/31 16:11:36 drh Exp $
|
||||
*/
|
||||
#ifndef _SQLITE3EXT_H_
|
||||
#define _SQLITE3EXT_H_
|
||||
#include "sqlite3.h"
|
||||
|
||||
typedef struct sqlite3_api_routines sqlite3_api_routines;
|
||||
|
||||
/*
|
||||
** The following structure hold pointers to all of the SQLite API
|
||||
** routines.
|
||||
**
|
||||
** WARNING: In order to maintain backwards compatibility, add new
|
||||
** interfaces to the end of this structure only. If you insert new
|
||||
** interfaces in the middle of this structure, then older different
|
||||
** versions of SQLite will not be able to load each others shared
|
||||
** libraries!
|
||||
*/
|
||||
struct sqlite3_api_routines {
|
||||
void * (*aggregate_context)(sqlite3_context*,int nBytes);
|
||||
int (*aggregate_count)(sqlite3_context*);
|
||||
int (*bind_blob)(sqlite3_stmt*,int,const void*,int n,void(*)(void*));
|
||||
int (*bind_double)(sqlite3_stmt*,int,double);
|
||||
int (*bind_int)(sqlite3_stmt*,int,int);
|
||||
int (*bind_int64)(sqlite3_stmt*,int,sqlite_int64);
|
||||
int (*bind_null)(sqlite3_stmt*,int);
|
||||
int (*bind_parameter_count)(sqlite3_stmt*);
|
||||
int (*bind_parameter_index)(sqlite3_stmt*,const char*zName);
|
||||
const char * (*bind_parameter_name)(sqlite3_stmt*,int);
|
||||
int (*bind_text)(sqlite3_stmt*,int,const char*,int n,void(*)(void*));
|
||||
int (*bind_text16)(sqlite3_stmt*,int,const void*,int,void(*)(void*));
|
||||
int (*bind_value)(sqlite3_stmt*,int,const sqlite3_value*);
|
||||
int (*busy_handler)(sqlite3*,int(*)(void*,int),void*);
|
||||
int (*busy_timeout)(sqlite3*,int ms);
|
||||
int (*changes)(sqlite3*);
|
||||
int (*close)(sqlite3*);
|
||||
int (*collation_needed)(sqlite3*,void*,void(*)(void*,sqlite3*,int eTextRep,const char*));
|
||||
int (*collation_needed16)(sqlite3*,void*,void(*)(void*,sqlite3*,int eTextRep,const void*));
|
||||
const void * (*column_blob)(sqlite3_stmt*,int iCol);
|
||||
int (*column_bytes)(sqlite3_stmt*,int iCol);
|
||||
int (*column_bytes16)(sqlite3_stmt*,int iCol);
|
||||
int (*column_count)(sqlite3_stmt*pStmt);
|
||||
const char * (*column_database_name)(sqlite3_stmt*,int);
|
||||
const void * (*column_database_name16)(sqlite3_stmt*,int);
|
||||
const char * (*column_decltype)(sqlite3_stmt*,int i);
|
||||
const void * (*column_decltype16)(sqlite3_stmt*,int);
|
||||
double (*column_double)(sqlite3_stmt*,int iCol);
|
||||
int (*column_int)(sqlite3_stmt*,int iCol);
|
||||
sqlite_int64 (*column_int64)(sqlite3_stmt*,int iCol);
|
||||
const char * (*column_name)(sqlite3_stmt*,int);
|
||||
const void * (*column_name16)(sqlite3_stmt*,int);
|
||||
const char * (*column_origin_name)(sqlite3_stmt*,int);
|
||||
const void * (*column_origin_name16)(sqlite3_stmt*,int);
|
||||
const char * (*column_table_name)(sqlite3_stmt*,int);
|
||||
const void * (*column_table_name16)(sqlite3_stmt*,int);
|
||||
const unsigned char * (*column_text)(sqlite3_stmt*,int iCol);
|
||||
const void * (*column_text16)(sqlite3_stmt*,int iCol);
|
||||
int (*column_type)(sqlite3_stmt*,int iCol);
|
||||
sqlite3_value* (*column_value)(sqlite3_stmt*,int iCol);
|
||||
void * (*commit_hook)(sqlite3*,int(*)(void*),void*);
|
||||
int (*complete)(const char*sql);
|
||||
int (*complete16)(const void*sql);
|
||||
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_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_module)(sqlite3*,const char*,const sqlite3_module*,void*);
|
||||
int (*data_count)(sqlite3_stmt*pStmt);
|
||||
sqlite3 * (*db_handle)(sqlite3_stmt*);
|
||||
int (*declare_vtab)(sqlite3*,const char*);
|
||||
int (*enable_shared_cache)(int);
|
||||
int (*errcode)(sqlite3*db);
|
||||
const char * (*errmsg)(sqlite3*);
|
||||
const void * (*errmsg16)(sqlite3*);
|
||||
int (*exec)(sqlite3*,const char*,sqlite3_callback,void*,char**);
|
||||
int (*expired)(sqlite3_stmt*);
|
||||
int (*finalize)(sqlite3_stmt*pStmt);
|
||||
void (*free)(void*);
|
||||
void (*free_table)(char**result);
|
||||
int (*get_autocommit)(sqlite3*);
|
||||
void * (*get_auxdata)(sqlite3_context*,int);
|
||||
int (*get_table)(sqlite3*,const char*,char***,int*,int*,char**);
|
||||
int (*global_recover)(void);
|
||||
void (*interruptx)(sqlite3*);
|
||||
sqlite_int64 (*last_insert_rowid)(sqlite3*);
|
||||
const char * (*libversion)(void);
|
||||
int (*libversion_number)(void);
|
||||
void *(*malloc)(int);
|
||||
char * (*mprintf)(const char*,...);
|
||||
int (*open)(const char*,sqlite3**);
|
||||
int (*open16)(const void*,sqlite3**);
|
||||
int (*prepare)(sqlite3*,const char*,int,sqlite3_stmt**,const char**);
|
||||
int (*prepare16)(sqlite3*,const void*,int,sqlite3_stmt**,const void**);
|
||||
void * (*profile)(sqlite3*,void(*)(void*,const char*,sqlite_uint64),void*);
|
||||
void (*progress_handler)(sqlite3*,int,int(*)(void*),void*);
|
||||
void *(*realloc)(void*,int);
|
||||
int (*reset)(sqlite3_stmt*pStmt);
|
||||
void (*result_blob)(sqlite3_context*,const void*,int,void(*)(void*));
|
||||
void (*result_double)(sqlite3_context*,double);
|
||||
void (*result_error)(sqlite3_context*,const char*,int);
|
||||
void (*result_error16)(sqlite3_context*,const void*,int);
|
||||
void (*result_int)(sqlite3_context*,int);
|
||||
void (*result_int64)(sqlite3_context*,sqlite_int64);
|
||||
void (*result_null)(sqlite3_context*);
|
||||
void (*result_text)(sqlite3_context*,const char*,int,void(*)(void*));
|
||||
void (*result_text16)(sqlite3_context*,const void*,int,void(*)(void*));
|
||||
void (*result_text16be)(sqlite3_context*,const void*,int,void(*)(void*));
|
||||
void (*result_text16le)(sqlite3_context*,const void*,int,void(*)(void*));
|
||||
void (*result_value)(sqlite3_context*,sqlite3_value*);
|
||||
void * (*rollback_hook)(sqlite3*,void(*)(void*),void*);
|
||||
int (*set_authorizer)(sqlite3*,int(*)(void*,int,const char*,const char*,const char*,const char*),void*);
|
||||
void (*set_auxdata)(sqlite3_context*,int,void*,void (*)(void*));
|
||||
char * (*snprintf)(int,char*,const char*,...);
|
||||
int (*step)(sqlite3_stmt*);
|
||||
int (*table_column_metadata)(sqlite3*,const char*,const char*,const char*,char const**,char const**,int*,int*,int*);
|
||||
void (*thread_cleanup)(void);
|
||||
int (*total_changes)(sqlite3*);
|
||||
void * (*trace)(sqlite3*,void(*xTrace)(void*,const char*),void*);
|
||||
int (*transfer_bindings)(sqlite3_stmt*,sqlite3_stmt*);
|
||||
void * (*update_hook)(sqlite3*,void(*)(void*,int ,char const*,char const*,sqlite_int64),void*);
|
||||
void * (*user_data)(sqlite3_context*);
|
||||
const void * (*value_blob)(sqlite3_value*);
|
||||
int (*value_bytes)(sqlite3_value*);
|
||||
int (*value_bytes16)(sqlite3_value*);
|
||||
double (*value_double)(sqlite3_value*);
|
||||
int (*value_int)(sqlite3_value*);
|
||||
sqlite_int64 (*value_int64)(sqlite3_value*);
|
||||
int (*value_numeric_type)(sqlite3_value*);
|
||||
const unsigned char * (*value_text)(sqlite3_value*);
|
||||
const void * (*value_text16)(sqlite3_value*);
|
||||
const void * (*value_text16be)(sqlite3_value*);
|
||||
const void * (*value_text16le)(sqlite3_value*);
|
||||
int (*value_type)(sqlite3_value*);
|
||||
char *(*vmprintf)(const char*,va_list);
|
||||
/* Added ??? */
|
||||
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 (*prepare16_v2)(sqlite3*,const void*,int,sqlite3_stmt**,const void**);
|
||||
int (*clear_bindings)(sqlite3_stmt*);
|
||||
/* Added by 3.4.1 */
|
||||
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*);
|
||||
};
|
||||
|
||||
/*
|
||||
** The following macros redefine the API routines so that they are
|
||||
** redirected throught the global sqlite3_api structure.
|
||||
**
|
||||
** This header file is also used by the loadext.c source file
|
||||
** (part of the main SQLite library - not an extension) so that
|
||||
** it can get access to the sqlite3_api_routines structure
|
||||
** definition. But the main library does not want to redefine
|
||||
** the API. So the redefinition macros are only valid if the
|
||||
** SQLITE_CORE macros is undefined.
|
||||
*/
|
||||
#ifndef SQLITE_CORE
|
||||
#define sqlite3_aggregate_context sqlite3_api->aggregate_context
|
||||
#define sqlite3_aggregate_count sqlite3_api->aggregate_count
|
||||
#define sqlite3_bind_blob sqlite3_api->bind_blob
|
||||
#define sqlite3_bind_double sqlite3_api->bind_double
|
||||
#define sqlite3_bind_int sqlite3_api->bind_int
|
||||
#define sqlite3_bind_int64 sqlite3_api->bind_int64
|
||||
#define sqlite3_bind_null sqlite3_api->bind_null
|
||||
#define sqlite3_bind_parameter_count sqlite3_api->bind_parameter_count
|
||||
#define sqlite3_bind_parameter_index sqlite3_api->bind_parameter_index
|
||||
#define sqlite3_bind_parameter_name sqlite3_api->bind_parameter_name
|
||||
#define sqlite3_bind_text sqlite3_api->bind_text
|
||||
#define sqlite3_bind_text16 sqlite3_api->bind_text16
|
||||
#define sqlite3_bind_value sqlite3_api->bind_value
|
||||
#define sqlite3_busy_handler sqlite3_api->busy_handler
|
||||
#define sqlite3_busy_timeout sqlite3_api->busy_timeout
|
||||
#define sqlite3_changes sqlite3_api->changes
|
||||
#define sqlite3_close sqlite3_api->close
|
||||
#define sqlite3_collation_needed sqlite3_api->collation_needed
|
||||
#define sqlite3_collation_needed16 sqlite3_api->collation_needed16
|
||||
#define sqlite3_column_blob sqlite3_api->column_blob
|
||||
#define sqlite3_column_bytes sqlite3_api->column_bytes
|
||||
#define sqlite3_column_bytes16 sqlite3_api->column_bytes16
|
||||
#define sqlite3_column_count sqlite3_api->column_count
|
||||
#define sqlite3_column_database_name sqlite3_api->column_database_name
|
||||
#define sqlite3_column_database_name16 sqlite3_api->column_database_name16
|
||||
#define sqlite3_column_decltype sqlite3_api->column_decltype
|
||||
#define sqlite3_column_decltype16 sqlite3_api->column_decltype16
|
||||
#define sqlite3_column_double sqlite3_api->column_double
|
||||
#define sqlite3_column_int sqlite3_api->column_int
|
||||
#define sqlite3_column_int64 sqlite3_api->column_int64
|
||||
#define sqlite3_column_name sqlite3_api->column_name
|
||||
#define sqlite3_column_name16 sqlite3_api->column_name16
|
||||
#define sqlite3_column_origin_name sqlite3_api->column_origin_name
|
||||
#define sqlite3_column_origin_name16 sqlite3_api->column_origin_name16
|
||||
#define sqlite3_column_table_name sqlite3_api->column_table_name
|
||||
#define sqlite3_column_table_name16 sqlite3_api->column_table_name16
|
||||
#define sqlite3_column_text sqlite3_api->column_text
|
||||
#define sqlite3_column_text16 sqlite3_api->column_text16
|
||||
#define sqlite3_column_type sqlite3_api->column_type
|
||||
#define sqlite3_column_value sqlite3_api->column_value
|
||||
#define sqlite3_commit_hook sqlite3_api->commit_hook
|
||||
#define sqlite3_complete sqlite3_api->complete
|
||||
#define sqlite3_complete16 sqlite3_api->complete16
|
||||
#define sqlite3_create_collation sqlite3_api->create_collation
|
||||
#define sqlite3_create_collation16 sqlite3_api->create_collation16
|
||||
#define sqlite3_create_function sqlite3_api->create_function
|
||||
#define sqlite3_create_function16 sqlite3_api->create_function16
|
||||
#define sqlite3_create_module sqlite3_api->create_module
|
||||
#define sqlite3_create_module_v2 sqlite3_api->create_module_v2
|
||||
#define sqlite3_data_count sqlite3_api->data_count
|
||||
#define sqlite3_db_handle sqlite3_api->db_handle
|
||||
#define sqlite3_declare_vtab sqlite3_api->declare_vtab
|
||||
#define sqlite3_enable_shared_cache sqlite3_api->enable_shared_cache
|
||||
#define sqlite3_errcode sqlite3_api->errcode
|
||||
#define sqlite3_errmsg sqlite3_api->errmsg
|
||||
#define sqlite3_errmsg16 sqlite3_api->errmsg16
|
||||
#define sqlite3_exec sqlite3_api->exec
|
||||
#define sqlite3_expired sqlite3_api->expired
|
||||
#define sqlite3_finalize sqlite3_api->finalize
|
||||
#define sqlite3_free sqlite3_api->free
|
||||
#define sqlite3_free_table sqlite3_api->free_table
|
||||
#define sqlite3_get_autocommit sqlite3_api->get_autocommit
|
||||
#define sqlite3_get_auxdata sqlite3_api->get_auxdata
|
||||
#define sqlite3_get_table sqlite3_api->get_table
|
||||
#define sqlite3_global_recover sqlite3_api->global_recover
|
||||
#define sqlite3_interrupt sqlite3_api->interruptx
|
||||
#define sqlite3_last_insert_rowid sqlite3_api->last_insert_rowid
|
||||
#define sqlite3_libversion sqlite3_api->libversion
|
||||
#define sqlite3_libversion_number sqlite3_api->libversion_number
|
||||
#define sqlite3_malloc sqlite3_api->malloc
|
||||
#define sqlite3_mprintf sqlite3_api->mprintf
|
||||
#define sqlite3_open sqlite3_api->open
|
||||
#define sqlite3_open16 sqlite3_api->open16
|
||||
#define sqlite3_prepare sqlite3_api->prepare
|
||||
#define sqlite3_prepare16 sqlite3_api->prepare16
|
||||
#define sqlite3_prepare_v2 sqlite3_api->prepare_v2
|
||||
#define sqlite3_prepare16_v2 sqlite3_api->prepare16_v2
|
||||
#define sqlite3_profile sqlite3_api->profile
|
||||
#define sqlite3_progress_handler sqlite3_api->progress_handler
|
||||
#define sqlite3_realloc sqlite3_api->realloc
|
||||
#define sqlite3_reset sqlite3_api->reset
|
||||
#define sqlite3_result_blob sqlite3_api->result_blob
|
||||
#define sqlite3_result_double sqlite3_api->result_double
|
||||
#define sqlite3_result_error sqlite3_api->result_error
|
||||
#define sqlite3_result_error16 sqlite3_api->result_error16
|
||||
#define sqlite3_result_int sqlite3_api->result_int
|
||||
#define sqlite3_result_int64 sqlite3_api->result_int64
|
||||
#define sqlite3_result_null sqlite3_api->result_null
|
||||
#define sqlite3_result_text sqlite3_api->result_text
|
||||
#define sqlite3_result_text16 sqlite3_api->result_text16
|
||||
#define sqlite3_result_text16be sqlite3_api->result_text16be
|
||||
#define sqlite3_result_text16le sqlite3_api->result_text16le
|
||||
#define sqlite3_result_value sqlite3_api->result_value
|
||||
#define sqlite3_rollback_hook sqlite3_api->rollback_hook
|
||||
#define sqlite3_set_authorizer sqlite3_api->set_authorizer
|
||||
#define sqlite3_set_auxdata sqlite3_api->set_auxdata
|
||||
#define sqlite3_snprintf sqlite3_api->snprintf
|
||||
#define sqlite3_step sqlite3_api->step
|
||||
#define sqlite3_table_column_metadata sqlite3_api->table_column_metadata
|
||||
#define sqlite3_thread_cleanup sqlite3_api->thread_cleanup
|
||||
#define sqlite3_total_changes sqlite3_api->total_changes
|
||||
#define sqlite3_trace sqlite3_api->trace
|
||||
#define sqlite3_transfer_bindings sqlite3_api->transfer_bindings
|
||||
#define sqlite3_update_hook sqlite3_api->update_hook
|
||||
#define sqlite3_user_data sqlite3_api->user_data
|
||||
#define sqlite3_value_blob sqlite3_api->value_blob
|
||||
#define sqlite3_value_bytes sqlite3_api->value_bytes
|
||||
#define sqlite3_value_bytes16 sqlite3_api->value_bytes16
|
||||
#define sqlite3_value_double sqlite3_api->value_double
|
||||
#define sqlite3_value_int sqlite3_api->value_int
|
||||
#define sqlite3_value_int64 sqlite3_api->value_int64
|
||||
#define sqlite3_value_numeric_type sqlite3_api->value_numeric_type
|
||||
#define sqlite3_value_text sqlite3_api->value_text
|
||||
#define sqlite3_value_text16 sqlite3_api->value_text16
|
||||
#define sqlite3_value_text16be sqlite3_api->value_text16be
|
||||
#define sqlite3_value_text16le sqlite3_api->value_text16le
|
||||
#define sqlite3_value_type sqlite3_api->value_type
|
||||
#define sqlite3_vmprintf sqlite3_api->vmprintf
|
||||
#define sqlite3_overload_function sqlite3_api->overload_function
|
||||
#define sqlite3_prepare_v2 sqlite3_api->prepare_v2
|
||||
#define sqlite3_prepare16_v2 sqlite3_api->prepare16_v2
|
||||
#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
|
||||
#endif /* SQLITE_CORE */
|
||||
|
||||
#define SQLITE_EXTENSION_INIT1 const sqlite3_api_routines *sqlite3_api;
|
||||
#define SQLITE_EXTENSION_INIT2(v) sqlite3_api = v;
|
||||
|
||||
#endif /* _SQLITE3EXT_H_ */
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,169 @@
|
|||
/*
|
||||
** 2007 May 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 defines various limits of what SQLite can process.
|
||||
**
|
||||
** @(#) $Id: sqliteLimit.h,v 1.2 2007/08/24 11:52:29 danielk1977 Exp $
|
||||
*/
|
||||
|
||||
/*
|
||||
** The maximum length of a TEXT or BLOB in bytes. This also
|
||||
** limits the size of a row in a table or index.
|
||||
**
|
||||
** The hard limit is the ability of a 32-bit signed integer
|
||||
** to count the size: 2^31-1 or 2147483647.
|
||||
*/
|
||||
#ifndef SQLITE_MAX_LENGTH
|
||||
# define SQLITE_MAX_LENGTH 1000000000
|
||||
#endif
|
||||
|
||||
/*
|
||||
** This is the maximum number of
|
||||
**
|
||||
** * Columns in a table
|
||||
** * Columns in an index
|
||||
** * Columns in a view
|
||||
** * Terms in the SET clause of an UPDATE statement
|
||||
** * Terms in the result set of a SELECT statement
|
||||
** * Terms in the GROUP BY or ORDER BY clauses of a SELECT statement.
|
||||
** * Terms in the VALUES clause of an INSERT statement
|
||||
**
|
||||
** The hard upper limit here is 32676. Most database people will
|
||||
** tell you that in a well-normalized database, you usually should
|
||||
** not have more than a dozen or so columns in any table. And if
|
||||
** that is the case, there is no point in having more than a few
|
||||
** dozen values in any of the other situations described above.
|
||||
*/
|
||||
#ifndef SQLITE_MAX_COLUMN
|
||||
# define SQLITE_MAX_COLUMN 2000
|
||||
#endif
|
||||
|
||||
/*
|
||||
** The maximum length of a single SQL statement in bytes.
|
||||
** The hard limit here is the same as SQLITE_MAX_LENGTH.
|
||||
*/
|
||||
#ifndef SQLITE_MAX_SQL_LENGTH
|
||||
# define SQLITE_MAX_SQL_LENGTH 1000000
|
||||
#endif
|
||||
|
||||
/*
|
||||
** The maximum depth of an expression tree. This is limited to
|
||||
** some extent by SQLITE_MAX_SQL_LENGTH. But sometime you might
|
||||
** want to place more severe limits on the complexity of an
|
||||
** expression. A value of 0 (the default) means do not enforce
|
||||
** any limitation on expression tree depth.
|
||||
*/
|
||||
#ifndef SQLITE_MAX_EXPR_DEPTH
|
||||
# define SQLITE_MAX_EXPR_DEPTH 1000
|
||||
#endif
|
||||
|
||||
/*
|
||||
** The maximum number of terms in a compound SELECT statement.
|
||||
** The code generator for compound SELECT statements does one
|
||||
** level of recursion for each term. A stack overflow can result
|
||||
** if the number of terms is too large. In practice, most SQL
|
||||
** never has more than 3 or 4 terms. Use a value of 0 to disable
|
||||
** any limit on the number of terms in a compount SELECT.
|
||||
*/
|
||||
#ifndef SQLITE_MAX_COMPOUND_SELECT
|
||||
# define SQLITE_MAX_COMPOUND_SELECT 500
|
||||
#endif
|
||||
|
||||
/*
|
||||
** The maximum number of opcodes in a VDBE program.
|
||||
** Not currently enforced.
|
||||
*/
|
||||
#ifndef SQLITE_MAX_VDBE_OP
|
||||
# define SQLITE_MAX_VDBE_OP 25000
|
||||
#endif
|
||||
|
||||
/*
|
||||
** The maximum number of arguments to an SQL function.
|
||||
*/
|
||||
#ifndef SQLITE_MAX_FUNCTION_ARG
|
||||
# define SQLITE_MAX_FUNCTION_ARG 100
|
||||
#endif
|
||||
|
||||
/*
|
||||
** The maximum number of in-memory pages to use for the main database
|
||||
** table and for temporary tables. The SQLITE_DEFAULT_CACHE_SIZE
|
||||
*/
|
||||
#ifndef SQLITE_DEFAULT_CACHE_SIZE
|
||||
# define SQLITE_DEFAULT_CACHE_SIZE 2000
|
||||
#endif
|
||||
#ifndef SQLITE_DEFAULT_TEMP_CACHE_SIZE
|
||||
# define SQLITE_DEFAULT_TEMP_CACHE_SIZE 500
|
||||
#endif
|
||||
|
||||
/*
|
||||
** The maximum number of attached databases. This must be at least 2
|
||||
** in order to support the main database file (0) and the file used to
|
||||
** hold temporary tables (1). And it must be less than 32 because
|
||||
** we use a bitmask of databases with a u32 in places (for example
|
||||
** the Parse.cookieMask field).
|
||||
*/
|
||||
#ifndef SQLITE_MAX_ATTACHED
|
||||
# define SQLITE_MAX_ATTACHED 10
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
** The maximum value of a ?nnn wildcard that the parser will accept.
|
||||
*/
|
||||
#ifndef SQLITE_MAX_VARIABLE_NUMBER
|
||||
# define SQLITE_MAX_VARIABLE_NUMBER 999
|
||||
#endif
|
||||
|
||||
/*
|
||||
** The default size of a database page.
|
||||
*/
|
||||
#ifndef SQLITE_DEFAULT_PAGE_SIZE
|
||||
# define SQLITE_DEFAULT_PAGE_SIZE 1024
|
||||
#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 it's own.
|
||||
*/
|
||||
#ifndef SQLITE_MAX_DEFAULT_PAGE_SIZE
|
||||
# define SQLITE_MAX_DEFAULT_PAGE_SIZE 8192
|
||||
#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.
|
||||
*/
|
||||
#ifndef SQLITE_MAX_PAGE_SIZE
|
||||
# define SQLITE_MAX_PAGE_SIZE 32768
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Maximum number of pages in one database file.
|
||||
**
|
||||
** This is really just the default value for the max_page_count pragma.
|
||||
** This value can be lowered (or raised) at run-time using that the
|
||||
** max_page_count macro.
|
||||
*/
|
||||
#ifndef SQLITE_MAX_PAGE_COUNT
|
||||
# define SQLITE_MAX_PAGE_COUNT 1073741823
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Maximum length (in bytes) of the pattern in a LIKE or GLOB
|
||||
** operator.
|
||||
*/
|
||||
#ifndef SQLITE_MAX_LIKE_PATTERN_LENGTH
|
||||
# define SQLITE_MAX_LIKE_PATTERN_LENGTH 50000
|
||||
#endif
|
|
@ -0,0 +1,20 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 9.00
|
||||
# Visual C++ Express 2005
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sqlite_vs2005", "sqlite_vs2005\sqlite_vs2005.vcproj", "{5E4E7BB0-CF29-493E-A983-C0E5FCF66F44}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Win32 = Debug|Win32
|
||||
Release|Win32 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{5E4E7BB0-CF29-493E-A983-C0E5FCF66F44}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{5E4E7BB0-CF29-493E-A983-C0E5FCF66F44}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{5E4E7BB0-CF29-493E-A983-C0E5FCF66F44}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{5E4E7BB0-CF29-493E-A983-C0E5FCF66F44}.Release|Win32.Build.0 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
|
@ -0,0 +1,131 @@
|
|||
EXPORTS
|
||||
sqlite3_aggregate_context
|
||||
sqlite3_aggregate_count
|
||||
sqlite3_apis
|
||||
sqlite3_auto_extension
|
||||
sqlite3_bind_blob
|
||||
sqlite3_bind_double
|
||||
sqlite3_bind_int
|
||||
sqlite3_bind_int64
|
||||
sqlite3_bind_null
|
||||
sqlite3_bind_parameter_count
|
||||
sqlite3_bind_parameter_index
|
||||
sqlite3_bind_parameter_name
|
||||
sqlite3_bind_text
|
||||
sqlite3_bind_text16
|
||||
sqlite3_bind_value
|
||||
sqlite3_bind_zeroblob
|
||||
sqlite3_blob_bytes
|
||||
sqlite3_blob_close
|
||||
sqlite3_blob_open
|
||||
sqlite3_blob_read
|
||||
sqlite3_blob_write
|
||||
sqlite3_busy_handler
|
||||
sqlite3_busy_timeout
|
||||
sqlite3_changes
|
||||
sqlite3_clear_bindings
|
||||
sqlite3_close
|
||||
sqlite3_collation_needed
|
||||
sqlite3_collation_needed16
|
||||
sqlite3_column_blob
|
||||
sqlite3_column_bytes
|
||||
sqlite3_column_bytes16
|
||||
sqlite3_column_count
|
||||
sqlite3_column_decltype
|
||||
sqlite3_column_decltype16
|
||||
sqlite3_column_double
|
||||
sqlite3_column_int
|
||||
sqlite3_column_int64
|
||||
sqlite3_column_name
|
||||
sqlite3_column_name16
|
||||
sqlite3_column_text
|
||||
sqlite3_column_text16
|
||||
sqlite3_column_type
|
||||
sqlite3_column_value
|
||||
sqlite3_commit_hook
|
||||
sqlite3_complete
|
||||
sqlite3_complete16
|
||||
sqlite3_create_collation
|
||||
sqlite3_create_collation16
|
||||
sqlite3_create_collation_v2
|
||||
sqlite3_create_function
|
||||
sqlite3_create_function16
|
||||
sqlite3_create_module
|
||||
sqlite3_create_module_v2
|
||||
sqlite3_data_count
|
||||
sqlite3_db_handle
|
||||
sqlite3_declare_vtab
|
||||
sqlite3_enable_load_extension
|
||||
sqlite3_enable_shared_cache
|
||||
sqlite3_errcode
|
||||
sqlite3_errmsg
|
||||
sqlite3_errmsg16
|
||||
sqlite3_exec
|
||||
sqlite3_expired
|
||||
sqlite3_extended_result_codes
|
||||
sqlite3_finalize
|
||||
sqlite3_free
|
||||
sqlite3_free_table
|
||||
sqlite3_get_autocommit
|
||||
sqlite3_get_auxdata
|
||||
sqlite3_get_table
|
||||
sqlite3_global_recover
|
||||
sqlite3_interrupt
|
||||
sqlite3_last_insert_rowid
|
||||
sqlite3_libversion
|
||||
sqlite3_libversion_number
|
||||
sqlite3_load_extension
|
||||
sqlite3_malloc
|
||||
sqlite3_mprintf
|
||||
sqlite3_open
|
||||
sqlite3_open16
|
||||
sqlite3_overload_function
|
||||
sqlite3_prepare
|
||||
sqlite3_prepare16
|
||||
sqlite3_prepare16_v2
|
||||
sqlite3_prepare_v2
|
||||
sqlite3_profile
|
||||
sqlite3_progress_handler
|
||||
sqlite3_realloc
|
||||
sqlite3_reset
|
||||
sqlite3_reset_auto_extension
|
||||
sqlite3_result_blob
|
||||
sqlite3_result_double
|
||||
sqlite3_result_error
|
||||
sqlite3_result_error16
|
||||
sqlite3_result_error_toobig
|
||||
sqlite3_result_int
|
||||
sqlite3_result_int64
|
||||
sqlite3_result_null
|
||||
sqlite3_result_text
|
||||
sqlite3_result_text16
|
||||
sqlite3_result_text16be
|
||||
sqlite3_result_text16le
|
||||
sqlite3_result_value
|
||||
sqlite3_result_zeroblob
|
||||
sqlite3_rollback_hook
|
||||
sqlite3_set_authorizer
|
||||
sqlite3_set_auxdata
|
||||
sqlite3_sleep
|
||||
sqlite3_snprintf
|
||||
sqlite3_step
|
||||
sqlite3_thread_cleanup
|
||||
sqlite3_total_changes
|
||||
sqlite3_trace
|
||||
sqlite3_transfer_bindings
|
||||
sqlite3_update_hook
|
||||
sqlite3_user_data
|
||||
sqlite3_value_blob
|
||||
sqlite3_value_bytes
|
||||
sqlite3_value_bytes16
|
||||
sqlite3_value_double
|
||||
sqlite3_value_int
|
||||
sqlite3_value_int64
|
||||
sqlite3_value_numeric_type
|
||||
sqlite3_value_text
|
||||
sqlite3_value_text16
|
||||
sqlite3_value_text16be
|
||||
sqlite3_value_text16le
|
||||
sqlite3_value_type
|
||||
sqlite3_version
|
||||
sqlite3_vmprintf
|
|
@ -0,0 +1,497 @@
|
|||
<?xml version="1.0" encoding="Windows-1252"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="8.00"
|
||||
Name="sqlite_vs2005"
|
||||
ProjectGUID="{5E4E7BB0-CF29-493E-A983-C0E5FCF66F44}"
|
||||
RootNamespace="sqlite_vs2005"
|
||||
Keyword="Win32Proj"
|
||||
>
|
||||
<Platforms>
|
||||
<Platform
|
||||
Name="Win32"
|
||||
/>
|
||||
</Platforms>
|
||||
<ToolFiles>
|
||||
</ToolFiles>
|
||||
<Configurations>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
|
||||
MinimalRebuild="true"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="3"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="3"
|
||||
Detect64BitPortabilityProblems="true"
|
||||
DebugInformationFormat="4"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalDependencies="kernel32.lib $(NoInherit)"
|
||||
LinkIncremental="2"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="1"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebDeploymentTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="2"
|
||||
CharacterSet="1"
|
||||
WholeProgramOptimization="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
|
||||
RuntimeLibrary="2"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="3"
|
||||
Detect64BitPortabilityProblems="true"
|
||||
DebugInformationFormat="3"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalDependencies="kernel32.lib $(NoInherit)"
|
||||
LinkIncremental="1"
|
||||
AdditionalLibraryDirectories="Kernel32.lib"
|
||||
ModuleDefinitionFile="sqlite3.def"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="2"
|
||||
OptimizeReferences="2"
|
||||
EnableCOMDATFolding="2"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebDeploymentTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
</Configurations>
|
||||
<References>
|
||||
</References>
|
||||
<Files>
|
||||
<Filter
|
||||
Name="Source Files"
|
||||
Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
|
||||
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\..\alter.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\analyze.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\attach.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\auth.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\btmutex.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\btree.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\btree.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\btreeInt.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\build.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\callback.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\complete.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\date.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\delete.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\expr.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\fts1.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\fts1_hash.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\fts1_hash.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\fts1_porter.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\fts1_tokenizer.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\fts1_tokenizer1.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\func.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\hash.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\hash.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\insert.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\journal.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\keywordhash.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\legacy.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\loadext.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\main.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\malloc.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\mem1.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\mem2.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\mutex.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\mutex.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\mutex_w32.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\opcodes.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\opcodes.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\os.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\os.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\os_common.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\os_os2.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\os_unix.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\os_win.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\pager.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\pager.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\parse.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\parse.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\pragma.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\prepare.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\printf.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\random.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\select.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\shell.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\sqlite3.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\sqlite3ext.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\sqliteInt.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\sqliteLimit.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\table.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\tokenize.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\trigger.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\update.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\utf.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\util.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\vacuum.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\vdbe.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\vdbe.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\vdbeapi.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\vdbeaux.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\vdbeblob.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\vdbefifo.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\vdbeInt.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\vdbemem.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\vtab.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\where.c"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Header Files"
|
||||
Filter="h;hpp;hxx;hm;inl;inc;xsd"
|
||||
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
|
||||
>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Resource Files"
|
||||
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
|
||||
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
|
||||
>
|
||||
</Filter>
|
||||
<File
|
||||
RelativePath=".\ReadMe.txt"
|
||||
>
|
||||
</File>
|
||||
</Files>
|
||||
<Globals>
|
||||
</Globals>
|
||||
</VisualStudioProject>
|
|
@ -0,0 +1,65 @@
|
|||
<?xml version="1.0" encoding="Windows-1252"?>
|
||||
<VisualStudioUserFile
|
||||
ProjectType="Visual C++"
|
||||
Version="8.00"
|
||||
ShowAllFiles="false"
|
||||
>
|
||||
<Configurations>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
>
|
||||
<DebugSettings
|
||||
Command="$(TargetPath)"
|
||||
WorkingDirectory=""
|
||||
CommandArguments=""
|
||||
Attach="false"
|
||||
DebuggerType="3"
|
||||
Remote="1"
|
||||
RemoteMachine="DAN-PC"
|
||||
RemoteCommand=""
|
||||
HttpUrl=""
|
||||
PDBPath=""
|
||||
SQLDebugging=""
|
||||
Environment=""
|
||||
EnvironmentMerge="true"
|
||||
DebuggerFlavor=""
|
||||
MPIRunCommand=""
|
||||
MPIRunArguments=""
|
||||
MPIRunWorkingDirectory=""
|
||||
ApplicationCommand=""
|
||||
ApplicationArguments=""
|
||||
ShimCommand=""
|
||||
MPIAcceptMode=""
|
||||
MPIAcceptFilter=""
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
>
|
||||
<DebugSettings
|
||||
Command=""
|
||||
WorkingDirectory=""
|
||||
CommandArguments=""
|
||||
Attach="false"
|
||||
DebuggerType="3"
|
||||
Remote="1"
|
||||
RemoteMachine="DAN-PC"
|
||||
RemoteCommand=""
|
||||
HttpUrl=""
|
||||
PDBPath=""
|
||||
SQLDebugging=""
|
||||
Environment=""
|
||||
EnvironmentMerge="true"
|
||||
DebuggerFlavor=""
|
||||
MPIRunCommand=""
|
||||
MPIRunArguments=""
|
||||
MPIRunWorkingDirectory=""
|
||||
ApplicationCommand=""
|
||||
ApplicationArguments=""
|
||||
ShimCommand=""
|
||||
MPIAcceptMode=""
|
||||
MPIAcceptFilter=""
|
||||
/>
|
||||
</Configuration>
|
||||
</Configurations>
|
||||
</VisualStudioUserFile>
|
|
@ -0,0 +1,206 @@
|
|||
/*
|
||||
** 2001 September 15
|
||||
**
|
||||
** The author disclaims copyright to this source code. In place of
|
||||
** a legal notice, here is a blessing:
|
||||
**
|
||||
** May you do good and not evil.
|
||||
** May you find forgiveness for yourself and forgive others.
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
*************************************************************************
|
||||
** This file contains the sqlite3_get_table() and sqlite3_free_table()
|
||||
** interface routines. These are just wrappers around the main
|
||||
** interface routine of sqlite3_exec().
|
||||
**
|
||||
** These routines are in a separate files so that they will not be linked
|
||||
** if they are not used.
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifndef SQLITE_OMIT_GET_TABLE
|
||||
|
||||
/*
|
||||
** This structure is used to pass data from sqlite3_get_table() through
|
||||
** to the callback function is uses to build the result.
|
||||
*/
|
||||
typedef struct TabResult {
|
||||
char **azResult;
|
||||
char *zErrMsg;
|
||||
int nResult;
|
||||
int nAlloc;
|
||||
int nRow;
|
||||
int nColumn;
|
||||
int nData;
|
||||
int rc;
|
||||
} TabResult;
|
||||
|
||||
/*
|
||||
** This routine is called once for each row in the result table. Its job
|
||||
** is to fill in the TabResult structure appropriately, allocating new
|
||||
** memory as necessary.
|
||||
*/
|
||||
static int sqlite3_get_table_cb(void *pArg, int nCol, char **argv, char **colv){
|
||||
TabResult *p = (TabResult*)pArg;
|
||||
int need;
|
||||
int i;
|
||||
char *z;
|
||||
|
||||
/* Make sure there is enough space in p->azResult to hold everything
|
||||
** we need to remember from this invocation of the callback.
|
||||
*/
|
||||
if( p->nRow==0 && argv!=0 ){
|
||||
need = nCol*2;
|
||||
}else{
|
||||
need = nCol;
|
||||
}
|
||||
if( p->nData + need >= p->nAlloc ){
|
||||
char **azNew;
|
||||
p->nAlloc = p->nAlloc*2 + need + 1;
|
||||
azNew = sqlite3_realloc( p->azResult, sizeof(char*)*p->nAlloc );
|
||||
if( azNew==0 ) goto malloc_failed;
|
||||
p->azResult = azNew;
|
||||
}
|
||||
|
||||
/* If this is the first row, then generate an extra row containing
|
||||
** the names of all columns.
|
||||
*/
|
||||
if( p->nRow==0 ){
|
||||
p->nColumn = nCol;
|
||||
for(i=0; i<nCol; i++){
|
||||
if( colv[i]==0 ){
|
||||
z = sqlite3_mprintf("");
|
||||
}else{
|
||||
z = sqlite3_mprintf("%s", colv[i]);
|
||||
}
|
||||
p->azResult[p->nData++] = z;
|
||||
}
|
||||
}else if( p->nColumn!=nCol ){
|
||||
sqlite3SetString(&p->zErrMsg,
|
||||
"sqlite3_get_table() called with two or more incompatible queries",
|
||||
(char*)0);
|
||||
p->rc = SQLITE_ERROR;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Copy over the row data
|
||||
*/
|
||||
if( argv!=0 ){
|
||||
for(i=0; i<nCol; i++){
|
||||
if( argv[i]==0 ){
|
||||
z = 0;
|
||||
}else{
|
||||
int n = strlen(argv[i])+1;
|
||||
z = sqlite3_malloc( n );
|
||||
if( z==0 ) goto malloc_failed;
|
||||
memcpy(z, argv[i], n);
|
||||
}
|
||||
p->azResult[p->nData++] = z;
|
||||
}
|
||||
p->nRow++;
|
||||
}
|
||||
return 0;
|
||||
|
||||
malloc_failed:
|
||||
p->rc = SQLITE_NOMEM;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
** Query the database. But instead of invoking a callback for each row,
|
||||
** malloc() for space to hold the result and return the entire results
|
||||
** at the conclusion of the call.
|
||||
**
|
||||
** The result that is written to ***pazResult is held in memory obtained
|
||||
** from malloc(). But the caller cannot free this memory directly.
|
||||
** Instead, the entire table should be passed to sqlite3_free_table() when
|
||||
** the calling procedure is finished using it.
|
||||
*/
|
||||
int sqlite3_get_table(
|
||||
sqlite3 *db, /* The database on which the SQL executes */
|
||||
const char *zSql, /* The SQL to be executed */
|
||||
char ***pazResult, /* Write the result table here */
|
||||
int *pnRow, /* Write the number of rows in the result here */
|
||||
int *pnColumn, /* Write the number of columns of result here */
|
||||
char **pzErrMsg /* Write error messages here */
|
||||
){
|
||||
int rc;
|
||||
TabResult res;
|
||||
if( pazResult==0 ){ return SQLITE_ERROR; }
|
||||
*pazResult = 0;
|
||||
if( pnColumn ) *pnColumn = 0;
|
||||
if( pnRow ) *pnRow = 0;
|
||||
res.zErrMsg = 0;
|
||||
res.nResult = 0;
|
||||
res.nRow = 0;
|
||||
res.nColumn = 0;
|
||||
res.nData = 1;
|
||||
res.nAlloc = 20;
|
||||
res.rc = SQLITE_OK;
|
||||
res.azResult = sqlite3_malloc( sizeof(char*)*res.nAlloc );
|
||||
if( res.azResult==0 ) return SQLITE_NOMEM;
|
||||
res.azResult[0] = 0;
|
||||
rc = sqlite3_exec(db, zSql, sqlite3_get_table_cb, &res, pzErrMsg);
|
||||
#ifndef NDEBUG
|
||||
sqlite3_mutex_enter(db->mutex);
|
||||
assert((rc&db->errMask)==rc && (res.rc&db->errMask)==res.rc);
|
||||
sqlite3_mutex_leave(db->mutex);
|
||||
#endif
|
||||
if( res.azResult ){
|
||||
assert( sizeof(res.azResult[0])>= sizeof(res.nData) );
|
||||
res.azResult[0] = (char*)res.nData;
|
||||
}
|
||||
if( (rc&0xff)==SQLITE_ABORT ){
|
||||
sqlite3_free_table(&res.azResult[1]);
|
||||
if( res.zErrMsg ){
|
||||
if( pzErrMsg ){
|
||||
sqlite3_free(*pzErrMsg);
|
||||
*pzErrMsg = sqlite3_mprintf("%s",res.zErrMsg);
|
||||
}
|
||||
sqlite3_free(res.zErrMsg);
|
||||
}
|
||||
sqlite3_mutex_enter(db->mutex);
|
||||
db->errCode = res.rc;
|
||||
sqlite3_mutex_leave(db->mutex);
|
||||
return res.rc;
|
||||
}
|
||||
sqlite3_free(res.zErrMsg);
|
||||
if( rc!=SQLITE_OK ){
|
||||
sqlite3_free_table(&res.azResult[1]);
|
||||
return rc;
|
||||
}
|
||||
if( res.nAlloc>res.nData ){
|
||||
char **azNew;
|
||||
azNew = sqlite3_realloc( res.azResult, sizeof(char*)*(res.nData+1) );
|
||||
if( azNew==0 ){
|
||||
sqlite3_free_table(&res.azResult[1]);
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
res.nAlloc = res.nData+1;
|
||||
res.azResult = azNew;
|
||||
}
|
||||
*pazResult = &res.azResult[1];
|
||||
if( pnColumn ) *pnColumn = res.nColumn;
|
||||
if( pnRow ) *pnRow = res.nRow;
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** This routine frees the space the sqlite3_get_table() malloced.
|
||||
*/
|
||||
void sqlite3_free_table(
|
||||
char **azResult /* Result returned from from sqlite3_get_table() */
|
||||
){
|
||||
if( azResult ){
|
||||
int i, n;
|
||||
azResult--;
|
||||
if( azResult==0 ) return;
|
||||
n = (int)azResult[0];
|
||||
for(i=1; i<n; i++){ if( azResult[i] ) sqlite3_free(azResult[i]); }
|
||||
sqlite3_free(azResult);
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* SQLITE_OMIT_GET_TABLE */
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,508 @@
|
|||
/*
|
||||
** 2001 September 15
|
||||
**
|
||||
** The author disclaims copyright to this source code. In place of
|
||||
** a legal notice, here is a blessing:
|
||||
**
|
||||
** May you do good and not evil.
|
||||
** May you find forgiveness for yourself and forgive others.
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
*************************************************************************
|
||||
** An tokenizer for SQL
|
||||
**
|
||||
** This file contains C code that splits an SQL input string up into
|
||||
** individual tokens and sends those tokens one-by-one over to the
|
||||
** parser for analysis.
|
||||
**
|
||||
** $Id: tokenize.c,v 1.136 2007/08/27 23:26:59 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include <ctype.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/*
|
||||
** The charMap() macro maps alphabetic characters into their
|
||||
** lower-case ASCII equivalent. On ASCII machines, this is just
|
||||
** an upper-to-lower case map. On EBCDIC machines we also need
|
||||
** to adjust the encoding. Only alphabetic characters and underscores
|
||||
** need to be translated.
|
||||
*/
|
||||
#ifdef SQLITE_ASCII
|
||||
# define charMap(X) sqlite3UpperToLower[(unsigned char)X]
|
||||
#endif
|
||||
#ifdef SQLITE_EBCDIC
|
||||
# define charMap(X) ebcdicToAscii[(unsigned char)X]
|
||||
const unsigned char ebcdicToAscii[] = {
|
||||
/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1x */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 2x */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 3x */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 4x */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 5x */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 95, 0, 0, /* 6x */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 7x */
|
||||
0, 97, 98, 99,100,101,102,103,104,105, 0, 0, 0, 0, 0, 0, /* 8x */
|
||||
0,106,107,108,109,110,111,112,113,114, 0, 0, 0, 0, 0, 0, /* 9x */
|
||||
0, 0,115,116,117,118,119,120,121,122, 0, 0, 0, 0, 0, 0, /* Ax */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* Bx */
|
||||
0, 97, 98, 99,100,101,102,103,104,105, 0, 0, 0, 0, 0, 0, /* Cx */
|
||||
0,106,107,108,109,110,111,112,113,114, 0, 0, 0, 0, 0, 0, /* Dx */
|
||||
0, 0,115,116,117,118,119,120,121,122, 0, 0, 0, 0, 0, 0, /* Ex */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* Fx */
|
||||
};
|
||||
#endif
|
||||
|
||||
/*
|
||||
** The sqlite3KeywordCode function looks up an identifier to determine if
|
||||
** it is a keyword. If it is a keyword, the token code of that keyword is
|
||||
** returned. If the input is not a keyword, TK_ID is returned.
|
||||
**
|
||||
** The implementation of this routine was generated by a program,
|
||||
** mkkeywordhash.h, located in the tool subdirectory of the distribution.
|
||||
** The output of the mkkeywordhash.c program is written into a file
|
||||
** named keywordhash.h and then included into this source file by
|
||||
** the #include below.
|
||||
*/
|
||||
#include "keywordhash.h"
|
||||
|
||||
|
||||
/*
|
||||
** If X is a character that can be used in an identifier then
|
||||
** IdChar(X) will be true. Otherwise it is false.
|
||||
**
|
||||
** For ASCII, any character with the high-order bit set is
|
||||
** allowed in an identifier. For 7-bit characters,
|
||||
** sqlite3IsIdChar[X] must be 1.
|
||||
**
|
||||
** For EBCDIC, the rules are more complex but have the same
|
||||
** end result.
|
||||
**
|
||||
** Ticket #1066. the SQL standard does not allow '$' in the
|
||||
** middle of identfiers. But many SQL implementations do.
|
||||
** SQLite will allow '$' in identifiers for compatibility.
|
||||
** But the feature is undocumented.
|
||||
*/
|
||||
#ifdef SQLITE_ASCII
|
||||
const char sqlite3IsAsciiIdChar[] = {
|
||||
/* x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF */
|
||||
0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 2x */
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, /* 3x */
|
||||
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 4x */
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, /* 5x */
|
||||
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 */
|
||||
};
|
||||
#define IdChar(C) (((c=C)&0x80)!=0 || (c>0x1f && sqlite3IsAsciiIdChar[c-0x20]))
|
||||
#endif
|
||||
#ifdef SQLITE_EBCDIC
|
||||
const char sqlite3IsEbcdicIdChar[] = {
|
||||
/* 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, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, /* 5x */
|
||||
0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, /* 6x */
|
||||
0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, /* 7x */
|
||||
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, /* 8x */
|
||||
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 0, /* 9x */
|
||||
1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, /* Ax */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* Bx */
|
||||
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, /* Cx */
|
||||
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, /* Dx */
|
||||
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 */
|
||||
};
|
||||
#define IdChar(C) (((c=C)>=0x42 && sqlite3IsEbcdicIdChar[c-0x40]))
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
** Return the length of the token that begins at z[0].
|
||||
** Store the token type in *tokenType before returning.
|
||||
*/
|
||||
static int getToken(const unsigned char *z, int *tokenType){
|
||||
int i, c;
|
||||
switch( *z ){
|
||||
case ' ': case '\t': case '\n': case '\f': case '\r': {
|
||||
for(i=1; isspace(z[i]); i++){}
|
||||
*tokenType = TK_SPACE;
|
||||
return i;
|
||||
}
|
||||
case '-': {
|
||||
if( z[1]=='-' ){
|
||||
for(i=2; (c=z[i])!=0 && c!='\n'; i++){}
|
||||
*tokenType = TK_COMMENT;
|
||||
return i;
|
||||
}
|
||||
*tokenType = TK_MINUS;
|
||||
return 1;
|
||||
}
|
||||
case '(': {
|
||||
*tokenType = TK_LP;
|
||||
return 1;
|
||||
}
|
||||
case ')': {
|
||||
*tokenType = TK_RP;
|
||||
return 1;
|
||||
}
|
||||
case ';': {
|
||||
*tokenType = TK_SEMI;
|
||||
return 1;
|
||||
}
|
||||
case '+': {
|
||||
*tokenType = TK_PLUS;
|
||||
return 1;
|
||||
}
|
||||
case '*': {
|
||||
*tokenType = TK_STAR;
|
||||
return 1;
|
||||
}
|
||||
case '/': {
|
||||
if( z[1]!='*' || z[2]==0 ){
|
||||
*tokenType = TK_SLASH;
|
||||
return 1;
|
||||
}
|
||||
for(i=3, c=z[2]; (c!='*' || z[i]!='/') && (c=z[i])!=0; i++){}
|
||||
if( c ) i++;
|
||||
*tokenType = TK_COMMENT;
|
||||
return i;
|
||||
}
|
||||
case '%': {
|
||||
*tokenType = TK_REM;
|
||||
return 1;
|
||||
}
|
||||
case '=': {
|
||||
*tokenType = TK_EQ;
|
||||
return 1 + (z[1]=='=');
|
||||
}
|
||||
case '<': {
|
||||
if( (c=z[1])=='=' ){
|
||||
*tokenType = TK_LE;
|
||||
return 2;
|
||||
}else if( c=='>' ){
|
||||
*tokenType = TK_NE;
|
||||
return 2;
|
||||
}else if( c=='<' ){
|
||||
*tokenType = TK_LSHIFT;
|
||||
return 2;
|
||||
}else{
|
||||
*tokenType = TK_LT;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
case '>': {
|
||||
if( (c=z[1])=='=' ){
|
||||
*tokenType = TK_GE;
|
||||
return 2;
|
||||
}else if( c=='>' ){
|
||||
*tokenType = TK_RSHIFT;
|
||||
return 2;
|
||||
}else{
|
||||
*tokenType = TK_GT;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
case '!': {
|
||||
if( z[1]!='=' ){
|
||||
*tokenType = TK_ILLEGAL;
|
||||
return 2;
|
||||
}else{
|
||||
*tokenType = TK_NE;
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
case '|': {
|
||||
if( z[1]!='|' ){
|
||||
*tokenType = TK_BITOR;
|
||||
return 1;
|
||||
}else{
|
||||
*tokenType = TK_CONCAT;
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
case ',': {
|
||||
*tokenType = TK_COMMA;
|
||||
return 1;
|
||||
}
|
||||
case '&': {
|
||||
*tokenType = TK_BITAND;
|
||||
return 1;
|
||||
}
|
||||
case '~': {
|
||||
*tokenType = TK_BITNOT;
|
||||
return 1;
|
||||
}
|
||||
case '`':
|
||||
case '\'':
|
||||
case '"': {
|
||||
int delim = z[0];
|
||||
for(i=1; (c=z[i])!=0; i++){
|
||||
if( c==delim ){
|
||||
if( z[i+1]==delim ){
|
||||
i++;
|
||||
}else{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if( c ){
|
||||
*tokenType = TK_STRING;
|
||||
return i+1;
|
||||
}else{
|
||||
*tokenType = TK_ILLEGAL;
|
||||
return i;
|
||||
}
|
||||
}
|
||||
case '.': {
|
||||
#ifndef SQLITE_OMIT_FLOATING_POINT
|
||||
if( !isdigit(z[1]) )
|
||||
#endif
|
||||
{
|
||||
*tokenType = TK_DOT;
|
||||
return 1;
|
||||
}
|
||||
/* If the next character is a digit, this is a floating point
|
||||
** number that begins with ".". Fall thru into the next case */
|
||||
}
|
||||
case '0': case '1': case '2': case '3': case '4':
|
||||
case '5': case '6': case '7': case '8': case '9': {
|
||||
*tokenType = TK_INTEGER;
|
||||
for(i=0; isdigit(z[i]); i++){}
|
||||
#ifndef SQLITE_OMIT_FLOATING_POINT
|
||||
if( z[i]=='.' ){
|
||||
i++;
|
||||
while( isdigit(z[i]) ){ i++; }
|
||||
*tokenType = TK_FLOAT;
|
||||
}
|
||||
if( (z[i]=='e' || z[i]=='E') &&
|
||||
( isdigit(z[i+1])
|
||||
|| ((z[i+1]=='+' || z[i+1]=='-') && isdigit(z[i+2]))
|
||||
)
|
||||
){
|
||||
i += 2;
|
||||
while( isdigit(z[i]) ){ i++; }
|
||||
*tokenType = TK_FLOAT;
|
||||
}
|
||||
#endif
|
||||
while( IdChar(z[i]) ){
|
||||
*tokenType = TK_ILLEGAL;
|
||||
i++;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
case '[': {
|
||||
for(i=1, c=z[0]; c!=']' && (c=z[i])!=0; i++){}
|
||||
*tokenType = TK_ID;
|
||||
return i;
|
||||
}
|
||||
case '?': {
|
||||
*tokenType = TK_VARIABLE;
|
||||
for(i=1; isdigit(z[i]); i++){}
|
||||
return i;
|
||||
}
|
||||
case '#': {
|
||||
for(i=1; isdigit(z[i]); i++){}
|
||||
if( i>1 ){
|
||||
/* Parameters of the form #NNN (where NNN is a number) are used
|
||||
** internally by sqlite3NestedParse. */
|
||||
*tokenType = TK_REGISTER;
|
||||
return i;
|
||||
}
|
||||
/* Fall through into the next case if the '#' is not followed by
|
||||
** a digit. Try to match #AAAA where AAAA is a parameter name. */
|
||||
}
|
||||
#ifndef SQLITE_OMIT_TCL_VARIABLE
|
||||
case '$':
|
||||
#endif
|
||||
case '@': /* For compatibility with MS SQL Server */
|
||||
case ':': {
|
||||
int n = 0;
|
||||
*tokenType = TK_VARIABLE;
|
||||
for(i=1; (c=z[i])!=0; i++){
|
||||
if( IdChar(c) ){
|
||||
n++;
|
||||
#ifndef SQLITE_OMIT_TCL_VARIABLE
|
||||
}else if( c=='(' && n>0 ){
|
||||
do{
|
||||
i++;
|
||||
}while( (c=z[i])!=0 && !isspace(c) && c!=')' );
|
||||
if( c==')' ){
|
||||
i++;
|
||||
}else{
|
||||
*tokenType = TK_ILLEGAL;
|
||||
}
|
||||
break;
|
||||
}else if( c==':' && z[i+1]==':' ){
|
||||
i++;
|
||||
#endif
|
||||
}else{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( n==0 ) *tokenType = TK_ILLEGAL;
|
||||
return i;
|
||||
}
|
||||
#ifndef SQLITE_OMIT_BLOB_LITERAL
|
||||
case 'x': case 'X': {
|
||||
if( (c=z[1])=='\'' || c=='"' ){
|
||||
int delim = c;
|
||||
*tokenType = TK_BLOB;
|
||||
for(i=2; (c=z[i])!=0; i++){
|
||||
if( c==delim ){
|
||||
if( i%2 ) *tokenType = TK_ILLEGAL;
|
||||
break;
|
||||
}
|
||||
if( !isxdigit(c) ){
|
||||
*tokenType = TK_ILLEGAL;
|
||||
return i;
|
||||
}
|
||||
}
|
||||
if( c ) i++;
|
||||
return i;
|
||||
}
|
||||
/* Otherwise fall through to the next case */
|
||||
}
|
||||
#endif
|
||||
default: {
|
||||
if( !IdChar(*z) ){
|
||||
break;
|
||||
}
|
||||
for(i=1; IdChar(z[i]); i++){}
|
||||
*tokenType = keywordCode((char*)z, i);
|
||||
return i;
|
||||
}
|
||||
}
|
||||
*tokenType = TK_ILLEGAL;
|
||||
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
|
||||
** passed in. An SQLITE_ status code is returned. If an error occurs
|
||||
** and pzErrMsg!=NULL then an error message might be written into
|
||||
** memory obtained from sqlite3_malloc() and *pzErrMsg made to point to that
|
||||
** error message. Or maybe not.
|
||||
*/
|
||||
int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzErrMsg){
|
||||
int nErr = 0;
|
||||
int i;
|
||||
void *pEngine;
|
||||
int tokenType;
|
||||
int lastTokenParsed = -1;
|
||||
sqlite3 *db = pParse->db;
|
||||
|
||||
if( db->activeVdbeCnt==0 ){
|
||||
db->u1.isInterrupted = 0;
|
||||
}
|
||||
pParse->rc = SQLITE_OK;
|
||||
i = 0;
|
||||
pEngine = sqlite3ParserAlloc((void*(*)(size_t))sqlite3_malloc);
|
||||
if( pEngine==0 ){
|
||||
db->mallocFailed = 1;
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
assert( pParse->sLastToken.dyn==0 );
|
||||
assert( pParse->pNewTable==0 );
|
||||
assert( pParse->pNewTrigger==0 );
|
||||
assert( pParse->nVar==0 );
|
||||
assert( pParse->nVarExpr==0 );
|
||||
assert( pParse->nVarExprAlloc==0 );
|
||||
assert( pParse->apVarExpr==0 );
|
||||
pParse->zTail = pParse->zSql = zSql;
|
||||
while( !db->mallocFailed && zSql[i]!=0 ){
|
||||
assert( i>=0 );
|
||||
pParse->sLastToken.z = (u8*)&zSql[i];
|
||||
assert( pParse->sLastToken.dyn==0 );
|
||||
pParse->sLastToken.n = getToken((unsigned char*)&zSql[i],&tokenType);
|
||||
i += pParse->sLastToken.n;
|
||||
if( i>SQLITE_MAX_SQL_LENGTH ){
|
||||
pParse->rc = SQLITE_TOOBIG;
|
||||
break;
|
||||
}
|
||||
switch( tokenType ){
|
||||
case TK_SPACE:
|
||||
case TK_COMMENT: {
|
||||
if( db->u1.isInterrupted ){
|
||||
pParse->rc = SQLITE_INTERRUPT;
|
||||
sqlite3SetString(pzErrMsg, "interrupt", (char*)0);
|
||||
goto abort_parse;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TK_ILLEGAL: {
|
||||
if( pzErrMsg ){
|
||||
sqlite3_free(*pzErrMsg);
|
||||
*pzErrMsg = sqlite3MPrintf(db, "unrecognized token: \"%T\"",
|
||||
&pParse->sLastToken);
|
||||
}
|
||||
nErr++;
|
||||
goto abort_parse;
|
||||
}
|
||||
case TK_SEMI: {
|
||||
pParse->zTail = &zSql[i];
|
||||
/* Fall thru into the default case */
|
||||
}
|
||||
default: {
|
||||
sqlite3Parser(pEngine, tokenType, pParse->sLastToken, pParse);
|
||||
lastTokenParsed = tokenType;
|
||||
if( pParse->rc!=SQLITE_OK ){
|
||||
goto abort_parse;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
abort_parse:
|
||||
if( zSql[i]==0 && nErr==0 && pParse->rc==SQLITE_OK ){
|
||||
if( lastTokenParsed!=TK_SEMI ){
|
||||
sqlite3Parser(pEngine, TK_SEMI, pParse->sLastToken, pParse);
|
||||
pParse->zTail = &zSql[i];
|
||||
}
|
||||
sqlite3Parser(pEngine, 0, pParse->sLastToken, pParse);
|
||||
}
|
||||
sqlite3ParserFree(pEngine, sqlite3_free);
|
||||
if( db->mallocFailed ){
|
||||
pParse->rc = SQLITE_NOMEM;
|
||||
}
|
||||
if( pParse->rc!=SQLITE_OK && pParse->rc!=SQLITE_DONE && pParse->zErrMsg==0 ){
|
||||
sqlite3SetString(&pParse->zErrMsg, sqlite3ErrStr(pParse->rc), (char*)0);
|
||||
}
|
||||
if( pParse->zErrMsg ){
|
||||
if( pzErrMsg && *pzErrMsg==0 ){
|
||||
*pzErrMsg = pParse->zErrMsg;
|
||||
}else{
|
||||
sqlite3_free(pParse->zErrMsg);
|
||||
}
|
||||
pParse->zErrMsg = 0;
|
||||
if( !nErr ) nErr++;
|
||||
}
|
||||
if( pParse->pVdbe && pParse->nErr>0 && pParse->nested==0 ){
|
||||
sqlite3VdbeDelete(pParse->pVdbe);
|
||||
pParse->pVdbe = 0;
|
||||
}
|
||||
#ifndef SQLITE_OMIT_SHARED_CACHE
|
||||
if( pParse->nested==0 ){
|
||||
sqlite3_free(pParse->aTableLock);
|
||||
pParse->aTableLock = 0;
|
||||
pParse->nTableLock = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
if( !IN_DECLARE_VTAB ){
|
||||
/* If the pParse->declareVtab flag is set, do not delete any table
|
||||
** structure built up in pParse->pNewTable. The calling code (see vtab.c)
|
||||
** will take responsibility for freeing the Table structure.
|
||||
*/
|
||||
sqlite3DeleteTable(pParse->pNewTable);
|
||||
}
|
||||
|
||||
sqlite3DeleteTrigger(pParse->pNewTrigger);
|
||||
sqlite3_free(pParse->apVarExpr);
|
||||
if( nErr>0 && (pParse->rc==SQLITE_OK || pParse->rc==SQLITE_DONE) ){
|
||||
pParse->rc = SQLITE_ERROR;
|
||||
}
|
||||
return nErr;
|
||||
}
|
|
@ -0,0 +1,839 @@
|
|||
/*
|
||||
**
|
||||
** 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 "sqliteInt.h"
|
||||
|
||||
#ifndef SQLITE_OMIT_TRIGGER
|
||||
/*
|
||||
** Delete a linked list of TriggerStep structures.
|
||||
*/
|
||||
void sqlite3DeleteTriggerStep(TriggerStep *pTriggerStep){
|
||||
while( pTriggerStep ){
|
||||
TriggerStep * pTmp = pTriggerStep;
|
||||
pTriggerStep = pTriggerStep->pNext;
|
||||
|
||||
if( pTmp->target.dyn ) sqlite3_free((char*)pTmp->target.z);
|
||||
sqlite3ExprDelete(pTmp->pWhere);
|
||||
sqlite3ExprListDelete(pTmp->pExprList);
|
||||
sqlite3SelectDelete(pTmp->pSelect);
|
||||
sqlite3IdListDelete(pTmp->pIdList);
|
||||
|
||||
sqlite3_free(pTmp);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** This is called by the parser when it sees a CREATE TRIGGER statement
|
||||
** up to the point of the BEGIN before the trigger actions. A Trigger
|
||||
** structure is generated based on the information available and stored
|
||||
** in pParse->pNewTrigger. After the trigger actions have been parsed, the
|
||||
** sqlite3FinishTrigger() function is called to complete the trigger
|
||||
** construction process.
|
||||
*/
|
||||
void sqlite3BeginTrigger(
|
||||
Parse *pParse, /* The parse context of the CREATE TRIGGER statement */
|
||||
Token *pName1, /* The name of the trigger */
|
||||
Token *pName2, /* The name of the trigger */
|
||||
int tr_tm, /* One of TK_BEFORE, TK_AFTER, TK_INSTEAD */
|
||||
int op, /* One of TK_INSERT, TK_UPDATE, TK_DELETE */
|
||||
IdList *pColumns, /* column list if this is an UPDATE OF trigger */
|
||||
SrcList *pTableName,/* The name of the table/view the trigger applies to */
|
||||
Expr *pWhen, /* WHEN clause */
|
||||
int isTemp, /* True if the TEMPORARY keyword is present */
|
||||
int noErr /* Suppress errors if the trigger already exists */
|
||||
){
|
||||
Trigger *pTrigger = 0;
|
||||
Table *pTab;
|
||||
char *zName = 0; /* Name of the trigger */
|
||||
sqlite3 *db = pParse->db;
|
||||
int iDb; /* The database to store the trigger in */
|
||||
Token *pName; /* The unqualified db name */
|
||||
DbFixer sFix;
|
||||
int iTabDb;
|
||||
|
||||
assert( pName1!=0 ); /* pName1->z might be NULL, but not pName1 itself */
|
||||
assert( pName2!=0 );
|
||||
if( isTemp ){
|
||||
/* If TEMP was specified, then the trigger name may not be qualified. */
|
||||
if( pName2->n>0 ){
|
||||
sqlite3ErrorMsg(pParse, "temporary trigger may not have qualified name");
|
||||
goto trigger_cleanup;
|
||||
}
|
||||
iDb = 1;
|
||||
pName = pName1;
|
||||
}else{
|
||||
/* Figure out the db that the the trigger will be created in */
|
||||
iDb = sqlite3TwoPartName(pParse, pName1, pName2, &pName);
|
||||
if( iDb<0 ){
|
||||
goto trigger_cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
/* If the trigger name was unqualified, and the table is a temp table,
|
||||
** then set iDb to 1 to create the trigger in the temporary database.
|
||||
** If sqlite3SrcListLookup() returns 0, indicating the table does not
|
||||
** exist, the error is caught by the block below.
|
||||
*/
|
||||
if( !pTableName || db->mallocFailed ){
|
||||
goto trigger_cleanup;
|
||||
}
|
||||
pTab = sqlite3SrcListLookup(pParse, pTableName);
|
||||
if( pName2->n==0 && pTab && pTab->pSchema==db->aDb[1].pSchema ){
|
||||
iDb = 1;
|
||||
}
|
||||
|
||||
/* Ensure the table name matches database name and that the table exists */
|
||||
if( db->mallocFailed ) goto trigger_cleanup;
|
||||
assert( pTableName->nSrc==1 );
|
||||
if( sqlite3FixInit(&sFix, pParse, iDb, "trigger", pName) &&
|
||||
sqlite3FixSrcList(&sFix, pTableName) ){
|
||||
goto trigger_cleanup;
|
||||
}
|
||||
pTab = sqlite3SrcListLookup(pParse, pTableName);
|
||||
if( !pTab ){
|
||||
/* The table does not exist. */
|
||||
goto trigger_cleanup;
|
||||
}
|
||||
if( IsVirtual(pTab) ){
|
||||
sqlite3ErrorMsg(pParse, "cannot create triggers on virtual tables");
|
||||
goto trigger_cleanup;
|
||||
}
|
||||
|
||||
/* Check that the trigger name is not reserved and that no trigger of the
|
||||
** specified name exists */
|
||||
zName = sqlite3NameFromToken(db, pName);
|
||||
if( !zName || SQLITE_OK!=sqlite3CheckObjectName(pParse, zName) ){
|
||||
goto trigger_cleanup;
|
||||
}
|
||||
if( sqlite3HashFind(&(db->aDb[iDb].pSchema->trigHash), zName,strlen(zName)) ){
|
||||
if( !noErr ){
|
||||
sqlite3ErrorMsg(pParse, "trigger %T already exists", pName);
|
||||
}
|
||||
goto trigger_cleanup;
|
||||
}
|
||||
|
||||
/* Do not create a trigger on a system table */
|
||||
if( sqlite3StrNICmp(pTab->zName, "sqlite_", 7)==0 ){
|
||||
sqlite3ErrorMsg(pParse, "cannot create trigger on system table");
|
||||
pParse->nErr++;
|
||||
goto trigger_cleanup;
|
||||
}
|
||||
|
||||
/* INSTEAD of triggers are only for views and views only support INSTEAD
|
||||
** of triggers.
|
||||
*/
|
||||
if( pTab->pSelect && tr_tm!=TK_INSTEAD ){
|
||||
sqlite3ErrorMsg(pParse, "cannot create %s trigger on view: %S",
|
||||
(tr_tm == TK_BEFORE)?"BEFORE":"AFTER", pTableName, 0);
|
||||
goto trigger_cleanup;
|
||||
}
|
||||
if( !pTab->pSelect && tr_tm==TK_INSTEAD ){
|
||||
sqlite3ErrorMsg(pParse, "cannot create INSTEAD OF"
|
||||
" trigger on table: %S", pTableName, 0);
|
||||
goto trigger_cleanup;
|
||||
}
|
||||
iTabDb = sqlite3SchemaToIndex(db, pTab->pSchema);
|
||||
|
||||
#ifndef SQLITE_OMIT_AUTHORIZATION
|
||||
{
|
||||
int code = SQLITE_CREATE_TRIGGER;
|
||||
const char *zDb = db->aDb[iTabDb].zName;
|
||||
const char *zDbTrig = isTemp ? db->aDb[1].zName : zDb;
|
||||
if( iTabDb==1 || isTemp ) code = SQLITE_CREATE_TEMP_TRIGGER;
|
||||
if( sqlite3AuthCheck(pParse, code, zName, pTab->zName, zDbTrig) ){
|
||||
goto trigger_cleanup;
|
||||
}
|
||||
if( sqlite3AuthCheck(pParse, SQLITE_INSERT, SCHEMA_TABLE(iTabDb),0,zDb)){
|
||||
goto trigger_cleanup;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* INSTEAD OF triggers can only appear on views and BEFORE triggers
|
||||
** cannot appear on views. So we might as well translate every
|
||||
** INSTEAD OF trigger into a BEFORE trigger. It simplifies code
|
||||
** elsewhere.
|
||||
*/
|
||||
if (tr_tm == TK_INSTEAD){
|
||||
tr_tm = TK_BEFORE;
|
||||
}
|
||||
|
||||
/* Build the Trigger object */
|
||||
pTrigger = (Trigger*)sqlite3DbMallocZero(db, sizeof(Trigger));
|
||||
if( pTrigger==0 ) goto trigger_cleanup;
|
||||
pTrigger->name = zName;
|
||||
zName = 0;
|
||||
pTrigger->table = sqlite3DbStrDup(db, pTableName->a[0].zName);
|
||||
pTrigger->pSchema = db->aDb[iDb].pSchema;
|
||||
pTrigger->pTabSchema = pTab->pSchema;
|
||||
pTrigger->op = op;
|
||||
pTrigger->tr_tm = tr_tm==TK_BEFORE ? TRIGGER_BEFORE : TRIGGER_AFTER;
|
||||
pTrigger->pWhen = sqlite3ExprDup(db, pWhen);
|
||||
pTrigger->pColumns = sqlite3IdListDup(db, pColumns);
|
||||
sqlite3TokenCopy(db, &pTrigger->nameToken,pName);
|
||||
assert( pParse->pNewTrigger==0 );
|
||||
pParse->pNewTrigger = pTrigger;
|
||||
|
||||
trigger_cleanup:
|
||||
sqlite3_free(zName);
|
||||
sqlite3SrcListDelete(pTableName);
|
||||
sqlite3IdListDelete(pColumns);
|
||||
sqlite3ExprDelete(pWhen);
|
||||
if( !pParse->pNewTrigger ){
|
||||
sqlite3DeleteTrigger(pTrigger);
|
||||
}else{
|
||||
assert( pParse->pNewTrigger==pTrigger );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** This routine is called after all of the trigger actions have been parsed
|
||||
** in order to complete the process of building the trigger.
|
||||
*/
|
||||
void sqlite3FinishTrigger(
|
||||
Parse *pParse, /* Parser context */
|
||||
TriggerStep *pStepList, /* The triggered program */
|
||||
Token *pAll /* Token that describes the complete CREATE TRIGGER */
|
||||
){
|
||||
Trigger *pTrig = 0; /* The trigger whose construction is finishing up */
|
||||
sqlite3 *db = pParse->db; /* The database */
|
||||
DbFixer sFix;
|
||||
int iDb; /* Database containing the trigger */
|
||||
|
||||
pTrig = pParse->pNewTrigger;
|
||||
pParse->pNewTrigger = 0;
|
||||
if( pParse->nErr || !pTrig ) goto triggerfinish_cleanup;
|
||||
iDb = sqlite3SchemaToIndex(pParse->db, pTrig->pSchema);
|
||||
pTrig->step_list = pStepList;
|
||||
while( pStepList ){
|
||||
pStepList->pTrig = pTrig;
|
||||
pStepList = pStepList->pNext;
|
||||
}
|
||||
if( sqlite3FixInit(&sFix, pParse, iDb, "trigger", &pTrig->nameToken)
|
||||
&& sqlite3FixTriggerStep(&sFix, pTrig->step_list) ){
|
||||
goto triggerfinish_cleanup;
|
||||
}
|
||||
|
||||
/* if we are not initializing, and this trigger is not on a TEMP table,
|
||||
** build the sqlite_master entry
|
||||
*/
|
||||
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;
|
||||
|
||||
/* Make an entry in the sqlite_master table */
|
||||
v = sqlite3GetVdbe(pParse);
|
||||
if( v==0 ) goto triggerfinish_cleanup;
|
||||
sqlite3BeginWriteOperation(pParse, 0, iDb);
|
||||
sqlite3OpenMasterTable(pParse, iDb);
|
||||
addr = sqlite3VdbeAddOpList(v, ArraySize(insertTrig), insertTrig);
|
||||
sqlite3VdbeChangeP3(v, addr+2, pTrig->name, 0);
|
||||
sqlite3VdbeChangeP3(v, addr+3, pTrig->table, 0);
|
||||
sqlite3VdbeChangeP3(v, addr+6, (char*)pAll->z, pAll->n);
|
||||
sqlite3ChangeCookie(db, v, iDb);
|
||||
sqlite3VdbeAddOp(v, OP_Close, 0, 0);
|
||||
sqlite3VdbeOp3(v, OP_ParseSchema, iDb, 0, sqlite3MPrintf(
|
||||
db, "type='trigger' AND name='%q'", pTrig->name), P3_DYNAMIC
|
||||
);
|
||||
}
|
||||
|
||||
if( db->init.busy ){
|
||||
int n;
|
||||
Table *pTab;
|
||||
Trigger *pDel;
|
||||
pDel = sqlite3HashInsert(&db->aDb[iDb].pSchema->trigHash,
|
||||
pTrig->name, strlen(pTrig->name), pTrig);
|
||||
if( pDel ){
|
||||
assert( pDel==pTrig );
|
||||
db->mallocFailed = 1;
|
||||
goto triggerfinish_cleanup;
|
||||
}
|
||||
n = strlen(pTrig->table) + 1;
|
||||
pTab = sqlite3HashFind(&pTrig->pTabSchema->tblHash, pTrig->table, n);
|
||||
assert( pTab!=0 );
|
||||
pTrig->pNext = pTab->pTrigger;
|
||||
pTab->pTrigger = pTrig;
|
||||
pTrig = 0;
|
||||
}
|
||||
|
||||
triggerfinish_cleanup:
|
||||
sqlite3DeleteTrigger(pTrig);
|
||||
assert( !pParse->pNewTrigger );
|
||||
sqlite3DeleteTriggerStep(pStepList);
|
||||
}
|
||||
|
||||
/*
|
||||
** 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
|
||||
** 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
|
||||
** string is ephemeral - it will go away as soon as the sqlite3_exec()
|
||||
** call that started the parser exits. This routine makes a persistent
|
||||
** copy of all the Expr.token.z strings so that the TriggerStep structure
|
||||
** will be valid even after the sqlite3_exec() call returns.
|
||||
*/
|
||||
static void sqlitePersistTriggerStep(sqlite3 *db, TriggerStep *p){
|
||||
if( p->target.z ){
|
||||
p->target.z = (u8*)sqlite3DbStrNDup(db, (char*)p->target.z, p->target.n);
|
||||
p->target.dyn = 1;
|
||||
}
|
||||
if( p->pSelect ){
|
||||
Select *pNew = sqlite3SelectDup(db, p->pSelect);
|
||||
sqlite3SelectDelete(p->pSelect);
|
||||
p->pSelect = pNew;
|
||||
}
|
||||
if( p->pWhere ){
|
||||
Expr *pNew = sqlite3ExprDup(db, p->pWhere);
|
||||
sqlite3ExprDelete(p->pWhere);
|
||||
p->pWhere = pNew;
|
||||
}
|
||||
if( p->pExprList ){
|
||||
ExprList *pNew = sqlite3ExprListDup(db, p->pExprList);
|
||||
sqlite3ExprListDelete(p->pExprList);
|
||||
p->pExprList = pNew;
|
||||
}
|
||||
if( p->pIdList ){
|
||||
IdList *pNew = sqlite3IdListDup(db, p->pIdList);
|
||||
sqlite3IdListDelete(p->pIdList);
|
||||
p->pIdList = pNew;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Turn a SELECT statement (that the pSelect parameter points to) into
|
||||
** a trigger step. Return a pointer to a TriggerStep structure.
|
||||
**
|
||||
** The parser calls this routine when it finds a SELECT statement in
|
||||
** body of a TRIGGER.
|
||||
*/
|
||||
TriggerStep *sqlite3TriggerSelectStep(sqlite3 *db, Select *pSelect){
|
||||
TriggerStep *pTriggerStep = sqlite3DbMallocZero(db, sizeof(TriggerStep));
|
||||
if( pTriggerStep==0 ) {
|
||||
sqlite3SelectDelete(pSelect);
|
||||
return 0;
|
||||
}
|
||||
|
||||
pTriggerStep->op = TK_SELECT;
|
||||
pTriggerStep->pSelect = pSelect;
|
||||
pTriggerStep->orconf = OE_Default;
|
||||
sqlitePersistTriggerStep(db, pTriggerStep);
|
||||
|
||||
return pTriggerStep;
|
||||
}
|
||||
|
||||
/*
|
||||
** Build a trigger step out of an INSERT statement. Return a pointer
|
||||
** to the new trigger step.
|
||||
**
|
||||
** The parser calls this routine when it sees an INSERT inside the
|
||||
** body of a trigger.
|
||||
*/
|
||||
TriggerStep *sqlite3TriggerInsertStep(
|
||||
sqlite3 *db, /* The database connection */
|
||||
Token *pTableName, /* Name of the table into which we insert */
|
||||
IdList *pColumn, /* List of columns in pTableName to insert into */
|
||||
ExprList *pEList, /* The VALUE clause: a list of values to be inserted */
|
||||
Select *pSelect, /* A SELECT statement that supplies values */
|
||||
int orconf /* The conflict algorithm (OE_Abort, OE_Replace, etc.) */
|
||||
){
|
||||
TriggerStep *pTriggerStep;
|
||||
|
||||
assert(pEList == 0 || pSelect == 0);
|
||||
assert(pEList != 0 || pSelect != 0 || db->mallocFailed);
|
||||
|
||||
pTriggerStep = sqlite3DbMallocZero(db, sizeof(TriggerStep));
|
||||
if( pTriggerStep ){
|
||||
pTriggerStep->op = TK_INSERT;
|
||||
pTriggerStep->pSelect = pSelect;
|
||||
pTriggerStep->target = *pTableName;
|
||||
pTriggerStep->pIdList = pColumn;
|
||||
pTriggerStep->pExprList = pEList;
|
||||
pTriggerStep->orconf = orconf;
|
||||
sqlitePersistTriggerStep(db, pTriggerStep);
|
||||
}else{
|
||||
sqlite3IdListDelete(pColumn);
|
||||
sqlite3ExprListDelete(pEList);
|
||||
sqlite3SelectDelete(pSelect);
|
||||
}
|
||||
|
||||
return pTriggerStep;
|
||||
}
|
||||
|
||||
/*
|
||||
** Construct a trigger step that implements an UPDATE statement and return
|
||||
** a pointer to that trigger step. The parser calls this routine when it
|
||||
** sees an UPDATE statement inside the body of a CREATE TRIGGER.
|
||||
*/
|
||||
TriggerStep *sqlite3TriggerUpdateStep(
|
||||
sqlite3 *db, /* The database connection */
|
||||
Token *pTableName, /* Name of the table to be updated */
|
||||
ExprList *pEList, /* The SET clause: list of column and new values */
|
||||
Expr *pWhere, /* The WHERE clause */
|
||||
int orconf /* The conflict algorithm. (OE_Abort, OE_Ignore, etc) */
|
||||
){
|
||||
TriggerStep *pTriggerStep = sqlite3DbMallocZero(db, sizeof(TriggerStep));
|
||||
if( pTriggerStep==0 ){
|
||||
sqlite3ExprListDelete(pEList);
|
||||
sqlite3ExprDelete(pWhere);
|
||||
return 0;
|
||||
}
|
||||
|
||||
pTriggerStep->op = TK_UPDATE;
|
||||
pTriggerStep->target = *pTableName;
|
||||
pTriggerStep->pExprList = pEList;
|
||||
pTriggerStep->pWhere = pWhere;
|
||||
pTriggerStep->orconf = orconf;
|
||||
sqlitePersistTriggerStep(db, pTriggerStep);
|
||||
|
||||
return pTriggerStep;
|
||||
}
|
||||
|
||||
/*
|
||||
** Construct a trigger step that implements a DELETE statement and return
|
||||
** a pointer to that trigger step. The parser calls this routine when it
|
||||
** sees a DELETE statement inside the body of a CREATE TRIGGER.
|
||||
*/
|
||||
TriggerStep *sqlite3TriggerDeleteStep(
|
||||
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 ){
|
||||
sqlite3ExprDelete(pWhere);
|
||||
return 0;
|
||||
}
|
||||
|
||||
pTriggerStep->op = TK_DELETE;
|
||||
pTriggerStep->target = *pTableName;
|
||||
pTriggerStep->pWhere = pWhere;
|
||||
pTriggerStep->orconf = OE_Default;
|
||||
sqlitePersistTriggerStep(db, pTriggerStep);
|
||||
|
||||
return pTriggerStep;
|
||||
}
|
||||
|
||||
/*
|
||||
** Recursively delete a Trigger structure
|
||||
*/
|
||||
void sqlite3DeleteTrigger(Trigger *pTrigger){
|
||||
if( pTrigger==0 ) return;
|
||||
sqlite3DeleteTriggerStep(pTrigger->step_list);
|
||||
sqlite3_free(pTrigger->name);
|
||||
sqlite3_free(pTrigger->table);
|
||||
sqlite3ExprDelete(pTrigger->pWhen);
|
||||
sqlite3IdListDelete(pTrigger->pColumns);
|
||||
if( pTrigger->nameToken.dyn ) sqlite3_free((char*)pTrigger->nameToken.z);
|
||||
sqlite3_free(pTrigger);
|
||||
}
|
||||
|
||||
/*
|
||||
** This function is called to drop a trigger from the database schema.
|
||||
**
|
||||
** This may be called directly from the parser and therefore identifies
|
||||
** the trigger by name. The sqlite3DropTriggerPtr() routine does the
|
||||
** same job as this routine except it takes a pointer to the trigger
|
||||
** instead of the trigger name.
|
||||
**/
|
||||
void sqlite3DropTrigger(Parse *pParse, SrcList *pName, int noErr){
|
||||
Trigger *pTrigger = 0;
|
||||
int i;
|
||||
const char *zDb;
|
||||
const char *zName;
|
||||
int nName;
|
||||
sqlite3 *db = pParse->db;
|
||||
|
||||
if( db->mallocFailed ) goto drop_trigger_cleanup;
|
||||
if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){
|
||||
goto drop_trigger_cleanup;
|
||||
}
|
||||
|
||||
assert( pName->nSrc==1 );
|
||||
zDb = pName->a[0].zDatabase;
|
||||
zName = pName->a[0].zName;
|
||||
nName = strlen(zName);
|
||||
for(i=OMIT_TEMPDB; i<db->nDb; i++){
|
||||
int j = (i<2) ? i^1 : i; /* Search TEMP before MAIN */
|
||||
if( zDb && sqlite3StrICmp(db->aDb[j].zName, zDb) ) continue;
|
||||
pTrigger = sqlite3HashFind(&(db->aDb[j].pSchema->trigHash), zName, nName);
|
||||
if( pTrigger ) break;
|
||||
}
|
||||
if( !pTrigger ){
|
||||
if( !noErr ){
|
||||
sqlite3ErrorMsg(pParse, "no such trigger: %S", pName, 0);
|
||||
}
|
||||
goto drop_trigger_cleanup;
|
||||
}
|
||||
sqlite3DropTriggerPtr(pParse, pTrigger);
|
||||
|
||||
drop_trigger_cleanup:
|
||||
sqlite3SrcListDelete(pName);
|
||||
}
|
||||
|
||||
/*
|
||||
** Return a pointer to the Table structure for the table that a trigger
|
||||
** is set on.
|
||||
*/
|
||||
static Table *tableOfTrigger(Trigger *pTrigger){
|
||||
int n = strlen(pTrigger->table) + 1;
|
||||
return sqlite3HashFind(&pTrigger->pTabSchema->tblHash, pTrigger->table, n);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Drop a trigger given a pointer to that trigger.
|
||||
*/
|
||||
void sqlite3DropTriggerPtr(Parse *pParse, Trigger *pTrigger){
|
||||
Table *pTable;
|
||||
Vdbe *v;
|
||||
sqlite3 *db = pParse->db;
|
||||
int iDb;
|
||||
|
||||
iDb = sqlite3SchemaToIndex(pParse->db, pTrigger->pSchema);
|
||||
assert( iDb>=0 && iDb<db->nDb );
|
||||
pTable = tableOfTrigger(pTrigger);
|
||||
assert( pTable );
|
||||
assert( pTable->pSchema==pTrigger->pSchema || iDb==1 );
|
||||
#ifndef SQLITE_OMIT_AUTHORIZATION
|
||||
{
|
||||
int code = SQLITE_DROP_TRIGGER;
|
||||
const char *zDb = db->aDb[iDb].zName;
|
||||
const char *zTab = SCHEMA_TABLE(iDb);
|
||||
if( iDb==1 ) code = SQLITE_DROP_TEMP_TRIGGER;
|
||||
if( sqlite3AuthCheck(pParse, code, pTrigger->name, pTable->zName, zDb) ||
|
||||
sqlite3AuthCheck(pParse, SQLITE_DELETE, zTab, 0, zDb) ){
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Generate code to destroy the database record of the trigger.
|
||||
*/
|
||||
assert( pTable!=0 );
|
||||
if( (v = sqlite3GetVdbe(pParse))!=0 ){
|
||||
int base;
|
||||
static const VdbeOpList dropTrigger[] = {
|
||||
{ OP_Rewind, 0, ADDR(9), 0},
|
||||
{ OP_String8, 0, 0, 0}, /* 1 */
|
||||
{ OP_Column, 0, 1, 0},
|
||||
{ OP_Ne, 0, ADDR(8), 0},
|
||||
{ OP_String8, 0, 0, "trigger"},
|
||||
{ OP_Column, 0, 0, 0},
|
||||
{ OP_Ne, 0, ADDR(8), 0},
|
||||
{ OP_Delete, 0, 0, 0},
|
||||
{ OP_Next, 0, ADDR(1), 0}, /* 8 */
|
||||
};
|
||||
|
||||
sqlite3BeginWriteOperation(pParse, 0, iDb);
|
||||
sqlite3OpenMasterTable(pParse, iDb);
|
||||
base = sqlite3VdbeAddOpList(v, ArraySize(dropTrigger), dropTrigger);
|
||||
sqlite3VdbeChangeP3(v, base+1, pTrigger->name, 0);
|
||||
sqlite3ChangeCookie(db, v, iDb);
|
||||
sqlite3VdbeAddOp(v, OP_Close, 0, 0);
|
||||
sqlite3VdbeOp3(v, OP_DropTrigger, iDb, 0, pTrigger->name, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Remove a trigger from the hash tables of the sqlite* pointer.
|
||||
*/
|
||||
void sqlite3UnlinkAndDeleteTrigger(sqlite3 *db, int iDb, const char *zName){
|
||||
Trigger *pTrigger;
|
||||
int nName = strlen(zName);
|
||||
pTrigger = sqlite3HashInsert(&(db->aDb[iDb].pSchema->trigHash),
|
||||
zName, nName, 0);
|
||||
if( pTrigger ){
|
||||
Table *pTable = tableOfTrigger(pTrigger);
|
||||
assert( pTable!=0 );
|
||||
if( pTable->pTrigger == pTrigger ){
|
||||
pTable->pTrigger = pTrigger->pNext;
|
||||
}else{
|
||||
Trigger *cc = pTable->pTrigger;
|
||||
while( cc ){
|
||||
if( cc->pNext == pTrigger ){
|
||||
cc->pNext = cc->pNext->pNext;
|
||||
break;
|
||||
}
|
||||
cc = cc->pNext;
|
||||
}
|
||||
assert(cc);
|
||||
}
|
||||
sqlite3DeleteTrigger(pTrigger);
|
||||
db->flags |= SQLITE_InternChanges;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** pEList is the SET clause of an UPDATE statement. Each entry
|
||||
** in pEList is of the format <id>=<expr>. If any of the entries
|
||||
** in pEList have an <id> which matches an identifier in pIdList,
|
||||
** then return TRUE. If pIdList==NULL, then it is considered a
|
||||
** wildcard that matches anything. Likewise if pEList==NULL then
|
||||
** it matches anything so always return true. Return false only
|
||||
** if there is no match.
|
||||
*/
|
||||
static int checkColumnOverLap(IdList *pIdList, ExprList *pEList){
|
||||
int e;
|
||||
if( !pIdList || !pEList ) return 1;
|
||||
for(e=0; e<pEList->nExpr; e++){
|
||||
if( sqlite3IdListIndex(pIdList, pEList->a[e].zName)>=0 ) return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return a bit vector to indicate what kind of triggers exist for operation
|
||||
** "op" on table pTab. If pChanges is not NULL then it is a list of columns
|
||||
** that are being updated. Triggers only match if the ON clause of the
|
||||
** trigger definition overlaps the set of columns being updated.
|
||||
**
|
||||
** The returned bit vector is some combination of TRIGGER_BEFORE and
|
||||
** TRIGGER_AFTER.
|
||||
*/
|
||||
int sqlite3TriggersExist(
|
||||
Parse *pParse, /* Used to check for recursive triggers */
|
||||
Table *pTab, /* The table the contains the triggers */
|
||||
int op, /* one of TK_DELETE, TK_INSERT, TK_UPDATE */
|
||||
ExprList *pChanges /* Columns that change in an UPDATE statement */
|
||||
){
|
||||
Trigger *pTrigger;
|
||||
int mask = 0;
|
||||
|
||||
pTrigger = IsVirtual(pTab) ? 0 : pTab->pTrigger;
|
||||
while( pTrigger ){
|
||||
if( pTrigger->op==op && checkColumnOverLap(pTrigger->pColumns, pChanges) ){
|
||||
mask |= pTrigger->tr_tm;
|
||||
}
|
||||
pTrigger = pTrigger->pNext;
|
||||
}
|
||||
return mask;
|
||||
}
|
||||
|
||||
/*
|
||||
** Convert the pStep->target token into a SrcList and return a pointer
|
||||
** to that SrcList.
|
||||
**
|
||||
** This routine adds a specific database name, if needed, to the target when
|
||||
** forming the SrcList. This prevents a trigger in one database from
|
||||
** referring to a target in another database. An exception is when the
|
||||
** trigger is in TEMP in which case it can refer to any other database it
|
||||
** wants.
|
||||
*/
|
||||
static SrcList *targetSrcList(
|
||||
Parse *pParse, /* The parsing context */
|
||||
TriggerStep *pStep /* The trigger containing the target token */
|
||||
){
|
||||
Token sDb; /* Dummy database name token */
|
||||
int iDb; /* Index of the database to use */
|
||||
SrcList *pSrc; /* SrcList to be returned */
|
||||
|
||||
iDb = sqlite3SchemaToIndex(pParse->db, pStep->pTrig->pSchema);
|
||||
if( iDb==0 || iDb>=2 ){
|
||||
assert( iDb<pParse->db->nDb );
|
||||
sDb.z = (u8*)pParse->db->aDb[iDb].zName;
|
||||
sDb.n = strlen((char*)sDb.z);
|
||||
pSrc = sqlite3SrcListAppend(pParse->db, 0, &sDb, &pStep->target);
|
||||
} else {
|
||||
pSrc = sqlite3SrcListAppend(pParse->db, 0, &pStep->target, 0);
|
||||
}
|
||||
return pSrc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Generate VDBE code for zero or more statements inside the body of a
|
||||
** trigger.
|
||||
*/
|
||||
static int codeTriggerProgram(
|
||||
Parse *pParse, /* The parser context */
|
||||
TriggerStep *pStepList, /* List of statements inside the trigger body */
|
||||
int orconfin /* Conflict algorithm. (OE_Abort, etc) */
|
||||
){
|
||||
TriggerStep * pTriggerStep = pStepList;
|
||||
int orconf;
|
||||
Vdbe *v = pParse->pVdbe;
|
||||
sqlite3 *db = pParse->db;
|
||||
|
||||
assert( pTriggerStep!=0 );
|
||||
assert( v!=0 );
|
||||
sqlite3VdbeAddOp(v, OP_ContextPush, 0, 0);
|
||||
VdbeComment((v, "# begin trigger %s", pStepList->pTrig->name));
|
||||
while( pTriggerStep ){
|
||||
orconf = (orconfin == OE_Default)?pTriggerStep->orconf:orconfin;
|
||||
pParse->trigStack->orconf = orconf;
|
||||
switch( pTriggerStep->op ){
|
||||
case TK_SELECT: {
|
||||
Select *ss = sqlite3SelectDup(db, pTriggerStep->pSelect);
|
||||
if( ss ){
|
||||
sqlite3SelectResolve(pParse, ss, 0);
|
||||
sqlite3Select(pParse, ss, SRT_Discard, 0, 0, 0, 0, 0);
|
||||
sqlite3SelectDelete(ss);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TK_UPDATE: {
|
||||
SrcList *pSrc;
|
||||
pSrc = targetSrcList(pParse, pTriggerStep);
|
||||
sqlite3VdbeAddOp(v, OP_ResetCount, 0, 0);
|
||||
sqlite3Update(pParse, pSrc,
|
||||
sqlite3ExprListDup(db, pTriggerStep->pExprList),
|
||||
sqlite3ExprDup(db, pTriggerStep->pWhere), orconf);
|
||||
sqlite3VdbeAddOp(v, OP_ResetCount, 1, 0);
|
||||
break;
|
||||
}
|
||||
case TK_INSERT: {
|
||||
SrcList *pSrc;
|
||||
pSrc = targetSrcList(pParse, pTriggerStep);
|
||||
sqlite3VdbeAddOp(v, OP_ResetCount, 0, 0);
|
||||
sqlite3Insert(pParse, pSrc,
|
||||
sqlite3ExprListDup(db, pTriggerStep->pExprList),
|
||||
sqlite3SelectDup(db, pTriggerStep->pSelect),
|
||||
sqlite3IdListDup(db, pTriggerStep->pIdList), orconf);
|
||||
sqlite3VdbeAddOp(v, OP_ResetCount, 1, 0);
|
||||
break;
|
||||
}
|
||||
case TK_DELETE: {
|
||||
SrcList *pSrc;
|
||||
sqlite3VdbeAddOp(v, OP_ResetCount, 0, 0);
|
||||
pSrc = targetSrcList(pParse, pTriggerStep);
|
||||
sqlite3DeleteFrom(pParse, pSrc,
|
||||
sqlite3ExprDup(db, pTriggerStep->pWhere));
|
||||
sqlite3VdbeAddOp(v, OP_ResetCount, 1, 0);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
pTriggerStep = pTriggerStep->pNext;
|
||||
}
|
||||
sqlite3VdbeAddOp(v, OP_ContextPop, 0, 0);
|
||||
VdbeComment((v, "# end trigger %s", pStepList->pTrig->name));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** This is called to code FOR EACH ROW triggers.
|
||||
**
|
||||
** When the code that this function generates is executed, the following
|
||||
** must be true:
|
||||
**
|
||||
** 1. No cursors may be open in the main database. (But newIdx and oldIdx
|
||||
** can be indices of cursors in temporary tables. See below.)
|
||||
**
|
||||
** 2. If the triggers being coded are ON INSERT or ON UPDATE triggers, then
|
||||
** a temporary vdbe cursor (index newIdx) must be open and pointing at
|
||||
** a row containing values to be substituted for new.* expressions in the
|
||||
** trigger program(s).
|
||||
**
|
||||
** 3. If the triggers being coded are ON DELETE or ON UPDATE triggers, then
|
||||
** a temporary vdbe cursor (index oldIdx) must be open and pointing at
|
||||
** a row containing values to be substituted for old.* expressions in the
|
||||
** trigger program(s).
|
||||
**
|
||||
*/
|
||||
int sqlite3CodeRowTrigger(
|
||||
Parse *pParse, /* Parse context */
|
||||
int op, /* One of TK_UPDATE, TK_INSERT, TK_DELETE */
|
||||
ExprList *pChanges, /* Changes list for any UPDATE OF triggers */
|
||||
int tr_tm, /* One of TRIGGER_BEFORE, TRIGGER_AFTER */
|
||||
Table *pTab, /* The table to code triggers from */
|
||||
int newIdx, /* The indice of the "new" row to access */
|
||||
int oldIdx, /* The indice of the "old" row to access */
|
||||
int orconf, /* ON CONFLICT policy */
|
||||
int ignoreJump /* Instruction to jump to for RAISE(IGNORE) */
|
||||
){
|
||||
Trigger *p;
|
||||
TriggerStack trigStackEntry;
|
||||
|
||||
assert(op == TK_UPDATE || op == TK_INSERT || op == TK_DELETE);
|
||||
assert(tr_tm == TRIGGER_BEFORE || tr_tm == TRIGGER_AFTER );
|
||||
|
||||
assert(newIdx != -1 || oldIdx != -1);
|
||||
|
||||
for(p=pTab->pTrigger; p; p=p->pNext){
|
||||
int fire_this = 0;
|
||||
|
||||
/* Determine whether we should code this trigger */
|
||||
if(
|
||||
p->op==op &&
|
||||
p->tr_tm==tr_tm &&
|
||||
(p->pSchema==p->pTabSchema || p->pSchema==pParse->db->aDb[1].pSchema) &&
|
||||
(op!=TK_UPDATE||!p->pColumns||checkColumnOverLap(p->pColumns,pChanges))
|
||||
){
|
||||
TriggerStack *pS; /* Pointer to trigger-stack entry */
|
||||
for(pS=pParse->trigStack; pS && p!=pS->pTrigger; pS=pS->pNext){}
|
||||
if( !pS ){
|
||||
fire_this = 1;
|
||||
}
|
||||
#if 0 /* Give no warning for recursive triggers. Just do not do them */
|
||||
else{
|
||||
sqlite3ErrorMsg(pParse, "recursive triggers not supported (%s)",
|
||||
p->name);
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if( fire_this ){
|
||||
int endTrigger;
|
||||
Expr * whenExpr;
|
||||
AuthContext sContext;
|
||||
NameContext sNC;
|
||||
|
||||
memset(&sNC, 0, sizeof(sNC));
|
||||
sNC.pParse = pParse;
|
||||
|
||||
/* Push an entry on to the trigger stack */
|
||||
trigStackEntry.pTrigger = p;
|
||||
trigStackEntry.newIdx = newIdx;
|
||||
trigStackEntry.oldIdx = oldIdx;
|
||||
trigStackEntry.pTab = pTab;
|
||||
trigStackEntry.pNext = pParse->trigStack;
|
||||
trigStackEntry.ignoreJump = ignoreJump;
|
||||
pParse->trigStack = &trigStackEntry;
|
||||
sqlite3AuthContextPush(pParse, &sContext, p->name);
|
||||
|
||||
/* code the WHEN clause */
|
||||
endTrigger = sqlite3VdbeMakeLabel(pParse->pVdbe);
|
||||
whenExpr = sqlite3ExprDup(pParse->db, p->pWhen);
|
||||
if( sqlite3ExprResolveNames(&sNC, whenExpr) ){
|
||||
pParse->trigStack = trigStackEntry.pNext;
|
||||
sqlite3ExprDelete(whenExpr);
|
||||
return 1;
|
||||
}
|
||||
sqlite3ExprIfFalse(pParse, whenExpr, endTrigger, 1);
|
||||
sqlite3ExprDelete(whenExpr);
|
||||
|
||||
codeTriggerProgram(pParse, p->step_list, orconf);
|
||||
|
||||
/* Pop the entry off the trigger stack */
|
||||
pParse->trigStack = trigStackEntry.pNext;
|
||||
sqlite3AuthContextPop(&sContext);
|
||||
|
||||
sqlite3VdbeResolveLabel(pParse->pVdbe, endTrigger);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif /* !defined(SQLITE_OMIT_TRIGGER) */
|
|
@ -0,0 +1,630 @@
|
|||
/*
|
||||
** 2001 September 15
|
||||
**
|
||||
** The author disclaims copyright to this source code. In place of
|
||||
** a legal notice, here is a blessing:
|
||||
**
|
||||
** May you do good and not evil.
|
||||
** May you find forgiveness for yourself and forgive others.
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
*************************************************************************
|
||||
** This file contains C code routines that are called by the parser
|
||||
** to handle UPDATE statements.
|
||||
**
|
||||
** $Id: update.c,v 1.140 2007/08/16 10:09:03 danielk1977 Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
/* Forward declaration */
|
||||
static void updateVirtualTable(
|
||||
Parse *pParse, /* The parsing context */
|
||||
SrcList *pSrc, /* The virtual table to be modified */
|
||||
Table *pTab, /* The virtual table */
|
||||
ExprList *pChanges, /* The columns to change in the UPDATE statement */
|
||||
Expr *pRowidExpr, /* Expression used to recompute the rowid */
|
||||
int *aXRef, /* Mapping from columns of pTab to entries in pChanges */
|
||||
Expr *pWhere /* WHERE clause of the UPDATE statement */
|
||||
);
|
||||
#endif /* SQLITE_OMIT_VIRTUALTABLE */
|
||||
|
||||
/*
|
||||
** The most recently coded instruction was an OP_Column to retrieve the
|
||||
** i-th column of table pTab. This routine sets the P3 parameter of the
|
||||
** OP_Column to the default value, if any.
|
||||
**
|
||||
** The default value of a column is specified by a DEFAULT clause in the
|
||||
** column definition. This was either supplied by the user when the 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
|
||||
** 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.
|
||||
** If the former, then all row-records are guaranteed to include a value
|
||||
** for the column and the P3 value is not required.
|
||||
**
|
||||
** Column definitions created by an ALTER TABLE command may only have
|
||||
** literal default values specified: a number, null or a string. (If a more
|
||||
** complicated default expression value was provided, it is evaluated
|
||||
** when the ALTER TABLE is executed and one of the literal values written
|
||||
** into the sqlite_master table.)
|
||||
**
|
||||
** Therefore, the P3 parameter is only required if the default value for
|
||||
** the column is a literal number, string or null. The sqlite3ValueFromExpr()
|
||||
** function is capable of transforming these types of expressions into
|
||||
** sqlite3_value objects.
|
||||
*/
|
||||
void sqlite3ColumnDefault(Vdbe *v, Table *pTab, int i){
|
||||
if( pTab && !pTab->pSelect ){
|
||||
sqlite3_value *pValue;
|
||||
u8 enc = ENC(sqlite3VdbeDb(v));
|
||||
Column *pCol = &pTab->aCol[i];
|
||||
assert( i<pTab->nCol );
|
||||
sqlite3ValueFromExpr(sqlite3VdbeDb(v), pCol->pDflt, enc, pCol->affinity, &pValue);
|
||||
if( pValue ){
|
||||
sqlite3VdbeChangeP3(v, -1, (const char *)pValue, P3_MEM);
|
||||
}else{
|
||||
VdbeComment((v, "# %s.%s", pTab->zName, pCol->zName));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Process an UPDATE statement.
|
||||
**
|
||||
** UPDATE OR IGNORE table_wxyz SET a=b, c=d WHERE e<5 AND f NOT NULL;
|
||||
** \_______/ \________/ \______/ \________________/
|
||||
* onError pTabList pChanges pWhere
|
||||
*/
|
||||
void sqlite3Update(
|
||||
Parse *pParse, /* The parser context */
|
||||
SrcList *pTabList, /* The table in which we should change things */
|
||||
ExprList *pChanges, /* Things to be changed */
|
||||
Expr *pWhere, /* The WHERE clause. May be null */
|
||||
int onError /* How to handle constraint errors */
|
||||
){
|
||||
int i, j; /* Loop counters */
|
||||
Table *pTab; /* The table to be updated */
|
||||
int addr = 0; /* VDBE instruction address of the start of the loop */
|
||||
WhereInfo *pWInfo; /* Information about the WHERE clause */
|
||||
Vdbe *v; /* The virtual database engine */
|
||||
Index *pIdx; /* For looping over indices */
|
||||
int nIdx; /* Number of indices that need updating */
|
||||
int nIdxTotal; /* Total number of indices */
|
||||
int iCur; /* VDBE Cursor number of pTab */
|
||||
sqlite3 *db; /* The database structure */
|
||||
Index **apIdx = 0; /* An array of indices that need updating too */
|
||||
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
|
||||
** an expression for the i-th column of the table.
|
||||
** aXRef[i]==-1 if the i-th column is not changed. */
|
||||
int chngRowid; /* True if the record number is being changed */
|
||||
Expr *pRowidExpr = 0; /* Expression defining the new record number */
|
||||
int openAll = 0; /* True if all indices need to be opened */
|
||||
AuthContext sContext; /* The authorization context */
|
||||
NameContext sNC; /* The name-context to resolve expressions in */
|
||||
int iDb; /* Database containing the table being updated */
|
||||
int memCnt = 0; /* Memory cell used for counting rows changed */
|
||||
|
||||
#ifndef SQLITE_OMIT_TRIGGER
|
||||
int isView; /* Trying to update a view */
|
||||
int triggers_exist = 0; /* True if any row triggers exist */
|
||||
#endif
|
||||
|
||||
int newIdx = -1; /* index of trigger "new" temp table */
|
||||
int oldIdx = -1; /* index of trigger "old" temp table */
|
||||
|
||||
sContext.pParse = 0;
|
||||
db = pParse->db;
|
||||
if( pParse->nErr || db->mallocFailed ){
|
||||
goto update_cleanup;
|
||||
}
|
||||
assert( pTabList->nSrc==1 );
|
||||
|
||||
/* Locate the table which we want to update.
|
||||
*/
|
||||
pTab = sqlite3SrcListLookup(pParse, pTabList);
|
||||
if( pTab==0 ) goto update_cleanup;
|
||||
iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
|
||||
|
||||
/* Figure out if we have any triggers and if the table being
|
||||
** updated is a view
|
||||
*/
|
||||
#ifndef SQLITE_OMIT_TRIGGER
|
||||
triggers_exist = sqlite3TriggersExist(pParse, pTab, TK_UPDATE, pChanges);
|
||||
isView = pTab->pSelect!=0;
|
||||
#else
|
||||
# define triggers_exist 0
|
||||
# define isView 0
|
||||
#endif
|
||||
#ifdef SQLITE_OMIT_VIEW
|
||||
# undef isView
|
||||
# define isView 0
|
||||
#endif
|
||||
|
||||
if( sqlite3IsReadOnly(pParse, pTab, triggers_exist) ){
|
||||
goto update_cleanup;
|
||||
}
|
||||
if( sqlite3ViewGetColumnNames(pParse, pTab) ){
|
||||
goto update_cleanup;
|
||||
}
|
||||
aXRef = sqlite3DbMallocRaw(db, sizeof(int) * pTab->nCol );
|
||||
if( aXRef==0 ) goto update_cleanup;
|
||||
for(i=0; i<pTab->nCol; i++) aXRef[i] = -1;
|
||||
|
||||
/* If there are FOR EACH ROW triggers, allocate cursors for the
|
||||
** special OLD and NEW tables
|
||||
*/
|
||||
if( triggers_exist ){
|
||||
newIdx = pParse->nTab++;
|
||||
oldIdx = pParse->nTab++;
|
||||
}
|
||||
|
||||
/* Allocate a cursors for the main database table and for all indices.
|
||||
** The index cursors might not be used, but if they are used they
|
||||
** need to occur right after the database cursor. So go ahead and
|
||||
** allocate enough space, just in case.
|
||||
*/
|
||||
pTabList->a[0].iCursor = iCur = pParse->nTab++;
|
||||
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
|
||||
pParse->nTab++;
|
||||
}
|
||||
|
||||
/* Initialize the name-context */
|
||||
memset(&sNC, 0, sizeof(sNC));
|
||||
sNC.pParse = pParse;
|
||||
sNC.pSrcList = pTabList;
|
||||
|
||||
/* Resolve the column names in all the expressions of the
|
||||
** of the UPDATE statement. Also find the column index
|
||||
** for each column to be updated in the pChanges array. For each
|
||||
** column to be updated, make sure we have authorization to change
|
||||
** that column.
|
||||
*/
|
||||
chngRowid = 0;
|
||||
for(i=0; i<pChanges->nExpr; i++){
|
||||
if( sqlite3ExprResolveNames(&sNC, pChanges->a[i].pExpr) ){
|
||||
goto update_cleanup;
|
||||
}
|
||||
for(j=0; j<pTab->nCol; j++){
|
||||
if( sqlite3StrICmp(pTab->aCol[j].zName, pChanges->a[i].zName)==0 ){
|
||||
if( j==pTab->iPKey ){
|
||||
chngRowid = 1;
|
||||
pRowidExpr = pChanges->a[i].pExpr;
|
||||
}
|
||||
aXRef[j] = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( j>=pTab->nCol ){
|
||||
if( sqlite3IsRowid(pChanges->a[i].zName) ){
|
||||
chngRowid = 1;
|
||||
pRowidExpr = pChanges->a[i].pExpr;
|
||||
}else{
|
||||
sqlite3ErrorMsg(pParse, "no such column: %s", pChanges->a[i].zName);
|
||||
goto update_cleanup;
|
||||
}
|
||||
}
|
||||
#ifndef SQLITE_OMIT_AUTHORIZATION
|
||||
{
|
||||
int rc;
|
||||
rc = sqlite3AuthCheck(pParse, SQLITE_UPDATE, pTab->zName,
|
||||
pTab->aCol[j].zName, db->aDb[iDb].zName);
|
||||
if( rc==SQLITE_DENY ){
|
||||
goto update_cleanup;
|
||||
}else if( rc==SQLITE_IGNORE ){
|
||||
aXRef[j] = -1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Allocate memory for the array apIdx[] and fill it with pointers to every
|
||||
** index that needs to be updated. Indices only need updating if their
|
||||
** key includes one of the columns named in pChanges or if the record
|
||||
** number of the original table entry is changing.
|
||||
*/
|
||||
for(nIdx=nIdxTotal=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, nIdxTotal++){
|
||||
if( chngRowid ){
|
||||
i = 0;
|
||||
}else {
|
||||
for(i=0; i<pIdx->nColumn; i++){
|
||||
if( aXRef[pIdx->aiColumn[i]]>=0 ) break;
|
||||
}
|
||||
}
|
||||
if( i<pIdx->nColumn ) nIdx++;
|
||||
}
|
||||
if( nIdxTotal>0 ){
|
||||
apIdx = sqlite3DbMallocRaw(db, sizeof(Index*) * nIdx + nIdxTotal );
|
||||
if( apIdx==0 ) goto update_cleanup;
|
||||
aIdxUsed = (char*)&apIdx[nIdx];
|
||||
}
|
||||
for(nIdx=j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
|
||||
if( chngRowid ){
|
||||
i = 0;
|
||||
}else{
|
||||
for(i=0; i<pIdx->nColumn; i++){
|
||||
if( aXRef[pIdx->aiColumn[i]]>=0 ) break;
|
||||
}
|
||||
}
|
||||
if( i<pIdx->nColumn ){
|
||||
apIdx[nIdx++] = pIdx;
|
||||
aIdxUsed[j] = 1;
|
||||
}else{
|
||||
aIdxUsed[j] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Begin generating code.
|
||||
*/
|
||||
v = sqlite3GetVdbe(pParse);
|
||||
if( v==0 ) goto update_cleanup;
|
||||
if( pParse->nested==0 ) sqlite3VdbeCountChanges(v);
|
||||
sqlite3BeginWriteOperation(pParse, 1, iDb);
|
||||
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
/* Virtual tables must be handled separately */
|
||||
if( IsVirtual(pTab) ){
|
||||
updateVirtualTable(pParse, pTabList, pTab, pChanges, pRowidExpr, aXRef,
|
||||
pWhere);
|
||||
pWhere = 0;
|
||||
pTabList = 0;
|
||||
goto update_cleanup;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Resolve the column names in all the expressions in the
|
||||
** WHERE clause.
|
||||
*/
|
||||
if( sqlite3ExprResolveNames(&sNC, pWhere) ){
|
||||
goto update_cleanup;
|
||||
}
|
||||
|
||||
/* Start the view context
|
||||
*/
|
||||
if( isView ){
|
||||
sqlite3AuthContextPush(pParse, &sContext, pTab->zName);
|
||||
}
|
||||
|
||||
/* If we are trying to update a view, realize that view into
|
||||
** a ephemeral table.
|
||||
*/
|
||||
if( isView ){
|
||||
Select *pView;
|
||||
pView = sqlite3SelectDup(db, pTab->pSelect);
|
||||
sqlite3Select(pParse, pView, SRT_EphemTab, iCur, 0, 0, 0, 0);
|
||||
sqlite3SelectDelete(pView);
|
||||
}
|
||||
|
||||
/* Begin the database scan
|
||||
*/
|
||||
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 0);
|
||||
if( pWInfo==0 ) goto update_cleanup;
|
||||
|
||||
/* Remember the rowid of every item to be updated.
|
||||
*/
|
||||
sqlite3VdbeAddOp(v, IsVirtual(pTab) ? OP_VRowid : OP_Rowid, iCur, 0);
|
||||
sqlite3VdbeAddOp(v, OP_FifoWrite, 0, 0);
|
||||
|
||||
/* End the database scan loop.
|
||||
*/
|
||||
sqlite3WhereEnd(pWInfo);
|
||||
|
||||
/* Initialize the count of updated rows
|
||||
*/
|
||||
if( db->flags & SQLITE_CountRows && !pParse->trigStack ){
|
||||
memCnt = pParse->nMem++;
|
||||
sqlite3VdbeAddOp(v, OP_MemInt, 0, memCnt);
|
||||
}
|
||||
|
||||
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) ){
|
||||
/*
|
||||
** Open every index that needs updating. Note that if any
|
||||
** index could potentially invoke a REPLACE conflict resolution
|
||||
** action, then we need to open all indices because we might need
|
||||
** to be deleting some records.
|
||||
*/
|
||||
sqlite3OpenTable(pParse, iCur, iDb, pTab, OP_OpenWrite);
|
||||
if( onError==OE_Replace ){
|
||||
openAll = 1;
|
||||
}else{
|
||||
openAll = 0;
|
||||
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
|
||||
if( pIdx->onError==OE_Replace ){
|
||||
openAll = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
|
||||
if( openAll || aIdxUsed[i] ){
|
||||
KeyInfo *pKey = sqlite3IndexKeyinfo(pParse, pIdx);
|
||||
sqlite3VdbeAddOp(v, OP_Integer, iDb, 0);
|
||||
sqlite3VdbeOp3(v, OP_OpenWrite, iCur+i+1, pIdx->tnum,
|
||||
(char*)pKey, P3_KEYINFO_HANDOFF);
|
||||
assert( pParse->nTab>iCur+i+1 );
|
||||
}
|
||||
}
|
||||
|
||||
/* Loop over every record that needs updating. We have to load
|
||||
** the old data for each record to be updated because some columns
|
||||
** might not change and we will need to copy the old value.
|
||||
** Also, the old data is needed to delete the old index entries.
|
||||
** So make the cursor point at the old record.
|
||||
*/
|
||||
if( !triggers_exist ){
|
||||
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
|
||||
** will be after the update. (The old record number is currently
|
||||
** on top of the stack.)
|
||||
*/
|
||||
if( chngRowid ){
|
||||
sqlite3ExprCode(pParse, pRowidExpr);
|
||||
sqlite3VdbeAddOp(v, OP_MustBeInt, 0, 0);
|
||||
}
|
||||
|
||||
/* Compute new data for this record.
|
||||
*/
|
||||
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{
|
||||
sqlite3ExprCode(pParse, pChanges->a[j].pExpr);
|
||||
}
|
||||
}
|
||||
|
||||
/* Do constraint checks
|
||||
*/
|
||||
sqlite3GenerateConstraintChecks(pParse, pTab, iCur, aIdxUsed, chngRowid, 1,
|
||||
onError, addr);
|
||||
|
||||
/* Delete the old indices for the current record.
|
||||
*/
|
||||
sqlite3GenerateRowIndexDelete(v, pTab, iCur, aIdxUsed);
|
||||
|
||||
/* If changing the record number, delete the old record.
|
||||
*/
|
||||
if( chngRowid ){
|
||||
sqlite3VdbeAddOp(v, OP_Delete, iCur, 0);
|
||||
}
|
||||
|
||||
/* Create the new index entries and the new record.
|
||||
*/
|
||||
sqlite3CompleteInsertion(pParse, pTab, iCur, aIdxUsed, chngRowid, 1, -1, 0);
|
||||
}
|
||||
|
||||
/* Increment the row counter
|
||||
*/
|
||||
if( db->flags & SQLITE_CountRows && !pParse->trigStack){
|
||||
sqlite3VdbeAddOp(v, OP_MemIncr, 1, memCnt);
|
||||
}
|
||||
|
||||
/* If there are triggers, close all the cursors after each iteration
|
||||
** through the loop. The fire the after triggers.
|
||||
*/
|
||||
if( triggers_exist ){
|
||||
if( !isView ){
|
||||
for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
|
||||
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
|
||||
** all record selected by the WHERE clause have been updated.
|
||||
*/
|
||||
sqlite3VdbeAddOp(v, OP_Goto, 0, addr);
|
||||
sqlite3VdbeJumpHere(v, addr);
|
||||
|
||||
/* Close all tables if there were no FOR EACH ROW triggers */
|
||||
if( !triggers_exist ){
|
||||
for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
|
||||
if( openAll || aIdxUsed[i] ){
|
||||
sqlite3VdbeAddOp(v, OP_Close, iCur+i+1, 0);
|
||||
}
|
||||
}
|
||||
sqlite3VdbeAddOp(v, OP_Close, iCur, 0);
|
||||
}else{
|
||||
sqlite3VdbeAddOp(v, OP_Close, newIdx, 0);
|
||||
sqlite3VdbeAddOp(v, OP_Close, oldIdx, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the number of rows that were changed. If this routine is
|
||||
** generating code because of a call to sqlite3NestedParse(), do not
|
||||
** invoke the callback function.
|
||||
*/
|
||||
if( db->flags & SQLITE_CountRows && !pParse->trigStack && pParse->nested==0 ){
|
||||
sqlite3VdbeAddOp(v, OP_MemLoad, memCnt, 0);
|
||||
sqlite3VdbeAddOp(v, OP_Callback, 1, 0);
|
||||
sqlite3VdbeSetNumCols(v, 1);
|
||||
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "rows updated", P3_STATIC);
|
||||
}
|
||||
|
||||
update_cleanup:
|
||||
sqlite3AuthContextPop(&sContext);
|
||||
sqlite3_free(apIdx);
|
||||
sqlite3_free(aXRef);
|
||||
sqlite3SrcListDelete(pTabList);
|
||||
sqlite3ExprListDelete(pChanges);
|
||||
sqlite3ExprDelete(pWhere);
|
||||
return;
|
||||
}
|
||||
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
/*
|
||||
** Generate code for an UPDATE of a virtual table.
|
||||
**
|
||||
** The strategy is that we create an ephemerial table that contains
|
||||
** for each row to be changed:
|
||||
**
|
||||
** (A) The original rowid of that row.
|
||||
** (B) The revised rowid for the row. (note1)
|
||||
** (C) The content of every column in the row.
|
||||
**
|
||||
** Then we loop over this ephemeral table and for each row in
|
||||
** the ephermeral table call VUpdate.
|
||||
**
|
||||
** When finished, drop the ephemeral table.
|
||||
**
|
||||
** (note1) Actually, if we know in advance that (A) is always the same
|
||||
** as (B) we only store (A), then duplicate (A) when pulling
|
||||
** it out of the ephemeral table before calling VUpdate.
|
||||
*/
|
||||
static void updateVirtualTable(
|
||||
Parse *pParse, /* The parsing context */
|
||||
SrcList *pSrc, /* The virtual table to be modified */
|
||||
Table *pTab, /* The virtual table */
|
||||
ExprList *pChanges, /* The columns to change in the UPDATE statement */
|
||||
Expr *pRowid, /* Expression used to recompute the rowid */
|
||||
int *aXRef, /* Mapping from columns of pTab to entries in pChanges */
|
||||
Expr *pWhere /* WHERE clause of the UPDATE statement */
|
||||
){
|
||||
Vdbe *v = pParse->pVdbe; /* Virtual machine under construction */
|
||||
ExprList *pEList = 0; /* The result set of the SELECT statement */
|
||||
Select *pSelect = 0; /* The SELECT statement */
|
||||
Expr *pExpr; /* Temporary expression */
|
||||
int ephemTab; /* Table holding the result of the SELECT */
|
||||
int i; /* Loop counter */
|
||||
int addr; /* Address of top of loop */
|
||||
sqlite3 *db = pParse->db; /* Database connection */
|
||||
|
||||
/* Construct the SELECT statement that will find the new values for
|
||||
** all updated rows.
|
||||
*/
|
||||
pEList = sqlite3ExprListAppend(pParse, 0,
|
||||
sqlite3CreateIdExpr(pParse, "_rowid_"), 0);
|
||||
if( pRowid ){
|
||||
pEList = sqlite3ExprListAppend(pParse, pEList,
|
||||
sqlite3ExprDup(db, pRowid), 0);
|
||||
}
|
||||
assert( pTab->iPKey<0 );
|
||||
for(i=0; i<pTab->nCol; i++){
|
||||
if( aXRef[i]>=0 ){
|
||||
pExpr = sqlite3ExprDup(db, pChanges->a[aXRef[i]].pExpr);
|
||||
}else{
|
||||
pExpr = sqlite3CreateIdExpr(pParse, pTab->aCol[i].zName);
|
||||
}
|
||||
pEList = sqlite3ExprListAppend(pParse, pEList, pExpr, 0);
|
||||
}
|
||||
pSelect = sqlite3SelectNew(pParse, pEList, pSrc, pWhere, 0, 0, 0, 0, 0, 0);
|
||||
|
||||
/* Create the ephemeral table into which the update results will
|
||||
** be stored.
|
||||
*/
|
||||
assert( v );
|
||||
ephemTab = pParse->nTab++;
|
||||
sqlite3VdbeAddOp(v, OP_OpenEphemeral, ephemTab, pTab->nCol+1+(pRowid!=0));
|
||||
|
||||
/* fill the ephemeral table
|
||||
*/
|
||||
sqlite3Select(pParse, pSelect, SRT_Table, ephemTab, 0, 0, 0, 0);
|
||||
|
||||
/*
|
||||
** Generate code to scan the ephemeral table and call VDelete and
|
||||
** VInsert
|
||||
*/
|
||||
sqlite3VdbeAddOp(v, OP_Rewind, ephemTab, 0);
|
||||
addr = sqlite3VdbeCurrentAddr(v);
|
||||
sqlite3VdbeAddOp(v, OP_Column, ephemTab, 0);
|
||||
if( pRowid ){
|
||||
sqlite3VdbeAddOp(v, OP_Column, ephemTab, 1);
|
||||
}else{
|
||||
sqlite3VdbeAddOp(v, OP_Dup, 0, 0);
|
||||
}
|
||||
for(i=0; i<pTab->nCol; i++){
|
||||
sqlite3VdbeAddOp(v, OP_Column, ephemTab, i+1+(pRowid!=0));
|
||||
}
|
||||
pParse->pVirtualLock = pTab;
|
||||
sqlite3VdbeOp3(v, OP_VUpdate, 0, pTab->nCol+2,
|
||||
(const char*)pTab->pVtab, P3_VTAB);
|
||||
sqlite3VdbeAddOp(v, OP_Next, ephemTab, addr);
|
||||
sqlite3VdbeJumpHere(v, addr-1);
|
||||
sqlite3VdbeAddOp(v, OP_Close, ephemTab, 0);
|
||||
|
||||
/* Cleanup */
|
||||
sqlite3SelectDelete(pSelect);
|
||||
}
|
||||
#endif /* SQLITE_OMIT_VIRTUALTABLE */
|
|
@ -0,0 +1,545 @@
|
|||
/*
|
||||
** 2004 April 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 routines used to translate between UTF-8,
|
||||
** UTF-16, UTF-16BE, and UTF-16LE.
|
||||
**
|
||||
** $Id: utf.c,v 1.59 2007/10/03 08:46:45 danielk1977 Exp $
|
||||
**
|
||||
** Notes on UTF-8:
|
||||
**
|
||||
** Byte-0 Byte-1 Byte-2 Byte-3 Value
|
||||
** 0xxxxxxx 00000000 00000000 0xxxxxxx
|
||||
** 110yyyyy 10xxxxxx 00000000 00000yyy yyxxxxxx
|
||||
** 1110zzzz 10yyyyyy 10xxxxxx 00000000 zzzzyyyy yyxxxxxx
|
||||
** 11110uuu 10uuzzzz 10yyyyyy 10xxxxxx 000uuuuu zzzzyyyy yyxxxxxx
|
||||
**
|
||||
**
|
||||
** Notes on UTF-16: (with wwww+1==uuuuu)
|
||||
**
|
||||
** Word-0 Word-1 Value
|
||||
** 110110ww wwzzzzyy 110111yy yyxxxxxx 000uuuuu zzzzyyyy yyxxxxxx
|
||||
** zzzzyyyy yyxxxxxx 00000000 zzzzyyyy yyxxxxxx
|
||||
**
|
||||
**
|
||||
** BOM or Byte Order Mark:
|
||||
** 0xff 0xfe little-endian utf-16 follows
|
||||
** 0xfe 0xff big-endian utf-16 follows
|
||||
**
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include <assert.h>
|
||||
#include "vdbeInt.h"
|
||||
|
||||
/*
|
||||
** The following constant value is used by the SQLITE_BIGENDIAN and
|
||||
** SQLITE_LITTLEENDIAN macros.
|
||||
*/
|
||||
const int sqlite3one = 1;
|
||||
|
||||
/*
|
||||
** This lookup table is used to help decode the first byte of
|
||||
** a multi-byte UTF8 character.
|
||||
*/
|
||||
static const unsigned char sqlite3UtfTrans1[] = {
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
|
||||
0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x00, 0x01, 0x02, 0x03, 0x00, 0x01, 0x00, 0x00,
|
||||
};
|
||||
|
||||
|
||||
#define WRITE_UTF8(zOut, c) { \
|
||||
if( c<0x00080 ){ \
|
||||
*zOut++ = (c&0xFF); \
|
||||
} \
|
||||
else if( c<0x00800 ){ \
|
||||
*zOut++ = 0xC0 + ((c>>6)&0x1F); \
|
||||
*zOut++ = 0x80 + (c & 0x3F); \
|
||||
} \
|
||||
else if( c<0x10000 ){ \
|
||||
*zOut++ = 0xE0 + ((c>>12)&0x0F); \
|
||||
*zOut++ = 0x80 + ((c>>6) & 0x3F); \
|
||||
*zOut++ = 0x80 + (c & 0x3F); \
|
||||
}else{ \
|
||||
*zOut++ = 0xF0 + ((c>>18) & 0x07); \
|
||||
*zOut++ = 0x80 + ((c>>12) & 0x3F); \
|
||||
*zOut++ = 0x80 + ((c>>6) & 0x3F); \
|
||||
*zOut++ = 0x80 + (c & 0x3F); \
|
||||
} \
|
||||
}
|
||||
|
||||
#define WRITE_UTF16LE(zOut, c) { \
|
||||
if( c<=0xFFFF ){ \
|
||||
*zOut++ = (c&0x00FF); \
|
||||
*zOut++ = ((c>>8)&0x00FF); \
|
||||
}else{ \
|
||||
*zOut++ = (((c>>10)&0x003F) + (((c-0x10000)>>10)&0x00C0)); \
|
||||
*zOut++ = (0x00D8 + (((c-0x10000)>>18)&0x03)); \
|
||||
*zOut++ = (c&0x00FF); \
|
||||
*zOut++ = (0x00DC + ((c>>8)&0x03)); \
|
||||
} \
|
||||
}
|
||||
|
||||
#define WRITE_UTF16BE(zOut, c) { \
|
||||
if( c<=0xFFFF ){ \
|
||||
*zOut++ = ((c>>8)&0x00FF); \
|
||||
*zOut++ = (c&0x00FF); \
|
||||
}else{ \
|
||||
*zOut++ = (0x00D8 + (((c-0x10000)>>18)&0x03)); \
|
||||
*zOut++ = (((c>>10)&0x003F) + (((c-0x10000)>>10)&0x00C0)); \
|
||||
*zOut++ = (0x00DC + ((c>>8)&0x03)); \
|
||||
*zOut++ = (c&0x00FF); \
|
||||
} \
|
||||
}
|
||||
|
||||
#define READ_UTF16LE(zIn, c){ \
|
||||
c = (*zIn++); \
|
||||
c += ((*zIn++)<<8); \
|
||||
if( c>=0xD800 && c<0xE000 ){ \
|
||||
int c2 = (*zIn++); \
|
||||
c2 += ((*zIn++)<<8); \
|
||||
c = (c2&0x03FF) + ((c&0x003F)<<10) + (((c&0x03C0)+0x0040)<<10); \
|
||||
if( (c & 0xFFFF0000)==0 ) c = 0xFFFD; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define READ_UTF16BE(zIn, c){ \
|
||||
c = ((*zIn++)<<8); \
|
||||
c += (*zIn++); \
|
||||
if( c>=0xD800 && c<0xE000 ){ \
|
||||
int c2 = ((*zIn++)<<8); \
|
||||
c2 += (*zIn++); \
|
||||
c = (c2&0x03FF) + ((c&0x003F)<<10) + (((c&0x03C0)+0x0040)<<10); \
|
||||
if( (c & 0xFFFF0000)==0 ) c = 0xFFFD; \
|
||||
} \
|
||||
}
|
||||
|
||||
/*
|
||||
** Translate a single UTF-8 character. Return the unicode value.
|
||||
**
|
||||
** During translation, assume that the byte that zTerm points
|
||||
** is a 0x00.
|
||||
**
|
||||
** Write a pointer to the next unread byte back into *pzNext.
|
||||
**
|
||||
** Notes On Invalid UTF-8:
|
||||
**
|
||||
** * This routine never allows a 7-bit character (0x00 through 0x7f) to
|
||||
** be encoded as a multi-byte character. Any multi-byte character that
|
||||
** attempts to encode a value between 0x00 and 0x7f is rendered as 0xfffd.
|
||||
**
|
||||
** * This routine never allows a UTF16 surrogate value to be encoded.
|
||||
** If a multi-byte character attempts to encode a value between
|
||||
** 0xd800 and 0xe000 then it is rendered as 0xfffd.
|
||||
**
|
||||
** * Bytes in the range of 0x80 through 0xbf which occur as the first
|
||||
** byte of a character are interpreted as single-byte characters
|
||||
** and rendered as themselves even though they are technically
|
||||
** invalid characters.
|
||||
**
|
||||
** * This routine accepts an infinite number of different UTF8 encodings
|
||||
** for unicode values 0x80 and greater. It do not change over-length
|
||||
** encodings to 0xfffd as some systems recommend.
|
||||
*/
|
||||
int sqlite3Utf8Read(
|
||||
const unsigned char *z, /* First byte of UTF-8 character */
|
||||
const unsigned char *zTerm, /* Pretend this byte is 0x00 */
|
||||
const unsigned char **pzNext /* Write first byte past UTF-8 char here */
|
||||
){
|
||||
int c = *(z++);
|
||||
if( c>=0xc0 ){
|
||||
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;
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
** If the TRANSLATE_TRACE macro is defined, the value of each Mem is
|
||||
** printed on stderr on the way into and out of sqlite3VdbeMemTranslate().
|
||||
*/
|
||||
/* #define TRANSLATE_TRACE 1 */
|
||||
|
||||
#ifndef SQLITE_OMIT_UTF16
|
||||
/*
|
||||
** This routine transforms the internal text encoding used by pMem to
|
||||
** desiredEnc. It is an error if the string is already of the desired
|
||||
** encoding, or if *pMem does not contain a string value.
|
||||
*/
|
||||
int sqlite3VdbeMemTranslate(Mem *pMem, u8 desiredEnc){
|
||||
unsigned char zShort[NBFS]; /* Temporary short output buffer */
|
||||
int len; /* Maximum length of output string in bytes */
|
||||
unsigned char *zOut; /* Output buffer */
|
||||
unsigned char *zIn; /* Input iterator */
|
||||
unsigned char *zTerm; /* End of input */
|
||||
unsigned char *z; /* Output iterator */
|
||||
unsigned int c;
|
||||
|
||||
assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
|
||||
assert( pMem->flags&MEM_Str );
|
||||
assert( pMem->enc!=desiredEnc );
|
||||
assert( pMem->enc!=0 );
|
||||
assert( pMem->n>=0 );
|
||||
|
||||
#if defined(TRANSLATE_TRACE) && defined(SQLITE_DEBUG)
|
||||
{
|
||||
char zBuf[100];
|
||||
sqlite3VdbeMemPrettyPrint(pMem, zBuf);
|
||||
fprintf(stderr, "INPUT: %s\n", zBuf);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* If the translation is between UTF-16 little and big endian, then
|
||||
** all that is required is to swap the byte order. This case is handled
|
||||
** differently from the others.
|
||||
*/
|
||||
if( pMem->enc!=SQLITE_UTF8 && desiredEnc!=SQLITE_UTF8 ){
|
||||
u8 temp;
|
||||
int rc;
|
||||
rc = sqlite3VdbeMemMakeWriteable(pMem);
|
||||
if( rc!=SQLITE_OK ){
|
||||
assert( rc==SQLITE_NOMEM );
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
zIn = (u8*)pMem->z;
|
||||
zTerm = &zIn[pMem->n];
|
||||
while( zIn<zTerm ){
|
||||
temp = *zIn;
|
||||
*zIn = *(zIn+1);
|
||||
zIn++;
|
||||
*zIn++ = temp;
|
||||
}
|
||||
pMem->enc = desiredEnc;
|
||||
goto translate_out;
|
||||
}
|
||||
|
||||
/* Set len to the maximum number of bytes required in the output buffer. */
|
||||
if( desiredEnc==SQLITE_UTF8 ){
|
||||
/* When converting from UTF-16, the maximum growth results from
|
||||
** translating a 2-byte character to a 4-byte UTF-8 character.
|
||||
** A single byte is required for the output string
|
||||
** nul-terminator.
|
||||
*/
|
||||
len = pMem->n * 2 + 1;
|
||||
}else{
|
||||
/* When converting from UTF-8 to UTF-16 the maximum growth is caused
|
||||
** when a 1-byte UTF-8 character is translated into a 2-byte UTF-16
|
||||
** character. Two bytes are required in the output buffer for the
|
||||
** nul-terminator.
|
||||
*/
|
||||
len = pMem->n * 2 + 2;
|
||||
}
|
||||
|
||||
/* Set zIn to point at the start of the input buffer and zTerm to point 1
|
||||
** byte past the end.
|
||||
**
|
||||
** Variable zOut is set to point at the output buffer. This may be space
|
||||
** obtained from sqlite3_malloc(), or Mem.zShort, if it large enough and
|
||||
** not in use, or the zShort array on the stack (see above).
|
||||
*/
|
||||
zIn = (u8*)pMem->z;
|
||||
zTerm = &zIn[pMem->n];
|
||||
if( len>NBFS ){
|
||||
zOut = sqlite3DbMallocRaw(pMem->db, len);
|
||||
if( !zOut ){
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
}else{
|
||||
zOut = zShort;
|
||||
}
|
||||
z = zOut;
|
||||
|
||||
if( pMem->enc==SQLITE_UTF8 ){
|
||||
if( desiredEnc==SQLITE_UTF16LE ){
|
||||
/* UTF-8 -> UTF-16 Little-endian */
|
||||
while( zIn<zTerm ){
|
||||
c = sqlite3Utf8Read(zIn, zTerm, (const u8**)&zIn);
|
||||
WRITE_UTF16LE(z, c);
|
||||
}
|
||||
}else{
|
||||
assert( desiredEnc==SQLITE_UTF16BE );
|
||||
/* UTF-8 -> UTF-16 Big-endian */
|
||||
while( zIn<zTerm ){
|
||||
c = sqlite3Utf8Read(zIn, zTerm, (const u8**)&zIn);
|
||||
WRITE_UTF16BE(z, c);
|
||||
}
|
||||
}
|
||||
pMem->n = z - zOut;
|
||||
*z++ = 0;
|
||||
}else{
|
||||
assert( desiredEnc==SQLITE_UTF8 );
|
||||
if( pMem->enc==SQLITE_UTF16LE ){
|
||||
/* UTF-16 Little-endian -> UTF-8 */
|
||||
while( zIn<zTerm ){
|
||||
READ_UTF16LE(zIn, c);
|
||||
WRITE_UTF8(z, c);
|
||||
}
|
||||
}else{
|
||||
/* UTF-16 Little-endian -> UTF-8 */
|
||||
while( zIn<zTerm ){
|
||||
READ_UTF16BE(zIn, c);
|
||||
WRITE_UTF8(z, c);
|
||||
}
|
||||
}
|
||||
pMem->n = z - zOut;
|
||||
}
|
||||
*z = 0;
|
||||
assert( (pMem->n+(desiredEnc==SQLITE_UTF8?1:2))<=len );
|
||||
|
||||
sqlite3VdbeMemRelease(pMem);
|
||||
pMem->flags &= ~(MEM_Static|MEM_Dyn|MEM_Ephem|MEM_Short);
|
||||
pMem->enc = desiredEnc;
|
||||
if( zOut==zShort ){
|
||||
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;
|
||||
|
||||
translate_out:
|
||||
#if defined(TRANSLATE_TRACE) && defined(SQLITE_DEBUG)
|
||||
{
|
||||
char zBuf[100];
|
||||
sqlite3VdbeMemPrettyPrint(pMem, zBuf);
|
||||
fprintf(stderr, "OUTPUT: %s\n", zBuf);
|
||||
}
|
||||
#endif
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** This routine checks for a byte-order mark at the beginning of the
|
||||
** UTF-16 string stored in *pMem. If one is present, it is removed and
|
||||
** the encoding of the Mem adjusted. This routine does not do any
|
||||
** byte-swapping, it just sets Mem.enc appropriately.
|
||||
**
|
||||
** The allocation (static, dynamic etc.) and encoding of the Mem may be
|
||||
** changed by this function.
|
||||
*/
|
||||
int sqlite3VdbeMemHandleBom(Mem *pMem){
|
||||
int rc = SQLITE_OK;
|
||||
u8 bom = 0;
|
||||
|
||||
if( pMem->n<0 || pMem->n>1 ){
|
||||
u8 b1 = *(u8 *)pMem->z;
|
||||
u8 b2 = *(((u8 *)pMem->z) + 1);
|
||||
if( b1==0xFE && b2==0xFF ){
|
||||
bom = SQLITE_UTF16BE;
|
||||
}
|
||||
if( b1==0xFF && b2==0xFE ){
|
||||
bom = SQLITE_UTF16LE;
|
||||
}
|
||||
}
|
||||
|
||||
if( bom ){
|
||||
/* This function is called as soon as a string is stored in a Mem*,
|
||||
** from within sqlite3VdbeMemSetStr(). At that point it is not possible
|
||||
** for the string to be stored in Mem.zShort, or for it to be stored
|
||||
** in dynamic memory with no destructor.
|
||||
*/
|
||||
assert( !(pMem->flags&MEM_Short) );
|
||||
assert( !(pMem->flags&MEM_Dyn) || pMem->xDel );
|
||||
if( pMem->flags & MEM_Dyn ){
|
||||
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;
|
||||
}
|
||||
#endif /* SQLITE_OMIT_UTF16 */
|
||||
|
||||
/*
|
||||
** pZ is a UTF-8 encoded unicode string. If nByte is less than zero,
|
||||
** return the number of unicode characters in pZ up to (but not including)
|
||||
** the first 0x00 byte. If nByte is not less than zero, return the
|
||||
** number of unicode characters in the first nByte of pZ (or up to
|
||||
** the first 0x00, whichever comes first).
|
||||
*/
|
||||
int sqlite3Utf8CharLen(const char *zIn, int nByte){
|
||||
int r = 0;
|
||||
const u8 *z = (const u8*)zIn;
|
||||
const u8 *zTerm;
|
||||
if( nByte>=0 ){
|
||||
zTerm = &z[nByte];
|
||||
}else{
|
||||
zTerm = (const u8*)(-1);
|
||||
}
|
||||
assert( z<=zTerm );
|
||||
while( *z!=0 && z<zTerm ){
|
||||
SQLITE_SKIP_UTF8(z);
|
||||
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;
|
||||
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
|
||||
/*
|
||||
** Convert a UTF-16 string in the native encoding into a UTF-8 string.
|
||||
** Memory to hold the UTF-8 string is obtained from sqlite3_malloc and must
|
||||
** be freed by the calling function.
|
||||
**
|
||||
** NULL is returned if there is an allocation error.
|
||||
*/
|
||||
char *sqlite3Utf16to8(sqlite3 *db, const void *z, int nByte){
|
||||
Mem m;
|
||||
memset(&m, 0, sizeof(m));
|
||||
m.db = db;
|
||||
sqlite3VdbeMemSetStr(&m, z, nByte, SQLITE_UTF16NATIVE, SQLITE_STATIC);
|
||||
sqlite3VdbeChangeEncoding(&m, SQLITE_UTF8);
|
||||
if( db->mallocFailed ){
|
||||
sqlite3VdbeMemRelease(&m);
|
||||
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);
|
||||
}
|
||||
|
||||
/*
|
||||
** pZ is a UTF-16 encoded unicode string. If nChar is less than zero,
|
||||
** return the number of bytes up to (but not including), the first pair
|
||||
** of consecutive 0x00 bytes in pZ. If nChar is not less than zero,
|
||||
** then return the number of bytes in the first nChar unicode characters
|
||||
** in pZ (or up until the first pair of 0x00 bytes, whichever comes first).
|
||||
*/
|
||||
int sqlite3Utf16ByteLen(const void *zIn, int nChar){
|
||||
unsigned int c = 1;
|
||||
char const *z = zIn;
|
||||
int n = 0;
|
||||
if( SQLITE_UTF16NATIVE==SQLITE_UTF16BE ){
|
||||
/* Using an "if (SQLITE_UTF16NATIVE==SQLITE_UTF16BE)" construct here
|
||||
** and in other parts of this file means that at one branch will
|
||||
** not be covered by coverage testing on any single host. But coverage
|
||||
** will be complete if the tests are run on both a little-endian and
|
||||
** big-endian host. Because both the UTF16NATIVE and SQLITE_UTF16BE
|
||||
** macros are constant at compile time the compiler can determine
|
||||
** which branch will be followed. It is therefore assumed that no runtime
|
||||
** penalty is paid for this "if" statement.
|
||||
*/
|
||||
while( c && ((nChar<0) || n<nChar) ){
|
||||
READ_UTF16BE(z, c);
|
||||
n++;
|
||||
}
|
||||
}else{
|
||||
while( c && ((nChar<0) || n<nChar) ){
|
||||
READ_UTF16LE(z, c);
|
||||
n++;
|
||||
}
|
||||
}
|
||||
return (z-(char const *)zIn)-((c==0)?2:0);
|
||||
}
|
||||
|
||||
#if defined(SQLITE_TEST)
|
||||
/*
|
||||
** This routine is called from the TCL test function "translate_selftest".
|
||||
** It checks that the primitives for serializing and deserializing
|
||||
** characters in each encoding are inverses of each other.
|
||||
*/
|
||||
void sqlite3UtfSelfTest(){
|
||||
unsigned int i, t;
|
||||
unsigned char zBuf[20];
|
||||
unsigned char *z;
|
||||
unsigned char *zTerm;
|
||||
int n;
|
||||
unsigned int c;
|
||||
|
||||
for(i=0; i<0x00110000; i++){
|
||||
z = zBuf;
|
||||
WRITE_UTF8(z, i);
|
||||
n = z-zBuf;
|
||||
z[0] = 0;
|
||||
zTerm = z;
|
||||
z = zBuf;
|
||||
c = sqlite3Utf8Read(z, zTerm, (const u8**)&z);
|
||||
t = i;
|
||||
if( i>=0xD800 && i<=0xDFFF ) t = 0xFFFD;
|
||||
if( (i&0xFFFFFFFE)==0xFFFE ) t = 0xFFFD;
|
||||
assert( c==t );
|
||||
assert( (z-zBuf)==n );
|
||||
}
|
||||
for(i=0; i<0x00110000; i++){
|
||||
if( i>=0xD800 && i<0xE000 ) continue;
|
||||
z = zBuf;
|
||||
WRITE_UTF16LE(z, i);
|
||||
n = z-zBuf;
|
||||
z[0] = 0;
|
||||
z = zBuf;
|
||||
READ_UTF16LE(z, c);
|
||||
assert( c==i );
|
||||
assert( (z-zBuf)==n );
|
||||
}
|
||||
for(i=0; i<0x00110000; i++){
|
||||
if( i>=0xD800 && i<0xE000 ) continue;
|
||||
z = zBuf;
|
||||
WRITE_UTF16BE(z, i);
|
||||
n = z-zBuf;
|
||||
z[0] = 0;
|
||||
z = zBuf;
|
||||
READ_UTF16BE(z, c);
|
||||
assert( c==i );
|
||||
assert( (z-zBuf)==n );
|
||||
}
|
||||
}
|
||||
#endif /* SQLITE_TEST */
|
||||
#endif /* SQLITE_OMIT_UTF16 */
|
|
@ -0,0 +1,706 @@
|
|||
/*
|
||||
** 2001 September 15
|
||||
**
|
||||
** The author disclaims copyright to this source code. In place of
|
||||
** a legal notice, here is a blessing:
|
||||
**
|
||||
** May you do good and not evil.
|
||||
** May you find forgiveness for yourself and forgive others.
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
*************************************************************************
|
||||
** Utility functions used throughout sqlite.
|
||||
**
|
||||
** This file contains functions for allocating memory, comparing
|
||||
** strings, and stuff like that.
|
||||
**
|
||||
** $Id: util.c,v 1.212 2007/09/01 10:01:13 danielk1977 Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include <stdarg.h>
|
||||
#include <ctype.h>
|
||||
|
||||
|
||||
/*
|
||||
** Set the most recent error code and error string for the sqlite
|
||||
** handle "db". The error code is set to "err_code".
|
||||
**
|
||||
** If it is not NULL, string zFormat specifies the format of the
|
||||
** error string in the style of the printf functions: The following
|
||||
** format characters are allowed:
|
||||
**
|
||||
** %s Insert a string
|
||||
** %z A string that should be freed after use
|
||||
** %d Insert an integer
|
||||
** %T Insert a token
|
||||
** %S Insert the first element of a SrcList
|
||||
**
|
||||
** zFormat and any string tokens that follow it are assumed to be
|
||||
** encoded in UTF-8.
|
||||
**
|
||||
** To clear the most recent error for sqlite handle "db", sqlite3Error
|
||||
** should be called with err_code set to SQLITE_OK and zFormat set
|
||||
** to NULL.
|
||||
*/
|
||||
void sqlite3Error(sqlite3 *db, int err_code, const char *zFormat, ...){
|
||||
if( db && (db->pErr || (db->pErr = sqlite3ValueNew(db))!=0) ){
|
||||
db->errCode = err_code;
|
||||
if( zFormat ){
|
||||
char *z;
|
||||
va_list ap;
|
||||
va_start(ap, zFormat);
|
||||
z = sqlite3VMPrintf(db, zFormat, ap);
|
||||
va_end(ap);
|
||||
sqlite3ValueSetStr(db->pErr, -1, z, SQLITE_UTF8, sqlite3_free);
|
||||
}else{
|
||||
sqlite3ValueSetStr(db->pErr, 0, 0, SQLITE_UTF8, SQLITE_STATIC);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Add an error message to pParse->zErrMsg and increment pParse->nErr.
|
||||
** The following formatting characters are allowed:
|
||||
**
|
||||
** %s Insert a string
|
||||
** %z A string that should be freed after use
|
||||
** %d Insert an integer
|
||||
** %T Insert a token
|
||||
** %S Insert the first element of a SrcList
|
||||
**
|
||||
** This function should be used to report any error that occurs whilst
|
||||
** compiling an SQL statement (i.e. within sqlite3_prepare()). The
|
||||
** last thing the sqlite3_prepare() function does is copy the error
|
||||
** stored by this function into the database handle using sqlite3Error().
|
||||
** Function sqlite3Error() should be used during statement execution
|
||||
** (sqlite3_step() etc.).
|
||||
*/
|
||||
void sqlite3ErrorMsg(Parse *pParse, const char *zFormat, ...){
|
||||
va_list ap;
|
||||
pParse->nErr++;
|
||||
sqlite3_free(pParse->zErrMsg);
|
||||
va_start(ap, zFormat);
|
||||
pParse->zErrMsg = sqlite3VMPrintf(pParse->db, zFormat, ap);
|
||||
va_end(ap);
|
||||
if( pParse->rc==SQLITE_OK ){
|
||||
pParse->rc = SQLITE_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Clear the error message in pParse, if any
|
||||
*/
|
||||
void sqlite3ErrorClear(Parse *pParse){
|
||||
sqlite3_free(pParse->zErrMsg);
|
||||
pParse->zErrMsg = 0;
|
||||
pParse->nErr = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Convert an SQL-style quoted string into a normal string by removing
|
||||
** the quote characters. The conversion is done in-place. If the
|
||||
** input does not begin with a quote character, then this routine
|
||||
** is a no-op.
|
||||
**
|
||||
** 2002-Feb-14: This routine is extended to remove MS-Access style
|
||||
** brackets from around identifers. For example: "[a-b-c]" becomes
|
||||
** "a-b-c".
|
||||
*/
|
||||
void sqlite3Dequote(char *z){
|
||||
int quote;
|
||||
int i, j;
|
||||
if( z==0 ) return;
|
||||
quote = z[0];
|
||||
switch( quote ){
|
||||
case '\'': break;
|
||||
case '"': break;
|
||||
case '`': break; /* For MySQL compatibility */
|
||||
case '[': quote = ']'; break; /* For MS SqlServer compatibility */
|
||||
default: return;
|
||||
}
|
||||
for(i=1, j=0; z[i]; i++){
|
||||
if( z[i]==quote ){
|
||||
if( z[i+1]==quote ){
|
||||
z[j++] = quote;
|
||||
i++;
|
||||
}else{
|
||||
z[j++] = 0;
|
||||
break;
|
||||
}
|
||||
}else{
|
||||
z[j++] = z[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* An array to map all upper-case characters into their corresponding
|
||||
** 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
|
||||
|
||||
/*
|
||||
** Some systems have stricmp(). Others have strcasecmp(). Because
|
||||
** there is no consistency, we will define our own.
|
||||
*/
|
||||
int sqlite3StrICmp(const char *zLeft, const char *zRight){
|
||||
register unsigned char *a, *b;
|
||||
a = (unsigned char *)zLeft;
|
||||
b = (unsigned char *)zRight;
|
||||
while( *a!=0 && UpperToLower[*a]==UpperToLower[*b]){ a++; b++; }
|
||||
return UpperToLower[*a] - UpperToLower[*b];
|
||||
}
|
||||
int sqlite3StrNICmp(const char *zLeft, const char *zRight, int N){
|
||||
register unsigned char *a, *b;
|
||||
a = (unsigned char *)zLeft;
|
||||
b = (unsigned char *)zRight;
|
||||
while( N-- > 0 && *a!=0 && UpperToLower[*a]==UpperToLower[*b]){ a++; b++; }
|
||||
return N<0 ? 0 : UpperToLower[*a] - UpperToLower[*b];
|
||||
}
|
||||
|
||||
/*
|
||||
** Return TRUE if z is a pure numeric string. Return FALSE if the
|
||||
** string contains any character which is not part of a number. If
|
||||
** the string is numeric and contains the '.' character, set *realnum
|
||||
** to TRUE (otherwise FALSE).
|
||||
**
|
||||
** An empty string is considered non-numeric.
|
||||
*/
|
||||
int sqlite3IsNumber(const char *z, int *realnum, u8 enc){
|
||||
int incr = (enc==SQLITE_UTF8?1:2);
|
||||
if( enc==SQLITE_UTF16BE ) z++;
|
||||
if( *z=='-' || *z=='+' ) z += incr;
|
||||
if( !isdigit(*(u8*)z) ){
|
||||
return 0;
|
||||
}
|
||||
z += incr;
|
||||
if( realnum ) *realnum = 0;
|
||||
while( isdigit(*(u8*)z) ){ z += incr; }
|
||||
if( *z=='.' ){
|
||||
z += incr;
|
||||
if( !isdigit(*(u8*)z) ) return 0;
|
||||
while( isdigit(*(u8*)z) ){ z += incr; }
|
||||
if( realnum ) *realnum = 1;
|
||||
}
|
||||
if( *z=='e' || *z=='E' ){
|
||||
z += incr;
|
||||
if( *z=='+' || *z=='-' ) z += incr;
|
||||
if( !isdigit(*(u8*)z) ) return 0;
|
||||
while( isdigit(*(u8*)z) ){ z += incr; }
|
||||
if( realnum ) *realnum = 1;
|
||||
}
|
||||
return *z==0;
|
||||
}
|
||||
|
||||
/*
|
||||
** The string z[] is an ascii representation of a real number.
|
||||
** Convert this string to a double.
|
||||
**
|
||||
** This routine assumes that z[] really is a valid number. If it
|
||||
** is not, the result is undefined.
|
||||
**
|
||||
** This routine is used instead of the library atof() function because
|
||||
** the library atof() might want to use "," as the decimal point instead
|
||||
** of "." depending on how locale is set. But that would cause problems
|
||||
** for SQL. So this routine always uses "." regardless of locale.
|
||||
*/
|
||||
int sqlite3AtoF(const char *z, double *pResult){
|
||||
#ifndef SQLITE_OMIT_FLOATING_POINT
|
||||
int sign = 1;
|
||||
const char *zBegin = z;
|
||||
LONGDOUBLE_TYPE v1 = 0.0;
|
||||
while( isspace(*(u8*)z) ) z++;
|
||||
if( *z=='-' ){
|
||||
sign = -1;
|
||||
z++;
|
||||
}else if( *z=='+' ){
|
||||
z++;
|
||||
}
|
||||
while( isdigit(*(u8*)z) ){
|
||||
v1 = v1*10.0 + (*z - '0');
|
||||
z++;
|
||||
}
|
||||
if( *z=='.' ){
|
||||
LONGDOUBLE_TYPE divisor = 1.0;
|
||||
z++;
|
||||
while( isdigit(*(u8*)z) ){
|
||||
v1 = v1*10.0 + (*z - '0');
|
||||
divisor *= 10.0;
|
||||
z++;
|
||||
}
|
||||
v1 /= divisor;
|
||||
}
|
||||
if( *z=='e' || *z=='E' ){
|
||||
int esign = 1;
|
||||
int eval = 0;
|
||||
LONGDOUBLE_TYPE scale = 1.0;
|
||||
z++;
|
||||
if( *z=='-' ){
|
||||
esign = -1;
|
||||
z++;
|
||||
}else if( *z=='+' ){
|
||||
z++;
|
||||
}
|
||||
while( isdigit(*(u8*)z) ){
|
||||
eval = eval*10 + *z - '0';
|
||||
z++;
|
||||
}
|
||||
while( eval>=64 ){ scale *= 1.0e+64; eval -= 64; }
|
||||
while( eval>=16 ){ scale *= 1.0e+16; eval -= 16; }
|
||||
while( eval>=4 ){ scale *= 1.0e+4; eval -= 4; }
|
||||
while( eval>=1 ){ scale *= 1.0e+1; eval -= 1; }
|
||||
if( esign<0 ){
|
||||
v1 /= scale;
|
||||
}else{
|
||||
v1 *= scale;
|
||||
}
|
||||
}
|
||||
*pResult = sign<0 ? -v1 : v1;
|
||||
return z - zBegin;
|
||||
#else
|
||||
return sqlite3Atoi64(z, pResult);
|
||||
#endif /* SQLITE_OMIT_FLOATING_POINT */
|
||||
}
|
||||
|
||||
/*
|
||||
** Compare the 19-character string zNum against the text representation
|
||||
** value 2^63: 9223372036854775808. Return negative, zero, or positive
|
||||
** if zNum is less than, equal to, or greater than the string.
|
||||
**
|
||||
** Unlike memcmp() this routine is guaranteed to return the difference
|
||||
** in the values of the last digit if the only difference is in the
|
||||
** last digit. So, for example,
|
||||
**
|
||||
** compare2pow63("9223372036854775800")
|
||||
**
|
||||
** will return -8.
|
||||
*/
|
||||
static int compare2pow63(const char *zNum){
|
||||
int c;
|
||||
c = memcmp(zNum,"922337203685477580",18);
|
||||
if( c==0 ){
|
||||
c = zNum[18] - '8';
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Return TRUE if zNum is a 64-bit signed integer and write
|
||||
** the value of the integer into *pNum. If zNum is not an integer
|
||||
** or is an integer that is too large to be expressed with 64 bits,
|
||||
** then return false.
|
||||
**
|
||||
** When this routine was originally written it dealt with only
|
||||
** 32-bit numbers. At that time, it was much faster than the
|
||||
** atoi() library routine in RedHat 7.2.
|
||||
*/
|
||||
int sqlite3Atoi64(const char *zNum, i64 *pNum){
|
||||
i64 v = 0;
|
||||
int neg;
|
||||
int i, c;
|
||||
while( isspace(*(u8*)zNum) ) zNum++;
|
||||
if( *zNum=='-' ){
|
||||
neg = 1;
|
||||
zNum++;
|
||||
}else if( *zNum=='+' ){
|
||||
neg = 0;
|
||||
zNum++;
|
||||
}else{
|
||||
neg = 0;
|
||||
}
|
||||
while( zNum[0]=='0' ){ zNum++; } /* Skip over leading zeros. Ticket #2454 */
|
||||
for(i=0; (c=zNum[i])>='0' && c<='9'; i++){
|
||||
v = v*10 + c - '0';
|
||||
}
|
||||
*pNum = neg ? -v : v;
|
||||
if( c!=0 || i==0 || i>19 ){
|
||||
/* zNum is empty or contains non-numeric text or is longer
|
||||
** than 19 digits (thus guaranting that it is too large) */
|
||||
return 0;
|
||||
}else if( i<19 ){
|
||||
/* Less than 19 digits, so we know that it fits in 64 bits */
|
||||
return 1;
|
||||
}else{
|
||||
/* 19-digit numbers must be no larger than 9223372036854775807 if positive
|
||||
** or 9223372036854775808 if negative. Note that 9223372036854665808
|
||||
** is 2^63. */
|
||||
return compare2pow63(zNum)<neg;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** The string zNum represents an integer. There might be some other
|
||||
** information following the integer too, but that part is ignored.
|
||||
** If the integer that the prefix of zNum represents will fit in a
|
||||
** 64-bit signed integer, return TRUE. Otherwise return FALSE.
|
||||
**
|
||||
** This routine returns FALSE for the string -9223372036854775808 even that
|
||||
** that number will, in theory fit in a 64-bit integer. Positive
|
||||
** 9223373036854775808 will not fit in 64 bits. So it seems safer to return
|
||||
** false.
|
||||
*/
|
||||
int sqlite3FitsIn64Bits(const char *zNum){
|
||||
int i, c;
|
||||
int neg = 0;
|
||||
if( *zNum=='-' ){
|
||||
neg = 1;
|
||||
zNum++;
|
||||
}else if( *zNum=='+' ){
|
||||
zNum++;
|
||||
}
|
||||
while( *zNum=='0' ){
|
||||
zNum++; /* Skip leading zeros. Ticket #2454 */
|
||||
}
|
||||
for(i=0; (c=zNum[i])>='0' && c<='9'; i++){}
|
||||
if( i<19 ){
|
||||
/* Guaranteed to fit if less than 19 digits */
|
||||
return 1;
|
||||
}else if( i>19 ){
|
||||
/* Guaranteed to be too big if greater than 19 digits */
|
||||
return 0;
|
||||
}else{
|
||||
/* Compare against 2^63. */
|
||||
return compare2pow63(zNum)<neg;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** If zNum represents an integer that will fit in 32-bits, then set
|
||||
** *pValue to that integer and return true. Otherwise return false.
|
||||
**
|
||||
** Any non-numeric characters that following zNum are ignored.
|
||||
** This is different from sqlite3Atoi64() which requires the
|
||||
** input number to be zero-terminated.
|
||||
*/
|
||||
int sqlite3GetInt32(const char *zNum, int *pValue){
|
||||
sqlite_int64 v = 0;
|
||||
int i, c;
|
||||
int neg = 0;
|
||||
if( zNum[0]=='-' ){
|
||||
neg = 1;
|
||||
zNum++;
|
||||
}else if( zNum[0]=='+' ){
|
||||
zNum++;
|
||||
}
|
||||
while( zNum[0]=='0' ) zNum++;
|
||||
for(i=0; i<11 && (c = zNum[i] - '0')>=0 && c<=9; i++){
|
||||
v = v*10 + c;
|
||||
}
|
||||
|
||||
/* The longest decimal representation of a 32 bit integer is 10 digits:
|
||||
**
|
||||
** 1234567890
|
||||
** 2^31 -> 2147483648
|
||||
*/
|
||||
if( i>10 ){
|
||||
return 0;
|
||||
}
|
||||
if( v-neg>2147483647 ){
|
||||
return 0;
|
||||
}
|
||||
if( neg ){
|
||||
v = -v;
|
||||
}
|
||||
*pValue = (int)v;
|
||||
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:
|
||||
**
|
||||
** KEY:
|
||||
** A = 0xxxxxxx 7 bits of data and one flag bit
|
||||
** B = 1xxxxxxx 7 bits of data and one flag bit
|
||||
** C = xxxxxxxx 8 bits of data
|
||||
**
|
||||
** 7 bits - A
|
||||
** 14 bits - BA
|
||||
** 21 bits - BBA
|
||||
** 28 bits - BBBA
|
||||
** 35 bits - BBBBA
|
||||
** 42 bits - BBBBBA
|
||||
** 49 bits - BBBBBBA
|
||||
** 56 bits - BBBBBBBA
|
||||
** 64 bits - BBBBBBBBC
|
||||
*/
|
||||
|
||||
/*
|
||||
** Write a 64-bit variable-length integer to memory starting at p[0].
|
||||
** The length of data write will be between 1 and 9 bytes. The number
|
||||
** of bytes written is returned.
|
||||
**
|
||||
** A variable-length integer consists of the lower 7 bits of each byte
|
||||
** for all bytes that have the 8th bit set and one byte with the 8th
|
||||
** bit clear. Except, if we get to the 9th byte, it stores the full
|
||||
** 8 bits and is the last byte.
|
||||
*/
|
||||
int sqlite3PutVarint(unsigned char *p, u64 v){
|
||||
int i, j, n;
|
||||
u8 buf[10];
|
||||
if( v & (((u64)0xff000000)<<32) ){
|
||||
p[8] = v;
|
||||
v >>= 8;
|
||||
for(i=7; i>=0; i--){
|
||||
p[i] = (v & 0x7f) | 0x80;
|
||||
v >>= 7;
|
||||
}
|
||||
return 9;
|
||||
}
|
||||
n = 0;
|
||||
do{
|
||||
buf[n++] = (v & 0x7f) | 0x80;
|
||||
v >>= 7;
|
||||
}while( v!=0 );
|
||||
buf[0] &= 0x7f;
|
||||
assert( n<=9 );
|
||||
for(i=0, j=n-1; j>=0; j--, i++){
|
||||
p[i] = buf[j];
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
/*
|
||||
** 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.
|
||||
*/
|
||||
int sqlite3GetVarint(const unsigned char *p, u64 *v){
|
||||
u32 x;
|
||||
u64 x64;
|
||||
int n;
|
||||
unsigned char c;
|
||||
if( ((c = p[0]) & 0x80)==0 ){
|
||||
*v = c;
|
||||
return 1;
|
||||
}
|
||||
x = c & 0x7f;
|
||||
if( ((c = p[1]) & 0x80)==0 ){
|
||||
*v = (x<<7) | c;
|
||||
return 2;
|
||||
}
|
||||
x = (x<<7) | (c&0x7f);
|
||||
if( ((c = p[2]) & 0x80)==0 ){
|
||||
*v = (x<<7) | c;
|
||||
return 3;
|
||||
}
|
||||
x = (x<<7) | (c&0x7f);
|
||||
if( ((c = p[3]) & 0x80)==0 ){
|
||||
*v = (x<<7) | c;
|
||||
return 4;
|
||||
}
|
||||
x64 = (x<<7) | (c&0x7f);
|
||||
n = 4;
|
||||
do{
|
||||
c = p[n++];
|
||||
if( n==9 ){
|
||||
x64 = (x64<<8) | c;
|
||||
break;
|
||||
}
|
||||
x64 = (x64<<7) | (c&0x7f);
|
||||
}while( (c & 0x80)!=0 );
|
||||
*v = x64;
|
||||
return n;
|
||||
}
|
||||
|
||||
/*
|
||||
** 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.
|
||||
*/
|
||||
int sqlite3GetVarint32(const unsigned char *p, u32 *v){
|
||||
u32 x;
|
||||
int n;
|
||||
unsigned char c;
|
||||
if( ((signed char*)p)[0]>=0 ){
|
||||
*v = p[0];
|
||||
return 1;
|
||||
}
|
||||
x = p[0] & 0x7f;
|
||||
if( ((signed char*)p)[1]>=0 ){
|
||||
*v = (x<<7) | p[1];
|
||||
return 2;
|
||||
}
|
||||
x = (x<<7) | (p[1] & 0x7f);
|
||||
n = 2;
|
||||
do{
|
||||
x = (x<<7) | ((c = p[n++])&0x7f);
|
||||
}while( (c & 0x80)!=0 && n<9 );
|
||||
*v = x;
|
||||
return n;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the number of bytes that will be needed to store the given
|
||||
** 64-bit integer.
|
||||
*/
|
||||
int sqlite3VarintLen(u64 v){
|
||||
int i = 0;
|
||||
do{
|
||||
i++;
|
||||
v >>= 7;
|
||||
}while( v!=0 && i<9 );
|
||||
return i;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Read or write a four-byte big-endian integer value.
|
||||
*/
|
||||
u32 sqlite3Get4byte(const u8 *p){
|
||||
return (p[0]<<24) | (p[1]<<16) | (p[2]<<8) | p[3];
|
||||
}
|
||||
void sqlite3Put4byte(unsigned char *p, u32 v){
|
||||
p[0] = v>>24;
|
||||
p[1] = v>>16;
|
||||
p[2] = v>>8;
|
||||
p[3] = v;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#if !defined(SQLITE_OMIT_BLOB_LITERAL) || defined(SQLITE_HAS_CODEC) \
|
||||
|| defined(SQLITE_TEST)
|
||||
/*
|
||||
** Translate a single byte of Hex into an integer.
|
||||
*/
|
||||
static int hexToInt(int h){
|
||||
if( h>='0' && h<='9' ){
|
||||
return h - '0';
|
||||
}else if( h>='a' && h<='f' ){
|
||||
return h - 'a' + 10;
|
||||
}else{
|
||||
assert( h>='A' && h<='F' );
|
||||
return h - 'A' + 10;
|
||||
}
|
||||
}
|
||||
#endif /* !SQLITE_OMIT_BLOB_LITERAL || SQLITE_HAS_CODEC || SQLITE_TEST */
|
||||
|
||||
#if !defined(SQLITE_OMIT_BLOB_LITERAL) || defined(SQLITE_HAS_CODEC)
|
||||
/*
|
||||
** Convert a BLOB literal of the form "x'hhhhhh'" into its binary
|
||||
** value. Return a pointer to its binary value. Space to hold the
|
||||
** binary value has been obtained from malloc and must be freed by
|
||||
** the calling routine.
|
||||
*/
|
||||
void *sqlite3HexToBlob(sqlite3 *db, const char *z){
|
||||
char *zBlob;
|
||||
int i;
|
||||
int n = strlen(z);
|
||||
if( n%2 ) return 0;
|
||||
|
||||
zBlob = (char *)sqlite3DbMallocRaw(db, n/2);
|
||||
if( zBlob ){
|
||||
for(i=0; i<n; i+=2){
|
||||
zBlob[i/2] = (hexToInt(z[i])<<4) | hexToInt(z[i+1]);
|
||||
}
|
||||
}
|
||||
return zBlob;
|
||||
}
|
||||
#endif /* !SQLITE_OMIT_BLOB_LITERAL || SQLITE_HAS_CODEC */
|
||||
|
||||
|
||||
/*
|
||||
** Change the sqlite.magic from SQLITE_MAGIC_OPEN to SQLITE_MAGIC_BUSY.
|
||||
** Return an error (non-zero) if the magic was not SQLITE_MAGIC_OPEN
|
||||
** when this routine is called.
|
||||
**
|
||||
** This routine is called when entering an SQLite API. The SQLITE_MAGIC_OPEN
|
||||
** value indicates that the database connection passed into the API is
|
||||
** open and is not being used by another thread. By changing the value
|
||||
** to SQLITE_MAGIC_BUSY we indicate that the connection is in use.
|
||||
** sqlite3SafetyOff() below will change the value back to SQLITE_MAGIC_OPEN
|
||||
** when the API exits.
|
||||
**
|
||||
** This routine is a attempt to detect if two threads use the
|
||||
** same sqlite* pointer at the same time. There is a race
|
||||
** condition so it is possible that the error is not detected.
|
||||
** But usually the problem will be seen. The result will be an
|
||||
** error which can be used to debug the application that is
|
||||
** using SQLite incorrectly.
|
||||
**
|
||||
** Ticket #202: If db->magic is not a valid open value, take care not
|
||||
** to modify the db structure at all. It could be that db is a stale
|
||||
** pointer. In other words, it could be that there has been a prior
|
||||
** call to sqlite3_close(db) and db has been deallocated. And we do
|
||||
** not want to write into deallocated memory.
|
||||
*/
|
||||
int sqlite3SafetyOn(sqlite3 *db){
|
||||
if( db->magic==SQLITE_MAGIC_OPEN ){
|
||||
db->magic = SQLITE_MAGIC_BUSY;
|
||||
return 0;
|
||||
}else if( db->magic==SQLITE_MAGIC_BUSY ){
|
||||
db->magic = SQLITE_MAGIC_ERROR;
|
||||
db->u1.isInterrupted = 1;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
** Change the magic from SQLITE_MAGIC_BUSY to SQLITE_MAGIC_OPEN.
|
||||
** Return an error (non-zero) if the magic was not SQLITE_MAGIC_BUSY
|
||||
** when this routine is called.
|
||||
*/
|
||||
int sqlite3SafetyOff(sqlite3 *db){
|
||||
if( db->magic==SQLITE_MAGIC_BUSY ){
|
||||
db->magic = SQLITE_MAGIC_OPEN;
|
||||
return 0;
|
||||
}else {
|
||||
db->magic = SQLITE_MAGIC_ERROR;
|
||||
db->u1.isInterrupted = 1;
|
||||
return 1;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,262 @@
|
|||
/*
|
||||
** 2003 April 6
|
||||
**
|
||||
** 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 used to implement the VACUUM command.
|
||||
**
|
||||
** Most of the code in this file may be omitted by defining the
|
||||
** SQLITE_OMIT_VACUUM macro.
|
||||
**
|
||||
** $Id: vacuum.c,v 1.73 2007/08/29 12:31:28 danielk1977 Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include "vdbeInt.h"
|
||||
|
||||
#if !defined(SQLITE_OMIT_VACUUM) && !defined(SQLITE_OMIT_ATTACH)
|
||||
/*
|
||||
** Execute zSql on database db. Return an error code.
|
||||
*/
|
||||
static int execSql(sqlite3 *db, const char *zSql){
|
||||
sqlite3_stmt *pStmt;
|
||||
if( !zSql ){
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
if( SQLITE_OK!=sqlite3_prepare(db, zSql, -1, &pStmt, 0) ){
|
||||
return sqlite3_errcode(db);
|
||||
}
|
||||
while( SQLITE_ROW==sqlite3_step(pStmt) ){}
|
||||
return sqlite3_finalize(pStmt);
|
||||
}
|
||||
|
||||
/*
|
||||
** Execute zSql on database db. The statement returns exactly
|
||||
** one column. Execute this as SQL on the same database.
|
||||
*/
|
||||
static int execExecSql(sqlite3 *db, const char *zSql){
|
||||
sqlite3_stmt *pStmt;
|
||||
int rc;
|
||||
|
||||
rc = sqlite3_prepare(db, zSql, -1, &pStmt, 0);
|
||||
if( rc!=SQLITE_OK ) return rc;
|
||||
|
||||
while( SQLITE_ROW==sqlite3_step(pStmt) ){
|
||||
rc = execSql(db, (char*)sqlite3_column_text(pStmt, 0));
|
||||
if( rc!=SQLITE_OK ){
|
||||
sqlite3_finalize(pStmt);
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
return sqlite3_finalize(pStmt);
|
||||
}
|
||||
|
||||
/*
|
||||
** The non-standard VACUUM command is used to clean up the database,
|
||||
** collapse free space, etc. It is modelled after the VACUUM command
|
||||
** in PostgreSQL.
|
||||
**
|
||||
** In version 1.0.x of SQLite, the VACUUM command would call
|
||||
** gdbm_reorganize() on all the database tables. But beginning
|
||||
** with 2.0.0, SQLite no longer uses GDBM so this command has
|
||||
** become a no-op.
|
||||
*/
|
||||
void sqlite3Vacuum(Parse *pParse){
|
||||
Vdbe *v = sqlite3GetVdbe(pParse);
|
||||
if( v ){
|
||||
sqlite3VdbeAddOp(v, OP_Vacuum, 0, 0);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
** This routine implements the OP_Vacuum opcode of the VDBE.
|
||||
*/
|
||||
int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
|
||||
int rc = SQLITE_OK; /* Return code from service routines */
|
||||
Btree *pMain; /* The database being vacuumed */
|
||||
Btree *pTemp; /* The temporary database we vacuum into */
|
||||
char *zSql = 0; /* SQL statements */
|
||||
int saved_flags; /* Saved value of the db->flags */
|
||||
Db *pDb = 0; /* Database to detach at end of vacuum */
|
||||
|
||||
/* Save the current value of the write-schema flag before setting it. */
|
||||
saved_flags = db->flags;
|
||||
db->flags |= SQLITE_WriteSchema | SQLITE_IgnoreChecks;
|
||||
|
||||
if( !db->autoCommit ){
|
||||
sqlite3SetString(pzErrMsg, "cannot VACUUM from within a transaction",
|
||||
(char*)0);
|
||||
rc = SQLITE_ERROR;
|
||||
goto end_of_vacuum;
|
||||
}
|
||||
pMain = db->aDb[0].pBt;
|
||||
|
||||
/* 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
|
||||
** occurs anyway. The integrity of the database is maintained by a
|
||||
** (possibly synchronous) transaction opened on the main database before
|
||||
** sqlite3BtreeCopyFile() is called.
|
||||
**
|
||||
** An optimisation would be to use a non-journaled pager.
|
||||
*/
|
||||
zSql = "ATTACH '' AS vacuum_db;";
|
||||
rc = execSql(db, zSql);
|
||||
if( rc!=SQLITE_OK ) goto end_of_vacuum;
|
||||
pDb = &db->aDb[db->nDb-1];
|
||||
assert( strcmp(db->aDb[db->nDb-1].zName,"vacuum_db")==0 );
|
||||
pTemp = db->aDb[db->nDb-1].pBt;
|
||||
sqlite3BtreeSetPageSize(pTemp, sqlite3BtreeGetPageSize(pMain),
|
||||
sqlite3BtreeGetReserve(pMain));
|
||||
if( db->mallocFailed ){
|
||||
rc = SQLITE_NOMEM;
|
||||
goto end_of_vacuum;
|
||||
}
|
||||
assert( sqlite3BtreeGetPageSize(pTemp)==sqlite3BtreeGetPageSize(pMain) );
|
||||
rc = execSql(db, "PRAGMA vacuum_db.synchronous=OFF");
|
||||
if( rc!=SQLITE_OK ){
|
||||
goto end_of_vacuum;
|
||||
}
|
||||
|
||||
#ifndef SQLITE_OMIT_AUTOVACUUM
|
||||
sqlite3BtreeSetAutoVacuum(pTemp, sqlite3BtreeGetAutoVacuum(pMain));
|
||||
#endif
|
||||
|
||||
/* Begin a transaction */
|
||||
rc = execSql(db, "BEGIN EXCLUSIVE;");
|
||||
if( rc!=SQLITE_OK ) goto end_of_vacuum;
|
||||
|
||||
/* Query the schema of the main database. Create a mirror schema
|
||||
** in the temporary database.
|
||||
*/
|
||||
rc = execExecSql(db,
|
||||
"SELECT 'CREATE TABLE vacuum_db.' || substr(sql,14,100000000) "
|
||||
" FROM sqlite_master WHERE type='table' AND name!='sqlite_sequence'"
|
||||
" AND rootpage>0"
|
||||
);
|
||||
if( rc!=SQLITE_OK ) goto end_of_vacuum;
|
||||
rc = execExecSql(db,
|
||||
"SELECT 'CREATE INDEX vacuum_db.' || substr(sql,14,100000000)"
|
||||
" FROM sqlite_master WHERE sql LIKE 'CREATE INDEX %' ");
|
||||
if( rc!=SQLITE_OK ) goto end_of_vacuum;
|
||||
rc = execExecSql(db,
|
||||
"SELECT 'CREATE UNIQUE INDEX vacuum_db.' || substr(sql,21,100000000) "
|
||||
" FROM sqlite_master WHERE sql LIKE 'CREATE UNIQUE INDEX %'");
|
||||
if( rc!=SQLITE_OK ) goto end_of_vacuum;
|
||||
|
||||
/* Loop through the tables in the main database. For each, do
|
||||
** an "INSERT INTO vacuum_db.xxx SELECT * FROM xxx;" to copy
|
||||
** the contents to the temporary database.
|
||||
*/
|
||||
rc = execExecSql(db,
|
||||
"SELECT 'INSERT INTO vacuum_db.' || quote(name) "
|
||||
"|| ' SELECT * FROM ' || quote(name) || ';'"
|
||||
"FROM sqlite_master "
|
||||
"WHERE type = 'table' AND name!='sqlite_sequence' "
|
||||
" AND rootpage>0"
|
||||
|
||||
);
|
||||
if( rc!=SQLITE_OK ) goto end_of_vacuum;
|
||||
|
||||
/* Copy over the sequence table
|
||||
*/
|
||||
rc = execExecSql(db,
|
||||
"SELECT 'DELETE FROM vacuum_db.' || quote(name) || ';' "
|
||||
"FROM vacuum_db.sqlite_master WHERE name='sqlite_sequence' "
|
||||
);
|
||||
if( rc!=SQLITE_OK ) goto end_of_vacuum;
|
||||
rc = execExecSql(db,
|
||||
"SELECT 'INSERT INTO vacuum_db.' || quote(name) "
|
||||
"|| ' SELECT * FROM ' || quote(name) || ';' "
|
||||
"FROM vacuum_db.sqlite_master WHERE name=='sqlite_sequence';"
|
||||
);
|
||||
if( rc!=SQLITE_OK ) goto end_of_vacuum;
|
||||
|
||||
|
||||
/* Copy the triggers, views, and virtual tables from the main database
|
||||
** over to the temporary database. None of these objects has any
|
||||
** associated storage, so all we have to do is copy their entries
|
||||
** from the SQLITE_MASTER table.
|
||||
*/
|
||||
rc = execSql(db,
|
||||
"INSERT INTO vacuum_db.sqlite_master "
|
||||
" SELECT type, name, tbl_name, rootpage, sql"
|
||||
" FROM sqlite_master"
|
||||
" WHERE type='view' OR type='trigger'"
|
||||
" OR (type='table' AND rootpage=0)"
|
||||
);
|
||||
if( rc ) goto end_of_vacuum;
|
||||
|
||||
/* At this point, unless the main db was completely empty, there is now a
|
||||
** transaction open on the vacuum database, but not on the main database.
|
||||
** Open a btree level transaction on the main database. This allows a
|
||||
** call to sqlite3BtreeCopyFile(). The main database btree level
|
||||
** transaction is then committed, so the SQL level never knows it was
|
||||
** opened for writing. This way, the SQL transaction used to create the
|
||||
** temporary database never needs to be committed.
|
||||
*/
|
||||
if( rc==SQLITE_OK ){
|
||||
u32 meta;
|
||||
int i;
|
||||
|
||||
/* This array determines which meta meta values are preserved in the
|
||||
** vacuum. Even entries are the meta value number and odd entries
|
||||
** are an increment to apply to the meta value after the vacuum.
|
||||
** The increment is used to increase the schema cookie so that other
|
||||
** connections to the same database will know to reread the schema.
|
||||
*/
|
||||
static const unsigned char aCopy[] = {
|
||||
1, 1, /* Add one to the old schema cookie */
|
||||
3, 0, /* Preserve the default page cache size */
|
||||
5, 0, /* Preserve the default text encoding */
|
||||
6, 0, /* Preserve the user version */
|
||||
};
|
||||
|
||||
assert( 1==sqlite3BtreeIsInTrans(pTemp) );
|
||||
assert( 1==sqlite3BtreeIsInTrans(pMain) );
|
||||
|
||||
/* Copy Btree meta values */
|
||||
for(i=0; i<sizeof(aCopy)/sizeof(aCopy[0]); i+=2){
|
||||
rc = sqlite3BtreeGetMeta(pMain, aCopy[i], &meta);
|
||||
if( rc!=SQLITE_OK ) goto end_of_vacuum;
|
||||
rc = sqlite3BtreeUpdateMeta(pTemp, aCopy[i], meta+aCopy[i+1]);
|
||||
if( rc!=SQLITE_OK ) goto end_of_vacuum;
|
||||
}
|
||||
|
||||
rc = sqlite3BtreeCopyFile(pMain, pTemp);
|
||||
if( rc!=SQLITE_OK ) goto end_of_vacuum;
|
||||
rc = sqlite3BtreeCommit(pTemp);
|
||||
if( rc!=SQLITE_OK ) goto end_of_vacuum;
|
||||
rc = sqlite3BtreeCommit(pMain);
|
||||
}
|
||||
|
||||
end_of_vacuum:
|
||||
/* Restore the original value of db->flags */
|
||||
db->flags = saved_flags;
|
||||
|
||||
/* Currently there is an SQL level transaction open on the vacuum
|
||||
** database. No locks are held on any other files (since the main file
|
||||
** was committed at the btree level). So it safe to end the transaction
|
||||
** by manually setting the autoCommit flag to true and detaching the
|
||||
** vacuum database. The vacuum_db journal file is deleted when the pager
|
||||
** is closed by the DETACH.
|
||||
*/
|
||||
db->autoCommit = 1;
|
||||
|
||||
if( pDb ){
|
||||
sqlite3BtreeClose(pDb->pBt);
|
||||
pDb->pBt = 0;
|
||||
pDb->pSchema = 0;
|
||||
}
|
||||
|
||||
sqlite3ResetInternalSchema(db, 0);
|
||||
|
||||
return rc;
|
||||
}
|
||||
#endif /* SQLITE_OMIT_VACUUM && SQLITE_OMIT_ATTACH */
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,151 @@
|
|||
/*
|
||||
** 2001 September 15
|
||||
**
|
||||
** The author disclaims copyright to this source code. In place of
|
||||
** a legal notice, here is a blessing:
|
||||
**
|
||||
** May you do good and not evil.
|
||||
** May you find forgiveness for yourself and forgive others.
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
*************************************************************************
|
||||
** Header file for the Virtual DataBase Engine (VDBE)
|
||||
**
|
||||
** This header defines the interface to the virtual database engine
|
||||
** or VDBE. The VDBE implements an abstract machine that runs a
|
||||
** simple program to access and modify the underlying database.
|
||||
**
|
||||
** $Id: vdbe.h,v 1.113 2007/08/30 01:19:59 drh Exp $
|
||||
*/
|
||||
#ifndef _SQLITE_VDBE_H_
|
||||
#define _SQLITE_VDBE_H_
|
||||
#include <stdio.h>
|
||||
|
||||
/*
|
||||
** A single VDBE is an opaque structure named "Vdbe". Only routines
|
||||
** in the source file sqliteVdbe.c are allowed to see the insides
|
||||
** of this structure.
|
||||
*/
|
||||
typedef struct Vdbe Vdbe;
|
||||
|
||||
/*
|
||||
** A single instruction of the virtual machine has an opcode
|
||||
** and as many as three operands. The instruction is recorded
|
||||
** as an instance of the following structure:
|
||||
*/
|
||||
struct VdbeOp {
|
||||
u8 opcode; /* What operation to perform */
|
||||
int p1; /* First operand */
|
||||
int p2; /* Second parameter (often the jump destination) */
|
||||
char *p3; /* Third parameter */
|
||||
int p3type; /* One of the P3_xxx constants defined below */
|
||||
#ifdef VDBE_PROFILE
|
||||
int cnt; /* Number of times this instruction was executed */
|
||||
long long cycles; /* Total time spend executing this instruction */
|
||||
#endif
|
||||
};
|
||||
typedef struct VdbeOp VdbeOp;
|
||||
|
||||
/*
|
||||
** A smaller version of VdbeOp used for the VdbeAddOpList() function because
|
||||
** it takes up less space.
|
||||
*/
|
||||
struct VdbeOpList {
|
||||
u8 opcode; /* What operation to perform */
|
||||
signed char p1; /* First operand */
|
||||
short int p2; /* Second parameter (often the jump destination) */
|
||||
char *p3; /* Third parameter */
|
||||
};
|
||||
typedef struct VdbeOpList VdbeOpList;
|
||||
|
||||
/*
|
||||
** Allowed values of VdbeOp.p3type
|
||||
*/
|
||||
#define P3_NOTUSED 0 /* The P3 parameter is not used */
|
||||
#define P3_DYNAMIC (-1) /* Pointer to a string obtained from sqliteMalloc() */
|
||||
#define P3_STATIC (-2) /* Pointer to a static string */
|
||||
#define P3_COLLSEQ (-4) /* P3 is a pointer to a CollSeq structure */
|
||||
#define P3_FUNCDEF (-5) /* P3 is a pointer to a FuncDef structure */
|
||||
#define P3_KEYINFO (-6) /* P3 is a pointer to a KeyInfo structure */
|
||||
#define P3_VDBEFUNC (-7) /* P3 is a pointer to a VdbeFunc structure */
|
||||
#define P3_MEM (-8) /* P3 is a pointer to a Mem* structure */
|
||||
#define P3_TRANSIENT (-9) /* P3 is a pointer to a transient string */
|
||||
#define P3_VTAB (-10) /* P3 is a pointer to an sqlite3_vtab structure */
|
||||
#define P3_MPRINTF (-11) /* P3 is a string obtained from sqlite3_mprintf() */
|
||||
|
||||
/* When adding a P3 argument using P3_KEYINFO, a copy of the KeyInfo structure
|
||||
** 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
|
||||
** 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
|
||||
** function should *not* try to free the KeyInfo.
|
||||
*/
|
||||
#define P3_KEYINFO_HANDOFF (-9)
|
||||
|
||||
/*
|
||||
** The Vdbe.aColName array contains 5n Mem structures, where n is the
|
||||
** number of columns of data returned by the statement.
|
||||
*/
|
||||
#define COLNAME_NAME 0
|
||||
#define COLNAME_DECLTYPE 1
|
||||
#define COLNAME_DATABASE 2
|
||||
#define COLNAME_TABLE 3
|
||||
#define COLNAME_COLUMN 4
|
||||
#define COLNAME_N 5 /* Number of COLNAME_xxx symbols */
|
||||
|
||||
/*
|
||||
** The following macro converts a relative address in the p2 field
|
||||
** of a VdbeOp structure into a negative number so that
|
||||
** sqlite3VdbeAddOpList() knows that the address is relative. Calling
|
||||
** the macro again restores the address.
|
||||
*/
|
||||
#define ADDR(X) (-1-(X))
|
||||
|
||||
/*
|
||||
** The makefile scans the vdbe.c source file and creates the "opcodes.h"
|
||||
** header file that defines a number for each opcode used by the VDBE.
|
||||
*/
|
||||
#include "opcodes.h"
|
||||
|
||||
/*
|
||||
** Prototypes for the VDBE interface. See comments on the implementation
|
||||
** for a description of what each of these routines does.
|
||||
*/
|
||||
Vdbe *sqlite3VdbeCreate(sqlite3*);
|
||||
int sqlite3VdbeAddOp(Vdbe*,int,int,int);
|
||||
int sqlite3VdbeOp3(Vdbe*,int,int,int,const char *zP3,int);
|
||||
int sqlite3VdbeAddOpList(Vdbe*, int nOp, VdbeOpList const *aOp);
|
||||
void sqlite3VdbeChangeP1(Vdbe*, int addr, int P1);
|
||||
void sqlite3VdbeChangeP2(Vdbe*, int addr, int P2);
|
||||
void sqlite3VdbeJumpHere(Vdbe*, int addr);
|
||||
void sqlite3VdbeChangeToNoop(Vdbe*, int addr, int N);
|
||||
void sqlite3VdbeChangeP3(Vdbe*, int addr, const char *zP1, int N);
|
||||
void sqlite3VdbeUsesBtree(Vdbe*, int);
|
||||
VdbeOp *sqlite3VdbeGetOp(Vdbe*, int);
|
||||
int sqlite3VdbeMakeLabel(Vdbe*);
|
||||
void sqlite3VdbeDelete(Vdbe*);
|
||||
void sqlite3VdbeMakeReady(Vdbe*,int,int,int,int);
|
||||
int sqlite3VdbeFinalize(Vdbe*);
|
||||
void sqlite3VdbeResolveLabel(Vdbe*, int);
|
||||
int sqlite3VdbeCurrentAddr(Vdbe*);
|
||||
#ifdef SQLITE_DEBUG
|
||||
void sqlite3VdbeTrace(Vdbe*,FILE*);
|
||||
#endif
|
||||
void sqlite3VdbeResetStepResult(Vdbe*);
|
||||
int sqlite3VdbeReset(Vdbe*);
|
||||
void sqlite3VdbeSetNumCols(Vdbe*,int);
|
||||
int sqlite3VdbeSetColName(Vdbe*, int, int, const char *, int);
|
||||
void sqlite3VdbeCountChanges(Vdbe*);
|
||||
sqlite3 *sqlite3VdbeDb(Vdbe*);
|
||||
void sqlite3VdbeSetSql(Vdbe*, const char *z, int n);
|
||||
const char *sqlite3VdbeGetSql(Vdbe*);
|
||||
void sqlite3VdbeSwap(Vdbe*,Vdbe*);
|
||||
|
||||
#ifndef NDEBUG
|
||||
void sqlite3VdbeComment(Vdbe*, const char*, ...);
|
||||
# define VdbeComment(X) sqlite3VdbeComment X
|
||||
#else
|
||||
# define VdbeComment(X)
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -0,0 +1,427 @@
|
|||
/*
|
||||
** 2003 September 6
|
||||
**
|
||||
** 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 is the header file for information that is private to the
|
||||
** VDBE. This information used to all be at the top of the single
|
||||
** source code file "vdbe.c". When that file became too big (over
|
||||
** 6000 lines long) it was split up into several smaller files and
|
||||
** this header information was factored out.
|
||||
*/
|
||||
#ifndef _VDBEINT_H_
|
||||
#define _VDBEINT_H_
|
||||
|
||||
/*
|
||||
** intToKey() and keyToInt() used to transform the rowid. But with
|
||||
** the latest versions of the design they are no-ops.
|
||||
*/
|
||||
#define keyToInt(X) (X)
|
||||
#define intToKey(X) (X)
|
||||
|
||||
|
||||
/*
|
||||
** SQL is translated into a sequence of instructions to be
|
||||
** executed by a virtual machine. Each instruction is an instance
|
||||
** of the following structure.
|
||||
*/
|
||||
typedef struct VdbeOp Op;
|
||||
|
||||
/*
|
||||
** Boolean values
|
||||
*/
|
||||
typedef unsigned char Bool;
|
||||
|
||||
/*
|
||||
** A cursor is a pointer into a single BTree within a database file.
|
||||
** The cursor can seek to a BTree entry with a particular key, or
|
||||
** loop over all entries of the Btree. You can also insert new BTree
|
||||
** entries or retrieve the key or data from the entry that the cursor
|
||||
** is currently pointing to.
|
||||
**
|
||||
** Every cursor that the virtual machine has open is represented by an
|
||||
** instance of the following structure.
|
||||
**
|
||||
** If the Cursor.isTriggerRow flag is set it means that this cursor is
|
||||
** 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
|
||||
** the rowid is in Cursor.iKey.
|
||||
*/
|
||||
struct Cursor {
|
||||
BtCursor *pCursor; /* The cursor structure of the backend */
|
||||
int iDb; /* Index of cursor database in db->aDb[] (or -1) */
|
||||
i64 lastRowid; /* Last rowid from a Next or NextIdx operation */
|
||||
i64 nextRowid; /* Next rowid returned by OP_NewRowid */
|
||||
Bool zeroed; /* True if zeroed out and ready for reuse */
|
||||
Bool rowidIsValid; /* True if lastRowid is valid */
|
||||
Bool atFirst; /* True if pointing to first entry */
|
||||
Bool useRandomRowid; /* Generate new record numbers semi-randomly */
|
||||
Bool nullRow; /* True if pointing to a row with no data */
|
||||
Bool nextRowidValid; /* True if the nextRowid field is valid */
|
||||
Bool pseudoTable; /* This is a NEW or OLD pseudo-tables of a trigger */
|
||||
Bool deferredMoveto; /* A call to sqlite3BtreeMoveto() is needed */
|
||||
Bool isTable; /* True if a table requiring integer keys */
|
||||
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() */
|
||||
Btree *pBt; /* Separate file holding temporary table */
|
||||
int nData; /* Number of bytes in pData */
|
||||
char *pData; /* Data for a NEW or OLD pseudo-table */
|
||||
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 */
|
||||
int nField; /* Number of fields in the header */
|
||||
i64 seqCount; /* Sequence counter */
|
||||
sqlite3_vtab_cursor *pVtabCursor; /* The cursor for a virtual table */
|
||||
const sqlite3_module *pModule; /* Module for cursor pVtabCursor */
|
||||
|
||||
/* Cached information about the header for the data record that the
|
||||
** cursor is currently pointing to. Only valid if cacheValid is true.
|
||||
** aRow might point to (ephemeral) data for the current row, or it might
|
||||
** be NULL.
|
||||
*/
|
||||
int cacheStatus; /* Cache is valid if this matches Vdbe.cacheCtr */
|
||||
int payloadSize; /* Total number of bytes in the record */
|
||||
u32 *aType; /* Type values for all entries in the record */
|
||||
u32 *aOffset; /* Cached offsets to the start of each columns data */
|
||||
u8 *aRow; /* Data for the current row, if all on one page */
|
||||
};
|
||||
typedef struct Cursor Cursor;
|
||||
|
||||
/*
|
||||
** Number of bytes of string storage space available to each stack
|
||||
** 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
|
||||
|
||||
/*
|
||||
** Internally, the vdbe manipulates nearly all SQL values as Mem
|
||||
** structures. Each Mem struct may cache multiple representations (string,
|
||||
** integer etc.) of the same value. A value (and therefore Mem structure)
|
||||
** has the following properties:
|
||||
**
|
||||
** Each value has a manifest type. The manifest type of the value stored
|
||||
** in a Mem struct is returned by the MemType(Mem*) macro. The type is
|
||||
** one of SQLITE_NULL, SQLITE_INTEGER, SQLITE_REAL, SQLITE_TEXT or
|
||||
** SQLITE_BLOB.
|
||||
*/
|
||||
struct Mem {
|
||||
union {
|
||||
i64 i; /* Integer value. Or FuncDef* when flags==MEM_Agg */
|
||||
FuncDef *pDef; /* Used only when flags==MEM_Agg */
|
||||
} u;
|
||||
double r; /* Real value */
|
||||
sqlite3 *db; /* The associated database connection */
|
||||
char *z; /* String or BLOB value */
|
||||
int n; /* Number of characters in string value, including '\0' */
|
||||
u16 flags; /* Some combination of MEM_Null, MEM_Str, MEM_Dyn, etc. */
|
||||
u8 type; /* One of SQLITE_NULL, SQLITE_TEXT, SQLITE_INTEGER, etc */
|
||||
u8 enc; /* SQLITE_UTF8, SQLITE_UTF16BE, SQLITE_UTF16LE */
|
||||
void (*xDel)(void *); /* If not null, call this function to delete Mem.z */
|
||||
char zShort[NBFS]; /* Space for short strings */
|
||||
};
|
||||
typedef struct Mem Mem;
|
||||
|
||||
/* One or more of the following flags are set to indicate the validOK
|
||||
** representations of the value stored in the Mem struct.
|
||||
**
|
||||
** If the MEM_Null flag is set, then the value is an SQL NULL value.
|
||||
** No other flags may be set in this case.
|
||||
**
|
||||
** If the MEM_Str flag is set then Mem.z points at a string representation.
|
||||
** Usually this is encoded in the same unicode encoding as the main
|
||||
** database (see below for exceptions). If the MEM_Term flag is also
|
||||
** set, then the string is nul terminated. The MEM_Int and MEM_Real
|
||||
** flags may coexist with the MEM_Str flag.
|
||||
**
|
||||
** Multiple of these values can appear in Mem.flags. But only one
|
||||
** at a time can appear in Mem.type.
|
||||
*/
|
||||
#define MEM_Null 0x0001 /* Value is NULL */
|
||||
#define MEM_Str 0x0002 /* Value is a string */
|
||||
#define MEM_Int 0x0004 /* Value is an integer */
|
||||
#define MEM_Real 0x0008 /* Value is a real number */
|
||||
#define MEM_Blob 0x0010 /* Value is a BLOB */
|
||||
|
||||
/* Whenever Mem contains a valid string or blob representation, one of
|
||||
** 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
|
||||
** string is \000 or \u0000 terminated
|
||||
*/
|
||||
#define MEM_Term 0x0020 /* String rep is nul terminated */
|
||||
#define MEM_Dyn 0x0040 /* Need to call sqliteFree() on Mem.z */
|
||||
#define MEM_Static 0x0080 /* Mem.z points to a static string */
|
||||
#define MEM_Ephem 0x0100 /* Mem.z points to an ephemeral string */
|
||||
#define MEM_Short 0x0200 /* Mem.z points to Mem.zShort */
|
||||
#define MEM_Agg 0x0400 /* Mem.z points to an agg function context */
|
||||
#define MEM_Zero 0x0800 /* Mem.i contains count of 0s appended to blob */
|
||||
|
||||
#ifdef SQLITE_OMIT_INCRBLOB
|
||||
#undef MEM_Zero
|
||||
#define MEM_Zero 0x0000
|
||||
#endif
|
||||
|
||||
|
||||
/* A VdbeFunc is just a FuncDef (defined in sqliteInt.h) that contains
|
||||
** additional information about auxiliary information bound to arguments
|
||||
** of the function. This is used to implement the sqlite3_get_auxdata()
|
||||
** and sqlite3_set_auxdata() APIs. The "auxdata" is some auxiliary data
|
||||
** that can be associated with a constant argument to a function. This
|
||||
** allows functions such as "regexp" to compile their constant regular
|
||||
** expression argument once and reused the compiled code for multiple
|
||||
** invocations.
|
||||
*/
|
||||
struct VdbeFunc {
|
||||
FuncDef *pFunc; /* The definition of the function */
|
||||
int nAux; /* Number of entries allocated for apAux[] */
|
||||
struct AuxData {
|
||||
void *pAux; /* Aux data for the i-th argument */
|
||||
void (*xDelete)(void *); /* Destructor for the aux data */
|
||||
} apAux[1]; /* One slot for each function argument */
|
||||
};
|
||||
typedef struct VdbeFunc VdbeFunc;
|
||||
|
||||
/*
|
||||
** The "context" argument for a installable function. A pointer to an
|
||||
** instance of this structure is the first argument to the routines used
|
||||
** implement the SQL functions.
|
||||
**
|
||||
** There is a typedef for this structure in sqlite.h. So all routines,
|
||||
** even the public interface to SQLite, can use a pointer to this structure.
|
||||
** But this file is the only place where the internal details of this
|
||||
** structure are known.
|
||||
**
|
||||
** This structure is defined inside of vdbeInt.h because it uses substructures
|
||||
** (Mem) which are only defined there.
|
||||
*/
|
||||
struct sqlite3_context {
|
||||
FuncDef *pFunc; /* Pointer to function information. MUST BE FIRST */
|
||||
VdbeFunc *pVdbeFunc; /* Auxilary data, if created. */
|
||||
Mem s; /* The return value is stored here */
|
||||
Mem *pMem; /* Memory cell used to store aggregate context */
|
||||
u8 isError; /* Set to true for an error */
|
||||
CollSeq *pColl; /* Collating sequence */
|
||||
};
|
||||
|
||||
/*
|
||||
** A Set structure is used for quick testing to see if a value
|
||||
** is part of a small set. Sets are used to implement code like
|
||||
** this:
|
||||
** x.y IN ('hi','hoo','hum')
|
||||
*/
|
||||
typedef struct Set Set;
|
||||
struct Set {
|
||||
Hash hash; /* A set is just a hash table */
|
||||
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,
|
||||
** and the current statement change count (i.e. changes since last statement).
|
||||
** The current keylist is also stored in the context.
|
||||
** Elements of Context structure type make up the ContextStack, which is
|
||||
** updated by the ContextPush and ContextPop opcodes (used by triggers).
|
||||
** The context is pushed before executing a trigger a popped when the
|
||||
** trigger finishes.
|
||||
*/
|
||||
typedef struct Context Context;
|
||||
struct Context {
|
||||
i64 lastRowid; /* Last insert rowid (sqlite3.lastRowid) */
|
||||
int nChange; /* Statement changes (Vdbe.nChanges) */
|
||||
Fifo sFifo; /* Records that will participate in a DELETE or UPDATE */
|
||||
};
|
||||
|
||||
/*
|
||||
** An instance of the virtual machine. This structure contains the complete
|
||||
** state of the virtual machine.
|
||||
**
|
||||
** The "sqlite3_stmt" structure pointer that is returned by sqlite3_compile()
|
||||
** is really a pointer to an instance of this structure.
|
||||
**
|
||||
** The Vdbe.inVtabMethod variable is set to non-zero for the duration of
|
||||
** any virtual table method invocations made by the vdbe program. It is
|
||||
** set to 2 for xDestroy method calls and 1 for all other methods. This
|
||||
** variable is used for two purposes: to allow xDestroy methods to execute
|
||||
** "DROP TABLE" statements and to prevent some nasty side effects of
|
||||
** malloc failure when SQLite is invoked recursively by a virtual table
|
||||
** method function.
|
||||
*/
|
||||
struct Vdbe {
|
||||
sqlite3 *db; /* The whole database */
|
||||
Vdbe *pPrev,*pNext; /* Linked list of VDBEs with the same Vdbe.db */
|
||||
int nOp; /* Number of instructions in the program */
|
||||
int nOpAlloc; /* Number of slots allocated for aOp[] */
|
||||
Op *aOp; /* Space to hold the virtual machine's program */
|
||||
int nLabel; /* Number of labels used */
|
||||
int nLabelAlloc; /* Number of slots allocated in aLabel[] */
|
||||
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 *aColName; /* Column names to return */
|
||||
int nCursor; /* Number of slots in apCsr[] */
|
||||
Cursor **apCsr; /* One element of this array for each open cursor */
|
||||
int nVar; /* Number of entries in aVar[] */
|
||||
Mem *aVar; /* Values for the OP_Variable opcode. */
|
||||
char **azVar; /* Name of variables */
|
||||
int okVar; /* True if azVar[] has been initialized */
|
||||
int magic; /* Magic number for sanity checking */
|
||||
int nMem; /* Number of memory locations currently allocated */
|
||||
Mem *aMem; /* The memory locations */
|
||||
int nCallback; /* Number of callbacks invoked so far */
|
||||
int cacheCtr; /* Cursor row cache generation counter */
|
||||
Fifo sFifo; /* A list of ROWIDs */
|
||||
int contextStackTop; /* Index of top element in the context stack */
|
||||
int contextStackDepth; /* The size of the "context" stack */
|
||||
Context *contextStack; /* Stack used by opcodes ContextPush & ContextPop*/
|
||||
int pc; /* The program counter */
|
||||
int rc; /* Value to return */
|
||||
unsigned uniqueCnt; /* Used by OP_MakeRecord when P2!=0 */
|
||||
int errorAction; /* Recovery action to do in case of an error */
|
||||
int inTempTrans; /* True if temp database is transactioned */
|
||||
int returnStack[25]; /* 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 */
|
||||
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 */
|
||||
u8 resOnStack; /* True if there are result values on the stack */
|
||||
u8 explain; /* True if EXPLAIN present on SQL command */
|
||||
u8 changeCntOn; /* True to update the change-counter */
|
||||
u8 aborted; /* True if ROLLBACK in another VM causes an abort */
|
||||
u8 expired; /* True if the VM needs to be recompiled */
|
||||
u8 minWriteFileFormat; /* Minimum file format for writable database files */
|
||||
u8 inVtabMethod; /* See comments above */
|
||||
int nChange; /* Number of db changes made since last reset */
|
||||
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 nSql; /* Number of bytes in zSql */
|
||||
char *zSql; /* Text of the SQL statement that generated this */
|
||||
#ifdef SQLITE_DEBUG
|
||||
FILE *trace; /* Write an execution trace here, if not NULL */
|
||||
#endif
|
||||
int openedStatement; /* True if this VM has opened a statement journal */
|
||||
#ifdef SQLITE_SSE
|
||||
int fetchId; /* Statement number used by sqlite3_fetch_statement */
|
||||
int lru; /* Counter used for LRU cache replacement */
|
||||
#endif
|
||||
};
|
||||
|
||||
/*
|
||||
** The following are allowed values for Vdbe.magic
|
||||
*/
|
||||
#define VDBE_MAGIC_INIT 0x26bceaa5 /* Building a VDBE program */
|
||||
#define VDBE_MAGIC_RUN 0xbdf20da3 /* VDBE is ready to execute */
|
||||
#define VDBE_MAGIC_HALT 0x519c2973 /* VDBE has completed execution */
|
||||
#define VDBE_MAGIC_DEAD 0xb606c3c8 /* The VDBE has been deallocated */
|
||||
|
||||
/*
|
||||
** Function prototypes
|
||||
*/
|
||||
void sqlite3VdbeFreeCursor(Vdbe *, Cursor*);
|
||||
void sqliteVdbePopStack(Vdbe*,int);
|
||||
int sqlite3VdbeCursorMoveto(Cursor*);
|
||||
#if defined(SQLITE_DEBUG) || defined(VDBE_PROFILE)
|
||||
void sqlite3VdbePrintOp(FILE*, int, Op*);
|
||||
#endif
|
||||
int sqlite3VdbeSerialTypeLen(u32);
|
||||
u32 sqlite3VdbeSerialType(Mem*, int);
|
||||
int sqlite3VdbeSerialPut(unsigned char*, int, Mem*, int);
|
||||
int sqlite3VdbeSerialGet(const unsigned char*, u32, Mem*);
|
||||
void sqlite3VdbeDeleteAuxData(VdbeFunc*, int);
|
||||
|
||||
int sqlite2BtreeKeyCompare(BtCursor *, const void *, int, int, int *);
|
||||
int sqlite3VdbeIdxKeyCompare(Cursor*,int,const unsigned char*,int*);
|
||||
int sqlite3VdbeIdxRowid(BtCursor *, i64 *);
|
||||
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 sqlite3VdbeList(Vdbe*);
|
||||
int sqlite3VdbeHalt(Vdbe*);
|
||||
int sqlite3VdbeChangeEncoding(Mem *, int);
|
||||
int sqlite3VdbeMemTooBig(Mem*);
|
||||
int sqlite3VdbeMemCopy(Mem*, const Mem*);
|
||||
void sqlite3VdbeMemShallowCopy(Mem*, const Mem*, int);
|
||||
int sqlite3VdbeMemMove(Mem*, Mem*);
|
||||
int sqlite3VdbeMemNulTerminate(Mem*);
|
||||
int sqlite3VdbeMemSetStr(Mem*, const char*, int, u8, void(*)(void*));
|
||||
void sqlite3VdbeMemSetInt64(Mem*, i64);
|
||||
void sqlite3VdbeMemSetDouble(Mem*, double);
|
||||
void sqlite3VdbeMemSetNull(Mem*);
|
||||
void sqlite3VdbeMemSetZeroBlob(Mem*,int);
|
||||
int sqlite3VdbeMemMakeWriteable(Mem*);
|
||||
int sqlite3VdbeMemDynamicify(Mem*);
|
||||
int sqlite3VdbeMemStringify(Mem*, int);
|
||||
i64 sqlite3VdbeIntValue(Mem*);
|
||||
int sqlite3VdbeMemIntegerify(Mem*);
|
||||
double sqlite3VdbeRealValue(Mem*);
|
||||
void sqlite3VdbeIntegerAffinity(Mem*);
|
||||
int sqlite3VdbeMemRealify(Mem*);
|
||||
int sqlite3VdbeMemNumerify(Mem*);
|
||||
int sqlite3VdbeMemFromBtree(BtCursor*,int,int,int,Mem*);
|
||||
void sqlite3VdbeMemRelease(Mem *p);
|
||||
int sqlite3VdbeMemFinalize(Mem*, FuncDef*);
|
||||
const char *sqlite3OpcodeName(int);
|
||||
|
||||
#ifndef NDEBUG
|
||||
void sqlite3VdbeMemSanity(Mem*);
|
||||
int sqlite3VdbeOpcodeNoPush(u8);
|
||||
#endif
|
||||
int sqlite3VdbeMemTranslate(Mem*, u8);
|
||||
#ifdef SQLITE_DEBUG
|
||||
void sqlite3VdbePrintSql(Vdbe*);
|
||||
void sqlite3VdbeMemPrettyPrint(Mem *pMem, char *zBuf);
|
||||
#endif
|
||||
int sqlite3VdbeMemHandleBom(Mem *pMem);
|
||||
void sqlite3VdbeFifoInit(Fifo*);
|
||||
int sqlite3VdbeFifoPush(Fifo*, i64);
|
||||
int sqlite3VdbeFifoPop(Fifo*, i64*);
|
||||
void sqlite3VdbeFifoClear(Fifo*);
|
||||
|
||||
#ifndef SQLITE_OMIT_INCRBLOB
|
||||
int sqlite3VdbeMemExpandBlob(Mem *);
|
||||
#else
|
||||
#define sqlite3VdbeMemExpandBlob(x) SQLITE_OK
|
||||
#endif
|
||||
|
||||
#endif /* !defined(_VDBEINT_H_) */
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,340 @@
|
|||
/*
|
||||
** 2007 May 1
|
||||
**
|
||||
** 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 used to implement incremental BLOB I/O.
|
||||
**
|
||||
** $Id: vdbeblob.c,v 1.16 2007/08/30 01:19:59 drh Exp $
|
||||
*/
|
||||
|
||||
#include "sqliteInt.h"
|
||||
#include "vdbeInt.h"
|
||||
|
||||
#ifndef SQLITE_OMIT_INCRBLOB
|
||||
|
||||
/*
|
||||
** Valid sqlite3_blob* handles point to Incrblob structures.
|
||||
*/
|
||||
typedef struct Incrblob Incrblob;
|
||||
struct Incrblob {
|
||||
int flags; /* Copy of "flags" passed to sqlite3_blob_open() */
|
||||
int nByte; /* Size of open blob, in bytes */
|
||||
int iOffset; /* Byte offset of blob in cursor data */
|
||||
BtCursor *pCsr; /* Cursor pointing at blob row */
|
||||
sqlite3_stmt *pStmt; /* Statement holding cursor open */
|
||||
sqlite3 *db; /* The associated database */
|
||||
};
|
||||
|
||||
/*
|
||||
** Open a blob handle.
|
||||
*/
|
||||
int sqlite3_blob_open(
|
||||
sqlite3* db, /* The database connection */
|
||||
const char *zDb, /* The attached database containing the blob */
|
||||
const char *zTable, /* The table containing the blob */
|
||||
const char *zColumn, /* The column containing the blob */
|
||||
sqlite_int64 iRow, /* The row containing the glob */
|
||||
int flags, /* True -> read/write access, false -> read-only */
|
||||
sqlite3_blob **ppBlob /* Handle for accessing the blob returned here */
|
||||
){
|
||||
int nAttempt = 0;
|
||||
int iCol; /* Index of zColumn in row-record */
|
||||
|
||||
/* This VDBE program seeks a btree cursor to the identified
|
||||
** db/table/row entry. The reason for using a vdbe program instead
|
||||
** of writing code to use the b-tree layer directly is that the
|
||||
** vdbe program will take advantage of the various transaction,
|
||||
** locking and error handling infrastructure built into the vdbe.
|
||||
**
|
||||
** After seeking the cursor, the vdbe executes an OP_Callback.
|
||||
** Code external to the Vdbe then "borrows" the b-tree cursor and
|
||||
** uses it to implement the blob_read(), blob_write() and
|
||||
** blob_bytes() functions.
|
||||
**
|
||||
** The sqlite3_blob_close() function finalizes the vdbe program,
|
||||
** which closes the b-tree cursor and (possibly) commits the
|
||||
** transaction.
|
||||
*/
|
||||
static const VdbeOpList openBlob[] = {
|
||||
{OP_Transaction, 0, 0, 0}, /* 0: Start a transaction */
|
||||
{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
|
||||
** OP_Noop before exection.
|
||||
*/
|
||||
{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}, /* 5: Num cols for cursor */
|
||||
|
||||
{OP_Variable, 1, 0, 0}, /* 6: Push the rowid to the stack */
|
||||
{OP_NotExists, 0, 10, 0}, /* 7: Seek the cursor */
|
||||
{OP_Column, 0, 0, 0}, /* 8 */
|
||||
{OP_Callback, 0, 0, 0}, /* 9 */
|
||||
{OP_Close, 0, 0, 0}, /* 10 */
|
||||
{OP_Halt, 0, 0, 0}, /* 11 */
|
||||
};
|
||||
|
||||
Vdbe *v = 0;
|
||||
int rc = SQLITE_OK;
|
||||
char zErr[128];
|
||||
|
||||
zErr[0] = 0;
|
||||
sqlite3_mutex_enter(db->mutex);
|
||||
do {
|
||||
Parse sParse;
|
||||
Table *pTab;
|
||||
|
||||
memset(&sParse, 0, sizeof(Parse));
|
||||
sParse.db = db;
|
||||
|
||||
rc = sqlite3SafetyOn(db);
|
||||
if( rc!=SQLITE_OK ){
|
||||
sqlite3_mutex_leave(db->mutex);
|
||||
return rc;
|
||||
}
|
||||
|
||||
sqlite3BtreeEnterAll(db);
|
||||
pTab = sqlite3LocateTable(&sParse, zTable, zDb);
|
||||
if( !pTab ){
|
||||
if( sParse.zErrMsg ){
|
||||
sqlite3_snprintf(sizeof(zErr), zErr, "%s", sParse.zErrMsg);
|
||||
}
|
||||
sqlite3_free(sParse.zErrMsg);
|
||||
rc = SQLITE_ERROR;
|
||||
sqlite3SafetyOff(db);
|
||||
sqlite3BtreeLeaveAll(db);
|
||||
goto blob_open_out;
|
||||
}
|
||||
|
||||
/* Now search pTab for the exact column. */
|
||||
for(iCol=0; iCol < pTab->nCol; iCol++) {
|
||||
if( sqlite3StrICmp(pTab->aCol[iCol].zName, zColumn)==0 ){
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( iCol==pTab->nCol ){
|
||||
sqlite3_snprintf(sizeof(zErr), zErr, "no such column: \"%s\"", zColumn);
|
||||
rc = SQLITE_ERROR;
|
||||
sqlite3SafetyOff(db);
|
||||
sqlite3BtreeLeaveAll(db);
|
||||
goto blob_open_out;
|
||||
}
|
||||
|
||||
/* If the value is being opened for writing, check that the
|
||||
** column is not indexed. It is against the rules to open an
|
||||
** indexed column for writing.
|
||||
*/
|
||||
if( flags ){
|
||||
Index *pIdx;
|
||||
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
|
||||
int j;
|
||||
for(j=0; j<pIdx->nColumn; j++){
|
||||
if( pIdx->aiColumn[j]==iCol ){
|
||||
sqlite3_snprintf(sizeof(zErr), zErr,
|
||||
"cannot open indexed column for writing");
|
||||
rc = SQLITE_ERROR;
|
||||
sqlite3SafetyOff(db);
|
||||
sqlite3BtreeLeaveAll(db);
|
||||
goto blob_open_out;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
v = sqlite3VdbeCreate(db);
|
||||
if( v ){
|
||||
int iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
|
||||
sqlite3VdbeAddOpList(v, sizeof(openBlob)/sizeof(VdbeOpList), openBlob);
|
||||
|
||||
/* Configure the OP_Transaction */
|
||||
sqlite3VdbeChangeP1(v, 0, iDb);
|
||||
sqlite3VdbeChangeP2(v, 0, (flags ? 1 : 0));
|
||||
|
||||
/* Configure the OP_VerifyCookie */
|
||||
sqlite3VdbeChangeP1(v, 1, iDb);
|
||||
sqlite3VdbeChangeP2(v, 1, pTab->pSchema->schema_cookie);
|
||||
|
||||
/* Make sure a mutex is held on the table to be accessed */
|
||||
sqlite3VdbeUsesBtree(v, iDb);
|
||||
|
||||
/* Configure the db number pushed onto the stack */
|
||||
sqlite3VdbeChangeP1(v, 2, iDb);
|
||||
|
||||
/* Remove either the OP_OpenWrite or OpenRead. Set the P2
|
||||
** parameter of the other to pTab->tnum.
|
||||
*/
|
||||
sqlite3VdbeChangeToNoop(v, (flags ? 3 : 4), 1);
|
||||
sqlite3VdbeChangeP2(v, (flags ? 4 : 3), pTab->tnum);
|
||||
|
||||
/* Configure the OP_SetNumColumns. Configure the cursor to
|
||||
** think that the table has one more column than it really
|
||||
** does. An OP_Column to retrieve this imaginary column will
|
||||
** always return an SQL NULL. This is useful because it means
|
||||
** we can invoke OP_Column to fill in the vdbe cursors type
|
||||
** and offset cache without causing any IO.
|
||||
*/
|
||||
sqlite3VdbeChangeP2(v, 5, pTab->nCol+1);
|
||||
if( !db->mallocFailed ){
|
||||
sqlite3VdbeMakeReady(v, 1, 0, 1, 0);
|
||||
}
|
||||
}
|
||||
|
||||
sqlite3BtreeLeaveAll(db);
|
||||
rc = sqlite3SafetyOff(db);
|
||||
if( rc!=SQLITE_OK || db->mallocFailed ){
|
||||
goto blob_open_out;
|
||||
}
|
||||
|
||||
sqlite3_bind_int64((sqlite3_stmt *)v, 1, iRow);
|
||||
rc = sqlite3_step((sqlite3_stmt *)v);
|
||||
if( rc!=SQLITE_ROW ){
|
||||
nAttempt++;
|
||||
rc = sqlite3_finalize((sqlite3_stmt *)v);
|
||||
sqlite3_snprintf(sizeof(zErr), zErr, sqlite3_errmsg(db));
|
||||
v = 0;
|
||||
}
|
||||
} while( nAttempt<5 && rc==SQLITE_SCHEMA );
|
||||
|
||||
if( rc==SQLITE_ROW ){
|
||||
/* The row-record has been opened successfully. Check that the
|
||||
** column in question contains text or a blob. If it contains
|
||||
** text, it is up to the caller to get the encoding right.
|
||||
*/
|
||||
Incrblob *pBlob;
|
||||
u32 type = v->apCsr[0]->aType[iCol];
|
||||
|
||||
if( type<12 ){
|
||||
sqlite3_snprintf(sizeof(zErr), zErr, "cannot open value of type %s",
|
||||
type==0?"null": type==7?"real": "integer"
|
||||
);
|
||||
rc = SQLITE_ERROR;
|
||||
goto blob_open_out;
|
||||
}
|
||||
pBlob = (Incrblob *)sqlite3DbMallocZero(db, sizeof(Incrblob));
|
||||
if( db->mallocFailed ){
|
||||
sqlite3_free(pBlob);
|
||||
goto blob_open_out;
|
||||
}
|
||||
pBlob->flags = flags;
|
||||
pBlob->pCsr = v->apCsr[0]->pCursor;
|
||||
sqlite3BtreeEnterCursor(pBlob->pCsr);
|
||||
sqlite3BtreeCacheOverflow(pBlob->pCsr);
|
||||
sqlite3BtreeLeaveCursor(pBlob->pCsr);
|
||||
pBlob->pStmt = (sqlite3_stmt *)v;
|
||||
pBlob->iOffset = v->apCsr[0]->aOffset[iCol];
|
||||
pBlob->nByte = sqlite3VdbeSerialTypeLen(type);
|
||||
pBlob->db = db;
|
||||
*ppBlob = (sqlite3_blob *)pBlob;
|
||||
rc = SQLITE_OK;
|
||||
}else if( rc==SQLITE_OK ){
|
||||
sqlite3_snprintf(sizeof(zErr), zErr, "no such rowid: %lld", iRow);
|
||||
rc = SQLITE_ERROR;
|
||||
}
|
||||
|
||||
blob_open_out:
|
||||
zErr[sizeof(zErr)-1] = '\0';
|
||||
if( rc!=SQLITE_OK || db->mallocFailed ){
|
||||
sqlite3_finalize((sqlite3_stmt *)v);
|
||||
}
|
||||
sqlite3Error(db, rc, (rc==SQLITE_OK?0:zErr));
|
||||
rc = sqlite3ApiExit(db, rc);
|
||||
sqlite3_mutex_leave(db->mutex);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Close a blob handle that was previously created using
|
||||
** sqlite3_blob_open().
|
||||
*/
|
||||
int sqlite3_blob_close(sqlite3_blob *pBlob){
|
||||
Incrblob *p = (Incrblob *)pBlob;
|
||||
int rc;
|
||||
|
||||
rc = sqlite3_finalize(p->pStmt);
|
||||
sqlite3_free(p);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Perform a read or write operation on a blob
|
||||
*/
|
||||
static int blobReadWrite(
|
||||
sqlite3_blob *pBlob,
|
||||
void *z,
|
||||
int n,
|
||||
int iOffset,
|
||||
int (*xCall)(BtCursor*, u32, u32, void*)
|
||||
){
|
||||
int rc;
|
||||
Incrblob *p = (Incrblob *)pBlob;
|
||||
Vdbe *v;
|
||||
sqlite3 *db = p->db;
|
||||
|
||||
/* Request is out of range. Return a transient error. */
|
||||
if( (iOffset+n)>p->nByte ){
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
sqlite3_mutex_enter(db->mutex);
|
||||
|
||||
/* If there is no statement handle, then the blob-handle has
|
||||
** already been invalidated. Return SQLITE_ABORT in this case.
|
||||
*/
|
||||
v = (Vdbe*)p->pStmt;
|
||||
if( v==0 ){
|
||||
rc = SQLITE_ABORT;
|
||||
}else{
|
||||
/* Call either BtreeData() or BtreePutData(). If SQLITE_ABORT is
|
||||
** 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);
|
||||
sqlite3_mutex_leave(db->mutex);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Read data from a blob handle.
|
||||
*/
|
||||
int sqlite3_blob_read(sqlite3_blob *pBlob, void *z, int n, int iOffset){
|
||||
return blobReadWrite(pBlob, z, n, iOffset, sqlite3BtreeData);
|
||||
}
|
||||
|
||||
/*
|
||||
** Write data to a blob handle.
|
||||
*/
|
||||
int sqlite3_blob_write(sqlite3_blob *pBlob, const void *z, int n, int iOffset){
|
||||
return blobReadWrite(pBlob, (void *)z, n, iOffset, sqlite3BtreePutData);
|
||||
}
|
||||
|
||||
/*
|
||||
** 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){
|
||||
Incrblob *p = (Incrblob *)pBlob;
|
||||
return p->nByte;
|
||||
}
|
||||
|
||||
#endif /* #ifndef SQLITE_OMIT_INCRBLOB */
|
|
@ -0,0 +1,114 @@
|
|||
/*
|
||||
** 2005 June 16
|
||||
**
|
||||
** The author disclaims copyright to this source code. In place of
|
||||
** a legal notice, here is a blessing:
|
||||
**
|
||||
** May you do good and not evil.
|
||||
** May you find forgiveness for yourself and forgive others.
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
*************************************************************************
|
||||
** This file implements a FIFO queue of rowids used for processing
|
||||
** UPDATE and DELETE statements.
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include "vdbeInt.h"
|
||||
|
||||
/*
|
||||
** Allocate a new FifoPage and return a pointer to it. Return NULL if
|
||||
** we run out of memory. Leave space on the page for nEntry entries.
|
||||
*/
|
||||
static FifoPage *allocateFifoPage(int nEntry){
|
||||
FifoPage *pPage;
|
||||
if( nEntry>32767 ){
|
||||
nEntry = 32767;
|
||||
}
|
||||
pPage = sqlite3_malloc( 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;
|
||||
sqlite3_free(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;
|
||||
sqlite3_free(pPage);
|
||||
}
|
||||
sqlite3VdbeFifoInit(pFifo);
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,797 @@
|
|||
/*
|
||||
** 2006 June 10
|
||||
**
|
||||
** 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 used to help implement virtual tables.
|
||||
**
|
||||
** $Id: vtab.c,v 1.59 2007/09/20 11:32:18 rse Exp $
|
||||
*/
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
#include "sqliteInt.h"
|
||||
|
||||
static int createModule(
|
||||
sqlite3 *db, /* Database in which module is registered */
|
||||
const char *zName, /* Name assigned to this module */
|
||||
const sqlite3_module *pModule, /* The definition of the module */
|
||||
void *pAux, /* Context pointer for xCreate/xConnect */
|
||||
void (*xDestroy)(void *) /* Module destructor function */
|
||||
) {
|
||||
int rc, nName;
|
||||
Module *pMod;
|
||||
|
||||
sqlite3_mutex_enter(db->mutex);
|
||||
nName = strlen(zName);
|
||||
pMod = (Module *)sqlite3DbMallocRaw(db, sizeof(Module) + nName + 1);
|
||||
if( pMod ){
|
||||
char *zCopy = (char *)(&pMod[1]);
|
||||
memcpy(zCopy, zName, nName+1);
|
||||
pMod->zName = zCopy;
|
||||
pMod->pModule = pModule;
|
||||
pMod->pAux = pAux;
|
||||
pMod->xDestroy = xDestroy;
|
||||
pMod = (Module *)sqlite3HashInsert(&db->aModule, zCopy, nName, (void*)pMod);
|
||||
if( pMod && pMod->xDestroy ){
|
||||
pMod->xDestroy(pMod->pAux);
|
||||
}
|
||||
sqlite3_free(pMod);
|
||||
sqlite3ResetInternalSchema(db, 0);
|
||||
}
|
||||
rc = sqlite3ApiExit(db, SQLITE_OK);
|
||||
sqlite3_mutex_leave(db->mutex);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** External API function used to create a new virtual-table module.
|
||||
*/
|
||||
int sqlite3_create_module(
|
||||
sqlite3 *db, /* Database in which module is registered */
|
||||
const char *zName, /* Name assigned to this module */
|
||||
const sqlite3_module *pModule, /* The definition of the module */
|
||||
void *pAux /* Context pointer for xCreate/xConnect */
|
||||
){
|
||||
return createModule(db, zName, pModule, pAux, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
** External API function used to create a new virtual-table module.
|
||||
*/
|
||||
int sqlite3_create_module_v2(
|
||||
sqlite3 *db, /* Database in which module is registered */
|
||||
const char *zName, /* Name assigned to this module */
|
||||
const sqlite3_module *pModule, /* The definition of the module */
|
||||
void *pAux, /* Context pointer for xCreate/xConnect */
|
||||
void (*xDestroy)(void *) /* Module destructor function */
|
||||
){
|
||||
return createModule(db, zName, pModule, pAux, xDestroy);
|
||||
}
|
||||
|
||||
/*
|
||||
** Lock the virtual table so that it cannot be disconnected.
|
||||
** Locks nest. Every lock should have a corresponding unlock.
|
||||
** If an unlock is omitted, resources leaks will occur.
|
||||
**
|
||||
** If a disconnect is attempted while a virtual table is locked,
|
||||
** the disconnect is deferred until all locks have been removed.
|
||||
*/
|
||||
void sqlite3VtabLock(sqlite3_vtab *pVtab){
|
||||
pVtab->nRef++;
|
||||
}
|
||||
|
||||
/*
|
||||
** Unlock a virtual table. When the last lock is removed,
|
||||
** disconnect the virtual table.
|
||||
*/
|
||||
void sqlite3VtabUnlock(sqlite3 *db, sqlite3_vtab *pVtab){
|
||||
pVtab->nRef--;
|
||||
assert(db);
|
||||
assert(!sqlite3SafetyCheck(db));
|
||||
if( pVtab->nRef==0 ){
|
||||
if( db->magic==SQLITE_MAGIC_BUSY ){
|
||||
sqlite3SafetyOff(db);
|
||||
pVtab->pModule->xDisconnect(pVtab);
|
||||
sqlite3SafetyOn(db);
|
||||
} else {
|
||||
pVtab->pModule->xDisconnect(pVtab);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Clear any and all virtual-table information from the Table record.
|
||||
** This routine is called, for example, just before deleting the Table
|
||||
** record.
|
||||
*/
|
||||
void sqlite3VtabClear(Table *p){
|
||||
sqlite3_vtab *pVtab = p->pVtab;
|
||||
if( pVtab ){
|
||||
assert( p->pMod && p->pMod->pModule );
|
||||
sqlite3VtabUnlock(p->pSchema->db, pVtab);
|
||||
p->pVtab = 0;
|
||||
}
|
||||
if( p->azModuleArg ){
|
||||
int i;
|
||||
for(i=0; i<p->nModuleArg; i++){
|
||||
sqlite3_free(p->azModuleArg[i]);
|
||||
}
|
||||
sqlite3_free(p->azModuleArg);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Add a new module argument to pTable->azModuleArg[].
|
||||
** The string is not copied - the pointer is stored. The
|
||||
** string will be freed automatically when the table is
|
||||
** deleted.
|
||||
*/
|
||||
static void addModuleArgument(sqlite3 *db, Table *pTable, char *zArg){
|
||||
int i = pTable->nModuleArg++;
|
||||
int nBytes = sizeof(char *)*(1+pTable->nModuleArg);
|
||||
char **azModuleArg;
|
||||
azModuleArg = sqlite3DbRealloc(db, pTable->azModuleArg, nBytes);
|
||||
if( azModuleArg==0 ){
|
||||
int j;
|
||||
for(j=0; j<i; j++){
|
||||
sqlite3_free(pTable->azModuleArg[j]);
|
||||
}
|
||||
sqlite3_free(zArg);
|
||||
sqlite3_free(pTable->azModuleArg);
|
||||
pTable->nModuleArg = 0;
|
||||
}else{
|
||||
azModuleArg[i] = zArg;
|
||||
azModuleArg[i+1] = 0;
|
||||
}
|
||||
pTable->azModuleArg = azModuleArg;
|
||||
}
|
||||
|
||||
/*
|
||||
** The parser calls this routine when it first sees a CREATE VIRTUAL TABLE
|
||||
** statement. The module name has been parsed, but the optional list
|
||||
** of parameters that follow the module name are still pending.
|
||||
*/
|
||||
void sqlite3VtabBeginParse(
|
||||
Parse *pParse, /* Parsing context */
|
||||
Token *pName1, /* Name of new table, or database name */
|
||||
Token *pName2, /* Name of new table or NULL */
|
||||
Token *pModuleName /* Name of the module for the virtual table */
|
||||
){
|
||||
int iDb; /* The database the table is being created in */
|
||||
Table *pTable; /* The new virtual table */
|
||||
sqlite3 *db; /* Database connection */
|
||||
|
||||
if( pParse->db->flags & SQLITE_SharedCache ){
|
||||
sqlite3ErrorMsg(pParse, "Cannot use virtual tables in shared-cache mode");
|
||||
return;
|
||||
}
|
||||
|
||||
sqlite3StartTable(pParse, pName1, pName2, 0, 0, 1, 0);
|
||||
pTable = pParse->pNewTable;
|
||||
if( pTable==0 || pParse->nErr ) return;
|
||||
assert( 0==pTable->pIndex );
|
||||
|
||||
db = pParse->db;
|
||||
iDb = sqlite3SchemaToIndex(db, pTable->pSchema);
|
||||
assert( iDb>=0 );
|
||||
|
||||
pTable->isVirtual = 1;
|
||||
pTable->nModuleArg = 0;
|
||||
addModuleArgument(db, pTable, sqlite3NameFromToken(db, pModuleName));
|
||||
addModuleArgument(db, pTable, sqlite3DbStrDup(db, db->aDb[iDb].zName));
|
||||
addModuleArgument(db, pTable, sqlite3DbStrDup(db, pTable->zName));
|
||||
pParse->sNameToken.n = pModuleName->z + pModuleName->n - pName1->z;
|
||||
|
||||
#ifndef SQLITE_OMIT_AUTHORIZATION
|
||||
/* Creating a virtual table invokes the authorization callback twice.
|
||||
** The first invocation, to obtain permission to INSERT a row into the
|
||||
** sqlite_master table, has already been made by sqlite3StartTable().
|
||||
** The second call, to obtain permission to create the table, is made now.
|
||||
*/
|
||||
if( pTable->azModuleArg ){
|
||||
sqlite3AuthCheck(pParse, SQLITE_CREATE_VTABLE, pTable->zName,
|
||||
pTable->azModuleArg[0], pParse->db->aDb[iDb].zName);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
** This routine takes the module argument that has been accumulating
|
||||
** in pParse->zArg[] and appends it to the list of arguments on the
|
||||
** virtual table currently under construction in pParse->pTable.
|
||||
*/
|
||||
static void addArgumentToVtab(Parse *pParse){
|
||||
if( pParse->sArg.z && pParse->pNewTable ){
|
||||
const char *z = (const char*)pParse->sArg.z;
|
||||
int n = pParse->sArg.n;
|
||||
sqlite3 *db = pParse->db;
|
||||
addModuleArgument(db, pParse->pNewTable, sqlite3DbStrNDup(db, z, n));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** The parser calls this routine after the CREATE VIRTUAL TABLE statement
|
||||
** has been completely parsed.
|
||||
*/
|
||||
void sqlite3VtabFinishParse(Parse *pParse, Token *pEnd){
|
||||
Table *pTab; /* The table being constructed */
|
||||
sqlite3 *db; /* The database connection */
|
||||
char *zModule; /* The module name of the table: USING modulename */
|
||||
Module *pMod = 0;
|
||||
|
||||
addArgumentToVtab(pParse);
|
||||
pParse->sArg.z = 0;
|
||||
|
||||
/* Lookup the module name. */
|
||||
pTab = pParse->pNewTable;
|
||||
if( pTab==0 ) return;
|
||||
db = pParse->db;
|
||||
if( pTab->nModuleArg<1 ) return;
|
||||
zModule = pTab->azModuleArg[0];
|
||||
pMod = (Module *)sqlite3HashFind(&db->aModule, zModule, strlen(zModule));
|
||||
pTab->pMod = pMod;
|
||||
|
||||
/* If the CREATE VIRTUAL TABLE statement is being entered for the
|
||||
** first time (in other words if the virtual table is actually being
|
||||
** created now instead of just being read out of sqlite_master) then
|
||||
** do additional initialization work and store the statement text
|
||||
** in the sqlite_master table.
|
||||
*/
|
||||
if( !db->init.busy ){
|
||||
char *zStmt;
|
||||
char *zWhere;
|
||||
int iDb;
|
||||
Vdbe *v;
|
||||
|
||||
/* Compute the complete text of the CREATE VIRTUAL TABLE statement */
|
||||
if( pEnd ){
|
||||
pParse->sNameToken.n = pEnd->z - pParse->sNameToken.z + pEnd->n;
|
||||
}
|
||||
zStmt = sqlite3MPrintf(db, "CREATE VIRTUAL TABLE %T", &pParse->sNameToken);
|
||||
|
||||
/* A slot for the record has already been allocated in the
|
||||
** SQLITE_MASTER table. We just need to update that slot with all
|
||||
** the information we've collected.
|
||||
**
|
||||
** The top of the stack is the rootpage allocated by sqlite3StartTable().
|
||||
** This value is always 0 and is ignored, a virtual table does not have a
|
||||
** rootpage. The next entry on the stack is the rowid of the record
|
||||
** in the sqlite_master table.
|
||||
*/
|
||||
iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
|
||||
sqlite3NestedParse(pParse,
|
||||
"UPDATE %Q.%s "
|
||||
"SET type='table', name=%Q, tbl_name=%Q, rootpage=0, sql=%Q "
|
||||
"WHERE rowid=#1",
|
||||
db->aDb[iDb].zName, SCHEMA_TABLE(iDb),
|
||||
pTab->zName,
|
||||
pTab->zName,
|
||||
zStmt
|
||||
);
|
||||
sqlite3_free(zStmt);
|
||||
v = sqlite3GetVdbe(pParse);
|
||||
sqlite3ChangeCookie(db, v, iDb);
|
||||
|
||||
sqlite3VdbeAddOp(v, OP_Expire, 0, 0);
|
||||
zWhere = sqlite3MPrintf(db, "name='%q'", pTab->zName);
|
||||
sqlite3VdbeOp3(v, OP_ParseSchema, iDb, 1, zWhere, P3_DYNAMIC);
|
||||
sqlite3VdbeOp3(v, OP_VCreate, iDb, 0, pTab->zName, strlen(pTab->zName) + 1);
|
||||
}
|
||||
|
||||
/* If we are rereading the sqlite_master table create the in-memory
|
||||
** record of the table. If the module has already been registered,
|
||||
** also call the xConnect method here.
|
||||
*/
|
||||
else {
|
||||
Table *pOld;
|
||||
Schema *pSchema = pTab->pSchema;
|
||||
const char *zName = pTab->zName;
|
||||
int nName = strlen(zName) + 1;
|
||||
pOld = sqlite3HashInsert(&pSchema->tblHash, zName, nName, pTab);
|
||||
if( pOld ){
|
||||
db->mallocFailed = 1;
|
||||
assert( pTab==pOld ); /* Malloc must have failed inside HashInsert() */
|
||||
return;
|
||||
}
|
||||
pSchema->db = pParse->db;
|
||||
pParse->pNewTable = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** The parser calls this routine when it sees the first token
|
||||
** of an argument to the module name in a CREATE VIRTUAL TABLE statement.
|
||||
*/
|
||||
void sqlite3VtabArgInit(Parse *pParse){
|
||||
addArgumentToVtab(pParse);
|
||||
pParse->sArg.z = 0;
|
||||
pParse->sArg.n = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** The parser calls this routine for each token after the first token
|
||||
** in an argument to the module name in a CREATE VIRTUAL TABLE statement.
|
||||
*/
|
||||
void sqlite3VtabArgExtend(Parse *pParse, Token *p){
|
||||
Token *pArg = &pParse->sArg;
|
||||
if( pArg->z==0 ){
|
||||
pArg->z = p->z;
|
||||
pArg->n = p->n;
|
||||
}else{
|
||||
assert(pArg->z < p->z);
|
||||
pArg->n = (p->z + p->n - pArg->z);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Invoke a virtual table constructor (either xCreate or xConnect). The
|
||||
** pointer to the function to invoke is passed as the fourth parameter
|
||||
** to this procedure.
|
||||
*/
|
||||
static int vtabCallConstructor(
|
||||
sqlite3 *db,
|
||||
Table *pTab,
|
||||
Module *pMod,
|
||||
int (*xConstruct)(sqlite3*,void*,int,const char*const*,sqlite3_vtab**,char**),
|
||||
char **pzErr
|
||||
){
|
||||
int rc;
|
||||
int rc2;
|
||||
sqlite3_vtab *pVtab = 0;
|
||||
const char *const*azArg = (const char *const*)pTab->azModuleArg;
|
||||
int nArg = pTab->nModuleArg;
|
||||
char *zErr = 0;
|
||||
char *zModuleName = sqlite3MPrintf(db, "%s", pTab->zName);
|
||||
|
||||
if( !zModuleName ){
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
|
||||
assert( !db->pVTab );
|
||||
assert( xConstruct );
|
||||
|
||||
db->pVTab = pTab;
|
||||
rc = sqlite3SafetyOff(db);
|
||||
assert( rc==SQLITE_OK );
|
||||
rc = xConstruct(db, pMod->pAux, nArg, azArg, &pVtab, &zErr);
|
||||
rc2 = sqlite3SafetyOn(db);
|
||||
if( rc==SQLITE_OK && pVtab ){
|
||||
pVtab->pModule = pMod->pModule;
|
||||
pVtab->nRef = 1;
|
||||
pTab->pVtab = pVtab;
|
||||
}
|
||||
|
||||
if( SQLITE_OK!=rc ){
|
||||
if( zErr==0 ){
|
||||
*pzErr = sqlite3MPrintf(db, "vtable constructor failed: %s", zModuleName);
|
||||
}else {
|
||||
*pzErr = sqlite3MPrintf(db, "%s", zErr);
|
||||
sqlite3_free(zErr);
|
||||
}
|
||||
}else if( db->pVTab ){
|
||||
const char *zFormat = "vtable constructor did not declare schema: %s";
|
||||
*pzErr = sqlite3MPrintf(db, zFormat, pTab->zName);
|
||||
rc = SQLITE_ERROR;
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = rc2;
|
||||
}
|
||||
db->pVTab = 0;
|
||||
sqlite3_free(zModuleName);
|
||||
|
||||
/* If everything went according to plan, loop through the columns
|
||||
** of the table to see if any of them contain the token "hidden".
|
||||
** If so, set the Column.isHidden flag and remove the token from
|
||||
** the type string.
|
||||
*/
|
||||
if( rc==SQLITE_OK ){
|
||||
int iCol;
|
||||
for(iCol=0; iCol<pTab->nCol; iCol++){
|
||||
char *zType = pTab->aCol[iCol].zType;
|
||||
int nType;
|
||||
int i = 0;
|
||||
if( !zType ) continue;
|
||||
nType = strlen(zType);
|
||||
if( sqlite3StrNICmp("hidden", zType, 6) || (zType[6] && zType[6]!=' ') ){
|
||||
for(i=0; i<nType; i++){
|
||||
if( (0==sqlite3StrNICmp(" hidden", &zType[i], 7))
|
||||
&& (zType[i+7]=='\0' || zType[i+7]==' ')
|
||||
){
|
||||
i++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if( i<nType ){
|
||||
int j;
|
||||
int nDel = 6 + (zType[i+6] ? 1 : 0);
|
||||
for(j=i; (j+nDel)<=nType; j++){
|
||||
zType[j] = zType[j+nDel];
|
||||
}
|
||||
if( zType[i]=='\0' && i>0 ){
|
||||
assert(zType[i-1]==' ');
|
||||
zType[i-1] = '\0';
|
||||
}
|
||||
pTab->aCol[iCol].isHidden = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** This function is invoked by the parser to call the xConnect() method
|
||||
** of the virtual table pTab. If an error occurs, an error code is returned
|
||||
** and an error left in pParse.
|
||||
**
|
||||
** This call is a no-op if table pTab is not a virtual table.
|
||||
*/
|
||||
int sqlite3VtabCallConnect(Parse *pParse, Table *pTab){
|
||||
Module *pMod;
|
||||
int rc = SQLITE_OK;
|
||||
|
||||
if( !pTab || !pTab->isVirtual || pTab->pVtab ){
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
pMod = pTab->pMod;
|
||||
if( !pMod ){
|
||||
const char *zModule = pTab->azModuleArg[0];
|
||||
sqlite3ErrorMsg(pParse, "no such module: %s", zModule);
|
||||
rc = SQLITE_ERROR;
|
||||
} else {
|
||||
char *zErr = 0;
|
||||
sqlite3 *db = pParse->db;
|
||||
rc = vtabCallConstructor(db, pTab, pMod, pMod->pModule->xConnect, &zErr);
|
||||
if( rc!=SQLITE_OK ){
|
||||
sqlite3ErrorMsg(pParse, "%s", zErr);
|
||||
}
|
||||
sqlite3_free(zErr);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Add the virtual table pVtab to the array sqlite3.aVTrans[].
|
||||
*/
|
||||
static int addToVTrans(sqlite3 *db, sqlite3_vtab *pVtab){
|
||||
const int ARRAY_INCR = 5;
|
||||
|
||||
/* Grow the sqlite3.aVTrans array if required */
|
||||
if( (db->nVTrans%ARRAY_INCR)==0 ){
|
||||
sqlite3_vtab **aVTrans;
|
||||
int nBytes = sizeof(sqlite3_vtab *) * (db->nVTrans + ARRAY_INCR);
|
||||
aVTrans = sqlite3DbRealloc(db, (void *)db->aVTrans, nBytes);
|
||||
if( !aVTrans ){
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
memset(&aVTrans[db->nVTrans], 0, sizeof(sqlite3_vtab *)*ARRAY_INCR);
|
||||
db->aVTrans = aVTrans;
|
||||
}
|
||||
|
||||
/* Add pVtab to the end of sqlite3.aVTrans */
|
||||
db->aVTrans[db->nVTrans++] = pVtab;
|
||||
sqlite3VtabLock(pVtab);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** This function is invoked by the vdbe to call the xCreate method
|
||||
** of the virtual table named zTab in database iDb.
|
||||
**
|
||||
** 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.
|
||||
** In this case the caller must call sqlite3_free() on *pzErr.
|
||||
*/
|
||||
int sqlite3VtabCallCreate(sqlite3 *db, int iDb, const char *zTab, char **pzErr){
|
||||
int rc = SQLITE_OK;
|
||||
Table *pTab;
|
||||
Module *pMod;
|
||||
const char *zModule;
|
||||
|
||||
pTab = sqlite3FindTable(db, zTab, db->aDb[iDb].zName);
|
||||
assert(pTab && pTab->isVirtual && !pTab->pVtab);
|
||||
pMod = pTab->pMod;
|
||||
zModule = pTab->azModuleArg[0];
|
||||
|
||||
/* If the module has been registered and includes a Create method,
|
||||
** invoke it now. If the module has not been registered, return an
|
||||
** error. Otherwise, do nothing.
|
||||
*/
|
||||
if( !pMod ){
|
||||
*pzErr = sqlite3MPrintf(db, "no such module: %s", zModule);
|
||||
rc = SQLITE_ERROR;
|
||||
}else{
|
||||
rc = vtabCallConstructor(db, pTab, pMod, pMod->pModule->xCreate, pzErr);
|
||||
}
|
||||
|
||||
if( rc==SQLITE_OK && pTab->pVtab ){
|
||||
rc = addToVTrans(db, pTab->pVtab);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** This function is used to set the schema of a virtual table. It is only
|
||||
** valid to call this function from within the xCreate() or xConnect() of a
|
||||
** virtual table module.
|
||||
*/
|
||||
int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){
|
||||
Parse sParse;
|
||||
|
||||
int rc = SQLITE_OK;
|
||||
Table *pTab;
|
||||
char *zErr = 0;
|
||||
|
||||
sqlite3_mutex_enter(db->mutex);
|
||||
pTab = db->pVTab;
|
||||
if( !pTab ){
|
||||
sqlite3Error(db, SQLITE_MISUSE, 0);
|
||||
sqlite3_mutex_leave(db->mutex);
|
||||
return SQLITE_MISUSE;
|
||||
}
|
||||
assert(pTab->isVirtual && pTab->nCol==0 && pTab->aCol==0);
|
||||
|
||||
memset(&sParse, 0, sizeof(Parse));
|
||||
sParse.declareVtab = 1;
|
||||
sParse.db = db;
|
||||
|
||||
if(
|
||||
SQLITE_OK == sqlite3RunParser(&sParse, zCreateTable, &zErr) &&
|
||||
sParse.pNewTable &&
|
||||
!sParse.pNewTable->pSelect &&
|
||||
!sParse.pNewTable->isVirtual
|
||||
){
|
||||
pTab->aCol = sParse.pNewTable->aCol;
|
||||
pTab->nCol = sParse.pNewTable->nCol;
|
||||
sParse.pNewTable->nCol = 0;
|
||||
sParse.pNewTable->aCol = 0;
|
||||
db->pVTab = 0;
|
||||
} else {
|
||||
sqlite3Error(db, SQLITE_ERROR, zErr);
|
||||
sqlite3_free(zErr);
|
||||
rc = SQLITE_ERROR;
|
||||
}
|
||||
sParse.declareVtab = 0;
|
||||
|
||||
sqlite3_finalize((sqlite3_stmt*)sParse.pVdbe);
|
||||
sqlite3DeleteTable(sParse.pNewTable);
|
||||
sParse.pNewTable = 0;
|
||||
|
||||
assert( (rc&0xff)==rc );
|
||||
rc = sqlite3ApiExit(db, rc);
|
||||
sqlite3_mutex_leave(db->mutex);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** This function is invoked by the vdbe to call the xDestroy method
|
||||
** of the virtual table named zTab in database iDb. This occurs
|
||||
** when a DROP TABLE is mentioned.
|
||||
**
|
||||
** This call is a no-op if zTab is not a virtual table.
|
||||
*/
|
||||
int sqlite3VtabCallDestroy(sqlite3 *db, int iDb, const char *zTab)
|
||||
{
|
||||
int rc = SQLITE_OK;
|
||||
Table *pTab;
|
||||
|
||||
pTab = sqlite3FindTable(db, zTab, db->aDb[iDb].zName);
|
||||
assert(pTab);
|
||||
if( pTab->pVtab ){
|
||||
int (*xDestroy)(sqlite3_vtab *pVTab) = pTab->pMod->pModule->xDestroy;
|
||||
rc = sqlite3SafetyOff(db);
|
||||
assert( rc==SQLITE_OK );
|
||||
if( xDestroy ){
|
||||
rc = xDestroy(pTab->pVtab);
|
||||
}
|
||||
sqlite3SafetyOn(db);
|
||||
if( rc==SQLITE_OK ){
|
||||
pTab->pVtab = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** This function invokes either the xRollback or xCommit method
|
||||
** of each of the virtual tables in the sqlite3.aVTrans array. The method
|
||||
** called is identified by the second argument, "offset", which is
|
||||
** the offset of the method to call in the sqlite3_module structure.
|
||||
**
|
||||
** The array is cleared after invoking the callbacks.
|
||||
*/
|
||||
static void callFinaliser(sqlite3 *db, int offset){
|
||||
int i;
|
||||
if( db->aVTrans ){
|
||||
for(i=0; i<db->nVTrans && db->aVTrans[i]; i++){
|
||||
sqlite3_vtab *pVtab = db->aVTrans[i];
|
||||
int (*x)(sqlite3_vtab *);
|
||||
x = *(int (**)(sqlite3_vtab *))((char *)pVtab->pModule + offset);
|
||||
if( x ) x(pVtab);
|
||||
sqlite3VtabUnlock(db, pVtab);
|
||||
}
|
||||
sqlite3_free(db->aVTrans);
|
||||
db->nVTrans = 0;
|
||||
db->aVTrans = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** If argument rc2 is not SQLITE_OK, then return it and do nothing.
|
||||
** Otherwise, invoke the xSync method of all virtual tables in the
|
||||
** sqlite3.aVTrans array. Return the error code for the first error
|
||||
** that occurs, or SQLITE_OK if all xSync operations are successful.
|
||||
*/
|
||||
int sqlite3VtabSync(sqlite3 *db, int rc2){
|
||||
int i;
|
||||
int rc = SQLITE_OK;
|
||||
int rcsafety;
|
||||
sqlite3_vtab **aVTrans = db->aVTrans;
|
||||
if( rc2!=SQLITE_OK ) return rc2;
|
||||
|
||||
rc = sqlite3SafetyOff(db);
|
||||
db->aVTrans = 0;
|
||||
for(i=0; rc==SQLITE_OK && i<db->nVTrans && aVTrans[i]; i++){
|
||||
sqlite3_vtab *pVtab = aVTrans[i];
|
||||
int (*x)(sqlite3_vtab *);
|
||||
x = pVtab->pModule->xSync;
|
||||
if( x ){
|
||||
rc = x(pVtab);
|
||||
}
|
||||
}
|
||||
db->aVTrans = aVTrans;
|
||||
rcsafety = sqlite3SafetyOn(db);
|
||||
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = rcsafety;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Invoke the xRollback method of all virtual tables in the
|
||||
** sqlite3.aVTrans array. Then clear the array itself.
|
||||
*/
|
||||
int sqlite3VtabRollback(sqlite3 *db){
|
||||
callFinaliser(db, (int)(&((sqlite3_module *)0)->xRollback));
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Invoke the xCommit method of all virtual tables in the
|
||||
** sqlite3.aVTrans array. Then clear the array itself.
|
||||
*/
|
||||
int sqlite3VtabCommit(sqlite3 *db){
|
||||
callFinaliser(db, (int)(&((sqlite3_module *)0)->xCommit));
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** If the virtual table pVtab supports the transaction interface
|
||||
** (xBegin/xRollback/xCommit and optionally xSync) and a transaction is
|
||||
** not currently open, invoke the xBegin method now.
|
||||
**
|
||||
** If the xBegin call is successful, place the sqlite3_vtab pointer
|
||||
** in the sqlite3.aVTrans array.
|
||||
*/
|
||||
int sqlite3VtabBegin(sqlite3 *db, sqlite3_vtab *pVtab){
|
||||
int rc = SQLITE_OK;
|
||||
const sqlite3_module *pModule;
|
||||
|
||||
/* Special case: If db->aVTrans is NULL and db->nVTrans is greater
|
||||
** than zero, then this function is being called from within a
|
||||
** virtual module xSync() callback. It is illegal to write to
|
||||
** virtual module tables in this case, so return SQLITE_LOCKED.
|
||||
*/
|
||||
if( 0==db->aVTrans && db->nVTrans>0 ){
|
||||
return SQLITE_LOCKED;
|
||||
}
|
||||
if( !pVtab ){
|
||||
return SQLITE_OK;
|
||||
}
|
||||
pModule = pVtab->pModule;
|
||||
|
||||
if( pModule->xBegin ){
|
||||
int i;
|
||||
|
||||
|
||||
/* If pVtab is already in the aVTrans array, return early */
|
||||
for(i=0; (i<db->nVTrans) && 0!=db->aVTrans[i]; i++){
|
||||
if( db->aVTrans[i]==pVtab ){
|
||||
return SQLITE_OK;
|
||||
}
|
||||
}
|
||||
|
||||
/* Invoke the xBegin method */
|
||||
rc = pModule->xBegin(pVtab);
|
||||
if( rc!=SQLITE_OK ){
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = addToVTrans(db, pVtab);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** The first parameter (pDef) is a function implementation. The
|
||||
** second parameter (pExpr) is the first argument to this function.
|
||||
** If pExpr is a column in a virtual table, then let the virtual
|
||||
** table implementation have an opportunity to overload the function.
|
||||
**
|
||||
** This routine is used to allow virtual table implementations to
|
||||
** overload MATCH, LIKE, GLOB, and REGEXP operators.
|
||||
**
|
||||
** Return either the pDef argument (indicating no change) or a
|
||||
** new FuncDef structure that is marked as ephemeral using the
|
||||
** SQLITE_FUNC_EPHEM flag.
|
||||
*/
|
||||
FuncDef *sqlite3VtabOverloadFunction(
|
||||
sqlite3 *db, /* Database connection for reporting malloc problems */
|
||||
FuncDef *pDef, /* Function to possibly overload */
|
||||
int nArg, /* Number of arguments to the function */
|
||||
Expr *pExpr /* First argument to the function */
|
||||
){
|
||||
Table *pTab;
|
||||
sqlite3_vtab *pVtab;
|
||||
sqlite3_module *pMod;
|
||||
void (*xFunc)(sqlite3_context*,int,sqlite3_value**);
|
||||
void *pArg;
|
||||
FuncDef *pNew;
|
||||
int rc = 0;
|
||||
char *zLowerName;
|
||||
unsigned char *z;
|
||||
|
||||
|
||||
/* Check to see the left operand is a column in a virtual table */
|
||||
if( pExpr==0 ) return pDef;
|
||||
if( pExpr->op!=TK_COLUMN ) return pDef;
|
||||
pTab = pExpr->pTab;
|
||||
if( pTab==0 ) return pDef;
|
||||
if( !pTab->isVirtual ) return pDef;
|
||||
pVtab = pTab->pVtab;
|
||||
assert( pVtab!=0 );
|
||||
assert( pVtab->pModule!=0 );
|
||||
pMod = (sqlite3_module *)pVtab->pModule;
|
||||
if( pMod->xFindFunction==0 ) return pDef;
|
||||
|
||||
/* Call the xFindFunction method on the virtual table implementation
|
||||
** to see if the implementation wants to overload this function
|
||||
*/
|
||||
zLowerName = sqlite3DbStrDup(db, pDef->zName);
|
||||
if( zLowerName ){
|
||||
for(z=(unsigned char*)zLowerName; *z; z++){
|
||||
*z = sqlite3UpperToLower[*z];
|
||||
}
|
||||
rc = pMod->xFindFunction(pVtab, nArg, zLowerName, &xFunc, &pArg);
|
||||
sqlite3_free(zLowerName);
|
||||
}
|
||||
if( rc==0 ){
|
||||
return pDef;
|
||||
}
|
||||
|
||||
/* Create a new ephemeral function definition for the overloaded
|
||||
** function */
|
||||
pNew = sqlite3DbMallocZero(db, sizeof(*pNew) + strlen(pDef->zName) );
|
||||
if( pNew==0 ){
|
||||
return pDef;
|
||||
}
|
||||
*pNew = *pDef;
|
||||
memcpy(pNew->zName, pDef->zName, strlen(pDef->zName)+1);
|
||||
pNew->xFunc = xFunc;
|
||||
pNew->pUserData = pArg;
|
||||
pNew->flags |= SQLITE_FUNC_EPHEM;
|
||||
return pNew;
|
||||
}
|
||||
|
||||
#endif /* SQLITE_OMIT_VIRTUALTABLE */
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue