/ Check-in [f42907ce]
Login

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

Overview
Comment:Improvements to the SQLITE_MISUSE detection logic. Also added test cases for this logic, including the new test file "misuse.test". (CVS 559)
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1:f42907ce457e012592f8c043dc6c915e87258b35
User & Date: drh 2002-05-10 13:14:07
Context
2002-05-10
14:37
Update the misuse.test script so that it will work under Windows. Changes to the speed testing script to support version 2.4.12. (CVS 560) check-in: 232b7ef2 user: drh tags: trunk
13:14
Improvements to the SQLITE_MISUSE detection logic. Also added test cases for this logic, including the new test file "misuse.test". (CVS 559) check-in: f42907ce user: drh tags: trunk
05:44
Attempt to detect when two or more threads try to use the same database at the same time and return an SQLITE_MISUSE error. Also return this error if an attempt is made to use a closed database. (CVS 558) check-in: a05fabd2 user: drh tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to VERSION.

1
2.4.11
|
1
2.4.12

Changes to src/main.c.

10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
...
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
...
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
...
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
...
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
...
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
**
*************************************************************************
** Main file for the SQLite library.  The routines in this file
** implement the programmer interface to the library.  Routines in
** other files are for internal use by SQLite and should not be
** accessed by users of the library.
**
** $Id: main.c,v 1.70 2002/05/10 05:44:56 drh Exp $
*/
#include "sqliteInt.h"
#include "os.h"

/*
** This is the callback routine for the code that initializes the
** database.  See sqliteInit() below for additional information.
................................................................................
}

/*
** Close an existing SQLite database
*/
void sqlite_close(sqlite *db){
  HashElem *i;
  if( sqliteSafetyOn(db) ){ return; }
  db->magic = SQLITE_MAGIC_CLOSED;
  sqliteBtreeClose(db->pBe);
  clearHashTable(db, 0);
  if( db->pBeTemp ){
    sqliteBtreeClose(db->pBeTemp);
  }
  for(i=sqliteHashFirst(&db->aFunc); i; i=sqliteHashNext(i)){
................................................................................
  sqlite_callback xCallback,  /* Invoke this callback routine */
  void *pArg,                 /* First argument to xCallback() */
  char **pzErrMsg             /* Write error messages here */
){
  Parse sParse;

  if( pzErrMsg ) *pzErrMsg = 0;
  if( sqliteSafetyOn(db) ){ return SQLITE_MISUSE; }
  if( (db->flags & SQLITE_Initialized)==0 ){
    int rc = sqliteInit(db, pzErrMsg);
    if( rc!=SQLITE_OK ){
      sqliteStrRealloc(pzErrMsg);
      sqliteSafetyOff(db);
      return rc;
    }
................................................................................
    clearHashTable(db, 0);
  }
  sqliteStrRealloc(pzErrMsg);
  if( sParse.rc==SQLITE_SCHEMA ){
    clearHashTable(db, 1);
  }
  db->recursionDepth--;
  if( sqliteSafetyOff(db) ){ sParse.rc = SQLITE_MISUSE; }
  return sParse.rc;
}






/*
** Change the magic from SQLITE_MAGIC_OPEN to SQLITE_MAGIC_BUSY.
** Return an error (non-zero) if the magic was not SQLITE_MAGIC_OPEN
** when this routine is called.
**
** This routine is a attempt to detect if two threads attempt
** to use the same sqlite* pointer at the same time.  There is a
** race condition so it is possible that the error is not detected.
** But usually the problem will be seen.  The result will be an
** error which can be used to debugging the application that is
** using SQLite incorrectly.
*/
int sqliteSafetyOn(sqlite *db){
  if( db->magic==SQLITE_MAGIC_OPEN ){
    db->magic = SQLITE_MAGIC_BUSY;
    return 0;
  }else{
    db->magic = SQLITE_MAGIC_ERROR;
    db->flags |= SQLITE_Interrupt;
    return 1;
  }
}

/*
** Change the magic from SQLITE_MAGIC_BUSY to SQLITE_MAGIC_OPEN.
** Return an error (non-zero) if the magic was not SQLITE_MAGIC_BUSY
** when this routine is called.
*/

int sqliteSafetyOff(sqlite *db){
  if( db->magic==SQLITE_MAGIC_BUSY ){
    db->magic = SQLITE_MAGIC_OPEN;
    return 0;
  }else{
    db->magic = SQLITE_MAGIC_ERROR;
    db->flags |= SQLITE_Interrupt;
    return 1;

















  }

}

/*
** This routine implements a busy callback that sleeps and tries
** again until a timeout value is reached.  The timeout value is
** an integer number of milliseconds passed in as the first
** argument.
................................................................................
  sqlite *db,          /* Add the function to this database connection */
  const char *zName,   /* Name of the function to add */
  int nArg,            /* Number of arguments */
  void (*xFunc)(sqlite_func*,int,const char**),  /* The implementation */
  void *pUserData      /* User data */
){
  FuncDef *p;
  if( db==0 || zName==0 ) return 1;
  p = sqliteFindFunction(db, zName, strlen(zName), nArg, 1);
  if( p==0 ) return 1;
  p->xFunc = xFunc;
  p->xStep = 0;
  p->xFinalize = 0;
  p->pUserData = pUserData;
  return 0;
................................................................................
  const char *zName,   /* Name of the function to add */
  int nArg,            /* Number of arguments */
  void (*xStep)(sqlite_func*,int,const char**), /* The step function */
  void (*xFinalize)(sqlite_func*),              /* The finalizer */
  void *pUserData      /* User data */
){
  FuncDef *p;
  if( db==0 || zName==0 ) return 1;
  p = sqliteFindFunction(db, zName, strlen(zName), nArg, 1);
  if( p==0 ) return 1;
  p->xFunc = 0;
  p->xStep = xStep;
  p->xFinalize = xFinalize;
  p->pUserData = pUserData;
  return 0;
}







