ydbi 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (122) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +6 -0
  3. data/ChangeLog +3699 -0
  4. data/Gemfile +4 -0
  5. data/LICENSE +25 -0
  6. data/Rakefile +8 -0
  7. data/TODO +44 -0
  8. data/bench/bench.rb +79 -0
  9. data/bin/dbi +518 -0
  10. data/bin/test_broken_dbi +37 -0
  11. data/build/Rakefile.dbi.rb +60 -0
  12. data/build/rake_task_lib.rb +187 -0
  13. data/doc/DBD_SPEC.rdoc +88 -0
  14. data/doc/DBI_SPEC.rdoc +157 -0
  15. data/doc/homepage/contact.html +62 -0
  16. data/doc/homepage/development.html +124 -0
  17. data/doc/homepage/index.html +83 -0
  18. data/doc/homepage/ruby-dbi.css +91 -0
  19. data/examples/test1.pl +39 -0
  20. data/examples/test1.rb +20 -0
  21. data/examples/xmltest.rb +8 -0
  22. data/lib/dbd/Mysql.rb +137 -0
  23. data/lib/dbd/ODBC.rb +89 -0
  24. data/lib/dbd/Pg.rb +188 -0
  25. data/lib/dbd/SQLite.rb +97 -0
  26. data/lib/dbd/SQLite3.rb +124 -0
  27. data/lib/dbd/mysql/database.rb +405 -0
  28. data/lib/dbd/mysql/driver.rb +125 -0
  29. data/lib/dbd/mysql/statement.rb +188 -0
  30. data/lib/dbd/odbc/database.rb +128 -0
  31. data/lib/dbd/odbc/driver.rb +38 -0
  32. data/lib/dbd/odbc/statement.rb +137 -0
  33. data/lib/dbd/pg/database.rb +516 -0
  34. data/lib/dbd/pg/exec.rb +47 -0
  35. data/lib/dbd/pg/statement.rb +160 -0
  36. data/lib/dbd/pg/tuples.rb +121 -0
  37. data/lib/dbd/pg/type.rb +209 -0
  38. data/lib/dbd/sqlite/database.rb +151 -0
  39. data/lib/dbd/sqlite/statement.rb +125 -0
  40. data/lib/dbd/sqlite3/database.rb +201 -0
  41. data/lib/dbd/sqlite3/statement.rb +78 -0
  42. data/lib/dbi.rb +336 -0
  43. data/lib/dbi/base_classes.rb +12 -0
  44. data/lib/dbi/base_classes/database.rb +135 -0
  45. data/lib/dbi/base_classes/driver.rb +47 -0
  46. data/lib/dbi/base_classes/statement.rb +171 -0
  47. data/lib/dbi/binary.rb +25 -0
  48. data/lib/dbi/columninfo.rb +107 -0
  49. data/lib/dbi/exceptions.rb +65 -0
  50. data/lib/dbi/handles.rb +49 -0
  51. data/lib/dbi/handles/database.rb +241 -0
  52. data/lib/dbi/handles/driver.rb +60 -0
  53. data/lib/dbi/handles/statement.rb +408 -0
  54. data/lib/dbi/row.rb +269 -0
  55. data/lib/dbi/sql.rb +22 -0
  56. data/lib/dbi/sql/preparedstatement.rb +115 -0
  57. data/lib/dbi/sql_type_constants.rb +75 -0
  58. data/lib/dbi/trace.rb +91 -0
  59. data/lib/dbi/types.rb +218 -0
  60. data/lib/dbi/typeutil.rb +109 -0
  61. data/lib/dbi/utils.rb +60 -0
  62. data/lib/dbi/utils/date.rb +59 -0
  63. data/lib/dbi/utils/tableformatter.rb +112 -0
  64. data/lib/dbi/utils/time.rb +52 -0
  65. data/lib/dbi/utils/timestamp.rb +96 -0
  66. data/lib/dbi/utils/xmlformatter.rb +73 -0
  67. data/lib/dbi/version.rb +3 -0
  68. data/prototypes/types2.rb +237 -0
  69. data/readme.md +274 -0
  70. data/setup.rb +1585 -0
  71. data/test/DBD_TESTS +50 -0
  72. data/test/TESTING +16 -0
  73. data/test/dbd/general/test_database.rb +206 -0
  74. data/test/dbd/general/test_statement.rb +326 -0
  75. data/test/dbd/general/test_types.rb +296 -0
  76. data/test/dbd/mysql/base.rb +26 -0
  77. data/test/dbd/mysql/down.sql +19 -0
  78. data/test/dbd/mysql/test_blob.rb +18 -0
  79. data/test/dbd/mysql/test_new_methods.rb +7 -0
  80. data/test/dbd/mysql/test_patches.rb +111 -0
  81. data/test/dbd/mysql/up.sql +28 -0
  82. data/test/dbd/odbc/base.rb +30 -0
  83. data/test/dbd/odbc/down.sql +19 -0
  84. data/test/dbd/odbc/test_new_methods.rb +12 -0
  85. data/test/dbd/odbc/test_ping.rb +10 -0
  86. data/test/dbd/odbc/test_statement.rb +44 -0
  87. data/test/dbd/odbc/test_transactions.rb +58 -0
  88. data/test/dbd/odbc/up.sql +33 -0
  89. data/test/dbd/postgresql/base.rb +31 -0
  90. data/test/dbd/postgresql/down.sql +31 -0
  91. data/test/dbd/postgresql/test_arrays.rb +179 -0
  92. data/test/dbd/postgresql/test_async.rb +121 -0
  93. data/test/dbd/postgresql/test_blob.rb +36 -0
  94. data/test/dbd/postgresql/test_bytea.rb +87 -0
  95. data/test/dbd/postgresql/test_ping.rb +10 -0
  96. data/test/dbd/postgresql/test_timestamp.rb +77 -0
  97. data/test/dbd/postgresql/test_transactions.rb +58 -0
  98. data/test/dbd/postgresql/testdbipg.rb +307 -0
  99. data/test/dbd/postgresql/up.sql +60 -0
  100. data/test/dbd/sqlite/base.rb +32 -0
  101. data/test/dbd/sqlite/test_database.rb +30 -0
  102. data/test/dbd/sqlite/test_driver.rb +68 -0
  103. data/test/dbd/sqlite/test_statement.rb +112 -0
  104. data/test/dbd/sqlite/up.sql +25 -0
  105. data/test/dbd/sqlite3/base.rb +32 -0
  106. data/test/dbd/sqlite3/test_database.rb +77 -0
  107. data/test/dbd/sqlite3/test_driver.rb +67 -0
  108. data/test/dbd/sqlite3/test_statement.rb +88 -0
  109. data/test/dbd/sqlite3/up.sql +33 -0
  110. data/test/dbi/tc_columninfo.rb +94 -0
  111. data/test/dbi/tc_date.rb +88 -0
  112. data/test/dbi/tc_dbi.rb +184 -0
  113. data/test/dbi/tc_row.rb +256 -0
  114. data/test/dbi/tc_sqlbind.rb +168 -0
  115. data/test/dbi/tc_statementhandle.rb +29 -0
  116. data/test/dbi/tc_time.rb +77 -0
  117. data/test/dbi/tc_timestamp.rb +142 -0
  118. data/test/dbi/tc_types.rb +268 -0
  119. data/test/ts_dbd.rb +131 -0
  120. data/test/ts_dbi.rb +16 -0
  121. data/ydbi.gemspec +24 -0
  122. metadata +224 -0
