/ Changes On Branch user-auth
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Changes In Branch user-auth Excluding Merge-Ins

This is equivalent to a diff from ad7063aa1a to b149ef5c63

2014-09-11
17:27
Add the SQLITE_USER_AUTHENTICATION extension to the trunk. This extension is disabled by default. Special compilation procedures are need to enable it. (check-in: 65884d4f81 user: drh tags: trunk)
17:14
Clean up some #includes in the extension API implementation. (Closed-Leaf check-in: b149ef5c63 user: drh tags: user-auth)
16:36
Suppress the potential schema error that occurs when a non-user-auth SQLite library tries to parse the sqlite_user table definition in a user-auth database. (check-in: cda33c1ef3 user: drh tags: user-auth)
2014-09-09
17:27
Add new APIs that take 64-bit length parameters: sqlite3_malloc64(), sqlite3_realloc64(), sqlite3_bind_blob64(), sqlite3_bind_texte64(), sqlite3_result_blob64(), and sqlite3_result_texte64(). Internal memory allocation routines also now use 64-bit unsigned length parameters for safety. Also add the sqlite3_msize() interface. Fix the sqlite3_get_table() to use sqlite3_realloc64() to avoid a integer overflow problem. (check-in: 94954850cf user: drh tags: 64-bit-lengths)
14:47
Non-working preliminary implementation attempts on user authentication. (check-in: 8440f093ba user: drh tags: user-auth)
2014-09-08
15:04
Merge support for large files on Android from trunk. (check-in: c2885c6bb2 user: drh tags: sessions)
2014-09-06
17:06
Fixes to os_unix.c to support database (and other) files larger than 2GiB on Android. (check-in: ad7063aa1a user: dan tags: trunk)
16:52
Merge latest trunk changes with this branch. (Closed-Leaf check-in: 9dca7ce557 user: dan tags: android-large-filles)
16:39
Fix typos in comments. No code changes. (check-in: e62aab5e92 user: peter.d.reid tags: trunk)

Added ext/userauth/sqlite3userauth.h.

























































































1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
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 */

Added ext/userauth/user-auth.txt.





































































































































































1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
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.

Added ext/userauth/userauth.c.




































































































































































































































































































































































1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
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 */

Changes to main.mk.

42
43
44
45
46
47
48
49

50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70

71
72
73
74
75
76
77
42
43
44
45
46
47
48

49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69

70
71
72
73
74
75
76
77







-
+




















-
+







# build the SQLite library and testing tools.
################################################################################

# This is how we compile
#
TCCX =  $(TCC) $(OPTS) -I. -I$(TOP)/src -I$(TOP) 
TCCX += -I$(TOP)/ext/rtree -I$(TOP)/ext/icu -I$(TOP)/ext/fts3
TCCX += -I$(TOP)/ext/async
TCCX += -I$(TOP)/ext/async -I$(TOP)/ext/userauth

# Object files for the SQLite library.
#
LIBOBJ+= vdbe.o parse.o \
         alter.o analyze.o attach.o auth.o \
         backup.o bitvec.o btmutex.o btree.o build.o \
         callback.o complete.o ctime.o date.o delete.o expr.o fault.o fkey.o \
         fts3.o fts3_aux.o fts3_expr.o fts3_hash.o fts3_icu.o fts3_porter.o \
         fts3_snippet.o fts3_tokenizer.o fts3_tokenizer1.o \
         fts3_tokenize_vtab.o \
	 fts3_unicode.o fts3_unicode2.o \
         fts3_write.o func.o global.o hash.o \
         icu.o insert.o journal.o legacy.o loadext.o \
         main.o malloc.o mem0.o mem1.o mem2.o mem3.o mem5.o \
         memjournal.o \
         mutex.o mutex_noop.o mutex_unix.o mutex_w32.o \
         notify.o opcodes.o os.o os_unix.o os_win.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



# All of the source code files.
#
210
211
212
213
214
215
216
217



218
219
220
221
222
223
224
210
211
212
213
214
215
216

217
218
219
220
221
222
223
224
225
226







-
+
+
+







SRC += \
  $(TOP)/ext/icu/sqliteicu.h \
  $(TOP)/ext/icu/icu.c
SRC += \
  $(TOP)/ext/rtree/sqlite3rtree.h \
  $(TOP)/ext/rtree/rtree.h \
  $(TOP)/ext/rtree/rtree.c

SRC += \
  $(TOP)/ext/userauth/userauth.c \
  $(TOP)/ext/userauth/sqlite3userauth.h

# Generated source code files
#
SRC += \
  keywordhash.h \
  opcodes.c \
  opcodes.h \
373
374
375
376
377
378
379


380
381
382
383
384
385
386
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390







+
+







  $(TOP)/ext/fts3/fts3Int.h \
  $(TOP)/ext/fts3/fts3_hash.h \
  $(TOP)/ext/fts3/fts3_tokenizer.h
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.
#
all:	sqlite3.h libsqlite3.a sqlite3$(EXE)

libsqlite3.a:	$(LIBOBJ)
553
554
555
556
557
558
559



560
561
562
563
564
565
566
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573







+
+
+







	$(TCCX) -DSQLITE_CORE -c $(TOP)/ext/fts3/fts3_unicode2.c

fts3_write.o:	$(TOP)/ext/fts3/fts3_write.c $(HDR) $(EXTHDR)
	$(TCCX) -DSQLITE_CORE -c $(TOP)/ext/fts3/fts3_write.c

rtree.o:	$(TOP)/ext/rtree/rtree.c $(HDR) $(EXTHDR)
	$(TCCX) -DSQLITE_CORE -c $(TOP)/ext/rtree/rtree.c

userauth.o:	$(TOP)/ext/userauth/userauth.c $(HDR) $(EXTHDR)
	$(TCCX) -DSQLITE_CORE -c $(TOP)/ext/userauth/userauth.c


# Rules for building test programs and for running tests
#
tclsqlite3:	$(TOP)/src/tclsqlite.c libsqlite3.a
	$(TCCX) $(TCL_FLAGS) -DTCLSH=1 -o tclsqlite3 \
		$(TOP)/src/tclsqlite.c libsqlite3.a $(LIBTCL) $(THREADLIB)

Changes to src/attach.c.

203
204
205
206
207
208
209









210
211
212
213
214
215
216
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225







+
+
+
+
+
+
+
+
+







  ** we found it.
  */
  if( rc==SQLITE_OK ){
    sqlite3BtreeEnterAll(db);
    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 );
    if( db->aDb[iDb].pBt ){
      sqlite3BtreeClose(db->aDb[iDb].pBt);
      db->aDb[iDb].pBt = 0;
      db->aDb[iDb].pSchema = 0;

Changes to src/auth.c.

69
70
71
72
73
74
75
76

77
78
79
80
81
82
83
69
70
71
72
73
74
75

76
77
78
79
80
81
82
83







-
+







*/
int sqlite3_set_authorizer(
  sqlite3 *db,
  int (*xAuth)(void*,int,const char*,const char*,const char*,const char*),
  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);
  return SQLITE_OK;
}

/*
104
105
106
107
108
109
110
111





112
113
114
115
116
117
118
104
105
106
107
108
109
110

111
112
113
114
115
116
117
118
119
120
121
122







-
+
+
+
+
+







  const char *zCol,               /* Column name */
  int iDb                         /* Index of containing database. */
){
  sqlite3 *db = pParse->db;       /* Database handle */
  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);
    }else{
      sqlite3ErrorMsg(pParse, "access to %s.%s is prohibited", zTab, zCol);
    }
    pParse->rc = SQLITE_AUTH;
204
205
206
207
208
209
210
211





212
213
214
215
216
217
218
208
209
210
211
212
213
214

215
216
217
218
219
220
221
222
223
224
225
226







-
+
+
+
+
+







  if( db->init.busy || IN_DECLARE_VTAB ){
    return SQLITE_OK;
  }

  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;
  }else if( rc!=SQLITE_OK && rc!=SQLITE_IGNORE ){
    rc = SQLITE_DENY;
    sqliteAuthBadReturnCode(pParse);
  }

Changes to src/build.c.

151
152
153
154
155
156
157











158
159
160
161
162
163
164
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175







+
+
+
+
+
+
+
+
+
+
+







  */
  v = sqlite3GetVdbe(pParse);
  assert( !pParse->isMultiWrite 
       || sqlite3VdbeAssertMayAbort(v, pParse->mayAbort));
  if( v ){
    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
    ** transaction on each used database and to verify the schema cookie
    ** on each used database.
    */
267
268
269
270
271
272
273










274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291







292
293
294
295
296
297
298
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326







+
+
+
+
+
+
+
+
+
+


















+
+
+
+
+
+
+







  sqlite3RunParser(pParse, zSql, &zErrMsg);
  sqlite3DbFree(db, zErrMsg);
  sqlite3DbFree(db, zSql);
  memcpy(&pParse->nVar, saveBuf, SAVE_SZ);
  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
** database containing the table.  Return NULL if not found.
**
** If zDatabase is 0, all databases are searched for the table and the
** first matching table is returned.  (No checking for duplicate table
** names is done.)  The search order is TEMP first, then MAIN, then any
** auxiliary databases added using the ATTACH command.
**
** See also sqlite3LocateTable().
*/
Table *sqlite3FindTable(sqlite3 *db, const char *zName, const char *zDatabase){
  Table *p = 0;
  int i;
  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;
    assert( sqlite3SchemaMutexHeld(db, j, 0) );
    p = sqlite3HashFind(&db->aDb[j].pSchema->tblHash, zName);
    if( p ) break;
  }
329
330
331
332
333
334
335






336
337
338
339
340
341
342
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376







+
+
+
+
+
+







    if( zDbase ){
      sqlite3ErrorMsg(pParse, "%s: %s.%s", zMsg, zDbase, zName);
    }else{
      sqlite3ErrorMsg(pParse, "%s: %s", zMsg, zName);
    }
    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;
}

/*
** Locate the table identified by *p.
**
** This is a wrapper around sqlite3LocateTable(). The difference between
2048
2049
2050
2051
2052
2053
2054
2055

2056
2057
2058
2059
2060
2061
2062
2082
2083
2084
2085
2086
2087
2088

2089
2090
2091
2092
2093
2094
2095
2096







-
+







*/
int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){
  Table *pSelTab;   /* A fake table from which we get the result set */
  Select *pSel;     /* Copy of the SELECT that implements the view */
  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 );

#ifndef SQLITE_OMIT_VIRTUALTABLE
  if( sqlite3VtabCallConnect(pParse, pTable) ){
    return SQLITE_ERROR;
  }
2863
2864
2865
2866
2867
2868
2869




2870
2871
2872
2873
2874
2875
2876
2897
2898
2899
2900
2901
2902
2903
2904
2905
2906
2907
2908
2909
2910
2911
2912
2913
2914







+
+
+
+







    iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
  }
  pDb = &db->aDb[iDb];

  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;
  }
#ifndef SQLITE_OMIT_VIEW
  if( pTab->pSelect ){
    sqlite3ErrorMsg(pParse, "views may not be indexed");

Changes to src/ctime.c.

363
364
365
366
367
368
369



370
371
372
373
374
375
376
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379







+
+
+







  "TEST",
#endif
#if defined(SQLITE_THREADSAFE)
  "THREADSAFE=" CTIMEOPT_VAL(SQLITE_THREADSAFE),
#endif
#ifdef SQLITE_USE_ALLOCA
  "USE_ALLOCA",
#endif
#ifdef SQLITE_USER_AUTHENTICATION
  "USER_AUTHENTICATION",
#endif
#ifdef SQLITE_WIN32_MALLOC
  "WIN32_MALLOC",
#endif
#ifdef SQLITE_ZERO_MALLOC
  "ZERO_MALLOC"
#endif

Changes to src/func.c.

1691
1692
1693
1694
1695
1696
1697



1698
1699
1700
1701
1702
1703
1704
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707







+
+
+







    FUNCTION2(likely,            1, 0, 0, noopFunc,  SQLITE_FUNC_UNLIKELY),
    VFUNCTION(random,            0, 0, 0, randomFunc       ),
    VFUNCTION(randomblob,        1, 0, 0, randomBlob       ),
    FUNCTION(nullif,             2, 0, 1, nullifFunc       ),
    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  ),
#endif /* SQLITE_OMIT_COMPILEOPTION_DIAGS */
    FUNCTION(quote,              1, 0, 0, quoteFunc        ),
    VFUNCTION(last_insert_rowid, 0, 0, 0, last_insert_rowid),
    VFUNCTION(changes,           0, 0, 0, changes          ),

Changes to src/legacy.c.

121
122
123
124
125
126
127
128

129
130
131
132
133
134
135
121
122
123
124
125
126
127

128
129
130
131
132
133
134
135







-
+







  }

exec_out:
  if( pStmt ) sqlite3VdbeFinalize((Vdbe *)pStmt);
  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 ){
      memcpy(*pzErrMsg, sqlite3_errmsg(db), nErrMsg);
    }else{
      rc = SQLITE_NOMEM;
      sqlite3Error(db, SQLITE_NOMEM);

Changes to src/main.c.

981
982
983
984
985
986
987




988
989
990
991
992
993
994
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998







+
+
+
+







  }
  sqlite3HashClear(&db->aModule);
#endif

  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;

  /* The temp-database schema is allocated differently from the other schema
  ** objects (using sqliteMalloc() directly, instead of sqlite3BtreeSchema()).
  ** So it needs to be freed here. Todo: Why not roll the temp schema into
  ** the same sqliteMalloc() as the one that allocates the database 
2561
2562
2563
2564
2565
2566
2567
2568
2569
2570
2571
2572
2573
2574
2575
2565
2566
2567
2568
2569
2570
2571

2572
2573
2574
2575
2576
2577
2578







-







      rc = SQLITE_NOMEM;
    }
    sqlite3Error(db, rc);
    goto opendb_out;
  }
  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.  
  */
  db->aDb[0].zName = "main";
  db->aDb[0].safety_level = 3;
  db->aDb[1].zName = "temp";

Changes to src/pragma.c.

1393
1394
1395
1396
1397
1398
1399






1400
1401
1402
1403
1404
1405
1406
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412