|







 







|







 







|







 







|

|
>
>
>
>
>
|
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
|
<
<
<
<
<



|
|
<

>
|
|
|
|
|
|
|
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>

>







 







|







 







|








10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
...
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
...
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
...
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
...
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
...
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
**
*************************************************************************
** Main file for the SQLite library.  The routines in this file
** implement the programmer interface to the library.  Routines in
** other files are for internal use by SQLite and should not be
** accessed by users of the library.
**
** $Id: main.c,v 1.71 2002/05/10 13:14:07 drh Exp $
*/
#include "sqliteInt.h"
#include "os.h"

/*
** This is the callback routine for the code that initializes the
** database.  See sqliteInit() below for additional information.
................................................................................
}

/*
** Close an existing SQLite database
*/
void sqlite_close(sqlite *db){
  HashElem *i;
  if( sqliteSafetyCheck(db) || sqliteSafetyOn(db) ){ return; }
  db->magic = SQLITE_MAGIC_CLOSED;
  sqliteBtreeClose(db->pBe);
  clearHashTable(db, 0);
  if( db->pBeTemp ){
    sqliteBtreeClose(db->pBeTemp);
  }
  for(i=sqliteHashFirst(&db->aFunc); i; i=sqliteHashNext(i)){
................................................................................
  sqlite_callback xCallback,  /* Invoke this callback routine */
  void *pArg,                 /* First argument to xCallback() */
  char **pzErrMsg             /* Write error messages here */
){
  Parse sParse;

  if( pzErrMsg ) *pzErrMsg = 0;
  if( sqliteSafetyOn(db) ) goto exec_misuse;
  if( (db->flags & SQLITE_Initialized)==0 ){
    int rc = sqliteInit(db, pzErrMsg);
    if( rc!=SQLITE_OK ){
      sqliteStrRealloc(pzErrMsg);
      sqliteSafetyOff(db);
      return rc;
    }
................................................................................
    clearHashTable(db, 0);
  }
  sqliteStrRealloc(pzErrMsg);
  if( sParse.rc==SQLITE_SCHEMA ){
    clearHashTable(db, 1);
  }
  db->recursionDepth--;
  if( sqliteSafetyOff(db) ) goto exec_misuse;
  return sParse.rc;

exec_misuse:
  if( pzErrMsg ){
    *pzErrMsg = 0;
    sqliteSetString(pzErrMsg, sqlite_error_string(SQLITE_MISUSE), 0);
    sqliteStrRealloc(pzErrMsg);
  }















  return SQLITE_MISUSE;





}

/*
** Return a static string that describes the kind of error specified in the
** argument.

*/
const char *sqlite_error_string(int rc){
  const char *z;
  switch( rc ){
    case SQLITE_OK:         z = "not an error";                          break;
    case SQLITE_ERROR:      z = "SQL logic error or missing database";   break;
    case SQLITE_INTERNAL:   z = "internal SQLite implementation flaw";   break;
    case SQLITE_PERM:       z = "access permission denied";              break;
    case SQLITE_ABORT:      z = "callback requested query abort";        break;
    case SQLITE_BUSY:       z = "database is locked";                    break;
    case SQLITE_LOCKED:     z = "database table is locked";              break;
    case SQLITE_NOMEM:      z = "out of memory";                         break;
    case SQLITE_READONLY:   z = "attempt to write a readonly database";  break;
    case SQLITE_INTERRUPT:  z = "interrupted";                           break;
    case SQLITE_IOERR:      z = "disk I/O error";                        break;
    case SQLITE_CORRUPT:    z = "database disk image is malformed";      break;
    case SQLITE_NOTFOUND:   z = "table or record not found";             break;
    case SQLITE_FULL:       z = "database is full";                      break;
    case SQLITE_CANTOPEN:   z = "unable to open database file";          break;
    case SQLITE_PROTOCOL:   z = "database locking protocol failure";     break;
    case SQLITE_EMPTY:      z = "table contains no data";                break;
    case SQLITE_SCHEMA:     z = "database schema has changed";           break;
    case SQLITE_TOOBIG:     z = "too much data for one table row";       break;
    case SQLITE_CONSTRAINT: z = "constraint failed";                     break;
    case SQLITE_MISMATCH:   z = "datatype mismatch";                     break;
    case SQLITE_MISUSE:     z = "library routine called out of sequence";break;
    default:                z = "unknown error";                         break;
  }
  return z;
}

/*
** This routine implements a busy callback that sleeps and tries
** again until a timeout value is reached.  The timeout value is
** an integer number of milliseconds passed in as the first
** argument.
................................................................................
  sqlite *db,          /* Add the function to this database connection */
  const char *zName,   /* Name of the function to add */
  int nArg,            /* Number of arguments */
  void (*xFunc)(sqlite_func*,int,const char**),  /* The implementation */
  void *pUserData      /* User data */
){
  FuncDef *p;
  if( db==0 || zName==0 || sqliteSafetyCheck(db) ) return 1;
  p = sqliteFindFunction(db, zName, strlen(zName), nArg, 1);
  if( p==0 ) return 1;
  p->xFunc = xFunc;
  p->xStep = 0;
  p->xFinalize = 0;
  p->pUserData = pUserData;
  return 0;
................................................................................
  const char *zName,   /* Name of the function to add */
  int nArg,            /* Number of arguments */
  void (*xStep)(sqlite_func*,int,const char**), /* The step function */
  void (*xFinalize)(sqlite_func*),              /* The finalizer */
  void *pUserData      /* User data */
){
  FuncDef *p;
  if( db==0 || zName==0 || sqliteSafetyCheck(db) ) return 1;
  p = sqliteFindFunction(db, zName, strlen(zName), nArg, 1);
  if( p==0 ) return 1;
  p->xFunc = 0;
  p->xStep = xStep;
  p->xFinalize = xFinalize;
  p->pUserData = pUserData;
  return 0;
}

