зеркало из https://github.com/mozilla/pjs.git
b=263211, sqlite3 and storage landing - step 1; r=darin,sr=shaver
This commit is contained in:
Родитель
ca9283c0f3
Коммит
42c8ec91cc
|
@ -0,0 +1,37 @@
|
|||
This directory contains source code to
|
||||
|
||||
SQLite: An Embeddable SQL Database Engine
|
||||
|
||||
To compile the project, first create a directory in which to place
|
||||
the build products. It is recommended, but not required, that the
|
||||
build directory be separate from the source directory. Cd into the
|
||||
build directory and then from the build directory run the configure
|
||||
script found at the root of the source tree. Then run "make".
|
||||
|
||||
For example:
|
||||
|
||||
tar xzf sqlite.tar.gz ;# Unpack the source tree into "sqlite"
|
||||
mkdir bld ;# Build will occur in a sibling directory
|
||||
cd bld ;# Change to the build directory
|
||||
../sqlite/configure ;# Run the configure script
|
||||
make ;# Run the makefile.
|
||||
|
||||
The configure script uses autoconf 2.50 and libtool. If the configure
|
||||
script does not work out for you, there is a generic makefile named
|
||||
"Makefile.linux-gcc" in the top directory of the source tree that you
|
||||
can copy and edit to suite your needs. Comments on the generic makefile
|
||||
show what changes are needed.
|
||||
|
||||
The linux binaries on the website are created using the generic makefile,
|
||||
not the configure script. The configure script is unmaintained. (You
|
||||
can volunteer to take over maintenance of the configure script, if you want!)
|
||||
The windows binaries on the website are created using MinGW32 configured
|
||||
as a cross-compiler running under Linux. For details, see the ./publish.sh
|
||||
script at the top-level of the source tree.
|
||||
|
||||
Contacts:
|
||||
|
||||
http://www.sqlite.org/
|
||||
http://www.hwaci.com/sw/sqlite/
|
||||
http://groups.yahoo.com/group/sqlite/
|
||||
drh@hwaci.com
|
|
@ -0,0 +1,31 @@
|
|||
|
||||
This is a CVS pull from 2004.10.05 (has to be CVS since a few bug
|
||||
fixes we need went in past 3.0.7). Note that THIS SUCKS: qe'll want
|
||||
to pick a release version, probably 3.0.8, and stick with that, as
|
||||
soon as it's out.
|
||||
|
||||
See http://www.sqlite.org/ for more info.
|
||||
|
||||
We have a mozilla-specific Makefile.in in src/ (normally no
|
||||
Makefile.in there) that we use to build.
|
||||
|
||||
There's also a hand-written config.h in src; the only thing
|
||||
sqlite wants there is SQLITE_PTR_SZ, which we define to be
|
||||
PR_BYTES_PER_WORD.
|
||||
|
||||
We only imported the bits that we actually need for the build --
|
||||
basically, the contents of the src directory, plus autogenerated files
|
||||
(see below). Note that we don't use all the files in the src dir,
|
||||
but we import *.c *.h *.in for simplicity.
|
||||
|
||||
To move to a new version:
|
||||
|
||||
Update VERSION in src/Makefile.in
|
||||
|
||||
Update opcodes.c, opcodes.h, parse.c, parse.h, all of which are
|
||||
normally generated as part of the sqlite build. Pull these out of the
|
||||
sqlite3 windows source .zip, or autoconfiscate and build a tarball and
|
||||
copy them out. Yes, this sucks, but it's better than having to build
|
||||
the parser and all that goop as part of our build.
|
||||
|
||||
-- Vlad Vukicevic <vladimir@pobox.com> 10/2004
|
|
@ -0,0 +1,94 @@
|
|||
#
|
||||
# ***** BEGIN LICENSE BLOCK *****
|
||||
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
#
|
||||
# The contents of this file are subject to the Mozilla Public License Version
|
||||
# 1.1 (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
# http://www.mozilla.org/MPL/
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS IS" basis,
|
||||
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
# for the specific language governing rights and limitations under the
|
||||
# License.
|
||||
#
|
||||
# The Initial Developer of the Original Code is
|
||||
# Oracle Corporation
|
||||
# Portions created by the Initial Developer are Copyright (C) 2004
|
||||
# the Initial Developer. All Rights Reserved.
|
||||
#
|
||||
# Contributor(s):
|
||||
# Vladimir Vukicevic <vladimir.vukicevic@oracle.com>
|
||||
#
|
||||
# Alternatively, the contents of this file may be used under the terms of
|
||||
# either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
# or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
# in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
# of those above. If you wish to allow use of your version of this file only
|
||||
# under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
# use your version of this file under the terms of the MPL, indicate your
|
||||
# decision by deleting the provisions above and replace them with the notice
|
||||
# and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
# the provisions above, a recipient may use your version of this file under
|
||||
# the terms of any one of the MPL, the GPL or the LGPL.
|
||||
#
|
||||
# ***** END LICENSE BLOCK *****
|
||||
|
||||
DEPTH = ../../..
|
||||
topsrcdir = @top_srcdir@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
MODULE = sqlite3
|
||||
LIBRARY_NAME = sqlite3_s
|
||||
MODULE_NAME = sqlite3
|
||||
FORCE_STATIC_LIB = 1
|
||||
|
||||
VERSION = 3.0.7+041005
|
||||
|
||||
EXPORTS = sqlite3.h
|
||||
|
||||
CSRCS = \
|
||||
attach.c \
|
||||
auth.c \
|
||||
btree.c \
|
||||
build.c \
|
||||
date.c \
|
||||
delete.c \
|
||||
expr.c \
|
||||
func.c \
|
||||
hash.c \
|
||||
insert.c \
|
||||
legacy.c \
|
||||
main.c \
|
||||
opcodes.c \
|
||||
os_mac.c \
|
||||
os_test.c \
|
||||
os_unix.c \
|
||||
os_win.c \
|
||||
pager.c \
|
||||
parse.c \
|
||||
pragma.c \
|
||||
printf.c \
|
||||
random.c \
|
||||
select.c \
|
||||
table.c \
|
||||
tokenize.c \
|
||||
trigger.c \
|
||||
update.c \
|
||||
utf.c \
|
||||
util.c \
|
||||
vacuum.c \
|
||||
vdbe.c \
|
||||
vdbeapi.c \
|
||||
vdbeaux.c \
|
||||
vdbemem.c \
|
||||
where.c \
|
||||
$(NULL)
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
sqlite3.h: sqlite.h.in
|
||||
sed -e "s/--VERS--/$VERSION/" $(srcdir)/sqlite.h.in > sqlite3.h
|
|
@ -0,0 +1,329 @@
|
|||
/*
|
||||
** 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.28 2004/09/06 17:24:12 drh 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 sqlite3Attach(
|
||||
Parse *pParse, /* The parser context */
|
||||
Token *pFilename, /* Name of database file */
|
||||
Token *pDbname, /* Name of the database to use internally */
|
||||
int keyType, /* 0: no key. 1: TEXT, 2: BLOB */
|
||||
Token *pKey /* Text of the key for keytype 1 and 2 */
|
||||
){
|
||||
Db *aNew;
|
||||
int rc, i;
|
||||
char *zFile, *zName;
|
||||
sqlite3 *db;
|
||||
Vdbe *v;
|
||||
|
||||
v = sqlite3GetVdbe(pParse);
|
||||
if( !v ) return;
|
||||
sqlite3VdbeAddOp(v, OP_Halt, 0, 0);
|
||||
if( pParse->explain ) return;
|
||||
db = pParse->db;
|
||||
if( db->nDb>=MAX_ATTACHED+2 ){
|
||||
sqlite3ErrorMsg(pParse, "too many attached databases - max %d",
|
||||
MAX_ATTACHED);
|
||||
pParse->rc = SQLITE_ERROR;
|
||||
return;
|
||||
}
|
||||
|
||||
if( !db->autoCommit ){
|
||||
sqlite3ErrorMsg(pParse, "cannot ATTACH database within transaction");
|
||||
pParse->rc = SQLITE_ERROR;
|
||||
return;
|
||||
}
|
||||
|
||||
zFile = sqlite3NameFromToken(pFilename);;
|
||||
if( zFile==0 ) return;
|
||||
#ifndef SQLITE_OMIT_AUTHORIZATION
|
||||
if( sqlite3AuthCheck(pParse, SQLITE_ATTACH, zFile, 0, 0)!=SQLITE_OK ){
|
||||
sqliteFree(zFile);
|
||||
return;
|
||||
}
|
||||
#endif /* SQLITE_OMIT_AUTHORIZATION */
|
||||
|
||||
zName = sqlite3NameFromToken(pDbname);
|
||||
if( zName==0 ) return;
|
||||
for(i=0; i<db->nDb; i++){
|
||||
char *z = db->aDb[i].zName;
|
||||
if( z && sqlite3StrICmp(z, zName)==0 ){
|
||||
sqlite3ErrorMsg(pParse, "database %z is already in use", zName);
|
||||
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));
|
||||
sqlite3HashInit(&aNew->tblHash, SQLITE_HASH_STRING, 0);
|
||||
sqlite3HashInit(&aNew->idxHash, SQLITE_HASH_STRING, 0);
|
||||
sqlite3HashInit(&aNew->trigHash, SQLITE_HASH_STRING, 0);
|
||||
sqlite3HashInit(&aNew->aFKey, SQLITE_HASH_STRING, 1);
|
||||
aNew->zName = zName;
|
||||
aNew->safety_level = 3;
|
||||
rc = sqlite3BtreeFactory(db, zFile, 0, MAX_PAGES, &aNew->pBt);
|
||||
if( rc ){
|
||||
sqlite3ErrorMsg(pParse, "unable to open database: %s", zFile);
|
||||
}
|
||||
#if SQLITE_HAS_CODEC
|
||||
{
|
||||
extern int sqlite3CodecAttach(sqlite3*, int, void*, int);
|
||||
char *zKey;
|
||||
int nKey;
|
||||
if( keyType==0 ){
|
||||
/* No key specified. Use the key from the main database */
|
||||
extern void sqlite3CodecGetKey(sqlite3*, int, void**, int*);
|
||||
sqlite3CodecGetKey(db, 0, (void**)&zKey, &nKey);
|
||||
}else if( keyType==1 ){
|
||||
/* Key specified as text */
|
||||
zKey = sqlite3NameFromToken(pKey);
|
||||
nKey = strlen(zKey);
|
||||
}else{
|
||||
/* Key specified as a BLOB */
|
||||
char *zTemp;
|
||||
assert( keyType==2 );
|
||||
pKey->z++;
|
||||
pKey->n--;
|
||||
zTemp = sqlite3NameFromToken(pKey);
|
||||
zKey = sqlite3HexToBlob(zTemp);
|
||||
sqliteFree(zTemp);
|
||||
}
|
||||
sqlite3CodecAttach(db, db->nDb-1, zKey, nKey);
|
||||
if( keyType ){
|
||||
sqliteFree(zKey);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
sqliteFree(zFile);
|
||||
db->flags &= ~SQLITE_Initialized;
|
||||
if( pParse->nErr==0 && rc==SQLITE_OK ){
|
||||
rc = sqlite3ReadSchema(pParse);
|
||||
}
|
||||
if( rc ){
|
||||
int i = db->nDb - 1;
|
||||
assert( i>=2 );
|
||||
if( db->aDb[i].pBt ){
|
||||
sqlite3BtreeClose(db->aDb[i].pBt);
|
||||
db->aDb[i].pBt = 0;
|
||||
}
|
||||
sqlite3ResetInternalSchema(db, 0);
|
||||
if( 0==pParse->nErr ){
|
||||
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 sqlite3Detach(Parse *pParse, Token *pDbname){
|
||||
int i;
|
||||
sqlite3 *db;
|
||||
Vdbe *v;
|
||||
Db *pDb = 0;
|
||||
|
||||
v = sqlite3GetVdbe(pParse);
|
||||
if( !v ) return;
|
||||
sqlite3VdbeAddOp(v, OP_Halt, 0, 0);
|
||||
if( pParse->explain ) return;
|
||||
db = pParse->db;
|
||||
for(i=0; i<db->nDb; i++){
|
||||
pDb = &db->aDb[i];
|
||||
if( pDb->pBt==0 || pDb->zName==0 ) continue;
|
||||
if( strlen(pDb->zName)!=pDbname->n ) continue;
|
||||
if( sqlite3StrNICmp(pDb->zName, pDbname->z, pDbname->n)==0 ) break;
|
||||
}
|
||||
if( i>=db->nDb ){
|
||||
sqlite3ErrorMsg(pParse, "no such database: %T", pDbname);
|
||||
return;
|
||||
}
|
||||
if( i<2 ){
|
||||
sqlite3ErrorMsg(pParse, "cannot detach database %T", pDbname);
|
||||
return;
|
||||
}
|
||||
if( !db->autoCommit ){
|
||||
sqlite3ErrorMsg(pParse, "cannot DETACH database within transaction");
|
||||
pParse->rc = SQLITE_ERROR;
|
||||
return;
|
||||
}
|
||||
#ifndef SQLITE_OMIT_AUTHORIZATION
|
||||
if( sqlite3AuthCheck(pParse,SQLITE_DETACH,db->aDb[i].zName,0,0)!=SQLITE_OK ){
|
||||
return;
|
||||
}
|
||||
#endif /* SQLITE_OMIT_AUTHORIZATION */
|
||||
sqlite3BtreeClose(pDb->pBt);
|
||||
pDb->pBt = 0;
|
||||
sqlite3ResetInternalSchema(db, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
** Initialize a DbFixer structure. This routine must be called prior
|
||||
** to passing the structure to one of the sqliteFixAAAA() routines below.
|
||||
**
|
||||
** The return value indicates whether or not fixation is required. TRUE
|
||||
** means we do need to fix the database references, FALSE means we do not.
|
||||
*/
|
||||
int sqlite3FixInit(
|
||||
DbFixer *pFix, /* The fixer to be initialized */
|
||||
Parse *pParse, /* Error messages will be written here */
|
||||
int iDb, /* This is the database that must be used */
|
||||
const char *zType, /* "view", "trigger", or "index" */
|
||||
const Token *pName /* Name of the view, trigger, or index */
|
||||
){
|
||||
sqlite3 *db;
|
||||
|
||||
if( iDb<0 || iDb==1 ) return 0;
|
||||
db = pParse->db;
|
||||
assert( db->nDb>iDb );
|
||||
pFix->pParse = pParse;
|
||||
pFix->zDb = db->aDb[iDb].zName;
|
||||
pFix->zType = zType;
|
||||
pFix->pName = pName;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
** The following set of routines walk through the parse tree and assign
|
||||
** a specific database to all table references where the database name
|
||||
** was left unspecified in the original SQL statement. The pFix structure
|
||||
** must have been initialized by a prior call to sqlite3FixInit().
|
||||
**
|
||||
** These routines are used to make sure that an index, trigger, or
|
||||
** view in one database does not refer to objects in a different database.
|
||||
** (Exception: indices, triggers, and views in the TEMP database are
|
||||
** allowed to refer to anything.) If a reference is explicitly made
|
||||
** to an object in a different database, an error message is added to
|
||||
** pParse->zErrMsg and these routines return non-zero. If everything
|
||||
** checks out, these routines return 0.
|
||||
*/
|
||||
int sqlite3FixSrcList(
|
||||
DbFixer *pFix, /* Context of the fixation */
|
||||
SrcList *pList /* The Source list to check and modify */
|
||||
){
|
||||
int i;
|
||||
const char *zDb;
|
||||
struct SrcList_item *pItem;
|
||||
|
||||
if( pList==0 ) return 0;
|
||||
zDb = pFix->zDb;
|
||||
for(i=0, pItem=pList->a; i<pList->nSrc; i++, pItem++){
|
||||
if( pItem->zDatabase==0 ){
|
||||
pItem->zDatabase = sqliteStrDup(zDb);
|
||||
}else if( sqlite3StrICmp(pItem->zDatabase,zDb)!=0 ){
|
||||
sqlite3ErrorMsg(pFix->pParse,
|
||||
"%s %T cannot reference objects in database %s",
|
||||
pFix->zType, pFix->pName, pItem->zDatabase);
|
||||
return 1;
|
||||
}
|
||||
if( sqlite3FixSelect(pFix, pItem->pSelect) ) return 1;
|
||||
if( sqlite3FixExpr(pFix, pItem->pOn) ) return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
int sqlite3FixSelect(
|
||||
DbFixer *pFix, /* Context of the fixation */
|
||||
Select *pSelect /* The SELECT statement to be fixed to one database */
|
||||
){
|
||||
while( pSelect ){
|
||||
if( sqlite3FixExprList(pFix, pSelect->pEList) ){
|
||||
return 1;
|
||||
}
|
||||
if( sqlite3FixSrcList(pFix, pSelect->pSrc) ){
|
||||
return 1;
|
||||
}
|
||||
if( sqlite3FixExpr(pFix, pSelect->pWhere) ){
|
||||
return 1;
|
||||
}
|
||||
if( sqlite3FixExpr(pFix, pSelect->pHaving) ){
|
||||
return 1;
|
||||
}
|
||||
pSelect = pSelect->pPrior;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
int sqlite3FixExpr(
|
||||
DbFixer *pFix, /* Context of the fixation */
|
||||
Expr *pExpr /* The expression to be fixed to one database */
|
||||
){
|
||||
while( pExpr ){
|
||||
if( sqlite3FixSelect(pFix, pExpr->pSelect) ){
|
||||
return 1;
|
||||
}
|
||||
if( sqlite3FixExprList(pFix, pExpr->pList) ){
|
||||
return 1;
|
||||
}
|
||||
if( sqlite3FixExpr(pFix, pExpr->pRight) ){
|
||||
return 1;
|
||||
}
|
||||
pExpr = pExpr->pLeft;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
int sqlite3FixExprList(
|
||||
DbFixer *pFix, /* Context of the fixation */
|
||||
ExprList *pList /* The expression to be fixed to one database */
|
||||
){
|
||||
int i;
|
||||
struct ExprList_item *pItem;
|
||||
if( pList==0 ) return 0;
|
||||
for(i=0, pItem=pList->a; i<pList->nExpr; i++, pItem++){
|
||||
if( sqlite3FixExpr(pFix, pItem->pExpr) ){
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
int sqlite3FixTriggerStep(
|
||||
DbFixer *pFix, /* Context of the fixation */
|
||||
TriggerStep *pStep /* The trigger step be fixed to one database */
|
||||
){
|
||||
while( pStep ){
|
||||
if( sqlite3FixSelect(pFix, pStep->pSelect) ){
|
||||
return 1;
|
||||
}
|
||||
if( sqlite3FixExpr(pFix, pStep->pWhere) ){
|
||||
return 1;
|
||||
}
|
||||
if( sqlite3FixExprList(pFix, pStep->pExprList) ){
|
||||
return 1;
|
||||
}
|
||||
pStep = pStep->pNext;
|
||||
}
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,223 @@
|
|||
/*
|
||||
** 2003 January 11
|
||||
**
|
||||
** The author disclaims copyright to this source code. In place of
|
||||
** a legal notice, here is a blessing:
|
||||
**
|
||||
** May you do good and not evil.
|
||||
** May you find forgiveness for yourself and forgive others.
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
*************************************************************************
|
||||
** This file contains code used to implement the sqlite3_set_authorizer()
|
||||
** API. This facility is an optional feature of the library. Embedded
|
||||
** systems that do not need this facility may omit it by recompiling
|
||||
** the library with -DSQLITE_OMIT_AUTHORIZATION=1
|
||||
**
|
||||
** $Id: auth.c,v 1.19 2004/09/30 13:43:13 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
|
||||
/*
|
||||
** All of the code in this file may be omitted by defining a single
|
||||
** macro.
|
||||
*/
|
||||
#ifndef SQLITE_OMIT_AUTHORIZATION
|
||||
|
||||
/*
|
||||
** Set or clear the access authorization function.
|
||||
**
|
||||
** The access authorization function is be called during the compilation
|
||||
** phase to verify that the user has read and/or write access permission on
|
||||
** various fields of the database. The first argument to the auth function
|
||||
** is a copy of the 3rd argument to this routine. The second argument
|
||||
** to the auth function is one of these constants:
|
||||
**
|
||||
** SQLITE_CREATE_INDEX
|
||||
** SQLITE_CREATE_TABLE
|
||||
** SQLITE_CREATE_TEMP_INDEX
|
||||
** SQLITE_CREATE_TEMP_TABLE
|
||||
** SQLITE_CREATE_TEMP_TRIGGER
|
||||
** SQLITE_CREATE_TEMP_VIEW
|
||||
** SQLITE_CREATE_TRIGGER
|
||||
** SQLITE_CREATE_VIEW
|
||||
** SQLITE_DELETE
|
||||
** SQLITE_DROP_INDEX
|
||||
** SQLITE_DROP_TABLE
|
||||
** SQLITE_DROP_TEMP_INDEX
|
||||
** SQLITE_DROP_TEMP_TABLE
|
||||
** SQLITE_DROP_TEMP_TRIGGER
|
||||
** SQLITE_DROP_TEMP_VIEW
|
||||
** SQLITE_DROP_TRIGGER
|
||||
** SQLITE_DROP_VIEW
|
||||
** SQLITE_INSERT
|
||||
** SQLITE_PRAGMA
|
||||
** SQLITE_READ
|
||||
** SQLITE_SELECT
|
||||
** SQLITE_TRANSACTION
|
||||
** SQLITE_UPDATE
|
||||
**
|
||||
** The third and fourth arguments to the auth function are the name of
|
||||
** the table and the column that are being accessed. The auth function
|
||||
** should return either SQLITE_OK, SQLITE_DENY, or SQLITE_IGNORE. If
|
||||
** SQLITE_OK is returned, it means that access is allowed. SQLITE_DENY
|
||||
** means that the SQL statement will never-run - the sqlite3_exec() call
|
||||
** will return with an error. SQLITE_IGNORE means that the SQL statement
|
||||
** should run but attempts to read the specified column will return NULL
|
||||
** and attempts to write the column will be ignored.
|
||||
**
|
||||
** Setting the auth function to NULL disables this hook. The default
|
||||
** setting of the auth function is NULL.
|
||||
*/
|
||||
int sqlite3_set_authorizer(
|
||||
sqlite3 *db,
|
||||
int (*xAuth)(void*,int,const char*,const char*,const char*,const char*),
|
||||
void *pArg
|
||||
){
|
||||
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){
|
||||
sqlite3ErrorMsg(pParse, "illegal return value (%d) from the "
|
||||
"authorization function - should be SQLITE_OK, SQLITE_IGNORE, "
|
||||
"or SQLITE_DENY", rc);
|
||||
pParse->rc = SQLITE_ERROR;
|
||||
}
|
||||
|
||||
/*
|
||||
** The pExpr should be a TK_COLUMN expression. The table referred to
|
||||
** is in pTabList or else it is the NEW or OLD table of a trigger.
|
||||
** Check to see if it is OK to read this particular column.
|
||||
**
|
||||
** If the auth function returns SQLITE_IGNORE, change the TK_COLUMN
|
||||
** instruction into a TK_NULL. If the auth function returns SQLITE_DENY,
|
||||
** then generate an error.
|
||||
*/
|
||||
void sqlite3AuthRead(
|
||||
Parse *pParse, /* The parser context */
|
||||
Expr *pExpr, /* The expression to check authorization on */
|
||||
SrcList *pTabList /* All table that pExpr might refer to */
|
||||
){
|
||||
sqlite3 *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 */
|
||||
TriggerStack *pStack; /* The stack of current triggers */
|
||||
|
||||
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 if( (pStack = pParse->trigStack)!=0 ){
|
||||
/* This must be an attempt to read the NEW or OLD pseudo-tables
|
||||
** of a trigger.
|
||||
*/
|
||||
assert( pExpr->iTable==pStack->newIdx || pExpr->iTable==pStack->oldIdx );
|
||||
pTab = pStack->pTab;
|
||||
}else{
|
||||
return;
|
||||
}
|
||||
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 ){
|
||||
sqlite3ErrorMsg(pParse, "access to %s.%s.%s is prohibited",
|
||||
zDBase, pTab->zName, zCol);
|
||||
}else{
|
||||
sqlite3ErrorMsg(pParse, "access to %s.%s is prohibited",pTab->zName,zCol);
|
||||
}
|
||||
pParse->rc = SQLITE_AUTH;
|
||||
}else if( rc!=SQLITE_OK ){
|
||||
sqliteAuthBadReturnCode(pParse, rc);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Do an authorization check using the code and arguments given. Return
|
||||
** either SQLITE_OK (zero) or SQLITE_IGNORE or SQLITE_DENY. If SQLITE_DENY
|
||||
** is returned, then the error count and error message in pParse are
|
||||
** modified appropriately.
|
||||
*/
|
||||
int sqlite3AuthCheck(
|
||||
Parse *pParse,
|
||||
int code,
|
||||
const char *zArg1,
|
||||
const char *zArg2,
|
||||
const char *zArg3
|
||||
){
|
||||
sqlite3 *db = pParse->db;
|
||||
int rc;
|
||||
|
||||
/* Don't do any authorization checks if the database is initialising. */
|
||||
if( db->init.busy ){
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
if( db->xAuth==0 ){
|
||||
return SQLITE_OK;
|
||||
}
|
||||
rc = db->xAuth(db->pAuthArg, code, zArg1, zArg2, zArg3, pParse->zAuthContext);
|
||||
if( rc==SQLITE_DENY ){
|
||||
sqlite3ErrorMsg(pParse, "not authorized");
|
||||
pParse->rc = SQLITE_AUTH;
|
||||
}else if( rc!=SQLITE_OK && rc!=SQLITE_IGNORE ){
|
||||
rc = SQLITE_DENY;
|
||||
sqliteAuthBadReturnCode(pParse, rc);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Push an authorization context. After this routine is called, the
|
||||
** zArg3 argument to authorization callbacks will be zContext until
|
||||
** popped. Or if pParse==0, this routine is a no-op.
|
||||
*/
|
||||
void sqlite3AuthContextPush(
|
||||
Parse *pParse,
|
||||
AuthContext *pContext,
|
||||
const char *zContext
|
||||
){
|
||||
pContext->pParse = pParse;
|
||||
if( pParse ){
|
||||
pContext->zAuthContext = pParse->zAuthContext;
|
||||
pParse->zAuthContext = zContext;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Pop an authorization context that was previously pushed
|
||||
** by sqlite3AuthContextPush
|
||||
*/
|
||||
void sqlite3AuthContextPop(AuthContext *pContext){
|
||||
if( pContext->pParse ){
|
||||
pContext->pParse->zAuthContext = pContext->zAuthContext;
|
||||
pContext->pParse = 0;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* SQLITE_OMIT_AUTHORIZATION */
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,124 @@
|
|||
/*
|
||||
** 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.58 2004/07/23 00:01:39 drh Exp $
|
||||
*/
|
||||
#ifndef _BTREE_H_
|
||||
#define _BTREE_H_
|
||||
|
||||
/* TODO: This definition is just included so other modules compile. It
|
||||
** needs to be revisited.
|
||||
*/
|
||||
#define SQLITE_N_BTREE_META 10
|
||||
|
||||
/*
|
||||
** Forward declarations of structure
|
||||
*/
|
||||
typedef struct Btree Btree;
|
||||
typedef struct BtCursor BtCursor;
|
||||
|
||||
|
||||
int sqlite3BtreeOpen(
|
||||
const char *zFilename, /* Name of database file to open */
|
||||
Btree **, /* Return open Btree* here */
|
||||
int flags /* Flags */
|
||||
);
|
||||
|
||||
/* The flags parameter to sqlite3BtreeOpen can be the bitwise or of the
|
||||
** following values.
|
||||
*/
|
||||
#define BTREE_OMIT_JOURNAL 1 /* Do not use journal. No argument */
|
||||
#define BTREE_MEMORY 2 /* In-memory DB. No argument */
|
||||
|
||||
int sqlite3BtreeClose(Btree*);
|
||||
int sqlite3BtreeSetBusyHandler(Btree*,BusyHandler*);
|
||||
int sqlite3BtreeSetCacheSize(Btree*,int);
|
||||
int sqlite3BtreeSetSafetyLevel(Btree*,int);
|
||||
int sqlite3BtreeSetPageSize(Btree*,int,int);
|
||||
int sqlite3BtreeGetPageSize(Btree*);
|
||||
int sqlite3BtreeGetReserve(Btree*);
|
||||
int sqlite3BtreeBeginTrans(Btree*,int);
|
||||
int sqlite3BtreeCommit(Btree*);
|
||||
int sqlite3BtreeRollback(Btree*);
|
||||
int sqlite3BtreeBeginStmt(Btree*);
|
||||
int sqlite3BtreeCommitStmt(Btree*);
|
||||
int sqlite3BtreeRollbackStmt(Btree*);
|
||||
int sqlite3BtreeCreateTable(Btree*, int*, int flags);
|
||||
int sqlite3BtreeIsInTrans(Btree*);
|
||||
int sqlite3BtreeIsInStmt(Btree*);
|
||||
int sqlite3BtreeSync(Btree*, const char *zMaster);
|
||||
|
||||
const char *sqlite3BtreeGetFilename(Btree *);
|
||||
const char *sqlite3BtreeGetDirname(Btree *);
|
||||
const char *sqlite3BtreeGetJournalname(Btree *);
|
||||
int sqlite3BtreeCopyFile(Btree *, Btree *);
|
||||
|
||||
/* The flags parameter to sqlite3BtreeCreateTable can be the bitwise OR
|
||||
** of the following flags:
|
||||
*/
|
||||
#define BTREE_INTKEY 1 /* Table has only 64-bit signed integer keys */
|
||||
#define BTREE_ZERODATA 2 /* Table has keys only - no data */
|
||||
#define BTREE_LEAFDATA 4 /* Data stored in leaves only. Implies INTKEY */
|
||||
|
||||
int sqlite3BtreeDropTable(Btree*, int);
|
||||
int sqlite3BtreeClearTable(Btree*, int);
|
||||
int sqlite3BtreeGetMeta(Btree*, int idx, u32 *pValue);
|
||||
int sqlite3BtreeUpdateMeta(Btree*, int idx, u32 value);
|
||||
|
||||
int sqlite3BtreeCursor(
|
||||
Btree*, /* BTree containing table to open */
|
||||
int iTable, /* Index of root page */
|
||||
int wrFlag, /* 1 for writing. 0 for read-only */
|
||||
int(*)(void*,int,const void*,int,const void*), /* Key comparison function */
|
||||
void*, /* First argument to compare function */
|
||||
BtCursor **ppCursor /* Returned cursor */
|
||||
);
|
||||
|
||||
void sqlite3BtreeSetCompare(
|
||||
BtCursor *,
|
||||
int(*)(void*,int,const void*,int,const void*),
|
||||
void*
|
||||
);
|
||||
|
||||
int sqlite3BtreeCloseCursor(BtCursor*);
|
||||
int sqlite3BtreeMoveto(BtCursor*, const void *pKey, i64 nKey, int *pRes);
|
||||
int sqlite3BtreeDelete(BtCursor*);
|
||||
int sqlite3BtreeInsert(BtCursor*, const void *pKey, i64 nKey,
|
||||
const void *pData, int nData);
|
||||
int sqlite3BtreeFirst(BtCursor*, int *pRes);
|
||||
int sqlite3BtreeLast(BtCursor*, int *pRes);
|
||||
int sqlite3BtreeNext(BtCursor*, int *pRes);
|
||||
int sqlite3BtreeEof(BtCursor*);
|
||||
int sqlite3BtreeFlags(BtCursor*);
|
||||
int sqlite3BtreePrevious(BtCursor*, int *pRes);
|
||||
int sqlite3BtreeKeySize(BtCursor*, i64 *pSize);
|
||||
int sqlite3BtreeKey(BtCursor*, u32 offset, u32 amt, void*);
|
||||
const void *sqlite3BtreeKeyFetch(BtCursor*, int *pAmt);
|
||||
const void *sqlite3BtreeDataFetch(BtCursor*, int *pAmt);
|
||||
int sqlite3BtreeDataSize(BtCursor*, u32 *pSize);
|
||||
int sqlite3BtreeData(BtCursor*, u32 offset, u32 amt, void*);
|
||||
|
||||
char *sqlite3BtreeIntegrityCheck(Btree*, int *aRoot, int nRoot);
|
||||
struct Pager *sqlite3BtreePager(Btree*);
|
||||
|
||||
|
||||
#ifdef SQLITE_TEST
|
||||
int sqlite3BtreeCursorInfo(BtCursor*, int*, int);
|
||||
void sqlite3BtreeCursorList(Btree*);
|
||||
int sqlite3BtreePageDump(Btree*, int, int recursive);
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* _BTREE_H_ */
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,9 @@
|
|||
|
||||
#ifndef _sqlite3_config_h
|
||||
#define _sqlite3_config_h
|
||||
|
||||
#include "prcpucfg.h"
|
||||
|
||||
#define SQLITE_PTR_SZ PR_BYTES_PER_WORD
|
||||
|
||||
#endif /* _sqlite3_config_h */
|
|
@ -0,0 +1,893 @@
|
|||
/*
|
||||
** 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
|
||||
** sqlite3RegisterDateTimeFunctions() found at the bottom of the file.
|
||||
** All other code has file scope.
|
||||
**
|
||||
** $Id: date.c,v 1.36 2004/10/01 02:00:31 drh 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 "sqliteInt.h"
|
||||
#include "os.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(*(u8*)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 = sqlite3AtoF(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(*(u8*)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(*(u8*)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((u8)zDate[1]) ){
|
||||
double rScale = 1.0;
|
||||
zDate++;
|
||||
while( isdigit(*(u8*)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(*(u8*)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( sqlite3StrICmp(zDate,"now")==0){
|
||||
double r;
|
||||
if( sqlite3OsCurrentTime(&r)==0 ){
|
||||
p->rJD = r;
|
||||
p->validJD = 1;
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}else if( sqlite3IsNumber(zDate, 0, SQLITE_UTF8) ){
|
||||
p->rJD = sqlite3AtoF(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;
|
||||
sqlite3OsEnterMutex();
|
||||
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;
|
||||
sqlite3OsLeaveMutex();
|
||||
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 occurrence 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(*(u8*)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(*(u8*)z) ) 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, sqlite3_value **argv, DateTime *p){
|
||||
int i;
|
||||
if( argc==0 ) return 1;
|
||||
if( SQLITE_NULL==sqlite3_value_type(argv[0]) ||
|
||||
parseDateOrTime(sqlite3_value_text(argv[0]), p) ) return 1;
|
||||
for(i=1; i<argc; i++){
|
||||
if( SQLITE_NULL==sqlite3_value_type(argv[i]) ||
|
||||
parseModifier(sqlite3_value_text(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(
|
||||
sqlite3_context *context,
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
DateTime x;
|
||||
if( isDate(argc, argv, &x)==0 ){
|
||||
computeJD(&x);
|
||||
sqlite3_result_double(context, x.rJD);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** datetime( TIMESTRING, MOD, MOD, ...)
|
||||
**
|
||||
** Return YYYY-MM-DD HH:MM:SS
|
||||
*/
|
||||
static void datetimeFunc(
|
||||
sqlite3_context *context,
|
||||
int argc,
|
||||
sqlite3_value **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));
|
||||
sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** time( TIMESTRING, MOD, MOD, ...)
|
||||
**
|
||||
** Return HH:MM:SS
|
||||
*/
|
||||
static void timeFunc(
|
||||
sqlite3_context *context,
|
||||
int argc,
|
||||
sqlite3_value **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);
|
||||
sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** date( TIMESTRING, MOD, MOD, ...)
|
||||
**
|
||||
** Return YYYY-MM-DD
|
||||
*/
|
||||
static void dateFunc(
|
||||
sqlite3_context *context,
|
||||
int argc,
|
||||
sqlite3_value **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);
|
||||
sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** 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(
|
||||
sqlite3_context *context,
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
DateTime x;
|
||||
int n, i, j;
|
||||
char *z;
|
||||
const char *zFmt = sqlite3_value_text(argv[0]);
|
||||
char zBuf[100];
|
||||
if( zFmt==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; /* Number of days since 1st day of year */
|
||||
DateTime y = x;
|
||||
y.validJD = 0;
|
||||
y.M = 1;
|
||||
y.D = 1;
|
||||
computeJD(&y);
|
||||
n = x.rJD - y.rJD;
|
||||
if( zFmt[i]=='W' ){
|
||||
int wd; /* 0=Monday, 1=Tuesday, ... 6=Sunday */
|
||||
wd = ((int)(x.rJD+0.5)) % 7;
|
||||
sprintf(&z[j],"%02d",(n+7-wd)/7);
|
||||
j += 2;
|
||||
}else{
|
||||
sprintf(&z[j],"%03d",n+1);
|
||||
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;
|
||||
sqlite3_result_text(context, z, -1, SQLITE_TRANSIENT);
|
||||
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 sqlite3RegisterDateTimeFunctions(sqlite3 *db){
|
||||
#ifndef SQLITE_OMIT_DATETIME_FUNCS
|
||||
static struct {
|
||||
char *zName;
|
||||
int nArg;
|
||||
void (*xFunc)(sqlite3_context*,int,sqlite3_value**);
|
||||
} aFuncs[] = {
|
||||
{ "julianday", -1, juliandayFunc },
|
||||
{ "date", -1, dateFunc },
|
||||
{ "time", -1, timeFunc },
|
||||
{ "datetime", -1, datetimeFunc },
|
||||
{ "strftime", -1, strftimeFunc },
|
||||
};
|
||||
int i;
|
||||
|
||||
for(i=0; i<sizeof(aFuncs)/sizeof(aFuncs[0]); i++){
|
||||
sqlite3_create_function(db, aFuncs[i].zName, aFuncs[i].nArg,
|
||||
SQLITE_UTF8, 0, aFuncs[i].xFunc, 0, 0);
|
||||
}
|
||||
#endif
|
||||
}
|
|
@ -0,0 +1,419 @@
|
|||
/*
|
||||
** 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.82 2004/10/05 02:41:42 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
|
||||
/*
|
||||
** Look up every table that is named in pSrc. If any table is not found,
|
||||
** add an error message to pParse->zErrMsg and return NULL. If all tables
|
||||
** are found, return a pointer to the last table.
|
||||
*/
|
||||
Table *sqlite3SrcListLookup(Parse *pParse, SrcList *pSrc){
|
||||
Table *pTab = 0;
|
||||
int i;
|
||||
struct SrcList_item *pItem;
|
||||
for(i=0, pItem=pSrc->a; i<pSrc->nSrc; i++, pItem++){
|
||||
pTab = sqlite3LocateTable(pParse, pItem->zName, pItem->zDatabase);
|
||||
pItem->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 sqlite3IsReadOnly(Parse *pParse, Table *pTab, int viewOk){
|
||||
if( pTab->readOnly ){
|
||||
sqlite3ErrorMsg(pParse, "table %s may not be modified", pTab->zName);
|
||||
return 1;
|
||||
}
|
||||
if( !viewOk && pTab->pSelect ){
|
||||
sqlite3ErrorMsg(pParse,"cannot modify %s because it is a view",pTab->zName);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Generate code that will open a table for reading.
|
||||
*/
|
||||
void sqlite3OpenTableForReading(
|
||||
Vdbe *v, /* Generate code into this VDBE */
|
||||
int iCur, /* The cursor number of the table */
|
||||
Table *pTab /* The table to be opened */
|
||||
){
|
||||
sqlite3VdbeAddOp(v, OP_Integer, pTab->iDb, 0);
|
||||
sqlite3VdbeAddOp(v, OP_OpenRead, iCur, pTab->tnum);
|
||||
VdbeComment((v, "# %s", pTab->zName));
|
||||
sqlite3VdbeAddOp(v, OP_SetNumColumns, iCur, pTab->nCol);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Process a DELETE FROM statement.
|
||||
*/
|
||||
void sqlite3DeleteFrom(
|
||||
Parse *pParse, /* The parser context */
|
||||
SrcList *pTabList, /* The table from which we should delete things */
|
||||
Expr *pWhere /* The WHERE clause. May be null */
|
||||
){
|
||||
Vdbe *v; /* The virtual database engine */
|
||||
Table *pTab; /* The table from which records will be deleted */
|
||||
const char *zDb; /* Name of database holding pTab */
|
||||
int end, addr = 0; /* A couple addresses of generated code */
|
||||
int i; /* Loop counter */
|
||||
WhereInfo *pWInfo; /* Information about the WHERE clause */
|
||||
Index *pIdx; /* For looping over indices of the table */
|
||||
int iCur; /* VDBE Cursor number for pTab */
|
||||
sqlite3 *db; /* Main database structure */
|
||||
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 || sqlite3_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 = sqlite3SrcListLookup(pParse, pTabList);
|
||||
if( pTab==0 ) goto delete_from_cleanup;
|
||||
before_triggers = sqlite3TriggersExist(pParse, pTab->pTrigger,
|
||||
TK_DELETE, TK_BEFORE, TK_ROW, 0);
|
||||
after_triggers = sqlite3TriggersExist(pParse, pTab->pTrigger,
|
||||
TK_DELETE, TK_AFTER, TK_ROW, 0);
|
||||
row_triggers_exist = before_triggers || after_triggers;
|
||||
isView = pTab->pSelect!=0;
|
||||
if( sqlite3IsReadOnly(pParse, pTab, before_triggers) ){
|
||||
goto delete_from_cleanup;
|
||||
}
|
||||
assert( pTab->iDb<db->nDb );
|
||||
zDb = db->aDb[pTab->iDb].zName;
|
||||
if( sqlite3AuthCheck(pParse, SQLITE_DELETE, pTab->zName, 0, zDb) ){
|
||||
goto delete_from_cleanup;
|
||||
}
|
||||
|
||||
/* If pTab is really a view, make sure it has been initialized.
|
||||
*/
|
||||
if( isView && sqlite3ViewGetColumnNames(pParse, pTab) ){
|
||||
goto delete_from_cleanup;
|
||||
}
|
||||
|
||||
/* Allocate a cursor used to store the old.* data for a trigger.
|
||||
*/
|
||||
if( 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( sqlite3ExprResolveAndCheck(pParse, pTabList, 0, pWhere, 0, 0) ){
|
||||
goto delete_from_cleanup;
|
||||
}
|
||||
|
||||
/* Start the view context
|
||||
*/
|
||||
if( isView ){
|
||||
sqlite3AuthContextPush(pParse, &sContext, pTab->zName);
|
||||
}
|
||||
|
||||
/* Begin generating code.
|
||||
*/
|
||||
v = sqlite3GetVdbe(pParse);
|
||||
if( v==0 ){
|
||||
goto delete_from_cleanup;
|
||||
}
|
||||
sqlite3VdbeCountChanges(v);
|
||||
sqlite3BeginWriteOperation(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 = sqlite3SelectDup(pTab->pSelect);
|
||||
sqlite3Select(pParse, pView, SRT_TempTable, iCur, 0, 0, 0, 0);
|
||||
sqlite3SelectDelete(pView);
|
||||
}
|
||||
|
||||
/* Initialize the counter of the number of rows deleted, if
|
||||
** we are counting rows.
|
||||
*/
|
||||
if( db->flags & SQLITE_CountRows ){
|
||||
sqlite3VdbeAddOp(v, OP_Integer, 0, 0);
|
||||
}
|
||||
|
||||
/* Special case: A DELETE without a WHERE clause deletes everything.
|
||||
** It is easier just to erase the whole table. Note, however, that
|
||||
** this means that the row change count will be incorrect.
|
||||
*/
|
||||
if( pWhere==0 && !row_triggers_exist ){
|
||||
if( db->flags & SQLITE_CountRows ){
|
||||
/* If counting rows deleted, just count the total number of
|
||||
** entries in the table. */
|
||||
int endOfLoop = sqlite3VdbeMakeLabel(v);
|
||||
int addr;
|
||||
if( !isView ){
|
||||
sqlite3OpenTableForReading(v, iCur, pTab);
|
||||
}
|
||||
sqlite3VdbeAddOp(v, OP_Rewind, iCur, sqlite3VdbeCurrentAddr(v)+2);
|
||||
addr = sqlite3VdbeAddOp(v, OP_AddImm, 1, 0);
|
||||
sqlite3VdbeAddOp(v, OP_Next, iCur, addr);
|
||||
sqlite3VdbeResolveLabel(v, endOfLoop);
|
||||
sqlite3VdbeAddOp(v, OP_Close, iCur, 0);
|
||||
}
|
||||
if( !isView ){
|
||||
sqlite3VdbeAddOp(v, OP_Clear, pTab->tnum, pTab->iDb);
|
||||
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
|
||||
sqlite3VdbeAddOp(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{
|
||||
/* Ensure all required collation sequences are available. */
|
||||
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
|
||||
if( sqlite3CheckIndexCollSeq(pParse, pIdx) ){
|
||||
goto delete_from_cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
/* Begin the database scan
|
||||
*/
|
||||
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 1, 0);
|
||||
if( pWInfo==0 ) goto delete_from_cleanup;
|
||||
|
||||
/* Remember the key of every item to be deleted.
|
||||
*/
|
||||
sqlite3VdbeAddOp(v, OP_ListWrite, 0, 0);
|
||||
if( db->flags & SQLITE_CountRows ){
|
||||
sqlite3VdbeAddOp(v, OP_AddImm, 1, 0);
|
||||
}
|
||||
|
||||
/* End the database scan loop.
|
||||
*/
|
||||
sqlite3WhereEnd(pWInfo);
|
||||
|
||||
/* Open the pseudo-table used to store OLD if there are triggers.
|
||||
*/
|
||||
if( row_triggers_exist ){
|
||||
sqlite3VdbeAddOp(v, OP_OpenPseudo, oldIdx, 0);
|
||||
sqlite3VdbeAddOp(v, OP_SetNumColumns, oldIdx, pTab->nCol);
|
||||
}
|
||||
|
||||
/* Delete every item whose key was written to the list during the
|
||||
** database scan. We have to delete items after the scan is complete
|
||||
** because deleting an item can change the scan order.
|
||||
*/
|
||||
sqlite3VdbeAddOp(v, OP_ListRewind, 0, 0);
|
||||
end = sqlite3VdbeMakeLabel(v);
|
||||
|
||||
/* This is the beginning of the delete loop when there are
|
||||
** row triggers.
|
||||
*/
|
||||
if( row_triggers_exist ){
|
||||
addr = sqlite3VdbeAddOp(v, OP_ListRead, 0, end);
|
||||
sqlite3VdbeAddOp(v, OP_Dup, 0, 0);
|
||||
if( !isView ){
|
||||
sqlite3OpenTableForReading(v, iCur, pTab);
|
||||
}
|
||||
sqlite3VdbeAddOp(v, OP_MoveGe, iCur, 0);
|
||||
sqlite3VdbeAddOp(v, OP_Recno, iCur, 0);
|
||||
sqlite3VdbeAddOp(v, OP_RowData, iCur, 0);
|
||||
sqlite3VdbeAddOp(v, OP_PutIntKey, oldIdx, 0);
|
||||
if( !isView ){
|
||||
sqlite3VdbeAddOp(v, OP_Close, iCur, 0);
|
||||
}
|
||||
|
||||
sqlite3CodeRowTrigger(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.
|
||||
*/
|
||||
sqlite3OpenTableAndIndices(pParse, pTab, iCur, OP_OpenWrite);
|
||||
|
||||
/* This is the beginning of the delete loop when there are no
|
||||
** row triggers */
|
||||
if( !row_triggers_exist ){
|
||||
addr = sqlite3VdbeAddOp(v, OP_ListRead, 0, end);
|
||||
}
|
||||
|
||||
/* Delete the row */
|
||||
sqlite3GenerateRowDelete(db, v, pTab, iCur, 1);
|
||||
}
|
||||
|
||||
/* 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){
|
||||
sqlite3VdbeAddOp(v, OP_Close, iCur + i, pIdx->tnum);
|
||||
}
|
||||
sqlite3VdbeAddOp(v, OP_Close, iCur, 0);
|
||||
}
|
||||
sqlite3CodeRowTrigger(pParse, TK_DELETE, 0, TK_AFTER, pTab, -1,
|
||||
oldIdx, (pParse->trigStack)?pParse->trigStack->orconf:OE_Default,
|
||||
addr);
|
||||
}
|
||||
|
||||
/* End of the delete loop */
|
||||
sqlite3VdbeAddOp(v, OP_Goto, 0, addr);
|
||||
sqlite3VdbeResolveLabel(v, end);
|
||||
sqlite3VdbeAddOp(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){
|
||||
sqlite3VdbeAddOp(v, OP_Close, iCur + i, pIdx->tnum);
|
||||
}
|
||||
sqlite3VdbeAddOp(v, OP_Close, iCur, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the number of rows that were deleted.
|
||||
*/
|
||||
if( db->flags & SQLITE_CountRows ){
|
||||
sqlite3VdbeAddOp(v, OP_Callback, 1, 0);
|
||||
sqlite3VdbeSetNumCols(v, 1);
|
||||
sqlite3VdbeSetColName(v, 0, "rows deleted", P3_STATIC);
|
||||
}
|
||||
|
||||
delete_from_cleanup:
|
||||
sqlite3AuthContextPop(&sContext);
|
||||
sqlite3SrcListDelete(pTabList);
|
||||
sqlite3ExprDelete(pWhere);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
** This routine generates VDBE code that causes a single row of a
|
||||
** single table to be deleted.
|
||||
**
|
||||
** The VDBE must be in a particular state when this routine is called.
|
||||
** These are the requirements:
|
||||
**
|
||||
** 1. A read/write cursor pointing to pTab, the table containing the row
|
||||
** to be deleted, must be opened as cursor number "base".
|
||||
**
|
||||
** 2. Read/write cursors for all indices of pTab must be open as
|
||||
** cursor number base+i for the i-th index.
|
||||
**
|
||||
** 3. The record number of the row to be deleted must be on the top
|
||||
** of the stack.
|
||||
**
|
||||
** This routine pops the top of the stack to remove the record number
|
||||
** and then generates code to remove both the table record and all index
|
||||
** entries that point to that record.
|
||||
*/
|
||||
void sqlite3GenerateRowDelete(
|
||||
sqlite3 *db, /* The database containing the index */
|
||||
Vdbe *v, /* Generate code into this VDBE */
|
||||
Table *pTab, /* Table containing the row to be deleted */
|
||||
int iCur, /* Cursor number for the table */
|
||||
int count /* Increment the row change counter */
|
||||
){
|
||||
int addr;
|
||||
addr = sqlite3VdbeAddOp(v, OP_NotExists, iCur, 0);
|
||||
sqlite3GenerateRowIndexDelete(db, v, pTab, iCur, 0);
|
||||
sqlite3VdbeAddOp(v, OP_Delete, iCur, (count?OPFLAG_NCHANGE:0));
|
||||
sqlite3VdbeChangeP2(v, addr, sqlite3VdbeCurrentAddr(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 sqlite3GenerateRowIndexDelete(
|
||||
sqlite3 *db, /* The database containing the index */
|
||||
Vdbe *v, /* Generate code into this VDBE */
|
||||
Table *pTab, /* Table containing the row to be deleted */
|
||||
int iCur, /* Cursor number for the table */
|
||||
char *aIdxUsed /* Only delete if aIdxUsed!=0 && aIdxUsed[i]!=0 */
|
||||
){
|
||||
int i;
|
||||
Index *pIdx;
|
||||
|
||||
for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
|
||||
if( aIdxUsed!=0 && aIdxUsed[i-1]==0 ) continue;
|
||||
sqlite3GenerateIndexKey(v, pIdx, iCur);
|
||||
sqlite3VdbeAddOp(v, OP_IdxDelete, iCur+i, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Generate code that will assemble an index key and put it on the top
|
||||
** of the tack. The key with be for index pIdx which is an index on pTab.
|
||||
** iCur is the index of a cursor open on the pTab table and pointing to
|
||||
** the entry that needs indexing.
|
||||
*/
|
||||
void sqlite3GenerateIndexKey(
|
||||
Vdbe *v, /* Generate code into this VDBE */
|
||||
Index *pIdx, /* The index for which to generate a key */
|
||||
int iCur /* Cursor number for the pIdx->pTable table */
|
||||
){
|
||||
int j;
|
||||
Table *pTab = pIdx->pTable;
|
||||
|
||||
sqlite3VdbeAddOp(v, OP_Recno, iCur, 0);
|
||||
for(j=0; j<pIdx->nColumn; j++){
|
||||
int idx = pIdx->aiColumn[j];
|
||||
if( idx==pTab->iPKey ){
|
||||
sqlite3VdbeAddOp(v, OP_Dup, j, 0);
|
||||
}else{
|
||||
sqlite3VdbeAddOp(v, OP_Column, iCur, idx);
|
||||
}
|
||||
}
|
||||
sqlite3VdbeAddOp(v, OP_MakeRecord, pIdx->nColumn, (1<<24));
|
||||
sqlite3IndexAffinityStr(v, pIdx);
|
||||
}
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,380 @@
|
|||
/*
|
||||
** 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.15 2004/08/20 14:08:51 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include <assert.h>
|
||||
|
||||
/* Turn bulk memory into a hash table object by initializing the
|
||||
** fields of the Hash structure.
|
||||
**
|
||||
** "pNew" is a pointer to the hash table that is to be initialized.
|
||||
** keyClass is one of the constants SQLITE_HASH_INT, SQLITE_HASH_POINTER,
|
||||
** SQLITE_HASH_BINARY, or SQLITE_HASH_STRING. The value of keyClass
|
||||
** determines what kind of key the hash table will use. "copyKey" is
|
||||
** true if the hash table should make its own private copy of keys and
|
||||
** false if it should just use the supplied pointer. CopyKey only makes
|
||||
** sense for SQLITE_HASH_STRING and SQLITE_HASH_BINARY and is ignored
|
||||
** for other key classes.
|
||||
*/
|
||||
void sqlite3HashInit(Hash *pNew, int keyClass, int copyKey){
|
||||
assert( pNew!=0 );
|
||||
assert( keyClass>=SQLITE_HASH_STRING && keyClass<=SQLITE_HASH_BINARY );
|
||||
pNew->keyClass = keyClass;
|
||||
#if 0
|
||||
if( keyClass==SQLITE_HASH_POINTER || keyClass==SQLITE_HASH_INT ) copyKey = 0;
|
||||
#endif
|
||||
pNew->copyKey = copyKey;
|
||||
pNew->first = 0;
|
||||
pNew->count = 0;
|
||||
pNew->htsize = 0;
|
||||
pNew->ht = 0;
|
||||
}
|
||||
|
||||
/* Remove all entries from a hash table. Reclaim all memory.
|
||||
** Call this routine to delete a hash table or to reset a hash table
|
||||
** to the empty state.
|
||||
*/
|
||||
void sqlite3HashClear(Hash *pH){
|
||||
HashElem *elem; /* For looping over all elements of the table */
|
||||
|
||||
assert( pH!=0 );
|
||||
elem = pH->first;
|
||||
pH->first = 0;
|
||||
if( pH->ht ) 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;
|
||||
}
|
||||
|
||||
#if 0 /* NOT USED */
|
||||
/*
|
||||
** Hash and comparison functions when the mode is SQLITE_HASH_INT
|
||||
*/
|
||||
static int intHash(const void *pKey, int nKey){
|
||||
return nKey ^ (nKey<<8) ^ (nKey>>8);
|
||||
}
|
||||
static int intCompare(const void *pKey1, int n1, const void *pKey2, int n2){
|
||||
return n2 - n1;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 0 /* NOT USED */
|
||||
/*
|
||||
** Hash and comparison functions when the mode is SQLITE_HASH_POINTER
|
||||
*/
|
||||
static int ptrHash(const void *pKey, int nKey){
|
||||
uptr x = Addr(pKey);
|
||||
return x ^ (x<<8) ^ (x>>8);
|
||||
}
|
||||
static int ptrCompare(const void *pKey1, int n1, const void *pKey2, int n2){
|
||||
if( pKey1==pKey2 ) return 0;
|
||||
if( pKey1<pKey2 ) return -1;
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Hash and comparison functions when the mode is SQLITE_HASH_STRING
|
||||
*/
|
||||
static int strHash(const void *pKey, int nKey){
|
||||
return sqlite3HashNoCase((const char*)pKey, nKey);
|
||||
}
|
||||
static int strCompare(const void *pKey1, int n1, const void *pKey2, int n2){
|
||||
if( n1!=n2 ) return 1;
|
||||
return sqlite3StrNICmp((const char*)pKey1,(const char*)pKey2,n1);
|
||||
}
|
||||
|
||||
/*
|
||||
** Hash and comparison functions when the mode is SQLITE_HASH_BINARY
|
||||
*/
|
||||
static int binHash(const void *pKey, int nKey){
|
||||
int h = 0;
|
||||
const char *z = (const char *)pKey;
|
||||
while( nKey-- > 0 ){
|
||||
h = (h<<3) ^ h ^ *(z++);
|
||||
}
|
||||
return h & 0x7fffffff;
|
||||
}
|
||||
static int binCompare(const void *pKey1, int n1, const void *pKey2, int n2){
|
||||
if( n1!=n2 ) return 1;
|
||||
return memcmp(pKey1,pKey2,n1);
|
||||
}
|
||||
|
||||
/*
|
||||
** Return a pointer to the appropriate hash function given the key class.
|
||||
**
|
||||
** The C syntax in this function definition may be unfamilar to some
|
||||
** programmers, so we provide the following additional explanation:
|
||||
**
|
||||
** The name of the function is "hashFunction". The function takes a
|
||||
** single parameter "keyClass". The return value of hashFunction()
|
||||
** is a pointer to another function. Specifically, the return value
|
||||
** of hashFunction() is a pointer to a function that takes two parameters
|
||||
** with types "const void*" and "int" and returns an "int".
|
||||
*/
|
||||
static int (*hashFunction(int keyClass))(const void*,int){
|
||||
#if 0 /* HASH_INT and HASH_POINTER are never used */
|
||||
switch( keyClass ){
|
||||
case SQLITE_HASH_INT: return &intHash;
|
||||
case SQLITE_HASH_POINTER: return &ptrHash;
|
||||
case SQLITE_HASH_STRING: return &strHash;
|
||||
case SQLITE_HASH_BINARY: return &binHash;;
|
||||
default: break;
|
||||
}
|
||||
return 0;
|
||||
#else
|
||||
if( keyClass==SQLITE_HASH_STRING ){
|
||||
return &strHash;
|
||||
}else{
|
||||
assert( keyClass==SQLITE_HASH_BINARY );
|
||||
return &binHash;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
** Return a pointer to the appropriate hash function given the key class.
|
||||
**
|
||||
** For help in interpreted the obscure C code in the function definition,
|
||||
** see the header comment on the previous function.
|
||||
*/
|
||||
static int (*compareFunction(int keyClass))(const void*,int,const void*,int){
|
||||
#if 0 /* HASH_INT and HASH_POINTER are never used */
|
||||
switch( keyClass ){
|
||||
case SQLITE_HASH_INT: return &intCompare;
|
||||
case SQLITE_HASH_POINTER: return &ptrCompare;
|
||||
case SQLITE_HASH_STRING: return &strCompare;
|
||||
case SQLITE_HASH_BINARY: return &binCompare;
|
||||
default: break;
|
||||
}
|
||||
return 0;
|
||||
#else
|
||||
if( keyClass==SQLITE_HASH_STRING ){
|
||||
return &strCompare;
|
||||
}else{
|
||||
assert( keyClass==SQLITE_HASH_BINARY );
|
||||
return &binCompare;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Link an element into the hash table
|
||||
*/
|
||||
static void insertElement(
|
||||
Hash *pH, /* The complete hash table */
|
||||
struct _ht *pEntry, /* The entry into which pNew is inserted */
|
||||
HashElem *pNew /* The element to be inserted */
|
||||
){
|
||||
HashElem *pHead; /* First element already in pEntry */
|
||||
pHead = pEntry->chain;
|
||||
if( pHead ){
|
||||
pNew->next = pHead;
|
||||
pNew->prev = pHead->prev;
|
||||
if( pHead->prev ){ pHead->prev->next = pNew; }
|
||||
else { pH->first = pNew; }
|
||||
pHead->prev = pNew;
|
||||
}else{
|
||||
pNew->next = pH->first;
|
||||
if( pH->first ){ pH->first->prev = pNew; }
|
||||
pNew->prev = 0;
|
||||
pH->first = pNew;
|
||||
}
|
||||
pEntry->count++;
|
||||
pEntry->chain = pNew;
|
||||
}
|
||||
|
||||
|
||||
/* Resize the hash table so that it cantains "new_size" buckets.
|
||||
** "new_size" must be a power of 2. The hash table might fail
|
||||
** to resize if 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 */
|
||||
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;
|
||||
insertElement(pH, &new_ht[h], elem);
|
||||
}
|
||||
}
|
||||
|
||||
/* This function (for internal use only) locates an element in an
|
||||
** hash table that matches the given key. The hash for this key has
|
||||
** already been computed and is passed as the 4th parameter.
|
||||
*/
|
||||
static HashElem *findElementGivenHash(
|
||||
const Hash *pH, /* The pH to be searched */
|
||||
const void *pKey, /* The key we are searching for */
|
||||
int nKey,
|
||||
int h /* The hash for this key. */
|
||||
){
|
||||
HashElem *elem; /* Used to loop thru the element list */
|
||||
int count; /* Number of elements left to test */
|
||||
int (*xCompare)(const void*,int,const void*,int); /* comparison function */
|
||||
|
||||
if( pH->ht ){
|
||||
struct _ht *pEntry = &pH->ht[h];
|
||||
elem = pEntry->chain;
|
||||
count = pEntry->count;
|
||||
xCompare = compareFunction(pH->keyClass);
|
||||
while( count-- && elem ){
|
||||
if( (*xCompare)(elem->pKey,elem->nKey,pKey,nKey)==0 ){
|
||||
return elem;
|
||||
}
|
||||
elem = elem->next;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Remove a single entry from the hash table given a pointer to that
|
||||
** element and a hash on the element's key.
|
||||
*/
|
||||
static void removeElementGivenHash(
|
||||
Hash *pH, /* The pH containing "elem" */
|
||||
HashElem* elem, /* The element to be removed from the pH */
|
||||
int h /* Hash value for the element */
|
||||
){
|
||||
struct _ht *pEntry;
|
||||
if( elem->prev ){
|
||||
elem->prev->next = elem->next;
|
||||
}else{
|
||||
pH->first = elem->next;
|
||||
}
|
||||
if( elem->next ){
|
||||
elem->next->prev = elem->prev;
|
||||
}
|
||||
pEntry = &pH->ht[h];
|
||||
if( pEntry->chain==elem ){
|
||||
pEntry->chain = elem->next;
|
||||
}
|
||||
pEntry->count--;
|
||||
if( pEntry->count<=0 ){
|
||||
pEntry->chain = 0;
|
||||
}
|
||||
if( pH->copyKey && 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 *sqlite3HashFind(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 *sqlite3HashInsert(Hash *pH, const void *pKey, int nKey, void *data){
|
||||
int hraw; /* Raw hash value of the key */
|
||||
int h; /* the hash of the key modulo hash table size */
|
||||
HashElem *elem; /* Used to loop thru the element list */
|
||||
HashElem *new_elem; /* New element added to the pH */
|
||||
int (*xHash)(const void*,int); /* The hash function */
|
||||
|
||||
assert( pH!=0 );
|
||||
xHash = hashFunction(pH->keyClass);
|
||||
assert( xHash!=0 );
|
||||
hraw = (*xHash)(pKey, nKey);
|
||||
assert( (pH->htsize & (pH->htsize-1))==0 );
|
||||
h = hraw & (pH->htsize-1);
|
||||
elem = findElementGivenHash(pH,pKey,nKey,h);
|
||||
if( elem ){
|
||||
void *old_data = elem->data;
|
||||
if( data==0 ){
|
||||
removeElementGivenHash(pH,elem,h);
|
||||
}else{
|
||||
elem->data = data;
|
||||
}
|
||||
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>0 );
|
||||
assert( (pH->htsize & (pH->htsize-1))==0 );
|
||||
h = hraw & (pH->htsize-1);
|
||||
insertElement(pH, &pH->ht[h], new_elem);
|
||||
new_elem->data = data;
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,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.8 2004/08/20 14:08:51 drh 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 // NOT USED */
|
||||
/* #define SQLITE_HASH_POINTER 2 // NOT USED */
|
||||
#define SQLITE_HASH_STRING 3
|
||||
#define SQLITE_HASH_BINARY 4
|
||||
|
||||
/*
|
||||
** Access routines. To delete, insert a NULL pointer.
|
||||
*/
|
||||
void sqlite3HashInit(Hash*, int keytype, int copyKey);
|
||||
void *sqlite3HashInsert(Hash*, const void *pKey, int nKey, void *pData);
|
||||
void *sqlite3HashFind(const Hash*, const void *pKey, int nKey);
|
||||
void sqlite3HashClear(Hash*);
|
||||
|
||||
/*
|
||||
** Macros for looping over all elements of a hash table. The idiom is
|
||||
** like this:
|
||||
**
|
||||
** Hash h;
|
||||
** HashElem *p;
|
||||
** ...
|
||||
** for(p=sqliteHashFirst(&h); p; p=sqliteHashNext(p)){
|
||||
** SomeStructure *pData = sqliteHashData(p);
|
||||
** // do something with pData
|
||||
** }
|
||||
*/
|
||||
#define sqliteHashFirst(H) ((H)->first)
|
||||
#define sqliteHashNext(E) ((E)->next)
|
||||
#define sqliteHashData(E) ((E)->data)
|
||||
#define sqliteHashKey(E) ((E)->pKey)
|
||||
#define sqliteHashKeysize(E) ((E)->nKey)
|
||||
|
||||
/*
|
||||
** Number of entries in a hash table
|
||||
*/
|
||||
#define sqliteHashCount(H) ((H)->count)
|
||||
|
||||
#endif /* _SQLITE_HASH_H_ */
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,138 @@
|
|||
/*
|
||||
** 2001 September 15
|
||||
**
|
||||
** The author disclaims copyright to this source code. In place of
|
||||
** a legal notice, here is a blessing:
|
||||
**
|
||||
** May you do good and not evil.
|
||||
** May you find forgiveness for yourself and forgive others.
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
*************************************************************************
|
||||
** Main file for the SQLite library. The routines in this file
|
||||
** implement the programmer interface to the library. Routines in
|
||||
** other files are for internal use by SQLite and should not be
|
||||
** accessed by users of the library.
|
||||
**
|
||||
** $Id: legacy.c,v 1.7 2004/09/06 17:34:13 drh Exp $
|
||||
*/
|
||||
|
||||
#include "sqliteInt.h"
|
||||
#include "os.h"
|
||||
#include <ctype.h>
|
||||
|
||||
/*
|
||||
** Execute SQL code. Return one of the SQLITE_ success/failure
|
||||
** codes. Also write an error message into memory obtained from
|
||||
** malloc() and make *pzErrMsg point to that message.
|
||||
**
|
||||
** If the SQL is a query, then for each row in the query result
|
||||
** the xCallback() function is called. pArg becomes the first
|
||||
** argument to xCallback(). If xCallback=NULL then no callback
|
||||
** is invoked, even for queries.
|
||||
*/
|
||||
int sqlite3_exec(
|
||||
sqlite3 *db, /* The database on which the SQL executes */
|
||||
const char *zSql, /* The SQL to be executed */
|
||||
sqlite3_callback xCallback, /* Invoke this callback routine */
|
||||
void *pArg, /* First argument to xCallback() */
|
||||
char **pzErrMsg /* Write error messages here */
|
||||
){
|
||||
int rc = SQLITE_OK;
|
||||
const char *zLeftover;
|
||||
sqlite3_stmt *pStmt = 0;
|
||||
char **azCols = 0;
|
||||
|
||||
int nRetry = 0;
|
||||
int nChange = 0;
|
||||
int nCallback;
|
||||
|
||||
if( zSql==0 ) return SQLITE_OK;
|
||||
while( (rc==SQLITE_OK || (rc==SQLITE_SCHEMA && (++nRetry)<2)) && zSql[0] ){
|
||||
int nCol;
|
||||
char **azVals = 0;
|
||||
|
||||
pStmt = 0;
|
||||
rc = sqlite3_prepare(db, zSql, -1, &pStmt, &zLeftover);
|
||||
if( rc!=SQLITE_OK ){
|
||||
if( pStmt ) sqlite3_finalize(pStmt);
|
||||
continue;
|
||||
}
|
||||
if( !pStmt ){
|
||||
/* this happens for a comment or white-space */
|
||||
zSql = zLeftover;
|
||||
continue;
|
||||
}
|
||||
|
||||
db->nChange += nChange;
|
||||
nCallback = 0;
|
||||
|
||||
nCol = sqlite3_column_count(pStmt);
|
||||
azCols = sqliteMalloc(2*nCol*sizeof(const char *));
|
||||
if( nCol && !azCols ){
|
||||
rc = SQLITE_NOMEM;
|
||||
goto exec_out;
|
||||
}
|
||||
|
||||
while( 1 ){
|
||||
int i;
|
||||
rc = sqlite3_step(pStmt);
|
||||
|
||||
/* Invoke the callback function if required */
|
||||
if( xCallback && (SQLITE_ROW==rc ||
|
||||
(SQLITE_DONE==rc && !nCallback && db->flags&SQLITE_NullCallback)) ){
|
||||
if( 0==nCallback ){
|
||||
for(i=0; i<nCol; i++){
|
||||
azCols[i] = (char *)sqlite3_column_name(pStmt, i);
|
||||
}
|
||||
nCallback++;
|
||||
}
|
||||
if( rc==SQLITE_ROW ){
|
||||
azVals = &azCols[nCol];
|
||||
for(i=0; i<nCol; i++){
|
||||
azVals[i] = (char *)sqlite3_column_text(pStmt, i);
|
||||
}
|
||||
}
|
||||
if( xCallback(pArg, nCol, azVals, azCols) ){
|
||||
rc = SQLITE_ABORT;
|
||||
goto exec_out;
|
||||
}
|
||||
}
|
||||
|
||||
if( rc!=SQLITE_ROW ){
|
||||
rc = sqlite3_finalize(pStmt);
|
||||
pStmt = 0;
|
||||
if( db->pVdbe==0 ){
|
||||
nChange = db->nChange;
|
||||
}
|
||||
if( rc!=SQLITE_SCHEMA ){
|
||||
nRetry = 0;
|
||||
zSql = zLeftover;
|
||||
while( isspace((unsigned char)zSql[0]) ) zSql++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
sqliteFree(azCols);
|
||||
azCols = 0;
|
||||
}
|
||||
|
||||
exec_out:
|
||||
if( pStmt ) sqlite3_finalize(pStmt);
|
||||
if( azCols ) sqliteFree(azCols);
|
||||
|
||||
if( sqlite3_malloc_failed ){
|
||||
rc = SQLITE_NOMEM;
|
||||
}
|
||||
if( rc!=SQLITE_OK && rc==sqlite3_errcode(db) && pzErrMsg ){
|
||||
*pzErrMsg = malloc(1+strlen(sqlite3_errmsg(db)));
|
||||
if( *pzErrMsg ){
|
||||
strcpy(*pzErrMsg, sqlite3_errmsg(db));
|
||||
}
|
||||
}else if( pzErrMsg ){
|
||||
*pzErrMsg = 0;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,129 @@
|
|||
/* Automatically generated file. Do not edit */
|
||||
char *sqlite3OpcodeNames[] = { "???",
|
||||
"Goto",
|
||||
"Gosub",
|
||||
"Return",
|
||||
"Halt",
|
||||
"Integer",
|
||||
"Real",
|
||||
"String8",
|
||||
"String",
|
||||
"HexBlob",
|
||||
"Blob",
|
||||
"Variable",
|
||||
"Pop",
|
||||
"Dup",
|
||||
"Pull",
|
||||
"Push",
|
||||
"Callback",
|
||||
"Concat",
|
||||
"Add",
|
||||
"Subtract",
|
||||
"Multiply",
|
||||
"Divide",
|
||||
"Remainder",
|
||||
"CollSeq",
|
||||
"Function",
|
||||
"BitAnd",
|
||||
"BitOr",
|
||||
"ShiftLeft",
|
||||
"ShiftRight",
|
||||
"AddImm",
|
||||
"ForceInt",
|
||||
"MustBeInt",
|
||||
"Eq",
|
||||
"Ne",
|
||||
"Lt",
|
||||
"Le",
|
||||
"Gt",
|
||||
"Ge",
|
||||
"And",
|
||||
"Or",
|
||||
"Negative",
|
||||
"AbsValue",
|
||||
"Not",
|
||||
"BitNot",
|
||||
"Noop",
|
||||
"If",
|
||||
"IfNot",
|
||||
"IsNull",
|
||||
"NotNull",
|
||||
"SetNumColumns",
|
||||
"IdxColumn",
|
||||
"Column",
|
||||
"MakeRecord",
|
||||
"Statement",
|
||||
"AutoCommit",
|
||||
"Transaction",
|
||||
"ReadCookie",
|
||||
"SetCookie",
|
||||
"VerifyCookie",
|
||||
"OpenRead",
|
||||
"OpenWrite",
|
||||
"OpenTemp",
|
||||
"OpenPseudo",
|
||||
"Close",
|
||||
"MoveLt",
|
||||
"MoveLe",
|
||||
"MoveGe",
|
||||
"MoveGt",
|
||||
"Distinct",
|
||||
"NotFound",
|
||||
"Found",
|
||||
"IsUnique",
|
||||
"NotExists",
|
||||
"NewRecno",
|
||||
"PutIntKey",
|
||||
"PutStrKey",
|
||||
"Delete",
|
||||
"ResetCount",
|
||||
"KeyAsData",
|
||||
"RowKey",
|
||||
"RowData",
|
||||
"Recno",
|
||||
"FullKey",
|
||||
"NullRow",
|
||||
"Last",
|
||||
"Rewind",
|
||||
"Prev",
|
||||
"Next",
|
||||
"IdxPut",
|
||||
"IdxDelete",
|
||||
"IdxRecno",
|
||||
"IdxLT",
|
||||
"IdxGT",
|
||||
"IdxGE",
|
||||
"IdxIsNull",
|
||||
"Destroy",
|
||||
"Clear",
|
||||
"CreateIndex",
|
||||
"CreateTable",
|
||||
"ParseSchema",
|
||||
"DropTable",
|
||||
"DropIndex",
|
||||
"DropTrigger",
|
||||
"IntegrityCk",
|
||||
"ListWrite",
|
||||
"ListRewind",
|
||||
"ListRead",
|
||||
"ListReset",
|
||||
"ListPush",
|
||||
"ListPop",
|
||||
"ContextPush",
|
||||
"ContextPop",
|
||||
"SortPut",
|
||||
"Sort",
|
||||
"SortNext",
|
||||
"SortReset",
|
||||
"MemStore",
|
||||
"MemLoad",
|
||||
"MemIncr",
|
||||
"AggReset",
|
||||
"AggInit",
|
||||
"AggFunc",
|
||||
"AggFocus",
|
||||
"AggSet",
|
||||
"AggGet",
|
||||
"AggNext",
|
||||
"Vacuum",
|
||||
};
|
|
@ -0,0 +1,127 @@
|
|||
/* 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_Real 6
|
||||
#define OP_String8 7
|
||||
#define OP_String 8
|
||||
#define OP_HexBlob 9
|
||||
#define OP_Blob 10
|
||||
#define OP_Variable 11
|
||||
#define OP_Pop 12
|
||||
#define OP_Dup 13
|
||||
#define OP_Pull 14
|
||||
#define OP_Push 15
|
||||
#define OP_Callback 16
|
||||
#define OP_Concat 17
|
||||
#define OP_Add 18
|
||||
#define OP_Subtract 19
|
||||
#define OP_Multiply 20
|
||||
#define OP_Divide 21
|
||||
#define OP_Remainder 22
|
||||
#define OP_CollSeq 23
|
||||
#define OP_Function 24
|
||||
#define OP_BitAnd 25
|
||||
#define OP_BitOr 26
|
||||
#define OP_ShiftLeft 27
|
||||
#define OP_ShiftRight 28
|
||||
#define OP_AddImm 29
|
||||
#define OP_ForceInt 30
|
||||
#define OP_MustBeInt 31
|
||||
#define OP_Eq 32
|
||||
#define OP_Ne 33
|
||||
#define OP_Lt 34
|
||||
#define OP_Le 35
|
||||
#define OP_Gt 36
|
||||
#define OP_Ge 37
|
||||
#define OP_And 38
|
||||
#define OP_Or 39
|
||||
#define OP_Negative 40
|
||||
#define OP_AbsValue 41
|
||||
#define OP_Not 42
|
||||
#define OP_BitNot 43
|
||||
#define OP_Noop 44
|
||||
#define OP_If 45
|
||||
#define OP_IfNot 46
|
||||
#define OP_IsNull 47
|
||||
#define OP_NotNull 48
|
||||
#define OP_SetNumColumns 49
|
||||
#define OP_IdxColumn 50
|
||||
#define OP_Column 51
|
||||
#define OP_MakeRecord 52
|
||||
#define OP_Statement 53
|
||||
#define OP_AutoCommit 54
|
||||
#define OP_Transaction 55
|
||||
#define OP_ReadCookie 56
|
||||
#define OP_SetCookie 57
|
||||
#define OP_VerifyCookie 58
|
||||
#define OP_OpenRead 59
|
||||
#define OP_OpenWrite 60
|
||||
#define OP_OpenTemp 61
|
||||
#define OP_OpenPseudo 62
|
||||
#define OP_Close 63
|
||||
#define OP_MoveLt 64
|
||||
#define OP_MoveLe 65
|
||||
#define OP_MoveGe 66
|
||||
#define OP_MoveGt 67
|
||||
#define OP_Distinct 68
|
||||
#define OP_NotFound 69
|
||||
#define OP_Found 70
|
||||
#define OP_IsUnique 71
|
||||
#define OP_NotExists 72
|
||||
#define OP_NewRecno 73
|
||||
#define OP_PutIntKey 74
|
||||
#define OP_PutStrKey 75
|
||||
#define OP_Delete 76
|
||||
#define OP_ResetCount 77
|
||||
#define OP_KeyAsData 78
|
||||
#define OP_RowKey 79
|
||||
#define OP_RowData 80
|
||||
#define OP_Recno 81
|
||||
#define OP_FullKey 82
|
||||
#define OP_NullRow 83
|
||||
#define OP_Last 84
|
||||
#define OP_Rewind 85
|
||||
#define OP_Prev 86
|
||||
#define OP_Next 87
|
||||
#define OP_IdxPut 88
|
||||
#define OP_IdxDelete 89
|
||||
#define OP_IdxRecno 90
|
||||
#define OP_IdxLT 91
|
||||
#define OP_IdxGT 92
|
||||
#define OP_IdxGE 93
|
||||
#define OP_IdxIsNull 94
|
||||
#define OP_Destroy 95
|
||||
#define OP_Clear 96
|
||||
#define OP_CreateIndex 97
|
||||
#define OP_CreateTable 98
|
||||
#define OP_ParseSchema 99
|
||||
#define OP_DropTable 100
|
||||
#define OP_DropIndex 101
|
||||
#define OP_DropTrigger 102
|
||||
#define OP_IntegrityCk 103
|
||||
#define OP_ListWrite 104
|
||||
#define OP_ListRewind 105
|
||||
#define OP_ListRead 106
|
||||
#define OP_ListReset 107
|
||||
#define OP_ListPush 108
|
||||
#define OP_ListPop 109
|
||||
#define OP_ContextPush 110
|
||||
#define OP_ContextPop 111
|
||||
#define OP_SortPut 112
|
||||
#define OP_Sort 113
|
||||
#define OP_SortNext 114
|
||||
#define OP_SortReset 115
|
||||
#define OP_MemStore 116
|
||||
#define OP_MemLoad 117
|
||||
#define OP_MemIncr 118
|
||||
#define OP_AggReset 119
|
||||
#define OP_AggInit 120
|
||||
#define OP_AggFunc 121
|
||||
#define OP_AggFocus 122
|
||||
#define OP_AggSet 123
|
||||
#define OP_AggGet 124
|
||||
#define OP_AggNext 125
|
||||
#define OP_Vacuum 126
|
|
@ -0,0 +1,197 @@
|
|||
/*
|
||||
** 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_
|
||||
|
||||
/*
|
||||
** 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)
|
||||
*/
|
||||
#if !defined(OS_UNIX) && !defined(OS_TEST)
|
||||
# ifndef OS_WIN
|
||||
# ifndef OS_MAC
|
||||
# if defined(__MACOS__)
|
||||
# define OS_MAC 1
|
||||
# define OS_WIN 0
|
||||
# define OS_UNIX 0
|
||||
# elif defined(_WIN32) || defined(WIN32) || defined(__CYGWIN__) || defined(__MINGW32__) || defined(__BORLANDC__)
|
||||
# define OS_MAC 0
|
||||
# define OS_WIN 1
|
||||
# define OS_UNIX 0
|
||||
# else
|
||||
# define OS_MAC 0
|
||||
# define OS_WIN 0
|
||||
# define OS_UNIX 1
|
||||
# endif
|
||||
# else
|
||||
# define OS_WIN 0
|
||||
# define OS_UNIX 0
|
||||
# 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
|
||||
|
||||
/*
|
||||
** Invoke the appropriate operating-system specific header file.
|
||||
*/
|
||||
#if OS_TEST
|
||||
# include "os_test.h"
|
||||
#endif
|
||||
#if OS_UNIX
|
||||
# include "os_unix.h"
|
||||
#endif
|
||||
#if OS_WIN
|
||||
# include "os_win.h"
|
||||
#endif
|
||||
#if OS_MAC
|
||||
# include "os_mac.h"
|
||||
#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
|
||||
|
||||
/*
|
||||
** The following values may be passed as the second argument to
|
||||
** sqlite3OsLock(). The various locks exhibit the following semantics:
|
||||
**
|
||||
** SHARED: Any number of processes may hold a SHARED lock simultaneously.
|
||||
** RESERVED: A single process may hold a RESERVED lock on a file at
|
||||
** any time. Other processes may hold and obtain new SHARED locks.
|
||||
** PENDING: A single process may hold a PENDING lock on a file at
|
||||
** any one time. Existing SHARED locks may persist, but no new
|
||||
** SHARED locks may be obtained by other processes.
|
||||
** EXCLUSIVE: An EXCLUSIVE lock precludes all other locks.
|
||||
**
|
||||
** PENDING_LOCK may not be passed directly to sqlite3OsLock(). Instead, a
|
||||
** process that requests an EXCLUSIVE lock may actually obtain a PENDING
|
||||
** lock. This can be upgraded to an EXCLUSIVE lock by a subsequent call to
|
||||
** sqlite3OsLock().
|
||||
*/
|
||||
#define NO_LOCK 0
|
||||
#define SHARED_LOCK 1
|
||||
#define RESERVED_LOCK 2
|
||||
#define PENDING_LOCK 3
|
||||
#define EXCLUSIVE_LOCK 4
|
||||
|
||||
/*
|
||||
** File Locking Notes: (Mostly about windows but also some info for Unix)
|
||||
**
|
||||
** We cannot use LockFileEx() or UnlockFileEx() on Win95/98/ME because
|
||||
** those functions are not available. So we use only LockFile() and
|
||||
** UnlockFile().
|
||||
**
|
||||
** LockFile() prevents not just writing but also reading by other processes.
|
||||
** A SHARED_LOCK is obtained by locking a single randomly-chosen
|
||||
** byte out of a specific range of bytes. The lock byte is obtained at
|
||||
** random so two separate readers can probably access the file at the
|
||||
** same time, unless they are unlucky and choose the same lock byte.
|
||||
** An EXCLUSIVE_LOCK is obtained by locking all bytes in the range.
|
||||
** There can only be one writer. A RESERVED_LOCK is obtained by locking
|
||||
** a single byte of the file that is designated as the reserved lock byte.
|
||||
** A PENDING_LOCK is obtained by locking a designated byte different from
|
||||
** the RESERVED_LOCK byte.
|
||||
**
|
||||
** On WinNT/2K/XP systems, LockFileEx() and UnlockFileEx() are available,
|
||||
** which means we can use reader/writer locks. When reader/writer locks
|
||||
** are used, the lock is placed on the same range of bytes that is used
|
||||
** for probabilistic locking in Win95/98/ME. Hence, the locking scheme
|
||||
** will support two or more Win95 readers or two or more WinNT readers.
|
||||
** But a single Win95 reader will lock out all WinNT readers and a single
|
||||
** WinNT reader will lock out all other Win95 readers.
|
||||
**
|
||||
** The following #defines specify the range of bytes used for locking.
|
||||
** SHARED_SIZE is the number of bytes available in the pool from which
|
||||
** a random byte is selected for a shared lock. The pool of bytes for
|
||||
** shared locks begins at SHARED_FIRST.
|
||||
**
|
||||
** These #defines are available in os.h so that Unix can use the same
|
||||
** byte ranges for locking. This leaves open the possiblity of having
|
||||
** clients on win95, winNT, and unix all talking to the same shared file
|
||||
** and all locking correctly. To do so would require that samba (or whatever
|
||||
** tool is being used for file sharing) implements locks correctly between
|
||||
** windows and unix. I'm guessing that isn't likely to happen, but by
|
||||
** using the same locking range we are at least open to the possibility.
|
||||
**
|
||||
** Locking in windows is manditory. For this reason, we cannot store
|
||||
** actual data in the bytes used for locking. The pager never allocates
|
||||
** the pages involved in locking therefore. SHARED_SIZE is selected so
|
||||
** that all locks will fit on a single page even at the minimum page size.
|
||||
** PENDING_BYTE defines the beginning of the locks. By default PENDING_BYTE
|
||||
** is set high so that we don't have to allocate an unused page except
|
||||
** for very large databases. But one should test the page skipping logic
|
||||
** by setting PENDING_BYTE low and running the entire regression suite.
|
||||
**
|
||||
** Changing the value of PENDING_BYTE results in a subtly incompatible
|
||||
** file format. Depending on how it is changed, you might not notice
|
||||
** the incompatibility right away, even running a full regression test.
|
||||
** The default location of PENDING_BYTE is the first byte past the
|
||||
** 1GB boundary.
|
||||
**
|
||||
*/
|
||||
#define PENDING_BYTE 0x40000000 /* First byte past the 1GB boundary */
|
||||
/* #define PENDING_BYTE 0x5400 // Page 20 - for testing */
|
||||
#define RESERVED_BYTE (PENDING_BYTE+1)
|
||||
#define SHARED_FIRST (PENDING_BYTE+2)
|
||||
#define SHARED_SIZE 510
|
||||
|
||||
|
||||
int sqlite3OsDelete(const char*);
|
||||
int sqlite3OsFileExists(const char*);
|
||||
int sqlite3OsOpenReadWrite(const char*, OsFile*, int*);
|
||||
int sqlite3OsOpenExclusive(const char*, OsFile*, int);
|
||||
int sqlite3OsOpenReadOnly(const char*, OsFile*);
|
||||
int sqlite3OsOpenDirectory(const char*, OsFile*);
|
||||
int sqlite3OsSyncDirectory(const char*);
|
||||
int sqlite3OsTempFileName(char*);
|
||||
int sqlite3OsClose(OsFile*);
|
||||
int sqlite3OsRead(OsFile*, void*, int amt);
|
||||
int sqlite3OsWrite(OsFile*, const void*, int amt);
|
||||
int sqlite3OsSeek(OsFile*, i64 offset);
|
||||
int sqlite3OsSync(OsFile*);
|
||||
int sqlite3OsTruncate(OsFile*, i64 size);
|
||||
int sqlite3OsFileSize(OsFile*, i64 *pSize);
|
||||
int sqlite3OsRandomSeed(char*);
|
||||
int sqlite3OsSleep(int ms);
|
||||
int sqlite3OsCurrentTime(double*);
|
||||
int sqlite3OsFileModTime(OsFile*, double*);
|
||||
void sqlite3OsEnterMutex(void);
|
||||
void sqlite3OsLeaveMutex(void);
|
||||
char *sqlite3OsFullPathname(const char*);
|
||||
int sqlite3OsLock(OsFile*, int);
|
||||
int sqlite3OsUnlock(OsFile*, int);
|
||||
int sqlite3OsCheckReservedLock(OsFile *id);
|
||||
|
||||
#endif /* _SQLITE_OS_H_ */
|
|
@ -0,0 +1,107 @@
|
|||
/*
|
||||
** 2004 May 22
|
||||
**
|
||||
** The author disclaims copyright to this source code. In place of
|
||||
** a legal notice, here is a blessing:
|
||||
**
|
||||
** May you do good and not evil.
|
||||
** May you find forgiveness for yourself and forgive others.
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
******************************************************************************
|
||||
**
|
||||
** This file contains macros and a little bit of code that is common to
|
||||
** all of the platform-specific files (os_*.c) and is #included into those
|
||||
** files.
|
||||
**
|
||||
** This file should be #included by the os_*.c files only. It is not a
|
||||
** general purpose header file.
|
||||
*/
|
||||
|
||||
/*
|
||||
** At least two bugs have slipped in because we changed the MEMORY_DEBUG
|
||||
** macro to SQLITE_DEBUG and some older makefiles have not yet made the
|
||||
** switch. The following code should catch this problem at compile-time.
|
||||
*/
|
||||
#ifdef MEMORY_DEBUG
|
||||
# error "The MEMORY_DEBUG macro is obsolete. Use SQLITE_DEBUG instead."
|
||||
#endif
|
||||
|
||||
|
||||
int sqlite3_os_trace = 0;
|
||||
#ifdef SQLITE_DEBUG
|
||||
static int last_page = 0;
|
||||
#define SEEK(X) last_page=(X)
|
||||
#define TRACE1(X) if( sqlite3_os_trace ) sqlite3DebugPrintf(X)
|
||||
#define TRACE2(X,Y) if( sqlite3_os_trace ) sqlite3DebugPrintf(X,Y)
|
||||
#define TRACE3(X,Y,Z) if( sqlite3_os_trace ) sqlite3DebugPrintf(X,Y,Z)
|
||||
#define TRACE4(X,Y,Z,A) if( sqlite3_os_trace ) sqlite3DebugPrintf(X,Y,Z,A)
|
||||
#define TRACE5(X,Y,Z,A,B) if( sqlite3_os_trace ) sqlite3DebugPrintf(X,Y,Z,A,B)
|
||||
#define TRACE6(X,Y,Z,A,B,C) if(sqlite3_os_trace) sqlite3DebugPrintf(X,Y,Z,A,B,C)
|
||||
#define TRACE7(X,Y,Z,A,B,C,D) \
|
||||
if(sqlite3_os_trace) sqlite3DebugPrintf(X,Y,Z,A,B,C,D)
|
||||
#else
|
||||
#define SEEK(X)
|
||||
#define TRACE1(X)
|
||||
#define TRACE2(X,Y)
|
||||
#define TRACE3(X,Y,Z)
|
||||
#define TRACE4(X,Y,Z,A)
|
||||
#define TRACE5(X,Y,Z,A,B)
|
||||
#define TRACE6(X,Y,Z,A,B,C)
|
||||
#define TRACE7(X,Y,Z,A,B,C,D)
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Macros for performance tracing. Normally turned off. Only works
|
||||
** on i486 hardware.
|
||||
*/
|
||||
#ifdef SQLITE_PERFORMANCE_TRACE
|
||||
__inline__ unsigned long long int hwtime(void){
|
||||
unsigned long long int x;
|
||||
__asm__("rdtsc\n\t"
|
||||
"mov %%edx, %%ecx\n\t"
|
||||
:"=A" (x));
|
||||
return x;
|
||||
}
|
||||
static unsigned long long int g_start;
|
||||
static unsigned int elapse;
|
||||
#define TIMER_START g_start=hwtime()
|
||||
#define TIMER_END elapse=hwtime()-g_start
|
||||
#define TIMER_ELAPSED elapse
|
||||
#else
|
||||
#define TIMER_START
|
||||
#define TIMER_END
|
||||
#define TIMER_ELAPSED 0
|
||||
#endif
|
||||
|
||||
/*
|
||||
** If we compile with the SQLITE_TEST macro set, then the following block
|
||||
** of code will give us the ability to simulate a disk I/O error. This
|
||||
** is used for testing the I/O recovery logic.
|
||||
*/
|
||||
#ifdef SQLITE_TEST
|
||||
int sqlite3_io_error_pending = 0;
|
||||
int sqlite3_diskfull_pending = 0;
|
||||
#define SimulateIOError(A) \
|
||||
if( sqlite3_io_error_pending ) \
|
||||
if( sqlite3_io_error_pending-- == 1 ){ local_ioerr(); return A; }
|
||||
static void local_ioerr(){
|
||||
sqlite3_io_error_pending = 0; /* Really just a place to set a breakpoint */
|
||||
}
|
||||
#define SimulateDiskfullError \
|
||||
if( sqlite3_diskfull_pending ) \
|
||||
if( sqlite3_diskfull_pending-- == 1 ){ local_ioerr(); return SQLITE_FULL; }
|
||||
#else
|
||||
#define SimulateIOError(A)
|
||||
#define SimulateDiskfullError
|
||||
#endif
|
||||
|
||||
/*
|
||||
** When testing, keep a count of the number of open files.
|
||||
*/
|
||||
#ifdef SQLITE_TEST
|
||||
int sqlite3_open_file_count = 0;
|
||||
#define OpenCounter(X) sqlite3_open_file_count+=(X)
|
||||
#else
|
||||
#define OpenCounter(X)
|
||||
#endif
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,89 @@
|
|||
/*
|
||||
** 2004 May 22
|
||||
**
|
||||
** The author disclaims copyright to this source code. In place of
|
||||
** a legal notice, here is a blessing:
|
||||
**
|
||||
** May you do good and not evil.
|
||||
** May you find forgiveness for yourself and forgive others.
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
******************************************************************************
|
||||
**
|
||||
** This header file defined OS-specific features for Unix.
|
||||
*/
|
||||
#ifndef _SQLITE_OS_UNIX_H_
|
||||
#define _SQLITE_OS_UNIX_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
|
||||
|
||||
/*
|
||||
** standard include files.
|
||||
*/
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/*
|
||||
** The OsFile structure is a operating-system independing representation
|
||||
** of an open file handle. It is defined differently for each architecture.
|
||||
**
|
||||
** This is the definition for Unix.
|
||||
**
|
||||
** OsFile.locktype takes one of the values SHARED_LOCK, RESERVED_LOCK,
|
||||
** PENDING_LOCK or EXCLUSIVE_LOCK.
|
||||
*/
|
||||
typedef struct OsFile OsFile;
|
||||
struct OsFile {
|
||||
struct Pager *pPager; /* The pager that owns this OsFile. Might be 0 */
|
||||
struct openCnt *pOpen; /* Info about all open fd's on this inode */
|
||||
struct lockInfo *pLock; /* Info about locks on this inode */
|
||||
int h; /* The file descriptor */
|
||||
unsigned char locktype; /* The type of lock held on this fd */
|
||||
unsigned char isOpen; /* True if needs to be closed */
|
||||
int dirfd; /* File descriptor for the directory */
|
||||
};
|
||||
|
||||
/*
|
||||
** Maximum number of characters in a temporary file name
|
||||
*/
|
||||
#define SQLITE_TEMPNAME_SIZE 200
|
||||
|
||||
/*
|
||||
** Minimum interval supported by sqlite3OsSleep().
|
||||
*/
|
||||
#if defined(HAVE_USLEEP) && HAVE_USLEEP
|
||||
# define SQLITE_MIN_SLEEP_MS 1
|
||||
#else
|
||||
# define SQLITE_MIN_SLEEP_MS 1000
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* _SQLITE_OS_UNIX_H_ */
|
|
@ -0,0 +1,747 @@
|
|||
/*
|
||||
** 2004 May 22
|
||||
**
|
||||
** The author disclaims copyright to this source code. In place of
|
||||
** a legal notice, here is a blessing:
|
||||
**
|
||||
** May you do good and not evil.
|
||||
** May you find forgiveness for yourself and forgive others.
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
******************************************************************************
|
||||
**
|
||||
** This file contains code that is specific to windows.
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include "os.h"
|
||||
#if OS_WIN /* This file is used for windows only */
|
||||
|
||||
#include <winbase.h>
|
||||
|
||||
/*
|
||||
** Macros used to determine whether or not to use threads.
|
||||
*/
|
||||
#if defined(THREADSAFE) && THREADSAFE
|
||||
# define SQLITE_W32_THREADS 1
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Include code that is common to all os_*.c files
|
||||
*/
|
||||
#include "os_common.h"
|
||||
|
||||
/*
|
||||
** Delete the named file
|
||||
*/
|
||||
int sqlite3OsDelete(const char *zFilename){
|
||||
DeleteFileA(zFilename);
|
||||
TRACE2("DELETE \"%s\"\n", zFilename);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return TRUE if the named file exists.
|
||||
*/
|
||||
int sqlite3OsFileExists(const char *zFilename){
|
||||
return GetFileAttributesA(zFilename) != 0xffffffff;
|
||||
}
|
||||
|
||||
/*
|
||||
** Attempt to open a file for both reading and writing. If that
|
||||
** fails, try opening it read-only. If the file does not exist,
|
||||
** try to create it.
|
||||
**
|
||||
** On success, a handle for the open file is written to *id
|
||||
** and *pReadonly is set to 0 if the file was opened for reading and
|
||||
** writing or 1 if the file was opened read-only. The function returns
|
||||
** SQLITE_OK.
|
||||
**
|
||||
** On failure, the function returns SQLITE_CANTOPEN and leaves
|
||||
** *id and *pReadonly unchanged.
|
||||
*/
|
||||
int sqlite3OsOpenReadWrite(
|
||||
const char *zFilename,
|
||||
OsFile *id,
|
||||
int *pReadonly
|
||||
){
|
||||
HANDLE h;
|
||||
assert( !id->isOpen );
|
||||
h = CreateFileA(zFilename,
|
||||
GENERIC_READ | GENERIC_WRITE,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||
NULL,
|
||||
OPEN_ALWAYS,
|
||||
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS,
|
||||
NULL
|
||||
);
|
||||
if( h==INVALID_HANDLE_VALUE ){
|
||||
h = CreateFileA(zFilename,
|
||||
GENERIC_READ,
|
||||
FILE_SHARE_READ,
|
||||
NULL,
|
||||
OPEN_ALWAYS,
|
||||
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS,
|
||||
NULL
|
||||
);
|
||||
if( h==INVALID_HANDLE_VALUE ){
|
||||
return SQLITE_CANTOPEN;
|
||||
}
|
||||
*pReadonly = 1;
|
||||
}else{
|
||||
*pReadonly = 0;
|
||||
}
|
||||
id->h = h;
|
||||
id->locktype = NO_LOCK;
|
||||
id->sharedLockByte = 0;
|
||||
id->isOpen = 1;
|
||||
OpenCounter(+1);
|
||||
TRACE3("OPEN R/W %d \"%s\"\n", h, zFilename);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Attempt to open a new file for exclusive access by this process.
|
||||
** The file will be opened for both reading and writing. To avoid
|
||||
** a potential security problem, we do not allow the file to have
|
||||
** previously existed. Nor do we allow the file to be a symbolic
|
||||
** link.
|
||||
**
|
||||
** If delFlag is true, then make arrangements to automatically delete
|
||||
** the file when it is closed.
|
||||
**
|
||||
** On success, write the file handle into *id and return SQLITE_OK.
|
||||
**
|
||||
** On failure, return SQLITE_CANTOPEN.
|
||||
*/
|
||||
int sqlite3OsOpenExclusive(const char *zFilename, OsFile *id, int delFlag){
|
||||
HANDLE h;
|
||||
int fileflags;
|
||||
assert( !id->isOpen );
|
||||
if( delFlag ){
|
||||
fileflags = FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_RANDOM_ACCESS
|
||||
| FILE_FLAG_DELETE_ON_CLOSE;
|
||||
}else{
|
||||
fileflags = FILE_FLAG_RANDOM_ACCESS;
|
||||
}
|
||||
h = CreateFileA(zFilename,
|
||||
GENERIC_READ | GENERIC_WRITE,
|
||||
0,
|
||||
NULL,
|
||||
CREATE_ALWAYS,
|
||||
fileflags,
|
||||
NULL
|
||||
);
|
||||
if( h==INVALID_HANDLE_VALUE ){
|
||||
return SQLITE_CANTOPEN;
|
||||
}
|
||||
id->h = h;
|
||||
id->locktype = NO_LOCK;
|
||||
id->sharedLockByte = 0;
|
||||
id->isOpen = 1;
|
||||
OpenCounter(+1);
|
||||
TRACE3("OPEN EX %d \"%s\"\n", h, zFilename);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Attempt to open a new file for read-only access.
|
||||
**
|
||||
** On success, write the file handle into *id and return SQLITE_OK.
|
||||
**
|
||||
** On failure, return SQLITE_CANTOPEN.
|
||||
*/
|
||||
int sqlite3OsOpenReadOnly(const char *zFilename, OsFile *id){
|
||||
HANDLE h;
|
||||
assert( !id->isOpen );
|
||||
h = CreateFileA(zFilename,
|
||||
GENERIC_READ,
|
||||
0,
|
||||
NULL,
|
||||
OPEN_EXISTING,
|
||||
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS,
|
||||
NULL
|
||||
);
|
||||
if( h==INVALID_HANDLE_VALUE ){
|
||||
return SQLITE_CANTOPEN;
|
||||
}
|
||||
id->h = h;
|
||||
id->locktype = NO_LOCK;
|
||||
id->sharedLockByte = 0;
|
||||
id->isOpen = 1;
|
||||
OpenCounter(+1);
|
||||
TRACE3("OPEN RO %d \"%s\"\n", h, zFilename);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Attempt to open a file descriptor for the directory that contains a
|
||||
** file. This file descriptor can be used to fsync() the directory
|
||||
** in order to make sure the creation of a new file is actually written
|
||||
** to disk.
|
||||
**
|
||||
** This routine is only meaningful for Unix. It is a no-op under
|
||||
** windows since windows does not support hard links.
|
||||
**
|
||||
** On success, a handle for a previously open file is at *id is
|
||||
** updated with the new directory file descriptor and SQLITE_OK is
|
||||
** returned.
|
||||
**
|
||||
** On failure, the function returns SQLITE_CANTOPEN and leaves
|
||||
** *id unchanged.
|
||||
*/
|
||||
int sqlite3OsOpenDirectory(
|
||||
const char *zDirname,
|
||||
OsFile *id
|
||||
){
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** If the following global variable points to a string which is the
|
||||
** name of a directory, then that directory will be used to store
|
||||
** temporary files.
|
||||
*/
|
||||
const char *sqlite3_temp_directory = 0;
|
||||
|
||||
/*
|
||||
** Create a temporary file name in zBuf. zBuf must be big enough to
|
||||
** hold at least SQLITE_TEMPNAME_SIZE characters.
|
||||
*/
|
||||
int sqlite3OsTempFileName(char *zBuf){
|
||||
static char zChars[] =
|
||||
"abcdefghijklmnopqrstuvwxyz"
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
"0123456789";
|
||||
int i, j;
|
||||
char zTempPath[SQLITE_TEMPNAME_SIZE];
|
||||
if( sqlite3_temp_directory ){
|
||||
strncpy(zTempPath, sqlite3_temp_directory, SQLITE_TEMPNAME_SIZE-30);
|
||||
zTempPath[SQLITE_TEMPNAME_SIZE-30] = 0;
|
||||
}else{
|
||||
GetTempPathA(SQLITE_TEMPNAME_SIZE-30, zTempPath);
|
||||
}
|
||||
for(i=strlen(zTempPath); i>0 && zTempPath[i-1]=='\\'; i--){}
|
||||
zTempPath[i] = 0;
|
||||
for(;;){
|
||||
sprintf(zBuf, "%s\\"TEMP_FILE_PREFIX, zTempPath);
|
||||
j = strlen(zBuf);
|
||||
sqlite3Randomness(15, &zBuf[j]);
|
||||
for(i=0; i<15; i++, j++){
|
||||
zBuf[j] = (char)zChars[ ((unsigned char)zBuf[j])%(sizeof(zChars)-1) ];
|
||||
}
|
||||
zBuf[j] = 0;
|
||||
if( !sqlite3OsFileExists(zBuf) ) break;
|
||||
}
|
||||
TRACE2("TEMP FILENAME: %s\n", zBuf);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Close a file.
|
||||
*/
|
||||
int sqlite3OsClose(OsFile *id){
|
||||
if( id->isOpen ){
|
||||
TRACE2("CLOSE %d\n", id->h);
|
||||
CloseHandle(id->h);
|
||||
OpenCounter(-1);
|
||||
id->isOpen = 0;
|
||||
}
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Read data from a file into a buffer. Return SQLITE_OK if all
|
||||
** bytes were read successfully and SQLITE_IOERR if anything goes
|
||||
** wrong.
|
||||
*/
|
||||
int sqlite3OsRead(OsFile *id, void *pBuf, int amt){
|
||||
DWORD got;
|
||||
assert( id->isOpen );
|
||||
SimulateIOError(SQLITE_IOERR);
|
||||
TRACE3("READ %d lock=%d\n", id->h, id->locktype);
|
||||
if( !ReadFile(id->h, pBuf, amt, &got, 0) ){
|
||||
got = 0;
|
||||
}
|
||||
if( got==(DWORD)amt ){
|
||||
return SQLITE_OK;
|
||||
}else{
|
||||
return SQLITE_IOERR;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Write data from a buffer into a file. Return SQLITE_OK on success
|
||||
** or some other error code on failure.
|
||||
*/
|
||||
int sqlite3OsWrite(OsFile *id, const void *pBuf, int amt){
|
||||
int rc;
|
||||
DWORD wrote;
|
||||
assert( id->isOpen );
|
||||
SimulateIOError(SQLITE_IOERR);
|
||||
SimulateDiskfullError;
|
||||
TRACE3("WRITE %d lock=%d\n", id->h, id->locktype);
|
||||
while( amt>0 && (rc = WriteFile(id->h, pBuf, amt, &wrote, 0))!=0 && wrote>0 ){
|
||||
amt -= wrote;
|
||||
pBuf = &((char*)pBuf)[wrote];
|
||||
}
|
||||
if( !rc || amt>(int)wrote ){
|
||||
return SQLITE_FULL;
|
||||
}
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Move the read/write pointer in a file.
|
||||
*/
|
||||
int sqlite3OsSeek(OsFile *id, i64 offset){
|
||||
LONG upperBits = offset>>32;
|
||||
LONG lowerBits = offset & 0xffffffff;
|
||||
DWORD rc;
|
||||
assert( id->isOpen );
|
||||
SEEK(offset/1024 + 1);
|
||||
rc = SetFilePointer(id->h, lowerBits, &upperBits, FILE_BEGIN);
|
||||
TRACE3("SEEK %d %lld\n", id->h, offset);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Make sure all writes to a particular file are committed to disk.
|
||||
*/
|
||||
int sqlite3OsSync(OsFile *id){
|
||||
assert( id->isOpen );
|
||||
TRACE3("SYNC %d lock=%d\n", id->h, id->locktype);
|
||||
if( FlushFileBuffers(id->h) ){
|
||||
return SQLITE_OK;
|
||||
}else{
|
||||
return SQLITE_IOERR;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Sync the directory zDirname. This is a no-op on operating systems other
|
||||
** than UNIX.
|
||||
*/
|
||||
int sqlite3OsSyncDirectory(const char *zDirname){
|
||||
SimulateIOError(SQLITE_IOERR);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Truncate an open file to a specified size
|
||||
*/
|
||||
int sqlite3OsTruncate(OsFile *id, i64 nByte){
|
||||
LONG upperBits = nByte>>32;
|
||||
assert( id->isOpen );
|
||||
TRACE3("TRUNCATE %d %lld\n", id->h, nByte);
|
||||
SimulateIOError(SQLITE_IOERR);
|
||||
SetFilePointer(id->h, nByte, &upperBits, FILE_BEGIN);
|
||||
SetEndOfFile(id->h);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Determine the current size of a file in bytes
|
||||
*/
|
||||
int sqlite3OsFileSize(OsFile *id, i64 *pSize){
|
||||
DWORD upperBits, lowerBits;
|
||||
assert( id->isOpen );
|
||||
SimulateIOError(SQLITE_IOERR);
|
||||
lowerBits = GetFileSize(id->h, &upperBits);
|
||||
*pSize = (((i64)upperBits)<<32) + lowerBits;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return true (non-zero) if we are running under WinNT, Win2K or WinXP.
|
||||
** Return false (zero) for Win95, Win98, or WinME.
|
||||
**
|
||||
** Here is an interesting observation: Win95, Win98, and WinME lack
|
||||
** the LockFileEx() API. But we can still statically link against that
|
||||
** API as long as we don't call it win running Win95/98/ME. A call to
|
||||
** this routine is used to determine if the host is Win95/98/ME or
|
||||
** WinNT/2K/XP so that we will know whether or not we can safely call
|
||||
** the LockFileEx() API.
|
||||
*/
|
||||
static int isNT(void){
|
||||
static int osType = 0; /* 0=unknown 1=win95 2=winNT */
|
||||
if( osType==0 ){
|
||||
OSVERSIONINFO sInfo;
|
||||
sInfo.dwOSVersionInfoSize = sizeof(sInfo);
|
||||
GetVersionEx(&sInfo);
|
||||
osType = sInfo.dwPlatformId==VER_PLATFORM_WIN32_NT ? 2 : 1;
|
||||
}
|
||||
return osType==2;
|
||||
}
|
||||
|
||||
/*
|
||||
** Acquire a reader lock.
|
||||
** Different API routines are called depending on whether or not this
|
||||
** is Win95 or WinNT.
|
||||
*/
|
||||
static int getReadLock(OsFile *id){
|
||||
int res;
|
||||
if( isNT() ){
|
||||
OVERLAPPED ovlp;
|
||||
ovlp.Offset = SHARED_FIRST;
|
||||
ovlp.OffsetHigh = 0;
|
||||
ovlp.hEvent = 0;
|
||||
res = LockFileEx(id->h, LOCKFILE_FAIL_IMMEDIATELY, 0, SHARED_SIZE,0,&ovlp);
|
||||
}else{
|
||||
int lk;
|
||||
sqlite3Randomness(sizeof(lk), &lk);
|
||||
id->sharedLockByte = (lk & 0x7fffffff)%(SHARED_SIZE - 1);
|
||||
res = LockFile(id->h, SHARED_FIRST+id->sharedLockByte, 0, 1, 0);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/*
|
||||
** Undo a readlock
|
||||
*/
|
||||
static int unlockReadLock(OsFile *id){
|
||||
int res;
|
||||
if( isNT() ){
|
||||
res = UnlockFile(id->h, SHARED_FIRST, 0, SHARED_SIZE, 0);
|
||||
}else{
|
||||
res = UnlockFile(id->h, SHARED_FIRST + id->sharedLockByte, 0, 1, 0);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/*
|
||||
** Lock the file with the lock specified by parameter locktype - one
|
||||
** of the following:
|
||||
**
|
||||
** (1) SHARED_LOCK
|
||||
** (2) RESERVED_LOCK
|
||||
** (3) PENDING_LOCK
|
||||
** (4) EXCLUSIVE_LOCK
|
||||
**
|
||||
** Sometimes when requesting one lock state, additional lock states
|
||||
** are inserted in between. The locking might fail on one of the later
|
||||
** transitions leaving the lock state different from what it started but
|
||||
** still short of its goal. The following chart shows the allowed
|
||||
** transitions and the inserted intermediate states:
|
||||
**
|
||||
** UNLOCKED -> SHARED
|
||||
** SHARED -> RESERVED
|
||||
** SHARED -> (PENDING) -> EXCLUSIVE
|
||||
** RESERVED -> (PENDING) -> EXCLUSIVE
|
||||
** PENDING -> EXCLUSIVE
|
||||
**
|
||||
** This routine will only increase a lock. The sqlite3OsUnlock() routine
|
||||
** erases all locks at once and returns us immediately to locking level 0.
|
||||
** It is not possible to lower the locking level one step at a time. You
|
||||
** must go straight to locking level 0.
|
||||
*/
|
||||
int sqlite3OsLock(OsFile *id, int locktype){
|
||||
int rc = SQLITE_OK; /* Return code from subroutines */
|
||||
int res = 1; /* Result of a windows lock call */
|
||||
int newLocktype; /* Set id->locktype to this value before exiting */
|
||||
int gotPendingLock = 0;/* True if we acquired a PENDING lock this time */
|
||||
|
||||
assert( id->isOpen );
|
||||
TRACE5("LOCK %d %d was %d(%d)\n",
|
||||
id->h, locktype, id->locktype, id->sharedLockByte);
|
||||
|
||||
/* If there is already a lock of this type or more restrictive on the
|
||||
** OsFile, do nothing. Don't use the end_lock: exit path, as
|
||||
** sqlite3OsEnterMutex() hasn't been called yet.
|
||||
*/
|
||||
if( id->locktype>=locktype ){
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/* Make sure the locking sequence is correct
|
||||
*/
|
||||
assert( id->locktype!=NO_LOCK || locktype==SHARED_LOCK );
|
||||
assert( locktype!=PENDING_LOCK );
|
||||
assert( locktype!=RESERVED_LOCK || id->locktype==SHARED_LOCK );
|
||||
|
||||
/* Lock the PENDING_LOCK byte if we need to acquire a PENDING lock or
|
||||
** a SHARED lock. If we are acquiring a SHARED lock, the acquisition of
|
||||
** the PENDING_LOCK byte is temporary.
|
||||
*/
|
||||
newLocktype = id->locktype;
|
||||
if( id->locktype==NO_LOCK
|
||||
|| (locktype==EXCLUSIVE_LOCK && id->locktype==RESERVED_LOCK)
|
||||
){
|
||||
int cnt = 3;
|
||||
while( cnt-->0 && (res = LockFile(id->h, PENDING_BYTE, 0, 1, 0))==0 ){
|
||||
/* Try 3 times to get the pending lock. The pending lock might be
|
||||
** held by another reader process who will release it momentarily.
|
||||
*/
|
||||
TRACE2("could not get a PENDING lock. cnt=%d\n", cnt);
|
||||
Sleep(1);
|
||||
}
|
||||
gotPendingLock = res;
|
||||
}
|
||||
|
||||
/* Acquire a shared lock
|
||||
*/
|
||||
if( locktype==SHARED_LOCK && res ){
|
||||
assert( id->locktype==NO_LOCK );
|
||||
res = getReadLock(id);
|
||||
if( res ){
|
||||
newLocktype = SHARED_LOCK;
|
||||
}
|
||||
}
|
||||
|
||||
/* Acquire a RESERVED lock
|
||||
*/
|
||||
if( locktype==RESERVED_LOCK && res ){
|
||||
assert( id->locktype==SHARED_LOCK );
|
||||
res = LockFile(id->h, RESERVED_BYTE, 0, 1, 0);
|
||||
if( res ){
|
||||
newLocktype = RESERVED_LOCK;
|
||||
}
|
||||
}
|
||||
|
||||
/* Acquire a PENDING lock
|
||||
*/
|
||||
if( locktype==EXCLUSIVE_LOCK && res ){
|
||||
newLocktype = PENDING_LOCK;
|
||||
gotPendingLock = 0;
|
||||
}
|
||||
|
||||
/* Acquire an EXCLUSIVE lock
|
||||
*/
|
||||
if( locktype==EXCLUSIVE_LOCK && res ){
|
||||
assert( id->locktype>=SHARED_LOCK );
|
||||
res = unlockReadLock(id);
|
||||
TRACE2("unreadlock = %d\n", res);
|
||||
res = LockFile(id->h, SHARED_FIRST, 0, SHARED_SIZE, 0);
|
||||
if( res ){
|
||||
newLocktype = EXCLUSIVE_LOCK;
|
||||
}else{
|
||||
TRACE2("error-code = %d\n", GetLastError());
|
||||
}
|
||||
}
|
||||
|
||||
/* If we are holding a PENDING lock that ought to be released, then
|
||||
** release it now.
|
||||
*/
|
||||
if( gotPendingLock && locktype==SHARED_LOCK ){
|
||||
UnlockFile(id->h, PENDING_BYTE, 0, 1, 0);
|
||||
}
|
||||
|
||||
/* Update the state of the lock has held in the file descriptor then
|
||||
** return the appropriate result code.
|
||||
*/
|
||||
if( res ){
|
||||
rc = SQLITE_OK;
|
||||
}else{
|
||||
TRACE4("LOCK FAILED %d trying for %d but got %d\n", id->h,
|
||||
locktype, newLocktype);
|
||||
rc = SQLITE_BUSY;
|
||||
}
|
||||
id->locktype = newLocktype;
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** This routine checks if there is a RESERVED lock held on the specified
|
||||
** file by this or any other process. If such a lock is held, return
|
||||
** non-zero, otherwise zero.
|
||||
*/
|
||||
int sqlite3OsCheckReservedLock(OsFile *id){
|
||||
int rc;
|
||||
assert( id->isOpen );
|
||||
if( id->locktype>=RESERVED_LOCK ){
|
||||
rc = 1;
|
||||
TRACE3("TEST WR-LOCK %d %d (local)\n", id->h, rc);
|
||||
}else{
|
||||
rc = LockFile(id->h, RESERVED_BYTE, 0, 1, 0);
|
||||
if( rc ){
|
||||
UnlockFile(id->h, RESERVED_BYTE, 0, 1, 0);
|
||||
}
|
||||
rc = !rc;
|
||||
TRACE3("TEST WR-LOCK %d %d (remote)\n", id->h, rc);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Lower the locking level on file descriptor id to locktype. locktype
|
||||
** must be either NO_LOCK or SHARED_LOCK.
|
||||
**
|
||||
** If the locking level of the file descriptor is already at or below
|
||||
** the requested locking level, this routine is a no-op.
|
||||
**
|
||||
** It is not possible for this routine to fail if the second argument
|
||||
** is NO_LOCK. If the second argument is SHARED_LOCK then this routine
|
||||
** might return SQLITE_IOERR;
|
||||
*/
|
||||
int sqlite3OsUnlock(OsFile *id, int locktype){
|
||||
int type;
|
||||
int rc = SQLITE_OK;
|
||||
assert( id->isOpen );
|
||||
assert( locktype<=SHARED_LOCK );
|
||||
TRACE5("UNLOCK %d to %d was %d(%d)\n", id->h, locktype,
|
||||
id->locktype, id->sharedLockByte);
|
||||
type = id->locktype;
|
||||
if( type>=EXCLUSIVE_LOCK ){
|
||||
UnlockFile(id->h, SHARED_FIRST, 0, SHARED_SIZE, 0);
|
||||
if( locktype==SHARED_LOCK && !getReadLock(id) ){
|
||||
/* This should never happen. We should always be able to
|
||||
** reacquire the read lock */
|
||||
rc = SQLITE_IOERR;
|
||||
}
|
||||
}
|
||||
if( type>=RESERVED_LOCK ){
|
||||
UnlockFile(id->h, RESERVED_BYTE, 0, 1, 0);
|
||||
}
|
||||
if( locktype==NO_LOCK && type>=SHARED_LOCK ){
|
||||
unlockReadLock(id);
|
||||
}
|
||||
if( type>=PENDING_LOCK ){
|
||||
UnlockFile(id->h, PENDING_BYTE, 0, 1, 0);
|
||||
}
|
||||
id->locktype = locktype;
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Get information to seed the random number generator. The seed
|
||||
** is written into the buffer zBuf[256]. The calling function must
|
||||
** supply a sufficiently large buffer.
|
||||
*/
|
||||
int sqlite3OsRandomSeed(char *zBuf){
|
||||
/* We have to initialize zBuf to prevent valgrind from reporting
|
||||
** errors. The reports issued by valgrind are incorrect - we would
|
||||
** prefer that the randomness be increased by making use of the
|
||||
** uninitialized space in zBuf - but valgrind errors tend to worry
|
||||
** some users. Rather than argue, it seems easier just to initialize
|
||||
** the whole array and silence valgrind, even if that means less randomness
|
||||
** in the random seed.
|
||||
**
|
||||
** When testing, initializing zBuf[] to zero is all we do. That means
|
||||
** that we always use the same random number sequence.* This makes the
|
||||
** tests repeatable.
|
||||
*/
|
||||
memset(zBuf, 0, 256);
|
||||
GetSystemTime((LPSYSTEMTIME)zBuf);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Sleep for a little while. Return the amount of time slept.
|
||||
*/
|
||||
int sqlite3OsSleep(int ms){
|
||||
Sleep(ms);
|
||||
return ms;
|
||||
}
|
||||
|
||||
/*
|
||||
** Static variables used for thread synchronization
|
||||
*/
|
||||
static int inMutex = 0;
|
||||
#ifdef SQLITE_W32_THREADS
|
||||
static CRITICAL_SECTION cs;
|
||||
#endif
|
||||
|
||||
/*
|
||||
** The following pair of routine implement mutual exclusion for
|
||||
** multi-threaded processes. Only a single thread is allowed to
|
||||
** executed code that is surrounded by EnterMutex() and LeaveMutex().
|
||||
**
|
||||
** SQLite uses only a single Mutex. There is not much critical
|
||||
** code and what little there is executes quickly and without blocking.
|
||||
*/
|
||||
void sqlite3OsEnterMutex(){
|
||||
#ifdef SQLITE_W32_THREADS
|
||||
static int isInit = 0;
|
||||
while( !isInit ){
|
||||
static long lock = 0;
|
||||
if( InterlockedIncrement(&lock)==1 ){
|
||||
InitializeCriticalSection(&cs);
|
||||
isInit = 1;
|
||||
}else{
|
||||
Sleep(1);
|
||||
}
|
||||
}
|
||||
EnterCriticalSection(&cs);
|
||||
#endif
|
||||
assert( !inMutex );
|
||||
inMutex = 1;
|
||||
}
|
||||
void sqlite3OsLeaveMutex(){
|
||||
assert( inMutex );
|
||||
inMutex = 0;
|
||||
#ifdef SQLITE_W32_THREADS
|
||||
LeaveCriticalSection(&cs);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
** Turn a relative pathname into a full pathname. Return a pointer
|
||||
** to the full pathname stored in space obtained from sqliteMalloc().
|
||||
** The calling function is responsible for freeing this space once it
|
||||
** is no longer needed.
|
||||
*/
|
||||
char *sqlite3OsFullPathname(const char *zRelative){
|
||||
char *zNotUsed;
|
||||
char *zFull;
|
||||
int nByte;
|
||||
nByte = GetFullPathNameA(zRelative, 0, 0, &zNotUsed) + 1;
|
||||
zFull = sqliteMalloc( nByte );
|
||||
if( zFull==0 ) return 0;
|
||||
GetFullPathNameA(zRelative, nByte, zFull, &zNotUsed);
|
||||
return zFull;
|
||||
}
|
||||
|
||||
/*
|
||||
** The following variable, if set to a non-zero value, becomes the result
|
||||
** returned from sqlite3OsCurrentTime(). This is used for testing.
|
||||
*/
|
||||
#ifdef SQLITE_TEST
|
||||
int sqlite3_current_time = 0;
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Find the current time (in Universal Coordinated Time). Write the
|
||||
** current time and date as a Julian Day number into *prNow and
|
||||
** return 0. Return 1 if the time and date cannot be found.
|
||||
*/
|
||||
int sqlite3OsCurrentTime(double *prNow){
|
||||
FILETIME ft;
|
||||
/* FILETIME structure is a 64-bit value representing the number of
|
||||
100-nanosecond intervals since January 1, 1601 (= JD 2305813.5).
|
||||
*/
|
||||
double now;
|
||||
GetSystemTimeAsFileTime( &ft );
|
||||
now = ((double)ft.dwHighDateTime) * 4294967296.0;
|
||||
*prNow = (now + ft.dwLowDateTime)/864000000000.0 + 2305813.5;
|
||||
#ifdef SQLITE_TEST
|
||||
if( sqlite3_current_time ){
|
||||
*prNow = sqlite3_current_time/86400.0 + 2440587.5;
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Find the time that the file was last modified. Write the
|
||||
** modification time and date as a Julian Day number into *prNow and
|
||||
** return SQLITE_OK. Return SQLITE_ERROR if the modification
|
||||
** time cannot be found.
|
||||
*/
|
||||
int sqlite3OsFileModTime(OsFile *id, double *prMTime){
|
||||
int rc;
|
||||
FILETIME ft;
|
||||
/* FILETIME structure is a 64-bit value representing the number of
|
||||
** 100-nanosecond intervals since January 1, 1601 (= JD 2305813.5).
|
||||
*/
|
||||
if( GetFileTime(id->h, 0, 0, &ft) ){
|
||||
double t;
|
||||
t = ((double)ft.dwHighDateTime) * 4294967296.0;
|
||||
*prMTime = (t + ft.dwLowDateTime)/864000000000.0 + 2305813.5;
|
||||
rc = SQLITE_OK;
|
||||
}else{
|
||||
rc = SQLITE_ERROR;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
#endif /* OS_WIN */
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,102 @@
|
|||
/*
|
||||
** 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.38 2004/10/05 02:41:43 drh Exp $
|
||||
*/
|
||||
|
||||
/*
|
||||
** The default size of a database page.
|
||||
*/
|
||||
#ifndef SQLITE_DEFAULT_PAGE_SIZE
|
||||
# define SQLITE_DEFAULT_PAGE_SIZE 1024
|
||||
#endif
|
||||
|
||||
/* Maximum page size. The upper bound on this value is 65536 (a limit
|
||||
** imposed by the 2-byte size of cell array pointers.) The
|
||||
** maximum page size determines the amount of stack space allocated
|
||||
** by many of the routines in pager.c and btree.c On embedded architectures
|
||||
** or any machine where memory and especially stack memory is limited,
|
||||
** one may wish to chose a smaller value for the maximum page size.
|
||||
*/
|
||||
#ifndef SQLITE_MAX_PAGE_SIZE
|
||||
# define SQLITE_MAX_PAGE_SIZE 8192
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Maximum number of pages in one database.
|
||||
*/
|
||||
#define SQLITE_MAX_PAGE 1073741823
|
||||
|
||||
/*
|
||||
** The type used to represent a page number. The first page in a file
|
||||
** is called page 1. 0 is used to represent "not a page".
|
||||
*/
|
||||
typedef unsigned int Pgno;
|
||||
|
||||
/*
|
||||
** Each open file is managed by a separate instance of the "Pager" structure.
|
||||
*/
|
||||
typedef struct Pager Pager;
|
||||
|
||||
|
||||
/*
|
||||
** See source code comments for a detailed description of the following
|
||||
** routines:
|
||||
*/
|
||||
int sqlite3pager_open(Pager **ppPager, const char *zFilename,
|
||||
int nExtra, int useJournal);
|
||||
void sqlite3pager_set_busyhandler(Pager*, BusyHandler *pBusyHandler);
|
||||
void sqlite3pager_set_destructor(Pager*, void(*)(void*,int));
|
||||
void sqlite3pager_set_reiniter(Pager*, void(*)(void*,int));
|
||||
void sqlite3pager_set_pagesize(Pager*, int);
|
||||
void sqlite3pager_read_fileheader(Pager*, int, unsigned char*);
|
||||
void sqlite3pager_set_cachesize(Pager*, int);
|
||||
int sqlite3pager_close(Pager *pPager);
|
||||
int sqlite3pager_get(Pager *pPager, Pgno pgno, void **ppPage);
|
||||
void *sqlite3pager_lookup(Pager *pPager, Pgno pgno);
|
||||
int sqlite3pager_ref(void*);
|
||||
int sqlite3pager_unref(void*);
|
||||
Pgno sqlite3pager_pagenumber(void*);
|
||||
int sqlite3pager_write(void*);
|
||||
int sqlite3pager_iswriteable(void*);
|
||||
int sqlite3pager_overwrite(Pager *pPager, Pgno pgno, void*);
|
||||
int sqlite3pager_pagecount(Pager*);
|
||||
int sqlite3pager_truncate(Pager*,Pgno);
|
||||
int sqlite3pager_begin(void*, int exFlag);
|
||||
int sqlite3pager_commit(Pager*);
|
||||
int sqlite3pager_sync(Pager*,const char *zMaster);
|
||||
int sqlite3pager_rollback(Pager*);
|
||||
int sqlite3pager_isreadonly(Pager*);
|
||||
int sqlite3pager_stmt_begin(Pager*);
|
||||
int sqlite3pager_stmt_commit(Pager*);
|
||||
int sqlite3pager_stmt_rollback(Pager*);
|
||||
void sqlite3pager_dont_rollback(void*);
|
||||
void sqlite3pager_dont_write(Pager*, Pgno);
|
||||
int *sqlite3pager_stats(Pager*);
|
||||
void sqlite3pager_set_safety_level(Pager*,int);
|
||||
const char *sqlite3pager_filename(Pager*);
|
||||
const char *sqlite3pager_dirname(Pager*);
|
||||
const char *sqlite3pager_journalname(Pager*);
|
||||
int sqlite3pager_rename(Pager*, const char *zNewName);
|
||||
void sqlite3pager_set_codec(Pager*,void(*)(void*,void*,Pgno,int),void*);
|
||||
|
||||
#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
|
||||
int sqlite3pager_lockstate(Pager*);
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_TEST
|
||||
void sqlite3pager_refdump(Pager*);
|
||||
int pager3_refinfo_enable;
|
||||
#endif
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,129 @@
|
|||
#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_DEFERRED 13
|
||||
#define TK_IMMEDIATE 14
|
||||
#define TK_EXCLUSIVE 15
|
||||
#define TK_COMMIT 16
|
||||
#define TK_END 17
|
||||
#define TK_ROLLBACK 18
|
||||
#define TK_CREATE 19
|
||||
#define TK_TABLE 20
|
||||
#define TK_TEMP 21
|
||||
#define TK_LP 22
|
||||
#define TK_RP 23
|
||||
#define TK_AS 24
|
||||
#define TK_COMMA 25
|
||||
#define TK_ID 26
|
||||
#define TK_ABORT 27
|
||||
#define TK_AFTER 28
|
||||
#define TK_ASC 29
|
||||
#define TK_ATTACH 30
|
||||
#define TK_BEFORE 31
|
||||
#define TK_CASCADE 32
|
||||
#define TK_CONFLICT 33
|
||||
#define TK_DATABASE 34
|
||||
#define TK_DESC 35
|
||||
#define TK_DETACH 36
|
||||
#define TK_EACH 37
|
||||
#define TK_FAIL 38
|
||||
#define TK_FOR 39
|
||||
#define TK_GLOB 40
|
||||
#define TK_IGNORE 41
|
||||
#define TK_INITIALLY 42
|
||||
#define TK_INSTEAD 43
|
||||
#define TK_LIKE 44
|
||||
#define TK_MATCH 45
|
||||
#define TK_KEY 46
|
||||
#define TK_OF 47
|
||||
#define TK_OFFSET 48
|
||||
#define TK_PRAGMA 49
|
||||
#define TK_RAISE 50
|
||||
#define TK_REPLACE 51
|
||||
#define TK_RESTRICT 52
|
||||
#define TK_ROW 53
|
||||
#define TK_STATEMENT 54
|
||||
#define TK_TRIGGER 55
|
||||
#define TK_VACUUM 56
|
||||
#define TK_VIEW 57
|
||||
#define TK_OR 58
|
||||
#define TK_AND 59
|
||||
#define TK_NOT 60
|
||||
#define TK_IS 61
|
||||
#define TK_BETWEEN 62
|
||||
#define TK_IN 63
|
||||
#define TK_ISNULL 64
|
||||
#define TK_NOTNULL 65
|
||||
#define TK_NE 66
|
||||
#define TK_EQ 67
|
||||
#define TK_GT 68
|
||||
#define TK_LE 69
|
||||
#define TK_LT 70
|
||||
#define TK_GE 71
|
||||
#define TK_BITAND 72
|
||||
#define TK_BITOR 73
|
||||
#define TK_LSHIFT 74
|
||||
#define TK_RSHIFT 75
|
||||
#define TK_PLUS 76
|
||||
#define TK_MINUS 77
|
||||
#define TK_STAR 78
|
||||
#define TK_SLASH 79
|
||||
#define TK_REM 80
|
||||
#define TK_CONCAT 81
|
||||
#define TK_UMINUS 82
|
||||
#define TK_UPLUS 83
|
||||
#define TK_BITNOT 84
|
||||
#define TK_STRING 85
|
||||
#define TK_JOIN_KW 86
|
||||
#define TK_INTEGER 87
|
||||
#define TK_CONSTRAINT 88
|
||||
#define TK_DEFAULT 89
|
||||
#define TK_FLOAT 90
|
||||
#define TK_NULL 91
|
||||
#define TK_PRIMARY 92
|
||||
#define TK_UNIQUE 93
|
||||
#define TK_CHECK 94
|
||||
#define TK_REFERENCES 95
|
||||
#define TK_COLLATE 96
|
||||
#define TK_ON 97
|
||||
#define TK_DELETE 98
|
||||
#define TK_UPDATE 99
|
||||
#define TK_INSERT 100
|
||||
#define TK_SET 101
|
||||
#define TK_DEFERRABLE 102
|
||||
#define TK_FOREIGN 103
|
||||
#define TK_DROP 104
|
||||
#define TK_UNION 105
|
||||
#define TK_ALL 106
|
||||
#define TK_INTERSECT 107
|
||||
#define TK_EXCEPT 108
|
||||
#define TK_SELECT 109
|
||||
#define TK_DISTINCT 110
|
||||
#define TK_DOT 111
|
||||
#define TK_FROM 112
|
||||
#define TK_JOIN 113
|
||||
#define TK_USING 114
|
||||
#define TK_ORDER 115
|
||||
#define TK_BY 116
|
||||
#define TK_GROUP 117
|
||||
#define TK_HAVING 118
|
||||
#define TK_LIMIT 119
|
||||
#define TK_WHERE 120
|
||||
#define TK_INTO 121
|
||||
#define TK_VALUES 122
|
||||
#define TK_BLOB 123
|
||||
#define TK_VARIABLE 124
|
||||
#define TK_CASE 125
|
||||
#define TK_WHEN 126
|
||||
#define TK_THEN 127
|
||||
#define TK_ELSE 128
|
||||
#define TK_INDEX 129
|
|
@ -0,0 +1,754 @@
|
|||
/*
|
||||
** 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.69 2004/10/05 15:42:53 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include <ctype.h>
|
||||
|
||||
#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
|
||||
# include "pager.h"
|
||||
# include "btree.h"
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Interpret the given string as a boolean value.
|
||||
*/
|
||||
static int getBoolean(const u8 *z){
|
||||
static const u8 *azTrue[] = { "yes", "on", "true" };
|
||||
int i;
|
||||
if( z[0]==0 ) return 0;
|
||||
if( sqlite3IsNumber(z, 0, SQLITE_UTF8) ){
|
||||
return atoi(z);
|
||||
}
|
||||
for(i=0; i<sizeof(azTrue)/sizeof(azTrue[0]); i++){
|
||||
if( sqlite3StrICmp(z,azTrue[i])==0 ) return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Interpret the given string as a safety level. Return 0 for OFF,
|
||||
** 1 for ON or NORMAL and 2 for FULL. Return 1 for an empty or
|
||||
** unrecognized string argument.
|
||||
**
|
||||
** Note that the values returned are one less that the values that
|
||||
** should be passed into sqlite3BtreeSetSafetyLevel(). The is done
|
||||
** to support legacy SQL code. The safety level used to be boolean
|
||||
** and older scripts may have used numbers 0 for OFF and 1 for ON.
|
||||
*/
|
||||
static int getSafetyLevel(u8 *z){
|
||||
static const struct {
|
||||
const u8 *zWord;
|
||||
int val;
|
||||
} aKey[] = {
|
||||
{ "no", 0 },
|
||||
{ "off", 0 },
|
||||
{ "false", 0 },
|
||||
{ "yes", 1 },
|
||||
{ "on", 1 },
|
||||
{ "true", 1 },
|
||||
{ "full", 2 },
|
||||
};
|
||||
int i;
|
||||
if( z[0]==0 ) return 1;
|
||||
if( sqlite3IsNumber(z, 0, SQLITE_UTF8) ){
|
||||
return atoi(z);
|
||||
}
|
||||
for(i=0; i<sizeof(aKey)/sizeof(aKey[0]); i++){
|
||||
if( sqlite3StrICmp(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(const char *z){
|
||||
if( z[0]>='0' && z[0]<='2' ){
|
||||
return z[0] - '0';
|
||||
}else if( sqlite3StrICmp(z, "file")==0 ){
|
||||
return 1;
|
||||
}else if( sqlite3StrICmp(z, "memory")==0 ){
|
||||
return 2;
|
||||
}else{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** If the TEMP database is open, close it and mark the database schema
|
||||
** as needing reloading. This must be done when using the TEMP_STORE
|
||||
** or DEFAULT_TEMP_STORE pragmas.
|
||||
*/
|
||||
static int changeTempStorage(Parse *pParse, const char *zStorageType){
|
||||
int ts = getTempStore(zStorageType);
|
||||
sqlite3 *db = pParse->db;
|
||||
if( db->temp_store==ts ) return SQLITE_OK;
|
||||
if( db->aDb[1].pBt!=0 ){
|
||||
if( db->flags & SQLITE_InTrans ){
|
||||
sqlite3ErrorMsg(pParse, "temporary storage cannot be changed "
|
||||
"from within a transaction");
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
sqlite3BtreeClose(db->aDb[1].pBt);
|
||||
db->aDb[1].pBt = 0;
|
||||
sqlite3ResetInternalSchema(db, 0);
|
||||
}
|
||||
db->temp_store = ts;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Generate code to return a single integer value.
|
||||
*/
|
||||
static void returnSingleInt(Parse *pParse, const char *zLabel, int value){
|
||||
Vdbe *v = sqlite3GetVdbe(pParse);
|
||||
sqlite3VdbeAddOp(v, OP_Integer, value, 0);
|
||||
if( pParse->explain==0 ){
|
||||
sqlite3VdbeSetNumCols(v, 1);
|
||||
sqlite3VdbeSetColName(v, 0, zLabel, P3_STATIC);
|
||||
}
|
||||
sqlite3VdbeAddOp(v, OP_Callback, 1, 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 },
|
||||
{ "sql_trace", SQLITE_SqlTrace },
|
||||
{ "vdbe_listing", SQLITE_VdbeListing },
|
||||
#if 1 /* FIX ME: Remove the following pragmas */
|
||||
{ "full_column_names", SQLITE_FullColNames },
|
||||
{ "short_column_names", SQLITE_ShortColNames },
|
||||
{ "count_changes", SQLITE_CountRows },
|
||||
{ "empty_result_callbacks", SQLITE_NullCallback },
|
||||
#endif
|
||||
};
|
||||
int i;
|
||||
for(i=0; i<sizeof(aPragma)/sizeof(aPragma[0]); i++){
|
||||
if( sqlite3StrICmp(zLeft, aPragma[i].zName)==0 ){
|
||||
sqlite3 *db = pParse->db;
|
||||
Vdbe *v;
|
||||
if( zRight==0 ){
|
||||
v = sqlite3GetVdbe(pParse);
|
||||
if( v ){
|
||||
returnSingleInt(pParse,
|
||||
aPragma[i].zName, (db->flags&aPragma[i].mask)!=0);
|
||||
}
|
||||
}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 [database.]id [= value]
|
||||
**
|
||||
** The identifier might also be a string. The value is a string, and
|
||||
** identifier, or a number. If minusFlag is true, then the value is
|
||||
** a number that was preceded by a minus sign.
|
||||
**
|
||||
** If the left side is "database.id" then pId1 is the database name
|
||||
** and pId2 is the id. If the left side is just "id" then pId1 is the
|
||||
** id and pId2 is any empty string.
|
||||
*/
|
||||
void sqlite3Pragma(
|
||||
Parse *pParse,
|
||||
Token *pId1, /* First part of [database.]id field */
|
||||
Token *pId2, /* Second part of [database.]id field, or NULL */
|
||||
Token *pValue, /* Token for <value>, or NULL */
|
||||
int minusFlag /* True if a '-' sign preceded <value> */
|
||||
){
|
||||
char *zLeft = 0; /* Nul-terminated UTF-8 string <id> */
|
||||
char *zRight = 0; /* Nul-terminated UTF-8 string <value>, or NULL */
|
||||
const char *zDb = 0; /* The database name */
|
||||
Token *pId; /* Pointer to <id> token */
|
||||
int iDb; /* Database index for <database> */
|
||||
sqlite3 *db = pParse->db;
|
||||
Db *pDb;
|
||||
Vdbe *v = sqlite3GetVdbe(pParse);
|
||||
if( v==0 ) return;
|
||||
|
||||
/* Interpret the [database.] part of the pragma statement. iDb is the
|
||||
** index of the database this pragma is being applied to in db.aDb[]. */
|
||||
iDb = sqlite3TwoPartName(pParse, pId1, pId2, &pId);
|
||||
if( iDb<0 ) return;
|
||||
pDb = &db->aDb[iDb];
|
||||
|
||||
zLeft = sqlite3NameFromToken(pId);
|
||||
if( !zLeft ) return;
|
||||
if( minusFlag ){
|
||||
zRight = sqlite3MPrintf("-%T", pValue);
|
||||
}else{
|
||||
zRight = sqlite3NameFromToken(pValue);
|
||||
}
|
||||
|
||||
zDb = ((iDb>0)?pDb->zName:0);
|
||||
if( sqlite3AuthCheck(pParse, SQLITE_PRAGMA, zLeft, zRight, zDb) ){
|
||||
goto pragma_out;
|
||||
}
|
||||
|
||||
/*
|
||||
** PRAGMA [database.]default_cache_size
|
||||
** PRAGMA [database.]default_cache_size=N
|
||||
**
|
||||
** The first form reports the current persistent setting for the
|
||||
** page cache size. The value returned is the maximum number of
|
||||
** pages in the page cache. The second form sets both the current
|
||||
** page cache size value and the persistent page cache size value
|
||||
** stored in the database file.
|
||||
**
|
||||
** The default cache size is stored in meta-value 2 of page 1 of the
|
||||
** database file. The cache size is actually the absolute value of
|
||||
** this memory location. The sign of meta-value 2 determines the
|
||||
** synchronous setting. A negative value means synchronous is off
|
||||
** and a positive value means synchronous is on.
|
||||
*/
|
||||
if( sqlite3StrICmp(zLeft,"default_cache_size")==0 ){
|
||||
static VdbeOpList getCacheSize[] = {
|
||||
{ OP_ReadCookie, 0, 2, 0}, /* 0 */
|
||||
{ OP_AbsValue, 0, 0, 0},
|
||||
{ OP_Dup, 0, 0, 0},
|
||||
{ OP_Integer, 0, 0, 0},
|
||||
{ OP_Ne, 0, 6, 0},
|
||||
{ OP_Integer, 0, 0, 0}, /* 5 */
|
||||
{ OP_Callback, 1, 0, 0},
|
||||
};
|
||||
int addr;
|
||||
if( sqlite3ReadSchema(pParse) ) goto pragma_out;
|
||||
if( !zRight ){
|
||||
sqlite3VdbeSetNumCols(v, 1);
|
||||
sqlite3VdbeSetColName(v, 0, "cache_size", P3_STATIC);
|
||||
addr = sqlite3VdbeAddOpList(v, ArraySize(getCacheSize), getCacheSize);
|
||||
sqlite3VdbeChangeP1(v, addr, iDb);
|
||||
sqlite3VdbeChangeP1(v, addr+5, MAX_PAGES);
|
||||
}else{
|
||||
int size = atoi(zRight);
|
||||
if( size<0 ) size = -size;
|
||||
sqlite3BeginWriteOperation(pParse, 0, iDb);
|
||||
sqlite3VdbeAddOp(v, OP_Integer, size, 0);
|
||||
sqlite3VdbeAddOp(v, OP_ReadCookie, iDb, 2);
|
||||
addr = sqlite3VdbeAddOp(v, OP_Integer, 0, 0);
|
||||
sqlite3VdbeAddOp(v, OP_Ge, 0, addr+3);
|
||||
sqlite3VdbeAddOp(v, OP_Negative, 0, 0);
|
||||
sqlite3VdbeAddOp(v, OP_SetCookie, iDb, 2);
|
||||
pDb->cache_size = size;
|
||||
sqlite3BtreeSetCacheSize(pDb->pBt, pDb->cache_size);
|
||||
}
|
||||
}else
|
||||
|
||||
/*
|
||||
** PRAGMA [database.]page_size
|
||||
** PRAGMA [database.]page_size=N
|
||||
**
|
||||
** The first form reports the current setting for the
|
||||
** database page size in bytes. The second form sets the
|
||||
** database page size value. The value can only be set if
|
||||
** the database has not yet been created.
|
||||
*/
|
||||
if( sqlite3StrICmp(zLeft,"page_size")==0 ){
|
||||
Btree *pBt = pDb->pBt;
|
||||
if( !zRight ){
|
||||
int size = pBt ? sqlite3BtreeGetPageSize(pBt) : 0;
|
||||
returnSingleInt(pParse, "page_size", size);
|
||||
}else{
|
||||
sqlite3BtreeSetPageSize(pBt, atoi(zRight), sqlite3BtreeGetReserve(pBt));
|
||||
}
|
||||
}else
|
||||
|
||||
/*
|
||||
** PRAGMA [database.]cache_size
|
||||
** PRAGMA [database.]cache_size=N
|
||||
**
|
||||
** The first form reports the current local setting for the
|
||||
** page cache size. The local setting can be different from
|
||||
** the persistent cache size value that is stored in the database
|
||||
** file itself. The value returned is the maximum number of
|
||||
** pages in the page cache. The second form sets the local
|
||||
** page cache size value. It does not change the persistent
|
||||
** cache size stored on the disk so the cache size will revert
|
||||
** to its default value when the database is closed and reopened.
|
||||
** N should be a positive integer.
|
||||
*/
|
||||
if( sqlite3StrICmp(zLeft,"cache_size")==0 ){
|
||||
if( sqlite3ReadSchema(pParse) ) goto pragma_out;
|
||||
if( !zRight ){
|
||||
returnSingleInt(pParse, "cache_size", pDb->cache_size);
|
||||
}else{
|
||||
int size = atoi(zRight);
|
||||
if( size<0 ) size = -size;
|
||||
pDb->cache_size = size;
|
||||
sqlite3BtreeSetCacheSize(pDb->pBt, pDb->cache_size);
|
||||
}
|
||||
}else
|
||||
|
||||
/*
|
||||
** PRAGMA temp_store
|
||||
** PRAGMA temp_store = "default"|"memory"|"file"
|
||||
**
|
||||
** Return or set the local value of the temp_store flag. Changing
|
||||
** the local value does not make changes to the disk file and the default
|
||||
** value will be restored the next time the database is opened.
|
||||
**
|
||||
** Note that it is possible for the library compile-time options to
|
||||
** override this setting
|
||||
*/
|
||||
if( sqlite3StrICmp(zLeft, "temp_store")==0 ){
|
||||
if( !zRight ){
|
||||
returnSingleInt(pParse, "temp_store", db->temp_store);
|
||||
}else{
|
||||
changeTempStorage(pParse, zRight);
|
||||
}
|
||||
}else
|
||||
|
||||
/*
|
||||
** PRAGMA [database.]synchronous
|
||||
** PRAGMA [database.]synchronous=OFF|ON|NORMAL|FULL
|
||||
**
|
||||
** Return or set the local value of the synchronous flag. Changing
|
||||
** the local value does not make changes to the disk file and the
|
||||
** default value will be restored the next time the database is
|
||||
** opened.
|
||||
*/
|
||||
if( sqlite3StrICmp(zLeft,"synchronous")==0 ){
|
||||
if( sqlite3ReadSchema(pParse) ) goto pragma_out;
|
||||
if( !zRight ){
|
||||
returnSingleInt(pParse, "synchronous", pDb->safety_level-1);
|
||||
}else{
|
||||
if( !db->autoCommit ){
|
||||
sqlite3ErrorMsg(pParse,
|
||||
"Safety level may not be changed inside a transaction");
|
||||
}else{
|
||||
pDb->safety_level = getSafetyLevel(zRight)+1;
|
||||
sqlite3BtreeSetSafetyLevel(pDb->pBt, pDb->safety_level);
|
||||
}
|
||||
}
|
||||
}else
|
||||
|
||||
#if 0 /* Used once during development. No longer needed */
|
||||
if( sqlite3StrICmp(zLeft, "trigger_overhead_test")==0 ){
|
||||
if( getBoolean(zRight) ){
|
||||
sqlite3_always_code_trigger_setup = 1;
|
||||
}else{
|
||||
sqlite3_always_code_trigger_setup = 0;
|
||||
}
|
||||
}else
|
||||
#endif
|
||||
|
||||
if( flagPragma(pParse, zLeft, zRight) ){
|
||||
/* The flagPragma() subroutine also generates any necessary code
|
||||
** there is nothing more to do here */
|
||||
}else
|
||||
|
||||
/*
|
||||
** PRAGMA table_info(<table>)
|
||||
**
|
||||
** Return a single row for each column of the named table. The columns of
|
||||
** the returned data set are:
|
||||
**
|
||||
** cid: Column id (numbered from left to right, starting at 0)
|
||||
** name: Column name
|
||||
** type: Column declaration type.
|
||||
** notnull: True if 'NOT NULL' is part of column declaration
|
||||
** dflt_value: The default value for the column, if any.
|
||||
*/
|
||||
if( sqlite3StrICmp(zLeft, "table_info")==0 && zRight ){
|
||||
Table *pTab;
|
||||
if( sqlite3ReadSchema(pParse) ) goto pragma_out;
|
||||
pTab = sqlite3FindTable(db, zRight, zDb);
|
||||
if( pTab ){
|
||||
int i;
|
||||
sqlite3VdbeSetNumCols(v, 6);
|
||||
sqlite3VdbeSetColName(v, 0, "cid", P3_STATIC);
|
||||
sqlite3VdbeSetColName(v, 1, "name", P3_STATIC);
|
||||
sqlite3VdbeSetColName(v, 2, "type", P3_STATIC);
|
||||
sqlite3VdbeSetColName(v, 3, "notnull", P3_STATIC);
|
||||
sqlite3VdbeSetColName(v, 4, "dflt_value", P3_STATIC);
|
||||
sqlite3VdbeSetColName(v, 5, "pk", P3_STATIC);
|
||||
sqlite3ViewGetColumnNames(pParse, pTab);
|
||||
for(i=0; i<pTab->nCol; i++){
|
||||
sqlite3VdbeAddOp(v, OP_Integer, i, 0);
|
||||
sqlite3VdbeOp3(v, OP_String8, 0, 0, pTab->aCol[i].zName, 0);
|
||||
sqlite3VdbeOp3(v, OP_String8, 0, 0,
|
||||
pTab->aCol[i].zType ? pTab->aCol[i].zType : "numeric", 0);
|
||||
sqlite3VdbeAddOp(v, OP_Integer, pTab->aCol[i].notNull, 0);
|
||||
sqlite3VdbeOp3(v, OP_String8, 0, 0,
|
||||
pTab->aCol[i].zDflt, P3_STATIC);
|
||||
sqlite3VdbeAddOp(v, OP_Integer, pTab->aCol[i].isPrimKey, 0);
|
||||
sqlite3VdbeAddOp(v, OP_Callback, 6, 0);
|
||||
}
|
||||
}
|
||||
}else
|
||||
|
||||
if( sqlite3StrICmp(zLeft, "index_info")==0 && zRight ){
|
||||
Index *pIdx;
|
||||
Table *pTab;
|
||||
if( sqlite3ReadSchema(pParse) ) goto pragma_out;
|
||||
pIdx = sqlite3FindIndex(db, zRight, zDb);
|
||||
if( pIdx ){
|
||||
int i;
|
||||
pTab = pIdx->pTable;
|
||||
sqlite3VdbeSetNumCols(v, 3);
|
||||
sqlite3VdbeSetColName(v, 0, "seqno", P3_STATIC);
|
||||
sqlite3VdbeSetColName(v, 1, "cid", P3_STATIC);
|
||||
sqlite3VdbeSetColName(v, 2, "name", P3_STATIC);
|
||||
for(i=0; i<pIdx->nColumn; i++){
|
||||
int cnum = pIdx->aiColumn[i];
|
||||
sqlite3VdbeAddOp(v, OP_Integer, i, 0);
|
||||
sqlite3VdbeAddOp(v, OP_Integer, cnum, 0);
|
||||
assert( pTab->nCol>cnum );
|
||||
sqlite3VdbeOp3(v, OP_String8, 0, 0, pTab->aCol[cnum].zName, 0);
|
||||
sqlite3VdbeAddOp(v, OP_Callback, 3, 0);
|
||||
}
|
||||
}
|
||||
}else
|
||||
|
||||
if( sqlite3StrICmp(zLeft, "index_list")==0 && zRight ){
|
||||
Index *pIdx;
|
||||
Table *pTab;
|
||||
if( sqlite3ReadSchema(pParse) ) goto pragma_out;
|
||||
pTab = sqlite3FindTable(db, zRight, zDb);
|
||||
if( pTab ){
|
||||
v = sqlite3GetVdbe(pParse);
|
||||
pIdx = pTab->pIndex;
|
||||
if( pIdx ){
|
||||
int i = 0;
|
||||
sqlite3VdbeSetNumCols(v, 3);
|
||||
sqlite3VdbeSetColName(v, 0, "seq", P3_STATIC);
|
||||
sqlite3VdbeSetColName(v, 1, "name", P3_STATIC);
|
||||
sqlite3VdbeSetColName(v, 2, "unique", P3_STATIC);
|
||||
while(pIdx){
|
||||
sqlite3VdbeAddOp(v, OP_Integer, i, 0);
|
||||
sqlite3VdbeOp3(v, OP_String8, 0, 0, pIdx->zName, 0);
|
||||
sqlite3VdbeAddOp(v, OP_Integer, pIdx->onError!=OE_None, 0);
|
||||
sqlite3VdbeAddOp(v, OP_Callback, 3, 0);
|
||||
++i;
|
||||
pIdx = pIdx->pNext;
|
||||
}
|
||||
}
|
||||
}
|
||||
}else
|
||||
|
||||
if( sqlite3StrICmp(zLeft, "foreign_key_list")==0 && zRight ){
|
||||
FKey *pFK;
|
||||
Table *pTab;
|
||||
if( sqlite3ReadSchema(pParse) ) goto pragma_out;
|
||||
pTab = sqlite3FindTable(db, zRight, zDb);
|
||||
if( pTab ){
|
||||
v = sqlite3GetVdbe(pParse);
|
||||
pFK = pTab->pFKey;
|
||||
if( pFK ){
|
||||
int i = 0;
|
||||
sqlite3VdbeSetNumCols(v, 5);
|
||||
sqlite3VdbeSetColName(v, 0, "id", P3_STATIC);
|
||||
sqlite3VdbeSetColName(v, 1, "seq", P3_STATIC);
|
||||
sqlite3VdbeSetColName(v, 2, "table", P3_STATIC);
|
||||
sqlite3VdbeSetColName(v, 3, "from", P3_STATIC);
|
||||
sqlite3VdbeSetColName(v, 4, "to", P3_STATIC);
|
||||
while(pFK){
|
||||
int j;
|
||||
for(j=0; j<pFK->nCol; j++){
|
||||
sqlite3VdbeAddOp(v, OP_Integer, i, 0);
|
||||
sqlite3VdbeAddOp(v, OP_Integer, j, 0);
|
||||
sqlite3VdbeOp3(v, OP_String8, 0, 0, pFK->zTo, 0);
|
||||
sqlite3VdbeOp3(v, OP_String8, 0, 0,
|
||||
pTab->aCol[pFK->aCol[j].iFrom].zName, 0);
|
||||
sqlite3VdbeOp3(v, OP_String8, 0, 0, pFK->aCol[j].zCol, 0);
|
||||
sqlite3VdbeAddOp(v, OP_Callback, 5, 0);
|
||||
}
|
||||
++i;
|
||||
pFK = pFK->pNextFrom;
|
||||
}
|
||||
}
|
||||
}
|
||||
}else
|
||||
|
||||
if( sqlite3StrICmp(zLeft, "database_list")==0 ){
|
||||
int i;
|
||||
if( sqlite3ReadSchema(pParse) ) goto pragma_out;
|
||||
sqlite3VdbeSetNumCols(v, 3);
|
||||
sqlite3VdbeSetColName(v, 0, "seq", P3_STATIC);
|
||||
sqlite3VdbeSetColName(v, 1, "name", P3_STATIC);
|
||||
sqlite3VdbeSetColName(v, 2, "file", P3_STATIC);
|
||||
for(i=0; i<db->nDb; i++){
|
||||
if( db->aDb[i].pBt==0 ) continue;
|
||||
assert( db->aDb[i].zName!=0 );
|
||||
sqlite3VdbeAddOp(v, OP_Integer, i, 0);
|
||||
sqlite3VdbeOp3(v, OP_String8, 0, 0, db->aDb[i].zName, 0);
|
||||
sqlite3VdbeOp3(v, OP_String8, 0, 0,
|
||||
sqlite3BtreeGetFilename(db->aDb[i].pBt), 0);
|
||||
sqlite3VdbeAddOp(v, OP_Callback, 3, 0);
|
||||
}
|
||||
}else
|
||||
|
||||
#ifndef NDEBUG
|
||||
if( sqlite3StrICmp(zLeft, "parser_trace")==0 ){
|
||||
extern void sqlite3ParserTrace(FILE*, char *);
|
||||
if( getBoolean(zRight) ){
|
||||
sqlite3ParserTrace(stdout, "parser: ");
|
||||
}else{
|
||||
sqlite3ParserTrace(0, 0);
|
||||
}
|
||||
}else
|
||||
#endif
|
||||
|
||||
if( sqlite3StrICmp(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},
|
||||
};
|
||||
|
||||
/* 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_String8, 0, 0, "ok"},
|
||||
{ OP_Callback, 1, 0, 0},
|
||||
};
|
||||
|
||||
/* Initialize the VDBE program */
|
||||
if( sqlite3ReadSchema(pParse) ) goto pragma_out;
|
||||
sqlite3VdbeSetNumCols(v, 1);
|
||||
sqlite3VdbeSetColName(v, 0, "integrity_check", P3_STATIC);
|
||||
sqlite3VdbeAddOpList(v, ArraySize(initCode), initCode);
|
||||
|
||||
/* Do an integrity check on each database file */
|
||||
for(i=0; i<db->nDb; i++){
|
||||
HashElem *x;
|
||||
int cnt = 0;
|
||||
|
||||
sqlite3CodeVerifySchema(pParse, i);
|
||||
|
||||
/* Do an integrity check of the B-Tree
|
||||
*/
|
||||
for(x=sqliteHashFirst(&db->aDb[i].tblHash); x; x=sqliteHashNext(x)){
|
||||
Table *pTab = sqliteHashData(x);
|
||||
Index *pIdx;
|
||||
sqlite3VdbeAddOp(v, OP_Integer, pTab->tnum, 0);
|
||||
cnt++;
|
||||
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
|
||||
if( sqlite3CheckIndexCollSeq(pParse, pIdx) ) goto pragma_out;
|
||||
sqlite3VdbeAddOp(v, OP_Integer, pIdx->tnum, 0);
|
||||
cnt++;
|
||||
}
|
||||
}
|
||||
assert( cnt>0 );
|
||||
sqlite3VdbeAddOp(v, OP_IntegrityCk, cnt, i);
|
||||
sqlite3VdbeAddOp(v, OP_Dup, 0, 1);
|
||||
addr = sqlite3VdbeOp3(v, OP_String8, 0, 0, "ok", P3_STATIC);
|
||||
sqlite3VdbeAddOp(v, OP_Eq, 0, addr+6);
|
||||
sqlite3VdbeOp3(v, OP_String8, 0, 0,
|
||||
sqlite3MPrintf("*** in database %s ***\n", db->aDb[i].zName),
|
||||
P3_DYNAMIC);
|
||||
sqlite3VdbeAddOp(v, OP_Pull, 1, 0);
|
||||
sqlite3VdbeAddOp(v, OP_Concat, 0, 1);
|
||||
sqlite3VdbeAddOp(v, OP_Callback, 1, 0);
|
||||
|
||||
/* Make sure all the indices are constructed correctly.
|
||||
*/
|
||||
sqlite3CodeVerifySchema(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;
|
||||
sqlite3OpenTableAndIndices(pParse, pTab, 1, OP_OpenRead);
|
||||
sqlite3VdbeAddOp(v, OP_Integer, 0, 0);
|
||||
sqlite3VdbeAddOp(v, OP_MemStore, 1, 1);
|
||||
loopTop = sqlite3VdbeAddOp(v, OP_Rewind, 1, 0);
|
||||
sqlite3VdbeAddOp(v, OP_MemIncr, 1, 0);
|
||||
for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
|
||||
int jmp2;
|
||||
static VdbeOpList idxErr[] = {
|
||||
{ OP_MemIncr, 0, 0, 0},
|
||||
{ OP_String8, 0, 0, "rowid "},
|
||||
{ OP_Recno, 1, 0, 0},
|
||||
{ OP_String8, 0, 0, " missing from index "},
|
||||
{ OP_String8, 0, 0, 0}, /* 4 */
|
||||
{ OP_Concat, 2, 0, 0},
|
||||
{ OP_Callback, 1, 0, 0},
|
||||
};
|
||||
sqlite3GenerateIndexKey(v, pIdx, 1);
|
||||
jmp2 = sqlite3VdbeAddOp(v, OP_Found, j+2, 0);
|
||||
addr = sqlite3VdbeAddOpList(v, ArraySize(idxErr), idxErr);
|
||||
sqlite3VdbeChangeP3(v, addr+4, pIdx->zName, P3_STATIC);
|
||||
sqlite3VdbeChangeP2(v, jmp2, sqlite3VdbeCurrentAddr(v));
|
||||
}
|
||||
sqlite3VdbeAddOp(v, OP_Next, 1, loopTop+1);
|
||||
sqlite3VdbeChangeP2(v, loopTop, sqlite3VdbeCurrentAddr(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_String8, 0, 0, "wrong # of entries in index "},
|
||||
{ OP_String8, 0, 0, 0}, /* 10 */
|
||||
{ OP_Concat, 0, 0, 0},
|
||||
{ OP_Callback, 1, 0, 0},
|
||||
};
|
||||
if( pIdx->tnum==0 ) continue;
|
||||
addr = sqlite3VdbeAddOpList(v, ArraySize(cntIdx), cntIdx);
|
||||
sqlite3VdbeChangeP1(v, addr+2, j+2);
|
||||
sqlite3VdbeChangeP2(v, addr+2, addr+5);
|
||||
sqlite3VdbeChangeP1(v, addr+4, j+2);
|
||||
sqlite3VdbeChangeP2(v, addr+4, addr+3);
|
||||
sqlite3VdbeChangeP2(v, addr+7, addr+ArraySize(cntIdx));
|
||||
sqlite3VdbeChangeP3(v, addr+10, pIdx->zName, P3_STATIC);
|
||||
}
|
||||
}
|
||||
}
|
||||
addr = sqlite3VdbeAddOpList(v, ArraySize(endCode), endCode);
|
||||
sqlite3VdbeChangeP2(v, addr+2, addr+ArraySize(endCode));
|
||||
}else
|
||||
/*
|
||||
** PRAGMA encoding
|
||||
** PRAGMA encoding = "utf-8"|"utf-16"|"utf-16le"|"utf-16be"
|
||||
**
|
||||
** In it's first form, this pragma returns the encoding of the main
|
||||
** database. If the database is not initialized, it is initialized now.
|
||||
**
|
||||
** The second form of this pragma is a no-op if the main database file
|
||||
** has not already been initialized. In this case it sets the default
|
||||
** encoding that will be used for the main database file if a new file
|
||||
** is created. If an existing main database file is opened, then the
|
||||
** default text encoding for the existing database is used.
|
||||
**
|
||||
** In all cases new databases created using the ATTACH command are
|
||||
** created to use the same default text encoding as the main database. If
|
||||
** the main database has not been initialized and/or created when ATTACH
|
||||
** is executed, this is done before the ATTACH operation.
|
||||
**
|
||||
** In the second form this pragma sets the text encoding to be used in
|
||||
** new database files created using this database handle. It is only
|
||||
** useful if invoked immediately after the main database i
|
||||
*/
|
||||
if( sqlite3StrICmp(zLeft, "encoding")==0 ){
|
||||
struct EncName {
|
||||
char *zName;
|
||||
u8 enc;
|
||||
} encnames[] = {
|
||||
{ "UTF-8", SQLITE_UTF8 },
|
||||
{ "UTF8", SQLITE_UTF8 },
|
||||
{ "UTF-16le", SQLITE_UTF16LE },
|
||||
{ "UTF16le", SQLITE_UTF16LE },
|
||||
{ "UTF-16be", SQLITE_UTF16BE },
|
||||
{ "UTF16be", SQLITE_UTF16BE },
|
||||
{ "UTF-16", 0 /* Filled in at run-time */ },
|
||||
{ "UTF16", 0 /* Filled in at run-time */ },
|
||||
{ 0, 0 }
|
||||
};
|
||||
struct EncName *pEnc;
|
||||
encnames[6].enc = encnames[7].enc = SQLITE_UTF16NATIVE;
|
||||
if( !zRight ){ /* "PRAGMA encoding" */
|
||||
if( sqlite3ReadSchema(pParse) ) goto pragma_out;
|
||||
sqlite3VdbeSetNumCols(v, 1);
|
||||
sqlite3VdbeSetColName(v, 0, "encoding", P3_STATIC);
|
||||
sqlite3VdbeAddOp(v, OP_String8, 0, 0);
|
||||
for(pEnc=&encnames[0]; pEnc->zName; pEnc++){
|
||||
if( pEnc->enc==pParse->db->enc ){
|
||||
sqlite3VdbeChangeP3(v, -1, pEnc->zName, P3_STATIC);
|
||||
break;
|
||||
}
|
||||
}
|
||||
sqlite3VdbeAddOp(v, OP_Callback, 1, 0);
|
||||
}else{ /* "PRAGMA encoding = XXX" */
|
||||
/* Only change the value of sqlite.enc if the database handle is not
|
||||
** initialized. If the main database exists, the new sqlite.enc value
|
||||
** will be overwritten when the schema is next loaded. If it does not
|
||||
** already exists, it will be created to use the new encoding value.
|
||||
*/
|
||||
if( !(pParse->db->flags&SQLITE_Initialized) ){
|
||||
for(pEnc=&encnames[0]; pEnc->zName; pEnc++){
|
||||
if( 0==sqlite3StrICmp(zRight, pEnc->zName) ){
|
||||
pParse->db->enc = pEnc->enc;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( !pEnc->zName ){
|
||||
sqlite3ErrorMsg(pParse, "unsupported encoding: %s", zRight);
|
||||
}
|
||||
}
|
||||
}
|
||||
}else
|
||||
|
||||
#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
|
||||
/*
|
||||
** Report the current state of file logs for all databases
|
||||
*/
|
||||
if( sqlite3StrICmp(zLeft, "lock_status")==0 ){
|
||||
static char *azLockName[] = {
|
||||
"unlocked", "shared", "reserved", "pending", "exclusive"
|
||||
};
|
||||
int i;
|
||||
Vdbe *v = sqlite3GetVdbe(pParse);
|
||||
sqlite3VdbeSetNumCols(v, 2);
|
||||
sqlite3VdbeSetColName(v, 0, "database", P3_STATIC);
|
||||
sqlite3VdbeSetColName(v, 1, "status", P3_STATIC);
|
||||
for(i=0; i<db->nDb; i++){
|
||||
Btree *pBt;
|
||||
Pager *pPager;
|
||||
if( db->aDb[i].zName==0 ) continue;
|
||||
sqlite3VdbeOp3(v, OP_String, 0, 0, db->aDb[i].zName, P3_STATIC);
|
||||
pBt = db->aDb[i].pBt;
|
||||
if( pBt==0 || (pPager = sqlite3BtreePager(pBt))==0 ){
|
||||
sqlite3VdbeOp3(v, OP_String, 0, 0, "closed", P3_STATIC);
|
||||
}else{
|
||||
int j = sqlite3pager_lockstate(pPager);
|
||||
sqlite3VdbeOp3(v, OP_String, 0, 0,
|
||||
(j>=0 && j<=4) ? azLockName[j] : "unknown", P3_STATIC);
|
||||
}
|
||||
sqlite3VdbeAddOp(v, OP_Callback, 2, 0);
|
||||
}
|
||||
}else
|
||||
#endif
|
||||
|
||||
{}
|
||||
pragma_out:
|
||||
sqliteFree(zLeft);
|
||||
sqliteFree(zRight);
|
||||
}
|
|
@ -0,0 +1,824 @@
|
|||
/*
|
||||
** The "printf" code that follows dates from the 1980's. It is in
|
||||
** the public domain. The original comments are included here for
|
||||
** completeness. They are very out-of-date but might be useful as
|
||||
** an historical reference. Most of the "enhancements" have been backed
|
||||
** out so that the functionality is now the same as standard printf().
|
||||
**
|
||||
**************************************************************************
|
||||
**
|
||||
** The following modules is an enhanced replacement for the "printf" subroutines
|
||||
** found in the standard C library. The following enhancements are
|
||||
** supported:
|
||||
**
|
||||
** + Additional functions. The standard set of "printf" functions
|
||||
** includes printf, fprintf, sprintf, vprintf, vfprintf, and
|
||||
** vsprintf. This module adds the following:
|
||||
**
|
||||
** * snprintf -- Works like sprintf, but has an extra argument
|
||||
** which is the size of the buffer written to.
|
||||
**
|
||||
** * mprintf -- Similar to sprintf. Writes output to memory
|
||||
** obtained from malloc.
|
||||
**
|
||||
** * xprintf -- Calls a function to dispose of output.
|
||||
**
|
||||
** * nprintf -- No output, but returns the number of characters
|
||||
** that would have been output by printf.
|
||||
**
|
||||
** * A v- version (ex: vsnprintf) of every function is also
|
||||
** supplied.
|
||||
**
|
||||
** + A few extensions to the formatting notation are supported:
|
||||
**
|
||||
** * The "=" flag (similar to "-") causes the output to be
|
||||
** be centered in the appropriately sized field.
|
||||
**
|
||||
** * The %b field outputs an integer in binary notation.
|
||||
**
|
||||
** * The %c field now accepts a precision. The character output
|
||||
** is repeated by the number of times the precision specifies.
|
||||
**
|
||||
** * The %' field works like %c, but takes as its character the
|
||||
** next character of the format string, instead of the next
|
||||
** argument. For example, printf("%.78'-") prints 78 minus
|
||||
** signs, the same as printf("%.78c",'-').
|
||||
**
|
||||
** + When compiled using GCC on a SPARC, this version of printf is
|
||||
** faster than the library printf for SUN OS 4.1.
|
||||
**
|
||||
** + All functions are fully reentrant.
|
||||
**
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
|
||||
/*
|
||||
** Conversion types fall into various categories as defined by the
|
||||
** following enumeration.
|
||||
*/
|
||||
#define etRADIX 1 /* Integer types. %d, %x, %o, and so forth */
|
||||
#define etFLOAT 2 /* Floating point. %f */
|
||||
#define etEXP 3 /* Exponentional notation. %e and %E */
|
||||
#define etGENERIC 4 /* Floating or exponential, depending on exponent. %g */
|
||||
#define etSIZE 5 /* Return number of characters processed so far. %n */
|
||||
#define etSTRING 6 /* Strings. %s */
|
||||
#define etDYNSTRING 7 /* Dynamically allocated strings. %z */
|
||||
#define etPERCENT 8 /* Percent symbol. %% */
|
||||
#define etCHARX 9 /* Characters. %c */
|
||||
#define etERROR 10 /* Used to indicate no such conversion type */
|
||||
/* The rest are extensions, not normally found in printf() */
|
||||
#define etCHARLIT 11 /* Literal characters. %' */
|
||||
#define etSQLESCAPE 12 /* Strings with '\'' doubled. %q */
|
||||
#define etSQLESCAPE2 13 /* Strings with '\'' doubled and enclosed in '',
|
||||
NULL pointers replaced by SQL NULL. %Q */
|
||||
#define etTOKEN 14 /* a pointer to a Token structure */
|
||||
#define etSRCLIST 15 /* a pointer to a SrcList */
|
||||
#define etPOINTER 16 /* The %p conversion */
|
||||
|
||||
|
||||
/*
|
||||
** An "etByte" is an 8-bit unsigned value.
|
||||
*/
|
||||
typedef unsigned char etByte;
|
||||
|
||||
/*
|
||||
** Each builtin conversion character (ex: the 'd' in "%d") is described
|
||||
** by an instance of the following structure
|
||||
*/
|
||||
typedef struct et_info { /* Information about each format field */
|
||||
char fmttype; /* The format field code letter */
|
||||
etByte base; /* The base for radix conversion */
|
||||
etByte flags; /* One or more of FLAG_ constants below */
|
||||
etByte type; /* Conversion paradigm */
|
||||
etByte charset; /* Offset into aDigits[] of the digits string */
|
||||
etByte prefix; /* Offset into aPrefix[] of the prefix string */
|
||||
} et_info;
|
||||
|
||||
/*
|
||||
** Allowed values for et_info.flags
|
||||
*/
|
||||
#define FLAG_SIGNED 1 /* True if the value to convert is signed */
|
||||
#define FLAG_INTERN 2 /* True if for internal use only */
|
||||
|
||||
|
||||
/*
|
||||
** The following table is searched linearly, so it is good to put the
|
||||
** most frequently used conversion types first.
|
||||
*/
|
||||
static const char aDigits[] = "0123456789ABCDEF0123456789abcdef";
|
||||
static const char aPrefix[] = "-x0\000X0";
|
||||
static et_info fmtinfo[] = {
|
||||
{ 'd', 10, 1, etRADIX, 0, 0 },
|
||||
{ 's', 0, 0, etSTRING, 0, 0 },
|
||||
{ 'z', 0, 2, etDYNSTRING, 0, 0 },
|
||||
{ 'q', 0, 0, etSQLESCAPE, 0, 0 },
|
||||
{ 'Q', 0, 0, etSQLESCAPE2, 0, 0 },
|
||||
{ 'c', 0, 0, etCHARX, 0, 0 },
|
||||
{ 'o', 8, 0, etRADIX, 0, 2 },
|
||||
{ 'u', 10, 0, etRADIX, 0, 0 },
|
||||
{ 'x', 16, 0, etRADIX, 16, 1 },
|
||||
{ 'X', 16, 0, etRADIX, 0, 4 },
|
||||
{ 'f', 0, 1, etFLOAT, 0, 0 },
|
||||
{ 'e', 0, 1, etEXP, 30, 0 },
|
||||
{ 'E', 0, 1, etEXP, 14, 0 },
|
||||
{ 'g', 0, 1, etGENERIC, 30, 0 },
|
||||
{ 'G', 0, 1, etGENERIC, 14, 0 },
|
||||
{ 'i', 10, 1, etRADIX, 0, 0 },
|
||||
{ 'n', 0, 0, etSIZE, 0, 0 },
|
||||
{ '%', 0, 0, etPERCENT, 0, 0 },
|
||||
{ 'p', 16, 0, etPOINTER, 0, 1 },
|
||||
{ 'T', 0, 2, etTOKEN, 0, 0 },
|
||||
{ 'S', 0, 2, etSRCLIST, 0, 0 },
|
||||
};
|
||||
#define etNINFO (sizeof(fmtinfo)/sizeof(fmtinfo[0]))
|
||||
|
||||
/*
|
||||
** If 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 */
|
||||
etByte flag_longlong; /* True if the "ll" flag is present */
|
||||
UINT64_TYPE 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
|
||||
|
||||
func(arg,"",0);
|
||||
count = length = 0;
|
||||
bufpt = 0;
|
||||
for(; (c=(*fmt))!=0; ++fmt){
|
||||
if( c!='%' ){
|
||||
int amt;
|
||||
bufpt = (char *)fmt;
|
||||
amt = 1;
|
||||
while( (c=(*++fmt))!='%' && c!=0 ) amt++;
|
||||
(*func)(arg,bufpt,amt);
|
||||
count += amt;
|
||||
if( c==0 ) break;
|
||||
}
|
||||
if( (c=(*++fmt))==0 ){
|
||||
errorflag = 1;
|
||||
(*func)(arg,"%",1);
|
||||
count++;
|
||||
break;
|
||||
}
|
||||
/* Find out what flags are present */
|
||||
flag_leftjustify = flag_plussign = flag_blanksign =
|
||||
flag_alternateform = flag_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;
|
||||
if( c=='l' ){
|
||||
flag_longlong = 1;
|
||||
c = *++fmt;
|
||||
}else{
|
||||
flag_longlong = 0;
|
||||
}
|
||||
}else{
|
||||
flag_long = flag_longlong = 0;
|
||||
}
|
||||
/* Fetch the info entry for the field */
|
||||
infop = 0;
|
||||
xtype = etERROR;
|
||||
for(idx=0; idx<etNINFO; idx++){
|
||||
if( c==fmtinfo[idx].fmttype ){
|
||||
infop = &fmtinfo[idx];
|
||||
if( useExtended || (infop->flags & FLAG_INTERN)==0 ){
|
||||
xtype = infop->type;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
zExtra = 0;
|
||||
|
||||
/*
|
||||
** 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_longlong TRUE if the letter 'll' (ell ell) prefixed
|
||||
** the conversion character.
|
||||
** flag_blanksign TRUE if a ' ' is present.
|
||||
** width The specified field width. This is
|
||||
** always non-negative. Zero is the default.
|
||||
** precision The specified precision. The default
|
||||
** is -1.
|
||||
** xtype The class of the conversion.
|
||||
** infop Pointer to the appropriate info struct.
|
||||
*/
|
||||
switch( xtype ){
|
||||
case etPOINTER:
|
||||
flag_longlong = sizeof(char*)==sizeof(i64);
|
||||
flag_long = sizeof(char*)==sizeof(long int);
|
||||
/* Fall through into the next case */
|
||||
case etRADIX:
|
||||
if( infop->flags & FLAG_SIGNED ){
|
||||
i64 v;
|
||||
if( flag_longlong ) v = va_arg(ap,i64);
|
||||
else if( flag_long ) v = va_arg(ap,long int);
|
||||
else v = va_arg(ap,int);
|
||||
if( v<0 ){
|
||||
longvalue = -v;
|
||||
prefix = '-';
|
||||
}else{
|
||||
longvalue = v;
|
||||
if( flag_plussign ) prefix = '+';
|
||||
else if( flag_blanksign ) prefix = ' ';
|
||||
else prefix = 0;
|
||||
}
|
||||
}else{
|
||||
if( flag_longlong ) longvalue = va_arg(ap,u64);
|
||||
else if( flag_long ) longvalue = va_arg(ap,unsigned long int);
|
||||
else longvalue = va_arg(ap,unsigned int);
|
||||
prefix = 0;
|
||||
}
|
||||
if( longvalue==0 ) flag_alternateform = 0;
|
||||
if( flag_zeropad && precision<width-(prefix!=0) ){
|
||||
precision = width-(prefix!=0);
|
||||
}
|
||||
bufpt = &buf[etBUFSIZE-1];
|
||||
{
|
||||
register const char *cset; /* Use registers for speed */
|
||||
register int base;
|
||||
cset = &aDigits[infop->charset];
|
||||
base = infop->base;
|
||||
do{ /* Convert to ascii */
|
||||
*(--bufpt) = cset[longvalue%base];
|
||||
longvalue = longvalue/base;
|
||||
}while( longvalue>0 );
|
||||
}
|
||||
length = &buf[etBUFSIZE-1]-bufpt;
|
||||
for(idx=precision-length; idx>0; idx--){
|
||||
*(--bufpt) = '0'; /* Zero pad */
|
||||
}
|
||||
if( prefix ) *(--bufpt) = prefix; /* Add sign */
|
||||
if( flag_alternateform && infop->prefix ){ /* Add "0" or "0x" */
|
||||
const char *pre;
|
||||
char x;
|
||||
pre = &aPrefix[infop->prefix];
|
||||
if( *bufpt!=pre[0] ){
|
||||
for(; (x=(*pre))!=0; pre++) *(--bufpt) = x;
|
||||
}
|
||||
}
|
||||
length = &buf[etBUFSIZE-1]-bufpt;
|
||||
break;
|
||||
case etFLOAT:
|
||||
case etEXP:
|
||||
case etGENERIC:
|
||||
realvalue = va_arg(ap,double);
|
||||
#ifndef 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++) = aDigits[infop->charset];
|
||||
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*);
|
||||
if( pToken && pToken->z ){
|
||||
(*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 ){
|
||||
if( nNewChar>0 ){
|
||||
memcpy(&pM->zText[pM->nChar], zNewText, nNewChar);
|
||||
pM->nChar += nNewChar;
|
||||
}
|
||||
pM->zText[pM->nChar] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** This routine is a wrapper around xprintf() that invokes mout() as
|
||||
** the consumer.
|
||||
*/
|
||||
static char *base_vprintf(
|
||||
void *(*xRealloc)(void*,int), /* Routine to realloc memory. May be NULL */
|
||||
int useInternal, /* Use internal %-conversions if true */
|
||||
char *zInitBuf, /* Initially write here, before mallocing */
|
||||
int nInitBuf, /* Size of zInitBuf[] */
|
||||
const char *zFormat, /* format string */
|
||||
va_list ap /* arguments */
|
||||
){
|
||||
struct sgMprintf sM;
|
||||
sM.zBase = sM.zText = zInitBuf;
|
||||
sM.nChar = sM.nTotal = 0;
|
||||
sM.nAlloc = nInitBuf;
|
||||
sM.xRealloc = xRealloc;
|
||||
vxprintf(mout, &sM, useInternal, zFormat, ap);
|
||||
if( xRealloc ){
|
||||
if( sM.zText==sM.zBase ){
|
||||
sM.zText = xRealloc(0, sM.nChar+1);
|
||||
if( sM.zText ){
|
||||
memcpy(sM.zText, sM.zBase, sM.nChar+1);
|
||||
}
|
||||
}else if( sM.nAlloc>sM.nChar+10 ){
|
||||
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 *sqlite3VMPrintf(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 *sqlite3MPrintf(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 *sqlite3_mprintf(const char *zFormat, ...){
|
||||
va_list ap;
|
||||
char *z;
|
||||
char zBuf[200];
|
||||
|
||||
va_start(ap,zFormat);
|
||||
z = base_vprintf((void*(*)(void*,int))realloc, 0,
|
||||
zBuf, sizeof(zBuf), zFormat, ap);
|
||||
va_end(ap);
|
||||
return z;
|
||||
}
|
||||
|
||||
/* This is the varargs version of sqlite3_mprintf.
|
||||
*/
|
||||
char *sqlite3_vmprintf(const char *zFormat, va_list ap){
|
||||
char zBuf[200];
|
||||
return base_vprintf((void*(*)(void*,int))realloc, 0,
|
||||
zBuf, sizeof(zBuf), zFormat, ap);
|
||||
}
|
||||
|
||||
/*
|
||||
** sqlite3_snprintf() works like snprintf() except that it ignores the
|
||||
** current locale settings. This is important for SQLite because we
|
||||
** are not able to use a "," as the decimal point in place of "." as
|
||||
** specified by some locales.
|
||||
*/
|
||||
char *sqlite3_snprintf(int n, char *zBuf, const char *zFormat, ...){
|
||||
char *z;
|
||||
va_list ap;
|
||||
|
||||
va_start(ap,zFormat);
|
||||
z = base_vprintf(0, 0, zBuf, n, zFormat, ap);
|
||||
va_end(ap);
|
||||
return z;
|
||||
}
|
||||
|
||||
#if defined(SQLITE_TEST) || defined(SQLITE_DEBUG)
|
||||
/*
|
||||
** A version of printf() that understands %lld. Used for debugging.
|
||||
** The printf() built into some versions of windows does not understand %lld
|
||||
** and segfaults if you give it a long long int.
|
||||
*/
|
||||
void sqlite3DebugPrintf(const char *zFormat, ...){
|
||||
extern int getpid(void);
|
||||
va_list ap;
|
||||
char zBuf[500];
|
||||
va_start(ap, zFormat);
|
||||
base_vprintf(0, 0, zBuf, sizeof(zBuf), zFormat, ap);
|
||||
va_end(ap);
|
||||
fprintf(stdout,"%d: %s", getpid(), zBuf);
|
||||
fflush(stdout);
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,100 @@
|
|||
/*
|
||||
** 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.12 2004/05/08 08:23:32 danielk1977 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;
|
||||
sqlite3OsRandomSeed(k);
|
||||
for(i=0; i<256; i++){
|
||||
prng.s[i] = i;
|
||||
}
|
||||
for(i=0; i<256; i++){
|
||||
prng.j += prng.s[i] + k[i];
|
||||
t = prng.s[prng.j];
|
||||
prng.s[prng.j] = prng.s[i];
|
||||
prng.s[i] = t;
|
||||
}
|
||||
prng.isInit = 1;
|
||||
}
|
||||
|
||||
/* Generate and return single random byte
|
||||
*/
|
||||
prng.i++;
|
||||
t = prng.s[prng.i];
|
||||
prng.j += t;
|
||||
prng.s[prng.i] = prng.s[prng.j];
|
||||
prng.s[prng.j] = t;
|
||||
t += prng.s[prng.i];
|
||||
return prng.s[t];
|
||||
}
|
||||
|
||||
/*
|
||||
** Return N random bytes.
|
||||
*/
|
||||
void sqlite3Randomness(int N, void *pBuf){
|
||||
unsigned char *zBuf = pBuf;
|
||||
sqlite3OsEnterMutex();
|
||||
while( N-- ){
|
||||
*(zBuf++) = randomByte();
|
||||
}
|
||||
sqlite3OsLeaveMutex();
|
||||
}
|
||||
|
||||
|
||||
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,195 @@
|
|||
/*
|
||||
** 2001 September 15
|
||||
**
|
||||
** The author disclaims copyright to this source code. In place of
|
||||
** a legal notice, here is a blessing:
|
||||
**
|
||||
** May you do good and not evil.
|
||||
** May you find forgiveness for yourself and forgive others.
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
*************************************************************************
|
||||
** This file contains the sqlite3_get_table() and sqlite3_free_table()
|
||||
** interface routines. These are just wrappers around the main
|
||||
** interface routine of sqlite3_exec().
|
||||
**
|
||||
** These routines are in a separate files so that they will not be linked
|
||||
** if they are not used.
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "sqliteInt.h"
|
||||
|
||||
/*
|
||||
** This structure is used to pass data from sqlite3_get_table() through
|
||||
** to the callback function is uses to build the result.
|
||||
*/
|
||||
typedef struct TabResult {
|
||||
char **azResult;
|
||||
char *zErrMsg;
|
||||
int nResult;
|
||||
int nAlloc;
|
||||
int nRow;
|
||||
int nColumn;
|
||||
int nData;
|
||||
int rc;
|
||||
} TabResult;
|
||||
|
||||
/*
|
||||
** This routine is called once for each row in the result table. Its job
|
||||
** is to fill in the TabResult structure appropriately, allocating new
|
||||
** memory as necessary.
|
||||
*/
|
||||
static int sqlite3_get_table_cb(void *pArg, int nCol, char **argv, char **colv){
|
||||
TabResult *p = (TabResult*)pArg;
|
||||
int need;
|
||||
int i;
|
||||
char *z;
|
||||
|
||||
/* Make sure there is enough space in p->azResult to hold everything
|
||||
** we need to remember from this invocation of the callback.
|
||||
*/
|
||||
if( p->nRow==0 && argv!=0 ){
|
||||
need = nCol*2;
|
||||
}else{
|
||||
need = nCol;
|
||||
}
|
||||
if( p->nData + need >= p->nAlloc ){
|
||||
char **azNew;
|
||||
p->nAlloc = p->nAlloc*2 + need + 1;
|
||||
azNew = realloc( p->azResult, sizeof(char*)*p->nAlloc );
|
||||
if( azNew==0 ) goto malloc_failed;
|
||||
p->azResult = azNew;
|
||||
}
|
||||
|
||||
/* If this is the first row, then generate an extra row containing
|
||||
** the names of all columns.
|
||||
*/
|
||||
if( p->nRow==0 ){
|
||||
p->nColumn = nCol;
|
||||
for(i=0; i<nCol; i++){
|
||||
if( colv[i]==0 ){
|
||||
z = 0;
|
||||
}else{
|
||||
z = malloc( strlen(colv[i])+1 );
|
||||
if( z==0 ) goto malloc_failed;
|
||||
strcpy(z, colv[i]);
|
||||
}
|
||||
p->azResult[p->nData++] = z;
|
||||
}
|
||||
}else if( p->nColumn!=nCol ){
|
||||
sqlite3SetString(&p->zErrMsg,
|
||||
"sqlite3_get_table() called with two or more incompatible queries",
|
||||
(char*)0);
|
||||
p->rc = SQLITE_ERROR;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Copy over the row data
|
||||
*/
|
||||
if( argv!=0 ){
|
||||
for(i=0; i<nCol; i++){
|
||||
if( argv[i]==0 ){
|
||||
z = 0;
|
||||
}else{
|
||||
z = malloc( strlen(argv[i])+1 );
|
||||
if( z==0 ) goto malloc_failed;
|
||||
strcpy(z, argv[i]);
|
||||
}
|
||||
p->azResult[p->nData++] = z;
|
||||
}
|
||||
p->nRow++;
|
||||
}
|
||||
return 0;
|
||||
|
||||
malloc_failed:
|
||||
p->rc = SQLITE_NOMEM;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
** Query the database. But instead of invoking a callback for each row,
|
||||
** malloc() for space to hold the result and return the entire results
|
||||
** at the conclusion of the call.
|
||||
**
|
||||
** The result that is written to ***pazResult is held in memory obtained
|
||||
** from malloc(). But the caller cannot free this memory directly.
|
||||
** Instead, the entire table should be passed to sqlite3_free_table() when
|
||||
** the calling procedure is finished using it.
|
||||
*/
|
||||
int sqlite3_get_table(
|
||||
sqlite3 *db, /* The database on which the SQL executes */
|
||||
const char *zSql, /* The SQL to be executed */
|
||||
char ***pazResult, /* Write the result table here */
|
||||
int *pnRow, /* Write the number of rows in the result here */
|
||||
int *pnColumn, /* Write the number of columns of result here */
|
||||
char **pzErrMsg /* Write error messages here */
|
||||
){
|
||||
int rc;
|
||||
TabResult res;
|
||||
if( pazResult==0 ){ return SQLITE_ERROR; }
|
||||
*pazResult = 0;
|
||||
if( pnColumn ) *pnColumn = 0;
|
||||
if( pnRow ) *pnRow = 0;
|
||||
res.zErrMsg = 0;
|
||||
res.nResult = 0;
|
||||
res.nRow = 0;
|
||||
res.nColumn = 0;
|
||||
res.nData = 1;
|
||||
res.nAlloc = 20;
|
||||
res.rc = SQLITE_OK;
|
||||
res.azResult = malloc( sizeof(char*)*res.nAlloc );
|
||||
if( res.azResult==0 ) return SQLITE_NOMEM;
|
||||
res.azResult[0] = 0;
|
||||
rc = sqlite3_exec(db, zSql, sqlite3_get_table_cb, &res, pzErrMsg);
|
||||
if( res.azResult ){
|
||||
res.azResult[0] = (char*)res.nData;
|
||||
}
|
||||
if( rc==SQLITE_ABORT ){
|
||||
sqlite3_free_table(&res.azResult[1]);
|
||||
if( res.zErrMsg ){
|
||||
if( pzErrMsg ){
|
||||
free(*pzErrMsg);
|
||||
*pzErrMsg = sqlite3_mprintf("%s",res.zErrMsg);
|
||||
}
|
||||
sqliteFree(res.zErrMsg);
|
||||
}
|
||||
db->errCode = res.rc;
|
||||
return res.rc;
|
||||
}
|
||||
sqliteFree(res.zErrMsg);
|
||||
if( rc!=SQLITE_OK ){
|
||||
sqlite3_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 ){
|
||||
sqlite3_free_table(&res.azResult[1]);
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
res.nAlloc = res.nData+1;
|
||||
res.azResult = azNew;
|
||||
}
|
||||
*pazResult = &res.azResult[1];
|
||||
if( pnColumn ) *pnColumn = res.nColumn;
|
||||
if( pnRow ) *pnRow = res.nRow;
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** This routine frees the space the sqlite3_get_table() malloced.
|
||||
*/
|
||||
void sqlite3_free_table(
|
||||
char **azResult /* Result returned from from sqlite3_get_table() */
|
||||
){
|
||||
if( azResult ){
|
||||
int i, n;
|
||||
azResult--;
|
||||
if( azResult==0 ) return;
|
||||
n = (int)azResult[0];
|
||||
for(i=1; i<n; i++){ if( azResult[i] ) free(azResult[i]); }
|
||||
free(azResult);
|
||||
}
|
||||
}
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,765 @@
|
|||
/*
|
||||
** 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.90 2004/10/05 02:41:43 drh 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, },
|
||||
{ "COLLATE", TK_COLLATE, },
|
||||
{ "COMMIT", TK_COMMIT, },
|
||||
{ "CONFLICT", TK_CONFLICT, },
|
||||
{ "CONSTRAINT", TK_CONSTRAINT, },
|
||||
{ "CREATE", TK_CREATE, },
|
||||
{ "CROSS", TK_JOIN_KW, },
|
||||
{ "DATABASE", TK_DATABASE, },
|
||||
{ "DEFAULT", TK_DEFAULT, },
|
||||
{ "DEFERRED", TK_DEFERRED, },
|
||||
{ "DEFERRABLE", TK_DEFERRABLE, },
|
||||
{ "DELETE", TK_DELETE, },
|
||||
{ "DESC", TK_DESC, },
|
||||
{ "DETACH", TK_DETACH, },
|
||||
{ "DISTINCT", TK_DISTINCT, },
|
||||
{ "DROP", TK_DROP, },
|
||||
{ "END", TK_END, },
|
||||
{ "EACH", TK_EACH, },
|
||||
{ "ELSE", TK_ELSE, },
|
||||
{ "EXCEPT", TK_EXCEPT, },
|
||||
{ "EXCLUSIVE", TK_EXCLUSIVE, },
|
||||
{ "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 sqlite3KeywordCode(const char *z, int n){
|
||||
int h, i;
|
||||
Keyword *p;
|
||||
static char needInit = 1;
|
||||
if( needInit ){
|
||||
/* Initialize the keyword hash table */
|
||||
sqlite3OsEnterMutex();
|
||||
if( needInit ){
|
||||
int nk;
|
||||
nk = sizeof(aKeywordTable)/sizeof(aKeywordTable[0]);
|
||||
for(i=0, p=aKeywordTable; i<nk; i++, p++){
|
||||
const char *zName = p->zName;
|
||||
int len = p->len = strlen(zName);
|
||||
h = sqlite3HashNoCase(zName, len) % KEY_HASH_SIZE;
|
||||
p->iNext = aiHashTable[h];
|
||||
aiHashTable[h] = i+1;
|
||||
}
|
||||
needInit = 0;
|
||||
}
|
||||
sqlite3OsLeaveMutex();
|
||||
}
|
||||
h = sqlite3HashNoCase(z, n) % KEY_HASH_SIZE;
|
||||
for(i=aiHashTable[h]; i; i=p->iNext){
|
||||
p = &aKeywordTable[i-1];
|
||||
if( p->len==n && sqlite3StrNICmp(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 */
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, /* 3x */
|
||||
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 4x */
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, /* 5x */
|
||||
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 6x */
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, /* 7x */
|
||||
};
|
||||
|
||||
#define IdChar(C) (((c=C)&0x80)!=0 || (c>0x2f && isIdChar[c-0x30]))
|
||||
|
||||
/*
|
||||
** 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, c;
|
||||
switch( *z ){
|
||||
case ' ': case '\t': case '\n': case '\f': case '\r': {
|
||||
for(i=1; isspace(z[i]); i++){}
|
||||
*tokenType = TK_SPACE;
|
||||
return i;
|
||||
}
|
||||
case '-': {
|
||||
if( z[1]=='-' ){
|
||||
for(i=2; (c=z[i])!=0 && c!='\n'; i++){}
|
||||
*tokenType = TK_COMMENT;
|
||||
return i;
|
||||
}
|
||||
*tokenType = TK_MINUS;
|
||||
return 1;
|
||||
}
|
||||
case '(': {
|
||||
*tokenType = TK_LP;
|
||||
return 1;
|
||||
}
|
||||
case ')': {
|
||||
*tokenType = TK_RP;
|
||||
return 1;
|
||||
}
|
||||
case ';': {
|
||||
*tokenType = TK_SEMI;
|
||||
return 1;
|
||||
}
|
||||
case '+': {
|
||||
*tokenType = TK_PLUS;
|
||||
return 1;
|
||||
}
|
||||
case '*': {
|
||||
*tokenType = TK_STAR;
|
||||
return 1;
|
||||
}
|
||||
case '/': {
|
||||
if( z[1]!='*' || z[2]==0 ){
|
||||
*tokenType = TK_SLASH;
|
||||
return 1;
|
||||
}
|
||||
for(i=3, c=z[2]; (c!='*' || z[i]!='/') && (c=z[i])!=0; i++){}
|
||||
if( c ) i++;
|
||||
*tokenType = TK_COMMENT;
|
||||
return i;
|
||||
}
|
||||
case '%': {
|
||||
*tokenType = TK_REM;
|
||||
return 1;
|
||||
}
|
||||
case '=': {
|
||||
*tokenType = TK_EQ;
|
||||
return 1 + (z[1]=='=');
|
||||
}
|
||||
case '<': {
|
||||
if( (c=z[1])=='=' ){
|
||||
*tokenType = TK_LE;
|
||||
return 2;
|
||||
}else if( c=='>' ){
|
||||
*tokenType = TK_NE;
|
||||
return 2;
|
||||
}else if( c=='<' ){
|
||||
*tokenType = TK_LSHIFT;
|
||||
return 2;
|
||||
}else{
|
||||
*tokenType = TK_LT;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
case '>': {
|
||||
if( (c=z[1])=='=' ){
|
||||
*tokenType = TK_GE;
|
||||
return 2;
|
||||
}else if( c=='>' ){
|
||||
*tokenType = TK_RSHIFT;
|
||||
return 2;
|
||||
}else{
|
||||
*tokenType = TK_GT;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
case '!': {
|
||||
if( z[1]!='=' ){
|
||||
*tokenType = TK_ILLEGAL;
|
||||
return 2;
|
||||
}else{
|
||||
*tokenType = TK_NE;
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
case '|': {
|
||||
if( z[1]!='|' ){
|
||||
*tokenType = TK_BITOR;
|
||||
return 1;
|
||||
}else{
|
||||
*tokenType = TK_CONCAT;
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
case ',': {
|
||||
*tokenType = TK_COMMA;
|
||||
return 1;
|
||||
}
|
||||
case '&': {
|
||||
*tokenType = TK_BITAND;
|
||||
return 1;
|
||||
}
|
||||
case '~': {
|
||||
*tokenType = TK_BITNOT;
|
||||
return 1;
|
||||
}
|
||||
case '\'': case '"': {
|
||||
int delim = z[0];
|
||||
for(i=1; (c=z[i])!=0; i++){
|
||||
if( c==delim ){
|
||||
if( z[i+1]==delim ){
|
||||
i++;
|
||||
}else{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if( c ) 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, c=z[0]; c!=']' && (c=z[i])!=0; i++){}
|
||||
*tokenType = TK_ID;
|
||||
return i;
|
||||
}
|
||||
case '?': {
|
||||
*tokenType = TK_VARIABLE;
|
||||
for(i=1; isdigit(z[i]); i++){}
|
||||
return i;
|
||||
}
|
||||
case ':': {
|
||||
for(i=1; IdChar(z[i]); i++){}
|
||||
*tokenType = i>1 ? TK_VARIABLE : TK_ILLEGAL;
|
||||
return i;
|
||||
}
|
||||
case '$': {
|
||||
*tokenType = TK_VARIABLE;
|
||||
if( z[1]=='{' ){
|
||||
int nBrace = 1;
|
||||
for(i=2; (c=z[i])!=0 && nBrace; i++){
|
||||
if( c=='{' ){
|
||||
nBrace++;
|
||||
}else if( c=='}' ){
|
||||
nBrace--;
|
||||
}
|
||||
}
|
||||
if( c==0 ) *tokenType = TK_ILLEGAL;
|
||||
}else{
|
||||
int n = 0;
|
||||
for(i=1; (c=z[i])!=0; i++){
|
||||
if( isalnum(c) || c=='_' ){
|
||||
n++;
|
||||
}else if( c=='(' && n>0 ){
|
||||
do{
|
||||
i++;
|
||||
}while( (c=z[i])!=0 && !isspace(c) && c!=')' );
|
||||
if( c==')' ){
|
||||
i++;
|
||||
}else{
|
||||
*tokenType = TK_ILLEGAL;
|
||||
}
|
||||
break;
|
||||
}else if( c==':' && z[i+1]==':' ){
|
||||
i++;
|
||||
}else{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( n==0 ) *tokenType = TK_ILLEGAL;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
case 'x': case 'X': {
|
||||
if( (c=z[1])=='\'' || c=='"' ){
|
||||
int delim = c;
|
||||
*tokenType = TK_BLOB;
|
||||
for(i=2; (c=z[i])!=0; i++){
|
||||
if( c==delim ){
|
||||
if( i%2 ) *tokenType = TK_ILLEGAL;
|
||||
break;
|
||||
}
|
||||
if( !isxdigit(c) ){
|
||||
*tokenType = TK_ILLEGAL;
|
||||
return i;
|
||||
}
|
||||
}
|
||||
if( c ) i++;
|
||||
return i;
|
||||
}
|
||||
/* Otherwise fall through to the next case */
|
||||
}
|
||||
default: {
|
||||
if( !IdChar(*z) ){
|
||||
break;
|
||||
}
|
||||
for(i=1; IdChar(z[i]); i++){}
|
||||
*tokenType = sqlite3KeywordCode((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 sqlite3RunParser(Parse *pParse, const char *zSql, char **pzErrMsg){
|
||||
int nErr = 0;
|
||||
int i;
|
||||
void *pEngine;
|
||||
int tokenType;
|
||||
int lastTokenParsed = -1;
|
||||
sqlite3 *db = pParse->db;
|
||||
extern void *sqlite3ParserAlloc(void*(*)(int));
|
||||
extern void sqlite3ParserFree(void*, void(*)(void*));
|
||||
extern int sqlite3Parser(void*, int, Token, Parse*);
|
||||
|
||||
db->flags &= ~SQLITE_Interrupt;
|
||||
pParse->rc = SQLITE_OK;
|
||||
i = 0;
|
||||
pEngine = sqlite3ParserAlloc((void*(*)(int))malloc);
|
||||
if( pEngine==0 ){
|
||||
sqlite3SetString(pzErrMsg, "out of memory", (char*)0);
|
||||
return 1;
|
||||
}
|
||||
assert( pParse->sLastToken.dyn==0 );
|
||||
assert( pParse->pNewTable==0 );
|
||||
assert( pParse->pNewTrigger==0 );
|
||||
assert( pParse->nVar==0 );
|
||||
assert( pParse->nVarExpr==0 );
|
||||
assert( pParse->nVarExprAlloc==0 );
|
||||
assert( pParse->apVarExpr==0 );
|
||||
pParse->zTail = pParse->zSql = zSql;
|
||||
while( sqlite3_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;
|
||||
sqlite3SetString(pzErrMsg, "interrupt", (char*)0);
|
||||
goto abort_parse;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TK_ILLEGAL: {
|
||||
if( pzErrMsg ){
|
||||
sqliteFree(*pzErrMsg);
|
||||
*pzErrMsg = sqlite3MPrintf("unrecognized token: \"%T\"",
|
||||
&pParse->sLastToken);
|
||||
}
|
||||
nErr++;
|
||||
goto abort_parse;
|
||||
}
|
||||
case TK_SEMI: {
|
||||
pParse->zTail = &zSql[i];
|
||||
/* Fall thru into the default case */
|
||||
}
|
||||
default: {
|
||||
sqlite3Parser(pEngine, tokenType, pParse->sLastToken, pParse);
|
||||
lastTokenParsed = tokenType;
|
||||
if( pParse->rc!=SQLITE_OK ){
|
||||
goto abort_parse;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
abort_parse:
|
||||
if( zSql[i]==0 && nErr==0 && pParse->rc==SQLITE_OK ){
|
||||
if( lastTokenParsed!=TK_SEMI ){
|
||||
sqlite3Parser(pEngine, TK_SEMI, pParse->sLastToken, pParse);
|
||||
pParse->zTail = &zSql[i];
|
||||
}
|
||||
sqlite3Parser(pEngine, 0, pParse->sLastToken, pParse);
|
||||
}
|
||||
sqlite3ParserFree(pEngine, free);
|
||||
if( sqlite3_malloc_failed ){
|
||||
pParse->rc = SQLITE_NOMEM;
|
||||
}
|
||||
if( pParse->rc!=SQLITE_OK && pParse->rc!=SQLITE_DONE && pParse->zErrMsg==0 ){
|
||||
sqlite3SetString(&pParse->zErrMsg, sqlite3ErrStr(pParse->rc),
|
||||
(char*)0);
|
||||
}
|
||||
if( pParse->zErrMsg ){
|
||||
if( pzErrMsg && *pzErrMsg==0 ){
|
||||
*pzErrMsg = pParse->zErrMsg;
|
||||
}else{
|
||||
sqliteFree(pParse->zErrMsg);
|
||||
}
|
||||
pParse->zErrMsg = 0;
|
||||
if( !nErr ) nErr++;
|
||||
}
|
||||
if( pParse->pVdbe && pParse->nErr>0 ){
|
||||
sqlite3VdbeDelete(pParse->pVdbe);
|
||||
pParse->pVdbe = 0;
|
||||
}
|
||||
sqlite3DeleteTable(pParse->db, pParse->pNewTable);
|
||||
sqlite3DeleteTrigger(pParse->pNewTrigger);
|
||||
sqliteFree(pParse->apVarExpr);
|
||||
if( nErr>0 && (pParse->rc==SQLITE_OK || pParse->rc==SQLITE_DONE) ){
|
||||
pParse->rc = SQLITE_ERROR;
|
||||
}
|
||||
return nErr;
|
||||
}
|
||||
|
||||
/*
|
||||
** Token types used by the sqlite3_complete() routine. See the header
|
||||
** comments on that procedure for additional information.
|
||||
*/
|
||||
#define tkEXPLAIN 0
|
||||
#define tkCREATE 1
|
||||
#define tkTEMP 2
|
||||
#define tkTRIGGER 3
|
||||
#define tkEND 4
|
||||
#define tkSEMI 5
|
||||
#define tkWS 6
|
||||
#define tkOTHER 7
|
||||
|
||||
/*
|
||||
** 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 sqlite3_complete(const char *zSql){
|
||||
u8 state = 0; /* Current state, using numbers defined in header comment */
|
||||
u8 token; /* Value of the next token */
|
||||
|
||||
/* The following matrix defines the transition from one state to another
|
||||
** according to what token is seen. trans[state][token] returns the
|
||||
** next state.
|
||||
*/
|
||||
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: {
|
||||
int c;
|
||||
if( IdChar((u8)*zSql) ){
|
||||
/* Keywords and unquoted identifiers */
|
||||
int nId;
|
||||
for(nId=1; IdChar(zSql[nId]); nId++){}
|
||||
switch( *zSql ){
|
||||
case 'c': case 'C': {
|
||||
if( nId==6 && sqlite3StrNICmp(zSql, "create", 6)==0 ){
|
||||
token = tkCREATE;
|
||||
}else{
|
||||
token = tkOTHER;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 't': case 'T': {
|
||||
if( nId==7 && sqlite3StrNICmp(zSql, "trigger", 7)==0 ){
|
||||
token = tkTRIGGER;
|
||||
}else if( nId==4 && sqlite3StrNICmp(zSql, "temp", 4)==0 ){
|
||||
token = tkTEMP;
|
||||
}else if( nId==9 && sqlite3StrNICmp(zSql, "temporary", 9)==0 ){
|
||||
token = tkTEMP;
|
||||
}else{
|
||||
token = tkOTHER;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'e': case 'E': {
|
||||
if( nId==3 && sqlite3StrNICmp(zSql, "end", 3)==0 ){
|
||||
token = tkEND;
|
||||
}else if( nId==7 && sqlite3StrNICmp(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;
|
||||
}
|
||||
|
||||
/*
|
||||
** This routine is the same as the sqlite3_complete() routine described
|
||||
** above, except that the parameter is required to be UTF-16 encoded, not
|
||||
** UTF-8.
|
||||
*/
|
||||
int sqlite3_complete16(const void *zSql){
|
||||
sqlite3_value *pVal;
|
||||
char const *zSql8;
|
||||
int rc = 0;
|
||||
|
||||
pVal = sqlite3ValueNew();
|
||||
sqlite3ValueSetStr(pVal, -1, zSql, SQLITE_UTF16NATIVE, SQLITE_STATIC);
|
||||
zSql8 = sqlite3ValueText(pVal, SQLITE_UTF8);
|
||||
if( zSql8 ){
|
||||
rc = sqlite3_complete(zSql8);
|
||||
}
|
||||
sqlite3ValueFree(pVal);
|
||||
return rc;
|
||||
}
|
|
@ -0,0 +1,804 @@
|
|||
/*
|
||||
**
|
||||
** 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 sqlite3DeleteTriggerStep(TriggerStep *pTriggerStep){
|
||||
while( pTriggerStep ){
|
||||
TriggerStep * pTmp = pTriggerStep;
|
||||
pTriggerStep = pTriggerStep->pNext;
|
||||
|
||||
if( pTmp->target.dyn ) sqliteFree((char*)pTmp->target.z);
|
||||
sqlite3ExprDelete(pTmp->pWhere);
|
||||
sqlite3ExprListDelete(pTmp->pExprList);
|
||||
sqlite3SelectDelete(pTmp->pSelect);
|
||||
sqlite3IdListDelete(pTmp->pIdList);
|
||||
|
||||
sqliteFree(pTmp);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** This is called by the parser when it sees a CREATE TRIGGER statement
|
||||
** up to the point of the BEGIN before the trigger actions. A Trigger
|
||||
** structure is generated based on the information available and stored
|
||||
** in pParse->pNewTrigger. After the trigger actions have been parsed, the
|
||||
** sqlite3FinishTrigger() function is called to complete the trigger
|
||||
** construction process.
|
||||
*/
|
||||
void sqlite3BeginTrigger(
|
||||
Parse *pParse, /* The parse context of the CREATE TRIGGER statement */
|
||||
Token *pName1, /* The name of the trigger */
|
||||
Token *pName2, /* The name of the trigger */
|
||||
int tr_tm, /* One of TK_BEFORE, TK_AFTER, TK_INSTEAD */
|
||||
int op, /* One of TK_INSERT, TK_UPDATE, TK_DELETE */
|
||||
IdList *pColumns, /* column list if this is an UPDATE OF trigger */
|
||||
SrcList *pTableName,/* The name of the table/view the trigger applies to */
|
||||
int foreach, /* One of TK_ROW or TK_STATEMENT */
|
||||
Expr *pWhen, /* WHEN clause */
|
||||
int isTemp /* True if the TEMPORARY keyword is present */
|
||||
){
|
||||
Trigger *pTrigger;
|
||||
Table *pTab;
|
||||
char *zName = 0; /* Name of the trigger */
|
||||
sqlite3 *db = pParse->db;
|
||||
int iDb; /* The database to store the trigger in */
|
||||
Token *pName; /* The unqualified db name */
|
||||
DbFixer sFix;
|
||||
|
||||
if( isTemp ){
|
||||
/* If TEMP was specified, then the trigger name may not be qualified. */
|
||||
if( pName2 && pName2->n>0 ){
|
||||
sqlite3ErrorMsg(pParse, "temporary trigger may not have qualified name");
|
||||
goto trigger_cleanup;
|
||||
}
|
||||
iDb = 1;
|
||||
pName = pName1;
|
||||
}else{
|
||||
/* Figure out the db that the the trigger will be created in */
|
||||
iDb = sqlite3TwoPartName(pParse, pName1, pName2, &pName);
|
||||
if( iDb<0 ){
|
||||
goto trigger_cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
/* If the trigger name was unqualified, and the table is a temp table,
|
||||
** then set iDb to 1 to create the trigger in the temporary database.
|
||||
** If sqlite3SrcListLookup() returns 0, indicating the table does not
|
||||
** exist, the error is caught by the block below.
|
||||
*/
|
||||
if( !pTableName || sqlite3_malloc_failed ) goto trigger_cleanup;
|
||||
pTab = sqlite3SrcListLookup(pParse, pTableName);
|
||||
if( pName2->n==0 && pTab && pTab->iDb==1 ){
|
||||
iDb = 1;
|
||||
}
|
||||
|
||||
/* Ensure the table name matches database name and that the table exists */
|
||||
if( sqlite3_malloc_failed ) goto trigger_cleanup;
|
||||
assert( pTableName->nSrc==1 );
|
||||
if( sqlite3FixInit(&sFix, pParse, iDb, "trigger", pName) &&
|
||||
sqlite3FixSrcList(&sFix, pTableName) ){
|
||||
goto trigger_cleanup;
|
||||
}
|
||||
pTab = sqlite3SrcListLookup(pParse, pTableName);
|
||||
if( !pTab ){
|
||||
/* The table does not exist. */
|
||||
goto trigger_cleanup;
|
||||
}
|
||||
|
||||
/* Check that the trigger name is not reserved and that no trigger of the
|
||||
** specified name exists */
|
||||
zName = sqlite3NameFromToken(pName);
|
||||
if( !zName || SQLITE_OK!=sqlite3CheckObjectName(pParse, zName) ){
|
||||
goto trigger_cleanup;
|
||||
}
|
||||
if( sqlite3HashFind(&(db->aDb[iDb].trigHash), zName,pName->n+1) ){
|
||||
sqlite3ErrorMsg(pParse, "trigger %T already exists", pName);
|
||||
goto trigger_cleanup;
|
||||
}
|
||||
|
||||
/* Do not create a trigger on a system table */
|
||||
if( (iDb!=1 && sqlite3StrICmp(pTab->zName, MASTER_NAME)==0) ||
|
||||
(iDb==1 && sqlite3StrICmp(pTab->zName, TEMP_MASTER_NAME)==0)
|
||||
){
|
||||
sqlite3ErrorMsg(pParse, "cannot create trigger on system table");
|
||||
pParse->nErr++;
|
||||
goto trigger_cleanup;
|
||||
}
|
||||
|
||||
/* INSTEAD of triggers are only for views and views only support INSTEAD
|
||||
** of triggers.
|
||||
*/
|
||||
if( pTab->pSelect && tr_tm!=TK_INSTEAD ){
|
||||
sqlite3ErrorMsg(pParse, "cannot create %s trigger on view: %S",
|
||||
(tr_tm == TK_BEFORE)?"BEFORE":"AFTER", pTableName, 0);
|
||||
goto trigger_cleanup;
|
||||
}
|
||||
if( !pTab->pSelect && tr_tm==TK_INSTEAD ){
|
||||
sqlite3ErrorMsg(pParse, "cannot create INSTEAD OF"
|
||||
" trigger on table: %S", pTableName, 0);
|
||||
goto trigger_cleanup;
|
||||
}
|
||||
|
||||
#ifndef SQLITE_OMIT_AUTHORIZATION
|
||||
{
|
||||
int code = SQLITE_CREATE_TRIGGER;
|
||||
const char *zDb = db->aDb[pTab->iDb].zName;
|
||||
const char *zDbTrig = isTemp ? db->aDb[1].zName : zDb;
|
||||
if( pTab->iDb==1 || isTemp ) code = SQLITE_CREATE_TEMP_TRIGGER;
|
||||
if( sqlite3AuthCheck(pParse, code, zName, pTab->zName, zDbTrig) ){
|
||||
goto trigger_cleanup;
|
||||
}
|
||||
if( sqlite3AuthCheck(pParse, SQLITE_INSERT, SCHEMA_TABLE(pTab->iDb),0,zDb)){
|
||||
goto trigger_cleanup;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* INSTEAD OF triggers can only appear on views and BEFORE triggers
|
||||
** cannot appear on views. So we might as well translate every
|
||||
** INSTEAD OF trigger into a BEFORE trigger. It simplifies code
|
||||
** elsewhere.
|
||||
*/
|
||||
if (tr_tm == TK_INSTEAD){
|
||||
tr_tm = TK_BEFORE;
|
||||
}
|
||||
|
||||
/* Build the Trigger object */
|
||||
pTrigger = (Trigger*)sqliteMalloc(sizeof(Trigger));
|
||||
if( pTrigger==0 ) goto trigger_cleanup;
|
||||
pTrigger->name = zName;
|
||||
zName = 0;
|
||||
pTrigger->table = sqliteStrDup(pTableName->a[0].zName);
|
||||
if( sqlite3_malloc_failed ) goto trigger_cleanup;
|
||||
pTrigger->iDb = iDb;
|
||||
pTrigger->iTabDb = pTab->iDb;
|
||||
pTrigger->op = op;
|
||||
pTrigger->tr_tm = tr_tm;
|
||||
pTrigger->pWhen = sqlite3ExprDup(pWhen);
|
||||
pTrigger->pColumns = sqlite3IdListDup(pColumns);
|
||||
pTrigger->foreach = foreach;
|
||||
sqlite3TokenCopy(&pTrigger->nameToken,pName);
|
||||
assert( pParse->pNewTrigger==0 );
|
||||
pParse->pNewTrigger = pTrigger;
|
||||
|
||||
trigger_cleanup:
|
||||
sqliteFree(zName);
|
||||
sqlite3SrcListDelete(pTableName);
|
||||
sqlite3IdListDelete(pColumns);
|
||||
sqlite3ExprDelete(pWhen);
|
||||
}
|
||||
|
||||
/*
|
||||
** This routine is called after all of the trigger actions have been parsed
|
||||
** in order to complete the process of building the trigger.
|
||||
*/
|
||||
void sqlite3FinishTrigger(
|
||||
Parse *pParse, /* Parser context */
|
||||
TriggerStep *pStepList, /* The triggered program */
|
||||
Token *pAll /* Token that describes the complete CREATE TRIGGER */
|
||||
){
|
||||
Trigger *nt = 0; /* The trigger whose construction is finishing up */
|
||||
sqlite3 *db = pParse->db; /* The database */
|
||||
DbFixer sFix;
|
||||
|
||||
if( pParse->nErr || pParse->pNewTrigger==0 ) goto triggerfinish_cleanup;
|
||||
nt = pParse->pNewTrigger;
|
||||
pParse->pNewTrigger = 0;
|
||||
nt->step_list = pStepList;
|
||||
while( pStepList ){
|
||||
pStepList->pTrig = nt;
|
||||
pStepList = pStepList->pNext;
|
||||
}
|
||||
if( sqlite3FixInit(&sFix, pParse, nt->iDb, "trigger", &nt->nameToken)
|
||||
&& sqlite3FixTriggerStep(&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_String8, 0, 0, "trigger" },
|
||||
{ OP_String8, 0, 0, 0 }, /* 2: trigger name */
|
||||
{ OP_String8, 0, 0, 0 }, /* 3: table name */
|
||||
{ OP_Integer, 0, 0, 0 },
|
||||
{ OP_String8, 0, 0, "CREATE TRIGGER "},
|
||||
{ OP_String8, 0, 0, 0 }, /* 6: SQL */
|
||||
{ OP_Concat, 0, 0, 0 },
|
||||
{ OP_MakeRecord, 5, 0, "tttit" },
|
||||
{ OP_PutIntKey, 0, 0, 0 },
|
||||
};
|
||||
int addr;
|
||||
Vdbe *v;
|
||||
|
||||
/* Make an entry in the sqlite_master table */
|
||||
v = sqlite3GetVdbe(pParse);
|
||||
if( v==0 ) goto triggerfinish_cleanup;
|
||||
sqlite3BeginWriteOperation(pParse, 0, nt->iDb);
|
||||
sqlite3OpenMasterTable(v, nt->iDb);
|
||||
addr = sqlite3VdbeAddOpList(v, ArraySize(insertTrig), insertTrig);
|
||||
sqlite3VdbeChangeP3(v, addr+2, nt->name, 0);
|
||||
sqlite3VdbeChangeP3(v, addr+3, nt->table, 0);
|
||||
sqlite3VdbeChangeP3(v, addr+6, pAll->z, pAll->n);
|
||||
if( nt->iDb!=0 ){
|
||||
sqlite3ChangeCookie(db, v, nt->iDb);
|
||||
}
|
||||
sqlite3VdbeAddOp(v, OP_Close, 0, 0);
|
||||
sqlite3VdbeOp3(v, OP_ParseSchema, nt->iDb, 0,
|
||||
sqlite3MPrintf("type='trigger' AND name='%q'", nt->name), P3_DYNAMIC);
|
||||
}
|
||||
|
||||
if( db->init.busy ){
|
||||
Table *pTab;
|
||||
sqlite3HashInsert(&db->aDb[nt->iDb].trigHash,
|
||||
nt->name, strlen(nt->name)+1, nt);
|
||||
pTab = sqlite3LocateTable(pParse, nt->table, db->aDb[nt->iTabDb].zName);
|
||||
assert( pTab!=0 );
|
||||
nt->pNext = pTab->pTrigger;
|
||||
pTab->pTrigger = nt;
|
||||
nt = 0;
|
||||
}
|
||||
|
||||
triggerfinish_cleanup:
|
||||
sqlite3DeleteTrigger(nt);
|
||||
sqlite3DeleteTrigger(pParse->pNewTrigger);
|
||||
pParse->pNewTrigger = 0;
|
||||
sqlite3DeleteTriggerStep(pStepList);
|
||||
}
|
||||
|
||||
/*
|
||||
** Make a copy of all components of the given trigger step. This has
|
||||
** the effect of copying all Expr.token.z values into memory obtained
|
||||
** from sqliteMalloc(). As initially created, the Expr.token.z values
|
||||
** all point to the input string that was fed to the parser. But that
|
||||
** string is ephemeral - it will go away as soon as the sqlite3_exec()
|
||||
** call that started the parser exits. This routine makes a persistent
|
||||
** copy of all the Expr.token.z strings so that the TriggerStep structure
|
||||
** will be valid even after the sqlite3_exec() call returns.
|
||||
*/
|
||||
static void sqlitePersistTriggerStep(TriggerStep *p){
|
||||
if( p->target.z ){
|
||||
p->target.z = sqliteStrNDup(p->target.z, p->target.n);
|
||||
p->target.dyn = 1;
|
||||
}
|
||||
if( p->pSelect ){
|
||||
Select *pNew = sqlite3SelectDup(p->pSelect);
|
||||
sqlite3SelectDelete(p->pSelect);
|
||||
p->pSelect = pNew;
|
||||
}
|
||||
if( p->pWhere ){
|
||||
Expr *pNew = sqlite3ExprDup(p->pWhere);
|
||||
sqlite3ExprDelete(p->pWhere);
|
||||
p->pWhere = pNew;
|
||||
}
|
||||
if( p->pExprList ){
|
||||
ExprList *pNew = sqlite3ExprListDup(p->pExprList);
|
||||
sqlite3ExprListDelete(p->pExprList);
|
||||
p->pExprList = pNew;
|
||||
}
|
||||
if( p->pIdList ){
|
||||
IdList *pNew = sqlite3IdListDup(p->pIdList);
|
||||
sqlite3IdListDelete(p->pIdList);
|
||||
p->pIdList = pNew;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Turn a SELECT statement (that the pSelect parameter points to) into
|
||||
** a trigger step. Return a pointer to a TriggerStep structure.
|
||||
**
|
||||
** The parser calls this routine when it finds a SELECT statement in
|
||||
** body of a TRIGGER.
|
||||
*/
|
||||
TriggerStep *sqlite3TriggerSelectStep(Select *pSelect){
|
||||
TriggerStep *pTriggerStep = sqliteMalloc(sizeof(TriggerStep));
|
||||
if( pTriggerStep==0 ) return 0;
|
||||
|
||||
pTriggerStep->op = TK_SELECT;
|
||||
pTriggerStep->pSelect = pSelect;
|
||||
pTriggerStep->orconf = OE_Default;
|
||||
sqlitePersistTriggerStep(pTriggerStep);
|
||||
|
||||
return pTriggerStep;
|
||||
}
|
||||
|
||||
/*
|
||||
** Build a trigger step out of an INSERT statement. Return a pointer
|
||||
** to the new trigger step.
|
||||
**
|
||||
** The parser calls this routine when it sees an INSERT inside the
|
||||
** body of a trigger.
|
||||
*/
|
||||
TriggerStep *sqlite3TriggerInsertStep(
|
||||
Token *pTableName, /* Name of the table into which we insert */
|
||||
IdList *pColumn, /* List of columns in pTableName to insert into */
|
||||
ExprList *pEList, /* The VALUE clause: a list of values to be inserted */
|
||||
Select *pSelect, /* A SELECT statement that supplies values */
|
||||
int orconf /* The conflict algorithm (OE_Abort, OE_Replace, etc.) */
|
||||
){
|
||||
TriggerStep *pTriggerStep = sqliteMalloc(sizeof(TriggerStep));
|
||||
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 *sqlite3TriggerUpdateStep(
|
||||
Token *pTableName, /* Name of the table to be updated */
|
||||
ExprList *pEList, /* The SET clause: list of column and new values */
|
||||
Expr *pWhere, /* The WHERE clause */
|
||||
int orconf /* The conflict algorithm. (OE_Abort, OE_Ignore, etc) */
|
||||
){
|
||||
TriggerStep *pTriggerStep = sqliteMalloc(sizeof(TriggerStep));
|
||||
if( pTriggerStep==0 ) return 0;
|
||||
|
||||
pTriggerStep->op = TK_UPDATE;
|
||||
pTriggerStep->target = *pTableName;
|
||||
pTriggerStep->pExprList = pEList;
|
||||
pTriggerStep->pWhere = pWhere;
|
||||
pTriggerStep->orconf = orconf;
|
||||
sqlitePersistTriggerStep(pTriggerStep);
|
||||
|
||||
return pTriggerStep;
|
||||
}
|
||||
|
||||
/*
|
||||
** Construct a trigger step that implements a DELETE statement and return
|
||||
** a pointer to that trigger step. The parser calls this routine when it
|
||||
** sees a DELETE statement inside the body of a CREATE TRIGGER.
|
||||
*/
|
||||
TriggerStep *sqlite3TriggerDeleteStep(Token *pTableName, Expr *pWhere){
|
||||
TriggerStep *pTriggerStep = sqliteMalloc(sizeof(TriggerStep));
|
||||
if( pTriggerStep==0 ) return 0;
|
||||
|
||||
pTriggerStep->op = TK_DELETE;
|
||||
pTriggerStep->target = *pTableName;
|
||||
pTriggerStep->pWhere = pWhere;
|
||||
pTriggerStep->orconf = OE_Default;
|
||||
sqlitePersistTriggerStep(pTriggerStep);
|
||||
|
||||
return pTriggerStep;
|
||||
}
|
||||
|
||||
/*
|
||||
** Recursively delete a Trigger structure
|
||||
*/
|
||||
void sqlite3DeleteTrigger(Trigger *pTrigger){
|
||||
if( pTrigger==0 ) return;
|
||||
sqlite3DeleteTriggerStep(pTrigger->step_list);
|
||||
sqliteFree(pTrigger->name);
|
||||
sqliteFree(pTrigger->table);
|
||||
sqlite3ExprDelete(pTrigger->pWhen);
|
||||
sqlite3IdListDelete(pTrigger->pColumns);
|
||||
if( pTrigger->nameToken.dyn ) sqliteFree((char*)pTrigger->nameToken.z);
|
||||
sqliteFree(pTrigger);
|
||||
}
|
||||
|
||||
/*
|
||||
** This function is called to drop a trigger from the database schema.
|
||||
**
|
||||
** This may be called directly from the parser and therefore identifies
|
||||
** the trigger by name. The sqlite3DropTriggerPtr() routine does the
|
||||
** same job as this routine except it takes a pointer to the trigger
|
||||
** instead of the trigger name.
|
||||
**/
|
||||
void sqlite3DropTrigger(Parse *pParse, SrcList *pName){
|
||||
Trigger *pTrigger = 0;
|
||||
int i;
|
||||
const char *zDb;
|
||||
const char *zName;
|
||||
int nName;
|
||||
sqlite3 *db = pParse->db;
|
||||
|
||||
if( sqlite3_malloc_failed ) goto drop_trigger_cleanup;
|
||||
if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){
|
||||
goto drop_trigger_cleanup;
|
||||
}
|
||||
|
||||
assert( pName->nSrc==1 );
|
||||
zDb = pName->a[0].zDatabase;
|
||||
zName = pName->a[0].zName;
|
||||
nName = strlen(zName);
|
||||
for(i=0; i<db->nDb; i++){
|
||||
int j = (i<2) ? i^1 : i; /* Search TEMP before MAIN */
|
||||
if( zDb && sqlite3StrICmp(db->aDb[j].zName, zDb) ) continue;
|
||||
pTrigger = sqlite3HashFind(&(db->aDb[j].trigHash), zName, nName+1);
|
||||
if( pTrigger ) break;
|
||||
}
|
||||
if( !pTrigger ){
|
||||
sqlite3ErrorMsg(pParse, "no such trigger: %S", pName, 0);
|
||||
goto drop_trigger_cleanup;
|
||||
}
|
||||
sqlite3DropTriggerPtr(pParse, pTrigger, 0);
|
||||
|
||||
drop_trigger_cleanup:
|
||||
sqlite3SrcListDelete(pName);
|
||||
}
|
||||
|
||||
/*
|
||||
** Return a pointer to the Table structure for the table that a trigger
|
||||
** is set on.
|
||||
*/
|
||||
static Table *tableOfTrigger(sqlite3 *db, Trigger *pTrigger){
|
||||
return sqlite3FindTable(db,pTrigger->table,db->aDb[pTrigger->iTabDb].zName);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Drop a trigger given a pointer to that trigger. If nested is false,
|
||||
** then also generate code to remove the trigger from the SQLITE_MASTER
|
||||
** table.
|
||||
*/
|
||||
void sqlite3DropTriggerPtr(Parse *pParse, Trigger *pTrigger, int nested){
|
||||
Table *pTable;
|
||||
Vdbe *v;
|
||||
sqlite3 *db = pParse->db;
|
||||
int iDb;
|
||||
|
||||
iDb = pTrigger->iDb;
|
||||
assert( iDb>=0 && iDb<db->nDb );
|
||||
pTable = tableOfTrigger(db, pTrigger);
|
||||
assert(pTable);
|
||||
assert( pTable->iDb==iDb || iDb==1 );
|
||||
#ifndef SQLITE_OMIT_AUTHORIZATION
|
||||
{
|
||||
int code = SQLITE_DROP_TRIGGER;
|
||||
const char *zDb = db->aDb[iDb].zName;
|
||||
const char *zTab = SCHEMA_TABLE(iDb);
|
||||
if( iDb==1 ) code = SQLITE_DROP_TEMP_TRIGGER;
|
||||
if( sqlite3AuthCheck(pParse, code, pTrigger->name, pTable->zName, zDb) ||
|
||||
sqlite3AuthCheck(pParse, SQLITE_DELETE, zTab, 0, zDb) ){
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Generate code to destroy the database record of the trigger.
|
||||
*/
|
||||
if( pTable!=0 && (v = sqlite3GetVdbe(pParse))!=0 ){
|
||||
int base;
|
||||
static VdbeOpList dropTrigger[] = {
|
||||
{ OP_Rewind, 0, ADDR(9), 0},
|
||||
{ OP_String8, 0, 0, 0}, /* 1 */
|
||||
{ OP_Column, 0, 1, 0},
|
||||
{ OP_Ne, 0, ADDR(8), 0},
|
||||
{ OP_String8, 0, 0, "trigger"},
|
||||
{ OP_Column, 0, 0, 0},
|
||||
{ OP_Ne, 0, ADDR(8), 0},
|
||||
{ OP_Delete, 0, 0, 0},
|
||||
{ OP_Next, 0, ADDR(1), 0}, /* 8 */
|
||||
};
|
||||
|
||||
sqlite3BeginWriteOperation(pParse, 0, iDb);
|
||||
sqlite3OpenMasterTable(v, iDb);
|
||||
base = sqlite3VdbeAddOpList(v, ArraySize(dropTrigger), dropTrigger);
|
||||
sqlite3VdbeChangeP3(v, base+1, pTrigger->name, 0);
|
||||
sqlite3ChangeCookie(db, v, iDb);
|
||||
sqlite3VdbeAddOp(v, OP_Close, 0, 0);
|
||||
sqlite3VdbeOp3(v, OP_DropTrigger, iDb, 0, pTrigger->name, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Remove a trigger from the hash tables of the sqlite* pointer.
|
||||
*/
|
||||
void sqlite3UnlinkAndDeleteTrigger(sqlite3 *db, int iDb, const char *zName){
|
||||
Trigger *pTrigger;
|
||||
int nName = strlen(zName);
|
||||
pTrigger = sqlite3HashInsert(&(db->aDb[iDb].trigHash), zName, nName+1, 0);
|
||||
if( pTrigger ){
|
||||
Table *pTable = tableOfTrigger(db, pTrigger);
|
||||
assert( pTable!=0 );
|
||||
if( pTable->pTrigger == pTrigger ){
|
||||
pTable->pTrigger = pTrigger->pNext;
|
||||
}else{
|
||||
Trigger *cc = pTable->pTrigger;
|
||||
while( cc ){
|
||||
if( cc->pNext == pTrigger ){
|
||||
cc->pNext = cc->pNext->pNext;
|
||||
break;
|
||||
}
|
||||
cc = cc->pNext;
|
||||
}
|
||||
assert(cc);
|
||||
}
|
||||
sqlite3DeleteTrigger(pTrigger);
|
||||
db->flags |= SQLITE_InternChanges;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** pEList is the SET clause of an UPDATE statement. Each entry
|
||||
** in pEList is of the format <id>=<expr>. If any of the entries
|
||||
** in pEList have an <id> which matches an identifier in pIdList,
|
||||
** then return TRUE. If pIdList==NULL, then it is considered a
|
||||
** wildcard that matches anything. Likewise if pEList==NULL then
|
||||
** it matches anything so always return true. Return false only
|
||||
** if there is no match.
|
||||
*/
|
||||
static int checkColumnOverLap(IdList *pIdList, ExprList *pEList){
|
||||
int e;
|
||||
if( !pIdList || !pEList ) return 1;
|
||||
for(e=0; e<pEList->nExpr; e++){
|
||||
if( sqlite3IdListIndex(pIdList, pEList->a[e].zName)>=0 ) return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* A global variable that is TRUE if we should always set up temp tables for
|
||||
* for triggers, even if there are no triggers to code. This is used to test
|
||||
* how much overhead the triggers algorithm is causing.
|
||||
*
|
||||
* This flag can be set or cleared using the "trigger_overhead_test" pragma.
|
||||
* The pragma is not documented since it is not really part of the interface
|
||||
* to SQLite, just the test procedure.
|
||||
*/
|
||||
int sqlite3_always_code_trigger_setup = 0;
|
||||
|
||||
/*
|
||||
* Returns true if a trigger matching op, tr_tm and foreach that is NOT already
|
||||
* on the Parse objects trigger-stack (to prevent recursive trigger firing) is
|
||||
* found in the list specified as pTrigger.
|
||||
*/
|
||||
int sqlite3TriggersExist(
|
||||
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( sqlite3_always_code_trigger_setup ){
|
||||
return 1;
|
||||
}
|
||||
|
||||
pTriggerCursor = pTrigger;
|
||||
while( pTriggerCursor ){
|
||||
if( pTriggerCursor->op == op &&
|
||||
pTriggerCursor->tr_tm == tr_tm &&
|
||||
pTriggerCursor->foreach == foreach &&
|
||||
checkColumnOverLap(pTriggerCursor->pColumns, pChanges) ){
|
||||
TriggerStack * ss;
|
||||
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 = sqlite3SrcListAppend(0, &sDb, &pStep->target);
|
||||
} else {
|
||||
pSrc = sqlite3SrcListAppend(0, &pStep->target, 0);
|
||||
}
|
||||
return pSrc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Generate VDBE code for zero or more statements inside the body of a
|
||||
** trigger.
|
||||
*/
|
||||
static int codeTriggerProgram(
|
||||
Parse *pParse, /* The parser context */
|
||||
TriggerStep *pStepList, /* List of statements inside the trigger body */
|
||||
int orconfin /* Conflict algorithm. (OE_Abort, etc) */
|
||||
){
|
||||
TriggerStep * pTriggerStep = pStepList;
|
||||
int orconf;
|
||||
Vdbe *v = pParse->pVdbe;
|
||||
|
||||
assert( pTriggerStep!=0 );
|
||||
assert( v!=0 );
|
||||
sqlite3VdbeAddOp(v, OP_ContextPush, 0, 0);
|
||||
VdbeComment((v, "# begin trigger %s", pStepList->pTrig->name));
|
||||
while( pTriggerStep ){
|
||||
orconf = (orconfin == OE_Default)?pTriggerStep->orconf:orconfin;
|
||||
pParse->trigStack->orconf = orconf;
|
||||
switch( pTriggerStep->op ){
|
||||
case TK_SELECT: {
|
||||
Select * ss = sqlite3SelectDup(pTriggerStep->pSelect);
|
||||
assert(ss);
|
||||
assert(ss->pSrc);
|
||||
sqlite3Select(pParse, ss, SRT_Discard, 0, 0, 0, 0, 0);
|
||||
sqlite3SelectDelete(ss);
|
||||
break;
|
||||
}
|
||||
case TK_UPDATE: {
|
||||
SrcList *pSrc;
|
||||
pSrc = targetSrcList(pParse, pTriggerStep);
|
||||
sqlite3VdbeAddOp(v, OP_ResetCount, 0, 0);
|
||||
sqlite3Update(pParse, pSrc,
|
||||
sqlite3ExprListDup(pTriggerStep->pExprList),
|
||||
sqlite3ExprDup(pTriggerStep->pWhere), orconf);
|
||||
sqlite3VdbeAddOp(v, OP_ResetCount, 1, 0);
|
||||
break;
|
||||
}
|
||||
case TK_INSERT: {
|
||||
SrcList *pSrc;
|
||||
pSrc = targetSrcList(pParse, pTriggerStep);
|
||||
sqlite3VdbeAddOp(v, OP_ResetCount, 0, 0);
|
||||
sqlite3Insert(pParse, pSrc,
|
||||
sqlite3ExprListDup(pTriggerStep->pExprList),
|
||||
sqlite3SelectDup(pTriggerStep->pSelect),
|
||||
sqlite3IdListDup(pTriggerStep->pIdList), orconf);
|
||||
sqlite3VdbeAddOp(v, OP_ResetCount, 1, 0);
|
||||
break;
|
||||
}
|
||||
case TK_DELETE: {
|
||||
SrcList *pSrc;
|
||||
sqlite3VdbeAddOp(v, OP_ResetCount, 0, 0);
|
||||
pSrc = targetSrcList(pParse, pTriggerStep);
|
||||
sqlite3DeleteFrom(pParse, pSrc, sqlite3ExprDup(pTriggerStep->pWhere));
|
||||
sqlite3VdbeAddOp(v, OP_ResetCount, 1, 0);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
pTriggerStep = pTriggerStep->pNext;
|
||||
}
|
||||
sqlite3VdbeAddOp(v, OP_ContextPop, 0, 0);
|
||||
VdbeComment((v, "# end trigger %s", pStepList->pTrig->name));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** This is called to code FOR EACH ROW triggers.
|
||||
**
|
||||
** When the code that this function generates is executed, the following
|
||||
** must be true:
|
||||
**
|
||||
** 1. No cursors may be open in the main database. (But newIdx and oldIdx
|
||||
** can be indices of cursors in temporary tables. See below.)
|
||||
**
|
||||
** 2. If the triggers being coded are ON INSERT or ON UPDATE triggers, then
|
||||
** a temporary vdbe cursor (index newIdx) must be open and pointing at
|
||||
** a row containing values to be substituted for new.* expressions in the
|
||||
** trigger program(s).
|
||||
**
|
||||
** 3. If the triggers being coded are ON DELETE or ON UPDATE triggers, then
|
||||
** a temporary vdbe cursor (index oldIdx) must be open and pointing at
|
||||
** a row containing values to be substituted for old.* expressions in the
|
||||
** trigger program(s).
|
||||
**
|
||||
*/
|
||||
int sqlite3CodeRowTrigger(
|
||||
Parse *pParse, /* Parse context */
|
||||
int op, /* One of TK_UPDATE, TK_INSERT, TK_DELETE */
|
||||
ExprList *pChanges, /* Changes list for any UPDATE OF triggers */
|
||||
int tr_tm, /* One of 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 *pStack;
|
||||
TriggerStack trigStackEntry;
|
||||
|
||||
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;
|
||||
for(pStack=pParse->trigStack; pStack; pStack=pStack->pNext){
|
||||
if( pStack->pTrigger==pTrigger ){
|
||||
fire_this = 0;
|
||||
}
|
||||
}
|
||||
if( op == TK_UPDATE && pTrigger->pColumns &&
|
||||
!checkColumnOverLap(pTrigger->pColumns, pChanges) ){
|
||||
fire_this = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if( fire_this ){
|
||||
int endTrigger;
|
||||
SrcList dummyTablist;
|
||||
Expr * whenExpr;
|
||||
AuthContext sContext;
|
||||
|
||||
dummyTablist.nSrc = 0;
|
||||
|
||||
/* Push an entry on to the trigger stack */
|
||||
trigStackEntry.pTrigger = pTrigger;
|
||||
trigStackEntry.newIdx = newIdx;
|
||||
trigStackEntry.oldIdx = oldIdx;
|
||||
trigStackEntry.pTab = pTab;
|
||||
trigStackEntry.pNext = pParse->trigStack;
|
||||
trigStackEntry.ignoreJump = ignoreJump;
|
||||
pParse->trigStack = &trigStackEntry;
|
||||
sqlite3AuthContextPush(pParse, &sContext, pTrigger->name);
|
||||
|
||||
/* code the WHEN clause */
|
||||
endTrigger = sqlite3VdbeMakeLabel(pParse->pVdbe);
|
||||
whenExpr = sqlite3ExprDup(pTrigger->pWhen);
|
||||
if( sqlite3ExprResolveIds(pParse, &dummyTablist, 0, whenExpr) ){
|
||||
pParse->trigStack = trigStackEntry.pNext;
|
||||
sqlite3ExprDelete(whenExpr);
|
||||
return 1;
|
||||
}
|
||||
sqlite3ExprIfFalse(pParse, whenExpr, endTrigger, 1);
|
||||
sqlite3ExprDelete(whenExpr);
|
||||
|
||||
codeTriggerProgram(pParse, pTrigger->step_list, orconf);
|
||||
|
||||
/* Pop the entry off the trigger stack */
|
||||
pParse->trigStack = trigStackEntry.pNext;
|
||||
sqlite3AuthContextPop(&sContext);
|
||||
|
||||
sqlite3VdbeResolveLabel(pParse->pVdbe, endTrigger);
|
||||
}
|
||||
pTrigger = pTrigger->pNext;
|
||||
}
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,450 @@
|
|||
/*
|
||||
** 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.90 2004/10/05 02:41:43 drh 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 sqlite3Update(
|
||||
Parse *pParse, /* The parser context */
|
||||
SrcList *pTabList, /* The table in which we should change things */
|
||||
ExprList *pChanges, /* Things to be changed */
|
||||
Expr *pWhere, /* The WHERE clause. May be null */
|
||||
int onError /* How to handle constraint errors */
|
||||
){
|
||||
int i, j; /* Loop counters */
|
||||
Table *pTab; /* The table to be updated */
|
||||
int addr = 0; /* VDBE instruction address of the start of the loop */
|
||||
WhereInfo *pWInfo; /* Information about the WHERE clause */
|
||||
Vdbe *v; /* The virtual database engine */
|
||||
Index *pIdx; /* For looping over indices */
|
||||
int nIdx; /* Number of indices that need updating */
|
||||
int nIdxTotal; /* Total number of indices */
|
||||
int iCur; /* VDBE Cursor number of pTab */
|
||||
sqlite3 *db; /* The database structure */
|
||||
Index **apIdx = 0; /* An array of indices that need updating too */
|
||||
char *aIdxUsed = 0; /* aIdxUsed[i]==1 if the i-th index is used */
|
||||
int *aXRef = 0; /* aXRef[i] is the index in pChanges->a[] of the
|
||||
** an expression for the i-th column of the table.
|
||||
** aXRef[i]==-1 if the i-th column is not changed. */
|
||||
int chngRecno; /* True if the record number is being changed */
|
||||
Expr *pRecnoExpr = 0; /* Expression defining the new record number */
|
||||
int openAll = 0; /* True if all indices need to be opened */
|
||||
int isView; /* Trying to update a view */
|
||||
AuthContext sContext; /* The authorization context */
|
||||
|
||||
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 || sqlite3_malloc_failed ) goto update_cleanup;
|
||||
db = pParse->db;
|
||||
assert( pTabList->nSrc==1 );
|
||||
|
||||
/* Locate the table which we want to update.
|
||||
*/
|
||||
pTab = sqlite3SrcListLookup(pParse, pTabList);
|
||||
if( pTab==0 ) goto update_cleanup;
|
||||
before_triggers = sqlite3TriggersExist(pParse, pTab->pTrigger,
|
||||
TK_UPDATE, TK_BEFORE, TK_ROW, pChanges);
|
||||
after_triggers = sqlite3TriggersExist(pParse, pTab->pTrigger,
|
||||
TK_UPDATE, TK_AFTER, TK_ROW, pChanges);
|
||||
row_triggers_exist = before_triggers || after_triggers;
|
||||
isView = pTab->pSelect!=0;
|
||||
if( sqlite3IsReadOnly(pParse, pTab, before_triggers) ){
|
||||
goto update_cleanup;
|
||||
}
|
||||
if( isView ){
|
||||
if( sqlite3ViewGetColumnNames(pParse, pTab) ){
|
||||
goto update_cleanup;
|
||||
}
|
||||
}
|
||||
aXRef = sqliteMallocRaw( sizeof(int) * pTab->nCol );
|
||||
if( aXRef==0 ) goto update_cleanup;
|
||||
for(i=0; i<pTab->nCol; i++) aXRef[i] = -1;
|
||||
|
||||
/* If there are FOR EACH ROW triggers, allocate cursors for the
|
||||
** special OLD and NEW tables
|
||||
*/
|
||||
if( 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( sqlite3ExprResolveAndCheck(pParse, pTabList, 0,
|
||||
pChanges->a[i].pExpr, 0, 0) ){
|
||||
goto update_cleanup;
|
||||
}
|
||||
for(j=0; j<pTab->nCol; j++){
|
||||
if( sqlite3StrICmp(pTab->aCol[j].zName, pChanges->a[i].zName)==0 ){
|
||||
if( j==pTab->iPKey ){
|
||||
chngRecno = 1;
|
||||
pRecnoExpr = pChanges->a[i].pExpr;
|
||||
}
|
||||
aXRef[j] = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( j>=pTab->nCol ){
|
||||
if( sqlite3IsRowid(pChanges->a[i].zName) ){
|
||||
chngRecno = 1;
|
||||
pRecnoExpr = pChanges->a[i].pExpr;
|
||||
}else{
|
||||
sqlite3ErrorMsg(pParse, "no such column: %s", pChanges->a[i].zName);
|
||||
goto update_cleanup;
|
||||
}
|
||||
}
|
||||
#ifndef SQLITE_OMIT_AUTHORIZATION
|
||||
{
|
||||
int rc;
|
||||
rc = sqlite3AuthCheck(pParse, SQLITE_UPDATE, pTab->zName,
|
||||
pTab->aCol[j].zName, db->aDb[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 = sqliteMallocRaw( sizeof(Index*) * nIdx + nIdxTotal );
|
||||
if( apIdx==0 ) goto update_cleanup;
|
||||
aIdxUsed = (char*)&apIdx[nIdx];
|
||||
}
|
||||
for(nIdx=j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
|
||||
if( chngRecno ){
|
||||
i = 0;
|
||||
}else{
|
||||
for(i=0; i<pIdx->nColumn; i++){
|
||||
if( aXRef[pIdx->aiColumn[i]]>=0 ) break;
|
||||
}
|
||||
}
|
||||
if( i<pIdx->nColumn ){
|
||||
if( sqlite3CheckIndexCollSeq(pParse, pIdx) ) goto update_cleanup;
|
||||
apIdx[nIdx++] = pIdx;
|
||||
aIdxUsed[j] = 1;
|
||||
}else{
|
||||
aIdxUsed[j] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Resolve the column names in all the expressions in the
|
||||
** WHERE clause.
|
||||
*/
|
||||
if( sqlite3ExprResolveAndCheck(pParse, pTabList, 0, pWhere, 0, 0) ){
|
||||
goto update_cleanup;
|
||||
}
|
||||
|
||||
/* Start the view context
|
||||
*/
|
||||
if( isView ){
|
||||
sqlite3AuthContextPush(pParse, &sContext, pTab->zName);
|
||||
}
|
||||
|
||||
/* Begin generating code.
|
||||
*/
|
||||
v = sqlite3GetVdbe(pParse);
|
||||
if( v==0 ) goto update_cleanup;
|
||||
sqlite3VdbeCountChanges(v);
|
||||
sqlite3BeginWriteOperation(pParse, 1, pTab->iDb);
|
||||
|
||||
/* If we are trying to update a view, construct that view into
|
||||
** a temporary table.
|
||||
*/
|
||||
if( isView ){
|
||||
Select *pView;
|
||||
pView = sqlite3SelectDup(pTab->pSelect);
|
||||
sqlite3Select(pParse, pView, SRT_TempTable, iCur, 0, 0, 0, 0);
|
||||
sqlite3SelectDelete(pView);
|
||||
}
|
||||
|
||||
/* Begin the database scan
|
||||
*/
|
||||
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 1, 0);
|
||||
if( pWInfo==0 ) goto update_cleanup;
|
||||
|
||||
/* Remember the index of every item to be updated.
|
||||
*/
|
||||
sqlite3VdbeAddOp(v, OP_ListWrite, 0, 0);
|
||||
|
||||
/* End the database scan loop.
|
||||
*/
|
||||
sqlite3WhereEnd(pWInfo);
|
||||
|
||||
/* Initialize the count of updated rows
|
||||
*/
|
||||
if( db->flags & SQLITE_CountRows && !pParse->trigStack ){
|
||||
sqlite3VdbeAddOp(v, OP_Integer, 0, 0);
|
||||
}
|
||||
|
||||
if( row_triggers_exist ){
|
||||
/* Create pseudo-tables for NEW and OLD
|
||||
*/
|
||||
sqlite3VdbeAddOp(v, OP_OpenPseudo, oldIdx, 0);
|
||||
sqlite3VdbeAddOp(v, OP_SetNumColumns, oldIdx, pTab->nCol);
|
||||
sqlite3VdbeAddOp(v, OP_OpenPseudo, newIdx, 0);
|
||||
sqlite3VdbeAddOp(v, OP_SetNumColumns, newIdx, pTab->nCol);
|
||||
|
||||
/* The top of the update loop for when there are triggers.
|
||||
*/
|
||||
sqlite3VdbeAddOp(v, OP_ListRewind, 0, 0);
|
||||
addr = sqlite3VdbeAddOp(v, OP_ListRead, 0, 0);
|
||||
sqlite3VdbeAddOp(v, OP_Dup, 0, 0);
|
||||
|
||||
/* Open a cursor and make it point to the record that is
|
||||
** being updated.
|
||||
*/
|
||||
sqlite3VdbeAddOp(v, OP_Dup, 0, 0);
|
||||
if( !isView ){
|
||||
sqlite3OpenTableForReading(v, iCur, pTab);
|
||||
}
|
||||
sqlite3VdbeAddOp(v, OP_MoveGe, iCur, 0);
|
||||
|
||||
/* Generate the OLD table
|
||||
*/
|
||||
sqlite3VdbeAddOp(v, OP_Recno, iCur, 0);
|
||||
sqlite3VdbeAddOp(v, OP_RowData, iCur, 0);
|
||||
sqlite3VdbeAddOp(v, OP_PutIntKey, oldIdx, 0);
|
||||
|
||||
/* Generate the NEW table
|
||||
*/
|
||||
if( chngRecno ){
|
||||
sqlite3ExprCode(pParse, pRecnoExpr);
|
||||
}else{
|
||||
sqlite3VdbeAddOp(v, OP_Recno, iCur, 0);
|
||||
}
|
||||
for(i=0; i<pTab->nCol; i++){ /* TODO: Factor out this loop as common code */
|
||||
if( i==pTab->iPKey ){
|
||||
sqlite3VdbeAddOp(v, OP_String8, 0, 0);
|
||||
continue;
|
||||
}
|
||||
j = aXRef[i];
|
||||
if( j<0 ){
|
||||
sqlite3VdbeAddOp(v, OP_Column, iCur, i);
|
||||
}else{
|
||||
sqlite3ExprCode(pParse, pChanges->a[j].pExpr);
|
||||
}
|
||||
}
|
||||
sqlite3VdbeAddOp(v, OP_MakeRecord, pTab->nCol, 0);
|
||||
if( !isView ){
|
||||
sqlite3TableAffinityStr(v, pTab);
|
||||
}
|
||||
if( pParse->nErr ) goto update_cleanup;
|
||||
sqlite3VdbeAddOp(v, OP_PutIntKey, newIdx, 0);
|
||||
if( !isView ){
|
||||
sqlite3VdbeAddOp(v, OP_Close, iCur, 0);
|
||||
}
|
||||
|
||||
/* Fire the BEFORE and INSTEAD OF triggers
|
||||
*/
|
||||
if( sqlite3CodeRowTrigger(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.
|
||||
*/
|
||||
sqlite3VdbeAddOp(v, OP_Integer, pTab->iDb, 0);
|
||||
sqlite3VdbeAddOp(v, OP_OpenWrite, iCur, pTab->tnum);
|
||||
sqlite3VdbeAddOp(v, OP_SetNumColumns, iCur, pTab->nCol);
|
||||
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] ){
|
||||
sqlite3VdbeAddOp(v, OP_Integer, pIdx->iDb, 0);
|
||||
sqlite3VdbeOp3(v, OP_OpenWrite, iCur+i+1, pIdx->tnum,
|
||||
(char*)&pIdx->keyInfo, P3_KEYINFO);
|
||||
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 ){
|
||||
sqlite3VdbeAddOp(v, OP_ListRewind, 0, 0);
|
||||
addr = sqlite3VdbeAddOp(v, OP_ListRead, 0, 0);
|
||||
sqlite3VdbeAddOp(v, OP_Dup, 0, 0);
|
||||
}
|
||||
sqlite3VdbeAddOp(v, OP_NotExists, iCur, addr);
|
||||
|
||||
/* If the record number will change, push the record number as it
|
||||
** will be after the update. (The old record number is currently
|
||||
** on top of the stack.)
|
||||
*/
|
||||
if( chngRecno ){
|
||||
sqlite3ExprCode(pParse, pRecnoExpr);
|
||||
sqlite3VdbeAddOp(v, OP_MustBeInt, 0, 0);
|
||||
}
|
||||
|
||||
/* Compute new data for this record.
|
||||
*/
|
||||
for(i=0; i<pTab->nCol; i++){
|
||||
if( i==pTab->iPKey ){
|
||||
sqlite3VdbeAddOp(v, OP_String8, 0, 0);
|
||||
continue;
|
||||
}
|
||||
j = aXRef[i];
|
||||
if( j<0 ){
|
||||
sqlite3VdbeAddOp(v, OP_Column, iCur, i);
|
||||
}else{
|
||||
sqlite3ExprCode(pParse, pChanges->a[j].pExpr);
|
||||
}
|
||||
}
|
||||
|
||||
/* Do constraint checks
|
||||
*/
|
||||
sqlite3GenerateConstraintChecks(pParse, pTab, iCur, aIdxUsed, chngRecno, 1,
|
||||
onError, addr);
|
||||
|
||||
/* Delete the old indices for the current record.
|
||||
*/
|
||||
sqlite3GenerateRowIndexDelete(db, v, pTab, iCur, aIdxUsed);
|
||||
|
||||
/* If changing the record number, delete the old record.
|
||||
*/
|
||||
if( chngRecno ){
|
||||
sqlite3VdbeAddOp(v, OP_Delete, iCur, 0);
|
||||
}
|
||||
|
||||
/* Create the new index entries and the new record.
|
||||
*/
|
||||
sqlite3CompleteInsertion(pParse, pTab, iCur, aIdxUsed, chngRecno, 1, -1);
|
||||
}
|
||||
|
||||
/* Increment the row counter
|
||||
*/
|
||||
if( db->flags & SQLITE_CountRows && !pParse->trigStack){
|
||||
sqlite3VdbeAddOp(v, OP_AddImm, 1, 0);
|
||||
}
|
||||
|
||||
/* If there are triggers, close all the cursors after each iteration
|
||||
** through the loop. The fire the after triggers.
|
||||
*/
|
||||
if( row_triggers_exist ){
|
||||
if( !isView ){
|
||||
for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
|
||||
if( openAll || aIdxUsed[i] )
|
||||
sqlite3VdbeAddOp(v, OP_Close, iCur+i+1, 0);
|
||||
}
|
||||
sqlite3VdbeAddOp(v, OP_Close, iCur, 0);
|
||||
}
|
||||
if( sqlite3CodeRowTrigger(pParse, TK_UPDATE, pChanges, 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.
|
||||
*/
|
||||
sqlite3VdbeAddOp(v, OP_Goto, 0, addr);
|
||||
sqlite3VdbeChangeP2(v, addr, sqlite3VdbeCurrentAddr(v));
|
||||
sqlite3VdbeAddOp(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] ){
|
||||
sqlite3VdbeAddOp(v, OP_Close, iCur+i+1, 0);
|
||||
}
|
||||
}
|
||||
sqlite3VdbeAddOp(v, OP_Close, iCur, 0);
|
||||
}else{
|
||||
sqlite3VdbeAddOp(v, OP_Close, newIdx, 0);
|
||||
sqlite3VdbeAddOp(v, OP_Close, oldIdx, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the number of rows that were changed.
|
||||
*/
|
||||
if( db->flags & SQLITE_CountRows && !pParse->trigStack ){
|
||||
sqlite3VdbeAddOp(v, OP_Callback, 1, 0);
|
||||
sqlite3VdbeSetNumCols(v, 1);
|
||||
sqlite3VdbeSetColName(v, 0, "rows updated", P3_STATIC);
|
||||
}
|
||||
|
||||
update_cleanup:
|
||||
sqlite3AuthContextPop(&sContext);
|
||||
sqliteFree(apIdx);
|
||||
sqliteFree(aXRef);
|
||||
sqlite3SrcListDelete(pTabList);
|
||||
sqlite3ExprListDelete(pChanges);
|
||||
sqlite3ExprDelete(pWhere);
|
||||
return;
|
||||
}
|
|
@ -0,0 +1,566 @@
|
|||
/*
|
||||
** 2004 April 13
|
||||
**
|
||||
** The author disclaims copyright to this source code. In place of
|
||||
** a legal notice, here is a blessing:
|
||||
**
|
||||
** May you do good and not evil.
|
||||
** May you find forgiveness for yourself and forgive others.
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
*************************************************************************
|
||||
** This file contains routines used to translate between UTF-8,
|
||||
** UTF-16, UTF-16BE, and UTF-16LE.
|
||||
**
|
||||
** $Id: utf.c,v 1.29 2004/09/24 23:20:52 drh Exp $
|
||||
**
|
||||
** Notes on UTF-8:
|
||||
**
|
||||
** Byte-0 Byte-1 Byte-2 Byte-3 Value
|
||||
** 0xxxxxxx 00000000 00000000 0xxxxxxx
|
||||
** 110yyyyy 10xxxxxx 00000000 00000yyy yyxxxxxx
|
||||
** 1110zzzz 10yyyyyy 10xxxxxx 00000000 zzzzyyyy yyxxxxxx
|
||||
** 11110uuu 10uuzzzz 10yyyyyy 10xxxxxx 000uuuuu zzzzyyyy yyxxxxxx
|
||||
**
|
||||
**
|
||||
** Notes on UTF-16: (with wwww+1==uuuuu)
|
||||
**
|
||||
** Word-0 Word-1 Value
|
||||
** 110110ww wwzzzzyy 110111yy yyxxxxxx 000uuuuu zzzzyyyy yyxxxxxx
|
||||
** zzzzyyyy yyxxxxxx 00000000 zzzzyyyy yyxxxxxx
|
||||
**
|
||||
**
|
||||
** BOM or Byte Order Mark:
|
||||
** 0xff 0xfe little-endian utf-16 follows
|
||||
** 0xfe 0xff big-endian utf-16 follows
|
||||
**
|
||||
**
|
||||
** Handling of malformed strings:
|
||||
**
|
||||
** SQLite accepts and processes malformed strings without an error wherever
|
||||
** possible. However this is not possible when converting between UTF-8 and
|
||||
** UTF-16.
|
||||
**
|
||||
** When converting malformed UTF-8 strings to UTF-16, one instance of the
|
||||
** replacement character U+FFFD for each byte that cannot be interpeted as
|
||||
** part of a valid unicode character.
|
||||
**
|
||||
** When converting malformed UTF-16 strings to UTF-8, one instance of the
|
||||
** replacement character U+FFFD for each pair of bytes that cannot be
|
||||
** interpeted as part of a valid unicode character.
|
||||
**
|
||||
** This file contains the following public routines:
|
||||
**
|
||||
** sqlite3VdbeMemTranslate() - Translate the encoding used by a Mem* string.
|
||||
** sqlite3VdbeMemHandleBom() - Handle byte-order-marks in UTF16 Mem* strings.
|
||||
** sqlite3utf16ByteLen() - Calculate byte-length of a void* UTF16 string.
|
||||
** sqlite3utf8CharLen() - Calculate char-length of a char* UTF8 string.
|
||||
** sqlite3utf8LikeCompare() - Do a LIKE match given two UTF8 char* strings.
|
||||
**
|
||||
*/
|
||||
#include <assert.h>
|
||||
#include "sqliteInt.h"
|
||||
#include "vdbeInt.h"
|
||||
|
||||
/*
|
||||
** This table maps from the first byte of a UTF-8 character to the number
|
||||
** of trailing bytes expected. A value '255' indicates that the table key
|
||||
** is not a legal first byte for a UTF-8 character.
|
||||
*/
|
||||
static const u8 xtra_utf8_bytes[256] = {
|
||||
/* 0xxxxxxx */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
|
||||
/* 10wwwwww */
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
|
||||
/* 110yyyyy */
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
|
||||
/* 1110zzzz */
|
||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||
|
||||
/* 11110yyy */
|
||||
3, 3, 3, 3, 3, 3, 3, 3, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
};
|
||||
|
||||
/*
|
||||
** This table maps from the number of trailing bytes in a UTF-8 character
|
||||
** to an integer constant that is effectively calculated for each character
|
||||
** read by a naive implementation of a UTF-8 character reader. The code
|
||||
** in the READ_UTF8 macro explains things best.
|
||||
*/
|
||||
static const int xtra_utf8_bits[4] = {
|
||||
0,
|
||||
12416, /* (0xC0 << 6) + (0x80) */
|
||||
925824, /* (0xE0 << 12) + (0x80 << 6) + (0x80) */
|
||||
63447168 /* (0xF0 << 18) + (0x80 << 12) + (0x80 << 6) + 0x80 */
|
||||
};
|
||||
|
||||
#define READ_UTF8(zIn, c) { \
|
||||
int xtra; \
|
||||
c = *(zIn)++; \
|
||||
xtra = xtra_utf8_bytes[c]; \
|
||||
switch( xtra ){ \
|
||||
case 255: c = (int)0xFFFD; break; \
|
||||
case 3: c = (c<<6) + *(zIn)++; \
|
||||
case 2: c = (c<<6) + *(zIn)++; \
|
||||
case 1: c = (c<<6) + *(zIn)++; \
|
||||
c -= xtra_utf8_bits[xtra]; \
|
||||
} \
|
||||
}
|
||||
int sqlite3ReadUtf8(const unsigned char *z){
|
||||
int c;
|
||||
READ_UTF8(z, c);
|
||||
return c;
|
||||
}
|
||||
|
||||
#define SKIP_UTF8(zIn) { \
|
||||
zIn += (xtra_utf8_bytes[*(u8 *)zIn] + 1); \
|
||||
}
|
||||
|
||||
#define WRITE_UTF8(zOut, c) { \
|
||||
if( c<0x00080 ){ \
|
||||
*zOut++ = (c&0xFF); \
|
||||
} \
|
||||
else if( c<0x00800 ){ \
|
||||
*zOut++ = 0xC0 + ((c>>6)&0x1F); \
|
||||
*zOut++ = 0x80 + (c & 0x3F); \
|
||||
} \
|
||||
else if( c<0x10000 ){ \
|
||||
*zOut++ = 0xE0 + ((c>>12)&0x0F); \
|
||||
*zOut++ = 0x80 + ((c>>6) & 0x3F); \
|
||||
*zOut++ = 0x80 + (c & 0x3F); \
|
||||
}else{ \
|
||||
*zOut++ = 0xF0 + ((c>>18) & 0x07); \
|
||||
*zOut++ = 0x80 + ((c>>12) & 0x3F); \
|
||||
*zOut++ = 0x80 + ((c>>6) & 0x3F); \
|
||||
*zOut++ = 0x80 + (c & 0x3F); \
|
||||
} \
|
||||
}
|
||||
|
||||
#define WRITE_UTF16LE(zOut, c) { \
|
||||
if( c<=0xFFFF ){ \
|
||||
*zOut++ = (c&0x00FF); \
|
||||
*zOut++ = ((c>>8)&0x00FF); \
|
||||
}else{ \
|
||||
*zOut++ = (((c>>10)&0x003F) + (((c-0x10000)>>10)&0x00C0)); \
|
||||
*zOut++ = (0x00D8 + (((c-0x10000)>>18)&0x03)); \
|
||||
*zOut++ = (c&0x00FF); \
|
||||
*zOut++ = (0x00DC + ((c>>8)&0x03)); \
|
||||
} \
|
||||
}
|
||||
|
||||
#define WRITE_UTF16BE(zOut, c) { \
|
||||
if( c<=0xFFFF ){ \
|
||||
*zOut++ = ((c>>8)&0x00FF); \
|
||||
*zOut++ = (c&0x00FF); \
|
||||
}else{ \
|
||||
*zOut++ = (0x00D8 + (((c-0x10000)>>18)&0x03)); \
|
||||
*zOut++ = (((c>>10)&0x003F) + (((c-0x10000)>>10)&0x00C0)); \
|
||||
*zOut++ = (0x00DC + ((c>>8)&0x03)); \
|
||||
*zOut++ = (c&0x00FF); \
|
||||
} \
|
||||
}
|
||||
|
||||
#define READ_UTF16LE(zIn, c){ \
|
||||
c = (*zIn++); \
|
||||
c += ((*zIn++)<<8); \
|
||||
if( c>=0xD800 && c<=0xE000 ){ \
|
||||
int c2 = (*zIn++); \
|
||||
c2 += ((*zIn++)<<8); \
|
||||
c = (c2&0x03FF) + ((c&0x003F)<<10) + (((c&0x03C0)+0x0040)<<10); \
|
||||
} \
|
||||
}
|
||||
|
||||
#define READ_UTF16BE(zIn, c){ \
|
||||
c = ((*zIn++)<<8); \
|
||||
c += (*zIn++); \
|
||||
if( c>=0xD800 && c<=0xE000 ){ \
|
||||
int c2 = ((*zIn++)<<8); \
|
||||
c2 += (*zIn++); \
|
||||
c = (c2&0x03FF) + ((c&0x003F)<<10) + (((c&0x03C0)+0x0040)<<10); \
|
||||
} \
|
||||
}
|
||||
|
||||
#define SKIP_UTF16BE(zIn){ \
|
||||
if( *zIn>=0xD8 && (*zIn<0xE0 || (*zIn==0xE0 && *(zIn+1)==0x00)) ){ \
|
||||
zIn += 4; \
|
||||
}else{ \
|
||||
zIn += 2; \
|
||||
} \
|
||||
}
|
||||
#define SKIP_UTF16LE(zIn){ \
|
||||
zIn++; \
|
||||
if( *zIn>=0xD8 && (*zIn<0xE0 || (*zIn==0xE0 && *(zIn-1)==0x00)) ){ \
|
||||
zIn += 3; \
|
||||
}else{ \
|
||||
zIn += 1; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define RSKIP_UTF16LE(zIn){ \
|
||||
if( *zIn>=0xD8 && (*zIn<0xE0 || (*zIn==0xE0 && *(zIn-1)==0x00)) ){ \
|
||||
zIn -= 4; \
|
||||
}else{ \
|
||||
zIn -= 2; \
|
||||
} \
|
||||
}
|
||||
#define RSKIP_UTF16BE(zIn){ \
|
||||
zIn--; \
|
||||
if( *zIn>=0xD8 && (*zIn<0xE0 || (*zIn==0xE0 && *(zIn+1)==0x00)) ){ \
|
||||
zIn -= 3; \
|
||||
}else{ \
|
||||
zIn -= 1; \
|
||||
} \
|
||||
}
|
||||
|
||||
/*
|
||||
** If the TRANSLATE_TRACE macro is defined, the value of each Mem is
|
||||
** printed on stderr on the way into and out of sqlite3VdbeMemTranslate().
|
||||
*/
|
||||
/* #define TRANSLATE_TRACE 1 */
|
||||
|
||||
/*
|
||||
** This routine transforms the internal text encoding used by pMem to
|
||||
** desiredEnc. It is an error if the string is already of the desired
|
||||
** encoding, or if *pMem does not contain a string value.
|
||||
*/
|
||||
int sqlite3VdbeMemTranslate(Mem *pMem, u8 desiredEnc){
|
||||
unsigned char zShort[NBFS]; /* Temporary short output buffer */
|
||||
int len; /* Maximum length of output string in bytes */
|
||||
unsigned char *zOut; /* Output buffer */
|
||||
unsigned char *zIn; /* Input iterator */
|
||||
unsigned char *zTerm; /* End of input */
|
||||
unsigned char *z; /* Output iterator */
|
||||
int c;
|
||||
|
||||
assert( pMem->flags&MEM_Str );
|
||||
assert( pMem->enc!=desiredEnc );
|
||||
assert( pMem->enc!=0 );
|
||||
assert( pMem->n>=0 );
|
||||
|
||||
#ifdef TRANSLATE_TRACE
|
||||
{
|
||||
char zBuf[100];
|
||||
sqlite3VdbeMemPrettyPrint(pMem, zBuf, 100);
|
||||
fprintf(stderr, "INPUT: %s\n", zBuf);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* If the translation is between UTF-16 little and big endian, then
|
||||
** all that is required is to swap the byte order. This case is handled
|
||||
** differently from the others.
|
||||
*/
|
||||
if( pMem->enc!=SQLITE_UTF8 && desiredEnc!=SQLITE_UTF8 ){
|
||||
u8 temp;
|
||||
int rc;
|
||||
rc = sqlite3VdbeMemMakeWriteable(pMem);
|
||||
if( rc!=SQLITE_OK ){
|
||||
assert( rc==SQLITE_NOMEM );
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
zIn = pMem->z;
|
||||
zTerm = &zIn[pMem->n];
|
||||
while( zIn<zTerm ){
|
||||
temp = *zIn;
|
||||
*zIn = *(zIn+1);
|
||||
zIn++;
|
||||
*zIn++ = temp;
|
||||
}
|
||||
pMem->enc = desiredEnc;
|
||||
goto translate_out;
|
||||
}
|
||||
|
||||
/* Set len to the maximum number of bytes required in the output buffer. */
|
||||
if( desiredEnc==SQLITE_UTF8 ){
|
||||
/* When converting from UTF-16, the maximum growth results from
|
||||
** translating a 2-byte character to a 3-byte UTF-8 character (i.e.
|
||||
** code-point 0xFFFC). A single byte is required for the output string
|
||||
** nul-terminator.
|
||||
*/
|
||||
len = (pMem->n/2) * 3 + 1;
|
||||
}else{
|
||||
/* When converting from UTF-8 to UTF-16 the maximum growth is caused
|
||||
** when a 1-byte UTF-8 character is translated into a 2-byte UTF-16
|
||||
** character. Two bytes are required in the output buffer for the
|
||||
** nul-terminator.
|
||||
*/
|
||||
len = pMem->n * 2 + 2;
|
||||
}
|
||||
|
||||
/* Set zIn to point at the start of the input buffer and zTerm to point 1
|
||||
** byte past the end.
|
||||
**
|
||||
** Variable zOut is set to point at the output buffer. This may be space
|
||||
** obtained from malloc(), or Mem.zShort, if it large enough and not in
|
||||
** use, or the zShort array on the stack (see above).
|
||||
*/
|
||||
zIn = pMem->z;
|
||||
zTerm = &zIn[pMem->n];
|
||||
if( len>NBFS ){
|
||||
zOut = sqliteMallocRaw(len);
|
||||
if( !zOut ) return SQLITE_NOMEM;
|
||||
}else{
|
||||
zOut = zShort;
|
||||
}
|
||||
z = zOut;
|
||||
|
||||
if( pMem->enc==SQLITE_UTF8 ){
|
||||
if( desiredEnc==SQLITE_UTF16LE ){
|
||||
/* UTF-8 -> UTF-16 Little-endian */
|
||||
while( zIn<zTerm ){
|
||||
READ_UTF8(zIn, c);
|
||||
WRITE_UTF16LE(z, c);
|
||||
}
|
||||
}else{
|
||||
assert( desiredEnc==SQLITE_UTF16BE );
|
||||
/* UTF-8 -> UTF-16 Big-endian */
|
||||
while( zIn<zTerm ){
|
||||
READ_UTF8(zIn, c);
|
||||
WRITE_UTF16BE(z, c);
|
||||
}
|
||||
}
|
||||
pMem->n = z - zOut;
|
||||
*z++ = 0;
|
||||
}else{
|
||||
assert( desiredEnc==SQLITE_UTF8 );
|
||||
if( pMem->enc==SQLITE_UTF16LE ){
|
||||
/* UTF-16 Little-endian -> UTF-8 */
|
||||
while( zIn<zTerm ){
|
||||
READ_UTF16LE(zIn, c);
|
||||
WRITE_UTF8(z, c);
|
||||
}
|
||||
}else{
|
||||
/* UTF-16 Little-endian -> UTF-8 */
|
||||
while( zIn<zTerm ){
|
||||
READ_UTF16BE(zIn, c);
|
||||
WRITE_UTF8(z, c);
|
||||
}
|
||||
}
|
||||
pMem->n = z - zOut;
|
||||
}
|
||||
*z = 0;
|
||||
assert( (pMem->n+(desiredEnc==SQLITE_UTF8?1:2))<=len );
|
||||
|
||||
sqlite3VdbeMemRelease(pMem);
|
||||
pMem->flags &= ~(MEM_Static|MEM_Dyn|MEM_Ephem|MEM_Short);
|
||||
pMem->enc = desiredEnc;
|
||||
if( zOut==zShort ){
|
||||
memcpy(pMem->zShort, zOut, len);
|
||||
zOut = pMem->zShort;
|
||||
pMem->flags |= (MEM_Term|MEM_Short);
|
||||
}else{
|
||||
pMem->flags |= (MEM_Term|MEM_Dyn);
|
||||
}
|
||||
pMem->z = zOut;
|
||||
|
||||
translate_out:
|
||||
#ifdef TRANSLATE_TRACE
|
||||
{
|
||||
char zBuf[100];
|
||||
sqlite3VdbeMemPrettyPrint(pMem, zBuf, 100);
|
||||
fprintf(stderr, "OUTPUT: %s\n", zBuf);
|
||||
}
|
||||
#endif
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** This routine checks for a byte-order mark at the beginning of the
|
||||
** UTF-16 string stored in *pMem. If one is present, it is removed and
|
||||
** the encoding of the Mem adjusted. This routine does not do any
|
||||
** byte-swapping, it just sets Mem.enc appropriately.
|
||||
**
|
||||
** The allocation (static, dynamic etc.) and encoding of the Mem may be
|
||||
** changed by this function.
|
||||
*/
|
||||
int sqlite3VdbeMemHandleBom(Mem *pMem){
|
||||
int rc = SQLITE_OK;
|
||||
u8 bom = 0;
|
||||
|
||||
if( pMem->n<0 || pMem->n>1 ){
|
||||
u8 b1 = *(u8 *)pMem->z;
|
||||
u8 b2 = *(((u8 *)pMem->z) + 1);
|
||||
if( b1==0xFE && b2==0xFF ){
|
||||
bom = SQLITE_UTF16BE;
|
||||
}
|
||||
if( b1==0xFF && b2==0xFE ){
|
||||
bom = SQLITE_UTF16LE;
|
||||
}
|
||||
}
|
||||
|
||||
if( bom ){
|
||||
/* This function is called as soon as a string is stored in a Mem*,
|
||||
** from within sqlite3VdbeMemSetStr(). At that point it is not possible
|
||||
** for the string to be stored in Mem.zShort, or for it to be stored
|
||||
** in dynamic memory with no destructor.
|
||||
*/
|
||||
assert( !(pMem->flags&MEM_Short) );
|
||||
assert( !(pMem->flags&MEM_Dyn) || pMem->xDel );
|
||||
if( pMem->flags & MEM_Dyn ){
|
||||
void (*xDel)(void*) = pMem->xDel;
|
||||
char *z = pMem->z;
|
||||
pMem->z = 0;
|
||||
pMem->xDel = 0;
|
||||
rc = sqlite3VdbeMemSetStr(pMem, &z[2], pMem->n-2, bom, SQLITE_TRANSIENT);
|
||||
xDel(z);
|
||||
}else{
|
||||
rc = sqlite3VdbeMemSetStr(pMem, &pMem->z[2], pMem->n-2, bom,
|
||||
SQLITE_TRANSIENT);
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** pZ is a UTF-8 encoded unicode string. If nByte is less than zero,
|
||||
** return the number of unicode characters in pZ up to (but not including)
|
||||
** the first 0x00 byte. If nByte is not less than zero, return the
|
||||
** number of unicode characters in the first nByte of pZ (or up to
|
||||
** the first 0x00, whichever comes first).
|
||||
*/
|
||||
int sqlite3utf8CharLen(const char *z, int nByte){
|
||||
int r = 0;
|
||||
const char *zTerm;
|
||||
if( nByte>=0 ){
|
||||
zTerm = &z[nByte];
|
||||
}else{
|
||||
zTerm = (const char *)(-1);
|
||||
}
|
||||
assert( z<=zTerm );
|
||||
while( *z!=0 && z<zTerm ){
|
||||
SKIP_UTF8(z);
|
||||
r++;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
** pZ is a UTF-16 encoded unicode string. If nChar is less than zero,
|
||||
** return the number of bytes up to (but not including), the first pair
|
||||
** of consecutive 0x00 bytes in pZ. If nChar is not less than zero,
|
||||
** then return the number of bytes in the first nChar unicode characters
|
||||
** in pZ (or up until the first pair of 0x00 bytes, whichever comes first).
|
||||
*/
|
||||
int sqlite3utf16ByteLen(const void *zIn, int nChar){
|
||||
int c = 1;
|
||||
char const *z = zIn;
|
||||
int n = 0;
|
||||
if( SQLITE_UTF16NATIVE==SQLITE_UTF16BE ){
|
||||
while( c && ((nChar<0) || n<nChar) ){
|
||||
READ_UTF16BE(z, c);
|
||||
n++;
|
||||
}
|
||||
}else{
|
||||
while( c && ((nChar<0) || n<nChar) ){
|
||||
READ_UTF16LE(z, c);
|
||||
n++;
|
||||
}
|
||||
}
|
||||
return (z-(char const *)zIn)-((c==0)?2:0);
|
||||
}
|
||||
|
||||
/*
|
||||
** UTF-16 implementation of the substr()
|
||||
*/
|
||||
void sqlite3utf16Substr(
|
||||
sqlite3_context *context,
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
int y, z;
|
||||
unsigned char const *zStr;
|
||||
unsigned char const *zStrEnd;
|
||||
unsigned char const *zStart;
|
||||
unsigned char const *zEnd;
|
||||
int i;
|
||||
|
||||
zStr = (unsigned char const *)sqlite3_value_text16(argv[0]);
|
||||
zStrEnd = &zStr[sqlite3_value_bytes16(argv[0])];
|
||||
y = sqlite3_value_int(argv[1]);
|
||||
z = sqlite3_value_int(argv[2]);
|
||||
|
||||
if( y>0 ){
|
||||
y = y-1;
|
||||
zStart = zStr;
|
||||
if( SQLITE_UTF16BE==SQLITE_UTF16NATIVE ){
|
||||
for(i=0; i<y && zStart<zStrEnd; i++) SKIP_UTF16BE(zStart);
|
||||
}else{
|
||||
for(i=0; i<y && zStart<zStrEnd; i++) SKIP_UTF16LE(zStart);
|
||||
}
|
||||
}else{
|
||||
zStart = zStrEnd;
|
||||
if( SQLITE_UTF16BE==SQLITE_UTF16NATIVE ){
|
||||
for(i=y; i<0 && zStart>zStr; i++) RSKIP_UTF16BE(zStart);
|
||||
}else{
|
||||
for(i=y; i<0 && zStart>zStr; i++) RSKIP_UTF16LE(zStart);
|
||||
}
|
||||
for(; i<0; i++) z -= 1;
|
||||
}
|
||||
|
||||
zEnd = zStart;
|
||||
if( SQLITE_UTF16BE==SQLITE_UTF16NATIVE ){
|
||||
for(i=0; i<z && zEnd<zStrEnd; i++) SKIP_UTF16BE(zEnd);
|
||||
}else{
|
||||
for(i=0; i<z && zEnd<zStrEnd; i++) SKIP_UTF16LE(zEnd);
|
||||
}
|
||||
|
||||
sqlite3_result_text16(context, zStart, zEnd-zStart, SQLITE_TRANSIENT);
|
||||
}
|
||||
|
||||
#if defined(SQLITE_TEST)
|
||||
/*
|
||||
** This routine is called from the TCL test function "translate_selftest".
|
||||
** It checks that the primitives for serializing and deserializing
|
||||
** characters in each encoding are inverses of each other.
|
||||
*/
|
||||
void sqlite3utfSelfTest(){
|
||||
int i;
|
||||
unsigned char zBuf[20];
|
||||
unsigned char *z;
|
||||
int n;
|
||||
int c;
|
||||
|
||||
for(i=0; i<0x00110000; i++){
|
||||
z = zBuf;
|
||||
WRITE_UTF8(z, i);
|
||||
n = z-zBuf;
|
||||
z = zBuf;
|
||||
READ_UTF8(z, c);
|
||||
assert( c==i );
|
||||
assert( (z-zBuf)==n );
|
||||
}
|
||||
for(i=0; i<0x00110000; i++){
|
||||
if( i>=0xD800 && i<=0xE000 ) continue;
|
||||
z = zBuf;
|
||||
WRITE_UTF16LE(z, i);
|
||||
n = z-zBuf;
|
||||
z = zBuf;
|
||||
READ_UTF16LE(z, c);
|
||||
assert( c==i );
|
||||
assert( (z-zBuf)==n );
|
||||
}
|
||||
for(i=0; i<0x00110000; i++){
|
||||
if( i>=0xD800 && i<=0xE000 ) continue;
|
||||
z = zBuf;
|
||||
WRITE_UTF16BE(z, i);
|
||||
n = z-zBuf;
|
||||
z = zBuf;
|
||||
READ_UTF16BE(z, c);
|
||||
assert( c==i );
|
||||
assert( (z-zBuf)==n );
|
||||
}
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,962 @@
|
|||
/*
|
||||
** 2001 September 15
|
||||
**
|
||||
** The author disclaims copyright to this source code. In place of
|
||||
** a legal notice, here is a blessing:
|
||||
**
|
||||
** May you do good and not evil.
|
||||
** May you find forgiveness for yourself and forgive others.
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
*************************************************************************
|
||||
** Utility functions used throughout sqlite.
|
||||
**
|
||||
** This file contains functions for allocating memory, comparing
|
||||
** strings, and stuff like that.
|
||||
**
|
||||
** $Id: util.c,v 1.119 2004/09/30 13:43:13 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include <stdarg.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#if SQLITE_DEBUG>2 && defined(__GLIBC__)
|
||||
#include <execinfo.h>
|
||||
void print_stack_trace(){
|
||||
void *bt[30];
|
||||
int i;
|
||||
int n = backtrace(bt, 30);
|
||||
|
||||
sqlite3DebugPrintf("STACK: ");
|
||||
for(i=0; i<n;i++){
|
||||
sqlite3DebugPrintf("%p ", bt[i]);
|
||||
}
|
||||
sqlite3DebugPrintf("\n");
|
||||
}
|
||||
#else
|
||||
#define print_stack_trace()
|
||||
#endif
|
||||
|
||||
/*
|
||||
** If malloc() ever fails, this global variable gets set to 1.
|
||||
** This causes the library to abort and never again function.
|
||||
*/
|
||||
int sqlite3_malloc_failed = 0;
|
||||
|
||||
/*
|
||||
** If SQLITE_DEBUG is defined, then use versions of malloc() and
|
||||
** free() that track memory usage and check for buffer overruns.
|
||||
*/
|
||||
#ifdef SQLITE_DEBUG
|
||||
|
||||
/*
|
||||
** For keeping track of the number of mallocs and frees. This
|
||||
** is used to check for memory leaks.
|
||||
*/
|
||||
int sqlite3_nMalloc; /* Number of sqliteMalloc() calls */
|
||||
int sqlite3_nFree; /* Number of sqliteFree() calls */
|
||||
int sqlite3_iMallocFail; /* Fail sqliteMalloc() after this many calls */
|
||||
#if SQLITE_DEBUG>1
|
||||
static int memcnt = 0;
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Number of 32-bit guard words
|
||||
*/
|
||||
#define N_GUARD 1
|
||||
|
||||
/*
|
||||
** Allocate new memory and set it to zero. Return NULL if
|
||||
** no memory is available.
|
||||
*/
|
||||
void *sqlite3Malloc_(int n, int bZero, char *zFile, int line){
|
||||
void *p;
|
||||
int *pi;
|
||||
int i, k;
|
||||
if( sqlite3_iMallocFail>=0 ){
|
||||
sqlite3_iMallocFail--;
|
||||
if( sqlite3_iMallocFail==0 ){
|
||||
sqlite3_malloc_failed++;
|
||||
#if SQLITE_DEBUG>1
|
||||
fprintf(stderr,"**** failed to allocate %d bytes at %s:%d\n",
|
||||
n, zFile,line);
|
||||
#endif
|
||||
sqlite3_iMallocFail--;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if( n==0 ) return 0;
|
||||
k = (n+sizeof(int)-1)/sizeof(int);
|
||||
pi = malloc( (N_GUARD*2+1+k)*sizeof(int));
|
||||
if( pi==0 ){
|
||||
sqlite3_malloc_failed++;
|
||||
return 0;
|
||||
}
|
||||
sqlite3_nMalloc++;
|
||||
for(i=0; i<N_GUARD; i++) pi[i] = 0xdead1122;
|
||||
pi[N_GUARD] = n;
|
||||
for(i=0; i<N_GUARD; i++) pi[k+1+N_GUARD+i] = 0xdead3344;
|
||||
p = &pi[N_GUARD+1];
|
||||
memset(p, bZero==0, n);
|
||||
#if SQLITE_DEBUG>1
|
||||
print_stack_trace();
|
||||
fprintf(stderr,"%06d malloc %d bytes at 0x%x from %s:%d\n",
|
||||
++memcnt, n, (int)p, zFile,line);
|
||||
#endif
|
||||
return p;
|
||||
}
|
||||
|
||||
/*
|
||||
** Check to see if the given pointer was obtained from sqliteMalloc()
|
||||
** and is able to hold at least N bytes. Raise an exception if this
|
||||
** is not the case.
|
||||
**
|
||||
** This routine is used for testing purposes only.
|
||||
*/
|
||||
void sqlite3CheckMemory(void *p, int N){
|
||||
int *pi = p;
|
||||
int n, i, k;
|
||||
pi -= N_GUARD+1;
|
||||
for(i=0; i<N_GUARD; i++){
|
||||
assert( pi[i]==0xdead1122 );
|
||||
}
|
||||
n = pi[N_GUARD];
|
||||
assert( N>=0 && N<n );
|
||||
k = (n+sizeof(int)-1)/sizeof(int);
|
||||
for(i=0; i<N_GUARD; i++){
|
||||
assert( pi[k+N_GUARD+1+i]==0xdead3344 );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Free memory previously obtained from sqliteMalloc()
|
||||
*/
|
||||
void sqlite3Free_(void *p, char *zFile, int line){
|
||||
if( p ){
|
||||
int *pi, i, k, n;
|
||||
pi = p;
|
||||
pi -= N_GUARD+1;
|
||||
sqlite3_nFree++;
|
||||
for(i=0; i<N_GUARD; i++){
|
||||
if( pi[i]!=0xdead1122 ){
|
||||
fprintf(stderr,"Low-end memory corruption at 0x%x\n", (int)p);
|
||||
return;
|
||||
}
|
||||
}
|
||||
n = pi[N_GUARD];
|
||||
k = (n+sizeof(int)-1)/sizeof(int);
|
||||
for(i=0; i<N_GUARD; i++){
|
||||
if( pi[k+N_GUARD+1+i]!=0xdead3344 ){
|
||||
fprintf(stderr,"High-end memory corruption at 0x%x\n", (int)p);
|
||||
return;
|
||||
}
|
||||
}
|
||||
memset(pi, 0xff, (k+N_GUARD*2+1)*sizeof(int));
|
||||
#if SQLITE_DEBUG>1
|
||||
fprintf(stderr,"%06d free %d bytes at 0x%x from %s:%d\n",
|
||||
++memcnt, n, (int)p, zFile,line);
|
||||
#endif
|
||||
free(pi);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Resize a prior allocation. If p==0, then this routine
|
||||
** works just like sqliteMalloc(). If n==0, then this routine
|
||||
** works just like sqliteFree().
|
||||
*/
|
||||
void *sqlite3Realloc_(void *oldP, int n, char *zFile, int line){
|
||||
int *oldPi, *pi, i, k, oldN, oldK;
|
||||
void *p;
|
||||
if( oldP==0 ){
|
||||
return sqlite3Malloc_(n,1,zFile,line);
|
||||
}
|
||||
if( n==0 ){
|
||||
sqlite3Free_(oldP,zFile,line);
|
||||
return 0;
|
||||
}
|
||||
oldPi = oldP;
|
||||
oldPi -= N_GUARD+1;
|
||||
if( oldPi[0]!=0xdead1122 ){
|
||||
fprintf(stderr,"Low-end memory corruption in realloc at 0x%x\n", (int)oldP);
|
||||
return 0;
|
||||
}
|
||||
oldN = oldPi[N_GUARD];
|
||||
oldK = (oldN+sizeof(int)-1)/sizeof(int);
|
||||
for(i=0; i<N_GUARD; i++){
|
||||
if( oldPi[oldK+N_GUARD+1+i]!=0xdead3344 ){
|
||||
fprintf(stderr,"High-end memory corruption in realloc at 0x%x\n",
|
||||
(int)oldP);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
k = (n + sizeof(int) - 1)/sizeof(int);
|
||||
pi = malloc( (k+N_GUARD*2+1)*sizeof(int) );
|
||||
if( pi==0 ){
|
||||
sqlite3_malloc_failed++;
|
||||
return 0;
|
||||
}
|
||||
for(i=0; i<N_GUARD; i++) pi[i] = 0xdead1122;
|
||||
pi[N_GUARD] = n;
|
||||
for(i=0; i<N_GUARD; i++) pi[k+N_GUARD+1+i] = 0xdead3344;
|
||||
p = &pi[N_GUARD+1];
|
||||
memcpy(p, oldP, n>oldN ? oldN : n);
|
||||
if( n>oldN ){
|
||||
memset(&((char*)p)[oldN], 0x55, n-oldN);
|
||||
}
|
||||
memset(oldPi, 0xab, (oldK+N_GUARD+2)*sizeof(int));
|
||||
free(oldPi);
|
||||
#if SQLITE_DEBUG>1
|
||||
print_stack_trace();
|
||||
fprintf(stderr,"%06d realloc %d to %d bytes at 0x%x to 0x%x at %s:%d\n",
|
||||
++memcnt, oldN, n, (int)oldP, (int)p, zFile, line);
|
||||
#endif
|
||||
return p;
|
||||
}
|
||||
|
||||
/*
|
||||
** Make a copy of a string in memory obtained from sqliteMalloc()
|
||||
*/
|
||||
char *sqlite3StrDup_(const char *z, char *zFile, int line){
|
||||
char *zNew;
|
||||
if( z==0 ) return 0;
|
||||
zNew = sqlite3Malloc_(strlen(z)+1, 0, zFile, line);
|
||||
if( zNew ) strcpy(zNew, z);
|
||||
return zNew;
|
||||
}
|
||||
char *sqlite3StrNDup_(const char *z, int n, char *zFile, int line){
|
||||
char *zNew;
|
||||
if( z==0 ) return 0;
|
||||
zNew = sqlite3Malloc_(n+1, 0, zFile, line);
|
||||
if( zNew ){
|
||||
memcpy(zNew, z, n);
|
||||
zNew[n] = 0;
|
||||
}
|
||||
return zNew;
|
||||
}
|
||||
|
||||
/*
|
||||
** A version of sqliteFree that is always a function, not a macro.
|
||||
*/
|
||||
void sqlite3FreeX(void *p){
|
||||
sqliteFree(p);
|
||||
}
|
||||
#endif /* SQLITE_DEBUG */
|
||||
|
||||
/*
|
||||
** The following versions of malloc() and free() are for use in a
|
||||
** normal build.
|
||||
*/
|
||||
#if !defined(SQLITE_DEBUG)
|
||||
|
||||
/*
|
||||
** Allocate new memory and set it to zero. Return NULL if
|
||||
** no memory is available. See also sqliteMallocRaw().
|
||||
*/
|
||||
void *sqlite3Malloc(int n){
|
||||
void *p;
|
||||
if( (p = malloc(n))==0 ){
|
||||
if( n>0 ) sqlite3_malloc_failed++;
|
||||
}else{
|
||||
memset(p, 0, n);
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
/*
|
||||
** Allocate new memory but do not set it to zero. Return NULL if
|
||||
** no memory is available. See also sqliteMalloc().
|
||||
*/
|
||||
void *sqlite3MallocRaw(int n){
|
||||
void *p;
|
||||
if( (p = malloc(n))==0 ){
|
||||
if( n>0 ) sqlite3_malloc_failed++;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
/*
|
||||
** Free memory previously obtained from sqliteMalloc()
|
||||
*/
|
||||
void sqlite3FreeX(void *p){
|
||||
if( p ){
|
||||
free(p);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Resize a prior allocation. If p==0, then this routine
|
||||
** works just like sqliteMalloc(). If n==0, then this routine
|
||||
** works just like sqliteFree().
|
||||
*/
|
||||
void *sqlite3Realloc(void *p, int n){
|
||||
void *p2;
|
||||
if( p==0 ){
|
||||
return sqliteMalloc(n);
|
||||
}
|
||||
if( n==0 ){
|
||||
sqliteFree(p);
|
||||
return 0;
|
||||
}
|
||||
p2 = realloc(p, n);
|
||||
if( p2==0 ){
|
||||
sqlite3_malloc_failed++;
|
||||
}
|
||||
return p2;
|
||||
}
|
||||
|
||||
/*
|
||||
** Make a copy of a string in memory obtained from sqliteMalloc()
|
||||
*/
|
||||
char *sqlite3StrDup(const char *z){
|
||||
char *zNew;
|
||||
if( z==0 ) return 0;
|
||||
zNew = sqliteMallocRaw(strlen(z)+1);
|
||||
if( zNew ) strcpy(zNew, z);
|
||||
return zNew;
|
||||
}
|
||||
char *sqlite3StrNDup(const char *z, int n){
|
||||
char *zNew;
|
||||
if( z==0 ) return 0;
|
||||
zNew = sqliteMallocRaw(n+1);
|
||||
if( zNew ){
|
||||
memcpy(zNew, z, n);
|
||||
zNew[n] = 0;
|
||||
}
|
||||
return zNew;
|
||||
}
|
||||
#endif /* !defined(SQLITE_DEBUG) */
|
||||
|
||||
/*
|
||||
** Create a string from the 2nd and subsequent arguments (up to the
|
||||
** first NULL argument), store the string in memory obtained from
|
||||
** sqliteMalloc() and make the pointer indicated by the 1st argument
|
||||
** point to that string. The 1st argument must either be NULL or
|
||||
** point to memory obtained from sqliteMalloc().
|
||||
*/
|
||||
void sqlite3SetString(char **pz, const char *zFirst, ...){
|
||||
va_list ap;
|
||||
int nByte;
|
||||
const char *z;
|
||||
char *zResult;
|
||||
|
||||
if( pz==0 ) return;
|
||||
nByte = strlen(zFirst) + 1;
|
||||
va_start(ap, zFirst);
|
||||
while( (z = va_arg(ap, const char*))!=0 ){
|
||||
nByte += strlen(z);
|
||||
}
|
||||
va_end(ap);
|
||||
sqliteFree(*pz);
|
||||
*pz = zResult = sqliteMallocRaw( nByte );
|
||||
if( zResult==0 ){
|
||||
return;
|
||||
}
|
||||
strcpy(zResult, zFirst);
|
||||
zResult += strlen(zResult);
|
||||
va_start(ap, zFirst);
|
||||
while( (z = va_arg(ap, const char*))!=0 ){
|
||||
strcpy(zResult, z);
|
||||
zResult += strlen(zResult);
|
||||
}
|
||||
va_end(ap);
|
||||
#ifdef SQLITE_DEBUG
|
||||
#if SQLITE_DEBUG>1
|
||||
fprintf(stderr,"string at 0x%x is %s\n", (int)*pz, *pz);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
** Set the most recent error code and error string for the sqlite
|
||||
** handle "db". The error code is set to "err_code".
|
||||
**
|
||||
** If it is not NULL, string zFormat specifies the format of the
|
||||
** error string in the style of the printf functions: The following
|
||||
** format characters are allowed:
|
||||
**
|
||||
** %s Insert a string
|
||||
** %z A string that should be freed after use
|
||||
** %d Insert an integer
|
||||
** %T Insert a token
|
||||
** %S Insert the first element of a SrcList
|
||||
**
|
||||
** zFormat and any string tokens that follow it are assumed to be
|
||||
** encoded in UTF-8.
|
||||
**
|
||||
** To clear the most recent error for slqite handle "db", sqlite3Error
|
||||
** should be called with err_code set to SQLITE_OK and zFormat set
|
||||
** to NULL.
|
||||
*/
|
||||
void sqlite3Error(sqlite3 *db, int err_code, const char *zFormat, ...){
|
||||
if( db && (db->pErr || (db->pErr = sqlite3ValueNew())) ){
|
||||
db->errCode = err_code;
|
||||
if( zFormat ){
|
||||
char *z;
|
||||
va_list ap;
|
||||
va_start(ap, zFormat);
|
||||
z = sqlite3VMPrintf(zFormat, ap);
|
||||
va_end(ap);
|
||||
sqlite3ValueSetStr(db->pErr, -1, z, SQLITE_UTF8, sqlite3FreeX);
|
||||
}else{
|
||||
sqlite3ValueSetStr(db->pErr, 0, 0, SQLITE_UTF8, SQLITE_STATIC);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Add an error message to pParse->zErrMsg and increment pParse->nErr.
|
||||
** The following formatting characters are allowed:
|
||||
**
|
||||
** %s Insert a string
|
||||
** %z A string that should be freed after use
|
||||
** %d Insert an integer
|
||||
** %T Insert a token
|
||||
** %S Insert the first element of a SrcList
|
||||
**
|
||||
** This function should be used to report any error that occurs whilst
|
||||
** compiling an SQL statement (i.e. within sqlite3_prepare()). The
|
||||
** last thing the sqlite3_prepare() function does is copy the error
|
||||
** stored by this function into the database handle using sqlite3Error().
|
||||
** Function sqlite3Error() should be used during statement execution
|
||||
** (sqlite3_step() etc.).
|
||||
*/
|
||||
void sqlite3ErrorMsg(Parse *pParse, const char *zFormat, ...){
|
||||
va_list ap;
|
||||
pParse->nErr++;
|
||||
sqliteFree(pParse->zErrMsg);
|
||||
va_start(ap, zFormat);
|
||||
pParse->zErrMsg = sqlite3VMPrintf(zFormat, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
/*
|
||||
** Convert an SQL-style quoted string into a normal string by removing
|
||||
** the quote characters. The conversion is done in-place. If the
|
||||
** input does not begin with a quote character, then this routine
|
||||
** is a no-op.
|
||||
**
|
||||
** 2002-Feb-14: This routine is extended to remove MS-Access style
|
||||
** brackets from around identifers. For example: "[a-b-c]" becomes
|
||||
** "a-b-c".
|
||||
*/
|
||||
void sqlite3Dequote(char *z){
|
||||
int quote;
|
||||
int i, j;
|
||||
if( z==0 ) return;
|
||||
quote = z[0];
|
||||
switch( quote ){
|
||||
case '\'': break;
|
||||
case '"': break;
|
||||
case '[': quote = ']'; break;
|
||||
default: return;
|
||||
}
|
||||
for(i=1, j=0; z[i]; i++){
|
||||
if( z[i]==quote ){
|
||||
if( z[i+1]==quote ){
|
||||
z[j++] = quote;
|
||||
i++;
|
||||
}else{
|
||||
z[j++] = 0;
|
||||
break;
|
||||
}
|
||||
}else{
|
||||
z[j++] = z[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* An array to map all upper-case characters into their corresponding
|
||||
** lower-case character.
|
||||
*/
|
||||
const unsigned char sqlite3UpperToLower[] = {
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
|
||||
18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
|
||||
36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53,
|
||||
54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 97, 98, 99,100,101,102,103,
|
||||
104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,
|
||||
122, 91, 92, 93, 94, 95, 96, 97, 98, 99,100,101,102,103,104,105,106,107,
|
||||
108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,
|
||||
126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,
|
||||
144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,
|
||||
162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,
|
||||
180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,
|
||||
198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,
|
||||
216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,
|
||||
234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,
|
||||
252,253,254,255
|
||||
};
|
||||
#define UpperToLower sqlite3UpperToLower
|
||||
|
||||
/*
|
||||
** This function computes a hash on the name of a keyword.
|
||||
** Case is not significant.
|
||||
*/
|
||||
int sqlite3HashNoCase(const char *z, int n){
|
||||
int h = 0;
|
||||
if( n<=0 ) n = strlen(z);
|
||||
while( n > 0 ){
|
||||
h = (h<<3) ^ h ^ UpperToLower[(unsigned char)*z++];
|
||||
n--;
|
||||
}
|
||||
return h & 0x7fffffff;
|
||||
}
|
||||
|
||||
/*
|
||||
** Some systems have stricmp(). Others have strcasecmp(). Because
|
||||
** there is no consistency, we will define our own.
|
||||
*/
|
||||
int sqlite3StrICmp(const char *zLeft, const char *zRight){
|
||||
register unsigned char *a, *b;
|
||||
a = (unsigned char *)zLeft;
|
||||
b = (unsigned char *)zRight;
|
||||
while( *a!=0 && UpperToLower[*a]==UpperToLower[*b]){ a++; b++; }
|
||||
return UpperToLower[*a] - UpperToLower[*b];
|
||||
}
|
||||
int sqlite3StrNICmp(const char *zLeft, const char *zRight, int N){
|
||||
register unsigned char *a, *b;
|
||||
a = (unsigned char *)zLeft;
|
||||
b = (unsigned char *)zRight;
|
||||
while( N-- > 0 && *a!=0 && UpperToLower[*a]==UpperToLower[*b]){ a++; b++; }
|
||||
return N<0 ? 0 : UpperToLower[*a] - UpperToLower[*b];
|
||||
}
|
||||
|
||||
/*
|
||||
** Return TRUE if z is a pure numeric string. Return FALSE if the
|
||||
** string contains any character which is not part of a number. If
|
||||
** the string is numeric and contains the '.' character, set *realnum
|
||||
** to TRUE (otherwise FALSE).
|
||||
**
|
||||
** An empty string is considered non-numeric.
|
||||
*/
|
||||
int sqlite3IsNumber(const char *z, int *realnum, u8 enc){
|
||||
int incr = (enc==SQLITE_UTF8?1:2);
|
||||
if( enc==SQLITE_UTF16BE ) z++;
|
||||
if( *z=='-' || *z=='+' ) z += incr;
|
||||
if( !isdigit(*(u8*)z) ){
|
||||
return 0;
|
||||
}
|
||||
z += incr;
|
||||
if( realnum ) *realnum = 0;
|
||||
while( isdigit(*(u8*)z) ){ z += incr; }
|
||||
if( *z=='.' ){
|
||||
z += incr;
|
||||
if( !isdigit(*(u8*)z) ) return 0;
|
||||
while( isdigit(*(u8*)z) ){ z += incr; }
|
||||
if( realnum ) *realnum = 1;
|
||||
}
|
||||
if( *z=='e' || *z=='E' ){
|
||||
z += incr;
|
||||
if( *z=='+' || *z=='-' ) z += incr;
|
||||
if( !isdigit(*(u8*)z) ) return 0;
|
||||
while( isdigit(*(u8*)z) ){ z += incr; }
|
||||
if( realnum ) *realnum = 1;
|
||||
}
|
||||
return *z==0;
|
||||
}
|
||||
|
||||
/*
|
||||
** The string z[] is an ascii representation of a real number.
|
||||
** Convert this string to a double.
|
||||
**
|
||||
** This routine assumes that z[] really is a valid number. If it
|
||||
** is not, the result is undefined.
|
||||
**
|
||||
** This routine is used instead of the library atof() function because
|
||||
** the library atof() might want to use "," as the decimal point instead
|
||||
** of "." depending on how locale is set. But that would cause problems
|
||||
** for SQL. So this routine always uses "." regardless of locale.
|
||||
*/
|
||||
double sqlite3AtoF(const char *z, const char **pzEnd){
|
||||
int sign = 1;
|
||||
LONGDOUBLE_TYPE v1 = 0.0;
|
||||
if( *z=='-' ){
|
||||
sign = -1;
|
||||
z++;
|
||||
}else if( *z=='+' ){
|
||||
z++;
|
||||
}
|
||||
while( isdigit(*(u8*)z) ){
|
||||
v1 = v1*10.0 + (*z - '0');
|
||||
z++;
|
||||
}
|
||||
if( *z=='.' ){
|
||||
LONGDOUBLE_TYPE divisor = 1.0;
|
||||
z++;
|
||||
while( isdigit(*(u8*)z) ){
|
||||
v1 = v1*10.0 + (*z - '0');
|
||||
divisor *= 10.0;
|
||||
z++;
|
||||
}
|
||||
v1 /= divisor;
|
||||
}
|
||||
if( *z=='e' || *z=='E' ){
|
||||
int esign = 1;
|
||||
int eval = 0;
|
||||
LONGDOUBLE_TYPE scale = 1.0;
|
||||
z++;
|
||||
if( *z=='-' ){
|
||||
esign = -1;
|
||||
z++;
|
||||
}else if( *z=='+' ){
|
||||
z++;
|
||||
}
|
||||
while( isdigit(*(u8*)z) ){
|
||||
eval = eval*10 + *z - '0';
|
||||
z++;
|
||||
}
|
||||
while( eval>=64 ){ scale *= 1.0e+64; eval -= 64; }
|
||||
while( eval>=16 ){ scale *= 1.0e+16; eval -= 16; }
|
||||
while( eval>=4 ){ scale *= 1.0e+4; eval -= 4; }
|
||||
while( eval>=1 ){ scale *= 1.0e+1; eval -= 1; }
|
||||
if( esign<0 ){
|
||||
v1 /= scale;
|
||||
}else{
|
||||
v1 *= scale;
|
||||
}
|
||||
}
|
||||
if( pzEnd ) *pzEnd = z;
|
||||
return sign<0 ? -v1 : v1;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return TRUE if zNum is a 64-bit signed integer and write
|
||||
** the value of the integer into *pNum. If zNum is not an integer
|
||||
** or is an integer that is too large to be expressed with 64 bits,
|
||||
** then return false. If n>0 and the integer is string is not
|
||||
** exactly n bytes long, return false.
|
||||
**
|
||||
** When this routine was originally written it dealt with only
|
||||
** 32-bit numbers. At that time, it was much faster than the
|
||||
** atoi() library routine in RedHat 7.2.
|
||||
*/
|
||||
int sqlite3atoi64(const char *zNum, i64 *pNum){
|
||||
i64 v = 0;
|
||||
int neg;
|
||||
int i, c;
|
||||
if( *zNum=='-' ){
|
||||
neg = 1;
|
||||
zNum++;
|
||||
}else if( *zNum=='+' ){
|
||||
neg = 0;
|
||||
zNum++;
|
||||
}else{
|
||||
neg = 0;
|
||||
}
|
||||
for(i=0; (c=zNum[i])>='0' && c<='9'; i++){
|
||||
v = v*10 + c - '0';
|
||||
}
|
||||
*pNum = neg ? -v : v;
|
||||
return c==0 && i>0 &&
|
||||
(i<19 || (i==19 && memcmp(zNum,"9223372036854775807",19)<=0));
|
||||
}
|
||||
|
||||
/*
|
||||
** The string zNum represents an integer. There might be some other
|
||||
** information following the integer too, but that part is ignored.
|
||||
** If the integer that the prefix of zNum represents will fit in a
|
||||
** 32-bit signed integer, return TRUE. Otherwise return FALSE.
|
||||
**
|
||||
** This routine returns FALSE for the string -2147483648 even that
|
||||
** that number will in fact fit in a 32-bit integer. But positive
|
||||
** 2147483648 will not fit in 32 bits. So it seems safer to return
|
||||
** false.
|
||||
*/
|
||||
static int sqlite3FitsIn32Bits(const char *zNum){
|
||||
int i, c;
|
||||
if( *zNum=='-' || *zNum=='+' ) zNum++;
|
||||
for(i=0; (c=zNum[i])>='0' && c<='9'; i++){}
|
||||
return i<10 || (i==10 && memcmp(zNum,"2147483647",10)<=0);
|
||||
}
|
||||
|
||||
/*
|
||||
** If zNum represents an integer that will fit in 32-bits, then set
|
||||
** *pValue to that integer and return true. Otherwise return false.
|
||||
*/
|
||||
int sqlite3GetInt32(const char *zNum, int *pValue){
|
||||
if( sqlite3FitsIn32Bits(zNum) ){
|
||||
*pValue = atoi(zNum);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** The string zNum represents an integer. There might be some other
|
||||
** information following the integer too, but that part is ignored.
|
||||
** If the integer that the prefix of zNum represents will fit in a
|
||||
** 64-bit signed integer, return TRUE. Otherwise return FALSE.
|
||||
**
|
||||
** This routine returns FALSE for the string -9223372036854775808 even that
|
||||
** that number will, in theory fit in a 64-bit integer. Positive
|
||||
** 9223373036854775808 will not fit in 64 bits. So it seems safer to return
|
||||
** false.
|
||||
*/
|
||||
int sqlite3FitsIn64Bits(const char *zNum){
|
||||
int i, c;
|
||||
if( *zNum=='-' || *zNum=='+' ) zNum++;
|
||||
for(i=0; (c=zNum[i])>='0' && c<='9'; i++){}
|
||||
return i<19 || (i==19 && memcmp(zNum,"9223372036854775807",19)<=0);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Change the sqlite.magic from SQLITE_MAGIC_OPEN to SQLITE_MAGIC_BUSY.
|
||||
** Return an error (non-zero) if the magic was not SQLITE_MAGIC_OPEN
|
||||
** when this routine is called.
|
||||
**
|
||||
** This routine is a attempt to detect if two threads use the
|
||||
** same sqlite* pointer at the same time. There is a race
|
||||
** condition so it is possible that the error is not detected.
|
||||
** But usually the problem will be seen. The result will be an
|
||||
** error which can be used to debug the application that is
|
||||
** using SQLite incorrectly.
|
||||
**
|
||||
** Ticket #202: If db->magic is not a valid open value, take care not
|
||||
** to modify the db structure at all. It could be that db is a stale
|
||||
** pointer. In other words, it could be that there has been a prior
|
||||
** call to sqlite3_close(db) and db has been deallocated. And we do
|
||||
** not want to write into deallocated memory.
|
||||
*/
|
||||
int sqlite3SafetyOn(sqlite3 *db){
|
||||
if( db->magic==SQLITE_MAGIC_OPEN ){
|
||||
db->magic = SQLITE_MAGIC_BUSY;
|
||||
return 0;
|
||||
}else if( db->magic==SQLITE_MAGIC_BUSY || db->magic==SQLITE_MAGIC_ERROR ){
|
||||
db->magic = SQLITE_MAGIC_ERROR;
|
||||
db->flags |= SQLITE_Interrupt;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
** Change the magic from SQLITE_MAGIC_BUSY to SQLITE_MAGIC_OPEN.
|
||||
** Return an error (non-zero) if the magic was not SQLITE_MAGIC_BUSY
|
||||
** when this routine is called.
|
||||
*/
|
||||
int sqlite3SafetyOff(sqlite3 *db){
|
||||
if( db->magic==SQLITE_MAGIC_BUSY ){
|
||||
db->magic = SQLITE_MAGIC_OPEN;
|
||||
return 0;
|
||||
}else if( db->magic==SQLITE_MAGIC_OPEN || db->magic==SQLITE_MAGIC_ERROR ){
|
||||
db->magic = SQLITE_MAGIC_ERROR;
|
||||
db->flags |= SQLITE_Interrupt;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
** Check to make sure we have a valid db pointer. This test is not
|
||||
** foolproof but it does provide some measure of protection against
|
||||
** misuse of the interface such as passing in db pointers that are
|
||||
** NULL or which have been previously closed. If this routine returns
|
||||
** TRUE it means that the db pointer is invalid and should not be
|
||||
** dereferenced for any reason. The calling function should invoke
|
||||
** SQLITE_MISUSE immediately.
|
||||
*/
|
||||
int sqlite3SafetyCheck(sqlite3 *db){
|
||||
int magic;
|
||||
if( db==0 ) return 1;
|
||||
magic = db->magic;
|
||||
if( magic!=SQLITE_MAGIC_CLOSED &&
|
||||
magic!=SQLITE_MAGIC_OPEN &&
|
||||
magic!=SQLITE_MAGIC_BUSY ) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** The variable-length integer encoding is as follows:
|
||||
**
|
||||
** KEY:
|
||||
** A = 0xxxxxxx 7 bits of data and one flag bit
|
||||
** B = 1xxxxxxx 7 bits of data and one flag bit
|
||||
** C = xxxxxxxx 8 bits of data
|
||||
**
|
||||
** 7 bits - A
|
||||
** 14 bits - BA
|
||||
** 21 bits - BBA
|
||||
** 28 bits - BBBA
|
||||
** 35 bits - BBBBA
|
||||
** 42 bits - BBBBBA
|
||||
** 49 bits - BBBBBBA
|
||||
** 56 bits - BBBBBBBA
|
||||
** 64 bits - BBBBBBBBC
|
||||
*/
|
||||
|
||||
/*
|
||||
** Write a 64-bit variable-length integer to memory starting at p[0].
|
||||
** The length of data write will be between 1 and 9 bytes. The number
|
||||
** of bytes written is returned.
|
||||
**
|
||||
** A variable-length integer consists of the lower 7 bits of each byte
|
||||
** for all bytes that have the 8th bit set and one byte with the 8th
|
||||
** bit clear. Except, if we get to the 9th byte, it stores the full
|
||||
** 8 bits and is the last byte.
|
||||
*/
|
||||
int sqlite3PutVarint(unsigned char *p, u64 v){
|
||||
int i, j, n;
|
||||
u8 buf[10];
|
||||
if( v & 0xff00000000000000 ){
|
||||
p[8] = v;
|
||||
v >>= 8;
|
||||
for(i=7; i>=0; i--){
|
||||
p[i] = (v & 0x7f) | 0x80;
|
||||
v >>= 7;
|
||||
}
|
||||
return 9;
|
||||
}
|
||||
n = 0;
|
||||
do{
|
||||
buf[n++] = (v & 0x7f) | 0x80;
|
||||
v >>= 7;
|
||||
}while( v!=0 );
|
||||
buf[0] &= 0x7f;
|
||||
assert( n<=9 );
|
||||
for(i=0, j=n-1; j>=0; j--, i++){
|
||||
p[i] = buf[j];
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
/*
|
||||
** Read a 64-bit variable-length integer from memory starting at p[0].
|
||||
** Return the number of bytes read. The value is stored in *v.
|
||||
*/
|
||||
int sqlite3GetVarint(const unsigned char *p, u64 *v){
|
||||
u32 x;
|
||||
u64 x64;
|
||||
int n;
|
||||
unsigned char c;
|
||||
if( ((c = p[0]) & 0x80)==0 ){
|
||||
*v = c;
|
||||
return 1;
|
||||
}
|
||||
x = c & 0x7f;
|
||||
if( ((c = p[1]) & 0x80)==0 ){
|
||||
*v = (x<<7) | c;
|
||||
return 2;
|
||||
}
|
||||
x = (x<<7) | (c&0x7f);
|
||||
if( ((c = p[2]) & 0x80)==0 ){
|
||||
*v = (x<<7) | c;
|
||||
return 3;
|
||||
}
|
||||
x = (x<<7) | (c&0x7f);
|
||||
if( ((c = p[3]) & 0x80)==0 ){
|
||||
*v = (x<<7) | c;
|
||||
return 4;
|
||||
}
|
||||
x64 = (x<<7) | (c&0x7f);
|
||||
n = 4;
|
||||
do{
|
||||
c = p[n++];
|
||||
if( n==9 ){
|
||||
x64 = (x64<<8) | c;
|
||||
break;
|
||||
}
|
||||
x64 = (x64<<7) | (c&0x7f);
|
||||
}while( (c & 0x80)!=0 );
|
||||
*v = x64;
|
||||
return n;
|
||||
}
|
||||
|
||||
/*
|
||||
** Read a 32-bit variable-length integer from memory starting at p[0].
|
||||
** Return the number of bytes read. The value is stored in *v.
|
||||
*/
|
||||
int sqlite3GetVarint32(const unsigned char *p, u32 *v){
|
||||
u32 x;
|
||||
int n;
|
||||
unsigned char c;
|
||||
if( ((c = p[0]) & 0x80)==0 ){
|
||||
*v = c;
|
||||
return 1;
|
||||
}
|
||||
x = c & 0x7f;
|
||||
if( ((c = p[1]) & 0x80)==0 ){
|
||||
*v = (x<<7) | c;
|
||||
return 2;
|
||||
}
|
||||
x = (x<<7) | (c & 0x7f);
|
||||
n = 2;
|
||||
do{
|
||||
x = (x<<7) | ((c = p[n++])&0x7f);
|
||||
}while( (c & 0x80)!=0 && n<9 );
|
||||
*v = x;
|
||||
return n;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the number of bytes that will be needed to store the given
|
||||
** 64-bit integer.
|
||||
*/
|
||||
int sqlite3VarintLen(u64 v){
|
||||
int i = 0;
|
||||
do{
|
||||
i++;
|
||||
v >>= 7;
|
||||
}while( v!=0 && i<9 );
|
||||
return i;
|
||||
}
|
||||
|
||||
/*
|
||||
** Translate a single byte of Hex into an integer.
|
||||
*/
|
||||
static int hexToInt(int h){
|
||||
if( h>='0' && h<='9' ){
|
||||
return h - '0';
|
||||
}else if( h>='a' && h<='f' ){
|
||||
return h - 'a' + 10;
|
||||
}else if( h>='A' && h<='F' ){
|
||||
return h - 'A' + 10;
|
||||
}else{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Convert a BLOB literal of the form "x'hhhhhh'" into its binary
|
||||
** value. Return a pointer to its binary value. Space to hold the
|
||||
** binary value has been obtained from malloc and must be freed by
|
||||
** the calling routine.
|
||||
*/
|
||||
void *sqlite3HexToBlob(const char *z){
|
||||
char *zBlob;
|
||||
int i;
|
||||
int n = strlen(z);
|
||||
if( n%2 ) return 0;
|
||||
|
||||
zBlob = (char *)sqliteMalloc(n/2);
|
||||
for(i=0; i<n; i+=2){
|
||||
zBlob[i/2] = (hexToInt(z[i])<<4) | hexToInt(z[i+1]);
|
||||
}
|
||||
return zBlob;
|
||||
}
|
||||
|
||||
#if defined(SQLITE_TEST)
|
||||
/*
|
||||
** Convert text generated by the "%p" conversion format back into
|
||||
** a pointer.
|
||||
*/
|
||||
void *sqlite3TextToPtr(const char *z){
|
||||
void *p;
|
||||
u64 v;
|
||||
u32 v2;
|
||||
if( z[0]=='0' && z[1]=='x' ){
|
||||
z += 2;
|
||||
}
|
||||
v = 0;
|
||||
while( *z ){
|
||||
v = (v<<4) + hexToInt(*z);
|
||||
z++;
|
||||
}
|
||||
if( sizeof(p)==sizeof(v) ){
|
||||
p = *(void**)&v;
|
||||
}else{
|
||||
assert( sizeof(p)==sizeof(v2) );
|
||||
v2 = (u32)v;
|
||||
p = *(void**)&v2;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,262 @@
|
|||
/*
|
||||
** 2003 April 6
|
||||
**
|
||||
** The author disclaims copyright to this source code. In place of
|
||||
** a legal notice, here is a blessing:
|
||||
**
|
||||
** May you do good and not evil.
|
||||
** May you find forgiveness for yourself and forgive others.
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
*************************************************************************
|
||||
** This file contains code used to implement the VACUUM command.
|
||||
**
|
||||
** Most of the code in this file may be omitted by defining the
|
||||
** SQLITE_OMIT_VACUUM macro.
|
||||
**
|
||||
** $Id: vacuum.c,v 1.32 2004/09/17 20:02:42 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include "os.h"
|
||||
|
||||
#if !defined(SQLITE_OMIT_VACUUM) || SQLITE_OMIT_VACUUM
|
||||
/*
|
||||
** Generate a random name of 20 character in length.
|
||||
*/
|
||||
static void randomName(unsigned char *zBuf){
|
||||
static const unsigned char zChars[] =
|
||||
"abcdefghijklmnopqrstuvwxyz"
|
||||
"0123456789";
|
||||
int i;
|
||||
sqlite3Randomness(20, zBuf);
|
||||
for(i=0; i<20; i++){
|
||||
zBuf[i] = zChars[ zBuf[i]%(sizeof(zChars)-1) ];
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Execute zSql on database db. Return an error code.
|
||||
*/
|
||||
static int execSql(sqlite3 *db, const char *zSql){
|
||||
sqlite3_stmt *pStmt;
|
||||
if( SQLITE_OK!=sqlite3_prepare(db, zSql, -1, &pStmt, 0) ){
|
||||
return sqlite3_errcode(db);
|
||||
}
|
||||
while( SQLITE_ROW==sqlite3_step(pStmt) );
|
||||
return sqlite3_finalize(pStmt);
|
||||
}
|
||||
|
||||
/*
|
||||
** Execute zSql on database db. The statement returns exactly
|
||||
** one column. Execute this as SQL on the same database.
|
||||
*/
|
||||
static int execExecSql(sqlite3 *db, const char *zSql){
|
||||
sqlite3_stmt *pStmt;
|
||||
int rc;
|
||||
|
||||
rc = sqlite3_prepare(db, zSql, -1, &pStmt, 0);
|
||||
if( rc!=SQLITE_OK ) return rc;
|
||||
|
||||
while( SQLITE_ROW==sqlite3_step(pStmt) ){
|
||||
rc = execSql(db, sqlite3_column_text(pStmt, 0));
|
||||
if( rc!=SQLITE_OK ){
|
||||
sqlite3_finalize(pStmt);
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
return sqlite3_finalize(pStmt);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
** The non-standard VACUUM command is used to clean up the database,
|
||||
** collapse free space, etc. It is modelled after the VACUUM command
|
||||
** in PostgreSQL.
|
||||
**
|
||||
** In version 1.0.x of SQLite, the VACUUM command would call
|
||||
** gdbm_reorganize() on all the database tables. But beginning
|
||||
** with 2.0.0, SQLite no longer uses GDBM so this command has
|
||||
** become a no-op.
|
||||
*/
|
||||
void sqlite3Vacuum(Parse *pParse, Token *pTableName){
|
||||
Vdbe *v = sqlite3GetVdbe(pParse);
|
||||
if( v ){
|
||||
sqlite3VdbeAddOp(v, OP_Vacuum, 0, 0);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
** This routine implements the OP_Vacuum opcode of the VDBE.
|
||||
*/
|
||||
int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
|
||||
int rc = SQLITE_OK; /* Return code from service routines */
|
||||
#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 */
|
||||
int i; /* Loop counter */
|
||||
Btree *pMain; /* The database being vacuumed */
|
||||
Btree *pTemp;
|
||||
char *zSql = 0;
|
||||
|
||||
if( !db->autoCommit ){
|
||||
sqlite3SetString(pzErrMsg, "cannot VACUUM from within a transaction",
|
||||
(char*)0);
|
||||
rc = SQLITE_ERROR;
|
||||
goto end_of_vacuum;
|
||||
}
|
||||
|
||||
/* Get the full pathname of the database file and create a
|
||||
** temporary filename in the same directory as the original file.
|
||||
*/
|
||||
pMain = db->aDb[0].pBt;
|
||||
zFilename = sqlite3BtreeGetFilename(pMain);
|
||||
assert( zFilename );
|
||||
if( zFilename[0]=='\0' ){
|
||||
/* The in-memory database. Do nothing. Return directly to avoid causing
|
||||
** an error trying to DETACH the vacuum_db (which never got attached)
|
||||
** in the exit-handler.
|
||||
*/
|
||||
return SQLITE_OK;
|
||||
}
|
||||
nFilename = strlen(zFilename);
|
||||
zTemp = sqliteMalloc( nFilename+100 );
|
||||
if( zTemp==0 ){
|
||||
rc = SQLITE_NOMEM;
|
||||
goto end_of_vacuum;
|
||||
}
|
||||
strcpy(zTemp, zFilename);
|
||||
i = 0;
|
||||
do {
|
||||
zTemp[nFilename] = '-';
|
||||
randomName((unsigned char*)&zTemp[nFilename+1]);
|
||||
} while( i<10 && sqlite3OsFileExists(zTemp) );
|
||||
|
||||
/* Attach the temporary database as 'vacuum_db'. The synchronous pragma
|
||||
** can be set to 'off' for this file, as it is not recovered if a crash
|
||||
** occurs anyway. The integrity of the database is maintained by a
|
||||
** (possibly synchronous) transaction opened on the main database before
|
||||
** sqlite3BtreeCopyFile() is called.
|
||||
**
|
||||
** An optimisation would be to use a non-journaled pager.
|
||||
*/
|
||||
zSql = sqlite3MPrintf("ATTACH '%q' AS vacuum_db;", zTemp);
|
||||
if( !zSql ){
|
||||
rc = SQLITE_NOMEM;
|
||||
goto end_of_vacuum;
|
||||
}
|
||||
rc = execSql(db, zSql);
|
||||
sqliteFree(zSql);
|
||||
zSql = 0;
|
||||
if( rc!=SQLITE_OK ) goto end_of_vacuum;
|
||||
assert( strcmp(db->aDb[db->nDb-1].zName,"vacuum_db")==0 );
|
||||
pTemp = db->aDb[db->nDb-1].pBt;
|
||||
sqlite3BtreeSetPageSize(pTemp, sqlite3BtreeGetPageSize(pMain),
|
||||
sqlite3BtreeGetReserve(pMain));
|
||||
assert( sqlite3BtreeGetPageSize(pTemp)==sqlite3BtreeGetPageSize(pMain) );
|
||||
execSql(db, "PRAGMA vacuum_db.synchronous=OFF");
|
||||
|
||||
/* Begin a transaction */
|
||||
rc = execSql(db, "BEGIN;");
|
||||
if( rc!=SQLITE_OK ) goto end_of_vacuum;
|
||||
|
||||
/* Query the schema of the main database. Create a mirror schema
|
||||
** in the temporary database.
|
||||
*/
|
||||
rc = execExecSql(db,
|
||||
"SELECT 'CREATE TABLE vacuum_db.' || substr(sql,14,100000000) "
|
||||
" FROM sqlite_master WHERE type='table' "
|
||||
"UNION ALL "
|
||||
"SELECT 'CREATE INDEX vacuum_db.' || substr(sql,14,100000000) "
|
||||
" FROM sqlite_master WHERE sql LIKE 'CREATE INDEX %' "
|
||||
"UNION ALL "
|
||||
"SELECT 'CREATE UNIQUE INDEX vacuum_db.' || substr(sql,21,100000000) "
|
||||
" FROM sqlite_master WHERE sql LIKE 'CREATE UNIQUE INDEX %'"
|
||||
"UNION ALL "
|
||||
"SELECT 'CREATE VIEW vacuum_db.' || substr(sql,13,100000000) "
|
||||
" FROM sqlite_master WHERE type='view'"
|
||||
);
|
||||
if( rc!=SQLITE_OK ) goto end_of_vacuum;
|
||||
|
||||
/* Loop through the tables in the main database. For each, do
|
||||
** an "INSERT INTO vacuum_db.xxx SELECT * FROM xxx;" to copy
|
||||
** the contents to the temporary database.
|
||||
*/
|
||||
rc = execExecSql(db,
|
||||
"SELECT 'INSERT INTO vacuum_db.' || quote(name) "
|
||||
"|| ' SELECT * FROM ' || quote(name) || ';'"
|
||||
"FROM sqlite_master "
|
||||
"WHERE type = 'table';"
|
||||
);
|
||||
if( rc!=SQLITE_OK ) goto end_of_vacuum;
|
||||
|
||||
/* Copy the triggers from the main database to the temporary database.
|
||||
** This was deferred before in case the triggers interfered with copying
|
||||
** the data. It's possible the indices should be deferred until this
|
||||
** point also.
|
||||
*/
|
||||
rc = execExecSql(db,
|
||||
"SELECT 'CREATE TRIGGER vacuum_db.' || substr(sql, 16, 1000000) "
|
||||
"FROM sqlite_master WHERE type='trigger'"
|
||||
);
|
||||
if( rc!=SQLITE_OK ) goto end_of_vacuum;
|
||||
|
||||
|
||||
/* At this point, unless the main db was completely empty, there is now a
|
||||
** transaction open on the vacuum database, but not on the main database.
|
||||
** Open a btree level transaction on the main database. This allows a
|
||||
** call to sqlite3BtreeCopyFile(). The main database btree level
|
||||
** transaction is then committed, so the SQL level never knows it was
|
||||
** opened for writing. This way, the SQL transaction used to create the
|
||||
** temporary database never needs to be committed.
|
||||
*/
|
||||
if( sqlite3BtreeIsInTrans(pTemp) ){
|
||||
u32 meta;
|
||||
|
||||
assert( 0==sqlite3BtreeIsInTrans(pMain) );
|
||||
rc = sqlite3BtreeBeginTrans(pMain, 1);
|
||||
if( rc!=SQLITE_OK ) goto end_of_vacuum;
|
||||
|
||||
/* Copy Btree meta values 3 and 4. These correspond to SQL layer meta
|
||||
** values 2 and 3, the default values of a couple of pragmas.
|
||||
*/
|
||||
rc = sqlite3BtreeGetMeta(pMain, 3, &meta);
|
||||
if( rc!=SQLITE_OK ) goto end_of_vacuum;
|
||||
rc = sqlite3BtreeUpdateMeta(pTemp, 3, meta);
|
||||
if( rc!=SQLITE_OK ) goto end_of_vacuum;
|
||||
rc = sqlite3BtreeGetMeta(pMain, 4, &meta);
|
||||
if( rc!=SQLITE_OK ) goto end_of_vacuum;
|
||||
rc = sqlite3BtreeUpdateMeta(pTemp, 4, meta);
|
||||
if( rc!=SQLITE_OK ) goto end_of_vacuum;
|
||||
|
||||
rc = sqlite3BtreeCopyFile(pMain, pTemp);
|
||||
if( rc!=SQLITE_OK ) goto end_of_vacuum;
|
||||
rc = sqlite3BtreeCommit(pMain);
|
||||
}
|
||||
|
||||
end_of_vacuum:
|
||||
/* Currently there is an SQL level transaction open on the vacuum
|
||||
** database. No locks are held on any other files (since the main file
|
||||
** was committed at the btree level). So it safe to end the transaction
|
||||
** by manually setting the autoCommit flag to true and detaching the
|
||||
** vacuum database. The vacuum_db journal file is deleted when the pager
|
||||
** is closed by the DETACH.
|
||||
*/
|
||||
db->autoCommit = 1;
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = execSql(db, "DETACH vacuum_db;");
|
||||
}else{
|
||||
execSql(db, "DETACH vacuum_db;");
|
||||
}
|
||||
if( zTemp ){
|
||||
sqlite3OsDelete(zTemp);
|
||||
sqliteFree(zTemp);
|
||||
}
|
||||
if( zSql ) sqliteFree( zSql );
|
||||
sqlite3ResetInternalSchema(db, 0);
|
||||
#endif
|
||||
return rc;
|
||||
}
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,131 @@
|
|||
/*
|
||||
** 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.91 2004/09/06 17:24:13 drh Exp $
|
||||
*/
|
||||
#ifndef _SQLITE_VDBE_H_
|
||||
#define _SQLITE_VDBE_H_
|
||||
#include <stdio.h>
|
||||
|
||||
/*
|
||||
** A single VDBE is an opaque structure named "Vdbe". Only routines
|
||||
** in the source file sqliteVdbe.c are allowed to see the insides
|
||||
** of this structure.
|
||||
*/
|
||||
typedef struct Vdbe Vdbe;
|
||||
|
||||
/*
|
||||
** A single instruction of the virtual machine has an opcode
|
||||
** and as many as three operands. The instruction is recorded
|
||||
** as an instance of the following structure:
|
||||
*/
|
||||
struct VdbeOp {
|
||||
u8 opcode; /* What operation to perform */
|
||||
int p1; /* First operand */
|
||||
int p2; /* Second parameter (often the jump destination) */
|
||||
char *p3; /* Third parameter */
|
||||
int p3type; /* 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 */
|
||||
#define P3_COLLSEQ (-4) /* P3 is a pointer to a CollSeq structure */
|
||||
#define P3_FUNCDEF (-5) /* P3 is a pointer to a FuncDef structure */
|
||||
#define P3_KEYINFO (-6) /* P3 is a pointer to a KeyInfo structure */
|
||||
#define P3_VDBEFUNC (-7) /* P3 is a pointer to a VdbeFunc structure */
|
||||
|
||||
/* When adding a P3 argument using P3_KEYINFO, a copy of the KeyInfo structure
|
||||
** is made. That copy is freed when the Vdbe is finalized. But if the
|
||||
** argument is P3_KEYINFO_HANDOFF, the passed in pointer is used. It still
|
||||
** gets freed when the Vdbe is finalized so it still should be obtained
|
||||
** from a single sqliteMalloc(). But no copy is made and the calling
|
||||
** function should *not* try to free the KeyInfo.
|
||||
*/
|
||||
#define P3_KEYINFO_HANDOFF (-7)
|
||||
|
||||
/*
|
||||
** The following macro converts a relative address in the p2 field
|
||||
** of a VdbeOp structure into a negative number so that
|
||||
** sqlite3VdbeAddOpList() knows that the address is relative. Calling
|
||||
** the macro again restores the address.
|
||||
*/
|
||||
#define ADDR(X) (-1-(X))
|
||||
|
||||
/*
|
||||
** The makefile scans the vdbe.c source file and creates the "opcodes.h"
|
||||
** header file that defines a number for each opcode used by the VDBE.
|
||||
*/
|
||||
#include "opcodes.h"
|
||||
|
||||
/*
|
||||
** Prototypes for the VDBE interface. See comments on the implementation
|
||||
** for a description of what each of these routines does.
|
||||
*/
|
||||
Vdbe *sqlite3VdbeCreate(sqlite3*);
|
||||
void sqlite3VdbeCreateCallback(Vdbe*, int*);
|
||||
int sqlite3VdbeAddOp(Vdbe*,int,int,int);
|
||||
int sqlite3VdbeOp3(Vdbe*,int,int,int,const char *zP3,int);
|
||||
int sqlite3VdbeAddOpList(Vdbe*, int nOp, VdbeOpList const *aOp);
|
||||
void sqlite3VdbeChangeP1(Vdbe*, int addr, int P1);
|
||||
void sqlite3VdbeChangeP2(Vdbe*, int addr, int P2);
|
||||
void sqlite3VdbeChangeP3(Vdbe*, int addr, const char *zP1, int N);
|
||||
void sqlite3VdbeDequoteP3(Vdbe*, int addr);
|
||||
int sqlite3VdbeFindOp(Vdbe*, int, int, int);
|
||||
VdbeOp *sqlite3VdbeGetOp(Vdbe*, int);
|
||||
int sqlite3VdbeMakeLabel(Vdbe*);
|
||||
void sqlite3VdbeDelete(Vdbe*);
|
||||
void sqlite3VdbeMakeReady(Vdbe*,int,int,int,int);
|
||||
int sqlite3VdbeFinalize(Vdbe*);
|
||||
void sqlite3VdbeResolveLabel(Vdbe*, int);
|
||||
int sqlite3VdbeCurrentAddr(Vdbe*);
|
||||
void sqlite3VdbeTrace(Vdbe*,FILE*);
|
||||
int sqlite3VdbeReset(Vdbe*);
|
||||
int sqliteVdbeSetVariables(Vdbe*,int,const char**);
|
||||
void sqlite3VdbeSetNumCols(Vdbe*,int);
|
||||
int sqlite3VdbeSetColName(Vdbe*, int, const char *, int);
|
||||
void sqlite3VdbeCountChanges(Vdbe*);
|
||||
|
||||
#ifndef NDEBUG
|
||||
void sqlite3VdbeComment(Vdbe*, const char*, ...);
|
||||
# define VdbeComment(X) sqlite3VdbeComment X
|
||||
#else
|
||||
# define VdbeComment(X)
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -0,0 +1,408 @@
|
|||
/*
|
||||
** 2003 September 6
|
||||
**
|
||||
** The author disclaims copyright to this source code. In place of
|
||||
** a legal notice, here is a blessing:
|
||||
**
|
||||
** May you do good and not evil.
|
||||
** May you find forgiveness for yourself and forgive others.
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
*************************************************************************
|
||||
** This is the header file for information that is private to the
|
||||
** VDBE. This information used to all be at the top of the single
|
||||
** source code file "vdbe.c". When that file became too big (over
|
||||
** 6000 lines long) it was split up into several smaller files and
|
||||
** this header information was factored out.
|
||||
*/
|
||||
|
||||
/*
|
||||
** intToKey() and keyToInt() used to transform the rowid. But with
|
||||
** the latest versions of the design they are no-ops.
|
||||
*/
|
||||
#define keyToInt(X) (X)
|
||||
#define intToKey(X) (X)
|
||||
|
||||
/*
|
||||
** The makefile scans the vdbe.c source file and creates the following
|
||||
** array of string constants which are the names of all VDBE opcodes. This
|
||||
** array is defined in a separate source code file named opcode.c which is
|
||||
** automatically generated by the makefile.
|
||||
*/
|
||||
extern char *sqlite3OpcodeNames[];
|
||||
|
||||
/*
|
||||
** SQL is translated into a sequence of instructions to be
|
||||
** executed by a virtual machine. Each instruction is an instance
|
||||
** of the following structure.
|
||||
*/
|
||||
typedef struct VdbeOp Op;
|
||||
|
||||
/*
|
||||
** Boolean values
|
||||
*/
|
||||
typedef unsigned char Bool;
|
||||
|
||||
/*
|
||||
** A cursor is a pointer into a single BTree within a database file.
|
||||
** The cursor can seek to a BTree entry with a particular key, or
|
||||
** loop over all entries of the Btree. You can also insert new BTree
|
||||
** entries or retrieve the key or data from the entry that the cursor
|
||||
** is currently pointing to.
|
||||
**
|
||||
** Every cursor that the virtual machine has open is represented by an
|
||||
** instance of the following structure.
|
||||
**
|
||||
** If the Cursor.isTriggerRow flag is set it means that this cursor is
|
||||
** really a single row that represents the NEW or OLD pseudo-table of
|
||||
** a row trigger. The data for the row is stored in Cursor.pData and
|
||||
** the rowid is in Cursor.iKey.
|
||||
*/
|
||||
struct Cursor {
|
||||
BtCursor *pCursor; /* The cursor structure of the backend */
|
||||
i64 lastRecno; /* Last recno from a Next or NextIdx operation */
|
||||
i64 nextRowid; /* Next rowid returned by OP_NewRowid */
|
||||
Bool zeroed; /* True if zeroed out and ready for reuse */
|
||||
Bool 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 sqlite3BtreeMoveto() is needed */
|
||||
Bool intKey; /* True if the table requires integer keys */
|
||||
Bool zeroData; /* True if table contains keys only - no data */
|
||||
u8 bogusIncrKey; /* Something for pIncrKey to point to if pKeyInfo==0 */
|
||||
i64 movetoTarget; /* Argument to the deferred sqlite3BtreeMoveto() */
|
||||
Btree *pBt; /* Separate file holding temporary table */
|
||||
int nData; /* Number of bytes in pData */
|
||||
char *pData; /* Data for a NEW or OLD pseudo-table */
|
||||
i64 iKey; /* Key for the NEW or OLD pseudo-table row */
|
||||
u8 *pIncrKey; /* Pointer to pKeyInfo->incrKey */
|
||||
KeyInfo *pKeyInfo; /* Info about index keys needed by index cursors */
|
||||
int nField; /* Number of fields in the header */
|
||||
|
||||
/* Cached information about the header for the data record that the
|
||||
** cursor is currently pointing to. Only valid if cacheValid is true.
|
||||
** zRow might point to (ephemeral) data for the current row, or it might
|
||||
** be NULL. */
|
||||
Bool cacheValid; /* True if the cache is valid */
|
||||
int payloadSize; /* Total number of bytes in the record */
|
||||
u32 *aType; /* Type values for all entries in the record */
|
||||
u32 *aOffset; /* Cached offsets to the start of each columns data */
|
||||
u8 *aRow; /* Data for the current row, if all on one page */
|
||||
};
|
||||
typedef struct Cursor Cursor;
|
||||
|
||||
/*
|
||||
** Number of bytes of string storage space available to each stack
|
||||
** layer without having to malloc. NBFS is short for Number of Bytes
|
||||
** For Strings.
|
||||
*/
|
||||
#define NBFS 32
|
||||
|
||||
/*
|
||||
** Internally, the vdbe manipulates nearly all SQL values as Mem
|
||||
** structures. Each Mem struct may cache multiple representations (string,
|
||||
** integer etc.) of the same value. A value (and therefore Mem structure)
|
||||
** has the following properties:
|
||||
**
|
||||
** Each value has a manifest type. The manifest type of the value stored
|
||||
** in a Mem struct is returned by the MemType(Mem*) macro. The type is
|
||||
** one of SQLITE_NULL, SQLITE_INTEGER, SQLITE_REAL, SQLITE_TEXT or
|
||||
** SQLITE_BLOB.
|
||||
*/
|
||||
struct Mem {
|
||||
i64 i; /* Integer value */
|
||||
int n; /* Number of characters in string value, including '\0' */
|
||||
u16 flags; /* Some combination of MEM_Null, MEM_Str, MEM_Dyn, etc. */
|
||||
u8 type; /* One of MEM_Null, MEM_Str, etc. */
|
||||
u8 enc; /* TEXT_Utf8, TEXT_Utf16le, or TEXT_Utf16be */
|
||||
double r; /* Real value */
|
||||
char *z; /* String or BLOB value */
|
||||
void (*xDel)(void *); /* If not null, call this function to delete Mem.z */
|
||||
char zShort[NBFS]; /* Space for short strings */
|
||||
};
|
||||
typedef struct Mem Mem;
|
||||
|
||||
/*
|
||||
** 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 */
|
||||
Mem data;
|
||||
Sorter *pNext; /* Next in the list */
|
||||
};
|
||||
|
||||
/*
|
||||
** Number of buckets used for merge-sort.
|
||||
*/
|
||||
#define NSORT 30
|
||||
|
||||
/* One or more of the following flags are set to indicate the validOK
|
||||
** representations of the value stored in the Mem struct.
|
||||
**
|
||||
** If the MEM_Null flag is set, then the value is an SQL NULL value.
|
||||
** No other flags may be set in this case.
|
||||
**
|
||||
** If the MEM_Str flag is set then Mem.z points at a string representation.
|
||||
** Usually this is encoded in the same unicode encoding as the main
|
||||
** database (see below for exceptions). If the MEM_Term flag is also
|
||||
** set, then the string is nul terminated. The MEM_Int and MEM_Real
|
||||
** flags may coexist with the MEM_Str flag.
|
||||
**
|
||||
** Multiple of these values can appear in Mem.flags. But only one
|
||||
** at a time can appear in Mem.type.
|
||||
*/
|
||||
#define MEM_Null 0x0001 /* Value is NULL */
|
||||
#define MEM_Str 0x0002 /* Value is a string */
|
||||
#define MEM_Int 0x0004 /* Value is an integer */
|
||||
#define MEM_Real 0x0008 /* Value is a real number */
|
||||
#define MEM_Blob 0x0010 /* Value is a BLOB */
|
||||
|
||||
/* Whenever Mem contains a valid string or blob representation, one of
|
||||
** the following flags must be set to determine the memory management
|
||||
** policy for Mem.z. The MEM_Term flag tells us whether or not the
|
||||
** string is \000 or \u0000 terminated
|
||||
*/
|
||||
#define MEM_Term 0x0020 /* String rep is nul terminated */
|
||||
#define MEM_Dyn 0x0040 /* Need to call sqliteFree() on Mem.z */
|
||||
#define MEM_Static 0x0080 /* Mem.z points to a static string */
|
||||
#define MEM_Ephem 0x0100 /* Mem.z points to an ephemeral string */
|
||||
#define MEM_Short 0x0200 /* Mem.z points to Mem.zShort */
|
||||
|
||||
/* 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 0x0400 /* Mem.z points to an agg function context */
|
||||
|
||||
|
||||
/* A VdbeFunc is just a FuncDef (defined in sqliteInt.h) that contains
|
||||
** additional information about auxiliary information bound to arguments
|
||||
** of the function. This is used to implement the sqlite3_get_auxdata()
|
||||
** and sqlite3_set_auxdata() APIs. The "auxdata" is some auxiliary data
|
||||
** that can be associated with a constant argument to a function. This
|
||||
** allows functions such as "regexp" to compile their constant regular
|
||||
** expression argument once and reused the compiled code for multiple
|
||||
** invocations.
|
||||
*/
|
||||
struct VdbeFunc {
|
||||
FuncDef *pFunc; /* The definition of the function */
|
||||
int nAux; /* Number of entries allocated for apAux[] */
|
||||
struct AuxData {
|
||||
void *pAux; /* Aux data for the i-th argument */
|
||||
void (*xDelete)(void *); /* Destructor for the aux data */
|
||||
} apAux[1]; /* One slot for each function argument */
|
||||
};
|
||||
typedef struct VdbeFunc VdbeFunc;
|
||||
|
||||
/*
|
||||
** The "context" argument for a installable function. A pointer to an
|
||||
** instance of this structure is the first argument to the routines used
|
||||
** implement the SQL functions.
|
||||
**
|
||||
** There is a typedef for this structure in sqlite.h. So all routines,
|
||||
** even the public interface to SQLite, can use a pointer to this structure.
|
||||
** But this file is the only place where the internal details of this
|
||||
** structure are known.
|
||||
**
|
||||
** This structure is defined inside of vdbe.c because it uses substructures
|
||||
** (Mem) which are only defined there.
|
||||
*/
|
||||
struct sqlite3_context {
|
||||
FuncDef *pFunc; /* Pointer to function information. MUST BE FIRST */
|
||||
VdbeFunc *pVdbeFunc; /* Auxilary data, if created. */
|
||||
Mem s; /* The return value is stored here */
|
||||
void *pAgg; /* Aggregate context */
|
||||
u8 isError; /* Set to true for an error */
|
||||
u8 isStep; /* Current in the step function */
|
||||
int cnt; /* Number of times that the step function has been called */
|
||||
CollSeq *pColl;
|
||||
};
|
||||
|
||||
/*
|
||||
** 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 */
|
||||
FuncDef **apFunc; /* Information about aggregate functions */
|
||||
Btree *pBtree; /* The tmp. btree used to group elements, if required. */
|
||||
BtCursor *pCsr; /* Read/write cursor to the table in pBtree */
|
||||
int nTab; /* Root page of the table in pBtree */
|
||||
u8 searching; /* True between the first AggNext and AggReset */
|
||||
};
|
||||
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 */
|
||||
i64 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).
|
||||
** The current keylist is also stored in the context.
|
||||
** Elements of Context structure type make up the ContextStack, which is
|
||||
** updated by the ContextPush and ContextPop opcodes (used by triggers).
|
||||
** The context is pushed before executing a trigger a popped when the
|
||||
** trigger finishes.
|
||||
*/
|
||||
typedef struct Context Context;
|
||||
struct Context {
|
||||
int lastRowid; /* Last insert rowid (sqlite3.lastRowid) */
|
||||
int nChange; /* Statement changes (Vdbe.nChanges) */
|
||||
Keylist *pList; /* Records that will participate in a DELETE or UPDATE */
|
||||
};
|
||||
|
||||
/*
|
||||
** An instance of the virtual machine. This structure contains the complete
|
||||
** state of the virtual machine.
|
||||
**
|
||||
** The "sqlite3_stmt" structure pointer that is returned by sqlite3_compile()
|
||||
** is really a pointer to an instance of this structure.
|
||||
*/
|
||||
struct Vdbe {
|
||||
sqlite3 *db; /* The whole database */
|
||||
Vdbe *pPrev,*pNext; /* Linked list of VDBEs with the same Vdbe.db */
|
||||
FILE *trace; /* Write an execution trace here, if not NULL */
|
||||
int nOp; /* Number of instructions in the program */
|
||||
int nOpAlloc; /* Number of slots allocated for aOp[] */
|
||||
Op *aOp; /* Space to hold the virtual machine's program */
|
||||
int nLabel; /* Number of labels used */
|
||||
int nLabelAlloc; /* Number of slots allocated in aLabel[] */
|
||||
int *aLabel; /* Space to hold the labels */
|
||||
Mem *aStack; /* The operand stack, except string values */
|
||||
Mem *pTos; /* Top entry in the operand stack */
|
||||
Mem **apArg; /* Arguments to currently executing user function */
|
||||
Mem *aColName; /* Column names to return */
|
||||
int nCursor; /* Number of slots in apCsr[] */
|
||||
Cursor **apCsr; /* One element of this array for each open cursor */
|
||||
Sorter *pSort; /* A linked list of objects to be sorted */
|
||||
int nVar; /* Number of entries in aVar[] */
|
||||
Mem *aVar; /* Values for the OP_Variable opcode. */
|
||||
char **azVar; /* Name of variables */
|
||||
int okVar; /* True if azVar[] has been initialized */
|
||||
int magic; /* Magic number for sanity checking */
|
||||
int nMem; /* Number of memory locations currently allocated */
|
||||
Mem *aMem; /* The memory locations */
|
||||
Agg agg; /* Aggregate information */
|
||||
int nCallback; /* Number of callbacks invoked so far */
|
||||
Keylist *pList; /* A list of ROWIDs */
|
||||
int contextStackTop; /* Index of top element in the context stack */
|
||||
int contextStackDepth; /* The size of the "context" stack */
|
||||
Context *contextStack; /* Stack used by opcodes ContextPush & ContextPop*/
|
||||
int pc; /* The program counter */
|
||||
int rc; /* Value to return */
|
||||
unsigned uniqueCnt; /* Used by OP_MakeRecord when P2!=0 */
|
||||
int errorAction; /* Recovery action to do in case of an error */
|
||||
int inTempTrans; /* True if temp database is transactioned */
|
||||
int returnStack[100]; /* Return address stack for OP_Gosub & OP_Return */
|
||||
int returnDepth; /* Next unused element in returnStack[] */
|
||||
int nResColumn; /* Number of columns in one row of the result set */
|
||||
char **azResColumn; /* Values for one row of result */
|
||||
int popStack; /* Pop the stack this much on entry to VdbeExec() */
|
||||
char *zErrMsg; /* Error message written here */
|
||||
u8 resOnStack; /* True if there are result values on the stack */
|
||||
u8 explain; /* True if EXPLAIN present on SQL command */
|
||||
u8 changeCntOn; /* True to update the change-counter */
|
||||
u8 aborted; /* True if ROLLBACK in another VM causes an abort */
|
||||
int nChange; /* Number of db changes made since last reset */
|
||||
};
|
||||
|
||||
/*
|
||||
** The following are allowed values for Vdbe.magic
|
||||
*/
|
||||
#define VDBE_MAGIC_INIT 0x26bceaa5 /* Building a VDBE program */
|
||||
#define VDBE_MAGIC_RUN 0xbdf20da3 /* VDBE is ready to execute */
|
||||
#define VDBE_MAGIC_HALT 0x519c2973 /* VDBE has completed execution */
|
||||
#define VDBE_MAGIC_DEAD 0xb606c3c8 /* The VDBE has been deallocated */
|
||||
|
||||
/*
|
||||
** Function prototypes
|
||||
*/
|
||||
void sqlite3VdbeFreeCursor(Cursor*);
|
||||
void sqlite3VdbeSorterReset(Vdbe*);
|
||||
int sqlite3VdbeAggReset(sqlite3*, Agg *, KeyInfo *);
|
||||
void sqlite3VdbeKeylistFree(Keylist*);
|
||||
void sqliteVdbePopStack(Vdbe*,int);
|
||||
int sqlite3VdbeCursorMoveto(Cursor*);
|
||||
#if !defined(NDEBUG) || defined(VDBE_PROFILE)
|
||||
void sqlite3VdbePrintOp(FILE*, int, Op*);
|
||||
#endif
|
||||
void sqlite3VdbePrintSql(Vdbe*);
|
||||
int sqlite3VdbeSerialTypeLen(u32);
|
||||
u32 sqlite3VdbeSerialType(Mem*);
|
||||
int sqlite3VdbeSerialPut(unsigned char*, Mem*);
|
||||
int sqlite3VdbeSerialGet(const unsigned char*, u32, Mem*);
|
||||
void sqlite3VdbeDeleteAuxData(VdbeFunc*, int);
|
||||
|
||||
int sqlite2BtreeKeyCompare(BtCursor *, const void *, int, int, int *);
|
||||
int sqlite3VdbeIdxKeyCompare(Cursor*, int , const unsigned char*, int*);
|
||||
int sqlite3VdbeIdxRowid(BtCursor *, i64 *);
|
||||
int sqlite3MemCompare(const Mem*, const Mem*, const CollSeq*);
|
||||
int sqlite3VdbeRecordCompare(void*,int,const void*,int, const void*);
|
||||
int sqlite3VdbeIdxRowidLen(int,const u8*);
|
||||
int sqlite3VdbeExec(Vdbe*);
|
||||
int sqlite3VdbeList(Vdbe*);
|
||||
int sqlite3VdbeHalt(Vdbe*);
|
||||
int sqlite3VdbeChangeEncoding(Mem *, int);
|
||||
int sqlite3VdbeMemCopy(Mem*, const Mem*);
|
||||
void sqlite3VdbeMemShallowCopy(Mem*, const Mem*, int);
|
||||
int sqlite3VdbeMemMove(Mem*, Mem*);
|
||||
int sqlite3VdbeMemNulTerminate(Mem*);
|
||||
int sqlite3VdbeMemSetStr(Mem*, const char*, int, u8, void(*)(void*));
|
||||
void sqlite3VdbeMemSetInt64(Mem*, i64);
|
||||
void sqlite3VdbeMemSetDouble(Mem*, double);
|
||||
void sqlite3VdbeMemSetNull(Mem*);
|
||||
int sqlite3VdbeMemMakeWriteable(Mem*);
|
||||
int sqlite3VdbeMemDynamicify(Mem*);
|
||||
int sqlite3VdbeMemStringify(Mem*, int);
|
||||
i64 sqlite3VdbeIntValue(Mem*);
|
||||
int sqlite3VdbeMemIntegerify(Mem*);
|
||||
double sqlite3VdbeRealValue(Mem*);
|
||||
int sqlite3VdbeMemRealify(Mem*);
|
||||
int sqlite3VdbeMemFromBtree(BtCursor*,int,int,int,Mem*);
|
||||
void sqlite3VdbeMemRelease(Mem *p);
|
||||
#ifndef NDEBUG
|
||||
void sqlite3VdbeMemSanity(Mem*, u8);
|
||||
#endif
|
||||
int sqlite3VdbeMemTranslate(Mem*, u8);
|
||||
void sqlite3VdbeMemPrettyPrint(Mem *pMem, char *zBuf, int nBuf);
|
||||
int sqlite3VdbeMemHandleBom(Mem *pMem);
|
|
@ -0,0 +1,588 @@
|
|||
/*
|
||||
** 2004 May 26
|
||||
**
|
||||
** The author disclaims copyright to this source code. In place of
|
||||
** a legal notice, here is a blessing:
|
||||
**
|
||||
** May you do good and not evil.
|
||||
** May you find forgiveness for yourself and forgive others.
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
*************************************************************************
|
||||
**
|
||||
** This file contains code use to implement APIs that are part of the
|
||||
** VDBE.
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include "vdbeInt.h"
|
||||
|
||||
/**************************** sqlite3_value_ *******************************
|
||||
** The following routines extract information from a Mem or sqlite3_value
|
||||
** structure.
|
||||
*/
|
||||
const void *sqlite3_value_blob(sqlite3_value *pVal){
|
||||
Mem *p = (Mem*)pVal;
|
||||
if( p->flags & (MEM_Blob|MEM_Str) ){
|
||||
return p->z;
|
||||
}else{
|
||||
return sqlite3_value_text(pVal);
|
||||
}
|
||||
}
|
||||
int sqlite3_value_bytes(sqlite3_value *pVal){
|
||||
return sqlite3ValueBytes(pVal, SQLITE_UTF8);
|
||||
}
|
||||
int sqlite3_value_bytes16(sqlite3_value *pVal){
|
||||
return sqlite3ValueBytes(pVal, SQLITE_UTF16NATIVE);
|
||||
}
|
||||
double sqlite3_value_double(sqlite3_value *pVal){
|
||||
return sqlite3VdbeRealValue((Mem*)pVal);
|
||||
}
|
||||
int sqlite3_value_int(sqlite3_value *pVal){
|
||||
return sqlite3VdbeIntValue((Mem*)pVal);
|
||||
}
|
||||
sqlite_int64 sqlite3_value_int64(sqlite3_value *pVal){
|
||||
return sqlite3VdbeIntValue((Mem*)pVal);
|
||||
}
|
||||
const unsigned char *sqlite3_value_text(sqlite3_value *pVal){
|
||||
return (const char *)sqlite3ValueText(pVal, SQLITE_UTF8);
|
||||
}
|
||||
const void *sqlite3_value_text16(sqlite3_value* pVal){
|
||||
return sqlite3ValueText(pVal, SQLITE_UTF16NATIVE);
|
||||
}
|
||||
const void *sqlite3_value_text16be(sqlite3_value *pVal){
|
||||
return sqlite3ValueText(pVal, SQLITE_UTF16BE);
|
||||
}
|
||||
const void *sqlite3_value_text16le(sqlite3_value *pVal){
|
||||
return sqlite3ValueText(pVal, SQLITE_UTF16LE);
|
||||
}
|
||||
int sqlite3_value_type(sqlite3_value* pVal){
|
||||
return pVal->type;
|
||||
}
|
||||
|
||||
/**************************** sqlite3_result_ *******************************
|
||||
** The following routines are used by user-defined functions to specify
|
||||
** the function result.
|
||||
*/
|
||||
void sqlite3_result_blob(
|
||||
sqlite3_context *pCtx,
|
||||
const void *z,
|
||||
int n,
|
||||
void (*xDel)(void *)
|
||||
){
|
||||
assert( n>0 );
|
||||
sqlite3VdbeMemSetStr(&pCtx->s, z, n, 0, xDel);
|
||||
}
|
||||
void sqlite3_result_double(sqlite3_context *pCtx, double rVal){
|
||||
sqlite3VdbeMemSetDouble(&pCtx->s, rVal);
|
||||
}
|
||||
void sqlite3_result_error(sqlite3_context *pCtx, const char *z, int n){
|
||||
pCtx->isError = 1;
|
||||
sqlite3VdbeMemSetStr(&pCtx->s, z, n, SQLITE_UTF8, SQLITE_TRANSIENT);
|
||||
}
|
||||
void sqlite3_result_error16(sqlite3_context *pCtx, const void *z, int n){
|
||||
pCtx->isError = 1;
|
||||
sqlite3VdbeMemSetStr(&pCtx->s, z, n, SQLITE_UTF16NATIVE, SQLITE_TRANSIENT);
|
||||
}
|
||||
void sqlite3_result_int(sqlite3_context *pCtx, int iVal){
|
||||
sqlite3VdbeMemSetInt64(&pCtx->s, (i64)iVal);
|
||||
}
|
||||
void sqlite3_result_int64(sqlite3_context *pCtx, i64 iVal){
|
||||
sqlite3VdbeMemSetInt64(&pCtx->s, iVal);
|
||||
}
|
||||
void sqlite3_result_null(sqlite3_context *pCtx){
|
||||
sqlite3VdbeMemSetNull(&pCtx->s);
|
||||
}
|
||||
void sqlite3_result_text(
|
||||
sqlite3_context *pCtx,
|
||||
const char *z,
|
||||
int n,
|
||||
void (*xDel)(void *)
|
||||
){
|
||||
sqlite3VdbeMemSetStr(&pCtx->s, z, n, SQLITE_UTF8, xDel);
|
||||
}
|
||||
void sqlite3_result_text16(
|
||||
sqlite3_context *pCtx,
|
||||
const void *z,
|
||||
int n,
|
||||
void (*xDel)(void *)
|
||||
){
|
||||
sqlite3VdbeMemSetStr(&pCtx->s, z, n, SQLITE_UTF16NATIVE, xDel);
|
||||
}
|
||||
void sqlite3_result_text16be(
|
||||
sqlite3_context *pCtx,
|
||||
const void *z,
|
||||
int n,
|
||||
void (*xDel)(void *)
|
||||
){
|
||||
sqlite3VdbeMemSetStr(&pCtx->s, z, n, SQLITE_UTF16BE, xDel);
|
||||
}
|
||||
void sqlite3_result_text16le(
|
||||
sqlite3_context *pCtx,
|
||||
const void *z,
|
||||
int n,
|
||||
void (*xDel)(void *)
|
||||
){
|
||||
sqlite3VdbeMemSetStr(&pCtx->s, z, n, SQLITE_UTF16LE, xDel);
|
||||
}
|
||||
void sqlite3_result_value(sqlite3_context *pCtx, sqlite3_value *pValue){
|
||||
sqlite3VdbeMemCopy(&pCtx->s, pValue);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Execute the statement pStmt, either until a row of data is ready, the
|
||||
** statement is completely executed or an error occurs.
|
||||
*/
|
||||
int sqlite3_step(sqlite3_stmt *pStmt){
|
||||
Vdbe *p = (Vdbe*)pStmt;
|
||||
sqlite3 *db;
|
||||
int rc;
|
||||
|
||||
if( p==0 || p->magic!=VDBE_MAGIC_RUN ){
|
||||
return SQLITE_MISUSE;
|
||||
}
|
||||
if( p->aborted ){
|
||||
return SQLITE_ABORT;
|
||||
}
|
||||
db = p->db;
|
||||
if( sqlite3SafetyOn(db) ){
|
||||
p->rc = SQLITE_MISUSE;
|
||||
return SQLITE_MISUSE;
|
||||
}
|
||||
if( p->pc<0 ){
|
||||
/* Invoke the trace callback if there is one
|
||||
*/
|
||||
if( (db = p->db)->xTrace && !db->init.busy ){
|
||||
assert( p->nOp>0 );
|
||||
assert( p->aOp[p->nOp-1].opcode==OP_Noop );
|
||||
assert( p->aOp[p->nOp-1].p3!=0 );
|
||||
assert( p->aOp[p->nOp-1].p3type==P3_DYNAMIC );
|
||||
sqlite3SafetyOff(db);
|
||||
db->xTrace(db->pTraceArg, p->aOp[p->nOp-1].p3);
|
||||
if( sqlite3SafetyOn(db) ){
|
||||
p->rc = SQLITE_MISUSE;
|
||||
return SQLITE_MISUSE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Print a copy of SQL as it is executed if the SQL_TRACE pragma is turned
|
||||
** on in debugging mode.
|
||||
*/
|
||||
#ifdef SQLITE_DEBUG
|
||||
if( (db->flags & SQLITE_SqlTrace)!=0 ){
|
||||
sqlite3DebugPrintf("SQL-trace: %s\n", p->aOp[p->nOp-1].p3);
|
||||
}
|
||||
#endif /* SQLITE_DEBUG */
|
||||
|
||||
db->activeVdbeCnt++;
|
||||
p->pc = 0;
|
||||
}
|
||||
if( p->explain ){
|
||||
rc = sqlite3VdbeList(p);
|
||||
}else{
|
||||
rc = sqlite3VdbeExec(p);
|
||||
}
|
||||
|
||||
if( sqlite3SafetyOff(db) ){
|
||||
rc = SQLITE_MISUSE;
|
||||
}
|
||||
|
||||
sqlite3Error(p->db, rc, p->zErrMsg);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Extract the user data from a sqlite3_context structure and return a
|
||||
** pointer to it.
|
||||
*/
|
||||
void *sqlite3_user_data(sqlite3_context *p){
|
||||
assert( p && p->pFunc );
|
||||
return p->pFunc->pUserData;
|
||||
}
|
||||
|
||||
/*
|
||||
** Allocate or return the aggregate context for a user function. A new
|
||||
** context is allocated on the first call. Subsequent calls return the
|
||||
** same context that was returned on prior calls.
|
||||
**
|
||||
** This routine is defined here in vdbe.c because it depends on knowing
|
||||
** the internals of the sqlite3_context structure which is only defined in
|
||||
** this source file.
|
||||
*/
|
||||
void *sqlite3_aggregate_context(sqlite3_context *p, int nByte){
|
||||
assert( p && p->pFunc && p->pFunc->xStep );
|
||||
if( p->pAgg==0 ){
|
||||
if( nByte<=NBFS ){
|
||||
p->pAgg = (void*)p->s.z;
|
||||
memset(p->pAgg, 0, nByte);
|
||||
}else{
|
||||
p->pAgg = sqliteMalloc( nByte );
|
||||
}
|
||||
}
|
||||
return p->pAgg;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the auxilary data pointer, if any, for the iArg'th argument to
|
||||
** the user-function defined by pCtx.
|
||||
*/
|
||||
void *sqlite3_get_auxdata(sqlite3_context *pCtx, int iArg){
|
||||
VdbeFunc *pVdbeFunc = pCtx->pVdbeFunc;
|
||||
if( !pVdbeFunc || iArg>=pVdbeFunc->nAux || iArg<0 ){
|
||||
return 0;
|
||||
}
|
||||
return pVdbeFunc->apAux[iArg].pAux;
|
||||
}
|
||||
|
||||
/*
|
||||
** Set the auxilary data pointer and delete function, for the iArg'th
|
||||
** argument to the user-function defined by pCtx. Any previous value is
|
||||
** deleted by calling the delete function specified when it was set.
|
||||
*/
|
||||
void sqlite3_set_auxdata(
|
||||
sqlite3_context *pCtx,
|
||||
int iArg,
|
||||
void *pAux,
|
||||
void (*xDelete)(void*)
|
||||
){
|
||||
struct AuxData *pAuxData;
|
||||
VdbeFunc *pVdbeFunc;
|
||||
if( iArg<0 ) return;
|
||||
|
||||
pVdbeFunc = pCtx->pVdbeFunc;
|
||||
if( !pVdbeFunc || pVdbeFunc->nAux<=iArg ){
|
||||
int nMalloc = sizeof(VdbeFunc) + sizeof(struct AuxData)*iArg;
|
||||
pCtx->pVdbeFunc = pVdbeFunc = sqliteRealloc(pVdbeFunc, nMalloc);
|
||||
if( !pVdbeFunc ) return;
|
||||
memset(&pVdbeFunc->apAux[pVdbeFunc->nAux], 0,
|
||||
sizeof(struct AuxData)*(iArg+1-pVdbeFunc->nAux));
|
||||
pVdbeFunc->nAux = iArg+1;
|
||||
pVdbeFunc->pFunc = pCtx->pFunc;
|
||||
}
|
||||
|
||||
pAuxData = &pVdbeFunc->apAux[iArg];
|
||||
if( pAuxData->pAux && pAuxData->xDelete ){
|
||||
pAuxData->xDelete(pAuxData->pAux);
|
||||
}
|
||||
pAuxData->pAux = pAux;
|
||||
pAuxData->xDelete = xDelete;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the number of times the Step function of a aggregate has been
|
||||
** called.
|
||||
**
|
||||
** This routine is defined here in vdbe.c because it depends on knowing
|
||||
** the internals of the sqlite3_context structure which is only defined in
|
||||
** this source file.
|
||||
*/
|
||||
int sqlite3_aggregate_count(sqlite3_context *p){
|
||||
assert( p && p->pFunc && p->pFunc->xStep );
|
||||
return p->cnt;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the number of columns in the result set for the statement pStmt.
|
||||
*/
|
||||
int sqlite3_column_count(sqlite3_stmt *pStmt){
|
||||
Vdbe *pVm = (Vdbe *)pStmt;
|
||||
return pVm ? pVm->nResColumn : 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the number of values available from the current row of the
|
||||
** currently executing statement pStmt.
|
||||
*/
|
||||
int sqlite3_data_count(sqlite3_stmt *pStmt){
|
||||
Vdbe *pVm = (Vdbe *)pStmt;
|
||||
if( pVm==0 || !pVm->resOnStack ) return 0;
|
||||
return pVm->nResColumn;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Check to see if column iCol of the given statement is valid. If
|
||||
** it is, return a pointer to the Mem for the value of that column.
|
||||
** If iCol is not valid, return a pointer to a Mem which has a value
|
||||
** of NULL.
|
||||
*/
|
||||
static Mem *columnMem(sqlite3_stmt *pStmt, int i){
|
||||
Vdbe *pVm = (Vdbe *)pStmt;
|
||||
int vals = sqlite3_data_count(pStmt);
|
||||
if( i>=vals || i<0 ){
|
||||
static Mem nullMem;
|
||||
if( nullMem.flags==0 ){ nullMem.flags = MEM_Null; }
|
||||
sqlite3Error(pVm->db, SQLITE_RANGE, 0);
|
||||
return &nullMem;
|
||||
}
|
||||
return &pVm->pTos[(1-vals)+i];
|
||||
}
|
||||
|
||||
/**************************** sqlite3_column_ *******************************
|
||||
** The following routines are used to access elements of the current row
|
||||
** in the result set.
|
||||
*/
|
||||
const void *sqlite3_column_blob(sqlite3_stmt *pStmt, int i){
|
||||
return sqlite3_value_blob( columnMem(pStmt,i) );
|
||||
}
|
||||
int sqlite3_column_bytes(sqlite3_stmt *pStmt, int i){
|
||||
return sqlite3_value_bytes( columnMem(pStmt,i) );
|
||||
}
|
||||
int sqlite3_column_bytes16(sqlite3_stmt *pStmt, int i){
|
||||
return sqlite3_value_bytes16( columnMem(pStmt,i) );
|
||||
}
|
||||
double sqlite3_column_double(sqlite3_stmt *pStmt, int i){
|
||||
return sqlite3_value_double( columnMem(pStmt,i) );
|
||||
}
|
||||
int sqlite3_column_int(sqlite3_stmt *pStmt, int i){
|
||||
return sqlite3_value_int( columnMem(pStmt,i) );
|
||||
}
|
||||
sqlite_int64 sqlite3_column_int64(sqlite3_stmt *pStmt, int i){
|
||||
return sqlite3_value_int64( columnMem(pStmt,i) );
|
||||
}
|
||||
const unsigned char *sqlite3_column_text(sqlite3_stmt *pStmt, int i){
|
||||
return sqlite3_value_text( columnMem(pStmt,i) );
|
||||
}
|
||||
const void *sqlite3_column_text16(sqlite3_stmt *pStmt, int i){
|
||||
return sqlite3_value_text16( columnMem(pStmt,i) );
|
||||
}
|
||||
int sqlite3_column_type(sqlite3_stmt *pStmt, int i){
|
||||
return sqlite3_value_type( columnMem(pStmt,i) );
|
||||
}
|
||||
|
||||
/*
|
||||
** Convert the N-th element of pStmt->pColName[] into a string using
|
||||
** xFunc() then return that string. If N is out of range, return 0.
|
||||
** If useType is 1, then use the second set of N elements (the datatype
|
||||
** names) instead of the first set.
|
||||
*/
|
||||
static const void *columnName(
|
||||
sqlite3_stmt *pStmt,
|
||||
int N,
|
||||
const void *(*xFunc)(Mem*),
|
||||
int useType
|
||||
){
|
||||
Vdbe *p = (Vdbe *)pStmt;
|
||||
int n = sqlite3_column_count(pStmt);
|
||||
|
||||
if( p==0 || N>=n || N<0 ){
|
||||
return 0;
|
||||
}
|
||||
if( useType ){
|
||||
N += n;
|
||||
}
|
||||
return xFunc(&p->aColName[N]);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Return the name of the Nth column of the result set returned by SQL
|
||||
** statement pStmt.
|
||||
*/
|
||||
const char *sqlite3_column_name(sqlite3_stmt *pStmt, int N){
|
||||
return columnName(pStmt, N, (const void*(*)(Mem*))sqlite3_value_text, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the name of the 'i'th column of the result set of SQL statement
|
||||
** pStmt, encoded as UTF-16.
|
||||
*/
|
||||
const void *sqlite3_column_name16(sqlite3_stmt *pStmt, int N){
|
||||
return columnName(pStmt, N, (const void*(*)(Mem*))sqlite3_value_text16, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the column declaration type (if applicable) of the 'i'th column
|
||||
** of the result set of SQL statement pStmt, encoded as UTF-8.
|
||||
*/
|
||||
const char *sqlite3_column_decltype(sqlite3_stmt *pStmt, int N){
|
||||
return columnName(pStmt, N, (const void*(*)(Mem*))sqlite3_value_text, 1);
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the column declaration type (if applicable) of the 'i'th column
|
||||
** of the result set of SQL statement pStmt, encoded as UTF-16.
|
||||
*/
|
||||
const void *sqlite3_column_decltype16(sqlite3_stmt *pStmt, int N){
|
||||
return columnName(pStmt, N, (const void*(*)(Mem*))sqlite3_value_text16, 1);
|
||||
}
|
||||
|
||||
/******************************* sqlite3_bind_ ***************************
|
||||
**
|
||||
** Routines used to attach values to wildcards in a compiled SQL statement.
|
||||
*/
|
||||
/*
|
||||
** Unbind the value bound to variable i in virtual machine p. This is the
|
||||
** the same as binding a NULL value to the column. If the "i" parameter is
|
||||
** out of range, then SQLITE_RANGE is returned. Othewise SQLITE_OK.
|
||||
**
|
||||
** The error code stored in database p->db is overwritten with the return
|
||||
** value in any case.
|
||||
*/
|
||||
static int vdbeUnbind(Vdbe *p, int i){
|
||||
Mem *pVar;
|
||||
if( p==0 || p->magic!=VDBE_MAGIC_RUN || p->pc>=0 ){
|
||||
sqlite3Error(p->db, SQLITE_MISUSE, 0);
|
||||
return SQLITE_MISUSE;
|
||||
}
|
||||
if( i<1 || i>p->nVar ){
|
||||
sqlite3Error(p->db, SQLITE_RANGE, 0);
|
||||
return SQLITE_RANGE;
|
||||
}
|
||||
i--;
|
||||
pVar = &p->aVar[i];
|
||||
sqlite3VdbeMemRelease(pVar);
|
||||
pVar->flags = MEM_Null;
|
||||
sqlite3Error(p->db, SQLITE_OK, 0);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Bind a text or BLOB value.
|
||||
*/
|
||||
static int bindText(
|
||||
sqlite3_stmt *pStmt,
|
||||
int i,
|
||||
const void *zData,
|
||||
int nData,
|
||||
void (*xDel)(void*),
|
||||
int encoding
|
||||
){
|
||||
Vdbe *p = (Vdbe *)pStmt;
|
||||
Mem *pVar;
|
||||
int rc;
|
||||
|
||||
rc = vdbeUnbind(p, i);
|
||||
if( rc || zData==0 ){
|
||||
return rc;
|
||||
}
|
||||
pVar = &p->aVar[i-1];
|
||||
rc = sqlite3VdbeMemSetStr(pVar, zData, nData, encoding, xDel);
|
||||
if( rc ){
|
||||
return rc;
|
||||
}
|
||||
if( rc==SQLITE_OK && encoding!=0 ){
|
||||
rc = sqlite3VdbeChangeEncoding(pVar, p->db->enc);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Bind a blob value to an SQL statement variable.
|
||||
*/
|
||||
int sqlite3_bind_blob(
|
||||
sqlite3_stmt *pStmt,
|
||||
int i,
|
||||
const void *zData,
|
||||
int nData,
|
||||
void (*xDel)(void*)
|
||||
){
|
||||
return bindText(pStmt, i, zData, nData, xDel, 0);
|
||||
}
|
||||
int sqlite3_bind_double(sqlite3_stmt *pStmt, int i, double rValue){
|
||||
int rc;
|
||||
Vdbe *p = (Vdbe *)pStmt;
|
||||
rc = vdbeUnbind(p, i);
|
||||
if( rc==SQLITE_OK ){
|
||||
sqlite3VdbeMemSetDouble(&p->aVar[i-1], rValue);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
int sqlite3_bind_int(sqlite3_stmt *p, int i, int iValue){
|
||||
return sqlite3_bind_int64(p, i, (i64)iValue);
|
||||
}
|
||||
int sqlite3_bind_int64(sqlite3_stmt *pStmt, int i, sqlite_int64 iValue){
|
||||
int rc;
|
||||
Vdbe *p = (Vdbe *)pStmt;
|
||||
rc = vdbeUnbind(p, i);
|
||||
if( rc==SQLITE_OK ){
|
||||
sqlite3VdbeMemSetInt64(&p->aVar[i-1], iValue);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
int sqlite3_bind_null(sqlite3_stmt* p, int i){
|
||||
return vdbeUnbind((Vdbe *)p, i);
|
||||
}
|
||||
int sqlite3_bind_text(
|
||||
sqlite3_stmt *pStmt,
|
||||
int i,
|
||||
const char *zData,
|
||||
int nData,
|
||||
void (*xDel)(void*)
|
||||
){
|
||||
return bindText(pStmt, i, zData, nData, xDel, SQLITE_UTF8);
|
||||
}
|
||||
int sqlite3_bind_text16(
|
||||
sqlite3_stmt *pStmt,
|
||||
int i,
|
||||
const void *zData,
|
||||
int nData,
|
||||
void (*xDel)(void*)
|
||||
){
|
||||
return bindText(pStmt, i, zData, nData, xDel, SQLITE_UTF16NATIVE);
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the number of wildcards that can be potentially bound to.
|
||||
** This routine is added to support DBD::SQLite.
|
||||
*/
|
||||
int sqlite3_bind_parameter_count(sqlite3_stmt *pStmt){
|
||||
Vdbe *p = (Vdbe*)pStmt;
|
||||
return p ? p->nVar : 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Create a mapping from variable numbers to variable names
|
||||
** in the Vdbe.azVar[] array, if such a mapping does not already
|
||||
** exist.
|
||||
*/
|
||||
static void createVarMap(Vdbe *p){
|
||||
if( !p->okVar ){
|
||||
int j;
|
||||
Op *pOp;
|
||||
for(j=0, pOp=p->aOp; j<p->nOp; j++, pOp++){
|
||||
if( pOp->opcode==OP_Variable ){
|
||||
assert( pOp->p1>0 && pOp->p1<=p->nVar );
|
||||
p->azVar[pOp->p1-1] = pOp->p3;
|
||||
}
|
||||
}
|
||||
p->okVar = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the name of a wildcard parameter. Return NULL if the index
|
||||
** is out of range or if the wildcard is unnamed.
|
||||
**
|
||||
** The result is always UTF-8.
|
||||
*/
|
||||
const char *sqlite3_bind_parameter_name(sqlite3_stmt *pStmt, int i){
|
||||
Vdbe *p = (Vdbe*)pStmt;
|
||||
if( p==0 || i<1 || i>p->nVar ){
|
||||
return 0;
|
||||
}
|
||||
createVarMap(p);
|
||||
return p->azVar[i-1];
|
||||
}
|
||||
|
||||
/*
|
||||
** Given a wildcard parameter name, return the index of the variable
|
||||
** with that name. If there is no variable with the given name,
|
||||
** return 0.
|
||||
*/
|
||||
int sqlite3_bind_parameter_index(sqlite3_stmt *pStmt, const char *zName){
|
||||
Vdbe *p = (Vdbe*)pStmt;
|
||||
int i;
|
||||
if( p==0 ){
|
||||
return 0;
|
||||
}
|
||||
createVarMap(p);
|
||||
for(i=0; i<p->nVar; i++){
|
||||
const char *z = p->azVar[i];
|
||||
if( z && strcmp(z,zName)==0 ){
|
||||
return i+1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,724 @@
|
|||
/*
|
||||
** 2004 May 26
|
||||
**
|
||||
** The author disclaims copyright to this source code. In place of
|
||||
** a legal notice, here is a blessing:
|
||||
**
|
||||
** May you do good and not evil.
|
||||
** May you find forgiveness for yourself and forgive others.
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
*************************************************************************
|
||||
**
|
||||
** This file contains code use to manipulate "Mem" structure. A "Mem"
|
||||
** stores a single value in the VDBE. Mem is an opaque structure visible
|
||||
** only within the VDBE. Interface routines refer to a Mem using the
|
||||
** name sqlite_value
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include "os.h"
|
||||
#include <ctype.h>
|
||||
#include "vdbeInt.h"
|
||||
|
||||
/*
|
||||
** If pMem is an object with a valid string representation, this routine
|
||||
** ensures the internal encoding for the string representation is
|
||||
** 'desiredEnc', one of SQLITE_UTF8, SQLITE_UTF16LE or SQLITE_UTF16BE.
|
||||
**
|
||||
** If pMem is not a string object, or the encoding of the string
|
||||
** representation is already stored using the requested encoding, then this
|
||||
** routine is a no-op.
|
||||
**
|
||||
** SQLITE_OK is returned if the conversion is successful (or not required).
|
||||
** SQLITE_NOMEM may be returned if a malloc() fails during conversion
|
||||
** between formats.
|
||||
*/
|
||||
int sqlite3VdbeChangeEncoding(Mem *pMem, int desiredEnc){
|
||||
if( !(pMem->flags&MEM_Str) || pMem->enc==desiredEnc ){
|
||||
return SQLITE_OK;
|
||||
}
|
||||
return sqlite3VdbeMemTranslate(pMem, desiredEnc);
|
||||
}
|
||||
|
||||
/*
|
||||
** Make the given Mem object MEM_Dyn.
|
||||
**
|
||||
** Return SQLITE_OK on success or SQLITE_NOMEM if malloc fails.
|
||||
*/
|
||||
int sqlite3VdbeMemDynamicify(Mem *pMem){
|
||||
int n = pMem->n;
|
||||
u8 *z;
|
||||
if( (pMem->flags & (MEM_Ephem|MEM_Static|MEM_Short))==0 ){
|
||||
return SQLITE_OK;
|
||||
}
|
||||
assert( (pMem->flags & MEM_Dyn)==0 );
|
||||
assert( pMem->flags & (MEM_Str|MEM_Blob) );
|
||||
z = sqliteMallocRaw( n+2 );
|
||||
if( z==0 ){
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
pMem->flags |= MEM_Dyn|MEM_Term;
|
||||
pMem->xDel = 0;
|
||||
memcpy(z, pMem->z, n );
|
||||
z[n] = 0;
|
||||
z[n+1] = 0;
|
||||
pMem->z = z;
|
||||
pMem->flags &= ~(MEM_Ephem|MEM_Static|MEM_Short);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Make the given Mem object either MEM_Short or MEM_Dyn so that bytes
|
||||
** of the Mem.z[] array can be modified.
|
||||
**
|
||||
** Return SQLITE_OK on success or SQLITE_NOMEM if malloc fails.
|
||||
*/
|
||||
int sqlite3VdbeMemMakeWriteable(Mem *pMem){
|
||||
int n;
|
||||
u8 *z;
|
||||
if( (pMem->flags & (MEM_Ephem|MEM_Static))==0 ){
|
||||
return SQLITE_OK;
|
||||
}
|
||||
assert( (pMem->flags & MEM_Dyn)==0 );
|
||||
assert( pMem->flags & (MEM_Str|MEM_Blob) );
|
||||
if( (n = pMem->n)+2<sizeof(pMem->zShort) ){
|
||||
z = pMem->zShort;
|
||||
pMem->flags |= MEM_Short|MEM_Term;
|
||||
}else{
|
||||
z = sqliteMallocRaw( n+2 );
|
||||
if( z==0 ){
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
pMem->flags |= MEM_Dyn|MEM_Term;
|
||||
pMem->xDel = 0;
|
||||
}
|
||||
memcpy(z, pMem->z, n );
|
||||
z[n] = 0;
|
||||
z[n+1] = 0;
|
||||
pMem->z = z;
|
||||
pMem->flags &= ~(MEM_Ephem|MEM_Static);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Make sure the given Mem is \u0000 terminated.
|
||||
*/
|
||||
int sqlite3VdbeMemNulTerminate(Mem *pMem){
|
||||
/* In SQLite, a string without a nul terminator occurs when a string
|
||||
** is loaded from disk (in this case the memory management is ephemeral),
|
||||
** or when it is supplied by the user as a bound variable or function
|
||||
** return value. Therefore, the memory management of the string must be
|
||||
** either ephemeral, static or controlled by a user-supplied destructor.
|
||||
*/
|
||||
assert(
|
||||
!(pMem->flags&MEM_Str) || /* it's not a string, or */
|
||||
(pMem->flags&MEM_Term) || /* it's nul term. already, or */
|
||||
(pMem->flags&(MEM_Ephem|MEM_Static)) || /* it's static or ephem, or */
|
||||
(pMem->flags&MEM_Dyn && pMem->xDel) /* external management */
|
||||
);
|
||||
if( (pMem->flags & MEM_Term)!=0 || (pMem->flags & MEM_Str)==0 ){
|
||||
return SQLITE_OK; /* Nothing to do */
|
||||
}
|
||||
|
||||
if( pMem->flags & (MEM_Static|MEM_Ephem) ){
|
||||
return sqlite3VdbeMemMakeWriteable(pMem);
|
||||
}else{
|
||||
char *z = sqliteMalloc(pMem->n+2);
|
||||
if( !z ) return SQLITE_NOMEM;
|
||||
memcpy(z, pMem->z, pMem->n);
|
||||
z[pMem->n] = 0;
|
||||
z[pMem->n+1] = 0;
|
||||
pMem->xDel(pMem->z);
|
||||
pMem->xDel = 0;
|
||||
pMem->z = z;
|
||||
}
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Add MEM_Str to the set of representations for the given Mem. Numbers
|
||||
** are converted using sqlite3_snprintf(). Converting a BLOB to a string
|
||||
** is a no-op.
|
||||
**
|
||||
** Existing representations MEM_Int and MEM_Real are *not* invalidated.
|
||||
**
|
||||
** A MEM_Null value will never be passed to this function. This function is
|
||||
** used for converting values to text for returning to the user (i.e. via
|
||||
** sqlite3_value_text()), or for ensuring that values to be used as btree
|
||||
** keys are strings. In the former case a NULL pointer is returned the
|
||||
** user and the later is an internal programming error.
|
||||
*/
|
||||
int sqlite3VdbeMemStringify(Mem *pMem, int enc){
|
||||
int rc = SQLITE_OK;
|
||||
int fg = pMem->flags;
|
||||
u8 *z = pMem->zShort;
|
||||
|
||||
assert( !(fg&(MEM_Str|MEM_Blob)) );
|
||||
assert( fg&(MEM_Int|MEM_Real) );
|
||||
|
||||
/* For a Real or Integer, use sqlite3_snprintf() to produce the UTF-8
|
||||
** string representation of the value. Then, if the required encoding
|
||||
** is UTF-16le or UTF-16be do a translation.
|
||||
**
|
||||
** FIX ME: It would be better if sqlite3_snprintf() could do UTF-16.
|
||||
*/
|
||||
if( fg & MEM_Real ){
|
||||
sqlite3_snprintf(NBFS, z, "%.15g", pMem->r);
|
||||
}else{
|
||||
assert( fg & MEM_Int );
|
||||
sqlite3_snprintf(NBFS, z, "%lld", pMem->i);
|
||||
}
|
||||
pMem->n = strlen(z);
|
||||
pMem->z = z;
|
||||
pMem->enc = SQLITE_UTF8;
|
||||
pMem->flags |= MEM_Str | MEM_Short | MEM_Term;
|
||||
sqlite3VdbeChangeEncoding(pMem, enc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Release any memory held by the Mem. This may leave the Mem in an
|
||||
** inconsistent state, for example with (Mem.z==0) and
|
||||
** (Mem.type==SQLITE_TEXT).
|
||||
*/
|
||||
void sqlite3VdbeMemRelease(Mem *p){
|
||||
if( p->flags & MEM_Dyn ){
|
||||
if( p->xDel ){
|
||||
p->xDel((void *)p->z);
|
||||
}else{
|
||||
sqliteFree(p->z);
|
||||
}
|
||||
p->z = 0;
|
||||
p->xDel = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Return some kind of integer value which is the best we can do
|
||||
** at representing the value that *pMem describes as an integer.
|
||||
** If pMem is an integer, then the value is exact. If pMem is
|
||||
** a floating-point then the value returned is the integer part.
|
||||
** If pMem is a string or blob, then we make an attempt to convert
|
||||
** it into a integer and return that. If pMem is NULL, return 0.
|
||||
**
|
||||
** If pMem is a string, its encoding might be changed.
|
||||
*/
|
||||
i64 sqlite3VdbeIntValue(Mem *pMem){
|
||||
int flags = pMem->flags;
|
||||
if( flags & MEM_Int ){
|
||||
return pMem->i;
|
||||
}else if( flags & MEM_Real ){
|
||||
return (i64)pMem->r;
|
||||
}else if( flags & (MEM_Str|MEM_Blob) ){
|
||||
i64 value;
|
||||
if( sqlite3VdbeChangeEncoding(pMem, SQLITE_UTF8)
|
||||
|| sqlite3VdbeMemNulTerminate(pMem) ){
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
assert( pMem->z );
|
||||
sqlite3atoi64(pMem->z, &value);
|
||||
return value;
|
||||
}else{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Convert pMem to type integer. Invalidate any prior representations.
|
||||
*/
|
||||
int sqlite3VdbeMemIntegerify(Mem *pMem){
|
||||
pMem->i = sqlite3VdbeIntValue(pMem);
|
||||
sqlite3VdbeMemRelease(pMem);
|
||||
pMem->flags = MEM_Int;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the best representation of pMem that we can get into a
|
||||
** double. If pMem is already a double or an integer, return its
|
||||
** value. If it is a string or blob, try to convert it to a double.
|
||||
** If it is a NULL, return 0.0.
|
||||
*/
|
||||
double sqlite3VdbeRealValue(Mem *pMem){
|
||||
if( pMem->flags & MEM_Real ){
|
||||
return pMem->r;
|
||||
}else if( pMem->flags & MEM_Int ){
|
||||
return (double)pMem->i;
|
||||
}else if( pMem->flags & (MEM_Str|MEM_Blob) ){
|
||||
if( sqlite3VdbeChangeEncoding(pMem, SQLITE_UTF8)
|
||||
|| sqlite3VdbeMemNulTerminate(pMem) ){
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
assert( pMem->z );
|
||||
return sqlite3AtoF(pMem->z, 0);
|
||||
}else{
|
||||
return 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Convert pMem so that it is of type MEM_Real. Invalidate any
|
||||
** prior representations.
|
||||
*/
|
||||
int sqlite3VdbeMemRealify(Mem *pMem){
|
||||
pMem->r = sqlite3VdbeRealValue(pMem);
|
||||
sqlite3VdbeMemRelease(pMem);
|
||||
pMem->flags = MEM_Real;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Delete any previous value and set the value stored in *pMem to NULL.
|
||||
*/
|
||||
void sqlite3VdbeMemSetNull(Mem *pMem){
|
||||
sqlite3VdbeMemRelease(pMem);
|
||||
pMem->flags = MEM_Null;
|
||||
pMem->type = SQLITE_NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
** Delete any previous value and set the value stored in *pMem to val,
|
||||
** manifest type INTEGER.
|
||||
*/
|
||||
void sqlite3VdbeMemSetInt64(Mem *pMem, i64 val){
|
||||
sqlite3VdbeMemRelease(pMem);
|
||||
pMem->i = val;
|
||||
pMem->flags = MEM_Int;
|
||||
pMem->type = SQLITE_INTEGER;
|
||||
}
|
||||
|
||||
/*
|
||||
** Delete any previous value and set the value stored in *pMem to val,
|
||||
** manifest type REAL.
|
||||
*/
|
||||
void sqlite3VdbeMemSetDouble(Mem *pMem, double val){
|
||||
sqlite3VdbeMemRelease(pMem);
|
||||
pMem->r = val;
|
||||
pMem->flags = MEM_Real;
|
||||
pMem->type = SQLITE_FLOAT;
|
||||
}
|
||||
|
||||
/*
|
||||
** Make an shallow copy of pFrom into pTo. Prior contents of
|
||||
** pTo are overwritten. The pFrom->z field is not duplicated. If
|
||||
** pFrom->z is used, then pTo->z points to the same thing as pFrom->z
|
||||
** and flags gets srcType (either MEM_Ephem or MEM_Static).
|
||||
*/
|
||||
void sqlite3VdbeMemShallowCopy(Mem *pTo, const Mem *pFrom, int srcType){
|
||||
memcpy(pTo, pFrom, sizeof(*pFrom)-sizeof(pFrom->zShort));
|
||||
pTo->xDel = 0;
|
||||
if( pTo->flags & (MEM_Str|MEM_Blob) ){
|
||||
pTo->flags &= ~(MEM_Dyn|MEM_Static|MEM_Short|MEM_Ephem);
|
||||
assert( srcType==MEM_Ephem || srcType==MEM_Static );
|
||||
pTo->flags |= srcType;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Make a full copy of pFrom into pTo. Prior contents of pTo are
|
||||
** freed before the copy is made.
|
||||
*/
|
||||
int sqlite3VdbeMemCopy(Mem *pTo, const Mem *pFrom){
|
||||
int rc;
|
||||
if( pTo->flags & MEM_Dyn ){
|
||||
sqlite3VdbeMemRelease(pTo);
|
||||
}
|
||||
sqlite3VdbeMemShallowCopy(pTo, pFrom, MEM_Ephem);
|
||||
if( pTo->flags & MEM_Ephem ){
|
||||
rc = sqlite3VdbeMemMakeWriteable(pTo);
|
||||
}else{
|
||||
rc = SQLITE_OK;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Transfer the contents of pFrom to pTo. Any existing value in pTo is
|
||||
** freed. If pFrom contains ephemeral data, a copy is made.
|
||||
**
|
||||
** pFrom contains an SQL NULL when this routine returns. SQLITE_NOMEM
|
||||
** might be returned if pFrom held ephemeral data and we were unable
|
||||
** to allocate enough space to make a copy.
|
||||
*/
|
||||
int sqlite3VdbeMemMove(Mem *pTo, Mem *pFrom){
|
||||
int rc;
|
||||
if( pTo->flags & MEM_Dyn ){
|
||||
sqlite3VdbeMemRelease(pTo);
|
||||
}
|
||||
memcpy(pTo, pFrom, sizeof(Mem));
|
||||
if( pFrom->flags & MEM_Short ){
|
||||
pTo->z = pTo->zShort;
|
||||
}
|
||||
pFrom->flags = MEM_Null;
|
||||
pFrom->xDel = 0;
|
||||
if( pTo->flags & MEM_Ephem ){
|
||||
rc = sqlite3VdbeMemMakeWriteable(pTo);
|
||||
}else{
|
||||
rc = SQLITE_OK;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Change the value of a Mem to be a string or a BLOB.
|
||||
*/
|
||||
int sqlite3VdbeMemSetStr(
|
||||
Mem *pMem, /* Memory cell to set to string value */
|
||||
const char *z, /* String pointer */
|
||||
int n, /* Bytes in string, or negative */
|
||||
u8 enc, /* Encoding of z. 0 for BLOBs */
|
||||
void (*xDel)(void*) /* Destructor function */
|
||||
){
|
||||
sqlite3VdbeMemRelease(pMem);
|
||||
if( !z ){
|
||||
pMem->flags = MEM_Null;
|
||||
pMem->type = SQLITE_NULL;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
pMem->z = (char *)z;
|
||||
if( xDel==SQLITE_STATIC ){
|
||||
pMem->flags = MEM_Static;
|
||||
}else if( xDel==SQLITE_TRANSIENT ){
|
||||
pMem->flags = MEM_Ephem;
|
||||
}else{
|
||||
pMem->flags = MEM_Dyn;
|
||||
pMem->xDel = xDel;
|
||||
}
|
||||
|
||||
pMem->enc = enc;
|
||||
pMem->type = enc==0 ? SQLITE_BLOB : SQLITE_TEXT;
|
||||
pMem->n = n;
|
||||
|
||||
switch( enc ){
|
||||
case 0:
|
||||
pMem->flags |= MEM_Blob;
|
||||
break;
|
||||
|
||||
case SQLITE_UTF8:
|
||||
pMem->flags |= MEM_Str;
|
||||
if( n<0 ){
|
||||
pMem->n = strlen(z);
|
||||
pMem->flags |= MEM_Term;
|
||||
}
|
||||
break;
|
||||
|
||||
case SQLITE_UTF16LE:
|
||||
case SQLITE_UTF16BE:
|
||||
pMem->flags |= MEM_Str;
|
||||
if( pMem->n<0 ){
|
||||
pMem->n = sqlite3utf16ByteLen(pMem->z,-1);
|
||||
pMem->flags |= MEM_Term;
|
||||
}
|
||||
if( sqlite3VdbeMemHandleBom(pMem) ){
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
if( pMem->flags&MEM_Ephem ){
|
||||
return sqlite3VdbeMemMakeWriteable(pMem);
|
||||
}
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Compare the values contained by the two memory cells, returning
|
||||
** negative, zero or positive if pMem1 is less than, equal to, or greater
|
||||
** than pMem2. Sorting order is NULL's first, followed by numbers (integers
|
||||
** and reals) sorted numerically, followed by text ordered by the collating
|
||||
** sequence pColl and finally blob's ordered by memcmp().
|
||||
**
|
||||
** Two NULL values are considered equal by this function.
|
||||
*/
|
||||
int sqlite3MemCompare(const Mem *pMem1, const Mem *pMem2, const CollSeq *pColl){
|
||||
int rc;
|
||||
int f1, f2;
|
||||
int combined_flags;
|
||||
|
||||
/* Interchange pMem1 and pMem2 if the collating sequence specifies
|
||||
** DESC order.
|
||||
*/
|
||||
f1 = pMem1->flags;
|
||||
f2 = pMem2->flags;
|
||||
combined_flags = f1|f2;
|
||||
|
||||
/* If one value is NULL, it is less than the other. If both values
|
||||
** are NULL, return 0.
|
||||
*/
|
||||
if( combined_flags&MEM_Null ){
|
||||
return (f2&MEM_Null) - (f1&MEM_Null);
|
||||
}
|
||||
|
||||
/* If one value is a number and the other is not, the number is less.
|
||||
** If both are numbers, compare as reals if one is a real, or as integers
|
||||
** if both values are integers.
|
||||
*/
|
||||
if( combined_flags&(MEM_Int|MEM_Real) ){
|
||||
if( !(f1&(MEM_Int|MEM_Real)) ){
|
||||
return 1;
|
||||
}
|
||||
if( !(f2&(MEM_Int|MEM_Real)) ){
|
||||
return -1;
|
||||
}
|
||||
if( (f1 & f2 & MEM_Int)==0 ){
|
||||
double r1, r2;
|
||||
if( (f1&MEM_Real)==0 ){
|
||||
r1 = pMem1->i;
|
||||
}else{
|
||||
r1 = pMem1->r;
|
||||
}
|
||||
if( (f2&MEM_Real)==0 ){
|
||||
r2 = pMem2->i;
|
||||
}else{
|
||||
r2 = pMem2->r;
|
||||
}
|
||||
if( r1<r2 ) return -1;
|
||||
if( r1>r2 ) return 1;
|
||||
return 0;
|
||||
}else{
|
||||
assert( f1&MEM_Int );
|
||||
assert( f2&MEM_Int );
|
||||
if( pMem1->i < pMem2->i ) return -1;
|
||||
if( pMem1->i > pMem2->i ) return 1;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* If one value is a string and the other is a blob, the string is less.
|
||||
** If both are strings, compare using the collating functions.
|
||||
*/
|
||||
if( combined_flags&MEM_Str ){
|
||||
if( (f1 & MEM_Str)==0 ){
|
||||
return 1;
|
||||
}
|
||||
if( (f2 & MEM_Str)==0 ){
|
||||
return -1;
|
||||
}
|
||||
|
||||
assert( pMem1->enc==pMem2->enc );
|
||||
assert( pMem1->enc==SQLITE_UTF8 ||
|
||||
pMem1->enc==SQLITE_UTF16LE || pMem1->enc==SQLITE_UTF16BE );
|
||||
|
||||
/* This assert may fail if the collation sequence is deleted after this
|
||||
** vdbe program is compiled. The documentation defines this as an
|
||||
** undefined condition. A crash is usual result.
|
||||
*/
|
||||
assert( !pColl || pColl->xCmp );
|
||||
|
||||
if( pColl ){
|
||||
if( pMem1->enc==pColl->enc ){
|
||||
return pColl->xCmp(pColl->pUser,pMem1->n,pMem1->z,pMem2->n,pMem2->z);
|
||||
}else{
|
||||
u8 origEnc = pMem1->enc;
|
||||
rc = pColl->xCmp(
|
||||
pColl->pUser,
|
||||
sqlite3ValueBytes((sqlite3_value*)pMem1, pColl->enc),
|
||||
sqlite3ValueText((sqlite3_value*)pMem1, pColl->enc),
|
||||
sqlite3ValueBytes((sqlite3_value*)pMem2, pColl->enc),
|
||||
sqlite3ValueText((sqlite3_value*)pMem2, pColl->enc)
|
||||
);
|
||||
sqlite3ValueBytes((sqlite3_value*)pMem1, origEnc);
|
||||
sqlite3ValueText((sqlite3_value*)pMem1, origEnc);
|
||||
sqlite3ValueBytes((sqlite3_value*)pMem2, origEnc);
|
||||
sqlite3ValueText((sqlite3_value*)pMem2, origEnc);
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
/* If a NULL pointer was passed as the collate function, fall through
|
||||
** to the blob case and use memcmp(). */
|
||||
}
|
||||
|
||||
/* Both values must be blobs. Compare using memcmp(). */
|
||||
rc = memcmp(pMem1->z, pMem2->z, (pMem1->n>pMem2->n)?pMem2->n:pMem1->n);
|
||||
if( rc==0 ){
|
||||
rc = pMem1->n - pMem2->n;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Move data out of a btree key or data field and into a Mem structure.
|
||||
** The data or key is taken from the entry that pCur is currently pointing
|
||||
** to. offset and amt determine what portion of the data or key to retrieve.
|
||||
** key is true to get the key or false to get data. The result is written
|
||||
** into the pMem element.
|
||||
**
|
||||
** The pMem structure is assumed to be uninitialized. Any prior content
|
||||
** is overwritten without being freed.
|
||||
**
|
||||
** If this routine fails for any reason (malloc returns NULL or unable
|
||||
** to read from the disk) then the pMem is left in an inconsistent state.
|
||||
*/
|
||||
int sqlite3VdbeMemFromBtree(
|
||||
BtCursor *pCur, /* Cursor pointing at record to retrieve. */
|
||||
int offset, /* Offset from the start of data to return bytes from. */
|
||||
int amt, /* Number of bytes to return. */
|
||||
int key, /* If true, retrieve from the btree key, not data. */
|
||||
Mem *pMem /* OUT: Return data in this Mem structure. */
|
||||
){
|
||||
char *zData; /* Data from the btree layer */
|
||||
int available; /* Number of bytes available on the local btree page */
|
||||
|
||||
if( key ){
|
||||
zData = (char *)sqlite3BtreeKeyFetch(pCur, &available);
|
||||
}else{
|
||||
zData = (char *)sqlite3BtreeDataFetch(pCur, &available);
|
||||
}
|
||||
|
||||
pMem->n = amt;
|
||||
if( offset+amt<=available ){
|
||||
pMem->z = &zData[offset];
|
||||
pMem->flags = MEM_Blob|MEM_Ephem;
|
||||
}else{
|
||||
int rc;
|
||||
if( amt>NBFS-2 ){
|
||||
zData = (char *)sqliteMallocRaw(amt+2);
|
||||
if( !zData ){
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
pMem->flags = MEM_Blob|MEM_Dyn|MEM_Term;
|
||||
pMem->xDel = 0;
|
||||
}else{
|
||||
zData = &(pMem->zShort[0]);
|
||||
pMem->flags = MEM_Blob|MEM_Short|MEM_Term;
|
||||
}
|
||||
pMem->z = zData;
|
||||
pMem->enc = 0;
|
||||
pMem->type = SQLITE_BLOB;
|
||||
|
||||
if( key ){
|
||||
rc = sqlite3BtreeKey(pCur, offset, amt, zData);
|
||||
}else{
|
||||
rc = sqlite3BtreeData(pCur, offset, amt, zData);
|
||||
}
|
||||
zData[amt] = 0;
|
||||
zData[amt+1] = 0;
|
||||
if( rc!=SQLITE_OK ){
|
||||
if( amt>NBFS ){
|
||||
sqliteFree(zData);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
/*
|
||||
** Perform various checks on the memory cell pMem. An assert() will
|
||||
** fail if pMem is internally inconsistent.
|
||||
*/
|
||||
void sqlite3VdbeMemSanity(Mem *pMem, u8 db_enc){
|
||||
int flags = pMem->flags;
|
||||
assert( flags!=0 ); /* Must define some type */
|
||||
if( pMem->flags & (MEM_Str|MEM_Blob) ){
|
||||
int x = pMem->flags & (MEM_Static|MEM_Dyn|MEM_Ephem|MEM_Short);
|
||||
assert( x!=0 ); /* Strings must define a string subtype */
|
||||
assert( (x & (x-1))==0 ); /* Only one string subtype can be defined */
|
||||
assert( pMem->z!=0 ); /* Strings must have a value */
|
||||
/* Mem.z points to Mem.zShort iff the subtype is MEM_Short */
|
||||
assert( (pMem->flags & MEM_Short)==0 || pMem->z==pMem->zShort );
|
||||
assert( (pMem->flags & MEM_Short)!=0 || pMem->z!=pMem->zShort );
|
||||
/* No destructor unless there is MEM_Dyn */
|
||||
assert( pMem->xDel==0 || (pMem->flags & MEM_Dyn)!=0 );
|
||||
|
||||
if( (flags & MEM_Str) ){
|
||||
assert( pMem->enc==SQLITE_UTF8 ||
|
||||
pMem->enc==SQLITE_UTF16BE ||
|
||||
pMem->enc==SQLITE_UTF16LE
|
||||
);
|
||||
/* If the string is UTF-8 encoded and nul terminated, then pMem->n
|
||||
** must be the length of the string. (Later:) If the database file
|
||||
** has been corrupted, '\000' characters might have been inserted
|
||||
** into the middle of the string. In that case, the strlen() might
|
||||
** be less.
|
||||
*/
|
||||
if( pMem->enc==SQLITE_UTF8 && (flags & MEM_Term) ){
|
||||
assert( strlen(pMem->z)<=pMem->n );
|
||||
assert( pMem->z[pMem->n]==0 );
|
||||
}
|
||||
}
|
||||
}else{
|
||||
/* Cannot define a string subtype for non-string objects */
|
||||
assert( (pMem->flags & (MEM_Static|MEM_Dyn|MEM_Ephem|MEM_Short))==0 );
|
||||
assert( pMem->xDel==0 );
|
||||
}
|
||||
/* MEM_Null excludes all other types */
|
||||
assert( (pMem->flags&(MEM_Str|MEM_Int|MEM_Real|MEM_Blob))==0
|
||||
|| (pMem->flags&MEM_Null)==0 );
|
||||
if( (pMem->flags & (MEM_Int|MEM_Real))==(MEM_Int|MEM_Real) ){
|
||||
assert( pMem->r==pMem->i );
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* This function is only available internally, it is not part of the
|
||||
** external API. It works in a similar way to sqlite3_value_text(),
|
||||
** except the data returned is in the encoding specified by the second
|
||||
** parameter, which must be one of SQLITE_UTF16BE, SQLITE_UTF16LE or
|
||||
** SQLITE_UTF8.
|
||||
*/
|
||||
const void *sqlite3ValueText(sqlite3_value* pVal, u8 enc){
|
||||
if( !pVal ) return 0;
|
||||
assert( enc==SQLITE_UTF16LE || enc==SQLITE_UTF16BE || enc==SQLITE_UTF8);
|
||||
|
||||
if( pVal->flags&MEM_Null ){
|
||||
return 0;
|
||||
}
|
||||
if( pVal->flags&MEM_Str ){
|
||||
sqlite3VdbeChangeEncoding(pVal, enc);
|
||||
}else if( !(pVal->flags&MEM_Blob) ){
|
||||
sqlite3VdbeMemStringify(pVal, enc);
|
||||
}
|
||||
return (const void *)(pVal->z);
|
||||
}
|
||||
|
||||
/*
|
||||
** Create a new sqlite3_value object.
|
||||
*/
|
||||
sqlite3_value* sqlite3ValueNew(){
|
||||
Mem *p = sqliteMalloc(sizeof(*p));
|
||||
if( p ){
|
||||
p->flags = MEM_Null;
|
||||
p->type = SQLITE_NULL;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
/*
|
||||
** Change the string value of an sqlite3_value object
|
||||
*/
|
||||
void sqlite3ValueSetStr(
|
||||
sqlite3_value *v,
|
||||
int n,
|
||||
const void *z,
|
||||
u8 enc,
|
||||
void (*xDel)(void*)
|
||||
){
|
||||
if( v ) sqlite3VdbeMemSetStr((Mem *)v, z, n, enc, xDel);
|
||||
}
|
||||
|
||||
/*
|
||||
** Free an sqlite3_value object
|
||||
*/
|
||||
void sqlite3ValueFree(sqlite3_value *v){
|
||||
if( !v ) return;
|
||||
sqlite3ValueSetStr(v, 0, 0, SQLITE_UTF8, SQLITE_STATIC);
|
||||
sqliteFree(v);
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the number of bytes in the sqlite3_value object assuming
|
||||
** that it uses the encoding "enc"
|
||||
*/
|
||||
int sqlite3ValueBytes(sqlite3_value *pVal, u8 enc){
|
||||
Mem *p = (Mem*)pVal;
|
||||
if( (p->flags & MEM_Blob)!=0 || sqlite3ValueText(pVal, enc) ){
|
||||
return p->n;
|
||||
}
|
||||
return 0;
|
||||
}
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Загрузка…
Ссылка в новой задаче