Bug 338155 r=vlad Upgrade to sqlite 3.3.5

This commit is contained in:
brettw%gmail.com 2006-05-22 17:48:14 +00:00
Родитель 518c8baf89
Коммит 403aed7344
38 изменённых файлов: 72 добавлений и 52001 удалений

Просмотреть файл

@ -1,493 +0,0 @@
/*
** 2003 April 6
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
**
** May you do good and not evil.
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
*************************************************************************
** This file contains code used to implement the ATTACH and DETACH commands.
**
** $Id: attach.c,v 1.49 2006/01/24 12:09:18 danielk1977 Exp $
*/
#include "sqliteInt.h"
/*
** Resolve an expression that was part of an ATTACH or DETACH statement. This
** is slightly different from resolving a normal SQL expression, because simple
** identifiers are treated as strings, not possible column names or aliases.
**
** i.e. if the parser sees:
**
** ATTACH DATABASE abc AS def
**
** it treats the two expressions as literal strings 'abc' and 'def' instead of
** looking for columns of the same name.
**
** This only applies to the root node of pExpr, so the statement:
**
** ATTACH DATABASE abc||def AS 'db2'
**
** will fail because neither abc or def can be resolved.
*/
static int resolveAttachExpr(NameContext *pName, Expr *pExpr)
{
int rc = SQLITE_OK;
if( pExpr ){
if( pExpr->op!=TK_ID ){
rc = sqlite3ExprResolveNames(pName, pExpr);
}else{
pExpr->op = TK_STRING;
}
}
return rc;
}
/*
** An SQL user-function registered to do the work of an ATTACH statement. The
** three arguments to the function come directly from an attach statement:
**
** ATTACH DATABASE x AS y KEY z
**
** SELECT sqlite_attach(x, y, z)
**
** If the optional "KEY z" syntax is omitted, an SQL NULL is passed as the
** third argument.
*/
static void attachFunc(
sqlite3_context *context,
int argc,
sqlite3_value **argv
){
int i;
int rc = 0;
sqlite3 *db = sqlite3_user_data(context);
const char *zName;
const char *zFile;
Db *aNew;
char zErr[128];
char *zErrDyn = 0;
zFile = (const char *)sqlite3_value_text(argv[0]);
zName = (const char *)sqlite3_value_text(argv[1]);
/* Check for the following errors:
**
** * Too many attached databases,
** * Transaction currently open
** * Specified database name already being used.
*/
if( db->nDb>=MAX_ATTACHED+2 ){
sqlite3_snprintf(
127, zErr, "too many attached databases - max %d", MAX_ATTACHED
);
goto attach_error;
}
if( !db->autoCommit ){
strcpy(zErr, "cannot ATTACH database within transaction");
goto attach_error;
}
for(i=0; i<db->nDb; i++){
char *z = db->aDb[i].zName;
if( z && sqlite3StrICmp(z, zName)==0 ){
sqlite3_snprintf(127, zErr, "database %s is already in use", zName);
goto attach_error;
}
}
/* Allocate the new entry in the db->aDb[] array and initialise the schema
** hash tables.
*/
if( db->aDb==db->aDbStatic ){
aNew = sqliteMalloc( sizeof(db->aDb[0])*3 );
if( aNew==0 ){
return;
}
memcpy(aNew, db->aDb, sizeof(db->aDb[0])*2);
}else{
aNew = sqliteRealloc(db->aDb, sizeof(db->aDb[0])*(db->nDb+1) );
if( aNew==0 ){
return;
}
}
db->aDb = aNew;
aNew = &db->aDb[db->nDb++];
memset(aNew, 0, sizeof(*aNew));
/* Open the database file. If the btree is successfully opened, use
** it to obtain the database schema. At this point the schema may
** or may not be initialised.
*/
rc = sqlite3BtreeFactory(db, zFile, 0, MAX_PAGES, &aNew->pBt);
if( rc==SQLITE_OK ){
aNew->pSchema = sqlite3SchemaGet(aNew->pBt);
if( !aNew->pSchema ){
rc = SQLITE_NOMEM;
}else if( aNew->pSchema->file_format && aNew->pSchema->enc!=ENC(db) ){
strcpy(zErr,
"attached databases must use the same text encoding as main database");
goto attach_error;
}
}
aNew->zName = sqliteStrDup(zName);
aNew->safety_level = 3;
#if SQLITE_HAS_CODEC
{
extern int sqlite3CodecAttach(sqlite3*, int, void*, int);
extern void sqlite3CodecGetKey(sqlite3*, int, void**, int*);
int nKey;
char *zKey;
int t = sqlite3_value_type(argv[2]);
switch( t ){
case SQLITE_INTEGER:
case SQLITE_FLOAT:
zErrDyn = sqliteStrDup("Invalid key value");
rc = SQLITE_ERROR;
break;
case SQLITE_TEXT:
case SQLITE_BLOB:
nKey = sqlite3_value_bytes(argv[2]);
zKey = (char *)sqlite3_value_blob(argv[2]);
sqlite3CodecAttach(db, db->nDb-1, zKey, nKey);
break;
case SQLITE_NULL:
/* No key specified. Use the key from the main database */
sqlite3CodecGetKey(db, 0, (void**)&zKey, &nKey);
sqlite3CodecAttach(db, db->nDb-1, zKey, nKey);
break;
}
}
#endif
/* If the file was opened successfully, read the schema for the new database.
** If this fails, or if opening the file failed, then close the file and
** remove the entry from the db->aDb[] array. i.e. put everything back the way
** we found it.
*/
if( rc==SQLITE_OK ){
sqlite3SafetyOn(db);
rc = sqlite3Init(db, &zErrDyn);
sqlite3SafetyOff(db);
}
if( rc ){
int iDb = db->nDb - 1;
assert( iDb>=2 );
if( db->aDb[iDb].pBt ){
sqlite3BtreeClose(db->aDb[iDb].pBt);
db->aDb[iDb].pBt = 0;
db->aDb[iDb].pSchema = 0;
}
sqlite3ResetInternalSchema(db, 0);
db->nDb = iDb;
sqlite3_snprintf(127, zErr, "unable to open database: %s", zFile);
goto attach_error;
}
return;
attach_error:
/* Return an error if we get here */
if( zErrDyn ){
sqlite3_result_error(context, zErrDyn, -1);
sqliteFree(zErrDyn);
}else{
zErr[sizeof(zErr)-1] = 0;
sqlite3_result_error(context, zErr, -1);
}
}
/*
** An SQL user-function registered to do the work of an DETACH statement. The
** three arguments to the function come directly from a detach statement:
**
** DETACH DATABASE x
**
** SELECT sqlite_detach(x)
*/
static void detachFunc(
sqlite3_context *context,
int argc,
sqlite3_value **argv
){
const char *zName = (const char *)sqlite3_value_text(argv[0]);
sqlite3 *db = sqlite3_user_data(context);
int i;
Db *pDb = 0;
char zErr[128];
assert(zName);
for(i=0; i<db->nDb; i++){
pDb = &db->aDb[i];
if( pDb->pBt==0 ) continue;
if( sqlite3StrICmp(pDb->zName, zName)==0 ) break;
}
if( i>=db->nDb ){
sqlite3_snprintf(sizeof(zErr), zErr, "no such database: %s", zName);
goto detach_error;
}
if( i<2 ){
sqlite3_snprintf(sizeof(zErr), zErr, "cannot detach database %s", zName);
goto detach_error;
}
if( !db->autoCommit ){
strcpy(zErr, "cannot DETACH database within transaction");
goto detach_error;
}
sqlite3BtreeClose(pDb->pBt);
pDb->pBt = 0;
pDb->pSchema = 0;
sqlite3ResetInternalSchema(db, 0);
return;
detach_error:
sqlite3_result_error(context, zErr, -1);
}
/*
** This procedure generates VDBE code for a single invocation of either the
** sqlite_detach() or sqlite_attach() SQL user functions.
*/
static void codeAttach(
Parse *pParse, /* The parser context */
int type, /* Either SQLITE_ATTACH or SQLITE_DETACH */
const char *zFunc, /* Either "sqlite_attach" or "sqlite_detach */
int nFunc, /* Number of args to pass to zFunc */
Expr *pAuthArg, /* Expression to pass to authorization callback */
Expr *pFilename, /* Name of database file */
Expr *pDbname, /* Name of the database to use internally */
Expr *pKey /* Database key for encryption extension */
){
int rc;
NameContext sName;
Vdbe *v;
FuncDef *pFunc;
sqlite3* db = pParse->db;
#ifndef SQLITE_OMIT_AUTHORIZATION
assert( sqlite3MallocFailed() || pAuthArg );
if( pAuthArg ){
char *zAuthArg = sqlite3NameFromToken(&pAuthArg->span);
if( !zAuthArg ){
goto attach_end;
}
rc = sqlite3AuthCheck(pParse, type, zAuthArg, 0, 0);
sqliteFree(zAuthArg);
if(rc!=SQLITE_OK ){
goto attach_end;
}
}
#endif /* SQLITE_OMIT_AUTHORIZATION */
memset(&sName, 0, sizeof(NameContext));
sName.pParse = pParse;
if(
SQLITE_OK!=(rc = resolveAttachExpr(&sName, pFilename)) ||
SQLITE_OK!=(rc = resolveAttachExpr(&sName, pDbname)) ||
SQLITE_OK!=(rc = resolveAttachExpr(&sName, pKey))
){
pParse->nErr++;
goto attach_end;
}
v = sqlite3GetVdbe(pParse);
sqlite3ExprCode(pParse, pFilename);
sqlite3ExprCode(pParse, pDbname);
sqlite3ExprCode(pParse, pKey);
assert( v || sqlite3MallocFailed() );
if( v ){
sqlite3VdbeAddOp(v, OP_Function, 0, nFunc);
pFunc = sqlite3FindFunction(db, zFunc, strlen(zFunc), nFunc, SQLITE_UTF8,0);
sqlite3VdbeChangeP3(v, -1, (char *)pFunc, P3_FUNCDEF);
/* Code an OP_Expire. For an ATTACH statement, set P1 to true (expire this
** statement only). For DETACH, set it to false (expire all existing
** statements).
*/
sqlite3VdbeAddOp(v, OP_Expire, (type==SQLITE_ATTACH), 0);
}
attach_end:
sqlite3ExprDelete(pFilename);
sqlite3ExprDelete(pDbname);
sqlite3ExprDelete(pKey);
}
/*
** Called by the parser to compile a DETACH statement.
**
** DETACH pDbname
*/
void sqlite3Detach(Parse *pParse, Expr *pDbname){
codeAttach(pParse, SQLITE_DETACH, "sqlite_detach", 1, pDbname, 0, 0, pDbname);
}
/*
** Called by the parser to compile an ATTACH statement.
**
** ATTACH p AS pDbname KEY pKey
*/
void sqlite3Attach(Parse *pParse, Expr *p, Expr *pDbname, Expr *pKey){
codeAttach(pParse, SQLITE_ATTACH, "sqlite_attach", 3, p, p, pDbname, pKey);
}
/*
** Register the functions sqlite_attach and sqlite_detach.
*/
void sqlite3AttachFunctions(sqlite3 *db){
static const int enc = SQLITE_UTF8;
sqlite3CreateFunc(db, "sqlite_attach", 3, enc, db, attachFunc, 0, 0);
sqlite3CreateFunc(db, "sqlite_detach", 1, enc, db, detachFunc, 0, 0);
}
/*
** Initialize a DbFixer structure. This routine must be called prior
** to passing the structure to one of the sqliteFixAAAA() routines below.
**
** The return value indicates whether or not fixation is required. TRUE
** means we do need to fix the database references, FALSE means we do not.
*/
int sqlite3FixInit(
DbFixer *pFix, /* The fixer to be initialized */
Parse *pParse, /* Error messages will be written here */
int iDb, /* This is the database that must be used */
const char *zType, /* "view", "trigger", or "index" */
const Token *pName /* Name of the view, trigger, or index */
){
sqlite3 *db;
if( iDb<0 || iDb==1 ) return 0;
db = pParse->db;
assert( db->nDb>iDb );
pFix->pParse = pParse;
pFix->zDb = db->aDb[iDb].zName;
pFix->zType = zType;
pFix->pName = pName;
return 1;
}
/*
** The following set of routines walk through the parse tree and assign
** a specific database to all table references where the database name
** was left unspecified in the original SQL statement. The pFix structure
** must have been initialized by a prior call to sqlite3FixInit().
**
** These routines are used to make sure that an index, trigger, or
** view in one database does not refer to objects in a different database.
** (Exception: indices, triggers, and views in the TEMP database are
** allowed to refer to anything.) If a reference is explicitly made
** to an object in a different database, an error message is added to
** pParse->zErrMsg and these routines return non-zero. If everything
** checks out, these routines return 0.
*/
int sqlite3FixSrcList(
DbFixer *pFix, /* Context of the fixation */
SrcList *pList /* The Source list to check and modify */
){
int i;
const char *zDb;
struct SrcList_item *pItem;
if( pList==0 ) return 0;
zDb = pFix->zDb;
for(i=0, pItem=pList->a; i<pList->nSrc; i++, pItem++){
if( pItem->zDatabase==0 ){
pItem->zDatabase = sqliteStrDup(zDb);
}else if( sqlite3StrICmp(pItem->zDatabase,zDb)!=0 ){
sqlite3ErrorMsg(pFix->pParse,
"%s %T cannot reference objects in database %s",
pFix->zType, pFix->pName, pItem->zDatabase);
return 1;
}
#if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_TRIGGER)
if( sqlite3FixSelect(pFix, pItem->pSelect) ) return 1;
if( sqlite3FixExpr(pFix, pItem->pOn) ) return 1;
#endif
}
return 0;
}
#if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_TRIGGER)
int sqlite3FixSelect(
DbFixer *pFix, /* Context of the fixation */
Select *pSelect /* The SELECT statement to be fixed to one database */
){
while( pSelect ){
if( sqlite3FixExprList(pFix, pSelect->pEList) ){
return 1;
}
if( sqlite3FixSrcList(pFix, pSelect->pSrc) ){
return 1;
}
if( sqlite3FixExpr(pFix, pSelect->pWhere) ){
return 1;
}
if( sqlite3FixExpr(pFix, pSelect->pHaving) ){
return 1;
}
pSelect = pSelect->pPrior;
}
return 0;
}
int sqlite3FixExpr(
DbFixer *pFix, /* Context of the fixation */
Expr *pExpr /* The expression to be fixed to one database */
){
while( pExpr ){
if( sqlite3FixSelect(pFix, pExpr->pSelect) ){
return 1;
}
if( sqlite3FixExprList(pFix, pExpr->pList) ){
return 1;
}
if( sqlite3FixExpr(pFix, pExpr->pRight) ){
return 1;
}
pExpr = pExpr->pLeft;
}
return 0;
}
int sqlite3FixExprList(
DbFixer *pFix, /* Context of the fixation */
ExprList *pList /* The expression to be fixed to one database */
){
int i;
struct ExprList_item *pItem;
if( pList==0 ) return 0;
for(i=0, pItem=pList->a; i<pList->nExpr; i++, pItem++){
if( sqlite3FixExpr(pFix, pItem->pExpr) ){
return 1;
}
}
return 0;
}
#endif
#ifndef SQLITE_OMIT_TRIGGER
int sqlite3FixTriggerStep(
DbFixer *pFix, /* Context of the fixation */
TriggerStep *pStep /* The trigger step be fixed to one database */
){
while( pStep ){
if( sqlite3FixSelect(pFix, pStep->pSelect) ){
return 1;
}
if( sqlite3FixExpr(pFix, pStep->pWhere) ){
return 1;
}
if( sqlite3FixExprList(pFix, pStep->pExprList) ){
return 1;
}
pStep = pStep->pNext;
}
return 0;
}
#endif

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -13,7 +13,7 @@
** This file contains functions used to access the internal hash tables
** of user defined functions and collation sequences.
**
** $Id: callback.c,v 1.4 2006-02-22 20:47:51 brettw%gmail.com Exp $
** $Id: callback.c,v 1.5 2006-05-22 17:48:14 brettw%gmail.com Exp $
*/
#include "sqliteInt.h"
@ -178,9 +178,11 @@ static CollSeq *findCollSeqEntry(
** return the pColl pointer to be deleted (because it wasn't added
** to the hash table).
*/
assert( !pDel ||
(sqlite3MallocFailed() && pDel==pColl) );
sqliteFree(pDel);
assert( !pDel || (sqlite3MallocFailed() && pDel==pColl) );
if( pDel ){
sqliteFree(pDel);
pColl = 0;
}
}
}
return pColl;
@ -312,3 +314,54 @@ FuncDef *sqlite3FindFunction(
}
return 0;
}
/*
** Free all resources held by the schema structure. The void* argument points
** at a Schema struct. This function does not call sqliteFree() on the
** pointer itself, it just cleans up subsiduary resources (i.e. the contents
** of the schema hash tables).
*/
void sqlite3SchemaFree(void *p){
Hash temp1;
Hash temp2;
HashElem *pElem;
Schema *pSchema = (Schema *)p;
temp1 = pSchema->tblHash;
temp2 = pSchema->trigHash;
sqlite3HashInit(&pSchema->trigHash, SQLITE_HASH_STRING, 0);
sqlite3HashClear(&pSchema->aFKey);
sqlite3HashClear(&pSchema->idxHash);
for(pElem=sqliteHashFirst(&temp2); pElem; pElem=sqliteHashNext(pElem)){
sqlite3DeleteTrigger((Trigger*)sqliteHashData(pElem));
}
sqlite3HashClear(&temp2);
sqlite3HashInit(&pSchema->tblHash, SQLITE_HASH_STRING, 0);
for(pElem=sqliteHashFirst(&temp1); pElem; pElem=sqliteHashNext(pElem)){
Table *pTab = sqliteHashData(pElem);
sqlite3DeleteTable(0, pTab);
}
sqlite3HashClear(&temp1);
pSchema->pSeqTab = 0;
pSchema->flags &= ~DB_SchemaLoaded;
}
/*
** Find and return the schema associated with a BTree. Create
** a new one if necessary.
*/
Schema *sqlite3SchemaGet(Btree *pBt){
Schema * p;
if( pBt ){
p = (Schema *)sqlite3BtreeSchema(pBt,sizeof(Schema),sqlite3SchemaFree);
}else{
p = (Schema *)sqliteMalloc(sizeof(Schema));
}
if( p && 0==p->file_format ){
sqlite3HashInit(&p->tblHash, SQLITE_HASH_STRING, 0);
sqlite3HashInit(&p->idxHash, SQLITE_HASH_STRING, 0);
sqlite3HashInit(&p->trigHash, SQLITE_HASH_STRING, 0);
sqlite3HashInit(&p->aFKey, SQLITE_HASH_STRING, 1);
}
return p;
}

Просмотреть файл

@ -1,452 +0,0 @@
/*
** 2001 September 15
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
**
** May you do good and not evil.
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
*************************************************************************
** This file contains C code routines that are called by the parser
** in order to generate code for DELETE FROM statements.
**
** $Id: delete.c,v 1.121 2006/02/10 02:27:43 danielk1977 Exp $
*/
#include "sqliteInt.h"
/*
** Look up every table that is named in pSrc. If any table is not found,
** add an error message to pParse->zErrMsg and return NULL. If all tables
** are found, return a pointer to the last table.
*/
Table *sqlite3SrcListLookup(Parse *pParse, SrcList *pSrc){
Table *pTab = 0;
int i;
struct SrcList_item *pItem;
for(i=0, pItem=pSrc->a; i<pSrc->nSrc; i++, pItem++){
pTab = sqlite3LocateTable(pParse, pItem->zName, pItem->zDatabase);
sqlite3DeleteTable(pParse->db, pItem->pTab);
pItem->pTab = pTab;
if( pTab ){
pTab->nRef++;
}
}
return pTab;
}
/*
** Check to make sure the given table is writable. If it is not
** writable, generate an error message and return 1. If it is
** writable return 0;
*/
int sqlite3IsReadOnly(Parse *pParse, Table *pTab, int viewOk){
if( pTab->readOnly && (pParse->db->flags & SQLITE_WriteSchema)==0
&& pParse->nested==0 ){
sqlite3ErrorMsg(pParse, "table %s may not be modified", pTab->zName);
return 1;
}
#ifndef SQLITE_OMIT_VIEW
if( !viewOk && pTab->pSelect ){
sqlite3ErrorMsg(pParse,"cannot modify %s because it is a view",pTab->zName);
return 1;
}
#endif
return 0;
}
/*
** Generate code that will open a table for reading.
*/
void sqlite3OpenTable(
Parse *p, /* Generate code into this VDBE */
int iCur, /* The cursor number of the table */
int iDb, /* The database index in sqlite3.aDb[] */
Table *pTab, /* The table to be opened */
int opcode /* OP_OpenRead or OP_OpenWrite */
){
Vdbe *v = sqlite3GetVdbe(p);
assert( opcode==OP_OpenWrite || opcode==OP_OpenRead );
sqlite3TableLock(p, iDb, pTab->tnum, (opcode==OP_OpenWrite), pTab->zName);
sqlite3VdbeAddOp(v, OP_Integer, iDb, 0);
VdbeComment((v, "# %s", pTab->zName));
sqlite3VdbeAddOp(v, opcode, iCur, pTab->tnum);
sqlite3VdbeAddOp(v, OP_SetNumColumns, iCur, pTab->nCol);
}
/*
** Generate code for a DELETE FROM statement.
**
** DELETE FROM table_wxyz WHERE a<5 AND b NOT NULL;
** \________/ \________________/
** pTabList pWhere
*/
void sqlite3DeleteFrom(
Parse *pParse, /* The parser context */
SrcList *pTabList, /* The table from which we should delete things */
Expr *pWhere /* The WHERE clause. May be null */
){
Vdbe *v; /* The virtual database engine */
Table *pTab; /* The table from which records will be deleted */
const char *zDb; /* Name of database holding pTab */
int end, addr = 0; /* A couple addresses of generated code */
int i; /* Loop counter */
WhereInfo *pWInfo; /* Information about the WHERE clause */
Index *pIdx; /* For looping over indices of the table */
int iCur; /* VDBE Cursor number for pTab */
sqlite3 *db; /* Main database structure */
AuthContext sContext; /* Authorization context */
int oldIdx = -1; /* Cursor for the OLD table of AFTER triggers */
NameContext sNC; /* Name context to resolve expressions in */
int iDb;
#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 || sqlite3MallocFailed() ){
goto delete_from_cleanup;
}
db = pParse->db;
assert( pTabList->nSrc==1 );
/* Locate the table which we want to delete. This table has to be
** put in an SrcList structure because some of the subroutines we
** will be calling are designed to work with multiple tables and expect
** an SrcList* parameter instead of just a Table* parameter.
*/
pTab = sqlite3SrcListLookup(pParse, pTabList);
if( pTab==0 ) goto delete_from_cleanup;
/* Figure out if we have any triggers and if the table being
** deleted from is a view
*/
#ifndef SQLITE_OMIT_TRIGGER
triggers_exist = sqlite3TriggersExist(pParse, pTab, TK_DELETE, 0);
isView = pTab->pSelect!=0;
#else
# define triggers_exist 0
# define isView 0
#endif
#ifdef SQLITE_OMIT_VIEW
# undef isView
# define isView 0
#endif
if( sqlite3IsReadOnly(pParse, pTab, triggers_exist) ){
goto delete_from_cleanup;
}
iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
assert( iDb<db->nDb );
zDb = db->aDb[iDb].zName;
if( sqlite3AuthCheck(pParse, SQLITE_DELETE, pTab->zName, 0, zDb) ){
goto delete_from_cleanup;
}
/* If pTab is really a view, make sure it has been initialized.
*/
if( isView && sqlite3ViewGetColumnNames(pParse, pTab) ){
goto delete_from_cleanup;
}
/* Allocate a cursor used to store the old.* data for a trigger.
*/
if( triggers_exist ){
oldIdx = pParse->nTab++;
}
/* Resolve the column names in the WHERE clause.
*/
assert( pTabList->nSrc==1 );
iCur = pTabList->a[0].iCursor = pParse->nTab++;
memset(&sNC, 0, sizeof(sNC));
sNC.pParse = pParse;
sNC.pSrcList = pTabList;
if( sqlite3ExprResolveNames(&sNC, pWhere) ){
goto delete_from_cleanup;
}
/* Start the view context
*/
if( isView ){
sqlite3AuthContextPush(pParse, &sContext, pTab->zName);
}
/* Begin generating code.
*/
v = sqlite3GetVdbe(pParse);
if( v==0 ){
goto delete_from_cleanup;
}
if( pParse->nested==0 ) sqlite3VdbeCountChanges(v);
sqlite3BeginWriteOperation(pParse, triggers_exist, iDb);
/* If we are trying to delete from a view, realize that view into
** a ephemeral table.
*/
if( isView ){
Select *pView = sqlite3SelectDup(pTab->pSelect);
sqlite3Select(pParse, pView, SRT_VirtualTab, iCur, 0, 0, 0, 0);
sqlite3SelectDelete(pView);
}
/* Initialize the counter of the number of rows deleted, if
** we are counting rows.
*/
if( db->flags & SQLITE_CountRows ){
sqlite3VdbeAddOp(v, OP_Integer, 0, 0);
}
/* Special case: A DELETE without a WHERE clause deletes everything.
** It is easier just to erase the whole table. Note, however, that
** this means that the row change count will be incorrect.
*/
if( pWhere==0 && !triggers_exist ){
if( db->flags & SQLITE_CountRows ){
/* If counting rows deleted, just count the total number of
** entries in the table. */
int endOfLoop = sqlite3VdbeMakeLabel(v);
int addr2;
if( !isView ){
sqlite3OpenTable(pParse, iCur, iDb, pTab, OP_OpenRead);
}
sqlite3VdbeAddOp(v, OP_Rewind, iCur, sqlite3VdbeCurrentAddr(v)+2);
addr2 = sqlite3VdbeAddOp(v, OP_AddImm, 1, 0);
sqlite3VdbeAddOp(v, OP_Next, iCur, addr2);
sqlite3VdbeResolveLabel(v, endOfLoop);
sqlite3VdbeAddOp(v, OP_Close, iCur, 0);
}
if( !isView ){
sqlite3VdbeAddOp(v, OP_Clear, pTab->tnum, iDb);
if( !pParse->nested ){
sqlite3VdbeChangeP3(v, -1, pTab->zName, P3_STATIC);
}
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
assert( pIdx->pSchema==pTab->pSchema );
sqlite3VdbeAddOp(v, OP_Clear, pIdx->tnum, iDb);
}
}
}
/* The usual case: There is a WHERE clause so we have to scan through
** the table and pick which records to delete.
*/
else{
/* Begin the database scan
*/
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 0);
if( pWInfo==0 ) goto delete_from_cleanup;
/* Remember the rowid of every item to be deleted.
*/
sqlite3VdbeAddOp(v, OP_Rowid, iCur, 0);
sqlite3VdbeAddOp(v, OP_FifoWrite, 0, 0);
if( db->flags & SQLITE_CountRows ){
sqlite3VdbeAddOp(v, OP_AddImm, 1, 0);
}
/* End the database scan loop.
*/
sqlite3WhereEnd(pWInfo);
/* Open the pseudo-table used to store OLD if there are triggers.
*/
if( triggers_exist ){
sqlite3VdbeAddOp(v, OP_OpenPseudo, oldIdx, 0);
sqlite3VdbeAddOp(v, OP_SetNumColumns, oldIdx, pTab->nCol);
}
/* Delete every item whose key was written to the list during the
** database scan. We have to delete items after the scan is complete
** because deleting an item can change the scan order.
*/
end = sqlite3VdbeMakeLabel(v);
/* This is the beginning of the delete loop when there are
** row triggers.
*/
if( triggers_exist ){
addr = sqlite3VdbeAddOp(v, OP_FifoRead, 0, end);
if( !isView ){
sqlite3VdbeAddOp(v, OP_Dup, 0, 0);
sqlite3OpenTable(pParse, iCur, iDb, pTab, OP_OpenRead);
}
sqlite3VdbeAddOp(v, OP_MoveGe, iCur, 0);
sqlite3VdbeAddOp(v, OP_Rowid, iCur, 0);
sqlite3VdbeAddOp(v, OP_RowData, iCur, 0);
sqlite3VdbeAddOp(v, OP_Insert, oldIdx, 0);
if( !isView ){
sqlite3VdbeAddOp(v, OP_Close, iCur, 0);
}
(void)sqlite3CodeRowTrigger(pParse, TK_DELETE, 0, TRIGGER_BEFORE, pTab,
-1, oldIdx, (pParse->trigStack)?pParse->trigStack->orconf:OE_Default,
addr);
}
if( !isView ){
/* Open cursors for the table we are deleting from and all its
** indices. If there are row triggers, this happens inside the
** OP_FifoRead loop because the cursor have to all be closed
** before the trigger fires. If there are no row triggers, the
** cursors are opened only once on the outside the loop.
*/
sqlite3OpenTableAndIndices(pParse, pTab, iCur, OP_OpenWrite);
/* This is the beginning of the delete loop when there are no
** row triggers */
if( !triggers_exist ){
addr = sqlite3VdbeAddOp(v, OP_FifoRead, 0, end);
}
/* Delete the row */
sqlite3GenerateRowDelete(db, v, pTab, iCur, pParse->nested==0);
}
/* If there are row triggers, close all cursors then invoke
** the AFTER triggers
*/
if( triggers_exist ){
if( !isView ){
for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
sqlite3VdbeAddOp(v, OP_Close, iCur + i, pIdx->tnum);
}
sqlite3VdbeAddOp(v, OP_Close, iCur, 0);
}
(void)sqlite3CodeRowTrigger(pParse, TK_DELETE, 0, TRIGGER_AFTER, pTab, -1,
oldIdx, (pParse->trigStack)?pParse->trigStack->orconf:OE_Default,
addr);
}
/* End of the delete loop */
sqlite3VdbeAddOp(v, OP_Goto, 0, addr);
sqlite3VdbeResolveLabel(v, end);
/* Close the cursors after the loop if there are no row triggers */
if( !triggers_exist ){
for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
sqlite3VdbeAddOp(v, OP_Close, iCur + i, pIdx->tnum);
}
sqlite3VdbeAddOp(v, OP_Close, iCur, 0);
}
}
/*
** Return the number of rows that were deleted. If this routine is
** generating code because of a call to sqlite3NestedParse(), do not
** invoke the callback function.
*/
if( db->flags & SQLITE_CountRows && pParse->nested==0 && !pParse->trigStack ){
sqlite3VdbeAddOp(v, OP_Callback, 1, 0);
sqlite3VdbeSetNumCols(v, 1);
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "rows deleted", P3_STATIC);
}
delete_from_cleanup:
sqlite3AuthContextPop(&sContext);
sqlite3SrcListDelete(pTabList);
sqlite3ExprDelete(pWhere);
return;
}
/*
** This routine generates VDBE code that causes a single row of a
** single table to be deleted.
**
** The VDBE must be in a particular state when this routine is called.
** These are the requirements:
**
** 1. A read/write cursor pointing to pTab, the table containing the row
** to be deleted, must be opened as cursor number "base".
**
** 2. Read/write cursors for all indices of pTab must be open as
** cursor number base+i for the i-th index.
**
** 3. The record number of the row to be deleted must be on the top
** of the stack.
**
** This routine pops the top of the stack to remove the record number
** and then generates code to remove both the table record and all index
** entries that point to that record.
*/
void sqlite3GenerateRowDelete(
sqlite3 *db, /* The database containing the index */
Vdbe *v, /* Generate code into this VDBE */
Table *pTab, /* Table containing the row to be deleted */
int iCur, /* Cursor number for the table */
int count /* Increment the row change counter */
){
int addr;
addr = sqlite3VdbeAddOp(v, OP_NotExists, iCur, 0);
sqlite3GenerateRowIndexDelete(db, v, pTab, iCur, 0);
sqlite3VdbeAddOp(v, OP_Delete, iCur, (count?OPFLAG_NCHANGE:0));
if( count ){
sqlite3VdbeChangeP3(v, -1, pTab->zName, P3_STATIC);
}
sqlite3VdbeJumpHere(v, addr);
}
/*
** This routine generates VDBE code that causes the deletion of all
** index entries associated with a single row of a single table.
**
** The VDBE must be in a particular state when this routine is called.
** These are the requirements:
**
** 1. A read/write cursor pointing to pTab, the table containing the row
** to be deleted, must be opened as cursor number "iCur".
**
** 2. Read/write cursors for all indices of pTab must be open as
** cursor number iCur+i for the i-th index.
**
** 3. The "iCur" cursor must be pointing to the row that is to be
** deleted.
*/
void sqlite3GenerateRowIndexDelete(
sqlite3 *db, /* The database containing the index */
Vdbe *v, /* Generate code into this VDBE */
Table *pTab, /* Table containing the row to be deleted */
int iCur, /* Cursor number for the table */
char *aIdxUsed /* Only delete if aIdxUsed!=0 && aIdxUsed[i]!=0 */
){
int i;
Index *pIdx;
for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
if( aIdxUsed!=0 && aIdxUsed[i-1]==0 ) continue;
sqlite3GenerateIndexKey(v, pIdx, iCur);
sqlite3VdbeAddOp(v, OP_IdxDelete, iCur+i, 0);
}
}
/*
** Generate code that will assemble an index key and put it on the top
** of the tack. The key with be for index pIdx which is an index on pTab.
** iCur is the index of a cursor open on the pTab table and pointing to
** the entry that needs indexing.
*/
void sqlite3GenerateIndexKey(
Vdbe *v, /* Generate code into this VDBE */
Index *pIdx, /* The index for which to generate a key */
int iCur /* Cursor number for the pIdx->pTable table */
){
int j;
Table *pTab = pIdx->pTable;
sqlite3VdbeAddOp(v, OP_Rowid, iCur, 0);
for(j=0; j<pIdx->nColumn; j++){
int idx = pIdx->aiColumn[j];
if( idx==pTab->iPKey ){
sqlite3VdbeAddOp(v, OP_Dup, j, 0);
}else{
sqlite3VdbeAddOp(v, OP_Column, iCur, idx);
sqlite3ColumnDefault(v, pTab, idx);
}
}
sqlite3VdbeAddOp(v, OP_MakeIdxRec, pIdx->nColumn, 0);
sqlite3IndexAffinityStr(v, pIdx);
}

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -1,98 +0,0 @@
/* Hash score: 159 */
static int keywordCode(const char *z, int n){
static const char zText[537] =
"ABORTABLEFTEMPORARYADDATABASELECTHENDEFAULTRANSACTIONATURALTER"
"AISEACHECKEYAFTEREFERENCESCAPELSEXCEPTRIGGEREGEXPLAINITIALLYANALYZE"
"XCLUSIVEXISTSTATEMENTANDEFERRABLEATTACHAVINGLOBEFOREIGNOREINDEX"
"AUTOINCREMENTBEGINNERENAMEBETWEENOTNULLIKEBYCASCADEFERREDELETE"
"CASECASTCOLLATECOLUMNCOMMITCONFLICTCONSTRAINTERSECTCREATECROSS"
"CURRENT_DATECURRENT_TIMESTAMPLANDESCDETACHDISTINCTDROPRAGMATCH"
"FAILIMITFROMFULLGROUPDATEIFIMMEDIATEINSERTINSTEADINTOFFSETISNULL"
"JOINORDEREPLACEOUTERESTRICTPRIMARYQUERYRIGHTROLLBACKROWHENUNION"
"UNIQUEUSINGVACUUMVALUESVIEWHERE";
static const unsigned char aHash[127] = {
92, 80, 107, 91, 0, 4, 0, 0, 114, 0, 83, 0, 0,
95, 44, 76, 93, 0, 106, 109, 97, 90, 0, 10, 0, 0,
113, 0, 110, 103, 0, 28, 48, 0, 41, 0, 0, 65, 71,
0, 63, 19, 0, 105, 36, 104, 0, 108, 74, 0, 0, 33,
0, 61, 37, 0, 8, 0, 115, 38, 12, 0, 77, 40, 25,
66, 0, 0, 31, 81, 53, 30, 50, 20, 88, 0, 34, 0,
75, 26, 0, 72, 0, 0, 0, 64, 47, 67, 22, 87, 29,
69, 86, 0, 1, 0, 9, 101, 58, 18, 0, 112, 82, 99,
54, 6, 85, 0, 0, 49, 94, 0, 102, 0, 70, 0, 0,
15, 0, 116, 51, 56, 0, 2, 55, 0, 111,
};
static const unsigned char aNext[116] = {
0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0,
0, 11, 0, 0, 0, 0, 5, 13, 0, 7, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 43, 0, 0, 0, 0, 0,
0, 0, 16, 0, 23, 52, 0, 0, 0, 0, 45, 0, 59,
0, 0, 0, 0, 0, 0, 0, 0, 73, 42, 0, 24, 60,
21, 0, 79, 0, 0, 68, 0, 0, 84, 46, 0, 0, 0,
0, 0, 0, 0, 0, 39, 96, 98, 0, 0, 100, 0, 32,
0, 14, 27, 78, 0, 57, 89, 0, 35, 0, 62, 0,
};
static const unsigned char aLen[116] = {
5, 5, 4, 4, 9, 2, 3, 8, 2, 6, 4, 3, 7,
11, 2, 7, 5, 5, 4, 5, 3, 5, 10, 6, 4, 6,
7, 6, 7, 9, 3, 7, 9, 6, 9, 3, 10, 6, 6,
4, 6, 3, 7, 6, 7, 5, 13, 2, 2, 5, 5, 6,
7, 3, 7, 4, 4, 2, 7, 3, 8, 6, 4, 4, 7,
6, 6, 8, 10, 9, 6, 5, 12, 12, 17, 4, 4, 6,
8, 2, 4, 6, 5, 4, 5, 4, 4, 5, 6, 2, 9,
6, 7, 4, 2, 6, 3, 6, 4, 5, 7, 5, 8, 7,
5, 5, 8, 3, 4, 5, 6, 5, 6, 6, 4, 5,
};
static const unsigned short int aOffset[116] = {
0, 4, 7, 10, 10, 14, 19, 21, 26, 27, 32, 34, 36,
42, 51, 52, 57, 61, 65, 67, 71, 74, 78, 86, 91, 94,
99, 105, 108, 113, 118, 122, 128, 136, 141, 150, 152, 162, 167,
172, 175, 177, 177, 181, 185, 187, 192, 194, 196, 205, 208, 212,
218, 224, 224, 227, 230, 234, 236, 237, 241, 248, 254, 258, 262,
269, 275, 281, 289, 296, 305, 311, 316, 328, 328, 344, 348, 352,
358, 359, 366, 369, 373, 378, 381, 386, 390, 394, 397, 403, 405,
414, 420, 427, 430, 430, 433, 436, 442, 446, 450, 457, 461, 469,
476, 481, 486, 494, 496, 500, 505, 511, 516, 522, 528, 531,
};
static const unsigned char aCode[116] = {
TK_ABORT, TK_TABLE, TK_JOIN_KW, TK_TEMP, TK_TEMP,
TK_OR, TK_ADD, TK_DATABASE, TK_AS, TK_SELECT,
TK_THEN, TK_END, TK_DEFAULT, TK_TRANSACTION,TK_ON,
TK_JOIN_KW, TK_ALTER, TK_RAISE, TK_EACH, TK_CHECK,
TK_KEY, TK_AFTER, TK_REFERENCES, TK_ESCAPE, TK_ELSE,
TK_EXCEPT, TK_TRIGGER, TK_LIKE_KW, TK_EXPLAIN, TK_INITIALLY,
TK_ALL, TK_ANALYZE, TK_EXCLUSIVE, TK_EXISTS, TK_STATEMENT,
TK_AND, TK_DEFERRABLE, TK_ATTACH, TK_HAVING, TK_LIKE_KW,
TK_BEFORE, TK_FOR, TK_FOREIGN, TK_IGNORE, TK_REINDEX,
TK_INDEX, TK_AUTOINCR, TK_TO, TK_IN, TK_BEGIN,
TK_JOIN_KW, TK_RENAME, TK_BETWEEN, TK_NOT, TK_NOTNULL,
TK_NULL, TK_LIKE_KW, TK_BY, TK_CASCADE, TK_ASC,
TK_DEFERRED, TK_DELETE, TK_CASE, TK_CAST, TK_COLLATE,
TK_COLUMNKW, TK_COMMIT, TK_CONFLICT, TK_CONSTRAINT, TK_INTERSECT,
TK_CREATE, TK_JOIN_KW, TK_CTIME_KW, TK_CTIME_KW, TK_CTIME_KW,
TK_PLAN, TK_DESC, TK_DETACH, TK_DISTINCT, TK_IS,
TK_DROP, TK_PRAGMA, TK_MATCH, TK_FAIL, TK_LIMIT,
TK_FROM, TK_JOIN_KW, TK_GROUP, TK_UPDATE, TK_IF,
TK_IMMEDIATE, TK_INSERT, TK_INSTEAD, TK_INTO, TK_OF,
TK_OFFSET, TK_SET, TK_ISNULL, TK_JOIN, TK_ORDER,
TK_REPLACE, TK_JOIN_KW, TK_RESTRICT, TK_PRIMARY, TK_QUERY,
TK_JOIN_KW, TK_ROLLBACK, TK_ROW, TK_WHEN, TK_UNION,
TK_UNIQUE, TK_USING, TK_VACUUM, TK_VALUES, TK_VIEW,
TK_WHERE,
};
int h, i;
if( n<2 ) return TK_ID;
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 unsigned char *z, int n){
return keywordCode((char*)z, n);
}