@@ -0,0 +1,91 @@
1
+ # $Id: trace.rb,v 1.1 2006/01/04 02:03:22 francis Exp $
2
+ #
3
+ # Tracing for DBI programs
4
+ #
5
+ # Copyright (c) 2001 Michael Neumann
6
+ #
7
+ # This program is free software; you can redistribute it and/or
8
+ # modify it under the terms of the GNU General Public License
9
+ # as published by the Free Software Foundation; either version 2
10
+ # of the License, or (at your option) any later version.
11
+ #
12
+ # This program is distributed in the hope that it will be useful,
13
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
+ # GNU General Public License for more details.
16
+ #
17
+ # You should have received a copy of the GNU General Public License
18
+ # along with this program; if not, write to the Free Software
19
+ # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20
+
21
+ raise LoadError, "the trace module has been removed until it actually works."
22
+
23
+ # works only correct with the newest version > 0.3.3
24
+ require "aspectr"
25
+ require "dbi" # to work as "ruby -r dbi/trace myapp.rb"
26
+
27
+ module DBI
28
+
29
+ class HandleTracer < AspectR::Aspect
30
+
31
+ def initialize(klass)
32
+ @never_wrap = /^__|^send$|^id$|^class$|^$ /
33
+ self.wrap(klass, :pre, :post, methods(klass))
34
+ end
35
+
36
+ # trace methods --------------------------------------------------------------
37
+
38
+ def pre(method, object, exitstatus, *args)
39
+
40
+ par = args.collect{|a| a.inspect}.join(", ")
41
+
42
+ if object.trace_mode == 2 then
43
+ object.trace_output << "-> #{method} for #{object} (#{par})\n"
44
+ elsif object.trace_mode == 3 then
45
+ object.trace_output << "-> #{method} for #{object.inspect} (#{par})\n"
46
+ end
47
+ end
48
+
49
+ def post(method, object, exitstatus, *args)
50
+
51
+ case object.trace_mode
52
+ when 1, 2 # return values and errors
53
+ arrow = object.trace_mode == 1 ? "<=" : "<-"
54
+ if exitstatus.kind_of? Array
55
+ object.trace_output << "#{arrow} #{method} for #{object} = #{exitstatus[0] || 'nil'}\n"
56
+ else
57
+ if exitstatus == true
58
+ object.trace_output << "!! #{$!.message.chomp}\n"
59
+ end
60
+ object.trace_output << "#{arrow} #{method} for #{object}\n"
61
+ end
62
+
63
+ when 3
64
+ if exitstatus.kind_of? Array
65
+ object.trace_output << "<- #{method} for #{object.inspect} = #{exitstatus[0].inspect}\n"
66
+ else
67
+ if exitstatus == true
68
+ object.trace_output << "!! #{$!.inspect}\n"
69
+ end
70
+ object.trace_output << "<- #{method} for #{object.inspect}\n"
71
+ end
72
+ end
73
+
74
+ end
75
+
76
+ private # helper methods -----------------------------------------------------
77
+
78
+ def methods(klass)
79
+ meths = (DBI::Handle.instance_methods | klass.instance_methods) - %w(trace_mode trace_output trace)
80
+ /(#{meths.collect{|m| Regexp.quote(m)}.join('|')})/
81
+ end
82
+
83
+ end
84
+
85
+ @@tracer_driver = HandleTracer.new(DBI::DriverHandle)
86
+ @@tracer_database = HandleTracer.new(DBI::DatabaseHandle)
87
+ @@tracer_statement = HandleTracer.new(DBI::StatementHandle)
88
+
89
+
90
+ end # module DBI
91
+
@@ -0,0 +1,218 @@
1
+ require 'time'
2
+ require 'bigdecimal'
3
+ require 'rational'
4
+
5
+ module DBI
6
+ #
7
+ # Interface to convert SQL result sets to native Ruby types.
8
+ #
9
+ # Type is used to convert result sets, which differ from bound variables
10
+ # (which generally go in the opposite direction). For those, see
11
+ # DBI::TypeUtil#convert and DBI::TypeUtil#register_conversion.
12
+ #
13
+ # Type objects have a simple interface: they implement a +parse+ method
14
+ # which takes the result from the DBD and attempts to convert it to the
15
+ # native type. In the event that they do not do this successfully, they are
16
+ # expected to return the object in its original form.
17
+ #
18
+ # As a result, many of the built-in Type classes fallback to simpler forms:
19
+ # Float falls back to Integer, Integer to Varchar, etc. It's questionable
20
+ # at this point if it's desirable to do this, but testing has so far proven
21
+ # it a non-issue.
22
+ #
23
+ # To reiterate, it is *never acceptable* to return +nil+ or some other
24
+ # placeholder when an object will not successfully parse. Return the object
25
+ # handed to you.
26
+ #
27
+ # Types must also handle +nil+ as a result to parse. In this case, the
28
+ # advisable solution is to just let the +nil+ pass through, as it's usually
29
+ # indicative of a SQL NULL result.
30
+ #
31
+ # DBI::Row handles delegation of these objects as a converter for the
32
+ # results. Typically, the type object is a class inferred from
33
+ # DBI::TypeUtil#type_name_to_module ran against the ColumnInfo field
34
+ # +type_name+. However, the the +dbi_type+ field can be used in its place
35
+ # to directly associate a Type object with the column in the DBD, and
36
+ # end-users can leverage StatementHandle#bind_coltype to manually tweak
37
+ # this transformation.
38
+ #
39
+ # As stated before, Type objects are objects. These objects may be Modules
40
+ # or Classes (and typically are), but there is no reason a traditional
41
+ # constructed object with a +parse+ method cannot be returned; in fact, it
42
+ # is used in a few spots to emulate complex types such as PostgreSQL
43
+ # arrays. Look into the +dbi_type+ ColumnInfo field to pass these types
44
+ # around.
45
+ #
46
+ module Type
47
+ #
48
+ # Represents a SQL NULL.
49
+ #
50
+ class Null
51
+ def self.parse(obj)
52
+ return nil if obj.to_s.match(/^null$/i)
53
+ return obj
54
+ end
55
+ end
56
+
57
+ #
58
+ # Represents a SQL char or varchar. General fallback class.
59
+ #
60
+ class Varchar
61
+ def self.parse(obj)
62
+ return obj unless obj
63
+ return obj.to_s if obj.respond_to? :to_s
64
+ return obj.to_str if obj.respond_to? :to_str
65
+ return obj
66
+ end
67
+ end
68
+
69
+ #
70
+ # Represents a whole number. Falls back to Varchar.
71
+ #
72
+ class Integer < Varchar
73
+ def self.parse(obj)
74
+ return nil if Null.parse(obj).nil?
75
+ return obj.to_i if obj.respond_to? :to_i
76
+ super
77
+ end
78
+ end
79
+
80
+ #
81
+ # Represents a decimal number with floating-point precision. Falls back
82
+ # to Integer.
83
+ #
84
+ class Float < Integer
85
+ def self.parse(obj)
86
+ return nil if Null.parse(obj).nil?
87
+ return obj.to_f if obj.respond_to? :to_f
88
+ super
89
+ end
90
+ end
91
+
92
+ #
93
+ # Represents a Decimal with real precision (BigDecimal). Falls back to
94
+ # Float.
95
+ #
96
+ class Decimal < Float
97
+ def self.parse(obj)
98
+ BigDecimal.new(obj) rescue super
99
+ end
100
+ end
101
+
102
+ #
103
+ # Represents a SQL TIMESTAMP and returns DateTime. Falls back to Null.
104
+ #
105
+ class Timestamp < Null
106
+ def self.create(year, month, day, hour, min, sec, usec=0, of=0)
107
+ # DateTime will remove leap and leap-leap seconds
108
+ sec = 59 if sec > 59
109
+ # store this before we modify it
110
+ civil = year, month, day
111
+ time = hour, min, sec, usec
112
+
113
+ date = ::DateTime.civil(year, month, day, hour, min, sec, of)
114
+ date += usec
115
+ #prefill_cache date, civil, time
116
+ date
117
+ end
118
+
119
+ # FIXME these methods are broken, I don't know why, and I don't really care right now.
120
+ # we shouldn't be playing in datetime's garden anyways.
121
+ if RUBY_VERSION =~ /^1\.8\./
122
+ def self.prefill_cache date, civil, time
123
+ time[3] /= 86400000000.0
124
+ date.instance_variable_set :"@__#{:civil.to_i}__", [civil]
125
+ date.instance_variable_set :"@__#{:time.to_i}__", [time]
126
+ end
127
+ else
128
+ def self.prefill_cache date, civil, time
129
+ time[3] /= 1000000.0
130
+ date.instance_variable_get(:@__ca__)[:civil.object_id] = civil
131
+ date.instance_variable_get(:@__ca__)[:time.object_id] = time
132
+ end
133
+ end
134
+
135
+ def self.parse_string str
136
+ # special casing the common formats here gives roughly an
137
+ # 8-fold speed boost over using Date._parse
138
+ case str
139
+ when /^(\d{4})-(\d{2})-(\d{2})(?: (\d{2}):(\d{2}):(\d{2})(\.\d+)?)?(?: ([+-]?\d{2}):?(\d{2}))?$/
140
+ parts = $~[1..-4].map { |s| s.to_i }
141
+ # i feel unclean. if we have fractional seconds, pad the number and then stuff it into a rational.
142
+ if $7
143
+ frac = $7.to_f * 10000000
144
+ parts << Rational(frac.to_i, 864000000000)
145
+ else
146
+ parts << 0
147
+ end
148
+ parts << Rational(($8 || 0).to_i * 60 + ($9 || 0).to_i, 1440)
149
+ else
150
+ parts = ::Date._parse(str).values_at(:year, :mon, :mday, :hour, :min, :sec, :sec_fraction, :offset)
151
+ # some defaults
152
+ today = nil
153
+ 8.times do |i|
154
+ next if parts[i]
155
+ today ||= ::Time.now.to_a.values_at(5, 4, 3) + [0, 0, 0, 0, 0]
156
+ parts[i] = today[i]
157
+ end
158
+ parts[6] = parts[6].kind_of?(Rational) ? parts[6] : Rational(parts[6], 1)
159
+ parts[6] *= Rational(1, 86400)
160
+ parts[7] = Rational(parts[7], 86400)
161
+ end
162
+ parts
163
+ end
164
+
165
+ def self.parse(obj)
166
+ case obj
167
+ when ::DateTime
168
+ return obj
169
+ when ::Date
170
+ return create(obj.year, obj.month, obj.day, 0, 0, 0)
171
+ when ::Time
172
+ return create(obj.year, obj.month, obj.day, obj.hour, obj.min, obj.sec, Rational(obj.usec, 86400000000), Rational(obj.utc_offset, 86400))
173
+ else
174
+ obj = super
175
+ return obj unless obj
176
+ return create(*parse_string(obj.to_s)) if obj.respond_to? :to_s
177
+ return create(*parse_string(obj.to_str)) if obj.respond_to? :to_str
178
+ return obj
179
+ end
180
+ end
181
+ end
182
+
183
+ #
184
+ # Represents a SQL BOOLEAN. Returns true/false. Falls back to Null.
185
+ #
186
+ class Boolean < Null
187
+ def self.parse(obj)
188
+ obj = super
189
+
190
+ return nil if obj.nil?
191
+
192
+ if obj == false or obj.kind_of? FalseClass
193
+ return false
194
+ elsif obj.kind_of? TrueClass
195
+ return true
196
+ else
197
+ case obj
198
+ when 't'
199
+ return true
200
+ when 'f'
201
+ return false
202
+ end
203
+
204
+ if obj.respond_to? :to_i
205
+ if obj.to_i == 0
206
+ return false
207
+ else
208
+ return true
209
+ end
210
+ else
211
+ # punt
212
+ return nil
213
+ end
214
+ end
215
+ end
216
+ end
217
+ end
218
+ end
@@ -0,0 +1,109 @@
1
+ module DBI
2
+ #
3
+ # TypeUtil is a series of utility methods for type management.
4
+ #
5
+ class TypeUtil
6
+ @@conversions = { }
7
+
8
+ #
9
+ # Register a conversion for a DBD. This applies to bound parameters for
10
+ # outgoing statements; please look at DBI::Type for result sets.
11
+ #
12
+ # Conversions are given a driver_name, which is then used to look up
13
+ # the conversion to perform on the object. Please see #convert for more
14
+ # information. Driver names are typically provided by the DBD, but may
15
+ # be overridden at any stage temporarily by assigning to the
16
+ # +driver_name+ attribute for the various handles.
17
+ #
18
+ # A conversion block is normally a +case+ statement that identifies
19
+ # various native ruby types and converts them to string, but ultimately
20
+ # the result type is dependent on low-level driver. The resulting
21
+ # object will be fed to the query as the bound value.
22
+ #
23
+ # The result of the block is two arguments, the first being the result
24
+ # object, and the second being a +cascade+ flag, which if true
25
+ # instructs #convert to run the result through the +default+ conversion
26
+ # as well and use its result. This is advantageous when you just need
27
+ # to convert everything to string, and allow +default+ to properly escape
28
+ # it.
29
+ #
30
+ def self.register_conversion(driver_name, &block)
31
+ raise "Must provide a block" unless block_given?
32
+ @@conversions[driver_name] = block
33
+ end
34
+
35
+ #
36
+ # Convert object for +driver_name+. See #register_conversion for a
37
+ # complete explanation of how type conversion is performed.
38
+ #
39
+ # If the conversion is instructed to cascade, it will go to the special
40
+ # "default" conversion, which is a pre-defined common case (and
41
+ # mutable) ruleset for native types. Note that it will use the result
42
+ # from the first conversion, not what was originally passed. Be sure to
43
+ # leave the object untouched if that is your intent. E.g., if your DBD
44
+ # converts an Integer to String and tells it to cascade, the "default"
45
+ # conversion will get a String and quote it, not an Integer (which has
46
+ # different rules).
47
+ #
48
+ def self.convert(driver_name, obj)
49
+ if @@conversions[driver_name]
50
+ newobj, cascade = @@conversions[driver_name].call(obj)
51
+ if cascade
52
+ return @@conversions["default"].call(newobj)
53
+ end
54
+ return newobj
55
+ end
56
+
57
+ return @@conversions["default"].call(obj)
58
+ end
59
+
60
+ #
61
+ # Convenience method to match many SQL named types to DBI::Type classes. If
62
+ # none can be matched, returns DBI::Type::Varchar.
63
+ #
64
+ def self.type_name_to_module(type_name)
65
+ case type_name
66
+ when /^int(?:\d+|eger)?$/i
67
+ DBI::Type::Integer
68
+ when /^varchar$/i, /^character varying$/i
69
+ DBI::Type::Varchar
70
+ when /^(?:float|real)$/i
71
+ DBI::Type::Float
72
+ when /^bool(?:ean)?$/i, /^tinyint$/i
73
+ DBI::Type::Boolean
74
+ when /^time(?:stamp(?:tz)?)?$/i
75
+ DBI::Type::Timestamp
76
+ when /^(?:decimal|numeric|double)$/i
77
+ DBI::Type::Decimal
78
+ else
79
+ DBI::Type::Varchar
80
+ end
81
+ end
82
+ end
83
+ end
84
+
85
+ DBI::TypeUtil.register_conversion("default") do |obj|
86
+ case obj
87
+ when DBI::Binary # these need to be handled specially by the driver
88
+ obj
89
+ when ::NilClass
90
+ nil
91
+ when ::TrueClass
92
+ "'1'"
93
+ when ::FalseClass
94
+ "'0'"
95
+ when ::Time, ::Date, ::DateTime
96
+ "'#{::DateTime.parse(obj.to_s).strftime("%Y-%m-%dT%H:%M:%S")}'"
97
+ when ::String, ::Symbol
98
+ obj = obj.to_s
99
+ obj = obj.gsub(/\\/) { "\\\\" }
100
+ obj = obj.gsub(/'/) { "''" }
101
+ "'#{obj}'"
102
+ when ::BigDecimal
103
+ obj.to_s("F")
104
+ when ::Numeric
105
+ obj.to_s
106
+ else
107
+ "'#{obj.to_s}'"
108
+ end
109
+ end
@@ -0,0 +1,60 @@
1
+ #
2
+ # $Id: utils.rb,v 1.5 2006/01/29 06:14:19 djberg96 Exp $
3
+ #
4
+
5
+ module DBI
6
+ #
7
+ # Utility classes and methods for use by both DBDs and consumers.
8
+ #
9
+ module Utils
10
+ #
11
+ # Given a block, returns the execution time for the block.
12
+ #
13
+ def self.measure
14
+ start = ::Time.now
15
+ yield
16
+ ::Time.now - start
17
+ end
18
+
19
+ #
20
+ # parse a string of the form "database=xxx;key=val;..."
21
+ # or database:host and return hash of key/value pairs
22
+ #
23
+ # Used in DBI.connect and offspring.
24
+ #
25
+ def self.parse_params(str)
26
+ # improved by John Gorman <jgorman@webbysoft.com>
27
+ params = str.split(";")
28
+ hash = {}
29
+ params.each do |param|
30
+ key, val = param.split("=")
31
+ hash[key] = val if key and val
32
+ end
33
+ if hash.empty?
34
+ database, host = str.split(":")
35
+ hash['database'] = database if database
36
+ hash['host'] = host if host
37
+ end
38
+ hash
39
+ end
40
+ end # module Utils
41
+ end # module DBI
42
+
43
+ #
44
+ # Type converter.
45
+ #
46
+ # FIXME this really needs to go into DBI::TypeUtil or similar
47
+ module DBI::Utils::ConvParam
48
+ #
49
+ # Wrapper to convert arrays of bound objects via DBI::TypeUtil#convert.
50
+ #
51
+ def self.conv_param(driver_name, *params)
52
+ params.collect { |param| DBI::TypeUtil.convert(driver_name, param) }
53
+ end
54
+ end
55
+
56
+ require 'dbi/utils/date'
57
+ require 'dbi/utils/time'
58
+ require 'dbi/utils/timestamp'
59
+ require 'dbi/utils/xmlformatter'
60
+ require 'dbi/utils/tableformatter'