+
+
+
+
+
+







    }else{
      int mask = aPragmaNames[mid].iArg;    /* Mask of bits to set or clear. */
      if( db->autoCommit==0 ){
        /* Foreign key support may not be enabled or disabled while not
        ** 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;
      }else{
        db->flags &= ~mask;
        if( mask==SQLITE_DeferFKs ) db->nDeferredImmCons = 0;
      }

Changes to src/prepare.c.

324
325
326
327
328
329
330
331

332
333
334
335
336
337
338
324
325
326
327
328
329
330

331
332
333
334
335
336
337
338







-
+







  {
    char *zSql;
    zSql = sqlite3MPrintf(db, 
        "SELECT name, rootpage, sql FROM '%q'.%s ORDER BY rowid",
        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
      rc = sqlite3_exec(db, zSql, sqlite3InitCallback, &initData, 0);
#ifndef SQLITE_OMIT_AUTHORIZATION
      db->xAuth = xAuth;
    }
390
391
392
393
394
395
396

397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413


414
415
416
417
418
419
420
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412


413
414
415
416
417
418
419
420
421







+















-
-
+
+







** file was of zero-length, then the DB_Empty flag is also set.
*/
int sqlite3Init(sqlite3 *db, char **pzErrMsg){
  int i, rc;
  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++){
    if( DbHasProperty(db, i, DB_SchemaLoaded) || i==1 ) continue;
    rc = sqlite3InitOne(db, i, pzErrMsg);
    if( rc ){
      sqlite3ResetOneSchema(db, i);
    }
  }

  /* Once all the other databases have been initialized, load the schema
  ** for the TEMP database. This is loaded last, as the TEMP database
  ** 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);
    }
  }
#endif

Changes to src/shell.c.

29
30
31
32
33
34
35



36
37
38
39
40
41
42
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45







+
+
+







#endif

#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <assert.h>
#include "sqlite3.h"
#if SQLITE_USER_AUTHENTICATION
# include "sqlite3userauth.h"
#endif
#include <ctype.h>
#include <stdarg.h>

#if !defined(_WIN32) && !defined(WIN32)
# include <signal.h>
# if !defined(__RTP__) && !defined(_WRS_KERNEL)
#  include <pwd.h>
3431
3432
3433
3434
3435
3436
3437

































































3438
3439
3440
3441
3442
3443
3444
3434
3435
3436
3437
3438
3439
3440
3441
3442
3443
3444
3445
3446
3447
3448
3449
3450
3451
3452
3453
3454
3455
3456
3457
3458
3459
3460
3461
3462
3463
3464
3465
3466
3467
3468
3469
3470
3471
3472
3473
3474
3475
3476
3477
3478
3479
3480
3481
3482
3483
3484
3485
3486
3487
3488
3489
3490
3491
3492
3493
3494
3495
3496
3497
3498
3499
3500
3501
3502
3503
3504
3505
3506
3507
3508
3509
3510
3511
3512







+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+







      sqlite3_trace(p->db, 0, 0);
    }else{
      sqlite3_trace(p->db, sql_trace_callback, p->traceOut);
    }
#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());
  }else

  if( c=='v' && strncmp(azArg[0], "vfsname", n)==0 ){
    const char *zDbName = nArg==2 ? azArg[1] : "main";

Changes to src/sqlite.h.in.

488
489
490
491
492
493
494

495
496
497
498
499
500
501
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502







+







#define SQLITE_CONSTRAINT_TRIGGER      (SQLITE_CONSTRAINT | (7<<8))
#define SQLITE_CONSTRAINT_UNIQUE       (SQLITE_CONSTRAINT | (8<<8))
#define SQLITE_CONSTRAINT_VTAB         (SQLITE_CONSTRAINT | (9<<8))
#define SQLITE_CONSTRAINT_ROWID        (SQLITE_CONSTRAINT |(10<<8))
#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
**
** These bit values are intended for use in the
** 3rd parameter to the [sqlite3_open_v2()] interface and
** in the 4th parameter to the [sqlite3_vfs.xOpen] method.

Changes to src/sqliteInt.h.

983
984
985
986
987
988
989







































990
991
992
993
994
995
996
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035







+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+







**
** Hash each FuncDef structure into one of the FuncDefHash.a[] slots.
** Collisions are on the FuncDef.pHash chain.
*/
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.
*/
struct sqlite3 {
  sqlite3_vfs *pVfs;            /* OS Interface */
  struct Vdbe *pVdbe;           /* List of active virtual machines */
1051
1052
1053
1054
1055
1056
1057
1058
1059

1060
1061
1062
1063
1064
1065
1066
1090
1091
1092
1093
1094
1095
1096


1097
1098
1099
1100
1101
1102
1103
1104







-
-
+







  sqlite3_value *pErr;          /* Most recent error message */
  union {
    volatile int isInterrupted; /* True if sqlite3_interrupt has been called */
    double notUsed1;            /* Spacer */
  } 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
  int (*xProgress)(void *);     /* The progress callback */
  void *pProgressArg;           /* Argument to the progress callback */
  unsigned nProgressOps;        /* Number of opcodes for progress callback */
#endif
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102



1103
1104
1105
1106
1107
1108
1109
1116
1117
1118
1119
1120
1121
1122

1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149







-

















+
+
+







  Savepoint *pSavepoint;        /* List of active savepoints */
  int busyTimeout;              /* Busy handler timeout, in msec */
  int nSavepoint;               /* Number of non-transaction savepoints */
  int nStatement;               /* Number of nested statement-transactions  */
  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. 
  **
  ** When X.pUnlockConnection==Y, that means that X is waiting for Y to
  ** unlock so that it can proceed.
  **
  ** When X.pBlockingConnection==Y, that means that something that X tried
  ** tried to do recently failed with an SQLITE_LOCKED error due to locks
  ** held by Y.
  */
  sqlite3 *pBlockingConnection; /* Connection that caused SQLITE_LOCKED */
  sqlite3 *pUnlockConnection;           /* Connection to watch for unlock */
  void *pUnlockArg;                     /* Argument to xUnlockNotify */
  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
};

/*
** A macro to discover the encoding of a database.
*/
#define ENC(db) ((db)->aDb[0].pSchema->enc)

Changes to src/tclsqlite.c.

868
869
870
871
872
873
874



875
876
877
878
879
880
881
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884







+
+
+







static int auth_callback(
  void *pArg,
  int code,
  const char *zArg1,
  const char *zArg2,
  const char *zArg3,
  const char *zArg4
#ifdef SQLITE_USER_AUTHENTICATION
  ,const char *zArg5
#endif
){
  const char *zCode;
  Tcl_DString str;
  int rc;
  const char *zReply;
  SqliteDb *pDb = (SqliteDb*)pArg;
  if( pDb->disableAuth ) return SQLITE_OK;
920
921
922
923
924
925
926



927
928
929
930
931
932
933
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939







+
+
+







  Tcl_DStringInit(&str);
  Tcl_DStringAppend(&str, pDb->zAuth, -1);
  Tcl_DStringAppendElement(&str, zCode);
  Tcl_DStringAppendElement(&str, zArg1 ? zArg1 : "");
  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";
  if( strcmp(zReply,"SQLITE_OK")==0 ){
    rc = SQLITE_OK;
  }else if( strcmp(zReply,"SQLITE_DENY")==0 ){
    rc = SQLITE_DENY;
1696
1697
1698
1699
1700
1701
1702



1703
1704

1705
1706
1707
1708
1709
1710
1711
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712

1713
1714
1715
1716
1717
1718
1719
1720







+
+
+

-
+







      if( zAuth && len>0 ){
        pDb->zAuth = Tcl_Alloc( len + 1 );
        memcpy(pDb->zAuth, zAuth, len+1);
      }else{
        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);
      }
    }
#endif
    break;
  }

Changes to src/test1.c.

6493
6494
6495
6496
6497
6498
6499






























































































































6500
6501
6502
6503
6504
6505
6506
6493
6494
6495
6496
6497
6498
6499
6500
6501
6502
6503
6504
6505
6506
6507
6508
6509
6510
6511
6512
6513
6514
6515
6516
6517
6518
6519
6520
6521
6522
6523
6524
6525
6526
6527
6528
6529
6530
6531
6532
6533
6534
6535
6536
6537
6538
6539
6540
6541
6542
6543
6544
6545
6546
6547
6548
6549
6550
6551
6552
6553
6554
6555
6556
6557
6558
6559
6560
6561
6562
6563
6564
6565
6566
6567
6568
6569
6570
6571
6572
6573
6574
6575
6576
6577
6578
6579
6580
6581
6582
6583
6584
6585
6586
6587
6588
6589
6590
6591
6592
6593
6594
6595
6596
6597
6598
6599
6600
6601
6602
6603
6604
6605
6606
6607
6608
6609
6610
6611
6612
6613
6614
6615
6616
6617
6618
6619
6620
6621
6622
6623
6624
6625
6626
6627
6628
6629
6630
6631
6632







+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+







  return TCL_OK;
 sql_error:
  Tcl_AppendResult(interp, "sql error: ", sqlite3_errmsg(db), 0);
  return TCL_ERROR;
}


#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.
*/
int Sqlitetest1_Init(Tcl_Interp *interp){
  extern int sqlite3_search_count;
  extern int sqlite3_found_count;
  extern int sqlite3_interrupt_count;
6730
6731
6732
6733
6734
6735
6736







6737
6738
6739
6740
6741
6742
6743
6856
6857
6858
6859
6860
6861
6862
6863
6864
6865
6866
6867
6868
6869
6870
6871
6872
6873
6874
6875
6876







+
+
+
+
+
+
+







     { "sqlite3_test_control", test_test_control },
#if SQLITE_OS_UNIX
     { "getrusage", test_getrusage },
#endif
     { "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;
  extern int sqlite3_sync_count, sqlite3_fullsync_count;
  extern int sqlite3_opentemp_count;
  extern int sqlite3_like_count;
  extern int sqlite3_xferopt_count;

Changes to src/test_config.c.

598
599
600
601
602
603
604






605
606
607
608
609
610
611
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617







+
+
+
+
+
+







#endif

#ifdef SQLITE_SECURE_DELETE
  Tcl_SetVar2(interp, "sqlite_options", "secure_delete", "1", TCL_GLOBAL_ONLY);
#else
  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
  Tcl_SetVar2(interp, "sqlite_options", "multiplex_ext_overwrite", "0", TCL_GLOBAL_ONLY);
#endif

Changes to test/auth.test.

32
33
34
35
36
37
38
39

40
41
42
43
44
45
46
32
33
34
35
36
37
38

39
40
41
42
43
44
45
46







-
+







    db authorizer ::auth
  }
}

