зеркало из https://github.com/mozilla/pjs.git
Update to SQLite 3.2.0
This commit is contained in:
Родитель
e62faa7147
Коммит
7be0b0b8dc
|
@ -48,11 +48,12 @@ LIBRARY_NAME = sqlite3_s
|
|||
MODULE_NAME = sqlite3
|
||||
FORCE_STATIC_LIB = 1
|
||||
|
||||
VERSION = 3.0.8
|
||||
VERSION = 3.2.0
|
||||
|
||||
EXPORTS = sqlite3.h
|
||||
|
||||
CSRCS = \
|
||||
alter.c \
|
||||
attach.c \
|
||||
auth.c \
|
||||
btree.c \
|
||||
|
|
|
@ -0,0 +1,550 @@
|
|||
/*
|
||||
** 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.1 2005-03-22 23:10:06 vladimir%pobox.com 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 second
|
||||
** 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;
|
||||
char const *zCsr = zSql;
|
||||
int len = 0;
|
||||
char *zRet;
|
||||
|
||||
/* 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.
|
||||
*/
|
||||
if( zSql ){
|
||||
do {
|
||||
/* 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 );
|
||||
|
||||
zRet = sqlite3MPrintf("%.*s%Q%s", tname.z - zSql, zSql,
|
||||
zTableName, tname.z+tname.n);
|
||||
sqlite3_result_text(context, zRet, -1, sqlite3FreeX);
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef SQLITE_OMIT_TRIGGER
|
||||
/* This function is used by SQL generated to implement the ALTER TABLE
|
||||
** 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 second 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;
|
||||
char const *zCsr = zSql;
|
||||
int len = 0;
|
||||
char *zRet;
|
||||
|
||||
/* 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 {
|
||||
/* 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("%.*s%Q%s", tname.z - zSql, zSql,
|
||||
zTableName, tname.z+tname.n);
|
||||
sqlite3_result_text(context, zRet, -1, sqlite3FreeX);
|
||||
}
|
||||
}
|
||||
#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++){
|
||||
sqlite3_create_function(db, aFuncs[i].zName, aFuncs[i].nArg,
|
||||
SQLITE_UTF8, 0, 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;
|
||||
if( pTab->iDb!=1 ){
|
||||
for( pTrig=pTab->pTrigger; pTrig; pTrig=pTrig->pNext ){
|
||||
if( pTrig->iDb==1 ){
|
||||
if( !zWhere ){
|
||||
zWhere = sqlite3MPrintf("name=%Q", pTrig->name);
|
||||
}else{
|
||||
tmp = zWhere;
|
||||
zWhere = sqlite3MPrintf("%s OR name=%Q", zWhere, pTrig->name);
|
||||
sqliteFree(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;
|
||||
#ifndef SQLITE_OMIT_TRIGGER
|
||||
Trigger *pTrig;
|
||||
#endif
|
||||
|
||||
v = sqlite3GetVdbe(pParse);
|
||||
if( !v ) return;
|
||||
iDb = pTab->iDb;
|
||||
|
||||
#ifndef SQLITE_OMIT_TRIGGER
|
||||
/* Drop any table triggers from the internal schema. */
|
||||
for(pTrig=pTab->pTrigger; pTrig; pTrig=pTrig->pNext){
|
||||
assert( pTrig->iDb==iDb || pTrig->iDb==1 );
|
||||
sqlite3VdbeOp3(v, OP_DropTrigger, pTrig->iDb, 0, pTrig->name, 0);
|
||||
}
|
||||
#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("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)) ){
|
||||
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 */
|
||||
Vdbe *v;
|
||||
#ifndef SQLITE_OMIT_TRIGGER
|
||||
char *zWhere = 0; /* Where clause to locate temp triggers */
|
||||
#endif
|
||||
|
||||
assert( pSrc->nSrc==1 );
|
||||
|
||||
pTab = sqlite3LocateTable(pParse, pSrc->a[0].zName, pSrc->a[0].zDatabase);
|
||||
if( !pTab ) goto exit_rename_table;
|
||||
iDb = pTab->iDb;
|
||||
zDb = db->aDb[iDb].zName;
|
||||
|
||||
/* Get a NULL terminated version of the new table name. */
|
||||
zName = sqlite3NameFromToken(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
|
||||
|
||||
/* Begin a transaction and code the VerifyCookie for database iDb.
|
||||
** Then modify the schema cookie (since the ALTER TABLE modifies the
|
||||
** schema).
|
||||
*/
|
||||
v = sqlite3GetVdbe(pParse);
|
||||
if( v==0 ){
|
||||
goto exit_rename_table;
|
||||
}
|
||||
sqlite3BeginWriteOperation(pParse, 0, iDb);
|
||||
sqlite3ChangeCookie(db, v, iDb);
|
||||
|
||||
/* 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, strlen(pTab->zName), pTab->zName
|
||||
);
|
||||
|
||||
#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)) ){
|
||||
sqlite3NestedParse(pParse,
|
||||
"UPDATE sqlite_temp_master SET "
|
||||
"sql = sqlite_rename_trigger(sql, %Q), "
|
||||
"tbl_name = %Q "
|
||||
"WHERE %s;", zName, zName, zWhere);
|
||||
sqliteFree(zWhere);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Drop and reload the internal table schema. */
|
||||
reloadTableSchema(pParse, pTab, zName);
|
||||
|
||||
exit_rename_table:
|
||||
sqlite3SrcListDelete(pSrc);
|
||||
sqliteFree(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 */
|
||||
Vdbe *v;
|
||||
|
||||
if( pParse->nErr ) return;
|
||||
pNew = pParse->pNewTable;
|
||||
assert( pNew );
|
||||
|
||||
iDb = pNew->iDb;
|
||||
zDb = pParse->db->aDb[iDb].zName;
|
||||
zTab = pNew->zName;
|
||||
pCol = &pNew->aCol[pNew->nCol-1];
|
||||
pDflt = pCol->pDflt;
|
||||
pTab = sqlite3FindTable(pParse->db, zTab, zDb);
|
||||
assert( pTab );
|
||||
|
||||
/* 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(pDflt, SQLITE_UTF8, SQLITE_AFF_NONE, &pVal) ){
|
||||
/* malloc() has failed */
|
||||
return;
|
||||
}
|
||||
if( !pVal ){
|
||||
sqlite3ErrorMsg(pParse, "Cannot add a column with non-constant default");
|
||||
return;
|
||||
}
|
||||
sqlite3ValueFree(pVal);
|
||||
}
|
||||
|
||||
/* Modify the CREATE TABLE statement. */
|
||||
zCol = sqliteStrNDup(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,0,%d) || ', ' || %Q || substr(sql,%d,length(sql)) "
|
||||
"WHERE type = 'table' AND name = %Q",
|
||||
zDb, SCHEMA_TABLE(iDb), pNew->addColOffset, zCol, pNew->addColOffset+1,
|
||||
zTab
|
||||
);
|
||||
sqliteFree(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.
|
||||
*/
|
||||
if( (v=sqlite3GetVdbe(pParse)) ){
|
||||
int f = (pDflt?3:2);
|
||||
|
||||
/* Only set the file format to $f if it is currently less than $f. */
|
||||
sqlite3VdbeAddOp(v, OP_ReadCookie, iDb, 1);
|
||||
sqlite3VdbeAddOp(v, OP_Integer, f, 0);
|
||||
sqlite3VdbeAddOp(v, OP_Ge, 0, sqlite3VdbeCurrentAddr(v)+3);
|
||||
sqlite3VdbeAddOp(v, OP_Integer, f, 0);
|
||||
sqlite3VdbeAddOp(v, OP_SetCookie, iDb, 1);
|
||||
}
|
||||
|
||||
/* 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;
|
||||
|
||||
/* Look up the table being altered. */
|
||||
assert( !pParse->pNewTable );
|
||||
pTab = sqlite3LocateTable(pParse, pSrc->a[0].zName, pSrc->a[0].zDatabase);
|
||||
if( !pTab ) goto exit_begin_add_column;
|
||||
|
||||
/* 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 = pTab->iDb;
|
||||
|
||||
/* Put a copy of the Table struct in Parse.pNewTable for the
|
||||
** sqlite3AddColumn() function and friends to modify.
|
||||
*/
|
||||
pNew = (Table *)sqliteMalloc(sizeof(Table));
|
||||
if( !pNew ) goto exit_begin_add_column;
|
||||
pParse->pNewTable = pNew;
|
||||
pNew->nCol = pTab->nCol;
|
||||
nAlloc = ((pNew->nCol)/8)+8;
|
||||
pNew->aCol = (Column *)sqliteMalloc(sizeof(Column)*nAlloc);
|
||||
pNew->zName = sqliteStrDup(pTab->zName);
|
||||
if( !pNew->aCol || !pNew->zName ){
|
||||
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 = sqliteStrDup(pCol->zName);
|
||||
pCol->zType = 0;
|
||||
pCol->pDflt = 0;
|
||||
}
|
||||
pNew->iDb = iDb;
|
||||
pNew->addColOffset = pTab->addColOffset;
|
||||
|
||||
/* Begin a transaction and increment the schema cookie. */
|
||||
sqlite3BeginWriteOperation(pParse, 0, iDb);
|
||||
v = sqlite3GetVdbe(pParse);
|
||||
if( !v ) goto exit_begin_add_column;
|
||||
sqlite3ChangeCookie(pParse->db, v, iDb);
|
||||
|
||||
exit_begin_add_column:
|
||||
sqlite3SrcListDelete(pSrc);
|
||||
return;
|
||||
}
|
||||
#endif /* SQLITE_ALTER_TABLE */
|
|
@ -11,7 +11,7 @@
|
|||
*************************************************************************
|
||||
** This file contains code used to implement the ATTACH and DETACH commands.
|
||||
**
|
||||
** $Id: attach.c,v 1.28 2004/09/06 17:24:12 drh Exp $
|
||||
** $Id: attach.c,v 1.33 2005/03/16 12:15:21 danielk1977 Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
|
||||
|
@ -32,12 +32,14 @@ void sqlite3Attach(
|
|||
){
|
||||
Db *aNew;
|
||||
int rc, i;
|
||||
char *zFile, *zName;
|
||||
char *zFile = 0;
|
||||
char *zName = 0;
|
||||
sqlite3 *db;
|
||||
Vdbe *v;
|
||||
|
||||
v = sqlite3GetVdbe(pParse);
|
||||
if( !v ) return;
|
||||
sqlite3VdbeAddOp(v, OP_Expire, 1, 0);
|
||||
sqlite3VdbeAddOp(v, OP_Halt, 0, 0);
|
||||
if( pParse->explain ) return;
|
||||
db = pParse->db;
|
||||
|
@ -54,34 +56,40 @@ void sqlite3Attach(
|
|||
return;
|
||||
}
|
||||
|
||||
zFile = sqlite3NameFromToken(pFilename);;
|
||||
if( zFile==0 ) return;
|
||||
zFile = sqlite3NameFromToken(pFilename);
|
||||
if( zFile==0 ){
|
||||
goto attach_end;
|
||||
}
|
||||
#ifndef SQLITE_OMIT_AUTHORIZATION
|
||||
if( sqlite3AuthCheck(pParse, SQLITE_ATTACH, zFile, 0, 0)!=SQLITE_OK ){
|
||||
sqliteFree(zFile);
|
||||
return;
|
||||
goto attach_end;
|
||||
}
|
||||
#endif /* SQLITE_OMIT_AUTHORIZATION */
|
||||
|
||||
zName = sqlite3NameFromToken(pDbname);
|
||||
if( zName==0 ) return;
|
||||
if( zName==0 ){
|
||||
goto attach_end;
|
||||
}
|
||||
for(i=0; i<db->nDb; i++){
|
||||
char *z = db->aDb[i].zName;
|
||||
if( z && sqlite3StrICmp(z, zName)==0 ){
|
||||
sqlite3ErrorMsg(pParse, "database %z is already in use", zName);
|
||||
sqlite3ErrorMsg(pParse, "database %s is already in use", zName);
|
||||
pParse->rc = SQLITE_ERROR;
|
||||
sqliteFree(zFile);
|
||||
return;
|
||||
goto attach_end;
|
||||
}
|
||||
}
|
||||
|
||||
if( db->aDb==db->aDbStatic ){
|
||||
aNew = sqliteMalloc( sizeof(db->aDb[0])*3 );
|
||||
if( aNew==0 ) return;
|
||||
if( aNew==0 ){
|
||||
goto attach_end;
|
||||
}
|
||||
memcpy(aNew, db->aDb, sizeof(db->aDb[0])*2);
|
||||
}else{
|
||||
aNew = sqliteRealloc(db->aDb, sizeof(db->aDb[0])*(db->nDb+1) );
|
||||
if( aNew==0 ) return;
|
||||
if( aNew==0 ){
|
||||
goto attach_end;
|
||||
}
|
||||
}
|
||||
db->aDb = aNew;
|
||||
aNew = &db->aDb[db->nDb++];
|
||||
|
@ -91,6 +99,7 @@ void sqlite3Attach(
|
|||
sqlite3HashInit(&aNew->trigHash, SQLITE_HASH_STRING, 0);
|
||||
sqlite3HashInit(&aNew->aFKey, SQLITE_HASH_STRING, 1);
|
||||
aNew->zName = zName;
|
||||
zName = 0;
|
||||
aNew->safety_level = 3;
|
||||
rc = sqlite3BtreeFactory(db, zFile, 0, MAX_PAGES, &aNew->pBt);
|
||||
if( rc ){
|
||||
|
@ -125,7 +134,6 @@ void sqlite3Attach(
|
|||
}
|
||||
}
|
||||
#endif
|
||||
sqliteFree(zFile);
|
||||
db->flags &= ~SQLITE_Initialized;
|
||||
if( pParse->nErr==0 && rc==SQLITE_OK ){
|
||||
rc = sqlite3ReadSchema(pParse);
|
||||
|
@ -143,6 +151,10 @@ void sqlite3Attach(
|
|||
pParse->rc = SQLITE_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
attach_end:
|
||||
sqliteFree(zFile);
|
||||
sqliteFree(zName);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -157,26 +169,30 @@ void sqlite3Detach(Parse *pParse, Token *pDbname){
|
|||
sqlite3 *db;
|
||||
Vdbe *v;
|
||||
Db *pDb = 0;
|
||||
char *zName;
|
||||
|
||||
v = sqlite3GetVdbe(pParse);
|
||||
if( !v ) return;
|
||||
sqlite3VdbeAddOp(v, OP_Expire, 0, 0);
|
||||
sqlite3VdbeAddOp(v, OP_Halt, 0, 0);
|
||||
if( pParse->explain ) return;
|
||||
db = pParse->db;
|
||||
zName = sqlite3NameFromToken(pDbname);
|
||||
if( zName==0 ) return;
|
||||
for(i=0; i<db->nDb; i++){
|
||||
pDb = &db->aDb[i];
|
||||
if( pDb->pBt==0 || pDb->zName==0 ) continue;
|
||||
if( strlen(pDb->zName)!=pDbname->n ) continue;
|
||||
if( sqlite3StrNICmp(pDb->zName, pDbname->z, pDbname->n)==0 ) break;
|
||||
if( pDb->pBt==0 ) continue;
|
||||
if( sqlite3StrICmp(pDb->zName, zName)==0 ) break;
|
||||
}
|
||||
if( i>=db->nDb ){
|
||||
sqlite3ErrorMsg(pParse, "no such database: %T", pDbname);
|
||||
sqlite3ErrorMsg(pParse, "no such database: %z", zName);
|
||||
return;
|
||||
}
|
||||
if( i<2 ){
|
||||
sqlite3ErrorMsg(pParse, "cannot detach database %T", pDbname);
|
||||
sqlite3ErrorMsg(pParse, "cannot detach database %z", zName);
|
||||
return;
|
||||
}
|
||||
sqliteFree(zName);
|
||||
if( !db->autoCommit ){
|
||||
sqlite3ErrorMsg(pParse, "cannot DETACH database within transaction");
|
||||
pParse->rc = SQLITE_ERROR;
|
||||
|
@ -251,11 +267,14 @@ int sqlite3FixSrcList(
|
|||
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 */
|
||||
|
@ -309,6 +328,9 @@ int sqlite3FixExprList(
|
|||
}
|
||||
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 */
|
||||
|
@ -327,3 +349,4 @@ int sqlite3FixTriggerStep(
|
|||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
** systems that do not need this facility may omit it by recompiling
|
||||
** the library with -DSQLITE_OMIT_AUTHORIZATION=1
|
||||
**
|
||||
** $Id: auth.c,v 1.19 2004/09/30 13:43:13 drh Exp $
|
||||
** $Id: auth.c,v 1.21 2005/01/29 08:32:44 danielk1977 Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
|
||||
|
@ -76,6 +76,7 @@ int sqlite3_set_authorizer(
|
|||
){
|
||||
db->xAuth = xAuth;
|
||||
db->pAuthArg = pArg;
|
||||
sqlite3ExpirePreparedStatements(db);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
|
@ -114,10 +115,10 @@ void sqlite3AuthRead(
|
|||
|
||||
if( db->xAuth==0 ) return;
|
||||
assert( pExpr->op==TK_COLUMN );
|
||||
for(iSrc=0; iSrc<pTabList->nSrc; iSrc++){
|
||||
for(iSrc=0; pTabList && iSrc<pTabList->nSrc; iSrc++){
|
||||
if( pExpr->iTable==pTabList->a[iSrc].iCursor ) break;
|
||||
}
|
||||
if( iSrc>=0 && iSrc<pTabList->nSrc ){
|
||||
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
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -13,7 +13,7 @@
|
|||
** subsystem. See comments in the source code for a detailed description
|
||||
** of what each interface routine does.
|
||||
**
|
||||
** @(#) $Id: btree.h,v 1.58 2004/07/23 00:01:39 drh Exp $
|
||||
** @(#) $Id: btree.h,v 1.63 2005/03/21 04:04:03 danielk1977 Exp $
|
||||
*/
|
||||
#ifndef _BTREE_H_
|
||||
#define _BTREE_H_
|
||||
|
@ -23,6 +23,14 @@
|
|||
*/
|
||||
#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
|
||||
|
||||
/*
|
||||
** Forward declarations of structure
|
||||
*/
|
||||
|
@ -38,9 +46,13 @@ int sqlite3BtreeOpen(
|
|||
|
||||
/* 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_MEMORY 2 /* In-memory DB. No argument */
|
||||
#define BTREE_NO_READLOCK 2 /* Omit readlocks on readonly files */
|
||||
#define BTREE_MEMORY 4 /* In-memory DB. No argument */
|
||||
|
||||
int sqlite3BtreeClose(Btree*);
|
||||
int sqlite3BtreeSetBusyHandler(Btree*,BusyHandler*);
|
||||
|
@ -49,6 +61,8 @@ int sqlite3BtreeSetSafetyLevel(Btree*,int);
|
|||
int sqlite3BtreeSetPageSize(Btree*,int,int);
|
||||
int sqlite3BtreeGetPageSize(Btree*);
|
||||
int sqlite3BtreeGetReserve(Btree*);
|
||||
int sqlite3BtreeSetAutoVacuum(Btree *, int);
|
||||
int sqlite3BtreeGetAutoVacuum(Btree *);
|
||||
int sqlite3BtreeBeginTrans(Btree*,int);
|
||||
int sqlite3BtreeCommit(Btree*);
|
||||
int sqlite3BtreeRollback(Btree*);
|
||||
|
@ -59,6 +73,7 @@ int sqlite3BtreeCreateTable(Btree*, int*, int flags);
|
|||
int sqlite3BtreeIsInTrans(Btree*);
|
||||
int sqlite3BtreeIsInStmt(Btree*);
|
||||
int sqlite3BtreeSync(Btree*, const char *zMaster);
|
||||
int sqlite3BtreeReset(Btree *);
|
||||
|
||||
const char *sqlite3BtreeGetFilename(Btree *);
|
||||
const char *sqlite3BtreeGetDirname(Btree *);
|
||||
|
@ -72,7 +87,7 @@ int sqlite3BtreeCopyFile(Btree *, Btree *);
|
|||
#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 sqlite3BtreeDropTable(Btree*, int, int*);
|
||||
int sqlite3BtreeClearTable(Btree*, int);
|
||||
int sqlite3BtreeGetMeta(Btree*, int idx, u32 *pValue);
|
||||
int sqlite3BtreeUpdateMeta(Btree*, int idx, u32 value);
|
||||
|
@ -117,8 +132,12 @@ struct Pager *sqlite3BtreePager(Btree*);
|
|||
#ifdef SQLITE_TEST
|
||||
int sqlite3BtreeCursorInfo(BtCursor*, int*, int);
|
||||
void sqlite3BtreeCursorList(Btree*);
|
||||
int sqlite3BtreePageDump(Btree*, int, int recursive);
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_DEBUG
|
||||
int sqlite3BtreePageDump(Btree*, int, int recursive);
|
||||
#else
|
||||
#define sqlite3BtreePageDump(X,Y,Z) SQLITE_OK
|
||||
#endif
|
||||
|
||||
#endif /* _BTREE_H_ */
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -1,9 +1 @@
|
|||
|
||||
#ifndef _sqlite3_config_h
|
||||
#define _sqlite3_config_h
|
||||
|
||||
#include "prcpucfg.h"
|
||||
|
||||
#define SQLITE_PTR_SZ PR_BYTES_PER_WORD
|
||||
|
||||
#endif /* _sqlite3_config_h */
|
||||
#define SQLITE_PTR_SZ 4
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
** sqlite3RegisterDateTimeFunctions() found at the bottom of the file.
|
||||
** All other code has file scope.
|
||||
**
|
||||
** $Id: date.c,v 1.37 2004/10/06 15:41:16 drh Exp $
|
||||
** $Id: date.c,v 1.44 2005/03/21 00:43:44 drh Exp $
|
||||
**
|
||||
** NOTES:
|
||||
**
|
||||
|
@ -272,7 +272,7 @@ static int parseYyyyMmDd(const char *zDate, DateTime *p){
|
|||
return 1;
|
||||
}
|
||||
zDate += 10;
|
||||
while( isspace(*(u8*)zDate) ){ zDate++; }
|
||||
while( isspace(*(u8*)zDate) || 'T'==*(u8*)zDate ){ zDate++; }
|
||||
if( parseHhMmSs(zDate, p)==0 ){
|
||||
/* We got the time */
|
||||
}else if( *zDate==0 ){
|
||||
|
@ -315,12 +315,10 @@ static int parseDateOrTime(const char *zDate, DateTime *p){
|
|||
return 0;
|
||||
}else if( sqlite3StrICmp(zDate,"now")==0){
|
||||
double r;
|
||||
if( sqlite3OsCurrentTime(&r)==0 ){
|
||||
p->rJD = r;
|
||||
p->validJD = 1;
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
sqlite3OsCurrentTime(&r);
|
||||
p->rJD = r;
|
||||
p->validJD = 1;
|
||||
return 0;
|
||||
}else if( sqlite3IsNumber(zDate, 0, SQLITE_UTF8) ){
|
||||
p->rJD = sqlite3AtoF(zDate, 0);
|
||||
p->validJD = 1;
|
||||
|
@ -862,9 +860,100 @@ static void strftimeFunc(
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** current_time()
|
||||
**
|
||||
** This function returns the same value as time('now').
|
||||
*/
|
||||
static void ctimeFunc(
|
||||
sqlite3_context *context,
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
sqlite3_value *pVal = sqlite3ValueNew();
|
||||
if( pVal ){
|
||||
sqlite3ValueSetStr(pVal, -1, "now", SQLITE_UTF8, SQLITE_STATIC);
|
||||
timeFunc(context, 1, &pVal);
|
||||
sqlite3ValueFree(pVal);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** current_date()
|
||||
**
|
||||
** This function returns the same value as date('now').
|
||||
*/
|
||||
static void cdateFunc(
|
||||
sqlite3_context *context,
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
sqlite3_value *pVal = sqlite3ValueNew();
|
||||
if( pVal ){
|
||||
sqlite3ValueSetStr(pVal, -1, "now", SQLITE_UTF8, SQLITE_STATIC);
|
||||
dateFunc(context, 1, &pVal);
|
||||
sqlite3ValueFree(pVal);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** current_timestamp()
|
||||
**
|
||||
** This function returns the same value as datetime('now').
|
||||
*/
|
||||
static void ctimestampFunc(
|
||||
sqlite3_context *context,
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
sqlite3_value *pVal = sqlite3ValueNew();
|
||||
if( pVal ){
|
||||
sqlite3ValueSetStr(pVal, -1, "now", SQLITE_UTF8, SQLITE_STATIC);
|
||||
datetimeFunc(context, 1, &pVal);
|
||||
sqlite3ValueFree(pVal);
|
||||
}
|
||||
}
|
||||
#endif /* !defined(SQLITE_OMIT_DATETIME_FUNCS) */
|
||||
|
||||
#ifdef SQLITE_OMIT_DATETIME_FUNCS
|
||||
/*
|
||||
** If the library is compiled to omit the full-scale date and time
|
||||
** handling (to get a smaller binary), the following minimal version
|
||||
** of the functions current_time(), current_date() and current_timestamp()
|
||||
** are included instead. This is to support column declarations that
|
||||
** include "DEFAULT CURRENT_TIME" etc.
|
||||
**
|
||||
** This function uses the C-library functions time(), gmtime()
|
||||
** and strftime(). The format string to pass to strftime() is supplied
|
||||
** as the user-data for the function.
|
||||
*/
|
||||
static void currentTimeFunc(
|
||||
sqlite3_context *context,
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
time_t t;
|
||||
char *zFormat = (char *)sqlite3_user_data(context);
|
||||
char zBuf[20];
|
||||
|
||||
time(&t);
|
||||
#ifdef SQLITE_TEST
|
||||
{
|
||||
extern int sqlite3_current_time; /* See os_XXX.c */
|
||||
if( sqlite3_current_time ){
|
||||
t = sqlite3_current_time;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
sqlite3OsEnterMutex();
|
||||
strftime(zBuf, 20, zFormat, gmtime(&t));
|
||||
sqlite3OsLeaveMutex();
|
||||
|
||||
sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
** This function registered all of the above C functions as SQL
|
||||
** functions. This should be the only routine in this file with
|
||||
|
@ -882,6 +971,9 @@ void sqlite3RegisterDateTimeFunctions(sqlite3 *db){
|
|||
{ "time", -1, timeFunc },
|
||||
{ "datetime", -1, datetimeFunc },
|
||||
{ "strftime", -1, strftimeFunc },
|
||||
{ "current_time", 0, ctimeFunc },
|
||||
{ "current_timestamp", 0, ctimestampFunc },
|
||||
{ "current_date", 0, cdateFunc },
|
||||
};
|
||||
int i;
|
||||
|
||||
|
@ -889,5 +981,20 @@ void sqlite3RegisterDateTimeFunctions(sqlite3 *db){
|
|||
sqlite3_create_function(db, aFuncs[i].zName, aFuncs[i].nArg,
|
||||
SQLITE_UTF8, 0, aFuncs[i].xFunc, 0, 0);
|
||||
}
|
||||
#else
|
||||
static const struct {
|
||||
char *zName;
|
||||
char *zFormat;
|
||||
} aFuncs[] = {
|
||||
{ "current_time", "%H:%M:%S" },
|
||||
{ "current_date", "%Y-%m-%d" },
|
||||
{ "current_timestamp", "%Y-%m-%d %H:%M:%S" }
|
||||
};
|
||||
int i;
|
||||
|
||||
for(i=0; i<sizeof(aFuncs)/sizeof(aFuncs[0]); i++){
|
||||
sqlite3_create_function(db, aFuncs[i].zName, 0, SQLITE_UTF8,
|
||||
aFuncs[i].zFormat, currentTimeFunc, 0, 0);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -10,9 +10,9 @@
|
|||
**
|
||||
*************************************************************************
|
||||
** This file contains C code routines that are called by the parser
|
||||
** to handle DELETE FROM statements.
|
||||
** in order to generate code for DELETE FROM statements.
|
||||
**
|
||||
** $Id: delete.c,v 1.82 2004/10/05 02:41:42 drh Exp $
|
||||
** $Id: delete.c,v 1.102 2005/03/16 12:15:21 danielk1977 Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
|
||||
|
@ -38,14 +38,17 @@ Table *sqlite3SrcListLookup(Parse *pParse, SrcList *pSrc){
|
|||
** writable return 0;
|
||||
*/
|
||||
int sqlite3IsReadOnly(Parse *pParse, Table *pTab, int viewOk){
|
||||
if( pTab->readOnly ){
|
||||
if( pTab->readOnly && (pParse->db->flags & SQLITE_WriteSchema)==0
|
||||
&& pParse->nested==0 ){
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -65,7 +68,11 @@ void sqlite3OpenTableForReading(
|
|||
|
||||
|
||||
/*
|
||||
** Process a DELETE FROM statement.
|
||||
** 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 */
|
||||
|
@ -81,17 +88,17 @@ void sqlite3DeleteFrom(
|
|||
Index *pIdx; /* For looping over indices of the table */
|
||||
int iCur; /* VDBE Cursor number for pTab */
|
||||
sqlite3 *db; /* Main database structure */
|
||||
int isView; /* True if attempting to delete from a view */
|
||||
AuthContext sContext; /* Authorization context */
|
||||
int oldIdx = -1; /* Cursor for the OLD table of AFTER triggers */
|
||||
NameContext sNC; /* Name context to resolve expressions in */
|
||||
|
||||
int row_triggers_exist = 0; /* True if any triggers exist */
|
||||
int before_triggers; /* True if there are BEFORE triggers */
|
||||
int after_triggers; /* True if there are AFTER triggers */
|
||||
int oldIdx = -1; /* Cursor for the OLD table of AFTER triggers */
|
||||
#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;
|
||||
if( pParse->nErr || sqlite3_malloc_failed ){
|
||||
pTabList = 0;
|
||||
goto delete_from_cleanup;
|
||||
}
|
||||
db = pParse->db;
|
||||
|
@ -104,13 +111,23 @@ void sqlite3DeleteFrom(
|
|||
*/
|
||||
pTab = sqlite3SrcListLookup(pParse, pTabList);
|
||||
if( pTab==0 ) goto delete_from_cleanup;
|
||||
before_triggers = sqlite3TriggersExist(pParse, pTab->pTrigger,
|
||||
TK_DELETE, TK_BEFORE, TK_ROW, 0);
|
||||
after_triggers = sqlite3TriggersExist(pParse, pTab->pTrigger,
|
||||
TK_DELETE, TK_AFTER, TK_ROW, 0);
|
||||
row_triggers_exist = before_triggers || after_triggers;
|
||||
|
||||
/* 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;
|
||||
if( sqlite3IsReadOnly(pParse, pTab, before_triggers) ){
|
||||
#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;
|
||||
}
|
||||
assert( pTab->iDb<db->nDb );
|
||||
|
@ -127,15 +144,18 @@ void sqlite3DeleteFrom(
|
|||
|
||||
/* Allocate a cursor used to store the old.* data for a trigger.
|
||||
*/
|
||||
if( row_triggers_exist ){
|
||||
if( triggers_exist ){
|
||||
oldIdx = pParse->nTab++;
|
||||
}
|
||||
|
||||
/* Resolve the column names in all the expressions.
|
||||
/* Resolve the column names in the WHERE clause.
|
||||
*/
|
||||
assert( pTabList->nSrc==1 );
|
||||
iCur = pTabList->a[0].iCursor = pParse->nTab++;
|
||||
if( sqlite3ExprResolveAndCheck(pParse, pTabList, 0, pWhere, 0, 0) ){
|
||||
memset(&sNC, 0, sizeof(sNC));
|
||||
sNC.pParse = pParse;
|
||||
sNC.pSrcList = pTabList;
|
||||
if( sqlite3ExprResolveNames(&sNC, pWhere) ){
|
||||
goto delete_from_cleanup;
|
||||
}
|
||||
|
||||
|
@ -151,8 +171,8 @@ void sqlite3DeleteFrom(
|
|||
if( v==0 ){
|
||||
goto delete_from_cleanup;
|
||||
}
|
||||
sqlite3VdbeCountChanges(v);
|
||||
sqlite3BeginWriteOperation(pParse, row_triggers_exist, pTab->iDb);
|
||||
if( pParse->nested==0 ) sqlite3VdbeCountChanges(v);
|
||||
sqlite3BeginWriteOperation(pParse, triggers_exist, pTab->iDb);
|
||||
|
||||
/* If we are trying to delete from a view, construct that view into
|
||||
** a temporary table.
|
||||
|
@ -174,7 +194,7 @@ void sqlite3DeleteFrom(
|
|||
** 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 && !row_triggers_exist ){
|
||||
if( pWhere==0 && !triggers_exist ){
|
||||
if( db->flags & SQLITE_CountRows ){
|
||||
/* If counting rows deleted, just count the total number of
|
||||
** entries in the table. */
|
||||
|
@ -210,11 +230,12 @@ void sqlite3DeleteFrom(
|
|||
|
||||
/* Begin the database scan
|
||||
*/
|
||||
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 1, 0);
|
||||
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 0, 0);
|
||||
if( pWInfo==0 ) goto delete_from_cleanup;
|
||||
|
||||
/* Remember the key of every item to be deleted.
|
||||
/* Remember the rowid of every item to be deleted.
|
||||
*/
|
||||
sqlite3VdbeAddOp(v, OP_Recno, iCur, 0);
|
||||
sqlite3VdbeAddOp(v, OP_ListWrite, 0, 0);
|
||||
if( db->flags & SQLITE_CountRows ){
|
||||
sqlite3VdbeAddOp(v, OP_AddImm, 1, 0);
|
||||
|
@ -226,7 +247,7 @@ void sqlite3DeleteFrom(
|
|||
|
||||
/* Open the pseudo-table used to store OLD if there are triggers.
|
||||
*/
|
||||
if( row_triggers_exist ){
|
||||
if( triggers_exist ){
|
||||
sqlite3VdbeAddOp(v, OP_OpenPseudo, oldIdx, 0);
|
||||
sqlite3VdbeAddOp(v, OP_SetNumColumns, oldIdx, pTab->nCol);
|
||||
}
|
||||
|
@ -241,7 +262,7 @@ void sqlite3DeleteFrom(
|
|||
/* This is the beginning of the delete loop when there are
|
||||
** row triggers.
|
||||
*/
|
||||
if( row_triggers_exist ){
|
||||
if( triggers_exist ){
|
||||
addr = sqlite3VdbeAddOp(v, OP_ListRead, 0, end);
|
||||
sqlite3VdbeAddOp(v, OP_Dup, 0, 0);
|
||||
if( !isView ){
|
||||
|
@ -255,8 +276,8 @@ void sqlite3DeleteFrom(
|
|||
sqlite3VdbeAddOp(v, OP_Close, iCur, 0);
|
||||
}
|
||||
|
||||
sqlite3CodeRowTrigger(pParse, TK_DELETE, 0, TK_BEFORE, pTab, -1,
|
||||
oldIdx, (pParse->trigStack)?pParse->trigStack->orconf:OE_Default,
|
||||
(void)sqlite3CodeRowTrigger(pParse, TK_DELETE, 0, TRIGGER_BEFORE, pTab,
|
||||
-1, oldIdx, (pParse->trigStack)?pParse->trigStack->orconf:OE_Default,
|
||||
addr);
|
||||
}
|
||||
|
||||
|
@ -271,25 +292,25 @@ void sqlite3DeleteFrom(
|
|||
|
||||
/* This is the beginning of the delete loop when there are no
|
||||
** row triggers */
|
||||
if( !row_triggers_exist ){
|
||||
if( !triggers_exist ){
|
||||
addr = sqlite3VdbeAddOp(v, OP_ListRead, 0, end);
|
||||
}
|
||||
|
||||
/* Delete the row */
|
||||
sqlite3GenerateRowDelete(db, v, pTab, iCur, 1);
|
||||
sqlite3GenerateRowDelete(db, v, pTab, iCur, pParse->nested==0);
|
||||
}
|
||||
|
||||
/* If there are row triggers, close all cursors then invoke
|
||||
** the AFTER triggers
|
||||
*/
|
||||
if( row_triggers_exist ){
|
||||
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);
|
||||
}
|
||||
sqlite3CodeRowTrigger(pParse, TK_DELETE, 0, TK_AFTER, pTab, -1,
|
||||
(void)sqlite3CodeRowTrigger(pParse, TK_DELETE, 0, TRIGGER_AFTER, pTab, -1,
|
||||
oldIdx, (pParse->trigStack)?pParse->trigStack->orconf:OE_Default,
|
||||
addr);
|
||||
}
|
||||
|
@ -300,7 +321,7 @@ void sqlite3DeleteFrom(
|
|||
sqlite3VdbeAddOp(v, OP_ListReset, 0, 0);
|
||||
|
||||
/* Close the cursors after the loop if there are no row triggers */
|
||||
if( !row_triggers_exist ){
|
||||
if( !triggers_exist ){
|
||||
for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
|
||||
sqlite3VdbeAddOp(v, OP_Close, iCur + i, pIdx->tnum);
|
||||
}
|
||||
|
@ -309,9 +330,11 @@ void sqlite3DeleteFrom(
|
|||
}
|
||||
|
||||
/*
|
||||
** Return the number of rows that were deleted.
|
||||
** 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 ){
|
||||
if( db->flags & SQLITE_CountRows && pParse->nested==0 && !pParse->trigStack ){
|
||||
sqlite3VdbeAddOp(v, OP_Callback, 1, 0);
|
||||
sqlite3VdbeSetNumCols(v, 1);
|
||||
sqlite3VdbeSetColName(v, 0, "rows deleted", P3_STATIC);
|
||||
|
@ -412,6 +435,7 @@ void sqlite3GenerateIndexKey(
|
|||
sqlite3VdbeAddOp(v, OP_Dup, j, 0);
|
||||
}else{
|
||||
sqlite3VdbeAddOp(v, OP_Column, iCur, idx);
|
||||
sqlite3ColumnDefault(v, pTab, idx);
|
||||
}
|
||||
}
|
||||
sqlite3VdbeAddOp(v, OP_MakeRecord, pIdx->nColumn, (1<<24));
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -16,13 +16,13 @@
|
|||
** sqliteRegisterBuildinFunctions() found at the bottom of the file.
|
||||
** All other code has file scope.
|
||||
**
|
||||
** $Id: func.c,v 1.85 2004/10/06 15:41:17 drh Exp $
|
||||
** $Id: func.c,v 1.96 2005/02/15 21:36:18 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include <ctype.h>
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include "sqliteInt.h"
|
||||
#include "vdbeInt.h"
|
||||
#include "os.h"
|
||||
|
||||
|
@ -347,10 +347,11 @@ static const struct compareInfo likeInfo = { '%', '_', 0, 1 };
|
|||
**
|
||||
** abc[*]xyz Matches "abc*xyz" only
|
||||
*/
|
||||
int patternCompare(
|
||||
static int patternCompare(
|
||||
const u8 *zPattern, /* The glob pattern */
|
||||
const u8 *zString, /* The string to compare against the glob */
|
||||
const struct compareInfo *pInfo /* Information about how to do the compare */
|
||||
const struct compareInfo *pInfo, /* Information about how to do the compare */
|
||||
const int esc /* The escape character */
|
||||
){
|
||||
register int c;
|
||||
int invert;
|
||||
|
@ -360,9 +361,10 @@ int patternCompare(
|
|||
u8 matchAll = pInfo->matchAll;
|
||||
u8 matchSet = pInfo->matchSet;
|
||||
u8 noCase = pInfo->noCase;
|
||||
int prevEscape = 0; /* True if the previous character was 'escape' */
|
||||
|
||||
while( (c = *zPattern)!=0 ){
|
||||
if( c==matchAll ){
|
||||
if( !prevEscape && c==matchAll ){
|
||||
while( (c=zPattern[1]) == matchAll || c == matchOne ){
|
||||
if( c==matchOne ){
|
||||
if( *zString==0 ) return 0;
|
||||
|
@ -370,9 +372,15 @@ int patternCompare(
|
|||
}
|
||||
zPattern++;
|
||||
}
|
||||
if( c && esc && sqlite3ReadUtf8(&zPattern[1])==esc ){
|
||||
u8 const *zTemp = &zPattern[1];
|
||||
sqliteNextChar(zTemp);
|
||||
c = *zTemp;
|
||||
}
|
||||
if( c==0 ) return 1;
|
||||
if( c==matchSet ){
|
||||
while( *zString && patternCompare(&zPattern[1],zString,pInfo)==0 ){
|
||||
assert( esc==0 ); /* This is GLOB, not LIKE */
|
||||
while( *zString && patternCompare(&zPattern[1],zString,pInfo,esc)==0 ){
|
||||
sqliteNextChar(zString);
|
||||
}
|
||||
return *zString!=0;
|
||||
|
@ -386,17 +394,18 @@ int patternCompare(
|
|||
while( c2 != 0 && c2 != c ){ c2 = *++zString; }
|
||||
}
|
||||
if( c2==0 ) return 0;
|
||||
if( patternCompare(&zPattern[1],zString,pInfo) ) return 1;
|
||||
if( patternCompare(&zPattern[1],zString,pInfo,esc) ) return 1;
|
||||
sqliteNextChar(zString);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}else if( c==matchOne ){
|
||||
}else if( !prevEscape && c==matchOne ){
|
||||
if( *zString==0 ) return 0;
|
||||
sqliteNextChar(zString);
|
||||
zPattern++;
|
||||
}else if( c==matchSet ){
|
||||
int prior_c = 0;
|
||||
assert( esc==0 ); /* This only occurs for GLOB, not LIKE */
|
||||
seen = 0;
|
||||
invert = 0;
|
||||
c = sqliteCharVal(zString);
|
||||
|
@ -424,6 +433,9 @@ int patternCompare(
|
|||
if( c2==0 || (seen ^ invert)==0 ) return 0;
|
||||
sqliteNextChar(zString);
|
||||
zPattern++;
|
||||
}else if( esc && !prevEscape && sqlite3ReadUtf8(zPattern)==esc){
|
||||
prevEscape = 1;
|
||||
sqliteNextChar(zPattern);
|
||||
}else{
|
||||
if( noCase ){
|
||||
if( sqlite3UpperToLower[c] != sqlite3UpperToLower[*zString] ) return 0;
|
||||
|
@ -432,6 +444,7 @@ int patternCompare(
|
|||
}
|
||||
zPattern++;
|
||||
zString++;
|
||||
prevEscape = 0;
|
||||
}
|
||||
}
|
||||
return *zString==0;
|
||||
|
@ -457,8 +470,21 @@ static void likeFunc(
|
|||
){
|
||||
const unsigned char *zA = sqlite3_value_text(argv[0]);
|
||||
const unsigned char *zB = sqlite3_value_text(argv[1]);
|
||||
int escape = 0;
|
||||
if( argc==3 ){
|
||||
/* The escape character string must consist of a single UTF-8 character.
|
||||
** Otherwise, return an error.
|
||||
*/
|
||||
const unsigned char *zEsc = sqlite3_value_text(argv[2]);
|
||||
if( sqlite3utf8CharLen(zEsc, -1)!=1 ){
|
||||
sqlite3_result_error(context,
|
||||
"ESCAPE expression must be a single character", -1);
|
||||
return;
|
||||
}
|
||||
escape = sqlite3ReadUtf8(zEsc);
|
||||
}
|
||||
if( zA && zB ){
|
||||
sqlite3_result_int(context, patternCompare(zA, zB, &likeInfo));
|
||||
sqlite3_result_int(context, patternCompare(zA, zB, &likeInfo, escape));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -469,13 +495,13 @@ static void likeFunc(
|
|||
**
|
||||
** A GLOB B
|
||||
**
|
||||
** is implemented as glob(A,B).
|
||||
** is implemented as glob(B,A).
|
||||
*/
|
||||
static void globFunc(sqlite3_context *context, int arg, sqlite3_value **argv){
|
||||
const unsigned char *zA = sqlite3_value_text(argv[0]);
|
||||
const unsigned char *zB = sqlite3_value_text(argv[1]);
|
||||
if( zA && zB ){
|
||||
sqlite3_result_int(context, patternCompare(zA, zB, &globInfo));
|
||||
sqlite3_result_int(context, patternCompare(zA, zB, &globInfo, 0));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -507,6 +533,7 @@ static void versionFunc(
|
|||
sqlite3_result_text(context, sqlite3_version, -1, SQLITE_STATIC);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** EXPERIMENTAL - This is not an official function. The interface may
|
||||
** change. This function may disappear. Do not write code that depends
|
||||
|
@ -704,10 +731,12 @@ static void test_destructor(
|
|||
memcpy(zVal, sqlite3ValueText(argv[0], db->enc), len);
|
||||
if( db->enc==SQLITE_UTF8 ){
|
||||
sqlite3_result_text(pCtx, zVal, -1, destructor);
|
||||
#ifndef SQLITE_OMIT_UTF16
|
||||
}else if( db->enc==SQLITE_UTF16LE ){
|
||||
sqlite3_result_text16le(pCtx, zVal, -1, destructor);
|
||||
}else{
|
||||
sqlite3_result_text16be(pCtx, zVal, -1, destructor);
|
||||
#endif /* SQLITE_OMIT_UTF16 */
|
||||
}
|
||||
}
|
||||
static void test_destructor_count(
|
||||
|
@ -762,6 +791,20 @@ static void test_auxdata(
|
|||
}
|
||||
#endif /* SQLITE_TEST */
|
||||
|
||||
#ifdef SQLITE_TEST
|
||||
/*
|
||||
** A function to test error reporting from user functions. This function
|
||||
** returns a copy of it's first argument as an error.
|
||||
*/
|
||||
static void test_error(
|
||||
sqlite3_context *pCtx,
|
||||
int nArg,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
sqlite3_result_error(pCtx, sqlite3_value_text(argv[0]), 0);
|
||||
}
|
||||
#endif /* SQLITE_TEST */
|
||||
|
||||
/*
|
||||
** An instance of the following structure holds the context of a
|
||||
** sum() or avg() aggregate computation.
|
||||
|
@ -808,33 +851,6 @@ struct StdDevCtx {
|
|||
int cnt; /* Number of terms counted */
|
||||
};
|
||||
|
||||
#if 0 /* Omit because math library is required */
|
||||
/*
|
||||
** Routines used to compute the standard deviation as an aggregate.
|
||||
*/
|
||||
static void stdDevStep(sqlite3_context *context, int argc, const char **argv){
|
||||
StdDevCtx *p;
|
||||
double x;
|
||||
if( argc<1 ) return;
|
||||
p = sqlite3_aggregate_context(context, sizeof(*p));
|
||||
if( p && argv[0] ){
|
||||
x = sqlite3AtoF(argv[0], 0);
|
||||
p->sum += x;
|
||||
p->sum2 += x*x;
|
||||
p->cnt++;
|
||||
}
|
||||
}
|
||||
static void stdDevFinalize(sqlite3_context *context){
|
||||
double rN = sqlite3_aggregate_count(context);
|
||||
StdDevCtx *p = sqlite3_aggregate_context(context, sizeof(*p));
|
||||
if( p && p->cnt>1 ){
|
||||
double rCnt = cnt;
|
||||
sqlite3_set_result_double(context,
|
||||
sqrt((p->sum2 - p->sum*p->sum/rCnt)/(rCnt-1.0)));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
** The following structure keeps track of state information for the
|
||||
** count() aggregate function.
|
||||
|
@ -933,7 +949,9 @@ void sqlite3RegisterBuiltinFunctions(sqlite3 *db){
|
|||
{ "typeof", 1, 0, SQLITE_UTF8, 0, typeofFunc },
|
||||
{ "length", 1, 0, SQLITE_UTF8, 0, lengthFunc },
|
||||
{ "substr", 3, 0, SQLITE_UTF8, 0, substrFunc },
|
||||
#ifndef SQLITE_OMIT_UTF16
|
||||
{ "substr", 3, 0, SQLITE_UTF16LE, 0, sqlite3utf16Substr },
|
||||
#endif
|
||||
{ "abs", 1, 0, SQLITE_UTF8, 0, absFunc },
|
||||
{ "round", 1, 0, SQLITE_UTF8, 0, roundFunc },
|
||||
{ "round", 2, 0, SQLITE_UTF8, 0, roundFunc },
|
||||
|
@ -945,6 +963,7 @@ void sqlite3RegisterBuiltinFunctions(sqlite3 *db){
|
|||
{ "ifnull", 2, 0, SQLITE_UTF8, 1, ifnullFunc },
|
||||
{ "random", -1, 0, SQLITE_UTF8, 0, randomFunc },
|
||||
{ "like", 2, 0, SQLITE_UTF8, 0, likeFunc },
|
||||
{ "like", 3, 0, SQLITE_UTF8, 0, likeFunc },
|
||||
{ "glob", 2, 0, SQLITE_UTF8, 0, globFunc },
|
||||
{ "nullif", 2, 0, SQLITE_UTF8, 1, nullifFunc },
|
||||
{ "sqlite_version", 0, 0, SQLITE_UTF8, 0, versionFunc},
|
||||
|
@ -960,6 +979,7 @@ void sqlite3RegisterBuiltinFunctions(sqlite3 *db){
|
|||
{ "test_destructor", 1, 1, SQLITE_UTF8, 0, test_destructor},
|
||||
{ "test_destructor_count", 0, 0, SQLITE_UTF8, 0, test_destructor_count},
|
||||
{ "test_auxdata", -1, 0, SQLITE_UTF8, 0, test_auxdata},
|
||||
{ "test_error", 1, 0, SQLITE_UTF8, 0, test_error},
|
||||
#endif
|
||||
};
|
||||
static const struct {
|
||||
|
@ -976,9 +996,6 @@ void sqlite3RegisterBuiltinFunctions(sqlite3 *db){
|
|||
{ "avg", 1, 0, 0, sumStep, avgFinalize },
|
||||
{ "count", 0, 0, 0, countStep, countFinalize },
|
||||
{ "count", 1, 0, 0, countStep, countFinalize },
|
||||
#if 0
|
||||
{ "stddev", 1, 0, stdDevStep, stdDevFinalize },
|
||||
#endif
|
||||
};
|
||||
int i;
|
||||
|
||||
|
@ -998,6 +1015,9 @@ void sqlite3RegisterBuiltinFunctions(sqlite3 *db){
|
|||
}
|
||||
}
|
||||
}
|
||||
#ifndef SQLITE_OMIT_ALTERTABLE
|
||||
sqlite3AlterFunctions(db);
|
||||
#endif
|
||||
for(i=0; i<sizeof(aAggs)/sizeof(aAggs[0]); i++){
|
||||
void *pArg = 0;
|
||||
switch( aAggs[i].argType ){
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
** This is the implementation of generic hash-tables
|
||||
** used in SQLite.
|
||||
**
|
||||
** $Id: hash.c,v 1.15 2004/08/20 14:08:51 drh Exp $
|
||||
** $Id: hash.c,v 1.16 2005/01/31 12:56:44 danielk1977 Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include <assert.h>
|
||||
|
@ -98,7 +98,14 @@ static int ptrCompare(const void *pKey1, int n1, const void *pKey2, int n2){
|
|||
** Hash and comparison functions when the mode is SQLITE_HASH_STRING
|
||||
*/
|
||||
static int strHash(const void *pKey, int nKey){
|
||||
return sqlite3HashNoCase((const char*)pKey, 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;
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
** This file contains C code routines that are called by the parser
|
||||
** to handle INSERT statements in SQLite.
|
||||
**
|
||||
** $Id: insert.c,v 1.119 2004/10/05 02:41:42 drh Exp $
|
||||
** $Id: insert.c,v 1.138 2005/03/21 01:20:58 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
|
||||
|
@ -94,6 +94,27 @@ void sqlite3TableAffinityStr(Vdbe *v, Table *pTab){
|
|||
sqlite3VdbeChangeP3(v, -1, pTab->zColAff, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
** Return non-zero if SELECT statement p opens the table with rootpage
|
||||
** iTab in database iDb. This is used to see if a statement of the form
|
||||
** "INSERT INTO <iDb, iTab> SELECT ..." can run without using temporary
|
||||
** table for the results of the SELECT.
|
||||
**
|
||||
** No checking is done for sub-selects that are part of expressions.
|
||||
*/
|
||||
static int selectReadsTable(Select *p, int iDb, int iTab){
|
||||
int i;
|
||||
struct SrcList_item *pItem;
|
||||
if( p->pSrc==0 ) return 0;
|
||||
for(i=0, pItem=p->pSrc->a; i<p->pSrc->nSrc; i++, pItem++){
|
||||
if( pItem->pSelect ){
|
||||
if( selectReadsTable(pItem->pSelect, iDb, iTab) ) return 1;
|
||||
}else{
|
||||
if( pItem->pTab->iDb==iDb && pItem->pTab->tnum==iTab ) return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** This routine is call to handle SQL of the following forms:
|
||||
|
@ -182,18 +203,24 @@ void sqlite3Insert(
|
|||
sqlite3 *db; /* The main database structure */
|
||||
int keyColumn = -1; /* Column that is the INTEGER PRIMARY KEY */
|
||||
int endOfLoop; /* Label for the end of the insertion loop */
|
||||
int useTempTable; /* Store SELECT results in intermediate table */
|
||||
int useTempTable = 0; /* Store SELECT results in intermediate table */
|
||||
int srcTab = 0; /* Data comes from this temporary cursor if >=0 */
|
||||
int iSelectLoop = 0; /* Address of code that implements the SELECT */
|
||||
int iCleanup = 0; /* Address of the cleanup code */
|
||||
int iInsertBlock = 0; /* Address of the subroutine used to insert data */
|
||||
int iCntMem = 0; /* Memory cell used for the row counter */
|
||||
int isView; /* True if attempting to insert into a view */
|
||||
int newIdx = -1; /* Cursor for the NEW table */
|
||||
Db *pDb; /* The database containing table being inserted into */
|
||||
int counterMem = 0; /* Memory cell holding AUTOINCREMENT counter */
|
||||
|
||||
int row_triggers_exist = 0; /* True if there are FOR EACH ROW triggers */
|
||||
int before_triggers; /* True if there are BEFORE triggers */
|
||||
int after_triggers; /* True if there are AFTER triggers */
|
||||
int newIdx = -1; /* Cursor for the NEW table */
|
||||
#ifndef SQLITE_OMIT_TRIGGER
|
||||
int isView; /* True if attempting to insert into a view */
|
||||
int triggers_exist = 0; /* True if there are FOR EACH ROW triggers */
|
||||
#endif
|
||||
|
||||
#ifndef SQLITE_OMIT_AUTOINCREMENT
|
||||
int counterRowid; /* Memory cell holding rowid of autoinc counter */
|
||||
#endif
|
||||
|
||||
if( pParse->nErr || sqlite3_malloc_failed ) goto insert_cleanup;
|
||||
db = pParse->db;
|
||||
|
@ -208,22 +235,32 @@ void sqlite3Insert(
|
|||
goto insert_cleanup;
|
||||
}
|
||||
assert( pTab->iDb<db->nDb );
|
||||
zDb = db->aDb[pTab->iDb].zName;
|
||||
pDb = &db->aDb[pTab->iDb];
|
||||
zDb = pDb->zName;
|
||||
if( sqlite3AuthCheck(pParse, SQLITE_INSERT, pTab->zName, 0, zDb) ){
|
||||
goto insert_cleanup;
|
||||
}
|
||||
|
||||
/* Figure out if we have any triggers and if the table being
|
||||
** inserted into is a view
|
||||
*/
|
||||
#ifndef SQLITE_OMIT_TRIGGER
|
||||
triggers_exist = sqlite3TriggersExist(pParse, pTab, TK_INSERT, 0);
|
||||
isView = pTab->pSelect!=0;
|
||||
#else
|
||||
# define triggers_exist 0
|
||||
# define isView 0
|
||||
#endif
|
||||
#ifdef SQLITE_OMIT_VIEW
|
||||
# undef isView
|
||||
# define isView 0
|
||||
#endif
|
||||
|
||||
/* Ensure that:
|
||||
* (a) the table is not read-only,
|
||||
* (b) that if it is a view then ON INSERT triggers exist
|
||||
*/
|
||||
before_triggers = sqlite3TriggersExist(pParse, pTab->pTrigger, TK_INSERT,
|
||||
TK_BEFORE, TK_ROW, 0);
|
||||
after_triggers = sqlite3TriggersExist(pParse, pTab->pTrigger, TK_INSERT,
|
||||
TK_AFTER, TK_ROW, 0);
|
||||
row_triggers_exist = before_triggers || after_triggers;
|
||||
isView = pTab->pSelect!=0;
|
||||
if( sqlite3IsReadOnly(pParse, pTab, before_triggers) ){
|
||||
if( sqlite3IsReadOnly(pParse, pTab, triggers_exist) ){
|
||||
goto insert_cleanup;
|
||||
}
|
||||
if( pTab==0 ) goto insert_cleanup;
|
||||
|
@ -245,14 +282,42 @@ void sqlite3Insert(
|
|||
*/
|
||||
v = sqlite3GetVdbe(pParse);
|
||||
if( v==0 ) goto insert_cleanup;
|
||||
sqlite3VdbeCountChanges(v);
|
||||
sqlite3BeginWriteOperation(pParse, pSelect || row_triggers_exist, pTab->iDb);
|
||||
if( pParse->nested==0 ) sqlite3VdbeCountChanges(v);
|
||||
sqlite3BeginWriteOperation(pParse, pSelect || triggers_exist, pTab->iDb);
|
||||
|
||||
/* if there are row triggers, allocate a temp table for new.* references. */
|
||||
if( row_triggers_exist ){
|
||||
if( triggers_exist ){
|
||||
newIdx = pParse->nTab++;
|
||||
}
|
||||
|
||||
#ifndef SQLITE_OMIT_AUTOINCREMENT
|
||||
/* If this is an AUTOINCREMENT table, look up the sequence number in the
|
||||
** sqlite_sequence table and store it in memory cell counterMem. Also
|
||||
** remember the rowid of the sqlite_sequence table entry in memory cell
|
||||
** counterRowid.
|
||||
*/
|
||||
if( pTab->autoInc ){
|
||||
int iCur = pParse->nTab;
|
||||
int base = sqlite3VdbeCurrentAddr(v);
|
||||
counterRowid = pParse->nMem++;
|
||||
counterMem = pParse->nMem++;
|
||||
sqlite3VdbeAddOp(v, OP_Integer, pTab->iDb, 0);
|
||||
sqlite3VdbeAddOp(v, OP_OpenRead, iCur, pDb->pSeqTab->tnum);
|
||||
sqlite3VdbeAddOp(v, OP_SetNumColumns, iCur, 2);
|
||||
sqlite3VdbeAddOp(v, OP_Rewind, iCur, base+13);
|
||||
sqlite3VdbeAddOp(v, OP_Column, iCur, 0);
|
||||
sqlite3VdbeOp3(v, OP_String8, 0, 0, pTab->zName, 0);
|
||||
sqlite3VdbeAddOp(v, OP_Ne, 28417, base+12);
|
||||
sqlite3VdbeAddOp(v, OP_Recno, iCur, 0);
|
||||
sqlite3VdbeAddOp(v, OP_MemStore, counterRowid, 1);
|
||||
sqlite3VdbeAddOp(v, OP_Column, iCur, 1);
|
||||
sqlite3VdbeAddOp(v, OP_MemStore, counterMem, 1);
|
||||
sqlite3VdbeAddOp(v, OP_Goto, 0, base+13);
|
||||
sqlite3VdbeAddOp(v, OP_Next, iCur, base+4);
|
||||
sqlite3VdbeAddOp(v, OP_Close, iCur, 0);
|
||||
}
|
||||
#endif /* SQLITE_OMIT_AUTOINCREMENT */
|
||||
|
||||
/* Figure out how many columns of data are supplied. If the data
|
||||
** is coming from a SELECT statement, then this step also generates
|
||||
** all the code to implement the SELECT statement and invoke a subroutine
|
||||
|
@ -268,8 +333,11 @@ void sqlite3Insert(
|
|||
iInitCode = sqlite3VdbeAddOp(v, OP_Goto, 0, 0);
|
||||
iSelectLoop = sqlite3VdbeCurrentAddr(v);
|
||||
iInsertBlock = sqlite3VdbeMakeLabel(v);
|
||||
rc = sqlite3Select(pParse, pSelect, SRT_Subroutine, iInsertBlock, 0,0,0,0);
|
||||
|
||||
/* Resolve the expressions in the SELECT statement and execute it. */
|
||||
rc = sqlite3Select(pParse, pSelect, SRT_Subroutine, iInsertBlock,0,0,0,0);
|
||||
if( rc || pParse->nErr || sqlite3_malloc_failed ) goto insert_cleanup;
|
||||
|
||||
iCleanup = sqlite3VdbeMakeLabel(v);
|
||||
sqlite3VdbeAddOp(v, OP_Goto, 0, iCleanup);
|
||||
assert( pSelect->pEList );
|
||||
|
@ -283,20 +351,8 @@ void sqlite3Insert(
|
|||
** of the tables being read by the SELECT statement. Also use a
|
||||
** temp table in the case of row triggers.
|
||||
*/
|
||||
if( row_triggers_exist ){
|
||||
if( triggers_exist || selectReadsTable(pSelect, pTab->iDb, pTab->tnum) ){
|
||||
useTempTable = 1;
|
||||
}else{
|
||||
int addr = 0;
|
||||
useTempTable = 0;
|
||||
while( useTempTable==0 ){
|
||||
VdbeOp *pOp;
|
||||
addr = sqlite3VdbeFindOp(v, addr, OP_OpenRead, pTab->tnum);
|
||||
if( addr==0 ) break;
|
||||
pOp = sqlite3VdbeGetOp(v, addr-2);
|
||||
if( pOp->opcode==OP_Integer && pOp->p1==pTab->iDb ){
|
||||
useTempTable = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( useTempTable ){
|
||||
|
@ -328,15 +384,16 @@ void sqlite3Insert(
|
|||
/* This is the case if the data for the INSERT is coming from a VALUES
|
||||
** clause
|
||||
*/
|
||||
SrcList dummy;
|
||||
NameContext sNC;
|
||||
memset(&sNC, 0, sizeof(sNC));
|
||||
sNC.pParse = pParse;
|
||||
assert( pList!=0 );
|
||||
srcTab = -1;
|
||||
useTempTable = 0;
|
||||
assert( pList );
|
||||
nColumn = pList->nExpr;
|
||||
dummy.nSrc = 0;
|
||||
for(i=0; i<nColumn; i++){
|
||||
if( sqlite3ExprResolveAndCheck(pParse,&dummy,0,pList->a[i].pExpr,0,0) ){
|
||||
if( sqlite3ExprResolveNames(&sNC, pList->a[i].pExpr) ){
|
||||
goto insert_cleanup;
|
||||
}
|
||||
}
|
||||
|
@ -404,7 +461,7 @@ void sqlite3Insert(
|
|||
|
||||
/* Open the temp table for FOR EACH ROW triggers
|
||||
*/
|
||||
if( row_triggers_exist ){
|
||||
if( triggers_exist ){
|
||||
sqlite3VdbeAddOp(v, OP_OpenPseudo, newIdx, 0);
|
||||
sqlite3VdbeAddOp(v, OP_SetNumColumns, newIdx, pTab->nCol);
|
||||
}
|
||||
|
@ -418,7 +475,7 @@ void sqlite3Insert(
|
|||
}
|
||||
|
||||
/* Open tables and indices if there are no row triggers */
|
||||
if( !row_triggers_exist ){
|
||||
if( !triggers_exist ){
|
||||
base = pParse->nTab;
|
||||
sqlite3OpenTableAndIndices(pParse, pTab, base, OP_OpenWrite);
|
||||
}
|
||||
|
@ -440,7 +497,7 @@ void sqlite3Insert(
|
|||
/* Run the BEFORE and INSTEAD OF triggers, if there are any
|
||||
*/
|
||||
endOfLoop = sqlite3VdbeMakeLabel(v);
|
||||
if( before_triggers ){
|
||||
if( triggers_exist & TRIGGER_BEFORE ){
|
||||
|
||||
/* build the NEW.* reference row. Note that if there is an INTEGER
|
||||
** PRIMARY KEY into which a NULL is being inserted, that NULL will be
|
||||
|
@ -452,9 +509,8 @@ void sqlite3Insert(
|
|||
sqlite3VdbeAddOp(v, OP_Integer, -1, 0);
|
||||
}else if( useTempTable ){
|
||||
sqlite3VdbeAddOp(v, OP_Column, srcTab, keyColumn);
|
||||
}else if( pSelect ){
|
||||
sqlite3VdbeAddOp(v, OP_Dup, nColumn - keyColumn - 1, 1);
|
||||
}else{
|
||||
assert( pSelect==0 ); /* Otherwise useTempTable is true */
|
||||
sqlite3ExprCode(pParse, pList->a[keyColumn].pExpr);
|
||||
sqlite3VdbeAddOp(v, OP_NotNull, -1, sqlite3VdbeCurrentAddr(v)+3);
|
||||
sqlite3VdbeAddOp(v, OP_Pop, 1, 0);
|
||||
|
@ -473,13 +529,12 @@ void sqlite3Insert(
|
|||
}
|
||||
}
|
||||
if( pColumn && j>=pColumn->nId ){
|
||||
sqlite3VdbeOp3(v, OP_String8, 0, 0, pTab->aCol[i].zDflt, P3_STATIC);
|
||||
sqlite3ExprCode(pParse, pTab->aCol[i].pDflt);
|
||||
}else if( useTempTable ){
|
||||
sqlite3VdbeAddOp(v, OP_Column, srcTab, j);
|
||||
}else if( pSelect ){
|
||||
sqlite3VdbeAddOp(v, OP_Dup, nColumn-j-1, 1);
|
||||
}else{
|
||||
sqlite3ExprCode(pParse, pList->a[j].pExpr);
|
||||
assert( pSelect==0 ); /* Otherwise useTempTable is true */
|
||||
sqlite3ExprCodeAndCache(pParse, pList->a[j].pExpr);
|
||||
}
|
||||
}
|
||||
sqlite3VdbeAddOp(v, OP_MakeRecord, pTab->nCol, 0);
|
||||
|
@ -495,7 +550,7 @@ void sqlite3Insert(
|
|||
sqlite3VdbeAddOp(v, OP_PutIntKey, newIdx, 0);
|
||||
|
||||
/* Fire BEFORE or INSTEAD OF triggers */
|
||||
if( sqlite3CodeRowTrigger(pParse, TK_INSERT, 0, TK_BEFORE, pTab,
|
||||
if( sqlite3CodeRowTrigger(pParse, TK_INSERT, 0, TRIGGER_BEFORE, pTab,
|
||||
newIdx, -1, onError, endOfLoop) ){
|
||||
goto insert_cleanup;
|
||||
}
|
||||
|
@ -504,7 +559,7 @@ void sqlite3Insert(
|
|||
/* If any triggers exists, the opening of tables and indices is deferred
|
||||
** until now.
|
||||
*/
|
||||
if( row_triggers_exist && !isView ){
|
||||
if( triggers_exist && !isView ){
|
||||
base = pParse->nTab;
|
||||
sqlite3OpenTableAndIndices(pParse, pTab, base, OP_OpenWrite);
|
||||
}
|
||||
|
@ -528,11 +583,16 @@ void sqlite3Insert(
|
|||
*/
|
||||
sqlite3VdbeAddOp(v, OP_NotNull, -1, sqlite3VdbeCurrentAddr(v)+3);
|
||||
sqlite3VdbeAddOp(v, OP_Pop, 1, 0);
|
||||
sqlite3VdbeAddOp(v, OP_NewRecno, base, 0);
|
||||
sqlite3VdbeAddOp(v, OP_NewRecno, base, counterMem);
|
||||
sqlite3VdbeAddOp(v, OP_MustBeInt, 0, 0);
|
||||
}else{
|
||||
sqlite3VdbeAddOp(v, OP_NewRecno, base, 0);
|
||||
sqlite3VdbeAddOp(v, OP_NewRecno, base, counterMem);
|
||||
}
|
||||
#ifndef SQLITE_OMIT_AUTOINCREMENT
|
||||
if( pTab->autoInc ){
|
||||
sqlite3VdbeAddOp(v, OP_MemMax, counterMem, 0);
|
||||
}
|
||||
#endif /* SQLITE_OMIT_AUTOINCREMENT */
|
||||
|
||||
/* Push onto the stack, data for all columns of the new entry, beginning
|
||||
** with the first column.
|
||||
|
@ -554,7 +614,7 @@ void sqlite3Insert(
|
|||
}
|
||||
}
|
||||
if( pColumn && j>=pColumn->nId ){
|
||||
sqlite3VdbeOp3(v, OP_String8, 0, 0, pTab->aCol[i].zDflt, P3_STATIC);
|
||||
sqlite3ExprCode(pParse, pTab->aCol[i].pDflt);
|
||||
}else if( useTempTable ){
|
||||
sqlite3VdbeAddOp(v, OP_Column, srcTab, j);
|
||||
}else if( pSelect ){
|
||||
|
@ -570,7 +630,7 @@ void sqlite3Insert(
|
|||
sqlite3GenerateConstraintChecks(pParse, pTab, base, 0, keyColumn>=0,
|
||||
0, onError, endOfLoop);
|
||||
sqlite3CompleteInsertion(pParse, pTab, base, 0,0,0,
|
||||
after_triggers ? newIdx : -1);
|
||||
(triggers_exist & TRIGGER_AFTER)!=0 ? newIdx : -1);
|
||||
}
|
||||
|
||||
/* Update the count of rows that are inserted
|
||||
|
@ -579,7 +639,7 @@ void sqlite3Insert(
|
|||
sqlite3VdbeAddOp(v, OP_MemIncr, iCntMem, 0);
|
||||
}
|
||||
|
||||
if( row_triggers_exist ){
|
||||
if( triggers_exist ){
|
||||
/* Close all tables opened */
|
||||
if( !isView ){
|
||||
sqlite3VdbeAddOp(v, OP_Close, base, 0);
|
||||
|
@ -589,8 +649,8 @@ void sqlite3Insert(
|
|||
}
|
||||
|
||||
/* Code AFTER triggers */
|
||||
if( sqlite3CodeRowTrigger(pParse, TK_INSERT, 0, TK_AFTER, pTab, newIdx, -1,
|
||||
onError, endOfLoop) ){
|
||||
if( sqlite3CodeRowTrigger(pParse, TK_INSERT, 0, TRIGGER_AFTER, pTab,
|
||||
newIdx, -1, onError, endOfLoop) ){
|
||||
goto insert_cleanup;
|
||||
}
|
||||
}
|
||||
|
@ -608,7 +668,7 @@ void sqlite3Insert(
|
|||
sqlite3VdbeResolveLabel(v, iCleanup);
|
||||
}
|
||||
|
||||
if( !row_triggers_exist ){
|
||||
if( !triggers_exist ){
|
||||
/* Close all tables opened */
|
||||
sqlite3VdbeAddOp(v, OP_Close, base, 0);
|
||||
for(idx=1, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, idx++){
|
||||
|
@ -616,10 +676,35 @@ void sqlite3Insert(
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the number of rows inserted.
|
||||
#ifndef SQLITE_OMIT_AUTOINCREMENT
|
||||
/* Update the sqlite_sequence table by storing the content of the
|
||||
** counter value in memory counterMem back into the sqlite_sequence
|
||||
** table.
|
||||
*/
|
||||
if( db->flags & SQLITE_CountRows ){
|
||||
if( pTab->autoInc ){
|
||||
int iCur = pParse->nTab;
|
||||
int base = sqlite3VdbeCurrentAddr(v);
|
||||
sqlite3VdbeAddOp(v, OP_Integer, pTab->iDb, 0);
|
||||
sqlite3VdbeAddOp(v, OP_OpenWrite, iCur, pDb->pSeqTab->tnum);
|
||||
sqlite3VdbeAddOp(v, OP_SetNumColumns, iCur, 2);
|
||||
sqlite3VdbeAddOp(v, OP_MemLoad, counterRowid, 0);
|
||||
sqlite3VdbeAddOp(v, OP_NotNull, -1, base+7);
|
||||
sqlite3VdbeAddOp(v, OP_Pop, 1, 0);
|
||||
sqlite3VdbeAddOp(v, OP_NewRecno, iCur, 0);
|
||||
sqlite3VdbeOp3(v, OP_String8, 0, 0, pTab->zName, 0);
|
||||
sqlite3VdbeAddOp(v, OP_MemLoad, counterMem, 0);
|
||||
sqlite3VdbeAddOp(v, OP_MakeRecord, 2, 0);
|
||||
sqlite3VdbeAddOp(v, OP_PutIntKey, iCur, 0);
|
||||
sqlite3VdbeAddOp(v, OP_Close, iCur, 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Return the number of rows inserted. 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, iCntMem, 0);
|
||||
sqlite3VdbeAddOp(v, OP_Callback, 1, 0);
|
||||
sqlite3VdbeSetNumCols(v, 1);
|
||||
|
@ -628,8 +713,8 @@ void sqlite3Insert(
|
|||
|
||||
insert_cleanup:
|
||||
sqlite3SrcListDelete(pTabList);
|
||||
if( pList ) sqlite3ExprListDelete(pList);
|
||||
if( pSelect ) sqlite3SelectDelete(pSelect);
|
||||
sqlite3ExprListDelete(pList);
|
||||
sqlite3SelectDelete(pSelect);
|
||||
sqlite3IdListDelete(pColumn);
|
||||
}
|
||||
|
||||
|
@ -753,11 +838,13 @@ void sqlite3GenerateConstraintChecks(
|
|||
}else if( onError==OE_Default ){
|
||||
onError = OE_Abort;
|
||||
}
|
||||
if( onError==OE_Replace && pTab->aCol[i].zDflt==0 ){
|
||||
if( onError==OE_Replace && pTab->aCol[i].pDflt==0 ){
|
||||
onError = OE_Abort;
|
||||
}
|
||||
sqlite3VdbeAddOp(v, OP_Dup, nCol-1-i, 1);
|
||||
addr = sqlite3VdbeAddOp(v, OP_NotNull, 1, 0);
|
||||
assert( onError==OE_Rollback || onError==OE_Abort || onError==OE_Fail
|
||||
|| onError==OE_Ignore || onError==OE_Replace );
|
||||
switch( onError ){
|
||||
case OE_Rollback:
|
||||
case OE_Abort:
|
||||
|
@ -775,11 +862,10 @@ void sqlite3GenerateConstraintChecks(
|
|||
break;
|
||||
}
|
||||
case OE_Replace: {
|
||||
sqlite3VdbeOp3(v, OP_String8, 0, 0, pTab->aCol[i].zDflt, P3_STATIC);
|
||||
sqlite3ExprCode(pParse, pTab->aCol[i].pDflt);
|
||||
sqlite3VdbeAddOp(v, OP_Push, nCol-i, 0);
|
||||
break;
|
||||
}
|
||||
default: assert(0);
|
||||
}
|
||||
sqlite3VdbeChangeP2(v, addr, sqlite3VdbeCurrentAddr(v));
|
||||
}
|
||||
|
@ -885,6 +971,8 @@ void sqlite3GenerateConstraintChecks(
|
|||
jumpInst2 = sqlite3VdbeAddOp(v, OP_IsUnique, base+iCur+1, 0);
|
||||
|
||||
/* Generate code that executes if the new index entry is not unique */
|
||||
assert( onError==OE_Rollback || onError==OE_Abort || onError==OE_Fail
|
||||
|| onError==OE_Ignore || onError==OE_Replace );
|
||||
switch( onError ){
|
||||
case OE_Rollback:
|
||||
case OE_Abort:
|
||||
|
@ -929,7 +1017,6 @@ void sqlite3GenerateConstraintChecks(
|
|||
seenReplace = 1;
|
||||
break;
|
||||
}
|
||||
default: assert(0);
|
||||
}
|
||||
contAddr = sqlite3VdbeCurrentAddr(v);
|
||||
assert( contAddr<(1<<24) );
|
||||
|
@ -975,12 +1062,18 @@ void sqlite3CompleteInsertion(
|
|||
}
|
||||
sqlite3VdbeAddOp(v, OP_MakeRecord, pTab->nCol, 0);
|
||||
sqlite3TableAffinityStr(v, pTab);
|
||||
#ifndef SQLITE_OMIT_TRIGGER
|
||||
if( newIdx>=0 ){
|
||||
sqlite3VdbeAddOp(v, OP_Dup, 1, 0);
|
||||
sqlite3VdbeAddOp(v, OP_Dup, 1, 0);
|
||||
sqlite3VdbeAddOp(v, OP_PutIntKey, newIdx, 0);
|
||||
}
|
||||
pik_flags = (OPFLAG_NCHANGE|(isUpdate?0:OPFLAG_LASTROWID));
|
||||
#endif
|
||||
if( pParse->nested ){
|
||||
pik_flags = 0;
|
||||
}else{
|
||||
pik_flags = (OPFLAG_NCHANGE|(isUpdate?0:OPFLAG_LASTROWID));
|
||||
}
|
||||
sqlite3VdbeAddOp(v, OP_PutIntKey, base, pik_flags);
|
||||
|
||||
if( isUpdate && recnoChng ){
|
||||
|
|
|
@ -0,0 +1,96 @@
|
|||
/* Hash score: 151 */
|
||||
static int keywordCode(const char *z, int n){
|
||||
static const char zText[510] =
|
||||
"ABORTABLEFTEMPORARYADDATABASELECTHENDEFAULTRANSACTIONATURALTER"
|
||||
"AISEACHECKEYAFTEREFERENCESCAPELSEXCEPTRIGGEREINDEXCLUSIVEXISTS"
|
||||
"TATEMENTANDEFERRABLEXPLAINITIALLYATTACHAVINGLOBEFOREIGNORENAME"
|
||||
"AUTOINCREMENTBEGINNEREPLACEBETWEENOTNULLIKEBYCASCADEFERREDELETE"
|
||||
"CASECOLLATECOLUMNCOMMITCONFLICTCONSTRAINTERSECTCREATECROSSCURRENT_DATE"
|
||||
"CURRENT_TIMESTAMPRAGMATCHDESCDETACHDISTINCTDROPRIMARYFAILIMIT"
|
||||
"FROMFULLGROUPDATEIMMEDIATEINSERTINSTEADINTOFFSETISNULLJOINORDER"
|
||||
"ESTRICTOUTERIGHTROLLBACKROWHENUNIONUNIQUEUSINGVACUUMVALUESVIEW"
|
||||
"HERE";
|
||||
static const unsigned char aHash[127] = {
|
||||
89, 79, 101, 88, 0, 4, 0, 0, 108, 0, 75, 0, 0,
|
||||
92, 44, 0, 90, 0, 100, 103, 94, 0, 0, 10, 0, 0,
|
||||
107, 0, 104, 98, 0, 11, 47, 0, 41, 0, 0, 63, 69,
|
||||
0, 62, 19, 0, 0, 33, 81, 0, 102, 72, 0, 0, 30,
|
||||
0, 60, 34, 0, 8, 0, 109, 38, 12, 0, 76, 40, 25,
|
||||
64, 0, 0, 37, 80, 52, 36, 49, 20, 86, 0, 31, 0,
|
||||
73, 26, 0, 70, 0, 0, 0, 0, 46, 65, 22, 85, 35,
|
||||
67, 84, 0, 1, 0, 9, 51, 57, 18, 0, 106, 74, 96,
|
||||
53, 6, 83, 0, 0, 48, 91, 0, 99, 0, 68, 0, 0,
|
||||
15, 0, 110, 50, 55, 0, 2, 54, 0, 105,
|
||||
};
|
||||
static const unsigned char aNext[110] = {
|
||||
0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0,
|
||||
0, 0, 0, 5, 13, 0, 7, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 43, 0, 0, 0, 0, 0, 0,
|
||||
0, 16, 0, 23, 45, 0, 0, 0, 0, 28, 58, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 71, 42, 0, 0, 24, 59, 21,
|
||||
0, 78, 0, 66, 0, 0, 82, 29, 0, 0, 0, 0, 0,
|
||||
0, 0, 39, 93, 95, 0, 0, 97, 14, 27, 77, 0, 56,
|
||||
87, 0, 32, 0, 61, 0,
|
||||
};
|
||||
static const unsigned char aLen[110] = {
|
||||
5, 5, 4, 4, 9, 2, 3, 8, 2, 6, 4, 3, 7,
|
||||
11, 2, 7, 5, 5, 4, 5, 3, 5, 10, 6, 4, 6,
|
||||
7, 7, 5, 9, 6, 9, 3, 10, 7, 9, 3, 6, 6,
|
||||
4, 6, 3, 7, 6, 6, 13, 2, 2, 5, 5, 7, 7,
|
||||
3, 7, 4, 4, 2, 7, 3, 8, 6, 4, 7, 6, 6,
|
||||
8, 10, 9, 6, 5, 12, 12, 17, 6, 5, 4, 6, 8,
|
||||
2, 4, 7, 4, 5, 4, 4, 5, 6, 9, 6, 7, 4,
|
||||
2, 6, 3, 6, 4, 5, 8, 5, 5, 8, 3, 4, 5,
|
||||
6, 5, 6, 6, 4, 5,
|
||||
};
|
||||
static const unsigned short int aOffset[110] = {
|
||||
0, 4, 7, 10, 10, 14, 19, 21, 26, 27, 32, 34, 36,
|
||||
42, 51, 52, 57, 61, 65, 67, 71, 74, 78, 86, 91, 94,
|
||||
99, 105, 107, 110, 118, 123, 132, 134, 143, 148, 153, 157, 162,
|
||||
167, 170, 172, 172, 176, 180, 186, 188, 190, 199, 202, 206, 213,
|
||||
219, 219, 222, 225, 229, 231, 232, 236, 243, 249, 253, 260, 266,
|
||||
272, 280, 287, 296, 302, 307, 319, 319, 335, 339, 344, 348, 354,
|
||||
355, 362, 365, 372, 375, 380, 384, 388, 391, 397, 406, 412, 419,
|
||||
422, 422, 425, 428, 434, 438, 442, 450, 454, 459, 467, 469, 473,
|
||||
478, 484, 489, 495, 501, 504,
|
||||
};
|
||||
static const unsigned char aCode[110] = {
|
||||
TK_ABORT, TK_TABLE, TK_JOIN_KW, TK_TEMP, TK_TEMP,
|
||||
TK_OR, TK_ADD, TK_DATABASE, TK_AS, TK_SELECT,
|
||||
TK_THEN, TK_END, TK_DEFAULT, TK_TRANSACTION,TK_ON,
|
||||
TK_JOIN_KW, TK_ALTER, TK_RAISE, TK_EACH, TK_CHECK,
|
||||
TK_KEY, TK_AFTER, TK_REFERENCES, TK_ESCAPE, TK_ELSE,
|
||||
TK_EXCEPT, TK_TRIGGER, TK_REINDEX, TK_INDEX, TK_EXCLUSIVE,
|
||||
TK_EXISTS, TK_STATEMENT, TK_AND, TK_DEFERRABLE, TK_EXPLAIN,
|
||||
TK_INITIALLY, TK_ALL, TK_ATTACH, TK_HAVING, TK_GLOB,
|
||||
TK_BEFORE, TK_FOR, TK_FOREIGN, TK_IGNORE, TK_RENAME,
|
||||
TK_AUTOINCR, TK_TO, TK_IN, TK_BEGIN, TK_JOIN_KW,
|
||||
TK_REPLACE, TK_BETWEEN, TK_NOT, TK_NOTNULL, TK_NULL,
|
||||
TK_LIKE, TK_BY, TK_CASCADE, TK_ASC, TK_DEFERRED,
|
||||
TK_DELETE, TK_CASE, TK_COLLATE, TK_COLUMNKW, TK_COMMIT,
|
||||
TK_CONFLICT, TK_CONSTRAINT, TK_INTERSECT, TK_CREATE, TK_JOIN_KW,
|
||||
TK_CDATE, TK_CTIME, TK_CTIMESTAMP, TK_PRAGMA, TK_MATCH,
|
||||
TK_DESC, TK_DETACH, TK_DISTINCT, TK_IS, TK_DROP,
|
||||
TK_PRIMARY, TK_FAIL, TK_LIMIT, TK_FROM, TK_JOIN_KW,
|
||||
TK_GROUP, TK_UPDATE, TK_IMMEDIATE, TK_INSERT, TK_INSTEAD,
|
||||
TK_INTO, TK_OF, TK_OFFSET, TK_SET, TK_ISNULL,
|
||||
TK_JOIN, TK_ORDER, TK_RESTRICT, TK_JOIN_KW, TK_JOIN_KW,
|
||||
TK_ROLLBACK, TK_ROW, TK_WHEN, TK_UNION, TK_UNIQUE,
|
||||
TK_USING, TK_VACUUM, TK_VALUES, TK_VIEW, TK_WHERE,
|
||||
};
|
||||
int h, i;
|
||||
if( n<2 ) return TK_ID;
|
||||
h = ((sqlite3UpperToLower[((unsigned char*)z)[0]]*4) ^
|
||||
(sqlite3UpperToLower[((unsigned char*)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 char *z, int n){
|
||||
return keywordCode(z, n);
|
||||
}
|
|
@ -14,7 +14,7 @@
|
|||
** other files are for internal use by SQLite and should not be
|
||||
** accessed by users of the library.
|
||||
**
|
||||
** $Id: main.c,v 1.263 2004/10/06 15:41:17 drh Exp $
|
||||
** $Id: main.c,v 1.283 2005/03/21 04:04:03 danielk1977 Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include "os.h"
|
||||
|
@ -26,6 +26,16 @@
|
|||
*/
|
||||
const int sqlite3one = 1;
|
||||
|
||||
#ifndef SQLITE_OMIT_GLOBALRECOVER
|
||||
/*
|
||||
** Linked list of all open database handles. This is used by the
|
||||
** sqlite3_global_recover() function. Entries are added to the list
|
||||
** by openDatabase() and removed by sqlite3_close().
|
||||
*/
|
||||
static sqlite3 *pDbList = 0;
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
** Fill the InitData structure with an error message that indicates
|
||||
** that the database is corrupt.
|
||||
|
@ -202,7 +212,7 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
|
|||
** 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 3:UTF-16 LE 4:UTF-16 BE
|
||||
** meta[5]
|
||||
** meta[5] The user cookie. Used by the application.
|
||||
** meta[6]
|
||||
** meta[7]
|
||||
** meta[8]
|
||||
|
@ -257,12 +267,25 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
|
|||
/* This happens if the database was initially empty */
|
||||
db->file_format = 1;
|
||||
}
|
||||
|
||||
if( db->file_format==2 || db->file_format==3 ){
|
||||
/* File format 2 is treated exactly as file format 1. New
|
||||
** databases are created with file format 1.
|
||||
*/
|
||||
db->file_format = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** file_format==1 Version 3.0.0.
|
||||
** file_format==1 Version 3.0.0.
|
||||
** file_format==2 Version 3.1.3.
|
||||
** file_format==3 Version 3.1.4.
|
||||
**
|
||||
** Version 3.0 can only use files with file_format==1. Version 3.1.3
|
||||
** can read and write files with file_format==1 or file_format==2.
|
||||
** Version 3.1.4 can read and write file formats 1, 2 and 3.
|
||||
*/
|
||||
if( meta[1]>1 ){
|
||||
if( meta[1]>3 ){
|
||||
sqlite3BtreeCloseCursor(curMain);
|
||||
sqlite3SetString(pzErrMsg, "unsupported file format", (char*)0);
|
||||
return SQLITE_ERROR;
|
||||
|
@ -279,7 +302,7 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
|
|||
}else{
|
||||
char *zSql;
|
||||
zSql = sqlite3MPrintf(
|
||||
"SELECT name, rootpage, sql, %s FROM '%q'.%s",
|
||||
"SELECT name, rootpage, sql, '%s' FROM '%q'.%s",
|
||||
zDbNum, db->aDb[iDb].zName, zMasterName);
|
||||
sqlite3SafetyOff(db);
|
||||
rc = sqlite3_exec(db, zSql, sqlite3InitCallback, &initData, 0);
|
||||
|
@ -373,12 +396,13 @@ int sqlite3ReadSchema(Parse *pParse){
|
|||
const char rcsid3[] = "@(#) \044Id: SQLite version " SQLITE_VERSION " $";
|
||||
const char sqlite3_version[] = SQLITE_VERSION;
|
||||
const char *sqlite3_libversion(void){ return sqlite3_version; }
|
||||
int sqlite3_libversion_number(void){ return SQLITE_VERSION_NUMBER; }
|
||||
|
||||
/*
|
||||
** This is the default collating function named "BINARY" which is always
|
||||
** available.
|
||||
*/
|
||||
static int binaryCollatingFunc(
|
||||
static int binCollFunc(
|
||||
void *NotUsed,
|
||||
int nKey1, const void *pKey1,
|
||||
int nKey2, const void *pKey2
|
||||
|
@ -500,6 +524,23 @@ int sqlite3_close(sqlite3 *db){
|
|||
sqlite3ValueFree(db->pErr);
|
||||
}
|
||||
|
||||
#ifndef SQLITE_OMIT_GLOBALRECOVER
|
||||
{
|
||||
sqlite3 *pPrev = pDbList;
|
||||
sqlite3OsEnterMutex();
|
||||
while( pPrev && pPrev->pNext!=db ){
|
||||
pPrev = pPrev->pNext;
|
||||
}
|
||||
if( pPrev ){
|
||||
pPrev->pNext = db->pNext;
|
||||
}else{
|
||||
assert( pDbList==db );
|
||||
pDbList = db->pNext;
|
||||
}
|
||||
sqlite3OsLeaveMutex();
|
||||
}
|
||||
#endif
|
||||
|
||||
db->magic = SQLITE_MAGIC_ERROR;
|
||||
sqliteFree(db);
|
||||
return SQLITE_OK;
|
||||
|
@ -553,7 +594,7 @@ const char *sqlite3ErrStr(int rc){
|
|||
case SQLITE_NOLFS: z = "kernel lacks large file support"; break;
|
||||
case SQLITE_AUTH: z = "authorization denied"; break;
|
||||
case SQLITE_FORMAT: z = "auxiliary database format error"; break;
|
||||
case SQLITE_RANGE: z = "bind index out of range"; break;
|
||||
case SQLITE_RANGE: z = "bind or column index out of range"; break;
|
||||
case SQLITE_NOTADB: z = "file is encrypted or is not a database";break;
|
||||
default: z = "unknown error"; break;
|
||||
}
|
||||
|
@ -706,6 +747,7 @@ int sqlite3_create_function(
|
|||
return SQLITE_ERROR;
|
||||
}
|
||||
|
||||
#ifndef SQLITE_OMIT_UTF16
|
||||
/* If SQLITE_UTF16 is specified as the encoding type, transform this
|
||||
** to one of SQLITE_UTF16LE or SQLITE_UTF16BE using the
|
||||
** SQLITE_UTF16NATIVE macro. SQLITE_UTF16 is not used internally.
|
||||
|
@ -725,6 +767,25 @@ int sqlite3_create_function(
|
|||
if( rc!=SQLITE_OK ) return rc;
|
||||
enc = SQLITE_UTF16BE;
|
||||
}
|
||||
#else
|
||||
enc = SQLITE_UTF8;
|
||||
#endif
|
||||
|
||||
/* Check if an existing function is being overridden or deleted. If so,
|
||||
** and there are active VMs, then return SQLITE_BUSY. If a function
|
||||
** is being overridden/deleted but there are no active VMs, allow the
|
||||
** operation to continue but invalidate all precompiled statements.
|
||||
*/
|
||||
p = sqlite3FindFunction(db, zFunctionName, nName, nArg, enc, 0);
|
||||
if( p && p->iPrefEnc==enc && p->nArg==nArg ){
|
||||
if( db->activeVdbeCnt ){
|
||||
sqlite3Error(db, SQLITE_BUSY,
|
||||
"Unable to delete/modify user-function due to active statements");
|
||||
return SQLITE_BUSY;
|
||||
}else{
|
||||
sqlite3ExpirePreparedStatements(db);
|
||||
}
|
||||
}
|
||||
|
||||
p = sqlite3FindFunction(db, zFunctionName, nName, nArg, enc, 1);
|
||||
if( p==0 ) return SQLITE_NOMEM;
|
||||
|
@ -734,6 +795,7 @@ int sqlite3_create_function(
|
|||
p->pUserData = pUserData;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
#ifndef SQLITE_OMIT_UTF16
|
||||
int sqlite3_create_function16(
|
||||
sqlite3 *db,
|
||||
const void *zFunctionName,
|
||||
|
@ -762,6 +824,7 @@ int sqlite3_create_function16(
|
|||
pUserData, xFunc, xStep, xFinal);
|
||||
return rc;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Register a trace function. The pArg from the previously registered trace
|
||||
|
@ -835,13 +898,14 @@ int sqlite3BtreeFactory(
|
|||
if( omitJournal ){
|
||||
btree_flags |= BTREE_OMIT_JOURNAL;
|
||||
}
|
||||
if( db->flags & SQLITE_NoReadlock ){
|
||||
btree_flags |= BTREE_NO_READLOCK;
|
||||
}
|
||||
if( zFilename==0 ){
|
||||
#ifndef TEMP_STORE
|
||||
# define TEMP_STORE 1
|
||||
#endif
|
||||
#if TEMP_STORE==0
|
||||
/* Do nothing */
|
||||
#endif
|
||||
#ifndef SQLITE_OMIT_MEMORYDB
|
||||
#if TEMP_STORE==1
|
||||
if( db->temp_store==2 ) zFilename = ":memory:";
|
||||
#endif
|
||||
|
@ -851,6 +915,7 @@ int sqlite3BtreeFactory(
|
|||
#if TEMP_STORE==3
|
||||
zFilename = ":memory:";
|
||||
#endif
|
||||
#endif /* SQLITE_OMIT_MEMORYDB */
|
||||
}
|
||||
|
||||
rc = sqlite3BtreeOpen(zFilename, ppBtree, btree_flags);
|
||||
|
@ -880,6 +945,7 @@ const char *sqlite3_errmsg(sqlite3 *db){
|
|||
return z;
|
||||
}
|
||||
|
||||
#ifndef SQLITE_OMIT_UTF16
|
||||
/*
|
||||
** Return UTF-16 encoded English language explanation of the most recent
|
||||
** error.
|
||||
|
@ -919,6 +985,7 @@ const void *sqlite3_errmsg16(sqlite3 *db){
|
|||
}
|
||||
return z;
|
||||
}
|
||||
#endif /* SQLITE_OMIT_UTF16 */
|
||||
|
||||
/*
|
||||
** Return the most recent error code generated by an SQLite routine.
|
||||
|
@ -1005,6 +1072,7 @@ int sqlite3_prepare(
|
|||
if( pzTail ) *pzTail = sParse.zTail;
|
||||
rc = sParse.rc;
|
||||
|
||||
#ifndef SQLITE_OMIT_EXPLAIN
|
||||
if( rc==SQLITE_OK && sParse.pVdbe && sParse.explain ){
|
||||
sqlite3VdbeSetNumCols(sParse.pVdbe, 5);
|
||||
sqlite3VdbeSetColName(sParse.pVdbe, 0, "addr", P3_STATIC);
|
||||
|
@ -1013,6 +1081,7 @@ int sqlite3_prepare(
|
|||
sqlite3VdbeSetColName(sParse.pVdbe, 3, "p2", P3_STATIC);
|
||||
sqlite3VdbeSetColName(sParse.pVdbe, 4, "p3", P3_STATIC);
|
||||
}
|
||||
#endif
|
||||
|
||||
prepare_out:
|
||||
if( sqlite3SafetyOff(db) ){
|
||||
|
@ -1033,6 +1102,7 @@ prepare_out:
|
|||
return rc;
|
||||
}
|
||||
|
||||
#ifndef SQLITE_OMIT_UTF16
|
||||
/*
|
||||
** Compile the UTF-16 encoded SQL statement zSql into a statement handle.
|
||||
*/
|
||||
|
@ -1076,6 +1146,7 @@ int sqlite3_prepare16(
|
|||
|
||||
return rc;
|
||||
}
|
||||
#endif /* SQLITE_OMIT_UTF16 */
|
||||
|
||||
/*
|
||||
** This routine does the work of opening a database on behalf of
|
||||
|
@ -1091,7 +1162,6 @@ static int openDatabase(
|
|||
){
|
||||
sqlite3 *db;
|
||||
int rc, i;
|
||||
char *zErrMsg = 0;
|
||||
|
||||
/* Allocate the sqlite data structure */
|
||||
db = sqliteMalloc( sizeof(sqlite3) );
|
||||
|
@ -1102,7 +1172,7 @@ static int openDatabase(
|
|||
db->aDb = db->aDbStatic;
|
||||
db->enc = SQLITE_UTF8;
|
||||
db->autoCommit = 1;
|
||||
/* db->flags |= SQLITE_ShortColNames; */
|
||||
db->flags |= SQLITE_ShortColNames;
|
||||
sqlite3HashInit(&db->aFunc, SQLITE_HASH_STRING, 0);
|
||||
sqlite3HashInit(&db->aCollSeq, SQLITE_HASH_STRING, 0);
|
||||
for(i=0; i<db->nDb; i++){
|
||||
|
@ -1116,11 +1186,9 @@ static int openDatabase(
|
|||
** and UTF-16, so add a version for each to avoid any unnecessary
|
||||
** conversions. The only error that can occur here is a malloc() failure.
|
||||
*/
|
||||
sqlite3_create_collation(db, "BINARY", SQLITE_UTF8, 0,binaryCollatingFunc);
|
||||
sqlite3_create_collation(db, "BINARY", SQLITE_UTF16LE, 0,binaryCollatingFunc);
|
||||
sqlite3_create_collation(db, "BINARY", SQLITE_UTF16BE, 0,binaryCollatingFunc);
|
||||
db->pDfltColl = sqlite3FindCollSeq(db, db->enc, "BINARY", 6, 0);
|
||||
if( !db->pDfltColl ){
|
||||
if( sqlite3_create_collation(db, "BINARY", SQLITE_UTF8, 0,binCollFunc) ||
|
||||
sqlite3_create_collation(db, "BINARY", SQLITE_UTF16, 0,binCollFunc) ||
|
||||
!(db->pDfltColl = sqlite3FindCollSeq(db, db->enc, "BINARY", 6, 0)) ){
|
||||
rc = db->errCode;
|
||||
assert( rc!=SQLITE_OK );
|
||||
db->magic = SQLITE_MAGIC_CLOSED;
|
||||
|
@ -1150,20 +1218,22 @@ static int openDatabase(
|
|||
** is accessed.
|
||||
*/
|
||||
sqlite3RegisterBuiltinFunctions(db);
|
||||
if( rc==SQLITE_OK ){
|
||||
sqlite3Error(db, SQLITE_OK, 0);
|
||||
db->magic = SQLITE_MAGIC_OPEN;
|
||||
}else{
|
||||
sqlite3Error(db, rc, "%s", zErrMsg, 0);
|
||||
if( zErrMsg ) sqliteFree(zErrMsg);
|
||||
db->magic = SQLITE_MAGIC_CLOSED;
|
||||
}
|
||||
sqlite3Error(db, SQLITE_OK, 0);
|
||||
db->magic = SQLITE_MAGIC_OPEN;
|
||||
|
||||
opendb_out:
|
||||
if( sqlite3_errcode(db)==SQLITE_OK && sqlite3_malloc_failed ){
|
||||
sqlite3Error(db, SQLITE_NOMEM, 0);
|
||||
}
|
||||
*ppDb = db;
|
||||
#ifndef SQLITE_OMIT_GLOBALRECOVER
|
||||
if( db ){
|
||||
sqlite3OsEnterMutex();
|
||||
db->pNext = pDbList;
|
||||
pDbList = db;
|
||||
sqlite3OsLeaveMutex();
|
||||
}
|
||||
#endif
|
||||
return sqlite3_errcode(db);
|
||||
}
|
||||
|
||||
|
@ -1177,6 +1247,7 @@ int sqlite3_open(
|
|||
return openDatabase(zFilename, ppDb);
|
||||
}
|
||||
|
||||
#ifndef SQLITE_OMIT_UTF16
|
||||
/*
|
||||
** Open a new database handle.
|
||||
*/
|
||||
|
@ -1205,6 +1276,7 @@ int sqlite3_open16(
|
|||
|
||||
return rc;
|
||||
}
|
||||
#endif /* SQLITE_OMIT_UTF16 */
|
||||
|
||||
/*
|
||||
** The following routine destroys a virtual machine that is created by
|
||||
|
@ -1239,7 +1311,7 @@ int sqlite3_reset(sqlite3_stmt *pStmt){
|
|||
rc = SQLITE_OK;
|
||||
}else{
|
||||
rc = sqlite3VdbeReset((Vdbe*)pStmt);
|
||||
sqlite3VdbeMakeReady((Vdbe*)pStmt, -1, 0, 0, 0);
|
||||
sqlite3VdbeMakeReady((Vdbe*)pStmt, -1, 0, 0, 0, 0);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
@ -1276,6 +1348,21 @@ int sqlite3_create_collation(
|
|||
);
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
|
||||
/* Check if this call is removing or replacing an existing collation
|
||||
** sequence. If so, and there are active VMs, return busy. If there
|
||||
** are no active VMs, invalidate any pre-compiled statements.
|
||||
*/
|
||||
pColl = sqlite3FindCollSeq(db, (u8)enc, zName, strlen(zName), 0);
|
||||
if( pColl && pColl->xCmp ){
|
||||
if( db->activeVdbeCnt ){
|
||||
sqlite3Error(db, SQLITE_BUSY,
|
||||
"Unable to delete/modify collation sequence due to active statements");
|
||||
return SQLITE_BUSY;
|
||||
}
|
||||
sqlite3ExpirePreparedStatements(db);
|
||||
}
|
||||
|
||||
pColl = sqlite3FindCollSeq(db, (u8)enc, zName, strlen(zName), 1);
|
||||
if( 0==pColl ){
|
||||
rc = SQLITE_NOMEM;
|
||||
|
@ -1288,6 +1375,7 @@ int sqlite3_create_collation(
|
|||
return rc;
|
||||
}
|
||||
|
||||
#ifndef SQLITE_OMIT_UTF16
|
||||
/*
|
||||
** Register a new collation sequence with the database handle db.
|
||||
*/
|
||||
|
@ -1308,6 +1396,7 @@ int sqlite3_create_collation16(
|
|||
zName8 = sqlite3ValueText(pTmp, SQLITE_UTF8);
|
||||
return sqlite3_create_collation(db, zName8, enc, pCtx, xCompare);
|
||||
}
|
||||
#endif /* SQLITE_OMIT_UTF16 */
|
||||
|
||||
/*
|
||||
** Register a collation sequence factory callback with the database handle
|
||||
|
@ -1327,6 +1416,7 @@ int sqlite3_collation_needed(
|
|||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
#ifndef SQLITE_OMIT_UTF16
|
||||
/*
|
||||
** Register a collation sequence factory callback with the database handle
|
||||
** db. Replace any previously installed collation sequence factory.
|
||||
|
@ -1344,3 +1434,40 @@ int sqlite3_collation_needed16(
|
|||
db->pCollNeededArg = pCollNeededArg;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
#endif /* SQLITE_OMIT_UTF16 */
|
||||
|
||||
#ifndef SQLITE_OMIT_GLOBALRECOVER
|
||||
/*
|
||||
** This function is called to recover from a malloc failure that occured
|
||||
** within SQLite.
|
||||
**
|
||||
** This function is *not* threadsafe. Calling this from within a threaded
|
||||
** application when threads other than the caller have used SQLite is
|
||||
** dangerous and will almost certainly result in malfunctions.
|
||||
*/
|
||||
int sqlite3_global_recover(){
|
||||
int rc = SQLITE_OK;
|
||||
|
||||
if( sqlite3_malloc_failed ){
|
||||
sqlite3 *db;
|
||||
int i;
|
||||
sqlite3_malloc_failed = 0;
|
||||
for(db=pDbList; db; db=db->pNext ){
|
||||
sqlite3ExpirePreparedStatements(db);
|
||||
for(i=0; i<db->nDb; i++){
|
||||
Btree *pBt = db->aDb[i].pBt;
|
||||
if( pBt && (rc=sqlite3BtreeReset(pBt)) ){
|
||||
goto recover_out;
|
||||
}
|
||||
}
|
||||
db->autoCommit = 1;
|
||||
}
|
||||
}
|
||||
|
||||
recover_out:
|
||||
if( rc!=SQLITE_OK ){
|
||||
sqlite3_malloc_failed = 1;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -1,128 +1,137 @@
|
|||
/* Automatically generated. Do not edit */
|
||||
/* See the mkopcodec.h script for details. */
|
||||
/* See the mkopcodec.awk script for details. */
|
||||
#if !defined(SQLITE_OMIT_EXPLAIN) || !defined(NDEBUG) || defined(VDBE_PROFILE) || defined(SQLITE_DEBUG)
|
||||
const char *const sqlite3OpcodeNames[] = { "?",
|
||||
"MemLoad",
|
||||
"Column",
|
||||
"SetCookie",
|
||||
"MoveGt",
|
||||
"AggFocus",
|
||||
"RowKey",
|
||||
"IdxRecno",
|
||||
"AggNext",
|
||||
"OpenWrite",
|
||||
"If",
|
||||
"PutStrKey",
|
||||
"Pop",
|
||||
"SortPut",
|
||||
"CollSeq",
|
||||
"OpenRead",
|
||||
"SortReset",
|
||||
"AutoCommit",
|
||||
"Sort",
|
||||
"ListRewind",
|
||||
"IntegrityCk",
|
||||
"Function",
|
||||
"Noop",
|
||||
"Return",
|
||||
"Variable",
|
||||
"String",
|
||||
"ParseSchema",
|
||||
"PutIntKey",
|
||||
"AggFunc",
|
||||
"Close",
|
||||
"ListWrite",
|
||||
"CreateIndex",
|
||||
"IsUnique",
|
||||
"IdxIsNull",
|
||||
"NotFound",
|
||||
"MustBeInt",
|
||||
"Halt",
|
||||
"IdxLT",
|
||||
"AddImm",
|
||||
"Statement",
|
||||
"RowData",
|
||||
"Push",
|
||||
"KeyAsData",
|
||||
"NotExists",
|
||||
"OpenTemp",
|
||||
"MemIncr",
|
||||
"Gosub",
|
||||
"AggSet",
|
||||
"Integer",
|
||||
"SortNext",
|
||||
"Prev",
|
||||
"CreateTable",
|
||||
"Last",
|
||||
"ResetCount",
|
||||
"Callback",
|
||||
"ContextPush",
|
||||
"DropTrigger",
|
||||
"DropIndex",
|
||||
"Or",
|
||||
"And",
|
||||
"Not",
|
||||
"FullKey",
|
||||
"IdxGE",
|
||||
"IdxDelete",
|
||||
"IsNull",
|
||||
"NotNull",
|
||||
"Ne",
|
||||
"Eq",
|
||||
"Gt",
|
||||
"Le",
|
||||
"Lt",
|
||||
"Ge",
|
||||
"BitAnd",
|
||||
"BitOr",
|
||||
"ShiftLeft",
|
||||
"ShiftRight",
|
||||
"Add",
|
||||
"Subtract",
|
||||
"Multiply",
|
||||
"Divide",
|
||||
"Remainder",
|
||||
"Concat",
|
||||
"Negative",
|
||||
"Vacuum",
|
||||
"BitNot",
|
||||
"String8",
|
||||
"MoveLe",
|
||||
"IfNot",
|
||||
"DropTable",
|
||||
"MakeRecord",
|
||||
"Delete",
|
||||
"ListRead",
|
||||
"ListReset",
|
||||
"Dup",
|
||||
"Goto",
|
||||
"Clear",
|
||||
"IdxGT",
|
||||
"MoveLt",
|
||||
"VerifyCookie",
|
||||
"Pull",
|
||||
"SetNumColumns",
|
||||
"AbsValue",
|
||||
"Transaction",
|
||||
"AggGet",
|
||||
"ContextPop",
|
||||
"Next",
|
||||
"AggInit",
|
||||
"Distinct",
|
||||
"NewRecno",
|
||||
"AggReset",
|
||||
"Destroy",
|
||||
"ReadCookie",
|
||||
"ForceInt",
|
||||
"IdxColumn",
|
||||
"Recno",
|
||||
"OpenPseudo",
|
||||
"Blob",
|
||||
"MemStore",
|
||||
"Rewind",
|
||||
"MoveGe",
|
||||
"IdxPut",
|
||||
"Found",
|
||||
"Real",
|
||||
"HexBlob",
|
||||
"NullRow",
|
||||
/* 1 */ "MemLoad",
|
||||
/* 2 */ "Column",
|
||||
/* 3 */ "SetCookie",
|
||||
/* 4 */ "IfMemPos",
|
||||
/* 5 */ "MoveGt",
|
||||
/* 6 */ "AggFocus",
|
||||
/* 7 */ "RowKey",
|
||||
/* 8 */ "IdxRecno",
|
||||
/* 9 */ "AggNext",
|
||||
/* 10 */ "OpenWrite",
|
||||
/* 11 */ "If",
|
||||
/* 12 */ "PutStrKey",
|
||||
/* 13 */ "Pop",
|
||||
/* 14 */ "SortPut",
|
||||
/* 15 */ "AggContextPush",
|
||||
/* 16 */ "CollSeq",
|
||||
/* 17 */ "OpenRead",
|
||||
/* 18 */ "Expire",
|
||||
/* 19 */ "SortReset",
|
||||
/* 20 */ "AutoCommit",
|
||||
/* 21 */ "Sort",
|
||||
/* 22 */ "ListRewind",
|
||||
/* 23 */ "IntegrityCk",
|
||||
/* 24 */ "Function",
|
||||
/* 25 */ "Noop",
|
||||
/* 26 */ "Return",
|
||||
/* 27 */ "Variable",
|
||||
/* 28 */ "String",
|
||||
/* 29 */ "ParseSchema",
|
||||
/* 30 */ "PutIntKey",
|
||||
/* 31 */ "AggFunc",
|
||||
/* 32 */ "Close",
|
||||
/* 33 */ "ListWrite",
|
||||
/* 34 */ "CreateIndex",
|
||||
/* 35 */ "IsUnique",
|
||||
/* 36 */ "IdxIsNull",
|
||||
/* 37 */ "NotFound",
|
||||
/* 38 */ "MustBeInt",
|
||||
/* 39 */ "Halt",
|
||||
/* 40 */ "IdxLT",
|
||||
/* 41 */ "AddImm",
|
||||
/* 42 */ "Statement",
|
||||
/* 43 */ "RowData",
|
||||
/* 44 */ "MemMax",
|
||||
/* 45 */ "Push",
|
||||
/* 46 */ "KeyAsData",
|
||||
/* 47 */ "NotExists",
|
||||
/* 48 */ "OpenTemp",
|
||||
/* 49 */ "MemIncr",
|
||||
/* 50 */ "Gosub",
|
||||
/* 51 */ "AggSet",
|
||||
/* 52 */ "Integer",
|
||||
/* 53 */ "SortNext",
|
||||
/* 54 */ "Prev",
|
||||
/* 55 */ "CreateTable",
|
||||
/* 56 */ "Last",
|
||||
/* 57 */ "ResetCount",
|
||||
/* 58 */ "Callback",
|
||||
/* 59 */ "ContextPush",
|
||||
/* 60 */ "DropTrigger",
|
||||
/* 61 */ "DropIndex",
|
||||
/* 62 */ "FullKey",
|
||||
/* 63 */ "IdxGE",
|
||||
/* 64 */ "Or",
|
||||
/* 65 */ "And",
|
||||
/* 66 */ "Not",
|
||||
/* 67 */ "IdxDelete",
|
||||
/* 68 */ "Vacuum",
|
||||
/* 69 */ "MoveLe",
|
||||
/* 70 */ "IsNull",
|
||||
/* 71 */ "NotNull",
|
||||
/* 72 */ "Ne",
|
||||
/* 73 */ "Eq",
|
||||
/* 74 */ "Gt",
|
||||
/* 75 */ "Le",
|
||||
/* 76 */ "Lt",
|
||||
/* 77 */ "Ge",
|
||||
/* 78 */ "IfNot",
|
||||
/* 79 */ "BitAnd",
|
||||
/* 80 */ "BitOr",
|
||||
/* 81 */ "ShiftLeft",
|
||||
/* 82 */ "ShiftRight",
|
||||
/* 83 */ "Add",
|
||||
/* 84 */ "Subtract",
|
||||
/* 85 */ "Multiply",
|
||||
/* 86 */ "Divide",
|
||||
/* 87 */ "Remainder",
|
||||
/* 88 */ "Concat",
|
||||
/* 89 */ "Negative",
|
||||
/* 90 */ "DropTable",
|
||||
/* 91 */ "BitNot",
|
||||
/* 92 */ "String8",
|
||||
/* 93 */ "MakeRecord",
|
||||
/* 94 */ "Delete",
|
||||
/* 95 */ "AggContextPop",
|
||||
/* 96 */ "ListRead",
|
||||
/* 97 */ "ListReset",
|
||||
/* 98 */ "Dup",
|
||||
/* 99 */ "Goto",
|
||||
/* 100 */ "Clear",
|
||||
/* 101 */ "IdxGT",
|
||||
/* 102 */ "MoveLt",
|
||||
/* 103 */ "VerifyCookie",
|
||||
/* 104 */ "Pull",
|
||||
/* 105 */ "SetNumColumns",
|
||||
/* 106 */ "AbsValue",
|
||||
/* 107 */ "Transaction",
|
||||
/* 108 */ "AggGet",
|
||||
/* 109 */ "ContextPop",
|
||||
/* 110 */ "Next",
|
||||
/* 111 */ "AggInit",
|
||||
/* 112 */ "Distinct",
|
||||
/* 113 */ "NewRecno",
|
||||
/* 114 */ "AggReset",
|
||||
/* 115 */ "Destroy",
|
||||
/* 116 */ "ReadCookie",
|
||||
/* 117 */ "ForceInt",
|
||||
/* 118 */ "Recno",
|
||||
/* 119 */ "OpenPseudo",
|
||||
/* 120 */ "Blob",
|
||||
/* 121 */ "MemStore",
|
||||
/* 122 */ "Rewind",
|
||||
/* 123 */ "MoveGe",
|
||||
/* 124 */ "IdxPut",
|
||||
/* 125 */ "Found",
|
||||
/* 126 */ "NullRow",
|
||||
/* 127 */ "NotUsed_127",
|
||||
/* 128 */ "NotUsed_128",
|
||||
/* 129 */ "NotUsed_129",
|
||||
/* 130 */ "Real",
|
||||
/* 131 */ "HexBlob",
|
||||
};
|
||||
#endif
|
||||
|
|
|
@ -1,126 +1,135 @@
|
|||
/* Automatically generated. Do not edit */
|
||||
/* See the mkopcodeh.awk script for details */
|
||||
#define OP_MemLoad 1
|
||||
#define OP_HexBlob 123
|
||||
#define OP_Column 2
|
||||
#define OP_SetCookie 3
|
||||
#define OP_Real 122
|
||||
#define OP_MoveGt 4
|
||||
#define OP_Ge 71
|
||||
#define OP_AggFocus 5
|
||||
#define OP_RowKey 6
|
||||
#define OP_IdxRecno 7
|
||||
#define OP_AggNext 8
|
||||
#define OP_Eq 67
|
||||
#define OP_OpenWrite 9
|
||||
#define OP_NotNull 65
|
||||
#define OP_If 10
|
||||
#define OP_PutStrKey 11
|
||||
#define OP_String8 85
|
||||
#define OP_Pop 12
|
||||
#define OP_SortPut 13
|
||||
#define OP_CollSeq 14
|
||||
#define OP_OpenRead 15
|
||||
#define OP_SortReset 16
|
||||
#define OP_AutoCommit 17
|
||||
#define OP_Gt 68
|
||||
#define OP_Sort 18
|
||||
#define OP_ListRewind 19
|
||||
#define OP_IntegrityCk 20
|
||||
#define OP_Function 21
|
||||
#define OP_Subtract 77
|
||||
#define OP_And 59
|
||||
#define OP_Noop 22
|
||||
#define OP_Return 23
|
||||
#define OP_Remainder 80
|
||||
#define OP_Multiply 78
|
||||
#define OP_Variable 24
|
||||
#define OP_String 25
|
||||
#define OP_ParseSchema 26
|
||||
#define OP_PutIntKey 27
|
||||
#define OP_AggFunc 28
|
||||
#define OP_Close 29
|
||||
#define OP_ListWrite 30
|
||||
#define OP_CreateIndex 31
|
||||
#define OP_IsUnique 32
|
||||
#define OP_IdxIsNull 33
|
||||
#define OP_NotFound 34
|
||||
#define OP_MustBeInt 35
|
||||
#define OP_Halt 36
|
||||
#define OP_IdxLT 37
|
||||
#define OP_AddImm 38
|
||||
#define OP_Statement 39
|
||||
#define OP_RowData 40
|
||||
#define OP_Push 41
|
||||
#define OP_Or 58
|
||||
#define OP_KeyAsData 42
|
||||
#define OP_NotExists 43
|
||||
#define OP_OpenTemp 44
|
||||
#define OP_MemIncr 45
|
||||
#define OP_Gosub 46
|
||||
#define OP_Divide 79
|
||||
#define OP_AggSet 47
|
||||
#define OP_Integer 48
|
||||
#define OP_SortNext 49
|
||||
#define OP_Prev 50
|
||||
#define OP_Concat 81
|
||||
#define OP_BitAnd 72
|
||||
#define OP_CreateTable 51
|
||||
#define OP_Last 52
|
||||
#define OP_IsNull 64
|
||||
#define OP_ShiftRight 75
|
||||
#define OP_ResetCount 53
|
||||
#define OP_Callback 54
|
||||
#define OP_ContextPush 55
|
||||
#define OP_DropTrigger 56
|
||||
#define OP_DropIndex 57
|
||||
#define OP_FullKey 61
|
||||
#define OP_IdxGE 62
|
||||
#define OP_IdxDelete 63
|
||||
#define OP_Vacuum 83
|
||||
#define OP_MoveLe 86
|
||||
#define OP_IfNot 87
|
||||
#define OP_DropTable 88
|
||||
#define OP_MakeRecord 89
|
||||
#define OP_Delete 90
|
||||
#define OP_ListRead 91
|
||||
#define OP_ListReset 92
|
||||
#define OP_ShiftLeft 74
|
||||
#define OP_Dup 93
|
||||
#define OP_Goto 94
|
||||
#define OP_Clear 95
|
||||
#define OP_IdxGT 96
|
||||
#define OP_MoveLt 97
|
||||
#define OP_Le 69
|
||||
#define OP_VerifyCookie 98
|
||||
#define OP_Pull 99
|
||||
#define OP_Not 60
|
||||
#define OP_SetNumColumns 100
|
||||
#define OP_AbsValue 101
|
||||
#define OP_Transaction 102
|
||||
#define OP_Negative 82
|
||||
#define OP_Ne 66
|
||||
#define OP_AggGet 103
|
||||
#define OP_ContextPop 104
|
||||
#define OP_BitOr 73
|
||||
#define OP_Next 105
|
||||
#define OP_AggInit 106
|
||||
#define OP_Distinct 107
|
||||
#define OP_NewRecno 108
|
||||
#define OP_Lt 70
|
||||
#define OP_AggReset 109
|
||||
#define OP_Destroy 110
|
||||
#define OP_ReadCookie 111
|
||||
#define OP_ForceInt 112
|
||||
#define OP_IdxColumn 113
|
||||
#define OP_Recno 114
|
||||
#define OP_OpenPseudo 115
|
||||
#define OP_Blob 116
|
||||
#define OP_Add 76
|
||||
#define OP_MemStore 117
|
||||
#define OP_Rewind 118
|
||||
#define OP_MoveGe 119
|
||||
#define OP_IdxPut 120
|
||||
#define OP_BitNot 84
|
||||
#define OP_Found 121
|
||||
#define OP_NullRow 124
|
||||
#define OP_MemLoad 1
|
||||
#define OP_HexBlob 131 /* same as TK_BLOB */
|
||||
#define OP_Column 2
|
||||
#define OP_SetCookie 3
|
||||
#define OP_IfMemPos 4
|
||||
#define OP_Real 130 /* same as TK_FLOAT */
|
||||
#define OP_MoveGt 5
|
||||
#define OP_Ge 77 /* same as TK_GE */
|
||||
#define OP_AggFocus 6
|
||||
#define OP_RowKey 7
|
||||
#define OP_IdxRecno 8
|
||||
#define OP_AggNext 9
|
||||
#define OP_Eq 73 /* same as TK_EQ */
|
||||
#define OP_OpenWrite 10
|
||||
#define OP_NotNull 71 /* same as TK_NOTNULL */
|
||||
#define OP_If 11
|
||||
#define OP_PutStrKey 12
|
||||
#define OP_String8 92 /* same as TK_STRING */
|
||||
#define OP_Pop 13
|
||||
#define OP_SortPut 14
|
||||
#define OP_AggContextPush 15
|
||||
#define OP_CollSeq 16
|
||||
#define OP_OpenRead 17
|
||||
#define OP_Expire 18
|
||||
#define OP_SortReset 19
|
||||
#define OP_AutoCommit 20
|
||||
#define OP_Gt 74 /* same as TK_GT */
|
||||
#define OP_Sort 21
|
||||
#define OP_ListRewind 22
|
||||
#define OP_IntegrityCk 23
|
||||
#define OP_Function 24
|
||||
#define OP_Subtract 84 /* same as TK_MINUS */
|
||||
#define OP_And 65 /* same as TK_AND */
|
||||
#define OP_Noop 25
|
||||
#define OP_Return 26
|
||||
#define OP_Remainder 87 /* same as TK_REM */
|
||||
#define OP_Multiply 85 /* same as TK_STAR */
|
||||
#define OP_Variable 27
|
||||
#define OP_String 28
|
||||
#define OP_ParseSchema 29
|
||||
#define OP_PutIntKey 30
|
||||
#define OP_AggFunc 31
|
||||
#define OP_Close 32
|
||||
#define OP_ListWrite 33
|
||||
#define OP_CreateIndex 34
|
||||
#define OP_IsUnique 35
|
||||
#define OP_IdxIsNull 36
|
||||
#define OP_NotFound 37
|
||||
#define OP_MustBeInt 38
|
||||
#define OP_Halt 39
|
||||
#define OP_IdxLT 40
|
||||
#define OP_AddImm 41
|
||||
#define OP_Statement 42
|
||||
#define OP_RowData 43
|
||||
#define OP_MemMax 44
|
||||
#define OP_Push 45
|
||||
#define OP_Or 64 /* same as TK_OR */
|
||||
#define OP_KeyAsData 46
|
||||
#define OP_NotExists 47
|
||||
#define OP_OpenTemp 48
|
||||
#define OP_MemIncr 49
|
||||
#define OP_Gosub 50
|
||||
#define OP_Divide 86 /* same as TK_SLASH */
|
||||
#define OP_AggSet 51
|
||||
#define OP_Integer 52
|
||||
#define OP_SortNext 53
|
||||
#define OP_Prev 54
|
||||
#define OP_Concat 88 /* same as TK_CONCAT */
|
||||
#define OP_BitAnd 79 /* same as TK_BITAND */
|
||||
#define OP_CreateTable 55
|
||||
#define OP_Last 56
|
||||
#define OP_IsNull 70 /* same as TK_ISNULL */
|
||||
#define OP_ShiftRight 82 /* same as TK_RSHIFT */
|
||||
#define OP_ResetCount 57
|
||||
#define OP_Callback 58
|
||||
#define OP_ContextPush 59
|
||||
#define OP_DropTrigger 60
|
||||
#define OP_DropIndex 61
|
||||
#define OP_FullKey 62
|
||||
#define OP_IdxGE 63
|
||||
#define OP_IdxDelete 67
|
||||
#define OP_Vacuum 68
|
||||
#define OP_MoveLe 69
|
||||
#define OP_IfNot 78
|
||||
#define OP_DropTable 90
|
||||
#define OP_MakeRecord 93
|
||||
#define OP_Delete 94
|
||||
#define OP_AggContextPop 95
|
||||
#define OP_ListRead 96
|
||||
#define OP_ListReset 97
|
||||
#define OP_ShiftLeft 81 /* same as TK_LSHIFT */
|
||||
#define OP_Dup 98
|
||||
#define OP_Goto 99
|
||||
#define OP_Clear 100
|
||||
#define OP_IdxGT 101
|
||||
#define OP_MoveLt 102
|
||||
#define OP_Le 75 /* same as TK_LE */
|
||||
#define OP_VerifyCookie 103
|
||||
#define OP_Pull 104
|
||||
#define OP_Not 66 /* same as TK_NOT */
|
||||
#define OP_SetNumColumns 105
|
||||
#define OP_AbsValue 106
|
||||
#define OP_Transaction 107
|
||||
#define OP_Negative 89 /* same as TK_UMINUS */
|
||||
#define OP_Ne 72 /* same as TK_NE */
|
||||
#define OP_AggGet 108
|
||||
#define OP_ContextPop 109
|
||||
#define OP_BitOr 80 /* same as TK_BITOR */
|
||||
#define OP_Next 110
|
||||
#define OP_AggInit 111
|
||||
#define OP_Distinct 112
|
||||
#define OP_NewRecno 113
|
||||
#define OP_Lt 76 /* same as TK_LT */
|
||||
#define OP_AggReset 114
|
||||
#define OP_Destroy 115
|
||||
#define OP_ReadCookie 116
|
||||
#define OP_ForceInt 117
|
||||
#define OP_Recno 118
|
||||
#define OP_OpenPseudo 119
|
||||
#define OP_Blob 120
|
||||
#define OP_Add 83 /* same as TK_PLUS */
|
||||
#define OP_MemStore 121
|
||||
#define OP_Rewind 122
|
||||
#define OP_MoveGe 123
|
||||
#define OP_IdxPut 124
|
||||
#define OP_BitNot 91 /* same as TK_BITNOT */
|
||||
#define OP_Found 125
|
||||
#define OP_NullRow 126
|
||||
|
||||
/* The following opcode values are never used */
|
||||
#define OP_NotUsed_127 127
|
||||
#define OP_NotUsed_128 128
|
||||
#define OP_NotUsed_129 129
|
||||
|
|
|
@ -25,30 +25,17 @@
|
|||
*/
|
||||
#if !defined(OS_UNIX) && !defined(OS_TEST)
|
||||
# ifndef OS_WIN
|
||||
# ifndef OS_MAC
|
||||
# if defined(__MACOS__)
|
||||
# define OS_MAC 1
|
||||
# define OS_WIN 0
|
||||
# define OS_UNIX 0
|
||||
# elif defined(_WIN32) || defined(WIN32) || defined(__CYGWIN__) || defined(__MINGW32__) || defined(__BORLANDC__)
|
||||
# define OS_MAC 0
|
||||
# define OS_WIN 1
|
||||
# define OS_UNIX 0
|
||||
# else
|
||||
# define OS_MAC 0
|
||||
# define OS_WIN 0
|
||||
# define OS_UNIX 1
|
||||
# endif
|
||||
# else
|
||||
# define OS_WIN 0
|
||||
# define OS_UNIX 0
|
||||
# if defined(_WIN32) || defined(WIN32) || defined(__CYGWIN__) || defined(__MINGW32__) || defined(__BORLANDC__)
|
||||
# define OS_WIN 1
|
||||
# define OS_UNIX 0
|
||||
# else
|
||||
# define OS_WIN 0
|
||||
# define OS_UNIX 1
|
||||
# endif
|
||||
# else
|
||||
# define OS_MAC 0
|
||||
# define OS_UNIX 0
|
||||
# endif
|
||||
#else
|
||||
# define OS_MAC 0
|
||||
# ifndef OS_WIN
|
||||
# define OS_WIN 0
|
||||
# endif
|
||||
|
@ -66,8 +53,12 @@
|
|||
#if OS_WIN
|
||||
# include "os_win.h"
|
||||
#endif
|
||||
#if OS_MAC
|
||||
# include "os_mac.h"
|
||||
|
||||
/* If the SET_FULLSYNC macro is not defined above, then make it
|
||||
** a no-op
|
||||
*/
|
||||
#ifndef SET_FULLSYNC
|
||||
# define SET_FULLSYNC(x,y)
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
@ -162,7 +153,7 @@
|
|||
**
|
||||
*/
|
||||
#define PENDING_BYTE 0x40000000 /* First byte past the 1GB boundary */
|
||||
/* #define PENDING_BYTE 0x5400 // Page 20 - for testing */
|
||||
/* #define PENDING_BYTE 0x5400 // Page 22 - for testing */
|
||||
#define RESERVED_BYTE (PENDING_BYTE+1)
|
||||
#define SHARED_FIRST (PENDING_BYTE+2)
|
||||
#define SHARED_SIZE 510
|
||||
|
@ -176,6 +167,7 @@ int sqlite3OsOpenReadOnly(const char*, OsFile*);
|
|||
int sqlite3OsOpenDirectory(const char*, OsFile*);
|
||||
int sqlite3OsSyncDirectory(const char*);
|
||||
int sqlite3OsTempFileName(char*);
|
||||
int sqlite3OsIsDirWritable(char*);
|
||||
int sqlite3OsClose(OsFile*);
|
||||
int sqlite3OsRead(OsFile*, void*, int amt);
|
||||
int sqlite3OsWrite(OsFile*, const void*, int amt);
|
||||
|
|
|
@ -574,7 +574,7 @@ int sqlite3OsOpenDirectory(
|
|||
** name of a directory, then that directory will be used to store
|
||||
** temporary files.
|
||||
*/
|
||||
const char *sqlite3_temp_directory = 0;
|
||||
char *sqlite3_temp_directory = 0;
|
||||
|
||||
/*
|
||||
** Create a temporary file name in zBuf. zBuf must be big enough to
|
||||
|
@ -616,6 +616,22 @@ int sqlite3OsTempFileName(char *zBuf){
|
|||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
#ifndef SQLITE_OMIT_PAGER_PRAGMAS
|
||||
/*
|
||||
** Check that a given pathname is a directory and is writable
|
||||
**
|
||||
*/
|
||||
int sqlite3OsIsDirWritable(char *zBuf){
|
||||
struct stat buf;
|
||||
if( zBuf==0 ) return 0;
|
||||
if( zBuf[0]==0 ) return 0;
|
||||
if( stat(zBuf, &buf) ) return 0;
|
||||
if( !S_ISDIR(buf.st_mode) ) return 0;
|
||||
if( access(zBuf, 07) ) return 0;
|
||||
return 1;
|
||||
}
|
||||
#endif /* SQLITE_OMIT_PAGER_PRAGMAS */
|
||||
|
||||
/*
|
||||
** Read data from a file into a buffer. Return SQLITE_OK if all
|
||||
** bytes were read successfully and SQLITE_IOERR if anything goes
|
||||
|
@ -628,7 +644,7 @@ int sqlite3OsRead(OsFile *id, void *pBuf, int amt){
|
|||
TIMER_START;
|
||||
got = read(id->h, pBuf, amt);
|
||||
TIMER_END;
|
||||
TRACE4("READ %-3d %7d %d\n", id->h, last_page, TIMER_ELAPSED);
|
||||
TRACE5("READ %-3d %5d %7d %d\n", id->h, got, last_page, TIMER_ELAPSED);
|
||||
SEEK(0);
|
||||
/* if( got<0 ) got = 0; */
|
||||
if( got==amt ){
|
||||
|
@ -645,6 +661,7 @@ int sqlite3OsRead(OsFile *id, void *pBuf, int amt){
|
|||
int sqlite3OsWrite(OsFile *id, const void *pBuf, int amt){
|
||||
int wrote = 0;
|
||||
assert( id->isOpen );
|
||||
assert( amt>0 );
|
||||
SimulateIOError(SQLITE_IOERR);
|
||||
SimulateDiskfullError;
|
||||
TIMER_START;
|
||||
|
@ -653,7 +670,7 @@ int sqlite3OsWrite(OsFile *id, const void *pBuf, int amt){
|
|||
pBuf = &((char*)pBuf)[wrote];
|
||||
}
|
||||
TIMER_END;
|
||||
TRACE4("WRITE %-3d %7d %d\n", id->h, last_page, TIMER_ELAPSED);
|
||||
TRACE5("WRITE %-3d %5d %7d %d\n", id->h, wrote, last_page, TIMER_ELAPSED);
|
||||
SEEK(0);
|
||||
if( amt>0 ){
|
||||
return SQLITE_FULL;
|
||||
|
@ -671,19 +688,60 @@ int sqlite3OsSeek(OsFile *id, i64 offset){
|
|||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
#ifdef SQLITE_TEST
|
||||
/*
|
||||
** Count the number of fullsyncs and normal syncs. This is used to test
|
||||
** that syncs and fullsyncs are occuring at the right times.
|
||||
*/
|
||||
int sqlite3_sync_count = 0;
|
||||
int sqlite3_fullsync_count = 0;
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
** The fsync() system call does not work as advertised on many
|
||||
** unix systems. The following procedure is an attempt to make
|
||||
** it work better.
|
||||
**
|
||||
** The SQLITE_NO_SYNC macro disables all fsync()s. This is useful
|
||||
** for testing when we want to run through the test suite quickly.
|
||||
** You are strongly advised *not* to deploy with SQLITE_NO_SYNC
|
||||
** enabled, however, since with SQLITE_NO_SYNC enabled, an OS crash
|
||||
** or power failure will likely corrupt the database file.
|
||||
*/
|
||||
static int full_fsync(int fd){
|
||||
static int full_fsync(int fd, int fullSync){
|
||||
int rc;
|
||||
|
||||
/* Record the number of times that we do a normal fsync() and
|
||||
** FULLSYNC. This is used during testing to verify that this procedure
|
||||
** gets called with the correct arguments.
|
||||
*/
|
||||
#ifdef SQLITE_TEST
|
||||
if( fullSync ) sqlite3_fullsync_count++;
|
||||
sqlite3_sync_count++;
|
||||
#endif
|
||||
|
||||
/* If we compiled with the SQLITE_NO_SYNC flag, then syncing is a
|
||||
** no-op
|
||||
*/
|
||||
#ifdef SQLITE_NO_SYNC
|
||||
rc = SQLITE_OK;
|
||||
#else
|
||||
|
||||
#ifdef F_FULLFSYNC
|
||||
rc = fcntl(fd, F_FULLFSYNC, 0);
|
||||
if( fullSync ){
|
||||
rc = fcntl(fd, F_FULLFSYNC, 0);
|
||||
}else{
|
||||
rc = 1;
|
||||
}
|
||||
/* If the FULLSYNC failed, try to do a normal fsync() */
|
||||
if( rc ) rc = fsync(fd);
|
||||
|
||||
#else
|
||||
rc = fsync(fd);
|
||||
#endif
|
||||
#endif /* defined(F_FULLFSYNC) */
|
||||
#endif /* defined(SQLITE_NO_SYNC) */
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
@ -702,12 +760,12 @@ int sqlite3OsSync(OsFile *id){
|
|||
assert( id->isOpen );
|
||||
SimulateIOError(SQLITE_IOERR);
|
||||
TRACE2("SYNC %-3d\n", id->h);
|
||||
if( full_fsync(id->h) ){
|
||||
if( full_fsync(id->h, id->fullSync) ){
|
||||
return SQLITE_IOERR;
|
||||
}
|
||||
if( id->dirfd>=0 ){
|
||||
TRACE2("DIRSYNC %-3d\n", id->dirfd);
|
||||
full_fsync(id->dirfd);
|
||||
full_fsync(id->dirfd, id->fullSync);
|
||||
close(id->dirfd); /* Only need to sync once, so close the directory */
|
||||
id->dirfd = -1; /* when we are done. */
|
||||
}
|
||||
|
@ -717,6 +775,10 @@ int sqlite3OsSync(OsFile *id){
|
|||
/*
|
||||
** Sync the directory zDirname. This is a no-op on operating systems other
|
||||
** than UNIX.
|
||||
**
|
||||
** This is used to make sure the master journal file has truely been deleted
|
||||
** before making changes to individual journals on a multi-database commit.
|
||||
** The F_FULLFSYNC option is not needed here.
|
||||
*/
|
||||
int sqlite3OsSyncDirectory(const char *zDirname){
|
||||
int fd;
|
||||
|
@ -879,7 +941,7 @@ int sqlite3OsLock(OsFile *id, int locktype){
|
|||
int s;
|
||||
|
||||
assert( id->isOpen );
|
||||
TRACE7("LOCK %d %s was %s(%s,%d) pid=%d\n", id->h, locktypeName(locktype),
|
||||
TRACE7("LOCK %d %s was %s(%s,%d) pid=%d\n", id->h, locktypeName(locktype),
|
||||
locktypeName(id->locktype), locktypeName(pLock->locktype), pLock->cnt
|
||||
,getpid() );
|
||||
|
||||
|
@ -888,7 +950,7 @@ int sqlite3OsLock(OsFile *id, int locktype){
|
|||
** sqlite3OsEnterMutex() hasn't been called yet.
|
||||
*/
|
||||
if( id->locktype>=locktype ){
|
||||
TRACE3("LOCK %d %s ok (already held)\n", id->h, locktypeName(locktype));
|
||||
TRACE3("LOCK %d %s ok (already held)\n", id->h, locktypeName(locktype));
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
|
@ -1009,7 +1071,7 @@ int sqlite3OsLock(OsFile *id, int locktype){
|
|||
|
||||
end_lock:
|
||||
sqlite3OsLeaveMutex();
|
||||
TRACE4("LOCK %d %s %s\n", id->h, locktypeName(locktype),
|
||||
TRACE4("LOCK %d %s %s\n", id->h, locktypeName(locktype),
|
||||
rc==SQLITE_OK ? "ok" : "failed");
|
||||
return rc;
|
||||
}
|
||||
|
@ -1031,7 +1093,7 @@ int sqlite3OsUnlock(OsFile *id, int locktype){
|
|||
int rc = SQLITE_OK;
|
||||
|
||||
assert( id->isOpen );
|
||||
TRACE7("UNLOCK %d %d was %d(%d,%d) pid=%d\n", id->h, locktype, id->locktype,
|
||||
TRACE7("UNLOCK %d %d was %d(%d,%d) pid=%d\n", id->h, locktype, id->locktype,
|
||||
id->pLock->locktype, id->pLock->cnt, getpid());
|
||||
|
||||
assert( locktype<=SHARED_LOCK );
|
||||
|
@ -1157,10 +1219,16 @@ int sqlite3OsRandomSeed(char *zBuf){
|
|||
memset(zBuf, 0, 256);
|
||||
#if !defined(SQLITE_TEST)
|
||||
{
|
||||
int pid;
|
||||
time((time_t*)zBuf);
|
||||
pid = getpid();
|
||||
memcpy(&zBuf[sizeof(time_t)], &pid, sizeof(pid));
|
||||
int pid, fd;
|
||||
fd = open("/dev/urandom", O_RDONLY);
|
||||
if( fd<0 ){
|
||||
time((time_t*)zBuf);
|
||||
pid = getpid();
|
||||
memcpy(&zBuf[sizeof(time_t)], &pid, sizeof(pid));
|
||||
}else{
|
||||
read(fd, zBuf, 256);
|
||||
close(fd);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return SQLITE_OK;
|
||||
|
|
|
@ -68,9 +68,15 @@ struct OsFile {
|
|||
int h; /* The file descriptor */
|
||||
unsigned char locktype; /* The type of lock held on this fd */
|
||||
unsigned char isOpen; /* True if needs to be closed */
|
||||
unsigned char fullSync; /* Use F_FULLSYNC if available */
|
||||
int dirfd; /* File descriptor for the directory */
|
||||
};
|
||||
|
||||
/*
|
||||
** A macro to set the OsFile.fullSync flag, if it exists.
|
||||
*/
|
||||
#define SET_FULLSYNC(x,y) ((x).fullSync = (y))
|
||||
|
||||
/*
|
||||
** Maximum number of characters in a temporary file name
|
||||
*/
|
||||
|
|
|
@ -18,6 +18,10 @@
|
|||
|
||||
#include <winbase.h>
|
||||
|
||||
#ifdef __CYGWIN__
|
||||
# include <sys/cygwin.h>
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Macros used to determine whether or not to use threads.
|
||||
*/
|
||||
|
@ -202,7 +206,7 @@ int sqlite3OsOpenDirectory(
|
|||
** name of a directory, then that directory will be used to store
|
||||
** temporary files.
|
||||
*/
|
||||
const char *sqlite3_temp_directory = 0;
|
||||
char *sqlite3_temp_directory = 0;
|
||||
|
||||
/*
|
||||
** Create a temporary file name in zBuf. zBuf must be big enough to
|
||||
|
@ -275,12 +279,13 @@ int sqlite3OsRead(OsFile *id, void *pBuf, int amt){
|
|||
** or some other error code on failure.
|
||||
*/
|
||||
int sqlite3OsWrite(OsFile *id, const void *pBuf, int amt){
|
||||
int rc;
|
||||
int rc = 0;
|
||||
DWORD wrote;
|
||||
assert( id->isOpen );
|
||||
SimulateIOError(SQLITE_IOERR);
|
||||
SimulateDiskfullError;
|
||||
TRACE3("WRITE %d lock=%d\n", id->h, id->locktype);
|
||||
assert( amt>0 );
|
||||
while( amt>0 && (rc = WriteFile(id->h, pBuf, amt, &wrote, 0))!=0 && wrote>0 ){
|
||||
amt -= wrote;
|
||||
pBuf = &((char*)pBuf)[wrote];
|
||||
|
@ -409,6 +414,24 @@ static int unlockReadLock(OsFile *id){
|
|||
return res;
|
||||
}
|
||||
|
||||
#ifndef SQLITE_OMIT_PAGER_PRAGMAS
|
||||
/*
|
||||
** Check that a given pathname is a directory and is writable
|
||||
**
|
||||
*/
|
||||
int sqlite3OsIsDirWritable(char *zBuf){
|
||||
int fileAttr;
|
||||
if(! zBuf ) return 0;
|
||||
if(! isNT() && strlen(zBuf) > MAX_PATH ) return 0;
|
||||
fileAttr = GetFileAttributesA(zBuf);
|
||||
if( fileAttr == 0xffffffff ) return 0;
|
||||
if( (fileAttr & FILE_ATTRIBUTE_DIRECTORY) != FILE_ATTRIBUTE_DIRECTORY ){
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
#endif /* SQLITE_OMIT_PAGER_PRAGMAS */
|
||||
|
||||
/*
|
||||
** Lock the file with the lock specified by parameter locktype - one
|
||||
** of the following:
|
||||
|
@ -684,10 +707,17 @@ char *sqlite3OsFullPathname(const char *zRelative){
|
|||
char *zNotUsed;
|
||||
char *zFull;
|
||||
int nByte;
|
||||
#ifdef __CYGWIN__
|
||||
nByte = strlen(zRelative) + MAX_PATH + 1001;
|
||||
zFull = sqliteMalloc( nByte );
|
||||
if( zFull==0 ) return 0;
|
||||
if( cygwin_conv_to_full_win32_path(zRelative, zFull) ) return 0;
|
||||
#else
|
||||
nByte = GetFullPathNameA(zRelative, 0, 0, &zNotUsed) + 1;
|
||||
zFull = sqliteMalloc( nByte );
|
||||
if( zFull==0 ) return 0;
|
||||
GetFullPathNameA(zRelative, nByte, zFull, &zNotUsed);
|
||||
#endif
|
||||
return zFull;
|
||||
}
|
||||
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -13,7 +13,7 @@
|
|||
** subsystem. The page cache subsystem reads and writes a file a page
|
||||
** at a time and provides a journal for rollback.
|
||||
**
|
||||
** @(#) $Id: pager.h,v 1.38 2004/10/05 02:41:43 drh Exp $
|
||||
** @(#) $Id: pager.h,v 1.42 2005/03/21 04:04:03 danielk1977 Exp $
|
||||
*/
|
||||
|
||||
/*
|
||||
|
@ -50,13 +50,21 @@ typedef unsigned int Pgno;
|
|||
*/
|
||||
typedef struct Pager Pager;
|
||||
|
||||
/*
|
||||
** Allowed values for the flags parameter to sqlite3pager_open().
|
||||
**
|
||||
** 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 */
|
||||
|
||||
|
||||
/*
|
||||
** See source code comments for a detailed description of the following
|
||||
** routines:
|
||||
*/
|
||||
int sqlite3pager_open(Pager **ppPager, const char *zFilename,
|
||||
int nExtra, int useJournal);
|
||||
int nExtra, int flags);
|
||||
void sqlite3pager_set_busyhandler(Pager*, BusyHandler *pBusyHandler);
|
||||
void sqlite3pager_set_destructor(Pager*, void(*)(void*,int));
|
||||
void sqlite3pager_set_reiniter(Pager*, void(*)(void*,int));
|
||||
|
@ -76,7 +84,7 @@ int sqlite3pager_pagecount(Pager*);
|
|||
int sqlite3pager_truncate(Pager*,Pgno);
|
||||
int sqlite3pager_begin(void*, int exFlag);
|
||||
int sqlite3pager_commit(Pager*);
|
||||
int sqlite3pager_sync(Pager*,const char *zMaster);
|
||||
int sqlite3pager_sync(Pager*,const char *zMaster, Pgno);
|
||||
int sqlite3pager_rollback(Pager*);
|
||||
int sqlite3pager_isreadonly(Pager*);
|
||||
int sqlite3pager_stmt_begin(Pager*);
|
||||
|
@ -91,6 +99,8 @@ const char *sqlite3pager_dirname(Pager*);
|
|||
const char *sqlite3pager_journalname(Pager*);
|
||||
int sqlite3pager_rename(Pager*, const char *zNewName);
|
||||
void sqlite3pager_set_codec(Pager*,void(*)(void*,void*,Pgno,int),void*);
|
||||
int sqlite3pager_movepage(Pager*,void*,Pgno);
|
||||
int sqlite3pager_reset(Pager*);
|
||||
|
||||
#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
|
||||
int sqlite3pager_lockstate(Pager*);
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -55,75 +55,88 @@
|
|||
#define TK_TRIGGER 55
|
||||
#define TK_VACUUM 56
|
||||
#define TK_VIEW 57
|
||||
#define TK_OR 58
|
||||
#define TK_AND 59
|
||||
#define TK_NOT 60
|
||||
#define TK_IS 61
|
||||
#define TK_BETWEEN 62
|
||||
#define TK_IN 63
|
||||
#define TK_ISNULL 64
|
||||
#define TK_NOTNULL 65
|
||||
#define TK_NE 66
|
||||
#define TK_EQ 67
|
||||
#define TK_GT 68
|
||||
#define TK_LE 69
|
||||
#define TK_LT 70
|
||||
#define TK_GE 71
|
||||
#define TK_BITAND 72
|
||||
#define TK_BITOR 73
|
||||
#define TK_LSHIFT 74
|
||||
#define TK_RSHIFT 75
|
||||
#define TK_PLUS 76
|
||||
#define TK_MINUS 77
|
||||
#define TK_STAR 78
|
||||
#define TK_SLASH 79
|
||||
#define TK_REM 80
|
||||
#define TK_CONCAT 81
|
||||
#define TK_UMINUS 82
|
||||
#define TK_UPLUS 83
|
||||
#define TK_BITNOT 84
|
||||
#define TK_STRING 85
|
||||
#define TK_JOIN_KW 86
|
||||
#define TK_CONSTRAINT 87
|
||||
#define TK_DEFAULT 88
|
||||
#define TK_NULL 89
|
||||
#define TK_PRIMARY 90
|
||||
#define TK_UNIQUE 91
|
||||
#define TK_CHECK 92
|
||||
#define TK_REFERENCES 93
|
||||
#define TK_COLLATE 94
|
||||
#define TK_ON 95
|
||||
#define TK_DELETE 96
|
||||
#define TK_UPDATE 97
|
||||
#define TK_INSERT 98
|
||||
#define TK_SET 99
|
||||
#define TK_DEFERRABLE 100
|
||||
#define TK_FOREIGN 101
|
||||
#define TK_DROP 102
|
||||
#define TK_UNION 103
|
||||
#define TK_ALL 104
|
||||
#define TK_INTERSECT 105
|
||||
#define TK_EXCEPT 106
|
||||
#define TK_SELECT 107
|
||||
#define TK_DISTINCT 108
|
||||
#define TK_DOT 109
|
||||
#define TK_FROM 110
|
||||
#define TK_JOIN 111
|
||||
#define TK_USING 112
|
||||
#define TK_ORDER 113
|
||||
#define TK_BY 114
|
||||
#define TK_GROUP 115
|
||||
#define TK_HAVING 116
|
||||
#define TK_LIMIT 117
|
||||
#define TK_WHERE 118
|
||||
#define TK_INTO 119
|
||||
#define TK_VALUES 120
|
||||
#define TK_INTEGER 121
|
||||
#define TK_FLOAT 122
|
||||
#define TK_BLOB 123
|
||||
#define TK_VARIABLE 124
|
||||
#define TK_CASE 125
|
||||
#define TK_WHEN 126
|
||||
#define TK_THEN 127
|
||||
#define TK_ELSE 128
|
||||
#define TK_INDEX 129
|
||||
#define TK_REINDEX 58
|
||||
#define TK_RENAME 59
|
||||
#define TK_CDATE 60
|
||||
#define TK_CTIME 61
|
||||
#define TK_CTIMESTAMP 62
|
||||
#define TK_ALTER 63
|
||||
#define TK_OR 64
|
||||
#define TK_AND 65
|
||||
#define TK_NOT 66
|
||||
#define TK_IS 67
|
||||
#define TK_BETWEEN 68
|
||||
#define TK_IN 69
|
||||
#define TK_ISNULL 70
|
||||
#define TK_NOTNULL 71
|
||||
#define TK_NE 72
|
||||
#define TK_EQ 73
|
||||
#define TK_GT 74
|
||||
#define TK_LE 75
|
||||
#define TK_LT 76
|
||||
#define TK_GE 77
|
||||
#define TK_ESCAPE 78
|
||||
#define TK_BITAND 79
|
||||
#define TK_BITOR 80
|
||||
#define TK_LSHIFT 81
|
||||
#define TK_RSHIFT 82
|
||||
#define TK_PLUS 83
|
||||
#define TK_MINUS 84
|
||||
#define TK_STAR 85
|
||||
#define TK_SLASH 86
|
||||
#define TK_REM 87
|
||||
#define TK_CONCAT 88
|
||||
#define TK_UMINUS 89
|
||||
#define TK_UPLUS 90
|
||||
#define TK_BITNOT 91
|
||||
#define TK_STRING 92
|
||||
#define TK_JOIN_KW 93
|
||||
#define TK_CONSTRAINT 94
|
||||
#define TK_DEFAULT 95
|
||||
#define TK_NULL 96
|
||||
#define TK_PRIMARY 97
|
||||
#define TK_UNIQUE 98
|
||||
#define TK_CHECK 99
|
||||
#define TK_REFERENCES 100
|
||||
#define TK_COLLATE 101
|
||||
#define TK_AUTOINCR 102
|
||||
#define TK_ON 103
|
||||
#define TK_DELETE 104
|
||||
#define TK_UPDATE 105
|
||||
#define TK_INSERT 106
|
||||
#define TK_SET 107
|
||||
#define TK_DEFERRABLE 108
|
||||
#define TK_FOREIGN 109
|
||||
#define TK_DROP 110
|
||||
#define TK_UNION 111
|
||||
#define TK_ALL 112
|
||||
#define TK_INTERSECT 113
|
||||
#define TK_EXCEPT 114
|
||||
#define TK_SELECT 115
|
||||
#define TK_DISTINCT 116
|
||||
#define TK_DOT 117
|
||||
#define TK_FROM 118
|
||||
#define TK_JOIN 119
|
||||
#define TK_USING 120
|
||||
#define TK_ORDER 121
|
||||
#define TK_BY 122
|
||||
#define TK_GROUP 123
|
||||
#define TK_HAVING 124
|
||||
#define TK_LIMIT 125
|
||||
#define TK_WHERE 126
|
||||
#define TK_INTO 127
|
||||
#define TK_VALUES 128
|
||||
#define TK_INTEGER 129
|
||||
#define TK_FLOAT 130
|
||||
#define TK_BLOB 131
|
||||
#define TK_REGISTER 132
|
||||
#define TK_VARIABLE 133
|
||||
#define TK_EXISTS 134
|
||||
#define TK_CASE 135
|
||||
#define TK_WHEN 136
|
||||
#define TK_THEN 137
|
||||
#define TK_ELSE 138
|
||||
#define TK_INDEX 139
|
||||
#define TK_TO 140
|
||||
#define TK_ADD 141
|
||||
#define TK_COLUMNKW 142
|
||||
|
|
|
@ -11,32 +11,21 @@
|
|||
*************************************************************************
|
||||
** This file contains code used to implement the PRAGMA command.
|
||||
**
|
||||
** $Id: pragma.c,v 1.70 2004/10/06 15:41:17 drh Exp $
|
||||
** $Id: pragma.c,v 1.90 2005/02/26 18:10:44 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include "os.h"
|
||||
#include <ctype.h>
|
||||
|
||||
/* Ignore this whole file if pragmas are disabled
|
||||
*/
|
||||
#ifndef SQLITE_OMIT_PRAGMA
|
||||
|
||||
#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
|
||||
# include "pager.h"
|
||||
# include "btree.h"
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Interpret the given string as a boolean value.
|
||||
*/
|
||||
static int getBoolean(const u8 *z){
|
||||
static const u8 *azTrue[] = { "yes", "on", "true" };
|
||||
int i;
|
||||
if( z[0]==0 ) return 0;
|
||||
if( sqlite3IsNumber(z, 0, SQLITE_UTF8) ){
|
||||
return atoi(z);
|
||||
}
|
||||
for(i=0; i<sizeof(azTrue)/sizeof(azTrue[0]); i++){
|
||||
if( sqlite3StrICmp(z,azTrue[i])==0 ) return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Interpret the given string as a safety level. Return 0 for OFF,
|
||||
** 1 for ON or NORMAL and 2 for FULL. Return 1 for an empty or
|
||||
|
@ -47,30 +36,33 @@ static int getBoolean(const u8 *z){
|
|||
** to support legacy SQL code. The safety level used to be boolean
|
||||
** and older scripts may have used numbers 0 for OFF and 1 for ON.
|
||||
*/
|
||||
static int getSafetyLevel(u8 *z){
|
||||
static const struct {
|
||||
const u8 *zWord;
|
||||
int val;
|
||||
} aKey[] = {
|
||||
{ "no", 0 },
|
||||
{ "off", 0 },
|
||||
{ "false", 0 },
|
||||
{ "yes", 1 },
|
||||
{ "on", 1 },
|
||||
{ "true", 1 },
|
||||
{ "full", 2 },
|
||||
};
|
||||
int i;
|
||||
if( z[0]==0 ) return 1;
|
||||
if( sqlite3IsNumber(z, 0, SQLITE_UTF8) ){
|
||||
static int getSafetyLevel(const u8 *z){
|
||||
/* 123456789 123456789 */
|
||||
static const char zText[] = "onoffalseyestruefull";
|
||||
static const u8 iOffset[] = {0, 1, 2, 4, 9, 12, 16};
|
||||
static const u8 iLength[] = {2, 2, 3, 5, 3, 4, 4};
|
||||
static const u8 iValue[] = {1, 0, 0, 0, 1, 1, 2};
|
||||
int i, n;
|
||||
if( isdigit(*z) ){
|
||||
return atoi(z);
|
||||
}
|
||||
for(i=0; i<sizeof(aKey)/sizeof(aKey[0]); i++){
|
||||
if( sqlite3StrICmp(z,aKey[i].zWord)==0 ) return aKey[i].val;
|
||||
n = strlen(z);
|
||||
for(i=0; i<sizeof(iLength); i++){
|
||||
if( iLength[i]==n && sqlite3StrNICmp(&zText[iOffset[i]],z,n)==0 ){
|
||||
return iValue[i];
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
** Interpret the given string as a boolean value.
|
||||
*/
|
||||
static int getBoolean(const u8 *z){
|
||||
return getSafetyLevel(z)&1;
|
||||
}
|
||||
|
||||
#ifndef SQLITE_OMIT_PAGER_PRAGMAS
|
||||
/*
|
||||
** Interpret the given string as a temp db location. Return 1 for file
|
||||
** backed temporary databases, 2 for the Red-Black tree in memory database
|
||||
|
@ -87,16 +79,15 @@ static int getTempStore(const char *z){
|
|||
return 0;
|
||||
}
|
||||
}
|
||||
#endif /* SQLITE_PAGER_PRAGMAS */
|
||||
|
||||
#ifndef SQLITE_OMIT_PAGER_PRAGMAS
|
||||
/*
|
||||
** If the TEMP database is open, close it and mark the database schema
|
||||
** as needing reloading. This must be done when using the TEMP_STORE
|
||||
** or DEFAULT_TEMP_STORE pragmas.
|
||||
** Invalidate temp storage, either when the temp storage is changed
|
||||
** from default, or when 'file' and the temp_store_directory has changed
|
||||
*/
|
||||
static int changeTempStorage(Parse *pParse, const char *zStorageType){
|
||||
int ts = getTempStore(zStorageType);
|
||||
static int invalidateTempStorage(Parse *pParse){
|
||||
sqlite3 *db = pParse->db;
|
||||
if( db->temp_store==ts ) return SQLITE_OK;
|
||||
if( db->aDb[1].pBt!=0 ){
|
||||
if( db->flags & SQLITE_InTrans ){
|
||||
sqlite3ErrorMsg(pParse, "temporary storage cannot be changed "
|
||||
|
@ -107,9 +98,27 @@ static int changeTempStorage(Parse *pParse, const char *zStorageType){
|
|||
db->aDb[1].pBt = 0;
|
||||
sqlite3ResetInternalSchema(db, 0);
|
||||
}
|
||||
return SQLITE_OK;
|
||||
}
|
||||
#endif /* SQLITE_PAGER_PRAGMAS */
|
||||
|
||||
#ifndef SQLITE_OMIT_PAGER_PRAGMAS
|
||||
/*
|
||||
** If the TEMP database is open, close it and mark the database schema
|
||||
** as needing reloading. This must be done when using the TEMP_STORE
|
||||
** or DEFAULT_TEMP_STORE pragmas.
|
||||
*/
|
||||
static int changeTempStorage(Parse *pParse, const char *zStorageType){
|
||||
int ts = getTempStore(zStorageType);
|
||||
sqlite3 *db = pParse->db;
|
||||
if( db->temp_store==ts ) return SQLITE_OK;
|
||||
if( invalidateTempStorage( pParse ) != SQLITE_OK ){
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
db->temp_store = ts;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
#endif /* SQLITE_PAGER_PRAGMAS */
|
||||
|
||||
/*
|
||||
** Generate code to return a single integer value.
|
||||
|
@ -124,47 +133,56 @@ static void returnSingleInt(Parse *pParse, const char *zLabel, int value){
|
|||
sqlite3VdbeAddOp(v, OP_Callback, 1, 0);
|
||||
}
|
||||
|
||||
#ifndef SQLITE_OMIT_FLAG_PRAGMAS
|
||||
/*
|
||||
** Check to see if zRight and zLeft refer to a pragma that queries
|
||||
** or changes one of the flags in db->flags. Return 1 if so and 0 if not.
|
||||
** Also, implement the pragma.
|
||||
*/
|
||||
static int flagPragma(Parse *pParse, const char *zLeft, const char *zRight){
|
||||
static const struct {
|
||||
static const struct sPragmaType {
|
||||
const char *zName; /* Name of the pragma */
|
||||
int mask; /* Mask for the db->flags value */
|
||||
} aPragma[] = {
|
||||
{ "vdbe_trace", SQLITE_VdbeTrace },
|
||||
{ "sql_trace", SQLITE_SqlTrace },
|
||||
{ "vdbe_listing", SQLITE_VdbeListing },
|
||||
#if 1 /* FIX ME: Remove the following pragmas */
|
||||
{ "full_column_names", SQLITE_FullColNames },
|
||||
{ "short_column_names", SQLITE_ShortColNames },
|
||||
{ "count_changes", SQLITE_CountRows },
|
||||
{ "empty_result_callbacks", SQLITE_NullCallback },
|
||||
#endif
|
||||
/* The following is VERY experimental */
|
||||
{ "writable_schema", SQLITE_WriteSchema },
|
||||
{ "omit_readlock", SQLITE_NoReadlock },
|
||||
};
|
||||
int i;
|
||||
for(i=0; i<sizeof(aPragma)/sizeof(aPragma[0]); i++){
|
||||
if( sqlite3StrICmp(zLeft, aPragma[i].zName)==0 ){
|
||||
const struct sPragmaType *p;
|
||||
for(i=0, p=aPragma; i<sizeof(aPragma)/sizeof(aPragma[0]); i++, p++){
|
||||
if( sqlite3StrICmp(zLeft, p->zName)==0 ){
|
||||
sqlite3 *db = pParse->db;
|
||||
Vdbe *v;
|
||||
if( zRight==0 ){
|
||||
v = sqlite3GetVdbe(pParse);
|
||||
if( v ){
|
||||
returnSingleInt(pParse,
|
||||
aPragma[i].zName, (db->flags&aPragma[i].mask)!=0);
|
||||
v = sqlite3GetVdbe(pParse);
|
||||
if( v ){
|
||||
if( zRight==0 ){
|
||||
returnSingleInt(pParse, p->zName, (db->flags & p->mask)!=0 );
|
||||
}else{
|
||||
if( getBoolean(zRight) ){
|
||||
db->flags |= p->mask;
|
||||
}else{
|
||||
db->flags &= ~p->mask;
|
||||
}
|
||||
}
|
||||
}else if( getBoolean(zRight) ){
|
||||
db->flags |= aPragma[i].mask;
|
||||
}else{
|
||||
db->flags &= ~aPragma[i].mask;
|
||||
/* If one of these pragmas is executed, any prepared statements
|
||||
** need to be recompiled.
|
||||
*/
|
||||
sqlite3VdbeAddOp(v, OP_Expire, 0, 0);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif /* SQLITE_OMIT_FLAG_PRAGMAS */
|
||||
|
||||
/*
|
||||
** Process a pragma statement.
|
||||
|
@ -217,6 +235,7 @@ void sqlite3Pragma(
|
|||
goto pragma_out;
|
||||
}
|
||||
|
||||
#ifndef SQLITE_OMIT_PAGER_PRAGMAS
|
||||
/*
|
||||
** PRAGMA [database.]default_cache_size
|
||||
** PRAGMA [database.]default_cache_size=N
|
||||
|
@ -281,10 +300,31 @@ void sqlite3Pragma(
|
|||
int size = pBt ? sqlite3BtreeGetPageSize(pBt) : 0;
|
||||
returnSingleInt(pParse, "page_size", size);
|
||||
}else{
|
||||
sqlite3BtreeSetPageSize(pBt, atoi(zRight), sqlite3BtreeGetReserve(pBt));
|
||||
sqlite3BtreeSetPageSize(pBt, atoi(zRight), -1);
|
||||
}
|
||||
}else
|
||||
#endif /* SQLITE_OMIT_PAGER_PRAGMAS */
|
||||
|
||||
/*
|
||||
** PRAGMA [database.]auto_vacuum
|
||||
** PRAGMA [database.]auto_vacuum=N
|
||||
**
|
||||
** Get or set the (boolean) value of the database 'auto-vacuum' parameter.
|
||||
*/
|
||||
#ifndef SQLITE_OMIT_AUTOVACUUM
|
||||
if( sqlite3StrICmp(zLeft,"auto_vacuum")==0 ){
|
||||
Btree *pBt = pDb->pBt;
|
||||
if( !zRight ){
|
||||
int auto_vacuum =
|
||||
pBt ? sqlite3BtreeGetAutoVacuum(pBt) : SQLITE_DEFAULT_AUTOVACUUM;
|
||||
returnSingleInt(pParse, "auto_vacuum", auto_vacuum);
|
||||
}else{
|
||||
sqlite3BtreeSetAutoVacuum(pBt, getBoolean(zRight));
|
||||
}
|
||||
}else
|
||||
#endif
|
||||
|
||||
#ifndef SQLITE_OMIT_PAGER_PRAGMAS
|
||||
/*
|
||||
** PRAGMA [database.]cache_size
|
||||
** PRAGMA [database.]cache_size=N
|
||||
|
@ -330,6 +370,45 @@ void sqlite3Pragma(
|
|||
}
|
||||
}else
|
||||
|
||||
/*
|
||||
** PRAGMA temp_store_directory
|
||||
** PRAGMA temp_store_directory = ""|"directory_name"
|
||||
**
|
||||
** Return or set the local value of the temp_store_directory flag. Changing
|
||||
** the value sets a specific directory to be used for temporary files.
|
||||
** Setting to a null string reverts to the default temporary directory search.
|
||||
** If temporary directory is changed, then invalidateTempStorage.
|
||||
**
|
||||
*/
|
||||
if( sqlite3StrICmp(zLeft, "temp_store_directory")==0 ){
|
||||
if( !zRight ){
|
||||
if( sqlite3_temp_directory ){
|
||||
sqlite3VdbeSetNumCols(v, 1);
|
||||
sqlite3VdbeSetColName(v, 0, "temp_store_directory", P3_STATIC);
|
||||
sqlite3VdbeOp3(v, OP_String8, 0, 0, sqlite3_temp_directory, 0);
|
||||
sqlite3VdbeAddOp(v, OP_Callback, 1, 0);
|
||||
}
|
||||
}else{
|
||||
if( zRight[0] && !sqlite3OsIsDirWritable(zRight) ){
|
||||
sqlite3ErrorMsg(pParse, "not a writable directory");
|
||||
goto pragma_out;
|
||||
}
|
||||
if( TEMP_STORE==0
|
||||
|| (TEMP_STORE==1 && db->temp_store<=1)
|
||||
|| (TEMP_STORE==2 && db->temp_store==1)
|
||||
){
|
||||
invalidateTempStorage(pParse);
|
||||
}
|
||||
sqliteFree(sqlite3_temp_directory);
|
||||
if( zRight[0] ){
|
||||
sqlite3_temp_directory = zRight;
|
||||
zRight = 0;
|
||||
}else{
|
||||
sqlite3_temp_directory = 0;
|
||||
}
|
||||
}
|
||||
}else
|
||||
|
||||
/*
|
||||
** PRAGMA [database.]synchronous
|
||||
** PRAGMA [database.]synchronous=OFF|ON|NORMAL|FULL
|
||||
|
@ -353,22 +432,16 @@ void sqlite3Pragma(
|
|||
}
|
||||
}
|
||||
}else
|
||||
#endif /* SQLITE_OMIT_PAGER_PRAGMAS */
|
||||
|
||||
#if 0 /* Used once during development. No longer needed */
|
||||
if( sqlite3StrICmp(zLeft, "trigger_overhead_test")==0 ){
|
||||
if( getBoolean(zRight) ){
|
||||
sqlite3_always_code_trigger_setup = 1;
|
||||
}else{
|
||||
sqlite3_always_code_trigger_setup = 0;
|
||||
}
|
||||
}else
|
||||
#endif
|
||||
|
||||
#ifndef SQLITE_OMIT_FLAG_PRAGMAS
|
||||
if( flagPragma(pParse, zLeft, zRight) ){
|
||||
/* The flagPragma() subroutine also generates any necessary code
|
||||
** there is nothing more to do here */
|
||||
}else
|
||||
#endif /* SQLITE_OMIT_FLAG_PRAGMAS */
|
||||
|
||||
#ifndef SQLITE_OMIT_SCHEMA_PRAGMAS
|
||||
/*
|
||||
** PRAGMA table_info(<table>)
|
||||
**
|
||||
|
@ -401,8 +474,7 @@ void sqlite3Pragma(
|
|||
sqlite3VdbeOp3(v, OP_String8, 0, 0,
|
||||
pTab->aCol[i].zType ? pTab->aCol[i].zType : "numeric", 0);
|
||||
sqlite3VdbeAddOp(v, OP_Integer, pTab->aCol[i].notNull, 0);
|
||||
sqlite3VdbeOp3(v, OP_String8, 0, 0,
|
||||
pTab->aCol[i].zDflt, P3_STATIC);
|
||||
sqlite3ExprCode(pParse, pTab->aCol[i].pDflt);
|
||||
sqlite3VdbeAddOp(v, OP_Integer, pTab->aCol[i].isPrimKey, 0);
|
||||
sqlite3VdbeAddOp(v, OP_Callback, 6, 0);
|
||||
}
|
||||
|
@ -458,6 +530,40 @@ void sqlite3Pragma(
|
|||
}
|
||||
}else
|
||||
|
||||
if( sqlite3StrICmp(zLeft, "database_list")==0 ){
|
||||
int i;
|
||||
if( sqlite3ReadSchema(pParse) ) goto pragma_out;
|
||||
sqlite3VdbeSetNumCols(v, 3);
|
||||
sqlite3VdbeSetColName(v, 0, "seq", P3_STATIC);
|
||||
sqlite3VdbeSetColName(v, 1, "name", P3_STATIC);
|
||||
sqlite3VdbeSetColName(v, 2, "file", P3_STATIC);
|
||||
for(i=0; i<db->nDb; i++){
|
||||
if( db->aDb[i].pBt==0 ) continue;
|
||||
assert( db->aDb[i].zName!=0 );
|
||||
sqlite3VdbeAddOp(v, OP_Integer, i, 0);
|
||||
sqlite3VdbeOp3(v, OP_String8, 0, 0, db->aDb[i].zName, 0);
|
||||
sqlite3VdbeOp3(v, OP_String8, 0, 0,
|
||||
sqlite3BtreeGetFilename(db->aDb[i].pBt), 0);
|
||||
sqlite3VdbeAddOp(v, OP_Callback, 3, 0);
|
||||
}
|
||||
}else
|
||||
|
||||
if( sqlite3StrICmp(zLeft, "collation_list")==0 ){
|
||||
int i = 0;
|
||||
HashElem *p;
|
||||
sqlite3VdbeSetNumCols(v, 2);
|
||||
sqlite3VdbeSetColName(v, 0, "seq", P3_STATIC);
|
||||
sqlite3VdbeSetColName(v, 1, "name", P3_STATIC);
|
||||
for(p=sqliteHashFirst(&db->aCollSeq); p; p=sqliteHashNext(p)){
|
||||
CollSeq *pColl = (CollSeq *)sqliteHashData(p);
|
||||
sqlite3VdbeAddOp(v, OP_Integer, i++, 0);
|
||||
sqlite3VdbeOp3(v, OP_String8, 0, 0, pColl->zName, 0);
|
||||
sqlite3VdbeAddOp(v, OP_Callback, 2, 0);
|
||||
}
|
||||
}else
|
||||
#endif /* SQLITE_OMIT_SCHEMA_PRAGMAS */
|
||||
|
||||
#ifndef SQLITE_OMIT_FOREIGN_KEY
|
||||
if( sqlite3StrICmp(zLeft, "foreign_key_list")==0 && zRight ){
|
||||
FKey *pFK;
|
||||
Table *pTab;
|
||||
|
@ -491,24 +597,7 @@ void sqlite3Pragma(
|
|||
}
|
||||
}
|
||||
}else
|
||||
|
||||
if( sqlite3StrICmp(zLeft, "database_list")==0 ){
|
||||
int i;
|
||||
if( sqlite3ReadSchema(pParse) ) goto pragma_out;
|
||||
sqlite3VdbeSetNumCols(v, 3);
|
||||
sqlite3VdbeSetColName(v, 0, "seq", P3_STATIC);
|
||||
sqlite3VdbeSetColName(v, 1, "name", P3_STATIC);
|
||||
sqlite3VdbeSetColName(v, 2, "file", P3_STATIC);
|
||||
for(i=0; i<db->nDb; i++){
|
||||
if( db->aDb[i].pBt==0 ) continue;
|
||||
assert( db->aDb[i].zName!=0 );
|
||||
sqlite3VdbeAddOp(v, OP_Integer, i, 0);
|
||||
sqlite3VdbeOp3(v, OP_String8, 0, 0, db->aDb[i].zName, 0);
|
||||
sqlite3VdbeOp3(v, OP_String8, 0, 0,
|
||||
sqlite3BtreeGetFilename(db->aDb[i].pBt), 0);
|
||||
sqlite3VdbeAddOp(v, OP_Callback, 3, 0);
|
||||
}
|
||||
}else
|
||||
#endif /* !defined(SQLITE_OMIT_FOREIGN_KEY) */
|
||||
|
||||
#ifndef NDEBUG
|
||||
if( sqlite3StrICmp(zLeft, "parser_trace")==0 ){
|
||||
|
@ -521,6 +610,7 @@ void sqlite3Pragma(
|
|||
}else
|
||||
#endif
|
||||
|
||||
#ifndef SQLITE_OMIT_INTEGRITY_CHECK
|
||||
if( sqlite3StrICmp(zLeft, "integrity_check")==0 ){
|
||||
int i, j, addr;
|
||||
|
||||
|
@ -645,6 +735,9 @@ void sqlite3Pragma(
|
|||
addr = sqlite3VdbeAddOpList(v, ArraySize(endCode), endCode);
|
||||
sqlite3VdbeChangeP2(v, addr+2, addr+ArraySize(endCode));
|
||||
}else
|
||||
#endif /* SQLITE_OMIT_INTEGRITY_CHECK */
|
||||
|
||||
#ifndef SQLITE_OMIT_UTF16
|
||||
/*
|
||||
** PRAGMA encoding
|
||||
** PRAGMA encoding = "utf-8"|"utf-16"|"utf-16le"|"utf-16be"
|
||||
|
@ -715,6 +808,69 @@ void sqlite3Pragma(
|
|||
}
|
||||
}
|
||||
}else
|
||||
#endif /* SQLITE_OMIT_UTF16 */
|
||||
|
||||
#ifndef SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS
|
||||
/*
|
||||
** PRAGMA [database.]schema_version
|
||||
** PRAGMA [database.]schema_version = <integer>
|
||||
**
|
||||
** PRAGMA [database.]user_version
|
||||
** PRAGMA [database.]user_version = <integer>
|
||||
**
|
||||
** The pragma's schema_version and user_version are used to set or get
|
||||
** the value of the schema-version and user-version, respectively. Both
|
||||
** the schema-version and the user-version are 32-bit signed integers
|
||||
** stored in the database header.
|
||||
**
|
||||
** The schema-cookie is usually only manipulated internally by SQLite. It
|
||||
** is incremented by SQLite whenever the database schema is modified (by
|
||||
** creating or dropping a table or index). The schema version is used by
|
||||
** SQLite each time a query is executed to ensure that the internal cache
|
||||
** of the schema used when compiling the SQL query matches the schema of
|
||||
** the database against which the compiled query is actually executed.
|
||||
** Subverting this mechanism by using "PRAGMA schema_version" to modify
|
||||
** the schema-version is potentially dangerous and may lead to program
|
||||
** crashes or database corruption. Use with caution!
|
||||
**
|
||||
** The user-version is not used internally by SQLite. It may be used by
|
||||
** applications for any purpose.
|
||||
*/
|
||||
if( sqlite3StrICmp(zLeft, "schema_version")==0 ||
|
||||
sqlite3StrICmp(zLeft, "user_version")==0 ){
|
||||
|
||||
int iCookie; /* Cookie index. 0 for schema-cookie, 6 for user-cookie. */
|
||||
if( zLeft[0]=='s' || zLeft[0]=='S' ){
|
||||
iCookie = 0;
|
||||
}else{
|
||||
iCookie = 5;
|
||||
}
|
||||
|
||||
if( zRight ){
|
||||
/* Write the specified cookie value */
|
||||
static const VdbeOpList setCookie[] = {
|
||||
{ OP_Transaction, 0, 1, 0}, /* 0 */
|
||||
{ OP_Integer, 0, 0, 0}, /* 1 */
|
||||
{ OP_SetCookie, 0, 0, 0}, /* 2 */
|
||||
};
|
||||
int addr = sqlite3VdbeAddOpList(v, ArraySize(setCookie), setCookie);
|
||||
sqlite3VdbeChangeP1(v, addr, iDb);
|
||||
sqlite3VdbeChangeP1(v, addr+1, atoi(zRight));
|
||||
sqlite3VdbeChangeP1(v, addr+2, iDb);
|
||||
sqlite3VdbeChangeP2(v, addr+2, iCookie);
|
||||
}else{
|
||||
/* Read the specified cookie value */
|
||||
static const VdbeOpList readCookie[] = {
|
||||
{ OP_ReadCookie, 0, 0, 0}, /* 0 */
|
||||
{ OP_Callback, 1, 0, 0}
|
||||
};
|
||||
int addr = sqlite3VdbeAddOpList(v, ArraySize(readCookie), readCookie);
|
||||
sqlite3VdbeChangeP1(v, addr, iDb);
|
||||
sqlite3VdbeChangeP2(v, addr, iCookie);
|
||||
sqlite3VdbeSetNumCols(v, 1);
|
||||
}
|
||||
}
|
||||
#endif /* SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS */
|
||||
|
||||
#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
|
||||
/*
|
||||
|
@ -748,7 +904,17 @@ void sqlite3Pragma(
|
|||
#endif
|
||||
|
||||
{}
|
||||
|
||||
if( v ){
|
||||
/* Code an OP_Expire at the end of each PRAGMA program to cause
|
||||
** the VDBE implementing the pragma to expire. Most (all?) pragmas
|
||||
** are only valid for a single execution.
|
||||
*/
|
||||
sqlite3VdbeAddOp(v, OP_Expire, 1, 0);
|
||||
}
|
||||
pragma_out:
|
||||
sqliteFree(zLeft);
|
||||
sqliteFree(zRight);
|
||||
}
|
||||
|
||||
#endif /* SQLITE_OMIT_PRAGMA */
|
||||
|
|
|
@ -99,6 +99,7 @@ typedef struct et_info { /* Information about each format field */
|
|||
*/
|
||||
#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 */
|
||||
|
||||
|
||||
/*
|
||||
|
@ -109,10 +110,10 @@ static const char aDigits[] = "0123456789ABCDEF0123456789abcdef";
|
|||
static const char aPrefix[] = "-x0\000X0";
|
||||
static const et_info fmtinfo[] = {
|
||||
{ 'd', 10, 1, etRADIX, 0, 0 },
|
||||
{ 's', 0, 0, etSTRING, 0, 0 },
|
||||
{ 'z', 0, 2, etDYNSTRING, 0, 0 },
|
||||
{ 'q', 0, 0, etSQLESCAPE, 0, 0 },
|
||||
{ 'Q', 0, 0, etSQLESCAPE2, 0, 0 },
|
||||
{ 's', 0, 4, etSTRING, 0, 0 },
|
||||
{ 'z', 0, 6, etDYNSTRING, 0, 0 },
|
||||
{ 'q', 0, 4, etSQLESCAPE, 0, 0 },
|
||||
{ 'Q', 0, 4, etSQLESCAPE2, 0, 0 },
|
||||
{ 'c', 0, 0, etCHARX, 0, 0 },
|
||||
{ 'o', 8, 0, etRADIX, 0, 2 },
|
||||
{ 'u', 10, 0, etRADIX, 0, 0 },
|
||||
|
@ -296,8 +297,6 @@ static int vxprintf(
|
|||
c = *++fmt;
|
||||
}
|
||||
}
|
||||
/* Limit the precision to prevent overflowing buf[] during conversion */
|
||||
if( precision>etBUFSIZE-40 ) precision = etBUFSIZE-40;
|
||||
}else{
|
||||
precision = -1;
|
||||
}
|
||||
|
@ -328,6 +327,11 @@ static int vxprintf(
|
|||
}
|
||||
zExtra = 0;
|
||||
|
||||
/* 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:
|
||||
**
|
||||
|
@ -563,13 +567,15 @@ static int vxprintf(
|
|||
case etSQLESCAPE2:
|
||||
{
|
||||
int i, j, n, c, isnull;
|
||||
int needQuote;
|
||||
char *arg = va_arg(ap,char*);
|
||||
isnull = arg==0;
|
||||
if( isnull ) arg = (xtype==etSQLESCAPE2 ? "NULL" : "(NULL)");
|
||||
for(i=n=0; (c=arg[i])!=0; i++){
|
||||
if( c=='\'' ) n++;
|
||||
}
|
||||
n += i + 1 + ((!isnull && xtype==etSQLESCAPE2) ? 2 : 0);
|
||||
needQuote = !isnull && xtype==etSQLESCAPE2;
|
||||
n += i + 1 + needQuote*2;
|
||||
if( n>etBUFSIZE ){
|
||||
bufpt = zExtra = sqliteMalloc( n );
|
||||
if( bufpt==0 ) return -1;
|
||||
|
@ -577,12 +583,12 @@ static int vxprintf(
|
|||
bufpt = buf;
|
||||
}
|
||||
j = 0;
|
||||
if( !isnull && xtype==etSQLESCAPE2 ) bufpt[j++] = '\'';
|
||||
if( needQuote ) bufpt[j++] = '\'';
|
||||
for(i=0; (c=arg[i])!=0; i++){
|
||||
bufpt[j++] = c;
|
||||
if( c=='\'' ) bufpt[j++] = c;
|
||||
}
|
||||
if( !isnull && xtype==etSQLESCAPE2 ) bufpt[j++] = '\'';
|
||||
if( needQuote ) bufpt[j++] = '\'';
|
||||
bufpt[j] = 0;
|
||||
length = j;
|
||||
if( precision>=0 && precision<length ) length = precision;
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -12,7 +12,7 @@
|
|||
** This file contains code to implement the "sqlite" command line
|
||||
** utility for accessing SQLite databases.
|
||||
**
|
||||
** $Id: shell.c,v 1.116 2004/10/07 00:32:40 drh Exp $
|
||||
** $Id: shell.c,v 1.122 2005/02/23 12:35:41 drh Exp $
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
@ -196,7 +196,9 @@ static char *one_input_line(const char *zPrior, FILE *in){
|
|||
zPrompt = mainPrompt;
|
||||
}
|
||||
zResult = readline(zPrompt);
|
||||
#if defined(HAVE_READLINE) && HAVE_READLINE==1
|
||||
if( zResult ) add_history(zResult);
|
||||
#endif
|
||||
return zResult;
|
||||
}
|
||||
|
||||
|
@ -360,6 +362,7 @@ static void output_csv(struct callback_data *p, const char *z, int bSep){
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef SIGINT
|
||||
/*
|
||||
** This routine runs when the user presses Ctrl-C
|
||||
*/
|
||||
|
@ -367,6 +370,7 @@ static void interrupt_handler(int NotUsed){
|
|||
seenInterrupt = 1;
|
||||
if( db ) sqlite3_interrupt(db);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
** This is the callback routine that the SQLite library
|
||||
|
@ -652,7 +656,11 @@ static int dump_callback(void *pArg, int nArg, char **azArg, char **azCol){
|
|||
zType = azArg[1];
|
||||
zSql = azArg[2];
|
||||
|
||||
fprintf(p->out, "%s;\n", zSql);
|
||||
if( strcmp(zTable,"sqlite_sequence")!=0 ){
|
||||
fprintf(p->out, "%s;\n", zSql);
|
||||
}else{
|
||||
fprintf(p->out, "DELETE FROM sqlite_sequence;\n");
|
||||
}
|
||||
|
||||
if( strcmp(zType, "table")==0 ){
|
||||
sqlite3_stmt *pTableInfo = 0;
|
||||
|
@ -746,7 +754,7 @@ static char zHelp[] =
|
|||
".help Show this message\n"
|
||||
".import FILE TABLE Import data from FILE into TABLE\n"
|
||||
".indices TABLE Show names of all indices on TABLE\n"
|
||||
".mode MODE ?TABLE? Set output mode where MODE is on of:\n"
|
||||
".mode MODE ?TABLE? Set output mode where MODE is one of:\n"
|
||||
" csv Comma-separated values\n"
|
||||
" column Left-aligned columns. (See .width)\n"
|
||||
" html HTML <table> code\n"
|
||||
|
@ -882,6 +890,7 @@ static int do_meta_command(char *zLine, struct callback_data *p){
|
|||
data.colWidth[0] = 3;
|
||||
data.colWidth[1] = 15;
|
||||
data.colWidth[2] = 58;
|
||||
data.cnt = 0;
|
||||
sqlite3_exec(p->db, "PRAGMA database_list; ", callback, &data, &zErrMsg);
|
||||
if( zErrMsg ){
|
||||
fprintf(stderr,"Error: %s\n", zErrMsg);
|
||||
|
@ -1677,7 +1686,11 @@ int main(int argc, char **argv){
|
|||
if( i<argc ){
|
||||
data.zDbFilename = argv[i++];
|
||||
}else{
|
||||
#ifndef SQLITE_OMIT_MEMORYDB
|
||||
data.zDbFilename = ":memory:";
|
||||
#else
|
||||
data.zDbFilename = 0;
|
||||
#endif
|
||||
}
|
||||
if( i<argc ){
|
||||
zFirstCmd = argv[i++];
|
||||
|
@ -1770,7 +1783,9 @@ int main(int argc, char **argv){
|
|||
if( zHome && (zHistory = malloc(strlen(zHome)+20))!=0 ){
|
||||
sprintf(zHistory,"%s/.sqlite_history", zHome);
|
||||
}
|
||||
#if defined(HAVE_READLINE) && HAVE_READLINE==1
|
||||
if( zHistory ) read_history(zHistory);
|
||||
#endif
|
||||
process_input(&data, 0);
|
||||
if( zHistory ){
|
||||
stifle_history(100);
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
** This header file defines the interface that the SQLite library
|
||||
** presents to client programs.
|
||||
**
|
||||
** @(#) $Id: sqlite.h.in,v 1.121 2004/10/06 15:52:01 drh Exp $
|
||||
** @(#) $Id: sqlite.h.in,v 1.131 2005/03/21 04:04:03 danielk1977 Exp $
|
||||
*/
|
||||
#ifndef _SQLITE3_H_
|
||||
#define _SQLITE3_H_
|
||||
|
@ -30,9 +30,25 @@ extern "C" {
|
|||
*/
|
||||
#ifdef SQLITE_VERSION
|
||||
# undef SQLITE_VERSION
|
||||
#else
|
||||
# define SQLITE_VERSION "--VERS--"
|
||||
#endif
|
||||
#define SQLITE_VERSION "--VERS--"
|
||||
|
||||
/*
|
||||
** The format of the version string is "X.Y.Z<trailing string>", where
|
||||
** X is the major version number, Y is the minor version number and Z
|
||||
** is the release number. The trailing string is often "alpha" or "beta".
|
||||
** For example "3.1.1beta".
|
||||
**
|
||||
** The SQLITE_VERSION_NUMBER is an integer with the value
|
||||
** (X*100000 + Y*1000 + Z). For example, for version "3.1.1beta",
|
||||
** SQLITE_VERSION_NUMBER is set to 3001001. To detect if they are using
|
||||
** version 3.1.1 or greater at compile time, programs may use the test
|
||||
** (SQLITE_VERSION_NUMBER>=3001001).
|
||||
*/
|
||||
#ifdef SQLITE_VERSION_NUMBER
|
||||
# undef SQLITE_VERSION_NUMBER
|
||||
#endif
|
||||
#define SQLITE_VERSION_NUMBER 3002000
|
||||
|
||||
/*
|
||||
** The version string is also compiled into the library so that a program
|
||||
|
@ -44,6 +60,12 @@ extern "C" {
|
|||
extern const char sqlite3_version[];
|
||||
const char *sqlite3_libversion(void);
|
||||
|
||||
/*
|
||||
** Return the value of the SQLITE_VERSION_NUMBER macro when the
|
||||
** library was compiled.
|
||||
*/
|
||||
int sqlite3_libversion_number(void);
|
||||
|
||||
/*
|
||||
** Each open sqlite database is represented by an instance of the
|
||||
** following opaque structure.
|
||||
|
@ -309,7 +331,7 @@ int sqlite3_busy_timeout(sqlite3*, int ms);
|
|||
** pass the result data pointer to sqlite3_free_table() in order to
|
||||
** release the memory that was malloc-ed. Because of the way the
|
||||
** malloc() happens, the calling function must not try to call
|
||||
** malloc() directly. Only sqlite3_free_table() is able to release
|
||||
** free() directly. Only sqlite3_free_table() is able to release
|
||||
** the memory properly and safely.
|
||||
**
|
||||
** The return value of this routine is the same as from sqlite3_exec().
|
||||
|
@ -428,6 +450,8 @@ int sqlite3_set_authorizer(
|
|||
#define SQLITE_UPDATE 23 /* Table Name Column Name */
|
||||
#define SQLITE_ATTACH 24 /* Filename NULL */
|
||||
#define SQLITE_DETACH 25 /* Database Name NULL */
|
||||
#define SQLITE_ALTER_TABLE 26 /* Database Name Table Name */
|
||||
#define SQLITE_REINDEX 27 /* Index Name NULL */
|
||||
|
||||
|
||||
/*
|
||||
|
@ -448,8 +472,8 @@ void *sqlite3_trace(sqlite3*, void(*xTrace)(void*,const char*), void*);
|
|||
/*
|
||||
** This routine configures a callback function - the progress callback - that
|
||||
** is invoked periodically during long running calls to sqlite3_exec(),
|
||||
** sqlite3_step() and sqlite3_get_table(). An example use for this API is to keep
|
||||
** a GUI updated during a large query.
|
||||
** sqlite3_step() and sqlite3_get_table(). An example use for this API is to
|
||||
** keep a GUI updated during a large query.
|
||||
**
|
||||
** The progress callback is invoked once for every N virtual machine opcodes,
|
||||
** where N is the second argument to this function. The progress callback
|
||||
|
@ -606,14 +630,19 @@ typedef struct Mem sqlite3_value;
|
|||
|
||||
/*
|
||||
** In the SQL strings input to sqlite3_prepare() and sqlite3_prepare16(),
|
||||
** one or more literals can be replace by a wildcard "?" or ":N:" where
|
||||
** N is an integer. These value of these wildcard literals can be set
|
||||
** using the routines listed below.
|
||||
** one or more literals can be replace by parameters "?" or ":AAA" or
|
||||
** "$VVV" where AAA is an identifer and VVV is a variable name according
|
||||
** to the syntax rules of the TCL programming language.
|
||||
** The value of these parameters (also called "host parameter names") can
|
||||
** be set using the routines listed below.
|
||||
**
|
||||
** In every case, the first parameter is a pointer to the sqlite3_stmt
|
||||
** structure returned from sqlite3_prepare(). The second parameter is the
|
||||
** index of the wildcard. The first "?" has an index of 1. ":N:" wildcards
|
||||
** use the index N.
|
||||
** index of the parameter. The first parameter as an index of 1. For
|
||||
** named parameters (":AAA" or "$VVV") you can use
|
||||
** sqlite3_bind_parameter_index() to get the correct index value given
|
||||
** the parameters name. If the same named parameter occurs more than
|
||||
** once, it is assigned the same index each time.
|
||||
**
|
||||
** The fifth parameter to sqlite3_bind_blob(), sqlite3_bind_text(), and
|
||||
** sqlite3_bind_text16() is a destructor used to dispose of the BLOB or
|
||||
|
@ -624,8 +653,8 @@ typedef struct Mem sqlite3_value;
|
|||
** own private copy of the data.
|
||||
**
|
||||
** The sqlite3_bind_* routine must be called before sqlite3_step() after
|
||||
** an sqlite3_prepare() or sqlite3_reset(). Unbound wildcards are interpreted
|
||||
** as NULL.
|
||||
** an sqlite3_prepare() or sqlite3_reset(). Unbound parameterss are
|
||||
** interpreted as NULL.
|
||||
*/
|
||||
int sqlite3_bind_blob(sqlite3_stmt*, int, const void*, int n, void(*)(void*));
|
||||
int sqlite3_bind_double(sqlite3_stmt*, int, double);
|
||||
|
@ -637,16 +666,16 @@ int sqlite3_bind_text16(sqlite3_stmt*, int, const void*, int, void(*)(void*));
|
|||
int sqlite3_bind_value(sqlite3_stmt*, int, const sqlite3_value*);
|
||||
|
||||
/*
|
||||
** Return the number of wildcards in a compiled SQL statement. This
|
||||
** Return the number of parameters in a compiled SQL statement. This
|
||||
** routine was added to support DBD::SQLite.
|
||||
*/
|
||||
int sqlite3_bind_parameter_count(sqlite3_stmt*);
|
||||
|
||||
/*
|
||||
** Return the name of the i-th parameter. Ordinary wildcards "?" are
|
||||
** nameless and a NULL is returned. For wildcards of the form :N or
|
||||
** $vvvv the complete text of the wildcard is returned.
|
||||
** NULL is returned if the index is out of range.
|
||||
** Return the name of the i-th parameter. Ordinary parameters "?" are
|
||||
** nameless and a NULL is returned. For parameters of the form :AAA or
|
||||
** $VVV the complete text of the parameter name is returned, including
|
||||
** the initial ":" or "$". NULL is returned if the index is out of range.
|
||||
*/
|
||||
const char *sqlite3_bind_parameter_name(sqlite3_stmt*, int);
|
||||
|
||||
|
@ -657,6 +686,13 @@ const char *sqlite3_bind_parameter_name(sqlite3_stmt*, int);
|
|||
*/
|
||||
int sqlite3_bind_parameter_index(sqlite3_stmt*, const char *zName);
|
||||
|
||||
/*
|
||||
** Set all the parameters in the compiled SQL statement to NULL.
|
||||
**
|
||||
******* THIS IS AN EXPERIMENTAL API AND IS SUBJECT TO CHANGE ******
|
||||
*/
|
||||
int sqlite3_clear_bindings(sqlite3_stmt*);
|
||||
|
||||
/*
|
||||
** Return the number of columns in the result set returned by the compiled
|
||||
** SQL statement. This routine returns 0 if pStmt is an SQL statement
|
||||
|
@ -1148,17 +1184,62 @@ int sqlite3_rekey(
|
|||
);
|
||||
|
||||
/*
|
||||
** If the following global variable is made to point to a constant
|
||||
** Sleep for a little while. The second parameter is the number of
|
||||
** miliseconds to sleep for.
|
||||
**
|
||||
** If the operating system does not support sleep requests with
|
||||
** milisecond time resolution, then the time will be rounded up to
|
||||
** the nearest second. The number of miliseconds of sleep actually
|
||||
** requested from the operating system is returned.
|
||||
**
|
||||
******* THIS IS AN EXPERIMENTAL API AND IS SUBJECT TO CHANGE ******
|
||||
*/
|
||||
int sqlite3_sleep(int);
|
||||
|
||||
/*
|
||||
** Return TRUE (non-zero) of the statement supplied as an argument needs
|
||||
** to be recompiled. A statement needs to be recompiled whenever the
|
||||
** execution environment changes in a way that would alter the program
|
||||
** that sqlite3_prepare() generates. For example, if new functions or
|
||||
** collating sequences are registered or if an authorizer function is
|
||||
** added or changed.
|
||||
**
|
||||
******* THIS IS AN EXPERIMENTAL API AND IS SUBJECT TO CHANGE ******
|
||||
*/
|
||||
int sqlite3_expired(sqlite3_stmt*);
|
||||
|
||||
/*
|
||||
** If the following global variable is made to point to a
|
||||
** string which is the name of a directory, then all temporary files
|
||||
** created by SQLite will be placed in that directory. If this variable
|
||||
** is NULL pointer, then SQLite does a search for an appropriate temporary
|
||||
** file directory.
|
||||
**
|
||||
** This variable should only be changed when there are no open databases.
|
||||
** Once sqlite3_open() has been called, this variable should not be changed
|
||||
** until all database connections are closed.
|
||||
** Once sqlite3_open() has been called, changing this variable will invalidate
|
||||
** the current temporary database, if any.
|
||||
*/
|
||||
extern const char *sqlite3_temp_directory;
|
||||
extern char *sqlite3_temp_directory;
|
||||
|
||||
/*
|
||||
** This function is called to recover from a malloc() failure that occured
|
||||
** within the SQLite library. Normally, after a single malloc() fails the
|
||||
** library refuses to function (all major calls return SQLITE_NOMEM).
|
||||
** This function library state so that it can be used again.
|
||||
**
|
||||
** All existing statements (sqlite3_stmt pointers) must be finalized or
|
||||
** reset before this call is made. Otherwise, SQLITE_BUSY is returned.
|
||||
** If any in-memory databases are in use, either as a main or TEMP
|
||||
** database, SQLITE_ERROR is returned. In either of these cases, the
|
||||
** library is not reset and remains unusable.
|
||||
**
|
||||
** This function is *not* threadsafe. Calling this from within a threaded
|
||||
** application when threads other than the caller have used SQLite is
|
||||
** dangerous and will almost certainly result in malfunctions.
|
||||
**
|
||||
** This functionality can be omitted from a build by defining the
|
||||
** SQLITE_OMIT_GLOBALRECOVER at compile time.
|
||||
*/
|
||||
int sqlite3_global_recover();
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* End of the 'extern "C"' block */
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
*************************************************************************
|
||||
** Internal interface definitions for SQLite.
|
||||
**
|
||||
** @(#) $Id: sqliteInt.h,v 1.327 2004/10/05 02:41:43 drh Exp $
|
||||
** @(#) $Id: sqliteInt.h,v 1.374 2005/03/21 04:04:03 danielk1977 Exp $
|
||||
*/
|
||||
#ifndef _SQLITEINT_H_
|
||||
#define _SQLITEINT_H_
|
||||
|
@ -47,13 +47,25 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <stddef.h>
|
||||
|
||||
/*
|
||||
** The maximum number of in-memory pages to use for the main database
|
||||
** table and for temporary tables.
|
||||
** table and for temporary tables. Internally, the MAX_PAGES and
|
||||
** TEMP_PAGES macros are used. To override the default values at
|
||||
** compilation time, the SQLITE_DEFAULT_CACHE_SIZE and
|
||||
** SQLITE_DEFAULT_TEMP_CACHE_SIZE macros should be set.
|
||||
*/
|
||||
#define MAX_PAGES 2000
|
||||
#define TEMP_PAGES 500
|
||||
#ifdef SQLITE_DEFAULT_CACHE_SIZE
|
||||
# define MAX_PAGES SQLITE_DEFAULT_CACHE_SIZE
|
||||
#else
|
||||
# define MAX_PAGES 2000
|
||||
#endif
|
||||
#ifdef SQLITE_DEFAULT_TEMP_CACHE_SIZE
|
||||
# define TEMP_PAGES SQLITE_DEFAULT_TEMP_CACHE_SIZE
|
||||
#else
|
||||
# define TEMP_PAGES 500
|
||||
#endif
|
||||
|
||||
/*
|
||||
** If the following macro is set to 1, then NULL values are considered
|
||||
|
@ -102,10 +114,28 @@
|
|||
** a minimum.
|
||||
*/
|
||||
/* #define SQLITE_OMIT_AUTHORIZATION 1 */
|
||||
/* #define SQLITE_OMIT_INMEMORYDB 1 */
|
||||
/* #define SQLITE_OMIT_MEMORYDB 1 */
|
||||
/* #define SQLITE_OMIT_VACUUM 1 */
|
||||
/* #define SQLITE_OMIT_DATETIME_FUNCS 1 */
|
||||
/* #define SQLITE_OMIT_PROGRESS_CALLBACK 1 */
|
||||
/* #define SQLITE_OMIT_AUTOVACUUM */
|
||||
/* #define SQLITE_OMIT_ALTERTABLE */
|
||||
|
||||
/*
|
||||
** Provide a default value for TEMP_STORE in case it is not specified
|
||||
** on the command-line
|
||||
*/
|
||||
#ifndef TEMP_STORE
|
||||
# define TEMP_STORE 1
|
||||
#endif
|
||||
|
||||
/*
|
||||
** GCC does not define the offsetof() macro so we'll have to do it
|
||||
** ourselves.
|
||||
*/
|
||||
#ifndef offsetof
|
||||
#define offsetof(STRUCTURE,FIELD) ((int)((char*)&((STRUCTURE*)0)->FIELD))
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Integers of known sizes. These typedefs might change for architectures
|
||||
|
@ -213,7 +243,7 @@ struct BusyHandler {
|
|||
** each malloc() and free(). This output can be analyzed
|
||||
** by an AWK script to determine if there are any leaks.
|
||||
*/
|
||||
#ifdef SQLITE_DEBUG
|
||||
#ifdef SQLITE_MEMDEBUG
|
||||
# define sqliteMalloc(X) sqlite3Malloc_(X,1,__FILE__,__LINE__)
|
||||
# define sqliteMallocRaw(X) sqlite3Malloc_(X,0,__FILE__,__LINE__)
|
||||
# define sqliteFree(X) sqlite3Free_(X,__FILE__,__LINE__)
|
||||
|
@ -239,10 +269,11 @@ extern int sqlite3_malloc_failed;
|
|||
** The following global variables are used for testing and debugging
|
||||
** only. They only work if SQLITE_DEBUG is defined.
|
||||
*/
|
||||
#ifdef SQLITE_DEBUG
|
||||
extern int sqlite3_nMalloc; /* Number of sqliteMalloc() calls */
|
||||
extern int sqlite3_nFree; /* Number of sqliteFree() calls */
|
||||
extern int sqlite3_iMallocFail; /* Fail sqliteMalloc() after this many calls */
|
||||
#ifdef SQLITE_MEMDEBUG
|
||||
extern int sqlite3_nMalloc; /* Number of sqliteMalloc() calls */
|
||||
extern int sqlite3_nFree; /* Number of sqliteFree() calls */
|
||||
extern int sqlite3_iMallocFail; /* Fail sqliteMalloc() after this many calls */
|
||||
extern int sqlite3_iMallocReset; /* Set iMallocFail to this when it reaches 0 */
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
@ -296,6 +327,8 @@ typedef struct AuthContext AuthContext;
|
|||
typedef struct KeyClass KeyClass;
|
||||
typedef struct CollSeq CollSeq;
|
||||
typedef struct KeyInfo KeyInfo;
|
||||
typedef struct NameContext NameContext;
|
||||
typedef struct Fetch Fetch;
|
||||
|
||||
/*
|
||||
** Each database file to be accessed by the system is an instance
|
||||
|
@ -316,7 +349,8 @@ struct Db {
|
|||
u8 inTrans; /* 0: not writable. 1: Transaction. 2: Checkpoint */
|
||||
u8 safety_level; /* How aggressive at synching data to disk */
|
||||
int cache_size; /* Number of pages to use in the cache */
|
||||
void *pAux; /* Auxiliary data. Usually NULL */
|
||||
Table *pSeqTab; /* The sqlite_sequence table used by AUTOINCREMENT */
|
||||
void *pAux; /* Auxiliary data. Usually NULL */
|
||||
void (*xFreeAux)(void*); /* Routine to free pAux */
|
||||
};
|
||||
|
||||
|
@ -408,7 +442,6 @@ struct sqlite3 {
|
|||
void *pProgressArg; /* Argument to the progress callback */
|
||||
int nProgressOps; /* Number of opcodes for progress callback */
|
||||
#endif
|
||||
|
||||
int errCode; /* Most recent error code (SQLITE_*) */
|
||||
u8 enc; /* Text encoding for this database. */
|
||||
u8 autoCommit; /* The auto-commit flag. */
|
||||
|
@ -417,9 +450,11 @@ struct sqlite3 {
|
|||
void *pCollNeededArg;
|
||||
sqlite3_value *pValue; /* Value used for transient conversions */
|
||||
sqlite3_value *pErr; /* Most recent error message */
|
||||
|
||||
char *zErrMsg; /* Most recent error message (UTF-8 encoded) */
|
||||
char *zErrMsg16; /* Most recent error message (UTF-8 encoded) */
|
||||
char *zErrMsg16; /* Most recent error message (UTF-16 encoded) */
|
||||
#ifndef SQLITE_OMIT_GLOBALRECOVER
|
||||
sqlite3 *pNext; /* Linked list of open db handles. */
|
||||
#endif
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -443,6 +478,9 @@ struct sqlite3 {
|
|||
/* result set is empty */
|
||||
#define SQLITE_SqlTrace 0x00000200 /* Debug print SQL as it executes */
|
||||
#define SQLITE_VdbeListing 0x00000400 /* Debug listings of VDBE programs */
|
||||
#define SQLITE_WriteSchema 0x00000800 /* OK to update SQLITE_MASTER */
|
||||
#define SQLITE_NoReadlock 0x00001000 /* Readlocks are omitted when
|
||||
** accessing read-only databases */
|
||||
|
||||
/*
|
||||
** Possible values for the sqlite.magic field.
|
||||
|
@ -478,7 +516,7 @@ struct FuncDef {
|
|||
*/
|
||||
struct Column {
|
||||
char *zName; /* Name of this column */
|
||||
char *zDflt; /* Default value of this column */
|
||||
Expr *pDflt; /* Default value of this column */
|
||||
char *zType; /* Data type for this column */
|
||||
CollSeq *pColl; /* Collating sequence. If NULL, use the default */
|
||||
u8 notNull; /* True if there is a NOT NULL constraint */
|
||||
|
@ -572,9 +610,13 @@ struct Table {
|
|||
u8 isTransient; /* True if automatically deleted when VDBE finishes */
|
||||
u8 hasPrimKey; /* True if there exists a primary key */
|
||||
u8 keyConf; /* What to do in case of uniqueness conflict on iPKey */
|
||||
u8 autoInc; /* True if the integer primary key is autoincrement */
|
||||
Trigger *pTrigger; /* List of SQL triggers on this table */
|
||||
FKey *pFKey; /* Linked list of all foreign keys in this table */
|
||||
char *zColAff; /* String defining the affinity of each column */
|
||||
#ifndef SQLITE_OMIT_ALTERTABLE
|
||||
int addColOffset; /* Offset in CREATE TABLE statement to add a new column */
|
||||
#endif
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -759,10 +801,20 @@ struct Token {
|
|||
** marker (a question mark character '?' in the original SQL) then the
|
||||
** Expr.iTable holds the index number for that variable.
|
||||
**
|
||||
** If the expression is a subquery then Expr.iColumn holds an integer
|
||||
** register number containing the result of the subquery. If the
|
||||
** subquery gives a constant result, then iTable is -1. If the subquery
|
||||
** gives a different answer at different times during statement processing
|
||||
** then iTable is the address of a subroutine that computes the subquery.
|
||||
**
|
||||
** The Expr.pSelect field points to a SELECT statement. The SELECT might
|
||||
** be the right operand of an IN operator. Or, if a scalar SELECT appears
|
||||
** in an expression the opcode is TK_SELECT and Expr.pSelect is the only
|
||||
** operand.
|
||||
**
|
||||
** If the Expr is of type OP_Column, and the table it is selecting from
|
||||
** is a disk table or the "old.*" pseudo-table, then pTab points to the
|
||||
** corresponding table definition.
|
||||
*/
|
||||
struct Expr {
|
||||
u8 op; /* Operation performed by this node */
|
||||
|
@ -777,16 +829,23 @@ struct Expr {
|
|||
Token span; /* Complete text of the expression */
|
||||
int iTable, iColumn; /* When op==TK_COLUMN, then this expr node means the
|
||||
** iColumn-th field of the iTable-th table. */
|
||||
int iAgg; /* When op==TK_COLUMN and pParse->useAgg==TRUE, pull
|
||||
int iAgg; /* When op==TK_COLUMN and pParse->fillAgg==FALSE, pull
|
||||
** result from the iAgg-th element of the aggregator */
|
||||
int iAggCtx; /* The value to pass as P1 of OP_AggGet. */
|
||||
Select *pSelect; /* When the expression is a sub-select. Also the
|
||||
** right side of "<expr> IN (<select>)" */
|
||||
Table *pTab; /* Table for OP_Column expressions. */
|
||||
};
|
||||
|
||||
/*
|
||||
** The following are the meanings of bits in the Expr.flags field.
|
||||
*/
|
||||
#define EP_FromJoin 0x0001 /* Originated in ON or USING clause of a join */
|
||||
#define EP_Agg 0x0002 /* Contains one or more aggregate functions */
|
||||
#define EP_Resolved 0x0004 /* IDs have been resolved to COLUMNs */
|
||||
#define EP_Error 0x0008 /* Expression contains one or more errors */
|
||||
#define EP_Not 0x0010 /* Operator preceeded by NOT */
|
||||
#define EP_VarSelect 0x0020 /* pSelect is correlated, not constant */
|
||||
|
||||
/*
|
||||
** These macros can be used to test, set, or clear bits in the
|
||||
|
@ -841,6 +900,11 @@ struct IdList {
|
|||
} *a;
|
||||
};
|
||||
|
||||
/*
|
||||
** The bitmask datatype defined below is used for various optimizations.
|
||||
*/
|
||||
typedef unsigned int Bitmask;
|
||||
|
||||
/*
|
||||
** The following structure describes the FROM clause of a SELECT statement.
|
||||
** Each table or subquery in the FROM clause is a separate element of
|
||||
|
@ -865,6 +929,7 @@ struct SrcList {
|
|||
int iCursor; /* The VDBE cursor number used to access this table */
|
||||
Expr *pOn; /* The ON clause of a join */
|
||||
IdList *pUsing; /* The USING clause of a join */
|
||||
Bitmask colUsed; /* Bit N (1<<N) set if column N or pTab is used */
|
||||
} a[1]; /* One entry for each identifier on the list */
|
||||
};
|
||||
|
||||
|
@ -886,9 +951,10 @@ struct SrcList {
|
|||
*/
|
||||
struct WhereLevel {
|
||||
int iMem; /* Memory cell used by this level */
|
||||
Index *pIdx; /* Index used */
|
||||
int iCur; /* Cursor number used for this index */
|
||||
int score; /* How well this indexed scored */
|
||||
Index *pIdx; /* Index used. NULL if no index */
|
||||
int iTabCur; /* The VDBE cursor used to access the table */
|
||||
int iIdxCur; /* The VDBE cursor used to acesss pIdx */
|
||||
int score; /* How well this index scored */
|
||||
int brk; /* Jump here to break out of the loop */
|
||||
int cont; /* Jump here to continue with the next loop cycle */
|
||||
int op, p1, p2; /* Opcode used to terminate the loop */
|
||||
|
@ -908,24 +974,50 @@ struct WhereLevel {
|
|||
struct WhereInfo {
|
||||
Parse *pParse;
|
||||
SrcList *pTabList; /* List of tables in the join */
|
||||
int iTop; /* The very beginning of the WHERE loop */
|
||||
int iContinue; /* Jump here to continue with next record */
|
||||
int iBreak; /* Jump here to break out of the loop */
|
||||
int nLevel; /* Number of nested loop */
|
||||
WhereLevel a[1]; /* Information about each nest loop in the WHERE */
|
||||
};
|
||||
|
||||
/*
|
||||
** A NameContext defines a context in which to resolve table and column
|
||||
** names. The context consists of a list of tables (the pSrcList) field and
|
||||
** a list of named expression (pEList). The named expression list may
|
||||
** be NULL. The pSrc corresponds to the FROM clause of a SELECT or
|
||||
** to the table being operated on by INSERT, UPDATE, or DELETE. The
|
||||
** pEList corresponds to the result set of a SELECT and is NULL for
|
||||
** other statements.
|
||||
**
|
||||
** NameContexts can be nested. When resolving names, the inner-most
|
||||
** context is searched first. If no match is found, the next outer
|
||||
** context is checked. If there is still no match, the next context
|
||||
** is checked. This process continues until either a match is found
|
||||
** or all contexts are check. When a match is found, the nRef member of
|
||||
** the context containing the match is incremented.
|
||||
**
|
||||
** Each subquery gets a new NameContext. The pNext field points to the
|
||||
** NameContext in the parent query. Thus the process of scanning the
|
||||
** NameContext list corresponds to searching through successively outer
|
||||
** subqueries looking for a match.
|
||||
*/
|
||||
struct NameContext {
|
||||
Parse *pParse; /* The parser */
|
||||
SrcList *pSrcList; /* One or more tables used to resolve names */
|
||||
ExprList *pEList; /* Optional list of named expressions */
|
||||
int nRef; /* Number of names resolved by this context */
|
||||
int nErr; /* Number of errors encountered while resolving names */
|
||||
u8 allowAgg; /* Aggregate functions allowed here */
|
||||
u8 hasAgg;
|
||||
int nDepth; /* Depth of subquery recursion. 1 for no recursion */
|
||||
NameContext *pNext; /* Next outer name context. NULL for outermost */
|
||||
};
|
||||
|
||||
/*
|
||||
** An instance of the following structure contains all information
|
||||
** needed to generate code for a single SELECT statement.
|
||||
**
|
||||
** The zSelect field is used when the Select structure must be persistent.
|
||||
** Normally, the expression tree points to tokens in the original input
|
||||
** string that encodes the select. But if the Select structure must live
|
||||
** longer than its input string (for example when it is used to describe
|
||||
** a VIEW) we have to make a copy of the input string so that the nodes
|
||||
** of the expression tree will have something to point to. zSelect is used
|
||||
** to hold that copy.
|
||||
**
|
||||
** nLimit is set to -1 if there is no LIMIT clause. nOffset is set to 0.
|
||||
** If there is a LIMIT clause, the parser sets nLimit to the value of the
|
||||
** limit and nOffset to the value of the offset (or 0 if there is not
|
||||
|
@ -942,10 +1034,13 @@ struct Select {
|
|||
Expr *pHaving; /* The HAVING clause */
|
||||
ExprList *pOrderBy; /* The ORDER BY clause */
|
||||
Select *pPrior; /* Prior select in a compound select statement */
|
||||
int nLimit, nOffset; /* LIMIT and OFFSET values. -1 means not used */
|
||||
Expr *pLimit; /* LIMIT expression. NULL means not used. */
|
||||
Expr *pOffset; /* OFFSET expression. NULL means not used. */
|
||||
int iLimit, iOffset; /* Memory registers holding LIMIT & OFFSET counters */
|
||||
char *zSelect; /* Complete text of the SELECT command */
|
||||
IdList **ppOpenTemp; /* OP_OpenTemp addresses used by multi-selects */
|
||||
Fetch *pFetch; /* If this stmt is part of a FETCH command */
|
||||
u8 isResolved; /* True once sqlite3SelectResolve() has run. */
|
||||
u8 isAgg; /* True if this is an aggregate query */
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -961,6 +1056,7 @@ struct Select {
|
|||
#define SRT_Discard 9 /* Do not save the results anywhere */
|
||||
#define SRT_Sorter 10 /* Store results in the sorter */
|
||||
#define SRT_Subroutine 11 /* Call a subroutine to handle results */
|
||||
#define SRT_Exists 12 /* Put 0 or 1 in a memory cell */
|
||||
|
||||
/*
|
||||
** When a SELECT uses aggregate functions (like "count(*)" or "avg(f1)")
|
||||
|
@ -991,41 +1087,51 @@ struct AggExpr {
|
|||
** An SQL parser context. A copy of this structure is passed through
|
||||
** the parser and down into all the parser action routine in order to
|
||||
** carry around information that is global to the entire parse.
|
||||
**
|
||||
** The structure is divided into two parts. When the parser and code
|
||||
** generate call themselves recursively, the first part of the structure
|
||||
** is constant but the second part is reset at the beginning and end of
|
||||
** each recursion.
|
||||
*/
|
||||
struct Parse {
|
||||
sqlite3 *db; /* The main database structure */
|
||||
int rc; /* Return code from execution */
|
||||
char *zErrMsg; /* An error message */
|
||||
Vdbe *pVdbe; /* An engine for executing database bytecode */
|
||||
u8 colNamesSet; /* TRUE after OP_ColumnName has been issued to pVdbe */
|
||||
u8 nameClash; /* A permanent table name clashes with temp table name */
|
||||
u8 checkSchema; /* Causes schema cookie check after an error */
|
||||
u8 nested; /* Number of nested calls to the parser/code generator */
|
||||
int nErr; /* Number of errors seen */
|
||||
int nTab; /* Number of previously allocated VDBE cursors */
|
||||
int nMem; /* Number of memory cells used so far */
|
||||
int nSet; /* Number of sets used so far */
|
||||
u32 cookieMask; /* Bitmask of schema verified databases */
|
||||
int cookieValue[MAX_ATTACHED+2]; /* Values of cookies to verify */
|
||||
int cookieGoto; /* Address of OP_Goto to cookie verifier subroutine */
|
||||
u32 writeMask; /* Start a write transaction on these databases */
|
||||
u8 fillAgg; /* If true, ignore the Expr.iAgg field. Normally false */
|
||||
|
||||
/* Above is constant between recursions. Below is reset before and after
|
||||
** each recursion */
|
||||
|
||||
int nVar; /* Number of '?' variables seen in the SQL so far */
|
||||
int nVarExpr; /* Number of used slots in apVarExpr[] */
|
||||
int nVarExprAlloc; /* Number of allocated slots in apVarExpr[] */
|
||||
Expr **apVarExpr; /* Pointers to :aaa and $aaaa wildcard expressions */
|
||||
u8 explain; /* True if the EXPLAIN flag is found on the query */
|
||||
Token sErrToken; /* The token at which the error occurred */
|
||||
Token sNameToken; /* Token with unqualified schema object name */
|
||||
Token sLastToken; /* The last token parsed */
|
||||
const char *zSql; /* All SQL text */
|
||||
const char *zTail; /* All SQL text past the last semicolon parsed */
|
||||
Table *pNewTable; /* A table being constructed by CREATE TABLE */
|
||||
Vdbe *pVdbe; /* An engine for executing database bytecode */
|
||||
u8 colNamesSet; /* TRUE after OP_ColumnName has been issued to pVdbe */
|
||||
u8 explain; /* True if the EXPLAIN flag is found on the query */
|
||||
u8 nameClash; /* A permanent table name clashes with temp table name */
|
||||
u8 useAgg; /* If true, extract field values from the aggregator
|
||||
** while generating expressions. Normally false */
|
||||
u8 checkSchema; /* Causes schema cookie check after an error */
|
||||
int nErr; /* Number of errors seen */
|
||||
int nTab; /* Number of previously allocated VDBE cursors */
|
||||
int nMem; /* Number of memory cells used so far */
|
||||
int nSet; /* Number of sets used so far */
|
||||
int nAgg; /* Number of aggregate expressions */
|
||||
int nVar; /* Number of '?' variables seen in the SQL so far */
|
||||
int nVarExpr; /* Number of used slots in apVarExpr[] */
|
||||
int nVarExprAlloc; /* Number of allocated slots in apVarExpr[] */
|
||||
Expr **apVarExpr; /* Pointers to :aaa and $aaaa wildcard expressions */
|
||||
AggExpr *aAgg; /* An array of aggregate expressions */
|
||||
const char *zAuthContext; /* The 6th parameter to db->xAuth callbacks */
|
||||
Trigger *pNewTrigger; /* Trigger under construct by a CREATE TRIGGER */
|
||||
TriggerStack *trigStack; /* Trigger actions being coded */
|
||||
u32 cookieMask; /* Bitmask of schema verified databases */
|
||||
int cookieValue[MAX_ATTACHED+2]; /* Values of cookies to verify */
|
||||
int cookieGoto; /* Address of OP_Goto to cookie verifier subroutine */
|
||||
u32 writeMask; /* Start a write transaction on these databases */
|
||||
const char *zAuthContext; /* The 6th parameter to db->xAuth callbacks */
|
||||
int nAgg; /* Number of aggregate expressions */
|
||||
AggExpr *aAgg; /* An array of aggregate expressions */
|
||||
int nMaxDepth; /* Maximum depth of subquery recursion */
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -1064,7 +1170,7 @@ struct Trigger {
|
|||
u8 iDb; /* Database containing this trigger */
|
||||
u8 iTabDb; /* Database containing Trigger.table */
|
||||
u8 op; /* One of TK_DELETE, TK_UPDATE, TK_INSERT */
|
||||
u8 tr_tm; /* One of TK_BEFORE, TK_AFTER */
|
||||
u8 tr_tm; /* One of TRIGGER_BEFORE, TRIGGER_AFTER */
|
||||
Expr *pWhen; /* The WHEN clause of the expresion (may be NULL) */
|
||||
IdList *pColumns; /* If this is an UPDATE OF <column-list> trigger,
|
||||
the <column-list> is stored here */
|
||||
|
@ -1075,6 +1181,16 @@ struct Trigger {
|
|||
Trigger *pNext; /* Next trigger associated with the table */
|
||||
};
|
||||
|
||||
/*
|
||||
** A trigger is either a BEFORE or an AFTER trigger. The following constants
|
||||
** determine which.
|
||||
**
|
||||
** If there are multiple triggers, you might of some BEFORE and some AFTER.
|
||||
** In that cases, the constants below can be ORed together.
|
||||
*/
|
||||
#define TRIGGER_BEFORE 1
|
||||
#define TRIGGER_AFTER 2
|
||||
|
||||
/*
|
||||
* An instance of struct TriggerStep is used to store a single SQL statement
|
||||
* that is a part of a trigger-program.
|
||||
|
@ -1188,7 +1304,6 @@ typedef struct {
|
|||
char **pzErrMsg; /* Error message stored here */
|
||||
} InitData;
|
||||
|
||||
|
||||
/*
|
||||
* This global flag is set for performance testing of triggers. When it is set
|
||||
* SQLite will perform the overhead of building new and old trigger references
|
||||
|
@ -1206,7 +1321,7 @@ int sqlite3IsNumber(const char*, int*, u8);
|
|||
int sqlite3Compare(const char *, const char *);
|
||||
int sqlite3SortCompare(const char *, const char *);
|
||||
void sqlite3RealToSortable(double r, char *);
|
||||
#ifdef SQLITE_DEBUG
|
||||
#ifdef SQLITE_MEMDEBUG
|
||||
void *sqlite3Malloc_(int,int,char*,int);
|
||||
void sqlite3Free_(void*,char*,int);
|
||||
void *sqlite3Realloc_(void*,int,char*,int);
|
||||
|
@ -1233,7 +1348,8 @@ void sqlite3Dequote(char*);
|
|||
int sqlite3KeywordCode(const char*, int);
|
||||
int sqlite3RunParser(Parse*, const char*, char **);
|
||||
void sqlite3FinishCoding(Parse*);
|
||||
Expr *sqlite3Expr(int, Expr*, Expr*, Token*);
|
||||
Expr *sqlite3Expr(int, Expr*, Expr*, const Token*);
|
||||
Expr *sqlite3RegisterExpr(Parse*,Token*);
|
||||
Expr *sqlite3ExprAnd(Expr*, Expr*);
|
||||
void sqlite3ExprSpan(Expr*,Token*,Token*);
|
||||
Expr *sqlite3ExprFunction(ExprList*, Token*);
|
||||
|
@ -1253,13 +1369,19 @@ void sqlite3OpenMasterTable(Vdbe *v, int);
|
|||
void sqlite3StartTable(Parse*,Token*,Token*,Token*,int,int);
|
||||
void sqlite3AddColumn(Parse*,Token*);
|
||||
void sqlite3AddNotNull(Parse*, int);
|
||||
void sqlite3AddPrimaryKey(Parse*, ExprList*, int);
|
||||
void sqlite3AddPrimaryKey(Parse*, ExprList*, int, int);
|
||||
void sqlite3AddColumnType(Parse*,Token*,Token*);
|
||||
void sqlite3AddDefaultValue(Parse*,Token*,int);
|
||||
void sqlite3AddDefaultValue(Parse*,Expr*);
|
||||
void sqlite3AddCollateType(Parse*, const char*, int);
|
||||
void sqlite3EndTable(Parse*,Token*,Select*);
|
||||
void sqlite3CreateView(Parse*,Token*,Token*,Token*,Select*,int);
|
||||
int sqlite3ViewGetColumnNames(Parse*,Table*);
|
||||
void sqlite3EndTable(Parse*,Token*,Token*,Select*);
|
||||
|
||||
#ifndef SQLITE_OMIT_VIEW
|
||||
void sqlite3CreateView(Parse*,Token*,Token*,Token*,Select*,int);
|
||||
int sqlite3ViewGetColumnNames(Parse*,Table*);
|
||||
#else
|
||||
# define sqlite3ViewGetColumnNames(A,B) 0
|
||||
#endif
|
||||
|
||||
void sqlite3DropTable(Parse*, SrcList*, int);
|
||||
void sqlite3DeleteTable(sqlite3*, Table*);
|
||||
void sqlite3Insert(Parse*, SrcList*, ExprList*, Select*, IdList*, int);
|
||||
|
@ -1277,35 +1399,36 @@ void sqlite3AddKeyType(Vdbe*, ExprList*);
|
|||
void sqlite3AddIdxKeyType(Vdbe*, Index*);
|
||||
int sqlite3Select(Parse*, Select*, int, int, Select*, int, int*, char *aff);
|
||||
Select *sqlite3SelectNew(ExprList*,SrcList*,Expr*,ExprList*,Expr*,ExprList*,
|
||||
int,int,int);
|
||||
int,Expr*,Expr*);
|
||||
void sqlite3SelectDelete(Select*);
|
||||
void sqlite3SelectUnbind(Select*);
|
||||
Table *sqlite3SrcListLookup(Parse*, SrcList*);
|
||||
int sqlite3IsReadOnly(Parse*, Table*, int);
|
||||
void sqlite3OpenTableForReading(Vdbe*, int iCur, Table*);
|
||||
void sqlite3OpenTable(Vdbe*, int iCur, Table*, int);
|
||||
void sqlite3DeleteFrom(Parse*, SrcList*, Expr*);
|
||||
void sqlite3Update(Parse*, SrcList*, ExprList*, Expr*, int);
|
||||
WhereInfo *sqlite3WhereBegin(Parse*, SrcList*, Expr*, int, ExprList**);
|
||||
WhereInfo *sqlite3WhereBegin(Parse*, SrcList*, Expr*, ExprList**, Fetch*);
|
||||
void sqlite3WhereEnd(WhereInfo*);
|
||||
void sqlite3ExprCode(Parse*, Expr*);
|
||||
void sqlite3ExprCodeAndCache(Parse*, Expr*);
|
||||
int sqlite3ExprCodeExprList(Parse*, ExprList*);
|
||||
void sqlite3ExprIfTrue(Parse*, Expr*, int, int);
|
||||
void sqlite3ExprIfFalse(Parse*, Expr*, int, int);
|
||||
void sqlite3NextedParse(Parse*, const char*, ...);
|
||||
Table *sqlite3FindTable(sqlite3*,const char*, const char*);
|
||||
Table *sqlite3LocateTable(Parse*,const char*, const char*);
|
||||
Index *sqlite3FindIndex(sqlite3*,const char*, const char*);
|
||||
void sqlite3UnlinkAndDeleteTable(sqlite3*,int,const char*);
|
||||
void sqlite3UnlinkAndDeleteIndex(sqlite3*,int,const char*);
|
||||
void sqlite3UnlinkAndDeleteTrigger(sqlite3*,int,const char*);
|
||||
void sqlite3Vacuum(Parse*, Token*);
|
||||
int sqlite3RunVacuum(char**, sqlite3*);
|
||||
char *sqlite3NameFromToken(Token*);
|
||||
int sqlite3ExprCheck(Parse*, Expr*, int, int*);
|
||||
int sqlite3ExprCompare(Expr*, Expr*);
|
||||
int sqliteFuncId(Token*);
|
||||
int sqlite3ExprResolveIds(Parse*, SrcList*, ExprList*, Expr*);
|
||||
int sqlite3ExprResolveAndCheck(Parse*,SrcList*,ExprList*,Expr*,int,int*);
|
||||
int sqlite3ExprAnalyzeAggregates(Parse*, Expr*);
|
||||
int sqlite3ExprResolveNames(NameContext *, Expr *);
|
||||
int sqlite3ExprAnalyzeAggregates(NameContext*, Expr*);
|
||||
Vdbe *sqlite3GetVdbe(Parse*);
|
||||
void sqlite3Randomness(int, void*);
|
||||
void sqlite3RollbackAll(sqlite3*);
|
||||
|
@ -1336,21 +1459,32 @@ int sqlite3SafetyOn(sqlite3*);
|
|||
int sqlite3SafetyOff(sqlite3*);
|
||||
int sqlite3SafetyCheck(sqlite3*);
|
||||
void sqlite3ChangeCookie(sqlite3*, Vdbe*, int);
|
||||
void sqlite3BeginTrigger(Parse*, Token*,Token*,int,int,IdList*,SrcList*,
|
||||
int,Expr*,int);
|
||||
void sqlite3FinishTrigger(Parse*, TriggerStep*, Token*);
|
||||
void sqlite3DropTrigger(Parse*, SrcList*);
|
||||
void sqlite3DropTriggerPtr(Parse*, Trigger*, int);
|
||||
int sqlite3TriggersExist(Parse* , Trigger* , int , int , int, ExprList*);
|
||||
int sqlite3CodeRowTrigger(Parse*, int, ExprList*, int, Table *, int, int,
|
||||
int, int);
|
||||
void sqliteViewTriggers(Parse*, Table*, Expr*, int, ExprList*);
|
||||
void sqlite3DeleteTriggerStep(TriggerStep*);
|
||||
TriggerStep *sqlite3TriggerSelectStep(Select*);
|
||||
TriggerStep *sqlite3TriggerInsertStep(Token*, IdList*, ExprList*, Select*, int);
|
||||
TriggerStep *sqlite3TriggerUpdateStep(Token*, ExprList*, Expr*, int);
|
||||
TriggerStep *sqlite3TriggerDeleteStep(Token*, Expr*);
|
||||
void sqlite3DeleteTrigger(Trigger*);
|
||||
|
||||
#ifndef SQLITE_OMIT_TRIGGER
|
||||
void sqlite3BeginTrigger(Parse*, Token*,Token*,int,int,IdList*,SrcList*,
|
||||
int,Expr*,int);
|
||||
void sqlite3FinishTrigger(Parse*, TriggerStep*, Token*);
|
||||
void sqlite3DropTrigger(Parse*, SrcList*);
|
||||
void sqlite3DropTriggerPtr(Parse*, Trigger*, int);
|
||||
int sqlite3TriggersExist(Parse*, Table*, int, ExprList*);
|
||||
int sqlite3CodeRowTrigger(Parse*, int, ExprList*, int, Table *, int, int,
|
||||
int, int);
|
||||
void sqliteViewTriggers(Parse*, Table*, Expr*, int, ExprList*);
|
||||
void sqlite3DeleteTriggerStep(TriggerStep*);
|
||||
TriggerStep *sqlite3TriggerSelectStep(Select*);
|
||||
TriggerStep *sqlite3TriggerInsertStep(Token*, IdList*, ExprList*,Select*,int);
|
||||
TriggerStep *sqlite3TriggerUpdateStep(Token*, ExprList*, Expr*, int);
|
||||
TriggerStep *sqlite3TriggerDeleteStep(Token*, Expr*);
|
||||
void sqlite3DeleteTrigger(Trigger*);
|
||||
void sqlite3UnlinkAndDeleteTrigger(sqlite3*,int,const char*);
|
||||
#else
|
||||
# define sqlite3TriggersExist(A,B,C,D,E,F) 0
|
||||
# define sqlite3DeleteTrigger(A)
|
||||
# define sqlite3DropTriggerPtr(A,B,C)
|
||||
# define sqlite3UnlinkAndDeleteTrigger(A,B,C)
|
||||
# define sqlite3CodeRowTrigger(A,B,C,D,E,F,G,H,I) 0
|
||||
#endif
|
||||
|
||||
int sqlite3JoinType(Parse*, Token*, Token*, Token*);
|
||||
void sqlite3CreateForeignKey(Parse*, ExprList*, Token*, ExprList*, int);
|
||||
void sqlite3DeferForeignKey(Parse*, int);
|
||||
|
@ -1386,7 +1520,6 @@ int sqlite3PutVarint(unsigned char *, u64);
|
|||
int sqlite3GetVarint(const unsigned char *, u64 *);
|
||||
int sqlite3GetVarint32(const unsigned char *, u32 *);
|
||||
int sqlite3VarintLen(u64 v);
|
||||
char sqlite3AffinityType(const char *, int);
|
||||
void sqlite3IndexAffinityStr(Vdbe *, Index *);
|
||||
void sqlite3TableAffinityStr(Vdbe *, Table *);
|
||||
char sqlite3CompareAffinity(Expr *pExpr, char aff2);
|
||||
|
@ -1414,6 +1547,20 @@ void sqlite3ValueSetStr(sqlite3_value*, int, const void *,u8, void(*)(void*));
|
|||
void sqlite3ValueFree(sqlite3_value*);
|
||||
sqlite3_value *sqlite3ValueNew();
|
||||
sqlite3_value *sqlite3GetTransientValue(sqlite3*db);
|
||||
int sqlite3ValueFromExpr(Expr *, u8, u8, sqlite3_value **);
|
||||
void sqlite3ValueApplyAffinity(sqlite3_value *, u8, u8);
|
||||
extern const unsigned char sqlite3UpperToLower[];
|
||||
void sqlite3RootPageMoved(Db*, int, int);
|
||||
void sqlite3Reindex(Parse*, Token*, Token*);
|
||||
void sqlite3AlterFunctions(sqlite3*);
|
||||
void sqlite3AlterRenameTable(Parse*, SrcList*, Token*);
|
||||
int sqlite3GetToken(const unsigned char *, int *);
|
||||
void sqlite3NestedParse(Parse*, const char*, ...);
|
||||
void sqlite3ExpirePreparedStatements(sqlite3*);
|
||||
void sqlite3CodeSubselect(Parse *, Expr *);
|
||||
int sqlite3SelectResolve(Parse *, Select *, NameContext *);
|
||||
void sqlite3ColumnDefault(Vdbe *, Table *, int);
|
||||
void sqlite3AlterFinishAddColumn(Parse *, Token *);
|
||||
void sqlite3AlterBeginAddColumn(Parse *, SrcList *);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
*************************************************************************
|
||||
** A TCL Interface to SQLite
|
||||
**
|
||||
** $Id: tclsqlite.c,v 1.106 2004/09/13 13:16:32 drh Exp $
|
||||
** $Id: tclsqlite.c,v 1.119 2005/02/26 17:31:27 drh Exp $
|
||||
*/
|
||||
#ifndef NO_TCL /* Omit this whole file if TCL is unavailable */
|
||||
|
||||
|
@ -22,6 +22,9 @@
|
|||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#define NUM_PREPARED_STMTS 10
|
||||
#define MAX_PREPARED_STMTS 100
|
||||
|
||||
/*
|
||||
** If TCL uses UTF-8 and SQLite is configured to use iso8859, then we
|
||||
** have to do a translation when going between the two. Set the
|
||||
|
@ -54,6 +57,19 @@ struct SqlCollate {
|
|||
SqlCollate *pNext; /* Next function on the list of them all */
|
||||
};
|
||||
|
||||
/*
|
||||
** Prepared statements are cached for faster execution. Each prepared
|
||||
** statement is described by an instance of the following structure.
|
||||
*/
|
||||
typedef struct SqlPreparedStmt SqlPreparedStmt;
|
||||
struct SqlPreparedStmt {
|
||||
SqlPreparedStmt *pNext; /* Next in linked list */
|
||||
SqlPreparedStmt *pPrev; /* Previous on the list */
|
||||
sqlite3_stmt *pStmt; /* The prepared statement */
|
||||
int nSql; /* chars in zSql[] */
|
||||
char zSql[1]; /* Text of the SQL statement */
|
||||
};
|
||||
|
||||
/*
|
||||
** There is one instance of this structure for each SQLite database
|
||||
** that has been opened by the SQLite TCL interface.
|
||||
|
@ -71,14 +87,35 @@ struct SqliteDb {
|
|||
SqlCollate *pCollate; /* List of SQL collation functions */
|
||||
int rc; /* Return code of most recent sqlite3_exec() */
|
||||
Tcl_Obj *pCollateNeeded; /* Collation needed script */
|
||||
SqlPreparedStmt *stmtList; /* List of prepared statements*/
|
||||
SqlPreparedStmt *stmtLast; /* Last statement in the list */
|
||||
int maxStmt; /* The next maximum number of stmtList */
|
||||
int nStmt; /* Number of statements in stmtList */
|
||||
};
|
||||
|
||||
/*
|
||||
** Finalize and free a list of prepared statements
|
||||
*/
|
||||
static void flushStmtCache( SqliteDb *pDb ){
|
||||
SqlPreparedStmt *pPreStmt;
|
||||
|
||||
while( pDb->stmtList ){
|
||||
sqlite3_finalize( pDb->stmtList->pStmt );
|
||||
pPreStmt = pDb->stmtList;
|
||||
pDb->stmtList = pDb->stmtList->pNext;
|
||||
Tcl_Free( (char*)pPreStmt );
|
||||
}
|
||||
pDb->nStmt = 0;
|
||||
pDb->stmtLast = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** TCL calls this procedure when an sqlite3 database command is
|
||||
** deleted.
|
||||
*/
|
||||
static void DbDeleteCmd(void *db){
|
||||
SqliteDb *pDb = (SqliteDb*)db;
|
||||
flushStmtCache(pDb);
|
||||
sqlite3_close(pDb->db);
|
||||
while( pDb->pFunc ){
|
||||
SqlFunc *pFunc = pDb->pFunc;
|
||||
|
@ -215,7 +252,7 @@ static int tclSqlCollate(
|
|||
** This routine is called to evaluate an SQL function implemented
|
||||
** using TCL script.
|
||||
*/
|
||||
static void tclSqlFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
|
||||
static void tclSqlFunc(sqlite3_context *context, int argc, sqlite3_value**argv){
|
||||
SqlFunc *p = sqlite3_user_data(context);
|
||||
Tcl_DString cmd;
|
||||
int i;
|
||||
|
@ -287,6 +324,8 @@ static int auth_callback(
|
|||
case SQLITE_UPDATE : zCode="SQLITE_UPDATE"; break;
|
||||
case SQLITE_ATTACH : zCode="SQLITE_ATTACH"; break;
|
||||
case SQLITE_DETACH : zCode="SQLITE_DETACH"; break;
|
||||
case SQLITE_ALTER_TABLE : zCode="SQLITE_ALTER_TABLE"; break;
|
||||
case SQLITE_REINDEX : zCode="SQLITE_REINDEX"; break;
|
||||
default : zCode="????"; break;
|
||||
}
|
||||
Tcl_DStringInit(&str);
|
||||
|
@ -332,6 +371,54 @@ static Tcl_Obj *dbTextToObj(char const *zText){
|
|||
return pVal;
|
||||
}
|
||||
|
||||
/*
|
||||
** This routine reads a line of text from FILE in, stores
|
||||
** the text in memory obtained from malloc() and returns a pointer
|
||||
** to the text. NULL is returned at end of file, or if malloc()
|
||||
** fails.
|
||||
**
|
||||
** The interface is like "readline" but no command-line editing
|
||||
** is done.
|
||||
**
|
||||
** copied from shell.c from '.import' command
|
||||
*/
|
||||
static char *local_getline(char *zPrompt, FILE *in){
|
||||
char *zLine;
|
||||
int nLine;
|
||||
int n;
|
||||
int eol;
|
||||
|
||||
nLine = 100;
|
||||
zLine = malloc( nLine );
|
||||
if( zLine==0 ) return 0;
|
||||
n = 0;
|
||||
eol = 0;
|
||||
while( !eol ){
|
||||
if( n+100>nLine ){
|
||||
nLine = nLine*2 + 100;
|
||||
zLine = realloc(zLine, nLine);
|
||||
if( zLine==0 ) return 0;
|
||||
}
|
||||
if( fgets(&zLine[n], nLine - n, in)==0 ){
|
||||
if( n==0 ){
|
||||
free(zLine);
|
||||
return 0;
|
||||
}
|
||||
zLine[n] = 0;
|
||||
eol = 1;
|
||||
break;
|
||||
}
|
||||
while( zLine[n] ){ n++; }
|
||||
if( n>0 && zLine[n-1]=='\n' ){
|
||||
n--;
|
||||
zLine[n] = 0;
|
||||
eol = 1;
|
||||
}
|
||||
}
|
||||
zLine = realloc( zLine, n+1 );
|
||||
return zLine;
|
||||
}
|
||||
|
||||
/*
|
||||
** The "sqlite" command below creates a new Tcl command for each
|
||||
** connection it opens to an SQLite database. This routine is invoked
|
||||
|
@ -350,22 +437,25 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
|||
int choice;
|
||||
int rc = TCL_OK;
|
||||
static const char *DB_strs[] = {
|
||||
"authorizer", "busy", "changes",
|
||||
"close", "collate", "collation_needed",
|
||||
"commit_hook", "complete", "errorcode",
|
||||
"eval", "function", "last_insert_rowid",
|
||||
"onecolumn", "progress", "rekey",
|
||||
"timeout", "total_changes", "trace",
|
||||
"authorizer", "busy", "cache",
|
||||
"changes", "close", "collate",
|
||||
"collation_needed", "commit_hook", "complete",
|
||||
"copy", "errorcode", "eval",
|
||||
"function", "last_insert_rowid", "onecolumn",
|
||||
"progress", "rekey", "timeout",
|
||||
"total_changes", "trace", "version",
|
||||
0
|
||||
};
|
||||
enum DB_enum {
|
||||
DB_AUTHORIZER, DB_BUSY, DB_CHANGES,
|
||||
DB_CLOSE, DB_COLLATE, DB_COLLATION_NEEDED,
|
||||
DB_COMMIT_HOOK, DB_COMPLETE, DB_ERRORCODE,
|
||||
DB_EVAL, DB_FUNCTION, DB_LAST_INSERT_ROWID,
|
||||
DB_ONECOLUMN, DB_PROGRESS, DB_REKEY,
|
||||
DB_TIMEOUT, DB_TOTAL_CHANGES, DB_TRACE,
|
||||
DB_AUTHORIZER, DB_BUSY, DB_CACHE,
|
||||
DB_CHANGES, DB_CLOSE, DB_COLLATE,
|
||||
DB_COLLATION_NEEDED, DB_COMMIT_HOOK, DB_COMPLETE,
|
||||
DB_COPY, DB_ERRORCODE, DB_EVAL,
|
||||
DB_FUNCTION, DB_LAST_INSERT_ROWID,DB_ONECOLUMN,
|
||||
DB_PROGRESS, DB_REKEY, DB_TIMEOUT,
|
||||
DB_TOTAL_CHANGES, DB_TRACE, DB_VERSION
|
||||
};
|
||||
/* don't leave trailing commas on DB_enum, it confuses the AIX xlc compiler */
|
||||
|
||||
if( objc<2 ){
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "SUBCOMMAND ...");
|
||||
|
@ -467,6 +557,55 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
|||
break;
|
||||
}
|
||||
|
||||
/* $db cache flush
|
||||
** $db cache size n
|
||||
**
|
||||
** Flush the prepared statement cache, or set the maximum number of
|
||||
** cached statements.
|
||||
*/
|
||||
case DB_CACHE: {
|
||||
char *subCmd;
|
||||
int n;
|
||||
|
||||
if( objc<=2 ){
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "cache option ?arg?");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
subCmd = Tcl_GetStringFromObj( objv[2], 0 );
|
||||
if( *subCmd=='f' && strcmp(subCmd,"flush")==0 ){
|
||||
if( objc!=3 ){
|
||||
Tcl_WrongNumArgs(interp, 2, objv, "flush");
|
||||
return TCL_ERROR;
|
||||
}else{
|
||||
flushStmtCache( pDb );
|
||||
}
|
||||
}else if( *subCmd=='s' && strcmp(subCmd,"size")==0 ){
|
||||
if( objc!=4 ){
|
||||
Tcl_WrongNumArgs(interp, 2, objv, "size n");
|
||||
return TCL_ERROR;
|
||||
}else{
|
||||
if( TCL_ERROR==Tcl_GetIntFromObj(interp, objv[3], &n) ){
|
||||
Tcl_AppendResult( interp, "cannot convert \"",
|
||||
Tcl_GetStringFromObj(objv[3],0), "\" to integer", 0);
|
||||
return TCL_ERROR;
|
||||
}else{
|
||||
if( n<0 ){
|
||||
flushStmtCache( pDb );
|
||||
n = 0;
|
||||
}else if( n>MAX_PREPARED_STMTS ){
|
||||
n = MAX_PREPARED_STMTS;
|
||||
}
|
||||
pDb->maxStmt = n;
|
||||
}
|
||||
}
|
||||
}else{
|
||||
Tcl_AppendResult( interp, "bad option \"",
|
||||
Tcl_GetStringFromObj(objv[0],0), "\": must be flush or size", 0);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* $db changes
|
||||
**
|
||||
** Return the number of rows that were modified, inserted, or deleted by
|
||||
|
@ -557,6 +696,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
|||
strcpy(pCollate->zScript, zScript);
|
||||
if( sqlite3_create_collation(pDb->db, zName, SQLITE_UTF8,
|
||||
pCollate, tclSqlCollate) ){
|
||||
Tcl_SetResult(interp, (char *)sqlite3_errmsg(pDb->db), TCL_VOLATILE);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
break;
|
||||
|
@ -589,6 +729,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
|||
** built-in "info complete" command of Tcl.
|
||||
*/
|
||||
case DB_COMPLETE: {
|
||||
#ifndef SQLITE_OMIT_COMPLETE
|
||||
Tcl_Obj *pResult;
|
||||
int isComplete;
|
||||
if( objc!=3 ){
|
||||
|
@ -598,6 +739,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
|||
isComplete = sqlite3_complete( Tcl_GetStringFromObj(objv[2], 0) );
|
||||
pResult = Tcl_GetObjResult(interp);
|
||||
Tcl_SetBooleanObj(pResult, isComplete);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -636,6 +778,8 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
|||
int nParm; /* Number of entries used in apParm[] */
|
||||
Tcl_Obj *aParm[10]; /* Static space for apParm[] in the common case */
|
||||
Tcl_Obj *pRet; /* Value to be returned */
|
||||
SqlPreparedStmt *pPreStmt; /* Pointer to a prepared statement */
|
||||
int rc2;
|
||||
|
||||
if( choice==DB_ONECOLUMN ){
|
||||
if( objc!=3 ){
|
||||
|
@ -665,29 +809,78 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
|||
Tcl_IncrRefCount(objv[2]);
|
||||
zSql = Tcl_GetStringFromObj(objv[2], 0);
|
||||
while( rc==TCL_OK && zSql[0] ){
|
||||
int i; /* Loop counter */
|
||||
int nVar; /* Number of wildcards in the SQL */
|
||||
int nCol; /* Number of columns in the result set */
|
||||
int i; /* Loop counter */
|
||||
int nVar; /* Number of bind parameters in the pStmt */
|
||||
int nCol; /* Number of columns in the result set */
|
||||
Tcl_Obj **apColName = 0; /* Array of column names */
|
||||
int len; /* String length of zSql */
|
||||
|
||||
/* Compile a single SQL statement */
|
||||
if( SQLITE_OK!=sqlite3_prepare(pDb->db, zSql, -1, &pStmt, &zLeft) ){
|
||||
Tcl_SetObjResult(interp, dbTextToObj(sqlite3_errmsg(pDb->db)));
|
||||
rc = TCL_ERROR;
|
||||
break;
|
||||
/* Try to find a SQL statement that has already been compiled and
|
||||
** which matches the next sequence of SQL.
|
||||
*/
|
||||
pStmt = 0;
|
||||
pPreStmt = pDb->stmtList;
|
||||
len = strlen(zSql);
|
||||
if( pPreStmt && sqlite3_expired(pPreStmt->pStmt) ){
|
||||
flushStmtCache(pDb);
|
||||
pPreStmt = 0;
|
||||
}
|
||||
for(; pPreStmt; pPreStmt=pPreStmt->pNext){
|
||||
int n = pPreStmt->nSql;
|
||||
if( len>=n
|
||||
&& memcmp(pPreStmt->zSql, zSql, n)==0
|
||||
&& (zSql[n]==0 || zSql[n-1]==';')
|
||||
){
|
||||
pStmt = pPreStmt->pStmt;
|
||||
zLeft = &zSql[pPreStmt->nSql];
|
||||
|
||||
/* When a prepared statement is found, unlink it from the
|
||||
** cache list. It will later be added back to the beginning
|
||||
** of the cache list in order to implement LRU replacement.
|
||||
*/
|
||||
if( pPreStmt->pPrev ){
|
||||
pPreStmt->pPrev->pNext = pPreStmt->pNext;
|
||||
}else{
|
||||
pDb->stmtList = pPreStmt->pNext;
|
||||
}
|
||||
if( pPreStmt->pNext ){
|
||||
pPreStmt->pNext->pPrev = pPreStmt->pPrev;
|
||||
}else{
|
||||
pDb->stmtLast = pPreStmt->pPrev;
|
||||
}
|
||||
pDb->nStmt--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* If no prepared statement was found. Compile the SQL text
|
||||
*/
|
||||
if( pStmt==0 ){
|
||||
if( SQLITE_OK!=sqlite3_errcode(pDb->db) ){
|
||||
if( SQLITE_OK!=sqlite3_prepare(pDb->db, zSql, -1, &pStmt, &zLeft) ){
|
||||
Tcl_SetObjResult(interp, dbTextToObj(sqlite3_errmsg(pDb->db)));
|
||||
rc = TCL_ERROR;
|
||||
break;
|
||||
}else{
|
||||
zSql = zLeft;
|
||||
continue;
|
||||
}
|
||||
if( pStmt==0 ){
|
||||
if( SQLITE_OK!=sqlite3_errcode(pDb->db) ){
|
||||
/* A compile-time error in the statement
|
||||
*/
|
||||
Tcl_SetObjResult(interp, dbTextToObj(sqlite3_errmsg(pDb->db)));
|
||||
rc = TCL_ERROR;
|
||||
break;
|
||||
}else{
|
||||
/* The statement was a no-op. Continue to the next statement
|
||||
** in the SQL string.
|
||||
*/
|
||||
zSql = zLeft;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
assert( pPreStmt==0 );
|
||||
}
|
||||
|
||||
/* Bind values to wildcards that begin with $ or : */
|
||||
/* Bind values to parameters that begin with $ or :
|
||||
*/
|
||||
nVar = sqlite3_bind_parameter_count(pStmt);
|
||||
nParm = 0;
|
||||
if( nVar>sizeof(aParm)/sizeof(aParm[0]) ){
|
||||
|
@ -697,7 +890,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
|||
}
|
||||
for(i=1; i<=nVar; i++){
|
||||
const char *zVar = sqlite3_bind_parameter_name(pStmt, i);
|
||||
if( zVar[0]=='$' || zVar[0]==':' ){
|
||||
if( zVar!=0 && (zVar[0]=='$' || zVar[0]==':') ){
|
||||
Tcl_Obj *pVar = Tcl_GetVar2Ex(interp, &zVar[1], 0, 0);
|
||||
if( pVar ){
|
||||
int n;
|
||||
|
@ -723,6 +916,8 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
|||
Tcl_IncrRefCount(pVar);
|
||||
apParm[nParm++] = pVar;
|
||||
}
|
||||
}else{
|
||||
sqlite3_bind_null( pStmt, i );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -827,19 +1022,75 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
|||
Tcl_Free((char*)apParm);
|
||||
}
|
||||
|
||||
/* Finalize the statement. If the result code is SQLITE_SCHEMA, then
|
||||
** try again to execute the same statement
|
||||
/* Reset the statement. If the result code is SQLITE_SCHEMA, then
|
||||
** flush the statement cache and try the statement again.
|
||||
*/
|
||||
if( SQLITE_SCHEMA==sqlite3_finalize(pStmt) ){
|
||||
rc2 = sqlite3_reset(pStmt);
|
||||
if( SQLITE_SCHEMA==rc2 ){
|
||||
/* After a schema change, flush the cache and try to run the
|
||||
** statement again
|
||||
*/
|
||||
flushStmtCache( pDb );
|
||||
sqlite3_finalize(pStmt);
|
||||
if( pPreStmt ) Tcl_Free((char*)pPreStmt);
|
||||
continue;
|
||||
}
|
||||
|
||||
if( SQLITE_OK!=sqlite3_errcode(pDb->db) ){
|
||||
}else if( SQLITE_OK!=rc2 ){
|
||||
/* If a run-time error occurs, report the error and stop reading
|
||||
** the SQL
|
||||
*/
|
||||
Tcl_SetObjResult(interp, dbTextToObj(sqlite3_errmsg(pDb->db)));
|
||||
sqlite3_finalize(pStmt);
|
||||
rc = TCL_ERROR;
|
||||
if( pPreStmt ) Tcl_Free((char*)pPreStmt);
|
||||
break;
|
||||
}else if( pDb->maxStmt<=0 ){
|
||||
/* If the cache is turned off, deallocated the statement */
|
||||
if( pPreStmt ) Tcl_Free((char*)pPreStmt);
|
||||
sqlite3_finalize(pStmt);
|
||||
}else{
|
||||
/* Everything worked and the cache is operational.
|
||||
** Create a new SqlPreparedStmt structure if we need one.
|
||||
** (If we already have one we can just reuse it.)
|
||||
*/
|
||||
if( pPreStmt==0 ){
|
||||
len = zLeft - zSql;
|
||||
pPreStmt = (SqlPreparedStmt*)Tcl_Alloc( sizeof(*pPreStmt) + len );
|
||||
if( pPreStmt==0 ) return TCL_ERROR;
|
||||
pPreStmt->pStmt = pStmt;
|
||||
pPreStmt->nSql = len;
|
||||
memcpy(pPreStmt->zSql, zSql, len);
|
||||
pPreStmt->zSql[len] = 0;
|
||||
}
|
||||
|
||||
/* Add the prepared statement to the beginning of the cache list
|
||||
*/
|
||||
pPreStmt->pNext = pDb->stmtList;
|
||||
pPreStmt->pPrev = 0;
|
||||
if( pDb->stmtList ){
|
||||
pDb->stmtList->pPrev = pPreStmt;
|
||||
}
|
||||
pDb->stmtList = pPreStmt;
|
||||
if( pDb->stmtLast==0 ){
|
||||
assert( pDb->nStmt==0 );
|
||||
pDb->stmtLast = pPreStmt;
|
||||
}else{
|
||||
assert( pDb->nStmt>0 );
|
||||
}
|
||||
pDb->nStmt++;
|
||||
|
||||
/* If we have too many statement in cache, remove the surplus from the
|
||||
** end of the cache list.
|
||||
*/
|
||||
while( pDb->nStmt>pDb->maxStmt ){
|
||||
sqlite3_finalize(pDb->stmtLast->pStmt);
|
||||
pDb->stmtLast = pDb->stmtLast->pPrev;
|
||||
Tcl_Free((char*)pDb->stmtLast->pNext);
|
||||
pDb->stmtLast->pNext = 0;
|
||||
pDb->nStmt--;
|
||||
}
|
||||
}
|
||||
|
||||
/* Proceed to the next statement */
|
||||
zSql = zLeft;
|
||||
}
|
||||
Tcl_DecrRefCount(objv[2]);
|
||||
|
@ -879,7 +1130,13 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
|||
strcpy(pFunc->zScript, zScript);
|
||||
rc = sqlite3_create_function(pDb->db, zName, -1, SQLITE_UTF8,
|
||||
pFunc, tclSqlFunc, 0, 0);
|
||||
if( rc!=SQLITE_OK ) rc = TCL_ERROR;
|
||||
if( rc!=SQLITE_OK ){
|
||||
rc = TCL_ERROR;
|
||||
Tcl_SetResult(interp, (char *)sqlite3_errmsg(pDb->db), TCL_VOLATILE);
|
||||
}else{
|
||||
/* Must flush any cached statements */
|
||||
flushStmtCache( pDb );
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -1040,6 +1297,202 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
|||
break;
|
||||
}
|
||||
|
||||
/* $db copy conflict-algorithm table filename ?SEPARATOR? ?NULLINDICATOR?
|
||||
**
|
||||
** Copy data into table from filename, optionally using SEPARATOR
|
||||
** as column separators. If a column contains a null string, or the
|
||||
** value of NULLINDICATOR, a NULL is inserted for the column.
|
||||
** conflict-algorithm is one of the sqlite conflict algorithms:
|
||||
** rollback, abort, fail, ignore, replace
|
||||
** On success, return the number of lines processed, not necessarily same
|
||||
** as 'db changes' due to conflict-algorithm selected.
|
||||
**
|
||||
** This code is basically an implementation/enhancement of
|
||||
** the sqlite3 shell.c ".import" command.
|
||||
**
|
||||
** This command usage is equivalent to the sqlite2.x COPY statement,
|
||||
** which imports file data into a table using the PostgreSQL COPY file format:
|
||||
** $db copy $conflit_algo $table_name $filename \t \\N
|
||||
*/
|
||||
case DB_COPY: {
|
||||
char *zTable; /* Insert data into this table */
|
||||
char *zFile; /* The file from which to extract data */
|
||||
char *zConflict; /* The conflict algorithm to use */
|
||||
sqlite3_stmt *pStmt; /* A statement */
|
||||
int rc; /* Result code */
|
||||
int nCol; /* Number of columns in the table */
|
||||
int nByte; /* Number of bytes in an SQL string */
|
||||
int i, j; /* Loop counters */
|
||||
int nSep; /* Number of bytes in zSep[] */
|
||||
int nNull; /* Number of bytes in zNull[] */
|
||||
char *zSql; /* An SQL statement */
|
||||
char *zLine; /* A single line of input from the file */
|
||||
char **azCol; /* zLine[] broken up into columns */
|
||||
char *zCommit; /* How to commit changes */
|
||||
FILE *in; /* The input file */
|
||||
int lineno = 0; /* Line number of input file */
|
||||
char zLineNum[80]; /* Line number print buffer */
|
||||
Tcl_Obj *pResult; /* interp result */
|
||||
|
||||
char *zSep;
|
||||
char *zNull;
|
||||
if( objc<5 || objc>7 ){
|
||||
Tcl_WrongNumArgs(interp, 2, objv,
|
||||
"CONFLICT-ALGORITHM TABLE FILENAME ?SEPARATOR? ?NULLINDICATOR?");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
if( objc>=6 ){
|
||||
zSep = Tcl_GetStringFromObj(objv[5], 0);
|
||||
}else{
|
||||
zSep = "\t";
|
||||
}
|
||||
if( objc>=7 ){
|
||||
zNull = Tcl_GetStringFromObj(objv[6], 0);
|
||||
}else{
|
||||
zNull = "";
|
||||
}
|
||||
zConflict = Tcl_GetStringFromObj(objv[2], 0);
|
||||
zTable = Tcl_GetStringFromObj(objv[3], 0);
|
||||
zFile = Tcl_GetStringFromObj(objv[4], 0);
|
||||
nSep = strlen(zSep);
|
||||
nNull = strlen(zNull);
|
||||
if( nSep==0 ){
|
||||
Tcl_AppendResult(interp, "Error: non-null separator required for copy", 0);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
if(sqlite3StrICmp(zConflict, "rollback") != 0 &&
|
||||
sqlite3StrICmp(zConflict, "abort" ) != 0 &&
|
||||
sqlite3StrICmp(zConflict, "fail" ) != 0 &&
|
||||
sqlite3StrICmp(zConflict, "ignore" ) != 0 &&
|
||||
sqlite3StrICmp(zConflict, "replace" ) != 0 ) {
|
||||
Tcl_AppendResult(interp, "Error: \"", zConflict,
|
||||
"\", conflict-algorithm must be one of: rollback, "
|
||||
"abort, fail, ignore, or replace", 0);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
zSql = sqlite3_mprintf("SELECT * FROM '%q'", zTable);
|
||||
if( zSql==0 ){
|
||||
Tcl_AppendResult(interp, "Error: no such table: ", zTable, 0);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
nByte = strlen(zSql);
|
||||
rc = sqlite3_prepare(pDb->db, zSql, 0, &pStmt, 0);
|
||||
sqlite3_free(zSql);
|
||||
if( rc ){
|
||||
Tcl_AppendResult(interp, "Error: ", sqlite3_errmsg(pDb->db), 0);
|
||||
nCol = 0;
|
||||
}else{
|
||||
nCol = sqlite3_column_count(pStmt);
|
||||
}
|
||||
sqlite3_finalize(pStmt);
|
||||
if( nCol==0 ) {
|
||||
return TCL_ERROR;
|
||||
}
|
||||
zSql = malloc( nByte + 50 + nCol*2 );
|
||||
if( zSql==0 ) {
|
||||
Tcl_AppendResult(interp, "Error: can't malloc()", 0);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
sqlite3_snprintf(nByte+50, zSql, "INSERT OR %q INTO '%q' VALUES(?",
|
||||
zConflict, zTable);
|
||||
j = strlen(zSql);
|
||||
for(i=1; i<nCol; i++){
|
||||
zSql[j++] = ',';
|
||||
zSql[j++] = '?';
|
||||
}
|
||||
zSql[j++] = ')';
|
||||
zSql[j] = 0;
|
||||
rc = sqlite3_prepare(pDb->db, zSql, 0, &pStmt, 0);
|
||||
free(zSql);
|
||||
if( rc ){
|
||||
Tcl_AppendResult(interp, "Error: ", sqlite3_errmsg(pDb->db), 0);
|
||||
sqlite3_finalize(pStmt);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
in = fopen(zFile, "rb");
|
||||
if( in==0 ){
|
||||
Tcl_AppendResult(interp, "Error: cannot open file: ", zFile, NULL);
|
||||
sqlite3_finalize(pStmt);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
azCol = malloc( sizeof(azCol[0])*(nCol+1) );
|
||||
if( azCol==0 ) {
|
||||
Tcl_AppendResult(interp, "Error: can't malloc()", 0);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
sqlite3_exec(pDb->db, "BEGIN", 0, 0, 0);
|
||||
zCommit = "COMMIT";
|
||||
while( (zLine = local_getline(0, in))!=0 ){
|
||||
char *z;
|
||||
i = 0;
|
||||
lineno++;
|
||||
azCol[0] = zLine;
|
||||
for(i=0, z=zLine; *z; z++){
|
||||
if( *z==zSep[0] && strncmp(z, zSep, nSep)==0 ){
|
||||
*z = 0;
|
||||
i++;
|
||||
if( i<nCol ){
|
||||
azCol[i] = &z[nSep];
|
||||
z += nSep-1;
|
||||
}
|
||||
}
|
||||
}
|
||||
if( i+1!=nCol ){
|
||||
char *zErr;
|
||||
zErr = malloc(200 + strlen(zFile));
|
||||
sprintf(zErr,"Error: %s line %d: expected %d columns of data but found %d",
|
||||
zFile, lineno, nCol, i+1);
|
||||
Tcl_AppendResult(interp, zErr, 0);
|
||||
free(zErr);
|
||||
zCommit = "ROLLBACK";
|
||||
break;
|
||||
}
|
||||
for(i=0; i<nCol; i++){
|
||||
/* check for null data, if so, bind as null */
|
||||
if ((nNull>0 && strcmp(azCol[i], zNull)==0) || strlen(azCol[i])==0) {
|
||||
sqlite3_bind_null(pStmt, i+1);
|
||||
}else{
|
||||
sqlite3_bind_text(pStmt, i+1, azCol[i], -1, SQLITE_STATIC);
|
||||
}
|
||||
}
|
||||
sqlite3_step(pStmt);
|
||||
rc = sqlite3_reset(pStmt);
|
||||
free(zLine);
|
||||
if( rc!=SQLITE_OK ){
|
||||
Tcl_AppendResult(interp,"Error: ", sqlite3_errmsg(pDb->db), 0);
|
||||
zCommit = "ROLLBACK";
|
||||
break;
|
||||
}
|
||||
}
|
||||
free(azCol);
|
||||
fclose(in);
|
||||
sqlite3_finalize(pStmt);
|
||||
sqlite3_exec(pDb->db, zCommit, 0, 0, 0);
|
||||
|
||||
if( zCommit[0] == 'C' ){
|
||||
/* success, set result as number of lines processed */
|
||||
pResult = Tcl_GetObjResult(interp);
|
||||
Tcl_SetIntObj(pResult, lineno);
|
||||
rc = TCL_OK;
|
||||
}else{
|
||||
/* failure, append lineno where failed */
|
||||
sprintf(zLineNum,"%d",lineno);
|
||||
Tcl_AppendResult(interp,", failed while processing line: ",zLineNum,0);
|
||||
rc = TCL_ERROR;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* $db version
|
||||
**
|
||||
** Return the version string for this database.
|
||||
*/
|
||||
case DB_VERSION: {
|
||||
Tcl_SetResult(interp, (char *)sqlite3_libversion(), TCL_STATIC);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
} /* End of the SWITCH statement */
|
||||
return rc;
|
||||
}
|
||||
|
@ -1146,6 +1599,7 @@ static int DbMain(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
|||
free(zErrMsg);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
p->maxStmt = NUM_PREPARED_STMTS;
|
||||
zArg = Tcl_GetStringFromObj(objv[1], 0);
|
||||
Tcl_CreateObjCommand(interp, zArg, DbObjCmd, (char*)p, DbDeleteCmd);
|
||||
|
||||
|
@ -1163,12 +1617,12 @@ static int DbMain(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
|||
#ifdef SQLITE_TEST
|
||||
{
|
||||
extern void Md5_Register(sqlite3*);
|
||||
#ifdef SQLITE_DEBUG
|
||||
#ifdef SQLITE_MEMDEBUG
|
||||
int mallocfail = sqlite3_iMallocFail;
|
||||
sqlite3_iMallocFail = 0;
|
||||
#endif
|
||||
Md5_Register(p->db);
|
||||
#ifdef SQLITE_DEBUG
|
||||
#ifdef SQLITE_MEMDEBUG
|
||||
sqlite3_iMallocFail = mallocfail;
|
||||
#endif
|
||||
}
|
||||
|
@ -1199,20 +1653,20 @@ int Sqlite3_Init(Tcl_Interp *interp){
|
|||
Tcl_InitStubs(interp, "8.4", 0);
|
||||
Tcl_CreateObjCommand(interp, "sqlite3", (Tcl_ObjCmdProc*)DbMain, 0, 0);
|
||||
Tcl_PkgProvide(interp, "sqlite3", "3.0");
|
||||
Tcl_CreateObjCommand(interp, "sqlite", (Tcl_ObjCmdProc*)DbMain, 0, 0);
|
||||
Tcl_PkgProvide(interp, "sqlite", "3.0");
|
||||
return TCL_OK;
|
||||
}
|
||||
int Tclsqlite3_Init(Tcl_Interp *interp){
|
||||
Tcl_InitStubs(interp, "8.4", 0);
|
||||
Tcl_CreateObjCommand(interp, "sqlite3", (Tcl_ObjCmdProc*)DbMain, 0, 0);
|
||||
Tcl_PkgProvide(interp, "sqlite3", "3.0");
|
||||
return TCL_OK;
|
||||
}
|
||||
int Sqlite3_SafeInit(Tcl_Interp *interp){
|
||||
return TCL_OK;
|
||||
}
|
||||
int Tclsqlite3_SafeInit(Tcl_Interp *interp){
|
||||
return TCL_OK;
|
||||
}
|
||||
int Tclsqlite3_Init(Tcl_Interp *interp){ return Sqlite3_Init(interp); }
|
||||
int Sqlite3_SafeInit(Tcl_Interp *interp){ return TCL_OK; }
|
||||
int Tclsqlite3_SafeInit(Tcl_Interp *interp){ return TCL_OK; }
|
||||
|
||||
#ifndef SQLITE_3_SUFFIX_ONLY
|
||||
int Sqlite_Init(Tcl_Interp *interp){ return Sqlite3_Init(interp); }
|
||||
int Tclsqlite_Init(Tcl_Interp *interp){ return Sqlite3_Init(interp); }
|
||||
int Sqlite_SafeInit(Tcl_Interp *interp){ return TCL_OK; }
|
||||
int Tclsqlite_SafeInit(Tcl_Interp *interp){ return TCL_OK; }
|
||||
#endif
|
||||
|
||||
#ifdef TCLSH
|
||||
/*****************************************************************************
|
||||
|
@ -1285,7 +1739,7 @@ int TCLSH_MAIN(int argc, char **argv){
|
|||
int i;
|
||||
Tcl_SetVar(interp,"argv0",argv[1],TCL_GLOBAL_ONLY);
|
||||
Tcl_SetVar(interp,"argv", "", TCL_GLOBAL_ONLY);
|
||||
for(i=2; i<argc; i++){
|
||||
for(i=3-TCLSH; i<argc; i++){
|
||||
Tcl_SetVar(interp, "argv", argv[i],
|
||||
TCL_GLOBAL_ONLY | TCL_LIST_ELEMENT | TCL_APPEND_VALUE);
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
** individual tokens and sends those tokens one-by-one over to the
|
||||
** parser for analysis.
|
||||
**
|
||||
** $Id: tokenize.c,v 1.91 2004/10/07 19:03:01 drh Exp $
|
||||
** $Id: tokenize.c,v 1.101 2005/02/26 17:31:27 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include "os.h"
|
||||
|
@ -23,106 +23,18 @@
|
|||
#include <stdlib.h>
|
||||
|
||||
/*
|
||||
** This function looks up an identifier to determine if it is a
|
||||
** keyword. If it is a keyword, the token code of that keyword is
|
||||
** 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.c, located in the tool subdirectory of the distribution.
|
||||
** The output of the mkkeywordhash.c program was manually cut and pasted
|
||||
** into this file. When the set of keywords for SQLite changes, you
|
||||
** must modify the mkkeywordhash.c program (to add or remove keywords from
|
||||
** the data tables) then rerun that program to regenerate this function.
|
||||
** 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.
|
||||
*/
|
||||
int sqlite3KeywordCode(const char *z, int n){
|
||||
static const char zText[519] =
|
||||
"ABORTAFTERALLANDASCATTACHBEFOREBEGINBETWEENBYCASCADECASECHECK"
|
||||
"COLLATECOMMITCONFLICTCONSTRAINTCREATECROSSDATABASEDEFAULTDEFERRABLE"
|
||||
"DEFERREDDELETEDESCDETACHDISTINCTDROPEACHELSEENDEXCEPTEXCLUSIVE"
|
||||
"EXPLAINFAILFOREIGNFROMFULLGLOBGROUPHAVINGIGNOREIMMEDIATEINDEX"
|
||||
"INITIALLYINNERINSERTINSTEADINTERSECTINTOISNULLJOINKEYLEFTLIKE"
|
||||
"LIMITMATCHNATURALNOTNULLNULLOFFSETONORDEROUTERPRAGMAPRIMARYRAISE"
|
||||
"REFERENCESREPLACERESTRICTRIGHTROLLBACKROWSELECTSETSTATEMENTTABLE"
|
||||
"TEMPORARYTHENTRANSACTIONTRIGGERUNIONUNIQUEUPDATEUSINGVACUUMVALUES"
|
||||
"VIEWWHENWHERE";
|
||||
static const unsigned char aHash[154] = {
|
||||
0, 75, 82, 0, 0, 97, 80, 0, 83, 0, 0, 0, 0,
|
||||
0, 0, 6, 0, 95, 4, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 96, 86, 8, 0, 26, 13, 7, 19, 15, 0, 0, 32,
|
||||
25, 0, 21, 31, 41, 0, 0, 0, 34, 27, 0, 0, 30,
|
||||
0, 0, 0, 9, 0, 10, 0, 0, 0, 0, 51, 0, 44,
|
||||
43, 0, 45, 40, 0, 29, 39, 35, 0, 0, 20, 0, 59,
|
||||
0, 16, 0, 17, 0, 18, 0, 55, 42, 72, 0, 33, 0,
|
||||
0, 61, 66, 56, 0, 0, 0, 0, 0, 0, 0, 54, 0,
|
||||
0, 0, 0, 0, 74, 50, 76, 64, 52, 0, 0, 0, 0,
|
||||
68, 84, 0, 47, 0, 58, 60, 92, 0, 0, 48, 0, 93,
|
||||
0, 63, 71, 98, 0, 0, 0, 0, 0, 67, 0, 0, 0,
|
||||
0, 87, 0, 0, 0, 0, 0, 90, 88, 0, 94,
|
||||
};
|
||||
static const unsigned char aNext[98] = {
|
||||
0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 12, 0, 0, 0, 0, 0, 0, 11, 0, 0, 0, 0,
|
||||
0, 0, 0, 14, 3, 24, 0, 0, 0, 1, 22, 0, 0,
|
||||
36, 23, 28, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0,
|
||||
0, 49, 37, 0, 0, 0, 38, 0, 53, 0, 57, 62, 0,
|
||||
0, 0, 0, 0, 0, 70, 46, 0, 65, 0, 0, 0, 0,
|
||||
69, 73, 0, 77, 0, 0, 0, 0, 0, 0, 81, 85, 0,
|
||||
91, 79, 78, 0, 0, 89, 0,
|
||||
};
|
||||
static const unsigned char aLen[98] = {
|
||||
5, 5, 3, 3, 2, 3, 6, 6, 5, 7, 2, 7, 4,
|
||||
5, 7, 6, 8, 10, 6, 5, 8, 7, 10, 8, 6, 4,
|
||||
6, 8, 4, 4, 4, 3, 6, 9, 7, 4, 3, 7, 4,
|
||||
4, 4, 5, 6, 6, 9, 2, 5, 9, 5, 6, 7, 9,
|
||||
4, 2, 6, 4, 3, 4, 4, 5, 5, 7, 3, 7, 4,
|
||||
2, 6, 2, 2, 5, 5, 6, 7, 5, 10, 7, 8, 5,
|
||||
8, 3, 6, 3, 9, 5, 4, 9, 4, 11, 7, 5, 6,
|
||||
6, 5, 6, 6, 4, 4, 5,
|
||||
};
|
||||
static const unsigned short int aOffset[98] = {
|
||||
0, 5, 10, 13, 16, 16, 19, 25, 31, 36, 43, 45, 52,
|
||||
56, 61, 68, 74, 82, 92, 98, 103, 111, 118, 128, 136, 142,
|
||||
146, 152, 160, 164, 168, 172, 175, 181, 190, 197, 201, 201, 208,
|
||||
212, 216, 220, 225, 231, 237, 246, 246, 251, 260, 265, 271, 278,
|
||||
287, 291, 291, 297, 301, 304, 308, 312, 317, 322, 329, 329, 336,
|
||||
340, 340, 346, 348, 348, 353, 358, 364, 371, 376, 386, 393, 401,
|
||||
406, 414, 417, 423, 426, 435, 440, 440, 449, 453, 464, 471, 476,
|
||||
482, 488, 493, 499, 505, 509, 513,
|
||||
};
|
||||
static const unsigned char aCode[98] = {
|
||||
TK_ABORT, TK_AFTER, TK_ALL, TK_AND, TK_AS,
|
||||
TK_ASC, TK_ATTACH, TK_BEFORE, TK_BEGIN, TK_BETWEEN,
|
||||
TK_BY, TK_CASCADE, TK_CASE, TK_CHECK, TK_COLLATE,
|
||||
TK_COMMIT, TK_CONFLICT, TK_CONSTRAINT, TK_CREATE, TK_JOIN_KW,
|
||||
TK_DATABASE, TK_DEFAULT, TK_DEFERRABLE, TK_DEFERRED, TK_DELETE,
|
||||
TK_DESC, TK_DETACH, TK_DISTINCT, TK_DROP, TK_EACH,
|
||||
TK_ELSE, TK_END, TK_EXCEPT, TK_EXCLUSIVE, TK_EXPLAIN,
|
||||
TK_FAIL, TK_FOR, TK_FOREIGN, TK_FROM, TK_JOIN_KW,
|
||||
TK_GLOB, TK_GROUP, TK_HAVING, TK_IGNORE, TK_IMMEDIATE,
|
||||
TK_IN, TK_INDEX, TK_INITIALLY, TK_JOIN_KW, TK_INSERT,
|
||||
TK_INSTEAD, TK_INTERSECT, TK_INTO, TK_IS, TK_ISNULL,
|
||||
TK_JOIN, TK_KEY, TK_JOIN_KW, TK_LIKE, TK_LIMIT,
|
||||
TK_MATCH, TK_JOIN_KW, TK_NOT, TK_NOTNULL, TK_NULL,
|
||||
TK_OF, TK_OFFSET, TK_ON, TK_OR, TK_ORDER,
|
||||
TK_JOIN_KW, TK_PRAGMA, TK_PRIMARY, TK_RAISE, TK_REFERENCES,
|
||||
TK_REPLACE, TK_RESTRICT, TK_JOIN_KW, TK_ROLLBACK, TK_ROW,
|
||||
TK_SELECT, TK_SET, TK_STATEMENT, TK_TABLE, TK_TEMP,
|
||||
TK_TEMP, TK_THEN, TK_TRANSACTION,TK_TRIGGER, TK_UNION,
|
||||
TK_UNIQUE, TK_UPDATE, TK_USING, TK_VACUUM, TK_VALUES,
|
||||
TK_VIEW, TK_WHEN, TK_WHERE,
|
||||
};
|
||||
int h, i;
|
||||
if( n<2 ) return TK_ID;
|
||||
h = (sqlite3UpperToLower[((unsigned char*)z)[0]]*5 +
|
||||
sqlite3UpperToLower[((unsigned char*)z)[n-1]]*3 +
|
||||
n) % 154;
|
||||
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;
|
||||
}
|
||||
#include "keywordhash.h"
|
||||
|
||||
|
||||
/*
|
||||
** If X is a character that can be used in an identifier and
|
||||
|
@ -137,9 +49,15 @@ int sqlite3KeywordCode(const char *z, int n){
|
|||
** with the high-order bit set. The latter rule means that
|
||||
** any sequence of UTF-8 characters or characters taken from
|
||||
** an extended ISO8859 character set can form an identifier.
|
||||
**
|
||||
** 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.
|
||||
*/
|
||||
static const char isIdChar[] = {
|
||||
/* 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 */
|
||||
|
@ -147,13 +65,13 @@ static const char isIdChar[] = {
|
|||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, /* 7x */
|
||||
};
|
||||
|
||||
#define IdChar(C) (((c=C)&0x80)!=0 || (c>0x2f && isIdChar[c-0x30]))
|
||||
#define IdChar(C) (((c=C)&0x80)!=0 || (c>0x1f && isIdChar[c-0x20]))
|
||||
|
||||
/*
|
||||
** Return the length of the token that begins at z[0].
|
||||
** Store the token type in *tokenType before returning.
|
||||
*/
|
||||
static int sqliteGetToken(const unsigned char *z, int *tokenType){
|
||||
static int getToken(const unsigned char *z, int *tokenType){
|
||||
int i, c;
|
||||
switch( *z ){
|
||||
case ' ': case '\t': case '\n': case '\f': case '\r': {
|
||||
|
@ -265,6 +183,11 @@ static int sqliteGetToken(const unsigned char *z, int *tokenType){
|
|||
*tokenType = TK_BITNOT;
|
||||
return 1;
|
||||
}
|
||||
case '#': {
|
||||
for(i=1; isdigit(z[i]) || (i==1 && z[1]=='-'); i++){}
|
||||
*tokenType = TK_REGISTER;
|
||||
return i;
|
||||
}
|
||||
case '\'': case '"': {
|
||||
int delim = z[0];
|
||||
for(i=1; (c=z[i])!=0; i++){
|
||||
|
@ -288,6 +211,7 @@ static int sqliteGetToken(const unsigned char *z, int *tokenType){
|
|||
case '5': case '6': case '7': case '8': case '9': {
|
||||
*tokenType = TK_INTEGER;
|
||||
for(i=1; isdigit(z[i]); i++){}
|
||||
#ifndef SQLITE_OMIT_FLOATING_POINT
|
||||
if( z[i]=='.' && isdigit(z[i+1]) ){
|
||||
i += 2;
|
||||
while( isdigit(z[i]) ){ i++; }
|
||||
|
@ -302,6 +226,7 @@ static int sqliteGetToken(const unsigned char *z, int *tokenType){
|
|||
while( isdigit(z[i]) ){ i++; }
|
||||
*tokenType = TK_FLOAT;
|
||||
}
|
||||
#endif
|
||||
return i;
|
||||
}
|
||||
case '[': {
|
||||
|
@ -319,6 +244,7 @@ static int sqliteGetToken(const unsigned char *z, int *tokenType){
|
|||
*tokenType = i>1 ? TK_VARIABLE : TK_ILLEGAL;
|
||||
return i;
|
||||
}
|
||||
#ifndef SQLITE_OMIT_TCL_VARIABLE
|
||||
case '$': {
|
||||
*tokenType = TK_VARIABLE;
|
||||
if( z[1]=='{' ){
|
||||
|
@ -355,7 +281,9 @@ static int sqliteGetToken(const unsigned char *z, int *tokenType){
|
|||
if( n==0 ) *tokenType = TK_ILLEGAL;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#ifndef SQLITE_OMIT_BLOB_LITERAL
|
||||
case 'x': case 'X': {
|
||||
if( (c=z[1])=='\'' || c=='"' ){
|
||||
int delim = c;
|
||||
|
@ -375,18 +303,22 @@ static int sqliteGetToken(const unsigned char *z, int *tokenType){
|
|||
}
|
||||
/* Otherwise fall through to the next case */
|
||||
}
|
||||
#endif
|
||||
default: {
|
||||
if( !IdChar(*z) ){
|
||||
break;
|
||||
}
|
||||
for(i=1; IdChar(z[i]); i++){}
|
||||
*tokenType = sqlite3KeywordCode((char*)z, 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
|
||||
|
@ -426,7 +358,7 @@ int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzErrMsg){
|
|||
assert( i>=0 );
|
||||
pParse->sLastToken.z = &zSql[i];
|
||||
assert( pParse->sLastToken.dyn==0 );
|
||||
pParse->sLastToken.n = sqliteGetToken((unsigned char*)&zSql[i], &tokenType);
|
||||
pParse->sLastToken.n = getToken((unsigned char*)&zSql[i],&tokenType);
|
||||
i += pParse->sLastToken.n;
|
||||
switch( tokenType ){
|
||||
case TK_SPACE:
|
||||
|
@ -486,7 +418,7 @@ abort_parse:
|
|||
pParse->zErrMsg = 0;
|
||||
if( !nErr ) nErr++;
|
||||
}
|
||||
if( pParse->pVdbe && pParse->nErr>0 ){
|
||||
if( pParse->pVdbe && pParse->nErr>0 && pParse->nested==0 ){
|
||||
sqlite3VdbeDelete(pParse->pVdbe);
|
||||
pParse->pVdbe = 0;
|
||||
}
|
||||
|
@ -499,18 +431,23 @@ abort_parse:
|
|||
return nErr;
|
||||
}
|
||||
|
||||
/* The sqlite3_complete() API may be omitted (to save code space) by
|
||||
** defining the following symbol.
|
||||
*/
|
||||
#ifndef SQLITE_OMIT_COMPLETE
|
||||
|
||||
/*
|
||||
** Token types used by the sqlite3_complete() routine. See the header
|
||||
** comments on that procedure for additional information.
|
||||
*/
|
||||
#define tkEXPLAIN 0
|
||||
#define tkCREATE 1
|
||||
#define tkTEMP 2
|
||||
#define tkTRIGGER 3
|
||||
#define tkEND 4
|
||||
#define tkSEMI 5
|
||||
#define tkWS 6
|
||||
#define tkOTHER 7
|
||||
#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.
|
||||
|
@ -525,16 +462,16 @@ abort_parse:
|
|||
** returns 1 if it ends in the START state and 0 if it ends
|
||||
** in any other state.
|
||||
**
|
||||
** (1) EXPLAIN The keyword EXPLAIN has been seen at the beginning of
|
||||
** (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.
|
||||
**
|
||||
** (2) CREATE The keyword CREATE has been seen at the beginning of a
|
||||
** (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
|
||||
**
|
||||
** (3) NORMAL We are in the middle of statement which ends with a single
|
||||
** semicolon.
|
||||
**
|
||||
** (4) TRIGGER We are in the middle of a trigger definition that must be
|
||||
** ended by a semicolon, the keyword END, and another semicolon.
|
||||
**
|
||||
|
@ -547,36 +484,51 @@ abort_parse:
|
|||
** Transitions between states above are determined by tokens extracted
|
||||
** from the input. The following tokens are significant:
|
||||
**
|
||||
** (0) tkEXPLAIN The "explain" keyword.
|
||||
** (1) tkCREATE The "create" keyword.
|
||||
** (2) tkTEMP The "temp" or "temporary" keyword.
|
||||
** (3) tkTRIGGER The "trigger" keyword.
|
||||
** (4) tkEND The "end" keyword.
|
||||
** (5) tkSEMI A semicolon.
|
||||
** (6) tkWS Whitespace
|
||||
** (7) tkOTHER Any other SQL token.
|
||||
** (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 */
|
||||
|
||||
/* The following matrix defines the transition from one state to another
|
||||
** according to what token is seen. trans[state][token] returns the
|
||||
** next state.
|
||||
#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: ** EXPLAIN CREATE TEMP TRIGGER END SEMI WS OTHER */
|
||||
/* 0 START: */ { 1, 2, 3, 3, 3, 0, 0, 3, },
|
||||
/* 1 EXPLAIN: */ { 3, 2, 3, 3, 3, 0, 1, 3, },
|
||||
/* 2 CREATE: */ { 3, 3, 2, 4, 3, 0, 2, 3, },
|
||||
/* 3 NORMAL: */ { 3, 3, 3, 3, 3, 0, 3, 3, },
|
||||
/* 4 TRIGGER: */ { 4, 4, 4, 4, 4, 5, 4, 4, },
|
||||
/* 5 SEMI: */ { 4, 4, 4, 4, 6, 5, 5, 4, },
|
||||
/* 6 END: */ { 4, 4, 4, 4, 4, 0, 6, 4, },
|
||||
/* 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 ){
|
||||
|
@ -636,6 +588,9 @@ int sqlite3_complete(const char *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 ){
|
||||
|
@ -660,9 +615,13 @@ int sqlite3_complete(const char *zSql){
|
|||
case 'e': case 'E': {
|
||||
if( nId==3 && sqlite3StrNICmp(zSql, "end", 3)==0 ){
|
||||
token = tkEND;
|
||||
}else if( nId==7 && sqlite3StrNICmp(zSql, "explain", 7)==0 ){
|
||||
}else
|
||||
#ifndef SQLITE_OMIT_EXPLAIN
|
||||
if( nId==7 && sqlite3StrNICmp(zSql, "explain", 7)==0 ){
|
||||
token = tkEXPLAIN;
|
||||
}else{
|
||||
}else
|
||||
#endif
|
||||
{
|
||||
token = tkOTHER;
|
||||
}
|
||||
break;
|
||||
|
@ -672,6 +631,7 @@ int sqlite3_complete(const char *zSql){
|
|||
break;
|
||||
}
|
||||
}
|
||||
#endif /* SQLITE_OMIT_TRIGGER */
|
||||
zSql += nId-1;
|
||||
}else{
|
||||
/* Operators and special symbols */
|
||||
|
@ -686,6 +646,7 @@ int sqlite3_complete(const char *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
|
||||
|
@ -705,3 +666,5 @@ int sqlite3_complete16(const void *zSql){
|
|||
sqlite3ValueFree(pVal);
|
||||
return rc;
|
||||
}
|
||||
#endif /* SQLITE_OMIT_UTF16 */
|
||||
#endif /* SQLITE_OMIT_COMPLETE */
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
*/
|
||||
#include "sqliteInt.h"
|
||||
|
||||
#ifndef SQLITE_OMIT_TRIGGER
|
||||
/*
|
||||
** Delete a linked list of TriggerStep structures.
|
||||
*/
|
||||
|
@ -50,7 +51,7 @@ void sqlite3BeginTrigger(
|
|||
Expr *pWhen, /* WHEN clause */
|
||||
int isTemp /* True if the TEMPORARY keyword is present */
|
||||
){
|
||||
Trigger *pTrigger;
|
||||
Trigger *pTrigger = 0;
|
||||
Table *pTab;
|
||||
char *zName = 0; /* Name of the trigger */
|
||||
sqlite3 *db = pParse->db;
|
||||
|
@ -110,9 +111,7 @@ void sqlite3BeginTrigger(
|
|||
}
|
||||
|
||||
/* Do not create a trigger on a system table */
|
||||
if( (iDb!=1 && sqlite3StrICmp(pTab->zName, MASTER_NAME)==0) ||
|
||||
(iDb==1 && sqlite3StrICmp(pTab->zName, TEMP_MASTER_NAME)==0)
|
||||
){
|
||||
if( sqlite3StrNICmp(pTab->zName, "sqlite_", 7)==0 ){
|
||||
sqlite3ErrorMsg(pParse, "cannot create trigger on system table");
|
||||
pParse->nErr++;
|
||||
goto trigger_cleanup;
|
||||
|
@ -162,11 +161,10 @@ void sqlite3BeginTrigger(
|
|||
pTrigger->name = zName;
|
||||
zName = 0;
|
||||
pTrigger->table = sqliteStrDup(pTableName->a[0].zName);
|
||||
if( sqlite3_malloc_failed ) goto trigger_cleanup;
|
||||
pTrigger->iDb = iDb;
|
||||
pTrigger->iTabDb = pTab->iDb;
|
||||
pTrigger->op = op;
|
||||
pTrigger->tr_tm = tr_tm;
|
||||
pTrigger->tr_tm = tr_tm==TK_BEFORE ? TRIGGER_BEFORE : TRIGGER_AFTER;
|
||||
pTrigger->pWhen = sqlite3ExprDup(pWhen);
|
||||
pTrigger->pColumns = sqlite3IdListDup(pColumns);
|
||||
pTrigger->foreach = foreach;
|
||||
|
@ -179,6 +177,11 @@ trigger_cleanup:
|
|||
sqlite3SrcListDelete(pTableName);
|
||||
sqlite3IdListDelete(pColumns);
|
||||
sqlite3ExprDelete(pWhen);
|
||||
if( !pParse->pNewTrigger ){
|
||||
sqlite3DeleteTrigger(pTrigger);
|
||||
}else{
|
||||
assert( pParse->pNewTrigger==pTrigger );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -190,20 +193,20 @@ void sqlite3FinishTrigger(
|
|||
TriggerStep *pStepList, /* The triggered program */
|
||||
Token *pAll /* Token that describes the complete CREATE TRIGGER */
|
||||
){
|
||||
Trigger *nt = 0; /* The trigger whose construction is finishing up */
|
||||
Trigger *pTrig = 0; /* The trigger whose construction is finishing up */
|
||||
sqlite3 *db = pParse->db; /* The database */
|
||||
DbFixer sFix;
|
||||
|
||||
if( pParse->nErr || pParse->pNewTrigger==0 ) goto triggerfinish_cleanup;
|
||||
nt = pParse->pNewTrigger;
|
||||
pTrig = pParse->pNewTrigger;
|
||||
pParse->pNewTrigger = 0;
|
||||
nt->step_list = pStepList;
|
||||
pTrig->step_list = pStepList;
|
||||
while( pStepList ){
|
||||
pStepList->pTrig = nt;
|
||||
pStepList->pTrig = pTrig;
|
||||
pStepList = pStepList->pNext;
|
||||
}
|
||||
if( sqlite3FixInit(&sFix, pParse, nt->iDb, "trigger", &nt->nameToken)
|
||||
&& sqlite3FixTriggerStep(&sFix, nt->step_list) ){
|
||||
if( sqlite3FixInit(&sFix, pParse, pTrig->iDb, "trigger", &pTrig->nameToken)
|
||||
&& sqlite3FixTriggerStep(&sFix, pTrig->step_list) ){
|
||||
goto triggerfinish_cleanup;
|
||||
}
|
||||
|
||||
|
@ -229,35 +232,37 @@ void sqlite3FinishTrigger(
|
|||
/* Make an entry in the sqlite_master table */
|
||||
v = sqlite3GetVdbe(pParse);
|
||||
if( v==0 ) goto triggerfinish_cleanup;
|
||||
sqlite3BeginWriteOperation(pParse, 0, nt->iDb);
|
||||
sqlite3OpenMasterTable(v, nt->iDb);
|
||||
sqlite3BeginWriteOperation(pParse, 0, pTrig->iDb);
|
||||
sqlite3OpenMasterTable(v, pTrig->iDb);
|
||||
addr = sqlite3VdbeAddOpList(v, ArraySize(insertTrig), insertTrig);
|
||||
sqlite3VdbeChangeP3(v, addr+2, nt->name, 0);
|
||||
sqlite3VdbeChangeP3(v, addr+3, nt->table, 0);
|
||||
sqlite3VdbeChangeP3(v, addr+2, pTrig->name, 0);
|
||||
sqlite3VdbeChangeP3(v, addr+3, pTrig->table, 0);
|
||||
sqlite3VdbeChangeP3(v, addr+6, pAll->z, pAll->n);
|
||||
if( nt->iDb!=0 ){
|
||||
sqlite3ChangeCookie(db, v, nt->iDb);
|
||||
}
|
||||
sqlite3ChangeCookie(db, v, pTrig->iDb);
|
||||
sqlite3VdbeAddOp(v, OP_Close, 0, 0);
|
||||
sqlite3VdbeOp3(v, OP_ParseSchema, nt->iDb, 0,
|
||||
sqlite3MPrintf("type='trigger' AND name='%q'", nt->name), P3_DYNAMIC);
|
||||
sqlite3VdbeOp3(v, OP_ParseSchema, pTrig->iDb, 0,
|
||||
sqlite3MPrintf("type='trigger' AND name='%q'", pTrig->name), P3_DYNAMIC);
|
||||
}
|
||||
|
||||
if( db->init.busy ){
|
||||
Table *pTab;
|
||||
sqlite3HashInsert(&db->aDb[nt->iDb].trigHash,
|
||||
nt->name, strlen(nt->name)+1, nt);
|
||||
pTab = sqlite3LocateTable(pParse, nt->table, db->aDb[nt->iTabDb].zName);
|
||||
Trigger *pDel;
|
||||
pDel = sqlite3HashInsert(&db->aDb[pTrig->iDb].trigHash,
|
||||
pTrig->name, strlen(pTrig->name)+1, pTrig);
|
||||
if( pDel ){
|
||||
assert( sqlite3_malloc_failed && pDel==pTrig );
|
||||
goto triggerfinish_cleanup;
|
||||
}
|
||||
pTab = sqlite3LocateTable(pParse,pTrig->table,db->aDb[pTrig->iTabDb].zName);
|
||||
assert( pTab!=0 );
|
||||
nt->pNext = pTab->pTrigger;
|
||||
pTab->pTrigger = nt;
|
||||
nt = 0;
|
||||
pTrig->pNext = pTab->pTrigger;
|
||||
pTab->pTrigger = pTrig;
|
||||
pTrig = 0;
|
||||
}
|
||||
|
||||
triggerfinish_cleanup:
|
||||
sqlite3DeleteTrigger(nt);
|
||||
sqlite3DeleteTrigger(pParse->pNewTrigger);
|
||||
pParse->pNewTrigger = 0;
|
||||
sqlite3DeleteTrigger(pTrig);
|
||||
assert( !pParse->pNewTrigger );
|
||||
sqlite3DeleteTriggerStep(pStepList);
|
||||
}
|
||||
|
||||
|
@ -332,18 +337,23 @@ TriggerStep *sqlite3TriggerInsertStep(
|
|||
int orconf /* The conflict algorithm (OE_Abort, OE_Replace, etc.) */
|
||||
){
|
||||
TriggerStep *pTriggerStep = sqliteMalloc(sizeof(TriggerStep));
|
||||
if( pTriggerStep==0 ) return 0;
|
||||
|
||||
assert(pEList == 0 || pSelect == 0);
|
||||
assert(pEList != 0 || pSelect != 0);
|
||||
|
||||
pTriggerStep->op = TK_INSERT;
|
||||
pTriggerStep->pSelect = pSelect;
|
||||
pTriggerStep->target = *pTableName;
|
||||
pTriggerStep->pIdList = pColumn;
|
||||
pTriggerStep->pExprList = pEList;
|
||||
pTriggerStep->orconf = orconf;
|
||||
sqlitePersistTriggerStep(pTriggerStep);
|
||||
if( pTriggerStep ){
|
||||
pTriggerStep->op = TK_INSERT;
|
||||
pTriggerStep->pSelect = pSelect;
|
||||
pTriggerStep->target = *pTableName;
|
||||
pTriggerStep->pIdList = pColumn;
|
||||
pTriggerStep->pExprList = pEList;
|
||||
pTriggerStep->orconf = orconf;
|
||||
sqlitePersistTriggerStep(pTriggerStep);
|
||||
}else{
|
||||
sqlite3IdListDelete(pColumn);
|
||||
sqlite3ExprListDelete(pEList);
|
||||
sqlite3SelectDup(pSelect);
|
||||
}
|
||||
|
||||
return pTriggerStep;
|
||||
}
|
||||
|
@ -555,52 +565,38 @@ static int checkColumnOverLap(IdList *pIdList, ExprList *pEList){
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* A global variable that is TRUE if we should always set up temp tables for
|
||||
* for triggers, even if there are no triggers to code. This is used to test
|
||||
* how much overhead the triggers algorithm is causing.
|
||||
*
|
||||
* This flag can be set or cleared using the "trigger_overhead_test" pragma.
|
||||
* The pragma is not documented since it is not really part of the interface
|
||||
* to SQLite, just the test procedure.
|
||||
*/
|
||||
int sqlite3_always_code_trigger_setup = 0;
|
||||
|
||||
/*
|
||||
* Returns true if a trigger matching op, tr_tm and foreach that is NOT already
|
||||
* on the Parse objects trigger-stack (to prevent recursive trigger firing) is
|
||||
* found in the list specified as pTrigger.
|
||||
*/
|
||||
** 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 */
|
||||
Trigger *pTrigger, /* A list of triggers associated with a table */
|
||||
Table *pTab, /* The table the contains the triggers */
|
||||
int op, /* one of TK_DELETE, TK_INSERT, TK_UPDATE */
|
||||
int tr_tm, /* one of TK_BEFORE, TK_AFTER */
|
||||
int foreach, /* one of TK_ROW or TK_STATEMENT */
|
||||
ExprList *pChanges /* Columns that change in an UPDATE statement */
|
||||
){
|
||||
Trigger * pTriggerCursor;
|
||||
Trigger *pTrigger = pTab->pTrigger;
|
||||
int mask = 0;
|
||||
|
||||
if( sqlite3_always_code_trigger_setup ){
|
||||
return 1;
|
||||
}
|
||||
|
||||
pTriggerCursor = pTrigger;
|
||||
while( pTriggerCursor ){
|
||||
if( pTriggerCursor->op == op &&
|
||||
pTriggerCursor->tr_tm == tr_tm &&
|
||||
pTriggerCursor->foreach == foreach &&
|
||||
checkColumnOverLap(pTriggerCursor->pColumns, pChanges) ){
|
||||
TriggerStack * ss;
|
||||
while( pTrigger ){
|
||||
if( pTrigger->op==op && checkColumnOverLap(pTrigger->pColumns, pChanges) ){
|
||||
TriggerStack *ss;
|
||||
ss = pParse->trigStack;
|
||||
while( ss && ss->pTrigger != pTrigger ){
|
||||
while( ss && ss->pTrigger!=pTab->pTrigger ){
|
||||
ss = ss->pNext;
|
||||
}
|
||||
if( !ss )return 1;
|
||||
if( ss==0 ){
|
||||
mask |= pTrigger->tr_tm;
|
||||
}
|
||||
}
|
||||
pTriggerCursor = pTriggerCursor->pNext;
|
||||
pTrigger = pTrigger->pNext;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return mask;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -658,6 +654,7 @@ static int codeTriggerProgram(
|
|||
Select * ss = sqlite3SelectDup(pTriggerStep->pSelect);
|
||||
assert(ss);
|
||||
assert(ss->pSrc);
|
||||
sqlite3SelectResolve(pParse, ss, 0);
|
||||
sqlite3Select(pParse, ss, SRT_Discard, 0, 0, 0, 0, 0);
|
||||
sqlite3SelectDelete(ss);
|
||||
break;
|
||||
|
@ -726,7 +723,7 @@ 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 TK_BEFORE, TK_AFTER */
|
||||
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 */
|
||||
|
@ -738,7 +735,7 @@ int sqlite3CodeRowTrigger(
|
|||
TriggerStack trigStackEntry;
|
||||
|
||||
assert(op == TK_UPDATE || op == TK_INSERT || op == TK_DELETE);
|
||||
assert(tr_tm == TK_BEFORE || tr_tm == TK_AFTER );
|
||||
assert(tr_tm == TRIGGER_BEFORE || tr_tm == TRIGGER_AFTER );
|
||||
|
||||
assert(newIdx != -1 || oldIdx != -1);
|
||||
|
||||
|
@ -747,8 +744,7 @@ int sqlite3CodeRowTrigger(
|
|||
int fire_this = 0;
|
||||
|
||||
/* determine whether we should code this trigger */
|
||||
if( pTrigger->op == op && pTrigger->tr_tm == tr_tm &&
|
||||
pTrigger->foreach == TK_ROW ){
|
||||
if( pTrigger->op == op && pTrigger->tr_tm == tr_tm ){
|
||||
fire_this = 1;
|
||||
for(pStack=pParse->trigStack; pStack; pStack=pStack->pNext){
|
||||
if( pStack->pTrigger==pTrigger ){
|
||||
|
@ -763,11 +759,12 @@ int sqlite3CodeRowTrigger(
|
|||
|
||||
if( fire_this ){
|
||||
int endTrigger;
|
||||
SrcList dummyTablist;
|
||||
Expr * whenExpr;
|
||||
AuthContext sContext;
|
||||
NameContext sNC;
|
||||
|
||||
dummyTablist.nSrc = 0;
|
||||
memset(&sNC, 0, sizeof(sNC));
|
||||
sNC.pParse = pParse;
|
||||
|
||||
/* Push an entry on to the trigger stack */
|
||||
trigStackEntry.pTrigger = pTrigger;
|
||||
|
@ -782,7 +779,7 @@ int sqlite3CodeRowTrigger(
|
|||
/* code the WHEN clause */
|
||||
endTrigger = sqlite3VdbeMakeLabel(pParse->pVdbe);
|
||||
whenExpr = sqlite3ExprDup(pTrigger->pWhen);
|
||||
if( sqlite3ExprResolveIds(pParse, &dummyTablist, 0, whenExpr) ){
|
||||
if( sqlite3ExprResolveNames(&sNC, whenExpr) ){
|
||||
pParse->trigStack = trigStackEntry.pNext;
|
||||
sqlite3ExprDelete(whenExpr);
|
||||
return 1;
|
||||
|
@ -802,3 +799,4 @@ int sqlite3CodeRowTrigger(
|
|||
}
|
||||
return 0;
|
||||
}
|
||||
#endif /* !defined(SQLITE_OMIT_TRIGGER) */
|
||||
|
|
|
@ -12,10 +12,45 @@
|
|||
** This file contains C code routines that are called by the parser
|
||||
** to handle UPDATE statements.
|
||||
**
|
||||
** $Id: update.c,v 1.90 2004/10/05 02:41:43 drh Exp $
|
||||
** $Id: update.c,v 1.105 2005/03/09 12:26:51 danielk1977 Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
|
||||
/*
|
||||
** The most recently coded instruction was an OP_Column to retrieve column
|
||||
** 'i' of table pTab. This routine sets the P3 parameter of the
|
||||
** 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 = sqlite3VdbeDb(v)->enc;
|
||||
Column *pCol = &pTab->aCol[i];
|
||||
sqlite3ValueFromExpr(pCol->pDflt, enc, pCol->affinity, &pValue);
|
||||
sqlite3VdbeChangeP3(v, -1, (const char *)pValue, P3_MEM);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Process an UPDATE statement.
|
||||
**
|
||||
|
@ -48,12 +83,13 @@ void sqlite3Update(
|
|||
int chngRecno; /* True if the record number is being changed */
|
||||
Expr *pRecnoExpr = 0; /* Expression defining the new record number */
|
||||
int openAll = 0; /* True if all indices need to be opened */
|
||||
int isView; /* Trying to update a view */
|
||||
AuthContext sContext; /* The authorization context */
|
||||
NameContext sNC; /* The name-context to resolve expressions in */
|
||||
|
||||
int before_triggers; /* True if there are any BEFORE triggers */
|
||||
int after_triggers; /* True if there are any AFTER triggers */
|
||||
int row_triggers_exist = 0; /* True if any row triggers exist */
|
||||
#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 */
|
||||
|
@ -67,13 +103,23 @@ void sqlite3Update(
|
|||
*/
|
||||
pTab = sqlite3SrcListLookup(pParse, pTabList);
|
||||
if( pTab==0 ) goto update_cleanup;
|
||||
before_triggers = sqlite3TriggersExist(pParse, pTab->pTrigger,
|
||||
TK_UPDATE, TK_BEFORE, TK_ROW, pChanges);
|
||||
after_triggers = sqlite3TriggersExist(pParse, pTab->pTrigger,
|
||||
TK_UPDATE, TK_AFTER, TK_ROW, pChanges);
|
||||
row_triggers_exist = before_triggers || after_triggers;
|
||||
|
||||
/* 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;
|
||||
if( sqlite3IsReadOnly(pParse, pTab, before_triggers) ){
|
||||
#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( isView ){
|
||||
|
@ -88,7 +134,7 @@ void sqlite3Update(
|
|||
/* If there are FOR EACH ROW triggers, allocate cursors for the
|
||||
** special OLD and NEW tables
|
||||
*/
|
||||
if( row_triggers_exist ){
|
||||
if( triggers_exist ){
|
||||
newIdx = pParse->nTab++;
|
||||
oldIdx = pParse->nTab++;
|
||||
}
|
||||
|
@ -103,6 +149,11 @@ void sqlite3Update(
|
|||
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
|
||||
|
@ -111,8 +162,7 @@ void sqlite3Update(
|
|||
*/
|
||||
chngRecno = 0;
|
||||
for(i=0; i<pChanges->nExpr; i++){
|
||||
if( sqlite3ExprResolveAndCheck(pParse, pTabList, 0,
|
||||
pChanges->a[i].pExpr, 0, 0) ){
|
||||
if( sqlite3ExprResolveNames(&sNC, pChanges->a[i].pExpr) ){
|
||||
goto update_cleanup;
|
||||
}
|
||||
for(j=0; j<pTab->nCol; j++){
|
||||
|
@ -188,7 +238,7 @@ void sqlite3Update(
|
|||
/* Resolve the column names in all the expressions in the
|
||||
** WHERE clause.
|
||||
*/
|
||||
if( sqlite3ExprResolveAndCheck(pParse, pTabList, 0, pWhere, 0, 0) ){
|
||||
if( sqlite3ExprResolveNames(&sNC, pWhere) ){
|
||||
goto update_cleanup;
|
||||
}
|
||||
|
||||
|
@ -202,7 +252,7 @@ void sqlite3Update(
|
|||
*/
|
||||
v = sqlite3GetVdbe(pParse);
|
||||
if( v==0 ) goto update_cleanup;
|
||||
sqlite3VdbeCountChanges(v);
|
||||
if( pParse->nested==0 ) sqlite3VdbeCountChanges(v);
|
||||
sqlite3BeginWriteOperation(pParse, 1, pTab->iDb);
|
||||
|
||||
/* If we are trying to update a view, construct that view into
|
||||
|
@ -217,11 +267,12 @@ void sqlite3Update(
|
|||
|
||||
/* Begin the database scan
|
||||
*/
|
||||
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 1, 0);
|
||||
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 0, 0);
|
||||
if( pWInfo==0 ) goto update_cleanup;
|
||||
|
||||
/* Remember the index of every item to be updated.
|
||||
*/
|
||||
sqlite3VdbeAddOp(v, OP_Recno, iCur, 0);
|
||||
sqlite3VdbeAddOp(v, OP_ListWrite, 0, 0);
|
||||
|
||||
/* End the database scan loop.
|
||||
|
@ -234,7 +285,7 @@ void sqlite3Update(
|
|||
sqlite3VdbeAddOp(v, OP_Integer, 0, 0);
|
||||
}
|
||||
|
||||
if( row_triggers_exist ){
|
||||
if( triggers_exist ){
|
||||
/* Create pseudo-tables for NEW and OLD
|
||||
*/
|
||||
sqlite3VdbeAddOp(v, OP_OpenPseudo, oldIdx, 0);
|
||||
|
@ -266,11 +317,11 @@ void sqlite3Update(
|
|||
/* Generate the NEW table
|
||||
*/
|
||||
if( chngRecno ){
|
||||
sqlite3ExprCode(pParse, pRecnoExpr);
|
||||
sqlite3ExprCodeAndCache(pParse, pRecnoExpr);
|
||||
}else{
|
||||
sqlite3VdbeAddOp(v, OP_Recno, iCur, 0);
|
||||
}
|
||||
for(i=0; i<pTab->nCol; i++){ /* TODO: Factor out this loop as common code */
|
||||
for(i=0; i<pTab->nCol; i++){
|
||||
if( i==pTab->iPKey ){
|
||||
sqlite3VdbeAddOp(v, OP_String8, 0, 0);
|
||||
continue;
|
||||
|
@ -278,8 +329,9 @@ void sqlite3Update(
|
|||
j = aXRef[i];
|
||||
if( j<0 ){
|
||||
sqlite3VdbeAddOp(v, OP_Column, iCur, i);
|
||||
sqlite3ColumnDefault(v, pTab, i);
|
||||
}else{
|
||||
sqlite3ExprCode(pParse, pChanges->a[j].pExpr);
|
||||
sqlite3ExprCodeAndCache(pParse, pChanges->a[j].pExpr);
|
||||
}
|
||||
}
|
||||
sqlite3VdbeAddOp(v, OP_MakeRecord, pTab->nCol, 0);
|
||||
|
@ -294,7 +346,7 @@ void sqlite3Update(
|
|||
|
||||
/* Fire the BEFORE and INSTEAD OF triggers
|
||||
*/
|
||||
if( sqlite3CodeRowTrigger(pParse, TK_UPDATE, pChanges, TK_BEFORE, pTab,
|
||||
if( sqlite3CodeRowTrigger(pParse, TK_UPDATE, pChanges, TRIGGER_BEFORE, pTab,
|
||||
newIdx, oldIdx, onError, addr) ){
|
||||
goto update_cleanup;
|
||||
}
|
||||
|
@ -336,7 +388,7 @@ void sqlite3Update(
|
|||
** Also, the old data is needed to delete the old index entires.
|
||||
** So make the cursor point at the old record.
|
||||
*/
|
||||
if( !row_triggers_exist ){
|
||||
if( !triggers_exist ){
|
||||
sqlite3VdbeAddOp(v, OP_ListRewind, 0, 0);
|
||||
addr = sqlite3VdbeAddOp(v, OP_ListRead, 0, 0);
|
||||
sqlite3VdbeAddOp(v, OP_Dup, 0, 0);
|
||||
|
@ -362,6 +414,7 @@ void sqlite3Update(
|
|||
j = aXRef[i];
|
||||
if( j<0 ){
|
||||
sqlite3VdbeAddOp(v, OP_Column, iCur, i);
|
||||
sqlite3ColumnDefault(v, pTab, i);
|
||||
}else{
|
||||
sqlite3ExprCode(pParse, pChanges->a[j].pExpr);
|
||||
}
|
||||
|
@ -396,7 +449,7 @@ void sqlite3Update(
|
|||
/* If there are triggers, close all the cursors after each iteration
|
||||
** through the loop. The fire the after triggers.
|
||||
*/
|
||||
if( row_triggers_exist ){
|
||||
if( triggers_exist ){
|
||||
if( !isView ){
|
||||
for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
|
||||
if( openAll || aIdxUsed[i] )
|
||||
|
@ -404,7 +457,7 @@ void sqlite3Update(
|
|||
}
|
||||
sqlite3VdbeAddOp(v, OP_Close, iCur, 0);
|
||||
}
|
||||
if( sqlite3CodeRowTrigger(pParse, TK_UPDATE, pChanges, TK_AFTER, pTab,
|
||||
if( sqlite3CodeRowTrigger(pParse, TK_UPDATE, pChanges, TRIGGER_AFTER, pTab,
|
||||
newIdx, oldIdx, onError, addr) ){
|
||||
goto update_cleanup;
|
||||
}
|
||||
|
@ -418,7 +471,7 @@ void sqlite3Update(
|
|||
sqlite3VdbeAddOp(v, OP_ListReset, 0, 0);
|
||||
|
||||
/* Close all tables if there were no FOR EACH ROW triggers */
|
||||
if( !row_triggers_exist ){
|
||||
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);
|
||||
|
@ -431,9 +484,11 @@ void sqlite3Update(
|
|||
}
|
||||
|
||||
/*
|
||||
** Return the number of rows that were changed.
|
||||
** 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 ){
|
||||
if( db->flags & SQLITE_CountRows && !pParse->trigStack && pParse->nested==0 ){
|
||||
sqlite3VdbeAddOp(v, OP_Callback, 1, 0);
|
||||
sqlite3VdbeSetNumCols(v, 1);
|
||||
sqlite3VdbeSetColName(v, 0, "rows updated", P3_STATIC);
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
** This file contains routines used to translate between UTF-8,
|
||||
** UTF-16, UTF-16BE, and UTF-16LE.
|
||||
**
|
||||
** $Id: utf.c,v 1.29 2004/09/24 23:20:52 drh Exp $
|
||||
** $Id: utf.c,v 1.32 2005/01/28 01:29:08 drh Exp $
|
||||
**
|
||||
** Notes on UTF-8:
|
||||
**
|
||||
|
@ -58,8 +58,8 @@
|
|||
** sqlite3utf8LikeCompare() - Do a LIKE match given two UTF8 char* strings.
|
||||
**
|
||||
*/
|
||||
#include <assert.h>
|
||||
#include "sqliteInt.h"
|
||||
#include <assert.h>
|
||||
#include "vdbeInt.h"
|
||||
|
||||
/*
|
||||
|
@ -232,6 +232,7 @@ int sqlite3ReadUtf8(const unsigned char *z){
|
|||
*/
|
||||
/* #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
|
||||
|
@ -251,7 +252,7 @@ int sqlite3VdbeMemTranslate(Mem *pMem, u8 desiredEnc){
|
|||
assert( pMem->enc!=0 );
|
||||
assert( pMem->n>=0 );
|
||||
|
||||
#ifdef TRANSLATE_TRACE
|
||||
#if defined(TRANSLATE_TRACE) && defined(SQLITE_DEBUG)
|
||||
{
|
||||
char zBuf[100];
|
||||
sqlite3VdbeMemPrettyPrint(pMem, zBuf, 100);
|
||||
|
@ -367,7 +368,7 @@ int sqlite3VdbeMemTranslate(Mem *pMem, u8 desiredEnc){
|
|||
pMem->z = zOut;
|
||||
|
||||
translate_out:
|
||||
#ifdef TRANSLATE_TRACE
|
||||
#if defined(TRANSLATE_TRACE) && defined(SQLITE_DEBUG)
|
||||
{
|
||||
char zBuf[100];
|
||||
sqlite3VdbeMemPrettyPrint(pMem, zBuf, 100);
|
||||
|
@ -423,6 +424,7 @@ int sqlite3VdbeMemHandleBom(Mem *pMem){
|
|||
}
|
||||
return rc;
|
||||
}
|
||||
#endif /* SQLITE_OMIT_UTF16 */
|
||||
|
||||
/*
|
||||
** pZ is a UTF-8 encoded unicode string. If nByte is less than zero,
|
||||
|
@ -447,6 +449,7 @@ int sqlite3utf8CharLen(const char *z, int nByte){
|
|||
return r;
|
||||
}
|
||||
|
||||
#ifndef SQLITE_OMIT_UTF16
|
||||
/*
|
||||
** 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
|
||||
|
@ -563,4 +566,5 @@ void sqlite3utfSelfTest(){
|
|||
assert( (z-zBuf)==n );
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif /* SQLITE_TEST */
|
||||
#endif /* SQLITE_OMIT_UTF16 */
|
||||
|
|
|
@ -14,24 +14,24 @@
|
|||
** This file contains functions for allocating memory, comparing
|
||||
** strings, and stuff like that.
|
||||
**
|
||||
** $Id: util.c,v 1.119 2004/09/30 13:43:13 drh Exp $
|
||||
** $Id: util.c,v 1.132 2005/03/18 14:03:15 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include <stdarg.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#if SQLITE_DEBUG>2 && defined(__GLIBC__)
|
||||
#if SQLITE_MEMDEBUG>2 && defined(__GLIBC__)
|
||||
#include <execinfo.h>
|
||||
void print_stack_trace(){
|
||||
void *bt[30];
|
||||
int i;
|
||||
int n = backtrace(bt, 30);
|
||||
|
||||
sqlite3DebugPrintf("STACK: ");
|
||||
fprintf(stderr, "STACK: ");
|
||||
for(i=0; i<n;i++){
|
||||
sqlite3DebugPrintf("%p ", bt[i]);
|
||||
fprintf(stderr, "%p ", bt[i]);
|
||||
}
|
||||
sqlite3DebugPrintf("\n");
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
#else
|
||||
#define print_stack_trace()
|
||||
|
@ -44,19 +44,23 @@ void print_stack_trace(){
|
|||
int sqlite3_malloc_failed = 0;
|
||||
|
||||
/*
|
||||
** If SQLITE_DEBUG is defined, then use versions of malloc() and
|
||||
** If SQLITE_MEMDEBUG is defined, then use versions of malloc() and
|
||||
** free() that track memory usage and check for buffer overruns.
|
||||
*/
|
||||
#ifdef SQLITE_DEBUG
|
||||
#ifdef SQLITE_MEMDEBUG
|
||||
|
||||
/*
|
||||
** For keeping track of the number of mallocs and frees. This
|
||||
** is used to check for memory leaks.
|
||||
** is used to check for memory leaks. The iMallocFail and iMallocReset
|
||||
** values are used to simulate malloc() failures during testing in
|
||||
** order to verify that the library correctly handles an out-of-memory
|
||||
** condition.
|
||||
*/
|
||||
int sqlite3_nMalloc; /* Number of sqliteMalloc() calls */
|
||||
int sqlite3_nFree; /* Number of sqliteFree() calls */
|
||||
int sqlite3_iMallocFail; /* Fail sqliteMalloc() after this many calls */
|
||||
#if SQLITE_DEBUG>1
|
||||
int sqlite3_iMallocReset = -1; /* When iMallocFail reaches 0, set to this */
|
||||
#if SQLITE_MEMDEBUG>1
|
||||
static int memcnt = 0;
|
||||
#endif
|
||||
|
||||
|
@ -77,11 +81,11 @@ void *sqlite3Malloc_(int n, int bZero, char *zFile, int line){
|
|||
sqlite3_iMallocFail--;
|
||||
if( sqlite3_iMallocFail==0 ){
|
||||
sqlite3_malloc_failed++;
|
||||
#if SQLITE_DEBUG>1
|
||||
#if SQLITE_MEMDEBUG>1
|
||||
fprintf(stderr,"**** failed to allocate %d bytes at %s:%d\n",
|
||||
n, zFile,line);
|
||||
#endif
|
||||
sqlite3_iMallocFail--;
|
||||
sqlite3_iMallocFail = sqlite3_iMallocReset;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
@ -89,7 +93,7 @@ void *sqlite3Malloc_(int n, int bZero, char *zFile, int line){
|
|||
k = (n+sizeof(int)-1)/sizeof(int);
|
||||
pi = malloc( (N_GUARD*2+1+k)*sizeof(int));
|
||||
if( pi==0 ){
|
||||
sqlite3_malloc_failed++;
|
||||
if( n>0 ) sqlite3_malloc_failed++;
|
||||
return 0;
|
||||
}
|
||||
sqlite3_nMalloc++;
|
||||
|
@ -98,7 +102,7 @@ void *sqlite3Malloc_(int n, int bZero, char *zFile, int line){
|
|||
for(i=0; i<N_GUARD; i++) pi[k+1+N_GUARD+i] = 0xdead3344;
|
||||
p = &pi[N_GUARD+1];
|
||||
memset(p, bZero==0, n);
|
||||
#if SQLITE_DEBUG>1
|
||||
#if SQLITE_MEMDEBUG>1
|
||||
print_stack_trace();
|
||||
fprintf(stderr,"%06d malloc %d bytes at 0x%x from %s:%d\n",
|
||||
++memcnt, n, (int)p, zFile,line);
|
||||
|
@ -152,7 +156,7 @@ void sqlite3Free_(void *p, char *zFile, int line){
|
|||
}
|
||||
}
|
||||
memset(pi, 0xff, (k+N_GUARD*2+1)*sizeof(int));
|
||||
#if SQLITE_DEBUG>1
|
||||
#if SQLITE_MEMDEBUG>1
|
||||
fprintf(stderr,"%06d free %d bytes at 0x%x from %s:%d\n",
|
||||
++memcnt, n, (int)p, zFile,line);
|
||||
#endif
|
||||
|
@ -193,7 +197,7 @@ void *sqlite3Realloc_(void *oldP, int n, char *zFile, int line){
|
|||
k = (n + sizeof(int) - 1)/sizeof(int);
|
||||
pi = malloc( (k+N_GUARD*2+1)*sizeof(int) );
|
||||
if( pi==0 ){
|
||||
sqlite3_malloc_failed++;
|
||||
if( n>0 ) sqlite3_malloc_failed++;
|
||||
return 0;
|
||||
}
|
||||
for(i=0; i<N_GUARD; i++) pi[i] = 0xdead1122;
|
||||
|
@ -206,7 +210,7 @@ void *sqlite3Realloc_(void *oldP, int n, char *zFile, int line){
|
|||
}
|
||||
memset(oldPi, 0xab, (oldK+N_GUARD+2)*sizeof(int));
|
||||
free(oldPi);
|
||||
#if SQLITE_DEBUG>1
|
||||
#if SQLITE_MEMDEBUG>1
|
||||
print_stack_trace();
|
||||
fprintf(stderr,"%06d realloc %d to %d bytes at 0x%x to 0x%x at %s:%d\n",
|
||||
++memcnt, oldN, n, (int)oldP, (int)p, zFile, line);
|
||||
|
@ -241,13 +245,13 @@ char *sqlite3StrNDup_(const char *z, int n, char *zFile, int line){
|
|||
void sqlite3FreeX(void *p){
|
||||
sqliteFree(p);
|
||||
}
|
||||
#endif /* SQLITE_DEBUG */
|
||||
#endif /* SQLITE_MEMDEBUG */
|
||||
|
||||
/*
|
||||
** The following versions of malloc() and free() are for use in a
|
||||
** normal build.
|
||||
*/
|
||||
#if !defined(SQLITE_DEBUG)
|
||||
#if !defined(SQLITE_MEMDEBUG)
|
||||
|
||||
/*
|
||||
** Allocate new memory and set it to zero. Return NULL if
|
||||
|
@ -300,7 +304,7 @@ void *sqlite3Realloc(void *p, int n){
|
|||
}
|
||||
p2 = realloc(p, n);
|
||||
if( p2==0 ){
|
||||
sqlite3_malloc_failed++;
|
||||
if( n>0 ) sqlite3_malloc_failed++;
|
||||
}
|
||||
return p2;
|
||||
}
|
||||
|
@ -325,7 +329,7 @@ char *sqlite3StrNDup(const char *z, int n){
|
|||
}
|
||||
return zNew;
|
||||
}
|
||||
#endif /* !defined(SQLITE_DEBUG) */
|
||||
#endif /* !defined(SQLITE_MEMDEBUG) */
|
||||
|
||||
/*
|
||||
** Create a string from the 2nd and subsequent arguments (up to the
|
||||
|
@ -488,20 +492,6 @@ const unsigned char sqlite3UpperToLower[] = {
|
|||
};
|
||||
#define UpperToLower sqlite3UpperToLower
|
||||
|
||||
/*
|
||||
** This function computes a hash on the name of a keyword.
|
||||
** Case is not significant.
|
||||
*/
|
||||
int sqlite3HashNoCase(const char *z, int n){
|
||||
int h = 0;
|
||||
if( n<=0 ) n = strlen(z);
|
||||
while( n > 0 ){
|
||||
h = (h<<3) ^ h ^ UpperToLower[(unsigned char)*z++];
|
||||
n--;
|
||||
}
|
||||
return h & 0x7fffffff;
|
||||
}
|
||||
|
||||
/*
|
||||
** Some systems have stricmp(). Others have strcasecmp(). Because
|
||||
** there is no consistency, we will define our own.
|
||||
|
@ -796,7 +786,7 @@ int sqlite3SafetyCheck(sqlite3 *db){
|
|||
int sqlite3PutVarint(unsigned char *p, u64 v){
|
||||
int i, j, n;
|
||||
u8 buf[10];
|
||||
if( v & 0xff00000000000000 ){
|
||||
if( v & (((u64)0xff000000)<<32) ){
|
||||
p[8] = v;
|
||||
v >>= 8;
|
||||
for(i=7; i>=0; i--){
|
||||
|
@ -868,16 +858,16 @@ int sqlite3GetVarint32(const unsigned char *p, u32 *v){
|
|||
u32 x;
|
||||
int n;
|
||||
unsigned char c;
|
||||
if( ((c = p[0]) & 0x80)==0 ){
|
||||
*v = c;
|
||||
if( ((signed char*)p)[0]>=0 ){
|
||||
*v = p[0];
|
||||
return 1;
|
||||
}
|
||||
x = c & 0x7f;
|
||||
if( ((c = p[1]) & 0x80)==0 ){
|
||||
*v = (x<<7) | c;
|
||||
x = p[0] & 0x7f;
|
||||
if( ((signed char*)p)[1]>=0 ){
|
||||
*v = (x<<7) | p[1];
|
||||
return 2;
|
||||
}
|
||||
x = (x<<7) | (c & 0x7f);
|
||||
x = (x<<7) | (p[1] & 0x7f);
|
||||
n = 2;
|
||||
do{
|
||||
x = (x<<7) | ((c = p[n++])&0x7f);
|
||||
|
@ -899,6 +889,8 @@ int sqlite3VarintLen(u64 v){
|
|||
return i;
|
||||
}
|
||||
|
||||
#if !defined(SQLITE_OMIT_BLOB_LITERAL) || defined(SQLITE_HAS_CODEC) \
|
||||
|| defined(SQLITE_TEST)
|
||||
/*
|
||||
** Translate a single byte of Hex into an integer.
|
||||
*/
|
||||
|
@ -907,13 +899,14 @@ static int hexToInt(int h){
|
|||
return h - '0';
|
||||
}else if( h>='a' && h<='f' ){
|
||||
return h - 'a' + 10;
|
||||
}else if( h>='A' && h<='F' ){
|
||||
return h - 'A' + 10;
|
||||
}else{
|
||||
return 0;
|
||||
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
|
||||
|
@ -932,6 +925,7 @@ void *sqlite3HexToBlob(const char *z){
|
|||
}
|
||||
return zBlob;
|
||||
}
|
||||
#endif /* !SQLITE_OMIT_BLOB_LITERAL || SQLITE_HAS_CODEC */
|
||||
|
||||
#if defined(SQLITE_TEST)
|
||||
/*
|
||||
|
|
|
@ -14,12 +14,12 @@
|
|||
** Most of the code in this file may be omitted by defining the
|
||||
** SQLITE_OMIT_VACUUM macro.
|
||||
**
|
||||
** $Id: vacuum.c,v 1.32 2004/09/17 20:02:42 drh Exp $
|
||||
** $Id: vacuum.c,v 1.40 2005/02/16 03:27:05 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include "os.h"
|
||||
|
||||
#if !defined(SQLITE_OMIT_VACUUM) || SQLITE_OMIT_VACUUM
|
||||
#ifndef SQLITE_OMIT_VACUUM
|
||||
/*
|
||||
** Generate a random name of 20 character in length.
|
||||
*/
|
||||
|
@ -93,11 +93,10 @@ void sqlite3Vacuum(Parse *pParse, Token *pTableName){
|
|||
*/
|
||||
int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
|
||||
int rc = SQLITE_OK; /* Return code from service routines */
|
||||
#if !defined(SQLITE_OMIT_VACUUM) || SQLITE_OMIT_VACUUM
|
||||
#ifndef SQLITE_OMIT_VACUUM
|
||||
const char *zFilename; /* full pathname of the database file */
|
||||
int nFilename; /* number of characters in zFilename[] */
|
||||
char *zTemp = 0; /* a temporary file in same directory as zFilename */
|
||||
int i; /* Loop counter */
|
||||
Btree *pMain; /* The database being vacuumed */
|
||||
Btree *pTemp;
|
||||
char *zSql = 0;
|
||||
|
@ -129,11 +128,19 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
|
|||
goto end_of_vacuum;
|
||||
}
|
||||
strcpy(zTemp, zFilename);
|
||||
i = 0;
|
||||
|
||||
/* The randomName() procedure in the following loop uses an excellent
|
||||
** source of randomness to generate a name from a space of 1.3e+31
|
||||
** possibilities. So unless the directory already contains on the order
|
||||
** of 1.3e+31 files, the probability that the following loop will
|
||||
** run more than once or twice is vanishingly small. We are certain
|
||||
** enough that this loop will always terminate (and terminate quickly)
|
||||
** that we don't even bother to set a maximum loop count.
|
||||
*/
|
||||
do {
|
||||
zTemp[nFilename] = '-';
|
||||
randomName((unsigned char*)&zTemp[nFilename+1]);
|
||||
} while( i<10 && sqlite3OsFileExists(zTemp) );
|
||||
} while( sqlite3OsFileExists(zTemp) );
|
||||
|
||||
/* 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
|
||||
|
@ -159,6 +166,10 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
|
|||
assert( sqlite3BtreeGetPageSize(pTemp)==sqlite3BtreeGetPageSize(pMain) );
|
||||
execSql(db, "PRAGMA vacuum_db.synchronous=OFF");
|
||||
|
||||
#ifndef SQLITE_OMIT_AUTOVACUUM
|
||||
sqlite3BtreeSetAutoVacuum(pTemp, sqlite3BtreeGetAutoVacuum(pMain));
|
||||
#endif
|
||||
|
||||
/* Begin a transaction */
|
||||
rc = execSql(db, "BEGIN;");
|
||||
if( rc!=SQLITE_OK ) goto end_of_vacuum;
|
||||
|
@ -168,14 +179,17 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
|
|||
*/
|
||||
rc = execExecSql(db,
|
||||
"SELECT 'CREATE TABLE vacuum_db.' || substr(sql,14,100000000) "
|
||||
" FROM sqlite_master WHERE type='table' "
|
||||
"UNION ALL "
|
||||
"SELECT 'CREATE INDEX vacuum_db.' || substr(sql,14,100000000) "
|
||||
" FROM sqlite_master WHERE sql LIKE 'CREATE INDEX %' "
|
||||
"UNION ALL "
|
||||
" FROM sqlite_master WHERE type='table' AND name!='sqlite_sequence'");
|
||||
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 %'"
|
||||
"UNION ALL "
|
||||
" FROM sqlite_master WHERE sql LIKE 'CREATE UNIQUE INDEX %'");
|
||||
if( rc!=SQLITE_OK ) goto end_of_vacuum;
|
||||
rc = execExecSql(db,
|
||||
"SELECT 'CREATE VIEW vacuum_db.' || substr(sql,13,100000000) "
|
||||
" FROM sqlite_master WHERE type='view'"
|
||||
);
|
||||
|
@ -189,10 +203,25 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
|
|||
"SELECT 'INSERT INTO vacuum_db.' || quote(name) "
|
||||
"|| ' SELECT * FROM ' || quote(name) || ';'"
|
||||
"FROM sqlite_master "
|
||||
"WHERE type = 'table';"
|
||||
"WHERE type = 'table' AND name!='sqlite_sequence';"
|
||||
);
|
||||
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 from the main database to the temporary database.
|
||||
** This was deferred before in case the triggers interfered with copying
|
||||
** the data. It's possible the indices should be deferred until this
|
||||
|
@ -215,22 +244,31 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
|
|||
*/
|
||||
if( sqlite3BtreeIsInTrans(pTemp) ){
|
||||
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( 0==sqlite3BtreeIsInTrans(pMain) );
|
||||
rc = sqlite3BtreeBeginTrans(pMain, 1);
|
||||
if( rc!=SQLITE_OK ) goto end_of_vacuum;
|
||||
|
||||
/* Copy Btree meta values 3 and 4. These correspond to SQL layer meta
|
||||
** values 2 and 3, the default values of a couple of pragmas.
|
||||
*/
|
||||
rc = sqlite3BtreeGetMeta(pMain, 3, &meta);
|
||||
if( rc!=SQLITE_OK ) goto end_of_vacuum;
|
||||
rc = sqlite3BtreeUpdateMeta(pTemp, 3, meta);
|
||||
if( rc!=SQLITE_OK ) goto end_of_vacuum;
|
||||
rc = sqlite3BtreeGetMeta(pMain, 4, &meta);
|
||||
if( rc!=SQLITE_OK ) goto end_of_vacuum;
|
||||
rc = sqlite3BtreeUpdateMeta(pTemp, 4, meta);
|
||||
if( rc!=SQLITE_OK ) goto end_of_vacuum;
|
||||
/* 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]);
|
||||
}
|
||||
|
||||
rc = sqlite3BtreeCopyFile(pMain, pTemp);
|
||||
if( rc!=SQLITE_OK ) goto end_of_vacuum;
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -15,7 +15,7 @@
|
|||
** or VDBE. The VDBE implements an abstract machine that runs a
|
||||
** simple program to access and modify the underlying database.
|
||||
**
|
||||
** $Id: vdbe.h,v 1.91 2004/09/06 17:24:13 drh Exp $
|
||||
** $Id: vdbe.h,v 1.93 2005/03/09 12:26:51 danielk1977 Exp $
|
||||
*/
|
||||
#ifndef _SQLITE_VDBE_H_
|
||||
#define _SQLITE_VDBE_H_
|
||||
|
@ -69,6 +69,7 @@ typedef struct VdbeOpList VdbeOpList;
|
|||
#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 */
|
||||
|
||||
/* 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
|
||||
|
@ -110,7 +111,7 @@ int sqlite3VdbeFindOp(Vdbe*, int, int, int);
|
|||
VdbeOp *sqlite3VdbeGetOp(Vdbe*, int);
|
||||
int sqlite3VdbeMakeLabel(Vdbe*);
|
||||
void sqlite3VdbeDelete(Vdbe*);
|
||||
void sqlite3VdbeMakeReady(Vdbe*,int,int,int,int);
|
||||
void sqlite3VdbeMakeReady(Vdbe*,int,int,int,int,int);
|
||||
int sqlite3VdbeFinalize(Vdbe*);
|
||||
void sqlite3VdbeResolveLabel(Vdbe*, int);
|
||||
int sqlite3VdbeCurrentAddr(Vdbe*);
|
||||
|
@ -120,6 +121,7 @@ int sqliteVdbeSetVariables(Vdbe*,int,const char**);
|
|||
void sqlite3VdbeSetNumCols(Vdbe*,int);
|
||||
int sqlite3VdbeSetColName(Vdbe*, int, const char *, int);
|
||||
void sqlite3VdbeCountChanges(Vdbe*);
|
||||
sqlite3 *sqlite3VdbeDb(Vdbe*);
|
||||
|
||||
#ifndef NDEBUG
|
||||
void sqlite3VdbeComment(Vdbe*, const char*, ...);
|
||||
|
|
|
@ -220,7 +220,6 @@ struct sqlite3_context {
|
|||
Mem s; /* The return value is stored here */
|
||||
void *pAgg; /* Aggregate context */
|
||||
u8 isError; /* Set to true for an error */
|
||||
u8 isStep; /* Current in the step function */
|
||||
int cnt; /* Number of times that the step function has been called */
|
||||
CollSeq *pColl;
|
||||
};
|
||||
|
@ -322,7 +321,9 @@ struct Vdbe {
|
|||
int magic; /* Magic number for sanity checking */
|
||||
int nMem; /* Number of memory locations currently allocated */
|
||||
Mem *aMem; /* The memory locations */
|
||||
Agg agg; /* Aggregate information */
|
||||
int nAgg; /* Number of elements in apAgg */
|
||||
Agg *apAgg; /* Array of aggregate contexts */
|
||||
Agg *pAgg; /* Current aggregate context */
|
||||
int nCallback; /* Number of callbacks invoked so far */
|
||||
Keylist *pList; /* A list of ROWIDs */
|
||||
int contextStackTop; /* Index of top element in the context stack */
|
||||
|
@ -343,6 +344,7 @@ struct Vdbe {
|
|||
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 */
|
||||
int nChange; /* Number of db changes made since last reset */
|
||||
};
|
||||
|
||||
|
@ -363,10 +365,12 @@ int sqlite3VdbeAggReset(sqlite3*, Agg *, KeyInfo *);
|
|||
void sqlite3VdbeKeylistFree(Keylist*);
|
||||
void sqliteVdbePopStack(Vdbe*,int);
|
||||
int sqlite3VdbeCursorMoveto(Cursor*);
|
||||
#if !defined(NDEBUG) || defined(VDBE_PROFILE)
|
||||
#if defined(SQLITE_DEBUG) || defined(VDBE_PROFILE)
|
||||
void sqlite3VdbePrintOp(FILE*, int, Op*);
|
||||
#endif
|
||||
#ifdef SQLITE_DEBUG
|
||||
void sqlite3VdbePrintSql(Vdbe*);
|
||||
#endif
|
||||
int sqlite3VdbeSerialTypeLen(u32);
|
||||
u32 sqlite3VdbeSerialType(Mem*);
|
||||
int sqlite3VdbeSerialPut(unsigned char*, Mem*);
|
||||
|
|
|
@ -16,6 +16,21 @@
|
|||
#include "sqliteInt.h"
|
||||
#include "vdbeInt.h"
|
||||
|
||||
/*
|
||||
** Return TRUE (non-zero) of the statement supplied as an argument needs
|
||||
** to be recompiled. A statement needs to be recompiled whenever the
|
||||
** execution environment changes in a way that would alter the program
|
||||
** that sqlite3_prepare() generates. For example, if new functions or
|
||||
** collating sequences are registered or if an authorizer function is
|
||||
** added or changed.
|
||||
**
|
||||
***** EXPERIMENTAL ******
|
||||
*/
|
||||
int sqlite3_expired(sqlite3_stmt *pStmt){
|
||||
Vdbe *p = (Vdbe*)pStmt;
|
||||
return p==0 || p->expired;
|
||||
}
|
||||
|
||||
/**************************** sqlite3_value_ *******************************
|
||||
** The following routines extract information from a Mem or sqlite3_value
|
||||
** structure.
|
||||
|
@ -46,6 +61,7 @@ sqlite_int64 sqlite3_value_int64(sqlite3_value *pVal){
|
|||
const unsigned char *sqlite3_value_text(sqlite3_value *pVal){
|
||||
return (const char *)sqlite3ValueText(pVal, SQLITE_UTF8);
|
||||
}
|
||||
#ifndef SQLITE_OMIT_UTF16
|
||||
const void *sqlite3_value_text16(sqlite3_value* pVal){
|
||||
return sqlite3ValueText(pVal, SQLITE_UTF16NATIVE);
|
||||
}
|
||||
|
@ -55,6 +71,7 @@ const void *sqlite3_value_text16be(sqlite3_value *pVal){
|
|||
const void *sqlite3_value_text16le(sqlite3_value *pVal){
|
||||
return sqlite3ValueText(pVal, SQLITE_UTF16LE);
|
||||
}
|
||||
#endif /* SQLITE_OMIT_UTF16 */
|
||||
int sqlite3_value_type(sqlite3_value* pVal){
|
||||
return pVal->type;
|
||||
}
|
||||
|
@ -100,6 +117,7 @@ void sqlite3_result_text(
|
|||
){
|
||||
sqlite3VdbeMemSetStr(&pCtx->s, z, n, SQLITE_UTF8, xDel);
|
||||
}
|
||||
#ifndef SQLITE_OMIT_UTF16
|
||||
void sqlite3_result_text16(
|
||||
sqlite3_context *pCtx,
|
||||
const void *z,
|
||||
|
@ -124,6 +142,7 @@ void sqlite3_result_text16le(
|
|||
){
|
||||
sqlite3VdbeMemSetStr(&pCtx->s, z, n, SQLITE_UTF16LE, xDel);
|
||||
}
|
||||
#endif /* SQLITE_OMIT_UTF16 */
|
||||
void sqlite3_result_value(sqlite3_context *pCtx, sqlite3_value *pValue){
|
||||
sqlite3VdbeMemCopy(&pCtx->s, pValue);
|
||||
}
|
||||
|
@ -144,6 +163,12 @@ int sqlite3_step(sqlite3_stmt *pStmt){
|
|||
if( p->aborted ){
|
||||
return SQLITE_ABORT;
|
||||
}
|
||||
if( p->pc<=0 && p->expired ){
|
||||
if( p->rc==SQLITE_OK ){
|
||||
p->rc = SQLITE_SCHEMA;
|
||||
}
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
db = p->db;
|
||||
if( sqlite3SafetyOn(db) ){
|
||||
p->rc = SQLITE_MISUSE;
|
||||
|
@ -177,9 +202,12 @@ int sqlite3_step(sqlite3_stmt *pStmt){
|
|||
db->activeVdbeCnt++;
|
||||
p->pc = 0;
|
||||
}
|
||||
#ifndef SQLITE_OMIT_EXPLAIN
|
||||
if( p->explain ){
|
||||
rc = sqlite3VdbeList(p);
|
||||
}else{
|
||||
}else
|
||||
#endif /* SQLITE_OMIT_EXPLAIN */
|
||||
{
|
||||
rc = sqlite3VdbeExec(p);
|
||||
}
|
||||
|
||||
|
@ -343,9 +371,11 @@ sqlite_int64 sqlite3_column_int64(sqlite3_stmt *pStmt, int i){
|
|||
const unsigned char *sqlite3_column_text(sqlite3_stmt *pStmt, int i){
|
||||
return sqlite3_value_text( columnMem(pStmt,i) );
|
||||
}
|
||||
#ifndef SQLITE_OMIT_UTF16
|
||||
const void *sqlite3_column_text16(sqlite3_stmt *pStmt, int i){
|
||||
return sqlite3_value_text16( columnMem(pStmt,i) );
|
||||
}
|
||||
#endif /* SQLITE_OMIT_UTF16 */
|
||||
int sqlite3_column_type(sqlite3_stmt *pStmt, int i){
|
||||
return sqlite3_value_type( columnMem(pStmt,i) );
|
||||
}
|
||||
|
@ -383,6 +413,15 @@ const char *sqlite3_column_name(sqlite3_stmt *pStmt, int N){
|
|||
return columnName(pStmt, N, (const void*(*)(Mem*))sqlite3_value_text, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the column declaration type (if applicable) of the 'i'th column
|
||||
** of the result set of SQL statement pStmt, encoded as UTF-8.
|
||||
*/
|
||||
const char *sqlite3_column_decltype(sqlite3_stmt *pStmt, int N){
|
||||
return columnName(pStmt, N, (const void*(*)(Mem*))sqlite3_value_text, 1);
|
||||
}
|
||||
|
||||
#ifndef SQLITE_OMIT_UTF16
|
||||
/*
|
||||
** Return the name of the 'i'th column of the result set of SQL statement
|
||||
** pStmt, encoded as UTF-16.
|
||||
|
@ -391,14 +430,6 @@ const void *sqlite3_column_name16(sqlite3_stmt *pStmt, int N){
|
|||
return columnName(pStmt, N, (const void*(*)(Mem*))sqlite3_value_text16, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the column declaration type (if applicable) of the 'i'th column
|
||||
** of the result set of SQL statement pStmt, encoded as UTF-8.
|
||||
*/
|
||||
const char *sqlite3_column_decltype(sqlite3_stmt *pStmt, int N){
|
||||
return columnName(pStmt, N, (const void*(*)(Mem*))sqlite3_value_text, 1);
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the column declaration type (if applicable) of the 'i'th column
|
||||
** of the result set of SQL statement pStmt, encoded as UTF-16.
|
||||
|
@ -406,6 +437,7 @@ const char *sqlite3_column_decltype(sqlite3_stmt *pStmt, int N){
|
|||
const void *sqlite3_column_decltype16(sqlite3_stmt *pStmt, int N){
|
||||
return columnName(pStmt, N, (const void*(*)(Mem*))sqlite3_value_text16, 1);
|
||||
}
|
||||
#endif /* SQLITE_OMIT_UTF16 */
|
||||
|
||||
/******************************* sqlite3_bind_ ***************************
|
||||
**
|
||||
|
@ -513,6 +545,7 @@ int sqlite3_bind_text(
|
|||
){
|
||||
return bindText(pStmt, i, zData, nData, xDel, SQLITE_UTF8);
|
||||
}
|
||||
#ifndef SQLITE_OMIT_UTF16
|
||||
int sqlite3_bind_text16(
|
||||
sqlite3_stmt *pStmt,
|
||||
int i,
|
||||
|
@ -522,6 +555,7 @@ int sqlite3_bind_text16(
|
|||
){
|
||||
return bindText(pStmt, i, zData, nData, xDel, SQLITE_UTF16NATIVE);
|
||||
}
|
||||
#endif /* SQLITE_OMIT_UTF16 */
|
||||
|
||||
/*
|
||||
** Return the number of wildcards that can be potentially bound to.
|
||||
|
@ -578,10 +612,12 @@ int sqlite3_bind_parameter_index(sqlite3_stmt *pStmt, const char *zName){
|
|||
return 0;
|
||||
}
|
||||
createVarMap(p);
|
||||
for(i=0; i<p->nVar; i++){
|
||||
const char *z = p->azVar[i];
|
||||
if( z && strcmp(z,zName)==0 ){
|
||||
return i+1;
|
||||
if( zName ){
|
||||
for(i=0; i<p->nVar; i++){
|
||||
const char *z = p->azVar[i];
|
||||
if( z && strcmp(z,zName)==0 ){
|
||||
return i+1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
|
|
@ -103,7 +103,7 @@ int sqlite3VdbeAddOp(Vdbe *p, int op, int p1, int p2){
|
|||
pOp->p2 = p2;
|
||||
pOp->p3 = 0;
|
||||
pOp->p3type = P3_NOTUSED;
|
||||
#ifndef NDEBUG
|
||||
#ifdef SQLITE_DEBUG
|
||||
if( sqlite3_vdbe_addop_trace ) sqlite3VdbePrintOp(0, i, &p->aOp[i]);
|
||||
#endif
|
||||
return i;
|
||||
|
@ -212,7 +212,7 @@ int sqlite3VdbeAddOpList(Vdbe *p, int nOp, VdbeOpList const *aOp){
|
|||
pOut->p2 = p2<0 ? addr + ADDR(p2) : p2;
|
||||
pOut->p3 = pIn->p3;
|
||||
pOut->p3type = pIn->p3 ? P3_STATIC : P3_NOTUSED;
|
||||
#ifndef NDEBUG
|
||||
#ifdef SQLITE_DEBUG
|
||||
if( sqlite3_vdbe_addop_trace ){
|
||||
sqlite3VdbePrintOp(0, i+addr, &p->aOp[i+addr]);
|
||||
}
|
||||
|
@ -271,7 +271,12 @@ void sqlite3VdbeChangeP2(Vdbe *p, int addr, int val){
|
|||
void sqlite3VdbeChangeP3(Vdbe *p, int addr, const char *zP3, int n){
|
||||
Op *pOp;
|
||||
assert( p->magic==VDBE_MAGIC_INIT );
|
||||
if( p==0 || p->aOp==0 ) return;
|
||||
if( p==0 || p->aOp==0 ){
|
||||
if( n==P3_DYNAMIC || n==P3_KEYINFO_HANDOFF ){
|
||||
sqliteFree((void*)zP3);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if( addr<0 || addr>=p->nOp ){
|
||||
addr = p->nOp - 1;
|
||||
if( addr<0 ) return;
|
||||
|
@ -375,6 +380,8 @@ VdbeOp *sqlite3VdbeGetOp(Vdbe *p, int addr){
|
|||
return &p->aOp[addr];
|
||||
}
|
||||
|
||||
#if !defined(SQLITE_OMIT_EXPLAIN) || !defined(NDEBUG) \
|
||||
|| defined(VDBE_PROFILE) || defined(SQLITE_DEBUG)
|
||||
/*
|
||||
** Compute a string that describes the P3 parameter for an opcode.
|
||||
** Use zTemp for any required temporary buffer space.
|
||||
|
@ -444,9 +451,10 @@ static char *displayP3(Op *pOp, char *zTemp, int nTemp){
|
|||
}
|
||||
return zP3;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#if !defined(NDEBUG) || defined(VDBE_PROFILE) || defined(SQLITE_DEBUG)
|
||||
#if defined(VDBE_PROFILE) || defined(SQLITE_DEBUG)
|
||||
/*
|
||||
** Print a single opcode. This routine is used for debugging only.
|
||||
*/
|
||||
|
@ -473,6 +481,7 @@ static void releaseMemArray(Mem *p, int N){
|
|||
}
|
||||
}
|
||||
|
||||
#ifndef SQLITE_OMIT_EXPLAIN
|
||||
/*
|
||||
** Give a listing of the program in the virtual machine.
|
||||
**
|
||||
|
@ -488,6 +497,9 @@ int sqlite3VdbeList(
|
|||
int rc = SQLITE_OK;
|
||||
|
||||
assert( p->explain );
|
||||
if( p->magic!=VDBE_MAGIC_RUN ) return SQLITE_MISUSE;
|
||||
assert( db->magic==SQLITE_MAGIC_BUSY );
|
||||
assert( p->rc==SQLITE_OK || p->rc==SQLITE_BUSY );
|
||||
|
||||
/* Even though this opcode does not put dynamic strings onto the
|
||||
** the stack, they may become dynamic if the user calls
|
||||
|
@ -498,17 +510,14 @@ int sqlite3VdbeList(
|
|||
}
|
||||
p->resOnStack = 0;
|
||||
|
||||
|
||||
i = p->pc++;
|
||||
if( i>=p->nOp ){
|
||||
p->rc = SQLITE_OK;
|
||||
rc = SQLITE_DONE;
|
||||
}else if( db->flags & SQLITE_Interrupt ){
|
||||
db->flags &= ~SQLITE_Interrupt;
|
||||
if( db->magic!=SQLITE_MAGIC_BUSY ){
|
||||
p->rc = SQLITE_MISUSE;
|
||||
}else{
|
||||
p->rc = SQLITE_INTERRUPT;
|
||||
}
|
||||
p->rc = SQLITE_INTERRUPT;
|
||||
rc = SQLITE_ERROR;
|
||||
sqlite3SetString(&p->zErrMsg, sqlite3ErrStr(p->rc), (char*)0);
|
||||
}else{
|
||||
|
@ -549,6 +558,7 @@ int sqlite3VdbeList(
|
|||
}
|
||||
return rc;
|
||||
}
|
||||
#endif /* SQLITE_OMIT_EXPLAIN */
|
||||
|
||||
/*
|
||||
** Print the SQL that was used to generate a VDBE program.
|
||||
|
@ -581,6 +591,7 @@ void sqlite3VdbeMakeReady(
|
|||
int nVar, /* Number of '?' see in the SQL statement */
|
||||
int nMem, /* Number of memory cells to allocate */
|
||||
int nCursor, /* Number of cursors to allocate */
|
||||
int nAgg, /* Number of aggregate contexts required */
|
||||
int isExplain /* True if the EXPLAIN keywords is present */
|
||||
){
|
||||
int n;
|
||||
|
@ -610,6 +621,7 @@ void sqlite3VdbeMakeReady(
|
|||
+ nVar*sizeof(char*) /* azVar */
|
||||
+ nMem*sizeof(Mem) /* aMem */
|
||||
+ nCursor*sizeof(Cursor*) /* apCsr */
|
||||
+ nAgg*sizeof(Agg) /* Aggregate contexts */
|
||||
);
|
||||
if( !sqlite3_malloc_failed ){
|
||||
p->aMem = &p->aStack[n];
|
||||
|
@ -620,15 +632,20 @@ void sqlite3VdbeMakeReady(
|
|||
p->apArg = (Mem**)&p->aVar[nVar];
|
||||
p->azVar = (char**)&p->apArg[n];
|
||||
p->apCsr = (Cursor**)&p->azVar[nVar];
|
||||
if( nAgg>0 ){
|
||||
p->nAgg = nAgg;
|
||||
p->apAgg = (Agg*)&p->apCsr[nCursor];
|
||||
}
|
||||
p->nCursor = nCursor;
|
||||
for(n=0; n<nVar; n++){
|
||||
p->aVar[n].flags = MEM_Null;
|
||||
}
|
||||
for(n=0; n<nMem; n++){
|
||||
p->aMem[n].flags = MEM_Null;
|
||||
}
|
||||
}
|
||||
}
|
||||
p->pAgg = p->apAgg;
|
||||
for(n=0; n<p->nMem; n++){
|
||||
p->aMem[n].flags = MEM_Null;
|
||||
}
|
||||
|
||||
#ifdef SQLITE_DEBUG
|
||||
if( (p->db->flags & SQLITE_VdbeListing)!=0
|
||||
|
@ -684,7 +701,7 @@ void sqlite3VdbeSorterReset(Vdbe *p){
|
|||
** Free all resources allociated with AggElem pElem, an element of
|
||||
** aggregate pAgg.
|
||||
*/
|
||||
void freeAggElem(AggElem *pElem, Agg *pAgg){
|
||||
static void freeAggElem(AggElem *pElem, Agg *pAgg){
|
||||
int i;
|
||||
for(i=0; i<pAgg->nMem; i++){
|
||||
Mem *pMem = &pElem->aMem[i];
|
||||
|
@ -694,9 +711,8 @@ void freeAggElem(AggElem *pElem, Agg *pAgg){
|
|||
ctx.s.flags = MEM_Null;
|
||||
ctx.pAgg = pMem->z;
|
||||
ctx.cnt = pMem->i;
|
||||
ctx.isStep = 0;
|
||||
ctx.isError = 0;
|
||||
(*pAgg->apFunc[i]->xFinalize)(&ctx);
|
||||
(*ctx.pFunc->xFinalize)(&ctx);
|
||||
pMem->z = ctx.pAgg;
|
||||
if( pMem->z!=0 && pMem->z!=pMem->zShort ){
|
||||
sqliteFree(pMem->z);
|
||||
|
@ -729,8 +745,10 @@ void freeAggElem(AggElem *pElem, Agg *pAgg){
|
|||
*/
|
||||
int sqlite3VdbeAggReset(sqlite3 *db, Agg *pAgg, KeyInfo *pKeyInfo){
|
||||
int rc = 0;
|
||||
BtCursor *pCsr = pAgg->pCsr;
|
||||
BtCursor *pCsr;
|
||||
|
||||
if( !pAgg ) return SQLITE_OK;
|
||||
pCsr = pAgg->pCsr;
|
||||
assert( (pCsr && pAgg->nTab>0) || (!pCsr && pAgg->nTab==0)
|
||||
|| sqlite3_malloc_failed );
|
||||
|
||||
|
@ -748,7 +766,7 @@ int sqlite3VdbeAggReset(sqlite3 *db, Agg *pAgg, KeyInfo *pKeyInfo){
|
|||
while( res==0 && rc==SQLITE_OK ){
|
||||
AggElem *pElem;
|
||||
rc = sqlite3BtreeData(pCsr, 0, sizeof(AggElem*), (char *)&pElem);
|
||||
if( res!=SQLITE_OK ){
|
||||
if( rc!=SQLITE_OK ){
|
||||
return rc;
|
||||
}
|
||||
assert( pAgg->apFunc!=0 );
|
||||
|
@ -779,7 +797,11 @@ int sqlite3VdbeAggReset(sqlite3 *db, Agg *pAgg, KeyInfo *pKeyInfo){
|
|||
if( db ){
|
||||
if( !pAgg->pBtree ){
|
||||
assert( pAgg->nTab==0 );
|
||||
#ifndef SQLITE_OMIT_MEMORYDB
|
||||
rc = sqlite3BtreeFactory(db, ":memory:", 0, TEMP_PAGES, &pAgg->pBtree);
|
||||
#else
|
||||
rc = sqlite3BtreeFactory(db, 0, 0, TEMP_PAGES, &pAgg->pBtree);
|
||||
#endif
|
||||
if( rc!=SQLITE_OK ) return rc;
|
||||
sqlite3BtreeBeginTrans(pAgg->pBtree, 1);
|
||||
rc = sqlite3BtreeCreateTable(pAgg->pBtree, &pAgg->nTab, 0);
|
||||
|
@ -878,7 +900,9 @@ static void Cleanup(Vdbe *p){
|
|||
sqliteFree(p->contextStack);
|
||||
}
|
||||
sqlite3VdbeSorterReset(p);
|
||||
sqlite3VdbeAggReset(0, &p->agg, 0);
|
||||
for(i=0; i<p->nAgg; i++){
|
||||
sqlite3VdbeAggReset(0, &p->apAgg[i], 0);
|
||||
}
|
||||
p->contextStack = 0;
|
||||
p->contextStackDepth = 0;
|
||||
p->contextStackTop = 0;
|
||||
|
@ -1026,7 +1050,7 @@ static int vdbeCommit(sqlite3 *db){
|
|||
** master journal file. If an error occurs at this point close
|
||||
** and delete the master journal file. All the individual journal files
|
||||
** still have 'null' as the master journal pointer, so they will roll
|
||||
** back independantly if a failure occurs.
|
||||
** back independently if a failure occurs.
|
||||
*/
|
||||
for(i=0; i<db->nDb; i++){
|
||||
Btree *pBt = db->aDb[i].pBt;
|
||||
|
@ -1050,18 +1074,12 @@ static int vdbeCommit(sqlite3 *db){
|
|||
*/
|
||||
zMainFile = sqlite3BtreeGetDirname(db->aDb[0].pBt);
|
||||
rc = sqlite3OsOpenDirectory(zMainFile, &master);
|
||||
if( rc!=SQLITE_OK ){
|
||||
if( rc!=SQLITE_OK || (rc = sqlite3OsSync(&master))!=SQLITE_OK ){
|
||||
sqlite3OsClose(&master);
|
||||
sqlite3OsDelete(zMaster);
|
||||
sqliteFree(zMaster);
|
||||
return rc;
|
||||
}
|
||||
rc = sqlite3OsSync(&master);
|
||||
if( rc!=SQLITE_OK ){
|
||||
sqlite3OsClose(&master);
|
||||
sqliteFree(zMaster);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Sync all the db files involved in the transaction. The same call
|
||||
** sets the master journal pointer in each individual journal. If
|
||||
|
@ -1103,8 +1121,6 @@ static int vdbeCommit(sqlite3 *db){
|
|||
** master journal exists now or if it will exist after the operating
|
||||
** system crash that may follow the fsync() failure.
|
||||
*/
|
||||
assert(0);
|
||||
sqliteFree(zMaster);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
@ -1193,7 +1209,9 @@ int sqlite3VdbeHalt(Vdbe *p){
|
|||
}
|
||||
closeAllCursors(p);
|
||||
checkActiveVdbeCnt(db);
|
||||
if( db->autoCommit && db->activeVdbeCnt==1 ){
|
||||
if( p->pc<0 ){
|
||||
/* No commit or rollback needed if the program never started */
|
||||
}else if( db->autoCommit && db->activeVdbeCnt==1 ){
|
||||
if( p->rc==SQLITE_OK || p->errorAction==OE_Fail ){
|
||||
/* The auto-commit flag is true, there are no other active queries
|
||||
** using this handle and the vdbe program was successful or hit an
|
||||
|
@ -1236,7 +1254,7 @@ int sqlite3VdbeHalt(Vdbe *p){
|
|||
}
|
||||
|
||||
/* If this was an INSERT, UPDATE or DELETE, set the change counter. */
|
||||
if( p->changeCntOn ){
|
||||
if( p->changeCntOn && p->pc>=0 ){
|
||||
if( !xFunc || xFunc==sqlite3BtreeCommitStmt ){
|
||||
sqlite3VdbeSetChanges(db, p->nChange);
|
||||
}else{
|
||||
|
@ -1285,17 +1303,27 @@ int sqlite3VdbeReset(Vdbe *p){
|
|||
*/
|
||||
sqlite3VdbeHalt(p);
|
||||
|
||||
/* Transfer the error code and error message from the VDBE into the
|
||||
** main database structure.
|
||||
/* If the VDBE has be run even partially, then transfer the error code
|
||||
** and error message from the VDBE into the main database structure. But
|
||||
** if the VDBE has just been set to run but has not actually executed any
|
||||
** instructions yet, leave the main database error information unchanged.
|
||||
*/
|
||||
if( p->zErrMsg ){
|
||||
sqlite3Error(p->db, p->rc, "%s", p->zErrMsg);
|
||||
sqliteFree(p->zErrMsg);
|
||||
p->zErrMsg = 0;
|
||||
}else if( p->rc ){
|
||||
if( p->pc>=0 ){
|
||||
if( p->zErrMsg ){
|
||||
sqlite3Error(p->db, p->rc, "%s", p->zErrMsg);
|
||||
sqliteFree(p->zErrMsg);
|
||||
p->zErrMsg = 0;
|
||||
}else if( p->rc ){
|
||||
sqlite3Error(p->db, p->rc, 0);
|
||||
}else{
|
||||
sqlite3Error(p->db, SQLITE_OK, 0);
|
||||
}
|
||||
}else if( p->rc && p->expired ){
|
||||
/* The expired flag was set on the VDBE before the first call
|
||||
** to sqlite3_step(). For consistency (since sqlite3_step() was
|
||||
** called), set the database error in this case as well.
|
||||
*/
|
||||
sqlite3Error(p->db, p->rc, 0);
|
||||
}else{
|
||||
sqlite3Error(p->db, SQLITE_OK, 0);
|
||||
}
|
||||
|
||||
/* Reclaim all memory used by the VDBE
|
||||
|
@ -1329,6 +1357,9 @@ int sqlite3VdbeReset(Vdbe *p){
|
|||
#endif
|
||||
p->magic = VDBE_MAGIC_INIT;
|
||||
p->aborted = 0;
|
||||
if( p->rc==SQLITE_SCHEMA ){
|
||||
sqlite3ResetInternalSchema(p->db, 0);
|
||||
}
|
||||
return p->rc;
|
||||
}
|
||||
|
||||
|
@ -1338,18 +1369,13 @@ int sqlite3VdbeReset(Vdbe *p){
|
|||
*/
|
||||
int sqlite3VdbeFinalize(Vdbe *p){
|
||||
int rc = SQLITE_OK;
|
||||
sqlite3 *db = p->db;
|
||||
|
||||
if( p->magic==VDBE_MAGIC_RUN || p->magic==VDBE_MAGIC_HALT ){
|
||||
rc = sqlite3VdbeReset(p);
|
||||
}else if( p->magic!=VDBE_MAGIC_INIT ){
|
||||
/* sqlite3Error(p->db, SQLITE_MISUSE, 0); */
|
||||
return SQLITE_MISUSE;
|
||||
}
|
||||
sqlite3VdbeDelete(p);
|
||||
if( rc==SQLITE_SCHEMA ){
|
||||
sqlite3ResetInternalSchema(db, 0);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
@ -1399,6 +1425,9 @@ void sqlite3VdbeDelete(Vdbe *p){
|
|||
sqlite3VdbeDeleteAuxData(pVdbeFunc, 0);
|
||||
sqliteFree(pVdbeFunc);
|
||||
}
|
||||
if( pOp->p3type==P3_MEM ){
|
||||
sqlite3ValueFree((sqlite3_value*)pOp->p3);
|
||||
}
|
||||
}
|
||||
sqliteFree(p->aOp);
|
||||
}
|
||||
|
@ -1418,19 +1447,22 @@ void sqlite3VdbeDelete(Vdbe *p){
|
|||
*/
|
||||
int sqlite3VdbeCursorMoveto(Cursor *p){
|
||||
if( p->deferredMoveto ){
|
||||
int res;
|
||||
int res, rc;
|
||||
extern int sqlite3_search_count;
|
||||
assert( p->intKey );
|
||||
if( p->intKey ){
|
||||
sqlite3BtreeMoveto(p->pCursor, 0, p->movetoTarget, &res);
|
||||
rc = sqlite3BtreeMoveto(p->pCursor, 0, p->movetoTarget, &res);
|
||||
}else{
|
||||
sqlite3BtreeMoveto(p->pCursor,(char*)&p->movetoTarget,sizeof(i64),&res);
|
||||
rc = sqlite3BtreeMoveto(p->pCursor,(char*)&p->movetoTarget,
|
||||
sizeof(i64),&res);
|
||||
}
|
||||
if( rc ) return rc;
|
||||
*p->pIncrKey = 0;
|
||||
p->lastRecno = keyToInt(p->movetoTarget);
|
||||
p->recnoIsValid = res==0;
|
||||
if( res<0 ){
|
||||
sqlite3BtreeNext(p->pCursor, &res);
|
||||
rc = sqlite3BtreeNext(p->pCursor, &res);
|
||||
if( rc ) return rc;
|
||||
}
|
||||
sqlite3_search_count++;
|
||||
p->deferredMoveto = 0;
|
||||
|
@ -1487,13 +1519,15 @@ u32 sqlite3VdbeSerialType(Mem *pMem){
|
|||
return 0;
|
||||
}
|
||||
if( flags&MEM_Int ){
|
||||
/* Figure out whether to use 1, 2, 4 or 8 bytes. */
|
||||
/* Figure out whether to use 1, 2, 4, 6 or 8 bytes. */
|
||||
# define MAX_6BYTE ((((i64)0x00010000)<<32)-1)
|
||||
i64 i = pMem->i;
|
||||
if( i>=-127 && i<=127 ) return 1;
|
||||
if( i>=-32767 && i<=32767 ) return 2;
|
||||
if( i>=-8388607 && i<=8388607 ) return 3;
|
||||
if( i>=-2147483647 && i<=2147483647 ) return 4;
|
||||
if( i>=-140737488355328L && i<=140737488355328L ) return 5;
|
||||
u64 u = i<0 ? -i : i;
|
||||
if( u<=127 ) return 1;
|
||||
if( u<=32767 ) return 2;
|
||||
if( u<=8388607 ) return 3;
|
||||
if( u<=2147483647 ) return 4;
|
||||
if( u<=MAX_6BYTE ) return 5;
|
||||
return 6;
|
||||
}
|
||||
if( flags&MEM_Real ){
|
||||
|
@ -1801,6 +1835,30 @@ void sqlite3VdbeSetChanges(sqlite3 *db, int nChange){
|
|||
** Set a flag in the vdbe to update the change counter when it is finalised
|
||||
** or reset.
|
||||
*/
|
||||
void sqlite3VdbeCountChanges(Vdbe *p){
|
||||
p->changeCntOn = 1;
|
||||
void sqlite3VdbeCountChanges(Vdbe *v){
|
||||
v->changeCntOn = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
** Mark every prepared statement associated with a database connection
|
||||
** as expired.
|
||||
**
|
||||
** An expired statement means that recompilation of the statement is
|
||||
** recommend. Statements expire when things happen that make their
|
||||
** programs obsolete. Removing user-defined functions or collating
|
||||
** sequences, or changing an authorization function are the types of
|
||||
** things that make prepared statements obsolete.
|
||||
*/
|
||||
void sqlite3ExpirePreparedStatements(sqlite3 *db){
|
||||
Vdbe *p;
|
||||
for(p = db->pVdbe; p; p=p->pNext){
|
||||
p->expired = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the database associated with the Vdbe.
|
||||
*/
|
||||
sqlite3 *sqlite3VdbeDb(Vdbe *v){
|
||||
return v->db;
|
||||
}
|
||||
|
|
|
@ -34,10 +34,21 @@
|
|||
** between formats.
|
||||
*/
|
||||
int sqlite3VdbeChangeEncoding(Mem *pMem, int desiredEnc){
|
||||
int rc;
|
||||
if( !(pMem->flags&MEM_Str) || pMem->enc==desiredEnc ){
|
||||
return SQLITE_OK;
|
||||
}
|
||||
return sqlite3VdbeMemTranslate(pMem, desiredEnc);
|
||||
#ifdef SQLITE_OMIT_UTF16
|
||||
return SQLITE_ERROR;
|
||||
#else
|
||||
rc = sqlite3VdbeMemTranslate(pMem, desiredEnc);
|
||||
if( rc==SQLITE_NOMEM ){
|
||||
sqlite3VdbeMemRelease(pMem);
|
||||
pMem->flags = MEM_Null;
|
||||
pMem->z = 0;
|
||||
}
|
||||
return rc;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -390,6 +401,8 @@ int sqlite3VdbeMemSetStr(
|
|||
pMem->type = enc==0 ? SQLITE_BLOB : SQLITE_TEXT;
|
||||
pMem->n = n;
|
||||
|
||||
assert( enc==0 || enc==SQLITE_UTF8 || enc==SQLITE_UTF16LE
|
||||
|| enc==SQLITE_UTF16BE );
|
||||
switch( enc ){
|
||||
case 0:
|
||||
pMem->flags |= MEM_Blob;
|
||||
|
@ -403,6 +416,7 @@ int sqlite3VdbeMemSetStr(
|
|||
}
|
||||
break;
|
||||
|
||||
#ifndef SQLITE_OMIT_UTF16
|
||||
case SQLITE_UTF16LE:
|
||||
case SQLITE_UTF16BE:
|
||||
pMem->flags |= MEM_Str;
|
||||
|
@ -413,10 +427,7 @@ int sqlite3VdbeMemSetStr(
|
|||
if( sqlite3VdbeMemHandleBom(pMem) ){
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
#endif /* SQLITE_OMIT_UTF16 */
|
||||
}
|
||||
if( pMem->flags&MEM_Ephem ){
|
||||
return sqlite3VdbeMemMakeWriteable(pMem);
|
||||
|
@ -689,6 +700,72 @@ sqlite3_value* sqlite3ValueNew(){
|
|||
return p;
|
||||
}
|
||||
|
||||
/*
|
||||
** Create a new sqlite3_value object, containing the value of pExpr.
|
||||
**
|
||||
** This only works for very simple expressions that consist of one constant
|
||||
** token (i.e. "5", "5.1", "NULL", "'a string'"). If the expression can
|
||||
** be converted directly into a value, then the value is allocated and
|
||||
** a pointer written to *ppVal. The caller is responsible for deallocating
|
||||
** the value by passing it to sqlite3ValueFree() later on. If the expression
|
||||
** cannot be converted to a value, then *ppVal is set to NULL.
|
||||
*/
|
||||
int sqlite3ValueFromExpr(
|
||||
Expr *pExpr,
|
||||
u8 enc,
|
||||
u8 affinity,
|
||||
sqlite3_value **ppVal
|
||||
){
|
||||
int op;
|
||||
char *zVal = 0;
|
||||
sqlite3_value *pVal = 0;
|
||||
|
||||
if( !pExpr ){
|
||||
*ppVal = 0;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
op = pExpr->op;
|
||||
|
||||
if( op==TK_STRING || op==TK_FLOAT || op==TK_INTEGER ){
|
||||
zVal = sqliteStrNDup(pExpr->token.z, pExpr->token.n);
|
||||
pVal = sqlite3ValueNew();
|
||||
if( !zVal || !pVal ) goto no_mem;
|
||||
sqlite3Dequote(zVal);
|
||||
sqlite3ValueSetStr(pVal, -1, zVal, SQLITE_UTF8, sqlite3FreeX);
|
||||
if( (op==TK_INTEGER || op==TK_FLOAT ) && affinity==SQLITE_AFF_NONE ){
|
||||
sqlite3ValueApplyAffinity(pVal, SQLITE_AFF_NUMERIC, enc);
|
||||
}else{
|
||||
sqlite3ValueApplyAffinity(pVal, affinity, enc);
|
||||
}
|
||||
}else if( op==TK_UMINUS ) {
|
||||
if( SQLITE_OK==sqlite3ValueFromExpr(pExpr->pLeft, enc, affinity, &pVal) ){
|
||||
pVal->i = -1 * pVal->i;
|
||||
pVal->r = -1.0 * pVal->r;
|
||||
}
|
||||
}
|
||||
#ifndef SQLITE_OMIT_BLOB_LITERAL
|
||||
else if( op==TK_BLOB ){
|
||||
int nVal;
|
||||
pVal = sqlite3ValueNew();
|
||||
zVal = sqliteStrNDup(pExpr->token.z+1, pExpr->token.n-1);
|
||||
if( !zVal || !pVal ) goto no_mem;
|
||||
sqlite3Dequote(zVal);
|
||||
nVal = strlen(zVal)/2;
|
||||
sqlite3VdbeMemSetStr(pVal, sqlite3HexToBlob(zVal), nVal, 0, sqlite3FreeX);
|
||||
sqliteFree(zVal);
|
||||
}
|
||||
#endif
|
||||
|
||||
*ppVal = pVal;
|
||||
return SQLITE_OK;
|
||||
|
||||
no_mem:
|
||||
sqliteFree(zVal);
|
||||
sqlite3ValueFree(pVal);
|
||||
*ppVal = 0;
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
|
||||
/*
|
||||
** Change the string value of an sqlite3_value object
|
||||
*/
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Загрузка…
Ссылка в новой задаче