/ Check-in [d93c1aeb]
Login

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

Overview
Comment:The sqlite_exec() function now returns SQLITE_AUTH when authorization fails. Ticket #231. (CVS 857)
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: d93c1aeb544a5b1056424945eb43854213b30e50
User & Date: drh 2003-01-31 17:21:50
Context
2003-02-01
13:53
When a CREATE TABLE ... AS SELECT statement fails, make sure the table name is removed from the internal hash tables. Ticket #238. (CVS 858) check-in: 65264780 user: drh tags: trunk
2003-01-31
17:21
The sqlite_exec() function now returns SQLITE_AUTH when authorization fails. Ticket #231. (CVS 857) check-in: d93c1aeb user: drh tags: trunk
17:16
Allow double-quoted strings as string constants in the IN operator. As a side-efffect, allow the GROUP BY clause to refer to columns by their integer column number. Ticket #237. (CVS 856) check-in: 187d9c40 user: drh tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/auth.c.

10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
..
67
68
69
70
71
72
73

74
75
76
77
78
79
80
...
109
110
111
112
113
114
115

116
117
118
119
120
121
122
...
134
135
136
137
138
139
140

141
142
143
144
145
146
147
148
149
**
*************************************************************************
** This file contains code used to implement the sqlite_set_authorizer()
** API.  This facility is an optional feature of the library.  Embedded
** systems that do not need this facility may omit it by recompiling
** the library with -DSQLITE_OMIT_AUTHORIZATION=1
**
** $Id: auth.c,v 1.3 2003/01/13 23:27:32 drh Exp $
*/
#include "sqliteInt.h"

/*
** All of the code in this file may be omitted by defining a single
** macro.
*/
................................................................................
static void sqliteAuthBadReturnCode(Parse *pParse, int rc){
  char zBuf[20];
  sprintf(zBuf, "(%d)", rc);
  sqliteSetString(&pParse->zErrMsg, "illegal return value ", zBuf,
    " from the authorization function - should be SQLITE_OK, "
    "SQLITE_IGNORE, or SQLITE_DENY", 0);
  pParse->nErr++;

}

/*
** The pExpr should be a TK_COLUMN expression.  The table referred to
** is in pTabList with an offset of base.  Check to see if it is OK to read
** this particular column.
**
................................................................................
  rc = db->xAuth(db->pAuthArg, SQLITE_READ, pTab->zName, zCol);
  if( rc==SQLITE_IGNORE ){
    pExpr->op = TK_NULL;
  }else if( rc==SQLITE_DENY ){
    sqliteSetString(&pParse->zErrMsg,"access to ",
        pTab->zName, ".", zCol, " is prohibited", 0);
    pParse->nErr++;

  }else if( rc!=SQLITE_OK ){
    sqliteAuthBadReturnCode(pParse, rc);
  }
}

/*
** Do an authorization check using the code and arguments given.  Return
................................................................................
  int rc;
  if( db->xAuth==0 ){
    return SQLITE_OK;
  }
  rc = db->xAuth(db->pAuthArg, code, zArg1, zArg2);
  if( rc==SQLITE_DENY ){
    sqliteSetString(&pParse->zErrMsg, "not authorized", 0);

    pParse->nErr++;
  }else if( rc!=SQLITE_OK && rc!=SQLITE_IGNORE ){
    rc = SQLITE_DENY;
    sqliteAuthBadReturnCode(pParse, rc);
  }
  return rc;
}

#endif /* SQLITE_OMIT_AUTHORIZATION */







|







 







>







 







>







 







>









10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
..
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
...
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
...
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
**
*************************************************************************
** This file contains code used to implement the sqlite_set_authorizer()
** API.  This facility is an optional feature of the library.  Embedded
** systems that do not need this facility may omit it by recompiling
** the library with -DSQLITE_OMIT_AUTHORIZATION=1
**
** $Id: auth.c,v 1.4 2003/01/31 17:21:50 drh Exp $
*/
#include "sqliteInt.h"