Просмотреть файл

@ -1,135 +0,0 @@
/*
** 2001 September 15
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
**
** May you do good and not evil.
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
*************************************************************************
** Main file for the SQLite library. The routines in this file
** implement the programmer interface to the library. Routines in
** other files are for internal use by SQLite and should not be
** accessed by users of the library.
**
** $Id: legacy.c,v 1.13 2006/01/23 13:14:55 drh Exp $
*/
#include "sqliteInt.h"
#include "os.h"
#include <ctype.h>
/*
** Execute SQL code. Return one of the SQLITE_ success/failure
** codes. Also write an error message into memory obtained from
** malloc() and make *pzErrMsg point to that message.
**
** If the SQL is a query, then for each row in the query result
** the xCallback() function is called. pArg becomes the first
** argument to xCallback(). If xCallback=NULL then no callback
** is invoked, even for queries.
*/
int sqlite3_exec(
sqlite3 *db, /* The database on which the SQL executes */
const char *zSql, /* The SQL to be executed */
sqlite3_callback xCallback, /* Invoke this callback routine */
void *pArg, /* First argument to xCallback() */
char **pzErrMsg /* Write error messages here */
){
int rc = SQLITE_OK;
const char *zLeftover;
sqlite3_stmt *pStmt = 0;
char **azCols = 0;
int nRetry = 0;
int nChange = 0;
int nCallback;
if( zSql==0 ) return SQLITE_OK;
while( (rc==SQLITE_OK || (rc==SQLITE_SCHEMA && (++nRetry)<2)) && zSql[0] ){
int nCol;
char **azVals = 0;
pStmt = 0;
rc = sqlite3_prepare(db, zSql, -1, &pStmt, &zLeftover);
if( rc!=SQLITE_OK ){
if( pStmt ) sqlite3_finalize(pStmt);
continue;
}
if( !pStmt ){
/* this happens for a comment or white-space */
zSql = zLeftover;
continue;
}
db->nChange += nChange;
nCallback = 0;
nCol = sqlite3_column_count(pStmt);
azCols = sqliteMalloc(2*nCol*sizeof(const char *) + 1);
if( azCols==0 ){
goto exec_out;
}
while( 1 ){
int i;
rc = sqlite3_step(pStmt);
/* Invoke the callback function if required */
if( xCallback && (SQLITE_ROW==rc ||
(SQLITE_DONE==rc && !nCallback && db->flags&SQLITE_NullCallback)) ){
if( 0==nCallback ){
for(i=0; i<nCol; i++){
azCols[i] = (char *)sqlite3_column_name(pStmt, i);
}
nCallback++;
}
if( rc==SQLITE_ROW ){
azVals = &azCols[nCol];
for(i=0; i<nCol; i++){
azVals[i] = (char *)sqlite3_column_text(pStmt, i);
}
}
if( xCallback(pArg, nCol, azVals, azCols) ){
rc = SQLITE_ABORT;
goto exec_out;
}
}
if( rc!=SQLITE_ROW ){
rc = sqlite3_finalize(pStmt);
pStmt = 0;
if( db->pVdbe==0 ){
nChange = db->nChange;
}
if( rc!=SQLITE_SCHEMA ){
nRetry = 0;
zSql = zLeftover;
while( isspace((unsigned char)zSql[0]) ) zSql++;
}
break;
}
}
sqliteFree(azCols);
azCols = 0;
}
exec_out:
if( pStmt ) sqlite3_finalize(pStmt);
if( azCols ) sqliteFree(azCols);
rc = sqlite3ApiExit(0, rc);
if( rc!=SQLITE_OK && rc==sqlite3_errcode(db) && pzErrMsg ){
*pzErrMsg = malloc(1+strlen(sqlite3_errmsg(db)));
if( *pzErrMsg ){
strcpy(*pzErrMsg, sqlite3_errmsg(db));
}
}else if( pzErrMsg ){
*pzErrMsg = 0;
}
return rc;
}

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -27,19 +27,12 @@
# if defined(_WIN32) || defined(WIN32) || defined(__CYGWIN__) || defined(__MINGW32__) || defined(__BORLANDC__)
# define OS_WIN 1
# define OS_UNIX 0
# define OS_OS2 0
# elif defined(_EMX_) || defined(_OS2) || defined(OS2) || defined(OS_OS2)
# define OS_WIN 0
# define OS_UNIX 0
# define OS_OS2 1
# else
# define OS_WIN 0
# define OS_UNIX 1
# define OS_OS2 0
# endif
# else
# define OS_UNIX 0
# define OS_OS2 0
# endif
#else
# ifndef OS_WIN
@ -54,14 +47,6 @@
#if OS_WIN
# include <windows.h>
# define SQLITE_TEMPNAME_SIZE (MAX_PATH+50)
#elif OS_OS2
# define INCL_DOSDATETIME
# define INCL_DOSFILEMGR
# define INCL_DOSERRORS
# define INCL_DOSMISC
# define INCL_DOSPROCESS
# include <os2.h>
# define SQLITE_TEMPNAME_SIZE (CCHMAXPATHCOMP)
#else
# define SQLITE_TEMPNAME_SIZE 200
#endif
@ -87,7 +72,7 @@
#endif
/*
** Define the interfaces for Unix, Windows and OS/2.
** Define the interfaces for Unix and for Windows.
*/
#if OS_UNIX
#define sqlite3OsOpenReadWrite sqlite3UnixOpenReadWrite
@ -133,28 +118,6 @@
#define sqlite3OsFree sqlite3GenericFree
#define sqlite3OsAllocationSize sqlite3GenericAllocationSize
#endif
#if OS_OS2
#define sqlite3OsOpenReadWrite sqlite3Os2OpenReadWrite
#define sqlite3OsOpenExclusive sqlite3Os2OpenExclusive
#define sqlite3OsOpenReadOnly sqlite3Os2OpenReadOnly
#define sqlite3OsDelete sqlite3Os2Delete
#define sqlite3OsFileExists sqlite3Os2FileExists
#define sqlite3OsFullPathname sqlite3Os2FullPathname
#define sqlite3OsIsDirWritable sqlite3Os2IsDirWritable
#define sqlite3OsSyncDirectory sqlite3Os2SyncDirectory
#define sqlite3OsTempFileName sqlite3Os2TempFileName
#define sqlite3OsRandomSeed sqlite3Os2RandomSeed
#define sqlite3OsSleep sqlite3Os2Sleep
#define sqlite3OsCurrentTime sqlite3Os2CurrentTime
#define sqlite3OsEnterMutex sqlite3Os2EnterMutex
#define sqlite3OsLeaveMutex sqlite3Os2LeaveMutex
#define sqlite3OsInMutex sqlite3Os2InMutex
#define sqlite3OsThreadSpecificData sqlite3Os2ThreadSpecificData
#define sqlite3OsMalloc sqlite3GenericMalloc
#define sqlite3OsRealloc sqlite3GenericRealloc
#define sqlite3OsFree sqlite3GenericFree
#define sqlite3OsAllocationSize sqlite3GenericAllocationSize
#endif
/*
** If using an alternative OS interface, then we must have an "os_other.h"

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -128,19 +128,19 @@ int sqlite3_os_type = 0;
** is obtained from sqliteMalloc.
*/
static WCHAR *utf8ToUnicode(const char *zFilename){
int nByte;
int nChar;
WCHAR *zWideFilename;
if( !isNT() ){
return 0;
}
nByte = MultiByteToWideChar(CP_UTF8, 0, zFilename, -1, NULL, 0)*sizeof(WCHAR);
zWideFilename = sqliteMalloc( nByte*sizeof(zWideFilename[0]) );
nChar = MultiByteToWideChar(CP_UTF8, 0, zFilename, -1, NULL, 0);
zWideFilename = sqliteMalloc( nChar*sizeof(zWideFilename[0]) );
if( zWideFilename==0 ){
return 0;
}
nByte = MultiByteToWideChar(CP_UTF8, 0, zFilename, -1, zWideFilename, nByte);
if( nByte==0 ){
nChar = MultiByteToWideChar(CP_UTF8, 0, zFilename, -1, zWideFilename, nChar);
if( nChar==0 ){
sqliteFree(zWideFilename);
zWideFilename = 0;
}

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -1,123 +0,0 @@
/*
** 2001 September 15
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
**
** May you do good and not evil.
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
*************************************************************************
** This header file defines the interface that the sqlite page cache
** subsystem. The page cache subsystem reads and writes a file a page
** at a time and provides a journal for rollback.
**
** @(#) $Id: pager.h,v 1.49 2006/02/11 01:25:51 drh Exp $
*/
#ifndef _PAGER_H_
#define _PAGER_H_
/*
** The default size of a database page.
*/
#ifndef SQLITE_DEFAULT_PAGE_SIZE
# define SQLITE_DEFAULT_PAGE_SIZE 1024
#endif
/* Maximum page size. The upper bound on this value is 32768. This a limit
** imposed by necessity of storing the value in a 2-byte unsigned integer
** and the fact that the page size must be a power of 2.
**
** This value is used to initialize certain arrays on the stack at
** various places in the code. On embedded machines where stack space
** is limited and the flexibility of having large pages is not needed,
** it makes good sense to reduce the maximum page size to something more
** reasonable, like 1024.
*/
#ifndef SQLITE_MAX_PAGE_SIZE
# define SQLITE_MAX_PAGE_SIZE 32768
#endif
/*
** Maximum number of pages in one database.
*/
#define SQLITE_MAX_PAGE 1073741823
/*
** The type used to represent a page number. The first page in a file
** is called page 1. 0 is used to represent "not a page".
*/
typedef unsigned int Pgno;
/*
** Each open file is managed by a separate instance of the "Pager" structure.
*/
typedef struct Pager Pager;
/*
** 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 flags);
void sqlite3pager_set_busyhandler(Pager*, BusyHandler *pBusyHandler);
void sqlite3pager_set_destructor(Pager*, void(*)(void*,int));
void sqlite3pager_set_reiniter(Pager*, void(*)(void*,int));
int sqlite3pager_set_pagesize(Pager*, int);
void sqlite3pager_read_fileheader(Pager*, int, unsigned char*);
void sqlite3pager_set_cachesize(Pager*, int);
int sqlite3pager_close(Pager *pPager);
int sqlite3pager_get(Pager *pPager, Pgno pgno, void **ppPage);
void *sqlite3pager_lookup(Pager *pPager, Pgno pgno);
int sqlite3pager_ref(void*);
int sqlite3pager_unref(void*);
Pgno sqlite3pager_pagenumber(void*);
int sqlite3pager_write(void*);
int sqlite3pager_iswriteable(void*);
int sqlite3pager_overwrite(Pager *pPager, Pgno pgno, void*);
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, Pgno);
int sqlite3pager_rollback(Pager*);
int sqlite3pager_isreadonly(Pager*);
int sqlite3pager_stmt_begin(Pager*);
int sqlite3pager_stmt_commit(Pager*);
int sqlite3pager_stmt_rollback(Pager*);
void sqlite3pager_dont_rollback(void*);
void sqlite3pager_dont_write(Pager*, Pgno);
int *sqlite3pager_stats(Pager*);
void sqlite3pager_set_safety_level(Pager*,int,int);
const char *sqlite3pager_filename(Pager*);
const char *sqlite3pager_dirname(Pager*);
const char *sqlite3pager_journalname(Pager*);
int sqlite3pager_nosync(Pager*);
int sqlite3pager_rename(Pager*, const char *zNewName);
void sqlite3pager_set_codec(Pager*,void(*)(void*,void*,Pgno,int),void*);
int sqlite3pager_movepage(Pager*,void*,Pgno);
int sqlite3pager_reset(Pager*);
int sqlite3pager_release_memory(int);
int sqlite3pager_loadall(Pager*);
#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
int sqlite3pager_lockstate(Pager*);
#endif
#ifdef SQLITE_TEST
void sqlite3pager_refdump(Pager*);
int pager3_refinfo_enable;
#endif
#endif /* _PAGER_H_ */

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -1,970 +0,0 @@
/*
** 2003 April 6
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
**
** May you do good and not evil.
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
*************************************************************************
** This file contains code used to implement the PRAGMA command.
**
** $Id: pragma.c,v 1.119 2006/02/17 12:25:16 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include "os.h"
#include <ctype.h>
/* Ignore this whole file if pragmas are disabled
*/
#if !defined(SQLITE_OMIT_PRAGMA) && !defined(SQLITE_OMIT_PARSER)
#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
# include "pager.h"
# include "btree.h"
#endif
/*
** 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
** unrecognized string argument.
**
** Note that the values returned are one less that the values that
** should be passed into sqlite3BtreeSetSafetyLevel(). The is done
** to support legacy SQL code. The safety level used to be boolean
** and older scripts may have used numbers 0 for OFF and 1 for ON.
*/
static int getSafetyLevel(const char *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);
}
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 char *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
** and 0 to use the compile-time default.
*/
static int getTempStore(const char *z){
if( z[0]>='0' && z[0]<='2' ){
return z[0] - '0';
}else if( sqlite3StrICmp(z, "file")==0 ){
return 1;
}else if( sqlite3StrICmp(z, "memory")==0 ){
return 2;
}else{
return 0;
}
}
#endif /* SQLITE_PAGER_PRAGMAS */
#ifndef SQLITE_OMIT_PAGER_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 invalidateTempStorage(Parse *pParse){
sqlite3 *db = pParse->db;
if( db->aDb[1].pBt!=0 ){
if( db->flags & SQLITE_InTrans ){
sqlite3ErrorMsg(pParse, "temporary storage cannot be changed "
"from within a transaction");
return SQLITE_ERROR;
}
sqlite3BtreeClose(db->aDb[1].pBt);
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.
*/
static void returnSingleInt(Parse *pParse, const char *zLabel, int value){
Vdbe *v = sqlite3GetVdbe(pParse);
sqlite3VdbeAddOp(v, OP_Integer, value, 0);
if( pParse->explain==0 ){
sqlite3VdbeSetNumCols(v, 1);
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, zLabel, P3_STATIC);
}
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 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 },
{ "full_column_names", SQLITE_FullColNames },
{ "short_column_names", SQLITE_ShortColNames },
{ "count_changes", SQLITE_CountRows },
{ "empty_result_callbacks", SQLITE_NullCallback },
{ "legacy_file_format", SQLITE_LegacyFileFmt },
{ "fullfsync", SQLITE_FullFSync },
#ifndef SQLITE_OMIT_CHECK
{ "ignore_check_constraints", SQLITE_IgnoreChecks },
#endif
/* The following is VERY experimental */
{ "writable_schema", SQLITE_WriteSchema },
{ "omit_readlock", SQLITE_NoReadlock },
/* TODO: Maybe it shouldn't be possible to change the ReadUncommitted
** flag if there are any active statements. */
{ "read_uncommitted", SQLITE_ReadUncommitted },
};
int i;
const struct sPragmaType *p;
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;
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;
}
}
}
return 1;
}
}
return 0;
}
#endif /* SQLITE_OMIT_FLAG_PRAGMAS */
/*
** Process a pragma statement.
**
** Pragmas are of this form:
**
** PRAGMA [database.]id [= value]
**
** The identifier might also be a string. The value is a string, and
** identifier, or a number. If minusFlag is true, then the value is
** a number that was preceded by a minus sign.
**
** If the left side is "database.id" then pId1 is the database name
** and pId2 is the id. If the left side is just "id" then pId1 is the
** id and pId2 is any empty string.
*/
void sqlite3Pragma(
Parse *pParse,
Token *pId1, /* First part of [database.]id field */
Token *pId2, /* Second part of [database.]id field, or NULL */
Token *pValue, /* Token for <value>, or NULL */
int minusFlag /* True if a '-' sign preceded <value> */
){
char *zLeft = 0; /* Nul-terminated UTF-8 string <id> */
char *zRight = 0; /* Nul-terminated UTF-8 string <value>, or NULL */
const char *zDb = 0; /* The database name */
Token *pId; /* Pointer to <id> token */
int iDb; /* Database index for <database> */
sqlite3 *db = pParse->db;
Db *pDb;
Vdbe *v = sqlite3GetVdbe(pParse);
if( v==0 ) return;
/* Interpret the [database.] part of the pragma statement. iDb is the
** index of the database this pragma is being applied to in db.aDb[]. */
iDb = sqlite3TwoPartName(pParse, pId1, pId2, &pId);
if( iDb<0 ) return;
pDb = &db->aDb[iDb];
/* If the temp database has been explicitly named as part of the
** pragma, make sure it is open.
*/
if( iDb==1 && sqlite3OpenTempDatabase(pParse) ){
return;
}
zLeft = sqlite3NameFromToken(pId);
if( !zLeft ) return;
if( minusFlag ){
zRight = sqlite3MPrintf("-%T", pValue);
}else{
zRight = sqlite3NameFromToken(pValue);
}
zDb = ((iDb>0)?pDb->zName:0);
if( sqlite3AuthCheck(pParse, SQLITE_PRAGMA, zLeft, zRight, zDb) ){
goto pragma_out;
}
#ifndef SQLITE_OMIT_PAGER_PRAGMAS
/*
** PRAGMA [database.]default_cache_size
** PRAGMA [database.]default_cache_size=N
**
** The first form reports the current persistent setting for the
** page cache size. The value returned is the maximum number of
** pages in the page cache. The second form sets both the current
** page cache size value and the persistent page cache size value
** stored in the database file.
**
** The default cache size is stored in meta-value 2 of page 1 of the
** database file. The cache size is actually the absolute value of
** this memory location. The sign of meta-value 2 determines the
** synchronous setting. A negative value means synchronous is off
** and a positive value means synchronous is on.
*/
if( sqlite3StrICmp(zLeft,"default_cache_size")==0 ){
static const VdbeOpList getCacheSize[] = {
{ OP_ReadCookie, 0, 2, 0}, /* 0 */
{ OP_AbsValue, 0, 0, 0},
{ OP_Dup, 0, 0, 0},
{ OP_Integer, 0, 0, 0},
{ OP_Ne, 0, 6, 0},
{ OP_Integer, 0, 0, 0}, /* 5 */
{ OP_Callback, 1, 0, 0},
};
int addr;
if( sqlite3ReadSchema(pParse) ) goto pragma_out;
if( !zRight ){
sqlite3VdbeSetNumCols(v, 1);
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "cache_size", P3_STATIC);
addr = sqlite3VdbeAddOpList(v, ArraySize(getCacheSize), getCacheSize);
sqlite3VdbeChangeP1(v, addr, iDb);
sqlite3VdbeChangeP1(v, addr+5, MAX_PAGES);
}else{
int size = atoi(zRight);
if( size<0 ) size = -size;
sqlite3BeginWriteOperation(pParse, 0, iDb);
sqlite3VdbeAddOp(v, OP_Integer, size, 0);
sqlite3VdbeAddOp(v, OP_ReadCookie, iDb, 2);
addr = sqlite3VdbeAddOp(v, OP_Integer, 0, 0);
sqlite3VdbeAddOp(v, OP_Ge, 0, addr+3);
sqlite3VdbeAddOp(v, OP_Negative, 0, 0);
sqlite3VdbeAddOp(v, OP_SetCookie, iDb, 2);
pDb->pSchema->cache_size = size;
sqlite3BtreeSetCacheSize(pDb->pBt, pDb->pSchema->cache_size);
}
}else
/*
** PRAGMA [database.]page_size
** PRAGMA [database.]page_size=N
**
** The first form reports the current setting for the
** database page size in bytes. The second form sets the
** database page size value. The value can only be set if
** the database has not yet been created.
*/
if( sqlite3StrICmp(zLeft,"page_size")==0 ){
Btree *pBt = pDb->pBt;
if( !zRight ){
int size = pBt ? sqlite3BtreeGetPageSize(pBt) : 0;
returnSingleInt(pParse, "page_size", size);
}else{
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
**
** The first form reports the current local setting for the
** page cache size. The local setting can be different from
** the persistent cache size value that is stored in the database
** file itself. The value returned is the maximum number of
** pages in the page cache. The second form sets the local
** page cache size value. It does not change the persistent
** cache size stored on the disk so the cache size will revert
** to its default value when the database is closed and reopened.
** N should be a positive integer.
*/
if( sqlite3StrICmp(zLeft,"cache_size")==0 ){
if( sqlite3ReadSchema(pParse) ) goto pragma_out;
if( !zRight ){
returnSingleInt(pParse, "cache_size", pDb->pSchema->cache_size);
}else{
int size = atoi(zRight);
if( size<0 ) size = -size;
pDb->pSchema->cache_size = size;
sqlite3BtreeSetCacheSize(pDb->pBt, pDb->pSchema->cache_size);
}
}else
/*
** PRAGMA temp_store
** PRAGMA temp_store = "default"|"memory"|"file"
**
** Return or set the local value of the temp_store flag. Changing
** the local value does not make changes to the disk file and the default
** value will be restored the next time the database is opened.
**
** Note that it is possible for the library compile-time options to
** override this setting
*/
if( sqlite3StrICmp(zLeft, "temp_store")==0 ){
if( !zRight ){
returnSingleInt(pParse, "temp_store", db->temp_store);
}else{
changeTempStorage(pParse, zRight);
}
}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, COLNAME_NAME,
"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
**
** Return or set the local value of the synchronous flag. Changing
** the local value does not make changes to the disk file and the
** default value will be restored the next time the database is
** opened.
*/
if( sqlite3StrICmp(zLeft,"synchronous")==0 ){
if( sqlite3ReadSchema(pParse) ) goto pragma_out;
if( !zRight ){
returnSingleInt(pParse, "synchronous", pDb->safety_level-1);
}else{
if( !db->autoCommit ){
sqlite3ErrorMsg(pParse,
"Safety level may not be changed inside a transaction");
}else{
pDb->safety_level = getSafetyLevel(zRight)+1;
}
}
}else
#endif /* SQLITE_OMIT_PAGER_PRAGMAS */
#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>)
**
** Return a single row for each column of the named table. The columns of
** the returned data set are:
**
** cid: Column id (numbered from left to right, starting at 0)
** name: Column name
** type: Column declaration type.
** notnull: True if 'NOT NULL' is part of column declaration
** dflt_value: The default value for the column, if any.
*/
if( sqlite3StrICmp(zLeft, "table_info")==0 && zRight ){
Table *pTab;
if( sqlite3ReadSchema(pParse) ) goto pragma_out;
pTab = sqlite3FindTable(db, zRight, zDb);
if( pTab ){
int i;
Column *pCol;
sqlite3VdbeSetNumCols(v, 6);
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "cid", P3_STATIC);
sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "name", P3_STATIC);
sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "type", P3_STATIC);
sqlite3VdbeSetColName(v, 3, COLNAME_NAME, "notnull", P3_STATIC);
sqlite3VdbeSetColName(v, 4, COLNAME_NAME, "dflt_value", P3_STATIC);
sqlite3VdbeSetColName(v, 5, COLNAME_NAME, "pk", P3_STATIC);
sqlite3ViewGetColumnNames(pParse, pTab);
for(i=0, pCol=pTab->aCol; i<pTab->nCol; i++, pCol++){
sqlite3VdbeAddOp(v, OP_Integer, i, 0);
sqlite3VdbeOp3(v, OP_String8, 0, 0, pCol->zName, 0);
sqlite3VdbeOp3(v, OP_String8, 0, 0,
pCol->zType ? pCol->zType : "numeric", 0);
sqlite3VdbeAddOp(v, OP_Integer, pCol->notNull, 0);
sqlite3ExprCode(pParse, pCol->pDflt);
sqlite3VdbeAddOp(v, OP_Integer, pCol->isPrimKey, 0);
sqlite3VdbeAddOp(v, OP_Callback, 6, 0);
}
}
}else
if( sqlite3StrICmp(zLeft, "index_info")==0 && zRight ){
Index *pIdx;
Table *pTab;
if( sqlite3ReadSchema(pParse) ) goto pragma_out;
pIdx = sqlite3FindIndex(db, zRight, zDb);
if( pIdx ){
int i;
pTab = pIdx->pTable;
sqlite3VdbeSetNumCols(v, 3);
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "seqno", P3_STATIC);
sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "cid", P3_STATIC);
sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "name", P3_STATIC);
for(i=0; i<pIdx->nColumn; i++){
int cnum = pIdx->aiColumn[i];
sqlite3VdbeAddOp(v, OP_Integer, i, 0);
sqlite3VdbeAddOp(v, OP_Integer, cnum, 0);
assert( pTab->nCol>cnum );
sqlite3VdbeOp3(v, OP_String8, 0, 0, pTab->aCol[cnum].zName, 0);
sqlite3VdbeAddOp(v, OP_Callback, 3, 0);
}
}
}else
if( sqlite3StrICmp(zLeft, "index_list")==0 && zRight ){
Index *pIdx;
Table *pTab;
if( sqlite3ReadSchema(pParse) ) goto pragma_out;
pTab = sqlite3FindTable(db, zRight, zDb);
if( pTab ){
v = sqlite3GetVdbe(pParse);
pIdx = pTab->pIndex;
if( pIdx ){
int i = 0;
sqlite3VdbeSetNumCols(v, 3);
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "seq", P3_STATIC);
sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "name", P3_STATIC);
sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "unique", P3_STATIC);
while(pIdx){
sqlite3VdbeAddOp(v, OP_Integer, i, 0);
sqlite3VdbeOp3(v, OP_String8, 0, 0, pIdx->zName, 0);
sqlite3VdbeAddOp(v, OP_Integer, pIdx->onError!=OE_None, 0);
sqlite3VdbeAddOp(v, OP_Callback, 3, 0);
++i;
pIdx = pIdx->pNext;
}
}
}
}else
if( sqlite3StrICmp(zLeft, "database_list")==0 ){
int i;
if( sqlite3ReadSchema(pParse) ) goto pragma_out;
sqlite3VdbeSetNumCols(v, 3);
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "seq", P3_STATIC);
sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "name", P3_STATIC);
sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "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, COLNAME_NAME, "seq", P3_STATIC);
sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "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;
if( sqlite3ReadSchema(pParse) ) goto pragma_out;
pTab = sqlite3FindTable(db, zRight, zDb);
if( pTab ){
v = sqlite3GetVdbe(pParse);
pFK = pTab->pFKey;
if( pFK ){
int i = 0;
sqlite3VdbeSetNumCols(v, 5);
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "id", P3_STATIC);
sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "seq", P3_STATIC);
sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "table", P3_STATIC);
sqlite3VdbeSetColName(v, 3, COLNAME_NAME, "from", P3_STATIC);
sqlite3VdbeSetColName(v, 4, COLNAME_NAME, "to", P3_STATIC);
while(pFK){
int j;
for(j=0; j<pFK->nCol; j++){
char *zCol = pFK->aCol[j].zCol;
sqlite3VdbeAddOp(v, OP_Integer, i, 0);
sqlite3VdbeAddOp(v, OP_Integer, j, 0);
sqlite3VdbeOp3(v, OP_String8, 0, 0, pFK->zTo, 0);
sqlite3VdbeOp3(v, OP_String8, 0, 0,
pTab->aCol[pFK->aCol[j].iFrom].zName, 0);
sqlite3VdbeOp3(v, zCol ? OP_String8 : OP_Null, 0, 0, zCol, 0);
sqlite3VdbeAddOp(v, OP_Callback, 5, 0);
}
++i;
pFK = pFK->pNextFrom;
}
}
}
}else
#endif /* !defined(SQLITE_OMIT_FOREIGN_KEY) */
#ifndef NDEBUG
if( sqlite3StrICmp(zLeft, "parser_trace")==0 ){
extern void sqlite3ParserTrace(FILE*, char *);
if( zRight ){
if( getBoolean(zRight) ){
sqlite3ParserTrace(stderr, "parser: ");
}else{
sqlite3ParserTrace(0, 0);
}
}
}else
#endif
/* Reinstall the LIKE and GLOB functions. The variant of LIKE
** used will be case sensitive or not depending on the RHS.
*/
if( sqlite3StrICmp(zLeft, "case_sensitive_like")==0 ){
if( zRight ){
sqlite3RegisterLikeFunctions(db, getBoolean(zRight));
}
}else
#ifndef SQLITE_OMIT_INTEGRITY_CHECK
if( sqlite3StrICmp(zLeft, "integrity_check")==0 ){
int i, j, addr;
/* Code that appears at the end of the integrity check. If no error
** messages have been generated, output OK. Otherwise output the
** error message
*/
static const VdbeOpList endCode[] = {
{ OP_MemLoad, 0, 0, 0},
{ OP_Integer, 0, 0, 0},
{ OP_Ne, 0, 0, 0}, /* 2 */
{ OP_String8, 0, 0, "ok"},
{ OP_Callback, 1, 0, 0},
};
/* Initialize the VDBE program */
if( sqlite3ReadSchema(pParse) ) goto pragma_out;
sqlite3VdbeSetNumCols(v, 1);
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "integrity_check", P3_STATIC);
sqlite3VdbeAddOp(v, OP_MemInt, 0, 0); /* Initialize error count to 0 */
/* Do an integrity check on each database file */
for(i=0; i<db->nDb; i++){
HashElem *x;
Hash *pTbls;
int cnt = 0;
if( OMIT_TEMPDB && i==1 ) continue;
sqlite3CodeVerifySchema(pParse, i);
/* Do an integrity check of the B-Tree
*/
pTbls = &db->aDb[i].pSchema->tblHash;
for(x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){
Table *pTab = sqliteHashData(x);
Index *pIdx;
sqlite3VdbeAddOp(v, OP_Integer, pTab->tnum, 0);
cnt++;
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
sqlite3VdbeAddOp(v, OP_Integer, pIdx->tnum, 0);
cnt++;
}
}
assert( cnt>0 );
sqlite3VdbeAddOp(v, OP_IntegrityCk, cnt, i);
sqlite3VdbeAddOp(v, OP_Dup, 0, 1);
addr = sqlite3VdbeOp3(v, OP_String8, 0, 0, "ok", P3_STATIC);
sqlite3VdbeAddOp(v, OP_Eq, 0, addr+7);
sqlite3VdbeOp3(v, OP_String8, 0, 0,
sqlite3MPrintf("*** in database %s ***\n", db->aDb[i].zName),
P3_DYNAMIC);
sqlite3VdbeAddOp(v, OP_Pull, 1, 0);
sqlite3VdbeAddOp(v, OP_Concat, 0, 1);
sqlite3VdbeAddOp(v, OP_Callback, 1, 0);
sqlite3VdbeAddOp(v, OP_MemIncr, 1, 0);
/* Make sure all the indices are constructed correctly.
*/
sqlite3CodeVerifySchema(pParse, i);
for(x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){
Table *pTab = sqliteHashData(x);
Index *pIdx;
int loopTop;
if( pTab->pIndex==0 ) continue;
sqlite3OpenTableAndIndices(pParse, pTab, 1, OP_OpenRead);
sqlite3VdbeAddOp(v, OP_MemInt, 0, 1);
loopTop = sqlite3VdbeAddOp(v, OP_Rewind, 1, 0);
sqlite3VdbeAddOp(v, OP_MemIncr, 1, 1);
for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
int jmp2;
static const VdbeOpList idxErr[] = {
{ OP_MemIncr, 1, 0, 0},
{ OP_String8, 0, 0, "rowid "},
{ OP_Rowid, 1, 0, 0},
{ OP_String8, 0, 0, " missing from index "},
{ OP_String8, 0, 0, 0}, /* 4 */
{ OP_Concat, 2, 0, 0},
{ OP_Callback, 1, 0, 0},
};
sqlite3GenerateIndexKey(v, pIdx, 1);
jmp2 = sqlite3VdbeAddOp(v, OP_Found, j+2, 0);
addr = sqlite3VdbeAddOpList(v, ArraySize(idxErr), idxErr);
sqlite3VdbeChangeP3(v, addr+4, pIdx->zName, P3_STATIC);
sqlite3VdbeJumpHere(v, jmp2);
}
sqlite3VdbeAddOp(v, OP_Next, 1, loopTop+1);
sqlite3VdbeJumpHere(v, loopTop);
for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
static const VdbeOpList cntIdx[] = {
{ OP_MemInt, 0, 2, 0},
{ OP_Rewind, 0, 0, 0}, /* 1 */
{ OP_MemIncr, 1, 2, 0},
{ OP_Next, 0, 0, 0}, /* 3 */
{ OP_MemLoad, 1, 0, 0},
{ OP_MemLoad, 2, 0, 0},
{ OP_Eq, 0, 0, 0}, /* 6 */
{ OP_MemIncr, 1, 0, 0},
{ OP_String8, 0, 0, "wrong # of entries in index "},
{ OP_String8, 0, 0, 0}, /* 9 */
{ OP_Concat, 0, 0, 0},
{ OP_Callback, 1, 0, 0},
};
if( pIdx->tnum==0 ) continue;
addr = sqlite3VdbeAddOpList(v, ArraySize(cntIdx), cntIdx);
sqlite3VdbeChangeP1(v, addr+1, j+2);
sqlite3VdbeChangeP2(v, addr+1, addr+4);
sqlite3VdbeChangeP1(v, addr+3, j+2);
sqlite3VdbeChangeP2(v, addr+3, addr+2);
sqlite3VdbeJumpHere(v, addr+6);
sqlite3VdbeChangeP3(v, addr+9, pIdx->zName, P3_STATIC);
}
}
}
addr = sqlite3VdbeAddOpList(v, ArraySize(endCode), endCode);
sqlite3VdbeJumpHere(v, addr+2);
}else
#endif /* SQLITE_OMIT_INTEGRITY_CHECK */
#ifndef SQLITE_OMIT_UTF16
/*
** PRAGMA encoding
** PRAGMA encoding = "utf-8"|"utf-16"|"utf-16le"|"utf-16be"
**
** In it's first form, this pragma returns the encoding of the main
** database. If the database is not initialized, it is initialized now.
**
** The second form of this pragma is a no-op if the main database file
** has not already been initialized. In this case it sets the default
** encoding that will be used for the main database file if a new file
** is created. If an existing main database file is opened, then the
** default text encoding for the existing database is used.
**
** In all cases new databases created using the ATTACH command are
** created to use the same default text encoding as the main database. If
** the main database has not been initialized and/or created when ATTACH
** is executed, this is done before the ATTACH operation.
**
** In the second form this pragma sets the text encoding to be used in
** new database files created using this database handle. It is only
** useful if invoked immediately after the main database i
*/
if( sqlite3StrICmp(zLeft, "encoding")==0 ){
static struct EncName {
char *zName;
u8 enc;
} encnames[] = {
{ "UTF-8", SQLITE_UTF8 },
{ "UTF8", SQLITE_UTF8 },
{ "UTF-16le", SQLITE_UTF16LE },
{ "UTF16le", SQLITE_UTF16LE },
{ "UTF-16be", SQLITE_UTF16BE },
{ "UTF16be", SQLITE_UTF16BE },
{ "UTF-16", 0 /* Filled in at run-time */ },
{ "UTF16", 0 /* Filled in at run-time */ },
{ 0, 0 }
};
struct EncName *pEnc;
encnames[6].enc = encnames[7].enc = SQLITE_UTF16NATIVE;
if( !zRight ){ /* "PRAGMA encoding" */
if( sqlite3ReadSchema(pParse) ) goto pragma_out;
sqlite3VdbeSetNumCols(v, 1);
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "encoding", P3_STATIC);
sqlite3VdbeAddOp(v, OP_String8, 0, 0);
for(pEnc=&encnames[0]; pEnc->zName; pEnc++){
if( pEnc->enc==ENC(pParse->db) ){
sqlite3VdbeChangeP3(v, -1, pEnc->zName, P3_STATIC);
break;
}
}
sqlite3VdbeAddOp(v, OP_Callback, 1, 0);
}else{ /* "PRAGMA encoding = XXX" */
/* Only change the value of sqlite.enc if the database handle is not
** initialized. If the main database exists, the new sqlite.enc value
** will be overwritten when the schema is next loaded. If it does not
** already exists, it will be created to use the new encoding value.
*/
if(
!(DbHasProperty(db, 0, DB_SchemaLoaded)) ||
DbHasProperty(db, 0, DB_Empty)
){
for(pEnc=&encnames[0]; pEnc->zName; pEnc++){
if( 0==sqlite3StrICmp(zRight, pEnc->zName) ){
ENC(pParse->db) = pEnc->enc;
break;
}
}
if( !pEnc->zName ){
sqlite3ErrorMsg(pParse, "unsupported encoding: %s", zRight);
}
}
}
}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)
/*
** Report the current state of file logs for all databases
*/
if( sqlite3StrICmp(zLeft, "lock_status")==0 ){
static const char *const azLockName[] = {
"unlocked", "shared", "reserved", "pending", "exclusive"
};
int i;
Vdbe *v = sqlite3GetVdbe(pParse);
sqlite3VdbeSetNumCols(v, 2);
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "database", P3_STATIC);
sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "status", P3_STATIC);
for(i=0; i<db->nDb; i++){
Btree *pBt;
Pager *pPager;
if( db->aDb[i].zName==0 ) continue;
sqlite3VdbeOp3(v, OP_String8, 0, 0, db->aDb[i].zName, P3_STATIC);
pBt = db->aDb[i].pBt;
if( pBt==0 || (pPager = sqlite3BtreePager(pBt))==0 ){
sqlite3VdbeOp3(v, OP_String8, 0, 0, "closed", P3_STATIC);
}else{
int j = sqlite3pager_lockstate(pPager);
sqlite3VdbeOp3(v, OP_String8, 0, 0,
(j>=0 && j<=4) ? azLockName[j] : "unknown", P3_STATIC);
}
sqlite3VdbeAddOp(v, OP_Callback, 2, 0);
}
}else
#endif
#ifdef SQLITE_SSE
/*
** Check to see if the sqlite_statements table exists. Create it
** if it does not.
*/
if( sqlite3StrICmp(zLeft, "create_sqlite_statement_table")==0 ){
extern int sqlite3CreateStatementsTable(Parse*);
sqlite3CreateStatementsTable(pParse);
}else
#endif
#if SQLITE_HAS_CODEC
if( sqlite3StrICmp(zLeft, "key")==0 ){
sqlite3_key(db, zRight, strlen(zRight));
}else
#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);
/*
** Reset the safety level, in case the fullfsync flag or synchronous
** setting changed.
*/
#ifndef SQLITE_OMIT_PAGER_PRAGMAS
if( db->autoCommit ){
sqlite3BtreeSetSafetyLevel(pDb->pBt, pDb->safety_level,
(db->flags&SQLITE_FullFSync)!=0);
}
#endif
}
pragma_out:
sqliteFree(zLeft);
sqliteFree(zRight);
}
#endif /* SQLITE_OMIT_PRAGMA || SQLITE_OMIT_PARSER */

