1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-08-01 06:27:03 +03:00

Merge latest trunk changes with this branch.

FossilOrigin-Name: 4b3651677e7132c4c45605bc1f216fc08ef31198
This commit is contained in:
dan
2015-01-01 18:03:49 +00:00
273 changed files with 24765 additions and 6748 deletions

View File

@ -3116,6 +3116,7 @@ static int fts3FilterMethod(
/* In case the cursor has been used before, clear it now. */
sqlite3_finalize(pCsr->pStmt);
sqlite3_free(pCsr->aDoclist);
sqlite3_free(pCsr->aMatchinfo);
sqlite3Fts3ExprFree(pCsr->pExpr);
memset(&pCursor[1], 0, sizeof(Fts3Cursor)-sizeof(sqlite3_vtab_cursor));
@ -3750,7 +3751,7 @@ static void hashDestroy(void *p){
*/
void sqlite3Fts3SimpleTokenizerModule(sqlite3_tokenizer_module const**ppModule);
void sqlite3Fts3PorterTokenizerModule(sqlite3_tokenizer_module const**ppModule);
#ifdef SQLITE_ENABLE_FTS4_UNICODE61
#ifndef SQLITE_DISABLE_FTS3_UNICODE
void sqlite3Fts3UnicodeTokenizer(sqlite3_tokenizer_module const**ppModule);
#endif
#ifdef SQLITE_ENABLE_ICU
@ -3768,7 +3769,7 @@ int sqlite3Fts3Init(sqlite3 *db){
Fts3Hash *pHash = 0;
const sqlite3_tokenizer_module *pSimple = 0;
const sqlite3_tokenizer_module *pPorter = 0;
#ifdef SQLITE_ENABLE_FTS4_UNICODE61
#ifndef SQLITE_DISABLE_FTS3_UNICODE
const sqlite3_tokenizer_module *pUnicode = 0;
#endif
@ -3777,7 +3778,7 @@ int sqlite3Fts3Init(sqlite3 *db){
sqlite3Fts3IcuTokenizerModule(&pIcu);
#endif
#ifdef SQLITE_ENABLE_FTS4_UNICODE61
#ifndef SQLITE_DISABLE_FTS3_UNICODE
sqlite3Fts3UnicodeTokenizer(&pUnicode);
#endif
@ -3805,7 +3806,7 @@ int sqlite3Fts3Init(sqlite3 *db){
if( sqlite3Fts3HashInsert(pHash, "simple", 7, (void *)pSimple)
|| sqlite3Fts3HashInsert(pHash, "porter", 7, (void *)pPorter)
#ifdef SQLITE_ENABLE_FTS4_UNICODE61
#ifndef SQLITE_DISABLE_FTS3_UNICODE
|| sqlite3Fts3HashInsert(pHash, "unicode61", 10, (void *)pUnicode)
#endif
#ifdef SQLITE_ENABLE_ICU
@ -4426,7 +4427,7 @@ static int fts3EvalIncrPhraseNext(
bMaxSet = 1;
}
}
assert( rc!=SQLITE_OK || a[p->nToken-1].bIgnore==0 );
assert( rc!=SQLITE_OK || (p->nToken>=1 && a[p->nToken-1].bIgnore==0) );
assert( rc!=SQLITE_OK || bMaxSet );
/* Keep advancing iterators until they all point to the same document */

View File

@ -585,7 +585,7 @@ int sqlite3Fts3MsrIncrRestart(Fts3MultiSegReader *pCsr);
int sqlite3Fts3InitTok(sqlite3*, Fts3Hash *);
/* fts3_unicode2.c (functions generated by parsing unicode text files) */
#ifdef SQLITE_ENABLE_FTS4_UNICODE61
#ifndef SQLITE_DISABLE_FTS3_UNICODE
int sqlite3FtsUnicodeFold(int, int);
int sqlite3FtsUnicodeIsalnum(int);
int sqlite3FtsUnicodeIsdiacritic(int);

View File

@ -190,7 +190,7 @@ static int getNextToken(
/* Set variable i to the maximum number of bytes of input to tokenize. */
for(i=0; i<n; i++){
if( sqlite3_fts3_enable_parentheses && (z[i]=='(' || z[i]==')') ) break;
if( z[i]=='*' || z[i]=='"' ) break;
if( z[i]=='"' ) break;
}
*pnConsumed = i;

View File

@ -183,7 +183,7 @@ static int isVowel(const char *z){
** by a consonant.
**
** In this routine z[] is in reverse order. So we are really looking
** for an instance of of a consonant followed by a vowel.
** for an instance of a consonant followed by a vowel.
*/
static int m_gt_0(const char *z){
while( isVowel(z) ){ z++; }

View File

@ -13,7 +13,7 @@
** Implementation of the "unicode" full-text-search tokenizer.
*/
#ifdef SQLITE_ENABLE_FTS4_UNICODE61
#ifndef SQLITE_DISABLE_FTS3_UNICODE
#include "fts3Int.h"
#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3)
@ -231,7 +231,7 @@ static int unicodeCreate(
for(i=0; rc==SQLITE_OK && i<nArg; i++){
const char *z = azArg[i];
int n = strlen(z);
int n = (int)strlen(z);
if( n==19 && memcmp("remove_diacritics=1", z, 19)==0 ){
pNew->bRemoveDiacritic = 1;
@ -318,7 +318,7 @@ static int unicodeNext(
){
unicode_cursor *pCsr = (unicode_cursor *)pC;
unicode_tokenizer *p = ((unicode_tokenizer *)pCsr->base.pTokenizer);
int iCode;
int iCode = 0;
char *zOut;
const unsigned char *z = &pCsr->aInput[pCsr->iOff];
const unsigned char *zStart = z;
@ -363,11 +363,11 @@ static int unicodeNext(
);
/* Set the output variables and return. */
pCsr->iOff = (z - pCsr->aInput);
pCsr->iOff = (int)(z - pCsr->aInput);
*paToken = pCsr->zToken;
*pnToken = zOut - pCsr->zToken;
*piStart = (zStart - pCsr->aInput);
*piEnd = (zEnd - pCsr->aInput);
*pnToken = (int)(zOut - pCsr->zToken);
*piStart = (int)(zStart - pCsr->aInput);
*piEnd = (int)(zEnd - pCsr->aInput);
*piPos = pCsr->iToken++;
return SQLITE_OK;
}
@ -390,4 +390,4 @@ void sqlite3Fts3UnicodeTokenizer(sqlite3_tokenizer_module const **ppModule){
}
#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) */
#endif /* ifndef SQLITE_ENABLE_FTS4_UNICODE61 */
#endif /* ifndef SQLITE_DISABLE_FTS3_UNICODE */

View File

@ -15,7 +15,7 @@
** DO NOT EDIT THIS MACHINE GENERATED FILE.
*/
#if defined(SQLITE_ENABLE_FTS4_UNICODE61)
#ifndef SQLITE_DISABLE_FTS3_UNICODE
#if defined(SQLITE_ENABLE_FTS3) || defined(SQLITE_ENABLE_FTS4)
#include <assert.h>
@ -39,7 +39,7 @@ int sqlite3FtsUnicodeIsalnum(int c){
** C. It is not possible to represent a range larger than 1023 codepoints
** using this format.
*/
const static unsigned int aEntry[] = {
static const unsigned int aEntry[] = {
0x00000030, 0x0000E807, 0x00016C06, 0x0001EC2F, 0x0002AC07,
0x0002D001, 0x0002D803, 0x0002EC01, 0x0002FC01, 0x00035C01,
0x0003DC01, 0x000B0804, 0x000B480E, 0x000B9407, 0x000BB401,
@ -131,7 +131,7 @@ int sqlite3FtsUnicodeIsalnum(int c){
return ( (aAscii[c >> 5] & (1 << (c & 0x001F)))==0 );
}else if( c<(1<<22) ){
unsigned int key = (((unsigned int)c)<<10) | 0x000003FF;
int iRes;
int iRes = 0;
int iHi = sizeof(aEntry)/sizeof(aEntry[0]) - 1;
int iLo = 0;
while( iHi>=iLo ){
@ -202,7 +202,7 @@ static int remove_diacritic(int c){
}
assert( key>=aDia[iRes] );
return ((c > (aDia[iRes]>>3) + (aDia[iRes]&0x07)) ? c : (int)aChar[iRes]);
};
}
/*
@ -362,4 +362,4 @@ int sqlite3FtsUnicodeFold(int c, int bRemoveDiacritic){
return ret;
}
#endif /* defined(SQLITE_ENABLE_FTS3) || defined(SQLITE_ENABLE_FTS4) */
#endif /* !defined(SQLITE_ENABLE_FTS4_UNICODE61) */
#endif /* !defined(SQLITE_DISABLE_FTS3_UNICODE) */

View File

@ -376,7 +376,7 @@ static void showSegmentStats(sqlite3 *db, const char *zTab){
sqlite3_finalize(pStmt);
nLeaf = nSeg - nIdx;
printf("Leaf segments larger than %5d bytes.... %9d %5.2f%%\n",
pgsz-45, n, n*100.0/nLeaf);
pgsz-45, n, nLeaf>0 ? n*100.0/nLeaf : 0.0);
pStmt = prepare(db, "SELECT max(level%%1024) FROM '%q_segdir'", zTab);
mxLevel = 0;
@ -554,7 +554,7 @@ static void decodeSegment(
sqlite3_int64 n;
sqlite3_int64 iDocsz;
int iHeight;
int i = 0;
sqlite3_int64 i = 0;
int cnt = 0;
char zTerm[1000];
@ -576,12 +576,12 @@ static void decodeSegment(
fprintf(stderr, "term to long\n");
exit(1);
}
memcpy(zTerm+iPrefix, aData+i, nTerm);
memcpy(zTerm+iPrefix, aData+i, (size_t)nTerm);
zTerm[iPrefix+nTerm] = 0;
i += nTerm;
if( iHeight==0 ){
i += getVarint(aData+i, &iDocsz);
printf("term: %-25s doclist %7lld bytes offset %d\n", zTerm, iDocsz, i);
printf("term: %-25s doclist %7lld bytes offset %lld\n", zTerm, iDocsz, i);
i += iDocsz;
}else{
printf("term: %-25s child %lld\n", zTerm, ++iChild);
@ -749,18 +749,19 @@ static void decodeDoclist(
*/
static void showDoclist(sqlite3 *db, const char *zTab){
const unsigned char *aData;
sqlite3_int64 offset, nData;
sqlite3_int64 offset;
int nData;
sqlite3_stmt *pStmt;
offset = atoi64(azExtra[1]);
nData = atoi64(azExtra[2]);
nData = atoi(azExtra[2]);
pStmt = prepareToGetSegment(db, zTab, azExtra[0]);
if( sqlite3_step(pStmt)!=SQLITE_ROW ){
sqlite3_finalize(pStmt);
return;
}
aData = sqlite3_column_blob(pStmt, 0);
printf("Doclist at %s offset %lld of size %lld bytes:\n",
printf("Doclist at %s offset %lld of size %d bytes:\n",
azExtra[0], offset, nData);
if( findOption("raw", 0, 0)!=0 ){
printBlob(aData+offset, nData);

View File

@ -160,7 +160,7 @@ proc print_rd {map} {
}
assert( key>=aDia[iRes] );
return ((c > (aDia[iRes]>>3) + (aDia[iRes]&0x07)) ? c : (int)aChar[iRes]);}
puts "\};"
puts "\}"
}
proc print_isdiacritic {zFunc map} {
@ -298,7 +298,7 @@ proc an_print_range_array {lRange} {
** using this format.
*/
}]
puts -nonewline " const static unsigned int aEntry\[\] = \{"
puts -nonewline " static const unsigned int aEntry\[\] = \{"
set i 0
foreach range $lRange {
foreach {iFirst nRange} $range {}
@ -349,7 +349,7 @@ proc print_isalnum {zFunc lRange} {
return ( (aAscii[c >> 5] & (1 << (c & 0x001F)))==0 );
}else if( c<(1<<22) ){
unsigned int key = (((unsigned int)c)<<10) | 0x000003FF;
int iRes;
int iRes = 0;
int iHi = sizeof(aEntry)/sizeof(aEntry[0]) - 1;
int iLo = 0;
while( iHi>=iLo ){
@ -735,7 +735,7 @@ proc print_fileheader {} {
if {$::generate_fts5_code} {
puts "#if defined(SQLITE_ENABLE_FTS5)"
} else {
puts "#if defined(SQLITE_ENABLE_FTS4_UNICODE61)"
puts "#ifndef SQLITE_DISABLE_FTS3_UNICODE"
puts "#if defined(SQLITE_ENABLE_FTS3) || defined(SQLITE_ENABLE_FTS4)"
}
puts ""
@ -831,5 +831,5 @@ if {$generate_fts5_code} {
puts "#endif /* defined(SQLITE_ENABLE_FTS5) */"
} else {
puts "#endif /* defined(SQLITE_ENABLE_FTS3) || defined(SQLITE_ENABLE_FTS4) */"
puts "#endif /* !defined(SQLITE_ENABLE_FTS4_UNICODE61) */"
puts "#endif /* !defined(SQLITE_DISABLE_FTS3_UNICODE) */"
}

122
ext/misc/eval.c Normal file
View File

@ -0,0 +1,122 @@
/*
** 2014-11-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 SQLite extension implements SQL function eval() which runs
** SQL statements recursively.
*/
#include "sqlite3ext.h"
SQLITE_EXTENSION_INIT1
#include <string.h>
/*
** Structure used to accumulate the output
*/
struct EvalResult {
char *z; /* Accumulated output */
const char *zSep; /* Separator */
int szSep; /* Size of the separator string */
sqlite3_int64 nAlloc; /* Number of bytes allocated for z[] */
sqlite3_int64 nUsed; /* Number of bytes of z[] actually used */
};
/*
** Callback from sqlite_exec() for the eval() function.
*/
static int callback(void *pCtx, int argc, char **argv, char **colnames){
struct EvalResult *p = (struct EvalResult*)pCtx;
int i;
for(i=0; i<argc; i++){
const char *z = argv[i] ? argv[i] : "";
size_t sz = strlen(z);
if( (sqlite3_int64)sz+p->nUsed+p->szSep+1 > p->nAlloc ){
char *zNew;
p->nAlloc = p->nAlloc*2 + sz + p->szSep + 1;
/* Using sqlite3_realloc64() would be better, but it is a recent
** addition and will cause a segfault if loaded by an older version
** of SQLite. */
zNew = p->nAlloc<=0x7fffffff ? sqlite3_realloc(p->z, (int)p->nAlloc) : 0;
if( zNew==0 ){
sqlite3_free(p->z);
memset(p, 0, sizeof(*p));
return 1;
}
p->z = zNew;
}
if( p->nUsed>0 ){
memcpy(&p->z[p->nUsed], p->zSep, p->szSep);
p->nUsed += p->szSep;
}
memcpy(&p->z[p->nUsed], z, sz);
p->nUsed += sz;
}
return 0;
}
/*
** Implementation of the eval(X) and eval(X,Y) SQL functions.
**
** Evaluate the SQL text in X. Return the results, using string
** Y as the separator. If Y is omitted, use a single space character.
*/
static void sqlEvalFunc(
sqlite3_context *context,
int argc,
sqlite3_value **argv
){
const char *zSql;
sqlite3 *db;
char *zErr = 0;
int rc;
struct EvalResult x;
memset(&x, 0, sizeof(x));
x.zSep = " ";
zSql = (const char*)sqlite3_value_text(argv[0]);
if( zSql==0 ) return;
if( argc>1 ){
x.zSep = (const char*)sqlite3_value_text(argv[1]);
if( x.zSep==0 ) return;
}
x.szSep = (int)strlen(x.zSep);
db = sqlite3_context_db_handle(context);
rc = sqlite3_exec(db, zSql, callback, &x, &zErr);
if( rc!=SQLITE_OK ){
sqlite3_result_error(context, zErr, -1);
sqlite3_free(zErr);
}else if( x.zSep==0 ){
sqlite3_result_error_nomem(context);
sqlite3_free(x.z);
}else{
sqlite3_result_text(context, x.z, (int)x.nUsed, sqlite3_free);
}
}
#ifdef _WIN32
__declspec(dllexport)
#endif
int sqlite3_eval_init(
sqlite3 *db,
char **pzErrMsg,
const sqlite3_api_routines *pApi
){
int rc = SQLITE_OK;
SQLITE_EXTENSION_INIT2(pApi);
(void)pzErrMsg; /* Unused parameter */
rc = sqlite3_create_function(db, "eval", 1, SQLITE_UTF8, 0,
sqlEvalFunc, 0, 0);
if( rc==SQLITE_OK ){
rc = sqlite3_create_function(db, "eval", 2, SQLITE_UTF8, 0,
sqlEvalFunc, 0, 0);
}
return rc;
}

View File

@ -61,7 +61,6 @@ static void writefileFunc(
){
FILE *out;
const char *z;
int n;
sqlite3_int64 rc;
const char *zFile;
@ -71,11 +70,9 @@ static void writefileFunc(
if( out==0 ) return;
z = (const char*)sqlite3_value_blob(argv[1]);
if( z==0 ){
n = 0;
rc = 0;
}else{
n = sqlite3_value_bytes(argv[1]);
rc = fwrite(z, 1, n, out);
rc = fwrite(z, 1, sqlite3_value_bytes(argv[1]), out);
}
fclose(out);
sqlite3_result_int64(context, rc);

103
ext/misc/showauth.c Normal file
View 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;
}

View File

@ -1893,7 +1893,7 @@ static int spellfix1Init(
char **pzErr
){
spellfix1_vtab *pNew = 0;
const char *zModule = argv[0];
/* const char *zModule = argv[0]; // not used */
const char *zDbName = argv[1];
const char *zTableName = argv[2];
int nDbName;
@ -1947,7 +1947,7 @@ static int spellfix1Init(
spellfix1DbExec(&rc, db,
"CREATE INDEX IF NOT EXISTS \"%w\".\"%w_vocab_index_langid_k2\" "
"ON \"%w_vocab\"(langid,k2);",
zDbName, zModule, zTableName
zDbName, zTableName, zTableName
);
}
for(i=3; rc==SQLITE_OK && i<argc; i++){
@ -2736,12 +2736,22 @@ static int spellfix1Update(
return SQLITE_NOMEM;
}
if( sqlite3_value_type(argv[0])==SQLITE_NULL ){
spellfix1DbExec(&rc, db,
"INSERT INTO \"%w\".\"%w_vocab\"(rank,langid,word,k1,k2) "
"VALUES(%d,%d,%Q,%Q,%Q)",
p->zDbName, p->zTableName,
iRank, iLang, zWord, zK1, zK2
);
if( sqlite3_value_type(argv[1])==SQLITE_NULL ){
spellfix1DbExec(&rc, db,
"INSERT INTO \"%w\".\"%w_vocab\"(rank,langid,word,k1,k2) "
"VALUES(%d,%d,%Q,%Q,%Q)",
p->zDbName, p->zTableName,
iRank, iLang, zWord, zK1, zK2
);
}else{
newRowid = sqlite3_value_int64(argv[1]);
spellfix1DbExec(&rc, db,
"INSERT INTO \"%w\".\"%w_vocab\"(id,rank,langid,word,k1,k2) "
"VALUES(%lld,%d,%d,%Q,%Q,%Q)",
p->zDbName, p->zTableName,
newRowid, iRank, iLang, zWord, zK1, zK2
);
}
*pRowid = sqlite3_last_insert_rowid(db);
}else{
rowid = sqlite3_value_int64(argv[0]);

View File

@ -1533,9 +1533,13 @@ static int rtreeFilter(
rtreeReference(pRtree);
/* Reset the cursor to the same state as rtreeOpen() leaves it in. */
freeCursorConstraints(pCsr);
pCsr->iStrategy = idxNum;
sqlite3_free(pCsr->aPoint);
memset(pCsr, 0, sizeof(RtreeCursor));
pCsr->base.pVtab = (sqlite3_vtab*)pRtree;
pCsr->iStrategy = idxNum;
if( idxNum==1 ){
/* Special case - lookup by rowid. */
RtreeNode *pLeaf; /* Leaf on which the required cell resides */

View File

@ -33,6 +33,7 @@ set testprefix rtree1
# rtree-8.*: Test constrained scans of r-tree data.
#
# rtree-12.*: Test that on-conflict clauses are supported.
# rtree-13.*: Test that bug [d2889096e7bdeac6d] has been fixed.
#
ifcapable !rtree {
@ -513,4 +514,25 @@ foreach {tn sql_template testdata} {
db close
}
}
#-------------------------------------------------------------------------
# Test that bug [d2889096e7bdeac6d] has been fixed.
#
reset_db
do_execsql_test 13.1 {
CREATE VIRTUAL TABLE t9 USING rtree(id, xmin, xmax);
INSERT INTO t9 VALUES(1,0,0);
INSERT INTO t9 VALUES(2,0,0);
SELECT * FROM t9 WHERE id IN (1, 2);
} {1 0.0 0.0 2 0.0 0.0}
do_execsql_test 13.2 {
WITH r(x) AS (
SELECT 1 UNION ALL
SELECT 2 UNION ALL
SELECT 3
)
SELECT * FROM r CROSS JOIN t9 WHERE id=x;
} {1 1 0.0 0.0 2 2 0.0 0.0}
finish_test

View File

@ -102,7 +102,7 @@ do_eqp_test rtree6.2.4.2 {
SELECT * FROM t1,t2 WHERE v=10 and x1<10 and x2>10
} {
0 0 0 {SCAN TABLE t1 VIRTUAL TABLE INDEX 2:C0E1}
0 1 1 {SEARCH TABLE t2 USING AUTOMATIC COVERING INDEX (v=?)}
0 1 1 {SEARCH TABLE t2 USING AUTOMATIC PARTIAL COVERING INDEX (v=?)}
}
do_eqp_test rtree6.2.5 {

81
ext/rtree/rtreeF.test Normal file
View File

@ -0,0 +1,81 @@
# 2014-08-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 file contains tests for the r-tree module.
#
# This file contains test cases for the ticket
# [369d57fb8e5ccdff06f197a37147a88f9de95cda] (2014-08-21)
#
# The following SQL causes an assertion fault while running
# sqlite3_prepare() on the DELETE statement:
#
# CREATE TABLE t1(x);
# CREATE TABLE t2(y);
# CREATE VIRTUAL TABLE t3 USING rtree(a,b,c);
# CREATE TRIGGER t2del AFTER DELETE ON t2 WHEN (SELECT 1 from t1) BEGIN
# DELETE FROM t3 WHERE a=old.y;
# END;
# DELETE FROM t2 WHERE y=1;
#
if {![info exists testdir]} {
set testdir [file join [file dirname [info script]] .. .. test]
}
source $testdir/tester.tcl
ifcapable !rtree { finish_test ; return }
do_execsql_test rtreeF-1.1 {
CREATE TABLE t1(x);
CREATE TABLE t2(y);
CREATE VIRTUAL TABLE t3 USING rtree(a,b,c);
CREATE TRIGGER t2dwl AFTER DELETE ON t2 WHEN (SELECT 1 from t1) BEGIN
DELETE FROM t3 WHERE a=old.y;
END;
INSERT INTO t1(x) VALUES(999);
INSERT INTO t2(y) VALUES(1),(2),(3),(4),(5);
INSERT INTO t3(a,b,c) VALUES(1,2,3),(2,3,4),(3,4,5),(4,5,6),(5,6,7);
SELECT a FROM t3 ORDER BY a;
SELECT '|';
SELECT y FROM t2 ORDER BY y;
} {1 2 3 4 5 | 1 2 3 4 5}
do_execsql_test rtreeF-1.2 {
DELETE FROM t2 WHERE y=3;
SELECT a FROM t3 ORDER BY a;
SELECT '|';
SELECT y FROM t2 ORDER BY y;
} {1 2 4 5 | 1 2 4 5}
do_execsql_test rtreeF-1.3 {
DELETE FROM t1;
DELETE FROM t2 WHERE y=5;
SELECT a FROM t3 ORDER BY a;
SELECT '|';
SELECT y FROM t2 ORDER BY y;
} {1 2 4 5 | 1 2 4}
do_execsql_test rtreeF-1.4 {
INSERT INTO t1 DEFAULT VALUES;
DELETE FROM t2 WHERE y=5;
SELECT a FROM t3 ORDER BY a;
SELECT '|';
SELECT y FROM t2 ORDER BY y;
} {1 2 4 5 | 1 2 4}
do_execsql_test rtreeF-1.5 {
DELETE FROM t2 WHERE y=2;
SELECT a FROM t3 ORDER BY a;
SELECT '|';
SELECT y FROM t2 ORDER BY y;
} {1 4 5 | 1 4}
finish_test

View 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
View 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
View 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 */