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.
- checksums.yaml +7 -0
- data/.gitignore +6 -0
- data/ChangeLog +3699 -0
- data/Gemfile +4 -0
- data/LICENSE +25 -0
- data/Rakefile +8 -0
- data/TODO +44 -0
- data/bench/bench.rb +79 -0
- data/bin/dbi +518 -0
- data/bin/test_broken_dbi +37 -0
- data/build/Rakefile.dbi.rb +60 -0
- data/build/rake_task_lib.rb +187 -0
- data/doc/DBD_SPEC.rdoc +88 -0
- data/doc/DBI_SPEC.rdoc +157 -0
- data/doc/homepage/contact.html +62 -0
- data/doc/homepage/development.html +124 -0
- data/doc/homepage/index.html +83 -0
- data/doc/homepage/ruby-dbi.css +91 -0
- data/examples/test1.pl +39 -0
- data/examples/test1.rb +20 -0
- data/examples/xmltest.rb +8 -0
- data/lib/dbd/Mysql.rb +137 -0
- data/lib/dbd/ODBC.rb +89 -0
- data/lib/dbd/Pg.rb +188 -0
- data/lib/dbd/SQLite.rb +97 -0
- data/lib/dbd/SQLite3.rb +124 -0
- data/lib/dbd/mysql/database.rb +405 -0
- data/lib/dbd/mysql/driver.rb +125 -0
- data/lib/dbd/mysql/statement.rb +188 -0
- data/lib/dbd/odbc/database.rb +128 -0
- data/lib/dbd/odbc/driver.rb +38 -0
- data/lib/dbd/odbc/statement.rb +137 -0
- data/lib/dbd/pg/database.rb +516 -0
- data/lib/dbd/pg/exec.rb +47 -0
- data/lib/dbd/pg/statement.rb +160 -0
- data/lib/dbd/pg/tuples.rb +121 -0
- data/lib/dbd/pg/type.rb +209 -0
- data/lib/dbd/sqlite/database.rb +151 -0
- data/lib/dbd/sqlite/statement.rb +125 -0
- data/lib/dbd/sqlite3/database.rb +201 -0
- data/lib/dbd/sqlite3/statement.rb +78 -0
- data/lib/dbi.rb +336 -0
- data/lib/dbi/base_classes.rb +12 -0
- data/lib/dbi/base_classes/database.rb +135 -0
- data/lib/dbi/base_classes/driver.rb +47 -0
- data/lib/dbi/base_classes/statement.rb +171 -0
- data/lib/dbi/binary.rb +25 -0
- data/lib/dbi/columninfo.rb +107 -0
- data/lib/dbi/exceptions.rb +65 -0
- data/lib/dbi/handles.rb +49 -0
- data/lib/dbi/handles/database.rb +241 -0
- data/lib/dbi/handles/driver.rb +60 -0
- data/lib/dbi/handles/statement.rb +408 -0
- data/lib/dbi/row.rb +269 -0
- data/lib/dbi/sql.rb +22 -0
- data/lib/dbi/sql/preparedstatement.rb +115 -0
- data/lib/dbi/sql_type_constants.rb +75 -0
- data/lib/dbi/trace.rb +91 -0
- data/lib/dbi/types.rb +218 -0
- data/lib/dbi/typeutil.rb +109 -0
- data/lib/dbi/utils.rb +60 -0
- data/lib/dbi/utils/date.rb +59 -0
- data/lib/dbi/utils/tableformatter.rb +112 -0
- data/lib/dbi/utils/time.rb +52 -0
- data/lib/dbi/utils/timestamp.rb +96 -0
- data/lib/dbi/utils/xmlformatter.rb +73 -0
- data/lib/dbi/version.rb +3 -0
- data/prototypes/types2.rb +237 -0
- data/readme.md +274 -0
- data/setup.rb +1585 -0
- data/test/DBD_TESTS +50 -0
- data/test/TESTING +16 -0
- data/test/dbd/general/test_database.rb +206 -0
- data/test/dbd/general/test_statement.rb +326 -0
- data/test/dbd/general/test_types.rb +296 -0
- data/test/dbd/mysql/base.rb +26 -0
- data/test/dbd/mysql/down.sql +19 -0
- data/test/dbd/mysql/test_blob.rb +18 -0
- data/test/dbd/mysql/test_new_methods.rb +7 -0
- data/test/dbd/mysql/test_patches.rb +111 -0
- data/test/dbd/mysql/up.sql +28 -0
- data/test/dbd/odbc/base.rb +30 -0
- data/test/dbd/odbc/down.sql +19 -0
- data/test/dbd/odbc/test_new_methods.rb +12 -0
- data/test/dbd/odbc/test_ping.rb +10 -0
- data/test/dbd/odbc/test_statement.rb +44 -0
- data/test/dbd/odbc/test_transactions.rb +58 -0
- data/test/dbd/odbc/up.sql +33 -0
- data/test/dbd/postgresql/base.rb +31 -0
- data/test/dbd/postgresql/down.sql +31 -0
- data/test/dbd/postgresql/test_arrays.rb +179 -0
- data/test/dbd/postgresql/test_async.rb +121 -0
- data/test/dbd/postgresql/test_blob.rb +36 -0
- data/test/dbd/postgresql/test_bytea.rb +87 -0
- data/test/dbd/postgresql/test_ping.rb +10 -0
- data/test/dbd/postgresql/test_timestamp.rb +77 -0
- data/test/dbd/postgresql/test_transactions.rb +58 -0
- data/test/dbd/postgresql/testdbipg.rb +307 -0
- data/test/dbd/postgresql/up.sql +60 -0
- data/test/dbd/sqlite/base.rb +32 -0
- data/test/dbd/sqlite/test_database.rb +30 -0
- data/test/dbd/sqlite/test_driver.rb +68 -0
- data/test/dbd/sqlite/test_statement.rb +112 -0
- data/test/dbd/sqlite/up.sql +25 -0
- data/test/dbd/sqlite3/base.rb +32 -0
- data/test/dbd/sqlite3/test_database.rb +77 -0
- data/test/dbd/sqlite3/test_driver.rb +67 -0
- data/test/dbd/sqlite3/test_statement.rb +88 -0
- data/test/dbd/sqlite3/up.sql +33 -0
- data/test/dbi/tc_columninfo.rb +94 -0
- data/test/dbi/tc_date.rb +88 -0
- data/test/dbi/tc_dbi.rb +184 -0
- data/test/dbi/tc_row.rb +256 -0
- data/test/dbi/tc_sqlbind.rb +168 -0
- data/test/dbi/tc_statementhandle.rb +29 -0
- data/test/dbi/tc_time.rb +77 -0
- data/test/dbi/tc_timestamp.rb +142 -0
- data/test/dbi/tc_types.rb +268 -0
- data/test/ts_dbd.rb +131 -0
- data/test/ts_dbi.rb +16 -0
- data/ydbi.gemspec +24 -0
- metadata +224 -0
data/lib/dbi/trace.rb
ADDED
@@ -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
|
+
|
data/lib/dbi/types.rb
ADDED
@@ -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
|
data/lib/dbi/typeutil.rb
ADDED
@@ -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
|
data/lib/dbi/utils.rb
ADDED
@@ -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'
|