]> gitweb.factorcode.org Git - factor.git/commitdiff
move db to basis
authorDoug Coleman <doug.coleman@gmail.com>
Tue, 2 Sep 2008 23:26:31 +0000 (18:26 -0500)
committerDoug Coleman <doug.coleman@gmail.com>
Tue, 2 Sep 2008 23:26:31 +0000 (18:26 -0500)
50 files changed:
basis/db/authors.txt [new file with mode: 0644]
basis/db/db-tests.factor [new file with mode: 0755]
basis/db/db.factor [new file with mode: 0755]
basis/db/errors/errors.factor [new file with mode: 0644]
basis/db/pools/pools-tests.factor [new file with mode: 0644]
basis/db/pools/pools.factor [new file with mode: 0644]
basis/db/postgresql/authors.txt [new file with mode: 0644]
basis/db/postgresql/ffi/ffi.factor [new file with mode: 0755]
basis/db/postgresql/lib/lib.factor [new file with mode: 0755]
basis/db/postgresql/postgresql-tests.factor [new file with mode: 0755]
basis/db/postgresql/postgresql.factor [new file with mode: 0755]
basis/db/queries/queries.factor [new file with mode: 0644]
basis/db/sql/sql-tests.factor [new file with mode: 0644]
basis/db/sql/sql.factor [new file with mode: 0755]
basis/db/sqlite/authors.txt [new file with mode: 0644]
basis/db/sqlite/ffi/ffi.factor [new file with mode: 0755]
basis/db/sqlite/lib/lib.factor [new file with mode: 0755]
basis/db/sqlite/sqlite-tests.factor [new file with mode: 0755]
basis/db/sqlite/sqlite.factor [new file with mode: 0755]
basis/db/sqlite/test.txt [new file with mode: 0644]
basis/db/summary.txt [new file with mode: 0644]
basis/db/tags.txt [new file with mode: 0644]
basis/db/tuples/tuples-tests.factor [new file with mode: 0755]
basis/db/tuples/tuples.factor [new file with mode: 0755]
basis/db/types/types.factor [new file with mode: 0755]
extra/db/authors.txt [deleted file]
extra/db/db-tests.factor [deleted file]
extra/db/db.factor [deleted file]
extra/db/errors/errors.factor [deleted file]
extra/db/pools/pools-tests.factor [deleted file]
extra/db/pools/pools.factor [deleted file]
extra/db/postgresql/authors.txt [deleted file]
extra/db/postgresql/ffi/ffi.factor [deleted file]
extra/db/postgresql/lib/lib.factor [deleted file]
extra/db/postgresql/postgresql-tests.factor [deleted file]
extra/db/postgresql/postgresql.factor [deleted file]
extra/db/queries/queries.factor [deleted file]
extra/db/sql/sql-tests.factor [deleted file]
extra/db/sql/sql.factor [deleted file]
extra/db/sqlite/authors.txt [deleted file]
extra/db/sqlite/ffi/ffi.factor [deleted file]
extra/db/sqlite/lib/lib.factor [deleted file]
extra/db/sqlite/sqlite-tests.factor [deleted file]
extra/db/sqlite/sqlite.factor [deleted file]
extra/db/sqlite/test.txt [deleted file]
extra/db/summary.txt [deleted file]
extra/db/tags.txt [deleted file]
extra/db/tuples/tuples-tests.factor [deleted file]
extra/db/tuples/tuples.factor [deleted file]
extra/db/types/types.factor [deleted file]