/*
** All of the code in this file may be omitted by defining a single
** macro.
*/
................................................................................
static void sqliteAuthBadReturnCode(Parse *pParse, int rc){
  char zBuf[20];
  sprintf(zBuf, "(%d)", rc);
  sqliteSetString(&pParse->zErrMsg, "illegal return value ", zBuf,
    " from the authorization function - should be SQLITE_OK, "
    "SQLITE_IGNORE, or SQLITE_DENY", 0);
  pParse->nErr++;
  pParse->rc = SQLITE_MISUSE;
}

/*
** The pExpr should be a TK_COLUMN expression.  The table referred to
** is in pTabList with an offset of base.  Check to see if it is OK to read
** this particular column.
**
................................................................................
  rc = db->xAuth(db->pAuthArg, SQLITE_READ, pTab->zName, zCol);
  if( rc==SQLITE_IGNORE ){
    pExpr->op = TK_NULL;
  }else if( rc==SQLITE_DENY ){
    sqliteSetString(&pParse->zErrMsg,"access to ",
        pTab->zName, ".", zCol, " is prohibited", 0);
    pParse->nErr++;
    pParse->rc = SQLITE_AUTH;
  }else if( rc!=SQLITE_OK ){
    sqliteAuthBadReturnCode(pParse, rc);
  }
}

/*
** Do an authorization check using the code and arguments given.  Return
................................................................................
  int rc;
  if( db->xAuth==0 ){
    return SQLITE_OK;
  }
  rc = db->xAuth(db->pAuthArg, code, zArg1, zArg2);
  if( rc==SQLITE_DENY ){
    sqliteSetString(&pParse->zErrMsg, "not authorized", 0);
    pParse->rc = SQLITE_AUTH;
    pParse->nErr++;
  }else if( rc!=SQLITE_OK && rc!=SQLITE_IGNORE ){
    rc = SQLITE_DENY;
    sqliteAuthBadReturnCode(pParse, rc);
  }
  return rc;
}

#endif /* SQLITE_OMIT_AUTHORIZATION */

Changes to src/tclsqlite.c.

7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
..
48
49
50
51
52
53
54

55
56
57
58
59
60
61
...
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338

339
340
341
342
343
344
345
...
426
427
428
429
430
431
432











433
434
435
436
437
438
439
...
479
480
481
482
483
484
485

486
487
488
489
490
491
492
...
567
568
569
570
571
572
573

574
575
576
577
578
579
580
**    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.
**
*************************************************************************
** A TCL Interface to SQLite
**
** $Id: tclsqlite.c,v 1.43 2002/11/04 19:32:26 drh Exp $
*/
#ifndef NO_TCL     /* Omit this whole file if TCL is unavailable */

#include "sqliteInt.h"
#include "tcl.h"
#include <stdlib.h>
#include <string.h>
................................................................................
*/
typedef struct SqliteDb SqliteDb;
struct SqliteDb {
  sqlite *db;           /* The "real" database structure */
  Tcl_Interp *interp;   /* The interpreter used for this database */
  char *zBusy;          /* The busy callback routine */
  SqlFunc *pFunc;       /* List of SQL functions */

};

