Changeset 15517 in project


Ignore:
Timestamp:
08/19/09 21:03:09 (10 years ago)
Author:
sjamaan
Message:

Implement transaction support (including nested transactions)

Location:
release/4/postgresql/trunk
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • release/4/postgresql/trunk/postgresql.scm

    r14796 r15517  
    2727  connect reset-connection disconnect connection?
    2828 
    29   multi-query query query*
     29  multi-query query query* with-transaction in-transaction?
    3030 
    3131  result? clear-result! row-count column-count
     
    218218;;;;;;;;;;;;;;;;;;;;
    219219
    220 (define-record pg-connection ptr type-parsers oid-parsers type-unparsers)
     220(define-record
     221  pg-connection ptr
     222  type-parsers oid-parsers type-unparsers
     223  transaction-depth)
    221224(define connection? pg-connection?)
    222225
     
    275278     (else
    276279      (let ((conn (make-pg-connection conn-ptr type-parsers
    277                                       (make-hash-table) type-unparsers)))
     280                                      (make-hash-table) type-unparsers 0)))
    278281        ;; We don't want libpq to piss in our stderr stream
    279282        ((foreign-lambda* void ((pgconn* conn))
     
    621624                         conn query params format))))
    622625
     626;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
     627;;;; Transaction management
     628;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
     629
     630(define (with-transaction conn thunk)
     631  (let* ((old-depth (pg-connection-transaction-depth conn))
     632         (rollback!
     633          (lambda ()
     634            (if (= old-depth 0)
     635                (query conn "ROLLBACK")
     636                ;; We do not *need* to give savepoints unique names,
     637                ;; but it aids debugging and we know the depth anyway.
     638                (query conn (conc "ROLLBACK TO SAVEPOINT s_" old-depth)))))
     639         (commit!
     640          (lambda ()
     641            (if (= old-depth 0)
     642                (query conn "COMMIT")
     643                (query conn (conc "RELEASE SAVEPOINT s_" old-depth))))))
     644    (if (= old-depth 0)
     645        (query conn "BEGIN")
     646        (query conn (conc "SAVEPOINT s_" old-depth)))
     647    (pg-connection-transaction-depth-set! conn (add1 old-depth))
     648    ;; TODO: Add a warning mechanism (using dynamic-wind) for when the
     649    ;; user tries to jump into/out of transactions with continuations?
     650    (handle-exceptions exn
     651      (begin
     652        (pg-connection-transaction-depth-set! conn old-depth)
     653        (rollback!)
     654        (raise exn))
     655      (let ((res (thunk)))
     656        (pg-connection-transaction-depth-set! conn old-depth)
     657        (if res (commit!) (rollback!))
     658        res))))
     659
     660(define (in-transaction? conn)
     661  (> (pg-connection-transaction-depth conn) 0))
     662
    623663;;;;;;;;;;;;;;;;;;;;;;
    624664;;;; Value escaping
  • release/4/postgresql/trunk/tests/run.scm

    r14792 r15517  
    342342         (query conn
    343343                "SELECT $1::text, $2::integer UNION SELECT 'three', 4" "one" 2))))
     344
     345(test-group "transactions"
     346  (query conn "CREATE TEMP TABLE foo ( bar integer )")
     347
     348  (test-group "simple transactions"
     349    (test "Transaction inactive"
     350          #f
     351          (in-transaction? conn))
     352    (test "Transaction active"
     353          #t
     354          (with-transaction conn
     355                            (lambda () (in-transaction? conn))))
     356    (test "Successful transaction"
     357          '(1)
     358          (and
     359           (with-transaction
     360            conn (lambda ()
     361                   (query conn "INSERT INTO foo (bar) VALUES (1)")))
     362           (column-values (query conn "SELECT * FROM foo"))))
     363 
     364    (query conn "TRUNCATE foo")
     365 
     366    (test "Unsuccessful transaction"
     367          #f
     368          (with-transaction
     369           conn (lambda ()
     370                  (query conn "INSERT INTO foo (bar) VALUES (1)")
     371                  #f)))
     372
     373    (test "Empty table after unsuccessful transaction"
     374          '()
     375          (column-values (query conn "SELECT * FROM foo")))
     376
     377    (handle-exceptions exn
     378      (void)
     379      (with-transaction
     380       conn (lambda ()
     381              (query conn "INSERT INTO foo (bar) VALUES (1)")
     382              (error "oops!"))))
     383 
     384    (test "Exception during transaction causes reset"
     385          '()
     386          (column-values (query conn "SELECT * FROM foo"))))
     387
     388  (test-group "nested transactions"
     389    (test "Successful transaction"
     390          '(1 2)
     391          (and
     392           (with-transaction
     393            conn (lambda ()
     394                   (query conn "INSERT INTO foo (bar) VALUES (1)")
     395                   (with-transaction
     396                    conn (lambda ()
     397                           (query conn "INSERT INTO foo (bar) VALUES (2)")))))
     398           (column-values (query conn "SELECT * FROM foo"))))
     399   
     400    (query conn "TRUNCATE foo")
     401
     402    (test "Unsuccessful main transaction"
     403          '()
     404          (and
     405           (not
     406            (with-transaction
     407             conn (lambda ()
     408                    (query conn "INSERT INTO foo (bar) VALUES (1)")
     409                    (with-transaction
     410                     conn (lambda ()
     411                            (query conn "INSERT INTO foo (bar) VALUES (2)")))
     412                    #f)))
     413           (column-values (query conn "SELECT * FROM foo"))))
     414   
     415    (test "Unsuccessful subtransaction"
     416          '(1)
     417          (and
     418           (with-transaction
     419            conn (lambda ()
     420                   (query conn "INSERT INTO foo (bar) VALUES (1)")
     421                   (with-transaction
     422                    conn (lambda ()
     423                           (query conn "INSERT INTO foo (bar) VALUES (2)")
     424                           #f))
     425                   #t))
     426           (column-values (query conn "SELECT * FROM foo"))))
     427
     428    (query conn "TRUNCATE foo")
     429
     430    (test "Multiple subtransactions"
     431          '(1 3)
     432          (and
     433           (with-transaction
     434            conn (lambda ()
     435                   (query conn "INSERT INTO foo (bar) VALUES (1)")
     436                   (with-transaction
     437                    conn (lambda ()
     438                           (query conn "INSERT INTO foo (bar) VALUES (2)")
     439                           #f))
     440                   (with-transaction
     441                    conn (lambda ()
     442                           (query conn "INSERT INTO foo (bar) VALUES (3)")))))
     443           (column-values (query conn "SELECT * FROM foo")))))
     444  )
Note: See TracChangeset for help on using the changeset viewer.