SQLite

Check-in [d93c1aeb54]
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
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: d93c1aeb544a5b1056424945eb43854213b30e50
User & Date: drh 2003-01-31 17:21:50.000
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: 65264780c5 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: d93c1aeb54 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: 187d9c4058 user: drh tags: trunk)
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/auth.c.
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
**
*************************************************************************
** 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.
*/







|







10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
**
*************************************************************************
** 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.
*/
67
68
69
70
71
72
73

74
75
76
77
78
79
80
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.
**







>







67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
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.
**
109
110
111
112
113
114
115

116
117
118
119
120
121
122
  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







>







110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
  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
134
135
136
137
138
139
140

141
142
143
144
145
146
147
148
149
  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 */







>









136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
  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.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/*
** 2001 September 15
**
** The author disclaims copyright to this source code.  In place of
** a legal notice, here is a blessing:
**
**    May you do good and not evil.
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** 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>













|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/*
** 2001 September 15
**
** The author disclaims copyright to this source code.  In place of
** a legal notice, here is a blessing:
**
**    May you do good and not evil.
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** 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>
48
49
50
51
52
53
54

55
56
57
58
59
60
61
*/
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;







>







48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
*/
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;
324
325
326
327
328
329
330
331
332
333

334
335
336
337
338

339
340
341
342
343
344
345
** 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) ){







|
|
<
>



|
|
>







325
326
327
328
329
330
331
332
333

334
335
336
337
338
339
340
341
342
343
344
345
346
347
** 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) ){
426
427
428
429
430
431
432











433
434
435
436
437
438
439
      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.







>
>
>
>
>
>
>
>
>
>
>







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
      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.
479
480
481
482
483
484
485

486
487
488
489
490
491
492
      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;







>







492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
      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;
567
568
569
570
571
572
573

574
575
576
577
578
579
580
    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);
      }







>







581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
    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
**    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.







|







9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
**    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.
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
    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







|
|







58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
    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.
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
# 2003 January 12
#
# The author disclaims copyright to this source code.  In place of
# a legal notice, here is a blessing:
#
#    May you do good and not evil.
#    May you find forgiveness for yourself and forgive others.
#    May you share freely, never taking more than you give.
#
#***********************************************************************
# This file implements regression tests for SQLite library.  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 {













|







|











>
>
>














>
>
>







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
# 2003 January 12
#
# The author disclaims copyright to this source code.  In place of
# a legal notice, here is a blessing:
#
#    May you do good and not evil.
#    May you find forgiveness for yourself and forgive others.
#    May you share freely, never taking more than you give.
#
#***********************************************************************
# This file implements regression tests for SQLite library.  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 {
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623



1624
1625
1626
1627
1628
1629
1630
    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
  }







|








>
>
>







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
    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"
    }