/*
** An instance of this structure passes information thru the sqlite
** logic from the original TCL command into the callback routine.
*/
typedef struct CallbackData CallbackData;
................................................................................
** subroutine to be invoked.
*/
static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
  SqliteDb *pDb = (SqliteDb*)cd;
  int choice;
  static const char *DB_strs[] = {
    "busy",               "changes",           "close",
    "complete",           "eval",              "function",
    "last_insert_rowid",  "open_aux_file",     "timeout",
    0                    
  };
  enum DB_enum {
    DB_BUSY,              DB_CHANGES,          DB_CLOSE,
    DB_COMPLETE,          DB_EVAL,             DB_FUNCTION,
    DB_LAST_INSERT_ROWID, DB_OPEN_AUX_FILE,    DB_TIMEOUT,

  };

  if( objc<2 ){
    Tcl_WrongNumArgs(interp, 1, objv, "SUBCOMMAND ...");
    return TCL_ERROR;
  }
  if( Tcl_GetIndexFromObj(interp, objv[1], DB_strs, "option", 0, &choice) ){
................................................................................
      return TCL_ERROR;
    }
    isComplete = sqlite_complete( Tcl_GetStringFromObj(objv[2], 0) );
    pResult = Tcl_GetObjResult(interp);
    Tcl_SetBooleanObj(pResult, isComplete);
    break;
  }











   
  /*
  **    $db eval $sql ?array {  ...code... }?
  **
  ** The SQL statement in $sql is evaluated.  For each row, the values are
  ** placed in elements of the array named "array" and ...code... is executed.
  ** If "array" and "code" are omitted, then no callback is every invoked.
................................................................................
      if( cbData.tcl_rc==TCL_BREAK ){ cbData.tcl_rc = TCL_OK; }
    }else{
      Tcl_Obj *pList = Tcl_NewObj();
      cbData.tcl_rc = TCL_OK;
      rc = sqlite_exec(pDb->db, zSql, DbEvalCallback2, pList, &zErrMsg);
      Tcl_SetObjResult(interp, pList);
    }

    if( rc==SQLITE_ABORT ){
      if( zErrMsg ) free(zErrMsg);
      rc = cbData.tcl_rc;
    }else if( zErrMsg ){
      Tcl_SetResult(interp, zErrMsg, TCL_VOLATILE);
      free(zErrMsg);
      rc = TCL_ERROR;
................................................................................
    int rc;
    if( objc!=3 ){
      Tcl_WrongNumArgs(interp, 2, objv, "FILENAME");
      return TCL_ERROR;
    }
    zFilename = Tcl_GetStringFromObj(objv[2], 0);
    rc = sqlite_open_aux_file(pDb->db, zFilename, &zErrMsg);

    if( rc!=0 ){
      if( zErrMsg ){
        Tcl_AppendResult(interp, zErrMsg, 0);
        free(zErrMsg);
      }else{
        Tcl_AppendResult(interp, sqlite_error_string(rc), 0);
      }







|







 







>







 







|
|
|



|
|
>







 







>
>
>
>
>
>
>
>
>
>
>







 







>







 







>







7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
..
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
...
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
...
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
...
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
...
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
**    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.
**
*************************************************************************
** A TCL Interface to SQLite
**
** $Id: tclsqlite.c,v 1.44 2003/01/31 17:21:50 drh Exp $
*/
#ifndef NO_TCL     /* Omit this whole file if TCL is unavailable */

#include "sqliteInt.h"
#include "tcl.h"
#include <stdlib.h>
#include <string.h>
................................................................................
*/
typedef struct SqliteDb SqliteDb;
struct SqliteDb {
  sqlite *db;           /* The "real" database structure */
  Tcl_Interp *interp;   /* The interpreter used for this database */
  char *zBusy;          /* The busy callback routine */
  SqlFunc *pFunc;       /* List of SQL functions */
  int rc;               /* Return code of most recent sqlite_exec() */
};

