/ Check-in [4ad096bd]
Login
SQLite training in Houston TX on 2019-11-05 (details)
Part of the 2019 Tcl Conference

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

Overview
Comment:Fix bug in the premutation testing that was causing many permutations from begin skipped. There are now 16 errors reported by the permutation test. (CVS 5610)
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 4ad096bda1fc5c7b66f71ff5b32a4085c9a40574
User & Date: drh 2008-08-25 17:23:29
Context
2008-08-25
19:09
Fix obscure permutation test problems. (CVS 5611) check-in: aa92a1be user: drh tags: trunk
17:23
Fix bug in the premutation testing that was causing many permutations from begin skipped. There are now 16 errors reported by the permutation test. (CVS 5610) check-in: 4ad096bd user: drh tags: trunk
14:49
Pick up a small performance increase by eliminating the pcacheRef() function. (CVS 5609) check-in: e3840fbf user: danielk1977 tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/pager.c.

14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
....
2491
2492
2493
2494
2495
2496
2497
2498
2499
2500
2501
2502




2503
2504
2505
2506
2507
2508
2509
2510
2511
2512
2513
2514
2515
2516
2517
2518
2519
2520
2521
2522
2523
2524
2525
2526
2527
** The pager is used to access a database disk file.  It implements
** atomic commit and rollback through the use of a journal file that
** is separate from the database file.  The pager also implements file
** locking to prevent two processes from writing the same database
** file simultaneously, or one process from reading the database while
** another is writing.
**
** @(#) $Id: pager.c,v 1.478 2008/08/25 07:12:29 danielk1977 Exp $
*/
#ifndef SQLITE_OMIT_DISKIO
#include "sqliteInt.h"

/*
** Macros for troubleshooting.  Normally turned off
*/
................................................................................
** journal file exists and is not empty this routine assumes it
** is hot.  The pager_playback() routine will discover that the
** journal file is not really hot and will no-op.
*/
static int hasHotJournal(Pager *pPager, int *pExists){
  sqlite3_vfs *pVfs = pPager->pVfs;
  int rc = SQLITE_OK;
  *pExists = 0;
  if( pPager->useJournal && pPager->fd->pMethods ){
    int exists;
    int locked;





    rc = sqlite3OsAccess(pVfs, pPager->zJournal, SQLITE_ACCESS_EXISTS, &exists);
    if( rc==SQLITE_OK && exists ){
      rc = sqlite3OsCheckReservedLock(pPager->fd, &locked);
    }

    if( rc==SQLITE_OK && exists && !locked ){
      int nPage;
      rc = sqlite3PagerPagecount(pPager, &nPage);
      if( rc==SQLITE_OK ){
        if( nPage==0 ){
          sqlite3OsDelete(pVfs, pPager->zJournal, 0);
        }else{
          *pExists = 1;
        }
      }
    }
  }

  return rc;
}

/*
** Read the content of page pPg out of the database file.
*/
static int readDbPage(Pager *pPager, PgHdr *pPg, Pgno pgno){







|







 







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







14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
....
2491
2492
2493
2494
2495
2496
2497


2498
2499

2500
2501
2502
2503
2504
2505
2506
2507

2508
2509
2510
2511
2512
2513
2514
2515
2516
2517
2518


2519
2520
2521
2522
2523
2524
2525
** The pager is used to access a database disk file.  It implements
** atomic commit and rollback through the use of a journal file that
** is separate from the database file.  The pager also implements file
** locking to prevent two processes from writing the same database
** file simultaneously, or one process from reading the database while
** another is writing.
**
** @(#) $Id: pager.c,v 1.479 2008/08/25 17:23:29 drh Exp $
*/
#ifndef SQLITE_OMIT_DISKIO
#include "sqliteInt.h"

/*
** Macros for troubleshooting.  Normally turned off
*/
................................................................................
** journal file exists and is not empty this routine assumes it
** is hot.  The pager_playback() routine will discover that the
** journal file is not really hot and will no-op.
*/
static int hasHotJournal(Pager *pPager, int *pExists){
  sqlite3_vfs *pVfs = pPager->pVfs;
  int rc = SQLITE_OK;


  int exists;
  int locked;

  assert( pPager!=0 );
  assert( pPager->useJournal );
  assert( pPager->fd->pMethods );
  *pExists = 0;
  rc = sqlite3OsAccess(pVfs, pPager->zJournal, SQLITE_ACCESS_EXISTS, &exists);
  if( rc==SQLITE_OK && exists ){
    rc = sqlite3OsCheckReservedLock(pPager->fd, &locked);
  }

  if( rc==SQLITE_OK && exists && !locked ){
    int nPage;
    rc = sqlite3PagerPagecount(pPager, &nPage);
    if( rc==SQLITE_OK ){
     if( nPage==0 ){
        sqlite3OsDelete(pVfs, pPager->zJournal, 0);
      }else{
        *pExists = 1;
      }
    }
  }


  return rc;
}

/*
** Read the content of page pPg out of the database file.
*/
static int readDbPage(Pager *pPager, PgHdr *pPg, Pgno pgno){

Changes to src/resolve.c.

10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
...
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
...
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
...
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
...
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
...
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
...
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
....
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
**
*************************************************************************
**
** This file contains routines used for walking the parser tree and
** resolve all identifiers by associating them with a particular
** table and column.
**
** $Id: resolve.c,v 1.3 2008/08/25 12:14:09 drh Exp $
*/
#include "sqliteInt.h"
#include <stdlib.h>
#include <string.h>

/*
** Given the name of a column of the form X.Y.Z or Y.Z or just Z, look up
................................................................................
    pSelect->pPrior->pNext = pSelect;
    pSelect = pSelect->pPrior;
  }
  while( pSelect && moreToDo ){
    struct ExprList_item *pItem;
    moreToDo = 0;
    pEList = pSelect->pEList;
    if( pEList==0 ){
      return 1;
    }
    for(i=0, pItem=pOrderBy->a; i<pOrderBy->nExpr; i++, pItem++){
      int iCol = -1;
      Expr *pE, *pDup;
      if( pItem->done ) continue;
      pE = pItem->pExpr;
      if( sqlite3ExprIsInteger(pE, &iCol) ){
        if( iCol<0 || iCol>pEList->nExpr ){
................................................................................
#if SQLITE_MAX_COLUMN
  if( pOrderBy->nExpr>db->aLimit[SQLITE_LIMIT_COLUMN] ){
    sqlite3ErrorMsg(pParse, "too many terms in %s BY clause", zType);
    return 1;
  }
#endif
  pEList = pSelect->pEList;
  if( pEList==0 ){
    return 0;
  }
  for(i=0, pItem=pOrderBy->a; i<pOrderBy->nExpr; i++, pItem++){
    if( pItem->iCol ){
      Expr *pE;
      CollSeq *pColl;
      int flags;

      if( pItem->iCol>pEList->nExpr ){
................................................................................
      }
      pE = pItem->pExpr;
      pColl = pE->pColl;
      flags = pE->flags & EP_ExpCollate;
      sqlite3ExprDelete(db, pE);
      pE = sqlite3ExprDup(db, pEList->a[pItem->iCol-1].pExpr);
      pItem->pExpr = pE;
      if( pE && pColl && flags ){
        pE->pColl = pColl;
        pE->flags |= flags;
      }
    }
  }
  return 0;
}
................................................................................
      pItem->iCol = iCol;
      continue;
    }
    if( sqlite3ExprIsInteger(pE, &iCol) ){
      /* The ORDER BY term is an integer constant.  Again, set the column
      ** number so that sqlite3ResolveOrderGroupBy() will convert the
      ** order-by term to a copy of the result-set expression */
      if( iCol<1 || iCol>nResult ){
        resolveOutOfRangeError(pParse, zType, i+1, nResult);
        return 1;
      }
      pItem->iCol = iCol;
      continue;
    }

................................................................................
  ExprList *pEList;       /* Result set expression list */
  int i;                  /* Loop counter */
  ExprList *pGroupBy;     /* The GROUP BY clause */
  Select *pLeftmost;      /* Left-most of SELECT of a compound */
  sqlite3 *db;            /* Database connection */
  

  if( p==0 ) return WRC_Continue;
  if( p->selFlags & SF_Resolved ){
    return WRC_Prune;
  }
  pOuterNC = pWalker->u.pNC;
  pParse = pWalker->pParse;
  db = pParse->db;

................................................................................
    */
    sNC.allowAgg = 1;
    sNC.pSrcList = p->pSrc;
    sNC.pNext = pOuterNC;
  
    /* Resolve names in the result set. */
    pEList = p->pEList;
    if( !pEList ) return WRC_Abort;
    for(i=0; i<pEList->nExpr; i++){
      Expr *pX = pEList->a[i].pExpr;
      if( sqlite3ResolveExprNames(&sNC, pX) ){
        return WRC_Abort;
      }
    }
  
................................................................................
void sqlite3ResolveSelectNames(
  Parse *pParse,         /* The parser context */
  Select *p,             /* The SELECT statement being coded. */
  NameContext *pOuterNC  /* Name context for parent SELECT statement */
){
  Walker w;

  if( p ){
    w.xExprCallback = resolveExprStep;
    w.xSelectCallback = resolveSelectStep;
    w.pParse = pParse;
    w.u.pNC = pOuterNC;
    sqlite3WalkSelect(&w, p);
  }
}







|







 







|
<
<







 







|
<
<







 







|







 







|







 







|







 







|







 







|
|
|
|
|
|
|
<
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
...
643
644
645
646
647
648
649
650


651
652
653
654
655
656
657
...
724
725
726
727
728
729
730
731


732
733
734
735
736
737
738
...
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
...
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
...
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
...
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
....
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107

**
*************************************************************************
**
** This file contains routines used for walking the parser tree and
** resolve all identifiers by associating them with a particular
** table and column.
**
** $Id: resolve.c,v 1.4 2008/08/25 17:23:29 drh Exp $
*/
#include "sqliteInt.h"
#include <stdlib.h>
#include <string.h>

/*
** Given the name of a column of the form X.Y.Z or Y.Z or just Z, look up
................................................................................
    pSelect->pPrior->pNext = pSelect;
    pSelect = pSelect->pPrior;
  }
  while( pSelect && moreToDo ){
    struct ExprList_item *pItem;
    moreToDo = 0;
    pEList = pSelect->pEList;
    assert( pEList!=0 );


    for(i=0, pItem=pOrderBy->a; i<pOrderBy->nExpr; i++, pItem++){
      int iCol = -1;
      Expr *pE, *pDup;
      if( pItem->done ) continue;
      pE = pItem->pExpr;
      if( sqlite3ExprIsInteger(pE, &iCol) ){
        if( iCol<0 || iCol>pEList->nExpr ){
................................................................................
#if SQLITE_MAX_COLUMN
  if( pOrderBy->nExpr>db->aLimit[SQLITE_LIMIT_COLUMN] ){
    sqlite3ErrorMsg(pParse, "too many terms in %s BY clause", zType);
    return 1;
  }
#endif
  pEList = pSelect->pEList;
  assert( pEList!=0 );  /* sqlite3SelectNew() guarantees this */


  for(i=0, pItem=pOrderBy->a; i<pOrderBy->nExpr; i++, pItem++){
    if( pItem->iCol ){
      Expr *pE;
      CollSeq *pColl;
      int flags;

      if( pItem->iCol>pEList->nExpr ){
................................................................................
      }
      pE = pItem->pExpr;
      pColl = pE->pColl;
      flags = pE->flags & EP_ExpCollate;
      sqlite3ExprDelete(db, pE);
      pE = sqlite3ExprDup(db, pEList->a[pItem->iCol-1].pExpr);
      pItem->pExpr = pE;
      if( pE && flags ){
        pE->pColl = pColl;
        pE->flags |= flags;
      }
    }
  }
  return 0;
}
................................................................................
      pItem->iCol = iCol;
      continue;
    }
    if( sqlite3ExprIsInteger(pE, &iCol) ){
      /* The ORDER BY term is an integer constant.  Again, set the column
      ** number so that sqlite3ResolveOrderGroupBy() will convert the
      ** order-by term to a copy of the result-set expression */
      if( iCol<1 ){
        resolveOutOfRangeError(pParse, zType, i+1, nResult);
        return 1;
      }
      pItem->iCol = iCol;
      continue;
    }

................................................................................
  ExprList *pEList;       /* Result set expression list */
  int i;                  /* Loop counter */
  ExprList *pGroupBy;     /* The GROUP BY clause */
  Select *pLeftmost;      /* Left-most of SELECT of a compound */
  sqlite3 *db;            /* Database connection */
  

  assert( p!=0 );
  if( p->selFlags & SF_Resolved ){
    return WRC_Prune;
  }
  pOuterNC = pWalker->u.pNC;
  pParse = pWalker->pParse;
  db = pParse->db;

................................................................................
    */
    sNC.allowAgg = 1;
    sNC.pSrcList = p->pSrc;
    sNC.pNext = pOuterNC;
  
    /* Resolve names in the result set. */
    pEList = p->pEList;
    assert( pEList!=0 );
    for(i=0; i<pEList->nExpr; i++){
      Expr *pX = pEList->a[i].pExpr;
      if( sqlite3ResolveExprNames(&sNC, pX) ){
        return WRC_Abort;
      }
    }
  
................................................................................
void sqlite3ResolveSelectNames(
  Parse *pParse,         /* The parser context */
  Select *p,             /* The SELECT statement being coded. */
  NameContext *pOuterNC  /* Name context for parent SELECT statement */
){
  Walker w;

  assert( p!=0 );
  w.xExprCallback = resolveExprStep;
  w.xSelectCallback = resolveSelectStep;
  w.pParse = pParse;
  w.u.pNC = pOuterNC;
  sqlite3WalkSelect(&w, p);
}

Changes to src/select.c.

8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
..
83
84
85
86
87
88
89
90
91

92
93
94
95
96
97
98
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** This file contains C code routines that are called by the parser
** to handle SELECT statements in SQLite.
**
** $Id: select.c,v 1.469 2008/08/22 16:29:51 drh Exp $
*/
#include "sqliteInt.h"


/*
** Delete all the content of a Select structure but do not deallocate
** the select structure itself.
................................................................................
  pNew->op = TK_SELECT;
  assert( pOffset==0 || pLimit!=0 );
  pNew->pLimit = pLimit;
  pNew->pOffset = pOffset;
  pNew->addrOpenEphm[0] = -1;
  pNew->addrOpenEphm[1] = -1;
  pNew->addrOpenEphm[2] = -1;
  if( pNew==&standin) {
    clearSelect(db, pNew);

    pNew = 0;
  }
  return pNew;
}

/*
** Delete the given Select structure and all of its substructures.







|







 







|

>







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
..
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** This file contains C code routines that are called by the parser
** to handle SELECT statements in SQLite.
**
** $Id: select.c,v 1.470 2008/08/25 17:23:29 drh Exp $
*/
#include "sqliteInt.h"


/*
** Delete all the content of a Select structure but do not deallocate
** the select structure itself.
................................................................................
  pNew->op = TK_SELECT;
  assert( pOffset==0 || pLimit!=0 );
  pNew->pLimit = pLimit;
  pNew->pOffset = pOffset;
  pNew->addrOpenEphm[0] = -1;
  pNew->addrOpenEphm[1] = -1;
  pNew->addrOpenEphm[2] = -1;
  if( db->mallocFailed ) {
    clearSelect(db, pNew);
    if( pNew!=&standin ) sqlite3DbFree(db, pNew);
    pNew = 0;
  }
  return pNew;
}

/*
** Delete the given Select structure and all of its substructures.

Changes to test/permutations.test.

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
...
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
...
467
468
469
470
471
472
473

474
475
476
477
478
479
480
481
...
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
#
#    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.
#
#***********************************************************************
#
# $Id: permutations.test,v 1.21 2008/08/21 15:54:01 danielk1977 Exp $

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

# Argument processing.
#


set ::testmode [lindex $argv 0]
set ::testfile [lindex $argv 1]

set argv [lrange $argv 2 end]


set ::permutations_presql ""
set ::permutations_test_prefix ""

if {$::testmode eq "veryquick"} {
  set ::testmode [list persistent_journal no_journal]
  set ISQUICK 1
}
if {$::testmode eq "quick"} {
  set ::testmode [list persistent_journal no_journal autovacuum_ioerr]
  set ISQUICK 1
}
if {$::testmode eq "all"} {
  set ::testmode {
    memsubsys1 memsubsys2 singlethread multithread onefile utf16 exclusive
    persistent_journal persistent_journal_error no_journal no_journal_error
    autovacuum_ioerr no_mutex_try
  }
}
if {$::testmode eq "targets"} { 
  puts ""
  puts -nonewline "veryquick            "
  puts "Same as persistent_journal and no_journal"
  puts -nonewline "quick                "
  puts "Same as persistent_journal, no_journal and autovacuum_ioerr"
  puts -nonewline "all                  "
  puts "Everything except autovacuum_crash"
}


set EXCLUDE {
  all.test                  in2.test                  onefile.test
  async2.test               incrvacuum_ioerr.test     permutations.test
  async.test                jrnlmode2.test            quick.test
  autovacuum_crash.test     jrnlmode3.test            shared_err.test
  autovacuum_ioerr.test     jrnlmode4.test            soak.test
................................................................................
  set options(-shutdown) ""
  set options(-initialize) ""
  set options(-exclude) ""
  set options(-include) $::ALLTESTS
  set options(-presql) ""
  set options(-description) "no description supplied (fixme)"
  array set options $args



  if {$::testmode eq "targets"} {
    puts [format "% -20s %s" $name [string trim $options(-description)]]
    return
  }
  if {$::testmode ne "" && [lsearch $::testmode $name]<0} return




  uplevel $options(-initialize)
  set ::permutations_presql $options(-presql)

  foreach file $options(-include) {
    if {[lsearch $options(-exclude) $file] < 0 && (


      $::testfile eq "" || $::testfile eq $file || "$::testfile.test" eq $file
    ) } {
      uplevel source $::testdir/$file


    }
  }

  uplevel $options(-shutdown)
}

#############################################################################
................................................................................
    sqlite3_initialize
  }
}

ifcapable threadsafe {
  run_tests "no_mutex_try" -description {
     The sqlite3_mutex_try() interface always fails

  } -initialize {
    catch {db close}
    sqlite3_shutdown
    install_mutex_counters 1
    set ::disable_mutex_try 1
  } -shutdown {
    catch {db close}
    sqlite3_shutdown
................................................................................
#   rename sa_crashsql crashsql
# } -include crash.test


# End of tests
#############################################################################

if {$::testmode eq "targets"} { puts "" ; exit }

# Restore the [sqlite3] command.
#
rename sqlite3 {}
rename really_sqlite3 sqlite3

# Restore the [finish_test] command.







|






>
>
|
|
>

>




|
|


|
|


|
|





|








>







 







>
>

|



|
>
>
>





|
>
>
|
|

>
>







 







>
|







 







|







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
...
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
...
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
...
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
#
#    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.
#
#***********************************************************************
#
# $Id: permutations.test,v 1.22 2008/08/25 17:23:29 drh Exp $

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

# Argument processing.
#
#puts "PERM-DEBUG: argv=$argv"
namespace eval ::perm {
  set testmode [lindex $::argv 0]
  set testfile [lindex $::argv 1]
}
set argv [lrange $argv 2 end]
#puts "PERM-DEBUG: testmode=$::perm::testmode"

set ::permutations_presql ""
set ::permutations_test_prefix ""

if {$::perm::testmode eq "veryquick"} {
  set ::perm::testmode [list persistent_journal no_journal]
  set ISQUICK 1
}
if {$::perm::testmode eq "quick"} {
  set ::perm::testmode [list persistent_journal no_journal autovacuum_ioerr]
  set ISQUICK 1
}
if {$::perm::testmode eq "all"} {
  set ::perm::testmode {
    memsubsys1 memsubsys2 singlethread multithread onefile utf16 exclusive
    persistent_journal persistent_journal_error no_journal no_journal_error
    autovacuum_ioerr no_mutex_try
  }
}
if {$::perm::testmode eq "targets"} { 
  puts ""
  puts -nonewline "veryquick            "
  puts "Same as persistent_journal and no_journal"
  puts -nonewline "quick                "
  puts "Same as persistent_journal, no_journal and autovacuum_ioerr"
  puts -nonewline "all                  "
  puts "Everything except autovacuum_crash"
}
puts "PERM-DEBUG: testmode=$::perm::testmode"

set EXCLUDE {
  all.test                  in2.test                  onefile.test
  async2.test               incrvacuum_ioerr.test     permutations.test
  async.test                jrnlmode2.test            quick.test
  autovacuum_crash.test     jrnlmode3.test            shared_err.test
  autovacuum_ioerr.test     jrnlmode4.test            soak.test
................................................................................
  set options(-shutdown) ""
  set options(-initialize) ""
  set options(-exclude) ""
  set options(-include) $::ALLTESTS
  set options(-presql) ""
  set options(-description) "no description supplied (fixme)"
  array set options $args
  #puts "PERM-DEBUG: name=$name testfile=$::perm::testfile"
  #puts "PERM-DEBUG: [array get options]"

  if {$::perm::testmode eq "targets"} {
    puts [format "% -20s %s" $name [string trim $options(-description)]]
    return
  }
  if {$::perm::testmode ne "" && [lsearch $::perm::testmode $name]<0} {
    puts "skipping permutation test $name..."
    return
  }

  uplevel $options(-initialize)
  set ::permutations_presql $options(-presql)

  foreach file $options(-include) {
    if {[lsearch $options(-exclude) $file] < 0 &&
       ( $::perm::testfile eq "" ||
         $::perm::testfile eq $file ||
        "$::perm::testfile.test" eq $file )
    } {
      uplevel source $::testdir/$file
    } else {
      # puts "skipping file $file"
    }
  }

  uplevel $options(-shutdown)
}

#############################################################################
................................................................................
    sqlite3_initialize
  }
}

ifcapable threadsafe {
  run_tests "no_mutex_try" -description {
     The sqlite3_mutex_try() interface always fails
  } -exclude [concat $EXCLUDE mutex1.test mutex2.test] \
  -initialize {
    catch {db close}
    sqlite3_shutdown
    install_mutex_counters 1
    set ::disable_mutex_try 1
  } -shutdown {
    catch {db close}
    sqlite3_shutdown
................................................................................
#   rename sa_crashsql crashsql
# } -include crash.test


# End of tests
#############################################################################

if {$::perm::testmode eq "targets"} { puts "" ; exit }

# Restore the [sqlite3] command.
#
rename sqlite3 {}
rename really_sqlite3 sqlite3

# Restore the [finish_test] command.