Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Modify the (transaction) method of the tcl interface to use savepoints. This makes nested calls to (transaction) work more intuitively. (CVS 6101) |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
f047758de9b499866aa4ddf16011498b |
User & Date: | danielk1977 2009-01-02 17:33:46.000 |
Context
2009-01-02
| ||
18:10 | Fix compiler warnings in pager.c (CVS 6102) (check-in: 78dd7909da user: drh tags: trunk) | |
17:33 | Modify the (transaction) method of the tcl interface to use savepoints. This makes nested calls to (transaction) work more intuitively. (CVS 6101) (check-in: f047758de9 user: danielk1977 tags: trunk) | |
15:47 | Add fts_expr.* files to Makefile.in. (CVS 6100) (check-in: 524c8634df user: shane tags: trunk) | |
Changes
Changes to src/sqliteInt.h.
1 2 3 4 5 6 7 8 9 10 11 12 13 | /* ** 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. ** | | | 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.817 2009/01/02 17:33:46 danielk1977 Exp $ */ #ifndef _SQLITEINT_H_ #define _SQLITEINT_H_ /* ** Include the configuration header output by 'configure' if we're using the ** autoconf-based build |
︙ | ︙ | |||
1499 1500 1501 1502 1503 1504 1505 | Select *pSelect; /* A SELECT statement used in place of a table name */ u8 isPopulated; /* Temporary table associated with SELECT is populated */ u8 jointype; /* Type of join between this able and the previous */ u8 notIndexed; /* True if there is a NOT INDEXED clause */ int iCursor; /* The VDBE cursor number used to access this table */ Expr *pOn; /* The ON clause of a join */ IdList *pUsing; /* The USING clause of a join */ | | | 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 | Select *pSelect; /* A SELECT statement used in place of a table name */ u8 isPopulated; /* Temporary table associated with SELECT is populated */ u8 jointype; /* Type of join between this able and the previous */ u8 notIndexed; /* True if there is a NOT INDEXED clause */ int iCursor; /* The VDBE cursor number used to access this table */ Expr *pOn; /* The ON clause of a join */ IdList *pUsing; /* The USING clause of a join */ Bitmask colUsed; /* Bit N (1<<N) set if column N of pTab is used */ char *zIndex; /* Identifier from "INDEXED BY <zIndex>" clause */ Index *pIndex; /* Index structure corresponding to zIndex, if any */ } a[1]; /* One entry for each identifier on the list */ }; /* ** Permitted values of the SrcList.a.jointype field |
︙ | ︙ |
Changes to src/tclsqlite.c.
︙ | ︙ | |||
8 9 10 11 12 13 14 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** A TCL Interface to SQLite. Append this file to sqlite3.c and ** compile the whole thing to build a TCL-enabled version of SQLite. ** | | | 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. ** ************************************************************************* ** A TCL Interface to SQLite. Append this file to sqlite3.c and ** compile the whole thing to build a TCL-enabled version of SQLite. ** ** $Id: tclsqlite.c,v 1.233 2009/01/02 17:33:46 danielk1977 Exp $ */ #include "tcl.h" #include <errno.h> /* ** Some additional include files are needed if this file is not ** appended to the amalgamation. |
︙ | ︙ | |||
114 115 116 117 118 119 120 121 122 123 124 125 126 127 | Tcl_Obj *pCollateNeeded; /* Collation needed script */ SqlPreparedStmt *stmtList; /* List of prepared statements*/ SqlPreparedStmt *stmtLast; /* Last statement in the list */ int maxStmt; /* The next maximum number of stmtList */ int nStmt; /* Number of statements in stmtList */ IncrblobChannel *pIncrblob;/* Linked list of open incrblob channels */ int nStep, nSort; /* Statistics for most recent operation */ }; struct IncrblobChannel { sqlite3_blob *pBlob; /* sqlite3 blob handle */ SqliteDb *pDb; /* Associated database connection */ int iSeek; /* Current seek offset */ Tcl_Channel channel; /* Channel identifier */ | > | 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 | Tcl_Obj *pCollateNeeded; /* Collation needed script */ SqlPreparedStmt *stmtList; /* List of prepared statements*/ SqlPreparedStmt *stmtLast; /* Last statement in the list */ int maxStmt; /* The next maximum number of stmtList */ int nStmt; /* Number of statements in stmtList */ IncrblobChannel *pIncrblob;/* Linked list of open incrblob channels */ int nStep, nSort; /* Statistics for most recent operation */ int nTransaction; /* Number of nested [transaction] methods */ }; struct IncrblobChannel { sqlite3_blob *pBlob; /* sqlite3 blob handle */ SqliteDb *pDb; /* Associated database connection */ int iSeek; /* Current seek offset */ Tcl_Channel channel; /* Channel identifier */ |
︙ | ︙ | |||
2257 2258 2259 2260 2261 2262 2263 | ** throws an exception. Or if no new transation was started, do nothing. ** pass the exception on up the stack. ** ** This command was inspired by Dave Thomas's talk on Ruby at the ** 2005 O'Reilly Open Source Convention (OSCON). */ case DB_TRANSACTION: { | < | > | > | | > | | < < | | | > > > > > | | | > | | > > > > > > > > | | > > > > > > > > > > > > > > | | | | | 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 | ** throws an exception. Or if no new transation was started, do nothing. ** pass the exception on up the stack. ** ** This command was inspired by Dave Thomas's talk on Ruby at the ** 2005 O'Reilly Open Source Convention (OSCON). */ case DB_TRANSACTION: { Tcl_Obj *pScript; const char *zBegin = "SAVEPOINT _tcl_transaction"; const char *zEnd; if( objc!=3 && objc!=4 ){ Tcl_WrongNumArgs(interp, 2, objv, "[TYPE] SCRIPT"); return TCL_ERROR; } if( pDb->nTransaction ){ zBegin = "SAVEPOINT _tcl_transaction"; }else if( pDb->nTransaction==0 && objc==4 ){ static const char *TTYPE_strs[] = { "deferred", "exclusive", "immediate", 0 }; enum TTYPE_enum { TTYPE_DEFERRED, TTYPE_EXCLUSIVE, TTYPE_IMMEDIATE }; int ttype; if( Tcl_GetIndexFromObj(interp, objv[2], TTYPE_strs, "transaction type", 0, &ttype) ){ return TCL_ERROR; } switch( (enum TTYPE_enum)ttype ){ case TTYPE_DEFERRED: /* no-op */; break; case TTYPE_EXCLUSIVE: zBegin = "BEGIN EXCLUSIVE"; break; case TTYPE_IMMEDIATE: zBegin = "BEGIN IMMEDIATE"; break; } } pScript = objv[objc-1]; pDb->disableAuth++; rc = sqlite3_exec(pDb->db, zBegin, 0, 0, 0); pDb->disableAuth--; if( rc!=SQLITE_OK ){ Tcl_AppendResult(interp, sqlite3_errmsg(pDb->db), 0); return TCL_ERROR; } pDb->nTransaction++; rc = Tcl_EvalObjEx(interp, pScript, 0); pDb->nTransaction--; if( rc!=TCL_ERROR ){ if( pDb->nTransaction ){ zEnd = "RELEASE _tcl_transaction"; }else{ zEnd = "COMMIT"; } }else{ if( pDb->nTransaction ){ zEnd = "ROLLBACK TO _tcl_transaction ; RELEASE _tcl_transaction"; }else{ zEnd = "ROLLBACK"; } } pDb->disableAuth++; if( sqlite3_exec(pDb->db, zEnd, 0, 0, 0) ){ /* This is a tricky scenario to handle. The most likely cause of an ** error is that the exec() above was an attempt to commit the ** top-level transaction that returned SQLITE_BUSY. Or, less likely, ** that an IO-error has occured. In either case, throw a Tcl exception ** and try to rollback the transaction. ** ** But it could also be that the user executed one or more BEGIN, ** COMMIT, SAVEPOINT, RELEASE or ROLLBACK commands that are confusing ** this method's logic. Not clear how this would be best handled. */ if( rc!=TCL_ERROR ){ Tcl_AppendResult(interp, sqlite3_errmsg(pDb->db), 0); rc = TCL_ERROR; } sqlite3_exec(pDb->db, "ROLLBACK", 0, 0, 0); } pDb->disableAuth--; break; } /* ** $db update_hook ?script? ** $db rollback_hook ?script? */ |
︙ | ︙ |
Changes to test/fts3near.test.
1 2 3 4 5 6 7 8 9 10 11 12 | # 2007 October 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. # #************************************************************************* # | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | # 2007 October 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. # #************************************************************************* # # $Id: fts3near.test,v 1.3 2009/01/02 17:33:46 danielk1977 Exp $ # set testdir [file dirname $argv0] source $testdir/tester.tcl # If SQLITE_ENABLE_FTS3 is defined, omit this file. ifcapable !fts3 { |
︙ | ︙ | |||
64 65 66 67 68 69 70 71 72 73 74 75 76 77 | } {1} do_test fts3near-1.12 { execsql {SELECT docid FROM t1 WHERE content MATCH 'five NEAR/1 "two three"'} } {2 3} do_test fts3near-1.13 { execsql {SELECT docid FROM t1 WHERE content MATCH 'one NEAR five'} } {1 3} # Output format of the offsets() function: # # <column number> <term number> <starting offset> <number of bytes> # db eval { | > > > > > > > | 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 | } {1} do_test fts3near-1.12 { execsql {SELECT docid FROM t1 WHERE content MATCH 'five NEAR/1 "two three"'} } {2 3} do_test fts3near-1.13 { execsql {SELECT docid FROM t1 WHERE content MATCH 'one NEAR five'} } {1 3} do_test fts3near-1.14 { execsql {SELECT docid FROM t1 WHERE content MATCH 'four NEAR four'} } {} do_test fts3near-1.15 { execsql {SELECT docid FROM t1 WHERE content MATCH 'one NEAR two NEAR one'} } {3} # Output format of the offsets() function: # # <column number> <term number> <starting offset> <number of bytes> # db eval { |
︙ | ︙ |
Changes to test/tclsqlite.test.
︙ | ︙ | |||
11 12 13 14 15 16 17 | # This file implements regression tests for TCL interface to the # SQLite library. # # Actually, all tests are based on the TCL interface, so the main # interface is pretty well tested. This file contains some addition # tests for fringe issues that the main test suite does not cover. # | | | 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | # This file implements regression tests for TCL interface to the # SQLite library. # # Actually, all tests are based on the TCL interface, so the main # interface is pretty well tested. This file contains some addition # tests for fringe issues that the main test suite does not cover. # # $Id: tclsqlite.test,v 1.71 2009/01/02 17:33:46 danielk1977 Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl # Check the error messages generated by tclsqlite # if {[sqlite3 -has-codec]} { |
︙ | ︙ | |||
410 411 412 413 414 415 416 | db eval {INSERT INTO t4 VALUES(3)} db eval {INSERT INTO t4 VALUES(4)} error test-error } } } db eval {SELECT * FROM t4} | | > | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 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 574 | db eval {INSERT INTO t4 VALUES(3)} db eval {INSERT INTO t4 VALUES(4)} error test-error } } } db eval {SELECT * FROM t4} } {1 2} do_test tcl-10.10 { for {set i 0} {$i<1} {incr i} { db transaction { db eval {INSERT INTO t4 VALUES(5)} continue } error "This line should not be run" } db eval {SELECT * FROM t4} } {1 2 5} do_test tcl-10.11 { for {set i 0} {$i<10} {incr i} { db transaction { db eval {INSERT INTO t4 VALUES(6)} break } } db eval {SELECT * FROM t4} } {1 2 5 6} do_test tcl-10.12 { set rc [catch { for {set i 0} {$i<10} {incr i} { db transaction { db eval {INSERT INTO t4 VALUES(7)} return } } }] } {2} do_test tcl-10.13 { db eval {SELECT * FROM t4} } {1 2 5 6 7} # Now test that [db transaction] commands may be nested with # the expected results. # do_test tcl-10.14 { db transaction { db eval { DELETE FROM t4; INSERT INTO t4 VALUES('one'); } catch { db transaction { db eval { INSERT INTO t4 VALUES('two') } db transaction { db eval { INSERT INTO t4 VALUES('three') } error "throw an error!" } } } } db eval {SELECT * FROM t4} } {one} do_test tcl-10.15 { # Make sure a transaction has not been left open. db eval {BEGIN ; COMMIT} } {} do_test tcl-10.16 { db transaction { db eval { INSERT INTO t4 VALUES('two'); } db transaction { db eval { INSERT INTO t4 VALUES('three') } db transaction { db eval { INSERT INTO t4 VALUES('four') } } } } db eval {SELECT * FROM t4} } {one two three four} do_test tcl-10.17 { catch { db transaction { db eval { INSERT INTO t4 VALUES('A'); } db transaction { db eval { INSERT INTO t4 VALUES('B') } db transaction { db eval { INSERT INTO t4 VALUES('C') } error "throw an error!" } } } } db eval {SELECT * FROM t4} } {one two three four} do_test tcl-10.18 { # Make sure a transaction has not been left open. db eval {BEGIN ; COMMIT} } {} # Mess up a [db transaction] command by locking the database using a # second connection when it tries to commit. Make sure the transaction # is not still open after the "database is locked" exception is thrown. # do_test tcl-10.18 { sqlite3 db2 test.db db2 eval { BEGIN; SELECT * FROM sqlite_master; } set rc [catch { db transaction { db eval {INSERT INTO t4 VALUES('five')} } } msg] list $rc $msg } {1 {database is locked}} do_test tcl-10.19 { db eval {BEGIN ; COMMIT} } {} # Thwart a [db transaction] command by locking the database using a # second connection with "BEGIN EXCLUSIVE". Make sure no transaction is # open after the "database is locked" exception is thrown. # do_test tcl-10.20 { db2 eval { COMMIT; BEGIN EXCLUSIVE; } set rc [catch { db transaction { db eval {INSERT INTO t4 VALUES('five')} } } msg] list $rc $msg } {1 {database is locked}} do_test tcl-10.21 { db2 close db eval {BEGIN ; COMMIT} } {} do_test tcl-10.22 { sqlite3 db2 test.db db transaction exclusive { catch { db2 eval {SELECT * FROM sqlite_master} } msg set msg "db2: $msg" } set msg } {db2: database is locked} db2 close do_test tcl-11.1 { db eval {INSERT INTO t4 VALUES(6)} db exists {SELECT x,x*2,x+x FROM t4 WHERE x==6} } {1} do_test tcl-11.2 { db exists {SELECT 0 FROM t4 WHERE x==6} } {1} do_test tcl-11.3 { db exists {SELECT 1 FROM t4 WHERE x==8} } {0} do_test tcl-12.1 { unset -nocomplain a b c version |
︙ | ︙ |