mirror of https://github.com/sqlite/sqlite
Merge latest trunk changes with this branch.
FossilOrigin-Name: 55b8011d5b455927f5b92a3cb911fd909fb0edab
This commit is contained in:
commit
d4a80e6742
|
@ -0,0 +1,88 @@
|
|||
/*
|
||||
** 2014-09-08
|
||||
**
|
||||
** 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 application interface definitions for the
|
||||
** user-authentication extension feature.
|
||||
**
|
||||
** To compile with the user-authentication feature, append this file to
|
||||
** end of an SQLite amalgamation header file ("sqlite3.h"), then add
|
||||
** the SQLITE_USER_AUTHENTICATION compile-time option. See the
|
||||
** user-auth.txt file in the same source directory as this file for
|
||||
** additional information.
|
||||
*/
|
||||
#ifdef SQLITE_USER_AUTHENTICATION
|
||||
|
||||
/*
|
||||
** If a database contains the SQLITE_USER table, then the
|
||||
** sqlite3_user_authenticate() interface must be invoked with an
|
||||
** appropriate username and password prior to enable read and write
|
||||
** access to the database.
|
||||
**
|
||||
** Return SQLITE_OK on success or SQLITE_ERROR if the username/password
|
||||
** combination is incorrect or unknown.
|
||||
**
|
||||
** If the SQLITE_USER table is not present in the database file, then
|
||||
** this interface is a harmless no-op returnning SQLITE_OK.
|
||||
*/
|
||||
int sqlite3_user_authenticate(
|
||||
sqlite3 *db, /* The database connection */
|
||||
const char *zUsername, /* Username */
|
||||
const char *aPW, /* Password or credentials */
|
||||
int nPW /* Number of bytes in aPW[] */
|
||||
);
|
||||
|
||||
/*
|
||||
** The sqlite3_user_add() interface can be used (by an admin user only)
|
||||
** to create a new user. When called on a no-authentication-required
|
||||
** database, this routine converts the database into an authentication-
|
||||
** required database, automatically makes the added user an
|
||||
** administrator, and logs in the current connection as that user.
|
||||
** The sqlite3_user_add() interface only works for the "main" database, not
|
||||
** for any ATTACH-ed databases. Any call to sqlite3_user_add() by a
|
||||
** non-admin user results in an error.
|
||||
*/
|
||||
int sqlite3_user_add(
|
||||
sqlite3 *db, /* Database connection */
|
||||
const char *zUsername, /* Username to be added */
|
||||
const char *aPW, /* Password or credentials */
|
||||
int nPW, /* Number of bytes in aPW[] */
|
||||
int isAdmin /* True to give new user admin privilege */
|
||||
);
|
||||
|
||||
/*
|
||||
** The sqlite3_user_change() interface can be used to change a users
|
||||
** login credentials or admin privilege. Any user can change their own
|
||||
** login credentials. Only an admin user can change another users login
|
||||
** credentials or admin privilege setting. No user may change their own
|
||||
** admin privilege setting.
|
||||
*/
|
||||
int sqlite3_user_change(
|
||||
sqlite3 *db, /* Database connection */
|
||||
const char *zUsername, /* Username to change */
|
||||
const char *aPW, /* New password or credentials */
|
||||
int nPW, /* Number of bytes in aPW[] */
|
||||
int isAdmin /* Modified admin privilege for the user */
|
||||
);
|
||||
|
||||
/*
|
||||
** The sqlite3_user_delete() interface can be used (by an admin user only)
|
||||
** to delete a user. The currently logged-in user cannot be deleted,
|
||||
** which guarantees that there is always an admin user and hence that
|
||||
** the database cannot be converted into a no-authentication-required
|
||||
** database.
|
||||
*/
|
||||
int sqlite3_user_delete(
|
||||
sqlite3 *db, /* Database connection */
|
||||
const char *zUsername /* Username to remove */
|
||||
);
|
||||
|
||||
#endif /* SQLITE_USER_AUTHENTICATION */
|
|
@ -0,0 +1,164 @@
|
|||
Activate the user authentication logic by including the
|
||||
ext/userauth/userauth.c source code file in the build and
|
||||
adding the -DSQLITE_USER_AUTHENTICATION compile-time option.
|
||||
The ext/userauth/sqlite3userauth.h header file is available to
|
||||
applications to define the interface.
|
||||
|
||||
When using the SQLite amalgamation, it is sufficient to append
|
||||
the ext/userauth/userauth.c source file onto the end of the
|
||||
amalgamation.
|
||||
|
||||
The following new APIs are available when user authentication is
|
||||
activated:
|
||||
|
||||
int sqlite3_user_authenticate(
|
||||
sqlite3 *db, /* The database connection */
|
||||
const char *zUsername, /* Username */
|
||||
const char *aPW, /* Password or credentials */
|
||||
int nPW /* Number of bytes in aPW[] */
|
||||
);
|
||||
|
||||
int sqlite3_user_add(
|
||||
sqlite3 *db, /* Database connection */
|
||||
const char *zUsername, /* Username to be added */
|
||||
const char *aPW, /* Password or credentials */
|
||||
int nPW, /* Number of bytes in aPW[] */
|
||||
int isAdmin /* True to give new user admin privilege */
|
||||
);
|
||||
|
||||
int sqlite3_user_change(
|
||||
sqlite3 *db, /* Database connection */
|
||||
const char *zUsername, /* Username to change */
|
||||
const void *aPW, /* Modified password or credentials */
|
||||
int nPW, /* Number of bytes in aPW[] */
|
||||
int isAdmin /* Modified admin privilege for the user */
|
||||
);
|
||||
|
||||
int sqlite3_user_delete(
|
||||
sqlite3 *db, /* Database connection */
|
||||
const char *zUsername /* Username to remove */
|
||||
);
|
||||
|
||||
With this extension, a database can be marked as requiring authentication.
|
||||
By default a database does not require authentication.
|
||||
|
||||
The sqlite3_open(), sqlite3_open16(), and sqlite3_open_v2() interfaces
|
||||
work as before: they open a new database connection. However, if the
|
||||
database being opened requires authentication, then attempts to read
|
||||
or write from the database will fail with an SQLITE_AUTH error until
|
||||
after sqlite3_user_authenticate() has been called successfully. The
|
||||
sqlite3_user_authenticate() call will return SQLITE_OK if the
|
||||
authentication credentials are accepted and SQLITE_ERROR if not.
|
||||
|
||||
Calling sqlite3_user_authenticate() on a no-authentication-required
|
||||
database connection is a harmless no-op.
|
||||
|
||||
If the database is encrypted, then sqlite3_key_v2() must be called first,
|
||||
with the correct decryption key, prior to invoking sqlite3_user_authenticate().
|
||||
|
||||
To recapitulate: When opening an existing unencrypted authentication-
|
||||
required database, the call sequence is:
|
||||
|
||||
sqlite3_open_v2()
|
||||
sqlite3_user_authenticate();
|
||||
/* Database is now usable */
|
||||
|
||||
To open an existing, encrypted, authentication-required database, the
|
||||
call sequence is:
|
||||
|
||||
sqlite3_open_v2();
|
||||
sqlite3_key_v2();
|
||||
sqlite3_user_authenticate();
|
||||
/* Database is now usable */
|
||||
|
||||
When opening a no-authentication-required database, the database
|
||||
connection is treated as if it was authenticated as an admin user.
|
||||
|
||||
When ATTACH-ing new database files to a connection, each newly attached
|
||||
database that is an authentication-required database is checked using
|
||||
the same username and password as supplied to the main database. If that
|
||||
check fails, then the ATTACH command fails with an SQLITE_AUTH error.
|
||||
|
||||
The sqlite3_user_add() interface can be used (by an admin user only)
|
||||
to create a new user. When called on a no-authentication-required
|
||||
database and when A is true, the sqlite3_user_add(D,U,P,N,A) routine
|
||||
converts the database into an authentication-required database and
|
||||
logs in the database connection D as user U with password P,N.
|
||||
To convert a no-authentication-required database into an authentication-
|
||||
required database, the isAdmin parameter must be true. If
|
||||
sqlite3_user_add(D,U,P,N,A) is called on a no-authentication-required
|
||||
database and A is false, then the call fails with an SQLITE_AUTH error.
|
||||
|
||||
Any call to sqlite3_user_add() by a non-admin user results in an error.
|
||||
|
||||
Hence, to create a new, unencrypted, authentication-required database,
|
||||
the call sequence is:
|
||||
|
||||
sqlite3_open_v2();
|
||||
sqlite3_user_add();
|
||||
|
||||
And to create a new, encrypted, authentication-required database, the call
|
||||
sequence is:
|
||||
|
||||
sqlite3_open_v2();
|
||||
sqlite3_key_v2();
|
||||
sqlite3_user_add();
|
||||
|
||||
The sqlite3_user_delete() interface can be used (by an admin user only)
|
||||
to delete a user. The currently logged-in user cannot be deleted,
|
||||
which guarantees that there is always an admin user and hence that
|
||||
the database cannot be converted into a no-authentication-required
|
||||
database.
|
||||
|
||||
The sqlite3_user_change() interface can be used to change a users
|
||||
login credentials or admin privilege. Any user can change their own
|
||||
password. Only an admin user can change another users login
|
||||
credentials or admin privilege setting. No user may change their own
|
||||
admin privilege setting.
|
||||
|
||||
The sqlite3_set_authorizer() callback is modified to take a 7th parameter
|
||||
which is the username of the currently logged in user, or NULL for a
|
||||
no-authentication-required database.
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
Implementation notes:
|
||||
|
||||
An authentication-required database is identified by the presence of a
|
||||
new table:
|
||||
|
||||
CREATE TABLE sqlite_user(
|
||||
uname TEXT PRIMARY KEY,
|
||||
isAdmin BOOLEAN,
|
||||
pw BLOB
|
||||
) WITHOUT ROWID;
|
||||
|
||||
The sqlite_user table is inaccessible (unreadable and unwriteable) to
|
||||
non-admin users and is read-only for admin users. However, if the same
|
||||
database file is opened by a version of SQLite that omits
|
||||
the -DSQLITE_USER_AUTHENTICATION compile-time option, then the sqlite_user
|
||||
table will be readable by anybody and writeable by anybody if
|
||||
the "PRAGMA writable_schema=ON" statement is run first.
|
||||
|
||||
The sqlite_user.pw field is encoded by a built-in SQL function
|
||||
"sqlite_crypt(X,Y)". The two arguments are both BLOBs. The first argument
|
||||
is the plaintext password supplied to the sqlite3_user_authenticate()
|
||||
interface. The second argument is the sqlite_user.pw value and is supplied
|
||||
so that the function can extract the "salt" used by the password encoder.
|
||||
The result of sqlite_crypt(X,Y) is another blob which is the value that
|
||||
ends up being stored in sqlite_user.pw. To verify credentials X supplied
|
||||
by the sqlite3_user_authenticate() routine, SQLite runs:
|
||||
|
||||
sqlite_user.pw == sqlite_crypt(X, sqlite_user.pw)
|
||||
|
||||
To compute an appropriate sqlite_user.pw value from a new or modified
|
||||
password X, sqlite_crypt(X,NULL) is run. A new random salt is selected
|
||||
when the second argument is NULL.
|
||||
|
||||
The built-in version of of sqlite_crypt() uses a simple Ceasar-cypher
|
||||
which prevents passwords from being revealed by searching the raw database
|
||||
for ASCII text, but is otherwise trivally broken. For better password
|
||||
security, the database should be encrypted using the SQLite Encryption
|
||||
Extension or similar technology. Or, the application can use the
|
||||
sqlite3_create_function() interface to provide an alternative
|
||||
implementation of sqlite_crypt() that computes a stronger password hash,
|
||||
perhaps using a cryptographic hash function like SHA1.
|
|
@ -0,0 +1,355 @@
|
|||
/*
|
||||
** 2014-09-08
|
||||
**
|
||||
** 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 bulk of the implementation of the
|
||||
** user-authentication extension feature. Some parts of the user-
|
||||
** authentication code are contained within the SQLite core (in the
|
||||
** src/ subdirectory of the main source code tree) but those parts
|
||||
** that could reasonable be separated out are moved into this file.
|
||||
**
|
||||
** To compile with the user-authentication feature, append this file to
|
||||
** end of an SQLite amalgamation, then add the SQLITE_USER_AUTHENTICATION
|
||||
** compile-time option. See the user-auth.txt file in the same source
|
||||
** directory as this file for additional information.
|
||||
*/
|
||||
#ifdef SQLITE_USER_AUTHENTICATION
|
||||
#ifndef _SQLITEINT_H_
|
||||
# include "sqliteInt.h"
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Prepare an SQL statement for use by the user authentication logic.
|
||||
** Return a pointer to the prepared statement on success. Return a
|
||||
** NULL pointer if there is an error of any kind.
|
||||
*/
|
||||
static sqlite3_stmt *sqlite3UserAuthPrepare(
|
||||
sqlite3 *db,
|
||||
const char *zFormat,
|
||||
...
|
||||
){
|
||||
sqlite3_stmt *pStmt;
|
||||
char *zSql;
|
||||
int rc;
|
||||
va_list ap;
|
||||
int savedFlags = db->flags;
|
||||
|
||||
va_start(ap, zFormat);
|
||||
zSql = sqlite3_vmprintf(zFormat, ap);
|
||||
va_end(ap);
|
||||
if( zSql==0 ) return 0;
|
||||
db->flags |= SQLITE_WriteSchema;
|
||||
rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0);
|
||||
db->flags = savedFlags;
|
||||
sqlite3_free(zSql);
|
||||
if( rc ){
|
||||
sqlite3_finalize(pStmt);
|
||||
pStmt = 0;
|
||||
}
|
||||
return pStmt;
|
||||
}
|
||||
|
||||
/*
|
||||
** Check to see if the sqlite_user table exists in database zDb.
|
||||
*/
|
||||
static int userTableExists(sqlite3 *db, const char *zDb){
|
||||
int rc;
|
||||
sqlite3_mutex_enter(db->mutex);
|
||||
sqlite3BtreeEnterAll(db);
|
||||
if( db->init.busy==0 ){
|
||||
char *zErr = 0;
|
||||
sqlite3Init(db, &zErr);
|
||||
sqlite3DbFree(db, zErr);
|
||||
}
|
||||
rc = sqlite3FindTable(db, "sqlite_user", zDb)!=0;
|
||||
sqlite3BtreeLeaveAll(db);
|
||||
sqlite3_mutex_leave(db->mutex);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Check to see if database zDb has a "sqlite_user" table and if it does
|
||||
** whether that table can authenticate zUser with nPw,zPw. Write one of
|
||||
** the UAUTH_* user authorization level codes into *peAuth and return a
|
||||
** result code.
|
||||
*/
|
||||
static int userAuthCheckLogin(
|
||||
sqlite3 *db, /* The database connection to check */
|
||||
const char *zDb, /* Name of specific database to check */
|
||||
u8 *peAuth /* OUT: One of UAUTH_* constants */
|
||||
){
|
||||
sqlite3_stmt *pStmt;
|
||||
int rc;
|
||||
|
||||
*peAuth = UAUTH_Unknown;
|
||||
if( !userTableExists(db, "main") ){
|
||||
*peAuth = UAUTH_Admin; /* No sqlite_user table. Everybody is admin. */
|
||||
return SQLITE_OK;
|
||||
}
|
||||
if( db->auth.zAuthUser==0 ){
|
||||
*peAuth = UAUTH_Fail;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
pStmt = sqlite3UserAuthPrepare(db,
|
||||
"SELECT pw=sqlite_crypt(?1,pw), isAdmin FROM \"%w\".sqlite_user"
|
||||
" WHERE uname=?2", zDb);
|
||||
if( pStmt==0 ) return SQLITE_NOMEM;
|
||||
sqlite3_bind_blob(pStmt, 1, db->auth.zAuthPW, db->auth.nAuthPW,SQLITE_STATIC);
|
||||
sqlite3_bind_text(pStmt, 2, db->auth.zAuthUser, -1, SQLITE_STATIC);
|
||||
rc = sqlite3_step(pStmt);
|
||||
if( rc==SQLITE_ROW && sqlite3_column_int(pStmt,0) ){
|
||||
*peAuth = sqlite3_column_int(pStmt, 1) + UAUTH_User;
|
||||
}else{
|
||||
*peAuth = UAUTH_Fail;
|
||||
}
|
||||
return sqlite3_finalize(pStmt);
|
||||
}
|
||||
int sqlite3UserAuthCheckLogin(
|
||||
sqlite3 *db, /* The database connection to check */
|
||||
const char *zDb, /* Name of specific database to check */
|
||||
u8 *peAuth /* OUT: One of UAUTH_* constants */
|
||||
){
|
||||
int rc;
|
||||
u8 savedAuthLevel;
|
||||
assert( zDb!=0 );
|
||||
assert( peAuth!=0 );
|
||||
savedAuthLevel = db->auth.authLevel;
|
||||
db->auth.authLevel = UAUTH_Admin;
|
||||
rc = userAuthCheckLogin(db, zDb, peAuth);
|
||||
db->auth.authLevel = savedAuthLevel;
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** If the current authLevel is UAUTH_Unknown, the take actions to figure
|
||||
** out what authLevel should be
|
||||
*/
|
||||
void sqlite3UserAuthInit(sqlite3 *db){
|
||||
if( db->auth.authLevel==UAUTH_Unknown ){
|
||||
u8 authLevel = UAUTH_Fail;
|
||||
sqlite3UserAuthCheckLogin(db, "main", &authLevel);
|
||||
db->auth.authLevel = authLevel;
|
||||
if( authLevel<UAUTH_Admin ) db->flags &= ~SQLITE_WriteSchema;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Implementation of the sqlite_crypt(X,Y) function.
|
||||
**
|
||||
** If Y is NULL then generate a new hash for password X and return that
|
||||
** hash. If Y is not null, then generate a hash for password X using the
|
||||
** same salt as the previous hash Y and return the new hash.
|
||||
*/
|
||||
void sqlite3CryptFunc(
|
||||
sqlite3_context *context,
|
||||
int NotUsed,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
const char *zIn;
|
||||
int nIn, ii;
|
||||
u8 *zOut;
|
||||
char zSalt[8];
|
||||
zIn = sqlite3_value_blob(argv[0]);
|
||||
nIn = sqlite3_value_bytes(argv[0]);
|
||||
if( sqlite3_value_type(argv[1])==SQLITE_BLOB
|
||||
&& sqlite3_value_bytes(argv[1])==nIn+sizeof(zSalt)
|
||||
){
|
||||
memcpy(zSalt, sqlite3_value_blob(argv[1]), sizeof(zSalt));
|
||||
}else{
|
||||
sqlite3_randomness(sizeof(zSalt), zSalt);
|
||||
}
|
||||
zOut = sqlite3_malloc( nIn+sizeof(zSalt) );
|
||||
if( zOut==0 ){
|
||||
sqlite3_result_error_nomem(context);
|
||||
}else{
|
||||
memcpy(zOut, zSalt, sizeof(zSalt));
|
||||
for(ii=0; ii<nIn; ii++){
|
||||
zOut[ii+sizeof(zSalt)] = zIn[ii]^zSalt[ii&0x7];
|
||||
}
|
||||
sqlite3_result_blob(context, zOut, nIn+sizeof(zSalt), sqlite3_free);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** If a database contains the SQLITE_USER table, then the
|
||||
** sqlite3_user_authenticate() interface must be invoked with an
|
||||
** appropriate username and password prior to enable read and write
|
||||
** access to the database.
|
||||
**
|
||||
** Return SQLITE_OK on success or SQLITE_ERROR if the username/password
|
||||
** combination is incorrect or unknown.
|
||||
**
|
||||
** If the SQLITE_USER table is not present in the database file, then
|
||||
** this interface is a harmless no-op returnning SQLITE_OK.
|
||||
*/
|
||||
int sqlite3_user_authenticate(
|
||||
sqlite3 *db, /* The database connection */
|
||||
const char *zUsername, /* Username */
|
||||
const char *zPW, /* Password or credentials */
|
||||
int nPW /* Number of bytes in aPW[] */
|
||||
){
|
||||
int rc;
|
||||
u8 authLevel = UAUTH_Fail;
|
||||
db->auth.authLevel = UAUTH_Unknown;
|
||||
sqlite3_free(db->auth.zAuthUser);
|
||||
sqlite3_free(db->auth.zAuthPW);
|
||||
memset(&db->auth, 0, sizeof(db->auth));
|
||||
db->auth.zAuthUser = sqlite3_mprintf("%s", zUsername);
|
||||
if( db->auth.zAuthUser==0 ) return SQLITE_NOMEM;
|
||||
db->auth.zAuthPW = sqlite3_malloc( nPW+1 );
|
||||
if( db->auth.zAuthPW==0 ) return SQLITE_NOMEM;
|
||||
memcpy(db->auth.zAuthPW,zPW,nPW);
|
||||
db->auth.nAuthPW = nPW;
|
||||
rc = sqlite3UserAuthCheckLogin(db, "main", &authLevel);
|
||||
db->auth.authLevel = authLevel;
|
||||
sqlite3ExpirePreparedStatements(db);
|
||||
if( rc ){
|
||||
return rc; /* OOM error, I/O error, etc. */
|
||||
}
|
||||
if( authLevel<UAUTH_User ){
|
||||
return SQLITE_AUTH; /* Incorrect username and/or password */
|
||||
}
|
||||
return SQLITE_OK; /* Successful login */
|
||||
}
|
||||
|
||||
/*
|
||||
** The sqlite3_user_add() interface can be used (by an admin user only)
|
||||
** to create a new user. When called on a no-authentication-required
|
||||
** database, this routine converts the database into an authentication-
|
||||
** required database, automatically makes the added user an
|
||||
** administrator, and logs in the current connection as that user.
|
||||
** The sqlite3_user_add() interface only works for the "main" database, not
|
||||
** for any ATTACH-ed databases. Any call to sqlite3_user_add() by a
|
||||
** non-admin user results in an error.
|
||||
*/
|
||||
int sqlite3_user_add(
|
||||
sqlite3 *db, /* Database connection */
|
||||
const char *zUsername, /* Username to be added */
|
||||
const char *aPW, /* Password or credentials */
|
||||
int nPW, /* Number of bytes in aPW[] */
|
||||
int isAdmin /* True to give new user admin privilege */
|
||||
){
|
||||
sqlite3_stmt *pStmt;
|
||||
int rc;
|
||||
sqlite3UserAuthInit(db);
|
||||
if( db->auth.authLevel<UAUTH_Admin ) return SQLITE_AUTH;
|
||||
if( !userTableExists(db, "main") ){
|
||||
if( !isAdmin ) return SQLITE_AUTH;
|
||||
pStmt = sqlite3UserAuthPrepare(db,
|
||||
"CREATE TABLE sqlite_user(\n"
|
||||
" uname TEXT PRIMARY KEY,\n"
|
||||
" isAdmin BOOLEAN,\n"
|
||||
" pw BLOB\n"
|
||||
") WITHOUT ROWID;");
|
||||
if( pStmt==0 ) return SQLITE_NOMEM;
|
||||
sqlite3_step(pStmt);
|
||||
rc = sqlite3_finalize(pStmt);
|
||||
if( rc ) return rc;
|
||||
}
|
||||
pStmt = sqlite3UserAuthPrepare(db,
|
||||
"INSERT INTO sqlite_user(uname,isAdmin,pw)"
|
||||
" VALUES(%Q,%d,sqlite_crypt(?1,NULL))",
|
||||
zUsername, isAdmin!=0);
|
||||
if( pStmt==0 ) return SQLITE_NOMEM;
|
||||
sqlite3_bind_blob(pStmt, 1, aPW, nPW, SQLITE_STATIC);
|
||||
sqlite3_step(pStmt);
|
||||
rc = sqlite3_finalize(pStmt);
|
||||
if( rc ) return rc;
|
||||
if( db->auth.zAuthUser==0 ){
|
||||
assert( isAdmin!=0 );
|
||||
sqlite3_user_authenticate(db, zUsername, aPW, nPW);
|
||||
}
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** The sqlite3_user_change() interface can be used to change a users
|
||||
** login credentials or admin privilege. Any user can change their own
|
||||
** login credentials. Only an admin user can change another users login
|
||||
** credentials or admin privilege setting. No user may change their own
|
||||
** admin privilege setting.
|
||||
*/
|
||||
int sqlite3_user_change(
|
||||
sqlite3 *db, /* Database connection */
|
||||
const char *zUsername, /* Username to change */
|
||||
const char *aPW, /* Modified password or credentials */
|
||||
int nPW, /* Number of bytes in aPW[] */
|
||||
int isAdmin /* Modified admin privilege for the user */
|
||||
){
|
||||
sqlite3_stmt *pStmt;
|
||||
int rc;
|
||||
u8 authLevel;
|
||||
|
||||
authLevel = db->auth.authLevel;
|
||||
if( authLevel<UAUTH_User ){
|
||||
/* Must be logged in to make a change */
|
||||
return SQLITE_AUTH;
|
||||
}
|
||||
if( strcmp(db->auth.zAuthUser, zUsername)!=0 ){
|
||||
if( db->auth.authLevel<UAUTH_Admin ){
|
||||
/* Must be an administrator to change a different user */
|
||||
return SQLITE_AUTH;
|
||||
}
|
||||
}else if( isAdmin!=(authLevel==UAUTH_Admin) ){
|
||||
/* Cannot change the isAdmin setting for self */
|
||||
return SQLITE_AUTH;
|
||||
}
|
||||
db->auth.authLevel = UAUTH_Admin;
|
||||
if( !userTableExists(db, "main") ){
|
||||
/* This routine is a no-op if the user to be modified does not exist */
|
||||
}else{
|
||||
pStmt = sqlite3UserAuthPrepare(db,
|
||||
"UPDATE sqlite_user SET isAdmin=%d, pw=sqlite_crypt(?1,NULL)"
|
||||
" WHERE uname=%Q", isAdmin, zUsername);
|
||||
if( pStmt==0 ){
|
||||
rc = SQLITE_NOMEM;
|
||||
}else{
|
||||
sqlite3_bind_blob(pStmt, 1, aPW, nPW, SQLITE_STATIC);
|
||||
sqlite3_step(pStmt);
|
||||
rc = sqlite3_finalize(pStmt);
|
||||
}
|
||||
}
|
||||
db->auth.authLevel = authLevel;
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** The sqlite3_user_delete() interface can be used (by an admin user only)
|
||||
** to delete a user. The currently logged-in user cannot be deleted,
|
||||
** which guarantees that there is always an admin user and hence that
|
||||
** the database cannot be converted into a no-authentication-required
|
||||
** database.
|
||||
*/
|
||||
int sqlite3_user_delete(
|
||||
sqlite3 *db, /* Database connection */
|
||||
const char *zUsername /* Username to remove */
|
||||
){
|
||||
sqlite3_stmt *pStmt;
|
||||
if( db->auth.authLevel<UAUTH_Admin ){
|
||||
/* Must be an administrator to delete a user */
|
||||
return SQLITE_AUTH;
|
||||
}
|
||||
if( strcmp(db->auth.zAuthUser, zUsername)==0 ){
|
||||
/* Cannot delete self */
|
||||
return SQLITE_AUTH;
|
||||
}
|
||||
if( !userTableExists(db, "main") ){
|
||||
/* This routine is a no-op if the user to be deleted does not exist */
|
||||
return SQLITE_OK;
|
||||
}
|
||||
pStmt = sqlite3UserAuthPrepare(db,
|
||||
"DELETE FROM sqlite_user WHERE uname=%Q", zUsername);
|
||||
if( pStmt==0 ) return SQLITE_NOMEM;
|
||||
sqlite3_step(pStmt);
|
||||
return sqlite3_finalize(pStmt);
|
||||
}
|
||||
|
||||
#endif /* SQLITE_USER_AUTHENTICATION */
|
13
main.mk
13
main.mk
|
@ -46,7 +46,7 @@
|
|||
#
|
||||
TCCX = $(TCC) $(OPTS) -I. -I$(TOP)/src -I$(TOP)
|
||||
TCCX += -I$(TOP)/ext/rtree -I$(TOP)/ext/icu -I$(TOP)/ext/fts3
|
||||
TCCX += -I$(TOP)/ext/async
|
||||
TCCX += -I$(TOP)/ext/async -I$(TOP)/ext/userauth
|
||||
|
||||
# Object files for the SQLite library.
|
||||
#
|
||||
|
@ -67,7 +67,7 @@ LIBOBJ+= vdbe.o parse.o \
|
|||
pager.o pcache.o pcache1.o pragma.o prepare.o printf.o \
|
||||
random.o resolve.o rowset.o rtree.o select.o status.o \
|
||||
table.o threads.o tokenize.o trigger.o \
|
||||
update.o util.o vacuum.o \
|
||||
update.o userauth.o util.o vacuum.o \
|
||||
vdbeapi.o vdbeaux.o vdbeblob.o vdbemem.o vdbesort.o \
|
||||
vdbetrace.o wal.o walker.o where.o utf.o vtab.o
|
||||
|
||||
|
@ -214,7 +214,9 @@ SRC += \
|
|||
$(TOP)/ext/rtree/sqlite3rtree.h \
|
||||
$(TOP)/ext/rtree/rtree.h \
|
||||
$(TOP)/ext/rtree/rtree.c
|
||||
|
||||
SRC += \
|
||||
$(TOP)/ext/userauth/userauth.c \
|
||||
$(TOP)/ext/userauth/sqlite3userauth.h
|
||||
|
||||
# Generated source code files
|
||||
#
|
||||
|
@ -378,6 +380,8 @@ EXTHDR += \
|
|||
$(TOP)/ext/rtree/rtree.h
|
||||
EXTHDR += \
|
||||
$(TOP)/ext/icu/sqliteicu.h
|
||||
EXTHDR += \
|
||||
$(TOP)/ext/userauth/sqlite3userauth.h
|
||||
|
||||
# This is the default Makefile target. The objects listed here
|
||||
# are what get build when you type just "make" with no arguments.
|
||||
|
@ -559,6 +563,9 @@ fts3_write.o: $(TOP)/ext/fts3/fts3_write.c $(HDR) $(EXTHDR)
|
|||
rtree.o: $(TOP)/ext/rtree/rtree.c $(HDR) $(EXTHDR)
|
||||
$(TCCX) -DSQLITE_CORE -c $(TOP)/ext/rtree/rtree.c
|
||||
|
||||
userauth.o: $(TOP)/ext/userauth/userauth.c $(HDR) $(EXTHDR)
|
||||
$(TCCX) -DSQLITE_CORE -c $(TOP)/ext/userauth/userauth.c
|
||||
|
||||
|
||||
# Rules for building test programs and for running tests
|
||||
#
|
||||
|
|
170
manifest
170
manifest
|
@ -1,5 +1,5 @@
|
|||
C Have\ssqlite3ota.c\suse\sgrave\saccents\sinstead\sof\sdouble-quotes\sto\senclose\sidentifiers\sin\sgenerated\sSQL.\sTo\savoid\shaving\sthe\sSQL\sengine\ssubstitute\sa\sliteral\sstring\sif\sa\scolumn\sreference\scannot\sbe\sresolved.
|
||||
D 2014-09-15T15:22:32.496
|
||||
C Merge\slatest\strunk\schanges\swith\sthis\sbranch.
|
||||
D 2014-09-15T15:34:31.844
|
||||
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
|
||||
F Makefile.in cf57f673d77606ab0f2d9627ca52a9ba1464146a
|
||||
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
|
||||
|
@ -150,10 +150,13 @@ F ext/rtree/rtree_util.tcl 06aab2ed5b826545bf215fff90ecb9255a8647ea
|
|||
F ext/rtree/sqlite3rtree.h 83349d519fe5f518b3ea025d18dd1fe51b1684bd
|
||||
F ext/rtree/tkt3363.test 142ab96eded44a3615ec79fba98c7bde7d0f96de
|
||||
F ext/rtree/viewrtree.tcl eea6224b3553599ae665b239bd827e182b466024
|
||||
F ext/userauth/sqlite3userauth.h 19cb6f0e31316d0ee4afdfb7a85ef9da3333a220
|
||||
F ext/userauth/user-auth.txt e6641021a9210364665fe625d067617d03f27b04
|
||||
F ext/userauth/userauth.c 5fa3bdb492f481bbc1709fc83c91ebd13460c69e
|
||||
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x
|
||||
F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8
|
||||
F magic.txt 8273bf49ba3b0c8559cb2774495390c31fd61c60
|
||||
F main.mk ed2e37f6cd016ecc614165b3392bdbf89a129b4a
|
||||
F main.mk 8e4a294f77e23b2d19e2ac8f5a8761d260bfa4af
|
||||
F mkopcodec.awk c2ff431854d702cdd2d779c9c0d1f58fa16fa4ea
|
||||
F mkopcodeh.awk c6b3fa301db6ef7ac916b14c60868aeaec1337b5
|
||||
F mkso.sh fd21c06b063bb16a5d25deea1752c2da6ac3ed83
|
||||
|
@ -167,79 +170,79 @@ F spec.template 86a4a43b99ebb3e75e6b9a735d5fd293a24e90ca
|
|||
F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b
|
||||
F sqlite3.1 3d8b83c91651f53472ca17599dae3457b8b89494
|
||||
F sqlite3.pc.in 48fed132e7cb71ab676105d2a4dc77127d8c1f3a
|
||||
F src/alter.c b00900877f766f116f9e16116f1ccacdc21d82f1
|
||||
F src/analyze.c f00f06e6ef66c61b41f154889fe7caf5ed55a0ce
|
||||
F src/attach.c 3801129015ef59d76bf23c95ef9b0069d18a0c52
|
||||
F src/auth.c 523da7fb4979469955d822ff9298352d6b31de34
|
||||
F src/alter.c ba266a779bc7ce10e52e59e7d3dc79fa342e8fdb
|
||||
F src/analyze.c 79383a54fee3b7f1fb03dd4c8c8115583f506de5
|
||||
F src/attach.c f4e94df2d1826feda65eb0939f7f6f5f923a0ad9
|
||||
F src/auth.c d8abcde53426275dab6243b441256fcd8ccbebb2
|
||||
F src/backup.c a31809c65623cc41849b94d368917f8bb66e6a7e
|
||||
F src/bitvec.c 19a4ba637bd85f8f63fc8c9bae5ade9fb05ec1cb
|
||||
F src/btmutex.c ec9d3f1295dafeb278c3830211cc5584132468f4
|
||||
F src/btree.c 9cb1989073502a9d2f18fbb0e7df8ad89dda2dcf
|
||||
F src/btmutex.c 49ca66250c7dfa844a4d4cb8272b87420d27d3a5
|
||||
F src/btree.c 3957262c61e865833021af435b6b6daf3a0829be
|
||||
F src/btree.h a79aa6a71e7f1055f01052b7f821bd1c2dce95c8
|
||||
F src/btreeInt.h cf180d86b2e9e418f638d65baa425c4c69c0e0e3
|
||||
F src/build.c c26b233dcdb1e2c8f468d49236c266f9f3de96d8
|
||||
F src/callback.c b97d0695ffcf6a8710ee445ffe56ee387d4d8a6f
|
||||
F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac
|
||||
F src/ctime.c 0231df905e2c4abba4483ee18ffc05adc321df2a
|
||||
F src/date.c 593c744b2623971e45affd0bde347631bdfa4625
|
||||
F src/delete.c 3c2a375c0329247d01222170ae19ad8a52ecbf9a
|
||||
F src/expr.c e1691ab0fe6be7247ef073b0038fb8ecd9944fad
|
||||
F src/btreeInt.h e0ecb5dba292722039a7540beb3fc448103273cc
|
||||
F src/build.c 047d7e1d2d89fa55134fa1d6b669c9c2983c0d11
|
||||
F src/callback.c 7b44ce59674338ad48b0e84e7b72f935ea4f68b0
|
||||
F src/complete.c 535183afb3c75628b78ce82612931ac7cdf26f14
|
||||
F src/ctime.c 16cd19215d9fd849ee2b7509b092f2e0bbd6a958
|
||||
F src/date.c 57a7f9ba9f6b4d5268f5e411739066a611f99036
|
||||
F src/delete.c df9e2f273675ebf8d7f229e7668ba941bdc7021a
|
||||
F src/expr.c 19392d98e089640c3336e65b4254cc337efef7d1
|
||||
F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb
|
||||
F src/fkey.c 8d81a780ad78d16ec9082585758a8f1d6bf02ca3
|
||||
F src/func.c bbb724b74ed96ca42675a7274646a71dd52bcda7
|
||||
F src/global.c 1e4bd956dc2f608f87d2a929abc4a20db65f30e4
|
||||
F src/fkey.c da985ae673efef2c712caef825a5d2edb087ead7
|
||||
F src/func.c 5d498933f6168dff80941c873805fe04dc2b766d
|
||||
F src/global.c 5110fa12e09729b84eee0191c984ec4008e21937
|
||||
F src/hash.c 4263fbc955f26c2e8cdc0cf214bc42435aa4e4f5
|
||||
F src/hash.h c8f3c31722cf3277d03713909761e152a5b81094
|
||||
F src/hwtime.h d32741c8f4df852c7d959236615444e2b1063b08
|
||||
F src/insert.c 62b0ceab1720dc74ed1fbcf953224132245704d8
|
||||
F src/insert.c 25e63641927530eee0487c5a8bbf6e5414c4c753
|
||||
F src/journal.c b4124532212b6952f42eb2c12fa3c25701d8ba8d
|
||||
F src/legacy.c 87c92f4a08e2f70220e3b22a9c3b2482d36a134a
|
||||
F src/lempar.c cdf0a000315332fc9b50b62f3b5e22e080a0952b
|
||||
F src/loadext.c 31c2122b7dd05a179049bbf163fd4839f181cbab
|
||||
F src/main.c c9802dc99c019fbba516202300d56be2c478fa93
|
||||
F src/malloc.c 954de5f998c23237e04474a3f2159bf483bba65a
|
||||
F src/legacy.c ba1863ea58c4c840335a84ec276fc2b25e22bc4e
|
||||
F src/lempar.c 7274c97d24bb46631e504332ccd3bd1b37841770
|
||||
F src/loadext.c de741e66e5ddc1598d904d7289239696e40ed994
|
||||
F src/main.c 6b9fd1867a5575db2119f850302a883e7684009c
|
||||
F src/malloc.c cc015821ba267ad5c91dc8761d0498a3fc3ce6ce
|
||||
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
|
||||
F src/mem1.c c0c990fcaddff810ea277b4fb5d9138603dd5d4b
|
||||
F src/mem1.c faf615aafd8be74a71494dfa027c113ea5c6615f
|
||||
F src/mem2.c dce31758da87ec2cfa52ba4c5df1aed6e07d8e8f
|
||||
F src/mem3.c 61c9d47b792908c532ca3a62b999cf21795c6534
|
||||
F src/mem5.c 74670012946c4adc8a6ad84d03acc80959c3e529
|
||||
F src/memjournal.c 0683aac6cab6ec2b5374c0db37c0deb2436a3785
|
||||
F src/mem5.c 61eeb90134f9a5be6c2e68d8daae7628b25953fb
|
||||
F src/memjournal.c 3eb2c0b51adbd869cb6a44780323f05fa904dc85
|
||||
F src/mutex.c 84a073c9a23a8d7bdd2ea832522d1730df18812c
|
||||
F src/mutex.h 5bc526e19dccc412b7ff04642f6fdad3fdfdabea
|
||||
F src/mutex.h 779d588e3b7756ec3ecf7d78cde1d84aba414f85
|
||||
F src/mutex_noop.c f3f09fd7a2eb4287cfc799753ffc30380e7b71a1
|
||||
F src/mutex_unix.c 1b10d5413dfc794364a8adf3eb3a192926b43fa3
|
||||
F src/mutex_w32.c 06bfff9a3a83b53389a51a967643db3967032e1e
|
||||
F src/notify.c 9711a7575036f0d3040ba61bc6e217f13a9888e7
|
||||
F src/os.c 1b147e4cf7cc39e618115c14a086aed44bc91ace
|
||||
F src/os.h 60d419395e32a8029fa380a80a3da2e9030f635e
|
||||
F src/os.h 3e57a24e2794a94d3cf2342c6d9a884888cd96bf
|
||||
F src/os_common.h 92815ed65f805560b66166e3583470ff94478f04
|
||||
F src/os_setup.h c9d4553b5aaa6f73391448b265b89bed0b890faa
|
||||
F src/os_unix.c 8525ca79457c5b4673a5fda2774ee39fe155f40f
|
||||
F src/os_win.c 2aa8aa7780d7cf03e912d2088ab2ec5c32f33dc5
|
||||
F src/os_unix.c addd023b26c623fec4dedc110fc4370a65b4768c
|
||||
F src/os_win.c 0a4042ef35f322e86fa01f6c8884c5e645b911e7
|
||||
F src/os_win.h 09e751b20bbc107ffbd46e13555dc73576d88e21
|
||||
F src/pager.c 9611de7c00ea3cfe35295d88ebda1a096b71b41d
|
||||
F src/pager.c b7c625fc92e86fea1971b8a630009eab3ff18997
|
||||
F src/pager.h 6a08df06b7edc3684375c0fab40602c695a044f2
|
||||
F src/parse.y 22d6a074e5f5a7258947a1dc55a9bf946b765dd0
|
||||
F src/pcache.c 3b3791297e8977002e56b4a9b8916f2039abad9b
|
||||
F src/pcache.c 4121a0571c18581ee9f82f086d5e2030051ebd6a
|
||||
F src/pcache.h 9b559127b83f84ff76d735c8262f04853be0c59a
|
||||
F src/pcache1.c c5af6403a55178c9d1c09e4f77b0f9c88822762c
|
||||
F src/pragma.c e1b8049c059ccab0afc2a483ff2e0dd599fcb124
|
||||
F src/prepare.c 314961aa6650cc860394cb2f31931cf2de93baa8
|
||||
F src/printf.c 00986c86ddfffefc2fd3c73667ff51b3b9709c74
|
||||
F src/pcache1.c dab8ab930d4a73b99768d881185994f34b80ecaa
|
||||
F src/pragma.c 5dba6b386cbfe0b094350b7d6c99fd410958f22d
|
||||
F src/prepare.c 905c3c601ccadd22bb70b63cd48392f7126c9807
|
||||
F src/printf.c e74925089a85e3c9f0e315595f41c139d3d118c2
|
||||
F src/random.c d10c1f85b6709ca97278428fd5db5bbb9c74eece
|
||||
F src/resolve.c 0ea356d32a5e884add23d1b9b4e8736681dd5697
|
||||
F src/rowset.c a9c9aae3234b44a6d7c6f5a3cadf90dce1e627be
|
||||
F src/select.c 89e569b263535662f54b537eb9118b2c554ae7aa
|
||||
F src/shell.c 713cef4d73c05fc8e12f4960072329d767a05d50
|
||||
F src/sqlite.h.in 578c42cb3899ee6ad93a0cccff4eb47e1e9a2c80
|
||||
F src/resolve.c a3466128b52a86c466e47ac1a19e2174f7b5cf89
|
||||
F src/rowset.c eccf6af6d620aaa4579bd3b72c1b6395d9e9fa1e
|
||||
F src/select.c 0cd6706fd52ae5db229e9041094db6ec27195335
|
||||
F src/shell.c c00220cdd7f2027780bc25b78376c16dc24e4b7d
|
||||
F src/sqlite.h.in 5bcaca9d5a8403fda0c8677de4c527907b317f1d
|
||||
F src/sqlite3.rc 992c9f5fb8285ae285d6be28240a7e8d3a7f2bad
|
||||
F src/sqlite3ext.h 886f5a34de171002ad46fae8c36a7d8051c190fc
|
||||
F src/sqliteInt.h 7c090825333d91ca392c2479a9e835e7b6a5eb12
|
||||
F src/sqlite3ext.h 17d487c3c91b0b8c584a32fbeb393f6f795eea7d
|
||||
F src/sqliteInt.h 3210f8bd040d1c6d8b1616325b15dd3ff749e48f
|
||||
F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d
|
||||
F src/status.c 7ac05a5c7017d0b9f0b4bcd701228b784f987158
|
||||
F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e
|
||||
F src/tclsqlite.c 29357f2be7b0d00e8ea900eaf727e0c5ffeaa660
|
||||
F src/test1.c e9a0e5804b078532e69e69ec14c8326bf2cfc318
|
||||
F src/table.c 218ae2ba022881846741dfc8351aefdf129e0377
|
||||
F src/tclsqlite.c ac7d1672f69c9d69defeb022f656d04f5cefd198
|
||||
F src/test1.c 75655557ebc7138e1d745313635b6b100c90c151
|
||||
F src/test2.c 98049e51a17dc62606a99a9eb95ee477f9996712
|
||||
F src/test3.c 1c0e5d6f080b8e33c1ce8b3078e7013fdbcd560c
|
||||
F src/test4.c 9b32d22f5f150abe23c1830e2057c4037c45b3df
|
||||
|
@ -252,18 +255,18 @@ F src/test_async.c 21e11293a2f72080eda70e1124e9102044531cd8
|
|||
F src/test_autoext.c dea8a01a7153b9adc97bd26161e4226329546e12
|
||||
F src/test_backup.c 3875e899222b651e18b662f86e0e50daa946344e
|
||||
F src/test_btree.c 2e9978eca99a9a4bfa8cae949efb00886860a64f
|
||||
F src/test_config.c d5f00627c4f47515a57f905806558153cccd7253
|
||||
F src/test_config.c 6f721f0337b96d58e81ff69bba101113c8168c2b
|
||||
F src/test_demovfs.c 69b2085076654ebc18014cbc6386f04409c959a9
|
||||
F src/test_devsym.c e7498904e72ba7491d142d5c83b476c4e76993bc
|
||||
F src/test_fs.c ced436e3d4b8e4681328409b8081051ce614e28f
|
||||
F src/test_func.c d3013ce36f19ac72a99c73864930fd1fa41832f8
|
||||
F src/test_hexio.c abfdecb6fa58c354623978efceb088ca18e379cd
|
||||
F src/test_init.c 66b33120ffe9cd853b5a905ec850d51151337b32
|
||||
F src/test_intarray.c db4614c2262a06abc4409dc048d59c580c38320f
|
||||
F src/test_intarray.c 6c610a21ab8edde85a3a2c7f2b069244ecf4d834
|
||||
F src/test_intarray.h 9dc57417fb65bc7835cc18548852cc08cc062202
|
||||
F src/test_journal.c f5c0a05b7b3d5930db769b5ee6c3766dc2221a64
|
||||
F src/test_loadext.c a5251f956ab6af21e138dc1f9c0399394a510cb4
|
||||
F src/test_malloc.c 5368fb1de77246da1ae0ff59cba0d30cb0e5812f
|
||||
F src/test_malloc.c ba34143f941a9d74b30bbffc8818389bb73a1ca2
|
||||
F src/test_multiplex.c ca90057438b63bf0840ebb84d0ef050624519a76
|
||||
F src/test_multiplex.h c08e4e8f8651f0c5e0509b138ff4d5b43ed1f5d3
|
||||
F src/test_mutex.c 293042d623ebba969160f471a82aa1551626454f
|
||||
|
@ -273,7 +276,7 @@ F src/test_pcache.c a5cd24730cb43c5b18629043314548c9169abb00
|
|||
F src/test_quota.c 65f6348fec0f2b3020c907247fb47556b214abb9
|
||||
F src/test_quota.h 2a8ad1952d1d2ca9af0ce0465e56e6c023b5e15d
|
||||
F src/test_rtree.c fdd8d29ca5165c7857987a2ba263fac5c69e231f
|
||||
F src/test_schema.c cd12a2223c3a394f4d07bb93bdf6d344c5c121b6
|
||||
F src/test_schema.c 2bdba21b82f601da69793e1f1d11bf481a79b091
|
||||
F src/test_server.c a2615049954cbb9cfb4a62e18e2f0616e4dc38fe
|
||||
F src/test_sqllog.c c1c1bbedbcaf82b93d83e4f9dd990e62476a680e
|
||||
F src/test_stat.c 9898687a6c2beca733b0dd6fe19163d987826d31
|
||||
|
@ -285,30 +288,30 @@ F src/test_vfs.c f84075a388527892ff184988f43b69ce69b8083c
|
|||
F src/test_vfstrace.c bab9594adc976cbe696ff3970728830b4c5ed698
|
||||
F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
|
||||
F src/threads.c 22dded4283dc4b25422f6444cdcb8d6b1ea0b5ff
|
||||
F src/tokenize.c ae45399d6252b4d736af43bee1576ce7bff86aec
|
||||
F src/trigger.c 4bddd12803275aa98f1c7ce0118fceb02b2167f6
|
||||
F src/update.c ea336ce7b8b3fc5e316ba8f082e6445babf81059
|
||||
F src/tokenize.c 3df63041994f55afeb168b463ec836e8f1c50e7c
|
||||
F src/trigger.c 25571661fdeae8c7f975ff40ffec205520a3f92f
|
||||
F src/update.c 729f6f18fc27740591d085e1172cebe311144bf0
|
||||
F src/utf.c 77abb5e6d27f3d236e50f7c8fff1d00e15262359
|
||||
F src/util.c 068dcd26354a3898ccc64ad5c4bdb95a7a15d33a
|
||||
F src/vacuum.c 3728d74919d4fb1356f9e9a13e27773db60b7179
|
||||
F src/vdbe.c 90db7ad740b6d3f7ab446e6244dbc17ce495cca6
|
||||
F src/util.c 4006c01772bd8d8ac4306d523bbcee41d3e392d8
|
||||
F src/vacuum.c 59f03f92bcff57faa6a8ca256eb29ccddfb0614a
|
||||
F src/vdbe.c 9a45dcbcc967fc0cb9248c75ba245d1d47de3e78
|
||||
F src/vdbe.h c63fad052c9e7388d551e556e119c0bcf6bebdf8
|
||||
F src/vdbeInt.h cdc8e421f85beb1ac9b4669ec5beadab6faa15e0
|
||||
F src/vdbeapi.c 09677a53dd8c71bcd670b0bd073bb9aefa02b441
|
||||
F src/vdbeaux.c cef5d34a64ae3a65b56d96d3fd663246ec8e1c36
|
||||
F src/vdbeInt.h b4843c35c3ba533b69d4250f550b5bacf2fb013d
|
||||
F src/vdbeapi.c 06b712d4772b318b69cd37a416deb1ff0426aa8c
|
||||
F src/vdbeaux.c 91fd1e0c54a765838dc61fcf79f31acce035ce38
|
||||
F src/vdbeblob.c a8e2c3baa3e7081347c4677185a631bfc43de043
|
||||
F src/vdbemem.c 921d5468a68ac06f369810992e84ca22cc730a62
|
||||
F src/vdbesort.c 7c45bfcd823f30d172bbbc1b9f51ef4402fbfe8d
|
||||
F src/vdbetrace.c 6f52bc0c51e144b7efdcfb2a8f771167a8816767
|
||||
F src/vdbemem.c dc36ea9fe26c25550c50085f388167086ef7d73a
|
||||
F src/vdbesort.c 36ac09004c2ca57486ba3d1f4ac5d0d62257b136
|
||||
F src/vdbetrace.c 16d39c1ef7d1f4a3a7464bea3b7b4bdd7849c415
|
||||
F src/vtab.c 019dbfd0406a7447c990e1f7bd1dfcdb8895697f
|
||||
F src/wal.c 93b4fcb56a98f435a2cb66024bb2b12d66d1ff53
|
||||
F src/wal.c 6f5ff51117293e7b2c75ad21834f51115e59ea96
|
||||
F src/wal.h 237bc4484f7c289f094ecb6efb2b6c02005484e1
|
||||
F src/walker.c 11edb74d587bc87b33ca96a5173e3ec1b8389e45
|
||||
F src/where.c d9eae96b2cbbe4842eac3ee156ccd1b933d802c4
|
||||
F src/whereInt.h 923820bee9726033a501a08d2fc69b9c1ee4feb3
|
||||
F src/walker.c c253b95b4ee44b21c406e2a1052636c31ea27804
|
||||
F src/where.c 839b5e1db2507e221ad1c308f148a8519ed750be
|
||||
F src/whereInt.h 124d970450955a6982e174b07c320ae6d62a595c
|
||||
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
|
||||
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
|
||||
F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6
|
||||
F test/aggnested.test b35b4cd69fc913f90d39a575e171e1116c3a4bb7
|
||||
F test/alias.test 4529fbc152f190268a15f9384a5651bbbabc9d87
|
||||
F test/all.test 6ff7b43c2b4b905c74dc4a813d201d0fa64c5783
|
||||
F test/alter.test 547dc2d292644301ac9a7dda22b319b74f9c08d2
|
||||
|
@ -339,9 +342,9 @@ F test/attach2.test 0ec5defa340363de6cd50fd595046465e9aaba2d
|
|||
F test/attach3.test 359eb65d00102cdfcef6fa4e81dc1648f8f80b27
|
||||
F test/attach4.test 53bf502f17647c6d6c5add46dda6bac8b6f4665c
|
||||
F test/attachmalloc.test 3a4bfca9545bfe906a8d2e622de10fbac5b711b0
|
||||
F test/auth.test 5bdf154eb28c0e4bbc0473f335858c0d96171768
|
||||
F test/auth2.test c3b415b76c033bedb81292118fb7c01f5f10cbcd
|
||||
F test/auth3.test a4755e6a2a2fea547ffe63c874eb569e60a28eb5
|
||||
F test/auth.test 855233ef26eb3601b6886567ea4e326c72959360
|
||||
F test/auth2.test 264c6af53cad9aba5218c68bbe18036e39007bfa
|
||||
F test/auth3.test 5cfa94ed90c6617c42b7ba4b133fd79678b251c7
|
||||
F test/autoinc.test c58912526998a39e11f66b533e23cfabea7f25b7
|
||||
F test/autoindex1.test 762ff3f8e25d852aae55c6462ca166a80c0cde61
|
||||
F test/autoindex2.test 60d2fc6f38364308ce73a9beb01b47ded38697de
|
||||
|
@ -482,7 +485,7 @@ F test/fallocate.test 3e979af17dfa7e5e9dda5eba1a696c04fa9d47f7
|
|||
F test/filectrl.test 14fa712e42c4cb791e09dfd58a6a03efb47ef13a
|
||||
F test/filefmt.test cb34663f126cbc2d358af552dcaf5c72769b0146
|
||||
F test/fkey1.test e1d1fa84cde579185ea01358436839703e415a5b
|
||||
F test/fkey2.test 32ca728bcb854feed72d1406ea375fe423eebff2
|
||||
F test/fkey2.test 1db212cda86b0d3ce72714001f7b6381c321341c
|
||||
F test/fkey3.test 76d475c80b84ee7a5d062e56ccb6ea68882e2b49
|
||||
F test/fkey4.test 86446017011273aad8f9a99c1a65019e7bd9ca9d
|
||||
F test/fkey5.test 8a1fde4e7721ae00b05b3178888833726ca2df8d
|
||||
|
@ -580,7 +583,7 @@ F test/fts3sort.test ed34c716a11cc2009a35210e84ad5f9c102362ca
|
|||
F test/fts3tok1.test c551043de056b0b1582a54e878991f57bad074bc
|
||||
F test/fts3tok_err.test 52273cd193b9036282f7bacb43da78c6be87418d
|
||||
F test/fts3varint.test 752c08ed5d32c5d7dc211b056f4ed68a76b7e36e
|
||||
F test/fts4aa.test 0c3152322c7f0b548cc942ad763eaba0da87ccca
|
||||
F test/fts4aa.test 10aac8e9d62c7357590acfabe3fad01e9a9ce1cb
|
||||
F test/fts4check.test 74d77f6cdb768ac49df5afda575cef14ae3d239a
|
||||
F test/fts4content.test 2e7252557d6d24afa101d9ba1de710d6140e6d06
|
||||
F test/fts4docid.test e33c383cfbdff0284685604d256f347a18fdbf01
|
||||
|
@ -715,7 +718,7 @@ F test/memsubsys2.test 3a1c1a9de48e5726faa85108b02459fae8cb9ee9
|
|||
F test/minmax.test 42fbad0e81afaa6e0de41c960329f2b2c3526efd
|
||||
F test/minmax2.test b44bae787fc7b227597b01b0ca5575c7cb54d3bc
|
||||
F test/minmax3.test cc1e8b010136db0d01a6f2a29ba5a9f321034354
|
||||
F test/minmax4.test 536a3360470633a177e42fbc19660d146b51daef
|
||||
F test/minmax4.test 936941484ebdceb8adec7c86b6cd9b6e5e897c1f
|
||||
F test/misc1.test 1201a037c24f982cc0e956cdaa34fcaf6439c417
|
||||
F test/misc2.test 00d7de54eda90e237fc9a38b9e5ccc769ebf6d4d
|
||||
F test/misc3.test cf3dda47d5dda3e53fc5804a100d3c82be736c9d
|
||||
|
@ -788,7 +791,7 @@ F test/rowhash.test 0bc1d31415e4575d10cacf31e1a66b5cc0f8be81
|
|||
F test/rowid.test b78b30afb9537a73788ca1233a23a32190a3bb1f
|
||||
F test/rtree.test 0c8d9dd458d6824e59683c19ab2ffa9ef946f798
|
||||
F test/run-wordcount.sh 891e89c4c2d16e629cd45951d4ed899ad12afc09
|
||||
F test/savepoint.test 6c53f76dffe5df0dd87646efe3e7aa159c36e07b
|
||||
F test/savepoint.test 51d3900dc071a7c2ad4248578a5925631b476313
|
||||
F test/savepoint2.test 9b8543940572a2f01a18298c3135ad0c9f4f67d7
|
||||
F test/savepoint3.test e328085853b14898d78ceea00dfe7db18bb6a9ec
|
||||
F test/savepoint4.test c8f8159ade6d2acd9128be61e1230f1c1edc6cc0
|
||||
|
@ -1060,6 +1063,7 @@ F test/unixexcl.test cd6c765f75e50e8e2c2ba763149e5d340ea19825
|
|||
F test/unordered.test ca7adce0419e4ca0c50f039885e76ed2c531eda8
|
||||
F test/update.test 1b6c488a8f993d090b7ee9ad0e234faa161b3aeb
|
||||
F test/uri.test 23662b7b61958b0f0e47082de7d06341ccf85d5b
|
||||
F test/userauth01.test e740a2697a7b40d7c5003a7d7edaee16acd349a9
|
||||
F test/utf16align.test 54cd35a27c005a9b6e7815d887718780b6a462ae
|
||||
F test/vacuum.test ce91c39f7f91a4273bf620efad21086b5aa6ef1d
|
||||
F test/vacuum2.test af432e6e3bfc0ea20a80cb86a03c7d9876d38324
|
||||
|
@ -1070,7 +1074,7 @@ F test/veryquick.test 57ab846bacf7b90cf4e9a672721ea5c5b669b661
|
|||
F test/view.test f311691d696a5cc27e3c1b875cec1b0866b4ccd9
|
||||
F test/vtab1.test b631d147b198cfd7903ab5fed028eb2a3d321dc6
|
||||
F test/vtab2.test 7bcffc050da5c68f4f312e49e443063e2d391c0d
|
||||
F test/vtab3.test baad99fd27217f5d6db10660522e0b7192446de1
|
||||
F test/vtab3.test b45f47d20f225ccc9c28dc915d92740c2dee311e
|
||||
F test/vtab4.test 942f8b8280b3ea8a41dae20e7822d065ca1cb275
|
||||
F test/vtab5.test 889f444970393c73f1e077e2bdc5d845e157a391
|
||||
F test/vtab6.test 5f5380c425e52993560ab4763db4f826d2ba7b09
|
||||
|
@ -1131,7 +1135,7 @@ F test/whereF.test 5b2ba0dbe8074aa13e416b37c753991f0a2492d7
|
|||
F test/whereG.test 69f5ec4b15760a8c860f80e2d55525669390aab3
|
||||
F test/whereH.test e4b07f7a3c2f5d31195cd33710054c78667573b2
|
||||
F test/whereI.test 1d89199697919d4930be05a71e7fe620f114e622
|
||||
F test/whereJ.test 8880784c211c459595f734a35bcc5f2061fce987
|
||||
F test/whereJ.test 63599653dfefe4e74ebb358db753417fe0aa8a49
|
||||
F test/wherelimit.test 5e9fd41e79bb2b2d588ed999d641d9c965619b31
|
||||
F test/wild001.test bca33f499866f04c24510d74baf1e578d4e44b1c
|
||||
F test/win32heap.test ea19770974795cff26e11575e12d422dbd16893c
|
||||
|
@ -1142,7 +1146,7 @@ F test/with2.test ee227a663586aa09771cafd4fa269c5217eaf775
|
|||
F test/withM.test e97f2a8c506ab3ea9eab94e6f6072f6cc924c991
|
||||
F test/without_rowid1.test 7862e605753c8d25329f665fa09072e842183151
|
||||
F test/without_rowid2.test af260339f79d13cb220288b67cd287fbcf81ad99
|
||||
F test/without_rowid3.test eac3d5c8a1924725b58503a368f2cbd24fd6c8a0
|
||||
F test/without_rowid3.test 1081aabf60a1e1123b7f9a8f6ae19954351843b0
|
||||
F test/without_rowid4.test 4e08bcbaee0399f35d58b5581881e7a6243d458a
|
||||
F test/without_rowid5.test b4a639a367f04d382d20e8f44fc1be4f2d57d107
|
||||
F test/wordcount.c 9915e06cb33d8ca8109b8700791afe80d305afda
|
||||
|
@ -1199,7 +1203,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1
|
|||
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
|
||||
F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32
|
||||
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
|
||||
P 473a72d7009a22ea514a98ee8869e7e7bca14cf5
|
||||
R 6e8944bfcc8da0bf6b98d50ae7beb161
|
||||
P 79f2418429aa05c56069c56d51b4d72f662a6970 69a64560777f85b47349b4b2aab01dc99298592e
|
||||
R 10cbf38158f2f089e176ffb2e809ade0
|
||||
U dan
|
||||
Z 793743aae527be1bb170d7639993b8ad
|
||||
Z c612131a6abb7d1e449d4f88a8b72de0
|
||||
|
|
|
@ -1 +1 @@
|
|||
79f2418429aa05c56069c56d51b4d72f662a6970
|
||||
55b8011d5b455927f5b92a3cb911fd909fb0edab
|
|
@ -174,8 +174,8 @@ static void renameTriggerFunc(
|
|||
UNUSED_PARAMETER(NotUsed);
|
||||
|
||||
/* The principle used to locate the table name in the CREATE TRIGGER
|
||||
** statement is that the table name is the first token that is immediatedly
|
||||
** preceded by either TK_ON or TK_DOT and immediatedly followed by one
|
||||
** statement is that the table name is the first token that is immediately
|
||||
** preceded by either TK_ON or TK_DOT and immediately followed by one
|
||||
** of TK_WHEN, TK_BEGIN or TK_FOR.
|
||||
*/
|
||||
if( zSql ){
|
||||
|
|
|
@ -35,7 +35,7 @@
|
|||
** not possible to enable both STAT3 and STAT4 at the same time. If they
|
||||
** are both enabled, then STAT4 takes precedence.
|
||||
**
|
||||
** For most applications, sqlite_stat1 provides all the statisics required
|
||||
** For most applications, sqlite_stat1 provides all the statistics required
|
||||
** for the query planner to make good choices.
|
||||
**
|
||||
** Format of sqlite_stat1:
|
||||
|
@ -387,7 +387,7 @@ static void stat4Destructor(void *pOld){
|
|||
** original WITHOUT ROWID table as N==K as a special case.
|
||||
**
|
||||
** This routine allocates the Stat4Accum object in heap memory. The return
|
||||
** value is a pointer to the the Stat4Accum object. The datatype of the
|
||||
** value is a pointer to the Stat4Accum object. The datatype of the
|
||||
** return value is BLOB, but it is really just a pointer to the Stat4Accum
|
||||
** object.
|
||||
*/
|
||||
|
@ -1583,7 +1583,7 @@ static void initAvgEq(Index *pIdx){
|
|||
/* Set nSum to the number of distinct (iCol+1) field prefixes that
|
||||
** occur in the stat4 table for this index before pFinal. Set
|
||||
** sumEq to the sum of the nEq values for column iCol for the same
|
||||
** set (adding the value only once where there exist dupicate
|
||||
** set (adding the value only once where there exist duplicate
|
||||
** prefixes). */
|
||||
for(i=0; i<(pIdx->nSample-1); i++){
|
||||
if( aSample[i].anDLt[iCol]!=aSample[i+1].anDLt[iCol] ){
|
||||
|
|
|
@ -207,6 +207,15 @@ static void attachFunc(
|
|||
rc = sqlite3Init(db, &zErrDyn);
|
||||
sqlite3BtreeLeaveAll(db);
|
||||
}
|
||||
#ifdef SQLITE_USER_AUTHENTICATION
|
||||
if( rc==SQLITE_OK ){
|
||||
u8 newAuth = 0;
|
||||
rc = sqlite3UserAuthCheckLogin(db, zName, &newAuth);
|
||||
if( newAuth<db->auth.authLevel ){
|
||||
rc = SQLITE_AUTH_USER;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if( rc ){
|
||||
int iDb = db->nDb - 1;
|
||||
assert( iDb>=2 );
|
||||
|
|
14
src/auth.c
14
src/auth.c
|
@ -73,7 +73,7 @@ int sqlite3_set_authorizer(
|
|||
void *pArg
|
||||
){
|
||||
sqlite3_mutex_enter(db->mutex);
|
||||
db->xAuth = xAuth;
|
||||
db->xAuth = (sqlite3_xauth)xAuth;
|
||||
db->pAuthArg = pArg;
|
||||
sqlite3ExpirePreparedStatements(db);
|
||||
sqlite3_mutex_leave(db->mutex);
|
||||
|
@ -108,7 +108,11 @@ int sqlite3AuthReadCol(
|
|||
char *zDb = db->aDb[iDb].zName; /* Name of attached database */
|
||||
int rc; /* Auth callback return code */
|
||||
|
||||
rc = db->xAuth(db->pAuthArg, SQLITE_READ, zTab,zCol,zDb,pParse->zAuthContext);
|
||||
rc = db->xAuth(db->pAuthArg, SQLITE_READ, zTab,zCol,zDb,pParse->zAuthContext
|
||||
#ifdef SQLITE_USER_AUTHENTICATION
|
||||
,db->auth.zAuthUser
|
||||
#endif
|
||||
);
|
||||
if( rc==SQLITE_DENY ){
|
||||
if( db->nDb>2 || iDb!=0 ){
|
||||
sqlite3ErrorMsg(pParse, "access to %s.%s.%s is prohibited",zDb,zTab,zCol);
|
||||
|
@ -208,7 +212,11 @@ int sqlite3AuthCheck(
|
|||
if( db->xAuth==0 ){
|
||||
return SQLITE_OK;
|
||||
}
|
||||
rc = db->xAuth(db->pAuthArg, code, zArg1, zArg2, zArg3, pParse->zAuthContext);
|
||||
rc = db->xAuth(db->pAuthArg, code, zArg1, zArg2, zArg3, pParse->zAuthContext
|
||||
#ifdef SQLITE_USER_AUTHENTICATION
|
||||
,db->auth.zAuthUser
|
||||
#endif
|
||||
);
|
||||
if( rc==SQLITE_DENY ){
|
||||
sqlite3ErrorMsg(pParse, "not authorized");
|
||||
pParse->rc = SQLITE_AUTH;
|
||||
|
|
|
@ -106,7 +106,7 @@ static void SQLITE_NOINLINE btreeLockCarefully(Btree *p){
|
|||
Btree *pLater;
|
||||
|
||||
/* In most cases, we should be able to acquire the lock we
|
||||
** want without having to go throught the ascending lock
|
||||
** want without having to go through the ascending lock
|
||||
** procedure that follows. Just be sure not to block.
|
||||
*/
|
||||
if( sqlite3_mutex_try(p->pBt->mutex)==SQLITE_OK ){
|
||||
|
|
32
src/btree.c
32
src/btree.c
|
@ -9,7 +9,7 @@
|
|||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
*************************************************************************
|
||||
** This file implements a external (disk-based) database using BTrees.
|
||||
** This file implements an external (disk-based) database using BTrees.
|
||||
** See the header comment on "btreeInt.h" for additional information.
|
||||
** Including a description of file format and an overview of operation.
|
||||
*/
|
||||
|
@ -607,7 +607,7 @@ static int saveCursorPosition(BtCursor *pCur){
|
|||
** data.
|
||||
*/
|
||||
if( 0==pCur->apPage[0]->intKey ){
|
||||
void *pKey = sqlite3Malloc( (int)pCur->nKey );
|
||||
void *pKey = sqlite3Malloc( pCur->nKey );
|
||||
if( pKey ){
|
||||
rc = sqlite3BtreeKey(pCur, 0, (int)pCur->nKey, pKey);
|
||||
if( rc==SQLITE_OK ){
|
||||
|
@ -1145,7 +1145,7 @@ static void ptrmapPutOvflPtr(MemPage *pPage, u8 *pCell, int *pRC){
|
|||
*/
|
||||
static int defragmentPage(MemPage *pPage){
|
||||
int i; /* Loop counter */
|
||||
int pc; /* Address of a i-th cell */
|
||||
int pc; /* Address of the i-th cell */
|
||||
int hdr; /* Offset to the page header */
|
||||
int size; /* Size of a cell */
|
||||
int usableSize; /* Number of usable bytes on a page */
|
||||
|
@ -2602,7 +2602,7 @@ page1_init_failed:
|
|||
** false then all cursors are counted.
|
||||
**
|
||||
** For the purposes of this routine, a cursor is any cursor that
|
||||
** is capable of reading or writing to the databse. Cursors that
|
||||
** is capable of reading or writing to the database. Cursors that
|
||||
** have been tripped into the CURSOR_FAULT state are not counted.
|
||||
*/
|
||||
static int countValidCursors(BtShared *pBt, int wrOnly){
|
||||
|
@ -3066,7 +3066,7 @@ static int allocateBtreePage(BtShared *, MemPage **, Pgno *, Pgno, u8);
|
|||
** calling this function again), return SQLITE_DONE. Or, if an error
|
||||
** occurs, return some other error code.
|
||||
**
|
||||
** More specificly, this function attempts to re-organize the database so
|
||||
** More specifically, this function attempts to re-organize the database so
|
||||
** that the last page of the file currently in use is no longer in use.
|
||||
**
|
||||
** Parameter nFin is the number of pages that this database would contain
|
||||
|
@ -3074,7 +3074,7 @@ static int allocateBtreePage(BtShared *, MemPage **, Pgno *, Pgno, u8);
|
|||
**
|
||||
** If the bCommit parameter is non-zero, this function assumes that the
|
||||
** caller will keep calling incrVacuumStep() until it returns SQLITE_DONE
|
||||
** or an error. bCommit is passed true for an auto-vacuum-on-commmit
|
||||
** or an error. bCommit is passed true for an auto-vacuum-on-commit
|
||||
** operation, or false for an incremental vacuum.
|
||||
*/
|
||||
static int incrVacuumStep(BtShared *pBt, Pgno nFin, Pgno iLastPg, int bCommit){
|
||||
|
@ -3541,7 +3541,7 @@ int sqlite3BtreeRollback(Btree *p, int tripCode){
|
|||
}
|
||||
|
||||
/*
|
||||
** Start a statement subtransaction. The subtransaction can can be rolled
|
||||
** Start a statement subtransaction. The subtransaction can be rolled
|
||||
** back independently of the main transaction. You must start a transaction
|
||||
** before starting a subtransaction. The subtransaction is ended automatically
|
||||
** if the main transaction commits or rolls back.
|
||||
|
@ -3775,7 +3775,7 @@ int sqlite3BtreeCloseCursor(BtCursor *pCur){
|
|||
** compiler to crash when getCellInfo() is implemented as a macro.
|
||||
** But there is a measureable speed advantage to using the macro on gcc
|
||||
** (when less compiler optimizations like -Os or -O0 are used and the
|
||||
** compiler is not doing agressive inlining.) So we use a real function
|
||||
** compiler is not doing aggressive inlining.) So we use a real function
|
||||
** for MSVC and a macro for everything else. Ticket #2457.
|
||||
*/
|
||||
#ifndef NDEBUG
|
||||
|
@ -3992,7 +3992,7 @@ static int copyPayload(
|
|||
**
|
||||
** If the current cursor entry uses one or more overflow pages and the
|
||||
** eOp argument is not 2, this function may allocate space for and lazily
|
||||
** popluates the overflow page-list cache array (BtCursor.aOverflow).
|
||||
** populates the overflow page-list cache array (BtCursor.aOverflow).
|
||||
** Subsequent calls use this cache to make seeking to the supplied offset
|
||||
** more efficient.
|
||||
**
|
||||
|
@ -4194,7 +4194,7 @@ static int accessPayload(
|
|||
|
||||
/*
|
||||
** Read part of the key associated with cursor pCur. Exactly
|
||||
** "amt" bytes will be transfered into pBuf[]. The transfer
|
||||
** "amt" bytes will be transferred into pBuf[]. The transfer
|
||||
** begins at "offset".
|
||||
**
|
||||
** The caller must ensure that pCur is pointing to a valid row
|
||||
|
@ -5890,7 +5890,7 @@ static void insertCell(
|
|||
** The cells are guaranteed to fit on the page.
|
||||
*/
|
||||
static void assemblePage(
|
||||
MemPage *pPage, /* The page to be assemblied */
|
||||
MemPage *pPage, /* The page to be assembled */
|
||||
int nCell, /* The number of cells to add to this page */
|
||||
u8 **apCell, /* Pointers to cell bodies */
|
||||
u16 *aSize /* Sizes of the cells */
|
||||
|
@ -6556,7 +6556,7 @@ static int balance_nonroot(
|
|||
}
|
||||
|
||||
/*
|
||||
** Put the new pages in accending order. This helps to
|
||||
** Put the new pages in ascending order. This helps to
|
||||
** keep entries in the disk file in order so that a scan
|
||||
** of the table is a linear scan through the file. That
|
||||
** in turn helps the operating system to deliver pages
|
||||
|
@ -6951,7 +6951,7 @@ static int balance(BtCursor *pCur){
|
|||
/* Call balance_quick() to create a new sibling of pPage on which
|
||||
** to store the overflow cell. balance_quick() inserts a new cell
|
||||
** into pParent, which may cause pParent overflow. If this
|
||||
** happens, the next interation of the do-loop will balance pParent
|
||||
** happens, the next iteration of the do-loop will balance pParent
|
||||
** use either balance_nonroot() or balance_deeper(). Until this
|
||||
** happens, the overflow cell is stored in the aBalanceQuickSpace[]
|
||||
** buffer.
|
||||
|
@ -7028,7 +7028,7 @@ static int balance(BtCursor *pCur){
|
|||
** MovetoUnpacked() to seek cursor pCur to (pKey, nKey) has already
|
||||
** been performed. seekResult is the search result returned (a negative
|
||||
** number if pCur points at an entry that is smaller than (pKey, nKey), or
|
||||
** a positive value if pCur points at an etry that is larger than
|
||||
** a positive value if pCur points at an entry that is larger than
|
||||
** (pKey, nKey)).
|
||||
**
|
||||
** If the seekResult parameter is non-zero, then the caller guarantees that
|
||||
|
@ -7185,7 +7185,7 @@ end_insert:
|
|||
|
||||
/*
|
||||
** Delete the entry that the cursor is pointing to. The cursor
|
||||
** is left pointing at a arbitrary location.
|
||||
** is left pointing at an arbitrary location.
|
||||
*/
|
||||
int sqlite3BtreeDelete(BtCursor *pCur){
|
||||
Btree *p = pCur->pBtree;
|
||||
|
@ -7883,7 +7883,7 @@ static void setPageReferenced(IntegrityCk *pCheck, Pgno iPg){
|
|||
/*
|
||||
** Add 1 to the reference count for page iPage. If this is the second
|
||||
** reference to the page, add an error message to pCheck->zErrMsg.
|
||||
** Return 1 if there are 2 ore more references to the page and 0 if
|
||||
** Return 1 if there are 2 or more references to the page and 0 if
|
||||
** if this is the first reference to the page.
|
||||
**
|
||||
** Also check that the page number is in bounds.
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
*************************************************************************
|
||||
** This file implements a external (disk-based) database using BTrees.
|
||||
** This file implements an external (disk-based) database using BTrees.
|
||||
** For a detailed discussion of BTrees, refer to
|
||||
**
|
||||
** Donald E. Knuth, THE ART OF COMPUTER PROGRAMMING, Volume 3:
|
||||
|
@ -135,7 +135,7 @@
|
|||
**
|
||||
** The flags define the format of this btree page. The leaf flag means that
|
||||
** this page has no children. The zerodata flag means that this page carries
|
||||
** only keys and no data. The intkey flag means that the key is a integer
|
||||
** only keys and no data. The intkey flag means that the key is an integer
|
||||
** which is stored in the key size entry of the cell header rather than in
|
||||
** the payload area.
|
||||
**
|
||||
|
@ -544,7 +544,7 @@ struct BtCursor {
|
|||
** seek the cursor to the saved position.
|
||||
**
|
||||
** CURSOR_FAULT:
|
||||
** A unrecoverable error (an I/O error or a malloc failure) has occurred
|
||||
** An unrecoverable error (an I/O error or a malloc failure) has occurred
|
||||
** on a different connection that shares the BtShared cache with this
|
||||
** cursor. The error has left the cache in an inconsistent state.
|
||||
** Do nothing else with this cursor. Any attempt to use the cursor
|
||||
|
|
50
src/build.c
50
src/build.c
|
@ -156,6 +156,17 @@ void sqlite3FinishCoding(Parse *pParse){
|
|||
while( sqlite3VdbeDeletePriorOpcode(v, OP_Close) ){}
|
||||
sqlite3VdbeAddOp0(v, OP_Halt);
|
||||
|
||||
#if SQLITE_USER_AUTHENTICATION
|
||||
if( pParse->nTableLock>0 && db->init.busy==0 ){
|
||||
sqlite3UserAuthInit(db);
|
||||
if( db->auth.authLevel<UAUTH_User ){
|
||||
pParse->rc = SQLITE_AUTH_USER;
|
||||
sqlite3ErrorMsg(pParse, "user not authenticated");
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* The cookie mask contains one bit for each database file open.
|
||||
** (Bit 0 is for main, bit 1 is for temp, and so forth.) Bits are
|
||||
** set for each database that is used. Generate code to start a
|
||||
|
@ -271,6 +282,16 @@ void sqlite3NestedParse(Parse *pParse, const char *zFormat, ...){
|
|||
pParse->nested--;
|
||||
}
|
||||
|
||||
#if SQLITE_USER_AUTHENTICATION
|
||||
/*
|
||||
** Return TRUE if zTable is the name of the system table that stores the
|
||||
** list of users and their access credentials.
|
||||
*/
|
||||
int sqlite3UserAuthTable(const char *zTable){
|
||||
return sqlite3_stricmp(zTable, "sqlite_user")==0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Locate the in-memory structure that describes a particular database
|
||||
** table given the name of that table and (optionally) the name of the
|
||||
|
@ -289,6 +310,13 @@ Table *sqlite3FindTable(sqlite3 *db, const char *zName, const char *zDatabase){
|
|||
assert( zName!=0 );
|
||||
/* All mutexes are required for schema access. Make sure we hold them. */
|
||||
assert( zDatabase!=0 || sqlite3BtreeHoldsAllMutexes(db) );
|
||||
#if SQLITE_USER_AUTHENTICATION
|
||||
/* Only the admin user is allowed to know that the sqlite_user table
|
||||
** exists */
|
||||
if( db->auth.authLevel<UAUTH_Admin && sqlite3UserAuthTable(zName)!=0 ){
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
for(i=OMIT_TEMPDB; i<db->nDb; i++){
|
||||
int j = (i<2) ? i^1 : i; /* Search TEMP before MAIN */
|
||||
if( zDatabase!=0 && sqlite3StrICmp(zDatabase, db->aDb[j].zName) ) continue;
|
||||
|
@ -333,6 +361,12 @@ Table *sqlite3LocateTable(
|
|||
}
|
||||
pParse->checkSchema = 1;
|
||||
}
|
||||
#if SQLITE_USER_AUTHENICATION
|
||||
else if( pParse->db->auth.authLevel<UAUTH_User ){
|
||||
sqlite3ErrorMsg(pParse, "user not authenticated");
|
||||
p = 0;
|
||||
}
|
||||
#endif
|
||||
return p;
|
||||
}
|
||||
|
||||
|
@ -1619,7 +1653,7 @@ static int hasColumn(const i16 *aiCol, int nCol, int x){
|
|||
** no rowid btree for a WITHOUT ROWID. Instead, the canonical
|
||||
** data storage is a covering index btree.
|
||||
** (2) Bypass the creation of the sqlite_master table entry
|
||||
** for the PRIMARY KEY as the the primary key index is now
|
||||
** for the PRIMARY KEY as the primary key index is now
|
||||
** identified by the sqlite_master table entry of the table itself.
|
||||
** (3) Set the Index.tnum of the PRIMARY KEY Index object in the
|
||||
** schema to the rootpage from the main table.
|
||||
|
@ -1640,7 +1674,7 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){
|
|||
Vdbe *v = pParse->pVdbe;
|
||||
|
||||
/* Convert the OP_CreateTable opcode that would normally create the
|
||||
** root-page for the table into a OP_CreateIndex opcode. The index
|
||||
** root-page for the table into an OP_CreateIndex opcode. The index
|
||||
** created will become the PRIMARY KEY index.
|
||||
*/
|
||||
if( pParse->addrCrTab ){
|
||||
|
@ -2052,7 +2086,7 @@ int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){
|
|||
int nErr = 0; /* Number of errors encountered */
|
||||
int n; /* Temporarily holds the number of cursors assigned */
|
||||
sqlite3 *db = pParse->db; /* Database connection for malloc errors */
|
||||
int (*xAuth)(void*,int,const char*,const char*,const char*,const char*);
|
||||
sqlite3_xauth xAuth; /* Saved xAuth pointer */
|
||||
|
||||
assert( pTable );
|
||||
|
||||
|
@ -2654,7 +2688,7 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){
|
|||
int iPartIdxLabel; /* Jump to this label to skip a row */
|
||||
Vdbe *v; /* Generate code into this virtual machine */
|
||||
KeyInfo *pKey; /* KeyInfo for index */
|
||||
int regRecord; /* Register holding assemblied index record */
|
||||
int regRecord; /* Register holding assembled index record */
|
||||
sqlite3 *db = pParse->db; /* The database connection */
|
||||
int iDb = sqlite3SchemaToIndex(db, pIndex->pSchema);
|
||||
|
||||
|
@ -2867,6 +2901,10 @@ Index *sqlite3CreateIndex(
|
|||
assert( pTab!=0 );
|
||||
assert( pParse->nErr==0 );
|
||||
if( sqlite3StrNICmp(pTab->zName, "sqlite_", 7)==0
|
||||
&& db->init.busy==0
|
||||
#if SQLITE_USER_AUTHENTICATION
|
||||
&& sqlite3UserAuthTable(pTab->zName)==0
|
||||
#endif
|
||||
&& sqlite3StrNICmp(&pTab->zName[7],"altertab_",9)!=0 ){
|
||||
sqlite3ErrorMsg(pParse, "table %s may not be indexed", pTab->zName);
|
||||
goto exit_create_index;
|
||||
|
@ -3254,7 +3292,7 @@ exit_create_index:
|
|||
** Fill the Index.aiRowEst[] array with default information - information
|
||||
** to be used when we have not run the ANALYZE command.
|
||||
**
|
||||
** aiRowEst[0] is suppose to contain the number of elements in the index.
|
||||
** aiRowEst[0] is supposed to contain the number of elements in the index.
|
||||
** Since we do not know, guess 1 million. aiRowEst[1] is an estimate of the
|
||||
** number of rows in the table that match any particular value of the
|
||||
** first column of the index. aiRowEst[2] is an estimate of the number
|
||||
|
@ -3633,7 +3671,7 @@ void sqlite3SrcListDelete(sqlite3 *db, SrcList *pList){
|
|||
** if this is the first term of the FROM clause. pTable and pDatabase
|
||||
** are the name of the table and database named in the FROM clause term.
|
||||
** pDatabase is NULL if the database name qualifier is missing - the
|
||||
** usual case. If the term has a alias, then pAlias points to the
|
||||
** usual case. If the term has an alias, then pAlias points to the
|
||||
** alias token. If the term is a subquery, then pSubquery is the
|
||||
** SELECT statement that the subquery encodes. The pTable and
|
||||
** pDatabase parameters are NULL for subqueries. The pOn and pUsing
|
||||
|
|
|
@ -142,7 +142,7 @@ int sqlite3CheckCollSeq(Parse *pParse, CollSeq *pColl){
|
|||
**
|
||||
** Each pointer stored in the sqlite3.aCollSeq hash table contains an
|
||||
** array of three CollSeq structures. The first is the collation sequence
|
||||
** prefferred for UTF-8, the second UTF-16le, and the third UTF-16be.
|
||||
** preferred for UTF-8, the second UTF-16le, and the third UTF-16be.
|
||||
**
|
||||
** Stored immediately after the three collation sequences is a copy of
|
||||
** the collation sequence name. A pointer to this string is stored in
|
||||
|
|
|
@ -70,7 +70,7 @@ extern const char sqlite3IsEbcdicIdChar[];
|
|||
** a statement.
|
||||
**
|
||||
** (4) CREATE The keyword CREATE has been seen at the beginning of a
|
||||
** statement, possibly preceeded by EXPLAIN and/or followed by
|
||||
** statement, possibly preceded by EXPLAIN and/or followed by
|
||||
** TEMP or TEMPORARY
|
||||
**
|
||||
** (5) TRIGGER We are in the middle of a trigger definition that must be
|
||||
|
@ -80,7 +80,7 @@ extern const char sqlite3IsEbcdicIdChar[];
|
|||
** the end of a trigger definition.
|
||||
**
|
||||
** (7) END We've seen the ";END" of the ";END;" that occurs at the end
|
||||
** of a trigger difinition.
|
||||
** of a trigger definition.
|
||||
**
|
||||
** Transitions between states above are determined by tokens extracted
|
||||
** from the input. The following tokens are significant:
|
||||
|
@ -123,7 +123,7 @@ int sqlite3_complete(const char *zSql){
|
|||
};
|
||||
#else
|
||||
/* If triggers are not supported by this compile then the statement machine
|
||||
** used to detect the end of a statement is much simplier
|
||||
** used to detect the end of a statement is much simpler
|
||||
*/
|
||||
static const u8 trans[3][3] = {
|
||||
/* Token: */
|
||||
|
|
|
@ -368,6 +368,9 @@ static const char * const azCompileOpt[] = {
|
|||
#ifdef SQLITE_USE_ALLOCA
|
||||
"USE_ALLOCA",
|
||||
#endif
|
||||
#ifdef SQLITE_USER_AUTHENTICATION
|
||||
"USER_AUTHENTICATION",
|
||||
#endif
|
||||
#ifdef SQLITE_WIN32_MALLOC
|
||||
"WIN32_MALLOC",
|
||||
#endif
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
** 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
|
||||
** This implementation 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.
|
||||
|
|
10
src/delete.c
10
src/delete.c
|
@ -90,7 +90,7 @@ void sqlite3MaterializeView(
|
|||
Parse *pParse, /* Parsing context */
|
||||
Table *pView, /* View definition */
|
||||
Expr *pWhere, /* Optional WHERE clause to be added */
|
||||
int iCur /* Cursor number for ephemerial table */
|
||||
int iCur /* Cursor number for ephemeral table */
|
||||
){
|
||||
SelectDest dest;
|
||||
Select *pSel;
|
||||
|
@ -248,7 +248,7 @@ void sqlite3DeleteFrom(
|
|||
int addrBypass = 0; /* Address of jump over the delete logic */
|
||||
int addrLoop = 0; /* Top of the delete loop */
|
||||
int addrDelete = 0; /* Jump directly to the delete logic */
|
||||
int addrEphOpen = 0; /* Instruction to open the Ephermeral table */
|
||||
int addrEphOpen = 0; /* Instruction to open the Ephemeral table */
|
||||
|
||||
#ifndef SQLITE_OMIT_TRIGGER
|
||||
int isView; /* True if attempting to delete from a view */
|
||||
|
@ -328,7 +328,7 @@ void sqlite3DeleteFrom(
|
|||
sqlite3BeginWriteOperation(pParse, 1, iDb);
|
||||
|
||||
/* If we are trying to delete from a view, realize that view into
|
||||
** a ephemeral table.
|
||||
** an ephemeral table.
|
||||
*/
|
||||
#if !defined(SQLITE_OMIT_VIEW) && !defined(SQLITE_OMIT_TRIGGER)
|
||||
if( isView ){
|
||||
|
@ -382,7 +382,7 @@ void sqlite3DeleteFrom(
|
|||
iRowSet = ++pParse->nMem;
|
||||
sqlite3VdbeAddOp2(v, OP_Null, 0, iRowSet);
|
||||
}else{
|
||||
/* For a WITHOUT ROWID table, create an ephermeral table used to
|
||||
/* For a WITHOUT ROWID table, create an ephemeral table used to
|
||||
** hold all primary keys for rows to be deleted. */
|
||||
pPk = sqlite3PrimaryKeyIndex(pTab);
|
||||
assert( pPk!=0 );
|
||||
|
@ -557,7 +557,7 @@ delete_from_cleanup:
|
|||
return;
|
||||
}
|
||||
/* Make sure "isView" and other macros defined above are undefined. Otherwise
|
||||
** thely may interfere with compilation of other functions in this file
|
||||
** they may interfere with compilation of other functions in this file
|
||||
** (or in another file, if this file becomes part of the amalgamation). */
|
||||
#ifdef isView
|
||||
#undef isView
|
||||
|
|
31
src/expr.c
31
src/expr.c
|
@ -22,7 +22,7 @@
|
|||
** affinity of that column is returned. Otherwise, 0x00 is returned,
|
||||
** indicating no affinity for the expression.
|
||||
**
|
||||
** i.e. the WHERE clause expresssions in the following statements all
|
||||
** i.e. the WHERE clause expressions in the following statements all
|
||||
** have an affinity:
|
||||
**
|
||||
** CREATE TABLE t1(a);
|
||||
|
@ -501,7 +501,7 @@ void sqlite3ExprAttachSubtrees(
|
|||
}
|
||||
|
||||
/*
|
||||
** Allocate a Expr node which joins as many as two subtrees.
|
||||
** Allocate an Expr node which joins as many as two subtrees.
|
||||
**
|
||||
** One or both of the subtrees can be NULL. Return a pointer to the new
|
||||
** Expr node. Or, if an OOM error occurs, set pParse->db->mallocFailed,
|
||||
|
@ -611,7 +611,7 @@ Expr *sqlite3ExprFunction(Parse *pParse, ExprList *pList, Token *pToken){
|
|||
**
|
||||
** Wildcards of the form ":aaa", "@aaa", or "$aaa" are assigned the same number
|
||||
** as the previous instance of the same wildcard. Or if this is the first
|
||||
** instance of the wildcard, the next sequenial variable number is
|
||||
** instance of the wildcard, the next sequential variable number is
|
||||
** assigned.
|
||||
*/
|
||||
void sqlite3ExprAssignVarNumber(Parse *pParse, Expr *pExpr){
|
||||
|
@ -746,7 +746,7 @@ static int exprStructSize(Expr *p){
|
|||
** During expression analysis, extra information is computed and moved into
|
||||
** later parts of teh Expr object and that extra information might get chopped
|
||||
** off if the expression is reduced. Note also that it does not work to
|
||||
** make a EXPRDUP_REDUCE copy of a reduced expression. It is only legal
|
||||
** make an EXPRDUP_REDUCE copy of a reduced expression. It is only legal
|
||||
** to reduce a pristine expression tree from the parser. The implementation
|
||||
** of dupedExprStructSize() contain multiple assert() statements that attempt
|
||||
** to enforce this constraint.
|
||||
|
@ -815,7 +815,7 @@ static int dupedExprSize(Expr *p, int flags){
|
|||
** is not NULL then *pzBuffer is assumed to point to a buffer large enough
|
||||
** to store the copy of expression p, the copies of p->u.zToken
|
||||
** (if applicable), and the copies of the p->pLeft and p->pRight expressions,
|
||||
** if any. Before returning, *pzBuffer is set to the first byte passed the
|
||||
** if any. Before returning, *pzBuffer is set to the first byte past the
|
||||
** portion of the buffer copied into by this function.
|
||||
*/
|
||||
static Expr *exprDup(sqlite3 *db, Expr *p, int flags, u8 **pzBuffer){
|
||||
|
@ -1541,7 +1541,7 @@ static int sqlite3InRhsIsConstant(Expr *pIn){
|
|||
**
|
||||
** If the RHS of the IN operator is a list or a more complex subquery, then
|
||||
** an ephemeral table might need to be generated from the RHS and then
|
||||
** pX->iTable made to point to the ephermeral table instead of an
|
||||
** pX->iTable made to point to the ephemeral table instead of an
|
||||
** existing table.
|
||||
**
|
||||
** The inFlags parameter must contain exactly one of the bits
|
||||
|
@ -1671,7 +1671,7 @@ int sqlite3FindInIndex(Parse *pParse, Expr *pX, u32 inFlags, int *prRhsHasNull){
|
|||
** and IN_INDEX_NOOP is an allowed reply
|
||||
** and the RHS of the IN operator is a list, not a subquery
|
||||
** and the RHS is not contant or has two or fewer terms,
|
||||
** then it is not worth creating an ephermeral table to evaluate
|
||||
** then it is not worth creating an ephemeral table to evaluate
|
||||
** the IN operator so return IN_INDEX_NOOP.
|
||||
*/
|
||||
if( eType==0
|
||||
|
@ -2432,16 +2432,9 @@ void sqlite3ExprCacheAffinityChange(Parse *pParse, int iStart, int iCount){
|
|||
** over to iTo..iTo+nReg-1. Keep the column cache up-to-date.
|
||||
*/
|
||||
void sqlite3ExprCodeMove(Parse *pParse, int iFrom, int iTo, int nReg){
|
||||
int i;
|
||||
struct yColCache *p;
|
||||
assert( iFrom>=iTo+nReg || iFrom+nReg<=iTo );
|
||||
sqlite3VdbeAddOp3(pParse->pVdbe, OP_Move, iFrom, iTo, nReg);
|
||||
for(i=0, p=pParse->aColCache; i<SQLITE_N_COLCACHE; i++, p++){
|
||||
int x = p->iReg;
|
||||
if( x>=iFrom && x<iFrom+nReg ){
|
||||
p->iReg += iTo-iFrom;
|
||||
}
|
||||
}
|
||||
sqlite3ExprCacheRemove(pParse, iFrom, nReg);
|
||||
}
|
||||
|
||||
#if defined(SQLITE_DEBUG) || defined(SQLITE_COVERAGE_TEST)
|
||||
|
@ -2758,7 +2751,7 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
|
|||
}
|
||||
|
||||
/* Attempt a direct implementation of the built-in COALESCE() and
|
||||
** IFNULL() functions. This avoids unnecessary evalation of
|
||||
** IFNULL() functions. This avoids unnecessary evaluation of
|
||||
** arguments past the first non-NULL argument.
|
||||
*/
|
||||
if( pDef->funcFlags & SQLITE_FUNC_COALESCE ){
|
||||
|
@ -3197,7 +3190,7 @@ void sqlite3ExprCodeFactorable(Parse *pParse, Expr *pExpr, int target){
|
|||
}
|
||||
|
||||
/*
|
||||
** Generate code that evalutes the given expression and puts the result
|
||||
** Generate code that evaluates the given expression and puts the result
|
||||
** in register target.
|
||||
**
|
||||
** Also make a copy of the expression results into another "cache" register
|
||||
|
@ -3552,7 +3545,7 @@ int sqlite3ExprCodeExprList(
|
|||
** x>=y AND x<=z
|
||||
**
|
||||
** Code it as such, taking care to do the common subexpression
|
||||
** elementation of x.
|
||||
** elimination of x.
|
||||
*/
|
||||
static void exprCodeBetween(
|
||||
Parse *pParse, /* Parsing and code generating context */
|
||||
|
@ -4289,7 +4282,7 @@ int sqlite3GetTempReg(Parse *pParse){
|
|||
** purpose.
|
||||
**
|
||||
** If a register is currently being used by the column cache, then
|
||||
** the dallocation is deferred until the column cache line that uses
|
||||
** the deallocation is deferred until the column cache line that uses
|
||||
** the register becomes stale.
|
||||
*/
|
||||
void sqlite3ReleaseTempReg(Parse *pParse, int iReg){
|
||||
|
|
|
@ -173,7 +173,7 @@
|
|||
**
|
||||
** 4) No parent key columns were provided explicitly as part of the
|
||||
** foreign key definition, and the PRIMARY KEY of the parent table
|
||||
** consists of a a different number of columns to the child key in
|
||||
** consists of a different number of columns to the child key in
|
||||
** the child table.
|
||||
**
|
||||
** then non-zero is returned, and a "foreign key mismatch" error loaded
|
||||
|
|
26
src/func.c
26
src/func.c
|
@ -9,7 +9,7 @@
|
|||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
*************************************************************************
|
||||
** This file contains the C-language implementions for many of the SQL
|
||||
** This file contains the C-language implementations for many of the SQL
|
||||
** functions of SQLite. (Some function, and in particular the date and
|
||||
** time functions, are implemented separately.)
|
||||
*/
|
||||
|
@ -325,13 +325,14 @@ static void substrFunc(
|
|||
for(z2=z; *z2 && p2; p2--){
|
||||
SQLITE_SKIP_UTF8(z2);
|
||||
}
|
||||
sqlite3_result_text(context, (char*)z, (int)(z2-z), SQLITE_TRANSIENT);
|
||||
sqlite3_result_text64(context, (char*)z, z2-z, SQLITE_TRANSIENT,
|
||||
SQLITE_UTF8);
|
||||
}else{
|
||||
if( p1+p2>len ){
|
||||
p2 = len-p1;
|
||||
if( p2<0 ) p2 = 0;
|
||||
}
|
||||
sqlite3_result_blob(context, (char*)&z[p1], (int)p2, SQLITE_TRANSIENT);
|
||||
sqlite3_result_blob64(context, (char*)&z[p1], (u64)p2, SQLITE_TRANSIENT);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -390,7 +391,7 @@ static void *contextMalloc(sqlite3_context *context, i64 nByte){
|
|||
sqlite3_result_error_toobig(context);
|
||||
z = 0;
|
||||
}else{
|
||||
z = sqlite3Malloc((int)nByte);
|
||||
z = sqlite3Malloc(nByte);
|
||||
if( !z ){
|
||||
sqlite3_result_error_nomem(context);
|
||||
}
|
||||
|
@ -1041,7 +1042,7 @@ static void charFunc(
|
|||
*zOut++ = 0x80 + (u8)(c & 0x3F);
|
||||
} \
|
||||
}
|
||||
sqlite3_result_text(context, (char*)z, (int)(zOut-z), sqlite3_free);
|
||||
sqlite3_result_text64(context, (char*)z, zOut-z, sqlite3_free, SQLITE_UTF8);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1638,7 +1639,7 @@ int sqlite3IsLikeFunction(sqlite3 *db, Expr *pExpr, int *pIsNocase, char *aWc){
|
|||
}
|
||||
|
||||
/*
|
||||
** All all of the FuncDef structures in the aBuiltinFunc[] array above
|
||||
** All of the FuncDef structures in the aBuiltinFunc[] array above
|
||||
** to the global function hash table. This occurs at start-time (as
|
||||
** a consequence of calling sqlite3_initialize()).
|
||||
**
|
||||
|
@ -1662,10 +1663,12 @@ void sqlite3RegisterGlobalFunctions(void){
|
|||
FUNCTION(trim, 2, 3, 0, trimFunc ),
|
||||
FUNCTION(min, -1, 0, 1, minmaxFunc ),
|
||||
FUNCTION(min, 0, 0, 1, 0 ),
|
||||
AGGREGATE(min, 1, 0, 1, minmaxStep, minMaxFinalize ),
|
||||
AGGREGATE2(min, 1, 0, 1, minmaxStep, minMaxFinalize,
|
||||
SQLITE_FUNC_MINMAX ),
|
||||
FUNCTION(max, -1, 1, 1, minmaxFunc ),
|
||||
FUNCTION(max, 0, 1, 1, 0 ),
|
||||
AGGREGATE(max, 1, 1, 1, minmaxStep, minMaxFinalize ),
|
||||
AGGREGATE2(max, 1, 1, 1, minmaxStep, minMaxFinalize,
|
||||
SQLITE_FUNC_MINMAX ),
|
||||
FUNCTION2(typeof, 1, 0, 0, typeofFunc, SQLITE_FUNC_TYPEOF),
|
||||
FUNCTION2(length, 1, 0, 0, lengthFunc, SQLITE_FUNC_LENGTH),
|
||||
FUNCTION(instr, 2, 0, 0, instrFunc ),
|
||||
|
@ -1695,6 +1698,9 @@ void sqlite3RegisterGlobalFunctions(void){
|
|||
FUNCTION(sqlite_version, 0, 0, 0, versionFunc ),
|
||||
FUNCTION(sqlite_source_id, 0, 0, 0, sourceidFunc ),
|
||||
FUNCTION(sqlite_log, 2, 0, 0, errlogFunc ),
|
||||
#if SQLITE_USER_AUTHENTICATION
|
||||
FUNCTION(sqlite_crypt, 2, 0, 0, sqlite3CryptFunc ),
|
||||
#endif
|
||||
#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS
|
||||
FUNCTION(sqlite_compileoption_used,1, 0, 0, compileoptionusedFunc ),
|
||||
FUNCTION(sqlite_compileoption_get, 1, 0, 0, compileoptiongetFunc ),
|
||||
|
@ -1715,8 +1721,8 @@ void sqlite3RegisterGlobalFunctions(void){
|
|||
AGGREGATE(sum, 1, 0, 0, sumStep, sumFinalize ),
|
||||
AGGREGATE(total, 1, 0, 0, sumStep, totalFinalize ),
|
||||
AGGREGATE(avg, 1, 0, 0, sumStep, avgFinalize ),
|
||||
/* AGGREGATE(count, 0, 0, 0, countStep, countFinalize ), */
|
||||
{0,SQLITE_UTF8|SQLITE_FUNC_COUNT,0,0,0,countStep,countFinalize,"count",0,0},
|
||||
AGGREGATE2(count, 0, 0, 0, countStep, countFinalize,
|
||||
SQLITE_FUNC_COUNT ),
|
||||
AGGREGATE(count, 1, 0, 0, countStep, countFinalize ),
|
||||
AGGREGATE(group_concat, 1, 0, 0, groupConcatStep, groupConcatFinalize),
|
||||
AGGREGATE(group_concat, 2, 0, 0, groupConcatStep, groupConcatFinalize),
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
**
|
||||
*************************************************************************
|
||||
**
|
||||
** This file contains definitions of global variables and contants.
|
||||
** This file contains definitions of global variables and constants.
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
|
||||
|
|
14
src/insert.c
14
src/insert.c
|
@ -410,7 +410,7 @@ static int xferOptimization(
|
|||
** The 4th template is used if the insert statement takes its
|
||||
** values from a SELECT but the data is being inserted into a table
|
||||
** that is also read as part of the SELECT. In the third form,
|
||||
** we have to use a intermediate table to store the results of
|
||||
** we have to use an intermediate table to store the results of
|
||||
** the select. The template is like this:
|
||||
**
|
||||
** X <- A
|
||||
|
@ -575,7 +575,7 @@ void sqlite3Insert(
|
|||
regAutoinc = autoIncBegin(pParse, iDb, pTab);
|
||||
|
||||
/* Allocate registers for holding the rowid of the new row,
|
||||
** the content of the new row, and the assemblied row record.
|
||||
** the content of the new row, and the assembled row record.
|
||||
*/
|
||||
regRowid = regIns = pParse->nMem+1;
|
||||
pParse->nMem += pTab->nCol + 1;
|
||||
|
@ -1027,7 +1027,7 @@ insert_cleanup:
|
|||
}
|
||||
|
||||
/* Make sure "isView" and other macros defined above are undefined. Otherwise
|
||||
** thely may interfere with compilation of other functions in this file
|
||||
** they may interfere with compilation of other functions in this file
|
||||
** (or in another file, if this file becomes part of the amalgamation). */
|
||||
#ifdef isView
|
||||
#undef isView
|
||||
|
@ -1143,7 +1143,7 @@ void sqlite3GenerateConstraintChecks(
|
|||
int ix; /* Index loop counter */
|
||||
int nCol; /* Number of columns */
|
||||
int onError; /* Conflict resolution strategy */
|
||||
int j1; /* Addresss of jump instruction */
|
||||
int j1; /* Address of jump instruction */
|
||||
int seenReplace = 0; /* True if REPLACE is used to resolve INT PK conflict */
|
||||
int nPkField; /* Number of fields in PRIMARY KEY. 1 for ROWID tables */
|
||||
int ipkTop = 0; /* Top of the rowid change constraint check */
|
||||
|
@ -1551,7 +1551,7 @@ void sqlite3CompleteInsertion(
|
|||
Index *pIdx; /* An index being inserted or updated */
|
||||
u8 pik_flags; /* flag values passed to the btree insert */
|
||||
int regData; /* Content registers (after the rowid) */
|
||||
int regRec; /* Register holding assemblied record for the table */
|
||||
int regRec; /* Register holding assembled record for the table */
|
||||
int i; /* Loop counter */
|
||||
u8 bAffinityDone = 0; /* True if OP_Affinity has been run already */
|
||||
|
||||
|
@ -1685,7 +1685,7 @@ int sqlite3OpenTableAndIndices(
|
|||
** The following global variable is incremented whenever the
|
||||
** transfer optimization is used. This is used for testing
|
||||
** purposes only - to make sure the transfer optimization really
|
||||
** is happening when it is suppose to.
|
||||
** is happening when it is supposed to.
|
||||
*/
|
||||
int sqlite3_xferopt_count;
|
||||
#endif /* SQLITE_TEST */
|
||||
|
@ -1752,7 +1752,7 @@ static int xferCompatibleIndex(Index *pDest, Index *pSrc){
|
|||
** INSERT INTO tab1 SELECT * FROM tab2;
|
||||
**
|
||||
** The xfer optimization transfers raw records from tab2 over to tab1.
|
||||
** Columns are not decoded and reassemblied, which greatly improves
|
||||
** Columns are not decoded and reassembled, which greatly improves
|
||||
** performance. Raw index records are transferred in the same way.
|
||||
**
|
||||
** The xfer optimization is only attempted if tab1 and tab2 are compatible.
|
||||
|
|
|
@ -125,7 +125,7 @@ exec_out:
|
|||
sqlite3DbFree(db, azCols);
|
||||
|
||||
rc = sqlite3ApiExit(db, rc);
|
||||
if( rc!=SQLITE_OK && ALWAYS(rc==sqlite3_errcode(db)) && pzErrMsg ){
|
||||
if( rc!=SQLITE_OK && pzErrMsg ){
|
||||
int nErrMsg = 1 + sqlite3Strlen30(sqlite3_errmsg(db));
|
||||
*pzErrMsg = sqlite3Malloc(nErrMsg);
|
||||
if( *pzErrMsg ){
|
||||
|
|
|
@ -271,9 +271,9 @@ static void yyGrowStack(yyParser *p){
|
|||
** A pointer to a parser. This pointer is used in subsequent calls
|
||||
** to Parse and ParseFree.
|
||||
*/
|
||||
void *ParseAlloc(void *(*mallocProc)(size_t)){
|
||||
void *ParseAlloc(void *(*mallocProc)(u64)){
|
||||
yyParser *pParser;
|
||||
pParser = (yyParser*)(*mallocProc)( (size_t)sizeof(yyParser) );
|
||||
pParser = (yyParser*)(*mallocProc)( (u64)sizeof(yyParser) );
|
||||
if( pParser ){
|
||||
pParser->yyidx = -1;
|
||||
#ifdef YYTRACKMAXSTACKDEPTH
|
||||
|
|
|
@ -390,7 +390,20 @@ static const sqlite3_api_routines sqlite3Apis = {
|
|||
sqlite3_uri_int64,
|
||||
sqlite3_uri_parameter,
|
||||
sqlite3_vsnprintf,
|
||||
sqlite3_wal_checkpoint_v2
|
||||
sqlite3_wal_checkpoint_v2,
|
||||
/* Version 3.8.7 and later */
|
||||
sqlite3_auto_extension,
|
||||
sqlite3_bind_blob64,
|
||||
sqlite3_bind_text64,
|
||||
sqlite3_cancel_auto_extension,
|
||||
sqlite3_load_extension,
|
||||
sqlite3_malloc64,
|
||||
sqlite3_msize,
|
||||
sqlite3_realloc64,
|
||||
sqlite3_reset_auto_extension,
|
||||
sqlite3_result_blob64,
|
||||
sqlite3_result_text64,
|
||||
sqlite3_strglob
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
11
src/main.c
11
src/main.c
|
@ -985,6 +985,10 @@ void sqlite3LeaveMutexAndCloseZombie(sqlite3 *db){
|
|||
sqlite3Error(db, SQLITE_OK); /* Deallocates any cached error strings. */
|
||||
sqlite3ValueFree(db->pErr);
|
||||
sqlite3CloseExtensions(db);
|
||||
#if SQLITE_USER_AUTHENTICATION
|
||||
sqlite3_free(db->auth.zAuthUser);
|
||||
sqlite3_free(db->auth.zAuthPW);
|
||||
#endif
|
||||
|
||||
db->magic = SQLITE_MAGIC_ERROR;
|
||||
|
||||
|
@ -2566,7 +2570,6 @@ static int openDatabase(
|
|||
db->aDb[0].pSchema = sqlite3SchemaGet(db, db->aDb[0].pBt);
|
||||
db->aDb[1].pSchema = sqlite3SchemaGet(db, 0);
|
||||
|
||||
|
||||
/* The default safety_level for the main database is 'full'; for the temp
|
||||
** database it is 'NONE'. This matches the pager layer defaults.
|
||||
*/
|
||||
|
@ -2853,9 +2856,9 @@ int sqlite3_get_autocommit(sqlite3 *db){
|
|||
}
|
||||
|
||||
/*
|
||||
** The following routines are subtitutes for constants SQLITE_CORRUPT,
|
||||
** The following routines are substitutes for constants SQLITE_CORRUPT,
|
||||
** SQLITE_MISUSE, SQLITE_CANTOPEN, SQLITE_IOERR and possibly other error
|
||||
** constants. They server two purposes:
|
||||
** constants. They serve two purposes:
|
||||
**
|
||||
** 1. Serve as a convenient place to set a breakpoint in a debugger
|
||||
** to detect when version error conditions occurs.
|
||||
|
@ -3169,7 +3172,7 @@ int sqlite3_test_control(int op, ...){
|
|||
** IMPORTANT: Changing the PENDING byte from 0x40000000 results in
|
||||
** an incompatible database file format. Changing the PENDING byte
|
||||
** while any database connection is open results in undefined and
|
||||
** dileterious behavior.
|
||||
** deleterious behavior.
|
||||
*/
|
||||
case SQLITE_TESTCTRL_PENDING_BYTE: {
|
||||
rc = PENDING_BYTE;
|
||||
|
|
42
src/malloc.c
42
src/malloc.c
|
@ -294,11 +294,9 @@ static int mallocWithAlarm(int n, void **pp){
|
|||
** Allocate memory. This routine is like sqlite3_malloc() except that it
|
||||
** assumes the memory subsystem has already been initialized.
|
||||
*/
|
||||
void *sqlite3Malloc(int n){
|
||||
void *sqlite3Malloc(u64 n){
|
||||
void *p;
|
||||
if( n<=0 /* IMP: R-65312-04917 */
|
||||
|| n>=0x7fffff00
|
||||
){
|
||||
if( n==0 || n>=0x7fffff00 ){
|
||||
/* A memory allocation of a number of bytes which is near the maximum
|
||||
** signed integer value might cause an integer overflow inside of the
|
||||
** xMalloc(). Hence we limit the maximum size to 0x7fffff00, giving
|
||||
|
@ -310,7 +308,7 @@ void *sqlite3Malloc(int n){
|
|||
mallocWithAlarm(n, &p);
|
||||
sqlite3_mutex_leave(mem0.mutex);
|
||||
}else{
|
||||
p = sqlite3GlobalConfig.m.xMalloc(n);
|
||||
p = sqlite3GlobalConfig.m.xMalloc((int)n);
|
||||
}
|
||||
assert( EIGHT_BYTE_ALIGNMENT(p) ); /* IMP: R-04675-44850 */
|
||||
return p;
|
||||
|
@ -322,6 +320,12 @@ void *sqlite3Malloc(int n){
|
|||
** allocation.
|
||||
*/
|
||||
void *sqlite3_malloc(int n){
|
||||
#ifndef SQLITE_OMIT_AUTOINIT
|
||||
if( sqlite3_initialize() ) return 0;
|
||||
#endif
|
||||
return n<=0 ? 0 : sqlite3Malloc(n);
|
||||
}
|
||||
void *sqlite3_malloc64(sqlite3_uint64 n){
|
||||
#ifndef SQLITE_OMIT_AUTOINIT
|
||||
if( sqlite3_initialize() ) return 0;
|
||||
#endif
|
||||
|
@ -458,6 +462,9 @@ int sqlite3DbMallocSize(sqlite3 *db, void *p){
|
|||
return sqlite3GlobalConfig.m.xSize(p);
|
||||
}
|
||||
}
|
||||
sqlite3_uint64 sqlite3_msize(void *p){
|
||||
return (sqlite3_uint64)sqlite3GlobalConfig.m.xSize(p);
|
||||
}
|
||||
|
||||
/*
|
||||
** Free memory previously obtained from sqlite3Malloc().
|
||||
|
@ -519,13 +526,13 @@ void sqlite3DbFree(sqlite3 *db, void *p){
|
|||
/*
|
||||
** Change the size of an existing memory allocation
|
||||
*/
|
||||
void *sqlite3Realloc(void *pOld, int nBytes){
|
||||
void *sqlite3Realloc(void *pOld, u64 nBytes){
|
||||
int nOld, nNew, nDiff;
|
||||
void *pNew;
|
||||
if( pOld==0 ){
|
||||
return sqlite3Malloc(nBytes); /* IMP: R-28354-25769 */
|
||||
}
|
||||
if( nBytes<=0 ){
|
||||
if( nBytes==0 ){
|
||||
sqlite3_free(pOld); /* IMP: R-31593-10574 */
|
||||
return 0;
|
||||
}
|
||||
|
@ -537,7 +544,7 @@ void *sqlite3Realloc(void *pOld, int nBytes){
|
|||
/* IMPLEMENTATION-OF: R-46199-30249 SQLite guarantees that the second
|
||||
** argument to xRealloc is always a value returned by a prior call to
|
||||
** xRoundup. */
|
||||
nNew = sqlite3GlobalConfig.m.xRoundup(nBytes);
|
||||
nNew = sqlite3GlobalConfig.m.xRoundup((int)nBytes);
|
||||
if( nOld==nNew ){
|
||||
pNew = pOld;
|
||||
}else if( sqlite3GlobalConfig.bMemstat ){
|
||||
|
@ -572,6 +579,13 @@ void *sqlite3Realloc(void *pOld, int nBytes){
|
|||
** subsystem is initialized prior to invoking sqliteRealloc.
|
||||
*/
|
||||
void *sqlite3_realloc(void *pOld, int n){
|
||||
#ifndef SQLITE_OMIT_AUTOINIT
|
||||
if( sqlite3_initialize() ) return 0;
|
||||
#endif
|
||||
if( n<0 ) n = 0;
|
||||
return sqlite3Realloc(pOld, n);
|
||||
}
|
||||
void *sqlite3_realloc64(void *pOld, sqlite3_uint64 n){
|
||||
#ifndef SQLITE_OMIT_AUTOINIT
|
||||
if( sqlite3_initialize() ) return 0;
|
||||
#endif
|
||||
|
@ -582,7 +596,7 @@ void *sqlite3_realloc(void *pOld, int n){
|
|||
/*
|
||||
** Allocate and zero memory.
|
||||
*/
|
||||
void *sqlite3MallocZero(int n){
|
||||
void *sqlite3MallocZero(u64 n){
|
||||
void *p = sqlite3Malloc(n);
|
||||
if( p ){
|
||||
memset(p, 0, n);
|
||||
|
@ -594,7 +608,7 @@ void *sqlite3MallocZero(int n){
|
|||
** Allocate and zero memory. If the allocation fails, make
|
||||
** the mallocFailed flag in the connection pointer.
|
||||
*/
|
||||
void *sqlite3DbMallocZero(sqlite3 *db, int n){
|
||||
void *sqlite3DbMallocZero(sqlite3 *db, u64 n){
|
||||
void *p = sqlite3DbMallocRaw(db, n);
|
||||
if( p ){
|
||||
memset(p, 0, n);
|
||||
|
@ -620,7 +634,7 @@ void *sqlite3DbMallocZero(sqlite3 *db, int n){
|
|||
** In other words, if a subsequent malloc (ex: "b") worked, it is assumed
|
||||
** that all prior mallocs (ex: "a") worked too.
|
||||
*/
|
||||
void *sqlite3DbMallocRaw(sqlite3 *db, int n){
|
||||
void *sqlite3DbMallocRaw(sqlite3 *db, u64 n){
|
||||
void *p;
|
||||
assert( db==0 || sqlite3_mutex_held(db->mutex) );
|
||||
assert( db==0 || db->pnBytesFreed==0 );
|
||||
|
@ -664,7 +678,7 @@ void *sqlite3DbMallocRaw(sqlite3 *db, int n){
|
|||
** Resize the block of memory pointed to by p to n bytes. If the
|
||||
** resize fails, set the mallocFailed flag in the connection object.
|
||||
*/
|
||||
void *sqlite3DbRealloc(sqlite3 *db, void *p, int n){
|
||||
void *sqlite3DbRealloc(sqlite3 *db, void *p, u64 n){
|
||||
void *pNew = 0;
|
||||
assert( db!=0 );
|
||||
assert( sqlite3_mutex_held(db->mutex) );
|
||||
|
@ -701,7 +715,7 @@ void *sqlite3DbRealloc(sqlite3 *db, void *p, int n){
|
|||
** Attempt to reallocate p. If the reallocation fails, then free p
|
||||
** and set the mallocFailed flag in the database connection.
|
||||
*/
|
||||
void *sqlite3DbReallocOrFree(sqlite3 *db, void *p, int n){
|
||||
void *sqlite3DbReallocOrFree(sqlite3 *db, void *p, u64 n){
|
||||
void *pNew;
|
||||
pNew = sqlite3DbRealloc(db, p, n);
|
||||
if( !pNew ){
|
||||
|
@ -731,7 +745,7 @@ char *sqlite3DbStrDup(sqlite3 *db, const char *z){
|
|||
}
|
||||
return zNew;
|
||||
}
|
||||
char *sqlite3DbStrNDup(sqlite3 *db, const char *z, int n){
|
||||
char *sqlite3DbStrNDup(sqlite3 *db, const char *z, u64 n){
|
||||
char *zNew;
|
||||
if( z==0 ){
|
||||
return 0;
|
||||
|
|
|
@ -188,7 +188,7 @@ static int sqlite3MemSize(void *pPrior){
|
|||
**
|
||||
** For this low-level interface, we know that pPrior!=0. Cases where
|
||||
** pPrior==0 while have been intercepted by higher-level routine and
|
||||
** redirected to xMalloc. Similarly, we know that nByte>0 becauses
|
||||
** redirected to xMalloc. Similarly, we know that nByte>0 because
|
||||
** cases where nByte<=0 will have been intercepted by higher-level
|
||||
** routines and redirected to xFree.
|
||||
*/
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
** 1. All memory allocations sizes are rounded up to a power of 2.
|
||||
**
|
||||
** 2. If two adjacent free blocks are the halves of a larger block,
|
||||
** then the two blocks are coalesed into the single larger block.
|
||||
** then the two blocks are coalesced into the single larger block.
|
||||
**
|
||||
** 3. New memory is allocated from the first available free block.
|
||||
**
|
||||
|
|
|
@ -26,7 +26,7 @@ typedef struct FileChunk FileChunk;
|
|||
**
|
||||
** The size chosen is a little less than a power of two. That way,
|
||||
** the FileChunk object will have a size that almost exactly fills
|
||||
** a power-of-two allocation. This mimimizes wasted space in power-of-two
|
||||
** a power-of-two allocation. This minimizes wasted space in power-of-two
|
||||
** memory allocators.
|
||||
*/
|
||||
#define JOURNAL_CHUNKSIZE ((int)(1024-sizeof(FileChunk*)))
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
** Figure out what version of the code to use. The choices are
|
||||
**
|
||||
** SQLITE_MUTEX_OMIT No mutex logic. Not even stubs. The
|
||||
** mutexes implemention cannot be overridden
|
||||
** mutexes implementation cannot be overridden
|
||||
** at start-time.
|
||||
**
|
||||
** SQLITE_MUTEX_NOOP For single-threaded applications. No
|
||||
|
|
2
src/os.h
2
src/os.h
|
@ -120,7 +120,7 @@
|
|||
** shared locks begins at SHARED_FIRST.
|
||||
**
|
||||
** The same locking strategy and
|
||||
** byte ranges are used for Unix. This leaves open the possiblity of having
|
||||
** byte ranges are used for Unix. This leaves open the possibility 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
|
||||
|
|
|
@ -299,6 +299,14 @@ static int randomnessPid = 0;
|
|||
# endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Explicitly call the 64-bit version of lseek() on Android. Otherwise, lseek()
|
||||
** is the 32-bit version, even if _FILE_OFFSET_BITS=64 is defined.
|
||||
*/
|
||||
#ifdef __ANDROID__
|
||||
# define lseek lseek64
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Different Unix systems declare open() in different ways. Same use
|
||||
** open(const char*,int,mode_t). Others use open(const char*,int,...).
|
||||
|
@ -631,7 +639,7 @@ static int unixMutexHeld(void) {
|
|||
#if defined(SQLITE_TEST) && defined(SQLITE_DEBUG)
|
||||
/*
|
||||
** Helper function for printing out trace information from debugging
|
||||
** binaries. This returns the string represetation of the supplied
|
||||
** binaries. This returns the string representation of the supplied
|
||||
** integer lock-type.
|
||||
*/
|
||||
static const char *azFileLock(int eFileLock){
|
||||
|
@ -708,9 +716,22 @@ static int lockTrace(int fd, int op, struct flock *p){
|
|||
|
||||
/*
|
||||
** Retry ftruncate() calls that fail due to EINTR
|
||||
**
|
||||
** All calls to ftruncate() within this file should be made through this wrapper.
|
||||
** On the Android platform, bypassing the logic below could lead to a corrupt
|
||||
** database.
|
||||
*/
|
||||
static int robust_ftruncate(int h, sqlite3_int64 sz){
|
||||
int rc;
|
||||
#ifdef __ANDROID__
|
||||
/* On Android, ftruncate() always uses 32-bit offsets, even if
|
||||
** _FILE_OFFSET_BITS=64 is defined. This means it is unsafe to attempt to
|
||||
** truncate a file to any size larger than 2GiB. Silently ignore any
|
||||
** such attempts. */
|
||||
if( sz>(sqlite3_int64)0x7FFFFFFF ){
|
||||
rc = SQLITE_OK;
|
||||
}else
|
||||
#endif
|
||||
do{ rc = osFtruncate(h,sz); }while( rc<0 && errno==EINTR );
|
||||
return rc;
|
||||
}
|
||||
|
@ -3098,7 +3119,7 @@ static int nfsUnlock(sqlite3_file *id, int eFileLock){
|
|||
** NB: If you define USE_PREAD or USE_PREAD64, then it might also
|
||||
** be necessary to define _XOPEN_SOURCE to be 500. This varies from
|
||||
** one system to another. Since SQLite does not define USE_PREAD
|
||||
** any any form by default, we will not attempt to define _XOPEN_SOURCE.
|
||||
** in any form by default, we will not attempt to define _XOPEN_SOURCE.
|
||||
** See tickets #2741 and #2681.
|
||||
**
|
||||
** To avoid stomping the errno value on a failed read the lastErrno value
|
||||
|
@ -3595,7 +3616,7 @@ static int unixTruncate(sqlite3_file *id, i64 nByte){
|
|||
nByte = ((nByte + pFile->szChunk - 1)/pFile->szChunk) * pFile->szChunk;
|
||||
}
|
||||
|
||||
rc = robust_ftruncate(pFile->h, (off_t)nByte);
|
||||
rc = robust_ftruncate(pFile->h, nByte);
|
||||
if( rc ){
|
||||
pFile->lastErrno = errno;
|
||||
return unixLogError(SQLITE_IOERR_TRUNCATE, "ftruncate", pFile->zPath);
|
||||
|
@ -3730,7 +3751,7 @@ static int fcntlSizeHint(unixFile *pFile, i64 nByte){
|
|||
}
|
||||
|
||||
/*
|
||||
** If *pArg is inititially negative then this is a query. Set *pArg to
|
||||
** If *pArg is initially negative then this is a query. Set *pArg to
|
||||
** 1 or 0 depending on whether or not bit mask of pFile->ctrlFlags is set.
|
||||
**
|
||||
** If *pArg is 0 or 1, then clear or set the mask bit of pFile->ctrlFlags.
|
||||
|
@ -3937,7 +3958,7 @@ static int unixSectorSize(sqlite3_file *id){
|
|||
** Return the device characteristics for the file.
|
||||
**
|
||||
** This VFS is set up to return SQLITE_IOCAP_POWERSAFE_OVERWRITE by default.
|
||||
** However, that choice is contraversial since technically the underlying
|
||||
** However, that choice is controversial since technically the underlying
|
||||
** file system does not always provide powersafe overwrites. (In other
|
||||
** words, after a power-loss event, parts of the file that were never
|
||||
** written might end up being altered.) However, non-PSOW behavior is very,
|
||||
|
@ -4909,7 +4930,7 @@ static int unixUnfetch(sqlite3_file *fd, i64 iOff, void *p){
|
|||
** looks at the filesystem type and tries to guess the best locking
|
||||
** strategy from that.
|
||||
**
|
||||
** For finder-funtion F, two objects are created:
|
||||
** For finder-function F, two objects are created:
|
||||
**
|
||||
** (1) The real finder-function named "FImpt()".
|
||||
**
|
||||
|
@ -5171,7 +5192,7 @@ static const sqlite3_io_methods
|
|||
#endif /* OS_VXWORKS && SQLITE_ENABLE_LOCKING_STYLE */
|
||||
|
||||
/*
|
||||
** An abstract type for a pointer to a IO method finder function:
|
||||
** An abstract type for a pointer to an IO method finder function:
|
||||
*/
|
||||
typedef const sqlite3_io_methods *(*finder_type)(const char*,unixFile*);
|
||||
|
||||
|
@ -5485,7 +5506,7 @@ static UnixUnusedFd *findReusableFd(const char *zPath, int flags){
|
|||
** descriptor on the same path, fail, and return an error to SQLite.
|
||||
**
|
||||
** Even if a subsequent open() call does succeed, the consequences of
|
||||
** not searching for a resusable file descriptor are not dire. */
|
||||
** not searching for a reusable file descriptor are not dire. */
|
||||
if( 0==osStat(zPath, &sStat) ){
|
||||
unixInodeInfo *pInode;
|
||||
|
||||
|
@ -5516,7 +5537,7 @@ static UnixUnusedFd *findReusableFd(const char *zPath, int flags){
|
|||
** written to *pMode. If an IO error occurs, an SQLite error code is
|
||||
** returned and the value of *pMode is not modified.
|
||||
**
|
||||
** In most cases cases, this routine sets *pMode to 0, which will become
|
||||
** In most cases, this routine sets *pMode to 0, which will become
|
||||
** an indication to robust_open() to create the file using
|
||||
** SQLITE_DEFAULT_FILE_PERMISSIONS adjusted by the umask.
|
||||
** But if the file being opened is a WAL or regular journal file, then
|
||||
|
@ -6308,7 +6329,7 @@ static int unixGetLastError(sqlite3_vfs *NotUsed, int NotUsed2, char *NotUsed3){
|
|||
** proxy path against the values stored in the conch. The conch file is
|
||||
** stored in the same directory as the database file and the file name
|
||||
** is patterned after the database file name as ".<databasename>-conch".
|
||||
** If the conch file does not exist, or it's contents do not match the
|
||||
** If the conch file does not exist, or its contents do not match the
|
||||
** host ID and/or proxy path, then the lock is escalated to an exclusive
|
||||
** lock and the conch file contents is updated with the host ID and proxy
|
||||
** path and the lock is downgraded to a shared lock again. If the conch
|
||||
|
@ -6360,7 +6381,7 @@ static int unixGetLastError(sqlite3_vfs *NotUsed, int NotUsed2, char *NotUsed3){
|
|||
** setting the environment variable SQLITE_FORCE_PROXY_LOCKING to 1 will
|
||||
** force proxy locking to be used for every database file opened, and 0
|
||||
** will force automatic proxy locking to be disabled for all database
|
||||
** files (explicity calling the SQLITE_SET_LOCKPROXYFILE pragma or
|
||||
** files (explicitly calling the SQLITE_SET_LOCKPROXYFILE pragma or
|
||||
** sqlite_file_control API is not affected by SQLITE_FORCE_PROXY_LOCKING).
|
||||
*/
|
||||
|
||||
|
|
|
@ -1286,12 +1286,14 @@ void sqlite3_win32_sleep(DWORD milliseconds){
|
|||
#endif
|
||||
}
|
||||
|
||||
#if SQLITE_MAX_WORKER_THREADS>0 && !SQLITE_OS_WINRT && SQLITE_THREADSAFE>0
|
||||
DWORD sqlite3Win32Wait(HANDLE hObject){
|
||||
DWORD rc;
|
||||
while( (rc = osWaitForSingleObjectEx(hObject, INFINITE,
|
||||
TRUE))==WAIT_IO_COMPLETION ){}
|
||||
return rc;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Return true (non-zero) if we are running under WinNT, Win2K, WinXP,
|
||||
|
@ -3126,7 +3128,7 @@ static int winUnlock(sqlite3_file *id, int locktype){
|
|||
}
|
||||
|
||||
/*
|
||||
** If *pArg is inititially negative then this is a query. Set *pArg to
|
||||
** If *pArg is initially negative then this is a query. Set *pArg to
|
||||
** 1 or 0 depending on whether or not bit mask of pFile->ctrlFlags is set.
|
||||
**
|
||||
** If *pArg is 0 or 1, then clear or set the mask bit of pFile->ctrlFlags.
|
||||
|
@ -4140,7 +4142,7 @@ static int winUnfetch(sqlite3_file *fd, i64 iOff, void *p){
|
|||
}else{
|
||||
/* FIXME: If Windows truly always prevents truncating or deleting a
|
||||
** file while a mapping is held, then the following winUnmapfile() call
|
||||
** is unnecessary can can be omitted - potentially improving
|
||||
** is unnecessary can be omitted - potentially improving
|
||||
** performance. */
|
||||
winUnmapfile(pFd);
|
||||
}
|
||||
|
|
28
src/pager.c
28
src/pager.c
|
@ -76,12 +76,12 @@
|
|||
** Definition: Two databases (or the same database at two points it time)
|
||||
** are said to be "logically equivalent" if they give the same answer to
|
||||
** all queries. Note in particular the content of freelist leaf
|
||||
** pages can be changed arbitarily without effecting the logical equivalence
|
||||
** pages can be changed arbitrarily without affecting the logical equivalence
|
||||
** of the database.
|
||||
**
|
||||
** (7) At any time, if any subset, including the empty set and the total set,
|
||||
** of the unsynced changes to a rollback journal are removed and the
|
||||
** journal is rolled back, the resulting database file will be logical
|
||||
** journal is rolled back, the resulting database file will be logically
|
||||
** equivalent to the database file at the beginning of the transaction.
|
||||
**
|
||||
** (8) When a transaction is rolled back, the xTruncate method of the VFS
|
||||
|
@ -378,7 +378,7 @@ int sqlite3PagerTrace=1; /* True to enable tracing */
|
|||
**
|
||||
** The exception is when the database file is unlocked as the pager moves
|
||||
** from ERROR to OPEN state. At this point there may be a hot-journal file
|
||||
** in the file-system that needs to be rolled back (as part of a OPEN->SHARED
|
||||
** in the file-system that needs to be rolled back (as part of an OPEN->SHARED
|
||||
** transition, by the same pager or any other). If the call to xUnlock()
|
||||
** fails at this point and the pager is left holding an EXCLUSIVE lock, this
|
||||
** can confuse the call to xCheckReservedLock() call made later as part
|
||||
|
@ -461,7 +461,7 @@ struct PagerSavepoint {
|
|||
#define SPILLFLAG_NOSYNC 0x04 /* Spill is ok, but do not sync */
|
||||
|
||||
/*
|
||||
** A open page cache is an instance of struct Pager. A description of
|
||||
** An open page cache is an instance of struct Pager. A description of
|
||||
** some of the more important member variables follows:
|
||||
**
|
||||
** eState
|
||||
|
@ -634,7 +634,7 @@ struct Pager {
|
|||
|
||||
/**************************************************************************
|
||||
** The following block contains those class members that change during
|
||||
** routine opertion. Class members not in this block are either fixed
|
||||
** routine operation. Class members not in this block are either fixed
|
||||
** when the pager is first created or else only change when there is a
|
||||
** significant mode change (such as changing the page_size, locking_mode,
|
||||
** or the journal_mode). From another view, these class members describe
|
||||
|
@ -2431,7 +2431,7 @@ static int pager_delmaster(Pager *pPager, const char *zMaster){
|
|||
rc = sqlite3OsFileSize(pMaster, &nMasterJournal);
|
||||
if( rc!=SQLITE_OK ) goto delmaster_out;
|
||||
nMasterPtr = pVfs->mxPathname+1;
|
||||
zMasterJournal = sqlite3Malloc((int)nMasterJournal + nMasterPtr + 1);
|
||||
zMasterJournal = sqlite3Malloc(nMasterJournal + nMasterPtr + 1);
|
||||
if( !zMasterJournal ){
|
||||
rc = SQLITE_NOMEM;
|
||||
goto delmaster_out;
|
||||
|
@ -2500,7 +2500,7 @@ delmaster_out:
|
|||
** If the file on disk is currently larger than nPage pages, then use the VFS
|
||||
** xTruncate() method to truncate it.
|
||||
**
|
||||
** Or, it might might be the case that the file on disk is smaller than
|
||||
** Or, it might be the case that the file on disk is smaller than
|
||||
** nPage pages. Some operating system implementations can get confused if
|
||||
** you try to truncate a file to some size that is larger than it
|
||||
** currently is, so detect this case and write a single zero byte to
|
||||
|
@ -2559,7 +2559,7 @@ int sqlite3SectorSize(sqlite3_file *pFile){
|
|||
/*
|
||||
** Set the value of the Pager.sectorSize variable for the given
|
||||
** pager based on the value returned by the xSectorSize method
|
||||
** of the open database file. The sector size will be used used
|
||||
** of the open database file. The sector size will be used
|
||||
** to determine the size and alignment of journal header and
|
||||
** master journal pointers within created journal files.
|
||||
**
|
||||
|
@ -3621,12 +3621,14 @@ int sqlite3PagerSetPagesize(Pager *pPager, u32 *pPageSize, int nReserve){
|
|||
|
||||
if( rc==SQLITE_OK ){
|
||||
pager_reset(pPager);
|
||||
pPager->dbSize = (Pgno)((nByte+pageSize-1)/pageSize);
|
||||
pPager->pageSize = pageSize;
|
||||
sqlite3PageFree(pPager->pTmpSpace);
|
||||
pPager->pTmpSpace = pNew;
|
||||
rc = sqlite3PcacheSetPageSize(pPager->pPCache, pageSize);
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
pPager->dbSize = (Pgno)((nByte+pageSize-1)/pageSize);
|
||||
pPager->pageSize = pageSize;
|
||||
}
|
||||
}
|
||||
|
||||
*pPageSize = pPager->pageSize;
|
||||
|
@ -3759,7 +3761,7 @@ static int pager_wait_on_lock(Pager *pPager, int locktype){
|
|||
int rc; /* Return code */
|
||||
|
||||
/* Check that this is either a no-op (because the requested lock is
|
||||
** already held, or one of the transistions that the busy-handler
|
||||
** already held), or one of the transitions that the busy-handler
|
||||
** may be invoked during, according to the comment above
|
||||
** sqlite3PagerSetBusyhandler().
|
||||
*/
|
||||
|
@ -4389,7 +4391,7 @@ static int pagerStress(void *p, PgHdr *pPg){
|
|||
** a rollback or by user request, respectively.
|
||||
**
|
||||
** Spilling is also prohibited when in an error state since that could
|
||||
** lead to database corruption. In the current implementaton it
|
||||
** lead to database corruption. In the current implementation it
|
||||
** is impossible for sqlite3PcacheFetch() to be called with createFlag==3
|
||||
** while in the error state, hence it is impossible for this routine to
|
||||
** be called in the error state. Nevertheless, we include a NEVER()
|
||||
|
@ -4929,7 +4931,7 @@ static int hasHotJournal(Pager *pPager, int *pExists){
|
|||
*pExists = (first!=0);
|
||||
}else if( rc==SQLITE_CANTOPEN ){
|
||||
/* If we cannot open the rollback journal file in order to see if
|
||||
** its has a zero header, that might be due to an I/O error, or
|
||||
** it has a zero header, that might be due to an I/O error, or
|
||||
** it might be due to the race condition described above and in
|
||||
** ticket #3883. Either way, assume that the journal is hot.
|
||||
** This might be a false positive. But if it is, then the
|
||||
|
|
36
src/pcache.c
36
src/pcache.c
|
@ -45,23 +45,6 @@ struct PCache {
|
|||
|
||||
/********************************** Linked List Management ********************/
|
||||
|
||||
#if !defined(NDEBUG) && defined(SQLITE_ENABLE_EXPENSIVE_ASSERT)
|
||||
/*
|
||||
** Check that the pCache->pSynced variable is set correctly. If it
|
||||
** is not, either fail an assert or return zero. Otherwise, return
|
||||
** non-zero. This is only used in debugging builds, as follows:
|
||||
**
|
||||
** expensive_assert( pcacheCheckSynced(pCache) );
|
||||
*/
|
||||
static int pcacheCheckSynced(PCache *pCache){
|
||||
PgHdr *p;
|
||||
for(p=pCache->pDirtyTail; p!=pCache->pSynced; p=p->pDirtyPrev){
|
||||
assert( p->nRef || (p->flags&PGHDR_NEED_SYNC) );
|
||||
}
|
||||
return (p==0 || p->nRef || (p->flags&PGHDR_NEED_SYNC)==0);
|
||||
}
|
||||
#endif /* !NDEBUG && SQLITE_ENABLE_EXPENSIVE_ASSERT */
|
||||
|
||||
/* Allowed values for second argument to pcacheManageDirtyList() */
|
||||
#define PCACHE_DIRTYLIST_REMOVE 1 /* Remove pPage from dirty list */
|
||||
#define PCACHE_DIRTYLIST_ADD 2 /* Add pPage to the dirty list */
|
||||
|
@ -107,7 +90,6 @@ static void pcacheManageDirtyList(PgHdr *pPage, u8 addRemove){
|
|||
}
|
||||
pPage->pDirtyNext = 0;
|
||||
pPage->pDirtyPrev = 0;
|
||||
expensive_assert( pcacheCheckSynced(p) );
|
||||
}
|
||||
if( addRemove & PCACHE_DIRTYLIST_ADD ){
|
||||
assert( pPage->pDirtyNext==0 && pPage->pDirtyPrev==0 && p->pDirty!=pPage );
|
||||
|
@ -116,18 +98,17 @@ static void pcacheManageDirtyList(PgHdr *pPage, u8 addRemove){
|
|||
if( pPage->pDirtyNext ){
|
||||
assert( pPage->pDirtyNext->pDirtyPrev==0 );
|
||||
pPage->pDirtyNext->pDirtyPrev = pPage;
|
||||
}else if( p->bPurgeable ){
|
||||
assert( p->eCreate==2 );
|
||||
p->eCreate = 1;
|
||||
}else{
|
||||
p->pDirtyTail = pPage;
|
||||
if( p->bPurgeable ){
|
||||
assert( p->eCreate==2 );
|
||||
p->eCreate = 1;
|
||||
}
|
||||
}
|
||||
p->pDirty = pPage;
|
||||
if( !p->pDirtyTail ){
|
||||
p->pDirtyTail = pPage;
|
||||
}
|
||||
if( !p->pSynced && 0==(pPage->flags&PGHDR_NEED_SYNC) ){
|
||||
p->pSynced = pPage;
|
||||
}
|
||||
expensive_assert( pcacheCheckSynced(p) );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -304,7 +285,6 @@ int sqlite3PcacheFetchStress(
|
|||
** cleared), but if that is not possible settle for any other
|
||||
** unreferenced dirty page.
|
||||
*/
|
||||
expensive_assert( pcacheCheckSynced(pCache) );
|
||||
for(pPg=pCache->pSynced;
|
||||
pPg && (pPg->nRef || (pPg->flags&PGHDR_NEED_SYNC));
|
||||
pPg=pPg->pDirtyPrev
|
||||
|
@ -390,7 +370,7 @@ PgHdr *sqlite3PcacheFetchFinish(
|
|||
|
||||
/*
|
||||
** Decrement the reference count on a page. If the page is clean and the
|
||||
** reference count drops to 0, then it is made elible for recycling.
|
||||
** reference count drops to 0, then it is made eligible for recycling.
|
||||
*/
|
||||
void SQLITE_NOINLINE sqlite3PcacheRelease(PgHdr *p){
|
||||
assert( p->nRef>0 );
|
||||
|
@ -399,7 +379,7 @@ void SQLITE_NOINLINE sqlite3PcacheRelease(PgHdr *p){
|
|||
p->pCache->nRef--;
|
||||
if( (p->flags&PGHDR_DIRTY)==0 ){
|
||||
pcacheUnpin(p);
|
||||
}else{
|
||||
}else if( p->pDirtyPrev!=0 ){
|
||||
/* Move the page to the head of the dirty list. */
|
||||
pcacheManageDirtyList(p, PCACHE_DIRTYLIST_FRONT);
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
** This file implements the default page cache implementation (the
|
||||
** sqlite3_pcache interface). It also contains part of the implementation
|
||||
** of the SQLITE_CONFIG_PAGECACHE and sqlite3_release_memory() features.
|
||||
** If the default page cache implementation is overriden, then neither of
|
||||
** If the default page cache implementation is overridden, then neither of
|
||||
** these two features are available.
|
||||
*/
|
||||
|
||||
|
@ -25,7 +25,7 @@ typedef struct PgFreeslot PgFreeslot;
|
|||
typedef struct PGroup PGroup;
|
||||
|
||||
/* Each page cache (or PCache) belongs to a PGroup. A PGroup is a set
|
||||
** of one or more PCaches that are able to recycle each others unpinned
|
||||
** of one or more PCaches that are able to recycle each other's unpinned
|
||||
** pages when they are under memory pressure. A PGroup is an instance of
|
||||
** the following object.
|
||||
**
|
||||
|
|
|
@ -1422,6 +1422,12 @@ void sqlite3Pragma(
|
|||
** in auto-commit mode. */
|
||||
mask &= ~(SQLITE_ForeignKeys);
|
||||
}
|
||||
#if SQLITE_USER_AUTHENTICATION
|
||||
if( db->auth.authLevel==UAUTH_User ){
|
||||
/* Do not allow non-admin users to modify the schema arbitrarily */
|
||||
mask &= ~(SQLITE_WriteSchema);
|
||||
}
|
||||
#endif
|
||||
|
||||
if( sqlite3GetBoolean(zRight, 0) ){
|
||||
db->flags |= mask;
|
||||
|
|
|
@ -328,7 +328,7 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
|
|||
db->aDb[iDb].zName, zMasterName);
|
||||
#ifndef SQLITE_OMIT_AUTHORIZATION
|
||||
{
|
||||
int (*xAuth)(void*,int,const char*,const char*,const char*,const char*);
|
||||
sqlite3_xauth xAuth;
|
||||
xAuth = db->xAuth;
|
||||
db->xAuth = 0;
|
||||
#endif
|
||||
|
@ -394,6 +394,7 @@ int sqlite3Init(sqlite3 *db, char **pzErrMsg){
|
|||
int commit_internal = !(db->flags&SQLITE_InternChanges);
|
||||
|
||||
assert( sqlite3_mutex_held(db->mutex) );
|
||||
assert( db->init.busy==0 );
|
||||
rc = SQLITE_OK;
|
||||
db->init.busy = 1;
|
||||
for(i=0; rc==SQLITE_OK && i<db->nDb; i++){
|
||||
|
@ -409,8 +410,8 @@ int sqlite3Init(sqlite3 *db, char **pzErrMsg){
|
|||
** schema may contain references to objects in other databases.
|
||||
*/
|
||||
#ifndef SQLITE_OMIT_TEMPDB
|
||||
if( rc==SQLITE_OK && ALWAYS(db->nDb>1)
|
||||
&& !DbHasProperty(db, 1, DB_SchemaLoaded) ){
|
||||
assert( db->nDb>1 );
|
||||
if( rc==SQLITE_OK && !DbHasProperty(db, 1, DB_SchemaLoaded) ){
|
||||
rc = sqlite3InitOne(db, 1, pzErrMsg);
|
||||
if( rc ){
|
||||
sqlite3ResetOneSchema(db, 1);
|
||||
|
|
|
@ -904,7 +904,7 @@ char *sqlite3MPrintf(sqlite3 *db, const char *zFormat, ...){
|
|||
|
||||
/*
|
||||
** Like sqlite3MPrintf(), but call sqlite3DbFree() on zStr after formatting
|
||||
** the string and before returnning. This routine is intended to be used
|
||||
** the string and before returning. This routine is intended to be used
|
||||
** to modify an existing string. For example:
|
||||
**
|
||||
** x = sqlite3MPrintf(db, x, "prefix %s suffix", x);
|
||||
|
|
|
@ -719,9 +719,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
|
|||
pExpr->iTable = pDef->zName[0]=='u' ? 62 : 938;
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifndef SQLITE_OMIT_AUTHORIZATION
|
||||
if( pDef ){
|
||||
auth = sqlite3AuthCheck(pParse, SQLITE_FUNCTION, 0, pDef->zName, 0);
|
||||
if( auth!=SQLITE_OK ){
|
||||
if( auth==SQLITE_DENY ){
|
||||
|
@ -732,9 +730,9 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
|
|||
pExpr->op = TK_NULL;
|
||||
return WRC_Prune;
|
||||
}
|
||||
#endif
|
||||
if( pDef->funcFlags & SQLITE_FUNC_CONSTANT ) ExprSetProperty(pExpr,EP_Constant);
|
||||
}
|
||||
#endif
|
||||
if( is_agg && (pNC->ncFlags & NC_AllowAgg)==0 ){
|
||||
sqlite3ErrorMsg(pParse, "misuse of aggregate function %.*s()", nId,zId);
|
||||
pNC->nErr++;
|
||||
|
@ -757,7 +755,13 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
|
|||
pExpr->op2++;
|
||||
pNC2 = pNC2->pNext;
|
||||
}
|
||||
if( pNC2 ) pNC2->ncFlags |= NC_HasAgg;
|
||||
assert( pDef!=0 );
|
||||
if( pNC2 ){
|
||||
assert( SQLITE_FUNC_MINMAX==NC_MinMaxAgg );
|
||||
testcase( (pDef->funcFlags & SQLITE_FUNC_MINMAX)!=0 );
|
||||
pNC2->ncFlags |= NC_HasAgg | (pDef->funcFlags & SQLITE_FUNC_MINMAX);
|
||||
|
||||
}
|
||||
pNC->ncFlags |= NC_AllowAgg;
|
||||
}
|
||||
/* FIX ME: Compute pExpr->affinity based on the expected return
|
||||
|
@ -1118,7 +1122,7 @@ static int resolveOrderGroupBy(
|
|||
}
|
||||
|
||||
/*
|
||||
** Resolve names in the SELECT statement p and all of its descendents.
|
||||
** Resolve names in the SELECT statement p and all of its descendants.
|
||||
*/
|
||||
static int resolveSelectStep(Walker *pWalker, Select *p){
|
||||
NameContext *pOuterNC; /* Context that contains this SELECT */
|
||||
|
@ -1222,7 +1226,8 @@ static int resolveSelectStep(Walker *pWalker, Select *p){
|
|||
assert( (p->selFlags & SF_Aggregate)==0 );
|
||||
pGroupBy = p->pGroupBy;
|
||||
if( pGroupBy || (sNC.ncFlags & NC_HasAgg)!=0 ){
|
||||
p->selFlags |= SF_Aggregate;
|
||||
assert( NC_MinMaxAgg==SF_MinMaxAgg );
|
||||
p->selFlags |= SF_Aggregate | (sNC.ncFlags&NC_MinMaxAgg);
|
||||
}else{
|
||||
sNC.ncFlags &= ~NC_AllowAgg;
|
||||
}
|
||||
|
@ -1350,7 +1355,7 @@ int sqlite3ResolveExprNames(
|
|||
NameContext *pNC, /* Namespace to resolve expressions in. */
|
||||
Expr *pExpr /* The expression to be analyzed. */
|
||||
){
|
||||
u8 savedHasAgg;
|
||||
u16 savedHasAgg;
|
||||
Walker w;
|
||||
|
||||
if( pExpr==0 ) return 0;
|
||||
|
@ -1363,8 +1368,8 @@ int sqlite3ResolveExprNames(
|
|||
pParse->nHeight += pExpr->nHeight;
|
||||
}
|
||||
#endif
|
||||
savedHasAgg = pNC->ncFlags & NC_HasAgg;
|
||||
pNC->ncFlags &= ~NC_HasAgg;
|
||||
savedHasAgg = pNC->ncFlags & (NC_HasAgg|NC_MinMaxAgg);
|
||||
pNC->ncFlags &= ~(NC_HasAgg|NC_MinMaxAgg);
|
||||
memset(&w, 0, sizeof(w));
|
||||
w.xExprCallback = resolveExprStep;
|
||||
w.xSelectCallback = resolveSelectStep;
|
||||
|
@ -1379,9 +1384,8 @@ int sqlite3ResolveExprNames(
|
|||
}
|
||||
if( pNC->ncFlags & NC_HasAgg ){
|
||||
ExprSetProperty(pExpr, EP_Agg);
|
||||
}else if( savedHasAgg ){
|
||||
pNC->ncFlags |= NC_HasAgg;
|
||||
}
|
||||
pNC->ncFlags |= savedHasAgg;
|
||||
return ExprHasProperty(pExpr, EP_Error);
|
||||
}
|
||||
|
||||
|
|
|
@ -50,7 +50,7 @@
|
|||
** No INSERTs may occurs after a SMALLEST. An assertion will fail if
|
||||
** that is attempted.
|
||||
**
|
||||
** The cost of an INSERT is roughly constant. (Sometime new memory
|
||||
** The cost of an INSERT is roughly constant. (Sometimes new memory
|
||||
** has to be allocated on an INSERT.) The cost of a TEST with a new
|
||||
** batch number is O(NlogN) where N is the number of elements in the RowSet.
|
||||
** The cost of a TEST using the same batch number is O(logN). The cost
|
||||
|
@ -443,8 +443,8 @@ int sqlite3RowSetNext(RowSet *p, i64 *pRowid){
|
|||
** Check to see if element iRowid was inserted into the rowset as
|
||||
** part of any insert batch prior to iBatch. Return 1 or 0.
|
||||
**
|
||||
** If this is the first test of a new batch and if there exist entires
|
||||
** on pRowSet->pEntry, then sort those entires into the forest at
|
||||
** If this is the first test of a new batch and if there exist entries
|
||||
** on pRowSet->pEntry, then sort those entries into the forest at
|
||||
** pRowSet->pForest so that they can be tested.
|
||||
*/
|
||||
int sqlite3RowSetTest(RowSet *pRowSet, int iBatch, sqlite3_int64 iRowid){
|
||||
|
|
41
src/select.c
41
src/select.c
|
@ -488,7 +488,7 @@ static void pushOntoSorter(
|
|||
sqlite3VdbeAddOp2(v, OP_Sequence, pSort->iECursor, regBase+nExpr);
|
||||
}
|
||||
if( nPrefixReg==0 ){
|
||||
sqlite3VdbeAddOp3(v, OP_Move, regData, regBase+nExpr+bSeq, nData);
|
||||
sqlite3ExprCodeMove(pParse, regData, regBase+nExpr+bSeq, nData);
|
||||
}
|
||||
|
||||
sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase+nOBSat, nBase-nOBSat, regRecord);
|
||||
|
@ -524,7 +524,7 @@ static void pushOntoSorter(
|
|||
sqlite3VdbeAddOp2(v, OP_Gosub, pSort->regReturn, pSort->labelBkOut);
|
||||
sqlite3VdbeAddOp1(v, OP_ResetSorter, pSort->iECursor);
|
||||
sqlite3VdbeJumpHere(v, addrFirst);
|
||||
sqlite3VdbeAddOp3(v, OP_Move, regBase, regPrevKey, pSort->nOBSat);
|
||||
sqlite3ExprCodeMove(pParse, regBase, regPrevKey, pSort->nOBSat);
|
||||
sqlite3VdbeJumpHere(v, addrJmp);
|
||||
}
|
||||
if( pSort->sortFlags & SORTFLAG_UseSorter ){
|
||||
|
@ -1010,7 +1010,7 @@ int sqlite3KeyInfoIsWriteable(KeyInfo *p){ return p->nRef==1; }
|
|||
** then the KeyInfo structure is appropriate for initializing a virtual
|
||||
** index to implement a DISTINCT test.
|
||||
**
|
||||
** Space to hold the KeyInfo structure is obtain from malloc. The calling
|
||||
** Space to hold the KeyInfo structure is obtained from malloc. The calling
|
||||
** function is responsible for seeing that this structure is eventually
|
||||
** freed.
|
||||
*/
|
||||
|
@ -1541,7 +1541,7 @@ static void generateColumnNames(
|
|||
}
|
||||
|
||||
/*
|
||||
** Given a an expression list (which is really the list of expressions
|
||||
** Given an expression list (which is really the list of expressions
|
||||
** that form the result set of a SELECT statement) compute appropriate
|
||||
** column names for a table that would hold the expression list.
|
||||
**
|
||||
|
@ -1614,7 +1614,7 @@ static int selectColumnsFromExprList(
|
|||
}
|
||||
|
||||
/* Make sure the column name is unique. If the name is not unique,
|
||||
** append a integer to the name so that it becomes unique.
|
||||
** append an integer to the name so that it becomes unique.
|
||||
*/
|
||||
nName = sqlite3Strlen30(zName);
|
||||
for(j=cnt=0; j<i; j++){
|
||||
|
@ -3098,7 +3098,7 @@ static void substSelect(
|
|||
**
|
||||
** SELECT x+y AS a FROM t1 WHERE z<100 AND a>5
|
||||
**
|
||||
** The code generated for this simpification gives the same result
|
||||
** The code generated for this simplification gives the same result
|
||||
** but only has to scan the data once. And because indices might
|
||||
** exist on the table t1, a complete scan of the data might be
|
||||
** avoided.
|
||||
|
@ -3131,8 +3131,10 @@ static void substSelect(
|
|||
** (9) The subquery does not use LIMIT or the outer query does not use
|
||||
** aggregates.
|
||||
**
|
||||
** (10) The subquery does not use aggregates or the outer query does not
|
||||
** use LIMIT.
|
||||
** (**) Restriction (10) was removed from the code on 2005-02-05 but we
|
||||
** accidently carried the comment forward until 2014-09-15. Original
|
||||
** text: "The subquery does not use aggregates or the outer query does not
|
||||
** use LIMIT."
|
||||
**
|
||||
** (11) The subquery and the outer query do not both have ORDER BY clauses.
|
||||
**
|
||||
|
@ -3195,6 +3197,11 @@ static void substSelect(
|
|||
** parent to a compound query confuses the code that handles
|
||||
** recursive queries in multiSelect().
|
||||
**
|
||||
** (24) The subquery is not an aggregate that uses the built-in min() or
|
||||
** or max() functions. (Without this restriction, a query like:
|
||||
** "SELECT x FROM (SELECT max(y), x FROM t1)" would not necessarily
|
||||
** return the value X for which Y was maximal.)
|
||||
**
|
||||
**
|
||||
** In this routine, the "p" parameter is a pointer to the outer query.
|
||||
** The subquery is p->pSrc->a[iFrom]. isAgg is true if the outer query
|
||||
|
@ -3242,7 +3249,7 @@ static int flattenSubquery(
|
|||
pSubSrc = pSub->pSrc;
|
||||
assert( pSubSrc );
|
||||
/* Prior to version 3.1.2, when LIMIT and OFFSET had to be simple constants,
|
||||
** not arbitrary expresssions, we allowed some combining of LIMIT and OFFSET
|
||||
** not arbitrary expressions, we allowed some combining of LIMIT and OFFSET
|
||||
** because they could be computed at compile-time. But when LIMIT and OFFSET
|
||||
** became arbitrary expressions, we were forced to add restrictions (13)
|
||||
** and (14). */
|
||||
|
@ -3267,8 +3274,14 @@ static int flattenSubquery(
|
|||
if( pSub->pLimit && (p->selFlags & SF_Distinct)!=0 ){
|
||||
return 0; /* Restriction (21) */
|
||||
}
|
||||
if( pSub->selFlags & SF_Recursive ) return 0; /* Restriction (22) */
|
||||
if( (p->selFlags & SF_Recursive) && pSub->pPrior ) return 0; /* (23) */
|
||||
testcase( pSub->selFlags & SF_Recursive );
|
||||
testcase( pSub->selFlags & SF_MinMaxAgg );
|
||||
if( pSub->selFlags & (SF_Recursive|SF_MinMaxAgg) ){
|
||||
return 0; /* Restrictions (22) and (24) */
|
||||
}
|
||||
if( (p->selFlags & SF_Recursive) && pSub->pPrior ){
|
||||
return 0; /* Restriction (23) */
|
||||
}
|
||||
|
||||
/* OBSOLETE COMMENT 1:
|
||||
** Restriction 3: If the subquery is a join, make sure the subquery is
|
||||
|
@ -3628,7 +3641,7 @@ static u8 minMaxQuery(AggInfo *pAggInfo, ExprList **ppMinMax){
|
|||
|
||||
/*
|
||||
** The select statement passed as the first argument is an aggregate query.
|
||||
** The second argment is the associated aggregate-info object. This
|
||||
** The second argument is the associated aggregate-info object. This
|
||||
** function tests if the SELECT is of the form:
|
||||
**
|
||||
** SELECT count(*) FROM <tbl>
|
||||
|
@ -3958,10 +3971,10 @@ static void selectPopWith(Walker *pWalker, Select *p){
|
|||
** fill pTabList->a[].pSelect with a copy of the SELECT statement
|
||||
** that implements the view. A copy is made of the view's SELECT
|
||||
** statement so that we can freely modify or delete that statement
|
||||
** without worrying about messing up the presistent representation
|
||||
** without worrying about messing up the persistent representation
|
||||
** of the view.
|
||||
**
|
||||
** (3) Add terms to the WHERE clause to accomodate the NATURAL keyword
|
||||
** (3) Add terms to the WHERE clause to accommodate the NATURAL keyword
|
||||
** on joins and the ON and USING clause of joins.
|
||||
**
|
||||
** (4) Scan the list of columns in the result set (pEList) looking
|
||||
|
|
68
src/shell.c
68
src/shell.c
|
@ -33,6 +33,9 @@
|
|||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include "sqlite3.h"
|
||||
#if SQLITE_USER_AUTHENTICATION
|
||||
# include "sqlite3userauth.h"
|
||||
#endif
|
||||
#include <ctype.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
|
@ -3435,6 +3438,71 @@ static int do_meta_command(char *zLine, ShellState *p){
|
|||
#endif
|
||||
}else
|
||||
|
||||
#if SQLITE_USER_AUTHENTICATION
|
||||
if( c=='u' && strncmp(azArg[0], "user", n)==0 ){
|
||||
if( nArg<2 ){
|
||||
fprintf(stderr, "Usage: .user SUBCOMMAND ...\n");
|
||||
rc = 1;
|
||||
goto meta_command_exit;
|
||||
}
|
||||
open_db(p, 0);
|
||||
if( strcmp(azArg[1],"login")==0 ){
|
||||
if( nArg!=4 ){
|
||||
fprintf(stderr, "Usage: .user login USER PASSWORD\n");
|
||||
rc = 1;
|
||||
goto meta_command_exit;
|
||||
}
|
||||
rc = sqlite3_user_authenticate(p->db, azArg[2], azArg[3],
|
||||
(int)strlen(azArg[3]));
|
||||
if( rc ){
|
||||
fprintf(stderr, "Authentication failed for user %s\n", azArg[2]);
|
||||
rc = 1;
|
||||
}
|
||||
}else if( strcmp(azArg[1],"add")==0 ){
|
||||
if( nArg!=5 ){
|
||||
fprintf(stderr, "Usage: .user add USER PASSWORD ISADMIN\n");
|
||||
rc = 1;
|
||||
goto meta_command_exit;
|
||||
}
|
||||
rc = sqlite3_user_add(p->db, azArg[2],
|
||||
azArg[3], (int)strlen(azArg[3]),
|
||||
booleanValue(azArg[4]));
|
||||
if( rc ){
|
||||
fprintf(stderr, "User-Add failed: %d\n", rc);
|
||||
rc = 1;
|
||||
}
|
||||
}else if( strcmp(azArg[1],"edit")==0 ){
|
||||
if( nArg!=5 ){
|
||||
fprintf(stderr, "Usage: .user edit USER PASSWORD ISADMIN\n");
|
||||
rc = 1;
|
||||
goto meta_command_exit;
|
||||
}
|
||||
rc = sqlite3_user_change(p->db, azArg[2],
|
||||
azArg[3], (int)strlen(azArg[3]),
|
||||
booleanValue(azArg[4]));
|
||||
if( rc ){
|
||||
fprintf(stderr, "User-Edit failed: %d\n", rc);
|
||||
rc = 1;
|
||||
}
|
||||
}else if( strcmp(azArg[1],"delete")==0 ){
|
||||
if( nArg!=3 ){
|
||||
fprintf(stderr, "Usage: .user delete USER\n");
|
||||
rc = 1;
|
||||
goto meta_command_exit;
|
||||
}
|
||||
rc = sqlite3_user_delete(p->db, azArg[2]);
|
||||
if( rc ){
|
||||
fprintf(stderr, "User-Delete failed: %d\n", rc);
|
||||
rc = 1;
|
||||
}
|
||||
}else{
|
||||
fprintf(stderr, "Usage: .user login|add|edit|delete ...\n");
|
||||
rc = 1;
|
||||
goto meta_command_exit;
|
||||
}
|
||||
}else
|
||||
#endif /* SQLITE_USER_AUTHENTICATION */
|
||||
|
||||
if( c=='v' && strncmp(azArg[0], "version", n)==0 ){
|
||||
fprintf(p->out, "SQLite %s %s\n" /*extra-version-info*/,
|
||||
sqlite3_libversion(), sqlite3_sourceid());
|
||||
|
|
|
@ -492,6 +492,7 @@ int sqlite3_exec(
|
|||
#define SQLITE_NOTICE_RECOVER_WAL (SQLITE_NOTICE | (1<<8))
|
||||
#define SQLITE_NOTICE_RECOVER_ROLLBACK (SQLITE_NOTICE | (2<<8))
|
||||
#define SQLITE_WARNING_AUTOINDEX (SQLITE_WARNING | (1<<8))
|
||||
#define SQLITE_AUTH_USER (SQLITE_AUTH | (1<<8))
|
||||
|
||||
/*
|
||||
** CAPI3REF: Flags For File Open Operations
|
||||
|
@ -2094,7 +2095,7 @@ int sqlite3_busy_handler(sqlite3*, int(*)(void*,int), void*);
|
|||
** turns off all busy handlers.
|
||||
**
|
||||
** ^(There can only be a single busy handler for a particular
|
||||
** [database connection] any any given moment. If another busy handler
|
||||
** [database connection] at any given moment. If another busy handler
|
||||
** was defined (using [sqlite3_busy_handler()]) prior to calling
|
||||
** this routine, that other busy handler is cleared.)^
|
||||
**
|
||||
|
@ -2298,6 +2299,10 @@ char *sqlite3_vsnprintf(int,char*,const char*, va_list);
|
|||
** sqlite3_malloc() is zero or negative then sqlite3_malloc() returns
|
||||
** a NULL pointer.
|
||||
**
|
||||
** ^The sqlite3_malloc64(N) routine works just like
|
||||
** sqlite3_malloc(N) except that N is an unsigned 64-bit integer instead
|
||||
** of a signed 32-bit integer.
|
||||
**
|
||||
** ^Calling sqlite3_free() with a pointer previously returned
|
||||
** by sqlite3_malloc() or sqlite3_realloc() releases that memory so
|
||||
** that it might be reused. ^The sqlite3_free() routine is
|
||||
|
@ -2309,24 +2314,38 @@ char *sqlite3_vsnprintf(int,char*,const char*, va_list);
|
|||
** might result if sqlite3_free() is called with a non-NULL pointer that
|
||||
** was not obtained from sqlite3_malloc() or sqlite3_realloc().
|
||||
**
|
||||
** ^(The sqlite3_realloc() interface attempts to resize a
|
||||
** prior memory allocation to be at least N bytes, where N is the
|
||||
** second parameter. The memory allocation to be resized is the first
|
||||
** parameter.)^ ^ If the first parameter to sqlite3_realloc()
|
||||
** ^The sqlite3_realloc(X,N) interface attempts to resize a
|
||||
** prior memory allocation X to be at least N bytes.
|
||||
** ^If the X parameter to sqlite3_realloc(X,N)
|
||||
** is a NULL pointer then its behavior is identical to calling
|
||||
** sqlite3_malloc(N) where N is the second parameter to sqlite3_realloc().
|
||||
** ^If the second parameter to sqlite3_realloc() is zero or
|
||||
** sqlite3_malloc(N).
|
||||
** ^If the N parameter to sqlite3_realloc(X,N) is zero or
|
||||
** negative then the behavior is exactly the same as calling
|
||||
** sqlite3_free(P) where P is the first parameter to sqlite3_realloc().
|
||||
** ^sqlite3_realloc() returns a pointer to a memory allocation
|
||||
** of at least N bytes in size or NULL if sufficient memory is unavailable.
|
||||
** sqlite3_free(X).
|
||||
** ^sqlite3_realloc(X,N) returns a pointer to a memory allocation
|
||||
** of at least N bytes in size or NULL if insufficient memory is available.
|
||||
** ^If M is the size of the prior allocation, then min(N,M) bytes
|
||||
** of the prior allocation are copied into the beginning of buffer returned
|
||||
** by sqlite3_realloc() and the prior allocation is freed.
|
||||
** ^If sqlite3_realloc() returns NULL, then the prior allocation
|
||||
** is not freed.
|
||||
** by sqlite3_realloc(X,N) and the prior allocation is freed.
|
||||
** ^If sqlite3_realloc(X,N) returns NULL and N is positive, then the
|
||||
** prior allocation is not freed.
|
||||
**
|
||||
** ^The memory returned by sqlite3_malloc() and sqlite3_realloc()
|
||||
** ^The sqlite3_realloc64(X,N) interfaces works the same as
|
||||
** sqlite3_realloc(X,N) except that N is a 64-bit unsigned integer instead
|
||||
** of a 32-bit signed integer.
|
||||
**
|
||||
** ^If X is a memory allocation previously obtained from sqlite3_malloc(),
|
||||
** sqlite3_malloc64(), sqlite3_realloc(), or sqlite3_realloc64(), then
|
||||
** sqlite3_msize(X) returns the size of that memory allocation in bytes.
|
||||
** ^The value returned by sqlite3_msize(X) might be larger than the number
|
||||
** of bytes requested when X was allocated. ^If X is a NULL pointer then
|
||||
** sqlite3_msize(X) returns zero. If X points to something that is not
|
||||
** the beginning of memory allocation, or if it points to a formerly
|
||||
** valid memory allocation that has now been freed, then the behavior
|
||||
** of sqlite3_msize(X) is undefined and possibly harmful.
|
||||
**
|
||||
** ^The memory returned by sqlite3_malloc(), sqlite3_realloc(),
|
||||
** sqlite3_malloc64(), and sqlite3_realloc64()
|
||||
** is always aligned to at least an 8 byte boundary, or to a
|
||||
** 4 byte boundary if the [SQLITE_4_BYTE_ALIGNED_MALLOC] compile-time
|
||||
** option is used.
|
||||
|
@ -2354,8 +2373,11 @@ char *sqlite3_vsnprintf(int,char*,const char*, va_list);
|
|||
** [sqlite3_free()] or [sqlite3_realloc()].
|
||||
*/
|
||||
void *sqlite3_malloc(int);
|
||||
void *sqlite3_malloc64(sqlite3_uint64);
|
||||
void *sqlite3_realloc(void*, int);
|
||||
void *sqlite3_realloc64(void*, sqlite3_uint64);
|
||||
void sqlite3_free(void*);
|
||||
sqlite3_uint64 sqlite3_msize(void*);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Memory Allocator Statistics
|
||||
|
@ -3364,7 +3386,8 @@ typedef struct sqlite3_context sqlite3_context;
|
|||
** If the fourth parameter to sqlite3_bind_blob() is negative, then
|
||||
** the behavior is undefined.
|
||||
** If a non-negative fourth parameter is provided to sqlite3_bind_text()
|
||||
** or sqlite3_bind_text16() then that parameter must be the byte offset
|
||||
** or sqlite3_bind_text16() or sqlite3_bind_text64() then
|
||||
** that parameter must be the byte offset
|
||||
** where the NUL terminator would occur assuming the string were NUL
|
||||
** terminated. If any NUL characters occur at byte offsets less than
|
||||
** the value of the fourth parameter then the resulting string value will
|
||||
|
@ -3383,6 +3406,14 @@ typedef struct sqlite3_context sqlite3_context;
|
|||
** SQLite makes its own private copy of the data immediately, before
|
||||
** the sqlite3_bind_*() routine returns.
|
||||
**
|
||||
** ^The sixth argument to sqlite3_bind_text64() must be one of
|
||||
** [SQLITE_UTF8], [SQLITE_UTF16], [SQLITE_UTF16BE], or [SQLITE_UTF16LE]
|
||||
** to specify the encoding of the text in the third parameter. If
|
||||
** the sixth argument to sqlite3_bind_text64() is not how of the
|
||||
** allowed values shown above, or if the text encoding is different
|
||||
** from the encoding specified by the sixth parameter, then the behavior
|
||||
** is undefined.
|
||||
**
|
||||
** ^The sqlite3_bind_zeroblob() routine binds a BLOB of length N that
|
||||
** is filled with zeroes. ^A zeroblob uses a fixed amount of memory
|
||||
** (just an integer to hold its size) while it is being processed.
|
||||
|
@ -3403,6 +3434,9 @@ typedef struct sqlite3_context sqlite3_context;
|
|||
**
|
||||
** ^The sqlite3_bind_* routines return [SQLITE_OK] on success or an
|
||||
** [error code] if anything goes wrong.
|
||||
** ^[SQLITE_TOOBIG] might be returned if the size of a string or BLOB
|
||||
** exceeds limits imposed by [sqlite3_limit]([SQLITE_LIMIT_LENGTH]) or
|
||||
** [SQLITE_MAX_LENGTH].
|
||||
** ^[SQLITE_RANGE] is returned if the parameter
|
||||
** index is out of range. ^[SQLITE_NOMEM] is returned if malloc() fails.
|
||||
**
|
||||
|
@ -3410,12 +3444,16 @@ typedef struct sqlite3_context sqlite3_context;
|
|||
** [sqlite3_bind_parameter_name()], and [sqlite3_bind_parameter_index()].
|
||||
*/
|
||||
int sqlite3_bind_blob(sqlite3_stmt*, int, const void*, int n, void(*)(void*));
|
||||
int sqlite3_bind_blob64(sqlite3_stmt*, int, const void*, sqlite3_uint64,
|
||||
void(*)(void*));
|
||||
int sqlite3_bind_double(sqlite3_stmt*, int, double);
|
||||
int sqlite3_bind_int(sqlite3_stmt*, int, int);
|
||||
int sqlite3_bind_int64(sqlite3_stmt*, int, sqlite3_int64);
|
||||
int sqlite3_bind_null(sqlite3_stmt*, int);
|
||||
int sqlite3_bind_text(sqlite3_stmt*, int, const char*, int n, void(*)(void*));
|
||||
int sqlite3_bind_text(sqlite3_stmt*,int,const char*,int,void(*)(void*));
|
||||
int sqlite3_bind_text16(sqlite3_stmt*, int, const void*, int, void(*)(void*));
|
||||
int sqlite3_bind_text64(sqlite3_stmt*, int, const char*, sqlite3_uint64,
|
||||
void(*)(void*), unsigned char encoding);
|
||||
int sqlite3_bind_value(sqlite3_stmt*, int, const sqlite3_value*);
|
||||
int sqlite3_bind_zeroblob(sqlite3_stmt*, int, int n);
|
||||
|
||||
|
@ -4164,7 +4202,7 @@ SQLITE_DEPRECATED int sqlite3_memory_alarm(void(*)(void*,sqlite3_int64,int),
|
|||
** object results in undefined behavior.
|
||||
**
|
||||
** ^These routines work just like the corresponding [column access functions]
|
||||
** except that these routines take a single [protected sqlite3_value] object
|
||||
** except that these routines take a single [protected sqlite3_value] object
|
||||
** pointer instead of a [sqlite3_stmt*] pointer and an integer column number.
|
||||
**
|
||||
** ^The sqlite3_value_text16() interface extracts a UTF-16 string
|
||||
|
@ -4407,10 +4445,14 @@ typedef void (*sqlite3_destructor_type)(void*);
|
|||
** of the application-defined function to be NULL.
|
||||
**
|
||||
** ^The sqlite3_result_text(), sqlite3_result_text16(),
|
||||
** sqlite3_result_text16le(), and sqlite3_result_text16be() interfaces
|
||||
** sqlite3_result_text16le(), and sqlite3_result_text16be()
|
||||
** set the return value of the application-defined function to be
|
||||
** a text string which is represented as UTF-8, UTF-16 native byte order,
|
||||
** UTF-16 little endian, or UTF-16 big endian, respectively.
|
||||
** ^The sqlite3_result_text64() interface sets the return value of an
|
||||
** application-defined function to be a text string in an encoding
|
||||
** specified by the fifth (and last) parameter, which must be one
|
||||
** of [SQLITE_UTF8], [SQLITE_UTF16], [SQLITE_UTF16BE], or [SQLITE_UTF16LE].
|
||||
** ^SQLite takes the text result from the application from
|
||||
** the 2nd parameter of the sqlite3_result_text* interfaces.
|
||||
** ^If the 3rd parameter to the sqlite3_result_text* interfaces
|
||||
|
@ -4454,6 +4496,7 @@ typedef void (*sqlite3_destructor_type)(void*);
|
|||
** the [sqlite3_context] pointer, the results are undefined.
|
||||
*/
|
||||
void sqlite3_result_blob(sqlite3_context*, const void*, int, void(*)(void*));
|
||||
void sqlite3_result_blob64(sqlite3_context*,const void*,sqlite3_uint64,void(*)(void*));
|
||||
void sqlite3_result_double(sqlite3_context*, double);
|
||||
void sqlite3_result_error(sqlite3_context*, const char*, int);
|
||||
void sqlite3_result_error16(sqlite3_context*, const void*, int);
|
||||
|
@ -4464,6 +4507,8 @@ void sqlite3_result_int(sqlite3_context*, int);
|
|||
void sqlite3_result_int64(sqlite3_context*, sqlite3_int64);
|
||||
void sqlite3_result_null(sqlite3_context*);
|
||||
void sqlite3_result_text(sqlite3_context*, const char*, int, void(*)(void*));
|
||||
void sqlite3_result_text64(sqlite3_context*, const char*,sqlite3_uint64,
|
||||
void(*)(void*), unsigned char encoding);
|
||||
void sqlite3_result_text16(sqlite3_context*, const void*, int, void(*)(void*));
|
||||
void sqlite3_result_text16le(sqlite3_context*, const void*, int,void(*)(void*));
|
||||
void sqlite3_result_text16be(sqlite3_context*, const void*, int,void(*)(void*));
|
||||
|
@ -6357,12 +6402,12 @@ int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int resetFlg);
|
|||
** the current value is always zero.)^
|
||||
**
|
||||
** [[SQLITE_DBSTATUS_CACHE_USED]] ^(<dt>SQLITE_DBSTATUS_CACHE_USED</dt>
|
||||
** <dd>This parameter returns the approximate number of of bytes of heap
|
||||
** <dd>This parameter returns the approximate number of bytes of heap
|
||||
** memory used by all pager caches associated with the database connection.)^
|
||||
** ^The highwater mark associated with SQLITE_DBSTATUS_CACHE_USED is always 0.
|
||||
**
|
||||
** [[SQLITE_DBSTATUS_SCHEMA_USED]] ^(<dt>SQLITE_DBSTATUS_SCHEMA_USED</dt>
|
||||
** <dd>This parameter returns the approximate number of of bytes of heap
|
||||
** <dd>This parameter returns the approximate number of bytes of heap
|
||||
** memory used to store the schema for all databases associated
|
||||
** with the connection - main, temp, and any [ATTACH]-ed databases.)^
|
||||
** ^The full amount of memory used by the schemas is reported, even if the
|
||||
|
@ -6371,7 +6416,7 @@ int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int resetFlg);
|
|||
** ^The highwater mark associated with SQLITE_DBSTATUS_SCHEMA_USED is always 0.
|
||||
**
|
||||
** [[SQLITE_DBSTATUS_STMT_USED]] ^(<dt>SQLITE_DBSTATUS_STMT_USED</dt>
|
||||
** <dd>This parameter returns the approximate number of of bytes of heap
|
||||
** <dd>This parameter returns the approximate number of bytes of heap
|
||||
** and lookaside memory used by all prepared statements associated with
|
||||
** the database connection.)^
|
||||
** ^The highwater mark associated with SQLITE_DBSTATUS_STMT_USED is always 0.
|
||||
|
|
|
@ -28,7 +28,7 @@ typedef struct sqlite3_api_routines sqlite3_api_routines;
|
|||
** WARNING: In order to maintain backwards compatibility, add new
|
||||
** interfaces to the end of this structure only. If you insert new
|
||||
** interfaces in the middle of this structure, then older different
|
||||
** versions of SQLite will not be able to load each others' shared
|
||||
** versions of SQLite will not be able to load each other's shared
|
||||
** libraries!
|
||||
*/
|
||||
struct sqlite3_api_routines {
|
||||
|
@ -250,11 +250,28 @@ struct sqlite3_api_routines {
|
|||
const char *(*uri_parameter)(const char*,const char*);
|
||||
char *(*vsnprintf)(int,char*,const char*,va_list);
|
||||
int (*wal_checkpoint_v2)(sqlite3*,const char*,int,int*,int*);
|
||||
/* Version 3.8.7 and later */
|
||||
int (*auto_extension)(void(*)(void));
|
||||
int (*bind_blob64)(sqlite3_stmt*,int,const void*,sqlite3_uint64,
|
||||
void(*)(void*));
|
||||
int (*bind_text64)(sqlite3_stmt*,int,const char*,sqlite3_uint64,
|
||||
void(*)(void*),unsigned char);
|
||||
int (*cancel_auto_extension)(void(*)(void));
|
||||
int (*load_extension)(sqlite3*,const char*,const char*,char**);
|
||||
void *(*malloc64)(sqlite3_uint64);
|
||||
sqlite3_uint64 (*msize)(void*);
|
||||
void *(*realloc64)(void*,sqlite3_uint64);
|
||||
void (*reset_auto_extension)(void);
|
||||
void (*result_blob64)(sqlite3_context*,const void*,sqlite3_uint64,
|
||||
void(*)(void*));
|
||||
void (*result_text64)(sqlite3_context*,const char*,sqlite3_uint64,
|
||||
void(*)(void*), unsigned char);
|
||||
int (*strglob)(const char*,const char*);
|
||||
};
|
||||
|
||||
/*
|
||||
** The following macros redefine the API routines so that they are
|
||||
** redirected throught the global sqlite3_api structure.
|
||||
** redirected through the global sqlite3_api structure.
|
||||
**
|
||||
** This header file is also used by the loadext.c source file
|
||||
** (part of the main SQLite library - not an extension) so that
|
||||
|
@ -467,6 +484,19 @@ struct sqlite3_api_routines {
|
|||
#define sqlite3_uri_parameter sqlite3_api->uri_parameter
|
||||
#define sqlite3_uri_vsnprintf sqlite3_api->vsnprintf
|
||||
#define sqlite3_wal_checkpoint_v2 sqlite3_api->wal_checkpoint_v2
|
||||
/* Version 3.8.7 and later */
|
||||
#define sqlite3_auto_extension sqlite3_api->auto_extension
|
||||
#define sqlite3_bind_blob64 sqlite3_api->bind_blob64
|
||||
#define sqlite3_bind_text64 sqlite3_api->bind_text64
|
||||
#define sqlite3_cancel_auto_extension sqlite3_api->cancel_auto_extension
|
||||
#define sqlite3_load_extension sqlite3_api->load_extension
|
||||
#define sqlite3_malloc64 sqlite3_api->malloc64
|
||||
#define sqlite3_msize sqlite3_api->msize
|
||||
#define sqlite3_realloc64 sqlite3_api->realloc64
|
||||
#define sqlite3_reset_auto_extension sqlite3_api->reset_auto_extension
|
||||
#define sqlite3_result_blob64 sqlite3_api->result_blob64
|
||||
#define sqlite3_result_text64 sqlite3_api->result_text64
|
||||
#define sqlite3_strglob sqlite3_api->strglob
|
||||
#endif /* SQLITE_CORE */
|
||||
|
||||
#ifndef SQLITE_CORE
|
||||
|
|
|
@ -351,7 +351,7 @@
|
|||
#endif
|
||||
|
||||
/*
|
||||
** Return true (non-zero) if the input is a integer that is too large
|
||||
** Return true (non-zero) if the input is an integer that is too large
|
||||
** to fit in 32-bits. This macro is used inside of various testcase()
|
||||
** macros to verify that we have tested SQLite for large-file support.
|
||||
*/
|
||||
|
@ -639,7 +639,7 @@ extern const int sqlite3one;
|
|||
** all alignment restrictions correct.
|
||||
**
|
||||
** Except, if SQLITE_4_BYTE_ALIGNED_MALLOC is defined, then the
|
||||
** underlying malloc() implemention might return us 4-byte aligned
|
||||
** underlying malloc() implementation might return us 4-byte aligned
|
||||
** pointers. In that case, only verify 4-byte alignment.
|
||||
*/
|
||||
#ifdef SQLITE_4_BYTE_ALIGNED_MALLOC
|
||||
|
@ -988,6 +988,45 @@ struct FuncDefHash {
|
|||
FuncDef *a[23]; /* Hash table for functions */
|
||||
};
|
||||
|
||||
#ifdef SQLITE_USER_AUTHENTICATION
|
||||
/*
|
||||
** Information held in the "sqlite3" database connection object and used
|
||||
** to manage user authentication.
|
||||
*/
|
||||
typedef struct sqlite3_userauth sqlite3_userauth;
|
||||
struct sqlite3_userauth {
|
||||
u8 authLevel; /* Current authentication level */
|
||||
int nAuthPW; /* Size of the zAuthPW in bytes */
|
||||
char *zAuthPW; /* Password used to authenticate */
|
||||
char *zAuthUser; /* User name used to authenticate */
|
||||
};
|
||||
|
||||
/* Allowed values for sqlite3_userauth.authLevel */
|
||||
#define UAUTH_Unknown 0 /* Authentication not yet checked */
|
||||
#define UAUTH_Fail 1 /* User authentication failed */
|
||||
#define UAUTH_User 2 /* Authenticated as a normal user */
|
||||
#define UAUTH_Admin 3 /* Authenticated as an administrator */
|
||||
|
||||
/* Functions used only by user authorization logic */
|
||||
int sqlite3UserAuthTable(const char*);
|
||||
int sqlite3UserAuthCheckLogin(sqlite3*,const char*,u8*);
|
||||
void sqlite3UserAuthInit(sqlite3*);
|
||||
void sqlite3CryptFunc(sqlite3_context*,int,sqlite3_value**);
|
||||
|
||||
#endif /* SQLITE_USER_AUTHENTICATION */
|
||||
|
||||
/*
|
||||
** typedef for the authorization callback function.
|
||||
*/
|
||||
#ifdef SQLITE_USER_AUTHENTICATION
|
||||
typedef int (*sqlite3_xauth)(void*,int,const char*,const char*,const char*,
|
||||
const char*, const char*);
|
||||
#else
|
||||
typedef int (*sqlite3_xauth)(void*,int,const char*,const char*,const char*,
|
||||
const char*);
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
** Each database connection is an instance of the following structure.
|
||||
*/
|
||||
|
@ -1055,8 +1094,7 @@ struct sqlite3 {
|
|||
} u1;
|
||||
Lookaside lookaside; /* Lookaside malloc configuration */
|
||||
#ifndef SQLITE_OMIT_AUTHORIZATION
|
||||
int (*xAuth)(void*,int,const char*,const char*,const char*,const char*);
|
||||
/* Access authorization function */
|
||||
sqlite3_xauth xAuth; /* Access authorization function */
|
||||
void *pAuthArg; /* 1st argument to the access auth function */
|
||||
#endif
|
||||
#ifndef SQLITE_OMIT_PROGRESS_CALLBACK
|
||||
|
@ -1082,7 +1120,6 @@ struct sqlite3 {
|
|||
i64 nDeferredCons; /* Net deferred constraints this transaction. */
|
||||
i64 nDeferredImmCons; /* Net deferred immediate constraints */
|
||||
int *pnBytesFreed; /* If not NULL, increment this in DbFree() */
|
||||
|
||||
#ifdef SQLITE_ENABLE_UNLOCK_NOTIFY
|
||||
/* The following variables are all protected by the STATIC_MASTER
|
||||
** mutex, not by sqlite3.mutex. They are used by code in notify.c.
|
||||
|
@ -1100,6 +1137,9 @@ struct sqlite3 {
|
|||
void (*xUnlockNotify)(void **, int); /* Unlock notify callback */
|
||||
sqlite3 *pNextBlocked; /* Next in list of all blocked connections */
|
||||
#endif
|
||||
#ifdef SQLITE_USER_AUTHENTICATION
|
||||
sqlite3_userauth auth; /* User authentication information */
|
||||
#endif
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -1161,7 +1201,6 @@ struct sqlite3 {
|
|||
#define SQLITE_Transitive 0x0200 /* Transitive constraints */
|
||||
#define SQLITE_OmitNoopJoin 0x0400 /* Omit unused tables in joins */
|
||||
#define SQLITE_Stat3 0x0800 /* Use the SQLITE_STAT3 table */
|
||||
#define SQLITE_AdjustOutEst 0x1000 /* Adjust output estimates using WHERE */
|
||||
#define SQLITE_AllOpts 0xffff /* All optimizations */
|
||||
|
||||
/*
|
||||
|
@ -1248,6 +1287,7 @@ struct FuncDestructor {
|
|||
#define SQLITE_FUNC_COALESCE 0x200 /* Built-in coalesce() or ifnull() */
|
||||
#define SQLITE_FUNC_UNLIKELY 0x400 /* Built-in unlikely() function */
|
||||
#define SQLITE_FUNC_CONSTANT 0x800 /* Constant inputs give a constant output */
|
||||
#define SQLITE_FUNC_MINMAX 0x1000 /* True for min() and max() aggregates */
|
||||
|
||||
/*
|
||||
** The following three macros, FUNCTION(), LIKEFUNC() and AGGREGATE() are
|
||||
|
@ -1295,6 +1335,9 @@ struct FuncDestructor {
|
|||
#define AGGREGATE(zName, nArg, arg, nc, xStep, xFinal) \
|
||||
{nArg, SQLITE_UTF8|(nc*SQLITE_FUNC_NEEDCOLL), \
|
||||
SQLITE_INT_TO_PTR(arg), 0, 0, xStep,xFinal,#zName,0,0}
|
||||
#define AGGREGATE2(zName, nArg, arg, nc, xStep, xFinal, extraFlags) \
|
||||
{nArg, SQLITE_UTF8|(nc*SQLITE_FUNC_NEEDCOLL)|extraFlags, \
|
||||
SQLITE_INT_TO_PTR(arg), 0, 0, xStep,xFinal,#zName,0,0}
|
||||
|
||||
/*
|
||||
** All current savepoints are stored in a linked list starting at
|
||||
|
@ -2217,17 +2260,22 @@ struct NameContext {
|
|||
NameContext *pNext; /* Next outer name context. NULL for outermost */
|
||||
int nRef; /* Number of names resolved by this context */
|
||||
int nErr; /* Number of errors encountered while resolving names */
|
||||
u8 ncFlags; /* Zero or more NC_* flags defined below */
|
||||
u16 ncFlags; /* Zero or more NC_* flags defined below */
|
||||
};
|
||||
|
||||
/*
|
||||
** Allowed values for the NameContext, ncFlags field.
|
||||
**
|
||||
** Note: NC_MinMaxAgg must have the same value as SF_MinMaxAgg and
|
||||
** SQLITE_FUNC_MINMAX.
|
||||
**
|
||||
*/
|
||||
#define NC_AllowAgg 0x01 /* Aggregate functions are allowed here */
|
||||
#define NC_HasAgg 0x02 /* One or more aggregate functions seen */
|
||||
#define NC_IsCheck 0x04 /* True if resolving names in a CHECK constraint */
|
||||
#define NC_InAggFunc 0x08 /* True if analyzing arguments to an agg func */
|
||||
#define NC_PartIdx 0x10 /* True if resolving a partial index WHERE */
|
||||
#define NC_AllowAgg 0x0001 /* Aggregate functions are allowed here */
|
||||
#define NC_HasAgg 0x0002 /* One or more aggregate functions seen */
|
||||
#define NC_IsCheck 0x0004 /* True if resolving names in a CHECK constraint */
|
||||
#define NC_InAggFunc 0x0008 /* True if analyzing arguments to an agg func */
|
||||
#define NC_PartIdx 0x0010 /* True if resolving a partial index WHERE */
|
||||
#define NC_MinMaxAgg 0x1000 /* min/max aggregates seen. See note above */
|
||||
|
||||
/*
|
||||
** An instance of the following structure contains all information
|
||||
|
@ -2278,13 +2326,13 @@ struct Select {
|
|||
#define SF_UsesEphemeral 0x0008 /* Uses the OpenEphemeral opcode */
|
||||
#define SF_Expanded 0x0010 /* sqlite3SelectExpand() called on this */
|
||||
#define SF_HasTypeInfo 0x0020 /* FROM subqueries have Table metadata */
|
||||
/* 0x0040 NOT USED */
|
||||
#define SF_Compound 0x0040 /* Part of a compound query */
|
||||
#define SF_Values 0x0080 /* Synthesized from VALUES clause */
|
||||
/* 0x0100 NOT USED */
|
||||
#define SF_NestedFrom 0x0200 /* Part of a parenthesized FROM clause */
|
||||
#define SF_MaybeConvert 0x0400 /* Need convertCompoundSelectToSubquery() */
|
||||
#define SF_Recursive 0x0800 /* The recursive part of a recursive CTE */
|
||||
#define SF_Compound 0x1000 /* Part of a compound query */
|
||||
#define SF_MinMaxAgg 0x1000 /* Aggregate containing min() or max() */
|
||||
|
||||
|
||||
/*
|
||||
|
@ -2886,8 +2934,8 @@ int sqlite3CantopenError(int);
|
|||
|
||||
/*
|
||||
** FTS4 is really an extension for FTS3. It is enabled using the
|
||||
** SQLITE_ENABLE_FTS3 macro. But to avoid confusion we also all
|
||||
** the SQLITE_ENABLE_FTS4 macro to serve as an alisse for SQLITE_ENABLE_FTS3.
|
||||
** SQLITE_ENABLE_FTS3 macro. But to avoid confusion we also call
|
||||
** the SQLITE_ENABLE_FTS4 macro to serve as an alias for SQLITE_ENABLE_FTS3.
|
||||
*/
|
||||
#if defined(SQLITE_ENABLE_FTS4) && !defined(SQLITE_ENABLE_FTS3)
|
||||
# define SQLITE_ENABLE_FTS3
|
||||
|
@ -2934,15 +2982,15 @@ int sqlite3Strlen30(const char*);
|
|||
|
||||
int sqlite3MallocInit(void);
|
||||
void sqlite3MallocEnd(void);
|
||||
void *sqlite3Malloc(int);
|
||||
void *sqlite3MallocZero(int);
|
||||
void *sqlite3DbMallocZero(sqlite3*, int);
|
||||
void *sqlite3DbMallocRaw(sqlite3*, int);
|
||||
void *sqlite3Malloc(u64);
|
||||
void *sqlite3MallocZero(u64);
|
||||
void *sqlite3DbMallocZero(sqlite3*, u64);
|
||||
void *sqlite3DbMallocRaw(sqlite3*, u64);
|
||||
char *sqlite3DbStrDup(sqlite3*,const char*);
|
||||
char *sqlite3DbStrNDup(sqlite3*,const char*, int);
|
||||
void *sqlite3Realloc(void*, int);
|
||||
void *sqlite3DbReallocOrFree(sqlite3 *, void *, int);
|
||||
void *sqlite3DbRealloc(sqlite3 *, void *, int);
|
||||
char *sqlite3DbStrNDup(sqlite3*,const char*, u64);
|
||||
void *sqlite3Realloc(void*, u64);
|
||||
void *sqlite3DbReallocOrFree(sqlite3 *, void *, u64);
|
||||
void *sqlite3DbRealloc(sqlite3 *, void *, u64);
|
||||
void sqlite3DbFree(sqlite3*, void*);
|
||||
int sqlite3MallocSize(void*);
|
||||
int sqlite3DbMallocSize(sqlite3*, void*);
|
||||
|
@ -3483,7 +3531,7 @@ int sqlite3Stat4Column(sqlite3*, const void*, int, int, sqlite3_value**);
|
|||
/*
|
||||
** The interface to the LEMON-generated parser
|
||||
*/
|
||||
void *sqlite3ParserAlloc(void*(*)(size_t));
|
||||
void *sqlite3ParserAlloc(void*(*)(u64));
|
||||
void sqlite3ParserFree(void*, void(*)(void*));
|
||||
void sqlite3Parser(void*, int, Token, Parse*);
|
||||
#ifdef YYTRACKMAXSTACKDEPTH
|
||||
|
|
12
src/table.c
12
src/table.c
|
@ -29,10 +29,10 @@
|
|||
typedef struct TabResult {
|
||||
char **azResult; /* Accumulated output */
|
||||
char *zErrMsg; /* Error message text, if an error occurs */
|
||||
int nAlloc; /* Slots allocated for azResult[] */
|
||||
int nRow; /* Number of rows in the result */
|
||||
int nColumn; /* Number of columns in the result */
|
||||
int nData; /* Slots used in azResult[]. (nRow+1)*nColumn */
|
||||
u32 nAlloc; /* Slots allocated for azResult[] */
|
||||
u32 nRow; /* Number of rows in the result */
|
||||
u32 nColumn; /* Number of columns in the result */
|
||||
u32 nData; /* Slots used in azResult[]. (nRow+1)*nColumn */
|
||||
int rc; /* Return code from sqlite3_exec() */
|
||||
} TabResult;
|
||||
|
||||
|
@ -58,7 +58,7 @@ static int sqlite3_get_table_cb(void *pArg, int nCol, char **argv, char **colv){
|
|||
if( p->nData + need > p->nAlloc ){
|
||||
char **azNew;
|
||||
p->nAlloc = p->nAlloc*2 + need;
|
||||
azNew = sqlite3_realloc( p->azResult, sizeof(char*)*p->nAlloc );
|
||||
azNew = sqlite3_realloc64( p->azResult, sizeof(char*)*p->nAlloc );
|
||||
if( azNew==0 ) goto malloc_failed;
|
||||
p->azResult = azNew;
|
||||
}
|
||||
|
@ -182,7 +182,7 @@ int sqlite3_get_table(
|
|||
** This routine frees the space the sqlite3_get_table() malloced.
|
||||
*/
|
||||
void sqlite3_free_table(
|
||||
char **azResult /* Result returned from from sqlite3_get_table() */
|
||||
char **azResult /* Result returned from sqlite3_get_table() */
|
||||
){
|
||||
if( azResult ){
|
||||
int i, n;
|
||||
|
|
|
@ -760,7 +760,7 @@ static void tclSqlFunc(sqlite3_context *context, int argc, sqlite3_value**argv){
|
|||
/* If there are arguments to the function, make a shallow copy of the
|
||||
** script object, lappend the arguments, then evaluate the copy.
|
||||
**
|
||||
** By "shallow" copy, we mean a only the outer list Tcl_Obj is duplicated.
|
||||
** By "shallow" copy, we mean only the outer list Tcl_Obj is duplicated.
|
||||
** The new Tcl_Obj contains pointers to the original list elements.
|
||||
** That way, when Tcl_EvalObjv() is run and shimmers the first element
|
||||
** of the list to tclCmdNameType, that alternate representation will
|
||||
|
@ -872,6 +872,9 @@ static int auth_callback(
|
|||
const char *zArg2,
|
||||
const char *zArg3,
|
||||
const char *zArg4
|
||||
#ifdef SQLITE_USER_AUTHENTICATION
|
||||
,const char *zArg5
|
||||
#endif
|
||||
){
|
||||
const char *zCode;
|
||||
Tcl_DString str;
|
||||
|
@ -924,6 +927,9 @@ static int auth_callback(
|
|||
Tcl_DStringAppendElement(&str, zArg2 ? zArg2 : "");
|
||||
Tcl_DStringAppendElement(&str, zArg3 ? zArg3 : "");
|
||||
Tcl_DStringAppendElement(&str, zArg4 ? zArg4 : "");
|
||||
#ifdef SQLITE_USER_AUTHENTICATION
|
||||
Tcl_DStringAppendElement(&str, zArg5 ? zArg5 : "");
|
||||
#endif
|
||||
rc = Tcl_GlobalEval(pDb->interp, Tcl_DStringValue(&str));
|
||||
Tcl_DStringFree(&str);
|
||||
zReply = rc==TCL_OK ? Tcl_GetStringResult(pDb->interp) : "SQLITE_DENY";
|
||||
|
@ -1700,8 +1706,11 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
|||
pDb->zAuth = 0;
|
||||
}
|
||||
if( pDb->zAuth ){
|
||||
typedef int (*sqlite3_auth_cb)(
|
||||
void*,int,const char*,const char*,
|
||||
const char*,const char*);
|
||||
pDb->interp = interp;
|
||||
sqlite3_set_authorizer(pDb->db, auth_callback, pDb);
|
||||
sqlite3_set_authorizer(pDb->db,(sqlite3_auth_cb)auth_callback,pDb);
|
||||
}else{
|
||||
sqlite3_set_authorizer(pDb->db, 0, 0);
|
||||
}
|
||||
|
|
137
src/test1.c
137
src/test1.c
|
@ -2605,7 +2605,7 @@ static int test_bind(
|
|||
** SQLite selected to call. The TCL test script implements the
|
||||
** "test_collate" proc.
|
||||
**
|
||||
** Note that this will only work with one intepreter at a time, as the
|
||||
** Note that this will only work with one interpreter at a time, as the
|
||||
** interp pointer to use when evaluating the TCL script is stored in
|
||||
** pTestCollateInterp.
|
||||
*/
|
||||
|
@ -3758,7 +3758,7 @@ static int test_prepare_v2(
|
|||
** Usage: sqlite3_prepare_tkt3134 DB
|
||||
**
|
||||
** Generate a prepared statement for a zero-byte string as a test
|
||||
** for ticket #3134. The string should be preceeded by a zero byte.
|
||||
** for ticket #3134. The string should be preceded by a zero byte.
|
||||
*/
|
||||
static int test_prepare_tkt3134(
|
||||
void * clientData,
|
||||
|
@ -6561,6 +6561,132 @@ static int testTransactionRestore(
|
|||
return TCL_OK;
|
||||
}
|
||||
|
||||
#ifdef SQLITE_USER_AUTHENTICATION
|
||||
#include "sqlite3userauth.h"
|
||||
/*
|
||||
** tclcmd: sqlite3_user_authenticate DB USERNAME PASSWORD
|
||||
*/
|
||||
static int test_user_authenticate(
|
||||
ClientData clientData, /* Unused */
|
||||
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
|
||||
int objc, /* Number of arguments */
|
||||
Tcl_Obj *CONST objv[] /* Command arguments */
|
||||
){
|
||||
char *zUser = 0;
|
||||
char *zPasswd = 0;
|
||||
int nPasswd = 0;
|
||||
sqlite3 *db;
|
||||
int rc;
|
||||
|
||||
if( objc!=4 ){
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "DB USERNAME PASSWORD");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ){
|
||||
return TCL_ERROR;
|
||||
}
|
||||
zUser = Tcl_GetString(objv[2]);
|
||||
zPasswd = Tcl_GetStringFromObj(objv[3], &nPasswd);
|
||||
rc = sqlite3_user_authenticate(db, zUser, zPasswd, nPasswd);
|
||||
Tcl_SetResult(interp, (char *)t1ErrorName(rc), TCL_STATIC);
|
||||
return TCL_OK;
|
||||
}
|
||||
#endif /* SQLITE_USER_AUTHENTICATION */
|
||||
|
||||
#ifdef SQLITE_USER_AUTHENTICATION
|
||||
/*
|
||||
** tclcmd: sqlite3_user_add DB USERNAME PASSWORD ISADMIN
|
||||
*/
|
||||
static int test_user_add(
|
||||
ClientData clientData, /* Unused */
|
||||
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
|
||||
int objc, /* Number of arguments */
|
||||
Tcl_Obj *CONST objv[] /* Command arguments */
|
||||
){
|
||||
char *zUser = 0;
|
||||
char *zPasswd = 0;
|
||||
int nPasswd = 0;
|
||||
int isAdmin = 0;
|
||||
sqlite3 *db;
|
||||
int rc;
|
||||
|
||||
if( objc!=5 ){
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "DB USERNAME PASSWORD ISADMIN");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ){
|
||||
return TCL_ERROR;
|
||||
}
|
||||
zUser = Tcl_GetString(objv[2]);
|
||||
zPasswd = Tcl_GetStringFromObj(objv[3], &nPasswd);
|
||||
Tcl_GetBooleanFromObj(interp, objv[4], &isAdmin);
|
||||
rc = sqlite3_user_add(db, zUser, zPasswd, nPasswd, isAdmin);
|
||||
Tcl_SetResult(interp, (char *)t1ErrorName(rc), TCL_STATIC);
|
||||
return TCL_OK;
|
||||
}
|
||||
#endif /* SQLITE_USER_AUTHENTICATION */
|
||||
|
||||
#ifdef SQLITE_USER_AUTHENTICATION
|
||||
/*
|
||||
** tclcmd: sqlite3_user_change DB USERNAME PASSWORD ISADMIN
|
||||
*/
|
||||
static int test_user_change(
|
||||
ClientData clientData, /* Unused */
|
||||
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
|
||||
int objc, /* Number of arguments */
|
||||
Tcl_Obj *CONST objv[] /* Command arguments */
|
||||
){
|
||||
char *zUser = 0;
|
||||
char *zPasswd = 0;
|
||||
int nPasswd = 0;
|
||||
int isAdmin = 0;
|
||||
sqlite3 *db;
|
||||
int rc;
|
||||
|
||||
if( objc!=5 ){
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "DB USERNAME PASSWORD ISADMIN");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ){
|
||||
return TCL_ERROR;
|
||||
}
|
||||
zUser = Tcl_GetString(objv[2]);
|
||||
zPasswd = Tcl_GetStringFromObj(objv[3], &nPasswd);
|
||||
Tcl_GetBooleanFromObj(interp, objv[4], &isAdmin);
|
||||
rc = sqlite3_user_change(db, zUser, zPasswd, nPasswd, isAdmin);
|
||||
Tcl_SetResult(interp, (char *)t1ErrorName(rc), TCL_STATIC);
|
||||
return TCL_OK;
|
||||
}
|
||||
#endif /* SQLITE_USER_AUTHENTICATION */
|
||||
|
||||
#ifdef SQLITE_USER_AUTHENTICATION
|
||||
/*
|
||||
** tclcmd: sqlite3_user_delete DB USERNAME
|
||||
*/
|
||||
static int test_user_delete(
|
||||
ClientData clientData, /* Unused */
|
||||
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
|
||||
int objc, /* Number of arguments */
|
||||
Tcl_Obj *CONST objv[] /* Command arguments */
|
||||
){
|
||||
char *zUser = 0;
|
||||
sqlite3 *db;
|
||||
int rc;
|
||||
|
||||
if( objc!=3 ){
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "DB USERNAME");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ){
|
||||
return TCL_ERROR;
|
||||
}
|
||||
zUser = Tcl_GetString(objv[2]);
|
||||
rc = sqlite3_user_delete(db, zUser);
|
||||
Tcl_SetResult(interp, (char *)t1ErrorName(rc), TCL_STATIC);
|
||||
return TCL_OK;
|
||||
}
|
||||
#endif /* SQLITE_USER_AUTHENTICATION */
|
||||
|
||||
/*
|
||||
** Register commands with the TCL interpreter.
|
||||
*/
|
||||
|
@ -6800,7 +6926,14 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
|
|||
{ "sorter_test_sort4_helper", sorter_test_sort4_helper },
|
||||
{ "sqlite3_transaction_save", testTransactionSave },
|
||||
{ "sqlite3_transaction_restore", testTransactionRestore },
|
||||
#ifdef SQLITE_USER_AUTHENTICATION
|
||||
{ "sqlite3_user_authenticate", test_user_authenticate, 0 },
|
||||
{ "sqlite3_user_add", test_user_add, 0 },
|
||||
{ "sqlite3_user_change", test_user_change, 0 },
|
||||
{ "sqlite3_user_delete", test_user_delete, 0 },
|
||||
#endif
|
||||
};
|
||||
|
||||
static int bitmask_size = sizeof(Bitmask)*8;
|
||||
int i;
|
||||
extern int sqlite3_sync_count, sqlite3_fullsync_count;
|
||||
|
|
|
@ -603,6 +603,12 @@ Tcl_SetVar2(interp, "sqlite_options", "mergesort", "1", TCL_GLOBAL_ONLY);
|
|||
Tcl_SetVar2(interp, "sqlite_options", "secure_delete", "0", TCL_GLOBAL_ONLY);
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_USER_AUTHENTICATION
|
||||
Tcl_SetVar2(interp, "sqlite_options", "userauth", "1", TCL_GLOBAL_ONLY);
|
||||
#else
|
||||
Tcl_SetVar2(interp, "sqlite_options", "userauth", "0", TCL_GLOBAL_ONLY);
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_MULTIPLEX_EXT_OVWR
|
||||
Tcl_SetVar2(interp, "sqlite_options", "multiplex_ext_overwrite", "1", TCL_GLOBAL_ONLY);
|
||||
#else
|
||||
|
|
|
@ -37,13 +37,13 @@ struct sqlite3_intarray {
|
|||
typedef struct intarray_vtab intarray_vtab;
|
||||
typedef struct intarray_cursor intarray_cursor;
|
||||
|
||||
/* A intarray table object */
|
||||
/* An intarray table object */
|
||||
struct intarray_vtab {
|
||||
sqlite3_vtab base; /* Base class */
|
||||
sqlite3_intarray *pContent; /* Content of the integer array */
|
||||
};
|
||||
|
||||
/* A intarray cursor object */
|
||||
/* An intarray cursor object */
|
||||
struct intarray_cursor {
|
||||
sqlite3_vtab_cursor base; /* Base class */
|
||||
int i; /* Current cursor position */
|
||||
|
|
|
@ -696,6 +696,12 @@ static int test_memdebug_pending(
|
|||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** The following global variable keeps track of the number of tests
|
||||
** that have run. This variable is only useful when running in the
|
||||
** debugger.
|
||||
*/
|
||||
static int sqlite3_memdebug_title_count = 0;
|
||||
|
||||
/*
|
||||
** Usage: sqlite3_memdebug_settitle TITLE
|
||||
|
@ -713,6 +719,7 @@ static int test_memdebug_settitle(
|
|||
int objc,
|
||||
Tcl_Obj *CONST objv[]
|
||||
){
|
||||
sqlite3_memdebug_title_count++;
|
||||
if( objc!=2 ){
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "TITLE");
|
||||
return TCL_ERROR;
|
||||
|
@ -880,7 +887,7 @@ static int test_memdebug_log(
|
|||
**
|
||||
** Set the scratch memory buffer using SQLITE_CONFIG_SCRATCH.
|
||||
** The buffer is static and is of limited size. N might be
|
||||
** adjusted downward as needed to accomodate the requested size.
|
||||
** adjusted downward as needed to accommodate the requested size.
|
||||
** The revised value of N is returned.
|
||||
**
|
||||
** A negative SIZE causes the buffer pointer to be NULL.
|
||||
|
@ -920,7 +927,7 @@ static int test_config_scratch(
|
|||
**
|
||||
** Set the page-cache memory buffer using SQLITE_CONFIG_PAGECACHE.
|
||||
** The buffer is static and is of limited size. N might be
|
||||
** adjusted downward as needed to accomodate the requested size.
|
||||
** adjusted downward as needed to accommodate the requested size.
|
||||
** The revised value of N is returned.
|
||||
**
|
||||
** A negative SIZE causes the buffer pointer to be NULL.
|
||||
|
|
|
@ -189,7 +189,7 @@ static int schemaNext(sqlite3_vtab_cursor *cur){
|
|||
|
||||
/* Set zSql to the SQL to pull the list of tables from the
|
||||
** sqlite_master (or sqlite_temp_master) table of the database
|
||||
** identfied by the row pointed to by the SQL statement pCur->pDbList
|
||||
** identified by the row pointed to by the SQL statement pCur->pDbList
|
||||
** (iterating through a "PRAGMA database_list;" statement).
|
||||
*/
|
||||
if( sqlite3_column_int(pCur->pDbList, 0)==1 ){
|
||||
|
|
|
@ -77,7 +77,7 @@ const unsigned char ebcdicToAscii[] = {
|
|||
** end result.
|
||||
**
|
||||
** Ticket #1066. the SQL standard does not allow '$' in the
|
||||
** middle of identfiers. But many SQL implementations do.
|
||||
** middle of identifiers. But many SQL implementations do.
|
||||
** SQLite will allow '$' in identifiers for compatibility.
|
||||
** But the feature is undocumented.
|
||||
*/
|
||||
|
@ -398,7 +398,7 @@ int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzErrMsg){
|
|||
pParse->zTail = zSql;
|
||||
i = 0;
|
||||
assert( pzErrMsg!=0 );
|
||||
pEngine = sqlite3ParserAlloc((void*(*)(size_t))sqlite3Malloc);
|
||||
pEngine = sqlite3ParserAlloc(sqlite3Malloc);
|
||||
if( pEngine==0 ){
|
||||
db->mallocFailed = 1;
|
||||
return SQLITE_NOMEM;
|
||||
|
|
|
@ -127,7 +127,7 @@ void sqlite3BeginTrigger(
|
|||
** ^^^^^^^^
|
||||
**
|
||||
** To maintain backwards compatibility, ignore the database
|
||||
** name on pTableName if we are reparsing our of SQLITE_MASTER.
|
||||
** name on pTableName if we are reparsing out of SQLITE_MASTER.
|
||||
*/
|
||||
if( db->init.busy && iDb!=1 ){
|
||||
sqlite3DbFree(db, pTableName->a[0].zDatabase);
|
||||
|
|
10
src/update.c
10
src/update.c
|
@ -327,7 +327,7 @@ void sqlite3Update(
|
|||
}
|
||||
|
||||
/* If we are trying to update a view, realize that view into
|
||||
** a ephemeral table.
|
||||
** an ephemeral table.
|
||||
*/
|
||||
#if !defined(SQLITE_OMIT_VIEW) && !defined(SQLITE_OMIT_TRIGGER)
|
||||
if( isView ){
|
||||
|
@ -488,7 +488,7 @@ void sqlite3Update(
|
|||
}
|
||||
|
||||
/* Populate the array of registers beginning at regNew with the new
|
||||
** row data. This array is used to check constaints, create the new
|
||||
** row data. This array is used to check constants, create the new
|
||||
** table and index records, and as the values for any new.* references
|
||||
** made by triggers.
|
||||
**
|
||||
|
@ -668,7 +668,7 @@ update_cleanup:
|
|||
return;
|
||||
}
|
||||
/* Make sure "isView" and other macros defined above are undefined. Otherwise
|
||||
** thely may interfere with compilation of other functions in this file
|
||||
** they may interfere with compilation of other functions in this file
|
||||
** (or in another file, if this file becomes part of the amalgamation). */
|
||||
#ifdef isView
|
||||
#undef isView
|
||||
|
@ -681,7 +681,7 @@ update_cleanup:
|
|||
/*
|
||||
** Generate code for an UPDATE of a virtual table.
|
||||
**
|
||||
** The strategy is that we create an ephemerial table that contains
|
||||
** The strategy is that we create an ephemeral table that contains
|
||||
** for each row to be changed:
|
||||
**
|
||||
** (A) The original rowid of that row.
|
||||
|
@ -689,7 +689,7 @@ update_cleanup:
|
|||
** (C) The content of every column in the row.
|
||||
**
|
||||
** Then we loop over this ephemeral table and for each row in
|
||||
** the ephermeral table call VUpdate.
|
||||
** the ephemeral table call VUpdate.
|
||||
**
|
||||
** When finished, drop the ephemeral table.
|
||||
**
|
||||
|
|
|
@ -204,7 +204,7 @@ void sqlite3ErrorMsg(Parse *pParse, const char *zFormat, ...){
|
|||
** occur.
|
||||
**
|
||||
** 2002-Feb-14: This routine is extended to remove MS-Access style
|
||||
** brackets from around identifers. For example: "[a-b-c]" becomes
|
||||
** brackets from around identifiers. For example: "[a-b-c]" becomes
|
||||
** "a-b-c".
|
||||
*/
|
||||
int sqlite3Dequote(char *z){
|
||||
|
|
|
@ -87,7 +87,7 @@ static int execExecSql(sqlite3 *db, char **pzErrMsg, const char *zSql){
|
|||
** step (3) requires additional temporary disk space approximately equal
|
||||
** to the size of the original database for the rollback journal.
|
||||
** Hence, temporary disk space that is approximately 2x the size of the
|
||||
** orginal database is required. Every page of the database is written
|
||||
** original database is required. Every page of the database is written
|
||||
** approximately 3 times: Once for step (2) and twice for step (3).
|
||||
** Two writes per page are required in step (3) because the original
|
||||
** database content must be written into the rollback journal prior to
|
||||
|
|
|
@ -2560,7 +2560,7 @@ case OP_MakeRecord: {
|
|||
** ------------------------------------------------------------------------
|
||||
**
|
||||
** Data(0) is taken from register P1. Data(1) comes from register P1+1
|
||||
** and so froth.
|
||||
** and so forth.
|
||||
**
|
||||
** Each type field is a varint representing the serial type of the
|
||||
** corresponding data element (see sqlite3VdbeSerialType()). The
|
||||
|
@ -3547,7 +3547,7 @@ case OP_SeekGT: { /* jump, in3 */
|
|||
if( pC->isTable ){
|
||||
/* The input value in P3 might be of any type: integer, real, string,
|
||||
** blob, or NULL. But it needs to be an integer before we can do
|
||||
** the seek, so covert it. */
|
||||
** the seek, so convert it. */
|
||||
pIn3 = &aMem[pOp->p3];
|
||||
if( (pIn3->flags & (MEM_Int|MEM_Real))==0 ){
|
||||
applyNumericAffinity(pIn3, 0);
|
||||
|
|
|
@ -238,7 +238,7 @@ struct Mem {
|
|||
#endif
|
||||
|
||||
/*
|
||||
** Each auxilliary data pointer stored by a user defined function
|
||||
** Each auxiliary data pointer stored by a user defined function
|
||||
** implementation calling sqlite3_set_auxdata() is stored in an instance
|
||||
** of this structure. All such structures associated with a single VM
|
||||
** are stored in a linked list headed at Vdbe.pAuxData. All are destroyed
|
||||
|
@ -253,7 +253,7 @@ struct AuxData {
|
|||
};
|
||||
|
||||
/*
|
||||
** The "context" argument for a installable function. A pointer to an
|
||||
** The "context" argument for an installable function. A pointer to an
|
||||
** instance of this structure is the first argument to the routines used
|
||||
** implement the SQL functions.
|
||||
**
|
||||
|
|
|
@ -212,9 +212,12 @@ int sqlite3_value_type(sqlite3_value* pVal){
|
|||
** The following routines are used by user-defined functions to specify
|
||||
** the function result.
|
||||
**
|
||||
** The setStrOrError() funtion calls sqlite3VdbeMemSetStr() to store the
|
||||
** The setStrOrError() function calls sqlite3VdbeMemSetStr() to store the
|
||||
** result as a string or blob but if the string or blob is too large, it
|
||||
** then sets the error code to SQLITE_TOOBIG
|
||||
**
|
||||
** The invokeValueDestructor(P,X) routine invokes destructor function X()
|
||||
** on value P is not going to be used and need to be destroyed.
|
||||
*/
|
||||
static void setResultStrOrError(
|
||||
sqlite3_context *pCtx, /* Function context */
|
||||
|
@ -227,6 +230,22 @@ static void setResultStrOrError(
|
|||
sqlite3_result_error_toobig(pCtx);
|
||||
}
|
||||
}
|
||||
static int invokeValueDestructor(
|
||||
const void *p, /* Value to destroy */
|
||||
void (*xDel)(void*), /* The destructor */
|
||||
sqlite3_context *pCtx /* Set a SQLITE_TOOBIG error if no NULL */
|
||||
){
|
||||
assert( xDel!=SQLITE_DYNAMIC );
|
||||
if( xDel==0 ){
|
||||
/* noop */
|
||||
}else if( xDel==SQLITE_TRANSIENT ){
|
||||
/* noop */
|
||||
}else{
|
||||
xDel((void*)p);
|
||||
}
|
||||
if( pCtx ) sqlite3_result_error_toobig(pCtx);
|
||||
return SQLITE_TOOBIG;
|
||||
}
|
||||
void sqlite3_result_blob(
|
||||
sqlite3_context *pCtx,
|
||||
const void *z,
|
||||
|
@ -237,6 +256,20 @@ void sqlite3_result_blob(
|
|||
assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
|
||||
setResultStrOrError(pCtx, z, n, 0, xDel);
|
||||
}
|
||||
void sqlite3_result_blob64(
|
||||
sqlite3_context *pCtx,
|
||||
const void *z,
|
||||
sqlite3_uint64 n,
|
||||
void (*xDel)(void *)
|
||||
){
|
||||
assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
|
||||
assert( xDel!=SQLITE_DYNAMIC );
|
||||
if( n>0x7fffffff ){
|
||||
(void)invokeValueDestructor(z, xDel, pCtx);
|
||||
}else{
|
||||
setResultStrOrError(pCtx, z, (int)n, 0, xDel);
|
||||
}
|
||||
}
|
||||
void sqlite3_result_double(sqlite3_context *pCtx, double rVal){
|
||||
assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
|
||||
sqlite3VdbeMemSetDouble(pCtx->pOut, rVal);
|
||||
|
@ -276,6 +309,21 @@ void sqlite3_result_text(
|
|||
assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
|
||||
setResultStrOrError(pCtx, z, n, SQLITE_UTF8, xDel);
|
||||
}
|
||||
void sqlite3_result_text64(
|
||||
sqlite3_context *pCtx,
|
||||
const char *z,
|
||||
sqlite3_uint64 n,
|
||||
void (*xDel)(void *),
|
||||
unsigned char enc
|
||||
){
|
||||
assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
|
||||
assert( xDel!=SQLITE_DYNAMIC );
|
||||
if( n>0x7fffffff ){
|
||||
(void)invokeValueDestructor(z, xDel, pCtx);
|
||||
}else{
|
||||
setResultStrOrError(pCtx, z, (int)n, enc, xDel);
|
||||
}
|
||||
}
|
||||
#ifndef SQLITE_OMIT_UTF16
|
||||
void sqlite3_result_text16(
|
||||
sqlite3_context *pCtx,
|
||||
|
@ -645,7 +693,7 @@ void *sqlite3_aggregate_context(sqlite3_context *p, int nByte){
|
|||
}
|
||||
|
||||
/*
|
||||
** Return the auxilary data pointer, if any, for the iArg'th argument to
|
||||
** Return the auxiliary 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){
|
||||
|
@ -660,7 +708,7 @@ void *sqlite3_get_auxdata(sqlite3_context *pCtx, int iArg){
|
|||
}
|
||||
|
||||
/*
|
||||
** Set the auxilary data pointer and delete function, for the iArg'th
|
||||
** Set the auxiliary 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.
|
||||
*/
|
||||
|
@ -706,7 +754,7 @@ failed:
|
|||
|
||||
#ifndef SQLITE_OMIT_DEPRECATED
|
||||
/*
|
||||
** Return the number of times the Step function of a aggregate has been
|
||||
** Return the number of times the Step function of an aggregate has been
|
||||
** called.
|
||||
**
|
||||
** This function is deprecated. Do not use it for new code. It is
|
||||
|
@ -976,7 +1024,7 @@ const void *sqlite3_column_decltype16(sqlite3_stmt *pStmt, int N){
|
|||
/*
|
||||
** Return the name of the database from which a result column derives.
|
||||
** NULL is returned if the result column is an expression or constant or
|
||||
** anything else which is not an unabiguous reference to a database column.
|
||||
** anything else which is not an unambiguous reference to a database column.
|
||||
*/
|
||||
const char *sqlite3_column_database_name(sqlite3_stmt *pStmt, int N){
|
||||
return columnName(
|
||||
|
@ -992,7 +1040,7 @@ const void *sqlite3_column_database_name16(sqlite3_stmt *pStmt, int N){
|
|||
/*
|
||||
** Return the name of the table from which a result column derives.
|
||||
** NULL is returned if the result column is an expression or constant or
|
||||
** anything else which is not an unabiguous reference to a database column.
|
||||
** anything else which is not an unambiguous reference to a database column.
|
||||
*/
|
||||
const char *sqlite3_column_table_name(sqlite3_stmt *pStmt, int N){
|
||||
return columnName(
|
||||
|
@ -1008,7 +1056,7 @@ const void *sqlite3_column_table_name16(sqlite3_stmt *pStmt, int N){
|
|||
/*
|
||||
** Return the name of the table column from which a result column derives.
|
||||
** NULL is returned if the result column is an expression or constant or
|
||||
** anything else which is not an unabiguous reference to a database column.
|
||||
** anything else which is not an unambiguous reference to a database column.
|
||||
*/
|
||||
const char *sqlite3_column_origin_name(sqlite3_stmt *pStmt, int N){
|
||||
return columnName(
|
||||
|
@ -1125,6 +1173,20 @@ int sqlite3_bind_blob(
|
|||
){
|
||||
return bindText(pStmt, i, zData, nData, xDel, 0);
|
||||
}
|
||||
int sqlite3_bind_blob64(
|
||||
sqlite3_stmt *pStmt,
|
||||
int i,
|
||||
const void *zData,
|
||||
sqlite3_uint64 nData,
|
||||
void (*xDel)(void*)
|
||||
){
|
||||
assert( xDel!=SQLITE_DYNAMIC );
|
||||
if( nData>0x7fffffff ){
|
||||
return invokeValueDestructor(zData, xDel, 0);
|
||||
}else{
|
||||
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;
|
||||
|
@ -1166,6 +1228,22 @@ int sqlite3_bind_text(
|
|||
){
|
||||
return bindText(pStmt, i, zData, nData, xDel, SQLITE_UTF8);
|
||||
}
|
||||
int sqlite3_bind_text64(
|
||||
sqlite3_stmt *pStmt,
|
||||
int i,
|
||||
const char *zData,
|
||||
sqlite3_uint64 nData,
|
||||
void (*xDel)(void*),
|
||||
unsigned char enc
|
||||
){
|
||||
assert( xDel!=SQLITE_DYNAMIC );
|
||||
if( nData>0x7fffffff ){
|
||||
return invokeValueDestructor(zData, xDel, 0);
|
||||
}else{
|
||||
if( enc==SQLITE_UTF16 ) enc = SQLITE_UTF16NATIVE;
|
||||
return bindText(pStmt, i, zData, nData, xDel, enc);
|
||||
}
|
||||
}
|
||||
#ifndef SQLITE_OMIT_UTF16
|
||||
int sqlite3_bind_text16(
|
||||
sqlite3_stmt *pStmt,
|
||||
|
@ -1288,7 +1366,7 @@ int sqlite3TransferBindings(sqlite3_stmt *pFromStmt, sqlite3_stmt *pToStmt){
|
|||
** Deprecated external interface. Internal/core SQLite code
|
||||
** should call sqlite3TransferBindings.
|
||||
**
|
||||
** Is is misuse to call this routine with statements from different
|
||||
** It is misuse to call this routine with statements from different
|
||||
** database connections. But as this is a deprecated interface, we
|
||||
** will not bother to check for that condition.
|
||||
**
|
||||
|
|
|
@ -895,7 +895,7 @@ void sqlite3VdbeSetLineNumber(Vdbe *v, int iLine){
|
|||
** routine, then a pointer to a dummy VdbeOp will be returned. That opcode
|
||||
** is readable but not writable, though it is cast to a writable value.
|
||||
** The return of a dummy opcode allows the call to continue functioning
|
||||
** after a OOM fault without having to check to see if the return from
|
||||
** after an OOM fault without having to check to see if the return from
|
||||
** this routine is a valid pointer. But because the dummy.opcode is 0,
|
||||
** dummy will never be written to. This is verified by code inspection and
|
||||
** by running with Valgrind.
|
||||
|
@ -1610,9 +1610,9 @@ void sqlite3VdbeRewind(Vdbe *p){
|
|||
** After the VDBE has be prepped, it can be executed by one or more
|
||||
** calls to sqlite3VdbeExec().
|
||||
**
|
||||
** This function may be called exact once on a each virtual machine.
|
||||
** This function may be called exactly once on each virtual machine.
|
||||
** After this routine is called the VM has been "packaged" and is ready
|
||||
** to run. After this routine is called, futher calls to
|
||||
** to run. After this routine is called, further calls to
|
||||
** sqlite3VdbeAddOp() functions are prohibited. This routine disconnects
|
||||
** the Vdbe from the Parse object that helped generate it so that the
|
||||
** the Vdbe becomes an independent entity and the Parse object can be
|
||||
|
@ -1990,7 +1990,7 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){
|
|||
|
||||
/* The complex case - There is a multi-file write-transaction active.
|
||||
** This requires a master journal file to ensure the transaction is
|
||||
** committed atomicly.
|
||||
** committed atomically.
|
||||
*/
|
||||
#ifndef SQLITE_OMIT_DISKIO
|
||||
else{
|
||||
|
@ -2638,7 +2638,7 @@ int sqlite3VdbeFinalize(Vdbe *p){
|
|||
** from left to right), or
|
||||
**
|
||||
** * the corresponding bit in argument mask is clear (where the first
|
||||
** function parameter corrsponds to bit 0 etc.).
|
||||
** function parameter corresponds to bit 0 etc.).
|
||||
*/
|
||||
void sqlite3VdbeDeleteAuxData(Vdbe *pVdbe, int iOp, int mask){
|
||||
AuxData **pp = &pVdbe->pAuxData;
|
||||
|
@ -2742,7 +2742,7 @@ static int SQLITE_NOINLINE handleDeferredMoveto(VdbeCursor *p){
|
|||
** Something has moved cursor "p" out of place. Maybe the row it was
|
||||
** pointed to was deleted out from under it. Or maybe the btree was
|
||||
** rebalanced. Whatever the cause, try to restore "p" to the place it
|
||||
** is suppose to be pointing. If the row was deleted out from under the
|
||||
** is supposed to be pointing. If the row was deleted out from under the
|
||||
** cursor, set the cursor to point to a NULL row.
|
||||
*/
|
||||
static int SQLITE_NOINLINE handleMovedCursor(VdbeCursor *p){
|
||||
|
@ -3267,7 +3267,7 @@ static int vdbeRecordCompareDebug(
|
|||
assert( mem1.zMalloc==0 );
|
||||
|
||||
/* rc==0 here means that one of the keys ran out of fields and
|
||||
** all the fields up to that point were equal. Return the the default_rc
|
||||
** all the fields up to that point were equal. Return the default_rc
|
||||
** value. */
|
||||
rc = pPKey2->default_rc;
|
||||
|
||||
|
@ -3458,7 +3458,7 @@ static i64 vdbeRecordDecodeInt(u32 serial_type, const u8 *aKey){
|
|||
** specified by {nKey1, pKey1} and pPKey2. It returns a negative, zero
|
||||
** or positive integer if key1 is less than, equal to or
|
||||
** greater than key2. The {nKey1, pKey1} key must be a blob
|
||||
** created by th OP_MakeRecord opcode of the VDBE. The pPKey2
|
||||
** created by the OP_MakeRecord opcode of the VDBE. The pPKey2
|
||||
** key must be a parsed key such as obtained from
|
||||
** sqlite3VdbeParseRecord.
|
||||
**
|
||||
|
@ -3648,7 +3648,7 @@ int sqlite3VdbeRecordCompare(
|
|||
assert( mem1.zMalloc==0 );
|
||||
|
||||
/* rc==0 here means that one or both of the keys ran out of fields and
|
||||
** all the fields up to that point were equal. Return the the default_rc
|
||||
** all the fields up to that point were equal. Return the default_rc
|
||||
** value. */
|
||||
assert( CORRUPT_DB
|
||||
|| vdbeRecordCompareDebug(nKey1, pKey1, pPKey2, pPKey2->default_rc)
|
||||
|
|
|
@ -37,7 +37,7 @@ int sqlite3VdbeCheckMemInvariants(Mem *p){
|
|||
**
|
||||
** (1) Memory in Mem.zMalloc and managed by the Mem object
|
||||
** (2) Memory to be freed using Mem.xDel
|
||||
** (3) An ephermal string or blob
|
||||
** (3) An ephemeral string or blob
|
||||
** (4) A static string or blob
|
||||
*/
|
||||
if( (p->flags & (MEM_Str|MEM_Blob)) && p->z!=0 ){
|
||||
|
@ -240,7 +240,7 @@ int sqlite3VdbeMemNulTerminate(Mem *pMem){
|
|||
** 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.
|
||||
** user and the latter is an internal programming error.
|
||||
*/
|
||||
int sqlite3VdbeMemStringify(Mem *pMem, u8 enc, u8 bForce){
|
||||
int fg = pMem->flags;
|
||||
|
@ -405,7 +405,7 @@ static i64 doubleToInt64(double r){
|
|||
** 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 represents an
|
||||
** it into an integer and return that. If pMem represents an
|
||||
** an SQL-NULL value, return 0.
|
||||
**
|
||||
** If pMem represents a string value, its encoding might be changed.
|
||||
|
@ -697,7 +697,7 @@ int sqlite3VdbeMemTooBig(Mem *p){
|
|||
|
||||
#ifdef SQLITE_DEBUG
|
||||
/*
|
||||
** This routine prepares a memory cell for modication by breaking
|
||||
** This routine prepares a memory cell for modification by breaking
|
||||
** its link to a shallow copy and by marking any current shallow
|
||||
** copies of this cell as invalid.
|
||||
**
|
||||
|
|
|
@ -2061,7 +2061,7 @@ static void *vdbePmaReaderBgInit(void *pCtx){
|
|||
|
||||
/*
|
||||
** Use a background thread to invoke vdbePmaReaderIncrMergeInit(INCRINIT_TASK)
|
||||
** on the the PmaReader object passed as the first argument.
|
||||
** on the PmaReader object passed as the first argument.
|
||||
**
|
||||
** This call will initialize the various fields of the pReadr->pIncr
|
||||
** structure and, if it is a multi-threaded IncrMerger, launch a
|
||||
|
|
|
@ -64,7 +64,7 @@ static int findNextHostParameter(const char *zSql, int *pnToken){
|
|||
** ALGORITHM: Scan the input string looking for host parameters in any of
|
||||
** these forms: ?, ?N, $A, @A, :A. Take care to avoid text within
|
||||
** string literals, quoted identifier names, and comments. For text forms,
|
||||
** the host parameter index is found by scanning the perpared
|
||||
** the host parameter index is found by scanning the prepared
|
||||
** statement for the corresponding OP_Variable opcode. Once the host
|
||||
** parameter index is known, locate the value in p->aVar[]. Then render
|
||||
** the value as a literal in place of the host parameter name.
|
||||
|
|
12
src/wal.c
12
src/wal.c
|
@ -574,7 +574,7 @@ static volatile WalIndexHdr *walIndexHdr(Wal *pWal){
|
|||
** The argument to this macro must be of type u32. On a little-endian
|
||||
** architecture, it returns the u32 value that results from interpreting
|
||||
** the 4 bytes as a big-endian value. On a big-endian architecture, it
|
||||
** returns the value that would be produced by intepreting the 4 bytes
|
||||
** returns the value that would be produced by interpreting the 4 bytes
|
||||
** of the input value as a little-endian integer.
|
||||
*/
|
||||
#define BYTESWAP32(x) ( \
|
||||
|
@ -988,7 +988,7 @@ static int walIndexAppend(Wal *pWal, u32 iFrame, u32 iPage){
|
|||
assert( idx <= HASHTABLE_NSLOT/2 + 1 );
|
||||
|
||||
/* If this is the first entry to be added to this hash-table, zero the
|
||||
** entire hash table and aPgno[] array before proceding.
|
||||
** entire hash table and aPgno[] array before proceeding.
|
||||
*/
|
||||
if( idx==1 ){
|
||||
int nByte = (int)((u8 *)&aHash[HASHTABLE_NSLOT] - (u8 *)&aPgno[1]);
|
||||
|
@ -1661,7 +1661,7 @@ static int walPagesize(Wal *pWal){
|
|||
** database file.
|
||||
**
|
||||
** This routine uses and updates the nBackfill field of the wal-index header.
|
||||
** This is the only routine tha will increase the value of nBackfill.
|
||||
** This is the only routine that will increase the value of nBackfill.
|
||||
** (A WAL reset or recovery will revert nBackfill to zero, but not increase
|
||||
** its value.)
|
||||
**
|
||||
|
@ -1967,7 +1967,7 @@ static int walIndexTryHdr(Wal *pWal, int *pChanged){
|
|||
** wal-index from the WAL before returning.
|
||||
**
|
||||
** Set *pChanged to 1 if the wal-index header value in pWal->hdr is
|
||||
** changed by this opertion. If pWal->hdr is unchanged, set *pChanged
|
||||
** changed by this operation. If pWal->hdr is unchanged, set *pChanged
|
||||
** to 0.
|
||||
**
|
||||
** If the wal-index header is successfully read, return SQLITE_OK.
|
||||
|
@ -2171,7 +2171,7 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){
|
|||
** may have been appended to the log before READ_LOCK(0) was obtained.
|
||||
** When holding READ_LOCK(0), the reader ignores the entire log file,
|
||||
** which implies that the database file contains a trustworthy
|
||||
** snapshoT. Since holding READ_LOCK(0) prevents a checkpoint from
|
||||
** snapshot. Since holding READ_LOCK(0) prevents a checkpoint from
|
||||
** happening, this is usually correct.
|
||||
**
|
||||
** However, if frames have been appended to the log (or if the log
|
||||
|
@ -2839,7 +2839,7 @@ int sqlite3WalFrames(
|
|||
**
|
||||
** Padding and syncing only occur if this set of frames complete a
|
||||
** transaction and if PRAGMA synchronous=FULL. If synchronous==NORMAL
|
||||
** or synchonous==OFF, then no padding or syncing are needed.
|
||||
** or synchronous==OFF, then no padding or syncing are needed.
|
||||
**
|
||||
** If SQLITE_IOCAP_POWERSAFE_OVERWRITE is defined, then padding is not
|
||||
** needed and only the sync is done. If padding is needed, then the
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
|
||||
/*
|
||||
** Walk an expression tree. Invoke the callback once for each node
|
||||
** of the expression, while decending. (In other words, the callback
|
||||
** of the expression, while descending. (In other words, the callback
|
||||
** is invoked before visiting children.)
|
||||
**
|
||||
** The return value from the callback should be one of the WRC_*
|
||||
|
|
52
src/where.c
52
src/where.c
|
@ -701,7 +701,7 @@ static int isLikeOrGlob(
|
|||
** value of the variable means there is no need to invoke the LIKE
|
||||
** function, then no OP_Variable will be added to the program.
|
||||
** This causes problems for the sqlite3_bind_parameter_name()
|
||||
** API. To workaround them, add a dummy OP_Variable here.
|
||||
** API. To work around them, add a dummy OP_Variable here.
|
||||
*/
|
||||
int r1 = sqlite3GetTempReg(pParse);
|
||||
sqlite3ExprCodeTarget(pParse, pRight, r1);
|
||||
|
@ -821,7 +821,7 @@ static void transferJoinMarkings(Expr *pDerived, Expr *pBase){
|
|||
** appropriate for indexing exist.
|
||||
**
|
||||
** All examples A through E above satisfy case 2. But if a term
|
||||
** also statisfies case 1 (such as B) we know that the optimizer will
|
||||
** also satisfies case 1 (such as B) we know that the optimizer will
|
||||
** always prefer case 1, so in that case we pretend that case 2 is not
|
||||
** satisfied.
|
||||
**
|
||||
|
@ -979,7 +979,7 @@ static void exprAnalyzeOrTerm(
|
|||
}
|
||||
if( (chngToIN & getMask(&pWInfo->sMaskSet, pOrTerm->leftCursor))==0 ){
|
||||
/* This term must be of the form t1.a==t2.b where t2 is in the
|
||||
** chngToIN set but t1 is not. This term will be either preceeded
|
||||
** chngToIN set but t1 is not. This term will be either preceded
|
||||
** or follwed by an inverted copy (t2.b==t1.a). Skip this term
|
||||
** and use its inversion. */
|
||||
testcase( pOrTerm->wtFlags & TERM_COPIED );
|
||||
|
@ -1390,7 +1390,7 @@ static void exprAnalyze(
|
|||
}
|
||||
|
||||
/*
|
||||
** This function searches pList for a entry that matches the iCol-th column
|
||||
** This function searches pList for an entry that matches the iCol-th column
|
||||
** of index pIdx.
|
||||
**
|
||||
** If such an expression is found, its index in pList->a[] is returned. If
|
||||
|
@ -2140,7 +2140,7 @@ static int whereRangeSkipScanEst(
|
|||
** number of rows that the index scan is expected to visit without
|
||||
** considering the range constraints. If nEq is 0, this is the number of
|
||||
** rows in the index. Assuming no error occurs, *pnOut is adjusted (reduced)
|
||||
** to account for the range contraints pLower and pUpper.
|
||||
** to account for the range constraints pLower and pUpper.
|
||||
**
|
||||
** In the absence of sqlite_stat4 ANALYZE data, or if such data cannot be
|
||||
** used, a single range inequality reduces the search space by a factor of 4.
|
||||
|
@ -3417,7 +3417,7 @@ static Bitmask codeOneLoopStart(
|
|||
** B: <after the loop>
|
||||
**
|
||||
** Added 2014-05-26: If the table is a WITHOUT ROWID table, then
|
||||
** use an ephermeral index instead of a RowSet to record the primary
|
||||
** use an ephemeral index instead of a RowSet to record the primary
|
||||
** keys of the rows we have already seen.
|
||||
**
|
||||
*/
|
||||
|
@ -3468,7 +3468,7 @@ static Bitmask codeOneLoopStart(
|
|||
}
|
||||
|
||||
/* Initialize the rowset register to contain NULL. An SQL NULL is
|
||||
** equivalent to an empty rowset. Or, create an ephermeral index
|
||||
** equivalent to an empty rowset. Or, create an ephemeral index
|
||||
** capable of holding primary keys in the case of a WITHOUT ROWID.
|
||||
**
|
||||
** Also initialize regReturn to contain the address of the instruction
|
||||
|
@ -4221,14 +4221,16 @@ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){
|
|||
** the number of output rows by a factor of 10 and each additional term
|
||||
** reduces the number of output rows by sqrt(2).
|
||||
*/
|
||||
static void whereLoopOutputAdjust(WhereClause *pWC, WhereLoop *pLoop){
|
||||
static void whereLoopOutputAdjust(
|
||||
WhereClause *pWC, /* The WHERE clause */
|
||||
WhereLoop *pLoop, /* The loop to adjust downward */
|
||||
LogEst nRow /* Number of rows in the entire table */
|
||||
){
|
||||
WhereTerm *pTerm, *pX;
|
||||
Bitmask notAllowed = ~(pLoop->prereq|pLoop->maskSelf);
|
||||
int i, j;
|
||||
int nEq = 0; /* Number of = constraints not within likely()/unlikely() */
|
||||
|
||||
if( !OptimizationEnabled(pWC->pWInfo->pParse->db, SQLITE_AdjustOutEst) ){
|
||||
return;
|
||||
}
|
||||
for(i=pWC->nTerm, pTerm=pWC->a; i>0; i--, pTerm++){
|
||||
if( (pTerm->wtFlags & TERM_VIRTUAL)!=0 ) break;
|
||||
if( (pTerm->prereqAll & pLoop->maskSelf)==0 ) continue;
|
||||
|
@ -4240,9 +4242,21 @@ static void whereLoopOutputAdjust(WhereClause *pWC, WhereLoop *pLoop){
|
|||
if( pX->iParent>=0 && (&pWC->a[pX->iParent])==pTerm ) break;
|
||||
}
|
||||
if( j<0 ){
|
||||
pLoop->nOut += (pTerm->truthProb<=0 ? pTerm->truthProb : -1);
|
||||
if( pTerm->truthProb<=0 ){
|
||||
pLoop->nOut += pTerm->truthProb;
|
||||
}else{
|
||||
pLoop->nOut--;
|
||||
if( pTerm->eOperator&WO_EQ ) nEq++;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* TUNING: If there is at least one equality constraint in the WHERE
|
||||
** clause that does not have a likelihood() explicitly assigned to it
|
||||
** then do not let the estimated number of output rows exceed half
|
||||
** the number of rows in the table. */
|
||||
if( nEq && pLoop->nOut>nRow-10 ){
|
||||
pLoop->nOut = nRow - 10;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -4288,6 +4302,7 @@ static int whereLoopAddBtreeIndex(
|
|||
LogEst saved_nOut; /* Original value of pNew->nOut */
|
||||
int iCol; /* Index of the column in the table */
|
||||
int rc = SQLITE_OK; /* Return code */
|
||||
LogEst rSize; /* Number of rows in the table */
|
||||
LogEst rLogSize; /* Logarithm of table size */
|
||||
WhereTerm *pTop = 0, *pBtm = 0; /* Top and bottom range constraints */
|
||||
|
||||
|
@ -4317,7 +4332,8 @@ static int whereLoopAddBtreeIndex(
|
|||
saved_prereq = pNew->prereq;
|
||||
saved_nOut = pNew->nOut;
|
||||
pNew->rSetup = 0;
|
||||
rLogSize = estLog(pProbe->aiRowLogEst[0]);
|
||||
rSize = pProbe->aiRowLogEst[0];
|
||||
rLogSize = estLog(rSize);
|
||||
|
||||
/* Consider using a skip-scan if there are no WHERE clause constraints
|
||||
** available for the left-most terms of the index, and if the average
|
||||
|
@ -4494,7 +4510,7 @@ static int whereLoopAddBtreeIndex(
|
|||
nOutUnadjusted = pNew->nOut;
|
||||
pNew->rRun += nInMul + nIn;
|
||||
pNew->nOut += nInMul + nIn;
|
||||
whereLoopOutputAdjust(pBuilder->pWC, pNew);
|
||||
whereLoopOutputAdjust(pBuilder->pWC, pNew, rSize);
|
||||
rc = whereLoopInsert(pBuilder, pNew);
|
||||
|
||||
if( pNew->wsFlags & WHERE_COLUMN_RANGE ){
|
||||
|
@ -4707,7 +4723,7 @@ static int whereLoopAddBtree(
|
|||
ApplyCostMultiplier(pNew->rSetup, pTab->costMult);
|
||||
/* TUNING: Each index lookup yields 20 rows in the table. This
|
||||
** is more than the usual guess of 10 rows, since we have no way
|
||||
** of knowning how selective the index will ultimately be. It would
|
||||
** of knowing how selective the index will ultimately be. It would
|
||||
** not be unreasonable to make this value much larger. */
|
||||
pNew->nOut = 43; assert( 43==sqlite3LogEst(20) );
|
||||
pNew->rRun = sqlite3LogEstAdd(rLogSize,pNew->nOut);
|
||||
|
@ -4748,7 +4764,7 @@ static int whereLoopAddBtree(
|
|||
/* TUNING: Cost of full table scan is (N*3.0). */
|
||||
pNew->rRun = rSize + 16;
|
||||
ApplyCostMultiplier(pNew->rRun, pTab->costMult);
|
||||
whereLoopOutputAdjust(pWC, pNew);
|
||||
whereLoopOutputAdjust(pWC, pNew, rSize);
|
||||
rc = whereLoopInsert(pBuilder, pNew);
|
||||
pNew->nOut = rSize;
|
||||
if( rc ) break;
|
||||
|
@ -4784,7 +4800,7 @@ static int whereLoopAddBtree(
|
|||
pNew->rRun = sqlite3LogEstAdd(pNew->rRun, rSize+16);
|
||||
}
|
||||
ApplyCostMultiplier(pNew->rRun, pTab->costMult);
|
||||
whereLoopOutputAdjust(pWC, pNew);
|
||||
whereLoopOutputAdjust(pWC, pNew, rSize);
|
||||
rc = whereLoopInsert(pBuilder, pNew);
|
||||
pNew->nOut = rSize;
|
||||
if( rc ) break;
|
||||
|
@ -5137,7 +5153,7 @@ static int whereLoopAddAll(WhereLoopBuilder *pBuilder){
|
|||
** strict. With GROUP BY and DISTINCT the only requirement is that
|
||||
** equivalent rows appear immediately adjacent to one another. GROUP BY
|
||||
** and DISTINCT do not require rows to appear in any particular order as long
|
||||
** as equivelent rows are grouped together. Thus for GROUP BY and DISTINCT
|
||||
** as equivalent rows are grouped together. Thus for GROUP BY and DISTINCT
|
||||
** the pOrderBy terms can be matched in any order. With ORDER BY, the
|
||||
** pOrderBy terms must be matched in strict left-to-right order.
|
||||
*/
|
||||
|
|
|
@ -176,7 +176,7 @@ static int whereLoopResize(sqlite3*, WhereLoop*, int);
|
|||
** 1. Then using those as a basis to compute the N best WherePath objects
|
||||
** of length 2. And so forth until the length of WherePaths equals the
|
||||
** number of nodes in the FROM clause. The best (lowest cost) WherePath
|
||||
** at the end is the choosen query plan.
|
||||
** at the end is the chosen query plan.
|
||||
*/
|
||||
struct WherePath {
|
||||
Bitmask maskLoop; /* Bitmask of all WhereLoop objects in this path */
|
||||
|
|
|
@ -156,8 +156,14 @@ do_test aggnested-3.2 {
|
|||
(SELECT value1 as xyz, max(x1) AS pqr
|
||||
FROM t1
|
||||
GROUP BY id1);
|
||||
SELECT
|
||||
(SELECT sum(value2<>xyz) FROM t2)
|
||||
FROM
|
||||
(SELECT value1 as xyz, max(x1) AS pqr
|
||||
FROM t1
|
||||
GROUP BY id1);
|
||||
}
|
||||
} {0}
|
||||
} {1 0}
|
||||
do_test aggnested-3.3 {
|
||||
db eval {
|
||||
DROP TABLE IF EXISTS t1;
|
||||
|
|
274
test/auth.test
274
test/auth.test
File diff suppressed because it is too large
Load Diff
|
@ -31,7 +31,7 @@ do_test auth2-1.1 {
|
|||
INSERT INTO t1 VALUES(1,2,3);
|
||||
}
|
||||
set ::flist {}
|
||||
proc auth {code arg1 arg2 arg3 arg4} {
|
||||
proc auth {code arg1 arg2 arg3 arg4 args} {
|
||||
if {$code=="SQLITE_FUNCTION"} {
|
||||
lappend ::flist $arg2
|
||||
if {$arg2=="max"} {
|
||||
|
@ -80,7 +80,7 @@ sqlite3 db test.db
|
|||
sqlite3 db2 test.db
|
||||
proc auth {args} {
|
||||
global authargs
|
||||
append authargs $args\n
|
||||
append authargs [lrange $args 0 4]\n
|
||||
return SQLITE_OK
|
||||
}
|
||||
db auth auth
|
||||
|
|
|
@ -30,7 +30,7 @@ if {[catch {db auth {}} msg]} {
|
|||
db cache size 0
|
||||
|
||||
db authorizer ::auth
|
||||
proc auth {code arg1 arg2 arg3 arg4} {
|
||||
proc auth {code arg1 arg2 arg3 arg4 args} {
|
||||
if {$code=="SQLITE_DELETE"} {
|
||||
return $::authcode
|
||||
}
|
||||
|
|
|
@ -1554,7 +1554,7 @@ ifcapable auth {
|
|||
}
|
||||
} {}
|
||||
|
||||
proc auth {args} {eval lappend ::authargs $args ; return SQLITE_OK}
|
||||
proc auth {args} {eval lappend ::authargs [lrange $args 0 4]; return SQLITE_OK}
|
||||
db auth auth
|
||||
|
||||
# An insert on the parent table must read the child key of any deferred
|
||||
|
|
|
@ -170,7 +170,7 @@ foreach {q r} [array get fts4aa_res] {
|
|||
# Should get the same search results when an authorizer prevents
|
||||
# all PRAGMA statements.
|
||||
#
|
||||
proc no_pragma_auth {code arg1 arg2 arg3 arg4} {
|
||||
proc no_pragma_auth {code arg1 arg2 arg3 arg4 args} {
|
||||
if {$code=="SQLITE_PRAGMA"} {return SQLITE_DENY}
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
|
|
@ -56,14 +56,16 @@ do_test minmax4-1.5 {
|
|||
do_test minmax4-1.6 {
|
||||
db eval {
|
||||
SELECT p, min(q) FROM t1;
|
||||
SELECT p FROM (SELECT p, min(q) FROM t1);
|
||||
}
|
||||
} {1 2}
|
||||
} {1 2 1}
|
||||
do_test minmax4-1.7 {
|
||||
db eval {
|
||||
INSERT INTO t1 VALUES(5,0);
|
||||
SELECT p, max(q) FROM t1;
|
||||
SELECT p FROM (SELECT max(q), p FROM t1);
|
||||
}
|
||||
} {3 4}
|
||||
} {3 4 3}
|
||||
do_test minmax4-1.8 {
|
||||
db eval {
|
||||
SELECT p, min(q) FROM t1;
|
||||
|
@ -73,8 +75,9 @@ do_test minmax4-1.9 {
|
|||
db eval {
|
||||
INSERT INTO t1 VALUES(6,1);
|
||||
SELECT p, max(q) FROM t1;
|
||||
SELECT p FROM (SELECT max(q), p FROM t1);
|
||||
}
|
||||
} {3 4}
|
||||
} {3 4 3}
|
||||
do_test minmax4-1.10 {
|
||||
db eval {
|
||||
SELECT p, min(q) FROM t1;
|
||||
|
|
|
@ -561,7 +561,7 @@ do_test savepoint-8-2 {
|
|||
#
|
||||
ifcapable auth {
|
||||
proc auth {args} {
|
||||
eval lappend ::authdata $args
|
||||
eval lappend ::authdata [lrange $args 0 4]
|
||||
return SQLITE_OK
|
||||
}
|
||||
db auth auth
|
||||
|
@ -583,7 +583,7 @@ ifcapable auth {
|
|||
} {SQLITE_SAVEPOINT RELEASE sp1 {} {}}
|
||||
|
||||
proc auth {args} {
|
||||
eval lappend ::authdata $args
|
||||
eval lappend ::authdata [lrange $args 0 4]
|
||||
return SQLITE_DENY
|
||||
}
|
||||
db auth auth
|
||||
|
|
|
@ -0,0 +1,257 @@
|
|||
# 2014-09-10
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#***********************************************************************
|
||||
#
|
||||
# This file implements tests of the SQLITE_USER_AUTHENTICATION extension.
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set testprefix userauth01
|
||||
|
||||
ifcapable !userauth {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
# Create a no-authentication-required database
|
||||
#
|
||||
do_execsql_test userauth01-1.0 {
|
||||
CREATE TABLE t1(x);
|
||||
INSERT INTO t1 VALUES(1),(2.5),('three'),(x'4444'),(NULL);
|
||||
SELECT quote(x) FROM t1 ORDER BY x;
|
||||
SELECT name FROM sqlite_master;
|
||||
} {NULL 1 2.5 'three' X'4444' t1}
|
||||
|
||||
# Calling sqlite3_user_authenticate() on a no-authentication-required
|
||||
# database connection is a harmless no-op.
|
||||
#
|
||||
do_test userauth01-1.1 {
|
||||
sqlite3_user_authenticate db alice pw-4-alice
|
||||
execsql {
|
||||
SELECT quote(x) FROM t1 ORDER BY x;
|
||||
SELECT name FROM sqlite_master;
|
||||
}
|
||||
} {NULL 1 2.5 'three' X'4444' t1}
|
||||
|
||||
# If sqlite3_user_add(D,U,P,N,A) is called on a no-authentication-required
|
||||
# database and A is false, then the call fails with an SQLITE_AUTH error.
|
||||
#
|
||||
do_test userauth01-1.2 {
|
||||
sqlite3_user_add db bob pw-4-bob 0
|
||||
} {SQLITE_AUTH}
|
||||
do_test userauth01-1.3 {
|
||||
execsql {
|
||||
SELECT quote(x) FROM t1 ORDER BY x;
|
||||
SELECT name FROM sqlite_master;
|
||||
}
|
||||
} {NULL 1 2.5 'three' X'4444' t1}
|
||||
|
||||
# When called on a no-authentication-required
|
||||
# database and when A is true, the sqlite3_user_add(D,U,P,N,A) routine
|
||||
# converts the database into an authentication-required database and
|
||||
# logs the database connection D in using user U with password P,N.
|
||||
#
|
||||
do_test userauth01-1.4 {
|
||||
sqlite3_user_add db alice pw-4-alice 1
|
||||
} {SQLITE_OK}
|
||||
do_test userauth01-1.5 {
|
||||
execsql {
|
||||
SELECT quote(x) FROM t1 ORDER BY x;
|
||||
SELECT uname, isadmin FROM sqlite_user ORDER BY uname;
|
||||
SELECT name FROM sqlite_master ORDER BY name;
|
||||
}
|
||||
} {NULL 1 2.5 'three' X'4444' alice 1 sqlite_user t1}
|
||||
|
||||
# The sqlite3_user_add() interface can be used (by an admin user only)
|
||||
# to create a new user.
|
||||
#
|
||||
do_test userauth01-1.6 {
|
||||
sqlite3_user_add db bob pw-4-bob 0
|
||||
sqlite3_user_add db cindy pw-4-cindy 0
|
||||
sqlite3_user_add db david pw-4-david 0
|
||||
execsql {
|
||||
SELECT uname, isadmin FROM sqlite_user ORDER BY uname;
|
||||
}
|
||||
} {alice 1 bob 0 cindy 0 david 0}
|
||||
|
||||
# The sqlite_user table is inaccessible (unreadable and unwriteable) to
|
||||
# non-admin users and is read-only for admin users. However, if the same
|
||||
#
|
||||
do_test userauth01-1.7 {
|
||||
sqlite3 db2 test.db
|
||||
sqlite3_user_authenticate db2 cindy pw-4-cindy
|
||||
db2 eval {
|
||||
SELECT quote(x) FROM t1 ORDER BY x;
|
||||
SELECT name FROM sqlite_master ORDER BY name;
|
||||
}
|
||||
} {NULL 1 2.5 'three' X'4444' sqlite_user t1}
|
||||
do_test userauth01-1.8 {
|
||||
catchsql {
|
||||
SELECT uname, isadmin FROM sqlite_user ORDER BY uname;
|
||||
} db2
|
||||
} {1 {no such table: sqlite_user}}
|
||||
|
||||
# Any user can change their own password.
|
||||
#
|
||||
do_test userauth01-1.9 {
|
||||
sqlite3_user_change db2 cindy xyzzy-cindy 0
|
||||
} {SQLITE_OK}
|
||||
do_test userauth01-1.10 {
|
||||
sqlite3_user_authenticate db2 cindy pw-4-cindy
|
||||
} {SQLITE_AUTH}
|
||||
do_test userauth01-1.11 {
|
||||
sqlite3_user_authenticate db2 cindy xyzzy-cindy
|
||||
} {SQLITE_OK}
|
||||
do_test userauth01-1.12 {
|
||||
sqlite3_user_change db alice xyzzy-alice 1
|
||||
} {SQLITE_OK}
|
||||
do_test userauth01-1.13 {
|
||||
sqlite3_user_authenticate db alice pw-4-alice
|
||||
} {SQLITE_AUTH}
|
||||
do_test userauth01-1.14 {
|
||||
sqlite3_user_authenticate db alice xyzzy-alice
|
||||
} {SQLITE_OK}
|
||||
|
||||
# No user may change their own admin privilege setting.
|
||||
#
|
||||
do_test userauth01-1.15 {
|
||||
sqlite3_user_change db alice xyzzy-alice 0
|
||||
} {SQLITE_AUTH}
|
||||
do_test userauth01-1.16 {
|
||||
db eval {SELECT uname, isadmin FROM sqlite_user ORDER BY uname}
|
||||
} {alice 1 bob 0 cindy 0 david 0}
|
||||
do_test userauth01-1.17 {
|
||||
sqlite3_user_change db2 cindy xyzzy-cindy 1
|
||||
} {SQLITE_AUTH}
|
||||
do_test userauth01-1.18 {
|
||||
db eval {SELECT uname, isadmin FROM sqlite_user ORDER BY uname}
|
||||
} {alice 1 bob 0 cindy 0 david 0}
|
||||
|
||||
# The sqlite3_user_change() interface can be used to change a users
|
||||
# login credentials or admin privilege.
|
||||
#
|
||||
do_test userauth01-1.20 {
|
||||
sqlite3_user_change db david xyzzy-david 1
|
||||
} {SQLITE_OK}
|
||||
do_test userauth01-1.21 {
|
||||
db eval {SELECT uname, isadmin FROM sqlite_user ORDER BY uname}
|
||||
} {alice 1 bob 0 cindy 0 david 1}
|
||||
do_test userauth01-1.22 {
|
||||
sqlite3_user_authenticate db2 david xyzzy-david
|
||||
} {SQLITE_OK}
|
||||
do_test userauth01-1.23 {
|
||||
db2 eval {SELECT uname, isadmin FROM sqlite_user ORDER BY uname}
|
||||
} {alice 1 bob 0 cindy 0 david 1}
|
||||
do_test userauth01-1.24 {
|
||||
sqlite3_user_change db david pw-4-david 0
|
||||
} {SQLITE_OK}
|
||||
do_test userauth01-1.25 {
|
||||
sqlite3_user_authenticate db2 david pw-4-david
|
||||
} {SQLITE_OK}
|
||||
do_test userauth01-1.26 {
|
||||
db eval {SELECT uname, isadmin FROM sqlite_user ORDER BY uname}
|
||||
} {alice 1 bob 0 cindy 0 david 0}
|
||||
do_test userauth01-1.27 {
|
||||
catchsql {SELECT uname, isadmin FROM sqlite_user ORDER BY uname} db2
|
||||
} {1 {no such table: sqlite_user}}
|
||||
|
||||
# Only an admin user can change another users login
|
||||
# credentials or admin privilege setting.
|
||||
#
|
||||
do_test userauth01-1.30 {
|
||||
sqlite3_user_change db2 bob xyzzy-bob 1
|
||||
} {SQLITE_AUTH}
|
||||
do_test userauth01-1.31 {
|
||||
db eval {SELECT uname, isadmin FROM sqlite_user ORDER BY uname}
|
||||
} {alice 1 bob 0 cindy 0 david 0}
|
||||
|
||||
# The sqlite3_user_delete() interface can be used (by an admin user only)
|
||||
# to delete a user.
|
||||
#
|
||||
do_test userauth01-1.40 {
|
||||
sqlite3_user_delete db bob
|
||||
} {SQLITE_OK}
|
||||
do_test userauth01-1.41 {
|
||||
db eval {SELECT uname, isadmin FROM sqlite_user ORDER BY uname}
|
||||
} {alice 1 cindy 0 david 0}
|
||||
do_test userauth01-1.42 {
|
||||
sqlite3_user_delete db2 cindy
|
||||
} {SQLITE_AUTH}
|
||||
do_test userauth01-1.43 {
|
||||
sqlite3_user_delete db2 alice
|
||||
} {SQLITE_AUTH}
|
||||
do_test userauth01-1.44 {
|
||||
db eval {SELECT uname, isadmin FROM sqlite_user ORDER BY uname}
|
||||
} {alice 1 cindy 0 david 0}
|
||||
|
||||
# The currently logged-in user cannot be deleted
|
||||
#
|
||||
do_test userauth01-1.50 {
|
||||
sqlite3_user_delete db alice
|
||||
} {SQLITE_AUTH}
|
||||
do_test userauth01-1.51 {
|
||||
db eval {SELECT uname, isadmin FROM sqlite_user ORDER BY uname}
|
||||
} {alice 1 cindy 0 david 0}
|
||||
|
||||
# When ATTACH-ing new database files to a connection, each newly attached
|
||||
# database that is an authentication-required database is checked using
|
||||
# the same username and password as supplied to the main database. If that
|
||||
# check fails, then the ATTACH command fails with an SQLITE_AUTH error.
|
||||
#
|
||||
do_test userauth01-1.60 {
|
||||
forcedelete test3.db
|
||||
sqlite3 db3 test3.db
|
||||
sqlite3_user_add db3 alice xyzzy-alice 1
|
||||
} {SQLITE_OK}
|
||||
do_test userauth01-1.61 {
|
||||
db3 eval {
|
||||
CREATE TABLE t3(a,b,c); INSERT INTO t3 VALUES(1,2,3);
|
||||
SELECT * FROM t3;
|
||||
}
|
||||
} {1 2 3}
|
||||
do_test userauth01-1.62 {
|
||||
db eval {
|
||||
ATTACH 'test3.db' AS aux;
|
||||
SELECT * FROM t1, t3 ORDER BY x LIMIT 1;
|
||||
DETACH aux;
|
||||
}
|
||||
} {{} 1 2 3}
|
||||
do_test userauth01-1.63 {
|
||||
sqlite3_user_change db alice pw-4-alice 1
|
||||
sqlite3_user_authenticate db alice pw-4-alice
|
||||
catchsql {
|
||||
ATTACH 'test3.db' AS aux;
|
||||
}
|
||||
} {1 {unable to open database: test3.db}}
|
||||
do_test userauth01-1.64 {
|
||||
sqlite3_extended_errcode db
|
||||
} {SQLITE_AUTH}
|
||||
do_test userauth01-1.65 {
|
||||
db eval {PRAGMA database_list}
|
||||
} {~/test3.db/}
|
||||
|
||||
# The sqlite3_set_authorizer() callback is modified to take a 7th parameter
|
||||
# which is the username of the currently logged in user, or NULL for a
|
||||
# no-authentication-required database.
|
||||
#
|
||||
proc auth {args} {
|
||||
lappend ::authargs $args
|
||||
return SQLITE_OK
|
||||
}
|
||||
do_test authuser01-2.1 {
|
||||
unset -nocomplain ::authargs
|
||||
db auth auth
|
||||
db eval {SELECT x FROM t1}
|
||||
set ::authargs
|
||||
} {/SQLITE_SELECT {} {} {} {} alice/}
|
||||
|
||||
|
||||
finish_test
|
|
@ -25,7 +25,7 @@ set ::auth_fail 0
|
|||
set ::auth_log [list]
|
||||
set ::auth_filter [list SQLITE_READ SQLITE_UPDATE SQLITE_SELECT SQLITE_PRAGMA]
|
||||
|
||||
proc auth {code arg1 arg2 arg3 arg4} {
|
||||
proc auth {code arg1 arg2 arg3 arg4 args} {
|
||||
if {[lsearch $::auth_filter $code]>-1} {
|
||||
return SQLITE_OK
|
||||
}
|
||||
|
|
303
test/whereJ.test
303
test/whereJ.test
|
@ -373,50 +373,271 @@ do_execsql_test whereJ-2.2 {
|
|||
|
||||
############################################################################
|
||||
|
||||
ifcapable stat4 {
|
||||
# Create and populate table.
|
||||
do_execsql_test 3.1 { CREATE TABLE t1(a, b, c) }
|
||||
for {set i 0} {$i < 32} {incr i 2} {
|
||||
for {set x 0} {$x < 100} {incr x} {
|
||||
execsql { INSERT INTO t1 VALUES($i, $x, $c) }
|
||||
incr c
|
||||
}
|
||||
execsql { INSERT INTO t1 VALUES($i+1, 5, $c) }
|
||||
# Create and populate table.
|
||||
do_execsql_test 3.1 { CREATE TABLE t1(a, b, c) }
|
||||
for {set i 0} {$i < 32} {incr i 2} {
|
||||
for {set x 0} {$x < 100} {incr x} {
|
||||
execsql { INSERT INTO t1 VALUES($i, $x, $c) }
|
||||
incr c
|
||||
}
|
||||
|
||||
do_execsql_test 3.2 {
|
||||
SELECT a, count(*) FROM t1 GROUP BY a HAVING a < 8;
|
||||
} {
|
||||
0 100 1 1 2 100 3 1 4 100 5 1 6 100 7 1
|
||||
}
|
||||
|
||||
do_execsql_test 3.3 {
|
||||
CREATE INDEX idx_ab ON t1(a, b);
|
||||
CREATE INDEX idx_c ON t1(c);
|
||||
ANALYZE;
|
||||
} {}
|
||||
|
||||
# This one should use index "idx_c".
|
||||
do_eqp_test 3.4 {
|
||||
SELECT * FROM t1 WHERE
|
||||
a = 4 AND b BETWEEN 20 AND 80 -- Matches 80 rows
|
||||
AND
|
||||
c BETWEEN 150 AND 160 -- Matches 10 rows
|
||||
} {
|
||||
0 0 0 {SEARCH TABLE t1 USING INDEX idx_c (c>? AND c<?)}
|
||||
}
|
||||
|
||||
# This one should use index "idx_ab".
|
||||
do_eqp_test 3.5 {
|
||||
SELECT * FROM t1 WHERE
|
||||
a = 5 AND b BETWEEN 20 AND 80 -- Matches 1 row
|
||||
AND
|
||||
c BETWEEN 150 AND 160 -- Matches 10 rows
|
||||
} {
|
||||
0 0 0 {SEARCH TABLE t1 USING INDEX idx_ab (a=? AND b>? AND b<?)}
|
||||
}
|
||||
execsql { INSERT INTO t1 VALUES($i+1, 5, $c) }
|
||||
incr c
|
||||
}
|
||||
|
||||
do_execsql_test 3.2 {
|
||||
SELECT a, count(*) FROM t1 GROUP BY a HAVING a < 8;
|
||||
} {
|
||||
0 100 1 1 2 100 3 1 4 100 5 1 6 100 7 1
|
||||
}
|
||||
|
||||
do_execsql_test 3.3 {
|
||||
CREATE INDEX idx_ab ON t1(a, b);
|
||||
CREATE INDEX idx_c ON t1(c);
|
||||
ANALYZE;
|
||||
} {}
|
||||
|
||||
# This one should use index "idx_c".
|
||||
do_eqp_test 3.4 {
|
||||
SELECT * FROM t1 WHERE
|
||||
a = 4 AND b BETWEEN 20 AND 80 -- Matches 80 rows
|
||||
AND
|
||||
c BETWEEN 150 AND 160 -- Matches 10 rows
|
||||
} {
|
||||
0 0 0 {SEARCH TABLE t1 USING INDEX idx_c (c>? AND c<?)}
|
||||
}
|
||||
|
||||
# This one should use index "idx_ab".
|
||||
do_eqp_test 3.5 {
|
||||
SELECT * FROM t1 WHERE
|
||||
a = 5 AND b BETWEEN 20 AND 80 -- Matches 1 row
|
||||
AND
|
||||
c BETWEEN 150 AND 160 -- Matches 10 rows
|
||||
} {
|
||||
0 0 0 {SEARCH TABLE t1 USING INDEX idx_ab (a=? AND b>? AND b<?)}
|
||||
}
|
||||
|
||||
###########################################################################################
|
||||
|
||||
# Reset the database and setup for a test case derived from actual SQLite users
|
||||
#
|
||||
db close
|
||||
sqlite3 db test.db
|
||||
do_execsql_test 4.1 {
|
||||
CREATE TABLE le(
|
||||
le_id largeint,
|
||||
xid char(31),
|
||||
type smallint,
|
||||
name char(255) DEFAULT '',
|
||||
mtime largeint DEFAULT 0,
|
||||
muuid int DEFAULT 0
|
||||
);
|
||||
CREATE TABLE cx(
|
||||
cx_id largeint,
|
||||
code char(31),
|
||||
type smallint,
|
||||
name char(31),
|
||||
description varchar,
|
||||
role smallint,
|
||||
mtime largeint DEFAULT 0,
|
||||
muuid int DEFAULT 0,
|
||||
le_id largeint DEFAULT 0,
|
||||
imco smallint DEFAULT 0
|
||||
);
|
||||
CREATE TABLE px(
|
||||
px_id largeint,
|
||||
cx_id largeint,
|
||||
px_tid largeint,
|
||||
name char(31),
|
||||
description varchar DEFAULT '',
|
||||
ia smallint,
|
||||
sl smallint,
|
||||
le_id largeint DEFAULT 0,
|
||||
mtime largeint DEFAULT 0,
|
||||
muuid int DEFAULT 0
|
||||
);
|
||||
CREATE INDEX le_id on le (le_id);
|
||||
CREATE INDEX c_id on cx (cx_id);
|
||||
CREATE INDEX c_leid on cx (le_id);
|
||||
CREATE INDEX p_id on px (px_id);
|
||||
CREATE INDEX p_cid0 on px (cx_id);
|
||||
CREATE INDEX p_pt on px (px_tid);
|
||||
CREATE INDEX p_leid on px (le_id);
|
||||
} {}
|
||||
do_execsql_test 4.2 {
|
||||
ANALYZE sqlite_master;
|
||||
INSERT INTO sqlite_stat1 VALUES('le','le_id','1979 1');
|
||||
INSERT INTO sqlite_stat1 VALUES('cx','c_leid','852 171');
|
||||
INSERT INTO sqlite_stat1 VALUES('cx','c_id','852 1');
|
||||
INSERT INTO sqlite_stat1 VALUES('px','p_leid','114443 63');
|
||||
INSERT INTO sqlite_stat1 VALUES('px','p_pt','114443 22889');
|
||||
INSERT INTO sqlite_stat1 VALUES('px','p_cid0','114443 181');
|
||||
INSERT INTO sqlite_stat1 VALUES('px','p_id','114443 1');
|
||||
INSERT INTO sqlite_stat4 VALUES('le','le_id','1 1','162 162','162 162',X'030202013903fb');
|
||||
INSERT INTO sqlite_stat4 VALUES('le','le_id','1 1','208 208','208 208',X'0302020253012d');
|
||||
INSERT INTO sqlite_stat4 VALUES('le','le_id','1 1','219 219','219 219',X'030202025e0131');
|
||||
INSERT INTO sqlite_stat4 VALUES('le','le_id','1 1','248 248','248 248',X'030202027b014e');
|
||||
INSERT INTO sqlite_stat4 VALUES('le','le_id','1 1','265 265','265 265',X'030202028c015f');
|
||||
INSERT INTO sqlite_stat4 VALUES('le','le_id','1 1','358 358','358 358',X'03020202e901bc');
|
||||
INSERT INTO sqlite_stat4 VALUES('le','le_id','1 1','439 439','439 439',X'030202033a020d');
|
||||
INSERT INTO sqlite_stat4 VALUES('le','le_id','1 1','657 657','657 657',X'030202041402b4');
|
||||
INSERT INTO sqlite_stat4 VALUES('le','le_id','1 1','659 659','659 659',X'030202041602b6');
|
||||
INSERT INTO sqlite_stat4 VALUES('le','le_id','1 1','681 681','681 681',X'030202042c02cc');
|
||||
INSERT INTO sqlite_stat4 VALUES('le','le_id','1 1','831 831','831 831',X'03020204c20482');
|
||||
INSERT INTO sqlite_stat4 VALUES('le','le_id','1 1','852 852','852 852',X'03020204d70497');
|
||||
INSERT INTO sqlite_stat4 VALUES('le','le_id','1 1','870 870','870 870',X'03020204e904a9');
|
||||
INSERT INTO sqlite_stat4 VALUES('le','le_id','1 1','879 879','879 879',X'03020204f204b2');
|
||||
INSERT INTO sqlite_stat4 VALUES('le','le_id','1 1','1099 1099','1099 1099',X'03020205ce058e');
|
||||
INSERT INTO sqlite_stat4 VALUES('le','le_id','1 1','1273 1273','1273 1273',X'030202067c05a9');
|
||||
INSERT INTO sqlite_stat4 VALUES('le','le_id','1 1','1319 1319','1319 1319',X'03020206e30730');
|
||||
INSERT INTO sqlite_stat4 VALUES('le','le_id','1 1','1330 1330','1330 1330',X'0302020700035b');
|
||||
INSERT INTO sqlite_stat4 VALUES('le','le_id','1 1','1539 1539','1539 1539',X'03020207d105d8');
|
||||
INSERT INTO sqlite_stat4 VALUES('le','le_id','1 1','1603 1603','1603 1603',X'03020208390780');
|
||||
INSERT INTO sqlite_stat4 VALUES('le','le_id','1 1','1759 1759','1759 1759',X'030202092f0618');
|
||||
INSERT INTO sqlite_stat4 VALUES('le','le_id','1 1','1843 1843','1843 1843',X'03020209880650');
|
||||
INSERT INTO sqlite_stat4 VALUES('le','le_id','1 1','1915 1915','1915 1915',X'03020209d0068b');
|
||||
INSERT INTO sqlite_stat4 VALUES('le','le_id','1 1','1927 1927','1927 1927',X'03020209dc0697');
|
||||
INSERT INTO sqlite_stat4 VALUES('cx','c_leid','846 1','0 94','0 94',X'0308015f');
|
||||
INSERT INTO sqlite_stat4 VALUES('cx','c_leid','846 1','0 189','0 189',X'03080200be');
|
||||
INSERT INTO sqlite_stat4 VALUES('cx','c_leid','846 1','0 284','0 284',X'0308020120');
|
||||
INSERT INTO sqlite_stat4 VALUES('cx','c_leid','846 1','0 379','0 379',X'030802017f');
|
||||
INSERT INTO sqlite_stat4 VALUES('cx','c_leid','846 1','0 474','0 474',X'03080201de');
|
||||
INSERT INTO sqlite_stat4 VALUES('cx','c_leid','846 1','0 569','0 569',X'030802023d');
|
||||
INSERT INTO sqlite_stat4 VALUES('cx','c_leid','846 1','0 664','0 664',X'030802029f');
|
||||
INSERT INTO sqlite_stat4 VALUES('cx','c_leid','846 1','0 759','0 759',X'03080202fe');
|
||||
INSERT INTO sqlite_stat4 VALUES('cx','c_leid','3 1','846 847','1 847',X'0301024500e6');
|
||||
INSERT INTO sqlite_stat4 VALUES('cx','c_leid','1 1','849 849','2 849',X'03010246027e');
|
||||
INSERT INTO sqlite_stat4 VALUES('cx','c_leid','1 1','850 850','3 850',X'0301024700c9');
|
||||
INSERT INTO sqlite_stat4 VALUES('cx','c_leid','1 1','851 851','4 851',X'03010248027f');
|
||||
INSERT INTO sqlite_stat4 VALUES('cx','c_id','1 1','94 94','94 94',X'03020200b801a8');
|
||||
INSERT INTO sqlite_stat4 VALUES('cx','c_id','1 1','113 113','113 113',X'03020200d101ad');
|
||||
INSERT INTO sqlite_stat4 VALUES('cx','c_id','1 1','171 171','171 171',X'030201011d2a');
|
||||
INSERT INTO sqlite_stat4 VALUES('cx','c_id','1 1','177 177','177 177',X'030202012600f2');
|
||||
INSERT INTO sqlite_stat4 VALUES('cx','c_id','1 1','189 189','189 189',X'030202013501c8');
|
||||
INSERT INTO sqlite_stat4 VALUES('cx','c_id','1 1','206 206','206 206',X'030201014f2d');
|
||||
INSERT INTO sqlite_stat4 VALUES('cx','c_id','1 1','231 231','231 231',X'030202016d00fc');
|
||||
INSERT INTO sqlite_stat4 VALUES('cx','c_id','1 1','284 284','284 284',X'03020201b702d0');
|
||||
INSERT INTO sqlite_stat4 VALUES('cx','c_id','1 1','291 291','291 291',X'03020101c042');
|
||||
INSERT INTO sqlite_stat4 VALUES('cx','c_id','1 1','311 311','311 311',X'03020201d801e7');
|
||||
INSERT INTO sqlite_stat4 VALUES('cx','c_id','1 1','339 339','339 339',X'03020101f74b');
|
||||
INSERT INTO sqlite_stat4 VALUES('cx','c_id','1 1','347 347','347 347',X'03020202030118');
|
||||
INSERT INTO sqlite_stat4 VALUES('cx','c_id','1 1','379 379','379 379',X'030202022f01fa');
|
||||
INSERT INTO sqlite_stat4 VALUES('cx','c_id','1 1','393 393','393 393',X'030201023f55');
|
||||
INSERT INTO sqlite_stat4 VALUES('cx','c_id','1 1','407 407','407 407',X'03020202500201');
|
||||
INSERT INTO sqlite_stat4 VALUES('cx','c_id','1 1','413 413','413 413',X'03020102565a');
|
||||
INSERT INTO sqlite_stat4 VALUES('cx','c_id','1 1','468 468','468 468',X'030201029468');
|
||||
INSERT INTO sqlite_stat4 VALUES('cx','c_id','1 1','474 474','474 474',X'030202029a0211');
|
||||
INSERT INTO sqlite_stat4 VALUES('cx','c_id','1 1','517 517','517 517',X'03020102cc76');
|
||||
INSERT INTO sqlite_stat4 VALUES('cx','c_id','1 1','548 548','548 548',X'03020202f00223');
|
||||
INSERT INTO sqlite_stat4 VALUES('cx','c_id','1 1','569 569','569 569',X'03020203090087');
|
||||
INSERT INTO sqlite_stat4 VALUES('cx','c_id','1 1','664 664','664 664',X'03020203740163');
|
||||
INSERT INTO sqlite_stat4 VALUES('cx','c_id','1 1','759 759','759 759',X'03020203e800b3');
|
||||
INSERT INTO sqlite_stat4 VALUES('cx','c_id','1 1','803 803','803 803',X'030202041b026f');
|
||||
INSERT INTO sqlite_stat4 VALUES('px','p_leid','110728 1','0 12715','0 12715',X'030802345b');
|
||||
INSERT INTO sqlite_stat4 VALUES('px','p_leid','110728 1','0 25431','0 25431',X'0308026718');
|
||||
INSERT INTO sqlite_stat4 VALUES('px','p_leid','110728 1','0 38147','0 38147',X'030803009a5c');
|
||||
INSERT INTO sqlite_stat4 VALUES('px','p_leid','110728 1','0 50863','0 50863',X'03080300cdbe');
|
||||
INSERT INTO sqlite_stat4 VALUES('px','p_leid','110728 1','0 63579','0 63579',X'0308030100e8');
|
||||
INSERT INTO sqlite_stat4 VALUES('px','p_leid','110728 1','0 76295','0 76295',X'03080301351d');
|
||||
INSERT INTO sqlite_stat4 VALUES('px','p_leid','110728 1','0 89011','0 89011',X'03080301674c');
|
||||
INSERT INTO sqlite_stat4 VALUES('px','p_leid','110728 1','0 101727','0 101727',X'030803019b99');
|
||||
INSERT INTO sqlite_stat4 VALUES('px','p_leid','28 1','110824 110843','16 110843',X'0301037a0107f1');
|
||||
INSERT INTO sqlite_stat4 VALUES('px','p_leid','53 1','110873 110875','25 110875',X'0302020095275a');
|
||||
INSERT INTO sqlite_stat4 VALUES('px','p_leid','32 1','110927 110936','27 110936',X'030203009b009b4a');
|
||||
INSERT INTO sqlite_stat4 VALUES('px','p_leid','51 1','110980 111017','30 111017',X'03020300a4016c00');
|
||||
INSERT INTO sqlite_stat4 VALUES('px','p_leid','67 1','111047 111059','38 111059',X'03020200af2611');
|
||||
INSERT INTO sqlite_stat4 VALUES('px','p_leid','60 1','111136 111156','43 111156',X'03020300bc009aeb');
|
||||
INSERT INTO sqlite_stat4 VALUES('px','p_leid','42 1','111222 111239','59 111239',X'03020300d200b17b');
|
||||
INSERT INTO sqlite_stat4 VALUES('px','p_leid','36 1','111264 111266','60 111266',X'03020200d426d6');
|
||||
INSERT INTO sqlite_stat4 VALUES('px','p_leid','27 1','111733 111757','159 111757',X'030203014e017e1b');
|
||||
INSERT INTO sqlite_stat4 VALUES('px','p_leid','36 1','111760 111773','160 111773',X'030203014f00a2b9');
|
||||
INSERT INTO sqlite_stat4 VALUES('px','p_leid','29 1','111822 111833','167 111833',X'0302030176009c22');
|
||||
INSERT INTO sqlite_stat4 VALUES('px','p_leid','75 1','113031 113095','1190 113095',X'030203068501912c');
|
||||
INSERT INTO sqlite_stat4 VALUES('px','p_leid','132 1','113230 113263','1252 113263',X'0302030711009ee6');
|
||||
INSERT INTO sqlite_stat4 VALUES('px','p_leid','110 1','113851 113918','1572 113918',X'03020308e9011ca2');
|
||||
INSERT INTO sqlite_stat4 VALUES('px','p_leid','78 1','114212 114217','1791 114217',X'03020209e13b24');
|
||||
INSERT INTO sqlite_stat4 VALUES('px','p_leid','112 1','114303 114351','1799 114351',X'03020309ea0128f2');
|
||||
INSERT INTO sqlite_stat4 VALUES('px','p_pt','89824 1','0 12715','0 12715',X'030802477e');
|
||||
INSERT INTO sqlite_stat4 VALUES('px','p_pt','89824 1','0 25431','0 25431',X'0308027c20');
|
||||
INSERT INTO sqlite_stat4 VALUES('px','p_pt','89824 1','0 38147','0 38147',X'03080300c211');
|
||||
INSERT INTO sqlite_stat4 VALUES('px','p_pt','89824 1','0 50863','0 50863',X'03080300fbe5');
|
||||
INSERT INTO sqlite_stat4 VALUES('px','p_pt','89824 1','0 63579','0 63579',X'0308030140ff');
|
||||
INSERT INTO sqlite_stat4 VALUES('px','p_pt','89824 1','0 76295','0 76295',X'03080301792d');
|
||||
INSERT INTO sqlite_stat4 VALUES('px','p_pt','89824 1','0 89011','0 89011',X'03080301bb68');
|
||||
INSERT INTO sqlite_stat4 VALUES('px','p_pt','24217 1','89824 101727','1 101727',X'03090300da12');
|
||||
INSERT INTO sqlite_stat4 VALUES('px','p_pt','154 1','114041 114154','2 114154',X'0301030200e5e9');
|
||||
INSERT INTO sqlite_stat4 VALUES('px','p_pt','198 1','114195 114351','3 114351',X'03010303015cb1');
|
||||
INSERT INTO sqlite_stat4 VALUES('px','p_pt','50 1','114393 114441','4 114441',X'0301030401b2ef');
|
||||
INSERT INTO sqlite_stat4 VALUES('px','p_cid0','3867 1','3 3736','2 3736',X'03010337015c6a');
|
||||
INSERT INTO sqlite_stat4 VALUES('px','p_cid0','4194 1','4177 8209','5 8209',X'0301033b015075');
|
||||
INSERT INTO sqlite_stat4 VALUES('px','p_cid0','4335 1','8371 11129','6 11129',X'0301033d0156fc');
|
||||
INSERT INTO sqlite_stat4 VALUES('px','p_cid0','1740 1','12706 12715','7 12715',X'0301023e34b9');
|
||||
INSERT INTO sqlite_stat4 VALUES('px','p_cid0','1680 1','14446 15487','8 15487',X'0301033f011694');
|
||||
INSERT INTO sqlite_stat4 VALUES('px','p_cid0','7163 1','20116 25431','32 25431',X'03020300a400ed26');
|
||||
INSERT INTO sqlite_stat4 VALUES('px','p_cid0','1525 1','29100 29302','42 29302',X'03020200bb00d1');
|
||||
INSERT INTO sqlite_stat4 VALUES('px','p_cid0','3703 1','30655 33323','45 33323',X'03020300be013fa5');
|
||||
INSERT INTO sqlite_stat4 VALUES('px','p_cid0','2612 1','37767 38147','61 38147',X'03020200e32828');
|
||||
INSERT INTO sqlite_stat4 VALUES('px','p_cid0','1882 1','40545 41584','63 41584',X'03020300ea01a35a');
|
||||
INSERT INTO sqlite_stat4 VALUES('px','p_cid0','6984 1','44110 50863','73 50863',X'0302030102017467');
|
||||
INSERT INTO sqlite_stat4 VALUES('px','p_cid0','1728 1','51230 51680','75 51680',X'030203010400b3e0');
|
||||
INSERT INTO sqlite_stat4 VALUES('px','p_cid0','2805 1','55491 57936','95 57936',X'030203014101a004');
|
||||
INSERT INTO sqlite_stat4 VALUES('px','p_cid0','2837 1','58934 59506','103 59506',X'030203015900a283');
|
||||
INSERT INTO sqlite_stat4 VALUES('px','p_cid0','94 1','63492 63579','137 63579',X'0302030191016319');
|
||||
INSERT INTO sqlite_stat4 VALUES('px','p_cid0','3573 1','63591 64497','140 64497',X'030203019c00822e');
|
||||
INSERT INTO sqlite_stat4 VALUES('px','p_cid0','5037 1','70917 73033','160 73033',X'03020301c70091d9');
|
||||
INSERT INTO sqlite_stat4 VALUES('px','p_cid0','1940 1','75954 76295','161 76295',X'03020201c817f1');
|
||||
INSERT INTO sqlite_stat4 VALUES('px','p_cid0','1927 1','83926 84371','209 84371',X'03020202114295');
|
||||
INSERT INTO sqlite_stat4 VALUES('px','p_cid0','1522 1','86601 88117','213 88117',X'030203021b01b7b5');
|
||||
INSERT INTO sqlite_stat4 VALUES('px','p_cid0','210 1','88906 89011','226 89011',X'030203022800dbbb');
|
||||
INSERT INTO sqlite_stat4 VALUES('px','p_cid0','6165 1','92125 98066','258 98066',X'030203024d0189ac');
|
||||
INSERT INTO sqlite_stat4 VALUES('px','p_cid0','2900 1','100721 101727','293 101727',X'030203027500cf39');
|
||||
INSERT INTO sqlite_stat4 VALUES('px','p_cid0','1501 1','110012 110154','503 110154',X'0302020380493a');
|
||||
INSERT INTO sqlite_stat4 VALUES('px','p_id','1 1','11129 11129','11129 11129',X'03030300d84e014d51');
|
||||
INSERT INTO sqlite_stat4 VALUES('px','p_id','1 1','12715 12715','12715 12715',X'03030200de816f51');
|
||||
INSERT INTO sqlite_stat4 VALUES('px','p_id','1 1','13030 13030','13030 13030',X'03030200e05b6fc4');
|
||||
INSERT INTO sqlite_stat4 VALUES('px','p_id','1 1','25431 25431','25431 25431',X'0303030123df00efb0');
|
||||
INSERT INTO sqlite_stat4 VALUES('px','p_id','1 1','29302 29302','29302 29302',X'030302013a2812c7');
|
||||
INSERT INTO sqlite_stat4 VALUES('px','p_id','1 1','35463 35463','35463 35463',X'03030301666e00f866');
|
||||
INSERT INTO sqlite_stat4 VALUES('px','p_id','1 1','38147 38147','38147 38147',X'030302017a391b74');
|
||||
INSERT INTO sqlite_stat4 VALUES('px','p_id','1 1','38525 38525','38525 38525',X'030303017c6e00fb58');
|
||||
INSERT INTO sqlite_stat4 VALUES('px','p_id','1 1','50863 50863','50863 50863',X'03030201b68724dd');
|
||||
INSERT INTO sqlite_stat4 VALUES('px','p_id','1 1','58461 58461','58461 58461',X'03030201d95b2e1e');
|
||||
INSERT INTO sqlite_stat4 VALUES('px','p_id','1 1','59506 59506','59506 59506',X'03030301dd7000a0fb');
|
||||
INSERT INTO sqlite_stat4 VALUES('px','p_id','1 1','63468 63468','63468 63468',X'03030301ecea011405');
|
||||
INSERT INTO sqlite_stat4 VALUES('px','p_id','1 1','63579 63579','63579 63579',X'03030201ed5932d5');
|
||||
INSERT INTO sqlite_stat4 VALUES('px','p_id','1 1','64497 64497','64497 64497',X'03030301f0ef00a680');
|
||||
INSERT INTO sqlite_stat4 VALUES('px','p_id','1 1','73033 73033','73033 73033',X'0303030225b90190e5');
|
||||
INSERT INTO sqlite_stat4 VALUES('px','p_id','1 1','75650 75650','75650 75650',X'030303023a19019362');
|
||||
INSERT INTO sqlite_stat4 VALUES('px','p_id','1 1','76295 76295','76295 76295',X'030303023e9801940c');
|
||||
INSERT INTO sqlite_stat4 VALUES('px','p_id','1 1','79152 79152','79152 79152',X'030303024be50196b9');
|
||||
INSERT INTO sqlite_stat4 VALUES('px','p_id','1 1','83249 83249','83249 83249',X'0303030261750123b1');
|
||||
INSERT INTO sqlite_stat4 VALUES('px','p_id','1 1','89011 89011','89011 89011',X'030303027b3900c3af');
|
||||
INSERT INTO sqlite_stat4 VALUES('px','p_id','1 1','98066 98066','98066 98066',X'03030302a76500ce54');
|
||||
INSERT INTO sqlite_stat4 VALUES('px','p_id','1 1','101590 101590','101590 101590',X'03030302b63d00d3b5');
|
||||
INSERT INTO sqlite_stat4 VALUES('px','p_id','1 1','101727 101727','101727 101727',X'03030202b6f24e9b');
|
||||
INSERT INTO sqlite_stat4 VALUES('px','p_id','1 1','107960 107960','107960 107960',X'03030302d8ce0136ad');
|
||||
ANALYZE sqlite_master;
|
||||
} {}
|
||||
|
||||
# The following query should do a full table scan of cx in the outer loop.
|
||||
# It is not correct to search table px using indx p_pt in the outer loop
|
||||
# with cx in the middle loop. Test case from Bloomberg on 2014-09-05.
|
||||
#
|
||||
do_execsql_test 4.2 {
|
||||
EXPLAIN QUERY PLAN
|
||||
SELECT
|
||||
px.name,
|
||||
px.description
|
||||
FROM
|
||||
le,
|
||||
cx,
|
||||
px
|
||||
WHERE
|
||||
cx.code = '2990'
|
||||
AND cx.type=2
|
||||
AND px.cx_id = cx.cx_id
|
||||
AND px.px_tid = 0
|
||||
AND px.le_id = le.le_id;
|
||||
} {/.*SCAN TABLE cx.*SEARCH TABLE px.*SEARCH TABLE le.*/}
|
||||
|
||||
|
||||
finish_test
|
||||
|
|
|
@ -1621,7 +1621,7 @@ ifcapable auth {
|
|||
}
|
||||
} {}
|
||||
|
||||
proc auth {args} {eval lappend ::authargs $args ; return SQLITE_OK}
|
||||
proc auth {args} {eval lappend ::authargs [lrange $args 0 4]; return SQLITE_OK}
|
||||
db auth auth
|
||||
|
||||
# An insert on the parent table must read the child key of any deferred
|
||||
|
|
Loading…
Reference in New Issue