SQLite

Check-in [4f1cfca5ca]
Login

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

Overview
Comment:Change prototype for busy callbacks to "int xBusy(void *, int);" (CVS 1573)
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 4f1cfca5ca703d0068cf8d6222dc8e0cfb7e24b6
User & Date: danielk1977 2004-06-12 01:43:26.000
Context
2004-06-12
02:17
Bug fix in the unix locking code. (CVS 1574) (check-in: dcad244f58 user: drh tags: trunk)
01:43
Change prototype for busy callbacks to "int xBusy(void *, int);" (CVS 1573) (check-in: 4f1cfca5ca user: danielk1977 tags: trunk)
00:42
Use the SQLITE_UTF* symbols instead of the old internal TEXT_Utf* symbols. (CVS 1572) (check-in: 9b84f2f488 user: danielk1977 tags: trunk)
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/main.c.
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
**
*************************************************************************
** 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.216 2004/06/12 00:42:35 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include "os.h"
#include <ctype.h>

/*
** A pointer to this structure is used to communicate information







|







10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
**
*************************************************************************
** 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.217 2004/06/12 01:43:26 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include "os.h"
#include <ctype.h>

/*
** A pointer to this structure is used to communicate information
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618

/*
** This routine sets the busy callback for an Sqlite database to the
** given callback function with the given argument.
*/
void sqlite3_busy_handler(
  sqlite *db,
  int (*xBusy)(void*,const char*,int),
  void *pArg
){
  db->busyHandler.xFunc = xBusy;
  db->busyHandler.pArg = pArg;
}

#ifndef SQLITE_OMIT_PROGRESS_CALLBACK







|







604
605
606
607
608
609
610
611
612
613
614
615
616
617
618

/*
** This routine sets the busy callback for an Sqlite database to the
** given callback function with the given argument.
*/
void sqlite3_busy_handler(
  sqlite *db,
  int (*xBusy)(void*,int),
  void *pArg
){
  db->busyHandler.xFunc = xBusy;
  db->busyHandler.pArg = pArg;
}

#ifndef SQLITE_OMIT_PROGRESS_CALLBACK
Changes to src/pager.c.
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
** 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.123 2004/06/10 23:35:50 drh Exp $
*/
#include "os.h"         /* Must be first to enable large file support */
#include "sqliteInt.h"
#include "pager.h"
#include <assert.h>
#include <string.h>








|







14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
** 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.124 2004/06/12 01:43:26 danielk1977 Exp $
*/
#include "os.h"         /* Must be first to enable large file support */
#include "sqliteInt.h"
#include "pager.h"
#include <assert.h>
#include <string.h>

