db: use log-based-eval for most examples
This commit is contained in:
parent
062a8ef5e7
commit
9bd5a9189b
|
@ -1,5 +1,6 @@
|
||||||
#lang racket/base
|
#lang racket/base
|
||||||
(require racket/class)
|
(require racket/class
|
||||||
|
racket/serialize)
|
||||||
(provide connection<%>
|
(provide connection<%>
|
||||||
dbsystem<%>
|
dbsystem<%>
|
||||||
prepared-statement<%>
|
prepared-statement<%>
|
||||||
|
@ -115,8 +116,8 @@
|
||||||
;; - (simple-result alist)
|
;; - (simple-result alist)
|
||||||
;; - (rows-result Header data)
|
;; - (rows-result Header data)
|
||||||
;; for user-visible rows-results: headers present, data is (listof vector)
|
;; for user-visible rows-results: headers present, data is (listof vector)
|
||||||
(struct simple-result (info) #:transparent)
|
(serializable-struct simple-result (info) #:transparent)
|
||||||
(struct rows-result (headers rows) #:transparent)
|
(serializable-struct rows-result (headers rows) #:transparent)
|
||||||
|
|
||||||
;; A cursor-result is
|
;; A cursor-result is
|
||||||
;; - (cursor-result Header prepared-statement ???)
|
;; - (cursor-result Header prepared-statement ???)
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
#lang racket/base
|
#lang racket/base
|
||||||
(require scribble/manual
|
(require scribble/manual
|
||||||
scribble/eval
|
scribble/eval
|
||||||
|
unstable/sandbox
|
||||||
|
racket/runtime-path
|
||||||
(for-label racket/base
|
(for-label racket/base
|
||||||
racket/contract))
|
racket/contract))
|
||||||
(provide (all-defined-out)
|
(provide (all-defined-out)
|
||||||
|
@ -18,18 +20,26 @@
|
||||||
|
|
||||||
;; ----
|
;; ----
|
||||||
|
|
||||||
(define the-eval (make-base-eval))
|
#|
|
||||||
(void
|
The log-based-eval should be run in an environment that defines
|
||||||
(interaction-eval #:eval the-eval
|
the DSN 'db-scribble-env as a PostgreSQL data source.
|
||||||
(require racket/class
|
|#
|
||||||
db/base
|
|
||||||
db/util/datetime))
|
|
||||||
(interaction-eval #:eval the-eval
|
|
||||||
(define connection% (class object% (super-new))))
|
|
||||||
(interaction-eval #:eval the-eval
|
|
||||||
(define connection-pool% (class object% (super-new)))))
|
|
||||||
|
|
||||||
(define-syntax-rule (examples/results [example result] ...)
|
(define-runtime-path example-log "example-log.rktd")
|
||||||
(examples #:eval the-eval (eval:alts example result) ...))
|
(define the-eval (make-log-based-eval example-log 'replay))
|
||||||
(define-syntax-rule (my-interaction [example result] ...)
|
|
||||||
(interaction #:eval the-eval (eval:alts example result) ...))
|
(the-eval '(require racket/class
|
||||||
|
db
|
||||||
|
db/util/postgresql
|
||||||
|
db/util/datetime))
|
||||||
|
|
||||||
|
#|
|
||||||
|
The fake eval is for eg connection examples
|
||||||
|
|#
|
||||||
|
|
||||||
|
(define fake-eval (make-base-eval))
|
||||||
|
(fake-eval '(begin (require racket/class)
|
||||||
|
(define connection% (class object% (super-new)))))
|
||||||
|
|
||||||
|
(define-syntax-rule (fake-examples [example result] ...)
|
||||||
|
(examples #:eval fake-eval (eval:alts example result) ...))
|
||||||
|
|
|
@ -100,7 +100,7 @@ Base connections are made using the following functions.
|
||||||
|
|
||||||
If the connection cannot be made, an exception is raised.
|
If the connection cannot be made, an exception is raised.
|
||||||
|
|
||||||
@(examples/results
|
@fake-examples[
|
||||||
[(postgresql-connect #:server "db.mysite.com"
|
[(postgresql-connect #:server "db.mysite.com"
|
||||||
#:port 5432
|
#:port 5432
|
||||||
#:database "webappdb"
|
#:database "webappdb"
|
||||||
|
@ -119,7 +119,7 @@ Base connections are made using the following functions.
|
||||||
[(postgresql-connect #:socket 'guess (code:comment "or (postgresql-guess-socket-path)")
|
[(postgresql-connect #:socket 'guess (code:comment "or (postgresql-guess-socket-path)")
|
||||||
#:user "me"
|
#:user "me"
|
||||||
#:database "me")
|
#:database "me")
|
||||||
(new connection%)])
|
(new connection%)]]
|
||||||
}
|
}
|
||||||
|
|
||||||
@defproc[(postgresql-guess-socket-path)
|
@defproc[(postgresql-guess-socket-path)
|
||||||
|
@ -162,7 +162,7 @@ Base connections are made using the following functions.
|
||||||
|
|
||||||
If the connection cannot be made, an exception is raised.
|
If the connection cannot be made, an exception is raised.
|
||||||
|
|
||||||
@(examples/results
|
@fake-examples[
|
||||||
[(mysql-connect #:server "db.mysite.com"
|
[(mysql-connect #:server "db.mysite.com"
|
||||||
#:port 3306
|
#:port 3306
|
||||||
#:database "webappdb"
|
#:database "webappdb"
|
||||||
|
@ -181,7 +181,7 @@ Base connections are made using the following functions.
|
||||||
[(mysql-connect #:socket (mysql-guess-socket-path)
|
[(mysql-connect #:socket (mysql-guess-socket-path)
|
||||||
#:user "me"
|
#:user "me"
|
||||||
#:database "me")
|
#:database "me")
|
||||||
(new connection%)])
|
(new connection%)]]
|
||||||
}
|
}
|
||||||
|
|
||||||
@defproc[(mysql-guess-socket-path)
|
@defproc[(mysql-guess-socket-path)
|
||||||
|
@ -234,12 +234,12 @@ Base connections are made using the following functions.
|
||||||
|
|
||||||
If the connection cannot be made, an exception is raised.
|
If the connection cannot be made, an exception is raised.
|
||||||
|
|
||||||
@(examples/results
|
@fake-examples[
|
||||||
[(sqlite3-connect #:database "/path/to/my.db")
|
[(sqlite3-connect #:database "/path/to/my.db")
|
||||||
(new connection%)]
|
(new connection%)]
|
||||||
[(sqlite3-connect #:database "relpath/to/my.db"
|
[(sqlite3-connect #:database "relpath/to/my.db"
|
||||||
#:mode 'create)
|
#:mode 'create)
|
||||||
(new connection%)])
|
(new connection%)]]
|
||||||
}
|
}
|
||||||
|
|
||||||
@defproc[(odbc-connect [#:dsn dsn string?]
|
@defproc[(odbc-connect [#:dsn dsn string?]
|
||||||
|
@ -348,20 +348,19 @@ Creates a @tech{connection pool}. The pool consists of up to
|
||||||
@racket[connect] function must return a fresh connection each time it
|
@racket[connect] function must return a fresh connection each time it
|
||||||
is called.
|
is called.
|
||||||
|
|
||||||
@examples/results[
|
@examples[#:eval the-eval
|
||||||
[(define pool
|
(eval:alts
|
||||||
|
(define pool
|
||||||
(connection-pool
|
(connection-pool
|
||||||
(lambda () (displayln "connecting!") (sqlite3-connect ....))
|
(lambda () (displayln "connecting!") (sqlite3-connect ....))
|
||||||
#:max-idle-connections 1))
|
#:max-idle-connections 1))
|
||||||
(void)]
|
(define pool
|
||||||
[(define c1 (connection-pool-lease pool))
|
(connection-pool
|
||||||
(displayln "connecting!")]
|
(lambda () (displayln "connecting!") (sqlite3-connect #:database 'memory)))))
|
||||||
[(define c2 (connection-pool-lease pool))
|
(define c1 (connection-pool-lease pool))
|
||||||
(displayln "connecting!")]
|
(define c2 (connection-pool-lease pool))
|
||||||
[(disconnect c1)
|
(disconnect c1)
|
||||||
(void)]
|
(code:line (define c3 (connection-pool-lease pool)) (code:comment "reuses actual conn. from c1"))
|
||||||
[(code:line (define c3 (connection-pool-lease pool)) (code:comment "reuses actual conn. from c1"))
|
|
||||||
(void)]
|
|
||||||
]
|
]
|
||||||
|
|
||||||
See also @racket[virtual-connection] for a mechanism that eliminates
|
See also @racket[virtual-connection] for a mechanism that eliminates
|
||||||
|
@ -434,10 +433,9 @@ closing its own connections. In particular, a @tech{virtual
|
||||||
connection} backed by a @tech{connection pool} combines convenience
|
connection} backed by a @tech{connection pool} combines convenience
|
||||||
with efficiency:
|
with efficiency:
|
||||||
|
|
||||||
@examples/results[
|
@racketblock[
|
||||||
[(define the-connection
|
(define the-connection
|
||||||
(virtual-connection (connection-pool (lambda () ....))))
|
(virtual-connection (connection-pool (lambda () ....))))
|
||||||
(void)]
|
|
||||||
]
|
]
|
||||||
|
|
||||||
The resulting virtual connection leases a connection from the pool on
|
The resulting virtual connection leases a connection from the pool on
|
||||||
|
@ -451,27 +449,25 @@ causes the current actual connection associated with the thread (if
|
||||||
there is one) to be disconnected, but the connection will be recreated
|
there is one) to be disconnected, but the connection will be recreated
|
||||||
if a query function is executed.
|
if a query function is executed.
|
||||||
|
|
||||||
@examples/results[
|
@examples[#:eval the-eval
|
||||||
[(define c
|
(eval:alts
|
||||||
|
(define c
|
||||||
(virtual-connection
|
(virtual-connection
|
||||||
(lambda ()
|
(lambda ()
|
||||||
(printf "connecting!\n")
|
(printf "connecting!\n")
|
||||||
(postgresql-connect ....))))
|
(postgresql-connect ....))))
|
||||||
(void)]
|
(define c
|
||||||
[(connected? c)
|
(virtual-connection
|
||||||
(values #f)]
|
(lambda ()
|
||||||
[(query-value c "select 1")
|
(printf "connecting!\n")
|
||||||
(begin (printf "connecting!\n") 1)]
|
(dsn-connect 'db-scribble-env)))))
|
||||||
[(connected? c)
|
(connected? c)
|
||||||
(values #t)]
|
(query-value c "select 1")
|
||||||
[(void (thread (lambda () (displayln (query-value c "select 2")))))
|
(connected? c)
|
||||||
(begin (printf "connecting!\n") (displayln 2))]
|
(void (thread (lambda () (displayln (query-value c "select 2")))))
|
||||||
[(disconnect c)
|
(disconnect c)
|
||||||
(void)]
|
(connected? c)
|
||||||
[(connected? c)
|
(query-value c "select 3")
|
||||||
(values #f)]
|
|
||||||
[(query-value c "select 3")
|
|
||||||
(begin (printf "connecting!\n") 3)]
|
|
||||||
]
|
]
|
||||||
|
|
||||||
Connections produced by @racket[virtual-connection] may not be used
|
Connections produced by @racket[virtual-connection] may not be used
|
||||||
|
@ -479,18 +475,16 @@ with the @racket[prepare] function. However, they may still be used to
|
||||||
execute parameterized queries expressed as strings or encapsulated via
|
execute parameterized queries expressed as strings or encapsulated via
|
||||||
@racket[virtual-statement].
|
@racket[virtual-statement].
|
||||||
|
|
||||||
@examples/results[
|
@examples[#:eval the-eval
|
||||||
[(prepare c "select 2 + $1")
|
(prepare c "select 2 + $1")
|
||||||
(error 'prepare "cannot prepare statement with virtual connection")]
|
(query-value c "select 2 + $1" 2)
|
||||||
[(query-value c "select 2 + $1" 2)
|
(define pst (virtual-statement "select 2 + $1"))
|
||||||
4]
|
(query-value c pst 3)
|
||||||
[(define pst (virtual-statement "select 2 + $1"))
|
|
||||||
(void)]
|
|
||||||
[(query-value c pst 3)
|
|
||||||
5]
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@(the-eval '(begin (set! c #f) (set! pst #f)))
|
||||||
|
|
||||||
@;{========================================}
|
@;{========================================}
|
||||||
|
|
||||||
@section[#:tag "kill-safe"]{Kill-safe Connections}
|
@section[#:tag "kill-safe"]{Kill-safe Connections}
|
||||||
|
@ -555,7 +549,7 @@ ODBC's DSNs.
|
||||||
for @racket[dsn], an exception is raised. If @racket[dsn] is a
|
for @racket[dsn], an exception is raised. If @racket[dsn] is a
|
||||||
@racket[data-source], then @racket[dsn-file] is ignored.
|
@racket[data-source], then @racket[dsn-file] is ignored.
|
||||||
|
|
||||||
@examples/results[
|
@fake-examples[
|
||||||
[(put-dsn 'pg
|
[(put-dsn 'pg
|
||||||
(postgresql-data-source #:user "me"
|
(postgresql-data-source #:user "me"
|
||||||
#:database "mydb"
|
#:database "mydb"
|
||||||
|
|
670
collects/db/scribblings/example-log.rktd
Normal file
670
collects/db/scribblings/example-log.rktd
Normal file
|
@ -0,0 +1,670 @@
|
||||||
|
;; This file was created by make-log-based-eval
|
||||||
|
((require racket/class db db/util/postgresql db/util/datetime)
|
||||||
|
((3) 0 () 0 () () (c values c (void)))
|
||||||
|
#""
|
||||||
|
#"")
|
||||||
|
((require db) ((3) 0 () 0 () () (c values c (void))) #"" #"")
|
||||||
|
((define pgc (dsn-connect 'db-scribble-env))
|
||||||
|
((3) 0 () 0 () () (c values c (void)))
|
||||||
|
#""
|
||||||
|
#"")
|
||||||
|
((query-exec
|
||||||
|
pgc
|
||||||
|
"create temporary table the_numbers (n integer, d varchar(20))")
|
||||||
|
((3) 0 () 0 () () (c values c (void)))
|
||||||
|
#""
|
||||||
|
#"")
|
||||||
|
((query-exec pgc "insert into the_numbers values (0, 'nothing')")
|
||||||
|
((3) 0 () 0 () () (c values c (void)))
|
||||||
|
#""
|
||||||
|
#"")
|
||||||
|
((query-exec pgc "insert into the_numbers values (1, 'the loneliest number')")
|
||||||
|
((3) 0 () 0 () () (c values c (void)))
|
||||||
|
#""
|
||||||
|
#"")
|
||||||
|
((query-exec pgc "insert into the_numbers values (2, 'company')")
|
||||||
|
((3) 0 () 0 () () (c values c (void)))
|
||||||
|
#""
|
||||||
|
#"")
|
||||||
|
((query pgc "insert into the_numbers values (3, 'a crowd')")
|
||||||
|
((3)
|
||||||
|
1
|
||||||
|
(((lib "db/private/generic/interfaces.rkt")
|
||||||
|
.
|
||||||
|
deserialize-info:simple-result-v0))
|
||||||
|
0
|
||||||
|
()
|
||||||
|
()
|
||||||
|
(c values c (0 (c (c command u . "INSERT 0 1")))))
|
||||||
|
#""
|
||||||
|
#"")
|
||||||
|
((query pgc "select n, d from the_numbers where n % 2 = 0")
|
||||||
|
((3)
|
||||||
|
1
|
||||||
|
(((lib "db/private/generic/interfaces.rkt")
|
||||||
|
.
|
||||||
|
deserialize-info:rows-result-v0))
|
||||||
|
0
|
||||||
|
()
|
||||||
|
()
|
||||||
|
(c
|
||||||
|
values
|
||||||
|
c
|
||||||
|
(0
|
||||||
|
(c
|
||||||
|
(c
|
||||||
|
(c name u . "n")
|
||||||
|
c
|
||||||
|
(c typeid . 23)
|
||||||
|
c
|
||||||
|
(c type-size . 4)
|
||||||
|
c
|
||||||
|
(c type-mod . -1))
|
||||||
|
c
|
||||||
|
(c
|
||||||
|
(c name u . "d")
|
||||||
|
c
|
||||||
|
(c typeid . 1043)
|
||||||
|
c
|
||||||
|
(c type-size . -1)
|
||||||
|
c
|
||||||
|
(c type-mod . 24)))
|
||||||
|
(c (v! 0 (u . "nothing")) c (v! 2 (u . "company"))))))
|
||||||
|
#""
|
||||||
|
#"")
|
||||||
|
((query-rows pgc "select n, d from the_numbers where n % 2 = 0")
|
||||||
|
((3)
|
||||||
|
0
|
||||||
|
()
|
||||||
|
0
|
||||||
|
()
|
||||||
|
()
|
||||||
|
(c values c (c (v! 0 (u . "nothing")) c (v! 2 (u . "company")))))
|
||||||
|
#""
|
||||||
|
#"")
|
||||||
|
((query-row pgc "select * from the_numbers where n = 0")
|
||||||
|
((3) 0 () 0 () () (c values c (v! 0 (u . "nothing"))))
|
||||||
|
#""
|
||||||
|
#"")
|
||||||
|
((query-list pgc "select d from the_numbers order by n")
|
||||||
|
((3)
|
||||||
|
0
|
||||||
|
()
|
||||||
|
0
|
||||||
|
()
|
||||||
|
()
|
||||||
|
(c
|
||||||
|
values
|
||||||
|
c
|
||||||
|
(c
|
||||||
|
(u . "nothing")
|
||||||
|
c
|
||||||
|
(u . "the loneliest number")
|
||||||
|
c
|
||||||
|
(u . "company")
|
||||||
|
c
|
||||||
|
(u . "a crowd"))))
|
||||||
|
#""
|
||||||
|
#"")
|
||||||
|
((query-value pgc "select count(*) from the_numbers")
|
||||||
|
((3) 0 () 0 () () (c values c 4))
|
||||||
|
#""
|
||||||
|
#"")
|
||||||
|
((query-value pgc "select d from the_numbers where n = 5")
|
||||||
|
((3)
|
||||||
|
0
|
||||||
|
()
|
||||||
|
0
|
||||||
|
()
|
||||||
|
()
|
||||||
|
(c
|
||||||
|
exn
|
||||||
|
c
|
||||||
|
"query-value: query returned zero rows (expected 1): \"select d from the_numbers where n = 5\""))
|
||||||
|
#""
|
||||||
|
#"")
|
||||||
|
((query-maybe-value pgc "select d from the_numbers where n = 5")
|
||||||
|
((3) 0 () 0 () () (c values c #f))
|
||||||
|
#""
|
||||||
|
#"")
|
||||||
|
((for
|
||||||
|
(((n d) (in-query pgc "select * from the_numbers where n < 4")))
|
||||||
|
(printf "~a: ~a\n" n d))
|
||||||
|
((3) 0 () 0 () () (c values c (void)))
|
||||||
|
#"0: nothing\n1: the loneliest number\n2: company\n3: a crowd\n"
|
||||||
|
#"")
|
||||||
|
((for/fold
|
||||||
|
((sum 0))
|
||||||
|
((n (in-query pgc "select n from the_numbers")))
|
||||||
|
(+ sum n))
|
||||||
|
((3) 0 () 0 () () (c values c 6))
|
||||||
|
#""
|
||||||
|
#"")
|
||||||
|
((begin
|
||||||
|
(with-handlers
|
||||||
|
((exn:fail? (lambda (e) (printf "~a~n" (exn-message e)))))
|
||||||
|
(query-value pgc "select NoSuchField from NoSuchTable"))
|
||||||
|
(query-value pgc "select 'okay to proceed!'"))
|
||||||
|
((3) 0 () 0 () () (c values c (u . "okay to proceed!")))
|
||||||
|
#"query-value: relation \"nosuchtable\" does not exist (SQLSTATE 42P01)\n"
|
||||||
|
#"")
|
||||||
|
((query-value pgc "select d from the_numbers where n = $1" 2)
|
||||||
|
((3) 0 () 0 () () (c values c (u . "company")))
|
||||||
|
#""
|
||||||
|
#"")
|
||||||
|
((query-list pgc "select n from the_numbers where n > $1 and n < $2" 0 3)
|
||||||
|
((3) 0 () 0 () () (c values c (c 1 c 2)))
|
||||||
|
#""
|
||||||
|
#"")
|
||||||
|
((define get-less-than-pst
|
||||||
|
(prepare pgc "select n from the_numbers where n < $1"))
|
||||||
|
((3) 0 () 0 () () (c values c (void)))
|
||||||
|
#""
|
||||||
|
#"")
|
||||||
|
((query-list pgc get-less-than-pst 1)
|
||||||
|
((3) 0 () 0 () () (c values c (c 0)))
|
||||||
|
#""
|
||||||
|
#"")
|
||||||
|
((query-list pgc (bind-prepared-statement get-less-than-pst '(2)))
|
||||||
|
((3) 0 () 0 () () (c values c (c 0 c 1)))
|
||||||
|
#""
|
||||||
|
#"")
|
||||||
|
((void) ((3) 0 () 0 () () (c values c (void))) #"" #"")
|
||||||
|
((define pool
|
||||||
|
(connection-pool
|
||||||
|
(lambda ()
|
||||||
|
(displayln "connecting!")
|
||||||
|
(sqlite3-connect #:database 'memory))))
|
||||||
|
((3) 0 () 0 () () (c values c (void)))
|
||||||
|
#""
|
||||||
|
#"")
|
||||||
|
((define c1 (connection-pool-lease pool))
|
||||||
|
((3) 0 () 0 () () (c values c (void)))
|
||||||
|
#"connecting!\n"
|
||||||
|
#"")
|
||||||
|
((define c2 (connection-pool-lease pool))
|
||||||
|
((3) 0 () 0 () () (c values c (void)))
|
||||||
|
#"connecting!\n"
|
||||||
|
#"")
|
||||||
|
((disconnect c1) ((3) 0 () 0 () () (c values c (void))) #"" #"")
|
||||||
|
((define c3 (connection-pool-lease pool))
|
||||||
|
((3) 0 () 0 () () (c values c (void)))
|
||||||
|
#""
|
||||||
|
#"")
|
||||||
|
((define c
|
||||||
|
(virtual-connection
|
||||||
|
(lambda () (printf "connecting!\n") (dsn-connect 'db-scribble-env))))
|
||||||
|
((3) 0 () 0 () () (c values c (void)))
|
||||||
|
#""
|
||||||
|
#"")
|
||||||
|
((connected? c) ((3) 0 () 0 () () (c values c #f)) #"" #"")
|
||||||
|
((query-value c "select 1")
|
||||||
|
((3) 0 () 0 () () (c values c 1))
|
||||||
|
#"connecting!\n"
|
||||||
|
#"")
|
||||||
|
((connected? c) ((3) 0 () 0 () () (c values c #t)) #"" #"")
|
||||||
|
((void (thread (lambda () (displayln (query-value c "select 2")))))
|
||||||
|
((3) 0 () 0 () () (c values c (void)))
|
||||||
|
#"connecting!\n2\n"
|
||||||
|
#"")
|
||||||
|
((disconnect c) ((3) 0 () 0 () () (c values c (void))) #"" #"")
|
||||||
|
((connected? c) ((3) 0 () 0 () () (c values c #f)) #"" #"")
|
||||||
|
((query-value c "select 3")
|
||||||
|
((3) 0 () 0 () () (c values c 3))
|
||||||
|
#"connecting!\n"
|
||||||
|
#"")
|
||||||
|
((prepare c "select 2 + $1")
|
||||||
|
((3)
|
||||||
|
0
|
||||||
|
()
|
||||||
|
0
|
||||||
|
()
|
||||||
|
()
|
||||||
|
(c exn c "prepare: cannot prepare statement with virtual connection"))
|
||||||
|
#""
|
||||||
|
#"")
|
||||||
|
((query-value c "select 2 + $1" 2) ((3) 0 () 0 () () (c values c 4)) #"" #"")
|
||||||
|
((define pst (virtual-statement "select 2 + $1"))
|
||||||
|
((3) 0 () 0 () () (c values c (void)))
|
||||||
|
#""
|
||||||
|
#"")
|
||||||
|
((query-value c pst 3) ((3) 0 () 0 () () (c values c 5)) #"" #"")
|
||||||
|
((begin (set! c #f) (set! pst #f))
|
||||||
|
((3) 0 () 0 () () (c values c (void)))
|
||||||
|
#""
|
||||||
|
#"")
|
||||||
|
((define c pgc) ((3) 0 () 0 () () (c values c (void))) #"" #"")
|
||||||
|
((query-exec pgc "insert into the_numbers values (42, 'the answer')")
|
||||||
|
((3) 0 () 0 () () (c values c (void)))
|
||||||
|
#""
|
||||||
|
#"")
|
||||||
|
((query-exec pgc "delete from the_numbers where n = $1" 42)
|
||||||
|
((3) 0 () 0 () () (c values c (void)))
|
||||||
|
#""
|
||||||
|
#"")
|
||||||
|
((query-rows pgc "select * from the_numbers where n = $1" 2)
|
||||||
|
((3) 0 () 0 () () (c values c (c (v! 2 (u . "company")))))
|
||||||
|
#""
|
||||||
|
#"")
|
||||||
|
((query-rows c "select 17")
|
||||||
|
((3) 0 () 0 () () (c values c (c (v! 17))))
|
||||||
|
#""
|
||||||
|
#"")
|
||||||
|
((query-list c "select n from the_numbers where n < 2")
|
||||||
|
((3) 0 () 0 () () (c values c (c 0 c 1)))
|
||||||
|
#""
|
||||||
|
#"")
|
||||||
|
((query-list c "select 'hello'")
|
||||||
|
((3) 0 () 0 () () (c values c (c (u . "hello"))))
|
||||||
|
#""
|
||||||
|
#"")
|
||||||
|
((query-row pgc "select * from the_numbers where n = $1" 2)
|
||||||
|
((3) 0 () 0 () () (c values c (v! 2 (u . "company"))))
|
||||||
|
#""
|
||||||
|
#"")
|
||||||
|
((query-row pgc "select min(n), max(n) from the_numbers")
|
||||||
|
((3) 0 () 0 () () (c values c (v! 0 3)))
|
||||||
|
#""
|
||||||
|
#"")
|
||||||
|
((query-maybe-row pgc "select * from the_numbers where n = $1" 100)
|
||||||
|
((3) 0 () 0 () () (c values c #f))
|
||||||
|
#""
|
||||||
|
#"")
|
||||||
|
((query-maybe-row c "select 17")
|
||||||
|
((3) 0 () 0 () () (c values c (v! 17)))
|
||||||
|
#""
|
||||||
|
#"")
|
||||||
|
((query-value pgc "select timestamp 'epoch'")
|
||||||
|
((3)
|
||||||
|
1
|
||||||
|
(((lib "db/private/generic/sql-data.rkt")
|
||||||
|
.
|
||||||
|
deserialize-info:sql-timestamp-v0))
|
||||||
|
0
|
||||||
|
()
|
||||||
|
()
|
||||||
|
(c values c (0 1970 1 1 0 0 0 0 #f)))
|
||||||
|
#""
|
||||||
|
#"")
|
||||||
|
((query-value pgc "select d from the_numbers where n = $1" 3)
|
||||||
|
((3) 0 () 0 () () (c values c (u . "a crowd")))
|
||||||
|
#""
|
||||||
|
#"")
|
||||||
|
((query-value pgc "select d from the_numbers where n = $1" 100)
|
||||||
|
((3)
|
||||||
|
0
|
||||||
|
()
|
||||||
|
0
|
||||||
|
()
|
||||||
|
()
|
||||||
|
(c
|
||||||
|
exn
|
||||||
|
c
|
||||||
|
"query-value: query returned zero rows (expected 1): #<statement-binding>"))
|
||||||
|
#""
|
||||||
|
#"")
|
||||||
|
((query-value c "select count(*) from the_numbers")
|
||||||
|
((3) 0 () 0 () () (c values c 4))
|
||||||
|
#""
|
||||||
|
#"")
|
||||||
|
((for/list ((n (in-query pgc "select n from the_numbers where n < 2"))) n)
|
||||||
|
((3) 0 () 0 () () (c values c (c 0 c 1)))
|
||||||
|
#""
|
||||||
|
#"")
|
||||||
|
((call-with-transaction
|
||||||
|
pgc
|
||||||
|
(lambda ()
|
||||||
|
(for
|
||||||
|
(((n d)
|
||||||
|
(in-query pgc "select * from the_numbers where n < $1" 4 #:fetch 1)))
|
||||||
|
(printf "~a: ~a\n" n d))))
|
||||||
|
((3) 0 () 0 () () (c values c (void)))
|
||||||
|
#"0: nothing\n1: the loneliest number\n2: company\n3: a crowd\n"
|
||||||
|
#"")
|
||||||
|
((for ((n (in-query pgc "select * from the_numbers"))) (displayln n))
|
||||||
|
((3)
|
||||||
|
0
|
||||||
|
()
|
||||||
|
0
|
||||||
|
()
|
||||||
|
()
|
||||||
|
(c
|
||||||
|
exn
|
||||||
|
c
|
||||||
|
"in-query: query returned 2 columns (expected 1): \"select * from the_numbers\""))
|
||||||
|
#""
|
||||||
|
#"")
|
||||||
|
((define vehicles-result
|
||||||
|
(rows-result
|
||||||
|
'(((name . "type")) ((name . "maker")) ((name . "model")))
|
||||||
|
`(#("car" "honda" "civic")
|
||||||
|
#("car" "ford" "focus")
|
||||||
|
#("car" "ford" "pinto")
|
||||||
|
#("bike" "giant" "boulder")
|
||||||
|
#("bike" "schwinn" ,sql-null))))
|
||||||
|
((3) 0 () 0 () () (c values c (void)))
|
||||||
|
#""
|
||||||
|
#"")
|
||||||
|
((group-rows vehicles-result #:group '(#("type")))
|
||||||
|
((3)
|
||||||
|
2
|
||||||
|
(((lib "db/private/generic/interfaces.rkt")
|
||||||
|
.
|
||||||
|
deserialize-info:rows-result-v0)
|
||||||
|
((lib "db/private/generic/sql-data.rkt") . deserialize-info:sql-null-v0))
|
||||||
|
1
|
||||||
|
("ford")
|
||||||
|
()
|
||||||
|
(c
|
||||||
|
values
|
||||||
|
c
|
||||||
|
(0
|
||||||
|
(c
|
||||||
|
(c (c name . "type"))
|
||||||
|
c
|
||||||
|
(c
|
||||||
|
(c name . "grouped")
|
||||||
|
c
|
||||||
|
(c grouped c (c (c name . "maker")) c (c (c name . "model")))))
|
||||||
|
(c
|
||||||
|
(v!
|
||||||
|
"car"
|
||||||
|
(c (v! "honda" "civic") c (v! (? . 0) "focus") c (v! (? . 0) "pinto")))
|
||||||
|
c
|
||||||
|
(v! "bike" (c (v! "giant" "boulder") c (v! "schwinn" (1))))))))
|
||||||
|
#""
|
||||||
|
#"")
|
||||||
|
((group-rows
|
||||||
|
vehicles-result
|
||||||
|
#:group
|
||||||
|
'(#("type") #("maker"))
|
||||||
|
#:group-mode
|
||||||
|
'(list))
|
||||||
|
((3)
|
||||||
|
1
|
||||||
|
(((lib "db/private/generic/interfaces.rkt")
|
||||||
|
.
|
||||||
|
deserialize-info:rows-result-v0))
|
||||||
|
1
|
||||||
|
((c name . "grouped"))
|
||||||
|
()
|
||||||
|
(c
|
||||||
|
values
|
||||||
|
c
|
||||||
|
(0
|
||||||
|
(c
|
||||||
|
(c (c name . "type"))
|
||||||
|
c
|
||||||
|
(c
|
||||||
|
(? . 0)
|
||||||
|
c
|
||||||
|
(c
|
||||||
|
grouped
|
||||||
|
c
|
||||||
|
(c (c name . "maker"))
|
||||||
|
c
|
||||||
|
(c (? . 0) c (c grouped c (c (c name . "model")))))))
|
||||||
|
(c
|
||||||
|
(v!
|
||||||
|
"car"
|
||||||
|
(c (v! "honda" (c "civic")) c (v! "ford" (c "focus" c "pinto"))))
|
||||||
|
c
|
||||||
|
(v! "bike" (c (v! "giant" (c "boulder")) c (v! "schwinn" ())))))))
|
||||||
|
#""
|
||||||
|
#"")
|
||||||
|
((rows->dict vehicles-result #:key "model" #:value '#("type" "maker"))
|
||||||
|
((3)
|
||||||
|
1
|
||||||
|
(((lib "db/private/generic/sql-data.rkt") . deserialize-info:sql-null-v0))
|
||||||
|
3
|
||||||
|
("car" "ford" "bike")
|
||||||
|
()
|
||||||
|
(c
|
||||||
|
values
|
||||||
|
c
|
||||||
|
(h
|
||||||
|
-
|
||||||
|
(equal)
|
||||||
|
((0) v! (? . 2) "schwinn")
|
||||||
|
("civic" v! (? . 0) "honda")
|
||||||
|
("pinto" v! (? . 0) (? . 1))
|
||||||
|
("focus" v! (? . 0) (? . 1))
|
||||||
|
("boulder" v! (? . 2) "giant"))))
|
||||||
|
#""
|
||||||
|
#"")
|
||||||
|
((rows->dict
|
||||||
|
vehicles-result
|
||||||
|
#:key
|
||||||
|
"maker"
|
||||||
|
#:value
|
||||||
|
"model"
|
||||||
|
#:value-mode
|
||||||
|
'(list))
|
||||||
|
((3)
|
||||||
|
0
|
||||||
|
()
|
||||||
|
0
|
||||||
|
()
|
||||||
|
()
|
||||||
|
(c
|
||||||
|
values
|
||||||
|
c
|
||||||
|
(h
|
||||||
|
-
|
||||||
|
(equal)
|
||||||
|
("ford" c "focus" c "pinto")
|
||||||
|
("honda" c "civic")
|
||||||
|
("giant" c "boulder")
|
||||||
|
("schwinn"))))
|
||||||
|
#""
|
||||||
|
#"")
|
||||||
|
((let* ((get-name-pst (prepare pgc "select d from the_numbers where n = $1"))
|
||||||
|
(get-name2 (bind-prepared-statement get-name-pst (list 2)))
|
||||||
|
(get-name3 (bind-prepared-statement get-name-pst (list 3))))
|
||||||
|
(list (query-value pgc get-name2) (query-value pgc get-name3)))
|
||||||
|
((3) 0 () 0 () () (c values c (c (u . "company") c (u . "a crowd"))))
|
||||||
|
#""
|
||||||
|
#"")
|
||||||
|
((define pst
|
||||||
|
(virtual-statement
|
||||||
|
(lambda (dbsys)
|
||||||
|
(case (dbsystem-name dbsys)
|
||||||
|
((postgresql) "select n from the_numbers where n < $1")
|
||||||
|
((sqlite3) "select n from the_numbers where n < ?")
|
||||||
|
(else (error "unknown system"))))))
|
||||||
|
((3) 0 () 0 () () (c values c (void)))
|
||||||
|
#""
|
||||||
|
#"")
|
||||||
|
((query-list pgc pst 3) ((3) 0 () 0 () () (c values c (c 0 c 1 c 2))) #"" #"")
|
||||||
|
((query-list pgc pst 3) ((3) 0 () 0 () () (c values c (c 0 c 1 c 2))) #"" #"")
|
||||||
|
((with-handlers
|
||||||
|
((exn:fail:sql? exn:fail:sql-info))
|
||||||
|
(query pgc "select * from nosuchtable"))
|
||||||
|
((3)
|
||||||
|
0
|
||||||
|
()
|
||||||
|
0
|
||||||
|
()
|
||||||
|
()
|
||||||
|
(c
|
||||||
|
values
|
||||||
|
c
|
||||||
|
(c
|
||||||
|
(c severity u . "ERROR")
|
||||||
|
c
|
||||||
|
(c code u . "42P01")
|
||||||
|
c
|
||||||
|
(c message u . "relation \"nosuchtable\" does not exist")
|
||||||
|
c
|
||||||
|
(c position u . "15")
|
||||||
|
c
|
||||||
|
(c file u . "parse_relation.c")
|
||||||
|
c
|
||||||
|
(c line u . "857")
|
||||||
|
c
|
||||||
|
(c routine u . "parserOpenTable"))))
|
||||||
|
#""
|
||||||
|
#"")
|
||||||
|
((query-value pgc "select count(*) from the_numbers")
|
||||||
|
((3) 0 () 0 () () (c values c 4))
|
||||||
|
#""
|
||||||
|
#"")
|
||||||
|
((query-value pgc "select false") ((3) 0 () 0 () () (c values c #f)) #"" #"")
|
||||||
|
((query-value pgc "select 1 + $1" 2) ((3) 0 () 0 () () (c values c 3)) #"" #"")
|
||||||
|
((query-value pgc "select inet '127.0.0.1'")
|
||||||
|
((3)
|
||||||
|
0
|
||||||
|
()
|
||||||
|
0
|
||||||
|
()
|
||||||
|
()
|
||||||
|
(c exn c "query-value: unsupported type: inet (typeid 869)"))
|
||||||
|
#""
|
||||||
|
#"")
|
||||||
|
((query-value pgc "select cast(inet '127.0.0.1' as varchar)")
|
||||||
|
((3) 0 () 0 () () (c values c (u . "127.0.0.1/32")))
|
||||||
|
#""
|
||||||
|
#"")
|
||||||
|
((query-value pgc "select real '+Infinity'")
|
||||||
|
((3) 0 () 0 () () (c values c +inf.0))
|
||||||
|
#""
|
||||||
|
#"")
|
||||||
|
((query-value pgc "select numeric '12345678901234567890'")
|
||||||
|
((3) 0 () 0 () () (c values c 12345678901234567890))
|
||||||
|
#""
|
||||||
|
#"")
|
||||||
|
((query-value pgc "select 1 in (1, 2, 3)")
|
||||||
|
((3) 0 () 0 () () (c values c #t))
|
||||||
|
#""
|
||||||
|
#"")
|
||||||
|
((query-value
|
||||||
|
pgc
|
||||||
|
"select 1 = any ($1::integer[])"
|
||||||
|
(list->pg-array (list 1 2 3)))
|
||||||
|
((3) 0 () 0 () () (c values c #t))
|
||||||
|
#""
|
||||||
|
#"")
|
||||||
|
((query-value pgc "select 1 = any ($1)" (list 1 2 3))
|
||||||
|
((3) 0 () 0 () () (c values c #t))
|
||||||
|
#""
|
||||||
|
#"")
|
||||||
|
((query-value pgc "select $1::integer = any ($2)" 1 (list 1 2 3))
|
||||||
|
((3) 0 () 0 () () (c values c #t))
|
||||||
|
#""
|
||||||
|
#"")
|
||||||
|
((query-value pgc "select $1 = any ($2)" 1 (list 1 2 3))
|
||||||
|
((3)
|
||||||
|
0
|
||||||
|
()
|
||||||
|
0
|
||||||
|
()
|
||||||
|
()
|
||||||
|
(c exn c "query-value: cannot convert to PostgreSQL string type: 1"))
|
||||||
|
#""
|
||||||
|
#"")
|
||||||
|
((query-value c "select NULL")
|
||||||
|
((3)
|
||||||
|
1
|
||||||
|
(((lib "db/private/generic/sql-data.rkt") . deserialize-info:sql-null-v0))
|
||||||
|
0
|
||||||
|
()
|
||||||
|
()
|
||||||
|
(c values c (0)))
|
||||||
|
#""
|
||||||
|
#"")
|
||||||
|
((sql-null->false "apple") ((3) 0 () 0 () () (c values c "apple")) #"" #"")
|
||||||
|
((sql-null->false sql-null) ((3) 0 () 0 () () (c values c #f)) #"" #"")
|
||||||
|
((sql-null->false #f) ((3) 0 () 0 () () (c values c #f)) #"" #"")
|
||||||
|
((false->sql-null "apple") ((3) 0 () 0 () () (c values c "apple")) #"" #"")
|
||||||
|
((false->sql-null #f)
|
||||||
|
((3)
|
||||||
|
1
|
||||||
|
(((lib "db/private/generic/sql-data.rkt") . deserialize-info:sql-null-v0))
|
||||||
|
0
|
||||||
|
()
|
||||||
|
()
|
||||||
|
(c values c (0)))
|
||||||
|
#""
|
||||||
|
#"")
|
||||||
|
((query-value pgc "select date '25-dec-1980'")
|
||||||
|
((3)
|
||||||
|
1
|
||||||
|
(((lib "db/private/generic/sql-data.rkt") . deserialize-info:sql-date-v0))
|
||||||
|
0
|
||||||
|
()
|
||||||
|
()
|
||||||
|
(c values c (0 1980 12 25)))
|
||||||
|
#""
|
||||||
|
#"")
|
||||||
|
((query-value pgc "select time '7:30'")
|
||||||
|
((3)
|
||||||
|
1
|
||||||
|
(((lib "db/private/generic/sql-data.rkt") . deserialize-info:sql-time-v0))
|
||||||
|
0
|
||||||
|
()
|
||||||
|
()
|
||||||
|
(c values c (0 7 30 0 0 #f)))
|
||||||
|
#""
|
||||||
|
#"")
|
||||||
|
((query-value pgc "select timestamp 'epoch'")
|
||||||
|
((3)
|
||||||
|
1
|
||||||
|
(((lib "db/private/generic/sql-data.rkt")
|
||||||
|
.
|
||||||
|
deserialize-info:sql-timestamp-v0))
|
||||||
|
0
|
||||||
|
()
|
||||||
|
()
|
||||||
|
(c values c (0 1970 1 1 0 0 0 0 #f)))
|
||||||
|
#""
|
||||||
|
#"")
|
||||||
|
((query-value pgc "select timestamp with time zone 'epoch'")
|
||||||
|
((3)
|
||||||
|
1
|
||||||
|
(((lib "db/private/generic/sql-data.rkt")
|
||||||
|
.
|
||||||
|
deserialize-info:sql-timestamp-v0))
|
||||||
|
0
|
||||||
|
()
|
||||||
|
()
|
||||||
|
(c values c (0 1969 12 31 19 0 0 0 -18000)))
|
||||||
|
#""
|
||||||
|
#"")
|
||||||
|
((sql-bits->list (string->sql-bits "1011"))
|
||||||
|
((3) 0 () 0 () () (c values c (c #t c #f c #t c #t)))
|
||||||
|
#""
|
||||||
|
#"")
|
||||||
|
((sql-bits->string (query-value pgc "select B'010110111'"))
|
||||||
|
((3) 0 () 0 () () (c values c (u . "010110111")))
|
||||||
|
#""
|
||||||
|
#"")
|
||||||
|
((sql-datetime->srfi-date (query-value pgc "select time '7:30'"))
|
||||||
|
((3)
|
||||||
|
1
|
||||||
|
(((lib "srfi/19/time.rkt") . deserialize-info:tm:date-v0))
|
||||||
|
0
|
||||||
|
()
|
||||||
|
()
|
||||||
|
(c values c (0 0 0 30 7 0 0 0 0)))
|
||||||
|
#""
|
||||||
|
#"")
|
||||||
|
((sql-datetime->srfi-date (query-value pgc "select date '25-dec-1980'"))
|
||||||
|
((3)
|
||||||
|
1
|
||||||
|
(((lib "srfi/19/time.rkt") . deserialize-info:tm:date-v0))
|
||||||
|
0
|
||||||
|
()
|
||||||
|
()
|
||||||
|
(c values c (0 0 0 0 0 25 12 1980 0)))
|
||||||
|
#""
|
||||||
|
#"")
|
||||||
|
((sql-datetime->srfi-date (query-value pgc "select timestamp 'epoch'"))
|
||||||
|
((3)
|
||||||
|
1
|
||||||
|
(((lib "srfi/19/time.rkt") . deserialize-info:tm:date-v0))
|
||||||
|
0
|
||||||
|
()
|
||||||
|
()
|
||||||
|
(c values c (0 0 0 0 0 1 1 1970 0)))
|
||||||
|
#""
|
||||||
|
#"")
|
|
@ -7,6 +7,12 @@
|
||||||
"tabbing.rkt"
|
"tabbing.rkt"
|
||||||
(for-label db db/util/geometry db/util/postgresql racket/dict))
|
(for-label db db/util/geometry db/util/postgresql racket/dict))
|
||||||
|
|
||||||
|
@;{ c - misc connection (alias to pgc)
|
||||||
|
myc - MySQL connection (???)
|
||||||
|
slc - SQLite connection (???)
|
||||||
|
}
|
||||||
|
@(the-eval '(define c pgc))
|
||||||
|
|
||||||
@title[#:tag "query-api"]{Queries}
|
@title[#:tag "query-api"]{Queries}
|
||||||
|
|
||||||
@declare-exporting[db db/base #:use-sources (db/base)]
|
@declare-exporting[db db/base #:use-sources (db/base)]
|
||||||
|
@ -126,11 +132,9 @@ The types of parameters and returned fields are described in
|
||||||
|
|
||||||
Executes a SQL statement for effect.
|
Executes a SQL statement for effect.
|
||||||
|
|
||||||
@examples/results[
|
@examples[#:eval the-eval
|
||||||
[(query-exec c "insert into some_table values (1, 'a')")
|
(query-exec pgc "insert into the_numbers values (42, 'the answer')")
|
||||||
(void)]
|
(query-exec pgc "delete from the_numbers where n = $1" 42)
|
||||||
[(query-exec pgc "delete from some_table where n = $1" 42)
|
|
||||||
(void)]
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -150,11 +154,9 @@ The types of parameters and returned fields are described in
|
||||||
Executes a SQL query, which must produce rows, and returns the list
|
Executes a SQL query, which must produce rows, and returns the list
|
||||||
of rows (as vectors) from the query.
|
of rows (as vectors) from the query.
|
||||||
|
|
||||||
@examples/results[
|
@examples[#:eval the-eval
|
||||||
[(query-rows pgc "select * from the_numbers where n = $1" 2)
|
(query-rows pgc "select * from the_numbers where n = $1" 2)
|
||||||
(list (vector 2 "company"))]
|
(query-rows c "select 17")
|
||||||
[(query-rows c "select 17")
|
|
||||||
(list (vector 17))]
|
|
||||||
]
|
]
|
||||||
|
|
||||||
If @racket[groupings] is not empty, the result is the same as if
|
If @racket[groupings] is not empty, the result is the same as if
|
||||||
|
@ -169,11 +171,9 @@ The types of parameters and returned fields are described in
|
||||||
Executes a SQL query, which must produce rows of exactly one
|
Executes a SQL query, which must produce rows of exactly one
|
||||||
column, and returns the list of values from the query.
|
column, and returns the list of values from the query.
|
||||||
|
|
||||||
@examples/results[
|
@examples[#:eval the-eval
|
||||||
[(query-list c "select n from the_numbers where n < 2")
|
(query-list c "select n from the_numbers where n < 2")
|
||||||
(list 0 1)]
|
(query-list c "select 'hello'")
|
||||||
[(query-list c "select 'hello'")
|
|
||||||
(list "hello")]
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -185,11 +185,9 @@ The types of parameters and returned fields are described in
|
||||||
Executes a SQL query, which must produce exactly one row, and
|
Executes a SQL query, which must produce exactly one row, and
|
||||||
returns its (single) row result as a vector.
|
returns its (single) row result as a vector.
|
||||||
|
|
||||||
@examples/results[
|
@examples[#:eval the-eval
|
||||||
[(query-row myc "select * from the_numbers where n = ?" 2)
|
(query-row pgc "select * from the_numbers where n = $1" 2)
|
||||||
(vector 2 "company")]
|
(query-row pgc "select min(n), max(n) from the_numbers")
|
||||||
[(query-row c "select 17")
|
|
||||||
(vector 17)]
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -201,11 +199,9 @@ The types of parameters and returned fields are described in
|
||||||
Like @racket[query-row], but the query may produce zero rows; in
|
Like @racket[query-row], but the query may produce zero rows; in
|
||||||
that case, @racket[#f] is returned.
|
that case, @racket[#f] is returned.
|
||||||
|
|
||||||
@examples/results[
|
@examples[#:eval the-eval
|
||||||
[(query-maybe-row pgc "select * from the_numbers where n = $1" 100)
|
(query-maybe-row pgc "select * from the_numbers where n = $1" 100)
|
||||||
#f]
|
(query-maybe-row c "select 17")
|
||||||
[(query-maybe-row c "select 17")
|
|
||||||
(vector 17)]
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -217,11 +213,9 @@ The types of parameters and returned fields are described in
|
||||||
Executes a SQL query, which must produce exactly one row of exactly
|
Executes a SQL query, which must produce exactly one row of exactly
|
||||||
one column, and returns its single value result.
|
one column, and returns its single value result.
|
||||||
|
|
||||||
@examples/results[
|
@examples[#:eval the-eval
|
||||||
[(query-value pgc "select timestamp 'epoch'")
|
(query-value pgc "select timestamp 'epoch'")
|
||||||
(sql-timestamp 1970 1 1 0 0 0 0 #f)]
|
(query-value pgc "select d from the_numbers where n = $1" 3)
|
||||||
[(query-value pgc "select s from the_numbers where n = $1" 3)
|
|
||||||
"a crowd"]
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -233,11 +227,9 @@ The types of parameters and returned fields are described in
|
||||||
Like @racket[query-value], but the query may produce zero rows; in
|
Like @racket[query-value], but the query may produce zero rows; in
|
||||||
that case, @racket[#f] is returned.
|
that case, @racket[#f] is returned.
|
||||||
|
|
||||||
@examples/results[
|
@examples[#:eval the-eval
|
||||||
[(query-value myc "select s from some_table where n = ?" 100)
|
(query-value pgc "select d from the_numbers where n = $1" 100)
|
||||||
#f]
|
(query-value c "select count(*) from the_numbers")
|
||||||
[(query-value c "select 17")
|
|
||||||
17]
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -272,18 +264,15 @@ The types of parameters and returned fields are described in
|
||||||
@racket[groupings] is not empty, then @racket[fetch-size] must
|
@racket[groupings] is not empty, then @racket[fetch-size] must
|
||||||
be @racket[+inf.0]; otherwise, an exception is raised.
|
be @racket[+inf.0]; otherwise, an exception is raised.
|
||||||
|
|
||||||
@examples/results[
|
@examples[#:eval the-eval
|
||||||
[(for/list ([n (in-query pgc "select n from the_numbers where n < 2")])
|
(for/list ([n (in-query pgc "select n from the_numbers where n < 2")])
|
||||||
n)
|
n)
|
||||||
'(0 1)]
|
(call-with-transaction pgc
|
||||||
[(call-with-transaction pgc
|
|
||||||
(lambda ()
|
(lambda ()
|
||||||
(for ([(n d)
|
(for ([(n d)
|
||||||
(in-query pgc "select * from the_numbers where n < $1" 4
|
(in-query pgc "select * from the_numbers where n < $1" 4
|
||||||
#:fetch 1)])
|
#:fetch 1)])
|
||||||
(printf "~a is ~a\n" n d))))
|
(printf "~a: ~a\n" n d))))
|
||||||
(for-each (lambda (n d) (printf "~a: ~a\n" n d))
|
|
||||||
'(0 1 2 3) '("nothing" "the loneliest number" "company" "a crowd"))]
|
|
||||||
]
|
]
|
||||||
|
|
||||||
An @racket[in-query] application can provide better performance when
|
An @racket[in-query] application can provide better performance when
|
||||||
|
@ -291,11 +280,9 @@ it appears directly in a @racket[for] clause. In addition, it may
|
||||||
perform stricter checks on the number of columns returned by the query
|
perform stricter checks on the number of columns returned by the query
|
||||||
based on the number of variables in the clause's left-hand side:
|
based on the number of variables in the clause's left-hand side:
|
||||||
|
|
||||||
@examples/results[
|
@examples[#:eval the-eval
|
||||||
[(for ([n (in-query pgc "select * from the_numbers")])
|
(for ([n (in-query pgc "select * from the_numbers")])
|
||||||
(displayln n))
|
(displayln n))
|
||||||
(error 'in-query "query returned 2 columns (expected 1): ~e"
|
|
||||||
"select * from the_numbers")]
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -490,8 +477,8 @@ closed.
|
||||||
but it must be used with the same connection that created
|
but it must be used with the same connection that created
|
||||||
@racket[pst].
|
@racket[pst].
|
||||||
|
|
||||||
@(examples/results
|
@examples[#:eval the-eval
|
||||||
[(let* ([get-name-pst
|
(let* ([get-name-pst
|
||||||
(prepare pgc "select d from the_numbers where n = $1")]
|
(prepare pgc "select d from the_numbers where n = $1")]
|
||||||
[get-name2
|
[get-name2
|
||||||
(bind-prepared-statement get-name-pst (list 2))]
|
(bind-prepared-statement get-name-pst (list 2))]
|
||||||
|
@ -499,7 +486,7 @@ closed.
|
||||||
(bind-prepared-statement get-name-pst (list 3))])
|
(bind-prepared-statement get-name-pst (list 3))])
|
||||||
(list (query-value pgc get-name2)
|
(list (query-value pgc get-name2)
|
||||||
(query-value pgc get-name3)))
|
(query-value pgc get-name3)))
|
||||||
(list "company" "a crowd")])
|
]
|
||||||
|
|
||||||
Most query functions perform the binding step implicitly.
|
Most query functions perform the binding step implicitly.
|
||||||
}
|
}
|
||||||
|
@ -526,19 +513,17 @@ closed.
|
||||||
function variant allows the SQL syntax to be dynamically customized
|
function variant allows the SQL syntax to be dynamically customized
|
||||||
for the database system in use.
|
for the database system in use.
|
||||||
|
|
||||||
@examples/results[
|
@examples[#:eval the-eval
|
||||||
[(define pst
|
(define pst
|
||||||
(virtual-statement
|
(virtual-statement
|
||||||
(lambda (dbsys)
|
(lambda (dbsys)
|
||||||
(case (dbsystem-name dbsys)
|
(case (dbsystem-name dbsys)
|
||||||
((postgresql) "select n from the_numbers where n < $1")
|
((postgresql) "select n from the_numbers where n < $1")
|
||||||
((sqlite3) "select n from the_numbers where n < ?")
|
((sqlite3) "select n from the_numbers where n < ?")
|
||||||
(else (error "unknown system"))))))
|
(else (error "unknown system"))))))
|
||||||
(void)]
|
(query-list pgc pst 3)
|
||||||
[(query-list pgc pst 3)
|
(eval:alts (query-list slc pst 3)
|
||||||
(list 1 2)]
|
(query-list pgc pst 3))
|
||||||
[(query-list slc pst 3)
|
|
||||||
(list 1 2)]
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -748,13 +733,9 @@ type.
|
||||||
@racket['message] key is typically present; its value is a string
|
@racket['message] key is typically present; its value is a string
|
||||||
containing the error message.
|
containing the error message.
|
||||||
|
|
||||||
@examples/results[
|
@examples[#:eval the-eval
|
||||||
[(with-handlers ([exn:fail:sql? exn:fail:sql-info])
|
(with-handlers ([exn:fail:sql? exn:fail:sql-info])
|
||||||
(query pgc "select * from nosuchtable"))
|
(query pgc "select * from nosuchtable"))
|
||||||
'((severity . "ERROR")
|
|
||||||
(code . "42P01")
|
|
||||||
(message . "relation \"nosuchtable\" does not exist")
|
|
||||||
...)]
|
|
||||||
]
|
]
|
||||||
|
|
||||||
Errors originating from the @racketmodname[db] library, such as
|
Errors originating from the @racketmodname[db] library, such as
|
||||||
|
|
|
@ -16,21 +16,19 @@ Connections automatically convert query results to appropriate Racket
|
||||||
types. Likewise, query parameters are accepted as Racket values and
|
types. Likewise, query parameters are accepted as Racket values and
|
||||||
converted to the appropriate SQL type.
|
converted to the appropriate SQL type.
|
||||||
|
|
||||||
@examples/results[
|
@examples[#:eval the-eval
|
||||||
[(query-value pgc "select count(*) from the_numbers") 4]
|
(query-value pgc "select count(*) from the_numbers")
|
||||||
[(query-value pgc "select false") (values #f)]
|
(query-value pgc "select false")
|
||||||
[(query-value pgc "select 1 + $1" 2) 3]
|
(query-value pgc "select 1 + $1" 2)
|
||||||
]
|
]
|
||||||
|
|
||||||
If a query result contains a column with a SQL type not supported by
|
If a query result contains a column with a SQL type not supported by
|
||||||
this library, an exception is raised. As a workaround, cast the column
|
this library, an exception is raised. As a workaround, cast the column
|
||||||
to a supported type:
|
to a supported type:
|
||||||
|
|
||||||
@examples/results[
|
@examples[#:eval the-eval
|
||||||
[(query-value pgc "select inet '127.0.0.1'")
|
(query-value pgc "select inet '127.0.0.1'")
|
||||||
(error 'query-value "unsupported type: inet (typeid 869)")]
|
(query-value pgc "select cast(inet '127.0.0.1' as varchar)")
|
||||||
[(query-value pgc "select cast(inet '127.0.0.1' as varchar)")
|
|
||||||
"127.0.0.1/32"]
|
|
||||||
]
|
]
|
||||||
|
|
||||||
The exception for unsupported types in result columns is raised when
|
The exception for unsupported types in result columns is raised when
|
||||||
|
@ -100,11 +98,9 @@ lower precision.) Other real values are converted to decimals with a
|
||||||
loss of precision. In PostgreSQL, @tt{numeric} and @tt{decimal} refer
|
loss of precision. In PostgreSQL, @tt{numeric} and @tt{decimal} refer
|
||||||
to the same type.
|
to the same type.
|
||||||
|
|
||||||
@examples/results[
|
@examples[#:eval the-eval
|
||||||
[(query-value pgc "select real '+Infinity'")
|
(query-value pgc "select real '+Infinity'")
|
||||||
+inf.0]
|
(query-value pgc "select numeric '12345678901234567890'")
|
||||||
[(query-value pgc "select numeric '12345678901234567890'")
|
|
||||||
12345678901234567890]
|
|
||||||
]
|
]
|
||||||
|
|
||||||
The geometric types such as @racket['point] are represented by
|
The geometric types such as @racket['point] are represented by
|
||||||
|
@ -128,11 +124,10 @@ the
|
||||||
@tt{= ANY}} syntax with an array parameter instead of dynamically
|
@tt{= ANY}} syntax with an array parameter instead of dynamically
|
||||||
constructing a SQL @tt{IN} expression:
|
constructing a SQL @tt{IN} expression:
|
||||||
|
|
||||||
@examples/results[
|
@examples[#:eval the-eval
|
||||||
[(query-value pgc "select 1 in (1, 2, 3)") #t]
|
(query-value pgc "select 1 in (1, 2, 3)")
|
||||||
[(query-value pgc "select 1 = any ($1::integer[])"
|
(query-value pgc "select 1 = any ($1::integer[])"
|
||||||
(list->pg-array (list 1 2 3)))
|
(list->pg-array (list 1 2 3)))
|
||||||
#t]
|
|
||||||
]
|
]
|
||||||
|
|
||||||
A list may be provided for an array parameter, in which case it is
|
A list may be provided for an array parameter, in which case it is
|
||||||
|
@ -140,15 +135,12 @@ automatically converted using @racket[list->pg-array]. The type
|
||||||
annotation can be dropped when the array type can be inferred from the
|
annotation can be dropped when the array type can be inferred from the
|
||||||
left-hand side.
|
left-hand side.
|
||||||
|
|
||||||
@examples/results[
|
@examples[#:eval the-eval
|
||||||
[(query-value pgc "select 1 = any ($1)" (list 1 2 3))
|
(query-value pgc "select 1 = any ($1)" (list 1 2 3))
|
||||||
#t]
|
(query-value pgc "select $1::integer = any ($2)"
|
||||||
[(query-value pgc "select $1::integer = any ($2)"
|
|
||||||
1 (list 1 2 3))
|
1 (list 1 2 3))
|
||||||
#t]
|
(query-value pgc "select $1 = any ($2)" (code:comment "what type are we using?")
|
||||||
[(query-value pgc "select $1 = any ($2)" (code:comment "what type are we using?")
|
|
||||||
1 (list 1 2 3))
|
1 (list 1 2 3))
|
||||||
(error 'query-value "cannot convert to PostgreSQL string type: 1")]
|
|
||||||
]
|
]
|
||||||
|
|
||||||
PostgreSQL defines many other types, such as network addresses and row
|
PostgreSQL defines many other types, such as network addresses and row
|
||||||
|
@ -247,7 +239,7 @@ strings, bytes, and real numbers.
|
||||||
An exact integer that cannot be represented as a 64-bit signed integer
|
An exact integer that cannot be represented as a 64-bit signed integer
|
||||||
is converted as @tt{real}, not @tt{integer}.
|
is converted as @tt{real}, not @tt{integer}.
|
||||||
|
|
||||||
@examples/results[
|
@fake-examples[
|
||||||
[(expt 2 80)
|
[(expt 2 80)
|
||||||
(expt 2 80)]
|
(expt 2 80)]
|
||||||
[(query-value slc "select ?" (expt 2 80))
|
[(query-value slc "select ?" (expt 2 80))
|
||||||
|
@ -326,9 +318,9 @@ SQL @tt{NULL} is translated into the unique @racket[sql-null] value.
|
||||||
results. The @racket[sql-null] value may be recognized using
|
results. The @racket[sql-null] value may be recognized using
|
||||||
@racket[eq?].
|
@racket[eq?].
|
||||||
|
|
||||||
@(examples/results
|
@examples[#:eval the-eval
|
||||||
[(query-value c "select NULL")
|
(query-value c "select NULL")
|
||||||
sql-null])
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
@defproc[(sql-null? [x any/c]) boolean?]{
|
@defproc[(sql-null? [x any/c]) boolean?]{
|
||||||
|
@ -410,25 +402,13 @@ values.
|
||||||
support nanosecond precision; PostgreSQL, for example, only supports
|
support nanosecond precision; PostgreSQL, for example, only supports
|
||||||
microsecond precision.
|
microsecond precision.
|
||||||
|
|
||||||
@(examples/results
|
@examples[#:eval the-eval
|
||||||
[(query-value pgc "select date '25-dec-1980'")
|
(query-value pgc "select date '25-dec-1980'")
|
||||||
(make-sql-date 1980 12 25)]
|
(query-value pgc "select time '7:30'")
|
||||||
[(query-value pgc "select time '7:30'")
|
(query-value pgc "select timestamp 'epoch'")
|
||||||
(make-sql-time 7 30 0 0 #f)]
|
(query-value pgc "select timestamp with time zone 'epoch'")
|
||||||
[(query-value pgc "select timestamp 'epoch'")
|
|
||||||
(make-sql-timestamp 1970 1 1 0 0 0 0 #f)]
|
|
||||||
[(query-value pgc "select timestamp with time zone 'epoch'")
|
|
||||||
(make-sql-timestamp 1969 12 31 19 0 0 0 -18000)])
|
|
||||||
}
|
|
||||||
|
|
||||||
@examples/results[
|
|
||||||
[(query-value myc "select date('1980-12-25')")
|
|
||||||
(make-sql-date 1980 12 25)]
|
|
||||||
[(query-value myc "select time('7:30')")
|
|
||||||
(make-sql-time 7 30 0 0 #f)]
|
|
||||||
[(query-value myc "select from_unixtime(0)")
|
|
||||||
(make-sql-timestamp 1969 12 31 19 0 0 0 #f)]
|
|
||||||
]
|
]
|
||||||
|
}
|
||||||
|
|
||||||
@defstruct*[sql-interval
|
@defstruct*[sql-interval
|
||||||
([years exact-integer?]
|
([years exact-integer?]
|
||||||
|
@ -550,10 +530,8 @@ represented by sql-bits values.
|
||||||
Converts a sql-bits value to or from its representation as a list or
|
Converts a sql-bits value to or from its representation as a list or
|
||||||
string.
|
string.
|
||||||
|
|
||||||
@examples/results[
|
@examples[#:eval the-eval
|
||||||
[(sql-bits->list (string->sql-bits "1011"))
|
(sql-bits->list (string->sql-bits "1011"))
|
||||||
(sql-bits->list (string->sql-bits "1011"))]
|
(sql-bits->string (query-value pgc "select B'010110111'"))
|
||||||
[(sql-bits->string (query-value pgc "select B'010110111'"))
|
|
||||||
(sql-bits->string (string->sql-bits "010110111"))]
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,40 +20,34 @@ database and perform simple queries. Some of the SQL syntax used below
|
||||||
is PostgreSQL-specific, such as the syntax of query parameters
|
is PostgreSQL-specific, such as the syntax of query parameters
|
||||||
(@litchar{$1} rather than @litchar{?}).
|
(@litchar{$1} rather than @litchar{?}).
|
||||||
|
|
||||||
@my-interaction[
|
@interaction[#:eval the-eval
|
||||||
[(require db)
|
(require db)
|
||||||
(void)]
|
|
||||||
]
|
]
|
||||||
|
|
||||||
First we create a connection. Replace @racket[_user], @racket[_db],
|
First we create a connection. Replace @racket[_user], @racket[_db],
|
||||||
and @racket[_password] below with the appropriate values for your
|
and @racket[_password] below with the appropriate values for your
|
||||||
configuration (see @secref{creating-connections} for other connection examples):
|
configuration (see @secref{creating-connections} for other connection examples):
|
||||||
|
|
||||||
@my-interaction[
|
@interaction[#:eval the-eval
|
||||||
[(define pgc
|
(eval:alts
|
||||||
|
(define pgc
|
||||||
(postgresql-connect #:user _user
|
(postgresql-connect #:user _user
|
||||||
#:database _db
|
#:database _db
|
||||||
#:password _password))
|
#:password _password))
|
||||||
(void)]
|
(define pgc (dsn-connect 'db-scribble-env)))
|
||||||
[pgc
|
|
||||||
(new connection%)]
|
|
||||||
]
|
]
|
||||||
|
|
||||||
Use @racket[query-exec] method to execute a SQL statement for effect.
|
Use @racket[query-exec] method to execute a SQL statement for effect.
|
||||||
|
|
||||||
@my-interaction[
|
@interaction[#:eval the-eval
|
||||||
[(query-exec pgc
|
(query-exec pgc
|
||||||
"create temporary table the_numbers (n integer, d varchar(20))")
|
"create temporary table the_numbers (n integer, d varchar(20))")
|
||||||
(void)]
|
(query-exec pgc
|
||||||
[(query-exec pgc
|
|
||||||
"insert into the_numbers values (0, 'nothing')")
|
"insert into the_numbers values (0, 'nothing')")
|
||||||
(void)]
|
(query-exec pgc
|
||||||
[(query-exec pgc
|
|
||||||
"insert into the_numbers values (1, 'the loneliest number')")
|
"insert into the_numbers values (1, 'the loneliest number')")
|
||||||
(void)]
|
(query-exec pgc
|
||||||
[(query-exec pgc
|
|
||||||
"insert into the_numbers values (2, 'company')")
|
"insert into the_numbers values (2, 'company')")
|
||||||
(void)]
|
|
||||||
]
|
]
|
||||||
|
|
||||||
The @racket[query] function is a more general way to execute a
|
The @racket[query] function is a more general way to execute a
|
||||||
|
@ -61,121 +55,95 @@ statement. It returns a structure encapsulating information about the
|
||||||
statement's execution. (But some of that information varies from
|
statement's execution. (But some of that information varies from
|
||||||
system to system and is subject to change.)
|
system to system and is subject to change.)
|
||||||
|
|
||||||
@my-interaction[
|
@interaction[#:eval the-eval
|
||||||
[(query pgc "insert into the_numbers values (3, 'a crowd')")
|
(query pgc "insert into the_numbers values (3, 'a crowd')")
|
||||||
(simple-result '((command insert 0 1)))]
|
(query pgc "select n, d from the_numbers where n % 2 = 0")
|
||||||
[(query pgc "select n, d from the_numbers where n % 2 = 0")
|
|
||||||
(rows-result
|
|
||||||
(list
|
|
||||||
'((name . "n") (typeid . 23))
|
|
||||||
'((name . "d") (typeid . 1043)))
|
|
||||||
'(#(0 "nothing") #(2 "company")))]
|
|
||||||
]
|
]
|
||||||
|
|
||||||
When the query is known to return rows and when the field
|
When the query is known to return rows and when the field
|
||||||
descriptions are not needed, it is more convenient to use the
|
descriptions are not needed, it is more convenient to use the
|
||||||
@racket[query-rows] function.
|
@racket[query-rows] function.
|
||||||
|
|
||||||
@my-interaction[
|
@interaction[#:eval the-eval
|
||||||
[(query-rows pgc "select n, d from the_numbers where n % 2 = 0")
|
(query-rows pgc "select n, d from the_numbers where n % 2 = 0")
|
||||||
'(#(0 "nothing") #(2 "company"))]
|
|
||||||
]
|
]
|
||||||
|
|
||||||
Use @racket[query-row] for queries that are known to return exactly
|
Use @racket[query-row] for queries that are known to return exactly
|
||||||
one row.
|
one row.
|
||||||
|
|
||||||
@my-interaction[
|
@interaction[#:eval the-eval
|
||||||
[(query-row pgc "select * from the_numbers where n = 0")
|
(query-row pgc "select * from the_numbers where n = 0")
|
||||||
(vector 0 "nothing")]
|
|
||||||
]
|
]
|
||||||
|
|
||||||
Similarly, use @racket[query-list] for queries that produce rows of
|
Similarly, use @racket[query-list] for queries that produce rows of
|
||||||
exactly one column.
|
exactly one column.
|
||||||
|
|
||||||
@my-interaction[
|
@interaction[#:eval the-eval
|
||||||
[(query-list pgc "select d from the_numbers order by n")
|
(query-list pgc "select d from the_numbers order by n")
|
||||||
(list "nothing" "the loneliest number" "company" "a crowd")]
|
|
||||||
]
|
]
|
||||||
|
|
||||||
When a query is known to return a single value (one row and one
|
When a query is known to return a single value (one row and one
|
||||||
column), use @racket[query-value].
|
column), use @racket[query-value].
|
||||||
|
|
||||||
@my-interaction[
|
@interaction[#:eval the-eval
|
||||||
[(query-value pgc "select count(*) from the_numbers")
|
(query-value pgc "select count(*) from the_numbers")
|
||||||
4]
|
(query-value pgc "select d from the_numbers where n = 5")
|
||||||
[(query-value pgc "select d from the_numbers where n = 5")
|
|
||||||
(error 'query-value
|
|
||||||
"query returned zero rows: ~s"
|
|
||||||
"select d from the_numbers where n = 5")]
|
|
||||||
]
|
]
|
||||||
|
|
||||||
When a query may return zero or one rows, as the last example, use
|
When a query may return zero or one rows, as the last example, use
|
||||||
@racket[query-maybe-row] or @racket[query-maybe-value] instead.
|
@racket[query-maybe-row] or @racket[query-maybe-value] instead.
|
||||||
|
|
||||||
@my-interaction[
|
@interaction[#:eval the-eval
|
||||||
[(query-maybe-value pgc "select d from the_numbers where n = 5")
|
(query-maybe-value pgc "select d from the_numbers where n = 5")
|
||||||
(values #f)]
|
|
||||||
]
|
]
|
||||||
|
|
||||||
The @racket[in-query] function produces a sequence that can be used
|
The @racket[in-query] function produces a sequence that can be used
|
||||||
with Racket's iteration forms:
|
with Racket's iteration forms:
|
||||||
|
|
||||||
@my-interaction[
|
@interaction[#:eval the-eval
|
||||||
[(for ([(n d) (in-query pgc "select * from the_numbers where n < 4")])
|
(for ([(n d) (in-query pgc "select * from the_numbers where n < 4")])
|
||||||
(printf "~a is ~a\n" n d))
|
(printf "~a: ~a\n" n d))
|
||||||
(for-each (lambda (n d) (printf "~a: ~a\n" n d))
|
(for/fold ([sum 0]) ([n (in-query pgc "select n from the_numbers")])
|
||||||
'(0 1 2 3)
|
|
||||||
'("nothing" "the loneliest number" "company" "a crowd"))]
|
|
||||||
[(for/fold ([sum 0]) ([n (in-query pgc "select n from the_numbers")])
|
|
||||||
(+ sum n))
|
(+ sum n))
|
||||||
(for/fold ([sum 0]) ([n (in-list '(0 1 2 3))])
|
|
||||||
(+ sum n))]
|
|
||||||
]
|
]
|
||||||
|
|
||||||
Errors in queries generally do not cause the connection to disconnect.
|
Errors in queries generally do not cause the connection to disconnect.
|
||||||
|
|
||||||
@my-interaction[
|
@interaction[#:eval the-eval
|
||||||
[(begin (with-handlers [(exn:fail?
|
(begin (with-handlers [(exn:fail?
|
||||||
(lambda (e)
|
(lambda (e)
|
||||||
(printf "~a~n" (exn-message e))))]
|
(printf "~a~n" (exn-message e))))]
|
||||||
(query-value pgc "select NoSuchField from NoSuchTable"))
|
(query-value pgc "select NoSuchField from NoSuchTable"))
|
||||||
(query-value pgc "select 'okay to proceed!'"))
|
(query-value pgc "select 'okay to proceed!'"))
|
||||||
(begin (display "query-value: relation \"nosuchtable\" does not exist (SQLSTATE 42P01)")
|
|
||||||
"okay to proceed!")]
|
|
||||||
]
|
]
|
||||||
|
|
||||||
Queries may contain parameters. The easiest way to execute a
|
Queries may contain parameters. The easiest way to execute a
|
||||||
parameterized query is to provide the parameters ``inline'' after the
|
parameterized query is to provide the parameters ``inline'' after the
|
||||||
SQL statement in the query function call.
|
SQL statement in the query function call.
|
||||||
|
|
||||||
@my-interaction[
|
@interaction[#:eval the-eval
|
||||||
[(query-value pgc
|
(query-value pgc
|
||||||
"select d from the_numbers where n = $1" 2)
|
"select d from the_numbers where n = $1" 2)
|
||||||
"company"]
|
(query-list pgc
|
||||||
[(query-list pgc
|
|
||||||
"select n from the_numbers where n > $1 and n < $2" 0 3)
|
"select n from the_numbers where n > $1 and n < $2" 0 3)
|
||||||
(list 1 2)]
|
|
||||||
]
|
]
|
||||||
|
|
||||||
Alternatively, a parameterized query may be prepared in advance and
|
Alternatively, a parameterized query may be prepared in advance and
|
||||||
executed later. @tech{Prepared statements} can be executed multiple
|
executed later. @tech{Prepared statements} can be executed multiple
|
||||||
times with different parameter values.
|
times with different parameter values.
|
||||||
|
|
||||||
@my-interaction[
|
@interaction[#:eval the-eval
|
||||||
[(define get-less-than-pst
|
(define get-less-than-pst
|
||||||
(prepare pgc "select n from the_numbers where n < $1"))
|
(prepare pgc "select n from the_numbers where n < $1"))
|
||||||
(void)]
|
(query-list pgc get-less-than-pst 1)
|
||||||
[(query-list pgc get-less-than-pst 1)
|
(query-list pgc (bind-prepared-statement get-less-than-pst '(2)))
|
||||||
(list 0)]
|
|
||||||
[(query-list pgc (bind-prepared-statement get-less-than-pst '(2)))
|
|
||||||
(list 0 1)]
|
|
||||||
]
|
]
|
||||||
|
|
||||||
When a connection's work is done, it should be disconnected.
|
When a connection's work is done, it should be disconnected.
|
||||||
|
|
||||||
@my-interaction[
|
@;{ Don't actually disconnect; use this connection for the rest of the examples. }
|
||||||
[(disconnect pgc)
|
@interaction[#:eval the-eval
|
||||||
(void)]
|
(eval:alts (disconnect pgc) (void))
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@ -480,32 +448,3 @@ web-server
|
||||||
By using a virtual connection backed by a connection pool, a servlet
|
By using a virtual connection backed by a connection pool, a servlet
|
||||||
can achieve simplicity, isolation, and performance all at the same
|
can achieve simplicity, isolation, and performance all at the same
|
||||||
time.
|
time.
|
||||||
|
|
||||||
@;{
|
|
||||||
|
|
||||||
TODO:
|
|
||||||
- talk about virtual statements, too
|
|
||||||
- show actual working servlet code
|
|
||||||
|
|
||||||
--
|
|
||||||
|
|
||||||
A prepared statement is tied to the connection used to create it;
|
|
||||||
attempting to use it with another connection results in an
|
|
||||||
error. Unfortunately, in some scenarios such as web servlets, the
|
|
||||||
lifetimes of connections are short or difficult to track, making
|
|
||||||
prepared statements inconvenient. In such cases, a better tool is the
|
|
||||||
@tech{virtual statement}, which prepares statements on demand and
|
|
||||||
caches them for future use with the same connection.
|
|
||||||
|
|
||||||
@my-interaction[
|
|
||||||
[(define get-less-than-pst
|
|
||||||
(virtual-statement "select n from the_numbers where n < $1"))
|
|
||||||
(void)]
|
|
||||||
[(code:line (query-list pgc1 get-less-than-pst 1) (code:comment "prepares statement for pgc1"))
|
|
||||||
(list 0)]
|
|
||||||
[(code:line (query-list pgc2 get-less-than-pst 2) (code:comment "prepares statement for pgc2"))
|
|
||||||
(list 0 1)]
|
|
||||||
[(code:line (query-list pgc1 get-less-than-pst 3) (code:comment "uses existing prep. stmt."))
|
|
||||||
(list 0 1 2)]
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
|
@ -37,17 +37,14 @@ modules below, not by @racketmodname[db] or @racketmodname[db/base].
|
||||||
SRFI date, for example, puts zeroes in the year, month, and day
|
SRFI date, for example, puts zeroes in the year, month, and day
|
||||||
fields.
|
fields.
|
||||||
|
|
||||||
@(examples/results
|
@examples[#:eval the-eval
|
||||||
[(sql-datetime->srfi-date
|
(sql-datetime->srfi-date
|
||||||
(query-value pgc "select time '7:30'"))
|
(query-value pgc "select time '7:30'"))
|
||||||
(sql-datetime->srfi-date (make-sql-time 7 30 0 0 #f))]
|
(sql-datetime->srfi-date
|
||||||
[(sql-datetime->srfi-date
|
|
||||||
(query-value pgc "select date '25-dec-1980'"))
|
(query-value pgc "select date '25-dec-1980'"))
|
||||||
(sql-datetime->srfi-date
|
(sql-datetime->srfi-date
|
||||||
(make-sql-date 1980 12 25))]
|
|
||||||
[(sql-datetime->srfi-date
|
|
||||||
(query-value pgc "select timestamp 'epoch'"))
|
(query-value pgc "select timestamp 'epoch'"))
|
||||||
(sql-datetime->srfi-date (make-sql-timestamp 1970 1 1 0 0 0 0 #f))])
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
@defproc[(sql-day-time-interval->seconds [interval sql-day-time-interval?])
|
@defproc[(sql-day-time-interval->seconds [interval sql-day-time-interval?])
|
||||||
|
|
Loading…
Reference in New Issue
Block a user