Changes to src/sqliteInt.h.

7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
...
657
658
659
660
661
662
663

**    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.
**
*************************************************************************
** Internal interface definitions for SQLite.
**
** @(#) $Id: sqliteInt.h,v 1.106 2002/05/10 05:44:56 drh Exp $
*/
#include "sqlite.h"
#include "hash.h"
#include "vdbe.h"
#include "parse.h"
#include "btree.h"
#include <stdio.h>
................................................................................
ExprList *sqliteExprListDup(ExprList*);
IdList *sqliteIdListDup(IdList*);
Select *sqliteSelectDup(Select*);
FuncDef *sqliteFindFunction(sqlite*,const char*,int,int,int);
void sqliteRegisterBuildinFunctions(sqlite*);
int sqliteSafetyOn(sqlite*);
int sqliteSafetyOff(sqlite*);








|







 







>
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
...
657
658
659
660
661
662
663
664
**    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.
**
*************************************************************************
** Internal interface definitions for SQLite.
**
** @(#) $Id: sqliteInt.h,v 1.107 2002/05/10 13:14:07 drh Exp $
*/
#include "sqlite.h"
#include "hash.h"
#include "vdbe.h"
#include "parse.h"
#include "btree.h"
#include <stdio.h>
................................................................................
ExprList *sqliteExprListDup(ExprList*);
IdList *sqliteIdListDup(IdList*);
Select *sqliteSelectDup(Select*);
FuncDef *sqliteFindFunction(sqlite*,const char*,int,int,int);
void sqliteRegisterBuildinFunctions(sqlite*);
int sqliteSafetyOn(sqlite*);
int sqliteSafetyOff(sqlite*);
int sqliteSafetyCheck(sqlite*);

Changes to src/tclsqlite.c.

7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
...
548
549
550
551
552
553
554





555
556

557
558


559
560
561
562
563
564
565
**    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.31 2002/04/12 10:08:59 drh Exp $
*/
#ifndef NO_TCL     /* Omit this whole file if TCL is unavailable */

#include "sqlite.h"
#include "tcl.h"
#include <stdlib.h>
#include <string.h>
................................................................................
  if( p->db==0 ){
    Tcl_SetResult(interp, zErrMsg, TCL_VOLATILE);
    Tcl_Free((char*)p);
    free(zErrMsg);
    return TCL_ERROR;
  }
  Tcl_CreateObjCommand(interp, argv[1], DbObjCmd, (char*)p, DbDeleteCmd);





#ifdef SQLITE_TEST
  {

     extern void Md5_Register(sqlite*);
     Md5_Register(p->db);


  }
#endif  
  return TCL_OK;
}

/*
** Provide a dummy Tcl_InitStubs if we are using this as a static







|







 







>
>
>
>
>


>
|
|
>
>







7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
...
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
**    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.32 2002/05/10 13:14:07 drh Exp $
*/
#ifndef NO_TCL     /* Omit this whole file if TCL is unavailable */

#include "sqlite.h"
#include "tcl.h"
#include <stdlib.h>
#include <string.h>
................................................................................
  if( p->db==0 ){
    Tcl_SetResult(interp, zErrMsg, TCL_VOLATILE);
    Tcl_Free((char*)p);
    free(zErrMsg);
    return TCL_ERROR;
  }
  Tcl_CreateObjCommand(interp, argv[1], DbObjCmd, (char*)p, DbDeleteCmd);

  /* If compiled with SQLITE_TEST turned on, then register the "md5sum"
  ** SQL function and return an integer which is the memory address of
  ** the underlying sqlite* pointer.
  */
#ifdef SQLITE_TEST
  {
    char zBuf[40];
    extern void Md5_Register(sqlite*);
    Md5_Register(p->db);
    sprintf(zBuf, "%d", (int)p->db);
    Tcl_AppendResult(interp, zBuf, 0);
  }
#endif  
  return TCL_OK;
}

/*
** Provide a dummy Tcl_InitStubs if we are using this as a static

Changes to src/test1.c.

9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
...
192
193
194
195
196
197
198















































































































199
200
201
202
203
204
205
...
351
352
353
354
355
356
357




358
359
360
361
362
363
364
365
366
**    May you share freely, never taking more than you give.
**
*************************************************************************
** Code for testing the printf() interface to SQLite.  This code
** is not included in the SQLite library.  It is used for automated
** testing of the SQLite library.
**
** $Id: test1.c,v 1.7 2002/03/11 02:06:13 drh Exp $
*/
#include "sqliteInt.h"
#include "tcl.h"
#include <stdlib.h>
#include <string.h>

/*
................................................................................
       " FILENAME\"", 0);
    return TCL_ERROR;
  }
  db = (sqlite*)atoi(argv[1]);
  sqlite_close(db);
  return TCL_OK;
}
















































































































/*
** Usage:  sqlite_mprintf_int FORMAT INTEGER INTEGER INTEGER
**
** Call mprintf with three integer arguments
*/
static int sqlite_mprintf_int(
................................................................................
  Tcl_CreateCommand(interp, "sqlite_mprintf_double", sqlite_mprintf_double,0,0);
  Tcl_CreateCommand(interp, "sqlite_open", sqlite_test_open, 0, 0);
  Tcl_CreateCommand(interp, "sqlite_last_insert_rowid", test_last_rowid, 0, 0);
  Tcl_CreateCommand(interp, "sqlite_exec_printf", test_exec_printf, 0, 0);
  Tcl_CreateCommand(interp, "sqlite_get_table_printf", test_get_table_printf,
      0, 0);
  Tcl_CreateCommand(interp, "sqlite_close", sqlite_test_close, 0, 0);




  Tcl_LinkVar(interp, "sqlite_search_count", 
      (char*)&sqlite_search_count, TCL_LINK_INT);
#ifdef MEMORY_DEBUG
  Tcl_CreateCommand(interp, "sqlite_malloc_fail", sqlite_malloc_fail, 0, 0);
  Tcl_CreateCommand(interp, "sqlite_malloc_stat", sqlite_malloc_stat, 0, 0);
#endif
  Tcl_CreateCommand(interp, "sqlite_abort", sqlite_abort, 0, 0);
  return TCL_OK;
}