1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
  ** will require a journal playback.
  */
  do {
    rc = sqlite3OsLock(&pPager->fd, EXCLUSIVE_LOCK);
  }while( rc==SQLITE_BUSY && 
      pPager->pBusyHandler && 
      pPager->pBusyHandler->xFunc && 
      pPager->pBusyHandler->xFunc(pPager->pBusyHandler->pArg, "", busy++)
  );
  if( rc!=SQLITE_OK ){
    return rc;
  }
  pPager->state = PAGER_EXCLUSIVE;

  while( pList ){







|







1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
  ** will require a journal playback.
  */
  do {
    rc = sqlite3OsLock(&pPager->fd, EXCLUSIVE_LOCK);
  }while( rc==SQLITE_BUSY && 
      pPager->pBusyHandler && 
      pPager->pBusyHandler->xFunc && 
      pPager->pBusyHandler->xFunc(pPager->pBusyHandler->pArg, busy++)
  );
  if( rc!=SQLITE_OK ){
    return rc;
  }
  pPager->state = PAGER_EXCLUSIVE;

  while( pList ){
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
  if( pPager->nRef==0 && !pPager->memDb ){
    int busy = 1;
    do {
      rc = sqlite3OsLock(&pPager->fd, SHARED_LOCK);
    }while( rc==SQLITE_BUSY && 
        pPager->pBusyHandler && 
        pPager->pBusyHandler->xFunc && 
        pPager->pBusyHandler->xFunc(pPager->pBusyHandler->pArg, "", busy++)
    );
    if( rc!=SQLITE_OK ){
      return rc;
    }
    pPager->state = PAGER_SHARED;

    /* If a journal file exists, and there is no RESERVED lock on the







|







1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
  if( pPager->nRef==0 && !pPager->memDb ){
    int busy = 1;
    do {
      rc = sqlite3OsLock(&pPager->fd, SHARED_LOCK);
    }while( rc==SQLITE_BUSY && 
        pPager->pBusyHandler && 
        pPager->pBusyHandler->xFunc && 
        pPager->pBusyHandler->xFunc(pPager->pBusyHandler->pArg, busy++)
    );
    if( rc!=SQLITE_OK ){
      return rc;
    }
    pPager->state = PAGER_SHARED;

    /* If a journal file exists, and there is no RESERVED lock on the
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
    }else{
      int busy = 1;
      do {
        rc = sqlite3OsLock(&pPager->fd, RESERVED_LOCK);
      }while( rc==SQLITE_BUSY && 
          pPager->pBusyHandler && 
          pPager->pBusyHandler->xFunc && 
          pPager->pBusyHandler->xFunc(pPager->pBusyHandler->pArg, "", busy++)
      );
      if( rc!=SQLITE_OK ){
        return rc;
      }
      pPager->nMaster = nMaster;
      pPager->state = PAGER_RESERVED;
      pPager->dirtyCache = 0;







|







2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
    }else{
      int busy = 1;
      do {
        rc = sqlite3OsLock(&pPager->fd, RESERVED_LOCK);
      }while( rc==SQLITE_BUSY && 
          pPager->pBusyHandler && 
          pPager->pBusyHandler->xFunc && 
          pPager->pBusyHandler->xFunc(pPager->pBusyHandler->pArg, busy++)
      );
      if( rc!=SQLITE_OK ){
        return rc;
      }
      pPager->nMaster = nMaster;
      pPager->state = PAGER_RESERVED;
      pPager->dirtyCache = 0;
Changes to src/sqlite.h.in.
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** This header file defines the interface that the SQLite library
** presents to client programs.
**
** @(#) $Id: sqlite.h.in,v 1.99 2004/06/12 00:42:35 danielk1977 Exp $
*/
#ifndef _SQLITE_H_
#define _SQLITE_H_
#include <stdarg.h>     /* Needed for the definition of va_list */

/*
** Make sure we can call this stuff from C++.







|







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** This header file defines the interface that the SQLite library
** presents to client programs.
**
** @(#) $Id: sqlite.h.in,v 1.100 2004/06/12 01:43:27 danielk1977 Exp $
*/
#ifndef _SQLITE_H_
#define _SQLITE_H_
#include <stdarg.h>     /* Needed for the definition of va_list */

/*
** Make sure we can call this stuff from C++.
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
** Sqlite is re-entrant, so the busy handler may start a new query. 
** (It is not clear why anyone would every want to do this, but it
** is allowed, in theory.)  But the busy handler may not close the
** database.  Closing the database from a busy handler will delete 
** data structures out from under the executing query and will 
** probably result in a coredump.
*/
void sqlite3_busy_handler(sqlite*, int(*)(void*,const char*,int), void*);

/*
** This routine sets a busy handler that sleeps for a while when a
** table is locked.  The handler will sleep multiple times until 
** at least "ms" milleseconds of sleeping have been done.  After
** "ms" milleseconds of sleeping, the handler returns 0 which
** causes sqlite3_exec() to return SQLITE_BUSY.







|







238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
** Sqlite is re-entrant, so the busy handler may start a new query. 
** (It is not clear why anyone would every want to do this, but it
** is allowed, in theory.)  But the busy handler may not close the
** database.  Closing the database from a busy handler will delete 
** data structures out from under the executing query and will 
** probably result in a coredump.
*/
void sqlite3_busy_handler(sqlite*, int(*)(void*,int), void*);

/*
** This routine sets a busy handler that sleeps for a while when a
** table is locked.  The handler will sleep multiple times until 
** at least "ms" milleseconds of sleeping have been done.  After
** "ms" milleseconds of sleeping, the handler returns 0 which
** causes sqlite3_exec() to return SQLITE_BUSY.
Changes to src/sqliteInt.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.
**
*************************************************************************
** Internal interface definitions for SQLite.
**
** @(#) $Id: sqliteInt.h,v 1.283 2004/06/12 00:42:35 danielk1977 Exp $
*/
#include "config.h"
#include "sqlite3.h"
#include "hash.h"
#include "parse.h"
#include <stdio.h>
#include <stdlib.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.
**
*************************************************************************
** Internal interface definitions for SQLite.
**
** @(#) $Id: sqliteInt.h,v 1.284 2004/06/12 01:43:27 danielk1977 Exp $
*/
#include "config.h"
#include "sqlite3.h"
#include "hash.h"
#include "parse.h"
#include <stdio.h>
#include <stdlib.h>
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
**
** The sqlite.busyHandler member of the sqlite struct contains the busy
** callback for the database handle. Each pager opened via the sqlite
** handle is passed a pointer to sqlite.busyHandler. The busy-handler
** callback is currently invoked only from within pager.c.
*/
struct BusyHandler {
  int (*xFunc)(void *,const char*,int);  /* The busy callback */
  void *pArg;                            /* First arg to busy callback */
};

/*
** Each database is an instance of the following structure.
**
** The sqlite.temp_store determines where temporary database files
** are stored.  If 1, then a file is created to hold those tables.  If







|
|







338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
**
** The sqlite.busyHandler member of the sqlite struct contains the busy
** callback for the database handle. Each pager opened via the sqlite
** handle is passed a pointer to sqlite.busyHandler. The busy-handler
** callback is currently invoked only from within pager.c.
*/
struct BusyHandler {
  int (*xFunc)(void *,int);  /* The busy callback */
  void *pArg;                /* First arg to busy callback */
};

/*
** Each database is an instance of the following structure.
**
** The sqlite.temp_store determines where temporary database files
** are stored.  If 1, then a file is created to hold those tables.  If
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.83 2004/06/10 10:50:38 danielk1977 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.84 2004/06/12 01:43:27 danielk1977 Exp $
*/
#ifndef NO_TCL     /* Omit this whole file if TCL is unavailable */

#include "sqliteInt.h"
#include "tcl.h"
#include <stdlib.h>
#include <string.h>
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
  Tcl_Free((char*)pDb);
}

/*
** This routine is called when a database file is locked while trying
** to execute SQL.
*/
static int DbBusyHandler(void *cd, const char *zTable, int nTries){
  SqliteDb *pDb = (SqliteDb*)cd;
  int rc;
  char zVal[30];
  char *zCmd;
  Tcl_DString cmd;

  Tcl_DStringInit(&cmd);
  Tcl_DStringAppend(&cmd, pDb->zBusy, -1);
  Tcl_DStringAppendElement(&cmd, zTable);
  sprintf(zVal, " %d", nTries);
  Tcl_DStringAppend(&cmd, zVal, -1);
  zCmd = Tcl_DStringValue(&cmd);
  rc = Tcl_Eval(pDb->interp, zCmd);
  Tcl_DStringFree(&cmd);
  if( rc!=TCL_OK || atoi(Tcl_GetStringResult(pDb->interp)) ){
    return 0;
  }
  return 1;







|








<
|
|







145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160

161
162
163
164
165
166
167
168
169
  Tcl_Free((char*)pDb);
}

/*
** This routine is called when a database file is locked while trying
** to execute SQL.
*/
static int DbBusyHandler(void *cd, int nTries){
  SqliteDb *pDb = (SqliteDb*)cd;
  int rc;
  char zVal[30];
  char *zCmd;
  Tcl_DString cmd;

  Tcl_DStringInit(&cmd);
  Tcl_DStringAppend(&cmd, pDb->zBusy, -1);

  sprintf(zVal, "%d", nTries);
  Tcl_DStringAppendElement(&cmd, zVal);
  zCmd = Tcl_DStringValue(&cmd);
  rc = Tcl_Eval(pDb->interp, zCmd);
  Tcl_DStringFree(&cmd);
  if( rc!=TCL_OK || atoi(Tcl_GetStringResult(pDb->interp)) ){
    return 0;
  }
  return 1;
Changes to src/vdbe.c.
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
**
** Various scripts scan this source file in order to generate HTML
** documentation, headers files, or other derived files.  The formatting
** of the code in this file is, therefore, important.  See other comments
** in this file for details.  If in doubt, do not deviate from existing
** commenting and indentation practices when changing or adding code.
**
** $Id: vdbe.c,v 1.366 2004/06/12 00:42:35 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include "os.h"
#include <ctype.h>
#include "vdbeInt.h"

/*







|







39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
**
** Various scripts scan this source file in order to generate HTML
** documentation, headers files, or other derived files.  The formatting
** of the code in this file is, therefore, important.  See other comments
** in this file for details.  If in doubt, do not deviate from existing
** commenting and indentation practices when changing or adding code.
**
** $Id: vdbe.c,v 1.367 2004/06/12 01:43:27 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include "os.h"
#include <ctype.h>
#include "vdbeInt.h"

/*
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396
2397

  if( pBt ){
    if( db->nMaster<0 ){
      db->nMaster = strlen(sqlite3BtreeGetFilename(db->aDb[0].pBt))+20;
    }
    rc = sqlite3BtreeBeginTrans(pBt, pOp->p2, db->nMaster);
    if( rc==SQLITE_BUSY ){
        if( db->busyHandler.xFunc==0 ){
          p->pc = pc;
          p->rc = SQLITE_BUSY;
          p->pTos = pTos;
          return SQLITE_BUSY;
        }else{
          sqlite3SetString(&p->zErrMsg, sqlite3ErrStr(rc), (char*)0);
        }
    }
    if( rc!=SQLITE_OK && rc!=SQLITE_READONLY && rc!=SQLITE_BUSY ){
      goto abort_due_to_error;
    }
  }
  break;
}

/* Opcode: ReadCookie P1 P2 *







<
|
|
|
|
<
<
|
<
|







2374
2375
2376
2377
2378
2379
2380

2381
2382
2383
2384


2385

2386
2387
2388
2389
2390
2391
2392
2393

  if( pBt ){
    if( db->nMaster<0 ){
      db->nMaster = strlen(sqlite3BtreeGetFilename(db->aDb[0].pBt))+20;
    }
    rc = sqlite3BtreeBeginTrans(pBt, pOp->p2, db->nMaster);
    if( rc==SQLITE_BUSY ){

      p->pc = pc;
      p->rc = SQLITE_BUSY;
      p->pTos = pTos;
      return SQLITE_BUSY;


    }

    if( rc!=SQLITE_OK && rc!=SQLITE_READONLY /* && rc!=SQLITE_BUSY */ ){
      goto abort_due_to_error;
    }
  }
  break;
}

/* Opcode: ReadCookie P1 P2 *
2561
2562
2563
2564
2565
2566
2567
2568
2569
2570
2571
2572
2573
2574
2575
2576
2577
2578
2579
2580
2581
2582
2583
    pCur->pIncrKey = &pCur->pKeyInfo->incrKey;
    pCur->pKeyInfo->enc = p->db->enc;
  }else{
    pCur->pIncrKey = &pCur->bogusIncrKey;
  }
  switch( rc ){
    case SQLITE_BUSY: {
      if( db->busyHandler.xFunc ){
        p->pc = pc;
        p->rc = SQLITE_BUSY;
        p->pTos = &pTos[1 + (pOp->p2<=0)]; /* Operands must remain on stack */
        return SQLITE_BUSY;
      }else{
        sqlite3SetString(&p->zErrMsg, sqlite3ErrStr(rc), (char*)0);
      }
      break;
    }
    case SQLITE_OK: {
      int flags = sqlite3BtreeFlags(pCur->pCursor);
      pCur->intKey = (flags & BTREE_INTKEY)!=0;
      pCur->zeroData = (flags & BTREE_ZERODATA)!=0;
      break;
    }