/*
** An instance of this structure passes information thru the sqlite
** logic from the original TCL command into the callback routine.
*/
typedef struct CallbackData CallbackData;
................................................................................
** subroutine to be invoked.
*/
static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
  SqliteDb *pDb = (SqliteDb*)cd;
  int choice;
  static const char *DB_strs[] = {
    "busy",               "changes",           "close",
    "complete",           "errorcode",         "eval",
    "function",           "last_insert_rowid", "open_aux_file",
    "timeout",            0                    
  };
  enum DB_enum {
    DB_BUSY,              DB_CHANGES,          DB_CLOSE,
    DB_COMPLETE,          DB_ERRORCODE,        DB_EVAL,
    DB_FUNCTION,          DB_LAST_INSERT_ROWID,DB_OPEN_AUX_FILE,
    DB_TIMEOUT,          
  };

  if( objc<2 ){
    Tcl_WrongNumArgs(interp, 1, objv, "SUBCOMMAND ...");
    return TCL_ERROR;
  }
  if( Tcl_GetIndexFromObj(interp, objv[1], DB_strs, "option", 0, &choice) ){
................................................................................
      return TCL_ERROR;
    }
    isComplete = sqlite_complete( Tcl_GetStringFromObj(objv[2], 0) );
    pResult = Tcl_GetObjResult(interp);
    Tcl_SetBooleanObj(pResult, isComplete);
    break;
  }

  /*
  **    $db errorcode
  **
  ** Return the numeric error code that was returned by the most recent
  ** call to sqlite_exec().
  */
  case DB_ERRORCODE: {
    Tcl_SetObjResult(interp, Tcl_NewIntObj(pDb->rc));
    break;
  }
   
  /*
  **    $db eval $sql ?array {  ...code... }?
  **
  ** The SQL statement in $sql is evaluated.  For each row, the values are
  ** placed in elements of the array named "array" and ...code... is executed.
  ** If "array" and "code" are omitted, then no callback is every invoked.
................................................................................
      if( cbData.tcl_rc==TCL_BREAK ){ cbData.tcl_rc = TCL_OK; }
    }else{
      Tcl_Obj *pList = Tcl_NewObj();
      cbData.tcl_rc = TCL_OK;
      rc = sqlite_exec(pDb->db, zSql, DbEvalCallback2, pList, &zErrMsg);
      Tcl_SetObjResult(interp, pList);
    }
    pDb->rc = rc;
    if( rc==SQLITE_ABORT ){
      if( zErrMsg ) free(zErrMsg);
      rc = cbData.tcl_rc;
    }else if( zErrMsg ){
      Tcl_SetResult(interp, zErrMsg, TCL_VOLATILE);
      free(zErrMsg);
      rc = TCL_ERROR;
................................................................................
    int rc;
    if( objc!=3 ){
      Tcl_WrongNumArgs(interp, 2, objv, "FILENAME");
      return TCL_ERROR;
    }
    zFilename = Tcl_GetStringFromObj(objv[2], 0);
    rc = sqlite_open_aux_file(pDb->db, zFilename, &zErrMsg);
    pDb->rc = rc;
    if( rc!=0 ){
      if( zErrMsg ){
        Tcl_AppendResult(interp, zErrMsg, 0);
        free(zErrMsg);
      }else{
        Tcl_AppendResult(interp, sqlite_error_string(rc), 0);
      }

Changes to src/where.c.

9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
..
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
**    May you share freely, never taking more than you give.
**
*************************************************************************
** This module contains C code that generates VDBE code used to process
** the WHERE clause of SQL statements.  Also found here are subroutines
** to generate VDBE code to evaluate expressions.
**
** $Id: where.c,v 1.71 2003/01/11 15:02:45 drh Exp $
*/
#include "sqliteInt.h"

/*
** The query generator uses an array of instances of this structure to
** help it analyze the subexpressions of the WHERE clause.  Each WHERE
** clause subexpression is separated from the others by an AND operator.
................................................................................
    aSlot[0].p = pExpr;
    return 1;
  }
  if( pExpr->pLeft->op!=TK_AND ){
    aSlot[0].p = pExpr->pLeft;
    cnt = 1 + exprSplit(nSlot-1, &aSlot[1], pExpr->pRight);
  }else{
    cnt = exprSplit(nSlot, aSlot, pExpr->pRight);
    cnt += exprSplit(nSlot-cnt, &aSlot[cnt], pExpr->pLeft);
  }
  return cnt;
}

/*
** This routine walks (recursively) an expression tree and generates
** a bitmask indicating which tables are used in that expression







|







 







|
|







9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
..
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
**    May you share freely, never taking more than you give.
**
*************************************************************************
** This module contains C code that generates VDBE code used to process
** the WHERE clause of SQL statements.  Also found here are subroutines
** to generate VDBE code to evaluate expressions.
**
** $Id: where.c,v 1.72 2003/01/31 17:21:50 drh Exp $
*/
#include "sqliteInt.h"