|







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







 







>
>
>
>









9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
...
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
...
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
**    May you share freely, never taking more than you give.
**
*************************************************************************
** Code for testing the printf() interface to SQLite.  This code
** is not included in the SQLite library.  It is used for automated
** testing of the SQLite library.
**
** $Id: test1.c,v 1.8 2002/05/10 13:14:07 drh Exp $
*/
#include "sqliteInt.h"
#include "tcl.h"
#include <stdlib.h>
#include <string.h>

/*
................................................................................
       " FILENAME\"", 0);
    return TCL_ERROR;
  }
  db = (sqlite*)atoi(argv[1]);
  sqlite_close(db);
  return TCL_OK;
}

/*
** Implementation of the x_coalesce() function.
** Return the first argument non-NULL argument.
*/
static void ifnullFunc(sqlite_func *context, int argc, const char **argv){
  int i;
  for(i=0; i<argc; i++){
    if( argv[i] ){
      sqlite_set_result_string(context, argv[i], -1);
      break;
    }
  }
}

/*
** Implementation of the x_sqlite_exec() function.  This function takes
** a single argument and attempts to execute that argument as SQL code.
** This is illegal and shut set the SQLITE_MISUSE flag on the database.
** 
** This routine simulates the effect of having two threads attempt to
** use the same database at the same time.
*/
static void sqliteExecFunc(sqlite_func *context, int argc, const char **argv){
  sqlite_exec((sqlite*)sqlite_user_data(context), argv[0], 0, 0, 0);
}

/*
** Usage:  sqlite_test_create_function DB
**
** Call the sqlite_create_function API on the given database in order
** to create a function named "x_coalesce".  This function does the same thing
** as the "coalesce" function.  This function also registers an SQL function
** named "x_sqlite_exec" that invokes sqlite_exec().  Invoking sqlite_exec()
** in this way is illegal recursion and should raise an SQLITE_MISUSE error.
** The effect is similar to trying to use the same database connection from
** two threads at the same time.
**
** The original motivation for this routine was to be able to call the
** sqlite_create_function function while a query is in progress in order
** to test the SQLITE_MISUSE detection logic.
*/
static int sqlite_test_create_function(
  void *NotUsed,
  Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
  int argc,              /* Number of arguments */
  char **argv            /* Text of each argument */
){
  sqlite *db;
  extern void Md5_Register(sqlite*);
  if( argc!=2 ){
    Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
       " FILENAME\"", 0);
    return TCL_ERROR;
  }
  db = (sqlite*)atoi(argv[1]);
  sqlite_create_function(db, "x_coalesce", -1, ifnullFunc, 0);
  sqlite_create_function(db, "x_sqlite_exec", 1, sqliteExecFunc, db);
  return TCL_OK;
}

/*
** Routines to implement the x_count() aggregate function.
*/
typedef struct CountCtx CountCtx;
struct CountCtx {
  int n;
};
static void countStep(sqlite_func *context, int argc, const char **argv){
  CountCtx *p;
  p = sqlite_aggregate_context(context, sizeof(*p));
  if( (argc==0 || argv[0]) && p ){
    p->n++;
  }
}   
static void countFinalize(sqlite_func *context){
  CountCtx *p;
  p = sqlite_aggregate_context(context, sizeof(*p));
  sqlite_set_result_int(context, p ? p->n : 0);
}

/*
** Usage:  sqlite_test_create_aggregate DB
**
** Call the sqlite_create_function API on the given database in order
** to create a function named "x_count".  This function does the same thing
** as the "md5sum" function.
**
** The original motivation for this routine was to be able to call the
** sqlite_create_aggregate function while a query is in progress in order
** to test the SQLITE_MISUSE detection logic.
*/
static int sqlite_test_create_aggregate(
  void *NotUsed,
  Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
  int argc,              /* Number of arguments */
  char **argv            /* Text of each argument */
){
  sqlite *db;
  if( argc!=2 ){
    Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
       " FILENAME\"", 0);
    return TCL_ERROR;
  }
  db = (sqlite*)atoi(argv[1]);
  sqlite_create_aggregate(db, "x_count", 0, countStep, countFinalize, 0);
  sqlite_create_aggregate(db, "x_count", 1, countStep, countFinalize, 0);
  return TCL_OK;
}



/*
** Usage:  sqlite_mprintf_int FORMAT INTEGER INTEGER INTEGER
**
** Call mprintf with three integer arguments
*/
static int sqlite_mprintf_int(
................................................................................
  Tcl_CreateCommand(interp, "sqlite_mprintf_double", sqlite_mprintf_double,0,0);
  Tcl_CreateCommand(interp, "sqlite_open", sqlite_test_open, 0, 0);
  Tcl_CreateCommand(interp, "sqlite_last_insert_rowid", test_last_rowid, 0, 0);
  Tcl_CreateCommand(interp, "sqlite_exec_printf", test_exec_printf, 0, 0);
  Tcl_CreateCommand(interp, "sqlite_get_table_printf", test_get_table_printf,
      0, 0);
  Tcl_CreateCommand(interp, "sqlite_close", sqlite_test_close, 0, 0);
  Tcl_CreateCommand(interp, "sqlite_create_function", 
      sqlite_test_create_function, 0, 0);
  Tcl_CreateCommand(interp, "sqlite_create_aggregate",
      sqlite_test_create_aggregate, 0, 0);
  Tcl_LinkVar(interp, "sqlite_search_count", 
      (char*)&sqlite_search_count, TCL_LINK_INT);
#ifdef MEMORY_DEBUG
  Tcl_CreateCommand(interp, "sqlite_malloc_fail", sqlite_malloc_fail, 0, 0);
  Tcl_CreateCommand(interp, "sqlite_malloc_stat", sqlite_malloc_stat, 0, 0);
#endif
  Tcl_CreateCommand(interp, "sqlite_abort", sqlite_abort, 0, 0);
  return TCL_OK;
}

