| OLD | NEW |
| 1 /* | 1 /* |
| 2 ** 2006 January 09 | 2 ** 2006 January 09 |
| 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 ** |
| (...skipping 22 matching lines...) Expand all Loading... |
| 33 */ | 33 */ |
| 34 int sqlite3_client_open(const char*, sqlite3**); | 34 int sqlite3_client_open(const char*, sqlite3**); |
| 35 int sqlite3_client_prepare(sqlite3*,const char*,int, | 35 int sqlite3_client_prepare(sqlite3*,const char*,int, |
| 36 sqlite3_stmt**,const char**); | 36 sqlite3_stmt**,const char**); |
| 37 int sqlite3_client_step(sqlite3_stmt*); | 37 int sqlite3_client_step(sqlite3_stmt*); |
| 38 int sqlite3_client_reset(sqlite3_stmt*); | 38 int sqlite3_client_reset(sqlite3_stmt*); |
| 39 int sqlite3_client_finalize(sqlite3_stmt*); | 39 int sqlite3_client_finalize(sqlite3_stmt*); |
| 40 int sqlite3_client_close(sqlite3*); | 40 int sqlite3_client_close(sqlite3*); |
| 41 int sqlite3_server_start(void); | 41 int sqlite3_server_start(void); |
| 42 int sqlite3_server_stop(void); | 42 int sqlite3_server_stop(void); |
| 43 void sqlite3_server_start2(int *pnDecr); |
| 43 | 44 |
| 44 /* | 45 /* |
| 45 ** Each thread is controlled by an instance of the following | 46 ** Each thread is controlled by an instance of the following |
| 46 ** structure. | 47 ** structure. |
| 47 */ | 48 */ |
| 48 typedef struct Thread Thread; | 49 typedef struct Thread Thread; |
| 49 struct Thread { | 50 struct Thread { |
| 50 /* The first group of fields are writable by the supervisor thread | 51 /* The first group of fields are writable by the supervisor thread |
| 51 ** and read-only to the client threads | 52 ** and read-only to the client threads |
| 52 */ | 53 */ |
| 53 char *zFilename; /* Name of database file */ | 54 char *zFilename; /* Name of database file */ |
| 54 void (*xOp)(Thread*); /* next operation to do */ | 55 void (*xOp)(Thread*); /* next operation to do */ |
| 55 char *zArg; /* argument usable by xOp */ | 56 char *zArg; /* argument usable by xOp */ |
| 56 volatile int opnum; /* Operation number */ | 57 volatile int opnum; /* Operation number */ |
| 57 volatile int busy; /* True if this thread is in use */ | 58 volatile int busy; /* True if this thread is in use */ |
| 58 | 59 |
| 59 /* The next group of fields are writable by the client threads | 60 /* The next group of fields are writable by the client threads |
| 60 ** but read-only to the superviser thread. | 61 ** but read-only to the superviser thread. |
| 61 */ | 62 */ |
| 62 volatile int completed; /* Number of operations completed */ | 63 volatile int completed; /* Number of operations completed */ |
| 63 sqlite3 *db; /* Open database */ | 64 sqlite3 *db; /* Open database */ |
| 64 sqlite3_stmt *pStmt; /* Pending operation */ | 65 sqlite3_stmt *pStmt; /* Pending operation */ |
| 65 char *zErr; /* operation error */ | 66 char *zErr; /* operation error */ |
| 66 char *zStaticErr; /* Static error message */ | 67 char *zStaticErr; /* Static error message */ |
| 67 int rc; /* operation return code */ | 68 int rc; /* operation return code */ |
| 68 int argc; /* number of columns in result */ | 69 int argc; /* number of columns in result */ |
| 69 const char *argv[100]; /* result columns */ | 70 const char *argv[100]; /* result columns */ |
| 70 const char *colv[100]; /* result column names */ | 71 const char *colv[100]; /* result column names */ |
| 72 |
| 73 /* Initialized to 1 by the supervisor thread when the client is |
| 74 ** created, and then deemed read-only to the supervisor thread. |
| 75 ** Is set to 0 by the server thread belonging to this client |
| 76 ** just before it exits. |
| 77 */ |
| 78 int nServer; /* Number of server threads running */ |
| 71 }; | 79 }; |
| 72 | 80 |
| 73 /* | 81 /* |
| 74 ** There can be as many as 26 threads running at once. Each is named | 82 ** There can be as many as 26 threads running at once. Each is named |
| 75 ** by a capital letter: A, B, C, ..., Y, Z. | 83 ** by a capital letter: A, B, C, ..., Y, Z. |
| 76 */ | 84 */ |
| 77 #define N_THREAD 26 | 85 #define N_THREAD 26 |
| 78 static Thread threadset[N_THREAD]; | 86 static Thread threadset[N_THREAD]; |
| 79 | 87 |
| 80 /* | 88 /* |
| (...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 168 threadset[i].opnum = 1; | 176 threadset[i].opnum = 1; |
| 169 threadset[i].completed = 0; | 177 threadset[i].completed = 0; |
| 170 rc = pthread_create(&x, 0, client_main, &threadset[i]); | 178 rc = pthread_create(&x, 0, client_main, &threadset[i]); |
| 171 if( rc ){ | 179 if( rc ){ |
| 172 Tcl_AppendResult(interp, "failed to create the thread", 0); | 180 Tcl_AppendResult(interp, "failed to create the thread", 0); |
| 173 sqlite3_free(threadset[i].zFilename); | 181 sqlite3_free(threadset[i].zFilename); |
| 174 threadset[i].busy = 0; | 182 threadset[i].busy = 0; |
| 175 return TCL_ERROR; | 183 return TCL_ERROR; |
| 176 } | 184 } |
| 177 pthread_detach(x); | 185 pthread_detach(x); |
| 178 sqlite3_server_start(); | 186 if( threadset[i].nServer==0 ){ |
| 187 threadset[i].nServer = 1; |
| 188 sqlite3_server_start2(&threadset[i].nServer); |
| 189 } |
| 179 return TCL_OK; | 190 return TCL_OK; |
| 180 } | 191 } |
| 181 | 192 |
| 182 /* | 193 /* |
| 183 ** Wait for a thread to reach its idle state. | 194 ** Wait for a thread to reach its idle state. |
| 184 */ | 195 */ |
| 185 static void client_wait(Thread *p){ | 196 static void client_wait(Thread *p){ |
| 186 while( p->opnum>p->completed ) sched_yield(); | 197 while( p->opnum>p->completed ) sched_yield(); |
| 187 } | 198 } |
| 188 | 199 |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 261 Tcl_AppendResult(interp, "no such thread", 0); | 272 Tcl_AppendResult(interp, "no such thread", 0); |
| 262 return TCL_ERROR; | 273 return TCL_ERROR; |
| 263 } | 274 } |
| 264 stop_thread(&threadset[i]); | 275 stop_thread(&threadset[i]); |
| 265 } | 276 } |
| 266 | 277 |
| 267 /* If no client threads are still running, also stop the server */ | 278 /* If no client threads are still running, also stop the server */ |
| 268 for(i=0; i<N_THREAD && threadset[i].busy==0; i++){} | 279 for(i=0; i<N_THREAD && threadset[i].busy==0; i++){} |
| 269 if( i>=N_THREAD ){ | 280 if( i>=N_THREAD ){ |
| 270 sqlite3_server_stop(); | 281 sqlite3_server_stop(); |
| 282 while( 1 ){ |
| 283 for(i=0; i<N_THREAD && threadset[i].nServer==0; i++); |
| 284 if( i==N_THREAD ) break; |
| 285 sched_yield(); |
| 286 } |
| 271 } | 287 } |
| 272 return TCL_OK; | 288 return TCL_OK; |
| 273 } | 289 } |
| 274 | 290 |
| 275 /* | 291 /* |
| 276 ** Usage: client_argc ID | 292 ** Usage: client_argc ID |
| 277 ** | 293 ** |
| 278 ** Wait on the most recent client_step to complete, then return the | 294 ** Wait on the most recent client_step to complete, then return the |
| 279 ** number of columns in the result set. | 295 ** number of columns in the result set. |
| 280 */ | 296 */ |
| (...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 369 if( Tcl_GetInt(interp, argv[2], &n) ) return TCL_ERROR; | 385 if( Tcl_GetInt(interp, argv[2], &n) ) return TCL_ERROR; |
| 370 client_wait(&threadset[i]); | 386 client_wait(&threadset[i]); |
| 371 if( n<0 || n>=threadset[i].argc ){ | 387 if( n<0 || n>=threadset[i].argc ){ |
| 372 Tcl_AppendResult(interp, "column number out of range", 0); | 388 Tcl_AppendResult(interp, "column number out of range", 0); |
| 373 return TCL_ERROR; | 389 return TCL_ERROR; |
| 374 } | 390 } |
| 375 Tcl_AppendResult(interp, threadset[i].colv[n], 0); | 391 Tcl_AppendResult(interp, threadset[i].colv[n], 0); |
| 376 return TCL_OK; | 392 return TCL_OK; |
| 377 } | 393 } |
| 378 | 394 |
| 395 extern const char *sqlite3ErrName(int); |
| 396 |
| 379 /* | 397 /* |
| 380 ** Usage: client_result ID | 398 ** Usage: client_result ID |
| 381 ** | 399 ** |
| 382 ** Wait on the most recent operation to complete, then return the | 400 ** Wait on the most recent operation to complete, then return the |
| 383 ** result code from that operation. | 401 ** result code from that operation. |
| 384 */ | 402 */ |
| 385 static int tcl_client_result( | 403 static int tcl_client_result( |
| 386 void *NotUsed, | 404 void *NotUsed, |
| 387 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | 405 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ |
| 388 int argc, /* Number of arguments */ | 406 int argc, /* Number of arguments */ |
| 389 const char **argv /* Text of each argument */ | 407 const char **argv /* Text of each argument */ |
| 390 ){ | 408 ){ |
| 391 int i; | 409 int i; |
| 392 const char *zName; | 410 const char *zName; |
| 393 | 411 |
| 394 if( argc!=2 ){ | 412 if( argc!=2 ){ |
| 395 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], | 413 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], |
| 396 " ID", 0); | 414 " ID", 0); |
| 397 return TCL_ERROR; | 415 return TCL_ERROR; |
| 398 } | 416 } |
| 399 i = parse_client_id(interp, argv[1]); | 417 i = parse_client_id(interp, argv[1]); |
| 400 if( i<0 ) return TCL_ERROR; | 418 if( i<0 ) return TCL_ERROR; |
| 401 if( !threadset[i].busy ){ | 419 if( !threadset[i].busy ){ |
| 402 Tcl_AppendResult(interp, "no such thread", 0); | 420 Tcl_AppendResult(interp, "no such thread", 0); |
| 403 return TCL_ERROR; | 421 return TCL_ERROR; |
| 404 } | 422 } |
| 405 client_wait(&threadset[i]); | 423 client_wait(&threadset[i]); |
| 406 switch( threadset[i].rc ){ | 424 zName = sqlite3ErrName(threadset[i].rc); |
| 407 case SQLITE_OK: zName = "SQLITE_OK"; break; | |
| 408 case SQLITE_ERROR: zName = "SQLITE_ERROR"; break; | |
| 409 case SQLITE_PERM: zName = "SQLITE_PERM"; break; | |
| 410 case SQLITE_ABORT: zName = "SQLITE_ABORT"; break; | |
| 411 case SQLITE_BUSY: zName = "SQLITE_BUSY"; break; | |
| 412 case SQLITE_LOCKED: zName = "SQLITE_LOCKED"; break; | |
| 413 case SQLITE_NOMEM: zName = "SQLITE_NOMEM"; break; | |
| 414 case SQLITE_READONLY: zName = "SQLITE_READONLY"; break; | |
| 415 case SQLITE_INTERRUPT: zName = "SQLITE_INTERRUPT"; break; | |
| 416 case SQLITE_IOERR: zName = "SQLITE_IOERR"; break; | |
| 417 case SQLITE_CORRUPT: zName = "SQLITE_CORRUPT"; break; | |
| 418 case SQLITE_FULL: zName = "SQLITE_FULL"; break; | |
| 419 case SQLITE_CANTOPEN: zName = "SQLITE_CANTOPEN"; break; | |
| 420 case SQLITE_PROTOCOL: zName = "SQLITE_PROTOCOL"; break; | |
| 421 case SQLITE_EMPTY: zName = "SQLITE_EMPTY"; break; | |
| 422 case SQLITE_SCHEMA: zName = "SQLITE_SCHEMA"; break; | |
| 423 case SQLITE_CONSTRAINT: zName = "SQLITE_CONSTRAINT"; break; | |
| 424 case SQLITE_MISMATCH: zName = "SQLITE_MISMATCH"; break; | |
| 425 case SQLITE_MISUSE: zName = "SQLITE_MISUSE"; break; | |
| 426 case SQLITE_NOLFS: zName = "SQLITE_NOLFS"; break; | |
| 427 case SQLITE_AUTH: zName = "SQLITE_AUTH"; break; | |
| 428 case SQLITE_FORMAT: zName = "SQLITE_FORMAT"; break; | |
| 429 case SQLITE_RANGE: zName = "SQLITE_RANGE"; break; | |
| 430 case SQLITE_ROW: zName = "SQLITE_ROW"; break; | |
| 431 case SQLITE_DONE: zName = "SQLITE_DONE"; break; | |
| 432 default: zName = "SQLITE_Unknown"; break; | |
| 433 } | |
| 434 Tcl_AppendResult(interp, zName, 0); | 425 Tcl_AppendResult(interp, zName, 0); |
| 435 return TCL_OK; | 426 return TCL_OK; |
| 436 } | 427 } |
| 437 | 428 |
| 438 /* | 429 /* |
| 439 ** Usage: client_error ID | 430 ** Usage: client_error ID |
| 440 ** | 431 ** |
| 441 ** Wait on the most recent operation to complete, then return the | 432 ** Wait on the most recent operation to complete, then return the |
| 442 ** error string. | 433 ** error string. |
| 443 */ | 434 */ |
| (...skipping 270 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 714 int i; | 705 int i; |
| 715 | 706 |
| 716 for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){ | 707 for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){ |
| 717 Tcl_CreateCommand(interp, aCmd[i].zName, aCmd[i].xProc, 0, 0); | 708 Tcl_CreateCommand(interp, aCmd[i].zName, aCmd[i].xProc, 0, 0); |
| 718 } | 709 } |
| 719 return TCL_OK; | 710 return TCL_OK; |
| 720 } | 711 } |
| 721 #else | 712 #else |
| 722 int Sqlitetest7_Init(Tcl_Interp *interp){ return TCL_OK; } | 713 int Sqlitetest7_Init(Tcl_Interp *interp){ return TCL_OK; } |
| 723 #endif /* SQLITE_OS_UNIX */ | 714 #endif /* SQLITE_OS_UNIX */ |
| OLD | NEW |