(module postgresql8 mzscheme
(require (only (lib "class.ss") send)
(lib "kw.ss")
(lib "unitsig.ss"))
(require (planet "debug.ss" ("untyped" "unlib.plt" 2))
(planet "gen.ss" ("untyped" "unlib.plt" 2))
(planet "symbol.ss" ("untyped" "unlib.plt" 2)))
(require (prefix postgresql: (file "spgsql-ssl/spgsql.ss"))
(file "../generic/util.ss")
(file "../base.ss")
(file "../db-sig.ss")
(prefix era: (file "../era.ss"))
(file "../query-core.ss")
(file "../transaction.ss")
(file "../type.ss")
(file "extract.ss")
(file "sql.ss"))
(provide config?
config-server
config-port
config-database
config-username
config-password
config-ssl
config-ssl-encrypt
(rename create-config make-config)
db@)
(define-struct config (server port database username password ssl ssl-encrypt))
(define create-config
(lambda/kw (server port database username #:optional [password #f] #:key [ssl 'yes] [ssl-encrypt 'sslv2-or-v3])
(make-config server port database username password ssl ssl-encrypt)))
(define db@
(unit/sig db^
(import)
(define (connect config)
(with-snooze-reraise (postgresql:exn:spgsql? "Could not connect to database")
(let* ([server (config-server config)]
[port (config-port config)]
[database (config-database config)]
[username (config-username config)]
[password (config-password config)]
[ssl (config-ssl config)]
[ssl-encrypt (config-ssl-encrypt config)]
[conn (postgresql:connect server
port
database
username
password
#:ssl ssl
#:ssl-encrypt ssl-encrypt)])
(send conn exec "SET DATESTYLE TO ISO;")
conn)))
(define (disconnect conn)
(with-snooze-reraise (postgresql:exn:spgsql? "Could not disconnect from database")
(send conn disconnect)))
(define (create-table conn entity)
(with-snooze-reraise (postgresql:exn:spgsql:query? (format "Could not create table for ~a" entity))
(send conn exec (create-sql entity))))
(define (drop-table conn entity)
(with-snooze-reraise (postgresql:exn:spgsql:query? (format "Could not drop table for ~a" entity))
(send conn exec (drop-sql entity))))
(define (insert-record conn struct)
(with-snooze-reraise (postgresql:exn:spgsql:query? (format "Could not insert database record for ~a" struct))
(let ([sequence-name (symbol-append (era:entity-name (era:struct-entity struct)) '-seq)])
(send conn exec (insert-sql struct))
(unquote-data type:id (send conn query-value (string-append "SELECT currval('" (quote-id sequence-name) "');"))))))
(define (update-record conn struct)
(with-snooze-reraise (postgresql:exn:spgsql:query? (format "Could not update database record for ~a" struct))
(send conn exec (update-sql struct)))
(void))
(define (delete-record conn entity id)
(with-snooze-reraise (postgresql:exn:spgsql:query? (format "Could not delete database record for ~a ~a" entity id))
(send conn exec (delete-sql entity id)))
(void))
(define (find-gen conn select)
(with-snooze-reraise (postgresql:exn:spgsql:query? (format "Could not execute SELECT query:~n~a" (select-sql select)))
(g:map (make-struct-extractor (select-what-entities select) (select-single-item? select))
(g:map (make-data-unquoter (select-what-types select))
(list->generator (send conn map (select-sql select) vector))))))
(define current-savepoints (make-parameter null))
(define (call-with-transaction conn body)
(let* ([frame (make-frame)]
[savepoint (gensym 'save)]
[old-savepoints (current-savepoints)]
[quoted-savepoint (quote-id savepoint)]
[body-complete-cell (make-thread-cell #f)] [transaction-complete-cell (make-thread-cell #f)]) (parameterize ([current-savepoints (cons savepoint old-savepoints)])
(dynamic-wind
(lambda ()
(if (thread-cell-ref transaction-complete-cell)
(raise-exn exn:fail:snooze:transaction
"Transaction block was interrupted and cannot be resumed.")
(begin
(when (null? old-savepoints)
(send conn exec "BEGIN;"))
(send conn exec (string-append "SAVEPOINT " quoted-savepoint ";")))))
(lambda ()
(call-with-frame frame
(lambda ()
(begin0 (body)
(thread-cell-set! body-complete-cell #t)))))
(lambda ()
(if (thread-cell-ref transaction-complete-cell)
(raise-exn exn:fail:snooze:transaction
"Transaction block was interrupted and resumed.")
(begin
(if (thread-cell-ref body-complete-cell)
(send conn exec (string-append "RELEASE SAVEPOINT " quoted-savepoint ";"))
(begin
(send conn exec (string-append "ROLLBACK TO SAVEPOINT " quoted-savepoint ";"))
(roll-back-frame! frame)))
(thread-cell-set! transaction-complete-cell #t)
(when (null? old-savepoints)
(send conn exec "COMMIT;")))))))))
(define (dump-sql select output-port format)
(fprintf output-port format (select-sql select))
select)
))
)