Changes to src/util.c.

10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
....
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


**
*************************************************************************
** Utility functions used throughout sqlite.
**
** This file contains functions for allocating memory, comparing
** strings, and stuff like that.
**
** $Id: util.c,v 1.42 2002/05/10 05:44:56 drh Exp $
*/
#include "sqliteInt.h"
#include <stdarg.h>
#include <ctype.h>

/*
** If malloc() ever fails, this global variable gets set to 1.
................................................................................
      }
    }
  }
  return *zString==0;
}

/*
** Return a static string that describes the kind of error specified in the
** argument.








*/
const char *sqlite_error_string(int rc){
  const char *z;
  switch( rc ){
    case SQLITE_OK:         z = "not an error";                          break;
    case SQLITE_ERROR:      z = "SQL logic error or missing database";   break;
    case SQLITE_INTERNAL:   z = "internal SQLite implementation flaw";   break;
    case SQLITE_PERM:       z = "access permission denied";              break;
    case SQLITE_ABORT:      z = "callback requested query abort";        break;
    case SQLITE_BUSY:       z = "database is locked";                    break;
    case SQLITE_LOCKED:     z = "database table is locked";              break;
    case SQLITE_NOMEM:      z = "out of memory";                         break;
    case SQLITE_READONLY:   z = "attempt to write a readonly database";  break;
    case SQLITE_INTERRUPT:  z = "interrupted";                           break;
    case SQLITE_IOERR:      z = "disk I/O error";                        break;
    case SQLITE_CORRUPT:    z = "database disk image is malformed";      break;
    case SQLITE_NOTFOUND:   z = "table or record not found";             break;
    case SQLITE_FULL:       z = "database is full";                      break;
    case SQLITE_CANTOPEN:   z = "unable to open database file";          break;
    case SQLITE_PROTOCOL:   z = "database locking protocol failure";     break;
    case SQLITE_EMPTY:      z = "table contains no data";                break;




    case SQLITE_SCHEMA:     z = "database schema has changed";           break;
    case SQLITE_TOOBIG:     z = "too much data for one table row";       break;
    case SQLITE_CONSTRAINT: z = "constraint failed";                     break;
    case SQLITE_MISMATCH:   z = "datatype mismatch";                     break;

    case SQLITE_MISUSE:     z = "SQLite library used incorrectly";       break;
    default:                z = "unknown error";                         break;






  }














  return z;
}









|







 







|
|
>
>
>
>
>
>
>
>

<
<
<
<
<
<
<
<
|
|
|
|
|
|
|
|
<
<
<
<
>
>
>
>
|
|
|
<
>
|
|
>
>
>
>
>
>

>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
|
>
>
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
....
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
**
*************************************************************************
** Utility functions used throughout sqlite.
**
** This file contains functions for allocating memory, comparing
** strings, and stuff like that.
**
** $Id: util.c,v 1.43 2002/05/10 13:14:07 drh Exp $
*/
#include "sqliteInt.h"
#include <stdarg.h>
#include <ctype.h>

/*
** If malloc() ever fails, this global variable gets set to 1.
................................................................................
      }
    }
  }
  return *zString==0;
}

/*
** Change the sqlite.magic from SQLITE_MAGIC_OPEN to SQLITE_MAGIC_BUSY.
** Return an error (non-zero) if the magic was not SQLITE_MAGIC_OPEN
** when this routine is called.
**
** This routine is a attempt to detect if two threads use the
** same sqlite* pointer at the same time.  There is a race 
** condition so it is possible that the error is not detected.
** But usually the problem will be seen.  The result will be an
** error which can be used to debugging the application that is
** using SQLite incorrectly.
*/








int sqliteSafetyOn(sqlite *db){
  if( db->magic==SQLITE_MAGIC_OPEN ){
    db->magic = SQLITE_MAGIC_BUSY;
    return 0;
  }else{
    db->magic = SQLITE_MAGIC_ERROR;
    db->flags |= SQLITE_Interrupt;
    return 1;




  }
}

/*
** Change the magic from SQLITE_MAGIC_BUSY to SQLITE_MAGIC_OPEN.
** Return an error (non-zero) if the magic was not SQLITE_MAGIC_BUSY
** when this routine is called.

*/
int sqliteSafetyOff(sqlite *db){
  if( db->magic==SQLITE_MAGIC_BUSY ){
    db->magic = SQLITE_MAGIC_OPEN;
    return 0;
  }else{
    db->magic = SQLITE_MAGIC_ERROR;
    db->flags |= SQLITE_Interrupt;
    return 1;
  }
}

/*
** Check to make sure we are not currently executing an sqlite_exec().
** If we are currently in an sqlite_exec(), return true and set
** sqlite.magic to SQLITE_MAGIC_ERROR.  This will cause a complete
** shutdown of the database.
**
** This routine is used to try to detect when API routines are called
** at the wrong time or in the wrong sequence.
*/
int sqliteSafetyCheck(sqlite *db){
  if( db->recursionDepth ){
    db->magic = SQLITE_MAGIC_ERROR;
    return 1;
  }
  return 0;
}

Changes to src/vdbe.c.

26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
....
1108
1109
1110
1111
1112
1113
1114
1115


1116


1117
1118
1119
1120
1121
1122
1123
....
1295
1296
1297
1298
1299
1300
1301



1302

