From defc1cfae97329b0aade66049093235a32485601 Mon Sep 17 00:00:00 2001 From: Doug Coleman <doug.coleman@gmail.com> Date: Tue, 15 Apr 2008 21:55:26 -0500 Subject: [PATCH 01/20] fix sql --- extra/db/sql/sql-tests.factor | 2 +- extra/db/sql/sql.factor | 34 +++++++++++++++++----------------- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/extra/db/sql/sql-tests.factor b/extra/db/sql/sql-tests.factor index 488026fcc7..db69d71a84 100644 --- a/extra/db/sql/sql-tests.factor +++ b/extra/db/sql/sql-tests.factor @@ -28,7 +28,7 @@ TUPLE: person name age ; { select { columns "salary" } { from "staff" } - { where { "branchno" "b003" } } + { where { "branchno" = "b003" } } } } { "branchno" > 3 } } diff --git a/extra/db/sql/sql.factor b/extra/db/sql/sql.factor index 26e8429efd..b0ec7aaf34 100755 --- a/extra/db/sql/sql.factor +++ b/extra/db/sql/sql.factor @@ -27,23 +27,23 @@ DEFER: sql% : sql-array% ( array -- ) unclip { - { columns [ "," (sql-interleave) ] } - { from [ "from" "," sql-interleave ] } - { where [ "where" "and" sql-interleave ] } - { group-by [ "group by" "," sql-interleave ] } - { having [ "having" "," sql-interleave ] } - { order-by [ "order by" "," sql-interleave ] } - { offset [ "offset" sql% sql% ] } - { limit [ "limit" sql% sql% ] } - { select [ "(select" sql% sql% ")" sql% ] } - { table [ sql% ] } - { set [ "set" "," sql-interleave ] } - { values [ "values(" sql% "," (sql-interleave) ")" sql% ] } - { count [ "count" sql-function, ] } - { sum [ "sum" sql-function, ] } - { avg [ "avg" sql-function, ] } - { min [ "min" sql-function, ] } - { max [ "max" sql-function, ] } + { \ columns [ "," (sql-interleave) ] } + { \ from [ "from" "," sql-interleave ] } + { \ where [ "where" "and" sql-interleave ] } + { \ group-by [ "group by" "," sql-interleave ] } + { \ having [ "having" "," sql-interleave ] } + { \ order-by [ "order by" "," sql-interleave ] } + { \ offset [ "offset" sql% sql% ] } + { \ limit [ "limit" sql% sql% ] } + { \ select [ "(select" sql% sql% ")" sql% ] } + { \ table [ sql% ] } + { \ set [ "set" "," sql-interleave ] } + { \ values [ break "values(" sql% "," (sql-interleave) ")" sql% ] } + { \ count [ "count" sql-function, ] } + { \ sum [ "sum" sql-function, ] } + { \ avg [ "avg" sql-function, ] } + { \ min [ "min" sql-function, ] } + { \ max [ "max" sql-function, ] } [ sql% [ sql% ] each ] } case ; From 336e30b054d6d8d6353c5c2a4431d69c7a659c66 Mon Sep 17 00:00:00 2001 From: Doug Coleman <doug.coleman@gmail.com> Date: Thu, 17 Apr 2008 19:43:07 -0500 Subject: [PATCH 02/20] add interval queries for sqlite --- extra/db/db.factor | 4 +- extra/db/sql/sql-tests.factor | 2 +- extra/db/sql/sql.factor | 11 +++-- extra/db/sqlite/lib/lib.factor | 5 ++- extra/db/sqlite/sqlite.factor | 68 ++++++++++++++++++++++------- extra/db/tuples/tuples-tests.factor | 41 ++++++++++++++--- extra/db/types/types.factor | 2 + 7 files changed, 103 insertions(+), 30 deletions(-) diff --git a/extra/db/db.factor b/extra/db/db.factor index baf4e9db5a..533f238f04 100755 --- a/extra/db/db.factor +++ b/extra/db/db.factor @@ -11,7 +11,7 @@ TUPLE: db update-statements delete-statements ; -: construct-db ( class -- obj ) +: new-db ( class -- obj ) new H{ } clone >>insert-statements H{ } clone >>update-statements @@ -20,7 +20,7 @@ TUPLE: db GENERIC: make-db* ( seq class -- db ) : make-db ( seq class -- db ) - construct-db make-db* ; + new-db make-db* ; GENERIC: db-open ( db -- db ) HOOK: db-close db ( handle -- ) diff --git a/extra/db/sql/sql-tests.factor b/extra/db/sql/sql-tests.factor index db69d71a84..cab7b83ced 100644 --- a/extra/db/sql/sql-tests.factor +++ b/extra/db/sql/sql-tests.factor @@ -1,7 +1,7 @@ USING: kernel namespaces db.sql sequences math ; IN: db.sql.tests -TUPLE: person name age ; +! TUPLE: person name age ; : insert-1 { insert { table "person" } diff --git a/extra/db/sql/sql.factor b/extra/db/sql/sql.factor index b0ec7aaf34..d7ef986ea6 100755 --- a/extra/db/sql/sql.factor +++ b/extra/db/sql/sql.factor @@ -55,15 +55,18 @@ TUPLE: no-sql-match ; { [ dup number? ] [ number>string sql% ] } { [ dup symbol? ] [ unparse sql% ] } { [ dup word? ] [ unparse sql% ] } + { [ dup quotation? ] [ call ] } [ T{ no-sql-match } throw ] } cond ; : parse-sql ( obj -- sql in-spec out-spec in out ) [ unclip { - { insert [ "insert into" sql% ] } - { update [ "update" sql% ] } - { delete [ "delete" sql% ] } - { select [ "select" sql% ] } + { \ create [ "create table" sql% ] } + { \ drop [ "drop table" sql% ] } + { \ insert [ "insert into" sql% ] } + { \ update [ "update" sql% ] } + { \ delete [ "delete" sql% ] } + { \ select [ "select" sql% ] } } case [ sql% ] each ] { "" { } { } { } { } } nmake ; diff --git a/extra/db/sqlite/lib/lib.factor b/extra/db/sqlite/lib/lib.factor index e66accd7e9..b6221e5a1e 100755 --- a/extra/db/sqlite/lib/lib.factor +++ b/extra/db/sqlite/lib/lib.factor @@ -4,7 +4,7 @@ USING: alien.c-types arrays assocs kernel math math.parser namespaces sequences db.sqlite.ffi db combinators continuations db.types calendar.format serialize io.streams.byte-array byte-arrays io.encodings.binary -tools.walker ; +tools.walker io.backend ; IN: db.sqlite.lib : sqlite-error ( n -- * ) @@ -23,7 +23,8 @@ IN: db.sqlite.lib [ sqlite-error ] } cond ; -: sqlite-open ( filename -- db ) +: sqlite-open ( path -- db ) + normalize-path "void*" <c-object> [ sqlite3_open sqlite-check-result ] keep *void* ; diff --git a/extra/db/sqlite/sqlite.factor b/extra/db/sqlite/sqlite.factor index 11c0150cd2..02bf314a0a 100755 --- a/extra/db/sqlite/sqlite.factor +++ b/extra/db/sqlite/sqlite.factor @@ -4,8 +4,9 @@ USING: alien arrays assocs classes compiler db hashtables io.files kernel math math.parser namespaces prettyprint sequences strings classes.tuple alien.c-types continuations db.sqlite.lib db.sqlite.ffi db.tuples -words combinators.lib db.types combinators +words combinators.lib db.types combinators math.intervals io namespaces.lib accessors ; +USE: tools.walker IN: db.sqlite TUPLE: sqlite-db < db path ; @@ -54,16 +55,20 @@ M: sqlite-statement bind-statement* ( statement -- ) [ statement-bind-params ] [ statement-handle ] bi sqlite-bind ; +GENERIC: sqlite-bind-conversion ( tuple obj -- array ) + +M: sql-spec sqlite-bind-conversion ( tuple spec -- array ) + [ column-name>> ":" prepend ] + [ slot-name>> rot get-slot-named ] + [ type>> ] tri 3array ; + +M: literal-bind sqlite-bind-conversion ( tuple literal-bind -- array ) + nip [ key>> ] [ value>> ] [ type>> ] tri 3array ; + M: sqlite-statement bind-tuple ( tuple statement -- ) [ - in-params>> - [ - [ column-name>> ":" prepend ] - [ slot-name>> rot get-slot-named ] - [ type>> ] tri 3array - ] with map - ] keep - bind-statement ; + in-params>> [ sqlite-bind-conversion ] with map + ] keep bind-statement ; : last-insert-id ( -- id ) db get db-handle sqlite3_last_insert_rowid @@ -129,13 +134,46 @@ M: sqlite-db <insert-native-statement> ( tuple -- statement ) M: sqlite-db <insert-nonnative-statement> ( tuple -- statement ) <insert-native-statement> ; +M: sqlite-db bind% ( spec -- ) + dup 1, column-name>> ":" prepend 0% ; + : where-primary-key% ( specs -- ) " where " 0% find-primary-key dup column-name>> 0% " = " 0% bind% ; -: where-clause ( specs -- ) - " where " 0% - [ " and " 0% ] [ dup column-name>> 0% " = " 0% bind% ] interleave ; +! : where-object ( tuple specs -- ) + ! [ dup column-name>> get-slot-named ] keep + ! dup column-name>> 0% " = " 0% bind% ; + +GENERIC: where-object ( specs obj -- ) + +: interval-comparison ( ? str -- str ) + "from" = " >" " <" ? swap [ "= " append ] when ; + +: where-interval ( spec val ? from/to -- ) + roll [ + column-name>> + [ 0% interval-comparison 0% ] + [ ":" spin 3append dup 0% ] 2bi + swap + ] [ + type>> + ] bi literal-bind boa 1, ; + +M: interval where-object ( specs obj -- ) + [ from>> first2 "from" where-interval " and " 0% ] + [ to>> first2 "to" where-interval ] 2bi ; + +M: object where-object ( specs obj -- ) + drop + dup column-name>> 0% " = " 0% bind% ; + +: where-clause ( tuple specs -- ) + " where " 0% [ + " and " 0% + ] [ + 2dup slot-name>> swap get-slot-named where-object + ] interleave drop ; M: sqlite-db <update-tuple-statement> ( class -- statement ) [ @@ -158,9 +196,6 @@ M: sqlite-db <delete-tuple-statement> ( specs table -- sql ) ! : select-interval ( interval name -- ) ; ! : select-sequence ( seq name -- ) ; -M: sqlite-db bind% ( spec -- ) - dup 1, column-name>> ":" prepend 0% ; - M: sqlite-db <select-by-slots-statement> ( tuple class -- statement ) [ "select " 0% @@ -168,8 +203,9 @@ M: sqlite-db <select-by-slots-statement> ( tuple class -- statement ) [ dup column-name>> 0% 2, ] interleave " from " 0% 0% + dupd [ slot-name>> swap get-slot-named ] with subset - dup empty? [ drop ] [ where-clause ] if ";" 0% + dup empty? [ 2drop ] [ where-clause ] if ";" 0% ] sqlite-make ; M: sqlite-db modifier-table ( -- hashtable ) diff --git a/extra/db/tuples/tuples-tests.factor b/extra/db/tuples/tuples-tests.factor index 951ded32ea..36a8d4cd3f 100755 --- a/extra/db/tuples/tuples-tests.factor +++ b/extra/db/tuples/tuples-tests.factor @@ -233,12 +233,43 @@ TUPLE: exam id name score ; [ ] [ T{ exam f f "Cartman" 41 } insert-tuple ] unit-test [ - T{ exam f 3 "Kenny" 60 } - T{ exam f 4 "Cartman" 41 } - ] [ T{ exam f 4 f T{ interval f { 0 t } { 70 t } } } select-tuples ] unit-test - ; + { + T{ exam f 3 "Kenny" 60 } + T{ exam f 4 "Cartman" 41 } + } + ] [ + T{ exam f f f T{ interval f { 0 t } { 70 t } } } select-tuples + ] unit-test -! [ test-ranges ] test-sqlite + [ + { } + ] [ + T{ exam f T{ interval f { 3 f } { 4 f } } f } select-tuples + ] unit-test + [ + { + T{ exam f 4 "Cartman" 41 } + } + ] [ + T{ exam f T{ interval f { 3 f } { 4 t } } f } select-tuples + ] unit-test + [ + { + T{ exam f 3 "Kenny" 60 } + } + ] [ + T{ exam f T{ interval f { 3 t } { 4 f } } f } select-tuples + ] unit-test + [ + { + T{ exam f 3 "Kenny" 60 } + T{ exam f 4 "Cartman" 41 } + } + ] [ + T{ exam f T{ interval f { 3 t } { 4 t } } f } select-tuples + ] unit-test ; + +[ test-ranges ] test-sqlite TUPLE: secret n message ; C: <secret> secret diff --git a/extra/db/types/types.factor b/extra/db/types/types.factor index 98bc451a6f..bea81f422b 100755 --- a/extra/db/types/types.factor +++ b/extra/db/types/types.factor @@ -15,6 +15,8 @@ HOOK: compound-type db ( str n -- hash ) TUPLE: sql-spec class slot-name column-name type modifiers primary-key ; +TUPLE: literal-bind key value type ; + SINGLETON: +native-id+ SINGLETON: +assigned-id+ SINGLETON: +random-id+ From afaab57f8356b77e7dd9547ecf46bd6e8f8ac638 Mon Sep 17 00:00:00 2001 From: Doug Coleman <doug.coleman@gmail.com> Date: Fri, 18 Apr 2008 12:43:21 -0500 Subject: [PATCH 03/20] interval, range queries in sqlite --- extra/db/sqlite/sqlite.factor | 62 +++++++++++++++++------------ extra/db/tuples/tuples-tests.factor | 28 +++++++++++-- extra/db/tuples/tuples.factor | 3 ++ extra/db/types/types.factor | 4 +- 4 files changed, 67 insertions(+), 30 deletions(-) diff --git a/extra/db/sqlite/sqlite.factor b/extra/db/sqlite/sqlite.factor index 02bf314a0a..de5c245517 100755 --- a/extra/db/sqlite/sqlite.factor +++ b/extra/db/sqlite/sqlite.factor @@ -5,7 +5,7 @@ hashtables io.files kernel math math.parser namespaces prettyprint sequences strings classes.tuple alien.c-types continuations db.sqlite.lib db.sqlite.ffi db.tuples words combinators.lib db.types combinators math.intervals -io namespaces.lib accessors ; +io namespaces.lib accessors vectors math.ranges ; USE: tools.walker IN: db.sqlite @@ -104,7 +104,8 @@ M: sqlite-db rollback-transaction ( -- ) "ROLLBACK" sql-command ; : sqlite-make ( class quot -- ) >r sql-props r> - { "" { } { } } nmake <simple-statement> ; inline + [ 0 sql-counter rot with-variable ] { "" { } { } } nmake + <simple-statement> ; inline M: sqlite-db create-sql-statement ( class -- statement ) [ @@ -134,6 +135,12 @@ M: sqlite-db <insert-native-statement> ( tuple -- statement ) M: sqlite-db <insert-nonnative-statement> ( tuple -- statement ) <insert-native-statement> ; +M: sqlite-db bind# ( spec obj -- ) + >r + [ column-name>> ":" swap next-sql-counter 3append dup 0% ] + [ type>> ] bi + r> <literal-bind> 1, ; + M: sqlite-db bind% ( spec -- ) dup 1, column-name>> ":" prepend 0% ; @@ -141,38 +148,44 @@ M: sqlite-db bind% ( spec -- ) " where " 0% find-primary-key dup column-name>> 0% " = " 0% bind% ; -! : where-object ( tuple specs -- ) - ! [ dup column-name>> get-slot-named ] keep - ! dup column-name>> 0% " = " 0% bind% ; - -GENERIC: where-object ( specs obj -- ) +GENERIC: where ( specs obj -- ) : interval-comparison ( ? str -- str ) "from" = " >" " <" ? swap [ "= " append ] when ; -: where-interval ( spec val ? from/to -- ) - roll [ - column-name>> - [ 0% interval-comparison 0% ] - [ ":" spin 3append dup 0% ] 2bi - swap - ] [ - type>> - ] bi literal-bind boa 1, ; +: where-interval ( spec obj from/to -- ) + pick column-name>> 0% + >r first2 r> interval-comparison 0% + bind# ; -M: interval where-object ( specs obj -- ) - [ from>> first2 "from" where-interval " and " 0% ] - [ to>> first2 "to" where-interval ] 2bi ; +: in-parens ( quot -- ) + "(" 0% call ")" 0% ; inline -M: object where-object ( specs obj -- ) - drop - dup column-name>> 0% " = " 0% bind% ; +M: interval where ( spec obj -- ) + [ + [ from>> "from" where-interval " and " 0% ] + [ to>> "to" where-interval ] 2bi + ] in-parens ; + +M: sequence where ( spec obj -- ) + [ + [ " or " 0% ] [ dupd where ] interleave drop + ] in-parens ; + +: object-where ( spec obj -- ) + over column-name>> 0% " = " 0% bind# ; + +M: object where ( spec obj -- ) object-where ; + +M: integer where ( spec obj -- ) object-where ; + +M: string where ( spec obj -- ) object-where ; : where-clause ( tuple specs -- ) " where " 0% [ " and " 0% ] [ - 2dup slot-name>> swap get-slot-named where-object + 2dup slot-name>> swap get-slot-named where ] interleave drop ; M: sqlite-db <update-tuple-statement> ( class -- statement ) @@ -193,9 +206,6 @@ M: sqlite-db <delete-tuple-statement> ( specs table -- sql ) dup column-name>> 0% " = " 0% bind% ] sqlite-make ; -! : select-interval ( interval name -- ) ; -! : select-sequence ( seq name -- ) ; - M: sqlite-db <select-by-slots-statement> ( tuple class -- statement ) [ "select " 0% diff --git a/extra/db/tuples/tuples-tests.factor b/extra/db/tuples/tuples-tests.factor index 36a8d4cd3f..691cc6f687 100755 --- a/extra/db/tuples/tuples-tests.factor +++ b/extra/db/tuples/tuples-tests.factor @@ -1,7 +1,7 @@ ! Copyright (C) 2008 Doug Coleman. ! See http://factorcode.org/license.txt for BSD license. USING: io.files kernel tools.test db db.tuples -db.types continuations namespaces math +db.types continuations namespaces math math.ranges prettyprint tools.walker db.sqlite calendar math.intervals db.postgresql ; IN: db.tuples.tests @@ -217,7 +217,7 @@ TUPLE: serialize-me id data ; TUPLE: exam id name score ; -: test-ranges ( -- ) +: test-intervals ( -- ) exam "EXAM" { { "id" "ID" +native-id+ } @@ -267,9 +267,31 @@ TUPLE: exam id name score ; } ] [ T{ exam f T{ interval f { 3 t } { 4 t } } f } select-tuples + ] unit-test + + [ + { + T{ exam f 1 "Kyle" 100 } + T{ exam f 2 "Stan" 80 } + } + ] [ + T{ exam f f { "Stan" "Kyle" } } select-tuples + ] unit-test + + [ + { + T{ exam f 1 "Kyle" 100 } + T{ exam f 2 "Stan" 80 } + T{ exam f 3 "Kenny" 60 } + } + ] [ + T{ exam f T{ range f 1 3 1 } } select-tuples ] unit-test ; -[ test-ranges ] test-sqlite +[ test-intervals ] test-sqlite + +: test-ranges + ; TUPLE: secret n message ; C: <secret> secret diff --git a/extra/db/tuples/tuples.factor b/extra/db/tuples/tuples.factor index 311f18daa9..32431b4ddc 100755 --- a/extra/db/tuples/tuples.factor +++ b/extra/db/tuples/tuples.factor @@ -22,6 +22,9 @@ IN: db.tuples class db-columns find-primary-key sql-spec-slot-name ] keep set-slot-named ; +SYMBOL: sql-counter +: next-sql-counter sql-counter [ inc ] [ get ] bi number>string ; + ! returns a sequence of prepared-statements HOOK: create-sql-statement db ( class -- obj ) HOOK: drop-sql-statement db ( class -- obj ) diff --git a/extra/db/types/types.factor b/extra/db/types/types.factor index bea81f422b..9959e894a7 100755 --- a/extra/db/types/types.factor +++ b/extra/db/types/types.factor @@ -15,7 +15,8 @@ HOOK: compound-type db ( str n -- hash ) TUPLE: sql-spec class slot-name column-name type modifiers primary-key ; -TUPLE: literal-bind key value type ; +TUPLE: literal-bind key type value ; +C: <literal-bind> literal-bind SINGLETON: +native-id+ SINGLETON: +assigned-id+ @@ -132,6 +133,7 @@ TUPLE: no-sql-modifier ; dup empty? [ " " prepend ] unless ; HOOK: bind% db ( spec -- ) +HOOK: bind# db ( spec obj -- ) : offset-of-slot ( str obj -- n ) class "slots" word-prop slot-named slot-spec-offset ; From 6044cc4b3905a7c4b9a30a241f7c31e8032949b8 Mon Sep 17 00:00:00 2001 From: Doug Coleman <doug.coleman@gmail.com> Date: Fri, 18 Apr 2008 16:01:31 -0500 Subject: [PATCH 04/20] make throwable, nonthrowable, retryable a type --- extra/db/db.factor | 60 +++++++++++++++++++-------- extra/db/postgresql/postgresql.factor | 2 +- extra/db/sqlite/sqlite.factor | 8 ++-- extra/db/tuples/tuples-tests.factor | 16 ++++--- 4 files changed, 55 insertions(+), 31 deletions(-) diff --git a/extra/db/db.factor b/extra/db/db.factor index 533f238f04..7a28dea558 100755 --- a/extra/db/db.factor +++ b/extra/db/db.factor @@ -2,7 +2,7 @@ ! See http://factorcode.org/license.txt for BSD license. USING: arrays assocs classes continuations kernel math namespaces sequences sequences.lib classes.tuple words strings -tools.walker accessors ; +tools.walker accessors combinators.lib ; IN: db TUPLE: db @@ -36,26 +36,47 @@ HOOK: db-close db ( handle -- ) ] with-variable ; ! TUPLE: sql sql in-params out-params ; -TUPLE: statement handle sql in-params out-params bind-params bound? ; +TUPLE: statement handle sql in-params out-params bind-params bound? type quot ; TUPLE: simple-statement < statement ; TUPLE: prepared-statement < statement ; -TUPLE: nonthrowable-statement < statement ; -TUPLE: throwable-statement < statement ; + +SINGLETON: throwable +SINGLETON: nonthrowable +SINGLETON: retryable + +: make-throwable ( obj -- obj' ) + dup sequence? [ + [ make-throwable ] map + ] [ + throwable >>type + ] if ; : make-nonthrowable ( obj -- obj' ) dup sequence? [ [ make-nonthrowable ] map ] [ - nonthrowable-statement construct-delegate + nonthrowable >>type ] if ; +: make-retryable ( obj quot -- obj' ) + over sequence? [ + [ make-retryable ] curry map + ] [ + >>quot + retryable >>type + ] if ; + +: handle-random-id ( statement -- ) + drop ; + TUPLE: result-set sql in-params out-params handle n max ; : construct-statement ( sql in out class -- statement ) new swap >>out-params swap >>in-params - swap >>sql ; + swap >>sql + throwable >>type ; HOOK: <simple-statement> db ( str in out -- statement ) HOOK: <prepared-statement> db ( str in out -- statement ) @@ -70,20 +91,25 @@ GENERIC# row-column-typed 1 ( result-set column -- sql ) GENERIC: advance-row ( result-set -- ) GENERIC: more-rows? ( result-set -- ? ) -GENERIC: execute-statement ( statement -- ) +GENERIC: execute-statement* ( statement type -- ) -M: throwable-statement execute-statement ( statement -- ) - dup sequence? [ - [ execute-statement ] each - ] [ - query-results dispose - ] if ; +M: throwable execute-statement* ( statement type -- ) + drop query-results dispose ; -M: nonthrowable-statement execute-statement ( statement -- ) - dup sequence? [ - [ execute-statement ] each - ] [ +M: nonthrowable execute-statement* ( statement type -- ) + drop [ query-results dispose ] [ 2drop ] recover ; + +M: retryable execute-statement* ( statement type -- ) + [ + dup dup quot>> call [ query-results dispose ] [ 2drop ] recover + ] curry 10 retry ; + +: execute-statement ( statement -- ) + dup sequence? [ + [ execute-statement ] each + ] [ + dup type>> execute-statement* ] if ; : bind-statement ( obj statement -- ) diff --git a/extra/db/postgresql/postgresql.factor b/extra/db/postgresql/postgresql.factor index 322143e7a2..9dfa123952 100755 --- a/extra/db/postgresql/postgresql.factor +++ b/extra/db/postgresql/postgresql.factor @@ -11,7 +11,7 @@ IN: db.postgresql TUPLE: postgresql-db < db host port pgopts pgtty db user pass ; -TUPLE: postgresql-statement < throwable-statement ; +TUPLE: postgresql-statement < statement ; TUPLE: postgresql-result-set < result-set ; diff --git a/extra/db/sqlite/sqlite.factor b/extra/db/sqlite/sqlite.factor index de5c245517..e2ea28fe9a 100755 --- a/extra/db/sqlite/sqlite.factor +++ b/extra/db/sqlite/sqlite.factor @@ -20,7 +20,7 @@ M: sqlite-db db-open ( db -- db ) M: sqlite-db db-close ( handle -- ) sqlite-close ; M: sqlite-db dispose ( db -- ) dispose-db ; -TUPLE: sqlite-statement < throwable-statement ; +TUPLE: sqlite-statement < statement ; TUPLE: sqlite-result-set < result-set has-more? ; @@ -105,7 +105,8 @@ M: sqlite-db rollback-transaction ( -- ) "ROLLBACK" sql-command ; : sqlite-make ( class quot -- ) >r sql-props r> [ 0 sql-counter rot with-variable ] { "" { } { } } nmake - <simple-statement> ; inline + <simple-statement> + dup handle-random-id ; inline M: sqlite-db create-sql-statement ( class -- statement ) [ @@ -223,7 +224,6 @@ M: sqlite-db modifier-table ( -- hashtable ) { +native-id+ "primary key" } { +assigned-id+ "primary key" } { +random-id+ "primary key" } - ! { +nonnative-id+ "primary key" } { +autoincrement+ "autoincrement" } { +unique+ "unique" } { +default+ "default" } @@ -236,7 +236,7 @@ M: sqlite-db compound-modifier ( str obj -- str' ) compound-type ; M: sqlite-db compound-type ( str seq -- str' ) over { { "default" [ first number>string join-space ] } - [ 2drop ] ! "no sqlite compound data type" 3array throw ] + [ 2drop ] } case ; M: sqlite-db type-table ( -- assoc ) diff --git a/extra/db/tuples/tuples-tests.factor b/extra/db/tuples/tuples-tests.factor index 691cc6f687..56e401d5ec 100755 --- a/extra/db/tuples/tuples-tests.factor +++ b/extra/db/tuples/tuples-tests.factor @@ -308,15 +308,13 @@ C: <secret> secret [ ] [ T{ secret } select-tuples ] unit-test ; - - -! [ test-random-id ] test-sqlite - [ native-person-schema test-tuples ] test-sqlite - [ assigned-person-schema test-tuples ] test-sqlite - [ assigned-person-schema test-repeated-insert ] test-sqlite - [ native-person-schema test-tuples ] test-postgresql - [ assigned-person-schema test-tuples ] test-postgresql - [ assigned-person-schema test-repeated-insert ] test-postgresql +[ test-random-id ] test-sqlite +[ native-person-schema test-tuples ] test-sqlite +[ assigned-person-schema test-tuples ] test-sqlite +[ assigned-person-schema test-repeated-insert ] test-sqlite +[ native-person-schema test-tuples ] test-postgresql +[ assigned-person-schema test-tuples ] test-postgresql +[ assigned-person-schema test-repeated-insert ] test-postgresql ! \ insert-tuple must-infer ! \ update-tuple must-infer From b257640f97885aade8e4364216de9d233d7cddc3 Mon Sep 17 00:00:00 2001 From: Doug Coleman <doug.coleman@gmail.com> Date: Sat, 19 Apr 2008 19:27:46 -0500 Subject: [PATCH 05/20] remove ?head* --- extra/sequences/lib/lib.factor | 3 --- 1 file changed, 3 deletions(-) diff --git a/extra/sequences/lib/lib.factor b/extra/sequences/lib/lib.factor index 15983329d6..6bc6c706cf 100755 --- a/extra/sequences/lib/lib.factor +++ b/extra/sequences/lib/lib.factor @@ -197,9 +197,6 @@ USE: continuations >r >r 0 max r> r> [ length tuck min >r min r> ] keep subseq ; -: ?head* ( seq n -- seq/f ) (head) ?subseq ; -: ?tail* ( seq n -- seq/f ) (tail) ?subseq ; - : accumulator ( quot -- quot vec ) V{ } clone [ [ push ] curry compose ] keep ; inline From a81aaa61009f3d84983b1004e94f925f466d4ea7 Mon Sep 17 00:00:00 2001 From: Doug Coleman <doug.coleman@gmail.com> Date: Sat, 19 Apr 2008 19:27:54 -0500 Subject: [PATCH 06/20] add random-id, still needs to retry if insert fails --- extra/db/db.factor | 6 +-- extra/db/sql/sql.factor | 6 +-- extra/db/sqlite/ffi/ffi.factor | 10 ++++- extra/db/sqlite/lib/lib.factor | 17 ++++++-- extra/db/sqlite/sqlite.factor | 34 +++++++++++++-- extra/db/tuples/tuples-tests.factor | 57 +++++++++++++++++++++---- extra/db/tuples/tuples.factor | 23 ++++++----- extra/db/types/types.factor | 64 ++++++++++++++++++----------- 8 files changed, 158 insertions(+), 59 deletions(-) diff --git a/extra/db/db.factor b/extra/db/db.factor index 7a28dea558..ce6232f414 100755 --- a/extra/db/db.factor +++ b/extra/db/db.factor @@ -36,7 +36,7 @@ HOOK: db-close db ( handle -- ) ] with-variable ; ! TUPLE: sql sql in-params out-params ; -TUPLE: statement handle sql in-params out-params bind-params bound? type quot ; +TUPLE: statement handle sql in-params out-params bind-params bound? type ; TUPLE: simple-statement < statement ; TUPLE: prepared-statement < statement ; @@ -62,13 +62,9 @@ SINGLETON: retryable over sequence? [ [ make-retryable ] curry map ] [ - >>quot retryable >>type ] if ; -: handle-random-id ( statement -- ) - drop ; - TUPLE: result-set sql in-params out-params handle n max ; : construct-statement ( sql in out class -- statement ) diff --git a/extra/db/sql/sql.factor b/extra/db/sql/sql.factor index d7ef986ea6..4561424a9d 100755 --- a/extra/db/sql/sql.factor +++ b/extra/db/sql/sql.factor @@ -38,7 +38,7 @@ DEFER: sql% { \ select [ "(select" sql% sql% ")" sql% ] } { \ table [ sql% ] } { \ set [ "set" "," sql-interleave ] } - { \ values [ break "values(" sql% "," (sql-interleave) ")" sql% ] } + { \ values [ "values(" sql% "," (sql-interleave) ")" sql% ] } { \ count [ "count" sql-function, ] } { \ sum [ "sum" sql-function, ] } { \ avg [ "avg" sql-function, ] } @@ -47,7 +47,7 @@ DEFER: sql% [ sql% [ sql% ] each ] } case ; -TUPLE: no-sql-match ; +ERROR: no-sql-match ; : sql% ( obj -- ) { { [ dup string? ] [ " " 0% 0% ] } @@ -56,7 +56,7 @@ TUPLE: no-sql-match ; { [ dup symbol? ] [ unparse sql% ] } { [ dup word? ] [ unparse sql% ] } { [ dup quotation? ] [ call ] } - [ T{ no-sql-match } throw ] + [ no-sql-match ] } cond ; : parse-sql ( obj -- sql in-spec out-spec in out ) diff --git a/extra/db/sqlite/ffi/ffi.factor b/extra/db/sqlite/ffi/ffi.factor index c724025874..6b94c02c65 100755 --- a/extra/db/sqlite/ffi/ffi.factor +++ b/extra/db/sqlite/ffi/ffi.factor @@ -3,7 +3,7 @@ ! An interface to the sqlite database. Tested against sqlite v3.1.3. ! Not all functions have been wrapped. USING: alien compiler kernel math namespaces sequences strings alien.syntax - system combinators ; + system combinators alien.c-types ; IN: db.sqlite.ffi << "sqlite" { @@ -112,11 +112,14 @@ FUNCTION: int sqlite3_prepare ( sqlite3* pDb, char* zSql, int nBytes, void* ppSt FUNCTION: int sqlite3_finalize ( sqlite3_stmt* pStmt ) ; FUNCTION: int sqlite3_reset ( sqlite3_stmt* pStmt ) ; FUNCTION: int sqlite3_step ( sqlite3_stmt* pStmt ) ; -FUNCTION: sqlite3_int64 sqlite3_last_insert_rowid ( sqlite3* pStmt ) ; +FUNCTION: sqlite3_uint64 sqlite3_last_insert_rowid ( sqlite3* pStmt ) ; FUNCTION: int sqlite3_bind_blob ( sqlite3_stmt* pStmt, int index, void* ptr, int len, int destructor ) ; FUNCTION: int sqlite3_bind_double ( sqlite3_stmt* pStmt, int index, double x ) ; FUNCTION: int sqlite3_bind_int ( sqlite3_stmt* pStmt, int index, int n ) ; FUNCTION: int sqlite3_bind_int64 ( sqlite3_stmt* pStmt, int index, sqlite3_int64 n ) ; +: sqlite3-bind-uint64 ( pStmt index in64 -- int ) + "int" "sqlite" "sqlite3_bind_int64" + { "sqlite3_stmt*" "int" "sqlite3_uint64" } alien-invoke ; FUNCTION: int sqlite3_bind_null ( sqlite3_stmt* pStmt, int n ) ; FUNCTION: int sqlite3_bind_text ( sqlite3_stmt* pStmt, int index, char* text, int len, int destructor ) ; FUNCTION: int sqlite3_bind_parameter_index ( sqlite3_stmt* pStmt, char* name ) ; @@ -126,6 +129,9 @@ FUNCTION: int sqlite3_column_bytes ( sqlite3_stmt* pStmt, int col ) ; FUNCTION: char* sqlite3_column_decltype ( sqlite3_stmt* pStmt, int col ) ; FUNCTION: int sqlite3_column_int ( sqlite3_stmt* pStmt, int col ) ; FUNCTION: sqlite3_int64 sqlite3_column_int64 ( sqlite3_stmt* pStmt, int col ) ; +: sqlite3-column-uint64 ( pStmt col -- uint64 ) + "sqlite3_uint64" "sqlite" "sqlite3_column_int64" + { "sqlite3_stmt*" "int" } alien-invoke ; FUNCTION: double sqlite3_column_double ( sqlite3_stmt* pStmt, int col ) ; FUNCTION: char* sqlite3_column_name ( sqlite3_stmt* pStmt, int col ) ; FUNCTION: char* sqlite3_column_text ( sqlite3_stmt* pStmt, int col ) ; diff --git a/extra/db/sqlite/lib/lib.factor b/extra/db/sqlite/lib/lib.factor index b6221e5a1e..61070b078b 100755 --- a/extra/db/sqlite/lib/lib.factor +++ b/extra/db/sqlite/lib/lib.factor @@ -52,6 +52,9 @@ IN: db.sqlite.lib : sqlite-bind-int64 ( handle i n -- ) sqlite3_bind_int64 sqlite-check-result ; +: sqlite-bind-uint64 ( handle i n -- ) + sqlite3-bind-uint64 sqlite-check-result ; + : sqlite-bind-double ( handle i x -- ) sqlite3_bind_double sqlite-check-result ; @@ -69,7 +72,10 @@ IN: db.sqlite.lib parameter-index sqlite-bind-int ; : sqlite-bind-int64-by-name ( handle name int64 -- ) - parameter-index sqlite-bind-int ; + parameter-index sqlite-bind-int64 ; + +: sqlite-bind-uint64-by-name ( handle name int64 -- ) + parameter-index sqlite-bind-uint64 ; : sqlite-bind-double-by-name ( handle name double -- ) parameter-index sqlite-bind-double ; @@ -86,6 +92,8 @@ IN: db.sqlite.lib { { INTEGER [ sqlite-bind-int-by-name ] } { BIG-INTEGER [ sqlite-bind-int64-by-name ] } + { SIGNED-BIG-INTEGER [ sqlite-bind-int64-by-name ] } + { UNSIGNED-BIG-INTEGER [ sqlite-bind-uint64-by-name ] } { TEXT [ sqlite-bind-text-by-name ] } { VARCHAR [ sqlite-bind-text-by-name ] } { DOUBLE [ sqlite-bind-double-by-name ] } @@ -99,6 +107,7 @@ IN: db.sqlite.lib sqlite-bind-blob-by-name ] } { +native-id+ [ sqlite-bind-int-by-name ] } + { +random-id+ [ sqlite-bind-int64-by-name ] } { NULL [ sqlite-bind-null-by-name ] } [ no-sql-type ] } case ; @@ -121,10 +130,12 @@ IN: db.sqlite.lib : sqlite-column-typed ( handle index type -- obj ) dup array? [ first ] when { - { +native-id+ [ sqlite3_column_int64 ] } - { +random-id+ [ sqlite3_column_int64 ] } + { +native-id+ [ sqlite3_column_int64 ] } + { +random-id+ [ sqlite3-column-uint64 ] } { INTEGER [ sqlite3_column_int ] } { BIG-INTEGER [ sqlite3_column_int64 ] } + { SIGNED-BIG-INTEGER [ sqlite3_column_int64 ] } + { UNSIGNED-BIG-INTEGER [ sqlite3-column-uint64 ] } { DOUBLE [ sqlite3_column_double ] } { TEXT [ sqlite3_column_text ] } { VARCHAR [ sqlite3_column_text ] } diff --git a/extra/db/sqlite/sqlite.factor b/extra/db/sqlite/sqlite.factor index e2ea28fe9a..5f8247f67b 100755 --- a/extra/db/sqlite/sqlite.factor +++ b/extra/db/sqlite/sqlite.factor @@ -5,7 +5,8 @@ hashtables io.files kernel math math.parser namespaces prettyprint sequences strings classes.tuple alien.c-types continuations db.sqlite.lib db.sqlite.ffi db.tuples words combinators.lib db.types combinators math.intervals -io namespaces.lib accessors vectors math.ranges ; +io namespaces.lib accessors vectors math.ranges random +math.bitfields.lib ; USE: tools.walker IN: db.sqlite @@ -65,6 +66,9 @@ M: sql-spec sqlite-bind-conversion ( tuple spec -- array ) M: literal-bind sqlite-bind-conversion ( tuple literal-bind -- array ) nip [ key>> ] [ value>> ] [ type>> ] tri 3array ; +M: generator-bind sqlite-bind-conversion ( tuple generate-bind -- array ) + nip [ key>> ] [ quot>> call ] [ type>> ] tri 3array ; + M: sqlite-statement bind-tuple ( tuple statement -- ) [ in-params>> [ sqlite-bind-conversion ] with map @@ -105,8 +109,7 @@ M: sqlite-db rollback-transaction ( -- ) "ROLLBACK" sql-command ; : sqlite-make ( class quot -- ) >r sql-props r> [ 0 sql-counter rot with-variable ] { "" { } { } } nmake - <simple-statement> - dup handle-random-id ; inline + <simple-statement> ; M: sqlite-db create-sql-statement ( class -- statement ) [ @@ -129,7 +132,21 @@ M: sqlite-db <insert-native-statement> ( tuple -- statement ) maybe-remove-id dup [ ", " 0% ] [ column-name>> 0% ] interleave ") values(" 0% - [ ", " 0% ] [ bind% ] interleave + [ ", " 0% ] [ + dup type>> +random-id+ = [ +break + dup modifiers>> find-random-generator + [ + [ + column-name>> ":" prepend + dup 0% random-id-quot + ] with-random + ] curry + [ type>> ] bi 10 <generator-bind> 1, + ] [ + bind% + ] if + ] interleave ");" 0% ] sqlite-make ; @@ -219,6 +236,9 @@ M: sqlite-db <select-by-slots-statement> ( tuple class -- statement ) dup empty? [ 2drop ] [ where-clause ] if ";" 0% ] sqlite-make ; +M: sqlite-db random-id-quot ( -- quot ) + [ 64 [ 2^ random ] keep 1 - set-bit ] ; + M: sqlite-db modifier-table ( -- hashtable ) H{ { +native-id+ "primary key" } @@ -229,6 +249,9 @@ M: sqlite-db modifier-table ( -- hashtable ) { +default+ "default" } { +null+ "null" } { +not-null+ "not null" } + { system-random-generator "" } + { secure-random-generator "" } + { random-generator "" } } ; M: sqlite-db compound-modifier ( str obj -- str' ) compound-type ; @@ -244,6 +267,9 @@ M: sqlite-db type-table ( -- assoc ) { +native-id+ "integer primary key" } { +random-id+ "integer primary key" } { INTEGER "integer" } + { BIG-INTEGER "bigint" } + { SIGNED-BIG-INTEGER "bigint" } + { UNSIGNED-BIG-INTEGER "bigint" } { TEXT "text" } { VARCHAR "text" } { DATE "date" } diff --git a/extra/db/tuples/tuples-tests.factor b/extra/db/tuples/tuples-tests.factor index 56e401d5ec..083cf059c9 100755 --- a/extra/db/tuples/tuples-tests.factor +++ b/extra/db/tuples/tuples-tests.factor @@ -1,9 +1,9 @@ ! Copyright (C) 2008 Doug Coleman. ! See http://factorcode.org/license.txt for BSD license. -USING: io.files kernel tools.test db db.tuples +USING: io.files kernel tools.test db db.tuples classes db.types continuations namespaces math math.ranges -prettyprint tools.walker db.sqlite calendar -math.intervals db.postgresql ; +prettyprint tools.walker db.sqlite calendar sequences +math.intervals db.postgresql accessors random math.bitfields.lib ; IN: db.tuples.tests TUPLE: person the-id the-name the-number the-real @@ -290,8 +290,37 @@ TUPLE: exam id name score ; [ test-intervals ] test-sqlite -: test-ranges - ; +TUPLE: bignum-test id m n o ; +: <bignum-test> ( m n o -- obj ) + bignum-test new + swap >>o + swap >>n + swap >>m ; + +: test-bignum + bignum-test "BIGNUM_TEST" + { + { "id" "ID" +native-id+ } + { "m" "M" BIG-INTEGER } + { "n" "N" UNSIGNED-BIG-INTEGER } + { "o" "O" SIGNED-BIG-INTEGER } + } define-persistent + [ bignum-test drop-table ] ignore-errors + [ ] [ bignum-test ensure-table ] unit-test + [ ] [ 63 2^ dup dup <bignum-test> insert-tuple ] unit-test + + [ T{ bignum-test f 1 + -9223372036854775808 9223372036854775808 -9223372036854775808 } ] + [ T{ bignum-test f 1 } select-tuple ] unit-test ; + +[ test-bignum ] test-sqlite + +TUPLE: does-not-persist ; + +[ + [ does-not-persist create-sql-statement ] + [ class \ not-persistent = ] must-fail-with +] test-sqlite TUPLE: secret n message ; C: <secret> secret @@ -299,14 +328,26 @@ C: <secret> secret : test-random-id secret "SECRET" { - { "n" "ID" +random-id+ } + { "n" "ID" +random-id+ system-random-generator } { "message" "MESSAGE" TEXT } } define-persistent [ ] [ secret ensure-table ] unit-test + [ ] [ f "kilroy was here" <secret> insert-tuple ] unit-test - [ ] [ T{ secret } select-tuples ] unit-test - ; + + [ ] [ f "kilroy was here2" <secret> insert-tuple ] unit-test + + [ ] [ f "kilroy was here3" <secret> insert-tuple ] unit-test + + [ t ] [ + T{ secret } select-tuples + first message>> "kilroy was here" head? + ] unit-test + + [ t ] [ + T{ secret } select-tuples length 3 = + ] unit-test ; [ test-random-id ] test-sqlite [ native-person-schema test-tuples ] test-sqlite diff --git a/extra/db/tuples/tuples.factor b/extra/db/tuples/tuples.factor index 32431b4ddc..e0b4fce2f3 100755 --- a/extra/db/tuples/tuples.factor +++ b/extra/db/tuples/tuples.factor @@ -13,9 +13,16 @@ IN: db.tuples "db-columns" set-word-prop "db-relations" set-word-prop ; -: db-table ( class -- obj ) "db-table" word-prop ; -: db-columns ( class -- obj ) "db-columns" word-prop ; -: db-relations ( class -- obj ) "db-relations" word-prop ; +ERROR: not-persistent ; + +: db-table ( class -- obj ) + "db-table" word-prop [ not-persistent ] unless* ; + +: db-columns ( class -- obj ) + "db-columns" word-prop ; + +: db-relations ( class -- obj ) + "db-relations" word-prop ; : set-primary-key ( key tuple -- ) [ @@ -61,7 +68,7 @@ HOOK: insert-tuple* db ( tuple statement -- ) ] curry 2each ; : sql-props ( class -- columns table ) - dup db-columns swap db-table ; + [ db-columns ] [ db-table ] bi ; : with-disposals ( seq quot -- ) over sequence? [ @@ -88,17 +95,13 @@ HOOK: insert-tuple* db ( tuple statement -- ) [ bind-tuple ] 2keep insert-tuple* ; : insert-nonnative ( tuple -- ) -! TODO logic here for unique ids dup class db get db-insert-statements [ <insert-nonnative-statement> ] cache [ bind-tuple ] keep execute-statement ; : insert-tuple ( tuple -- ) - dup class db-columns find-primary-key nonnative-id? [ - insert-nonnative - ] [ - insert-native - ] if ; + dup class db-columns find-primary-key nonnative-id? + [ insert-nonnative ] [ insert-native ] if ; : update-tuple ( tuple -- ) dup class diff --git a/extra/db/types/types.factor b/extra/db/types/types.factor index 9959e894a7..b8855ce296 100755 --- a/extra/db/types/types.factor +++ b/extra/db/types/types.factor @@ -4,7 +4,7 @@ USING: arrays assocs db kernel math math.parser sequences continuations sequences.deep sequences.lib words namespaces tools.walker slots slots.private classes mirrors classes.tuple combinators calendar.format symbols -classes.singleton ; +classes.singleton accessors quotations random ; IN: db.types HOOK: modifier-table db ( -- hash ) @@ -12,12 +12,16 @@ HOOK: compound-modifier db ( str seq -- hash ) HOOK: type-table db ( -- hash ) HOOK: create-type-table db ( -- hash ) HOOK: compound-type db ( str n -- hash ) +HOOK: random-id-quot db ( -- quot ) -TUPLE: sql-spec class slot-name column-name type modifiers primary-key ; +TUPLE: sql-spec class slot-name column-name type primary-key modifiers ; TUPLE: literal-bind key type value ; C: <literal-bind> literal-bind +TUPLE: generator-bind key quot type retries ; +C: <generator-bind> generator-bind + SINGLETON: +native-id+ SINGLETON: +assigned-id+ SINGLETON: +random-id+ @@ -27,6 +31,15 @@ UNION: +nonnative-id+ +random-id+ +assigned-id+ ; SYMBOLS: +autoincrement+ +serial+ +unique+ +default+ +null+ +not-null+ +foreign-id+ +has-many+ ; +: find-random-generator ( seq -- obj ) + [ + { + random-generator + system-random-generator + secure-random-generator + } member? + ] find nip [ system-random-generator ] unless* ; + : primary-key? ( spec -- ? ) sql-spec-primary-key +primary-key+? ; @@ -51,26 +64,27 @@ SYMBOLS: +autoincrement+ +serial+ +unique+ +default+ +null+ +not-null+ : relation? ( spec -- ? ) [ +has-many+ = ] deep-find ; -SYMBOLS: INTEGER BIG-INTEGER DOUBLE REAL BOOLEAN TEXT VARCHAR -DATE TIME DATETIME TIMESTAMP BLOB FACTOR-BLOB NULL ; +: handle-random-id ( statement -- ) + dup in-params>> [ type>> +random-id+ = ] find drop >boolean [ + retryable >>type + random-id-quot >>quot + ] when drop ; + +SYMBOLS: INTEGER BIG-INTEGER SIGNED-BIG-INTEGER UNSIGNED-BIG-INTEGER +DOUBLE REAL BOOLEAN TEXT VARCHAR DATE TIME DATETIME TIMESTAMP BLOB +FACTOR-BLOB NULL ; : spec>tuple ( class spec -- tuple ) - [ ?first3 ] keep 3 ?tail* - { - set-sql-spec-class - set-sql-spec-slot-name - set-sql-spec-column-name - set-sql-spec-type - set-sql-spec-modifiers - } sql-spec construct + 3 f pad-right + [ first3 ] keep 3 tail + sql-spec new + swap >>modifiers + swap >>type + swap >>column-name + swap >>slot-name + swap >>class dup normalize-spec ; -TUPLE: no-sql-type ; -: no-sql-type ( -- * ) T{ no-sql-type } throw ; - -TUPLE: no-sql-modifier ; -: no-sql-modifier ( -- * ) T{ no-sql-modifier } throw ; - : number>string* ( n/str -- str ) dup number? [ number>string ] when ; @@ -88,13 +102,15 @@ TUPLE: no-sql-modifier ; ! PostgreSQL Types: ! http://developer.postgresql.org/pgdocs/postgres/datatype.html +ERROR: unknown-modifier ; + : lookup-modifier ( obj -- str ) - dup array? [ - unclip lookup-modifier swap compound-modifier - ] [ - modifier-table at* - [ "unknown modifier" throw ] unless - ] if ; + { + { [ dup array? ] [ unclip lookup-modifier swap compound-modifier ] } + [ modifier-table at* [ unknown-modifier ] unless ] + } cond ; + +ERROR: no-sql-type ; : lookup-type* ( obj -- str ) dup array? [ From 9b5351e81f4b6b4e46da33aedaae748be135b10a Mon Sep 17 00:00:00 2001 From: Doug Coleman <doug.coleman@gmail.com> Date: Sat, 19 Apr 2008 19:28:25 -0500 Subject: [PATCH 07/20] remove extra using --- extra/db/sqlite/sqlite.factor | 2 -- 1 file changed, 2 deletions(-) diff --git a/extra/db/sqlite/sqlite.factor b/extra/db/sqlite/sqlite.factor index 5f8247f67b..093a705b0d 100755 --- a/extra/db/sqlite/sqlite.factor +++ b/extra/db/sqlite/sqlite.factor @@ -7,7 +7,6 @@ continuations db.sqlite.lib db.sqlite.ffi db.tuples words combinators.lib db.types combinators math.intervals io namespaces.lib accessors vectors math.ranges random math.bitfields.lib ; -USE: tools.walker IN: db.sqlite TUPLE: sqlite-db < db path ; @@ -134,7 +133,6 @@ M: sqlite-db <insert-native-statement> ( tuple -- statement ) ") values(" 0% [ ", " 0% ] [ dup type>> +random-id+ = [ -break dup modifiers>> find-random-generator [ [ From 896c920d85008304c9896ca0daf46e91b9faadea Mon Sep 17 00:00:00 2001 From: Doug Coleman <doug.coleman@gmail.com> Date: Sat, 19 Apr 2008 22:09:36 -0500 Subject: [PATCH 08/20] retryable statements actually retry now --- extra/db/db.factor | 15 +----------- extra/db/sqlite/ffi/ffi.factor | 3 ++- extra/db/sqlite/lib/lib.factor | 4 +++- extra/db/sqlite/sqlite.factor | 24 ++++++++++++------- extra/db/tuples/tuples-tests.factor | 2 +- extra/db/tuples/tuples.factor | 36 ++++++++++++++++++++++++++++- extra/db/types/types.factor | 8 +------ 7 files changed, 59 insertions(+), 33 deletions(-) diff --git a/extra/db/db.factor b/extra/db/db.factor index ce6232f414..82193ed467 100755 --- a/extra/db/db.factor +++ b/extra/db/db.factor @@ -42,7 +42,6 @@ TUPLE: prepared-statement < statement ; SINGLETON: throwable SINGLETON: nonthrowable -SINGLETON: retryable : make-throwable ( obj -- obj' ) dup sequence? [ @@ -58,13 +57,6 @@ SINGLETON: retryable nonthrowable >>type ] if ; -: make-retryable ( obj quot -- obj' ) - over sequence? [ - [ make-retryable ] curry map - ] [ - retryable >>type - ] if ; - TUPLE: result-set sql in-params out-params handle n max ; : construct-statement ( sql in out class -- statement ) @@ -78,6 +70,7 @@ HOOK: <simple-statement> db ( str in out -- statement ) HOOK: <prepared-statement> db ( str in out -- statement ) GENERIC: prepare-statement ( statement -- ) GENERIC: bind-statement* ( statement -- ) +GENERIC: low-level-bind ( statement -- ) GENERIC: bind-tuple ( tuple statement -- ) GENERIC: query-results ( query -- result-set ) GENERIC: #rows ( result-set -- n ) @@ -95,12 +88,6 @@ M: throwable execute-statement* ( statement type -- ) M: nonthrowable execute-statement* ( statement type -- ) drop [ query-results dispose ] [ 2drop ] recover ; -M: retryable execute-statement* ( statement type -- ) - [ - dup dup quot>> call - [ query-results dispose ] [ 2drop ] recover - ] curry 10 retry ; - : execute-statement ( statement -- ) dup sequence? [ [ execute-statement ] each diff --git a/extra/db/sqlite/ffi/ffi.factor b/extra/db/sqlite/ffi/ffi.factor index 6b94c02c65..4b5a019fca 100755 --- a/extra/db/sqlite/ffi/ffi.factor +++ b/extra/db/sqlite/ffi/ffi.factor @@ -108,7 +108,7 @@ LIBRARY: sqlite FUNCTION: int sqlite3_open ( char* filename, void* ppDb ) ; FUNCTION: int sqlite3_close ( sqlite3* pDb ) ; FUNCTION: char* sqlite3_errmsg ( sqlite3* pDb ) ; -FUNCTION: int sqlite3_prepare ( sqlite3* pDb, char* zSql, int nBytes, void* ppStmt, void* pzTail ) ; +FUNCTION: int sqlite3_prepare_v2 ( sqlite3* pDb, char* zSql, int nBytes, void* ppStmt, void* pzTail ) ; FUNCTION: int sqlite3_finalize ( sqlite3_stmt* pStmt ) ; FUNCTION: int sqlite3_reset ( sqlite3_stmt* pStmt ) ; FUNCTION: int sqlite3_step ( sqlite3_stmt* pStmt ) ; @@ -123,6 +123,7 @@ FUNCTION: int sqlite3_bind_int64 ( sqlite3_stmt* pStmt, int index, sqlite3_int64 FUNCTION: int sqlite3_bind_null ( sqlite3_stmt* pStmt, int n ) ; FUNCTION: int sqlite3_bind_text ( sqlite3_stmt* pStmt, int index, char* text, int len, int destructor ) ; FUNCTION: int sqlite3_bind_parameter_index ( sqlite3_stmt* pStmt, char* name ) ; +FUNCTION: int sqlite3_clear_bindings ( sqlite3_stmt* pStmt ) ; FUNCTION: int sqlite3_column_count ( sqlite3_stmt* pStmt ) ; FUNCTION: void* sqlite3_column_blob ( sqlite3_stmt* pStmt, int col ) ; FUNCTION: int sqlite3_column_bytes ( sqlite3_stmt* pStmt, int col ) ; diff --git a/extra/db/sqlite/lib/lib.factor b/extra/db/sqlite/lib/lib.factor index 61070b078b..b6078fc983 100755 --- a/extra/db/sqlite/lib/lib.factor +++ b/extra/db/sqlite/lib/lib.factor @@ -33,7 +33,7 @@ IN: db.sqlite.lib : sqlite-prepare ( db sql -- handle ) dup length "void*" <c-object> "void*" <c-object> - [ sqlite3_prepare sqlite-check-result ] 2keep + [ sqlite3_prepare_v2 sqlite-check-result ] 2keep drop *void* ; : sqlite-bind-parameter-index ( handle name -- index ) @@ -114,6 +114,8 @@ IN: db.sqlite.lib : sqlite-finalize ( handle -- ) sqlite3_finalize sqlite-check-result ; : sqlite-reset ( handle -- ) sqlite3_reset sqlite-check-result ; +: sqlite-clear-bindings ( handle -- ) + sqlite3_clear_bindings sqlite-check-result ; : sqlite-#columns ( query -- int ) sqlite3_column_count ; : sqlite-column ( handle index -- string ) sqlite3_column_text ; : sqlite-column-name ( handle index -- string ) sqlite3_column_name ; diff --git a/extra/db/sqlite/sqlite.factor b/extra/db/sqlite/sqlite.factor index 093a705b0d..6dc394abd9 100755 --- a/extra/db/sqlite/sqlite.factor +++ b/extra/db/sqlite/sqlite.factor @@ -7,6 +7,7 @@ continuations db.sqlite.lib db.sqlite.ffi db.tuples words combinators.lib db.types combinators math.intervals io namespaces.lib accessors vectors math.ranges random math.bitfields.lib ; +USE: tools.walker IN: db.sqlite TUPLE: sqlite-db < db path ; @@ -43,17 +44,21 @@ M: sqlite-statement dispose ( statement -- ) M: sqlite-result-set dispose ( result-set -- ) f >>handle drop ; -: sqlite-bind ( triples handle -- ) - swap [ first3 sqlite-bind-type ] with each ; - : reset-statement ( statement -- ) sqlite-maybe-prepare handle>> sqlite-reset ; +: reset-bindings ( statement -- ) + sqlite-maybe-prepare + handle>> [ sqlite3_reset drop ] [ sqlite3_clear_bindings drop ] bi ; + +M: sqlite-statement low-level-bind ( statement -- ) + [ statement-bind-params ] [ statement-handle ] bi + swap [ first3 sqlite-bind-type ] with each ; + M: sqlite-statement bind-statement* ( statement -- ) sqlite-maybe-prepare - dup statement-bound? [ dup reset-statement ] when - [ statement-bind-params ] [ statement-handle ] bi - sqlite-bind ; + dup statement-bound? [ dup reset-bindings ] when + low-level-bind ; GENERIC: sqlite-bind-conversion ( tuple obj -- array ) @@ -140,13 +145,16 @@ M: sqlite-db <insert-native-statement> ( tuple -- statement ) dup 0% random-id-quot ] with-random ] curry - [ type>> ] bi 10 <generator-bind> 1, + [ type>> ] bi <generator-bind> 1, ] [ bind% ] if ] interleave ");" 0% - ] sqlite-make ; + ] sqlite-make + dup in-params>> [ generator-bind? ] contains? [ + make-retryable + ] when ; M: sqlite-db <insert-nonnative-statement> ( tuple -- statement ) <insert-native-statement> ; diff --git a/extra/db/tuples/tuples-tests.factor b/extra/db/tuples/tuples-tests.factor index 083cf059c9..2eb31ebe18 100755 --- a/extra/db/tuples/tuples-tests.factor +++ b/extra/db/tuples/tuples-tests.factor @@ -346,7 +346,7 @@ C: <secret> secret ] unit-test [ t ] [ - T{ secret } select-tuples length 3 = + T{ secret } select-tuples dup . length 3 = ] unit-test ; [ test-random-id ] test-sqlite diff --git a/extra/db/tuples/tuples.factor b/extra/db/tuples/tuples.factor index e0b4fce2f3..1b1e48ddee 100755 --- a/extra/db/tuples/tuples.factor +++ b/extra/db/tuples/tuples.factor @@ -1,7 +1,7 @@ ! Copyright (C) 2008 Doug Coleman. ! See http://factorcode.org/license.txt for BSD license. USING: arrays assocs classes db kernel namespaces -classes.tuple words sequences slots math +classes.tuple words sequences slots math accessors math.parser io prettyprint db.types continuations mirrors sequences.lib tools.walker combinators.lib ; IN: db.tuples @@ -49,6 +49,40 @@ HOOK: <select-by-slots-statement> db ( tuple class -- tuple ) HOOK: insert-tuple* db ( tuple statement -- ) +SINGLETON: retryable + +: make-retryable ( obj -- obj' ) + dup sequence? [ + [ make-retryable ] map + ] [ + retryable >>type + ] if ; + +: regenerate-params ( statement -- statement ) + dup + [ bind-params>> ] [ in-params>> ] bi + [ + dup generator-bind? [ + quot>> call over set-second + ] [ + drop + ] if + ] 2map >>bind-params ; + +: handle-random-id ( statement -- ) + dup in-params>> [ type>> +random-id+ = ] find drop >boolean [ + retryable >>type + random-id-quot >>quot + ] when drop ; + +M: retryable execute-statement* ( statement type -- ) + drop + [ + [ query-results dispose t ] + [ ] + [ regenerate-params bind-statement* f ] cleanup + ] curry 10 retry drop ; + : resulting-tuple ( row out-params -- tuple ) dup first sql-spec-class new [ [ diff --git a/extra/db/types/types.factor b/extra/db/types/types.factor index b8855ce296..9f111a42e4 100755 --- a/extra/db/types/types.factor +++ b/extra/db/types/types.factor @@ -19,7 +19,7 @@ TUPLE: sql-spec class slot-name column-name type primary-key modifiers ; TUPLE: literal-bind key type value ; C: <literal-bind> literal-bind -TUPLE: generator-bind key quot type retries ; +TUPLE: generator-bind key quot type ; C: <generator-bind> generator-bind SINGLETON: +native-id+ @@ -64,12 +64,6 @@ SYMBOLS: +autoincrement+ +serial+ +unique+ +default+ +null+ +not-null+ : relation? ( spec -- ? ) [ +has-many+ = ] deep-find ; -: handle-random-id ( statement -- ) - dup in-params>> [ type>> +random-id+ = ] find drop >boolean [ - retryable >>type - random-id-quot >>quot - ] when drop ; - SYMBOLS: INTEGER BIG-INTEGER SIGNED-BIG-INTEGER UNSIGNED-BIG-INTEGER DOUBLE REAL BOOLEAN TEXT VARCHAR DATE TIME DATETIME TIMESTAMP BLOB FACTOR-BLOB NULL ; From 4184a3ce549e1c21a8889d22ae77d4a5deff7edd Mon Sep 17 00:00:00 2001 From: Doug Coleman <doug.coleman@gmail.com> Date: Sat, 19 Apr 2008 23:18:12 -0500 Subject: [PATCH 09/20] partial conversion of postgres --- extra/db/postgresql/lib/lib.factor | 10 ++++++-- extra/db/postgresql/postgresql.factor | 35 ++++++++++++++++----------- extra/db/sqlite/sqlite.factor | 15 +++++++----- extra/db/tuples/tuples-tests.factor | 4 ++- extra/db/types/types.factor | 3 +-- 5 files changed, 42 insertions(+), 25 deletions(-) diff --git a/extra/db/postgresql/lib/lib.factor b/extra/db/postgresql/lib/lib.factor index bfe7dab3ce..cd3d619326 100755 --- a/extra/db/postgresql/lib/lib.factor +++ b/extra/db/postgresql/lib/lib.factor @@ -5,7 +5,7 @@ quotations sequences db.postgresql.ffi alien alien.c-types db.types tools.walker ascii splitting math.parser combinators libc shuffle calendar.format byte-arrays destructors prettyprint accessors strings serialize io.encodings.binary -io.streams.byte-array ; +io.streams.byte-array inspector ; IN: db.postgresql.lib : postgresql-result-error-message ( res -- str/f ) @@ -28,7 +28,13 @@ IN: db.postgresql.lib : postgresql-error ( res -- res ) dup [ postgresql-error-message throw ] unless ; -: postgresql-result-ok? ( n -- ? ) +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? ; diff --git a/extra/db/postgresql/postgresql.factor b/extra/db/postgresql/postgresql.factor index 9dfa123952..d0eb390888 100755 --- a/extra/db/postgresql/postgresql.factor +++ b/extra/db/postgresql/postgresql.factor @@ -5,7 +5,7 @@ kernel math math.parser namespaces prettyprint quotations sequences debugger db db.postgresql.lib db.postgresql.ffi db.tuples db.types tools.annotations math.ranges combinators sequences.lib classes locals words tools.walker -namespaces.lib accessors ; +namespaces.lib accessors random ; IN: db.postgresql TUPLE: postgresql-db < db @@ -43,10 +43,9 @@ M: postgresql-statement bind-statement* ( statement -- ) drop ; M: postgresql-statement bind-tuple ( tuple statement -- ) - [ - statement-in-params - [ sql-spec-slot-name swap get-slot-named ] with map - ] keep set-statement-bind-params ; + tuck in-params>> + [ slot-name>> swap get-slot-named ] with map + >>bind-params drop ; M: postgresql-result-set #rows ( result-set -- n ) handle>> PQntuples ; @@ -55,11 +54,11 @@ M: postgresql-result-set #columns ( result-set -- n ) handle>> PQnfields ; M: postgresql-result-set row-column ( result-set column -- obj ) - >r dup result-set-handle swap result-set-n r> pq-get-string ; + >r [ handle>> ] [ n>> ] bi r> pq-get-string ; M: postgresql-result-set row-column-typed ( result-set column -- obj ) dup pick result-set-out-params nth sql-spec-type - >r >r [ result-set-handle ] [ result-set-n ] bi r> r> postgresql-column-typed ; + >r >r [ handle>> ] [ result-set-n ] bi r> r> postgresql-column-typed ; M: postgresql-statement query-results ( query -- result-set ) dup statement-bind-params [ @@ -82,7 +81,7 @@ M: postgresql-statement dispose ( query -- ) f swap set-statement-handle ; M: postgresql-result-set dispose ( result-set -- ) - dup result-set-handle PQclear + dup handle>> PQclear 0 0 f roll { set-result-set-n set-result-set-max set-result-set-handle } set-slots ; @@ -90,7 +89,7 @@ M: postgresql-result-set dispose ( result-set -- ) M: postgresql-statement prepare-statement ( statement -- ) [ >r db get handle>> "" r> - dup statement-sql swap statement-in-params + [ sql>> ] [ in-params>> ] bi length f PQprepare postgresql-error ] keep set-statement-handle ; @@ -115,7 +114,10 @@ SYMBOL: postgresql-counter postgresql-counter [ inc ] keep get 0# ; M: postgresql-db bind% ( spec -- ) - 1, bind-name% ; + bind-name% 1, ; + +M: postgresql-db bind# ( spec obj -- ) + >r bind-name% f swap type>> r> <literal-bind> 1, ; : postgresql-make ( class quot -- ) >r sql-props r> @@ -125,11 +127,10 @@ M: postgresql-db bind% ( spec -- ) : create-table-sql ( class -- statement ) [ "create table " 0% 0% - "(" 0% - [ ", " 0% ] [ - dup sql-spec-column-name 0% + "(" 0% [ ", " 0% ] [ + dup column-name>> 0% " " 0% - dup sql-spec-type t lookup-type 0% + dup type>> t lookup-type 0% modifiers 0% ] interleave ");" 0% ] postgresql-make ; @@ -250,6 +251,7 @@ M: postgresql-db <select-by-slots-statement> ( tuple class -- statement ) M: postgresql-db type-table ( -- hash ) H{ { +native-id+ "integer" } + { +random-id+ "bigint" } { TEXT "text" } { VARCHAR "varchar" } { INTEGER "integer" } @@ -265,6 +267,7 @@ M: postgresql-db type-table ( -- hash ) M: postgresql-db create-type-table ( -- hash ) H{ { +native-id+ "serial primary key" } + { +random-id+ "bigint primary key" } } ; : postgresql-compound ( str n -- newstr ) @@ -286,12 +289,16 @@ M: postgresql-db modifier-table ( -- hashtable ) H{ { +native-id+ "primary key" } { +assigned-id+ "primary key" } + { +random-id+ "primary key" } { +foreign-id+ "references" } { +autoincrement+ "autoincrement" } { +unique+ "unique" } { +default+ "default" } { +null+ "null" } { +not-null+ "not null" } + { system-random-generator "" } + { secure-random-generator "" } + { random-generator "" } } ; M: postgresql-db compound-type ( str n -- newstr ) diff --git a/extra/db/sqlite/sqlite.factor b/extra/db/sqlite/sqlite.factor index 6dc394abd9..f361e18c48 100755 --- a/extra/db/sqlite/sqlite.factor +++ b/extra/db/sqlite/sqlite.factor @@ -110,10 +110,16 @@ M: sqlite-db begin-transaction ( -- ) "BEGIN" sql-command ; M: sqlite-db commit-transaction ( -- ) "COMMIT" sql-command ; M: sqlite-db rollback-transaction ( -- ) "ROLLBACK" sql-command ; + +: maybe-make-retryable ( statement -- statement ) + dup in-params>> [ generator-bind? ] contains? [ + make-retryable + ] when ; + : sqlite-make ( class quot -- ) >r sql-props r> [ 0 sql-counter rot with-variable ] { "" { } { } } nmake - <simple-statement> ; + <simple-statement> maybe-make-retryable ; M: sqlite-db create-sql-statement ( class -- statement ) [ @@ -124,7 +130,7 @@ M: sqlite-db create-sql-statement ( class -- statement ) dup type>> t lookup-type 0% modifiers 0% ] interleave ");" 0% - ] sqlite-make ; + ] sqlite-make dup sql>> . ; M: sqlite-db drop-sql-statement ( class -- statement ) [ "drop table " 0% 0% ";" 0% drop ] sqlite-make ; @@ -151,10 +157,7 @@ M: sqlite-db <insert-native-statement> ( tuple -- statement ) ] if ] interleave ");" 0% - ] sqlite-make - dup in-params>> [ generator-bind? ] contains? [ - make-retryable - ] when ; + ] sqlite-make ; M: sqlite-db <insert-nonnative-statement> ( tuple -- statement ) <insert-native-statement> ; diff --git a/extra/db/tuples/tuples-tests.factor b/extra/db/tuples/tuples-tests.factor index 2eb31ebe18..038197d864 100755 --- a/extra/db/tuples/tuples-tests.factor +++ b/extra/db/tuples/tuples-tests.factor @@ -346,13 +346,15 @@ C: <secret> secret ] unit-test [ t ] [ - T{ secret } select-tuples dup . length 3 = + T{ secret } select-tuples length 3 = ] unit-test ; [ test-random-id ] test-sqlite [ native-person-schema test-tuples ] test-sqlite [ assigned-person-schema test-tuples ] test-sqlite [ assigned-person-schema test-repeated-insert ] test-sqlite + +[ test-random-id ] test-postgresql [ native-person-schema test-tuples ] test-postgresql [ assigned-person-schema test-tuples ] test-postgresql [ assigned-person-schema test-repeated-insert ] test-postgresql diff --git a/extra/db/types/types.factor b/extra/db/types/types.factor index 9f111a42e4..41db970b12 100755 --- a/extra/db/types/types.factor +++ b/extra/db/types/types.factor @@ -110,8 +110,7 @@ ERROR: no-sql-type ; dup array? [ first lookup-type* ] [ - type-table at* - [ no-sql-type ] unless + type-table at* [ no-sql-type ] unless ] if ; : lookup-create-type ( obj -- str ) From 3be408184ce053ff31229cd0b693444ee220d4c1 Mon Sep 17 00:00:00 2001 From: Doug Coleman <doug.coleman@gmail.com> Date: Sat, 19 Apr 2008 23:41:48 -0500 Subject: [PATCH 10/20] remove most of the old setters --- extra/db/postgresql/lib/lib.factor | 36 +++++++--------- extra/db/postgresql/postgresql.factor | 60 ++++++++++++++------------- 2 files changed, 45 insertions(+), 51 deletions(-) diff --git a/extra/db/postgresql/lib/lib.factor b/extra/db/postgresql/lib/lib.factor index cd3d619326..bb4c6872fb 100755 --- a/extra/db/postgresql/lib/lib.factor +++ b/extra/db/postgresql/lib/lib.factor @@ -23,7 +23,7 @@ IN: db.postgresql.lib "\n" split [ [ blank? ] trim ] map "\n" join ; : postgresql-error-message ( -- str ) - db get db-handle (postgresql-error-message) ; + db get handle>> (postgresql-error-message) ; : postgresql-error ( res -- res ) dup [ postgresql-error-message throw ] unless ; @@ -43,7 +43,7 @@ M: postgresql-result-null summary ( obj -- str ) dup PQstatus zero? [ (postgresql-error-message) throw ] unless ; : do-postgresql-statement ( statement -- res ) - db get db-handle swap statement-sql PQexec dup postgresql-result-ok? [ + db get handle>> swap sql>> PQexec dup postgresql-result-ok? [ dup postgresql-result-error-message swap PQclear throw ] unless ; @@ -64,25 +64,19 @@ M: postgresql-result-null summary ( obj -- str ) } case ; : param-types ( statement -- seq ) - statement-in-params - [ sql-spec-type type>oid ] map - >c-uint-array ; + in-params>> [ type>> type>oid ] map >c-uint-array ; : malloc-byte-array/length [ malloc-byte-array dup free-always ] [ length ] bi ; - : param-values ( statement -- seq seq2 ) - [ statement-bind-params ] - [ statement-in-params ] bi + [ bind-params>> ] [ in-params>> ] bi [ - sql-spec-type { + type>> { { FACTOR-BLOB [ - dup [ - object>bytes - malloc-byte-array/length ] [ 0 ] if ] } - { BLOB [ - dup [ malloc-byte-array/length ] [ 0 ] if ] } + dup [ object>bytes malloc-byte-array/length ] [ 0 ] if + ] } + { BLOB [ dup [ malloc-byte-array/length ] [ 0 ] if ] } [ drop number>string* dup [ malloc-char-string dup free-always @@ -96,22 +90,20 @@ M: postgresql-result-null summary ( obj -- str ) ] if ; : param-formats ( statement -- seq ) - statement-in-params - [ sql-spec-type type>param-format ] map - >c-uint-array ; + in-params>> [ type>> type>param-format ] map >c-uint-array ; : do-postgresql-bound-statement ( statement -- res ) [ - >r db get db-handle r> + >r db get handle>> r> { - [ statement-sql ] - [ statement-bind-params length ] + [ sql>> ] + [ bind-params>> length ] [ param-types ] [ param-values ] [ param-formats ] } cleave 0 PQexecParams dup postgresql-result-ok? [ - dup postgresql-result-error-message swap PQclear throw + [ postgresql-result-error-message ] [ PQclear ] bi throw ] unless ] with-destructors ; @@ -120,7 +112,7 @@ M: postgresql-result-null summary ( obj -- str ) : pq-get-string ( handle row column -- obj ) 3dup PQgetvalue alien>char-string - dup "" = [ >r pq-get-is-null f r> ? ] [ 3nip ] if ; + dup empty? [ >r pq-get-is-null f r> ? ] [ 3nip ] if ; : pq-get-number ( handle row column -- obj ) pq-get-string dup [ string>number ] when ; diff --git a/extra/db/postgresql/postgresql.factor b/extra/db/postgresql/postgresql.factor index d0eb390888..f13bceddd3 100755 --- a/extra/db/postgresql/postgresql.factor +++ b/extra/db/postgresql/postgresql.factor @@ -57,11 +57,11 @@ M: postgresql-result-set row-column ( result-set column -- obj ) >r [ handle>> ] [ n>> ] bi r> pq-get-string ; M: postgresql-result-set row-column-typed ( result-set column -- obj ) - dup pick result-set-out-params nth sql-spec-type - >r >r [ handle>> ] [ result-set-n ] bi r> r> postgresql-column-typed ; + dup pick out-params>> nth type>> + >r >r [ handle>> ] [ n>> ] bi r> r> postgresql-column-typed ; M: postgresql-statement query-results ( query -- result-set ) - dup statement-bind-params [ + dup bind-params>> [ over [ bind-statement ] keep do-postgresql-bound-statement ] [ @@ -71,27 +71,29 @@ M: postgresql-statement query-results ( query -- result-set ) dup init-result-set ; M: postgresql-result-set advance-row ( result-set -- ) - dup result-set-n 1+ swap set-result-set-n ; + [ 1+ ] change-n drop ; M: postgresql-result-set more-rows? ( result-set -- ? ) - dup result-set-n swap result-set-max < ; + [ n>> ] [ max>> ] bi < ; M: postgresql-statement dispose ( query -- ) - dup statement-handle PQclear - f swap set-statement-handle ; + dup handle>> PQclear + f >>handle drop ; M: postgresql-result-set dispose ( result-set -- ) - dup handle>> PQclear - 0 0 f roll { - set-result-set-n set-result-set-max set-result-set-handle - } set-slots ; + [ handle>> PQclear ] + [ + 0 >>n + 0 >>max + f >>handle drop + ] bi ; M: postgresql-statement prepare-statement ( statement -- ) - [ - >r db get handle>> "" r> - [ sql>> ] [ in-params>> ] bi - length f PQprepare postgresql-error - ] keep set-statement-handle ; + dup + >r db get handle>> "" r> + [ sql>> ] [ in-params>> ] bi + length f PQprepare postgresql-error + >>handle drop ; M: postgresql-db <simple-statement> ( sql in out -- statement ) <postgresql-statement> ; @@ -111,7 +113,7 @@ M: postgresql-db rollback-transaction ( -- ) SYMBOL: postgresql-counter : bind-name% ( -- ) CHAR: $ 0, - postgresql-counter [ inc ] keep get 0# ; + postgresql-counter [ inc ] [ get 0# ] bi ; M: postgresql-db bind% ( spec -- ) bind-name% 1, ; @@ -142,7 +144,7 @@ M: postgresql-db bind# ( spec obj -- ) "(" 0% over [ "," 0% ] [ - sql-spec-type f lookup-type 0% + type>> f lookup-type 0% ] interleave ")" 0% " returns bigint as '" 0% @@ -150,7 +152,7 @@ M: postgresql-db bind# ( spec obj -- ) "insert into " 0% dup 0% "(" 0% - over [ ", " 0% ] [ sql-spec-column-name 0% ] interleave + over [ ", " 0% ] [ column-name>> 0% ] interleave ") values(" 0% swap [ ", " 0% ] [ drop bind-name% ] interleave "); " 0% @@ -169,7 +171,7 @@ M: postgresql-db create-sql-statement ( class -- seq ) "drop function add_" 0% 0% "(" 0% remove-id - [ ", " 0% ] [ sql-spec-type f lookup-type 0% ] interleave + [ ", " 0% ] [ type>> f lookup-type 0% ] interleave ");" 0% ] postgresql-make ; @@ -199,7 +201,7 @@ M: postgresql-db <insert-nonnative-statement> ( class -- statement ) [ "insert into " 0% 0% "(" 0% - dup [ ", " 0% ] [ sql-spec-column-name 0% ] interleave + dup [ ", " 0% ] [ column-name>> 0% ] interleave ")" 0% " values(" 0% @@ -216,10 +218,10 @@ M: postgresql-db <update-tuple-statement> ( class -- statement ) " set " 0% dup remove-id [ ", " 0% ] - [ dup sql-spec-column-name 0% " = " 0% bind% ] interleave + [ dup column-name>> 0% " = " 0% bind% ] interleave " where " 0% find-primary-key - dup sql-spec-column-name 0% " = " 0% bind% + dup column-name>> 0% " = " 0% bind% ] postgresql-make ; M: postgresql-db <delete-tuple-statement> ( class -- statement ) @@ -227,7 +229,7 @@ M: postgresql-db <delete-tuple-statement> ( class -- statement ) "delete from " 0% 0% " where " 0% find-primary-key - dup sql-spec-column-name 0% " = " 0% bind% + dup column-name>> 0% " = " 0% bind% ] postgresql-make ; M: postgresql-db <select-by-slots-statement> ( tuple class -- statement ) @@ -235,16 +237,16 @@ M: postgresql-db <select-by-slots-statement> ( tuple class -- statement ) ! tuple columns table "select " 0% over [ ", " 0% ] - [ dup sql-spec-column-name 0% 2, ] interleave + [ dup column-name>> 0% 2, ] interleave " from " 0% 0% - [ sql-spec-slot-name swap get-slot-named ] with subset + [ slot-name>> swap get-slot-named ] with subset dup empty? [ drop ] [ " where " 0% [ " and " 0% ] - [ dup sql-spec-column-name 0% " = " 0% bind% ] interleave + [ dup column-name>> 0% " = " 0% bind% ] interleave ] if ";" 0% ] postgresql-make ; @@ -276,8 +278,8 @@ M: postgresql-db create-type-table ( -- hash ) { "varchar" [ first number>string paren append ] } { "references" [ first2 >r [ unparse join-space ] keep db-columns r> - swap [ sql-spec-slot-name = ] with find nip - sql-spec-column-name paren append + swap [ slot-name>> = ] with find nip + column-name>> paren append ] } [ "no compound found" 3array throw ] } case ; From b0ddc983efc3ad7555fe4b77291a7e7bfcfc384e Mon Sep 17 00:00:00 2001 From: Doug Coleman <doug.coleman@gmail.com> Date: Sat, 19 Apr 2008 23:48:07 -0500 Subject: [PATCH 11/20] more refactoring --- extra/db/postgresql/lib/lib.factor | 3 +-- extra/db/postgresql/postgresql.factor | 8 +++++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/extra/db/postgresql/lib/lib.factor b/extra/db/postgresql/lib/lib.factor index bb4c6872fb..56bfc29be8 100755 --- a/extra/db/postgresql/lib/lib.factor +++ b/extra/db/postgresql/lib/lib.factor @@ -44,7 +44,7 @@ M: postgresql-result-null summary ( obj -- str ) : do-postgresql-statement ( statement -- res ) db get handle>> swap sql>> PQexec dup postgresql-result-ok? [ - dup postgresql-result-error-message swap PQclear throw + [ postgresql-result-error-message ] [ PQclear ] bi throw ] unless ; : type>oid ( symbol -- n ) @@ -165,4 +165,3 @@ M: postgresql-malloc-destructor dispose ( obj -- ) dup [ bytes>object ] when ] } [ no-sql-type ] } case ; - ! PQgetlength PQgetisnull diff --git a/extra/db/postgresql/postgresql.factor b/extra/db/postgresql/postgresql.factor index f13bceddd3..bcf71ea95f 100755 --- a/extra/db/postgresql/postgresql.factor +++ b/extra/db/postgresql/postgresql.factor @@ -53,12 +53,15 @@ M: postgresql-result-set #rows ( result-set -- n ) M: postgresql-result-set #columns ( result-set -- n ) handle>> PQnfields ; +: result-handle-n ( result-set -- handle n ) + [ handle>> ] [ n>> ] bi ; + M: postgresql-result-set row-column ( result-set column -- obj ) - >r [ handle>> ] [ n>> ] bi r> pq-get-string ; + >r result-handle-n r> pq-get-string ; M: postgresql-result-set row-column-typed ( result-set column -- obj ) dup pick out-params>> nth type>> - >r >r [ handle>> ] [ n>> ] bi r> r> postgresql-column-typed ; + >r >r result-handle-n r> r> postgresql-column-typed ; M: postgresql-statement query-results ( query -- result-set ) dup bind-params>> [ @@ -234,7 +237,6 @@ M: postgresql-db <delete-tuple-statement> ( class -- statement ) M: postgresql-db <select-by-slots-statement> ( tuple class -- statement ) [ - ! tuple columns table "select " 0% over [ ", " 0% ] [ dup column-name>> 0% 2, ] interleave From 7293a4f4f8013ce6af452e6921d46f40d91680b3 Mon Sep 17 00:00:00 2001 From: Doug Coleman <doug.coleman@gmail.com> Date: Sun, 20 Apr 2008 00:20:21 -0500 Subject: [PATCH 12/20] clean up the tuples tests --- extra/db/tuples/tuples-tests.factor | 36 ++++++++++++++++------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/extra/db/tuples/tuples-tests.factor b/extra/db/tuples/tuples-tests.factor index 038197d864..0648f9b254 100755 --- a/extra/db/tuples/tuples-tests.factor +++ b/extra/db/tuples/tuples-tests.factor @@ -212,9 +212,6 @@ TUPLE: serialize-me id data ; { T{ serialize-me f 1 H{ { 1 2 } } } } ] [ T{ serialize-me f 1 } select-tuples ] unit-test ; -[ test-serialize ] test-sqlite -! [ test-serialize ] test-postgresql - TUPLE: exam id name score ; : test-intervals ( -- ) @@ -288,8 +285,6 @@ TUPLE: exam id name score ; T{ exam f T{ range f 1 3 1 } } select-tuples ] unit-test ; -[ test-intervals ] test-sqlite - TUPLE: bignum-test id m n o ; : <bignum-test> ( m n o -- obj ) bignum-test new @@ -313,15 +308,6 @@ TUPLE: bignum-test id m n o ; -9223372036854775808 9223372036854775808 -9223372036854775808 } ] [ T{ bignum-test f 1 } select-tuple ] unit-test ; -[ test-bignum ] test-sqlite - -TUPLE: does-not-persist ; - -[ - [ does-not-persist create-sql-statement ] - [ class \ not-persistent = ] must-fail-with -] test-sqlite - TUPLE: secret n message ; C: <secret> secret @@ -349,15 +335,33 @@ C: <secret> secret T{ secret } select-tuples length 3 = ] unit-test ; -[ test-random-id ] test-sqlite [ native-person-schema test-tuples ] test-sqlite [ assigned-person-schema test-tuples ] test-sqlite [ assigned-person-schema test-repeated-insert ] test-sqlite +[ test-bignum ] test-sqlite +[ test-serialize ] test-sqlite +[ test-intervals ] test-sqlite +[ test-random-id ] test-sqlite -[ test-random-id ] test-postgresql [ native-person-schema test-tuples ] test-postgresql [ assigned-person-schema test-tuples ] test-postgresql [ assigned-person-schema test-repeated-insert ] test-postgresql +[ test-bignum ] test-sqlite +[ test-serialize ] test-postgresql +! [ test-intervals ] test-postgresql +! [ test-random-id ] test-postgresql + +TUPLE: does-not-persist ; + +[ + [ does-not-persist create-sql-statement ] + [ class \ not-persistent = ] must-fail-with +] test-sqlite + +[ + [ does-not-persist create-sql-statement ] + [ class \ not-persistent = ] must-fail-with +] test-postgresql ! \ insert-tuple must-infer ! \ update-tuple must-infer From 89a728f645cf92f9482716c811ef411edca78f3b Mon Sep 17 00:00:00 2001 From: Doug Coleman <doug.coleman@gmail.com> Date: Sun, 20 Apr 2008 00:52:05 -0500 Subject: [PATCH 13/20] about to consolidate sql types/create types/modifiers --- extra/db/postgresql/postgresql.factor | 30 +++++++++++---------------- extra/db/sqlite/sqlite.factor | 16 +++++++------- extra/db/types/types.factor | 7 +++---- 3 files changed, 22 insertions(+), 31 deletions(-) diff --git a/extra/db/postgresql/postgresql.factor b/extra/db/postgresql/postgresql.factor index bcf71ea95f..5f98720de0 100755 --- a/extra/db/postgresql/postgresql.factor +++ b/extra/db/postgresql/postgresql.factor @@ -93,7 +93,7 @@ M: postgresql-result-set dispose ( result-set -- ) M: postgresql-statement prepare-statement ( statement -- ) dup - >r db get handle>> "" r> + >r db get handle>> f r> [ sql>> ] [ in-params>> ] bi length f PQprepare postgresql-error >>handle drop ; @@ -274,21 +274,6 @@ M: postgresql-db create-type-table ( -- hash ) { +random-id+ "bigint primary key" } } ; -: postgresql-compound ( str n -- newstr ) - over { - { "default" [ first number>string join-space ] } - { "varchar" [ first number>string paren append ] } - { "references" [ - first2 >r [ unparse join-space ] keep db-columns r> - swap [ slot-name>> = ] with find nip - column-name>> paren append - ] } - [ "no compound found" 3array throw ] - } case ; - -M: postgresql-db compound-modifier ( str seq -- newstr ) - postgresql-compound ; - M: postgresql-db modifier-table ( -- hashtable ) H{ { +native-id+ "primary key" } @@ -305,5 +290,14 @@ M: postgresql-db modifier-table ( -- hashtable ) { random-generator "" } } ; -M: postgresql-db compound-type ( str n -- newstr ) - postgresql-compound ; +M: postgresql-db compound ( str obj -- str' ) + over { + { "default" [ first number>string join-space ] } + { "varchar" [ first number>string paren append ] } + { "references" [ + first2 >r [ unparse join-space ] keep db-columns r> + swap [ slot-name>> = ] with find nip + column-name>> paren append + ] } + [ "no compound found" 3array throw ] + } case ; diff --git a/extra/db/sqlite/sqlite.factor b/extra/db/sqlite/sqlite.factor index f361e18c48..fb3fbe92be 100755 --- a/extra/db/sqlite/sqlite.factor +++ b/extra/db/sqlite/sqlite.factor @@ -110,7 +110,6 @@ M: sqlite-db begin-transaction ( -- ) "BEGIN" sql-command ; M: sqlite-db commit-transaction ( -- ) "COMMIT" sql-command ; M: sqlite-db rollback-transaction ( -- ) "ROLLBACK" sql-command ; - : maybe-make-retryable ( statement -- statement ) dup in-params>> [ generator-bind? ] contains? [ make-retryable @@ -263,14 +262,6 @@ M: sqlite-db modifier-table ( -- hashtable ) { random-generator "" } } ; -M: sqlite-db compound-modifier ( str obj -- str' ) compound-type ; - -M: sqlite-db compound-type ( str seq -- str' ) - over { - { "default" [ first number>string join-space ] } - [ 2drop ] - } case ; - M: sqlite-db type-table ( -- assoc ) H{ { +native-id+ "integer primary key" } @@ -291,3 +282,10 @@ M: sqlite-db type-table ( -- assoc ) } ; M: sqlite-db create-type-table ( symbol -- str ) type-table ; + +M: sqlite-db compound ( str seq -- str' ) + over { + { "default" [ first number>string join-space ] } + [ 2drop ] + } case ; + diff --git a/extra/db/types/types.factor b/extra/db/types/types.factor index 41db970b12..80e11e7afb 100755 --- a/extra/db/types/types.factor +++ b/extra/db/types/types.factor @@ -8,10 +8,9 @@ classes.singleton accessors quotations random ; IN: db.types HOOK: modifier-table db ( -- hash ) -HOOK: compound-modifier db ( str seq -- hash ) +HOOK: compound db ( str obj -- hash ) HOOK: type-table db ( -- hash ) HOOK: create-type-table db ( -- hash ) -HOOK: compound-type db ( str n -- hash ) HOOK: random-id-quot db ( -- quot ) TUPLE: sql-spec class slot-name column-name type primary-key modifiers ; @@ -100,7 +99,7 @@ ERROR: unknown-modifier ; : lookup-modifier ( obj -- str ) { - { [ dup array? ] [ unclip lookup-modifier swap compound-modifier ] } + { [ dup array? ] [ unclip lookup-modifier swap compound ] } [ modifier-table at* [ unknown-modifier ] unless ] } cond ; @@ -115,7 +114,7 @@ ERROR: no-sql-type ; : lookup-create-type ( obj -- str ) dup array? [ - unclip lookup-create-type swap compound-type + unclip lookup-create-type swap compound ] [ dup create-type-table at* [ nip ] [ drop lookup-type* ] if From f5485c1a3dc729028ab21d2bd25a865051e5aee9 Mon Sep 17 00:00:00 2001 From: Doug Coleman <doug.coleman@gmail.com> Date: Sun, 20 Apr 2008 15:48:09 -0500 Subject: [PATCH 14/20] redo lookup-type --- extra/db/postgresql/postgresql.factor | 67 ++++++++++++--------------- extra/db/types/types.factor | 47 +++++++++---------- 2 files changed, 51 insertions(+), 63 deletions(-) diff --git a/extra/db/postgresql/postgresql.factor b/extra/db/postgresql/postgresql.factor index 5f98720de0..04a0a7143f 100755 --- a/extra/db/postgresql/postgresql.factor +++ b/extra/db/postgresql/postgresql.factor @@ -135,7 +135,7 @@ M: postgresql-db bind# ( spec obj -- ) "(" 0% [ ", " 0% ] [ dup column-name>> 0% " " 0% - dup type>> t lookup-type 0% + dup type>> lookup-create-type 0% modifiers 0% ] interleave ");" 0% ] postgresql-make ; @@ -147,7 +147,7 @@ M: postgresql-db bind# ( spec obj -- ) "(" 0% over [ "," 0% ] [ - type>> f lookup-type 0% + type>> lookup-type 0% ] interleave ")" 0% " returns bigint as '" 0% @@ -174,7 +174,7 @@ M: postgresql-db create-sql-statement ( class -- seq ) "drop function add_" 0% 0% "(" 0% remove-id - [ ", " 0% ] [ type>> f lookup-type 0% ] interleave + [ ", " 0% ] [ type>> lookup-type 0% ] interleave ");" 0% ] postgresql-make ; @@ -252,42 +252,33 @@ M: postgresql-db <select-by-slots-statement> ( tuple class -- statement ) ] if ";" 0% ] postgresql-make ; -M: postgresql-db type-table ( -- hash ) +M: postgresql-db persistent-table ( -- hashtable ) H{ - { +native-id+ "integer" } - { +random-id+ "bigint" } - { TEXT "text" } - { VARCHAR "varchar" } - { INTEGER "integer" } - { DOUBLE "real" } - { DATE "date" } - { TIME "time" } - { DATETIME "timestamp" } - { TIMESTAMP "timestamp" } - { BLOB "bytea" } - { FACTOR-BLOB "bytea" } - } ; - -M: postgresql-db create-type-table ( -- hash ) - H{ - { +native-id+ "serial primary key" } - { +random-id+ "bigint primary key" } - } ; - -M: postgresql-db modifier-table ( -- hashtable ) - H{ - { +native-id+ "primary key" } - { +assigned-id+ "primary key" } - { +random-id+ "primary key" } - { +foreign-id+ "references" } - { +autoincrement+ "autoincrement" } - { +unique+ "unique" } - { +default+ "default" } - { +null+ "null" } - { +not-null+ "not null" } - { system-random-generator "" } - { secure-random-generator "" } - { random-generator "" } + { +native-id+ { "integer" "serial primary key" f } } + { +assigned-id+ { f f "primary key" } } + { +random-id+ { "bigint" "bigint primary key" f } } + { TEXT { "text" f f } } + { 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 } } + { +foreign-id+ { f f "references" } } + { +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 } } } ; M: postgresql-db compound ( str obj -- str' ) diff --git a/extra/db/types/types.factor b/extra/db/types/types.factor index 80e11e7afb..a31713fa35 100755 --- a/extra/db/types/types.factor +++ b/extra/db/types/types.factor @@ -7,10 +7,9 @@ mirrors classes.tuple combinators calendar.format symbols classes.singleton accessors quotations random ; IN: db.types -HOOK: modifier-table db ( -- hash ) +HOOK: persistent-table db ( -- hash ) HOOK: compound db ( str obj -- hash ) -HOOK: type-table db ( -- hash ) -HOOK: create-type-table db ( -- hash ) + HOOK: random-id-quot db ( -- quot ) TUPLE: sql-spec class slot-name column-name type primary-key modifiers ; @@ -40,26 +39,26 @@ SYMBOLS: +autoincrement+ +serial+ +unique+ +default+ +null+ +not-null+ ] find nip [ system-random-generator ] unless* ; : primary-key? ( spec -- ? ) - sql-spec-primary-key +primary-key+? ; + primary-key>> +primary-key+? ; : native-id? ( spec -- ? ) - sql-spec-primary-key +native-id+? ; + primary-key>> +native-id+? ; : nonnative-id? ( spec -- ? ) - sql-spec-primary-key +nonnative-id+? ; + primary-key>> +nonnative-id+? ; : normalize-spec ( spec -- ) - dup sql-spec-type dup +primary-key+? [ - swap set-sql-spec-primary-key + dup type>> dup +primary-key+? [ + >>primary-key drop ] [ - drop dup sql-spec-modifiers [ + drop dup modifiers>> [ +primary-key+? ] deep-find - [ swap set-sql-spec-primary-key ] [ drop ] if* + [ >>primary-key drop ] [ drop ] if* ] if ; : find-primary-key ( specs -- obj ) - [ sql-spec-primary-key ] find nip ; + [ primary-key>> ] find nip ; : relation? ( spec -- ? ) [ +has-many+ = ] deep-find ; @@ -88,7 +87,7 @@ FACTOR-BLOB NULL ; [ relation? not ] subset ; : remove-id ( specs -- obj ) - [ sql-spec-primary-key not ] subset ; + [ primary-key>> not ] subset ; ! SQLite Types: http://www.sqlite.org/datatype3.html ! NULL INTEGER REAL TEXT BLOB @@ -100,29 +99,28 @@ ERROR: unknown-modifier ; : lookup-modifier ( obj -- str ) { { [ dup array? ] [ unclip lookup-modifier swap compound ] } - [ modifier-table at* [ unknown-modifier ] unless ] + [ persistent-table at* [ unknown-modifier ] unless third ] } cond ; ERROR: no-sql-type ; -: lookup-type* ( obj -- str ) +: (lookup-type) ( obj -- str ) + persistent-table at* [ no-sql-type ] unless ; + +: lookup-type ( obj -- str ) dup array? [ - first lookup-type* + unclip (lookup-type) first nip ] [ - type-table at* [ no-sql-type ] unless + (lookup-type) first ] if ; : lookup-create-type ( obj -- str ) dup array? [ - unclip lookup-create-type swap compound + unclip (lookup-type) second swap compound ] [ - dup create-type-table at* - [ nip ] [ drop lookup-type* ] if + (lookup-type) second ] if ; -: lookup-type ( obj create? -- str ) - [ lookup-create-type ] [ lookup-type* ] if ; - : single-quote ( str -- newstr ) "'" swap "'" 3append ; @@ -136,8 +134,7 @@ ERROR: no-sql-type ; " " swap 3append ; : modifiers ( spec -- str ) - sql-spec-modifiers - [ lookup-modifier ] map " " join + modifiers>> [ lookup-modifier ] map " " join dup empty? [ " " prepend ] unless ; HOOK: bind% db ( spec -- ) @@ -157,6 +154,6 @@ HOOK: bind# db ( spec obj -- ) : tuple>params ( specs tuple -- obj ) [ - >r dup sql-spec-type swap sql-spec-slot-name r> + >r [ type>> ] [ slot-name>> ] bi r> get-slot-named swap ] curry { } map>assoc ; From be8ac1d7b6a5c87d03ce3295ac1cf0ba40d38bef Mon Sep 17 00:00:00 2001 From: Doug Coleman <doug.coleman@gmail.com> Date: Sun, 20 Apr 2008 16:57:50 -0500 Subject: [PATCH 15/20] use new lookup for sqlite --- extra/db/sqlite/sqlite.factor | 60 +++++++++++++---------------- extra/db/tuples/tuples-tests.factor | 29 ++++++-------- 2 files changed, 37 insertions(+), 52 deletions(-) diff --git a/extra/db/sqlite/sqlite.factor b/extra/db/sqlite/sqlite.factor index fb3fbe92be..1bf3e28bb2 100755 --- a/extra/db/sqlite/sqlite.factor +++ b/extra/db/sqlite/sqlite.factor @@ -126,7 +126,7 @@ M: sqlite-db create-sql-statement ( class -- statement ) "(" 0% [ ", " 0% ] [ dup column-name>> 0% " " 0% - dup type>> t lookup-type 0% + dup type>> lookup-create-type 0% modifiers 0% ] interleave ");" 0% ] sqlite-make dup sql>> . ; @@ -247,42 +247,34 @@ M: sqlite-db <select-by-slots-statement> ( tuple class -- statement ) M: sqlite-db random-id-quot ( -- quot ) [ 64 [ 2^ random ] keep 1 - set-bit ] ; -M: sqlite-db modifier-table ( -- hashtable ) +M: sqlite-db persistent-table ( -- assoc ) H{ - { +native-id+ "primary key" } - { +assigned-id+ "primary key" } - { +random-id+ "primary key" } - { +autoincrement+ "autoincrement" } - { +unique+ "unique" } - { +default+ "default" } - { +null+ "null" } - { +not-null+ "not null" } - { system-random-generator "" } - { secure-random-generator "" } - { random-generator "" } + { +native-id+ { "integer primary key" "integer primary key" f } } + { +assigned-id+ { f f "primary key" } } + { +random-id+ { "integer primary key" "integer primary key" f } } + { INTEGER { "integer" "integer" "primary key" } } + { BIG-INTEGER { "bigint" "bigint" } } + { SIGNED-BIG-INTEGER { "bigint" "bigint" } } + { UNSIGNED-BIG-INTEGER { "bigint" "bigint" } } + { TEXT { "text" "text" } } + { VARCHAR { "text" "text" } } + { DATE { "date" "date" } } + { TIME { "time" "time" } } + { DATETIME { "datetime" "datetime" } } + { TIMESTAMP { "timestamp" "timestamp" } } + { DOUBLE { "real" "real" } } + { BLOB { "blob" "blob" } } + { FACTOR-BLOB { "blob" "blob" } } + { +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 } } } ; -M: sqlite-db type-table ( -- assoc ) - H{ - { +native-id+ "integer primary key" } - { +random-id+ "integer primary key" } - { INTEGER "integer" } - { BIG-INTEGER "bigint" } - { SIGNED-BIG-INTEGER "bigint" } - { UNSIGNED-BIG-INTEGER "bigint" } - { TEXT "text" } - { VARCHAR "text" } - { DATE "date" } - { TIME "time" } - { DATETIME "datetime" } - { TIMESTAMP "timestamp" } - { DOUBLE "real" } - { BLOB "blob" } - { FACTOR-BLOB "blob" } - } ; - -M: sqlite-db create-type-table ( symbol -- str ) type-table ; - M: sqlite-db compound ( str seq -- str' ) over { { "default" [ first number>string join-space ] } diff --git a/extra/db/tuples/tuples-tests.factor b/extra/db/tuples/tuples-tests.factor index 0648f9b254..c6870bd703 100755 --- a/extra/db/tuples/tuples-tests.factor +++ b/extra/db/tuples/tuples-tests.factor @@ -2,7 +2,7 @@ ! See http://factorcode.org/license.txt for BSD license. USING: io.files kernel tools.test db db.tuples classes db.types continuations namespaces math math.ranges -prettyprint tools.walker db.sqlite calendar sequences +prettyprint tools.walker calendar sequences db.sqlite math.intervals db.postgresql accessors random math.bitfields.lib ; IN: db.tuples.tests @@ -106,13 +106,6 @@ SYMBOL: person4 [ ] [ person drop-table ] unit-test ; -: make-native-person-table ( -- ) - [ person drop-table ] [ drop ] recover - person create-table - T{ person f f "billy" 200 3.14 } insert-tuple - T{ person f f "johnny" 10 3.14 } insert-tuple - ; - : native-person-schema ( -- ) person "PERSON" { @@ -192,7 +185,6 @@ TUPLE: annotation n paste-id summary author mode contents ; : test-repeated-insert [ ] [ person ensure-table ] unit-test - [ ] [ person1 get insert-tuple ] unit-test [ person1 get insert-tuple ] must-fail ; @@ -302,11 +294,12 @@ TUPLE: bignum-test id m n o ; } define-persistent [ bignum-test drop-table ] ignore-errors [ ] [ bignum-test ensure-table ] unit-test - [ ] [ 63 2^ dup dup <bignum-test> insert-tuple ] unit-test + [ ] [ 63 2^ 1- dup dup <bignum-test> insert-tuple ] unit-test ; - [ T{ bignum-test f 1 - -9223372036854775808 9223372036854775808 -9223372036854775808 } ] - [ T{ bignum-test f 1 } select-tuple ] unit-test ; + ! sqlite only + ! [ T{ bignum-test f 1 + ! -9223372036854775808 9223372036854775808 -9223372036854775808 } ] + ! [ T{ bignum-test f 1 } select-tuple ] unit-test ; TUPLE: secret n message ; C: <secret> secret @@ -346,17 +339,17 @@ C: <secret> secret [ native-person-schema test-tuples ] test-postgresql [ assigned-person-schema test-tuples ] test-postgresql [ assigned-person-schema test-repeated-insert ] test-postgresql -[ test-bignum ] test-sqlite +[ test-bignum ] test-postgresql [ test-serialize ] test-postgresql ! [ test-intervals ] test-postgresql ! [ test-random-id ] test-postgresql TUPLE: does-not-persist ; -[ - [ does-not-persist create-sql-statement ] - [ class \ not-persistent = ] must-fail-with -] test-sqlite +! [ + ! [ does-not-persist create-sql-statement ] + ! [ class \ not-persistent = ] must-fail-with +! ] test-sqlite [ [ does-not-persist create-sql-statement ] From 5dc015f0f563fdd3ba657b2de62e36f859539113 Mon Sep 17 00:00:00 2001 From: Doug Coleman <doug.coleman@gmail.com> Date: Sun, 20 Apr 2008 17:47:43 -0500 Subject: [PATCH 16/20] add queries.db to refactor some code --- extra/db/postgresql/postgresql.factor | 41 ++++++++------------------- extra/db/queries/queries.factor | 19 +++++++++++++ extra/db/sqlite/sqlite.factor | 28 +++++------------- 3 files changed, 38 insertions(+), 50 deletions(-) create mode 100644 extra/db/queries/queries.factor diff --git a/extra/db/postgresql/postgresql.factor b/extra/db/postgresql/postgresql.factor index 04a0a7143f..4b76804fc2 100755 --- a/extra/db/postgresql/postgresql.factor +++ b/extra/db/postgresql/postgresql.factor @@ -5,7 +5,7 @@ kernel math math.parser namespaces prettyprint quotations sequences debugger db db.postgresql.lib db.postgresql.ffi db.tuples db.types tools.annotations math.ranges combinators sequences.lib classes locals words tools.walker -namespaces.lib accessors random ; +namespaces.lib accessors random db.queries ; IN: db.postgresql TUPLE: postgresql-db < db @@ -15,9 +15,6 @@ TUPLE: postgresql-statement < statement ; TUPLE: postgresql-result-set < result-set ; -: <postgresql-statement> ( statement in out -- postgresql-statement ) - postgresql-statement construct-statement ; - M: postgresql-db make-db* ( seq tuple -- db ) >r first4 r> swap >>db @@ -99,19 +96,10 @@ M: postgresql-statement prepare-statement ( statement -- ) >>handle drop ; M: postgresql-db <simple-statement> ( sql in out -- statement ) - <postgresql-statement> ; + postgresql-statement construct-statement ; M: postgresql-db <prepared-statement> ( sql in out -- statement ) - <postgresql-statement> dup prepare-statement ; - -M: postgresql-db begin-transaction ( -- ) - "BEGIN" sql-command ; - -M: postgresql-db commit-transaction ( -- ) - "COMMIT" sql-command ; - -M: postgresql-db rollback-transaction ( -- ) - "ROLLBACK" sql-command ; + <simple-statement> dup prepare-statement ; SYMBOL: postgresql-counter : bind-name% ( -- ) @@ -124,11 +112,6 @@ M: postgresql-db bind% ( spec -- ) M: postgresql-db bind# ( spec obj -- ) >r bind-name% f swap type>> r> <literal-bind> 1, ; -: postgresql-make ( class quot -- ) - >r sql-props r> - [ postgresql-counter off call ] { "" { } { } } nmake - <postgresql-statement> ; inline - : create-table-sql ( class -- statement ) [ "create table " 0% 0% @@ -138,7 +121,7 @@ M: postgresql-db bind# ( spec obj -- ) dup type>> lookup-create-type 0% modifiers 0% ] interleave ");" 0% - ] postgresql-make ; + ] query-make ; : create-function-sql ( class -- statement ) [ @@ -160,7 +143,7 @@ M: postgresql-db bind# ( spec obj -- ) swap [ ", " 0% ] [ drop bind-name% ] interleave "); " 0% "select currval(''" 0% 0% "_id_seq'');' language sql;" 0% - ] postgresql-make ; + ] query-make ; M: postgresql-db create-sql-statement ( class -- seq ) [ @@ -176,12 +159,12 @@ M: postgresql-db create-sql-statement ( class -- seq ) remove-id [ ", " 0% ] [ type>> lookup-type 0% ] interleave ");" 0% - ] postgresql-make ; + ] query-make ; : drop-table-sql ( table -- statement ) [ "drop table " 0% 0% ";" 0% drop - ] postgresql-make ; + ] query-make ; M: postgresql-db drop-sql-statement ( class -- seq ) [ @@ -198,7 +181,7 @@ M: postgresql-db <insert-native-statement> ( class -- statement ) remove-id [ ", " 0% ] [ bind% ] interleave ");" 0% - ] postgresql-make ; + ] query-make ; M: postgresql-db <insert-nonnative-statement> ( class -- statement ) [ @@ -210,7 +193,7 @@ M: postgresql-db <insert-nonnative-statement> ( class -- statement ) " values(" 0% [ ", " 0% ] [ bind% ] interleave ");" 0% - ] postgresql-make ; + ] query-make ; M: postgresql-db insert-tuple* ( tuple statement -- ) query-modify-tuple ; @@ -225,7 +208,7 @@ M: postgresql-db <update-tuple-statement> ( class -- statement ) " where " 0% find-primary-key dup column-name>> 0% " = " 0% bind% - ] postgresql-make ; + ] query-make ; M: postgresql-db <delete-tuple-statement> ( class -- statement ) [ @@ -233,7 +216,7 @@ M: postgresql-db <delete-tuple-statement> ( class -- statement ) " where " 0% find-primary-key dup column-name>> 0% " = " 0% bind% - ] postgresql-make ; + ] query-make ; M: postgresql-db <select-by-slots-statement> ( tuple class -- statement ) [ @@ -250,7 +233,7 @@ M: postgresql-db <select-by-slots-statement> ( tuple class -- statement ) [ " and " 0% ] [ dup column-name>> 0% " = " 0% bind% ] interleave ] if ";" 0% - ] postgresql-make ; + ] query-make ; M: postgresql-db persistent-table ( -- hashtable ) H{ diff --git a/extra/db/queries/queries.factor b/extra/db/queries/queries.factor new file mode 100644 index 0000000000..d0b379ab76 --- /dev/null +++ b/extra/db/queries/queries.factor @@ -0,0 +1,19 @@ +! Copyright (C) 2008 Doug Coleman. +! See http://factorcode.org/license.txt for BSD license. +USING: accessors kernel namespaces sequences namespaces.lib db +db.tuples db.types ; +IN: db.queries + +: maybe-make-retryable ( statement -- statement ) + dup in-params>> [ generator-bind? ] contains? [ + make-retryable + ] when ; + +: query-make ( class quot -- ) + >r sql-props r> + [ 0 sql-counter rot with-variable ] { "" { } { } } nmake + <simple-statement> maybe-make-retryable ; + +M: db begin-transaction ( -- ) "BEGIN" sql-command ; +M: db commit-transaction ( -- ) "COMMIT" sql-command ; +M: db rollback-transaction ( -- ) "ROLLBACK" sql-command ; diff --git a/extra/db/sqlite/sqlite.factor b/extra/db/sqlite/sqlite.factor index 1bf3e28bb2..5ceff51325 100755 --- a/extra/db/sqlite/sqlite.factor +++ b/extra/db/sqlite/sqlite.factor @@ -6,7 +6,7 @@ prettyprint sequences strings classes.tuple alien.c-types continuations db.sqlite.lib db.sqlite.ffi db.tuples words combinators.lib db.types combinators math.intervals io namespaces.lib accessors vectors math.ranges random -math.bitfields.lib ; +math.bitfields.lib db.queries ; USE: tools.walker IN: db.sqlite @@ -106,20 +106,6 @@ M: sqlite-statement query-results ( query -- result-set ) dup handle>> sqlite-result-set construct-result-set dup advance-row ; -M: sqlite-db begin-transaction ( -- ) "BEGIN" sql-command ; -M: sqlite-db commit-transaction ( -- ) "COMMIT" sql-command ; -M: sqlite-db rollback-transaction ( -- ) "ROLLBACK" sql-command ; - -: maybe-make-retryable ( statement -- statement ) - dup in-params>> [ generator-bind? ] contains? [ - make-retryable - ] when ; - -: sqlite-make ( class quot -- ) - >r sql-props r> - [ 0 sql-counter rot with-variable ] { "" { } { } } nmake - <simple-statement> maybe-make-retryable ; - M: sqlite-db create-sql-statement ( class -- statement ) [ "create table " 0% 0% @@ -129,10 +115,10 @@ M: sqlite-db create-sql-statement ( class -- statement ) dup type>> lookup-create-type 0% modifiers 0% ] interleave ");" 0% - ] sqlite-make dup sql>> . ; + ] query-make dup sql>> . ; M: sqlite-db drop-sql-statement ( class -- statement ) - [ "drop table " 0% 0% ";" 0% drop ] sqlite-make ; + [ "drop table " 0% 0% ";" 0% drop ] query-make ; M: sqlite-db <insert-native-statement> ( tuple -- statement ) [ @@ -156,7 +142,7 @@ M: sqlite-db <insert-native-statement> ( tuple -- statement ) ] if ] interleave ");" 0% - ] sqlite-make ; + ] query-make ; M: sqlite-db <insert-nonnative-statement> ( tuple -- statement ) <insert-native-statement> ; @@ -222,7 +208,7 @@ M: sqlite-db <update-tuple-statement> ( class -- statement ) dup remove-id [ ", " 0% ] [ dup column-name>> 0% " = " 0% bind% ] interleave where-primary-key% - ] sqlite-make ; + ] query-make ; M: sqlite-db <delete-tuple-statement> ( specs table -- sql ) [ @@ -230,7 +216,7 @@ M: sqlite-db <delete-tuple-statement> ( specs table -- sql ) " where " 0% find-primary-key dup column-name>> 0% " = " 0% bind% - ] sqlite-make ; + ] query-make ; M: sqlite-db <select-by-slots-statement> ( tuple class -- statement ) [ @@ -242,7 +228,7 @@ M: sqlite-db <select-by-slots-statement> ( tuple class -- statement ) dupd [ slot-name>> swap get-slot-named ] with subset dup empty? [ 2drop ] [ where-clause ] if ";" 0% - ] sqlite-make ; + ] query-make ; M: sqlite-db random-id-quot ( -- quot ) [ 64 [ 2^ random ] keep 1 - set-bit ] ; From cd62fff6045932f2468f8ea7b5270a06b1ed4303 Mon Sep 17 00:00:00 2001 From: Doug Coleman <doug.coleman@gmail.com> Date: Sun, 20 Apr 2008 17:50:39 -0500 Subject: [PATCH 17/20] remove old code --- extra/db/postgresql/postgresql.factor | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/extra/db/postgresql/postgresql.factor b/extra/db/postgresql/postgresql.factor index 4b76804fc2..0401913a8d 100755 --- a/extra/db/postgresql/postgresql.factor +++ b/extra/db/postgresql/postgresql.factor @@ -101,10 +101,9 @@ M: postgresql-db <simple-statement> ( sql in out -- statement ) M: postgresql-db <prepared-statement> ( sql in out -- statement ) <simple-statement> dup prepare-statement ; -SYMBOL: postgresql-counter : bind-name% ( -- ) CHAR: $ 0, - postgresql-counter [ inc ] [ get 0# ] bi ; + sql-counter [ inc ] [ get 0# ] bi ; M: postgresql-db bind% ( spec -- ) bind-name% 1, ; From dfe736a8b98b522797004f510fbb10f6e26525cb Mon Sep 17 00:00:00 2001 From: Doug Coleman <doug.coleman@gmail.com> Date: Sun, 20 Apr 2008 17:55:08 -0500 Subject: [PATCH 18/20] eliminate tons of code duplication --- extra/db/postgresql/postgresql.factor | 20 ------------------ extra/db/queries/queries.factor | 29 +++++++++++++++++++++++++-- extra/db/sqlite/sqlite.factor | 25 ----------------------- 3 files changed, 27 insertions(+), 47 deletions(-) diff --git a/extra/db/postgresql/postgresql.factor b/extra/db/postgresql/postgresql.factor index 0401913a8d..fc3b08d9b9 100755 --- a/extra/db/postgresql/postgresql.factor +++ b/extra/db/postgresql/postgresql.factor @@ -197,26 +197,6 @@ M: postgresql-db <insert-nonnative-statement> ( class -- statement ) M: postgresql-db insert-tuple* ( tuple statement -- ) query-modify-tuple ; -M: postgresql-db <update-tuple-statement> ( class -- statement ) - [ - "update " 0% 0% - " set " 0% - dup remove-id - [ ", " 0% ] - [ dup column-name>> 0% " = " 0% bind% ] interleave - " where " 0% - find-primary-key - dup column-name>> 0% " = " 0% bind% - ] query-make ; - -M: postgresql-db <delete-tuple-statement> ( class -- statement ) - [ - "delete from " 0% 0% - " where " 0% - find-primary-key - dup column-name>> 0% " = " 0% bind% - ] query-make ; - M: postgresql-db <select-by-slots-statement> ( tuple class -- statement ) [ "select " 0% diff --git a/extra/db/queries/queries.factor b/extra/db/queries/queries.factor index d0b379ab76..79c1909c05 100644 --- a/extra/db/queries/queries.factor +++ b/extra/db/queries/queries.factor @@ -1,7 +1,7 @@ ! Copyright (C) 2008 Doug Coleman. ! See http://factorcode.org/license.txt for BSD license. -USING: accessors kernel namespaces sequences namespaces.lib db -db.tuples db.types ; +USING: accessors kernel math namespaces sequences random +math.bitfields.lib namespaces.lib db db.tuples db.types ; IN: db.queries : maybe-make-retryable ( statement -- statement ) @@ -17,3 +17,28 @@ IN: db.queries M: db begin-transaction ( -- ) "BEGIN" sql-command ; M: db commit-transaction ( -- ) "COMMIT" sql-command ; M: db rollback-transaction ( -- ) "ROLLBACK" sql-command ; + +: where-primary-key% ( specs -- ) + " where " 0% + find-primary-key dup column-name>> 0% " = " 0% bind% ; + +M: db <update-tuple-statement> ( class -- statement ) + [ + "update " 0% 0% + " set " 0% + dup remove-id + [ ", " 0% ] [ dup column-name>> 0% " = " 0% bind% ] interleave + where-primary-key% + ] query-make ; + +M: db <delete-tuple-statement> ( specs table -- sql ) + [ + "delete from " 0% 0% + " where " 0% + find-primary-key + dup column-name>> 0% " = " 0% bind% + ] query-make ; + +M: db random-id-quot ( -- quot ) + [ 63 [ 2^ random ] keep 1 - set-bit ] ; + diff --git a/extra/db/sqlite/sqlite.factor b/extra/db/sqlite/sqlite.factor index 5ceff51325..b948fb1696 100755 --- a/extra/db/sqlite/sqlite.factor +++ b/extra/db/sqlite/sqlite.factor @@ -156,10 +156,6 @@ M: sqlite-db bind# ( spec obj -- ) M: sqlite-db bind% ( spec -- ) dup 1, column-name>> ":" prepend 0% ; -: where-primary-key% ( specs -- ) - " where " 0% - find-primary-key dup column-name>> 0% " = " 0% bind% ; - GENERIC: where ( specs obj -- ) : interval-comparison ( ? str -- str ) @@ -200,24 +196,6 @@ M: string where ( spec obj -- ) object-where ; 2dup slot-name>> swap get-slot-named where ] interleave drop ; -M: sqlite-db <update-tuple-statement> ( class -- statement ) - [ - "update " 0% - 0% - " set " 0% - dup remove-id - [ ", " 0% ] [ dup column-name>> 0% " = " 0% bind% ] interleave - where-primary-key% - ] query-make ; - -M: sqlite-db <delete-tuple-statement> ( specs table -- sql ) - [ - "delete from " 0% 0% - " where " 0% - find-primary-key - dup column-name>> 0% " = " 0% bind% - ] query-make ; - M: sqlite-db <select-by-slots-statement> ( tuple class -- statement ) [ "select " 0% @@ -230,9 +208,6 @@ M: sqlite-db <select-by-slots-statement> ( tuple class -- statement ) dup empty? [ 2drop ] [ where-clause ] if ";" 0% ] query-make ; -M: sqlite-db random-id-quot ( -- quot ) - [ 64 [ 2^ random ] keep 1 - set-bit ] ; - M: sqlite-db persistent-table ( -- assoc ) H{ { +native-id+ { "integer primary key" "integer primary key" f } } From 4da64986f3503902136e8492842b6297006d635a Mon Sep 17 00:00:00 2001 From: Doug Coleman <doug.coleman@gmail.com> Date: Mon, 21 Apr 2008 00:13:12 -0500 Subject: [PATCH 19/20] fix postgresql for new alien accessors --- extra/db/postgresql/lib/lib.factor | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/extra/db/postgresql/lib/lib.factor b/extra/db/postgresql/lib/lib.factor index 56bfc29be8..3fc95fcafe 100755 --- a/extra/db/postgresql/lib/lib.factor +++ b/extra/db/postgresql/lib/lib.factor @@ -4,8 +4,8 @@ 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 shuffle calendar.format byte-arrays destructors prettyprint -accessors strings serialize io.encodings.binary -io.streams.byte-array inspector ; +accessors strings serialize io.encodings.binary io.encodings.utf8 +alien.strings io.streams.byte-array inspector ; IN: db.postgresql.lib : postgresql-result-error-message ( res -- str/f ) @@ -79,7 +79,7 @@ M: postgresql-result-null summary ( obj -- str ) { BLOB [ dup [ malloc-byte-array/length ] [ 0 ] if ] } [ drop number>string* dup [ - malloc-char-string dup free-always + utf8 malloc-string dup free-always ] when 0 ] } case 2array @@ -111,7 +111,7 @@ M: postgresql-result-null summary ( obj -- str ) PQgetisnull 1 = ; : pq-get-string ( handle row column -- obj ) - 3dup PQgetvalue alien>char-string + 3dup PQgetvalue utf8 alien>string dup empty? [ >r pq-get-is-null f r> ? ] [ 3nip ] if ; : pq-get-number ( handle row column -- obj ) From 411fb2f97d871b4c40fedcd0915a580f7bfd8499 Mon Sep 17 00:00:00 2001 From: Doug Coleman <doug.coleman@gmail.com> Date: Mon, 21 Apr 2008 00:45:14 -0500 Subject: [PATCH 20/20] postgresql interval and range and sequence queries --- extra/db/postgresql/postgresql.factor | 32 +++++++-------- extra/db/queries/queries.factor | 56 ++++++++++++++++++++++++++- extra/db/sqlite/sqlite.factor | 52 ------------------------- extra/db/tuples/tuples-tests.factor | 2 +- 4 files changed, 69 insertions(+), 73 deletions(-) diff --git a/extra/db/postgresql/postgresql.factor b/extra/db/postgresql/postgresql.factor index fc3b08d9b9..057c5f5168 100755 --- a/extra/db/postgresql/postgresql.factor +++ b/extra/db/postgresql/postgresql.factor @@ -39,9 +39,20 @@ M: postgresql-db dispose ( db -- ) M: postgresql-statement bind-statement* ( statement -- ) drop ; +GENERIC: postgresql-bind-conversion + +M: sql-spec postgresql-bind-conversion ( tuple spec -- array ) + slot-name>> swap get-slot-named ; + +M: literal-bind postgresql-bind-conversion ( tuple literal-bind -- array ) + nip value>> ; + +M: generator-bind postgresql-bind-conversion ( tuple generate-bind -- array ) + nip quot>> call ; + M: postgresql-statement bind-tuple ( tuple statement -- ) tuck in-params>> - [ slot-name>> swap get-slot-named ] with map + [ postgresql-bind-conversion ] with map >>bind-params drop ; M: postgresql-result-set #rows ( result-set -- n ) @@ -197,29 +208,12 @@ M: postgresql-db <insert-nonnative-statement> ( class -- statement ) M: postgresql-db insert-tuple* ( tuple statement -- ) query-modify-tuple ; -M: postgresql-db <select-by-slots-statement> ( tuple class -- statement ) - [ - "select " 0% - over [ ", " 0% ] - [ dup column-name>> 0% 2, ] interleave - - " from " 0% 0% - [ slot-name>> swap get-slot-named ] with subset - dup empty? [ - drop - ] [ - " where " 0% - [ " and " 0% ] - [ dup column-name>> 0% " = " 0% bind% ] interleave - ] if ";" 0% - ] query-make ; - M: postgresql-db persistent-table ( -- hashtable ) H{ { +native-id+ { "integer" "serial primary key" f } } { +assigned-id+ { f f "primary key" } } { +random-id+ { "bigint" "bigint primary key" f } } - { TEXT { "text" f f } } + { TEXT { "text" "text" f } } { VARCHAR { "varchar" "varchar" f } } { INTEGER { "integer" "integer" f } } { BIG-INTEGER { "bigint" "bigint" f } } diff --git a/extra/db/queries/queries.factor b/extra/db/queries/queries.factor index 79c1909c05..7053eefba1 100644 --- a/extra/db/queries/queries.factor +++ b/extra/db/queries/queries.factor @@ -1,7 +1,9 @@ ! Copyright (C) 2008 Doug Coleman. ! See http://factorcode.org/license.txt for BSD license. USING: accessors kernel math namespaces sequences random -math.bitfields.lib namespaces.lib db db.tuples db.types ; +strings +math.bitfields.lib namespaces.lib db db.tuples db.types +math.intervals ; IN: db.queries : maybe-make-retryable ( statement -- statement ) @@ -42,3 +44,55 @@ M: db <delete-tuple-statement> ( specs table -- sql ) M: db random-id-quot ( -- quot ) [ 63 [ 2^ random ] keep 1 - set-bit ] ; +GENERIC: where ( specs obj -- ) + +: interval-comparison ( ? str -- str ) + "from" = " >" " <" ? swap [ "= " append ] when ; + +: where-interval ( spec obj from/to -- ) + pick column-name>> 0% + >r first2 r> interval-comparison 0% + bind# ; + +: in-parens ( quot -- ) + "(" 0% call ")" 0% ; inline + +M: interval where ( spec obj -- ) + [ + [ from>> "from" where-interval " and " 0% ] + [ to>> "to" where-interval ] 2bi + ] in-parens ; + +M: sequence where ( spec obj -- ) + [ + [ " or " 0% ] [ dupd where ] interleave drop + ] in-parens ; + +: object-where ( spec obj -- ) + over column-name>> 0% " = " 0% bind# ; + +M: object where ( spec obj -- ) object-where ; + +M: integer where ( spec obj -- ) object-where ; + +M: string where ( spec obj -- ) object-where ; + +: where-clause ( tuple specs -- ) + " where " 0% [ + " and " 0% + ] [ + 2dup slot-name>> swap get-slot-named where + ] interleave drop ; + +M: db <select-by-slots-statement> ( tuple class -- statement ) + [ + "select " 0% + over [ ", " 0% ] + [ dup column-name>> 0% 2, ] interleave + + " from " 0% 0% + dupd + [ slot-name>> swap get-slot-named ] with subset + dup empty? [ 2drop ] [ where-clause ] if ";" 0% + ] query-make ; + diff --git a/extra/db/sqlite/sqlite.factor b/extra/db/sqlite/sqlite.factor index b948fb1696..f4247cf6d8 100755 --- a/extra/db/sqlite/sqlite.factor +++ b/extra/db/sqlite/sqlite.factor @@ -156,58 +156,6 @@ M: sqlite-db bind# ( spec obj -- ) M: sqlite-db bind% ( spec -- ) dup 1, column-name>> ":" prepend 0% ; -GENERIC: where ( specs obj -- ) - -: interval-comparison ( ? str -- str ) - "from" = " >" " <" ? swap [ "= " append ] when ; - -: where-interval ( spec obj from/to -- ) - pick column-name>> 0% - >r first2 r> interval-comparison 0% - bind# ; - -: in-parens ( quot -- ) - "(" 0% call ")" 0% ; inline - -M: interval where ( spec obj -- ) - [ - [ from>> "from" where-interval " and " 0% ] - [ to>> "to" where-interval ] 2bi - ] in-parens ; - -M: sequence where ( spec obj -- ) - [ - [ " or " 0% ] [ dupd where ] interleave drop - ] in-parens ; - -: object-where ( spec obj -- ) - over column-name>> 0% " = " 0% bind# ; - -M: object where ( spec obj -- ) object-where ; - -M: integer where ( spec obj -- ) object-where ; - -M: string where ( spec obj -- ) object-where ; - -: where-clause ( tuple specs -- ) - " where " 0% [ - " and " 0% - ] [ - 2dup slot-name>> swap get-slot-named where - ] interleave drop ; - -M: sqlite-db <select-by-slots-statement> ( tuple class -- statement ) - [ - "select " 0% - over [ ", " 0% ] - [ dup column-name>> 0% 2, ] interleave - - " from " 0% 0% - dupd - [ slot-name>> swap get-slot-named ] with subset - dup empty? [ 2drop ] [ where-clause ] if ";" 0% - ] query-make ; - M: sqlite-db persistent-table ( -- assoc ) H{ { +native-id+ { "integer primary key" "integer primary key" f } } diff --git a/extra/db/tuples/tuples-tests.factor b/extra/db/tuples/tuples-tests.factor index c6870bd703..026370e806 100755 --- a/extra/db/tuples/tuples-tests.factor +++ b/extra/db/tuples/tuples-tests.factor @@ -341,7 +341,7 @@ C: <secret> secret [ assigned-person-schema test-repeated-insert ] test-postgresql [ test-bignum ] test-postgresql [ test-serialize ] test-postgresql -! [ test-intervals ] test-postgresql +[ test-intervals ] test-postgresql ! [ test-random-id ] test-postgresql TUPLE: does-not-persist ;