<
|
|
|
|
<
<
<
<







2557
2558
2559
2560
2561
2562
2563

2564
2565
2566
2567




2568
2569
2570
2571
2572
2573
2574
    pCur->pIncrKey = &pCur->pKeyInfo->incrKey;
    pCur->pKeyInfo->enc = p->db->enc;
  }else{
    pCur->pIncrKey = &pCur->bogusIncrKey;
  }
  switch( rc ){
    case SQLITE_BUSY: {

      p->pc = pc;
      p->rc = SQLITE_BUSY;
      p->pTos = &pTos[1 + (pOp->p2<=0)]; /* Operands must remain on stack */
      return SQLITE_BUSY;




    }
    case SQLITE_OK: {
      int flags = sqlite3BtreeFlags(pCur->pCursor);
      pCur->intKey = (flags & BTREE_INTKEY)!=0;
      pCur->zeroData = (flags & BTREE_ZERODATA)!=0;
      break;
    }
Changes to test/lock.test.
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.
#
#***********************************************************************
# This file implements regression tests for SQLite library.  The
# focus of this script is database locks.
#
# $Id: lock.test,v 1.23 2004/06/10 00:29:12 drh Exp $


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

# Create an alternative connection to the database
#













|







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.
#
#***********************************************************************
# This file implements regression tests for SQLite library.  The
# focus of this script is database locks.
#
# $Id: lock.test,v 1.24 2004/06/12 01:43:27 danielk1977 Exp $


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

# Create an alternative connection to the database
#
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
  catchsql {SELECT * FROM t2} db2
} {0 {9 8}}