1303
1304
1305
1306
1307
1308
1309
1310
** type to the other occurs as necessary.
** 
** Most of the code in this file is taken up by the sqliteVdbeExec()
** function which does the work of interpreting a VDBE program.
** But other routines are also provided to help in building up
** a program instruction by instruction.
**
** $Id: vdbe.c,v 1.140 2002/05/10 05:44:56 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>

/*
** The following global variable is incremented every time a cursor
** moves, either by the OP_MoveTo or the OP_Next opcode.  The test
................................................................................
  azValue[2] = zP1;
  azValue[3] = zP2;
  azValue[5] = 0;
  rc = SQLITE_OK;
  for(i=0; rc==SQLITE_OK && i<p->nOp; i++){
    if( db->flags & SQLITE_Interrupt ){
      db->flags &= ~SQLITE_Interrupt;
      sqliteSetString(pzErrMsg, "interrupted", 0);


      rc = SQLITE_INTERRUPT;


      break;
    }
    sprintf(zAddr,"%d",i);
    sprintf(zP1,"%d", p->aOp[i].p1);
    sprintf(zP2,"%d", p->aOp[i].p2);
    if( p->aOp[i].p3type==P3_POINTER ){
      sprintf(zP3, "ptr(%#x)", (int)p->aOp[i].p3);
................................................................................
             VERIFY(&& pc>=0); pc++){
    pOp = &p->aOp[pc];

    /* Interrupt processing if requested.
    */
    if( db->flags & SQLITE_Interrupt ){
      db->flags &= ~SQLITE_Interrupt;



      rc = SQLITE_INTERRUPT;

      sqliteSetString(pzErrMsg, "interrupted", 0);
      break;
    }

    /* Only allow tracing if NDEBUG is not defined.
    */
