factor/basis/db/postgresql/postgresql.factor

294 lines
8.5 KiB
Factor
Raw Normal View History

! Copyright (C) 2007, 2008 Doug Coleman.
2008-02-01 18:43:44 -05:00
! See http://factorcode.org/license.txt for BSD license.
USING: arrays assocs alien alien.syntax continuations io
2008-09-10 23:11:40 -04:00
kernel math math.parser namespaces make prettyprint quotations
sequences debugger db db.postgresql.lib db.postgresql.ffi
db.tuples db.types tools.annotations math.ranges
combinators classes locals words tools.walker db.private
2009-02-20 23:59:01 -05:00
nmake accessors random db.queries destructors db.tuples.private
db.postgresql db.errors.postgresql splitting ;
2008-02-01 18:43:44 -05:00
IN: db.postgresql
TUPLE: postgresql-db host port pgopts pgtty database username password ;
: <postgresql-db> ( -- postgresql-db )
postgresql-db new ;
<PRIVATE
TUPLE: postgresql-db-connection < db-connection ;
: <postgresql-db-connection> ( handle -- db-connection )
postgresql-db-connection new-db-connection
swap >>handle ;
PRIVATE>
2008-04-05 21:22:33 -04:00
TUPLE: postgresql-statement < statement ;
2008-04-05 21:22:33 -04:00
TUPLE: postgresql-result-set < result-set ;
M: postgresql-db db-open ( db -- db-connection )
{
2008-04-05 21:22:33 -04:00
[ host>> ]
[ port>> ]
[ pgopts>> ]
[ pgtty>> ]
[ database>> ]
[ username>> ]
[ password>> ]
} cleave connect-postgres <postgresql-db-connection> ;
2008-02-01 18:43:44 -05:00
2008-12-17 22:04:17 -05:00
M: postgresql-db-connection db-close ( handle -- ) PQfinish ;
2008-02-01 18:43:44 -05:00
2008-09-27 15:07:39 -04:00
M: postgresql-statement bind-statement* ( statement -- ) drop ;
2008-02-01 18:43:44 -05:00
2008-09-09 20:06:47 -04:00
GENERIC: postgresql-bind-conversion ( tuple object -- low-level-binding )
2008-09-09 20:06:47 -04:00
M: sql-spec postgresql-bind-conversion ( tuple spec -- object )
2008-04-21 14:11:19 -04:00
slot-name>> swap get-slot-named <low-level-binding> ;
2008-09-09 20:06:47 -04:00
M: literal-bind postgresql-bind-conversion ( tuple literal-bind -- object )
2008-04-21 14:11:19 -04:00
nip value>> <low-level-binding> ;
2008-09-09 20:06:47 -04:00
M: generator-bind postgresql-bind-conversion ( tuple generate-bind -- object )
2008-04-28 18:17:19 -04:00
dup generator-singleton>> eval-generator
[ swap slot-name>> rot set-slot-named ] [ <low-level-binding> ] bi ;
M: postgresql-statement bind-tuple ( tuple statement -- )
2009-01-23 19:20:47 -05:00
[ nip ] [
in-params>>
[ postgresql-bind-conversion ] with map
] 2bi
2008-04-20 00:18:12 -04:00
>>bind-params drop ;
M: postgresql-result-set #rows ( result-set -- n )
2008-04-05 21:22:33 -04:00
handle>> PQntuples ;
2008-02-01 18:43:44 -05:00
M: postgresql-result-set #columns ( result-set -- n )
2008-04-05 21:22:33 -04:00
handle>> PQnfields ;
2008-02-01 18:43:44 -05:00
2008-04-20 00:48:07 -04:00
: result-handle-n ( result-set -- handle n )
[ handle>> ] [ n>> ] bi ;
2008-09-09 20:06:47 -04:00
M: postgresql-result-set row-column ( result-set column -- object )
2008-09-27 15:07:39 -04:00
[ result-handle-n ] dip pq-get-string ;
2008-09-09 20:06:47 -04:00
M: postgresql-result-set row-column-typed ( result-set column -- object )
2008-04-20 00:41:48 -04:00
dup pick out-params>> nth type>>
2008-09-27 15:07:39 -04:00
[ result-handle-n ] 2dip postgresql-column-typed ;
M: postgresql-statement query-results ( query -- result-set )
2008-04-20 00:41:48 -04:00
dup bind-params>> [
over [ bind-statement ] keep
do-postgresql-bound-statement
] [
dup do-postgresql-statement
] if*
postgresql-result-set new-result-set
dup init-result-set ;
M: postgresql-result-set advance-row ( result-set -- )
2008-04-20 00:41:48 -04:00
[ 1+ ] change-n drop ;
M: postgresql-result-set more-rows? ( result-set -- ? )
2008-04-20 00:41:48 -04:00
[ n>> ] [ max>> ] bi < ;
2008-02-01 18:43:44 -05:00
M: postgresql-statement dispose ( query -- )
2008-04-20 00:41:48 -04:00
dup handle>> PQclear
f >>handle drop ;
M: postgresql-result-set dispose ( result-set -- )
2008-04-20 00:41:48 -04:00
[ handle>> PQclear ]
[
0 >>n
0 >>max
f >>handle drop
] bi ;
2008-02-01 18:43:44 -05:00
M: postgresql-statement prepare-statement ( statement -- )
2008-04-20 00:41:48 -04:00
dup
2008-12-17 22:04:17 -05:00
[ db-connection get handle>> f ] dip
2008-04-20 00:41:48 -04:00
[ sql>> ] [ in-params>> ] bi
length f PQprepare postgresql-error
>>handle drop ;
2008-02-01 18:43:44 -05:00
M: postgresql-db-connection <simple-statement> ( sql in out -- statement )
postgresql-statement new-statement ;
2008-02-01 18:43:44 -05:00
M: postgresql-db-connection <prepared-statement> ( sql in out -- statement )
2008-04-20 18:47:43 -04:00
<simple-statement> dup prepare-statement ;
: bind-name% ( -- )
CHAR: $ 0,
2008-04-20 18:50:39 -04:00
sql-counter [ inc ] [ get 0# ] bi ;
M: postgresql-db-connection bind% ( spec -- )
2008-04-20 00:18:12 -04:00
bind-name% 1, ;
M: postgresql-db-connection bind# ( spec object -- )
[ bind-name% f swap type>> ] dip
<literal-bind> 1, ;
: create-table-sql ( class -- statement )
[
2008-09-27 15:07:39 -04:00
dupd
"create table " 0% 0%
2008-04-20 00:18:12 -04:00
"(" 0% [ ", " 0% ] [
dup column-name>> 0%
" " 0%
2008-04-20 16:48:09 -04:00
dup type>> lookup-create-type 0%
modifiers 0%
2008-09-27 15:07:39 -04:00
] interleave
", " 0%
find-primary-key
"primary key(" 0%
[ "," 0% ] [ column-name>> 0% ] interleave
"));" 0%
2008-04-20 18:47:43 -04:00
] query-make ;
: create-function-sql ( class -- statement )
[
[ dup remove-id ] dip
"create function add_" 0% dup 0%
"(" 0%
over [ "," 0% ]
[
2008-04-20 16:48:09 -04:00
type>> lookup-type 0%
] interleave
")" 0%
" returns bigint as '" 0%
"insert into " 0%
dup 0%
"(" 0%
2008-04-20 00:41:48 -04:00
over [ ", " 0% ] [ column-name>> 0% ] interleave
") values(" 0%
swap [ ", " 0% ] [ drop bind-name% ] interleave
"); " 0%
"select currval(''" 0% 0% "_" 0%
find-primary-key first column-name>> 0%
"_seq'');' language sql;" 0%
2008-04-20 18:47:43 -04:00
] query-make ;
M: postgresql-db-connection create-sql-statement ( class -- seq )
[
[ create-table-sql , ] keep
2008-09-27 15:07:39 -04:00
dup db-assigned? [ create-function-sql , ] [ drop ] if
] { } make ;
: drop-function-sql ( class -- statement )
[
"drop function add_" 0% 0%
"(" 0%
remove-id
2008-04-20 16:48:09 -04:00
[ ", " 0% ] [ type>> lookup-type 0% ] interleave
");" 0%
2008-04-20 18:47:43 -04:00
] query-make ;
: drop-table-sql ( table -- statement )
[
"drop table " 0% 0% drop
2008-04-20 18:47:43 -04:00
] query-make ;
M: postgresql-db-connection drop-sql-statement ( class -- seq )
[
[ drop-table-sql , ] keep
2008-09-27 15:07:39 -04:00
dup db-assigned? [ drop-function-sql , ] [ drop ] if
] { } make ;
M: postgresql-db-connection <insert-db-assigned-statement> ( class -- statement )
[
"select add_" 0% 0%
"(" 0%
2008-09-27 15:07:39 -04:00
dup find-primary-key first 2,
remove-id
[ ", " 0% ] [ bind% ] interleave
");" 0%
2008-04-20 18:47:43 -04:00
] query-make ;
M: postgresql-db-connection <insert-user-assigned-statement> ( class -- statement )
[
"insert into " 0% 0%
"(" 0%
2008-04-20 00:41:48 -04:00
dup [ ", " 0% ] [ column-name>> 0% ] interleave
")" 0%
" values(" 0%
2008-04-21 14:11:19 -04:00
[ ", " 0% ] [
dup type>> +random-id+ = [
[
2008-04-28 18:17:19 -04:00
bind-name%
slot-name>>
f
random-id-generator
2008-04-21 14:11:19 -04:00
] [ type>> ] bi <generator-bind> 1,
] [
bind%
] if
] interleave
");" 0%
2008-04-20 18:47:43 -04:00
] query-make ;
M: postgresql-db-connection insert-tuple-set-key ( tuple statement -- )
query-modify-tuple ;
M: postgresql-db-connection persistent-table ( -- hashtable )
H{
2008-09-27 15:07:39 -04:00
{ +db-assigned-id+ { "integer" "serial" f } }
{ +user-assigned-id+ { f f f } }
{ +random-id+ { "bigint" "bigint" f } }
2008-09-27 16:56:43 -04:00
2008-09-27 17:26:21 -04:00
{ +foreign-id+ { f f "references" } }
2008-10-10 16:32:36 -04:00
{ +on-update+ { f f "on update" } }
2008-09-27 16:56:43 -04:00
{ +on-delete+ { f f "on delete" } }
{ +restrict+ { f f "restrict" } }
{ +cascade+ { f f "cascade" } }
{ +set-null+ { f f "set null" } }
{ +set-default+ { f f "set default" } }
{ TEXT { "text" "text" f } }
2008-04-20 16:48:09 -04:00
{ VARCHAR { "varchar" "varchar" f } }
{ INTEGER { "integer" "integer" f } }
{ BIG-INTEGER { "bigint" "bigint" f } }
{ UNSIGNED-BIG-INTEGER { "bigint" "bigint" f } }
{ SIGNED-BIG-INTEGER { "bigint" "bigint" f } }
{ DOUBLE { "real" "real" f } }
{ DATE { "date" "date" f } }
{ TIME { "time" "time" f } }
{ DATETIME { "timestamp" "timestamp" f } }
{ TIMESTAMP { "timestamp" "timestamp" f } }
{ BLOB { "bytea" "bytea" f } }
{ FACTOR-BLOB { "bytea" "bytea" f } }
{ URL { "varchar" "varchar" f } }
2008-04-20 16:48:09 -04:00
{ +autoincrement+ { f f "autoincrement" } }
{ +unique+ { f f "unique" } }
{ +default+ { f f "default" } }
{ +null+ { f f "null" } }
{ +not-null+ { f f "not null" } }
{ system-random-generator { f f f } }
{ secure-random-generator { f f f } }
{ random-generator { f f f } }
} ;
2008-09-09 20:06:47 -04:00
ERROR: no-compound-found string object ;
M: postgresql-db-connection compound ( string object -- string' )
over {
2008-12-04 01:06:02 -05:00
{ "default" [ first number>string " " glue ] }
2008-12-04 03:21:36 -05:00
{ "varchar" [ first number>string "(" ")" surround append ] }
2008-09-27 17:26:21 -04:00
{ "references" [ >reference-string ] }
2008-09-09 20:06:47 -04:00
[ drop no-compound-found ]
} case ;
2009-02-20 23:59:01 -05:00
M: postgresql-db-connection parse-db-error
"\n" split dup length {
{ 1 [ first parse-postgresql-sql-error ] }
{ 3 [
first3
[ parse-postgresql-sql-error ] 2dip
postgresql-location >>location
] }
} case ;