| OLD | NEW |
| 1 /* | 1 /* |
| 2 ** 2007 September 9 | 2 ** 2007 September 9 |
| 3 ** | 3 ** |
| 4 ** The author disclaims copyright to this source code. In place of | 4 ** The author disclaims copyright to this source code. In place of |
| 5 ** a legal notice, here is a blessing: | 5 ** a legal notice, here is a blessing: |
| 6 ** | 6 ** |
| 7 ** May you do good and not evil. | 7 ** May you do good and not evil. |
| 8 ** May you find forgiveness for yourself and forgive others. | 8 ** May you find forgiveness for yourself and forgive others. |
| 9 ** May you share freely, never taking more than you give. | 9 ** May you share freely, never taking more than you give. |
| 10 ** | 10 ** |
| 11 ************************************************************************* | 11 ************************************************************************* |
| 12 ** | 12 ** |
| 13 ** This file contains the implementation of some Tcl commands used to | 13 ** This file contains the implementation of some Tcl commands used to |
| 14 ** test that sqlite3 database handles may be concurrently accessed by | 14 ** test that sqlite3 database handles may be concurrently accessed by |
| 15 ** multiple threads. Right now this only works on unix. | 15 ** multiple threads. Right now this only works on unix. |
| 16 */ | 16 */ |
| 17 | 17 |
| 18 #include "sqliteInt.h" | 18 #include "sqliteInt.h" |
| 19 #include <tcl.h> | 19 #if defined(INCLUDE_SQLITE_TCL_H) |
| 20 # include "sqlite_tcl.h" |
| 21 #else |
| 22 # include "tcl.h" |
| 23 #endif |
| 20 | 24 |
| 21 #if SQLITE_THREADSAFE | 25 #if SQLITE_THREADSAFE |
| 22 | 26 |
| 23 #include <errno.h> | 27 #include <errno.h> |
| 24 | 28 |
| 25 #if !defined(_MSC_VER) | 29 #if !defined(_MSC_VER) |
| 26 #include <unistd.h> | 30 #include <unistd.h> |
| 27 #endif | 31 #endif |
| 28 | 32 |
| 29 /* | 33 /* |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 65 | 69 |
| 66 /* Functions from test1.c */ | 70 /* Functions from test1.c */ |
| 67 extern void *sqlite3TestTextToPtr(const char *); | 71 extern void *sqlite3TestTextToPtr(const char *); |
| 68 extern int getDbPointer(Tcl_Interp *, const char *, sqlite3 **); | 72 extern int getDbPointer(Tcl_Interp *, const char *, sqlite3 **); |
| 69 extern int sqlite3TestMakePointerStr(Tcl_Interp *, char *, void *); | 73 extern int sqlite3TestMakePointerStr(Tcl_Interp *, char *, void *); |
| 70 extern int sqlite3TestErrCode(Tcl_Interp *, sqlite3 *, int); | 74 extern int sqlite3TestErrCode(Tcl_Interp *, sqlite3 *, int); |
| 71 | 75 |
| 72 /* | 76 /* |
| 73 ** Handler for events of type EvalEvent. | 77 ** Handler for events of type EvalEvent. |
| 74 */ | 78 */ |
| 75 static int tclScriptEvent(Tcl_Event *evPtr, int flags){ | 79 static int SQLITE_TCLAPI tclScriptEvent(Tcl_Event *evPtr, int flags){ |
| 76 int rc; | 80 int rc; |
| 77 EvalEvent *p = (EvalEvent *)evPtr; | 81 EvalEvent *p = (EvalEvent *)evPtr; |
| 78 rc = Tcl_Eval(p->interp, p->zScript); | 82 rc = Tcl_Eval(p->interp, p->zScript); |
| 79 if( rc!=TCL_OK ){ | 83 if( rc!=TCL_OK ){ |
| 80 Tcl_BackgroundError(p->interp); | 84 Tcl_BackgroundError(p->interp); |
| 81 } | 85 } |
| 82 UNUSED_PARAMETER(flags); | 86 UNUSED_PARAMETER(flags); |
| 83 return 1; | 87 return 1; |
| 84 } | 88 } |
| 85 | 89 |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 160 /* | 164 /* |
| 161 ** sqlthread spawn VARNAME SCRIPT | 165 ** sqlthread spawn VARNAME SCRIPT |
| 162 ** | 166 ** |
| 163 ** Spawn a new thread with its own Tcl interpreter and run the | 167 ** Spawn a new thread with its own Tcl interpreter and run the |
| 164 ** specified SCRIPT(s) in it. The thread terminates after running | 168 ** specified SCRIPT(s) in it. The thread terminates after running |
| 165 ** the script. The result of the script is stored in the variable | 169 ** the script. The result of the script is stored in the variable |
| 166 ** VARNAME. | 170 ** VARNAME. |
| 167 ** | 171 ** |
| 168 ** The caller can wait for the script to terminate using [vwait VARNAME]. | 172 ** The caller can wait for the script to terminate using [vwait VARNAME]. |
| 169 */ | 173 */ |
| 170 static int sqlthread_spawn( | 174 static int SQLITE_TCLAPI sqlthread_spawn( |
| 171 ClientData clientData, | 175 ClientData clientData, |
| 172 Tcl_Interp *interp, | 176 Tcl_Interp *interp, |
| 173 int objc, | 177 int objc, |
| 174 Tcl_Obj *CONST objv[] | 178 Tcl_Obj *CONST objv[] |
| 175 ){ | 179 ){ |
| 176 Tcl_ThreadId x; | 180 Tcl_ThreadId x; |
| 177 SqlThread *pNew; | 181 SqlThread *pNew; |
| 178 int rc; | 182 int rc; |
| 179 | 183 |
| 180 int nVarname; char *zVarname; | 184 int nVarname; char *zVarname; |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 213 ** sqlthread parent SCRIPT | 217 ** sqlthread parent SCRIPT |
| 214 ** | 218 ** |
| 215 ** This can be called by spawned threads only. It sends the specified | 219 ** This can be called by spawned threads only. It sends the specified |
| 216 ** script back to the parent thread for execution. The result of | 220 ** script back to the parent thread for execution. The result of |
| 217 ** evaluating the SCRIPT is returned. The parent thread must enter | 221 ** evaluating the SCRIPT is returned. The parent thread must enter |
| 218 ** the event loop for this to work - otherwise the caller will | 222 ** the event loop for this to work - otherwise the caller will |
| 219 ** block indefinitely. | 223 ** block indefinitely. |
| 220 ** | 224 ** |
| 221 ** NOTE: At the moment, this doesn't work. FIXME. | 225 ** NOTE: At the moment, this doesn't work. FIXME. |
| 222 */ | 226 */ |
| 223 static int sqlthread_parent( | 227 static int SQLITE_TCLAPI sqlthread_parent( |
| 224 ClientData clientData, | 228 ClientData clientData, |
| 225 Tcl_Interp *interp, | 229 Tcl_Interp *interp, |
| 226 int objc, | 230 int objc, |
| 227 Tcl_Obj *CONST objv[] | 231 Tcl_Obj *CONST objv[] |
| 228 ){ | 232 ){ |
| 229 EvalEvent *pEvent; | 233 EvalEvent *pEvent; |
| 230 char *zMsg; | 234 char *zMsg; |
| 231 int nMsg; | 235 int nMsg; |
| 232 SqlThread *p = (SqlThread *)clientData; | 236 SqlThread *p = (SqlThread *)clientData; |
| 233 | 237 |
| (...skipping 24 matching lines...) Expand all Loading... |
| 258 sqlite3_sleep(50); | 262 sqlite3_sleep(50); |
| 259 return 1; /* Try again... */ | 263 return 1; /* Try again... */ |
| 260 } | 264 } |
| 261 | 265 |
| 262 /* | 266 /* |
| 263 ** sqlthread open | 267 ** sqlthread open |
| 264 ** | 268 ** |
| 265 ** Open a database handle and return the string representation of | 269 ** Open a database handle and return the string representation of |
| 266 ** the pointer value. | 270 ** the pointer value. |
| 267 */ | 271 */ |
| 268 static int sqlthread_open( | 272 static int SQLITE_TCLAPI sqlthread_open( |
| 269 ClientData clientData, | 273 ClientData clientData, |
| 270 Tcl_Interp *interp, | 274 Tcl_Interp *interp, |
| 271 int objc, | 275 int objc, |
| 272 Tcl_Obj *CONST objv[] | 276 Tcl_Obj *CONST objv[] |
| 273 ){ | 277 ){ |
| 274 int sqlite3TestMakePointerStr(Tcl_Interp *interp, char *zPtr, void *p); | 278 int sqlite3TestMakePointerStr(Tcl_Interp *interp, char *zPtr, void *p); |
| 275 | 279 |
| 276 const char *zFilename; | 280 const char *zFilename; |
| 277 sqlite3 *db; | 281 sqlite3 *db; |
| 278 char zBuf[100]; | 282 char zBuf[100]; |
| 279 extern void Md5_Register(sqlite3*); | 283 extern int Md5_Register(sqlite3*,char**,const sqlite3_api_routines*); |
| 280 | 284 |
| 281 UNUSED_PARAMETER(clientData); | 285 UNUSED_PARAMETER(clientData); |
| 282 UNUSED_PARAMETER(objc); | 286 UNUSED_PARAMETER(objc); |
| 283 | 287 |
| 284 zFilename = Tcl_GetString(objv[2]); | 288 zFilename = Tcl_GetString(objv[2]); |
| 285 sqlite3_open(zFilename, &db); | 289 sqlite3_open(zFilename, &db); |
| 286 #ifdef SQLITE_HAS_CODEC | 290 #ifdef SQLITE_HAS_CODEC |
| 287 if( db && objc>=4 ){ | 291 if( db && objc>=4 ){ |
| 288 const char *zKey; | 292 const char *zKey; |
| 289 int nKey; | 293 int nKey; |
| 290 int rc; | 294 int rc; |
| 291 zKey = Tcl_GetStringFromObj(objv[3], &nKey); | 295 zKey = Tcl_GetStringFromObj(objv[3], &nKey); |
| 292 rc = sqlite3_key(db, zKey, nKey); | 296 rc = sqlite3_key(db, zKey, nKey); |
| 293 if( rc!=SQLITE_OK ){ | 297 if( rc!=SQLITE_OK ){ |
| 294 char *zErrMsg = sqlite3_mprintf("error %d: %s", rc, sqlite3_errmsg(db)); | 298 char *zErrMsg = sqlite3_mprintf("error %d: %s", rc, sqlite3_errmsg(db)); |
| 295 sqlite3_close(db); | 299 sqlite3_close(db); |
| 296 Tcl_AppendResult(interp, zErrMsg, (char*)0); | 300 Tcl_AppendResult(interp, zErrMsg, (char*)0); |
| 297 sqlite3_free(zErrMsg); | 301 sqlite3_free(zErrMsg); |
| 298 return TCL_ERROR; | 302 return TCL_ERROR; |
| 299 } | 303 } |
| 300 } | 304 } |
| 301 #endif | 305 #endif |
| 302 Md5_Register(db); | 306 Md5_Register(db, 0, 0); |
| 303 sqlite3_busy_handler(db, xBusy, 0); | 307 sqlite3_busy_handler(db, xBusy, 0); |
| 304 | 308 |
| 305 if( sqlite3TestMakePointerStr(interp, zBuf, db) ) return TCL_ERROR; | 309 if( sqlite3TestMakePointerStr(interp, zBuf, db) ) return TCL_ERROR; |
| 306 Tcl_AppendResult(interp, zBuf, 0); | 310 Tcl_AppendResult(interp, zBuf, 0); |
| 307 | 311 |
| 308 return TCL_OK; | 312 return TCL_OK; |
| 309 } | 313 } |
| 310 | 314 |
| 311 | 315 |
| 312 /* | 316 /* |
| 313 ** sqlthread open | 317 ** sqlthread open |
| 314 ** | 318 ** |
| 315 ** Return the current thread-id (Tcl_GetCurrentThread()) cast to | 319 ** Return the current thread-id (Tcl_GetCurrentThread()) cast to |
| 316 ** an integer. | 320 ** an integer. |
| 317 */ | 321 */ |
| 318 static int sqlthread_id( | 322 static int SQLITE_TCLAPI sqlthread_id( |
| 319 ClientData clientData, | 323 ClientData clientData, |
| 320 Tcl_Interp *interp, | 324 Tcl_Interp *interp, |
| 321 int objc, | 325 int objc, |
| 322 Tcl_Obj *CONST objv[] | 326 Tcl_Obj *CONST objv[] |
| 323 ){ | 327 ){ |
| 324 Tcl_ThreadId id = Tcl_GetCurrentThread(); | 328 Tcl_ThreadId id = Tcl_GetCurrentThread(); |
| 325 Tcl_SetObjResult(interp, Tcl_NewIntObj(SQLITE_PTR_TO_INT(id))); | 329 Tcl_SetObjResult(interp, Tcl_NewIntObj(SQLITE_PTR_TO_INT(id))); |
| 326 UNUSED_PARAMETER(clientData); | 330 UNUSED_PARAMETER(clientData); |
| 327 UNUSED_PARAMETER(objc); | 331 UNUSED_PARAMETER(objc); |
| 328 UNUSED_PARAMETER(objv); | 332 UNUSED_PARAMETER(objv); |
| 329 return TCL_OK; | 333 return TCL_OK; |
| 330 } | 334 } |
| 331 | 335 |
| 332 | 336 |
| 333 /* | 337 /* |
| 334 ** Dispatch routine for the sub-commands of [sqlthread]. | 338 ** Dispatch routine for the sub-commands of [sqlthread]. |
| 335 */ | 339 */ |
| 336 static int sqlthread_proc( | 340 static int SQLITE_TCLAPI sqlthread_proc( |
| 337 ClientData clientData, | 341 ClientData clientData, |
| 338 Tcl_Interp *interp, | 342 Tcl_Interp *interp, |
| 339 int objc, | 343 int objc, |
| 340 Tcl_Obj *CONST objv[] | 344 Tcl_Obj *CONST objv[] |
| 341 ){ | 345 ){ |
| 342 struct SubCommand { | 346 struct SubCommand { |
| 343 char *zName; | 347 char *zName; |
| 344 Tcl_ObjCmdProc *xProc; | 348 Tcl_ObjCmdProc *xProc; |
| 345 int nArg; | 349 int nArg; |
| 346 char *zUsage; | 350 char *zUsage; |
| (...skipping 27 matching lines...) Expand all Loading... |
| 374 return pSub->xProc(clientData, interp, objc, objv); | 378 return pSub->xProc(clientData, interp, objc, objv); |
| 375 } | 379 } |
| 376 | 380 |
| 377 /* | 381 /* |
| 378 ** The [clock_seconds] command. This is more or less the same as the | 382 ** The [clock_seconds] command. This is more or less the same as the |
| 379 ** regular tcl [clock seconds], except that it is available in testfixture | 383 ** regular tcl [clock seconds], except that it is available in testfixture |
| 380 ** when linked against both Tcl 8.4 and 8.5. Because [clock seconds] is | 384 ** when linked against both Tcl 8.4 and 8.5. Because [clock seconds] is |
| 381 ** implemented as a script in Tcl 8.5, it is not usually available to | 385 ** implemented as a script in Tcl 8.5, it is not usually available to |
| 382 ** testfixture. | 386 ** testfixture. |
| 383 */ | 387 */ |
| 384 static int clock_seconds_proc( | 388 static int SQLITE_TCLAPI clock_seconds_proc( |
| 385 ClientData clientData, | 389 ClientData clientData, |
| 386 Tcl_Interp *interp, | 390 Tcl_Interp *interp, |
| 387 int objc, | 391 int objc, |
| 388 Tcl_Obj *CONST objv[] | 392 Tcl_Obj *CONST objv[] |
| 389 ){ | 393 ){ |
| 390 Tcl_Time now; | 394 Tcl_Time now; |
| 391 Tcl_GetTime(&now); | 395 Tcl_GetTime(&now); |
| 392 Tcl_SetObjResult(interp, Tcl_NewIntObj(now.sec)); | 396 Tcl_SetObjResult(interp, Tcl_NewIntObj(now.sec)); |
| 393 UNUSED_PARAMETER(clientData); | 397 UNUSED_PARAMETER(clientData); |
| 394 UNUSED_PARAMETER(objc); | 398 UNUSED_PARAMETER(objc); |
| (...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 536 } | 540 } |
| 537 return rc; | 541 return rc; |
| 538 } | 542 } |
| 539 /* END_SQLITE_BLOCKING_STEP */ | 543 /* END_SQLITE_BLOCKING_STEP */ |
| 540 | 544 |
| 541 /* | 545 /* |
| 542 ** Usage: sqlite3_blocking_step STMT | 546 ** Usage: sqlite3_blocking_step STMT |
| 543 ** | 547 ** |
| 544 ** Advance the statement to the next row. | 548 ** Advance the statement to the next row. |
| 545 */ | 549 */ |
| 546 static int blocking_step_proc( | 550 static int SQLITE_TCLAPI blocking_step_proc( |
| 547 void * clientData, | 551 void * clientData, |
| 548 Tcl_Interp *interp, | 552 Tcl_Interp *interp, |
| 549 int objc, | 553 int objc, |
| 550 Tcl_Obj *CONST objv[] | 554 Tcl_Obj *CONST objv[] |
| 551 ){ | 555 ){ |
| 552 | 556 |
| 553 sqlite3_stmt *pStmt; | 557 sqlite3_stmt *pStmt; |
| 554 int rc; | 558 int rc; |
| 555 | 559 |
| 556 if( objc!=2 ){ | 560 if( objc!=2 ){ |
| 557 Tcl_WrongNumArgs(interp, 1, objv, "STMT"); | 561 Tcl_WrongNumArgs(interp, 1, objv, "STMT"); |
| 558 return TCL_ERROR; | 562 return TCL_ERROR; |
| 559 } | 563 } |
| 560 | 564 |
| 561 pStmt = (sqlite3_stmt*)sqlite3TestTextToPtr(Tcl_GetString(objv[1])); | 565 pStmt = (sqlite3_stmt*)sqlite3TestTextToPtr(Tcl_GetString(objv[1])); |
| 562 rc = sqlite3_blocking_step(pStmt); | 566 rc = sqlite3_blocking_step(pStmt); |
| 563 | 567 |
| 564 Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), 0); | 568 Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), 0); |
| 565 return TCL_OK; | 569 return TCL_OK; |
| 566 } | 570 } |
| 567 | 571 |
| 568 /* | 572 /* |
| 569 ** Usage: sqlite3_blocking_prepare_v2 DB sql bytes ?tailvar? | 573 ** Usage: sqlite3_blocking_prepare_v2 DB sql bytes ?tailvar? |
| 570 ** Usage: sqlite3_nonblocking_prepare_v2 DB sql bytes ?tailvar? | 574 ** Usage: sqlite3_nonblocking_prepare_v2 DB sql bytes ?tailvar? |
| 571 */ | 575 */ |
| 572 static int blocking_prepare_v2_proc( | 576 static int SQLITE_TCLAPI blocking_prepare_v2_proc( |
| 573 void * clientData, | 577 void * clientData, |
| 574 Tcl_Interp *interp, | 578 Tcl_Interp *interp, |
| 575 int objc, | 579 int objc, |
| 576 Tcl_Obj *CONST objv[] | 580 Tcl_Obj *CONST objv[] |
| 577 ){ | 581 ){ |
| 578 sqlite3 *db; | 582 sqlite3 *db; |
| 579 const char *zSql; | 583 const char *zSql; |
| 580 int bytes; | 584 int bytes; |
| 581 const char *zTail = 0; | 585 const char *zTail = 0; |
| 582 sqlite3_stmt *pStmt = 0; | 586 sqlite3_stmt *pStmt = 0; |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 638 Tcl_CreateObjCommand(interp, | 642 Tcl_CreateObjCommand(interp, |
| 639 "sqlite3_nonblocking_prepare_v2", blocking_prepare_v2_proc, 0, 0); | 643 "sqlite3_nonblocking_prepare_v2", blocking_prepare_v2_proc, 0, 0); |
| 640 #endif | 644 #endif |
| 641 return TCL_OK; | 645 return TCL_OK; |
| 642 } | 646 } |
| 643 #else | 647 #else |
| 644 int SqlitetestThread_Init(Tcl_Interp *interp){ | 648 int SqlitetestThread_Init(Tcl_Interp *interp){ |
| 645 return TCL_OK; | 649 return TCL_OK; |
| 646 } | 650 } |
| 647 #endif | 651 #endif |
| OLD | NEW |