diff --git a/basis/db/authors.txt b/basis/db/authors.txt
new file mode 100644 (file)
index 0000000..7c1b2f2
--- /dev/null
@@ -0,0 +1 @@
+Doug Coleman
diff --git a/basis/db/db-tests.factor b/basis/db/db-tests.factor
new file mode 100755 (executable)
index 0000000..0d95e3a
--- /dev/null
@@ -0,0 +1,6 @@
+IN: db.tests\r
+USING: tools.test db kernel ;\r
+\r
+{ 1 0 } [ [ drop ] query-each ] must-infer-as\r
+{ 1 1 } [ [ ] query-map ] must-infer-as\r
+{ 2 0 } [ [ ] with-db ] must-infer-as\r
diff --git a/basis/db/db.factor b/basis/db/db.factor
new file mode 100755 (executable)
index 0000000..c52d1db
--- /dev/null
@@ -0,0 +1,146 @@
+! Copyright (C) 2008 Doug Coleman.
+! See http://factorcode.org/license.txt for BSD license.
+USING: arrays assocs classes continuations destructors kernel math
+namespaces sequences sequences.lib classes.tuple words strings
+tools.walker accessors combinators.lib ;
+IN: db
+
+TUPLE: db
+    handle
+    insert-statements
+    update-statements
+    delete-statements ;
+
+: new-db ( class -- obj )
+    new
+        H{ } clone >>insert-statements
+        H{ } clone >>update-statements
+        H{ } clone >>delete-statements ;
+
+GENERIC: make-db* ( seq class -- db )
+
+: make-db ( seq class -- db )
+    new-db make-db* ;
+
+GENERIC: db-open ( db -- db )
+HOOK: db-close db ( handle -- )
+
+: dispose-statements ( assoc -- ) values dispose-each ;
+
+: dispose-db ( db -- ) 
+    dup db [
+        dup insert-statements>> dispose-statements
+        dup update-statements>> dispose-statements
+        dup delete-statements>> dispose-statements
+        handle>> db-close
+    ] with-variable ;
+
+TUPLE: statement handle sql in-params out-params bind-params bound? type retries ;
+TUPLE: simple-statement < statement ;
+TUPLE: prepared-statement < statement ;
+
+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 ;
+
+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 )
+GENERIC: #columns ( result-set -- n )
+GENERIC# row-column 1 ( result-set column -- obj )
+GENERIC# row-column-typed 1 ( result-set column -- sql )
+GENERIC: advance-row ( result-set -- )
+GENERIC: more-rows? ( result-set -- ? )
+
+GENERIC: execute-statement* ( statement type -- )
+
+M: object execute-statement* ( statement type -- )
+    drop query-results dispose ;
+
+: execute-statement ( statement -- )
+    dup sequence? [
+        [ execute-statement ] each
+    ] [
+        dup type>> execute-statement*
+    ] if ;
+
+: bind-statement ( obj statement -- )
+    swap >>bind-params
+    [ bind-statement* ] keep
+    t >>bound? drop ;
+
+: init-result-set ( result-set -- )
+    dup #rows >>max
+    0 >>n drop ;
+
+: construct-result-set ( query handle class -- result-set )
+    new
+        swap >>handle
+        >r [ sql>> ] [ in-params>> ] [ out-params>> ] tri r>
+        swap >>out-params
+        swap >>in-params
+        swap >>sql ;
+
+: sql-row ( result-set -- seq )
+    dup #columns [ row-column ] with map ;
+
+: sql-row-typed ( result-set -- seq )
+    dup #columns [ row-column-typed ] with map ;
+
+: query-each ( statement quot: ( statement -- ) -- )
+    over more-rows? [
+        [ call ] 2keep over advance-row query-each
+    ] [
+        2drop
+    ] if ; inline recursive
+
+: query-map ( statement quot -- seq )
+    accumulator >r query-each r> { } like ; inline
+
+: with-db ( seq class quot -- )
+    >r make-db db-open db r>
+    [ db get swap [ drop ] prepose with-disposal ] curry with-variable ;
+    inline
+
+: default-query ( query -- result-set )
+    query-results [ [ sql-row ] query-map ] with-disposal ;
+
+: do-bound-query ( obj query -- rows )
+    [ bind-statement ] keep default-query ;
+
+: do-bound-command ( obj query -- )
+    [ bind-statement ] keep execute-statement ;
+
+SYMBOL: in-transaction
+HOOK: begin-transaction db ( -- )
+HOOK: commit-transaction db ( -- )
+HOOK: rollback-transaction db ( -- )
+
+: in-transaction? ( -- ? ) in-transaction get ;
+
+: with-transaction ( quot -- )
+    t in-transaction [
+        begin-transaction
+        [ ] [ rollback-transaction ] cleanup commit-transaction
+    ] with-variable ;
+
+: sql-query ( sql -- rows )
+    f f <simple-statement> [ default-query ] with-disposal ;
+
+: sql-command ( sql -- )
+    dup string? [
+        f f <simple-statement> [ execute-statement ] with-disposal
+    ] [
+        ! [
+            [ sql-command ] each
+        ! ] with-transaction
+    ] if ;
diff --git a/basis/db/errors/errors.factor b/basis/db/errors/errors.factor
new file mode 100644 (file)
index 0000000..1e0d1e7
--- /dev/null
@@ -0,0 +1,11 @@
+! Copyright (C) 2008 Doug Coleman.
+! See http://factorcode.org/license.txt for BSD license.
+USING: kernel ;
+IN: db.errors
+
+ERROR: db-error ;
+ERROR: sql-error ;
+
+
+ERROR: table-exists ;
+ERROR: bad-schema ;
diff --git a/basis/db/pools/pools-tests.factor b/basis/db/pools/pools-tests.factor
new file mode 100644 (file)
index 0000000..34e072c
--- /dev/null
@@ -0,0 +1,22 @@
+IN: db.pools.tests
+USING: db.pools tools.test continuations io.files namespaces
+accessors kernel math destructors ;
+
+\ <db-pool> must-infer
+
+{ 2 0 } [ [ ] with-db-pool ] must-infer-as
+
+{ 1 0 } [ [ ] with-pooled-db ] must-infer-as
+
+! Test behavior after image save/load
+USE: db.sqlite
+
+[ "pool-test.db" temp-file delete-file ] ignore-errors
+
+[ ] [ "pool-test.db" sqlite-db <db-pool> "pool" set ] unit-test
+
+[ ] [ "pool" get expired>> t >>expired drop ] unit-test
+
+[ ] [ 1000 [ "pool" get [ ] with-pooled-db ] times ] unit-test
+
+[ ] [ "pool" get dispose ] unit-test
diff --git a/basis/db/pools/pools.factor b/basis/db/pools/pools.factor
new file mode 100644 (file)
index 0000000..63153c4
--- /dev/null
@@ -0,0 +1,21 @@
+! Copyright (C) 2008 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors kernel arrays namespaces sequences continuations
+io.pools db ;
+IN: db.pools
+
+TUPLE: db-pool < pool db params ;
+
+: <db-pool> ( params db -- pool )
+    db-pool <pool>
+        swap >>db
+        swap >>params ;
+
+: with-db-pool ( db params quot -- )
+    >r <db-pool> r> with-pool ; inline
+
+M: db-pool make-connection ( pool -- )
+    [ params>> ] [ db>> ] bi make-db db-open ;
+
+: with-pooled-db ( pool quot -- )
+    [ db swap with-variable ] curry with-pooled-connection ; inline
diff --git a/basis/db/postgresql/authors.txt b/basis/db/postgresql/authors.txt
new file mode 100644 (file)
index 0000000..7c1b2f2
--- /dev/null
@@ -0,0 +1 @@
+Doug Coleman
diff --git a/basis/db/postgresql/ffi/ffi.factor b/basis/db/postgresql/ffi/ffi.factor
new file mode 100755 (executable)
index 0000000..4358d7f
--- /dev/null
@@ -0,0 +1,368 @@
+! Copyright (C) 2007, 2008 Doug Coleman.
+! See http://factorcode.org/license.txt for BSD license.
+! tested on debian linux with postgresql 8.1
+USING: alien alien.syntax combinators system ;
+IN: db.postgresql.ffi
+
+<< "postgresql" {
+    { [ os winnt? ]  [ "libpq.dll" ] }
+    { [ os macosx? ] [ "libpq.dylib" ] }
+    { [ os unix?  ]  [ "libpq.so" ] }
+} cond "cdecl" add-library >>
+
+! ConnSatusType
+: CONNECTION_OK                     HEX: 0 ; inline
+: CONNECTION_BAD                    HEX: 1 ; inline
+: CONNECTION_STARTED                HEX: 2 ; inline
+: CONNECTION_MADE                   HEX: 3 ; inline
+: CONNECTION_AWAITING_RESPONSE      HEX: 4 ; inline
+: CONNECTION_AUTH_OK                HEX: 5 ; inline
+: CONNECTION_SETENV                 HEX: 6 ; inline
+: CONNECTION_SSL_STARTUP            HEX: 7 ; inline
+: CONNECTION_NEEDED                 HEX: 8 ; inline
+
+! PostgresPollingStatusType
+: PGRES_POLLING_FAILED              HEX: 0 ; inline
+: PGRES_POLLING_READING             HEX: 1 ; inline
+: PGRES_POLLING_WRITING             HEX: 2 ; inline
+: PGRES_POLLING_OK                  HEX: 3 ; inline
+: PGRES_POLLING_ACTIVE              HEX: 4 ; inline
+
+! ExecStatusType;
+: PGRES_EMPTY_QUERY                 HEX: 0 ; inline
+: PGRES_COMMAND_OK                  HEX: 1 ; inline
+: PGRES_TUPLES_OK                   HEX: 2 ; inline
+: PGRES_COPY_OUT                    HEX: 3 ; inline
+: PGRES_COPY_IN                     HEX: 4 ; inline
+: PGRES_BAD_RESPONSE                HEX: 5 ; inline
+: PGRES_NONFATAL_ERROR              HEX: 6 ; inline
+: PGRES_FATAL_ERROR                 HEX: 7 ; inline
+
+! PGTransactionStatusType;
+: PQTRANS_IDLE                      HEX: 0 ; inline
+: PQTRANS_ACTIVE                    HEX: 1 ; inline
+: PQTRANS_INTRANS                   HEX: 2 ; inline
+: PQTRANS_INERROR                   HEX: 3 ; inline
+: PQTRANS_UNKNOWN                   HEX: 4 ; inline
+
+! PGVerbosity;
+: PQERRORS_TERSE                    HEX: 0 ; inline
+: PQERRORS_DEFAULT                  HEX: 1 ; inline
+: PQERRORS_VERBOSE                  HEX: 2 ; inline
+
+: InvalidOid 0 ; inline
+
+TYPEDEF: int ConnStatusType
+TYPEDEF: int ExecStatusType 
+TYPEDEF: int PostgresPollingStatusType
+TYPEDEF: int PGTransactionStatusType 
+TYPEDEF: int PGVerbosity 
+
+TYPEDEF: void* PGconn*
+TYPEDEF: void* PGresult*
+TYPEDEF: void* PGcancel*
+TYPEDEF: uint Oid
+TYPEDEF: uint* Oid*
+TYPEDEF: char pqbool
+TYPEDEF: void* PQconninfoOption*
+TYPEDEF: void* PGnotify*
+TYPEDEF: void* PQArgBlock*
+TYPEDEF: void* PQprintOpt*
+TYPEDEF: void* FILE*
+TYPEDEF: void* SSL*
+
+LIBRARY: postgresql
+
+! Exported functions of libpq
+
+! make a new client connection to the backend
+! Asynchronous (non-blocking)
+FUNCTION: PGconn* PQconnectStart ( char* conninfo ) ;
+FUNCTION: PostgresPollingStatusType PQconnectPoll ( PGconn* conn ) ;
+
+! Synchronous (blocking)
+FUNCTION: PGconn* PQconnectdb ( char* conninfo ) ;
+FUNCTION: PGconn* PQsetdbLogin ( char* pghost, char* pgport,
+             char* pgoptions, char* pgtty,
+             char* dbName,
+             char* login, char* pwd ) ;
+
+: PQsetdb ( M_PGHOST M_PGPORT M_PGOPT M_PGTTY M_DBNAME -- PGconn* )
+    f f PQsetdbLogin ;
+
+! close the current connection and free the PGconn data structure
+FUNCTION: void PQfinish ( PGconn* conn ) ;
+
+! get info about connection options known to PQconnectdb
+FUNCTION: PQconninfoOption* PQconndefaults ( ) ;
+
+! free the data structure returned by PQconndefaults()
+FUNCTION: void PQconninfoFree ( PQconninfoOption* connOptions ) ;
+
+! Asynchronous (non-blocking)
+FUNCTION: int    PQresetStart ( PGconn* conn ) ;
+FUNCTION: PostgresPollingStatusType PQresetPoll ( PGconn* conn ) ;
+
+! Synchronous (blocking)
+FUNCTION: void PQreset ( PGconn* conn ) ;
+
+! request a cancel structure
+FUNCTION: PGcancel* PQgetCancel ( PGconn* conn ) ;
+
+! free a cancel structure
+FUNCTION: void PQfreeCancel ( PGcancel* cancel ) ;
+
+! issue a cancel request
+FUNCTION: int    PQrequestCancel ( PGconn* conn ) ;
+
+! Accessor functions for PGconn objects
+FUNCTION: char* PQdb ( PGconn* conn ) ;
+FUNCTION: char* PQuser ( PGconn* conn ) ;
+FUNCTION: char* PQpass ( PGconn* conn ) ;
+FUNCTION: char* PQhost ( PGconn* conn ) ;
+FUNCTION: char* PQport ( PGconn* conn ) ;
+FUNCTION: char* PQtty ( PGconn* conn ) ;
+FUNCTION: char* PQoptions ( PGconn* conn ) ;
+FUNCTION: ConnStatusType PQstatus ( PGconn* conn ) ;
+FUNCTION: PGTransactionStatusType PQtransactionStatus ( PGconn* conn ) ;
+FUNCTION: char* PQparameterStatus ( PGconn* conn,
+                  char* paramName ) ;
+FUNCTION: int PQprotocolVersion ( PGconn* conn ) ;
+! FUNCTION: int PQServerVersion ( PGconn* conn ) ;
+FUNCTION: char* PQerrorMessage ( PGconn* conn ) ;
+FUNCTION: int PQsocket ( PGconn* conn ) ;
+FUNCTION: int PQbackendPID ( PGconn* conn ) ;
+FUNCTION: int PQclientEncoding ( PGconn* conn ) ;
+FUNCTION: int PQsetClientEncoding ( PGconn* conn, char* encoding ) ;
+
+! May not be compiled into libpq
+! Get the SSL structure associated with a connection
+FUNCTION: SSL* PQgetssl ( PGconn* conn ) ;
+
+! Tell libpq whether it needs to initialize OpenSSL
+FUNCTION: void PQinitSSL ( int do_init ) ;
+
+! Set verbosity for PQerrorMessage and PQresultErrorMessage
+FUNCTION: PGVerbosity PQsetErrorVerbosity ( PGconn* conn,
+    PGVerbosity verbosity ) ;
+
+! Enable/disable tracing
+FUNCTION: void PQtrace ( PGconn* conn, FILE* debug_port ) ;
+FUNCTION: void PQuntrace ( PGconn* conn ) ;
+
+! BROKEN
+! Function types for notice-handling callbacks
+! typedef void (*PQnoticeReceiver) (void *arg, PGresult *res);
+! typedef void (*PQnoticeProcessor) (void *arg, char* message);
+! ALIAS: void* PQnoticeReceiver
+! ALIAS: void* PQnoticeProcessor
+
+! Override default notice handling routines
+! FUNCTION: PQnoticeReceiver PQsetNoticeReceiver ( PGconn* conn,
+                    ! PQnoticeReceiver proc,
+                    ! void* arg ) ;
+! FUNCTION: PQnoticeProcessor PQsetNoticeProcessor ( PGconn* conn,
+                    ! PQnoticeProcessor proc,
+                    ! void* arg ) ;
+! END BROKEN
+
+! === in fe-exec.c ===
+
+! Simple synchronous query
+FUNCTION: PGresult* PQexec ( PGconn* conn, char* query ) ;
+FUNCTION: PGresult* PQexecParams ( PGconn* conn,
+             char* command,
+             int nParams,
+             Oid* paramTypes,
+             char** paramValues,
+             int* paramLengths,
+             int* paramFormats,
+             int resultFormat ) ;
+FUNCTION: PGresult* PQprepare ( PGconn* conn, char* stmtName,
+        char* query, int nParams,
+        Oid* paramTypes ) ;
+FUNCTION: PGresult* PQexecPrepared ( PGconn* conn,
+             char* stmtName,
+             int nParams,
+             char** paramValues,
+             int* paramLengths,
+             int* paramFormats,
+             int resultFormat ) ;
+
+! Interface for multiple-result or asynchronous queries
+FUNCTION: int PQsendQuery ( PGconn* conn, char* query ) ;
+FUNCTION: int PQsendQueryParams ( PGconn* conn,
+                  char* command,
+                  int nParams,
+                  Oid* paramTypes,
+                  char** paramValues,
+                  int* paramLengths,
+                  int* paramFormats,
+                  int resultFormat ) ;
+FUNCTION: PGresult* PQsendPrepare ( PGconn* conn, char* stmtName,
+            char* query, int nParams,
+            Oid* paramTypes ) ;
+FUNCTION: int PQsendQueryPrepared ( PGconn* conn,
+                  char* stmtName,
+                  int nParams,
+                  char** paramValues,
+                  int *paramLengths,
+                  int *paramFormats,
+                  int resultFormat ) ;
+FUNCTION: PGresult* PQgetResult ( PGconn* conn ) ;
+
+! Routines for managing an asynchronous query
+FUNCTION: int    PQisBusy ( PGconn* conn ) ;
+FUNCTION: int    PQconsumeInput ( PGconn* conn ) ;
+
+! LISTEN/NOTIFY support
+FUNCTION: PGnotify* PQnotifies ( PGconn* conn ) ;
+
+! Routines for copy in/out
+FUNCTION: int    PQputCopyData ( PGconn* conn, char* buffer, int nbytes ) ;
+FUNCTION: int    PQputCopyEnd ( PGconn* conn, char* errormsg ) ;
+FUNCTION: int    PQgetCopyData ( PGconn* conn, char** buffer, int async ) ;
+
+! Deprecated routines for copy in/out
+FUNCTION: int    PQgetline ( PGconn* conn, char* string, int length ) ;
+FUNCTION: int    PQputline ( PGconn* conn, char* string ) ;
+FUNCTION: int    PQgetlineAsync ( PGconn* conn, char* buffer, int bufsize ) ;
+FUNCTION: int    PQputnbytes ( PGconn* conn, char* buffer, int nbytes ) ;
+FUNCTION: int    PQendcopy ( PGconn* conn ) ;
+
+! Set blocking/nonblocking connection to the backend
+FUNCTION: int    PQsetnonblocking ( PGconn* conn, int arg ) ;
+FUNCTION: int    PQisnonblocking ( PGconn* conn ) ;
+
+! Force the write buffer to be written (or at least try)
+FUNCTION: int    PQflush ( PGconn* conn ) ;
+
+! 
+! * "Fast path" interface --- not really recommended for application
+! * use
+!
+FUNCTION: PGresult* PQfn ( PGconn* conn,
+     int fnid,
+     int* result_buf,
+     int* result_len,
+     int result_is_int,
+     PQArgBlock* args,
+     int nargs ) ;
+
+! Accessor functions for PGresult objects
+FUNCTION: ExecStatusType PQresultStatus ( PGresult* res ) ;
+FUNCTION: char* PQresStatus ( ExecStatusType status ) ;
+FUNCTION: char* PQresultErrorMessage ( PGresult* res ) ;
+FUNCTION: char* PQresultErrorField ( PGresult* res, int fieldcode ) ;
+FUNCTION: int   PQntuples ( PGresult* res ) ;
+FUNCTION: int   PQnfields ( PGresult* res ) ;
+FUNCTION: int   PQbinaryTuples ( PGresult* res ) ;
+FUNCTION: char* PQfname ( PGresult* res, int field_num ) ;
+FUNCTION: int   PQfnumber ( PGresult* res, char* field_name ) ;
+FUNCTION: Oid   PQftable ( PGresult* res, int field_num ) ;
+FUNCTION: int   PQftablecol ( PGresult* res, int field_num ) ;
+FUNCTION: int   PQfformat ( PGresult* res, int field_num ) ;
+FUNCTION: Oid   PQftype ( PGresult* res, int field_num ) ;
+FUNCTION: int   PQfsize ( PGresult* res, int field_num ) ;
+FUNCTION: int   PQfmod ( PGresult* res, int field_num ) ;
+FUNCTION: char* PQcmdStatus ( PGresult* res ) ;
+FUNCTION: char* PQoidStatus ( PGresult* res ) ;
+FUNCTION: Oid   PQoidValue ( PGresult* res ) ;
+FUNCTION: char* PQcmdTuples ( PGresult* res ) ;
+! FUNCTION: char* PQgetvalue ( PGresult* res, int tup_num, int field_num ) ;
+FUNCTION: void* PQgetvalue ( PGresult* res, int tup_num, int field_num ) ;
+FUNCTION: int   PQgetlength ( PGresult* res, int tup_num, int field_num ) ;
+FUNCTION: int   PQgetisnull ( PGresult* res, int tup_num, int field_num ) ;
+
+! Delete a PGresult
+FUNCTION: void PQclear ( PGresult* res ) ;
+
+! For freeing other alloc'd results, such as PGnotify structs
+FUNCTION: void PQfreemem ( void* ptr ) ;
+
+! Exists for backward compatibility.
+: PQfreeNotify ( ptr -- ) PQfreemem ;
+
+!
+! Make an empty PGresult with given status (some apps find this
+! useful). If conn is not NULL and status indicates an error, the
+! conn's errorMessage is copied.
+!
+FUNCTION: PGresult* PQmakeEmptyPGresult ( PGconn* conn, ExecStatusType status ) ;
+
+! Quoting strings before inclusion in queries.
+FUNCTION: size_t PQescapeStringConn ( PGconn* conn,
+                                    char* to, char* from, size_t length,
+                                    int* error ) ;
+FUNCTION: uchar* PQescapeByteaConn ( PGconn* conn,
+                                    char* from, size_t length,
+                                    size_t* to_length ) ;
+FUNCTION: void* PQunescapeBytea ( uchar* strtext, size_t* retbuflen ) ;
+! FUNCTION: uchar* PQunescapeBytea ( uchar* strtext, size_t* retbuflen ) ;
+! These forms are deprecated!
+FUNCTION: size_t PQescapeString ( void* to, char* from, size_t length ) ;
+FUNCTION: uchar* PQescapeBytea ( uchar* bintext, size_t binlen,
+              size_t* bytealen ) ;
+
+! === in fe-print.c ===
+
+FUNCTION: void PQprint ( FILE* fout, PGresult* res, PQprintOpt* ps ) ;
+
+! really old printing routines
+FUNCTION: void PQdisplayTuples ( PGresult* res,
+                                FILE* fp,               
+                                int fillAlign,
+                                char* fieldSep,
+                                int printHeader,
+                                int quiet ) ;
+
+FUNCTION: void PQprintTuples ( PGresult* res,
+                          FILE* fout,           
+                          int printAttName,
+                          int terseOutput,      
+                          int width ) ; 
+! === in fe-lobj.c ===
+
+! Large-object access routines
+FUNCTION: int    lo_open ( PGconn* conn, Oid lobjId, int mode ) ;
+FUNCTION: int    lo_close ( PGconn* conn, int fd ) ;
+FUNCTION: int    lo_read ( PGconn* conn, int fd, char* buf, size_t len ) ;
+FUNCTION: int    lo_write ( PGconn* conn, int fd, char* buf, size_t len ) ;
+FUNCTION: int    lo_lseek ( PGconn* conn, int fd, int offset, int whence ) ;
+FUNCTION: Oid    lo_creat ( PGconn* conn, int mode ) ;
+! FUNCTION: Oid    lo_creat ( PGconn* conn, Oid lobjId ) ;
+FUNCTION: int    lo_tell ( PGconn* conn, int fd ) ;
+FUNCTION: int    lo_unlink ( PGconn* conn, Oid lobjId ) ;
+FUNCTION: Oid    lo_import ( PGconn* conn, char* filename ) ;
+FUNCTION: int    lo_export ( PGconn* conn, Oid lobjId, char* filename ) ;
+
+! === in fe-misc.c ===
+
+! Determine length of multibyte encoded char at *s
+FUNCTION: int    PQmblen ( uchar* s, int encoding ) ;
+
+! Determine display length of multibyte encoded char at *s
+FUNCTION: int    PQdsplen ( uchar* s, int encoding ) ;
+
+! Get encoding id from environment variable PGCLIENTENCODING
+FUNCTION: int    PQenv2encoding ( ) ;
+
+! From git, include/catalog/pg_type.h
+: BOOL-OID 16 ; inline
+: BYTEA-OID 17 ; inline
+: CHAR-OID 18 ; inline
+: NAME-OID 19 ; inline
+: INT8-OID 20 ; inline
+: INT2-OID 21 ; inline
+: INT4-OID 23 ; inline
+: TEXT-OID 23 ; inline
+: OID-OID 26 ; inline
+: FLOAT4-OID 700 ; inline
+: FLOAT8-OID 701 ; inline
+: VARCHAR-OID 1043 ; inline
+: DATE-OID 1082 ; inline
+: TIME-OID 1083 ; inline
+: TIMESTAMP-OID 1114 ; inline
+: TIMESTAMPTZ-OID 1184 ; inline
+: INTERVAL-OID 1186 ; inline
+: NUMERIC-OID 1700 ; inline
diff --git a/basis/db/postgresql/lib/lib.factor b/basis/db/postgresql/lib/lib.factor
new file mode 100755 (executable)
index 0000000..eba7f69
--- /dev/null
@@ -0,0 +1,173 @@
+! Copyright (C) 2008 Doug Coleman.
+! See http://factorcode.org/license.txt for BSD license.
+USING: arrays continuations db io kernel math namespaces
+quotations sequences db.postgresql.ffi alien alien.c-types
+db.types tools.walker ascii splitting math.parser combinators
+libc shuffle calendar.format byte-arrays destructors prettyprint
+accessors strings serialize io.encodings.binary io.encodings.utf8
+alien.strings io.streams.byte-array summary present urls ;
+IN: db.postgresql.lib
+
+: postgresql-result-error-message ( res -- str/f )
+    dup zero? [
+        drop f
+    ] [
+        PQresultErrorMessage [ blank? ] trim
+    ] if ;
+
+: postgres-result-error ( res -- )
+    postgresql-result-error-message [ throw ] when* ;
+
+: (postgresql-error-message) ( handle -- str )
+    PQerrorMessage
+    "\n" split [ [ blank? ] trim ] map "\n" join ;
+
+: postgresql-error-message ( -- str )
+    db get handle>> (postgresql-error-message) ;
+
+: postgresql-error ( res -- res )
+    dup [ postgresql-error-message throw ] unless ;
+
+ERROR: postgresql-result-null ;
+
+M: postgresql-result-null summary ( obj -- str )
+    drop "PQexec returned f." ;
+
+: postgresql-result-ok? ( res -- ? )
+    [ postgresql-result-null ] unless*
+    PQresultStatus
+    PGRES_COMMAND_OK PGRES_TUPLES_OK 2array member? ;
+
+: connect-postgres ( host port pgopts pgtty db user pass -- conn )
+    PQsetdbLogin
+    dup PQstatus zero? [ (postgresql-error-message) throw ] unless ;
+
+: do-postgresql-statement ( statement -- res )
+    db get handle>> swap sql>> PQexec dup postgresql-result-ok? [
+        [ postgresql-result-error-message ] [ PQclear ] bi throw
+    ] unless ;
+
+: type>oid ( symbol -- n )
+    dup array? [ first ] when
+    {
+        { BLOB [ BYTEA-OID ] }
+        { FACTOR-BLOB [ BYTEA-OID ] }
+        [ drop 0 ]
+    } case ;
+
+: type>param-format ( symbol -- n )
+    dup array? [ first ] when
+    {
+        { BLOB [ 1 ] }
+        { FACTOR-BLOB [ 1 ] }
+        [ drop 0 ]
+    } case ;
+
+: param-types ( statement -- seq )
+    in-params>> [ type>> type>oid ] map >c-uint-array ;
+
+: malloc-byte-array/length ( byte-array -- alien length )
+    [ malloc-byte-array &free ] [ length ] bi ;
+
+: default-param-value ( obj -- alien n )
+    number>string* dup [ utf8 malloc-string &free ] when 0 ;
+
+: param-values ( statement -- seq seq2 )
+    [ bind-params>> ] [ in-params>> ] bi
+    [
+        >r value>> r> type>> {
+            { FACTOR-BLOB [
+                dup [ object>bytes malloc-byte-array/length ] [ 0 ] if
+            ] }
+            { BLOB [ dup [ malloc-byte-array/length ] [ 0 ] if ] }
+            { DATE [ dup [ timestamp>ymd ] when default-param-value ] }
+            { TIME [ dup [ timestamp>hms ] when default-param-value ] }
+            { DATETIME [ dup [ timestamp>ymdhms ] when default-param-value ] }
+            { TIMESTAMP [ dup [ timestamp>ymdhms ] when default-param-value ] }
+            { URL [ dup [ present ] when default-param-value ] }
+            [ drop default-param-value ]
+        } case 2array
+    ] 2map flip dup empty? [
+        drop f f
+    ] [
+        first2 [ >c-void*-array ] [ >c-uint-array ] bi*
+    ] if ;
+
+: param-formats ( statement -- seq )
+    in-params>> [ type>> type>param-format ] map >c-uint-array ;
+
+: do-postgresql-bound-statement ( statement -- res )
+    [
+        >r db get handle>> r>
+        {
+            [ sql>> ]
+            [ bind-params>> length ]
+            [ param-types ]
+            [ param-values ]
+            [ param-formats ]
+        } cleave
+        0 PQexecParams dup postgresql-result-ok? [
+            [ postgresql-result-error-message ] [ PQclear ] bi throw
+        ] unless
+    ] with-destructors ;
+
+: pq-get-is-null ( handle row column -- ? )
+    PQgetisnull 1 = ;
+
+: pq-get-string ( handle row column -- obj )
+    3dup PQgetvalue utf8 alien>string
+    dup empty? [ >r pq-get-is-null f r> ? ] [ 3nip ] if ;
+
+: pq-get-number ( handle row column -- obj )
+    pq-get-string dup [ string>number ] when ;
+
+TUPLE: postgresql-malloc-destructor alien ;
+C: <postgresql-malloc-destructor> postgresql-malloc-destructor
+
+M: postgresql-malloc-destructor dispose ( obj -- )
+    alien>> PQfreemem ;
+
+: &postgresql-free ( alien -- alien )
+    dup <postgresql-malloc-destructor> &dispose drop ; inline
+
+: pq-get-blob ( handle row column -- obj/f )
+    [ PQgetvalue ] 3keep 3dup PQgetlength
+    dup 0 > [
+        3nip
+        [
+            memory>byte-array >string
+            0 <uint>
+            [
+                PQunescapeBytea dup zero? [
+                    postgresql-result-error-message throw
+                ] [
+                    &postgresql-free
+                ] if
+            ] keep
+            *uint memory>byte-array
+        ] with-destructors 
+    ] [
+        drop pq-get-is-null nip [ f ] [ B{ } clone ] if
+    ] if ;
+
+: postgresql-column-typed ( handle row column type -- obj )
+    dup array? [ first ] when
+    {
+        { +db-assigned-id+ [ pq-get-number ] }
+        { +random-id+ [ pq-get-number ] }
+        { INTEGER [ pq-get-number ] }
+        { BIG-INTEGER [ pq-get-number ] }
+        { DOUBLE [ pq-get-number ] }
+        { TEXT [ pq-get-string ] }
+        { VARCHAR [ pq-get-string ] }
+        { DATE [ pq-get-string dup [ ymd>timestamp ] when ] }
+        { TIME [ pq-get-string dup [ hms>timestamp ] when ] }
+        { TIMESTAMP [ pq-get-string dup [ ymdhms>timestamp ] when ] }
+        { DATETIME [ pq-get-string dup [ ymdhms>timestamp ] when ] }
+        { BLOB [ pq-get-blob ] }
+        { URL [ pq-get-string dup [ >url ] when ] }
+        { FACTOR-BLOB [
+            pq-get-blob
+            dup [ bytes>object ] when ] }
+        [ no-sql-type ]
+    } case ;
diff --git a/basis/db/postgresql/postgresql-tests.factor b/basis/db/postgresql/postgresql-tests.factor
new file mode 100755 (executable)
index 0000000..65b75a6
--- /dev/null
@@ -0,0 +1,95 @@
+! You will need to run  'createdb factor-test' to create the database.
+! Set username and password in  the 'connect' word.
+
+USING: kernel db.postgresql alien continuations io classes
+prettyprint sequences namespaces tools.test db
+db.tuples db.types unicode.case ;
+IN: db.postgresql.tests
+
+: test-db ( -- postgresql-db )
+    { "localhost" "postgres" "foob" "factor-test" } postgresql-db ;
+
+[ ] [ test-db [ ] with-db ] unit-test
+
+[ ] [
+    test-db [
+        [ "drop table person;" sql-command ] ignore-errors
+        "create table person (name varchar(30), country varchar(30));"
+            sql-command
+
+        "insert into person values('John', 'America');" sql-command
+        "insert into person values('Jane', 'New Zealand');" sql-command
+    ] with-db
+] unit-test
+
+[
+    {
+        { "John" "America" }
+        { "Jane" "New Zealand" }
+    }
+] [
+    test-db [
+        "select * from person" sql-query
+    ] with-db
+] unit-test
+
+[
+    {
+        { "John" "America" }
+        { "Jane" "New Zealand" }
+    }
+] [ test-db [ "select * from person" sql-query ] with-db ] unit-test
+
+[
+] [
+    test-db [
+        "insert into person(name, country) values('Jimmy', 'Canada')"
+        sql-command
+    ] with-db
+] unit-test
+
+[
+    {
+        { "John" "America" }
+        { "Jane" "New Zealand" }
+        { "Jimmy" "Canada" }
+    }
+] [ test-db [ "select * from person" sql-query ] with-db ] unit-test
+
+[
+    test-db [
+        [
+            "insert into person(name, country) values('Jose', 'Mexico')" sql-command
+            "insert into person(name, country) values('Jose', 'Mexico')" sql-command
+            "oops" throw
+        ] with-transaction
+    ] with-db
+] must-fail
+
+[ 3 ] [
+    test-db [
+        "select * from person" sql-query length
+    ] with-db
+] unit-test
+
+[
+] [
+    test-db [
+        [
+            "insert into person(name, country) values('Jose', 'Mexico')"
+            sql-command
+            "insert into person(name, country) values('Jose', 'Mexico')"
+            sql-command
+        ] with-transaction
+    ] with-db
+] unit-test
+
+[ 5 ] [
+    test-db [
+        "select * from person" sql-query length
+    ] with-db
+] unit-test
+
+
+: with-dummy-db ( quot -- )
+    >r T{ postgresql-db } db r> with-variable ;
diff --git a/basis/db/postgresql/postgresql.factor b/basis/db/postgresql/postgresql.factor
new file mode 100755 (executable)
index 0000000..e57efbc
--- /dev/null
@@ -0,0 +1,264 @@
+! Copyright (C) 2007, 2008 Doug Coleman.
+! See http://factorcode.org/license.txt for BSD license.
+USING: arrays assocs alien alien.syntax continuations io
+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 db.queries destructors ;
+USE: tools.walker
+IN: db.postgresql
+
+TUPLE: postgresql-db < db
+    host port pgopts pgtty db user pass ;
+
+TUPLE: postgresql-statement < statement ;
+
+TUPLE: postgresql-result-set < result-set ;
+
+M: postgresql-db make-db* ( seq tuple -- db )
+    >r first4 r>
+        swap >>db
+        swap >>pass
+        swap >>user
+        swap >>host ;
+
+M: postgresql-db db-open ( db -- db )
+    dup {
+        [ host>> ]
+        [ port>> ]
+        [ pgopts>> ]
+        [ pgtty>> ]
+        [ db>> ]
+        [ user>> ]
+        [ pass>> ]
+    } cleave connect-postgres >>handle ;
+
+M: postgresql-db dispose ( db -- )
+    handle>> PQfinish ;
+
+M: postgresql-statement bind-statement* ( statement -- )
+    drop ;
+
+GENERIC: postgresql-bind-conversion ( tuple obj -- low-level-binding )
+
+M: sql-spec postgresql-bind-conversion ( tuple spec -- obj )
+    slot-name>> swap get-slot-named <low-level-binding> ;
+
+M: literal-bind postgresql-bind-conversion ( tuple literal-bind -- obj )
+    nip value>> <low-level-binding> ;
+
+M: generator-bind postgresql-bind-conversion ( tuple generate-bind -- obj )
+    dup generator-singleton>> eval-generator
+    [ swap slot-name>> rot set-slot-named ] [ <low-level-binding> ] bi ;
+
+M: postgresql-statement bind-tuple ( tuple statement -- )
+    tuck in-params>>
+    [ postgresql-bind-conversion ] with map
+    >>bind-params drop ;
+
+M: postgresql-result-set #rows ( result-set -- n )
+    handle>> PQntuples ;
+
+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 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 result-handle-n r> r> postgresql-column-typed ;
+
+M: postgresql-statement query-results ( query -- result-set )
+    dup bind-params>> [
+        over [ bind-statement ] keep
+        do-postgresql-bound-statement
+    ] [
+        dup do-postgresql-statement
+    ] if*
+    postgresql-result-set construct-result-set
+    dup init-result-set ;
+
+M: postgresql-result-set advance-row ( result-set -- )
+    [ 1+ ] change-n drop ;
+
+M: postgresql-result-set more-rows? ( result-set -- ? )
+    [ n>> ] [ max>> ] bi < ;
+
+M: postgresql-statement dispose ( query -- )
+    dup handle>> PQclear
+    f >>handle drop ;
+
+M: postgresql-result-set dispose ( result-set -- )
+    [ handle>> PQclear ]
+    [
+        0 >>n
+        0 >>max
+        f >>handle drop
+    ] bi ;
+
+M: postgresql-statement prepare-statement ( statement -- )
+    dup
+    >r db get handle>> f r>
+    [ sql>> ] [ in-params>> ] bi
+    length f PQprepare postgresql-error
+    >>handle drop ;
+
+M: postgresql-db <simple-statement> ( sql in out -- statement )
+    postgresql-statement construct-statement ;
+
+M: postgresql-db <prepared-statement> ( sql in out -- statement )
+    <simple-statement> dup prepare-statement ;
+
+: bind-name% ( -- )
+    CHAR: $ 0,
+    sql-counter [ inc ] [ get 0# ] bi ;
+
+M: postgresql-db bind% ( spec -- )
+    bind-name% 1, ;
+
+M: postgresql-db bind# ( spec obj -- )
+    >r bind-name% f swap type>> r> <literal-bind> 1, ;
+
+: create-table-sql ( class -- statement )
+    [
+        "create table " 0% 0%
+        "(" 0% [ ", " 0% ] [
+            dup column-name>> 0%
+            " " 0%
+            dup type>> lookup-create-type 0%
+            modifiers 0%
+        ] interleave ");" 0%
+    ] query-make ;
+
+: create-function-sql ( class -- statement )
+    [
+        >r remove-id r>
+        "create function add_" 0% dup 0%
+        "(" 0%
+        over [ "," 0% ]
+        [
+            type>> lookup-type 0%
+        ] interleave
+        ")" 0%
+        " returns bigint as '" 0%
+
+        "insert into " 0%
+        dup 0%
+        "(" 0%
+        over [ ", " 0% ] [ column-name>> 0% ] interleave
+        ") values(" 0%
+        swap [ ", " 0% ] [ drop bind-name% ] interleave
+        "); " 0%
+        "select currval(''" 0% 0% "_id_seq'');' language sql;" 0%
+    ] query-make ;
+
+M: postgresql-db create-sql-statement ( class -- seq )
+    [
+        [ create-table-sql , ] keep
+        dup db-columns find-primary-key db-assigned-id-spec?
+        [ create-function-sql , ] [ drop ] if
+    ] { } make ;
+
+: drop-function-sql ( class -- statement )
+    [
+        "drop function add_" 0% 0%
+        "(" 0%
+        remove-id
+        [ ", " 0% ] [ type>> lookup-type 0% ] interleave
+        ");" 0%
+    ] query-make ;
+
+: drop-table-sql ( table -- statement )
+    [
+        "drop table " 0% 0% drop
+    ] query-make ;
+
+M: postgresql-db drop-sql-statement ( class -- seq )
+    [
+        [ drop-table-sql , ] keep
+        dup db-columns find-primary-key db-assigned-id-spec?
+        [ drop-function-sql , ] [ drop ] if
+    ] { } make ;
+
+M: postgresql-db <insert-db-assigned-statement> ( class -- statement )
+    [
+        "select add_" 0% 0%
+        "(" 0%
+        dup find-primary-key 2,
+        remove-id
+        [ ", " 0% ] [ bind% ] interleave
+        ");" 0%
+    ] query-make ;
+
+M: postgresql-db <insert-user-assigned-statement> ( class -- statement )
+    [
+        "insert into " 0% 0%
+        "(" 0%
+        dup [ ", " 0% ] [ column-name>> 0% ] interleave
+        ")" 0%
+
+        " values(" 0%
+        [ ", " 0% ] [
+            dup type>> +random-id+ = [
+                [
+                    bind-name%
+                    slot-name>>
+                    f
+                    random-id-generator
+                ] [ type>> ] bi <generator-bind> 1,
+            ] [
+                bind%
+            ] if
+        ] interleave
+        ");" 0%
+    ] query-make ;
+
+M: postgresql-db insert-tuple* ( tuple statement -- )
+    query-modify-tuple ;
+
+M: postgresql-db persistent-table ( -- hashtable )
+    H{
+        { +db-assigned-id+ { "integer" "serial primary key" f } }
+        { +user-assigned-id+ { f f "primary key" } }
+        { +random-id+ { "bigint" "bigint primary key" f } }
+        { TEXT { "text" "text" 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 } }
+        { URL { "varchar" "varchar" 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' )
+    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/basis/db/queries/queries.factor b/basis/db/queries/queries.factor
new file mode 100644 (file)
index 0000000..3a751a9
--- /dev/null
@@ -0,0 +1,188 @@
+! Copyright (C) 2008 Doug Coleman.
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors kernel math namespaces sequences random
+strings math.parser math.intervals combinators
+math.bitfields.lib namespaces.lib db db.tuples db.types
+sequences.lib db.sql classes words shuffle arrays ;
+IN: db.queries
+
+GENERIC: where ( specs obj -- )
+
+: 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 ] curry { "" { } { } } nmake
+    <simple-statement> maybe-make-retryable ; inline
+
+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: random-id-generator eval-generator ( singleton -- obj )
+    drop
+    system-random-generator get [
+        63 [ 2^ random ] keep 1 - set-bit
+    ] with-random ;
+
+: interval-comparison ( ? str -- str )
+    "from" = " >" " <" ? swap [ "= " append ] when ;
+
+: fp-infinity? ( float -- ? )
+    dup float? [
+        double>bits -52 shift 11 2^ 1- [ bitand ] keep =
+    ] [
+        drop f
+    ] if ;
+
+: (infinite-interval?) ( interval -- ?1 ?2 )
+    [ from>> ] [ to>> ] bi
+    [ first fp-infinity? ] bi@ ;
+
+: double-infinite-interval? ( obj -- ? )
+    dup interval? [ (infinite-interval?) and ] [ drop f ] if ;
+
+: infinite-interval? ( obj -- ? )
+    dup interval? [ (infinite-interval?) or ] [ drop f ] if ;
+
+: where-interval ( spec obj from/to -- )
+    over first fp-infinity? [
+        3drop
+    ] [
+        pick column-name>> 0%
+        >r first2 r> interval-comparison 0%
+        bind#
+    ] if ;
+
+: in-parens ( quot -- )
+    "(" 0% call ")" 0% ; inline
+
+M: interval where ( spec obj -- )
+    [
+        [ from>> "from" where-interval ] [
+            nip infinite-interval? [ " and " 0% ] unless
+        ] [ to>> "to" where-interval ] 2tri
+    ] 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 ;
+
+: filter-slots ( tuple specs -- specs' )
+    [
+        slot-name>> swap get-slot-named
+        dup double-infinite-interval? [ drop f ] when
+    ] with filter ;
+
+: where-clause ( tuple specs -- )
+    dupd filter-slots [
+        drop
+    ] [
+        " where " 0% [
+            " and " 0%
+        ] [
+            2dup slot-name>> swap get-slot-named where
+        ] interleave drop
+    ] if-empty ;
+
+M: db <delete-tuples-statement> ( tuple table -- sql )
+    [
+        "delete from " 0% 0%
+        where-clause
+    ] query-make ;
+
+M: db <select-by-slots-statement> ( tuple class -- statement )
+    [
+        "select " 0%
+        over [ ", " 0% ]
+        [ dup column-name>> 0% 2, ] interleave
+
+        " from " 0% 0%
+        where-clause
+    ] query-make ;
+
+: do-group ( tuple groups -- )
+    [
+        ", " join " group by " prepend append
+    ] curry change-sql drop ;
+
+: do-order ( tuple order -- )
+    [
+        ", " join " order by " prepend append
+    ] curry change-sql drop ;
+
+: do-offset ( tuple n -- )
+    [
+        number>string " offset " prepend append
+    ] curry change-sql drop ;
+
+: do-limit ( tuple n -- )
+    [
+        number>string " limit " prepend append
+    ] curry change-sql drop ;
+
+: make-query ( tuple query -- tuple' )
+    dupd
+    {
+        [ group>> [ do-group ] [ drop ] if-seq ]
+        [ order>> [ do-order ] [ drop ] if-seq ]
+        [ limit>> [ do-limit ] [ drop ] if* ]
+        [ offset>> [ do-offset ] [ drop ] if* ]
+    } 2cleave ;
+
+M: db <query> ( tuple class query -- tuple )
+    [ <select-by-slots-statement> ] dip make-query ;
+
+! select ID, NAME, SCORE from EXAM limit 1 offset 3
+
+: select-tuples* ( tuple -- statement )
+    dup
+    [
+        select 0,
+        dup class db-columns [ ", " 0, ]
+        [ dup column-name>> 0, 2, ] interleave
+        from 0,
+        class name>> 0,
+    ] { { } { } { } } nmake
+    >r >r parse-sql 4drop r> r>
+    <simple-statement> maybe-make-retryable do-select ;
+
+M: db <count-statement> ( tuple class groups -- statement )
+    \ query new
+        swap >>group
+    [ [ "select count(*) from " 0% 0% where-clause ] query-make ]
+    dip make-query ;
+
+: create-index ( index-name table-name columns -- )
+    [
+        >r >r "create index " % % r> " on " % % r> "(" %
+        "," join % ")" %
+    ] "" make sql-command ;
+
+: drop-index ( index-name -- )
+    [ "drop index " % % ] "" make sql-command ;
diff --git a/basis/db/sql/sql-tests.factor b/basis/db/sql/sql-tests.factor
new file mode 100644 (file)
index 0000000..0b57c2d
--- /dev/null
@@ -0,0 +1,42 @@
+USING: kernel namespaces db.sql sequences math ;
+IN: db.sql.tests
+
+! TUPLE: person name age ;
+: insert-1
+    { insert
+        {
+            { table "person" }
+            { columns "name" "age" }
+            { values "erg" 26 }
+        }
+    } ;
+
+: update-1
+    { update "person"
+       { set { "name" "erg" }
+             { "age" 6 } }
+       { where { "age" 6 } }
+    } ;
+
+: select-1
+    { select
+        { columns
+                "branchno"
+                { count "staffno" as "mycount" }
+                { sum "salary" as "mysum" } }
+        { from "staff" "lol" }
+        { where
+                { "salary" > all
+                    { select
+                        { columns "salary" }
+                        { from "staff" }
+                        { where { "branchno" = "b003" } }
+                    }
+                }
+                { "branchno" > 3 } }
+        { group-by "branchno" "lol2" }
+        { having { count "staffno" > 1 } }
+        { order-by "branchno" }
+        { offset 40 }
+        { limit 20 }
+    } ;
diff --git a/basis/db/sql/sql.factor b/basis/db/sql/sql.factor
new file mode 100755 (executable)
index 0000000..7dd4abf
--- /dev/null
@@ -0,0 +1,77 @@
+USING: kernel parser quotations classes.tuple words math.order
+namespaces.lib namespaces sequences arrays combinators
+prettyprint strings math.parser sequences.lib math symbols ;
+IN: db.sql
+
+SYMBOLS: insert update delete select distinct columns from as
+where group-by having order-by limit offset is-null desc all
+any count avg table values ;
+
+: input-spec, ( obj -- ) 1, ;
+: output-spec, ( obj -- ) 2, ;
+: input, ( obj -- ) 3, ;
+: output, ( obj -- ) 4, ;
+
+DEFER: sql%
+
+: (sql-interleave) ( seq sep -- )
+    [ sql% ] curry [ sql% ] interleave ;
+
+: sql-interleave ( seq str sep -- )
+    swap sql% (sql-interleave) ;
+
+: sql-function, ( seq function -- )
+    sql% "(" sql% unclip sql% ")" sql% [ sql% ] each ;
+
+: sql-where ( seq -- )
+B
+    [
+        [ second 0, ]
+        [ first 0, ]
+        [ third 1, \ ? 0, ] tri
+    ] each ;
+
+: sql-array% ( array -- )
+B
+    unclip
+    {
+        { \ create [ "create table" sql% ] }
+        { \ drop [ "drop table" sql% ] }
+        { \ insert [ "insert into" sql% ] }
+        { \ update [ "update" sql% ] }
+        { \ delete [ "delete" sql% ] }
+        { \ select [ B "select" sql% "," (sql-interleave) ] }
+        { \ columns [ "," (sql-interleave) ] }
+        { \ from [ "from" "," sql-interleave ] }
+        { \ where [ B "where" 0, sql-where ] }
+        { \ 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, ] }
+        [ sql% [ sql% ] each ]
+    } case ;
+
+ERROR: no-sql-match ;
+: sql% ( obj -- )
+    {
+        { [ dup string? ] [ 0, ] }
+        { [ dup array? ] [ sql-array% ] }
+        { [ dup number? ] [ number>string sql% ] }
+        { [ dup symbol? ] [ unparse sql% ] }
+        { [ dup word? ] [ unparse sql% ] }
+        { [ dup quotation? ] [ call ] }
+        [ no-sql-match ]
+    } cond ;
+
+: parse-sql ( obj -- sql in-spec out-spec in out )
+    [ [ sql% ] each ] { { } { } { } } nmake ;
diff --git a/basis/db/sqlite/authors.txt b/basis/db/sqlite/authors.txt
new file mode 100644 (file)
index 0000000..26093b4
--- /dev/null
@@ -0,0 +1,2 @@
+Chris Double
+Doug Coleman
diff --git a/basis/db/sqlite/ffi/ffi.factor b/basis/db/sqlite/ffi/ffi.factor
new file mode 100755 (executable)
index 0000000..b443f53
--- /dev/null
@@ -0,0 +1,140 @@
+! Copyright (C) 2005 Chris Double, Doug Coleman.
+! See http://factorcode.org/license.txt for BSD license.
+! 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 alien.c-types ;
+IN: db.sqlite.ffi
+
+<< "sqlite" {
+        { [ os winnt? ]  [ "sqlite3.dll" ] }
+        { [ os macosx? ] [ "/usr/lib/libsqlite3.dylib" ] }
+        { [ os unix? ]  [ "libsqlite3.so" ] }
+    } cond "cdecl" add-library >>
+
+! Return values from sqlite functions
+: SQLITE_OK           0   ; inline ! Successful result
+: SQLITE_ERROR        1   ; inline ! SQL error or missing database
+: SQLITE_INTERNAL     2   ; inline ! An internal logic error in SQLite 
+: SQLITE_PERM         3   ; inline ! Access permission denied 
+: SQLITE_ABORT        4   ; inline ! Callback routine requested an abort 
+: SQLITE_BUSY         5   ; inline ! The database file is locked 
+: SQLITE_LOCKED       6   ; inline ! A table in the database is locked 
+: SQLITE_NOMEM        7   ; inline ! A malloc() failed 
+: SQLITE_READONLY     8   ; inline ! Attempt to write a readonly database 
+: SQLITE_INTERRUPT    9   ; inline ! Operation terminated by sqlite_interrupt() 
+: SQLITE_IOERR       10   ; inline ! Some kind of disk I/O error occurred 
+: SQLITE_CORRUPT     11   ; inline ! The database disk image is malformed 
+: SQLITE_NOTFOUND    12   ; inline ! (Internal Only) Table or record not found 
+: SQLITE_FULL        13   ; inline ! Insertion failed because database is full 
+: SQLITE_CANTOPEN    14   ; inline ! Unable to open the database file 
+: SQLITE_PROTOCOL    15   ; inline ! Database lock protocol error 
+: SQLITE_EMPTY       16   ; inline ! (Internal Only) Database table is empty 
+: SQLITE_SCHEMA      17   ; inline ! The database schema changed 
+: SQLITE_TOOBIG      18   ; inline ! Too much data for one row of a table 
+: SQLITE_CONSTRAINT  19   ; inline ! Abort due to contraint violation 
+: SQLITE_MISMATCH    20   ; inline ! Data type mismatch 
+: SQLITE_MISUSE      21   ; inline ! Library used incorrectly 
+: SQLITE_NOLFS       22   ; inline ! Uses OS features not supported on host 
+: SQLITE_AUTH        23   ; inline ! Authorization denied 
+: SQLITE_FORMAT      24   ; inline ! Auxiliary database format error
+: SQLITE_RANGE       25   ; inline ! 2nd parameter to sqlite3_bind out of range
+: SQLITE_NOTADB      26   ; inline ! File opened that is not a database file
+
+: sqlite-error-messages ( -- seq ) {
+    "Successful result"
+    "SQL error or missing database"
+    "An internal logic error in SQLite"
+    "Access permission denied"
+    "Callback routine requested an abort"
+    "The database file is locked"
+    "A table in the database is locked"
+    "A malloc() failed"
+    "Attempt to write a readonly database"
+    "Operation terminated by sqlite_interrupt()"
+    "Some kind of disk I/O error occurred"
+    "The database disk image is malformed"
+    "(Internal Only) Table or record not found"
+    "Insertion failed because database is full"
+    "Unable to open the database file"
+    "Database lock protocol error"
+    "(Internal Only) Database table is empty"
+    "The database schema changed"
+    "Too much data for one row of a table"
+    "Abort due to contraint violation"
+    "Data type mismatch"
+    "Library used incorrectly"
+    "Uses OS features not supported on host"
+    "Authorization denied"
+    "Auxiliary database format error"
+    "2nd parameter to sqlite3_bind out of range"
+    "File opened that is not a database file"
+} ;
+
+! Return values from sqlite3_step
+: SQLITE_ROW         100  ; inline
+: SQLITE_DONE        101  ; inline
+
+! Return values from the sqlite3_column_type function
+: SQLITE_INTEGER     1 ; inline
+: SQLITE_FLOAT       2 ; inline
+: SQLITE_TEXT        3 ; inline
+: SQLITE_BLOB        4 ; inline
+: SQLITE_NULL        5 ; inline
+
+! Values for the 'destructor' parameter of the 'bind' routines. 
+: SQLITE_STATIC      0  ; inline
+: SQLITE_TRANSIENT   -1 ; inline
+
+: SQLITE_OPEN_READONLY         HEX: 00000001 ; inline
+: SQLITE_OPEN_READWRITE        HEX: 00000002 ; inline
+: SQLITE_OPEN_CREATE           HEX: 00000004 ; inline
+: SQLITE_OPEN_DELETEONCLOSE    HEX: 00000008 ; inline
+: SQLITE_OPEN_EXCLUSIVE        HEX: 00000010 ; inline
+: SQLITE_OPEN_MAIN_DB          HEX: 00000100 ; inline
+: SQLITE_OPEN_TEMP_DB          HEX: 00000200 ; inline
+: SQLITE_OPEN_TRANSIENT_DB     HEX: 00000400 ; inline
+: SQLITE_OPEN_MAIN_JOURNAL     HEX: 00000800 ; inline
+: SQLITE_OPEN_TEMP_JOURNAL     HEX: 00001000 ; inline
+: SQLITE_OPEN_SUBJOURNAL       HEX: 00002000 ; inline
+: SQLITE_OPEN_MASTER_JOURNAL   HEX: 00004000 ; inline
+
+TYPEDEF: void sqlite3
+TYPEDEF: void sqlite3_stmt
+TYPEDEF: longlong sqlite3_int64
+TYPEDEF: ulonglong sqlite3_uint64
+
+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 ) ;
+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 ) ;
+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 ) ;
+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 ) ;
+FUNCTION: int sqlite3_column_type ( sqlite3_stmt* pStmt, int col ) ;
diff --git a/basis/db/sqlite/lib/lib.factor b/basis/db/sqlite/lib/lib.factor
new file mode 100755 (executable)
index 0000000..03f424e
--- /dev/null
@@ -0,0 +1,172 @@
+! Copyright (C) 2008 Chris Double, Doug Coleman.
+! See http://factorcode.org/license.txt for BSD license.
+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
+io.backend db.errors present urls io.encodings.utf8
+io.encodings.string accessors ;
+IN: db.sqlite.lib
+
+ERROR: sqlite-error < db-error n string ;
+ERROR: sqlite-sql-error < sql-error n string ;
+
+: throw-sqlite-error ( n -- * )
+    dup sqlite-error-messages nth sqlite-error ;
+
+: sqlite-statement-error ( -- * )
+    SQLITE_ERROR
+    db get handle>> sqlite3_errmsg sqlite-sql-error ;
+
+: sqlite-check-result ( n -- )
+    {
+        { SQLITE_OK [ ] }
+        { SQLITE_ERROR [ sqlite-statement-error ] }
+        [ throw-sqlite-error ]
+    } case ;
+
+: sqlite-open ( path -- db )
+    normalize-path
+    "void*" <c-object>
+    [ sqlite3_open sqlite-check-result ] keep *void* ;
+
+: sqlite-close ( db -- )
+    sqlite3_close sqlite-check-result ;
+
+: sqlite-prepare ( db sql -- handle )
+    utf8 encode dup length "void*" <c-object> "void*" <c-object>
+    [ sqlite3_prepare_v2 sqlite-check-result ] 2keep
+    drop *void* ;
+
+: sqlite-bind-parameter-index ( handle name -- index )
+    sqlite3_bind_parameter_index ;
+
+: parameter-index ( handle name text -- handle name text )
+    >r dupd sqlite-bind-parameter-index r> ;
+
+: sqlite-bind-text ( handle index text -- )
+    utf8 encode dup length SQLITE_TRANSIENT
+    sqlite3_bind_text sqlite-check-result ;
+
+: sqlite-bind-int ( handle i n -- )
+    sqlite3_bind_int sqlite-check-result ;
+
+: 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 ;
+
+: sqlite-bind-null ( handle i -- )
+    sqlite3_bind_null sqlite-check-result ;
+
+: sqlite-bind-blob ( handle i byte-array -- )
+    dup length SQLITE_TRANSIENT
+    sqlite3_bind_blob sqlite-check-result ;
+
+: sqlite-bind-text-by-name ( handle name text -- )
+    parameter-index sqlite-bind-text ;
+
+: sqlite-bind-int-by-name ( handle name int -- )
+    parameter-index sqlite-bind-int ;
+
+: sqlite-bind-int64-by-name ( handle name int64 -- )
+    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 ;
+
+: sqlite-bind-blob-by-name ( handle name blob -- )
+    parameter-index sqlite-bind-blob ;
+
+: sqlite-bind-null-by-name ( handle name obj -- )
+    parameter-index drop sqlite-bind-null ;
+
+: sqlite-bind-type ( handle key value type -- )
+    over [ drop NULL ] unless
+    dup array? [ first ] when
+    {
+        { 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 ] }
+        { DATE [ timestamp>ymd sqlite-bind-text-by-name ] }
+        { TIME [ timestamp>hms sqlite-bind-text-by-name ] }
+        { DATETIME [ timestamp>ymdhms sqlite-bind-text-by-name ] }
+        { TIMESTAMP [ timestamp>ymdhms sqlite-bind-text-by-name ] }
+        { BLOB [ sqlite-bind-blob-by-name ] }
+        { FACTOR-BLOB [
+            object>bytes
+            sqlite-bind-blob-by-name
+        ] }
+        { URL [ present sqlite-bind-text-by-name ] }
+        { +db-assigned-id+ [ sqlite-bind-int-by-name ] }
+        { +random-id+ [ sqlite-bind-int64-by-name ] }
+        { NULL [ sqlite-bind-null-by-name ] }
+        [ no-sql-type ]
+    } case ;
+
+: 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 ;
+: sqlite-column-type ( handle index -- string ) sqlite3_column_type ;
+
+: sqlite-column-blob ( handle index -- byte-array/f )
+    [ sqlite3_column_bytes ] 2keep
+    pick zero? [
+        3drop f
+    ] [
+        sqlite3_column_blob swap memory>byte-array
+    ] if ;
+
+: sqlite-column-typed ( handle index type -- obj )
+    dup array? [ first ] when
+    {
+        { +db-assigned-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 ] }
+        { DATE [ sqlite3_column_text dup [ ymd>timestamp ] when ] }
+        { TIME [ sqlite3_column_text dup [ hms>timestamp ] when ] }
+        { TIMESTAMP [ sqlite3_column_text dup [ ymdhms>timestamp ] when ] }
+        { DATETIME [ sqlite3_column_text dup [ ymdhms>timestamp ] when ] }
+        { BLOB [ sqlite-column-blob ] }
+        { URL [ sqlite3_column_text dup [ >url ] when ] }
+        { FACTOR-BLOB [
+            sqlite-column-blob
+            dup [ bytes>object ] when
+        ] }
+        ! { NULL [ 2drop f ] }
+        [ no-sql-type ]
+    } case ;
+
+: sqlite-row ( handle -- seq )
+    dup sqlite-#columns [ sqlite-column ] with map ;
+
+: sqlite-step-has-more-rows? ( prepared -- bool )
+    {
+        { SQLITE_ROW [ t ] }
+        { SQLITE_DONE [ f ] }
+        [ sqlite-check-result f ]
+    } case ;
+
+: sqlite-next ( prepared -- ? )
+    sqlite3_step sqlite-step-has-more-rows? ;
diff --git a/basis/db/sqlite/sqlite-tests.factor b/basis/db/sqlite/sqlite-tests.factor
new file mode 100755 (executable)
index 0000000..b30cb4b
--- /dev/null
@@ -0,0 +1,76 @@
+USING: io io.files io.launcher kernel namespaces
+prettyprint tools.test db.sqlite db sequences
+continuations db.types db.tuples unicode.case ;
+IN: db.sqlite.tests
+
+: db-path "test.db" temp-file ;
+: test.db db-path sqlite-db ;
+
+[ ] [ [ db-path delete-file ] ignore-errors ] unit-test
+
+[ ] [
+    test.db [
+        "create table person (name varchar(30), country varchar(30))" sql-command
+        "insert into person values('John', 'America')" sql-command
+        "insert into person values('Jane', 'New Zealand')" sql-command
+    ] with-db
+] unit-test
+
+
+[ { { "John" "America" } { "Jane" "New Zealand" } } ] [
+    test.db [
+        "select * from person" sql-query
+    ] with-db
+] unit-test
+
+[ { { "1" "John" "America" } { "2" "Jane" "New Zealand" } } ]
+[ test.db [ "select rowid, * from person" sql-query ] with-db ] unit-test
+
+[ ] [
+    test.db [
+        "insert into person(name, country) values('Jimmy', 'Canada')"
+        sql-command
+    ] with-db
+] unit-test
+
+[
+    {
+        { "1" "John" "America" }
+        { "2" "Jane" "New Zealand" }
+        { "3" "Jimmy" "Canada" }
+    }
+] [ test.db [ "select rowid, * from person" sql-query ] with-db ] unit-test
+
+[
+    test.db [
+        [
+            "insert into person(name, country) values('Jose', 'Mexico')" sql-command
+            "insert into person(name, country) values('Jose', 'Mexico')" sql-command
+            "oops" throw
+        ] with-transaction
+    ] with-db
+] must-fail
+
+[ 3 ] [
+    test.db [
+        "select * from person" sql-query length
+    ] with-db
+] unit-test
+
+[
+] [
+    test.db [
+        [
+            "insert into person(name, country) values('Jose', 'Mexico')"
+            sql-command
+            "insert into person(name, country) values('Jose', 'Mexico')"
+            sql-command
+        ] with-transaction
+    ] with-db
+] unit-test
+
+[ 5 ] [
+    test.db [
+        "select * from person" sql-query length
+    ] with-db
+] unit-test
diff --git a/basis/db/sqlite/sqlite.factor b/basis/db/sqlite/sqlite.factor
new file mode 100755 (executable)
index 0000000..231b60e
--- /dev/null
@@ -0,0 +1,200 @@
+! Copyright (C) 2005, 2008 Chris Double, Doug Coleman.
+! See http://factorcode.org/license.txt for BSD license.
+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 math.intervals
+io namespaces.lib accessors vectors math.ranges random
+math.bitfields.lib db.queries destructors ;
+USE: tools.walker
+IN: db.sqlite
+
+TUPLE: sqlite-db < db path ;
+
+M: sqlite-db make-db* ( path db -- db )
+    swap >>path ;
+
+M: sqlite-db db-open ( db -- db )
+    dup path>> sqlite-open >>handle ;
+
+M: sqlite-db db-close ( handle -- ) sqlite-close ;
+M: sqlite-db dispose ( db -- ) dispose-db ;
+
+TUPLE: sqlite-statement < statement ;
+
+TUPLE: sqlite-result-set < result-set has-more? ;
+
+M: sqlite-db <simple-statement> ( str in out -- obj )
+    <prepared-statement> ;
+
+M: sqlite-db <prepared-statement> ( str in out -- obj )
+    sqlite-statement construct-statement ;
+
+: sqlite-maybe-prepare ( statement -- statement )
+    dup handle>> [
+        db get handle>> over sql>> sqlite-prepare
+        >>handle
+    ] unless ;
+
+M: sqlite-statement dispose ( statement -- )
+    handle>>
+    [ [ sqlite3_reset drop ] keep sqlite-finalize ] when* ;
+
+M: sqlite-result-set dispose ( result-set -- )
+    f >>handle drop ;
+
+: 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 -- )
+    [ bind-params>> ] [ handle>> ] bi
+    [ swap [ key>> ] [ value>> ] [ type>> ] tri sqlite-bind-type ] curry each ;
+
+M: sqlite-statement bind-statement* ( statement -- )
+    sqlite-maybe-prepare
+    dup bound?>> [ dup reset-bindings ] when
+    low-level-bind ;
+
+GENERIC: sqlite-bind-conversion ( tuple obj -- array )
+
+TUPLE: sqlite-low-level-binding < low-level-binding key type ;
+: <sqlite-low-level-binding> ( key value type -- obj )
+    sqlite-low-level-binding new
+        swap >>type
+        swap >>value
+        swap >>key ;
+
+M: sql-spec sqlite-bind-conversion ( tuple spec -- array )
+    [ column-name>> ":" prepend ]
+    [ slot-name>> rot get-slot-named ]
+    [ type>> ] tri <sqlite-low-level-binding> ;
+
+M: literal-bind sqlite-bind-conversion ( tuple literal-bind -- array )
+    nip [ key>> ] [ value>> ] [ type>> ] tri
+    <sqlite-low-level-binding> ;
+
+M: generator-bind sqlite-bind-conversion ( tuple generate-bind -- array )
+    tuck
+    [ generator-singleton>> eval-generator tuck ] [ slot-name>> ] bi
+    rot set-slot-named
+    >r [ key>> ] [ type>> ] bi r> swap <sqlite-low-level-binding> ;
+
+M: sqlite-statement bind-tuple ( tuple statement -- )
+    [
+        in-params>> [ sqlite-bind-conversion ] with map
+    ] keep bind-statement ;
+
+: last-insert-id ( -- id )
+    db get handle>> sqlite3_last_insert_rowid
+    dup zero? [ "last-id failed" throw ] when ;
+
+M: sqlite-db insert-tuple* ( tuple statement -- )
+    execute-statement last-insert-id swap set-primary-key ;
+
+M: sqlite-result-set #columns ( result-set -- n )
+    handle>> sqlite-#columns ;
+
+M: sqlite-result-set row-column ( result-set n -- obj )
+    [ handle>> ] [ sqlite-column ] bi* ;
+
+M: sqlite-result-set row-column-typed ( result-set n -- obj )
+    dup pick out-params>> nth type>>
+    >r >r handle>> r> r> sqlite-column-typed ;
+
+M: sqlite-result-set advance-row ( result-set -- )
+    dup handle>> sqlite-next >>has-more? drop ;
+
+M: sqlite-result-set more-rows? ( result-set -- ? )
+    has-more?>> ;
+
+M: sqlite-statement query-results ( query -- result-set )
+    sqlite-maybe-prepare
+    dup handle>> sqlite-result-set construct-result-set
+    dup advance-row ;
+
+M: sqlite-db create-sql-statement ( class -- statement )
+    [
+        "create table " 0% 0%
+        "(" 0% [ ", " 0% ] [
+            dup column-name>> 0%
+            " " 0%
+            dup type>> lookup-create-type 0%
+            modifiers 0%
+        ] interleave ");" 0%
+    ] query-make ;
+
+M: sqlite-db drop-sql-statement ( class -- statement )
+    [ "drop table " 0% 0% ";" 0% drop ] query-make ;
+
+M: sqlite-db <insert-db-assigned-statement> ( tuple -- statement )
+    [
+        "insert into " 0% 0%
+        "(" 0%
+        remove-db-assigned-id
+        dup [ ", " 0% ] [ column-name>> 0% ] interleave
+        ") values(" 0%
+        [ ", " 0% ] [
+            dup type>> +random-id+ = [
+                [ slot-name>> ]
+                [
+                    column-name>> ":" prepend dup 0%
+                    random-id-generator
+                ] [ type>> ] tri <generator-bind> 1,
+            ] [
+                bind%
+            ] if
+        ] interleave
+        ");" 0%
+    ] query-make ;
+
+M: sqlite-db <insert-user-assigned-statement> ( tuple -- statement )
+    <insert-db-assigned-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% ;
+
+M: sqlite-db persistent-table ( -- assoc )
+    H{
+        { +db-assigned-id+ { "integer primary key" "integer primary key" "primary key" } }
+        { +user-assigned-id+ { f f "primary key" } }
+        { +random-id+ { "integer primary key" "integer primary key" "primary key" } }
+        { 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" } }
+        { URL { "text" "text" } }
+        { +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 compound ( str seq -- str' )
+    over {
+        { "default" [ first number>string join-space ] }
+        [ 2drop ] 
+    } case ;
diff --git a/basis/db/sqlite/test.txt b/basis/db/sqlite/test.txt
new file mode 100644 (file)
index 0000000..e4487d3
--- /dev/null
@@ -0,0 +1,3 @@
+create table person (name varchar(30), country varchar(30));
+insert into person values('John', 'America');
+insert into person values('Jane', 'New Zealand');
diff --git a/basis/db/summary.txt b/basis/db/summary.txt
new file mode 100644 (file)
index 0000000..daebf38
--- /dev/null
@@ -0,0 +1 @@
+Relational database abstraction layer
diff --git a/basis/db/tags.txt b/basis/db/tags.txt
new file mode 100644 (file)
index 0000000..0aef4fe
--- /dev/null
@@ -0,0 +1 @@
+enterprise
diff --git a/basis/db/tuples/tuples-tests.factor b/basis/db/tuples/tuples-tests.factor
new file mode 100755 (executable)
index 0000000..5dd3ec8
--- /dev/null
@@ -0,0 +1,501 @@
+! Copyright (C) 2008 Doug Coleman.
+! 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 calendar sequences db.sqlite math.intervals
+db.postgresql accessors random math.bitfields.lib
+math.ranges strings sequences.lib urls fry ;
+IN: db.tuples.tests
+
+TUPLE: person the-id the-name the-number the-real
+ts date time blob factor-blob url ;
+
+: <person> ( name age real ts date time blob factor-blob url -- person )
+    person new
+        swap >>url
+        swap >>factor-blob
+        swap >>blob
+        swap >>time
+        swap >>date
+        swap >>ts
+        swap >>the-real
+        swap >>the-number
+        swap >>the-name ;
+
+: <user-assigned-person> ( id name age real ts date time blob factor-blob url -- person )
+    <person>
+        swap >>the-id ;
+
+SYMBOL: person1
+SYMBOL: person2
+SYMBOL: person3
+SYMBOL: person4
+
+: test-tuples ( -- )
+    [ ] [ person recreate-table ] unit-test
+    [ ] [ person ensure-table ] unit-test
+    [ ] [ person drop-table ] unit-test
+    [ ] [ person create-table ] unit-test
+    [ person create-table ] must-fail
+    [ ] [ person ensure-table ] unit-test
+    
+    [ ] [ person1 get insert-tuple ] unit-test
+
+    [ 1 ] [ person1 get the-id>> ] unit-test
+
+    [ ] [ person1 get 200 >>the-number drop ] unit-test
+
+    [ ] [ person1 get update-tuple ] unit-test
+
+    [ T{ person f 1 "billy" 200 3.14 } ]
+    [ T{ person f 1 } select-tuple ] unit-test
+    [ ] [ person2 get insert-tuple ] unit-test
+    [
+        {
+            T{ person f 1 "billy" 200 3.14 }
+            T{ person f 2 "johnny" 10 3.14 }
+        }
+    ] [ T{ person f f f f 3.14 } select-tuples ] unit-test
+    [
+        {
+            T{ person f 1 "billy" 200 3.14 }
+            T{ person f 2 "johnny" 10 3.14 }
+        }
+    ] [ T{ person f } select-tuples ] unit-test
+
+    [
+        {
+            T{ person f 2 "johnny" 10 3.14 }
+        }
+    ] [ T{ person f f f 10 3.14 } select-tuples ] unit-test
+
+
+    [ ] [ person1 get delete-tuples ] unit-test
+    [ f ] [ T{ person f 1 } select-tuple ] unit-test
+
+    [ ] [ person3 get insert-tuple ] unit-test
+
+    [
+        T{
+            person
+            f
+            3
+            "teddy"
+            10
+            3.14
+            T{ timestamp f 2008 3 5 16 24 11 T{ duration f 0 0 0 0 0 0 } }
+            T{ timestamp f 2008 11 22 0 0 0 T{ duration f 0 0 0 0 0 0 } }
+            T{ timestamp f 0 0 0 12 34 56 T{ duration f 0 0 0 0 0 0 } }
+            B{ 115 116 111 114 101 105 110 97 98 108 111 98 }
+        }
+    ] [ T{ person f 3 } select-tuple ] unit-test
+
+    [ ] [ person4 get insert-tuple ] unit-test
+    [
+        T{
+            person
+            f
+            4
+            "eddie"
+            10
+            3.14
+            T{ timestamp f 2008 3 5 16 24 11 T{ duration f 0 0 0 0 0 0 } }
+            T{ timestamp f 2008 11 22 0 0 0 T{ duration f 0 0 0 0 0 0 } }
+            T{ timestamp f 0 0 0 12 34 56 T{ duration f 0 0 0 0 0 0 } }
+            f
+            H{ { 1 2 } { 3 4 } { 5 "lol" } }
+            URL" http://www.google.com/search?hl=en&q=trailer+park+boys&btnG=Google+Search"
+        }
+    ] [ T{ person f 4 } select-tuple ] unit-test
+
+    [ ] [ person drop-table ] unit-test ;
+
+: db-assigned-person-schema ( -- )
+    person "PERSON"
+    {
+        { "the-id" "ID" +db-assigned-id+ }
+        { "the-name" "NAME" { VARCHAR 256 } +not-null+ }
+        { "the-number" "AGE" INTEGER { +default+ 0 } }
+        { "the-real" "REAL" DOUBLE { +default+ 0.3 } }
+        { "ts" "TS" TIMESTAMP }
+        { "date" "D" DATE }
+        { "time" "T" TIME }
+        { "blob" "B" BLOB }
+        { "factor-blob" "FB" FACTOR-BLOB }
+        { "url" "U" URL }
+    } define-persistent
+    "billy" 10 3.14 f f f f f f <person> person1 set
+    "johnny" 10 3.14 f f f f f f <person> person2 set
+    "teddy" 10 3.14
+        T{ timestamp f 2008 3 5 16 24 11 T{ duration f 0 0 0 0 0 0 } }
+        T{ timestamp f 2008 11 22 0 0 0 T{ duration f 0 0 0 0 0 0 } }
+        T{ timestamp f 0 0 0 12 34 56 T{ duration f 0 0 0 0 0 0 } }
+        B{ 115 116 111 114 101 105 110 97 98 108 111 98 } f f <person> person3 set
+    "eddie" 10 3.14
+        T{ timestamp f 2008 3 5 16 24 11 T{ duration f 0 0 0 0 0 0 } }
+        T{ timestamp f 2008 11 22 0 0 0 T{ duration f 0 0 0 0 0 0 } }
+        T{ timestamp f 0 0 0 12 34 56 T{ duration f 0 0 0 0 0 0 } }
+        f H{ { 1 2 } { 3 4 } { 5 "lol" } } URL" http://www.google.com/search?hl=en&q=trailer+park+boys&btnG=Google+Search"  <person> person4 set ;
+
+: user-assigned-person-schema ( -- )
+    person "PERSON"
+    {
+        { "the-id" "ID" INTEGER +user-assigned-id+ }
+        { "the-name" "NAME" { VARCHAR 256 } +not-null+ }
+        { "the-number" "AGE" INTEGER { +default+ 0 } }
+        { "the-real" "REAL" DOUBLE { +default+ 0.3 } }
+        { "ts" "TS" TIMESTAMP }
+        { "date" "D" DATE }
+        { "time" "T" TIME }
+        { "blob" "B" BLOB }
+        { "factor-blob" "FB" FACTOR-BLOB }
+        { "url" "U" URL }
+    } define-persistent
+    1 "billy" 10 3.14 f f f f f f <user-assigned-person> person1 set
+    2 "johnny" 10 3.14 f f f f f f <user-assigned-person> person2 set
+    3 "teddy" 10 3.14
+        T{ timestamp f 2008 3 5 16 24 11 T{ duration f 0 0 0 0 0 0 } }
+        T{ timestamp f 2008 11 22 0 0 0 T{ duration f 0 0 0 0 0 0 } }
+        T{ timestamp f 0 0 0 12 34 56 T{ duration f 0 0 0 0 0 0 } }
+        B{ 115 116 111 114 101 105 110 97 98 108 111 98 }
+        f f <user-assigned-person> person3 set
+    4 "eddie" 10 3.14
+        T{ timestamp f 2008 3 5 16 24 11 T{ duration f 0 0 0 0 0 0 } }
+        T{ timestamp f 2008 11 22 0 0 0 T{ duration f 0 0 0 0 0 0 } }
+        T{ timestamp f 0 0 0 12 34 56 T{ duration f 0 0 0 0 0 0 } }
+        f H{ { 1 2 } { 3 4 } { 5 "lol" } } URL" http://www.google.com/search?hl=en&q=trailer+park+boys&btnG=Google+Search" <user-assigned-person> person4 set ;
+
+TUPLE: paste n summary author channel mode contents timestamp annotations ;
+TUPLE: annotation n paste-id summary author mode contents ;
+
+: db-assigned-paste-schema ( -- )
+    paste "PASTE"
+    {
+        { "n" "ID" +db-assigned-id+ }
+        { "summary" "SUMMARY" TEXT }
+        { "author" "AUTHOR" TEXT }
+        { "channel" "CHANNEL" TEXT }
+        { "mode" "MODE" TEXT }
+        { "contents" "CONTENTS" TEXT }
+        { "date" "DATE" TIMESTAMP }
+        { "annotations" { +has-many+ annotation } }
+    } define-persistent
+
+    annotation "ANNOTATION"
+    {
+        { "n" "ID" +db-assigned-id+ }
+        { "paste-id" "PASTE_ID" INTEGER { +foreign-id+ paste "n" } }
+        { "summary" "SUMMARY" TEXT }
+        { "author" "AUTHOR" TEXT }
+        { "mode" "MODE" TEXT }
+        { "contents" "CONTENTS" TEXT }
+    } define-persistent ;
+
+! { "localhost" "postgres" "" "factor-test" } postgresql-db [
+    ! [ paste drop-table ] [ drop ] recover
+    ! [ annotation drop-table ] [ drop ] recover
+    ! [ paste drop-table ] [ drop ] recover
+    ! [ annotation drop-table ] [ drop ] recover
+    ! [ ] [ paste create-table ] unit-test
+    ! [ ] [ annotation create-table ] unit-test
+! ] with-db
+
+: test-sqlite ( quot -- )
+    [ ] swap '[ "tuples-test.db" temp-file sqlite-db , with-db ] unit-test ;
+
+: test-postgresql ( quot -- )
+    [ ] swap '[ { "localhost" "postgres" "foob" "factor-test" } postgresql-db , with-db ] unit-test ;
+
+: test-repeated-insert
+    [ ] [ person ensure-table ] unit-test
+    [ ] [ person1 get insert-tuple ] unit-test
+    [ person1 get insert-tuple ] must-fail ;
+
+TUPLE: serialize-me id data ;
+
+: test-serialize ( -- )
+    serialize-me "SERIALIZED"
+    {
+        { "id" "ID" +db-assigned-id+ }
+        { "data" "DATA" FACTOR-BLOB }
+    } define-persistent
+    [ serialize-me drop-table ] [ drop ] recover
+    [ ] [ serialize-me create-table ] unit-test
+
+    [ ] [ T{ serialize-me f f H{ { 1 2 } } } insert-tuple ] unit-test
+    [
+        { T{ serialize-me f 1 H{ { 1 2 } } } }
+    ] [ T{ serialize-me f 1 } select-tuples ] unit-test ;
+
+TUPLE: exam id name score ; 
+
+: random-exam ( -- exam )
+        f
+        6 [ CHAR: a CHAR: z [a,b] random ] replicate >string
+        100 random
+    exam boa ;
+
+: test-intervals ( -- )
+    exam "EXAM"
+    {
+        { "id" "ID" +db-assigned-id+ }
+        { "name" "NAME" TEXT }
+        { "score" "SCORE" INTEGER }
+    } define-persistent
+    [ exam drop-table ] [ drop ] recover
+    [ ] [ exam create-table ] unit-test
+
+    [ ] [ T{ exam f f "Kyle" 100 } insert-tuple ] unit-test
+    [ ] [ T{ exam f f "Stan" 80 } insert-tuple ] unit-test
+    [ ] [ T{ exam f f "Kenny" 60 } insert-tuple ] unit-test
+    [ ] [ 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 f f T{ interval f { 0 t } { 70 t } } } select-tuples
+    ] unit-test
+
+    [
+        { }
+    ] [
+        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
+
+    [
+        {
+            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
+
+    [
+        {
+            T{ exam f 2 "Stan" 80 }
+            T{ exam f 3 "Kenny" 60 }
+            T{ exam f 4 "Cartman" 41 }
+        }
+    ] [
+        T{ exam f T{ interval f { 2 t } { 1.0/0.0 f } } } select-tuples
+    ] unit-test
+
+    [
+        {
+            T{ exam f 1 "Kyle" 100 }
+        }
+    ] [
+        T{ exam f T{ interval f { -1.0/0.0 t } { 2 f } } } 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 4 "Cartman" 41 }
+        }
+    ] [
+        T{ exam f T{ interval f { -1.0/0.0 t } { 1/0. f } } } 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 4 "Cartman" 41 }
+        }
+    ] [
+        T{ exam } select-tuples
+    ] unit-test
+
+    [ 4 ] [ T{ exam } f count-tuples ] unit-test ;
+
+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" +db-assigned-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^ 1- dup dup <bignum-test> insert-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
+
+: test-random-id
+    secret "SECRET"
+    {
+        { "n" "ID" +random-id+ system-random-generator }
+        { "message" "MESSAGE" TEXT }
+    } define-persistent
+
+    [ ] [ secret recreate-table ] unit-test
+
+    [ t ] [ f "kilroy was here" <secret> [ insert-tuple ] keep n>> integer? ] 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 ;
+
+[ db-assigned-person-schema test-tuples ] test-sqlite
+[ user-assigned-person-schema test-tuples ] test-sqlite
+[ user-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
+
+[ db-assigned-person-schema test-tuples ] test-postgresql
+[ user-assigned-person-schema test-tuples ] test-postgresql
+[ user-assigned-person-schema test-repeated-insert ] test-postgresql
+[ 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-postgresql
+
+
+TUPLE: suparclass id a ;
+
+suparclass f {
+    { "id" "ID" +db-assigned-id+ }
+    { "a" "A" INTEGER }
+} define-persistent
+
+TUPLE: subbclass < suparclass b ;
+
+subbclass "SUBCLASS" {
+    { "b" "B" TEXT }
+} define-persistent
+
+TUPLE: fubbclass < subbclass ;
+
+fubbclass "FUBCLASS" { } define-persistent
+
+: test-db-inheritance ( -- )
+    [ ] [ subbclass ensure-table ] unit-test
+    [ ] [ fubbclass ensure-table ] unit-test
+    
+    [ ] [
+        subbclass new 5 >>a "hi" >>b dup insert-tuple id>> "id" set
+    ] unit-test
+    
+    [ t "hi" 5 ] [
+        subbclass new "id" get >>id select-tuple
+        [ subbclass? ] [ b>> ] [ a>> ] tri
+    ] unit-test
+    
+    [ ] [ fubbclass new 0 >>a "hi" >>b insert-tuple ] unit-test
+    
+    [ t ] [ fubbclass new select-tuples [ fubbclass? ] all? ] unit-test ;
+
+[ test-db-inheritance ] test-sqlite
+[ test-db-inheritance ] test-postgresql
+
+
+TUPLE: string-encoding-test id string ;
+
+string-encoding-test "STRING_ENCODING_TEST" {
+    { "id" "ID" +db-assigned-id+ }
+    { "string" "STRING" TEXT }
+} define-persistent
+
+: test-string-encoding ( -- )
+    [ ] [ string-encoding-test ensure-table ] unit-test
+
+    [ ] [
+        string-encoding-test new
+            "\u{copyright-sign}\u{bengali-letter-cha}" >>string
+        [ insert-tuple ] [ id>> "id" set ] bi
+    ] unit-test
+    
+    [ "\u{copyright-sign}\u{bengali-letter-cha}" ] [
+        string-encoding-test new "id" get >>id select-tuple string>>
+    ] unit-test ;
+
+[ test-string-encoding ] test-sqlite
+[ test-string-encoding ] test-postgresql
+
+! Don't comment these out. These words must infer
+\ bind-tuple must-infer
+\ insert-tuple must-infer
+\ update-tuple must-infer
+\ delete-tuples must-infer
+\ select-tuple must-infer
+\ define-persistent must-infer
+\ ensure-table must-infer
+\ create-table must-infer
+\ drop-table must-infer
diff --git a/basis/db/tuples/tuples.factor b/basis/db/tuples/tuples.factor
new file mode 100755 (executable)
index 0000000..1b7ab24
--- /dev/null
@@ -0,0 +1,172 @@
+! 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 accessors
+math.parser io prettyprint db.types continuations
+destructors mirrors sequences.lib combinators.lib ;
+IN: db.tuples
+
+: define-persistent ( class table columns -- )
+    >r dupd "db-table" set-word-prop dup r>
+    [ relation? ] partition swapd
+    dupd [ spec>tuple ] with map
+    "db-columns" set-word-prop
+    "db-relations" set-word-prop ;
+
+ERROR: not-persistent class ;
+
+: db-table ( class -- obj )
+    dup "db-table" word-prop [ ] [ not-persistent ] ?if ;
+
+: db-columns ( class -- obj )
+    superclasses [ "db-columns" word-prop ] map concat ;
+
+: db-relations ( class -- obj )
+    "db-relations" word-prop ;
+
+: set-primary-key ( key tuple -- )
+    [
+        class db-columns find-primary-key slot-name>>
+    ] keep set-slot-named ;
+
+SYMBOL: sql-counter
+: next-sql-counter ( -- str )
+    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 )
+
+HOOK: <insert-db-assigned-statement> db ( class -- obj )
+HOOK: <insert-user-assigned-statement> db ( class -- obj )
+HOOK: <update-tuple-statement> db ( class -- obj )
+HOOK: <delete-tuples-statement> db ( tuple class -- obj )
+HOOK: <select-by-slots-statement> db ( tuple class -- tuple )
+TUPLE: query group order offset limit ;
+HOOK: <query> db ( tuple class query -- statement' )
+HOOK: <count-statement> db ( tuple class groups -- n )
+
+HOOK: insert-tuple* db ( tuple statement -- )
+
+GENERIC: eval-generator ( singleton -- obj )
+SINGLETON: retryable
+
+: make-retryable ( obj -- obj' )
+    dup sequence? [
+        [ make-retryable ] map
+    ] [
+        retryable >>type
+        10 >>retries
+    ] if ;
+
+: regenerate-params ( statement -- statement )
+    dup
+    [ bind-params>> ] [ in-params>> ] bi
+    [
+        dup generator-bind? [
+            generator-singleton>> eval-generator >>value
+        ] [
+            drop
+        ] if
+    ] 2map >>bind-params ;
+
+M: retryable execute-statement* ( statement type -- )
+    drop [
+        [
+            [ query-results dispose t ]
+            [ ]
+            [ regenerate-params bind-statement* f ] cleanup
+        ] curry
+    ] [ retries>> ] bi retry drop ;
+
+: resulting-tuple ( class row out-params -- tuple )
+    rot class new [
+        [
+            >r slot-name>> r> set-slot-named
+        ] curry 2each
+    ] keep ;
+
+: query-tuples ( exemplar-tuple statement -- seq )
+    [ out-params>> ] keep query-results [
+        [ sql-row-typed swap resulting-tuple ] with with query-map
+    ] with-disposal ;
+: query-modify-tuple ( tuple statement -- )
+    [ query-results [ sql-row-typed ] with-disposal ] keep
+    out-params>> rot [
+        >r slot-name>> r> set-slot-named
+    ] curry 2each ;
+
+: sql-props ( class -- columns table )
+    [ db-columns ] [ db-table ] bi ;
+
+: with-disposals ( seq quot -- )
+    over sequence? [
+        [ with-disposal ] curry each
+    ] [
+        with-disposal
+    ] if ; inline
+
+: create-table ( class -- )
+    create-sql-statement [ execute-statement ] with-disposals ;
+
+: drop-table ( class -- )
+    drop-sql-statement [ execute-statement ] with-disposals ;
+
+: recreate-table ( class -- )
+    [
+        [ drop-sql-statement [ execute-statement ] with-disposals
+        ] curry ignore-errors
+    ] [ create-table ] bi ;
+
+: ensure-table ( class -- )
+    [ create-table ] curry ignore-errors ;
+
+: ensure-tables ( classes -- )
+    [ ensure-table ] each ;
+
+: insert-db-assigned-statement ( tuple -- )
+    dup class
+    db get insert-statements>> [ <insert-db-assigned-statement> ] cache
+    [ bind-tuple ] 2keep insert-tuple* ;
+
+: insert-user-assigned-statement ( tuple -- )
+    dup class
+    db get insert-statements>> [ <insert-user-assigned-statement> ] cache
+    [ bind-tuple ] keep execute-statement ;
+
+: insert-tuple ( tuple -- )
+    dup class db-columns find-primary-key db-assigned-id-spec?
+    [ insert-db-assigned-statement ] [ insert-user-assigned-statement ] if ;
+
+: update-tuple ( tuple -- )
+    dup class
+    db get update-statements>> [ <update-tuple-statement> ] cache
+    [ bind-tuple ] keep execute-statement ;
+
+: delete-tuples ( tuple -- )
+    dup dup class <delete-tuples-statement> [
+        [ bind-tuple ] keep execute-statement
+    ] with-disposal ;
+
+: do-select ( exemplar-tuple statement -- tuples )
+    [ [ bind-tuple ] [ query-tuples ] 2bi ] with-disposal ;
+
+: query ( tuple query -- tuples )
+    >r dup dup class r> <query> do-select ;
+
+: select-tuples ( tuple -- tuples )
+    dup dup class <select-by-slots-statement> do-select ;
+
+: select-tuple ( tuple -- tuple/f )
+    dup dup class \ query new 1 >>limit <query> do-select ?first ;
+
+: do-count ( exemplar-tuple statement -- tuples )
+    [
+        [ bind-tuple ] [ nip default-query ] 2bi
+    ] with-disposal ;
+
+: count-tuples ( tuple groups -- n )
+    >r dup dup class r> <count-statement> do-count
+    dup length 1 =
+    [ first first string>number ] [ [ first string>number ] map ] if ;
diff --git a/basis/db/types/types.factor b/basis/db/types/types.factor
new file mode 100755 (executable)
index 0000000..c348009
--- /dev/null
@@ -0,0 +1,161 @@
+! Copyright (C) 2008 Doug Coleman.
+! See http://factorcode.org/license.txt for BSD license.
+USING: arrays assocs db kernel math math.parser
+sequences continuations sequences.deep sequences.lib
+words namespaces slots slots.private classes mirrors
+classes.tuple combinators calendar.format symbols
+classes.singleton accessors quotations random ;
+IN: db.types
+
+HOOK: persistent-table db ( -- hash )
+HOOK: compound db ( str obj -- hash )
+
+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 slot-name key generator-singleton type ;
+C: <generator-bind> generator-bind
+SINGLETON: random-id-generator
+
+TUPLE: low-level-binding value ;
+C: <low-level-binding> low-level-binding
+
+SINGLETON: +db-assigned-id+
+SINGLETON: +user-assigned-id+
+SINGLETON: +random-id+
+UNION: +primary-key+ +db-assigned-id+ +user-assigned-id+ +random-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 -- ? )
+    primary-key>> +primary-key+? ;
+
+: db-assigned-id-spec? ( spec -- ? )
+    primary-key>> +db-assigned-id+? ;
+
+: assigned-id-spec? ( spec -- ? )
+    primary-key>> +user-assigned-id+? ;
+
+: normalize-spec ( spec -- )
+    dup type>> dup +primary-key+? [
+        >>primary-key drop
+    ] [
+        drop dup modifiers>> [
+            +primary-key+?
+        ] deep-find
+        [ >>primary-key drop ] [ drop ] if*
+    ] if ;
+
+: find-primary-key ( specs -- obj )
+    [ primary-key>> ] find nip ;
+
+: relation? ( spec -- ? ) [ +has-many+ = ] deep-find ;
+
+SYMBOLS: INTEGER BIG-INTEGER SIGNED-BIG-INTEGER UNSIGNED-BIG-INTEGER
+DOUBLE REAL BOOLEAN TEXT VARCHAR DATE TIME DATETIME TIMESTAMP BLOB
+FACTOR-BLOB NULL URL ;
+
+: spec>tuple ( class spec -- tuple )
+    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 ;
+
+: number>string* ( n/str -- str )
+    dup number? [ number>string ] when ;
+
+: remove-db-assigned-id ( specs -- obj )
+    [ +db-assigned-id+? not ] filter ;
+
+: remove-relations ( specs -- newcolumns )
+    [ relation? not ] filter ;
+
+: remove-id ( specs -- obj )
+    [ primary-key>> not ] filter ;
+
+! SQLite Types: http://www.sqlite.org/datatype3.html
+! NULL INTEGER REAL TEXT BLOB
+! PostgreSQL Types:
+! http://developer.postgresql.org/pgdocs/postgres/datatype.html
+
+ERROR: unknown-modifier ;
+
+: lookup-modifier ( obj -- str )
+    {
+        { [ dup array? ] [ unclip lookup-modifier swap compound ] }
+        [ persistent-table at* [ unknown-modifier ] unless third ]
+    } cond ;
+
+ERROR: no-sql-type ;
+
+: (lookup-type) ( obj -- str )
+    persistent-table at* [ no-sql-type ] unless ;
+
+: lookup-type ( obj -- str )
+    dup array? [
+        unclip (lookup-type) first nip
+    ] [
+        (lookup-type) first
+    ] if ;
+
+: lookup-create-type ( obj -- str )
+    dup array? [
+        unclip (lookup-type) second swap compound
+    ] [
+        (lookup-type) second
+    ] if ;
+
+: single-quote ( str -- newstr )
+    "'" swap "'" 3append ;
+
+: double-quote ( str -- newstr )
+    "\"" swap "\"" 3append ;
+
+: paren ( str -- newstr )
+    "(" swap ")" 3append ;
+
+: join-space ( str1 str2 -- newstr )
+    " " swap 3append ;
+
+: modifiers ( spec -- str )
+    modifiers>> [ lookup-modifier ] map " " join
+    dup empty? [ " " prepend ] unless ;
+
+HOOK: bind% db ( spec -- )
+HOOK: bind# db ( spec obj -- )
+
+: offset-of-slot ( str obj -- n )
+    class superclasses [ "slots" word-prop ] map concat
+    slot-named offset>> ;
+
+: get-slot-named ( name obj -- value )
+    tuck offset-of-slot slot ;
+
+: set-slot-named ( value name obj -- )
+    tuck offset-of-slot set-slot ;
+
+: tuple>filled-slots ( tuple -- alist )
+    <mirror> [ nip ] assoc-filter ;
+
+: tuple>params ( specs tuple -- obj )
+    [
+        >r [ type>> ] [ slot-name>> ] bi r>
+        get-slot-named swap
+    ] curry { } map>assoc ;
diff --git a/extra/db/authors.txt b/extra/db/authors.txt
deleted file mode 100644 (file)
index 7c1b2f2..0000000
+++ /dev/null
@@ -1 +0,0 @@
-Doug Coleman
diff --git a/extra/db/db-tests.factor b/extra/db/db-tests.factor
deleted file mode 100755 (executable)
index 0d95e3a..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-IN: db.tests\r
-USING: tools.test db kernel ;\r
-\r
-{ 1 0 } [ [ drop ] query-each ] must-infer-as\r
-{ 1 1 } [ [ ] query-map ] must-infer-as\r
-{ 2 0 } [ [ ] with-db ] must-infer-as\r
diff --git a/extra/db/db.factor b/extra/db/db.factor
deleted file mode 100755 (executable)
index c52d1db..0000000
+++ /dev/null
@@ -1,146 +0,0 @@
-! Copyright (C) 2008 Doug Coleman.
-! See http://factorcode.org/license.txt for BSD license.
-USING: arrays assocs classes continuations destructors kernel math
-namespaces sequences sequences.lib classes.tuple words strings
-tools.walker accessors combinators.lib ;
-IN: db
-
-TUPLE: db
-    handle
-    insert-statements
-    update-statements
-    delete-statements ;
-
-: new-db ( class -- obj )
-    new
-        H{ } clone >>insert-statements
-        H{ } clone >>update-statements
-        H{ } clone >>delete-statements ;
-
-GENERIC: make-db* ( seq class -- db )
-
-: make-db ( seq class -- db )
-    new-db make-db* ;
-
-GENERIC: db-open ( db -- db )
-HOOK: db-close db ( handle -- )
-
-: dispose-statements ( assoc -- ) values dispose-each ;
-
-: dispose-db ( db -- ) 
-    dup db [
-        dup insert-statements>> dispose-statements
-        dup update-statements>> dispose-statements
-        dup delete-statements>> dispose-statements
-        handle>> db-close
-    ] with-variable ;
-
-TUPLE: statement handle sql in-params out-params bind-params bound? type retries ;
-TUPLE: simple-statement < statement ;
-TUPLE: prepared-statement < statement ;
-
-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 ;
-
-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 )
-GENERIC: #columns ( result-set -- n )
-GENERIC# row-column 1 ( result-set column -- obj )
-GENERIC# row-column-typed 1 ( result-set column -- sql )
-GENERIC: advance-row ( result-set -- )
-GENERIC: more-rows? ( result-set -- ? )
-
-GENERIC: execute-statement* ( statement type -- )
-
-M: object execute-statement* ( statement type -- )
-    drop query-results dispose ;
-
-: execute-statement ( statement -- )
-    dup sequence? [
-        [ execute-statement ] each
-    ] [
-        dup type>> execute-statement*
-    ] if ;
-
-: bind-statement ( obj statement -- )
-    swap >>bind-params
-    [ bind-statement* ] keep
-    t >>bound? drop ;
-
-: init-result-set ( result-set -- )
-    dup #rows >>max
-    0 >>n drop ;
-
-: construct-result-set ( query handle class -- result-set )
-    new
-        swap >>handle
-        >r [ sql>> ] [ in-params>> ] [ out-params>> ] tri r>
-        swap >>out-params
-        swap >>in-params
-        swap >>sql ;
-
-: sql-row ( result-set -- seq )
-    dup #columns [ row-column ] with map ;
-
-: sql-row-typed ( result-set -- seq )
-    dup #columns [ row-column-typed ] with map ;
-
-: query-each ( statement quot: ( statement -- ) -- )
-    over more-rows? [
-        [ call ] 2keep over advance-row query-each
-    ] [
-        2drop
-    ] if ; inline recursive
-
-: query-map ( statement quot -- seq )
-    accumulator >r query-each r> { } like ; inline
-
-: with-db ( seq class quot -- )
-    >r make-db db-open db r>
-    [ db get swap [ drop ] prepose with-disposal ] curry with-variable ;
-    inline
-
-: default-query ( query -- result-set )
-    query-results [ [ sql-row ] query-map ] with-disposal ;
-
-: do-bound-query ( obj query -- rows )
-    [ bind-statement ] keep default-query ;
-
-: do-bound-command ( obj query -- )
-    [ bind-statement ] keep execute-statement ;
-
-SYMBOL: in-transaction
-HOOK: begin-transaction db ( -- )
-HOOK: commit-transaction db ( -- )
-HOOK: rollback-transaction db ( -- )
-
-: in-transaction? ( -- ? ) in-transaction get ;
-
-: with-transaction ( quot -- )
-    t in-transaction [
-        begin-transaction
-        [ ] [ rollback-transaction ] cleanup commit-transaction
-    ] with-variable ;
-
-: sql-query ( sql -- rows )
-    f f <simple-statement> [ default-query ] with-disposal ;
-
-: sql-command ( sql -- )
-    dup string? [
-        f f <simple-statement> [ execute-statement ] with-disposal
-    ] [
-        ! [
-            [ sql-command ] each
-        ! ] with-transaction
-    ] if ;
diff --git a/extra/db/errors/errors.factor b/extra/db/errors/errors.factor
deleted file mode 100644 (file)
index 1e0d1e7..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-! Copyright (C) 2008 Doug Coleman.
-! See http://factorcode.org/license.txt for BSD license.
-USING: kernel ;
-IN: db.errors
-
-ERROR: db-error ;
-ERROR: sql-error ;
-
-
-ERROR: table-exists ;
-ERROR: bad-schema ;
diff --git a/extra/db/pools/pools-tests.factor b/extra/db/pools/pools-tests.factor
deleted file mode 100644 (file)
index 34e072c..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-IN: db.pools.tests
-USING: db.pools tools.test continuations io.files namespaces
-accessors kernel math destructors ;
-
-\ <db-pool> must-infer
-
-{ 2 0 } [ [ ] with-db-pool ] must-infer-as
-
-{ 1 0 } [ [ ] with-pooled-db ] must-infer-as
-
-! Test behavior after image save/load
-USE: db.sqlite
-
-[ "pool-test.db" temp-file delete-file ] ignore-errors
-
-[ ] [ "pool-test.db" sqlite-db <db-pool> "pool" set ] unit-test
-
-[ ] [ "pool" get expired>> t >>expired drop ] unit-test
-
-[ ] [ 1000 [ "pool" get [ ] with-pooled-db ] times ] unit-test
-
-[ ] [ "pool" get dispose ] unit-test
diff --git a/extra/db/pools/pools.factor b/extra/db/pools/pools.factor
deleted file mode 100644 (file)
index 63153c4..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-! Copyright (C) 2008 Slava Pestov.
-! See http://factorcode.org/license.txt for BSD license.
-USING: accessors kernel arrays namespaces sequences continuations
-io.pools db ;
-IN: db.pools
-
-TUPLE: db-pool < pool db params ;
-
-: <db-pool> ( params db -- pool )
-    db-pool <pool>
-        swap >>db
-        swap >>params ;
-
-: with-db-pool ( db params quot -- )
-    >r <db-pool> r> with-pool ; inline
-
-M: db-pool make-connection ( pool -- )
-    [ params>> ] [ db>> ] bi make-db db-open ;
-
-: with-pooled-db ( pool quot -- )
-    [ db swap with-variable ] curry with-pooled-connection ; inline
diff --git a/extra/db/postgresql/authors.txt b/extra/db/postgresql/authors.txt
deleted file mode 100644 (file)
index 7c1b2f2..0000000
+++ /dev/null
@@ -1 +0,0 @@
-Doug Coleman
diff --git a/extra/db/postgresql/ffi/ffi.factor b/extra/db/postgresql/ffi/ffi.factor
deleted file mode 100755 (executable)
index 4358d7f..0000000
+++ /dev/null
@@ -1,368 +0,0 @@
-! Copyright (C) 2007, 2008 Doug Coleman.
-! See http://factorcode.org/license.txt for BSD license.
-! tested on debian linux with postgresql 8.1
-USING: alien alien.syntax combinators system ;
-IN: db.postgresql.ffi
-
-<< "postgresql" {
-    { [ os winnt? ]  [ "libpq.dll" ] }
-    { [ os macosx? ] [ "libpq.dylib" ] }
-    { [ os unix?  ]  [ "libpq.so" ] }
-} cond "cdecl" add-library >>
-
-! ConnSatusType
-: CONNECTION_OK                     HEX: 0 ; inline
-: CONNECTION_BAD                    HEX: 1 ; inline
-: CONNECTION_STARTED                HEX: 2 ; inline
-: CONNECTION_MADE                   HEX: 3 ; inline
-: CONNECTION_AWAITING_RESPONSE      HEX: 4 ; inline
-: CONNECTION_AUTH_OK                HEX: 5 ; inline
-: CONNECTION_SETENV                 HEX: 6 ; inline
-: CONNECTION_SSL_STARTUP            HEX: 7 ; inline
-: CONNECTION_NEEDED                 HEX: 8 ; inline
-
-! PostgresPollingStatusType
-: PGRES_POLLING_FAILED              HEX: 0 ; inline
-: PGRES_POLLING_READING             HEX: 1 ; inline
-: PGRES_POLLING_WRITING             HEX: 2 ; inline
-: PGRES_POLLING_OK                  HEX: 3 ; inline
-: PGRES_POLLING_ACTIVE              HEX: 4 ; inline
-
-! ExecStatusType;
-: PGRES_EMPTY_QUERY                 HEX: 0 ; inline
-: PGRES_COMMAND_OK                  HEX: 1 ; inline
-: PGRES_TUPLES_OK                   HEX: 2 ; inline
-: PGRES_COPY_OUT                    HEX: 3 ; inline
-: PGRES_COPY_IN                     HEX: 4 ; inline
-: PGRES_BAD_RESPONSE                HEX: 5 ; inline
-: PGRES_NONFATAL_ERROR              HEX: 6 ; inline
-: PGRES_FATAL_ERROR                 HEX: 7 ; inline
-
-! PGTransactionStatusType;
-: PQTRANS_IDLE                      HEX: 0 ; inline
-: PQTRANS_ACTIVE                    HEX: 1 ; inline
-: PQTRANS_INTRANS                   HEX: 2 ; inline
-: PQTRANS_INERROR                   HEX: 3 ; inline
-: PQTRANS_UNKNOWN                   HEX: 4 ; inline
-
-! PGVerbosity;
-: PQERRORS_TERSE                    HEX: 0 ; inline
-: PQERRORS_DEFAULT                  HEX: 1 ; inline
-: PQERRORS_VERBOSE                  HEX: 2 ; inline
-
-: InvalidOid 0 ; inline
-
-TYPEDEF: int ConnStatusType
-TYPEDEF: int ExecStatusType 
-TYPEDEF: int PostgresPollingStatusType
-TYPEDEF: int PGTransactionStatusType 
-TYPEDEF: int PGVerbosity 
-
-TYPEDEF: void* PGconn*
-TYPEDEF: void* PGresult*
-TYPEDEF: void* PGcancel*
-TYPEDEF: uint Oid
-TYPEDEF: uint* Oid*
-TYPEDEF: char pqbool
-TYPEDEF: void* PQconninfoOption*
-TYPEDEF: void* PGnotify*
-TYPEDEF: void* PQArgBlock*
-TYPEDEF: void* PQprintOpt*
-TYPEDEF: void* FILE*
-TYPEDEF: void* SSL*
-
-LIBRARY: postgresql
-
-! Exported functions of libpq
-
-! make a new client connection to the backend
-! Asynchronous (non-blocking)
-FUNCTION: PGconn* PQconnectStart ( char* conninfo ) ;
-FUNCTION: PostgresPollingStatusType PQconnectPoll ( PGconn* conn ) ;
-
-! Synchronous (blocking)
-FUNCTION: PGconn* PQconnectdb ( char* conninfo ) ;
-FUNCTION: PGconn* PQsetdbLogin ( char* pghost, char* pgport,
-             char* pgoptions, char* pgtty,
-             char* dbName,
-             char* login, char* pwd ) ;
-
-: PQsetdb ( M_PGHOST M_PGPORT M_PGOPT M_PGTTY M_DBNAME -- PGconn* )
-    f f PQsetdbLogin ;
-
-! close the current connection and free the PGconn data structure
-FUNCTION: void PQfinish ( PGconn* conn ) ;
-
-! get info about connection options known to PQconnectdb
-FUNCTION: PQconninfoOption* PQconndefaults ( ) ;
-
-! free the data structure returned by PQconndefaults()
-FUNCTION: void PQconninfoFree ( PQconninfoOption* connOptions ) ;
-
-! Asynchronous (non-blocking)
-FUNCTION: int    PQresetStart ( PGconn* conn ) ;
-FUNCTION: PostgresPollingStatusType PQresetPoll ( PGconn* conn ) ;
-
-! Synchronous (blocking)
-FUNCTION: void PQreset ( PGconn* conn ) ;
-
-! request a cancel structure
-FUNCTION: PGcancel* PQgetCancel ( PGconn* conn ) ;
-
-! free a cancel structure
-FUNCTION: void PQfreeCancel ( PGcancel* cancel ) ;
-
-! issue a cancel request
-FUNCTION: int    PQrequestCancel ( PGconn* conn ) ;
-
-! Accessor functions for PGconn objects
-FUNCTION: char* PQdb ( PGconn* conn ) ;
-FUNCTION: char* PQuser ( PGconn* conn ) ;
-FUNCTION: char* PQpass ( PGconn* conn ) ;
-FUNCTION: char* PQhost ( PGconn* conn ) ;
-FUNCTION: char* PQport ( PGconn* conn ) ;
-FUNCTION: char* PQtty ( PGconn* conn ) ;
-FUNCTION: char* PQoptions ( PGconn* conn ) ;
-FUNCTION: ConnStatusType PQstatus ( PGconn* conn ) ;
-FUNCTION: PGTransactionStatusType PQtransactionStatus ( PGconn* conn ) ;
-FUNCTION: char* PQparameterStatus ( PGconn* conn,
-                  char* paramName ) ;
-FUNCTION: int PQprotocolVersion ( PGconn* conn ) ;
-! FUNCTION: int PQServerVersion ( PGconn* conn ) ;
-FUNCTION: char* PQerrorMessage ( PGconn* conn ) ;
-FUNCTION: int PQsocket ( PGconn* conn ) ;
-FUNCTION: int PQbackendPID ( PGconn* conn ) ;
-FUNCTION: int PQclientEncoding ( PGconn* conn ) ;
-FUNCTION: int PQsetClientEncoding ( PGconn* conn, char* encoding ) ;
-
-! May not be compiled into libpq
-! Get the SSL structure associated with a connection
-FUNCTION: SSL* PQgetssl ( PGconn* conn ) ;
-
-! Tell libpq whether it needs to initialize OpenSSL
-FUNCTION: void PQinitSSL ( int do_init ) ;
-
-! Set verbosity for PQerrorMessage and PQresultErrorMessage
-FUNCTION: PGVerbosity PQsetErrorVerbosity ( PGconn* conn,
-    PGVerbosity verbosity ) ;
-
-! Enable/disable tracing
-FUNCTION: void PQtrace ( PGconn* conn, FILE* debug_port ) ;
-FUNCTION: void PQuntrace ( PGconn* conn ) ;
-
-! BROKEN
-! Function types for notice-handling callbacks
-! typedef void (*PQnoticeReceiver) (void *arg, PGresult *res);
-! typedef void (*PQnoticeProcessor) (void *arg, char* message);
-! ALIAS: void* PQnoticeReceiver
-! ALIAS: void* PQnoticeProcessor
-
-! Override default notice handling routines
-! FUNCTION: PQnoticeReceiver PQsetNoticeReceiver ( PGconn* conn,
-                    ! PQnoticeReceiver proc,
-                    ! void* arg ) ;
-! FUNCTION: PQnoticeProcessor PQsetNoticeProcessor ( PGconn* conn,
-                    ! PQnoticeProcessor proc,
-                    ! void* arg ) ;
-! END BROKEN
-
-! === in fe-exec.c ===
-
-! Simple synchronous query
-FUNCTION: PGresult* PQexec ( PGconn* conn, char* query ) ;
-FUNCTION: PGresult* PQexecParams ( PGconn* conn,
-             char* command,
-             int nParams,
-             Oid* paramTypes,
-             char** paramValues,
-             int* paramLengths,
-             int* paramFormats,
-             int resultFormat ) ;
-FUNCTION: PGresult* PQprepare ( PGconn* conn, char* stmtName,
-        char* query, int nParams,
-        Oid* paramTypes ) ;
-FUNCTION: PGresult* PQexecPrepared ( PGconn* conn,
-             char* stmtName,
-             int nParams,
-             char** paramValues,
-             int* paramLengths,
-             int* paramFormats,
-             int resultFormat ) ;
-
-! Interface for multiple-result or asynchronous queries
-FUNCTION: int PQsendQuery ( PGconn* conn, char* query ) ;
-FUNCTION: int PQsendQueryParams ( PGconn* conn,
-                  char* command,
-                  int nParams,
-                  Oid* paramTypes,
-                  char** paramValues,
-                  int* paramLengths,
-                  int* paramFormats,
-                  int resultFormat ) ;
-FUNCTION: PGresult* PQsendPrepare ( PGconn* conn, char* stmtName,
-            char* query, int nParams,
-            Oid* paramTypes ) ;
-FUNCTION: int PQsendQueryPrepared ( PGconn* conn,
-                  char* stmtName,
-                  int nParams,
-                  char** paramValues,
-                  int *paramLengths,
-                  int *paramFormats,
-                  int resultFormat ) ;
-FUNCTION: PGresult* PQgetResult ( PGconn* conn ) ;
-
-! Routines for managing an asynchronous query
-FUNCTION: int    PQisBusy ( PGconn* conn ) ;
-FUNCTION: int    PQconsumeInput ( PGconn* conn ) ;
-
-! LISTEN/NOTIFY support
-FUNCTION: PGnotify* PQnotifies ( PGconn* conn ) ;
-
-! Routines for copy in/out
-FUNCTION: int    PQputCopyData ( PGconn* conn, char* buffer, int nbytes ) ;
-FUNCTION: int    PQputCopyEnd ( PGconn* conn, char* errormsg ) ;
-FUNCTION: int    PQgetCopyData ( PGconn* conn, char** buffer, int async ) ;
-
-! Deprecated routines for copy in/out
-FUNCTION: int    PQgetline ( PGconn* conn, char* string, int length ) ;
-FUNCTION: int    PQputline ( PGconn* conn, char* string ) ;
-FUNCTION: int    PQgetlineAsync ( PGconn* conn, char* buffer, int bufsize ) ;
-FUNCTION: int    PQputnbytes ( PGconn* conn, char* buffer, int nbytes ) ;
-FUNCTION: int    PQendcopy ( PGconn* conn ) ;
-
-! Set blocking/nonblocking connection to the backend
-FUNCTION: int    PQsetnonblocking ( PGconn* conn, int arg ) ;
-FUNCTION: int    PQisnonblocking ( PGconn* conn ) ;
-
-! Force the write buffer to be written (or at least try)
-FUNCTION: int    PQflush ( PGconn* conn ) ;
-
-! 
-! * "Fast path" interface --- not really recommended for application
-! * use
-!
-FUNCTION: PGresult* PQfn ( PGconn* conn,
-     int fnid,
-     int* result_buf,
-     int* result_len,
-     int result_is_int,
-     PQArgBlock* args,
-     int nargs ) ;
-
-! Accessor functions for PGresult objects
-FUNCTION: ExecStatusType PQresultStatus ( PGresult* res ) ;
-FUNCTION: char* PQresStatus ( ExecStatusType status ) ;
-FUNCTION: char* PQresultErrorMessage ( PGresult* res ) ;
-FUNCTION: char* PQresultErrorField ( PGresult* res, int fieldcode ) ;
-FUNCTION: int   PQntuples ( PGresult* res ) ;
-FUNCTION: int   PQnfields ( PGresult* res ) ;
-FUNCTION: int   PQbinaryTuples ( PGresult* res ) ;
-FUNCTION: char* PQfname ( PGresult* res, int field_num ) ;
-FUNCTION: int   PQfnumber ( PGresult* res, char* field_name ) ;
-FUNCTION: Oid   PQftable ( PGresult* res, int field_num ) ;
-FUNCTION: int   PQftablecol ( PGresult* res, int field_num ) ;
-FUNCTION: int   PQfformat ( PGresult* res, int field_num ) ;
-FUNCTION: Oid   PQftype ( PGresult* res, int field_num ) ;
-FUNCTION: int   PQfsize ( PGresult* res, int field_num ) ;
-FUNCTION: int   PQfmod ( PGresult* res, int field_num ) ;
-FUNCTION: char* PQcmdStatus ( PGresult* res ) ;
-FUNCTION: char* PQoidStatus ( PGresult* res ) ;
-FUNCTION: Oid   PQoidValue ( PGresult* res ) ;
-FUNCTION: char* PQcmdTuples ( PGresult* res ) ;
-! FUNCTION: char* PQgetvalue ( PGresult* res, int tup_num, int field_num ) ;
-FUNCTION: void* PQgetvalue ( PGresult* res, int tup_num, int field_num ) ;
-FUNCTION: int   PQgetlength ( PGresult* res, int tup_num, int field_num ) ;
-FUNCTION: int   PQgetisnull ( PGresult* res, int tup_num, int field_num ) ;
-
-! Delete a PGresult
-FUNCTION: void PQclear ( PGresult* res ) ;
-
-! For freeing other alloc'd results, such as PGnotify structs
-FUNCTION: void PQfreemem ( void* ptr ) ;
-
-! Exists for backward compatibility.
-: PQfreeNotify ( ptr -- ) PQfreemem ;
-
-!
-! Make an empty PGresult with given status (some apps find this
-! useful). If conn is not NULL and status indicates an error, the
-! conn's errorMessage is copied.
-!
-FUNCTION: PGresult* PQmakeEmptyPGresult ( PGconn* conn, ExecStatusType status ) ;
-
-! Quoting strings before inclusion in queries.
-FUNCTION: size_t PQescapeStringConn ( PGconn* conn,
-                                    char* to, char* from, size_t length,
-                                    int* error ) ;
-FUNCTION: uchar* PQescapeByteaConn ( PGconn* conn,
-                                    char* from, size_t length,
-                                    size_t* to_length ) ;
-FUNCTION: void* PQunescapeBytea ( uchar* strtext, size_t* retbuflen ) ;
-! FUNCTION: uchar* PQunescapeBytea ( uchar* strtext, size_t* retbuflen ) ;
-! These forms are deprecated!
-FUNCTION: size_t PQescapeString ( void* to, char* from, size_t length ) ;
-FUNCTION: uchar* PQescapeBytea ( uchar* bintext, size_t binlen,
-              size_t* bytealen ) ;
-
-! === in fe-print.c ===
-
-FUNCTION: void PQprint ( FILE* fout, PGresult* res, PQprintOpt* ps ) ;
-
-! really old printing routines
-FUNCTION: void PQdisplayTuples ( PGresult* res,
-                                FILE* fp,               
-                                int fillAlign,
-                                char* fieldSep,
-                                int printHeader,
-                                int quiet ) ;
-
-FUNCTION: void PQprintTuples ( PGresult* res,
-                          FILE* fout,           
-                          int printAttName,
-                          int terseOutput,      
-                          int width ) ; 
-! === in fe-lobj.c ===
-
-! Large-object access routines
-FUNCTION: int    lo_open ( PGconn* conn, Oid lobjId, int mode ) ;
-FUNCTION: int    lo_close ( PGconn* conn, int fd ) ;
-FUNCTION: int    lo_read ( PGconn* conn, int fd, char* buf, size_t len ) ;
-FUNCTION: int    lo_write ( PGconn* conn, int fd, char* buf, size_t len ) ;
-FUNCTION: int    lo_lseek ( PGconn* conn, int fd, int offset, int whence ) ;
-FUNCTION: Oid    lo_creat ( PGconn* conn, int mode ) ;
-! FUNCTION: Oid    lo_creat ( PGconn* conn, Oid lobjId ) ;
-FUNCTION: int    lo_tell ( PGconn* conn, int fd ) ;
-FUNCTION: int    lo_unlink ( PGconn* conn, Oid lobjId ) ;
-FUNCTION: Oid    lo_import ( PGconn* conn, char* filename ) ;
-FUNCTION: int    lo_export ( PGconn* conn, Oid lobjId, char* filename ) ;
-
-! === in fe-misc.c ===
-
-! Determine length of multibyte encoded char at *s
-FUNCTION: int    PQmblen ( uchar* s, int encoding ) ;
-
-! Determine display length of multibyte encoded char at *s
-FUNCTION: int    PQdsplen ( uchar* s, int encoding ) ;
-
-! Get encoding id from environment variable PGCLIENTENCODING
-FUNCTION: int    PQenv2encoding ( ) ;
-
-! From git, include/catalog/pg_type.h
-: BOOL-OID 16 ; inline
-: BYTEA-OID 17 ; inline
-: CHAR-OID 18 ; inline
-: NAME-OID 19 ; inline
-: INT8-OID 20 ; inline
-: INT2-OID 21 ; inline
-: INT4-OID 23 ; inline
-: TEXT-OID 23 ; inline
-: OID-OID 26 ; inline
-: FLOAT4-OID 700 ; inline
-: FLOAT8-OID 701 ; inline
-: VARCHAR-OID 1043 ; inline
-: DATE-OID 1082 ; inline
-: TIME-OID 1083 ; inline
-: TIMESTAMP-OID 1114 ; inline
-: TIMESTAMPTZ-OID 1184 ; inline
-: INTERVAL-OID 1186 ; inline
-: NUMERIC-OID 1700 ; inline
diff --git a/extra/db/postgresql/lib/lib.factor b/extra/db/postgresql/lib/lib.factor
deleted file mode 100755 (executable)
index eba7f69..0000000
+++ /dev/null
@@ -1,173 +0,0 @@
-! Copyright (C) 2008 Doug Coleman.
-! See http://factorcode.org/license.txt for BSD license.
-USING: arrays continuations db io kernel math namespaces
-quotations sequences db.postgresql.ffi alien alien.c-types
-db.types tools.walker ascii splitting math.parser combinators
-libc shuffle calendar.format byte-arrays destructors prettyprint
-accessors strings serialize io.encodings.binary io.encodings.utf8
-alien.strings io.streams.byte-array summary present urls ;
-IN: db.postgresql.lib
-
-: postgresql-result-error-message ( res -- str/f )
-    dup zero? [
-        drop f
-    ] [
-        PQresultErrorMessage [ blank? ] trim
-    ] if ;
-
-: postgres-result-error ( res -- )
-    postgresql-result-error-message [ throw ] when* ;
-
-: (postgresql-error-message) ( handle -- str )
-    PQerrorMessage
-    "\n" split [ [ blank? ] trim ] map "\n" join ;
-
-: postgresql-error-message ( -- str )
-    db get handle>> (postgresql-error-message) ;
-
-: postgresql-error ( res -- res )
-    dup [ postgresql-error-message throw ] unless ;
-
-ERROR: postgresql-result-null ;
-
-M: postgresql-result-null summary ( obj -- str )
-    drop "PQexec returned f." ;
-
-: postgresql-result-ok? ( res -- ? )
-    [ postgresql-result-null ] unless*
-    PQresultStatus
-    PGRES_COMMAND_OK PGRES_TUPLES_OK 2array member? ;
-
-: connect-postgres ( host port pgopts pgtty db user pass -- conn )
-    PQsetdbLogin
-    dup PQstatus zero? [ (postgresql-error-message) throw ] unless ;
-
-: do-postgresql-statement ( statement -- res )
-    db get handle>> swap sql>> PQexec dup postgresql-result-ok? [
-        [ postgresql-result-error-message ] [ PQclear ] bi throw
-    ] unless ;
-
-: type>oid ( symbol -- n )
-    dup array? [ first ] when
-    {
-        { BLOB [ BYTEA-OID ] }
-        { FACTOR-BLOB [ BYTEA-OID ] }
-        [ drop 0 ]
-    } case ;
-
-: type>param-format ( symbol -- n )
-    dup array? [ first ] when
-    {
-        { BLOB [ 1 ] }
-        { FACTOR-BLOB [ 1 ] }
-        [ drop 0 ]
-    } case ;
-
-: param-types ( statement -- seq )
-    in-params>> [ type>> type>oid ] map >c-uint-array ;
-
-: malloc-byte-array/length ( byte-array -- alien length )
-    [ malloc-byte-array &free ] [ length ] bi ;
-
-: default-param-value ( obj -- alien n )
-    number>string* dup [ utf8 malloc-string &free ] when 0 ;
-
-: param-values ( statement -- seq seq2 )
-    [ bind-params>> ] [ in-params>> ] bi
-    [
-        >r value>> r> type>> {
-            { FACTOR-BLOB [
-                dup [ object>bytes malloc-byte-array/length ] [ 0 ] if
-            ] }
-            { BLOB [ dup [ malloc-byte-array/length ] [ 0 ] if ] }
-            { DATE [ dup [ timestamp>ymd ] when default-param-value ] }
-            { TIME [ dup [ timestamp>hms ] when default-param-value ] }
-            { DATETIME [ dup [ timestamp>ymdhms ] when default-param-value ] }
-            { TIMESTAMP [ dup [ timestamp>ymdhms ] when default-param-value ] }
-            { URL [ dup [ present ] when default-param-value ] }
-            [ drop default-param-value ]
-        } case 2array
-    ] 2map flip dup empty? [
-        drop f f
-    ] [
-        first2 [ >c-void*-array ] [ >c-uint-array ] bi*
-    ] if ;
-
-: param-formats ( statement -- seq )
-    in-params>> [ type>> type>param-format ] map >c-uint-array ;
-
-: do-postgresql-bound-statement ( statement -- res )
-    [
-        >r db get handle>> r>
-        {
-            [ sql>> ]
-            [ bind-params>> length ]
-            [ param-types ]
-            [ param-values ]
-            [ param-formats ]
-        } cleave
-        0 PQexecParams dup postgresql-result-ok? [
-            [ postgresql-result-error-message ] [ PQclear ] bi throw
-        ] unless
-    ] with-destructors ;
-
-: pq-get-is-null ( handle row column -- ? )
-    PQgetisnull 1 = ;
-
-: pq-get-string ( handle row column -- obj )
-    3dup PQgetvalue utf8 alien>string
-    dup empty? [ >r pq-get-is-null f r> ? ] [ 3nip ] if ;
-
-: pq-get-number ( handle row column -- obj )
-    pq-get-string dup [ string>number ] when ;
-
-TUPLE: postgresql-malloc-destructor alien ;
-C: <postgresql-malloc-destructor> postgresql-malloc-destructor
-
-M: postgresql-malloc-destructor dispose ( obj -- )
-    alien>> PQfreemem ;
-
-: &postgresql-free ( alien -- alien )
-    dup <postgresql-malloc-destructor> &dispose drop ; inline
-
-: pq-get-blob ( handle row column -- obj/f )
-    [ PQgetvalue ] 3keep 3dup PQgetlength
-    dup 0 > [
-        3nip
-        [
-            memory>byte-array >string
-            0 <uint>
-            [
-                PQunescapeBytea dup zero? [
-                    postgresql-result-error-message throw
-                ] [
-                    &postgresql-free
-                ] if
-            ] keep
-            *uint memory>byte-array
-        ] with-destructors 
-    ] [
-        drop pq-get-is-null nip [ f ] [ B{ } clone ] if
-    ] if ;
-
-: postgresql-column-typed ( handle row column type -- obj )
-    dup array? [ first ] when
-    {
-        { +db-assigned-id+ [ pq-get-number ] }
-        { +random-id+ [ pq-get-number ] }
-        { INTEGER [ pq-get-number ] }
-        { BIG-INTEGER [ pq-get-number ] }
-        { DOUBLE [ pq-get-number ] }
-        { TEXT [ pq-get-string ] }
-        { VARCHAR [ pq-get-string ] }
-        { DATE [ pq-get-string dup [ ymd>timestamp ] when ] }
-        { TIME [ pq-get-string dup [ hms>timestamp ] when ] }
-        { TIMESTAMP [ pq-get-string dup [ ymdhms>timestamp ] when ] }
-        { DATETIME [ pq-get-string dup [ ymdhms>timestamp ] when ] }
-        { BLOB [ pq-get-blob ] }
-        { URL [ pq-get-string dup [ >url ] when ] }
-        { FACTOR-BLOB [
-            pq-get-blob
-            dup [ bytes>object ] when ] }
-        [ no-sql-type ]
-    } case ;
diff --git a/extra/db/postgresql/postgresql-tests.factor b/extra/db/postgresql/postgresql-tests.factor
deleted file mode 100755 (executable)
index 65b75a6..0000000
+++ /dev/null
@@ -1,95 +0,0 @@
-! You will need to run  'createdb factor-test' to create the database.
-! Set username and password in  the 'connect' word.
-
-USING: kernel db.postgresql alien continuations io classes
-prettyprint sequences namespaces tools.test db
-db.tuples db.types unicode.case ;
-IN: db.postgresql.tests
-
-: test-db ( -- postgresql-db )
-    { "localhost" "postgres" "foob" "factor-test" } postgresql-db ;
-
-[ ] [ test-db [ ] with-db ] unit-test
-
-[ ] [
-    test-db [
-        [ "drop table person;" sql-command ] ignore-errors
-        "create table person (name varchar(30), country varchar(30));"
-            sql-command
-
-        "insert into person values('John', 'America');" sql-command
-        "insert into person values('Jane', 'New Zealand');" sql-command
-    ] with-db
-] unit-test
-
-[
-    {
-        { "John" "America" }
-        { "Jane" "New Zealand" }
-    }
-] [
-    test-db [
-        "select * from person" sql-query
-    ] with-db
-] unit-test
-
-[
-    {
-        { "John" "America" }
-        { "Jane" "New Zealand" }
-    }
-] [ test-db [ "select * from person" sql-query ] with-db ] unit-test
-
-[
-] [
-    test-db [
-        "insert into person(name, country) values('Jimmy', 'Canada')"
-        sql-command
-    ] with-db
-] unit-test
-
-[
-    {
-        { "John" "America" }
-        { "Jane" "New Zealand" }
-        { "Jimmy" "Canada" }
-    }
-] [ test-db [ "select * from person" sql-query ] with-db ] unit-test
-
-[
-    test-db [
-        [
-            "insert into person(name, country) values('Jose', 'Mexico')" sql-command
-            "insert into person(name, country) values('Jose', 'Mexico')" sql-command
-            "oops" throw
-        ] with-transaction
-    ] with-db
-] must-fail
-
-[ 3 ] [
-    test-db [
-        "select * from person" sql-query length
-    ] with-db
-] unit-test
-
-[
-] [
-    test-db [
-        [
-            "insert into person(name, country) values('Jose', 'Mexico')"
-            sql-command
-            "insert into person(name, country) values('Jose', 'Mexico')"
-            sql-command
-        ] with-transaction
-    ] with-db
-] unit-test
-
-[ 5 ] [
-    test-db [
-        "select * from person" sql-query length
-    ] with-db
-] unit-test
-
-
-: with-dummy-db ( quot -- )
-    >r T{ postgresql-db } db r> with-variable ;
diff --git a/extra/db/postgresql/postgresql.factor b/extra/db/postgresql/postgresql.factor
deleted file mode 100755 (executable)
index e57efbc..0000000
+++ /dev/null
@@ -1,264 +0,0 @@
-! Copyright (C) 2007, 2008 Doug Coleman.
-! See http://factorcode.org/license.txt for BSD license.
-USING: arrays assocs alien alien.syntax continuations io
-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 db.queries destructors ;
-USE: tools.walker
-IN: db.postgresql
-
-TUPLE: postgresql-db < db
-    host port pgopts pgtty db user pass ;
-
-TUPLE: postgresql-statement < statement ;
-
-TUPLE: postgresql-result-set < result-set ;
-
-M: postgresql-db make-db* ( seq tuple -- db )
-    >r first4 r>
-        swap >>db
-        swap >>pass
-        swap >>user
-        swap >>host ;
-
-M: postgresql-db db-open ( db -- db )
-    dup {
-        [ host>> ]
-        [ port>> ]
-        [ pgopts>> ]
-        [ pgtty>> ]
-        [ db>> ]
-        [ user>> ]
-        [ pass>> ]
-    } cleave connect-postgres >>handle ;
-
-M: postgresql-db dispose ( db -- )
-    handle>> PQfinish ;
-
-M: postgresql-statement bind-statement* ( statement -- )
-    drop ;
-
-GENERIC: postgresql-bind-conversion ( tuple obj -- low-level-binding )
-
-M: sql-spec postgresql-bind-conversion ( tuple spec -- obj )
-    slot-name>> swap get-slot-named <low-level-binding> ;
-
-M: literal-bind postgresql-bind-conversion ( tuple literal-bind -- obj )
-    nip value>> <low-level-binding> ;
-
-M: generator-bind postgresql-bind-conversion ( tuple generate-bind -- obj )
-    dup generator-singleton>> eval-generator
-    [ swap slot-name>> rot set-slot-named ] [ <low-level-binding> ] bi ;
-
-M: postgresql-statement bind-tuple ( tuple statement -- )
-    tuck in-params>>
-    [ postgresql-bind-conversion ] with map
-    >>bind-params drop ;
-
-M: postgresql-result-set #rows ( result-set -- n )
-    handle>> PQntuples ;
-
-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 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 result-handle-n r> r> postgresql-column-typed ;
-
-M: postgresql-statement query-results ( query -- result-set )
-    dup bind-params>> [
-        over [ bind-statement ] keep
-        do-postgresql-bound-statement
-    ] [
-        dup do-postgresql-statement
-    ] if*
-    postgresql-result-set construct-result-set
-    dup init-result-set ;
-
-M: postgresql-result-set advance-row ( result-set -- )
-    [ 1+ ] change-n drop ;
-
-M: postgresql-result-set more-rows? ( result-set -- ? )
-    [ n>> ] [ max>> ] bi < ;
-
-M: postgresql-statement dispose ( query -- )
-    dup handle>> PQclear
-    f >>handle drop ;
-
-M: postgresql-result-set dispose ( result-set -- )
-    [ handle>> PQclear ]
-    [
-        0 >>n
-        0 >>max
-        f >>handle drop
-    ] bi ;
-
-M: postgresql-statement prepare-statement ( statement -- )
-    dup
-    >r db get handle>> f r>
-    [ sql>> ] [ in-params>> ] bi
-    length f PQprepare postgresql-error
-    >>handle drop ;
-
-M: postgresql-db <simple-statement> ( sql in out -- statement )
-    postgresql-statement construct-statement ;
-
-M: postgresql-db <prepared-statement> ( sql in out -- statement )
-    <simple-statement> dup prepare-statement ;
-
-: bind-name% ( -- )
-    CHAR: $ 0,
-    sql-counter [ inc ] [ get 0# ] bi ;
-
-M: postgresql-db bind% ( spec -- )
-    bind-name% 1, ;
-
-M: postgresql-db bind# ( spec obj -- )
-    >r bind-name% f swap type>> r> <literal-bind> 1, ;
-
-: create-table-sql ( class -- statement )
-    [
-        "create table " 0% 0%
-        "(" 0% [ ", " 0% ] [
-            dup column-name>> 0%
-            " " 0%
-            dup type>> lookup-create-type 0%
-            modifiers 0%
-        ] interleave ");" 0%
-    ] query-make ;
-
-: create-function-sql ( class -- statement )
-    [
-        >r remove-id r>
-        "create function add_" 0% dup 0%
-        "(" 0%
-        over [ "," 0% ]
-        [
-            type>> lookup-type 0%
-        ] interleave
-        ")" 0%
-        " returns bigint as '" 0%
-
-        "insert into " 0%
-        dup 0%
-        "(" 0%
-        over [ ", " 0% ] [ column-name>> 0% ] interleave
-        ") values(" 0%
-        swap [ ", " 0% ] [ drop bind-name% ] interleave
-        "); " 0%
-        "select currval(''" 0% 0% "_id_seq'');' language sql;" 0%
-    ] query-make ;
-
-M: postgresql-db create-sql-statement ( class -- seq )
-    [
-        [ create-table-sql , ] keep
-        dup db-columns find-primary-key db-assigned-id-spec?
-        [ create-function-sql , ] [ drop ] if
-    ] { } make ;
-
-: drop-function-sql ( class -- statement )
-    [
-        "drop function add_" 0% 0%
-        "(" 0%
-        remove-id
-        [ ", " 0% ] [ type>> lookup-type 0% ] interleave
-        ");" 0%
-    ] query-make ;
-
-: drop-table-sql ( table -- statement )
-    [
-        "drop table " 0% 0% drop
-    ] query-make ;
-
-M: postgresql-db drop-sql-statement ( class -- seq )
-    [
-        [ drop-table-sql , ] keep
-        dup db-columns find-primary-key db-assigned-id-spec?
-        [ drop-function-sql , ] [ drop ] if
-    ] { } make ;
-
-M: postgresql-db <insert-db-assigned-statement> ( class -- statement )
-    [
-        "select add_" 0% 0%
-        "(" 0%
-        dup find-primary-key 2,
-        remove-id
-        [ ", " 0% ] [ bind% ] interleave
-        ");" 0%
-    ] query-make ;
-
-M: postgresql-db <insert-user-assigned-statement> ( class -- statement )
-    [
-        "insert into " 0% 0%
-        "(" 0%
-        dup [ ", " 0% ] [ column-name>> 0% ] interleave
-        ")" 0%
-
-        " values(" 0%
-        [ ", " 0% ] [
-            dup type>> +random-id+ = [
-                [
-                    bind-name%
-                    slot-name>>
-                    f
-                    random-id-generator
-                ] [ type>> ] bi <generator-bind> 1,
-            ] [
-                bind%
-            ] if
-        ] interleave
-        ");" 0%
-    ] query-make ;
-
-M: postgresql-db insert-tuple* ( tuple statement -- )
-    query-modify-tuple ;
-
-M: postgresql-db persistent-table ( -- hashtable )
-    H{
-        { +db-assigned-id+ { "integer" "serial primary key" f } }
-        { +user-assigned-id+ { f f "primary key" } }
-        { +random-id+ { "bigint" "bigint primary key" f } }
-        { TEXT { "text" "text" 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 } }
-        { URL { "varchar" "varchar" 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' )
-    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/queries/queries.factor b/extra/db/queries/queries.factor
deleted file mode 100644 (file)
index 3a751a9..0000000
+++ /dev/null
@@ -1,188 +0,0 @@
-! Copyright (C) 2008 Doug Coleman.
-! See http://factorcode.org/license.txt for BSD license.
-USING: accessors kernel math namespaces sequences random
-strings math.parser math.intervals combinators
-math.bitfields.lib namespaces.lib db db.tuples db.types
-sequences.lib db.sql classes words shuffle arrays ;
-IN: db.queries
-
-GENERIC: where ( specs obj -- )
-
-: 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 ] curry { "" { } { } } nmake
-    <simple-statement> maybe-make-retryable ; inline
-
-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: random-id-generator eval-generator ( singleton -- obj )
-    drop
-    system-random-generator get [
-        63 [ 2^ random ] keep 1 - set-bit
-    ] with-random ;
-
-: interval-comparison ( ? str -- str )
-    "from" = " >" " <" ? swap [ "= " append ] when ;
-
-: fp-infinity? ( float -- ? )
-    dup float? [
-        double>bits -52 shift 11 2^ 1- [ bitand ] keep =
-    ] [
-        drop f
-    ] if ;
-
-: (infinite-interval?) ( interval -- ?1 ?2 )
-    [ from>> ] [ to>> ] bi
-    [ first fp-infinity? ] bi@ ;
-
-: double-infinite-interval? ( obj -- ? )
-    dup interval? [ (infinite-interval?) and ] [ drop f ] if ;
-
-: infinite-interval? ( obj -- ? )
-    dup interval? [ (infinite-interval?) or ] [ drop f ] if ;
-
-: where-interval ( spec obj from/to -- )
-    over first fp-infinity? [
-        3drop
-    ] [
-        pick column-name>> 0%
-        >r first2 r> interval-comparison 0%
-        bind#
-    ] if ;
-
-: in-parens ( quot -- )
-    "(" 0% call ")" 0% ; inline
-
-M: interval where ( spec obj -- )
-    [
-        [ from>> "from" where-interval ] [
-            nip infinite-interval? [ " and " 0% ] unless
-        ] [ to>> "to" where-interval ] 2tri
-    ] 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 ;
-
-: filter-slots ( tuple specs -- specs' )
-    [
-        slot-name>> swap get-slot-named
-        dup double-infinite-interval? [ drop f ] when
-    ] with filter ;
-
-: where-clause ( tuple specs -- )
-    dupd filter-slots [
-        drop
-    ] [
-        " where " 0% [
-            " and " 0%
-        ] [
-            2dup slot-name>> swap get-slot-named where
-        ] interleave drop
-    ] if-empty ;
-
-M: db <delete-tuples-statement> ( tuple table -- sql )
-    [
-        "delete from " 0% 0%
-        where-clause
-    ] query-make ;
-
-M: db <select-by-slots-statement> ( tuple class -- statement )
-    [
-        "select " 0%
-        over [ ", " 0% ]
-        [ dup column-name>> 0% 2, ] interleave
-
-        " from " 0% 0%
-        where-clause
-    ] query-make ;
-
-: do-group ( tuple groups -- )
-    [
-        ", " join " group by " prepend append
-    ] curry change-sql drop ;
-
-: do-order ( tuple order -- )
-    [
-        ", " join " order by " prepend append
-    ] curry change-sql drop ;
-
-: do-offset ( tuple n -- )
-    [
-        number>string " offset " prepend append
-    ] curry change-sql drop ;
-
-: do-limit ( tuple n -- )
-    [
-        number>string " limit " prepend append
-    ] curry change-sql drop ;
-
-: make-query ( tuple query -- tuple' )
-    dupd
-    {
-        [ group>> [ do-group ] [ drop ] if-seq ]
-        [ order>> [ do-order ] [ drop ] if-seq ]
-        [ limit>> [ do-limit ] [ drop ] if* ]
-        [ offset>> [ do-offset ] [ drop ] if* ]
-    } 2cleave ;
-
-M: db <query> ( tuple class query -- tuple )
-    [ <select-by-slots-statement> ] dip make-query ;
-
-! select ID, NAME, SCORE from EXAM limit 1 offset 3
-
-: select-tuples* ( tuple -- statement )
-    dup
-    [
-        select 0,
-        dup class db-columns [ ", " 0, ]
-        [ dup column-name>> 0, 2, ] interleave
-        from 0,
-        class name>> 0,
-    ] { { } { } { } } nmake
-    >r >r parse-sql 4drop r> r>
-    <simple-statement> maybe-make-retryable do-select ;
-
-M: db <count-statement> ( tuple class groups -- statement )
-    \ query new
-        swap >>group
-    [ [ "select count(*) from " 0% 0% where-clause ] query-make ]
-    dip make-query ;
-
-: create-index ( index-name table-name columns -- )
-    [
-        >r >r "create index " % % r> " on " % % r> "(" %
-        "," join % ")" %
-    ] "" make sql-command ;
-
-: drop-index ( index-name -- )
-    [ "drop index " % % ] "" make sql-command ;
diff --git a/extra/db/sql/sql-tests.factor b/extra/db/sql/sql-tests.factor
deleted file mode 100644 (file)
index 0b57c2d..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-USING: kernel namespaces db.sql sequences math ;
-IN: db.sql.tests
-
-! TUPLE: person name age ;
-: insert-1
-    { insert
-        {
-            { table "person" }
-            { columns "name" "age" }
-            { values "erg" 26 }
-        }
-    } ;
-
-: update-1
-    { update "person"
-       { set { "name" "erg" }
-             { "age" 6 } }
-       { where { "age" 6 } }
-    } ;
-
-: select-1
-    { select
-        { columns
-                "branchno"
-                { count "staffno" as "mycount" }
-                { sum "salary" as "mysum" } }
-        { from "staff" "lol" }
-        { where
-                { "salary" > all
-                    { select
-                        { columns "salary" }
-                        { from "staff" }
-                        { where { "branchno" = "b003" } }
-                    }
-                }
-                { "branchno" > 3 } }
-        { group-by "branchno" "lol2" }
-        { having { count "staffno" > 1 } }
-        { order-by "branchno" }
-        { offset 40 }
-        { limit 20 }
-    } ;
diff --git a/extra/db/sql/sql.factor b/extra/db/sql/sql.factor
deleted file mode 100755 (executable)
index 7dd4abf..0000000
+++ /dev/null
@@ -1,77 +0,0 @@
-USING: kernel parser quotations classes.tuple words math.order
-namespaces.lib namespaces sequences arrays combinators
-prettyprint strings math.parser sequences.lib math symbols ;
-IN: db.sql
-
-SYMBOLS: insert update delete select distinct columns from as
-where group-by having order-by limit offset is-null desc all
-any count avg table values ;
-
-: input-spec, ( obj -- ) 1, ;
-: output-spec, ( obj -- ) 2, ;
-: input, ( obj -- ) 3, ;
-: output, ( obj -- ) 4, ;
-
-DEFER: sql%
-
-: (sql-interleave) ( seq sep -- )
-    [ sql% ] curry [ sql% ] interleave ;
-
-: sql-interleave ( seq str sep -- )
-    swap sql% (sql-interleave) ;
-
-: sql-function, ( seq function -- )
-    sql% "(" sql% unclip sql% ")" sql% [ sql% ] each ;
-
-: sql-where ( seq -- )
-B
-    [
-        [ second 0, ]
-        [ first 0, ]
-        [ third 1, \ ? 0, ] tri
-    ] each ;
-
-: sql-array% ( array -- )
-B
-    unclip
-    {
-        { \ create [ "create table" sql% ] }
-        { \ drop [ "drop table" sql% ] }
-        { \ insert [ "insert into" sql% ] }
-        { \ update [ "update" sql% ] }
-        { \ delete [ "delete" sql% ] }
-        { \ select [ B "select" sql% "," (sql-interleave) ] }
-        { \ columns [ "," (sql-interleave) ] }
-        { \ from [ "from" "," sql-interleave ] }
-        { \ where [ B "where" 0, sql-where ] }
-        { \ 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, ] }
-        [ sql% [ sql% ] each ]
-    } case ;
-
-ERROR: no-sql-match ;
-: sql% ( obj -- )
-    {
-        { [ dup string? ] [ 0, ] }
-        { [ dup array? ] [ sql-array% ] }
-        { [ dup number? ] [ number>string sql% ] }
-        { [ dup symbol? ] [ unparse sql% ] }
-        { [ dup word? ] [ unparse sql% ] }
-        { [ dup quotation? ] [ call ] }
-        [ no-sql-match ]
-    } cond ;
-
-: parse-sql ( obj -- sql in-spec out-spec in out )
-    [ [ sql% ] each ] { { } { } { } } nmake ;
diff --git a/extra/db/sqlite/authors.txt b/extra/db/sqlite/authors.txt
deleted file mode 100644 (file)
index 26093b4..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-Chris Double
-Doug Coleman
diff --git a/extra/db/sqlite/ffi/ffi.factor b/extra/db/sqlite/ffi/ffi.factor
deleted file mode 100755 (executable)
index b443f53..0000000
+++ /dev/null
@@ -1,140 +0,0 @@
-! Copyright (C) 2005 Chris Double, Doug Coleman.
-! See http://factorcode.org/license.txt for BSD license.
-! 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 alien.c-types ;
-IN: db.sqlite.ffi
-
-<< "sqlite" {
-        { [ os winnt? ]  [ "sqlite3.dll" ] }
-        { [ os macosx? ] [ "/usr/lib/libsqlite3.dylib" ] }
-        { [ os unix? ]  [ "libsqlite3.so" ] }
-    } cond "cdecl" add-library >>
-
-! Return values from sqlite functions
-: SQLITE_OK           0   ; inline ! Successful result
-: SQLITE_ERROR        1   ; inline ! SQL error or missing database
-: SQLITE_INTERNAL     2   ; inline ! An internal logic error in SQLite 
-: SQLITE_PERM         3   ; inline ! Access permission denied 
-: SQLITE_ABORT        4   ; inline ! Callback routine requested an abort 
-: SQLITE_BUSY         5   ; inline ! The database file is locked 
-: SQLITE_LOCKED       6   ; inline ! A table in the database is locked 
-: SQLITE_NOMEM        7   ; inline ! A malloc() failed 
-: SQLITE_READONLY     8   ; inline ! Attempt to write a readonly database 
-: SQLITE_INTERRUPT    9   ; inline ! Operation terminated by sqlite_interrupt() 
-: SQLITE_IOERR       10   ; inline ! Some kind of disk I/O error occurred 
-: SQLITE_CORRUPT     11   ; inline ! The database disk image is malformed 
-: SQLITE_NOTFOUND    12   ; inline ! (Internal Only) Table or record not found 
-: SQLITE_FULL        13   ; inline ! Insertion failed because database is full 
-: SQLITE_CANTOPEN    14   ; inline ! Unable to open the database file 
-: SQLITE_PROTOCOL    15   ; inline ! Database lock protocol error 
-: SQLITE_EMPTY       16   ; inline ! (Internal Only) Database table is empty 
-: SQLITE_SCHEMA      17   ; inline ! The database schema changed 
-: SQLITE_TOOBIG      18   ; inline ! Too much data for one row of a table 
-: SQLITE_CONSTRAINT  19   ; inline ! Abort due to contraint violation 
-: SQLITE_MISMATCH    20   ; inline ! Data type mismatch 
-: SQLITE_MISUSE      21   ; inline ! Library used incorrectly 
-: SQLITE_NOLFS       22   ; inline ! Uses OS features not supported on host 
-: SQLITE_AUTH        23   ; inline ! Authorization denied 
-: SQLITE_FORMAT      24   ; inline ! Auxiliary database format error
-: SQLITE_RANGE       25   ; inline ! 2nd parameter to sqlite3_bind out of range
-: SQLITE_NOTADB      26   ; inline ! File opened that is not a database file
-
-: sqlite-error-messages ( -- seq ) {
-    "Successful result"
-    "SQL error or missing database"
-    "An internal logic error in SQLite"
-    "Access permission denied"
-    "Callback routine requested an abort"
-    "The database file is locked"
-    "A table in the database is locked"
-    "A malloc() failed"
-    "Attempt to write a readonly database"
-    "Operation terminated by sqlite_interrupt()"
-    "Some kind of disk I/O error occurred"
-    "The database disk image is malformed"
-    "(Internal Only) Table or record not found"
-    "Insertion failed because database is full"
-    "Unable to open the database file"
-    "Database lock protocol error"
-    "(Internal Only) Database table is empty"
-    "The database schema changed"
-    "Too much data for one row of a table"
-    "Abort due to contraint violation"
-    "Data type mismatch"
-    "Library used incorrectly"
-    "Uses OS features not supported on host"
-    "Authorization denied"
-    "Auxiliary database format error"
-    "2nd parameter to sqlite3_bind out of range"
-    "File opened that is not a database file"
-} ;
-
-! Return values from sqlite3_step
-: SQLITE_ROW         100  ; inline
-: SQLITE_DONE        101  ; inline
-
-! Return values from the sqlite3_column_type function
-: SQLITE_INTEGER     1 ; inline
-: SQLITE_FLOAT       2 ; inline
-: SQLITE_TEXT        3 ; inline
-: SQLITE_BLOB        4 ; inline
-: SQLITE_NULL        5 ; inline
-
-! Values for the 'destructor' parameter of the 'bind' routines. 
-: SQLITE_STATIC      0  ; inline
-: SQLITE_TRANSIENT   -1 ; inline
-
-: SQLITE_OPEN_READONLY         HEX: 00000001 ; inline
-: SQLITE_OPEN_READWRITE        HEX: 00000002 ; inline
-: SQLITE_OPEN_CREATE           HEX: 00000004 ; inline
-: SQLITE_OPEN_DELETEONCLOSE    HEX: 00000008 ; inline
-: SQLITE_OPEN_EXCLUSIVE        HEX: 00000010 ; inline
-: SQLITE_OPEN_MAIN_DB          HEX: 00000100 ; inline
-: SQLITE_OPEN_TEMP_DB          HEX: 00000200 ; inline
-: SQLITE_OPEN_TRANSIENT_DB     HEX: 00000400 ; inline
-: SQLITE_OPEN_MAIN_JOURNAL     HEX: 00000800 ; inline
-: SQLITE_OPEN_TEMP_JOURNAL     HEX: 00001000 ; inline
-: SQLITE_OPEN_SUBJOURNAL       HEX: 00002000 ; inline
-: SQLITE_OPEN_MASTER_JOURNAL   HEX: 00004000 ; inline
-
-TYPEDEF: void sqlite3
-TYPEDEF: void sqlite3_stmt
-TYPEDEF: longlong sqlite3_int64
-TYPEDEF: ulonglong sqlite3_uint64
-
-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 ) ;
-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 ) ;
-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 ) ;
-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 ) ;
-FUNCTION: int sqlite3_column_type ( sqlite3_stmt* pStmt, int col ) ;
diff --git a/extra/db/sqlite/lib/lib.factor b/extra/db/sqlite/lib/lib.factor
deleted file mode 100755 (executable)
index 03f424e..0000000
+++ /dev/null
@@ -1,172 +0,0 @@
-! Copyright (C) 2008 Chris Double, Doug Coleman.
-! See http://factorcode.org/license.txt for BSD license.
-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
-io.backend db.errors present urls io.encodings.utf8
-io.encodings.string accessors ;
-IN: db.sqlite.lib
-
-ERROR: sqlite-error < db-error n string ;
-ERROR: sqlite-sql-error < sql-error n string ;
-
-: throw-sqlite-error ( n -- * )
-    dup sqlite-error-messages nth sqlite-error ;
-
-: sqlite-statement-error ( -- * )
-    SQLITE_ERROR
-    db get handle>> sqlite3_errmsg sqlite-sql-error ;
-
-: sqlite-check-result ( n -- )
-    {
-        { SQLITE_OK [ ] }
-        { SQLITE_ERROR [ sqlite-statement-error ] }
-        [ throw-sqlite-error ]
-    } case ;
-
-: sqlite-open ( path -- db )
-    normalize-path
-    "void*" <c-object>
-    [ sqlite3_open sqlite-check-result ] keep *void* ;
-
-: sqlite-close ( db -- )
-    sqlite3_close sqlite-check-result ;
-
-: sqlite-prepare ( db sql -- handle )
-    utf8 encode dup length "void*" <c-object> "void*" <c-object>
-    [ sqlite3_prepare_v2 sqlite-check-result ] 2keep
-    drop *void* ;
-
-: sqlite-bind-parameter-index ( handle name -- index )
-    sqlite3_bind_parameter_index ;
-
-: parameter-index ( handle name text -- handle name text )
-    >r dupd sqlite-bind-parameter-index r> ;
-
-: sqlite-bind-text ( handle index text -- )
-    utf8 encode dup length SQLITE_TRANSIENT
-    sqlite3_bind_text sqlite-check-result ;
-
-: sqlite-bind-int ( handle i n -- )
-    sqlite3_bind_int sqlite-check-result ;
-
-: 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 ;
-
-: sqlite-bind-null ( handle i -- )
-    sqlite3_bind_null sqlite-check-result ;
-
-: sqlite-bind-blob ( handle i byte-array -- )
-    dup length SQLITE_TRANSIENT
-    sqlite3_bind_blob sqlite-check-result ;
-
-: sqlite-bind-text-by-name ( handle name text -- )
-    parameter-index sqlite-bind-text ;
-
-: sqlite-bind-int-by-name ( handle name int -- )
-    parameter-index sqlite-bind-int ;
-
-: sqlite-bind-int64-by-name ( handle name int64 -- )
-    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 ;
-
-: sqlite-bind-blob-by-name ( handle name blob -- )
-    parameter-index sqlite-bind-blob ;
-
-: sqlite-bind-null-by-name ( handle name obj -- )
-    parameter-index drop sqlite-bind-null ;
-
-: sqlite-bind-type ( handle key value type -- )
-    over [ drop NULL ] unless
-    dup array? [ first ] when
-    {
-        { 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 ] }
-        { DATE [ timestamp>ymd sqlite-bind-text-by-name ] }
-        { TIME [ timestamp>hms sqlite-bind-text-by-name ] }
-        { DATETIME [ timestamp>ymdhms sqlite-bind-text-by-name ] }
-        { TIMESTAMP [ timestamp>ymdhms sqlite-bind-text-by-name ] }
-        { BLOB [ sqlite-bind-blob-by-name ] }
-        { FACTOR-BLOB [
-            object>bytes
-            sqlite-bind-blob-by-name
-        ] }
-        { URL [ present sqlite-bind-text-by-name ] }
-        { +db-assigned-id+ [ sqlite-bind-int-by-name ] }
-        { +random-id+ [ sqlite-bind-int64-by-name ] }
-        { NULL [ sqlite-bind-null-by-name ] }
-        [ no-sql-type ]
-    } case ;
-
-: 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 ;
-: sqlite-column-type ( handle index -- string ) sqlite3_column_type ;
-
-: sqlite-column-blob ( handle index -- byte-array/f )
-    [ sqlite3_column_bytes ] 2keep
-    pick zero? [
-        3drop f
-    ] [
-        sqlite3_column_blob swap memory>byte-array
-    ] if ;
-
-: sqlite-column-typed ( handle index type -- obj )
-    dup array? [ first ] when
-    {
-        { +db-assigned-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 ] }
-        { DATE [ sqlite3_column_text dup [ ymd>timestamp ] when ] }
-        { TIME [ sqlite3_column_text dup [ hms>timestamp ] when ] }
-        { TIMESTAMP [ sqlite3_column_text dup [ ymdhms>timestamp ] when ] }
-        { DATETIME [ sqlite3_column_text dup [ ymdhms>timestamp ] when ] }
-        { BLOB [ sqlite-column-blob ] }
-        { URL [ sqlite3_column_text dup [ >url ] when ] }
-        { FACTOR-BLOB [
-            sqlite-column-blob
-            dup [ bytes>object ] when
-        ] }
-        ! { NULL [ 2drop f ] }
-        [ no-sql-type ]
-    } case ;
-
-: sqlite-row ( handle -- seq )
-    dup sqlite-#columns [ sqlite-column ] with map ;
-
-: sqlite-step-has-more-rows? ( prepared -- bool )
-    {
-        { SQLITE_ROW [ t ] }
-        { SQLITE_DONE [ f ] }
-        [ sqlite-check-result f ]
-    } case ;
-
-: sqlite-next ( prepared -- ? )
-    sqlite3_step sqlite-step-has-more-rows? ;
diff --git a/extra/db/sqlite/sqlite-tests.factor b/extra/db/sqlite/sqlite-tests.factor
deleted file mode 100755 (executable)
index b30cb4b..0000000
+++ /dev/null
@@ -1,76 +0,0 @@
-USING: io io.files io.launcher kernel namespaces
-prettyprint tools.test db.sqlite db sequences
-continuations db.types db.tuples unicode.case ;
-IN: db.sqlite.tests
-
-: db-path "test.db" temp-file ;
-: test.db db-path sqlite-db ;
-
-[ ] [ [ db-path delete-file ] ignore-errors ] unit-test
-
-[ ] [
-    test.db [
-        "create table person (name varchar(30), country varchar(30))" sql-command
-        "insert into person values('John', 'America')" sql-command
-        "insert into person values('Jane', 'New Zealand')" sql-command
-    ] with-db
-] unit-test
-
-
-[ { { "John" "America" } { "Jane" "New Zealand" } } ] [
-    test.db [
-        "select * from person" sql-query
-    ] with-db
-] unit-test
-
-[ { { "1" "John" "America" } { "2" "Jane" "New Zealand" } } ]
-[ test.db [ "select rowid, * from person" sql-query ] with-db ] unit-test
-
-[ ] [
-    test.db [
-        "insert into person(name, country) values('Jimmy', 'Canada')"
-        sql-command
-    ] with-db
-] unit-test
-
-[
-    {
-        { "1" "John" "America" }
-        { "2" "Jane" "New Zealand" }
-        { "3" "Jimmy" "Canada" }
-    }
-] [ test.db [ "select rowid, * from person" sql-query ] with-db ] unit-test
-
-[
-    test.db [
-        [
-            "insert into person(name, country) values('Jose', 'Mexico')" sql-command
-            "insert into person(name, country) values('Jose', 'Mexico')" sql-command
-            "oops" throw
-        ] with-transaction
-    ] with-db
-] must-fail
-
-[ 3 ] [
-    test.db [
-        "select * from person" sql-query length
-    ] with-db
-] unit-test
-
-[
-] [
-    test.db [
-        [
-            "insert into person(name, country) values('Jose', 'Mexico')"
-            sql-command
-            "insert into person(name, country) values('Jose', 'Mexico')"
-            sql-command
-        ] with-transaction
-    ] with-db
-] unit-test
-
-[ 5 ] [
-    test.db [
-        "select * from person" sql-query length
-    ] with-db
-] unit-test
diff --git a/extra/db/sqlite/sqlite.factor b/extra/db/sqlite/sqlite.factor
deleted file mode 100755 (executable)
index 231b60e..0000000
+++ /dev/null
@@ -1,200 +0,0 @@
-! Copyright (C) 2005, 2008 Chris Double, Doug Coleman.
-! See http://factorcode.org/license.txt for BSD license.
-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 math.intervals
-io namespaces.lib accessors vectors math.ranges random
-math.bitfields.lib db.queries destructors ;
-USE: tools.walker
-IN: db.sqlite
-
-TUPLE: sqlite-db < db path ;
-
-M: sqlite-db make-db* ( path db -- db )
-    swap >>path ;
-
-M: sqlite-db db-open ( db -- db )
-    dup path>> sqlite-open >>handle ;
-
-M: sqlite-db db-close ( handle -- ) sqlite-close ;
-M: sqlite-db dispose ( db -- ) dispose-db ;
-
-TUPLE: sqlite-statement < statement ;
-
-TUPLE: sqlite-result-set < result-set has-more? ;
-
-M: sqlite-db <simple-statement> ( str in out -- obj )
-    <prepared-statement> ;
-
-M: sqlite-db <prepared-statement> ( str in out -- obj )
-    sqlite-statement construct-statement ;
-
-: sqlite-maybe-prepare ( statement -- statement )
-    dup handle>> [
-        db get handle>> over sql>> sqlite-prepare
-        >>handle
-    ] unless ;
-
-M: sqlite-statement dispose ( statement -- )
-    handle>>
-    [ [ sqlite3_reset drop ] keep sqlite-finalize ] when* ;
-
-M: sqlite-result-set dispose ( result-set -- )
-    f >>handle drop ;
-
-: 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 -- )
-    [ bind-params>> ] [ handle>> ] bi
-    [ swap [ key>> ] [ value>> ] [ type>> ] tri sqlite-bind-type ] curry each ;
-
-M: sqlite-statement bind-statement* ( statement -- )
-    sqlite-maybe-prepare
-    dup bound?>> [ dup reset-bindings ] when
-    low-level-bind ;
-
-GENERIC: sqlite-bind-conversion ( tuple obj -- array )
-
-TUPLE: sqlite-low-level-binding < low-level-binding key type ;
-: <sqlite-low-level-binding> ( key value type -- obj )
-    sqlite-low-level-binding new
-        swap >>type
-        swap >>value
-        swap >>key ;
-
-M: sql-spec sqlite-bind-conversion ( tuple spec -- array )
-    [ column-name>> ":" prepend ]
-    [ slot-name>> rot get-slot-named ]
-    [ type>> ] tri <sqlite-low-level-binding> ;
-
-M: literal-bind sqlite-bind-conversion ( tuple literal-bind -- array )
-    nip [ key>> ] [ value>> ] [ type>> ] tri
-    <sqlite-low-level-binding> ;
-
-M: generator-bind sqlite-bind-conversion ( tuple generate-bind -- array )
-    tuck
-    [ generator-singleton>> eval-generator tuck ] [ slot-name>> ] bi
-    rot set-slot-named
-    >r [ key>> ] [ type>> ] bi r> swap <sqlite-low-level-binding> ;
-
-M: sqlite-statement bind-tuple ( tuple statement -- )
-    [
-        in-params>> [ sqlite-bind-conversion ] with map
-    ] keep bind-statement ;
-
-: last-insert-id ( -- id )
-    db get handle>> sqlite3_last_insert_rowid
-    dup zero? [ "last-id failed" throw ] when ;
-
-M: sqlite-db insert-tuple* ( tuple statement -- )
-    execute-statement last-insert-id swap set-primary-key ;
-
-M: sqlite-result-set #columns ( result-set -- n )
-    handle>> sqlite-#columns ;
-
-M: sqlite-result-set row-column ( result-set n -- obj )
-    [ handle>> ] [ sqlite-column ] bi* ;
-
-M: sqlite-result-set row-column-typed ( result-set n -- obj )
-    dup pick out-params>> nth type>>
-    >r >r handle>> r> r> sqlite-column-typed ;
-
-M: sqlite-result-set advance-row ( result-set -- )
-    dup handle>> sqlite-next >>has-more? drop ;
-
-M: sqlite-result-set more-rows? ( result-set -- ? )
-    has-more?>> ;
-
-M: sqlite-statement query-results ( query -- result-set )
-    sqlite-maybe-prepare
-    dup handle>> sqlite-result-set construct-result-set
-    dup advance-row ;
-
-M: sqlite-db create-sql-statement ( class -- statement )
-    [
-        "create table " 0% 0%
-        "(" 0% [ ", " 0% ] [
-            dup column-name>> 0%
-            " " 0%
-            dup type>> lookup-create-type 0%
-            modifiers 0%
-        ] interleave ");" 0%
-    ] query-make ;
-
-M: sqlite-db drop-sql-statement ( class -- statement )
-    [ "drop table " 0% 0% ";" 0% drop ] query-make ;
-
-M: sqlite-db <insert-db-assigned-statement> ( tuple -- statement )
-    [
-        "insert into " 0% 0%
-        "(" 0%
-        remove-db-assigned-id
-        dup [ ", " 0% ] [ column-name>> 0% ] interleave
-        ") values(" 0%
-        [ ", " 0% ] [
-            dup type>> +random-id+ = [
-                [ slot-name>> ]
-                [
-                    column-name>> ":" prepend dup 0%
-                    random-id-generator
-                ] [ type>> ] tri <generator-bind> 1,
-            ] [
-                bind%
-            ] if
-        ] interleave
-        ");" 0%
-    ] query-make ;
-
-M: sqlite-db <insert-user-assigned-statement> ( tuple -- statement )
-    <insert-db-assigned-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% ;
-
-M: sqlite-db persistent-table ( -- assoc )
-    H{
-        { +db-assigned-id+ { "integer primary key" "integer primary key" "primary key" } }
-        { +user-assigned-id+ { f f "primary key" } }
-        { +random-id+ { "integer primary key" "integer primary key" "primary key" } }
-        { 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" } }
-        { URL { "text" "text" } }
-        { +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 compound ( str seq -- str' )
-    over {
-        { "default" [ first number>string join-space ] }
-        [ 2drop ] 
-    } case ;
diff --git a/extra/db/sqlite/test.txt b/extra/db/sqlite/test.txt
deleted file mode 100644 (file)
index e4487d3..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-create table person (name varchar(30), country varchar(30));
-insert into person values('John', 'America');
-insert into person values('Jane', 'New Zealand');
diff --git a/extra/db/summary.txt b/extra/db/summary.txt
deleted file mode 100644 (file)
index daebf38..0000000
+++ /dev/null
@@ -1 +0,0 @@
-Relational database abstraction layer
diff --git a/extra/db/tags.txt b/extra/db/tags.txt
deleted file mode 100644 (file)
index 0aef4fe..0000000
+++ /dev/null
@@ -1 +0,0 @@
-enterprise
diff --git a/extra/db/tuples/tuples-tests.factor b/extra/db/tuples/tuples-tests.factor
deleted file mode 100755 (executable)
index 5dd3ec8..0000000
+++ /dev/null
@@ -1,501 +0,0 @@
-! Copyright (C) 2008 Doug Coleman.
-! 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 calendar sequences db.sqlite math.intervals
-db.postgresql accessors random math.bitfields.lib
-math.ranges strings sequences.lib urls fry ;
-IN: db.tuples.tests
-
-TUPLE: person the-id the-name the-number the-real
-ts date time blob factor-blob url ;
-
-: <person> ( name age real ts date time blob factor-blob url -- person )
-    person new
-        swap >>url
-        swap >>factor-blob
-        swap >>blob
-        swap >>time
-        swap >>date
-        swap >>ts
-        swap >>the-real
-        swap >>the-number
-        swap >>the-name ;
-
-: <user-assigned-person> ( id name age real ts date time blob factor-blob url -- person )
-    <person>
-        swap >>the-id ;
-
-SYMBOL: person1
-SYMBOL: person2
-SYMBOL: person3
-SYMBOL: person4
-
-: test-tuples ( -- )
-    [ ] [ person recreate-table ] unit-test
-    [ ] [ person ensure-table ] unit-test
-    [ ] [ person drop-table ] unit-test
-    [ ] [ person create-table ] unit-test
-    [ person create-table ] must-fail
-    [ ] [ person ensure-table ] unit-test
-    
-    [ ] [ person1 get insert-tuple ] unit-test
-
-    [ 1 ] [ person1 get the-id>> ] unit-test
-
-    [ ] [ person1 get 200 >>the-number drop ] unit-test
-
-    [ ] [ person1 get update-tuple ] unit-test
-
-    [ T{ person f 1 "billy" 200 3.14 } ]
-    [ T{ person f 1 } select-tuple ] unit-test
-    [ ] [ person2 get insert-tuple ] unit-test
-    [
-        {
-            T{ person f 1 "billy" 200 3.14 }
-            T{ person f 2 "johnny" 10 3.14 }
-        }
-    ] [ T{ person f f f f 3.14 } select-tuples ] unit-test
-    [
-        {
-            T{ person f 1 "billy" 200 3.14 }
-            T{ person f 2 "johnny" 10 3.14 }
-        }
-    ] [ T{ person f } select-tuples ] unit-test
-
-    [
-        {
-            T{ person f 2 "johnny" 10 3.14 }
-        }
-    ] [ T{ person f f f 10 3.14 } select-tuples ] unit-test
-
-
-    [ ] [ person1 get delete-tuples ] unit-test
-    [ f ] [ T{ person f 1 } select-tuple ] unit-test
-
-    [ ] [ person3 get insert-tuple ] unit-test
-
-    [
-        T{
-            person
-            f
-            3
-            "teddy"
-            10
-            3.14
-            T{ timestamp f 2008 3 5 16 24 11 T{ duration f 0 0 0 0 0 0 } }
-            T{ timestamp f 2008 11 22 0 0 0 T{ duration f 0 0 0 0 0 0 } }
-            T{ timestamp f 0 0 0 12 34 56 T{ duration f 0 0 0 0 0 0 } }
-            B{ 115 116 111 114 101 105 110 97 98 108 111 98 }
-        }
-    ] [ T{ person f 3 } select-tuple ] unit-test
-
-    [ ] [ person4 get insert-tuple ] unit-test
-    [
-        T{
-            person
-            f
-            4
-            "eddie"
-            10
-            3.14
-            T{ timestamp f 2008 3 5 16 24 11 T{ duration f 0 0 0 0 0 0 } }
-            T{ timestamp f 2008 11 22 0 0 0 T{ duration f 0 0 0 0 0 0 } }
-            T{ timestamp f 0 0 0 12 34 56 T{ duration f 0 0 0 0 0 0 } }
-            f
-            H{ { 1 2 } { 3 4 } { 5 "lol" } }
-            URL" http://www.google.com/search?hl=en&q=trailer+park+boys&btnG=Google+Search"
-        }
-    ] [ T{ person f 4 } select-tuple ] unit-test
-
-    [ ] [ person drop-table ] unit-test ;
-
-: db-assigned-person-schema ( -- )
-    person "PERSON"
-    {
-        { "the-id" "ID" +db-assigned-id+ }
-        { "the-name" "NAME" { VARCHAR 256 } +not-null+ }
-        { "the-number" "AGE" INTEGER { +default+ 0 } }
-        { "the-real" "REAL" DOUBLE { +default+ 0.3 } }
-        { "ts" "TS" TIMESTAMP }
-        { "date" "D" DATE }
-        { "time" "T" TIME }
-        { "blob" "B" BLOB }
-        { "factor-blob" "FB" FACTOR-BLOB }
-        { "url" "U" URL }
-    } define-persistent
-    "billy" 10 3.14 f f f f f f <person> person1 set
-    "johnny" 10 3.14 f f f f f f <person> person2 set
-    "teddy" 10 3.14
-        T{ timestamp f 2008 3 5 16 24 11 T{ duration f 0 0 0 0 0 0 } }
-        T{ timestamp f 2008 11 22 0 0 0 T{ duration f 0 0 0 0 0 0 } }
-        T{ timestamp f 0 0 0 12 34 56 T{ duration f 0 0 0 0 0 0 } }
-        B{ 115 116 111 114 101 105 110 97 98 108 111 98 } f f <person> person3 set
-    "eddie" 10 3.14
-        T{ timestamp f 2008 3 5 16 24 11 T{ duration f 0 0 0 0 0 0 } }
-        T{ timestamp f 2008 11 22 0 0 0 T{ duration f 0 0 0 0 0 0 } }
-        T{ timestamp f 0 0 0 12 34 56 T{ duration f 0 0 0 0 0 0 } }
-        f H{ { 1 2 } { 3 4 } { 5 "lol" } } URL" http://www.google.com/search?hl=en&q=trailer+park+boys&btnG=Google+Search"  <person> person4 set ;
-
-: user-assigned-person-schema ( -- )
-    person "PERSON"
-    {
-        { "the-id" "ID" INTEGER +user-assigned-id+ }
-        { "the-name" "NAME" { VARCHAR 256 } +not-null+ }
-        { "the-number" "AGE" INTEGER { +default+ 0 } }
-        { "the-real" "REAL" DOUBLE { +default+ 0.3 } }
-        { "ts" "TS" TIMESTAMP }
-        { "date" "D" DATE }
-        { "time" "T" TIME }
-        { "blob" "B" BLOB }
-        { "factor-blob" "FB" FACTOR-BLOB }
-        { "url" "U" URL }
-    } define-persistent
-    1 "billy" 10 3.14 f f f f f f <user-assigned-person> person1 set
-    2 "johnny" 10 3.14 f f f f f f <user-assigned-person> person2 set
-    3 "teddy" 10 3.14
-        T{ timestamp f 2008 3 5 16 24 11 T{ duration f 0 0 0 0 0 0 } }
-        T{ timestamp f 2008 11 22 0 0 0 T{ duration f 0 0 0 0 0 0 } }
-        T{ timestamp f 0 0 0 12 34 56 T{ duration f 0 0 0 0 0 0 } }
-        B{ 115 116 111 114 101 105 110 97 98 108 111 98 }
-        f f <user-assigned-person> person3 set
-    4 "eddie" 10 3.14
-        T{ timestamp f 2008 3 5 16 24 11 T{ duration f 0 0 0 0 0 0 } }
-        T{ timestamp f 2008 11 22 0 0 0 T{ duration f 0 0 0 0 0 0 } }
-        T{ timestamp f 0 0 0 12 34 56 T{ duration f 0 0 0 0 0 0 } }
-        f H{ { 1 2 } { 3 4 } { 5 "lol" } } URL" http://www.google.com/search?hl=en&q=trailer+park+boys&btnG=Google+Search" <user-assigned-person> person4 set ;
-
-TUPLE: paste n summary author channel mode contents timestamp annotations ;
-TUPLE: annotation n paste-id summary author mode contents ;
-
-: db-assigned-paste-schema ( -- )
-    paste "PASTE"
-    {
-        { "n" "ID" +db-assigned-id+ }
-        { "summary" "SUMMARY" TEXT }
-        { "author" "AUTHOR" TEXT }
-        { "channel" "CHANNEL" TEXT }
-        { "mode" "MODE" TEXT }
-        { "contents" "CONTENTS" TEXT }
-        { "date" "DATE" TIMESTAMP }
-        { "annotations" { +has-many+ annotation } }
-    } define-persistent
-
-    annotation "ANNOTATION"
-    {
-        { "n" "ID" +db-assigned-id+ }
-        { "paste-id" "PASTE_ID" INTEGER { +foreign-id+ paste "n" } }
-        { "summary" "SUMMARY" TEXT }
-        { "author" "AUTHOR" TEXT }
-        { "mode" "MODE" TEXT }
-        { "contents" "CONTENTS" TEXT }
-    } define-persistent ;
-
-! { "localhost" "postgres" "" "factor-test" } postgresql-db [
-    ! [ paste drop-table ] [ drop ] recover
-    ! [ annotation drop-table ] [ drop ] recover
-    ! [ paste drop-table ] [ drop ] recover
-    ! [ annotation drop-table ] [ drop ] recover
-    ! [ ] [ paste create-table ] unit-test
-    ! [ ] [ annotation create-table ] unit-test
-! ] with-db
-
-: test-sqlite ( quot -- )
-    [ ] swap '[ "tuples-test.db" temp-file sqlite-db , with-db ] unit-test ;
-
-: test-postgresql ( quot -- )
-    [ ] swap '[ { "localhost" "postgres" "foob" "factor-test" } postgresql-db , with-db ] unit-test ;
-
-: test-repeated-insert
-    [ ] [ person ensure-table ] unit-test
-    [ ] [ person1 get insert-tuple ] unit-test
-    [ person1 get insert-tuple ] must-fail ;
-
-TUPLE: serialize-me id data ;
-
-: test-serialize ( -- )
-    serialize-me "SERIALIZED"
-    {
-        { "id" "ID" +db-assigned-id+ }
-        { "data" "DATA" FACTOR-BLOB }
-    } define-persistent
-    [ serialize-me drop-table ] [ drop ] recover
-    [ ] [ serialize-me create-table ] unit-test
-
-    [ ] [ T{ serialize-me f f H{ { 1 2 } } } insert-tuple ] unit-test
-    [
-        { T{ serialize-me f 1 H{ { 1 2 } } } }
-    ] [ T{ serialize-me f 1 } select-tuples ] unit-test ;
-
-TUPLE: exam id name score ; 
-
-: random-exam ( -- exam )
-        f
-        6 [ CHAR: a CHAR: z [a,b] random ] replicate >string
-        100 random
-    exam boa ;
-
-: test-intervals ( -- )
-    exam "EXAM"
-    {
-        { "id" "ID" +db-assigned-id+ }
-        { "name" "NAME" TEXT }
-        { "score" "SCORE" INTEGER }
-    } define-persistent
-    [ exam drop-table ] [ drop ] recover
-    [ ] [ exam create-table ] unit-test
-
-    [ ] [ T{ exam f f "Kyle" 100 } insert-tuple ] unit-test
-    [ ] [ T{ exam f f "Stan" 80 } insert-tuple ] unit-test
-    [ ] [ T{ exam f f "Kenny" 60 } insert-tuple ] unit-test
-    [ ] [ 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 f f T{ interval f { 0 t } { 70 t } } } select-tuples
-    ] unit-test
-
-    [
-        { }
-    ] [
-        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
-
-    [
-        {
-            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
-
-    [
-        {
-            T{ exam f 2 "Stan" 80 }
-            T{ exam f 3 "Kenny" 60 }
-            T{ exam f 4 "Cartman" 41 }
-        }
-    ] [
-        T{ exam f T{ interval f { 2 t } { 1.0/0.0 f } } } select-tuples
-    ] unit-test
-
-    [
-        {
-            T{ exam f 1 "Kyle" 100 }
-        }
-    ] [
-        T{ exam f T{ interval f { -1.0/0.0 t } { 2 f } } } 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 4 "Cartman" 41 }
-        }
-    ] [
-        T{ exam f T{ interval f { -1.0/0.0 t } { 1/0. f } } } 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 4 "Cartman" 41 }
-        }
-    ] [
-        T{ exam } select-tuples
-    ] unit-test
-
-    [ 4 ] [ T{ exam } f count-tuples ] unit-test ;
-
-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" +db-assigned-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^ 1- dup dup <bignum-test> insert-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
-
-: test-random-id
-    secret "SECRET"
-    {
-        { "n" "ID" +random-id+ system-random-generator }
-        { "message" "MESSAGE" TEXT }
-    } define-persistent
-
-    [ ] [ secret recreate-table ] unit-test
-
-    [ t ] [ f "kilroy was here" <secret> [ insert-tuple ] keep n>> integer? ] 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 ;
-
-[ db-assigned-person-schema test-tuples ] test-sqlite
-[ user-assigned-person-schema test-tuples ] test-sqlite
-[ user-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
-
-[ db-assigned-person-schema test-tuples ] test-postgresql
-[ user-assigned-person-schema test-tuples ] test-postgresql
-[ user-assigned-person-schema test-repeated-insert ] test-postgresql
-[ 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-postgresql
-
-
-TUPLE: suparclass id a ;
-
-suparclass f {
-    { "id" "ID" +db-assigned-id+ }
-    { "a" "A" INTEGER }
-} define-persistent
-
-TUPLE: subbclass < suparclass b ;
-
-subbclass "SUBCLASS" {
-    { "b" "B" TEXT }
-} define-persistent
-
-TUPLE: fubbclass < subbclass ;
-
-fubbclass "FUBCLASS" { } define-persistent
-
-: test-db-inheritance ( -- )
-    [ ] [ subbclass ensure-table ] unit-test
-    [ ] [ fubbclass ensure-table ] unit-test
-    
-    [ ] [
-        subbclass new 5 >>a "hi" >>b dup insert-tuple id>> "id" set
-    ] unit-test
-    
-    [ t "hi" 5 ] [
-        subbclass new "id" get >>id select-tuple
-        [ subbclass? ] [ b>> ] [ a>> ] tri
-    ] unit-test
-    
-    [ ] [ fubbclass new 0 >>a "hi" >>b insert-tuple ] unit-test
-    
-    [ t ] [ fubbclass new select-tuples [ fubbclass? ] all? ] unit-test ;
-
-[ test-db-inheritance ] test-sqlite
-[ test-db-inheritance ] test-postgresql
-
-
-TUPLE: string-encoding-test id string ;
-
-string-encoding-test "STRING_ENCODING_TEST" {
-    { "id" "ID" +db-assigned-id+ }
-    { "string" "STRING" TEXT }
-} define-persistent
-
-: test-string-encoding ( -- )
-    [ ] [ string-encoding-test ensure-table ] unit-test
-
-    [ ] [
-        string-encoding-test new
-            "\u{copyright-sign}\u{bengali-letter-cha}" >>string
-        [ insert-tuple ] [ id>> "id" set ] bi
-    ] unit-test
-    
-    [ "\u{copyright-sign}\u{bengali-letter-cha}" ] [
-        string-encoding-test new "id" get >>id select-tuple string>>
-    ] unit-test ;
-
-[ test-string-encoding ] test-sqlite
-[ test-string-encoding ] test-postgresql
-
-! Don't comment these out. These words must infer
-\ bind-tuple must-infer
-\ insert-tuple must-infer
-\ update-tuple must-infer
-\ delete-tuples must-infer
-\ select-tuple must-infer
-\ define-persistent must-infer
-\ ensure-table must-infer
-\ create-table must-infer
-\ drop-table must-infer
diff --git a/extra/db/tuples/tuples.factor b/extra/db/tuples/tuples.factor
deleted file mode 100755 (executable)
index 1b7ab24..0000000
+++ /dev/null
@@ -1,172 +0,0 @@
-! 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 accessors
-math.parser io prettyprint db.types continuations
-destructors mirrors sequences.lib combinators.lib ;
-IN: db.tuples
-
-: define-persistent ( class table columns -- )
-    >r dupd "db-table" set-word-prop dup r>
-    [ relation? ] partition swapd
-    dupd [ spec>tuple ] with map
-    "db-columns" set-word-prop
-    "db-relations" set-word-prop ;
-
-ERROR: not-persistent class ;
-
-: db-table ( class -- obj )
-    dup "db-table" word-prop [ ] [ not-persistent ] ?if ;
-
-: db-columns ( class -- obj )
-    superclasses [ "db-columns" word-prop ] map concat ;
-
-: db-relations ( class -- obj )
-    "db-relations" word-prop ;
-
-: set-primary-key ( key tuple -- )
-    [
-        class db-columns find-primary-key slot-name>>
-    ] keep set-slot-named ;
-
-SYMBOL: sql-counter
-: next-sql-counter ( -- str )
-    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 )
-
-HOOK: <insert-db-assigned-statement> db ( class -- obj )
-HOOK: <insert-user-assigned-statement> db ( class -- obj )
-HOOK: <update-tuple-statement> db ( class -- obj )
-HOOK: <delete-tuples-statement> db ( tuple class -- obj )
-HOOK: <select-by-slots-statement> db ( tuple class -- tuple )
-TUPLE: query group order offset limit ;
-HOOK: <query> db ( tuple class query -- statement' )
-HOOK: <count-statement> db ( tuple class groups -- n )
-
-HOOK: insert-tuple* db ( tuple statement -- )
-
-GENERIC: eval-generator ( singleton -- obj )
-SINGLETON: retryable
-
-: make-retryable ( obj -- obj' )
-    dup sequence? [
-        [ make-retryable ] map
-    ] [
-        retryable >>type
-        10 >>retries
-    ] if ;
-
-: regenerate-params ( statement -- statement )
-    dup
-    [ bind-params>> ] [ in-params>> ] bi
-    [
-        dup generator-bind? [
-            generator-singleton>> eval-generator >>value
-        ] [
-            drop
-        ] if
-    ] 2map >>bind-params ;
-
-M: retryable execute-statement* ( statement type -- )
-    drop [
-        [
-            [ query-results dispose t ]
-            [ ]
-            [ regenerate-params bind-statement* f ] cleanup
-        ] curry
-    ] [ retries>> ] bi retry drop ;
-
-: resulting-tuple ( class row out-params -- tuple )
-    rot class new [
-        [
-            >r slot-name>> r> set-slot-named
-        ] curry 2each
-    ] keep ;
-
-: query-tuples ( exemplar-tuple statement -- seq )
-    [ out-params>> ] keep query-results [
-        [ sql-row-typed swap resulting-tuple ] with with query-map
-    ] with-disposal ;
-: query-modify-tuple ( tuple statement -- )
-    [ query-results [ sql-row-typed ] with-disposal ] keep
-    out-params>> rot [
-        >r slot-name>> r> set-slot-named
-    ] curry 2each ;
-
-: sql-props ( class -- columns table )
-    [ db-columns ] [ db-table ] bi ;
-
-: with-disposals ( seq quot -- )
-    over sequence? [
-        [ with-disposal ] curry each
-    ] [
-        with-disposal
-    ] if ; inline
-
-: create-table ( class -- )
-    create-sql-statement [ execute-statement ] with-disposals ;
-
-: drop-table ( class -- )
-    drop-sql-statement [ execute-statement ] with-disposals ;
-
-: recreate-table ( class -- )
-    [
-        [ drop-sql-statement [ execute-statement ] with-disposals
-        ] curry ignore-errors
-    ] [ create-table ] bi ;
-
-: ensure-table ( class -- )
-    [ create-table ] curry ignore-errors ;
-
-: ensure-tables ( classes -- )
-    [ ensure-table ] each ;
-
-: insert-db-assigned-statement ( tuple -- )
-    dup class
-    db get insert-statements>> [ <insert-db-assigned-statement> ] cache
-    [ bind-tuple ] 2keep insert-tuple* ;
-
-: insert-user-assigned-statement ( tuple -- )
-    dup class
-    db get insert-statements>> [ <insert-user-assigned-statement> ] cache
-    [ bind-tuple ] keep execute-statement ;
-
-: insert-tuple ( tuple -- )
-    dup class db-columns find-primary-key db-assigned-id-spec?
-    [ insert-db-assigned-statement ] [ insert-user-assigned-statement ] if ;
-
-: update-tuple ( tuple -- )
-    dup class
-    db get update-statements>> [ <update-tuple-statement> ] cache
-    [ bind-tuple ] keep execute-statement ;
-
-: delete-tuples ( tuple -- )
-    dup dup class <delete-tuples-statement> [
-        [ bind-tuple ] keep execute-statement
-    ] with-disposal ;
-
-: do-select ( exemplar-tuple statement -- tuples )
-    [ [ bind-tuple ] [ query-tuples ] 2bi ] with-disposal ;
-
-: query ( tuple query -- tuples )
-    >r dup dup class r> <query> do-select ;
-
-: select-tuples ( tuple -- tuples )
-    dup dup class <select-by-slots-statement> do-select ;
-
-: select-tuple ( tuple -- tuple/f )
-    dup dup class \ query new 1 >>limit <query> do-select ?first ;
-
-: do-count ( exemplar-tuple statement -- tuples )
-    [
-        [ bind-tuple ] [ nip default-query ] 2bi
-    ] with-disposal ;
-
-: count-tuples ( tuple groups -- n )
-    >r dup dup class r> <count-statement> do-count
-    dup length 1 =
-    [ first first string>number ] [ [ first string>number ] map ] if ;
diff --git a/extra/db/types/types.factor b/extra/db/types/types.factor
deleted file mode 100755 (executable)
index c348009..0000000
+++ /dev/null
@@ -1,161 +0,0 @@
-! Copyright (C) 2008 Doug Coleman.
-! See http://factorcode.org/license.txt for BSD license.
-USING: arrays assocs db kernel math math.parser
-sequences continuations sequences.deep sequences.lib
-words namespaces slots slots.private classes mirrors
-classes.tuple combinators calendar.format symbols
-classes.singleton accessors quotations random ;
-IN: db.types
-
-HOOK: persistent-table db ( -- hash )
-HOOK: compound db ( str obj -- hash )
-
-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 slot-name key generator-singleton type ;
-C: <generator-bind> generator-bind
-SINGLETON: random-id-generator
-
-TUPLE: low-level-binding value ;
-C: <low-level-binding> low-level-binding
-
-SINGLETON: +db-assigned-id+
-SINGLETON: +user-assigned-id+
-SINGLETON: +random-id+
-UNION: +primary-key+ +db-assigned-id+ +user-assigned-id+ +random-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 -- ? )
-    primary-key>> +primary-key+? ;
-
-: db-assigned-id-spec? ( spec -- ? )
-    primary-key>> +db-assigned-id+? ;
-
-: assigned-id-spec? ( spec -- ? )
-    primary-key>> +user-assigned-id+? ;
-
-: normalize-spec ( spec -- )
-    dup type>> dup +primary-key+? [
-        >>primary-key drop
-    ] [
-        drop dup modifiers>> [
-            +primary-key+?
-        ] deep-find
-        [ >>primary-key drop ] [ drop ] if*
-    ] if ;
-
-: find-primary-key ( specs -- obj )
-    [ primary-key>> ] find nip ;
-
-: relation? ( spec -- ? ) [ +has-many+ = ] deep-find ;
-
-SYMBOLS: INTEGER BIG-INTEGER SIGNED-BIG-INTEGER UNSIGNED-BIG-INTEGER
-DOUBLE REAL BOOLEAN TEXT VARCHAR DATE TIME DATETIME TIMESTAMP BLOB
-FACTOR-BLOB NULL URL ;
-
-: spec>tuple ( class spec -- tuple )
-    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 ;
-
-: number>string* ( n/str -- str )
-    dup number? [ number>string ] when ;
-
-: remove-db-assigned-id ( specs -- obj )
-    [ +db-assigned-id+? not ] filter ;
-
-: remove-relations ( specs -- newcolumns )
-    [ relation? not ] filter ;
-
-: remove-id ( specs -- obj )
-    [ primary-key>> not ] filter ;
-
-! SQLite Types: http://www.sqlite.org/datatype3.html
-! NULL INTEGER REAL TEXT BLOB
-! PostgreSQL Types:
-! http://developer.postgresql.org/pgdocs/postgres/datatype.html
-
-ERROR: unknown-modifier ;
-
-: lookup-modifier ( obj -- str )
-    {
-        { [ dup array? ] [ unclip lookup-modifier swap compound ] }
-        [ persistent-table at* [ unknown-modifier ] unless third ]
-    } cond ;
-
-ERROR: no-sql-type ;
-
-: (lookup-type) ( obj -- str )
-    persistent-table at* [ no-sql-type ] unless ;
-
-: lookup-type ( obj -- str )
-    dup array? [
-        unclip (lookup-type) first nip
-    ] [
-        (lookup-type) first
-    ] if ;
-
-: lookup-create-type ( obj -- str )
-    dup array? [
-        unclip (lookup-type) second swap compound
-    ] [
-        (lookup-type) second
-    ] if ;
-
-: single-quote ( str -- newstr )
-    "'" swap "'" 3append ;
-
-: double-quote ( str -- newstr )
-    "\"" swap "\"" 3append ;
-
-: paren ( str -- newstr )
-    "(" swap ")" 3append ;
-
-: join-space ( str1 str2 -- newstr )
-    " " swap 3append ;
-
-: modifiers ( spec -- str )
-    modifiers>> [ lookup-modifier ] map " " join
-    dup empty? [ " " prepend ] unless ;
-
-HOOK: bind% db ( spec -- )
-HOOK: bind# db ( spec obj -- )
-
-: offset-of-slot ( str obj -- n )
-    class superclasses [ "slots" word-prop ] map concat
-    slot-named offset>> ;
-
-: get-slot-named ( name obj -- value )
-    tuck offset-of-slot slot ;
-
-: set-slot-named ( value name obj -- )
-    tuck offset-of-slot set-slot ;
-
-: tuple>filled-slots ( tuple -- alist )
-    <mirror> [ nip ] assoc-filter ;
-
-: tuple>params ( specs tuple -- obj )
-    [
-        >r [ type>> ] [ slot-name>> ] bi r>
-        get-slot-named swap
-    ] curry { } map>assoc ;