help-smalltalk
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Help-smalltalk] [PATCH] SQLite3 bindings


From: Paolo Bonzini
Subject: [Help-smalltalk] [PATCH] SQLite3 bindings
Date: Mon, 03 Dec 2007 08:57:46 +0100
User-agent: Thunderbird 2.0.0.9 (Macintosh/20071031)

These are contributed by Daniele Sciascia. I only modified them a little to support DML queries and to improve error reporting.

Paolo
--- orig/configure.ac
+++ mod/configure.ac
@@ -279,6 +279,12 @@ AC_MSG_RESULT($enable_mysql_tests)
 GST_PACKAGE_ENABLE([DBD-PostgreSQL], [dbd-postgresql],
    [GST_HAVE_LIB(pq, PQconnectdb)],
    [ac_cv_lib_pq_PQconnectdb])
+
+GST_PACKAGE_ENABLE([DBD-SQLite], [dbd-sqlite],
+   [AC_CHECK_HEADER([sqlite3.h])],
+   [ac_cv_header_sqlite3_h],
+   [Makefile], [dbd-sqlite3.la])
+
 GST_PACKAGE_ENABLE([DBI], [dbi])
 
 GST_PACKAGE_ENABLE([GDBM], [gdbm],


--- orig/tests/testsuite.at
+++ mod/tests/testsuite.at
@@ -148,4 +148,5 @@ AT_OPTIONAL_PACKAGE_TEST([GDBM])
 AT_OPTIONAL_PACKAGE_TEST([Iconv])
 AT_PACKAGE_TEST([MySQL], [], [$mysqlvars], [test "$enable_mysql_tests" != no])
 AT_PACKAGE_TEST([Sport])
+AT_OPTIONAL_PACKAGE_TEST([DBD-SQLite])
 AT_OPTIONAL_PACKAGE_TEST([ZLib])



--- /dev/null
+++ mod/packages/dbd-sqlite/ColumnInfo.st
@@ -0,0 +1,95 @@
+"======================================================================
+|
+|   SQLite bindings, ColumnInfo class
+|
+|
+ ======================================================================"
+
+
+"======================================================================
+|
+| Copyright 2007 Free Software Foundation, Inc.
+| Written by Daniele Sciascia
+|
+| This is free software; you can redistribute it and/or modify it
+| under the terms of the GNU General Public License as published by the Free
+| Software Foundation; either version 2, or (at your option) any later version.
+|
+| This code is distributed in the hope that it will be useful, but WITHOUT
+| ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+| FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
+| details.
+|
+| You should have received a copy of the GNU General Public License along with
+| Mumble; see the file COPYING.  If not, write to the Free Software
+| Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+|
+ ======================================================================
+"
+
+
+ColumnInfo subclass: SQLiteColumnInfo [
+    | resultSet index |
+    
+    TypeNames := nil.
+    
+    SQLiteColumnInfo class >> in: aResultSet at: anIndex [
+        ^(self new)
+            index: anIndex;
+            resultSet: aResultSet;
+            yourself
+    ]
+    
+    SQLiteColumnInfo class >> initTypes [
+        TypeNames := LookupTable new.
+        TypeNames at: 1 put: 'Integer'.
+        TypeNames at: 2 put: 'Float'.
+        TypeNames at: 3 put: 'Text'.
+        TypeNames at: 4 put: 'Blob'.
+        TypeNames at: 5 put: 'Null'.
+    ]
+    
+    resultSet: aResultSet [
+        <category: 'private'>
+        resultSet := aResultSet
+    ]
+    
+    name [
+           <category: 'accessing'>
+           ^resultSet columnAt: self index
+    ]
+
+    index [
+           <category: 'accessing'>
+        ^index
+    ]
+    
+    index: anIndex [
+        <category: 'private'>
+        index := anIndex
+    ]
+
+    type [
+           <category: 'accessing'>
+        ^TypeNames at: (resultSet columnTypeAt: self index)
+    ]
+
+    size [
+           "Return the size of the column (abstract)."
+           <category: 'accessing'>
+           self notYetImplemented
+    ]
+
+    printOn: aStream [
+           <category: 'printing'>
+           aStream
+               nextPutAll: self name;
+               nextPut: $(;
+               nextPutAll: self type;
+               nextPut: $)
+    ]
+]
+
+Eval [
+    SQLiteColumnInfo initTypes
+]
--- /dev/null
+++ mod/packages/dbd-sqlite/Connection.st
@@ -0,0 +1,96 @@
+"======================================================================
+|
+|   SQLite bindings, Connection class
+|
+|
+ ======================================================================"
+
+
+"======================================================================
+|
+| Copyright 2007 Free Software Foundation, Inc.
+| Written by Daniele Sciascia
+|
+| This is free software; you can redistribute it and/or modify it
+| under the terms of the GNU General Public License as published by the Free
+| Software Foundation; either version 2, or (at your option) any later version.
+|
+| This code is distributed in the hope that it will be useful, but WITHOUT
+| ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+| FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
+| details.
+|
+| You should have received a copy of the GNU General Public License along with
+| Mumble; see the file COPYING.  If not, write to the Free Software
+| Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+|
+ ======================================================================
+"
+
+
+Connection subclass: SQLiteConnection [
+       | stmtHandles handle |
+       
+       <category: 'DBI-Drivers'>
+       <comment: 'I represent a connection to a SQLite database'>
+       
+       
+       SQLiteConnection class >> paramConnect: params user: aUserName 
password: aPassword [
+        <category: 'connecting'>
+               | dbName aSqlite3Handle |
+               
+               dbName := params at: 'dbname'
+               ifAbsent: [self error: 'Missing parameter: dbname'].
+               aSqlite3Handle := SQLite3DBHandle open: dbName.
+               ^(self new)
+                   initializeWithHandle: aSqlite3Handle;
+                   yourself
+       ]
+       
+       initializeWithHandle: aSqlite3Handle [ 
+           handle := aSqlite3Handle.
+           stmtHandles := WeakIdentitySet new.
+       ]
+       
+       close [
+           <category: 'connecting'>
+           stmtHandles do: [ :each | each removeToBeFinalized; finalize ].
+           ^handle close
+       ]
+       
+       SQLiteConnection class >> driverName [
+           <category: 'initialization'>
+               ^'SQLite'
+       ]
+       
+    handle [
+        <category: 'private'>
+        ^handle
+    ]
+       
+       finalize [
+           <category: 'private'>
+           self close
+       ]
+       
+    do: aSQLQuery [
+        <category: 'querying'>
+        ^(self prepare: aSQLQuery) execute
+    ]
+
+    select: aSQLQuery [
+        <category: 'querying'>
+       ^(self prepare: aSQLQuery) execute
+    ]
+
+    prepare: aSQLQuery [
+        <category: 'querying'>
+        | stmtHandle |  
+        stmtHandle := self handle prepare: aSQLQuery.
+        stmtHandle addToBeFinalized.
+        stmtHandles add: stmtHandle.
+        ^(SQLiteStatement on: self)
+                    handle: stmtHandle;
+                    queryString: aSQLQuery.
+    ]
+]
--- /dev/null
+++ mod/packages/dbd-sqlite/Makefile.am
@@ -0,0 +1,11 @@
+pkglib_LTLIBRARIES = dbd-sqlite3.la
+
+AM_CPPFLAGS = -I$(top_srcdir)/libgst -I$(top_srcdir)/lib-src
+
+gst_module_ldflags = -rpath $(pkglibdir) -release $(VERSION) -module \
+        -no-undefined -export-symbols-regex gst_initModule
+
+dbd_sqlite3_la_SOURCES = sqlite3.c
+dbd_sqlite3_la_LIBADD = -lsqlite3
+dbd_sqlite3_la_LDFLAGS = $(gst_module_ldflags)
+
--- /dev/null
+++ mod/packages/dbd-sqlite/Makefile.frag
@@ -0,0 +1,5 @@
+DBD-SQLite_FILES = \
+packages/dbd-sqlite/SQLite.st packages/dbd-sqlite/Connection.st 
packages/dbd-sqlite/ResultSet.st packages/dbd-sqlite/Statement.st 
packages/dbd-sqlite/Row.st packages/dbd-sqlite/ColumnInfo.st 
packages/dbd-sqlite/SQLiteTests.st 
+$(DBD-SQLite_FILES):
+$(srcdir)/packages/dbd-sqlite/stamp-classes: $(DBD-SQLite_FILES)
+       touch $(srcdir)/packages/dbd-sqlite/stamp-classes
--- /dev/null
+++ mod/packages/dbd-sqlite/ResultSet.st
@@ -0,0 +1,157 @@
+"======================================================================
+|
+|   SQLite bindings, ResultSet class
+|
+|
+ ======================================================================"
+
+
+"======================================================================
+|
+| Copyright 2007 Free Software Foundation, Inc.
+| Written by Daniele Sciascia
+|
+| This is free software; you can redistribute it and/or modify it
+| under the terms of the GNU General Public License as published by the Free
+| Software Foundation; either version 2, or (at your option) any later version.
+|
+| This code is distributed in the hope that it will be useful, but WITHOUT
+| ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+| FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
+| details.
+|
+| You should have received a copy of the GNU General Public License along with
+| Mumble; see the file COPYING.  If not, write to the Free Software
+| Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+|
+ ======================================================================
+"
+
+
+ResultSet subclass: SQLiteResultSet [
+    | handle rows columns index |
+                  
+    SQLiteResultSet class >> on: aStatement [
+        <category: 'instance creation'>
+        ^self new initializeWithStatement: aStatement
+    ]
+    
+    initializeWithStatement: aStatement [
+        <category: 'initialization'>
+        index := 0.
+        self statement: aStatement.
+        self handle: (aStatement handle).
+        self isSelect
+           ifTrue: [self populate]
+           ifFalse: [self exec]
+    ]
+    
+    exec [
+        <category: 'initialization'>
+       | resCode |
+        resCode := self handle exec.
+        self handle checkError: resCode = 101.
+       rows := handle changes
+    ]
+
+    populate [
+        <category: 'initialization'>
+        | resCode |
+        
+        rows := OrderedCollection new.
+        [ resCode := self handle exec.
+          resCode = 100
+        ] whileTrue: [rows addLast: 
+                        (SQLiteRow forValues: (self handle returnedRow) in: 
self)].
+        
+        self handle checkError: resCode = 101.
+    ]
+    
+    handle [
+        <category: 'private'>
+        ^handle
+    ]
+    
+    handle: aSQLite3StmtHandle [
+        <category: 'private'>
+        handle := aSQLite3StmtHandle
+    ]
+
+    next [
+        <category: 'cursor access'>
+       self atEnd ifTrue: [self error: 'No more rows'].
+       index := index + 1.
+       ^self rows at: index
+    ]
+
+    atEnd [
+        <category: 'cursor access'>
+        ^index >= self rowCount
+    ]
+    
+    position [
+        <category: 'stream protocol'>
+        ^index
+    ]
+
+    position: anInteger [
+        <category: 'stream protocol'>
+        (anInteger between: 0 and: self size)
+            ifTrue: [ index := anInteger ] 
+            ifFalse: [ SystemExceptions.IndexOutOfRange signalOn: self 
withIndex: anInteger ].
+        ^index
+    ]
+
+    columns [
+        <category: 'accessing'>
+        columns isNil
+            ifTrue: [| n |
+                     n := self handle colCount.
+                     columns := LookupTable new: n.
+                     1 to: n do: [:i | columns at: (self columnNames at: i)
+                                               put: (SQLiteColumnInfo in: self 
at: i)]].
+        ^columns
+    ]
+
+    columnNames [
+        <category: 'accessing'>
+        ^self handle colNames
+    ]
+    
+    columnTypes [
+        ^self handle colTypes
+    ]
+    
+    columnTypeAt: index [
+        ^self columnTypes at: index
+    ]
+
+    isSelect [
+        <category: 'accessing'>
+       ^self statement isSelect
+    ]
+
+    isDML [
+        <category: 'accessing'>
+       ^self statement isSelect not
+    ]
+    
+    rows [
+        <category: 'accessing'>
+        ^rows
+    ]
+
+    rowCount [
+        <category: 'accessing'>
+        self isSelect 
+            ifTrue: [^self rows size]
+            ifFalse: [^self error: 'Not a SELECT statement.']
+    ]
+
+    rowsAffected [
+        <category: 'accessing'>
+        self isDML 
+            ifTrue: [^self rows]
+            ifFalse: [^self error: 'Not a DML statement.']
+    ]
+]
--- /dev/null
+++ mod/packages/dbd-sqlite/Row.st
@@ -0,0 +1,56 @@
+"======================================================================
+|
+|   SQLite bindings, Row class
+|
+|
+ ======================================================================"
+
+
+"======================================================================
+|
+| Copyright 2007 Free Software Foundation, Inc.
+| Written by Daniele Sciascia
+|
+| This is free software; you can redistribute it and/or modify it
+| under the terms of the GNU General Public License as published by the Free
+| Software Foundation; either version 2, or (at your option) any later version.
+|
+| This code is distributed in the hope that it will be useful, but WITHOUT
+| ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+| FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
+| details.
+|
+| You should have received a copy of the GNU General Public License along with
+| Mumble; see the file COPYING.  If not, write to the Free Software
+| Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+|
+ ======================================================================
+"
+
+
+Row subclass: SQLiteRow [
+    | values |
+    
+    SQLiteRow class >> forValues: anArray in: aResultSet [
+        ^super new 
+            values: anArray;
+            resultSet: aResultSet;
+            yourself
+    ]
+    
+    values: anArray [
+        <category: 'private'>
+        values := anArray
+    ]
+    
+    at: aColumnName [
+           <category: 'accessing'>
+           ^self atIndex: (resultSet columns at: aColumnName) index
+    ]
+
+    atIndex: aColumnIndex [
+           <category: 'accessing'>
+           ^values at: aColumnIndex
+    ]
+]
+
--- /dev/null
+++ mod/packages/dbd-sqlite/SQLite.st
@@ -0,0 +1,125 @@
+"======================================================================
+|
+|   SQLite bindings, bridge to the C library
+|
+|
+ ======================================================================"
+
+
+"======================================================================
+|
+| Copyright 2007 Free Software Foundation, Inc.
+| Written by Daniele Sciascia
+|
+| This is free software; you can redistribute it and/or modify it
+| under the terms of the GNU General Public License as published by the Free
+| Software Foundation; either version 2, or (at your option) any later version.
+|
+| This code is distributed in the hope that it will be useful, but WITHOUT
+| ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+| FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
+| details.
+|
+| You should have received a copy of the GNU General Public License along with
+| Mumble; see the file COPYING.  If not, write to the Free Software
+| Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+|
+ ======================================================================
+"
+
+
+Object subclass: SQLite3Handle [
+    | db |
+
+    errorMessage [
+        <cCall: 'gst_sqlite3_error_message' returing: #string args: #(#self)>
+    ]
+    
+    checkError: aBoolean [
+       aBoolean ifFalse: [ self error: self errorMessage ]
+    ]
+
+    changes [
+        <category: 'sqlite3 wrapper'>
+        <cCall: 'gst_sqlite3_changes' returning: #int args: #(#self)>
+    ]
+]
+
+SQLite3Handle subclass: SQLite3DBHandle [
+    SQLite3DBHandle class >> open: dbname [
+       | result rc |
+        result := self new.
+        rc := result open: dbname.
+       rc = 0 ifFalse: [ self error: 'error: ', rc printString ].
+       ^result
+    ]
+    
+    open: dbname [
+        <cCall: 'gst_sqlite3_open' returning: #int args: #(#self #string)>
+    ]
+
+    close [
+       <cCall: 'gst_sqlite3_close' returning: #int args: #(#self)>
+    ]
+    
+    prepare: aSQLQuery [
+        ^SQLite3StmtHandle forQuery: aSQLQuery onHandle: db
+    ]
+]
+
+SQLite3Handle subclass: SQLite3StmtHandle [
+    | stmt colCount colTypes colNames returnedRow |
+    
+    SQLite3StmtHandle class >> forQuery: aSQLQuery onHandle: aDbHandle [
+       | result rc |
+       result := self new db: aDbHandle.
+       rc := result prepare: aSQLQuery.
+       rc = 0 ifFalse: [ self error: 'error: ', rc printString ].
+        ^result
+    ]
+    
+    db [
+        <category: 'private'>
+        ^db
+    ]
+    
+    db: aDbHandle [
+        <category: 'private'>
+        db := aDbHandle
+    ]
+    
+    finalize [
+        <category: 'private'>
+        <cCall: 'gst_sqlite3_finalize' returning: #int args: #(#self)>
+    ]
+    
+    prepare: aSQLQuery [
+        <category: 'sqlite3 wrapper'>
+        <cCall: 'gst_sqlite3_prepare' returning: #int args: #(#self #string)>
+    ]
+    
+    exec [
+        <category: 'sqlite3 wrapper'>
+        <cCall: 'gst_sqlite3_exec' returning: #int args: #(#self)>
+    ]
+    
+    colCount [
+        <category: 'accessing'>
+        ^colCount
+    ]
+    
+    colTypes [
+        <category: 'accessing'>
+        ^colTypes
+    ]
+    
+    colNames [
+        <category: 'accessing'>
+        ^colNames
+    ]
+    
+    returnedRow [
+        <category: 'accessing'>
+        ^returnedRow
+    ]
+]
--- /dev/null
+++ mod/packages/dbd-sqlite/SQLiteTests.st
@@ -0,0 +1,159 @@
+"======================================================================
+|
+|   SQLite bindings test suite
+|
+|
+ ======================================================================"
+
+
+"======================================================================
+|
+| Copyright 2007 Free Software Foundation, Inc.
+| Written by Daniele Sciascia
+|
+| This is free software; you can redistribute it and/or modify it
+| under the terms of the GNU General Public License as published by the Free
+| Software Foundation; either version 2, or (at your option) any later version.
+|
+| This code is distributed in the hope that it will be useful, but WITHOUT
+| ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+| FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
+| details.
+|
+| You should have received a copy of the GNU General Public License along with
+| Mumble; see the file COPYING.  If not, write to the Free Software
+| Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+|
+ ======================================================================
+"
+
+
+
+TestCase subclass: SQLiteBaseTest [
+    | connection |
+    
+    setUp [
+       | f |
+       f := File name: 'testdb'.
+       f exists ifTrue: [ f remove ].
+        connection := DBI.Connection
+                        connect: 'dbi:SQLite:dbname=testdb'
+                        user: nil
+                        password: nil.
+       connection do: '
+           BEGIN TRANSACTION'.
+       connection do: '
+           CREATE TABLE test(int_field integer, string_field text,
+                             double_field double)'.
+       connection do: '
+           INSERT INTO "test" VALUES(1, "one", 1.0)'.
+       connection do: '
+           INSERT INTO "test" VALUES(2, "two", 2.0)'.
+       connection do: '
+           INSERT INTO "test" VALUES(3, "three", 3.0)'.
+       connection do: '
+           COMMIT'.
+    ]
+    
+    tearDown [
+        connection close
+    ]
+    
+    connection [
+        ^connection
+    ]
+]
+
+SQLiteBaseTest subclass: SQLiteDMLResultSetTestCase [
+    | rs |
+    
+    setUp [
+        super setUp.
+        rs := self connection
+                do: 'delete from test where string_field like "t%"'
+    ]
+
+    testRowsAffected [
+       self assert: rs rowsAffected = 2
+    ]
+]
+    
+
+SQLiteBaseTest subclass: SQLiteResultSetTestCase [
+    | rs |
+    
+    setUp [
+        super setUp.
+        rs := self connection
+               select: 'select * from test'
+    ]
+    
+    testNext [
+        self should: [rs position = 0].
+        rs next.
+        self should: [rs position = 1].
+        rs next.
+        self should: [rs position = 2].
+        rs next.
+        self should: [rs atEnd]
+    ]
+    
+    testAtEnd [
+        self shouldnt: [rs atEnd].
+        rs next.
+        self shouldnt: [rs atEnd].
+        rs next.
+        self shouldnt: [rs atEnd].
+        rs next.
+        self should: [rs atEnd]
+    ]
+    
+    testColumnNames [
+        self should: [rs columnNames = #('int_field' 'string_field' 
'double_field')]
+    ]
+    
+    testRowCount [
+        self should: [rs rowCount = 3]
+    ]
+]
+
+SQLiteBaseTest subclass: SQLiteRowTestCase [
+    | rs row |
+    
+    setUp [
+        super setUp.
+        rs := self connection select: 'select * from test where int_field = 1'.
+        row := rs rows at: 1.
+    ]
+    
+    testAt [
+        self should: [(row at: 'int_field') = 1].
+        self should: [(row at: 'string_field') = 'one'].
+        self should: [(row at: 'double_field') = 1.0]
+    ]
+    
+    testAtIndex [
+        self should: [(row atIndex: 1) = 1].
+        self should: [(row atIndex: 2) = 'one'].
+        self should: [(row atIndex: 3) = 1.0]
+    ]
+]
+
+TestSuite subclass: SQLiteTestSuite [
+    SQLiteTestSuite class >> suite [
+        ^super new initialize
+    ]
+    
+    initialize [
+        self name: 'SQLite-Test'.
+        self addTest: (SQLiteResultSetTestCase selector: #testNext).
+        self addTest: (SQLiteResultSetTestCase selector: #testAtEnd).
+        self addTest: (SQLiteResultSetTestCase selector: #testColumnNames).
+        self addTest: (SQLiteResultSetTestCase selector: #testRowCount).
+
+        self addTest: (SQLiteRowTestCase selector: #testAt).
+        self addTest: (SQLiteRowTestCase selector: #testAtIndex).
+
+        self addTest: (SQLiteDMLResultSetTestCase selector: #testRowsAffected).
+    ]
+]
--- /dev/null
+++ mod/packages/dbd-sqlite/Statement.st
@@ -0,0 +1,89 @@
+"======================================================================
+|
+|   SQLite bindings, Statement class
+|
+|
+ ======================================================================"
+
+
+"======================================================================
+|
+| Copyright 2007 Free Software Foundation, Inc.
+| Written by Daniele Sciascia
+|
+| This is free software; you can redistribute it and/or modify it
+| under the terms of the GNU General Public License as published by the Free
+| Software Foundation; either version 2, or (at your option) any later version.
+|
+| This code is distributed in the hope that it will be useful, but WITHOUT
+| ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+| FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
+| details.
+|
+| You should have received a copy of the GNU General Public License along with
+| Mumble; see the file COPYING.  If not, write to the Free Software
+| Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+|
+ ======================================================================
+"
+
+
+
+Statement subclass: SQLiteStatement [
+    | handle queryString isSelect |
+    
+    <category: 'DBI-Drivers'>
+    <comment: 'I represent a SQLite prepared statement'>
+    
+    SelectQueries := #('EXPLAIN' 'SELECT') asSet.
+
+    handle [
+        <category: 'private'>
+        ^handle
+    ]
+    
+    handle: aSqlite3StmtHandle [
+        <category: 'private'>
+        handle := aSqlite3StmtHandle
+    ]
+    
+    queryString [
+        <category: 'accessing'>
+        ^queryString
+    ]
+    
+    queryString: aSQLQuery [
+        <category: 'accessing'>
+        queryString := aSQLQuery.
+        
+    ]
+    
+    isSelect [
+        <category: 'accessing'>
+        isSelect isNil
+            ifTrue: [isSelect := SelectQueries includes: self getCommand].
+        ^isSelect
+    ]
+    
+    execute [
+           <category: 'querying'>
+        ^SQLiteResultSet on: self
+    ]
+    
+    executeWithAll: aParams [
+        <category: 'querying'>
+           self notYetImplemented
+    ]
+    
+    getCommand [
+        <category: 'private'>
+        | readStream writeStream aCharacter |
+        writeStream := WriteStream on: String new.
+        readStream := ReadStream on: queryString.
+        readStream skipSeparators.
+        [readStream atEnd
+           or: [aCharacter := readStream next. aCharacter isSeparator]]
+                whileFalse: [writeStream nextPut: aCharacter asUppercase].
+        ^writeStream contents
+    ]
+]
--- /dev/null
+++ mod/packages/dbd-sqlite/package.xml
@@ -0,0 +1,27 @@
+<package>
+  <name>DBD-SQLite</name>
+  <prereq>DBI</prereq>
+  <namespace>DBI.SQLite</namespace>
+  <module>dbd-sqlite3</module>
+
+  <filein>SQLite.st</filein>
+  <filein>Connection.st</filein>
+  <filein>ResultSet.st</filein>
+  <filein>Statement.st</filein>
+  <filein>Row.st</filein>
+  <filein>ColumnInfo.st</filein>
+  
+  <file>SQLite.st</file>
+  <file>Connection.st</file>
+  <file>ResultSet.st</file>
+  <file>Statement.st</file>
+  <file>Row.st</file>
+  <file>ColumnInfo.st</file>
+  
+  <test>
+    <sunit>DBI.SQLite.SQLiteTestSuite</sunit>
+    <filein>SQLiteTests.st</filein>
+  </test>
+
+  <file>SQLiteTests.st</file>
+</package>
--- /dev/null
+++ mod/packages/dbd-sqlite/sqlite3.c
@@ -0,0 +1,248 @@
+/******************************* -*- C -*- ****************************
+ *
+ *      SQLite bindings
+ *
+ *
+ ***********************************************************************/
+
+/***********************************************************************
+ *
+ * Copyright 2007 Free Software Foundation, Inc.
+ * Written by Daniele Sciascia.
+ *
+ * This file is part of GNU Smalltalk.
+ *
+ * GNU Smalltalk is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2, or (at your option) any later
+ * version.
+ *
+ * Linking GNU Smalltalk statically or dynamically with other modules is
+ * making a combined work based on GNU Smalltalk.  Thus, the terms and
+ * conditions of the GNU General Public License cover the whole
+ * combination.
+ *
+ * In addition, as a special exception, the Free Software Foundation
+ * give you permission to combine GNU Smalltalk with free software
+ * programs or libraries that are released under the GNU LGPL and with
+ * independent programs running under the GNU Smalltalk virtual machine.
+ *
+ * You may copy and distribute such a system following the terms of the
+ * GNU GPL for GNU Smalltalk and the licenses of the other code
+ * concerned, provided that you include the source code of that other
+ * code when and as the GNU GPL requires distribution of source code.
+ *
+ * Note that people who make modified versions of GNU Smalltalk are not
+ * obligated to grant this special exception for their modified
+ * versions; it is their choice whether to do so.  The GNU General
+ * Public License gives permission to release a modified version without
+ * this exception; this exception also makes it possible to release a
+ * modified version which carries forward this exception.
+ *
+ * GNU Smalltalk is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * GNU Smalltalk; see the file COPYING.  If not, write to the Free Software
+ * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ ***********************************************************************/
+
+
+#include <stdio.h>
+#include "gstpub.h"
+#include "sqlite3.h"
+
+typedef struct st_Sqlite3Handle
+{
+  OBJ_HEADER;
+  OOP db;
+} *SQLite3Handle;
+
+typedef struct st_SQLite3StmtHandle
+{
+  OBJ_HEADER;
+  OOP db;
+  OOP stmt;
+  OOP colCount;
+  OOP colTypes;
+  OOP colNames;
+  OOP returnedRow;
+} *SQLite3StmtHandle;
+
+
+static VMProxy *vmProxy;
+
+
+int
+gst_sqlite3_open (OOP self, const char *db_name)
+{
+  int rc;
+  sqlite3 *db;
+  OOP dbHandle;
+  SQLite3Handle h;
+
+  rc = sqlite3_open (db_name, &db);
+  dbHandle = vmProxy->cObjectToOOP (db);
+  h = (SQLite3Handle) OOP_TO_OBJ (self);
+  h->db = dbHandle;
+
+  return rc;
+}
+
+int
+gst_sqlite3_close (OOP self)
+{
+  sqlite3 *db;
+  SQLite3Handle h;
+
+  h = (SQLite3Handle) OOP_TO_OBJ (self);
+  db = (sqlite3 *) vmProxy->OOPToCObject (h->db);
+  return sqlite3_close (db);
+}
+
+int
+gst_sqlite3_prepare (OOP self, const char *sql)
+{
+  int rc, i, cols;
+  sqlite3 *db;
+  sqlite3_stmt *stmt;
+  OOP tmpOOP;
+  SQLite3StmtHandle h;
+
+  h = (SQLite3StmtHandle) OOP_TO_OBJ (self);
+  db = (sqlite3 *) vmProxy->OOPToCObject (h->db);
+
+  rc = sqlite3_prepare (db, sql, -1, &stmt, 0);
+  tmpOOP = vmProxy->cObjectToOOP (stmt);
+  h->stmt = tmpOOP;
+
+  if (rc != SQLITE_OK)
+    return rc;
+
+  cols = sqlite3_column_count (stmt);
+
+  tmpOOP = vmProxy->intToOOP (cols);
+  h->colCount = tmpOOP;
+
+  tmpOOP = vmProxy->objectAlloc (vmProxy->arrayClass, cols);
+  h->colTypes = tmpOOP;
+
+  tmpOOP = vmProxy->objectAlloc (vmProxy->arrayClass, cols);
+  h->colNames = tmpOOP;
+
+  tmpOOP = vmProxy->objectAlloc (vmProxy->arrayClass, cols);
+  h->returnedRow = tmpOOP;
+
+  for (i = 0; i < cols; i++)
+    {
+      tmpOOP = vmProxy->stringToOOP (sqlite3_column_name (stmt, i));
+      vmProxy->OOPAtPut (h->colNames, i, tmpOOP);
+    }
+
+  return rc;
+}
+
+int
+gst_sqlite3_exec (OOP self)
+{
+  int rc;
+  sqlite3_stmt *stmt;
+  SQLite3StmtHandle h;
+
+  h = (SQLite3StmtHandle) OOP_TO_OBJ (self);
+  stmt = (sqlite3_stmt *) vmProxy->OOPToCObject (h->stmt);
+
+  rc = sqlite3_step (stmt);
+
+  if (rc == SQLITE_ROW)
+    {
+      int i, cols, type;
+      OOP tmpOOP;
+
+      cols = sqlite3_column_count (stmt);
+      for (i = 0; i < cols; i++)
+       {
+         type = sqlite3_column_type (stmt, i);
+         tmpOOP = vmProxy->intToOOP (type);
+         vmProxy->OOPAtPut (h->colTypes, i, tmpOOP);
+
+         switch (type)
+           {
+           case SQLITE_INTEGER:
+             tmpOOP = vmProxy->intToOOP (sqlite3_column_int (stmt, i));
+             break;
+           case SQLITE_FLOAT:
+             tmpOOP = vmProxy->floatToOOP (sqlite3_column_double (stmt, i));
+             break;
+           case SQLITE_TEXT:
+             tmpOOP = vmProxy->stringToOOP (sqlite3_column_text (stmt, i));
+             break;
+           case SQLITE_BLOB:
+             tmpOOP = vmProxy->stringToOOP (sqlite3_column_text (stmt, i));
+             break;
+           case SQLITE_NULL:
+             tmpOOP = vmProxy->nilOOP;
+             break;
+           default:
+             fprintf (stderr, "sqlite3 error: %s\n",
+                      "returned type not recognized");
+           }
+
+         vmProxy->OOPAtPut (h->returnedRow, i, tmpOOP);
+       }
+    }
+
+  return rc;
+}
+
+const char *
+gst_sqlite3_error_message (OOP self)
+{
+  sqlite3 *db;
+  SQLite3Handle h;
+
+  h = (SQLite3Handle) OOP_TO_OBJ (self);
+  db = (sqlite3 *) vmProxy->OOPToCObject (h->db);
+
+  return sqlite3_errmsg (db);
+}
+
+int
+gst_sqlite3_finalize (OOP self)
+{
+  sqlite3_stmt *stmt;
+  SQLite3StmtHandle h;
+
+  h = (SQLite3StmtHandle) OOP_TO_OBJ (self);
+  stmt = (sqlite3_stmt *) vmProxy->OOPToCObject (h->stmt);
+
+  return sqlite3_finalize (stmt);
+}
+
+int
+gst_sqlite3_changes (OOP self)
+{
+  sqlite3 *db;
+  SQLite3StmtHandle h;
+
+  h = (SQLite3StmtHandle) OOP_TO_OBJ (self);
+  db = (sqlite3 *) vmProxy->OOPToCObject (h->db);
+
+  return sqlite3_changes (db);
+}
+
+void
+gst_initModule (VMProxy * proxy)
+{
+  vmProxy = proxy;
+  vmProxy->defineCFunc ("gst_sqlite3_open", gst_sqlite3_open);
+  vmProxy->defineCFunc ("gst_sqlite3_close", gst_sqlite3_close);
+  vmProxy->defineCFunc ("gst_sqlite3_prepare", gst_sqlite3_prepare);
+  vmProxy->defineCFunc ("gst_sqlite3_exec", gst_sqlite3_exec);
+  vmProxy->defineCFunc ("gst_sqlite3_changes", gst_sqlite3_changes);
+  vmProxy->defineCFunc ("gst_sqlite3_error_message", 
gst_sqlite3_error_message);
+  vmProxy->defineCFunc ("gst_sqlite3_finalize", gst_sqlite3_finalize);
+}


reply via email to

[Prev in Thread] Current Thread [Next in Thread]