# If the other thread (the one that does not hold the transaction with
# a RESERVED lock) tries to get a RESERVED lock, we get a busy callback.
#
do_test lock-2.3 {
  proc callback {args} {
    set ::callback_value $args
    break
  }
  set ::callback_value {}
  db2 busy callback
  set r [catch {execsql {UPDATE t1 SET a=b, b=a} db2} msg]
  lappend r $msg
  lappend r $::callback_value
} {1 {database is locked} {{} 1}}
do_test lock-2.4 {
  proc callback {file count} {
    lappend ::callback_value $count
    if {$count>4} break
  }
  set ::callback_value {}
  db2 busy callback
  set r [catch {execsql {UPDATE t1 SET a=b, b=a} db2} msg]
  lappend r $msg
  lappend r $::callback_value
} {1 {database is locked} {1 2 3 4 5}}
do_test lock-2.5 {
  proc callback {file count} {
    lappend ::callback_value $count
    if {$count>4} break
  }
  set ::callback_value {}
  db2 busy callback
  set r [catch {execsql {SELECT * FROM t1} db2} msg]
  lappend r $msg
  lappend r $::callback_value
} {0 {2 1} {}}

# In this test, the 3rd invocation of the busy callback causes
# the first thread to release its transaction.  That allows the
# second thread to continue.
#
do_test lock-2.6 {
  proc callback {file count} {
    lappend ::callback_value $count
    if {$count>2} {
      execsql {ROLLBACK}
    }
  }
  set ::callback_value {}
  db2 busy callback
  set r [catch {execsql {SELECT * FROM t2} db2} msg]
  lappend r $msg
  lappend r $::callback_value
} {0 {9 8} {}}
do_test lock-2.7 {
  proc callback {file count} {
    lappend ::callback_value $count
    if {$count>2} {
      execsql {ROLLBACK}
    }
  }
  set ::callback_value {}
  db2 busy callback







|
|







|

|










|















|












|







168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
  catchsql {SELECT * FROM t2} db2
} {0 {9 8}}