#ifndef NDEBUG
    if( p->trace ){







|







 







|
>
>
|
>
>







 







>
>
>
|
>
|







26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
....
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
....
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
** type to the other occurs as necessary.
** 
** Most of the code in this file is taken up by the sqliteVdbeExec()
** function which does the work of interpreting a VDBE program.
** But other routines are also provided to help in building up
** a program instruction by instruction.
**
** $Id: vdbe.c,v 1.141 2002/05/10 13:14:07 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>

/*
** The following global variable is incremented every time a cursor
** moves, either by the OP_MoveTo or the OP_Next opcode.  The test
................................................................................
  azValue[2] = zP1;
  azValue[3] = zP2;
  azValue[5] = 0;
  rc = SQLITE_OK;
  for(i=0; rc==SQLITE_OK && i<p->nOp; i++){
    if( db->flags & SQLITE_Interrupt ){
      db->flags &= ~SQLITE_Interrupt;
      if( db->magic!=SQLITE_MAGIC_BUSY ){
        rc = SQLITE_MISUSE;
      }else{
        rc = SQLITE_INTERRUPT;
      }
      sqliteSetString(pzErrMsg, sqlite_error_string(rc), 0);
      break;
    }
    sprintf(zAddr,"%d",i);
    sprintf(zP1,"%d", p->aOp[i].p1);
    sprintf(zP2,"%d", p->aOp[i].p2);
    if( p->aOp[i].p3type==P3_POINTER ){
      sprintf(zP3, "ptr(%#x)", (int)p->aOp[i].p3);
................................................................................
             VERIFY(&& pc>=0); pc++){
    pOp = &p->aOp[pc];

    /* Interrupt processing if requested.
    */
    if( db->flags & SQLITE_Interrupt ){
      db->flags &= ~SQLITE_Interrupt;
      if( db->magic!=SQLITE_MAGIC_BUSY ){
        rc = SQLITE_MISUSE;
      }else{
        rc = SQLITE_INTERRUPT;
      }
      sqliteSetString(pzErrMsg, sqlite_error_string(rc), 0);
      break;
    }

    /* Only allow tracing if NDEBUG is not defined.
    */
#ifndef NDEBUG
    if( p->trace ){

Changes to test/all.test.

6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
..
29
30
31
32
33
34
35

36
37
38
39
40
41
42
..
67
68
69
70
71
72
73
74
75
76

77
78
79
#    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 runs all tests.
#
# $Id: all.test,v 1.13 2002/03/06 22:01:36 drh Exp $

set testdir [file dirname $argv0]
source $testdir/tester.tcl
rename finish_test really_finish_test
proc finish_test {} {memleak_check}

if {[file exists ./sqlite_test_count]} {
................................................................................
#
set LeakList {}

set EXCLUDE {
  all.test
  quick.test
  malloc.test

  btree2.test
}

for {set Counter 0} {$Counter<$COUNT && $nErr==0} {incr Counter} {
  if {$Counter%2} {
    set ::SETUP_SQL {PRAGMA default_synchronous=off;}
  } else {
................................................................................
       lappend ::failList memory-leak-test
       break
    }
  }
  puts " Ok"
}

# Run the malloc tests after memory leak detection.  We do leak
# some if malloc fails.
#

catch {source $testdir/malloc.test}

really_finish_test







|







 







>







 







|
|

>



6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
..
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
..
68
69
70
71
72
73
74
75
76
77
78
79
80
81
#    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 runs all tests.
#
# $Id: all.test,v 1.14 2002/05/10 13:14:08 drh Exp $

set testdir [file dirname $argv0]
source $testdir/tester.tcl
rename finish_test really_finish_test
proc finish_test {} {memleak_check}

if {[file exists ./sqlite_test_count]} {
................................................................................
#
set LeakList {}

set EXCLUDE {
  all.test
  quick.test
  malloc.test
  misuse.test
  btree2.test
}

for {set Counter 0} {$Counter<$COUNT && $nErr==0} {incr Counter} {
  if {$Counter%2} {
    set ::SETUP_SQL {PRAGMA default_synchronous=off;}
  } else {
................................................................................
       lappend ::failList memory-leak-test
       break
    }
  }
  puts " Ok"
}

# Run the malloc tests and the misuse test after memory leak detection.
# Both tests leak memory.
#
catch {source $testdir/misuse.test}
catch {source $testdir/malloc.test}

really_finish_test

Changes to test/lock.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
#    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 is database locks.
#
# $Id: lock.test,v 1.13 2001/10/09 04:19:47 drh Exp $


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

# Create an alternative connection to the database
#
do_test lock-1.0 {
  sqlite db2 ./test.db

} {}
do_test lock-1.1 {
  execsql {SELECT name FROM sqlite_master WHERE type='table' ORDER BY name}
} {}
do_test lock-1.2 {
  execsql {SELECT name FROM sqlite_master WHERE type='table' ORDER BY name} db2
} {}







|









>







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
#    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 is database locks.
#
# $Id: lock.test,v 1.14 2002/05/10 13:14:08 drh Exp $


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

# Create an alternative connection to the database
#
do_test lock-1.0 {
  sqlite db2 ./test.db
  set dummy {}
} {}
do_test lock-1.1 {
  execsql {SELECT name FROM sqlite_master WHERE type='table' ORDER BY name}
} {}
do_test lock-1.2 {
  execsql {SELECT name FROM sqlite_master WHERE type='table' ORDER BY name} db2
} {}

Changes to test/main.test.

7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
..
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
#    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 file is exercising the code in main.c.
#
# $Id: main.test,v 1.9 2001/10/13 02:59:09 drh Exp $

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

# Tests of the sqlite_complete() function.
#
do_test main-1.1 {
................................................................................
do_test main-2.0 {
  catch {db close}
  file delete -force test.db
  set fd [open test.db w]
  puts $fd hi!
  close $fd
  set v [catch {sqlite db test.db} msg]
  lappend v $msg
} {0 {}}

# Here are some tests for tokenize.c.  
#
do_test main-3.1 {
  catch {db close}
  foreach f [glob -nocomplain testdb/*] {file delete -force $f}







|







 







|







7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
..
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
#    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 file is exercising the code in main.c.
#
# $Id: main.test,v 1.10 2002/05/10 13:14:08 drh Exp $

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

# Tests of the sqlite_complete() function.
#
do_test main-1.1 {
................................................................................
do_test main-2.0 {
  catch {db close}
  file delete -force test.db
  set fd [open test.db w]
  puts $fd hi!
  close $fd
  set v [catch {sqlite db test.db} msg]
  if {$v} {lappend v $msg} {lappend v {}}
} {0 {}}

# Here are some tests for tokenize.c.  
#
do_test main-3.1 {
  catch {db close}
  foreach f [glob -nocomplain testdb/*] {file delete -force $f}

Added test/misuse.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
# 2002 May 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 regression tests for SQLite library.
#
# This file implements tests for the SQLITE_MISUSE detection logic.
# This test file leaks memory and file descriptors.
#
# $Id: misuse.test,v 1.1 2002/05/10 13:14:08 drh Exp $

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

# Make sure the test logic works
#
do_test misuse-1.1 {
  db close
  set ::DB [sqlite db test.db]
  execsql {
    CREATE TABLE t1(a,b);
    INSERT INTO t1 VALUES(1,2);
  }
  sqlite_exec_printf $::DB {SELECT * FROM t1} {}
} {0 {a b 1 2}}
do_test misuse-1.2 {
  sqlite_exec_printf $::DB {SELECT x_coalesce(NULL,a) AS 'xyz' FROM t1} {}
} {1 {no such function: x_coalesce}}
do_test misuse-1.3 {
  sqlite_create_function $::DB
  sqlite_exec_printf $::DB {SELECT x_coalesce(NULL,a) AS 'xyz' FROM t1} {}
} {0 {xyz 1}}

# Use the x_sqlite_exec() SQL function to simulate the effect of two
# threads trying to use the same database at the same time.
#
do_test misuse-1.4 {
  sqlite_exec_printf $::DB {
     SELECT x_sqlite_exec('SELECT * FROM t1');
  } {}
} {21 {library routine called out of sequence}}
do_test misuse-1.5 {
  sqlite_exec_printf $::DB {SELECT * FROM t1} {}
} {21 {library routine called out of sequence}}
do_test misuse-1.6 {
  catchsql {
    SELECT * FROM t1
  }
} {1 {library routine called out of sequence}}

# Attempt to register a new SQL function while an sqlite_exec() is active.
#
do_test misuse-2.1 {
  db close
  set ::DB [sqlite db test.db]
  execsql {
    SELECT * FROM t1
  }
} {1 2}
do_test misuse-2.2 {
  sqlite_exec_printf $::DB {SELECT * FROM t1} {}
} {0 {a b 1 2}}
do_test misuse-2.3 {
  set v [catch {
    db eval {SELECT * FROM t1} {} {
      sqlite_create_function $::DB
    }
  } msg]
  lappend v $msg
} {1 {library routine called out of sequence}}
do_test misuse-2.4 {
  sqlite_exec_printf $::DB {SELECT * FROM t1} {}
} {21 {library routine called out of sequence}}
do_test misuse-2.5 {
  catchsql {
    SELECT * FROM t1
  }
} {1 {library routine called out of sequence}}

# Attempt to register a new SQL aggregate while an sqlite_exec() is active.
#
do_test misuse-3.1 {
  db close
  set ::DB [sqlite db test.db]
  execsql {
    SELECT * FROM t1
  }
} {1 2}
do_test misuse-3.2 {
  sqlite_exec_printf $::DB {SELECT * FROM t1} {}
} {0 {a b 1 2}}
do_test misuse-3.3 {
  set v [catch {
    db eval {SELECT * FROM t1} {} {
      sqlite_create_aggregate $::DB
    }
  } msg]
  lappend v $msg
} {1 {library routine called out of sequence}}
do_test misuse-3.4 {
  sqlite_exec_printf $::DB {SELECT * FROM t1} {}
} {21 {library routine called out of sequence}}
do_test misuse-3.5 {
  catchsql {
    SELECT * FROM t1
  }
} {1 {library routine called out of sequence}}

# Attempt to close the database from an sqlite_exec callback.
#
do_test misuse-4.1 {
  db close
  set ::DB [sqlite db test.db]
  execsql {
    SELECT * FROM t1
  }
} {1 2}
do_test misuse-4.2 {
  sqlite_exec_printf $::DB {SELECT * FROM t1} {}
} {0 {a b 1 2}}
do_test misuse-4.3 {
  set v [catch {
    db eval {SELECT * FROM t1} {} {
      sqlite_close $::DB
    }
  } msg]
  lappend v $msg
} {1 {library routine called out of sequence}}
do_test misuse-4.4 {
  sqlite_exec_printf $::DB {SELECT * FROM t1} {}
} {21 {library routine called out of sequence}}
do_test misuse-4.5 {
  catchsql {
    SELECT * FROM t1
  }
} {1 {library routine called out of sequence}}

# Attempt to use a database after it has been closed.
#
do_test misuse-5.1 {
  db close
  set ::DB [sqlite db test.db]
  execsql {
    SELECT * FROM t1
  }
} {1 2}
do_test misuse-5.2 {
  sqlite_exec_printf $::DB {SELECT * FROM t1} {}
} {0 {a b 1 2}}
do_test misuse-5.3 {
  db close
  sqlite_exec_printf $::DB {SELECT * FROM t1} {}
} {21 {library routine called out of sequence}}

finish_test

Changes to test/temptable.test.

8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

24
25
26
27
28
29
30
#    May you share freely, never taking more than you give.
#
#***********************************************************************
# This file implements regression tests for SQLite library.
#
# This file implements tests for temporary tables and indices.
#
# $Id: temptable.test,v 1.4 2002/01/10 14:31:49 drh Exp $

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

# Create an alternative connection to the database
#
do_test temptable-1.0 {
  sqlite db2 ./test.db

} {}

# Create a permanent table.
#
do_test temptable-1.1 {
  execsql {CREATE TABLE t1(a,b,c);}
  execsql {INSERT INTO t1 VALUES(1,2,3);}







|








>







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#    May you share freely, never taking more than you give.
#
#***********************************************************************
# This file implements regression tests for SQLite library.
#
# This file implements tests for temporary tables and indices.
#
# $Id: temptable.test,v 1.5 2002/05/10 13:14:08 drh Exp $

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

# Create an alternative connection to the database
#
do_test temptable-1.0 {
  sqlite db2 ./test.db
  set dummy {}
} {}

# Create a permanent table.
#
do_test temptable-1.1 {
  execsql {CREATE TABLE t1(a,b,c);}
  execsql {INSERT INTO t1 VALUES(1,2,3);}

Changes to www/c_interface.tcl.

1
2
3
4
5
6
7
8
9
10
11
...
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
#
# Run this Tcl script to generate the sqlite.html file.
#
set rcsid {$Id: c_interface.tcl,v 1.27 2002/05/10 05:44:57 drh Exp $}

puts {<html>
<head>
  <title>The C language interface to the SQLite library</title>
</head>
<body bgcolor=white>
<h1 align=center>
................................................................................
an INTEGER PRIMARY KEY column is only allowed to store integer data.
</p></dd>
<dt>SQLITE_MISUSE</dt>
<dd><p>This error might occur if one or more of the SQLite API routines
is used incorrectly.  Examples of incorrect usage include calling
<b>sqlite_exec()</b> after the database has been closed using
<b>sqlite_close()</b> or calling <b>sqlite_exec()</b> with the same
database pointer simultaneously from two separate threads.  The
library makes an effort to detect these sorts of problems, but it
cannot detect them with 100% accuracy.
</p></dd>
</dl>
</blockquote>

<h2>The Extended API</h2>

<p>Only the three core routines shown above are required to use



|







 







|
<
<







1
2
3
4
5
6
7
8
9
10
11
...
296
297
298
299
300
301
302
303


304
305
306
307
308
309
310
#
# Run this Tcl script to generate the sqlite.html file.
#
set rcsid {$Id: c_interface.tcl,v 1.28 2002/05/10 13:14:08 drh Exp $}

puts {<html>
<head>
  <title>The C language interface to the SQLite library</title>
</head>
<body bgcolor=white>
<h1 align=center>
................................................................................
an INTEGER PRIMARY KEY column is only allowed to store integer data.
</p></dd>
<dt>SQLITE_MISUSE</dt>
<dd><p>This error might occur if one or more of the SQLite API routines
is used incorrectly.  Examples of incorrect usage include calling
<b>sqlite_exec()</b> after the database has been closed using
<b>sqlite_close()</b> or calling <b>sqlite_exec()</b> with the same
database pointer simultaneously from two separate threads.


</p></dd>
</dl>
</blockquote>

<h2>The Extended API</h2>

<p>Only the three core routines shown above are required to use

Changes to www/changes.tcl.

20
21
22
23
24
25
26





27
28
29
30
31
32
33
}


proc chng {date desc} {
  puts "<DT><B>$date</B></DT>"
  puts "<DD><P><UL>$desc</UL></P></DD>"
}






chng {2002 May 08 (2.4.11)} {
<li>Bug fix: Column names in the result set were not being generated
    correctly for some (rather complex) VIEWs.  This could cause a
    segfault under certain circumstances.</li>
}








>
>
>
>
>







20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
}


proc chng {date desc} {
  puts "<DT><B>$date</B></DT>"
  puts "<DD><P><UL>$desc</UL></P></DD>"
}

chng {2002 May 09 (2.4.12)} {
<li>Added logic to detect when the library API routines are called out
    of sequence.</li>
}

chng {2002 May 08 (2.4.11)} {
<li>Bug fix: Column names in the result set were not being generated
    correctly for some (rather complex) VIEWs.  This could cause a
    segfault under certain circumstances.</li>
}