1 ! Copyright (C) 2008 Doug Coleman.
2 ! See http://factorcode.org/license.txt for BSD license.
3 USING: arrays continuations db io kernel math namespaces
4 quotations sequences db.postgresql.ffi alien alien.c-types
5 db.types tools.walker ascii splitting math.parser combinators
6 libc shuffle calendar.format byte-arrays destructors prettyprint
7 accessors strings serialize io.encodings.binary io.encodings.utf8
8 alien.strings io.streams.byte-array summary present urls
9 specialized-arrays.uint specialized-arrays.alien ;
12 : postgresql-result-error-message ( res -- str/f )
16 PQresultErrorMessage [ blank? ] trim
19 : postgres-result-error ( res -- )
20 postgresql-result-error-message [ throw ] when* ;
22 : (postgresql-error-message) ( handle -- str )
24 "\n" split [ [ blank? ] trim ] map "\n" join ;
26 : postgresql-error-message ( -- str )
27 db get handle>> (postgresql-error-message) ;
29 : postgresql-error ( res -- res )
30 dup [ postgresql-error-message throw ] unless ;
32 ERROR: postgresql-result-null ;
34 M: postgresql-result-null summary ( obj -- str )
35 drop "PQexec returned f." ;
37 : postgresql-result-ok? ( res -- ? )
38 [ postgresql-result-null ] unless*
40 PGRES_COMMAND_OK PGRES_TUPLES_OK 2array member? ;
42 : connect-postgres ( host port pgopts pgtty db user pass -- conn )
44 dup PQstatus zero? [ (postgresql-error-message) throw ] unless ;
46 : do-postgresql-statement ( statement -- res )
47 db get handle>> swap sql>> PQexec dup postgresql-result-ok? [
48 [ postgresql-result-error-message ] [ PQclear ] bi throw
51 : type>oid ( symbol -- n )
52 dup array? [ first ] when
54 { BLOB [ BYTEA-OID ] }
55 { FACTOR-BLOB [ BYTEA-OID ] }
59 : type>param-format ( symbol -- n )
60 dup array? [ first ] when
67 : param-types ( statement -- seq )
68 in-params>> [ type>> type>oid ] uint-array{ } map-as underlying>> ;
70 : malloc-byte-array/length ( byte-array -- alien length )
71 [ malloc-byte-array &free ] [ length ] bi ;
73 : default-param-value ( obj -- alien n )
74 number>string* dup [ utf8 malloc-string &free ] when 0 ;
76 : param-values ( statement -- seq seq2 )
77 [ bind-params>> ] [ in-params>> ] bi
79 [ value>> ] [ type>> ] bi* {
81 dup [ object>bytes malloc-byte-array/length ] [ 0 ] if
83 { BLOB [ dup [ malloc-byte-array/length ] [ 0 ] if ] }
84 { DATE [ dup [ timestamp>ymd ] when default-param-value ] }
85 { TIME [ dup [ timestamp>hms ] when default-param-value ] }
86 { DATETIME [ dup [ timestamp>ymdhms ] when default-param-value ] }
87 { TIMESTAMP [ dup [ timestamp>ymdhms ] when default-param-value ] }
88 { URL [ dup [ present ] when default-param-value ] }
89 [ drop default-param-value ]
94 first2 [ >void*-array underlying>> ] [ >uint-array underlying>> ] bi*
97 : param-formats ( statement -- seq )
98 in-params>> [ type>> type>param-format ] uint-array{ } map-as underlying>> ;
100 : do-postgresql-bound-statement ( statement -- res )
102 [ db get handle>> ] dip
105 [ bind-params>> length ]
110 0 PQexecParams dup postgresql-result-ok? [
111 [ postgresql-result-error-message ] [ PQclear ] bi throw
115 : pq-get-is-null ( handle row column -- ? )
118 : pq-get-string ( handle row column -- obj )
119 3dup PQgetvalue utf8 alien>string
120 dup empty? [ [ pq-get-is-null f ] dip ? ] [ 3nip ] if ;
122 : pq-get-number ( handle row column -- obj )
123 pq-get-string dup [ string>number ] when ;
125 TUPLE: postgresql-malloc-destructor alien ;
126 C: <postgresql-malloc-destructor> postgresql-malloc-destructor
128 M: postgresql-malloc-destructor dispose ( obj -- )
131 : &postgresql-free ( alien -- alien )
132 dup <postgresql-malloc-destructor> &dispose drop ; inline
134 : pq-get-blob ( handle row column -- obj/f )
135 [ PQgetvalue ] 3keep 3dup PQgetlength
139 memory>byte-array >string
142 PQunescapeBytea dup zero? [
143 postgresql-result-error-message throw
148 *uint memory>byte-array
151 drop pq-get-is-null nip [ f ] [ B{ } clone ] if
154 : postgresql-column-typed ( handle row column type -- obj )
155 dup array? [ first ] when
157 { +db-assigned-id+ [ pq-get-number ] }
158 { +random-id+ [ pq-get-number ] }
159 { INTEGER [ pq-get-number ] }
160 { BIG-INTEGER [ pq-get-number ] }
161 { DOUBLE [ pq-get-number ] }
162 { TEXT [ pq-get-string ] }
163 { VARCHAR [ pq-get-string ] }
164 { DATE [ pq-get-string dup [ ymd>timestamp ] when ] }
165 { TIME [ pq-get-string dup [ hms>timestamp ] when ] }
166 { TIMESTAMP [ pq-get-string dup [ ymdhms>timestamp ] when ] }
167 { DATETIME [ pq-get-string dup [ ymdhms>timestamp ] when ] }
168 { BLOB [ pq-get-blob ] }
169 { URL [ pq-get-string dup [ >url ] when ] }
172 dup [ bytes>object ] when ] }