# If the other thread (the one that does not hold the transaction with
# a RESERVED lock) tries to get a RESERVED lock, we get a busy callback.
#
do_test lock-2.3 {
  proc callback {count} {
    set ::callback_value $count
    break
  }
  set ::callback_value {}
  db2 busy callback
  set r [catch {execsql {UPDATE t1 SET a=b, b=a} db2} msg]
  lappend r $msg
  lappend r $::callback_value
} {1 {database is locked} 1}
do_test lock-2.4 {
  proc callback {count} {
    lappend ::callback_value $count
    if {$count>4} break
  }
  set ::callback_value {}
  db2 busy callback
  set r [catch {execsql {UPDATE t1 SET a=b, b=a} db2} msg]
  lappend r $msg
  lappend r $::callback_value
} {1 {database is locked} {1 2 3 4 5}}
do_test lock-2.5 {
  proc callback {count} {
    lappend ::callback_value $count
    if {$count>4} break
  }
  set ::callback_value {}
  db2 busy callback
  set r [catch {execsql {SELECT * FROM t1} db2} msg]
  lappend r $msg
  lappend r $::callback_value
} {0 {2 1} {}}

# In this test, the 3rd invocation of the busy callback causes
# the first thread to release its transaction.  That allows the
# second thread to continue.
#
do_test lock-2.6 {
  proc callback {count} {
    lappend ::callback_value $count
    if {$count>2} {
      execsql {ROLLBACK}
    }
  }
  set ::callback_value {}
  db2 busy callback
  set r [catch {execsql {SELECT * FROM t2} db2} msg]
  lappend r $msg
  lappend r $::callback_value
} {0 {9 8} {}}
do_test lock-2.7 {
  proc callback {count} {
    lappend ::callback_value $count
    if {$count>2} {
      execsql {ROLLBACK}
    }
  }
  set ::callback_value {}
  db2 busy callback
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
} {1 {database is locked}}
do_test lock-4.2 {
  set ::callback_value {}
  set rc [catch {db2 eval {UPDATE t1 SET a=0}} msg]
  lappend rc $msg $::callback_value
} {1 {database is locked} {}}
do_test lock-4.3 {
  proc callback {file count} {
    lappend ::callback_value $count
    if {$count>4} break
  }
  db2 busy callback
  set rc [catch {db2 eval {UPDATE t1 SET a=0}} msg]
  lappend rc $msg $::callback_value
} {1 {database is locked} {1 2 3 4 5}}