do_test auth-1.1.1 {
  db close
  set ::DB [sqlite3 db test.db]
  proc auth {code arg1 arg2 arg3 arg4} {
  proc auth {code arg1 arg2 arg3 arg4 args} {
    if {$code=="SQLITE_INSERT" && $arg1=="sqlite_master"} {
      return SQLITE_DENY
    }
    return SQLITE_OK
  }
  db authorizer ::auth
  catchsql {CREATE TABLE t1(a,b,c)}
57
58
59
60
61
62
63
64

65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85

86
87
88
89
90
91
92
93
94
95
96
97

98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115

116
117
118
119
120
121
122
123
124
125
126
127

128
129
130
131
132
133
134
135
136
137
138
139
140
141
142

143
144
145
146
147
148
149
150
151
152
153
154

155
156
157
158
159
160
161
162
163
164
165
166
167
168

169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184

185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201

202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217

218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235

236
237
238
239
240
241
242
243
244
245
246
247
248

249
250
251
252
253
254
255
256
257
258
259
260
261
262
263

264
265
266
267
268
269
270
271
272
273
274
275

276
277
278
279
280
281
282
283
284
285
286
287

288
289
290
291
292
293
294
295
296
297
298
299
300

301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316

317
318
319
320
321
322
323
324
325

326
327
328
329
330
331
332
333
334

335
336
337
338
339
340
341
342
343

344
345
346
347
348
349
350
351
352

353
354
355
356
357
358
359
360
361
362

363
364
365
366
367
368
369
370
371
372
373
374

375
376
377
378
379
380
381
382
383
384
385
386

387
388
389
390
391
392
393
394
395
396
397
398
399

400
401
402
403
404
405
406
407
408
409
410
411

412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427

428
429
430
431
432
433
434
435
436

437
438
439
440
441
442
443
444
445

446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465

466
467
468
469
470
471
472
473
474
475
476
477

478
479
480
481
482
483
484
485
486
487
488
489
490
491

492
493
494
495
496
497
498
499
500
501
502
503

504
505
506
507
508
509
510
511
512
513
514
515
516
517

518
519
520
521
522
523
524
525
526
527
528
529

530
531
532
533
534
535
536
537
538
539
540
541
542
543

544
545
546
547
548
549
550
551
552
553
554
555

556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572

573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588

589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606

607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622

623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640

641
642
643
644
645
646
647
648
649
650
651
652

653
654
655
656
657
658
659
660
661
662
663
664
665
666

667
668
669
670
671
672
673
674
675
676
677
678

679
680
681
682
683
684
685
686
687
688
689
690
691
692

693
694
695
696
697
698
699
700
701
702
703
704
705
706
707

708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723

724
725
726
727
728
729
730
731
732
733
734
735

736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751

752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770

771
772
773
774
775
776
777
778
779
780
781
782
783
784
785

786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801

802
803
804
805
806
807
808
809
810
811
812
813

814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829

830
831
832
833
834
835
836
57
58
59
60
61
62
63

64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84

85
86
87
88
89
90
91
92
93
94
95
96

97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114

115
116
117
118
119
120
121
122
123
124
125
126

127
128
129
130
131
132
133
134
135
136
137
138
139
140
141

142
143
144
145
146
147
148
149
150
151
152
153

154
155
156
157
158
159
160
161
162
163
164
165
166
167

168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183

184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200

201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216

217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234

235
236
237
238
239
240
241
242
243
244
245
246
247

248
249
250
251
252
253
254
255
256
257
258
259
260
261
262

263
264
265
266
267
268
269
270
271
272
273
274

275
276
277
278
279
280
281
282
283
284
285
286

287
288
289
290
291
292
293
294
295
296
297
298
299

300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315

316
317
318
319
320
321
322
323
324

325
326
327
328
329
330
331
332
333

334
335
336
337
338
339
340
341
342

343
344
345
346
347
348
349
350
351

352
353
354
355
356
357
358
359
360
361

362
363
364
365
366
367
368
369
370
371
372
373

374
375
376
377
378
379
380
381
382
383
384
385

386
387
388
389
390
391
392
393
394
395
396
397
398

399
400
401
402
403
404
405
406
407
408
409
410

411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426

427
428
429
430
431
432
433
434
435

436
437
438
439
440
441
442
443
444

445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464

465
466
467
468
469
470
471
472
473
474
475
476

477
478
479
480
481
482
483
484
485
486
487
488
489
490

491
492
493
494
495
496
497
498
499
500
501
502

503
504
505
506
507
508
509
510
511
512
513
514
515
516

517
518
519
520
521
522
523
524
525
526
527
528

529
530
531
532
533
534
535
536
537
538
539
540
541
542

543
544
545
546
547
548
549
550
551
552
553
554

555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571

572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587

588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605

606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621

622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639

640
641
642
643
644
645
646
647
648
649
650
651

652
653
654
655
656
657
658
659
660
661
662
663
664
665

666
667
668
669
670
671
672
673
674
675
676
677

678
679
680
681
682
683
684
685
686
687
688
689
690
691

692
693
694
695
696
697
698
699
700
701
702
703
704
705
706

707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722

723
724
725
726
727
728
729
730
731
732
733
734

735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750

751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769

770
771
772
773
774
775
776
777
778
779
780
781
782
783
784

785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800

801
802
803
804
805
806
807
808
809
810
811
812

813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828

829
830
831
832
833
834
835
836







-
+




















-
+











-
+

















-
+











-
+














-
+











-
+













-
+















-
+
















-
+















-
+

















-
+












-
+














-
+











-
+











-
+












-
+















-
+








-
+








-
+








-
+








-
+









-
+











-
+











-
+












-
+











-
+















-
+








-
+








-
+



















-
+











-
+













-
+











-
+













-
+











-
+













-
+











-
+
















-
+















-
+

















-
+















-
+

















-
+











-
+













-
+











-
+













-
+














-
+















-
+











-
+















-
+


















-
+














-
+















-
+











-
+















-
+







    SELECT x;
  }
} {1 {no such column: x}}
do_test auth-1.2 {
  execsql {SELECT name FROM sqlite_master}
} {}
do_test auth-1.3.1 {
  proc auth {code arg1 arg2 arg3 arg4} {
  proc auth {code arg1 arg2 arg3 arg4 args} {
    if {$code=="SQLITE_CREATE_TABLE"} {
      set ::authargs [list $arg1 $arg2 $arg3 $arg4]
      return SQLITE_DENY
    }
    return SQLITE_OK
  }
  catchsql {CREATE TABLE t1(a,b,c)}
} {1 {not authorized}}
do_test auth-1.3.2 {
  db errorcode
} {23}
do_test auth-1.3.3 {
  set ::authargs
} {t1 {} main {}}
do_test auth-1.4 {
  execsql {SELECT name FROM sqlite_master}
} {}

ifcapable tempdb {
  do_test auth-1.5 {
    proc auth {code arg1 arg2 arg3 arg4} {
    proc auth {code arg1 arg2 arg3 arg4 args} {
      if {$code=="SQLITE_INSERT" && $arg1=="sqlite_temp_master"} {
        return SQLITE_DENY
      }
      return SQLITE_OK
    }
    catchsql {CREATE TEMP TABLE t1(a,b,c)}
  } {1 {not authorized}}
  do_test auth-1.6 {
    execsql {SELECT name FROM sqlite_temp_master}
  } {}
  do_test auth-1.7.1 {
    proc auth {code arg1 arg2 arg3 arg4} {
    proc auth {code arg1 arg2 arg3 arg4 args} {
      if {$code=="SQLITE_CREATE_TEMP_TABLE"} {
        set ::authargs [list $arg1 $arg2 $arg3 $arg4]
        return SQLITE_DENY
      }
      return SQLITE_OK
    }
    catchsql {CREATE TEMP TABLE t1(a,b,c)}
  } {1 {not authorized}}
  do_test auth-1.7.2 {
     set ::authargs
  } {t1 {} temp {}}
  do_test auth-1.8 {
    execsql {SELECT name FROM sqlite_temp_master}
  } {}
}

do_test auth-1.9 {
  proc auth {code arg1 arg2 arg3 arg4} {
  proc auth {code arg1 arg2 arg3 arg4 args} {
    if {$code=="SQLITE_INSERT" && $arg1=="sqlite_master"} {
      return SQLITE_IGNORE
    }
    return SQLITE_OK
  }
  catchsql {CREATE TABLE t1(a,b,c)}
} {0 {}}
do_test auth-1.10 {
  execsql {SELECT name FROM sqlite_master}
} {}
do_test auth-1.11 {
  proc auth {code arg1 arg2 arg3 arg4} {
  proc auth {code arg1 arg2 arg3 arg4 args} {
    if {$code=="SQLITE_CREATE_TABLE"} {
      set ::authargs [list $arg1 $arg2 $arg3 $arg4]
      return SQLITE_IGNORE
    }
    return SQLITE_OK
  }
  catchsql {CREATE TABLE t1(a,b,c)}
} {0 {}}
do_test auth-1.12 {
  execsql {SELECT name FROM sqlite_master}
} {}

ifcapable tempdb {
  do_test auth-1.13 {
    proc auth {code arg1 arg2 arg3 arg4} {
    proc auth {code arg1 arg2 arg3 arg4 args} {
      if {$code=="SQLITE_INSERT" && $arg1=="sqlite_temp_master"} {
        return SQLITE_IGNORE
      }
      return SQLITE_OK
    }
    catchsql {CREATE TEMP TABLE t1(a,b,c)}
  } {0 {}}
  do_test auth-1.14 {
    execsql {SELECT name FROM sqlite_temp_master}
  } {}
  do_test auth-1.15 {
    proc auth {code arg1 arg2 arg3 arg4} {
    proc auth {code arg1 arg2 arg3 arg4 args} {
      if {$code=="SQLITE_CREATE_TEMP_TABLE"} {
        set ::authargs [list $arg1 $arg2 $arg3 $arg4]
        return SQLITE_IGNORE
      }
      return SQLITE_OK
    }
    catchsql {CREATE TEMP TABLE t1(a,b,c)}
  } {0 {}}
  do_test auth-1.16 {
    execsql {SELECT name FROM sqlite_temp_master}
  } {}
  
  do_test auth-1.17 {
    proc auth {code arg1 arg2 arg3 arg4} {
    proc auth {code arg1 arg2 arg3 arg4 args} {
      if {$code=="SQLITE_CREATE_TABLE"} {
        set ::authargs [list $arg1 $arg2 $arg3 $arg4]
        return SQLITE_DENY
      }
      return SQLITE_OK
    }
    catchsql {CREATE TEMP TABLE t1(a,b,c)}
  } {0 {}}
  do_test auth-1.18 {
    execsql {SELECT name FROM sqlite_temp_master}
  } {t1}
}

do_test auth-1.19.1 {
  set ::authargs {}
  proc auth {code arg1 arg2 arg3 arg4} {
  proc auth {code arg1 arg2 arg3 arg4 args} {
    if {$code=="SQLITE_CREATE_TEMP_TABLE"} {
      set ::authargs [list $arg1 $arg2 $arg3 $arg4]
      return SQLITE_DENY
    }
    return SQLITE_OK
  }
  catchsql {CREATE TABLE t2(a,b,c)}
} {0 {}}
do_test auth-1.19.2 {
  set ::authargs
} {}
do_test auth-1.20 {
  execsql {SELECT name FROM sqlite_master}
} {t2}

do_test auth-1.21.1 {
  proc auth {code arg1 arg2 arg3 arg4} {
  proc auth {code arg1 arg2 arg3 arg4 args} {
    if {$code=="SQLITE_DROP_TABLE"} {
      set ::authargs [list $arg1 $arg2 $arg3 $arg4]
      return SQLITE_DENY
    }
    return SQLITE_OK
  }
  catchsql {DROP TABLE t2}
} {1 {not authorized}}
do_test auth-1.21.2 {
  set ::authargs
} {t2 {} main {}}
do_test auth-1.22 {
  execsql {SELECT name FROM sqlite_master}
} {t2}
do_test auth-1.23.1 {
  proc auth {code arg1 arg2 arg3 arg4} {
  proc auth {code arg1 arg2 arg3 arg4 args} {
    if {$code=="SQLITE_DROP_TABLE"} {
      set ::authargs [list $arg1 $arg2 $arg3 $arg4]
      return SQLITE_IGNORE
    }
    return SQLITE_OK
  }
  catchsql {DROP TABLE t2}
} {0 {}}
do_test auth-1.23.2 {
  set ::authargs
} {t2 {} main {}}
do_test auth-1.24 {
  execsql {SELECT name FROM sqlite_master}
} {t2}

ifcapable tempdb {
  do_test auth-1.25 {
    proc auth {code arg1 arg2 arg3 arg4} {
    proc auth {code arg1 arg2 arg3 arg4 args} {
      if {$code=="SQLITE_DROP_TEMP_TABLE"} {
        set ::authargs [list $arg1 $arg2 $arg3 $arg4]
        return SQLITE_DENY
      }
      return SQLITE_OK
    }
    catchsql {DROP TABLE t1}
  } {1 {not authorized}}
  do_test auth-1.26 {
    execsql {SELECT name FROM sqlite_temp_master}
  } {t1}
  do_test auth-1.27 {
    proc auth {code arg1 arg2 arg3 arg4} {
    proc auth {code arg1 arg2 arg3 arg4 args} {
      if {$code=="SQLITE_DROP_TEMP_TABLE"} {
        set ::authargs [list $arg1 $arg2 $arg3 $arg4]
        return SQLITE_IGNORE
      }
      return SQLITE_OK
    }
    catchsql {DROP TABLE t1}
  } {0 {}}
  do_test auth-1.28 {
    execsql {SELECT name FROM sqlite_temp_master}
  } {t1}
}

do_test auth-1.29 {
  proc auth {code arg1 arg2 arg3 arg4} {
  proc auth {code arg1 arg2 arg3 arg4 args} {
    if {$code=="SQLITE_INSERT" && $arg1=="t2"} {
      return SQLITE_DENY
    }
    return SQLITE_OK
  }
  catchsql {INSERT INTO t2 VALUES(1,2,3)}
} {1 {not authorized}}
do_test auth-1.30 {
  execsql {SELECT * FROM t2}
} {}
do_test auth-1.31 {
  proc auth {code arg1 arg2 arg3 arg4} {
  proc auth {code arg1 arg2 arg3 arg4 args} {
    if {$code=="SQLITE_INSERT" && $arg1=="t2"} {
      return SQLITE_IGNORE
    }
    return SQLITE_OK
  }
  catchsql {INSERT INTO t2 VALUES(1,2,3)}
} {0 {}}
do_test auth-1.32 {
  execsql {SELECT * FROM t2}
} {}
do_test auth-1.33 {
  proc auth {code arg1 arg2 arg3 arg4} {
  proc auth {code arg1 arg2 arg3 arg4 args} {
    if {$code=="SQLITE_INSERT" && $arg1=="t1"} {
      return SQLITE_IGNORE
    }
    return SQLITE_OK
  }
  catchsql {INSERT INTO t2 VALUES(1,2,3)}
} {0 {}}
do_test auth-1.34 {
  execsql {SELECT * FROM t2}
} {1 2 3}

do_test auth-1.35.1 {
  proc auth {code arg1 arg2 arg3 arg4} {
  proc auth {code arg1 arg2 arg3 arg4 args} {
    if {$code=="SQLITE_READ" && $arg1=="t2" && $arg2=="b"} {
      return SQLITE_DENY
    }
    return SQLITE_OK
  }
  catchsql {SELECT * FROM t2}
} {1 {access to t2.b is prohibited}}
ifcapable attach {
  do_test auth-1.35.2 {
    execsql {ATTACH DATABASE 'test.db' AS two}
    catchsql {SELECT * FROM two.t2}
  } {1 {access to two.t2.b is prohibited}}
  execsql {DETACH DATABASE two}
}
do_test auth-1.36 {
  proc auth {code arg1 arg2 arg3 arg4} {
  proc auth {code arg1 arg2 arg3 arg4 args} {
    if {$code=="SQLITE_READ" && $arg1=="t2" && $arg2=="b"} {
      return SQLITE_IGNORE
    }
    return SQLITE_OK
  }
  catchsql {SELECT * FROM t2}
} {0 {1 {} 3}}
do_test auth-1.37 {
  proc auth {code arg1 arg2 arg3 arg4} {
  proc auth {code arg1 arg2 arg3 arg4 args} {
    if {$code=="SQLITE_READ" && $arg1=="t2" && $arg2=="b"} {
      return SQLITE_IGNORE
    }
    return SQLITE_OK
  }
  catchsql {SELECT * FROM t2 WHERE b=2}
} {0 {}}
do_test auth-1.38 {
  proc auth {code arg1 arg2 arg3 arg4} {
  proc auth {code arg1 arg2 arg3 arg4 args} {
    if {$code=="SQLITE_READ" && $arg1=="t2" && $arg2=="a"} {
      return SQLITE_IGNORE
    }
    return SQLITE_OK
  }
  catchsql {SELECT * FROM t2 WHERE b=2}
} {0 {{} 2 3}}
do_test auth-1.39 {
  proc auth {code arg1 arg2 arg3 arg4} {
  proc auth {code arg1 arg2 arg3 arg4 args} {
    if {$code=="SQLITE_READ" && $arg1=="t2" && $arg2=="b"} {
      return SQLITE_IGNORE
    }
    return SQLITE_OK
  }
  catchsql {SELECT * FROM t2 WHERE b IS NULL}
} {0 {1 {} 3}}
do_test auth-1.40 {
  proc auth {code arg1 arg2 arg3 arg4} {
  proc auth {code arg1 arg2 arg3 arg4 args} {
    if {$code=="SQLITE_READ" && $arg1=="t2" && $arg2=="b"} {
      return SQLITE_DENY
    }
    return SQLITE_OK
  }
  catchsql {SELECT a,c FROM t2 WHERE b IS NULL}
} {1 {access to t2.b is prohibited}}
  
do_test auth-1.41 {
  proc auth {code arg1 arg2 arg3 arg4} {
  proc auth {code arg1 arg2 arg3 arg4 args} {
    if {$code=="SQLITE_UPDATE" && $arg1=="t2" && $arg2=="b"} {
      return SQLITE_DENY
    }
    return SQLITE_OK
  }
  catchsql {UPDATE t2 SET a=11}
} {0 {}}
do_test auth-1.42 {
  execsql {SELECT * FROM t2}
} {11 2 3}
do_test auth-1.43 {
  proc auth {code arg1 arg2 arg3 arg4} {
  proc auth {code arg1 arg2 arg3 arg4 args} {
    if {$code=="SQLITE_UPDATE" && $arg1=="t2" && $arg2=="b"} {
      return SQLITE_DENY
    }
    return SQLITE_OK
  }
  catchsql {UPDATE t2 SET b=22, c=33}
} {1 {not authorized}}
do_test auth-1.44 {
  execsql {SELECT * FROM t2}
} {11 2 3}
do_test auth-1.45 {
  proc auth {code arg1 arg2 arg3 arg4} {
  proc auth {code arg1 arg2 arg3 arg4 args} {
    if {$code=="SQLITE_UPDATE" && $arg1=="t2" && $arg2=="b"} {
      return SQLITE_IGNORE
    }
    return SQLITE_OK
  }
  catchsql {UPDATE t2 SET b=22, c=33}
} {0 {}}
do_test auth-1.46 {
  execsql {SELECT * FROM t2}
} {11 2 33}

do_test auth-1.47 {
  proc auth {code arg1 arg2 arg3 arg4} {
  proc auth {code arg1 arg2 arg3 arg4 args} {
    if {$code=="SQLITE_DELETE" && $arg1=="t2"} {
      return SQLITE_DENY
    }
    return SQLITE_OK
  }
  catchsql {DELETE FROM t2 WHERE a=11}
} {1 {not authorized}}
do_test auth-1.48 {
  execsql {SELECT * FROM t2}
} {11 2 33}
do_test auth-1.49 {
  proc auth {code arg1 arg2 arg3 arg4} {
  proc auth {code arg1 arg2 arg3 arg4 args} {
    if {$code=="SQLITE_DELETE" && $arg1=="t2"} {
      return SQLITE_IGNORE
    }
    return SQLITE_OK
  }
  catchsql {DELETE FROM t2 WHERE a=11}
} {0 {}}
do_test auth-1.50 {
  execsql {SELECT * FROM t2}
} {}
do_test auth-1.50.2 {
  execsql {INSERT INTO t2 VALUES(11, 2, 33)}
} {}

do_test auth-1.51 {
  proc auth {code arg1 arg2 arg3 arg4} {
  proc auth {code arg1 arg2 arg3 arg4 args} {
    if {$code=="SQLITE_SELECT"} {
      return SQLITE_DENY
    }
    return SQLITE_OK
  }
  catchsql {SELECT * FROM t2}
} {1 {not authorized}}
do_test auth-1.52 {
  proc auth {code arg1 arg2 arg3 arg4} {
  proc auth {code arg1 arg2 arg3 arg4 args} {
    if {$code=="SQLITE_SELECT"} {
      return SQLITE_IGNORE
    }
    return SQLITE_OK
  }
  catchsql {SELECT * FROM t2}
} {0 {}}
do_test auth-1.53 {
  proc auth {code arg1 arg2 arg3 arg4} {
  proc auth {code arg1 arg2 arg3 arg4 args} {
    if {$code=="SQLITE_SELECT"} {
      return SQLITE_OK
    }
    return SQLITE_OK
  }
  catchsql {SELECT * FROM t2}
} {0 {11 2 33}}

# Update for version 3: There used to be a handful of test here that
# tested the authorisation callback with the COPY command. The following
# test makes the same database modifications as they used to.
do_test auth-1.54 {
  execsql {INSERT INTO t2 VALUES(7, 8, 9);}
} {}
do_test auth-1.55 {
  execsql {SELECT * FROM t2}
} {11 2 33 7 8 9}

do_test auth-1.63 {
  proc auth {code arg1 arg2 arg3 arg4} {
  proc auth {code arg1 arg2 arg3 arg4 args} {
    if {$code=="SQLITE_DELETE" && $arg1=="sqlite_master"} {
       return SQLITE_DENY
    }
    return SQLITE_OK
  }
  catchsql {DROP TABLE t2}
} {1 {not authorized}}
do_test auth-1.64 {
  execsql {SELECT name FROM sqlite_master}
} {t2}
do_test auth-1.65 {
  proc auth {code arg1 arg2 arg3 arg4} {
  proc auth {code arg1 arg2 arg3 arg4 args} {
    if {$code=="SQLITE_DELETE" && $arg1=="t2"} {
       return SQLITE_DENY
    }
    return SQLITE_OK
  }
  catchsql {DROP TABLE t2}
} {1 {not authorized}}
do_test auth-1.66 {
  execsql {SELECT name FROM sqlite_master}
} {t2}

ifcapable tempdb {
  do_test auth-1.67 {
    proc auth {code arg1 arg2 arg3 arg4} {
    proc auth {code arg1 arg2 arg3 arg4 args} {
      if {$code=="SQLITE_DELETE" && $arg1=="sqlite_temp_master"} {
         return SQLITE_DENY
      }
      return SQLITE_OK
    }
    catchsql {DROP TABLE t1}
  } {1 {not authorized}}
  do_test auth-1.68 {
    execsql {SELECT name FROM sqlite_temp_master}
  } {t1}
  do_test auth-1.69 {
    proc auth {code arg1 arg2 arg3 arg4} {
    proc auth {code arg1 arg2 arg3 arg4 args} {
      if {$code=="SQLITE_DELETE" && $arg1=="t1"} {
         return SQLITE_DENY
      }
      return SQLITE_OK
    }
    catchsql {DROP TABLE t1}
  } {1 {not authorized}}
  do_test auth-1.70 {
    execsql {SELECT name FROM sqlite_temp_master}
  } {t1}
}

do_test auth-1.71 {
  proc auth {code arg1 arg2 arg3 arg4} {
  proc auth {code arg1 arg2 arg3 arg4 args} {
    if {$code=="SQLITE_DELETE" && $arg1=="sqlite_master"} {
       return SQLITE_IGNORE
    }
    return SQLITE_OK
  }
  catchsql {DROP TABLE t2}
} {0 {}}
do_test auth-1.72 {
  execsql {SELECT name FROM sqlite_master}
} {t2}
do_test auth-1.73 {
  proc auth {code arg1 arg2 arg3 arg4} {
  proc auth {code arg1 arg2 arg3 arg4 args} {
    if {$code=="SQLITE_DELETE" && $arg1=="t2"} {
       return SQLITE_IGNORE
    }
    return SQLITE_OK
  }
  catchsql {DROP TABLE t2}
} {0 {}}
do_test auth-1.74 {
  execsql {SELECT name FROM sqlite_master}
} {t2}

ifcapable tempdb {
  do_test auth-1.75 {
    proc auth {code arg1 arg2 arg3 arg4} {
    proc auth {code arg1 arg2 arg3 arg4 args} {
      if {$code=="SQLITE_DELETE" && $arg1=="sqlite_temp_master"} {
         return SQLITE_IGNORE
      }
      return SQLITE_OK
    }
    catchsql {DROP TABLE t1}
  } {0 {}}
  do_test auth-1.76 {
    execsql {SELECT name FROM sqlite_temp_master}
  } {t1}
  do_test auth-1.77 {
    proc auth {code arg1 arg2 arg3 arg4} {
    proc auth {code arg1 arg2 arg3 arg4 args} {
      if {$code=="SQLITE_DELETE" && $arg1=="t1"} {
         return SQLITE_IGNORE
      }
      return SQLITE_OK
    }
    catchsql {DROP TABLE t1}
  } {0 {}}
  do_test auth-1.78 {
    execsql {SELECT name FROM sqlite_temp_master}
  } {t1}
}

# Test cases auth-1.79 to auth-1.124 test creating and dropping views.
# Omit these if the library was compiled with views omitted.
ifcapable view {
do_test auth-1.79 {
  proc auth {code arg1 arg2 arg3 arg4} {
  proc auth {code arg1 arg2 arg3 arg4 args} {
    if {$code=="SQLITE_CREATE_VIEW"} {
      set ::authargs [list $arg1 $arg2 $arg3 $arg4] 
      return SQLITE_DENY
    }
    return SQLITE_OK
  }
  catchsql {CREATE VIEW v1 AS SELECT a+1,b+1 FROM t2}
} {1 {not authorized}}
do_test auth-1.80 {
  set ::authargs
} {v1 {} main {}}
do_test auth-1.81 {
  execsql {SELECT name FROM sqlite_master}
} {t2}
do_test auth-1.82 {
  proc auth {code arg1 arg2 arg3 arg4} {
  proc auth {code arg1 arg2 arg3 arg4 args} {
    if {$code=="SQLITE_CREATE_VIEW"} {
      set ::authargs [list $arg1 $arg2 $arg3 $arg4] 
      return SQLITE_IGNORE
    }
    return SQLITE_OK
  }
  catchsql {CREATE VIEW v1 AS SELECT a+1,b+1 FROM t2}
} {0 {}}
do_test auth-1.83 {
  set ::authargs
} {v1 {} main {}}
do_test auth-1.84 {
  execsql {SELECT name FROM sqlite_master}
} {t2}

ifcapable tempdb {
  do_test auth-1.85 {
    proc auth {code arg1 arg2 arg3 arg4} {
    proc auth {code arg1 arg2 arg3 arg4 args} {
      if {$code=="SQLITE_CREATE_TEMP_VIEW"} {
        set ::authargs [list $arg1 $arg2 $arg3 $arg4] 
        return SQLITE_DENY
      }
      return SQLITE_OK
    }
    catchsql {CREATE TEMPORARY VIEW v1 AS SELECT a+1,b+1 FROM t2}
  } {1 {not authorized}}
  do_test auth-1.86 {
    set ::authargs
  } {v1 {} temp {}}
  do_test auth-1.87 {
    execsql {SELECT name FROM sqlite_temp_master}
  } {t1}
  do_test auth-1.88 {
    proc auth {code arg1 arg2 arg3 arg4} {
    proc auth {code arg1 arg2 arg3 arg4 args} {
      if {$code=="SQLITE_CREATE_TEMP_VIEW"} {
        set ::authargs [list $arg1 $arg2 $arg3 $arg4] 
        return SQLITE_IGNORE
      }
      return SQLITE_OK
    }
    catchsql {CREATE TEMPORARY VIEW v1 AS SELECT a+1,b+1 FROM t2}
  } {0 {}}
  do_test auth-1.89 {
    set ::authargs
  } {v1 {} temp {}}
  do_test auth-1.90 {
    execsql {SELECT name FROM sqlite_temp_master}
  } {t1}
}

do_test auth-1.91 {
  proc auth {code arg1 arg2 arg3 arg4} {
  proc auth {code arg1 arg2 arg3 arg4 args} {
    if {$code=="SQLITE_INSERT" && $arg1=="sqlite_master"} {
      return SQLITE_DENY
    }
    return SQLITE_OK
  }
  catchsql {CREATE VIEW v1 AS SELECT a+1,b+1 FROM t2}
} {1 {not authorized}}
do_test auth-1.92 {
  execsql {SELECT name FROM sqlite_master}
} {t2}
do_test auth-1.93 {
  proc auth {code arg1 arg2 arg3 arg4} {
  proc auth {code arg1 arg2 arg3 arg4 args} {
    if {$code=="SQLITE_INSERT" && $arg1=="sqlite_master"} {
      return SQLITE_IGNORE
    }
    return SQLITE_OK
  }
  catchsql {CREATE VIEW v1 AS SELECT a+1,b+1 FROM t2}
} {0 {}}
do_test auth-1.94 {
  execsql {SELECT name FROM sqlite_master}
} {t2}

ifcapable tempdb {
  do_test auth-1.95 {
    proc auth {code arg1 arg2 arg3 arg4} {
    proc auth {code arg1 arg2 arg3 arg4 args} {
      if {$code=="SQLITE_INSERT" && $arg1=="sqlite_temp_master"} {
        return SQLITE_DENY
      }
      return SQLITE_OK
    }
    catchsql {CREATE TEMPORARY VIEW v1 AS SELECT a+1,b+1 FROM t2}
  } {1 {not authorized}}
  do_test auth-1.96 {
    execsql {SELECT name FROM sqlite_temp_master}
  } {t1}
  do_test auth-1.97 {
    proc auth {code arg1 arg2 arg3 arg4} {
    proc auth {code arg1 arg2 arg3 arg4 args} {
      if {$code=="SQLITE_INSERT" && $arg1=="sqlite_temp_master"} {
        return SQLITE_IGNORE
      }
      return SQLITE_OK
    }
    catchsql {CREATE TEMPORARY VIEW v1 AS SELECT a+1,b+1 FROM t2}
  } {0 {}}
  do_test auth-1.98 {
    execsql {SELECT name FROM sqlite_temp_master}
  } {t1}
}

do_test auth-1.99 {
  proc auth {code arg1 arg2 arg3 arg4} {
  proc auth {code arg1 arg2 arg3 arg4 args} {
    if {$code=="SQLITE_DELETE" && $arg1=="sqlite_master"} {
      return SQLITE_DENY
    }
    return SQLITE_OK
  }
  catchsql {
    CREATE VIEW v2 AS SELECT a+1,b+1 FROM t2;
    DROP VIEW v2
  }
} {1 {not authorized}}
do_test auth-1.100 {
  execsql {SELECT name FROM sqlite_master}
} {t2 v2}
do_test auth-1.101 {
  proc auth {code arg1 arg2 arg3 arg4} {
  proc auth {code arg1 arg2 arg3 arg4 args} {
    if {$code=="SQLITE_DROP_VIEW"} {
      set ::authargs [list $arg1 $arg2 $arg3 $arg4]
      return SQLITE_DENY
    }
    return SQLITE_OK
  }
  catchsql {DROP VIEW v2}
} {1 {not authorized}}
do_test auth-1.102 {
  set ::authargs
} {v2 {} main {}}
do_test auth-1.103 {
  execsql {SELECT name FROM sqlite_master}
} {t2 v2}
do_test auth-1.104 {
  proc auth {code arg1 arg2 arg3 arg4} {
  proc auth {code arg1 arg2 arg3 arg4 args} {
    if {$code=="SQLITE_DELETE" && $arg1=="sqlite_master"} {
      return SQLITE_IGNORE
    }
    return SQLITE_OK
  }
  catchsql {DROP VIEW v2}
} {0 {}}
do_test auth-1.105 {
  execsql {SELECT name FROM sqlite_master}
} {t2 v2}
do_test auth-1.106 {
  proc auth {code arg1 arg2 arg3 arg4} {
  proc auth {code arg1 arg2 arg3 arg4 args} {
    if {$code=="SQLITE_DROP_VIEW"} {
      set ::authargs [list $arg1 $arg2 $arg3 $arg4]
      return SQLITE_IGNORE
    }
    return SQLITE_OK
  }
  catchsql {DROP VIEW v2}
} {0 {}}
do_test auth-1.107 {
  set ::authargs
} {v2 {} main {}}
do_test auth-1.108 {
  execsql {SELECT name FROM sqlite_master}
} {t2 v2}
do_test auth-1.109 {
  proc auth {code arg1 arg2 arg3 arg4} {
  proc auth {code arg1 arg2 arg3 arg4 args} {
    if {$code=="SQLITE_DROP_VIEW"} {
      set ::authargs [list $arg1 $arg2 $arg3 $arg4]
      return SQLITE_OK
    }
    return SQLITE_OK
  }
  catchsql {DROP VIEW v2}
} {0 {}}
do_test auth-1.110 {
  set ::authargs
} {v2 {} main {}}
do_test auth-1.111 {
  execsql {SELECT name FROM sqlite_master}
} {t2}


ifcapable tempdb {
  do_test auth-1.112 {
    proc auth {code arg1 arg2 arg3 arg4} {
    proc auth {code arg1 arg2 arg3 arg4 args} {
      if {$code=="SQLITE_DELETE" && $arg1=="sqlite_temp_master"} {
        return SQLITE_DENY
      }
      return SQLITE_OK
    }
    catchsql {
      CREATE TEMP VIEW v1 AS SELECT a+1,b+1 FROM t1;
      DROP VIEW v1
    }
  } {1 {not authorized}}
  do_test auth-1.113 {
    execsql {SELECT name FROM sqlite_temp_master}
  } {t1 v1}
  do_test auth-1.114 {
    proc auth {code arg1 arg2 arg3 arg4} {
    proc auth {code arg1 arg2 arg3 arg4 args} {
      if {$code=="SQLITE_DROP_TEMP_VIEW"} {
        set ::authargs [list $arg1 $arg2 $arg3 $arg4]
        return SQLITE_DENY
      }
      return SQLITE_OK
    }
    catchsql {DROP VIEW v1}
  } {1 {not authorized}}
  do_test auth-1.115 {
    set ::authargs
  } {v1 {} temp {}}
  do_test auth-1.116 {
    execsql {SELECT name FROM sqlite_temp_master}
  } {t1 v1}
  do_test auth-1.117 {
    proc auth {code arg1 arg2 arg3 arg4} {
    proc auth {code arg1 arg2 arg3 arg4 args} {
      if {$code=="SQLITE_DELETE" && $arg1=="sqlite_temp_master"} {
        return SQLITE_IGNORE
      }
      return SQLITE_OK
    }
    catchsql {DROP VIEW v1}
  } {0 {}}
  do_test auth-1.118 {
    execsql {SELECT name FROM sqlite_temp_master}
  } {t1 v1}
  do_test auth-1.119 {
    proc auth {code arg1 arg2 arg3 arg4} {
    proc auth {code arg1 arg2 arg3 arg4 args} {
      if {$code=="SQLITE_DROP_TEMP_VIEW"} {
        set ::authargs [list $arg1 $arg2 $arg3 $arg4]
        return SQLITE_IGNORE
      }
      return SQLITE_OK
    }
    catchsql {DROP VIEW v1}
  } {0 {}}
  do_test auth-1.120 {
    set ::authargs
  } {v1 {} temp {}}
  do_test auth-1.121 {
    execsql {SELECT name FROM sqlite_temp_master}
  } {t1 v1}
  do_test auth-1.122 {
    proc auth {code arg1 arg2 arg3 arg4} {
    proc auth {code arg1 arg2 arg3 arg4 args} {
      if {$code=="SQLITE_DROP_TEMP_VIEW"} {
        set ::authargs [list $arg1 $arg2 $arg3 $arg4]
        return SQLITE_OK
      }
      return SQLITE_OK
    }
    catchsql {DROP VIEW v1}
845
846
847
848
849
850
851
852

853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872

873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888

889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908

909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924

925
926
927
928
929
930
931
845
846
847
848
849
850
851

852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871

872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887

888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907

908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923

924
925
926
927
928
929
930
931







-
+



















-
+















-
+



















-
+















-
+







} ;# ifcapable view

# Test cases auth-1.125 to auth-1.176 test creating and dropping triggers.
# Omit these if the library was compiled with triggers omitted.
#
ifcapable trigger&&tempdb {
do_test auth-1.125 {
  proc auth {code arg1 arg2 arg3 arg4} {
  proc auth {code arg1 arg2 arg3 arg4 args} {
    if {$code=="SQLITE_CREATE_TRIGGER"} {
      set ::authargs [list $arg1 $arg2 $arg3 $arg4]
      return SQLITE_DENY
    }
    return SQLITE_OK
  }
  catchsql {
    CREATE TRIGGER r2 DELETE on t2 BEGIN
        SELECT NULL;
    END;
  }
} {1 {not authorized}}
do_test auth-1.126 {
  set ::authargs
} {r2 t2 main {}}
do_test auth-1.127 {
  execsql {SELECT name FROM sqlite_master}
} {t2}
do_test auth-1.128 {
  proc auth {code arg1 arg2 arg3 arg4} {
  proc auth {code arg1 arg2 arg3 arg4 args} {
    if {$code=="SQLITE_INSERT" && $arg1=="sqlite_master"} {
      return SQLITE_DENY
    }
    return SQLITE_OK
  }
  catchsql {
    CREATE TRIGGER r2 DELETE on t2 BEGIN
        SELECT NULL;
    END;
  }
} {1 {not authorized}}
do_test auth-1.129 {
  execsql {SELECT name FROM sqlite_master}
} {t2}
do_test auth-1.130 {
  proc auth {code arg1 arg2 arg3 arg4} {
  proc auth {code arg1 arg2 arg3 arg4 args} {
    if {$code=="SQLITE_CREATE_TRIGGER"} {
      set ::authargs [list $arg1 $arg2 $arg3 $arg4]
      return SQLITE_IGNORE
    }
    return SQLITE_OK
  }
  catchsql {
    CREATE TRIGGER r2 DELETE on t2 BEGIN
        SELECT NULL;
    END;
  }
} {0 {}}
do_test auth-1.131 {
  set ::authargs
} {r2 t2 main {}}
do_test auth-1.132 {
  execsql {SELECT name FROM sqlite_master}
} {t2}
do_test auth-1.133 {
  proc auth {code arg1 arg2 arg3 arg4} {
  proc auth {code arg1 arg2 arg3 arg4 args} {
    if {$code=="SQLITE_INSERT" && $arg1=="sqlite_master"} {
      return SQLITE_IGNORE
    }
    return SQLITE_OK
  }
  catchsql {
    CREATE TRIGGER r2 DELETE on t2 BEGIN
        SELECT NULL;
    END;
  }
} {0 {}}
do_test auth-1.134 {
  execsql {SELECT name FROM sqlite_master}
} {t2}
do_test auth-1.135 {
  proc auth {code arg1 arg2 arg3 arg4} {
  proc auth {code arg1 arg2 arg3 arg4 args} {
    if {$code=="SQLITE_CREATE_TRIGGER"} {
      set ::authargs [list $arg1 $arg2 $arg3 $arg4]
      return SQLITE_OK
    }
    return SQLITE_OK
  }
  catchsql {
940
941
942
943
944
945
946
947

948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966

967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986

987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002

1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022

1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038

1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059

1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071

1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087

1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099

1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115

1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136

1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148

1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164

1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176

1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192

1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210

1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226

1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238

1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254

1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266

1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284

1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300

1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312

1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328

1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340

1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358

1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370

1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386

1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398

1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414

1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432

1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444

1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460

1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472

1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488

1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506

1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522

1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538

1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551

1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568

1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581

1582
1583
1584
1585
1586
1587
1588
940
941
942
943
944
945
946

947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965

966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985

986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001

1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021

1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037

1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058

1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070

1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086

1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098

1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114

1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135

1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147

1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163

1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175

1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191

1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209

1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225

1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237

1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253

1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265

1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283

1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299

1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311

1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327

1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339

1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357

1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369

1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385

1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397

1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413

1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431

1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443

1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459

1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471

1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487

1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505

1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521

1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537

1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550

1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567

1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580

1581
1582
1583
1584
1585
1586
1587
1588







-
+


















-
+



















-
+















-
+



















-
+















-
+




















-
+











-
+















-
+











-
+















-
+




















-
+











-
+















-
+











-
+















-
+

















-
+















-
+











-
+















-
+











-
+

















-
+















-
+











-
+















-
+











-
+

















-
+











-
+















-
+











-
+















-
+

















-
+











-
+















-
+











-
+















-
+

















-
+















-
+















-
+












-
+
















-
+












-
+







} {r2 t2 main {}}
do_test auth-1.136.2 {
  execsql {
    SELECT name FROM sqlite_master WHERE type='trigger'
  }
} {r2}
do_test auth-1.136.3 {
  proc auth {code arg1 arg2 arg3 arg4} {
  proc auth {code arg1 arg2 arg3 arg4 args} {
    lappend ::authargs $code $arg1 $arg2 $arg3 $arg4
    return SQLITE_OK
  }
  set ::authargs {}
  execsql {
    INSERT INTO t2 VALUES(1,2,3);
  }
  set ::authargs 
} {SQLITE_INSERT t2 {} main {} SQLITE_INSERT tx {} main r2 SQLITE_READ t2 ROWID main r2}
do_test auth-1.136.4 {
  execsql {
    SELECT * FROM tx;
  }
} {3}
do_test auth-1.137 {
  execsql {SELECT name FROM sqlite_master}
} {t2 tx r2}
do_test auth-1.138 {
  proc auth {code arg1 arg2 arg3 arg4} {
  proc auth {code arg1 arg2 arg3 arg4 args} {
    if {$code=="SQLITE_CREATE_TEMP_TRIGGER"} {
      set ::authargs [list $arg1 $arg2 $arg3 $arg4]
      return SQLITE_DENY
    }
    return SQLITE_OK
  }
  catchsql {
    CREATE TRIGGER r1 DELETE on t1 BEGIN
        SELECT NULL;
    END;
  }
} {1 {not authorized}}
do_test auth-1.139 {
  set ::authargs
} {r1 t1 temp {}}
do_test auth-1.140 {
  execsql {SELECT name FROM sqlite_temp_master}
} {t1}
do_test auth-1.141 {
  proc auth {code arg1 arg2 arg3 arg4} {
  proc auth {code arg1 arg2 arg3 arg4 args} {
    if {$code=="SQLITE_INSERT" && $arg1=="sqlite_temp_master"} {
      return SQLITE_DENY
    }
    return SQLITE_OK
  }
  catchsql {
    CREATE TRIGGER r1 DELETE on t1 BEGIN
        SELECT NULL;
    END;
  }
} {1 {not authorized}}
do_test auth-1.142 {
  execsql {SELECT name FROM sqlite_temp_master}
} {t1}
do_test auth-1.143 {
  proc auth {code arg1 arg2 arg3 arg4} {
  proc auth {code arg1 arg2 arg3 arg4 args} {
    if {$code=="SQLITE_CREATE_TEMP_TRIGGER"} {
      set ::authargs [list $arg1 $arg2 $arg3 $arg4]
      return SQLITE_IGNORE
    }
    return SQLITE_OK
  }
  catchsql {
    CREATE TRIGGER r1 DELETE on t1 BEGIN
        SELECT NULL;
    END;
  }
} {0 {}}
do_test auth-1.144 {
  set ::authargs
} {r1 t1 temp {}}
do_test auth-1.145 {
  execsql {SELECT name FROM sqlite_temp_master}
} {t1}
do_test auth-1.146 {
  proc auth {code arg1 arg2 arg3 arg4} {
  proc auth {code arg1 arg2 arg3 arg4 args} {
    if {$code=="SQLITE_INSERT" && $arg1=="sqlite_temp_master"} {
      return SQLITE_IGNORE
    }
    return SQLITE_OK
  }
  catchsql {
    CREATE TRIGGER r1 DELETE on t1 BEGIN
        SELECT NULL;
    END;
  }
} {0 {}}
do_test auth-1.147 {
  execsql {SELECT name FROM sqlite_temp_master}
} {t1}
do_test auth-1.148 {
  proc auth {code arg1 arg2 arg3 arg4} {
  proc auth {code arg1 arg2 arg3 arg4 args} {
    if {$code=="SQLITE_CREATE_TEMP_TRIGGER"} {
      set ::authargs [list $arg1 $arg2 $arg3 $arg4]
      return SQLITE_OK
    }
    return SQLITE_OK
  }
  catchsql {
    CREATE TRIGGER r1 DELETE on t1 BEGIN
        SELECT NULL;
    END;
  }
} {0 {}}
do_test auth-1.149 {
  set ::authargs
} {r1 t1 temp {}}
do_test auth-1.150 {
  execsql {SELECT name FROM sqlite_temp_master}
} {t1 r1}

do_test auth-1.151 {
  proc auth {code arg1 arg2 arg3 arg4} {
  proc auth {code arg1 arg2 arg3 arg4 args} {
    if {$code=="SQLITE_DELETE" && $arg1=="sqlite_master"} {
      return SQLITE_DENY
    }
    return SQLITE_OK
  }
  catchsql {DROP TRIGGER r2}
} {1 {not authorized}}
do_test auth-1.152 {
  execsql {SELECT name FROM sqlite_master}
} {t2 tx r2}
do_test auth-1.153 {
  proc auth {code arg1 arg2 arg3 arg4} {
  proc auth {code arg1 arg2 arg3 arg4 args} {
    if {$code=="SQLITE_DROP_TRIGGER"} {
      set ::authargs [list $arg1 $arg2 $arg3 $arg4]
      return SQLITE_DENY
    }
    return SQLITE_OK
  }
  catchsql {DROP TRIGGER r2}
} {1 {not authorized}}
do_test auth-1.154 {
  set ::authargs
} {r2 t2 main {}}
do_test auth-1.155 {
  execsql {SELECT name FROM sqlite_master}
} {t2 tx r2}
do_test auth-1.156 {
  proc auth {code arg1 arg2 arg3 arg4} {
  proc auth {code arg1 arg2 arg3 arg4 args} {
    if {$code=="SQLITE_DELETE" && $arg1=="sqlite_master"} {
      return SQLITE_IGNORE
    }
    return SQLITE_OK
  }
  catchsql {DROP TRIGGER r2}
} {0 {}}
do_test auth-1.157 {
  execsql {SELECT name FROM sqlite_master}
} {t2 tx r2}
do_test auth-1.158 {
  proc auth {code arg1 arg2 arg3 arg4} {
  proc auth {code arg1 arg2 arg3 arg4 args} {
    if {$code=="SQLITE_DROP_TRIGGER"} {
      set ::authargs [list $arg1 $arg2 $arg3 $arg4]
      return SQLITE_IGNORE
    }
    return SQLITE_OK
  }
  catchsql {DROP TRIGGER r2}
} {0 {}}
do_test auth-1.159 {
  set ::authargs
} {r2 t2 main {}}
do_test auth-1.160 {
  execsql {SELECT name FROM sqlite_master}
} {t2 tx r2}
do_test auth-1.161 {
  proc auth {code arg1 arg2 arg3 arg4} {
  proc auth {code arg1 arg2 arg3 arg4 args} {
    if {$code=="SQLITE_DROP_TRIGGER"} {
      set ::authargs [list $arg1 $arg2 $arg3 $arg4]
      return SQLITE_OK
    }
    return SQLITE_OK
  }
  catchsql {DROP TRIGGER r2}
} {0 {}}
do_test auth-1.162 {
  set ::authargs
} {r2 t2 main {}}
do_test auth-1.163 {
  execsql {
    DROP TABLE tx;
    DELETE FROM t2 WHERE a=1 AND b=2 AND c=3;
    SELECT name FROM sqlite_master;
  }
} {t2}

do_test auth-1.164 {
  proc auth {code arg1 arg2 arg3 arg4} {
  proc auth {code arg1 arg2 arg3 arg4 args} {
    if {$code=="SQLITE_DELETE" && $arg1=="sqlite_temp_master"} {
      return SQLITE_DENY
    }
    return SQLITE_OK
  }
  catchsql {DROP TRIGGER r1}
} {1 {not authorized}}
do_test auth-1.165 {
  execsql {SELECT name FROM sqlite_temp_master}
} {t1 r1}
do_test auth-1.166 {
  proc auth {code arg1 arg2 arg3 arg4} {
  proc auth {code arg1 arg2 arg3 arg4 args} {
    if {$code=="SQLITE_DROP_TEMP_TRIGGER"} {
      set ::authargs [list $arg1 $arg2 $arg3 $arg4]
      return SQLITE_DENY
    }
    return SQLITE_OK
  }
  catchsql {DROP TRIGGER r1}
} {1 {not authorized}}
do_test auth-1.167 {
  set ::authargs
} {r1 t1 temp {}}
do_test auth-1.168 {
  execsql {SELECT name FROM sqlite_temp_master}
} {t1 r1}
do_test auth-1.169 {
  proc auth {code arg1 arg2 arg3 arg4} {
  proc auth {code arg1 arg2 arg3 arg4 args} {
    if {$code=="SQLITE_DELETE" && $arg1=="sqlite_temp_master"} {
      return SQLITE_IGNORE
    }
    return SQLITE_OK
  }
  catchsql {DROP TRIGGER r1}
} {0 {}}
do_test auth-1.170 {
  execsql {SELECT name FROM sqlite_temp_master}
} {t1 r1}
do_test auth-1.171 {
  proc auth {code arg1 arg2 arg3 arg4} {
  proc auth {code arg1 arg2 arg3 arg4 args} {
    if {$code=="SQLITE_DROP_TEMP_TRIGGER"} {
      set ::authargs [list $arg1 $arg2 $arg3 $arg4]
      return SQLITE_IGNORE
    }
    return SQLITE_OK
  }
  catchsql {DROP TRIGGER r1}
} {0 {}}
do_test auth-1.172 {
  set ::authargs
} {r1 t1 temp {}}
do_test auth-1.173 {
  execsql {SELECT name FROM sqlite_temp_master}
} {t1 r1}
do_test auth-1.174 {
  proc auth {code arg1 arg2 arg3 arg4} {
  proc auth {code arg1 arg2 arg3 arg4 args} {
    if {$code=="SQLITE_DROP_TEMP_TRIGGER"} {
      set ::authargs [list $arg1 $arg2 $arg3 $arg4]
      return SQLITE_OK
    }
    return SQLITE_OK
  }
  catchsql {DROP TRIGGER r1}
} {0 {}}
do_test auth-1.175 {
  set ::authargs
} {r1 t1 temp {}}
do_test auth-1.176 {
  execsql {SELECT name FROM sqlite_temp_master}
} {t1}
} ;# ifcapable trigger

do_test auth-1.177 {
  proc auth {code arg1 arg2 arg3 arg4} {
  proc auth {code arg1 arg2 arg3 arg4 args} {
    if {$code=="SQLITE_CREATE_INDEX"} {
      set ::authargs [list $arg1 $arg2 $arg3 $arg4]
      return SQLITE_DENY
    }
    return SQLITE_OK
  }
  catchsql {CREATE INDEX i2 ON t2(a)}
} {1 {not authorized}}
do_test auth-1.178 {
  set ::authargs
} {i2 t2 main {}}
do_test auth-1.179 {
  execsql {SELECT name FROM sqlite_master}
} {t2}
do_test auth-1.180 {
  proc auth {code arg1 arg2 arg3 arg4} {
  proc auth {code arg1 arg2 arg3 arg4 args} {
    if {$code=="SQLITE_INSERT" && $arg1=="sqlite_master"} {
      return SQLITE_DENY
    }
    return SQLITE_OK
  }
  catchsql {CREATE INDEX i2 ON t2(a)}
} {1 {not authorized}}
do_test auth-1.181 {
  execsql {SELECT name FROM sqlite_master}
} {t2}
do_test auth-1.182 {
  proc auth {code arg1 arg2 arg3 arg4} {
  proc auth {code arg1 arg2 arg3 arg4 args} {
    if {$code=="SQLITE_CREATE_INDEX"} {
      set ::authargs [list $arg1 $arg2 $arg3 $arg4]
      return SQLITE_IGNORE
    }
    return SQLITE_OK
  }
  catchsql {CREATE INDEX i2 ON t2(b)}
} {0 {}}
do_test auth-1.183 {
  set ::authargs
} {i2 t2 main {}}
do_test auth-1.184 {
  execsql {SELECT name FROM sqlite_master}
} {t2}
do_test auth-1.185 {
  proc auth {code arg1 arg2 arg3 arg4} {
  proc auth {code arg1 arg2 arg3 arg4 args} {
    if {$code=="SQLITE_INSERT" && $arg1=="sqlite_master"} {
      return SQLITE_IGNORE
    }
    return SQLITE_OK
  }
  catchsql {CREATE INDEX i2 ON t2(b)}
} {0 {}}
do_test auth-1.186 {
  execsql {SELECT name FROM sqlite_master}
} {t2}
do_test auth-1.187 {
  proc auth {code arg1 arg2 arg3 arg4} {
  proc auth {code arg1 arg2 arg3 arg4 args} {
    if {$code=="SQLITE_CREATE_INDEX"} {
      set ::authargs [list $arg1 $arg2 $arg3 $arg4]
      return SQLITE_OK
    }
    return SQLITE_OK
  }
  catchsql {CREATE INDEX i2 ON t2(a)}
} {0 {}}
do_test auth-1.188 {
  set ::authargs
} {i2 t2 main {}}
do_test auth-1.189 {
  execsql {SELECT name FROM sqlite_master}
} {t2 i2}

ifcapable tempdb {
  do_test auth-1.190 {
    proc auth {code arg1 arg2 arg3 arg4} {
    proc auth {code arg1 arg2 arg3 arg4 args} {
      if {$code=="SQLITE_CREATE_TEMP_INDEX"} {
        set ::authargs [list $arg1 $arg2 $arg3 $arg4]
        return SQLITE_DENY
      }
      return SQLITE_OK
    }
    catchsql {CREATE INDEX i1 ON t1(a)}
  } {1 {not authorized}}
  do_test auth-1.191 {
    set ::authargs
  } {i1 t1 temp {}}
  do_test auth-1.192 {
    execsql {SELECT name FROM sqlite_temp_master}
  } {t1}
  do_test auth-1.193 {
    proc auth {code arg1 arg2 arg3 arg4} {
    proc auth {code arg1 arg2 arg3 arg4 args} {
      if {$code=="SQLITE_INSERT" && $arg1=="sqlite_temp_master"} {
        return SQLITE_DENY
      }
      return SQLITE_OK
    }
    catchsql {CREATE INDEX i1 ON t1(b)}
  } {1 {not authorized}}
  do_test auth-1.194 {
    execsql {SELECT name FROM sqlite_temp_master}
  } {t1}
  do_test auth-1.195 {
    proc auth {code arg1 arg2 arg3 arg4} {
    proc auth {code arg1 arg2 arg3 arg4 args} {
      if {$code=="SQLITE_CREATE_TEMP_INDEX"} {
        set ::authargs [list $arg1 $arg2 $arg3 $arg4]
        return SQLITE_IGNORE
      }
      return SQLITE_OK
    }
    catchsql {CREATE INDEX i1 ON t1(b)}
  } {0 {}}
  do_test auth-1.196 {
    set ::authargs
  } {i1 t1 temp {}}
  do_test auth-1.197 {
    execsql {SELECT name FROM sqlite_temp_master}
  } {t1}
  do_test auth-1.198 {
    proc auth {code arg1 arg2 arg3 arg4} {
    proc auth {code arg1 arg2 arg3 arg4 args} {
      if {$code=="SQLITE_INSERT" && $arg1=="sqlite_temp_master"} {
        return SQLITE_IGNORE
      }
      return SQLITE_OK
    }
    catchsql {CREATE INDEX i1 ON t1(c)}
  } {0 {}}
  do_test auth-1.199 {
    execsql {SELECT name FROM sqlite_temp_master}
  } {t1}
  do_test auth-1.200 {
    proc auth {code arg1 arg2 arg3 arg4} {
    proc auth {code arg1 arg2 arg3 arg4 args} {
      if {$code=="SQLITE_CREATE_TEMP_INDEX"} {
        set ::authargs [list $arg1 $arg2 $arg3 $arg4]
        return SQLITE_OK
      }
      return SQLITE_OK
    }
    catchsql {CREATE INDEX i1 ON t1(a)}
  } {0 {}}
  do_test auth-1.201 {
    set ::authargs
  } {i1 t1 temp {}}
  do_test auth-1.202 {
    execsql {SELECT name FROM sqlite_temp_master}
  } {t1 i1}
}

do_test auth-1.203 {
  proc auth {code arg1 arg2 arg3 arg4} {
  proc auth {code arg1 arg2 arg3 arg4 args} {
    if {$code=="SQLITE_DELETE" && $arg1=="sqlite_master"} {
      return SQLITE_DENY
    }
    return SQLITE_OK
  }
  catchsql {DROP INDEX i2}
} {1 {not authorized}}
do_test auth-1.204 {
  execsql {SELECT name FROM sqlite_master}
} {t2 i2}
do_test auth-1.205 {
  proc auth {code arg1 arg2 arg3 arg4} {
  proc auth {code arg1 arg2 arg3 arg4 args} {
    if {$code=="SQLITE_DROP_INDEX"} {
      set ::authargs [list $arg1 $arg2 $arg3 $arg4]
      return SQLITE_DENY
    }
    return SQLITE_OK
  }
  catchsql {DROP INDEX i2}
} {1 {not authorized}}
do_test auth-1.206 {
  set ::authargs
} {i2 t2 main {}}
do_test auth-1.207 {
  execsql {SELECT name FROM sqlite_master}
} {t2 i2}
do_test auth-1.208 {
  proc auth {code arg1 arg2 arg3 arg4} {
  proc auth {code arg1 arg2 arg3 arg4 args} {
    if {$code=="SQLITE_DELETE" && $arg1=="sqlite_master"} {
      return SQLITE_IGNORE
    }
    return SQLITE_OK
  }
  catchsql {DROP INDEX i2}
} {0 {}}
do_test auth-1.209 {
  execsql {SELECT name FROM sqlite_master}
} {t2 i2}
do_test auth-1.210 {
  proc auth {code arg1 arg2 arg3 arg4} {
  proc auth {code arg1 arg2 arg3 arg4 args} {
    if {$code=="SQLITE_DROP_INDEX"} {
      set ::authargs [list $arg1 $arg2 $arg3 $arg4]
      return SQLITE_IGNORE
    }
    return SQLITE_OK
  }
  catchsql {DROP INDEX i2}
} {0 {}}
do_test auth-1.211 {
  set ::authargs
} {i2 t2 main {}}
do_test auth-1.212 {
  execsql {SELECT name FROM sqlite_master}
} {t2 i2}
do_test auth-1.213 {
  proc auth {code arg1 arg2 arg3 arg4} {
  proc auth {code arg1 arg2 arg3 arg4 args} {
    if {$code=="SQLITE_DROP_INDEX"} {
      set ::authargs [list $arg1 $arg2 $arg3 $arg4]
      return SQLITE_OK
    }
    return SQLITE_OK
  }
  catchsql {DROP INDEX i2}
} {0 {}}
do_test auth-1.214 {
  set ::authargs
} {i2 t2 main {}}
do_test auth-1.215 {
  execsql {SELECT name FROM sqlite_master}
} {t2}

ifcapable tempdb {
  do_test auth-1.216 {
    proc auth {code arg1 arg2 arg3 arg4} {
    proc auth {code arg1 arg2 arg3 arg4 args} {
      if {$code=="SQLITE_DELETE" && $arg1=="sqlite_temp_master"} {
        return SQLITE_DENY
      }
      return SQLITE_OK
    }
    catchsql {DROP INDEX i1}
  } {1 {not authorized}}
  do_test auth-1.217 {
    execsql {SELECT name FROM sqlite_temp_master}
  } {t1 i1}
  do_test auth-1.218 {
    proc auth {code arg1 arg2 arg3 arg4} {
    proc auth {code arg1 arg2 arg3 arg4 args} {
      if {$code=="SQLITE_DROP_TEMP_INDEX"} {
        set ::authargs [list $arg1 $arg2 $arg3 $arg4]
        return SQLITE_DENY
      }
      return SQLITE_OK
    }
    catchsql {DROP INDEX i1}
  } {1 {not authorized}}
  do_test auth-1.219 {
    set ::authargs
  } {i1 t1 temp {}}
  do_test auth-1.220 {
    execsql {SELECT name FROM sqlite_temp_master}
  } {t1 i1}
  do_test auth-1.221 {
    proc auth {code arg1 arg2 arg3 arg4} {
    proc auth {code arg1 arg2 arg3 arg4 args} {
      if {$code=="SQLITE_DELETE" && $arg1=="sqlite_temp_master"} {
        return SQLITE_IGNORE
      }
      return SQLITE_OK
    }
    catchsql {DROP INDEX i1}
  } {0 {}}
  do_test auth-1.222 {
    execsql {SELECT name FROM sqlite_temp_master}
  } {t1 i1}
  do_test auth-1.223 {
    proc auth {code arg1 arg2 arg3 arg4} {
    proc auth {code arg1 arg2 arg3 arg4 args} {
      if {$code=="SQLITE_DROP_TEMP_INDEX"} {
        set ::authargs [list $arg1 $arg2 $arg3 $arg4]
        return SQLITE_IGNORE
      }
      return SQLITE_OK
    }
    catchsql {DROP INDEX i1}
  } {0 {}}
  do_test auth-1.224 {
    set ::authargs
  } {i1 t1 temp {}}
  do_test auth-1.225 {
    execsql {SELECT name FROM sqlite_temp_master}
  } {t1 i1}
  do_test auth-1.226 {
    proc auth {code arg1 arg2 arg3 arg4} {
    proc auth {code arg1 arg2 arg3 arg4 args} {
      if {$code=="SQLITE_DROP_TEMP_INDEX"} {
        set ::authargs [list $arg1 $arg2 $arg3 $arg4]
        return SQLITE_OK
      }
      return SQLITE_OK
    }
    catchsql {DROP INDEX i1}
  } {0 {}}
  do_test auth-1.227 {
    set ::authargs
  } {i1 t1 temp {}}
  do_test auth-1.228 {
    execsql {SELECT name FROM sqlite_temp_master}
  } {t1}
}

do_test auth-1.229 {
  proc auth {code arg1 arg2 arg3 arg4} {
  proc auth {code arg1 arg2 arg3 arg4 args} {
    if {$code=="SQLITE_PRAGMA"} {
      set ::authargs [list $arg1 $arg2 $arg3 $arg4]
      return SQLITE_DENY
    }
    return SQLITE_OK
  }
  catchsql {PRAGMA full_column_names=on}
} {1 {not authorized}}
do_test auth-1.230 {
  set ::authargs
} {full_column_names on {} {}}
do_test auth-1.231 {
  execsql2 {SELECT a FROM t2}
} {a 11 a 7}
do_test auth-1.232 {
  proc auth {code arg1 arg2 arg3 arg4} {
  proc auth {code arg1 arg2 arg3 arg4 args} {
    if {$code=="SQLITE_PRAGMA"} {
      set ::authargs [list $arg1 $arg2 $arg3 $arg4]
      return SQLITE_IGNORE
    }
    return SQLITE_OK
  }
  catchsql {PRAGMA full_column_names=on}
} {0 {}}
do_test auth-1.233 {
  set ::authargs
} {full_column_names on {} {}}
do_test auth-1.234 {
  execsql2 {SELECT a FROM t2}
} {a 11 a 7}
do_test auth-1.235 {
  proc auth {code arg1 arg2 arg3 arg4} {
  proc auth {code arg1 arg2 arg3 arg4 args} {
    if {$code=="SQLITE_PRAGMA"} {
      set ::authargs [list $arg1 $arg2 $arg3 $arg4]
      return SQLITE_OK
    }
    return SQLITE_OK
  }
  catchsql {PRAGMA full_column_names=on}
} {0 {}}
do_test auth-1.236 {
  execsql2 {SELECT a FROM t2}
} {t2.a 11 t2.a 7}
do_test auth-1.237 {
  proc auth {code arg1 arg2 arg3 arg4} {
  proc auth {code arg1 arg2 arg3 arg4 args} {
    if {$code=="SQLITE_PRAGMA"} {
      set ::authargs [list $arg1 $arg2 $arg3 $arg4]
      return SQLITE_OK
    }
    return SQLITE_OK
  }
  catchsql {PRAGMA full_column_names=OFF}
} {0 {}}
do_test auth-1.238 {
  set ::authargs
} {full_column_names OFF {} {}}
do_test auth-1.239 {
  execsql2 {SELECT a FROM t2}
} {a 11 a 7}

do_test auth-1.240 {
  proc auth {code arg1 arg2 arg3 arg4} {
  proc auth {code arg1 arg2 arg3 arg4 args} {
    if {$code=="SQLITE_TRANSACTION"} {
      set ::authargs [list $arg1 $arg2 $arg3 $arg4]
      return SQLITE_DENY
    }
    return SQLITE_OK
  }
  catchsql {BEGIN}
} {1 {not authorized}}
do_test auth-1.241 {
  set ::authargs
} {BEGIN {} {} {}}
do_test auth-1.242 {
  proc auth {code arg1 arg2 arg3 arg4} {
  proc auth {code arg1 arg2 arg3 arg4 args} {
    if {$code=="SQLITE_TRANSACTION" && $arg1!="BEGIN"} {
      set ::authargs [list $arg1 $arg2 $arg3 $arg4]
      return SQLITE_DENY
    }
    return SQLITE_OK
  }
  catchsql {BEGIN; INSERT INTO t2 VALUES(44,55,66); COMMIT}
1614
1615
1616
1617
1618
1619
1620
1621

1622
1623
1624
1625
1626
1627
1628
1614
1615
1616
1617
1618
1619
1620

1621
1622
1623
1624
1625
1626
1627
1628







-
+







} {11 2 33 7 8 9}

# ticket #340 - authorization for ATTACH and DETACH.
#
ifcapable attach {
  do_test auth-1.251 {
    db authorizer ::auth
    proc auth {code arg1 arg2 arg3 arg4} {
    proc auth {code arg1 arg2 arg3 arg4 args} {
      if {$code=="SQLITE_ATTACH"} {
        set ::authargs [list $arg1 $arg2 $arg3 $arg4]
      }
      return SQLITE_OK
    }
    catchsql {
      ATTACH DATABASE ':memory:' AS test1
1640
1641
1642
1643
1644
1645
1646
1647

1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663

1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678

1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695

1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713

1714
1715
1716
1717
1718
1719
1720
1640
1641
1642
1643
1644
1645
1646

1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662

1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677

1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694

1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712

1713
1714
1715
1716
1717
1718
1719
1720







-
+















-
+














-
+
















-
+

















-
+







  do_test auth-1.252c {
    db eval {DETACH test1}
    db eval {ATTACH ':mem' || 'ory:' AS test1}
    set ::authargs
  } {{} {} {} {}}
  do_test auth-1.253 {
    catchsql {DETACH DATABASE test1}
    proc auth {code arg1 arg2 arg3 arg4} {
    proc auth {code arg1 arg2 arg3 arg4 args} {
      if {$code=="SQLITE_ATTACH"} {
        set ::authargs [list $arg1 $arg2 $arg3 $arg4]
        return SQLITE_DENY
      }
      return SQLITE_OK
    }
    catchsql {
      ATTACH DATABASE ':memory:' AS test1;
    }
  } {1 {not authorized}}
  do_test auth-1.254 {
    lindex [execsql {PRAGMA database_list}] 7
  } {}
  do_test auth-1.255 {
    catchsql {DETACH DATABASE test1}
    proc auth {code arg1 arg2 arg3 arg4} {
    proc auth {code arg1 arg2 arg3 arg4 args} {
      if {$code=="SQLITE_ATTACH"} {
        set ::authargs [list $arg1 $arg2 $arg3 $arg4]
        return SQLITE_IGNORE
      }
      return SQLITE_OK
    }
    catchsql {
      ATTACH DATABASE ':memory:' AS test1;
    }
  } {0 {}}
  do_test auth-1.256 {
    lindex [execsql {PRAGMA database_list}] 7
  } {}
  do_test auth-1.257 {
    proc auth {code arg1 arg2 arg3 arg4} {
    proc auth {code arg1 arg2 arg3 arg4 args} {
      if {$code=="SQLITE_DETACH"} {
        set ::authargs [list $arg1 $arg2 $arg3 $arg4]
        return SQLITE_OK
      }
      return SQLITE_OK
    }
    execsql {ATTACH DATABASE ':memory:' AS test1}
    catchsql {
      DETACH DATABASE test1;
    }
  } {0 {}}
  do_test auth-1.258 {
    lindex [execsql {PRAGMA database_list}] 7
  } {}
  do_test auth-1.259 {
    execsql {ATTACH DATABASE ':memory:' AS test1}
    proc auth {code arg1 arg2 arg3 arg4} {
    proc auth {code arg1 arg2 arg3 arg4 args} {
      if {$code=="SQLITE_DETACH"} {
        set ::authargs [list $arg1 $arg2 $arg3 $arg4]
        return SQLITE_IGNORE
      }
      return SQLITE_OK
    }
    catchsql {
      DETACH DATABASE test1;
    }
  } {0 {}}
  ifcapable tempdb {
    ifcapable schema_pragmas {
    do_test auth-1.260 {
      lindex [execsql {PRAGMA database_list}] 7
    } {test1}
    } ;# ifcapable schema_pragmas
    do_test auth-1.261 {
      proc auth {code arg1 arg2 arg3 arg4} {
      proc auth {code arg1 arg2 arg3 arg4 args} {
        if {$code=="SQLITE_DETACH"} {
          set ::authargs [list $arg1 $arg2 $arg3 $arg4]
          return SQLITE_DENY
        }
        return SQLITE_OK
      }
      catchsql {
1731
1732
1733
1734
1735
1736
1737
1738

1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756

1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774

1775
1776
1777
1778
1779
1780
1781
1731
1732
1733
1734
1735
1736
1737

1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755

1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773

1774
1775
1776
1777
1778
1779
1780
1781







-
+

















-
+

















-
+







    db authorizer ::auth
    
    # Authorization for ALTER TABLE. These tests are omitted if the library
    # was built without ALTER TABLE support.
    ifcapable altertable {
    
      do_test auth-1.263 {
        proc auth {code arg1 arg2 arg3 arg4} {
        proc auth {code arg1 arg2 arg3 arg4 args} {
          if {$code=="SQLITE_ALTER_TABLE"} {
            set ::authargs [list $arg1 $arg2 $arg3 $arg4]
            return SQLITE_OK
          }
          return SQLITE_OK
        }
        catchsql {
          ALTER TABLE t1 RENAME TO t1x
        }
      } {0 {}}
      do_test auth-1.264 {
        execsql {SELECT name FROM sqlite_temp_master WHERE type='table'}
      } {t1x}
      do_test auth-1.265 {
        set authargs
      } {temp t1 {} {}}
      do_test auth-1.266 {
        proc auth {code arg1 arg2 arg3 arg4} {
        proc auth {code arg1 arg2 arg3 arg4 args} {
          if {$code=="SQLITE_ALTER_TABLE"} {
            set ::authargs [list $arg1 $arg2 $arg3 $arg4]
            return SQLITE_IGNORE
          }
          return SQLITE_OK
        }
        catchsql {
          ALTER TABLE t1x RENAME TO t1
        }
      } {0 {}}
      do_test auth-1.267 {
        execsql {SELECT name FROM sqlite_temp_master WHERE type='table'}
      } {t1x}
      do_test auth-1.268 {
        set authargs
      } {temp t1x {} {}}
      do_test auth-1.269 {
        proc auth {code arg1 arg2 arg3 arg4} {
        proc auth {code arg1 arg2 arg3 arg4 args} {
          if {$code=="SQLITE_ALTER_TABLE"} {
            set ::authargs [list $arg1 $arg2 $arg3 $arg4]
            return SQLITE_DENY
          }
          return SQLITE_OK
        }
        catchsql {
1800
1801
1802
1803
1804
1805
1806
1807

1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825

1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843

1844
1845
1846
1847
1848
1849
1850
1800
1801
1802
1803
1804
1805
1806

1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824

1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842

1843
1844
1845
1846
1847
1848
1849
1850







-
+

















-
+

















-
+







}

ifcapable  altertable {
db authorizer {}
catchsql {ALTER TABLE t1x RENAME TO t1}
db authorizer ::auth
do_test auth-1.272 {
  proc auth {code arg1 arg2 arg3 arg4} {
  proc auth {code arg1 arg2 arg3 arg4 args} {
    if {$code=="SQLITE_ALTER_TABLE"} {
      set ::authargs [list $arg1 $arg2 $arg3 $arg4]
      return SQLITE_OK
    }
    return SQLITE_OK
  }
  catchsql {
    ALTER TABLE t2 RENAME TO t2x
  }
} {0 {}}
do_test auth-1.273 {
  execsql {SELECT name FROM sqlite_master WHERE type='table'}
} {t2x}
do_test auth-1.274 {
  set authargs
} {main t2 {} {}}
do_test auth-1.275 {
  proc auth {code arg1 arg2 arg3 arg4} {
  proc auth {code arg1 arg2 arg3 arg4 args} {
    if {$code=="SQLITE_ALTER_TABLE"} {
      set ::authargs [list $arg1 $arg2 $arg3 $arg4]
      return SQLITE_IGNORE
    }
    return SQLITE_OK
  }
  catchsql {
    ALTER TABLE t2x RENAME TO t2
  }
} {0 {}}
do_test auth-1.276 {
  execsql {SELECT name FROM sqlite_master WHERE type='table'}
} {t2x}
do_test auth-1.277 {
  set authargs
} {main t2x {} {}}
do_test auth-1.278 {
  proc auth {code arg1 arg2 arg3 arg4} {
  proc auth {code arg1 arg2 arg3 arg4 args} {
    if {$code=="SQLITE_ALTER_TABLE"} {
      set ::authargs [list $arg1 $arg2 $arg3 $arg4]
      return SQLITE_DENY
    }
    return SQLITE_OK
  }
  catchsql {
1863
1864
1865
1866
1867
1868
1869
1870

1871
1872
1873
1874
1875
1876
1877
1863
1864
1865
1866
1867
1868
1869

1870
1871
1872
1873
1874
1875
1876
1877







-
+







} ;# ifcapable altertable

# Test the authorization callbacks for the REINDEX command.
ifcapable reindex {

proc auth {code args} {
  if {$code=="SQLITE_REINDEX"} {
    set ::authargs [concat $::authargs $args]
    set ::authargs [concat $::authargs [lrange $args 0 3]]
  }
  return SQLITE_OK
}
db authorizer auth
do_test auth-1.281 {
  execsql {
    CREATE TABLE t3(a PRIMARY KEY, b, c);
1946
1947
1948
1949
1950
1951
1952
1953

1954
1955
1956
1957
1958
1959
1960
1946
1947
1948
1949
1950
1951
1952

1953
1954
1955
1956
1957
1958
1959
1960







-
+







    execsql {
      REINDEX temp.t3;
    }
    set ::authargs
  } {t3_idx2 {} temp {} t3_idx1 {} temp {} sqlite_autoindex_t3_1 {} temp {}}
  proc auth {code args} {
    if {$code=="SQLITE_REINDEX"} {
      set ::authargs [concat $::authargs $args]
      set ::authargs [concat $::authargs [lrange $args 0 3]]
      return SQLITE_DENY
    }
    return SQLITE_OK
  }
  do_test auth-1.292 {
    set ::authargs {}
    catchsql {
1969
1970
1971
1972
1973
1974
1975
1976

1977
1978
1979
1980
1981
1982
1983
1969
1970
1971
1972
1973
1974
1975

1976
1977
1978
1979
1980
1981
1982
1983







-
+







}

} ;# ifcapable reindex 

ifcapable analyze {
  proc auth {code args} {
    if {$code=="SQLITE_ANALYZE"} {
      set ::authargs [concat $::authargs $args]
      set ::authargs [concat $::authargs [lrange $args 0 3]]
    }
    return SQLITE_OK
  }
  do_test auth-1.294 {
    set ::authargs {}
    execsql {
      CREATE TABLE t4(a,b,c);
2016
2017
2018
2019
2020
2021
2022
2023

2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042

2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061

2062
2063
2064
2065
2066
2067
2068
2016
2017
2018
2019
2020
2021
2022

2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041

2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060

2061
2062
2063
2064
2065
2066
2067
2068







-
+


















-
+


















-
+








# Authorization for ALTER TABLE ADD COLUMN.
# These tests are omitted if the library
# was built without ALTER TABLE support.
ifcapable {altertable} {
  do_test auth-1.300 {
    execsql {CREATE TABLE t5(x)}
    proc auth {code arg1 arg2 arg3 arg4} {
    proc auth {code arg1 arg2 arg3 arg4 args} {
      if {$code=="SQLITE_ALTER_TABLE"} {
        set ::authargs [list $arg1 $arg2 $arg3 $arg4]
        return SQLITE_OK
      }
      return SQLITE_OK
    }
    catchsql {
      ALTER TABLE t5 ADD COLUMN new_col_1;
    }
  } {0 {}}
  do_test auth-1.301 {
    set x [execsql {SELECT sql FROM sqlite_master WHERE name='t5'}]
    regexp new_col_1 $x
  } {1}
  do_test auth-1.302 {
    set authargs
  } {main t5 {} {}}
  do_test auth-1.303 {
    proc auth {code arg1 arg2 arg3 arg4} {
    proc auth {code arg1 arg2 arg3 arg4 args} {
      if {$code=="SQLITE_ALTER_TABLE"} {
        set ::authargs [list $arg1 $arg2 $arg3 $arg4]
        return SQLITE_IGNORE
      }
      return SQLITE_OK
    }
    catchsql {
      ALTER TABLE t5 ADD COLUMN new_col_2;
    }
  } {0 {}}
  do_test auth-1.304 {
    set x [execsql {SELECT sql FROM sqlite_master WHERE name='t5'}]
    regexp new_col_2 $x
  } {0}
  do_test auth-1.305 {
    set authargs
  } {main t5 {} {}}
  do_test auth-1.306 {
    proc auth {code arg1 arg2 arg3 arg4} {
    proc auth {code arg1 arg2 arg3 arg4 args} {
      if {$code=="SQLITE_ALTER_TABLE"} {
        set ::authargs [list $arg1 $arg2 $arg3 $arg4]
        return SQLITE_DENY
      }
      return SQLITE_OK
    }
    catchsql {
2078
2079
2080
2081
2082
2083
2084
2085

2086
2087
2088
2089
2090
2091
2092
2078
2079
2080
2081
2082
2083
2084

2085
2086
2087
2088
2089
2090
2091
2092







-
+







    set authargs
  } {main t5 {} {}}
  execsql {DROP TABLE t5}
} ;# ifcapable altertable

ifcapable {cte} {
  do_test auth-1.310 {
    proc auth {code arg1 arg2 arg3 arg4} {
    proc auth {code arg1 arg2 arg3 arg4 args} {
      if {$code=="SQLITE_RECURSIVE"} {
        return SQLITE_DENY
      }
      return SQLITE_OK
    }
    db eval {
       DROP TABLE IF EXISTS t1;
2113
2114
2115
2116
2117
2118
2119
2120

2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140

2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153

2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165

2166
2167
2168
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184

2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196

2197
2198
2199
2200
2201
2202
2203
2204
2205

2206
2207
2208
2209
2210
2211
2212
2213
2214

2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227

2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240

2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258

2259
2260
2261
2262
2263
2264
2265
2113
2114
2115
2116
2117
2118
2119

2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139

2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152

2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164

2165
2166
2167
2168
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183

2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195

2196
2197
2198
2199
2200
2201
2202
2203
2204

2205
2206
2207
2208
2209
2210
2211
2212
2213

2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226

2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239

2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257

2258
2259
2260
2261
2262
2263
2264
2265







-
+



















-
+












-
+











-
+


















-
+











-
+








-
+








-
+












-
+












-
+

















-
+







    WITH RECURSIVE
       auth1314(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM auth1314 WHERE x<5)
    SELECT * FROM t1 LEFT JOIN auth1314;
  } {1 {not authorized}}
} ;# ifcapable cte

do_test auth-2.1 {
  proc auth {code arg1 arg2 arg3 arg4} {
  proc auth {code arg1 arg2 arg3 arg4 args} {
    if {$code=="SQLITE_READ" && $arg1=="t3" && $arg2=="x"} {
      return SQLITE_DENY
    }
    return SQLITE_OK
  }
  db authorizer ::auth
  execsql {CREATE TABLE t3(x INTEGER PRIMARY KEY, y, z)}
  catchsql {SELECT * FROM t3}
} {1 {access to t3.x is prohibited}}
do_test auth-2.1 {
  catchsql {SELECT y,z FROM t3}
} {0 {}}
do_test auth-2.2 {
  catchsql {SELECT ROWID,y,z FROM t3}
} {1 {access to t3.x is prohibited}}
do_test auth-2.3 {
  catchsql {SELECT OID,y,z FROM t3}
} {1 {access to t3.x is prohibited}}
do_test auth-2.4 {
  proc auth {code arg1 arg2 arg3 arg4} {
  proc auth {code arg1 arg2 arg3 arg4 args} {
    if {$code=="SQLITE_READ" && $arg1=="t3" && $arg2=="x"} {
      return SQLITE_IGNORE
    }
    return SQLITE_OK
  }
  execsql {INSERT INTO t3 VALUES(44,55,66)}
  catchsql {SELECT * FROM t3}
} {0 {{} 55 66}}
do_test auth-2.5 {
  catchsql {SELECT rowid,y,z FROM t3}
} {0 {{} 55 66}}
do_test auth-2.6 {
  proc auth {code arg1 arg2 arg3 arg4} {
  proc auth {code arg1 arg2 arg3 arg4 args} {
    if {$code=="SQLITE_READ" && $arg1=="t3" && $arg2=="ROWID"} {
      return SQLITE_IGNORE
    }
    return SQLITE_OK
  }
  catchsql {SELECT * FROM t3}
} {0 {44 55 66}}
do_test auth-2.7 {
  catchsql {SELECT ROWID,y,z FROM t3}
} {0 {44 55 66}}
do_test auth-2.8 {
  proc auth {code arg1 arg2 arg3 arg4} {
  proc auth {code arg1 arg2 arg3 arg4 args} {
    if {$code=="SQLITE_READ" && $arg1=="t2" && $arg2=="ROWID"} {
      return SQLITE_IGNORE
    }
    return SQLITE_OK
  }
  catchsql {SELECT ROWID,b,c FROM t2}
} {0 {{} 2 33 {} 8 9}}
do_test auth-2.9.1 {
  # We have to flush the cache here in case the Tcl interface tries to
  # reuse a statement compiled with sqlite3_prepare_v2(). In this case,
  # the first error encountered is an SQLITE_SCHEMA error. Then, when
  # trying to recompile the statement, the authorization error is encountered.
  # If we do not flush the cache, the correct error message is returned, but
  # the error code is SQLITE_SCHEMA, not SQLITE_ERROR as required by the test
  # case after this one.
  #
  db cache flush

  proc auth {code arg1 arg2 arg3 arg4} {
  proc auth {code arg1 arg2 arg3 arg4 args} {
    if {$code=="SQLITE_READ" && $arg1=="t2" && $arg2=="ROWID"} {
      return bogus
    }
    return SQLITE_OK
  }
  catchsql {SELECT ROWID,b,c FROM t2}
} {1 {authorizer malfunction}}
do_test auth-2.9.2 {
  db errorcode
} {1}
do_test auth-2.10 {
  proc auth {code arg1 arg2 arg3 arg4} {
  proc auth {code arg1 arg2 arg3 arg4 args} {
    if {$code=="SQLITE_SELECT"} {
      return bogus
    }
    return SQLITE_OK
  }
  catchsql {SELECT ROWID,b,c FROM t2}
} {1 {authorizer malfunction}}
do_test auth-2.11.1 {
  proc auth {code arg1 arg2 arg3 arg4} {
  proc auth {code arg1 arg2 arg3 arg4 args} {
    if {$code=="SQLITE_READ" && $arg2=="a"} {
      return SQLITE_IGNORE
    }
    return SQLITE_OK
  }
  catchsql {SELECT * FROM t2, t3}
} {0 {{} 2 33 44 55 66 {} 8 9 44 55 66}}
do_test auth-2.11.2 {
  proc auth {code arg1 arg2 arg3 arg4} {
  proc auth {code arg1 arg2 arg3 arg4 args} {
    if {$code=="SQLITE_READ" && $arg2=="x"} {
      return SQLITE_IGNORE
    }
    return SQLITE_OK
  }
  catchsql {SELECT * FROM t2, t3}
} {0 {11 2 33 {} 55 66 7 8 9 {} 55 66}}

# Make sure the OLD and NEW pseudo-tables of a trigger get authorized.
#
ifcapable trigger {
  do_test auth-3.1 {
    proc auth {code arg1 arg2 arg3 arg4} {
    proc auth {code arg1 arg2 arg3 arg4 args} {
      return SQLITE_OK
    }
    execsql {
      CREATE TABLE tx(a1,a2,b1,b2,c1,c2);
      CREATE TRIGGER r1 AFTER UPDATE ON t2 FOR EACH ROW BEGIN
        INSERT INTO tx VALUES(OLD.a,NEW.a,OLD.b,NEW.b,OLD.c,NEW.c);
      END;
      UPDATE t2 SET a=a+1;
      SELECT * FROM tx;
    }
  } {11 12 2 2 33 33 7 8 8 8 9 9}
  do_test auth-3.2 {
    proc auth {code arg1 arg2 arg3 arg4} {
    proc auth {code arg1 arg2 arg3 arg4 args} {
      if {$code=="SQLITE_READ" && $arg1=="t2" && $arg2=="c"} {
        return SQLITE_IGNORE
      }
      return SQLITE_OK
    }
    execsql {
      DELETE FROM tx;
      UPDATE t2 SET a=a+100;
      SELECT * FROM tx;
    }
  } {12 112 2 2 {} {} 8 108 8 8 {} {}}
} ;# ifcapable trigger

# Make sure the names of views and triggers are passed on on arg4.
#
ifcapable trigger {
do_test auth-4.1 {
  proc auth {code arg1 arg2 arg3 arg4} {
  proc auth {code arg1 arg2 arg3 arg4 args} {
    lappend ::authargs $code $arg1 $arg2 $arg3 $arg4
    return SQLITE_OK
  }
  set authargs {}
  execsql {
    UPDATE t2 SET a=a+1;
  }
2336
2337
2338
2339
2340
2341
2342
2343

2344
2345
2346
2347
2348
2349
2350
2336
2337
2338
2339
2340
2341
2342

2343
2344
2345
2346
2347
2348
2349
2350







-
+








} ;# ifcapable view && trigger

# Ticket #1338:  Make sure authentication works in the presence of an AS
# clause.
#
do_test auth-5.1 {
  proc auth {code arg1 arg2 arg3 arg4} {
  proc auth {code arg1 arg2 arg3 arg4 args} {
    return SQLITE_OK
  }
  execsql {
    SELECT count(a) AS cnt FROM t4 ORDER BY cnt
  }
} {1}

2389
2390
2391
2392
2393
2394
2395
2396

2397
2398
2399
2400
2401
2402
2403
2389
2390
2391
2392
2393
2394
2395

2396
2397
2398
2399
2400
2401
2402
2403







-
+







      CREATE TRIGGER t5_tr1 AFTER INSERT ON t5 BEGIN 
        UPDATE t5 SET x = 1 WHERE NEW.x = 0;
      END;
    }
  } {}
  set ::authargs [list]
  proc auth {args} {
    eval lappend ::authargs $args
    eval lappend ::authargs [lrange $args 0 4]
    return SQLITE_OK
  }
  do_test auth-5.3.2 {
    execsql { INSERT INTO t5 (x) values(0) }
    set ::authargs
  } [list SQLITE_INSERT t5 {} main {}    \
          SQLITE_UPDATE t5 x main t5_tr1 \
2415
2416
2417
2418
2419
2420
2421
2422

2423
2424
2425
2426
2427
2428
2429
2415
2416
2417
2418
2419
2420
2421

2422
2423
2424
2425
2426
2427
2428
2429







-
+







  execsql {
    CREATE TABLE t6(a,b,c,d,e,f,g,h);
    INSERT INTO t6 VALUES(1,2,3,4,5,6,7,8);
  }
} {}
set ::authargs [list]
proc auth {args} {
  eval lappend ::authargs $args
  eval lappend ::authargs [lrange $args 0 4]
  return SQLITE_OK
}
do_test auth-6.2 {
  execsql {UPDATE t6 SET rowID=rowID+100}
  set ::authargs
} [list SQLITE_READ   t6 ROWID main {} \
        SQLITE_UPDATE t6 ROWID main {} \

Changes to test/auth2.test.

27
28
29
30
31
32
33
34

35
36
37
38
39
40
41
27
28
29
30
31
32
33

34
35
36
37
38
39
40
41







-
+








do_test auth2-1.1 {
  execsql {
    CREATE TABLE t1(a,b,c);
    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"} {
        return SQLITE_DENY
      } elseif {$arg2=="min"} {
        return SQLITE_IGNORE
      } else {
76
77
78
79
80
81
82
83

84
85
86
87
88
89
90
76
77
78
79
80
81
82

83
84
85
86
87
88
89
90







-
+







# and when computing the result set of a view.
#
db close
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
do_test auth2-2.1 {
  set ::authargs {}
  db eval {
    CREATE TABLE t2(x,y,z);

Changes to test/auth3.test.

26
27
28
29
30
31
32
33

34
35
36
37
38
39
40
26
27
28
29
30
31
32

33
34
35
36
37
38
39
40







-
+







}

# Disable the statement cache for these tests.
# 
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
  }
  return SQLITE_OK
}

#--------------------------------------------------------------------------

Changes to test/fkey2.test.

1550
1551
1552
1553
1554
1555
1556
1557

1558
1559
1560
1561
1562
1563
1564
1550
1551
1552
1553
1554
1555
1556

1557
1558
1559
1560
1561
1562
1563
1564







-
+







    execsql {
      CREATE TABLE long(a, b PRIMARY KEY, c);
      CREATE TABLE short(d, e, f REFERENCES long);
      CREATE TABLE mid(g, h, i REFERENCES long DEFERRABLE INITIALLY DEFERRED);
    }
  } {}

  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
  # foreign key constraints. But not the child key of immediate constraints.
  set authargs {}
  do_test fkey2-18.2 {
    execsql { INSERT INTO long VALUES(1, 2, 3) }

Changes to test/fts4aa.test.

166
167
168
169
170
171
172
173

174
175
176
177
178
179
180
166
167
168
169
170
171
172

173
174
175
176
177
178
179
180







-
+







    db eval {SELECT docid FROM t1 WHERE words MATCH $::q ORDER BY docid}
  } $r
}

# 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;
}
do_test fts4aa-4.0 {
  db auth ::no_pragma_auth
  db eval {
    DROP TABLE t1;

Changes to test/savepoint.test.

557
558
559
560
561
562
563
564

565
566
567
568
569
570
571
557
558
559
560
561
562
563

564
565
566
567
568
569
570
571







-
+







  execsql { RELEASE "including Whitespace " }
} {}

# Test that the authorization callback works.
#
ifcapable auth {
  proc auth {args} {
    eval lappend ::authdata $args
    eval lappend ::authdata [lrange $args 0 4]
    return SQLITE_OK
  }
  db auth auth

  do_test savepoint-9.1 {
    set ::authdata [list]
    execsql { SAVEPOINT sp1 }
579
580
581
582
583
584
585
586

587
588
589
590
591
592
593
579
580
581
582
583
584
585

586
587
588
589
590
591
592
593







-
+







  do_test savepoint-9.3 {
    set ::authdata [list]
    execsql { RELEASE sp1 }
    set ::authdata
  } {SQLITE_SAVEPOINT RELEASE sp1 {} {}}

  proc auth {args} {
    eval lappend ::authdata $args
    eval lappend ::authdata [lrange $args 0 4]
    return SQLITE_DENY
  }
  db auth auth

  do_test savepoint-9.4 {
    set ::authdata [list]
    set res [catchsql { SAVEPOINT sp1 }]

Added test/userauth01.test.


































































































































































































































































1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
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

Changes to test/vtab3.test.

21
22
23
24
25
26
27
28

29
30
31
32
33
34
35
21
22
23
24
25
26
27

28
29
30
31
32
33
34
35







-
+







  return
}

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
  }
  lappend ::auth_log $code $arg1 $arg2 $arg3 $arg4
  incr ::auth_fail -1
  if {$::auth_fail == 0} {
    return SQLITE_DENY

Changes to test/without_rowid3.test.

1617
1618
1619
1620
1621
1622
1623
1624

1625
1626
1627
1628
1629
1630
1631
1617
1618
1619
1620
1621
1622
1623

1624
1625
1626
1627
1628
1629
1630
1631







-
+







    execsql {
      CREATE TABLE long(a, b PRIMARY KEY, c) WITHOUT rowid;
      CREATE TABLE short(d, e, f REFERENCES long);
      CREATE TABLE mid(g, h, i REFERENCES long DEFERRABLE INITIALLY DEFERRED);
    }
  } {}

  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
  # foreign key constraints. But not the child key of immediate constraints.
  set authargs {}
  do_test without_rowid3-18.2 {
    execsql { INSERT INTO long VALUES(1, 2, 3) }