dbd-jdbc 0.1.6-java

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in dbd-jdbc.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,27 @@
1
+ (C) 2009 Chad Johnson <chad.j.johnson@gmail.com>.
2
+ (C) 2008 Ola Bini <ola.bini@gmail.com>.
3
+ (C) 2006 Kristopher Schmidt <krisschmidt@optonline.net>.
4
+
5
+ All rights reserved.
6
+
7
+ Redistribution and use in source and binary forms, with or without
8
+ modification, are permitted provided that the following conditions
9
+ are met:
10
+ 1. Redistributions of source code must retain the above copyright
11
+ notice, this list of conditions and the following disclaimer.
12
+ 2. Redistributions in binary form must reproduce the above copyright
13
+ notice, this list of conditions and the following disclaimer in the
14
+ documentation and/or other materials provided with the distribution.
15
+ 3. The name of the author may not be used to endorse or promote products
16
+ derived from this software without specific prior written permission.
17
+
18
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
19
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
20
+ AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
21
+ THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
24
+ OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25
+ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
26
+ OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
27
+ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
data/README.txt ADDED
@@ -0,0 +1,85 @@
1
+ RECENT CHANGES
2
+ ==============
3
+ The dbd-jdbc project has recently moved to Github and can be found at the following url
4
+ (http://github.com/chadj/dbd-jdbc). Please report any bugs found to the issue
5
+ tracker on Github.
6
+
7
+ OVERVIEW
8
+ ========
9
+ The Jdbc driver for DBI runs only under JRuby, using JRuby's Java integration to act
10
+ as a thin wrapper around JDBC Connections obtained through DriverManager.
11
+ Theoretically this driver can support any database that has JDBC support, although the
12
+ behavior of certain aspects of the DBI API will differ slightly based on the
13
+ implementation of the JDBC driver and the underlying database (see LIMITATIONS)
14
+
15
+ INSTALLATION
16
+ ============
17
+ Besides the ruby files being installed with DBI (in DBD/Jdbc), the JDBC driver classes
18
+ must be added to the JRuby classpath. One way to do this on UNIX machines is to
19
+ place a JDBC driver jarfile in JRUBY_HOME/lib. Another way is to set the CLASSPATH
20
+ environment variable. The jruby (or jruby.bat) script can also be modified to add to
21
+ the classpath. In the future there may be more dynamic ways to add jarfiles to the
22
+ classpath as well; check with the JRuby documentation.
23
+
24
+ USAGE
25
+ =====
26
+ This driver is used like any standard DBI driver, by requiring 'dbi' and obtaining a
27
+ connection through the DBI.connect method. The DSN for the database should be "dbi:"
28
+ followed by the standard Java database URL (jdbc:<subprotocol>:<subname>). In
29
+ addition, the attributes hash passed to the connect method must contain the key/value
30
+ pair "driver" => <jdbc driver class name>. For example (MySQL):
31
+
32
+ dbh = DBI.connect('dbi:jdbc:mysql://localhost:3306/test', 'anonymous', '',
33
+ { "driver" => "com.mysql.jdbc.Driver" } )
34
+
35
+ SUPPORTED ATTRIBUTES
36
+ ====================
37
+ Besides the mandatory "driver" attribute that must be passed in the DBI connect method,
38
+ there are additional attributes that can be passed to modify the behavior of the
39
+ driver. In addition to setting these attributes during the connect call, they can be
40
+ set on a driver handle using []= (e.g. dbh["autocommit"] = true). The currently
41
+ supported attributes are:
42
+
43
+ 1) autocommit: sets the autoCommit status of the underlying JDBC Connection
44
+ (there is a 1-1 relationship between a DBI Database instance and a JDBC Connection)
45
+ 2) nulltype: sets the java.sql.Types constant to use when binding nil to a Statement.
46
+ See LIMITATIONS
47
+
48
+ LIMITATIONS
49
+ ===========
50
+ There are limitations to the JDBC driver that are largely based on incompatibilities
51
+ between the DBI and JDBC APIs, and the differences in underlying JDBC driver
52
+ implementations.
53
+
54
+ 1) Binding nil to statements is somewhat unreliable due to the fact that JDBC requires
55
+ type information in PreparedStatement.setNull(int), but there is no type information
56
+ associated with nil in ruby. E.g., statements like DBI.select_all("select * from a, b,
57
+ c where col1=? and col2=?", "a", nil) might run into problems. One workaround is to
58
+ hardcode NULL in the sql statement. If executing multiple inserts and some values
59
+ might be nil, the driver will call setNull with the type specified in the driver
60
+ attribute "nulltype". If the default fails with a given driver, try specifying
61
+ different nulltypes such as "dbh['nulltype'] = java.sql.Types::NULL" or
62
+ "dbh['nulltype'] = java.sql.Types::OTHER" to see if it will work.
63
+
64
+ 2) Type conversion in result sets: Java to Ruby type conversion in results of queries
65
+ is more limited than in JDBC, since DBI returns an entire row at a time, without type
66
+ information specified (unlike JDBC ResultSet where getInt, getString, etc allow each
67
+ column to be typed appropriately). The driver attempts to convert each data type,
68
+ relying mostly on getObject() and the JRuby type conversion system. Due to the fact
69
+ that JDBC drivers are not constrained to the exact Java types returned for each SQL
70
+ type, it is possible for some conversion oddities to arise (e.g. returning Java
71
+ BigDecimal which isn't converted by JRuby, leading to a Java BigDecimal rather than
72
+ Ruby Fixnum/BigDecimal).
73
+
74
+ 3) Type conversion in prepared statements: In addition to not being able to use type
75
+ data when returning data, it isn't possible to specify type data directly when binding
76
+ parameters either (when binding multiple parameters, DBI has ability to set type data,
77
+ and when calling bind_param, this driver does not currently support type data in the
78
+ attributes). Most conversions should work without problem, but there is ambiguity in
79
+ the Ruby Float type since it can be treated as float or double (or BigDecimal) in Java
80
+ (and FLOAT, DOUBLE, REAL, NUMERIC, DECIMAL, etc in java.sql.Types). setDouble() is
81
+ used to try to retain the highest precision, but some problems have been seen (e.g.
82
+ Sybase REAL works better with setFloat()). When doing inserts or retrieval, be sure
83
+ that the driver keeps the desired precision (the only workaround is to change the
84
+ database column type to something that works better for doubles with the given JDBC
85
+ driver and database)
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
data/dbd-jdbc.gemspec ADDED
@@ -0,0 +1,24 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'dbd/jdbc/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = "dbd-jdbc"
8
+ gem.version = DBI::DBD::Jdbc::VERSION
9
+ gem.authors = ["Chad Johnson"]
10
+ gem.email = ["chad.j.johnson@gmail.com"]
11
+ gem.description = %q{A JDBC DBD driver for Ruby DBI}
12
+ gem.summary = %q{JDBC driver for DBI, originally by Kristopher Schmidt and Ola Bini}
13
+ gem.homepage = "http://github.com/chadj/dbd-jdbc"
14
+ gem.rubyforge_project = 'jruby-extras'
15
+ gem.platform = Gem::Platform::JAVA
16
+ gem.files = `git ls-files`.split($/)
17
+ gem.require_paths = ["lib"]
18
+
19
+ gem.add_development_dependency 'rake'
20
+
21
+ # Not adding dbi as a hard dependency, since either the "real" dbi gem
22
+ # or rails-dbi will work.
23
+ gem.requirements << 'dbi or ruby-dbi gem'
24
+ end
data/lib/dbd/Jdbc.rb ADDED
@@ -0,0 +1,103 @@
1
+ # (C) 2009 Chad Johnson <chad.j.johnson@gmail.com>.
2
+ # (C) 2008 Ola Bini <ola.bini@gmail.com>.
3
+ # (C) 2006 Kristopher Schmidt <krisschmidt@optonline.net>.
4
+ #
5
+ # All rights reserved.
6
+ #
7
+ # Redistribution and use in source and binary forms, with or without
8
+ # modification, are permitted provided that the following conditions
9
+ # are met:
10
+ # 1. Redistributions of source code must retain the above copyright
11
+ # notice, this list of conditions and the following disclaimer.
12
+ # 2. Redistributions in binary form must reproduce the above copyright
13
+ # notice, this list of conditions and the following disclaimer in the
14
+ # documentation and/or other materials provided with the distribution.
15
+ # 3. The name of the author may not be used to endorse or promote products
16
+ # derived from this software without specific prior written permission.
17
+ #
18
+ # THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
19
+ # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
20
+ # AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
21
+ # THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22
+ # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23
+ # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
24
+ # OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25
+ # WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
26
+ # OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
27
+ # ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
+
29
+ require 'java'
30
+ require 'dbi'
31
+
32
+ module DBI
33
+ module DBD
34
+ #
35
+ # DBD::Jdbc - Database Driver for Java / JDBC
36
+ #
37
+ # Requires DBI and JRuby
38
+ #
39
+ module Jdbc
40
+ java_import 'java.sql.Connection'
41
+ java_import 'java.sql.ResultSet'
42
+ java_import 'java.util.HashMap'
43
+ java_import 'java.util.Collections'
44
+
45
+ #
46
+ # Transaction isolation levels copied from JDBC
47
+ #
48
+ TRANSACTION_NONE = Connection::TRANSACTION_NONE
49
+ TRANSACTION_READ_COMMITTED = Connection::TRANSACTION_READ_COMMITTED
50
+ TRANSACTION_READ_UNCOMMITTED = Connection::TRANSACTION_READ_UNCOMMITTED
51
+ TRANSACTION_REPEATABLE_READ = Connection::TRANSACTION_REPEATABLE_READ
52
+ TRANSACTION_SERIALIZABLE = Connection::TRANSACTION_SERIALIZABLE
53
+ # Convience isolation levels
54
+ NONE = Connection::TRANSACTION_NONE
55
+ READ_COMMITTED = Connection::TRANSACTION_READ_COMMITTED
56
+ READ_UNCOMMITTED = Connection::TRANSACTION_READ_UNCOMMITTED
57
+ REPEATABLE_READ = Connection::TRANSACTION_REPEATABLE_READ
58
+ SERIALIZABLE = Connection::TRANSACTION_SERIALIZABLE
59
+
60
+ #
61
+ # returns 'Jdbc'
62
+ #
63
+ # See DBI::TypeUtil#convert for more information.
64
+ #
65
+ def self.driver_name
66
+ "Jdbc"
67
+ end
68
+
69
+ module Type
70
+ class Timestamp < DBI::Type::Null
71
+ def self.parse(obj)
72
+ obj = super
73
+ return obj unless obj
74
+
75
+ if obj.kind_of?(::DateTime) || obj.kind_of?(::Time) || obj.kind_of?(::Date)
76
+ return obj
77
+ elsif obj.kind_of?(::String)
78
+ return ::DateTime.strptime(obj, "%Y-%m-%d %H:%M:%S")
79
+ else
80
+ return ::DateTime.parse(obj.to_s) if obj.respond_to? :to_s
81
+ return ::DateTime.parse(obj.to_str) if obj.respond_to? :to_str
82
+ return obj
83
+ end
84
+ end
85
+ end
86
+ end
87
+
88
+ #
89
+ # Bound values pass through this function before being handed to Statement.bind_param
90
+ #
91
+ # The false value prevents the default type conversion from occurring
92
+ #
93
+ DBI::TypeUtil.register_conversion(driver_name) do |obj|
94
+ [obj, false]
95
+ end
96
+ end
97
+ end
98
+ end
99
+
100
+ require 'dbd/jdbc/type_conversion'
101
+ require 'dbd/jdbc/driver'
102
+ require 'dbd/jdbc/database'
103
+ require 'dbd/jdbc/statement'
@@ -0,0 +1,180 @@
1
+ # (C) 2009 Chad Johnson <chad.j.johnson@gmail.com>.
2
+ # (C) 2008 Ola Bini <ola.bini@gmail.com>.
3
+ # (C) 2006 Kristopher Schmidt <krisschmidt@optonline.net>.
4
+ #
5
+ # All rights reserved.
6
+ #
7
+ # Redistribution and use in source and binary forms, with or without
8
+ # modification, are permitted provided that the following conditions
9
+ # are met:
10
+ # 1. Redistributions of source code must retain the above copyright
11
+ # notice, this list of conditions and the following disclaimer.
12
+ # 2. Redistributions in binary form must reproduce the above copyright
13
+ # notice, this list of conditions and the following disclaimer in the
14
+ # documentation and/or other materials provided with the distribution.
15
+ # 3. The name of the author may not be used to endorse or promote products
16
+ # derived from this software without specific prior written permission.
17
+ #
18
+ # THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
19
+ # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
20
+ # AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
21
+ # THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22
+ # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23
+ # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
24
+ # OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25
+ # WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
26
+ # OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
27
+ # ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
+
29
+ module DBI::DBD::Jdbc
30
+ #
31
+ # Models the DBI::BaseDatabase API to create DBI::DatabaseHandle objects.
32
+ #
33
+ class Database < DBI::BaseDatabase
34
+ include TypeConversions
35
+
36
+ def initialize(connection)
37
+ @connection = connection
38
+ @attributes = {
39
+ #works with Sybase and Mysql.
40
+ "nulltype" => java.sql.Types::VARCHAR,
41
+ "allow_scroll" => false
42
+ }
43
+ end
44
+
45
+ def disconnect
46
+ @connection.rollback unless self["autocommit"]
47
+ @connection.close
48
+ rescue NativeException => error
49
+ raise DBI::DatabaseError.new(error.message)
50
+ end
51
+
52
+ def prepare(sql)
53
+ if self["allow_scroll"]
54
+ return Statement.new(@connection.prepareStatement(sql,ResultSet::TYPE_SCROLL_INSENSITIVE, ResultSet::CONCUR_READ_ONLY), self["nulltype"], self["allow_scroll"])
55
+ else
56
+ return Statement.new(@connection.prepareStatement(sql), self["nulltype"], self["allow_scroll"])
57
+ end
58
+ rescue NativeException => error
59
+ raise DBI::DatabaseError.new(error.message)
60
+ end
61
+
62
+ def do(statement, *bindvars)
63
+ res = nil
64
+ if bindvars.nil? || bindvars.empty?
65
+ stmt = @connection.createStatement()
66
+ begin
67
+ stmt.execute(statement)
68
+ ensure
69
+ stmt.close rescue NativeException
70
+ end
71
+ else
72
+ stmt = execute(statement, *bindvars)
73
+ res = stmt.rows
74
+ stmt.finish
75
+ end
76
+ return res
77
+ rescue NativeException => error
78
+ raise DBI::DatabaseError.new(error.message)
79
+ end
80
+
81
+ def ping
82
+ return !@connection.isClosed
83
+ rescue NativeException => error
84
+ raise DBI::DatabaseError.new(error.message)
85
+ end
86
+
87
+ def commit
88
+ @connection.commit()
89
+ rescue NativeException => error
90
+ raise DBI::DatabaseError.new(error.message)
91
+ end
92
+
93
+ def rollback
94
+ @connection.rollback()
95
+ rescue NativeException => error
96
+ raise DBI::DatabaseError.new(error.message)
97
+ end
98
+
99
+ def tables
100
+ rs = @connection.getMetaData.getTables(nil, nil, nil, nil)
101
+ tables = []
102
+ while(rs.next())
103
+ tables << rs.getString(3)
104
+ end
105
+ return tables
106
+ rescue NativeException => error
107
+ raise DBI::DatabaseError.new(error.message)
108
+ end
109
+
110
+ def columns(table)
111
+ (table,schema,db) = table.split(".").reverse
112
+
113
+ metaData = @connection.getMetaData()
114
+ rs = metaData.getColumns(db, schema, table, nil)
115
+ columns = []
116
+ while(rs.next())
117
+ type_name, dbi_type = jdbc_to_dbi_sqltype(rs.getShort(5))
118
+ columns << {
119
+ "name" => rs.getString(4),
120
+ "sql_type" => type_name,
121
+ "type_name" => rs.getString(6),
122
+ "precision" => rs.getInt(7),
123
+ "scale" => rs.getInt(9),
124
+ "default" => rs.getString(13),
125
+ "nullable" => (rs.getInt(11) == 1)
126
+ }
127
+ columns[-1]["dbi_type"] = dbi_type if dbi_type
128
+ end
129
+ return columns
130
+ rescue NativeException => error
131
+ raise DBI::DatabaseError.new(error.message)
132
+ end
133
+
134
+ def [](attribute)
135
+ attribute = attribute.downcase
136
+ check_attribute(attribute)
137
+ case attribute
138
+ when "autocommit" then @connection.getAutoCommit()
139
+ when "isolation", "isolation_level" then @connection.getTransactionIsolation()
140
+ else
141
+ @attributes[attribute]
142
+ end
143
+ rescue NativeException => error
144
+ raise DBI::DatabaseError.new(error.message)
145
+ end
146
+
147
+ def []=(attribute, value)
148
+ attribute = attribute.downcase
149
+ check_attribute(attribute)
150
+ case attribute
151
+ when "autocommit" then @connection.setAutoCommit(value)
152
+ when "isolation", "isolation_level" then @connection.setTransactionIsolation(value)
153
+ else
154
+ @attributes[attribute] = value
155
+ end
156
+ rescue NativeException => error
157
+ raise DBI::DatabaseError.new(error.message)
158
+ end
159
+
160
+ def java_connection
161
+ return @connection
162
+ end
163
+
164
+ def self.from_java_connection(java_connection, type_coercion = true)
165
+ dbh = DBI::DatabaseHandle.new(Database.new(java_connection), type_coercion)
166
+ dbh.driver_name = "Jdbc"
167
+ dbh
168
+ end
169
+
170
+ private
171
+
172
+ def check_attribute(attribute)
173
+ raise DBI::NotSupportedError.new("Database attribute #{attribute} is not supported") unless (attribute == "autocommit" ||
174
+ attribute == "isolation" ||
175
+ attribute == "isolation_level" ||
176
+ @attributes.has_key?(attribute))
177
+ end
178
+
179
+ end
180
+ end # module DBI
@@ -0,0 +1,70 @@
1
+ # (C) 2009 Chad Johnson <chad.j.johnson@gmail.com>.
2
+ # (C) 2008 Ola Bini <ola.bini@gmail.com>.
3
+ # (C) 2006 Kristopher Schmidt <krisschmidt@optonline.net>.
4
+ #
5
+ # All rights reserved.
6
+ #
7
+ # Redistribution and use in source and binary forms, with or without
8
+ # modification, are permitted provided that the following conditions
9
+ # are met:
10
+ # 1. Redistributions of source code must retain the above copyright
11
+ # notice, this list of conditions and the following disclaimer.
12
+ # 2. Redistributions in binary form must reproduce the above copyright
13
+ # notice, this list of conditions and the following disclaimer in the
14
+ # documentation and/or other materials provided with the distribution.
15
+ # 3. The name of the author may not be used to endorse or promote products
16
+ # derived from this software without specific prior written permission.
17
+ #
18
+ # THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
19
+ # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
20
+ # AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
21
+ # THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22
+ # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23
+ # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
24
+ # OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25
+ # WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
26
+ # OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
27
+ # ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
+
29
+ module DBI::DBD::Jdbc
30
+ #
31
+ # Models the DBI::BaseDriver API to create DBI::DriverHandle objects.
32
+ #
33
+ class Driver < DBI::BaseDriver
34
+
35
+ def initialize
36
+ super("0.4.0")
37
+ #attributes specific to this class. All attributes in the
38
+ #connect attributes that aren't in this list will be
39
+ #applied to the database handle
40
+ @driverAttributes = [ "driver" ]
41
+ @loaded_drivers = Collections.synchronizedMap(HashMap.new)
42
+ end
43
+
44
+ def load(name)
45
+ unless @loaded_drivers.containsKey(name)
46
+ clazz = java.lang.Class.forName(name,true,JRuby.runtime.jruby_class_loader)
47
+ java.sql.DriverManager.registerDriver(clazz.newInstance)
48
+
49
+ @loaded_drivers.put(name,true)
50
+ end
51
+ end
52
+
53
+ def connect(dbname, user, auth, attr)
54
+ driverClass = attr["driver"]
55
+ raise DBI::InterfaceError.new('driver class name must be specified as "driver" in connection attributes') unless driverClass
56
+
57
+ load(driverClass)
58
+
59
+ connection = java.sql.DriverManager.getConnection("jdbc:"+dbname, user, auth)
60
+ dbh = Database.new(connection)
61
+
62
+ (attr.keys - @driverAttributes).each { |key| dbh[key] = attr[key] }
63
+
64
+ return dbh
65
+ rescue NativeException => error
66
+ raise DBI::DatabaseError.new(error.message)
67
+ end
68
+
69
+ end #Driver
70
+ end
@@ -0,0 +1,212 @@
1
+ # (C) 2009 Chad Johnson <chad.j.johnson@gmail.com>.
2
+ # (C) 2008 Ola Bini <ola.bini@gmail.com>.
3
+ # (C) 2006 Kristopher Schmidt <krisschmidt@optonline.net>.
4
+ #
5
+ # All rights reserved.
6
+ #
7
+ # Redistribution and use in source and binary forms, with or without
8
+ # modification, are permitted provided that the following conditions
9
+ # are met:
10
+ # 1. Redistributions of source code must retain the above copyright
11
+ # notice, this list of conditions and the following disclaimer.
12
+ # 2. Redistributions in binary form must reproduce the above copyright
13
+ # notice, this list of conditions and the following disclaimer in the
14
+ # documentation and/or other materials provided with the distribution.
15
+ # 3. The name of the author may not be used to endorse or promote products
16
+ # derived from this software without specific prior written permission.
17
+ #
18
+ # THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
19
+ # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
20
+ # AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
21
+ # THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22
+ # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23
+ # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
24
+ # OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25
+ # WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
26
+ # OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
27
+ # ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
+
29
+ module DBI::DBD::Jdbc
30
+ #
31
+ # Models the DBI::BaseStatement API to create DBI::StatementHandle objects.
32
+ #
33
+ class Statement < DBI::BaseStatement
34
+ include TypeConversions
35
+
36
+ def initialize(statement, nulltype, allow_scroll = false)
37
+ @statement = statement
38
+ @nulltype = nulltype
39
+ @allow_scroll = allow_scroll
40
+ @rows = nil
41
+ @data = []
42
+ end
43
+
44
+ def bind_param(param, value, attribs)
45
+ raise DBI::InterfaceError.new("Statement.bind_param only supports numeric placeholder numbers") unless param.is_a?(Fixnum)
46
+ if value.nil?
47
+ @statement.setNull(param, @nulltype)
48
+ elsif value.is_a?(String)
49
+ #
50
+ # The syntax below appears to be the best way to ensure that
51
+ # RubyStrings get converted to Java Strings correctly if it
52
+ # contains UTF-8.
53
+ #
54
+ # java.lang.String.new() will assume the system default
55
+ # encoding when converting the RubyString bytes ....
56
+ #
57
+ @statement.setString(param, java.lang.String.new(value))
58
+ elsif value.is_a?(Fixnum)
59
+ #no reason not to coerce it to a long?
60
+ @statement.setLong(param, value)
61
+ elsif value.is_a?(Float)
62
+ #despite DBD spec saying Float->SQL Float, using Double gives
63
+ #better precision and passes tests that setFloat does not.
64
+ @statement.setDouble(param, value)
65
+ elsif value.is_a?(::DateTime) || value.is_a?(DBI::Timestamp)
66
+ @statement.setTimestamp(param, timestamp_to_jdbctimestamp(value))
67
+ elsif value.is_a?(::Date) || value.is_a?(DBI::Date)
68
+ @statement.setDate(param, date_to_jdbcdate(value))
69
+ elsif value.is_a?(::Time) || value.is_a?(DBI::Time)
70
+ @statement.setTime(param, time_to_jdbctime(value))
71
+ else
72
+ @statement.setObject(param, value)
73
+ end
74
+ rescue NativeException => error
75
+ raise DBI::DatabaseError.new(error.message)
76
+ end
77
+
78
+ def execute
79
+ if @statement.execute()
80
+ @rs = @statement.getResultSet
81
+ @rows = nil
82
+ @data.clear
83
+ else
84
+ @rs = nil
85
+ @rows = @statement.getUpdateCount
86
+ end
87
+ rescue NativeException => error
88
+ raise DBI::DatabaseError.new(error.message)
89
+ end
90
+
91
+ def finish
92
+ @statement.close()
93
+ @rs = nil
94
+ @rows = nil
95
+ rescue NativeException => error
96
+ raise DBI::DatabaseError.new(error.message)
97
+ end
98
+
99
+ def fetch
100
+ if (@rs && @rs.next())
101
+ return fill_data
102
+ else
103
+ return nil
104
+ end
105
+ rescue NativeException => error
106
+ raise DBI::DatabaseError.new(error.message)
107
+ end
108
+
109
+ def fill_data
110
+ @data.clear
111
+ metaData = @rs.getMetaData()
112
+ (1..metaData.getColumnCount()).each do |columnNumber|
113
+ @data << get_value(columnNumber, @rs, metaData)
114
+ end
115
+ return @data
116
+ end
117
+
118
+ #
119
+ # Unless "allow_scroll" was set on this connection this will default to the
120
+ # DBI::BaseStatement#fetch_scroll implementation.
121
+ #
122
+ # See DBI::BaseStatement#fetch_scroll. These additional constants are supported
123
+ # when "allow_scroll" is set on the connection.
124
+ #
125
+ # * DBI::SQL_FETCH_PRIOR: Fetch the row previous to the current one.
126
+ # * DBI::SQL_FETCH_FIRST: Fetch the first row.
127
+ # * DBI::SQL_FETCH_ABSOLUTE: Fetch the row at the offset provided.
128
+ # * DBI::SQL_FETCH_RELATIVE: Fetch the row at the current point + offset.
129
+ #
130
+ def fetch_scroll(direction, offset)
131
+ return super(direction, offset) unless @allow_scroll
132
+
133
+ case direction
134
+ when DBI::SQL_FETCH_NEXT
135
+ fill_data if @rs && @rs.next()
136
+ when DBI::SQL_FETCH_PRIOR
137
+ fill_data if @rs && @rs.previous()
138
+ when DBI::SQL_FETCH_FIRST
139
+ fill_data if @rs && @rs.first()
140
+ when DBI::SQL_FETCH_LAST
141
+ fill_data if @rs && @rs.last()
142
+ when DBI::SQL_FETCH_ABSOLUTE
143
+ fill_data if @rs && @rs.absolute(offset)
144
+ when DBI::SQL_FETCH_RELATIVE
145
+ fill_data if @rs && @rs.relative(offset)
146
+ else
147
+ raise DBI::NotSupportedError
148
+ end
149
+ rescue NativeException => error
150
+ raise DBI::NotSupportedError.new(error.message)
151
+ end
152
+
153
+ def column_info
154
+ info = Array.new
155
+ return info unless @rs
156
+ metaData = @rs.getMetaData()
157
+ (1..metaData.getColumnCount()).each do |columnNumber|
158
+ type_name, dbi_type = jdbc_to_dbi_sqltype(metaData.getColumnType(columnNumber))
159
+ info << {
160
+ "name" => metaData.getColumnName(columnNumber),
161
+ "sql_type" => type_name,
162
+ "type_name" => metaData.getColumnTypeName(columnNumber),
163
+ "precision" => metaData.getPrecision(columnNumber),
164
+ "scale" => metaData.getScale(columnNumber),
165
+ "nullable" => (metaData.isNullable(columnNumber) == 1)
166
+ }
167
+ info[-1]["dbi_type"] = dbi_type if dbi_type
168
+ end
169
+ return info
170
+ rescue NativeException => error
171
+ raise DBI::DatabaseError.new(error.message)
172
+ end
173
+
174
+ def rows
175
+ return @rows
176
+ end
177
+
178
+ def self.from_java_statement(java_statement, type_coercion = false, null_type = java.sql.Types::VARCHAR)
179
+ raise DBI::DatabaseError.new("Only java.sql.PreparedStatement instances accepted") unless java_statement.kind_of?(java.sql.PreparedStatement)
180
+
181
+ DBI::StatementHandle.new(Statement.new(java_statement, null_type), true, true, type_coercion)
182
+ end
183
+
184
+ private
185
+
186
+ def get_value(columnNumber, rs, metaData)
187
+ #note only map things that seem unlikely to coerce properly to jruby,
188
+ #since anything mapped as primitive type cannot be returned as null
189
+ return case metaData.getColumnType(columnNumber)
190
+ when java.sql.Types::BIT
191
+ rs.getBoolean(columnNumber)
192
+ when java.sql.Types::NUMERIC, java.sql.Types::DECIMAL
193
+ # TODO: Find a better way to return Numerics and Decimals as nil when they are null in the DB
194
+ if rs.getObject(columnNumber)
195
+ metaData.getScale(columnNumber) == 0 ? rs.getLong(columnNumber) : rs.getDouble(columnNumber)
196
+ else
197
+ nil
198
+ end
199
+ when java.sql.Types::DATE
200
+ jdbcdate_to_date(rs.getDate(columnNumber))
201
+ when java.sql.Types::TIME
202
+ jdbctime_to_time(rs.getTime(columnNumber))
203
+ when java.sql.Types::TIMESTAMP
204
+ jdbctimestamp_to_timestamp(rs.getTimestamp(columnNumber))
205
+ else
206
+ rs.getObject(columnNumber)
207
+ end
208
+ end
209
+
210
+ end # class Statement
211
+
212
+ end # module Jdbc
@@ -0,0 +1,123 @@
1
+ # (C) 2009 Chad Johnson <chad.j.johnson@gmail.com>.
2
+ # (C) 2008 Ola Bini <ola.bini@gmail.com>.
3
+ # (C) 2006 Kristopher Schmidt <krisschmidt@optonline.net>.
4
+ #
5
+ # All rights reserved.
6
+ #
7
+ # Redistribution and use in source and binary forms, with or without
8
+ # modification, are permitted provided that the following conditions
9
+ # are met:
10
+ # 1. Redistributions of source code must retain the above copyright
11
+ # notice, this list of conditions and the following disclaimer.
12
+ # 2. Redistributions in binary form must reproduce the above copyright
13
+ # notice, this list of conditions and the following disclaimer in the
14
+ # documentation and/or other materials provided with the distribution.
15
+ # 3. The name of the author may not be used to endorse or promote products
16
+ # derived from this software without specific prior written permission.
17
+ #
18
+ # THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
19
+ # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
20
+ # AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
21
+ # THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22
+ # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23
+ # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
24
+ # OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25
+ # WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
26
+ # OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
27
+ # ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
+
29
+ module DBI::DBD::Jdbc::TypeConversions
30
+ java_import 'java.util.Calendar'
31
+ java_import 'java.sql.Types'
32
+
33
+ def jdbc_to_dbi_sqltype(jdbctype)
34
+ return case jdbctype
35
+ when Types::BIGINT then [DBI::SQL_BIGINT, nil]
36
+ when Types::BINARY then [DBI::SQL_BINARY, nil]
37
+ when Types::BIT then [DBI::SQL_BIT, DBI::Type::Boolean]
38
+ when Types::CHAR then [DBI::SQL_CHAR, nil]
39
+ when Types::DATE then [DBI::SQL_DATE, DBI::DBD::Jdbc::Type::Timestamp]
40
+ when Types::DECIMAL then [DBI::SQL_DECIMAL, nil]
41
+ when Types::DOUBLE then [DBI::SQL_DOUBLE, nil]
42
+ when Types::FLOAT then [DBI::SQL_FLOAT, nil]
43
+ when Types::INTEGER then [DBI::SQL_INTEGER, nil]
44
+ when Types::LONGVARBINARY then [DBI::SQL_LONGVARBINARY, nil]
45
+ when Types::LONGVARCHAR then [DBI::SQL_LONGVARCHAR, nil]
46
+ when Types::NUMERIC then [DBI::SQL_NUMERIC, nil]
47
+ when Types::REAL then [DBI::SQL_REAL, nil]
48
+ when Types::SMALLINT then [DBI::SQL_SMALLINT, nil]
49
+ when Types::TIME then [DBI::SQL_TIME, DBI::DBD::Jdbc::Type::Timestamp]
50
+ when Types::TIMESTAMP then [DBI::SQL_TIMESTAMP, DBI::DBD::Jdbc::Type::Timestamp]
51
+ when Types::TINYINT then [DBI::SQL_TINYINT, nil]
52
+ when Types::VARBINARY then [DBI::SQL_VARBINARY, nil]
53
+ when Types::VARCHAR then [DBI::SQL_VARCHAR, nil]
54
+ else
55
+ [DBI::SQL_OTHER, nil]
56
+ end
57
+ end
58
+
59
+ def date_to_jdbcdate(dbidate)
60
+ cal = Calendar.getInstance()
61
+ set_calendar_date_fields(dbidate, cal)
62
+ return java.sql.Date.new(cal.getTime().getTime())
63
+ end
64
+
65
+ def time_to_jdbctime(dbitime)
66
+ cal = Calendar.getInstance()
67
+ set_calendar_date_fields(dbitime, cal)
68
+ set_calendar_time_fields(dbitime, cal)
69
+ return java.sql.Time.new(cal.getTime().getTime())
70
+ end
71
+
72
+ def timestamp_to_jdbctimestamp(dbitimestamp)
73
+ cal = Calendar.getInstance()
74
+ set_calendar_date_fields(dbitimestamp, cal)
75
+ set_calendar_time_fields(dbitimestamp, cal)
76
+ return java.sql.Timestamp.new(cal.getTime().getTime())
77
+ end
78
+
79
+ def jdbcdate_to_date(jdbcdate)
80
+ return nil if jdbcdate.nil?
81
+ cal = get_calendar(jdbcdate)
82
+ return ::Date.new(cal.get(Calendar::YEAR), cal.get(Calendar::MONTH)+1, cal.get(Calendar::DAY_OF_MONTH))
83
+ end
84
+
85
+ def jdbctime_to_time(jdbctime)
86
+ return nil if jdbctime.nil?
87
+ cal = get_calendar(jdbctime)
88
+ return ::Time.mktime(cal.get(Calendar::YEAR), cal.get(Calendar::MONTH)+1, cal.get(Calendar::DAY_OF_MONTH), cal.get(Calendar::HOUR_OF_DAY), cal.get(Calendar::MINUTE), cal.get(Calendar::SECOND), cal.get(Calendar::MILLISECOND) * 1000)
89
+ end
90
+
91
+ def jdbctimestamp_to_timestamp(jdbctimestamp)
92
+ return nil if jdbctimestamp.nil?
93
+ cal = get_calendar(jdbctimestamp)
94
+ return ::DateTime.new(cal.get(Calendar::YEAR), cal.get(Calendar::MONTH)+1, cal.get(Calendar::DAY_OF_MONTH), cal.get(Calendar::HOUR_OF_DAY), cal.get(Calendar::MINUTE), cal.get(Calendar::SECOND))
95
+ end
96
+
97
+ private
98
+
99
+ def set_calendar_date_fields(dbidate, cal)
100
+ cal.set(Calendar::YEAR, dbidate.year) if dbidate.respond_to? :year
101
+ cal.set(Calendar::MONTH, dbidate.month-1) if dbidate.respond_to? :month
102
+ cal.set(Calendar::DAY_OF_MONTH, dbidate.day) if dbidate.respond_to? :day
103
+ end
104
+
105
+ def set_calendar_time_fields(dbitime, cal)
106
+ cal.set(Calendar::HOUR_OF_DAY, dbitime.hour)
107
+ cal.set(Calendar::MINUTE, dbitime.min)
108
+ cal.set(Calendar::SECOND, dbitime.sec)
109
+
110
+ if dbitime.respond_to? :strftime
111
+ cal.set(Calendar::MILLISECOND, dbitime.strftime('%L').to_i)
112
+ else
113
+ cal.set(Calendar::MILLISECOND, 0)
114
+ end
115
+ end
116
+
117
+ def get_calendar(jdbctype)
118
+ cal = Calendar.getInstance()
119
+ cal.setTime(java.util.Date.new(jdbctype.getTime()))
120
+ return cal
121
+ end
122
+
123
+ end
@@ -0,0 +1,7 @@
1
+ module DBI
2
+ module DBD
3
+ module Jdbc
4
+ VERSION = "0.1.6"
5
+ end
6
+ end
7
+ end
metadata ADDED
@@ -0,0 +1,84 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: dbd-jdbc
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.6
5
+ prerelease:
6
+ platform: java
7
+ authors:
8
+ - Chad Johnson
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-01-11 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rake
16
+ version_requirements: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - ! '>='
19
+ - !ruby/object:Gem::Version
20
+ version: !binary |-
21
+ MA==
22
+ none: false
23
+ requirement: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ! '>='
26
+ - !ruby/object:Gem::Version
27
+ version: !binary |-
28
+ MA==
29
+ none: false
30
+ prerelease: false
31
+ type: :development
32
+ description: A JDBC DBD driver for Ruby DBI
33
+ email:
34
+ - chad.j.johnson@gmail.com
35
+ executables: []
36
+ extensions: []
37
+ extra_rdoc_files: []
38
+ files:
39
+ - .gitignore
40
+ - Gemfile
41
+ - LICENSE
42
+ - README.txt
43
+ - Rakefile
44
+ - dbd-jdbc.gemspec
45
+ - lib/dbd/Jdbc.rb
46
+ - lib/dbd/jdbc/database.rb
47
+ - lib/dbd/jdbc/driver.rb
48
+ - lib/dbd/jdbc/statement.rb
49
+ - lib/dbd/jdbc/type_conversion.rb
50
+ - lib/dbd/jdbc/version.rb
51
+ homepage: http://github.com/chadj/dbd-jdbc
52
+ licenses: []
53
+ post_install_message:
54
+ rdoc_options: []
55
+ require_paths:
56
+ - lib
57
+ required_ruby_version: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ segments:
62
+ - 0
63
+ version: !binary |-
64
+ MA==
65
+ hash: 2
66
+ none: false
67
+ required_rubygems_version: !ruby/object:Gem::Requirement
68
+ requirements:
69
+ - - ! '>='
70
+ - !ruby/object:Gem::Version
71
+ segments:
72
+ - 0
73
+ version: !binary |-
74
+ MA==
75
+ hash: 2
76
+ none: false
77
+ requirements:
78
+ - dbi or ruby-dbi gem
79
+ rubyforge_project: jruby-extras
80
+ rubygems_version: 1.8.24
81
+ signing_key:
82
+ specification_version: 3
83
+ summary: JDBC driver for DBI, originally by Kristopher Schmidt and Ola Bini
84
+ test_files: []