Merge all recent trunk changes into the sessions branch.
FossilOrigin-Name: 6406b77f2c447751a2fbb16f01c61cdcfd6af59e
This commit is contained in:
commit
6b011d83b4
103
ext/misc/showauth.c
Normal file
103
ext/misc/showauth.c
Normal file
@ -0,0 +1,103 @@
|
||||
/*
|
||||
** 2014-09-21
|
||||
**
|
||||
** 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 SQLite extension adds a debug "authorizer" callback to the database
|
||||
** connection. The callback merely writes the authorization request to
|
||||
** standard output and returns SQLITE_OK.
|
||||
**
|
||||
** This extension can be used (for example) in the command-line shell to
|
||||
** trace the operation of the authorizer.
|
||||
*/
|
||||
#include "sqlite3ext.h"
|
||||
SQLITE_EXTENSION_INIT1
|
||||
#include <stdio.h>
|
||||
|
||||
/*
|
||||
** Display the authorization request
|
||||
*/
|
||||
static int authCallback(
|
||||
void *pClientData,
|
||||
int op,
|
||||
const char *z1,
|
||||
const char *z2,
|
||||
const char *z3,
|
||||
const char *z4
|
||||
){
|
||||
const char *zOp;
|
||||
char zOpSpace[50];
|
||||
switch( op ){
|
||||
case SQLITE_CREATE_INDEX: zOp = "CREATE_INDEX"; break;
|
||||
case SQLITE_CREATE_TABLE: zOp = "CREATE_TABLE"; break;
|
||||
case SQLITE_CREATE_TEMP_INDEX: zOp = "CREATE_TEMP_INDEX"; break;
|
||||
case SQLITE_CREATE_TEMP_TABLE: zOp = "CREATE_TEMP_TABLE"; break;
|
||||
case SQLITE_CREATE_TEMP_TRIGGER: zOp = "CREATE_TEMP_TRIGGER"; break;
|
||||
case SQLITE_CREATE_TEMP_VIEW: zOp = "CREATE_TEMP_VIEW"; break;
|
||||
case SQLITE_CREATE_TRIGGER: zOp = "CREATE_TRIGGER"; break;
|
||||
case SQLITE_CREATE_VIEW: zOp = "CREATE_VIEW"; break;
|
||||
case SQLITE_DELETE: zOp = "DELETE"; break;
|
||||
case SQLITE_DROP_INDEX: zOp = "DROP_INDEX"; break;
|
||||
case SQLITE_DROP_TABLE: zOp = "DROP_TABLE"; break;
|
||||
case SQLITE_DROP_TEMP_INDEX: zOp = "DROP_TEMP_INDEX"; break;
|
||||
case SQLITE_DROP_TEMP_TABLE: zOp = "DROP_TEMP_TABLE"; break;
|
||||
case SQLITE_DROP_TEMP_TRIGGER: zOp = "DROP_TEMP_TRIGGER"; break;
|
||||
case SQLITE_DROP_TEMP_VIEW: zOp = "DROP_TEMP_VIEW"; break;
|
||||
case SQLITE_DROP_TRIGGER: zOp = "DROP_TRIGGER"; break;
|
||||
case SQLITE_DROP_VIEW: zOp = "DROP_VIEW"; break;
|
||||
case SQLITE_INSERT: zOp = "INSERT"; break;
|
||||
case SQLITE_PRAGMA: zOp = "PRAGMA"; break;
|
||||
case SQLITE_READ: zOp = "READ"; break;
|
||||
case SQLITE_SELECT: zOp = "SELECT"; break;
|
||||
case SQLITE_TRANSACTION: zOp = "TRANSACTION"; break;
|
||||
case SQLITE_UPDATE: zOp = "UPDATE"; break;
|
||||
case SQLITE_ATTACH: zOp = "ATTACH"; break;
|
||||
case SQLITE_DETACH: zOp = "DETACH"; break;
|
||||
case SQLITE_ALTER_TABLE: zOp = "ALTER_TABLE"; break;
|
||||
case SQLITE_REINDEX: zOp = "REINDEX"; break;
|
||||
case SQLITE_ANALYZE: zOp = "ANALYZE"; break;
|
||||
case SQLITE_CREATE_VTABLE: zOp = "CREATE_VTABLE"; break;
|
||||
case SQLITE_DROP_VTABLE: zOp = "DROP_VTABLE"; break;
|
||||
case SQLITE_FUNCTION: zOp = "FUNCTION"; break;
|
||||
case SQLITE_SAVEPOINT: zOp = "SAVEPOINT"; break;
|
||||
case SQLITE_COPY: zOp = "COPY"; break;
|
||||
case SQLITE_RECURSIVE: zOp = "RECURSIVE"; break;
|
||||
|
||||
|
||||
default: {
|
||||
sqlite3_snprintf(sizeof(zOpSpace), zOpSpace, "%d", op);
|
||||
zOp = zOpSpace;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( z1==0 ) z1 = "NULL";
|
||||
if( z2==0 ) z2 = "NULL";
|
||||
if( z3==0 ) z3 = "NULL";
|
||||
if( z4==0 ) z4 = "NULL";
|
||||
printf("AUTH: %s,%s,%s,%s,%s\n", zOp, z1, z2, z3, z4);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
__declspec(dllexport)
|
||||
#endif
|
||||
int sqlite3_showauth_init(
|
||||
sqlite3 *db,
|
||||
char **pzErrMsg,
|
||||
const sqlite3_api_routines *pApi
|
||||
){
|
||||
int rc = SQLITE_OK;
|
||||
SQLITE_EXTENSION_INIT2(pApi);
|
||||
(void)pzErrMsg; /* Unused parameter */
|
||||
rc = sqlite3_set_authorizer(db, authCallback, 0);
|
||||
return rc;
|
||||
}
|
88
ext/userauth/sqlite3userauth.h
Normal file
88
ext/userauth/sqlite3userauth.h
Normal file
@ -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 */
|
164
ext/userauth/user-auth.txt
Normal file
164
ext/userauth/user-auth.txt
Normal file
@ -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.
|
355
ext/userauth/userauth.c
Normal file
355
ext/userauth/userauth.c
Normal file
@ -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
|
||||
TCCX += -I$(TOP)/ext/session
|
||||
|
||||
# Object files for the SQLite library.
|
||||
@ -68,7 +68,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
|
||||
|
||||
@ -220,7 +220,9 @@ SRC += \
|
||||
SRC += \
|
||||
$(TOP)/ext/session/sqlite3session.c \
|
||||
$(TOP)/ext/session/sqlite3session.h
|
||||
|
||||
SRC += \
|
||||
$(TOP)/ext/userauth/userauth.c \
|
||||
$(TOP)/ext/userauth/sqlite3userauth.h
|
||||
|
||||
# Generated source code files
|
||||
#
|
||||
@ -385,6 +387,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.
|
||||
@ -567,6 +571,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
|
||||
|
||||
sqlite3session.o: $(TOP)/ext/session/sqlite3session.c $(HDR) $(EXTHDR)
|
||||
$(TCCX) -DSQLITE_CORE -c $(TOP)/ext/session/sqlite3session.c
|
||||
|
||||
|
130
manifest
130
manifest
@ -1,5 +1,5 @@
|
||||
C Merge\ssupport\sfor\slarge\sfiles\son\sAndroid\sfrom\strunk.
|
||||
D 2014-09-08T15:04:24.810
|
||||
C Merge\sall\srecent\strunk\schanges\sinto\sthe\ssessions\sbranch.
|
||||
D 2014-09-21T22:49:20.257
|
||||
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
|
||||
F Makefile.in dd5f245aa8c741bc65845747203c8ce2f3fb6c83
|
||||
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
|
||||
@ -116,6 +116,7 @@ F ext/misc/nextchar.c 35c8b8baacb96d92abbb34a83a997b797075b342
|
||||
F ext/misc/percentile.c bcbee3c061b884eccb80e21651daaae8e1e43c63
|
||||
F ext/misc/regexp.c af92cdaa5058fcec1451e49becc7ba44dba023dc
|
||||
F ext/misc/rot13.c 1ac6f95f99b575907b9b09c81a349114cf9be45a
|
||||
F ext/misc/showauth.c 732578f0fe4ce42d577e1c86dc89dd14a006ab52
|
||||
F ext/misc/spellfix.c 56739fab8c2ed6a9e2dac5592a88d281a999c43b
|
||||
F ext/misc/totype.c 4a167594e791abeed95e0a8db028822b5e8fe512
|
||||
F ext/misc/vfslog.c fe40fab5c077a40477f7e5eba994309ecac6cc95
|
||||
@ -160,10 +161,13 @@ F ext/session/sessionfault.test e7965159a73d385c1a4af12d82c3a039ebdd71a6
|
||||
F ext/session/sqlite3session.c 4c7689bd8286147f7d9bf5d4b6ca5e7e7ee588ab
|
||||
F ext/session/sqlite3session.h 66c14a2f6193c47773770307636e88c43db6f839
|
||||
F ext/session/test_session.c a252fb669d3a1b3552ee7b87fe610debc0afeb7b
|
||||
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 4dfbd8fbc91ee5732554b31a205960241c4fc059
|
||||
F main.mk 7711bc77822814799b853271ee19ac79e98bfb4b
|
||||
F mkopcodec.awk c2ff431854d702cdd2d779c9c0d1f58fa16fa4ea
|
||||
F mkopcodeh.awk c6b3fa301db6ef7ac916b14c60868aeaec1337b5
|
||||
F mkso.sh fd21c06b063bb16a5d25deea1752c2da6ac3ed83
|
||||
@ -178,36 +182,36 @@ F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b
|
||||
F sqlite3.1 3d8b83c91651f53472ca17599dae3457b8b89494
|
||||
F sqlite3.pc.in 48fed132e7cb71ab676105d2a4dc77127d8c1f3a
|
||||
F src/alter.c ba266a779bc7ce10e52e59e7d3dc79fa342e8fdb
|
||||
F src/analyze.c 79383a54fee3b7f1fb03dd4c8c8115583f506de5
|
||||
F src/attach.c 3801129015ef59d76bf23c95ef9b0069d18a0c52
|
||||
F src/auth.c 523da7fb4979469955d822ff9298352d6b31de34
|
||||
F src/analyze.c 6290a109be876daaa242cd7216f97240f5401776
|
||||
F src/attach.c f4e94df2d1826feda65eb0939f7f6f5f923a0ad9
|
||||
F src/auth.c d8abcde53426275dab6243b441256fcd8ccbebb2
|
||||
F src/backup.c a31809c65623cc41849b94d368917f8bb66e6a7e
|
||||
F src/bitvec.c 19a4ba637bd85f8f63fc8c9bae5ade9fb05ec1cb
|
||||
F src/btmutex.c 49ca66250c7dfa844a4d4cb8272b87420d27d3a5
|
||||
F src/btree.c b1c1cd1cc3ae2e433a23b9a6c9ab53805707d8cd
|
||||
F src/btree.c 6aa61c0e3d20d1d1acc8fb33d8f0ebd675305d3c
|
||||
F src/btree.h a79aa6a71e7f1055f01052b7f821bd1c2dce95c8
|
||||
F src/btreeInt.h e0ecb5dba292722039a7540beb3fc448103273cc
|
||||
F src/build.c 8cb237719c185eec7bd8449b2e747491ded11932
|
||||
F src/build.c 8dbca25988045fbf2a33c9631c42706fa6449e60
|
||||
F src/callback.c 7b44ce59674338ad48b0e84e7b72f935ea4f68b0
|
||||
F src/complete.c 535183afb3c75628b78ce82612931ac7cdf26f14
|
||||
F src/ctime.c 0231df905e2c4abba4483ee18ffc05adc321df2a
|
||||
F src/ctime.c 16cd19215d9fd849ee2b7509b092f2e0bbd6a958
|
||||
F src/date.c 57a7f9ba9f6b4d5268f5e411739066a611f99036
|
||||
F src/delete.c de3d07d6602b90ae6e8bdebeb7b3265bb846377f
|
||||
F src/expr.c 441a7e24e2f7bea9475778fa8acce9e8a69ca8f0
|
||||
F src/expr.c 4f101c8ddc6d5a22303c88278069f5261562a9a8
|
||||
F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb
|
||||
F src/fkey.c da985ae673efef2c712caef825a5d2edb087ead7
|
||||
F src/func.c 0517037766e18eff7dce298e6b3a8e6311df75ec
|
||||
F src/func.c 1629ccdd8ef3f19d7accc9d9287190489469ff81
|
||||
F src/global.c 5110fa12e09729b84eee0191c984ec4008e21937
|
||||
F src/hash.c 4263fbc955f26c2e8cdc0cf214bc42435aa4e4f5
|
||||
F src/hash.h c8f3c31722cf3277d03713909761e152a5b81094
|
||||
F src/hwtime.h d32741c8f4df852c7d959236615444e2b1063b08
|
||||
F src/insert.c 92e955206fadb4d1184161d00894b32c90879e86
|
||||
F src/insert.c 4f6df86bbed2d7b59e4601730407876825dd7b71
|
||||
F src/journal.c b4124532212b6952f42eb2c12fa3c25701d8ba8d
|
||||
F src/legacy.c 87c92f4a08e2f70220e3b22a9c3b2482d36a134a
|
||||
F src/lempar.c cdf0a000315332fc9b50b62f3b5e22e080a0952b
|
||||
F src/loadext.c 31c2122b7dd05a179049bbf163fd4839f181cbab
|
||||
F src/main.c faf3629e61ba31912b474316c02f173878ddd566
|
||||
F src/malloc.c 954de5f998c23237e04474a3f2159bf483bba65a
|
||||
F src/legacy.c ba1863ea58c4c840335a84ec276fc2b25e22bc4e
|
||||
F src/lempar.c 7274c97d24bb46631e504332ccd3bd1b37841770
|
||||
F src/loadext.c de741e66e5ddc1598d904d7289239696e40ed994
|
||||
F src/main.c 1010acfb69ccd62e34e3b83664537450225c74e2
|
||||
F src/malloc.c 5bb99ee1e08ad58e457063cf79ce521db0e24195
|
||||
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
|
||||
F src/mem1.c faf615aafd8be74a71494dfa027c113ea5c6615f
|
||||
F src/mem2.c dce31758da87ec2cfa52ba4c5df1aed6e07d8e8f
|
||||
@ -224,32 +228,32 @@ F src/os.c 1b147e4cf7cc39e618115c14a086aed44bc91ace
|
||||
F src/os.h 3e57a24e2794a94d3cf2342c6d9a884888cd96bf
|
||||
F src/os_common.h 92815ed65f805560b66166e3583470ff94478f04
|
||||
F src/os_setup.h c9d4553b5aaa6f73391448b265b89bed0b890faa
|
||||
F src/os_unix.c addd023b26c623fec4dedc110fc4370a65b4768c
|
||||
F src/os_unix.c 9096a1b1449182e67e759f59994eee04113bc587
|
||||
F src/os_win.c 0a4042ef35f322e86fa01f6c8884c5e645b911e7
|
||||
F src/os_win.h 09e751b20bbc107ffbd46e13555dc73576d88e21
|
||||
F src/pager.c 31da9594ad4c3b5851bb6fe1a95c33835ab7ddce
|
||||
F src/pager.c caab007743821d96752597c9cfd7351654697b06
|
||||
F src/pager.h ffd5607f7b3e4590b415b007a4382f693334d428
|
||||
F src/parse.y 22d6a074e5f5a7258947a1dc55a9bf946b765dd0
|
||||
F src/pcache.c 2048affdb09a04478b5fc6e64cb1083078d369be
|
||||
F src/parse.y b98772da2bb5415970085b707203f92569400aa8
|
||||
F src/pcache.c 4121a0571c18581ee9f82f086d5e2030051ebd6a
|
||||
F src/pcache.h 9b559127b83f84ff76d735c8262f04853be0c59a
|
||||
F src/pcache1.c dab8ab930d4a73b99768d881185994f34b80ecaa
|
||||
F src/pragma.c 14bcdb504128a476cce5bbc086d5226c5e46c225
|
||||
F src/prepare.c 3842c1dfc0b053458e3adcf9f6efc48e03e3fe3d
|
||||
F src/printf.c e74925089a85e3c9f0e315595f41c139d3d118c2
|
||||
F src/pragma.c 3f3e959390a10c0131676f0e307acce372777e0f
|
||||
F src/prepare.c 6ef0cf2f9274982988ed6b7cab1be23147e94196
|
||||
F src/printf.c 3a47f526b173813d9a7f4e7044007771ba68cde1
|
||||
F src/random.c d10c1f85b6709ca97278428fd5db5bbb9c74eece
|
||||
F src/resolve.c 0d1621e45fffe4b4396477cf46e41a84b0145ffb
|
||||
F src/resolve.c a3466128b52a86c466e47ac1a19e2174f7b5cf89
|
||||
F src/rowset.c eccf6af6d620aaa4579bd3b72c1b6395d9e9fa1e
|
||||
F src/select.c b4457526cee73c0b69fad42f799f619b1d5a8a8a
|
||||
F src/shell.c ec6d5f630ed617dc80cbc35d9e45fe47f07923db
|
||||
F src/sqlite.h.in 70de5c9e5ac117363db78d144c7e6f1f65d007a1
|
||||
F src/select.c a83ed8bc2a31c131e3addb6f0488b68334085e7b
|
||||
F src/shell.c 85aae71dcc9bd6df28047b95ab631eb0ac91401f
|
||||
F src/sqlite.h.in 1af072be5ed8902c8c12b5b105487d0efedd00b4
|
||||
F src/sqlite3.rc 992c9f5fb8285ae285d6be28240a7e8d3a7f2bad
|
||||
F src/sqlite3ext.h 1f40357fb9b12a80c5a3b2b109fd249b009213d4
|
||||
F src/sqliteInt.h 4d6c5c87324c2b6218c01a0895c0d298fffb5aff
|
||||
F src/sqlite3ext.h 17d487c3c91b0b8c584a32fbeb393f6f795eea7d
|
||||
F src/sqliteInt.h 35f074ded974804602e3ed89576a74c9b7255c93
|
||||
F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d
|
||||
F src/status.c 7ac05a5c7017d0b9f0b4bcd701228b784f987158
|
||||
F src/table.c 4e28a53e66bad8d014a510ef0205f5497c712b08
|
||||
F src/tclsqlite.c 9d0073dda76ab2508c8fde50950f4556fe2fdafb
|
||||
F src/test1.c 22bfe1ce9f2f3746d682093a475ec0a33e0e55d8
|
||||
F src/table.c 2e99ef7ef16187e17033d9398dc962ce22dab5cb
|
||||
F src/tclsqlite.c 684c317b85f4729de12909bfad80d3f5500357cf
|
||||
F src/test1.c 523cd70ded28db71af9a30ec184cbe0957de9575
|
||||
F src/test2.c 98049e51a17dc62606a99a9eb95ee477f9996712
|
||||
F src/test3.c 1c0e5d6f080b8e33c1ce8b3078e7013fdbcd560c
|
||||
F src/test4.c 9b32d22f5f150abe23c1830e2057c4037c45b3df
|
||||
@ -262,11 +266,11 @@ 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 a65043d01ad3bd2dfe9a3aa7e39a9935b069f6aa
|
||||
F src/test_config.c 5a2a9a580f9c2dfd2ffd52966fd361f2148909d1
|
||||
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_func.c 14e543ae4d905ee31dc322b2f8d31bfac1769d45
|
||||
F src/test_hexio.c abfdecb6fa58c354623978efceb088ca18e379cd
|
||||
F src/test_init.c 66b33120ffe9cd853b5a905ec850d51151337b32
|
||||
F src/test_intarray.c 6c610a21ab8edde85a3a2c7f2b069244ecf4d834
|
||||
@ -295,30 +299,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 722872c816887fd66931333c59570ebd9622a95f
|
||||
F src/tokenize.c 3df63041994f55afeb168b463ec836e8f1c50e7c
|
||||
F src/trigger.c 25571661fdeae8c7f975ff40ffec205520a3f92f
|
||||
F src/update.c b9e5295d3a78e96b7c2978c4f9d224d06880f031
|
||||
F src/utf.c 77abb5e6d27f3d236e50f7c8fff1d00e15262359
|
||||
F src/utf.c fc6b889ba0779b7722634cdeaa25f1930d93820c
|
||||
F src/util.c 4006c01772bd8d8ac4306d523bbcee41d3e392d8
|
||||
F src/vacuum.c 59f03f92bcff57faa6a8ca256eb29ccddfb0614a
|
||||
F src/vdbe.c 16b7d573a683e70a1e502332c5f90dd48fa34736
|
||||
F src/vdbe.h ca3b6df299adce6e2f499c57e42ae54f142ae823
|
||||
F src/vdbeInt.h 0dec00acd7e490a456a0ebaa6f478de94da7b52d
|
||||
F src/vdbeapi.c d63985095b5d24b522fc206c547df1683a4e73ee
|
||||
F src/vdbeaux.c 264284931ecd079076ab40a71522570107b8e723
|
||||
F src/vdbe.c 5e6d4ef36cfff2bacb4d11eccc99bd55c76692f5
|
||||
F src/vdbe.h d61daeffed696e21630759de9e135ee298ad9573
|
||||
F src/vdbeInt.h 0e6e8d18199cef7dd5e9fa5de8490f60806259f0
|
||||
F src/vdbeapi.c cdded67e36d2a20f6d1c7d56f008a646557d2bf0
|
||||
F src/vdbeaux.c 07b0045d0f34d0ad70c1c42ff75246a7e64e4e87
|
||||
F src/vdbeblob.c d65b01f439df63911ac3d7a9a85c15503965f2c3
|
||||
F src/vdbemem.c dc36ea9fe26c25550c50085f388167086ef7d73a
|
||||
F src/vdbesort.c ab39574ec6e0c6213bd2a5c09cca9f9f8ba98450
|
||||
F src/vdbetrace.c 16d39c1ef7d1f4a3a7464bea3b7b4bdd7849c415
|
||||
F src/vdbemem.c 5096fe50a1bd12bc2294a8b27ca6e6d1b15ef607
|
||||
F src/vdbesort.c 5c1bacf90578d22b630fbf6ed98ccf60d83435ef
|
||||
F src/vdbetrace.c 4f29b04edb0cec3d5fcd9b566d9f0e75c8984362
|
||||
F src/vtab.c 019dbfd0406a7447c990e1f7bd1dfcdb8895697f
|
||||
F src/wal.c 10e7de7ce90865a68153f001a61f1d985cd17983
|
||||
F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4
|
||||
F src/walker.c c253b95b4ee44b21c406e2a1052636c31ea27804
|
||||
F src/where.c 839b5e1db2507e221ad1c308f148a8519ed750be
|
||||
F src/where.c 0888567c0e01a41b6001647e333f8ccfd3ae7d36
|
||||
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
|
||||
@ -349,9 +353,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
|
||||
@ -492,7 +496,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
|
||||
@ -590,7 +594,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
|
||||
@ -725,7 +729,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
|
||||
@ -752,7 +756,7 @@ F test/notnull.test f8fcf58669ddba79274daa2770d61dfad8274f62
|
||||
F test/null.test a8b09b8ed87852742343b33441a9240022108993
|
||||
F test/numcast.test 5d126f7f581432e86a90d1e35cac625164aec4a1
|
||||
F test/openv2.test 0d3040974bf402e19b7df4b783e447289d7ab394
|
||||
F test/orderby1.test 12426f99518cde45f34215ca6a0ebc0e9bc5c77a
|
||||
F test/orderby1.test eb246e377612b21a418fbea57047ba8ea88aaa6b
|
||||
F test/orderby2.test bc11009f7cd99d96b1b11e57b199b00633eb5b04
|
||||
F test/orderby3.test 8619d06a3debdcd80a27c0fdea5c40b468854b99
|
||||
F test/orderby4.test 4d39bfbaaa3ae64d026ca2ff166353d2edca4ba4
|
||||
@ -798,7 +802,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
|
||||
@ -859,6 +863,7 @@ F test/sort.test 15e1d3014abc3f6d4357ed81b93b82117aefd235
|
||||
F test/sort2.test 269f4f50c6e468cc32b302ae7ff0add8338ec6de
|
||||
F test/sort3.test 6178ade30810ac9166fcdf14b7065e49c0f534e2
|
||||
F test/sort4.test 6c37d85f7cd28d50cce222fcab84ccd771e105cb
|
||||
F test/sort5.test a448240a42b49239edc00f85d6d7ac7a1b261e1f
|
||||
F test/sortfault.test b8e35177f97438b930ee87c9419ca2599e8073e1
|
||||
F test/speed1.test f2974a91d79f58507ada01864c0e323093065452
|
||||
F test/speed1p.explain d841e650a04728b39e6740296b852dccdca9b2cb
|
||||
@ -874,7 +879,7 @@ F test/sqllimits1.test b1aae27cc98eceb845e7f7adf918561256e31298
|
||||
F test/stat.test 76fd746b85459e812a0193410fb599f0531f22de
|
||||
F test/stmt.test 25d64e3dbf9a3ce89558667d7f39d966fe2a71b9
|
||||
F test/subquery.test 666fdecceac258f5fd84bed09a64e49d9f37edd9
|
||||
F test/subquery2.test 91e1e364072aeff431d1f9689b15147e421d88c7
|
||||
F test/subquery2.test 438f8a7da1457277b22e4176510f7659b286995f
|
||||
F test/subselect.test d24fd8757daf97dafd2e889c73ea4c4272dcf4e4
|
||||
F test/substr.test 18f57c4ca8a598805c4d64e304c418734d843c1a
|
||||
F test/superlock.test 1cde669f68d2dd37d6c9bd35eee1d95491ae3fc2
|
||||
@ -1071,6 +1076,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
|
||||
@ -1081,7 +1087,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
|
||||
@ -1153,7 +1159,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
|
||||
@ -1191,7 +1197,7 @@ F tool/rollback-test.c 9fc98427d1e23e84429d7e6d07d9094fbdec65a5
|
||||
F tool/showdb.c bd073a78bce714a0e42d92ea474b3eb8cb53be5d
|
||||
F tool/showjournal.c 053eb1cc774710c6890b7dd6293300cc297b16a5
|
||||
F tool/showstat4.c c39279d6bd37cb999b634f0064f6f86ad7af008f
|
||||
F tool/showwal.c 3209120269cdf9380f091459e47b776b4f81dfd3
|
||||
F tool/showwal.c 85cb36d4fe3e93e2fbd63e786e0d1ce42d0c4fad
|
||||
F tool/soak1.tcl 8d407956e1a45b485a8e072470a3e629a27037fe
|
||||
F tool/space_used.tcl f714c41a59e326b8b9042f415b628b561bafa06b
|
||||
F tool/spaceanal.tcl 8e50b217c56a6a086a1b47eac9d09c5cd65b996f
|
||||
@ -1210,7 +1216,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 d4cce2c71e64ab7b6a65a81b88b69445ed859351 ad7063aa1a0db32cdbe71815545b2edca57d3bcc
|
||||
R 4a5cc1720b7ac28a8c5dae667ce4d5c3
|
||||
P c2885c6bb24cc55178467e57e77bf71df58b3b13 d5880abd63c83c88e135257373afa0a3fd88297e
|
||||
R 9d7f30c83131a55806d3c1dd053387df
|
||||
U drh
|
||||
Z 6dac05eb8bc8db62f0a6dc6a2d623660
|
||||
Z c53e54ee2e290caf615c330d235d140a
|
||||
|
@ -1 +1 @@
|
||||
c2885c6bb24cc55178467e57e77bf71df58b3b13
|
||||
6406b77f2c447751a2fbb16f01c61cdcfd6af59e
|
@ -1201,7 +1201,8 @@ static void analyzeOneTable(
|
||||
|
||||
/* Add the entry to the stat1 table. */
|
||||
callStatGet(v, regStat4, STAT_GET_STAT1, regStat1);
|
||||
sqlite3VdbeAddOp4(v, OP_MakeRecord, regTabname, 3, regTemp, "aaa", 0);
|
||||
assert( "BBB"[0]==SQLITE_AFF_TEXT );
|
||||
sqlite3VdbeAddOp4(v, OP_MakeRecord, regTabname, 3, regTemp, "BBB", 0);
|
||||
sqlite3VdbeAddOp2(v, OP_NewRowid, iStatCur, regNewRowid);
|
||||
sqlite3VdbeAddOp3(v, OP_Insert, iStatCur, regTemp, regNewRowid);
|
||||
sqlite3VdbeChangeP5(v, OPFLAG_APPEND);
|
||||
@ -1264,7 +1265,8 @@ static void analyzeOneTable(
|
||||
sqlite3VdbeAddOp2(v, OP_Count, iTabCur, regStat1);
|
||||
jZeroRows = sqlite3VdbeAddOp1(v, OP_IfNot, regStat1); VdbeCoverage(v);
|
||||
sqlite3VdbeAddOp2(v, OP_Null, 0, regIdxname);
|
||||
sqlite3VdbeAddOp4(v, OP_MakeRecord, regTabname, 3, regTemp, "aaa", 0);
|
||||
assert( "BBB"[0]==SQLITE_AFF_TEXT );
|
||||
sqlite3VdbeAddOp4(v, OP_MakeRecord, regTabname, 3, regTemp, "BBB", 0);
|
||||
sqlite3VdbeAddOp2(v, OP_NewRowid, iStatCur, regNewRowid);
|
||||
sqlite3VdbeAddOp3(v, OP_Insert, iStatCur, regTemp, regNewRowid);
|
||||
sqlite3VdbeChangeP5(v, OPFLAG_APPEND);
|
||||
|
@ -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;
|
||||
|
@ -606,7 +606,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 ){
|
||||
@ -4746,14 +4746,14 @@ int sqlite3BtreeMovetoUnpacked(
|
||||
** single byte varint and the record fits entirely on the main
|
||||
** b-tree page. */
|
||||
testcase( pCell+nCell+1==pPage->aDataEnd );
|
||||
c = xRecordCompare(nCell, (void*)&pCell[1], pIdxKey, 0);
|
||||
c = xRecordCompare(nCell, (void*)&pCell[1], pIdxKey);
|
||||
}else if( !(pCell[1] & 0x80)
|
||||
&& (nCell = ((nCell&0x7f)<<7) + pCell[1])<=pPage->maxLocal
|
||||
){
|
||||
/* The record-size field is a 2 byte varint and the record
|
||||
** fits entirely on the main b-tree page. */
|
||||
testcase( pCell+nCell+2==pPage->aDataEnd );
|
||||
c = xRecordCompare(nCell, (void*)&pCell[2], pIdxKey, 0);
|
||||
c = xRecordCompare(nCell, (void*)&pCell[2], pIdxKey);
|
||||
}else{
|
||||
/* The record flows over onto one or more overflow pages. In
|
||||
** this case the whole cell needs to be parsed, a buffer allocated
|
||||
@ -4774,7 +4774,7 @@ int sqlite3BtreeMovetoUnpacked(
|
||||
sqlite3_free(pCellKey);
|
||||
goto moveto_finish;
|
||||
}
|
||||
c = xRecordCompare(nCell, pCellKey, pIdxKey, 0);
|
||||
c = xRecordCompare(nCell, pCellKey, pIdxKey);
|
||||
sqlite3_free(pCellKey);
|
||||
}
|
||||
assert(
|
||||
|
52
src/build.c
52
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;
|
||||
}
|
||||
|
||||
@ -1143,7 +1177,7 @@ char sqlite3AffinityType(const char *zIn, u8 *pszEst){
|
||||
** estimate is scaled so that the size of an integer is 1. */
|
||||
if( pszEst ){
|
||||
*pszEst = 1; /* default size is approx 4 bytes */
|
||||
if( aff<=SQLITE_AFF_NONE ){
|
||||
if( aff<SQLITE_AFF_NUMERIC ){
|
||||
if( zChar ){
|
||||
while( zChar[0] ){
|
||||
if( sqlite3Isdigit(zChar[0]) ){
|
||||
@ -1514,8 +1548,8 @@ static char *createTableStmt(sqlite3 *db, Table *p){
|
||||
zStmt[k++] = '(';
|
||||
for(pCol=p->aCol, i=0; i<p->nCol; i++, pCol++){
|
||||
static const char * const azType[] = {
|
||||
/* SQLITE_AFF_TEXT */ " TEXT",
|
||||
/* SQLITE_AFF_NONE */ "",
|
||||
/* SQLITE_AFF_TEXT */ " TEXT",
|
||||
/* SQLITE_AFF_NUMERIC */ " NUM",
|
||||
/* SQLITE_AFF_INTEGER */ " INT",
|
||||
/* SQLITE_AFF_REAL */ " REAL"
|
||||
@ -1527,15 +1561,15 @@ static char *createTableStmt(sqlite3 *db, Table *p){
|
||||
k += sqlite3Strlen30(&zStmt[k]);
|
||||
zSep = zSep2;
|
||||
identPut(zStmt, &k, pCol->zName);
|
||||
assert( pCol->affinity-SQLITE_AFF_TEXT >= 0 );
|
||||
assert( pCol->affinity-SQLITE_AFF_TEXT < ArraySize(azType) );
|
||||
testcase( pCol->affinity==SQLITE_AFF_TEXT );
|
||||
assert( pCol->affinity-SQLITE_AFF_NONE >= 0 );
|
||||
assert( pCol->affinity-SQLITE_AFF_NONE < ArraySize(azType) );
|
||||
testcase( pCol->affinity==SQLITE_AFF_NONE );
|
||||
testcase( pCol->affinity==SQLITE_AFF_TEXT );
|
||||
testcase( pCol->affinity==SQLITE_AFF_NUMERIC );
|
||||
testcase( pCol->affinity==SQLITE_AFF_INTEGER );
|
||||
testcase( pCol->affinity==SQLITE_AFF_REAL );
|
||||
|
||||
zType = azType[pCol->affinity - SQLITE_AFF_TEXT];
|
||||
zType = azType[pCol->affinity - SQLITE_AFF_NONE];
|
||||
len = sqlite3Strlen30(zType);
|
||||
assert( pCol->affinity==SQLITE_AFF_NONE
|
||||
|| pCol->affinity==sqlite3AffinityType(zType, 0) );
|
||||
@ -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 );
|
||||
|
||||
@ -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;
|
||||
|
@ -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
|
||||
|
10
src/expr.c
10
src/expr.c
@ -1069,6 +1069,7 @@ Select *sqlite3SelectDup(sqlite3 *db, Select *p, int flags){
|
||||
pNew->addrOpenEphm[1] = -1;
|
||||
pNew->nSelectRow = p->nSelectRow;
|
||||
pNew->pWith = withDup(db, p->pWith);
|
||||
sqlite3SelectSetName(pNew, p->zSelName);
|
||||
return pNew;
|
||||
}
|
||||
#else
|
||||
@ -2432,16 +2433,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)
|
||||
|
23
src/func.c
23
src/func.c
@ -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);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1491,6 +1492,7 @@ static void minmaxStep(
|
||||
sqlite3SkipAccumulatorLoad(context);
|
||||
}
|
||||
}else{
|
||||
pBest->db = sqlite3_context_db_handle(context);
|
||||
sqlite3VdbeMemCopy(pBest, pArg);
|
||||
}
|
||||
}
|
||||
@ -1662,10 +1664,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 +1699,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 +1722,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),
|
||||
|
22
src/insert.c
22
src/insert.c
@ -56,13 +56,13 @@ void sqlite3OpenTable(
|
||||
**
|
||||
** Character Column affinity
|
||||
** ------------------------------
|
||||
** 'a' TEXT
|
||||
** 'b' NONE
|
||||
** 'c' NUMERIC
|
||||
** 'd' INTEGER
|
||||
** 'e' REAL
|
||||
** 'A' NONE
|
||||
** 'B' TEXT
|
||||
** 'C' NUMERIC
|
||||
** 'D' INTEGER
|
||||
** 'F' REAL
|
||||
**
|
||||
** An extra 'd' is appended to the end of the string to cover the
|
||||
** An extra 'D' is appended to the end of the string to cover the
|
||||
** rowid that appears as the last column in every index.
|
||||
**
|
||||
** Memory for the buffer containing the column index affinity string
|
||||
@ -111,11 +111,11 @@ const char *sqlite3IndexAffinityStr(Vdbe *v, Index *pIdx){
|
||||
**
|
||||
** Character Column affinity
|
||||
** ------------------------------
|
||||
** 'a' TEXT
|
||||
** 'b' NONE
|
||||
** 'c' NUMERIC
|
||||
** 'd' INTEGER
|
||||
** 'e' REAL
|
||||
** 'A' NONE
|
||||
** 'B' TEXT
|
||||
** 'C' NUMERIC
|
||||
** 'D' INTEGER
|
||||
** 'E' REAL
|
||||
*/
|
||||
void sqlite3TableAffinity(Vdbe *v, Table *pTab, int iReg){
|
||||
int i;
|
||||
|
@ -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
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -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;
|
||||
|
||||
@ -2587,7 +2591,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.
|
||||
*/
|
||||
|
75
src/malloc.c
75
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
|
||||
@ -307,10 +305,10 @@ void *sqlite3Malloc(int n){
|
||||
p = 0;
|
||||
}else if( sqlite3GlobalConfig.bMemstat ){
|
||||
sqlite3_mutex_enter(mem0.mutex);
|
||||
mallocWithAlarm(n, &p);
|
||||
mallocWithAlarm((int)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
|
||||
@ -447,17 +451,23 @@ int sqlite3MallocSize(void *p){
|
||||
return sqlite3GlobalConfig.m.xSize(p);
|
||||
}
|
||||
int sqlite3DbMallocSize(sqlite3 *db, void *p){
|
||||
assert( db!=0 );
|
||||
assert( sqlite3_mutex_held(db->mutex) );
|
||||
if( isLookaside(db, p) ){
|
||||
return db->lookaside.sz;
|
||||
if( db==0 ){
|
||||
return sqlite3MallocSize(p);
|
||||
}else{
|
||||
assert( sqlite3MemdebugHasType(p, MEMTYPE_DB) );
|
||||
assert( sqlite3MemdebugHasType(p, MEMTYPE_LOOKASIDE|MEMTYPE_HEAP) );
|
||||
assert( db!=0 || sqlite3MemdebugNoType(p, MEMTYPE_LOOKASIDE) );
|
||||
return sqlite3GlobalConfig.m.xSize(p);
|
||||
assert( sqlite3_mutex_held(db->mutex) );
|
||||
if( isLookaside(db, p) ){
|
||||
return db->lookaside.sz;
|
||||
}else{
|
||||
assert( sqlite3MemdebugHasType(p, MEMTYPE_DB) );
|
||||
assert( sqlite3MemdebugHasType(p, MEMTYPE_LOOKASIDE|MEMTYPE_HEAP) );
|
||||
assert( db!=0 || sqlite3MemdebugNoType(p, MEMTYPE_LOOKASIDE) );
|
||||
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 +529,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,12 +547,12 @@ 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 ){
|
||||
sqlite3_mutex_enter(mem0.mutex);
|
||||
sqlite3StatusSet(SQLITE_STATUS_MALLOC_SIZE, nBytes);
|
||||
sqlite3StatusSet(SQLITE_STATUS_MALLOC_SIZE, (int)nBytes);
|
||||
nDiff = nNew - nOld;
|
||||
if( sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED) >=
|
||||
mem0.alarmThreshold-nDiff ){
|
||||
@ -552,7 +562,7 @@ void *sqlite3Realloc(void *pOld, int nBytes){
|
||||
assert( sqlite3MemdebugNoType(pOld, ~MEMTYPE_HEAP) );
|
||||
pNew = sqlite3GlobalConfig.m.xRealloc(pOld, nNew);
|
||||
if( pNew==0 && mem0.alarmCallback ){
|
||||
sqlite3MallocAlarm(nBytes);
|
||||
sqlite3MallocAlarm((int)nBytes);
|
||||
pNew = sqlite3GlobalConfig.m.xRealloc(pOld, nNew);
|
||||
}
|
||||
if( pNew ){
|
||||
@ -572,6 +582,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,10 +599,10 @@ 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);
|
||||
memset(p, 0, (size_t)n);
|
||||
}
|
||||
return p;
|
||||
}
|
||||
@ -594,10 +611,10 @@ 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);
|
||||
memset(p, 0, (size_t)n);
|
||||
}
|
||||
return p;
|
||||
}
|
||||
@ -620,7 +637,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 +681,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) );
|
||||
@ -685,7 +702,7 @@ void *sqlite3DbRealloc(sqlite3 *db, void *p, int n){
|
||||
assert( sqlite3MemdebugHasType(p, MEMTYPE_DB) );
|
||||
assert( sqlite3MemdebugHasType(p, MEMTYPE_LOOKASIDE|MEMTYPE_HEAP) );
|
||||
sqlite3MemdebugSetType(p, MEMTYPE_HEAP);
|
||||
pNew = sqlite3_realloc(p, n);
|
||||
pNew = sqlite3_realloc64(p, n);
|
||||
if( !pNew ){
|
||||
sqlite3MemdebugSetType(p, MEMTYPE_DB|MEMTYPE_HEAP);
|
||||
db->mallocFailed = 1;
|
||||
@ -701,7 +718,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 +748,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;
|
||||
@ -739,7 +756,7 @@ char *sqlite3DbStrNDup(sqlite3 *db, const char *z, int n){
|
||||
assert( (n&0x7fffffff)==n );
|
||||
zNew = sqlite3DbMallocRaw(db, n+1);
|
||||
if( zNew ){
|
||||
memcpy(zNew, z, n);
|
||||
memcpy(zNew, z, (size_t)n);
|
||||
zNew[n] = 0;
|
||||
}
|
||||
return zNew;
|
||||
|
@ -4997,7 +4997,7 @@ IOMETHODS(
|
||||
IOMETHODS(
|
||||
nolockIoFinder, /* Finder function name */
|
||||
nolockIoMethods, /* sqlite3_io_methods object name */
|
||||
1, /* shared memory is disabled */
|
||||
3, /* shared memory is disabled */
|
||||
nolockClose, /* xClose method */
|
||||
nolockLock, /* xLock method */
|
||||
nolockUnlock, /* xUnlock method */
|
||||
|
@ -2428,7 +2428,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;
|
||||
@ -7230,7 +7230,7 @@ int sqlite3PagerCloseWal(Pager *pPager){
|
||||
** is empty, return 0.
|
||||
*/
|
||||
int sqlite3PagerWalFramesize(Pager *pPager){
|
||||
assert( pPager->eState==PAGER_READER );
|
||||
assert( pPager->eState>=PAGER_READER );
|
||||
return sqlite3WalFramesize(pPager->pWal);
|
||||
}
|
||||
#endif
|
||||
|
26
src/parse.y
26
src/parse.y
@ -459,9 +459,33 @@ multiselect_op(A) ::= UNION(OP). {A = @OP;}
|
||||
multiselect_op(A) ::= UNION ALL. {A = TK_ALL;}
|
||||
multiselect_op(A) ::= EXCEPT|INTERSECT(OP). {A = @OP;}
|
||||
%endif SQLITE_OMIT_COMPOUND_SELECT
|
||||
oneselect(A) ::= SELECT distinct(D) selcollist(W) from(X) where_opt(Y)
|
||||
oneselect(A) ::= SELECT(S) distinct(D) selcollist(W) from(X) where_opt(Y)
|
||||
groupby_opt(P) having_opt(Q) orderby_opt(Z) limit_opt(L). {
|
||||
A = sqlite3SelectNew(pParse,W,X,Y,P,Q,Z,D,L.pLimit,L.pOffset);
|
||||
#if SELECTTRACE_ENABLED
|
||||
/* Populate the Select.zSelName[] string that is used to help with
|
||||
** query planner debugging, to differentiate between multiple Select
|
||||
** objects in a complex query.
|
||||
**
|
||||
** If the SELECT keyword is immediately followed by a C-style comment
|
||||
** then extract the first few alphanumeric characters from within that
|
||||
** comment to be the zSelName value. Otherwise, the label is #N where
|
||||
** is an integer that is incremented with each SELECT statement seen.
|
||||
*/
|
||||
if( A!=0 ){
|
||||
const char *z = S.z+6;
|
||||
int i;
|
||||
sqlite3_snprintf(sizeof(A->zSelName), A->zSelName, "#%d",
|
||||
++pParse->nSelect);
|
||||
while( z[0]==' ' ) z++;
|
||||
if( z[0]=='/' && z[1]=='*' ){
|
||||
z += 2;
|
||||
while( z[0]==' ' ) z++;
|
||||
for(i=0; sqlite3Isalnum(z[i]); i++){}
|
||||
sqlite3_snprintf(sizeof(A->zSelName), A->zSelName, "%.*s", i, z);
|
||||
}
|
||||
}
|
||||
#endif /* SELECTRACE_ENABLED */
|
||||
}
|
||||
oneselect(A) ::= values(X). {A = X;}
|
||||
|
||||
|
34
src/pcache.c
34
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
|
||||
@ -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);
|
||||
}
|
||||
|
@ -1397,6 +1397,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);
|
||||
|
23
src/printf.c
23
src/printf.c
@ -14,6 +14,21 @@
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
|
||||
/*
|
||||
** If the strchrnul() library function is available, then set
|
||||
** HAVE_STRCHRNUL. If that routine is not available, this module
|
||||
** will supply its own. The built-in version is slower than
|
||||
** the glibc version so the glibc version is definitely preferred.
|
||||
*/
|
||||
#if !defined(HAVE_STRCHRNUL)
|
||||
# if defined(linux)
|
||||
# define HAVE_STRCHRNUL 1
|
||||
# else
|
||||
# define HAVE_STRCHRNUL 0
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
** Conversion types fall into various categories as defined by the
|
||||
** following enumeration.
|
||||
@ -224,9 +239,13 @@ void sqlite3VXPrintf(
|
||||
for(; (c=(*fmt))!=0; ++fmt){
|
||||
if( c!='%' ){
|
||||
bufpt = (char *)fmt;
|
||||
while( (c=(*++fmt))!='%' && c!=0 ){};
|
||||
#if HAVE_STRCHRNUL
|
||||
fmt = strchrnul(fmt, '%');
|
||||
#else
|
||||
do{ fmt++; }while( *fmt && *fmt != '%' );
|
||||
#endif
|
||||
sqlite3StrAccumAppend(pAccum, bufpt, (int)(fmt - bufpt));
|
||||
if( c==0 ) break;
|
||||
if( *fmt==0 ) break;
|
||||
}
|
||||
if( (c=(*++fmt))==0 ){
|
||||
sqlite3StrAccumAppend(pAccum, "%", 1);
|
||||
|
@ -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
|
||||
@ -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);
|
||||
}
|
||||
|
||||
|
87
src/select.c
87
src/select.c
@ -14,6 +14,20 @@
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
|
||||
/*
|
||||
** Trace output macros
|
||||
*/
|
||||
#if SELECTTRACE_ENABLED
|
||||
/***/ int sqlite3SelectTrace = 0;
|
||||
# define SELECTTRACE(K,P,S,X) \
|
||||
if(sqlite3SelectTrace&(K)) \
|
||||
sqlite3DebugPrintf("%*s%s.%p: ",(P)->nSelectIndent*2-2,"",(S)->zSelName,(S)),\
|
||||
sqlite3DebugPrintf X
|
||||
#else
|
||||
# define SELECTTRACE(K,P,S,X)
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
** An instance of the following object is used to record information about
|
||||
** how to process the DISTINCT keyword, to simplify passing that information
|
||||
@ -126,6 +140,18 @@ Select *sqlite3SelectNew(
|
||||
return pNew;
|
||||
}
|
||||
|
||||
#if SELECTTRACE_ENABLED
|
||||
/*
|
||||
** Set the name of a Select object
|
||||
*/
|
||||
void sqlite3SelectSetName(Select *p, const char *zName){
|
||||
if( p && zName ){
|
||||
sqlite3_snprintf(sizeof(p->zSelName), p->zSelName, "%s", zName);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
** Delete the given Select structure and all of its substructures.
|
||||
*/
|
||||
@ -488,7 +514,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 +550,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 ){
|
||||
@ -3131,8 +3157,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 +3223,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
|
||||
@ -3267,8 +3300,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
|
||||
@ -3342,6 +3381,8 @@ static int flattenSubquery(
|
||||
}
|
||||
|
||||
/***** If we reach this point, flattening is permitted. *****/
|
||||
SELECTTRACE(1,pParse,p,("flatten %s.%p from term %d\n",
|
||||
pSub->zSelName, pSub, iFrom));
|
||||
|
||||
/* Authorize the subquery */
|
||||
pParse->zAuthContext = pSubitem->zName;
|
||||
@ -3394,6 +3435,7 @@ static int flattenSubquery(
|
||||
p->pLimit = 0;
|
||||
p->pOffset = 0;
|
||||
pNew = sqlite3SelectDup(db, p, 0);
|
||||
sqlite3SelectSetName(pNew, pSub->zSelName);
|
||||
p->pOffset = pOffset;
|
||||
p->pLimit = pLimit;
|
||||
p->pOrderBy = pOrderBy;
|
||||
@ -3406,6 +3448,9 @@ static int flattenSubquery(
|
||||
if( pPrior ) pPrior->pNext = pNew;
|
||||
pNew->pNext = p;
|
||||
p->pPrior = pNew;
|
||||
SELECTTRACE(2,pParse,p,
|
||||
("compound-subquery flattener creates %s.%p as peer\n",
|
||||
pNew->zSelName, pNew));
|
||||
}
|
||||
if( db->mallocFailed ) return 1;
|
||||
}
|
||||
@ -3535,8 +3580,23 @@ static int flattenSubquery(
|
||||
pParent->pHaving = substExpr(db, pParent->pHaving, iParent, pSub->pEList);
|
||||
}
|
||||
if( pSub->pOrderBy ){
|
||||
/* At this point, any non-zero iOrderByCol values indicate that the
|
||||
** ORDER BY column expression is identical to the iOrderByCol'th
|
||||
** expression returned by SELECT statement pSub. Since these values
|
||||
** do not necessarily correspond to columns in SELECT statement pParent,
|
||||
** zero them before transfering the ORDER BY clause.
|
||||
**
|
||||
** Not doing this may cause an error if a subsequent call to this
|
||||
** function attempts to flatten a compound sub-query into pParent
|
||||
** (the only way this can happen is if the compound sub-query is
|
||||
** currently part of pSub->pSrc). See ticket [d11a6e908f]. */
|
||||
ExprList *pOrderBy = pSub->pOrderBy;
|
||||
for(i=0; i<pOrderBy->nExpr; i++){
|
||||
pOrderBy->a[i].u.x.iOrderByCol = 0;
|
||||
}
|
||||
assert( pParent->pOrderBy==0 );
|
||||
pParent->pOrderBy = pSub->pOrderBy;
|
||||
assert( pSub->pPrior==0 );
|
||||
pParent->pOrderBy = pOrderBy;
|
||||
pSub->pOrderBy = 0;
|
||||
}else if( pParent->pOrderBy ){
|
||||
substExprList(db, pParent->pOrderBy, iParent, pSub->pEList);
|
||||
@ -4052,6 +4112,7 @@ static int selectExpander(Walker *pWalker, Select *p){
|
||||
if( sqlite3ViewGetColumnNames(pParse, pTab) ) return WRC_Abort;
|
||||
assert( pFrom->pSelect==0 );
|
||||
pFrom->pSelect = sqlite3SelectDup(db, pTab->pSelect, 0);
|
||||
sqlite3SelectSetName(pFrom->pSelect, pTab->zName);
|
||||
sqlite3WalkSelect(pWalker, pFrom->pSelect);
|
||||
}
|
||||
#endif
|
||||
@ -4586,6 +4647,10 @@ int sqlite3Select(
|
||||
}
|
||||
if( sqlite3AuthCheck(pParse, SQLITE_SELECT, 0, 0, 0) ) return 1;
|
||||
memset(&sAggInfo, 0, sizeof(sAggInfo));
|
||||
#if SELECTTRACE_ENABLED
|
||||
pParse->nSelectIndent++;
|
||||
SELECTTRACE(1,pParse,p, ("begin processing\n"));
|
||||
#endif
|
||||
|
||||
assert( p->pOrderBy==0 || pDest->eDest!=SRT_DistFifo );
|
||||
assert( p->pOrderBy==0 || pDest->eDest!=SRT_Fifo );
|
||||
@ -4742,6 +4807,10 @@ int sqlite3Select(
|
||||
if( p->pPrior ){
|
||||
rc = multiSelect(pParse, p, pDest);
|
||||
explainSetInteger(pParse->iSelectId, iRestoreSelectId);
|
||||
#if SELECTTRACE_ENABLED
|
||||
SELECTTRACE(1,pParse,p,("end compound-select processing\n"));
|
||||
pParse->nSelectIndent--;
|
||||
#endif
|
||||
return rc;
|
||||
}
|
||||
#endif
|
||||
@ -5341,6 +5410,10 @@ select_end:
|
||||
|
||||
sqlite3DbFree(db, sAggInfo.aCol);
|
||||
sqlite3DbFree(db, sAggInfo.aFunc);
|
||||
#if SELECTTRACE_ENABLED
|
||||
SELECTTRACE(1,pParse,p,("end processing\n"));
|
||||
pParse->nSelectIndent--;
|
||||
#endif
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
75
src/shell.c
75
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>
|
||||
|
||||
@ -3188,6 +3191,13 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
}
|
||||
}else
|
||||
|
||||
#if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_SELECTTRACE)
|
||||
if( c=='s' && n==11 && strncmp(azArg[0], "selecttrace", n)==0 ){
|
||||
extern int sqlite3SelectTrace;
|
||||
sqlite3SelectTrace = nArg>=2 ? booleanValue(azArg[1]) : 0xff;
|
||||
}else
|
||||
#endif
|
||||
|
||||
#if defined(SQLITE_ENABLE_SESSION)
|
||||
if( c=='s' && strncmp(azArg[0],"session",n)==0 && n>=3 ){
|
||||
OpenSession *pSession = &p->aSession[0];
|
||||
@ -3718,6 +3728,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
|
||||
@ -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);
|
||||
|
||||
@ -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*));
|
||||
|
@ -250,6 +250,23 @@ 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*);
|
||||
};
|
||||
|
||||
/*
|
||||
@ -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
|
||||
|
151
src/sqliteInt.h
151
src/sqliteInt.h
@ -47,6 +47,15 @@
|
||||
# define _LARGEFILE_SOURCE 1
|
||||
#endif
|
||||
|
||||
/* Needed for various definitions... */
|
||||
#if defined(__GNUC__) && !defined(_GNU_SOURCE)
|
||||
# define _GNU_SOURCE
|
||||
#endif
|
||||
|
||||
#if defined(__OpenBSD__) && !defined(_BSD_SOURCE)
|
||||
# define _BSD_SOURCE
|
||||
#endif
|
||||
|
||||
/*
|
||||
** For MinGW, check to see if we can include the header file containing its
|
||||
** version information, among other things. Normally, this internal MinGW
|
||||
@ -104,15 +113,6 @@
|
||||
#pragma warn -spa /* Suspicious pointer arithmetic */
|
||||
#endif
|
||||
|
||||
/* Needed for various definitions... */
|
||||
#ifndef _GNU_SOURCE
|
||||
# define _GNU_SOURCE
|
||||
#endif
|
||||
|
||||
#if defined(__OpenBSD__) && !defined(_BSD_SOURCE)
|
||||
# define _BSD_SOURCE
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Include standard header files as necessary
|
||||
*/
|
||||
@ -706,6 +706,16 @@ extern const int sqlite3one;
|
||||
# undef SQLITE_ENABLE_STAT3_OR_STAT4
|
||||
#endif
|
||||
|
||||
/*
|
||||
** SELECTTRACE_ENABLED will be either 1 or 0 depending on whether or not
|
||||
** the Select query generator tracing logic is turned on.
|
||||
*/
|
||||
#if defined(SQLITE_DEBUG) || defined(SQLITE_ENABLE_SELECTTRACE)
|
||||
# define SELECTTRACE_ENABLED 1
|
||||
#else
|
||||
# define SELECTTRACE_ENABLED 0
|
||||
#endif
|
||||
|
||||
/*
|
||||
** An instance of the following structure is used to store the busy-handler
|
||||
** callback for a given sqlite handle.
|
||||
@ -989,6 +999,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.
|
||||
*/
|
||||
@ -1063,8 +1112,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
|
||||
@ -1090,7 +1138,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.
|
||||
@ -1108,6 +1155,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
|
||||
};
|
||||
|
||||
/*
|
||||
@ -1253,6 +1303,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
|
||||
@ -1300,6 +1351,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
|
||||
@ -1386,18 +1440,18 @@ struct CollSeq {
|
||||
** 't' for SQLITE_AFF_TEXT. But we can save a little space and improve
|
||||
** the speed a little by numbering the values consecutively.
|
||||
**
|
||||
** But rather than start with 0 or 1, we begin with 'a'. That way,
|
||||
** But rather than start with 0 or 1, we begin with 'A'. That way,
|
||||
** when multiple affinity types are concatenated into a string and
|
||||
** used as the P4 operand, they will be more readable.
|
||||
**
|
||||
** Note also that the numeric types are grouped together so that testing
|
||||
** for a numeric type is a single comparison.
|
||||
** for a numeric type is a single comparison. And the NONE type is first.
|
||||
*/
|
||||
#define SQLITE_AFF_TEXT 'a'
|
||||
#define SQLITE_AFF_NONE 'b'
|
||||
#define SQLITE_AFF_NUMERIC 'c'
|
||||
#define SQLITE_AFF_INTEGER 'd'
|
||||
#define SQLITE_AFF_REAL 'e'
|
||||
#define SQLITE_AFF_NONE 'A'
|
||||
#define SQLITE_AFF_TEXT 'B'
|
||||
#define SQLITE_AFF_NUMERIC 'C'
|
||||
#define SQLITE_AFF_INTEGER 'D'
|
||||
#define SQLITE_AFF_REAL 'E'
|
||||
|
||||
#define sqlite3IsNumericAffinity(X) ((X)>=SQLITE_AFF_NUMERIC)
|
||||
|
||||
@ -1405,7 +1459,7 @@ struct CollSeq {
|
||||
** The SQLITE_AFF_MASK values masks off the significant bits of an
|
||||
** affinity value.
|
||||
*/
|
||||
#define SQLITE_AFF_MASK 0x67
|
||||
#define SQLITE_AFF_MASK 0x47
|
||||
|
||||
/*
|
||||
** Additional bit values that can be ORed with an affinity without
|
||||
@ -1416,10 +1470,10 @@ struct CollSeq {
|
||||
** operator is NULL. It is added to certain comparison operators to
|
||||
** prove that the operands are always NOT NULL.
|
||||
*/
|
||||
#define SQLITE_JUMPIFNULL 0x08 /* jumps if either operand is NULL */
|
||||
#define SQLITE_STOREP2 0x10 /* Store result in reg[P2] rather than jump */
|
||||
#define SQLITE_JUMPIFNULL 0x10 /* jumps if either operand is NULL */
|
||||
#define SQLITE_STOREP2 0x20 /* Store result in reg[P2] rather than jump */
|
||||
#define SQLITE_NULLEQ 0x80 /* NULL=NULL */
|
||||
#define SQLITE_NOTNULL 0x88 /* Assert that operands are never NULL */
|
||||
#define SQLITE_NOTNULL 0x90 /* Assert that operands are never NULL */
|
||||
|
||||
/*
|
||||
** An object of this type is created for each virtual table present in
|
||||
@ -2222,17 +2276,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
|
||||
@ -2259,6 +2318,9 @@ struct Select {
|
||||
u8 op; /* One of: TK_UNION TK_ALL TK_INTERSECT TK_EXCEPT */
|
||||
u16 selFlags; /* Various SF_* values */
|
||||
int iLimit, iOffset; /* Memory registers holding LIMIT & OFFSET counters */
|
||||
#if SELECTTRACE_ENABLED
|
||||
char zSelName[12]; /* Symbolic name of this SELECT use for debugging */
|
||||
#endif
|
||||
int addrOpenEphm[2]; /* OP_OpenEphem opcodes related to this select */
|
||||
u64 nSelectRow; /* Estimated number of result rows */
|
||||
SrcList *pSrc; /* The FROM clause */
|
||||
@ -2283,13 +2345,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() */
|
||||
|
||||
|
||||
/*
|
||||
@ -2517,6 +2579,10 @@ struct Parse {
|
||||
int regRowid; /* Register holding rowid of CREATE TABLE entry */
|
||||
int regRoot; /* Register holding root page number for new objects */
|
||||
int nMaxArg; /* Max args passed to user function by sub-program */
|
||||
#if SELECTTRACE_ENABLED
|
||||
int nSelect; /* Number of SELECT statements seen */
|
||||
int nSelectIndent; /* How far to indent SELECTTRACE() output */
|
||||
#endif
|
||||
#ifndef SQLITE_OMIT_SHARED_CACHE
|
||||
int nTableLock; /* Number of locks in aTableLock */
|
||||
TableLock *aTableLock; /* Required table locks for shared-cache mode */
|
||||
@ -2943,15 +3009,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*);
|
||||
@ -3255,6 +3321,11 @@ ExprList *sqlite3ExprListDup(sqlite3*,ExprList*,int);
|
||||
SrcList *sqlite3SrcListDup(sqlite3*,SrcList*,int);
|
||||
IdList *sqlite3IdListDup(sqlite3*,IdList*);
|
||||
Select *sqlite3SelectDup(sqlite3*,Select*,int);
|
||||
#if SELECTTRACE_ENABLED
|
||||
void sqlite3SelectSetName(Select*,const char*);
|
||||
#else
|
||||
# define sqlite3SelectSetName(A,B)
|
||||
#endif
|
||||
void sqlite3FuncDefInsert(FuncDefHash*, FuncDef*);
|
||||
FuncDef *sqlite3FindFunction(sqlite3*,const char*,int,int,u8,u8);
|
||||
void sqlite3RegisterBuiltinFunctions(sqlite3*);
|
||||
@ -3492,7 +3563,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;
|
||||
}
|
||||
@ -73,7 +73,7 @@ static int sqlite3_get_table_cb(void *pArg, int nCol, char **argv, char **colv){
|
||||
if( z==0 ) goto malloc_failed;
|
||||
p->azResult[p->nData++] = z;
|
||||
}
|
||||
}else if( p->nColumn!=nCol ){
|
||||
}else if( (int)p->nColumn!=nCol ){
|
||||
sqlite3_free(p->zErrMsg);
|
||||
p->zErrMsg = sqlite3_mprintf(
|
||||
"sqlite3_get_table() called with two or more incompatible queries"
|
||||
|
@ -916,6 +916,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;
|
||||
@ -968,6 +971,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";
|
||||
@ -1785,8 +1791,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);
|
||||
}
|
||||
|
133
src/test1.c
133
src/test1.c
@ -6497,6 +6497,132 @@ static int sorter_test_sort4_helper(
|
||||
}
|
||||
|
||||
|
||||
#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.
|
||||
*/
|
||||
@ -6734,6 +6860,13 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
|
||||
{ "load_static_extension", tclLoadStaticExtensionCmd },
|
||||
{ "sorter_test_fakeheap", sorter_test_fakeheap },
|
||||
{ "sorter_test_sort4_helper", sorter_test_sort4_helper },
|
||||
#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;
|
||||
|
@ -615,6 +615,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
|
||||
|
@ -504,7 +504,7 @@ static void test_extract(
|
||||
sqlite3_result_value(context, &mem);
|
||||
}
|
||||
|
||||
sqlite3DbFree(db, mem.zMalloc);
|
||||
if( mem.szMalloc ) sqlite3DbFree(db, mem.zMalloc);
|
||||
}
|
||||
}
|
||||
|
||||
@ -591,7 +591,7 @@ static void test_decode(
|
||||
|
||||
Tcl_ListObjAppendElement(0, pRet, pVal);
|
||||
|
||||
if( mem.zMalloc ){
|
||||
if( mem.szMalloc ){
|
||||
sqlite3DbFree(db, mem.zMalloc);
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -314,12 +314,13 @@ SQLITE_NOINLINE int sqlite3VdbeMemTranslate(Mem *pMem, u8 desiredEnc){
|
||||
*z = 0;
|
||||
assert( (pMem->n+(desiredEnc==SQLITE_UTF8?1:2))<=len );
|
||||
|
||||
c = pMem->flags;
|
||||
sqlite3VdbeMemRelease(pMem);
|
||||
pMem->flags &= ~(MEM_Static|MEM_Dyn|MEM_Ephem);
|
||||
pMem->flags = MEM_Str|MEM_Term|(c&MEM_AffMask);
|
||||
pMem->enc = desiredEnc;
|
||||
pMem->flags |= (MEM_Term);
|
||||
pMem->z = (char*)zOut;
|
||||
pMem->zMalloc = pMem->z;
|
||||
pMem->szMalloc = sqlite3DbMallocSize(pMem->db, pMem->z);
|
||||
|
||||
translate_out:
|
||||
#if defined(TRANSLATE_TRACE) && defined(SQLITE_DEBUG)
|
||||
|
206
src/vdbe.c
206
src/vdbe.c
@ -219,7 +219,7 @@ static VdbeCursor *allocateCursor(
|
||||
sqlite3VdbeFreeCursor(p, p->apCsr[iCur]);
|
||||
p->apCsr[iCur] = 0;
|
||||
}
|
||||
if( SQLITE_OK==sqlite3VdbeMemGrow(pMem, nByte, 0) ){
|
||||
if( SQLITE_OK==sqlite3VdbeMemClearAndResize(pMem, nByte) ){
|
||||
p->apCsr[iCur] = pCx = (VdbeCursor*)pMem->z;
|
||||
memset(pCx, 0, sizeof(VdbeCursor));
|
||||
pCx->iDb = iDb;
|
||||
@ -252,13 +252,13 @@ static void applyNumericAffinity(Mem *pRec, int bTryForInt){
|
||||
double rValue;
|
||||
i64 iValue;
|
||||
u8 enc = pRec->enc;
|
||||
if( (pRec->flags&MEM_Str)==0 ) return;
|
||||
assert( (pRec->flags & (MEM_Str|MEM_Int|MEM_Real))==MEM_Str );
|
||||
if( sqlite3AtoF(pRec->z, &rValue, pRec->n, enc)==0 ) return;
|
||||
if( 0==sqlite3Atoi64(pRec->z, &iValue, pRec->n, enc) ){
|
||||
pRec->u.i = iValue;
|
||||
pRec->flags |= MEM_Int;
|
||||
}else{
|
||||
pRec->r = rValue;
|
||||
pRec->u.r = rValue;
|
||||
pRec->flags |= MEM_Real;
|
||||
if( bTryForInt ) sqlite3VdbeIntegerAffinity(pRec);
|
||||
}
|
||||
@ -287,7 +287,17 @@ static void applyAffinity(
|
||||
char affinity, /* The affinity to be applied */
|
||||
u8 enc /* Use this text encoding */
|
||||
){
|
||||
if( affinity==SQLITE_AFF_TEXT ){
|
||||
if( affinity>=SQLITE_AFF_NUMERIC ){
|
||||
assert( affinity==SQLITE_AFF_INTEGER || affinity==SQLITE_AFF_REAL
|
||||
|| affinity==SQLITE_AFF_NUMERIC );
|
||||
if( (pRec->flags & MEM_Int)==0 ){
|
||||
if( (pRec->flags & MEM_Real)==0 ){
|
||||
if( pRec->flags & MEM_Str ) applyNumericAffinity(pRec,1);
|
||||
}else{
|
||||
sqlite3VdbeIntegerAffinity(pRec);
|
||||
}
|
||||
}
|
||||
}else if( affinity==SQLITE_AFF_TEXT ){
|
||||
/* Only attempt the conversion to TEXT if there is an integer or real
|
||||
** representation (blob and NULL do not get converted) but no string
|
||||
** representation.
|
||||
@ -295,16 +305,6 @@ static void applyAffinity(
|
||||
if( 0==(pRec->flags&MEM_Str) && (pRec->flags&(MEM_Real|MEM_Int)) ){
|
||||
sqlite3VdbeMemStringify(pRec, enc, 1);
|
||||
}
|
||||
}else if( affinity!=SQLITE_AFF_NONE ){
|
||||
assert( affinity==SQLITE_AFF_INTEGER || affinity==SQLITE_AFF_REAL
|
||||
|| affinity==SQLITE_AFF_NUMERIC );
|
||||
if( (pRec->flags & MEM_Int)==0 ){
|
||||
if( (pRec->flags & MEM_Real)==0 ){
|
||||
applyNumericAffinity(pRec,1);
|
||||
}else{
|
||||
sqlite3VdbeIntegerAffinity(pRec);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -339,13 +339,13 @@ void sqlite3ValueApplyAffinity(
|
||||
/*
|
||||
** pMem currently only holds a string type (or maybe a BLOB that we can
|
||||
** interpret as a string if we want to). Compute its corresponding
|
||||
** numeric type, if has one. Set the pMem->r and pMem->u.i fields
|
||||
** numeric type, if has one. Set the pMem->u.r and pMem->u.i fields
|
||||
** accordingly.
|
||||
*/
|
||||
static u16 SQLITE_NOINLINE computeNumericType(Mem *pMem){
|
||||
assert( (pMem->flags & (MEM_Int|MEM_Real))==0 );
|
||||
assert( (pMem->flags & (MEM_Str|MEM_Blob))!=0 );
|
||||
if( sqlite3AtoF(pMem->z, &pMem->r, pMem->n, pMem->enc)==0 ){
|
||||
if( sqlite3AtoF(pMem->z, &pMem->u.r, pMem->n, pMem->enc)==0 ){
|
||||
return 0;
|
||||
}
|
||||
if( sqlite3Atoi64(pMem->z, &pMem->u.i, pMem->n, pMem->enc)==SQLITE_OK ){
|
||||
@ -359,7 +359,7 @@ static u16 SQLITE_NOINLINE computeNumericType(Mem *pMem){
|
||||
** none.
|
||||
**
|
||||
** Unlike applyNumericAffinity(), this routine does not modify pMem->flags.
|
||||
** But it does set pMem->r and pMem->u.i appropriately.
|
||||
** But it does set pMem->u.r and pMem->u.i appropriately.
|
||||
*/
|
||||
static u16 numericType(Mem *pMem){
|
||||
if( pMem->flags & (MEM_Int|MEM_Real) ){
|
||||
@ -469,7 +469,7 @@ static void memTracePrint(Mem *p){
|
||||
printf(" i:%lld", p->u.i);
|
||||
#ifndef SQLITE_OMIT_FLOATING_POINT
|
||||
}else if( p->flags & MEM_Real ){
|
||||
printf(" r:%g", p->r);
|
||||
printf(" r:%g", p->u.r);
|
||||
#endif
|
||||
}else if( p->flags & MEM_RowSet ){
|
||||
printf(" (rowset)");
|
||||
@ -650,7 +650,7 @@ int sqlite3VdbeExec(
|
||||
assert( pOp->p2<=(p->nMem-p->nCursor) );
|
||||
pOut = &aMem[pOp->p2];
|
||||
memAboutToChange(p, pOut);
|
||||
VdbeMemReleaseExtern(pOut);
|
||||
if( VdbeMemDynamic(pOut) ) sqlite3VdbeMemSetNull(pOut);
|
||||
pOut->flags = MEM_Int;
|
||||
}
|
||||
|
||||
@ -1012,7 +1012,7 @@ case OP_Int64: { /* out2-prerelease */
|
||||
case OP_Real: { /* same as TK_FLOAT, out2-prerelease */
|
||||
pOut->flags = MEM_Real;
|
||||
assert( !sqlite3IsNaN(*pOp->p4.pReal) );
|
||||
pOut->r = *pOp->p4.pReal;
|
||||
pOut->u.r = *pOp->p4.pReal;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
@ -1035,9 +1035,9 @@ case OP_String8: { /* same as TK_STRING, out2-prerelease */
|
||||
rc = sqlite3VdbeMemSetStr(pOut, pOp->p4.z, -1, SQLITE_UTF8, SQLITE_STATIC);
|
||||
if( rc==SQLITE_TOOBIG ) goto too_big;
|
||||
if( SQLITE_OK!=sqlite3VdbeChangeEncoding(pOut, encoding) ) goto no_mem;
|
||||
assert( pOut->zMalloc==pOut->z );
|
||||
assert( pOut->szMalloc>0 && pOut->zMalloc==pOut->z );
|
||||
assert( VdbeMemDynamic(pOut)==0 );
|
||||
pOut->zMalloc = 0;
|
||||
pOut->szMalloc = 0;
|
||||
pOut->flags |= MEM_Static;
|
||||
if( pOp->p4type==P4_DYNAMIC ){
|
||||
sqlite3DbFree(db, pOp->p4.z);
|
||||
@ -1089,7 +1089,7 @@ case OP_Null: { /* out2-prerelease */
|
||||
while( cnt>0 ){
|
||||
pOut++;
|
||||
memAboutToChange(p, pOut);
|
||||
VdbeMemReleaseExtern(pOut);
|
||||
sqlite3VdbeMemSetNull(pOut);
|
||||
pOut->flags = nullFlag;
|
||||
cnt--;
|
||||
}
|
||||
@ -1157,7 +1157,6 @@ case OP_Variable: { /* out2-prerelease */
|
||||
** for P3 to be less than 1.
|
||||
*/
|
||||
case OP_Move: {
|
||||
char *zMalloc; /* Holding variable for allocated memory */
|
||||
int n; /* Number of registers left to copy */
|
||||
int p1; /* Register to copy from */
|
||||
int p2; /* Register to copy to */
|
||||
@ -1175,17 +1174,12 @@ case OP_Move: {
|
||||
assert( pIn1<=&aMem[(p->nMem-p->nCursor)] );
|
||||
assert( memIsValid(pIn1) );
|
||||
memAboutToChange(p, pOut);
|
||||
sqlite3VdbeMemRelease(pOut);
|
||||
zMalloc = pOut->zMalloc;
|
||||
memcpy(pOut, pIn1, sizeof(Mem));
|
||||
sqlite3VdbeMemMove(pOut, pIn1);
|
||||
#ifdef SQLITE_DEBUG
|
||||
if( pOut->pScopyFrom>=&aMem[p1] && pOut->pScopyFrom<&aMem[p1+pOp->p3] ){
|
||||
pOut->pScopyFrom += p1 - pOp->p2;
|
||||
}
|
||||
#endif
|
||||
pIn1->flags = MEM_Undefined;
|
||||
pIn1->xDel = 0;
|
||||
pIn1->zMalloc = zMalloc;
|
||||
REGISTER_TRACE(p2++, pOut);
|
||||
pIn1++;
|
||||
pOut++;
|
||||
@ -1490,7 +1484,7 @@ fp_math:
|
||||
if( sqlite3IsNaN(rB) ){
|
||||
goto arithmetic_result_is_null;
|
||||
}
|
||||
pOut->r = rB;
|
||||
pOut->u.r = rB;
|
||||
MemSetTypeFlag(pOut, MEM_Real);
|
||||
if( ((type1|type2)&MEM_Real)==0 && !bIntint ){
|
||||
sqlite3VdbeIntegerAffinity(pOut);
|
||||
@ -1765,7 +1759,7 @@ case OP_RealAffinity: { /* in1 */
|
||||
** A NULL value is not changed by this routine. It remains NULL.
|
||||
*/
|
||||
case OP_Cast: { /* in1 */
|
||||
assert( pOp->p2>=SQLITE_AFF_TEXT && pOp->p2<=SQLITE_AFF_REAL );
|
||||
assert( pOp->p2>=SQLITE_AFF_NONE && pOp->p2<=SQLITE_AFF_REAL );
|
||||
testcase( pOp->p2==SQLITE_AFF_TEXT );
|
||||
testcase( pOp->p2==SQLITE_AFF_NONE );
|
||||
testcase( pOp->p2==SQLITE_AFF_NUMERIC );
|
||||
@ -1915,15 +1909,35 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */
|
||||
}else{
|
||||
/* Neither operand is NULL. Do a comparison. */
|
||||
affinity = pOp->p5 & SQLITE_AFF_MASK;
|
||||
if( affinity ){
|
||||
applyAffinity(pIn1, affinity, encoding);
|
||||
applyAffinity(pIn3, affinity, encoding);
|
||||
if( db->mallocFailed ) goto no_mem;
|
||||
if( affinity>=SQLITE_AFF_NUMERIC ){
|
||||
if( (pIn1->flags & (MEM_Int|MEM_Real|MEM_Str))==MEM_Str ){
|
||||
applyNumericAffinity(pIn1,0);
|
||||
}
|
||||
if( (pIn3->flags & (MEM_Int|MEM_Real|MEM_Str))==MEM_Str ){
|
||||
applyNumericAffinity(pIn3,0);
|
||||
}
|
||||
}else if( affinity==SQLITE_AFF_TEXT ){
|
||||
if( (pIn1->flags & MEM_Str)==0 && (pIn1->flags & (MEM_Int|MEM_Real))!=0 ){
|
||||
testcase( pIn1->flags & MEM_Int );
|
||||
testcase( pIn1->flags & MEM_Real );
|
||||
sqlite3VdbeMemStringify(pIn1, encoding, 1);
|
||||
}
|
||||
if( (pIn3->flags & MEM_Str)==0 && (pIn3->flags & (MEM_Int|MEM_Real))!=0 ){
|
||||
testcase( pIn3->flags & MEM_Int );
|
||||
testcase( pIn3->flags & MEM_Real );
|
||||
sqlite3VdbeMemStringify(pIn3, encoding, 1);
|
||||
}
|
||||
}
|
||||
|
||||
assert( pOp->p4type==P4_COLLSEQ || pOp->p4.pColl==0 );
|
||||
ExpandBlob(pIn1);
|
||||
ExpandBlob(pIn3);
|
||||
if( pIn1->flags & MEM_Zero ){
|
||||
sqlite3VdbeMemExpandBlob(pIn1);
|
||||
flags1 &= ~MEM_Zero;
|
||||
}
|
||||
if( pIn3->flags & MEM_Zero ){
|
||||
sqlite3VdbeMemExpandBlob(pIn3);
|
||||
flags3 &= ~MEM_Zero;
|
||||
}
|
||||
if( db->mallocFailed ) goto no_mem;
|
||||
res = sqlite3MemCompare(pIn3, pIn1, pOp->p4.pColl);
|
||||
}
|
||||
switch( pOp->opcode ){
|
||||
@ -1948,8 +1962,8 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */
|
||||
}
|
||||
}
|
||||
/* Undo any changes made by applyAffinity() to the input registers. */
|
||||
pIn1->flags = (pIn1->flags&~MEM_TypeMask) | (flags1&MEM_TypeMask);
|
||||
pIn3->flags = (pIn3->flags&~MEM_TypeMask) | (flags3&MEM_TypeMask);
|
||||
pIn1->flags = flags1;
|
||||
pIn3->flags = flags3;
|
||||
break;
|
||||
}
|
||||
|
||||
@ -2117,10 +2131,10 @@ case OP_Or: { /* same as TK_OR, in1, in2, out3 */
|
||||
case OP_Not: { /* same as TK_NOT, in1, out2 */
|
||||
pIn1 = &aMem[pOp->p1];
|
||||
pOut = &aMem[pOp->p2];
|
||||
if( pIn1->flags & MEM_Null ){
|
||||
sqlite3VdbeMemSetNull(pOut);
|
||||
}else{
|
||||
sqlite3VdbeMemSetInt64(pOut, !sqlite3VdbeIntValue(pIn1));
|
||||
sqlite3VdbeMemSetNull(pOut);
|
||||
if( (pIn1->flags & MEM_Null)==0 ){
|
||||
pOut->flags = MEM_Int;
|
||||
pOut->u.i = !sqlite3VdbeIntValue(pIn1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -2135,10 +2149,10 @@ case OP_Not: { /* same as TK_NOT, in1, out2 */
|
||||
case OP_BitNot: { /* same as TK_BITNOT, in1, out2 */
|
||||
pIn1 = &aMem[pOp->p1];
|
||||
pOut = &aMem[pOp->p2];
|
||||
if( pIn1->flags & MEM_Null ){
|
||||
sqlite3VdbeMemSetNull(pOut);
|
||||
}else{
|
||||
sqlite3VdbeMemSetInt64(pOut, ~sqlite3VdbeIntValue(pIn1));
|
||||
sqlite3VdbeMemSetNull(pOut);
|
||||
if( (pIn1->flags & MEM_Null)==0 ){
|
||||
pOut->flags = MEM_Int;
|
||||
pOut->u.i = ~sqlite3VdbeIntValue(pIn1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -2256,7 +2270,6 @@ case OP_Column: {
|
||||
int p2; /* column number to retrieve */
|
||||
VdbeCursor *pC; /* The VDBE cursor */
|
||||
BtCursor *pCrsr; /* The BTree cursor */
|
||||
u32 *aType; /* aType[i] holds the numeric type of the i-th column */
|
||||
u32 *aOffset; /* aOffset[i] is offset to start of data for i-th column */
|
||||
int len; /* The length of the serialized data for the column */
|
||||
int i; /* Loop counter */
|
||||
@ -2269,6 +2282,7 @@ case OP_Column: {
|
||||
u32 szField; /* Number of bytes in the content of a field */
|
||||
u32 avail; /* Number of bytes of available data */
|
||||
u32 t; /* A type code from the record header */
|
||||
u16 fx; /* pDest->flags value */
|
||||
Mem *pReg; /* PseudoTable input register */
|
||||
|
||||
p2 = pOp->p2;
|
||||
@ -2279,8 +2293,7 @@ case OP_Column: {
|
||||
pC = p->apCsr[pOp->p1];
|
||||
assert( pC!=0 );
|
||||
assert( p2<pC->nField );
|
||||
aType = pC->aType;
|
||||
aOffset = aType + pC->nField;
|
||||
aOffset = pC->aType + pC->nField;
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
assert( pC->pVtabCursor==0 ); /* OP_Column never called on virtual table */
|
||||
#endif
|
||||
@ -2361,7 +2374,7 @@ case OP_Column: {
|
||||
}
|
||||
|
||||
/* Make sure at least the first p2+1 entries of the header have been
|
||||
** parsed and valid information is in aOffset[] and aType[].
|
||||
** parsed and valid information is in aOffset[] and pC->aType[].
|
||||
*/
|
||||
if( pC->nHdrParsed<=p2 ){
|
||||
/* If there is more header available for parsing in the record, try
|
||||
@ -2381,7 +2394,7 @@ case OP_Column: {
|
||||
zData = pC->aRow;
|
||||
}
|
||||
|
||||
/* Fill in aType[i] and aOffset[i] values through the p2-th field. */
|
||||
/* Fill in pC->aType[i] and aOffset[i] values through the p2-th field. */
|
||||
i = pC->nHdrParsed;
|
||||
offset = aOffset[i];
|
||||
zHdr = zData + pC->iHdrOffset;
|
||||
@ -2394,7 +2407,7 @@ case OP_Column: {
|
||||
}else{
|
||||
zHdr += sqlite3GetVarint32(zHdr, &t);
|
||||
}
|
||||
aType[i] = t;
|
||||
pC->aType[i] = t;
|
||||
szField = sqlite3VdbeSerialTypeLen(t);
|
||||
offset += szField;
|
||||
if( offset<szField ){ /* True if offset overflows */
|
||||
@ -2441,61 +2454,61 @@ case OP_Column: {
|
||||
}
|
||||
|
||||
/* Extract the content for the p2+1-th column. Control can only
|
||||
** reach this point if aOffset[p2], aOffset[p2+1], and aType[p2] are
|
||||
** reach this point if aOffset[p2], aOffset[p2+1], and pC->aType[p2] are
|
||||
** all valid.
|
||||
*/
|
||||
assert( p2<pC->nHdrParsed );
|
||||
assert( rc==SQLITE_OK );
|
||||
assert( sqlite3VdbeCheckMemInvariants(pDest) );
|
||||
if( VdbeMemDynamic(pDest) ) sqlite3VdbeMemSetNull(pDest);
|
||||
t = pC->aType[p2];
|
||||
if( pC->szRow>=aOffset[p2+1] ){
|
||||
/* This is the common case where the desired content fits on the original
|
||||
** page - where the content is not on an overflow page */
|
||||
VdbeMemReleaseExtern(pDest);
|
||||
sqlite3VdbeSerialGet(pC->aRow+aOffset[p2], aType[p2], pDest);
|
||||
sqlite3VdbeSerialGet(pC->aRow+aOffset[p2], t, pDest);
|
||||
}else{
|
||||
/* This branch happens only when content is on overflow pages */
|
||||
t = aType[p2];
|
||||
if( ((pOp->p5 & (OPFLAG_LENGTHARG|OPFLAG_TYPEOFARG))!=0
|
||||
&& ((t>=12 && (t&1)==0) || (pOp->p5 & OPFLAG_TYPEOFARG)!=0))
|
||||
|| (len = sqlite3VdbeSerialTypeLen(t))==0
|
||||
){
|
||||
/* Content is irrelevant for the typeof() function and for
|
||||
** the length(X) function if X is a blob. So we might as well use
|
||||
** bogus content rather than reading content from disk. NULL works
|
||||
** for text and blob and whatever is in the payloadSize64 variable
|
||||
** will work for everything else. Content is also irrelevant if
|
||||
** the content length is 0. */
|
||||
zData = t<=13 ? (u8*)&payloadSize64 : 0;
|
||||
sMem.zMalloc = 0;
|
||||
/* Content is irrelevant for
|
||||
** 1. the typeof() function,
|
||||
** 2. the length(X) function if X is a blob, and
|
||||
** 3. if the content length is zero.
|
||||
** So we might as well use bogus content rather than reading
|
||||
** content from disk. NULL will work for the value for strings
|
||||
** and blobs and whatever is in the payloadSize64 variable
|
||||
** will work for everything else. */
|
||||
sqlite3VdbeSerialGet(t<=13 ? (u8*)&payloadSize64 : 0, t, pDest);
|
||||
}else{
|
||||
memset(&sMem, 0, sizeof(sMem));
|
||||
sqlite3VdbeMemMove(&sMem, pDest);
|
||||
rc = sqlite3VdbeMemFromBtree(pCrsr, aOffset[p2], len, !pC->isTable,
|
||||
&sMem);
|
||||
pDest);
|
||||
if( rc!=SQLITE_OK ){
|
||||
goto op_column_error;
|
||||
}
|
||||
zData = (u8*)sMem.z;
|
||||
}
|
||||
sqlite3VdbeSerialGet(zData, t, pDest);
|
||||
/* If we dynamically allocated space to hold the data (in the
|
||||
** sqlite3VdbeMemFromBtree() call above) then transfer control of that
|
||||
** dynamically allocated space over to the pDest structure.
|
||||
** This prevents a memory copy. */
|
||||
if( sMem.zMalloc ){
|
||||
assert( sMem.z==sMem.zMalloc );
|
||||
assert( VdbeMemDynamic(pDest)==0 );
|
||||
assert( (pDest->flags & (MEM_Blob|MEM_Str))==0 || pDest->z==sMem.z );
|
||||
pDest->flags &= ~(MEM_Ephem|MEM_Static);
|
||||
pDest->flags |= MEM_Term;
|
||||
pDest->z = sMem.z;
|
||||
pDest->zMalloc = sMem.zMalloc;
|
||||
sqlite3VdbeSerialGet((const u8*)pDest->z, t, pDest);
|
||||
pDest->flags &= ~MEM_Ephem;
|
||||
}
|
||||
}
|
||||
pDest->enc = encoding;
|
||||
|
||||
op_column_out:
|
||||
Deephemeralize(pDest);
|
||||
/* If the column value is an ephemeral string, go ahead and persist
|
||||
** that string in case the cursor moves before the column value is
|
||||
** used. The following code does the equivalent of Deephemeralize()
|
||||
** but does it faster. */
|
||||
if( (pDest->flags & MEM_Ephem)!=0 && pDest->z ){
|
||||
fx = pDest->flags & (MEM_Str|MEM_Blob);
|
||||
assert( fx!=0 );
|
||||
zData = (const u8*)pDest->z;
|
||||
len = pDest->n;
|
||||
if( sqlite3VdbeMemClearAndResize(pDest, len+2) ) goto no_mem;
|
||||
memcpy(pDest->z, zData, len);
|
||||
pDest->z[len] = 0;
|
||||
pDest->z[len+1] = 0;
|
||||
pDest->flags = fx|MEM_Term;
|
||||
}
|
||||
op_column_error:
|
||||
UPDATE_MAX_BLOBSIZE(pDest);
|
||||
REGISTER_TRACE(pOp->p3, pDest);
|
||||
@ -2646,9 +2659,9 @@ case OP_MakeRecord: {
|
||||
/* Make sure the output register has a buffer large enough to store
|
||||
** the new record. The output register (pOp->p3) is not allowed to
|
||||
** be one of the input registers (because the following call to
|
||||
** sqlite3VdbeMemGrow() could clobber the value before it is used).
|
||||
** sqlite3VdbeMemClearAndResize() could clobber the value before it is used).
|
||||
*/
|
||||
if( sqlite3VdbeMemGrow(pOut, (int)nByte, 0) ){
|
||||
if( sqlite3VdbeMemClearAndResize(pOut, (int)nByte) ){
|
||||
goto no_mem;
|
||||
}
|
||||
zNewRecord = (u8 *)pOut->z;
|
||||
@ -2669,7 +2682,6 @@ case OP_MakeRecord: {
|
||||
assert( pOp->p3>0 && pOp->p3<=(p->nMem-p->nCursor) );
|
||||
pOut->n = (int)nByte;
|
||||
pOut->flags = MEM_Blob;
|
||||
pOut->xDel = 0;
|
||||
if( nZero ){
|
||||
pOut->u.nZero = nZero;
|
||||
pOut->flags |= MEM_Zero;
|
||||
@ -3559,7 +3571,7 @@ case OP_SeekGT: { /* jump, in3 */
|
||||
** blob, or NULL. But it needs to be an integer before we can do
|
||||
** the seek, so convert it. */
|
||||
pIn3 = &aMem[pOp->p3];
|
||||
if( (pIn3->flags & (MEM_Int|MEM_Real))==0 ){
|
||||
if( (pIn3->flags & (MEM_Int|MEM_Real|MEM_Str))==MEM_Str ){
|
||||
applyNumericAffinity(pIn3, 0);
|
||||
}
|
||||
iKey = sqlite3VdbeIntValue(pIn3);
|
||||
@ -3582,7 +3594,7 @@ case OP_SeekGT: { /* jump, in3 */
|
||||
** (x > 4.9) -> (x >= 5)
|
||||
** (x <= 4.9) -> (x < 5)
|
||||
*/
|
||||
if( pIn3->r<(double)iKey ){
|
||||
if( pIn3->u.r<(double)iKey ){
|
||||
assert( OP_SeekGE==(OP_SeekGT-1) );
|
||||
assert( OP_SeekLT==(OP_SeekLE-1) );
|
||||
assert( (OP_SeekLE & 0x0001)==(OP_SeekGT & 0x0001) );
|
||||
@ -3591,7 +3603,7 @@ case OP_SeekGT: { /* jump, in3 */
|
||||
|
||||
/* If the approximation iKey is smaller than the actual real search
|
||||
** term, substitute <= for < and > for >=. */
|
||||
else if( pIn3->r>(double)iKey ){
|
||||
else if( pIn3->u.r>(double)iKey ){
|
||||
assert( OP_SeekLE==(OP_SeekLT+1) );
|
||||
assert( OP_SeekGT==(OP_SeekGE+1) );
|
||||
assert( (OP_SeekLT & 0x0001)==(OP_SeekGE & 0x0001) );
|
||||
@ -4404,7 +4416,7 @@ case OP_RowData: {
|
||||
goto too_big;
|
||||
}
|
||||
}
|
||||
if( sqlite3VdbeMemGrow(pOut, n, 0) ){
|
||||
if( sqlite3VdbeMemClearAndResize(pOut, n) ){
|
||||
goto no_mem;
|
||||
}
|
||||
pOut->n = n;
|
||||
@ -4914,7 +4926,7 @@ case OP_IdxGE: { /* jump */
|
||||
{ int i; for(i=0; i<r.nField; i++) assert( memIsValid(&r.aMem[i]) ); }
|
||||
#endif
|
||||
res = 0; /* Not needed. Only used to silence a warning. */
|
||||
rc = sqlite3VdbeIdxKeyCompare(pC, &r, &res);
|
||||
rc = sqlite3VdbeIdxKeyCompare(db, pC, &r, &res);
|
||||
assert( (OP_IdxLE&1)==(OP_IdxLT&1) && (OP_IdxGE&1)==(OP_IdxGT&1) );
|
||||
if( (pOp->opcode&1)==(OP_IdxLT&1) ){
|
||||
assert( pOp->opcode==OP_IdxLE || pOp->opcode==OP_IdxLT );
|
||||
@ -5684,11 +5696,7 @@ case OP_AggStep: {
|
||||
assert( pOp->p3>0 && pOp->p3<=(p->nMem-p->nCursor) );
|
||||
ctx.pMem = pMem = &aMem[pOp->p3];
|
||||
pMem->n++;
|
||||
t.flags = MEM_Null;
|
||||
t.z = 0;
|
||||
t.zMalloc = 0;
|
||||
t.xDel = 0;
|
||||
t.db = db;
|
||||
sqlite3VdbeMemInit(&t, db, MEM_Null);
|
||||
ctx.pOut = &t;
|
||||
ctx.isError = 0;
|
||||
ctx.pColl = 0;
|
||||
|
@ -214,10 +214,10 @@ void sqlite3VdbeSetVarmask(Vdbe*, int);
|
||||
int sqlite3MemCompare(const Mem*, const Mem*, const CollSeq*);
|
||||
|
||||
void sqlite3VdbeRecordUnpack(KeyInfo*,int,const void*,UnpackedRecord*);
|
||||
int sqlite3VdbeRecordCompare(int,const void*,UnpackedRecord*,int);
|
||||
int sqlite3VdbeRecordCompare(int,const void*,UnpackedRecord*);
|
||||
UnpackedRecord *sqlite3VdbeAllocUnpackedRecord(KeyInfo *, char *, int, char **);
|
||||
|
||||
typedef int (*RecordCompare)(int,const void*,UnpackedRecord*,int);
|
||||
typedef int (*RecordCompare)(int,const void*,UnpackedRecord*);
|
||||
RecordCompare sqlite3VdbeFindCompare(UnpackedRecord*);
|
||||
|
||||
#ifndef SQLITE_OMIT_TRIGGER
|
||||
|
@ -161,25 +161,28 @@ struct VdbeFrame {
|
||||
** integer etc.) of the same value.
|
||||
*/
|
||||
struct Mem {
|
||||
sqlite3 *db; /* The associated database connection */
|
||||
char *z; /* String or BLOB value */
|
||||
double r; /* Real value */
|
||||
union {
|
||||
union MemValue {
|
||||
double r; /* Real value used when MEM_Real is set in flags */
|
||||
i64 i; /* Integer value used when MEM_Int is set in flags */
|
||||
int nZero; /* Used when bit MEM_Zero is set in flags */
|
||||
FuncDef *pDef; /* Used only when flags==MEM_Agg */
|
||||
RowSet *pRowSet; /* Used only when flags==MEM_RowSet */
|
||||
VdbeFrame *pFrame; /* Used when flags==MEM_Frame */
|
||||
} u;
|
||||
int n; /* Number of characters in string value, excluding '\0' */
|
||||
u16 flags; /* Some combination of MEM_Null, MEM_Str, MEM_Dyn, etc. */
|
||||
u8 enc; /* SQLITE_UTF8, SQLITE_UTF16BE, SQLITE_UTF16LE */
|
||||
int n; /* Number of characters in string value, excluding '\0' */
|
||||
char *z; /* String or BLOB value */
|
||||
/* ShallowCopy only needs to copy the information above */
|
||||
char *zMalloc; /* Space to hold MEM_Str or MEM_Blob if szMalloc>0 */
|
||||
int szMalloc; /* Size of the zMalloc allocation */
|
||||
int iPadding1; /* Padding for 8-byte alignment */
|
||||
sqlite3 *db; /* The associated database connection */
|
||||
void (*xDel)(void*);/* Destructor for Mem.z - only valid if MEM_Dyn */
|
||||
#ifdef SQLITE_DEBUG
|
||||
Mem *pScopyFrom; /* This Mem is a shallow copy of pScopyFrom */
|
||||
void *pFiller; /* So that sizeof(Mem) is a multiple of 8 */
|
||||
#endif
|
||||
void (*xDel)(void *); /* If not null, call this function to delete Mem.z */
|
||||
char *zMalloc; /* Dynamic buffer allocated by sqlite3_malloc() */
|
||||
};
|
||||
|
||||
/* One or more of the following flags are set to indicate the validOK
|
||||
@ -267,13 +270,13 @@ struct AuxData {
|
||||
*/
|
||||
struct sqlite3_context {
|
||||
Mem *pOut; /* The return value is stored here */
|
||||
FuncDef *pFunc; /* Pointer to function information. MUST BE FIRST */
|
||||
FuncDef *pFunc; /* Pointer to function information */
|
||||
Mem *pMem; /* Memory cell used to store aggregate context */
|
||||
CollSeq *pColl; /* Collating sequence */
|
||||
Vdbe *pVdbe; /* The VM that owns this context */
|
||||
int iOp; /* Instruction number of OP_Function */
|
||||
int isError; /* Error code returned by the function. */
|
||||
u8 skipFlag; /* Skip skip accumulator loading if true */
|
||||
u8 skipFlag; /* Skip accumulator loading if true */
|
||||
u8 fErrorOrAux; /* isError!=0 or pVdbe->pAuxData modified */
|
||||
};
|
||||
|
||||
@ -415,8 +418,8 @@ u32 sqlite3VdbeSerialGet(const unsigned char*, u32, Mem*);
|
||||
void sqlite3VdbeDeleteAuxData(Vdbe*, int, int);
|
||||
|
||||
int sqlite2BtreeKeyCompare(BtCursor *, const void *, int, int, int *);
|
||||
int sqlite3VdbeIdxKeyCompare(VdbeCursor*,UnpackedRecord*,int*);
|
||||
int sqlite3VdbeIdxRowid(sqlite3*, BtCursor *, i64 *);
|
||||
int sqlite3VdbeIdxKeyCompare(sqlite3*,VdbeCursor*,UnpackedRecord*,int*);
|
||||
int sqlite3VdbeIdxRowid(sqlite3*, BtCursor*, i64*);
|
||||
int sqlite3VdbeExec(Vdbe*);
|
||||
int sqlite3VdbeList(Vdbe*);
|
||||
int sqlite3VdbeHalt(Vdbe*);
|
||||
@ -433,6 +436,7 @@ void sqlite3VdbeMemSetInt64(Mem*, i64);
|
||||
#else
|
||||
void sqlite3VdbeMemSetDouble(Mem*, double);
|
||||
#endif
|
||||
void sqlite3VdbeMemInit(Mem*,sqlite3*,u16);
|
||||
void sqlite3VdbeMemSetNull(Mem*);
|
||||
void sqlite3VdbeMemSetZeroBlob(Mem*,int);
|
||||
void sqlite3VdbeMemSetRowSet(Mem*);
|
||||
@ -447,14 +451,12 @@ int sqlite3VdbeMemNumerify(Mem*);
|
||||
void sqlite3VdbeMemCast(Mem*,u8,u8);
|
||||
int sqlite3VdbeMemFromBtree(BtCursor*,u32,u32,int,Mem*);
|
||||
void sqlite3VdbeMemRelease(Mem *p);
|
||||
void sqlite3VdbeMemReleaseExternal(Mem *p);
|
||||
#define VdbeMemDynamic(X) \
|
||||
(((X)->flags&(MEM_Agg|MEM_Dyn|MEM_RowSet|MEM_Frame))!=0)
|
||||
#define VdbeMemReleaseExtern(X) \
|
||||
if( VdbeMemDynamic(X) ) sqlite3VdbeMemReleaseExternal(X);
|
||||
int sqlite3VdbeMemFinalize(Mem*, FuncDef*);
|
||||
const char *sqlite3OpcodeName(int);
|
||||
int sqlite3VdbeMemGrow(Mem *pMem, int n, int preserve);
|
||||
int sqlite3VdbeMemClearAndResize(Mem *pMem, int n);
|
||||
int sqlite3VdbeCloseStatement(Vdbe *, int);
|
||||
void sqlite3VdbeFrameDelete(VdbeFrame*);
|
||||
int sqlite3VdbeFrameRestore(VdbeFrame *);
|
||||
|
102
src/vdbeapi.c
102
src/vdbeapi.c
@ -215,6 +215,9 @@ int sqlite3_value_type(sqlite3_value* pVal){
|
||||
** 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,
|
||||
@ -614,11 +662,10 @@ static SQLITE_NOINLINE void *createAggContext(sqlite3_context *p, int nByte){
|
||||
Mem *pMem = p->pMem;
|
||||
assert( (pMem->flags & MEM_Agg)==0 );
|
||||
if( nByte<=0 ){
|
||||
sqlite3VdbeMemReleaseExternal(pMem);
|
||||
pMem->flags = MEM_Null;
|
||||
sqlite3VdbeMemSetNull(pMem);
|
||||
pMem->z = 0;
|
||||
}else{
|
||||
sqlite3VdbeMemGrow(pMem, nByte, 0);
|
||||
sqlite3VdbeMemClearAndResize(pMem, nByte);
|
||||
pMem->flags = MEM_Agg;
|
||||
pMem->u.pDef = p->pFunc;
|
||||
if( pMem->z ){
|
||||
@ -755,11 +802,22 @@ static const Mem *columnNullValue(void){
|
||||
#if defined(SQLITE_DEBUG) && defined(__GNUC__)
|
||||
__attribute__((aligned(8)))
|
||||
#endif
|
||||
= {0, "", (double)0, {0}, 0, MEM_Null, 0,
|
||||
= {
|
||||
/* .u = */ {0},
|
||||
/* .flags = */ MEM_Null,
|
||||
/* .enc = */ 0,
|
||||
/* .n = */ 0,
|
||||
/* .z = */ 0,
|
||||
/* .zMalloc = */ 0,
|
||||
/* .szMalloc = */ 0,
|
||||
/* .iPadding1 = */ 0,
|
||||
/* .db = */ 0,
|
||||
/* .xDel = */ 0,
|
||||
#ifdef SQLITE_DEBUG
|
||||
0, 0, /* pScopyFrom, pFiller */
|
||||
/* .pScopyFrom = */ 0,
|
||||
/* .pFiller = */ 0,
|
||||
#endif
|
||||
0, 0 };
|
||||
};
|
||||
return &nullMem;
|
||||
}
|
||||
|
||||
@ -1125,6 +1183,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, (int)nData, xDel, 0);
|
||||
}
|
||||
}
|
||||
int sqlite3_bind_double(sqlite3_stmt *pStmt, int i, double rValue){
|
||||
int rc;
|
||||
Vdbe *p = (Vdbe *)pStmt;
|
||||
@ -1166,6 +1238,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, (int)nData, xDel, enc);
|
||||
}
|
||||
}
|
||||
#ifndef SQLITE_OMIT_UTF16
|
||||
int sqlite3_bind_text16(
|
||||
sqlite3_stmt *pStmt,
|
||||
@ -1185,7 +1273,7 @@ int sqlite3_bind_value(sqlite3_stmt *pStmt, int i, const sqlite3_value *pValue){
|
||||
break;
|
||||
}
|
||||
case SQLITE_FLOAT: {
|
||||
rc = sqlite3_bind_double(pStmt, i, pValue->r);
|
||||
rc = sqlite3_bind_double(pStmt, i, pValue->u.r);
|
||||
break;
|
||||
}
|
||||
case SQLITE_BLOB: {
|
||||
|
141
src/vdbeaux.c
141
src/vdbeaux.c
@ -10,9 +10,7 @@
|
||||
**
|
||||
*************************************************************************
|
||||
** This file contains code used for creating, destroying, and populating
|
||||
** a VDBE (or an "sqlite3_stmt" as it is known to the outside world.) Prior
|
||||
** to version 2.8.7, all this code was combined into the vdbe.c source file.
|
||||
** But that file was getting too big so this subroutines were split out.
|
||||
** a VDBE (or an "sqlite3_stmt" as it is known to the outside world.)
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include "vdbeInt.h"
|
||||
@ -699,7 +697,7 @@ static void freeP4(sqlite3 *db, int p4type, void *p4){
|
||||
sqlite3ValueFree((sqlite3_value*)p4);
|
||||
}else{
|
||||
Mem *p = (Mem*)p4;
|
||||
sqlite3DbFree(db, p->zMalloc);
|
||||
if( p->szMalloc ) sqlite3DbFree(db, p->zMalloc);
|
||||
sqlite3DbFree(db, p);
|
||||
}
|
||||
break;
|
||||
@ -1077,7 +1075,7 @@ static char *displayP4(Op *pOp, char *zTemp, int nTemp){
|
||||
}else if( pMem->flags & MEM_Int ){
|
||||
sqlite3_snprintf(nTemp, zTemp, "%lld", pMem->u.i);
|
||||
}else if( pMem->flags & MEM_Real ){
|
||||
sqlite3_snprintf(nTemp, zTemp, "%.16g", pMem->r);
|
||||
sqlite3_snprintf(nTemp, zTemp, "%.16g", pMem->u.r);
|
||||
}else if( pMem->flags & MEM_Null ){
|
||||
sqlite3_snprintf(nTemp, zTemp, "NULL");
|
||||
}else{
|
||||
@ -1227,16 +1225,16 @@ void sqlite3VdbePrintOp(FILE *pOut, int pc, Op *pOp){
|
||||
*/
|
||||
static void releaseMemArray(Mem *p, int N){
|
||||
if( p && N ){
|
||||
Mem *pEnd;
|
||||
Mem *pEnd = &p[N];
|
||||
sqlite3 *db = p->db;
|
||||
u8 malloc_failed = db->mallocFailed;
|
||||
if( db->pnBytesFreed ){
|
||||
for(pEnd=&p[N]; p<pEnd; p++){
|
||||
sqlite3DbFree(db, p->zMalloc);
|
||||
}
|
||||
do{
|
||||
if( p->szMalloc ) sqlite3DbFree(db, p->zMalloc);
|
||||
}while( (++p)<pEnd );
|
||||
return;
|
||||
}
|
||||
for(pEnd=&p[N]; p<pEnd; p++){
|
||||
do{
|
||||
assert( (&p[1])==pEnd || p[0].db==p[1].db );
|
||||
assert( sqlite3VdbeCheckMemInvariants(p) );
|
||||
|
||||
@ -1258,13 +1256,13 @@ static void releaseMemArray(Mem *p, int N){
|
||||
testcase( p->flags & MEM_RowSet );
|
||||
if( p->flags&(MEM_Agg|MEM_Dyn|MEM_Frame|MEM_RowSet) ){
|
||||
sqlite3VdbeMemRelease(p);
|
||||
}else if( p->zMalloc ){
|
||||
}else if( p->szMalloc ){
|
||||
sqlite3DbFree(db, p->zMalloc);
|
||||
p->zMalloc = 0;
|
||||
p->szMalloc = 0;
|
||||
}
|
||||
|
||||
p->flags = MEM_Undefined;
|
||||
}
|
||||
}while( (++p)<pEnd );
|
||||
db->mallocFailed = malloc_failed;
|
||||
}
|
||||
}
|
||||
@ -1427,7 +1425,7 @@ int sqlite3VdbeList(
|
||||
pMem->u.i = pOp->p3; /* P3 */
|
||||
pMem++;
|
||||
|
||||
if( sqlite3VdbeMemGrow(pMem, 32, 0) ){ /* P4 */
|
||||
if( sqlite3VdbeMemClearAndResize(pMem, 32) ){ /* P4 */
|
||||
assert( p->db->mallocFailed );
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
@ -1443,7 +1441,7 @@ int sqlite3VdbeList(
|
||||
pMem++;
|
||||
|
||||
if( p->explain==1 ){
|
||||
if( sqlite3VdbeMemGrow(pMem, 4, 0) ){
|
||||
if( sqlite3VdbeMemClearAndResize(pMem, 4) ){
|
||||
assert( p->db->mallocFailed );
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
@ -1454,7 +1452,7 @@ int sqlite3VdbeList(
|
||||
pMem++;
|
||||
|
||||
#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
|
||||
if( sqlite3VdbeMemGrow(pMem, 500, 0) ){
|
||||
if( sqlite3VdbeMemClearAndResize(pMem, 500) ){
|
||||
assert( p->db->mallocFailed );
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
@ -1607,7 +1605,7 @@ void sqlite3VdbeRewind(Vdbe *p){
|
||||
/*
|
||||
** Prepare a virtual machine for execution for the first time after
|
||||
** creating the virtual machine. This involves things such
|
||||
** as allocating stack space and initializing the program counter.
|
||||
** as allocating registers and initializing the program counter.
|
||||
** After the VDBE has be prepped, it can be executed by one or more
|
||||
** calls to sqlite3VdbeExec().
|
||||
**
|
||||
@ -1819,11 +1817,7 @@ static void closeAllCursors(Vdbe *p){
|
||||
}
|
||||
|
||||
/*
|
||||
** Clean up the VM after execution.
|
||||
**
|
||||
** This routine will automatically close any cursors, lists, and/or
|
||||
** sorters that were left open. It also deletes the values of
|
||||
** variables in the aVar[] array.
|
||||
** Clean up the VM after a single run.
|
||||
*/
|
||||
static void Cleanup(Vdbe *p){
|
||||
sqlite3 *db = p->db;
|
||||
@ -2950,8 +2944,8 @@ u32 sqlite3VdbeSerialPut(u8 *buf, Mem *pMem, u32 serial_type){
|
||||
u64 v;
|
||||
u32 i;
|
||||
if( serial_type==7 ){
|
||||
assert( sizeof(v)==sizeof(pMem->r) );
|
||||
memcpy(&v, &pMem->r, sizeof(v));
|
||||
assert( sizeof(v)==sizeof(pMem->u.r) );
|
||||
memcpy(&v, &pMem->u.r, sizeof(v));
|
||||
swapMixedEndianFloat(v);
|
||||
}else{
|
||||
v = pMem->u.i;
|
||||
@ -3021,10 +3015,10 @@ static u32 SQLITE_NOINLINE serialGet(
|
||||
swapMixedEndianFloat(t2);
|
||||
assert( sizeof(r1)==sizeof(t2) && memcmp(&r1, &t2, sizeof(r1))==0 );
|
||||
#endif
|
||||
assert( sizeof(x)==8 && sizeof(pMem->r)==8 );
|
||||
assert( sizeof(x)==8 && sizeof(pMem->u.r)==8 );
|
||||
swapMixedEndianFloat(x);
|
||||
memcpy(&pMem->r, &x, sizeof(x));
|
||||
pMem->flags = sqlite3IsNaN(pMem->r) ? MEM_Null : MEM_Real;
|
||||
memcpy(&pMem->u.r, &x, sizeof(x));
|
||||
pMem->flags = sqlite3IsNaN(pMem->u.r) ? MEM_Null : MEM_Real;
|
||||
}
|
||||
return 8;
|
||||
}
|
||||
@ -3086,7 +3080,6 @@ u32 sqlite3VdbeSerialGet(
|
||||
static const u16 aFlag[] = { MEM_Blob|MEM_Ephem, MEM_Str|MEM_Ephem };
|
||||
pMem->z = (char *)buf;
|
||||
pMem->n = (serial_type-12)/2;
|
||||
pMem->xDel = 0;
|
||||
pMem->flags = aFlag[serial_type&1];
|
||||
return pMem->n;
|
||||
}
|
||||
@ -3162,18 +3155,18 @@ void sqlite3VdbeRecordUnpack(
|
||||
idx = getVarint32(aKey, szHdr);
|
||||
d = szHdr;
|
||||
u = 0;
|
||||
while( idx<szHdr && u<p->nField && d<=nKey ){
|
||||
while( idx<szHdr && d<=nKey ){
|
||||
u32 serial_type;
|
||||
|
||||
idx += getVarint32(&aKey[idx], serial_type);
|
||||
pMem->enc = pKeyInfo->enc;
|
||||
pMem->db = pKeyInfo->db;
|
||||
/* pMem->flags = 0; // sqlite3VdbeSerialGet() will set this for us */
|
||||
pMem->zMalloc = 0;
|
||||
pMem->szMalloc = 0;
|
||||
pMem->z = 0;
|
||||
d += sqlite3VdbeSerialGet(&aKey[d], serial_type, pMem);
|
||||
pMem++;
|
||||
u++;
|
||||
if( (++u)>=p->nField ) break;
|
||||
}
|
||||
assert( u<=pKeyInfo->nField + 1 );
|
||||
p->nField = u;
|
||||
@ -3210,7 +3203,7 @@ static int vdbeRecordCompareDebug(
|
||||
mem1.enc = pKeyInfo->enc;
|
||||
mem1.db = pKeyInfo->db;
|
||||
/* mem1.flags = 0; // Will be initialized by sqlite3VdbeSerialGet() */
|
||||
VVA_ONLY( mem1.zMalloc = 0; ) /* Only needed by assert() statements */
|
||||
VVA_ONLY( mem1.szMalloc = 0; ) /* Only needed by assert() statements */
|
||||
|
||||
/* Compilers may complain that mem1.u.i is potentially uninitialized.
|
||||
** We could initialize it, as shown here, to silence those complaints.
|
||||
@ -3253,7 +3246,7 @@ static int vdbeRecordCompareDebug(
|
||||
*/
|
||||
rc = sqlite3MemCompare(&mem1, &pPKey2->aMem[i], pKeyInfo->aColl[i]);
|
||||
if( rc!=0 ){
|
||||
assert( mem1.zMalloc==0 ); /* See comment below */
|
||||
assert( mem1.szMalloc==0 ); /* See comment below */
|
||||
if( pKeyInfo->aSortOrder[i] ){
|
||||
rc = -rc; /* Invert the result for DESC sort order. */
|
||||
}
|
||||
@ -3266,7 +3259,7 @@ static int vdbeRecordCompareDebug(
|
||||
** the following assert(). If the assert() fails, it indicates a
|
||||
** memory leak and a need to call sqlite3VdbeMemRelease(&mem1).
|
||||
*/
|
||||
assert( mem1.zMalloc==0 );
|
||||
assert( mem1.szMalloc==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 default_rc
|
||||
@ -3305,8 +3298,8 @@ static int vdbeCompareMemString(
|
||||
int n1, n2;
|
||||
Mem c1;
|
||||
Mem c2;
|
||||
memset(&c1, 0, sizeof(c1));
|
||||
memset(&c2, 0, sizeof(c2));
|
||||
sqlite3VdbeMemInit(&c1, pMem1->db, MEM_Null);
|
||||
sqlite3VdbeMemInit(&c2, pMem1->db, MEM_Null);
|
||||
sqlite3VdbeMemShallowCopy(&c1, pMem1, MEM_Ephem);
|
||||
sqlite3VdbeMemShallowCopy(&c2, pMem2, MEM_Ephem);
|
||||
v1 = sqlite3ValueText((sqlite3_value*)&c1, pColl->enc);
|
||||
@ -3321,6 +3314,18 @@ static int vdbeCompareMemString(
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Compare two blobs. Return negative, zero, or positive if the first
|
||||
** is less than, equal to, or greater than the second, respectively.
|
||||
** If one blob is a prefix of the other, then the shorter is the lessor.
|
||||
*/
|
||||
static SQLITE_NOINLINE int sqlite3BlobCompare(const Mem *pB1, const Mem *pB2){
|
||||
int c = memcmp(pB1->z, pB2->z, pB1->n>pB2->n ? pB2->n : pB1->n);
|
||||
if( c ) return c;
|
||||
return pB1->n - pB2->n;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Compare the values contained by the two memory cells, returning
|
||||
** negative, zero or positive if pMem1 is less than, equal to, or greater
|
||||
@ -3331,7 +3336,6 @@ static int vdbeCompareMemString(
|
||||
** Two NULL values are considered equal by this function.
|
||||
*/
|
||||
int sqlite3MemCompare(const Mem *pMem1, const Mem *pMem2, const CollSeq *pColl){
|
||||
int rc;
|
||||
int f1, f2;
|
||||
int combined_flags;
|
||||
|
||||
@ -3359,14 +3363,14 @@ int sqlite3MemCompare(const Mem *pMem1, const Mem *pMem2, const CollSeq *pColl){
|
||||
return 0;
|
||||
}
|
||||
if( (f1&MEM_Real)!=0 ){
|
||||
r1 = pMem1->r;
|
||||
r1 = pMem1->u.r;
|
||||
}else if( (f1&MEM_Int)!=0 ){
|
||||
r1 = (double)pMem1->u.i;
|
||||
}else{
|
||||
return 1;
|
||||
}
|
||||
if( (f2&MEM_Real)!=0 ){
|
||||
r2 = pMem2->r;
|
||||
r2 = pMem2->u.r;
|
||||
}else if( (f2&MEM_Int)!=0 ){
|
||||
r2 = (double)pMem2->u.i;
|
||||
}else{
|
||||
@ -3406,11 +3410,7 @@ int sqlite3MemCompare(const Mem *pMem1, const Mem *pMem2, const CollSeq *pColl){
|
||||
}
|
||||
|
||||
/* Both values must be blobs. Compare using memcmp(). */
|
||||
rc = memcmp(pMem1->z, pMem2->z, (pMem1->n>pMem2->n)?pMem2->n:pMem1->n);
|
||||
if( rc==0 ){
|
||||
rc = pMem1->n - pMem2->n;
|
||||
}
|
||||
return rc;
|
||||
return sqlite3BlobCompare(pMem1, pMem2);
|
||||
}
|
||||
|
||||
|
||||
@ -3476,7 +3476,7 @@ static i64 vdbeRecordDecodeInt(u32 serial_type, const u8 *aKey){
|
||||
** pPKey2->errCode is set to SQLITE_NOMEM and, if it is not NULL, the
|
||||
** malloc-failed flag set on database handle (pPKey2->pKeyInfo->db).
|
||||
*/
|
||||
int sqlite3VdbeRecordCompare(
|
||||
static int vdbeRecordCompareWithSkip(
|
||||
int nKey1, const void *pKey1, /* Left key */
|
||||
UnpackedRecord *pPKey2, /* Right key */
|
||||
int bSkip /* If true, skip the first field */
|
||||
@ -3511,7 +3511,7 @@ int sqlite3VdbeRecordCompare(
|
||||
i = 0;
|
||||
}
|
||||
|
||||
VVA_ONLY( mem1.zMalloc = 0; ) /* Only needed by assert() statements */
|
||||
VVA_ONLY( mem1.szMalloc = 0; ) /* Only needed by assert() statements */
|
||||
assert( pPKey2->pKeyInfo->nField+pPKey2->pKeyInfo->nXField>=pPKey2->nField
|
||||
|| CORRUPT_DB );
|
||||
assert( pPKey2->pKeyInfo->aSortOrder!=0 );
|
||||
@ -3531,9 +3531,9 @@ int sqlite3VdbeRecordCompare(
|
||||
}else if( serial_type==7 ){
|
||||
double rhs = (double)pRhs->u.i;
|
||||
sqlite3VdbeSerialGet(&aKey1[d1], serial_type, &mem1);
|
||||
if( mem1.r<rhs ){
|
||||
if( mem1.u.r<rhs ){
|
||||
rc = -1;
|
||||
}else if( mem1.r>rhs ){
|
||||
}else if( mem1.u.r>rhs ){
|
||||
rc = +1;
|
||||
}
|
||||
}else{
|
||||
@ -3555,11 +3555,11 @@ int sqlite3VdbeRecordCompare(
|
||||
}else if( serial_type==0 ){
|
||||
rc = -1;
|
||||
}else{
|
||||
double rhs = pRhs->r;
|
||||
double rhs = pRhs->u.r;
|
||||
double lhs;
|
||||
sqlite3VdbeSerialGet(&aKey1[d1], serial_type, &mem1);
|
||||
if( serial_type==7 ){
|
||||
lhs = mem1.r;
|
||||
lhs = mem1.u.r;
|
||||
}else{
|
||||
lhs = (double)mem1.u.i;
|
||||
}
|
||||
@ -3634,7 +3634,7 @@ int sqlite3VdbeRecordCompare(
|
||||
rc = -rc;
|
||||
}
|
||||
assert( vdbeRecordCompareDebug(nKey1, pKey1, pPKey2, rc) );
|
||||
assert( mem1.zMalloc==0 ); /* See comment below */
|
||||
assert( mem1.szMalloc==0 ); /* See comment below */
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -3647,7 +3647,7 @@ int sqlite3VdbeRecordCompare(
|
||||
/* No memory allocation is ever used on mem1. Prove this using
|
||||
** the following assert(). If the assert() fails, it indicates a
|
||||
** memory leak and a need to call sqlite3VdbeMemRelease(&mem1). */
|
||||
assert( mem1.zMalloc==0 );
|
||||
assert( mem1.szMalloc==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 default_rc
|
||||
@ -3658,6 +3658,13 @@ int sqlite3VdbeRecordCompare(
|
||||
);
|
||||
return pPKey2->default_rc;
|
||||
}
|
||||
int sqlite3VdbeRecordCompare(
|
||||
int nKey1, const void *pKey1, /* Left key */
|
||||
UnpackedRecord *pPKey2 /* Right key */
|
||||
){
|
||||
return vdbeRecordCompareWithSkip(nKey1, pKey1, pPKey2, 0);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** This function is an optimized version of sqlite3VdbeRecordCompare()
|
||||
@ -3670,8 +3677,7 @@ int sqlite3VdbeRecordCompare(
|
||||
*/
|
||||
static int vdbeRecordCompareInt(
|
||||
int nKey1, const void *pKey1, /* Left key */
|
||||
UnpackedRecord *pPKey2, /* Right key */
|
||||
int bSkip /* Ignored */
|
||||
UnpackedRecord *pPKey2 /* Right key */
|
||||
){
|
||||
const u8 *aKey = &((const u8*)pKey1)[*(const u8*)pKey1 & 0x3F];
|
||||
int serial_type = ((const u8*)pKey1)[1];
|
||||
@ -3680,9 +3686,7 @@ static int vdbeRecordCompareInt(
|
||||
u64 x;
|
||||
i64 v = pPKey2->aMem[0].u.i;
|
||||
i64 lhs;
|
||||
UNUSED_PARAMETER(bSkip);
|
||||
|
||||
assert( bSkip==0 );
|
||||
assert( (*(u8*)pKey1)<=0x3F || CORRUPT_DB );
|
||||
switch( serial_type ){
|
||||
case 1: { /* 1-byte signed integer */
|
||||
@ -3732,10 +3736,10 @@ static int vdbeRecordCompareInt(
|
||||
** (as gcc is clever enough to combine the two like cases). Other
|
||||
** compilers might be similar. */
|
||||
case 0: case 7:
|
||||
return sqlite3VdbeRecordCompare(nKey1, pKey1, pPKey2, 0);
|
||||
return sqlite3VdbeRecordCompare(nKey1, pKey1, pPKey2);
|
||||
|
||||
default:
|
||||
return sqlite3VdbeRecordCompare(nKey1, pKey1, pPKey2, 0);
|
||||
return sqlite3VdbeRecordCompare(nKey1, pKey1, pPKey2);
|
||||
}
|
||||
|
||||
if( v>lhs ){
|
||||
@ -3745,7 +3749,7 @@ static int vdbeRecordCompareInt(
|
||||
}else if( pPKey2->nField>1 ){
|
||||
/* The first fields of the two keys are equal. Compare the trailing
|
||||
** fields. */
|
||||
res = sqlite3VdbeRecordCompare(nKey1, pKey1, pPKey2, 1);
|
||||
res = vdbeRecordCompareWithSkip(nKey1, pKey1, pPKey2, 1);
|
||||
}else{
|
||||
/* The first fields of the two keys are equal and there are no trailing
|
||||
** fields. Return pPKey2->default_rc in this case. */
|
||||
@ -3764,17 +3768,13 @@ static int vdbeRecordCompareInt(
|
||||
*/
|
||||
static int vdbeRecordCompareString(
|
||||
int nKey1, const void *pKey1, /* Left key */
|
||||
UnpackedRecord *pPKey2, /* Right key */
|
||||
int bSkip
|
||||
UnpackedRecord *pPKey2 /* Right key */
|
||||
){
|
||||
const u8 *aKey1 = (const u8*)pKey1;
|
||||
int serial_type;
|
||||
int res;
|
||||
UNUSED_PARAMETER(bSkip);
|
||||
|
||||
assert( bSkip==0 );
|
||||
getVarint32(&aKey1[1], serial_type);
|
||||
|
||||
if( serial_type<12 ){
|
||||
res = pPKey2->r1; /* (pKey1/nKey1) is a number or a null */
|
||||
}else if( !(serial_type & 0x01) ){
|
||||
@ -3796,7 +3796,7 @@ static int vdbeRecordCompareString(
|
||||
res = nStr - pPKey2->aMem[0].n;
|
||||
if( res==0 ){
|
||||
if( pPKey2->nField>1 ){
|
||||
res = sqlite3VdbeRecordCompare(nKey1, pKey1, pPKey2, 1);
|
||||
res = vdbeRecordCompareWithSkip(nKey1, pKey1, pPKey2, 1);
|
||||
}else{
|
||||
res = pPKey2->default_rc;
|
||||
}
|
||||
@ -3878,8 +3878,6 @@ int sqlite3VdbeIdxRowid(sqlite3 *db, BtCursor *pCur, i64 *rowid){
|
||||
u32 lenRowid; /* Size of the rowid */
|
||||
Mem m, v;
|
||||
|
||||
UNUSED_PARAMETER(db);
|
||||
|
||||
/* Get the size of the index entry. Only indices entries of less
|
||||
** than 2GiB are support - anything large must be database corruption.
|
||||
** Any corruption is detected in sqlite3BtreeParseCellPtr(), though, so
|
||||
@ -3891,7 +3889,7 @@ int sqlite3VdbeIdxRowid(sqlite3 *db, BtCursor *pCur, i64 *rowid){
|
||||
assert( (nCellKey & SQLITE_MAX_U32)==(u64)nCellKey );
|
||||
|
||||
/* Read in the complete content of the index entry */
|
||||
memset(&m, 0, sizeof(m));
|
||||
sqlite3VdbeMemInit(&m, db, 0);
|
||||
rc = sqlite3VdbeMemFromBtree(pCur, 0, (u32)nCellKey, 1, &m);
|
||||
if( rc ){
|
||||
return rc;
|
||||
@ -3934,7 +3932,7 @@ int sqlite3VdbeIdxRowid(sqlite3 *db, BtCursor *pCur, i64 *rowid){
|
||||
/* Jump here if database corruption is detected after m has been
|
||||
** allocated. Free the m object and return SQLITE_CORRUPT. */
|
||||
idx_rowid_corruption:
|
||||
testcase( m.zMalloc!=0 );
|
||||
testcase( m.szMalloc!=0 );
|
||||
sqlite3VdbeMemRelease(&m);
|
||||
return SQLITE_CORRUPT_BKPT;
|
||||
}
|
||||
@ -3951,6 +3949,7 @@ idx_rowid_corruption:
|
||||
** of the keys prior to the final rowid, not the entire key.
|
||||
*/
|
||||
int sqlite3VdbeIdxKeyCompare(
|
||||
sqlite3 *db, /* Database connection */
|
||||
VdbeCursor *pC, /* The cursor to compare against */
|
||||
UnpackedRecord *pUnpacked, /* Unpacked version of key */
|
||||
int *res /* Write the comparison result here */
|
||||
@ -3969,12 +3968,12 @@ int sqlite3VdbeIdxKeyCompare(
|
||||
*res = 0;
|
||||
return SQLITE_CORRUPT_BKPT;
|
||||
}
|
||||
memset(&m, 0, sizeof(m));
|
||||
sqlite3VdbeMemInit(&m, db, 0);
|
||||
rc = sqlite3VdbeMemFromBtree(pC->pCursor, 0, (u32)nCellKey, 1, &m);
|
||||
if( rc ){
|
||||
return rc;
|
||||
}
|
||||
*res = sqlite3VdbeRecordCompare(m.n, m.z, pUnpacked, 0);
|
||||
*res = sqlite3VdbeRecordCompare(m.n, m.z, pUnpacked);
|
||||
sqlite3VdbeMemRelease(&m);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
276
src/vdbemem.c
276
src/vdbemem.c
@ -26,11 +26,20 @@
|
||||
** this: assert( sqlite3VdbeCheckMemInvariants(pMem) );
|
||||
*/
|
||||
int sqlite3VdbeCheckMemInvariants(Mem *p){
|
||||
/* The MEM_Dyn bit is set if and only if Mem.xDel is a non-NULL destructor
|
||||
** function for Mem.z
|
||||
/* If MEM_Dyn is set then Mem.xDel!=0.
|
||||
** Mem.xDel is might not be initialized if MEM_Dyn is clear.
|
||||
*/
|
||||
assert( (p->flags & MEM_Dyn)==0 || p->xDel!=0 );
|
||||
assert( (p->flags & MEM_Dyn)!=0 || p->xDel==0 );
|
||||
|
||||
/* MEM_Dyn may only be set if Mem.szMalloc==0 */
|
||||
assert( (p->flags & MEM_Dyn)==0 || p->szMalloc==0 );
|
||||
|
||||
/* Cannot be both MEM_Int and MEM_Real at the same time */
|
||||
assert( (p->flags & (MEM_Int|MEM_Real))!=(MEM_Int|MEM_Real) );
|
||||
|
||||
/* The szMalloc field holds the correct memory allocation size */
|
||||
assert( p->szMalloc==0
|
||||
|| p->szMalloc==sqlite3DbMallocSize(p->db,p->zMalloc) );
|
||||
|
||||
/* If p holds a string or blob, the Mem.z must point to exactly
|
||||
** one of the following:
|
||||
@ -40,15 +49,14 @@ int sqlite3VdbeCheckMemInvariants(Mem *p){
|
||||
** (3) An ephemeral string or blob
|
||||
** (4) A static string or blob
|
||||
*/
|
||||
if( (p->flags & (MEM_Str|MEM_Blob)) && p->z!=0 ){
|
||||
if( (p->flags & (MEM_Str|MEM_Blob)) && p->n>0 ){
|
||||
assert(
|
||||
((p->z==p->zMalloc)? 1 : 0) +
|
||||
((p->szMalloc>0 && p->z==p->zMalloc)? 1 : 0) +
|
||||
((p->flags&MEM_Dyn)!=0 ? 1 : 0) +
|
||||
((p->flags&MEM_Ephem)!=0 ? 1 : 0) +
|
||||
((p->flags&MEM_Static)!=0 ? 1 : 0) == 1
|
||||
);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
@ -102,7 +110,7 @@ int sqlite3VdbeChangeEncoding(Mem *pMem, int desiredEnc){
|
||||
** blob if bPreserve is true. If bPreserve is false, any prior content
|
||||
** in pMem->z is discarded.
|
||||
*/
|
||||
int sqlite3VdbeMemGrow(Mem *pMem, int n, int bPreserve){
|
||||
SQLITE_NOINLINE int sqlite3VdbeMemGrow(Mem *pMem, int n, int bPreserve){
|
||||
assert( sqlite3VdbeCheckMemInvariants(pMem) );
|
||||
assert( (pMem->flags&MEM_RowSet)==0 );
|
||||
|
||||
@ -111,20 +119,24 @@ int sqlite3VdbeMemGrow(Mem *pMem, int n, int bPreserve){
|
||||
assert( bPreserve==0 || pMem->flags&(MEM_Blob|MEM_Str) );
|
||||
testcase( bPreserve && pMem->z==0 );
|
||||
|
||||
if( pMem->zMalloc==0 || sqlite3DbMallocSize(pMem->db, pMem->zMalloc)<n ){
|
||||
assert( pMem->szMalloc==0
|
||||
|| pMem->szMalloc==sqlite3DbMallocSize(pMem->db, pMem->zMalloc) );
|
||||
if( pMem->szMalloc<n ){
|
||||
if( n<32 ) n = 32;
|
||||
if( bPreserve && pMem->z==pMem->zMalloc ){
|
||||
if( bPreserve && pMem->szMalloc>0 && pMem->z==pMem->zMalloc ){
|
||||
pMem->z = pMem->zMalloc = sqlite3DbReallocOrFree(pMem->db, pMem->z, n);
|
||||
bPreserve = 0;
|
||||
}else{
|
||||
sqlite3DbFree(pMem->db, pMem->zMalloc);
|
||||
if( pMem->szMalloc>0 ) sqlite3DbFree(pMem->db, pMem->zMalloc);
|
||||
pMem->zMalloc = sqlite3DbMallocRaw(pMem->db, n);
|
||||
}
|
||||
if( pMem->zMalloc==0 ){
|
||||
VdbeMemReleaseExtern(pMem);
|
||||
sqlite3VdbeMemSetNull(pMem);
|
||||
pMem->z = 0;
|
||||
pMem->flags = MEM_Null;
|
||||
pMem->szMalloc = 0;
|
||||
return SQLITE_NOMEM;
|
||||
}else{
|
||||
pMem->szMalloc = sqlite3DbMallocSize(pMem->db, pMem->zMalloc);
|
||||
}
|
||||
}
|
||||
|
||||
@ -138,15 +150,36 @@ int sqlite3VdbeMemGrow(Mem *pMem, int n, int bPreserve){
|
||||
|
||||
pMem->z = pMem->zMalloc;
|
||||
pMem->flags &= ~(MEM_Dyn|MEM_Ephem|MEM_Static);
|
||||
pMem->xDel = 0;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Make the given Mem object MEM_Dyn. In other words, make it so
|
||||
** that any TEXT or BLOB content is stored in memory obtained from
|
||||
** malloc(). In this way, we know that the memory is safe to be
|
||||
** overwritten or altered.
|
||||
** Change the pMem->zMalloc allocation to be at least szNew bytes.
|
||||
** If pMem->zMalloc already meets or exceeds the requested size, this
|
||||
** routine is a no-op.
|
||||
**
|
||||
** Any prior string or blob content in the pMem object may be discarded.
|
||||
** The pMem->xDel destructor is called, if it exists. Though MEM_Str
|
||||
** and MEM_Blob values may be discarded, MEM_Int, MEM_Real, and MEM_Null
|
||||
** values are preserved.
|
||||
**
|
||||
** Return SQLITE_OK on success or an error code (probably SQLITE_NOMEM)
|
||||
** if unable to complete the resizing.
|
||||
*/
|
||||
int sqlite3VdbeMemClearAndResize(Mem *pMem, int szNew){
|
||||
assert( szNew>=0 );
|
||||
if( pMem->szMalloc<szNew ){
|
||||
return sqlite3VdbeMemGrow(pMem, szNew, 0);
|
||||
}
|
||||
assert( (pMem->flags & MEM_Dyn)==0 );
|
||||
pMem->z = pMem->zMalloc;
|
||||
pMem->flags &= (MEM_Null|MEM_Int|MEM_Real);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Change pMem so that its MEM_Str or MEM_Blob value is stored in
|
||||
** MEM.zMalloc, where it can be safely written.
|
||||
**
|
||||
** Return SQLITE_OK on success or SQLITE_NOMEM if malloc fails.
|
||||
*/
|
||||
@ -156,7 +189,7 @@ int sqlite3VdbeMemMakeWriteable(Mem *pMem){
|
||||
assert( (pMem->flags&MEM_RowSet)==0 );
|
||||
ExpandBlob(pMem);
|
||||
f = pMem->flags;
|
||||
if( (f&(MEM_Str|MEM_Blob)) && pMem->z!=pMem->zMalloc ){
|
||||
if( (f&(MEM_Str|MEM_Blob)) && (pMem->szMalloc==0 || pMem->z!=pMem->zMalloc) ){
|
||||
if( sqlite3VdbeMemGrow(pMem, pMem->n + 2, 1) ){
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
@ -254,7 +287,7 @@ int sqlite3VdbeMemStringify(Mem *pMem, u8 enc, u8 bForce){
|
||||
assert( EIGHT_BYTE_ALIGNMENT(pMem) );
|
||||
|
||||
|
||||
if( sqlite3VdbeMemGrow(pMem, nByte, 0) ){
|
||||
if( sqlite3VdbeMemClearAndResize(pMem, nByte) ){
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
|
||||
@ -268,7 +301,7 @@ int sqlite3VdbeMemStringify(Mem *pMem, u8 enc, u8 bForce){
|
||||
sqlite3_snprintf(nByte, pMem->z, "%lld", pMem->u.i);
|
||||
}else{
|
||||
assert( fg & MEM_Real );
|
||||
sqlite3_snprintf(nByte, pMem->z, "%!.15g", pMem->r);
|
||||
sqlite3_snprintf(nByte, pMem->z, "%!.15g", pMem->u.r);
|
||||
}
|
||||
pMem->n = sqlite3Strlen30(pMem->z);
|
||||
pMem->enc = SQLITE_UTF8;
|
||||
@ -301,8 +334,8 @@ int sqlite3VdbeMemFinalize(Mem *pMem, FuncDef *pFunc){
|
||||
ctx.pMem = pMem;
|
||||
ctx.pFunc = pFunc;
|
||||
pFunc->xFinalize(&ctx); /* IMP: R-24505-23230 */
|
||||
assert( 0==(pMem->flags&MEM_Dyn) && !pMem->xDel );
|
||||
sqlite3DbFree(pMem->db, pMem->zMalloc);
|
||||
assert( (pMem->flags & MEM_Dyn)==0 );
|
||||
if( pMem->szMalloc>0 ) sqlite3DbFree(pMem->db, pMem->zMalloc);
|
||||
memcpy(pMem, &t, sizeof(t));
|
||||
rc = ctx.isError;
|
||||
}
|
||||
@ -310,29 +343,34 @@ int sqlite3VdbeMemFinalize(Mem *pMem, FuncDef *pFunc){
|
||||
}
|
||||
|
||||
/*
|
||||
** If the memory cell contains a string value that must be freed by
|
||||
** invoking an external callback, free it now. Calling this function
|
||||
** does not free any Mem.zMalloc buffer.
|
||||
** If the memory cell contains a value that must be freed by
|
||||
** invoking the external callback in Mem.xDel, then this routine
|
||||
** will free that value. It also sets Mem.flags to MEM_Null.
|
||||
**
|
||||
** The VdbeMemReleaseExtern() macro invokes this routine if only if there
|
||||
** is work for this routine to do.
|
||||
** This is a helper routine for sqlite3VdbeMemSetNull() and
|
||||
** for sqlite3VdbeMemRelease(). Use those other routines as the
|
||||
** entry point for releasing Mem resources.
|
||||
*/
|
||||
void sqlite3VdbeMemReleaseExternal(Mem *p){
|
||||
static SQLITE_NOINLINE void vdbeMemClearExternAndSetNull(Mem *p){
|
||||
assert( p->db==0 || sqlite3_mutex_held(p->db->mutex) );
|
||||
assert( VdbeMemDynamic(p) );
|
||||
if( p->flags&MEM_Agg ){
|
||||
sqlite3VdbeMemFinalize(p, p->u.pDef);
|
||||
assert( (p->flags & MEM_Agg)==0 );
|
||||
sqlite3VdbeMemRelease(p);
|
||||
}else if( p->flags&MEM_Dyn ){
|
||||
testcase( p->flags & MEM_Dyn );
|
||||
}
|
||||
if( p->flags&MEM_Dyn ){
|
||||
assert( (p->flags&MEM_RowSet)==0 );
|
||||
assert( p->xDel!=SQLITE_DYNAMIC && p->xDel!=0 );
|
||||
p->xDel((void *)p->z);
|
||||
p->xDel = 0;
|
||||
}else if( p->flags&MEM_RowSet ){
|
||||
sqlite3RowSetClear(p->u.pRowSet);
|
||||
}else if( p->flags&MEM_Frame ){
|
||||
sqlite3VdbeMemSetNull(p);
|
||||
VdbeFrame *pFrame = p->u.pFrame;
|
||||
pFrame->pParent = pFrame->v->pDelFrame;
|
||||
pFrame->v->pDelFrame = pFrame;
|
||||
}
|
||||
p->flags = MEM_Null;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -340,33 +378,35 @@ void sqlite3VdbeMemReleaseExternal(Mem *p){
|
||||
** by p->xDel and memory in p->zMalloc.
|
||||
**
|
||||
** This is a helper routine invoked by sqlite3VdbeMemRelease() in
|
||||
** the uncommon case when there really is memory in p that is
|
||||
** need of freeing.
|
||||
** the unusual case where there really is memory in p that needs
|
||||
** to be freed.
|
||||
*/
|
||||
static SQLITE_NOINLINE void vdbeMemRelease(Mem *p){
|
||||
static SQLITE_NOINLINE void vdbeMemClear(Mem *p){
|
||||
if( VdbeMemDynamic(p) ){
|
||||
sqlite3VdbeMemReleaseExternal(p);
|
||||
vdbeMemClearExternAndSetNull(p);
|
||||
}
|
||||
if( p->zMalloc ){
|
||||
if( p->szMalloc ){
|
||||
sqlite3DbFree(p->db, p->zMalloc);
|
||||
p->zMalloc = 0;
|
||||
p->szMalloc = 0;
|
||||
}
|
||||
p->z = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Release any memory held by the Mem. This may leave the Mem in an
|
||||
** inconsistent state, for example with (Mem.z==0) and
|
||||
** (Mem.flags==MEM_Str).
|
||||
** Release any memory resources held by the Mem. Both the memory that is
|
||||
** free by Mem.xDel and the Mem.zMalloc allocation are freed.
|
||||
**
|
||||
** Use this routine prior to clean up prior to abandoning a Mem, or to
|
||||
** reset a Mem back to its minimum memory utilization.
|
||||
**
|
||||
** Use sqlite3VdbeMemSetNull() to release just the Mem.xDel space
|
||||
** prior to inserting new content into the Mem.
|
||||
*/
|
||||
void sqlite3VdbeMemRelease(Mem *p){
|
||||
assert( sqlite3VdbeCheckMemInvariants(p) );
|
||||
if( VdbeMemDynamic(p) || p->zMalloc ){
|
||||
vdbeMemRelease(p);
|
||||
}else{
|
||||
p->z = 0;
|
||||
if( VdbeMemDynamic(p) || p->szMalloc ){
|
||||
vdbeMemClear(p);
|
||||
}
|
||||
assert( p->xDel==0 );
|
||||
}
|
||||
|
||||
/*
|
||||
@ -418,7 +458,7 @@ i64 sqlite3VdbeIntValue(Mem *pMem){
|
||||
if( flags & MEM_Int ){
|
||||
return pMem->u.i;
|
||||
}else if( flags & MEM_Real ){
|
||||
return doubleToInt64(pMem->r);
|
||||
return doubleToInt64(pMem->u.r);
|
||||
}else if( flags & (MEM_Str|MEM_Blob) ){
|
||||
i64 value = 0;
|
||||
assert( pMem->z || pMem->n==0 );
|
||||
@ -439,7 +479,7 @@ double sqlite3VdbeRealValue(Mem *pMem){
|
||||
assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
|
||||
assert( EIGHT_BYTE_ALIGNMENT(pMem) );
|
||||
if( pMem->flags & MEM_Real ){
|
||||
return pMem->r;
|
||||
return pMem->u.r;
|
||||
}else if( pMem->flags & MEM_Int ){
|
||||
return (double)pMem->u.i;
|
||||
}else if( pMem->flags & (MEM_Str|MEM_Blob) ){
|
||||
@ -458,12 +498,13 @@ double sqlite3VdbeRealValue(Mem *pMem){
|
||||
** MEM_Int if we can.
|
||||
*/
|
||||
void sqlite3VdbeIntegerAffinity(Mem *pMem){
|
||||
i64 ix;
|
||||
assert( pMem->flags & MEM_Real );
|
||||
assert( (pMem->flags & MEM_RowSet)==0 );
|
||||
assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
|
||||
assert( EIGHT_BYTE_ALIGNMENT(pMem) );
|
||||
|
||||
pMem->u.i = doubleToInt64(pMem->r);
|
||||
ix = doubleToInt64(pMem->u.r);
|
||||
|
||||
/* Only mark the value as an integer if
|
||||
**
|
||||
@ -475,11 +516,9 @@ void sqlite3VdbeIntegerAffinity(Mem *pMem){
|
||||
** the second condition under the assumption that addition overflow causes
|
||||
** values to wrap around.
|
||||
*/
|
||||
if( pMem->r==(double)pMem->u.i
|
||||
&& pMem->u.i>SMALLEST_INT64
|
||||
&& pMem->u.i<LARGEST_INT64
|
||||
){
|
||||
pMem->flags |= MEM_Int;
|
||||
if( pMem->u.r==ix && ix>SMALLEST_INT64 && ix<LARGEST_INT64 ){
|
||||
pMem->u.i = ix;
|
||||
MemSetTypeFlag(pMem, MEM_Int);
|
||||
}
|
||||
}
|
||||
|
||||
@ -504,7 +543,7 @@ int sqlite3VdbeMemRealify(Mem *pMem){
|
||||
assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
|
||||
assert( EIGHT_BYTE_ALIGNMENT(pMem) );
|
||||
|
||||
pMem->r = sqlite3VdbeRealValue(pMem);
|
||||
pMem->u.r = sqlite3VdbeRealValue(pMem);
|
||||
MemSetTypeFlag(pMem, MEM_Real);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
@ -524,7 +563,7 @@ int sqlite3VdbeMemNumerify(Mem *pMem){
|
||||
if( 0==sqlite3Atoi64(pMem->z, &pMem->u.i, pMem->n, pMem->enc) ){
|
||||
MemSetTypeFlag(pMem, MEM_Int);
|
||||
}else{
|
||||
pMem->r = sqlite3VdbeRealValue(pMem);
|
||||
pMem->u.r = sqlite3VdbeRealValue(pMem);
|
||||
MemSetTypeFlag(pMem, MEM_Real);
|
||||
sqlite3VdbeIntegerAffinity(pMem);
|
||||
}
|
||||
@ -578,20 +617,37 @@ void sqlite3VdbeMemCast(Mem *pMem, u8 aff, u8 encoding){
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Initialize bulk memory to be a consistent Mem object.
|
||||
**
|
||||
** The minimum amount of initialization feasible is performed.
|
||||
*/
|
||||
void sqlite3VdbeMemInit(Mem *pMem, sqlite3 *db, u16 flags){
|
||||
assert( (flags & ~MEM_TypeMask)==0 );
|
||||
pMem->flags = flags;
|
||||
pMem->db = db;
|
||||
pMem->szMalloc = 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Delete any previous value and set the value stored in *pMem to NULL.
|
||||
**
|
||||
** This routine calls the Mem.xDel destructor to dispose of values that
|
||||
** require the destructor. But it preserves the Mem.zMalloc memory allocation.
|
||||
** To free all resources, use sqlite3VdbeMemRelease(), which both calls this
|
||||
** routine to invoke the destructor and deallocates Mem.zMalloc.
|
||||
**
|
||||
** Use this routine to reset the Mem prior to insert a new value.
|
||||
**
|
||||
** Use sqlite3VdbeMemRelease() to complete erase the Mem prior to abandoning it.
|
||||
*/
|
||||
void sqlite3VdbeMemSetNull(Mem *pMem){
|
||||
if( pMem->flags & MEM_Frame ){
|
||||
VdbeFrame *pFrame = pMem->u.pFrame;
|
||||
pFrame->pParent = pFrame->v->pDelFrame;
|
||||
pFrame->v->pDelFrame = pFrame;
|
||||
if( VdbeMemDynamic(pMem) ){
|
||||
vdbeMemClearExternAndSetNull(pMem);
|
||||
}else{
|
||||
pMem->flags = MEM_Null;
|
||||
}
|
||||
if( pMem->flags & MEM_RowSet ){
|
||||
sqlite3RowSetClear(pMem->u.pRowSet);
|
||||
}
|
||||
MemSetTypeFlag(pMem, MEM_Null);
|
||||
}
|
||||
void sqlite3ValueSetNull(sqlite3_value *p){
|
||||
sqlite3VdbeMemSetNull((Mem*)p);
|
||||
@ -608,14 +664,7 @@ void sqlite3VdbeMemSetZeroBlob(Mem *pMem, int n){
|
||||
if( n<0 ) n = 0;
|
||||
pMem->u.nZero = n;
|
||||
pMem->enc = SQLITE_UTF8;
|
||||
|
||||
#ifdef SQLITE_OMIT_INCRBLOB
|
||||
sqlite3VdbeMemGrow(pMem, n, 0);
|
||||
if( pMem->z ){
|
||||
pMem->n = n;
|
||||
memset(pMem->z, 0, n);
|
||||
}
|
||||
#endif
|
||||
pMem->z = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -624,7 +673,7 @@ void sqlite3VdbeMemSetZeroBlob(Mem *pMem, int n){
|
||||
** a 64-bit integer.
|
||||
*/
|
||||
static SQLITE_NOINLINE void vdbeReleaseAndSetInt64(Mem *pMem, i64 val){
|
||||
sqlite3VdbeMemReleaseExternal(pMem);
|
||||
sqlite3VdbeMemSetNull(pMem);
|
||||
pMem->u.i = val;
|
||||
pMem->flags = MEM_Int;
|
||||
}
|
||||
@ -648,11 +697,9 @@ void sqlite3VdbeMemSetInt64(Mem *pMem, i64 val){
|
||||
** manifest type REAL.
|
||||
*/
|
||||
void sqlite3VdbeMemSetDouble(Mem *pMem, double val){
|
||||
if( sqlite3IsNaN(val) ){
|
||||
sqlite3VdbeMemSetNull(pMem);
|
||||
}else{
|
||||
sqlite3VdbeMemRelease(pMem);
|
||||
pMem->r = val;
|
||||
sqlite3VdbeMemSetNull(pMem);
|
||||
if( !sqlite3IsNaN(val) ){
|
||||
pMem->u.r = val;
|
||||
pMem->flags = MEM_Real;
|
||||
}
|
||||
}
|
||||
@ -670,10 +717,11 @@ void sqlite3VdbeMemSetRowSet(Mem *pMem){
|
||||
pMem->zMalloc = sqlite3DbMallocRaw(db, 64);
|
||||
if( db->mallocFailed ){
|
||||
pMem->flags = MEM_Null;
|
||||
pMem->szMalloc = 0;
|
||||
}else{
|
||||
assert( pMem->zMalloc );
|
||||
pMem->u.pRowSet = sqlite3RowSetInit(db, pMem->zMalloc,
|
||||
sqlite3DbMallocSize(db, pMem->zMalloc));
|
||||
pMem->szMalloc = sqlite3DbMallocSize(db, pMem->zMalloc);
|
||||
pMem->u.pRowSet = sqlite3RowSetInit(db, pMem->zMalloc, pMem->szMalloc);
|
||||
assert( pMem->u.pRowSet!=0 );
|
||||
pMem->flags = MEM_RowSet;
|
||||
}
|
||||
@ -730,9 +778,9 @@ void sqlite3VdbeMemAboutToChange(Vdbe *pVdbe, Mem *pMem){
|
||||
*/
|
||||
void sqlite3VdbeMemShallowCopy(Mem *pTo, const Mem *pFrom, int srcType){
|
||||
assert( (pFrom->flags & MEM_RowSet)==0 );
|
||||
VdbeMemReleaseExtern(pTo);
|
||||
assert( pTo->db==pFrom->db );
|
||||
if( VdbeMemDynamic(pTo) ) vdbeMemClearExternAndSetNull(pTo);
|
||||
memcpy(pTo, pFrom, MEMCELLSIZE);
|
||||
pTo->xDel = 0;
|
||||
if( (pFrom->flags&MEM_Static)==0 ){
|
||||
pTo->flags &= ~(MEM_Dyn|MEM_Static|MEM_Ephem);
|
||||
assert( srcType==MEM_Ephem || srcType==MEM_Static );
|
||||
@ -748,11 +796,9 @@ int sqlite3VdbeMemCopy(Mem *pTo, const Mem *pFrom){
|
||||
int rc = SQLITE_OK;
|
||||
|
||||
assert( (pFrom->flags & MEM_RowSet)==0 );
|
||||
VdbeMemReleaseExtern(pTo);
|
||||
if( VdbeMemDynamic(pTo) ) vdbeMemClearExternAndSetNull(pTo);
|
||||
memcpy(pTo, pFrom, MEMCELLSIZE);
|
||||
pTo->flags &= ~MEM_Dyn;
|
||||
pTo->xDel = 0;
|
||||
|
||||
if( pTo->flags&(MEM_Str|MEM_Blob) ){
|
||||
if( 0==(pFrom->flags&MEM_Static) ){
|
||||
pTo->flags |= MEM_Ephem;
|
||||
@ -777,8 +823,7 @@ void sqlite3VdbeMemMove(Mem *pTo, Mem *pFrom){
|
||||
sqlite3VdbeMemRelease(pTo);
|
||||
memcpy(pTo, pFrom, sizeof(Mem));
|
||||
pFrom->flags = MEM_Null;
|
||||
pFrom->xDel = 0;
|
||||
pFrom->zMalloc = 0;
|
||||
pFrom->szMalloc = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -825,7 +870,8 @@ int sqlite3VdbeMemSetStr(
|
||||
if( nByte<0 ){
|
||||
assert( enc!=0 );
|
||||
if( enc==SQLITE_UTF8 ){
|
||||
for(nByte=0; nByte<=iLimit && z[nByte]; nByte++){}
|
||||
nByte = sqlite3Strlen30(z);
|
||||
if( nByte>iLimit ) nByte = iLimit+1;
|
||||
}else{
|
||||
for(nByte=0; nByte<=iLimit && (z[nByte] | z[nByte+1]); nByte+=2){}
|
||||
}
|
||||
@ -844,14 +890,14 @@ int sqlite3VdbeMemSetStr(
|
||||
if( nByte>iLimit ){
|
||||
return SQLITE_TOOBIG;
|
||||
}
|
||||
if( sqlite3VdbeMemGrow(pMem, nAlloc, 0) ){
|
||||
if( sqlite3VdbeMemClearAndResize(pMem, nAlloc) ){
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
memcpy(pMem->z, z, nAlloc);
|
||||
}else if( xDel==SQLITE_DYNAMIC ){
|
||||
sqlite3VdbeMemRelease(pMem);
|
||||
pMem->zMalloc = pMem->z = (char *)z;
|
||||
pMem->xDel = 0;
|
||||
pMem->szMalloc = sqlite3DbMallocSize(pMem->db, pMem->zMalloc);
|
||||
}else{
|
||||
sqlite3VdbeMemRelease(pMem);
|
||||
pMem->z = (char *)z;
|
||||
@ -883,8 +929,11 @@ int sqlite3VdbeMemSetStr(
|
||||
** key is true to get the key or false to get data. The result is written
|
||||
** into the pMem element.
|
||||
**
|
||||
** The pMem structure is assumed to be uninitialized. Any prior content
|
||||
** is overwritten without being freed.
|
||||
** The pMem object must have been initialized. This routine will use
|
||||
** pMem->zMalloc to hold the content from the btree, if possible. New
|
||||
** pMem->zMalloc space will be allocated if necessary. The calling routine
|
||||
** is responsible for making sure that the pMem object is eventually
|
||||
** destroyed.
|
||||
**
|
||||
** If this routine fails for any reason (malloc returns NULL or unable
|
||||
** to read from the disk) then the pMem is left in an inconsistent state.
|
||||
@ -901,6 +950,7 @@ int sqlite3VdbeMemFromBtree(
|
||||
int rc = SQLITE_OK; /* Return code */
|
||||
|
||||
assert( sqlite3BtreeCursorIsValid(pCur) );
|
||||
assert( !VdbeMemDynamic(pMem) );
|
||||
|
||||
/* Note: the calls to BtreeKeyFetch() and DataFetch() below assert()
|
||||
** that both the BtShared and database handle mutexes are held. */
|
||||
@ -913,23 +963,25 @@ int sqlite3VdbeMemFromBtree(
|
||||
assert( zData!=0 );
|
||||
|
||||
if( offset+amt<=available ){
|
||||
sqlite3VdbeMemRelease(pMem);
|
||||
pMem->z = &zData[offset];
|
||||
pMem->flags = MEM_Blob|MEM_Ephem;
|
||||
pMem->n = (int)amt;
|
||||
}else if( SQLITE_OK==(rc = sqlite3VdbeMemGrow(pMem, amt+2, 0)) ){
|
||||
if( key ){
|
||||
rc = sqlite3BtreeKey(pCur, offset, amt, pMem->z);
|
||||
}else{
|
||||
rc = sqlite3BtreeData(pCur, offset, amt, pMem->z);
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
pMem->z[amt] = 0;
|
||||
pMem->z[amt+1] = 0;
|
||||
pMem->flags = MEM_Blob|MEM_Term;
|
||||
pMem->n = (int)amt;
|
||||
}else{
|
||||
sqlite3VdbeMemRelease(pMem);
|
||||
}else{
|
||||
pMem->flags = MEM_Null;
|
||||
if( SQLITE_OK==(rc = sqlite3VdbeMemClearAndResize(pMem, amt+2)) ){
|
||||
if( key ){
|
||||
rc = sqlite3BtreeKey(pCur, offset, amt, pMem->z);
|
||||
}else{
|
||||
rc = sqlite3BtreeData(pCur, offset, amt, pMem->z);
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
pMem->z[amt] = 0;
|
||||
pMem->z[amt+1] = 0;
|
||||
pMem->flags = MEM_Blob|MEM_Term;
|
||||
pMem->n = (int)amt;
|
||||
}else{
|
||||
sqlite3VdbeMemRelease(pMem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1153,14 +1205,14 @@ static int valueFromExpr(
|
||||
&& pVal!=0
|
||||
){
|
||||
sqlite3VdbeMemNumerify(pVal);
|
||||
if( pVal->u.i==SMALLEST_INT64 ){
|
||||
pVal->flags &= ~MEM_Int;
|
||||
pVal->flags |= MEM_Real;
|
||||
pVal->r = (double)SMALLEST_INT64;
|
||||
if( pVal->flags & MEM_Real ){
|
||||
pVal->u.r = -pVal->u.r;
|
||||
}else if( pVal->u.i==SMALLEST_INT64 ){
|
||||
pVal->u.r = -(double)SMALLEST_INT64;
|
||||
MemSetTypeFlag(pVal, MEM_Real);
|
||||
}else{
|
||||
pVal->u.i = -pVal->u.i;
|
||||
}
|
||||
pVal->r = -pVal->r;
|
||||
sqlite3ValueApplyAffinity(pVal, affinity, enc);
|
||||
}
|
||||
}else if( op==TK_NULL ){
|
||||
@ -1468,7 +1520,7 @@ void sqlite3Stat4ProbeFree(UnpackedRecord *pRec){
|
||||
Mem *aMem = pRec->aMem;
|
||||
sqlite3 *db = aMem[0].db;
|
||||
for(i=0; i<nCol; i++){
|
||||
sqlite3DbFree(db, aMem[i].zMalloc);
|
||||
if( aMem[i].szMalloc ) sqlite3DbFree(db, aMem[i].zMalloc);
|
||||
}
|
||||
sqlite3KeyInfoUnref(pRec->pKeyInfo);
|
||||
sqlite3DbFree(db, pRec);
|
||||
|
@ -602,8 +602,11 @@ static int vdbePmaReadVarint(PmaReader *p, u64 *pnOut){
|
||||
static int vdbeSorterMapFile(SortSubtask *pTask, SorterFile *pFile, u8 **pp){
|
||||
int rc = SQLITE_OK;
|
||||
if( pFile->iEof<=(i64)(pTask->pSorter->db->nMaxSorterMmap) ){
|
||||
rc = sqlite3OsFetch(pFile->pFd, 0, (int)pFile->iEof, (void**)pp);
|
||||
testcase( rc!=SQLITE_OK );
|
||||
sqlite3_file *pFd = pFile->pFd;
|
||||
if( pFd->pMethods->iVersion>=3 ){
|
||||
rc = sqlite3OsFetch(pFd, 0, (int)pFile->iEof, (void**)pp);
|
||||
testcase( rc!=SQLITE_OK );
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
@ -758,7 +761,7 @@ static int vdbeSorterCompare(
|
||||
if( pKey2 ){
|
||||
sqlite3VdbeRecordUnpack(pTask->pSorter->pKeyInfo, nKey2, pKey2, r2);
|
||||
}
|
||||
return sqlite3VdbeRecordCompare(nKey1, pKey1, r2, 0);
|
||||
return sqlite3VdbeRecordCompare(nKey1, pKey1, r2);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1121,7 +1124,7 @@ void sqlite3VdbeSorterClose(sqlite3 *db, VdbeCursor *pCsr){
|
||||
** the specific VFS implementation.
|
||||
*/
|
||||
static void vdbeSorterExtendFile(sqlite3 *db, sqlite3_file *pFd, i64 nByte){
|
||||
if( nByte<=(i64)(db->nMaxSorterMmap) ){
|
||||
if( nByte<=(i64)(db->nMaxSorterMmap) && pFd->pMethods->iVersion>=3 ){
|
||||
int rc = sqlite3OsTruncate(pFd, nByte);
|
||||
if( rc==SQLITE_OK ){
|
||||
void *p = 0;
|
||||
@ -2458,7 +2461,7 @@ int sqlite3VdbeSorterRowkey(const VdbeCursor *pCsr, Mem *pOut){
|
||||
void *pKey; int nKey; /* Sorter key to copy into pOut */
|
||||
|
||||
pKey = vdbeSorterRowkey(pSorter, &nKey);
|
||||
if( sqlite3VdbeMemGrow(pOut, nKey, 0) ){
|
||||
if( sqlite3VdbeMemClearAndResize(pOut, nKey) ){
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
pOut->n = nKey;
|
||||
@ -2514,6 +2517,6 @@ int sqlite3VdbeSorterCompare(
|
||||
}
|
||||
}
|
||||
|
||||
*pRes = sqlite3VdbeRecordCompare(pVal->n, pVal->z, r2, 0);
|
||||
*pRes = sqlite3VdbeRecordCompare(pVal->n, pVal->z, r2);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
@ -127,7 +127,7 @@ char *sqlite3VdbeExpandSql(
|
||||
}else if( pVar->flags & MEM_Int ){
|
||||
sqlite3XPrintf(&out, 0, "%lld", pVar->u.i);
|
||||
}else if( pVar->flags & MEM_Real ){
|
||||
sqlite3XPrintf(&out, 0, "%!.15g", pVar->r);
|
||||
sqlite3XPrintf(&out, 0, "%!.15g", pVar->u.r);
|
||||
}else if( pVar->flags & MEM_Str ){
|
||||
int nOut; /* Number of bytes of the string text to include in output */
|
||||
#ifndef SQLITE_OMIT_UTF16
|
||||
|
@ -1913,7 +1913,7 @@ static void whereKeyStats(
|
||||
assert( pRec->nField>0 && iCol<pIdx->nSampleCol );
|
||||
do{
|
||||
iTest = (iMin+i)/2;
|
||||
res = sqlite3VdbeRecordCompare(aSample[iTest].n, aSample[iTest].p, pRec, 0);
|
||||
res = sqlite3VdbeRecordCompare(aSample[iTest].n, aSample[iTest].p, pRec);
|
||||
if( res<0 ){
|
||||
iMin = iTest+1;
|
||||
}else{
|
||||
@ -1928,16 +1928,16 @@ static void whereKeyStats(
|
||||
if( res==0 ){
|
||||
/* If (res==0) is true, then sample $i must be equal to pRec */
|
||||
assert( i<pIdx->nSample );
|
||||
assert( 0==sqlite3VdbeRecordCompare(aSample[i].n, aSample[i].p, pRec, 0)
|
||||
assert( 0==sqlite3VdbeRecordCompare(aSample[i].n, aSample[i].p, pRec)
|
||||
|| pParse->db->mallocFailed );
|
||||
}else{
|
||||
/* Otherwise, pRec must be smaller than sample $i and larger than
|
||||
** sample ($i-1). */
|
||||
assert( i==pIdx->nSample
|
||||
|| sqlite3VdbeRecordCompare(aSample[i].n, aSample[i].p, pRec, 0)>0
|
||||
|| sqlite3VdbeRecordCompare(aSample[i].n, aSample[i].p, pRec)>0
|
||||
|| pParse->db->mallocFailed );
|
||||
assert( i==0
|
||||
|| sqlite3VdbeRecordCompare(aSample[i-1].n, aSample[i-1].p, pRec, 0)<0
|
||||
|| sqlite3VdbeRecordCompare(aSample[i-1].n, aSample[i-1].p, pRec)<0
|
||||
|| pParse->db->mallocFailed );
|
||||
}
|
||||
#endif /* ifdef SQLITE_DEBUG */
|
||||
@ -4560,6 +4560,7 @@ static int indexMightHelpWithOrderBy(
|
||||
Expr *pExpr = sqlite3ExprSkipCollate(pOB->a[ii].pExpr);
|
||||
if( pExpr->op!=TK_COLUMN ) return 0;
|
||||
if( pExpr->iTable==iCursor ){
|
||||
if( pExpr->iColumn<0 ) return 1;
|
||||
for(jj=0; jj<pIndex->nKeyCol; jj++){
|
||||
if( pExpr->iColumn==pIndex->aiColumn[jj] ) return 1;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -481,5 +481,19 @@ do_execsql_test 6.0 {
|
||||
FROM abc;
|
||||
} {hardware hardware hardware}
|
||||
|
||||
# Here is a test for a query-planner problem reported on the SQLite
|
||||
# mailing list on 2014-09-18 by "Merike". Beginning with version 3.8.0,
|
||||
# a separate sort was being used rather than using the single-column
|
||||
# index. This was due to an oversight in the indexMightHelpWithOrderby()
|
||||
# routine in where.c.
|
||||
#
|
||||
do_execsql_test 7.0 {
|
||||
CREATE TABLE t7(a,b);
|
||||
CREATE INDEX t7a ON t7(a);
|
||||
CREATE INDEX t7ab ON t7(a,b);
|
||||
EXPLAIN QUERY PLAN
|
||||
SELECT * FROM t7 WHERE a=?1 ORDER BY rowid;
|
||||
} {~/ORDER BY/}
|
||||
|
||||
|
||||
finish_test
|
||||
|
@ -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
|
||||
|
45
test/sort5.test
Normal file
45
test/sort5.test
Normal file
@ -0,0 +1,45 @@
|
||||
# 2014 September 15.
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#***********************************************************************
|
||||
# This file implements regression tests for SQLite library.
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set testprefix sort5
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Verify that sorting works with a version 1 sqlite3_io_methods structure.
|
||||
#
|
||||
testvfs tvfs -iversion 1 -default true
|
||||
reset_db
|
||||
do_execsql_test 1.0 {
|
||||
PRAGMA mmap_size = 10000000;
|
||||
PRAGMA cache_size = 10;
|
||||
CREATE TABLE t1(a, b);
|
||||
} {0}
|
||||
|
||||
do_test 1.1 {
|
||||
execsql BEGIN
|
||||
for {set i 0} {$i < 2000} {incr i} {
|
||||
execsql { INSERT INTO t1 VALUES($i, randomblob(2000)) }
|
||||
}
|
||||
execsql COMMIT
|
||||
} {}
|
||||
|
||||
do_execsql_test 1.2 {
|
||||
CREATE INDEX i1 ON t1(b);
|
||||
}
|
||||
|
||||
db close
|
||||
tvfs delete
|
||||
finish_test
|
||||
|
@ -103,5 +103,50 @@ do_execsql_test 2.2 {
|
||||
LIMIT (SELECT a FROM t5)
|
||||
} {2 3 3 6 4 10}
|
||||
|
||||
############################################################################
|
||||
# Ticket http://www.sqlite.org/src/info/d11a6e908f (2014-09-20)
|
||||
# Query planner fault on three-way nested join with compound inner SELECT
|
||||
#
|
||||
do_execsql_test 3.0 {
|
||||
DROP TABLE IF EXISTS t1;
|
||||
DROP TABLE IF EXISTS t2;
|
||||
CREATE TABLE t1 (id INTEGER PRIMARY KEY, data TEXT);
|
||||
INSERT INTO t1(id,data) VALUES(9,'nine-a');
|
||||
INSERT INTO t1(id,data) VALUES(10,'ten-a');
|
||||
INSERT INTO t1(id,data) VALUES(11,'eleven-a');
|
||||
CREATE TABLE t2 (id INTEGER PRIMARY KEY, data TEXT);
|
||||
INSERT INTO t2(id,data) VALUES(9,'nine-b');
|
||||
INSERT INTO t2(id,data) VALUES(10,'ten-b');
|
||||
INSERT INTO t2(id,data) VALUES(11,'eleven-b');
|
||||
|
||||
SELECT id FROM (
|
||||
SELECT id,data FROM (
|
||||
SELECT * FROM t1 UNION ALL SELECT * FROM t2
|
||||
)
|
||||
WHERE id=10 ORDER BY data
|
||||
);
|
||||
} {10 10}
|
||||
do_execsql_test 3.1 {
|
||||
SELECT data FROM (
|
||||
SELECT 'dummy', data FROM (
|
||||
SELECT data FROM t1 UNION ALL SELECT data FROM t1
|
||||
) ORDER BY data
|
||||
);
|
||||
} {eleven-a eleven-a nine-a nine-a ten-a ten-a}
|
||||
do_execsql_test 3.2 {
|
||||
DROP TABLE IF EXISTS t3;
|
||||
DROP TABLE IF EXISTS t4;
|
||||
CREATE TABLE t3(id INTEGER, data TEXT);
|
||||
CREATE TABLE t4(id INTEGER, data TEXT);
|
||||
INSERT INTO t3 VALUES(4, 'a'),(2,'c');
|
||||
INSERT INTO t4 VALUES(3, 'b'),(1,'d');
|
||||
|
||||
SELECT data, id FROM (
|
||||
SELECT id, data FROM (
|
||||
SELECT * FROM t3 UNION ALL SELECT * FROM t4
|
||||
) ORDER BY data
|
||||
);
|
||||
} {a 4 b 3 c 2 d 1}
|
||||
|
||||
|
||||
finish_test
|
||||
|
257
test/userauth01.test
Normal file
257
test/userauth01.test
Normal file
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -510,7 +510,7 @@ static void decode_btree_page(
|
||||
|
||||
int main(int argc, char **argv){
|
||||
struct stat sbuf;
|
||||
unsigned char zPgSz[2];
|
||||
unsigned char zPgSz[4];
|
||||
if( argc<2 ){
|
||||
fprintf(stderr,"Usage: %s FILENAME ?PAGE? ...\n", argv[0]);
|
||||
exit(1);
|
||||
@ -522,9 +522,9 @@ int main(int argc, char **argv){
|
||||
}
|
||||
zPgSz[0] = 0;
|
||||
zPgSz[1] = 0;
|
||||
lseek(fd, 10, SEEK_SET);
|
||||
read(fd, zPgSz, 2);
|
||||
pagesize = zPgSz[0]*256 + zPgSz[1];
|
||||
lseek(fd, 8, SEEK_SET);
|
||||
read(fd, zPgSz, 4);
|
||||
pagesize = zPgSz[1]*65536 + zPgSz[2]*256 + zPgSz[3];
|
||||
if( pagesize==0 ) pagesize = 1024;
|
||||
printf("Pagesize: %d\n", pagesize);
|
||||
fstat(fd, &sbuf);
|
||||
|
Loading…
Reference in New Issue
Block a user