Просмотреть файл

@ -13,7 +13,7 @@
** interface, and routines that contribute to loading the database schema
** from disk.
**
** $Id: prepare.c,v 1.4 2006-02-22 20:47:51 brettw%gmail.com Exp $
** $Id: prepare.c,v 1.5 2006-05-22 17:48:14 brettw%gmail.com Exp $
*/
#include "sqliteInt.h"
#include "os.h"
@ -74,6 +74,7 @@ int sqlite3InitCallback(void *pInit, int argc, char **argv, char **azColName){
db->init.newTnum = atoi(argv[1]);
rc = sqlite3_exec(db, argv[2], 0, 0, &zErr);
db->init.iDb = 0;
assert( rc!=SQLITE_OK || zErr==0 );
if( SQLITE_OK!=rc ){
if( rc==SQLITE_NOMEM ){
sqlite3FailedMalloc();
@ -409,57 +410,6 @@ static int schemaIsValid(sqlite3 *db){
return allOk;
}
/*
** Free all resources held by the schema structure. The void* argument points
** at a Schema struct. This function does not call sqliteFree() on the
** pointer itself, it just cleans up subsiduary resources (i.e. the contents
** of the schema hash tables).
*/
void sqlite3SchemaFree(void *p){
Hash temp1;
Hash temp2;
HashElem *pElem;
Schema *pSchema = (Schema *)p;
temp1 = pSchema->tblHash;
temp2 = pSchema->trigHash;
sqlite3HashInit(&pSchema->trigHash, SQLITE_HASH_STRING, 0);
sqlite3HashClear(&pSchema->aFKey);
sqlite3HashClear(&pSchema->idxHash);
for(pElem=sqliteHashFirst(&temp2); pElem; pElem=sqliteHashNext(pElem)){
sqlite3DeleteTrigger((Trigger*)sqliteHashData(pElem));
}
sqlite3HashClear(&temp2);
sqlite3HashInit(&pSchema->tblHash, SQLITE_HASH_STRING, 0);
for(pElem=sqliteHashFirst(&temp1); pElem; pElem=sqliteHashNext(pElem)){
Table *pTab = sqliteHashData(pElem);
sqlite3DeleteTable(0, pTab);
}
sqlite3HashClear(&temp1);
pSchema->pSeqTab = 0;
pSchema->flags &= ~DB_SchemaLoaded;
}
/*
** Find and return the schema associated with a BTree. Create
** a new one if necessary.
*/
Schema *sqlite3SchemaGet(Btree *pBt){
Schema * p;
if( pBt ){
p = (Schema *)sqlite3BtreeSchema(pBt,sizeof(Schema),sqlite3SchemaFree);
}else{
p = (Schema *)sqliteMalloc(sizeof(Schema));
}
if( p && 0==p->file_format ){
sqlite3HashInit(&p->tblHash, SQLITE_HASH_STRING, 0);
sqlite3HashInit(&p->idxHash, SQLITE_HASH_STRING, 0);
sqlite3HashInit(&p->trigHash, SQLITE_HASH_STRING, 0);
sqlite3HashInit(&p->aFKey, SQLITE_HASH_STRING, 1);
}
return p;
}
/*
** Convert a schema pointer into the iDb index that indicates
** which database file in db->aDb[] the schema refers to.

Просмотреть файл

@ -1,868 +0,0 @@
/*
** The "printf" code that follows dates from the 1980's. It is in
** the public domain. The original comments are included here for
** completeness. They are very out-of-date but might be useful as
** an historical reference. Most of the "enhancements" have been backed
** out so that the functionality is now the same as standard printf().
**
**************************************************************************
**
** The following modules is an enhanced replacement for the "printf" subroutines
** found in the standard C library. The following enhancements are
** supported:
**
** + Additional functions. The standard set of "printf" functions
** includes printf, fprintf, sprintf, vprintf, vfprintf, and
** vsprintf. This module adds the following:
**
** * snprintf -- Works like sprintf, but has an extra argument
** which is the size of the buffer written to.
**
** * mprintf -- Similar to sprintf. Writes output to memory
** obtained from malloc.
**
** * xprintf -- Calls a function to dispose of output.
**
** * nprintf -- No output, but returns the number of characters
** that would have been output by printf.
**
** * A v- version (ex: vsnprintf) of every function is also
** supplied.
**
** + A few extensions to the formatting notation are supported:
**
** * The "=" flag (similar to "-") causes the output to be
** be centered in the appropriately sized field.
**
** * The %b field outputs an integer in binary notation.
**
** * The %c field now accepts a precision. The character output
** is repeated by the number of times the precision specifies.
**
** * The %' field works like %c, but takes as its character the
** next character of the format string, instead of the next
** argument. For example, printf("%.78'-") prints 78 minus
** signs, the same as printf("%.78c",'-').
**
** + When compiled using GCC on a SPARC, this version of printf is
** faster than the library printf for SUN OS 4.1.
**
** + All functions are fully reentrant.
**
*/
#include "sqliteInt.h"
/*
** Conversion types fall into various categories as defined by the
** following enumeration.
*/
#define etRADIX 1 /* Integer types. %d, %x, %o, and so forth */
#define etFLOAT 2 /* Floating point. %f */
#define etEXP 3 /* Exponentional notation. %e and %E */
#define etGENERIC 4 /* Floating or exponential, depending on exponent. %g */
#define etSIZE 5 /* Return number of characters processed so far. %n */
#define etSTRING 6 /* Strings. %s */
#define etDYNSTRING 7 /* Dynamically allocated strings. %z */
#define etPERCENT 8 /* Percent symbol. %% */
#define etCHARX 9 /* Characters. %c */
#define etERROR 10 /* Used to indicate no such conversion type */
/* The rest are extensions, not normally found in printf() */
#define etCHARLIT 11 /* Literal characters. %' */
#define etSQLESCAPE 12 /* Strings with '\'' doubled. %q */
#define etSQLESCAPE2 13 /* Strings with '\'' doubled and enclosed in '',
NULL pointers replaced by SQL NULL. %Q */
#define etTOKEN 14 /* a pointer to a Token structure */
#define etSRCLIST 15 /* a pointer to a SrcList */
#define etPOINTER 16 /* The %p conversion */
/*
** An "etByte" is an 8-bit unsigned value.
*/
typedef unsigned char etByte;
/*
** Each builtin conversion character (ex: the 'd' in "%d") is described
** by an instance of the following structure
*/
typedef struct et_info { /* Information about each format field */
char fmttype; /* The format field code letter */
etByte base; /* The base for radix conversion */
etByte flags; /* One or more of FLAG_ constants below */
etByte type; /* Conversion paradigm */
etByte charset; /* Offset into aDigits[] of the digits string */
etByte prefix; /* Offset into aPrefix[] of the prefix string */
} et_info;
/*
** Allowed values for et_info.flags
*/
#define FLAG_SIGNED 1 /* True if the value to convert is signed */
#define FLAG_INTERN 2 /* True if for internal use only */
#define FLAG_STRING 4 /* Allow infinity precision */
/*
** The following table is searched linearly, so it is good to put the
** most frequently used conversion types first.
*/
static const char aDigits[] = "0123456789ABCDEF0123456789abcdef";
static const char aPrefix[] = "-x0\000X0";
static const et_info fmtinfo[] = {
{ 'd', 10, 1, etRADIX, 0, 0 },
{ 's', 0, 4, etSTRING, 0, 0 },
{ 'g', 0, 1, etGENERIC, 30, 0 },
{ 'z', 0, 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 },
{ 'x', 16, 0, etRADIX, 16, 1 },
{ 'X', 16, 0, etRADIX, 0, 4 },
#ifndef SQLITE_OMIT_FLOATING_POINT
{ 'f', 0, 1, etFLOAT, 0, 0 },
{ 'e', 0, 1, etEXP, 30, 0 },
{ 'E', 0, 1, etEXP, 14, 0 },
{ 'G', 0, 1, etGENERIC, 14, 0 },
#endif
{ 'i', 10, 1, etRADIX, 0, 0 },
{ 'n', 0, 0, etSIZE, 0, 0 },
{ '%', 0, 0, etPERCENT, 0, 0 },
{ 'p', 16, 0, etPOINTER, 0, 1 },
{ 'T', 0, 2, etTOKEN, 0, 0 },
{ 'S', 0, 2, etSRCLIST, 0, 0 },
};
#define etNINFO (sizeof(fmtinfo)/sizeof(fmtinfo[0]))
/*
** If SQLITE_OMIT_FLOATING_POINT is defined, then none of the floating point
** conversions will work.
*/
#ifndef SQLITE_OMIT_FLOATING_POINT
/*
** "*val" is a double such that 0.1 <= *val < 10.0
** Return the ascii code for the leading digit of *val, then
** multiply "*val" by 10.0 to renormalize.
**
** Example:
** input: *val = 3.14159
** output: *val = 1.4159 function return = '3'
**
** The counter *cnt is incremented each time. After counter exceeds
** 16 (the number of significant digits in a 64-bit float) '0' is
** always returned.
*/
static int et_getdigit(LONGDOUBLE_TYPE *val, int *cnt){
int digit;
LONGDOUBLE_TYPE d;
if( (*cnt)++ >= 16 ) return '0';
digit = (int)*val;
d = digit;
digit += '0';
*val = (*val - d)*10.0;
return digit;
}
#endif /* SQLITE_OMIT_FLOATING_POINT */
/*
** On machines with a small stack size, you can redefine the
** SQLITE_PRINT_BUF_SIZE to be less than 350. But beware - for
** smaller values some %f conversions may go into an infinite loop.
*/
#ifndef SQLITE_PRINT_BUF_SIZE
# define SQLITE_PRINT_BUF_SIZE 350
#endif
#define etBUFSIZE SQLITE_PRINT_BUF_SIZE /* Size of the output buffer */
/*
** The root program. All variations call this core.
**
** INPUTS:
** func This is a pointer to a function taking three arguments
** 1. A pointer to anything. Same as the "arg" parameter.
** 2. A pointer to the list of characters to be output
** (Note, this list is NOT null terminated.)
** 3. An integer number of characters to be output.
** (Note: This number might be zero.)
**
** arg This is the pointer to anything which will be passed as the
** first argument to "func". Use it for whatever you like.
**
** fmt This is the format string, as in the usual print.
**
** ap This is a pointer to a list of arguments. Same as in
** vfprint.
**
** OUTPUTS:
** The return value is the total number of characters sent to
** the function "func". Returns -1 on a error.
**
** Note that the order in which automatic variables are declared below
** seems to make a big difference in determining how fast this beast
** will run.
*/
static int vxprintf(
void (*func)(void*,const char*,int), /* Consumer of text */
void *arg, /* First argument to the consumer */
int useExtended, /* Allow extended %-conversions */
const char *fmt, /* Format string */
va_list ap /* arguments */
){
int c; /* Next character in the format string */
char *bufpt; /* Pointer to the conversion buffer */
int precision; /* Precision of the current field */
int length; /* Length of the field */
int idx; /* A general purpose loop counter */
int count; /* Total number of characters output */
int width; /* Width of the current field */
etByte flag_leftjustify; /* True if "-" flag is present */
etByte flag_plussign; /* True if "+" flag is present */
etByte flag_blanksign; /* True if " " flag is present */
etByte flag_alternateform; /* True if "#" flag is present */
etByte flag_altform2; /* True if "!" flag is present */
etByte flag_zeropad; /* True if field width constant starts with zero */
etByte flag_long; /* True if "l" flag is present */
etByte flag_longlong; /* True if the "ll" flag is present */
etByte done; /* Loop termination flag */
UINT64_TYPE longvalue; /* Value for integer types */
LONGDOUBLE_TYPE realvalue; /* Value for real types */
const et_info *infop; /* Pointer to the appropriate info structure */
char buf[etBUFSIZE]; /* Conversion buffer */
char prefix; /* Prefix character. "+" or "-" or " " or '\0'. */
etByte errorflag = 0; /* True if an error is encountered */
etByte xtype; /* Conversion paradigm */
char *zExtra; /* Extra memory used for etTCLESCAPE conversions */
static const char spaces[] =
" ";
#define etSPACESIZE (sizeof(spaces)-1)
#ifndef SQLITE_OMIT_FLOATING_POINT
int exp, e2; /* exponent of real numbers */
double rounder; /* Used for rounding floating point values */
etByte flag_dp; /* True if decimal point should be shown */
etByte flag_rtz; /* True if trailing zeros should be removed */
etByte flag_exp; /* True to force display of the exponent */
int nsd; /* Number of significant digits returned */
#endif
func(arg,"",0);
count = length = 0;
bufpt = 0;
for(; (c=(*fmt))!=0; ++fmt){
if( c!='%' ){
int amt;
bufpt = (char *)fmt;
amt = 1;
while( (c=(*++fmt))!='%' && c!=0 ) amt++;
(*func)(arg,bufpt,amt);
count += amt;
if( c==0 ) break;
}
if( (c=(*++fmt))==0 ){
errorflag = 1;
(*func)(arg,"%",1);
count++;
break;
}
/* Find out what flags are present */
flag_leftjustify = flag_plussign = flag_blanksign =
flag_alternateform = flag_altform2 = flag_zeropad = 0;
done = 0;
do{
switch( c ){
case '-': flag_leftjustify = 1; break;
case '+': flag_plussign = 1; break;
case ' ': flag_blanksign = 1; break;
case '#': flag_alternateform = 1; break;
case '!': flag_altform2 = 1; break;
case '0': flag_zeropad = 1; break;
default: done = 1; break;
}
}while( !done && (c=(*++fmt))!=0 );
/* Get the field width */
width = 0;
if( c=='*' ){
width = va_arg(ap,int);
if( width<0 ){
flag_leftjustify = 1;
width = -width;
}
c = *++fmt;
}else{
while( c>='0' && c<='9' ){
width = width*10 + c - '0';
c = *++fmt;
}
}
if( width > etBUFSIZE-10 ){
width = etBUFSIZE-10;
}
/* Get the precision */
if( c=='.' ){
precision = 0;
c = *++fmt;
if( c=='*' ){
precision = va_arg(ap,int);
if( precision<0 ) precision = -precision;
c = *++fmt;
}else{
while( c>='0' && c<='9' ){
precision = precision*10 + c - '0';
c = *++fmt;
}
}
}else{
precision = -1;
}
/* Get the conversion type modifier */
if( c=='l' ){
flag_long = 1;
c = *++fmt;
if( c=='l' ){
flag_longlong = 1;
c = *++fmt;
}else{
flag_longlong = 0;
}
}else{
flag_long = flag_longlong = 0;
}
/* Fetch the info entry for the field */
infop = 0;
xtype = etERROR;
for(idx=0; idx<etNINFO; idx++){
if( c==fmtinfo[idx].fmttype ){
infop = &fmtinfo[idx];
if( useExtended || (infop->flags & FLAG_INTERN)==0 ){
xtype = infop->type;
}
break;
}
}
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:
**
** flag_alternateform TRUE if a '#' is present.
** flag_altform2 TRUE if a '!' is present.
** flag_plussign TRUE if a '+' is present.
** flag_leftjustify TRUE if a '-' is present or if the
** field width was negative.
** flag_zeropad TRUE if the width began with 0.
** flag_long TRUE if the letter 'l' (ell) prefixed
** the conversion character.
** flag_longlong TRUE if the letter 'll' (ell ell) prefixed
** the conversion character.
** flag_blanksign TRUE if a ' ' is present.
** width The specified field width. This is
** always non-negative. Zero is the default.
** precision The specified precision. The default
** is -1.
** xtype The class of the conversion.
** infop Pointer to the appropriate info struct.
*/
switch( xtype ){
case etPOINTER:
flag_longlong = sizeof(char*)==sizeof(i64);
flag_long = sizeof(char*)==sizeof(long int);
/* Fall through into the next case */
case etRADIX:
if( infop->flags & FLAG_SIGNED ){
i64 v;
if( flag_longlong ) v = va_arg(ap,i64);
else if( flag_long ) v = va_arg(ap,long int);
else v = va_arg(ap,int);
if( v<0 ){
longvalue = -v;
prefix = '-';
}else{
longvalue = v;
if( flag_plussign ) prefix = '+';
else if( flag_blanksign ) prefix = ' ';
else prefix = 0;
}
}else{
if( flag_longlong ) longvalue = va_arg(ap,u64);
else if( flag_long ) longvalue = va_arg(ap,unsigned long int);
else longvalue = va_arg(ap,unsigned int);
prefix = 0;
}
if( longvalue==0 ) flag_alternateform = 0;
if( flag_zeropad && precision<width-(prefix!=0) ){
precision = width-(prefix!=0);
}
bufpt = &buf[etBUFSIZE-1];
{
register const char *cset; /* Use registers for speed */
register int base;
cset = &aDigits[infop->charset];
base = infop->base;
do{ /* Convert to ascii */
*(--bufpt) = cset[longvalue%base];
longvalue = longvalue/base;
}while( longvalue>0 );
}
length = &buf[etBUFSIZE-1]-bufpt;
for(idx=precision-length; idx>0; idx--){
*(--bufpt) = '0'; /* Zero pad */
}
if( prefix ) *(--bufpt) = prefix; /* Add sign */
if( flag_alternateform && infop->prefix ){ /* Add "0" or "0x" */
const char *pre;
char x;
pre = &aPrefix[infop->prefix];
if( *bufpt!=pre[0] ){
for(; (x=(*pre))!=0; pre++) *(--bufpt) = x;
}
}
length = &buf[etBUFSIZE-1]-bufpt;
break;
case etFLOAT:
case etEXP:
case etGENERIC:
realvalue = va_arg(ap,double);
#ifndef SQLITE_OMIT_FLOATING_POINT
if( precision<0 ) precision = 6; /* Set default precision */
if( precision>etBUFSIZE/2-10 ) precision = etBUFSIZE/2-10;
if( realvalue<0.0 ){
realvalue = -realvalue;
prefix = '-';
}else{
if( flag_plussign ) prefix = '+';
else if( flag_blanksign ) prefix = ' ';
else prefix = 0;
}
if( xtype==etGENERIC && precision>0 ) precision--;
#if 0
/* Rounding works like BSD when the constant 0.4999 is used. Wierd! */
for(idx=precision, rounder=0.4999; idx>0; idx--, rounder*=0.1);
#else
/* It makes more sense to use 0.5 */
for(idx=precision, rounder=0.5; idx>0; idx--, rounder*=0.1);
#endif
if( xtype==etFLOAT ) realvalue += rounder;
/* Normalize realvalue to within 10.0 > realvalue >= 1.0 */
exp = 0;
if( realvalue>0.0 ){
while( realvalue>=1e32 && exp<=350 ){ realvalue *= 1e-32; exp+=32; }
while( realvalue>=1e8 && exp<=350 ){ realvalue *= 1e-8; exp+=8; }
while( realvalue>=10.0 && exp<=350 ){ realvalue *= 0.1; exp++; }
while( realvalue<1e-8 && exp>=-350 ){ realvalue *= 1e8; exp-=8; }
while( realvalue<1.0 && exp>=-350 ){ realvalue *= 10.0; exp--; }
if( exp>350 || exp<-350 ){
bufpt = "NaN";
length = 3;
break;
}
}
bufpt = buf;
/*
** If the field type is etGENERIC, then convert to either etEXP
** or etFLOAT, as appropriate.
*/
flag_exp = xtype==etEXP;
if( xtype!=etFLOAT ){
realvalue += rounder;
if( realvalue>=10.0 ){ realvalue *= 0.1; exp++; }
}
if( xtype==etGENERIC ){
flag_rtz = !flag_alternateform;
if( exp<-4 || exp>precision ){
xtype = etEXP;
}else{
precision = precision - exp;
xtype = etFLOAT;
}
}else{
flag_rtz = 0;
}
if( xtype==etEXP ){
e2 = 0;
}else{
e2 = exp;
}
nsd = 0;
flag_dp = (precision>0) | flag_alternateform | flag_altform2;
/* The sign in front of the number */
if( prefix ){
*(bufpt++) = prefix;
}
/* Digits prior to the decimal point */
if( e2<0 ){
*(bufpt++) = '0';
}else{
for(; e2>=0; e2--){
*(bufpt++) = et_getdigit(&realvalue,&nsd);
}
}
/* The decimal point */
if( flag_dp ){
*(bufpt++) = '.';
}
/* "0" digits after the decimal point but before the first
** significant digit of the number */
for(e2++; e2<0 && precision>0; precision--, e2++){
*(bufpt++) = '0';
}
/* Significant digits after the decimal point */
while( (precision--)>0 ){
*(bufpt++) = et_getdigit(&realvalue,&nsd);
}
/* Remove trailing zeros and the "." if no digits follow the "." */
if( flag_rtz && flag_dp ){
while( bufpt[-1]=='0' ) *(--bufpt) = 0;
assert( bufpt>buf );
if( bufpt[-1]=='.' ){
if( flag_altform2 ){
*(bufpt++) = '0';
}else{
*(--bufpt) = 0;
}
}
}
/* Add the "eNNN" suffix */
if( flag_exp || (xtype==etEXP && exp) ){
*(bufpt++) = aDigits[infop->charset];
if( exp<0 ){
*(bufpt++) = '-'; exp = -exp;
}else{
*(bufpt++) = '+';
}
if( exp>=100 ){
*(bufpt++) = (exp/100)+'0'; /* 100's digit */
exp %= 100;
}
*(bufpt++) = exp/10+'0'; /* 10's digit */
*(bufpt++) = exp%10+'0'; /* 1's digit */
}
*bufpt = 0;
/* The converted number is in buf[] and zero terminated. Output it.
** Note that the number is in the usual order, not reversed as with
** integer conversions. */
length = bufpt-buf;
bufpt = buf;
/* Special case: Add leading zeros if the flag_zeropad flag is
** set and we are not left justified */
if( flag_zeropad && !flag_leftjustify && length < width){
int i;
int nPad = width - length;
for(i=width; i>=nPad; i--){
bufpt[i] = bufpt[i-nPad];
}
i = prefix!=0;
while( nPad-- ) bufpt[i++] = '0';
length = width;
}
#endif
break;
case etSIZE:
*(va_arg(ap,int*)) = count;
length = width = 0;
break;
case etPERCENT:
buf[0] = '%';
bufpt = buf;
length = 1;
break;
case etCHARLIT:
case etCHARX:
c = buf[0] = (xtype==etCHARX ? va_arg(ap,int) : *++fmt);
if( precision>=0 ){
for(idx=1; idx<precision; idx++) buf[idx] = c;
length = precision;
}else{
length =1;
}
bufpt = buf;
break;
case etSTRING:
case etDYNSTRING:
bufpt = va_arg(ap,char*);
if( bufpt==0 ){
bufpt = "";
}else if( xtype==etDYNSTRING ){
zExtra = bufpt;
}
length = strlen(bufpt);
if( precision>=0 && precision<length ) length = precision;
break;
case etSQLESCAPE:
case etSQLESCAPE2: {
int i, j, n, ch, isnull;
int needQuote;
char *escarg = va_arg(ap,char*);
isnull = escarg==0;
if( isnull ) escarg = (xtype==etSQLESCAPE2 ? "NULL" : "(NULL)");
for(i=n=0; (ch=escarg[i])!=0; i++){
if( ch=='\'' ) n++;
}
needQuote = !isnull && xtype==etSQLESCAPE2;
n += i + 1 + needQuote*2;
if( n>etBUFSIZE ){
bufpt = zExtra = sqliteMalloc( n );
if( bufpt==0 ) return -1;
}else{
bufpt = buf;
}
j = 0;
if( needQuote ) bufpt[j++] = '\'';
for(i=0; (ch=escarg[i])!=0; i++){
bufpt[j++] = ch;
if( ch=='\'' ) bufpt[j++] = ch;
}
if( needQuote ) bufpt[j++] = '\'';
bufpt[j] = 0;
length = j;
if( precision>=0 && precision<length ) length = precision;
break;
}
case etTOKEN: {
Token *pToken = va_arg(ap, Token*);
if( pToken && pToken->z ){
(*func)(arg, (char*)pToken->z, pToken->n);
}
length = width = 0;
break;
}
case etSRCLIST: {
SrcList *pSrc = va_arg(ap, SrcList*);
int k = va_arg(ap, int);
struct SrcList_item *pItem = &pSrc->a[k];
assert( k>=0 && k<pSrc->nSrc );
if( pItem->zDatabase && pItem->zDatabase[0] ){
(*func)(arg, pItem->zDatabase, strlen(pItem->zDatabase));
(*func)(arg, ".", 1);
}
(*func)(arg, pItem->zName, strlen(pItem->zName));
length = width = 0;
break;
}
case etERROR:
buf[0] = '%';
buf[1] = c;
errorflag = 0;
idx = 1+(c!=0);
(*func)(arg,"%",idx);
count += idx;
if( c==0 ) fmt--;
break;
}/* End switch over the format type */
/*
** The text of the conversion is pointed to by "bufpt" and is
** "length" characters long. The field width is "width". Do
** the output.
*/
if( !flag_leftjustify ){
register int nspace;
nspace = width-length;
if( nspace>0 ){
count += nspace;
while( nspace>=etSPACESIZE ){
(*func)(arg,spaces,etSPACESIZE);
nspace -= etSPACESIZE;
}
if( nspace>0 ) (*func)(arg,spaces,nspace);
}
}
if( length>0 ){
(*func)(arg,bufpt,length);
count += length;
}
if( flag_leftjustify ){
register int nspace;
nspace = width-length;
if( nspace>0 ){
count += nspace;
while( nspace>=etSPACESIZE ){
(*func)(arg,spaces,etSPACESIZE);
nspace -= etSPACESIZE;
}
if( nspace>0 ) (*func)(arg,spaces,nspace);
}
}
if( zExtra ){
sqliteFree(zExtra);
}
}/* End for loop over the format string */
return errorflag ? -1 : count;
} /* End of function */
/* This structure is used to store state information about the
** write to memory that is currently in progress.
*/
struct sgMprintf {
char *zBase; /* A base allocation */
char *zText; /* The string collected so far */
int nChar; /* Length of the string so far */
int nTotal; /* Output size if unconstrained */
int nAlloc; /* Amount of space allocated in zText */
void *(*xRealloc)(void*,int); /* Function used to realloc memory */
};
/*
** This function implements the callback from vxprintf.
**
** This routine add nNewChar characters of text in zNewText to
** the sgMprintf structure pointed to by "arg".
*/
static void mout(void *arg, const char *zNewText, int nNewChar){
struct sgMprintf *pM = (struct sgMprintf*)arg;
pM->nTotal += nNewChar;
if( pM->nChar + nNewChar + 1 > pM->nAlloc ){
if( pM->xRealloc==0 ){
nNewChar = pM->nAlloc - pM->nChar - 1;
}else{
pM->nAlloc = pM->nChar + nNewChar*2 + 1;
if( pM->zText==pM->zBase ){
pM->zText = pM->xRealloc(0, pM->nAlloc);
if( pM->zText && pM->nChar ){
memcpy(pM->zText, pM->zBase, pM->nChar);
}
}else{
char *zNew;
zNew = pM->xRealloc(pM->zText, pM->nAlloc);
if( zNew ){
pM->zText = zNew;
}
}
}
}
if( pM->zText ){
if( nNewChar>0 ){
memcpy(&pM->zText[pM->nChar], zNewText, nNewChar);
pM->nChar += nNewChar;
}
pM->zText[pM->nChar] = 0;
}
}
/*
** This routine is a wrapper around xprintf() that invokes mout() as
** the consumer.
*/
static char *base_vprintf(
void *(*xRealloc)(void*,int), /* Routine to realloc memory. May be NULL */
int useInternal, /* Use internal %-conversions if true */
char *zInitBuf, /* Initially write here, before mallocing */
int nInitBuf, /* Size of zInitBuf[] */
const char *zFormat, /* format string */
va_list ap /* arguments */
){
struct sgMprintf sM;
sM.zBase = sM.zText = zInitBuf;
sM.nChar = sM.nTotal = 0;
sM.nAlloc = nInitBuf;
sM.xRealloc = xRealloc;
vxprintf(mout, &sM, useInternal, zFormat, ap);
if( xRealloc ){
if( sM.zText==sM.zBase ){
sM.zText = xRealloc(0, sM.nChar+1);
if( sM.zText ){
memcpy(sM.zText, sM.zBase, sM.nChar+1);
}
}else if( sM.nAlloc>sM.nChar+10 ){
char *zNew = xRealloc(sM.zText, sM.nChar+1);
if( zNew ){
sM.zText = zNew;
}
}
}
return sM.zText;
}
/*
** Realloc that is a real function, not a macro.
*/
static void *printf_realloc(void *old, int size){
return sqliteRealloc(old,size);
}
/*
** Print into memory obtained from sqliteMalloc(). Use the internal
** %-conversion extensions.
*/
char *sqlite3VMPrintf(const char *zFormat, va_list ap){
char zBase[SQLITE_PRINT_BUF_SIZE];
return base_vprintf(printf_realloc, 1, zBase, sizeof(zBase), zFormat, ap);
}
/*
** Print into memory obtained from sqliteMalloc(). Use the internal
** %-conversion extensions.
*/
char *sqlite3MPrintf(const char *zFormat, ...){
va_list ap;
char *z;
char zBase[SQLITE_PRINT_BUF_SIZE];
va_start(ap, zFormat);
z = base_vprintf(printf_realloc, 1, zBase, sizeof(zBase), zFormat, ap);
va_end(ap);
return z;
}
/*
** Print into memory obtained from malloc(). Do not use the internal
** %-conversion extensions. This routine is for use by external users.
*/
char *sqlite3_mprintf(const char *zFormat, ...){
va_list ap;
char *z;
char zBuf[200];
va_start(ap,zFormat);
z = base_vprintf((void*(*)(void*,int))realloc, 0,
zBuf, sizeof(zBuf), zFormat, ap);
va_end(ap);
return z;
}
/* This is the varargs version of sqlite3_mprintf.
*/
char *sqlite3_vmprintf(const char *zFormat, va_list ap){
char zBuf[200];
return base_vprintf((void*(*)(void*,int))realloc, 0,
zBuf, sizeof(zBuf), zFormat, ap);
}
/*
** sqlite3_snprintf() works like snprintf() except that it ignores the
** current locale settings. This is important for SQLite because we
** are not able to use a "," as the decimal point in place of "." as
** specified by some locales.
*/
char *sqlite3_snprintf(int n, char *zBuf, const char *zFormat, ...){
char *z;
va_list ap;
va_start(ap,zFormat);
z = base_vprintf(0, 0, zBuf, n, zFormat, ap);
va_end(ap);
return z;
}
#if defined(SQLITE_TEST) || defined(SQLITE_DEBUG)
/*
** A version of printf() that understands %lld. Used for debugging.
** The printf() built into some versions of windows does not understand %lld
** and segfaults if you give it a long long int.
*/
void sqlite3DebugPrintf(const char *zFormat, ...){
extern int getpid(void);
va_list ap;
char zBuf[500];
va_start(ap, zFormat);
base_vprintf(0, 0, zBuf, sizeof(zBuf), zFormat, ap);
va_end(ap);
fprintf(stdout,"%d: %s", getpid(), zBuf);
fflush(stdout);
}
#endif

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -12,7 +12,7 @@
** This header file defines the interface that the SQLite library
** presents to client programs.
**
** @(#) $Id: sqlite3.h,v 1.4 2006/02/22 20:47:51 brettw%gmail.com Exp $
** @(#) $Id: sqlite.h.in,v 1.165 2006/04/04 01:54:55 drh Exp $
*/
#ifndef _SQLITE3_H_
#define _SQLITE3_H_
@ -31,7 +31,7 @@ extern "C" {
#ifdef SQLITE_VERSION
# undef SQLITE_VERSION
#endif
#define SQLITE_VERSION "3.3.4"
#define SQLITE_VERSION "3.3.5"
/*
** The format of the version string is "X.Y.Z<trailing string>", where
@ -48,7 +48,7 @@ extern "C" {
#ifdef SQLITE_VERSION_NUMBER
# undef SQLITE_VERSION_NUMBER
#endif
#define SQLITE_VERSION_NUMBER 3003004
#define SQLITE_VERSION_NUMBER 3003005
/*
** The version string is also compiled into the library so that a program
@ -78,7 +78,10 @@ typedef struct sqlite3 sqlite3;
** to do a typedef that for 64-bit integers that depends on what compiler
** is being used.
*/
#if defined(_MSC_VER) || defined(__BORLANDC__)
#ifdef SQLITE_INT64_TYPE
typedef SQLITE_INT64_TYPE sqlite_int64;
typedef unsigned SQLITE_INT64_TYPE sqlite_uint64;
#elif defined(_MSC_VER) || defined(__BORLANDC__)
typedef __int64 sqlite_int64;
typedef unsigned __int64 sqlite_uint64;
#else

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -1,485 +0,0 @@
/*
** 2006 January 07
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
**
** May you do good and not evil.
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
******************************************************************************
**
** This file contains demonstration code. Nothing in this file gets compiled
** or linked into the SQLite library unless you use a non-standard option:
**
** -DSQLITE_SERVER=1
**
** The configure script will never generate a Makefile with the option
** above. You will need to manually modify the Makefile if you want to
** include any of the code from this file in your project. Or, at your
** option, you may copy and paste the code from this file and
** thereby avoiding a recompile of SQLite.
**
**
** This source file demonstrates how to use SQLite to create an SQL database
** server thread in a multiple-threaded program. One or more client threads
** send messages to the server thread and the server thread processes those
** messages in the order received and returns the results to the client.
**
** One might ask: "Why bother? Why not just let each thread connect
** to the database directly?" There are a several of reasons to
** prefer the client/server approach.
**
** (1) Some systems (ex: Redhat9) have broken threading implementations
** that prevent SQLite database connections from being used in
** a thread different from the one where they were created. With
** the client/server approach, all database connections are created
** and used within the server thread. Client calls to the database
** can be made from multiple threads (though not at the same time!)
**
** (2) Beginning with SQLite version 3.3.0, when two or more
** connections to the same database occur within the same thread,
** they can optionally share their database cache. This reduces
** I/O and memory requirements. Cache shared is controlled using
** the sqlite3_enable_shared_cache() API.
**
** (3) Database connections on a shared cache use table-level locking
** instead of file-level locking for improved concurrency.
**
** (4) Database connections on a shared cache can by optionally
** set to READ UNCOMMITTED isolation. (The default isolation for
** SQLite is SERIALIZABLE.) When this occurs, readers will
** never be blocked by a writer and writers will not be
** blocked by readers. There can still only be a single writer
** at a time, but multiple readers can simultaneously exist with
** that writer. This is a huge increase in concurrency.
**
** To summarize the rational for using a client/server approach: prior
** to SQLite version 3.3.0 it probably was not worth the trouble. But
** with SQLite version 3.3.0 and beyond you can get significant performance
** and concurrency improvements and memory usage reductions by going
** client/server.
**
** Note: The extra features of version 3.3.0 described by points (2)
** through (4) above are only available if you compile without the
** option -DSQLITE_OMIT_SHARED_CACHE.
**
** Here is how the client/server approach works: The database server
** thread is started on this procedure:
**
** void *sqlite3_server(void *NotUsed);
**
** The sqlite_server procedure runs as long as the g.serverHalt variable
** is false. A mutex is used to make sure no more than one server runs
** at a time. The server waits for messages to arrive on a message
** queue and processes the messages in order.
**
** Two convenience routines are provided for starting and stopping the
** server thread:
**
** void sqlite3_server_start(void);
** void sqlite3_server_stop(void);
**
** Both of the convenience routines return immediately. Neither will
** ever give an error. If a server is already started or already halted,
** then the routines are effectively no-ops.
**
** Clients use the following interfaces:
**
** sqlite3_client_open
** sqlite3_client_prepare
** sqlite3_client_step
** sqlite3_client_reset
** sqlite3_client_finalize
** sqlite3_client_close
**
** These interfaces work exactly like the standard core SQLite interfaces
** having the same names without the "_client_" infix. Many other SQLite
** interfaces can be used directly without having to send messages to the
** server as long as SQLITE_ENABLE_MEMORY_MANAGEMENT is not defined.
** The following interfaces fall into this second category:
**
** sqlite3_bind_*
** sqlite3_changes
** sqlite3_clear_bindings
** sqlite3_column_*
** sqlite3_complete
** sqlite3_create_collation
** sqlite3_create_function
** sqlite3_data_count
** sqlite3_db_handle
** sqlite3_errcode
** sqlite3_errmsg
** sqlite3_last_insert_rowid
** sqlite3_total_changes
** sqlite3_transfer_bindings
**
** A single SQLite connection (an sqlite3* object) or an SQLite statement
** (an sqlite3_stmt* object) should only be passed to a single interface
** function at a time. The connections and statements can be passed from
** any thread to any of the functions listed in the second group above as
** long as the same connection is not in use by two threads at once and
** as long as SQLITE_ENABLE_MEMORY_MANAGEMENT is not defined. Additional
** information about the SQLITE_ENABLE_MEMORY_MANAGEMENT constraint is
** below.
**
** The busy handler for all database connections should remain turned
** off. That means that any lock contention will cause the associated
** sqlite3_client_step() call to return immediately with an SQLITE_BUSY
** error code. If a busy handler is enabled and lock contention occurs,
** then the entire server thread will block. This will cause not only
** the requesting client to block but every other database client as
** well. It is possible to enhance the code below so that lock
** contention will cause the message to be placed back on the top of
** the queue to be tried again later. But such enhanced processing is
** not included here, in order to keep the example simple.
**
** This example code assumes the use of pthreads. Pthreads
** implementations are available for windows. (See, for example
** http://sourceware.org/pthreads-win32/announcement.html.) Or, you
** can translate the locking and thread synchronization code to use
** windows primitives easily enough. The details are left as an
** exercise to the reader.
**
**** Restrictions Associated With SQLITE_ENABLE_MEMORY_MANAGEMENT ****
**
** If you compile with SQLITE_ENABLE_MEMORY_MANAGEMENT defined, then
** SQLite includes code that tracks how much memory is being used by
** each thread. These memory counts can become confused if memory
** is allocated by one thread and then freed by another. For that
** reason, when SQLITE_ENABLE_MEMORY_MANAGEMENT is used, all operations
** that might allocate or free memory should be performanced in the same
** thread that originally created the database connection. In that case,
** many of the operations that are listed above as safe to be performed
** in separate threads would need to be sent over to the server to be
** done there. If SQLITE_ENABLE_MEMORY_MANAGEMENT is defined, then
** the following functions can be used safely from different threads
** without messing up the allocation counts:
**
** sqlite3_bind_parameter_name
** sqlite3_bind_parameter_index
** sqlite3_changes
** sqlite3_column_blob
** sqlite3_column_count
** sqlite3_complete
** sqlite3_data_count
** sqlite3_db_handle
** sqlite3_errcode
** sqlite3_errmsg
** sqlite3_last_insert_rowid
** sqlite3_total_changes
**
** The remaining functions are not thread-safe when memory management
** is enabled. So one would have to define some new interface routines
** along the following lines:
**
** sqlite3_client_bind_*
** sqlite3_client_clear_bindings
** sqlite3_client_column_*
** sqlite3_client_create_collation
** sqlite3_client_create_function
** sqlite3_client_transfer_bindings
**
** The example code in this file is intended for use with memory
** management turned off. So the implementation of these additional
** client interfaces is left as an exercise to the reader.
**
** It may seem surprising to the reader that the list of safe functions
** above does not include things like sqlite3_bind_int() or
** sqlite3_column_int(). But those routines might, in fact, allocate
** or deallocate memory. In the case of sqlite3_bind_int(), if the
** parameter was previously bound to a string that string might need
** to be deallocated before the new integer value is inserted. In
** the case of sqlite3_column_int(), the value of the column might be
** a UTF-16 string which will need to be converted to UTF-8 then into
** an integer.
*/
/*
** Only compile the code in this file on UNIX with a THREADSAFE build
** and only if the SQLITE_SERVER macro is defined.
*/
#ifdef SQLITE_SERVER
#if defined(OS_UNIX) && OS_UNIX && defined(THREADSAFE) && THREADSAFE
/*
** We require only pthreads and the public interface of SQLite.
*/
#include <pthread.h>
#include "sqlite3.h"
/*
** Messages are passed from client to server and back again as
** instances of the following structure.
*/
typedef struct SqlMessage SqlMessage;
struct SqlMessage {
int op; /* Opcode for the message */
sqlite3 *pDb; /* The SQLite connection */
sqlite3_stmt *pStmt; /* A specific statement */
int errCode; /* Error code returned */
const char *zIn; /* Input filename or SQL statement */
int nByte; /* Size of the zIn parameter for prepare() */
const char *zOut; /* Tail of the SQL statement */
SqlMessage *pNext; /* Next message in the queue */
SqlMessage *pPrev; /* Previous message in the queue */
pthread_mutex_t clientMutex; /* Hold this mutex to access the message */
pthread_cond_t clientWakeup; /* Signal to wake up the client */
};
/*
** Legal values for SqlMessage.op
*/
#define MSG_Open 1 /* sqlite3_open(zIn, &pDb) */
#define MSG_Prepare 2 /* sqlite3_prepare(pDb, zIn, nByte, &pStmt, &zOut) */
#define MSG_Step 3 /* sqlite3_step(pStmt) */
#define MSG_Reset 4 /* sqlite3_reset(pStmt) */
#define MSG_Finalize 5 /* sqlite3_finalize(pStmt) */
#define MSG_Close 6 /* sqlite3_close(pDb) */
#define MSG_Done 7 /* Server has finished with this message */
/*
** State information about the server is stored in a static variable
** named "g" as follows:
*/
static struct ServerState {
pthread_mutex_t queueMutex; /* Hold this mutex to access the msg queue */
pthread_mutex_t serverMutex; /* Held by the server while it is running */
pthread_cond_t serverWakeup; /* Signal this condvar to wake up the server */
volatile int serverHalt; /* Server halts itself when true */
SqlMessage *pQueueHead; /* Head of the message queue */
SqlMessage *pQueueTail; /* Tail of the message queue */
} g = {
PTHREAD_MUTEX_INITIALIZER,
PTHREAD_MUTEX_INITIALIZER,
PTHREAD_COND_INITIALIZER,
};
/*
** Send a message to the server. Block until we get a reply.
**
** The mutex and condition variable in the message are uninitialized
** when this routine is called. This routine takes care of
** initializing them and destroying them when it has finished.
*/
static void sendToServer(SqlMessage *pMsg){
/* Initialize the mutex and condition variable on the message
*/
pthread_mutex_init(&pMsg->clientMutex, 0);
pthread_cond_init(&pMsg->clientWakeup, 0);
/* Add the message to the head of the server's message queue.
*/
pthread_mutex_lock(&g.queueMutex);
pMsg->pNext = g.pQueueHead;
if( g.pQueueHead==0 ){
g.pQueueTail = pMsg;
}else{
g.pQueueHead->pPrev = pMsg;
}
pMsg->pPrev = 0;
g.pQueueHead = pMsg;
pthread_mutex_unlock(&g.queueMutex);
/* Signal the server that the new message has be queued, then
** block waiting for the server to process the message.
*/
pthread_mutex_lock(&pMsg->clientMutex);
pthread_cond_signal(&g.serverWakeup);
while( pMsg->op!=MSG_Done ){
pthread_cond_wait(&pMsg->clientWakeup, &pMsg->clientMutex);
}
pthread_mutex_unlock(&pMsg->clientMutex);
/* Destroy the mutex and condition variable of the message.
*/
pthread_mutex_destroy(&pMsg->clientMutex);
pthread_cond_destroy(&pMsg->clientWakeup);
}
/*
** The following 6 routines are client-side implementations of the
** core SQLite interfaces:
**
** sqlite3_open
** sqlite3_prepare
** sqlite3_step
** sqlite3_reset
** sqlite3_finalize
** sqlite3_close
**
** Clients should use the following client-side routines instead of
** the core routines above.
**
** sqlite3_client_open
** sqlite3_client_prepare
** sqlite3_client_step
** sqlite3_client_reset
** sqlite3_client_finalize
** sqlite3_client_close
**
** Each of these routines creates a message for the desired operation,
** sends that message to the server, waits for the server to process
** then message and return a response.
*/
int sqlite3_client_open(const char *zDatabaseName, sqlite3 **ppDb){
SqlMessage msg;
msg.op = MSG_Open;
msg.zIn = zDatabaseName;
sendToServer(&msg);
*ppDb = msg.pDb;
return msg.errCode;
}
int sqlite3_client_prepare(
sqlite3 *pDb,
const char *zSql,
int nByte,
sqlite3_stmt **ppStmt,
const char **pzTail
){
SqlMessage msg;
msg.op = MSG_Prepare;
msg.pDb = pDb;
msg.zIn = zSql;
msg.nByte = nByte;
sendToServer(&msg);
*ppStmt = msg.pStmt;
if( pzTail ) *pzTail = msg.zOut;
return msg.errCode;
}
int sqlite3_client_step(sqlite3_stmt *pStmt){
SqlMessage msg;
msg.op = MSG_Step;
msg.pStmt = pStmt;
sendToServer(&msg);
return msg.errCode;
}
int sqlite3_client_reset(sqlite3_stmt *pStmt){
SqlMessage msg;
msg.op = MSG_Reset;
msg.pStmt = pStmt;
sendToServer(&msg);
return msg.errCode;
}
int sqlite3_client_finalize(sqlite3_stmt *pStmt){
SqlMessage msg;
msg.op = MSG_Finalize;
msg.pStmt = pStmt;
sendToServer(&msg);
return msg.errCode;
}
int sqlite3_client_close(sqlite3 *pDb){
SqlMessage msg;
msg.op = MSG_Close;
msg.pDb = pDb;
sendToServer(&msg);
return msg.errCode;
}
/*
** This routine implements the server. To start the server, first
** make sure g.serverHalt is false, then create a new detached thread
** on this procedure. See the sqlite3_server_start() routine below
** for an example. This procedure loops until g.serverHalt becomes
** true.
*/
void *sqlite3_server(void *NotUsed){
sqlite3_enable_shared_cache(1);
if( pthread_mutex_trylock(&g.serverMutex) ){
sqlite3_enable_shared_cache(0);
return 0; /* Another server is already running */
}
while( !g.serverHalt ){
SqlMessage *pMsg;
/* Remove the last message from the message queue.
*/
pthread_mutex_lock(&g.queueMutex);
while( g.pQueueTail==0 && g.serverHalt==0 ){
pthread_cond_wait(&g.serverWakeup, &g.queueMutex);
}
pMsg = g.pQueueTail;
if( pMsg ){
if( pMsg->pPrev ){
pMsg->pPrev->pNext = 0;
}else{
g.pQueueHead = 0;
}
g.pQueueTail = pMsg->pPrev;
}
pthread_mutex_unlock(&g.queueMutex);
if( pMsg==0 ) break;
/* Process the message just removed
*/
pthread_mutex_lock(&pMsg->clientMutex);
switch( pMsg->op ){
case MSG_Open: {
pMsg->errCode = sqlite3_open(pMsg->zIn, &pMsg->pDb);
break;
}
case MSG_Prepare: {
pMsg->errCode = sqlite3_prepare(pMsg->pDb, pMsg->zIn, pMsg->nByte,
&pMsg->pStmt, &pMsg->zOut);
break;
}
case MSG_Step: {
pMsg->errCode = sqlite3_step(pMsg->pStmt);
break;
}
case MSG_Reset: {
pMsg->errCode = sqlite3_reset(pMsg->pStmt);
break;
}
case MSG_Finalize: {
pMsg->errCode = sqlite3_finalize(pMsg->pStmt);
break;
}
case MSG_Close: {
pMsg->errCode = sqlite3_close(pMsg->pDb);
break;
}
}
/* Signal the client that the message has been processed.
*/
pMsg->op = MSG_Done;
pthread_mutex_unlock(&pMsg->clientMutex);
pthread_cond_signal(&pMsg->clientWakeup);
}
pthread_mutex_unlock(&g.serverMutex);
sqlite3_thread_cleanup();
return 0;
}
/*
** Start a server thread if one is not already running. If there
** is aleady a server thread running, the new thread will quickly
** die and this routine is effectively a no-op.
*/
void sqlite3_server_start(void){
pthread_t x;
int rc;
g.serverHalt = 0;
rc = pthread_create(&x, 0, sqlite3_server, 0);
if( rc==0 ){
pthread_detach(x);
}
}
/*
** If a server thread is running, then stop it. If no server is
** running, this routine is effectively a no-op.
**
** This routine returns immediately without waiting for the server
** thread to stop. But be assured that the server will eventually stop.
*/
void sqlite3_server_stop(void){
g.serverHalt = 1;
pthread_cond_broadcast(&g.serverWakeup);
}
#endif /* defined(OS_UNIX) && OS_UNIX && defined(THREADSAFE) && THREADSAFE */
#endif /* defined(SQLITE_SERVER) */

Просмотреть файл

@ -1,443 +0,0 @@
/*
** 2001 September 15
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
**
** May you do good and not evil.
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
*************************************************************************
** An tokenizer for SQL
**
** This file contains C code that splits an SQL input string up into
** individual tokens and sends those tokens one-by-one over to the
** parser for analysis.
**
** $Id: tokenize.c,v 1.117 2006/02/09 22:24:41 drh Exp $
*/
#include "sqliteInt.h"
#include "os.h"
#include <ctype.h>
#include <stdlib.h>
/*
** The sqlite3KeywordCode function looks up an identifier to determine if
** it is a keyword. If it is a keyword, the token code of that keyword is
** returned. If the input is not a keyword, TK_ID is returned.
**
** The implementation of this routine was generated by a program,
** mkkeywordhash.h, located in the tool subdirectory of the distribution.
** The output of the mkkeywordhash.c program is written into a file
** named keywordhash.h and then included into this source file by
** the #include below.
*/
#include "keywordhash.h"
/*
** If X is a character that can be used in an identifier and
** X&0x80==0 then sqlite3IsIdChar[X] will be 1. If X&0x80==0x80 then
** X is always an identifier character. (Hence all UTF-8
** characters can be part of an identifier). sqlite3IsIdChar[X] will
** be 0 for every character in the lower 128 ASCII characters
** that cannot be used as part of an identifier.
**
** In this implementation, an identifier can be a string of
** alphabetic characters, digits, and "_" plus any character
** 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.
*/
const char sqlite3IsIdChar[] = {
/* x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF */
0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 2x */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, /* 3x */
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 4x */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, /* 5x */
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 6x */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, /* 7x */
};
#define IdChar(C) (((c=C)&0x80)!=0 || (c>0x1f && sqlite3IsIdChar[c-0x20]))
/*
** Return the length of the token that begins at z[0].
** Store the token type in *tokenType before returning.
*/
static int getToken(const unsigned char *z, int *tokenType){
int i, c;
switch( *z ){
case ' ': case '\t': case '\n': case '\f': case '\r': {
for(i=1; isspace(z[i]); i++){}
*tokenType = TK_SPACE;
return i;
}
case '-': {
if( z[1]=='-' ){
for(i=2; (c=z[i])!=0 && c!='\n'; i++){}
*tokenType = TK_COMMENT;
return i;
}
*tokenType = TK_MINUS;
return 1;
}
case '(': {
*tokenType = TK_LP;
return 1;
}
case ')': {
*tokenType = TK_RP;
return 1;
}
case ';': {
*tokenType = TK_SEMI;
return 1;
}
case '+': {
*tokenType = TK_PLUS;
return 1;
}
case '*': {
*tokenType = TK_STAR;
return 1;
}
case '/': {
if( z[1]!='*' || z[2]==0 ){
*tokenType = TK_SLASH;
return 1;
}
for(i=3, c=z[2]; (c!='*' || z[i]!='/') && (c=z[i])!=0; i++){}
if( c ) i++;
*tokenType = TK_COMMENT;
return i;
}
case '%': {
*tokenType = TK_REM;
return 1;
}
case '=': {
*tokenType = TK_EQ;
return 1 + (z[1]=='=');
}
case '<': {
if( (c=z[1])=='=' ){
*tokenType = TK_LE;
return 2;
}else if( c=='>' ){
*tokenType = TK_NE;
return 2;
}else if( c=='<' ){
*tokenType = TK_LSHIFT;
return 2;
}else{
*tokenType = TK_LT;
return 1;
}
}
case '>': {
if( (c=z[1])=='=' ){
*tokenType = TK_GE;
return 2;
}else if( c=='>' ){
*tokenType = TK_RSHIFT;
return 2;
}else{
*tokenType = TK_GT;
return 1;
}
}
case '!': {
if( z[1]!='=' ){
*tokenType = TK_ILLEGAL;
return 2;
}else{
*tokenType = TK_NE;
return 2;
}
}
case '|': {
if( z[1]!='|' ){
*tokenType = TK_BITOR;
return 1;
}else{
*tokenType = TK_CONCAT;
return 2;
}
}
case ',': {
*tokenType = TK_COMMA;
return 1;
}
case '&': {
*tokenType = TK_BITAND;
return 1;
}
case '~': {
*tokenType = TK_BITNOT;
return 1;
}
case '`':
case '\'':
case '"': {
int delim = z[0];
for(i=1; (c=z[i])!=0; i++){
if( c==delim ){
if( z[i+1]==delim ){
i++;
}else{
break;
}
}
}
if( c ){
*tokenType = TK_STRING;
return i+1;
}else{
*tokenType = TK_ILLEGAL;
return i;
}
}
case '.': {
#ifndef SQLITE_OMIT_FLOATING_POINT
if( !isdigit(z[1]) )
#endif
{
*tokenType = TK_DOT;
return 1;
}
/* If the next character is a digit, this is a floating point
** number that begins with ".". Fall thru into the next case */
}
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9': {
*tokenType = TK_INTEGER;
for(i=0; isdigit(z[i]); i++){}
#ifndef SQLITE_OMIT_FLOATING_POINT
if( z[i]=='.' ){
i++;
while( isdigit(z[i]) ){ i++; }
*tokenType = TK_FLOAT;
}
if( (z[i]=='e' || z[i]=='E') &&
( isdigit(z[i+1])
|| ((z[i+1]=='+' || z[i+1]=='-') && isdigit(z[i+2]))
)
){
i += 2;
while( isdigit(z[i]) ){ i++; }
*tokenType = TK_FLOAT;
}
#endif
return i;
}
case '[': {
for(i=1, c=z[0]; c!=']' && (c=z[i])!=0; i++){}
*tokenType = TK_ID;
return i;
}
case '?': {
*tokenType = TK_VARIABLE;
for(i=1; isdigit(z[i]); i++){}
return i;
}
case '#': {
for(i=1; isdigit(z[i]); i++){}
if( i>1 ){
/* Parameters of the form #NNN (where NNN is a number) are used
** internally by sqlite3NestedParse. */
*tokenType = TK_REGISTER;
return i;
}
/* Fall through into the next case if the '#' is not followed by
** a digit. Try to match #AAAA where AAAA is a parameter name. */
}
#ifndef SQLITE_OMIT_TCL_VARIABLE
case '$':
#endif
case '@': /* For compatibility with MS SQL Server */
case ':': {
int n = 0;
*tokenType = TK_VARIABLE;
for(i=1; (c=z[i])!=0; i++){
if( IdChar(c) ){
n++;
#ifndef SQLITE_OMIT_TCL_VARIABLE
}else if( c=='(' && n>0 ){
do{
i++;
}while( (c=z[i])!=0 && !isspace(c) && c!=')' );
if( c==')' ){
i++;
}else{
*tokenType = TK_ILLEGAL;
}
break;
}else if( c==':' && z[i+1]==':' ){
i++;
#endif
}else{
break;
}
}
if( n==0 ) *tokenType = TK_ILLEGAL;
return i;
}
#ifndef SQLITE_OMIT_BLOB_LITERAL
case 'x': case 'X': {
if( (c=z[1])=='\'' || c=='"' ){
int delim = c;
*tokenType = TK_BLOB;
for(i=2; (c=z[i])!=0; i++){
if( c==delim ){
if( i%2 ) *tokenType = TK_ILLEGAL;
break;
}
if( !isxdigit(c) ){
*tokenType = TK_ILLEGAL;
return i;
}
}
if( c ) i++;
return i;
}
/* Otherwise fall through to the next case */
}
#endif
default: {
if( !IdChar(*z) ){
break;
}
for(i=1; IdChar(z[i]); i++){}
*tokenType = keywordCode((char*)z, i);
return i;
}
}
*tokenType = TK_ILLEGAL;
return 1;
}
int sqlite3GetToken(const unsigned char *z, int *tokenType){
return getToken(z, tokenType);
}
/*
** Run the parser on the given SQL string. The parser structure is
** passed in. An SQLITE_ status code is returned. If an error occurs
** and pzErrMsg!=NULL then an error message might be written into
** memory obtained from malloc() and *pzErrMsg made to point to that
** error message. Or maybe not.
*/
int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzErrMsg){
int nErr = 0;
int i;
void *pEngine;
int tokenType;
int lastTokenParsed = -1;
sqlite3 *db = pParse->db;
extern void *sqlite3ParserAlloc(void*(*)(int));
extern void sqlite3ParserFree(void*, void(*)(void*));
extern int sqlite3Parser(void*, int, Token, Parse*);
db->flags &= ~SQLITE_Interrupt;
pParse->rc = SQLITE_OK;
i = 0;
pEngine = sqlite3ParserAlloc((void*(*)(int))sqlite3MallocX);
if( pEngine==0 ){
return SQLITE_NOMEM;
}
assert( pParse->sLastToken.dyn==0 );
assert( pParse->pNewTable==0 );
assert( pParse->pNewTrigger==0 );
assert( pParse->nVar==0 );
assert( pParse->nVarExpr==0 );
assert( pParse->nVarExprAlloc==0 );
assert( pParse->apVarExpr==0 );
pParse->zTail = pParse->zSql = zSql;
while( !sqlite3MallocFailed() && zSql[i]!=0 ){
assert( i>=0 );
pParse->sLastToken.z = (u8*)&zSql[i];
assert( pParse->sLastToken.dyn==0 );
pParse->sLastToken.n = getToken((unsigned char*)&zSql[i],&tokenType);
i += pParse->sLastToken.n;
switch( tokenType ){
case TK_SPACE:
case TK_COMMENT: {
if( (db->flags & SQLITE_Interrupt)!=0 ){
pParse->rc = SQLITE_INTERRUPT;
sqlite3SetString(pzErrMsg, "interrupt", (char*)0);
goto abort_parse;
}
break;
}
case TK_ILLEGAL: {
if( pzErrMsg ){
sqliteFree(*pzErrMsg);
*pzErrMsg = sqlite3MPrintf("unrecognized token: \"%T\"",
&pParse->sLastToken);
}
nErr++;
goto abort_parse;
}
case TK_SEMI: {
pParse->zTail = &zSql[i];
/* Fall thru into the default case */
}
default: {
sqlite3Parser(pEngine, tokenType, pParse->sLastToken, pParse);
lastTokenParsed = tokenType;
if( pParse->rc!=SQLITE_OK ){
goto abort_parse;
}
break;
}
}
}
abort_parse:
if( zSql[i]==0 && nErr==0 && pParse->rc==SQLITE_OK ){
if( lastTokenParsed!=TK_SEMI ){
sqlite3Parser(pEngine, TK_SEMI, pParse->sLastToken, pParse);
pParse->zTail = &zSql[i];
}
sqlite3Parser(pEngine, 0, pParse->sLastToken, pParse);
}
sqlite3ParserFree(pEngine, sqlite3FreeX);
if( sqlite3MallocFailed() ){
pParse->rc = SQLITE_NOMEM;
}
if( pParse->rc!=SQLITE_OK && pParse->rc!=SQLITE_DONE && pParse->zErrMsg==0 ){
sqlite3SetString(&pParse->zErrMsg, sqlite3ErrStr(pParse->rc), (char*)0);
}
if( pParse->zErrMsg ){
if( pzErrMsg && *pzErrMsg==0 ){
*pzErrMsg = pParse->zErrMsg;
}else{
sqliteFree(pParse->zErrMsg);
}
pParse->zErrMsg = 0;
if( !nErr ) nErr++;
}
if( pParse->pVdbe && pParse->nErr>0 && pParse->nested==0 ){
sqlite3VdbeDelete(pParse->pVdbe);
pParse->pVdbe = 0;
}
#ifndef SQLITE_OMIT_SHARED_CACHE
if( pParse->nested==0 ){
sqliteFree(pParse->aTableLock);
pParse->aTableLock = 0;
pParse->nTableLock = 0;
}
#endif
sqlite3DeleteTable(pParse->db, pParse->pNewTable);
sqlite3DeleteTrigger(pParse->pNewTrigger);
sqliteFree(pParse->apVarExpr);
if( nErr>0 && (pParse->rc==SQLITE_OK || pParse->rc==SQLITE_DONE) ){
pParse->rc = SQLITE_ERROR;
}
return nErr;
}

Просмотреть файл

@ -1,811 +0,0 @@
/*
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
**
** May you do good and not evil.
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
*************************************************************************
*
*/
#include "sqliteInt.h"
#ifndef SQLITE_OMIT_TRIGGER
/*
** Delete a linked list of TriggerStep structures.
*/
void sqlite3DeleteTriggerStep(TriggerStep *pTriggerStep){
while( pTriggerStep ){
TriggerStep * pTmp = pTriggerStep;
pTriggerStep = pTriggerStep->pNext;
if( pTmp->target.dyn ) sqliteFree((char*)pTmp->target.z);
sqlite3ExprDelete(pTmp->pWhere);
sqlite3ExprListDelete(pTmp->pExprList);
sqlite3SelectDelete(pTmp->pSelect);
sqlite3IdListDelete(pTmp->pIdList);
sqliteFree(pTmp);
}
}
/*
** This is called by the parser when it sees a CREATE TRIGGER statement
** up to the point of the BEGIN before the trigger actions. A Trigger
** structure is generated based on the information available and stored
** in pParse->pNewTrigger. After the trigger actions have been parsed, the
** sqlite3FinishTrigger() function is called to complete the trigger
** construction process.
*/
void sqlite3BeginTrigger(
Parse *pParse, /* The parse context of the CREATE TRIGGER statement */
Token *pName1, /* The name of the trigger */
Token *pName2, /* The name of the trigger */
int tr_tm, /* One of TK_BEFORE, TK_AFTER, TK_INSTEAD */
int op, /* One of TK_INSERT, TK_UPDATE, TK_DELETE */
IdList *pColumns, /* column list if this is an UPDATE OF trigger */
SrcList *pTableName,/* The name of the table/view the trigger applies to */
int foreach, /* One of TK_ROW or TK_STATEMENT */
Expr *pWhen, /* WHEN clause */
int isTemp /* True if the TEMPORARY keyword is present */
){
Trigger *pTrigger = 0;
Table *pTab;
char *zName = 0; /* Name of the trigger */
sqlite3 *db = pParse->db;
int iDb; /* The database to store the trigger in */
Token *pName; /* The unqualified db name */
DbFixer sFix;
int iTabDb;
if( isTemp ){
/* If TEMP was specified, then the trigger name may not be qualified. */
if( pName2 && pName2->n>0 ){
sqlite3ErrorMsg(pParse, "temporary trigger may not have qualified name");
goto trigger_cleanup;
}
iDb = 1;
pName = pName1;
}else{
/* Figure out the db that the the trigger will be created in */
iDb = sqlite3TwoPartName(pParse, pName1, pName2, &pName);
if( iDb<0 ){
goto trigger_cleanup;
}
}
/* If the trigger name was unqualified, and the table is a temp table,
** then set iDb to 1 to create the trigger in the temporary database.
** If sqlite3SrcListLookup() returns 0, indicating the table does not
** exist, the error is caught by the block below.
*/
if( !pTableName || sqlite3MallocFailed() ){
goto trigger_cleanup;
}
pTab = sqlite3SrcListLookup(pParse, pTableName);
if( pName2->n==0 && pTab && pTab->pSchema==db->aDb[1].pSchema ){
iDb = 1;
}
/* Ensure the table name matches database name and that the table exists */
if( sqlite3MallocFailed() ) goto trigger_cleanup;
assert( pTableName->nSrc==1 );
if( sqlite3FixInit(&sFix, pParse, iDb, "trigger", pName) &&
sqlite3FixSrcList(&sFix, pTableName) ){
goto trigger_cleanup;
}
pTab = sqlite3SrcListLookup(pParse, pTableName);
if( !pTab ){
/* The table does not exist. */
goto trigger_cleanup;
}
/* Check that the trigger name is not reserved and that no trigger of the
** specified name exists */
zName = sqlite3NameFromToken(pName);
if( !zName || SQLITE_OK!=sqlite3CheckObjectName(pParse, zName) ){
goto trigger_cleanup;
}
if( sqlite3HashFind(&(db->aDb[iDb].pSchema->trigHash), zName,pName->n+1) ){
sqlite3ErrorMsg(pParse, "trigger %T already exists", pName);
goto trigger_cleanup;
}
/* Do not create a trigger on a system table */
if( sqlite3StrNICmp(pTab->zName, "sqlite_", 7)==0 ){
sqlite3ErrorMsg(pParse, "cannot create trigger on system table");
pParse->nErr++;
goto trigger_cleanup;
}
/* INSTEAD of triggers are only for views and views only support INSTEAD
** of triggers.
*/
if( pTab->pSelect && tr_tm!=TK_INSTEAD ){
sqlite3ErrorMsg(pParse, "cannot create %s trigger on view: %S",
(tr_tm == TK_BEFORE)?"BEFORE":"AFTER", pTableName, 0);
goto trigger_cleanup;
}
if( !pTab->pSelect && tr_tm==TK_INSTEAD ){
sqlite3ErrorMsg(pParse, "cannot create INSTEAD OF"
" trigger on table: %S", pTableName, 0);
goto trigger_cleanup;
}
iTabDb = sqlite3SchemaToIndex(db, pTab->pSchema);
#ifndef SQLITE_OMIT_AUTHORIZATION
{
int code = SQLITE_CREATE_TRIGGER;
const char *zDb = db->aDb[iTabDb].zName;
const char *zDbTrig = isTemp ? db->aDb[1].zName : zDb;
if( iTabDb==1 || isTemp ) code = SQLITE_CREATE_TEMP_TRIGGER;
if( sqlite3AuthCheck(pParse, code, zName, pTab->zName, zDbTrig) ){
goto trigger_cleanup;
}
if( sqlite3AuthCheck(pParse, SQLITE_INSERT, SCHEMA_TABLE(iTabDb),0,zDb)){
goto trigger_cleanup;
}
}
#endif
/* INSTEAD OF triggers can only appear on views and BEFORE triggers
** cannot appear on views. So we might as well translate every
** INSTEAD OF trigger into a BEFORE trigger. It simplifies code
** elsewhere.
*/
if (tr_tm == TK_INSTEAD){
tr_tm = TK_BEFORE;
}
/* Build the Trigger object */
pTrigger = (Trigger*)sqliteMalloc(sizeof(Trigger));
if( pTrigger==0 ) goto trigger_cleanup;
pTrigger->name = zName;
zName = 0;
pTrigger->table = sqliteStrDup(pTableName->a[0].zName);
pTrigger->pSchema = db->aDb[iDb].pSchema;
pTrigger->pTabSchema = pTab->pSchema;
pTrigger->op = op;
pTrigger->tr_tm = tr_tm==TK_BEFORE ? TRIGGER_BEFORE : TRIGGER_AFTER;
pTrigger->pWhen = sqlite3ExprDup(pWhen);
pTrigger->pColumns = sqlite3IdListDup(pColumns);
pTrigger->foreach = foreach;
sqlite3TokenCopy(&pTrigger->nameToken,pName);
assert( pParse->pNewTrigger==0 );
pParse->pNewTrigger = pTrigger;
trigger_cleanup:
sqliteFree(zName);
sqlite3SrcListDelete(pTableName);
sqlite3IdListDelete(pColumns);
sqlite3ExprDelete(pWhen);
if( !pParse->pNewTrigger ){
sqlite3DeleteTrigger(pTrigger);
}else{
assert( pParse->pNewTrigger==pTrigger );
}
}
/*
** This routine is called after all of the trigger actions have been parsed
** in order to complete the process of building the trigger.
*/
void sqlite3FinishTrigger(
Parse *pParse, /* Parser context */
TriggerStep *pStepList, /* The triggered program */
Token *pAll /* Token that describes the complete CREATE TRIGGER */
){
Trigger *pTrig = 0; /* The trigger whose construction is finishing up */
sqlite3 *db = pParse->db; /* The database */
DbFixer sFix;
int iDb; /* Database containing the trigger */
pTrig = pParse->pNewTrigger;
pParse->pNewTrigger = 0;
if( pParse->nErr || !pTrig ) goto triggerfinish_cleanup;
iDb = sqlite3SchemaToIndex(pParse->db, pTrig->pSchema);
pTrig->step_list = pStepList;
while( pStepList ){
pStepList->pTrig = pTrig;
pStepList = pStepList->pNext;
}
if( sqlite3FixInit(&sFix, pParse, iDb, "trigger", &pTrig->nameToken)
&& sqlite3FixTriggerStep(&sFix, pTrig->step_list) ){
goto triggerfinish_cleanup;
}
/* if we are not initializing, and this trigger is not on a TEMP table,
** build the sqlite_master entry
*/
if( !db->init.busy ){
static const VdbeOpList insertTrig[] = {
{ OP_NewRowid, 0, 0, 0 },
{ OP_String8, 0, 0, "trigger" },
{ OP_String8, 0, 0, 0 }, /* 2: trigger name */
{ OP_String8, 0, 0, 0 }, /* 3: table name */
{ OP_Integer, 0, 0, 0 },
{ OP_String8, 0, 0, "CREATE TRIGGER "},
{ OP_String8, 0, 0, 0 }, /* 6: SQL */
{ OP_Concat, 0, 0, 0 },
{ OP_MakeRecord, 5, 0, "aaada" },
{ OP_Insert, 0, 0, 0 },
};
int addr;
Vdbe *v;
/* Make an entry in the sqlite_master table */
v = sqlite3GetVdbe(pParse);
if( v==0 ) goto triggerfinish_cleanup;
sqlite3BeginWriteOperation(pParse, 0, iDb);
sqlite3OpenMasterTable(pParse, iDb);
addr = sqlite3VdbeAddOpList(v, ArraySize(insertTrig), insertTrig);
sqlite3VdbeChangeP3(v, addr+2, pTrig->name, 0);
sqlite3VdbeChangeP3(v, addr+3, pTrig->table, 0);
sqlite3VdbeChangeP3(v, addr+6, (char*)pAll->z, pAll->n);
sqlite3ChangeCookie(db, v, iDb);
sqlite3VdbeAddOp(v, OP_Close, 0, 0);
sqlite3VdbeOp3(v, OP_ParseSchema, iDb, 0,
sqlite3MPrintf("type='trigger' AND name='%q'", pTrig->name), P3_DYNAMIC);
}
if( db->init.busy ){
int n;
Table *pTab;
Trigger *pDel;
pDel = sqlite3HashInsert(&db->aDb[iDb].pSchema->trigHash,
pTrig->name, strlen(pTrig->name)+1, pTrig);
if( pDel ){
assert( sqlite3MallocFailed() && pDel==pTrig );
goto triggerfinish_cleanup;
}
n = strlen(pTrig->table) + 1;
pTab = sqlite3HashFind(&pTrig->pTabSchema->tblHash, pTrig->table, n);
assert( pTab!=0 );
pTrig->pNext = pTab->pTrigger;
pTab->pTrigger = pTrig;
pTrig = 0;
}
triggerfinish_cleanup:
sqlite3DeleteTrigger(pTrig);
assert( !pParse->pNewTrigger );
sqlite3DeleteTriggerStep(pStepList);
}
/*
** Make a copy of all components of the given trigger step. This has
** the effect of copying all Expr.token.z values into memory obtained
** from sqliteMalloc(). As initially created, the Expr.token.z values
** all point to the input string that was fed to the parser. But that
** string is ephemeral - it will go away as soon as the sqlite3_exec()
** call that started the parser exits. This routine makes a persistent
** copy of all the Expr.token.z strings so that the TriggerStep structure
** will be valid even after the sqlite3_exec() call returns.
*/
static void sqlitePersistTriggerStep(TriggerStep *p){
if( p->target.z ){
p->target.z = (u8*)sqliteStrNDup((char*)p->target.z, p->target.n);
p->target.dyn = 1;
}
if( p->pSelect ){
Select *pNew = sqlite3SelectDup(p->pSelect);
sqlite3SelectDelete(p->pSelect);
p->pSelect = pNew;
}
if( p->pWhere ){
Expr *pNew = sqlite3ExprDup(p->pWhere);
sqlite3ExprDelete(p->pWhere);
p->pWhere = pNew;
}
if( p->pExprList ){
ExprList *pNew = sqlite3ExprListDup(p->pExprList);
sqlite3ExprListDelete(p->pExprList);
p->pExprList = pNew;
}
if( p->pIdList ){
IdList *pNew = sqlite3IdListDup(p->pIdList);
sqlite3IdListDelete(p->pIdList);
p->pIdList = pNew;
}
}
/*
** Turn a SELECT statement (that the pSelect parameter points to) into
** a trigger step. Return a pointer to a TriggerStep structure.
**
** The parser calls this routine when it finds a SELECT statement in
** body of a TRIGGER.
*/
TriggerStep *sqlite3TriggerSelectStep(Select *pSelect){
TriggerStep *pTriggerStep = sqliteMalloc(sizeof(TriggerStep));
if( pTriggerStep==0 ) {
sqlite3SelectDelete(pSelect);
return 0;
}
pTriggerStep->op = TK_SELECT;
pTriggerStep->pSelect = pSelect;
pTriggerStep->orconf = OE_Default;
sqlitePersistTriggerStep(pTriggerStep);
return pTriggerStep;
}
/*
** Build a trigger step out of an INSERT statement. Return a pointer
** to the new trigger step.
**
** The parser calls this routine when it sees an INSERT inside the
** body of a trigger.
*/
TriggerStep *sqlite3TriggerInsertStep(
Token *pTableName, /* Name of the table into which we insert */
IdList *pColumn, /* List of columns in pTableName to insert into */
ExprList *pEList, /* The VALUE clause: a list of values to be inserted */
Select *pSelect, /* A SELECT statement that supplies values */
int orconf /* The conflict algorithm (OE_Abort, OE_Replace, etc.) */
){
TriggerStep *pTriggerStep = sqliteMalloc(sizeof(TriggerStep));
assert(pEList == 0 || pSelect == 0);
assert(pEList != 0 || pSelect != 0);
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;
}
/*
** Construct a trigger step that implements an UPDATE statement and return
** a pointer to that trigger step. The parser calls this routine when it
** sees an UPDATE statement inside the body of a CREATE TRIGGER.
*/
TriggerStep *sqlite3TriggerUpdateStep(
Token *pTableName, /* Name of the table to be updated */
ExprList *pEList, /* The SET clause: list of column and new values */
Expr *pWhere, /* The WHERE clause */
int orconf /* The conflict algorithm. (OE_Abort, OE_Ignore, etc) */
){
TriggerStep *pTriggerStep = sqliteMalloc(sizeof(TriggerStep));
if( pTriggerStep==0 ) return 0;
pTriggerStep->op = TK_UPDATE;
pTriggerStep->target = *pTableName;
pTriggerStep->pExprList = pEList;
pTriggerStep->pWhere = pWhere;
pTriggerStep->orconf = orconf;
sqlitePersistTriggerStep(pTriggerStep);
return pTriggerStep;
}
/*
** Construct a trigger step that implements a DELETE statement and return
** a pointer to that trigger step. The parser calls this routine when it
** sees a DELETE statement inside the body of a CREATE TRIGGER.
*/
TriggerStep *sqlite3TriggerDeleteStep(Token *pTableName, Expr *pWhere){
TriggerStep *pTriggerStep = sqliteMalloc(sizeof(TriggerStep));
if( pTriggerStep==0 ) return 0;
pTriggerStep->op = TK_DELETE;
pTriggerStep->target = *pTableName;
pTriggerStep->pWhere = pWhere;
pTriggerStep->orconf = OE_Default;
sqlitePersistTriggerStep(pTriggerStep);
return pTriggerStep;
}
/*
** Recursively delete a Trigger structure
*/
void sqlite3DeleteTrigger(Trigger *pTrigger){
if( pTrigger==0 ) return;
sqlite3DeleteTriggerStep(pTrigger->step_list);
sqliteFree(pTrigger->name);
sqliteFree(pTrigger->table);
sqlite3ExprDelete(pTrigger->pWhen);
sqlite3IdListDelete(pTrigger->pColumns);
if( pTrigger->nameToken.dyn ) sqliteFree((char*)pTrigger->nameToken.z);
sqliteFree(pTrigger);
}
/*
** This function is called to drop a trigger from the database schema.
**
** This may be called directly from the parser and therefore identifies
** the trigger by name. The sqlite3DropTriggerPtr() routine does the
** same job as this routine except it takes a pointer to the trigger
** instead of the trigger name.
**/
void sqlite3DropTrigger(Parse *pParse, SrcList *pName){
Trigger *pTrigger = 0;
int i;
const char *zDb;
const char *zName;
int nName;
sqlite3 *db = pParse->db;
if( sqlite3MallocFailed() ) goto drop_trigger_cleanup;
if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){
goto drop_trigger_cleanup;
}
assert( pName->nSrc==1 );
zDb = pName->a[0].zDatabase;
zName = pName->a[0].zName;
nName = strlen(zName);
for(i=OMIT_TEMPDB; i<db->nDb; i++){
int j = (i<2) ? i^1 : i; /* Search TEMP before MAIN */
if( zDb && sqlite3StrICmp(db->aDb[j].zName, zDb) ) continue;
pTrigger = sqlite3HashFind(&(db->aDb[j].pSchema->trigHash), zName, nName+1);
if( pTrigger ) break;
}
if( !pTrigger ){
sqlite3ErrorMsg(pParse, "no such trigger: %S", pName, 0);
goto drop_trigger_cleanup;
}
sqlite3DropTriggerPtr(pParse, pTrigger, 0);
drop_trigger_cleanup:
sqlite3SrcListDelete(pName);
}
/*
** Return a pointer to the Table structure for the table that a trigger
** is set on.
*/
static Table *tableOfTrigger(sqlite3 *db, Trigger *pTrigger){
int n = strlen(pTrigger->table) + 1;
return sqlite3HashFind(&pTrigger->pTabSchema->tblHash, pTrigger->table, n);
}
/*
** Drop a trigger given a pointer to that trigger. If nested is false,
** then also generate code to remove the trigger from the SQLITE_MASTER
** table.
*/
void sqlite3DropTriggerPtr(Parse *pParse, Trigger *pTrigger, int nested){
Table *pTable;
Vdbe *v;
sqlite3 *db = pParse->db;
int iDb;
iDb = sqlite3SchemaToIndex(pParse->db, pTrigger->pSchema);
assert( iDb>=0 && iDb<db->nDb );
pTable = tableOfTrigger(db, pTrigger);
assert(pTable);
assert( pTable->pSchema==pTrigger->pSchema || iDb==1 );
#ifndef SQLITE_OMIT_AUTHORIZATION
{
int code = SQLITE_DROP_TRIGGER;
const char *zDb = db->aDb[iDb].zName;
const char *zTab = SCHEMA_TABLE(iDb);
if( iDb==1 ) code = SQLITE_DROP_TEMP_TRIGGER;
if( sqlite3AuthCheck(pParse, code, pTrigger->name, pTable->zName, zDb) ||
sqlite3AuthCheck(pParse, SQLITE_DELETE, zTab, 0, zDb) ){
return;
}
}
#endif
/* Generate code to destroy the database record of the trigger.
*/
if( pTable!=0 && (v = sqlite3GetVdbe(pParse))!=0 ){
int base;
static const VdbeOpList dropTrigger[] = {
{ OP_Rewind, 0, ADDR(9), 0},
{ OP_String8, 0, 0, 0}, /* 1 */
{ OP_Column, 0, 1, 0},
{ OP_Ne, 0, ADDR(8), 0},
{ OP_String8, 0, 0, "trigger"},
{ OP_Column, 0, 0, 0},
{ OP_Ne, 0, ADDR(8), 0},
{ OP_Delete, 0, 0, 0},
{ OP_Next, 0, ADDR(1), 0}, /* 8 */
};
sqlite3BeginWriteOperation(pParse, 0, iDb);
sqlite3OpenMasterTable(pParse, iDb);
base = sqlite3VdbeAddOpList(v, ArraySize(dropTrigger), dropTrigger);
sqlite3VdbeChangeP3(v, base+1, pTrigger->name, 0);
sqlite3ChangeCookie(db, v, iDb);
sqlite3VdbeAddOp(v, OP_Close, 0, 0);
sqlite3VdbeOp3(v, OP_DropTrigger, iDb, 0, pTrigger->name, 0);
}
}
/*
** Remove a trigger from the hash tables of the sqlite* pointer.
*/
void sqlite3UnlinkAndDeleteTrigger(sqlite3 *db, int iDb, const char *zName){
Trigger *pTrigger;
int nName = strlen(zName);
pTrigger = sqlite3HashInsert(&(db->aDb[iDb].pSchema->trigHash), zName, nName+1, 0);
if( pTrigger ){
Table *pTable = tableOfTrigger(db, pTrigger);
assert( pTable!=0 );
if( pTable->pTrigger == pTrigger ){
pTable->pTrigger = pTrigger->pNext;
}else{
Trigger *cc = pTable->pTrigger;
while( cc ){
if( cc->pNext == pTrigger ){
cc->pNext = cc->pNext->pNext;
break;
}
cc = cc->pNext;
}
assert(cc);
}
sqlite3DeleteTrigger(pTrigger);
db->flags |= SQLITE_InternChanges;
}
}
/*
** pEList is the SET clause of an UPDATE statement. Each entry
** in pEList is of the format <id>=<expr>. If any of the entries
** in pEList have an <id> which matches an identifier in pIdList,
** then return TRUE. If pIdList==NULL, then it is considered a
** wildcard that matches anything. Likewise if pEList==NULL then
** it matches anything so always return true. Return false only
** if there is no match.
*/
static int checkColumnOverLap(IdList *pIdList, ExprList *pEList){
int e;
if( !pIdList || !pEList ) return 1;
for(e=0; e<pEList->nExpr; e++){
if( sqlite3IdListIndex(pIdList, pEList->a[e].zName)>=0 ) return 1;
}
return 0;
}
/*
** Return a bit vector to indicate what kind of triggers exist for operation
** "op" on table pTab. If pChanges is not NULL then it is a list of columns
** that are being updated. Triggers only match if the ON clause of the
** trigger definition overlaps the set of columns being updated.
**
** The returned bit vector is some combination of TRIGGER_BEFORE and
** TRIGGER_AFTER.
*/
int sqlite3TriggersExist(
Parse *pParse, /* Used to check for recursive triggers */
Table *pTab, /* The table the contains the triggers */
int op, /* one of TK_DELETE, TK_INSERT, TK_UPDATE */
ExprList *pChanges /* Columns that change in an UPDATE statement */
){
Trigger *pTrigger = pTab->pTrigger;
int mask = 0;
while( pTrigger ){
if( pTrigger->op==op && checkColumnOverLap(pTrigger->pColumns, pChanges) ){
TriggerStack *ss;
ss = pParse->trigStack;
while( ss && ss->pTrigger!=pTab->pTrigger ){
ss = ss->pNext;
}
if( ss==0 ){
mask |= pTrigger->tr_tm;
}
}
pTrigger = pTrigger->pNext;
}
return mask;
}
/*
** Convert the pStep->target token into a SrcList and return a pointer
** to that SrcList.
**
** This routine adds a specific database name, if needed, to the target when
** forming the SrcList. This prevents a trigger in one database from
** referring to a target in another database. An exception is when the
** trigger is in TEMP in which case it can refer to any other database it
** wants.
*/
static SrcList *targetSrcList(
Parse *pParse, /* The parsing context */
TriggerStep *pStep /* The trigger containing the target token */
){
Token sDb; /* Dummy database name token */
int iDb; /* Index of the database to use */
SrcList *pSrc; /* SrcList to be returned */
iDb = sqlite3SchemaToIndex(pParse->db, pStep->pTrig->pSchema);
if( iDb==0 || iDb>=2 ){
assert( iDb<pParse->db->nDb );
sDb.z = (u8*)pParse->db->aDb[iDb].zName;
sDb.n = strlen((char*)sDb.z);
pSrc = sqlite3SrcListAppend(0, &sDb, &pStep->target);
} else {
pSrc = sqlite3SrcListAppend(0, &pStep->target, 0);
}
return pSrc;
}
/*
** Generate VDBE code for zero or more statements inside the body of a
** trigger.
*/
static int codeTriggerProgram(
Parse *pParse, /* The parser context */
TriggerStep *pStepList, /* List of statements inside the trigger body */
int orconfin /* Conflict algorithm. (OE_Abort, etc) */
){
TriggerStep * pTriggerStep = pStepList;
int orconf;
Vdbe *v = pParse->pVdbe;
assert( pTriggerStep!=0 );
assert( v!=0 );
sqlite3VdbeAddOp(v, OP_ContextPush, 0, 0);
VdbeComment((v, "# begin trigger %s", pStepList->pTrig->name));
while( pTriggerStep ){
orconf = (orconfin == OE_Default)?pTriggerStep->orconf:orconfin;
pParse->trigStack->orconf = orconf;
switch( pTriggerStep->op ){
case TK_SELECT: {
Select * ss = sqlite3SelectDup(pTriggerStep->pSelect);
assert(ss);
assert(ss->pSrc);
sqlite3SelectResolve(pParse, ss, 0);
sqlite3Select(pParse, ss, SRT_Discard, 0, 0, 0, 0, 0);
sqlite3SelectDelete(ss);
break;
}
case TK_UPDATE: {
SrcList *pSrc;
pSrc = targetSrcList(pParse, pTriggerStep);
sqlite3VdbeAddOp(v, OP_ResetCount, 0, 0);
sqlite3Update(pParse, pSrc,
sqlite3ExprListDup(pTriggerStep->pExprList),
sqlite3ExprDup(pTriggerStep->pWhere), orconf);
sqlite3VdbeAddOp(v, OP_ResetCount, 1, 0);
break;
}
case TK_INSERT: {
SrcList *pSrc;
pSrc = targetSrcList(pParse, pTriggerStep);
sqlite3VdbeAddOp(v, OP_ResetCount, 0, 0);
sqlite3Insert(pParse, pSrc,
sqlite3ExprListDup(pTriggerStep->pExprList),
sqlite3SelectDup(pTriggerStep->pSelect),
sqlite3IdListDup(pTriggerStep->pIdList), orconf);
sqlite3VdbeAddOp(v, OP_ResetCount, 1, 0);
break;
}
case TK_DELETE: {
SrcList *pSrc;
sqlite3VdbeAddOp(v, OP_ResetCount, 0, 0);
pSrc = targetSrcList(pParse, pTriggerStep);
sqlite3DeleteFrom(pParse, pSrc, sqlite3ExprDup(pTriggerStep->pWhere));
sqlite3VdbeAddOp(v, OP_ResetCount, 1, 0);
break;
}
default:
assert(0);
}
pTriggerStep = pTriggerStep->pNext;
}
sqlite3VdbeAddOp(v, OP_ContextPop, 0, 0);
VdbeComment((v, "# end trigger %s", pStepList->pTrig->name));
return 0;
}
/*
** This is called to code FOR EACH ROW triggers.
**
** When the code that this function generates is executed, the following
** must be true:
**
** 1. No cursors may be open in the main database. (But newIdx and oldIdx
** can be indices of cursors in temporary tables. See below.)
**
** 2. If the triggers being coded are ON INSERT or ON UPDATE triggers, then
** a temporary vdbe cursor (index newIdx) must be open and pointing at
** a row containing values to be substituted for new.* expressions in the
** trigger program(s).
**
** 3. If the triggers being coded are ON DELETE or ON UPDATE triggers, then
** a temporary vdbe cursor (index oldIdx) must be open and pointing at
** a row containing values to be substituted for old.* expressions in the
** trigger program(s).
**
*/
int sqlite3CodeRowTrigger(
Parse *pParse, /* Parse context */
int op, /* One of TK_UPDATE, TK_INSERT, TK_DELETE */
ExprList *pChanges, /* Changes list for any UPDATE OF triggers */
int tr_tm, /* One of TRIGGER_BEFORE, TRIGGER_AFTER */
Table *pTab, /* The table to code triggers from */
int newIdx, /* The indice of the "new" row to access */
int oldIdx, /* The indice of the "old" row to access */
int orconf, /* ON CONFLICT policy */
int ignoreJump /* Instruction to jump to for RAISE(IGNORE) */
){
Trigger *p;
TriggerStack trigStackEntry;
assert(op == TK_UPDATE || op == TK_INSERT || op == TK_DELETE);
assert(tr_tm == TRIGGER_BEFORE || tr_tm == TRIGGER_AFTER );
assert(newIdx != -1 || oldIdx != -1);
for(p=pTab->pTrigger; p; p=p->pNext){
int fire_this = 0;
/* Determine whether we should code this trigger */
if(
p->op==op &&
p->tr_tm==tr_tm &&
(p->pSchema==p->pTabSchema || p->pSchema==pParse->db->aDb[1].pSchema) &&
(op!=TK_UPDATE||!p->pColumns||checkColumnOverLap(p->pColumns,pChanges))
){
TriggerStack *pS; /* Pointer to trigger-stack entry */
for(pS=pParse->trigStack; pS && p!=pS->pTrigger; pS=pS->pNext);
if( !pS ){
fire_this = 1;
}
}
if( fire_this ){
int endTrigger;
Expr * whenExpr;
AuthContext sContext;
NameContext sNC;
memset(&sNC, 0, sizeof(sNC));
sNC.pParse = pParse;
/* Push an entry on to the trigger stack */
trigStackEntry.pTrigger = p;
trigStackEntry.newIdx = newIdx;
trigStackEntry.oldIdx = oldIdx;
trigStackEntry.pTab = pTab;
trigStackEntry.pNext = pParse->trigStack;
trigStackEntry.ignoreJump = ignoreJump;
pParse->trigStack = &trigStackEntry;
sqlite3AuthContextPush(pParse, &sContext, p->name);
/* code the WHEN clause */
endTrigger = sqlite3VdbeMakeLabel(pParse->pVdbe);
whenExpr = sqlite3ExprDup(p->pWhen);
if( sqlite3ExprResolveNames(&sNC, whenExpr) ){
pParse->trigStack = trigStackEntry.pNext;
sqlite3ExprDelete(whenExpr);
return 1;
}
sqlite3ExprIfFalse(pParse, whenExpr, endTrigger, 1);
sqlite3ExprDelete(whenExpr);
codeTriggerProgram(pParse, p->step_list, orconf);
/* Pop the entry off the trigger stack */
pParse->trigStack = trigStackEntry.pNext;
sqlite3AuthContextPop(&sContext);
sqlite3VdbeResolveLabel(pParse->pVdbe, endTrigger);
}
}
return 0;
}
#endif /* !defined(SQLITE_OMIT_TRIGGER) */

Просмотреть файл

@ -1,508 +0,0 @@
/*
** 2001 September 15
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
**
** May you do good and not evil.
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
*************************************************************************
** This file contains C code routines that are called by the parser
** to handle UPDATE statements.
**
** $Id: update.c,v 1.122 2006/02/10 02:27:43 danielk1977 Exp $
*/
#include "sqliteInt.h"
/*
** The most recently coded instruction was an OP_Column to retrieve the
** i-th column of table pTab. This routine sets the P3 parameter of the
** OP_Column to the default value, if any.
**
** The default value of a column is specified by a DEFAULT clause in the
** column definition. This was either supplied by the user when the table
** was created, or added later to the table definition by an ALTER TABLE
** command. If the latter, then the row-records in the table btree on disk
** may not contain a value for the column and the default value, taken
** from the P3 parameter of the OP_Column instruction, is returned instead.
** If the former, then all row-records are guaranteed to include a value
** for the column and the P3 value is not required.
**
** Column definitions created by an ALTER TABLE command may only have
** literal default values specified: a number, null or a string. (If a more
** complicated default expression value was provided, it is evaluated
** when the ALTER TABLE is executed and one of the literal values written
** into the sqlite_master table.)
**
** Therefore, the P3 parameter is only required if the default value for
** the column is a literal number, string or null. The sqlite3ValueFromExpr()
** function is capable of transforming these types of expressions into
** sqlite3_value objects.
*/
void sqlite3ColumnDefault(Vdbe *v, Table *pTab, int i){
if( pTab && !pTab->pSelect ){
sqlite3_value *pValue;
u8 enc = ENC(sqlite3VdbeDb(v));
Column *pCol = &pTab->aCol[i];
sqlite3ValueFromExpr(pCol->pDflt, enc, pCol->affinity, &pValue);
if( pValue ){
sqlite3VdbeChangeP3(v, -1, (const char *)pValue, P3_MEM);
}else{
VdbeComment((v, "# %s.%s", pTab->zName, pCol->zName));
}
}
}
/*
** Process an UPDATE statement.
**
** UPDATE OR IGNORE table_wxyz SET a=b, c=d WHERE e<5 AND f NOT NULL;
** \_______/ \________/ \______/ \________________/
* onError pTabList pChanges pWhere
*/
void sqlite3Update(
Parse *pParse, /* The parser context */
SrcList *pTabList, /* The table in which we should change things */
ExprList *pChanges, /* Things to be changed */
Expr *pWhere, /* The WHERE clause. May be null */
int onError /* How to handle constraint errors */
){
int i, j; /* Loop counters */
Table *pTab; /* The table to be updated */
int addr = 0; /* VDBE instruction address of the start of the loop */
WhereInfo *pWInfo; /* Information about the WHERE clause */
Vdbe *v; /* The virtual database engine */
Index *pIdx; /* For looping over indices */
int nIdx; /* Number of indices that need updating */
int nIdxTotal; /* Total number of indices */
int iCur; /* VDBE Cursor number of pTab */
sqlite3 *db; /* The database structure */
Index **apIdx = 0; /* An array of indices that need updating too */
char *aIdxUsed = 0; /* aIdxUsed[i]==1 if the i-th index is used */
int *aXRef = 0; /* aXRef[i] is the index in pChanges->a[] of the
** an expression for the i-th column of the table.
** aXRef[i]==-1 if the i-th column is not changed. */
int chngRowid; /* True if the record number is being changed */
Expr *pRowidExpr = 0; /* Expression defining the new record number */
int openAll = 0; /* True if all indices need to be opened */
AuthContext sContext; /* The authorization context */
NameContext sNC; /* The name-context to resolve expressions in */
int iDb; /* Database containing the table being updated */
#ifndef SQLITE_OMIT_TRIGGER
int isView; /* Trying to update a view */
int triggers_exist = 0; /* True if any row triggers exist */
#endif
int newIdx = -1; /* index of trigger "new" temp table */
int oldIdx = -1; /* index of trigger "old" temp table */
sContext.pParse = 0;
if( pParse->nErr || sqlite3MallocFailed() ){
goto update_cleanup;
}
db = pParse->db;
assert( pTabList->nSrc==1 );
/* Locate the table which we want to update.
*/
pTab = sqlite3SrcListLookup(pParse, pTabList);
if( pTab==0 ) goto update_cleanup;
iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
/* Figure out if we have any triggers and if the table being
** updated is a view
*/
#ifndef SQLITE_OMIT_TRIGGER
triggers_exist = sqlite3TriggersExist(pParse, pTab, TK_UPDATE, pChanges);
isView = pTab->pSelect!=0;
#else
# define triggers_exist 0
# define isView 0
#endif
#ifdef SQLITE_OMIT_VIEW
# undef isView
# define isView 0
#endif
if( sqlite3IsReadOnly(pParse, pTab, triggers_exist) ){
goto update_cleanup;
}
if( isView ){
if( sqlite3ViewGetColumnNames(pParse, pTab) ){
goto update_cleanup;
}
}
aXRef = sqliteMallocRaw( sizeof(int) * pTab->nCol );
if( aXRef==0 ) goto update_cleanup;
for(i=0; i<pTab->nCol; i++) aXRef[i] = -1;
/* If there are FOR EACH ROW triggers, allocate cursors for the
** special OLD and NEW tables
*/
if( triggers_exist ){
newIdx = pParse->nTab++;
oldIdx = pParse->nTab++;
}
/* Allocate a cursors for the main database table and for all indices.
** The index cursors might not be used, but if they are used they
** need to occur right after the database cursor. So go ahead and
** allocate enough space, just in case.
*/
pTabList->a[0].iCursor = iCur = pParse->nTab++;
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
pParse->nTab++;
}
/* Initialize the name-context */
memset(&sNC, 0, sizeof(sNC));
sNC.pParse = pParse;
sNC.pSrcList = pTabList;
/* Resolve the column names in all the expressions of the
** of the UPDATE statement. Also find the column index
** for each column to be updated in the pChanges array. For each
** column to be updated, make sure we have authorization to change
** that column.
*/
chngRowid = 0;
for(i=0; i<pChanges->nExpr; i++){
if( sqlite3ExprResolveNames(&sNC, pChanges->a[i].pExpr) ){
goto update_cleanup;
}
for(j=0; j<pTab->nCol; j++){
if( sqlite3StrICmp(pTab->aCol[j].zName, pChanges->a[i].zName)==0 ){
if( j==pTab->iPKey ){
chngRowid = 1;
pRowidExpr = pChanges->a[i].pExpr;
}
aXRef[j] = i;
break;
}
}
if( j>=pTab->nCol ){
if( sqlite3IsRowid(pChanges->a[i].zName) ){
chngRowid = 1;
pRowidExpr = pChanges->a[i].pExpr;
}else{
sqlite3ErrorMsg(pParse, "no such column: %s", pChanges->a[i].zName);
goto update_cleanup;
}
}
#ifndef SQLITE_OMIT_AUTHORIZATION
{
int rc;
rc = sqlite3AuthCheck(pParse, SQLITE_UPDATE, pTab->zName,
pTab->aCol[j].zName, db->aDb[iDb].zName);
if( rc==SQLITE_DENY ){
goto update_cleanup;
}else if( rc==SQLITE_IGNORE ){
aXRef[j] = -1;
}
}
#endif
}
/* Allocate memory for the array apIdx[] and fill it with pointers to every
** index that needs to be updated. Indices only need updating if their
** key includes one of the columns named in pChanges or if the record
** number of the original table entry is changing.
*/
for(nIdx=nIdxTotal=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, nIdxTotal++){
if( chngRowid ){
i = 0;
}else {
for(i=0; i<pIdx->nColumn; i++){
if( aXRef[pIdx->aiColumn[i]]>=0 ) break;
}
}
if( i<pIdx->nColumn ) nIdx++;
}
if( nIdxTotal>0 ){
apIdx = sqliteMallocRaw( sizeof(Index*) * nIdx + nIdxTotal );
if( apIdx==0 ) goto update_cleanup;
aIdxUsed = (char*)&apIdx[nIdx];
}
for(nIdx=j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
if( chngRowid ){
i = 0;
}else{
for(i=0; i<pIdx->nColumn; i++){
if( aXRef[pIdx->aiColumn[i]]>=0 ) break;
}
}
if( i<pIdx->nColumn ){
apIdx[nIdx++] = pIdx;
aIdxUsed[j] = 1;
}else{
aIdxUsed[j] = 0;
}
}
/* Resolve the column names in all the expressions in the
** WHERE clause.
*/
if( sqlite3ExprResolveNames(&sNC, pWhere) ){
goto update_cleanup;
}
/* Start the view context
*/
if( isView ){
sqlite3AuthContextPush(pParse, &sContext, pTab->zName);
}
/* Begin generating code.
*/
v = sqlite3GetVdbe(pParse);
if( v==0 ) goto update_cleanup;
if( pParse->nested==0 ) sqlite3VdbeCountChanges(v);
sqlite3BeginWriteOperation(pParse, 1, iDb);
/* If we are trying to update a view, realize that view into
** a ephemeral table.
*/
if( isView ){
Select *pView;
pView = sqlite3SelectDup(pTab->pSelect);
sqlite3Select(pParse, pView, SRT_VirtualTab, iCur, 0, 0, 0, 0);
sqlite3SelectDelete(pView);
}
/* Begin the database scan
*/
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 0);
if( pWInfo==0 ) goto update_cleanup;
/* Remember the index of every item to be updated.
*/
sqlite3VdbeAddOp(v, OP_Rowid, iCur, 0);
sqlite3VdbeAddOp(v, OP_FifoWrite, 0, 0);
/* End the database scan loop.
*/
sqlite3WhereEnd(pWInfo);
/* Initialize the count of updated rows
*/
if( db->flags & SQLITE_CountRows && !pParse->trigStack ){
sqlite3VdbeAddOp(v, OP_Integer, 0, 0);
}
if( triggers_exist ){
/* Create pseudo-tables for NEW and OLD
*/
sqlite3VdbeAddOp(v, OP_OpenPseudo, oldIdx, 0);
sqlite3VdbeAddOp(v, OP_SetNumColumns, oldIdx, pTab->nCol);
sqlite3VdbeAddOp(v, OP_OpenPseudo, newIdx, 0);
sqlite3VdbeAddOp(v, OP_SetNumColumns, newIdx, pTab->nCol);
/* The top of the update loop for when there are triggers.
*/
addr = sqlite3VdbeAddOp(v, OP_FifoRead, 0, 0);
if( !isView ){
sqlite3VdbeAddOp(v, OP_Dup, 0, 0);
sqlite3VdbeAddOp(v, OP_Dup, 0, 0);
/* Open a cursor and make it point to the record that is
** being updated.
*/
sqlite3OpenTable(pParse, iCur, iDb, pTab, OP_OpenRead);
}
sqlite3VdbeAddOp(v, OP_MoveGe, iCur, 0);
/* Generate the OLD table
*/
sqlite3VdbeAddOp(v, OP_Rowid, iCur, 0);
sqlite3VdbeAddOp(v, OP_RowData, iCur, 0);
sqlite3VdbeAddOp(v, OP_Insert, oldIdx, 0);
/* Generate the NEW table
*/
if( chngRowid ){
sqlite3ExprCodeAndCache(pParse, pRowidExpr);
}else{
sqlite3VdbeAddOp(v, OP_Rowid, iCur, 0);
}
for(i=0; i<pTab->nCol; i++){
if( i==pTab->iPKey ){
sqlite3VdbeAddOp(v, OP_Null, 0, 0);
continue;
}
j = aXRef[i];
if( j<0 ){
sqlite3VdbeAddOp(v, OP_Column, iCur, i);
sqlite3ColumnDefault(v, pTab, i);
}else{
sqlite3ExprCodeAndCache(pParse, pChanges->a[j].pExpr);
}
}
sqlite3VdbeAddOp(v, OP_MakeRecord, pTab->nCol, 0);
if( !isView ){
sqlite3TableAffinityStr(v, pTab);
}
if( pParse->nErr ) goto update_cleanup;
sqlite3VdbeAddOp(v, OP_Insert, newIdx, 0);
if( !isView ){
sqlite3VdbeAddOp(v, OP_Close, iCur, 0);
}
/* Fire the BEFORE and INSTEAD OF triggers
*/
if( sqlite3CodeRowTrigger(pParse, TK_UPDATE, pChanges, TRIGGER_BEFORE, pTab,
newIdx, oldIdx, onError, addr) ){
goto update_cleanup;
}
}
if( !isView ){
/*
** Open every index that needs updating. Note that if any
** index could potentially invoke a REPLACE conflict resolution
** action, then we need to open all indices because we might need
** to be deleting some records.
*/
sqlite3OpenTable(pParse, iCur, iDb, pTab, OP_OpenWrite);
if( onError==OE_Replace ){
openAll = 1;
}else{
openAll = 0;
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
if( pIdx->onError==OE_Replace ){
openAll = 1;
break;
}
}
}
for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
if( openAll || aIdxUsed[i] ){
KeyInfo *pKey = sqlite3IndexKeyinfo(pParse, pIdx);
sqlite3VdbeAddOp(v, OP_Integer, iDb, 0);
sqlite3VdbeOp3(v, OP_OpenWrite, iCur+i+1, pIdx->tnum,
(char*)pKey, P3_KEYINFO_HANDOFF);
assert( pParse->nTab>iCur+i+1 );
}
}
/* Loop over every record that needs updating. We have to load
** the old data for each record to be updated because some columns
** might not change and we will need to copy the old value.
** Also, the old data is needed to delete the old index entires.
** So make the cursor point at the old record.
*/
if( !triggers_exist ){
addr = sqlite3VdbeAddOp(v, OP_FifoRead, 0, 0);
sqlite3VdbeAddOp(v, OP_Dup, 0, 0);
}
sqlite3VdbeAddOp(v, OP_NotExists, iCur, addr);
/* If the record number will change, push the record number as it
** will be after the update. (The old record number is currently
** on top of the stack.)
*/
if( chngRowid ){
sqlite3ExprCode(pParse, pRowidExpr);
sqlite3VdbeAddOp(v, OP_MustBeInt, 0, 0);
}
/* Compute new data for this record.
*/
for(i=0; i<pTab->nCol; i++){
if( i==pTab->iPKey ){
sqlite3VdbeAddOp(v, OP_Null, 0, 0);
continue;
}
j = aXRef[i];
if( j<0 ){
sqlite3VdbeAddOp(v, OP_Column, iCur, i);
sqlite3ColumnDefault(v, pTab, i);
}else{
sqlite3ExprCode(pParse, pChanges->a[j].pExpr);
}
}
/* Do constraint checks
*/
sqlite3GenerateConstraintChecks(pParse, pTab, iCur, aIdxUsed, chngRowid, 1,
onError, addr);
/* Delete the old indices for the current record.
*/
sqlite3GenerateRowIndexDelete(db, v, pTab, iCur, aIdxUsed);
/* If changing the record number, delete the old record.
*/
if( chngRowid ){
sqlite3VdbeAddOp(v, OP_Delete, iCur, 0);
}
/* Create the new index entries and the new record.
*/
sqlite3CompleteInsertion(pParse, pTab, iCur, aIdxUsed, chngRowid, 1, -1);
}
/* Increment the row counter
*/
if( db->flags & SQLITE_CountRows && !pParse->trigStack){
sqlite3VdbeAddOp(v, OP_AddImm, 1, 0);
}
/* If there are triggers, close all the cursors after each iteration
** through the loop. The fire the after triggers.
*/
if( triggers_exist ){
if( !isView ){
for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
if( openAll || aIdxUsed[i] )
sqlite3VdbeAddOp(v, OP_Close, iCur+i+1, 0);
}
sqlite3VdbeAddOp(v, OP_Close, iCur, 0);
}
if( sqlite3CodeRowTrigger(pParse, TK_UPDATE, pChanges, TRIGGER_AFTER, pTab,
newIdx, oldIdx, onError, addr) ){
goto update_cleanup;
}
}
/* Repeat the above with the next record to be updated, until
** all record selected by the WHERE clause have been updated.
*/
sqlite3VdbeAddOp(v, OP_Goto, 0, addr);
sqlite3VdbeJumpHere(v, addr);
/* Close all tables if there were no FOR EACH ROW triggers */
if( !triggers_exist ){
for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
if( openAll || aIdxUsed[i] ){
sqlite3VdbeAddOp(v, OP_Close, iCur+i+1, 0);
}
}
sqlite3VdbeAddOp(v, OP_Close, iCur, 0);
}else{
sqlite3VdbeAddOp(v, OP_Close, newIdx, 0);
sqlite3VdbeAddOp(v, OP_Close, oldIdx, 0);
}
/*
** Return the number of rows that were changed. If this routine is
** generating code because of a call to sqlite3NestedParse(), do not
** invoke the callback function.
*/
if( db->flags & SQLITE_CountRows && !pParse->trigStack && pParse->nested==0 ){
sqlite3VdbeAddOp(v, OP_Callback, 1, 0);
sqlite3VdbeSetNumCols(v, 1);
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "rows updated", P3_STATIC);
}
update_cleanup:
sqlite3AuthContextPop(&sContext);
sqliteFree(apIdx);
sqliteFree(aXRef);
sqlite3SrcListDelete(pTabList);
sqlite3ExprListDelete(pChanges);
sqlite3ExprDelete(pWhere);
return;
}