/*
** The query generator uses an array of instances of this structure to
** help it analyze the subexpressions of the WHERE clause.  Each WHERE
** clause subexpression is separated from the others by an AND operator.
................................................................................
    aSlot[0].p = pExpr;
    return 1;
  }
  if( pExpr->pLeft->op!=TK_AND ){
    aSlot[0].p = pExpr->pLeft;
    cnt = 1 + exprSplit(nSlot-1, &aSlot[1], pExpr->pRight);
  }else{
    cnt = exprSplit(nSlot, aSlot, pExpr->pLeft);
    cnt += exprSplit(nSlot-cnt, &aSlot[cnt], pExpr->pRight);
  }
  return cnt;
}

/*
** This routine walks (recursively) an expression tree and generates
** a bitmask indicating which tables are used in that expression

Changes to test/auth.test.

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
....
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623



1624
1625
1626
1627
1628
1629
1630
#    May you find forgiveness for yourself and forgive others.
#    May you share freely, never taking more than you give.
#
#***********************************************************************
# This file implements regression tests for SQLite library.  The
# focus of this script testing the sqlite_set_authorizer() API.
#
# $Id: auth.test,v 1.4 2003/01/14 13:48:21 drh Exp $
#

set testdir [file dirname $argv0]
source $testdir/tester.tcl

if {[info command sqlite_set_authorizer]!=""} {

do_test auth-1.1 {
  db close
  set ::DB [sqlite db test.db]
  proc auth {code arg1 arg2} {
    if {$code=="SQLITE_INSERT" && $arg1=="sqlite_master"} {
      return SQLITE_DENY
    }
    return SQLITE_OK
  }
  sqlite_set_authorizer $::DB ::auth
  catchsql {CREATE TABLE t1(a,b,c)}
} {1 {not authorized}}



do_test auth-1.2 {
  execsql {SELECT name FROM sqlite_master}
} {}
do_test auth-1.3.1 {
  proc auth {code arg1 arg2} {
    if {$code=="SQLITE_CREATE_TABLE"} {
      set ::authargs [list $arg1 $arg2]
................................................................................
      return SQLITE_DENY
    }
    return SQLITE_OK
  }
  catchsql {CREATE TABLE t1(a,b,c)}
} {1 {not authorized}}
do_test auth-1.3.2 {



  set ::authargs
} {t1 {}}
do_test auth-1.4 {
  execsql {SELECT name FROM sqlite_master}
} {}

do_test auth-1.5 {
................................................................................
    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 {
  proc auth {code arg1 arg2} {
    if {$code=="SQLITE_READ" && $arg1=="t2" && $arg2=="ROWID"} {
      return bogus
    }
    return SQLITE_OK
  }
  catchsql {SELECT ROWID,b,c FROM t2}
} {1 {illegal return value (999) from the authorization function - should be SQLITE_OK, SQLITE_IGNORE, or SQLITE_DENY}}



do_test auth-2.10 {
  proc auth {code arg1 arg2} {
    if {$code=="SQLITE_SELECT"} {
      return bogus
    }
    return SQLITE_OK
  }







|







|











>
>
>







 







>
>
>







 







|








>
>
>







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
....
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
#    May you find forgiveness for yourself and forgive others.
#    May you share freely, never taking more than you give.
#
#***********************************************************************
# This file implements regression tests for SQLite library.  The
# focus of this script testing the sqlite_set_authorizer() API.
#
# $Id: auth.test,v 1.5 2003/01/31 17:21:50 drh Exp $
#

set testdir [file dirname $argv0]
source $testdir/tester.tcl

if {[info command sqlite_set_authorizer]!=""} {

do_test auth-1.1.1 {
  db close
  set ::DB [sqlite db test.db]
  proc auth {code arg1 arg2} {
    if {$code=="SQLITE_INSERT" && $arg1=="sqlite_master"} {
      return SQLITE_DENY
    }
    return SQLITE_OK
  }
  sqlite_set_authorizer $::DB ::auth
  catchsql {CREATE TABLE t1(a,b,c)}
} {1 {not authorized}}
do_test auth-1.1.2 {
  db errorcode
} {23}
do_test auth-1.2 {
  execsql {SELECT name FROM sqlite_master}
} {}
do_test auth-1.3.1 {
  proc auth {code arg1 arg2} {
    if {$code=="SQLITE_CREATE_TABLE"} {
      set ::authargs [list $arg1 $arg2]
................................................................................
      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 {}}
do_test auth-1.4 {
  execsql {SELECT name FROM sqlite_master}
} {}

do_test auth-1.5 {
................................................................................
    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 {
  proc auth {code arg1 arg2} {
    if {$code=="SQLITE_READ" && $arg1=="t2" && $arg2=="ROWID"} {
      return bogus
    }
    return SQLITE_OK
  }
  catchsql {SELECT ROWID,b,c FROM t2}
} {1 {illegal return value (999) from the authorization function - should be SQLITE_OK, SQLITE_IGNORE, or SQLITE_DENY}}
do_test auth-2.9.2 {
  db errorcode
} {21}
do_test auth-2.10 {
  proc auth {code arg1 arg2} {
    if {$code=="SQLITE_SELECT"} {
      return bogus
    }
    return SQLITE_OK
  }

Changes to test/tclsqlite.test.

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
# This file implements regression tests for TCL interface to the
# SQLite library. 
#
# Actually, all tests are based on the TCL interface, so the main
# interface is pretty well tested.  This file contains some addition
# tests for fringe issues that the main test suite does not cover.
#
# $Id: tclsqlite.test,v 1.8 2002/09/14 13:47:33 drh Exp $

set testdir [file dirname $argv0]
source $testdir/tester.tcl

# Check the error messages generated by tclsqlite
#
do_test tcl-1.1 {
  set v [catch {sqlite bogus} msg]
  lappend v $msg
} {1 {wrong # args: should be "sqlite HANDLE FILENAME ?MODE?"}}
do_test tcl-1.2 {
  set v [catch {db bogus} msg]
  lappend v $msg
} {1 {bad option "bogus": must be busy, changes, close, complete, eval, function, last_insert_rowid, open_aux_file, or timeout}}
do_test tcl-1.3 {
  execsql {CREATE TABLE t1(a int, b int)}
  execsql {INSERT INTO t1 VALUES(10,20)}
  set v [catch {
    db eval {SELECT * FROM t1} data {
      error "The error message"
    }







|













|







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
# This file implements regression tests for TCL interface to the
# SQLite library. 
#
# Actually, all tests are based on the TCL interface, so the main
# interface is pretty well tested.  This file contains some addition
# tests for fringe issues that the main test suite does not cover.
#
# $Id: tclsqlite.test,v 1.9 2003/01/31 17:21:51 drh Exp $

set testdir [file dirname $argv0]
source $testdir/tester.tcl

# Check the error messages generated by tclsqlite
#
do_test tcl-1.1 {
  set v [catch {sqlite bogus} msg]
  lappend v $msg
} {1 {wrong # args: should be "sqlite HANDLE FILENAME ?MODE?"}}
do_test tcl-1.2 {
  set v [catch {db bogus} msg]
  lappend v $msg
} {1 {bad option "bogus": must be busy, changes, close, complete, errorcode, eval, function, last_insert_rowid, open_aux_file, or timeout}}
do_test tcl-1.3 {
  execsql {CREATE TABLE t1(a int, b int)}
  execsql {INSERT INTO t1 VALUES(10,20)}
  set v [catch {
    db eval {SELECT * FROM t1} data {
      error "The error message"
    }