175 lines
5.6 KiB
Factor
175 lines
5.6 KiB
Factor
! Copyright (C) 2008 Doug Coleman.
|
|
! See http://factorcode.org/license.txt for BSD license.
|
|
USING: arrays continuations db io kernel math namespaces
|
|
quotations sequences db.postgresql.ffi alien alien.c-types
|
|
db.types tools.walker ascii splitting math.parser combinators
|
|
libc calendar.format byte-arrays destructors prettyprint
|
|
accessors strings serialize io.encodings.binary io.encodings.utf8
|
|
alien.strings io.streams.byte-array summary present urls
|
|
specialized-arrays.uint specialized-arrays.alien db.private ;
|
|
IN: db.postgresql.lib
|
|
|
|
: postgresql-result-error-message ( res -- str/f )
|
|
dup zero? [
|
|
drop f
|
|
] [
|
|
PQresultErrorMessage [ blank? ] trim
|
|
] if ;
|
|
|
|
: postgres-result-error ( res -- )
|
|
postgresql-result-error-message [ throw ] when* ;
|
|
|
|
: (postgresql-error-message) ( handle -- str )
|
|
PQerrorMessage
|
|
"\n" split [ [ blank? ] trim ] map "\n" join ;
|
|
|
|
: postgresql-error-message ( -- str )
|
|
db-connection get handle>> (postgresql-error-message) ;
|
|
|
|
: postgresql-error ( res -- res )
|
|
dup [ postgresql-error-message throw ] unless ;
|
|
|
|
ERROR: postgresql-result-null ;
|
|
|
|
M: postgresql-result-null summary ( obj -- str )
|
|
drop "PQexec returned f." ;
|
|
|
|
: postgresql-result-ok? ( res -- ? )
|
|
[ postgresql-result-null ] unless*
|
|
PQresultStatus
|
|
PGRES_COMMAND_OK PGRES_TUPLES_OK 2array member? ;
|
|
|
|
: connect-postgres ( host port pgopts pgtty db user pass -- conn )
|
|
PQsetdbLogin
|
|
dup PQstatus zero? [ (postgresql-error-message) throw ] unless ;
|
|
|
|
: do-postgresql-statement ( statement -- res )
|
|
db-connection get handle>> swap sql>> PQexec dup postgresql-result-ok? [
|
|
[ postgresql-result-error-message ] [ PQclear ] bi throw
|
|
] unless ;
|
|
|
|
: type>oid ( symbol -- n )
|
|
dup array? [ first ] when
|
|
{
|
|
{ BLOB [ BYTEA-OID ] }
|
|
{ FACTOR-BLOB [ BYTEA-OID ] }
|
|
[ drop 0 ]
|
|
} case ;
|
|
|
|
: type>param-format ( symbol -- n )
|
|
dup array? [ first ] when
|
|
{
|
|
{ BLOB [ 1 ] }
|
|
{ FACTOR-BLOB [ 1 ] }
|
|
[ drop 0 ]
|
|
} case ;
|
|
|
|
: param-types ( statement -- seq )
|
|
in-params>> [ type>> type>oid ] uint-array{ } map-as ;
|
|
|
|
: malloc-byte-array/length ( byte-array -- alien length )
|
|
[ malloc-byte-array &free ] [ length ] bi ;
|
|
|
|
: default-param-value ( obj -- alien n )
|
|
number>string* dup [ utf8 malloc-string &free ] when 0 ;
|
|
|
|
: param-values ( statement -- seq seq2 )
|
|
[ bind-params>> ] [ in-params>> ] bi
|
|
[
|
|
[ value>> ] [ type>> ] bi* {
|
|
{ FACTOR-BLOB [
|
|
dup [ object>bytes malloc-byte-array/length ] [ 0 ] if
|
|
] }
|
|
{ BLOB [ dup [ malloc-byte-array/length ] [ 0 ] if ] }
|
|
{ DATE [ dup [ timestamp>ymd ] when default-param-value ] }
|
|
{ TIME [ dup [ timestamp>hms ] when default-param-value ] }
|
|
{ DATETIME [ dup [ timestamp>ymdhms ] when default-param-value ] }
|
|
{ TIMESTAMP [ dup [ timestamp>ymdhms ] when default-param-value ] }
|
|
{ URL [ dup [ present ] when default-param-value ] }
|
|
[ drop default-param-value ]
|
|
} case 2array
|
|
] 2map flip [
|
|
f f
|
|
] [
|
|
first2 [ >void*-array ] [ >uint-array ] bi*
|
|
] if-empty ;
|
|
|
|
: param-formats ( statement -- seq )
|
|
in-params>> [ type>> type>param-format ] uint-array{ } map-as ;
|
|
|
|
: do-postgresql-bound-statement ( statement -- res )
|
|
[
|
|
[ db-connection get handle>> ] dip
|
|
{
|
|
[ sql>> ]
|
|
[ bind-params>> length ]
|
|
[ param-types ]
|
|
[ param-values ]
|
|
[ param-formats ]
|
|
} cleave
|
|
0 PQexecParams dup postgresql-result-ok? [
|
|
[ postgresql-result-error-message ] [ PQclear ] bi throw
|
|
] unless
|
|
] with-destructors ;
|
|
|
|
: pq-get-is-null ( handle row column -- ? )
|
|
PQgetisnull 1 = ;
|
|
|
|
: pq-get-string ( handle row column -- obj )
|
|
3dup PQgetvalue utf8 alien>string
|
|
dup empty? [ [ pq-get-is-null f ] dip ? ] [ [ 3drop ] dip ] if ;
|
|
|
|
: pq-get-number ( handle row column -- obj )
|
|
pq-get-string dup [ string>number ] when ;
|
|
|
|
TUPLE: postgresql-malloc-destructor alien ;
|
|
C: <postgresql-malloc-destructor> postgresql-malloc-destructor
|
|
|
|
M: postgresql-malloc-destructor dispose ( obj -- )
|
|
alien>> PQfreemem ;
|
|
|
|
: &postgresql-free ( alien -- alien )
|
|
dup <postgresql-malloc-destructor> &dispose drop ; inline
|
|
|
|
: pq-get-blob ( handle row column -- obj/f )
|
|
[ PQgetvalue ] 3keep 3dup PQgetlength
|
|
dup 0 > [
|
|
[ 3drop ] dip
|
|
[
|
|
memory>byte-array >string
|
|
0 <uint>
|
|
[
|
|
PQunescapeBytea dup zero? [
|
|
postgresql-result-error-message throw
|
|
] [
|
|
&postgresql-free
|
|
] if
|
|
] keep
|
|
*uint memory>byte-array
|
|
] with-destructors
|
|
] [
|
|
drop pq-get-is-null nip [ f ] [ B{ } clone ] if
|
|
] if ;
|
|
|
|
: postgresql-column-typed ( handle row column type -- obj )
|
|
dup array? [ first ] when
|
|
{
|
|
{ +db-assigned-id+ [ pq-get-number ] }
|
|
{ +random-id+ [ pq-get-number ] }
|
|
{ INTEGER [ pq-get-number ] }
|
|
{ BIG-INTEGER [ pq-get-number ] }
|
|
{ DOUBLE [ pq-get-number ] }
|
|
{ TEXT [ pq-get-string ] }
|
|
{ VARCHAR [ pq-get-string ] }
|
|
{ DATE [ pq-get-string dup [ ymd>timestamp ] when ] }
|
|
{ TIME [ pq-get-string dup [ hms>timestamp ] when ] }
|
|
{ TIMESTAMP [ pq-get-string dup [ ymdhms>timestamp ] when ] }
|
|
{ DATETIME [ pq-get-string dup [ ymdhms>timestamp ] when ] }
|
|
{ BLOB [ pq-get-blob ] }
|
|
{ URL [ pq-get-string dup [ >url ] when ] }
|
|
{ FACTOR-BLOB [
|
|
pq-get-blob
|
|
dup [ bytes>object ] when ] }
|
|
[ no-sql-type ]
|
|
} case ;
|