Просмотреть файл

@ -1,596 +0,0 @@
/*
** 2004 April 13
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
**
** May you do good and not evil.
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
*************************************************************************
** This file contains routines used to translate between UTF-8,
** UTF-16, UTF-16BE, and UTF-16LE.
**
** $Id: utf.c,v 1.37 2006/01/24 10:58:22 danielk1977 Exp $
**
** Notes on UTF-8:
**
** Byte-0 Byte-1 Byte-2 Byte-3 Value
** 0xxxxxxx 00000000 00000000 0xxxxxxx
** 110yyyyy 10xxxxxx 00000000 00000yyy yyxxxxxx
** 1110zzzz 10yyyyyy 10xxxxxx 00000000 zzzzyyyy yyxxxxxx
** 11110uuu 10uuzzzz 10yyyyyy 10xxxxxx 000uuuuu zzzzyyyy yyxxxxxx
**
**
** Notes on UTF-16: (with wwww+1==uuuuu)
**
** Word-0 Word-1 Value
** 110110ww wwzzzzyy 110111yy yyxxxxxx 000uuuuu zzzzyyyy yyxxxxxx
** zzzzyyyy yyxxxxxx 00000000 zzzzyyyy yyxxxxxx
**
**
** BOM or Byte Order Mark:
** 0xff 0xfe little-endian utf-16 follows
** 0xfe 0xff big-endian utf-16 follows
**
**
** Handling of malformed strings:
**
** SQLite accepts and processes malformed strings without an error wherever
** possible. However this is not possible when converting between UTF-8 and
** UTF-16.
**
** When converting malformed UTF-8 strings to UTF-16, one instance of the
** replacement character U+FFFD for each byte that cannot be interpeted as
** part of a valid unicode character.
**
** When converting malformed UTF-16 strings to UTF-8, one instance of the
** replacement character U+FFFD for each pair of bytes that cannot be
** interpeted as part of a valid unicode character.
**
** This file contains the following public routines:
**
** sqlite3VdbeMemTranslate() - Translate the encoding used by a Mem* string.
** sqlite3VdbeMemHandleBom() - Handle byte-order-marks in UTF16 Mem* strings.
** sqlite3utf16ByteLen() - Calculate byte-length of a void* UTF16 string.
** sqlite3utf8CharLen() - Calculate char-length of a char* UTF8 string.
** sqlite3utf8LikeCompare() - Do a LIKE match given two UTF8 char* strings.
**
*/
#include "sqliteInt.h"
#include <assert.h>
#include "vdbeInt.h"
/*
** This table maps from the first byte of a UTF-8 character to the number
** of trailing bytes expected. A value '255' indicates that the table key
** is not a legal first byte for a UTF-8 character.
*/
static const u8 xtra_utf8_bytes[256] = {
/* 0xxxxxxx */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* 10wwwwww */
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
/* 110yyyyy */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
/* 1110zzzz */
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
/* 11110yyy */
3, 3, 3, 3, 3, 3, 3, 3, 255, 255, 255, 255, 255, 255, 255, 255,
};
/*
** This table maps from the number of trailing bytes in a UTF-8 character
** to an integer constant that is effectively calculated for each character
** read by a naive implementation of a UTF-8 character reader. The code
** in the READ_UTF8 macro explains things best.
*/
static const int xtra_utf8_bits[4] = {
0,
12416, /* (0xC0 << 6) + (0x80) */
925824, /* (0xE0 << 12) + (0x80 << 6) + (0x80) */
63447168 /* (0xF0 << 18) + (0x80 << 12) + (0x80 << 6) + 0x80 */
};
#define READ_UTF8(zIn, c) { \
int xtra; \
c = *(zIn)++; \
xtra = xtra_utf8_bytes[c]; \
switch( xtra ){ \
case 255: c = (int)0xFFFD; break; \
case 3: c = (c<<6) + *(zIn)++; \
case 2: c = (c<<6) + *(zIn)++; \
case 1: c = (c<<6) + *(zIn)++; \
c -= xtra_utf8_bits[xtra]; \
} \
}
int sqlite3ReadUtf8(const unsigned char *z){
int c;
READ_UTF8(z, c);
return c;
}
#define SKIP_UTF8(zIn) { \
zIn += (xtra_utf8_bytes[*(u8 *)zIn] + 1); \
}
#define WRITE_UTF8(zOut, c) { \
if( c<0x00080 ){ \
*zOut++ = (c&0xFF); \
} \
else if( c<0x00800 ){ \
*zOut++ = 0xC0 + ((c>>6)&0x1F); \
*zOut++ = 0x80 + (c & 0x3F); \
} \
else if( c<0x10000 ){ \
*zOut++ = 0xE0 + ((c>>12)&0x0F); \
*zOut++ = 0x80 + ((c>>6) & 0x3F); \
*zOut++ = 0x80 + (c & 0x3F); \
}else{ \
*zOut++ = 0xF0 + ((c>>18) & 0x07); \
*zOut++ = 0x80 + ((c>>12) & 0x3F); \
*zOut++ = 0x80 + ((c>>6) & 0x3F); \
*zOut++ = 0x80 + (c & 0x3F); \
} \
}
#define WRITE_UTF16LE(zOut, c) { \
if( c<=0xFFFF ){ \
*zOut++ = (c&0x00FF); \
*zOut++ = ((c>>8)&0x00FF); \
}else{ \
*zOut++ = (((c>>10)&0x003F) + (((c-0x10000)>>10)&0x00C0)); \
*zOut++ = (0x00D8 + (((c-0x10000)>>18)&0x03)); \
*zOut++ = (c&0x00FF); \
*zOut++ = (0x00DC + ((c>>8)&0x03)); \
} \
}
#define WRITE_UTF16BE(zOut, c) { \
if( c<=0xFFFF ){ \
*zOut++ = ((c>>8)&0x00FF); \
*zOut++ = (c&0x00FF); \
}else{ \
*zOut++ = (0x00D8 + (((c-0x10000)>>18)&0x03)); \
*zOut++ = (((c>>10)&0x003F) + (((c-0x10000)>>10)&0x00C0)); \
*zOut++ = (0x00DC + ((c>>8)&0x03)); \
*zOut++ = (c&0x00FF); \
} \
}
#define READ_UTF16LE(zIn, c){ \
c = (*zIn++); \
c += ((*zIn++)<<8); \
if( c>=0xD800 && c<=0xE000 ){ \
int c2 = (*zIn++); \
c2 += ((*zIn++)<<8); \
c = (c2&0x03FF) + ((c&0x003F)<<10) + (((c&0x03C0)+0x0040)<<10); \
} \
}
#define READ_UTF16BE(zIn, c){ \
c = ((*zIn++)<<8); \
c += (*zIn++); \
if( c>=0xD800 && c<=0xE000 ){ \
int c2 = ((*zIn++)<<8); \
c2 += (*zIn++); \
c = (c2&0x03FF) + ((c&0x003F)<<10) + (((c&0x03C0)+0x0040)<<10); \
} \
}
#define SKIP_UTF16BE(zIn){ \
if( *zIn>=0xD8 && (*zIn<0xE0 || (*zIn==0xE0 && *(zIn+1)==0x00)) ){ \
zIn += 4; \
}else{ \
zIn += 2; \
} \
}
#define SKIP_UTF16LE(zIn){ \
zIn++; \
if( *zIn>=0xD8 && (*zIn<0xE0 || (*zIn==0xE0 && *(zIn-1)==0x00)) ){ \
zIn += 3; \
}else{ \
zIn += 1; \
} \
}
#define RSKIP_UTF16LE(zIn){ \
if( *zIn>=0xD8 && (*zIn<0xE0 || (*zIn==0xE0 && *(zIn-1)==0x00)) ){ \
zIn -= 4; \
}else{ \
zIn -= 2; \
} \
}
#define RSKIP_UTF16BE(zIn){ \
zIn--; \
if( *zIn>=0xD8 && (*zIn<0xE0 || (*zIn==0xE0 && *(zIn+1)==0x00)) ){ \
zIn -= 3; \
}else{ \
zIn -= 1; \
} \
}
/*
** If the TRANSLATE_TRACE macro is defined, the value of each Mem is
** printed on stderr on the way into and out of sqlite3VdbeMemTranslate().
*/
/* #define TRANSLATE_TRACE 1 */
#ifndef SQLITE_OMIT_UTF16
/*
** This routine transforms the internal text encoding used by pMem to
** desiredEnc. It is an error if the string is already of the desired
** encoding, or if *pMem does not contain a string value.
*/
int sqlite3VdbeMemTranslate(Mem *pMem, u8 desiredEnc){
unsigned char zShort[NBFS]; /* Temporary short output buffer */
int len; /* Maximum length of output string in bytes */
unsigned char *zOut; /* Output buffer */
unsigned char *zIn; /* Input iterator */
unsigned char *zTerm; /* End of input */
unsigned char *z; /* Output iterator */
int c;
assert( pMem->flags&MEM_Str );
assert( pMem->enc!=desiredEnc );
assert( pMem->enc!=0 );
assert( pMem->n>=0 );
#if defined(TRANSLATE_TRACE) && defined(SQLITE_DEBUG)
{
char zBuf[100];
sqlite3VdbeMemPrettyPrint(pMem, zBuf, 100);
fprintf(stderr, "INPUT: %s\n", zBuf);
}
#endif
/* If the translation is between UTF-16 little and big endian, then
** all that is required is to swap the byte order. This case is handled
** differently from the others.
*/
if( pMem->enc!=SQLITE_UTF8 && desiredEnc!=SQLITE_UTF8 ){
u8 temp;
int rc;
rc = sqlite3VdbeMemMakeWriteable(pMem);
if( rc!=SQLITE_OK ){
assert( rc==SQLITE_NOMEM );
return SQLITE_NOMEM;
}
zIn = (u8*)pMem->z;
zTerm = &zIn[pMem->n];
while( zIn<zTerm ){
temp = *zIn;
*zIn = *(zIn+1);
zIn++;
*zIn++ = temp;
}
pMem->enc = desiredEnc;
goto translate_out;
}
/* Set len to the maximum number of bytes required in the output buffer. */
if( desiredEnc==SQLITE_UTF8 ){
/* When converting from UTF-16, the maximum growth results from
** translating a 2-byte character to a 3-byte UTF-8 character (i.e.
** code-point 0xFFFC). A single byte is required for the output string
** nul-terminator.
*/
len = (pMem->n/2) * 3 + 1;
}else{
/* When converting from UTF-8 to UTF-16 the maximum growth is caused
** when a 1-byte UTF-8 character is translated into a 2-byte UTF-16
** character. Two bytes are required in the output buffer for the
** nul-terminator.
*/
len = pMem->n * 2 + 2;
}
/* Set zIn to point at the start of the input buffer and zTerm to point 1
** byte past the end.
**
** Variable zOut is set to point at the output buffer. This may be space
** obtained from malloc(), or Mem.zShort, if it large enough and not in
** use, or the zShort array on the stack (see above).
*/
zIn = (u8*)pMem->z;
zTerm = &zIn[pMem->n];
if( len>NBFS ){
zOut = sqliteMallocRaw(len);
if( !zOut ) return SQLITE_NOMEM;
}else{
zOut = zShort;
}
z = zOut;
if( pMem->enc==SQLITE_UTF8 ){
if( desiredEnc==SQLITE_UTF16LE ){
/* UTF-8 -> UTF-16 Little-endian */
while( zIn<zTerm ){
READ_UTF8(zIn, c);
WRITE_UTF16LE(z, c);
}
}else{
assert( desiredEnc==SQLITE_UTF16BE );
/* UTF-8 -> UTF-16 Big-endian */
while( zIn<zTerm ){
READ_UTF8(zIn, c);
WRITE_UTF16BE(z, c);
}
}
pMem->n = z - zOut;
*z++ = 0;
}else{
assert( desiredEnc==SQLITE_UTF8 );
if( pMem->enc==SQLITE_UTF16LE ){
/* UTF-16 Little-endian -> UTF-8 */
while( zIn<zTerm ){
READ_UTF16LE(zIn, c);
WRITE_UTF8(z, c);
}
}else{
/* UTF-16 Little-endian -> UTF-8 */
while( zIn<zTerm ){
READ_UTF16BE(zIn, c);
WRITE_UTF8(z, c);
}
}
pMem->n = z - zOut;
}
*z = 0;
assert( (pMem->n+(desiredEnc==SQLITE_UTF8?1:2))<=len );
sqlite3VdbeMemRelease(pMem);
pMem->flags &= ~(MEM_Static|MEM_Dyn|MEM_Ephem|MEM_Short);
pMem->enc = desiredEnc;
if( zOut==zShort ){
memcpy(pMem->zShort, zOut, len);
zOut = (u8*)pMem->zShort;
pMem->flags |= (MEM_Term|MEM_Short);
}else{
pMem->flags |= (MEM_Term|MEM_Dyn);
}
pMem->z = (char*)zOut;
translate_out:
#if defined(TRANSLATE_TRACE) && defined(SQLITE_DEBUG)
{
char zBuf[100];
sqlite3VdbeMemPrettyPrint(pMem, zBuf, 100);
fprintf(stderr, "OUTPUT: %s\n", zBuf);
}
#endif
return SQLITE_OK;
}
/*
** This routine checks for a byte-order mark at the beginning of the
** UTF-16 string stored in *pMem. If one is present, it is removed and
** the encoding of the Mem adjusted. This routine does not do any
** byte-swapping, it just sets Mem.enc appropriately.
**
** The allocation (static, dynamic etc.) and encoding of the Mem may be
** changed by this function.
*/
int sqlite3VdbeMemHandleBom(Mem *pMem){
int rc = SQLITE_OK;
u8 bom = 0;
if( pMem->n<0 || pMem->n>1 ){
u8 b1 = *(u8 *)pMem->z;
u8 b2 = *(((u8 *)pMem->z) + 1);
if( b1==0xFE && b2==0xFF ){
bom = SQLITE_UTF16BE;
}
if( b1==0xFF && b2==0xFE ){
bom = SQLITE_UTF16LE;
}
}
if( bom ){
/* This function is called as soon as a string is stored in a Mem*,
** from within sqlite3VdbeMemSetStr(). At that point it is not possible
** for the string to be stored in Mem.zShort, or for it to be stored
** in dynamic memory with no destructor.
*/
assert( !(pMem->flags&MEM_Short) );
assert( !(pMem->flags&MEM_Dyn) || pMem->xDel );
if( pMem->flags & MEM_Dyn ){
void (*xDel)(void*) = pMem->xDel;
char *z = pMem->z;
pMem->z = 0;
pMem->xDel = 0;
rc = sqlite3VdbeMemSetStr(pMem, &z[2], pMem->n-2, bom, SQLITE_TRANSIENT);
xDel(z);
}else{
rc = sqlite3VdbeMemSetStr(pMem, &pMem->z[2], pMem->n-2, bom,
SQLITE_TRANSIENT);
}
}
return rc;
}
#endif /* SQLITE_OMIT_UTF16 */
/*
** pZ is a UTF-8 encoded unicode string. If nByte is less than zero,
** return the number of unicode characters in pZ up to (but not including)
** the first 0x00 byte. If nByte is not less than zero, return the
** number of unicode characters in the first nByte of pZ (or up to
** the first 0x00, whichever comes first).
*/
int sqlite3utf8CharLen(const char *z, int nByte){
int r = 0;
const char *zTerm;
if( nByte>=0 ){
zTerm = &z[nByte];
}else{
zTerm = (const char *)(-1);
}
assert( z<=zTerm );
while( *z!=0 && z<zTerm ){
SKIP_UTF8(z);
r++;
}
return r;
}
#ifndef SQLITE_OMIT_UTF16
/*
** Convert a UTF-16 string in the native encoding into a UTF-8 string.
** Memory to hold the UTF-8 string is obtained from malloc and must be
** freed by the calling function.
**
** NULL is returned if there is an allocation error.
*/
char *sqlite3utf16to8(const void *z, int nByte){
Mem m;
memset(&m, 0, sizeof(m));
sqlite3VdbeMemSetStr(&m, z, nByte, SQLITE_UTF16NATIVE, SQLITE_STATIC);
sqlite3VdbeChangeEncoding(&m, SQLITE_UTF8);
assert( m.flags & MEM_Term );
assert( m.flags & MEM_Str );
return (m.flags & MEM_Dyn)!=0 ? m.z : sqliteStrDup(m.z);
}
/*
** pZ is a UTF-16 encoded unicode string. If nChar is less than zero,
** return the number of bytes up to (but not including), the first pair
** of consecutive 0x00 bytes in pZ. If nChar is not less than zero,
** then return the number of bytes in the first nChar unicode characters
** in pZ (or up until the first pair of 0x00 bytes, whichever comes first).
*/
int sqlite3utf16ByteLen(const void *zIn, int nChar){
int c = 1;
char const *z = zIn;
int n = 0;
if( SQLITE_UTF16NATIVE==SQLITE_UTF16BE ){
/* Using an "if (SQLITE_UTF16NATIVE==SQLITE_UTF16BE)" construct here
** and in other parts of this file means that at one branch will
** not be covered by coverage testing on any single host. But coverage
** will be complete if the tests are run on both a little-endian and
** big-endian host. Because both the UTF16NATIVE and SQLITE_UTF16BE
** macros are constant at compile time the compiler can determine
** which branch will be followed. It is therefore assumed that no runtime
** penalty is paid for this "if" statement.
*/
while( c && ((nChar<0) || n<nChar) ){
READ_UTF16BE(z, c);
n++;
}
}else{
while( c && ((nChar<0) || n<nChar) ){
READ_UTF16LE(z, c);
n++;
}
}
return (z-(char const *)zIn)-((c==0)?2:0);
}
/*
** UTF-16 implementation of the substr()
*/
void sqlite3utf16Substr(
sqlite3_context *context,
int argc,
sqlite3_value **argv
){
int y, z;
unsigned char const *zStr;
unsigned char const *zStrEnd;
unsigned char const *zStart;
unsigned char const *zEnd;
int i;
zStr = (unsigned char const *)sqlite3_value_text16(argv[0]);
zStrEnd = &zStr[sqlite3_value_bytes16(argv[0])];
y = sqlite3_value_int(argv[1]);
z = sqlite3_value_int(argv[2]);
if( y>0 ){
y = y-1;
zStart = zStr;
if( SQLITE_UTF16BE==SQLITE_UTF16NATIVE ){
for(i=0; i<y && zStart<zStrEnd; i++) SKIP_UTF16BE(zStart);
}else{
for(i=0; i<y && zStart<zStrEnd; i++) SKIP_UTF16LE(zStart);
}
}else{
zStart = zStrEnd;
if( SQLITE_UTF16BE==SQLITE_UTF16NATIVE ){
for(i=y; i<0 && zStart>zStr; i++) RSKIP_UTF16BE(zStart);
}else{
for(i=y; i<0 && zStart>zStr; i++) RSKIP_UTF16LE(zStart);
}
for(; i<0; i++) z -= 1;
}
zEnd = zStart;
if( SQLITE_UTF16BE==SQLITE_UTF16NATIVE ){
for(i=0; i<z && zEnd<zStrEnd; i++) SKIP_UTF16BE(zEnd);
}else{
for(i=0; i<z && zEnd<zStrEnd; i++) SKIP_UTF16LE(zEnd);
}
sqlite3_result_text16(context, zStart, zEnd-zStart, SQLITE_TRANSIENT);
}
#if defined(SQLITE_TEST)
/*
** This routine is called from the TCL test function "translate_selftest".
** It checks that the primitives for serializing and deserializing
** characters in each encoding are inverses of each other.
*/
void sqlite3utfSelfTest(){
int i;
unsigned char zBuf[20];
unsigned char *z;
int n;
int c;
for(i=0; i<0x00110000; i++){
z = zBuf;
WRITE_UTF8(z, i);
n = z-zBuf;
z = zBuf;
READ_UTF8(z, c);
assert( c==i );
assert( (z-zBuf)==n );
}
for(i=0; i<0x00110000; i++){
if( i>=0xD800 && i<=0xE000 ) continue;
z = zBuf;
WRITE_UTF16LE(z, i);
n = z-zBuf;
z = zBuf;
READ_UTF16LE(z, c);
assert( c==i );
assert( (z-zBuf)==n );
}
for(i=0; i<0x00110000; i++){
if( i>=0xD800 && i<=0xE000 ) continue;
z = zBuf;
WRITE_UTF16BE(z, i);
n = z-zBuf;
z = zBuf;
READ_UTF16BE(z, c);
assert( c==i );
assert( (z-zBuf)==n );
}
}
#endif /* SQLITE_TEST */
#endif /* SQLITE_OMIT_UTF16 */

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -1,329 +0,0 @@
/*
** 2003 April 6
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
**
** May you do good and not evil.
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
*************************************************************************
** This file contains code used to implement the VACUUM command.
**
** Most of the code in this file may be omitted by defining the
** SQLITE_OMIT_VACUUM macro.
**
** $Id: vacuum.c,v 1.58 2006/01/18 16:51:36 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include "vdbeInt.h"
#include "os.h"
#ifndef SQLITE_OMIT_VACUUM
/*
** Generate a random name of 20 character in length.
*/
static void randomName(unsigned char *zBuf){
static const unsigned char zChars[] =
"abcdefghijklmnopqrstuvwxyz"
"0123456789";
int i;
sqlite3Randomness(20, zBuf);
for(i=0; i<20; i++){
zBuf[i] = zChars[ zBuf[i]%(sizeof(zChars)-1) ];
}
}
/*
** Execute zSql on database db. Return an error code.
*/
static int execSql(sqlite3 *db, const char *zSql){
sqlite3_stmt *pStmt;
if( SQLITE_OK!=sqlite3_prepare(db, zSql, -1, &pStmt, 0) ){
return sqlite3_errcode(db);
}
while( SQLITE_ROW==sqlite3_step(pStmt) );
return sqlite3_finalize(pStmt);
}
/*
** Execute zSql on database db. The statement returns exactly
** one column. Execute this as SQL on the same database.
*/
static int execExecSql(sqlite3 *db, const char *zSql){
sqlite3_stmt *pStmt;
int rc;
rc = sqlite3_prepare(db, zSql, -1, &pStmt, 0);
if( rc!=SQLITE_OK ) return rc;
while( SQLITE_ROW==sqlite3_step(pStmt) ){
rc = execSql(db, (char*)sqlite3_column_text(pStmt, 0));
if( rc!=SQLITE_OK ){
sqlite3_finalize(pStmt);
return rc;
}
}
return sqlite3_finalize(pStmt);
}
#endif
/*
** The non-standard VACUUM command is used to clean up the database,
** collapse free space, etc. It is modelled after the VACUUM command
** in PostgreSQL.
**
** In version 1.0.x of SQLite, the VACUUM command would call
** gdbm_reorganize() on all the database tables. But beginning
** with 2.0.0, SQLite no longer uses GDBM so this command has
** become a no-op.
*/
void sqlite3Vacuum(Parse *pParse, Token *pTableName){
Vdbe *v = sqlite3GetVdbe(pParse);
if( v ){
sqlite3VdbeAddOp(v, OP_Vacuum, 0, 0);
}
return;
}
/*
** This routine implements the OP_Vacuum opcode of the VDBE.
*/
int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
int rc = SQLITE_OK; /* Return code from service routines */
#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 */
Btree *pMain; /* The database being vacuumed */
Btree *pTemp;
char *zSql = 0;
int saved_flags; /* Saved value of the db->flags */
Db *pDb = 0; /* Database to detach at end of vacuum */
/* Save the current value of the write-schema flag before setting it. */
saved_flags = db->flags;
db->flags |= SQLITE_WriteSchema | SQLITE_IgnoreChecks;
if( !db->autoCommit ){
sqlite3SetString(pzErrMsg, "cannot VACUUM from within a transaction",
(char*)0);
rc = SQLITE_ERROR;
goto end_of_vacuum;
}
/* Get the full pathname of the database file and create a
** temporary filename in the same directory as the original file.
*/
pMain = db->aDb[0].pBt;
zFilename = sqlite3BtreeGetFilename(pMain);
assert( zFilename );
if( zFilename[0]=='\0' ){
/* The in-memory database. Do nothing. Return directly to avoid causing
** an error trying to DETACH the vacuum_db (which never got attached)
** in the exit-handler.
*/
return SQLITE_OK;
}
nFilename = strlen(zFilename);
zTemp = sqliteMalloc( nFilename+100 );
if( zTemp==0 ){
rc = SQLITE_NOMEM;
goto end_of_vacuum;
}
strcpy(zTemp, zFilename);
/* 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( 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
** occurs anyway. The integrity of the database is maintained by a
** (possibly synchronous) transaction opened on the main database before
** sqlite3BtreeCopyFile() is called.
**
** An optimisation would be to use a non-journaled pager.
*/
zSql = sqlite3MPrintf("ATTACH '%q' AS vacuum_db;", zTemp);
if( !zSql ){
rc = SQLITE_NOMEM;
goto end_of_vacuum;
}
rc = execSql(db, zSql);
sqliteFree(zSql);
zSql = 0;
if( rc!=SQLITE_OK ) goto end_of_vacuum;
pDb = &db->aDb[db->nDb-1];
assert( strcmp(db->aDb[db->nDb-1].zName,"vacuum_db")==0 );
pTemp = db->aDb[db->nDb-1].pBt;
sqlite3BtreeSetPageSize(pTemp, sqlite3BtreeGetPageSize(pMain),
sqlite3BtreeGetReserve(pMain));
assert( sqlite3BtreeGetPageSize(pTemp)==sqlite3BtreeGetPageSize(pMain) );
rc = execSql(db, "PRAGMA vacuum_db.synchronous=OFF");
if( rc!=SQLITE_OK ){
goto end_of_vacuum;
}
#ifndef SQLITE_OMIT_AUTOVACUUM
sqlite3BtreeSetAutoVacuum(pTemp, sqlite3BtreeGetAutoVacuum(pMain));
#endif
/* Begin a transaction */
rc = execSql(db, "BEGIN EXCLUSIVE;");
if( rc!=SQLITE_OK ) goto end_of_vacuum;
/* Query the schema of the main database. Create a mirror schema
** in the temporary database.
*/
rc = execExecSql(db,
"SELECT 'CREATE TABLE vacuum_db.' || substr(sql,14,100000000) "
" FROM sqlite_master WHERE type='table' AND name!='sqlite_sequence'");
if( rc!=SQLITE_OK ) goto end_of_vacuum;
rc = execExecSql(db,
"SELECT 'CREATE INDEX vacuum_db.' || substr(sql,14,100000000)"
" FROM sqlite_master WHERE sql LIKE 'CREATE INDEX %' ");
if( rc!=SQLITE_OK ) goto end_of_vacuum;
rc = execExecSql(db,
"SELECT 'CREATE UNIQUE INDEX vacuum_db.' || substr(sql,21,100000000) "
" FROM sqlite_master WHERE sql LIKE 'CREATE UNIQUE INDEX %'");
if( rc!=SQLITE_OK ) goto end_of_vacuum;
rc = execExecSql(db,
"SELECT 'CREATE VIEW vacuum_db.' || substr(sql,13,100000000) "
" FROM sqlite_master WHERE type='view'"
);
if( rc!=SQLITE_OK ) goto end_of_vacuum;
/* Loop through the tables in the main database. For each, do
** an "INSERT INTO vacuum_db.xxx SELECT * FROM xxx;" to copy
** the contents to the temporary database.
*/
rc = execExecSql(db,
"SELECT 'INSERT INTO vacuum_db.' || quote(name) "
"|| ' SELECT * FROM ' || quote(name) || ';'"
"FROM sqlite_master "
"WHERE type = 'table' AND name!='sqlite_sequence';"
);
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
** point also.
*/
rc = execExecSql(db,
"SELECT 'CREATE TRIGGER vacuum_db.' || substr(sql, 16, 1000000) "
"FROM sqlite_master WHERE type='trigger'"
);
if( rc!=SQLITE_OK ) goto end_of_vacuum;
/* At this point, unless the main db was completely empty, there is now a
** transaction open on the vacuum database, but not on the main database.
** Open a btree level transaction on the main database. This allows a
** call to sqlite3BtreeCopyFile(). The main database btree level
** transaction is then committed, so the SQL level never knows it was
** opened for writing. This way, the SQL transaction used to create the
** temporary database never needs to be committed.
*/
if( rc==SQLITE_OK ){
u32 meta;
int i;
/* This array determines which meta meta values are preserved in the
** vacuum. Even entries are the meta value number and odd entries
** are an increment to apply to the meta value after the vacuum.
** The increment is used to increase the schema cookie so that other
** connections to the same database will know to reread the schema.
*/
static const unsigned char aCopy[] = {
1, 1, /* Add one to the old schema cookie */
3, 0, /* Preserve the default page cache size */
5, 0, /* Preserve the default text encoding */
6, 0, /* Preserve the user version */
};
assert( 1==sqlite3BtreeIsInTrans(pTemp) );
assert( 1==sqlite3BtreeIsInTrans(pMain) );
/* Copy Btree meta values */
for(i=0; i<sizeof(aCopy)/sizeof(aCopy[0]); i+=2){
rc = sqlite3BtreeGetMeta(pMain, aCopy[i], &meta);
if( rc!=SQLITE_OK ) goto end_of_vacuum;
rc = sqlite3BtreeUpdateMeta(pTemp, aCopy[i], meta+aCopy[i+1]);
if( rc!=SQLITE_OK ) goto end_of_vacuum;
}
rc = sqlite3BtreeCopyFile(pMain, pTemp);
if( rc!=SQLITE_OK ) goto end_of_vacuum;
rc = sqlite3BtreeCommit(pTemp);
if( rc!=SQLITE_OK ) goto end_of_vacuum;
rc = sqlite3BtreeCommit(pMain);
}
end_of_vacuum:
/* Restore the original value of db->flags */
db->flags = saved_flags;
/* Currently there is an SQL level transaction open on the vacuum
** database. No locks are held on any other files (since the main file
** was committed at the btree level). So it safe to end the transaction
** by manually setting the autoCommit flag to true and detaching the
** vacuum database. The vacuum_db journal file is deleted when the pager
** is closed by the DETACH.
*/
db->autoCommit = 1;
if( pDb ){
sqlite3MallocDisallow();
sqlite3BtreeClose(pDb->pBt);
sqlite3MallocAllow();
pDb->pBt = 0;
pDb->pSchema = 0;
}
/* If one of the execSql() calls above returned SQLITE_NOMEM, then the
** mallocFailed flag will be clear (because execSql() calls sqlite3_exec()).
** Fix this so the flag and return code match.
*/
if( rc==SQLITE_NOMEM ){
sqlite3MallocFailed();
}
if( zTemp ){
sqlite3OsDelete(zTemp);
sqliteFree(zTemp);
}
sqliteFree( zSql );
sqlite3ResetInternalSchema(db, 0);
#endif
return rc;
}

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -1,143 +0,0 @@
/*
** 2001 September 15
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
**
** May you do good and not evil.
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
*************************************************************************
** Header file for the Virtual DataBase Engine (VDBE)
**
** This header defines the interface to the virtual database engine
** or VDBE. The VDBE implements an abstract machine that runs a
** simple program to access and modify the underlying database.
**
** $Id: vdbe.h,v 1.101 2006/02/10 03:06:10 danielk1977 Exp $
*/
#ifndef _SQLITE_VDBE_H_
#define _SQLITE_VDBE_H_
#include <stdio.h>
/*
** A single VDBE is an opaque structure named "Vdbe". Only routines
** in the source file sqliteVdbe.c are allowed to see the insides
** of this structure.
*/
typedef struct Vdbe Vdbe;
/*
** A single instruction of the virtual machine has an opcode
** and as many as three operands. The instruction is recorded
** as an instance of the following structure:
*/
struct VdbeOp {
u8 opcode; /* What operation to perform */
int p1; /* First operand */
int p2; /* Second parameter (often the jump destination) */
char *p3; /* Third parameter */
int p3type; /* One of the P3_xxx constants defined below */
#ifdef VDBE_PROFILE
int cnt; /* Number of times this instruction was executed */
long long cycles; /* Total time spend executing this instruction */
#endif
};
typedef struct VdbeOp VdbeOp;
/*
** A smaller version of VdbeOp used for the VdbeAddOpList() function because
** it takes up less space.
*/
struct VdbeOpList {
u8 opcode; /* What operation to perform */
signed char p1; /* First operand */
short int p2; /* Second parameter (often the jump destination) */
char *p3; /* Third parameter */
};
typedef struct VdbeOpList VdbeOpList;
/*
** Allowed values of VdbeOp.p3type
*/
#define P3_NOTUSED 0 /* The P3 parameter is not used */
#define P3_DYNAMIC (-1) /* Pointer to a string obtained from sqliteMalloc() */
#define P3_STATIC (-2) /* Pointer to a static string */
#define P3_COLLSEQ (-4) /* P3 is a pointer to a CollSeq structure */
#define P3_FUNCDEF (-5) /* P3 is a pointer to a FuncDef structure */
#define P3_KEYINFO (-6) /* P3 is a pointer to a KeyInfo structure */
#define P3_VDBEFUNC (-7) /* P3 is a pointer to a VdbeFunc structure */
#define P3_MEM (-8) /* P3 is a pointer to a Mem* structure */
#define P3_TRANSIENT (-9) /* P3 is a pointer to a transient string */
/* When adding a P3 argument using P3_KEYINFO, a copy of the KeyInfo structure
** is made. That copy is freed when the Vdbe is finalized. But if the
** argument is P3_KEYINFO_HANDOFF, the passed in pointer is used. It still
** gets freed when the Vdbe is finalized so it still should be obtained
** from a single sqliteMalloc(). But no copy is made and the calling
** function should *not* try to free the KeyInfo.
*/
#define P3_KEYINFO_HANDOFF (-9)
/*
** The Vdbe.aColName array contains 5n Mem structures, where n is the
** number of columns of data returned by the statement.
*/
#define COLNAME_NAME 0
#define COLNAME_DECLTYPE 1
#define COLNAME_DATABASE 2
#define COLNAME_TABLE 3
#define COLNAME_COLUMN 4
#define COLNAME_N 5 /* Number of COLNAME_xxx symbols */
/*
** The following macro converts a relative address in the p2 field
** of a VdbeOp structure into a negative number so that
** sqlite3VdbeAddOpList() knows that the address is relative. Calling
** the macro again restores the address.
*/
#define ADDR(X) (-1-(X))
/*
** The makefile scans the vdbe.c source file and creates the "opcodes.h"
** header file that defines a number for each opcode used by the VDBE.
*/
#include "opcodes.h"
/*
** Prototypes for the VDBE interface. See comments on the implementation
** for a description of what each of these routines does.
*/
Vdbe *sqlite3VdbeCreate(sqlite3*);
void sqlite3VdbeCreateCallback(Vdbe*, int*);
int sqlite3VdbeAddOp(Vdbe*,int,int,int);
int sqlite3VdbeOp3(Vdbe*,int,int,int,const char *zP3,int);
int sqlite3VdbeAddOpList(Vdbe*, int nOp, VdbeOpList const *aOp);
void sqlite3VdbeChangeP1(Vdbe*, int addr, int P1);
void sqlite3VdbeChangeP2(Vdbe*, int addr, int P2);
void sqlite3VdbeJumpHere(Vdbe*, int addr);
void sqlite3VdbeChangeP3(Vdbe*, int addr, const char *zP1, int N);
VdbeOp *sqlite3VdbeGetOp(Vdbe*, int);
int sqlite3VdbeMakeLabel(Vdbe*);
void sqlite3VdbeDelete(Vdbe*);
void sqlite3VdbeMakeReady(Vdbe*,int,int,int,int);
int sqlite3VdbeFinalize(Vdbe*);
void sqlite3VdbeResolveLabel(Vdbe*, int);
int sqlite3VdbeCurrentAddr(Vdbe*);
void sqlite3VdbeTrace(Vdbe*,FILE*);
int sqlite3VdbeReset(Vdbe*);
int sqliteVdbeSetVariables(Vdbe*,int,const char**);
void sqlite3VdbeSetNumCols(Vdbe*,int);
int sqlite3VdbeSetColName(Vdbe*, int, int, const char *, int);
void sqlite3VdbeCountChanges(Vdbe*);
sqlite3 *sqlite3VdbeDb(Vdbe*);
#ifndef NDEBUG
void sqlite3VdbeComment(Vdbe*, const char*, ...);
# define VdbeComment(X) sqlite3VdbeComment X
#else
# define VdbeComment(X)
#endif
#endif