|







277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
} {1 {database is locked}}
do_test lock-4.2 {
  set ::callback_value {}
  set rc [catch {db2 eval {UPDATE t1 SET a=0}} msg]
  lappend rc $msg $::callback_value
} {1 {database is locked} {}}
do_test lock-4.3 {
  proc callback {count} {
    lappend ::callback_value $count
    if {$count>4} break
  }
  db2 busy callback
  set rc [catch {db2 eval {UPDATE t1 SET a=0}} msg]
  lappend rc $msg $::callback_value
} {1 {database is locked} {1 2 3 4 5}}
Changes to test/threadtest1.c.
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57

extern char *sqlite_mprintf(const char *zFormat, ...);
extern char *sqlite_vmprintf(const char *zFormat, va_list);

/*
** When a lock occurs, yield.
*/
static int db_is_locked(void *NotUsed, const char *zNotUsed, int iNotUsed){
  /* sched_yield(); */
  if( verbose ) printf("BUSY %s\n", (char*)NotUsed);
  usleep(100);
  return 1;
}

/*







|







43
44
45
46
47
48
49
50
51
52
53
54
55
56
57

extern char *sqlite_mprintf(const char *zFormat, ...);
extern char *sqlite_vmprintf(const char *zFormat, va_list);

/*
** When a lock occurs, yield.
*/
static int db_is_locked(void *NotUsed, int iNotUsed){
  /* sched_yield(); */
  if( verbose ) printf("BUSY %s\n", (char*)NotUsed);
  usleep(100);
  return 1;
}

/*