From b54833c728fa0a0bc40e236fa7287b78e609364f Mon Sep 17 00:00:00 2001
From: Doug Coleman <doug.coleman@gmail.com>
Date: Fri, 20 Feb 2009 20:11:26 -0600
Subject: [PATCH 1/3] remove a bunch of trigger deletion code -- triggers get
 deleted when tables are dropped

---
 basis/db/sqlite/sqlite.factor | 74 ++++++++---------------------------
 1 file changed, 16 insertions(+), 58 deletions(-)

diff --git a/basis/db/sqlite/sqlite.factor b/basis/db/sqlite/sqlite.factor
index 19cfc5d0b7..a4adba3473 100755
--- a/basis/db/sqlite/sqlite.factor
+++ b/basis/db/sqlite/sqlite.factor
@@ -223,13 +223,6 @@ M: sqlite-db-connection persistent-table ( -- assoc )
     "> interpolate
     ] with-string-writer ;
 
-: drop-insert-trigger ( -- string )
-    [
-        <"
-            DROP TRIGGER fki_${table-name}_${table-id}_${foreign-table-name}_${foreign-table-id}_id;
-        "> interpolate
-    ] with-string-writer ;
-
 : update-trigger ( -- string )
     [
     <"
@@ -255,13 +248,6 @@ M: sqlite-db-connection persistent-table ( -- assoc )
     "> interpolate
     ] with-string-writer ;
 
-: drop-update-trigger ( -- string )
-    [
-        <"
-            DROP TRIGGER fku_${table-name}_${table-id}_${foreign-table-name}_${foreign-table-id}_id;
-        "> interpolate
-    ] with-string-writer ;
-
 : delete-trigger-restrict ( -- string )
     [
     <"
@@ -274,13 +260,6 @@ M: sqlite-db-connection persistent-table ( -- assoc )
     "> interpolate
     ] with-string-writer ;
 
-: drop-delete-trigger-restrict ( -- string )
-    [
-        <"
-            DROP TRIGGER fkd_${table-name}_${table-id}_${foreign-table-name}_${foreign-table-id}_id;
-        "> interpolate
-    ] with-string-writer ;
-
 : delete-trigger-cascade ( -- string )
     [
     <"
@@ -292,13 +271,6 @@ M: sqlite-db-connection persistent-table ( -- assoc )
     "> interpolate
     ] with-string-writer ;
 
-: drop-delete-trigger-cascade ( -- string )
-    [
-        <"
-            DROP TRIGGER fkd_${table-name}_${table-id}_${foreign-table-name}_${foreign-table-id}_id;
-        "> interpolate
-    ] with-string-writer ;
-
 : can-be-null? ( -- ? )
     "sql-spec" get modifiers>> [ +not-null+ = ] any? not ;
 
@@ -322,33 +294,22 @@ M: sqlite-db-connection persistent-table ( -- assoc )
         delete-trigger-restrict sqlite-trigger,
     ] if ;
 
