ggiunto sqlite
git-svn-id: svn://10.65.10.50/trunk@11835 c028cbd2-c16b-5b4b-a496-9718f37d4682
This commit is contained in:
parent
454abe3b5b
commit
ed9d03ee76
308
sqlite/attach.c
Executable file
308
sqlite/attach.c
Executable file
@ -0,0 +1,308 @@
|
||||
/*
|
||||
** 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.1.1.1 2004-03-11 22:22:22 alex Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
|
||||
/*
|
||||
** This routine is called by the parser to process an ATTACH statement:
|
||||
**
|
||||
** ATTACH DATABASE filename AS dbname
|
||||
**
|
||||
** The pFilename and pDbname arguments are the tokens that define the
|
||||
** filename and dbname in the ATTACH statement.
|
||||
*/
|
||||
void sqliteAttach(Parse *pParse, Token *pFilename, Token *pDbname, Token *pKey){
|
||||
Db *aNew;
|
||||
int rc, i;
|
||||
char *zFile, *zName;
|
||||
sqlite *db;
|
||||
Vdbe *v;
|
||||
|
||||
v = sqliteGetVdbe(pParse);
|
||||
sqliteVdbeAddOp(v, OP_Halt, 0, 0);
|
||||
if( pParse->explain ) return;
|
||||
db = pParse->db;
|
||||
if( db->file_format<4 ){
|
||||
sqliteErrorMsg(pParse, "cannot attach auxiliary databases to an "
|
||||
"older format master database", 0);
|
||||
pParse->rc = SQLITE_ERROR;
|
||||
return;
|
||||
}
|
||||
if( db->nDb>=MAX_ATTACHED+2 ){
|
||||
sqliteErrorMsg(pParse, "too many attached databases - max %d",
|
||||
MAX_ATTACHED);
|
||||
pParse->rc = SQLITE_ERROR;
|
||||
return;
|
||||
}
|
||||
|
||||
zFile = 0;
|
||||
sqliteSetNString(&zFile, pFilename->z, pFilename->n, 0);
|
||||
if( zFile==0 ) return;
|
||||
sqliteDequote(zFile);
|
||||
#ifndef SQLITE_OMIT_AUTHORIZATION
|
||||
if( sqliteAuthCheck(pParse, SQLITE_ATTACH, zFile, 0, 0)!=SQLITE_OK ){
|
||||
sqliteFree(zFile);
|
||||
return;
|
||||
}
|
||||
#endif /* SQLITE_OMIT_AUTHORIZATION */
|
||||
|
||||
zName = 0;
|
||||
sqliteSetNString(&zName, pDbname->z, pDbname->n, 0);
|
||||
if( zName==0 ) return;
|
||||
sqliteDequote(zName);
|
||||
for(i=0; i<db->nDb; i++){
|
||||
if( db->aDb[i].zName && sqliteStrICmp(db->aDb[i].zName, zName)==0 ){
|
||||
sqliteErrorMsg(pParse, "database %z is already in use", zName);
|
||||
pParse->rc = SQLITE_ERROR;
|
||||
sqliteFree(zFile);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
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));
|
||||
sqliteHashInit(&aNew->tblHash, SQLITE_HASH_STRING, 0);
|
||||
sqliteHashInit(&aNew->idxHash, SQLITE_HASH_STRING, 0);
|
||||
sqliteHashInit(&aNew->trigHash, SQLITE_HASH_STRING, 0);
|
||||
sqliteHashInit(&aNew->aFKey, SQLITE_HASH_STRING, 1);
|
||||
aNew->zName = zName;
|
||||
rc = sqliteBtreeFactory(db, zFile, 0, MAX_PAGES, &aNew->pBt);
|
||||
if( rc ){
|
||||
sqliteErrorMsg(pParse, "unable to open database: %s", zFile);
|
||||
}
|
||||
#if SQLITE_HAS_CODEC
|
||||
{
|
||||
extern int sqliteCodecAttach(sqlite*, int, void*, int);
|
||||
char *zKey = 0;
|
||||
int nKey;
|
||||
if( pKey && pKey->z && pKey->n ){
|
||||
sqliteSetNString(&zKey, pKey->z, pKey->n, 0);
|
||||
sqliteDequote(zKey);
|
||||
nKey = strlen(zKey);
|
||||
}else{
|
||||
zKey = 0;
|
||||
nKey = 0;
|
||||
}
|
||||
sqliteCodecAttach(db, db->nDb-1, zKey, nKey);
|
||||
}
|
||||
#endif
|
||||
sqliteFree(zFile);
|
||||
db->flags &= ~SQLITE_Initialized;
|
||||
if( pParse->nErr ) return;
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqliteInit(pParse->db, &pParse->zErrMsg);
|
||||
}
|
||||
if( rc ){
|
||||
int i = db->nDb - 1;
|
||||
assert( i>=2 );
|
||||
if( db->aDb[i].pBt ){
|
||||
sqliteBtreeClose(db->aDb[i].pBt);
|
||||
db->aDb[i].pBt = 0;
|
||||
}
|
||||
sqliteResetInternalSchema(db, 0);
|
||||
pParse->nErr++;
|
||||
pParse->rc = SQLITE_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** This routine is called by the parser to process a DETACH statement:
|
||||
**
|
||||
** DETACH DATABASE dbname
|
||||
**
|
||||
** The pDbname argument is the name of the database in the DETACH statement.
|
||||
*/
|
||||
void sqliteDetach(Parse *pParse, Token *pDbname){
|
||||
int i;
|
||||
sqlite *db;
|
||||
Vdbe *v;
|
||||
|
||||
v = sqliteGetVdbe(pParse);
|
||||
sqliteVdbeAddOp(v, OP_Halt, 0, 0);
|
||||
if( pParse->explain ) return;
|
||||
db = pParse->db;
|
||||
for(i=0; i<db->nDb; i++){
|
||||
if( db->aDb[i].pBt==0 || db->aDb[i].zName==0 ) continue;
|
||||
if( strlen(db->aDb[i].zName)!=pDbname->n ) continue;
|
||||
if( sqliteStrNICmp(db->aDb[i].zName, pDbname->z, pDbname->n)==0 ) break;
|
||||
}
|
||||
if( i>=db->nDb ){
|
||||
sqliteErrorMsg(pParse, "no such database: %T", pDbname);
|
||||
return;
|
||||
}
|
||||
if( i<2 ){
|
||||
sqliteErrorMsg(pParse, "cannot detach database %T", pDbname);
|
||||
return;
|
||||
}
|
||||
#ifndef SQLITE_OMIT_AUTHORIZATION
|
||||
if( sqliteAuthCheck(pParse,SQLITE_DETACH,db->aDb[i].zName,0,0)!=SQLITE_OK ){
|
||||
return;
|
||||
}
|
||||
#endif /* SQLITE_OMIT_AUTHORIZATION */
|
||||
sqliteBtreeClose(db->aDb[i].pBt);
|
||||
db->aDb[i].pBt = 0;
|
||||
sqliteFree(db->aDb[i].zName);
|
||||
sqliteResetInternalSchema(db, i);
|
||||
db->nDb--;
|
||||
if( i<db->nDb ){
|
||||
db->aDb[i] = db->aDb[db->nDb];
|
||||
memset(&db->aDb[db->nDb], 0, sizeof(db->aDb[0]));
|
||||
sqliteResetInternalSchema(db, i);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** 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 sqliteFixInit(
|
||||
DbFixer *pFix, /* The fixer to be initialized */
|
||||
Parse *pParse, /* Error messages will be written here */
|
||||
int iDb, /* This is the database that must must be used */
|
||||
const char *zType, /* "view", "trigger", or "index" */
|
||||
const Token *pName /* Name of the view, trigger, or index */
|
||||
){
|
||||
sqlite *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 sqliteFixInit().
|
||||
**
|
||||
** 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 sqliteFixSrcList(
|
||||
DbFixer *pFix, /* Context of the fixation */
|
||||
SrcList *pList /* The Source list to check and modify */
|
||||
){
|
||||
int i;
|
||||
const char *zDb;
|
||||
|
||||
if( pList==0 ) return 0;
|
||||
zDb = pFix->zDb;
|
||||
for(i=0; i<pList->nSrc; i++){
|
||||
if( pList->a[i].zDatabase==0 ){
|
||||
pList->a[i].zDatabase = sqliteStrDup(zDb);
|
||||
}else if( sqliteStrICmp(pList->a[i].zDatabase,zDb)!=0 ){
|
||||
sqliteErrorMsg(pFix->pParse,
|
||||
"%s %z cannot reference objects in database %s",
|
||||
pFix->zType, sqliteStrNDup(pFix->pName->z, pFix->pName->n),
|
||||
pList->a[i].zDatabase);
|
||||
return 1;
|
||||
}
|
||||
if( sqliteFixSelect(pFix, pList->a[i].pSelect) ) return 1;
|
||||
if( sqliteFixExpr(pFix, pList->a[i].pOn) ) return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
int sqliteFixSelect(
|
||||
DbFixer *pFix, /* Context of the fixation */
|
||||
Select *pSelect /* The SELECT statement to be fixed to one database */
|
||||
){
|
||||
while( pSelect ){
|
||||
if( sqliteFixExprList(pFix, pSelect->pEList) ){
|
||||
return 1;
|
||||
}
|
||||
if( sqliteFixSrcList(pFix, pSelect->pSrc) ){
|
||||
return 1;
|
||||
}
|
||||
if( sqliteFixExpr(pFix, pSelect->pWhere) ){
|
||||
return 1;
|
||||
}
|
||||
if( sqliteFixExpr(pFix, pSelect->pHaving) ){
|
||||
return 1;
|
||||
}
|
||||
pSelect = pSelect->pPrior;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
int sqliteFixExpr(
|
||||
DbFixer *pFix, /* Context of the fixation */
|
||||
Expr *pExpr /* The expression to be fixed to one database */
|
||||
){
|
||||
while( pExpr ){
|
||||
if( sqliteFixSelect(pFix, pExpr->pSelect) ){
|
||||
return 1;
|
||||
}
|
||||
if( sqliteFixExprList(pFix, pExpr->pList) ){
|
||||
return 1;
|
||||
}
|
||||
if( sqliteFixExpr(pFix, pExpr->pRight) ){
|
||||
return 1;
|
||||
}
|
||||
pExpr = pExpr->pLeft;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
int sqliteFixExprList(
|
||||
DbFixer *pFix, /* Context of the fixation */
|
||||
ExprList *pList /* The expression to be fixed to one database */
|
||||
){
|
||||
int i;
|
||||
if( pList==0 ) return 0;
|
||||
for(i=0; i<pList->nExpr; i++){
|
||||
if( sqliteFixExpr(pFix, pList->a[i].pExpr) ){
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
int sqliteFixTriggerStep(
|
||||
DbFixer *pFix, /* Context of the fixation */
|
||||
TriggerStep *pStep /* The trigger step be fixed to one database */
|
||||
){
|
||||
while( pStep ){
|
||||
if( sqliteFixSelect(pFix, pStep->pSelect) ){
|
||||
return 1;
|
||||
}
|
||||
if( sqliteFixExpr(pFix, pStep->pWhere) ){
|
||||
return 1;
|
||||
}
|
||||
if( sqliteFixExprList(pFix, pStep->pExprList) ){
|
||||
return 1;
|
||||
}
|
||||
pStep = pStep->pNext;
|
||||
}
|
||||
return 0;
|
||||
}
|
219
sqlite/auth.c
Executable file
219
sqlite/auth.c
Executable file
@ -0,0 +1,219 @@
|
||||
/*
|
||||
** 2003 January 11
|
||||
**
|
||||
** The author disclaims copyright to this source code. In place of
|
||||
** a legal notice, here is a blessing:
|
||||
**
|
||||
** May you do good and not evil.
|
||||
** May you find forgiveness for yourself and forgive others.
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
*************************************************************************
|
||||
** This file contains code used to implement the sqlite_set_authorizer()
|
||||
** API. This facility is an optional feature of the library. Embedded
|
||||
** systems that do not need this facility may omit it by recompiling
|
||||
** the library with -DSQLITE_OMIT_AUTHORIZATION=1
|
||||
**
|
||||
** $Id: auth.c,v 1.1.1.1 2004-03-11 22:22:23 alex Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
|
||||
/*
|
||||
** All of the code in this file may be omitted by defining a single
|
||||
** macro.
|
||||
*/
|
||||
#ifndef SQLITE_OMIT_AUTHORIZATION
|
||||
|
||||
/*
|
||||
** Set or clear the access authorization function.
|
||||
**
|
||||
** The access authorization function is be called during the compilation
|
||||
** phase to verify that the user has read and/or write access permission on
|
||||
** various fields of the database. The first argument to the auth function
|
||||
** is a copy of the 3rd argument to this routine. The second argument
|
||||
** to the auth function is one of these constants:
|
||||
**
|
||||
** SQLITE_COPY
|
||||
** SQLITE_CREATE_INDEX
|
||||
** SQLITE_CREATE_TABLE
|
||||
** SQLITE_CREATE_TEMP_INDEX
|
||||
** SQLITE_CREATE_TEMP_TABLE
|
||||
** SQLITE_CREATE_TEMP_TRIGGER
|
||||
** SQLITE_CREATE_TEMP_VIEW
|
||||
** SQLITE_CREATE_TRIGGER
|
||||
** SQLITE_CREATE_VIEW
|
||||
** SQLITE_DELETE
|
||||
** SQLITE_DROP_INDEX
|
||||
** SQLITE_DROP_TABLE
|
||||
** SQLITE_DROP_TEMP_INDEX
|
||||
** SQLITE_DROP_TEMP_TABLE
|
||||
** SQLITE_DROP_TEMP_TRIGGER
|
||||
** SQLITE_DROP_TEMP_VIEW
|
||||
** SQLITE_DROP_TRIGGER
|
||||
** SQLITE_DROP_VIEW
|
||||
** SQLITE_INSERT
|
||||
** SQLITE_PRAGMA
|
||||
** SQLITE_READ
|
||||
** SQLITE_SELECT
|
||||
** SQLITE_TRANSACTION
|
||||
** SQLITE_UPDATE
|
||||
**
|
||||
** The third and fourth arguments to the auth function are the name of
|
||||
** the table and the column that are being accessed. The auth function
|
||||
** should return either SQLITE_OK, SQLITE_DENY, or SQLITE_IGNORE. If
|
||||
** SQLITE_OK is returned, it means that access is allowed. SQLITE_DENY
|
||||
** means that the SQL statement will never-run - the sqlite_exec() call
|
||||
** will return with an error. SQLITE_IGNORE means that the SQL statement
|
||||
** should run but attempts to read the specified column will return NULL
|
||||
** and attempts to write the column will be ignored.
|
||||
**
|
||||
** Setting the auth function to NULL disables this hook. The default
|
||||
** setting of the auth function is NULL.
|
||||
*/
|
||||
int sqlite_set_authorizer(
|
||||
sqlite *db,
|
||||
int (*xAuth)(void*,int,const char*,const char*,const char*,const char*),
|
||||
void *pArg
|
||||
){
|
||||
db->xAuth = xAuth;
|
||||
db->pAuthArg = pArg;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Write an error message into pParse->zErrMsg that explains that the
|
||||
** user-supplied authorization function returned an illegal value.
|
||||
*/
|
||||
static void sqliteAuthBadReturnCode(Parse *pParse, int rc){
|
||||
sqliteErrorMsg(pParse, "illegal return value (%d) from the "
|
||||
"authorization function - should be SQLITE_OK, SQLITE_IGNORE, "
|
||||
"or SQLITE_DENY", rc);
|
||||
pParse->rc = SQLITE_MISUSE;
|
||||
}
|
||||
|
||||
/*
|
||||
** The pExpr should be a TK_COLUMN expression. The table referred to
|
||||
** is in pTabList or else it is the NEW or OLD table of a trigger.
|
||||
** Check to see if it is OK to read this particular column.
|
||||
**
|
||||
** If the auth function returns SQLITE_IGNORE, change the TK_COLUMN
|
||||
** instruction into a TK_NULL. If the auth function returns SQLITE_DENY,
|
||||
** then generate an error.
|
||||
*/
|
||||
void sqliteAuthRead(
|
||||
Parse *pParse, /* The parser context */
|
||||
Expr *pExpr, /* The expression to check authorization on */
|
||||
SrcList *pTabList /* All table that pExpr might refer to */
|
||||
){
|
||||
sqlite *db = pParse->db;
|
||||
int rc;
|
||||
Table *pTab; /* The table being read */
|
||||
const char *zCol; /* Name of the column of the table */
|
||||
int iSrc; /* Index in pTabList->a[] of table being read */
|
||||
const char *zDBase; /* Name of database being accessed */
|
||||
|
||||
if( db->xAuth==0 ) return;
|
||||
assert( pExpr->op==TK_COLUMN );
|
||||
for(iSrc=0; iSrc<pTabList->nSrc; iSrc++){
|
||||
if( pExpr->iTable==pTabList->a[iSrc].iCursor ) break;
|
||||
}
|
||||
if( iSrc>=0 && iSrc<pTabList->nSrc ){
|
||||
pTab = pTabList->a[iSrc].pTab;
|
||||
}else{
|
||||
/* This must be an attempt to read the NEW or OLD pseudo-tables
|
||||
** of a trigger.
|
||||
*/
|
||||
TriggerStack *pStack; /* The stack of current triggers */
|
||||
pStack = pParse->trigStack;
|
||||
assert( pStack!=0 );
|
||||
assert( pExpr->iTable==pStack->newIdx || pExpr->iTable==pStack->oldIdx );
|
||||
pTab = pStack->pTab;
|
||||
}
|
||||
if( pTab==0 ) return;
|
||||
if( pExpr->iColumn>=0 ){
|
||||
assert( pExpr->iColumn<pTab->nCol );
|
||||
zCol = pTab->aCol[pExpr->iColumn].zName;
|
||||
}else if( pTab->iPKey>=0 ){
|
||||
assert( pTab->iPKey<pTab->nCol );
|
||||
zCol = pTab->aCol[pTab->iPKey].zName;
|
||||
}else{
|
||||
zCol = "ROWID";
|
||||
}
|
||||
assert( pExpr->iDb<db->nDb );
|
||||
zDBase = db->aDb[pExpr->iDb].zName;
|
||||
rc = db->xAuth(db->pAuthArg, SQLITE_READ, pTab->zName, zCol, zDBase,
|
||||
pParse->zAuthContext);
|
||||
if( rc==SQLITE_IGNORE ){
|
||||
pExpr->op = TK_NULL;
|
||||
}else if( rc==SQLITE_DENY ){
|
||||
if( db->nDb>2 || pExpr->iDb!=0 ){
|
||||
sqliteErrorMsg(pParse, "access to %s.%s.%s is prohibited",
|
||||
zDBase, pTab->zName, zCol);
|
||||
}else{
|
||||
sqliteErrorMsg(pParse, "access to %s.%s is prohibited", pTab->zName,zCol);
|
||||
}
|
||||
pParse->rc = SQLITE_AUTH;
|
||||
}else if( rc!=SQLITE_OK ){
|
||||
sqliteAuthBadReturnCode(pParse, rc);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Do an authorization check using the code and arguments given. Return
|
||||
** either SQLITE_OK (zero) or SQLITE_IGNORE or SQLITE_DENY. If SQLITE_DENY
|
||||
** is returned, then the error count and error message in pParse are
|
||||
** modified appropriately.
|
||||
*/
|
||||
int sqliteAuthCheck(
|
||||
Parse *pParse,
|
||||
int code,
|
||||
const char *zArg1,
|
||||
const char *zArg2,
|
||||
const char *zArg3
|
||||
){
|
||||
sqlite *db = pParse->db;
|
||||
int rc;
|
||||
|
||||
if( db->xAuth==0 ){
|
||||
return SQLITE_OK;
|
||||
}
|
||||
rc = db->xAuth(db->pAuthArg, code, zArg1, zArg2, zArg3, pParse->zAuthContext);
|
||||
if( rc==SQLITE_DENY ){
|
||||
sqliteErrorMsg(pParse, "not authorized");
|
||||
pParse->rc = SQLITE_AUTH;
|
||||
}else if( rc!=SQLITE_OK && rc!=SQLITE_IGNORE ){
|
||||
rc = SQLITE_DENY;
|
||||
sqliteAuthBadReturnCode(pParse, rc);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Push an authorization context. After this routine is called, the
|
||||
** zArg3 argument to authorization callbacks will be zContext until
|
||||
** popped. Or if pParse==0, this routine is a no-op.
|
||||
*/
|
||||
void sqliteAuthContextPush(
|
||||
Parse *pParse,
|
||||
AuthContext *pContext,
|
||||
const char *zContext
|
||||
){
|
||||
pContext->pParse = pParse;
|
||||
if( pParse ){
|
||||
pContext->zAuthContext = pParse->zAuthContext;
|
||||
pParse->zAuthContext = zContext;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Pop an authorization context that was previously pushed
|
||||
** by sqliteAuthContextPush
|
||||
*/
|
||||
void sqliteAuthContextPop(AuthContext *pContext){
|
||||
if( pContext->pParse ){
|
||||
pContext->pParse->zAuthContext = pContext->zAuthContext;
|
||||
pContext->pParse = 0;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* SQLITE_OMIT_AUTHORIZATION */
|
3579
sqlite/btree.c
Executable file
3579
sqlite/btree.c
Executable file
File diff suppressed because it is too large
Load Diff
156
sqlite/btree.h
Executable file
156
sqlite/btree.h
Executable file
@ -0,0 +1,156 @@
|
||||
/*
|
||||
** 2001 September 15
|
||||
**
|
||||
** The author disclaims copyright to this source code. In place of
|
||||
** a legal notice, here is a blessing:
|
||||
**
|
||||
** May you do good and not evil.
|
||||
** May you find forgiveness for yourself and forgive others.
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
*************************************************************************
|
||||
** This header file defines the interface that the sqlite B-Tree file
|
||||
** subsystem. See comments in the source code for a detailed description
|
||||
** of what each interface routine does.
|
||||
**
|
||||
** @(#) $Id: btree.h,v 1.1.1.1 2004-03-11 22:22:24 alex Exp $
|
||||
*/
|
||||
#ifndef _BTREE_H_
|
||||
#define _BTREE_H_
|
||||
|
||||
/*
|
||||
** Forward declarations of structure
|
||||
*/
|
||||
typedef struct Btree Btree;
|
||||
typedef struct BtCursor BtCursor;
|
||||
typedef struct BtOps BtOps;
|
||||
typedef struct BtCursorOps BtCursorOps;
|
||||
|
||||
|
||||
/*
|
||||
** An instance of the following structure contains pointers to all
|
||||
** methods against an open BTree. Alternative BTree implementations
|
||||
** (examples: file based versus in-memory) can be created by substituting
|
||||
** different methods. Users of the BTree cannot tell the difference.
|
||||
**
|
||||
** In C++ we could do this by defining a virtual base class and then
|
||||
** creating subclasses for each different implementation. But this is
|
||||
** C not C++ so we have to be a little more explicit.
|
||||
*/
|
||||
struct BtOps {
|
||||
int (*Close)(Btree*);
|
||||
int (*SetCacheSize)(Btree*, int);
|
||||
int (*SetSafetyLevel)(Btree*, int);
|
||||
int (*BeginTrans)(Btree*);
|
||||
int (*Commit)(Btree*);
|
||||
int (*Rollback)(Btree*);
|
||||
int (*BeginCkpt)(Btree*);
|
||||
int (*CommitCkpt)(Btree*);
|
||||
int (*RollbackCkpt)(Btree*);
|
||||
int (*CreateTable)(Btree*, int*);
|
||||
int (*CreateIndex)(Btree*, int*);
|
||||
int (*DropTable)(Btree*, int);
|
||||
int (*ClearTable)(Btree*, int);
|
||||
int (*Cursor)(Btree*, int iTable, int wrFlag, BtCursor **ppCur);
|
||||
int (*GetMeta)(Btree*, int*);
|
||||
int (*UpdateMeta)(Btree*, int*);
|
||||
char *(*IntegrityCheck)(Btree*, int*, int);
|
||||
const char *(*GetFilename)(Btree*);
|
||||
int (*Copyfile)(Btree*,Btree*);
|
||||
struct Pager *(*Pager)(Btree*);
|
||||
#ifdef SQLITE_TEST
|
||||
int (*PageDump)(Btree*, int, int);
|
||||
#endif
|
||||
};
|
||||
|
||||
/*
|
||||
** An instance of this structure defines all of the methods that can
|
||||
** be executed against a cursor.
|
||||
*/
|
||||
struct BtCursorOps {
|
||||
int (*Moveto)(BtCursor*, const void *pKey, int nKey, int *pRes);
|
||||
int (*Delete)(BtCursor*);
|
||||
int (*Insert)(BtCursor*, const void *pKey, int nKey,
|
||||
const void *pData, int nData);
|
||||
int (*First)(BtCursor*, int *pRes);
|
||||
int (*Last)(BtCursor*, int *pRes);
|
||||
int (*Next)(BtCursor*, int *pRes);
|
||||
int (*Previous)(BtCursor*, int *pRes);
|
||||
int (*KeySize)(BtCursor*, int *pSize);
|
||||
int (*Key)(BtCursor*, int offset, int amt, char *zBuf);
|
||||
int (*KeyCompare)(BtCursor*, const void *pKey, int nKey,
|
||||
int nIgnore, int *pRes);
|
||||
int (*DataSize)(BtCursor*, int *pSize);
|
||||
int (*Data)(BtCursor*, int offset, int amt, char *zBuf);
|
||||
int (*CloseCursor)(BtCursor*);
|
||||
#ifdef SQLITE_TEST
|
||||
int (*CursorDump)(BtCursor*, int*);
|
||||
#endif
|
||||
};
|
||||
|
||||
/*
|
||||
** The number of 4-byte "meta" values contained on the first page of each
|
||||
** database file.
|
||||
*/
|
||||
#define SQLITE_N_BTREE_META 10
|
||||
|
||||
int sqliteBtreeOpen(const char *zFilename, int mode, int nPg, Btree **ppBtree);
|
||||
int sqliteRbtreeOpen(const char *zFilename, int mode, int nPg, Btree **ppBtree);
|
||||
|
||||
#define btOps(pBt) (*((BtOps **)(pBt)))
|
||||
#define btCOps(pCur) (*((BtCursorOps **)(pCur)))
|
||||
|
||||
#define sqliteBtreeClose(pBt) (btOps(pBt)->Close(pBt))
|
||||
#define sqliteBtreeSetCacheSize(pBt, sz) (btOps(pBt)->SetCacheSize(pBt, sz))
|
||||
#define sqliteBtreeSetSafetyLevel(pBt, sl) (btOps(pBt)->SetSafetyLevel(pBt, sl))
|
||||
#define sqliteBtreeBeginTrans(pBt) (btOps(pBt)->BeginTrans(pBt))
|
||||
#define sqliteBtreeCommit(pBt) (btOps(pBt)->Commit(pBt))
|
||||
#define sqliteBtreeRollback(pBt) (btOps(pBt)->Rollback(pBt))
|
||||
#define sqliteBtreeBeginCkpt(pBt) (btOps(pBt)->BeginCkpt(pBt))
|
||||
#define sqliteBtreeCommitCkpt(pBt) (btOps(pBt)->CommitCkpt(pBt))
|
||||
#define sqliteBtreeRollbackCkpt(pBt) (btOps(pBt)->RollbackCkpt(pBt))
|
||||
#define sqliteBtreeCreateTable(pBt,piTable)\
|
||||
(btOps(pBt)->CreateTable(pBt,piTable))
|
||||
#define sqliteBtreeCreateIndex(pBt, piIndex)\
|
||||
(btOps(pBt)->CreateIndex(pBt, piIndex))
|
||||
#define sqliteBtreeDropTable(pBt, iTable) (btOps(pBt)->DropTable(pBt, iTable))
|
||||
#define sqliteBtreeClearTable(pBt, iTable)\
|
||||
(btOps(pBt)->ClearTable(pBt, iTable))
|
||||
#define sqliteBtreeCursor(pBt, iTable, wrFlag, ppCur)\
|
||||
(btOps(pBt)->Cursor(pBt, iTable, wrFlag, ppCur))
|
||||
#define sqliteBtreeMoveto(pCur, pKey, nKey, pRes)\
|
||||
(btCOps(pCur)->Moveto(pCur, pKey, nKey, pRes))
|
||||
#define sqliteBtreeDelete(pCur) (btCOps(pCur)->Delete(pCur))
|
||||
#define sqliteBtreeInsert(pCur, pKey, nKey, pData, nData) \
|
||||
(btCOps(pCur)->Insert(pCur, pKey, nKey, pData, nData))
|
||||
#define sqliteBtreeFirst(pCur, pRes) (btCOps(pCur)->First(pCur, pRes))
|
||||
#define sqliteBtreeLast(pCur, pRes) (btCOps(pCur)->Last(pCur, pRes))
|
||||
#define sqliteBtreeNext(pCur, pRes) (btCOps(pCur)->Next(pCur, pRes))
|
||||
#define sqliteBtreePrevious(pCur, pRes) (btCOps(pCur)->Previous(pCur, pRes))
|
||||
#define sqliteBtreeKeySize(pCur, pSize) (btCOps(pCur)->KeySize(pCur, pSize) )
|
||||
#define sqliteBtreeKey(pCur, offset, amt, zBuf)\
|
||||
(btCOps(pCur)->Key(pCur, offset, amt, zBuf))
|
||||
#define sqliteBtreeKeyCompare(pCur, pKey, nKey, nIgnore, pRes)\
|
||||
(btCOps(pCur)->KeyCompare(pCur, pKey, nKey, nIgnore, pRes))
|
||||
#define sqliteBtreeDataSize(pCur, pSize) (btCOps(pCur)->DataSize(pCur, pSize))
|
||||
#define sqliteBtreeData(pCur, offset, amt, zBuf)\
|
||||
(btCOps(pCur)->Data(pCur, offset, amt, zBuf))
|
||||
#define sqliteBtreeCloseCursor(pCur) (btCOps(pCur)->CloseCursor(pCur))
|
||||
#define sqliteBtreeGetMeta(pBt, aMeta) (btOps(pBt)->GetMeta(pBt, aMeta))
|
||||
#define sqliteBtreeUpdateMeta(pBt, aMeta) (btOps(pBt)->UpdateMeta(pBt, aMeta))
|
||||
#define sqliteBtreeIntegrityCheck(pBt, aRoot, nRoot)\
|
||||
(btOps(pBt)->IntegrityCheck(pBt, aRoot, nRoot))
|
||||
#define sqliteBtreeGetFilename(pBt) (btOps(pBt)->GetFilename(pBt))
|
||||
#define sqliteBtreeCopyFile(pBt1, pBt2) (btOps(pBt1)->Copyfile(pBt1, pBt2))
|
||||
#define sqliteBtreePager(pBt) (btOps(pBt)->Pager(pBt))
|
||||
|
||||
#ifdef SQLITE_TEST
|
||||
#define sqliteBtreePageDump(pBt, pgno, recursive)\
|
||||
(btOps(pBt)->PageDump(pBt, pgno, recursive))
|
||||
#define sqliteBtreeCursorDump(pCur, aResult)\
|
||||
(btCOps(pCur)->CursorDump(pCur, aResult))
|
||||
int btree_native_byte_order;
|
||||
#endif /* SQLITE_TEST */
|
||||
|
||||
|
||||
#endif /* _BTREE_H_ */
|
1488
sqlite/btree_rb.c
Executable file
1488
sqlite/btree_rb.c
Executable file
File diff suppressed because it is too large
Load Diff
2157
sqlite/build.c
Executable file
2157
sqlite/build.c
Executable file
File diff suppressed because it is too large
Load Diff
1
sqlite/config.h
Executable file
1
sqlite/config.h
Executable file
@ -0,0 +1 @@
|
||||
#define SQLITE_PTR_SZ 4
|
110
sqlite/copy.c
Executable file
110
sqlite/copy.c
Executable file
@ -0,0 +1,110 @@
|
||||
/*
|
||||
** 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 COPY command.
|
||||
**
|
||||
** $Id: copy.c,v 1.1.1.1 2004-03-11 22:22:23 alex Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
|
||||
/*
|
||||
** The COPY command is for compatibility with PostgreSQL and specificially
|
||||
** for the ability to read the output of pg_dump. The format is as
|
||||
** follows:
|
||||
**
|
||||
** COPY table FROM file [USING DELIMITERS string]
|
||||
**
|
||||
** "table" is an existing table name. We will read lines of code from
|
||||
** file to fill this table with data. File might be "stdin". The optional
|
||||
** delimiter string identifies the field separators. The default is a tab.
|
||||
*/
|
||||
void sqliteCopy(
|
||||
Parse *pParse, /* The parser context */
|
||||
SrcList *pTableName, /* The name of the table into which we will insert */
|
||||
Token *pFilename, /* The file from which to obtain information */
|
||||
Token *pDelimiter, /* Use this as the field delimiter */
|
||||
int onError /* What to do if a constraint fails */
|
||||
){
|
||||
Table *pTab;
|
||||
int i;
|
||||
Vdbe *v;
|
||||
int addr, end;
|
||||
char *zFile = 0;
|
||||
const char *zDb;
|
||||
sqlite *db = pParse->db;
|
||||
|
||||
|
||||
if( sqlite_malloc_failed ) goto copy_cleanup;
|
||||
assert( pTableName->nSrc==1 );
|
||||
pTab = sqliteSrcListLookup(pParse, pTableName);
|
||||
if( pTab==0 || sqliteIsReadOnly(pParse, pTab, 0) ) goto copy_cleanup;
|
||||
zFile = sqliteStrNDup(pFilename->z, pFilename->n);
|
||||
sqliteDequote(zFile);
|
||||
assert( pTab->iDb<db->nDb );
|
||||
zDb = db->aDb[pTab->iDb].zName;
|
||||
if( sqliteAuthCheck(pParse, SQLITE_INSERT, pTab->zName, 0, zDb)
|
||||
|| sqliteAuthCheck(pParse, SQLITE_COPY, pTab->zName, zFile, zDb) ){
|
||||
goto copy_cleanup;
|
||||
}
|
||||
v = sqliteGetVdbe(pParse);
|
||||
if( v ){
|
||||
sqliteBeginWriteOperation(pParse, 1, pTab->iDb);
|
||||
addr = sqliteVdbeOp3(v, OP_FileOpen, 0, 0, pFilename->z, pFilename->n);
|
||||
sqliteVdbeDequoteP3(v, addr);
|
||||
sqliteOpenTableAndIndices(pParse, pTab, 0);
|
||||
if( db->flags & SQLITE_CountRows ){
|
||||
sqliteVdbeAddOp(v, OP_Integer, 0, 0); /* Initialize the row count */
|
||||
}
|
||||
end = sqliteVdbeMakeLabel(v);
|
||||
addr = sqliteVdbeAddOp(v, OP_FileRead, pTab->nCol, end);
|
||||
if( pDelimiter ){
|
||||
sqliteVdbeChangeP3(v, addr, pDelimiter->z, pDelimiter->n);
|
||||
sqliteVdbeDequoteP3(v, addr);
|
||||
}else{
|
||||
sqliteVdbeChangeP3(v, addr, "\t", 1);
|
||||
}
|
||||
if( pTab->iPKey>=0 ){
|
||||
sqliteVdbeAddOp(v, OP_FileColumn, pTab->iPKey, 0);
|
||||
sqliteVdbeAddOp(v, OP_MustBeInt, 0, 0);
|
||||
}else{
|
||||
sqliteVdbeAddOp(v, OP_NewRecno, 0, 0);
|
||||
}
|
||||
for(i=0; i<pTab->nCol; i++){
|
||||
if( i==pTab->iPKey ){
|
||||
/* The integer primary key column is filled with NULL since its
|
||||
** value is always pulled from the record number */
|
||||
sqliteVdbeAddOp(v, OP_String, 0, 0);
|
||||
}else{
|
||||
sqliteVdbeAddOp(v, OP_FileColumn, i, 0);
|
||||
}
|
||||
}
|
||||
sqliteGenerateConstraintChecks(pParse, pTab, 0, 0, pTab->iPKey>=0,
|
||||
0, onError, addr);
|
||||
sqliteCompleteInsertion(pParse, pTab, 0, 0, 0, 0, -1);
|
||||
if( (db->flags & SQLITE_CountRows)!=0 ){
|
||||
sqliteVdbeAddOp(v, OP_AddImm, 1, 0); /* Increment row count */
|
||||
}
|
||||
sqliteVdbeAddOp(v, OP_Goto, 0, addr);
|
||||
sqliteVdbeResolveLabel(v, end);
|
||||
sqliteVdbeAddOp(v, OP_Noop, 0, 0);
|
||||
sqliteEndWriteOperation(pParse);
|
||||
if( db->flags & SQLITE_CountRows ){
|
||||
sqliteVdbeAddOp(v, OP_ColumnName, 0, 1);
|
||||
sqliteVdbeChangeP3(v, -1, "rows inserted", P3_STATIC);
|
||||
sqliteVdbeAddOp(v, OP_Callback, 1, 0);
|
||||
}
|
||||
}
|
||||
|
||||
copy_cleanup:
|
||||
sqliteSrcListDelete(pTableName);
|
||||
sqliteFree(zFile);
|
||||
return;
|
||||
}
|
873
sqlite/date.c
Executable file
873
sqlite/date.c
Executable file
@ -0,0 +1,873 @@
|
||||
/*
|
||||
** 2003 October 31
|
||||
**
|
||||
** The author disclaims copyright to this source code. In place of
|
||||
** a legal notice, here is a blessing:
|
||||
**
|
||||
** May you do good and not evil.
|
||||
** May you find forgiveness for yourself and forgive others.
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
*************************************************************************
|
||||
** This file contains the C functions that implement date and time
|
||||
** functions for SQLite.
|
||||
**
|
||||
** There is only one exported symbol in this file - the function
|
||||
** sqliteRegisterDateTimeFunctions() found at the bottom of the file.
|
||||
** All other code has file scope.
|
||||
**
|
||||
** $Id: date.c,v 1.1.1.1 2004-03-11 22:22:23 alex Exp $
|
||||
**
|
||||
** NOTES:
|
||||
**
|
||||
** SQLite processes all times and dates as Julian Day numbers. The
|
||||
** dates and times are stored as the number of days since noon
|
||||
** in Greenwich on November 24, 4714 B.C. according to the Gregorian
|
||||
** calendar system.
|
||||
**
|
||||
** 1970-01-01 00:00:00 is JD 2440587.5
|
||||
** 2000-01-01 00:00:00 is JD 2451544.5
|
||||
**
|
||||
** This implemention requires years to be expressed as a 4-digit number
|
||||
** which means that only dates between 0000-01-01 and 9999-12-31 can
|
||||
** be represented, even though julian day numbers allow a much wider
|
||||
** range of dates.
|
||||
**
|
||||
** The Gregorian calendar system is used for all dates and times,
|
||||
** even those that predate the Gregorian calendar. Historians usually
|
||||
** use the Julian calendar for dates prior to 1582-10-15 and for some
|
||||
** dates afterwards, depending on locale. Beware of this difference.
|
||||
**
|
||||
** The conversion algorithms are implemented based on descriptions
|
||||
** in the following text:
|
||||
**
|
||||
** Jean Meeus
|
||||
** Astronomical Algorithms, 2nd Edition, 1998
|
||||
** ISBM 0-943396-61-1
|
||||
** Willmann-Bell, Inc
|
||||
** Richmond, Virginia (USA)
|
||||
*/
|
||||
#include "os.h"
|
||||
#include "sqliteInt.h"
|
||||
#include <ctype.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <time.h>
|
||||
|
||||
#ifndef SQLITE_OMIT_DATETIME_FUNCS
|
||||
|
||||
/*
|
||||
** A structure for holding a single date and time.
|
||||
*/
|
||||
typedef struct DateTime DateTime;
|
||||
struct DateTime {
|
||||
double rJD; /* The julian day number */
|
||||
int Y, M, D; /* Year, month, and day */
|
||||
int h, m; /* Hour and minutes */
|
||||
int tz; /* Timezone offset in minutes */
|
||||
double s; /* Seconds */
|
||||
char validYMD; /* True if Y,M,D are valid */
|
||||
char validHMS; /* True if h,m,s are valid */
|
||||
char validJD; /* True if rJD is valid */
|
||||
char validTZ; /* True if tz is valid */
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
** Convert zDate into one or more integers. Additional arguments
|
||||
** come in groups of 5 as follows:
|
||||
**
|
||||
** N number of digits in the integer
|
||||
** min minimum allowed value of the integer
|
||||
** max maximum allowed value of the integer
|
||||
** nextC first character after the integer
|
||||
** pVal where to write the integers value.
|
||||
**
|
||||
** Conversions continue until one with nextC==0 is encountered.
|
||||
** The function returns the number of successful conversions.
|
||||
*/
|
||||
static int getDigits(const char *zDate, ...){
|
||||
va_list ap;
|
||||
int val;
|
||||
int N;
|
||||
int min;
|
||||
int max;
|
||||
int nextC;
|
||||
int *pVal;
|
||||
int cnt = 0;
|
||||
va_start(ap, zDate);
|
||||
do{
|
||||
N = va_arg(ap, int);
|
||||
min = va_arg(ap, int);
|
||||
max = va_arg(ap, int);
|
||||
nextC = va_arg(ap, int);
|
||||
pVal = va_arg(ap, int*);
|
||||
val = 0;
|
||||
while( N-- ){
|
||||
if( !isdigit(*zDate) ){
|
||||
return cnt;
|
||||
}
|
||||
val = val*10 + *zDate - '0';
|
||||
zDate++;
|
||||
}
|
||||
if( val<min || val>max || (nextC!=0 && nextC!=*zDate) ){
|
||||
return cnt;
|
||||
}
|
||||
*pVal = val;
|
||||
zDate++;
|
||||
cnt++;
|
||||
}while( nextC );
|
||||
return cnt;
|
||||
}
|
||||
|
||||
/*
|
||||
** Read text from z[] and convert into a floating point number. Return
|
||||
** the number of digits converted.
|
||||
*/
|
||||
static int getValue(const char *z, double *pR){
|
||||
const char *zEnd;
|
||||
*pR = sqliteAtoF(z, &zEnd);
|
||||
return zEnd - z;
|
||||
}
|
||||
|
||||
/*
|
||||
** Parse a timezone extension on the end of a date-time.
|
||||
** The extension is of the form:
|
||||
**
|
||||
** (+/-)HH:MM
|
||||
**
|
||||
** If the parse is successful, write the number of minutes
|
||||
** of change in *pnMin and return 0. If a parser error occurs,
|
||||
** return 0.
|
||||
**
|
||||
** A missing specifier is not considered an error.
|
||||
*/
|
||||
static int parseTimezone(const char *zDate, DateTime *p){
|
||||
int sgn = 0;
|
||||
int nHr, nMn;
|
||||
while( isspace(*zDate) ){ zDate++; }
|
||||
p->tz = 0;
|
||||
if( *zDate=='-' ){
|
||||
sgn = -1;
|
||||
}else if( *zDate=='+' ){
|
||||
sgn = +1;
|
||||
}else{
|
||||
return *zDate!=0;
|
||||
}
|
||||
zDate++;
|
||||
if( getDigits(zDate, 2, 0, 14, ':', &nHr, 2, 0, 59, 0, &nMn)!=2 ){
|
||||
return 1;
|
||||
}
|
||||
zDate += 5;
|
||||
p->tz = sgn*(nMn + nHr*60);
|
||||
while( isspace(*zDate) ){ zDate++; }
|
||||
return *zDate!=0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Parse times of the form HH:MM or HH:MM:SS or HH:MM:SS.FFFF.
|
||||
** The HH, MM, and SS must each be exactly 2 digits. The
|
||||
** fractional seconds FFFF can be one or more digits.
|
||||
**
|
||||
** Return 1 if there is a parsing error and 0 on success.
|
||||
*/
|
||||
static int parseHhMmSs(const char *zDate, DateTime *p){
|
||||
int h, m, s;
|
||||
double ms = 0.0;
|
||||
if( getDigits(zDate, 2, 0, 24, ':', &h, 2, 0, 59, 0, &m)!=2 ){
|
||||
return 1;
|
||||
}
|
||||
zDate += 5;
|
||||
if( *zDate==':' ){
|
||||
zDate++;
|
||||
if( getDigits(zDate, 2, 0, 59, 0, &s)!=1 ){
|
||||
return 1;
|
||||
}
|
||||
zDate += 2;
|
||||
if( *zDate=='.' && isdigit(zDate[1]) ){
|
||||
double rScale = 1.0;
|
||||
zDate++;
|
||||
while( isdigit(*zDate) ){
|
||||
ms = ms*10.0 + *zDate - '0';
|
||||
rScale *= 10.0;
|
||||
zDate++;
|
||||
}
|
||||
ms /= rScale;
|
||||
}
|
||||
}else{
|
||||
s = 0;
|
||||
}
|
||||
p->validJD = 0;
|
||||
p->validHMS = 1;
|
||||
p->h = h;
|
||||
p->m = m;
|
||||
p->s = s + ms;
|
||||
if( parseTimezone(zDate, p) ) return 1;
|
||||
p->validTZ = p->tz!=0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Convert from YYYY-MM-DD HH:MM:SS to julian day. We always assume
|
||||
** that the YYYY-MM-DD is according to the Gregorian calendar.
|
||||
**
|
||||
** Reference: Meeus page 61
|
||||
*/
|
||||
static void computeJD(DateTime *p){
|
||||
int Y, M, D, A, B, X1, X2;
|
||||
|
||||
if( p->validJD ) return;
|
||||
if( p->validYMD ){
|
||||
Y = p->Y;
|
||||
M = p->M;
|
||||
D = p->D;
|
||||
}else{
|
||||
Y = 2000; /* If no YMD specified, assume 2000-Jan-01 */
|
||||
M = 1;
|
||||
D = 1;
|
||||
}
|
||||
if( M<=2 ){
|
||||
Y--;
|
||||
M += 12;
|
||||
}
|
||||
A = Y/100;
|
||||
B = 2 - A + (A/4);
|
||||
X1 = 365.25*(Y+4716);
|
||||
X2 = 30.6001*(M+1);
|
||||
p->rJD = X1 + X2 + D + B - 1524.5;
|
||||
p->validJD = 1;
|
||||
p->validYMD = 0;
|
||||
if( p->validHMS ){
|
||||
p->rJD += (p->h*3600.0 + p->m*60.0 + p->s)/86400.0;
|
||||
if( p->validTZ ){
|
||||
p->rJD += p->tz*60/86400.0;
|
||||
p->validHMS = 0;
|
||||
p->validTZ = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Parse dates of the form
|
||||
**
|
||||
** YYYY-MM-DD HH:MM:SS.FFF
|
||||
** YYYY-MM-DD HH:MM:SS
|
||||
** YYYY-MM-DD HH:MM
|
||||
** YYYY-MM-DD
|
||||
**
|
||||
** Write the result into the DateTime structure and return 0
|
||||
** on success and 1 if the input string is not a well-formed
|
||||
** date.
|
||||
*/
|
||||
static int parseYyyyMmDd(const char *zDate, DateTime *p){
|
||||
int Y, M, D, neg;
|
||||
|
||||
if( zDate[0]=='-' ){
|
||||
zDate++;
|
||||
neg = 1;
|
||||
}else{
|
||||
neg = 0;
|
||||
}
|
||||
if( getDigits(zDate,4,0,9999,'-',&Y,2,1,12,'-',&M,2,1,31,0,&D)!=3 ){
|
||||
return 1;
|
||||
}
|
||||
zDate += 10;
|
||||
while( isspace(*zDate) ){ zDate++; }
|
||||
if( parseHhMmSs(zDate, p)==0 ){
|
||||
/* We got the time */
|
||||
}else if( *zDate==0 ){
|
||||
p->validHMS = 0;
|
||||
}else{
|
||||
return 1;
|
||||
}
|
||||
p->validJD = 0;
|
||||
p->validYMD = 1;
|
||||
p->Y = neg ? -Y : Y;
|
||||
p->M = M;
|
||||
p->D = D;
|
||||
if( p->validTZ ){
|
||||
computeJD(p);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Attempt to parse the given string into a Julian Day Number. Return
|
||||
** the number of errors.
|
||||
**
|
||||
** The following are acceptable forms for the input string:
|
||||
**
|
||||
** YYYY-MM-DD HH:MM:SS.FFF +/-HH:MM
|
||||
** DDDD.DD
|
||||
** now
|
||||
**
|
||||
** In the first form, the +/-HH:MM is always optional. The fractional
|
||||
** seconds extension (the ".FFF") is optional. The seconds portion
|
||||
** (":SS.FFF") is option. The year and date can be omitted as long
|
||||
** as there is a time string. The time string can be omitted as long
|
||||
** as there is a year and date.
|
||||
*/
|
||||
static int parseDateOrTime(const char *zDate, DateTime *p){
|
||||
memset(p, 0, sizeof(*p));
|
||||
if( parseYyyyMmDd(zDate,p)==0 ){
|
||||
return 0;
|
||||
}else if( parseHhMmSs(zDate, p)==0 ){
|
||||
return 0;
|
||||
}else if( sqliteStrICmp(zDate,"now")==0){
|
||||
double r;
|
||||
if( sqliteOsCurrentTime(&r)==0 ){
|
||||
p->rJD = r;
|
||||
p->validJD = 1;
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}else if( sqliteIsNumber(zDate) ){
|
||||
p->rJD = sqliteAtoF(zDate, 0);
|
||||
p->validJD = 1;
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
** Compute the Year, Month, and Day from the julian day number.
|
||||
*/
|
||||
static void computeYMD(DateTime *p){
|
||||
int Z, A, B, C, D, E, X1;
|
||||
if( p->validYMD ) return;
|
||||
if( !p->validJD ){
|
||||
p->Y = 2000;
|
||||
p->M = 1;
|
||||
p->D = 1;
|
||||
}else{
|
||||
Z = p->rJD + 0.5;
|
||||
A = (Z - 1867216.25)/36524.25;
|
||||
A = Z + 1 + A - (A/4);
|
||||
B = A + 1524;
|
||||
C = (B - 122.1)/365.25;
|
||||
D = 365.25*C;
|
||||
E = (B-D)/30.6001;
|
||||
X1 = 30.6001*E;
|
||||
p->D = B - D - X1;
|
||||
p->M = E<14 ? E-1 : E-13;
|
||||
p->Y = p->M>2 ? C - 4716 : C - 4715;
|
||||
}
|
||||
p->validYMD = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
** Compute the Hour, Minute, and Seconds from the julian day number.
|
||||
*/
|
||||
static void computeHMS(DateTime *p){
|
||||
int Z, s;
|
||||
if( p->validHMS ) return;
|
||||
Z = p->rJD + 0.5;
|
||||
s = (p->rJD + 0.5 - Z)*86400000.0 + 0.5;
|
||||
p->s = 0.001*s;
|
||||
s = p->s;
|
||||
p->s -= s;
|
||||
p->h = s/3600;
|
||||
s -= p->h*3600;
|
||||
p->m = s/60;
|
||||
p->s += s - p->m*60;
|
||||
p->validHMS = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
** Compute both YMD and HMS
|
||||
*/
|
||||
static void computeYMD_HMS(DateTime *p){
|
||||
computeYMD(p);
|
||||
computeHMS(p);
|
||||
}
|
||||
|
||||
/*
|
||||
** Clear the YMD and HMS and the TZ
|
||||
*/
|
||||
static void clearYMD_HMS_TZ(DateTime *p){
|
||||
p->validYMD = 0;
|
||||
p->validHMS = 0;
|
||||
p->validTZ = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Compute the difference (in days) between localtime and UTC (a.k.a. GMT)
|
||||
** for the time value p where p is in UTC.
|
||||
*/
|
||||
static double localtimeOffset(DateTime *p){
|
||||
DateTime x, y;
|
||||
time_t t;
|
||||
struct tm *pTm;
|
||||
x = *p;
|
||||
computeYMD_HMS(&x);
|
||||
if( x.Y<1971 || x.Y>=2038 ){
|
||||
x.Y = 2000;
|
||||
x.M = 1;
|
||||
x.D = 1;
|
||||
x.h = 0;
|
||||
x.m = 0;
|
||||
x.s = 0.0;
|
||||
} else {
|
||||
int s = x.s + 0.5;
|
||||
x.s = s;
|
||||
}
|
||||
x.tz = 0;
|
||||
x.validJD = 0;
|
||||
computeJD(&x);
|
||||
t = (x.rJD-2440587.5)*86400.0 + 0.5;
|
||||
sqliteOsEnterMutex();
|
||||
pTm = localtime(&t);
|
||||
y.Y = pTm->tm_year + 1900;
|
||||
y.M = pTm->tm_mon + 1;
|
||||
y.D = pTm->tm_mday;
|
||||
y.h = pTm->tm_hour;
|
||||
y.m = pTm->tm_min;
|
||||
y.s = pTm->tm_sec;
|
||||
sqliteOsLeaveMutex();
|
||||
y.validYMD = 1;
|
||||
y.validHMS = 1;
|
||||
y.validJD = 0;
|
||||
y.validTZ = 0;
|
||||
computeJD(&y);
|
||||
return y.rJD - x.rJD;
|
||||
}
|
||||
|
||||
/*
|
||||
** Process a modifier to a date-time stamp. The modifiers are
|
||||
** as follows:
|
||||
**
|
||||
** NNN days
|
||||
** NNN hours
|
||||
** NNN minutes
|
||||
** NNN.NNNN seconds
|
||||
** NNN months
|
||||
** NNN years
|
||||
** start of month
|
||||
** start of year
|
||||
** start of week
|
||||
** start of day
|
||||
** weekday N
|
||||
** unixepoch
|
||||
** localtime
|
||||
** utc
|
||||
**
|
||||
** Return 0 on success and 1 if there is any kind of error.
|
||||
*/
|
||||
static int parseModifier(const char *zMod, DateTime *p){
|
||||
int rc = 1;
|
||||
int n;
|
||||
double r;
|
||||
char *z, zBuf[30];
|
||||
z = zBuf;
|
||||
for(n=0; n<sizeof(zBuf)-1 && zMod[n]; n++){
|
||||
z[n] = tolower(zMod[n]);
|
||||
}
|
||||
z[n] = 0;
|
||||
switch( z[0] ){
|
||||
case 'l': {
|
||||
/* localtime
|
||||
**
|
||||
** Assuming the current time value is UTC (a.k.a. GMT), shift it to
|
||||
** show local time.
|
||||
*/
|
||||
if( strcmp(z, "localtime")==0 ){
|
||||
computeJD(p);
|
||||
p->rJD += localtimeOffset(p);
|
||||
clearYMD_HMS_TZ(p);
|
||||
rc = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'u': {
|
||||
/*
|
||||
** unixepoch
|
||||
**
|
||||
** Treat the current value of p->rJD as the number of
|
||||
** seconds since 1970. Convert to a real julian day number.
|
||||
*/
|
||||
if( strcmp(z, "unixepoch")==0 && p->validJD ){
|
||||
p->rJD = p->rJD/86400.0 + 2440587.5;
|
||||
clearYMD_HMS_TZ(p);
|
||||
rc = 0;
|
||||
}else if( strcmp(z, "utc")==0 ){
|
||||
double c1;
|
||||
computeJD(p);
|
||||
c1 = localtimeOffset(p);
|
||||
p->rJD -= c1;
|
||||
clearYMD_HMS_TZ(p);
|
||||
p->rJD += c1 - localtimeOffset(p);
|
||||
rc = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'w': {
|
||||
/*
|
||||
** weekday N
|
||||
**
|
||||
** Move the date to the same time on the next occurrance of
|
||||
** weekday N where 0==Sunday, 1==Monday, and so forth. If the
|
||||
** date is already on the appropriate weekday, this is a no-op.
|
||||
*/
|
||||
if( strncmp(z, "weekday ", 8)==0 && getValue(&z[8],&r)>0
|
||||
&& (n=r)==r && n>=0 && r<7 ){
|
||||
int Z;
|
||||
computeYMD_HMS(p);
|
||||
p->validTZ = 0;
|
||||
p->validJD = 0;
|
||||
computeJD(p);
|
||||
Z = p->rJD + 1.5;
|
||||
Z %= 7;
|
||||
if( Z>n ) Z -= 7;
|
||||
p->rJD += n - Z;
|
||||
clearYMD_HMS_TZ(p);
|
||||
rc = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 's': {
|
||||
/*
|
||||
** start of TTTTT
|
||||
**
|
||||
** Move the date backwards to the beginning of the current day,
|
||||
** or month or year.
|
||||
*/
|
||||
if( strncmp(z, "start of ", 9)!=0 ) break;
|
||||
z += 9;
|
||||
computeYMD(p);
|
||||
p->validHMS = 1;
|
||||
p->h = p->m = 0;
|
||||
p->s = 0.0;
|
||||
p->validTZ = 0;
|
||||
p->validJD = 0;
|
||||
if( strcmp(z,"month")==0 ){
|
||||
p->D = 1;
|
||||
rc = 0;
|
||||
}else if( strcmp(z,"year")==0 ){
|
||||
computeYMD(p);
|
||||
p->M = 1;
|
||||
p->D = 1;
|
||||
rc = 0;
|
||||
}else if( strcmp(z,"day")==0 ){
|
||||
rc = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case '+':
|
||||
case '-':
|
||||
case '0':
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9': {
|
||||
n = getValue(z, &r);
|
||||
if( n<=0 ) break;
|
||||
if( z[n]==':' ){
|
||||
/* A modifier of the form (+|-)HH:MM:SS.FFF adds (or subtracts) the
|
||||
** specified number of hours, minutes, seconds, and fractional seconds
|
||||
** to the time. The ".FFF" may be omitted. The ":SS.FFF" may be
|
||||
** omitted.
|
||||
*/
|
||||
const char *z2 = z;
|
||||
DateTime tx;
|
||||
int day;
|
||||
if( !isdigit(*z2) ) z2++;
|
||||
memset(&tx, 0, sizeof(tx));
|
||||
if( parseHhMmSs(z2, &tx) ) break;
|
||||
computeJD(&tx);
|
||||
tx.rJD -= 0.5;
|
||||
day = (int)tx.rJD;
|
||||
tx.rJD -= day;
|
||||
if( z[0]=='-' ) tx.rJD = -tx.rJD;
|
||||
computeJD(p);
|
||||
clearYMD_HMS_TZ(p);
|
||||
p->rJD += tx.rJD;
|
||||
rc = 0;
|
||||
break;
|
||||
}
|
||||
z += n;
|
||||
while( isspace(z[0]) ) z++;
|
||||
n = strlen(z);
|
||||
if( n>10 || n<3 ) break;
|
||||
if( z[n-1]=='s' ){ z[n-1] = 0; n--; }
|
||||
computeJD(p);
|
||||
rc = 0;
|
||||
if( n==3 && strcmp(z,"day")==0 ){
|
||||
p->rJD += r;
|
||||
}else if( n==4 && strcmp(z,"hour")==0 ){
|
||||
p->rJD += r/24.0;
|
||||
}else if( n==6 && strcmp(z,"minute")==0 ){
|
||||
p->rJD += r/(24.0*60.0);
|
||||
}else if( n==6 && strcmp(z,"second")==0 ){
|
||||
p->rJD += r/(24.0*60.0*60.0);
|
||||
}else if( n==5 && strcmp(z,"month")==0 ){
|
||||
int x, y;
|
||||
computeYMD_HMS(p);
|
||||
p->M += r;
|
||||
x = p->M>0 ? (p->M-1)/12 : (p->M-12)/12;
|
||||
p->Y += x;
|
||||
p->M -= x*12;
|
||||
p->validJD = 0;
|
||||
computeJD(p);
|
||||
y = r;
|
||||
if( y!=r ){
|
||||
p->rJD += (r - y)*30.0;
|
||||
}
|
||||
}else if( n==4 && strcmp(z,"year")==0 ){
|
||||
computeYMD_HMS(p);
|
||||
p->Y += r;
|
||||
p->validJD = 0;
|
||||
computeJD(p);
|
||||
}else{
|
||||
rc = 1;
|
||||
}
|
||||
clearYMD_HMS_TZ(p);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Process time function arguments. argv[0] is a date-time stamp.
|
||||
** argv[1] and following are modifiers. Parse them all and write
|
||||
** the resulting time into the DateTime structure p. Return 0
|
||||
** on success and 1 if there are any errors.
|
||||
*/
|
||||
static int isDate(int argc, const char **argv, DateTime *p){
|
||||
int i;
|
||||
if( argc==0 ) return 1;
|
||||
if( argv[0]==0 || parseDateOrTime(argv[0], p) ) return 1;
|
||||
for(i=1; i<argc; i++){
|
||||
if( argv[i]==0 || parseModifier(argv[i], p) ) return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** The following routines implement the various date and time functions
|
||||
** of SQLite.
|
||||
*/
|
||||
|
||||
/*
|
||||
** julianday( TIMESTRING, MOD, MOD, ...)
|
||||
**
|
||||
** Return the julian day number of the date specified in the arguments
|
||||
*/
|
||||
static void juliandayFunc(sqlite_func *context, int argc, const char **argv){
|
||||
DateTime x;
|
||||
if( isDate(argc, argv, &x)==0 ){
|
||||
computeJD(&x);
|
||||
sqlite_set_result_double(context, x.rJD);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** datetime( TIMESTRING, MOD, MOD, ...)
|
||||
**
|
||||
** Return YYYY-MM-DD HH:MM:SS
|
||||
*/
|
||||
static void datetimeFunc(sqlite_func *context, int argc, const char **argv){
|
||||
DateTime x;
|
||||
if( isDate(argc, argv, &x)==0 ){
|
||||
char zBuf[100];
|
||||
computeYMD_HMS(&x);
|
||||
sprintf(zBuf, "%04d-%02d-%02d %02d:%02d:%02d",x.Y, x.M, x.D, x.h, x.m,
|
||||
(int)(x.s));
|
||||
sqlite_set_result_string(context, zBuf, -1);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** time( TIMESTRING, MOD, MOD, ...)
|
||||
**
|
||||
** Return HH:MM:SS
|
||||
*/
|
||||
static void timeFunc(sqlite_func *context, int argc, const char **argv){
|
||||
DateTime x;
|
||||
if( isDate(argc, argv, &x)==0 ){
|
||||
char zBuf[100];
|
||||
computeHMS(&x);
|
||||
sprintf(zBuf, "%02d:%02d:%02d", x.h, x.m, (int)x.s);
|
||||
sqlite_set_result_string(context, zBuf, -1);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** date( TIMESTRING, MOD, MOD, ...)
|
||||
**
|
||||
** Return YYYY-MM-DD
|
||||
*/
|
||||
static void dateFunc(sqlite_func *context, int argc, const char **argv){
|
||||
DateTime x;
|
||||
if( isDate(argc, argv, &x)==0 ){
|
||||
char zBuf[100];
|
||||
computeYMD(&x);
|
||||
sprintf(zBuf, "%04d-%02d-%02d", x.Y, x.M, x.D);
|
||||
sqlite_set_result_string(context, zBuf, -1);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** strftime( FORMAT, TIMESTRING, MOD, MOD, ...)
|
||||
**
|
||||
** Return a string described by FORMAT. Conversions as follows:
|
||||
**
|
||||
** %d day of month
|
||||
** %f ** fractional seconds SS.SSS
|
||||
** %H hour 00-24
|
||||
** %j day of year 000-366
|
||||
** %J ** Julian day number
|
||||
** %m month 01-12
|
||||
** %M minute 00-59
|
||||
** %s seconds since 1970-01-01
|
||||
** %S seconds 00-59
|
||||
** %w day of week 0-6 sunday==0
|
||||
** %W week of year 00-53
|
||||
** %Y year 0000-9999
|
||||
** %% %
|
||||
*/
|
||||
static void strftimeFunc(sqlite_func *context, int argc, const char **argv){
|
||||
DateTime x;
|
||||
int n, i, j;
|
||||
char *z;
|
||||
const char *zFmt = argv[0];
|
||||
char zBuf[100];
|
||||
if( argv[0]==0 || isDate(argc-1, argv+1, &x) ) return;
|
||||
for(i=0, n=1; zFmt[i]; i++, n++){
|
||||
if( zFmt[i]=='%' ){
|
||||
switch( zFmt[i+1] ){
|
||||
case 'd':
|
||||
case 'H':
|
||||
case 'm':
|
||||
case 'M':
|
||||
case 'S':
|
||||
case 'W':
|
||||
n++;
|
||||
/* fall thru */
|
||||
case 'w':
|
||||
case '%':
|
||||
break;
|
||||
case 'f':
|
||||
n += 8;
|
||||
break;
|
||||
case 'j':
|
||||
n += 3;
|
||||
break;
|
||||
case 'Y':
|
||||
n += 8;
|
||||
break;
|
||||
case 's':
|
||||
case 'J':
|
||||
n += 50;
|
||||
break;
|
||||
default:
|
||||
return; /* ERROR. return a NULL */
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
if( n<sizeof(zBuf) ){
|
||||
z = zBuf;
|
||||
}else{
|
||||
z = sqliteMalloc( n );
|
||||
if( z==0 ) return;
|
||||
}
|
||||
computeJD(&x);
|
||||
computeYMD_HMS(&x);
|
||||
for(i=j=0; zFmt[i]; i++){
|
||||
if( zFmt[i]!='%' ){
|
||||
z[j++] = zFmt[i];
|
||||
}else{
|
||||
i++;
|
||||
switch( zFmt[i] ){
|
||||
case 'd': sprintf(&z[j],"%02d",x.D); j+=2; break;
|
||||
case 'f': {
|
||||
int s = x.s;
|
||||
int ms = (x.s - s)*1000.0;
|
||||
sprintf(&z[j],"%02d.%03d",s,ms);
|
||||
j += strlen(&z[j]);
|
||||
break;
|
||||
}
|
||||
case 'H': sprintf(&z[j],"%02d",x.h); j+=2; break;
|
||||
case 'W': /* Fall thru */
|
||||
case 'j': {
|
||||
int n;
|
||||
DateTime y = x;
|
||||
y.validJD = 0;
|
||||
y.M = 1;
|
||||
y.D = 1;
|
||||
computeJD(&y);
|
||||
n = x.rJD - y.rJD + 1;
|
||||
if( zFmt[i]=='W' ){
|
||||
sprintf(&z[j],"%02d",(n+6)/7);
|
||||
j += 2;
|
||||
}else{
|
||||
sprintf(&z[j],"%03d",n);
|
||||
j += 3;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'J': sprintf(&z[j],"%.16g",x.rJD); j+=strlen(&z[j]); break;
|
||||
case 'm': sprintf(&z[j],"%02d",x.M); j+=2; break;
|
||||
case 'M': sprintf(&z[j],"%02d",x.m); j+=2; break;
|
||||
case 's': {
|
||||
sprintf(&z[j],"%d",(int)((x.rJD-2440587.5)*86400.0 + 0.5));
|
||||
j += strlen(&z[j]);
|
||||
break;
|
||||
}
|
||||
case 'S': sprintf(&z[j],"%02d",(int)(x.s+0.5)); j+=2; break;
|
||||
case 'w': z[j++] = (((int)(x.rJD+1.5)) % 7) + '0'; break;
|
||||
case 'Y': sprintf(&z[j],"%04d",x.Y); j+=strlen(&z[j]); break;
|
||||
case '%': z[j++] = '%'; break;
|
||||
}
|
||||
}
|
||||
}
|
||||
z[j] = 0;
|
||||
sqlite_set_result_string(context, z, -1);
|
||||
if( z!=zBuf ){
|
||||
sqliteFree(z);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif /* !defined(SQLITE_OMIT_DATETIME_FUNCS) */
|
||||
|
||||
/*
|
||||
** This function registered all of the above C functions as SQL
|
||||
** functions. This should be the only routine in this file with
|
||||
** external linkage.
|
||||
*/
|
||||
void sqliteRegisterDateTimeFunctions(sqlite *db){
|
||||
static struct {
|
||||
char *zName;
|
||||
int nArg;
|
||||
int dataType;
|
||||
void (*xFunc)(sqlite_func*,int,const char**);
|
||||
} aFuncs[] = {
|
||||
#ifndef SQLITE_OMIT_DATETIME_FUNCS
|
||||
{ "julianday", -1, SQLITE_NUMERIC, juliandayFunc },
|
||||
{ "date", -1, SQLITE_TEXT, dateFunc },
|
||||
{ "time", -1, SQLITE_TEXT, timeFunc },
|
||||
{ "datetime", -1, SQLITE_TEXT, datetimeFunc },
|
||||
{ "strftime", -1, SQLITE_TEXT, strftimeFunc },
|
||||
#endif
|
||||
};
|
||||
int i;
|
||||
|
||||
for(i=0; i<sizeof(aFuncs)/sizeof(aFuncs[0]); i++){
|
||||
sqlite_create_function(db, aFuncs[i].zName,
|
||||
aFuncs[i].nArg, aFuncs[i].xFunc, 0);
|
||||
if( aFuncs[i].xFunc ){
|
||||
sqlite_function_type(db, aFuncs[i].zName, aFuncs[i].dataType);
|
||||
}
|
||||
}
|
||||
}
|
393
sqlite/delete.c
Executable file
393
sqlite/delete.c
Executable file
@ -0,0 +1,393 @@
|
||||
/*
|
||||
** 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 DELETE FROM statements.
|
||||
**
|
||||
** $Id: delete.c,v 1.1.1.1 2004-03-11 22:22:23 alex 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 *sqliteSrcListLookup(Parse *pParse, SrcList *pSrc){
|
||||
Table *pTab = 0;
|
||||
int i;
|
||||
for(i=0; i<pSrc->nSrc; i++){
|
||||
const char *zTab = pSrc->a[i].zName;
|
||||
const char *zDb = pSrc->a[i].zDatabase;
|
||||
pTab = sqliteLocateTable(pParse, zTab, zDb);
|
||||
pSrc->a[i].pTab = pTab;
|
||||
}
|
||||
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 sqliteIsReadOnly(Parse *pParse, Table *pTab, int viewOk){
|
||||
if( pTab->readOnly ){
|
||||
sqliteErrorMsg(pParse, "table %s may not be modified", pTab->zName);
|
||||
return 1;
|
||||
}
|
||||
if( !viewOk && pTab->pSelect ){
|
||||
sqliteErrorMsg(pParse, "cannot modify %s because it is a view",pTab->zName);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Process a DELETE FROM statement.
|
||||
*/
|
||||
void sqliteDeleteFrom(
|
||||
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; /* 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 */
|
||||
sqlite *db; /* Main database structure */
|
||||
int isView; /* True if attempting to delete from a view */
|
||||
AuthContext sContext; /* Authorization context */
|
||||
|
||||
int row_triggers_exist = 0; /* True if any triggers exist */
|
||||
int before_triggers; /* True if there are BEFORE triggers */
|
||||
int after_triggers; /* True if there are AFTER triggers */
|
||||
int oldIdx = -1; /* Cursor for the OLD table of AFTER triggers */
|
||||
|
||||
sContext.pParse = 0;
|
||||
if( pParse->nErr || sqlite_malloc_failed ){
|
||||
pTabList = 0;
|
||||
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 = sqliteSrcListLookup(pParse, pTabList);
|
||||
if( pTab==0 ) goto delete_from_cleanup;
|
||||
before_triggers = sqliteTriggersExist(pParse, pTab->pTrigger,
|
||||
TK_DELETE, TK_BEFORE, TK_ROW, 0);
|
||||
after_triggers = sqliteTriggersExist(pParse, pTab->pTrigger,
|
||||
TK_DELETE, TK_AFTER, TK_ROW, 0);
|
||||
row_triggers_exist = before_triggers || after_triggers;
|
||||
isView = pTab->pSelect!=0;
|
||||
if( sqliteIsReadOnly(pParse, pTab, before_triggers) ){
|
||||
goto delete_from_cleanup;
|
||||
}
|
||||
assert( pTab->iDb<db->nDb );
|
||||
zDb = db->aDb[pTab->iDb].zName;
|
||||
if( sqliteAuthCheck(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 && sqliteViewGetColumnNames(pParse, pTab) ){
|
||||
goto delete_from_cleanup;
|
||||
}
|
||||
|
||||
/* Allocate a cursor used to store the old.* data for a trigger.
|
||||
*/
|
||||
if( row_triggers_exist ){
|
||||
oldIdx = pParse->nTab++;
|
||||
}
|
||||
|
||||
/* Resolve the column names in all the expressions.
|
||||
*/
|
||||
assert( pTabList->nSrc==1 );
|
||||
iCur = pTabList->a[0].iCursor = pParse->nTab++;
|
||||
if( pWhere ){
|
||||
if( sqliteExprResolveIds(pParse, pTabList, 0, pWhere) ){
|
||||
goto delete_from_cleanup;
|
||||
}
|
||||
if( sqliteExprCheck(pParse, pWhere, 0, 0) ){
|
||||
goto delete_from_cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
/* Start the view context
|
||||
*/
|
||||
if( isView ){
|
||||
sqliteAuthContextPush(pParse, &sContext, pTab->zName);
|
||||
}
|
||||
|
||||
/* Begin generating code.
|
||||
*/
|
||||
v = sqliteGetVdbe(pParse);
|
||||
if( v==0 ){
|
||||
goto delete_from_cleanup;
|
||||
}
|
||||
sqliteBeginWriteOperation(pParse, row_triggers_exist, pTab->iDb);
|
||||
|
||||
/* If we are trying to delete from a view, construct that view into
|
||||
** a temporary table.
|
||||
*/
|
||||
if( isView ){
|
||||
Select *pView = sqliteSelectDup(pTab->pSelect);
|
||||
sqliteSelect(pParse, pView, SRT_TempTable, iCur, 0, 0, 0);
|
||||
sqliteSelectDelete(pView);
|
||||
}
|
||||
|
||||
/* Initialize the counter of the number of rows deleted, if
|
||||
** we are counting rows.
|
||||
*/
|
||||
if( db->flags & SQLITE_CountRows ){
|
||||
sqliteVdbeAddOp(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 && !row_triggers_exist ){
|
||||
if( db->flags & SQLITE_CountRows ){
|
||||
/* If counting rows deleted, just count the total number of
|
||||
** entries in the table. */
|
||||
int endOfLoop = sqliteVdbeMakeLabel(v);
|
||||
int addr;
|
||||
if( !isView ){
|
||||
sqliteVdbeAddOp(v, OP_Integer, pTab->iDb, 0);
|
||||
sqliteVdbeAddOp(v, OP_OpenRead, iCur, pTab->tnum);
|
||||
}
|
||||
sqliteVdbeAddOp(v, OP_Rewind, iCur, sqliteVdbeCurrentAddr(v)+2);
|
||||
addr = sqliteVdbeAddOp(v, OP_AddImm, 1, 0);
|
||||
sqliteVdbeAddOp(v, OP_Next, iCur, addr);
|
||||
sqliteVdbeResolveLabel(v, endOfLoop);
|
||||
sqliteVdbeAddOp(v, OP_Close, iCur, 0);
|
||||
}
|
||||
if( !isView ){
|
||||
sqliteVdbeAddOp(v, OP_Clear, pTab->tnum, pTab->iDb);
|
||||
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
|
||||
sqliteVdbeAddOp(v, OP_Clear, pIdx->tnum, pIdx->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 = sqliteWhereBegin(pParse, pTabList, pWhere, 1, 0);
|
||||
if( pWInfo==0 ) goto delete_from_cleanup;
|
||||
|
||||
/* Remember the key of every item to be deleted.
|
||||
*/
|
||||
sqliteVdbeAddOp(v, OP_ListWrite, 0, 0);
|
||||
if( db->flags & SQLITE_CountRows ){
|
||||
sqliteVdbeAddOp(v, OP_AddImm, 1, 0);
|
||||
}
|
||||
|
||||
/* End the database scan loop.
|
||||
*/
|
||||
sqliteWhereEnd(pWInfo);
|
||||
|
||||
/* Open the pseudo-table used to store OLD if there are triggers.
|
||||
*/
|
||||
if( row_triggers_exist ){
|
||||
sqliteVdbeAddOp(v, OP_OpenPseudo, oldIdx, 0);
|
||||
}
|
||||
|
||||
/* 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.
|
||||
*/
|
||||
sqliteVdbeAddOp(v, OP_ListRewind, 0, 0);
|
||||
end = sqliteVdbeMakeLabel(v);
|
||||
|
||||
/* This is the beginning of the delete loop when there are
|
||||
** row triggers.
|
||||
*/
|
||||
if( row_triggers_exist ){
|
||||
addr = sqliteVdbeAddOp(v, OP_ListRead, 0, end);
|
||||
sqliteVdbeAddOp(v, OP_Dup, 0, 0);
|
||||
if( !isView ){
|
||||
sqliteVdbeAddOp(v, OP_Integer, pTab->iDb, 0);
|
||||
sqliteVdbeAddOp(v, OP_OpenRead, iCur, pTab->tnum);
|
||||
}
|
||||
sqliteVdbeAddOp(v, OP_MoveTo, iCur, 0);
|
||||
|
||||
sqliteVdbeAddOp(v, OP_Recno, iCur, 0);
|
||||
sqliteVdbeAddOp(v, OP_RowData, iCur, 0);
|
||||
sqliteVdbeAddOp(v, OP_PutIntKey, oldIdx, 0);
|
||||
if( !isView ){
|
||||
sqliteVdbeAddOp(v, OP_Close, iCur, 0);
|
||||
}
|
||||
|
||||
sqliteCodeRowTrigger(pParse, TK_DELETE, 0, TK_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_ListRead 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.
|
||||
*/
|
||||
pParse->nTab = iCur + 1;
|
||||
sqliteOpenTableAndIndices(pParse, pTab, iCur);
|
||||
|
||||
/* This is the beginning of the delete loop when there are no
|
||||
** row triggers */
|
||||
if( !row_triggers_exist ){
|
||||
addr = sqliteVdbeAddOp(v, OP_ListRead, 0, end);
|
||||
}
|
||||
|
||||
/* Delete the row */
|
||||
sqliteGenerateRowDelete(db, v, pTab, iCur, pParse->trigStack==0);
|
||||
}
|
||||
|
||||
/* If there are row triggers, close all cursors then invoke
|
||||
** the AFTER triggers
|
||||
*/
|
||||
if( row_triggers_exist ){
|
||||
if( !isView ){
|
||||
for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
|
||||
sqliteVdbeAddOp(v, OP_Close, iCur + i, pIdx->tnum);
|
||||
}
|
||||
sqliteVdbeAddOp(v, OP_Close, iCur, 0);
|
||||
}
|
||||
sqliteCodeRowTrigger(pParse, TK_DELETE, 0, TK_AFTER, pTab, -1,
|
||||
oldIdx, (pParse->trigStack)?pParse->trigStack->orconf:OE_Default,
|
||||
addr);
|
||||
}
|
||||
|
||||
/* End of the delete loop */
|
||||
sqliteVdbeAddOp(v, OP_Goto, 0, addr);
|
||||
sqliteVdbeResolveLabel(v, end);
|
||||
sqliteVdbeAddOp(v, OP_ListReset, 0, 0);
|
||||
|
||||
/* Close the cursors after the loop if there are no row triggers */
|
||||
if( !row_triggers_exist ){
|
||||
for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
|
||||
sqliteVdbeAddOp(v, OP_Close, iCur + i, pIdx->tnum);
|
||||
}
|
||||
sqliteVdbeAddOp(v, OP_Close, iCur, 0);
|
||||
pParse->nTab = iCur;
|
||||
}
|
||||
}
|
||||
sqliteVdbeAddOp(v, OP_SetCounts, 0, 0);
|
||||
sqliteEndWriteOperation(pParse);
|
||||
|
||||
/*
|
||||
** Return the number of rows that were deleted.
|
||||
*/
|
||||
if( db->flags & SQLITE_CountRows ){
|
||||
sqliteVdbeAddOp(v, OP_ColumnName, 0, 1);
|
||||
sqliteVdbeChangeP3(v, -1, "rows deleted", P3_STATIC);
|
||||
sqliteVdbeAddOp(v, OP_Callback, 1, 0);
|
||||
}
|
||||
|
||||
delete_from_cleanup:
|
||||
sqliteAuthContextPop(&sContext);
|
||||
sqliteSrcListDelete(pTabList);
|
||||
sqliteExprDelete(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 sqliteGenerateRowDelete(
|
||||
sqlite *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 = sqliteVdbeAddOp(v, OP_NotExists, iCur, 0);
|
||||
sqliteGenerateRowIndexDelete(db, v, pTab, iCur, 0);
|
||||
sqliteVdbeAddOp(v, OP_Delete, iCur,
|
||||
(count?OPFLAG_NCHANGE:0) | OPFLAG_CSCHANGE);
|
||||
sqliteVdbeChangeP2(v, addr, sqliteVdbeCurrentAddr(v));
|
||||
}
|
||||
|
||||
/*
|
||||
** 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 sqliteGenerateRowIndexDelete(
|
||||
sqlite *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){
|
||||
int j;
|
||||
if( aIdxUsed!=0 && aIdxUsed[i-1]==0 ) continue;
|
||||
sqliteVdbeAddOp(v, OP_Recno, iCur, 0);
|
||||
for(j=0; j<pIdx->nColumn; j++){
|
||||
int idx = pIdx->aiColumn[j];
|
||||
if( idx==pTab->iPKey ){
|
||||
sqliteVdbeAddOp(v, OP_Dup, j, 0);
|
||||
}else{
|
||||
sqliteVdbeAddOp(v, OP_Column, iCur, idx);
|
||||
}
|
||||
}
|
||||
sqliteVdbeAddOp(v, OP_MakeIdxKey, pIdx->nColumn, 0);
|
||||
if( db->file_format>=4 ) sqliteAddIdxKeyType(v, pIdx);
|
||||
sqliteVdbeAddOp(v, OP_IdxDelete, iCur+i, 0);
|
||||
}
|
||||
}
|
1656
sqlite/expr.c
Executable file
1656
sqlite/expr.c
Executable file
File diff suppressed because it is too large
Load Diff
646
sqlite/func.c
Executable file
646
sqlite/func.c
Executable file
@ -0,0 +1,646 @@
|
||||
/*
|
||||
** 2002 February 23
|
||||
**
|
||||
** The author disclaims copyright to this source code. In place of
|
||||
** a legal notice, here is a blessing:
|
||||
**
|
||||
** May you do good and not evil.
|
||||
** May you find forgiveness for yourself and forgive others.
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
*************************************************************************
|
||||
** This file contains the C functions that implement various SQL
|
||||
** functions of SQLite.
|
||||
**
|
||||
** There is only one exported symbol in this file - the function
|
||||
** sqliteRegisterBuildinFunctions() found at the bottom of the file.
|
||||
** All other code has file scope.
|
||||
**
|
||||
** $Id: func.c,v 1.1.1.1 2004-03-11 22:22:23 alex Exp $
|
||||
*/
|
||||
#include <ctype.h>
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include "sqliteInt.h"
|
||||
#include "os.h"
|
||||
|
||||
/*
|
||||
** Implementation of the non-aggregate min() and max() functions
|
||||
*/
|
||||
static void minmaxFunc(sqlite_func *context, int argc, const char **argv){
|
||||
const char *zBest;
|
||||
int i;
|
||||
int (*xCompare)(const char*, const char*);
|
||||
int mask; /* 0 for min() or 0xffffffff for max() */
|
||||
|
||||
if( argc==0 ) return;
|
||||
mask = (int)sqlite_user_data(context);
|
||||
zBest = argv[0];
|
||||
if( zBest==0 ) return;
|
||||
if( argv[1][0]=='n' ){
|
||||
xCompare = sqliteCompare;
|
||||
}else{
|
||||
xCompare = strcmp;
|
||||
}
|
||||
for(i=2; i<argc; i+=2){
|
||||
if( argv[i]==0 ) return;
|
||||
if( (xCompare(argv[i], zBest)^mask)<0 ){
|
||||
zBest = argv[i];
|
||||
}
|
||||
}
|
||||
sqlite_set_result_string(context, zBest, -1);
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the type of the argument.
|
||||
*/
|
||||
static void typeofFunc(sqlite_func *context, int argc, const char **argv){
|
||||
assert( argc==2 );
|
||||
sqlite_set_result_string(context, argv[1], -1);
|
||||
}
|
||||
|
||||
/*
|
||||
** Implementation of the length() function
|
||||
*/
|
||||
static void lengthFunc(sqlite_func *context, int argc, const char **argv){
|
||||
const char *z;
|
||||
int len;
|
||||
|
||||
assert( argc==1 );
|
||||
z = argv[0];
|
||||
if( z==0 ) return;
|
||||
#ifdef SQLITE_UTF8
|
||||
for(len=0; *z; z++){ if( (0xc0&*z)!=0x80 ) len++; }
|
||||
#else
|
||||
len = strlen(z);
|
||||
#endif
|
||||
sqlite_set_result_int(context, len);
|
||||
}
|
||||
|
||||
/*
|
||||
** Implementation of the abs() function
|
||||
*/
|
||||
static void absFunc(sqlite_func *context, int argc, const char **argv){
|
||||
const char *z;
|
||||
assert( argc==1 );
|
||||
z = argv[0];
|
||||
if( z==0 ) return;
|
||||
if( z[0]=='-' && isdigit(z[1]) ) z++;
|
||||
sqlite_set_result_string(context, z, -1);
|
||||
}
|
||||
|
||||
/*
|
||||
** Implementation of the substr() function
|
||||
*/
|
||||
static void substrFunc(sqlite_func *context, int argc, const char **argv){
|
||||
const char *z;
|
||||
#ifdef SQLITE_UTF8
|
||||
const char *z2;
|
||||
int i;
|
||||
#endif
|
||||
int p1, p2, len;
|
||||
assert( argc==3 );
|
||||
z = argv[0];
|
||||
if( z==0 ) return;
|
||||
p1 = atoi(argv[1]?argv[1]:0);
|
||||
p2 = atoi(argv[2]?argv[2]:0);
|
||||
#ifdef SQLITE_UTF8
|
||||
for(len=0, z2=z; *z2; z2++){ if( (0xc0&*z2)!=0x80 ) len++; }
|
||||
#else
|
||||
len = strlen(z);
|
||||
#endif
|
||||
if( p1<0 ){
|
||||
p1 += len;
|
||||
if( p1<0 ){
|
||||
p2 += p1;
|
||||
p1 = 0;
|
||||
}
|
||||
}else if( p1>0 ){
|
||||
p1--;
|
||||
}
|
||||
if( p1+p2>len ){
|
||||
p2 = len-p1;
|
||||
}
|
||||
#ifdef SQLITE_UTF8
|
||||
for(i=0; i<p1 && z[i]; i++){
|
||||
if( (z[i]&0xc0)==0x80 ) p1++;
|
||||
}
|
||||
while( z[i] && (z[i]&0xc0)==0x80 ){ i++; p1++; }
|
||||
for(; i<p1+p2 && z[i]; i++){
|
||||
if( (z[i]&0xc0)==0x80 ) p2++;
|
||||
}
|
||||
while( z[i] && (z[i]&0xc0)==0x80 ){ i++; p2++; }
|
||||
#endif
|
||||
if( p2<0 ) p2 = 0;
|
||||
sqlite_set_result_string(context, &z[p1], p2);
|
||||
}
|
||||
|
||||
/*
|
||||
** Implementation of the round() function
|
||||
*/
|
||||
static void roundFunc(sqlite_func *context, int argc, const char **argv){
|
||||
int n;
|
||||
double r;
|
||||
char zBuf[100];
|
||||
assert( argc==1 || argc==2 );
|
||||
if( argv[0]==0 || (argc==2 && argv[1]==0) ) return;
|
||||
n = argc==2 ? atoi(argv[1]) : 0;
|
||||
if( n>30 ) n = 30;
|
||||
if( n<0 ) n = 0;
|
||||
r = sqliteAtoF(argv[0], 0);
|
||||
sprintf(zBuf,"%.*f",n,r);
|
||||
sqlite_set_result_string(context, zBuf, -1);
|
||||
}
|
||||
|
||||
/*
|
||||
** Implementation of the upper() and lower() SQL functions.
|
||||
*/
|
||||
static void upperFunc(sqlite_func *context, int argc, const char **argv){
|
||||
char *z;
|
||||
int i;
|
||||
if( argc<1 || argv[0]==0 ) return;
|
||||
z = sqlite_set_result_string(context, argv[0], -1);
|
||||
if( z==0 ) return;
|
||||
for(i=0; z[i]; i++){
|
||||
if( islower(z[i]) ) z[i] = toupper(z[i]);
|
||||
}
|
||||
}
|
||||
static void lowerFunc(sqlite_func *context, int argc, const char **argv){
|
||||
char *z;
|
||||
int i;
|
||||
if( argc<1 || argv[0]==0 ) return;
|
||||
z = sqlite_set_result_string(context, argv[0], -1);
|
||||
if( z==0 ) return;
|
||||
for(i=0; z[i]; i++){
|
||||
if( isupper(z[i]) ) z[i] = tolower(z[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Implementation of the IFNULL(), NVL(), and COALESCE() functions.
|
||||
** All three do the same thing. They return the first non-NULL
|
||||
** argument.
|
||||
*/
|
||||
static void ifnullFunc(sqlite_func *context, int argc, const char **argv){
|
||||
int i;
|
||||
for(i=0; i<argc; i++){
|
||||
if( argv[i] ){
|
||||
sqlite_set_result_string(context, argv[i], -1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Implementation of random(). Return a random integer.
|
||||
*/
|
||||
static void randomFunc(sqlite_func *context, int argc, const char **argv){
|
||||
int r;
|
||||
sqliteRandomness(sizeof(r), &r);
|
||||
sqlite_set_result_int(context, r);
|
||||
}
|
||||
|
||||
/*
|
||||
** Implementation of the last_insert_rowid() SQL function. The return
|
||||
** value is the same as the sqlite_last_insert_rowid() API function.
|
||||
*/
|
||||
static void last_insert_rowid(sqlite_func *context, int arg, const char **argv){
|
||||
sqlite *db = sqlite_user_data(context);
|
||||
sqlite_set_result_int(context, sqlite_last_insert_rowid(db));
|
||||
}
|
||||
|
||||
/*
|
||||
** Implementation of the change_count() SQL function. The return
|
||||
** value is the same as the sqlite_changes() API function.
|
||||
*/
|
||||
static void change_count(sqlite_func *context, int arg, const char **argv){
|
||||
sqlite *db = sqlite_user_data(context);
|
||||
sqlite_set_result_int(context, sqlite_changes(db));
|
||||
}
|
||||
|
||||
/*
|
||||
** Implementation of the last_statement_change_count() SQL function. The
|
||||
** return value is the same as the sqlite_last_statement_changes() API function.
|
||||
*/
|
||||
static void last_statement_change_count(sqlite_func *context, int arg,
|
||||
const char **argv){
|
||||
sqlite *db = sqlite_user_data(context);
|
||||
sqlite_set_result_int(context, sqlite_last_statement_changes(db));
|
||||
}
|
||||
|
||||
/*
|
||||
** Implementation of the like() SQL function. This function implements
|
||||
** the build-in LIKE operator. The first argument to the function is the
|
||||
** string and the second argument is the pattern. So, the SQL statements:
|
||||
**
|
||||
** A LIKE B
|
||||
**
|
||||
** is implemented as like(A,B).
|
||||
*/
|
||||
static void likeFunc(sqlite_func *context, int arg, const char **argv){
|
||||
if( argv[0]==0 || argv[1]==0 ) return;
|
||||
sqlite_set_result_int(context,
|
||||
sqliteLikeCompare((const unsigned char*)argv[0],
|
||||
(const unsigned char*)argv[1]));
|
||||
}
|
||||
|
||||
/*
|
||||
** Implementation of the glob() SQL function. This function implements
|
||||
** the build-in GLOB operator. The first argument to the function is the
|
||||
** string and the second argument is the pattern. So, the SQL statements:
|
||||
**
|
||||
** A GLOB B
|
||||
**
|
||||
** is implemented as glob(A,B).
|
||||
*/
|
||||
static void globFunc(sqlite_func *context, int arg, const char **argv){
|
||||
if( argv[0]==0 || argv[1]==0 ) return;
|
||||
sqlite_set_result_int(context,
|
||||
sqliteGlobCompare((const unsigned char*)argv[0],
|
||||
(const unsigned char*)argv[1]));
|
||||
}
|
||||
|
||||
/*
|
||||
** Implementation of the NULLIF(x,y) function. The result is the first
|
||||
** argument if the arguments are different. The result is NULL if the
|
||||
** arguments are equal to each other.
|
||||
*/
|
||||
static void nullifFunc(sqlite_func *context, int argc, const char **argv){
|
||||
if( argv[0]!=0 && sqliteCompare(argv[0],argv[1])!=0 ){
|
||||
sqlite_set_result_string(context, argv[0], -1);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Implementation of the VERSION(*) function. The result is the version
|
||||
** of the SQLite library that is running.
|
||||
*/
|
||||
static void versionFunc(sqlite_func *context, int argc, const char **argv){
|
||||
sqlite_set_result_string(context, sqlite_version, -1);
|
||||
}
|
||||
|
||||
/*
|
||||
** EXPERIMENTAL - This is not an official function. The interface may
|
||||
** change. This function may disappear. Do not write code that depends
|
||||
** on this function.
|
||||
**
|
||||
** Implementation of the QUOTE() function. This function takes a single
|
||||
** argument. If the argument is numeric, the return value is the same as
|
||||
** the argument. If the argument is NULL, the return value is the string
|
||||
** "NULL". Otherwise, the argument is enclosed in single quotes with
|
||||
** single-quote escapes.
|
||||
*/
|
||||
static void quoteFunc(sqlite_func *context, int argc, const char **argv){
|
||||
if( argc<1 ) return;
|
||||
if( argv[0]==0 ){
|
||||
sqlite_set_result_string(context, "NULL", 4);
|
||||
}else if( sqliteIsNumber(argv[0]) ){
|
||||
sqlite_set_result_string(context, argv[0], -1);
|
||||
}else{
|
||||
int i,j,n;
|
||||
char *z;
|
||||
for(i=n=0; argv[0][i]; i++){ if( argv[0][i]=='\'' ) n++; }
|
||||
z = sqliteMalloc( i+n+3 );
|
||||
if( z==0 ) return;
|
||||
z[0] = '\'';
|
||||
for(i=0, j=1; argv[0][i]; i++){
|
||||
z[j++] = argv[0][i];
|
||||
if( argv[0][i]=='\'' ){
|
||||
z[j++] = '\'';
|
||||
}
|
||||
}
|
||||
z[j++] = '\'';
|
||||
z[j] = 0;
|
||||
sqlite_set_result_string(context, z, j);
|
||||
sqliteFree(z);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef SQLITE_SOUNDEX
|
||||
/*
|
||||
** Compute the soundex encoding of a word.
|
||||
*/
|
||||
static void soundexFunc(sqlite_func *context, int argc, const char **argv){
|
||||
char zResult[8];
|
||||
const char *zIn;
|
||||
int i, j;
|
||||
static const unsigned char iCode[] = {
|
||||
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, 1, 2, 3, 0, 1, 2, 0, 0, 2, 2, 4, 5, 5, 0,
|
||||
1, 2, 6, 2, 3, 0, 1, 0, 2, 0, 2, 0, 0, 0, 0, 0,
|
||||
0, 0, 1, 2, 3, 0, 1, 2, 0, 0, 2, 2, 4, 5, 5, 0,
|
||||
1, 2, 6, 2, 3, 0, 1, 0, 2, 0, 2, 0, 0, 0, 0, 0,
|
||||
};
|
||||
assert( argc==1 );
|
||||
zIn = argv[0];
|
||||
for(i=0; zIn[i] && !isalpha(zIn[i]); i++){}
|
||||
if( zIn[i] ){
|
||||
zResult[0] = toupper(zIn[i]);
|
||||
for(j=1; j<4 && zIn[i]; i++){
|
||||
int code = iCode[zIn[i]&0x7f];
|
||||
if( code>0 ){
|
||||
zResult[j++] = code + '0';
|
||||
}
|
||||
}
|
||||
while( j<4 ){
|
||||
zResult[j++] = '0';
|
||||
}
|
||||
zResult[j] = 0;
|
||||
sqlite_set_result_string(context, zResult, 4);
|
||||
}else{
|
||||
sqlite_set_result_string(context, "?000", 4);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_TEST
|
||||
/*
|
||||
** This function generates a string of random characters. Used for
|
||||
** generating test data.
|
||||
*/
|
||||
static void randStr(sqlite_func *context, int argc, const char **argv){
|
||||
static const unsigned char zSrc[] =
|
||||
"abcdefghijklmnopqrstuvwxyz"
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
"0123456789"
|
||||
".-!,:*^+=_|?/<> ";
|
||||
int iMin, iMax, n, r, i;
|
||||
unsigned char zBuf[1000];
|
||||
if( argc>=1 ){
|
||||
iMin = atoi(argv[0]);
|
||||
if( iMin<0 ) iMin = 0;
|
||||
if( iMin>=sizeof(zBuf) ) iMin = sizeof(zBuf)-1;
|
||||
}else{
|
||||
iMin = 1;
|
||||
}
|
||||
if( argc>=2 ){
|
||||
iMax = atoi(argv[1]);
|
||||
if( iMax<iMin ) iMax = iMin;
|
||||
if( iMax>=sizeof(zBuf) ) iMax = sizeof(zBuf)-1;
|
||||
}else{
|
||||
iMax = 50;
|
||||
}
|
||||
n = iMin;
|
||||
if( iMax>iMin ){
|
||||
sqliteRandomness(sizeof(r), &r);
|
||||
r &= 0x7fffffff;
|
||||
n += r%(iMax + 1 - iMin);
|
||||
}
|
||||
assert( n<sizeof(zBuf) );
|
||||
sqliteRandomness(n, zBuf);
|
||||
for(i=0; i<n; i++){
|
||||
zBuf[i] = zSrc[zBuf[i]%(sizeof(zSrc)-1)];
|
||||
}
|
||||
zBuf[n] = 0;
|
||||
sqlite_set_result_string(context, zBuf, n);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
** An instance of the following structure holds the context of a
|
||||
** sum() or avg() aggregate computation.
|
||||
*/
|
||||
typedef struct SumCtx SumCtx;
|
||||
struct SumCtx {
|
||||
double sum; /* Sum of terms */
|
||||
int cnt; /* Number of elements summed */
|
||||
};
|
||||
|
||||
/*
|
||||
** Routines used to compute the sum or average.
|
||||
*/
|
||||
static void sumStep(sqlite_func *context, int argc, const char **argv){
|
||||
SumCtx *p;
|
||||
if( argc<1 ) return;
|
||||
p = sqlite_aggregate_context(context, sizeof(*p));
|
||||
if( p && argv[0] ){
|
||||
p->sum += sqliteAtoF(argv[0], 0);
|
||||
p->cnt++;
|
||||
}
|
||||
}
|
||||
static void sumFinalize(sqlite_func *context){
|
||||
SumCtx *p;
|
||||
p = sqlite_aggregate_context(context, sizeof(*p));
|
||||
sqlite_set_result_double(context, p ? p->sum : 0.0);
|
||||
}
|
||||
static void avgFinalize(sqlite_func *context){
|
||||
SumCtx *p;
|
||||
p = sqlite_aggregate_context(context, sizeof(*p));
|
||||
if( p && p->cnt>0 ){
|
||||
sqlite_set_result_double(context, p->sum/(double)p->cnt);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** An instance of the following structure holds the context of a
|
||||
** variance or standard deviation computation.
|
||||
*/
|
||||
typedef struct StdDevCtx StdDevCtx;
|
||||
struct StdDevCtx {
|
||||
double sum; /* Sum of terms */
|
||||
double sum2; /* Sum of the squares of terms */
|
||||
int cnt; /* Number of terms counted */
|
||||
};
|
||||
|
||||
#if 0 /* Omit because math library is required */
|
||||
/*
|
||||
** Routines used to compute the standard deviation as an aggregate.
|
||||
*/
|
||||
static void stdDevStep(sqlite_func *context, int argc, const char **argv){
|
||||
StdDevCtx *p;
|
||||
double x;
|
||||
if( argc<1 ) return;
|
||||
p = sqlite_aggregate_context(context, sizeof(*p));
|
||||
if( p && argv[0] ){
|
||||
x = sqliteAtoF(argv[0], 0);
|
||||
p->sum += x;
|
||||
p->sum2 += x*x;
|
||||
p->cnt++;
|
||||
}
|
||||
}
|
||||
static void stdDevFinalize(sqlite_func *context){
|
||||
double rN = sqlite_aggregate_count(context);
|
||||
StdDevCtx *p = sqlite_aggregate_context(context, sizeof(*p));
|
||||
if( p && p->cnt>1 ){
|
||||
double rCnt = cnt;
|
||||
sqlite_set_result_double(context,
|
||||
sqrt((p->sum2 - p->sum*p->sum/rCnt)/(rCnt-1.0)));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
** The following structure keeps track of state information for the
|
||||
** count() aggregate function.
|
||||
*/
|
||||
typedef struct CountCtx CountCtx;
|
||||
struct CountCtx {
|
||||
int n;
|
||||
};
|
||||
|
||||
/*
|
||||
** Routines to implement the count() aggregate function.
|
||||
*/
|
||||
static void countStep(sqlite_func *context, int argc, const char **argv){
|
||||
CountCtx *p;
|
||||
p = sqlite_aggregate_context(context, sizeof(*p));
|
||||
if( (argc==0 || argv[0]) && p ){
|
||||
p->n++;
|
||||
}
|
||||
}
|
||||
static void countFinalize(sqlite_func *context){
|
||||
CountCtx *p;
|
||||
p = sqlite_aggregate_context(context, sizeof(*p));
|
||||
sqlite_set_result_int(context, p ? p->n : 0);
|
||||
}
|
||||
|
||||
/*
|
||||
** This function tracks state information for the min() and max()
|
||||
** aggregate functions.
|
||||
*/
|
||||
typedef struct MinMaxCtx MinMaxCtx;
|
||||
struct MinMaxCtx {
|
||||
char *z; /* The best so far */
|
||||
char zBuf[28]; /* Space that can be used for storage */
|
||||
};
|
||||
|
||||
/*
|
||||
** Routines to implement min() and max() aggregate functions.
|
||||
*/
|
||||
static void minmaxStep(sqlite_func *context, int argc, const char **argv){
|
||||
MinMaxCtx *p;
|
||||
int (*xCompare)(const char*, const char*);
|
||||
int mask; /* 0 for min() or 0xffffffff for max() */
|
||||
|
||||
assert( argc==2 );
|
||||
if( argv[1][0]=='n' ){
|
||||
xCompare = sqliteCompare;
|
||||
}else{
|
||||
xCompare = strcmp;
|
||||
}
|
||||
mask = (int)sqlite_user_data(context);
|
||||
p = sqlite_aggregate_context(context, sizeof(*p));
|
||||
if( p==0 || argc<1 || argv[0]==0 ) return;
|
||||
if( p->z==0 || (xCompare(argv[0],p->z)^mask)<0 ){
|
||||
int len;
|
||||
if( !p->zBuf[0] ){
|
||||
sqliteFree(p->z);
|
||||
}
|
||||
len = strlen(argv[0]);
|
||||
if( len < sizeof(p->zBuf)-1 ){
|
||||
p->z = &p->zBuf[1];
|
||||
p->zBuf[0] = 1;
|
||||
}else{
|
||||
p->z = sqliteMalloc( len+1 );
|
||||
p->zBuf[0] = 0;
|
||||
if( p->z==0 ) return;
|
||||
}
|
||||
strcpy(p->z, argv[0]);
|
||||
}
|
||||
}
|
||||
static void minMaxFinalize(sqlite_func *context){
|
||||
MinMaxCtx *p;
|
||||
p = sqlite_aggregate_context(context, sizeof(*p));
|
||||
if( p && p->z ){
|
||||
sqlite_set_result_string(context, p->z, strlen(p->z));
|
||||
}
|
||||
if( p && !p->zBuf[0] ){
|
||||
sqliteFree(p->z);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** This function registered all of the above C functions as SQL
|
||||
** functions. This should be the only routine in this file with
|
||||
** external linkage.
|
||||
*/
|
||||
void sqliteRegisterBuiltinFunctions(sqlite *db){
|
||||
static struct {
|
||||
char *zName;
|
||||
signed char nArg;
|
||||
signed char dataType;
|
||||
u8 argType; /* 0: none. 1: db 2: (-1) */
|
||||
void (*xFunc)(sqlite_func*,int,const char**);
|
||||
} aFuncs[] = {
|
||||
{ "min", -1, SQLITE_ARGS, 0, minmaxFunc },
|
||||
{ "min", 0, 0, 0, 0 },
|
||||
{ "max", -1, SQLITE_ARGS, 2, minmaxFunc },
|
||||
{ "max", 0, 0, 2, 0 },
|
||||
{ "typeof", 1, SQLITE_TEXT, 0, typeofFunc },
|
||||
{ "length", 1, SQLITE_NUMERIC, 0, lengthFunc },
|
||||
{ "substr", 3, SQLITE_TEXT, 0, substrFunc },
|
||||
{ "abs", 1, SQLITE_NUMERIC, 0, absFunc },
|
||||
{ "round", 1, SQLITE_NUMERIC, 0, roundFunc },
|
||||
{ "round", 2, SQLITE_NUMERIC, 0, roundFunc },
|
||||
{ "upper", 1, SQLITE_TEXT, 0, upperFunc },
|
||||
{ "lower", 1, SQLITE_TEXT, 0, lowerFunc },
|
||||
{ "coalesce", -1, SQLITE_ARGS, 0, ifnullFunc },
|
||||
{ "coalesce", 0, 0, 0, 0 },
|
||||
{ "coalesce", 1, 0, 0, 0 },
|
||||
{ "ifnull", 2, SQLITE_ARGS, 0, ifnullFunc },
|
||||
{ "random", -1, SQLITE_NUMERIC, 0, randomFunc },
|
||||
{ "like", 2, SQLITE_NUMERIC, 0, likeFunc },
|
||||
{ "glob", 2, SQLITE_NUMERIC, 0, globFunc },
|
||||
{ "nullif", 2, SQLITE_ARGS, 0, nullifFunc },
|
||||
{ "sqlite_version",0,SQLITE_TEXT, 0, versionFunc},
|
||||
{ "quote", 1, SQLITE_ARGS, 0, quoteFunc },
|
||||
{ "last_insert_rowid", 0, SQLITE_NUMERIC, 1, last_insert_rowid },
|
||||
{ "change_count", 0, SQLITE_NUMERIC, 1, change_count },
|
||||
{ "last_statement_change_count",
|
||||
0, SQLITE_NUMERIC, 1, last_statement_change_count },
|
||||
#ifdef SQLITE_SOUNDEX
|
||||
{ "soundex", 1, SQLITE_TEXT, 0, soundexFunc},
|
||||
#endif
|
||||
#ifdef SQLITE_TEST
|
||||
{ "randstr", 2, SQLITE_TEXT, 0, randStr },
|
||||
#endif
|
||||
};
|
||||
static struct {
|
||||
char *zName;
|
||||
signed char nArg;
|
||||
signed char dataType;
|
||||
u8 argType;
|
||||
void (*xStep)(sqlite_func*,int,const char**);
|
||||
void (*xFinalize)(sqlite_func*);
|
||||
} aAggs[] = {
|
||||
{ "min", 1, 0, 0, minmaxStep, minMaxFinalize },
|
||||
{ "max", 1, 0, 2, minmaxStep, minMaxFinalize },
|
||||
{ "sum", 1, SQLITE_NUMERIC, 0, sumStep, sumFinalize },
|
||||
{ "avg", 1, SQLITE_NUMERIC, 0, sumStep, avgFinalize },
|
||||
{ "count", 0, SQLITE_NUMERIC, 0, countStep, countFinalize },
|
||||
{ "count", 1, SQLITE_NUMERIC, 0, countStep, countFinalize },
|
||||
#if 0
|
||||
{ "stddev", 1, SQLITE_NUMERIC, 0, stdDevStep, stdDevFinalize },
|
||||
#endif
|
||||
};
|
||||
static const char *azTypeFuncs[] = { "min", "max", "typeof" };
|
||||
int i;
|
||||
|
||||
for(i=0; i<sizeof(aFuncs)/sizeof(aFuncs[0]); i++){
|
||||
void *pArg = aFuncs[i].argType==2 ? (void*)(-1) : db;
|
||||
sqlite_create_function(db, aFuncs[i].zName,
|
||||
aFuncs[i].nArg, aFuncs[i].xFunc, pArg);
|
||||
if( aFuncs[i].xFunc ){
|
||||
sqlite_function_type(db, aFuncs[i].zName, aFuncs[i].dataType);
|
||||
}
|
||||
}
|
||||
for(i=0; i<sizeof(aAggs)/sizeof(aAggs[0]); i++){
|
||||
void *pArg = aAggs[i].argType==2 ? (void*)(-1) : db;
|
||||
sqlite_create_aggregate(db, aAggs[i].zName,
|
||||
aAggs[i].nArg, aAggs[i].xStep, aAggs[i].xFinalize, pArg);
|
||||
sqlite_function_type(db, aAggs[i].zName, aAggs[i].dataType);
|
||||
}
|
||||
for(i=0; i<sizeof(azTypeFuncs)/sizeof(azTypeFuncs[0]); i++){
|
||||
int n = strlen(azTypeFuncs[i]);
|
||||
FuncDef *p = sqliteHashFind(&db->aFunc, azTypeFuncs[i], n);
|
||||
while( p ){
|
||||
p->includeTypes = 1;
|
||||
p = p->pNext;
|
||||
}
|
||||
}
|
||||
sqliteRegisterDateTimeFunctions(db);
|
||||
}
|
356
sqlite/hash.c
Executable file
356
sqlite/hash.c
Executable file
@ -0,0 +1,356 @@
|
||||
/*
|
||||
** 2001 September 22
|
||||
**
|
||||
** The author disclaims copyright to this source code. In place of
|
||||
** a legal notice, here is a blessing:
|
||||
**
|
||||
** May you do good and not evil.
|
||||
** May you find forgiveness for yourself and forgive others.
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
*************************************************************************
|
||||
** This is the implementation of generic hash-tables
|
||||
** used in SQLite.
|
||||
**
|
||||
** $Id: hash.c,v 1.1.1.1 2004-03-11 22:22:23 alex Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include <assert.h>
|
||||
|
||||
/* Turn bulk memory into a hash table object by initializing the
|
||||
** fields of the Hash structure.
|
||||
**
|
||||
** "new" is a pointer to the hash table that is to be initialized.
|
||||
** keyClass is one of the constants SQLITE_HASH_INT, SQLITE_HASH_POINTER,
|
||||
** SQLITE_HASH_BINARY, or SQLITE_HASH_STRING. The value of keyClass
|
||||
** determines what kind of key the hash table will use. "copyKey" is
|
||||
** true if the hash table should make its own private copy of keys and
|
||||
** false if it should just use the supplied pointer. CopyKey only makes
|
||||
** sense for SQLITE_HASH_STRING and SQLITE_HASH_BINARY and is ignored
|
||||
** for other key classes.
|
||||
*/
|
||||
void sqliteHashInit(Hash *new, int keyClass, int copyKey){
|
||||
assert( new!=0 );
|
||||
assert( keyClass>=SQLITE_HASH_INT && keyClass<=SQLITE_HASH_BINARY );
|
||||
new->keyClass = keyClass;
|
||||
new->copyKey = copyKey &&
|
||||
(keyClass==SQLITE_HASH_STRING || keyClass==SQLITE_HASH_BINARY);
|
||||
new->first = 0;
|
||||
new->count = 0;
|
||||
new->htsize = 0;
|
||||
new->ht = 0;
|
||||
}
|
||||
|
||||
/* Remove all entries from a hash table. Reclaim all memory.
|
||||
** Call this routine to delete a hash table or to reset a hash table
|
||||
** to the empty state.
|
||||
*/
|
||||
void sqliteHashClear(Hash *pH){
|
||||
HashElem *elem; /* For looping over all elements of the table */
|
||||
|
||||
assert( pH!=0 );
|
||||
elem = pH->first;
|
||||
pH->first = 0;
|
||||
if( pH->ht ) sqliteFree(pH->ht);
|
||||
pH->ht = 0;
|
||||
pH->htsize = 0;
|
||||
while( elem ){
|
||||
HashElem *next_elem = elem->next;
|
||||
if( pH->copyKey && elem->pKey ){
|
||||
sqliteFree(elem->pKey);
|
||||
}
|
||||
sqliteFree(elem);
|
||||
elem = next_elem;
|
||||
}
|
||||
pH->count = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Hash and comparison functions when the mode is SQLITE_HASH_INT
|
||||
*/
|
||||
static int intHash(const void *pKey, int nKey){
|
||||
return nKey ^ (nKey<<8) ^ (nKey>>8);
|
||||
}
|
||||
static int intCompare(const void *pKey1, int n1, const void *pKey2, int n2){
|
||||
return n2 - n1;
|
||||
}
|
||||
|
||||
#if 0 /* NOT USED */
|
||||
/*
|
||||
** Hash and comparison functions when the mode is SQLITE_HASH_POINTER
|
||||
*/
|
||||
static int ptrHash(const void *pKey, int nKey){
|
||||
uptr x = Addr(pKey);
|
||||
return x ^ (x<<8) ^ (x>>8);
|
||||
}
|
||||
static int ptrCompare(const void *pKey1, int n1, const void *pKey2, int n2){
|
||||
if( pKey1==pKey2 ) return 0;
|
||||
if( pKey1<pKey2 ) return -1;
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Hash and comparison functions when the mode is SQLITE_HASH_STRING
|
||||
*/
|
||||
static int strHash(const void *pKey, int nKey){
|
||||
return sqliteHashNoCase((const char*)pKey, nKey);
|
||||
}
|
||||
static int strCompare(const void *pKey1, int n1, const void *pKey2, int n2){
|
||||
if( n1!=n2 ) return n2-n1;
|
||||
return sqliteStrNICmp((const char*)pKey1,(const char*)pKey2,n1);
|
||||
}
|
||||
|
||||
/*
|
||||
** Hash and comparison functions when the mode is SQLITE_HASH_BINARY
|
||||
*/
|
||||
static int binHash(const void *pKey, int nKey){
|
||||
int h = 0;
|
||||
const char *z = (const char *)pKey;
|
||||
while( nKey-- > 0 ){
|
||||
h = (h<<3) ^ h ^ *(z++);
|
||||
}
|
||||
return h & 0x7fffffff;
|
||||
}
|
||||
static int binCompare(const void *pKey1, int n1, const void *pKey2, int n2){
|
||||
if( n1!=n2 ) return n2-n1;
|
||||
return memcmp(pKey1,pKey2,n1);
|
||||
}
|
||||
|
||||
/*
|
||||
** Return a pointer to the appropriate hash function given the key class.
|
||||
**
|
||||
** The C syntax in this function definition may be unfamilar to some
|
||||
** programmers, so we provide the following additional explanation:
|
||||
**
|
||||
** The name of the function is "hashFunction". The function takes a
|
||||
** single parameter "keyClass". The return value of hashFunction()
|
||||
** is a pointer to another function. Specifically, the return value
|
||||
** of hashFunction() is a pointer to a function that takes two parameters
|
||||
** with types "const void*" and "int" and returns an "int".
|
||||
*/
|
||||
static int (*hashFunction(int keyClass))(const void*,int){
|
||||
switch( keyClass ){
|
||||
case SQLITE_HASH_INT: return &intHash;
|
||||
/* case SQLITE_HASH_POINTER: return &ptrHash; // NOT USED */
|
||||
case SQLITE_HASH_STRING: return &strHash;
|
||||
case SQLITE_HASH_BINARY: return &binHash;;
|
||||
default: break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return a pointer to the appropriate hash function given the key class.
|
||||
**
|
||||
** For help in interpreted the obscure C code in the function definition,
|
||||
** see the header comment on the previous function.
|
||||
*/
|
||||
static int (*compareFunction(int keyClass))(const void*,int,const void*,int){
|
||||
switch( keyClass ){
|
||||
case SQLITE_HASH_INT: return &intCompare;
|
||||
/* case SQLITE_HASH_POINTER: return &ptrCompare; // NOT USED */
|
||||
case SQLITE_HASH_STRING: return &strCompare;
|
||||
case SQLITE_HASH_BINARY: return &binCompare;
|
||||
default: break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Resize the hash table so that it cantains "new_size" buckets.
|
||||
** "new_size" must be a power of 2. The hash table might fail
|
||||
** to resize if sqliteMalloc() fails.
|
||||
*/
|
||||
static void rehash(Hash *pH, int new_size){
|
||||
struct _ht *new_ht; /* The new hash table */
|
||||
HashElem *elem, *next_elem; /* For looping over existing elements */
|
||||
HashElem *x; /* Element being copied to new hash table */
|
||||
int (*xHash)(const void*,int); /* The hash function */
|
||||
|
||||
assert( (new_size & (new_size-1))==0 );
|
||||
new_ht = (struct _ht *)sqliteMalloc( new_size*sizeof(struct _ht) );
|
||||
if( new_ht==0 ) return;
|
||||
if( pH->ht ) sqliteFree(pH->ht);
|
||||
pH->ht = new_ht;
|
||||
pH->htsize = new_size;
|
||||
xHash = hashFunction(pH->keyClass);
|
||||
for(elem=pH->first, pH->first=0; elem; elem = next_elem){
|
||||
int h = (*xHash)(elem->pKey, elem->nKey) & (new_size-1);
|
||||
next_elem = elem->next;
|
||||
x = new_ht[h].chain;
|
||||
if( x ){
|
||||
elem->next = x;
|
||||
elem->prev = x->prev;
|
||||
if( x->prev ) x->prev->next = elem;
|
||||
else pH->first = elem;
|
||||
x->prev = elem;
|
||||
}else{
|
||||
elem->next = pH->first;
|
||||
if( pH->first ) pH->first->prev = elem;
|
||||
elem->prev = 0;
|
||||
pH->first = elem;
|
||||
}
|
||||
new_ht[h].chain = elem;
|
||||
new_ht[h].count++;
|
||||
}
|
||||
}
|
||||
|
||||
/* This function (for internal use only) locates an element in an
|
||||
** hash table that matches the given key. The hash for this key has
|
||||
** already been computed and is passed as the 4th parameter.
|
||||
*/
|
||||
static HashElem *findElementGivenHash(
|
||||
const Hash *pH, /* The pH to be searched */
|
||||
const void *pKey, /* The key we are searching for */
|
||||
int nKey,
|
||||
int h /* The hash for this key. */
|
||||
){
|
||||
HashElem *elem; /* Used to loop thru the element list */
|
||||
int count; /* Number of elements left to test */
|
||||
int (*xCompare)(const void*,int,const void*,int); /* comparison function */
|
||||
|
||||
if( pH->ht ){
|
||||
elem = pH->ht[h].chain;
|
||||
count = pH->ht[h].count;
|
||||
xCompare = compareFunction(pH->keyClass);
|
||||
while( count-- && elem ){
|
||||
if( (*xCompare)(elem->pKey,elem->nKey,pKey,nKey)==0 ){
|
||||
return elem;
|
||||
}
|
||||
elem = elem->next;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Remove a single entry from the hash table given a pointer to that
|
||||
** element and a hash on the element's key.
|
||||
*/
|
||||
static void removeElementGivenHash(
|
||||
Hash *pH, /* The pH containing "elem" */
|
||||
HashElem* elem, /* The element to be removed from the pH */
|
||||
int h /* Hash value for the element */
|
||||
){
|
||||
if( elem->prev ){
|
||||
elem->prev->next = elem->next;
|
||||
}else{
|
||||
pH->first = elem->next;
|
||||
}
|
||||
if( elem->next ){
|
||||
elem->next->prev = elem->prev;
|
||||
}
|
||||
if( pH->ht[h].chain==elem ){
|
||||
pH->ht[h].chain = elem->next;
|
||||
}
|
||||
pH->ht[h].count--;
|
||||
if( pH->ht[h].count<=0 ){
|
||||
pH->ht[h].chain = 0;
|
||||
}
|
||||
if( pH->copyKey && elem->pKey ){
|
||||
sqliteFree(elem->pKey);
|
||||
}
|
||||
sqliteFree( elem );
|
||||
pH->count--;
|
||||
}
|
||||
|
||||
/* Attempt to locate an element of the hash table pH with a key
|
||||
** that matches pKey,nKey. Return the data for this element if it is
|
||||
** found, or NULL if there is no match.
|
||||
*/
|
||||
void *sqliteHashFind(const Hash *pH, const void *pKey, int nKey){
|
||||
int h; /* A hash on key */
|
||||
HashElem *elem; /* The element that matches key */
|
||||
int (*xHash)(const void*,int); /* The hash function */
|
||||
|
||||
if( pH==0 || pH->ht==0 ) return 0;
|
||||
xHash = hashFunction(pH->keyClass);
|
||||
assert( xHash!=0 );
|
||||
h = (*xHash)(pKey,nKey);
|
||||
assert( (pH->htsize & (pH->htsize-1))==0 );
|
||||
elem = findElementGivenHash(pH,pKey,nKey, h & (pH->htsize-1));
|
||||
return elem ? elem->data : 0;
|
||||
}
|
||||
|
||||
/* Insert an element into the hash table pH. The key is pKey,nKey
|
||||
** and the data is "data".
|
||||
**
|
||||
** If no element exists with a matching key, then a new
|
||||
** element is created. A copy of the key is made if the copyKey
|
||||
** flag is set. NULL is returned.
|
||||
**
|
||||
** If another element already exists with the same key, then the
|
||||
** new data replaces the old data and the old data is returned.
|
||||
** The key is not copied in this instance. If a malloc fails, then
|
||||
** the new data is returned and the hash table is unchanged.
|
||||
**
|
||||
** If the "data" parameter to this function is NULL, then the
|
||||
** element corresponding to "key" is removed from the hash table.
|
||||
*/
|
||||
void *sqliteHashInsert(Hash *pH, const void *pKey, int nKey, void *data){
|
||||
int hraw; /* Raw hash value of the key */
|
||||
int h; /* the hash of the key modulo hash table size */
|
||||
HashElem *elem; /* Used to loop thru the element list */
|
||||
HashElem *new_elem; /* New element added to the pH */
|
||||
int (*xHash)(const void*,int); /* The hash function */
|
||||
|
||||
assert( pH!=0 );
|
||||
xHash = hashFunction(pH->keyClass);
|
||||
assert( xHash!=0 );
|
||||
hraw = (*xHash)(pKey, nKey);
|
||||
assert( (pH->htsize & (pH->htsize-1))==0 );
|
||||
h = hraw & (pH->htsize-1);
|
||||
elem = findElementGivenHash(pH,pKey,nKey,h);
|
||||
if( elem ){
|
||||
void *old_data = elem->data;
|
||||
if( data==0 ){
|
||||
removeElementGivenHash(pH,elem,h);
|
||||
}else{
|
||||
elem->data = data;
|
||||
}
|
||||
return old_data;
|
||||
}
|
||||
if( data==0 ) return 0;
|
||||
new_elem = (HashElem*)sqliteMalloc( sizeof(HashElem) );
|
||||
if( new_elem==0 ) return data;
|
||||
if( pH->copyKey && pKey!=0 ){
|
||||
new_elem->pKey = sqliteMallocRaw( nKey );
|
||||
if( new_elem->pKey==0 ){
|
||||
sqliteFree(new_elem);
|
||||
return data;
|
||||
}
|
||||
memcpy((void*)new_elem->pKey, pKey, nKey);
|
||||
}else{
|
||||
new_elem->pKey = (void*)pKey;
|
||||
}
|
||||
new_elem->nKey = nKey;
|
||||
pH->count++;
|
||||
if( pH->htsize==0 ) rehash(pH,8);
|
||||
if( pH->htsize==0 ){
|
||||
pH->count = 0;
|
||||
sqliteFree(new_elem);
|
||||
return data;
|
||||
}
|
||||
if( pH->count > pH->htsize ){
|
||||
rehash(pH,pH->htsize*2);
|
||||
}
|
||||
assert( (pH->htsize & (pH->htsize-1))==0 );
|
||||
h = hraw & (pH->htsize-1);
|
||||
elem = pH->ht[h].chain;
|
||||
if( elem ){
|
||||
new_elem->next = elem;
|
||||
new_elem->prev = elem->prev;
|
||||
if( elem->prev ){ elem->prev->next = new_elem; }
|
||||
else { pH->first = new_elem; }
|
||||
elem->prev = new_elem;
|
||||
}else{
|
||||
new_elem->next = pH->first;
|
||||
new_elem->prev = 0;
|
||||
if( pH->first ){ pH->first->prev = new_elem; }
|
||||
pH->first = new_elem;
|
||||
}
|
||||
pH->ht[h].count++;
|
||||
pH->ht[h].chain = new_elem;
|
||||
new_elem->data = data;
|
||||
return 0;
|
||||
}
|
109
sqlite/hash.h
Executable file
109
sqlite/hash.h
Executable file
@ -0,0 +1,109 @@
|
||||
/*
|
||||
** 2001 September 22
|
||||
**
|
||||
** The author disclaims copyright to this source code. In place of
|
||||
** a legal notice, here is a blessing:
|
||||
**
|
||||
** May you do good and not evil.
|
||||
** May you find forgiveness for yourself and forgive others.
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
*************************************************************************
|
||||
** This is the header file for the generic hash-table implemenation
|
||||
** used in SQLite.
|
||||
**
|
||||
** $Id: hash.h,v 1.1.1.1 2004-03-11 22:22:23 alex Exp $
|
||||
*/
|
||||
#ifndef _SQLITE_HASH_H_
|
||||
#define _SQLITE_HASH_H_
|
||||
|
||||
/* Forward declarations of structures. */
|
||||
typedef struct Hash Hash;
|
||||
typedef struct HashElem HashElem;
|
||||
|
||||
/* A complete hash table is an instance of the following structure.
|
||||
** The internals of this structure are intended to be opaque -- client
|
||||
** code should not attempt to access or modify the fields of this structure
|
||||
** directly. Change this structure only by using the routines below.
|
||||
** However, many of the "procedures" and "functions" for modifying and
|
||||
** accessing this structure are really macros, so we can't really make
|
||||
** this structure opaque.
|
||||
*/
|
||||
struct Hash {
|
||||
char keyClass; /* SQLITE_HASH_INT, _POINTER, _STRING, _BINARY */
|
||||
char copyKey; /* True if copy of key made on insert */
|
||||
int count; /* Number of entries in this table */
|
||||
HashElem *first; /* The first element of the array */
|
||||
int htsize; /* Number of buckets in the hash table */
|
||||
struct _ht { /* the hash table */
|
||||
int count; /* Number of entries with this hash */
|
||||
HashElem *chain; /* Pointer to first entry with this hash */
|
||||
} *ht;
|
||||
};
|
||||
|
||||
/* Each element in the hash table is an instance of the following
|
||||
** structure. All elements are stored on a single doubly-linked list.
|
||||
**
|
||||
** Again, this structure is intended to be opaque, but it can't really
|
||||
** be opaque because it is used by macros.
|
||||
*/
|
||||
struct HashElem {
|
||||
HashElem *next, *prev; /* Next and previous elements in the table */
|
||||
void *data; /* Data associated with this element */
|
||||
void *pKey; int nKey; /* Key associated with this element */
|
||||
};
|
||||
|
||||
/*
|
||||
** There are 4 different modes of operation for a hash table:
|
||||
**
|
||||
** SQLITE_HASH_INT nKey is used as the key and pKey is ignored.
|
||||
**
|
||||
** SQLITE_HASH_POINTER pKey is used as the key and nKey is ignored.
|
||||
**
|
||||
** SQLITE_HASH_STRING pKey points to a string that is nKey bytes long
|
||||
** (including the null-terminator, if any). Case
|
||||
** is ignored in comparisons.
|
||||
**
|
||||
** SQLITE_HASH_BINARY pKey points to binary data nKey bytes long.
|
||||
** memcmp() is used to compare keys.
|
||||
**
|
||||
** A copy of the key is made for SQLITE_HASH_STRING and SQLITE_HASH_BINARY
|
||||
** if the copyKey parameter to HashInit is 1.
|
||||
*/
|
||||
#define SQLITE_HASH_INT 1
|
||||
/* #define SQLITE_HASH_POINTER 2 // NOT USED */
|
||||
#define SQLITE_HASH_STRING 3
|
||||
#define SQLITE_HASH_BINARY 4
|
||||
|
||||
/*
|
||||
** Access routines. To delete, insert a NULL pointer.
|
||||
*/
|
||||
void sqliteHashInit(Hash*, int keytype, int copyKey);
|
||||
void *sqliteHashInsert(Hash*, const void *pKey, int nKey, void *pData);
|
||||
void *sqliteHashFind(const Hash*, const void *pKey, int nKey);
|
||||
void sqliteHashClear(Hash*);
|
||||
|
||||
/*
|
||||
** Macros for looping over all elements of a hash table. The idiom is
|
||||
** like this:
|
||||
**
|
||||
** Hash h;
|
||||
** HashElem *p;
|
||||
** ...
|
||||
** for(p=sqliteHashFirst(&h); p; p=sqliteHashNext(p)){
|
||||
** SomeStructure *pData = sqliteHashData(p);
|
||||
** // do something with pData
|
||||
** }
|
||||
*/
|
||||
#define sqliteHashFirst(H) ((H)->first)
|
||||
#define sqliteHashNext(E) ((E)->next)
|
||||
#define sqliteHashData(E) ((E)->data)
|
||||
#define sqliteHashKey(E) ((E)->pKey)
|
||||
#define sqliteHashKeysize(E) ((E)->nKey)
|
||||
|
||||
/*
|
||||
** Number of entries in a hash table
|
||||
*/
|
||||
#define sqliteHashCount(H) ((H)->count)
|
||||
|
||||
#endif /* _SQLITE_HASH_H_ */
|
919
sqlite/insert.c
Executable file
919
sqlite/insert.c
Executable file
@ -0,0 +1,919 @@
|
||||
/*
|
||||
** 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 INSERT statements in SQLite.
|
||||
**
|
||||
** $Id: insert.c,v 1.1.1.1 2004-03-11 22:22:24 alex Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
|
||||
/*
|
||||
** This routine is call to handle SQL of the following forms:
|
||||
**
|
||||
** insert into TABLE (IDLIST) values(EXPRLIST)
|
||||
** insert into TABLE (IDLIST) select
|
||||
**
|
||||
** The IDLIST following the table name is always optional. If omitted,
|
||||
** then a list of all columns for the table is substituted. The IDLIST
|
||||
** appears in the pColumn parameter. pColumn is NULL if IDLIST is omitted.
|
||||
**
|
||||
** The pList parameter holds EXPRLIST in the first form of the INSERT
|
||||
** statement above, and pSelect is NULL. For the second form, pList is
|
||||
** NULL and pSelect is a pointer to the select statement used to generate
|
||||
** data for the insert.
|
||||
**
|
||||
** The code generated follows one of three templates. For a simple
|
||||
** select with data coming from a VALUES clause, the code executes
|
||||
** once straight down through. The template looks like this:
|
||||
**
|
||||
** open write cursor to <table> and its indices
|
||||
** puts VALUES clause expressions onto the stack
|
||||
** write the resulting record into <table>
|
||||
** cleanup
|
||||
**
|
||||
** If the statement is of the form
|
||||
**
|
||||
** INSERT INTO <table> SELECT ...
|
||||
**
|
||||
** And the SELECT clause does not read from <table> at any time, then
|
||||
** the generated code follows this template:
|
||||
**
|
||||
** goto B
|
||||
** A: setup for the SELECT
|
||||
** loop over the tables in the SELECT
|
||||
** gosub C
|
||||
** end loop
|
||||
** cleanup after the SELECT
|
||||
** goto D
|
||||
** B: open write cursor to <table> and its indices
|
||||
** goto A
|
||||
** C: insert the select result into <table>
|
||||
** return
|
||||
** D: cleanup
|
||||
**
|
||||
** The third template is used if the insert statement takes its
|
||||
** values from a SELECT but the data is being inserted into a table
|
||||
** that is also read as part of the SELECT. In the third form,
|
||||
** we have to use a intermediate table to store the results of
|
||||
** the select. The template is like this:
|
||||
**
|
||||
** goto B
|
||||
** A: setup for the SELECT
|
||||
** loop over the tables in the SELECT
|
||||
** gosub C
|
||||
** end loop
|
||||
** cleanup after the SELECT
|
||||
** goto D
|
||||
** C: insert the select result into the intermediate table
|
||||
** return
|
||||
** B: open a cursor to an intermediate table
|
||||
** goto A
|
||||
** D: open write cursor to <table> and its indices
|
||||
** loop over the intermediate table
|
||||
** transfer values form intermediate table into <table>
|
||||
** end the loop
|
||||
** cleanup
|
||||
*/
|
||||
void sqliteInsert(
|
||||
Parse *pParse, /* Parser context */
|
||||
SrcList *pTabList, /* Name of table into which we are inserting */
|
||||
ExprList *pList, /* List of values to be inserted */
|
||||
Select *pSelect, /* A SELECT statement to use as the data source */
|
||||
IdList *pColumn, /* Column names corresponding to IDLIST. */
|
||||
int onError /* How to handle constraint errors */
|
||||
){
|
||||
Table *pTab; /* The table to insert into */
|
||||
char *zTab; /* Name of the table into which we are inserting */
|
||||
const char *zDb; /* Name of the database holding this table */
|
||||
int i, j, idx; /* Loop counters */
|
||||
Vdbe *v; /* Generate code into this virtual machine */
|
||||
Index *pIdx; /* For looping over indices of the table */
|
||||
int nColumn; /* Number of columns in the data */
|
||||
int base; /* VDBE Cursor number for pTab */
|
||||
int iCont, iBreak; /* Beginning and end of the loop over srcTab */
|
||||
sqlite *db; /* The main database structure */
|
||||
int keyColumn = -1; /* Column that is the INTEGER PRIMARY KEY */
|
||||
int endOfLoop; /* Label for the end of the insertion loop */
|
||||
int useTempTable; /* Store SELECT results in intermediate table */
|
||||
int srcTab; /* Data comes from this temporary cursor if >=0 */
|
||||
int iSelectLoop; /* Address of code that implements the SELECT */
|
||||
int iCleanup; /* Address of the cleanup code */
|
||||
int iInsertBlock; /* Address of the subroutine used to insert data */
|
||||
int iCntMem; /* Memory cell used for the row counter */
|
||||
int isView; /* True if attempting to insert into a view */
|
||||
|
||||
int row_triggers_exist = 0; /* True if there are FOR EACH ROW triggers */
|
||||
int before_triggers; /* True if there are BEFORE triggers */
|
||||
int after_triggers; /* True if there are AFTER triggers */
|
||||
int newIdx = -1; /* Cursor for the NEW table */
|
||||
|
||||
if( pParse->nErr || sqlite_malloc_failed ) goto insert_cleanup;
|
||||
db = pParse->db;
|
||||
|
||||
/* Locate the table into which we will be inserting new information.
|
||||
*/
|
||||
assert( pTabList->nSrc==1 );
|
||||
zTab = pTabList->a[0].zName;
|
||||
if( zTab==0 ) goto insert_cleanup;
|
||||
pTab = sqliteSrcListLookup(pParse, pTabList);
|
||||
if( pTab==0 ){
|
||||
goto insert_cleanup;
|
||||
}
|
||||
assert( pTab->iDb<db->nDb );
|
||||
zDb = db->aDb[pTab->iDb].zName;
|
||||
if( sqliteAuthCheck(pParse, SQLITE_INSERT, pTab->zName, 0, zDb) ){
|
||||
goto insert_cleanup;
|
||||
}
|
||||
|
||||
/* Ensure that:
|
||||
* (a) the table is not read-only,
|
||||
* (b) that if it is a view then ON INSERT triggers exist
|
||||
*/
|
||||
before_triggers = sqliteTriggersExist(pParse, pTab->pTrigger, TK_INSERT,
|
||||
TK_BEFORE, TK_ROW, 0);
|
||||
after_triggers = sqliteTriggersExist(pParse, pTab->pTrigger, TK_INSERT,
|
||||
TK_AFTER, TK_ROW, 0);
|
||||
row_triggers_exist = before_triggers || after_triggers;
|
||||
isView = pTab->pSelect!=0;
|
||||
if( sqliteIsReadOnly(pParse, pTab, before_triggers) ){
|
||||
goto insert_cleanup;
|
||||
}
|
||||
if( pTab==0 ) goto insert_cleanup;
|
||||
|
||||
/* If pTab is really a view, make sure it has been initialized.
|
||||
*/
|
||||
if( isView && sqliteViewGetColumnNames(pParse, pTab) ){
|
||||
goto insert_cleanup;
|
||||
}
|
||||
|
||||
/* Allocate a VDBE
|
||||
*/
|
||||
v = sqliteGetVdbe(pParse);
|
||||
if( v==0 ) goto insert_cleanup;
|
||||
sqliteBeginWriteOperation(pParse, pSelect || row_triggers_exist, pTab->iDb);
|
||||
|
||||
/* if there are row triggers, allocate a temp table for new.* references. */
|
||||
if( row_triggers_exist ){
|
||||
newIdx = pParse->nTab++;
|
||||
}
|
||||
|
||||
/* Figure out how many columns of data are supplied. If the data
|
||||
** is coming from a SELECT statement, then this step also generates
|
||||
** all the code to implement the SELECT statement and invoke a subroutine
|
||||
** to process each row of the result. (Template 2.) If the SELECT
|
||||
** statement uses the the table that is being inserted into, then the
|
||||
** subroutine is also coded here. That subroutine stores the SELECT
|
||||
** results in a temporary table. (Template 3.)
|
||||
*/
|
||||
if( pSelect ){
|
||||
/* Data is coming from a SELECT. Generate code to implement that SELECT
|
||||
*/
|
||||
int rc, iInitCode;
|
||||
iInitCode = sqliteVdbeAddOp(v, OP_Goto, 0, 0);
|
||||
iSelectLoop = sqliteVdbeCurrentAddr(v);
|
||||
iInsertBlock = sqliteVdbeMakeLabel(v);
|
||||
rc = sqliteSelect(pParse, pSelect, SRT_Subroutine, iInsertBlock, 0,0,0);
|
||||
if( rc || pParse->nErr || sqlite_malloc_failed ) goto insert_cleanup;
|
||||
iCleanup = sqliteVdbeMakeLabel(v);
|
||||
sqliteVdbeAddOp(v, OP_Goto, 0, iCleanup);
|
||||
assert( pSelect->pEList );
|
||||
nColumn = pSelect->pEList->nExpr;
|
||||
|
||||
/* Set useTempTable to TRUE if the result of the SELECT statement
|
||||
** should be written into a temporary table. Set to FALSE if each
|
||||
** row of the SELECT can be written directly into the result table.
|
||||
**
|
||||
** A temp table must be used if the table being updated is also one
|
||||
** of the tables being read by the SELECT statement. Also use a
|
||||
** temp table in the case of row triggers.
|
||||
*/
|
||||
if( row_triggers_exist ){
|
||||
useTempTable = 1;
|
||||
}else{
|
||||
int addr = sqliteVdbeFindOp(v, OP_OpenRead, pTab->tnum);
|
||||
useTempTable = 0;
|
||||
if( addr>0 ){
|
||||
VdbeOp *pOp = sqliteVdbeGetOp(v, addr-2);
|
||||
if( pOp->opcode==OP_Integer && pOp->p1==pTab->iDb ){
|
||||
useTempTable = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( useTempTable ){
|
||||
/* Generate the subroutine that SELECT calls to process each row of
|
||||
** the result. Store the result in a temporary table
|
||||
*/
|
||||
srcTab = pParse->nTab++;
|
||||
sqliteVdbeResolveLabel(v, iInsertBlock);
|
||||
sqliteVdbeAddOp(v, OP_MakeRecord, nColumn, 0);
|
||||
sqliteVdbeAddOp(v, OP_NewRecno, srcTab, 0);
|
||||
sqliteVdbeAddOp(v, OP_Pull, 1, 0);
|
||||
sqliteVdbeAddOp(v, OP_PutIntKey, srcTab, 0);
|
||||
sqliteVdbeAddOp(v, OP_Return, 0, 0);
|
||||
|
||||
/* The following code runs first because the GOTO at the very top
|
||||
** of the program jumps to it. Create the temporary table, then jump
|
||||
** back up and execute the SELECT code above.
|
||||
*/
|
||||
sqliteVdbeChangeP2(v, iInitCode, sqliteVdbeCurrentAddr(v));
|
||||
sqliteVdbeAddOp(v, OP_OpenTemp, srcTab, 0);
|
||||
sqliteVdbeAddOp(v, OP_Goto, 0, iSelectLoop);
|
||||
sqliteVdbeResolveLabel(v, iCleanup);
|
||||
}else{
|
||||
sqliteVdbeChangeP2(v, iInitCode, sqliteVdbeCurrentAddr(v));
|
||||
}
|
||||
}else{
|
||||
/* This is the case if the data for the INSERT is coming from a VALUES
|
||||
** clause
|
||||
*/
|
||||
SrcList dummy;
|
||||
assert( pList!=0 );
|
||||
srcTab = -1;
|
||||
useTempTable = 0;
|
||||
assert( pList );
|
||||
nColumn = pList->nExpr;
|
||||
dummy.nSrc = 0;
|
||||
for(i=0; i<nColumn; i++){
|
||||
if( sqliteExprResolveIds(pParse, &dummy, 0, pList->a[i].pExpr) ){
|
||||
goto insert_cleanup;
|
||||
}
|
||||
if( sqliteExprCheck(pParse, pList->a[i].pExpr, 0, 0) ){
|
||||
goto insert_cleanup;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Make sure the number of columns in the source data matches the number
|
||||
** of columns to be inserted into the table.
|
||||
*/
|
||||
if( pColumn==0 && nColumn!=pTab->nCol ){
|
||||
sqliteErrorMsg(pParse,
|
||||
"table %S has %d columns but %d values were supplied",
|
||||
pTabList, 0, pTab->nCol, nColumn);
|
||||
goto insert_cleanup;
|
||||
}
|
||||
if( pColumn!=0 && nColumn!=pColumn->nId ){
|
||||
sqliteErrorMsg(pParse, "%d values for %d columns", nColumn, pColumn->nId);
|
||||
goto insert_cleanup;
|
||||
}
|
||||
|
||||
/* If the INSERT statement included an IDLIST term, then make sure
|
||||
** all elements of the IDLIST really are columns of the table and
|
||||
** remember the column indices.
|
||||
**
|
||||
** If the table has an INTEGER PRIMARY KEY column and that column
|
||||
** is named in the IDLIST, then record in the keyColumn variable
|
||||
** the index into IDLIST of the primary key column. keyColumn is
|
||||
** the index of the primary key as it appears in IDLIST, not as
|
||||
** is appears in the original table. (The index of the primary
|
||||
** key in the original table is pTab->iPKey.)
|
||||
*/
|
||||
if( pColumn ){
|
||||
for(i=0; i<pColumn->nId; i++){
|
||||
pColumn->a[i].idx = -1;
|
||||
}
|
||||
for(i=0; i<pColumn->nId; i++){
|
||||
for(j=0; j<pTab->nCol; j++){
|
||||
if( sqliteStrICmp(pColumn->a[i].zName, pTab->aCol[j].zName)==0 ){
|
||||
pColumn->a[i].idx = j;
|
||||
if( j==pTab->iPKey ){
|
||||
keyColumn = i;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( j>=pTab->nCol ){
|
||||
if( sqliteIsRowid(pColumn->a[i].zName) ){
|
||||
keyColumn = i;
|
||||
}else{
|
||||
sqliteErrorMsg(pParse, "table %S has no column named %s",
|
||||
pTabList, 0, pColumn->a[i].zName);
|
||||
pParse->nErr++;
|
||||
goto insert_cleanup;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* If there is no IDLIST term but the table has an integer primary
|
||||
** key, the set the keyColumn variable to the primary key column index
|
||||
** in the original table definition.
|
||||
*/
|
||||
if( pColumn==0 ){
|
||||
keyColumn = pTab->iPKey;
|
||||
}
|
||||
|
||||
/* Open the temp table for FOR EACH ROW triggers
|
||||
*/
|
||||
if( row_triggers_exist ){
|
||||
sqliteVdbeAddOp(v, OP_OpenPseudo, newIdx, 0);
|
||||
}
|
||||
|
||||
/* Initialize the count of rows to be inserted
|
||||
*/
|
||||
if( db->flags & SQLITE_CountRows ){
|
||||
iCntMem = pParse->nMem++;
|
||||
sqliteVdbeAddOp(v, OP_Integer, 0, 0);
|
||||
sqliteVdbeAddOp(v, OP_MemStore, iCntMem, 1);
|
||||
}
|
||||
|
||||
/* Open tables and indices if there are no row triggers */
|
||||
if( !row_triggers_exist ){
|
||||
base = pParse->nTab;
|
||||
idx = sqliteOpenTableAndIndices(pParse, pTab, base);
|
||||
pParse->nTab += idx;
|
||||
}
|
||||
|
||||
/* If the data source is a temporary table, then we have to create
|
||||
** a loop because there might be multiple rows of data. If the data
|
||||
** source is a subroutine call from the SELECT statement, then we need
|
||||
** to launch the SELECT statement processing.
|
||||
*/
|
||||
if( useTempTable ){
|
||||
iBreak = sqliteVdbeMakeLabel(v);
|
||||
sqliteVdbeAddOp(v, OP_Rewind, srcTab, iBreak);
|
||||
iCont = sqliteVdbeCurrentAddr(v);
|
||||
}else if( pSelect ){
|
||||
sqliteVdbeAddOp(v, OP_Goto, 0, iSelectLoop);
|
||||
sqliteVdbeResolveLabel(v, iInsertBlock);
|
||||
}
|
||||
|
||||
/* Run the BEFORE and INSTEAD OF triggers, if there are any
|
||||
*/
|
||||
endOfLoop = sqliteVdbeMakeLabel(v);
|
||||
if( before_triggers ){
|
||||
|
||||
/* build the NEW.* reference row. Note that if there is an INTEGER
|
||||
** PRIMARY KEY into which a NULL is being inserted, that NULL will be
|
||||
** translated into a unique ID for the row. But on a BEFORE trigger,
|
||||
** we do not know what the unique ID will be (because the insert has
|
||||
** not happened yet) so we substitute a rowid of -1
|
||||
*/
|
||||
if( keyColumn<0 ){
|
||||
sqliteVdbeAddOp(v, OP_Integer, -1, 0);
|
||||
}else if( useTempTable ){
|
||||
sqliteVdbeAddOp(v, OP_Column, srcTab, keyColumn);
|
||||
}else if( pSelect ){
|
||||
sqliteVdbeAddOp(v, OP_Dup, nColumn - keyColumn - 1, 1);
|
||||
}else{
|
||||
sqliteExprCode(pParse, pList->a[keyColumn].pExpr);
|
||||
sqliteVdbeAddOp(v, OP_NotNull, -1, sqliteVdbeCurrentAddr(v)+3);
|
||||
sqliteVdbeAddOp(v, OP_Pop, 1, 0);
|
||||
sqliteVdbeAddOp(v, OP_Integer, -1, 0);
|
||||
sqliteVdbeAddOp(v, OP_MustBeInt, 0, 0);
|
||||
}
|
||||
|
||||
/* Create the new column data
|
||||
*/
|
||||
for(i=0; i<pTab->nCol; i++){
|
||||
if( pColumn==0 ){
|
||||
j = i;
|
||||
}else{
|
||||
for(j=0; j<pColumn->nId; j++){
|
||||
if( pColumn->a[j].idx==i ) break;
|
||||
}
|
||||
}
|
||||
if( pColumn && j>=pColumn->nId ){
|
||||
sqliteVdbeOp3(v, OP_String, 0, 0, pTab->aCol[i].zDflt, P3_STATIC);
|
||||
}else if( useTempTable ){
|
||||
sqliteVdbeAddOp(v, OP_Column, srcTab, j);
|
||||
}else if( pSelect ){
|
||||
sqliteVdbeAddOp(v, OP_Dup, nColumn-j-1, 1);
|
||||
}else{
|
||||
sqliteExprCode(pParse, pList->a[j].pExpr);
|
||||
}
|
||||
}
|
||||
sqliteVdbeAddOp(v, OP_MakeRecord, pTab->nCol, 0);
|
||||
sqliteVdbeAddOp(v, OP_PutIntKey, newIdx, 0);
|
||||
|
||||
/* Fire BEFORE or INSTEAD OF triggers */
|
||||
if( sqliteCodeRowTrigger(pParse, TK_INSERT, 0, TK_BEFORE, pTab,
|
||||
newIdx, -1, onError, endOfLoop) ){
|
||||
goto insert_cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
/* If any triggers exists, the opening of tables and indices is deferred
|
||||
** until now.
|
||||
*/
|
||||
if( row_triggers_exist && !isView ){
|
||||
base = pParse->nTab;
|
||||
idx = sqliteOpenTableAndIndices(pParse, pTab, base);
|
||||
pParse->nTab += idx;
|
||||
}
|
||||
|
||||
/* Push the record number for the new entry onto the stack. The
|
||||
** record number is a randomly generate integer created by NewRecno
|
||||
** except when the table has an INTEGER PRIMARY KEY column, in which
|
||||
** case the record number is the same as that column.
|
||||
*/
|
||||
if( !isView ){
|
||||
if( keyColumn>=0 ){
|
||||
if( useTempTable ){
|
||||
sqliteVdbeAddOp(v, OP_Column, srcTab, keyColumn);
|
||||
}else if( pSelect ){
|
||||
sqliteVdbeAddOp(v, OP_Dup, nColumn - keyColumn - 1, 1);
|
||||
}else{
|
||||
sqliteExprCode(pParse, pList->a[keyColumn].pExpr);
|
||||
}
|
||||
/* If the PRIMARY KEY expression is NULL, then use OP_NewRecno
|
||||
** to generate a unique primary key value.
|
||||
*/
|
||||
sqliteVdbeAddOp(v, OP_NotNull, -1, sqliteVdbeCurrentAddr(v)+3);
|
||||
sqliteVdbeAddOp(v, OP_Pop, 1, 0);
|
||||
sqliteVdbeAddOp(v, OP_NewRecno, base, 0);
|
||||
sqliteVdbeAddOp(v, OP_MustBeInt, 0, 0);
|
||||
}else{
|
||||
sqliteVdbeAddOp(v, OP_NewRecno, base, 0);
|
||||
}
|
||||
|
||||
/* Push onto the stack, data for all columns of the new entry, beginning
|
||||
** with the first column.
|
||||
*/
|
||||
for(i=0; i<pTab->nCol; i++){
|
||||
if( i==pTab->iPKey ){
|
||||
/* The value of the INTEGER PRIMARY KEY column is always a NULL.
|
||||
** Whenever this column is read, the record number will be substituted
|
||||
** in its place. So will fill this column with a NULL to avoid
|
||||
** taking up data space with information that will never be used. */
|
||||
sqliteVdbeAddOp(v, OP_String, 0, 0);
|
||||
continue;
|
||||
}
|
||||
if( pColumn==0 ){
|
||||
j = i;
|
||||
}else{
|
||||
for(j=0; j<pColumn->nId; j++){
|
||||
if( pColumn->a[j].idx==i ) break;
|
||||
}
|
||||
}
|
||||
if( pColumn && j>=pColumn->nId ){
|
||||
sqliteVdbeOp3(v, OP_String, 0, 0, pTab->aCol[i].zDflt, P3_STATIC);
|
||||
}else if( useTempTable ){
|
||||
sqliteVdbeAddOp(v, OP_Column, srcTab, j);
|
||||
}else if( pSelect ){
|
||||
sqliteVdbeAddOp(v, OP_Dup, i+nColumn-j, 1);
|
||||
}else{
|
||||
sqliteExprCode(pParse, pList->a[j].pExpr);
|
||||
}
|
||||
}
|
||||
|
||||
/* Generate code to check constraints and generate index keys and
|
||||
** do the insertion.
|
||||
*/
|
||||
sqliteGenerateConstraintChecks(pParse, pTab, base, 0, keyColumn>=0,
|
||||
0, onError, endOfLoop);
|
||||
sqliteCompleteInsertion(pParse, pTab, base, 0,0,0,
|
||||
after_triggers ? newIdx : -1);
|
||||
}
|
||||
|
||||
/* Update the count of rows that are inserted
|
||||
*/
|
||||
if( (db->flags & SQLITE_CountRows)!=0 ){
|
||||
sqliteVdbeAddOp(v, OP_MemIncr, iCntMem, 0);
|
||||
}
|
||||
|
||||
if( row_triggers_exist ){
|
||||
/* Close all tables opened */
|
||||
if( !isView ){
|
||||
sqliteVdbeAddOp(v, OP_Close, base, 0);
|
||||
for(idx=1, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, idx++){
|
||||
sqliteVdbeAddOp(v, OP_Close, idx+base, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/* Code AFTER triggers */
|
||||
if( sqliteCodeRowTrigger(pParse, TK_INSERT, 0, TK_AFTER, pTab, newIdx, -1,
|
||||
onError, endOfLoop) ){
|
||||
goto insert_cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
/* The bottom of the loop, if the data source is a SELECT statement
|
||||
*/
|
||||
sqliteVdbeResolveLabel(v, endOfLoop);
|
||||
if( useTempTable ){
|
||||
sqliteVdbeAddOp(v, OP_Next, srcTab, iCont);
|
||||
sqliteVdbeResolveLabel(v, iBreak);
|
||||
sqliteVdbeAddOp(v, OP_Close, srcTab, 0);
|
||||
}else if( pSelect ){
|
||||
sqliteVdbeAddOp(v, OP_Pop, nColumn, 0);
|
||||
sqliteVdbeAddOp(v, OP_Return, 0, 0);
|
||||
sqliteVdbeResolveLabel(v, iCleanup);
|
||||
}
|
||||
|
||||
if( !row_triggers_exist ){
|
||||
/* Close all tables opened */
|
||||
sqliteVdbeAddOp(v, OP_Close, base, 0);
|
||||
for(idx=1, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, idx++){
|
||||
sqliteVdbeAddOp(v, OP_Close, idx+base, 0);
|
||||
}
|
||||
}
|
||||
|
||||
sqliteVdbeAddOp(v, OP_SetCounts, 0, 0);
|
||||
sqliteEndWriteOperation(pParse);
|
||||
|
||||
/*
|
||||
** Return the number of rows inserted.
|
||||
*/
|
||||
if( db->flags & SQLITE_CountRows ){
|
||||
sqliteVdbeOp3(v, OP_ColumnName, 0, 1, "rows inserted", P3_STATIC);
|
||||
sqliteVdbeAddOp(v, OP_MemLoad, iCntMem, 0);
|
||||
sqliteVdbeAddOp(v, OP_Callback, 1, 0);
|
||||
}
|
||||
|
||||
insert_cleanup:
|
||||
sqliteSrcListDelete(pTabList);
|
||||
if( pList ) sqliteExprListDelete(pList);
|
||||
if( pSelect ) sqliteSelectDelete(pSelect);
|
||||
sqliteIdListDelete(pColumn);
|
||||
}
|
||||
|
||||
/*
|
||||
** Generate code to do a constraint check prior to an INSERT or an UPDATE.
|
||||
**
|
||||
** When this routine is called, the stack contains (from bottom to top)
|
||||
** the following values:
|
||||
**
|
||||
** 1. The recno of the row to be updated before the update. This
|
||||
** value is omitted unless we are doing an UPDATE that involves a
|
||||
** change to the record number.
|
||||
**
|
||||
** 2. The recno of the row after the update.
|
||||
**
|
||||
** 3. The data in the first column of the entry after the update.
|
||||
**
|
||||
** i. Data from middle columns...
|
||||
**
|
||||
** N. The data in the last column of the entry after the update.
|
||||
**
|
||||
** The old recno shown as entry (1) above is omitted unless both isUpdate
|
||||
** and recnoChng are 1. isUpdate is true for UPDATEs and false for
|
||||
** INSERTs and recnoChng is true if the record number is being changed.
|
||||
**
|
||||
** The code generated by this routine pushes additional entries onto
|
||||
** the stack which are the keys for new index entries for the new record.
|
||||
** The order of index keys is the same as the order of the indices on
|
||||
** the pTable->pIndex list. A key is only created for index i if
|
||||
** aIdxUsed!=0 and aIdxUsed[i]!=0.
|
||||
**
|
||||
** This routine also generates code to check constraints. NOT NULL,
|
||||
** CHECK, and UNIQUE constraints are all checked. If a constraint fails,
|
||||
** then the appropriate action is performed. There are five possible
|
||||
** actions: ROLLBACK, ABORT, FAIL, REPLACE, and IGNORE.
|
||||
**
|
||||
** Constraint type Action What Happens
|
||||
** --------------- ---------- ----------------------------------------
|
||||
** any ROLLBACK The current transaction is rolled back and
|
||||
** sqlite_exec() returns immediately with a
|
||||
** return code of SQLITE_CONSTRAINT.
|
||||
**
|
||||
** any ABORT Back out changes from the current command
|
||||
** only (do not do a complete rollback) then
|
||||
** cause sqlite_exec() to return immediately
|
||||
** with SQLITE_CONSTRAINT.
|
||||
**
|
||||
** any FAIL Sqlite_exec() returns immediately with a
|
||||
** return code of SQLITE_CONSTRAINT. The
|
||||
** transaction is not rolled back and any
|
||||
** prior changes are retained.
|
||||
**
|
||||
** any IGNORE The record number and data is popped from
|
||||
** the stack and there is an immediate jump
|
||||
** to label ignoreDest.
|
||||
**
|
||||
** NOT NULL REPLACE The NULL value is replace by the default
|
||||
** value for that column. If the default value
|
||||
** is NULL, the action is the same as ABORT.
|
||||
**
|
||||
** UNIQUE REPLACE The other row that conflicts with the row
|
||||
** being inserted is removed.
|
||||
**
|
||||
** CHECK REPLACE Illegal. The results in an exception.
|
||||
**
|
||||
** Which action to take is determined by the overrideError parameter.
|
||||
** Or if overrideError==OE_Default, then the pParse->onError parameter
|
||||
** is used. Or if pParse->onError==OE_Default then the onError value
|
||||
** for the constraint is used.
|
||||
**
|
||||
** The calling routine must open a read/write cursor for pTab with
|
||||
** cursor number "base". All indices of pTab must also have open
|
||||
** read/write cursors with cursor number base+i for the i-th cursor.
|
||||
** Except, if there is no possibility of a REPLACE action then
|
||||
** cursors do not need to be open for indices where aIdxUsed[i]==0.
|
||||
**
|
||||
** If the isUpdate flag is true, it means that the "base" cursor is
|
||||
** initially pointing to an entry that is being updated. The isUpdate
|
||||
** flag causes extra code to be generated so that the "base" cursor
|
||||
** is still pointing at the same entry after the routine returns.
|
||||
** Without the isUpdate flag, the "base" cursor might be moved.
|
||||
*/
|
||||
void sqliteGenerateConstraintChecks(
|
||||
Parse *pParse, /* The parser context */
|
||||
Table *pTab, /* the table into which we are inserting */
|
||||
int base, /* Index of a read/write cursor pointing at pTab */
|
||||
char *aIdxUsed, /* Which indices are used. NULL means all are used */
|
||||
int recnoChng, /* True if the record number will change */
|
||||
int isUpdate, /* True for UPDATE, False for INSERT */
|
||||
int overrideError, /* Override onError to this if not OE_Default */
|
||||
int ignoreDest /* Jump to this label on an OE_Ignore resolution */
|
||||
){
|
||||
int i;
|
||||
Vdbe *v;
|
||||
int nCol;
|
||||
int onError;
|
||||
int addr;
|
||||
int extra;
|
||||
int iCur;
|
||||
Index *pIdx;
|
||||
int seenReplace = 0;
|
||||
int jumpInst1, jumpInst2;
|
||||
int contAddr;
|
||||
int hasTwoRecnos = (isUpdate && recnoChng);
|
||||
|
||||
v = sqliteGetVdbe(pParse);
|
||||
assert( v!=0 );
|
||||
assert( pTab->pSelect==0 ); /* This table is not a VIEW */
|
||||
nCol = pTab->nCol;
|
||||
|
||||
/* Test all NOT NULL constraints.
|
||||
*/
|
||||
for(i=0; i<nCol; i++){
|
||||
if( i==pTab->iPKey ){
|
||||
continue;
|
||||
}
|
||||
onError = pTab->aCol[i].notNull;
|
||||
if( onError==OE_None ) continue;
|
||||
if( overrideError!=OE_Default ){
|
||||
onError = overrideError;
|
||||
}else if( pParse->db->onError!=OE_Default ){
|
||||
onError = pParse->db->onError;
|
||||
}else if( onError==OE_Default ){
|
||||
onError = OE_Abort;
|
||||
}
|
||||
if( onError==OE_Replace && pTab->aCol[i].zDflt==0 ){
|
||||
onError = OE_Abort;
|
||||
}
|
||||
sqliteVdbeAddOp(v, OP_Dup, nCol-1-i, 1);
|
||||
addr = sqliteVdbeAddOp(v, OP_NotNull, 1, 0);
|
||||
switch( onError ){
|
||||
case OE_Rollback:
|
||||
case OE_Abort:
|
||||
case OE_Fail: {
|
||||
char *zMsg = 0;
|
||||
sqliteVdbeAddOp(v, OP_Halt, SQLITE_CONSTRAINT, onError);
|
||||
sqliteSetString(&zMsg, pTab->zName, ".", pTab->aCol[i].zName,
|
||||
" may not be NULL", (char*)0);
|
||||
sqliteVdbeChangeP3(v, -1, zMsg, P3_DYNAMIC);
|
||||
break;
|
||||
}
|
||||
case OE_Ignore: {
|
||||
sqliteVdbeAddOp(v, OP_Pop, nCol+1+hasTwoRecnos, 0);
|
||||
sqliteVdbeAddOp(v, OP_Goto, 0, ignoreDest);
|
||||
break;
|
||||
}
|
||||
case OE_Replace: {
|
||||
sqliteVdbeOp3(v, OP_String, 0, 0, pTab->aCol[i].zDflt, P3_STATIC);
|
||||
sqliteVdbeAddOp(v, OP_Push, nCol-i, 0);
|
||||
break;
|
||||
}
|
||||
default: assert(0);
|
||||
}
|
||||
sqliteVdbeChangeP2(v, addr, sqliteVdbeCurrentAddr(v));
|
||||
}
|
||||
|
||||
/* Test all CHECK constraints
|
||||
*/
|
||||
/**** TBD ****/
|
||||
|
||||
/* If we have an INTEGER PRIMARY KEY, make sure the primary key
|
||||
** of the new record does not previously exist. Except, if this
|
||||
** is an UPDATE and the primary key is not changing, that is OK.
|
||||
*/
|
||||
if( recnoChng ){
|
||||
onError = pTab->keyConf;
|
||||
if( overrideError!=OE_Default ){
|
||||
onError = overrideError;
|
||||
}else if( pParse->db->onError!=OE_Default ){
|
||||
onError = pParse->db->onError;
|
||||
}else if( onError==OE_Default ){
|
||||
onError = OE_Abort;
|
||||
}
|
||||
|
||||
if( isUpdate ){
|
||||
sqliteVdbeAddOp(v, OP_Dup, nCol+1, 1);
|
||||
sqliteVdbeAddOp(v, OP_Dup, nCol+1, 1);
|
||||
jumpInst1 = sqliteVdbeAddOp(v, OP_Eq, 0, 0);
|
||||
}
|
||||
sqliteVdbeAddOp(v, OP_Dup, nCol, 1);
|
||||
jumpInst2 = sqliteVdbeAddOp(v, OP_NotExists, base, 0);
|
||||
switch( onError ){
|
||||
default: {
|
||||
onError = OE_Abort;
|
||||
/* Fall thru into the next case */
|
||||
}
|
||||
case OE_Rollback:
|
||||
case OE_Abort:
|
||||
case OE_Fail: {
|
||||
sqliteVdbeOp3(v, OP_Halt, SQLITE_CONSTRAINT, onError,
|
||||
"PRIMARY KEY must be unique", P3_STATIC);
|
||||
break;
|
||||
}
|
||||
case OE_Replace: {
|
||||
sqliteGenerateRowIndexDelete(pParse->db, v, pTab, base, 0);
|
||||
if( isUpdate ){
|
||||
sqliteVdbeAddOp(v, OP_Dup, nCol+hasTwoRecnos, 1);
|
||||
sqliteVdbeAddOp(v, OP_MoveTo, base, 0);
|
||||
}
|
||||
seenReplace = 1;
|
||||
break;
|
||||
}
|
||||
case OE_Ignore: {
|
||||
assert( seenReplace==0 );
|
||||
sqliteVdbeAddOp(v, OP_Pop, nCol+1+hasTwoRecnos, 0);
|
||||
sqliteVdbeAddOp(v, OP_Goto, 0, ignoreDest);
|
||||
break;
|
||||
}
|
||||
}
|
||||
contAddr = sqliteVdbeCurrentAddr(v);
|
||||
sqliteVdbeChangeP2(v, jumpInst2, contAddr);
|
||||
if( isUpdate ){
|
||||
sqliteVdbeChangeP2(v, jumpInst1, contAddr);
|
||||
sqliteVdbeAddOp(v, OP_Dup, nCol+1, 1);
|
||||
sqliteVdbeAddOp(v, OP_MoveTo, base, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/* Test all UNIQUE constraints by creating entries for each UNIQUE
|
||||
** index and making sure that duplicate entries do not already exist.
|
||||
** Add the new records to the indices as we go.
|
||||
*/
|
||||
extra = -1;
|
||||
for(iCur=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, iCur++){
|
||||
if( aIdxUsed && aIdxUsed[iCur]==0 ) continue; /* Skip unused indices */
|
||||
extra++;
|
||||
|
||||
/* Create a key for accessing the index entry */
|
||||
sqliteVdbeAddOp(v, OP_Dup, nCol+extra, 1);
|
||||
for(i=0; i<pIdx->nColumn; i++){
|
||||
int idx = pIdx->aiColumn[i];
|
||||
if( idx==pTab->iPKey ){
|
||||
sqliteVdbeAddOp(v, OP_Dup, i+extra+nCol+1, 1);
|
||||
}else{
|
||||
sqliteVdbeAddOp(v, OP_Dup, i+extra+nCol-idx, 1);
|
||||
}
|
||||
}
|
||||
jumpInst1 = sqliteVdbeAddOp(v, OP_MakeIdxKey, pIdx->nColumn, 0);
|
||||
if( pParse->db->file_format>=4 ) sqliteAddIdxKeyType(v, pIdx);
|
||||
|
||||
/* Find out what action to take in case there is an indexing conflict */
|
||||
onError = pIdx->onError;
|
||||
if( onError==OE_None ) continue; /* pIdx is not a UNIQUE index */
|
||||
if( overrideError!=OE_Default ){
|
||||
onError = overrideError;
|
||||
}else if( pParse->db->onError!=OE_Default ){
|
||||
onError = pParse->db->onError;
|
||||
}else if( onError==OE_Default ){
|
||||
onError = OE_Abort;
|
||||
}
|
||||
if( seenReplace ){
|
||||
if( onError==OE_Ignore ) onError = OE_Replace;
|
||||
else if( onError==OE_Fail ) onError = OE_Abort;
|
||||
}
|
||||
|
||||
|
||||
/* Check to see if the new index entry will be unique */
|
||||
sqliteVdbeAddOp(v, OP_Dup, extra+nCol+1+hasTwoRecnos, 1);
|
||||
jumpInst2 = sqliteVdbeAddOp(v, OP_IsUnique, base+iCur+1, 0);
|
||||
|
||||
/* Generate code that executes if the new index entry is not unique */
|
||||
switch( onError ){
|
||||
case OE_Rollback:
|
||||
case OE_Abort:
|
||||
case OE_Fail: {
|
||||
int j, n1, n2;
|
||||
char zErrMsg[200];
|
||||
strcpy(zErrMsg, pIdx->nColumn>1 ? "columns " : "column ");
|
||||
n1 = strlen(zErrMsg);
|
||||
for(j=0; j<pIdx->nColumn && n1<sizeof(zErrMsg)-30; j++){
|
||||
char *zCol = pTab->aCol[pIdx->aiColumn[j]].zName;
|
||||
n2 = strlen(zCol);
|
||||
if( j>0 ){
|
||||
strcpy(&zErrMsg[n1], ", ");
|
||||
n1 += 2;
|
||||
}
|
||||
if( n1+n2>sizeof(zErrMsg)-30 ){
|
||||
strcpy(&zErrMsg[n1], "...");
|
||||
n1 += 3;
|
||||
break;
|
||||
}else{
|
||||
strcpy(&zErrMsg[n1], zCol);
|
||||
n1 += n2;
|
||||
}
|
||||
}
|
||||
strcpy(&zErrMsg[n1],
|
||||
pIdx->nColumn>1 ? " are not unique" : " is not unique");
|
||||
sqliteVdbeOp3(v, OP_Halt, SQLITE_CONSTRAINT, onError, zErrMsg, 0);
|
||||
break;
|
||||
}
|
||||
case OE_Ignore: {
|
||||
assert( seenReplace==0 );
|
||||
sqliteVdbeAddOp(v, OP_Pop, nCol+extra+3+hasTwoRecnos, 0);
|
||||
sqliteVdbeAddOp(v, OP_Goto, 0, ignoreDest);
|
||||
break;
|
||||
}
|
||||
case OE_Replace: {
|
||||
sqliteGenerateRowDelete(pParse->db, v, pTab, base, 0);
|
||||
if( isUpdate ){
|
||||
sqliteVdbeAddOp(v, OP_Dup, nCol+extra+1+hasTwoRecnos, 1);
|
||||
sqliteVdbeAddOp(v, OP_MoveTo, base, 0);
|
||||
}
|
||||
seenReplace = 1;
|
||||
break;
|
||||
}
|
||||
default: assert(0);
|
||||
}
|
||||
contAddr = sqliteVdbeCurrentAddr(v);
|
||||
#if NULL_DISTINCT_FOR_UNIQUE
|
||||
sqliteVdbeChangeP2(v, jumpInst1, contAddr);
|
||||
#endif
|
||||
sqliteVdbeChangeP2(v, jumpInst2, contAddr);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** This routine generates code to finish the INSERT or UPDATE operation
|
||||
** that was started by a prior call to sqliteGenerateConstraintChecks.
|
||||
** The stack must contain keys for all active indices followed by data
|
||||
** and the recno for the new entry. This routine creates the new
|
||||
** entries in all indices and in the main table.
|
||||
**
|
||||
** The arguments to this routine should be the same as the first six
|
||||
** arguments to sqliteGenerateConstraintChecks.
|
||||
*/
|
||||
void sqliteCompleteInsertion(
|
||||
Parse *pParse, /* The parser context */
|
||||
Table *pTab, /* the table into which we are inserting */
|
||||
int base, /* Index of a read/write cursor pointing at pTab */
|
||||
char *aIdxUsed, /* Which indices are used. NULL means all are used */
|
||||
int recnoChng, /* True if the record number will change */
|
||||
int isUpdate, /* True for UPDATE, False for INSERT */
|
||||
int newIdx /* Index of NEW table for triggers. -1 if none */
|
||||
){
|
||||
int i;
|
||||
Vdbe *v;
|
||||
int nIdx;
|
||||
Index *pIdx;
|
||||
|
||||
v = sqliteGetVdbe(pParse);
|
||||
assert( v!=0 );
|
||||
assert( pTab->pSelect==0 ); /* This table is not a VIEW */
|
||||
for(nIdx=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, nIdx++){}
|
||||
for(i=nIdx-1; i>=0; i--){
|
||||
if( aIdxUsed && aIdxUsed[i]==0 ) continue;
|
||||
sqliteVdbeAddOp(v, OP_IdxPut, base+i+1, 0);
|
||||
}
|
||||
sqliteVdbeAddOp(v, OP_MakeRecord, pTab->nCol, 0);
|
||||
if( newIdx>=0 ){
|
||||
sqliteVdbeAddOp(v, OP_Dup, 1, 0);
|
||||
sqliteVdbeAddOp(v, OP_Dup, 1, 0);
|
||||
sqliteVdbeAddOp(v, OP_PutIntKey, newIdx, 0);
|
||||
}
|
||||
sqliteVdbeAddOp(v, OP_PutIntKey, base,
|
||||
(pParse->trigStack?0:OPFLAG_NCHANGE) |
|
||||
(isUpdate?0:OPFLAG_LASTROWID) | OPFLAG_CSCHANGE);
|
||||
if( isUpdate && recnoChng ){
|
||||
sqliteVdbeAddOp(v, OP_Pop, 1, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Generate code that will open write cursors for a table and for all
|
||||
** indices of that table. The "base" parameter is the cursor number used
|
||||
** for the table. Indices are opened on subsequent cursors.
|
||||
**
|
||||
** Return the total number of cursors opened. This is always at least
|
||||
** 1 (for the main table) plus more for each cursor.
|
||||
*/
|
||||
int sqliteOpenTableAndIndices(Parse *pParse, Table *pTab, int base){
|
||||
int i;
|
||||
Index *pIdx;
|
||||
Vdbe *v = sqliteGetVdbe(pParse);
|
||||
assert( v!=0 );
|
||||
sqliteVdbeAddOp(v, OP_Integer, pTab->iDb, 0);
|
||||
sqliteVdbeOp3(v, OP_OpenWrite, base, pTab->tnum, pTab->zName, P3_STATIC);
|
||||
for(i=1, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
|
||||
sqliteVdbeAddOp(v, OP_Integer, pIdx->iDb, 0);
|
||||
sqliteVdbeOp3(v, OP_OpenWrite, i+base, pIdx->tnum, pIdx->zName, P3_STATIC);
|
||||
}
|
||||
return i;
|
||||
}
|
1136
sqlite/main.c
Executable file
1136
sqlite/main.c
Executable file
File diff suppressed because it is too large
Load Diff
138
sqlite/opcodes.c
Executable file
138
sqlite/opcodes.c
Executable file
@ -0,0 +1,138 @@
|
||||
/* Automatically generated file. Do not edit */
|
||||
char *sqliteOpcodeNames[] = { "???",
|
||||
"Goto",
|
||||
"Gosub",
|
||||
"Return",
|
||||
"Halt",
|
||||
"Integer",
|
||||
"String",
|
||||
"Variable",
|
||||
"Pop",
|
||||
"Dup",
|
||||
"Pull",
|
||||
"Push",
|
||||
"ColumnName",
|
||||
"Callback",
|
||||
"Concat",
|
||||
"Add",
|
||||
"Subtract",
|
||||
"Multiply",
|
||||
"Divide",
|
||||
"Remainder",
|
||||
"Function",
|
||||
"BitAnd",
|
||||
"BitOr",
|
||||
"ShiftLeft",
|
||||
"ShiftRight",
|
||||
"AddImm",
|
||||
"ForceInt",
|
||||
"MustBeInt",
|
||||
"Eq",
|
||||
"Ne",
|
||||
"Lt",
|
||||
"Le",
|
||||
"Gt",
|
||||
"Ge",
|
||||
"StrEq",
|
||||
"StrNe",
|
||||
"StrLt",
|
||||
"StrLe",
|
||||
"StrGt",
|
||||
"StrGe",
|
||||
"And",
|
||||
"Or",
|
||||
"Negative",
|
||||
"AbsValue",
|
||||
"Not",
|
||||
"BitNot",
|
||||
"Noop",
|
||||
"If",
|
||||
"IfNot",
|
||||
"IsNull",
|
||||
"NotNull",
|
||||
"MakeRecord",
|
||||
"MakeIdxKey",
|
||||
"MakeKey",
|
||||
"IncrKey",
|
||||
"Checkpoint",
|
||||
"Transaction",
|
||||
"Commit",
|
||||
"Rollback",
|
||||
"ReadCookie",
|
||||
"SetCookie",
|
||||
"VerifyCookie",
|
||||
"OpenRead",
|
||||
"OpenWrite",
|
||||
"OpenTemp",
|
||||
"OpenPseudo",
|
||||
"Close",
|
||||
"MoveLt",
|
||||
"MoveTo",
|
||||
"Distinct",
|
||||
"NotFound",
|
||||
"Found",
|
||||
"IsUnique",
|
||||
"NotExists",
|
||||
"NewRecno",
|
||||
"PutIntKey",
|
||||
"PutStrKey",
|
||||
"Delete",
|
||||
"SetCounts",
|
||||
"KeyAsData",
|
||||
"RowKey",
|
||||
"RowData",
|
||||
"Column",
|
||||
"Recno",
|
||||
"FullKey",
|
||||
"NullRow",
|
||||
"Last",
|
||||
"Rewind",
|
||||
"Prev",
|
||||
"Next",
|
||||
"IdxPut",
|
||||
"IdxDelete",
|
||||
"IdxRecno",
|
||||
"IdxLT",
|
||||
"IdxGT",
|
||||
"IdxGE",
|
||||
"IdxIsNull",
|
||||
"Destroy",
|
||||
"Clear",
|
||||
"CreateIndex",
|
||||
"CreateTable",
|
||||
"IntegrityCk",
|
||||
"ListWrite",
|
||||
"ListRewind",
|
||||
"ListRead",
|
||||
"ListReset",
|
||||
"ListPush",
|
||||
"ListPop",
|
||||
"ContextPush",
|
||||
"ContextPop",
|
||||
"SortPut",
|
||||
"SortMakeRec",
|
||||
"SortMakeKey",
|
||||
"Sort",
|
||||
"SortNext",
|
||||
"SortCallback",
|
||||
"SortReset",
|
||||
"FileOpen",
|
||||
"FileRead",
|
||||
"FileColumn",
|
||||
"MemStore",
|
||||
"MemLoad",
|
||||
"MemIncr",
|
||||
"AggReset",
|
||||
"AggInit",
|
||||
"AggFunc",
|
||||
"AggFocus",
|
||||
"AggSet",
|
||||
"AggGet",
|
||||
"AggNext",
|
||||
"SetInsert",
|
||||
"SetFound",
|
||||
"SetNotFound",
|
||||
"SetFirst",
|
||||
"SetNext",
|
||||
"Vacuum",
|
||||
};
|
136
sqlite/opcodes.h
Executable file
136
sqlite/opcodes.h
Executable file
@ -0,0 +1,136 @@
|
||||
/* Automatically generated file. Do not edit */
|
||||
#define OP_Goto 1
|
||||
#define OP_Gosub 2
|
||||
#define OP_Return 3
|
||||
#define OP_Halt 4
|
||||
#define OP_Integer 5
|
||||
#define OP_String 6
|
||||
#define OP_Variable 7
|
||||
#define OP_Pop 8
|
||||
#define OP_Dup 9
|
||||
#define OP_Pull 10
|
||||
#define OP_Push 11
|
||||
#define OP_ColumnName 12
|
||||
#define OP_Callback 13
|
||||
#define OP_Concat 14
|
||||
#define OP_Add 15
|
||||
#define OP_Subtract 16
|
||||
#define OP_Multiply 17
|
||||
#define OP_Divide 18
|
||||
#define OP_Remainder 19
|
||||
#define OP_Function 20
|
||||
#define OP_BitAnd 21
|
||||
#define OP_BitOr 22
|
||||
#define OP_ShiftLeft 23
|
||||
#define OP_ShiftRight 24
|
||||
#define OP_AddImm 25
|
||||
#define OP_ForceInt 26
|
||||
#define OP_MustBeInt 27
|
||||
#define OP_Eq 28
|
||||
#define OP_Ne 29
|
||||
#define OP_Lt 30
|
||||
#define OP_Le 31
|
||||
#define OP_Gt 32
|
||||
#define OP_Ge 33
|
||||
#define OP_StrEq 34
|
||||
#define OP_StrNe 35
|
||||
#define OP_StrLt 36
|
||||
#define OP_StrLe 37
|
||||
#define OP_StrGt 38
|
||||
#define OP_StrGe 39
|
||||
#define OP_And 40
|
||||
#define OP_Or 41
|
||||
#define OP_Negative 42
|
||||
#define OP_AbsValue 43
|
||||
#define OP_Not 44
|
||||
#define OP_BitNot 45
|
||||
#define OP_Noop 46
|
||||
#define OP_If 47
|
||||
#define OP_IfNot 48
|
||||
#define OP_IsNull 49
|
||||
#define OP_NotNull 50
|
||||
#define OP_MakeRecord 51
|
||||
#define OP_MakeIdxKey 52
|
||||
#define OP_MakeKey 53
|
||||
#define OP_IncrKey 54
|
||||
#define OP_Checkpoint 55
|
||||
#define OP_Transaction 56
|
||||
#define OP_Commit 57
|
||||
#define OP_Rollback 58
|
||||
#define OP_ReadCookie 59
|
||||
#define OP_SetCookie 60
|
||||
#define OP_VerifyCookie 61
|
||||
#define OP_OpenRead 62
|
||||
#define OP_OpenWrite 63
|
||||
#define OP_OpenTemp 64
|
||||
#define OP_OpenPseudo 65
|
||||
#define OP_Close 66
|
||||
#define OP_MoveLt 67
|
||||
#define OP_MoveTo 68
|
||||
#define OP_Distinct 69
|
||||
#define OP_NotFound 70
|
||||
#define OP_Found 71
|
||||
#define OP_IsUnique 72
|
||||
#define OP_NotExists 73
|
||||
#define OP_NewRecno 74
|
||||
#define OP_PutIntKey 75
|
||||
#define OP_PutStrKey 76
|
||||
#define OP_Delete 77
|
||||
#define OP_SetCounts 78
|
||||
#define OP_KeyAsData 79
|
||||
#define OP_RowKey 80
|
||||
#define OP_RowData 81
|
||||
#define OP_Column 82
|
||||
#define OP_Recno 83
|
||||
#define OP_FullKey 84
|
||||
#define OP_NullRow 85
|
||||
#define OP_Last 86
|
||||
#define OP_Rewind 87
|
||||
#define OP_Prev 88
|
||||
#define OP_Next 89
|
||||
#define OP_IdxPut 90
|
||||
#define OP_IdxDelete 91
|
||||
#define OP_IdxRecno 92
|
||||
#define OP_IdxLT 93
|
||||
#define OP_IdxGT 94
|
||||
#define OP_IdxGE 95
|
||||
#define OP_IdxIsNull 96
|
||||
#define OP_Destroy 97
|
||||
#define OP_Clear 98
|
||||
#define OP_CreateIndex 99
|
||||
#define OP_CreateTable 100
|
||||
#define OP_IntegrityCk 101
|
||||
#define OP_ListWrite 102
|
||||
#define OP_ListRewind 103
|
||||
#define OP_ListRead 104
|
||||
#define OP_ListReset 105
|
||||
#define OP_ListPush 106
|
||||
#define OP_ListPop 107
|
||||
#define OP_ContextPush 108
|
||||
#define OP_ContextPop 109
|
||||
#define OP_SortPut 110
|
||||
#define OP_SortMakeRec 111
|
||||
#define OP_SortMakeKey 112
|
||||
#define OP_Sort 113
|
||||
#define OP_SortNext 114
|
||||
#define OP_SortCallback 115
|
||||
#define OP_SortReset 116
|
||||
#define OP_FileOpen 117
|
||||
#define OP_FileRead 118
|
||||
#define OP_FileColumn 119
|
||||
#define OP_MemStore 120
|
||||
#define OP_MemLoad 121
|
||||
#define OP_MemIncr 122
|
||||
#define OP_AggReset 123
|
||||
#define OP_AggInit 124
|
||||
#define OP_AggFunc 125
|
||||
#define OP_AggFocus 126
|
||||
#define OP_AggSet 127
|
||||
#define OP_AggGet 128
|
||||
#define OP_AggNext 129
|
||||
#define OP_SetInsert 130
|
||||
#define OP_SetFound 131
|
||||
#define OP_SetNotFound 132
|
||||
#define OP_SetFirst 133
|
||||
#define OP_SetNext 134
|
||||
#define OP_Vacuum 135
|
1818
sqlite/os.c
Executable file
1818
sqlite/os.c
Executable file
File diff suppressed because it is too large
Load Diff
191
sqlite/os.h
Executable file
191
sqlite/os.h
Executable file
@ -0,0 +1,191 @@
|
||||
/*
|
||||
** 2001 September 16
|
||||
**
|
||||
** The author disclaims copyright to this source code. In place of
|
||||
** a legal notice, here is a blessing:
|
||||
**
|
||||
** May you do good and not evil.
|
||||
** May you find forgiveness for yourself and forgive others.
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
******************************************************************************
|
||||
**
|
||||
** This header file (together with is companion C source-code file
|
||||
** "os.c") attempt to abstract the underlying operating system so that
|
||||
** the SQLite library will work on both POSIX and windows systems.
|
||||
*/
|
||||
#ifndef _SQLITE_OS_H_
|
||||
#define _SQLITE_OS_H_
|
||||
|
||||
/*
|
||||
** Helpful hint: To get this to compile on HP/UX, add -D_INCLUDE_POSIX_SOURCE
|
||||
** to the compiler command line.
|
||||
*/
|
||||
|
||||
/*
|
||||
** These #defines should enable >2GB file support on Posix if the
|
||||
** underlying operating system supports it. If the OS lacks
|
||||
** large file support, or if the OS is windows, these should be no-ops.
|
||||
**
|
||||
** Large file support can be disabled using the -DSQLITE_DISABLE_LFS switch
|
||||
** on the compiler command line. This is necessary if you are compiling
|
||||
** on a recent machine (ex: RedHat 7.2) but you want your code to work
|
||||
** on an older machine (ex: RedHat 6.0). If you compile on RedHat 7.2
|
||||
** without this option, LFS is enable. But LFS does not exist in the kernel
|
||||
** in RedHat 6.0, so the code won't work. Hence, for maximum binary
|
||||
** portability you should omit LFS.
|
||||
**
|
||||
** Similar is true for MacOS. LFS is only supported on MacOS 9 and later.
|
||||
*/
|
||||
#ifndef SQLITE_DISABLE_LFS
|
||||
# define _LARGE_FILE 1
|
||||
# ifndef _FILE_OFFSET_BITS
|
||||
# define _FILE_OFFSET_BITS 64
|
||||
# endif
|
||||
# define _LARGEFILE_SOURCE 1
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Temporary files are named starting with this prefix followed by 16 random
|
||||
** alphanumeric characters, and no file extension. They are stored in the
|
||||
** OS's standard temporary file directory, and are deleted prior to exit.
|
||||
** If sqlite is being embedded in another program, you may wish to change the
|
||||
** prefix to reflect your program's name, so that if your program exits
|
||||
** prematurely, old temporary files can be easily identified. This can be done
|
||||
** using -DTEMP_FILE_PREFIX=myprefix_ on the compiler command line.
|
||||
*/
|
||||
#ifndef TEMP_FILE_PREFIX
|
||||
# define TEMP_FILE_PREFIX "sqlite_"
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Figure out if we are dealing with Unix, Windows or MacOS.
|
||||
**
|
||||
** N.B. MacOS means Mac Classic (or Carbon). Treat Darwin (OS X) as Unix.
|
||||
** The MacOS build is designed to use CodeWarrior (tested with v8)
|
||||
*/
|
||||
#ifndef OS_UNIX
|
||||
# ifndef OS_WIN
|
||||
# ifndef OS_MAC
|
||||
# if defined(__MACOS__)
|
||||
# define OS_MAC 1
|
||||
# define OS_WIN 0
|
||||
# define OS_UNIX 0
|
||||
# elif defined(_WIN32) || defined(WIN32) || defined(__CYGWIN__) || defined(__MINGW32__) || defined(__BORLANDC__)
|
||||
# define OS_MAC 0
|
||||
# define OS_WIN 1
|
||||
# define OS_UNIX 0
|
||||
# else
|
||||
# define OS_MAC 0
|
||||
# define OS_WIN 0
|
||||
# define OS_UNIX 1
|
||||
# endif
|
||||
# else
|
||||
# define OS_WIN 0
|
||||
# define OS_UNIX 0
|
||||
# endif
|
||||
# else
|
||||
# define OS_MAC 0
|
||||
# define OS_UNIX 0
|
||||
# endif
|
||||
#else
|
||||
# define OS_MAC 0
|
||||
# ifndef OS_WIN
|
||||
# define OS_WIN 0
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
** A handle for an open file is stored in an OsFile object.
|
||||
*/
|
||||
#if OS_UNIX
|
||||
# include <sys/types.h>
|
||||
# include <sys/stat.h>
|
||||
# include <fcntl.h>
|
||||
# include <unistd.h>
|
||||
typedef struct OsFile OsFile;
|
||||
struct OsFile {
|
||||
struct openCnt *pOpen; /* Info about all open fd's on this inode */
|
||||
struct lockInfo *pLock; /* Info about locks on this inode */
|
||||
int fd; /* The file descriptor */
|
||||
int locked; /* True if this instance holds the lock */
|
||||
int dirfd; /* File descriptor for the directory */
|
||||
};
|
||||
# define SQLITE_TEMPNAME_SIZE 200
|
||||
# if defined(HAVE_USLEEP) && HAVE_USLEEP
|
||||
# define SQLITE_MIN_SLEEP_MS 1
|
||||
# else
|
||||
# define SQLITE_MIN_SLEEP_MS 1000
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if OS_WIN
|
||||
#include <windows.h>
|
||||
#include <winbase.h>
|
||||
typedef struct OsFile OsFile;
|
||||
struct OsFile {
|
||||
HANDLE h; /* Handle for accessing the file */
|
||||
int locked; /* 0: unlocked, <0: write lock, >0: read lock */
|
||||
};
|
||||
# if defined(_MSC_VER) || defined(__BORLANDC__)
|
||||
typedef __int64 off_t;
|
||||
# else
|
||||
# if !defined(_CYGWIN_TYPES_H)
|
||||
typedef long long off_t;
|
||||
# if defined(__MINGW32__)
|
||||
# define _OFF_T_
|
||||
# endif
|
||||
# endif
|
||||
# endif
|
||||
# define SQLITE_TEMPNAME_SIZE (MAX_PATH+50)
|
||||
# define SQLITE_MIN_SLEEP_MS 1
|
||||
#endif
|
||||
|
||||
#if OS_MAC
|
||||
# include <unistd.h>
|
||||
# include <Files.h>
|
||||
typedef struct OsFile OsFile;
|
||||
struct OsFile {
|
||||
SInt16 refNum; /* Data fork/file reference number */
|
||||
SInt16 refNumRF; /* Resource fork reference number (for locking) */
|
||||
int locked; /* 0: unlocked, <0: write lock, >0: read lock */
|
||||
int delOnClose; /* True if file is to be deleted on close */
|
||||
char *pathToDel; /* Name of file to delete on close */
|
||||
};
|
||||
# ifdef _LARGE_FILE
|
||||
typedef SInt64 off_t;
|
||||
# else
|
||||
typedef SInt32 off_t;
|
||||
# endif
|
||||
# define SQLITE_TEMPNAME_SIZE _MAX_PATH
|
||||
# define SQLITE_MIN_SLEEP_MS 17
|
||||
#endif
|
||||
|
||||
int sqliteOsDelete(const char*);
|
||||
int sqliteOsFileExists(const char*);
|
||||
int sqliteOsFileRename(const char*, const char*);
|
||||
int sqliteOsOpenReadWrite(const char*, OsFile*, int*);
|
||||
int sqliteOsOpenExclusive(const char*, OsFile*, int);
|
||||
int sqliteOsOpenReadOnly(const char*, OsFile*);
|
||||
int sqliteOsOpenDirectory(const char*, OsFile*);
|
||||
int sqliteOsTempFileName(char*);
|
||||
int sqliteOsClose(OsFile*);
|
||||
int sqliteOsRead(OsFile*, void*, int amt);
|
||||
int sqliteOsWrite(OsFile*, const void*, int amt);
|
||||
int sqliteOsSeek(OsFile*, off_t offset);
|
||||
int sqliteOsSync(OsFile*);
|
||||
int sqliteOsTruncate(OsFile*, off_t size);
|
||||
int sqliteOsFileSize(OsFile*, off_t *pSize);
|
||||
int sqliteOsReadLock(OsFile*);
|
||||
int sqliteOsWriteLock(OsFile*);
|
||||
int sqliteOsUnlock(OsFile*);
|
||||
int sqliteOsRandomSeed(char*);
|
||||
int sqliteOsSleep(int ms);
|
||||
int sqliteOsCurrentTime(double*);
|
||||
void sqliteOsEnterMutex(void);
|
||||
void sqliteOsLeaveMutex(void);
|
||||
char *sqliteOsFullPathname(const char*);
|
||||
|
||||
|
||||
|
||||
#endif /* _SQLITE_OS_H_ */
|
2220
sqlite/pager.c
Executable file
2220
sqlite/pager.c
Executable file
File diff suppressed because it is too large
Load Diff
107
sqlite/pager.h
Executable file
107
sqlite/pager.h
Executable file
@ -0,0 +1,107 @@
|
||||
/*
|
||||
** 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.1.1.1 2004-03-11 22:22:23 alex Exp $
|
||||
*/
|
||||
|
||||
/*
|
||||
** The size of one page
|
||||
**
|
||||
** You can change this value to another (reasonable) value you want.
|
||||
** It need not be a power of two, though the interface to the disk
|
||||
** will likely be faster if it is.
|
||||
**
|
||||
** Experiments show that a page size of 1024 gives the best speed
|
||||
** for common usages. The speed differences for different sizes
|
||||
** such as 512, 2048, 4096, an so forth, is minimal. Note, however,
|
||||
** that changing the page size results in a completely imcompatible
|
||||
** file format.
|
||||
*/
|
||||
#ifndef SQLITE_PAGE_SIZE
|
||||
#define SQLITE_PAGE_SIZE 1024
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Number of extra bytes of data allocated at the end of each page and
|
||||
** stored on disk but not used by the higher level btree layer. Changing
|
||||
** this value results in a completely incompatible file format.
|
||||
*/
|
||||
#ifndef SQLITE_PAGE_RESERVE
|
||||
#define SQLITE_PAGE_RESERVE 0
|
||||
#endif
|
||||
|
||||
/*
|
||||
** The total number of usable bytes stored on disk for each page.
|
||||
** The usable bytes come at the beginning of the page and the reserve
|
||||
** bytes come at the end.
|
||||
*/
|
||||
#define SQLITE_USABLE_SIZE (SQLITE_PAGE_SIZE-SQLITE_PAGE_RESERVE)
|
||||
|
||||
/*
|
||||
** Maximum number of pages in one database. (This is a limitation of
|
||||
** imposed by 4GB files size limits.)
|
||||
*/
|
||||
#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;
|
||||
|
||||
/*
|
||||
** See source code comments for a detailed description of the following
|
||||
** routines:
|
||||
*/
|
||||
int sqlitepager_open(Pager **ppPager, const char *zFilename,
|
||||
int nPage, int nExtra, int useJournal);
|
||||
void sqlitepager_set_destructor(Pager*, void(*)(void*));
|
||||
void sqlitepager_set_cachesize(Pager*, int);
|
||||
int sqlitepager_close(Pager *pPager);
|
||||
int sqlitepager_get(Pager *pPager, Pgno pgno, void **ppPage);
|
||||
void *sqlitepager_lookup(Pager *pPager, Pgno pgno);
|
||||
int sqlitepager_ref(void*);
|
||||
int sqlitepager_unref(void*);
|
||||
Pgno sqlitepager_pagenumber(void*);
|
||||
int sqlitepager_write(void*);
|
||||
int sqlitepager_iswriteable(void*);
|
||||
int sqlitepager_overwrite(Pager *pPager, Pgno pgno, void*);
|
||||
int sqlitepager_pagecount(Pager*);
|
||||
int sqlitepager_truncate(Pager*,Pgno);
|
||||
int sqlitepager_begin(void*);
|
||||
int sqlitepager_commit(Pager*);
|
||||
int sqlitepager_rollback(Pager*);
|
||||
int sqlitepager_isreadonly(Pager*);
|
||||
int sqlitepager_ckpt_begin(Pager*);
|
||||
int sqlitepager_ckpt_commit(Pager*);
|
||||
int sqlitepager_ckpt_rollback(Pager*);
|
||||
void sqlitepager_dont_rollback(void*);
|
||||
void sqlitepager_dont_write(Pager*, Pgno);
|
||||
int *sqlitepager_stats(Pager*);
|
||||
void sqlitepager_set_safety_level(Pager*,int);
|
||||
const char *sqlitepager_filename(Pager*);
|
||||
int sqlitepager_rename(Pager*, const char *zNewName);
|
||||
void sqlitepager_set_codec(Pager*,void(*)(void*,void*,Pgno,int),void*);
|
||||
|
||||
#ifdef SQLITE_TEST
|
||||
void sqlitepager_refdump(Pager*);
|
||||
int pager_refinfo_enable;
|
||||
int journal_format;
|
||||
#endif
|
4035
sqlite/parse.c
Executable file
4035
sqlite/parse.c
Executable file
File diff suppressed because it is too large
Load Diff
130
sqlite/parse.h
Executable file
130
sqlite/parse.h
Executable file
@ -0,0 +1,130 @@
|
||||
#define TK_END_OF_FILE 1
|
||||
#define TK_ILLEGAL 2
|
||||
#define TK_SPACE 3
|
||||
#define TK_UNCLOSED_STRING 4
|
||||
#define TK_COMMENT 5
|
||||
#define TK_FUNCTION 6
|
||||
#define TK_COLUMN 7
|
||||
#define TK_AGG_FUNCTION 8
|
||||
#define TK_SEMI 9
|
||||
#define TK_EXPLAIN 10
|
||||
#define TK_BEGIN 11
|
||||
#define TK_TRANSACTION 12
|
||||
#define TK_COMMIT 13
|
||||
#define TK_END 14
|
||||
#define TK_ROLLBACK 15
|
||||
#define TK_CREATE 16
|
||||
#define TK_TABLE 17
|
||||
#define TK_TEMP 18
|
||||
#define TK_LP 19
|
||||
#define TK_RP 20
|
||||
#define TK_AS 21
|
||||
#define TK_COMMA 22
|
||||
#define TK_ID 23
|
||||
#define TK_ABORT 24
|
||||
#define TK_AFTER 25
|
||||
#define TK_ASC 26
|
||||
#define TK_ATTACH 27
|
||||
#define TK_BEFORE 28
|
||||
#define TK_CASCADE 29
|
||||
#define TK_CLUSTER 30
|
||||
#define TK_CONFLICT 31
|
||||
#define TK_COPY 32
|
||||
#define TK_DATABASE 33
|
||||
#define TK_DEFERRED 34
|
||||
#define TK_DELIMITERS 35
|
||||
#define TK_DESC 36
|
||||
#define TK_DETACH 37
|
||||
#define TK_EACH 38
|
||||
#define TK_FAIL 39
|
||||
#define TK_FOR 40
|
||||
#define TK_GLOB 41
|
||||
#define TK_IGNORE 42
|
||||
#define TK_IMMEDIATE 43
|
||||
#define TK_INITIALLY 44
|
||||
#define TK_INSTEAD 45
|
||||
#define TK_LIKE 46
|
||||
#define TK_MATCH 47
|
||||
#define TK_KEY 48
|
||||
#define TK_OF 49
|
||||
#define TK_OFFSET 50
|
||||
#define TK_PRAGMA 51
|
||||
#define TK_RAISE 52
|
||||
#define TK_REPLACE 53
|
||||
#define TK_RESTRICT 54
|
||||
#define TK_ROW 55
|
||||
#define TK_STATEMENT 56
|
||||
#define TK_TRIGGER 57
|
||||
#define TK_VACUUM 58
|
||||
#define TK_VIEW 59
|
||||
#define TK_OR 60
|
||||
#define TK_AND 61
|
||||
#define TK_NOT 62
|
||||
#define TK_EQ 63
|
||||
#define TK_NE 64
|
||||
#define TK_ISNULL 65
|
||||
#define TK_NOTNULL 66
|
||||
#define TK_IS 67
|
||||
#define TK_BETWEEN 68
|
||||
#define TK_IN 69
|
||||
#define TK_GT 70
|
||||
#define TK_GE 71
|
||||
#define TK_LT 72
|
||||
#define TK_LE 73
|
||||
#define TK_BITAND 74
|
||||
#define TK_BITOR 75
|
||||
#define TK_LSHIFT 76
|
||||
#define TK_RSHIFT 77
|
||||
#define TK_PLUS 78
|
||||
#define TK_MINUS 79
|
||||
#define TK_STAR 80
|
||||
#define TK_SLASH 81
|
||||
#define TK_REM 82
|
||||
#define TK_CONCAT 83
|
||||
#define TK_UMINUS 84
|
||||
#define TK_UPLUS 85
|
||||
#define TK_BITNOT 86
|
||||
#define TK_STRING 87
|
||||
#define TK_JOIN_KW 88
|
||||
#define TK_INTEGER 89
|
||||
#define TK_CONSTRAINT 90
|
||||
#define TK_DEFAULT 91
|
||||
#define TK_FLOAT 92
|
||||
#define TK_NULL 93
|
||||
#define TK_PRIMARY 94
|
||||
#define TK_UNIQUE 95
|
||||
#define TK_CHECK 96
|
||||
#define TK_REFERENCES 97
|
||||
#define TK_COLLATE 98
|
||||
#define TK_ON 99
|
||||
#define TK_DELETE 100
|
||||
#define TK_UPDATE 101
|
||||
#define TK_INSERT 102
|
||||
#define TK_SET 103
|
||||
#define TK_DEFERRABLE 104
|
||||
#define TK_FOREIGN 105
|
||||
#define TK_DROP 106
|
||||
#define TK_UNION 107
|
||||
#define TK_ALL 108
|
||||
#define TK_INTERSECT 109
|
||||
#define TK_EXCEPT 110
|
||||
#define TK_SELECT 111
|
||||
#define TK_DISTINCT 112
|
||||
#define TK_DOT 113
|
||||
#define TK_FROM 114
|
||||
#define TK_JOIN 115
|
||||
#define TK_USING 116
|
||||
#define TK_ORDER 117
|
||||
#define TK_BY 118
|
||||
#define TK_GROUP 119
|
||||
#define TK_HAVING 120
|
||||
#define TK_LIMIT 121
|
||||
#define TK_WHERE 122
|
||||
#define TK_INTO 123
|
||||
#define TK_VALUES 124
|
||||
#define TK_VARIABLE 125
|
||||
#define TK_CASE 126
|
||||
#define TK_WHEN 127
|
||||
#define TK_THEN 128
|
||||
#define TK_ELSE 129
|
||||
#define TK_INDEX 130
|
699
sqlite/pragma.c
Executable file
699
sqlite/pragma.c
Executable file
@ -0,0 +1,699 @@
|
||||
/*
|
||||
** 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.1.1.1 2004-03-11 22:22:23 alex Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include <ctype.h>
|
||||
|
||||
/*
|
||||
** Interpret the given string as a boolean value.
|
||||
*/
|
||||
static int getBoolean(const char *z){
|
||||
static char *azTrue[] = { "yes", "on", "true" };
|
||||
int i;
|
||||
if( z[0]==0 ) return 0;
|
||||
if( isdigit(z[0]) || (z[0]=='-' && isdigit(z[1])) ){
|
||||
return atoi(z);
|
||||
}
|
||||
for(i=0; i<sizeof(azTrue)/sizeof(azTrue[0]); i++){
|
||||
if( sqliteStrICmp(z,azTrue[i])==0 ) return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Interpret the given string as a safety level. Return 0 for OFF,
|
||||
** 1 for ON or NORMAL and 2 for FULL. Return 1 for an empty or
|
||||
** unrecognized string argument.
|
||||
**
|
||||
** Note that the values returned are one less that the values that
|
||||
** should be passed into sqliteBtreeSetSafetyLevel(). 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(char *z){
|
||||
static const struct {
|
||||
const char *zWord;
|
||||
int val;
|
||||
} aKey[] = {
|
||||
{ "no", 0 },
|
||||
{ "off", 0 },
|
||||
{ "false", 0 },
|
||||
{ "yes", 1 },
|
||||
{ "on", 1 },
|
||||
{ "true", 1 },
|
||||
{ "full", 2 },
|
||||
};
|
||||
int i;
|
||||
if( z[0]==0 ) return 1;
|
||||
if( isdigit(z[0]) || (z[0]=='-' && isdigit(z[1])) ){
|
||||
return atoi(z);
|
||||
}
|
||||
for(i=0; i<sizeof(aKey)/sizeof(aKey[0]); i++){
|
||||
if( sqliteStrICmp(z,aKey[i].zWord)==0 ) return aKey[i].val;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
** 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(char *z){
|
||||
if( z[0]>='0' || z[0]<='2' ){
|
||||
return z[0] - '0';
|
||||
}else if( sqliteStrICmp(z, "file")==0 ){
|
||||
return 1;
|
||||
}else if( sqliteStrICmp(z, "memory")==0 ){
|
||||
return 2;
|
||||
}else{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** 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 {
|
||||
const char *zName; /* Name of the pragma */
|
||||
int mask; /* Mask for the db->flags value */
|
||||
} aPragma[] = {
|
||||
{ "vdbe_trace", SQLITE_VdbeTrace },
|
||||
{ "full_column_names", SQLITE_FullColNames },
|
||||
{ "short_column_names", SQLITE_ShortColNames },
|
||||
{ "show_datatypes", SQLITE_ReportTypes },
|
||||
{ "count_changes", SQLITE_CountRows },
|
||||
{ "empty_result_callbacks", SQLITE_NullCallback },
|
||||
};
|
||||
int i;
|
||||
for(i=0; i<sizeof(aPragma)/sizeof(aPragma[0]); i++){
|
||||
if( sqliteStrICmp(zLeft, aPragma[i].zName)==0 ){
|
||||
sqlite *db = pParse->db;
|
||||
Vdbe *v;
|
||||
if( strcmp(zLeft,zRight)==0 && (v = sqliteGetVdbe(pParse))!=0 ){
|
||||
sqliteVdbeOp3(v, OP_ColumnName, 0, 1, aPragma[i].zName, P3_STATIC);
|
||||
sqliteVdbeOp3(v, OP_ColumnName, 1, 0, "boolean", P3_STATIC);
|
||||
sqliteVdbeCode(v, OP_Integer, (db->flags & aPragma[i].mask)!=0, 0,
|
||||
OP_Callback, 1, 0,
|
||||
0);
|
||||
}else if( getBoolean(zRight) ){
|
||||
db->flags |= aPragma[i].mask;
|
||||
}else{
|
||||
db->flags &= ~aPragma[i].mask;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Process a pragma statement.
|
||||
**
|
||||
** Pragmas are of this form:
|
||||
**
|
||||
** PRAGMA 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.
|
||||
*/
|
||||
void sqlitePragma(Parse *pParse, Token *pLeft, Token *pRight, int minusFlag){
|
||||
char *zLeft = 0;
|
||||
char *zRight = 0;
|
||||
sqlite *db = pParse->db;
|
||||
Vdbe *v = sqliteGetVdbe(pParse);
|
||||
if( v==0 ) return;
|
||||
|
||||
zLeft = sqliteStrNDup(pLeft->z, pLeft->n);
|
||||
sqliteDequote(zLeft);
|
||||
if( minusFlag ){
|
||||
zRight = 0;
|
||||
sqliteSetNString(&zRight, "-", 1, pRight->z, pRight->n, 0);
|
||||
}else{
|
||||
zRight = sqliteStrNDup(pRight->z, pRight->n);
|
||||
sqliteDequote(zRight);
|
||||
}
|
||||
if( sqliteAuthCheck(pParse, SQLITE_PRAGMA, zLeft, zRight, 0) ){
|
||||
sqliteFree(zLeft);
|
||||
sqliteFree(zRight);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
** PRAGMA default_cache_size
|
||||
** PRAGMA 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( sqliteStrICmp(zLeft,"default_cache_size")==0 ){
|
||||
static VdbeOpList getCacheSize[] = {
|
||||
{ OP_ReadCookie, 0, 2, 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_ColumnName, 0, 1, "cache_size"},
|
||||
{ OP_Callback, 1, 0, 0},
|
||||
};
|
||||
int addr;
|
||||
if( pRight->z==pLeft->z ){
|
||||
addr = sqliteVdbeAddOpList(v, ArraySize(getCacheSize), getCacheSize);
|
||||
sqliteVdbeChangeP1(v, addr+5, MAX_PAGES);
|
||||
}else{
|
||||
int size = atoi(zRight);
|
||||
if( size<0 ) size = -size;
|
||||
sqliteBeginWriteOperation(pParse, 0, 0);
|
||||
sqliteVdbeAddOp(v, OP_Integer, size, 0);
|
||||
sqliteVdbeAddOp(v, OP_ReadCookie, 0, 2);
|
||||
addr = sqliteVdbeAddOp(v, OP_Integer, 0, 0);
|
||||
sqliteVdbeAddOp(v, OP_Ge, 0, addr+3);
|
||||
sqliteVdbeAddOp(v, OP_Negative, 0, 0);
|
||||
sqliteVdbeAddOp(v, OP_SetCookie, 0, 2);
|
||||
sqliteEndWriteOperation(pParse);
|
||||
db->cache_size = db->cache_size<0 ? -size : size;
|
||||
sqliteBtreeSetCacheSize(db->aDb[0].pBt, db->cache_size);
|
||||
}
|
||||
}else
|
||||
|
||||
/*
|
||||
** PRAGMA cache_size
|
||||
** PRAGMA 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( sqliteStrICmp(zLeft,"cache_size")==0 ){
|
||||
static VdbeOpList getCacheSize[] = {
|
||||
{ OP_ColumnName, 0, 1, "cache_size"},
|
||||
{ OP_Callback, 1, 0, 0},
|
||||
};
|
||||
if( pRight->z==pLeft->z ){
|
||||
int size = db->cache_size;;
|
||||
if( size<0 ) size = -size;
|
||||
sqliteVdbeAddOp(v, OP_Integer, size, 0);
|
||||
sqliteVdbeAddOpList(v, ArraySize(getCacheSize), getCacheSize);
|
||||
}else{
|
||||
int size = atoi(zRight);
|
||||
if( size<0 ) size = -size;
|
||||
if( db->cache_size<0 ) size = -size;
|
||||
db->cache_size = size;
|
||||
sqliteBtreeSetCacheSize(db->aDb[0].pBt, db->cache_size);
|
||||
}
|
||||
}else
|
||||
|
||||
/*
|
||||
** PRAGMA default_synchronous
|
||||
** PRAGMA default_synchronous=ON|OFF|NORMAL|FULL
|
||||
**
|
||||
** The first form returns the persistent value of the "synchronous" setting
|
||||
** that is stored in the database. This is the synchronous setting that
|
||||
** is used whenever the database is opened unless overridden by a separate
|
||||
** "synchronous" pragma. The second form changes the persistent and the
|
||||
** local synchronous setting to the value given.
|
||||
**
|
||||
** If synchronous is OFF, SQLite does not attempt any fsync() systems calls
|
||||
** to make sure data is committed to disk. Write operations are very fast,
|
||||
** but a power failure can leave the database in an inconsistent state.
|
||||
** If synchronous is ON or NORMAL, SQLite will do an fsync() system call to
|
||||
** make sure data is being written to disk. The risk of corruption due to
|
||||
** a power loss in this mode is negligible but non-zero. If synchronous
|
||||
** is FULL, extra fsync()s occur to reduce the risk of corruption to near
|
||||
** zero, but with a write performance penalty. The default mode is NORMAL.
|
||||
*/
|
||||
if( sqliteStrICmp(zLeft,"default_synchronous")==0 ){
|
||||
static VdbeOpList getSync[] = {
|
||||
{ OP_ColumnName, 0, 1, "synchronous"},
|
||||
{ OP_ReadCookie, 0, 3, 0},
|
||||
{ OP_Dup, 0, 0, 0},
|
||||
{ OP_If, 0, 0, 0}, /* 3 */
|
||||
{ OP_ReadCookie, 0, 2, 0},
|
||||
{ OP_Integer, 0, 0, 0},
|
||||
{ OP_Lt, 0, 5, 0},
|
||||
{ OP_AddImm, 1, 0, 0},
|
||||
{ OP_Callback, 1, 0, 0},
|
||||
{ OP_Halt, 0, 0, 0},
|
||||
{ OP_AddImm, -1, 0, 0}, /* 10 */
|
||||
{ OP_Callback, 1, 0, 0}
|
||||
};
|
||||
if( pRight->z==pLeft->z ){
|
||||
int addr = sqliteVdbeAddOpList(v, ArraySize(getSync), getSync);
|
||||
sqliteVdbeChangeP2(v, addr+3, addr+10);
|
||||
}else{
|
||||
int addr;
|
||||
int size = db->cache_size;
|
||||
if( size<0 ) size = -size;
|
||||
sqliteBeginWriteOperation(pParse, 0, 0);
|
||||
sqliteVdbeAddOp(v, OP_ReadCookie, 0, 2);
|
||||
sqliteVdbeAddOp(v, OP_Dup, 0, 0);
|
||||
addr = sqliteVdbeAddOp(v, OP_Integer, 0, 0);
|
||||
sqliteVdbeAddOp(v, OP_Ne, 0, addr+3);
|
||||
sqliteVdbeAddOp(v, OP_AddImm, MAX_PAGES, 0);
|
||||
sqliteVdbeAddOp(v, OP_AbsValue, 0, 0);
|
||||
db->safety_level = getSafetyLevel(zRight)+1;
|
||||
if( db->safety_level==1 ){
|
||||
sqliteVdbeAddOp(v, OP_Negative, 0, 0);
|
||||
size = -size;
|
||||
}
|
||||
sqliteVdbeAddOp(v, OP_SetCookie, 0, 2);
|
||||
sqliteVdbeAddOp(v, OP_Integer, db->safety_level, 0);
|
||||
sqliteVdbeAddOp(v, OP_SetCookie, 0, 3);
|
||||
sqliteEndWriteOperation(pParse);
|
||||
db->cache_size = size;
|
||||
sqliteBtreeSetCacheSize(db->aDb[0].pBt, db->cache_size);
|
||||
sqliteBtreeSetSafetyLevel(db->aDb[0].pBt, db->safety_level);
|
||||
}
|
||||
}else
|
||||
|
||||
/*
|
||||
** PRAGMA synchronous
|
||||
** PRAGMA 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( sqliteStrICmp(zLeft,"synchronous")==0 ){
|
||||
static VdbeOpList getSync[] = {
|
||||
{ OP_ColumnName, 0, 1, "synchronous"},
|
||||
{ OP_Callback, 1, 0, 0},
|
||||
};
|
||||
if( pRight->z==pLeft->z ){
|
||||
sqliteVdbeAddOp(v, OP_Integer, db->safety_level-1, 0);
|
||||
sqliteVdbeAddOpList(v, ArraySize(getSync), getSync);
|
||||
}else{
|
||||
int size = db->cache_size;
|
||||
if( size<0 ) size = -size;
|
||||
db->safety_level = getSafetyLevel(zRight)+1;
|
||||
if( db->safety_level==1 ) size = -size;
|
||||
db->cache_size = size;
|
||||
sqliteBtreeSetCacheSize(db->aDb[0].pBt, db->cache_size);
|
||||
sqliteBtreeSetSafetyLevel(db->aDb[0].pBt, db->safety_level);
|
||||
}
|
||||
}else
|
||||
|
||||
#ifndef NDEBUG
|
||||
if( sqliteStrICmp(zLeft, "trigger_overhead_test")==0 ){
|
||||
if( getBoolean(zRight) ){
|
||||
always_code_trigger_setup = 1;
|
||||
}else{
|
||||
always_code_trigger_setup = 0;
|
||||
}
|
||||
}else
|
||||
#endif
|
||||
|
||||
if( flagPragma(pParse, zLeft, zRight) ){
|
||||
/* The flagPragma() call also generates any necessary code */
|
||||
}else
|
||||
|
||||
if( sqliteStrICmp(zLeft, "table_info")==0 ){
|
||||
Table *pTab;
|
||||
pTab = sqliteFindTable(db, zRight, 0);
|
||||
if( pTab ){
|
||||
static VdbeOpList tableInfoPreface[] = {
|
||||
{ OP_ColumnName, 0, 0, "cid"},
|
||||
{ OP_ColumnName, 1, 0, "name"},
|
||||
{ OP_ColumnName, 2, 0, "type"},
|
||||
{ OP_ColumnName, 3, 0, "notnull"},
|
||||
{ OP_ColumnName, 4, 0, "dflt_value"},
|
||||
{ OP_ColumnName, 5, 1, "pk"},
|
||||
};
|
||||
int i;
|
||||
sqliteVdbeAddOpList(v, ArraySize(tableInfoPreface), tableInfoPreface);
|
||||
sqliteViewGetColumnNames(pParse, pTab);
|
||||
for(i=0; i<pTab->nCol; i++){
|
||||
sqliteVdbeAddOp(v, OP_Integer, i, 0);
|
||||
sqliteVdbeOp3(v, OP_String, 0, 0, pTab->aCol[i].zName, 0);
|
||||
sqliteVdbeOp3(v, OP_String, 0, 0,
|
||||
pTab->aCol[i].zType ? pTab->aCol[i].zType : "numeric", 0);
|
||||
sqliteVdbeAddOp(v, OP_Integer, pTab->aCol[i].notNull, 0);
|
||||
sqliteVdbeOp3(v, OP_String, 0, 0,
|
||||
pTab->aCol[i].zDflt, P3_STATIC);
|
||||
sqliteVdbeAddOp(v, OP_Integer, pTab->aCol[i].isPrimKey, 0);
|
||||
sqliteVdbeAddOp(v, OP_Callback, 6, 0);
|
||||
}
|
||||
}
|
||||
}else
|
||||
|
||||
if( sqliteStrICmp(zLeft, "index_info")==0 ){
|
||||
Index *pIdx;
|
||||
Table *pTab;
|
||||
pIdx = sqliteFindIndex(db, zRight, 0);
|
||||
if( pIdx ){
|
||||
static VdbeOpList tableInfoPreface[] = {
|
||||
{ OP_ColumnName, 0, 0, "seqno"},
|
||||
{ OP_ColumnName, 1, 0, "cid"},
|
||||
{ OP_ColumnName, 2, 1, "name"},
|
||||
};
|
||||
int i;
|
||||
pTab = pIdx->pTable;
|
||||
sqliteVdbeAddOpList(v, ArraySize(tableInfoPreface), tableInfoPreface);
|
||||
for(i=0; i<pIdx->nColumn; i++){
|
||||
int cnum = pIdx->aiColumn[i];
|
||||
sqliteVdbeAddOp(v, OP_Integer, i, 0);
|
||||
sqliteVdbeAddOp(v, OP_Integer, cnum, 0);
|
||||
assert( pTab->nCol>cnum );
|
||||
sqliteVdbeOp3(v, OP_String, 0, 0, pTab->aCol[cnum].zName, 0);
|
||||
sqliteVdbeAddOp(v, OP_Callback, 3, 0);
|
||||
}
|
||||
}
|
||||
}else
|
||||
|
||||
if( sqliteStrICmp(zLeft, "index_list")==0 ){
|
||||
Index *pIdx;
|
||||
Table *pTab;
|
||||
pTab = sqliteFindTable(db, zRight, 0);
|
||||
if( pTab ){
|
||||
v = sqliteGetVdbe(pParse);
|
||||
pIdx = pTab->pIndex;
|
||||
}
|
||||
if( pTab && pIdx ){
|
||||
int i = 0;
|
||||
static VdbeOpList indexListPreface[] = {
|
||||
{ OP_ColumnName, 0, 0, "seq"},
|
||||
{ OP_ColumnName, 1, 0, "name"},
|
||||
{ OP_ColumnName, 2, 1, "unique"},
|
||||
};
|
||||
|
||||
sqliteVdbeAddOpList(v, ArraySize(indexListPreface), indexListPreface);
|
||||
while(pIdx){
|
||||
sqliteVdbeAddOp(v, OP_Integer, i, 0);
|
||||
sqliteVdbeOp3(v, OP_String, 0, 0, pIdx->zName, 0);
|
||||
sqliteVdbeAddOp(v, OP_Integer, pIdx->onError!=OE_None, 0);
|
||||
sqliteVdbeAddOp(v, OP_Callback, 3, 0);
|
||||
++i;
|
||||
pIdx = pIdx->pNext;
|
||||
}
|
||||
}
|
||||
}else
|
||||
|
||||
if( sqliteStrICmp(zLeft, "foreign_key_list")==0 ){
|
||||
FKey *pFK;
|
||||
Table *pTab;
|
||||
pTab = sqliteFindTable(db, zRight, 0);
|
||||
if( pTab ){
|
||||
v = sqliteGetVdbe(pParse);
|
||||
pFK = pTab->pFKey;
|
||||
}
|
||||
if( pTab && pFK ){
|
||||
int i = 0;
|
||||
static VdbeOpList indexListPreface[] = {
|
||||
{ OP_ColumnName, 0, 0, "id"},
|
||||
{ OP_ColumnName, 1, 0, "seq"},
|
||||
{ OP_ColumnName, 2, 0, "table"},
|
||||
{ OP_ColumnName, 3, 0, "from"},
|
||||
{ OP_ColumnName, 4, 1, "to"},
|
||||
};
|
||||
|
||||
sqliteVdbeAddOpList(v, ArraySize(indexListPreface), indexListPreface);
|
||||
while(pFK){
|
||||
int j;
|
||||
for(j=0; j<pFK->nCol; j++){
|
||||
sqliteVdbeAddOp(v, OP_Integer, i, 0);
|
||||
sqliteVdbeAddOp(v, OP_Integer, j, 0);
|
||||
sqliteVdbeOp3(v, OP_String, 0, 0, pFK->zTo, 0);
|
||||
sqliteVdbeOp3(v, OP_String, 0, 0,
|
||||
pTab->aCol[pFK->aCol[j].iFrom].zName, 0);
|
||||
sqliteVdbeOp3(v, OP_String, 0, 0, pFK->aCol[j].zCol, 0);
|
||||
sqliteVdbeAddOp(v, OP_Callback, 5, 0);
|
||||
}
|
||||
++i;
|
||||
pFK = pFK->pNextFrom;
|
||||
}
|
||||
}
|
||||
}else
|
||||
|
||||
if( sqliteStrICmp(zLeft, "database_list")==0 ){
|
||||
int i;
|
||||
static VdbeOpList indexListPreface[] = {
|
||||
{ OP_ColumnName, 0, 0, "seq"},
|
||||
{ OP_ColumnName, 1, 0, "name"},
|
||||
{ OP_ColumnName, 2, 1, "file"},
|
||||
};
|
||||
|
||||
sqliteVdbeAddOpList(v, ArraySize(indexListPreface), indexListPreface);
|
||||
for(i=0; i<db->nDb; i++){
|
||||
if( db->aDb[i].pBt==0 ) continue;
|
||||
assert( db->aDb[i].zName!=0 );
|
||||
sqliteVdbeAddOp(v, OP_Integer, i, 0);
|
||||
sqliteVdbeOp3(v, OP_String, 0, 0, db->aDb[i].zName, 0);
|
||||
sqliteVdbeOp3(v, OP_String, 0, 0,
|
||||
sqliteBtreeGetFilename(db->aDb[i].pBt), 0);
|
||||
sqliteVdbeAddOp(v, OP_Callback, 3, 0);
|
||||
}
|
||||
}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( sqliteStrICmp(zLeft, "temp_store")==0 ){
|
||||
static VdbeOpList getTmpDbLoc[] = {
|
||||
{ OP_ColumnName, 0, 1, "temp_store"},
|
||||
{ OP_Callback, 1, 0, 0},
|
||||
};
|
||||
if( pRight->z==pLeft->z ){
|
||||
sqliteVdbeAddOp(v, OP_Integer, db->temp_store, 0);
|
||||
sqliteVdbeAddOpList(v, ArraySize(getTmpDbLoc), getTmpDbLoc);
|
||||
}else{
|
||||
if (&db->aDb[1].pBt != 0) {
|
||||
sqliteErrorMsg(pParse, "The temporary database already exists - "
|
||||
"its location cannot now be changed");
|
||||
} else {
|
||||
db->temp_store = getTempStore(zRight);
|
||||
}
|
||||
}
|
||||
}else
|
||||
|
||||
/*
|
||||
** PRAGMA default_temp_store
|
||||
** PRAGMA default_temp_store = "default"|"memory"|"file"
|
||||
**
|
||||
** Return or set the value of the persistent temp_store flag (as
|
||||
** well as the value currently in force).
|
||||
**
|
||||
** Note that it is possible for the library compile-time options to
|
||||
** override this setting
|
||||
*/
|
||||
if( sqliteStrICmp(zLeft, "default_temp_store")==0 ){
|
||||
static VdbeOpList getTmpDbLoc[] = {
|
||||
{ OP_ColumnName, 0, 1, "temp_store"},
|
||||
{ OP_ReadCookie, 0, 5, 0},
|
||||
{ OP_Callback, 1, 0, 0}};
|
||||
if( pRight->z==pLeft->z ){
|
||||
sqliteVdbeAddOpList(v, ArraySize(getTmpDbLoc), getTmpDbLoc);
|
||||
}else{
|
||||
if (&db->aDb[1].pBt != 0) {
|
||||
sqliteErrorMsg(pParse, "The temporary database already exists - "
|
||||
"its location cannot now be changed");
|
||||
} else {
|
||||
sqliteBeginWriteOperation(pParse, 0, 0);
|
||||
db->temp_store = getTempStore(zRight);
|
||||
sqliteVdbeAddOp(v, OP_Integer, db->temp_store, 0);
|
||||
sqliteVdbeAddOp(v, OP_SetCookie, 0, 5);
|
||||
sqliteEndWriteOperation(pParse);
|
||||
}
|
||||
}
|
||||
}else
|
||||
|
||||
#ifndef NDEBUG
|
||||
if( sqliteStrICmp(zLeft, "parser_trace")==0 ){
|
||||
extern void sqliteParserTrace(FILE*, char *);
|
||||
if( getBoolean(zRight) ){
|
||||
sqliteParserTrace(stdout, "parser: ");
|
||||
}else{
|
||||
sqliteParserTrace(0, 0);
|
||||
}
|
||||
}else
|
||||
#endif
|
||||
|
||||
if( sqliteStrICmp(zLeft, "integrity_check")==0 ){
|
||||
int i, j, addr;
|
||||
|
||||
/* Code that initializes the integrity check program. Set the
|
||||
** error count 0
|
||||
*/
|
||||
static VdbeOpList initCode[] = {
|
||||
{ OP_Integer, 0, 0, 0},
|
||||
{ OP_MemStore, 0, 1, 0},
|
||||
{ OP_ColumnName, 0, 1, "integrity_check"},
|
||||
};
|
||||
|
||||
/* Code to do an BTree integrity check on a single database file.
|
||||
*/
|
||||
static VdbeOpList checkDb[] = {
|
||||
{ OP_SetInsert, 0, 0, "2"},
|
||||
{ OP_Integer, 0, 0, 0}, /* 1 */
|
||||
{ OP_OpenRead, 0, 2, 0},
|
||||
{ OP_Rewind, 0, 7, 0}, /* 3 */
|
||||
{ OP_Column, 0, 3, 0}, /* 4 */
|
||||
{ OP_SetInsert, 0, 0, 0},
|
||||
{ OP_Next, 0, 4, 0}, /* 6 */
|
||||
{ OP_IntegrityCk, 0, 0, 0}, /* 7 */
|
||||
{ OP_Dup, 0, 1, 0},
|
||||
{ OP_String, 0, 0, "ok"},
|
||||
{ OP_StrEq, 0, 12, 0}, /* 10 */
|
||||
{ OP_MemIncr, 0, 0, 0},
|
||||
{ OP_String, 0, 0, "*** in database "},
|
||||
{ OP_String, 0, 0, 0}, /* 13 */
|
||||
{ OP_String, 0, 0, " ***\n"},
|
||||
{ OP_Pull, 3, 0, 0},
|
||||
{ OP_Concat, 4, 1, 0},
|
||||
{ OP_Callback, 1, 0, 0},
|
||||
};
|
||||
|
||||
/* 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 VdbeOpList endCode[] = {
|
||||
{ OP_MemLoad, 0, 0, 0},
|
||||
{ OP_Integer, 0, 0, 0},
|
||||
{ OP_Ne, 0, 0, 0}, /* 2 */
|
||||
{ OP_String, 0, 0, "ok"},
|
||||
{ OP_Callback, 1, 0, 0},
|
||||
};
|
||||
|
||||
/* Initialize the VDBE program */
|
||||
sqliteVdbeAddOpList(v, ArraySize(initCode), initCode);
|
||||
|
||||
/* Do an integrity check on each database file */
|
||||
for(i=0; i<db->nDb; i++){
|
||||
HashElem *x;
|
||||
|
||||
/* Do an integrity check of the B-Tree
|
||||
*/
|
||||
addr = sqliteVdbeAddOpList(v, ArraySize(checkDb), checkDb);
|
||||
sqliteVdbeChangeP1(v, addr+1, i);
|
||||
sqliteVdbeChangeP2(v, addr+3, addr+7);
|
||||
sqliteVdbeChangeP2(v, addr+6, addr+4);
|
||||
sqliteVdbeChangeP2(v, addr+7, i);
|
||||
sqliteVdbeChangeP2(v, addr+10, addr+ArraySize(checkDb));
|
||||
sqliteVdbeChangeP3(v, addr+13, db->aDb[i].zName, P3_STATIC);
|
||||
|
||||
/* Make sure all the indices are constructed correctly.
|
||||
*/
|
||||
sqliteCodeVerifySchema(pParse, i);
|
||||
for(x=sqliteHashFirst(&db->aDb[i].tblHash); x; x=sqliteHashNext(x)){
|
||||
Table *pTab = sqliteHashData(x);
|
||||
Index *pIdx;
|
||||
int loopTop;
|
||||
|
||||
if( pTab->pIndex==0 ) continue;
|
||||
sqliteVdbeAddOp(v, OP_Integer, i, 0);
|
||||
sqliteVdbeOp3(v, OP_OpenRead, 1, pTab->tnum, pTab->zName, 0);
|
||||
for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
|
||||
if( pIdx->tnum==0 ) continue;
|
||||
sqliteVdbeAddOp(v, OP_Integer, pIdx->iDb, 0);
|
||||
sqliteVdbeOp3(v, OP_OpenRead, j+2, pIdx->tnum, pIdx->zName, 0);
|
||||
}
|
||||
sqliteVdbeAddOp(v, OP_Integer, 0, 0);
|
||||
sqliteVdbeAddOp(v, OP_MemStore, 1, 1);
|
||||
loopTop = sqliteVdbeAddOp(v, OP_Rewind, 1, 0);
|
||||
sqliteVdbeAddOp(v, OP_MemIncr, 1, 0);
|
||||
for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
|
||||
int k, jmp2;
|
||||
static VdbeOpList idxErr[] = {
|
||||
{ OP_MemIncr, 0, 0, 0},
|
||||
{ OP_String, 0, 0, "rowid "},
|
||||
{ OP_Recno, 1, 0, 0},
|
||||
{ OP_String, 0, 0, " missing from index "},
|
||||
{ OP_String, 0, 0, 0}, /* 4 */
|
||||
{ OP_Concat, 4, 0, 0},
|
||||
{ OP_Callback, 1, 0, 0},
|
||||
};
|
||||
sqliteVdbeAddOp(v, OP_Recno, 1, 0);
|
||||
for(k=0; k<pIdx->nColumn; k++){
|
||||
int idx = pIdx->aiColumn[k];
|
||||
if( idx==pTab->iPKey ){
|
||||
sqliteVdbeAddOp(v, OP_Recno, 1, 0);
|
||||
}else{
|
||||
sqliteVdbeAddOp(v, OP_Column, 1, idx);
|
||||
}
|
||||
}
|
||||
sqliteVdbeAddOp(v, OP_MakeIdxKey, pIdx->nColumn, 0);
|
||||
if( db->file_format>=4 ) sqliteAddIdxKeyType(v, pIdx);
|
||||
jmp2 = sqliteVdbeAddOp(v, OP_Found, j+2, 0);
|
||||
addr = sqliteVdbeAddOpList(v, ArraySize(idxErr), idxErr);
|
||||
sqliteVdbeChangeP3(v, addr+4, pIdx->zName, P3_STATIC);
|
||||
sqliteVdbeChangeP2(v, jmp2, sqliteVdbeCurrentAddr(v));
|
||||
}
|
||||
sqliteVdbeAddOp(v, OP_Next, 1, loopTop+1);
|
||||
sqliteVdbeChangeP2(v, loopTop, sqliteVdbeCurrentAddr(v));
|
||||
for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
|
||||
static VdbeOpList cntIdx[] = {
|
||||
{ OP_Integer, 0, 0, 0},
|
||||
{ OP_MemStore, 2, 1, 0},
|
||||
{ OP_Rewind, 0, 0, 0}, /* 2 */
|
||||
{ OP_MemIncr, 2, 0, 0},
|
||||
{ OP_Next, 0, 0, 0}, /* 4 */
|
||||
{ OP_MemLoad, 1, 0, 0},
|
||||
{ OP_MemLoad, 2, 0, 0},
|
||||
{ OP_Eq, 0, 0, 0}, /* 7 */
|
||||
{ OP_MemIncr, 0, 0, 0},
|
||||
{ OP_String, 0, 0, "wrong # of entries in index "},
|
||||
{ OP_String, 0, 0, 0}, /* 10 */
|
||||
{ OP_Concat, 2, 0, 0},
|
||||
{ OP_Callback, 1, 0, 0},
|
||||
};
|
||||
if( pIdx->tnum==0 ) continue;
|
||||
addr = sqliteVdbeAddOpList(v, ArraySize(cntIdx), cntIdx);
|
||||
sqliteVdbeChangeP1(v, addr+2, j+2);
|
||||
sqliteVdbeChangeP2(v, addr+2, addr+5);
|
||||
sqliteVdbeChangeP1(v, addr+4, j+2);
|
||||
sqliteVdbeChangeP2(v, addr+4, addr+3);
|
||||
sqliteVdbeChangeP2(v, addr+7, addr+ArraySize(cntIdx));
|
||||
sqliteVdbeChangeP3(v, addr+10, pIdx->zName, P3_STATIC);
|
||||
}
|
||||
}
|
||||
}
|
||||
addr = sqliteVdbeAddOpList(v, ArraySize(endCode), endCode);
|
||||
sqliteVdbeChangeP2(v, addr+2, addr+ArraySize(endCode));
|
||||
}else
|
||||
|
||||
{}
|
||||
sqliteFree(zLeft);
|
||||
sqliteFree(zRight);
|
||||
}
|
855
sqlite/printf.c
Executable file
855
sqlite/printf.c
Executable file
@ -0,0 +1,855 @@
|
||||
/*
|
||||
** 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 */
|
||||
|
||||
|
||||
/*
|
||||
** 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 */
|
||||
char *charset; /* The character set for conversion */
|
||||
char *prefix; /* Prefix on non-zero values in alt format */
|
||||
} 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 */
|
||||
|
||||
|
||||
/*
|
||||
** The following table is searched linearly, so it is good to put the
|
||||
** most frequently used conversion types first.
|
||||
*/
|
||||
static et_info fmtinfo[] = {
|
||||
{ 'd', 10, 1, etRADIX, "0123456789", 0 },
|
||||
{ 's', 0, 0, etSTRING, 0, 0 },
|
||||
{ 'z', 0, 2, etDYNSTRING, 0, 0 },
|
||||
{ 'q', 0, 0, etSQLESCAPE, 0, 0 },
|
||||
{ 'Q', 0, 0, etSQLESCAPE2, 0, 0 },
|
||||
{ 'c', 0, 0, etCHARX, 0, 0 },
|
||||
{ 'o', 8, 0, etRADIX, "01234567", "0" },
|
||||
{ 'u', 10, 0, etRADIX, "0123456789", 0 },
|
||||
{ 'x', 16, 0, etRADIX, "0123456789abcdef", "x0" },
|
||||
{ 'X', 16, 0, etRADIX, "0123456789ABCDEF", "X0" },
|
||||
{ 'f', 0, 1, etFLOAT, 0, 0 },
|
||||
{ 'e', 0, 1, etEXP, "e", 0 },
|
||||
{ 'E', 0, 1, etEXP, "E", 0 },
|
||||
{ 'g', 0, 1, etGENERIC, "e", 0 },
|
||||
{ 'G', 0, 1, etGENERIC, "E", 0 },
|
||||
{ 'i', 10, 1, etRADIX, "0123456789", 0 },
|
||||
{ 'n', 0, 0, etSIZE, 0, 0 },
|
||||
{ '%', 0, 0, etPERCENT, 0, 0 },
|
||||
{ 'p', 10, 0, etRADIX, "0123456789", 0 },
|
||||
{ 'T', 0, 2, etTOKEN, 0, 0 },
|
||||
{ 'S', 0, 2, etSRCLIST, 0, 0 },
|
||||
};
|
||||
#define etNINFO (sizeof(fmtinfo)/sizeof(fmtinfo[0]))
|
||||
|
||||
/*
|
||||
** If NOFLOATINGPOINT is defined, then none of the floating point
|
||||
** conversions will work.
|
||||
*/
|
||||
#ifndef etNOFLOATINGPOINT
|
||||
/*
|
||||
** "*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
|
||||
|
||||
#define etBUFSIZE 1000 /* 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_zeropad; /* True if field width constant starts with zero */
|
||||
etByte flag_long; /* True if "l" flag is present */
|
||||
unsigned long longvalue; /* Value for integer types */
|
||||
LONGDOUBLE_TYPE realvalue; /* Value for real types */
|
||||
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 char spaces[] = " ";
|
||||
#define etSPACESIZE (sizeof(spaces)-1)
|
||||
#ifndef etNOFLOATINGPOINT
|
||||
int exp; /* 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
|
||||
|
||||
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_zeropad = 0;
|
||||
do{
|
||||
switch( c ){
|
||||
case '-': flag_leftjustify = 1; c = 0; break;
|
||||
case '+': flag_plussign = 1; c = 0; break;
|
||||
case ' ': flag_blanksign = 1; c = 0; break;
|
||||
case '#': flag_alternateform = 1; c = 0; break;
|
||||
case '0': flag_zeropad = 1; c = 0; break;
|
||||
default: break;
|
||||
}
|
||||
}while( c==0 && (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;
|
||||
}
|
||||
}
|
||||
/* Limit the precision to prevent overflowing buf[] during conversion */
|
||||
if( precision>etBUFSIZE-40 ) precision = etBUFSIZE-40;
|
||||
}else{
|
||||
precision = -1;
|
||||
}
|
||||
/* Get the conversion type modifier */
|
||||
if( c=='l' ){
|
||||
flag_long = 1;
|
||||
c = *++fmt;
|
||||
}else{
|
||||
flag_long = 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;
|
||||
|
||||
/*
|
||||
** At this point, variables are initialized as follows:
|
||||
**
|
||||
** flag_alternateform 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_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 etRADIX:
|
||||
if( flag_long ) longvalue = va_arg(ap,long);
|
||||
else longvalue = va_arg(ap,int);
|
||||
#if 1
|
||||
/* For the format %#x, the value zero is printed "0" not "0x0".
|
||||
** I think this is stupid. */
|
||||
if( longvalue==0 ) flag_alternateform = 0;
|
||||
#else
|
||||
/* More sensible: turn off the prefix for octal (to prevent "00"),
|
||||
** but leave the prefix for hex. */
|
||||
if( longvalue==0 && infop->base==8 ) flag_alternateform = 0;
|
||||
#endif
|
||||
if( infop->flags & FLAG_SIGNED ){
|
||||
if( *(long*)&longvalue<0 ){
|
||||
longvalue = -*(long*)&longvalue;
|
||||
prefix = '-';
|
||||
}else if( flag_plussign ) prefix = '+';
|
||||
else if( flag_blanksign ) prefix = ' ';
|
||||
else prefix = 0;
|
||||
}else prefix = 0;
|
||||
if( flag_zeropad && precision<width-(prefix!=0) ){
|
||||
precision = width-(prefix!=0);
|
||||
}
|
||||
bufpt = &buf[etBUFSIZE-1];
|
||||
{
|
||||
register char *cset; /* Use registers for speed */
|
||||
register int base;
|
||||
cset = 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" */
|
||||
char *pre, x;
|
||||
pre = infop->prefix;
|
||||
if( *bufpt!=pre[0] ){
|
||||
for(pre=infop->prefix; (x=(*pre))!=0; pre++) *(--bufpt) = x;
|
||||
}
|
||||
}
|
||||
length = &buf[etBUFSIZE-1]-bufpt;
|
||||
break;
|
||||
case etFLOAT:
|
||||
case etEXP:
|
||||
case etGENERIC:
|
||||
realvalue = va_arg(ap,double);
|
||||
#ifndef etNOFLOATINGPOINT
|
||||
if( precision<0 ) precision = 6; /* Set default precision */
|
||||
if( precision>etBUFSIZE-10 ) precision = etBUFSIZE-10;
|
||||
if( realvalue<0.0 ){
|
||||
realvalue = -realvalue;
|
||||
prefix = '-';
|
||||
}else{
|
||||
if( flag_plussign ) prefix = '+';
|
||||
else if( flag_blanksign ) prefix = ' ';
|
||||
else prefix = 0;
|
||||
}
|
||||
if( infop->type==etGENERIC && precision>0 ) precision--;
|
||||
rounder = 0.0;
|
||||
#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( infop->type==etFLOAT ) realvalue += rounder;
|
||||
/* Normalize realvalue to within 10.0 > realvalue >= 1.0 */
|
||||
exp = 0;
|
||||
if( realvalue>0.0 ){
|
||||
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;
|
||||
}
|
||||
/*
|
||||
** The "exp+precision" test causes output to be of type etEXP if
|
||||
** the precision is too large to fit in buf[].
|
||||
*/
|
||||
nsd = 0;
|
||||
if( xtype==etFLOAT && exp+precision<etBUFSIZE-30 ){
|
||||
flag_dp = (precision>0 || flag_alternateform);
|
||||
if( prefix ) *(bufpt++) = prefix; /* Sign */
|
||||
if( exp<0 ) *(bufpt++) = '0'; /* Digits before "." */
|
||||
else for(; exp>=0; exp--) *(bufpt++) = et_getdigit(&realvalue,&nsd);
|
||||
if( flag_dp ) *(bufpt++) = '.'; /* The decimal point */
|
||||
for(exp++; exp<0 && precision>0; precision--, exp++){
|
||||
*(bufpt++) = '0';
|
||||
}
|
||||
while( (precision--)>0 ) *(bufpt++) = et_getdigit(&realvalue,&nsd);
|
||||
*(bufpt--) = 0; /* Null terminate */
|
||||
if( flag_rtz && flag_dp ){ /* Remove trailing zeros and "." */
|
||||
while( bufpt>=buf && *bufpt=='0' ) *(bufpt--) = 0;
|
||||
if( bufpt>=buf && *bufpt=='.' ) *(bufpt--) = 0;
|
||||
}
|
||||
bufpt++; /* point to next free slot */
|
||||
}else{ /* etEXP or etGENERIC */
|
||||
flag_dp = (precision>0 || flag_alternateform);
|
||||
if( prefix ) *(bufpt++) = prefix; /* Sign */
|
||||
*(bufpt++) = et_getdigit(&realvalue,&nsd); /* First digit */
|
||||
if( flag_dp ) *(bufpt++) = '.'; /* Decimal point */
|
||||
while( (precision--)>0 ) *(bufpt++) = et_getdigit(&realvalue,&nsd);
|
||||
bufpt--; /* point to last digit */
|
||||
if( flag_rtz && flag_dp ){ /* Remove tail zeros */
|
||||
while( bufpt>=buf && *bufpt=='0' ) *(bufpt--) = 0;
|
||||
if( bufpt>=buf && *bufpt=='.' ) *(bufpt--) = 0;
|
||||
}
|
||||
bufpt++; /* point to next free slot */
|
||||
if( exp || flag_exp ){
|
||||
*(bufpt++) = infop->charset[0];
|
||||
if( exp<0 ){ *(bufpt++) = '-'; exp = -exp; } /* sign of 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 */
|
||||
}
|
||||
}
|
||||
/* 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, c, isnull;
|
||||
char *arg = va_arg(ap,char*);
|
||||
isnull = arg==0;
|
||||
if( isnull ) arg = (xtype==etSQLESCAPE2 ? "NULL" : "(NULL)");
|
||||
for(i=n=0; (c=arg[i])!=0; i++){
|
||||
if( c=='\'' ) n++;
|
||||
}
|
||||
n += i + 1 + ((!isnull && xtype==etSQLESCAPE2) ? 2 : 0);
|
||||
if( n>etBUFSIZE ){
|
||||
bufpt = zExtra = sqliteMalloc( n );
|
||||
if( bufpt==0 ) return -1;
|
||||
}else{
|
||||
bufpt = buf;
|
||||
}
|
||||
j = 0;
|
||||
if( !isnull && xtype==etSQLESCAPE2 ) bufpt[j++] = '\'';
|
||||
for(i=0; (c=arg[i])!=0; i++){
|
||||
bufpt[j++] = c;
|
||||
if( c=='\'' ) bufpt[j++] = c;
|
||||
}
|
||||
if( !isnull && xtype==etSQLESCAPE2 ) bufpt[j++] = '\'';
|
||||
bufpt[j] = 0;
|
||||
length = j;
|
||||
if( precision>=0 && precision<length ) length = precision;
|
||||
}
|
||||
break;
|
||||
case etTOKEN: {
|
||||
Token *pToken = va_arg(ap, Token*);
|
||||
(*func)(arg, 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{
|
||||
pM->zText = pM->xRealloc(pM->zText, pM->nAlloc);
|
||||
}
|
||||
}
|
||||
}
|
||||
if( pM->zText && 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);
|
||||
memcpy(sM.zText, sM.zBase, sM.nChar+1);
|
||||
}else if( sM.nAlloc>sM.nChar+10 ){
|
||||
sM.zText = xRealloc(sM.zText, sM.nChar+1);
|
||||
}
|
||||
}
|
||||
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 *sqliteVMPrintf(const char *zFormat, va_list ap){
|
||||
char zBase[1000];
|
||||
return base_vprintf(printf_realloc, 1, zBase, sizeof(zBase), zFormat, ap);
|
||||
}
|
||||
|
||||
/*
|
||||
** Print into memory obtained from sqliteMalloc(). Use the internal
|
||||
** %-conversion extensions.
|
||||
*/
|
||||
char *sqliteMPrintf(const char *zFormat, ...){
|
||||
va_list ap;
|
||||
char *z;
|
||||
char zBase[1000];
|
||||
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 *sqlite_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 sqlite_mprintf.
|
||||
*/
|
||||
char *sqlite_vmprintf(const char *zFormat, va_list ap){
|
||||
char zBuf[200];
|
||||
return base_vprintf((void*(*)(void*,int))realloc, 0,
|
||||
zBuf, sizeof(zBuf), zFormat, ap);
|
||||
}
|
||||
|
||||
/*
|
||||
** sqlite_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 *sqlite_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;
|
||||
}
|
||||
|
||||
/*
|
||||
** The following four routines implement the varargs versions of the
|
||||
** sqlite_exec() and sqlite_get_table() interfaces. See the sqlite.h
|
||||
** header files for a more detailed description of how these interfaces
|
||||
** work.
|
||||
**
|
||||
** These routines are all just simple wrappers.
|
||||
*/
|
||||
int sqlite_exec_printf(
|
||||
sqlite *db, /* An open database */
|
||||
const char *sqlFormat, /* printf-style format string for the SQL */
|
||||
sqlite_callback xCallback, /* Callback function */
|
||||
void *pArg, /* 1st argument to callback function */
|
||||
char **errmsg, /* Error msg written here */
|
||||
... /* Arguments to the format string. */
|
||||
){
|
||||
va_list ap;
|
||||
int rc;
|
||||
|
||||
va_start(ap, errmsg);
|
||||
rc = sqlite_exec_vprintf(db, sqlFormat, xCallback, pArg, errmsg, ap);
|
||||
va_end(ap);
|
||||
return rc;
|
||||
}
|
||||
int sqlite_exec_vprintf(
|
||||
sqlite *db, /* An open database */
|
||||
const char *sqlFormat, /* printf-style format string for the SQL */
|
||||
sqlite_callback xCallback, /* Callback function */
|
||||
void *pArg, /* 1st argument to callback function */
|
||||
char **errmsg, /* Error msg written here */
|
||||
va_list ap /* Arguments to the format string. */
|
||||
){
|
||||
char *zSql;
|
||||
int rc;
|
||||
|
||||
zSql = sqlite_vmprintf(sqlFormat, ap);
|
||||
rc = sqlite_exec(db, zSql, xCallback, pArg, errmsg);
|
||||
free(zSql);
|
||||
return rc;
|
||||
}
|
||||
int sqlite_get_table_printf(
|
||||
sqlite *db, /* An open database */
|
||||
const char *sqlFormat, /* printf-style format string for the SQL */
|
||||
char ***resultp, /* Result written to a char *[] that this points to */
|
||||
int *nrow, /* Number of result rows written here */
|
||||
int *ncol, /* Number of result columns written here */
|
||||
char **errmsg, /* Error msg written here */
|
||||
... /* Arguments to the format string */
|
||||
){
|
||||
va_list ap;
|
||||
int rc;
|
||||
|
||||
va_start(ap, errmsg);
|
||||
rc = sqlite_get_table_vprintf(db, sqlFormat, resultp, nrow, ncol, errmsg, ap);
|
||||
va_end(ap);
|
||||
return rc;
|
||||
}
|
||||
int sqlite_get_table_vprintf(
|
||||
sqlite *db, /* An open database */
|
||||
const char *sqlFormat, /* printf-style format string for the SQL */
|
||||
char ***resultp, /* Result written to a char *[] that this points to */
|
||||
int *nrow, /* Number of result rows written here */
|
||||
int *ncolumn, /* Number of result columns written here */
|
||||
char **errmsg, /* Error msg written here */
|
||||
va_list ap /* Arguments to the format string */
|
||||
){
|
||||
char *zSql;
|
||||
int rc;
|
||||
|
||||
zSql = sqlite_vmprintf(sqlFormat, ap);
|
||||
rc = sqlite_get_table(db, zSql, resultp, nrow, ncolumn, errmsg);
|
||||
free(zSql);
|
||||
return rc;
|
||||
}
|
97
sqlite/random.c
Executable file
97
sqlite/random.c
Executable file
@ -0,0 +1,97 @@
|
||||
/*
|
||||
** 2001 September 15
|
||||
**
|
||||
** The author disclaims copyright to this source code. In place of
|
||||
** a legal notice, here is a blessing:
|
||||
**
|
||||
** May you do good and not evil.
|
||||
** May you find forgiveness for yourself and forgive others.
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
*************************************************************************
|
||||
** This file contains code to implement a pseudo-random number
|
||||
** generator (PRNG) for SQLite.
|
||||
**
|
||||
** Random numbers are used by some of the database backends in order
|
||||
** to generate random integer keys for tables or random filenames.
|
||||
**
|
||||
** $Id: random.c,v 1.1.1.1 2004-03-11 22:22:23 alex Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include "os.h"
|
||||
|
||||
|
||||
/*
|
||||
** Get a single 8-bit random value from the RC4 PRNG. The Mutex
|
||||
** must be held while executing this routine.
|
||||
**
|
||||
** Why not just use a library random generator like lrand48() for this?
|
||||
** Because the OP_NewRecno opcode in the VDBE depends on having a very
|
||||
** good source of random numbers. The lrand48() library function may
|
||||
** well be good enough. But maybe not. Or maybe lrand48() has some
|
||||
** subtle problems on some systems that could cause problems. It is hard
|
||||
** to know. To minimize the risk of problems due to bad lrand48()
|
||||
** implementations, SQLite uses this random number generator based
|
||||
** on RC4, which we know works very well.
|
||||
*/
|
||||
static int randomByte(){
|
||||
unsigned char t;
|
||||
|
||||
/* All threads share a single random number generator.
|
||||
** This structure is the current state of the generator.
|
||||
*/
|
||||
static struct {
|
||||
unsigned char isInit; /* True if initialized */
|
||||
unsigned char i, j; /* State variables */
|
||||
unsigned char s[256]; /* State variables */
|
||||
} prng;
|
||||
|
||||
/* Initialize the state of the random number generator once,
|
||||
** the first time this routine is called. The seed value does
|
||||
** not need to contain a lot of randomness since we are not
|
||||
** trying to do secure encryption or anything like that...
|
||||
**
|
||||
** Nothing in this file or anywhere else in SQLite does any kind of
|
||||
** encryption. The RC4 algorithm is being used as a PRNG (pseudo-random
|
||||
** number generator) not as an encryption device.
|
||||
*/
|
||||
if( !prng.isInit ){
|
||||
int i;
|
||||
char k[256];
|
||||
prng.j = 0;
|
||||
prng.i = 0;
|
||||
sqliteOsRandomSeed(k);
|
||||
for(i=0; i<256; i++){
|
||||
prng.s[i] = i;
|
||||
}
|
||||
for(i=0; i<256; i++){
|
||||
prng.j += prng.s[i] + k[i];
|
||||
t = prng.s[prng.j];
|
||||
prng.s[prng.j] = prng.s[i];
|
||||
prng.s[i] = t;
|
||||
}
|
||||
prng.isInit = 1;
|
||||
}
|
||||
|
||||
/* Generate and return single random byte
|
||||
*/
|
||||
prng.i++;
|
||||
t = prng.s[prng.i];
|
||||
prng.j += t;
|
||||
prng.s[prng.i] = prng.s[prng.j];
|
||||
prng.s[prng.j] = t;
|
||||
t += prng.s[prng.i];
|
||||
return prng.s[t];
|
||||
}
|
||||
|
||||
/*
|
||||
** Return N random bytes.
|
||||
*/
|
||||
void sqliteRandomness(int N, void *pBuf){
|
||||
unsigned char *zBuf = pBuf;
|
||||
sqliteOsEnterMutex();
|
||||
while( N-- ){
|
||||
*(zBuf++) = randomByte();
|
||||
}
|
||||
sqliteOsLeaveMutex();
|
||||
}
|
2404
sqlite/select.c
Executable file
2404
sqlite/select.c
Executable file
File diff suppressed because it is too large
Load Diff
1350
sqlite/shell.c
Executable file
1350
sqlite/shell.c
Executable file
File diff suppressed because it is too large
Load Diff
834
sqlite/sqlite.h
Executable file
834
sqlite/sqlite.h
Executable file
@ -0,0 +1,834 @@
|
||||
/*
|
||||
** 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 library
|
||||
** presents to client programs.
|
||||
**
|
||||
** @(#) $Id: sqlite.h,v 1.1.1.1 2004-03-11 22:22:22 alex Exp $
|
||||
*/
|
||||
#ifndef _SQLITE_H_
|
||||
#define _SQLITE_H_
|
||||
#include <stdarg.h> /* Needed for the definition of va_list */
|
||||
|
||||
/*
|
||||
** Make sure we can call this stuff from C++.
|
||||
*/
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
** The version of the SQLite library.
|
||||
*/
|
||||
#define SQLITE_VERSION "2.8.13"
|
||||
|
||||
/*
|
||||
** The version string is also compiled into the library so that a program
|
||||
** can check to make sure that the lib*.a file and the *.h file are from
|
||||
** the same version.
|
||||
*/
|
||||
extern const char sqlite_version[];
|
||||
|
||||
/*
|
||||
** The SQLITE_UTF8 macro is defined if the library expects to see
|
||||
** UTF-8 encoded data. The SQLITE_ISO8859 macro is defined if the
|
||||
** iso8859 encoded should be used.
|
||||
*/
|
||||
#define SQLITE_ISO8859 1
|
||||
|
||||
/*
|
||||
** The following constant holds one of two strings, "UTF-8" or "iso8859",
|
||||
** depending on which character encoding the SQLite library expects to
|
||||
** see. The character encoding makes a difference for the LIKE and GLOB
|
||||
** operators and for the LENGTH() and SUBSTR() functions.
|
||||
*/
|
||||
extern const char sqlite_encoding[];
|
||||
|
||||
/*
|
||||
** Each open sqlite database is represented by an instance of the
|
||||
** following opaque structure.
|
||||
*/
|
||||
typedef struct sqlite sqlite;
|
||||
|
||||
/*
|
||||
** A function to open a new sqlite database.
|
||||
**
|
||||
** If the database does not exist and mode indicates write
|
||||
** permission, then a new database is created. If the database
|
||||
** does not exist and mode does not indicate write permission,
|
||||
** then the open fails, an error message generated (if errmsg!=0)
|
||||
** and the function returns 0.
|
||||
**
|
||||
** If mode does not indicates user write permission, then the
|
||||
** database is opened read-only.
|
||||
**
|
||||
** The Truth: As currently implemented, all databases are opened
|
||||
** for writing all the time. Maybe someday we will provide the
|
||||
** ability to open a database readonly. The mode parameters is
|
||||
** provided in anticipation of that enhancement.
|
||||
*/
|
||||
sqlite *sqlite_open(const char *filename, int mode, char **errmsg);
|
||||
|
||||
/*
|
||||
** A function to close the database.
|
||||
**
|
||||
** Call this function with a pointer to a structure that was previously
|
||||
** returned from sqlite_open() and the corresponding database will by closed.
|
||||
*/
|
||||
void sqlite_close(sqlite *);
|
||||
|
||||
/*
|
||||
** The type for a callback function.
|
||||
*/
|
||||
typedef int (*sqlite_callback)(void*,int,char**, char**);
|
||||
|
||||
/*
|
||||
** A function to executes one or more statements of SQL.
|
||||
**
|
||||
** If one or more of the SQL statements are queries, then
|
||||
** the callback function specified by the 3rd parameter is
|
||||
** invoked once for each row of the query result. This callback
|
||||
** should normally return 0. If the callback returns a non-zero
|
||||
** value then the query is aborted, all subsequent SQL statements
|
||||
** are skipped and the sqlite_exec() function returns the SQLITE_ABORT.
|
||||
**
|
||||
** The 4th parameter is an arbitrary pointer that is passed
|
||||
** to the callback function as its first parameter.
|
||||
**
|
||||
** The 2nd parameter to the callback function is the number of
|
||||
** columns in the query result. The 3rd parameter to the callback
|
||||
** is an array of strings holding the values for each column.
|
||||
** The 4th parameter to the callback is an array of strings holding
|
||||
** the names of each column.
|
||||
**
|
||||
** The callback function may be NULL, even for queries. A NULL
|
||||
** callback is not an error. It just means that no callback
|
||||
** will be invoked.
|
||||
**
|
||||
** If an error occurs while parsing or evaluating the SQL (but
|
||||
** not while executing the callback) then an appropriate error
|
||||
** message is written into memory obtained from malloc() and
|
||||
** *errmsg is made to point to that message. The calling function
|
||||
** is responsible for freeing the memory that holds the error
|
||||
** message. Use sqlite_freemem() for this. If errmsg==NULL,
|
||||
** then no error message is ever written.
|
||||
**
|
||||
** The return value is is SQLITE_OK if there are no errors and
|
||||
** some other return code if there is an error. The particular
|
||||
** return value depends on the type of error.
|
||||
**
|
||||
** If the query could not be executed because a database file is
|
||||
** locked or busy, then this function returns SQLITE_BUSY. (This
|
||||
** behavior can be modified somewhat using the sqlite_busy_handler()
|
||||
** and sqlite_busy_timeout() functions below.)
|
||||
*/
|
||||
int sqlite_exec(
|
||||
sqlite*, /* An open database */
|
||||
const char *sql, /* SQL to be executed */
|
||||
sqlite_callback, /* Callback function */
|
||||
void *, /* 1st argument to callback function */
|
||||
char **errmsg /* Error msg written here */
|
||||
);
|
||||
|
||||
/*
|
||||
** Return values for sqlite_exec() and sqlite_step()
|
||||
*/
|
||||
#define SQLITE_OK 0 /* Successful result */
|
||||
#define SQLITE_ERROR 1 /* SQL error or missing database */
|
||||
#define SQLITE_INTERNAL 2 /* An internal logic error in SQLite */
|
||||
#define SQLITE_PERM 3 /* Access permission denied */
|
||||
#define SQLITE_ABORT 4 /* Callback routine requested an abort */
|
||||
#define SQLITE_BUSY 5 /* The database file is locked */
|
||||
#define SQLITE_LOCKED 6 /* A table in the database is locked */
|
||||
#define SQLITE_NOMEM 7 /* A malloc() failed */
|
||||
#define SQLITE_READONLY 8 /* Attempt to write a readonly database */
|
||||
#define SQLITE_INTERRUPT 9 /* Operation terminated by sqlite_interrupt() */
|
||||
#define SQLITE_IOERR 10 /* Some kind of disk I/O error occurred */
|
||||
#define SQLITE_CORRUPT 11 /* The database disk image is malformed */
|
||||
#define SQLITE_NOTFOUND 12 /* (Internal Only) Table or record not found */
|
||||
#define SQLITE_FULL 13 /* Insertion failed because database is full */
|
||||
#define SQLITE_CANTOPEN 14 /* Unable to open the database file */
|
||||
#define SQLITE_PROTOCOL 15 /* Database lock protocol error */
|
||||
#define SQLITE_EMPTY 16 /* (Internal Only) Database table is empty */
|
||||
#define SQLITE_SCHEMA 17 /* The database schema changed */
|
||||
#define SQLITE_TOOBIG 18 /* Too much data for one row of a table */
|
||||
#define SQLITE_CONSTRAINT 19 /* Abort due to contraint violation */
|
||||
#define SQLITE_MISMATCH 20 /* Data type mismatch */
|
||||
#define SQLITE_MISUSE 21 /* Library used incorrectly */
|
||||
#define SQLITE_NOLFS 22 /* Uses OS features not supported on host */
|
||||
#define SQLITE_AUTH 23 /* Authorization denied */
|
||||
#define SQLITE_FORMAT 24 /* Auxiliary database format error */
|
||||
#define SQLITE_RANGE 25 /* 2nd parameter to sqlite_bind out of range */
|
||||
#define SQLITE_NOTADB 26 /* File opened that is not a database file */
|
||||
#define SQLITE_ROW 100 /* sqlite_step() has another row ready */
|
||||
#define SQLITE_DONE 101 /* sqlite_step() has finished executing */
|
||||
|
||||
/*
|
||||
** Each entry in an SQLite table has a unique integer key. (The key is
|
||||
** the value of the INTEGER PRIMARY KEY column if there is such a column,
|
||||
** otherwise the key is generated at random. The unique key is always
|
||||
** available as the ROWID, OID, or _ROWID_ column.) The following routine
|
||||
** returns the integer key of the most recent insert in the database.
|
||||
**
|
||||
** This function is similar to the mysql_insert_id() function from MySQL.
|
||||
*/
|
||||
int sqlite_last_insert_rowid(sqlite*);
|
||||
|
||||
/*
|
||||
** This function returns the number of database rows that were changed
|
||||
** (or inserted or deleted) by the most recent called sqlite_exec().
|
||||
**
|
||||
** All changes are counted, even if they were later undone by a
|
||||
** ROLLBACK or ABORT. Except, changes associated with creating and
|
||||
** dropping tables are not counted.
|
||||
**
|
||||
** If a callback invokes sqlite_exec() recursively, then the changes
|
||||
** in the inner, recursive call are counted together with the changes
|
||||
** in the outer call.
|
||||
**
|
||||
** SQLite implements the command "DELETE FROM table" without a WHERE clause
|
||||
** by dropping and recreating the table. (This is much faster than going
|
||||
** through and deleting individual elements form the table.) Because of
|
||||
** this optimization, the change count for "DELETE FROM table" will be
|
||||
** zero regardless of the number of elements that were originally in the
|
||||
** table. To get an accurate count of the number of rows deleted, use
|
||||
** "DELETE FROM table WHERE 1" instead.
|
||||
*/
|
||||
int sqlite_changes(sqlite*);
|
||||
|
||||
/*
|
||||
** This function returns the number of database rows that were changed
|
||||
** by the last INSERT, UPDATE, or DELETE statment executed by sqlite_exec(),
|
||||
** or by the last VM to run to completion. The change count is not updated
|
||||
** by SQL statements other than INSERT, UPDATE or DELETE.
|
||||
**
|
||||
** Changes are counted, even if they are later undone by a ROLLBACK or
|
||||
** ABORT. Changes associated with trigger programs that execute as a
|
||||
** result of the INSERT, UPDATE, or DELETE statement are not counted.
|
||||
**
|
||||
** If a callback invokes sqlite_exec() recursively, then the changes
|
||||
** in the inner, recursive call are counted together with the changes
|
||||
** in the outer call.
|
||||
**
|
||||
** SQLite implements the command "DELETE FROM table" without a WHERE clause
|
||||
** by dropping and recreating the table. (This is much faster than going
|
||||
** through and deleting individual elements form the table.) Because of
|
||||
** this optimization, the change count for "DELETE FROM table" will be
|
||||
** zero regardless of the number of elements that were originally in the
|
||||
** table. To get an accurate count of the number of rows deleted, use
|
||||
** "DELETE FROM table WHERE 1" instead.
|
||||
**
|
||||
******* THIS IS AN EXPERIMENTAL API AND IS SUBJECT TO CHANGE ******
|
||||
*/
|
||||
int sqlite_last_statement_changes(sqlite*);
|
||||
|
||||
/* If the parameter to this routine is one of the return value constants
|
||||
** defined above, then this routine returns a constant text string which
|
||||
** descripts (in English) the meaning of the return value.
|
||||
*/
|
||||
const char *sqlite_error_string(int);
|
||||
#define sqliteErrStr sqlite_error_string /* Legacy. Do not use in new code. */
|
||||
|
||||
/* This function causes any pending database operation to abort and
|
||||
** return at its earliest opportunity. This routine is typically
|
||||
** called in response to a user action such as pressing "Cancel"
|
||||
** or Ctrl-C where the user wants a long query operation to halt
|
||||
** immediately.
|
||||
*/
|
||||
void sqlite_interrupt(sqlite*);
|
||||
|
||||
|
||||
/* This function returns true if the given input string comprises
|
||||
** one or more complete SQL statements.
|
||||
**
|
||||
** The algorithm is simple. If the last token other than spaces
|
||||
** and comments is a semicolon, then return true. otherwise return
|
||||
** false.
|
||||
*/
|
||||
int sqlite_complete(const char *sql);
|
||||
|
||||
/*
|
||||
** This routine identifies a callback function that is invoked
|
||||
** whenever an attempt is made to open a database table that is
|
||||
** currently locked by another process or thread. If the busy callback
|
||||
** is NULL, then sqlite_exec() returns SQLITE_BUSY immediately if
|
||||
** it finds a locked table. If the busy callback is not NULL, then
|
||||
** sqlite_exec() invokes the callback with three arguments. The
|
||||
** second argument is the name of the locked table and the third
|
||||
** argument is the number of times the table has been busy. If the
|
||||
** busy callback returns 0, then sqlite_exec() immediately returns
|
||||
** SQLITE_BUSY. If the callback returns non-zero, then sqlite_exec()
|
||||
** tries to open the table again and the cycle repeats.
|
||||
**
|
||||
** The default busy callback is NULL.
|
||||
**
|
||||
** Sqlite is re-entrant, so the busy handler may start a new query.
|
||||
** (It is not clear why anyone would every want to do this, but it
|
||||
** is allowed, in theory.) But the busy handler may not close the
|
||||
** database. Closing the database from a busy handler will delete
|
||||
** data structures out from under the executing query and will
|
||||
** probably result in a coredump.
|
||||
*/
|
||||
void sqlite_busy_handler(sqlite*, int(*)(void*,const char*,int), void*);
|
||||
|
||||
/*
|
||||
** This routine sets a busy handler that sleeps for a while when a
|
||||
** table is locked. The handler will sleep multiple times until
|
||||
** at least "ms" milleseconds of sleeping have been done. After
|
||||
** "ms" milleseconds of sleeping, the handler returns 0 which
|
||||
** causes sqlite_exec() to return SQLITE_BUSY.
|
||||
**
|
||||
** Calling this routine with an argument less than or equal to zero
|
||||
** turns off all busy handlers.
|
||||
*/
|
||||
void sqlite_busy_timeout(sqlite*, int ms);
|
||||
|
||||
/*
|
||||
** This next routine is really just a wrapper around sqlite_exec().
|
||||
** Instead of invoking a user-supplied callback for each row of the
|
||||
** result, this routine remembers each row of the result in memory
|
||||
** obtained from malloc(), then returns all of the result after the
|
||||
** query has finished.
|
||||
**
|
||||
** As an example, suppose the query result where this table:
|
||||
**
|
||||
** Name | Age
|
||||
** -----------------------
|
||||
** Alice | 43
|
||||
** Bob | 28
|
||||
** Cindy | 21
|
||||
**
|
||||
** If the 3rd argument were &azResult then after the function returns
|
||||
** azResult will contain the following data:
|
||||
**
|
||||
** azResult[0] = "Name";
|
||||
** azResult[1] = "Age";
|
||||
** azResult[2] = "Alice";
|
||||
** azResult[3] = "43";
|
||||
** azResult[4] = "Bob";
|
||||
** azResult[5] = "28";
|
||||
** azResult[6] = "Cindy";
|
||||
** azResult[7] = "21";
|
||||
**
|
||||
** Notice that there is an extra row of data containing the column
|
||||
** headers. But the *nrow return value is still 3. *ncolumn is
|
||||
** set to 2. In general, the number of values inserted into azResult
|
||||
** will be ((*nrow) + 1)*(*ncolumn).
|
||||
**
|
||||
** After the calling function has finished using the result, it should
|
||||
** pass the result data pointer to sqlite_free_table() in order to
|
||||
** release the memory that was malloc-ed. Because of the way the
|
||||
** malloc() happens, the calling function must not try to call
|
||||
** malloc() directly. Only sqlite_free_table() is able to release
|
||||
** the memory properly and safely.
|
||||
**
|
||||
** The return value of this routine is the same as from sqlite_exec().
|
||||
*/
|
||||
int sqlite_get_table(
|
||||
sqlite*, /* An open database */
|
||||
const char *sql, /* SQL to be executed */
|
||||
char ***resultp, /* Result written to a char *[] that this points to */
|
||||
int *nrow, /* Number of result rows written here */
|
||||
int *ncolumn, /* Number of result columns written here */
|
||||
char **errmsg /* Error msg written here */
|
||||
);
|
||||
|
||||
/*
|
||||
** Call this routine to free the memory that sqlite_get_table() allocated.
|
||||
*/
|
||||
void sqlite_free_table(char **result);
|
||||
|
||||
/*
|
||||
** The following routines are wrappers around sqlite_exec() and
|
||||
** sqlite_get_table(). The only difference between the routines that
|
||||
** follow and the originals is that the second argument to the
|
||||
** routines that follow is really a printf()-style format
|
||||
** string describing the SQL to be executed. Arguments to the format
|
||||
** string appear at the end of the argument list.
|
||||
**
|
||||
** All of the usual printf formatting options apply. In addition, there
|
||||
** is a "%q" option. %q works like %s in that it substitutes a null-terminated
|
||||
** string from the argument list. But %q also doubles every '\'' character.
|
||||
** %q is designed for use inside a string literal. By doubling each '\''
|
||||
** character it escapes that character and allows it to be inserted into
|
||||
** the string.
|
||||
**
|
||||
** For example, so some string variable contains text as follows:
|
||||
**
|
||||
** char *zText = "It's a happy day!";
|
||||
**
|
||||
** We can use this text in an SQL statement as follows:
|
||||
**
|
||||
** sqlite_exec_printf(db, "INSERT INTO table VALUES('%q')",
|
||||
** callback1, 0, 0, zText);
|
||||
**
|
||||
** Because the %q format string is used, the '\'' character in zText
|
||||
** is escaped and the SQL generated is as follows:
|
||||
**
|
||||
** INSERT INTO table1 VALUES('It''s a happy day!')
|
||||
**
|
||||
** This is correct. Had we used %s instead of %q, the generated SQL
|
||||
** would have looked like this:
|
||||
**
|
||||
** INSERT INTO table1 VALUES('It's a happy day!');
|
||||
**
|
||||
** This second example is an SQL syntax error. As a general rule you
|
||||
** should always use %q instead of %s when inserting text into a string
|
||||
** literal.
|
||||
*/
|
||||
int sqlite_exec_printf(
|
||||
sqlite*, /* An open database */
|
||||
const char *sqlFormat, /* printf-style format string for the SQL */
|
||||
sqlite_callback, /* Callback function */
|
||||
void *, /* 1st argument to callback function */
|
||||
char **errmsg, /* Error msg written here */
|
||||
... /* Arguments to the format string. */
|
||||
);
|
||||
int sqlite_exec_vprintf(
|
||||
sqlite*, /* An open database */
|
||||
const char *sqlFormat, /* printf-style format string for the SQL */
|
||||
sqlite_callback, /* Callback function */
|
||||
void *, /* 1st argument to callback function */
|
||||
char **errmsg, /* Error msg written here */
|
||||
va_list ap /* Arguments to the format string. */
|
||||
);
|
||||
int sqlite_get_table_printf(
|
||||
sqlite*, /* An open database */
|
||||
const char *sqlFormat, /* printf-style format string for the SQL */
|
||||
char ***resultp, /* Result written to a char *[] that this points to */
|
||||
int *nrow, /* Number of result rows written here */
|
||||
int *ncolumn, /* Number of result columns written here */
|
||||
char **errmsg, /* Error msg written here */
|
||||
... /* Arguments to the format string */
|
||||
);
|
||||
int sqlite_get_table_vprintf(
|
||||
sqlite*, /* An open database */
|
||||
const char *sqlFormat, /* printf-style format string for the SQL */
|
||||
char ***resultp, /* Result written to a char *[] that this points to */
|
||||
int *nrow, /* Number of result rows written here */
|
||||
int *ncolumn, /* Number of result columns written here */
|
||||
char **errmsg, /* Error msg written here */
|
||||
va_list ap /* Arguments to the format string */
|
||||
);
|
||||
char *sqlite_mprintf(const char*,...);
|
||||
char *sqlite_vmprintf(const char*, va_list);
|
||||
|
||||
/*
|
||||
** Windows systems should call this routine to free memory that
|
||||
** is returned in the in the errmsg parameter of sqlite_open() when
|
||||
** SQLite is a DLL. For some reason, it does not work to call free()
|
||||
** directly.
|
||||
*/
|
||||
void sqlite_freemem(void *p);
|
||||
|
||||
/*
|
||||
** Windows systems need functions to call to return the sqlite_version
|
||||
** and sqlite_encoding strings.
|
||||
*/
|
||||
const char *sqlite_libversion(void);
|
||||
const char *sqlite_libencoding(void);
|
||||
|
||||
/*
|
||||
** A pointer to the following structure is used to communicate with
|
||||
** the implementations of user-defined functions.
|
||||
*/
|
||||
typedef struct sqlite_func sqlite_func;
|
||||
|
||||
/*
|
||||
** Use the following routines to create new user-defined functions. See
|
||||
** the documentation for details.
|
||||
*/
|
||||
int sqlite_create_function(
|
||||
sqlite*, /* Database where the new function is registered */
|
||||
const char *zName, /* Name of the new function */
|
||||
int nArg, /* Number of arguments. -1 means any number */
|
||||
void (*xFunc)(sqlite_func*,int,const char**), /* C code to implement */
|
||||
void *pUserData /* Available via the sqlite_user_data() call */
|
||||
);
|
||||
int sqlite_create_aggregate(
|
||||
sqlite*, /* Database where the new function is registered */
|
||||
const char *zName, /* Name of the function */
|
||||
int nArg, /* Number of arguments */
|
||||
void (*xStep)(sqlite_func*,int,const char**), /* Called for each row */
|
||||
void (*xFinalize)(sqlite_func*), /* Called once to get final result */
|
||||
void *pUserData /* Available via the sqlite_user_data() call */
|
||||
);
|
||||
|
||||
/*
|
||||
** Use the following routine to define the datatype returned by a
|
||||
** user-defined function. The second argument can be one of the
|
||||
** constants SQLITE_NUMERIC, SQLITE_TEXT, or SQLITE_ARGS or it
|
||||
** can be an integer greater than or equal to zero. When the datatype
|
||||
** parameter is non-negative, the type of the result will be the
|
||||
** same as the datatype-th argument. If datatype==SQLITE_NUMERIC
|
||||
** then the result is always numeric. If datatype==SQLITE_TEXT then
|
||||
** the result is always text. If datatype==SQLITE_ARGS then the result
|
||||
** is numeric if any argument is numeric and is text otherwise.
|
||||
*/
|
||||
int sqlite_function_type(
|
||||
sqlite *db, /* The database there the function is registered */
|
||||
const char *zName, /* Name of the function */
|
||||
int datatype /* The datatype for this function */
|
||||
);
|
||||
#define SQLITE_NUMERIC (-1)
|
||||
#define SQLITE_TEXT (-2)
|
||||
#define SQLITE_ARGS (-3)
|
||||
|
||||
/*
|
||||
** The user function implementations call one of the following four routines
|
||||
** in order to return their results. The first parameter to each of these
|
||||
** routines is a copy of the first argument to xFunc() or xFinialize().
|
||||
** The second parameter to these routines is the result to be returned.
|
||||
** A NULL can be passed as the second parameter to sqlite_set_result_string()
|
||||
** in order to return a NULL result.
|
||||
**
|
||||
** The 3rd argument to _string and _error is the number of characters to
|
||||
** take from the string. If this argument is negative, then all characters
|
||||
** up to and including the first '\000' are used.
|
||||
**
|
||||
** The sqlite_set_result_string() function allocates a buffer to hold the
|
||||
** result and returns a pointer to this buffer. The calling routine
|
||||
** (that is, the implmentation of a user function) can alter the content
|
||||
** of this buffer if desired.
|
||||
*/
|
||||
char *sqlite_set_result_string(sqlite_func*,const char*,int);
|
||||
void sqlite_set_result_int(sqlite_func*,int);
|
||||
void sqlite_set_result_double(sqlite_func*,double);
|
||||
void sqlite_set_result_error(sqlite_func*,const char*,int);
|
||||
|
||||
/*
|
||||
** The pUserData parameter to the sqlite_create_function() and
|
||||
** sqlite_create_aggregate() routines used to register user functions
|
||||
** is available to the implementation of the function using this
|
||||
** call.
|
||||
*/
|
||||
void *sqlite_user_data(sqlite_func*);
|
||||
|
||||
/*
|
||||
** Aggregate functions use the following routine to allocate
|
||||
** a structure for storing their state. The first time this routine
|
||||
** is called for a particular aggregate, a new structure of size nBytes
|
||||
** is allocated, zeroed, and returned. On subsequent calls (for the
|
||||
** same aggregate instance) the same buffer is returned. The implementation
|
||||
** of the aggregate can use the returned buffer to accumulate data.
|
||||
**
|
||||
** The buffer allocated is freed automatically be SQLite.
|
||||
*/
|
||||
void *sqlite_aggregate_context(sqlite_func*, int nBytes);
|
||||
|
||||
/*
|
||||
** The next routine returns the number of calls to xStep for a particular
|
||||
** aggregate function instance. The current call to xStep counts so this
|
||||
** routine always returns at least 1.
|
||||
*/
|
||||
int sqlite_aggregate_count(sqlite_func*);
|
||||
|
||||
/*
|
||||
** This routine registers a callback with the SQLite library. The
|
||||
** callback is invoked (at compile-time, not at run-time) for each
|
||||
** attempt to access a column of a table in the database. The callback
|
||||
** returns SQLITE_OK if access is allowed, SQLITE_DENY if the entire
|
||||
** SQL statement should be aborted with an error and SQLITE_IGNORE
|
||||
** if the column should be treated as a NULL value.
|
||||
*/
|
||||
int sqlite_set_authorizer(
|
||||
sqlite*,
|
||||
int (*xAuth)(void*,int,const char*,const char*,const char*,const char*),
|
||||
void *pUserData
|
||||
);
|
||||
|
||||
/*
|
||||
** The second parameter to the access authorization function above will
|
||||
** be one of the values below. These values signify what kind of operation
|
||||
** is to be authorized. The 3rd and 4th parameters to the authorization
|
||||
** function will be parameters or NULL depending on which of the following
|
||||
** codes is used as the second parameter. The 5th parameter is the name
|
||||
** of the database ("main", "temp", etc.) if applicable. The 6th parameter
|
||||
** is the name of the inner-most trigger or view that is responsible for
|
||||
** the access attempt or NULL if this access attempt is directly from
|
||||
** input SQL code.
|
||||
**
|
||||
** Arg-3 Arg-4
|
||||
*/
|
||||
#define SQLITE_COPY 0 /* Table Name File Name */
|
||||
#define SQLITE_CREATE_INDEX 1 /* Index Name Table Name */
|
||||
#define SQLITE_CREATE_TABLE 2 /* Table Name NULL */
|
||||
#define SQLITE_CREATE_TEMP_INDEX 3 /* Index Name Table Name */
|
||||
#define SQLITE_CREATE_TEMP_TABLE 4 /* Table Name NULL */
|
||||
#define SQLITE_CREATE_TEMP_TRIGGER 5 /* Trigger Name Table Name */
|
||||
#define SQLITE_CREATE_TEMP_VIEW 6 /* View Name NULL */
|
||||
#define SQLITE_CREATE_TRIGGER 7 /* Trigger Name Table Name */
|
||||
#define SQLITE_CREATE_VIEW 8 /* View Name NULL */
|
||||
#define SQLITE_DELETE 9 /* Table Name NULL */
|
||||
#define SQLITE_DROP_INDEX 10 /* Index Name Table Name */
|
||||
#define SQLITE_DROP_TABLE 11 /* Table Name NULL */
|
||||
#define SQLITE_DROP_TEMP_INDEX 12 /* Index Name Table Name */
|
||||
#define SQLITE_DROP_TEMP_TABLE 13 /* Table Name NULL */
|
||||
#define SQLITE_DROP_TEMP_TRIGGER 14 /* Trigger Name Table Name */
|
||||
#define SQLITE_DROP_TEMP_VIEW 15 /* View Name NULL */
|
||||
#define SQLITE_DROP_TRIGGER 16 /* Trigger Name Table Name */
|
||||
#define SQLITE_DROP_VIEW 17 /* View Name NULL */
|
||||
#define SQLITE_INSERT 18 /* Table Name NULL */
|
||||
#define SQLITE_PRAGMA 19 /* Pragma Name 1st arg or NULL */
|
||||
#define SQLITE_READ 20 /* Table Name Column Name */
|
||||
#define SQLITE_SELECT 21 /* NULL NULL */
|
||||
#define SQLITE_TRANSACTION 22 /* NULL NULL */
|
||||
#define SQLITE_UPDATE 23 /* Table Name Column Name */
|
||||
#define SQLITE_ATTACH 24 /* Filename NULL */
|
||||
#define SQLITE_DETACH 25 /* Database Name NULL */
|
||||
|
||||
|
||||
/*
|
||||
** The return value of the authorization function should be one of the
|
||||
** following constants:
|
||||
*/
|
||||
/* #define SQLITE_OK 0 // Allow access (This is actually defined above) */
|
||||
#define SQLITE_DENY 1 /* Abort the SQL statement with an error */
|
||||
#define SQLITE_IGNORE 2 /* Don't allow access, but don't generate an error */
|
||||
|
||||
/*
|
||||
** Register a function that is called at every invocation of sqlite_exec()
|
||||
** or sqlite_compile(). This function can be used (for example) to generate
|
||||
** a log file of all SQL executed against a database.
|
||||
*/
|
||||
void *sqlite_trace(sqlite*, void(*xTrace)(void*,const char*), void*);
|
||||
|
||||
/*** The Callback-Free API
|
||||
**
|
||||
** The following routines implement a new way to access SQLite that does not
|
||||
** involve the use of callbacks.
|
||||
**
|
||||
** An sqlite_vm is an opaque object that represents a single SQL statement
|
||||
** that is ready to be executed.
|
||||
*/
|
||||
typedef struct sqlite_vm sqlite_vm;
|
||||
|
||||
/*
|
||||
** To execute an SQLite query without the use of callbacks, you first have
|
||||
** to compile the SQL using this routine. The 1st parameter "db" is a pointer
|
||||
** to an sqlite object obtained from sqlite_open(). The 2nd parameter
|
||||
** "zSql" is the text of the SQL to be compiled. The remaining parameters
|
||||
** are all outputs.
|
||||
**
|
||||
** *pzTail is made to point to the first character past the end of the first
|
||||
** SQL statement in zSql. This routine only compiles the first statement
|
||||
** in zSql, so *pzTail is left pointing to what remains uncompiled.
|
||||
**
|
||||
** *ppVm is left pointing to a "virtual machine" that can be used to execute
|
||||
** the compiled statement. Or if there is an error, *ppVm may be set to NULL.
|
||||
** If the input text contained no SQL (if the input is and empty string or
|
||||
** a comment) then *ppVm is set to NULL.
|
||||
**
|
||||
** If any errors are detected during compilation, an error message is written
|
||||
** into space obtained from malloc() and *pzErrMsg is made to point to that
|
||||
** error message. The calling routine is responsible for freeing the text
|
||||
** of this message when it has finished with it. Use sqlite_freemem() to
|
||||
** free the message. pzErrMsg may be NULL in which case no error message
|
||||
** will be generated.
|
||||
**
|
||||
** On success, SQLITE_OK is returned. Otherwise and error code is returned.
|
||||
*/
|
||||
int sqlite_compile(
|
||||
sqlite *db, /* The open database */
|
||||
const char *zSql, /* SQL statement to be compiled */
|
||||
const char **pzTail, /* OUT: uncompiled tail of zSql */
|
||||
sqlite_vm **ppVm, /* OUT: the virtual machine to execute zSql */
|
||||
char **pzErrmsg /* OUT: Error message. */
|
||||
);
|
||||
|
||||
/*
|
||||
** After an SQL statement has been compiled, it is handed to this routine
|
||||
** to be executed. This routine executes the statement as far as it can
|
||||
** go then returns. The return value will be one of SQLITE_DONE,
|
||||
** SQLITE_ERROR, SQLITE_BUSY, SQLITE_ROW, or SQLITE_MISUSE.
|
||||
**
|
||||
** SQLITE_DONE means that the execute of the SQL statement is complete
|
||||
** an no errors have occurred. sqlite_step() should not be called again
|
||||
** for the same virtual machine. *pN is set to the number of columns in
|
||||
** the result set and *pazColName is set to an array of strings that
|
||||
** describe the column names and datatypes. The name of the i-th column
|
||||
** is (*pazColName)[i] and the datatype of the i-th column is
|
||||
** (*pazColName)[i+*pN]. *pazValue is set to NULL.
|
||||
**
|
||||
** SQLITE_ERROR means that the virtual machine encountered a run-time
|
||||
** error. sqlite_step() should not be called again for the same
|
||||
** virtual machine. *pN is set to 0 and *pazColName and *pazValue are set
|
||||
** to NULL. Use sqlite_finalize() to obtain the specific error code
|
||||
** and the error message text for the error.
|
||||
**
|
||||
** SQLITE_BUSY means that an attempt to open the database failed because
|
||||
** another thread or process is holding a lock. The calling routine
|
||||
** can try again to open the database by calling sqlite_step() again.
|
||||
** The return code will only be SQLITE_BUSY if no busy handler is registered
|
||||
** using the sqlite_busy_handler() or sqlite_busy_timeout() routines. If
|
||||
** a busy handler callback has been registered but returns 0, then this
|
||||
** routine will return SQLITE_ERROR and sqltie_finalize() will return
|
||||
** SQLITE_BUSY when it is called.
|
||||
**
|
||||
** SQLITE_ROW means that a single row of the result is now available.
|
||||
** The data is contained in *pazValue. The value of the i-th column is
|
||||
** (*azValue)[i]. *pN and *pazColName are set as described in SQLITE_DONE.
|
||||
** Invoke sqlite_step() again to advance to the next row.
|
||||
**
|
||||
** SQLITE_MISUSE is returned if sqlite_step() is called incorrectly.
|
||||
** For example, if you call sqlite_step() after the virtual machine
|
||||
** has halted (after a prior call to sqlite_step() has returned SQLITE_DONE)
|
||||
** or if you call sqlite_step() with an incorrectly initialized virtual
|
||||
** machine or a virtual machine that has been deleted or that is associated
|
||||
** with an sqlite structure that has been closed.
|
||||
*/
|
||||
int sqlite_step(
|
||||
sqlite_vm *pVm, /* The virtual machine to execute */
|
||||
int *pN, /* OUT: Number of columns in result */
|
||||
const char ***pazValue, /* OUT: Column data */
|
||||
const char ***pazColName /* OUT: Column names and datatypes */
|
||||
);
|
||||
|
||||
/*
|
||||
** This routine is called to delete a virtual machine after it has finished
|
||||
** executing. The return value is the result code. SQLITE_OK is returned
|
||||
** if the statement executed successfully and some other value is returned if
|
||||
** there was any kind of error. If an error occurred and pzErrMsg is not
|
||||
** NULL, then an error message is written into memory obtained from malloc()
|
||||
** and *pzErrMsg is made to point to that error message. The calling routine
|
||||
** should use sqlite_freemem() to delete this message when it has finished
|
||||
** with it.
|
||||
**
|
||||
** This routine can be called at any point during the execution of the
|
||||
** virtual machine. If the virtual machine has not completed execution
|
||||
** when this routine is called, that is like encountering an error or
|
||||
** an interrupt. (See sqlite_interrupt().) Incomplete updates may be
|
||||
** rolled back and transactions cancelled, depending on the circumstances,
|
||||
** and the result code returned will be SQLITE_ABORT.
|
||||
*/
|
||||
int sqlite_finalize(sqlite_vm*, char **pzErrMsg);
|
||||
|
||||
/*
|
||||
** This routine deletes the virtual machine, writes any error message to
|
||||
** *pzErrMsg and returns an SQLite return code in the same way as the
|
||||
** sqlite_finalize() function.
|
||||
**
|
||||
** Additionally, if ppVm is not NULL, *ppVm is left pointing to a new virtual
|
||||
** machine loaded with the compiled version of the original query ready for
|
||||
** execution.
|
||||
**
|
||||
** If sqlite_reset() returns SQLITE_SCHEMA, then *ppVm is set to NULL.
|
||||
**
|
||||
******* THIS IS AN EXPERIMENTAL API AND IS SUBJECT TO CHANGE ******
|
||||
*/
|
||||
int sqlite_reset(sqlite_vm*, char **pzErrMsg);
|
||||
|
||||
/*
|
||||
** If the SQL that was handed to sqlite_compile contains variables that
|
||||
** are represeted in the SQL text by a question mark ('?'). This routine
|
||||
** is used to assign values to those variables.
|
||||
**
|
||||
** The first parameter is a virtual machine obtained from sqlite_compile().
|
||||
** The 2nd "idx" parameter determines which variable in the SQL statement
|
||||
** to bind the value to. The left most '?' is 1. The 3rd parameter is
|
||||
** the value to assign to that variable. The 4th parameter is the number
|
||||
** of bytes in the value, including the terminating \000 for strings.
|
||||
** Finally, the 5th "copy" parameter is TRUE if SQLite should make its
|
||||
** own private copy of this value, or false if the space that the 3rd
|
||||
** parameter points to will be unchanging and can be used directly by
|
||||
** SQLite.
|
||||
**
|
||||
** Unbound variables are treated as having a value of NULL. To explicitly
|
||||
** set a variable to NULL, call this routine with the 3rd parameter as a
|
||||
** NULL pointer.
|
||||
**
|
||||
** If the 4th "len" parameter is -1, then strlen() is used to find the
|
||||
** length.
|
||||
**
|
||||
** This routine can only be called immediately after sqlite_compile()
|
||||
** or sqlite_reset() and before any calls to sqlite_step().
|
||||
**
|
||||
******* THIS IS AN EXPERIMENTAL API AND IS SUBJECT TO CHANGE ******
|
||||
*/
|
||||
int sqlite_bind(sqlite_vm*, int idx, const char *value, int len, int copy);
|
||||
|
||||
/*
|
||||
** This routine configures a callback function - the progress callback - that
|
||||
** is invoked periodically during long running calls to sqlite_exec(),
|
||||
** sqlite_step() and sqlite_get_table(). An example use for this API is to keep
|
||||
** a GUI updated during a large query.
|
||||
**
|
||||
** The progress callback is invoked once for every N virtual machine opcodes,
|
||||
** where N is the second argument to this function. The progress callback
|
||||
** itself is identified by the third argument to this function. The fourth
|
||||
** argument to this function is a void pointer passed to the progress callback
|
||||
** function each time it is invoked.
|
||||
**
|
||||
** If a call to sqlite_exec(), sqlite_step() or sqlite_get_table() results
|
||||
** in less than N opcodes being executed, then the progress callback is not
|
||||
** invoked.
|
||||
**
|
||||
** Calling this routine overwrites any previously installed progress callback.
|
||||
** To remove the progress callback altogether, pass NULL as the third
|
||||
** argument to this function.
|
||||
**
|
||||
** If the progress callback returns a result other than 0, then the current
|
||||
** query is immediately terminated and any database changes rolled back. If the
|
||||
** query was part of a larger transaction, then the transaction is not rolled
|
||||
** back and remains active. The sqlite_exec() call returns SQLITE_ABORT.
|
||||
**
|
||||
******* THIS IS AN EXPERIMENTAL API AND IS SUBJECT TO CHANGE ******
|
||||
*/
|
||||
void sqlite_progress_handler(sqlite*, int, int(*)(void*), void*);
|
||||
|
||||
/*
|
||||
** Register a callback function to be invoked whenever a new transaction
|
||||
** is committed. The pArg argument is passed through to the callback.
|
||||
** callback. If the callback function returns non-zero, then the commit
|
||||
** is converted into a rollback.
|
||||
**
|
||||
** If another function was previously registered, its pArg value is returned.
|
||||
** Otherwise NULL is returned.
|
||||
**
|
||||
** Registering a NULL function disables the callback.
|
||||
**
|
||||
******* THIS IS AN EXPERIMENTAL API AND IS SUBJECT TO CHANGE ******
|
||||
*/
|
||||
void *sqlite_commit_hook(sqlite*, int(*)(void*), void*);
|
||||
|
||||
/*
|
||||
** Open an encrypted SQLite database. If pKey==0 or nKey==0, this routine
|
||||
** is the same as sqlite_open().
|
||||
**
|
||||
** The code to implement this API is not available in the public release
|
||||
** of SQLite.
|
||||
*/
|
||||
sqlite *sqlite_open_encrypted(
|
||||
const char *zFilename, /* Name of the encrypted database */
|
||||
const void *pKey, /* Pointer to the key */
|
||||
int nKey, /* Number of bytes in the key */
|
||||
int *pErrcode, /* Write error code here */
|
||||
char **pzErrmsg /* Write error message here */
|
||||
);
|
||||
|
||||
/*
|
||||
** Change the key on an open database. If the current database is not
|
||||
** encrypted, this routine will encrypt it. If pNew==0 or nNew==0, the
|
||||
** database is decrypted.
|
||||
**
|
||||
** The code to implement this API is not available in the public release
|
||||
** of SQLite.
|
||||
*/
|
||||
int sqlite_rekey(
|
||||
sqlite *db, /* Database to be rekeyed */
|
||||
const void *pKey, int nKey /* The new key */
|
||||
);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* End of the 'extern "C"' block */
|
||||
#endif
|
||||
|
||||
#endif /* _SQLITE_H_ */
|
1266
sqlite/sqliteInt.h
Executable file
1266
sqlite/sqliteInt.h
Executable file
File diff suppressed because it is too large
Load Diff
203
sqlite/table.c
Executable file
203
sqlite/table.c
Executable file
@ -0,0 +1,203 @@
|
||||
/*
|
||||
** 2001 September 15
|
||||
**
|
||||
** The author disclaims copyright to this source code. In place of
|
||||
** a legal notice, here is a blessing:
|
||||
**
|
||||
** May you do good and not evil.
|
||||
** May you find forgiveness for yourself and forgive others.
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
*************************************************************************
|
||||
** This file contains the sqlite_get_table() and sqlite_free_table()
|
||||
** interface routines. These are just wrappers around the main
|
||||
** interface routine of sqlite_exec().
|
||||
**
|
||||
** These routines are in a separate files so that they will not be linked
|
||||
** if they are not used.
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "sqliteInt.h"
|
||||
|
||||
/*
|
||||
** This structure is used to pass data from sqlite_get_table() through
|
||||
** to the callback function is uses to build the result.
|
||||
*/
|
||||
typedef struct TabResult {
|
||||
char **azResult;
|
||||
char *zErrMsg;
|
||||
int nResult;
|
||||
int nAlloc;
|
||||
int nRow;
|
||||
int nColumn;
|
||||
int nData;
|
||||
int rc;
|
||||
} TabResult;
|
||||
|
||||
/*
|
||||
** This routine is called once for each row in the result table. Its job
|
||||
** is to fill in the TabResult structure appropriately, allocating new
|
||||
** memory as necessary.
|
||||
*/
|
||||
static int sqlite_get_table_cb(void *pArg, int nCol, char **argv, char **colv){
|
||||
TabResult *p = (TabResult*)pArg;
|
||||
int need;
|
||||
int i;
|
||||
char *z;
|
||||
|
||||
/* Make sure there is enough space in p->azResult to hold everything
|
||||
** we need to remember from this invocation of the callback.
|
||||
*/
|
||||
if( p->nRow==0 && argv!=0 ){
|
||||
need = nCol*2;
|
||||
}else{
|
||||
need = nCol;
|
||||
}
|
||||
if( p->nData + need >= p->nAlloc ){
|
||||
char **azNew;
|
||||
p->nAlloc = p->nAlloc*2 + need + 1;
|
||||
azNew = realloc( p->azResult, sizeof(char*)*p->nAlloc );
|
||||
if( azNew==0 ){
|
||||
p->rc = SQLITE_NOMEM;
|
||||
return 1;
|
||||
}
|
||||
p->azResult = azNew;
|
||||
}
|
||||
|
||||
/* If this is the first row, then generate an extra row containing
|
||||
** the names of all columns.
|
||||
*/
|
||||
if( p->nRow==0 ){
|
||||
p->nColumn = nCol;
|
||||
for(i=0; i<nCol; i++){
|
||||
if( colv[i]==0 ){
|
||||
z = 0;
|
||||
}else{
|
||||
z = malloc( strlen(colv[i])+1 );
|
||||
if( z==0 ){
|
||||
p->rc = SQLITE_NOMEM;
|
||||
return 1;
|
||||
}
|
||||
strcpy(z, colv[i]);
|
||||
}
|
||||
p->azResult[p->nData++] = z;
|
||||
}
|
||||
}else if( p->nColumn!=nCol ){
|
||||
sqliteSetString(&p->zErrMsg,
|
||||
"sqlite_get_table() called with two or more incompatible queries",
|
||||
(char*)0);
|
||||
p->rc = SQLITE_ERROR;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Copy over the row data
|
||||
*/
|
||||
if( argv!=0 ){
|
||||
for(i=0; i<nCol; i++){
|
||||
if( argv[i]==0 ){
|
||||
z = 0;
|
||||
}else{
|
||||
z = malloc( strlen(argv[i])+1 );
|
||||
if( z==0 ){
|
||||
p->rc = SQLITE_NOMEM;
|
||||
return 1;
|
||||
}
|
||||
strcpy(z, argv[i]);
|
||||
}
|
||||
p->azResult[p->nData++] = z;
|
||||
}
|
||||
p->nRow++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Query the database. But instead of invoking a callback for each row,
|
||||
** malloc() for space to hold the result and return the entire results
|
||||
** at the conclusion of the call.
|
||||
**
|
||||
** The result that is written to ***pazResult is held in memory obtained
|
||||
** from malloc(). But the caller cannot free this memory directly.
|
||||
** Instead, the entire table should be passed to sqlite_free_table() when
|
||||
** the calling procedure is finished using it.
|
||||
*/
|
||||
int sqlite_get_table(
|
||||
sqlite *db, /* The database on which the SQL executes */
|
||||
const char *zSql, /* The SQL to be executed */
|
||||
char ***pazResult, /* Write the result table here */
|
||||
int *pnRow, /* Write the number of rows in the result here */
|
||||
int *pnColumn, /* Write the number of columns of result here */
|
||||
char **pzErrMsg /* Write error messages here */
|
||||
){
|
||||
int rc;
|
||||
TabResult res;
|
||||
if( pazResult==0 ){ return SQLITE_ERROR; }
|
||||
*pazResult = 0;
|
||||
if( pnColumn ) *pnColumn = 0;
|
||||
if( pnRow ) *pnRow = 0;
|
||||
res.zErrMsg = 0;
|
||||
res.nResult = 0;
|
||||
res.nRow = 0;
|
||||
res.nColumn = 0;
|
||||
res.nData = 1;
|
||||
res.nAlloc = 20;
|
||||
res.rc = SQLITE_OK;
|
||||
res.azResult = malloc( sizeof(char*)*res.nAlloc );
|
||||
if( res.azResult==0 ){
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
res.azResult[0] = 0;
|
||||
rc = sqlite_exec(db, zSql, sqlite_get_table_cb, &res, pzErrMsg);
|
||||
if( res.azResult ){
|
||||
res.azResult[0] = (char*)res.nData;
|
||||
}
|
||||
if( rc==SQLITE_ABORT ){
|
||||
sqlite_free_table(&res.azResult[1]);
|
||||
if( res.zErrMsg ){
|
||||
if( pzErrMsg ){
|
||||
free(*pzErrMsg);
|
||||
*pzErrMsg = res.zErrMsg;
|
||||
sqliteStrRealloc(pzErrMsg);
|
||||
}else{
|
||||
sqliteFree(res.zErrMsg);
|
||||
}
|
||||
}
|
||||
return res.rc;
|
||||
}
|
||||
sqliteFree(res.zErrMsg);
|
||||
if( rc!=SQLITE_OK ){
|
||||
sqlite_free_table(&res.azResult[1]);
|
||||
return rc;
|
||||
}
|
||||
if( res.nAlloc>res.nData ){
|
||||
char **azNew;
|
||||
azNew = realloc( res.azResult, sizeof(char*)*(res.nData+1) );
|
||||
if( azNew==0 ){
|
||||
sqlite_free_table(&res.azResult[1]);
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
res.nAlloc = res.nData+1;
|
||||
res.azResult = azNew;
|
||||
}
|
||||
*pazResult = &res.azResult[1];
|
||||
if( pnColumn ) *pnColumn = res.nColumn;
|
||||
if( pnRow ) *pnRow = res.nRow;
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** This routine frees the space the sqlite_get_table() malloced.
|
||||
*/
|
||||
void sqlite_free_table(
|
||||
char **azResult /* Result returned from from sqlite_get_table() */
|
||||
){
|
||||
if( azResult ){
|
||||
int i, n;
|
||||
azResult--;
|
||||
if( azResult==0 ) return;
|
||||
n = (int)azResult[0];
|
||||
for(i=1; i<n; i++){ if( azResult[i] ) free(azResult[i]); }
|
||||
free(azResult);
|
||||
}
|
||||
}
|
1238
sqlite/tclsqlite.c
Executable file
1238
sqlite/tclsqlite.c
Executable file
File diff suppressed because it is too large
Load Diff
679
sqlite/tokenize.c
Executable file
679
sqlite/tokenize.c
Executable file
@ -0,0 +1,679 @@
|
||||
/*
|
||||
** 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.1.1.1 2004-03-11 22:22:24 alex Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include "os.h"
|
||||
#include <ctype.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/*
|
||||
** All the keywords of the SQL language are stored as in a hash
|
||||
** table composed of instances of the following structure.
|
||||
*/
|
||||
typedef struct Keyword Keyword;
|
||||
struct Keyword {
|
||||
char *zName; /* The keyword name */
|
||||
u8 tokenType; /* Token value for this keyword */
|
||||
u8 len; /* Length of this keyword */
|
||||
u8 iNext; /* Index in aKeywordTable[] of next with same hash */
|
||||
};
|
||||
|
||||
/*
|
||||
** These are the keywords
|
||||
*/
|
||||
static Keyword aKeywordTable[] = {
|
||||
{ "ABORT", TK_ABORT, },
|
||||
{ "AFTER", TK_AFTER, },
|
||||
{ "ALL", TK_ALL, },
|
||||
{ "AND", TK_AND, },
|
||||
{ "AS", TK_AS, },
|
||||
{ "ASC", TK_ASC, },
|
||||
{ "ATTACH", TK_ATTACH, },
|
||||
{ "BEFORE", TK_BEFORE, },
|
||||
{ "BEGIN", TK_BEGIN, },
|
||||
{ "BETWEEN", TK_BETWEEN, },
|
||||
{ "BY", TK_BY, },
|
||||
{ "CASCADE", TK_CASCADE, },
|
||||
{ "CASE", TK_CASE, },
|
||||
{ "CHECK", TK_CHECK, },
|
||||
{ "CLUSTER", TK_CLUSTER, },
|
||||
{ "COLLATE", TK_COLLATE, },
|
||||
{ "COMMIT", TK_COMMIT, },
|
||||
{ "CONFLICT", TK_CONFLICT, },
|
||||
{ "CONSTRAINT", TK_CONSTRAINT, },
|
||||
{ "COPY", TK_COPY, },
|
||||
{ "CREATE", TK_CREATE, },
|
||||
{ "CROSS", TK_JOIN_KW, },
|
||||
{ "DATABASE", TK_DATABASE, },
|
||||
{ "DEFAULT", TK_DEFAULT, },
|
||||
{ "DEFERRED", TK_DEFERRED, },
|
||||
{ "DEFERRABLE", TK_DEFERRABLE, },
|
||||
{ "DELETE", TK_DELETE, },
|
||||
{ "DELIMITERS", TK_DELIMITERS, },
|
||||
{ "DESC", TK_DESC, },
|
||||
{ "DETACH", TK_DETACH, },
|
||||
{ "DISTINCT", TK_DISTINCT, },
|
||||
{ "DROP", TK_DROP, },
|
||||
{ "END", TK_END, },
|
||||
{ "EACH", TK_EACH, },
|
||||
{ "ELSE", TK_ELSE, },
|
||||
{ "EXCEPT", TK_EXCEPT, },
|
||||
{ "EXPLAIN", TK_EXPLAIN, },
|
||||
{ "FAIL", TK_FAIL, },
|
||||
{ "FOR", TK_FOR, },
|
||||
{ "FOREIGN", TK_FOREIGN, },
|
||||
{ "FROM", TK_FROM, },
|
||||
{ "FULL", TK_JOIN_KW, },
|
||||
{ "GLOB", TK_GLOB, },
|
||||
{ "GROUP", TK_GROUP, },
|
||||
{ "HAVING", TK_HAVING, },
|
||||
{ "IGNORE", TK_IGNORE, },
|
||||
{ "IMMEDIATE", TK_IMMEDIATE, },
|
||||
{ "IN", TK_IN, },
|
||||
{ "INDEX", TK_INDEX, },
|
||||
{ "INITIALLY", TK_INITIALLY, },
|
||||
{ "INNER", TK_JOIN_KW, },
|
||||
{ "INSERT", TK_INSERT, },
|
||||
{ "INSTEAD", TK_INSTEAD, },
|
||||
{ "INTERSECT", TK_INTERSECT, },
|
||||
{ "INTO", TK_INTO, },
|
||||
{ "IS", TK_IS, },
|
||||
{ "ISNULL", TK_ISNULL, },
|
||||
{ "JOIN", TK_JOIN, },
|
||||
{ "KEY", TK_KEY, },
|
||||
{ "LEFT", TK_JOIN_KW, },
|
||||
{ "LIKE", TK_LIKE, },
|
||||
{ "LIMIT", TK_LIMIT, },
|
||||
{ "MATCH", TK_MATCH, },
|
||||
{ "NATURAL", TK_JOIN_KW, },
|
||||
{ "NOT", TK_NOT, },
|
||||
{ "NOTNULL", TK_NOTNULL, },
|
||||
{ "NULL", TK_NULL, },
|
||||
{ "OF", TK_OF, },
|
||||
{ "OFFSET", TK_OFFSET, },
|
||||
{ "ON", TK_ON, },
|
||||
{ "OR", TK_OR, },
|
||||
{ "ORDER", TK_ORDER, },
|
||||
{ "OUTER", TK_JOIN_KW, },
|
||||
{ "PRAGMA", TK_PRAGMA, },
|
||||
{ "PRIMARY", TK_PRIMARY, },
|
||||
{ "RAISE", TK_RAISE, },
|
||||
{ "REFERENCES", TK_REFERENCES, },
|
||||
{ "REPLACE", TK_REPLACE, },
|
||||
{ "RESTRICT", TK_RESTRICT, },
|
||||
{ "RIGHT", TK_JOIN_KW, },
|
||||
{ "ROLLBACK", TK_ROLLBACK, },
|
||||
{ "ROW", TK_ROW, },
|
||||
{ "SELECT", TK_SELECT, },
|
||||
{ "SET", TK_SET, },
|
||||
{ "STATEMENT", TK_STATEMENT, },
|
||||
{ "TABLE", TK_TABLE, },
|
||||
{ "TEMP", TK_TEMP, },
|
||||
{ "TEMPORARY", TK_TEMP, },
|
||||
{ "THEN", TK_THEN, },
|
||||
{ "TRANSACTION", TK_TRANSACTION, },
|
||||
{ "TRIGGER", TK_TRIGGER, },
|
||||
{ "UNION", TK_UNION, },
|
||||
{ "UNIQUE", TK_UNIQUE, },
|
||||
{ "UPDATE", TK_UPDATE, },
|
||||
{ "USING", TK_USING, },
|
||||
{ "VACUUM", TK_VACUUM, },
|
||||
{ "VALUES", TK_VALUES, },
|
||||
{ "VIEW", TK_VIEW, },
|
||||
{ "WHEN", TK_WHEN, },
|
||||
{ "WHERE", TK_WHERE, },
|
||||
};
|
||||
|
||||
/*
|
||||
** This is the hash table
|
||||
*/
|
||||
#define KEY_HASH_SIZE 101
|
||||
static u8 aiHashTable[KEY_HASH_SIZE];
|
||||
|
||||
|
||||
/*
|
||||
** This function looks up an identifier to determine if it is a
|
||||
** keyword. If it is a keyword, the token code of that keyword is
|
||||
** returned. If the input is not a keyword, TK_ID is returned.
|
||||
*/
|
||||
int sqliteKeywordCode(const char *z, int n){
|
||||
int h, i;
|
||||
Keyword *p;
|
||||
static char needInit = 1;
|
||||
if( needInit ){
|
||||
/* Initialize the keyword hash table */
|
||||
sqliteOsEnterMutex();
|
||||
if( needInit ){
|
||||
int nk;
|
||||
nk = sizeof(aKeywordTable)/sizeof(aKeywordTable[0]);
|
||||
for(i=0; i<nk; i++){
|
||||
aKeywordTable[i].len = strlen(aKeywordTable[i].zName);
|
||||
h = sqliteHashNoCase(aKeywordTable[i].zName, aKeywordTable[i].len);
|
||||
h %= KEY_HASH_SIZE;
|
||||
aKeywordTable[i].iNext = aiHashTable[h];
|
||||
aiHashTable[h] = i+1;
|
||||
}
|
||||
needInit = 0;
|
||||
}
|
||||
sqliteOsLeaveMutex();
|
||||
}
|
||||
h = sqliteHashNoCase(z, n) % KEY_HASH_SIZE;
|
||||
for(i=aiHashTable[h]; i; i=p->iNext){
|
||||
p = &aKeywordTable[i-1];
|
||||
if( p->len==n && sqliteStrNICmp(p->zName, z, n)==0 ){
|
||||
return p->tokenType;
|
||||
}
|
||||
}
|
||||
return TK_ID;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** If X is a character that can be used in an identifier and
|
||||
** X&0x80==0 then isIdChar[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). isIdChar[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.
|
||||
*/
|
||||
static const char isIdChar[] = {
|
||||
/* x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1x */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 2x */
|
||||
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 */
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
** Return the length of the token that begins at z[0].
|
||||
** Store the token type in *tokenType before returning.
|
||||
*/
|
||||
static int sqliteGetToken(const unsigned char *z, int *tokenType){
|
||||
int i;
|
||||
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; z[i] && z[i]!='\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; z[i] && (z[i]!='/' || z[i-1]!='*'); i++){}
|
||||
if( z[i] ) i++;
|
||||
*tokenType = TK_COMMENT;
|
||||
return i;
|
||||
}
|
||||
case '%': {
|
||||
*tokenType = TK_REM;
|
||||
return 1;
|
||||
}
|
||||
case '=': {
|
||||
*tokenType = TK_EQ;
|
||||
return 1 + (z[1]=='=');
|
||||
}
|
||||
case '<': {
|
||||
if( z[1]=='=' ){
|
||||
*tokenType = TK_LE;
|
||||
return 2;
|
||||
}else if( z[1]=='>' ){
|
||||
*tokenType = TK_NE;
|
||||
return 2;
|
||||
}else if( z[1]=='<' ){
|
||||
*tokenType = TK_LSHIFT;
|
||||
return 2;
|
||||
}else{
|
||||
*tokenType = TK_LT;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
case '>': {
|
||||
if( z[1]=='=' ){
|
||||
*tokenType = TK_GE;
|
||||
return 2;
|
||||
}else if( z[1]=='>' ){
|
||||
*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 '"': {
|
||||
int delim = z[0];
|
||||
for(i=1; z[i]; i++){
|
||||
if( z[i]==delim ){
|
||||
if( z[i+1]==delim ){
|
||||
i++;
|
||||
}else{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if( z[i] ) i++;
|
||||
*tokenType = TK_STRING;
|
||||
return i;
|
||||
}
|
||||
case '.': {
|
||||
*tokenType = TK_DOT;
|
||||
return 1;
|
||||
}
|
||||
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=1; isdigit(z[i]); i++){}
|
||||
if( z[i]=='.' && isdigit(z[i+1]) ){
|
||||
i += 2;
|
||||
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;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
case '[': {
|
||||
for(i=1; z[i] && z[i-1]!=']'; i++){}
|
||||
*tokenType = TK_ID;
|
||||
return i;
|
||||
}
|
||||
case '?': {
|
||||
*tokenType = TK_VARIABLE;
|
||||
return 1;
|
||||
}
|
||||
default: {
|
||||
if( (*z&0x80)==0 && !isIdChar[*z] ){
|
||||
break;
|
||||
}
|
||||
for(i=1; (z[i]&0x80)!=0 || isIdChar[z[i]]; i++){}
|
||||
*tokenType = sqliteKeywordCode((char*)z, i);
|
||||
return i;
|
||||
}
|
||||
}
|
||||
*tokenType = TK_ILLEGAL;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
** 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 sqliteRunParser(Parse *pParse, const char *zSql, char **pzErrMsg){
|
||||
int nErr = 0;
|
||||
int i;
|
||||
void *pEngine;
|
||||
int tokenType;
|
||||
int lastTokenParsed = -1;
|
||||
sqlite *db = pParse->db;
|
||||
extern void *sqliteParserAlloc(void*(*)(int));
|
||||
extern void sqliteParserFree(void*, void(*)(void*));
|
||||
extern int sqliteParser(void*, int, Token, Parse*);
|
||||
|
||||
db->flags &= ~SQLITE_Interrupt;
|
||||
pParse->rc = SQLITE_OK;
|
||||
i = 0;
|
||||
pEngine = sqliteParserAlloc((void*(*)(int))malloc);
|
||||
if( pEngine==0 ){
|
||||
sqliteSetString(pzErrMsg, "out of memory", (char*)0);
|
||||
return 1;
|
||||
}
|
||||
pParse->sLastToken.dyn = 0;
|
||||
pParse->zTail = zSql;
|
||||
while( sqlite_malloc_failed==0 && zSql[i]!=0 ){
|
||||
assert( i>=0 );
|
||||
pParse->sLastToken.z = &zSql[i];
|
||||
assert( pParse->sLastToken.dyn==0 );
|
||||
pParse->sLastToken.n = sqliteGetToken((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;
|
||||
sqliteSetString(pzErrMsg, "interrupt", (char*)0);
|
||||
goto abort_parse;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TK_ILLEGAL: {
|
||||
sqliteSetNString(pzErrMsg, "unrecognized token: \"", -1,
|
||||
pParse->sLastToken.z, pParse->sLastToken.n, "\"", 1, 0);
|
||||
nErr++;
|
||||
goto abort_parse;
|
||||
}
|
||||
case TK_SEMI: {
|
||||
pParse->zTail = &zSql[i];
|
||||
/* Fall thru into the default case */
|
||||
}
|
||||
default: {
|
||||
sqliteParser(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 ){
|
||||
sqliteParser(pEngine, TK_SEMI, pParse->sLastToken, pParse);
|
||||
pParse->zTail = &zSql[i];
|
||||
}
|
||||
sqliteParser(pEngine, 0, pParse->sLastToken, pParse);
|
||||
}
|
||||
sqliteParserFree(pEngine, free);
|
||||
if( pParse->rc!=SQLITE_OK && pParse->rc!=SQLITE_DONE && pParse->zErrMsg==0 ){
|
||||
sqliteSetString(&pParse->zErrMsg, sqlite_error_string(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 ){
|
||||
sqliteVdbeDelete(pParse->pVdbe);
|
||||
pParse->pVdbe = 0;
|
||||
}
|
||||
if( pParse->pNewTable ){
|
||||
sqliteDeleteTable(pParse->db, pParse->pNewTable);
|
||||
pParse->pNewTable = 0;
|
||||
}
|
||||
if( pParse->pNewTrigger ){
|
||||
sqliteDeleteTrigger(pParse->pNewTrigger);
|
||||
pParse->pNewTrigger = 0;
|
||||
}
|
||||
if( nErr>0 && (pParse->rc==SQLITE_OK || pParse->rc==SQLITE_DONE) ){
|
||||
pParse->rc = SQLITE_ERROR;
|
||||
}
|
||||
return nErr;
|
||||
}
|
||||
|
||||
/*
|
||||
** Token types used by the sqlite_complete() routine. See the header
|
||||
** comments on that procedure for additional information.
|
||||
*/
|
||||
#define tkEXPLAIN 0
|
||||
#define tkCREATE 1
|
||||
#define tkTEMP 2
|
||||
#define tkTRIGGER 3
|
||||
#define tkEND 4
|
||||
#define tkSEMI 5
|
||||
#define tkWS 6
|
||||
#define tkOTHER 7
|
||||
|
||||
/*
|
||||
** Return TRUE if the given SQL string ends in a semicolon.
|
||||
**
|
||||
** Special handling is require for CREATE TRIGGER statements.
|
||||
** Whenever the CREATE TRIGGER keywords are seen, the statement
|
||||
** must end with ";END;".
|
||||
**
|
||||
** This implementation uses a state machine with 7 states:
|
||||
**
|
||||
** (0) START At the beginning or end of an SQL statement. This routine
|
||||
** returns 1 if it ends in the START state and 0 if it ends
|
||||
** in any other state.
|
||||
**
|
||||
** (1) EXPLAIN The keyword EXPLAIN has been seen at the beginning of
|
||||
** a statement.
|
||||
**
|
||||
** (2) CREATE The keyword CREATE has been seen at the beginning of a
|
||||
** statement, possibly preceeded by EXPLAIN and/or followed by
|
||||
** TEMP or TEMPORARY
|
||||
**
|
||||
** (3) NORMAL We are in the middle of statement which ends with a single
|
||||
** semicolon.
|
||||
**
|
||||
** (4) TRIGGER We are in the middle of a trigger definition that must be
|
||||
** ended by a semicolon, the keyword END, and another semicolon.
|
||||
**
|
||||
** (5) SEMI We've seen the first semicolon in the ";END;" that occurs at
|
||||
** the end of a trigger definition.
|
||||
**
|
||||
** (6) END We've seen the ";END" of the ";END;" that occurs at the end
|
||||
** of a trigger difinition.
|
||||
**
|
||||
** Transitions between states above are determined by tokens extracted
|
||||
** from the input. The following tokens are significant:
|
||||
**
|
||||
** (0) tkEXPLAIN The "explain" keyword.
|
||||
** (1) tkCREATE The "create" keyword.
|
||||
** (2) tkTEMP The "temp" or "temporary" keyword.
|
||||
** (3) tkTRIGGER The "trigger" keyword.
|
||||
** (4) tkEND The "end" keyword.
|
||||
** (5) tkSEMI A semicolon.
|
||||
** (6) tkWS Whitespace
|
||||
** (7) tkOTHER Any other SQL token.
|
||||
**
|
||||
** Whitespace never causes a state transition and is always ignored.
|
||||
*/
|
||||
int sqlite_complete(const char *zSql){
|
||||
u8 state = 0; /* Current state, using numbers defined in header comment */
|
||||
u8 token; /* Value of the next token */
|
||||
|
||||
/* The following matrix defines the transition from one state to another
|
||||
** according to what token is seen. trans[state][token] returns the
|
||||
** next state.
|
||||
*/
|
||||
static const u8 trans[7][8] = {
|
||||
/* Token: */
|
||||
/* State: ** EXPLAIN CREATE TEMP TRIGGER END SEMI WS OTHER */
|
||||
/* 0 START: */ { 1, 2, 3, 3, 3, 0, 0, 3, },
|
||||
/* 1 EXPLAIN: */ { 3, 2, 3, 3, 3, 0, 1, 3, },
|
||||
/* 2 CREATE: */ { 3, 3, 2, 4, 3, 0, 2, 3, },
|
||||
/* 3 NORMAL: */ { 3, 3, 3, 3, 3, 0, 3, 3, },
|
||||
/* 4 TRIGGER: */ { 4, 4, 4, 4, 4, 5, 4, 4, },
|
||||
/* 5 SEMI: */ { 4, 4, 4, 4, 6, 5, 5, 4, },
|
||||
/* 6 END: */ { 4, 4, 4, 4, 4, 0, 6, 4, },
|
||||
};
|
||||
|
||||
while( *zSql ){
|
||||
switch( *zSql ){
|
||||
case ';': { /* A semicolon */
|
||||
token = tkSEMI;
|
||||
break;
|
||||
}
|
||||
case ' ':
|
||||
case '\r':
|
||||
case '\t':
|
||||
case '\n':
|
||||
case '\f': { /* White space is ignored */
|
||||
token = tkWS;
|
||||
break;
|
||||
}
|
||||
case '/': { /* C-style comments */
|
||||
if( zSql[1]!='*' ){
|
||||
token = tkOTHER;
|
||||
break;
|
||||
}
|
||||
zSql += 2;
|
||||
while( zSql[0] && (zSql[0]!='*' || zSql[1]!='/') ){ zSql++; }
|
||||
if( zSql[0]==0 ) return 0;
|
||||
zSql++;
|
||||
token = tkWS;
|
||||
break;
|
||||
}
|
||||
case '-': { /* SQL-style comments from "--" to end of line */
|
||||
if( zSql[1]!='-' ){
|
||||
token = tkOTHER;
|
||||
break;
|
||||
}
|
||||
while( *zSql && *zSql!='\n' ){ zSql++; }
|
||||
if( *zSql==0 ) return state==0;
|
||||
token = tkWS;
|
||||
break;
|
||||
}
|
||||
case '[': { /* Microsoft-style identifiers in [...] */
|
||||
zSql++;
|
||||
while( *zSql && *zSql!=']' ){ zSql++; }
|
||||
if( *zSql==0 ) return 0;
|
||||
token = tkOTHER;
|
||||
break;
|
||||
}
|
||||
case '"': /* single- and double-quoted strings */
|
||||
case '\'': {
|
||||
int c = *zSql;
|
||||
zSql++;
|
||||
while( *zSql && *zSql!=c ){ zSql++; }
|
||||
if( *zSql==0 ) return 0;
|
||||
token = tkOTHER;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
if( isIdChar[(u8)*zSql] ){
|
||||
/* Keywords and unquoted identifiers */
|
||||
int nId;
|
||||
for(nId=1; isIdChar[(u8)zSql[nId]]; nId++){}
|
||||
switch( *zSql ){
|
||||
case 'c': case 'C': {
|
||||
if( nId==6 && sqliteStrNICmp(zSql, "create", 6)==0 ){
|
||||
token = tkCREATE;
|
||||
}else{
|
||||
token = tkOTHER;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 't': case 'T': {
|
||||
if( nId==7 && sqliteStrNICmp(zSql, "trigger", 7)==0 ){
|
||||
token = tkTRIGGER;
|
||||
}else if( nId==4 && sqliteStrNICmp(zSql, "temp", 4)==0 ){
|
||||
token = tkTEMP;
|
||||
}else if( nId==9 && sqliteStrNICmp(zSql, "temporary", 9)==0 ){
|
||||
token = tkTEMP;
|
||||
}else{
|
||||
token = tkOTHER;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'e': case 'E': {
|
||||
if( nId==3 && sqliteStrNICmp(zSql, "end", 3)==0 ){
|
||||
token = tkEND;
|
||||
}else if( nId==7 && sqliteStrNICmp(zSql, "explain", 7)==0 ){
|
||||
token = tkEXPLAIN;
|
||||
}else{
|
||||
token = tkOTHER;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
token = tkOTHER;
|
||||
break;
|
||||
}
|
||||
}
|
||||
zSql += nId-1;
|
||||
}else{
|
||||
/* Operators and special symbols */
|
||||
token = tkOTHER;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
state = trans[state][token];
|
||||
zSql++;
|
||||
}
|
||||
return state==0;
|
||||
}
|
764
sqlite/trigger.c
Executable file
764
sqlite/trigger.c
Executable file
@ -0,0 +1,764 @@
|
||||
/*
|
||||
**
|
||||
** 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"
|
||||
|
||||
/*
|
||||
** Delete a linked list of TriggerStep structures.
|
||||
*/
|
||||
void sqliteDeleteTriggerStep(TriggerStep *pTriggerStep){
|
||||
while( pTriggerStep ){
|
||||
TriggerStep * pTmp = pTriggerStep;
|
||||
pTriggerStep = pTriggerStep->pNext;
|
||||
|
||||
if( pTmp->target.dyn ) sqliteFree((char*)pTmp->target.z);
|
||||
sqliteExprDelete(pTmp->pWhere);
|
||||
sqliteExprListDelete(pTmp->pExprList);
|
||||
sqliteSelectDelete(pTmp->pSelect);
|
||||
sqliteIdListDelete(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
|
||||
** sqliteFinishTrigger() function is called to complete the trigger
|
||||
** construction process.
|
||||
*/
|
||||
void sqliteBeginTrigger(
|
||||
Parse *pParse, /* The parse context of the CREATE TRIGGER statement */
|
||||
Token *pName, /* 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 *nt;
|
||||
Table *tab;
|
||||
char *zName = 0; /* Name of the trigger */
|
||||
sqlite *db = pParse->db;
|
||||
int iDb; /* When database to store the trigger in */
|
||||
DbFixer sFix;
|
||||
|
||||
/* Check that:
|
||||
** 1. the trigger name does not already exist.
|
||||
** 2. the table (or view) does exist in the same database as the trigger.
|
||||
** 3. that we are not trying to create a trigger on the sqlite_master table
|
||||
** 4. That we are not trying to create an INSTEAD OF trigger on a table.
|
||||
** 5. That we are not trying to create a BEFORE or AFTER trigger on a view.
|
||||
*/
|
||||
if( sqlite_malloc_failed ) goto trigger_cleanup;
|
||||
assert( pTableName->nSrc==1 );
|
||||
if( db->init.busy
|
||||
&& sqliteFixInit(&sFix, pParse, db->init.iDb, "trigger", pName)
|
||||
&& sqliteFixSrcList(&sFix, pTableName)
|
||||
){
|
||||
goto trigger_cleanup;
|
||||
}
|
||||
tab = sqliteSrcListLookup(pParse, pTableName);
|
||||
if( !tab ){
|
||||
goto trigger_cleanup;
|
||||
}
|
||||
iDb = isTemp ? 1 : tab->iDb;
|
||||
if( iDb>=2 && !db->init.busy ){
|
||||
sqliteErrorMsg(pParse, "triggers may not be added to auxiliary "
|
||||
"database %s", db->aDb[tab->iDb].zName);
|
||||
goto trigger_cleanup;
|
||||
}
|
||||
|
||||
zName = sqliteStrNDup(pName->z, pName->n);
|
||||
sqliteDequote(zName);
|
||||
if( sqliteHashFind(&(db->aDb[iDb].trigHash), zName,pName->n+1) ){
|
||||
sqliteErrorMsg(pParse, "trigger %T already exists", pName);
|
||||
goto trigger_cleanup;
|
||||
}
|
||||
if( sqliteStrNICmp(tab->zName, "sqlite_", 7)==0 ){
|
||||
sqliteErrorMsg(pParse, "cannot create trigger on system table");
|
||||
pParse->nErr++;
|
||||
goto trigger_cleanup;
|
||||
}
|
||||
if( tab->pSelect && tr_tm != TK_INSTEAD ){
|
||||
sqliteErrorMsg(pParse, "cannot create %s trigger on view: %S",
|
||||
(tr_tm == TK_BEFORE)?"BEFORE":"AFTER", pTableName, 0);
|
||||
goto trigger_cleanup;
|
||||
}
|
||||
if( !tab->pSelect && tr_tm == TK_INSTEAD ){
|
||||
sqliteErrorMsg(pParse, "cannot create INSTEAD OF"
|
||||
" trigger on table: %S", pTableName, 0);
|
||||
goto trigger_cleanup;
|
||||
}
|
||||
#ifndef SQLITE_OMIT_AUTHORIZATION
|
||||
{
|
||||
int code = SQLITE_CREATE_TRIGGER;
|
||||
const char *zDb = db->aDb[tab->iDb].zName;
|
||||
const char *zDbTrig = isTemp ? db->aDb[1].zName : zDb;
|
||||
if( tab->iDb==1 || isTemp ) code = SQLITE_CREATE_TEMP_TRIGGER;
|
||||
if( sqliteAuthCheck(pParse, code, zName, tab->zName, zDbTrig) ){
|
||||
goto trigger_cleanup;
|
||||
}
|
||||
if( sqliteAuthCheck(pParse, SQLITE_INSERT, SCHEMA_TABLE(tab->iDb), 0, zDb)){
|
||||
goto trigger_cleanup;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* INSTEAD OF triggers can only appear on views and BEGIN 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 */
|
||||
nt = (Trigger*)sqliteMalloc(sizeof(Trigger));
|
||||
if( nt==0 ) goto trigger_cleanup;
|
||||
nt->name = zName;
|
||||
zName = 0;
|
||||
nt->table = sqliteStrDup(pTableName->a[0].zName);
|
||||
if( sqlite_malloc_failed ) goto trigger_cleanup;
|
||||
nt->iDb = iDb;
|
||||
nt->iTabDb = tab->iDb;
|
||||
nt->op = op;
|
||||
nt->tr_tm = tr_tm;
|
||||
nt->pWhen = sqliteExprDup(pWhen);
|
||||
nt->pColumns = sqliteIdListDup(pColumns);
|
||||
nt->foreach = foreach;
|
||||
sqliteTokenCopy(&nt->nameToken,pName);
|
||||
assert( pParse->pNewTrigger==0 );
|
||||
pParse->pNewTrigger = nt;
|
||||
|
||||
trigger_cleanup:
|
||||
sqliteFree(zName);
|
||||
sqliteSrcListDelete(pTableName);
|
||||
sqliteIdListDelete(pColumns);
|
||||
sqliteExprDelete(pWhen);
|
||||
}
|
||||
|
||||
/*
|
||||
** This routine is called after all of the trigger actions have been parsed
|
||||
** in order to complete the process of building the trigger.
|
||||
*/
|
||||
void sqliteFinishTrigger(
|
||||
Parse *pParse, /* Parser context */
|
||||
TriggerStep *pStepList, /* The triggered program */
|
||||
Token *pAll /* Token that describes the complete CREATE TRIGGER */
|
||||
){
|
||||
Trigger *nt = 0; /* The trigger whose construction is finishing up */
|
||||
sqlite *db = pParse->db; /* The database */
|
||||
DbFixer sFix;
|
||||
|
||||
if( pParse->nErr || pParse->pNewTrigger==0 ) goto triggerfinish_cleanup;
|
||||
nt = pParse->pNewTrigger;
|
||||
pParse->pNewTrigger = 0;
|
||||
nt->step_list = pStepList;
|
||||
while( pStepList ){
|
||||
pStepList->pTrig = nt;
|
||||
pStepList = pStepList->pNext;
|
||||
}
|
||||
if( sqliteFixInit(&sFix, pParse, nt->iDb, "trigger", &nt->nameToken)
|
||||
&& sqliteFixTriggerStep(&sFix, nt->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 VdbeOpList insertTrig[] = {
|
||||
{ OP_NewRecno, 0, 0, 0 },
|
||||
{ OP_String, 0, 0, "trigger" },
|
||||
{ OP_String, 0, 0, 0 }, /* 2: trigger name */
|
||||
{ OP_String, 0, 0, 0 }, /* 3: table name */
|
||||
{ OP_Integer, 0, 0, 0 },
|
||||
{ OP_String, 0, 0, 0 }, /* 5: SQL */
|
||||
{ OP_MakeRecord, 5, 0, 0 },
|
||||
{ OP_PutIntKey, 0, 0, 0 },
|
||||
};
|
||||
int addr;
|
||||
Vdbe *v;
|
||||
|
||||
/* Make an entry in the sqlite_master table */
|
||||
v = sqliteGetVdbe(pParse);
|
||||
if( v==0 ) goto triggerfinish_cleanup;
|
||||
sqliteBeginWriteOperation(pParse, 0, 0);
|
||||
sqliteOpenMasterTable(v, nt->iDb);
|
||||
addr = sqliteVdbeAddOpList(v, ArraySize(insertTrig), insertTrig);
|
||||
sqliteVdbeChangeP3(v, addr+2, nt->name, 0);
|
||||
sqliteVdbeChangeP3(v, addr+3, nt->table, 0);
|
||||
sqliteVdbeChangeP3(v, addr+5, pAll->z, pAll->n);
|
||||
if( nt->iDb==0 ){
|
||||
sqliteChangeCookie(db, v);
|
||||
}
|
||||
sqliteVdbeAddOp(v, OP_Close, 0, 0);
|
||||
sqliteEndWriteOperation(pParse);
|
||||
}
|
||||
|
||||
if( !pParse->explain ){
|
||||
Table *pTab;
|
||||
sqliteHashInsert(&db->aDb[nt->iDb].trigHash,
|
||||
nt->name, strlen(nt->name)+1, nt);
|
||||
pTab = sqliteLocateTable(pParse, nt->table, db->aDb[nt->iTabDb].zName);
|
||||
assert( pTab!=0 );
|
||||
nt->pNext = pTab->pTrigger;
|
||||
pTab->pTrigger = nt;
|
||||
nt = 0;
|
||||
}
|
||||
|
||||
triggerfinish_cleanup:
|
||||
sqliteDeleteTrigger(nt);
|
||||
sqliteDeleteTrigger(pParse->pNewTrigger);
|
||||
pParse->pNewTrigger = 0;
|
||||
sqliteDeleteTriggerStep(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 sqlite_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 sqlite_exec() call returns.
|
||||
*/
|
||||
static void sqlitePersistTriggerStep(TriggerStep *p){
|
||||
if( p->target.z ){
|
||||
p->target.z = sqliteStrNDup(p->target.z, p->target.n);
|
||||
p->target.dyn = 1;
|
||||
}
|
||||
if( p->pSelect ){
|
||||
Select *pNew = sqliteSelectDup(p->pSelect);
|
||||
sqliteSelectDelete(p->pSelect);
|
||||
p->pSelect = pNew;
|
||||
}
|
||||
if( p->pWhere ){
|
||||
Expr *pNew = sqliteExprDup(p->pWhere);
|
||||
sqliteExprDelete(p->pWhere);
|
||||
p->pWhere = pNew;
|
||||
}
|
||||
if( p->pExprList ){
|
||||
ExprList *pNew = sqliteExprListDup(p->pExprList);
|
||||
sqliteExprListDelete(p->pExprList);
|
||||
p->pExprList = pNew;
|
||||
}
|
||||
if( p->pIdList ){
|
||||
IdList *pNew = sqliteIdListDup(p->pIdList);
|
||||
sqliteIdListDelete(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 *sqliteTriggerSelectStep(Select *pSelect){
|
||||
TriggerStep *pTriggerStep = sqliteMalloc(sizeof(TriggerStep));
|
||||
if( pTriggerStep==0 ) 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 *sqliteTriggerInsertStep(
|
||||
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));
|
||||
if( pTriggerStep==0 ) return 0;
|
||||
|
||||
assert(pEList == 0 || pSelect == 0);
|
||||
assert(pEList != 0 || pSelect != 0);
|
||||
|
||||
pTriggerStep->op = TK_INSERT;
|
||||
pTriggerStep->pSelect = pSelect;
|
||||
pTriggerStep->target = *pTableName;
|
||||
pTriggerStep->pIdList = pColumn;
|
||||
pTriggerStep->pExprList = pEList;
|
||||
pTriggerStep->orconf = orconf;
|
||||
sqlitePersistTriggerStep(pTriggerStep);
|
||||
|
||||
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 *sqliteTriggerUpdateStep(
|
||||
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 *sqliteTriggerDeleteStep(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 sqliteDeleteTrigger(Trigger *pTrigger){
|
||||
if( pTrigger==0 ) return;
|
||||
sqliteDeleteTriggerStep(pTrigger->step_list);
|
||||
sqliteFree(pTrigger->name);
|
||||
sqliteFree(pTrigger->table);
|
||||
sqliteExprDelete(pTrigger->pWhen);
|
||||
sqliteIdListDelete(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 sqliteDropTriggerPtr() routine does the
|
||||
* same job as this routine except it take a spointer to the trigger
|
||||
* instead of the trigger name.
|
||||
*
|
||||
* Note that this function does not delete the trigger entirely. Instead it
|
||||
* removes it from the internal schema and places it in the trigDrop hash
|
||||
* table. This is so that the trigger can be restored into the database schema
|
||||
* if the transaction is rolled back.
|
||||
*/
|
||||
void sqliteDropTrigger(Parse *pParse, SrcList *pName){
|
||||
Trigger *pTrigger;
|
||||
int i;
|
||||
const char *zDb;
|
||||
const char *zName;
|
||||
int nName;
|
||||
sqlite *db = pParse->db;
|
||||
|
||||
if( sqlite_malloc_failed ) goto drop_trigger_cleanup;
|
||||
assert( pName->nSrc==1 );
|
||||
zDb = pName->a[0].zDatabase;
|
||||
zName = pName->a[0].zName;
|
||||
nName = strlen(zName);
|
||||
for(i=0; i<db->nDb; i++){
|
||||
int j = (i<2) ? i^1 : i; /* Search TEMP before MAIN */
|
||||
if( zDb && sqliteStrICmp(db->aDb[j].zName, zDb) ) continue;
|
||||
pTrigger = sqliteHashFind(&(db->aDb[j].trigHash), zName, nName+1);
|
||||
if( pTrigger ) break;
|
||||
}
|
||||
if( !pTrigger ){
|
||||
sqliteErrorMsg(pParse, "no such trigger: %S", pName, 0);
|
||||
goto drop_trigger_cleanup;
|
||||
}
|
||||
sqliteDropTriggerPtr(pParse, pTrigger, 0);
|
||||
|
||||
drop_trigger_cleanup:
|
||||
sqliteSrcListDelete(pName);
|
||||
}
|
||||
|
||||
/*
|
||||
** 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 sqliteDropTriggerPtr(Parse *pParse, Trigger *pTrigger, int nested){
|
||||
Table *pTable;
|
||||
Vdbe *v;
|
||||
sqlite *db = pParse->db;
|
||||
|
||||
assert( pTrigger->iDb<db->nDb );
|
||||
if( pTrigger->iDb>=2 ){
|
||||
sqliteErrorMsg(pParse, "triggers may not be removed from "
|
||||
"auxiliary database %s", db->aDb[pTrigger->iDb].zName);
|
||||
return;
|
||||
}
|
||||
pTable = sqliteFindTable(db, pTrigger->table,db->aDb[pTrigger->iTabDb].zName);
|
||||
assert(pTable);
|
||||
assert( pTable->iDb==pTrigger->iDb || pTrigger->iDb==1 );
|
||||
#ifndef SQLITE_OMIT_AUTHORIZATION
|
||||
{
|
||||
int code = SQLITE_DROP_TRIGGER;
|
||||
const char *zDb = db->aDb[pTrigger->iDb].zName;
|
||||
const char *zTab = SCHEMA_TABLE(pTrigger->iDb);
|
||||
if( pTrigger->iDb ) code = SQLITE_DROP_TEMP_TRIGGER;
|
||||
if( sqliteAuthCheck(pParse, code, pTrigger->name, pTable->zName, zDb) ||
|
||||
sqliteAuthCheck(pParse, SQLITE_DELETE, zTab, 0, zDb) ){
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Generate code to destroy the database record of the trigger.
|
||||
*/
|
||||
if( pTable!=0 && !nested && (v = sqliteGetVdbe(pParse))!=0 ){
|
||||
int base;
|
||||
static VdbeOpList dropTrigger[] = {
|
||||
{ OP_Rewind, 0, ADDR(9), 0},
|
||||
{ OP_String, 0, 0, 0}, /* 1 */
|
||||
{ OP_Column, 0, 1, 0},
|
||||
{ OP_Ne, 0, ADDR(8), 0},
|
||||
{ OP_String, 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 */
|
||||
};
|
||||
|
||||
sqliteBeginWriteOperation(pParse, 0, 0);
|
||||
sqliteOpenMasterTable(v, pTrigger->iDb);
|
||||
base = sqliteVdbeAddOpList(v, ArraySize(dropTrigger), dropTrigger);
|
||||
sqliteVdbeChangeP3(v, base+1, pTrigger->name, 0);
|
||||
if( pTrigger->iDb==0 ){
|
||||
sqliteChangeCookie(db, v);
|
||||
}
|
||||
sqliteVdbeAddOp(v, OP_Close, 0, 0);
|
||||
sqliteEndWriteOperation(pParse);
|
||||
}
|
||||
|
||||
/*
|
||||
* If this is not an "explain", then delete the trigger structure.
|
||||
*/
|
||||
if( !pParse->explain ){
|
||||
const char *zName = pTrigger->name;
|
||||
int nName = strlen(zName);
|
||||
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);
|
||||
}
|
||||
sqliteHashInsert(&(db->aDb[pTrigger->iDb].trigHash), zName, nName+1, 0);
|
||||
sqliteDeleteTrigger(pTrigger);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** 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( sqliteIdListIndex(pIdList, pEList->a[e].zName)>=0 ) return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* A global variable that is TRUE if we should always set up temp tables for
|
||||
* for triggers, even if there are no triggers to code. This is used to test
|
||||
* how much overhead the triggers algorithm is causing.
|
||||
*
|
||||
* This flag can be set or cleared using the "trigger_overhead_test" pragma.
|
||||
* The pragma is not documented since it is not really part of the interface
|
||||
* to SQLite, just the test procedure.
|
||||
*/
|
||||
int always_code_trigger_setup = 0;
|
||||
|
||||
/*
|
||||
* Returns true if a trigger matching op, tr_tm and foreach that is NOT already
|
||||
* on the Parse objects trigger-stack (to prevent recursive trigger firing) is
|
||||
* found in the list specified as pTrigger.
|
||||
*/
|
||||
int sqliteTriggersExist(
|
||||
Parse *pParse, /* Used to check for recursive triggers */
|
||||
Trigger *pTrigger, /* A list of triggers associated with a table */
|
||||
int op, /* one of TK_DELETE, TK_INSERT, TK_UPDATE */
|
||||
int tr_tm, /* one of TK_BEFORE, TK_AFTER */
|
||||
int foreach, /* one of TK_ROW or TK_STATEMENT */
|
||||
ExprList *pChanges /* Columns that change in an UPDATE statement */
|
||||
){
|
||||
Trigger * pTriggerCursor;
|
||||
|
||||
if( always_code_trigger_setup ){
|
||||
return 1;
|
||||
}
|
||||
|
||||
pTriggerCursor = pTrigger;
|
||||
while( pTriggerCursor ){
|
||||
if( pTriggerCursor->op == op &&
|
||||
pTriggerCursor->tr_tm == tr_tm &&
|
||||
pTriggerCursor->foreach == foreach &&
|
||||
checkColumnOverLap(pTriggerCursor->pColumns, pChanges) ){
|
||||
TriggerStack * ss;
|
||||
ss = pParse->trigStack;
|
||||
while( ss && ss->pTrigger != pTrigger ){
|
||||
ss = ss->pNext;
|
||||
}
|
||||
if( !ss )return 1;
|
||||
}
|
||||
pTriggerCursor = pTriggerCursor->pNext;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** 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 = pStep->pTrig->iDb;
|
||||
if( iDb==0 || iDb>=2 ){
|
||||
assert( iDb<pParse->db->nDb );
|
||||
sDb.z = pParse->db->aDb[iDb].zName;
|
||||
sDb.n = strlen(sDb.z);
|
||||
pSrc = sqliteSrcListAppend(0, &sDb, &pStep->target);
|
||||
} else {
|
||||
pSrc = sqliteSrcListAppend(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;
|
||||
|
||||
while( pTriggerStep ){
|
||||
int saveNTab = pParse->nTab;
|
||||
|
||||
orconf = (orconfin == OE_Default)?pTriggerStep->orconf:orconfin;
|
||||
pParse->trigStack->orconf = orconf;
|
||||
switch( pTriggerStep->op ){
|
||||
case TK_SELECT: {
|
||||
Select * ss = sqliteSelectDup(pTriggerStep->pSelect);
|
||||
assert(ss);
|
||||
assert(ss->pSrc);
|
||||
sqliteSelect(pParse, ss, SRT_Discard, 0, 0, 0, 0);
|
||||
sqliteSelectDelete(ss);
|
||||
break;
|
||||
}
|
||||
case TK_UPDATE: {
|
||||
SrcList *pSrc;
|
||||
pSrc = targetSrcList(pParse, pTriggerStep);
|
||||
sqliteVdbeAddOp(pParse->pVdbe, OP_ListPush, 0, 0);
|
||||
sqliteUpdate(pParse, pSrc,
|
||||
sqliteExprListDup(pTriggerStep->pExprList),
|
||||
sqliteExprDup(pTriggerStep->pWhere), orconf);
|
||||
sqliteVdbeAddOp(pParse->pVdbe, OP_ListPop, 0, 0);
|
||||
break;
|
||||
}
|
||||
case TK_INSERT: {
|
||||
SrcList *pSrc;
|
||||
pSrc = targetSrcList(pParse, pTriggerStep);
|
||||
sqliteInsert(pParse, pSrc,
|
||||
sqliteExprListDup(pTriggerStep->pExprList),
|
||||
sqliteSelectDup(pTriggerStep->pSelect),
|
||||
sqliteIdListDup(pTriggerStep->pIdList), orconf);
|
||||
break;
|
||||
}
|
||||
case TK_DELETE: {
|
||||
SrcList *pSrc;
|
||||
sqliteVdbeAddOp(pParse->pVdbe, OP_ListPush, 0, 0);
|
||||
pSrc = targetSrcList(pParse, pTriggerStep);
|
||||
sqliteDeleteFrom(pParse, pSrc, sqliteExprDup(pTriggerStep->pWhere));
|
||||
sqliteVdbeAddOp(pParse->pVdbe, OP_ListPop, 0, 0);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
pParse->nTab = saveNTab;
|
||||
pTriggerStep = pTriggerStep->pNext;
|
||||
}
|
||||
|
||||
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 sqliteCodeRowTrigger(
|
||||
Parse *pParse, /* Parse context */
|
||||
int op, /* One of TK_UPDATE, TK_INSERT, TK_DELETE */
|
||||
ExprList *pChanges, /* Changes list for any UPDATE OF triggers */
|
||||
int tr_tm, /* One of TK_BEFORE, TK_AFTER */
|
||||
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 * pTrigger;
|
||||
TriggerStack * pTriggerStack;
|
||||
|
||||
assert(op == TK_UPDATE || op == TK_INSERT || op == TK_DELETE);
|
||||
assert(tr_tm == TK_BEFORE || tr_tm == TK_AFTER );
|
||||
|
||||
assert(newIdx != -1 || oldIdx != -1);
|
||||
|
||||
pTrigger = pTab->pTrigger;
|
||||
while( pTrigger ){
|
||||
int fire_this = 0;
|
||||
|
||||
/* determine whether we should code this trigger */
|
||||
if( pTrigger->op == op && pTrigger->tr_tm == tr_tm &&
|
||||
pTrigger->foreach == TK_ROW ){
|
||||
fire_this = 1;
|
||||
pTriggerStack = pParse->trigStack;
|
||||
while( pTriggerStack ){
|
||||
if( pTriggerStack->pTrigger == pTrigger ){
|
||||
fire_this = 0;
|
||||
}
|
||||
pTriggerStack = pTriggerStack->pNext;
|
||||
}
|
||||
if( op == TK_UPDATE && pTrigger->pColumns &&
|
||||
!checkColumnOverLap(pTrigger->pColumns, pChanges) ){
|
||||
fire_this = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if( fire_this && (pTriggerStack = sqliteMalloc(sizeof(TriggerStack)))!=0 ){
|
||||
int endTrigger;
|
||||
SrcList dummyTablist;
|
||||
Expr * whenExpr;
|
||||
AuthContext sContext;
|
||||
|
||||
dummyTablist.nSrc = 0;
|
||||
|
||||
/* Push an entry on to the trigger stack */
|
||||
pTriggerStack->pTrigger = pTrigger;
|
||||
pTriggerStack->newIdx = newIdx;
|
||||
pTriggerStack->oldIdx = oldIdx;
|
||||
pTriggerStack->pTab = pTab;
|
||||
pTriggerStack->pNext = pParse->trigStack;
|
||||
pTriggerStack->ignoreJump = ignoreJump;
|
||||
pParse->trigStack = pTriggerStack;
|
||||
sqliteAuthContextPush(pParse, &sContext, pTrigger->name);
|
||||
|
||||
/* code the WHEN clause */
|
||||
endTrigger = sqliteVdbeMakeLabel(pParse->pVdbe);
|
||||
whenExpr = sqliteExprDup(pTrigger->pWhen);
|
||||
if( sqliteExprResolveIds(pParse, &dummyTablist, 0, whenExpr) ){
|
||||
pParse->trigStack = pParse->trigStack->pNext;
|
||||
sqliteFree(pTriggerStack);
|
||||
sqliteExprDelete(whenExpr);
|
||||
return 1;
|
||||
}
|
||||
sqliteExprIfFalse(pParse, whenExpr, endTrigger, 1);
|
||||
sqliteExprDelete(whenExpr);
|
||||
|
||||
sqliteVdbeAddOp(pParse->pVdbe, OP_ContextPush, 0, 0);
|
||||
codeTriggerProgram(pParse, pTrigger->step_list, orconf);
|
||||
sqliteVdbeAddOp(pParse->pVdbe, OP_ContextPop, 0, 0);
|
||||
|
||||
/* Pop the entry off the trigger stack */
|
||||
pParse->trigStack = pParse->trigStack->pNext;
|
||||
sqliteAuthContextPop(&sContext);
|
||||
sqliteFree(pTriggerStack);
|
||||
|
||||
sqliteVdbeResolveLabel(pParse->pVdbe, endTrigger);
|
||||
}
|
||||
pTrigger = pTrigger->pNext;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
452
sqlite/update.c
Executable file
452
sqlite/update.c
Executable file
@ -0,0 +1,452 @@
|
||||
/*
|
||||
** 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.1.1.1 2004-03-11 22:22:22 alex Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
|
||||
/*
|
||||
** 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 sqliteUpdate(
|
||||
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; /* 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 */
|
||||
sqlite *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 chngRecno; /* True if the record number is being changed */
|
||||
Expr *pRecnoExpr; /* Expression defining the new record number */
|
||||
int openAll; /* True if all indices need to be opened */
|
||||
int isView; /* Trying to update a view */
|
||||
AuthContext sContext; /* The authorization context */
|
||||
|
||||
int before_triggers; /* True if there are any BEFORE triggers */
|
||||
int after_triggers; /* True if there are any AFTER triggers */
|
||||
int row_triggers_exist = 0; /* True if any row triggers exist */
|
||||
|
||||
int newIdx = -1; /* index of trigger "new" temp table */
|
||||
int oldIdx = -1; /* index of trigger "old" temp table */
|
||||
|
||||
sContext.pParse = 0;
|
||||
if( pParse->nErr || sqlite_malloc_failed ) goto update_cleanup;
|
||||
db = pParse->db;
|
||||
assert( pTabList->nSrc==1 );
|
||||
|
||||
/* Locate the table which we want to update.
|
||||
*/
|
||||
pTab = sqliteSrcListLookup(pParse, pTabList);
|
||||
if( pTab==0 ) goto update_cleanup;
|
||||
before_triggers = sqliteTriggersExist(pParse, pTab->pTrigger,
|
||||
TK_UPDATE, TK_BEFORE, TK_ROW, pChanges);
|
||||
after_triggers = sqliteTriggersExist(pParse, pTab->pTrigger,
|
||||
TK_UPDATE, TK_AFTER, TK_ROW, pChanges);
|
||||
row_triggers_exist = before_triggers || after_triggers;
|
||||
isView = pTab->pSelect!=0;
|
||||
if( sqliteIsReadOnly(pParse, pTab, before_triggers) ){
|
||||
goto update_cleanup;
|
||||
}
|
||||
if( isView ){
|
||||
if( sqliteViewGetColumnNames(pParse, pTab) ){
|
||||
goto update_cleanup;
|
||||
}
|
||||
}
|
||||
aXRef = sqliteMalloc( 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( row_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++;
|
||||
}
|
||||
|
||||
/* 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.
|
||||
*/
|
||||
chngRecno = 0;
|
||||
for(i=0; i<pChanges->nExpr; i++){
|
||||
if( sqliteExprResolveIds(pParse, pTabList, 0, pChanges->a[i].pExpr) ){
|
||||
goto update_cleanup;
|
||||
}
|
||||
if( sqliteExprCheck(pParse, pChanges->a[i].pExpr, 0, 0) ){
|
||||
goto update_cleanup;
|
||||
}
|
||||
for(j=0; j<pTab->nCol; j++){
|
||||
if( sqliteStrICmp(pTab->aCol[j].zName, pChanges->a[i].zName)==0 ){
|
||||
if( j==pTab->iPKey ){
|
||||
chngRecno = 1;
|
||||
pRecnoExpr = pChanges->a[i].pExpr;
|
||||
}
|
||||
aXRef[j] = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( j>=pTab->nCol ){
|
||||
if( sqliteIsRowid(pChanges->a[i].zName) ){
|
||||
chngRecno = 1;
|
||||
pRecnoExpr = pChanges->a[i].pExpr;
|
||||
}else{
|
||||
sqliteErrorMsg(pParse, "no such column: %s", pChanges->a[i].zName);
|
||||
goto update_cleanup;
|
||||
}
|
||||
}
|
||||
#ifndef SQLITE_OMIT_AUTHORIZATION
|
||||
{
|
||||
int rc;
|
||||
rc = sqliteAuthCheck(pParse, SQLITE_UPDATE, pTab->zName,
|
||||
pTab->aCol[j].zName, db->aDb[pTab->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( chngRecno ){
|
||||
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 = sqliteMalloc( 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( chngRecno ){
|
||||
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( pWhere ){
|
||||
if( sqliteExprResolveIds(pParse, pTabList, 0, pWhere) ){
|
||||
goto update_cleanup;
|
||||
}
|
||||
if( sqliteExprCheck(pParse, pWhere, 0, 0) ){
|
||||
goto update_cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
/* Start the view context
|
||||
*/
|
||||
if( isView ){
|
||||
sqliteAuthContextPush(pParse, &sContext, pTab->zName);
|
||||
}
|
||||
|
||||
/* Begin generating code.
|
||||
*/
|
||||
v = sqliteGetVdbe(pParse);
|
||||
if( v==0 ) goto update_cleanup;
|
||||
sqliteBeginWriteOperation(pParse, 1, pTab->iDb);
|
||||
|
||||
/* If we are trying to update a view, construct that view into
|
||||
** a temporary table.
|
||||
*/
|
||||
if( isView ){
|
||||
Select *pView;
|
||||
pView = sqliteSelectDup(pTab->pSelect);
|
||||
sqliteSelect(pParse, pView, SRT_TempTable, iCur, 0, 0, 0);
|
||||
sqliteSelectDelete(pView);
|
||||
}
|
||||
|
||||
/* Begin the database scan
|
||||
*/
|
||||
pWInfo = sqliteWhereBegin(pParse, pTabList, pWhere, 1, 0);
|
||||
if( pWInfo==0 ) goto update_cleanup;
|
||||
|
||||
/* Remember the index of every item to be updated.
|
||||
*/
|
||||
sqliteVdbeAddOp(v, OP_ListWrite, 0, 0);
|
||||
|
||||
/* End the database scan loop.
|
||||
*/
|
||||
sqliteWhereEnd(pWInfo);
|
||||
|
||||
/* Initialize the count of updated rows
|
||||
*/
|
||||
if( db->flags & SQLITE_CountRows && !pParse->trigStack ){
|
||||
sqliteVdbeAddOp(v, OP_Integer, 0, 0);
|
||||
}
|
||||
|
||||
if( row_triggers_exist ){
|
||||
/* Create pseudo-tables for NEW and OLD
|
||||
*/
|
||||
sqliteVdbeAddOp(v, OP_OpenPseudo, oldIdx, 0);
|
||||
sqliteVdbeAddOp(v, OP_OpenPseudo, newIdx, 0);
|
||||
|
||||
/* The top of the update loop for when there are triggers.
|
||||
*/
|
||||
sqliteVdbeAddOp(v, OP_ListRewind, 0, 0);
|
||||
addr = sqliteVdbeAddOp(v, OP_ListRead, 0, 0);
|
||||
sqliteVdbeAddOp(v, OP_Dup, 0, 0);
|
||||
|
||||
/* Open a cursor and make it point to the record that is
|
||||
** being updated.
|
||||
*/
|
||||
sqliteVdbeAddOp(v, OP_Dup, 0, 0);
|
||||
if( !isView ){
|
||||
sqliteVdbeAddOp(v, OP_Integer, pTab->iDb, 0);
|
||||
sqliteVdbeAddOp(v, OP_OpenRead, iCur, pTab->tnum);
|
||||
}
|
||||
sqliteVdbeAddOp(v, OP_MoveTo, iCur, 0);
|
||||
|
||||
/* Generate the OLD table
|
||||
*/
|
||||
sqliteVdbeAddOp(v, OP_Recno, iCur, 0);
|
||||
sqliteVdbeAddOp(v, OP_RowData, iCur, 0);
|
||||
sqliteVdbeAddOp(v, OP_PutIntKey, oldIdx, 0);
|
||||
|
||||
/* Generate the NEW table
|
||||
*/
|
||||
if( chngRecno ){
|
||||
sqliteExprCode(pParse, pRecnoExpr);
|
||||
}else{
|
||||
sqliteVdbeAddOp(v, OP_Recno, iCur, 0);
|
||||
}
|
||||
for(i=0; i<pTab->nCol; i++){
|
||||
if( i==pTab->iPKey ){
|
||||
sqliteVdbeAddOp(v, OP_String, 0, 0);
|
||||
continue;
|
||||
}
|
||||
j = aXRef[i];
|
||||
if( j<0 ){
|
||||
sqliteVdbeAddOp(v, OP_Column, iCur, i);
|
||||
}else{
|
||||
sqliteExprCode(pParse, pChanges->a[j].pExpr);
|
||||
}
|
||||
}
|
||||
sqliteVdbeAddOp(v, OP_MakeRecord, pTab->nCol, 0);
|
||||
sqliteVdbeAddOp(v, OP_PutIntKey, newIdx, 0);
|
||||
if( !isView ){
|
||||
sqliteVdbeAddOp(v, OP_Close, iCur, 0);
|
||||
}
|
||||
|
||||
/* Fire the BEFORE and INSTEAD OF triggers
|
||||
*/
|
||||
if( sqliteCodeRowTrigger(pParse, TK_UPDATE, pChanges, TK_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.
|
||||
*/
|
||||
sqliteVdbeAddOp(v, OP_Integer, pTab->iDb, 0);
|
||||
sqliteVdbeAddOp(v, OP_OpenWrite, iCur, pTab->tnum);
|
||||
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] ){
|
||||
sqliteVdbeAddOp(v, OP_Integer, pIdx->iDb, 0);
|
||||
sqliteVdbeAddOp(v, OP_OpenWrite, iCur+i+1, pIdx->tnum);
|
||||
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( !row_triggers_exist ){
|
||||
sqliteVdbeAddOp(v, OP_ListRewind, 0, 0);
|
||||
addr = sqliteVdbeAddOp(v, OP_ListRead, 0, 0);
|
||||
sqliteVdbeAddOp(v, OP_Dup, 0, 0);
|
||||
}
|
||||
sqliteVdbeAddOp(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( chngRecno ){
|
||||
sqliteExprCode(pParse, pRecnoExpr);
|
||||
sqliteVdbeAddOp(v, OP_MustBeInt, 0, 0);
|
||||
}
|
||||
|
||||
/* Compute new data for this record.
|
||||
*/
|
||||
for(i=0; i<pTab->nCol; i++){
|
||||
if( i==pTab->iPKey ){
|
||||
sqliteVdbeAddOp(v, OP_String, 0, 0);
|
||||
continue;
|
||||
}
|
||||
j = aXRef[i];
|
||||
if( j<0 ){
|
||||
sqliteVdbeAddOp(v, OP_Column, iCur, i);
|
||||
}else{
|
||||
sqliteExprCode(pParse, pChanges->a[j].pExpr);
|
||||
}
|
||||
}
|
||||
|
||||
/* Do constraint checks
|
||||
*/
|
||||
sqliteGenerateConstraintChecks(pParse, pTab, iCur, aIdxUsed, chngRecno, 1,
|
||||
onError, addr);
|
||||
|
||||
/* Delete the old indices for the current record.
|
||||
*/
|
||||
sqliteGenerateRowIndexDelete(db, v, pTab, iCur, aIdxUsed);
|
||||
|
||||
/* If changing the record number, delete the old record.
|
||||
*/
|
||||
if( chngRecno ){
|
||||
sqliteVdbeAddOp(v, OP_Delete, iCur, 0);
|
||||
}
|
||||
|
||||
/* Create the new index entries and the new record.
|
||||
*/
|
||||
sqliteCompleteInsertion(pParse, pTab, iCur, aIdxUsed, chngRecno, 1, -1);
|
||||
}
|
||||
|
||||
/* Increment the row counter
|
||||
*/
|
||||
if( db->flags & SQLITE_CountRows && !pParse->trigStack){
|
||||
sqliteVdbeAddOp(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( row_triggers_exist ){
|
||||
if( !isView ){
|
||||
for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
|
||||
if( openAll || aIdxUsed[i] )
|
||||
sqliteVdbeAddOp(v, OP_Close, iCur+i+1, 0);
|
||||
}
|
||||
sqliteVdbeAddOp(v, OP_Close, iCur, 0);
|
||||
pParse->nTab = iCur;
|
||||
}
|
||||
if( sqliteCodeRowTrigger(pParse, TK_UPDATE, pChanges, TK_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.
|
||||
*/
|
||||
sqliteVdbeAddOp(v, OP_Goto, 0, addr);
|
||||
sqliteVdbeChangeP2(v, addr, sqliteVdbeCurrentAddr(v));
|
||||
sqliteVdbeAddOp(v, OP_ListReset, 0, 0);
|
||||
|
||||
/* Close all tables if there were no FOR EACH ROW triggers */
|
||||
if( !row_triggers_exist ){
|
||||
for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
|
||||
if( openAll || aIdxUsed[i] ){
|
||||
sqliteVdbeAddOp(v, OP_Close, iCur+i+1, 0);
|
||||
}
|
||||
}
|
||||
sqliteVdbeAddOp(v, OP_Close, iCur, 0);
|
||||
pParse->nTab = iCur;
|
||||
}else{
|
||||
sqliteVdbeAddOp(v, OP_Close, newIdx, 0);
|
||||
sqliteVdbeAddOp(v, OP_Close, oldIdx, 0);
|
||||
}
|
||||
|
||||
sqliteVdbeAddOp(v, OP_SetCounts, 0, 0);
|
||||
sqliteEndWriteOperation(pParse);
|
||||
|
||||
/*
|
||||
** Return the number of rows that were changed.
|
||||
*/
|
||||
if( db->flags & SQLITE_CountRows && !pParse->trigStack ){
|
||||
sqliteVdbeOp3(v, OP_ColumnName, 0, 1, "rows updated", P3_STATIC);
|
||||
sqliteVdbeAddOp(v, OP_Callback, 1, 0);
|
||||
}
|
||||
|
||||
update_cleanup:
|
||||
sqliteAuthContextPop(&sContext);
|
||||
sqliteFree(apIdx);
|
||||
sqliteFree(aXRef);
|
||||
sqliteSrcListDelete(pTabList);
|
||||
sqliteExprListDelete(pChanges);
|
||||
sqliteExprDelete(pWhere);
|
||||
return;
|
||||
}
|
1135
sqlite/util.c
Executable file
1135
sqlite/util.c
Executable file
File diff suppressed because it is too large
Load Diff
320
sqlite/vacuum.c
Executable file
320
sqlite/vacuum.c
Executable file
@ -0,0 +1,320 @@
|
||||
/*
|
||||
** 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.1.1.1 2004-03-11 22:22:23 alex Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include "os.h"
|
||||
|
||||
/*
|
||||
** A structure for holding a dynamic string - a string that can grow
|
||||
** without bound.
|
||||
*/
|
||||
typedef struct dynStr dynStr;
|
||||
struct dynStr {
|
||||
char *z; /* Text of the string in space obtained from sqliteMalloc() */
|
||||
int nAlloc; /* Amount of space allocated to z[] */
|
||||
int nUsed; /* Next unused slot in z[] */
|
||||
};
|
||||
|
||||
/*
|
||||
** A structure that holds the vacuum context
|
||||
*/
|
||||
typedef struct vacuumStruct vacuumStruct;
|
||||
struct vacuumStruct {
|
||||
sqlite *dbOld; /* Original database */
|
||||
sqlite *dbNew; /* New database */
|
||||
char **pzErrMsg; /* Write errors here */
|
||||
int rc; /* Set to non-zero on an error */
|
||||
const char *zTable; /* Name of a table being copied */
|
||||
const char *zPragma; /* Pragma to execute with results */
|
||||
dynStr s1, s2; /* Two dynamic strings */
|
||||
};
|
||||
|
||||
#if !defined(SQLITE_OMIT_VACUUM) || SQLITE_OMIT_VACUUM
|
||||
/*
|
||||
** Append text to a dynamic string
|
||||
*/
|
||||
static void appendText(dynStr *p, const char *zText, int nText){
|
||||
if( nText<0 ) nText = strlen(zText);
|
||||
if( p->z==0 || p->nUsed + nText + 1 >= p->nAlloc ){
|
||||
char *zNew;
|
||||
p->nAlloc = p->nUsed + nText + 1000;
|
||||
zNew = sqliteRealloc(p->z, p->nAlloc);
|
||||
if( zNew==0 ){
|
||||
sqliteFree(p->z);
|
||||
memset(p, 0, sizeof(*p));
|
||||
return;
|
||||
}
|
||||
p->z = zNew;
|
||||
}
|
||||
memcpy(&p->z[p->nUsed], zText, nText+1);
|
||||
p->nUsed += nText;
|
||||
}
|
||||
|
||||
/*
|
||||
** Append text to a dynamic string, having first put the text in quotes.
|
||||
*/
|
||||
static void appendQuoted(dynStr *p, const char *zText){
|
||||
int i, j;
|
||||
appendText(p, "'", 1);
|
||||
for(i=j=0; zText[i]; i++){
|
||||
if( zText[i]=='\'' ){
|
||||
appendText(p, &zText[j], i-j+1);
|
||||
j = i + 1;
|
||||
appendText(p, "'", 1);
|
||||
}
|
||||
}
|
||||
if( j<i ){
|
||||
appendText(p, &zText[j], i-j);
|
||||
}
|
||||
appendText(p, "'", 1);
|
||||
}
|
||||
|
||||
/*
|
||||
** Execute statements of SQL. If an error occurs, write the error
|
||||
** message into *pzErrMsg and return non-zero.
|
||||
*/
|
||||
static int execsql(char **pzErrMsg, sqlite *db, const char *zSql){
|
||||
char *zErrMsg = 0;
|
||||
int rc;
|
||||
|
||||
/* printf("***** executing *****\n%s\n", zSql); */
|
||||
rc = sqlite_exec(db, zSql, 0, 0, &zErrMsg);
|
||||
if( zErrMsg ){
|
||||
sqliteSetString(pzErrMsg, zErrMsg, (char*)0);
|
||||
sqlite_freemem(zErrMsg);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** This is the second stage callback. Each invocation contains all the
|
||||
** data for a single row of a single table in the original database. This
|
||||
** routine must write that information into the new database.
|
||||
*/
|
||||
static int vacuumCallback2(void *pArg, int argc, char **argv, char **NotUsed){
|
||||
vacuumStruct *p = (vacuumStruct*)pArg;
|
||||
const char *zSep = "(";
|
||||
int i;
|
||||
|
||||
if( argv==0 ) return 0;
|
||||
p->s2.nUsed = 0;
|
||||
appendText(&p->s2, "INSERT INTO ", -1);
|
||||
appendQuoted(&p->s2, p->zTable);
|
||||
appendText(&p->s2, " VALUES", -1);
|
||||
for(i=0; i<argc; i++){
|
||||
appendText(&p->s2, zSep, 1);
|
||||
zSep = ",";
|
||||
if( argv[i]==0 ){
|
||||
appendText(&p->s2, "NULL", 4);
|
||||
}else{
|
||||
appendQuoted(&p->s2, argv[i]);
|
||||
}
|
||||
}
|
||||
appendText(&p->s2,")", 1);
|
||||
p->rc = execsql(p->pzErrMsg, p->dbNew, p->s2.z);
|
||||
return p->rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** This is the first stage callback. Each invocation contains three
|
||||
** arguments where are taken from the SQLITE_MASTER table of the original
|
||||
** database: (1) the entry type, (2) the entry name, and (3) the SQL for
|
||||
** the entry. In all cases, execute the SQL of the third argument.
|
||||
** For tables, run a query to select all entries in that table and
|
||||
** transfer them to the second-stage callback.
|
||||
*/
|
||||
static int vacuumCallback1(void *pArg, int argc, char **argv, char **NotUsed){
|
||||
vacuumStruct *p = (vacuumStruct*)pArg;
|
||||
int rc = 0;
|
||||
assert( argc==3 );
|
||||
if( argv==0 ) return 0;
|
||||
assert( argv[0]!=0 );
|
||||
assert( argv[1]!=0 );
|
||||
assert( argv[2]!=0 );
|
||||
rc = execsql(p->pzErrMsg, p->dbNew, argv[2]);
|
||||
if( rc==SQLITE_OK && strcmp(argv[0],"table")==0 ){
|
||||
char *zErrMsg = 0;
|
||||
p->s1.nUsed = 0;
|
||||
appendText(&p->s1, "SELECT * FROM ", -1);
|
||||
appendQuoted(&p->s1, argv[1]);
|
||||
p->zTable = argv[1];
|
||||
rc = sqlite_exec(p->dbOld, p->s1.z, vacuumCallback2, p, &zErrMsg);
|
||||
if( zErrMsg ){
|
||||
sqliteSetString(p->pzErrMsg, zErrMsg, (char*)0);
|
||||
sqlite_freemem(zErrMsg);
|
||||
}
|
||||
}
|
||||
if( rc!=SQLITE_ABORT ) p->rc = rc;
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** This callback is used to transfer PRAGMA settings from one database
|
||||
** to the other. The value in argv[0] should be passed to a pragma
|
||||
** identified by ((vacuumStruct*)pArg)->zPragma.
|
||||
*/
|
||||
static int vacuumCallback3(void *pArg, int argc, char **argv, char **NotUsed){
|
||||
vacuumStruct *p = (vacuumStruct*)pArg;
|
||||
char zBuf[200];
|
||||
assert( argc==1 );
|
||||
if( argv==0 ) return 0;
|
||||
assert( argv[0]!=0 );
|
||||
assert( strlen(p->zPragma)<100 );
|
||||
assert( strlen(argv[0])<30 );
|
||||
sprintf(zBuf,"PRAGMA %s=%s;", p->zPragma, argv[0]);
|
||||
p->rc = execsql(p->pzErrMsg, p->dbNew, zBuf);
|
||||
return p->rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Generate a random name of 20 character in length.
|
||||
*/
|
||||
static void randomName(unsigned char *zBuf){
|
||||
static const unsigned char zChars[] =
|
||||
"abcdefghijklmnopqrstuvwxyz"
|
||||
"0123456789";
|
||||
int i;
|
||||
sqliteRandomness(20, zBuf);
|
||||
for(i=0; i<20; i++){
|
||||
zBuf[i] = zChars[ zBuf[i]%(sizeof(zChars)-1) ];
|
||||
}
|
||||
}
|
||||
#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 sqliteVacuum(Parse *pParse, Token *pTableName){
|
||||
Vdbe *v = sqliteGetVdbe(pParse);
|
||||
sqliteVdbeAddOp(v, OP_Vacuum, 0, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
** This routine implements the OP_Vacuum opcode of the VDBE.
|
||||
*/
|
||||
int sqliteRunVacuum(char **pzErrMsg, sqlite *db){
|
||||
#if !defined(SQLITE_OMIT_VACUUM) || 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 */
|
||||
sqlite *dbNew = 0; /* The new vacuumed database */
|
||||
int rc = SQLITE_OK; /* Return code from service routines */
|
||||
int i; /* Loop counter */
|
||||
char *zErrMsg; /* Error message */
|
||||
vacuumStruct sVac; /* Information passed to callbacks */
|
||||
|
||||
/* These are all of the pragmas that need to be transferred over
|
||||
** to the new database */
|
||||
static const char *zPragma[] = {
|
||||
"default_synchronous",
|
||||
"default_cache_size",
|
||||
/* "default_temp_store", */
|
||||
};
|
||||
|
||||
if( db->flags & SQLITE_InTrans ){
|
||||
sqliteSetString(pzErrMsg, "cannot VACUUM from within a transaction",
|
||||
(char*)0);
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
memset(&sVac, 0, sizeof(sVac));
|
||||
|
||||
/* Get the full pathname of the database file and create two
|
||||
** temporary filenames in the same directory as the original file.
|
||||
*/
|
||||
zFilename = sqliteBtreeGetFilename(db->aDb[0].pBt);
|
||||
if( zFilename==0 ){
|
||||
/* This only happens with the in-memory database. VACUUM is a no-op
|
||||
** there, so just return */
|
||||
return SQLITE_OK;
|
||||
}
|
||||
nFilename = strlen(zFilename);
|
||||
zTemp = sqliteMalloc( nFilename+100 );
|
||||
if( zTemp==0 ) return SQLITE_NOMEM;
|
||||
strcpy(zTemp, zFilename);
|
||||
for(i=0; i<10; i++){
|
||||
zTemp[nFilename] = '-';
|
||||
randomName(&zTemp[nFilename+1]);
|
||||
if( !sqliteOsFileExists(zTemp) ) break;
|
||||
}
|
||||
if( i>=10 ){
|
||||
sqliteSetString(pzErrMsg, "unable to create a temporary database file "
|
||||
"in the same directory as the original database", (char*)0);
|
||||
goto end_of_vacuum;
|
||||
}
|
||||
|
||||
|
||||
dbNew = sqlite_open(zTemp, 0, &zErrMsg);
|
||||
if( dbNew==0 ){
|
||||
sqliteSetString(pzErrMsg, "unable to open a temporary database at ",
|
||||
zTemp, " - ", zErrMsg, (char*)0);
|
||||
goto end_of_vacuum;
|
||||
}
|
||||
if( (rc = execsql(pzErrMsg, db, "BEGIN"))!=0 ) goto end_of_vacuum;
|
||||
if( (rc = execsql(pzErrMsg, dbNew, "PRAGMA synchronous=off; BEGIN"))!=0 ){
|
||||
goto end_of_vacuum;
|
||||
}
|
||||
|
||||
sVac.dbOld = db;
|
||||
sVac.dbNew = dbNew;
|
||||
sVac.pzErrMsg = pzErrMsg;
|
||||
for(i=0; rc==SQLITE_OK && i<sizeof(zPragma)/sizeof(zPragma[0]); i++){
|
||||
char zBuf[200];
|
||||
assert( strlen(zPragma[i])<100 );
|
||||
sprintf(zBuf, "PRAGMA %s;", zPragma[i]);
|
||||
sVac.zPragma = zPragma[i];
|
||||
rc = sqlite_exec(db, zBuf, vacuumCallback3, &sVac, &zErrMsg);
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite_exec(db,
|
||||
"SELECT type, name, sql FROM sqlite_master "
|
||||
"WHERE sql NOT NULL AND type!='view' "
|
||||
"UNION ALL "
|
||||
"SELECT type, name, sql FROM sqlite_master "
|
||||
"WHERE sql NOT NULL AND type=='view'",
|
||||
vacuumCallback1, &sVac, &zErrMsg);
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqliteBtreeCopyFile(db->aDb[0].pBt, dbNew->aDb[0].pBt);
|
||||
sqlite_exec(db, "COMMIT", 0, 0, 0);
|
||||
sqliteResetInternalSchema(db, 0);
|
||||
}
|
||||
|
||||
end_of_vacuum:
|
||||
if( rc && zErrMsg!=0 ){
|
||||
sqliteSetString(pzErrMsg, "unable to vacuum database - ",
|
||||
zErrMsg, (char*)0);
|
||||
}
|
||||
sqlite_exec(db, "ROLLBACK", 0, 0, 0);
|
||||
if( dbNew ) sqlite_close(dbNew);
|
||||
sqliteOsDelete(zTemp);
|
||||
sqliteFree(zTemp);
|
||||
sqliteFree(sVac.s1.z);
|
||||
sqliteFree(sVac.s2.z);
|
||||
if( zErrMsg ) sqlite_freemem(zErrMsg);
|
||||
if( rc==SQLITE_ABORT ) sVac.rc = SQLITE_ERROR;
|
||||
return sVac.rc;
|
||||
#endif
|
||||
}
|
4885
sqlite/vdbe.c
Executable file
4885
sqlite/vdbe.c
Executable file
File diff suppressed because it is too large
Load Diff
112
sqlite/vdbe.h
Executable file
112
sqlite/vdbe.h
Executable file
@ -0,0 +1,112 @@
|
||||
/*
|
||||
** 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.1.1.1 2004-03-11 22:22:23 alex 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; /* P3_STATIC, P3_DYNAMIC or P3_POINTER */
|
||||
#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_POINTER (-3) /* P3 is a pointer to some structure or object */
|
||||
|
||||
/*
|
||||
** The following macro converts a relative address in the p2 field
|
||||
** of a VdbeOp structure into a negative number so that
|
||||
** sqliteVdbeAddOpList() 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 *sqliteVdbeCreate(sqlite*);
|
||||
void sqliteVdbeCreateCallback(Vdbe*, int*);
|
||||
int sqliteVdbeAddOp(Vdbe*,int,int,int);
|
||||
int sqliteVdbeOp3(Vdbe*,int,int,int,const char *zP3,int);
|
||||
int sqliteVdbeCode(Vdbe*,...);
|
||||
int sqliteVdbeAddOpList(Vdbe*, int nOp, VdbeOpList const *aOp);
|
||||
void sqliteVdbeChangeP1(Vdbe*, int addr, int P1);
|
||||
void sqliteVdbeChangeP2(Vdbe*, int addr, int P2);
|
||||
void sqliteVdbeChangeP3(Vdbe*, int addr, const char *zP1, int N);
|
||||
void sqliteVdbeDequoteP3(Vdbe*, int addr);
|
||||
int sqliteVdbeFindOp(Vdbe*, int, int);
|
||||
VdbeOp *sqliteVdbeGetOp(Vdbe*, int);
|
||||
int sqliteVdbeMakeLabel(Vdbe*);
|
||||
void sqliteVdbeDelete(Vdbe*);
|
||||
void sqliteVdbeMakeReady(Vdbe*,int,int);
|
||||
int sqliteVdbeExec(Vdbe*);
|
||||
int sqliteVdbeList(Vdbe*);
|
||||
int sqliteVdbeFinalize(Vdbe*,char**);
|
||||
void sqliteVdbeResolveLabel(Vdbe*, int);
|
||||
int sqliteVdbeCurrentAddr(Vdbe*);
|
||||
void sqliteVdbeTrace(Vdbe*,FILE*);
|
||||
void sqliteVdbeCompressSpace(Vdbe*,int);
|
||||
int sqliteVdbeReset(Vdbe*,char **);
|
||||
int sqliteVdbeSetVariables(Vdbe*,int,const char**);
|
||||
|
||||
#endif
|
303
sqlite/vdbeInt.h
Executable file
303
sqlite/vdbeInt.h
Executable file
@ -0,0 +1,303 @@
|
||||
/*
|
||||
** 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
** When converting from the native format to the key format and back
|
||||
** again, in addition to changing the byte order we invert the high-order
|
||||
** bit of the most significant byte. This causes negative numbers to
|
||||
** sort before positive numbers in the memcmp() function.
|
||||
*/
|
||||
#define keyToInt(X) (sqliteVdbeByteSwap(X) ^ 0x80000000)
|
||||
#define intToKey(X) (sqliteVdbeByteSwap((X) ^ 0x80000000))
|
||||
|
||||
/*
|
||||
** The makefile scans this 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 *sqliteOpcodeNames[];
|
||||
|
||||
/*
|
||||
** 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 lastRecno; /* Last recno from a Next or NextIdx operation */
|
||||
int nextRowid; /* Next rowid returned by OP_NewRowid */
|
||||
Bool recnoIsValid; /* True if lastRecno is valid */
|
||||
Bool keyAsData; /* The OP_Column command works on key instead of data */
|
||||
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 sqliteBtreeMoveto() is needed */
|
||||
int movetoTarget; /* Argument to the deferred sqliteBtreeMoveto() */
|
||||
Btree *pBt; /* Separate file holding temporary table */
|
||||
int nData; /* Number of bytes in pData */
|
||||
char *pData; /* Data for a NEW or OLD pseudo-table */
|
||||
int iKey; /* Key for the NEW or OLD pseudo-table row */
|
||||
};
|
||||
typedef struct Cursor Cursor;
|
||||
|
||||
/*
|
||||
** A sorter builds a list of elements to be sorted. Each element of
|
||||
** the list is an instance of the following structure.
|
||||
*/
|
||||
typedef struct Sorter Sorter;
|
||||
struct Sorter {
|
||||
int nKey; /* Number of bytes in the key */
|
||||
char *zKey; /* The key by which we will sort */
|
||||
int nData; /* Number of bytes in the data */
|
||||
char *pData; /* The data associated with this key */
|
||||
Sorter *pNext; /* Next in the list */
|
||||
};
|
||||
|
||||
/*
|
||||
** Number of buckets used for merge-sort.
|
||||
*/
|
||||
#define NSORT 30
|
||||
|
||||
/*
|
||||
** 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 single level of the stack or a single memory cell
|
||||
** is an instance of the following structure.
|
||||
*/
|
||||
struct Mem {
|
||||
int i; /* Integer value */
|
||||
int n; /* Number of characters in string value, including '\0' */
|
||||
int flags; /* Some combination of MEM_Null, MEM_Str, MEM_Dyn, etc. */
|
||||
double r; /* Real value */
|
||||
char *z; /* String value */
|
||||
char zShort[NBFS]; /* Space for short strings */
|
||||
};
|
||||
typedef struct Mem Mem;
|
||||
|
||||
/*
|
||||
** Allowed values for Mem.flags
|
||||
*/
|
||||
#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_Dyn 0x0010 /* Need to call sqliteFree() on Mem.z */
|
||||
#define MEM_Static 0x0020 /* Mem.z points to a static string */
|
||||
#define MEM_Ephem 0x0040 /* Mem.z points to an ephemeral string */
|
||||
#define MEM_Short 0x0080 /* Mem.z points to Mem.zShort */
|
||||
|
||||
/* The following MEM_ value appears only in AggElem.aMem.s.flag fields.
|
||||
** It indicates that the corresponding AggElem.aMem.z points to a
|
||||
** aggregate function context that needs to be finalized.
|
||||
*/
|
||||
#define MEM_AggCtx 0x0100 /* Mem.z points to an agg function context */
|
||||
|
||||
/*
|
||||
** 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 vdbe.c because it uses substructures
|
||||
** (Mem) which are only defined there.
|
||||
*/
|
||||
struct sqlite_func {
|
||||
FuncDef *pFunc; /* Pointer to function information. MUST BE FIRST */
|
||||
Mem s; /* The return value is stored here */
|
||||
void *pAgg; /* Aggregate context */
|
||||
u8 isError; /* Set to true for an error */
|
||||
u8 isStep; /* Current in the step function */
|
||||
int cnt; /* Number of times that the step function has been called */
|
||||
};
|
||||
|
||||
/*
|
||||
** An Agg structure describes an Aggregator. Each Agg consists of
|
||||
** zero or more Aggregator elements (AggElem). Each AggElem contains
|
||||
** a key and one or more values. The values are used in processing
|
||||
** aggregate functions in a SELECT. The key is used to implement
|
||||
** the GROUP BY clause of a select.
|
||||
*/
|
||||
typedef struct Agg Agg;
|
||||
typedef struct AggElem AggElem;
|
||||
struct Agg {
|
||||
int nMem; /* Number of values stored in each AggElem */
|
||||
AggElem *pCurrent; /* The AggElem currently in focus */
|
||||
HashElem *pSearch; /* The hash element for pCurrent */
|
||||
Hash hash; /* Hash table of all aggregate elements */
|
||||
FuncDef **apFunc; /* Information about aggregate functions */
|
||||
};
|
||||
struct AggElem {
|
||||
char *zKey; /* The key to this AggElem */
|
||||
int nKey; /* Number of bytes in the key, including '\0' at end */
|
||||
Mem aMem[1]; /* The values for this AggElem */
|
||||
};
|
||||
|
||||
/*
|
||||
** 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 Keylist is a bunch of keys into a table. The keylist can
|
||||
** grow without bound. The keylist stores the ROWIDs of database
|
||||
** records that need to be deleted or updated.
|
||||
*/
|
||||
typedef struct Keylist Keylist;
|
||||
struct Keylist {
|
||||
int nKey; /* Number of slots in aKey[] */
|
||||
int nUsed; /* Next unwritten slot in aKey[] */
|
||||
int nRead; /* Next unread slot in aKey[] */
|
||||
Keylist *pNext; /* Next block of keys */
|
||||
int aKey[1]; /* One or more keys. Extra space allocated as needed */
|
||||
};
|
||||
|
||||
/*
|
||||
** A Context stores the last insert rowid, the last statement change count,
|
||||
** and the current statement change count (i.e. changes since last statement).
|
||||
** Elements of Context structure type make up the ContextStack, which is
|
||||
** updated by the ContextPush and ContextPop opcodes (used by triggers)
|
||||
*/
|
||||
typedef struct Context Context;
|
||||
struct Context {
|
||||
int lastRowid; /* Last insert rowid (from db->lastRowid) */
|
||||
int lsChange; /* Last statement change count (from db->lsChange) */
|
||||
int csChange; /* Current statement change count (from db->csChange) */
|
||||
};
|
||||
|
||||
/*
|
||||
** An instance of the virtual machine. This structure contains the complete
|
||||
** state of the virtual machine.
|
||||
**
|
||||
** The "sqlite_vm" structure pointer that is returned by sqlite_compile()
|
||||
** is really a pointer to an instance of this structure.
|
||||
*/
|
||||
struct Vdbe {
|
||||
sqlite *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 */
|
||||
char **zArgv; /* Text values used by the callback */
|
||||
char **azColName; /* Becomes the 4th parameter to callbacks */
|
||||
int nCursor; /* Number of slots in aCsr[] */
|
||||
Cursor *aCsr; /* One element of this array for each open cursor */
|
||||
Sorter *pSort; /* A linked list of objects to be sorted */
|
||||
FILE *pFile; /* At most one open file handler */
|
||||
int nField; /* Number of file fields */
|
||||
char **azField; /* Data for each file field */
|
||||
int nVar; /* Number of entries in azVariable[] */
|
||||
char **azVar; /* Values for the OP_Variable opcode */
|
||||
int *anVar; /* Length of each value in azVariable[] */
|
||||
u8 *abVar; /* TRUE if azVariable[i] needs to be sqliteFree()ed */
|
||||
char *zLine; /* A single line from the input file */
|
||||
int nLineAlloc; /* Number of spaces allocated for zLine */
|
||||
int magic; /* Magic number for sanity checking */
|
||||
int nMem; /* Number of memory locations currently allocated */
|
||||
Mem *aMem; /* The memory locations */
|
||||
Agg agg; /* Aggregate information */
|
||||
int nSet; /* Number of sets allocated */
|
||||
Set *aSet; /* An array of sets */
|
||||
int nCallback; /* Number of callbacks invoked so far */
|
||||
Keylist *pList; /* A list of ROWIDs */
|
||||
int keylistStackDepth; /* The size of the "keylist" stack */
|
||||
Keylist **keylistStack; /* The stack used by opcodes ListPush & ListPop */
|
||||
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 undoTransOnError; /* If error, either ROLLBACK or COMMIT */
|
||||
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 explain; /* True if EXPLAIN present on SQL command */
|
||||
};
|
||||
|
||||
/*
|
||||
** 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 sqliteVdbeCleanupCursor(Cursor*);
|
||||
void sqliteVdbeSorterReset(Vdbe*);
|
||||
void sqliteVdbeAggReset(Agg*);
|
||||
void sqliteVdbeKeylistFree(Keylist*);
|
||||
void sqliteVdbePopStack(Vdbe*,int);
|
||||
int sqliteVdbeCursorMoveto(Cursor*);
|
||||
int sqliteVdbeByteSwap(int);
|
||||
#if !defined(NDEBUG) || defined(VDBE_PROFILE)
|
||||
void sqliteVdbePrintOp(FILE*, int, Op*);
|
||||
#endif
|
1061
sqlite/vdbeaux.c
Executable file
1061
sqlite/vdbeaux.c
Executable file
File diff suppressed because it is too large
Load Diff
1204
sqlite/where.c
Executable file
1204
sqlite/where.c
Executable file
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user