Просмотреть файл

@ -1,388 +0,0 @@
/*
** 2003 September 6
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
**
** May you do good and not evil.
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
*************************************************************************
** This is the header file for information that is private to the
** VDBE. This information used to all be at the top of the single
** source code file "vdbe.c". When that file became too big (over
** 6000 lines long) it was split up into several smaller files and
** this header information was factored out.
*/
/*
** intToKey() and keyToInt() used to transform the rowid. But with
** the latest versions of the design they are no-ops.
*/
#define keyToInt(X) (X)
#define intToKey(X) (X)
/*
** The makefile scans the vdbe.c source file and creates the following
** array of string constants which are the names of all VDBE opcodes. This
** array is defined in a separate source code file named opcode.c which is
** automatically generated by the makefile.
*/
extern char *sqlite3OpcodeNames[];
/*
** SQL is translated into a sequence of instructions to be
** executed by a virtual machine. Each instruction is an instance
** of the following structure.
*/
typedef struct VdbeOp Op;
/*
** Boolean values
*/
typedef unsigned char Bool;
/*
** A cursor is a pointer into a single BTree within a database file.
** The cursor can seek to a BTree entry with a particular key, or
** loop over all entries of the Btree. You can also insert new BTree
** entries or retrieve the key or data from the entry that the cursor
** is currently pointing to.
**
** Every cursor that the virtual machine has open is represented by an
** instance of the following structure.
**
** If the Cursor.isTriggerRow flag is set it means that this cursor is
** really a single row that represents the NEW or OLD pseudo-table of
** a row trigger. The data for the row is stored in Cursor.pData and
** the rowid is in Cursor.iKey.
*/
struct Cursor {
BtCursor *pCursor; /* The cursor structure of the backend */
int iDb; /* Index of cursor database in db->aDb[] (or -1) */
i64 lastRowid; /* Last rowid from a Next or NextIdx operation */
i64 nextRowid; /* Next rowid returned by OP_NewRowid */
Bool zeroed; /* True if zeroed out and ready for reuse */
Bool rowidIsValid; /* True if lastRowid is valid */
Bool atFirst; /* True if pointing to first entry */
Bool useRandomRowid; /* Generate new record numbers semi-randomly */
Bool nullRow; /* True if pointing to a row with no data */
Bool nextRowidValid; /* True if the nextRowid field is valid */
Bool pseudoTable; /* This is a NEW or OLD pseudo-tables of a trigger */
Bool deferredMoveto; /* A call to sqlite3BtreeMoveto() is needed */
Bool isTable; /* True if a table requiring integer keys */
Bool isIndex; /* True if an index containing keys only - no data */
u8 bogusIncrKey; /* Something for pIncrKey to point to if pKeyInfo==0 */
i64 movetoTarget; /* Argument to the deferred sqlite3BtreeMoveto() */
Btree *pBt; /* Separate file holding temporary table */
int nData; /* Number of bytes in pData */
char *pData; /* Data for a NEW or OLD pseudo-table */
i64 iKey; /* Key for the NEW or OLD pseudo-table row */
u8 *pIncrKey; /* Pointer to pKeyInfo->incrKey */
KeyInfo *pKeyInfo; /* Info about index keys needed by index cursors */
int nField; /* Number of fields in the header */
i64 seqCount; /* Sequence counter */
/* Cached information about the header for the data record that the
** cursor is currently pointing to. Only valid if cacheValid is true.
** aRow might point to (ephemeral) data for the current row, or it might
** be NULL.
*/
int cacheStatus; /* Cache is valid if this matches Vdbe.cacheCtr */
int payloadSize; /* Total number of bytes in the record */
u32 *aType; /* Type values for all entries in the record */
u32 *aOffset; /* Cached offsets to the start of each columns data */
u8 *aRow; /* Data for the current row, if all on one page */
};
typedef struct Cursor Cursor;
/*
** Number of bytes of string storage space available to each stack
** layer without having to malloc. NBFS is short for Number of Bytes
** For Strings.
*/
#define NBFS 32
/*
** A value for Cursor.cacheValid that means the cache is always invalid.
*/
#define CACHE_STALE 0
/*
** Internally, the vdbe manipulates nearly all SQL values as Mem
** structures. Each Mem struct may cache multiple representations (string,
** integer etc.) of the same value. A value (and therefore Mem structure)
** has the following properties:
**
** Each value has a manifest type. The manifest type of the value stored
** in a Mem struct is returned by the MemType(Mem*) macro. The type is
** one of SQLITE_NULL, SQLITE_INTEGER, SQLITE_REAL, SQLITE_TEXT or
** SQLITE_BLOB.
*/
struct Mem {
i64 i; /* Integer value. Or FuncDef* when flags==MEM_Agg */
double r; /* Real value */
char *z; /* String or BLOB value */
int n; /* Number of characters in string value, including '\0' */
u16 flags; /* Some combination of MEM_Null, MEM_Str, MEM_Dyn, etc. */
u8 type; /* One of MEM_Null, MEM_Str, etc. */
u8 enc; /* TEXT_Utf8, TEXT_Utf16le, or TEXT_Utf16be */
void (*xDel)(void *); /* If not null, call this function to delete Mem.z */
char zShort[NBFS]; /* Space for short strings */
};
typedef struct Mem Mem;
/* One or more of the following flags are set to indicate the validOK
** representations of the value stored in the Mem struct.
**
** If the MEM_Null flag is set, then the value is an SQL NULL value.
** No other flags may be set in this case.
**
** If the MEM_Str flag is set then Mem.z points at a string representation.
** Usually this is encoded in the same unicode encoding as the main
** database (see below for exceptions). If the MEM_Term flag is also
** set, then the string is nul terminated. The MEM_Int and MEM_Real
** flags may coexist with the MEM_Str flag.
**
** Multiple of these values can appear in Mem.flags. But only one
** at a time can appear in Mem.type.
*/
#define MEM_Null 0x0001 /* Value is NULL */
#define MEM_Str 0x0002 /* Value is a string */
#define MEM_Int 0x0004 /* Value is an integer */
#define MEM_Real 0x0008 /* Value is a real number */
#define MEM_Blob 0x0010 /* Value is a BLOB */
/* Whenever Mem contains a valid string or blob representation, one of
** the following flags must be set to determine the memory management
** policy for Mem.z. The MEM_Term flag tells us whether or not the
** string is \000 or \u0000 terminated
*/
#define MEM_Term 0x0020 /* String rep is nul terminated */
#define MEM_Dyn 0x0040 /* Need to call sqliteFree() on Mem.z */
#define MEM_Static 0x0080 /* Mem.z points to a static string */
#define MEM_Ephem 0x0100 /* Mem.z points to an ephemeral string */
#define MEM_Short 0x0200 /* Mem.z points to Mem.zShort */
#define MEM_Agg 0x0400 /* Mem.z points to an agg function context */
/* A VdbeFunc is just a FuncDef (defined in sqliteInt.h) that contains
** additional information about auxiliary information bound to arguments
** of the function. This is used to implement the sqlite3_get_auxdata()
** and sqlite3_set_auxdata() APIs. The "auxdata" is some auxiliary data
** that can be associated with a constant argument to a function. This
** allows functions such as "regexp" to compile their constant regular
** expression argument once and reused the compiled code for multiple
** invocations.
*/
struct VdbeFunc {
FuncDef *pFunc; /* The definition of the function */
int nAux; /* Number of entries allocated for apAux[] */
struct AuxData {
void *pAux; /* Aux data for the i-th argument */
void (*xDelete)(void *); /* Destructor for the aux data */
} apAux[1]; /* One slot for each function argument */
};
typedef struct VdbeFunc VdbeFunc;
/*
** The "context" argument for a installable function. A pointer to an
** instance of this structure is the first argument to the routines used
** implement the SQL functions.
**
** There is a typedef for this structure in sqlite.h. So all routines,
** even the public interface to SQLite, can use a pointer to this structure.
** But this file is the only place where the internal details of this
** structure are known.
**
** This structure is defined inside of vdbeInt.h because it uses substructures
** (Mem) which are only defined there.
*/
struct sqlite3_context {
FuncDef *pFunc; /* Pointer to function information. MUST BE FIRST */
VdbeFunc *pVdbeFunc; /* Auxilary data, if created. */
Mem s; /* The return value is stored here */
Mem *pMem; /* Memory cell used to store aggregate context */
u8 isError; /* Set to true for an error */
CollSeq *pColl; /* Collating sequence */
};
/*
** A Set structure is used for quick testing to see if a value
** is part of a small set. Sets are used to implement code like
** this:
** x.y IN ('hi','hoo','hum')
*/
typedef struct Set Set;
struct Set {
Hash hash; /* A set is just a hash table */
HashElem *prev; /* Previously accessed hash elemen */
};
/*
** A FifoPage structure holds a single page of valves. Pages are arranged
** in a list.
*/
typedef struct FifoPage FifoPage;
struct FifoPage {
int nSlot; /* Number of entries aSlot[] */
int iWrite; /* Push the next value into this entry in aSlot[] */
int iRead; /* Read the next value from this entry in aSlot[] */
FifoPage *pNext; /* Next page in the fifo */
i64 aSlot[1]; /* One or more slots for rowid values */
};
/*
** The Fifo structure is typedef-ed in vdbeInt.h. But the implementation
** of that structure is private to this file.
**
** The Fifo structure describes the entire fifo.
*/
typedef struct Fifo Fifo;
struct Fifo {
int nEntry; /* Total number of entries */
FifoPage *pFirst; /* First page on the list */
FifoPage *pLast; /* Last page on the list */
};
/*
** A Context stores the last insert rowid, the last statement change count,
** and the current statement change count (i.e. changes since last statement).
** The current keylist is also stored in the context.
** Elements of Context structure type make up the ContextStack, which is
** updated by the ContextPush and ContextPop opcodes (used by triggers).
** The context is pushed before executing a trigger a popped when the
** trigger finishes.
*/
typedef struct Context Context;
struct Context {
i64 lastRowid; /* Last insert rowid (sqlite3.lastRowid) */
int nChange; /* Statement changes (Vdbe.nChanges) */
Fifo sFifo; /* Records that will participate in a DELETE or UPDATE */
};
/*
** An instance of the virtual machine. This structure contains the complete
** state of the virtual machine.
**
** The "sqlite3_stmt" structure pointer that is returned by sqlite3_compile()
** is really a pointer to an instance of this structure.
*/
struct Vdbe {
sqlite3 *db; /* The whole database */
Vdbe *pPrev,*pNext; /* Linked list of VDBEs with the same Vdbe.db */
FILE *trace; /* Write an execution trace here, if not NULL */
int nOp; /* Number of instructions in the program */
int nOpAlloc; /* Number of slots allocated for aOp[] */
Op *aOp; /* Space to hold the virtual machine's program */
int nLabel; /* Number of labels used */
int nLabelAlloc; /* Number of slots allocated in aLabel[] */
int *aLabel; /* Space to hold the labels */
Mem *aStack; /* The operand stack, except string values */
Mem *pTos; /* Top entry in the operand stack */
Mem **apArg; /* Arguments to currently executing user function */
Mem *aColName; /* Column names to return */
int nCursor; /* Number of slots in apCsr[] */
Cursor **apCsr; /* One element of this array for each open cursor */
int nVar; /* Number of entries in aVar[] */
Mem *aVar; /* Values for the OP_Variable opcode. */
char **azVar; /* Name of variables */
int okVar; /* True if azVar[] has been initialized */
int magic; /* Magic number for sanity checking */
int nMem; /* Number of memory locations currently allocated */
Mem *aMem; /* The memory locations */
int nCallback; /* Number of callbacks invoked so far */
int cacheCtr; /* Cursor row cache generation counter */
Fifo sFifo; /* A list of ROWIDs */
int contextStackTop; /* Index of top element in the context stack */
int contextStackDepth; /* The size of the "context" stack */
Context *contextStack; /* Stack used by opcodes ContextPush & ContextPop*/
int pc; /* The program counter */
int rc; /* Value to return */
unsigned uniqueCnt; /* Used by OP_MakeRecord when P2!=0 */
int errorAction; /* Recovery action to do in case of an error */
int inTempTrans; /* True if temp database is transactioned */
int returnStack[100]; /* Return address stack for OP_Gosub & OP_Return */
int returnDepth; /* Next unused element in returnStack[] */
int nResColumn; /* Number of columns in one row of the result set */
char **azResColumn; /* Values for one row of result */
int popStack; /* Pop the stack this much on entry to VdbeExec() */
char *zErrMsg; /* Error message written here */
u8 resOnStack; /* True if there are result values on the stack */
u8 explain; /* True if EXPLAIN present on SQL command */
u8 changeCntOn; /* True to update the change-counter */
u8 aborted; /* True if ROLLBACK in another VM causes an abort */
u8 expired; /* True if the VM needs to be recompiled */
u8 minWriteFileFormat; /* Minimum file format for writable database files */
int nChange; /* Number of db changes made since last reset */
i64 startTime; /* Time when query started - used for profiling */
};
/*
** The following are allowed values for Vdbe.magic
*/
#define VDBE_MAGIC_INIT 0x26bceaa5 /* Building a VDBE program */
#define VDBE_MAGIC_RUN 0xbdf20da3 /* VDBE is ready to execute */
#define VDBE_MAGIC_HALT 0x519c2973 /* VDBE has completed execution */
#define VDBE_MAGIC_DEAD 0xb606c3c8 /* The VDBE has been deallocated */
/*
** Function prototypes
*/
void sqlite3VdbeFreeCursor(Cursor*);
void sqliteVdbePopStack(Vdbe*,int);
int sqlite3VdbeCursorMoveto(Cursor*);
#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);
int sqlite3VdbeSerialPut(unsigned char*, Mem*, int);
int sqlite3VdbeSerialGet(const unsigned char*, u32, Mem*);
void sqlite3VdbeDeleteAuxData(VdbeFunc*, int);
int sqlite2BtreeKeyCompare(BtCursor *, const void *, int, int, int *);
int sqlite3VdbeIdxKeyCompare(Cursor*, int , const unsigned char*, int*);
int sqlite3VdbeIdxRowid(BtCursor *, i64 *);
int sqlite3MemCompare(const Mem*, const Mem*, const CollSeq*);
int sqlite3VdbeRecordCompare(void*,int,const void*,int, const void*);
int sqlite3VdbeIdxRowidLen(int,const u8*);
int sqlite3VdbeExec(Vdbe*);
int sqlite3VdbeList(Vdbe*);
int sqlite3VdbeHalt(Vdbe*);
int sqlite3VdbeChangeEncoding(Mem *, int);
int sqlite3VdbeMemCopy(Mem*, const Mem*);
void sqlite3VdbeMemShallowCopy(Mem*, const Mem*, int);
int sqlite3VdbeMemMove(Mem*, Mem*);
int sqlite3VdbeMemNulTerminate(Mem*);
int sqlite3VdbeMemSetStr(Mem*, const char*, int, u8, void(*)(void*));
void sqlite3VdbeMemSetInt64(Mem*, i64);
void sqlite3VdbeMemSetDouble(Mem*, double);
void sqlite3VdbeMemSetNull(Mem*);
int sqlite3VdbeMemMakeWriteable(Mem*);
int sqlite3VdbeMemDynamicify(Mem*);
int sqlite3VdbeMemStringify(Mem*, int);
i64 sqlite3VdbeIntValue(Mem*);
int sqlite3VdbeMemIntegerify(Mem*);
double sqlite3VdbeRealValue(Mem*);
void sqlite3VdbeIntegerAffinity(Mem*);
int sqlite3VdbeMemRealify(Mem*);
int sqlite3VdbeMemNumerify(Mem*);
int sqlite3VdbeMemFromBtree(BtCursor*,int,int,int,Mem*);
void sqlite3VdbeMemRelease(Mem *p);
int sqlite3VdbeMemFinalize(Mem*, FuncDef*);
#ifndef NDEBUG
void sqlite3VdbeMemSanity(Mem*, u8);
int sqlite3VdbeOpcodeNoPush(u8);
#endif
int sqlite3VdbeMemTranslate(Mem*, u8);
void sqlite3VdbeMemPrettyPrint(Mem *pMem, char *zBuf, int nBuf);
int sqlite3VdbeMemHandleBom(Mem *pMem);
void sqlite3VdbeFifoInit(Fifo*);
int sqlite3VdbeFifoPush(Fifo*, i64);
int sqlite3VdbeFifoPop(Fifo*, i64*);
void sqlite3VdbeFifoClear(Fifo*);

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -1,907 +0,0 @@
/*
** 2004 May 26
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
**
** May you do good and not evil.
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
*************************************************************************
**
** This file contains code use to manipulate "Mem" structure. A "Mem"
** stores a single value in the VDBE. Mem is an opaque structure visible
** only within the VDBE. Interface routines refer to a Mem using the
** name sqlite_value
*/
#include "sqliteInt.h"
#include "os.h"
#include <ctype.h>
#include "vdbeInt.h"
/*
** If pMem is an object with a valid string representation, this routine
** ensures the internal encoding for the string representation is
** 'desiredEnc', one of SQLITE_UTF8, SQLITE_UTF16LE or SQLITE_UTF16BE.
**
** If pMem is not a string object, or the encoding of the string
** representation is already stored using the requested encoding, then this
** routine is a no-op.
**
** SQLITE_OK is returned if the conversion is successful (or not required).
** SQLITE_NOMEM may be returned if a malloc() fails during conversion
** between formats.
*/
int sqlite3VdbeChangeEncoding(Mem *pMem, int desiredEnc){
int rc;
if( !(pMem->flags&MEM_Str) || pMem->enc==desiredEnc ){
return SQLITE_OK;
}
#ifdef SQLITE_OMIT_UTF16
return SQLITE_ERROR;
#else
/* MemTranslate() may return SQLITE_OK or SQLITE_NOMEM. If NOMEM is returned,
** then the encoding of the value may not have changed.
*/
rc = sqlite3VdbeMemTranslate(pMem, desiredEnc);
assert(rc==SQLITE_OK || rc==SQLITE_NOMEM);
assert(rc==SQLITE_OK || pMem->enc!=desiredEnc);
assert(rc==SQLITE_NOMEM || pMem->enc==desiredEnc);
if( rc==SQLITE_NOMEM ){
/*
sqlite3VdbeMemRelease(pMem);
pMem->flags = MEM_Null;
pMem->z = 0;
*/
}
return rc;
#endif
}
/*
** Make the given Mem object MEM_Dyn.
**
** Return SQLITE_OK on success or SQLITE_NOMEM if malloc fails.
*/
int sqlite3VdbeMemDynamicify(Mem *pMem){
int n = pMem->n;
u8 *z;
if( (pMem->flags & (MEM_Ephem|MEM_Static|MEM_Short))==0 ){
return SQLITE_OK;
}
assert( (pMem->flags & MEM_Dyn)==0 );
assert( pMem->flags & (MEM_Str|MEM_Blob) );
z = sqliteMallocRaw( n+2 );
if( z==0 ){
return SQLITE_NOMEM;
}
pMem->flags |= MEM_Dyn|MEM_Term;
pMem->xDel = 0;
memcpy(z, pMem->z, n );
z[n] = 0;
z[n+1] = 0;
pMem->z = (char*)z;
pMem->flags &= ~(MEM_Ephem|MEM_Static|MEM_Short);
return SQLITE_OK;
}
/*
** Make the given Mem object either MEM_Short or MEM_Dyn so that bytes
** of the Mem.z[] array can be modified.
**
** Return SQLITE_OK on success or SQLITE_NOMEM if malloc fails.
*/
int sqlite3VdbeMemMakeWriteable(Mem *pMem){
int n;
u8 *z;
if( (pMem->flags & (MEM_Ephem|MEM_Static))==0 ){
return SQLITE_OK;
}
assert( (pMem->flags & MEM_Dyn)==0 );
assert( pMem->flags & (MEM_Str|MEM_Blob) );
if( (n = pMem->n)+2<sizeof(pMem->zShort) ){
z = (u8*)pMem->zShort;
pMem->flags |= MEM_Short|MEM_Term;
}else{
z = sqliteMallocRaw( n+2 );
if( z==0 ){
return SQLITE_NOMEM;
}
pMem->flags |= MEM_Dyn|MEM_Term;
pMem->xDel = 0;
}
memcpy(z, pMem->z, n );
z[n] = 0;
z[n+1] = 0;
pMem->z = (char*)z;
pMem->flags &= ~(MEM_Ephem|MEM_Static);
assert(0==(1&(int)pMem->z));
return SQLITE_OK;
}
/*
** Make sure the given Mem is \u0000 terminated.
*/
int sqlite3VdbeMemNulTerminate(Mem *pMem){
/* In SQLite, a string without a nul terminator occurs when a string
** is loaded from disk (in this case the memory management is ephemeral),
** or when it is supplied by the user as a bound variable or function
** return value. Therefore, the memory management of the string must be
** either ephemeral, static or controlled by a user-supplied destructor.
*/
assert(
!(pMem->flags&MEM_Str) || /* it's not a string, or */
(pMem->flags&MEM_Term) || /* it's nul term. already, or */
(pMem->flags&(MEM_Ephem|MEM_Static)) || /* it's static or ephem, or */
(pMem->flags&MEM_Dyn && pMem->xDel) /* external management */
);
if( (pMem->flags & MEM_Term)!=0 || (pMem->flags & MEM_Str)==0 ){
return SQLITE_OK; /* Nothing to do */
}
if( pMem->flags & (MEM_Static|MEM_Ephem) ){
return sqlite3VdbeMemMakeWriteable(pMem);
}else{
char *z = sqliteMalloc(pMem->n+2);
if( !z ) return SQLITE_NOMEM;
memcpy(z, pMem->z, pMem->n);
z[pMem->n] = 0;
z[pMem->n+1] = 0;
pMem->xDel(pMem->z);
pMem->xDel = 0;
pMem->z = z;
}
return SQLITE_OK;
}
/*
** Add MEM_Str to the set of representations for the given Mem. Numbers
** are converted using sqlite3_snprintf(). Converting a BLOB to a string
** is a no-op.
**
** Existing representations MEM_Int and MEM_Real are *not* invalidated.
**
** A MEM_Null value will never be passed to this function. This function is
** used for converting values to text for returning to the user (i.e. via
** sqlite3_value_text()), or for ensuring that values to be used as btree
** keys are strings. In the former case a NULL pointer is returned the
** user and the later is an internal programming error.
*/
int sqlite3VdbeMemStringify(Mem *pMem, int enc){
int rc = SQLITE_OK;
int fg = pMem->flags;
char *z = pMem->zShort;
assert( !(fg&(MEM_Str|MEM_Blob)) );
assert( fg&(MEM_Int|MEM_Real) );
/* For a Real or Integer, use sqlite3_snprintf() to produce the UTF-8
** string representation of the value. Then, if the required encoding
** is UTF-16le or UTF-16be do a translation.
**
** FIX ME: It would be better if sqlite3_snprintf() could do UTF-16.
*/
if( fg & MEM_Int ){
sqlite3_snprintf(NBFS, z, "%lld", pMem->i);
}else{
assert( fg & MEM_Real );
sqlite3_snprintf(NBFS, z, "%!.15g", pMem->r);
}
pMem->n = strlen(z);
pMem->z = z;
pMem->enc = SQLITE_UTF8;
pMem->flags |= MEM_Str | MEM_Short | MEM_Term;
sqlite3VdbeChangeEncoding(pMem, enc);
return rc;
}
/*
** Memory cell pMem contains the context of an aggregate function.
** This routine calls the finalize method for that function. The
** result of the aggregate is stored back into pMem.
**
** Return SQLITE_ERROR if the finalizer reports an error. SQLITE_OK
** otherwise.
*/
int sqlite3VdbeMemFinalize(Mem *pMem, FuncDef *pFunc){
int rc = SQLITE_OK;
if( pFunc && pFunc->xFinalize ){
sqlite3_context ctx;
assert( (pMem->flags & MEM_Null)!=0 || pFunc==*(FuncDef**)&pMem->i );
ctx.s.flags = MEM_Null;
ctx.s.z = pMem->zShort;
ctx.pMem = pMem;
ctx.pFunc = pFunc;
ctx.isError = 0;
pFunc->xFinalize(&ctx);
if( pMem->z && pMem->z!=pMem->zShort ){
sqliteFree( pMem->z );
}
*pMem = ctx.s;
if( pMem->flags & MEM_Short ){
pMem->z = pMem->zShort;
}
if( ctx.isError ){
rc = SQLITE_ERROR;
}
}
return rc;
}
/*
** Release any memory held by the Mem. This may leave the Mem in an
** inconsistent state, for example with (Mem.z==0) and
** (Mem.type==SQLITE_TEXT).
*/
void sqlite3VdbeMemRelease(Mem *p){
if( p->flags & (MEM_Dyn|MEM_Agg) ){
if( p->xDel ){
if( p->flags & MEM_Agg ){
sqlite3VdbeMemFinalize(p, *(FuncDef**)&p->i);
assert( (p->flags & MEM_Agg)==0 );
sqlite3VdbeMemRelease(p);
}else{
p->xDel((void *)p->z);
}
}else{
sqliteFree(p->z);
}
p->z = 0;
p->xDel = 0;
}
}
/*
** Return some kind of integer value which is the best we can do
** at representing the value that *pMem describes as an integer.
** If pMem is an integer, then the value is exact. If pMem is
** a floating-point then the value returned is the integer part.
** If pMem is a string or blob, then we make an attempt to convert
** it into a integer and return that. If pMem is NULL, return 0.
**
** If pMem is a string, its encoding might be changed.
*/
i64 sqlite3VdbeIntValue(Mem *pMem){
int flags = pMem->flags;
if( flags & MEM_Int ){
return pMem->i;
}else if( flags & MEM_Real ){
return (i64)pMem->r;
}else if( flags & (MEM_Str|MEM_Blob) ){
i64 value;
if( sqlite3VdbeChangeEncoding(pMem, SQLITE_UTF8)
|| sqlite3VdbeMemNulTerminate(pMem) ){
return 0;
}
assert( pMem->z );
sqlite3atoi64(pMem->z, &value);
return value;
}else{
return 0;
}
}
/*
** Return the best representation of pMem that we can get into a
** double. If pMem is already a double or an integer, return its
** value. If it is a string or blob, try to convert it to a double.
** If it is a NULL, return 0.0.
*/
double sqlite3VdbeRealValue(Mem *pMem){
if( pMem->flags & MEM_Real ){
return pMem->r;
}else if( pMem->flags & MEM_Int ){
return (double)pMem->i;
}else if( pMem->flags & (MEM_Str|MEM_Blob) ){
double val = 0.0;
if( sqlite3VdbeChangeEncoding(pMem, SQLITE_UTF8)
|| sqlite3VdbeMemNulTerminate(pMem) ){
return 0.0;
}
assert( pMem->z );
sqlite3AtoF(pMem->z, &val);
return val;
}else{
return 0.0;
}
}
/*
** The MEM structure is already a MEM_Real. Try to also make it a
** MEM_Int if we can.
*/
void sqlite3VdbeIntegerAffinity(Mem *pMem){
assert( pMem->flags & MEM_Real );
pMem->i = pMem->r;
if( ((double)pMem->i)==pMem->r ){
pMem->flags |= MEM_Int;
}
}
/*
** Convert pMem to type integer. Invalidate any prior representations.
*/
int sqlite3VdbeMemIntegerify(Mem *pMem){
pMem->i = sqlite3VdbeIntValue(pMem);
sqlite3VdbeMemRelease(pMem);
pMem->flags = MEM_Int;
return SQLITE_OK;
}
/*
** Convert pMem so that it is of type MEM_Real.
** Invalidate any prior representations.
*/
int sqlite3VdbeMemRealify(Mem *pMem){
pMem->r = sqlite3VdbeRealValue(pMem);
sqlite3VdbeMemRelease(pMem);
pMem->flags = MEM_Real;
return SQLITE_OK;
}
/*
** Convert pMem so that it has types MEM_Real or MEM_Int or both.
** Invalidate any prior representations.
*/
int sqlite3VdbeMemNumerify(Mem *pMem){
sqlite3VdbeMemRealify(pMem);
sqlite3VdbeIntegerAffinity(pMem);
return SQLITE_OK;
}
/*
** Delete any previous value and set the value stored in *pMem to NULL.
*/
void sqlite3VdbeMemSetNull(Mem *pMem){
sqlite3VdbeMemRelease(pMem);
pMem->flags = MEM_Null;
pMem->type = SQLITE_NULL;
pMem->n = 0;
}
/*
** Delete any previous value and set the value stored in *pMem to val,
** manifest type INTEGER.
*/
void sqlite3VdbeMemSetInt64(Mem *pMem, i64 val){
sqlite3VdbeMemRelease(pMem);
pMem->i = val;
pMem->flags = MEM_Int;
pMem->type = SQLITE_INTEGER;
}
/*
** Delete any previous value and set the value stored in *pMem to val,
** manifest type REAL.
*/
void sqlite3VdbeMemSetDouble(Mem *pMem, double val){
sqlite3VdbeMemRelease(pMem);
pMem->r = val;
pMem->flags = MEM_Real;
pMem->type = SQLITE_FLOAT;
}
/*
** Make an shallow copy of pFrom into pTo. Prior contents of
** pTo are overwritten. The pFrom->z field is not duplicated. If
** pFrom->z is used, then pTo->z points to the same thing as pFrom->z
** and flags gets srcType (either MEM_Ephem or MEM_Static).
*/
void sqlite3VdbeMemShallowCopy(Mem *pTo, const Mem *pFrom, int srcType){
memcpy(pTo, pFrom, sizeof(*pFrom)-sizeof(pFrom->zShort));
pTo->xDel = 0;
if( pTo->flags & (MEM_Str|MEM_Blob) ){
pTo->flags &= ~(MEM_Dyn|MEM_Static|MEM_Short|MEM_Ephem);
assert( srcType==MEM_Ephem || srcType==MEM_Static );
pTo->flags |= srcType;
}
}
/*
** Make a full copy of pFrom into pTo. Prior contents of pTo are
** freed before the copy is made.
*/
int sqlite3VdbeMemCopy(Mem *pTo, const Mem *pFrom){
int rc;
if( pTo->flags & MEM_Dyn ){
sqlite3VdbeMemRelease(pTo);
}
sqlite3VdbeMemShallowCopy(pTo, pFrom, MEM_Ephem);
if( pTo->flags & MEM_Ephem ){
rc = sqlite3VdbeMemMakeWriteable(pTo);
}else{
rc = SQLITE_OK;
}
return rc;
}
/*
** Transfer the contents of pFrom to pTo. Any existing value in pTo is
** freed. If pFrom contains ephemeral data, a copy is made.
**
** pFrom contains an SQL NULL when this routine returns. SQLITE_NOMEM
** might be returned if pFrom held ephemeral data and we were unable
** to allocate enough space to make a copy.
*/
int sqlite3VdbeMemMove(Mem *pTo, Mem *pFrom){
int rc;
if( pTo->flags & MEM_Dyn ){
sqlite3VdbeMemRelease(pTo);
}
memcpy(pTo, pFrom, sizeof(Mem));
if( pFrom->flags & MEM_Short ){
pTo->z = pTo->zShort;
}
pFrom->flags = MEM_Null;
pFrom->xDel = 0;
if( pTo->flags & MEM_Ephem ){
rc = sqlite3VdbeMemMakeWriteable(pTo);
}else{
rc = SQLITE_OK;
}
return rc;
}
/*
** Change the value of a Mem to be a string or a BLOB.
*/
int sqlite3VdbeMemSetStr(
Mem *pMem, /* Memory cell to set to string value */
const char *z, /* String pointer */
int n, /* Bytes in string, or negative */
u8 enc, /* Encoding of z. 0 for BLOBs */
void (*xDel)(void*) /* Destructor function */
){
sqlite3VdbeMemRelease(pMem);
if( !z ){
pMem->flags = MEM_Null;
pMem->type = SQLITE_NULL;
return SQLITE_OK;
}
pMem->z = (char *)z;
if( xDel==SQLITE_STATIC ){
pMem->flags = MEM_Static;
}else if( xDel==SQLITE_TRANSIENT ){
pMem->flags = MEM_Ephem;
}else{
pMem->flags = MEM_Dyn;
pMem->xDel = xDel;
}
pMem->enc = enc;
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;
pMem->enc = SQLITE_UTF8;
break;
case SQLITE_UTF8:
pMem->flags |= MEM_Str;
if( n<0 ){
pMem->n = strlen(z);
pMem->flags |= MEM_Term;
}
break;
#ifndef SQLITE_OMIT_UTF16
case SQLITE_UTF16LE:
case SQLITE_UTF16BE:
pMem->flags |= MEM_Str;
if( pMem->n<0 ){
pMem->n = sqlite3utf16ByteLen(pMem->z,-1);
pMem->flags |= MEM_Term;
}
if( sqlite3VdbeMemHandleBom(pMem) ){
return SQLITE_NOMEM;
}
#endif /* SQLITE_OMIT_UTF16 */
}
if( pMem->flags&MEM_Ephem ){
return sqlite3VdbeMemMakeWriteable(pMem);
}
return SQLITE_OK;
}
/*
** Compare the values contained by the two memory cells, returning
** negative, zero or positive if pMem1 is less than, equal to, or greater
** than pMem2. Sorting order is NULL's first, followed by numbers (integers
** and reals) sorted numerically, followed by text ordered by the collating
** sequence pColl and finally blob's ordered by memcmp().
**
** Two NULL values are considered equal by this function.
*/
int sqlite3MemCompare(const Mem *pMem1, const Mem *pMem2, const CollSeq *pColl){
int rc;
int f1, f2;
int combined_flags;
/* Interchange pMem1 and pMem2 if the collating sequence specifies
** DESC order.
*/
f1 = pMem1->flags;
f2 = pMem2->flags;
combined_flags = f1|f2;
/* If one value is NULL, it is less than the other. If both values
** are NULL, return 0.
*/
if( combined_flags&MEM_Null ){
return (f2&MEM_Null) - (f1&MEM_Null);
}
/* If one value is a number and the other is not, the number is less.
** If both are numbers, compare as reals if one is a real, or as integers
** if both values are integers.
*/
if( combined_flags&(MEM_Int|MEM_Real) ){
if( !(f1&(MEM_Int|MEM_Real)) ){
return 1;
}
if( !(f2&(MEM_Int|MEM_Real)) ){
return -1;
}
if( (f1 & f2 & MEM_Int)==0 ){
double r1, r2;
if( (f1&MEM_Real)==0 ){
r1 = pMem1->i;
}else{
r1 = pMem1->r;
}
if( (f2&MEM_Real)==0 ){
r2 = pMem2->i;
}else{
r2 = pMem2->r;
}
if( r1<r2 ) return -1;
if( r1>r2 ) return 1;
return 0;
}else{
assert( f1&MEM_Int );
assert( f2&MEM_Int );
if( pMem1->i < pMem2->i ) return -1;
if( pMem1->i > pMem2->i ) return 1;
return 0;
}
}
/* If one value is a string and the other is a blob, the string is less.
** If both are strings, compare using the collating functions.
*/
if( combined_flags&MEM_Str ){
if( (f1 & MEM_Str)==0 ){
return 1;
}
if( (f2 & MEM_Str)==0 ){
return -1;
}
assert( pMem1->enc==pMem2->enc );
assert( pMem1->enc==SQLITE_UTF8 ||
pMem1->enc==SQLITE_UTF16LE || pMem1->enc==SQLITE_UTF16BE );
/* The collation sequence must be defined at this point, even if
** the user deletes the collation sequence after the vdbe program is
** compiled (this was not always the case).
*/
assert( !pColl || pColl->xCmp );
if( pColl ){
if( pMem1->enc==pColl->enc ){
/* The strings are already in the correct encoding. Call the
** comparison function directly */
return pColl->xCmp(pColl->pUser,pMem1->n,pMem1->z,pMem2->n,pMem2->z);
}else{
u8 origEnc = pMem1->enc;
const void *v1, *v2;
int n1, n2;
/* Convert the strings into the encoding that the comparison
** function expects */
v1 = sqlite3ValueText((sqlite3_value*)pMem1, pColl->enc);
n1 = v1==0 ? 0 : pMem1->n;
assert( n1==sqlite3ValueBytes((sqlite3_value*)pMem1, pColl->enc) );
v2 = sqlite3ValueText((sqlite3_value*)pMem2, pColl->enc);
n2 = v2==0 ? 0 : pMem2->n;
assert( n2==sqlite3ValueBytes((sqlite3_value*)pMem2, pColl->enc) );
/* Do the comparison */
rc = pColl->xCmp(pColl->pUser, n1, v1, n2, v2);
/* Convert the strings back into the database encoding */
sqlite3ValueText((sqlite3_value*)pMem1, origEnc);
sqlite3ValueText((sqlite3_value*)pMem2, origEnc);
return rc;
}
}
/* If a NULL pointer was passed as the collate function, fall through
** to the blob case and use memcmp(). */
}
/* Both values must be blobs. Compare using memcmp(). */
rc = memcmp(pMem1->z, pMem2->z, (pMem1->n>pMem2->n)?pMem2->n:pMem1->n);
if( rc==0 ){
rc = pMem1->n - pMem2->n;
}
return rc;
}
/*
** Move data out of a btree key or data field and into a Mem structure.
** The data or key is taken from the entry that pCur is currently pointing
** to. offset and amt determine what portion of the data or key to retrieve.
** key is true to get the key or false to get data. The result is written
** into the pMem element.
**
** The pMem structure is assumed to be uninitialized. Any prior content
** is overwritten without being freed.
**
** If this routine fails for any reason (malloc returns NULL or unable
** to read from the disk) then the pMem is left in an inconsistent state.
*/
int sqlite3VdbeMemFromBtree(
BtCursor *pCur, /* Cursor pointing at record to retrieve. */
int offset, /* Offset from the start of data to return bytes from. */
int amt, /* Number of bytes to return. */
int key, /* If true, retrieve from the btree key, not data. */
Mem *pMem /* OUT: Return data in this Mem structure. */
){
char *zData; /* Data from the btree layer */
int available; /* Number of bytes available on the local btree page */
if( key ){
zData = (char *)sqlite3BtreeKeyFetch(pCur, &available);
}else{
zData = (char *)sqlite3BtreeDataFetch(pCur, &available);
}
pMem->n = amt;
if( offset+amt<=available ){
pMem->z = &zData[offset];
pMem->flags = MEM_Blob|MEM_Ephem;
}else{
int rc;
if( amt>NBFS-2 ){
zData = (char *)sqliteMallocRaw(amt+2);
if( !zData ){
return SQLITE_NOMEM;
}
pMem->flags = MEM_Blob|MEM_Dyn|MEM_Term;
pMem->xDel = 0;
}else{
zData = &(pMem->zShort[0]);
pMem->flags = MEM_Blob|MEM_Short|MEM_Term;
}
pMem->z = zData;
pMem->enc = 0;
pMem->type = SQLITE_BLOB;
if( key ){
rc = sqlite3BtreeKey(pCur, offset, amt, zData);
}else{
rc = sqlite3BtreeData(pCur, offset, amt, zData);
}
zData[amt] = 0;
zData[amt+1] = 0;
if( rc!=SQLITE_OK ){
if( amt>NBFS-2 ){
assert( zData!=pMem->zShort );
assert( pMem->flags & MEM_Dyn );
sqliteFree(zData);
} else {
assert( zData==pMem->zShort );
assert( pMem->flags & MEM_Short );
}
return rc;
}
}
return SQLITE_OK;
}
#ifndef NDEBUG
/*
** Perform various checks on the memory cell pMem. An assert() will
** fail if pMem is internally inconsistent.
*/
void sqlite3VdbeMemSanity(Mem *pMem, u8 db_enc){
int flags = pMem->flags;
assert( flags!=0 ); /* Must define some type */
if( pMem->flags & (MEM_Str|MEM_Blob) ){
int x = pMem->flags & (MEM_Static|MEM_Dyn|MEM_Ephem|MEM_Short);
assert( x!=0 ); /* Strings must define a string subtype */
assert( (x & (x-1))==0 ); /* Only one string subtype can be defined */
assert( pMem->z!=0 ); /* Strings must have a value */
/* Mem.z points to Mem.zShort iff the subtype is MEM_Short */
assert( (pMem->flags & MEM_Short)==0 || pMem->z==pMem->zShort );
assert( (pMem->flags & MEM_Short)!=0 || pMem->z!=pMem->zShort );
/* No destructor unless there is MEM_Dyn */
assert( pMem->xDel==0 || (pMem->flags & MEM_Dyn)!=0 );
if( (flags & MEM_Str) ){
assert( pMem->enc==SQLITE_UTF8 ||
pMem->enc==SQLITE_UTF16BE ||
pMem->enc==SQLITE_UTF16LE
);
/* If the string is UTF-8 encoded and nul terminated, then pMem->n
** must be the length of the string. (Later:) If the database file
** has been corrupted, '\000' characters might have been inserted
** into the middle of the string. In that case, the strlen() might
** be less.
*/
if( pMem->enc==SQLITE_UTF8 && (flags & MEM_Term) ){
assert( strlen(pMem->z)<=pMem->n );
assert( pMem->z[pMem->n]==0 );
}
}
}else{
/* Cannot define a string subtype for non-string objects */
assert( (pMem->flags & (MEM_Static|MEM_Dyn|MEM_Ephem|MEM_Short))==0 );
assert( pMem->xDel==0 );
}
/* MEM_Null excludes all other types */
assert( (pMem->flags&(MEM_Str|MEM_Int|MEM_Real|MEM_Blob))==0
|| (pMem->flags&MEM_Null)==0 );
/* If the MEM is both real and integer, the values are equal */
assert( (pMem->flags & (MEM_Int|MEM_Real))!=(MEM_Int|MEM_Real)
|| pMem->r==pMem->i );
}
#endif
/* This function is only available internally, it is not part of the
** external API. It works in a similar way to sqlite3_value_text(),
** except the data returned is in the encoding specified by the second
** parameter, which must be one of SQLITE_UTF16BE, SQLITE_UTF16LE or
** SQLITE_UTF8.
**
** (2006-02-16:) The enc value can be or-ed with SQLITE_UTF16_ALIGNED.
** If that is the case, then the result must be aligned on an even byte
** boundary.
*/
const void *sqlite3ValueText(sqlite3_value* pVal, u8 enc){
if( !pVal ) return 0;
assert( (enc&3)==(enc&~SQLITE_UTF16_ALIGNED) );
if( pVal->flags&MEM_Null ){
return 0;
}
assert( (MEM_Blob>>3) == MEM_Str );
pVal->flags |= (pVal->flags & MEM_Blob)>>3;
if( pVal->flags&MEM_Str ){
sqlite3VdbeChangeEncoding(pVal, enc & ~SQLITE_UTF16_ALIGNED);
if( (enc & SQLITE_UTF16_ALIGNED)!=0 && 1==(1&(int)pVal->z) ){
assert( (pVal->flags & (MEM_Ephem|MEM_Static))!=0 );
if( sqlite3VdbeMemMakeWriteable(pVal)!=SQLITE_OK ){
return 0;
}
}
}else if( !(pVal->flags&MEM_Blob) ){
sqlite3VdbeMemStringify(pVal, enc);
assert( 0==(1&(int)pVal->z) );
}
assert(pVal->enc==(enc & ~SQLITE_UTF16_ALIGNED) || sqlite3MallocFailed() );
if( pVal->enc==(enc & ~SQLITE_UTF16_ALIGNED) ){
return pVal->z;
}else{
return 0;
}
}
/*
** Create a new sqlite3_value object.
*/
sqlite3_value* sqlite3ValueNew(void){
Mem *p = sqliteMalloc(sizeof(*p));
if( p ){
p->flags = MEM_Null;
p->type = SQLITE_NULL;
}
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((char*)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((char*)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
*/
void sqlite3ValueSetStr(
sqlite3_value *v,
int n,
const void *z,
u8 enc,
void (*xDel)(void*)
){
if( v ) sqlite3VdbeMemSetStr((Mem *)v, z, n, enc, xDel);
}
/*
** Free an sqlite3_value object
*/
void sqlite3ValueFree(sqlite3_value *v){
if( !v ) return;
sqlite3ValueSetStr(v, 0, 0, SQLITE_UTF8, SQLITE_STATIC);
sqliteFree(v);
}
/*
** Return the number of bytes in the sqlite3_value object assuming
** that it uses the encoding "enc"
*/
int sqlite3ValueBytes(sqlite3_value *pVal, u8 enc){
Mem *p = (Mem*)pVal;
if( (p->flags & MEM_Blob)!=0 || sqlite3ValueText(pVal, enc) ){
return p->n;
}
return 0;
}

Разница между файлами не показана из-за своего большого размера Загрузить разницу