-: drop-sqlite-triggers ( -- )
-    drop-insert-trigger sqlite-trigger,
-    drop-update-trigger sqlite-trigger,
-    delete-cascade? [
-        drop-delete-trigger-cascade sqlite-trigger,
-    ] [
-        drop-delete-trigger-restrict sqlite-trigger,
-    ] if ;
-
-: db-triggers ( sql-specs word -- )
-    '[
-        [ modifiers>> [ +foreign-id+ = ] deep-any? ] filter
+: create-db-triggers ( sql-specs -- )
+    [ modifiers>> [ +foreign-id+ = ] deep-any? ] filter
+    [
+        [ class>> db-table-name "db-table" set ]
         [
-            [ class>> db-table-name "db-table" set ]
+            [ "sql-spec" set ]
+            [ column-name>> "table-id" set ]
+            [ ] tri
+            modifiers>> [ [ +foreign-id+ = ] deep-any? ] filter
             [
-                [ "sql-spec" set ]
-                [ column-name>> "table-id" set ]
-                [ ] tri
-                modifiers>> [ [ +foreign-id+ = ] deep-any? ] filter
-                [
-                    [ second db-table-name "foreign-table-name" set ]
-                    [ third "foreign-table-id" set ] bi
-                    _ execute
-                ] each
-            ] bi
-        ] each
-    ] call ; inline
+                [ second db-table-name "foreign-table-name" set ]
+                [ third "foreign-table-id" set ] bi
+                create-sqlite-triggers
+            ] each
+        ] bi
+    ] each ;
 
 : sqlite-create-table ( sql-specs class-name -- )
     [
@@ -373,15 +334,12 @@ M: sqlite-db-connection persistent-table ( -- assoc )
 
 M: sqlite-db-connection create-sql-statement ( class -- statement )
     [
-        ! specs name
         [ sqlite-create-table ]
-        [ drop \ create-sqlite-triggers db-triggers ] 2bi
+        [ drop create-db-triggers ] 2bi
     ] query-make ;
 
 M: sqlite-db-connection drop-sql-statement ( class -- statements )
-    [
-        nip "drop table " 0% 0% ";" 0%
-    ] query-make ;
+    [ nip "drop table " 0% 0% ";" 0% ] query-make ;
 
 M: sqlite-db-connection compound ( string seq -- new-string )
     over {

From 985597ba6858552d22294dc40e5794170fdaa3d6 Mon Sep 17 00:00:00 2001
From: Doug Coleman <doug.coleman@gmail.com>
Date: Fri, 20 Feb 2009 20:40:17 -0600
Subject: [PATCH 2/3] add error handling to sqlite, postgresql is next.
 switching computers..

---
 basis/db/db.factor                            |  8 +++--
 basis/db/errors/errors.factor                 | 12 ++++++-
 basis/db/errors/postgresql/authors.txt        |  1 +
 .../errors/postgresql/postgresql-tests.factor |  4 +++
 basis/db/errors/postgresql/postgresql.factor  |  7 +++++
 basis/db/errors/sqlite/authors.txt            |  1 +
 basis/db/errors/sqlite/sqlite-tests.factor    | 26 ++++++++++++++++
 basis/db/errors/sqlite/sqlite.factor          | 31 +++++++++++++++++++
 basis/db/postgresql/postgresql-tests.factor   | 22 ++++++-------
 9 files changed, 98 insertions(+), 14 deletions(-)
 create mode 100644 basis/db/errors/postgresql/authors.txt
 create mode 100644 basis/db/errors/postgresql/postgresql-tests.factor
 create mode 100644 basis/db/errors/postgresql/postgresql.factor
 create mode 100644 basis/db/errors/sqlite/authors.txt
 create mode 100644 basis/db/errors/sqlite/sqlite-tests.factor
 create mode 100644 basis/db/errors/sqlite/sqlite.factor

diff --git a/basis/db/db.factor b/basis/db/db.factor
index 0b18044f2b..eb06f0c894 100644
--- a/basis/db/db.factor
+++ b/basis/db/db.factor
@@ -2,7 +2,7 @@
 ! See http://factorcode.org/license.txt for BSD license.
 USING: arrays assocs classes continuations destructors kernel math
 namespaces sequences classes.tuple words strings
-tools.walker accessors combinators fry ;
+tools.walker accessors combinators fry db.errors ;
 IN: db
 
 <PRIVATE
@@ -77,7 +77,11 @@ GENERIC: bind-tuple ( tuple statement -- )
 GENERIC: execute-statement* ( statement type -- )
 
 M: object execute-statement* ( statement type -- )
-    drop query-results dispose ;
+    '[
+        _ _ drop query-results dispose
+    ] [
+        parse-db-error rethrow
+    ] recover ;
 
 : execute-one-statement ( statement -- )
     dup type>> execute-statement* ;
diff --git a/basis/db/errors/errors.factor b/basis/db/errors/errors.factor
index da6301639f..1d48012cf9 100644
--- a/basis/db/errors/errors.factor
+++ b/basis/db/errors/errors.factor
@@ -1,10 +1,20 @@
 ! Copyright (C) 2008 Doug Coleman.
 ! See http://factorcode.org/license.txt for BSD license.
-USING: kernel ;
+USING: kernel db.private ;
 IN: db.errors
 
+HOOK: parse-db-error db-connection ( error -- error' )
+
 ERROR: db-error ;
 ERROR: sql-error ;
 
 ERROR: table-exists ;
 ERROR: bad-schema ;
+
+ERROR: sql-syntax-error error ;
+
+ERROR: sql-table-exists table ;
+C: <sql-table-exists> sql-table-exists
+
+ERROR: sql-table-missing table ;
+C: <sql-table-missing> sql-table-missing
diff --git a/basis/db/errors/postgresql/authors.txt b/basis/db/errors/postgresql/authors.txt
new file mode 100644
index 0000000000..b4bd0e7b35
--- /dev/null
+++ b/basis/db/errors/postgresql/authors.txt
@@ -0,0 +1 @@
+Doug Coleman
\ No newline at end of file
diff --git a/basis/db/errors/postgresql/postgresql-tests.factor b/basis/db/errors/postgresql/postgresql-tests.factor
new file mode 100644
index 0000000000..59b9bfe4a8
--- /dev/null
+++ b/basis/db/errors/postgresql/postgresql-tests.factor
@@ -0,0 +1,4 @@
+! Copyright (C) 2009 Doug Coleman.
+! See http://factorcode.org/license.txt for BSD license.
+USING: tools.test db.errors.postgresql ;
+IN: db.errors.postgresql.tests
diff --git a/basis/db/errors/postgresql/postgresql.factor b/basis/db/errors/postgresql/postgresql.factor
new file mode 100644
index 0000000000..9d88c96cb1
--- /dev/null
+++ b/basis/db/errors/postgresql/postgresql.factor
@@ -0,0 +1,7 @@
+! Copyright (C) 2009 Doug Coleman.
+! See http://factorcode.org/license.txt for BSD license.
+USING: ;
+IN: db.errors.postgresql
+
+M: postgresql-db-connection parse-db-error
+    ;
\ No newline at end of file
diff --git a/basis/db/errors/sqlite/authors.txt b/basis/db/errors/sqlite/authors.txt
new file mode 100644
index 0000000000..b4bd0e7b35
--- /dev/null
+++ b/basis/db/errors/sqlite/authors.txt
@@ -0,0 +1 @@
+Doug Coleman
\ No newline at end of file
diff --git a/basis/db/errors/sqlite/sqlite-tests.factor b/basis/db/errors/sqlite/sqlite-tests.factor
new file mode 100644
index 0000000000..68ae55f8a8
--- /dev/null
+++ b/basis/db/errors/sqlite/sqlite-tests.factor
@@ -0,0 +1,26 @@
+! Copyright (C) 2009 Doug Coleman.
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors combinators.short-circuit db db.errors
+db.errors.sqlite db.sqlite io.files.unique kernel namespaces
+tools.test ;
+IN: db.errors.sqlite.tests
+
+: sqlite-error-test-db-path ( -- path )
+    "sqlite" "error-test" make-unique-file ;
+
+sqlite-error-test-db-path <sqlite-db> [
+
+    [
+        "insert into foo (id) values('1');" sql-command
+    ] [
+        { [ sql-table-missing? ] [ table>> "foo" = ] } 1&&
+    ] must-fail-with
+    
+    [
+        "create table foo(id);" sql-command
+        "create table foo(id);" sql-command
+    ] [
+        { [ sql-table-exists? ] [ table>> "foo" = ] } 1&&
+    ] must-fail-with
+
+] with-db
\ No newline at end of file
diff --git a/basis/db/errors/sqlite/sqlite.factor b/basis/db/errors/sqlite/sqlite.factor
new file mode 100644
index 0000000000..770a12b2a1
--- /dev/null
+++ b/basis/db/errors/sqlite/sqlite.factor
@@ -0,0 +1,31 @@
+! Copyright (C) 2009 Doug Coleman.
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors combinators db.errors db.sqlite.private kernel
+sequences peg.ebnf strings ;
+IN: db.errors.sqlite
+
+ERROR: unparsed-sqlite-error error ;
+
+SINGLETONS: table-exists table-missing ;
+
+: sqlite-table-error ( table message -- error )
+    {
+        { table-exists [ <sql-table-exists> ] }
+    } case ;
+
+EBNF: parse-sqlite-sql-error
+
+TableMessage = " already exists" => [[ table-exists ]]
+
+SqliteError =
+    "table " (!(TableMessage).)+:table TableMessage:message
+      => [[ table >string message sqlite-table-error ]]
+    | "no such table: " .+:table
+      => [[ table >string <sql-table-missing> ]]
+;EBNF
+
+M: sqlite-db-connection parse-db-error
+    dup n>> {
+        { 1 [ string>> parse-sqlite-sql-error ] }
+        [ drop ]
+    } case ;
\ No newline at end of file
diff --git a/basis/db/postgresql/postgresql-tests.factor b/basis/db/postgresql/postgresql-tests.factor
index cf6dc903f1..e2e2cbf7c0 100644
--- a/basis/db/postgresql/postgresql-tests.factor
+++ b/basis/db/postgresql/postgresql-tests.factor
@@ -3,7 +3,7 @@ prettyprint sequences namespaces tools.test db db.private
 db.tuples db.types unicode.case accessors system ;
 IN: db.postgresql.tests
 
-: test-db ( -- postgresql-db )
+: postgresql-test-db ( -- postgresql-db )
     <postgresql-db>
         "localhost" >>host
         "postgres" >>username
@@ -11,10 +11,10 @@ IN: db.postgresql.tests
         "factor-test" >>database ;
 
 os windows? cpu x86.64? and [
-    [ ] [ test-db [ ] with-db ] unit-test
+    [ ] [ postgresql-test-db [ ] with-db ] unit-test
 
     [ ] [
-        test-db [
+        postgresql-test-db [
             [ "drop table person;" sql-command ] ignore-errors
             "create table person (name varchar(30), country varchar(30));"
                 sql-command
@@ -30,7 +30,7 @@ os windows? cpu x86.64? and [
             { "Jane" "New Zealand" }
         }
     ] [
-        test-db [
+        postgresql-test-db [
             "select * from person" sql-query
         ] with-db
     ] unit-test
@@ -40,11 +40,11 @@ os windows? cpu x86.64? and [
             { "John" "America" }
             { "Jane" "New Zealand" }
         }
-    ] [ test-db [ "select * from person" sql-query ] with-db ] unit-test
+    ] [ postgresql-test-db [ "select * from person" sql-query ] with-db ] unit-test
 
     [
     ] [
-        test-db [
+        postgresql-test-db [
             "insert into person(name, country) values('Jimmy', 'Canada')"
             sql-command
         ] with-db
@@ -56,10 +56,10 @@ os windows? cpu x86.64? and [
             { "Jane" "New Zealand" }
             { "Jimmy" "Canada" }
         }
-    ] [ test-db [ "select * from person" sql-query ] with-db ] unit-test
+    ] [ postgresql-test-db [ "select * from person" sql-query ] with-db ] unit-test
 
     [
-        test-db [
+        postgresql-test-db [
             [
                 "insert into person(name, country) values('Jose', 'Mexico')" sql-command
                 "insert into person(name, country) values('Jose', 'Mexico')" sql-command
@@ -69,14 +69,14 @@ os windows? cpu x86.64? and [
     ] must-fail
 
     [ 3 ] [
-        test-db [
+        postgresql-test-db [
             "select * from person" sql-query length
         ] with-db
     ] unit-test
 
     [
     ] [
-        test-db [
+        postgresql-test-db [
             [
                 "insert into person(name, country) values('Jose', 'Mexico')"
                 sql-command
@@ -87,7 +87,7 @@ os windows? cpu x86.64? and [
     ] unit-test
 
     [ 5 ] [
-        test-db [
+        postgresql-test-db [
             "select * from person" sql-query length
         ] with-db
     ] unit-test

From a1f3e5695b9dc3dd1feec2bd6c1498ca006a4283 Mon Sep 17 00:00:00 2001
From: sheeple <sheeple@oberon.local>
Date: Fri, 20 Feb 2009 22:59:01 -0600
Subject: [PATCH 3/3] fix circularity in db

---
 basis/db/db.factor                           |  5 +++--
 basis/db/errors/errors.factor                |  4 +---
 basis/db/errors/postgresql/postgresql.factor |  3 ---
 basis/db/errors/sqlite/sqlite.factor         | 10 ++--------
 basis/db/postgresql/postgresql.factor        |  7 +++++--
 basis/db/sqlite/sqlite.factor                |  9 ++++++++-
 6 files changed, 19 insertions(+), 19 deletions(-)

diff --git a/basis/db/db.factor b/basis/db/db.factor
index eb06f0c894..96b72b8865 100644
--- a/basis/db/db.factor
+++ b/basis/db/db.factor
@@ -5,14 +5,14 @@ namespaces sequences classes.tuple words strings
 tools.walker accessors combinators fry db.errors ;
 IN: db
 
-<PRIVATE
-
 TUPLE: db-connection
     handle
     insert-statements
     update-statements
     delete-statements ;
 
+<PRIVATE
+
 : new-db-connection ( class -- obj )
     new
         H{ } clone >>insert-statements
@@ -23,6 +23,7 @@ PRIVATE>
 
 GENERIC: db-open ( db -- db-connection )
 HOOK: db-close db-connection ( handle -- )
+HOOK: parse-db-error db-connection ( error -- error' )
 
 : dispose-statements ( assoc -- ) values dispose-each ;
 
diff --git a/basis/db/errors/errors.factor b/basis/db/errors/errors.factor
index 1d48012cf9..9420dbbfc4 100644
--- a/basis/db/errors/errors.factor
+++ b/basis/db/errors/errors.factor
@@ -1,10 +1,8 @@
 ! Copyright (C) 2008 Doug Coleman.
 ! See http://factorcode.org/license.txt for BSD license.
-USING: kernel db.private ;
+USING: kernel ;
 IN: db.errors
 
-HOOK: parse-db-error db-connection ( error -- error' )
-
 ERROR: db-error ;
 ERROR: sql-error ;
 
diff --git a/basis/db/errors/postgresql/postgresql.factor b/basis/db/errors/postgresql/postgresql.factor
index 9d88c96cb1..e45ff092e8 100644
--- a/basis/db/errors/postgresql/postgresql.factor
+++ b/basis/db/errors/postgresql/postgresql.factor
@@ -2,6 +2,3 @@
 ! See http://factorcode.org/license.txt for BSD license.
 USING: ;
 IN: db.errors.postgresql
-
-M: postgresql-db-connection parse-db-error
-    ;
\ No newline at end of file
diff --git a/basis/db/errors/sqlite/sqlite.factor b/basis/db/errors/sqlite/sqlite.factor
index 770a12b2a1..c247a36257 100644
--- a/basis/db/errors/sqlite/sqlite.factor
+++ b/basis/db/errors/sqlite/sqlite.factor
@@ -1,7 +1,7 @@
 ! Copyright (C) 2009 Doug Coleman.
 ! See http://factorcode.org/license.txt for BSD license.
-USING: accessors combinators db.errors db.sqlite.private kernel
-sequences peg.ebnf strings ;
+USING: accessors combinators db kernel sequences peg.ebnf
+strings db.errors ;
 IN: db.errors.sqlite
 
 ERROR: unparsed-sqlite-error error ;
@@ -23,9 +23,3 @@ SqliteError =
     | "no such table: " .+:table
       => [[ table >string <sql-table-missing> ]]
 ;EBNF
-
-M: sqlite-db-connection parse-db-error
-    dup n>> {
-        { 1 [ string>> parse-sqlite-sql-error ] }
-        [ drop ]
-    } case ;
\ No newline at end of file
diff --git a/basis/db/postgresql/postgresql.factor b/basis/db/postgresql/postgresql.factor
index 1f55dcf769..1c39166071 100644
--- a/basis/db/postgresql/postgresql.factor
+++ b/basis/db/postgresql/postgresql.factor
@@ -5,8 +5,8 @@ kernel math math.parser namespaces make prettyprint quotations
 sequences debugger db db.postgresql.lib db.postgresql.ffi
 db.tuples db.types tools.annotations math.ranges
 combinators classes locals words tools.walker db.private
-nmake accessors random db.queries destructors db.tuples.private ;
-USE: tools.walker
+nmake accessors random db.queries destructors db.tuples.private
+db.postgresql ;
 IN: db.postgresql
 
 TUPLE: postgresql-db host port pgopts pgtty database username password ;
@@ -280,3 +280,6 @@ M: postgresql-db-connection compound ( string object -- string' )
         { "references" [ >reference-string ] }
         [ drop no-compound-found ]
     } case ;
+
+M: postgresql-db-connection parse-db-error
+    ;
diff --git a/basis/db/sqlite/sqlite.factor b/basis/db/sqlite/sqlite.factor
index a4adba3473..5b658f36c9 100755
--- a/basis/db/sqlite/sqlite.factor
+++ b/basis/db/sqlite/sqlite.factor
@@ -6,7 +6,8 @@ sequences strings classes.tuple alien.c-types continuations
 db.sqlite.lib db.sqlite.ffi db.tuples words db.types combinators
 math.intervals io nmake accessors vectors math.ranges random
 math.bitwise db.queries destructors db.tuples.private interpolate
-io.streams.string multiline make db.private sequences.deep ;
+io.streams.string multiline make db.private sequences.deep
+db.errors.sqlite ;
 IN: db.sqlite
 
 TUPLE: sqlite-db path ;
@@ -347,3 +348,9 @@ M: sqlite-db-connection compound ( string seq -- new-string )
         { "references" [ >reference-string ] }
         [ 2drop ]
     } case ;
+
+M: sqlite-db-connection parse-db-error
+    dup n>> {
+        { 1 [ string>> parse-sqlite-sql-error ] }
+        [ drop ]
+    } case ;